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

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