*** empty log message ***
[findutils.git] / find / pred.c
blob3d3bff6fb606249f9cc4b9e93f810bcfb8da5ab2
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 ENABLE_NLS
32 # include <libintl.h>
33 # define _(Text) gettext (Text)
34 #else
35 # define _(Text) Text
36 #endif
37 #ifdef gettext_noop
38 # define N_(String) gettext_noop (String)
39 #else
40 # define N_(String) (String)
41 #endif
43 #if !defined(SIGCHLD) && defined(SIGCLD)
44 #define SIGCHLD SIGCLD
45 #endif
47 #if HAVE_DIRENT_H
48 # include <dirent.h>
49 # define NAMLEN(dirent) strlen((dirent)->d_name)
50 #else
51 # define dirent direct
52 # define NAMLEN(dirent) (dirent)->d_namlen
53 # if HAVE_SYS_NDIR_H
54 # include <sys/ndir.h>
55 # endif
56 # if HAVE_SYS_DIR_H
57 # include <sys/dir.h>
58 # endif
59 # if HAVE_NDIR_H
60 # include <ndir.h>
61 # endif
62 #endif
64 #ifdef CLOSEDIR_VOID
65 /* Fake a return value. */
66 #define CLOSEDIR(d) (closedir (d), 0)
67 #else
68 #define CLOSEDIR(d) closedir (d)
69 #endif
71 /* Extract or fake data from a `struct stat'.
72 ST_NBLOCKS: Number of 512-byte blocks in the file
73 (including indirect blocks).
74 HP-UX, perhaps uniquely, counts st_blocks in 1024-byte units.
75 This workaround loses when mixing HP-UX and 4BSD filesystems, though. */
76 #ifdef _POSIX_SOURCE
77 # define ST_NBLOCKS(statp) (((statp)->st_size + 512 - 1) / 512)
78 #else
79 # ifndef HAVE_ST_BLOCKS
80 # define ST_NBLOCKS(statp) (st_blocks ((statp)->st_size))
81 # else
82 # if defined(hpux) || defined(__hpux__)
83 # define ST_NBLOCKS(statp) ((statp)->st_blocks * 2)
84 # else
85 # define ST_NBLOCKS(statp) ((statp)->st_blocks)
86 # endif
87 # endif
88 #endif
90 static boolean insert_lname PARAMS((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr, boolean ignore_case));
91 static boolean launch PARAMS((struct predicate *pred_ptr));
92 static char *format_date PARAMS((time_t when, int kind));
94 #ifdef DEBUG
95 struct pred_assoc
97 PFB pred_func;
98 char *pred_name;
101 struct pred_assoc pred_table[] =
103 {pred_amin, "amin "},
104 {pred_and, "and "},
105 {pred_anewer, "anewer "},
106 {pred_atime, "atime "},
107 {pred_close, ") "},
108 {pred_amin, "cmin "},
109 {pred_cnewer, "cnewer "},
110 {pred_comma, ", "},
111 {pred_ctime, "ctime "},
112 {pred_empty, "empty "},
113 {pred_exec, "exec "},
114 {pred_false, "false "},
115 {pred_fprint, "fprint "},
116 {pred_fprint0, "fprint0 "},
117 {pred_fprintf, "fprintf "},
118 {pred_fstype, "fstype "},
119 {pred_gid, "gid "},
120 {pred_group, "group "},
121 {pred_ilname, "ilname "},
122 {pred_iname, "iname "},
123 {pred_inum, "inum "},
124 {pred_ipath, "ipath "},
125 {pred_links, "links "},
126 {pred_lname, "lname "},
127 {pred_ls, "ls "},
128 {pred_amin, "mmin "},
129 {pred_mtime, "mtime "},
130 {pred_name, "name "},
131 {pred_negate, "not "},
132 {pred_newer, "newer "},
133 {pred_nogroup, "nogroup "},
134 {pred_nouser, "nouser "},
135 {pred_ok, "ok "},
136 {pred_open, "( "},
137 {pred_or, "or "},
138 {pred_path, "path "},
139 {pred_perm, "perm "},
140 {pred_print, "print "},
141 {pred_print0, "print0 "},
142 {pred_prune, "prune "},
143 {pred_regex, "regex "},
144 {pred_size, "size "},
145 {pred_true, "true "},
146 {pred_type, "type "},
147 {pred_uid, "uid "},
148 {pred_used, "used "},
149 {pred_user, "user "},
150 {pred_xtype, "xtype "},
151 {0, "none "}
154 struct op_assoc
156 short type;
157 char *type_name;
160 struct op_assoc type_table[] =
162 {NO_TYPE, "no "},
163 {PRIMARY_TYPE, "primary "},
164 {UNI_OP, "uni_op "},
165 {BI_OP, "bi_op "},
166 {OPEN_PAREN, "open_paren "},
167 {CLOSE_PAREN, "close_paren "},
168 {-1, "unknown "}
171 struct prec_assoc
173 short prec;
174 char *prec_name;
177 struct prec_assoc prec_table[] =
179 {NO_PREC, "no "},
180 {COMMA_PREC, "comma "},
181 {OR_PREC, "or "},
182 {AND_PREC, "and "},
183 {NEGATE_PREC, "negate "},
184 {MAX_PREC, "max "},
185 {-1, "unknown "}
187 #endif /* DEBUG */
189 /* Predicate processing routines.
191 PATHNAME is the full pathname of the file being checked.
192 *STAT_BUF contains information about PATHNAME.
193 *PRED_PTR contains information for applying the predicate.
195 Return true if the file passes this predicate, false if not. */
197 boolean
198 pred_amin (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
200 switch (pred_ptr->args.info.kind)
202 case COMP_GT:
203 if (stat_buf->st_atime > (time_t) pred_ptr->args.info.l_val)
204 return (true);
205 break;
206 case COMP_LT:
207 if (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val)
208 return (true);
209 break;
210 case COMP_EQ:
211 if ((stat_buf->st_atime >= (time_t) pred_ptr->args.info.l_val)
212 && (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val + 60))
213 return (true);
214 break;
216 return (false);
219 boolean
220 pred_and (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
222 if (pred_ptr->pred_left == NULL
223 || (*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
224 pred_ptr->pred_left))
226 /* Check whether we need a stat here. */
227 if (pred_ptr->need_stat)
229 if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
231 error (0, errno, "%s", pathname);
232 exit_status = 1;
233 return (false);
235 have_stat = true;
237 return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
238 pred_ptr->pred_right));
240 else
241 return (false);
244 boolean
245 pred_anewer (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
247 if (stat_buf->st_atime > pred_ptr->args.time)
248 return (true);
249 return (false);
252 boolean
253 pred_atime (char *pathname, struct stat *stat_buf, 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 (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
278 return (true);
281 boolean
282 pred_cmin (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
284 switch (pred_ptr->args.info.kind)
286 case COMP_GT:
287 if (stat_buf->st_ctime > (time_t) pred_ptr->args.info.l_val)
288 return (true);
289 break;
290 case COMP_LT:
291 if (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val)
292 return (true);
293 break;
294 case COMP_EQ:
295 if ((stat_buf->st_ctime >= (time_t) pred_ptr->args.info.l_val)
296 && (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val + 60))
297 return (true);
298 break;
300 return (false);
303 boolean
304 pred_cnewer (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
306 if (stat_buf->st_ctime > pred_ptr->args.time)
307 return (true);
308 return (false);
311 boolean
312 pred_comma (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
314 if (pred_ptr->pred_left != NULL)
315 (*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
316 pred_ptr->pred_left);
317 /* Check whether we need a stat here. */
318 if (pred_ptr->need_stat)
320 if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
322 error (0, errno, "%s", pathname);
323 exit_status = 1;
324 return (false);
326 have_stat = true;
328 return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
329 pred_ptr->pred_right));
332 boolean
333 pred_ctime (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
335 switch (pred_ptr->args.info.kind)
337 case COMP_GT:
338 if (stat_buf->st_ctime > (time_t) pred_ptr->args.info.l_val)
339 return (true);
340 break;
341 case COMP_LT:
342 if (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val)
343 return (true);
344 break;
345 case COMP_EQ:
346 if ((stat_buf->st_ctime >= (time_t) pred_ptr->args.info.l_val)
347 && (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val
348 + DAYSECS))
349 return (true);
350 break;
352 return (false);
355 boolean
356 pred_empty (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
358 if (S_ISDIR (stat_buf->st_mode))
360 DIR *d;
361 struct dirent *dp;
362 boolean empty = true;
364 errno = 0;
365 d = opendir (rel_pathname);
366 if (d == NULL)
368 error (0, errno, "%s", pathname);
369 exit_status = 1;
370 return (false);
372 for (dp = readdir (d); dp; dp = readdir (d))
374 if (dp->d_name[0] != '.'
375 || (dp->d_name[1] != '\0'
376 && (dp->d_name[1] != '.' || dp->d_name[2] != '\0')))
378 empty = false;
379 break;
382 if (CLOSEDIR (d))
384 error (0, errno, "%s", pathname);
385 exit_status = 1;
386 return (false);
388 return (empty);
390 else if (S_ISREG (stat_buf->st_mode))
391 return (stat_buf->st_size == 0);
392 else
393 return (false);
396 boolean
397 pred_exec (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
399 int i;
400 int path_pos;
401 struct exec_val *execp; /* Pointer for efficiency. */
403 execp = &pred_ptr->args.exec_vec;
405 /* Replace "{}" with the real path in each affected arg. */
406 for (path_pos = 0; execp->paths[path_pos].offset >= 0; path_pos++)
408 register char *from, *to;
410 i = execp->paths[path_pos].offset;
411 execp->vec[i] =
412 xmalloc (strlen (execp->paths[path_pos].origarg) + 1
413 + (strlen (pathname) - 2) * execp->paths[path_pos].count);
414 for (from = execp->paths[path_pos].origarg, to = execp->vec[i]; *from; )
415 if (from[0] == '{' && from[1] == '}')
417 to = stpcpy (to, pathname);
418 from += 2;
420 else
421 *to++ = *from++;
422 *to = *from; /* Copy null. */
425 i = launch (pred_ptr);
427 /* Free the temporary args. */
428 for (path_pos = 0; execp->paths[path_pos].offset >= 0; path_pos++)
429 free (execp->vec[execp->paths[path_pos].offset]);
431 return (i);
434 boolean
435 pred_false (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
437 return (false);
440 boolean
441 pred_fls (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
443 list_file (pathname, rel_pathname, stat_buf, pred_ptr->args.stream);
444 return (true);
447 boolean
448 pred_fprint (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
450 fputs (pathname, pred_ptr->args.stream);
451 putc ('\n', pred_ptr->args.stream);
452 return (true);
455 boolean
456 pred_fprint0 (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
458 fputs (pathname, pred_ptr->args.stream);
459 putc (0, pred_ptr->args.stream);
460 return (true);
463 boolean
464 pred_fprintf (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
466 FILE *fp = pred_ptr->args.printf_vec.stream;
467 struct segment *segment;
468 char *cp;
470 for (segment = pred_ptr->args.printf_vec.segment; segment;
471 segment = segment->next)
473 if (segment->kind & 0xff00) /* Component of date. */
475 time_t t;
477 switch (segment->kind & 0xff)
479 case 'A':
480 t = stat_buf->st_atime;
481 break;
482 case 'C':
483 t = stat_buf->st_ctime;
484 break;
485 case 'T':
486 t = stat_buf->st_mtime;
487 break;
488 default:
489 abort ();
491 fprintf (fp, segment->text,
492 format_date (t, (segment->kind >> 8) & 0xff));
493 continue;
496 switch (segment->kind)
498 case KIND_PLAIN: /* Plain text string (no % conversion). */
499 fwrite (segment->text, 1, segment->text_len, fp);
500 break;
501 case KIND_STOP: /* Terminate argument and flush output. */
502 fwrite (segment->text, 1, segment->text_len, fp);
503 fflush (fp);
504 return (true);
505 case 'a': /* atime in `ctime' format. */
506 cp = ctime (&stat_buf->st_atime);
507 cp[24] = '\0';
508 fprintf (fp, segment->text, cp);
509 break;
510 case 'b': /* size in 512-byte blocks */
511 fprintf (fp, segment->text, ST_NBLOCKS (stat_buf));
512 break;
513 case 'c': /* ctime in `ctime' format */
514 cp = ctime (&stat_buf->st_ctime);
515 cp[24] = '\0';
516 fprintf (fp, segment->text, cp);
517 break;
518 case 'd': /* depth in search tree */
519 fprintf (fp, segment->text, curdepth);
520 break;
521 case 'f': /* basename of path */
522 cp = strrchr (pathname, '/');
523 if (cp)
524 cp++;
525 else
526 cp = pathname;
527 fprintf (fp, segment->text, cp);
528 break;
529 case 'F': /* filesystem type */
530 fprintf (fp, segment->text,
531 filesystem_type (pathname, rel_pathname, stat_buf));
532 break;
533 case 'g': /* group name */
535 struct group *g;
537 g = getgrgid (stat_buf->st_gid);
538 if (g)
540 segment->text[segment->text_len] = 's';
541 fprintf (fp, segment->text, g->gr_name);
542 break;
544 /* else fallthru */
546 case 'G': /* GID number */
547 segment->text[segment->text_len] = 'u';
548 fprintf (fp, segment->text, stat_buf->st_gid);
549 break;
550 case 'h': /* leading directories part of path */
552 char cc;
554 cp = strrchr (pathname, '/');
555 if (cp == NULL) /* No leading directories. */
556 break;
557 cc = *cp;
558 *cp = '\0';
559 fprintf (fp, segment->text, pathname);
560 *cp = cc;
561 break;
563 case 'H': /* ARGV element file was found under */
565 char cc = pathname[path_length];
567 pathname[path_length] = '\0';
568 fprintf (fp, segment->text, pathname);
569 pathname[path_length] = cc;
570 break;
572 case 'i': /* inode number */
573 fprintf (fp, segment->text, stat_buf->st_ino);
574 break;
575 case 'k': /* size in 1K blocks */
576 fprintf (fp, segment->text, (ST_NBLOCKS (stat_buf) + 1) / 2);
577 break;
578 case 'l': /* object of symlink */
579 #ifdef S_ISLNK
581 char *linkname = 0;
583 if (S_ISLNK (stat_buf->st_mode))
585 linkname = get_link_name (pathname, rel_pathname);
586 if (linkname == 0)
587 exit_status = 1;
589 if (linkname)
591 fprintf (fp, segment->text, linkname);
592 free (linkname);
594 else
595 fprintf (fp, segment->text, "");
597 #endif /* S_ISLNK */
598 break;
599 case 'm': /* mode as octal number (perms only) */
600 fprintf (fp, segment->text, stat_buf->st_mode & 07777);
601 break;
602 case 'n': /* number of links */
603 fprintf (fp, segment->text, stat_buf->st_nlink);
604 break;
605 case 'p': /* pathname */
606 fprintf (fp, segment->text, pathname);
607 break;
608 case 'P': /* pathname with ARGV element stripped */
609 if (curdepth)
611 cp = pathname + path_length;
612 if (*cp == '/')
613 /* Move past the slash between the ARGV element
614 and the rest of the pathname. But if the ARGV element
615 ends in a slash, we didn't add another, so we've
616 already skipped past it. */
617 cp++;
619 else
620 cp = "";
621 fprintf (fp, segment->text, cp);
622 break;
623 case 's': /* size in bytes */
624 fprintf (fp, segment->text, stat_buf->st_size);
625 break;
626 case 't': /* mtime in `ctime' format */
627 cp = ctime (&stat_buf->st_mtime);
628 cp[24] = '\0';
629 fprintf (fp, segment->text, cp);
630 break;
631 case 'u': /* user name */
633 struct passwd *p;
635 p = getpwuid (stat_buf->st_uid);
636 if (p)
638 segment->text[segment->text_len] = 's';
639 fprintf (fp, segment->text, p->pw_name);
640 break;
642 /* else fallthru */
644 case 'U': /* UID number */
645 segment->text[segment->text_len] = 'u';
646 fprintf (fp, segment->text, stat_buf->st_uid);
647 break;
650 return (true);
653 boolean
654 pred_fstype (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
656 if (strcmp (filesystem_type (pathname, rel_pathname, stat_buf),
657 pred_ptr->args.str) == 0)
658 return (true);
659 return (false);
662 boolean
663 pred_gid (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
665 switch (pred_ptr->args.info.kind)
667 case COMP_GT:
668 if (stat_buf->st_gid > pred_ptr->args.info.l_val)
669 return (true);
670 break;
671 case COMP_LT:
672 if (stat_buf->st_gid < pred_ptr->args.info.l_val)
673 return (true);
674 break;
675 case COMP_EQ:
676 if (stat_buf->st_gid == pred_ptr->args.info.l_val)
677 return (true);
678 break;
680 return (false);
683 boolean
684 pred_group (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
686 if (pred_ptr->args.gid == stat_buf->st_gid)
687 return (true);
688 else
689 return (false);
692 boolean
693 pred_ilname (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
695 return insert_lname (pathname, stat_buf, pred_ptr, true);
698 boolean
699 pred_iname (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
701 const char *base;
703 base = base_name (pathname);
704 if (fnmatch (pred_ptr->args.str, base, FNM_PERIOD | FNM_CASEFOLD) == 0)
705 return (true);
706 return (false);
709 boolean
710 pred_inum (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
712 switch (pred_ptr->args.info.kind)
714 case COMP_GT:
715 if (stat_buf->st_ino > pred_ptr->args.info.l_val)
716 return (true);
717 break;
718 case COMP_LT:
719 if (stat_buf->st_ino < pred_ptr->args.info.l_val)
720 return (true);
721 break;
722 case COMP_EQ:
723 if (stat_buf->st_ino == pred_ptr->args.info.l_val)
724 return (true);
725 break;
727 return (false);
730 boolean
731 pred_ipath (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
733 if (fnmatch (pred_ptr->args.str, pathname, FNM_CASEFOLD) == 0)
734 return (true);
735 return (false);
738 boolean
739 pred_links (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
741 switch (pred_ptr->args.info.kind)
743 case COMP_GT:
744 if (stat_buf->st_nlink > pred_ptr->args.info.l_val)
745 return (true);
746 break;
747 case COMP_LT:
748 if (stat_buf->st_nlink < pred_ptr->args.info.l_val)
749 return (true);
750 break;
751 case COMP_EQ:
752 if (stat_buf->st_nlink == pred_ptr->args.info.l_val)
753 return (true);
754 break;
756 return (false);
759 boolean
760 pred_lname (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
762 return insert_lname (pathname, stat_buf, pred_ptr, false);
765 static boolean
766 insert_lname (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr, boolean ignore_case)
768 boolean ret = false;
769 #ifdef S_ISLNK
770 if (S_ISLNK (stat_buf->st_mode))
772 char *linkname = get_link_name (pathname, rel_pathname);
773 if (linkname)
775 if (fnmatch (pred_ptr->args.str, linkname,
776 ignore_case ? FNM_CASEFOLD : 0) == 0)
777 ret = true;
778 free (linkname);
781 #endif /* S_ISLNK */
782 return (ret);
785 boolean
786 pred_ls (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
788 list_file (pathname, rel_pathname, stat_buf, stdout);
789 return (true);
792 boolean
793 pred_mmin (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
795 switch (pred_ptr->args.info.kind)
797 case COMP_GT:
798 if (stat_buf->st_mtime > (time_t) pred_ptr->args.info.l_val)
799 return (true);
800 break;
801 case COMP_LT:
802 if (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val)
803 return (true);
804 break;
805 case COMP_EQ:
806 if ((stat_buf->st_mtime >= (time_t) pred_ptr->args.info.l_val)
807 && (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val + 60))
808 return (true);
809 break;
811 return (false);
814 boolean
815 pred_mtime (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
817 switch (pred_ptr->args.info.kind)
819 case COMP_GT:
820 if (stat_buf->st_mtime > (time_t) pred_ptr->args.info.l_val)
821 return (true);
822 break;
823 case COMP_LT:
824 if (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val)
825 return (true);
826 break;
827 case COMP_EQ:
828 if ((stat_buf->st_mtime >= (time_t) pred_ptr->args.info.l_val)
829 && (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val
830 + DAYSECS))
831 return (true);
832 break;
834 return (false);
837 boolean
838 pred_name (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
840 const char *base;
842 base = base_name (pathname);
843 if (fnmatch (pred_ptr->args.str, base, FNM_PERIOD) == 0)
844 return (true);
845 return (false);
848 boolean
849 pred_negate (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
851 /* Check whether we need a stat here. */
852 if (pred_ptr->need_stat)
854 if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
856 error (0, errno, "%s", pathname);
857 exit_status = 1;
858 return (false);
860 have_stat = true;
862 return (!(*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
863 pred_ptr->pred_right));
866 boolean
867 pred_newer (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
869 if (stat_buf->st_mtime > pred_ptr->args.time)
870 return (true);
871 return (false);
874 boolean
875 pred_nogroup (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
877 #ifdef CACHE_IDS
878 extern char *gid_unused;
880 return gid_unused[(unsigned) stat_buf->st_gid];
881 #else
882 return getgrgid (stat_buf->st_gid) == NULL;
883 #endif
886 boolean
887 pred_nouser (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
889 #ifdef CACHE_IDS
890 extern char *uid_unused;
892 return uid_unused[(unsigned) stat_buf->st_uid];
893 #else
894 return getpwuid (stat_buf->st_uid) == NULL;
895 #endif
898 boolean
899 pred_ok (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
901 int i, yes;
903 fflush (stdout);
904 /* The draft open standard requires that, in the POSIX locale,
905 the last non-blank character of this prompt be '?'.
906 The exact format is not specified.
907 This standard does not have requirements for locales other than POSIX
909 fprintf (stderr, _("< %s ... %s > ? "),
910 pred_ptr->args.exec_vec.vec[0], pathname);
911 fflush (stderr);
912 i = getchar ();
913 yes = (i == 'y' || i == 'Y');
914 while (i != EOF && i != '\n')
915 i = getchar ();
916 if (!yes)
917 return (false);
918 return pred_exec (pathname, stat_buf, pred_ptr);
921 boolean
922 pred_open (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
924 return (true);
927 boolean
928 pred_or (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
930 if (pred_ptr->pred_left == NULL
931 || !(*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
932 pred_ptr->pred_left))
934 /* Check whether we need a stat here. */
935 if (pred_ptr->need_stat)
937 if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
939 error (0, errno, "%s", pathname);
940 exit_status = 1;
941 return (false);
943 have_stat = true;
945 return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
946 pred_ptr->pred_right));
948 else
949 return (true);
952 boolean
953 pred_path (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
955 if (fnmatch (pred_ptr->args.str, pathname, 0) == 0)
956 return (true);
957 return (false);
960 boolean
961 pred_perm (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
963 if (pred_ptr->args.perm & 010000)
965 /* Magic flag set in parse_perm:
966 true if at least the given bits are set. */
967 if ((stat_buf->st_mode & 07777 & pred_ptr->args.perm)
968 == (pred_ptr->args.perm & 07777))
969 return (true);
971 else if (pred_ptr->args.perm & 020000)
973 /* Magic flag set in parse_perm:
974 true if any of the given bits are set. */
975 if ((stat_buf->st_mode & 07777) & pred_ptr->args.perm)
976 return (true);
978 else
980 /* True if exactly the given bits are set. */
981 if ((stat_buf->st_mode & 07777) == pred_ptr->args.perm)
982 return (true);
984 return (false);
987 boolean
988 pred_print (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
990 puts (pathname);
991 return (true);
994 boolean
995 pred_print0 (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
997 fputs (pathname, stdout);
998 putc (0, stdout);
999 return (true);
1002 boolean
1003 pred_prune (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1005 stop_at_current_level = true;
1006 return (do_dir_first); /* This is what SunOS find seems to do. */
1009 boolean
1010 pred_regex (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1012 int len = strlen (pathname);
1013 if (re_match (pred_ptr->args.regex, pathname, len, 0,
1014 (struct re_registers *) NULL) == len)
1015 return (true);
1016 return (false);
1019 boolean
1020 pred_size (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1022 unsigned long f_val;
1024 f_val = (stat_buf->st_size + pred_ptr->args.size.blocksize - 1)
1025 / pred_ptr->args.size.blocksize;
1026 switch (pred_ptr->args.size.kind)
1028 case COMP_GT:
1029 if (f_val > pred_ptr->args.size.size)
1030 return (true);
1031 break;
1032 case COMP_LT:
1033 if (f_val < pred_ptr->args.size.size)
1034 return (true);
1035 break;
1036 case COMP_EQ:
1037 if (f_val == pred_ptr->args.size.size)
1038 return (true);
1039 break;
1041 return (false);
1044 boolean
1045 pred_true (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1047 return (true);
1050 boolean
1051 pred_type (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1053 unsigned long mode = stat_buf->st_mode;
1054 unsigned long type = pred_ptr->args.type;
1056 #ifndef S_IFMT
1057 /* POSIX system; check `mode' the slow way. */
1058 if ((S_ISBLK (mode) && type == S_IFBLK)
1059 || (S_ISCHR (mode) && type == S_IFCHR)
1060 || (S_ISDIR (mode) && type == S_IFDIR)
1061 || (S_ISREG (mode) && type == S_IFREG)
1062 #ifdef S_IFLNK
1063 || (S_ISLNK (mode) && type == S_IFLNK)
1064 #endif
1065 #ifdef S_IFIFO
1066 || (S_ISFIFO (mode) && type == S_IFIFO)
1067 #endif
1068 #ifdef S_IFSOCK
1069 || (S_ISSOCK (mode) && type == S_IFSOCK)
1070 #endif
1072 #else /* S_IFMT */
1073 /* Unix system; check `mode' the fast way. */
1074 if ((mode & S_IFMT) == type)
1075 #endif /* S_IFMT */
1076 return (true);
1077 else
1078 return (false);
1081 boolean
1082 pred_uid (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1084 switch (pred_ptr->args.info.kind)
1086 case COMP_GT:
1087 if (stat_buf->st_uid > pred_ptr->args.info.l_val)
1088 return (true);
1089 break;
1090 case COMP_LT:
1091 if (stat_buf->st_uid < pred_ptr->args.info.l_val)
1092 return (true);
1093 break;
1094 case COMP_EQ:
1095 if (stat_buf->st_uid == pred_ptr->args.info.l_val)
1096 return (true);
1097 break;
1099 return (false);
1102 boolean
1103 pred_used (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1105 time_t delta;
1107 delta = stat_buf->st_atime - stat_buf->st_ctime; /* Use difftime? */
1108 switch (pred_ptr->args.info.kind)
1110 case COMP_GT:
1111 if (delta > (time_t) pred_ptr->args.info.l_val)
1112 return (true);
1113 break;
1114 case COMP_LT:
1115 if (delta < (time_t) pred_ptr->args.info.l_val)
1116 return (true);
1117 break;
1118 case COMP_EQ:
1119 if ((delta >= (time_t) pred_ptr->args.info.l_val)
1120 && (delta < (time_t) pred_ptr->args.info.l_val + DAYSECS))
1121 return (true);
1122 break;
1124 return (false);
1127 boolean
1128 pred_user (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1130 if (pred_ptr->args.uid == stat_buf->st_uid)
1131 return (true);
1132 else
1133 return (false);
1136 boolean
1137 pred_xtype (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1139 struct stat sbuf;
1140 int (*ystat) ();
1142 ystat = xstat == lstat ? stat : lstat;
1143 if ((*ystat) (rel_pathname, &sbuf) != 0)
1145 if (ystat == stat && errno == ENOENT)
1146 /* Mimic behavior of ls -lL. */
1147 return (pred_type (pathname, stat_buf, pred_ptr));
1148 error (0, errno, "%s", pathname);
1149 exit_status = 1;
1150 return (false);
1152 return (pred_type (pathname, &sbuf, pred_ptr));
1155 /* 1) fork to get a child; parent remembers the child pid
1156 2) child execs the command requested
1157 3) parent waits for child; checks for proper pid of child
1159 Possible returns:
1161 ret errno status(h) status(l)
1163 pid x signal# 0177 stopped
1164 pid x exit arg 0 term by _exit
1165 pid x 0 signal # term by signal
1166 -1 EINTR parent got signal
1167 -1 other some other kind of error
1169 Return true only if the pid matches, status(l) is
1170 zero, and the exit arg (status high) is 0.
1171 Otherwise return false, possibly printing an error message. */
1173 static boolean
1174 launch (struct predicate *pred_ptr)
1176 int status;
1177 pid_t wait_ret, child_pid;
1178 struct exec_val *execp; /* Pointer for efficiency. */
1179 static int first_time = 1;
1181 execp = &pred_ptr->args.exec_vec;
1183 /* Make sure output of command doesn't get mixed with find output. */
1184 fflush (stdout);
1185 fflush (stderr);
1187 /* Make sure to listen for the kids. */
1188 if (first_time)
1190 first_time = 0;
1191 signal (SIGCHLD, SIG_DFL);
1194 child_pid = fork ();
1195 if (child_pid == -1)
1196 error (1, errno, _("cannot fork"));
1197 if (child_pid == 0)
1199 /* We be the child. */
1200 #ifndef HAVE_FCHDIR
1201 if (chdir (starting_dir) < 0)
1203 error (0, errno, "%s", starting_dir);
1204 _exit (1);
1206 #else
1207 if (fchdir (starting_desc) < 0)
1209 error (0, errno, _("cannot return to starting directory"));
1210 _exit (1);
1212 #endif
1213 execvp (execp->vec[0], execp->vec);
1214 error (0, errno, "%s", execp->vec[0]);
1215 _exit (1);
1218 wait_ret = wait (&status);
1219 if (wait_ret == -1)
1221 error (0, errno, _("error waiting for %s"), execp->vec[0]);
1222 exit_status = 1;
1223 return (false);
1225 if (wait_ret != child_pid)
1227 error (0, 0, _("wait got pid %d, expected pid %d"), wait_ret, child_pid);
1228 exit_status = 1;
1229 return (false);
1231 if (WIFSTOPPED (status))
1233 error (0, 0, _("%s stopped by signal %d"),
1234 execp->vec[0], WSTOPSIG (status));
1235 exit_status = 1;
1236 return (false);
1238 if (WIFSIGNALED (status))
1240 error (0, 0, _("%s terminated by signal %d"),
1241 execp->vec[0], WTERMSIG (status));
1242 exit_status = 1;
1243 return (false);
1245 return (!WEXITSTATUS (status));
1248 /* Return a static string formatting the time WHEN according to the
1249 strftime format character KIND. */
1251 static char *
1252 format_date (time_t when, int kind)
1254 static char fmt[3];
1255 static char buf[64]; /* More than enough space. */
1257 if (kind == '@')
1259 sprintf (buf, "%ld", when);
1260 return (buf);
1262 else
1264 fmt[0] = '%';
1265 fmt[1] = kind;
1266 fmt[2] = '\0';
1267 if (strftime (buf, sizeof (buf), fmt, localtime (&when)))
1268 return (buf);
1270 return "";
1273 #ifdef DEBUG
1274 /* Return a pointer to the string representation of
1275 the predicate function PRED_FUNC. */
1277 char *
1278 find_pred_name (pred_func)
1279 PFB pred_func;
1281 int i;
1283 for (i = 0; pred_table[i].pred_func != 0; i++)
1284 if (pred_table[i].pred_func == pred_func)
1285 break;
1286 return (pred_table[i].pred_name);
1289 static char *
1290 type_name (type)
1291 short type;
1293 int i;
1295 for (i = 0; type_table[i].type != (short) -1; i++)
1296 if (type_table[i].type == type)
1297 break;
1298 return (type_table[i].type_name);
1301 static char *
1302 prec_name (prec)
1303 short prec;
1305 int i;
1307 for (i = 0; prec_table[i].prec != (short) -1; i++)
1308 if (prec_table[i].prec == prec)
1309 break;
1310 return (prec_table[i].prec_name);
1313 /* Walk the expression tree NODE to stdout.
1314 INDENT is the number of levels to indent the left margin. */
1316 void
1317 print_tree (node, indent)
1318 struct predicate *node;
1319 int indent;
1321 int i;
1323 if (node == NULL)
1324 return;
1325 for (i = 0; i < indent; i++)
1326 printf (" ");
1327 printf ("pred = %s type = %s prec = %s addr = %x\n",
1328 find_pred_name (node->pred_func),
1329 type_name (node->p_type), prec_name (node->p_prec), node);
1330 for (i = 0; i < indent; i++)
1331 printf (" ");
1332 printf (_("left:\n"));
1333 print_tree (node->pred_left, indent + 1);
1334 for (i = 0; i < indent; i++)
1335 printf (" ");
1336 printf (_("right:\n"));
1337 print_tree (node->pred_right, indent + 1);
1340 /* Copy STR into BUF and trim blanks from the end of BUF.
1341 Return BUF. */
1343 static char *
1344 blank_rtrim (str, buf)
1345 char *str;
1346 char *buf;
1348 int i;
1350 if (str == NULL)
1351 return (NULL);
1352 strcpy (buf, str);
1353 i = strlen (buf) - 1;
1354 while ((i >= 0) && ((buf[i] == ' ') || buf[i] == '\t'))
1355 i--;
1356 buf[++i] = '\0';
1357 return (buf);
1360 /* Print out the predicate list starting at NODE. */
1362 void
1363 print_list (node)
1364 struct predicate *node;
1366 struct predicate *cur;
1367 char name[256];
1369 cur = node;
1370 while (cur != NULL)
1372 printf ("%s ", blank_rtrim (find_pred_name (cur->pred_func), name));
1373 cur = cur->pred_next;
1375 printf ("\n");
1377 #endif /* DEBUG */