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