Annotation of src/usr.bin/find/function.c, Revision 1.2
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";*/
1.2 ! deraadt 39: static char rcsid[] = "$Id: function.c,v 1.1.1.1 1995/10/18 08:45:13 deraadt Exp $";
1.1 deraadt 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]) {
1.2 ! deraadt 878: #ifdef S_IFWHT
! 879: case 'W':
! 880: mask = S_IFWHT;
! 881: break;
! 882: #endif
1.1 deraadt 883: case 'b':
884: mask = S_IFBLK;
885: break;
886: case 'c':
887: mask = S_IFCHR;
888: break;
889: case 'd':
890: mask = S_IFDIR;
891: break;
892: case 'f':
893: mask = S_IFREG;
894: break;
895: case 'l':
896: mask = S_IFLNK;
897: break;
898: case 'p':
899: mask = S_IFIFO;
900: break;
901: case 's':
902: mask = S_IFSOCK;
903: break;
904: default:
905: errx(1, "-type: %s: unknown type", typestring);
906: }
907:
908: new = palloc(N_TYPE, f_type);
909: new->m_data = mask;
910: return (new);
911: }
912:
913: /*
914: * -user uname functions --
915: *
916: * True if the file belongs to the user uname. If uname is numeric and
917: * an equivalent of the getpwnam() S9.2.2 [POSIX.1] function does not
918: * return a valid user name, uname is taken as a user ID.
919: */
920: int
921: f_user(plan, entry)
922: PLAN *plan;
923: FTSENT *entry;
924: {
925: return (entry->fts_statp->st_uid == plan->u_data);
926: }
927:
928: PLAN *
929: c_user(username)
930: char *username;
931: {
932: PLAN *new;
933: struct passwd *p;
934: uid_t uid;
935:
936: ftsoptions &= ~FTS_NOSTAT;
937:
938: p = getpwnam(username);
939: if (p == NULL) {
940: uid = atoi(username);
941: if (uid == 0 && username[0] != '0')
942: errx(1, "-user: %s: no such user", username);
943: } else
944: uid = p->pw_uid;
945:
946: new = palloc(N_USER, f_user);
947: new->u_data = uid;
948: return (new);
949: }
950:
951: /*
952: * -xdev functions --
953: *
954: * Always true, causes find not to decend past directories that have a
955: * different device ID (st_dev, see stat() S5.6.2 [POSIX.1])
956: */
957: PLAN *
958: c_xdev()
959: {
960: ftsoptions |= FTS_XDEV;
961:
962: return (palloc(N_XDEV, f_always_true));
963: }
964:
965: /*
966: * ( expression ) functions --
967: *
968: * True if expression is true.
969: */
970: int
971: f_expr(plan, entry)
972: PLAN *plan;
973: FTSENT *entry;
974: {
975: register PLAN *p;
976: register int state;
977:
978: for (p = plan->p_data[0];
979: p && (state = (p->eval)(p, entry)); p = p->next);
980: return (state);
981: }
982:
983: /*
984: * N_OPENPAREN and N_CLOSEPAREN nodes are temporary place markers. They are
985: * eliminated during phase 2 of find_formplan() --- the '(' node is converted
986: * to a N_EXPR node containing the expression and the ')' node is discarded.
987: */
988: PLAN *
989: c_openparen()
990: {
991: return (palloc(N_OPENPAREN, (int (*)())-1));
992: }
993:
994: PLAN *
995: c_closeparen()
996: {
997: return (palloc(N_CLOSEPAREN, (int (*)())-1));
998: }
999:
1000: /*
1001: * ! expression functions --
1002: *
1003: * Negation of a primary; the unary NOT operator.
1004: */
1005: int
1006: f_not(plan, entry)
1007: PLAN *plan;
1008: FTSENT *entry;
1009: {
1010: register PLAN *p;
1011: register int state;
1012:
1013: for (p = plan->p_data[0];
1014: p && (state = (p->eval)(p, entry)); p = p->next);
1015: return (!state);
1016: }
1017:
1018: PLAN *
1019: c_not()
1020: {
1021: return (palloc(N_NOT, f_not));
1022: }
1023:
1024: /*
1025: * expression -o expression functions --
1026: *
1027: * Alternation of primaries; the OR operator. The second expression is
1028: * not evaluated if the first expression is true.
1029: */
1030: int
1031: f_or(plan, entry)
1032: PLAN *plan;
1033: FTSENT *entry;
1034: {
1035: register PLAN *p;
1036: register int state;
1037:
1038: for (p = plan->p_data[0];
1039: p && (state = (p->eval)(p, entry)); p = p->next);
1040:
1041: if (state)
1042: return (1);
1043:
1044: for (p = plan->p_data[1];
1045: p && (state = (p->eval)(p, entry)); p = p->next);
1046: return (state);
1047: }
1048:
1049: PLAN *
1050: c_or()
1051: {
1052: return (palloc(N_OR, f_or));
1053: }
1054:
1055: static PLAN *
1056: palloc(t, f)
1057: enum ntype t;
1058: int (*f) __P((PLAN *, FTSENT *));
1059: {
1060: PLAN *new;
1061:
1062: if (new = malloc(sizeof(PLAN))) {
1063: new->type = t;
1064: new->eval = f;
1065: new->flags = 0;
1066: new->next = NULL;
1067: return (new);
1068: }
1069: err(1, NULL);
1070: /* NOTREACHED */
1071: }