*** empty log message ***
[findutils.git] / find / pred.c
blob7e53349ef49388be8b5cc944b09e4220a0302645
1 /* pred.c -- execute the expression tree.
2 Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
18 #define _GNU_SOURCE
19 #include <config.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <stdio.h>
23 #include <fnmatch.h>
24 #include <signal.h>
25 #include <pwd.h>
26 #include <grp.h>
27 #include "defs.h"
28 #include "modetype.h"
29 #include "wait.h"
31 #if !defined(SIGCHLD) && defined(SIGCLD)
32 #define SIGCHLD SIGCLD
33 #endif
35 #if HAVE_DIRENT_H
36 # include <dirent.h>
37 # define NAMLEN(dirent) strlen((dirent)->d_name)
38 #else
39 # define dirent direct
40 # define NAMLEN(dirent) (dirent)->d_namlen
41 # if HAVE_SYS_NDIR_H
42 # include <sys/ndir.h>
43 # endif
44 # if HAVE_SYS_DIR_H
45 # include <sys/dir.h>
46 # endif
47 # if HAVE_NDIR_H
48 # include <ndir.h>
49 # endif
50 #endif
52 #ifdef CLOSEDIR_VOID
53 /* Fake a return value. */
54 #define CLOSEDIR(d) (closedir (d), 0)
55 #else
56 #define CLOSEDIR(d) closedir (d)
57 #endif
59 /* Extract or fake data from a `struct stat'.
60 ST_NBLOCKS: Number of 512-byte blocks in the file
61 (including indirect blocks).
62 HP-UX, perhaps uniquely, counts st_blocks in 1024-byte units.
63 This workaround loses when mixing HP-UX and 4BSD filesystems, though. */
64 #ifdef _POSIX_SOURCE
65 # define ST_NBLOCKS(statp) (((statp)->st_size + 512 - 1) / 512)
66 #else
67 # ifndef HAVE_ST_BLOCKS
68 # define ST_NBLOCKS(statp) (st_blocks ((statp)->st_size))
69 # else
70 # if defined(hpux) || defined(__hpux__)
71 # define ST_NBLOCKS(statp) ((statp)->st_blocks * 2)
72 # else
73 # define ST_NBLOCKS(statp) ((statp)->st_blocks)
74 # endif
75 # endif
76 #endif
78 static boolean insert_lname P_((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr, boolean ignore_case));
79 static boolean launch P_((struct predicate *pred_ptr));
80 static char *format_date P_((time_t when, int kind));
82 #ifdef DEBUG
83 struct pred_assoc
85 PFB pred_func;
86 char *pred_name;
89 struct pred_assoc pred_table[] =
91 {pred_amin, "amin "},
92 {pred_and, "and "},
93 {pred_anewer, "anewer "},
94 {pred_atime, "atime "},
95 {pred_close, ") "},
96 {pred_amin, "cmin "},
97 {pred_cnewer, "cnewer "},
98 {pred_comma, ", "},
99 {pred_ctime, "ctime "},
100 {pred_empty, "empty "},
101 {pred_exec, "exec "},
102 {pred_false, "false "},
103 {pred_fprint, "fprint "},
104 {pred_fprint0, "fprint0 "},
105 {pred_fprintf, "fprintf "},
106 {pred_fstype, "fstype "},
107 {pred_gid, "gid "},
108 {pred_group, "group "},
109 {pred_ilname, "ilname "},
110 {pred_iname, "iname "},
111 {pred_inum, "inum "},
112 {pred_ipath, "ipath "},
113 {pred_links, "links "},
114 {pred_lname, "lname "},
115 {pred_ls, "ls "},
116 {pred_amin, "mmin "},
117 {pred_mtime, "mtime "},
118 {pred_name, "name "},
119 {pred_negate, "not "},
120 {pred_newer, "newer "},
121 {pred_nogroup, "nogroup "},
122 {pred_nouser, "nouser "},
123 {pred_ok, "ok "},
124 {pred_open, "( "},
125 {pred_or, "or "},
126 {pred_path, "path "},
127 {pred_perm, "perm "},
128 {pred_print, "print "},
129 {pred_print0, "print0 "},
130 {pred_prune, "prune "},
131 {pred_regex, "regex "},
132 {pred_size, "size "},
133 {pred_true, "true "},
134 {pred_type, "type "},
135 {pred_uid, "uid "},
136 {pred_used, "used "},
137 {pred_user, "user "},
138 {pred_xtype, "xtype "},
139 {0, "none "}
142 struct op_assoc
144 short type;
145 char *type_name;
148 struct op_assoc type_table[] =
150 {NO_TYPE, "no "},
151 {PRIMARY_TYPE, "primary "},
152 {UNI_OP, "uni_op "},
153 {BI_OP, "bi_op "},
154 {OPEN_PAREN, "open_paren "},
155 {CLOSE_PAREN, "close_paren "},
156 {-1, "unknown "}
159 struct prec_assoc
161 short prec;
162 char *prec_name;
165 struct prec_assoc prec_table[] =
167 {NO_PREC, "no "},
168 {COMMA_PREC, "comma "},
169 {OR_PREC, "or "},
170 {AND_PREC, "and "},
171 {NEGATE_PREC, "negate "},
172 {MAX_PREC, "max "},
173 {-1, "unknown "}
175 #endif /* DEBUG */
177 /* Predicate processing routines.
179 PATHNAME is the full pathname of the file being checked.
180 *STAT_BUF contains information about PATHNAME.
181 *PRED_PTR contains information for applying the predicate.
183 Return true if the file passes this predicate, false if not. */
185 boolean
186 pred_amin (pathname, stat_buf, pred_ptr)
187 char *pathname;
188 struct stat *stat_buf;
189 struct predicate *pred_ptr;
191 switch (pred_ptr->args.info.kind)
193 case COMP_GT:
194 if (stat_buf->st_atime > (time_t) pred_ptr->args.info.l_val)
195 return (true);
196 break;
197 case COMP_LT:
198 if (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val)
199 return (true);
200 break;
201 case COMP_EQ:
202 if ((stat_buf->st_atime >= (time_t) pred_ptr->args.info.l_val)
203 && (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val + 60))
204 return (true);
205 break;
207 return (false);
210 boolean
211 pred_and (pathname, stat_buf, pred_ptr)
212 char *pathname;
213 struct stat *stat_buf;
214 struct predicate *pred_ptr;
216 if (pred_ptr->pred_left == NULL
217 || (*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
218 pred_ptr->pred_left))
220 /* Check whether we need a stat here. */
221 if (pred_ptr->need_stat)
223 if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
225 error (0, errno, "%s", pathname);
226 exit_status = 1;
227 return (false);
229 have_stat = true;
231 return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
232 pred_ptr->pred_right));
234 else
235 return (false);
238 boolean
239 pred_anewer (pathname, stat_buf, pred_ptr)
240 char *pathname;
241 struct stat *stat_buf;
242 struct predicate *pred_ptr;
244 if (stat_buf->st_atime > pred_ptr->args.time)
245 return (true);
246 return (false);
249 boolean
250 pred_atime (pathname, stat_buf, pred_ptr)
251 char *pathname;
252 struct stat *stat_buf;
253 struct predicate *pred_ptr;
255 switch (pred_ptr->args.info.kind)
257 case COMP_GT:
258 if (stat_buf->st_atime > (time_t) pred_ptr->args.info.l_val)
259 return (true);
260 break;
261 case COMP_LT:
262 if (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val)
263 return (true);
264 break;
265 case COMP_EQ:
266 if ((stat_buf->st_atime >= (time_t) pred_ptr->args.info.l_val)
267 && (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val
268 + DAYSECS))
269 return (true);
270 break;
272 return (false);
275 boolean
276 pred_close (pathname, stat_buf, pred_ptr)
277 char *pathname;
278 struct stat *stat_buf;
279 struct predicate *pred_ptr;
281 return (true);
284 boolean
285 pred_cmin (pathname, stat_buf, pred_ptr)
286 char *pathname;
287 struct stat *stat_buf;
288 struct predicate *pred_ptr;
290 switch (pred_ptr->args.info.kind)
292 case COMP_GT:
293 if (stat_buf->st_ctime > (time_t) pred_ptr->args.info.l_val)
294 return (true);
295 break;
296 case COMP_LT:
297 if (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val)
298 return (true);
299 break;
300 case COMP_EQ:
301 if ((stat_buf->st_ctime >= (time_t) pred_ptr->args.info.l_val)
302 && (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val + 60))
303 return (true);
304 break;
306 return (false);
309 boolean
310 pred_cnewer (pathname, stat_buf, pred_ptr)
311 char *pathname;
312 struct stat *stat_buf;
313 struct predicate *pred_ptr;
315 if (stat_buf->st_ctime > pred_ptr->args.time)
316 return (true);
317 return (false);
320 boolean
321 pred_comma (pathname, stat_buf, pred_ptr)
322 char *pathname;
323 struct stat *stat_buf;
324 struct predicate *pred_ptr;
326 if (pred_ptr->pred_left != NULL)
327 (*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
328 pred_ptr->pred_left);
329 /* Check whether we need a stat here. */
330 if (pred_ptr->need_stat)
332 if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
334 error (0, errno, "%s", pathname);
335 exit_status = 1;
336 return (false);
338 have_stat = true;
340 return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
341 pred_ptr->pred_right));
344 boolean
345 pred_ctime (pathname, stat_buf, pred_ptr)
346 char *pathname;
347 struct stat *stat_buf;
348 struct predicate *pred_ptr;
350 switch (pred_ptr->args.info.kind)
352 case COMP_GT:
353 if (stat_buf->st_ctime > (time_t) pred_ptr->args.info.l_val)
354 return (true);
355 break;
356 case COMP_LT:
357 if (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val)
358 return (true);
359 break;
360 case COMP_EQ:
361 if ((stat_buf->st_ctime >= (time_t) pred_ptr->args.info.l_val)
362 && (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val
363 + DAYSECS))
364 return (true);
365 break;
367 return (false);
370 boolean
371 pred_empty (pathname, stat_buf, pred_ptr)
372 char *pathname;
373 struct stat *stat_buf;
374 struct predicate *pred_ptr;
376 if (S_ISDIR (stat_buf->st_mode))
378 DIR *d;
379 struct dirent *dp;
380 boolean empty = true;
382 errno = 0;
383 d = opendir (rel_pathname);
384 if (d == NULL)
386 error (0, errno, "%s", pathname);
387 exit_status = 1;
388 return (false);
390 for (dp = readdir (d); dp; dp = readdir (d))
392 if (dp->d_name[0] != '.'
393 || (dp->d_name[1] != '\0'
394 && (dp->d_name[1] != '.' || dp->d_name[2] != '\0')))
396 empty = false;
397 break;
400 if (CLOSEDIR (d))
402 error (0, errno, "%s", pathname);
403 exit_status = 1;
404 return (false);
406 return (empty);
408 else if (S_ISREG (stat_buf->st_mode))
409 return (stat_buf->st_size == 0);
410 else
411 return (false);
414 boolean
415 pred_exec (pathname, stat_buf, pred_ptr)
416 char *pathname;
417 struct stat *stat_buf;
418 struct predicate *pred_ptr;
420 int i;
421 int path_pos;
422 struct exec_val *execp; /* Pointer for efficiency. */
424 execp = &pred_ptr->args.exec_vec;
426 /* Replace "{}" with the real path in each affected arg. */
427 for (path_pos = 0; execp->paths[path_pos].offset >= 0; path_pos++)
429 register char *from, *to;
431 i = execp->paths[path_pos].offset;
432 execp->vec[i] =
433 xmalloc (strlen (execp->paths[path_pos].origarg) + 1
434 + (strlen (pathname) - 2) * execp->paths[path_pos].count);
435 for (from = execp->paths[path_pos].origarg, to = execp->vec[i]; *from; )
436 if (from[0] == '{' && from[1] == '}')
438 to = stpcpy (to, pathname);
439 from += 2;
441 else
442 *to++ = *from++;
443 *to = *from; /* Copy null. */
446 i = launch (pred_ptr);
448 /* Free the temporary args. */
449 for (path_pos = 0; execp->paths[path_pos].offset >= 0; path_pos++)
450 free (execp->vec[execp->paths[path_pos].offset]);
452 return (i);
455 boolean
456 pred_false (pathname, stat_buf, pred_ptr)
457 char *pathname;
458 struct stat *stat_buf;
459 struct predicate *pred_ptr;
461 return (false);
464 boolean
465 pred_fls (pathname, stat_buf, pred_ptr)
466 char *pathname;
467 struct stat *stat_buf;
468 struct predicate *pred_ptr;
470 list_file (pathname, rel_pathname, stat_buf, pred_ptr->args.stream);
471 return (true);
474 boolean
475 pred_fprint (pathname, stat_buf, pred_ptr)
476 char *pathname;
477 struct stat *stat_buf;
478 struct predicate *pred_ptr;
480 fputs (pathname, pred_ptr->args.stream);
481 putc ('\n', pred_ptr->args.stream);
482 return (true);
485 boolean
486 pred_fprint0 (pathname, stat_buf, pred_ptr)
487 char *pathname;
488 struct stat *stat_buf;
489 struct predicate *pred_ptr;
491 fputs (pathname, pred_ptr->args.stream);
492 putc (0, pred_ptr->args.stream);
493 return (true);
496 boolean
497 pred_fprintf (pathname, stat_buf, pred_ptr)
498 char *pathname;
499 struct stat *stat_buf;
500 struct predicate *pred_ptr;
502 FILE *fp = pred_ptr->args.printf_vec.stream;
503 struct segment *segment;
504 char *cp;
506 for (segment = pred_ptr->args.printf_vec.segment; segment;
507 segment = segment->next)
509 if (segment->kind & 0xff00) /* Component of date. */
511 time_t t;
513 switch (segment->kind & 0xff)
515 case 'A':
516 t = stat_buf->st_atime;
517 break;
518 case 'C':
519 t = stat_buf->st_ctime;
520 break;
521 case 'T':
522 t = stat_buf->st_mtime;
523 break;
524 default:
525 abort ();
527 fprintf (fp, segment->text,
528 format_date (t, (segment->kind >> 8) & 0xff));
529 continue;
532 switch (segment->kind)
534 case KIND_PLAIN: /* Plain text string (no % conversion). */
535 fwrite (segment->text, 1, segment->text_len, fp);
536 break;
537 case KIND_STOP: /* Terminate argument and flush output. */
538 fwrite (segment->text, 1, segment->text_len, fp);
539 fflush (fp);
540 return (true);
541 case 'a': /* atime in `ctime' format. */
542 cp = ctime (&stat_buf->st_atime);
543 cp[24] = '\0';
544 fprintf (fp, segment->text, cp);
545 break;
546 case 'b': /* size in 512-byte blocks */
547 fprintf (fp, segment->text, ST_NBLOCKS (stat_buf));
548 break;
549 case 'c': /* ctime in `ctime' format */
550 cp = ctime (&stat_buf->st_ctime);
551 cp[24] = '\0';
552 fprintf (fp, segment->text, cp);
553 break;
554 case 'd': /* depth in search tree */
555 fprintf (fp, segment->text, curdepth);
556 break;
557 case 'f': /* basename of path */
558 cp = strrchr (pathname, '/');
559 if (cp)
560 cp++;
561 else
562 cp = pathname;
563 fprintf (fp, segment->text, cp);
564 break;
565 case 'F': /* filesystem type */
566 fprintf (fp, segment->text,
567 filesystem_type (pathname, rel_pathname, stat_buf));
568 break;
569 case 'g': /* group name */
571 struct group *g;
573 g = getgrgid (stat_buf->st_gid);
574 if (g)
576 segment->text[segment->text_len] = 's';
577 fprintf (fp, segment->text, g->gr_name);
578 break;
580 /* else fallthru */
582 case 'G': /* GID number */
583 segment->text[segment->text_len] = 'u';
584 fprintf (fp, segment->text, stat_buf->st_gid);
585 break;
586 case 'h': /* leading directories part of path */
588 char cc;
590 cp = strrchr (pathname, '/');
591 if (cp == NULL) /* No leading directories. */
592 break;
593 cc = *cp;
594 *cp = '\0';
595 fprintf (fp, segment->text, pathname);
596 *cp = cc;
597 break;
599 case 'H': /* ARGV element file was found under */
601 char cc = pathname[path_length];
603 pathname[path_length] = '\0';
604 fprintf (fp, segment->text, pathname);
605 pathname[path_length] = cc;
606 break;
608 case 'i': /* inode number */
609 fprintf (fp, segment->text, stat_buf->st_ino);
610 break;
611 case 'k': /* size in 1K blocks */
612 fprintf (fp, segment->text, (ST_NBLOCKS (stat_buf) + 1) / 2);
613 break;
614 case 'l': /* object of symlink */
615 #ifdef S_ISLNK
617 char *linkname = 0;
619 if (S_ISLNK (stat_buf->st_mode))
621 linkname = get_link_name (pathname, rel_pathname);
622 if (linkname == 0)
623 exit_status = 1;
625 if (linkname)
627 fprintf (fp, segment->text, linkname);
628 free (linkname);
630 else
631 fprintf (fp, segment->text, "");
633 #endif /* S_ISLNK */
634 break;
635 case 'm': /* mode as octal number (perms only) */
636 fprintf (fp, segment->text, stat_buf->st_mode & 07777);
637 break;
638 case 'n': /* number of links */
639 fprintf (fp, segment->text, stat_buf->st_nlink);
640 break;
641 case 'p': /* pathname */
642 fprintf (fp, segment->text, pathname);
643 break;
644 case 'P': /* pathname with ARGV element stripped */
645 if (curdepth)
647 cp = pathname + path_length;
648 if (*cp == '/')
649 /* Move past the slash between the ARGV element
650 and the rest of the pathname. But if the ARGV element
651 ends in a slash, we didn't add another, so we've
652 already skipped past it. */
653 cp++;
655 else
656 cp = "";
657 fprintf (fp, segment->text, cp);
658 break;
659 case 's': /* size in bytes */
660 fprintf (fp, segment->text, stat_buf->st_size);
661 break;
662 case 't': /* mtime in `ctime' format */
663 cp = ctime (&stat_buf->st_mtime);
664 cp[24] = '\0';
665 fprintf (fp, segment->text, cp);
666 break;
667 case 'u': /* user name */
669 struct passwd *p;
671 p = getpwuid (stat_buf->st_uid);
672 if (p)
674 segment->text[segment->text_len] = 's';
675 fprintf (fp, segment->text, p->pw_name);
676 break;
678 /* else fallthru */
680 case 'U': /* UID number */
681 segment->text[segment->text_len] = 'u';
682 fprintf (fp, segment->text, stat_buf->st_uid);
683 break;
686 return (true);
689 boolean
690 pred_fstype (pathname, stat_buf, pred_ptr)
691 char *pathname;
692 struct stat *stat_buf;
693 struct predicate *pred_ptr;
695 if (strcmp (filesystem_type (pathname, rel_pathname, stat_buf),
696 pred_ptr->args.str) == 0)
697 return (true);
698 return (false);
701 boolean
702 pred_gid (pathname, stat_buf, pred_ptr)
703 char *pathname;
704 struct stat *stat_buf;
705 struct predicate *pred_ptr;
707 switch (pred_ptr->args.info.kind)
709 case COMP_GT:
710 if (stat_buf->st_gid > pred_ptr->args.info.l_val)
711 return (true);
712 break;
713 case COMP_LT:
714 if (stat_buf->st_gid < pred_ptr->args.info.l_val)
715 return (true);
716 break;
717 case COMP_EQ:
718 if (stat_buf->st_gid == pred_ptr->args.info.l_val)
719 return (true);
720 break;
722 return (false);
725 boolean
726 pred_group (pathname, stat_buf, pred_ptr)
727 char *pathname;
728 struct stat *stat_buf;
729 struct predicate *pred_ptr;
731 if (pred_ptr->args.gid == stat_buf->st_gid)
732 return (true);
733 else
734 return (false);
737 boolean
738 pred_ilname (pathname, stat_buf, pred_ptr)
739 char *pathname;
740 struct stat *stat_buf;
741 struct predicate *pred_ptr;
743 return insert_lname (pathname, stat_buf, pred_ptr, true);
746 boolean
747 pred_iname (pathname, stat_buf, pred_ptr)
748 char *pathname;
749 struct stat *stat_buf;
750 struct predicate *pred_ptr;
752 const char *base;
754 base = basename (pathname);
755 if (fnmatch (pred_ptr->args.str, base, FNM_PERIOD | FNM_CASEFOLD) == 0)
756 return (true);
757 return (false);
760 boolean
761 pred_inum (pathname, stat_buf, pred_ptr)
762 char *pathname;
763 struct stat *stat_buf;
764 struct predicate *pred_ptr;
766 switch (pred_ptr->args.info.kind)
768 case COMP_GT:
769 if (stat_buf->st_ino > pred_ptr->args.info.l_val)
770 return (true);
771 break;
772 case COMP_LT:
773 if (stat_buf->st_ino < pred_ptr->args.info.l_val)
774 return (true);
775 break;
776 case COMP_EQ:
777 if (stat_buf->st_ino == pred_ptr->args.info.l_val)
778 return (true);
779 break;
781 return (false);
784 boolean
785 pred_ipath (pathname, stat_buf, pred_ptr)
786 char *pathname;
787 struct stat *stat_buf;
788 struct predicate *pred_ptr;
790 if (fnmatch (pred_ptr->args.str, pathname, FNM_CASEFOLD) == 0)
791 return (true);
792 return (false);
795 boolean
796 pred_links (pathname, stat_buf, pred_ptr)
797 char *pathname;
798 struct stat *stat_buf;
799 struct predicate *pred_ptr;
801 switch (pred_ptr->args.info.kind)
803 case COMP_GT:
804 if (stat_buf->st_nlink > pred_ptr->args.info.l_val)
805 return (true);
806 break;
807 case COMP_LT:
808 if (stat_buf->st_nlink < pred_ptr->args.info.l_val)
809 return (true);
810 break;
811 case COMP_EQ:
812 if (stat_buf->st_nlink == pred_ptr->args.info.l_val)
813 return (true);
814 break;
816 return (false);
819 boolean
820 pred_lname (pathname, stat_buf, pred_ptr)
821 char *pathname;
822 struct stat *stat_buf;
823 struct predicate *pred_ptr;
825 return insert_lname (pathname, stat_buf, pred_ptr, false);
828 static boolean
829 insert_lname (pathname, stat_buf, pred_ptr, ignore_case)
830 char *pathname;
831 struct stat *stat_buf;
832 struct predicate *pred_ptr;
833 boolean ignore_case;
835 boolean ret = false;
836 #ifdef S_ISLNK
837 if (S_ISLNK (stat_buf->st_mode))
839 char *linkname = get_link_name (pathname, rel_pathname);
840 if (linkname)
842 if (fnmatch (pred_ptr->args.str, linkname,
843 ignore_case ? FNM_CASEFOLD : 0) == 0)
844 ret = true;
845 free (linkname);
848 #endif /* S_ISLNK */
849 return (ret);
852 boolean
853 pred_ls (pathname, stat_buf, pred_ptr)
854 char *pathname;
855 struct stat *stat_buf;
856 struct predicate *pred_ptr;
858 list_file (pathname, rel_pathname, stat_buf, stdout);
859 return (true);
862 boolean
863 pred_mmin (pathname, stat_buf, pred_ptr)
864 char *pathname;
865 struct stat *stat_buf;
866 struct predicate *pred_ptr;
868 switch (pred_ptr->args.info.kind)
870 case COMP_GT:
871 if (stat_buf->st_mtime > (time_t) pred_ptr->args.info.l_val)
872 return (true);
873 break;
874 case COMP_LT:
875 if (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val)
876 return (true);
877 break;
878 case COMP_EQ:
879 if ((stat_buf->st_mtime >= (time_t) pred_ptr->args.info.l_val)
880 && (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val + 60))
881 return (true);
882 break;
884 return (false);
887 boolean
888 pred_mtime (pathname, stat_buf, pred_ptr)
889 char *pathname;
890 struct stat *stat_buf;
891 struct predicate *pred_ptr;
893 switch (pred_ptr->args.info.kind)
895 case COMP_GT:
896 if (stat_buf->st_mtime > (time_t) pred_ptr->args.info.l_val)
897 return (true);
898 break;
899 case COMP_LT:
900 if (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val)
901 return (true);
902 break;
903 case COMP_EQ:
904 if ((stat_buf->st_mtime >= (time_t) pred_ptr->args.info.l_val)
905 && (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val
906 + DAYSECS))
907 return (true);
908 break;
910 return (false);
913 boolean
914 pred_name (pathname, stat_buf, pred_ptr)
915 char *pathname;
916 struct stat *stat_buf;
917 struct predicate *pred_ptr;
919 const char *base;
921 base = basename (pathname);
922 if (fnmatch (pred_ptr->args.str, base, FNM_PERIOD) == 0)
923 return (true);
924 return (false);
927 boolean
928 pred_negate (pathname, stat_buf, pred_ptr)
929 char *pathname;
930 struct stat *stat_buf;
931 struct predicate *pred_ptr;
933 /* Check whether we need a stat here. */
934 if (pred_ptr->need_stat)
936 if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
938 error (0, errno, "%s", pathname);
939 exit_status = 1;
940 return (false);
942 have_stat = true;
944 return (!(*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
945 pred_ptr->pred_right));
948 boolean
949 pred_newer (pathname, stat_buf, pred_ptr)
950 char *pathname;
951 struct stat *stat_buf;
952 struct predicate *pred_ptr;
954 if (stat_buf->st_mtime > pred_ptr->args.time)
955 return (true);
956 return (false);
959 boolean
960 pred_nogroup (pathname, stat_buf, pred_ptr)
961 char *pathname;
962 struct stat *stat_buf;
963 struct predicate *pred_ptr;
965 #ifdef CACHE_IDS
966 extern char *gid_unused;
968 return gid_unused[(unsigned) stat_buf->st_gid];
969 #else
970 return getgrgid (stat_buf->st_gid) == NULL;
971 #endif
974 boolean
975 pred_nouser (pathname, stat_buf, pred_ptr)
976 char *pathname;
977 struct stat *stat_buf;
978 struct predicate *pred_ptr;
980 #ifdef CACHE_IDS
981 extern char *uid_unused;
983 return uid_unused[(unsigned) stat_buf->st_uid];
984 #else
985 return getpwuid (stat_buf->st_uid) == NULL;
986 #endif
989 boolean
990 pred_ok (pathname, stat_buf, pred_ptr)
991 char *pathname;
992 struct stat *stat_buf;
993 struct predicate *pred_ptr;
995 int i, yes;
997 fflush (stdout);
998 fprintf (stderr, "< %s ... %s > ? ",
999 pred_ptr->args.exec_vec.vec[0], pathname);
1000 fflush (stderr);
1001 i = getchar ();
1002 yes = (i == 'y' || i == 'Y');
1003 while (i != EOF && i != '\n')
1004 i = getchar ();
1005 if (!yes)
1006 return (false);
1007 return pred_exec (pathname, stat_buf, pred_ptr);
1010 boolean
1011 pred_open (pathname, stat_buf, pred_ptr)
1012 char *pathname;
1013 struct stat *stat_buf;
1014 struct predicate *pred_ptr;
1016 return (true);
1019 boolean
1020 pred_or (pathname, stat_buf, pred_ptr)
1021 char *pathname;
1022 struct stat *stat_buf;
1023 struct predicate *pred_ptr;
1025 if (pred_ptr->pred_left == NULL
1026 || !(*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
1027 pred_ptr->pred_left))
1029 /* Check whether we need a stat here. */
1030 if (pred_ptr->need_stat)
1032 if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
1034 error (0, errno, "%s", pathname);
1035 exit_status = 1;
1036 return (false);
1038 have_stat = true;
1040 return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
1041 pred_ptr->pred_right));
1043 else
1044 return (true);
1047 boolean
1048 pred_path (pathname, stat_buf, pred_ptr)
1049 char *pathname;
1050 struct stat *stat_buf;
1051 struct predicate *pred_ptr;
1053 if (fnmatch (pred_ptr->args.str, pathname, 0) == 0)
1054 return (true);
1055 return (false);
1058 boolean
1059 pred_perm (pathname, stat_buf, pred_ptr)
1060 char *pathname;
1061 struct stat *stat_buf;
1062 struct predicate *pred_ptr;
1064 if (pred_ptr->args.perm & 010000)
1066 /* Magic flag set in parse_perm:
1067 true if at least the given bits are set. */
1068 if ((stat_buf->st_mode & 07777 & pred_ptr->args.perm)
1069 == (pred_ptr->args.perm & 07777))
1070 return (true);
1072 else if (pred_ptr->args.perm & 020000)
1074 /* Magic flag set in parse_perm:
1075 true if any of the given bits are set. */
1076 if ((stat_buf->st_mode & 07777) & pred_ptr->args.perm)
1077 return (true);
1079 else
1081 /* True if exactly the given bits are set. */
1082 if ((stat_buf->st_mode & 07777) == pred_ptr->args.perm)
1083 return (true);
1085 return (false);
1088 boolean
1089 pred_print (pathname, stat_buf, pred_ptr)
1090 char *pathname;
1091 struct stat *stat_buf;
1092 struct predicate *pred_ptr;
1094 puts (pathname);
1095 return (true);
1098 boolean
1099 pred_print0 (pathname, stat_buf, pred_ptr)
1100 char *pathname;
1101 struct stat *stat_buf;
1102 struct predicate *pred_ptr;
1104 fputs (pathname, stdout);
1105 putc (0, stdout);
1106 return (true);
1109 boolean
1110 pred_prune (pathname, stat_buf, pred_ptr)
1111 char *pathname;
1112 struct stat *stat_buf;
1113 struct predicate *pred_ptr;
1115 stop_at_current_level = true;
1116 return (do_dir_first); /* This is what SunOS find seems to do. */
1119 boolean
1120 pred_regex (pathname, stat_buf, pred_ptr)
1121 char *pathname;
1122 struct stat *stat_buf;
1123 struct predicate *pred_ptr;
1125 int len = strlen (pathname);
1126 if (re_match (pred_ptr->args.regex, pathname, len, 0,
1127 (struct re_registers *) NULL) == len)
1128 return (true);
1129 return (false);
1132 boolean
1133 pred_size (pathname, stat_buf, pred_ptr)
1134 char *pathname;
1135 struct stat *stat_buf;
1136 struct predicate *pred_ptr;
1138 unsigned long f_val;
1140 f_val = (stat_buf->st_size + pred_ptr->args.size.blocksize - 1)
1141 / pred_ptr->args.size.blocksize;
1142 switch (pred_ptr->args.size.kind)
1144 case COMP_GT:
1145 if (f_val > pred_ptr->args.size.size)
1146 return (true);
1147 break;
1148 case COMP_LT:
1149 if (f_val < pred_ptr->args.size.size)
1150 return (true);
1151 break;
1152 case COMP_EQ:
1153 if (f_val == pred_ptr->args.size.size)
1154 return (true);
1155 break;
1157 return (false);
1160 boolean
1161 pred_true (pathname, stat_buf, pred_ptr)
1162 char *pathname;
1163 struct stat *stat_buf;
1164 struct predicate *pred_ptr;
1166 return (true);
1169 boolean
1170 pred_type (pathname, stat_buf, pred_ptr)
1171 char *pathname;
1172 struct stat *stat_buf;
1173 struct predicate *pred_ptr;
1175 unsigned long mode = stat_buf->st_mode;
1176 unsigned long type = pred_ptr->args.type;
1178 #ifndef S_IFMT
1179 /* POSIX system; check `mode' the slow way. */
1180 if ((S_ISBLK (mode) && type == S_IFBLK)
1181 || (S_ISCHR (mode) && type == S_IFCHR)
1182 || (S_ISDIR (mode) && type == S_IFDIR)
1183 || (S_ISREG (mode) && type == S_IFREG)
1184 #ifdef S_IFLNK
1185 || (S_ISLNK (mode) && type == S_IFLNK)
1186 #endif
1187 #ifdef S_IFIFO
1188 || (S_ISFIFO (mode) && type == S_IFIFO)
1189 #endif
1190 #ifdef S_IFSOCK
1191 || (S_ISSOCK (mode) && type == S_IFSOCK)
1192 #endif
1194 #else /* S_IFMT */
1195 /* Unix system; check `mode' the fast way. */
1196 if ((mode & S_IFMT) == type)
1197 #endif /* S_IFMT */
1198 return (true);
1199 else
1200 return (false);
1203 boolean
1204 pred_uid (pathname, stat_buf, pred_ptr)
1205 char *pathname;
1206 struct stat *stat_buf;
1207 struct predicate *pred_ptr;
1209 switch (pred_ptr->args.info.kind)
1211 case COMP_GT:
1212 if (stat_buf->st_uid > pred_ptr->args.info.l_val)
1213 return (true);
1214 break;
1215 case COMP_LT:
1216 if (stat_buf->st_uid < pred_ptr->args.info.l_val)
1217 return (true);
1218 break;
1219 case COMP_EQ:
1220 if (stat_buf->st_uid == pred_ptr->args.info.l_val)
1221 return (true);
1222 break;
1224 return (false);
1227 boolean
1228 pred_used (pathname, stat_buf, pred_ptr)
1229 char *pathname;
1230 struct stat *stat_buf;
1231 struct predicate *pred_ptr;
1233 time_t delta;
1235 delta = stat_buf->st_atime - stat_buf->st_ctime; /* Use difftime? */
1236 switch (pred_ptr->args.info.kind)
1238 case COMP_GT:
1239 if (delta > (time_t) pred_ptr->args.info.l_val)
1240 return (true);
1241 break;
1242 case COMP_LT:
1243 if (delta < (time_t) pred_ptr->args.info.l_val)
1244 return (true);
1245 break;
1246 case COMP_EQ:
1247 if ((delta >= (time_t) pred_ptr->args.info.l_val)
1248 && (delta < (time_t) pred_ptr->args.info.l_val + DAYSECS))
1249 return (true);
1250 break;
1252 return (false);
1255 boolean
1256 pred_user (pathname, stat_buf, pred_ptr)
1257 char *pathname;
1258 struct stat *stat_buf;
1259 struct predicate *pred_ptr;
1261 if (pred_ptr->args.uid == stat_buf->st_uid)
1262 return (true);
1263 else
1264 return (false);
1267 boolean
1268 pred_xtype (pathname, stat_buf, pred_ptr)
1269 char *pathname;
1270 struct stat *stat_buf;
1271 struct predicate *pred_ptr;
1273 struct stat sbuf;
1274 int (*ystat) ();
1276 ystat = xstat == lstat ? stat : lstat;
1277 if ((*ystat) (rel_pathname, &sbuf) != 0)
1279 if (ystat == stat && errno == ENOENT)
1280 /* Mimic behavior of ls -lL. */
1281 return (pred_type (pathname, stat_buf, pred_ptr));
1282 error (0, errno, "%s", pathname);
1283 exit_status = 1;
1284 return (false);
1286 return (pred_type (pathname, &sbuf, pred_ptr));
1289 /* 1) fork to get a child; parent remembers the child pid
1290 2) child execs the command requested
1291 3) parent waits for child; checks for proper pid of child
1293 Possible returns:
1295 ret errno status(h) status(l)
1297 pid x signal# 0177 stopped
1298 pid x exit arg 0 term by _exit
1299 pid x 0 signal # term by signal
1300 -1 EINTR parent got signal
1301 -1 other some other kind of error
1303 Return true only if the pid matches, status(l) is
1304 zero, and the exit arg (status high) is 0.
1305 Otherwise return false, possibly printing an error message. */
1307 static boolean
1308 launch (pred_ptr)
1309 struct predicate *pred_ptr;
1311 int status;
1312 pid_t wait_ret, child_pid;
1313 struct exec_val *execp; /* Pointer for efficiency. */
1314 static int first_time = 1;
1316 execp = &pred_ptr->args.exec_vec;
1318 /* Make sure output of command doesn't get mixed with find output. */
1319 fflush (stdout);
1320 fflush (stderr);
1322 /* Make sure to listen for the kids. */
1323 if (first_time)
1325 first_time = 0;
1326 signal (SIGCHLD, SIG_DFL);
1329 child_pid = fork ();
1330 if (child_pid == -1)
1331 error (1, errno, "cannot fork");
1332 if (child_pid == 0)
1334 /* We be the child. */
1335 #ifndef HAVE_FCHDIR
1336 if (chdir (starting_dir) < 0)
1338 error (0, errno, "%s", starting_dir);
1339 _exit (1);
1341 #else
1342 if (fchdir (starting_desc) < 0)
1344 error (0, errno, "cannot return to starting directory");
1345 _exit (1);
1347 #endif
1348 execvp (execp->vec[0], execp->vec);
1349 error (0, errno, "%s", execp->vec[0]);
1350 _exit (1);
1353 wait_ret = wait (&status);
1354 if (wait_ret == -1)
1356 error (0, errno, "error waiting for %s", execp->vec[0]);
1357 exit_status = 1;
1358 return (false);
1360 if (wait_ret != child_pid)
1362 error (0, 0, "wait got pid %d, expected pid %d", wait_ret, child_pid);
1363 exit_status = 1;
1364 return (false);
1366 if (WIFSTOPPED (status))
1368 error (0, 0, "%s stopped by signal %d",
1369 execp->vec[0], WSTOPSIG (status));
1370 exit_status = 1;
1371 return (false);
1373 if (WIFSIGNALED (status))
1375 error (0, 0, "%s terminated by signal %d",
1376 execp->vec[0], WTERMSIG (status));
1377 exit_status = 1;
1378 return (false);
1380 return (!WEXITSTATUS (status));
1383 /* Return a static string formatting the time WHEN according to the
1384 strftime format character KIND. */
1386 static char *
1387 format_date (when, kind)
1388 time_t when;
1389 int kind;
1391 static char fmt[3];
1392 static char buf[64]; /* More than enough space. */
1394 if (kind == '@')
1396 sprintf (buf, "%ld", when);
1397 return (buf);
1399 else
1401 fmt[0] = '%';
1402 fmt[1] = kind;
1403 fmt[2] = '\0';
1404 if (strftime (buf, sizeof (buf), fmt, localtime (&when)))
1405 return (buf);
1407 return "";
1410 #ifdef DEBUG
1411 /* Return a pointer to the string representation of
1412 the predicate function PRED_FUNC. */
1414 char *
1415 find_pred_name (pred_func)
1416 PFB pred_func;
1418 int i;
1420 for (i = 0; pred_table[i].pred_func != 0; i++)
1421 if (pred_table[i].pred_func == pred_func)
1422 break;
1423 return (pred_table[i].pred_name);
1426 static char *
1427 type_name (type)
1428 short type;
1430 int i;
1432 for (i = 0; type_table[i].type != (short) -1; i++)
1433 if (type_table[i].type == type)
1434 break;
1435 return (type_table[i].type_name);
1438 static char *
1439 prec_name (prec)
1440 short prec;
1442 int i;
1444 for (i = 0; prec_table[i].prec != (short) -1; i++)
1445 if (prec_table[i].prec == prec)
1446 break;
1447 return (prec_table[i].prec_name);
1450 /* Walk the expression tree NODE to stdout.
1451 INDENT is the number of levels to indent the left margin. */
1453 void
1454 print_tree (node, indent)
1455 struct predicate *node;
1456 int indent;
1458 int i;
1460 if (node == NULL)
1461 return;
1462 for (i = 0; i < indent; i++)
1463 printf (" ");
1464 printf ("pred = %s type = %s prec = %s addr = %x\n",
1465 find_pred_name (node->pred_func),
1466 type_name (node->p_type), prec_name (node->p_prec), node);
1467 for (i = 0; i < indent; i++)
1468 printf (" ");
1469 printf ("left:\n");
1470 print_tree (node->pred_left, indent + 1);
1471 for (i = 0; i < indent; i++)
1472 printf (" ");
1473 printf ("right:\n");
1474 print_tree (node->pred_right, indent + 1);
1477 /* Copy STR into BUF and trim blanks from the end of BUF.
1478 Return BUF. */
1480 static char *
1481 blank_rtrim (str, buf)
1482 char *str;
1483 char *buf;
1485 int i;
1487 if (str == NULL)
1488 return (NULL);
1489 strcpy (buf, str);
1490 i = strlen (buf) - 1;
1491 while ((i >= 0) && ((buf[i] == ' ') || buf[i] == '\t'))
1492 i--;
1493 buf[++i] = '\0';
1494 return (buf);
1497 /* Print out the predicate list starting at NODE. */
1499 void
1500 print_list (node)
1501 struct predicate *node;
1503 struct predicate *cur;
1504 char name[256];
1506 cur = node;
1507 while (cur != NULL)
1509 printf ("%s ", blank_rtrim (find_pred_name (cur->pred_func), name));
1510 cur = cur->pred_next;
1512 printf ("\n");
1514 #endif /* DEBUG */