[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.18

1.18    ! deraadt     1: /*     $OpenBSD: function.c,v 1.17 1999/12/04 22:42:32 millert Exp $   */
1.4       deraadt     2:
1.1       deraadt     3: /*-
                      4:  * Copyright (c) 1990, 1993
                      5:  *     The Regents of the University of California.  All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to Berkeley by
                      8:  * Cimarron D. Taylor of the University of California, Berkeley.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  * 3. All advertising materials mentioning features or use of this software
                     19:  *    must display the following acknowledgement:
                     20:  *     This product includes software developed by the University of
                     21:  *     California, Berkeley and its contributors.
                     22:  * 4. Neither the name of the University nor the names of its contributors
                     23:  *    may be used to endorse or promote products derived from this software
                     24:  *    without specific prior written permission.
                     25:  *
                     26:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     27:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     28:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     29:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     30:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     31:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     32:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     33:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     34:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     35:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     36:  * SUCH DAMAGE.
                     37:  */
                     38:
                     39: #ifndef lint
                     40: /*static char sccsid[] = "from: @(#)function.c 8.1 (Berkeley) 6/6/93";*/
1.18    ! deraadt    41: static char rcsid[] = "$OpenBSD: function.c,v 1.17 1999/12/04 22:42:32 millert Exp $";
1.1       deraadt    42: #endif /* not lint */
                     43:
                     44: #include <sys/param.h>
                     45: #include <sys/ucred.h>
                     46: #include <sys/stat.h>
                     47: #include <sys/wait.h>
                     48: #include <sys/mount.h>
                     49:
1.7       tholo      50: #include <dirent.h>
1.1       deraadt    51: #include <err.h>
                     52: #include <errno.h>
1.15      millert    53: #include <fcntl.h>
1.1       deraadt    54: #include <fnmatch.h>
                     55: #include <fts.h>
                     56: #include <grp.h>
1.10      millert    57: #include <libgen.h>
1.1       deraadt    58: #include <pwd.h>
                     59: #include <stdio.h>
                     60: #include <stdlib.h>
                     61: #include <string.h>
                     62: #include <tzfile.h>
                     63: #include <unistd.h>
                     64:
                     65: #include "find.h"
                     66:
                     67: #define        COMPARE(a, b) {                                                 \
                     68:        switch (plan->flags) {                                          \
                     69:        case F_EQUAL:                                                   \
                     70:                return (a == b);                                        \
                     71:        case F_LESSTHAN:                                                \
                     72:                return (a < b);                                         \
                     73:        case F_GREATER:                                                 \
                     74:                return (a > b);                                         \
                     75:        default:                                                        \
                     76:                abort();                                                \
                     77:        }                                                               \
                     78: }
                     79:
                     80: static PLAN *palloc __P((enum ntype, int (*) __P((PLAN *, FTSENT *))));
                     81:
1.9       millert    82: extern int dotfd;
                     83: extern time_t now;
                     84: extern FTS *tree;
                     85:
1.1       deraadt    86: /*
                     87:  * find_parsenum --
                     88:  *     Parse a string of the form [+-]# and return the value.
                     89:  */
                     90: static long
                     91: find_parsenum(plan, option, vp, endch)
                     92:        PLAN *plan;
                     93:        char *option, *vp, *endch;
                     94: {
                     95:        long value;
                     96:        char *endchar, *str;    /* Pointer to character ending conversion. */
                     97:
                     98:        /* Determine comparison from leading + or -. */
                     99:        str = vp;
                    100:        switch (*str) {
                    101:        case '+':
                    102:                ++str;
                    103:                plan->flags = F_GREATER;
                    104:                break;
                    105:        case '-':
                    106:                ++str;
                    107:                plan->flags = F_LESSTHAN;
                    108:                break;
                    109:        default:
                    110:                plan->flags = F_EQUAL;
                    111:                break;
                    112:        }
                    113:
                    114:        /*
                    115:         * Convert the string with strtol().  Note, if strtol() returns zero
                    116:         * and endchar points to the beginning of the string we know we have
                    117:         * a syntax error.
                    118:         */
                    119:        value = strtol(str, &endchar, 10);
                    120:        if (value == 0 && endchar == str)
                    121:                errx(1, "%s: %s: illegal numeric value", option, vp);
                    122:        if (endchar[0] && (endch == NULL || endchar[0] != *endch))
                    123:                errx(1, "%s: %s: illegal trailing character", option, vp);
                    124:        if (endch)
                    125:                *endch = endchar[0];
                    126:        return (value);
                    127: }
                    128:
                    129: /*
                    130:  * The value of n for the inode times (atime, ctime, and mtime) is a range,
                    131:  * i.e. n matches from (n - 1) to n 24 hour periods.  This interacts with
                    132:  * -n, such that "-mtime -1" would be less than 0 days, which isn't what the
                    133:  * user wanted.  Correct so that -1 is "less than 1".
                    134:  */
                    135: #define        TIME_CORRECT(p, ttype)                                          \
                    136:        if ((p)->type == ttype && (p)->flags == F_LESSTHAN)             \
1.17      millert   137:                ++((p)->sec_data);
1.1       deraadt   138:
                    139: /*
1.11      deraadt   140:  * -amin n functions --
                    141:  *
                    142:  *     True if the difference between the file access time and the
                    143:  *     current time is n min periods.
                    144:  */
                    145: int
                    146: f_amin(plan, entry)
                    147:        PLAN *plan;
                    148:        FTSENT *entry;
                    149: {
                    150:        extern time_t now;
                    151:
                    152:        COMPARE((now - entry->fts_statp->st_atime +
1.17      millert   153:            60 - 1) / 60, plan->sec_data);
1.11      deraadt   154: }
                    155:
                    156: PLAN *
                    157: c_amin(arg)
                    158:        char *arg;
                    159: {
                    160:        PLAN *new;
                    161:
                    162:        ftsoptions &= ~FTS_NOSTAT;
                    163:
                    164:        new = palloc(N_AMIN, f_amin);
1.17      millert   165:        new->sec_data = find_parsenum(new, "-amin", arg, NULL);
1.11      deraadt   166:        TIME_CORRECT(new, N_AMIN);
                    167:        return (new);
                    168: }
                    169:
                    170: /*
1.1       deraadt   171:  * -atime n functions --
                    172:  *
                    173:  *     True if the difference between the file access time and the
                    174:  *     current time is n 24 hour periods.
                    175:  */
                    176: int
                    177: f_atime(plan, entry)
                    178:        PLAN *plan;
                    179:        FTSENT *entry;
                    180: {
                    181:
                    182:        COMPARE((now - entry->fts_statp->st_atime +
1.17      millert   183:            SECSPERDAY - 1) / SECSPERDAY, plan->sec_data);
1.1       deraadt   184: }
                    185:
                    186: PLAN *
                    187: c_atime(arg)
                    188:        char *arg;
                    189: {
                    190:        PLAN *new;
                    191:
                    192:        ftsoptions &= ~FTS_NOSTAT;
                    193:
                    194:        new = palloc(N_ATIME, f_atime);
1.17      millert   195:        new->sec_data = find_parsenum(new, "-atime", arg, NULL);
1.1       deraadt   196:        TIME_CORRECT(new, N_ATIME);
                    197:        return (new);
                    198: }
1.11      deraadt   199:
                    200: /*
                    201:  * -cmin n functions --
                    202:  *
                    203:  *     True if the difference between the last change of file
                    204:  *     status information and the current time is n min periods.
                    205:  */
                    206: int
                    207: f_cmin(plan, entry)
                    208:        PLAN *plan;
                    209:        FTSENT *entry;
                    210: {
                    211:        extern time_t now;
                    212:
                    213:        COMPARE((now - entry->fts_statp->st_ctime +
1.17      millert   214:            60 - 1) / 60, plan->sec_data);
1.11      deraadt   215: }
                    216:
                    217: PLAN *
                    218: c_cmin(arg)
                    219:        char *arg;
                    220: {
                    221:        PLAN *new;
                    222:
                    223:        ftsoptions &= ~FTS_NOSTAT;
                    224:
                    225:        new = palloc(N_CMIN, f_cmin);
1.17      millert   226:        new->sec_data = find_parsenum(new, "-cmin", arg, NULL);
1.11      deraadt   227:        TIME_CORRECT(new, N_CMIN);
                    228:        return (new);
                    229: }
                    230:
1.1       deraadt   231: /*
                    232:  * -ctime n functions --
                    233:  *
                    234:  *     True if the difference between the last change of file
                    235:  *     status information and the current time is n 24 hour periods.
                    236:  */
                    237: int
                    238: f_ctime(plan, entry)
                    239:        PLAN *plan;
                    240:        FTSENT *entry;
                    241: {
                    242:
                    243:        COMPARE((now - entry->fts_statp->st_ctime +
1.17      millert   244:            SECSPERDAY - 1) / SECSPERDAY, plan->sec_data);
1.1       deraadt   245: }
                    246:
                    247: PLAN *
                    248: c_ctime(arg)
                    249:        char *arg;
                    250: {
                    251:        PLAN *new;
                    252:
                    253:        ftsoptions &= ~FTS_NOSTAT;
                    254:
                    255:        new = palloc(N_CTIME, f_ctime);
1.17      millert   256:        new->sec_data = find_parsenum(new, "-ctime", arg, NULL);
1.1       deraadt   257:        TIME_CORRECT(new, N_CTIME);
                    258:        return (new);
                    259: }
                    260:
                    261: /*
                    262:  * -depth functions --
                    263:  *
                    264:  *     Always true, causes descent of the directory hierarchy to be done
                    265:  *     so that all entries in a directory are acted on before the directory
                    266:  *     itself.
                    267:  */
                    268: int
                    269: f_always_true(plan, entry)
                    270:        PLAN *plan;
                    271:        FTSENT *entry;
                    272: {
                    273:        return (1);
                    274: }
                    275:
                    276: PLAN *
                    277: c_depth()
                    278: {
                    279:        isdepth = 1;
                    280:
                    281:        return (palloc(N_DEPTH, f_always_true));
                    282: }
                    283:
1.7       tholo     284: /*
                    285:  * -empty functions --
                    286:  *
                    287:  *     True if the file or directory is empty
                    288:  */
                    289: int
                    290: f_empty(plan, entry)
                    291:        PLAN *plan;
                    292:        FTSENT *entry;
                    293: {
                    294:        if (S_ISREG(entry->fts_statp->st_mode) && entry->fts_statp->st_size == 0)
                    295:                return (1);
                    296:        if (S_ISDIR(entry->fts_statp->st_mode)) {
                    297:                struct dirent *dp;
                    298:                int empty;
                    299:                DIR *dir;
                    300:
                    301:                empty = 1;
                    302:                dir = opendir(entry->fts_accpath);
                    303:                if (dir == NULL)
                    304:                        err(1, "%s", entry->fts_accpath);
                    305:                for (dp = readdir(dir); dp; dp = readdir(dir))
                    306:                        if (dp->d_name[0] != '.' ||
                    307:                            (dp->d_name[1] != '\0' &&
                    308:                             (dp->d_name[1] != '.' || dp->d_name[2] != '\0'))) {
                    309:                                empty = 0;
                    310:                                break;
                    311:                        }
                    312:                closedir(dir);
                    313:                return (empty);
                    314:        }
                    315:        return (0);
                    316: }
                    317:
                    318: PLAN *
                    319: c_empty()
                    320: {
                    321:        ftsoptions &= ~FTS_NOSTAT;
                    322:
                    323:        return (palloc(N_EMPTY, f_empty));
                    324: }
                    325:
1.1       deraadt   326: /*
                    327:  * [-exec | -ok] utility [arg ... ] ; functions --
                    328:  *
                    329:  *     True if the executed utility returns a zero value as exit status.
                    330:  *     The end of the primary expression is delimited by a semicolon.  If
                    331:  *     "{}" occurs anywhere, it gets replaced by the current pathname.
                    332:  *     The current directory for the execution of utility is the same as
                    333:  *     the current directory when the find utility was started.
                    334:  *
                    335:  *     The primary -ok is different in that it requests affirmation of the
                    336:  *     user before executing the utility.
                    337:  */
                    338: int
                    339: f_exec(plan, entry)
                    340:        register PLAN *plan;
                    341:        FTSENT *entry;
                    342: {
                    343:        register int cnt;
                    344:        pid_t pid;
                    345:        int status;
                    346:
                    347:        for (cnt = 0; plan->e_argv[cnt]; ++cnt)
                    348:                if (plan->e_len[cnt])
                    349:                        brace_subst(plan->e_orig[cnt], &plan->e_argv[cnt],
                    350:                            entry->fts_path, plan->e_len[cnt]);
                    351:
                    352:        if (plan->flags == F_NEEDOK && !queryuser(plan->e_argv))
                    353:                return (0);
                    354:
                    355:        /* don't mix output of command with find output */
                    356:        fflush(stdout);
                    357:        fflush(stderr);
                    358:
                    359:        switch (pid = vfork()) {
                    360:        case -1:
                    361:                err(1, "fork");
                    362:                /* NOTREACHED */
                    363:        case 0:
                    364:                if (fchdir(dotfd)) {
                    365:                        warn("chdir");
                    366:                        _exit(1);
                    367:                }
                    368:                execvp(plan->e_argv[0], plan->e_argv);
                    369:                warn("%s", plan->e_argv[0]);
                    370:                _exit(1);
                    371:        }
                    372:        pid = waitpid(pid, &status, 0);
                    373:        return (pid != -1 && WIFEXITED(status) && !WEXITSTATUS(status));
                    374: }
                    375:
                    376: /*
                    377:  * c_exec --
                    378:  *     build three parallel arrays, one with pointers to the strings passed
                    379:  *     on the command line, one with (possibly duplicated) pointers to the
                    380:  *     argv array, and one with integer values that are lengths of the
                    381:  *     strings, but also flags meaning that the string has to be massaged.
                    382:  */
                    383: PLAN *
                    384: c_exec(argvp, isok)
                    385:        char ***argvp;
                    386:        int isok;
                    387: {
                    388:        PLAN *new;                      /* node returned */
                    389:        register int cnt;
                    390:        register char **argv, **ap, *p;
                    391:
                    392:        isoutput = 1;
                    393:
                    394:        new = palloc(N_EXEC, f_exec);
                    395:        if (isok)
                    396:                new->flags = F_NEEDOK;
                    397:
                    398:        for (ap = argv = *argvp;; ++ap) {
                    399:                if (!*ap)
                    400:                        errx(1,
                    401:                            "%s: no terminating \";\"", isok ? "-ok" : "-exec");
1.8       millert   402:                if (**ap == ';')
                    403:                        break;
                    404:        }
                    405:
                    406:        cnt = ap - *argvp + 1;
                    407:        new->e_argv = (char **)emalloc((u_int)cnt * sizeof(char *));
                    408:        new->e_orig = (char **)emalloc((u_int)cnt * sizeof(char *));
                    409:        new->e_len = (int *)emalloc((u_int)cnt * sizeof(int));
                    410:
                    411:        for (argv = *argvp, cnt = 0; argv < ap; ++argv, ++cnt) {
                    412:                new->e_orig[cnt] = *argv;
                    413:                for (p = *argv; *p; ++p)
                    414:                        if (p[0] == '{' && p[1] == '}') {
                    415:                                new->e_argv[cnt] = emalloc((u_int)MAXPATHLEN);
                    416:                                new->e_len[cnt] = MAXPATHLEN;
                    417:                                break;
                    418:                        }
                    419:                if (!*p) {
                    420:                        new->e_argv[cnt] = *argv;
                    421:                        new->e_len[cnt] = 0;
                    422:                }
                    423:        }
                    424:        new->e_argv[cnt] = new->e_orig[cnt] = NULL;
                    425:
                    426:        *argvp = argv + 1;
                    427:        return (new);
                    428: }
                    429:
                    430: /*
                    431:  * -execdir utility [arg ... ] ; functions --
                    432:  *
                    433:  *     True if the executed utility returns a zero value as exit status.
                    434:  *     The end of the primary expression is delimited by a semicolon.  If
                    435:  *     "{}" occurs anywhere, it gets replaced by the unqualified pathname.
                    436:  *     The current directory for the execution of utility is the same as
                    437:  *     the directory where the file lives.
                    438:  */
                    439: int
                    440: f_execdir(plan, entry)
                    441:        register PLAN *plan;
                    442:        FTSENT *entry;
                    443: {
                    444:        register int cnt;
                    445:        pid_t pid;
1.15      millert   446:        int status, fd;
1.10      millert   447:        char base[MAXPATHLEN];
1.8       millert   448:
1.15      millert   449:        /* fts(3) does not chdir for the root level so we do it ourselves. */
                    450:        if (entry->fts_level == FTS_ROOTLEVEL) {
                    451:                if ((fd = open(".", O_RDONLY)) == -1) {
                    452:                        warn("cannot open \".\"");
                    453:                        return (0);
                    454:                }
                    455:                if (chdir(entry->fts_accpath)) {
1.16      millert   456:                        (void) close(fd);
1.15      millert   457:                        return (0);
                    458:                }
                    459:        }
                    460:
1.10      millert   461:        /* Substitute basename(path) for {} since cwd is it's parent dir */
                    462:        (void)strncpy(base, basename(entry->fts_path), sizeof(base) - 1);
                    463:        base[sizeof(base) - 1] = '\0';
1.8       millert   464:        for (cnt = 0; plan->e_argv[cnt]; ++cnt)
                    465:                if (plan->e_len[cnt])
                    466:                        brace_subst(plan->e_orig[cnt], &plan->e_argv[cnt],
1.10      millert   467:                            base, plan->e_len[cnt]);
1.8       millert   468:
                    469:        /* don't mix output of command with find output */
                    470:        fflush(stdout);
                    471:        fflush(stderr);
                    472:
                    473:        switch (pid = vfork()) {
                    474:        case -1:
                    475:                err(1, "fork");
                    476:                /* NOTREACHED */
                    477:        case 0:
                    478:                execvp(plan->e_argv[0], plan->e_argv);
                    479:                warn("%s", plan->e_argv[0]);
                    480:                _exit(1);
                    481:        }
1.15      millert   482:
                    483:        /* Undo the above... */
                    484:        if (entry->fts_level == FTS_ROOTLEVEL) {
                    485:                if (fchdir(fd) == -1) {
                    486:                        warn("unable to chdir back to starting directory");
1.16      millert   487:                        (void) close(fd);
1.15      millert   488:                        return (0);
                    489:                }
1.16      millert   490:                (void) close(fd);
1.15      millert   491:        }
                    492:
1.8       millert   493:        pid = waitpid(pid, &status, 0);
                    494:        return (pid != -1 && WIFEXITED(status) && !WEXITSTATUS(status));
                    495: }
                    496:
                    497: /*
                    498:  * c_execdir --
                    499:  *     build three parallel arrays, one with pointers to the strings passed
                    500:  *     on the command line, one with (possibly duplicated) pointers to the
                    501:  *     argv array, and one with integer values that are lengths of the
                    502:  *     strings, but also flags meaning that the string has to be massaged.
                    503:  */
                    504: PLAN *
                    505: c_execdir(argvp)
                    506:        char ***argvp;
                    507: {
                    508:        PLAN *new;                      /* node returned */
                    509:        register int cnt;
                    510:        register char **argv, **ap, *p;
                    511:
                    512:        ftsoptions &= ~FTS_NOSTAT;
                    513:        isoutput = 1;
                    514:
                    515:        new = palloc(N_EXECDIR, f_execdir);
                    516:
                    517:        for (ap = argv = *argvp;; ++ap) {
                    518:                if (!*ap)
                    519:                        errx(1,
                    520:                            "-execdir: no terminating \";\"");
1.1       deraadt   521:                if (**ap == ';')
                    522:                        break;
                    523:        }
                    524:
                    525:        cnt = ap - *argvp + 1;
                    526:        new->e_argv = (char **)emalloc((u_int)cnt * sizeof(char *));
                    527:        new->e_orig = (char **)emalloc((u_int)cnt * sizeof(char *));
                    528:        new->e_len = (int *)emalloc((u_int)cnt * sizeof(int));
                    529:
                    530:        for (argv = *argvp, cnt = 0; argv < ap; ++argv, ++cnt) {
                    531:                new->e_orig[cnt] = *argv;
                    532:                for (p = *argv; *p; ++p)
                    533:                        if (p[0] == '{' && p[1] == '}') {
                    534:                                new->e_argv[cnt] = emalloc((u_int)MAXPATHLEN);
                    535:                                new->e_len[cnt] = MAXPATHLEN;
                    536:                                break;
                    537:                        }
                    538:                if (!*p) {
                    539:                        new->e_argv[cnt] = *argv;
                    540:                        new->e_len[cnt] = 0;
                    541:                }
                    542:        }
                    543:        new->e_argv[cnt] = new->e_orig[cnt] = NULL;
                    544:
                    545:        *argvp = argv + 1;
                    546:        return (new);
                    547: }
                    548:
                    549: /*
                    550:  * -follow functions --
                    551:  *
                    552:  *     Always true, causes symbolic links to be followed on a global
                    553:  *     basis.
                    554:  */
                    555: PLAN *
                    556: c_follow()
                    557: {
                    558:        ftsoptions &= ~FTS_PHYSICAL;
                    559:        ftsoptions |= FTS_LOGICAL;
                    560:
                    561:        return (palloc(N_FOLLOW, f_always_true));
                    562: }
                    563:
                    564: /*
                    565:  * -fstype functions --
                    566:  *
                    567:  *     True if the file is of a certain type.
                    568:  */
                    569: int
                    570: f_fstype(plan, entry)
                    571:        PLAN *plan;
                    572:        FTSENT *entry;
                    573: {
                    574:        static dev_t curdev;    /* need a guaranteed illegal dev value */
                    575:        static int first = 1;
                    576:        struct statfs sb;
                    577:        static short val;
                    578:        static char fstype[MFSNAMELEN];
                    579:        char *p, save[2];
                    580:
                    581:        /* Only check when we cross mount point. */
                    582:        if (first || curdev != entry->fts_statp->st_dev) {
                    583:                curdev = entry->fts_statp->st_dev;
                    584:
                    585:                /*
                    586:                 * Statfs follows symlinks; find wants the link's file system,
                    587:                 * not where it points.
                    588:                 */
                    589:                if (entry->fts_info == FTS_SL ||
                    590:                    entry->fts_info == FTS_SLNONE) {
1.9       millert   591:                        if ((p = strrchr(entry->fts_accpath, '/')))
1.1       deraadt   592:                                ++p;
                    593:                        else
                    594:                                p = entry->fts_accpath;
                    595:                        save[0] = p[0];
                    596:                        p[0] = '.';
                    597:                        save[1] = p[1];
                    598:                        p[1] = '\0';
                    599:
                    600:                } else
                    601:                        p = NULL;
                    602:
                    603:                if (statfs(entry->fts_accpath, &sb))
                    604:                        err(1, "%s", entry->fts_accpath);
                    605:
                    606:                if (p) {
                    607:                        p[0] = save[0];
                    608:                        p[1] = save[1];
                    609:                }
                    610:
                    611:                first = 0;
                    612:
                    613:                /*
                    614:                 * Further tests may need both of these values, so
                    615:                 * always copy both of them.
                    616:                 */
                    617:                val = sb.f_flags;
                    618:                strncpy(fstype, sb.f_fstypename, MFSNAMELEN);
                    619:        }
                    620:        switch (plan->flags) {
                    621:        case F_MTFLAG:
                    622:                return (val & plan->mt_data);
                    623:        case F_MTTYPE:
                    624:                return (strncmp(fstype, plan->c_data, MFSNAMELEN) == 0);
                    625:        default:
                    626:                abort();
                    627:        }
                    628: }
                    629:
                    630: PLAN *
                    631: c_fstype(arg)
                    632:        char *arg;
                    633: {
                    634:        register PLAN *new;
                    635:
                    636:        ftsoptions &= ~FTS_NOSTAT;
                    637:
                    638:        new = palloc(N_FSTYPE, f_fstype);
                    639:        switch (*arg) {
                    640:        case 'l':
                    641:                if (!strcmp(arg, "local")) {
                    642:                        new->flags = F_MTFLAG;
                    643:                        new->mt_data = MNT_LOCAL;
                    644:                        return (new);
                    645:                }
                    646:                break;
                    647:        case 'r':
                    648:                if (!strcmp(arg, "rdonly")) {
                    649:                        new->flags = F_MTFLAG;
                    650:                        new->mt_data = MNT_RDONLY;
                    651:                        return (new);
                    652:                }
                    653:                break;
                    654:        }
                    655:
                    656:        new->flags = F_MTTYPE;
                    657:        new->c_data = arg;
                    658:        return (new);
                    659: }
                    660:
                    661: /*
                    662:  * -group gname functions --
                    663:  *
                    664:  *     True if the file belongs to the group gname.  If gname is numeric and
                    665:  *     an equivalent of the getgrnam() function does not return a valid group
                    666:  *     name, gname is taken as a group ID.
                    667:  */
                    668: int
                    669: f_group(plan, entry)
                    670:        PLAN *plan;
                    671:        FTSENT *entry;
                    672: {
                    673:        return (entry->fts_statp->st_gid == plan->g_data);
                    674: }
                    675:
                    676: PLAN *
                    677: c_group(gname)
                    678:        char *gname;
                    679: {
                    680:        PLAN *new;
                    681:        struct group *g;
                    682:        gid_t gid;
                    683:
                    684:        ftsoptions &= ~FTS_NOSTAT;
                    685:
                    686:        g = getgrnam(gname);
                    687:        if (g == NULL) {
                    688:                gid = atoi(gname);
                    689:                if (gid == 0 && gname[0] != '0')
                    690:                        errx(1, "-group: %s: no such group", gname);
                    691:        } else
                    692:                gid = g->gr_gid;
                    693:
                    694:        new = palloc(N_GROUP, f_group);
                    695:        new->g_data = gid;
                    696:        return (new);
                    697: }
                    698:
                    699: /*
                    700:  * -inum n functions --
                    701:  *
                    702:  *     True if the file has inode # n.
                    703:  */
                    704: int
                    705: f_inum(plan, entry)
                    706:        PLAN *plan;
                    707:        FTSENT *entry;
                    708: {
                    709:        COMPARE(entry->fts_statp->st_ino, plan->i_data);
                    710: }
                    711:
                    712: PLAN *
                    713: c_inum(arg)
                    714:        char *arg;
                    715: {
                    716:        PLAN *new;
                    717:
                    718:        ftsoptions &= ~FTS_NOSTAT;
                    719:
                    720:        new = palloc(N_INUM, f_inum);
                    721:        new->i_data = find_parsenum(new, "-inum", arg, NULL);
                    722:        return (new);
                    723: }
                    724:
                    725: /*
                    726:  * -links n functions --
                    727:  *
                    728:  *     True if the file has n links.
                    729:  */
                    730: int
                    731: f_links(plan, entry)
                    732:        PLAN *plan;
                    733:        FTSENT *entry;
                    734: {
                    735:        COMPARE(entry->fts_statp->st_nlink, plan->l_data);
                    736: }
                    737:
                    738: PLAN *
                    739: c_links(arg)
                    740:        char *arg;
                    741: {
                    742:        PLAN *new;
                    743:
                    744:        ftsoptions &= ~FTS_NOSTAT;
                    745:
                    746:        new = palloc(N_LINKS, f_links);
                    747:        new->l_data = (nlink_t)find_parsenum(new, "-links", arg, NULL);
                    748:        return (new);
                    749: }
                    750:
                    751: /*
                    752:  * -ls functions --
                    753:  *
                    754:  *     Always true - prints the current entry to stdout in "ls" format.
                    755:  */
                    756: int
                    757: f_ls(plan, entry)
                    758:        PLAN *plan;
                    759:        FTSENT *entry;
                    760: {
                    761:        printlong(entry->fts_path, entry->fts_accpath, entry->fts_statp);
                    762:        return (1);
                    763: }
                    764:
                    765: PLAN *
                    766: c_ls()
                    767: {
                    768:        ftsoptions &= ~FTS_NOSTAT;
                    769:        isoutput = 1;
                    770:
                    771:        return (palloc(N_LS, f_ls));
1.5       tholo     772: }
                    773:
                    774: /*
                    775:  * - maxdepth n functions --
                    776:  *
                    777:  *     True if the current search depth is less than or equal to the
                    778:  *     maximum depth specified
                    779:  */
                    780: int
1.6       tholo     781: f_maxdepth(plan, entry)
1.5       tholo     782:        PLAN *plan;
                    783:        FTSENT *entry;
                    784: {
                    785:
1.6       tholo     786:        if (entry->fts_level >= plan->max_data)
1.5       tholo     787:                fts_set(tree, entry, FTS_SKIP);
1.6       tholo     788:        return (entry->fts_level <= plan->max_data);
1.5       tholo     789: }
                    790:
                    791: PLAN *
1.6       tholo     792: c_maxdepth(arg)
1.5       tholo     793:        char *arg;
                    794: {
                    795:        PLAN *new;
                    796:
1.6       tholo     797:        new = palloc(N_MAXDEPTH, f_maxdepth);
                    798:        new->max_data = atoi(arg);
                    799:        return (new);
                    800: }
                    801:
                    802: /*
                    803:  * - mindepth n functions --
                    804:  *
                    805:  *     True if the current search depth is greater than or equal to the
                    806:  *     minimum depth specified
                    807:  */
                    808: int
                    809: f_mindepth(plan, entry)
                    810:        PLAN *plan;
                    811:        FTSENT *entry;
                    812: {
                    813:
                    814:        return (entry->fts_level >= plan->min_data);
                    815: }
                    816:
                    817: PLAN *
                    818: c_mindepth(arg)
                    819:        char *arg;
                    820: {
                    821:        PLAN *new;
                    822:
                    823:        new = palloc(N_MINDEPTH, f_mindepth);
                    824:        new->min_data = atoi(arg);
1.5       tholo     825:        return (new);
1.1       deraadt   826: }
                    827:
                    828: /*
                    829:  * -mtime n functions --
                    830:  *
                    831:  *     True if the difference between the file modification time and the
                    832:  *     current time is n 24 hour periods.
                    833:  */
                    834: int
                    835: f_mtime(plan, entry)
                    836:        PLAN *plan;
                    837:        FTSENT *entry;
                    838: {
                    839:
                    840:        COMPARE((now - entry->fts_statp->st_mtime + SECSPERDAY - 1) /
1.17      millert   841:            SECSPERDAY, plan->sec_data);
1.1       deraadt   842: }
                    843:
                    844: PLAN *
                    845: c_mtime(arg)
                    846:        char *arg;
                    847: {
                    848:        PLAN *new;
                    849:
                    850:        ftsoptions &= ~FTS_NOSTAT;
                    851:
                    852:        new = palloc(N_MTIME, f_mtime);
1.17      millert   853:        new->sec_data = find_parsenum(new, "-mtime", arg, NULL);
1.1       deraadt   854:        TIME_CORRECT(new, N_MTIME);
1.11      deraadt   855:        return (new);
                    856: }
                    857:
                    858: /*
                    859:  * -mmin n functions --
                    860:  *
                    861:  *     True if the difference between the file modification time and the
                    862:  *     current time is n min periods.
                    863:  */
                    864: int
                    865: f_mmin(plan, entry)
                    866:        PLAN *plan;
                    867:        FTSENT *entry;
                    868: {
                    869:        extern time_t now;
                    870:
                    871:        COMPARE((now - entry->fts_statp->st_mtime + 60 - 1) /
1.17      millert   872:            60, plan->sec_data);
1.11      deraadt   873: }
                    874:
                    875: PLAN *
                    876: c_mmin(arg)
                    877:        char *arg;
                    878: {
                    879:        PLAN *new;
                    880:
                    881:        ftsoptions &= ~FTS_NOSTAT;
                    882:
                    883:        new = palloc(N_MMIN, f_mmin);
1.17      millert   884:        new->sec_data = find_parsenum(new, "-mmin", arg, NULL);
1.11      deraadt   885:        TIME_CORRECT(new, N_MMIN);
1.1       deraadt   886:        return (new);
                    887: }
                    888:
                    889: /*
                    890:  * -name functions --
                    891:  *
                    892:  *     True if the basename of the filename being examined
                    893:  *     matches pattern using Pattern Matching Notation S3.14
                    894:  */
                    895: int
                    896: f_name(plan, entry)
                    897:        PLAN *plan;
                    898:        FTSENT *entry;
                    899: {
                    900:        return (!fnmatch(plan->c_data, entry->fts_name, 0));
                    901: }
                    902:
                    903: PLAN *
                    904: c_name(pattern)
                    905:        char *pattern;
                    906: {
                    907:        PLAN *new;
                    908:
                    909:        new = palloc(N_NAME, f_name);
1.18    ! deraadt   910:        new->c_data = pattern;
        !           911:        return (new);
        !           912: }
        !           913:
        !           914: /*
        !           915:  * -iname functions --
        !           916:  *
        !           917:  *     Similar to -name, but does case insensitive matching
        !           918:  *
        !           919:  */
        !           920: int
        !           921: f_iname(plan, entry)
        !           922:        PLAN *plan;
        !           923:        FTSENT *entry;
        !           924: {
        !           925:        return (!fnmatch(plan->c_data, entry->fts_name, FNM_CASEFOLD));
        !           926: }
        !           927:
        !           928: PLAN *
        !           929: c_iname(pattern)
        !           930:        char *pattern;
        !           931: {
        !           932:        PLAN *new;
        !           933:
        !           934:        new = palloc(N_INAME, f_iname);
1.1       deraadt   935:        new->c_data = pattern;
                    936:        return (new);
                    937: }
                    938:
                    939: /*
                    940:  * -newer file functions --
                    941:  *
                    942:  *     True if the current file has been modified more recently
                    943:  *     then the modification time of the file named by the pathname
                    944:  *     file.
                    945:  */
                    946: int
                    947: f_newer(plan, entry)
                    948:        PLAN *plan;
                    949:        FTSENT *entry;
                    950: {
1.17      millert   951:
                    952:        return (entry->fts_statp->st_mtimespec.tv_sec > plan->t_data.tv_sec ||
                    953:            (entry->fts_statp->st_mtimespec.tv_sec == plan->t_data.tv_sec &&
                    954:            entry->fts_statp->st_mtimespec.tv_nsec > plan->t_data.tv_nsec));
1.1       deraadt   955: }
                    956:
                    957: PLAN *
                    958: c_newer(filename)
                    959:        char *filename;
                    960: {
                    961:        PLAN *new;
                    962:        struct stat sb;
                    963:
                    964:        ftsoptions &= ~FTS_NOSTAT;
                    965:
                    966:        if (stat(filename, &sb))
                    967:                err(1, "%s", filename);
                    968:        new = palloc(N_NEWER, f_newer);
1.17      millert   969:        memcpy(&new->t_data, &sb.st_mtimespec, sizeof(struct timespec));
                    970:        return (new);
                    971: }
                    972:
                    973: /*
                    974:  * -anewer file functions --
                    975:  *
                    976:  *     True if the current file has been accessed more recently
                    977:  *     then the access time of the file named by the pathname
                    978:  *     file.
                    979:  */
                    980: int
                    981: f_anewer(plan, entry)
                    982:        PLAN *plan;
                    983:        FTSENT *entry;
                    984: {
                    985:
                    986:        return (entry->fts_statp->st_atimespec.tv_sec > plan->t_data.tv_sec ||
                    987:            (entry->fts_statp->st_atimespec.tv_sec == plan->t_data.tv_sec &&
                    988:            entry->fts_statp->st_atimespec.tv_nsec > plan->t_data.tv_nsec));
                    989: }
                    990:
                    991: PLAN *
                    992: c_anewer(filename)
                    993:        char *filename;
                    994: {
                    995:        PLAN *new;
                    996:        struct stat sb;
                    997:
                    998:        ftsoptions &= ~FTS_NOSTAT;
                    999:
                   1000:        if (stat(filename, &sb))
                   1001:                err(1, "%s", filename);
                   1002:        new = palloc(N_NEWER, f_newer);
                   1003:        memcpy(&new->t_data, &sb.st_atimespec, sizeof(struct timespec));
                   1004:        return (new);
                   1005: }
                   1006:
                   1007: /*
                   1008:  * -cnewer file functions --
                   1009:  *
                   1010:  *     True if the current file has been changed more recently
                   1011:  *     then the inode change time of the file named by the pathname
                   1012:  *     file.
                   1013:  */
                   1014: int
                   1015: f_cnewer(plan, entry)
                   1016:        PLAN *plan;
                   1017:        FTSENT *entry;
                   1018: {
                   1019:
                   1020:        return (entry->fts_statp->st_ctimespec.tv_sec > plan->t_data.tv_sec ||
                   1021:            (entry->fts_statp->st_ctimespec.tv_sec == plan->t_data.tv_sec &&
                   1022:            entry->fts_statp->st_ctimespec.tv_nsec > plan->t_data.tv_nsec));
                   1023: }
                   1024:
                   1025: PLAN *
                   1026: c_cnewer(filename)
                   1027:        char *filename;
                   1028: {
                   1029:        PLAN *new;
                   1030:        struct stat sb;
                   1031:
                   1032:        ftsoptions &= ~FTS_NOSTAT;
                   1033:
                   1034:        if (stat(filename, &sb))
                   1035:                err(1, "%s", filename);
                   1036:        new = palloc(N_NEWER, f_newer);
                   1037:        memcpy(&new->t_data, &sb.st_ctimespec, sizeof(struct timespec));
1.1       deraadt  1038:        return (new);
                   1039: }
                   1040:
                   1041: /*
                   1042:  * -nogroup functions --
                   1043:  *
                   1044:  *     True if file belongs to a user ID for which the equivalent
                   1045:  *     of the getgrnam() 9.2.1 [POSIX.1] function returns NULL.
                   1046:  */
                   1047: int
                   1048: f_nogroup(plan, entry)
                   1049:        PLAN *plan;
                   1050:        FTSENT *entry;
                   1051: {
                   1052:        char *group_from_gid();
                   1053:
                   1054:        return (group_from_gid(entry->fts_statp->st_gid, 1) ? 0 : 1);
                   1055: }
                   1056:
                   1057: PLAN *
                   1058: c_nogroup()
                   1059: {
                   1060:        ftsoptions &= ~FTS_NOSTAT;
                   1061:
                   1062:        return (palloc(N_NOGROUP, f_nogroup));
                   1063: }
                   1064:
                   1065: /*
                   1066:  * -nouser functions --
                   1067:  *
                   1068:  *     True if file belongs to a user ID for which the equivalent
                   1069:  *     of the getpwuid() 9.2.2 [POSIX.1] function returns NULL.
                   1070:  */
                   1071: int
                   1072: f_nouser(plan, entry)
                   1073:        PLAN *plan;
                   1074:        FTSENT *entry;
                   1075: {
                   1076:        char *user_from_uid();
                   1077:
                   1078:        return (user_from_uid(entry->fts_statp->st_uid, 1) ? 0 : 1);
                   1079: }
                   1080:
                   1081: PLAN *
                   1082: c_nouser()
                   1083: {
                   1084:        ftsoptions &= ~FTS_NOSTAT;
                   1085:
                   1086:        return (palloc(N_NOUSER, f_nouser));
                   1087: }
                   1088:
                   1089: /*
                   1090:  * -path functions --
                   1091:  *
                   1092:  *     True if the path of the filename being examined
                   1093:  *     matches pattern using Pattern Matching Notation S3.14
                   1094:  */
                   1095: int
                   1096: f_path(plan, entry)
                   1097:        PLAN *plan;
                   1098:        FTSENT *entry;
                   1099: {
                   1100:        return (!fnmatch(plan->c_data, entry->fts_path, 0));
                   1101: }
                   1102:
                   1103: PLAN *
                   1104: c_path(pattern)
                   1105:        char *pattern;
                   1106: {
                   1107:        PLAN *new;
                   1108:
                   1109:        new = palloc(N_NAME, f_path);
                   1110:        new->c_data = pattern;
                   1111:        return (new);
                   1112: }
                   1113:
                   1114: /*
                   1115:  * -perm functions --
                   1116:  *
                   1117:  *     The mode argument is used to represent file mode bits.  If it starts
                   1118:  *     with a leading digit, it's treated as an octal mode, otherwise as a
                   1119:  *     symbolic mode.
                   1120:  */
                   1121: int
                   1122: f_perm(plan, entry)
                   1123:        PLAN *plan;
                   1124:        FTSENT *entry;
                   1125: {
                   1126:        mode_t mode;
                   1127:
                   1128:        mode = entry->fts_statp->st_mode &
                   1129:            (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO);
                   1130:        if (plan->flags == F_ATLEAST)
                   1131:                return ((plan->m_data | mode) == mode);
                   1132:        else
                   1133:                return (mode == plan->m_data);
                   1134:        /* NOTREACHED */
                   1135: }
                   1136:
                   1137: PLAN *
                   1138: c_perm(perm)
                   1139:        char *perm;
                   1140: {
                   1141:        PLAN *new;
                   1142:        mode_t *set;
                   1143:
                   1144:        ftsoptions &= ~FTS_NOSTAT;
                   1145:
                   1146:        new = palloc(N_PERM, f_perm);
                   1147:
                   1148:        if (*perm == '-') {
                   1149:                new->flags = F_ATLEAST;
                   1150:                ++perm;
                   1151:        }
                   1152:
                   1153:        if ((set = setmode(perm)) == NULL)
                   1154:                err(1, "-perm: %s: illegal mode string", perm);
                   1155:
                   1156:        new->m_data = getmode(set, 0);
1.12      deraadt  1157:        free(set);
1.1       deraadt  1158:        return (new);
                   1159: }
                   1160:
                   1161: /*
                   1162:  * -print functions --
                   1163:  *
                   1164:  *     Always true, causes the current pathame to be written to
                   1165:  *     standard output.
                   1166:  */
                   1167: int
                   1168: f_print(plan, entry)
                   1169:        PLAN *plan;
                   1170:        FTSENT *entry;
                   1171: {
                   1172:        (void)printf("%s\n", entry->fts_path);
                   1173:        return(1);
                   1174: }
                   1175:
                   1176: /* ARGSUSED */
1.9       millert  1177: int
1.1       deraadt  1178: f_print0(plan, entry)
                   1179:        PLAN *plan;
                   1180:        FTSENT *entry;
                   1181: {
                   1182:        (void)fputs(entry->fts_path, stdout);
                   1183:        (void)fputc('\0', stdout);
                   1184:        return(1);
                   1185: }
                   1186:
                   1187: PLAN *
                   1188: c_print()
                   1189: {
                   1190:        isoutput = 1;
                   1191:
                   1192:        return(palloc(N_PRINT, f_print));
                   1193: }
                   1194:
                   1195: PLAN *
                   1196: c_print0()
                   1197: {
                   1198:        isoutput = 1;
                   1199:
                   1200:        return(palloc(N_PRINT0, f_print0));
                   1201: }
                   1202:
                   1203: /*
                   1204:  * -prune functions --
                   1205:  *
                   1206:  *     Prune a portion of the hierarchy.
                   1207:  */
                   1208: int
                   1209: f_prune(plan, entry)
                   1210:        PLAN *plan;
                   1211:        FTSENT *entry;
                   1212: {
                   1213:
                   1214:        if (fts_set(tree, entry, FTS_SKIP))
                   1215:                err(1, "%s", entry->fts_path);
                   1216:        return (1);
                   1217: }
                   1218:
                   1219: PLAN *
                   1220: c_prune()
                   1221: {
                   1222:        return (palloc(N_PRUNE, f_prune));
                   1223: }
                   1224:
                   1225: /*
                   1226:  * -size n[c] functions --
                   1227:  *
                   1228:  *     True if the file size in bytes, divided by an implementation defined
                   1229:  *     value and rounded up to the next integer, is n.  If n is followed by
                   1230:  *     a c, the size is in bytes.
                   1231:  */
                   1232: #define        FIND_SIZE       512
                   1233: static int divsize = 1;
                   1234:
                   1235: int
                   1236: f_size(plan, entry)
                   1237:        PLAN *plan;
                   1238:        FTSENT *entry;
                   1239: {
                   1240:        off_t size;
                   1241:
                   1242:        size = divsize ? (entry->fts_statp->st_size + FIND_SIZE - 1) /
                   1243:            FIND_SIZE : entry->fts_statp->st_size;
                   1244:        COMPARE(size, plan->o_data);
                   1245: }
                   1246:
                   1247: PLAN *
                   1248: c_size(arg)
                   1249:        char *arg;
                   1250: {
                   1251:        PLAN *new;
                   1252:        char endch;
                   1253:
                   1254:        ftsoptions &= ~FTS_NOSTAT;
                   1255:
                   1256:        new = palloc(N_SIZE, f_size);
                   1257:        endch = 'c';
                   1258:        new->o_data = find_parsenum(new, "-size", arg, &endch);
                   1259:        if (endch == 'c')
                   1260:                divsize = 0;
                   1261:        return (new);
                   1262: }
                   1263:
                   1264: /*
                   1265:  * -type c functions --
                   1266:  *
                   1267:  *     True if the type of the file is c, where c is b, c, d, p, or f for
                   1268:  *     block special file, character special file, directory, FIFO, or
                   1269:  *     regular file, respectively.
                   1270:  */
                   1271: int
                   1272: f_type(plan, entry)
                   1273:        PLAN *plan;
                   1274:        FTSENT *entry;
                   1275: {
                   1276:        return ((entry->fts_statp->st_mode & S_IFMT) == plan->m_data);
                   1277: }
                   1278:
                   1279: PLAN *
                   1280: c_type(typestring)
                   1281:        char *typestring;
                   1282: {
                   1283:        PLAN *new;
                   1284:        mode_t  mask;
                   1285:
                   1286:        ftsoptions &= ~FTS_NOSTAT;
                   1287:
                   1288:        switch (typestring[0]) {
1.2       deraadt  1289: #ifdef S_IFWHT
1.3       deraadt  1290:        case 'W':
                   1291:                mask = S_IFWHT;
1.13      espie    1292:                if ((ftsoptions & FTS_WHITEOUT) == 0)
                   1293:                        warnx("-type W without -W is a no-op");
1.3       deraadt  1294:                break;
1.2       deraadt  1295: #endif
1.1       deraadt  1296:        case 'b':
                   1297:                mask = S_IFBLK;
                   1298:                break;
                   1299:        case 'c':
                   1300:                mask = S_IFCHR;
                   1301:                break;
                   1302:        case 'd':
                   1303:                mask = S_IFDIR;
                   1304:                break;
                   1305:        case 'f':
                   1306:                mask = S_IFREG;
                   1307:                break;
                   1308:        case 'l':
                   1309:                mask = S_IFLNK;
                   1310:                break;
                   1311:        case 'p':
                   1312:                mask = S_IFIFO;
                   1313:                break;
                   1314:        case 's':
                   1315:                mask = S_IFSOCK;
                   1316:                break;
                   1317:        default:
                   1318:                errx(1, "-type: %s: unknown type", typestring);
                   1319:        }
                   1320:
                   1321:        new = palloc(N_TYPE, f_type);
                   1322:        new->m_data = mask;
                   1323:        return (new);
                   1324: }
                   1325:
                   1326: /*
                   1327:  * -user uname functions --
                   1328:  *
                   1329:  *     True if the file belongs to the user uname.  If uname is numeric and
                   1330:  *     an equivalent of the getpwnam() S9.2.2 [POSIX.1] function does not
                   1331:  *     return a valid user name, uname is taken as a user ID.
                   1332:  */
                   1333: int
                   1334: f_user(plan, entry)
                   1335:        PLAN *plan;
                   1336:        FTSENT *entry;
                   1337: {
                   1338:        return (entry->fts_statp->st_uid == plan->u_data);
                   1339: }
                   1340:
                   1341: PLAN *
                   1342: c_user(username)
                   1343:        char *username;
                   1344: {
                   1345:        PLAN *new;
                   1346:        struct passwd *p;
                   1347:        uid_t uid;
                   1348:
                   1349:        ftsoptions &= ~FTS_NOSTAT;
                   1350:
                   1351:        p = getpwnam(username);
                   1352:        if (p == NULL) {
                   1353:                uid = atoi(username);
                   1354:                if (uid == 0 && username[0] != '0')
                   1355:                        errx(1, "-user: %s: no such user", username);
                   1356:        } else
                   1357:                uid = p->pw_uid;
                   1358:
                   1359:        new = palloc(N_USER, f_user);
                   1360:        new->u_data = uid;
                   1361:        return (new);
                   1362: }
                   1363:
                   1364: /*
                   1365:  * -xdev functions --
                   1366:  *
                   1367:  *     Always true, causes find not to decend past directories that have a
                   1368:  *     different device ID (st_dev, see stat() S5.6.2 [POSIX.1])
                   1369:  */
                   1370: PLAN *
                   1371: c_xdev()
                   1372: {
                   1373:        ftsoptions |= FTS_XDEV;
                   1374:
                   1375:        return (palloc(N_XDEV, f_always_true));
                   1376: }
                   1377:
                   1378: /*
                   1379:  * ( expression ) functions --
                   1380:  *
                   1381:  *     True if expression is true.
                   1382:  */
                   1383: int
                   1384: f_expr(plan, entry)
                   1385:        PLAN *plan;
                   1386:        FTSENT *entry;
                   1387: {
                   1388:        register PLAN *p;
                   1389:        register int state;
                   1390:
                   1391:        for (p = plan->p_data[0];
                   1392:            p && (state = (p->eval)(p, entry)); p = p->next);
                   1393:        return (state);
                   1394: }
                   1395:
                   1396: /*
                   1397:  * N_OPENPAREN and N_CLOSEPAREN nodes are temporary place markers.  They are
                   1398:  * eliminated during phase 2 of find_formplan() --- the '(' node is converted
                   1399:  * to a N_EXPR node containing the expression and the ')' node is discarded.
                   1400:  */
                   1401: PLAN *
                   1402: c_openparen()
                   1403: {
                   1404:        return (palloc(N_OPENPAREN, (int (*)())-1));
                   1405: }
                   1406:
                   1407: PLAN *
                   1408: c_closeparen()
                   1409: {
                   1410:        return (palloc(N_CLOSEPAREN, (int (*)())-1));
                   1411: }
                   1412:
                   1413: /*
                   1414:  * ! expression functions --
                   1415:  *
                   1416:  *     Negation of a primary; the unary NOT operator.
                   1417:  */
                   1418: int
                   1419: f_not(plan, entry)
                   1420:        PLAN *plan;
                   1421:        FTSENT *entry;
                   1422: {
                   1423:        register PLAN *p;
                   1424:        register int state;
                   1425:
                   1426:        for (p = plan->p_data[0];
                   1427:            p && (state = (p->eval)(p, entry)); p = p->next);
                   1428:        return (!state);
                   1429: }
                   1430:
                   1431: PLAN *
                   1432: c_not()
                   1433: {
                   1434:        return (palloc(N_NOT, f_not));
                   1435: }
                   1436:
                   1437: /*
                   1438:  * expression -o expression functions --
                   1439:  *
                   1440:  *     Alternation of primaries; the OR operator.  The second expression is
                   1441:  * not evaluated if the first expression is true.
                   1442:  */
                   1443: int
                   1444: f_or(plan, entry)
                   1445:        PLAN *plan;
                   1446:        FTSENT *entry;
                   1447: {
                   1448:        register PLAN *p;
                   1449:        register int state;
                   1450:
                   1451:        for (p = plan->p_data[0];
                   1452:            p && (state = (p->eval)(p, entry)); p = p->next);
                   1453:
                   1454:        if (state)
                   1455:                return (1);
                   1456:
                   1457:        for (p = plan->p_data[1];
                   1458:            p && (state = (p->eval)(p, entry)); p = p->next);
                   1459:        return (state);
                   1460: }
                   1461:
                   1462: PLAN *
                   1463: c_or()
                   1464: {
                   1465:        return (palloc(N_OR, f_or));
                   1466: }
                   1467:
                   1468: static PLAN *
                   1469: palloc(t, f)
                   1470:        enum ntype t;
                   1471:        int (*f) __P((PLAN *, FTSENT *));
                   1472: {
                   1473:        PLAN *new;
                   1474:
1.17      millert  1475:        if ((new = calloc(1, sizeof(PLAN)))) {
1.1       deraadt  1476:                new->type = t;
                   1477:                new->eval = f;
                   1478:                return (new);
                   1479:        }
                   1480:        err(1, NULL);
                   1481:        /* NOTREACHED */
                   1482: }