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