*** empty log message ***
[findutils.git] / find / pred.c
blob6afaeed295a2ee27b53fecd029955cb807c5a219
1 /* pred.c -- execute the expression tree.
2 Copyright (C) 1990, 91, 92, 93, 94, 2000 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 "defs.h"
21 #include <fnmatch.h>
22 #include <signal.h>
23 #include <pwd.h>
24 #include <grp.h>
25 #include "basename.h"
26 #include "human.h"
27 #include "modetype.h"
28 #include "wait.h"
30 #if ENABLE_NLS
31 # include <libintl.h>
32 # define _(Text) gettext (Text)
33 #else
34 # define _(Text) Text
35 #endif
36 #ifdef gettext_noop
37 # define N_(String) gettext_noop (String)
38 #else
39 # define N_(String) (String)
40 #endif
42 #if !defined(SIGCHLD) && defined(SIGCLD)
43 #define SIGCHLD SIGCLD
44 #endif
46 #if HAVE_DIRENT_H
47 # include <dirent.h>
48 # define NAMLEN(dirent) strlen((dirent)->d_name)
49 #else
50 # define dirent direct
51 # define NAMLEN(dirent) (dirent)->d_namlen
52 # if HAVE_SYS_NDIR_H
53 # include <sys/ndir.h>
54 # endif
55 # if HAVE_SYS_DIR_H
56 # include <sys/dir.h>
57 # endif
58 # if HAVE_NDIR_H
59 # include <ndir.h>
60 # endif
61 #endif
63 #ifdef CLOSEDIR_VOID
64 /* Fake a return value. */
65 #define CLOSEDIR(d) (closedir (d), 0)
66 #else
67 #define CLOSEDIR(d) closedir (d)
68 #endif
70 extern int yesno ();
73 /* Get or fake the disk device blocksize.
74 Usually defined by sys/param.h (if at all). */
75 #ifndef DEV_BSIZE
76 # ifdef BSIZE
77 # define DEV_BSIZE BSIZE
78 # else /* !BSIZE */
79 # define DEV_BSIZE 4096
80 # endif /* !BSIZE */
81 #endif /* !DEV_BSIZE */
83 /* Extract or fake data from a `struct stat'.
84 ST_BLKSIZE: Preferred I/O blocksize for the file, in bytes.
85 ST_NBLOCKS: Number of blocks in the file, including indirect blocks.
86 ST_NBLOCKSIZE: Size of blocks used when calculating ST_NBLOCKS. */
87 #ifndef HAVE_STRUCT_STAT_ST_BLOCKS
88 # define ST_BLKSIZE(statbuf) DEV_BSIZE
89 # if defined(_POSIX_SOURCE) || !defined(BSIZE) /* fileblocks.c uses BSIZE. */
90 # define ST_NBLOCKS(statbuf) \
91 (S_ISREG ((statbuf).st_mode) \
92 || S_ISDIR ((statbuf).st_mode) \
93 ? (statbuf).st_size / ST_NBLOCKSIZE + ((statbuf).st_size % ST_NBLOCKSIZE != 0) : 0)
94 # else /* !_POSIX_SOURCE && BSIZE */
95 # define ST_NBLOCKS(statbuf) \
96 (S_ISREG ((statbuf).st_mode) \
97 || S_ISDIR ((statbuf).st_mode) \
98 ? st_blocks ((statbuf).st_size) : 0)
99 # endif /* !_POSIX_SOURCE && BSIZE */
100 #else /* HAVE_STRUCT_STAT_ST_BLOCKS */
101 /* Some systems, like Sequents, return st_blksize of 0 on pipes. */
102 # define ST_BLKSIZE(statbuf) ((statbuf).st_blksize > 0 \
103 ? (statbuf).st_blksize : DEV_BSIZE)
104 # if defined(hpux) || defined(__hpux__) || defined(__hpux)
105 /* HP-UX counts st_blocks in 1024-byte units.
106 This loses when mixing HP-UX and BSD filesystems with NFS. */
107 # define ST_NBLOCKSIZE 1024
108 # else /* !hpux */
109 # if defined(_AIX) && defined(_I386)
110 /* AIX PS/2 counts st_blocks in 4K units. */
111 # define ST_NBLOCKSIZE (4 * 1024)
112 # else /* not AIX PS/2 */
113 # if defined(_CRAY)
114 # define ST_NBLOCKS(statbuf) \
115 (S_ISREG ((statbuf).st_mode) \
116 || S_ISDIR ((statbuf).st_mode) \
117 ? (statbuf).st_blocks * ST_BLKSIZE(statbuf)/ST_NBLOCKSIZE : 0)
118 # endif /* _CRAY */
119 # endif /* not AIX PS/2 */
120 # endif /* !hpux */
121 #endif /* HAVE_STRUCT_STAT_ST_BLOCKS */
123 #ifndef ST_NBLOCKS
124 # define ST_NBLOCKS(statbuf) \
125 (S_ISREG ((statbuf).st_mode) \
126 || S_ISDIR ((statbuf).st_mode) \
127 ? (statbuf).st_blocks : 0)
128 #endif
130 #ifndef ST_NBLOCKSIZE
131 # define ST_NBLOCKSIZE 512
132 #endif
134 #undef MAX
135 #define MAX(a, b) ((a) > (b) ? (a) : (b))
137 static boolean insert_lname PARAMS((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr, boolean ignore_case));
138 static boolean launch PARAMS((struct predicate *pred_ptr));
139 static char *format_date PARAMS((time_t when, int kind));
140 static char *ctime_format PARAMS((time_t when));
142 #ifdef DEBUG
143 struct pred_assoc
145 PFB pred_func;
146 char *pred_name;
149 struct pred_assoc pred_table[] =
151 {pred_amin, "amin "},
152 {pred_and, "and "},
153 {pred_anewer, "anewer "},
154 {pred_atime, "atime "},
155 {pred_close, ") "},
156 {pred_amin, "cmin "},
157 {pred_cnewer, "cnewer "},
158 {pred_comma, ", "},
159 {pred_ctime, "ctime "},
160 {pred_empty, "empty "},
161 {pred_exec, "exec "},
162 {pred_false, "false "},
163 {pred_fprint, "fprint "},
164 {pred_fprint0, "fprint0 "},
165 {pred_fprintf, "fprintf "},
166 {pred_fstype, "fstype "},
167 {pred_gid, "gid "},
168 {pred_group, "group "},
169 {pred_ilname, "ilname "},
170 {pred_iname, "iname "},
171 {pred_inum, "inum "},
172 {pred_ipath, "ipath "},
173 {pred_links, "links "},
174 {pred_lname, "lname "},
175 {pred_ls, "ls "},
176 {pred_amin, "mmin "},
177 {pred_mtime, "mtime "},
178 {pred_name, "name "},
179 {pred_negate, "not "},
180 {pred_newer, "newer "},
181 {pred_nogroup, "nogroup "},
182 {pred_nouser, "nouser "},
183 {pred_ok, "ok "},
184 {pred_open, "( "},
185 {pred_or, "or "},
186 {pred_path, "path "},
187 {pred_perm, "perm "},
188 {pred_print, "print "},
189 {pred_print0, "print0 "},
190 {pred_prune, "prune "},
191 {pred_regex, "regex "},
192 {pred_size, "size "},
193 {pred_true, "true "},
194 {pred_type, "type "},
195 {pred_uid, "uid "},
196 {pred_used, "used "},
197 {pred_user, "user "},
198 {pred_xtype, "xtype "},
199 {0, "none "}
202 struct op_assoc
204 short type;
205 char *type_name;
208 struct op_assoc type_table[] =
210 {NO_TYPE, "no "},
211 {PRIMARY_TYPE, "primary "},
212 {UNI_OP, "uni_op "},
213 {BI_OP, "bi_op "},
214 {OPEN_PAREN, "open_paren "},
215 {CLOSE_PAREN, "close_paren "},
216 {-1, "unknown "}
219 struct prec_assoc
221 short prec;
222 char *prec_name;
225 struct prec_assoc prec_table[] =
227 {NO_PREC, "no "},
228 {COMMA_PREC, "comma "},
229 {OR_PREC, "or "},
230 {AND_PREC, "and "},
231 {NEGATE_PREC, "negate "},
232 {MAX_PREC, "max "},
233 {-1, "unknown "}
235 #endif /* DEBUG */
237 /* Predicate processing routines.
239 PATHNAME is the full pathname of the file being checked.
240 *STAT_BUF contains information about PATHNAME.
241 *PRED_PTR contains information for applying the predicate.
243 Return true if the file passes this predicate, false if not. */
245 boolean
246 pred_amin (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
248 switch (pred_ptr->args.info.kind)
250 case COMP_GT:
251 if (stat_buf->st_atime > (time_t) pred_ptr->args.info.l_val)
252 return (true);
253 break;
254 case COMP_LT:
255 if (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val)
256 return (true);
257 break;
258 case COMP_EQ:
259 if ((stat_buf->st_atime >= (time_t) pred_ptr->args.info.l_val)
260 && (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val + 60))
261 return (true);
262 break;
264 return (false);
267 boolean
268 pred_and (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
270 if (pred_ptr->pred_left == NULL
271 || (*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
272 pred_ptr->pred_left))
274 /* Check whether we need a stat here. */
275 if (pred_ptr->need_stat)
277 if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
279 error (0, errno, "%s", pathname);
280 exit_status = 1;
281 return (false);
283 have_stat = true;
285 return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
286 pred_ptr->pred_right));
288 else
289 return (false);
292 boolean
293 pred_anewer (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
295 if (stat_buf->st_atime > pred_ptr->args.time)
296 return (true);
297 return (false);
300 boolean
301 pred_atime (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
303 switch (pred_ptr->args.info.kind)
305 case COMP_GT:
306 if (stat_buf->st_atime > (time_t) pred_ptr->args.info.l_val)
307 return (true);
308 break;
309 case COMP_LT:
310 if (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val)
311 return (true);
312 break;
313 case COMP_EQ:
314 if ((stat_buf->st_atime >= (time_t) pred_ptr->args.info.l_val)
315 && (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val
316 + DAYSECS))
317 return (true);
318 break;
320 return (false);
323 boolean
324 pred_close (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
326 return (true);
329 boolean
330 pred_cmin (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
332 switch (pred_ptr->args.info.kind)
334 case COMP_GT:
335 if (stat_buf->st_ctime > (time_t) pred_ptr->args.info.l_val)
336 return (true);
337 break;
338 case COMP_LT:
339 if (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val)
340 return (true);
341 break;
342 case COMP_EQ:
343 if ((stat_buf->st_ctime >= (time_t) pred_ptr->args.info.l_val)
344 && (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val + 60))
345 return (true);
346 break;
348 return (false);
351 boolean
352 pred_cnewer (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
354 if (stat_buf->st_ctime > pred_ptr->args.time)
355 return (true);
356 return (false);
359 boolean
360 pred_comma (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
362 if (pred_ptr->pred_left != NULL)
363 (*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
364 pred_ptr->pred_left);
365 /* Check whether we need a stat here. */
366 if (pred_ptr->need_stat)
368 if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
370 error (0, errno, "%s", pathname);
371 exit_status = 1;
372 return (false);
374 have_stat = true;
376 return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
377 pred_ptr->pred_right));
380 boolean
381 pred_ctime (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
383 switch (pred_ptr->args.info.kind)
385 case COMP_GT:
386 if (stat_buf->st_ctime > (time_t) pred_ptr->args.info.l_val)
387 return (true);
388 break;
389 case COMP_LT:
390 if (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val)
391 return (true);
392 break;
393 case COMP_EQ:
394 if ((stat_buf->st_ctime >= (time_t) pred_ptr->args.info.l_val)
395 && (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val
396 + DAYSECS))
397 return (true);
398 break;
400 return (false);
403 boolean
404 pred_empty (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
406 if (S_ISDIR (stat_buf->st_mode))
408 DIR *d;
409 struct dirent *dp;
410 boolean empty = true;
412 errno = 0;
413 d = opendir (rel_pathname);
414 if (d == NULL)
416 error (0, errno, "%s", pathname);
417 exit_status = 1;
418 return (false);
420 for (dp = readdir (d); dp; dp = readdir (d))
422 if (dp->d_name[0] != '.'
423 || (dp->d_name[1] != '\0'
424 && (dp->d_name[1] != '.' || dp->d_name[2] != '\0')))
426 empty = false;
427 break;
430 if (CLOSEDIR (d))
432 error (0, errno, "%s", pathname);
433 exit_status = 1;
434 return (false);
436 return (empty);
438 else if (S_ISREG (stat_buf->st_mode))
439 return (stat_buf->st_size == 0);
440 else
441 return (false);
444 boolean
445 pred_exec (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
447 int i;
448 int path_pos;
449 struct exec_val *execp; /* Pointer for efficiency. */
451 execp = &pred_ptr->args.exec_vec;
453 /* Replace "{}" with the real path in each affected arg. */
454 for (path_pos = 0; execp->paths[path_pos].offset >= 0; path_pos++)
456 register char *from, *to;
458 i = execp->paths[path_pos].offset;
459 execp->vec[i] =
460 xmalloc (strlen (execp->paths[path_pos].origarg) + 1
461 + (strlen (pathname) - 2) * execp->paths[path_pos].count);
462 for (from = execp->paths[path_pos].origarg, to = execp->vec[i]; *from; )
463 if (from[0] == '{' && from[1] == '}')
465 to = stpcpy (to, pathname);
466 from += 2;
468 else
469 *to++ = *from++;
470 *to = *from; /* Copy null. */
473 i = launch (pred_ptr);
475 /* Free the temporary args. */
476 for (path_pos = 0; execp->paths[path_pos].offset >= 0; path_pos++)
477 free (execp->vec[execp->paths[path_pos].offset]);
479 return (i);
482 boolean
483 pred_false (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
485 return (false);
488 boolean
489 pred_fls (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
491 list_file (pathname, rel_pathname, stat_buf, start_time,
492 output_block_size, pred_ptr->args.stream);
493 return (true);
496 boolean
497 pred_fprint (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
499 fputs (pathname, pred_ptr->args.stream);
500 putc ('\n', pred_ptr->args.stream);
501 return (true);
504 boolean
505 pred_fprint0 (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
507 fputs (pathname, pred_ptr->args.stream);
508 putc (0, pred_ptr->args.stream);
509 return (true);
512 boolean
513 pred_fprintf (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
515 FILE *fp = pred_ptr->args.printf_vec.stream;
516 struct segment *segment;
517 char *cp;
518 char hbuf[LONGEST_HUMAN_READABLE + 1];
520 for (segment = pred_ptr->args.printf_vec.segment; segment;
521 segment = segment->next)
523 if (segment->kind & 0xff00) /* Component of date. */
525 time_t t;
527 switch (segment->kind & 0xff)
529 case 'A':
530 t = stat_buf->st_atime;
531 break;
532 case 'C':
533 t = stat_buf->st_ctime;
534 break;
535 case 'T':
536 t = stat_buf->st_mtime;
537 break;
538 default:
539 abort ();
541 fprintf (fp, segment->text,
542 format_date (t, (segment->kind >> 8) & 0xff));
543 continue;
546 switch (segment->kind)
548 case KIND_PLAIN: /* Plain text string (no % conversion). */
549 fwrite (segment->text, 1, segment->text_len, fp);
550 break;
551 case KIND_STOP: /* Terminate argument and flush output. */
552 fwrite (segment->text, 1, segment->text_len, fp);
553 fflush (fp);
554 return (true);
555 case 'a': /* atime in `ctime' format. */
556 fprintf (fp, segment->text, ctime_format (stat_buf->st_atime));
557 break;
558 case 'b': /* size in 512-byte blocks */
559 fprintf (fp, segment->text,
560 human_readable ((uintmax_t) ST_NBLOCKS (*stat_buf),
561 hbuf, ST_NBLOCKSIZE, 512));
562 break;
563 case 'c': /* ctime in `ctime' format */
564 fprintf (fp, segment->text, ctime_format (stat_buf->st_ctime));
565 break;
566 case 'd': /* depth in search tree */
567 fprintf (fp, segment->text, curdepth);
568 break;
569 case 'f': /* basename of path */
570 fprintf (fp, segment->text, base_name (pathname));
571 break;
572 case 'F': /* filesystem type */
573 fprintf (fp, segment->text,
574 filesystem_type (pathname, rel_pathname, stat_buf));
575 break;
576 case 'g': /* group name */
578 struct group *g;
580 g = getgrgid (stat_buf->st_gid);
581 if (g)
583 segment->text[segment->text_len] = 's';
584 fprintf (fp, segment->text, g->gr_name);
585 break;
587 /* else fallthru */
589 case 'G': /* GID number */
590 fprintf (fp, segment->text,
591 human_readable ((uintmax_t) stat_buf->st_gid, hbuf, 1, 1));
592 break;
593 case 'h': /* leading directories part of path */
595 char cc;
597 cp = strrchr (pathname, '/');
598 if (cp == NULL) /* No leading directories. */
599 break;
600 cc = *cp;
601 *cp = '\0';
602 fprintf (fp, segment->text, pathname);
603 *cp = cc;
604 break;
606 case 'H': /* ARGV element file was found under */
608 char cc = pathname[path_length];
610 pathname[path_length] = '\0';
611 fprintf (fp, segment->text, pathname);
612 pathname[path_length] = cc;
613 break;
615 case 'i': /* inode number */
616 fprintf (fp, segment->text,
617 human_readable ((uintmax_t) stat_buf->st_ino, hbuf, 1, 1));
618 break;
619 case 'k': /* size in 1K blocks */
620 fprintf (fp, segment->text,
621 human_readable ((uintmax_t) ST_NBLOCKS (*stat_buf),
622 hbuf, ST_NBLOCKSIZE, 1024));
623 break;
624 case 'l': /* object of symlink */
625 #ifdef S_ISLNK
627 char *linkname = 0;
629 if (S_ISLNK (stat_buf->st_mode))
631 linkname = get_link_name (pathname, rel_pathname);
632 if (linkname == 0)
633 exit_status = 1;
635 if (linkname)
637 fprintf (fp, segment->text, linkname);
638 free (linkname);
640 else
641 fprintf (fp, segment->text, "");
643 #endif /* S_ISLNK */
644 break;
645 case 'm': /* mode as octal number (perms only) */
647 /* Output the mode portably using the traditional numbers,
648 even if the host unwisely uses some other numbering
649 scheme. But help the compiler in the common case where
650 the host uses the traditional numbering scheme. */
651 mode_t m = stat_buf->st_mode;
652 boolean traditional_numbering_scheme =
653 (S_ISUID == 04000 && S_ISGID == 02000 && S_ISVTX == 01000
654 && S_IRUSR == 00400 && S_IWUSR == 00200 && S_IXUSR == 00100
655 && S_IRGRP == 00040 && S_IWGRP == 00020 && S_IXGRP == 00010
656 && S_IROTH == 00004 && S_IWOTH == 00002 && S_IXOTH == 00001);
657 fprintf (fp, segment->text,
658 (traditional_numbering_scheme
659 ? m & MODE_ALL
660 : ((m & S_ISUID ? 04000 : 0)
661 | (m & S_ISGID ? 02000 : 0)
662 | (m & S_ISVTX ? 01000 : 0)
663 | (m & S_IRUSR ? 00400 : 0)
664 | (m & S_IWUSR ? 00200 : 0)
665 | (m & S_IXUSR ? 00100 : 0)
666 | (m & S_IRGRP ? 00040 : 0)
667 | (m & S_IWGRP ? 00020 : 0)
668 | (m & S_IXGRP ? 00010 : 0)
669 | (m & S_IROTH ? 00004 : 0)
670 | (m & S_IWOTH ? 00002 : 0)
671 | (m & S_IXOTH ? 00001 : 0))));
673 break;
674 case 'n': /* number of links */
675 fprintf (fp, segment->text,
676 human_readable ((uintmax_t) stat_buf->st_nlink,
677 hbuf, 1, 1));
678 break;
679 case 'p': /* pathname */
680 fprintf (fp, segment->text, pathname);
681 break;
682 case 'P': /* pathname with ARGV element stripped */
683 if (curdepth)
685 cp = pathname + path_length;
686 if (*cp == '/')
687 /* Move past the slash between the ARGV element
688 and the rest of the pathname. But if the ARGV element
689 ends in a slash, we didn't add another, so we've
690 already skipped past it. */
691 cp++;
693 else
694 cp = "";
695 fprintf (fp, segment->text, cp);
696 break;
697 case 's': /* size in bytes */
698 fprintf (fp, segment->text,
699 human_readable ((uintmax_t) stat_buf->st_size,
700 hbuf, 1, 1));
701 break;
702 case 't': /* mtime in `ctime' format */
703 fprintf (fp, segment->text, ctime_format (stat_buf->st_mtime));
704 break;
705 case 'u': /* user name */
707 struct passwd *p;
709 p = getpwuid (stat_buf->st_uid);
710 if (p)
712 segment->text[segment->text_len] = 's';
713 fprintf (fp, segment->text, p->pw_name);
714 break;
716 /* else fallthru */
718 case 'U': /* UID number */
719 fprintf (fp, segment->text,
720 human_readable ((uintmax_t) stat_buf->st_uid, hbuf, 1, 1));
721 break;
724 return (true);
727 boolean
728 pred_fstype (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
730 if (strcmp (filesystem_type (pathname, rel_pathname, stat_buf),
731 pred_ptr->args.str) == 0)
732 return (true);
733 return (false);
736 boolean
737 pred_gid (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
739 switch (pred_ptr->args.info.kind)
741 case COMP_GT:
742 if (stat_buf->st_gid > pred_ptr->args.info.l_val)
743 return (true);
744 break;
745 case COMP_LT:
746 if (stat_buf->st_gid < pred_ptr->args.info.l_val)
747 return (true);
748 break;
749 case COMP_EQ:
750 if (stat_buf->st_gid == pred_ptr->args.info.l_val)
751 return (true);
752 break;
754 return (false);
757 boolean
758 pred_group (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
760 if (pred_ptr->args.gid == stat_buf->st_gid)
761 return (true);
762 else
763 return (false);
766 boolean
767 pred_ilname (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
769 return insert_lname (pathname, stat_buf, pred_ptr, true);
772 boolean
773 pred_iname (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
775 const char *base;
777 base = base_name (pathname);
778 if (fnmatch (pred_ptr->args.str, base, FNM_PERIOD | FNM_CASEFOLD) == 0)
779 return (true);
780 return (false);
783 boolean
784 pred_inum (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
786 switch (pred_ptr->args.info.kind)
788 case COMP_GT:
789 if (stat_buf->st_ino > pred_ptr->args.info.l_val)
790 return (true);
791 break;
792 case COMP_LT:
793 if (stat_buf->st_ino < pred_ptr->args.info.l_val)
794 return (true);
795 break;
796 case COMP_EQ:
797 if (stat_buf->st_ino == pred_ptr->args.info.l_val)
798 return (true);
799 break;
801 return (false);
804 boolean
805 pred_ipath (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
807 if (fnmatch (pred_ptr->args.str, pathname, FNM_CASEFOLD) == 0)
808 return (true);
809 return (false);
812 boolean
813 pred_links (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
815 switch (pred_ptr->args.info.kind)
817 case COMP_GT:
818 if (stat_buf->st_nlink > pred_ptr->args.info.l_val)
819 return (true);
820 break;
821 case COMP_LT:
822 if (stat_buf->st_nlink < pred_ptr->args.info.l_val)
823 return (true);
824 break;
825 case COMP_EQ:
826 if (stat_buf->st_nlink == pred_ptr->args.info.l_val)
827 return (true);
828 break;
830 return (false);
833 boolean
834 pred_lname (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
836 return insert_lname (pathname, stat_buf, pred_ptr, false);
839 static boolean
840 insert_lname (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr, boolean ignore_case)
842 boolean ret = false;
843 #ifdef S_ISLNK
844 if (S_ISLNK (stat_buf->st_mode))
846 char *linkname = get_link_name (pathname, rel_pathname);
847 if (linkname)
849 if (fnmatch (pred_ptr->args.str, linkname,
850 ignore_case ? FNM_CASEFOLD : 0) == 0)
851 ret = true;
852 free (linkname);
855 #endif /* S_ISLNK */
856 return (ret);
859 boolean
860 pred_ls (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
862 list_file (pathname, rel_pathname, stat_buf, start_time,
863 output_block_size, stdout);
864 return (true);
867 boolean
868 pred_mmin (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
870 switch (pred_ptr->args.info.kind)
872 case COMP_GT:
873 if (stat_buf->st_mtime > (time_t) pred_ptr->args.info.l_val)
874 return (true);
875 break;
876 case COMP_LT:
877 if (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val)
878 return (true);
879 break;
880 case COMP_EQ:
881 if ((stat_buf->st_mtime >= (time_t) pred_ptr->args.info.l_val)
882 && (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val + 60))
883 return (true);
884 break;
886 return (false);
889 boolean
890 pred_mtime (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
892 switch (pred_ptr->args.info.kind)
894 case COMP_GT:
895 if (stat_buf->st_mtime > (time_t) pred_ptr->args.info.l_val)
896 return (true);
897 break;
898 case COMP_LT:
899 if (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val)
900 return (true);
901 break;
902 case COMP_EQ:
903 if ((stat_buf->st_mtime >= (time_t) pred_ptr->args.info.l_val)
904 && (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val
905 + DAYSECS))
906 return (true);
907 break;
909 return (false);
912 boolean
913 pred_name (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
915 const char *base;
917 base = base_name (pathname);
918 if (fnmatch (pred_ptr->args.str, base, FNM_PERIOD) == 0)
919 return (true);
920 return (false);
923 boolean
924 pred_negate (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
926 /* Check whether we need a stat here. */
927 if (pred_ptr->need_stat)
929 if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
931 error (0, errno, "%s", pathname);
932 exit_status = 1;
933 return (false);
935 have_stat = true;
937 return (!(*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
938 pred_ptr->pred_right));
941 boolean
942 pred_newer (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
944 if (stat_buf->st_mtime > pred_ptr->args.time)
945 return (true);
946 return (false);
949 boolean
950 pred_nogroup (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
952 #ifdef CACHE_IDS
953 extern char *gid_unused;
955 return gid_unused[(unsigned) stat_buf->st_gid];
956 #else
957 return getgrgid (stat_buf->st_gid) == NULL;
958 #endif
961 boolean
962 pred_nouser (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
964 #ifdef CACHE_IDS
965 extern char *uid_unused;
967 return uid_unused[(unsigned) stat_buf->st_uid];
968 #else
969 return getpwuid (stat_buf->st_uid) == NULL;
970 #endif
973 boolean
974 pred_ok (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
976 fflush (stdout);
977 /* The draft open standard requires that, in the POSIX locale,
978 the last non-blank character of this prompt be '?'.
979 The exact format is not specified.
980 This standard does not have requirements for locales other than POSIX
982 fprintf (stderr, _("< %s ... %s > ? "),
983 pred_ptr->args.exec_vec.vec[0], pathname);
984 fflush (stderr);
985 if (yesno ())
986 return pred_exec (pathname, stat_buf, pred_ptr);
987 else
988 return (false);
991 boolean
992 pred_open (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
994 return (true);
997 boolean
998 pred_or (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1000 if (pred_ptr->pred_left == NULL
1001 || !(*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
1002 pred_ptr->pred_left))
1004 /* Check whether we need a stat here. */
1005 if (pred_ptr->need_stat)
1007 if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
1009 error (0, errno, "%s", pathname);
1010 exit_status = 1;
1011 return (false);
1013 have_stat = true;
1015 return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
1016 pred_ptr->pred_right));
1018 else
1019 return (true);
1022 boolean
1023 pred_path (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1025 if (fnmatch (pred_ptr->args.str, pathname, 0) == 0)
1026 return (true);
1027 return (false);
1030 boolean
1031 pred_perm (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1033 switch (pred_ptr->args.perm.kind)
1035 case PERM_AT_LEAST:
1036 return (stat_buf->st_mode & pred_ptr->args.perm.val) == pred_ptr->args.perm.val;
1037 break;
1039 case PERM_ANY:
1040 return (stat_buf->st_mode & pred_ptr->args.perm.val) != 0;
1041 break;
1043 case PERM_EXACT:
1044 return (stat_buf->st_mode & MODE_ALL) == pred_ptr->args.perm.val;
1045 break;
1047 default:
1048 abort ();
1049 break;
1053 boolean
1054 pred_print (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1056 puts (pathname);
1057 return (true);
1060 boolean
1061 pred_print0 (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1063 fputs (pathname, stdout);
1064 putc (0, stdout);
1065 return (true);
1068 boolean
1069 pred_prune (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1071 stop_at_current_level = true;
1072 return (do_dir_first); /* This is what SunOS find seems to do. */
1075 boolean
1076 pred_regex (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1078 int len = strlen (pathname);
1079 if (re_match (pred_ptr->args.regex, pathname, len, 0,
1080 (struct re_registers *) NULL) == len)
1081 return (true);
1082 return (false);
1085 boolean
1086 pred_size (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1088 uintmax_t f_val;
1090 f_val = ((stat_buf->st_size / pred_ptr->args.size.blocksize)
1091 + (stat_buf->st_size % pred_ptr->args.size.blocksize != 0));
1092 switch (pred_ptr->args.size.kind)
1094 case COMP_GT:
1095 if (f_val > pred_ptr->args.size.size)
1096 return (true);
1097 break;
1098 case COMP_LT:
1099 if (f_val < pred_ptr->args.size.size)
1100 return (true);
1101 break;
1102 case COMP_EQ:
1103 if (f_val == pred_ptr->args.size.size)
1104 return (true);
1105 break;
1107 return (false);
1110 boolean
1111 pred_true (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1113 return (true);
1116 boolean
1117 pred_type (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1119 mode_t mode = stat_buf->st_mode;
1120 mode_t type = pred_ptr->args.type;
1122 #ifndef S_IFMT
1123 /* POSIX system; check `mode' the slow way. */
1124 if ((S_ISBLK (mode) && type == S_IFBLK)
1125 || (S_ISCHR (mode) && type == S_IFCHR)
1126 || (S_ISDIR (mode) && type == S_IFDIR)
1127 || (S_ISREG (mode) && type == S_IFREG)
1128 #ifdef S_IFLNK
1129 || (S_ISLNK (mode) && type == S_IFLNK)
1130 #endif
1131 #ifdef S_IFIFO
1132 || (S_ISFIFO (mode) && type == S_IFIFO)
1133 #endif
1134 #ifdef S_IFSOCK
1135 || (S_ISSOCK (mode) && type == S_IFSOCK)
1136 #endif
1137 #ifdef S_IFDOOR
1138 || (S_ISDOOR (mode) && type == S_IFDOOR)
1139 #endif
1141 #else /* S_IFMT */
1142 /* Unix system; check `mode' the fast way. */
1143 if ((mode & S_IFMT) == type)
1144 #endif /* S_IFMT */
1145 return (true);
1146 else
1147 return (false);
1150 boolean
1151 pred_uid (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1153 switch (pred_ptr->args.info.kind)
1155 case COMP_GT:
1156 if (stat_buf->st_uid > pred_ptr->args.info.l_val)
1157 return (true);
1158 break;
1159 case COMP_LT:
1160 if (stat_buf->st_uid < pred_ptr->args.info.l_val)
1161 return (true);
1162 break;
1163 case COMP_EQ:
1164 if (stat_buf->st_uid == pred_ptr->args.info.l_val)
1165 return (true);
1166 break;
1168 return (false);
1171 boolean
1172 pred_used (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1174 time_t delta;
1176 delta = stat_buf->st_atime - stat_buf->st_ctime; /* Use difftime? */
1177 switch (pred_ptr->args.info.kind)
1179 case COMP_GT:
1180 if (delta > (time_t) pred_ptr->args.info.l_val)
1181 return (true);
1182 break;
1183 case COMP_LT:
1184 if (delta < (time_t) pred_ptr->args.info.l_val)
1185 return (true);
1186 break;
1187 case COMP_EQ:
1188 if ((delta >= (time_t) pred_ptr->args.info.l_val)
1189 && (delta < (time_t) pred_ptr->args.info.l_val + DAYSECS))
1190 return (true);
1191 break;
1193 return (false);
1196 boolean
1197 pred_user (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1199 if (pred_ptr->args.uid == stat_buf->st_uid)
1200 return (true);
1201 else
1202 return (false);
1205 boolean
1206 pred_xtype (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1208 struct stat sbuf;
1209 int (*ystat) ();
1211 ystat = xstat == lstat ? stat : lstat;
1212 if ((*ystat) (rel_pathname, &sbuf) != 0)
1214 if (ystat == stat && errno == ENOENT)
1215 /* Mimic behavior of ls -lL. */
1216 return (pred_type (pathname, stat_buf, pred_ptr));
1217 error (0, errno, "%s", pathname);
1218 exit_status = 1;
1219 return (false);
1221 return (pred_type (pathname, &sbuf, pred_ptr));
1224 /* 1) fork to get a child; parent remembers the child pid
1225 2) child execs the command requested
1226 3) parent waits for child; checks for proper pid of child
1228 Possible returns:
1230 ret errno status(h) status(l)
1232 pid x signal# 0177 stopped
1233 pid x exit arg 0 term by _exit
1234 pid x 0 signal # term by signal
1235 -1 EINTR parent got signal
1236 -1 other some other kind of error
1238 Return true only if the pid matches, status(l) is
1239 zero, and the exit arg (status high) is 0.
1240 Otherwise return false, possibly printing an error message. */
1242 static boolean
1243 launch (struct predicate *pred_ptr)
1245 int status;
1246 pid_t child_pid;
1247 struct exec_val *execp; /* Pointer for efficiency. */
1248 static int first_time = 1;
1250 execp = &pred_ptr->args.exec_vec;
1252 /* Make sure output of command doesn't get mixed with find output. */
1253 fflush (stdout);
1254 fflush (stderr);
1256 /* Make sure to listen for the kids. */
1257 if (first_time)
1259 first_time = 0;
1260 signal (SIGCHLD, SIG_DFL);
1263 child_pid = fork ();
1264 if (child_pid == -1)
1265 error (1, errno, _("cannot fork"));
1266 if (child_pid == 0)
1268 /* We be the child. */
1269 if (starting_desc < 0
1270 ? chdir (starting_dir) != 0
1271 : fchdir (starting_desc) != 0)
1273 error (0, errno, "%s", starting_dir);
1274 _exit (1);
1276 execvp (execp->vec[0], execp->vec);
1277 error (0, errno, "%s", execp->vec[0]);
1278 _exit (1);
1282 while (waitpid (child_pid, &status, 0) == (pid_t) -1)
1283 if (errno != EINTR)
1285 error (0, errno, _("error waiting for %s"), execp->vec[0]);
1286 exit_status = 1;
1287 return false;
1289 if (WIFSIGNALED (status))
1291 error (0, 0, _("%s terminated by signal %d"),
1292 execp->vec[0], WTERMSIG (status));
1293 exit_status = 1;
1294 return (false);
1296 return (!WEXITSTATUS (status));
1299 /* Return a static string formatting the time WHEN according to the
1300 strftime format character KIND. */
1302 static char *
1303 format_date (time_t when, int kind)
1305 static char buf[MAX (LONGEST_HUMAN_READABLE + 2, 64)];
1306 struct tm *tm;
1307 char fmt[3];
1309 fmt[0] = '%';
1310 fmt[1] = kind;
1311 fmt[2] = '\0';
1313 if (kind != '@'
1314 && (tm = localtime (&when))
1315 && strftime (buf, sizeof buf, fmt, tm))
1316 return buf;
1317 else
1319 uintmax_t w = when;
1320 char *p = human_readable (when < 0 ? -w : w, buf + 1, 1, 1);
1321 if (when < 0)
1322 *--p = '-';
1323 return p;
1327 static char *
1328 ctime_format (when)
1329 time_t when;
1331 char *r = ctime (&when);
1332 if (!r)
1334 /* The time cannot be represented as a struct tm.
1335 Output it as an integer. */
1336 return format_date (when, '@');
1338 else
1340 /* Remove the trailing newline from the ctime output,
1341 being careful not to assume that the output is fixed-width. */
1342 *strchr (r, '\n') = '\0';
1343 return r;
1347 #ifdef DEBUG
1348 /* Return a pointer to the string representation of
1349 the predicate function PRED_FUNC. */
1351 char *
1352 find_pred_name (pred_func)
1353 PFB pred_func;
1355 int i;
1357 for (i = 0; pred_table[i].pred_func != 0; i++)
1358 if (pred_table[i].pred_func == pred_func)
1359 break;
1360 return (pred_table[i].pred_name);
1363 static char *
1364 type_name (type)
1365 short type;
1367 int i;
1369 for (i = 0; type_table[i].type != (short) -1; i++)
1370 if (type_table[i].type == type)
1371 break;
1372 return (type_table[i].type_name);
1375 static char *
1376 prec_name (prec)
1377 short prec;
1379 int i;
1381 for (i = 0; prec_table[i].prec != (short) -1; i++)
1382 if (prec_table[i].prec == prec)
1383 break;
1384 return (prec_table[i].prec_name);
1387 /* Walk the expression tree NODE to stdout.
1388 INDENT is the number of levels to indent the left margin. */
1390 void
1391 print_tree (node, indent)
1392 struct predicate *node;
1393 int indent;
1395 int i;
1397 if (node == NULL)
1398 return;
1399 for (i = 0; i < indent; i++)
1400 printf (" ");
1401 printf ("pred = %s type = %s prec = %s addr = %x\n",
1402 find_pred_name (node->pred_func),
1403 type_name (node->p_type), prec_name (node->p_prec), node);
1404 for (i = 0; i < indent; i++)
1405 printf (" ");
1406 printf (_("left:\n"));
1407 print_tree (node->pred_left, indent + 1);
1408 for (i = 0; i < indent; i++)
1409 printf (" ");
1410 printf (_("right:\n"));
1411 print_tree (node->pred_right, indent + 1);
1414 /* Copy STR into BUF and trim blanks from the end of BUF.
1415 Return BUF. */
1417 static char *
1418 blank_rtrim (str, buf)
1419 char *str;
1420 char *buf;
1422 int i;
1424 if (str == NULL)
1425 return (NULL);
1426 strcpy (buf, str);
1427 i = strlen (buf) - 1;
1428 while ((i >= 0) && ((buf[i] == ' ') || buf[i] == '\t'))
1429 i--;
1430 buf[++i] = '\0';
1431 return (buf);
1434 /* Print out the predicate list starting at NODE. */
1436 void
1437 print_list (node)
1438 struct predicate *node;
1440 struct predicate *cur;
1441 char name[256];
1443 cur = node;
1444 while (cur != NULL)
1446 printf ("%s ", blank_rtrim (find_pred_name (cur->pred_func), name));
1447 cur = cur->pred_next;
1449 printf ("\n");
1451 #endif /* DEBUG */