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: }