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

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