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

1.22    ! millert     1: /*     $OpenBSD: function.c,v 1.21 2001/11/19 19:02:13 mpech 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.22    ! millert    41: static char rcsid[] = "$OpenBSD: function.c,v 1.21 2001/11/19 19:02:13 mpech 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:
1.22    ! millert    80: static PLAN *palloc __P((enum ntype, int (*)(PLAN *, FTSENT *)));
1.1       deraadt    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)
1.21      mpech     340:        PLAN *plan;
1.1       deraadt   341:        FTSENT *entry;
                    342: {
1.21      mpech     343:        int cnt;
1.1       deraadt   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 */
1.21      mpech     389:        int cnt;
                    390:        char **argv, **ap, *p;
1.1       deraadt   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)
1.21      mpech     441:        PLAN *plan;
1.8       millert   442:        FTSENT *entry;
                    443: {
1.21      mpech     444:        int cnt;
1.8       millert   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 */
1.21      mpech     509:        int cnt;
                    510:        char **argv, **ap, *p;
1.8       millert   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: }
1.19      millert   548:
                    549: /*
                    550:  * -flags functions --
                    551:  *
                    552:  *     The flags argument is used to represent file flags bits.
                    553:  */
                    554: int
                    555: f_flags(plan, entry)
                    556:        PLAN *plan;
                    557:        FTSENT *entry;
                    558: {
                    559:        u_int flags;
                    560:
                    561:        flags = entry->fts_statp->st_flags &
                    562:            (UF_NODUMP | UF_IMMUTABLE | UF_APPEND | UF_OPAQUE |
                    563:             SF_ARCHIVED | SF_IMMUTABLE | SF_APPEND);
                    564:        if (plan->flags == F_ATLEAST)
                    565:                /* note that plan->fl_flags always is a subset of
                    566:                   plan->fl_mask */
                    567:                return ((flags & plan->fl_mask) == plan->fl_flags);
                    568:        else
                    569:                return (flags == plan->fl_flags);
                    570:        /* NOTREACHED */
                    571: }
                    572:
                    573: PLAN *
                    574: c_flags(flags_str)
                    575:        char *flags_str;
                    576: {
                    577:        PLAN *new;
1.20      mickey    578:        u_int32_t flags, notflags;
1.19      millert   579:
                    580:        ftsoptions &= ~FTS_NOSTAT;
                    581:
                    582:        new = palloc(N_FLAGS, f_flags);
                    583:
                    584:        if (*flags_str == '-') {
                    585:                new->flags = F_ATLEAST;
                    586:                ++flags_str;
                    587:        }
                    588:
1.20      mickey    589:        if (strtofflags(&flags_str, &flags, &notflags) == 1)
1.19      millert   590:                errx(1, "-flags: %s: illegal flags string", flags_str);
                    591:
                    592:        new->fl_flags = flags;
                    593:        new->fl_mask = flags | notflags;
                    594:        return (new);
                    595: }
1.1       deraadt   596:
                    597: /*
                    598:  * -follow functions --
                    599:  *
                    600:  *     Always true, causes symbolic links to be followed on a global
                    601:  *     basis.
                    602:  */
                    603: PLAN *
                    604: c_follow()
                    605: {
                    606:        ftsoptions &= ~FTS_PHYSICAL;
                    607:        ftsoptions |= FTS_LOGICAL;
                    608:
                    609:        return (palloc(N_FOLLOW, f_always_true));
                    610: }
                    611:
                    612: /*
                    613:  * -fstype functions --
                    614:  *
                    615:  *     True if the file is of a certain type.
                    616:  */
                    617: int
                    618: f_fstype(plan, entry)
                    619:        PLAN *plan;
                    620:        FTSENT *entry;
                    621: {
                    622:        static dev_t curdev;    /* need a guaranteed illegal dev value */
                    623:        static int first = 1;
                    624:        struct statfs sb;
                    625:        static short val;
                    626:        static char fstype[MFSNAMELEN];
                    627:        char *p, save[2];
                    628:
                    629:        /* Only check when we cross mount point. */
                    630:        if (first || curdev != entry->fts_statp->st_dev) {
                    631:                curdev = entry->fts_statp->st_dev;
                    632:
                    633:                /*
                    634:                 * Statfs follows symlinks; find wants the link's file system,
                    635:                 * not where it points.
                    636:                 */
                    637:                if (entry->fts_info == FTS_SL ||
                    638:                    entry->fts_info == FTS_SLNONE) {
1.9       millert   639:                        if ((p = strrchr(entry->fts_accpath, '/')))
1.1       deraadt   640:                                ++p;
                    641:                        else
                    642:                                p = entry->fts_accpath;
                    643:                        save[0] = p[0];
                    644:                        p[0] = '.';
                    645:                        save[1] = p[1];
                    646:                        p[1] = '\0';
                    647:
                    648:                } else
                    649:                        p = NULL;
                    650:
                    651:                if (statfs(entry->fts_accpath, &sb))
                    652:                        err(1, "%s", entry->fts_accpath);
                    653:
                    654:                if (p) {
                    655:                        p[0] = save[0];
                    656:                        p[1] = save[1];
                    657:                }
                    658:
                    659:                first = 0;
                    660:
                    661:                /*
                    662:                 * Further tests may need both of these values, so
                    663:                 * always copy both of them.
                    664:                 */
                    665:                val = sb.f_flags;
                    666:                strncpy(fstype, sb.f_fstypename, MFSNAMELEN);
                    667:        }
                    668:        switch (plan->flags) {
                    669:        case F_MTFLAG:
                    670:                return (val & plan->mt_data);
                    671:        case F_MTTYPE:
                    672:                return (strncmp(fstype, plan->c_data, MFSNAMELEN) == 0);
                    673:        default:
                    674:                abort();
                    675:        }
                    676: }
                    677:
                    678: PLAN *
                    679: c_fstype(arg)
                    680:        char *arg;
                    681: {
1.21      mpech     682:        PLAN *new;
1.1       deraadt   683:
                    684:        ftsoptions &= ~FTS_NOSTAT;
                    685:
                    686:        new = palloc(N_FSTYPE, f_fstype);
                    687:        switch (*arg) {
                    688:        case 'l':
                    689:                if (!strcmp(arg, "local")) {
                    690:                        new->flags = F_MTFLAG;
                    691:                        new->mt_data = MNT_LOCAL;
                    692:                        return (new);
                    693:                }
                    694:                break;
                    695:        case 'r':
                    696:                if (!strcmp(arg, "rdonly")) {
                    697:                        new->flags = F_MTFLAG;
                    698:                        new->mt_data = MNT_RDONLY;
                    699:                        return (new);
                    700:                }
                    701:                break;
                    702:        }
                    703:
                    704:        new->flags = F_MTTYPE;
                    705:        new->c_data = arg;
                    706:        return (new);
                    707: }
                    708:
                    709: /*
                    710:  * -group gname functions --
                    711:  *
                    712:  *     True if the file belongs to the group gname.  If gname is numeric and
                    713:  *     an equivalent of the getgrnam() function does not return a valid group
                    714:  *     name, gname is taken as a group ID.
                    715:  */
                    716: int
                    717: f_group(plan, entry)
                    718:        PLAN *plan;
                    719:        FTSENT *entry;
                    720: {
                    721:        return (entry->fts_statp->st_gid == plan->g_data);
                    722: }
                    723:
                    724: PLAN *
                    725: c_group(gname)
                    726:        char *gname;
                    727: {
                    728:        PLAN *new;
                    729:        struct group *g;
                    730:        gid_t gid;
                    731:
                    732:        ftsoptions &= ~FTS_NOSTAT;
                    733:
                    734:        g = getgrnam(gname);
                    735:        if (g == NULL) {
                    736:                gid = atoi(gname);
                    737:                if (gid == 0 && gname[0] != '0')
                    738:                        errx(1, "-group: %s: no such group", gname);
                    739:        } else
                    740:                gid = g->gr_gid;
                    741:
                    742:        new = palloc(N_GROUP, f_group);
                    743:        new->g_data = gid;
                    744:        return (new);
                    745: }
                    746:
                    747: /*
                    748:  * -inum n functions --
                    749:  *
                    750:  *     True if the file has inode # n.
                    751:  */
                    752: int
                    753: f_inum(plan, entry)
                    754:        PLAN *plan;
                    755:        FTSENT *entry;
                    756: {
                    757:        COMPARE(entry->fts_statp->st_ino, plan->i_data);
                    758: }
                    759:
                    760: PLAN *
                    761: c_inum(arg)
                    762:        char *arg;
                    763: {
                    764:        PLAN *new;
                    765:
                    766:        ftsoptions &= ~FTS_NOSTAT;
                    767:
                    768:        new = palloc(N_INUM, f_inum);
                    769:        new->i_data = find_parsenum(new, "-inum", arg, NULL);
                    770:        return (new);
                    771: }
                    772:
                    773: /*
                    774:  * -links n functions --
                    775:  *
                    776:  *     True if the file has n links.
                    777:  */
                    778: int
                    779: f_links(plan, entry)
                    780:        PLAN *plan;
                    781:        FTSENT *entry;
                    782: {
                    783:        COMPARE(entry->fts_statp->st_nlink, plan->l_data);
                    784: }
                    785:
                    786: PLAN *
                    787: c_links(arg)
                    788:        char *arg;
                    789: {
                    790:        PLAN *new;
                    791:
                    792:        ftsoptions &= ~FTS_NOSTAT;
                    793:
                    794:        new = palloc(N_LINKS, f_links);
                    795:        new->l_data = (nlink_t)find_parsenum(new, "-links", arg, NULL);
                    796:        return (new);
                    797: }
                    798:
                    799: /*
                    800:  * -ls functions --
                    801:  *
                    802:  *     Always true - prints the current entry to stdout in "ls" format.
                    803:  */
                    804: int
                    805: f_ls(plan, entry)
                    806:        PLAN *plan;
                    807:        FTSENT *entry;
                    808: {
                    809:        printlong(entry->fts_path, entry->fts_accpath, entry->fts_statp);
                    810:        return (1);
                    811: }
                    812:
                    813: PLAN *
                    814: c_ls()
                    815: {
                    816:        ftsoptions &= ~FTS_NOSTAT;
                    817:        isoutput = 1;
                    818:
                    819:        return (palloc(N_LS, f_ls));
1.5       tholo     820: }
                    821:
                    822: /*
                    823:  * - maxdepth n functions --
                    824:  *
                    825:  *     True if the current search depth is less than or equal to the
                    826:  *     maximum depth specified
                    827:  */
                    828: int
1.6       tholo     829: f_maxdepth(plan, entry)
1.5       tholo     830:        PLAN *plan;
                    831:        FTSENT *entry;
                    832: {
                    833:
1.6       tholo     834:        if (entry->fts_level >= plan->max_data)
1.5       tholo     835:                fts_set(tree, entry, FTS_SKIP);
1.6       tholo     836:        return (entry->fts_level <= plan->max_data);
1.5       tholo     837: }
                    838:
                    839: PLAN *
1.6       tholo     840: c_maxdepth(arg)
1.5       tholo     841:        char *arg;
                    842: {
                    843:        PLAN *new;
                    844:
1.6       tholo     845:        new = palloc(N_MAXDEPTH, f_maxdepth);
                    846:        new->max_data = atoi(arg);
                    847:        return (new);
                    848: }
                    849:
                    850: /*
                    851:  * - mindepth n functions --
                    852:  *
                    853:  *     True if the current search depth is greater than or equal to the
                    854:  *     minimum depth specified
                    855:  */
                    856: int
                    857: f_mindepth(plan, entry)
                    858:        PLAN *plan;
                    859:        FTSENT *entry;
                    860: {
                    861:
                    862:        return (entry->fts_level >= plan->min_data);
                    863: }
                    864:
                    865: PLAN *
                    866: c_mindepth(arg)
                    867:        char *arg;
                    868: {
                    869:        PLAN *new;
                    870:
                    871:        new = palloc(N_MINDEPTH, f_mindepth);
                    872:        new->min_data = atoi(arg);
1.5       tholo     873:        return (new);
1.1       deraadt   874: }
                    875:
                    876: /*
                    877:  * -mtime n functions --
                    878:  *
                    879:  *     True if the difference between the file modification time and the
                    880:  *     current time is n 24 hour periods.
                    881:  */
                    882: int
                    883: f_mtime(plan, entry)
                    884:        PLAN *plan;
                    885:        FTSENT *entry;
                    886: {
                    887:
                    888:        COMPARE((now - entry->fts_statp->st_mtime + SECSPERDAY - 1) /
1.17      millert   889:            SECSPERDAY, plan->sec_data);
1.1       deraadt   890: }
                    891:
                    892: PLAN *
                    893: c_mtime(arg)
                    894:        char *arg;
                    895: {
                    896:        PLAN *new;
                    897:
                    898:        ftsoptions &= ~FTS_NOSTAT;
                    899:
                    900:        new = palloc(N_MTIME, f_mtime);
1.17      millert   901:        new->sec_data = find_parsenum(new, "-mtime", arg, NULL);
1.1       deraadt   902:        TIME_CORRECT(new, N_MTIME);
1.11      deraadt   903:        return (new);
                    904: }
                    905:
                    906: /*
                    907:  * -mmin n functions --
                    908:  *
                    909:  *     True if the difference between the file modification time and the
                    910:  *     current time is n min periods.
                    911:  */
                    912: int
                    913: f_mmin(plan, entry)
                    914:        PLAN *plan;
                    915:        FTSENT *entry;
                    916: {
                    917:        extern time_t now;
                    918:
                    919:        COMPARE((now - entry->fts_statp->st_mtime + 60 - 1) /
1.17      millert   920:            60, plan->sec_data);
1.11      deraadt   921: }
                    922:
                    923: PLAN *
                    924: c_mmin(arg)
                    925:        char *arg;
                    926: {
                    927:        PLAN *new;
                    928:
                    929:        ftsoptions &= ~FTS_NOSTAT;
                    930:
                    931:        new = palloc(N_MMIN, f_mmin);
1.17      millert   932:        new->sec_data = find_parsenum(new, "-mmin", arg, NULL);
1.11      deraadt   933:        TIME_CORRECT(new, N_MMIN);
1.1       deraadt   934:        return (new);
                    935: }
                    936:
                    937: /*
                    938:  * -name functions --
                    939:  *
                    940:  *     True if the basename of the filename being examined
                    941:  *     matches pattern using Pattern Matching Notation S3.14
                    942:  */
                    943: int
                    944: f_name(plan, entry)
                    945:        PLAN *plan;
                    946:        FTSENT *entry;
                    947: {
                    948:        return (!fnmatch(plan->c_data, entry->fts_name, 0));
                    949: }
                    950:
                    951: PLAN *
                    952: c_name(pattern)
                    953:        char *pattern;
                    954: {
                    955:        PLAN *new;
                    956:
                    957:        new = palloc(N_NAME, f_name);
1.18      deraadt   958:        new->c_data = pattern;
                    959:        return (new);
                    960: }
                    961:
                    962: /*
                    963:  * -iname functions --
                    964:  *
                    965:  *     Similar to -name, but does case insensitive matching
                    966:  *
                    967:  */
                    968: int
                    969: f_iname(plan, entry)
                    970:        PLAN *plan;
                    971:        FTSENT *entry;
                    972: {
                    973:        return (!fnmatch(plan->c_data, entry->fts_name, FNM_CASEFOLD));
                    974: }
                    975:
                    976: PLAN *
                    977: c_iname(pattern)
                    978:        char *pattern;
                    979: {
                    980:        PLAN *new;
                    981:
                    982:        new = palloc(N_INAME, f_iname);
1.1       deraadt   983:        new->c_data = pattern;
                    984:        return (new);
                    985: }
                    986:
                    987: /*
                    988:  * -newer file functions --
                    989:  *
                    990:  *     True if the current file has been modified more recently
                    991:  *     then the modification time of the file named by the pathname
                    992:  *     file.
                    993:  */
                    994: int
                    995: f_newer(plan, entry)
                    996:        PLAN *plan;
                    997:        FTSENT *entry;
                    998: {
1.17      millert   999:
                   1000:        return (entry->fts_statp->st_mtimespec.tv_sec > plan->t_data.tv_sec ||
                   1001:            (entry->fts_statp->st_mtimespec.tv_sec == plan->t_data.tv_sec &&
                   1002:            entry->fts_statp->st_mtimespec.tv_nsec > plan->t_data.tv_nsec));
1.1       deraadt  1003: }
                   1004:
                   1005: PLAN *
                   1006: c_newer(filename)
                   1007:        char *filename;
                   1008: {
                   1009:        PLAN *new;
                   1010:        struct stat sb;
                   1011:
                   1012:        ftsoptions &= ~FTS_NOSTAT;
                   1013:
                   1014:        if (stat(filename, &sb))
                   1015:                err(1, "%s", filename);
                   1016:        new = palloc(N_NEWER, f_newer);
1.17      millert  1017:        memcpy(&new->t_data, &sb.st_mtimespec, sizeof(struct timespec));
                   1018:        return (new);
                   1019: }
                   1020:
                   1021: /*
                   1022:  * -anewer file functions --
                   1023:  *
                   1024:  *     True if the current file has been accessed more recently
                   1025:  *     then the access time of the file named by the pathname
                   1026:  *     file.
                   1027:  */
                   1028: int
                   1029: f_anewer(plan, entry)
                   1030:        PLAN *plan;
                   1031:        FTSENT *entry;
                   1032: {
                   1033:
                   1034:        return (entry->fts_statp->st_atimespec.tv_sec > plan->t_data.tv_sec ||
                   1035:            (entry->fts_statp->st_atimespec.tv_sec == plan->t_data.tv_sec &&
                   1036:            entry->fts_statp->st_atimespec.tv_nsec > plan->t_data.tv_nsec));
                   1037: }
                   1038:
                   1039: PLAN *
                   1040: c_anewer(filename)
                   1041:        char *filename;
                   1042: {
                   1043:        PLAN *new;
                   1044:        struct stat sb;
                   1045:
                   1046:        ftsoptions &= ~FTS_NOSTAT;
                   1047:
                   1048:        if (stat(filename, &sb))
                   1049:                err(1, "%s", filename);
                   1050:        new = palloc(N_NEWER, f_newer);
                   1051:        memcpy(&new->t_data, &sb.st_atimespec, sizeof(struct timespec));
                   1052:        return (new);
                   1053: }
                   1054:
                   1055: /*
                   1056:  * -cnewer file functions --
                   1057:  *
                   1058:  *     True if the current file has been changed more recently
                   1059:  *     then the inode change time of the file named by the pathname
                   1060:  *     file.
                   1061:  */
                   1062: int
                   1063: f_cnewer(plan, entry)
                   1064:        PLAN *plan;
                   1065:        FTSENT *entry;
                   1066: {
                   1067:
                   1068:        return (entry->fts_statp->st_ctimespec.tv_sec > plan->t_data.tv_sec ||
                   1069:            (entry->fts_statp->st_ctimespec.tv_sec == plan->t_data.tv_sec &&
                   1070:            entry->fts_statp->st_ctimespec.tv_nsec > plan->t_data.tv_nsec));
                   1071: }
                   1072:
                   1073: PLAN *
                   1074: c_cnewer(filename)
                   1075:        char *filename;
                   1076: {
                   1077:        PLAN *new;
                   1078:        struct stat sb;
                   1079:
                   1080:        ftsoptions &= ~FTS_NOSTAT;
                   1081:
                   1082:        if (stat(filename, &sb))
                   1083:                err(1, "%s", filename);
                   1084:        new = palloc(N_NEWER, f_newer);
                   1085:        memcpy(&new->t_data, &sb.st_ctimespec, sizeof(struct timespec));
1.1       deraadt  1086:        return (new);
                   1087: }
                   1088:
                   1089: /*
                   1090:  * -nogroup functions --
                   1091:  *
                   1092:  *     True if file belongs to a user ID for which the equivalent
                   1093:  *     of the getgrnam() 9.2.1 [POSIX.1] function returns NULL.
                   1094:  */
                   1095: int
                   1096: f_nogroup(plan, entry)
                   1097:        PLAN *plan;
                   1098:        FTSENT *entry;
                   1099: {
                   1100:        char *group_from_gid();
                   1101:
                   1102:        return (group_from_gid(entry->fts_statp->st_gid, 1) ? 0 : 1);
                   1103: }
                   1104:
                   1105: PLAN *
                   1106: c_nogroup()
                   1107: {
                   1108:        ftsoptions &= ~FTS_NOSTAT;
                   1109:
                   1110:        return (palloc(N_NOGROUP, f_nogroup));
                   1111: }
                   1112:
                   1113: /*
                   1114:  * -nouser functions --
                   1115:  *
                   1116:  *     True if file belongs to a user ID for which the equivalent
                   1117:  *     of the getpwuid() 9.2.2 [POSIX.1] function returns NULL.
                   1118:  */
                   1119: int
                   1120: f_nouser(plan, entry)
                   1121:        PLAN *plan;
                   1122:        FTSENT *entry;
                   1123: {
                   1124:        char *user_from_uid();
                   1125:
                   1126:        return (user_from_uid(entry->fts_statp->st_uid, 1) ? 0 : 1);
                   1127: }
                   1128:
                   1129: PLAN *
                   1130: c_nouser()
                   1131: {
                   1132:        ftsoptions &= ~FTS_NOSTAT;
                   1133:
                   1134:        return (palloc(N_NOUSER, f_nouser));
                   1135: }
                   1136:
                   1137: /*
                   1138:  * -path functions --
                   1139:  *
                   1140:  *     True if the path of the filename being examined
                   1141:  *     matches pattern using Pattern Matching Notation S3.14
                   1142:  */
                   1143: int
                   1144: f_path(plan, entry)
                   1145:        PLAN *plan;
                   1146:        FTSENT *entry;
                   1147: {
                   1148:        return (!fnmatch(plan->c_data, entry->fts_path, 0));
                   1149: }
                   1150:
                   1151: PLAN *
                   1152: c_path(pattern)
                   1153:        char *pattern;
                   1154: {
                   1155:        PLAN *new;
                   1156:
                   1157:        new = palloc(N_NAME, f_path);
                   1158:        new->c_data = pattern;
                   1159:        return (new);
                   1160: }
                   1161:
                   1162: /*
                   1163:  * -perm functions --
                   1164:  *
                   1165:  *     The mode argument is used to represent file mode bits.  If it starts
                   1166:  *     with a leading digit, it's treated as an octal mode, otherwise as a
                   1167:  *     symbolic mode.
                   1168:  */
                   1169: int
                   1170: f_perm(plan, entry)
                   1171:        PLAN *plan;
                   1172:        FTSENT *entry;
                   1173: {
                   1174:        mode_t mode;
                   1175:
                   1176:        mode = entry->fts_statp->st_mode &
                   1177:            (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO);
                   1178:        if (plan->flags == F_ATLEAST)
                   1179:                return ((plan->m_data | mode) == mode);
                   1180:        else
                   1181:                return (mode == plan->m_data);
                   1182:        /* NOTREACHED */
                   1183: }
                   1184:
                   1185: PLAN *
                   1186: c_perm(perm)
                   1187:        char *perm;
                   1188: {
                   1189:        PLAN *new;
                   1190:        mode_t *set;
                   1191:
                   1192:        ftsoptions &= ~FTS_NOSTAT;
                   1193:
                   1194:        new = palloc(N_PERM, f_perm);
                   1195:
                   1196:        if (*perm == '-') {
                   1197:                new->flags = F_ATLEAST;
                   1198:                ++perm;
                   1199:        }
                   1200:
                   1201:        if ((set = setmode(perm)) == NULL)
1.19      millert  1202:                errx(1, "-perm: %s: illegal mode string", perm);
1.1       deraadt  1203:
                   1204:        new->m_data = getmode(set, 0);
1.12      deraadt  1205:        free(set);
1.1       deraadt  1206:        return (new);
                   1207: }
                   1208:
                   1209: /*
                   1210:  * -print functions --
                   1211:  *
                   1212:  *     Always true, causes the current pathame to be written to
                   1213:  *     standard output.
                   1214:  */
                   1215: int
                   1216: f_print(plan, entry)
                   1217:        PLAN *plan;
                   1218:        FTSENT *entry;
                   1219: {
                   1220:        (void)printf("%s\n", entry->fts_path);
                   1221:        return(1);
                   1222: }
                   1223:
                   1224: /* ARGSUSED */
1.9       millert  1225: int
1.1       deraadt  1226: f_print0(plan, entry)
                   1227:        PLAN *plan;
                   1228:        FTSENT *entry;
                   1229: {
                   1230:        (void)fputs(entry->fts_path, stdout);
                   1231:        (void)fputc('\0', stdout);
                   1232:        return(1);
                   1233: }
                   1234:
                   1235: PLAN *
                   1236: c_print()
                   1237: {
                   1238:        isoutput = 1;
                   1239:
                   1240:        return(palloc(N_PRINT, f_print));
                   1241: }
                   1242:
                   1243: PLAN *
                   1244: c_print0()
                   1245: {
                   1246:        isoutput = 1;
                   1247:
                   1248:        return(palloc(N_PRINT0, f_print0));
                   1249: }
                   1250:
                   1251: /*
                   1252:  * -prune functions --
                   1253:  *
                   1254:  *     Prune a portion of the hierarchy.
                   1255:  */
                   1256: int
                   1257: f_prune(plan, entry)
                   1258:        PLAN *plan;
                   1259:        FTSENT *entry;
                   1260: {
                   1261:
                   1262:        if (fts_set(tree, entry, FTS_SKIP))
                   1263:                err(1, "%s", entry->fts_path);
                   1264:        return (1);
                   1265: }
                   1266:
                   1267: PLAN *
                   1268: c_prune()
                   1269: {
                   1270:        return (palloc(N_PRUNE, f_prune));
                   1271: }
                   1272:
                   1273: /*
                   1274:  * -size n[c] functions --
                   1275:  *
                   1276:  *     True if the file size in bytes, divided by an implementation defined
                   1277:  *     value and rounded up to the next integer, is n.  If n is followed by
                   1278:  *     a c, the size is in bytes.
                   1279:  */
                   1280: #define        FIND_SIZE       512
                   1281: static int divsize = 1;
                   1282:
                   1283: int
                   1284: f_size(plan, entry)
                   1285:        PLAN *plan;
                   1286:        FTSENT *entry;
                   1287: {
                   1288:        off_t size;
                   1289:
                   1290:        size = divsize ? (entry->fts_statp->st_size + FIND_SIZE - 1) /
                   1291:            FIND_SIZE : entry->fts_statp->st_size;
                   1292:        COMPARE(size, plan->o_data);
                   1293: }
                   1294:
                   1295: PLAN *
                   1296: c_size(arg)
                   1297:        char *arg;
                   1298: {
                   1299:        PLAN *new;
                   1300:        char endch;
                   1301:
                   1302:        ftsoptions &= ~FTS_NOSTAT;
                   1303:
                   1304:        new = palloc(N_SIZE, f_size);
                   1305:        endch = 'c';
                   1306:        new->o_data = find_parsenum(new, "-size", arg, &endch);
                   1307:        if (endch == 'c')
                   1308:                divsize = 0;
                   1309:        return (new);
                   1310: }
                   1311:
                   1312: /*
                   1313:  * -type c functions --
                   1314:  *
                   1315:  *     True if the type of the file is c, where c is b, c, d, p, or f for
                   1316:  *     block special file, character special file, directory, FIFO, or
                   1317:  *     regular file, respectively.
                   1318:  */
                   1319: int
                   1320: f_type(plan, entry)
                   1321:        PLAN *plan;
                   1322:        FTSENT *entry;
                   1323: {
                   1324:        return ((entry->fts_statp->st_mode & S_IFMT) == plan->m_data);
                   1325: }
                   1326:
                   1327: PLAN *
                   1328: c_type(typestring)
                   1329:        char *typestring;
                   1330: {
                   1331:        PLAN *new;
                   1332:        mode_t  mask;
                   1333:
                   1334:        ftsoptions &= ~FTS_NOSTAT;
                   1335:
                   1336:        switch (typestring[0]) {
1.2       deraadt  1337: #ifdef S_IFWHT
1.3       deraadt  1338:        case 'W':
                   1339:                mask = S_IFWHT;
1.13      espie    1340:                if ((ftsoptions & FTS_WHITEOUT) == 0)
                   1341:                        warnx("-type W without -W is a no-op");
1.3       deraadt  1342:                break;
1.2       deraadt  1343: #endif
1.1       deraadt  1344:        case 'b':
                   1345:                mask = S_IFBLK;
                   1346:                break;
                   1347:        case 'c':
                   1348:                mask = S_IFCHR;
                   1349:                break;
                   1350:        case 'd':
                   1351:                mask = S_IFDIR;
                   1352:                break;
                   1353:        case 'f':
                   1354:                mask = S_IFREG;
                   1355:                break;
                   1356:        case 'l':
                   1357:                mask = S_IFLNK;
                   1358:                break;
                   1359:        case 'p':
                   1360:                mask = S_IFIFO;
                   1361:                break;
                   1362:        case 's':
                   1363:                mask = S_IFSOCK;
                   1364:                break;
                   1365:        default:
                   1366:                errx(1, "-type: %s: unknown type", typestring);
                   1367:        }
                   1368:
                   1369:        new = palloc(N_TYPE, f_type);
                   1370:        new->m_data = mask;
                   1371:        return (new);
                   1372: }
                   1373:
                   1374: /*
                   1375:  * -user uname functions --
                   1376:  *
                   1377:  *     True if the file belongs to the user uname.  If uname is numeric and
                   1378:  *     an equivalent of the getpwnam() S9.2.2 [POSIX.1] function does not
                   1379:  *     return a valid user name, uname is taken as a user ID.
                   1380:  */
                   1381: int
                   1382: f_user(plan, entry)
                   1383:        PLAN *plan;
                   1384:        FTSENT *entry;
                   1385: {
                   1386:        return (entry->fts_statp->st_uid == plan->u_data);
                   1387: }
                   1388:
                   1389: PLAN *
                   1390: c_user(username)
                   1391:        char *username;
                   1392: {
                   1393:        PLAN *new;
                   1394:        struct passwd *p;
                   1395:        uid_t uid;
                   1396:
                   1397:        ftsoptions &= ~FTS_NOSTAT;
                   1398:
                   1399:        p = getpwnam(username);
                   1400:        if (p == NULL) {
                   1401:                uid = atoi(username);
                   1402:                if (uid == 0 && username[0] != '0')
                   1403:                        errx(1, "-user: %s: no such user", username);
                   1404:        } else
                   1405:                uid = p->pw_uid;
                   1406:
                   1407:        new = palloc(N_USER, f_user);
                   1408:        new->u_data = uid;
                   1409:        return (new);
                   1410: }
                   1411:
                   1412: /*
                   1413:  * -xdev functions --
                   1414:  *
                   1415:  *     Always true, causes find not to decend past directories that have a
                   1416:  *     different device ID (st_dev, see stat() S5.6.2 [POSIX.1])
                   1417:  */
                   1418: PLAN *
                   1419: c_xdev()
                   1420: {
                   1421:        ftsoptions |= FTS_XDEV;
                   1422:
                   1423:        return (palloc(N_XDEV, f_always_true));
                   1424: }
                   1425:
                   1426: /*
                   1427:  * ( expression ) functions --
                   1428:  *
                   1429:  *     True if expression is true.
                   1430:  */
                   1431: int
                   1432: f_expr(plan, entry)
                   1433:        PLAN *plan;
                   1434:        FTSENT *entry;
                   1435: {
1.21      mpech    1436:        PLAN *p;
                   1437:        int state;
1.1       deraadt  1438:
                   1439:        for (p = plan->p_data[0];
                   1440:            p && (state = (p->eval)(p, entry)); p = p->next);
                   1441:        return (state);
                   1442: }
                   1443:
                   1444: /*
                   1445:  * N_OPENPAREN and N_CLOSEPAREN nodes are temporary place markers.  They are
                   1446:  * eliminated during phase 2 of find_formplan() --- the '(' node is converted
                   1447:  * to a N_EXPR node containing the expression and the ')' node is discarded.
                   1448:  */
                   1449: PLAN *
                   1450: c_openparen()
                   1451: {
                   1452:        return (palloc(N_OPENPAREN, (int (*)())-1));
                   1453: }
                   1454:
                   1455: PLAN *
                   1456: c_closeparen()
                   1457: {
                   1458:        return (palloc(N_CLOSEPAREN, (int (*)())-1));
                   1459: }
                   1460:
                   1461: /*
                   1462:  * ! expression functions --
                   1463:  *
                   1464:  *     Negation of a primary; the unary NOT operator.
                   1465:  */
                   1466: int
                   1467: f_not(plan, entry)
                   1468:        PLAN *plan;
                   1469:        FTSENT *entry;
                   1470: {
1.21      mpech    1471:        PLAN *p;
                   1472:        int state;
1.1       deraadt  1473:
                   1474:        for (p = plan->p_data[0];
                   1475:            p && (state = (p->eval)(p, entry)); p = p->next);
                   1476:        return (!state);
                   1477: }
                   1478:
                   1479: PLAN *
                   1480: c_not()
                   1481: {
                   1482:        return (palloc(N_NOT, f_not));
                   1483: }
                   1484:
                   1485: /*
                   1486:  * expression -o expression functions --
                   1487:  *
                   1488:  *     Alternation of primaries; the OR operator.  The second expression is
                   1489:  * not evaluated if the first expression is true.
                   1490:  */
                   1491: int
                   1492: f_or(plan, entry)
                   1493:        PLAN *plan;
                   1494:        FTSENT *entry;
                   1495: {
1.21      mpech    1496:        PLAN *p;
                   1497:        int state;
1.1       deraadt  1498:
                   1499:        for (p = plan->p_data[0];
                   1500:            p && (state = (p->eval)(p, entry)); p = p->next);
                   1501:
                   1502:        if (state)
                   1503:                return (1);
                   1504:
                   1505:        for (p = plan->p_data[1];
                   1506:            p && (state = (p->eval)(p, entry)); p = p->next);
                   1507:        return (state);
                   1508: }
                   1509:
                   1510: PLAN *
                   1511: c_or()
                   1512: {
                   1513:        return (palloc(N_OR, f_or));
                   1514: }
                   1515:
                   1516: static PLAN *
                   1517: palloc(t, f)
                   1518:        enum ntype t;
1.22    ! millert  1519:        int (*f)(PLAN *, FTSENT *);
1.1       deraadt  1520: {
                   1521:        PLAN *new;
                   1522:
1.17      millert  1523:        if ((new = calloc(1, sizeof(PLAN)))) {
1.1       deraadt  1524:                new->type = t;
                   1525:                new->eval = f;
                   1526:                return (new);
                   1527:        }
                   1528:        err(1, NULL);
                   1529:        /* NOTREACHED */
                   1530: }