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

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