[BACK]Return to expand.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / rdist

Annotation of src/usr.bin/rdist/expand.c, Revision 1.18

1.18    ! deraadt     1: /*     $OpenBSD: expand.c,v 1.17 2018/09/21 19:00:45 millert Exp $     */
1.4       deraadt     2:
1.1       deraadt     3: /*
1.2       dm          4:  * Copyright (c) 1983 Regents of the University of California.
                      5:  * All rights reserved.
1.1       deraadt     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.
1.11      millert    15:  * 3. Neither the name of the University nor the names of its contributors
1.1       deraadt    16:  *    may be used to endorse or promote products derived from this software
                     17:  *    without specific prior written permission.
                     18:  *
                     19:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     20:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     21:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     22:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     23:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     24:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     25:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     26:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     27:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     28:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     29:  * SUCH DAMAGE.
                     30:  */
                     31:
1.14      guenther   32: #include <dirent.h>
1.15      guenther   33: #include <errno.h>
                     34: #include <fcntl.h>
                     35: #include <stdlib.h>
                     36: #include <string.h>
                     37: #include <unistd.h>
1.14      guenther   38:
1.15      guenther   39: #include "client.h"
1.1       deraadt    40:
1.2       dm         41: #define        MAXEARGS        2048
                     42: #define LC             '{'
                     43: #define RC             '}'
1.1       deraadt    44:
                     45: static char    shchars[] = "${[*?";
                     46:
1.2       dm         47: int            which;          /* bit mask of types to expand */
                     48: int            eargc;          /* expanded arg count */
                     49: char         **eargv;          /* expanded arg vectors */
                     50: char          *path;
                     51: char          *pathp;
                     52: char          *lastpathp;
                     53: char          *tilde;          /* "~user" if not expanding tilde, else "" */
                     54: char          *tpathp;
1.17      millert    55: char           pathbuf[BUFSIZ];
1.2       dm         56:
                     57: int            expany;         /* any expansions done? */
                     58: char          *entp;
                     59: char         **sortbase;
                     60: char          *argvbuf[MAXEARGS];
                     61:
1.1       deraadt    62: #define sort() qsort((char *)sortbase, &eargv[eargc] - sortbase, \
                     63:                      sizeof(*sortbase), argcmp), sortbase = &eargv[eargc]
                     64:
1.10      millert    65: static void Cat(u_char *, u_char *);
                     66: static void addpath(int);
                     67: static int argcmp(const void *, const void *);
                     68:
                     69: static void
                     70: Cat(u_char *s1, u_char *s2)            /* quote in s1 and s2 */
1.2       dm         71: {
1.7       mpech      72:        char *cp;
1.2       dm         73:        int len = strlen((char *)s1) + strlen((char *)s2) + 2;
                     74:
                     75:        if ((eargc + 1) >= MAXEARGS) {
                     76:                yyerror("Too many names");
                     77:                return;
                     78:        }
                     79:
1.5       millert    80:        eargv[++eargc] = NULL;
1.2       dm         81:        eargv[eargc - 1] = cp = xmalloc(len);
                     82:
                     83:        do {
                     84:                if (*s1 == QUOTECHAR)
                     85:                        s1++;
1.10      millert    86:        } while ((*cp++ = *s1++) != '\0');
1.2       dm         87:        cp--;
                     88:        do {
                     89:                if (*s2 == QUOTECHAR)
                     90:                        s2++;
1.10      millert    91:        } while ((*cp++ = *s2++) != '\0');
1.2       dm         92: }
                     93:
1.10      millert    94: static void
                     95: addpath(int c)
1.2       dm         96: {
                     97:        if (pathp >= lastpathp) {
                     98:                yyerror("Pathname too long");
                     99:                return;
                    100:        } else {
                    101:                *pathp++ = c;
                    102:                *pathp = CNULL;
                    103:        }
                    104: }
1.1       deraadt   105:
                    106: /*
                    107:  * Take a list of names and expand any macros, etc.
                    108:  * wh = E_VARS if expanding variables.
                    109:  * wh = E_SHELL if expanding shell characters.
                    110:  * wh = E_TILDE if expanding `~'.
                    111:  * or any of these or'ed together.
                    112:  *
                    113:  * Major portions of this were snarfed from csh/sh.glob.c.
                    114:  */
                    115: struct namelist *
1.10      millert   116: expand(struct namelist *list, int wh)          /* quote in list->n_name */
1.1       deraadt   117: {
1.7       mpech     118:        struct namelist *nl, *prev;
                    119:        int n;
1.1       deraadt   120:
1.2       dm        121:        if (debug)
1.13      guenther  122:                debugmsg(DM_CALL, "expand(%p, %d) start, list = %s",
1.2       dm        123:                         list, wh, getnlstr(list));
1.1       deraadt   124:
1.2       dm        125:        if (wh == 0)
                    126:                fatalerr("expand() contains invalid 'wh' argument.");
1.1       deraadt   127:
                    128:        which = wh;
                    129:        path = tpathp = pathp = pathbuf;
1.2       dm        130:        *pathp = CNULL;
1.9       millert   131:        lastpathp = &pathbuf[sizeof pathbuf - 2];
1.1       deraadt   132:        tilde = "";
                    133:        eargc = 0;
                    134:        eargv = sortbase = argvbuf;
1.5       millert   135:        *eargv = NULL;
1.2       dm        136:
1.1       deraadt   137:        /*
                    138:         * Walk the name list and expand names into eargv[];
                    139:         */
                    140:        for (nl = list; nl != NULL; nl = nl->n_next)
1.2       dm        141:                expstr((u_char *)nl->n_name);
1.1       deraadt   142:        /*
                    143:         * Take expanded list of names from eargv[] and build a new list.
                    144:         */
                    145:        list = prev = NULL;
                    146:        for (n = 0; n < eargc; n++) {
1.5       millert   147:                nl = makenl(NULL);
1.1       deraadt   148:                nl->n_name = eargv[n];
                    149:                if (prev == NULL)
                    150:                        list = prev = nl;
                    151:                else {
                    152:                        prev->n_next = nl;
                    153:                        prev = nl;
                    154:                }
                    155:        }
1.2       dm        156:
1.1       deraadt   157:        return(list);
                    158: }
                    159:
1.2       dm        160: /*
                    161:  * xstrchr() is a version of strchr() that
                    162:  * handles u_char buffers.
                    163:  */
1.10      millert   164: u_char *
                    165: xstrchr(u_char *str, int ch)
1.1       deraadt   166: {
1.7       mpech     167:        u_char *cp;
1.2       dm        168:
                    169:        for (cp = str; cp && *cp != CNULL; ++cp)
                    170:                if (ch == *cp)
                    171:                        return(cp);
                    172:
1.5       millert   173:        return(NULL);
1.2       dm        174: }
                    175:
1.10      millert   176: void
                    177: expstr(u_char *s)
1.2       dm        178: {
1.7       mpech     179:        u_char *cp, *cp1;
                    180:        struct namelist *tp;
1.2       dm        181:        u_char *tail;
                    182:        u_char ebuf[BUFSIZ];
                    183:        u_char varbuff[BUFSIZ];
1.1       deraadt   184:        int savec, oeargc;
                    185:
1.2       dm        186:        if (s == NULL || *s == CNULL)
1.1       deraadt   187:                return;
                    188:
1.2       dm        189:        /*
                    190:         * Remove quoted characters
                    191:         */
                    192:        if (IS_ON(which, E_VARS)) {
1.10      millert   193:                if (strlen((char *)s) > sizeof(varbuff)) {
1.2       dm        194:                        yyerror("Variable is too large.");
                    195:                        return;
                    196:                }
                    197:                for (cp = s, cp1 = varbuff; cp && *cp; ++cp) {
                    198:                        /*
                    199:                         * remove quoted character if the next
                    200:                         * character is not $
                    201:                         */
                    202:                        if (*cp == QUOTECHAR && *(cp+1) != '$')
                    203:                                ++cp;
                    204:                        else
                    205:                                *cp1++ = *cp;
                    206:                }
                    207:                *cp1 = CNULL;
                    208:                s = varbuff;
                    209:        }
                    210:
                    211:        /*
                    212:         * Consider string 's' a variable that should be expanded if
                    213:         * there is a '$' in 's' that is not quoted.
                    214:         */
                    215:        if (IS_ON(which, E_VARS) &&
                    216:            ((cp = xstrchr(s, '$')) && !(cp > s && *(cp-1) == QUOTECHAR))) {
                    217:                *cp++ = CNULL;
                    218:                if (*cp == CNULL) {
1.1       deraadt   219:                        yyerror("no variable name after '$'");
                    220:                        return;
                    221:                }
                    222:                if (*cp == LC) {
                    223:                        cp++;
1.2       dm        224:                        for (cp1 = cp; ; cp1 = tail + 1) {
                    225:                                if ((tail = xstrchr(cp1, RC)) == NULL) {
                    226:                                        yyerror("unmatched '{'");
                    227:                                        return;
                    228:                                }
                    229:                                if (tail[-1] != QUOTECHAR) break;
1.1       deraadt   230:                        }
1.2       dm        231:                        *tail++ = savec = CNULL;
                    232:                        if (*cp == CNULL) {
1.1       deraadt   233:                                yyerror("no variable name after '$'");
                    234:                                return;
                    235:                        }
                    236:                } else {
                    237:                        tail = cp + 1;
                    238:                        savec = *tail;
1.2       dm        239:                        *tail = CNULL;
1.1       deraadt   240:                }
1.5       millert   241:                tp = lookup((char *)cp, LOOKUP, NULL);
1.2       dm        242:                if (savec != CNULL)
1.1       deraadt   243:                        *tail = savec;
                    244:                if (tp != NULL) {
                    245:                        for (; tp != NULL; tp = tp->n_next) {
1.10      millert   246:                                (void) snprintf((char *)ebuf, sizeof(ebuf),
                    247:                                                "%s%s%s", s, tp->n_name, tail);
1.2       dm        248:                                expstr(ebuf);
1.1       deraadt   249:                        }
                    250:                        return;
                    251:                }
1.10      millert   252:                (void) snprintf((char *)ebuf, sizeof(ebuf), "%s%s", s, tail);
1.2       dm        253:                expstr(ebuf);
1.1       deraadt   254:                return;
                    255:        }
1.2       dm        256:        if ((which & ~E_VARS) == 0 || !strcmp((char *)s, "{") ||
                    257:            !strcmp((char *)s, "{}")) {
                    258:                Cat(s, (u_char *)"");
1.1       deraadt   259:                sort();
                    260:                return;
                    261:        }
                    262:        if (*s == '~') {
1.17      millert   263:                if ((cp = strchr(s, '/')) == NULL) {
1.1       deraadt   264:                        tilde = "~";
1.17      millert   265:                        s++;
1.1       deraadt   266:                } else {
1.17      millert   267:                        tilde = memcpy(ebuf, s, (cp - s));
                    268:                        ebuf[cp - s] = '\0';
1.1       deraadt   269:                        s = cp;
                    270:                }
1.17      millert   271:                cp = exptilde(path, tilde, sizeof(pathbuf));
                    272:                tpathp = pathp = (char *)cp;
1.1       deraadt   273:        } else {
                    274:                tpathp = pathp = path;
                    275:                tilde = "";
                    276:        }
1.2       dm        277:        *pathp = CNULL;
1.1       deraadt   278:        if (!(which & E_SHELL)) {
                    279:                if (which & E_TILDE)
1.2       dm        280:                        Cat((u_char *)path, s);
1.1       deraadt   281:                else
1.2       dm        282:                        Cat((u_char *)tilde, s);
1.1       deraadt   283:                sort();
                    284:                return;
                    285:        }
                    286:        oeargc = eargc;
                    287:        expany = 0;
                    288:        expsh(s);
                    289:        if (eargc == oeargc)
1.2       dm        290:                Cat(s, (u_char *)"");           /* "nonomatch" is set */
1.1       deraadt   291:        sort();
                    292: }
                    293:
1.5       millert   294: static int
1.10      millert   295: argcmp(const void *v1, const void *v2)
1.1       deraadt   296: {
1.10      millert   297:        const char *const *a1 = v1, *const *a2 = v2;
1.1       deraadt   298:
1.2       dm        299:        return (strcmp(*a1, *a2));
1.1       deraadt   300: }
                    301:
                    302: /*
                    303:  * If there are any Shell meta characters in the name,
                    304:  * expand into a list, after searching directory
                    305:  */
1.10      millert   306: void
                    307: expsh(u_char *s)                       /* quote in s */
1.1       deraadt   308: {
1.7       mpech     309:        u_char *cp, *oldcp;
                    310:        char *spathp;
1.1       deraadt   311:        struct stat stb;
                    312:
                    313:        spathp = pathp;
                    314:        cp = s;
                    315:        while (!any(*cp, shchars)) {
1.2       dm        316:                if (*cp == CNULL) {
1.1       deraadt   317:                        if (!expany || stat(path, &stb) >= 0) {
                    318:                                if (which & E_TILDE)
1.2       dm        319:                                        Cat((u_char *)path, (u_char *)"");
1.1       deraadt   320:                                else
1.2       dm        321:                                        Cat((u_char *)tilde, (u_char *)tpathp);
1.1       deraadt   322:                        }
                    323:                        goto endit;
                    324:                }
1.2       dm        325:                if (*cp == QUOTECHAR) cp++;
1.1       deraadt   326:                addpath(*cp++);
                    327:        }
                    328:        oldcp = cp;
                    329:        while (cp > s && *cp != '/')
                    330:                cp--, pathp--;
                    331:        if (*cp == '/')
                    332:                cp++, pathp++;
1.2       dm        333:        *pathp = CNULL;
1.1       deraadt   334:        if (*oldcp == '{') {
1.5       millert   335:                (void) execbrc(cp, NULL);
1.1       deraadt   336:                return;
                    337:        }
1.2       dm        338:        matchdir((char *)cp);
1.1       deraadt   339: endit:
                    340:        pathp = spathp;
1.2       dm        341:        *pathp = CNULL;
1.1       deraadt   342: }
                    343:
1.10      millert   344: void
                    345: matchdir(char *pattern)                        /* quote in pattern */
1.1       deraadt   346: {
                    347:        struct stat stb;
1.14      guenther  348:        struct dirent *dp;
1.1       deraadt   349:        DIR *dirp;
                    350:
                    351:        dirp = opendir(path);
                    352:        if (dirp == NULL) {
                    353:                if (expany)
                    354:                        return;
                    355:                goto patherr2;
                    356:        }
1.18    ! deraadt   357:        if (fstat(dirfd(dirp), &stb) == -1)
1.1       deraadt   358:                goto patherr1;
1.2       dm        359:        if (!S_ISDIR(stb.st_mode)) {
1.1       deraadt   360:                errno = ENOTDIR;
                    361:                goto patherr1;
                    362:        }
                    363:        while ((dp = readdir(dirp)) != NULL)
                    364:                if (match(dp->d_name, pattern)) {
                    365:                        if (which & E_TILDE)
1.2       dm        366:                                Cat((u_char *)path, (u_char *)dp->d_name);
1.1       deraadt   367:                        else {
1.9       millert   368:                                (void) strlcpy(pathp, dp->d_name,
                    369:                                    lastpathp - pathp + 2);
1.2       dm        370:                                Cat((u_char *)tilde, (u_char *)tpathp);
                    371:                                *pathp = CNULL;
1.1       deraadt   372:                        }
                    373:                }
                    374:        closedir(dirp);
                    375:        return;
                    376:
                    377: patherr1:
                    378:        closedir(dirp);
                    379: patherr2:
1.9       millert   380:        (void) strlcat(path, ": ", lastpathp - path + 2);
                    381:        (void) strlcat(path, SYSERR, lastpathp - path + 2);
1.1       deraadt   382:        yyerror(path);
                    383: }
                    384:
1.5       millert   385: int
1.10      millert   386: execbrc(u_char *p, u_char *s)          /* quote in p */
1.1       deraadt   387: {
1.2       dm        388:        u_char restbuf[BUFSIZ + 2];
1.7       mpech     389:        u_char *pe, *pm, *pl;
1.1       deraadt   390:        int brclev = 0;
1.2       dm        391:        u_char *lm, savec;
                    392:        char *spathp;
1.1       deraadt   393:
                    394:        for (lm = restbuf; *p != '{'; *lm++ = *p++)
1.2       dm        395:                if (*p == QUOTECHAR) *lm++ = *p++;
                    396:
1.1       deraadt   397:        for (pe = ++p; *pe; pe++)
                    398:                switch (*pe) {
                    399:
                    400:                case '{':
                    401:                        brclev++;
                    402:                        continue;
                    403:
                    404:                case '}':
                    405:                        if (brclev == 0)
                    406:                                goto pend;
                    407:                        brclev--;
                    408:                        continue;
                    409:
                    410:                case '[':
                    411:                        for (pe++; *pe && *pe != ']'; pe++)
1.2       dm        412:                                if (*p == QUOTECHAR) pe++;
1.1       deraadt   413:                        if (!*pe)
                    414:                                yyerror("Missing ']'");
                    415:                        continue;
1.2       dm        416:
                    417:                case QUOTECHAR:         /* skip this character */
                    418:                        pe++;
                    419:                        continue;
1.1       deraadt   420:                }
                    421: pend:
                    422:        if (brclev || !*pe) {
                    423:                yyerror("Missing '}'");
                    424:                return (0);
                    425:        }
                    426:        for (pl = pm = p; pm <= pe; pm++)
1.2       dm        427:                /* the strip code was a noop */
                    428:                switch (*pm) {
1.1       deraadt   429:
                    430:                case '{':
                    431:                        brclev++;
                    432:                        continue;
                    433:
                    434:                case '}':
                    435:                        if (brclev) {
                    436:                                brclev--;
                    437:                                continue;
                    438:                        }
                    439:                        goto doit;
                    440:
                    441:                case ',':
                    442:                        if (brclev)
                    443:                                continue;
                    444: doit:
                    445:                        savec = *pm;
                    446:                        *pm = 0;
1.9       millert   447:                        *lm = 0;
                    448:                        (void) strlcat((char *)restbuf, (char *)pl,
1.10      millert   449:                            sizeof(restbuf));
1.8       deraadt   450:                        (void) strlcat((char *)restbuf, (char *)pe + 1,
1.10      millert   451:                            sizeof(restbuf));
1.1       deraadt   452:                        *pm = savec;
                    453:                        if (s == 0) {
                    454:                                spathp = pathp;
                    455:                                expsh(restbuf);
                    456:                                pathp = spathp;
                    457:                                *pathp = 0;
1.2       dm        458:                        } else if (amatch((char *)s, restbuf))
1.1       deraadt   459:                                return (1);
                    460:                        sort();
                    461:                        pl = pm + 1;
                    462:                        continue;
                    463:
                    464:                case '[':
                    465:                        for (pm++; *pm && *pm != ']'; pm++)
1.2       dm        466:                                if (*pm == QUOTECHAR) pm++;
1.1       deraadt   467:                        if (!*pm)
                    468:                                yyerror("Missing ']'");
                    469:                        continue;
1.2       dm        470:
                    471:                case QUOTECHAR:                 /* skip one character */
                    472:                        pm++;
                    473:                        continue;
1.1       deraadt   474:                }
                    475:        return (0);
                    476: }
                    477:
1.5       millert   478: int
1.10      millert   479: match(char *s, char *p)                                /* quote in p */
1.1       deraadt   480: {
1.7       mpech     481:        int c;
                    482:        char *sentp;
1.1       deraadt   483:        char sexpany = expany;
                    484:
                    485:        if (*s == '.' && *p != '.')
                    486:                return (0);
                    487:        sentp = entp;
                    488:        entp = s;
                    489:        c = amatch(s, p);
                    490:        entp = sentp;
                    491:        expany = sexpany;
                    492:        return (c);
                    493: }
                    494:
1.5       millert   495: int
1.10      millert   496: amatch(char *s, u_char *p)                     /* quote in p */
1.1       deraadt   497: {
1.7       mpech     498:        int scc;
1.1       deraadt   499:        int ok, lc;
                    500:        char *spathp;
                    501:        struct stat stb;
                    502:        int c, cc;
                    503:
                    504:        expany = 1;
                    505:        for (;;) {
1.2       dm        506:                scc = *s++;
1.1       deraadt   507:                switch (c = *p++) {
                    508:
                    509:                case '{':
1.2       dm        510:                        return (execbrc((u_char *)p - 1, (u_char *)s - 1));
1.1       deraadt   511:
                    512:                case '[':
                    513:                        ok = 0;
                    514:                        lc = 077777;
1.10      millert   515:                        while ((cc = *p++) != '\0') {
1.1       deraadt   516:                                if (cc == ']') {
                    517:                                        if (ok)
                    518:                                                break;
                    519:                                        return (0);
                    520:                                }
1.2       dm        521:                                if (cc == QUOTECHAR) cc = *p++;
1.1       deraadt   522:                                if (cc == '-') {
1.2       dm        523:                                        if (lc <= scc && scc <= (int)*p++)
1.1       deraadt   524:                                                ok++;
                    525:                                } else
                    526:                                        if (scc == (lc = cc))
                    527:                                                ok++;
                    528:                        }
                    529:                        if (cc == 0) {
                    530:                                yyerror("Missing ']'");
                    531:                                return (0);
                    532:                        }
                    533:                        continue;
                    534:
                    535:                case '*':
                    536:                        if (!*p)
                    537:                                return (1);
                    538:                        if (*p == '/') {
                    539:                                p++;
                    540:                                goto slash;
                    541:                        }
                    542:                        for (s--; *s; s++)
                    543:                                if (amatch(s, p))
                    544:                                        return (1);
                    545:                        return (0);
                    546:
1.2       dm        547:                case CNULL:
                    548:                        return (scc == CNULL);
1.1       deraadt   549:
                    550:                default:
1.2       dm        551:                        if (c != scc)
1.1       deraadt   552:                                return (0);
                    553:                        continue;
                    554:
                    555:                case '?':
1.2       dm        556:                        if (scc == CNULL)
1.1       deraadt   557:                                return (0);
                    558:                        continue;
                    559:
                    560:                case '/':
                    561:                        if (scc)
                    562:                                return (0);
                    563: slash:
                    564:                        s = entp;
                    565:                        spathp = pathp;
                    566:                        while (*s)
                    567:                                addpath(*s++);
                    568:                        addpath('/');
1.10      millert   569:                        if (stat(path, &stb) == 0 && S_ISDIR(stb.st_mode)) {
1.2       dm        570:                                if (*p == CNULL) {
1.10      millert   571:                                        if (which & E_TILDE) {
1.2       dm        572:                                                Cat((u_char *)path,
                    573:                                                    (u_char *)"");
1.10      millert   574:                                        } else {
1.2       dm        575:                                                Cat((u_char *)tilde,
                    576:                                                    (u_char *)tpathp);
1.10      millert   577:                                        }
                    578:                                } else
1.1       deraadt   579:                                        expsh(p);
1.10      millert   580:                        }
1.1       deraadt   581:                        pathp = spathp;
1.2       dm        582:                        *pathp = CNULL;
1.1       deraadt   583:                        return (0);
                    584:                }
                    585:        }
                    586: }