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

Annotation of src/usr.bin/find/function.c, Revision 1.2

1.1       deraadt     1: /*-
                      2:  * Copyright (c) 1990, 1993
                      3:  *     The Regents of the University of California.  All rights reserved.
                      4:  *
                      5:  * This code is derived from software contributed to Berkeley by
                      6:  * Cimarron D. Taylor of the University of California, Berkeley.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
                     16:  * 3. All advertising materials mentioning features or use of this software
                     17:  *    must display the following acknowledgement:
                     18:  *     This product includes software developed by the University of
                     19:  *     California, Berkeley and its contributors.
                     20:  * 4. Neither the name of the University nor the names of its contributors
                     21:  *    may be used to endorse or promote products derived from this software
                     22:  *    without specific prior written permission.
                     23:  *
                     24:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     25:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     26:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     27:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     28:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     29:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     30:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     33:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     34:  * SUCH DAMAGE.
                     35:  */
                     36:
                     37: #ifndef lint
                     38: /*static char sccsid[] = "from: @(#)function.c 8.1 (Berkeley) 6/6/93";*/
1.2     ! deraadt    39: static char rcsid[] = "$Id: function.c,v 1.1.1.1 1995/10/18 08:45:13 deraadt Exp $";
1.1       deraadt    40: #endif /* not lint */
                     41:
                     42: #include <sys/param.h>
                     43: #include <sys/ucred.h>
                     44: #include <sys/stat.h>
                     45: #include <sys/wait.h>
                     46: #include <sys/mount.h>
                     47:
                     48: #include <err.h>
                     49: #include <errno.h>
                     50: #include <fnmatch.h>
                     51: #include <fts.h>
                     52: #include <grp.h>
                     53: #include <pwd.h>
                     54: #include <stdio.h>
                     55: #include <stdlib.h>
                     56: #include <string.h>
                     57: #include <tzfile.h>
                     58: #include <unistd.h>
                     59:
                     60: #include "find.h"
                     61:
                     62: #define        COMPARE(a, b) {                                                 \
                     63:        switch (plan->flags) {                                          \
                     64:        case F_EQUAL:                                                   \
                     65:                return (a == b);                                        \
                     66:        case F_LESSTHAN:                                                \
                     67:                return (a < b);                                         \
                     68:        case F_GREATER:                                                 \
                     69:                return (a > b);                                         \
                     70:        default:                                                        \
                     71:                abort();                                                \
                     72:        }                                                               \
                     73: }
                     74:
                     75: static PLAN *palloc __P((enum ntype, int (*) __P((PLAN *, FTSENT *))));
                     76:
                     77: /*
                     78:  * find_parsenum --
                     79:  *     Parse a string of the form [+-]# and return the value.
                     80:  */
                     81: static long
                     82: find_parsenum(plan, option, vp, endch)
                     83:        PLAN *plan;
                     84:        char *option, *vp, *endch;
                     85: {
                     86:        long value;
                     87:        char *endchar, *str;    /* Pointer to character ending conversion. */
                     88:
                     89:        /* Determine comparison from leading + or -. */
                     90:        str = vp;
                     91:        switch (*str) {
                     92:        case '+':
                     93:                ++str;
                     94:                plan->flags = F_GREATER;
                     95:                break;
                     96:        case '-':
                     97:                ++str;
                     98:                plan->flags = F_LESSTHAN;
                     99:                break;
                    100:        default:
                    101:                plan->flags = F_EQUAL;
                    102:                break;
                    103:        }
                    104:
                    105:        /*
                    106:         * Convert the string with strtol().  Note, if strtol() returns zero
                    107:         * and endchar points to the beginning of the string we know we have
                    108:         * a syntax error.
                    109:         */
                    110:        value = strtol(str, &endchar, 10);
                    111:        if (value == 0 && endchar == str)
                    112:                errx(1, "%s: %s: illegal numeric value", option, vp);
                    113:        if (endchar[0] && (endch == NULL || endchar[0] != *endch))
                    114:                errx(1, "%s: %s: illegal trailing character", option, vp);
                    115:        if (endch)
                    116:                *endch = endchar[0];
                    117:        return (value);
                    118: }
                    119:
                    120: /*
                    121:  * The value of n for the inode times (atime, ctime, and mtime) is a range,
                    122:  * i.e. n matches from (n - 1) to n 24 hour periods.  This interacts with
                    123:  * -n, such that "-mtime -1" would be less than 0 days, which isn't what the
                    124:  * user wanted.  Correct so that -1 is "less than 1".
                    125:  */
                    126: #define        TIME_CORRECT(p, ttype)                                          \
                    127:        if ((p)->type == ttype && (p)->flags == F_LESSTHAN)             \
                    128:                ++((p)->t_data);
                    129:
                    130: /*
                    131:  * -atime n functions --
                    132:  *
                    133:  *     True if the difference between the file access time and the
                    134:  *     current time is n 24 hour periods.
                    135:  */
                    136: int
                    137: f_atime(plan, entry)
                    138:        PLAN *plan;
                    139:        FTSENT *entry;
                    140: {
                    141:        extern time_t now;
                    142:
                    143:        COMPARE((now - entry->fts_statp->st_atime +
                    144:            SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
                    145: }
                    146:
                    147: PLAN *
                    148: c_atime(arg)
                    149:        char *arg;
                    150: {
                    151:        PLAN *new;
                    152:
                    153:        ftsoptions &= ~FTS_NOSTAT;
                    154:
                    155:        new = palloc(N_ATIME, f_atime);
                    156:        new->t_data = find_parsenum(new, "-atime", arg, NULL);
                    157:        TIME_CORRECT(new, N_ATIME);
                    158:        return (new);
                    159: }
                    160: /*
                    161:  * -ctime n functions --
                    162:  *
                    163:  *     True if the difference between the last change of file
                    164:  *     status information and the current time is n 24 hour periods.
                    165:  */
                    166: int
                    167: f_ctime(plan, entry)
                    168:        PLAN *plan;
                    169:        FTSENT *entry;
                    170: {
                    171:        extern time_t now;
                    172:
                    173:        COMPARE((now - entry->fts_statp->st_ctime +
                    174:            SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
                    175: }
                    176:
                    177: PLAN *
                    178: c_ctime(arg)
                    179:        char *arg;
                    180: {
                    181:        PLAN *new;
                    182:
                    183:        ftsoptions &= ~FTS_NOSTAT;
                    184:
                    185:        new = palloc(N_CTIME, f_ctime);
                    186:        new->t_data = find_parsenum(new, "-ctime", arg, NULL);
                    187:        TIME_CORRECT(new, N_CTIME);
                    188:        return (new);
                    189: }
                    190:
                    191: /*
                    192:  * -depth functions --
                    193:  *
                    194:  *     Always true, causes descent of the directory hierarchy to be done
                    195:  *     so that all entries in a directory are acted on before the directory
                    196:  *     itself.
                    197:  */
                    198: int
                    199: f_always_true(plan, entry)
                    200:        PLAN *plan;
                    201:        FTSENT *entry;
                    202: {
                    203:        return (1);
                    204: }
                    205:
                    206: PLAN *
                    207: c_depth()
                    208: {
                    209:        isdepth = 1;
                    210:
                    211:        return (palloc(N_DEPTH, f_always_true));
                    212: }
                    213:
                    214: /*
                    215:  * [-exec | -ok] utility [arg ... ] ; functions --
                    216:  *
                    217:  *     True if the executed utility returns a zero value as exit status.
                    218:  *     The end of the primary expression is delimited by a semicolon.  If
                    219:  *     "{}" occurs anywhere, it gets replaced by the current pathname.
                    220:  *     The current directory for the execution of utility is the same as
                    221:  *     the current directory when the find utility was started.
                    222:  *
                    223:  *     The primary -ok is different in that it requests affirmation of the
                    224:  *     user before executing the utility.
                    225:  */
                    226: int
                    227: f_exec(plan, entry)
                    228:        register PLAN *plan;
                    229:        FTSENT *entry;
                    230: {
                    231:        extern int dotfd;
                    232:        register int cnt;
                    233:        pid_t pid;
                    234:        int status;
                    235:
                    236:        for (cnt = 0; plan->e_argv[cnt]; ++cnt)
                    237:                if (plan->e_len[cnt])
                    238:                        brace_subst(plan->e_orig[cnt], &plan->e_argv[cnt],
                    239:                            entry->fts_path, plan->e_len[cnt]);
                    240:
                    241:        if (plan->flags == F_NEEDOK && !queryuser(plan->e_argv))
                    242:                return (0);
                    243:
                    244:        /* don't mix output of command with find output */
                    245:        fflush(stdout);
                    246:        fflush(stderr);
                    247:
                    248:        switch (pid = vfork()) {
                    249:        case -1:
                    250:                err(1, "fork");
                    251:                /* NOTREACHED */
                    252:        case 0:
                    253:                if (fchdir(dotfd)) {
                    254:                        warn("chdir");
                    255:                        _exit(1);
                    256:                }
                    257:                execvp(plan->e_argv[0], plan->e_argv);
                    258:                warn("%s", plan->e_argv[0]);
                    259:                _exit(1);
                    260:        }
                    261:        pid = waitpid(pid, &status, 0);
                    262:        return (pid != -1 && WIFEXITED(status) && !WEXITSTATUS(status));
                    263: }
                    264:
                    265: /*
                    266:  * c_exec --
                    267:  *     build three parallel arrays, one with pointers to the strings passed
                    268:  *     on the command line, one with (possibly duplicated) pointers to the
                    269:  *     argv array, and one with integer values that are lengths of the
                    270:  *     strings, but also flags meaning that the string has to be massaged.
                    271:  */
                    272: PLAN *
                    273: c_exec(argvp, isok)
                    274:        char ***argvp;
                    275:        int isok;
                    276: {
                    277:        PLAN *new;                      /* node returned */
                    278:        register int cnt;
                    279:        register char **argv, **ap, *p;
                    280:
                    281:        isoutput = 1;
                    282:
                    283:        new = palloc(N_EXEC, f_exec);
                    284:        if (isok)
                    285:                new->flags = F_NEEDOK;
                    286:
                    287:        for (ap = argv = *argvp;; ++ap) {
                    288:                if (!*ap)
                    289:                        errx(1,
                    290:                            "%s: no terminating \";\"", isok ? "-ok" : "-exec");
                    291:                if (**ap == ';')
                    292:                        break;
                    293:        }
                    294:
                    295:        cnt = ap - *argvp + 1;
                    296:        new->e_argv = (char **)emalloc((u_int)cnt * sizeof(char *));
                    297:        new->e_orig = (char **)emalloc((u_int)cnt * sizeof(char *));
                    298:        new->e_len = (int *)emalloc((u_int)cnt * sizeof(int));
                    299:
                    300:        for (argv = *argvp, cnt = 0; argv < ap; ++argv, ++cnt) {
                    301:                new->e_orig[cnt] = *argv;
                    302:                for (p = *argv; *p; ++p)
                    303:                        if (p[0] == '{' && p[1] == '}') {
                    304:                                new->e_argv[cnt] = emalloc((u_int)MAXPATHLEN);
                    305:                                new->e_len[cnt] = MAXPATHLEN;
                    306:                                break;
                    307:                        }
                    308:                if (!*p) {
                    309:                        new->e_argv[cnt] = *argv;
                    310:                        new->e_len[cnt] = 0;
                    311:                }
                    312:        }
                    313:        new->e_argv[cnt] = new->e_orig[cnt] = NULL;
                    314:
                    315:        *argvp = argv + 1;
                    316:        return (new);
                    317: }
                    318:
                    319: /*
                    320:  * -follow functions --
                    321:  *
                    322:  *     Always true, causes symbolic links to be followed on a global
                    323:  *     basis.
                    324:  */
                    325: PLAN *
                    326: c_follow()
                    327: {
                    328:        ftsoptions &= ~FTS_PHYSICAL;
                    329:        ftsoptions |= FTS_LOGICAL;
                    330:
                    331:        return (palloc(N_FOLLOW, f_always_true));
                    332: }
                    333:
                    334: /*
                    335:  * -fstype functions --
                    336:  *
                    337:  *     True if the file is of a certain type.
                    338:  */
                    339: int
                    340: f_fstype(plan, entry)
                    341:        PLAN *plan;
                    342:        FTSENT *entry;
                    343: {
                    344:        static dev_t curdev;    /* need a guaranteed illegal dev value */
                    345:        static int first = 1;
                    346:        struct statfs sb;
                    347:        static short val;
                    348:        static char fstype[MFSNAMELEN];
                    349:        char *p, save[2];
                    350:
                    351:        /* Only check when we cross mount point. */
                    352:        if (first || curdev != entry->fts_statp->st_dev) {
                    353:                curdev = entry->fts_statp->st_dev;
                    354:
                    355:                /*
                    356:                 * Statfs follows symlinks; find wants the link's file system,
                    357:                 * not where it points.
                    358:                 */
                    359:                if (entry->fts_info == FTS_SL ||
                    360:                    entry->fts_info == FTS_SLNONE) {
                    361:                        if (p = strrchr(entry->fts_accpath, '/'))
                    362:                                ++p;
                    363:                        else
                    364:                                p = entry->fts_accpath;
                    365:                        save[0] = p[0];
                    366:                        p[0] = '.';
                    367:                        save[1] = p[1];
                    368:                        p[1] = '\0';
                    369:
                    370:                } else
                    371:                        p = NULL;
                    372:
                    373:                if (statfs(entry->fts_accpath, &sb))
                    374:                        err(1, "%s", entry->fts_accpath);
                    375:
                    376:                if (p) {
                    377:                        p[0] = save[0];
                    378:                        p[1] = save[1];
                    379:                }
                    380:
                    381:                first = 0;
                    382:
                    383:                /*
                    384:                 * Further tests may need both of these values, so
                    385:                 * always copy both of them.
                    386:                 */
                    387:                val = sb.f_flags;
                    388:                strncpy(fstype, sb.f_fstypename, MFSNAMELEN);
                    389:        }
                    390:        switch (plan->flags) {
                    391:        case F_MTFLAG:
                    392:                return (val & plan->mt_data);
                    393:        case F_MTTYPE:
                    394:                return (strncmp(fstype, plan->c_data, MFSNAMELEN) == 0);
                    395:        default:
                    396:                abort();
                    397:        }
                    398: }
                    399:
                    400: PLAN *
                    401: c_fstype(arg)
                    402:        char *arg;
                    403: {
                    404:        register PLAN *new;
                    405:
                    406:        ftsoptions &= ~FTS_NOSTAT;
                    407:
                    408:        new = palloc(N_FSTYPE, f_fstype);
                    409:        switch (*arg) {
                    410:        case 'l':
                    411:                if (!strcmp(arg, "local")) {
                    412:                        new->flags = F_MTFLAG;
                    413:                        new->mt_data = MNT_LOCAL;
                    414:                        return (new);
                    415:                }
                    416:                break;
                    417:        case 'r':
                    418:                if (!strcmp(arg, "rdonly")) {
                    419:                        new->flags = F_MTFLAG;
                    420:                        new->mt_data = MNT_RDONLY;
                    421:                        return (new);
                    422:                }
                    423:                break;
                    424:        }
                    425:
                    426:        new->flags = F_MTTYPE;
                    427:        new->c_data = arg;
                    428:        return (new);
                    429: }
                    430:
                    431: /*
                    432:  * -group gname functions --
                    433:  *
                    434:  *     True if the file belongs to the group gname.  If gname is numeric and
                    435:  *     an equivalent of the getgrnam() function does not return a valid group
                    436:  *     name, gname is taken as a group ID.
                    437:  */
                    438: int
                    439: f_group(plan, entry)
                    440:        PLAN *plan;
                    441:        FTSENT *entry;
                    442: {
                    443:        return (entry->fts_statp->st_gid == plan->g_data);
                    444: }
                    445:
                    446: PLAN *
                    447: c_group(gname)
                    448:        char *gname;
                    449: {
                    450:        PLAN *new;
                    451:        struct group *g;
                    452:        gid_t gid;
                    453:
                    454:        ftsoptions &= ~FTS_NOSTAT;
                    455:
                    456:        g = getgrnam(gname);
                    457:        if (g == NULL) {
                    458:                gid = atoi(gname);
                    459:                if (gid == 0 && gname[0] != '0')
                    460:                        errx(1, "-group: %s: no such group", gname);
                    461:        } else
                    462:                gid = g->gr_gid;
                    463:
                    464:        new = palloc(N_GROUP, f_group);
                    465:        new->g_data = gid;
                    466:        return (new);
                    467: }
                    468:
                    469: /*
                    470:  * -inum n functions --
                    471:  *
                    472:  *     True if the file has inode # n.
                    473:  */
                    474: int
                    475: f_inum(plan, entry)
                    476:        PLAN *plan;
                    477:        FTSENT *entry;
                    478: {
                    479:        COMPARE(entry->fts_statp->st_ino, plan->i_data);
                    480: }
                    481:
                    482: PLAN *
                    483: c_inum(arg)
                    484:        char *arg;
                    485: {
                    486:        PLAN *new;
                    487:
                    488:        ftsoptions &= ~FTS_NOSTAT;
                    489:
                    490:        new = palloc(N_INUM, f_inum);
                    491:        new->i_data = find_parsenum(new, "-inum", arg, NULL);
                    492:        return (new);
                    493: }
                    494:
                    495: /*
                    496:  * -links n functions --
                    497:  *
                    498:  *     True if the file has n links.
                    499:  */
                    500: int
                    501: f_links(plan, entry)
                    502:        PLAN *plan;
                    503:        FTSENT *entry;
                    504: {
                    505:        COMPARE(entry->fts_statp->st_nlink, plan->l_data);
                    506: }
                    507:
                    508: PLAN *
                    509: c_links(arg)
                    510:        char *arg;
                    511: {
                    512:        PLAN *new;
                    513:
                    514:        ftsoptions &= ~FTS_NOSTAT;
                    515:
                    516:        new = palloc(N_LINKS, f_links);
                    517:        new->l_data = (nlink_t)find_parsenum(new, "-links", arg, NULL);
                    518:        return (new);
                    519: }
                    520:
                    521: /*
                    522:  * -ls functions --
                    523:  *
                    524:  *     Always true - prints the current entry to stdout in "ls" format.
                    525:  */
                    526: int
                    527: f_ls(plan, entry)
                    528:        PLAN *plan;
                    529:        FTSENT *entry;
                    530: {
                    531:        printlong(entry->fts_path, entry->fts_accpath, entry->fts_statp);
                    532:        return (1);
                    533: }
                    534:
                    535: PLAN *
                    536: c_ls()
                    537: {
                    538:        ftsoptions &= ~FTS_NOSTAT;
                    539:        isoutput = 1;
                    540:
                    541:        return (palloc(N_LS, f_ls));
                    542: }
                    543:
                    544: /*
                    545:  * -mtime n functions --
                    546:  *
                    547:  *     True if the difference between the file modification time and the
                    548:  *     current time is n 24 hour periods.
                    549:  */
                    550: int
                    551: f_mtime(plan, entry)
                    552:        PLAN *plan;
                    553:        FTSENT *entry;
                    554: {
                    555:        extern time_t now;
                    556:
                    557:        COMPARE((now - entry->fts_statp->st_mtime + SECSPERDAY - 1) /
                    558:            SECSPERDAY, plan->t_data);
                    559: }
                    560:
                    561: PLAN *
                    562: c_mtime(arg)
                    563:        char *arg;
                    564: {
                    565:        PLAN *new;
                    566:
                    567:        ftsoptions &= ~FTS_NOSTAT;
                    568:
                    569:        new = palloc(N_MTIME, f_mtime);
                    570:        new->t_data = find_parsenum(new, "-mtime", arg, NULL);
                    571:        TIME_CORRECT(new, N_MTIME);
                    572:        return (new);
                    573: }
                    574:
                    575: /*
                    576:  * -name functions --
                    577:  *
                    578:  *     True if the basename of the filename being examined
                    579:  *     matches pattern using Pattern Matching Notation S3.14
                    580:  */
                    581: int
                    582: f_name(plan, entry)
                    583:        PLAN *plan;
                    584:        FTSENT *entry;
                    585: {
                    586:        return (!fnmatch(plan->c_data, entry->fts_name, 0));
                    587: }
                    588:
                    589: PLAN *
                    590: c_name(pattern)
                    591:        char *pattern;
                    592: {
                    593:        PLAN *new;
                    594:
                    595:        new = palloc(N_NAME, f_name);
                    596:        new->c_data = pattern;
                    597:        return (new);
                    598: }
                    599:
                    600: /*
                    601:  * -newer file functions --
                    602:  *
                    603:  *     True if the current file has been modified more recently
                    604:  *     then the modification time of the file named by the pathname
                    605:  *     file.
                    606:  */
                    607: int
                    608: f_newer(plan, entry)
                    609:        PLAN *plan;
                    610:        FTSENT *entry;
                    611: {
                    612:        return (entry->fts_statp->st_mtime > plan->t_data);
                    613: }
                    614:
                    615: PLAN *
                    616: c_newer(filename)
                    617:        char *filename;
                    618: {
                    619:        PLAN *new;
                    620:        struct stat sb;
                    621:
                    622:        ftsoptions &= ~FTS_NOSTAT;
                    623:
                    624:        if (stat(filename, &sb))
                    625:                err(1, "%s", filename);
                    626:        new = palloc(N_NEWER, f_newer);
                    627:        new->t_data = sb.st_mtime;
                    628:        return (new);
                    629: }
                    630:
                    631: /*
                    632:  * -nogroup functions --
                    633:  *
                    634:  *     True if file belongs to a user ID for which the equivalent
                    635:  *     of the getgrnam() 9.2.1 [POSIX.1] function returns NULL.
                    636:  */
                    637: int
                    638: f_nogroup(plan, entry)
                    639:        PLAN *plan;
                    640:        FTSENT *entry;
                    641: {
                    642:        char *group_from_gid();
                    643:
                    644:        return (group_from_gid(entry->fts_statp->st_gid, 1) ? 0 : 1);
                    645: }
                    646:
                    647: PLAN *
                    648: c_nogroup()
                    649: {
                    650:        ftsoptions &= ~FTS_NOSTAT;
                    651:
                    652:        return (palloc(N_NOGROUP, f_nogroup));
                    653: }
                    654:
                    655: /*
                    656:  * -nouser functions --
                    657:  *
                    658:  *     True if file belongs to a user ID for which the equivalent
                    659:  *     of the getpwuid() 9.2.2 [POSIX.1] function returns NULL.
                    660:  */
                    661: int
                    662: f_nouser(plan, entry)
                    663:        PLAN *plan;
                    664:        FTSENT *entry;
                    665: {
                    666:        char *user_from_uid();
                    667:
                    668:        return (user_from_uid(entry->fts_statp->st_uid, 1) ? 0 : 1);
                    669: }
                    670:
                    671: PLAN *
                    672: c_nouser()
                    673: {
                    674:        ftsoptions &= ~FTS_NOSTAT;
                    675:
                    676:        return (palloc(N_NOUSER, f_nouser));
                    677: }
                    678:
                    679: /*
                    680:  * -path functions --
                    681:  *
                    682:  *     True if the path of the filename being examined
                    683:  *     matches pattern using Pattern Matching Notation S3.14
                    684:  */
                    685: int
                    686: f_path(plan, entry)
                    687:        PLAN *plan;
                    688:        FTSENT *entry;
                    689: {
                    690:        return (!fnmatch(plan->c_data, entry->fts_path, 0));
                    691: }
                    692:
                    693: PLAN *
                    694: c_path(pattern)
                    695:        char *pattern;
                    696: {
                    697:        PLAN *new;
                    698:
                    699:        new = palloc(N_NAME, f_path);
                    700:        new->c_data = pattern;
                    701:        return (new);
                    702: }
                    703:
                    704: /*
                    705:  * -perm functions --
                    706:  *
                    707:  *     The mode argument is used to represent file mode bits.  If it starts
                    708:  *     with a leading digit, it's treated as an octal mode, otherwise as a
                    709:  *     symbolic mode.
                    710:  */
                    711: int
                    712: f_perm(plan, entry)
                    713:        PLAN *plan;
                    714:        FTSENT *entry;
                    715: {
                    716:        mode_t mode;
                    717:
                    718:        mode = entry->fts_statp->st_mode &
                    719:            (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO);
                    720:        if (plan->flags == F_ATLEAST)
                    721:                return ((plan->m_data | mode) == mode);
                    722:        else
                    723:                return (mode == plan->m_data);
                    724:        /* NOTREACHED */
                    725: }
                    726:
                    727: PLAN *
                    728: c_perm(perm)
                    729:        char *perm;
                    730: {
                    731:        PLAN *new;
                    732:        mode_t *set;
                    733:
                    734:        ftsoptions &= ~FTS_NOSTAT;
                    735:
                    736:        new = palloc(N_PERM, f_perm);
                    737:
                    738:        if (*perm == '-') {
                    739:                new->flags = F_ATLEAST;
                    740:                ++perm;
                    741:        }
                    742:
                    743:        if ((set = setmode(perm)) == NULL)
                    744:                err(1, "-perm: %s: illegal mode string", perm);
                    745:
                    746:        new->m_data = getmode(set, 0);
                    747:        return (new);
                    748: }
                    749:
                    750: /*
                    751:  * -print functions --
                    752:  *
                    753:  *     Always true, causes the current pathame to be written to
                    754:  *     standard output.
                    755:  */
                    756: int
                    757: f_print(plan, entry)
                    758:        PLAN *plan;
                    759:        FTSENT *entry;
                    760: {
                    761:        (void)printf("%s\n", entry->fts_path);
                    762:        return(1);
                    763: }
                    764:
                    765: /* ARGSUSED */
                    766: f_print0(plan, entry)
                    767:        PLAN *plan;
                    768:        FTSENT *entry;
                    769: {
                    770:        (void)fputs(entry->fts_path, stdout);
                    771:        (void)fputc('\0', stdout);
                    772:        return(1);
                    773: }
                    774:
                    775: PLAN *
                    776: c_print()
                    777: {
                    778:        isoutput = 1;
                    779:
                    780:        return(palloc(N_PRINT, f_print));
                    781: }
                    782:
                    783: PLAN *
                    784: c_print0()
                    785: {
                    786:        isoutput = 1;
                    787:
                    788:        return(palloc(N_PRINT0, f_print0));
                    789: }
                    790:
                    791: /*
                    792:  * -prune functions --
                    793:  *
                    794:  *     Prune a portion of the hierarchy.
                    795:  */
                    796: int
                    797: f_prune(plan, entry)
                    798:        PLAN *plan;
                    799:        FTSENT *entry;
                    800: {
                    801:        extern FTS *tree;
                    802:
                    803:        if (fts_set(tree, entry, FTS_SKIP))
                    804:                err(1, "%s", entry->fts_path);
                    805:        return (1);
                    806: }
                    807:
                    808: PLAN *
                    809: c_prune()
                    810: {
                    811:        return (palloc(N_PRUNE, f_prune));
                    812: }
                    813:
                    814: /*
                    815:  * -size n[c] functions --
                    816:  *
                    817:  *     True if the file size in bytes, divided by an implementation defined
                    818:  *     value and rounded up to the next integer, is n.  If n is followed by
                    819:  *     a c, the size is in bytes.
                    820:  */
                    821: #define        FIND_SIZE       512
                    822: static int divsize = 1;
                    823:
                    824: int
                    825: f_size(plan, entry)
                    826:        PLAN *plan;
                    827:        FTSENT *entry;
                    828: {
                    829:        off_t size;
                    830:
                    831:        size = divsize ? (entry->fts_statp->st_size + FIND_SIZE - 1) /
                    832:            FIND_SIZE : entry->fts_statp->st_size;
                    833:        COMPARE(size, plan->o_data);
                    834: }
                    835:
                    836: PLAN *
                    837: c_size(arg)
                    838:        char *arg;
                    839: {
                    840:        PLAN *new;
                    841:        char endch;
                    842:
                    843:        ftsoptions &= ~FTS_NOSTAT;
                    844:
                    845:        new = palloc(N_SIZE, f_size);
                    846:        endch = 'c';
                    847:        new->o_data = find_parsenum(new, "-size", arg, &endch);
                    848:        if (endch == 'c')
                    849:                divsize = 0;
                    850:        return (new);
                    851: }
                    852:
                    853: /*
                    854:  * -type c functions --
                    855:  *
                    856:  *     True if the type of the file is c, where c is b, c, d, p, or f for
                    857:  *     block special file, character special file, directory, FIFO, or
                    858:  *     regular file, respectively.
                    859:  */
                    860: int
                    861: f_type(plan, entry)
                    862:        PLAN *plan;
                    863:        FTSENT *entry;
                    864: {
                    865:        return ((entry->fts_statp->st_mode & S_IFMT) == plan->m_data);
                    866: }
                    867:
                    868: PLAN *
                    869: c_type(typestring)
                    870:        char *typestring;
                    871: {
                    872:        PLAN *new;
                    873:        mode_t  mask;
                    874:
                    875:        ftsoptions &= ~FTS_NOSTAT;
                    876:
                    877:        switch (typestring[0]) {
1.2     ! deraadt   878: #ifdef S_IFWHT
        !           879:       case 'W':
        !           880:               mask = S_IFWHT;
        !           881:               break;
        !           882: #endif
1.1       deraadt   883:        case 'b':
                    884:                mask = S_IFBLK;
                    885:                break;
                    886:        case 'c':
                    887:                mask = S_IFCHR;
                    888:                break;
                    889:        case 'd':
                    890:                mask = S_IFDIR;
                    891:                break;
                    892:        case 'f':
                    893:                mask = S_IFREG;
                    894:                break;
                    895:        case 'l':
                    896:                mask = S_IFLNK;
                    897:                break;
                    898:        case 'p':
                    899:                mask = S_IFIFO;
                    900:                break;
                    901:        case 's':
                    902:                mask = S_IFSOCK;
                    903:                break;
                    904:        default:
                    905:                errx(1, "-type: %s: unknown type", typestring);
                    906:        }
                    907:
                    908:        new = palloc(N_TYPE, f_type);
                    909:        new->m_data = mask;
                    910:        return (new);
                    911: }
                    912:
                    913: /*
                    914:  * -user uname functions --
                    915:  *
                    916:  *     True if the file belongs to the user uname.  If uname is numeric and
                    917:  *     an equivalent of the getpwnam() S9.2.2 [POSIX.1] function does not
                    918:  *     return a valid user name, uname is taken as a user ID.
                    919:  */
                    920: int
                    921: f_user(plan, entry)
                    922:        PLAN *plan;
                    923:        FTSENT *entry;
                    924: {
                    925:        return (entry->fts_statp->st_uid == plan->u_data);
                    926: }
                    927:
                    928: PLAN *
                    929: c_user(username)
                    930:        char *username;
                    931: {
                    932:        PLAN *new;
                    933:        struct passwd *p;
                    934:        uid_t uid;
                    935:
                    936:        ftsoptions &= ~FTS_NOSTAT;
                    937:
                    938:        p = getpwnam(username);
                    939:        if (p == NULL) {
                    940:                uid = atoi(username);
                    941:                if (uid == 0 && username[0] != '0')
                    942:                        errx(1, "-user: %s: no such user", username);
                    943:        } else
                    944:                uid = p->pw_uid;
                    945:
                    946:        new = palloc(N_USER, f_user);
                    947:        new->u_data = uid;
                    948:        return (new);
                    949: }
                    950:
                    951: /*
                    952:  * -xdev functions --
                    953:  *
                    954:  *     Always true, causes find not to decend past directories that have a
                    955:  *     different device ID (st_dev, see stat() S5.6.2 [POSIX.1])
                    956:  */
                    957: PLAN *
                    958: c_xdev()
                    959: {
                    960:        ftsoptions |= FTS_XDEV;
                    961:
                    962:        return (palloc(N_XDEV, f_always_true));
                    963: }
                    964:
                    965: /*
                    966:  * ( expression ) functions --
                    967:  *
                    968:  *     True if expression is true.
                    969:  */
                    970: int
                    971: f_expr(plan, entry)
                    972:        PLAN *plan;
                    973:        FTSENT *entry;
                    974: {
                    975:        register PLAN *p;
                    976:        register int state;
                    977:
                    978:        for (p = plan->p_data[0];
                    979:            p && (state = (p->eval)(p, entry)); p = p->next);
                    980:        return (state);
                    981: }
                    982:
                    983: /*
                    984:  * N_OPENPAREN and N_CLOSEPAREN nodes are temporary place markers.  They are
                    985:  * eliminated during phase 2 of find_formplan() --- the '(' node is converted
                    986:  * to a N_EXPR node containing the expression and the ')' node is discarded.
                    987:  */
                    988: PLAN *
                    989: c_openparen()
                    990: {
                    991:        return (palloc(N_OPENPAREN, (int (*)())-1));
                    992: }
                    993:
                    994: PLAN *
                    995: c_closeparen()
                    996: {
                    997:        return (palloc(N_CLOSEPAREN, (int (*)())-1));
                    998: }
                    999:
                   1000: /*
                   1001:  * ! expression functions --
                   1002:  *
                   1003:  *     Negation of a primary; the unary NOT operator.
                   1004:  */
                   1005: int
                   1006: f_not(plan, entry)
                   1007:        PLAN *plan;
                   1008:        FTSENT *entry;
                   1009: {
                   1010:        register PLAN *p;
                   1011:        register int state;
                   1012:
                   1013:        for (p = plan->p_data[0];
                   1014:            p && (state = (p->eval)(p, entry)); p = p->next);
                   1015:        return (!state);
                   1016: }
                   1017:
                   1018: PLAN *
                   1019: c_not()
                   1020: {
                   1021:        return (palloc(N_NOT, f_not));
                   1022: }
                   1023:
                   1024: /*
                   1025:  * expression -o expression functions --
                   1026:  *
                   1027:  *     Alternation of primaries; the OR operator.  The second expression is
                   1028:  * not evaluated if the first expression is true.
                   1029:  */
                   1030: int
                   1031: f_or(plan, entry)
                   1032:        PLAN *plan;
                   1033:        FTSENT *entry;
                   1034: {
                   1035:        register PLAN *p;
                   1036:        register int state;
                   1037:
                   1038:        for (p = plan->p_data[0];
                   1039:            p && (state = (p->eval)(p, entry)); p = p->next);
                   1040:
                   1041:        if (state)
                   1042:                return (1);
                   1043:
                   1044:        for (p = plan->p_data[1];
                   1045:            p && (state = (p->eval)(p, entry)); p = p->next);
                   1046:        return (state);
                   1047: }
                   1048:
                   1049: PLAN *
                   1050: c_or()
                   1051: {
                   1052:        return (palloc(N_OR, f_or));
                   1053: }
                   1054:
                   1055: static PLAN *
                   1056: palloc(t, f)
                   1057:        enum ntype t;
                   1058:        int (*f) __P((PLAN *, FTSENT *));
                   1059: {
                   1060:        PLAN *new;
                   1061:
                   1062:        if (new = malloc(sizeof(PLAN))) {
                   1063:                new->type = t;
                   1064:                new->eval = f;
                   1065:                new->flags = 0;
                   1066:                new->next = NULL;
                   1067:                return (new);
                   1068:        }
                   1069:        err(1, NULL);
                   1070:        /* NOTREACHED */
                   1071: }