Annotation of src/usr.bin/find/function.c, Revision 1.5
1.5 ! tholo 1: /* $OpenBSD: function.c,v 1.4 1996/06/26 05:33:10 deraadt 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.5 ! tholo 41: static char rcsid[] = "$OpenBSD: function.c,v 1.4 1996/06/26 05:33:10 deraadt 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
! 553: f_mdepth(plan, entry)
! 554: PLAN *plan;
! 555: FTSENT *entry;
! 556: {
! 557: extern FTS *tree;
! 558:
! 559: if (entry->fts_level >= plan->d_data)
! 560: fts_set(tree, entry, FTS_SKIP);
! 561: return (entry->fts_level <= plan->d_data);
! 562: }
! 563:
! 564: PLAN *
! 565: c_mdepth(arg)
! 566: char *arg;
! 567: {
! 568: PLAN *new;
! 569:
! 570: new = palloc(N_MDEPTH, f_mdepth);
! 571: new->d_data = atoi(arg);
! 572: return (new);
1.1 deraadt 573: }
574:
575: /*
576: * -mtime n functions --
577: *
578: * True if the difference between the file modification time and the
579: * current time is n 24 hour periods.
580: */
581: int
582: f_mtime(plan, entry)
583: PLAN *plan;
584: FTSENT *entry;
585: {
586: extern time_t now;
587:
588: COMPARE((now - entry->fts_statp->st_mtime + SECSPERDAY - 1) /
589: SECSPERDAY, plan->t_data);
590: }
591:
592: PLAN *
593: c_mtime(arg)
594: char *arg;
595: {
596: PLAN *new;
597:
598: ftsoptions &= ~FTS_NOSTAT;
599:
600: new = palloc(N_MTIME, f_mtime);
601: new->t_data = find_parsenum(new, "-mtime", arg, NULL);
602: TIME_CORRECT(new, N_MTIME);
603: return (new);
604: }
605:
606: /*
607: * -name functions --
608: *
609: * True if the basename of the filename being examined
610: * matches pattern using Pattern Matching Notation S3.14
611: */
612: int
613: f_name(plan, entry)
614: PLAN *plan;
615: FTSENT *entry;
616: {
617: return (!fnmatch(plan->c_data, entry->fts_name, 0));
618: }
619:
620: PLAN *
621: c_name(pattern)
622: char *pattern;
623: {
624: PLAN *new;
625:
626: new = palloc(N_NAME, f_name);
627: new->c_data = pattern;
628: return (new);
629: }
630:
631: /*
632: * -newer file functions --
633: *
634: * True if the current file has been modified more recently
635: * then the modification time of the file named by the pathname
636: * file.
637: */
638: int
639: f_newer(plan, entry)
640: PLAN *plan;
641: FTSENT *entry;
642: {
643: return (entry->fts_statp->st_mtime > plan->t_data);
644: }
645:
646: PLAN *
647: c_newer(filename)
648: char *filename;
649: {
650: PLAN *new;
651: struct stat sb;
652:
653: ftsoptions &= ~FTS_NOSTAT;
654:
655: if (stat(filename, &sb))
656: err(1, "%s", filename);
657: new = palloc(N_NEWER, f_newer);
658: new->t_data = sb.st_mtime;
659: return (new);
660: }
661:
662: /*
663: * -nogroup functions --
664: *
665: * True if file belongs to a user ID for which the equivalent
666: * of the getgrnam() 9.2.1 [POSIX.1] function returns NULL.
667: */
668: int
669: f_nogroup(plan, entry)
670: PLAN *plan;
671: FTSENT *entry;
672: {
673: char *group_from_gid();
674:
675: return (group_from_gid(entry->fts_statp->st_gid, 1) ? 0 : 1);
676: }
677:
678: PLAN *
679: c_nogroup()
680: {
681: ftsoptions &= ~FTS_NOSTAT;
682:
683: return (palloc(N_NOGROUP, f_nogroup));
684: }
685:
686: /*
687: * -nouser functions --
688: *
689: * True if file belongs to a user ID for which the equivalent
690: * of the getpwuid() 9.2.2 [POSIX.1] function returns NULL.
691: */
692: int
693: f_nouser(plan, entry)
694: PLAN *plan;
695: FTSENT *entry;
696: {
697: char *user_from_uid();
698:
699: return (user_from_uid(entry->fts_statp->st_uid, 1) ? 0 : 1);
700: }
701:
702: PLAN *
703: c_nouser()
704: {
705: ftsoptions &= ~FTS_NOSTAT;
706:
707: return (palloc(N_NOUSER, f_nouser));
708: }
709:
710: /*
711: * -path functions --
712: *
713: * True if the path of the filename being examined
714: * matches pattern using Pattern Matching Notation S3.14
715: */
716: int
717: f_path(plan, entry)
718: PLAN *plan;
719: FTSENT *entry;
720: {
721: return (!fnmatch(plan->c_data, entry->fts_path, 0));
722: }
723:
724: PLAN *
725: c_path(pattern)
726: char *pattern;
727: {
728: PLAN *new;
729:
730: new = palloc(N_NAME, f_path);
731: new->c_data = pattern;
732: return (new);
733: }
734:
735: /*
736: * -perm functions --
737: *
738: * The mode argument is used to represent file mode bits. If it starts
739: * with a leading digit, it's treated as an octal mode, otherwise as a
740: * symbolic mode.
741: */
742: int
743: f_perm(plan, entry)
744: PLAN *plan;
745: FTSENT *entry;
746: {
747: mode_t mode;
748:
749: mode = entry->fts_statp->st_mode &
750: (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO);
751: if (plan->flags == F_ATLEAST)
752: return ((plan->m_data | mode) == mode);
753: else
754: return (mode == plan->m_data);
755: /* NOTREACHED */
756: }
757:
758: PLAN *
759: c_perm(perm)
760: char *perm;
761: {
762: PLAN *new;
763: mode_t *set;
764:
765: ftsoptions &= ~FTS_NOSTAT;
766:
767: new = palloc(N_PERM, f_perm);
768:
769: if (*perm == '-') {
770: new->flags = F_ATLEAST;
771: ++perm;
772: }
773:
774: if ((set = setmode(perm)) == NULL)
775: err(1, "-perm: %s: illegal mode string", perm);
776:
777: new->m_data = getmode(set, 0);
778: return (new);
779: }
780:
781: /*
782: * -print functions --
783: *
784: * Always true, causes the current pathame to be written to
785: * standard output.
786: */
787: int
788: f_print(plan, entry)
789: PLAN *plan;
790: FTSENT *entry;
791: {
792: (void)printf("%s\n", entry->fts_path);
793: return(1);
794: }
795:
796: /* ARGSUSED */
797: f_print0(plan, entry)
798: PLAN *plan;
799: FTSENT *entry;
800: {
801: (void)fputs(entry->fts_path, stdout);
802: (void)fputc('\0', stdout);
803: return(1);
804: }
805:
806: PLAN *
807: c_print()
808: {
809: isoutput = 1;
810:
811: return(palloc(N_PRINT, f_print));
812: }
813:
814: PLAN *
815: c_print0()
816: {
817: isoutput = 1;
818:
819: return(palloc(N_PRINT0, f_print0));
820: }
821:
822: /*
823: * -prune functions --
824: *
825: * Prune a portion of the hierarchy.
826: */
827: int
828: f_prune(plan, entry)
829: PLAN *plan;
830: FTSENT *entry;
831: {
832: extern FTS *tree;
833:
834: if (fts_set(tree, entry, FTS_SKIP))
835: err(1, "%s", entry->fts_path);
836: return (1);
837: }
838:
839: PLAN *
840: c_prune()
841: {
842: return (palloc(N_PRUNE, f_prune));
843: }
844:
845: /*
846: * -size n[c] functions --
847: *
848: * True if the file size in bytes, divided by an implementation defined
849: * value and rounded up to the next integer, is n. If n is followed by
850: * a c, the size is in bytes.
851: */
852: #define FIND_SIZE 512
853: static int divsize = 1;
854:
855: int
856: f_size(plan, entry)
857: PLAN *plan;
858: FTSENT *entry;
859: {
860: off_t size;
861:
862: size = divsize ? (entry->fts_statp->st_size + FIND_SIZE - 1) /
863: FIND_SIZE : entry->fts_statp->st_size;
864: COMPARE(size, plan->o_data);
865: }
866:
867: PLAN *
868: c_size(arg)
869: char *arg;
870: {
871: PLAN *new;
872: char endch;
873:
874: ftsoptions &= ~FTS_NOSTAT;
875:
876: new = palloc(N_SIZE, f_size);
877: endch = 'c';
878: new->o_data = find_parsenum(new, "-size", arg, &endch);
879: if (endch == 'c')
880: divsize = 0;
881: return (new);
882: }
883:
884: /*
885: * -type c functions --
886: *
887: * True if the type of the file is c, where c is b, c, d, p, or f for
888: * block special file, character special file, directory, FIFO, or
889: * regular file, respectively.
890: */
891: int
892: f_type(plan, entry)
893: PLAN *plan;
894: FTSENT *entry;
895: {
896: return ((entry->fts_statp->st_mode & S_IFMT) == plan->m_data);
897: }
898:
899: PLAN *
900: c_type(typestring)
901: char *typestring;
902: {
903: PLAN *new;
904: mode_t mask;
905:
906: ftsoptions &= ~FTS_NOSTAT;
907:
908: switch (typestring[0]) {
1.2 deraadt 909: #ifdef S_IFWHT
1.3 deraadt 910: case 'W':
911: mask = S_IFWHT;
912: break;
1.2 deraadt 913: #endif
1.1 deraadt 914: case 'b':
915: mask = S_IFBLK;
916: break;
917: case 'c':
918: mask = S_IFCHR;
919: break;
920: case 'd':
921: mask = S_IFDIR;
922: break;
923: case 'f':
924: mask = S_IFREG;
925: break;
926: case 'l':
927: mask = S_IFLNK;
928: break;
929: case 'p':
930: mask = S_IFIFO;
931: break;
932: case 's':
933: mask = S_IFSOCK;
934: break;
935: default:
936: errx(1, "-type: %s: unknown type", typestring);
937: }
938:
939: new = palloc(N_TYPE, f_type);
940: new->m_data = mask;
941: return (new);
942: }
943:
944: /*
945: * -user uname functions --
946: *
947: * True if the file belongs to the user uname. If uname is numeric and
948: * an equivalent of the getpwnam() S9.2.2 [POSIX.1] function does not
949: * return a valid user name, uname is taken as a user ID.
950: */
951: int
952: f_user(plan, entry)
953: PLAN *plan;
954: FTSENT *entry;
955: {
956: return (entry->fts_statp->st_uid == plan->u_data);
957: }
958:
959: PLAN *
960: c_user(username)
961: char *username;
962: {
963: PLAN *new;
964: struct passwd *p;
965: uid_t uid;
966:
967: ftsoptions &= ~FTS_NOSTAT;
968:
969: p = getpwnam(username);
970: if (p == NULL) {
971: uid = atoi(username);
972: if (uid == 0 && username[0] != '0')
973: errx(1, "-user: %s: no such user", username);
974: } else
975: uid = p->pw_uid;
976:
977: new = palloc(N_USER, f_user);
978: new->u_data = uid;
979: return (new);
980: }
981:
982: /*
983: * -xdev functions --
984: *
985: * Always true, causes find not to decend past directories that have a
986: * different device ID (st_dev, see stat() S5.6.2 [POSIX.1])
987: */
988: PLAN *
989: c_xdev()
990: {
991: ftsoptions |= FTS_XDEV;
992:
993: return (palloc(N_XDEV, f_always_true));
994: }
995:
996: /*
997: * ( expression ) functions --
998: *
999: * True if expression is true.
1000: */
1001: int
1002: f_expr(plan, entry)
1003: PLAN *plan;
1004: FTSENT *entry;
1005: {
1006: register PLAN *p;
1007: register int state;
1008:
1009: for (p = plan->p_data[0];
1010: p && (state = (p->eval)(p, entry)); p = p->next);
1011: return (state);
1012: }
1013:
1014: /*
1015: * N_OPENPAREN and N_CLOSEPAREN nodes are temporary place markers. They are
1016: * eliminated during phase 2 of find_formplan() --- the '(' node is converted
1017: * to a N_EXPR node containing the expression and the ')' node is discarded.
1018: */
1019: PLAN *
1020: c_openparen()
1021: {
1022: return (palloc(N_OPENPAREN, (int (*)())-1));
1023: }
1024:
1025: PLAN *
1026: c_closeparen()
1027: {
1028: return (palloc(N_CLOSEPAREN, (int (*)())-1));
1029: }
1030:
1031: /*
1032: * ! expression functions --
1033: *
1034: * Negation of a primary; the unary NOT operator.
1035: */
1036: int
1037: f_not(plan, entry)
1038: PLAN *plan;
1039: FTSENT *entry;
1040: {
1041: register PLAN *p;
1042: register int state;
1043:
1044: for (p = plan->p_data[0];
1045: p && (state = (p->eval)(p, entry)); p = p->next);
1046: return (!state);
1047: }
1048:
1049: PLAN *
1050: c_not()
1051: {
1052: return (palloc(N_NOT, f_not));
1053: }
1054:
1055: /*
1056: * expression -o expression functions --
1057: *
1058: * Alternation of primaries; the OR operator. The second expression is
1059: * not evaluated if the first expression is true.
1060: */
1061: int
1062: f_or(plan, entry)
1063: PLAN *plan;
1064: FTSENT *entry;
1065: {
1066: register PLAN *p;
1067: register int state;
1068:
1069: for (p = plan->p_data[0];
1070: p && (state = (p->eval)(p, entry)); p = p->next);
1071:
1072: if (state)
1073: return (1);
1074:
1075: for (p = plan->p_data[1];
1076: p && (state = (p->eval)(p, entry)); p = p->next);
1077: return (state);
1078: }
1079:
1080: PLAN *
1081: c_or()
1082: {
1083: return (palloc(N_OR, f_or));
1084: }
1085:
1086: static PLAN *
1087: palloc(t, f)
1088: enum ntype t;
1089: int (*f) __P((PLAN *, FTSENT *));
1090: {
1091: PLAN *new;
1092:
1093: if (new = malloc(sizeof(PLAN))) {
1094: new->type = t;
1095: new->eval = f;
1096: new->flags = 0;
1097: new->next = NULL;
1098: return (new);
1099: }
1100: err(1, NULL);
1101: /* NOTREACHED */
1102: }