Use gnulib-tool --import to import the gnulib code, rather than the odd way we were...
[findutils.git] / find / pred.c
blob25832b32cfc17dd1926d2935dc7769f524435026
1 /* pred.c -- execute the expression tree.
2 Copyright (C) 1990, 91, 92, 93, 94, 2000, 2003 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., 9 Temple Place - Suite 330, Boston, MA 02111-1307,
17 USA.
20 #define _GNU_SOURCE
21 #include "defs.h"
23 #include <fnmatch.h>
24 #include <signal.h>
25 #include <pwd.h>
26 #include <grp.h>
27 #include "../gnulib/lib/dirname.h"
28 #include "../gnulib/lib/human.h"
29 #include "modetype.h"
30 #include "wait.h"
32 #if ENABLE_NLS
33 # include <libintl.h>
34 # define _(Text) gettext (Text)
35 #else
36 # define _(Text) Text
37 #endif
38 #ifdef gettext_noop
39 # define N_(String) gettext_noop (String)
40 #else
41 /* See locate.c for explanation as to why not use (String) */
42 # define N_(String) String
43 #endif
45 #if !defined(SIGCHLD) && defined(SIGCLD)
46 #define SIGCHLD SIGCLD
47 #endif
49 #if HAVE_DIRENT_H
50 # include <dirent.h>
51 # define NAMLEN(dirent) strlen((dirent)->d_name)
52 #else
53 # define dirent direct
54 # define NAMLEN(dirent) (dirent)->d_namlen
55 # if HAVE_SYS_NDIR_H
56 # include <sys/ndir.h>
57 # endif
58 # if HAVE_SYS_DIR_H
59 # include <sys/dir.h>
60 # endif
61 # if HAVE_NDIR_H
62 # include <ndir.h>
63 # endif
64 #endif
66 #ifdef CLOSEDIR_VOID
67 /* Fake a return value. */
68 #define CLOSEDIR(d) (closedir (d), 0)
69 #else
70 #define CLOSEDIR(d) closedir (d)
71 #endif
73 extern int yesno ();
76 /* Get or fake the disk device blocksize.
77 Usually defined by sys/param.h (if at all). */
78 #ifndef DEV_BSIZE
79 # ifdef BSIZE
80 # define DEV_BSIZE BSIZE
81 # else /* !BSIZE */
82 # define DEV_BSIZE 4096
83 # endif /* !BSIZE */
84 #endif /* !DEV_BSIZE */
86 /* Extract or fake data from a `struct stat'.
87 ST_BLKSIZE: Preferred I/O blocksize for the file, in bytes.
88 ST_NBLOCKS: Number of blocks in the file, including indirect blocks.
89 ST_NBLOCKSIZE: Size of blocks used when calculating ST_NBLOCKS. */
90 #ifndef HAVE_STRUCT_STAT_ST_BLOCKS
91 # define ST_BLKSIZE(statbuf) DEV_BSIZE
92 # if defined(_POSIX_SOURCE) || !defined(BSIZE) /* fileblocks.c uses BSIZE. */
93 # define ST_NBLOCKS(statbuf) \
94 (S_ISREG ((statbuf).st_mode) \
95 || S_ISDIR ((statbuf).st_mode) \
96 ? (statbuf).st_size / ST_NBLOCKSIZE + ((statbuf).st_size % ST_NBLOCKSIZE != 0) : 0)
97 # else /* !_POSIX_SOURCE && BSIZE */
98 # define ST_NBLOCKS(statbuf) \
99 (S_ISREG ((statbuf).st_mode) \
100 || S_ISDIR ((statbuf).st_mode) \
101 ? st_blocks ((statbuf).st_size) : 0)
102 # endif /* !_POSIX_SOURCE && BSIZE */
103 #else /* HAVE_STRUCT_STAT_ST_BLOCKS */
104 /* Some systems, like Sequents, return st_blksize of 0 on pipes. */
105 # define ST_BLKSIZE(statbuf) ((statbuf).st_blksize > 0 \
106 ? (statbuf).st_blksize : DEV_BSIZE)
107 # if defined(hpux) || defined(__hpux__) || defined(__hpux)
108 /* HP-UX counts st_blocks in 1024-byte units.
109 This loses when mixing HP-UX and BSD filesystems with NFS. */
110 # define ST_NBLOCKSIZE 1024
111 # else /* !hpux */
112 # if defined(_AIX) && defined(_I386)
113 /* AIX PS/2 counts st_blocks in 4K units. */
114 # define ST_NBLOCKSIZE (4 * 1024)
115 # else /* not AIX PS/2 */
116 # if defined(_CRAY)
117 # define ST_NBLOCKS(statbuf) \
118 (S_ISREG ((statbuf).st_mode) \
119 || S_ISDIR ((statbuf).st_mode) \
120 ? (statbuf).st_blocks * ST_BLKSIZE(statbuf)/ST_NBLOCKSIZE : 0)
121 # endif /* _CRAY */
122 # endif /* not AIX PS/2 */
123 # endif /* !hpux */
124 #endif /* HAVE_STRUCT_STAT_ST_BLOCKS */
126 #ifndef ST_NBLOCKS
127 # define ST_NBLOCKS(statbuf) \
128 (S_ISREG ((statbuf).st_mode) \
129 || S_ISDIR ((statbuf).st_mode) \
130 ? (statbuf).st_blocks : 0)
131 #endif
133 #ifndef ST_NBLOCKSIZE
134 # define ST_NBLOCKSIZE 512
135 #endif
137 #undef MAX
138 #define MAX(a, b) ((a) > (b) ? (a) : (b))
140 static boolean insert_lname PARAMS((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr, boolean ignore_case));
141 static boolean launch PARAMS((struct predicate *pred_ptr));
142 static char *format_date PARAMS((time_t when, int kind));
143 static char *ctime_format PARAMS((time_t when));
145 #ifdef DEBUG
146 struct pred_assoc
148 PFB pred_func;
149 char *pred_name;
152 struct pred_assoc pred_table[] =
154 {pred_amin, "amin "},
155 {pred_and, "and "},
156 {pred_anewer, "anewer "},
157 {pred_atime, "atime "},
158 {pred_close, ") "},
159 {pred_amin, "cmin "},
160 {pred_cnewer, "cnewer "},
161 {pred_comma, ", "},
162 {pred_ctime, "ctime "},
163 {pred_empty, "empty "},
164 {pred_exec, "exec "},
165 {pred_false, "false "},
166 {pred_fprint, "fprint "},
167 {pred_fprint0, "fprint0 "},
168 {pred_fprintf, "fprintf "},
169 {pred_fstype, "fstype "},
170 {pred_gid, "gid "},
171 {pred_group, "group "},
172 {pred_ilname, "ilname "},
173 {pred_iname, "iname "},
174 {pred_inum, "inum "},
175 {pred_ipath, "ipath "},
176 {pred_links, "links "},
177 {pred_lname, "lname "},
178 {pred_ls, "ls "},
179 {pred_amin, "mmin "},
180 {pred_mtime, "mtime "},
181 {pred_name, "name "},
182 {pred_negate, "not "},
183 {pred_newer, "newer "},
184 {pred_nogroup, "nogroup "},
185 {pred_nouser, "nouser "},
186 {pred_ok, "ok "},
187 {pred_open, "( "},
188 {pred_or, "or "},
189 {pred_path, "path "},
190 {pred_perm, "perm "},
191 {pred_print, "print "},
192 {pred_print0, "print0 "},
193 {pred_prune, "prune "},
194 {pred_regex, "regex "},
195 {pred_size, "size "},
196 {pred_true, "true "},
197 {pred_type, "type "},
198 {pred_uid, "uid "},
199 {pred_used, "used "},
200 {pred_user, "user "},
201 {pred_xtype, "xtype "},
202 {0, "none "}
205 struct op_assoc
207 short type;
208 char *type_name;
211 struct op_assoc type_table[] =
213 {NO_TYPE, "no "},
214 {PRIMARY_TYPE, "primary "},
215 {UNI_OP, "uni_op "},
216 {BI_OP, "bi_op "},
217 {OPEN_PAREN, "open_paren "},
218 {CLOSE_PAREN, "close_paren "},
219 {-1, "unknown "}
222 struct prec_assoc
224 short prec;
225 char *prec_name;
228 struct prec_assoc prec_table[] =
230 {NO_PREC, "no "},
231 {COMMA_PREC, "comma "},
232 {OR_PREC, "or "},
233 {AND_PREC, "and "},
234 {NEGATE_PREC, "negate "},
235 {MAX_PREC, "max "},
236 {-1, "unknown "}
238 #endif /* DEBUG */
240 /* Predicate processing routines.
242 PATHNAME is the full pathname of the file being checked.
243 *STAT_BUF contains information about PATHNAME.
244 *PRED_PTR contains information for applying the predicate.
246 Return true if the file passes this predicate, false if not. */
248 boolean
249 pred_amin (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
251 switch (pred_ptr->args.info.kind)
253 case COMP_GT:
254 if (stat_buf->st_atime > (time_t) pred_ptr->args.info.l_val)
255 return (true);
256 break;
257 case COMP_LT:
258 if (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val)
259 return (true);
260 break;
261 case COMP_EQ:
262 if ((stat_buf->st_atime >= (time_t) pred_ptr->args.info.l_val)
263 && (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val + 60))
264 return (true);
265 break;
267 return (false);
270 boolean
271 pred_and (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
273 if (pred_ptr->pred_left == NULL
274 || (*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
275 pred_ptr->pred_left))
277 /* Check whether we need a stat here. */
278 if (pred_ptr->need_stat)
280 if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
282 error (0, errno, "%s", pathname);
283 exit_status = 1;
284 return (false);
286 have_stat = true;
288 return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
289 pred_ptr->pred_right));
291 else
292 return (false);
295 boolean
296 pred_anewer (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
298 if (stat_buf->st_atime > pred_ptr->args.time)
299 return (true);
300 return (false);
303 boolean
304 pred_atime (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
306 switch (pred_ptr->args.info.kind)
308 case COMP_GT:
309 if (stat_buf->st_atime > (time_t) pred_ptr->args.info.l_val)
310 return (true);
311 break;
312 case COMP_LT:
313 if (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val)
314 return (true);
315 break;
316 case COMP_EQ:
317 if ((stat_buf->st_atime >= (time_t) pred_ptr->args.info.l_val)
318 && (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val
319 + DAYSECS))
320 return (true);
321 break;
323 return (false);
326 boolean
327 pred_close (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
329 return (true);
332 boolean
333 pred_cmin (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 + 60))
348 return (true);
349 break;
351 return (false);
354 boolean
355 pred_cnewer (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
357 if (stat_buf->st_ctime > pred_ptr->args.time)
358 return (true);
359 return (false);
362 boolean
363 pred_comma (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
365 if (pred_ptr->pred_left != NULL)
366 (*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
367 pred_ptr->pred_left);
368 /* Check whether we need a stat here. */
369 if (pred_ptr->need_stat)
371 if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
373 error (0, errno, "%s", pathname);
374 exit_status = 1;
375 return (false);
377 have_stat = true;
379 return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
380 pred_ptr->pred_right));
383 boolean
384 pred_ctime (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
386 switch (pred_ptr->args.info.kind)
388 case COMP_GT:
389 if (stat_buf->st_ctime > (time_t) pred_ptr->args.info.l_val)
390 return (true);
391 break;
392 case COMP_LT:
393 if (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val)
394 return (true);
395 break;
396 case COMP_EQ:
397 if ((stat_buf->st_ctime >= (time_t) pred_ptr->args.info.l_val)
398 && (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val
399 + DAYSECS))
400 return (true);
401 break;
403 return (false);
406 boolean
407 pred_empty (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
409 if (S_ISDIR (stat_buf->st_mode))
411 DIR *d;
412 struct dirent *dp;
413 boolean empty = true;
415 errno = 0;
416 d = opendir (rel_pathname);
417 if (d == NULL)
419 error (0, errno, "%s", pathname);
420 exit_status = 1;
421 return (false);
423 for (dp = readdir (d); dp; dp = readdir (d))
425 if (dp->d_name[0] != '.'
426 || (dp->d_name[1] != '\0'
427 && (dp->d_name[1] != '.' || dp->d_name[2] != '\0')))
429 empty = false;
430 break;
433 if (CLOSEDIR (d))
435 error (0, errno, "%s", pathname);
436 exit_status = 1;
437 return (false);
439 return (empty);
441 else if (S_ISREG (stat_buf->st_mode))
442 return (stat_buf->st_size == 0);
443 else
444 return (false);
447 boolean
448 pred_exec (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
450 int i;
451 int path_pos;
452 struct exec_val *execp; /* Pointer for efficiency. */
454 execp = &pred_ptr->args.exec_vec;
456 /* Replace "{}" with the real path in each affected arg. */
457 for (path_pos = 0; execp->paths[path_pos].offset >= 0; path_pos++)
459 register char *from, *to;
461 i = execp->paths[path_pos].offset;
462 execp->vec[i] =
463 xmalloc (strlen (execp->paths[path_pos].origarg) + 1
464 + (strlen (pathname) - 2) * execp->paths[path_pos].count);
465 for (from = execp->paths[path_pos].origarg, to = execp->vec[i]; *from; )
466 if (from[0] == '{' && from[1] == '}')
468 to = stpcpy (to, pathname);
469 from += 2;
471 else
472 *to++ = *from++;
473 *to = *from; /* Copy null. */
476 i = launch (pred_ptr);
478 /* Free the temporary args. */
479 for (path_pos = 0; execp->paths[path_pos].offset >= 0; path_pos++)
480 free (execp->vec[execp->paths[path_pos].offset]);
482 return (i);
485 boolean
486 pred_false (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
488 return (false);
491 boolean
492 pred_fls (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
494 list_file (pathname, rel_pathname, stat_buf, start_time,
495 output_block_size, pred_ptr->args.stream);
496 return (true);
499 boolean
500 pred_fprint (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
502 fputs (pathname, pred_ptr->args.stream);
503 putc ('\n', pred_ptr->args.stream);
504 return (true);
507 boolean
508 pred_fprint0 (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
510 fputs (pathname, pred_ptr->args.stream);
511 putc (0, pred_ptr->args.stream);
512 return (true);
515 boolean
516 pred_fprintf (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
518 FILE *fp = pred_ptr->args.printf_vec.stream;
519 struct segment *segment;
520 char *cp;
521 char hbuf[LONGEST_HUMAN_READABLE + 1];
523 for (segment = pred_ptr->args.printf_vec.segment; segment;
524 segment = segment->next)
526 if (segment->kind & 0xff00) /* Component of date. */
528 time_t t;
530 switch (segment->kind & 0xff)
532 case 'A':
533 t = stat_buf->st_atime;
534 break;
535 case 'C':
536 t = stat_buf->st_ctime;
537 break;
538 case 'T':
539 t = stat_buf->st_mtime;
540 break;
541 default:
542 abort ();
544 fprintf (fp, segment->text,
545 format_date (t, (segment->kind >> 8) & 0xff));
546 continue;
549 switch (segment->kind)
551 case KIND_PLAIN: /* Plain text string (no % conversion). */
552 fwrite (segment->text, 1, segment->text_len, fp);
553 break;
554 case KIND_STOP: /* Terminate argument and flush output. */
555 fwrite (segment->text, 1, segment->text_len, fp);
556 fflush (fp);
557 return (true);
558 case 'a': /* atime in `ctime' format. */
559 fprintf (fp, segment->text, ctime_format (stat_buf->st_atime));
560 break;
561 case 'b': /* size in 512-byte blocks */
562 fprintf (fp, segment->text,
563 human_readable ((uintmax_t) ST_NBLOCKS (*stat_buf),
564 hbuf, human_ceiling,
565 ST_NBLOCKSIZE, 512));
566 break;
567 case 'c': /* ctime in `ctime' format */
568 fprintf (fp, segment->text, ctime_format (stat_buf->st_ctime));
569 break;
570 case 'd': /* depth in search tree */
571 fprintf (fp, segment->text, curdepth);
572 break;
573 case 'f': /* basename of path */
574 fprintf (fp, segment->text, base_name (pathname));
575 break;
576 case 'F': /* filesystem type */
577 fprintf (fp, segment->text,
578 filesystem_type (pathname, rel_pathname, stat_buf));
579 break;
580 case 'g': /* group name */
582 struct group *g;
584 g = getgrgid (stat_buf->st_gid);
585 if (g)
587 segment->text[segment->text_len] = 's';
588 fprintf (fp, segment->text, g->gr_name);
589 break;
591 /* else fallthru */
593 case 'G': /* GID number */
594 fprintf (fp, segment->text,
595 human_readable ((uintmax_t) stat_buf->st_gid, hbuf,
596 human_ceiling, 1, 1));
597 break;
598 case 'h': /* leading directories part of path */
600 char cc;
602 cp = strrchr (pathname, '/');
603 if (cp == NULL) /* No leading directories. */
604 break;
605 cc = *cp;
606 *cp = '\0';
607 fprintf (fp, segment->text, pathname);
608 *cp = cc;
609 break;
611 case 'H': /* ARGV element file was found under */
613 char cc = pathname[path_length];
615 pathname[path_length] = '\0';
616 fprintf (fp, segment->text, pathname);
617 pathname[path_length] = cc;
618 break;
620 case 'i': /* inode number */
621 fprintf (fp, segment->text,
622 human_readable ((uintmax_t) stat_buf->st_ino, hbuf,
623 human_ceiling,
624 1, 1));
625 break;
626 case 'k': /* size in 1K blocks */
627 fprintf (fp, segment->text,
628 human_readable ((uintmax_t) ST_NBLOCKS (*stat_buf),
629 hbuf, human_ceiling,
630 ST_NBLOCKSIZE, 1024));
631 break;
632 case 'l': /* object of symlink */
633 #ifdef S_ISLNK
635 char *linkname = 0;
637 if (S_ISLNK (stat_buf->st_mode))
639 linkname = get_link_name (pathname, rel_pathname);
640 if (linkname == 0)
641 exit_status = 1;
643 if (linkname)
645 fprintf (fp, segment->text, linkname);
646 free (linkname);
648 else
649 fprintf (fp, segment->text, "");
651 #endif /* S_ISLNK */
652 break;
653 case 'm': /* mode as octal number (perms only) */
655 /* Output the mode portably using the traditional numbers,
656 even if the host unwisely uses some other numbering
657 scheme. But help the compiler in the common case where
658 the host uses the traditional numbering scheme. */
659 mode_t m = stat_buf->st_mode;
660 boolean traditional_numbering_scheme =
661 (S_ISUID == 04000 && S_ISGID == 02000 && S_ISVTX == 01000
662 && S_IRUSR == 00400 && S_IWUSR == 00200 && S_IXUSR == 00100
663 && S_IRGRP == 00040 && S_IWGRP == 00020 && S_IXGRP == 00010
664 && S_IROTH == 00004 && S_IWOTH == 00002 && S_IXOTH == 00001);
665 fprintf (fp, segment->text,
666 (traditional_numbering_scheme
667 ? m & MODE_ALL
668 : ((m & S_ISUID ? 04000 : 0)
669 | (m & S_ISGID ? 02000 : 0)
670 | (m & S_ISVTX ? 01000 : 0)
671 | (m & S_IRUSR ? 00400 : 0)
672 | (m & S_IWUSR ? 00200 : 0)
673 | (m & S_IXUSR ? 00100 : 0)
674 | (m & S_IRGRP ? 00040 : 0)
675 | (m & S_IWGRP ? 00020 : 0)
676 | (m & S_IXGRP ? 00010 : 0)
677 | (m & S_IROTH ? 00004 : 0)
678 | (m & S_IWOTH ? 00002 : 0)
679 | (m & S_IXOTH ? 00001 : 0))));
681 break;
682 case 'n': /* number of links */
683 fprintf (fp, segment->text,
684 human_readable ((uintmax_t) stat_buf->st_nlink,
685 hbuf,
686 human_ceiling,
687 1, 1));
688 break;
689 case 'p': /* pathname */
690 fprintf (fp, segment->text, pathname);
691 break;
692 case 'P': /* pathname with ARGV element stripped */
693 if (curdepth)
695 cp = pathname + path_length;
696 if (*cp == '/')
697 /* Move past the slash between the ARGV element
698 and the rest of the pathname. But if the ARGV element
699 ends in a slash, we didn't add another, so we've
700 already skipped past it. */
701 cp++;
703 else
704 cp = "";
705 fprintf (fp, segment->text, cp);
706 break;
707 case 's': /* size in bytes */
708 fprintf (fp, segment->text,
709 human_readable ((uintmax_t) stat_buf->st_size,
710 hbuf, human_ceiling, 1, 1));
711 break;
712 case 't': /* mtime in `ctime' format */
713 fprintf (fp, segment->text, ctime_format (stat_buf->st_mtime));
714 break;
715 case 'u': /* user name */
717 struct passwd *p;
719 p = getpwuid (stat_buf->st_uid);
720 if (p)
722 segment->text[segment->text_len] = 's';
723 fprintf (fp, segment->text, p->pw_name);
724 break;
726 /* else fallthru */
728 case 'U': /* UID number */
729 fprintf (fp, segment->text,
730 human_readable ((uintmax_t) stat_buf->st_uid, hbuf,
731 human_ceiling, 1, 1));
732 break;
735 return (true);
738 boolean
739 pred_fstype (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
741 if (strcmp (filesystem_type (pathname, rel_pathname, stat_buf),
742 pred_ptr->args.str) == 0)
743 return (true);
744 return (false);
747 boolean
748 pred_gid (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
750 switch (pred_ptr->args.info.kind)
752 case COMP_GT:
753 if (stat_buf->st_gid > pred_ptr->args.info.l_val)
754 return (true);
755 break;
756 case COMP_LT:
757 if (stat_buf->st_gid < pred_ptr->args.info.l_val)
758 return (true);
759 break;
760 case COMP_EQ:
761 if (stat_buf->st_gid == pred_ptr->args.info.l_val)
762 return (true);
763 break;
765 return (false);
768 boolean
769 pred_group (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
771 if (pred_ptr->args.gid == stat_buf->st_gid)
772 return (true);
773 else
774 return (false);
777 boolean
778 pred_ilname (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
780 return insert_lname (pathname, stat_buf, pred_ptr, true);
783 boolean
784 pred_iname (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
786 const char *base;
788 /* FNM_PERIOD is not used here because POSIX requires that it not be.
789 * See http://standards.ieee.org/reading/ieee/interp/1003-2-92_int/pasc-1003.2-126.html
791 base = base_name (pathname);
792 if (fnmatch (pred_ptr->args.str, base, FNM_CASEFOLD) == 0)
793 return (true);
794 return (false);
797 boolean
798 pred_inum (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
800 switch (pred_ptr->args.info.kind)
802 case COMP_GT:
803 if (stat_buf->st_ino > pred_ptr->args.info.l_val)
804 return (true);
805 break;
806 case COMP_LT:
807 if (stat_buf->st_ino < pred_ptr->args.info.l_val)
808 return (true);
809 break;
810 case COMP_EQ:
811 if (stat_buf->st_ino == pred_ptr->args.info.l_val)
812 return (true);
813 break;
815 return (false);
818 boolean
819 pred_ipath (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
821 if (fnmatch (pred_ptr->args.str, pathname, FNM_CASEFOLD) == 0)
822 return (true);
823 return (false);
826 boolean
827 pred_links (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
829 switch (pred_ptr->args.info.kind)
831 case COMP_GT:
832 if (stat_buf->st_nlink > pred_ptr->args.info.l_val)
833 return (true);
834 break;
835 case COMP_LT:
836 if (stat_buf->st_nlink < pred_ptr->args.info.l_val)
837 return (true);
838 break;
839 case COMP_EQ:
840 if (stat_buf->st_nlink == pred_ptr->args.info.l_val)
841 return (true);
842 break;
844 return (false);
847 boolean
848 pred_lname (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
850 return insert_lname (pathname, stat_buf, pred_ptr, false);
853 static boolean
854 insert_lname (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr, boolean ignore_case)
856 boolean ret = false;
857 #ifdef S_ISLNK
858 if (S_ISLNK (stat_buf->st_mode))
860 char *linkname = get_link_name (pathname, rel_pathname);
861 if (linkname)
863 if (fnmatch (pred_ptr->args.str, linkname,
864 ignore_case ? FNM_CASEFOLD : 0) == 0)
865 ret = true;
866 free (linkname);
869 #endif /* S_ISLNK */
870 return (ret);
873 boolean
874 pred_ls (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
876 list_file (pathname, rel_pathname, stat_buf, start_time,
877 output_block_size, stdout);
878 return (true);
881 boolean
882 pred_mmin (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
884 switch (pred_ptr->args.info.kind)
886 case COMP_GT:
887 if (stat_buf->st_mtime > (time_t) pred_ptr->args.info.l_val)
888 return (true);
889 break;
890 case COMP_LT:
891 if (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val)
892 return (true);
893 break;
894 case COMP_EQ:
895 if ((stat_buf->st_mtime >= (time_t) pred_ptr->args.info.l_val)
896 && (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val + 60))
897 return (true);
898 break;
900 return (false);
903 boolean
904 pred_mtime (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
906 switch (pred_ptr->args.info.kind)
908 case COMP_GT:
909 if (stat_buf->st_mtime > (time_t) pred_ptr->args.info.l_val)
910 return (true);
911 break;
912 case COMP_LT:
913 if (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val)
914 return (true);
915 break;
916 case COMP_EQ:
917 if ((stat_buf->st_mtime >= (time_t) pred_ptr->args.info.l_val)
918 && (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val
919 + DAYSECS))
920 return (true);
921 break;
923 return (false);
926 boolean
927 pred_name (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
929 const char *base;
931 base = base_name (pathname);
933 /* FNM_PERIOD is not used here because POSIX requires that it not be.
934 * See http://standards.ieee.org/reading/ieee/interp/1003-2-92_int/pasc-1003.2-126.html
936 if (fnmatch (pred_ptr->args.str, base, 0) == 0)
937 return (true);
938 return (false);
941 boolean
942 pred_negate (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
944 /* Check whether we need a stat here. */
945 if (pred_ptr->need_stat)
947 if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
949 error (0, errno, "%s", pathname);
950 exit_status = 1;
951 return (false);
953 have_stat = true;
955 return (!(*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
956 pred_ptr->pred_right));
959 boolean
960 pred_newer (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
962 if (stat_buf->st_mtime > pred_ptr->args.time)
963 return (true);
964 return (false);
967 boolean
968 pred_nogroup (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
970 #ifdef CACHE_IDS
971 extern char *gid_unused;
973 return gid_unused[(unsigned) stat_buf->st_gid];
974 #else
975 return getgrgid (stat_buf->st_gid) == NULL;
976 #endif
979 boolean
980 pred_nouser (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
982 #ifdef CACHE_IDS
983 extern char *uid_unused;
985 return uid_unused[(unsigned) stat_buf->st_uid];
986 #else
987 return getpwuid (stat_buf->st_uid) == NULL;
988 #endif
991 boolean
992 pred_ok (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
994 fflush (stdout);
995 /* The draft open standard requires that, in the POSIX locale,
996 the last non-blank character of this prompt be '?'.
997 The exact format is not specified.
998 This standard does not have requirements for locales other than POSIX
1000 fprintf (stderr, _("< %s ... %s > ? "),
1001 pred_ptr->args.exec_vec.vec[0], pathname);
1002 fflush (stderr);
1003 if (yesno ())
1004 return pred_exec (pathname, stat_buf, pred_ptr);
1005 else
1006 return (false);
1009 boolean
1010 pred_open (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1012 return (true);
1015 boolean
1016 pred_or (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1018 if (pred_ptr->pred_left == NULL
1019 || !(*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
1020 pred_ptr->pred_left))
1022 /* Check whether we need a stat here. */
1023 if (pred_ptr->need_stat)
1025 if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
1027 error (0, errno, "%s", pathname);
1028 exit_status = 1;
1029 return (false);
1031 have_stat = true;
1033 return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
1034 pred_ptr->pred_right));
1036 else
1037 return (true);
1040 boolean
1041 pred_path (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1043 if (fnmatch (pred_ptr->args.str, pathname, 0) == 0)
1044 return (true);
1045 return (false);
1048 boolean
1049 pred_perm (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1051 switch (pred_ptr->args.perm.kind)
1053 case PERM_AT_LEAST:
1054 return (stat_buf->st_mode & pred_ptr->args.perm.val) == pred_ptr->args.perm.val;
1055 break;
1057 case PERM_ANY:
1058 return (stat_buf->st_mode & pred_ptr->args.perm.val) != 0;
1059 break;
1061 case PERM_EXACT:
1062 return (stat_buf->st_mode & MODE_ALL) == pred_ptr->args.perm.val;
1063 break;
1065 default:
1066 abort ();
1067 break;
1071 boolean
1072 pred_print (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1074 puts (pathname);
1075 return (true);
1078 boolean
1079 pred_print0 (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1081 fputs (pathname, stdout);
1082 putc (0, stdout);
1083 return (true);
1086 boolean
1087 pred_prune (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1089 stop_at_current_level = true;
1090 return (do_dir_first); /* This is what SunOS find seems to do. */
1093 boolean
1094 pred_regex (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1096 int len = strlen (pathname);
1097 if (re_match (pred_ptr->args.regex, pathname, len, 0,
1098 (struct re_registers *) NULL) == len)
1099 return (true);
1100 return (false);
1103 boolean
1104 pred_size (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1106 uintmax_t f_val;
1108 f_val = ((stat_buf->st_size / pred_ptr->args.size.blocksize)
1109 + (stat_buf->st_size % pred_ptr->args.size.blocksize != 0));
1110 switch (pred_ptr->args.size.kind)
1112 case COMP_GT:
1113 if (f_val > pred_ptr->args.size.size)
1114 return (true);
1115 break;
1116 case COMP_LT:
1117 if (f_val < pred_ptr->args.size.size)
1118 return (true);
1119 break;
1120 case COMP_EQ:
1121 if (f_val == pred_ptr->args.size.size)
1122 return (true);
1123 break;
1125 return (false);
1128 boolean
1129 pred_true (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1131 return (true);
1134 boolean
1135 pred_type (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1137 mode_t mode = stat_buf->st_mode;
1138 mode_t type = pred_ptr->args.type;
1140 #ifndef S_IFMT
1141 /* POSIX system; check `mode' the slow way. */
1142 if ((S_ISBLK (mode) && type == S_IFBLK)
1143 || (S_ISCHR (mode) && type == S_IFCHR)
1144 || (S_ISDIR (mode) && type == S_IFDIR)
1145 || (S_ISREG (mode) && type == S_IFREG)
1146 #ifdef S_IFLNK
1147 || (S_ISLNK (mode) && type == S_IFLNK)
1148 #endif
1149 #ifdef S_IFIFO
1150 || (S_ISFIFO (mode) && type == S_IFIFO)
1151 #endif
1152 #ifdef S_IFSOCK
1153 || (S_ISSOCK (mode) && type == S_IFSOCK)
1154 #endif
1155 #ifdef S_IFDOOR
1156 || (S_ISDOOR (mode) && type == S_IFDOOR)
1157 #endif
1159 #else /* S_IFMT */
1160 /* Unix system; check `mode' the fast way. */
1161 if ((mode & S_IFMT) == type)
1162 #endif /* S_IFMT */
1163 return (true);
1164 else
1165 return (false);
1168 boolean
1169 pred_uid (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1171 switch (pred_ptr->args.info.kind)
1173 case COMP_GT:
1174 if (stat_buf->st_uid > pred_ptr->args.info.l_val)
1175 return (true);
1176 break;
1177 case COMP_LT:
1178 if (stat_buf->st_uid < pred_ptr->args.info.l_val)
1179 return (true);
1180 break;
1181 case COMP_EQ:
1182 if (stat_buf->st_uid == pred_ptr->args.info.l_val)
1183 return (true);
1184 break;
1186 return (false);
1189 boolean
1190 pred_used (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1192 time_t delta;
1194 delta = stat_buf->st_atime - stat_buf->st_ctime; /* Use difftime? */
1195 switch (pred_ptr->args.info.kind)
1197 case COMP_GT:
1198 if (delta > (time_t) pred_ptr->args.info.l_val)
1199 return (true);
1200 break;
1201 case COMP_LT:
1202 if (delta < (time_t) pred_ptr->args.info.l_val)
1203 return (true);
1204 break;
1205 case COMP_EQ:
1206 if ((delta >= (time_t) pred_ptr->args.info.l_val)
1207 && (delta < (time_t) pred_ptr->args.info.l_val + DAYSECS))
1208 return (true);
1209 break;
1211 return (false);
1214 boolean
1215 pred_user (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1217 if (pred_ptr->args.uid == stat_buf->st_uid)
1218 return (true);
1219 else
1220 return (false);
1223 boolean
1224 pred_xtype (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1226 struct stat sbuf;
1227 int (*ystat) ();
1229 ystat = xstat == lstat ? stat : lstat;
1230 if ((*ystat) (rel_pathname, &sbuf) != 0)
1232 if (ystat == stat && errno == ENOENT)
1233 /* Mimic behavior of ls -lL. */
1234 return (pred_type (pathname, stat_buf, pred_ptr));
1235 error (0, errno, "%s", pathname);
1236 exit_status = 1;
1237 return (false);
1239 return (pred_type (pathname, &sbuf, pred_ptr));
1242 /* 1) fork to get a child; parent remembers the child pid
1243 2) child execs the command requested
1244 3) parent waits for child; checks for proper pid of child
1246 Possible returns:
1248 ret errno status(h) status(l)
1250 pid x signal# 0177 stopped
1251 pid x exit arg 0 term by _exit
1252 pid x 0 signal # term by signal
1253 -1 EINTR parent got signal
1254 -1 other some other kind of error
1256 Return true only if the pid matches, status(l) is
1257 zero, and the exit arg (status high) is 0.
1258 Otherwise return false, possibly printing an error message. */
1260 static boolean
1261 launch (struct predicate *pred_ptr)
1263 int status;
1264 pid_t child_pid;
1265 struct exec_val *execp; /* Pointer for efficiency. */
1266 static int first_time = 1;
1268 execp = &pred_ptr->args.exec_vec;
1270 /* Make sure output of command doesn't get mixed with find output. */
1271 fflush (stdout);
1272 fflush (stderr);
1274 /* Make sure to listen for the kids. */
1275 if (first_time)
1277 first_time = 0;
1278 signal (SIGCHLD, SIG_DFL);
1281 child_pid = fork ();
1282 if (child_pid == -1)
1283 error (1, errno, _("cannot fork"));
1284 if (child_pid == 0)
1286 /* We be the child. */
1287 if (starting_desc < 0
1288 ? chdir (starting_dir) != 0
1289 : fchdir (starting_desc) != 0)
1291 error (0, errno, "%s", starting_dir);
1292 _exit (1);
1294 execvp (execp->vec[0], execp->vec);
1295 error (0, errno, "%s", execp->vec[0]);
1296 _exit (1);
1300 while (waitpid (child_pid, &status, 0) == (pid_t) -1)
1301 if (errno != EINTR)
1303 error (0, errno, _("error waiting for %s"), execp->vec[0]);
1304 exit_status = 1;
1305 return false;
1307 if (WIFSIGNALED (status))
1309 error (0, 0, _("%s terminated by signal %d"),
1310 execp->vec[0], WTERMSIG (status));
1311 exit_status = 1;
1312 return (false);
1314 return (!WEXITSTATUS (status));
1317 /* Return a static string formatting the time WHEN according to the
1318 strftime format character KIND. */
1320 static char *
1321 format_date (time_t when, int kind)
1323 static char buf[MAX (LONGEST_HUMAN_READABLE + 2, 64)];
1324 struct tm *tm;
1325 char fmt[3];
1327 fmt[0] = '%';
1328 fmt[1] = kind;
1329 fmt[2] = '\0';
1331 if (kind != '@'
1332 && (tm = localtime (&when))
1333 && strftime (buf, sizeof buf, fmt, tm))
1334 return buf;
1335 else
1337 uintmax_t w = when;
1338 char *p = human_readable (when < 0 ? -w : w, buf + 1,
1339 human_ceiling, 1, 1);
1340 if (when < 0)
1341 *--p = '-';
1342 return p;
1346 static char *
1347 ctime_format (when)
1348 time_t when;
1350 char *r = ctime (&when);
1351 if (!r)
1353 /* The time cannot be represented as a struct tm.
1354 Output it as an integer. */
1355 return format_date (when, '@');
1357 else
1359 /* Remove the trailing newline from the ctime output,
1360 being careful not to assume that the output is fixed-width. */
1361 *strchr (r, '\n') = '\0';
1362 return r;
1366 #ifdef DEBUG
1367 /* Return a pointer to the string representation of
1368 the predicate function PRED_FUNC. */
1370 char *
1371 find_pred_name (pred_func)
1372 PFB pred_func;
1374 int i;
1376 for (i = 0; pred_table[i].pred_func != 0; i++)
1377 if (pred_table[i].pred_func == pred_func)
1378 break;
1379 return (pred_table[i].pred_name);
1382 static char *
1383 type_name (type)
1384 short type;
1386 int i;
1388 for (i = 0; type_table[i].type != (short) -1; i++)
1389 if (type_table[i].type == type)
1390 break;
1391 return (type_table[i].type_name);
1394 static char *
1395 prec_name (prec)
1396 short prec;
1398 int i;
1400 for (i = 0; prec_table[i].prec != (short) -1; i++)
1401 if (prec_table[i].prec == prec)
1402 break;
1403 return (prec_table[i].prec_name);
1406 /* Walk the expression tree NODE to stdout.
1407 INDENT is the number of levels to indent the left margin. */
1409 void
1410 print_tree (node, indent)
1411 struct predicate *node;
1412 int indent;
1414 int i;
1416 if (node == NULL)
1417 return;
1418 for (i = 0; i < indent; i++)
1419 printf (" ");
1420 printf ("pred = %s type = %s prec = %s addr = %x\n",
1421 find_pred_name (node->pred_func),
1422 type_name (node->p_type), prec_name (node->p_prec), node);
1423 for (i = 0; i < indent; i++)
1424 printf (" ");
1425 printf (_("left:\n"));
1426 print_tree (node->pred_left, indent + 1);
1427 for (i = 0; i < indent; i++)
1428 printf (" ");
1429 printf (_("right:\n"));
1430 print_tree (node->pred_right, indent + 1);
1433 /* Copy STR into BUF and trim blanks from the end of BUF.
1434 Return BUF. */
1436 static char *
1437 blank_rtrim (str, buf)
1438 char *str;
1439 char *buf;
1441 int i;
1443 if (str == NULL)
1444 return (NULL);
1445 strcpy (buf, str);
1446 i = strlen (buf) - 1;
1447 while ((i >= 0) && ((buf[i] == ' ') || buf[i] == '\t'))
1448 i--;
1449 buf[++i] = '\0';
1450 return (buf);
1453 /* Print out the predicate list starting at NODE. */
1455 void
1456 print_list (node)
1457 struct predicate *node;
1459 struct predicate *cur;
1460 char name[256];
1462 cur = node;
1463 while (cur != NULL)
1465 printf ("%s ", blank_rtrim (find_pred_name (cur->pred_func), name));
1466 cur = cur->pred_next;
1468 printf ("\n");
1470 #endif /* DEBUG */