[BACK]Return to wordexp.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libc / gen

Annotation of src/lib/libc/gen/wordexp.c, Revision 1.3

1.3     ! lukem       1: /*     $NetBSD: wordexp.c,v 1.2 2005/11/29 03:11:59 christos Exp $     */
1.1       seb         2:
                      3: /*-
                      4:  * Copyright (c) 2002 Tim J. Robbins.
                      5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  *
                     16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
                     17:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     18:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     19:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
                     20:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     21:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     22:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     23:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     24:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     25:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     26:  * SUCH DAMAGE.
                     27:  */
                     28:
                     29: #include "namespace.h"
                     30: #include <sys/cdefs.h>
                     31: #include <sys/types.h>
                     32: #include <assert.h>
                     33: #include <sys/wait.h>
                     34: #include <fcntl.h>
                     35: #include <paths.h>
                     36: #include <stdio.h>
                     37: #include <stdlib.h>
                     38: #include <string.h>
                     39: #include <unistd.h>
                     40: #include <wordexp.h>
                     41:
                     42: #if defined(LIBC_SCCS) && !defined(lint)
                     43: #if 0
                     44: __FBSDID("$FreeBSD: /repoman/r/ncvs/src/lib/libc/gen/wordexp.c,v 1.5 2004/04/09 11:32:32 tjr Exp $");
                     45: #else
1.3     ! lukem      46: __RCSID("$NetBSD: wordexp.c,v 1.2 2005/11/29 03:11:59 christos Exp $");
1.1       seb        47: #endif
                     48: #endif /* LIBC_SCCS and not lint */
                     49:
                     50: static int     we_askshell(const char *, wordexp_t *, int);
                     51: static int     we_check(const char *, int);
                     52:
                     53: /*
                     54:  * wordexp --
                     55:  *     Perform shell word expansion on `words' and place the resulting list
                     56:  *     of words in `we'. See wordexp(3).
                     57:  *
                     58:  */
                     59: int
                     60: wordexp(const char * __restrict words, wordexp_t * __restrict we, int flags)
                     61: {
                     62:        int error;
                     63:
                     64:        _DIAGASSERT(we != NULL);
                     65:        _DIAGASSERT(words != NULL);
                     66:        if (flags & WRDE_REUSE)
                     67:                wordfree(we);
                     68:        if ((flags & WRDE_APPEND) == 0) {
                     69:                we->we_wordc = 0;
                     70:                we->we_wordv = NULL;
                     71:                we->we_strings = NULL;
                     72:                we->we_nbytes = 0;
                     73:        }
                     74:        if ((error = we_check(words, flags)) != 0) {
                     75:                wordfree(we);
                     76:                return (error);
                     77:        }
                     78:        if ((error = we_askshell(words, we, flags)) != 0) {
                     79:                wordfree(we);
                     80:                return (error);
                     81:        }
                     82:        return (0);
                     83: }
                     84:
                     85: /*
                     86:  * we_askshell --
                     87:  *     Use the `wordexp' /bin/sh builtin function to do most of the work
                     88:  *     in expanding the word string. This function is complicated by
                     89:  *     memory management.
                     90:  */
                     91: static int
                     92: we_askshell(const char *words, wordexp_t *we, int flags)
                     93: {
                     94:        int pdes[2];                    /* Pipe to child */
                     95:        size_t nwords, nbytes;          /* Number of words, bytes from child */
                     96:        int i;                          /* Handy integer */
1.3     ! lukem      97:        unsigned int ui;                /* For array iteration */
1.1       seb        98:        size_t sofs;                    /* Offset into we->we_strings */
                     99:        size_t vofs;                    /* Offset into we->we_wordv */
                    100:        pid_t pid;                      /* Process ID of child */
                    101:        int status;                     /* Child exit status */
1.2       christos  102:        const char *ifs;                /* IFS env. var. */
1.1       seb       103:        char *np, *p;                   /* Handy pointers */
                    104:        char *nstrings;                 /* Temporary for realloc() */
                    105:        char **nwv;                     /* Temporary for realloc() */
                    106:        FILE *fp;                       /* Stream to read pipe */
                    107:        extern char **environ;
                    108:        char *cmd;
                    109:
                    110:        if ((ifs = getenv("IFS")) == NULL)
                    111:                ifs = " \t\n";
                    112:        if (asprintf(&cmd, "wordexp%c%s\n", *ifs, words) < 0)
                    113:                return (WRDE_NOSPACE);
                    114:        if (pipe(pdes) < 0) {
                    115:                free(cmd);
                    116:                return (WRDE_ERRNO);
                    117:        }
                    118:        if ((fp = fdopen(pdes[0], "r")) == NULL) {
                    119:                free(cmd);
                    120:                return (WRDE_ERRNO);
                    121:        }
                    122:        if ((pid = fork()) < 0) {
                    123:                free(cmd);
                    124:                fclose(fp);
                    125:                close(pdes[1]);
                    126:                return (WRDE_ERRNO);
                    127:        }
                    128:        else if (pid == 0) {
                    129:                /*
                    130:                 * We are the child; just get /bin/sh to run the wordexp
                    131:                 * builtin on `words'.
                    132:                 */
                    133:                int devnull;
                    134:
                    135:                close(pdes[0]);
                    136:                if (pdes[1] != STDOUT_FILENO) {
                    137:                        if (dup2(pdes[1], STDOUT_FILENO) < 0)
                    138:                                _exit(1);
                    139:                        close(pdes[1]);
                    140:                }
                    141:                if ((flags & WRDE_SHOWERR) == 0) {
                    142:                        if ((devnull = open(_PATH_DEVNULL, O_RDWR, 0666)) < 0)
                    143:                                _exit(1);
                    144:                        if (dup2(devnull, STDERR_FILENO) < 0)
                    145:                                _exit(1);
                    146:                        close(devnull);
                    147:                }
                    148:                execle(_PATH_BSHELL, "sh", flags & WRDE_UNDEF ? "-u" : "+u",
                    149:                    "-c", cmd, (char *)NULL, environ);
                    150:                _exit(1);
                    151:        }
                    152:
                    153:        /*
                    154:         * We are the parent; read the output of the shell wordexp function,
                    155:         * which is a decimal word count, an null, a decimal byte count,
                    156:         * (not including terminating null bytes), a null and then followed
                    157:         * by the expanded words separated by nulls.
                    158:         */
                    159:        free(cmd);
                    160:        close(pdes[1]);
                    161:        /* read the word count */
                    162:        nwords = 0;
                    163:        while ((i = getc(fp)) != EOF) {
                    164:                if (i == '\0')
                    165:                        break;
                    166:                nwords *= 10;
                    167:                nwords += (i - '0');
                    168:        }
                    169:        /* read the byte count */
                    170:        nbytes = 0;
                    171:        while ((i = getc(fp)) != EOF) {
                    172:                if (i == '\0')
                    173:                        break;
                    174:                nbytes *= 10;
                    175:                nbytes += (i - '0');
                    176:        }
                    177:        if (i == EOF) {
                    178:                fclose(fp);
                    179:                waitpid(pid, &status, 0);
                    180:                return (flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX);
                    181:        }
                    182:        nbytes += nwords;
                    183:
                    184:        /*
                    185:         * Allocate or reallocate (when flags & WRDE_APPEND) the word vector
                    186:         * and string storage buffers for the expanded words we're about to
                    187:         * read from the child.
                    188:         */
                    189:        sofs = we->we_nbytes;
                    190:        vofs = we->we_wordc;
                    191:        if ((flags & (WRDE_DOOFFS|WRDE_APPEND)) == (WRDE_DOOFFS|WRDE_APPEND))
                    192:                vofs += we->we_offs;
                    193:        we->we_wordc += nwords;
                    194:        we->we_nbytes += nbytes;
                    195:        if ((nwv = realloc(we->we_wordv, (we->we_wordc + 1 +
                    196:            (flags & WRDE_DOOFFS ?  we->we_offs : 0)) *
                    197:            sizeof(char *))) == NULL) {
                    198:                fclose(fp);
                    199:                waitpid(pid, &status, 0);
                    200:                return (WRDE_NOSPACE);
                    201:        }
                    202:        we->we_wordv = nwv;
                    203:        if ((nstrings = realloc(we->we_strings, we->we_nbytes)) == NULL) {
                    204:                fclose(fp);
                    205:                waitpid(pid, &status, 0);
                    206:                return (WRDE_NOSPACE);
                    207:        }
1.3     ! lukem     208:        for (ui = 0; ui < vofs; ui++)
        !           209:                if (we->we_wordv[ui] != NULL)
        !           210:                        we->we_wordv[ui] += nstrings - we->we_strings;
1.1       seb       211:        we->we_strings = nstrings;
                    212:
                    213:        if (fread(we->we_strings + sofs, sizeof(char), nbytes, fp) != nbytes) {
                    214:                fclose(fp);
                    215:                waitpid(pid, &status, 0);
                    216:                return (flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX);
                    217:        }
                    218:
                    219:        if (waitpid(pid, &status, 0) < 0 || !WIFEXITED(status) ||
                    220:            WEXITSTATUS(status) != 0) {
                    221:                fclose(fp);
                    222:                return (flags & WRDE_UNDEF ? WRDE_BADVAL : WRDE_SYNTAX);
                    223:        }
                    224:        fclose(fp);
                    225:
                    226:        /*
                    227:         * Break the null-terminated expanded word strings out into
                    228:         * the vector.
                    229:         */
                    230:        if (vofs == 0 && flags & WRDE_DOOFFS)
                    231:                while (vofs < we->we_offs)
                    232:                        we->we_wordv[vofs++] = NULL;
                    233:        p = we->we_strings + sofs;
                    234:        while (nwords-- != 0) {
                    235:                we->we_wordv[vofs++] = p;
                    236:                if ((np = memchr(p, '\0', nbytes)) == NULL)
                    237:                        return (WRDE_NOSPACE);  /* XXX */
                    238:                nbytes -= np - p + 1;
                    239:                p = np + 1;
                    240:        }
                    241:        we->we_wordv[vofs] = NULL;
                    242:
                    243:        return (0);
                    244: }
                    245:
                    246: /*
                    247:  * we_check --
                    248:  *     Check that the string contains none of the following unquoted
                    249:  *     special characters: <newline> |&;<>(){}
                    250:  *     or command substitutions when WRDE_NOCMD is set in flags.
                    251:  */
                    252: static int
                    253: we_check(const char *words, int flags)
                    254: {
                    255:        char c;
                    256:        int dquote, level, quote, squote;
                    257:
                    258:        quote = squote = dquote = 0;
                    259:        while ((c = *words++) != '\0') {
                    260:                switch (c) {
                    261:                case '\\':
                    262:                        quote ^= 1;
                    263:                        continue;
                    264:                case '\'':
                    265:                        if (quote + dquote == 0)
                    266:                                squote ^= 1;
                    267:                        break;
                    268:                case '"':
                    269:                        if (quote + squote == 0)
                    270:                                dquote ^= 1;
                    271:                        break;
                    272:                case '`':
                    273:                        if (quote + squote == 0 && flags & WRDE_NOCMD)
                    274:                                return (WRDE_CMDSUB);
                    275:                        while ((c = *words++) != '\0' && c != '`')
                    276:                                if (c == '\\' && (c = *words++) == '\0')
                    277:                                        break;
                    278:                        if (c == '\0')
                    279:                                return (WRDE_SYNTAX);
                    280:                        break;
                    281:                case '|': case '&': case ';': case '<': case '>':
                    282:                case '{': case '}': case '(': case ')': case '\n':
                    283:                        if (quote + squote + dquote == 0)
                    284:                                return (WRDE_BADCHAR);
                    285:                        break;
                    286:                case '$':
                    287:                        if ((c = *words++) == '\0')
                    288:                                break;
                    289:                        else if (quote + squote == 0 && c == '(') {
                    290:                                if (flags & WRDE_NOCMD && *words != '(')
                    291:                                        return (WRDE_CMDSUB);
                    292:                                level = 1;
                    293:                                while ((c = *words++) != '\0') {
                    294:                                        if (c == '\\') {
                    295:                                                if ((c = *words++) == '\0')
                    296:                                                        break;
                    297:                                        } else if (c == '(')
                    298:                                                level++;
                    299:                                        else if (c == ')' && --level == 0)
                    300:                                                break;
                    301:                                }
                    302:                                if (c == '\0' || level != 0)
                    303:                                        return (WRDE_SYNTAX);
                    304:                        } else if (quote + squote == 0 && c == '{') {
                    305:                                level = 1;
                    306:                                while ((c = *words++) != '\0') {
                    307:                                        if (c == '\\') {
                    308:                                                if ((c = *words++) == '\0')
                    309:                                                        break;
                    310:                                        } else if (c == '{')
                    311:                                                level++;
                    312:                                        else if (c == '}' && --level == 0)
                    313:                                                break;
                    314:                                }
                    315:                                if (c == '\0' || level != 0)
                    316:                                        return (WRDE_SYNTAX);
                    317:                        } else
                    318:                                c = *--words;
                    319:                        break;
                    320:                default:
                    321:                        break;
                    322:                }
                    323:                quote = 0;
                    324:        }
                    325:        if (quote + squote + dquote != 0)
                    326:                return (WRDE_SYNTAX);
                    327:
                    328:        return (0);
                    329: }
                    330:
                    331: /*
                    332:  * wordfree --
                    333:  *     Free the result of wordexp(). See wordexp(3).
                    334:  *
                    335:  */
                    336: void
                    337: wordfree(wordexp_t *we)
                    338: {
                    339:        _DIAGASSERT(we != NULL);
                    340:        free(we->we_wordv);
                    341:        free(we->we_strings);
                    342:        we->we_wordv = NULL;
                    343:        we->we_strings = NULL;
                    344:        we->we_nbytes = 0;
                    345:        we->we_wordc = 0;
                    346: }

CVSweb <webmaster@jp.NetBSD.org>