*** empty log message ***
[findutils.git] / find / pred.c
blobb16e8362082ad7f1901e68d7ab1e9cd4222d5a55
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
1138 #else /* S_IFMT */
1139 /* Unix system; check `mode' the fast way. */
1140 if ((mode & S_IFMT) == type)
1141 #endif /* S_IFMT */
1142 return (true);
1143 else
1144 return (false);
1147 boolean
1148 pred_uid (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1150 switch (pred_ptr->args.info.kind)
1152 case COMP_GT:
1153 if (stat_buf->st_uid > pred_ptr->args.info.l_val)
1154 return (true);
1155 break;
1156 case COMP_LT:
1157 if (stat_buf->st_uid < pred_ptr->args.info.l_val)
1158 return (true);
1159 break;
1160 case COMP_EQ:
1161 if (stat_buf->st_uid == pred_ptr->args.info.l_val)
1162 return (true);
1163 break;
1165 return (false);
1168 boolean
1169 pred_used (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1171 time_t delta;
1173 delta = stat_buf->st_atime - stat_buf->st_ctime; /* Use difftime? */
1174 switch (pred_ptr->args.info.kind)
1176 case COMP_GT:
1177 if (delta > (time_t) pred_ptr->args.info.l_val)
1178 return (true);
1179 break;
1180 case COMP_LT:
1181 if (delta < (time_t) pred_ptr->args.info.l_val)
1182 return (true);
1183 break;
1184 case COMP_EQ:
1185 if ((delta >= (time_t) pred_ptr->args.info.l_val)
1186 && (delta < (time_t) pred_ptr->args.info.l_val + DAYSECS))
1187 return (true);
1188 break;
1190 return (false);
1193 boolean
1194 pred_user (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1196 if (pred_ptr->args.uid == stat_buf->st_uid)
1197 return (true);
1198 else
1199 return (false);
1202 boolean
1203 pred_xtype (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1205 struct stat sbuf;
1206 int (*ystat) ();
1208 ystat = xstat == lstat ? stat : lstat;
1209 if ((*ystat) (rel_pathname, &sbuf) != 0)
1211 if (ystat == stat && errno == ENOENT)
1212 /* Mimic behavior of ls -lL. */
1213 return (pred_type (pathname, stat_buf, pred_ptr));
1214 error (0, errno, "%s", pathname);
1215 exit_status = 1;
1216 return (false);
1218 return (pred_type (pathname, &sbuf, pred_ptr));
1221 /* 1) fork to get a child; parent remembers the child pid
1222 2) child execs the command requested
1223 3) parent waits for child; checks for proper pid of child
1225 Possible returns:
1227 ret errno status(h) status(l)
1229 pid x signal# 0177 stopped
1230 pid x exit arg 0 term by _exit
1231 pid x 0 signal # term by signal
1232 -1 EINTR parent got signal
1233 -1 other some other kind of error
1235 Return true only if the pid matches, status(l) is
1236 zero, and the exit arg (status high) is 0.
1237 Otherwise return false, possibly printing an error message. */
1239 static boolean
1240 launch (struct predicate *pred_ptr)
1242 int status;
1243 pid_t child_pid;
1244 struct exec_val *execp; /* Pointer for efficiency. */
1245 static int first_time = 1;
1247 execp = &pred_ptr->args.exec_vec;
1249 /* Make sure output of command doesn't get mixed with find output. */
1250 fflush (stdout);
1251 fflush (stderr);
1253 /* Make sure to listen for the kids. */
1254 if (first_time)
1256 first_time = 0;
1257 signal (SIGCHLD, SIG_DFL);
1260 child_pid = fork ();
1261 if (child_pid == -1)
1262 error (1, errno, _("cannot fork"));
1263 if (child_pid == 0)
1265 /* We be the child. */
1266 #ifndef HAVE_FCHDIR
1267 if (chdir (starting_dir) < 0)
1269 error (0, errno, "%s", starting_dir);
1270 _exit (1);
1272 #else
1273 if (fchdir (starting_desc) < 0)
1275 error (0, errno, _("cannot return to starting directory"));
1276 _exit (1);
1278 #endif
1279 execvp (execp->vec[0], execp->vec);
1280 error (0, errno, "%s", execp->vec[0]);
1281 _exit (1);
1285 while (waitpid (child_pid, &status, 0) == (pid_t) -1)
1286 if (errno != EINTR)
1288 error (0, errno, _("error waiting for %s"), execp->vec[0]);
1289 exit_status = 1;
1290 return false;
1292 if (WIFSIGNALED (status))
1294 error (0, 0, _("%s terminated by signal %d"),
1295 execp->vec[0], WTERMSIG (status));
1296 exit_status = 1;
1297 return (false);
1299 return (!WEXITSTATUS (status));
1302 /* Return a static string formatting the time WHEN according to the
1303 strftime format character KIND. */
1305 static char *
1306 format_date (time_t when, int kind)
1308 static char buf[MAX (LONGEST_HUMAN_READABLE + 2, 64)];
1309 struct tm *tm;
1310 char fmt[3];
1312 fmt[0] = '%';
1313 fmt[1] = kind;
1314 fmt[2] = '\0';
1316 if (kind != '@'
1317 && (tm = localtime (&when))
1318 && strftime (buf, sizeof buf, fmt, tm))
1319 return buf;
1320 else
1322 uintmax_t w = when;
1323 char *p = human_readable (when < 0 ? -w : w, buf + 1, 1, 1);
1324 if (when < 0)
1325 *--p = '-';
1326 return p;
1330 static char *
1331 ctime_format (when)
1332 time_t when;
1334 char *r = ctime (&when);
1335 if (!r)
1337 /* The time cannot be represented as a struct tm.
1338 Output it as an integer. */
1339 return format_date (when, '@');
1341 else
1343 /* Remove the trailing newline from the ctime output,
1344 being careful not to assume that the output is fixed-width. */
1345 *strchr (r, '\n') = '\0';
1346 return r;
1350 #ifdef DEBUG
1351 /* Return a pointer to the string representation of
1352 the predicate function PRED_FUNC. */
1354 char *
1355 find_pred_name (pred_func)
1356 PFB pred_func;
1358 int i;
1360 for (i = 0; pred_table[i].pred_func != 0; i++)
1361 if (pred_table[i].pred_func == pred_func)
1362 break;
1363 return (pred_table[i].pred_name);
1366 static char *
1367 type_name (type)
1368 short type;
1370 int i;
1372 for (i = 0; type_table[i].type != (short) -1; i++)
1373 if (type_table[i].type == type)
1374 break;
1375 return (type_table[i].type_name);
1378 static char *
1379 prec_name (prec)
1380 short prec;
1382 int i;
1384 for (i = 0; prec_table[i].prec != (short) -1; i++)
1385 if (prec_table[i].prec == prec)
1386 break;
1387 return (prec_table[i].prec_name);
1390 /* Walk the expression tree NODE to stdout.
1391 INDENT is the number of levels to indent the left margin. */
1393 void
1394 print_tree (node, indent)
1395 struct predicate *node;
1396 int indent;
1398 int i;
1400 if (node == NULL)
1401 return;
1402 for (i = 0; i < indent; i++)
1403 printf (" ");
1404 printf ("pred = %s type = %s prec = %s addr = %x\n",
1405 find_pred_name (node->pred_func),
1406 type_name (node->p_type), prec_name (node->p_prec), node);
1407 for (i = 0; i < indent; i++)
1408 printf (" ");
1409 printf (_("left:\n"));
1410 print_tree (node->pred_left, indent + 1);
1411 for (i = 0; i < indent; i++)
1412 printf (" ");
1413 printf (_("right:\n"));
1414 print_tree (node->pred_right, indent + 1);
1417 /* Copy STR into BUF and trim blanks from the end of BUF.
1418 Return BUF. */
1420 static char *
1421 blank_rtrim (str, buf)
1422 char *str;
1423 char *buf;
1425 int i;
1427 if (str == NULL)
1428 return (NULL);
1429 strcpy (buf, str);
1430 i = strlen (buf) - 1;
1431 while ((i >= 0) && ((buf[i] == ' ') || buf[i] == '\t'))
1432 i--;
1433 buf[++i] = '\0';
1434 return (buf);
1437 /* Print out the predicate list starting at NODE. */
1439 void
1440 print_list (node)
1441 struct predicate *node;
1443 struct predicate *cur;
1444 char name[256];
1446 cur = node;
1447 while (cur != NULL)
1449 printf ("%s ", blank_rtrim (find_pred_name (cur->pred_func), name));
1450 cur = cur->pred_next;
1452 printf ("\n");
1454 #endif /* DEBUG */