* locate/testsuite/Makefile.am: Added missing \ at end of
[findutils.git] / find / pred.c
blobd0bc136ecae77d280f2539ca693f894a99fdec1d
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
71 /* Get or fake the disk device blocksize.
72 Usually defined by sys/param.h (if at all). */
73 #ifndef DEV_BSIZE
74 # ifdef BSIZE
75 # define DEV_BSIZE BSIZE
76 # else /* !BSIZE */
77 # define DEV_BSIZE 4096
78 # endif /* !BSIZE */
79 #endif /* !DEV_BSIZE */
81 /* Extract or fake data from a `struct stat'.
82 ST_BLKSIZE: Preferred I/O blocksize for the file, in bytes.
83 ST_NBLOCKS: Number of blocks in the file, including indirect blocks.
84 ST_NBLOCKSIZE: Size of blocks used when calculating ST_NBLOCKS. */
85 #ifndef HAVE_STRUCT_STAT_ST_BLOCKS
86 # define ST_BLKSIZE(statbuf) DEV_BSIZE
87 # if defined(_POSIX_SOURCE) || !defined(BSIZE) /* fileblocks.c uses BSIZE. */
88 # define ST_NBLOCKS(statbuf) \
89 (S_ISREG ((statbuf).st_mode) \
90 || S_ISDIR ((statbuf).st_mode) \
91 ? (statbuf).st_size / ST_NBLOCKSIZE + ((statbuf).st_size % ST_NBLOCKSIZE != 0) : 0)
92 # else /* !_POSIX_SOURCE && BSIZE */
93 # define ST_NBLOCKS(statbuf) \
94 (S_ISREG ((statbuf).st_mode) \
95 || S_ISDIR ((statbuf).st_mode) \
96 ? st_blocks ((statbuf).st_size) : 0)
97 # endif /* !_POSIX_SOURCE && BSIZE */
98 #else /* HAVE_STRUCT_STAT_ST_BLOCKS */
99 /* Some systems, like Sequents, return st_blksize of 0 on pipes. */
100 # define ST_BLKSIZE(statbuf) ((statbuf).st_blksize > 0 \
101 ? (statbuf).st_blksize : DEV_BSIZE)
102 # if defined(hpux) || defined(__hpux__) || defined(__hpux)
103 /* HP-UX counts st_blocks in 1024-byte units.
104 This loses when mixing HP-UX and BSD filesystems with NFS. */
105 # define ST_NBLOCKSIZE 1024
106 # else /* !hpux */
107 # if defined(_AIX) && defined(_I386)
108 /* AIX PS/2 counts st_blocks in 4K units. */
109 # define ST_NBLOCKSIZE (4 * 1024)
110 # else /* not AIX PS/2 */
111 # if defined(_CRAY)
112 # define ST_NBLOCKS(statbuf) \
113 (S_ISREG ((statbuf).st_mode) \
114 || S_ISDIR ((statbuf).st_mode) \
115 ? (statbuf).st_blocks * ST_BLKSIZE(statbuf)/ST_NBLOCKSIZE : 0)
116 # endif /* _CRAY */
117 # endif /* not AIX PS/2 */
118 # endif /* !hpux */
119 #endif /* HAVE_STRUCT_STAT_ST_BLOCKS */
121 #ifndef ST_NBLOCKS
122 # define ST_NBLOCKS(statbuf) \
123 (S_ISREG ((statbuf).st_mode) \
124 || S_ISDIR ((statbuf).st_mode) \
125 ? (statbuf).st_blocks : 0)
126 #endif
128 #ifndef ST_NBLOCKSIZE
129 # define ST_NBLOCKSIZE 512
130 #endif
132 #undef MAX
133 #define MAX(a, b) ((a) > (b) ? (a) : (b))
135 static boolean insert_lname PARAMS((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr, boolean ignore_case));
136 static boolean launch PARAMS((struct predicate *pred_ptr));
137 static char *format_date PARAMS((time_t when, int kind));
138 static char *ctime_format PARAMS((time_t when));
140 #ifdef DEBUG
141 struct pred_assoc
143 PFB pred_func;
144 char *pred_name;
147 struct pred_assoc pred_table[] =
149 {pred_amin, "amin "},
150 {pred_and, "and "},
151 {pred_anewer, "anewer "},
152 {pred_atime, "atime "},
153 {pred_close, ") "},
154 {pred_amin, "cmin "},
155 {pred_cnewer, "cnewer "},
156 {pred_comma, ", "},
157 {pred_ctime, "ctime "},
158 {pred_empty, "empty "},
159 {pred_exec, "exec "},
160 {pred_false, "false "},
161 {pred_fprint, "fprint "},
162 {pred_fprint0, "fprint0 "},
163 {pred_fprintf, "fprintf "},
164 {pred_fstype, "fstype "},
165 {pred_gid, "gid "},
166 {pred_group, "group "},
167 {pred_ilname, "ilname "},
168 {pred_iname, "iname "},
169 {pred_inum, "inum "},
170 {pred_ipath, "ipath "},
171 {pred_links, "links "},
172 {pred_lname, "lname "},
173 {pred_ls, "ls "},
174 {pred_amin, "mmin "},
175 {pred_mtime, "mtime "},
176 {pred_name, "name "},
177 {pred_negate, "not "},
178 {pred_newer, "newer "},
179 {pred_nogroup, "nogroup "},
180 {pred_nouser, "nouser "},
181 {pred_ok, "ok "},
182 {pred_open, "( "},
183 {pred_or, "or "},
184 {pred_path, "path "},
185 {pred_perm, "perm "},
186 {pred_print, "print "},
187 {pred_print0, "print0 "},
188 {pred_prune, "prune "},
189 {pred_regex, "regex "},
190 {pred_size, "size "},
191 {pred_true, "true "},
192 {pred_type, "type "},
193 {pred_uid, "uid "},
194 {pred_used, "used "},
195 {pred_user, "user "},
196 {pred_xtype, "xtype "},
197 {0, "none "}
200 struct op_assoc
202 short type;
203 char *type_name;
206 struct op_assoc type_table[] =
208 {NO_TYPE, "no "},
209 {PRIMARY_TYPE, "primary "},
210 {UNI_OP, "uni_op "},
211 {BI_OP, "bi_op "},
212 {OPEN_PAREN, "open_paren "},
213 {CLOSE_PAREN, "close_paren "},
214 {-1, "unknown "}
217 struct prec_assoc
219 short prec;
220 char *prec_name;
223 struct prec_assoc prec_table[] =
225 {NO_PREC, "no "},
226 {COMMA_PREC, "comma "},
227 {OR_PREC, "or "},
228 {AND_PREC, "and "},
229 {NEGATE_PREC, "negate "},
230 {MAX_PREC, "max "},
231 {-1, "unknown "}
233 #endif /* DEBUG */
235 /* Predicate processing routines.
237 PATHNAME is the full pathname of the file being checked.
238 *STAT_BUF contains information about PATHNAME.
239 *PRED_PTR contains information for applying the predicate.
241 Return true if the file passes this predicate, false if not. */
243 boolean
244 pred_amin (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
246 switch (pred_ptr->args.info.kind)
248 case COMP_GT:
249 if (stat_buf->st_atime > (time_t) pred_ptr->args.info.l_val)
250 return (true);
251 break;
252 case COMP_LT:
253 if (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val)
254 return (true);
255 break;
256 case COMP_EQ:
257 if ((stat_buf->st_atime >= (time_t) pred_ptr->args.info.l_val)
258 && (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val + 60))
259 return (true);
260 break;
262 return (false);
265 boolean
266 pred_and (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
268 if (pred_ptr->pred_left == NULL
269 || (*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
270 pred_ptr->pred_left))
272 /* Check whether we need a stat here. */
273 if (pred_ptr->need_stat)
275 if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
277 error (0, errno, "%s", pathname);
278 exit_status = 1;
279 return (false);
281 have_stat = true;
283 return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
284 pred_ptr->pred_right));
286 else
287 return (false);
290 boolean
291 pred_anewer (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
293 if (stat_buf->st_atime > pred_ptr->args.time)
294 return (true);
295 return (false);
298 boolean
299 pred_atime (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
301 switch (pred_ptr->args.info.kind)
303 case COMP_GT:
304 if (stat_buf->st_atime > (time_t) pred_ptr->args.info.l_val)
305 return (true);
306 break;
307 case COMP_LT:
308 if (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val)
309 return (true);
310 break;
311 case COMP_EQ:
312 if ((stat_buf->st_atime >= (time_t) pred_ptr->args.info.l_val)
313 && (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val
314 + DAYSECS))
315 return (true);
316 break;
318 return (false);
321 boolean
322 pred_close (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
324 return (true);
327 boolean
328 pred_cmin (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
330 switch (pred_ptr->args.info.kind)
332 case COMP_GT:
333 if (stat_buf->st_ctime > (time_t) pred_ptr->args.info.l_val)
334 return (true);
335 break;
336 case COMP_LT:
337 if (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val)
338 return (true);
339 break;
340 case COMP_EQ:
341 if ((stat_buf->st_ctime >= (time_t) pred_ptr->args.info.l_val)
342 && (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val + 60))
343 return (true);
344 break;
346 return (false);
349 boolean
350 pred_cnewer (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
352 if (stat_buf->st_ctime > pred_ptr->args.time)
353 return (true);
354 return (false);
357 boolean
358 pred_comma (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
360 if (pred_ptr->pred_left != NULL)
361 (*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
362 pred_ptr->pred_left);
363 /* Check whether we need a stat here. */
364 if (pred_ptr->need_stat)
366 if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
368 error (0, errno, "%s", pathname);
369 exit_status = 1;
370 return (false);
372 have_stat = true;
374 return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
375 pred_ptr->pred_right));
378 boolean
379 pred_ctime (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
381 switch (pred_ptr->args.info.kind)
383 case COMP_GT:
384 if (stat_buf->st_ctime > (time_t) pred_ptr->args.info.l_val)
385 return (true);
386 break;
387 case COMP_LT:
388 if (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val)
389 return (true);
390 break;
391 case COMP_EQ:
392 if ((stat_buf->st_ctime >= (time_t) pred_ptr->args.info.l_val)
393 && (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val
394 + DAYSECS))
395 return (true);
396 break;
398 return (false);
401 boolean
402 pred_empty (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
404 if (S_ISDIR (stat_buf->st_mode))
406 DIR *d;
407 struct dirent *dp;
408 boolean empty = true;
410 errno = 0;
411 d = opendir (rel_pathname);
412 if (d == NULL)
414 error (0, errno, "%s", pathname);
415 exit_status = 1;
416 return (false);
418 for (dp = readdir (d); dp; dp = readdir (d))
420 if (dp->d_name[0] != '.'
421 || (dp->d_name[1] != '\0'
422 && (dp->d_name[1] != '.' || dp->d_name[2] != '\0')))
424 empty = false;
425 break;
428 if (CLOSEDIR (d))
430 error (0, errno, "%s", pathname);
431 exit_status = 1;
432 return (false);
434 return (empty);
436 else if (S_ISREG (stat_buf->st_mode))
437 return (stat_buf->st_size == 0);
438 else
439 return (false);
442 boolean
443 pred_exec (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
445 int i;
446 int path_pos;
447 struct exec_val *execp; /* Pointer for efficiency. */
449 execp = &pred_ptr->args.exec_vec;
451 /* Replace "{}" with the real path in each affected arg. */
452 for (path_pos = 0; execp->paths[path_pos].offset >= 0; path_pos++)
454 register char *from, *to;
456 i = execp->paths[path_pos].offset;
457 execp->vec[i] =
458 xmalloc (strlen (execp->paths[path_pos].origarg) + 1
459 + (strlen (pathname) - 2) * execp->paths[path_pos].count);
460 for (from = execp->paths[path_pos].origarg, to = execp->vec[i]; *from; )
461 if (from[0] == '{' && from[1] == '}')
463 to = stpcpy (to, pathname);
464 from += 2;
466 else
467 *to++ = *from++;
468 *to = *from; /* Copy null. */
471 i = launch (pred_ptr);
473 /* Free the temporary args. */
474 for (path_pos = 0; execp->paths[path_pos].offset >= 0; path_pos++)
475 free (execp->vec[execp->paths[path_pos].offset]);
477 return (i);
480 boolean
481 pred_false (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
483 return (false);
486 boolean
487 pred_fls (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
489 list_file (pathname, rel_pathname, stat_buf, start_time,
490 output_block_size, pred_ptr->args.stream);
491 return (true);
494 boolean
495 pred_fprint (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
497 fputs (pathname, pred_ptr->args.stream);
498 putc ('\n', pred_ptr->args.stream);
499 return (true);
502 boolean
503 pred_fprint0 (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
505 fputs (pathname, pred_ptr->args.stream);
506 putc (0, pred_ptr->args.stream);
507 return (true);
510 boolean
511 pred_fprintf (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
513 FILE *fp = pred_ptr->args.printf_vec.stream;
514 struct segment *segment;
515 char *cp;
516 char hbuf[LONGEST_HUMAN_READABLE + 1];
518 for (segment = pred_ptr->args.printf_vec.segment; segment;
519 segment = segment->next)
521 if (segment->kind & 0xff00) /* Component of date. */
523 time_t t;
525 switch (segment->kind & 0xff)
527 case 'A':
528 t = stat_buf->st_atime;
529 break;
530 case 'C':
531 t = stat_buf->st_ctime;
532 break;
533 case 'T':
534 t = stat_buf->st_mtime;
535 break;
536 default:
537 abort ();
539 fprintf (fp, segment->text,
540 format_date (t, (segment->kind >> 8) & 0xff));
541 continue;
544 switch (segment->kind)
546 case KIND_PLAIN: /* Plain text string (no % conversion). */
547 fwrite (segment->text, 1, segment->text_len, fp);
548 break;
549 case KIND_STOP: /* Terminate argument and flush output. */
550 fwrite (segment->text, 1, segment->text_len, fp);
551 fflush (fp);
552 return (true);
553 case 'a': /* atime in `ctime' format. */
554 fprintf (fp, segment->text, ctime_format (stat_buf->st_atime));
555 break;
556 case 'b': /* size in 512-byte blocks */
557 fprintf (fp, segment->text,
558 human_readable ((uintmax_t) ST_NBLOCKS (*stat_buf),
559 hbuf, ST_NBLOCKSIZE, 512));
560 break;
561 case 'c': /* ctime in `ctime' format */
562 fprintf (fp, segment->text, ctime_format (stat_buf->st_ctime));
563 break;
564 case 'd': /* depth in search tree */
565 fprintf (fp, segment->text, curdepth);
566 break;
567 case 'f': /* basename of path */
568 fprintf (fp, segment->text, base_name (pathname));
569 break;
570 case 'F': /* filesystem type */
571 fprintf (fp, segment->text,
572 filesystem_type (pathname, rel_pathname, stat_buf));
573 break;
574 case 'g': /* group name */
576 struct group *g;
578 g = getgrgid (stat_buf->st_gid);
579 if (g)
581 segment->text[segment->text_len] = 's';
582 fprintf (fp, segment->text, g->gr_name);
583 break;
585 /* else fallthru */
587 case 'G': /* GID number */
588 fprintf (fp, segment->text,
589 human_readable ((uintmax_t) stat_buf->st_gid, hbuf, 1, 1));
590 break;
591 case 'h': /* leading directories part of path */
593 char cc;
595 cp = strrchr (pathname, '/');
596 if (cp == NULL) /* No leading directories. */
597 break;
598 cc = *cp;
599 *cp = '\0';
600 fprintf (fp, segment->text, pathname);
601 *cp = cc;
602 break;
604 case 'H': /* ARGV element file was found under */
606 char cc = pathname[path_length];
608 pathname[path_length] = '\0';
609 fprintf (fp, segment->text, pathname);
610 pathname[path_length] = cc;
611 break;
613 case 'i': /* inode number */
614 fprintf (fp, segment->text,
615 human_readable ((uintmax_t) stat_buf->st_ino, hbuf, 1, 1));
616 break;
617 case 'k': /* size in 1K blocks */
618 fprintf (fp, segment->text,
619 human_readable ((uintmax_t) ST_NBLOCKS (*stat_buf),
620 hbuf, ST_NBLOCKSIZE, 1024));
621 break;
622 case 'l': /* object of symlink */
623 #ifdef S_ISLNK
625 char *linkname = 0;
627 if (S_ISLNK (stat_buf->st_mode))
629 linkname = get_link_name (pathname, rel_pathname);
630 if (linkname == 0)
631 exit_status = 1;
633 if (linkname)
635 fprintf (fp, segment->text, linkname);
636 free (linkname);
638 else
639 fprintf (fp, segment->text, "");
641 #endif /* S_ISLNK */
642 break;
643 case 'm': /* mode as octal number (perms only) */
645 /* Output the mode portably using the traditional numbers,
646 even if the host unwisely uses some other numbering
647 scheme. But help the compiler in the common case where
648 the host uses the traditional numbering scheme. */
649 mode_t m = stat_buf->st_mode;
650 boolean traditional_numbering_scheme =
651 (S_ISUID == 04000 && S_ISGID == 02000 && S_ISVTX == 01000
652 && S_IRUSR == 00400 && S_IWUSR == 00200 && S_IXUSR == 00100
653 && S_IRGRP == 00040 && S_IWGRP == 00020 && S_IXGRP == 00010
654 && S_IROTH == 00004 && S_IWOTH == 00002 && S_IXOTH == 00001);
655 fprintf (fp, segment->text,
656 (traditional_numbering_scheme
657 ? m & MODE_ALL
658 : ((m & S_ISUID ? 04000 : 0)
659 | (m & S_ISGID ? 02000 : 0)
660 | (m & S_ISVTX ? 01000 : 0)
661 | (m & S_IRUSR ? 00400 : 0)
662 | (m & S_IWUSR ? 00200 : 0)
663 | (m & S_IXUSR ? 00100 : 0)
664 | (m & S_IRGRP ? 00040 : 0)
665 | (m & S_IWGRP ? 00020 : 0)
666 | (m & S_IXGRP ? 00010 : 0)
667 | (m & S_IROTH ? 00004 : 0)
668 | (m & S_IWOTH ? 00002 : 0)
669 | (m & S_IXOTH ? 00001 : 0))));
671 break;
672 case 'n': /* number of links */
673 fprintf (fp, segment->text,
674 human_readable ((uintmax_t) stat_buf->st_nlink,
675 hbuf, 1, 1));
676 break;
677 case 'p': /* pathname */
678 fprintf (fp, segment->text, pathname);
679 break;
680 case 'P': /* pathname with ARGV element stripped */
681 if (curdepth)
683 cp = pathname + path_length;
684 if (*cp == '/')
685 /* Move past the slash between the ARGV element
686 and the rest of the pathname. But if the ARGV element
687 ends in a slash, we didn't add another, so we've
688 already skipped past it. */
689 cp++;
691 else
692 cp = "";
693 fprintf (fp, segment->text, cp);
694 break;
695 case 's': /* size in bytes */
696 fprintf (fp, segment->text,
697 human_readable ((uintmax_t) stat_buf->st_size,
698 hbuf, 1, 1));
699 break;
700 case 't': /* mtime in `ctime' format */
701 fprintf (fp, segment->text, ctime_format (stat_buf->st_mtime));
702 break;
703 case 'u': /* user name */
705 struct passwd *p;
707 p = getpwuid (stat_buf->st_uid);
708 if (p)
710 segment->text[segment->text_len] = 's';
711 fprintf (fp, segment->text, p->pw_name);
712 break;
714 /* else fallthru */
716 case 'U': /* UID number */
717 fprintf (fp, segment->text,
718 human_readable ((uintmax_t) stat_buf->st_uid, hbuf, 1, 1));
719 break;
722 return (true);
725 boolean
726 pred_fstype (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
728 if (strcmp (filesystem_type (pathname, rel_pathname, stat_buf),
729 pred_ptr->args.str) == 0)
730 return (true);
731 return (false);
734 boolean
735 pred_gid (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
737 switch (pred_ptr->args.info.kind)
739 case COMP_GT:
740 if (stat_buf->st_gid > pred_ptr->args.info.l_val)
741 return (true);
742 break;
743 case COMP_LT:
744 if (stat_buf->st_gid < pred_ptr->args.info.l_val)
745 return (true);
746 break;
747 case COMP_EQ:
748 if (stat_buf->st_gid == pred_ptr->args.info.l_val)
749 return (true);
750 break;
752 return (false);
755 boolean
756 pred_group (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
758 if (pred_ptr->args.gid == stat_buf->st_gid)
759 return (true);
760 else
761 return (false);
764 boolean
765 pred_ilname (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
767 return insert_lname (pathname, stat_buf, pred_ptr, true);
770 boolean
771 pred_iname (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
773 const char *base;
775 base = base_name (pathname);
776 if (fnmatch (pred_ptr->args.str, base, FNM_PERIOD | FNM_CASEFOLD) == 0)
777 return (true);
778 return (false);
781 boolean
782 pred_inum (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
784 switch (pred_ptr->args.info.kind)
786 case COMP_GT:
787 if (stat_buf->st_ino > pred_ptr->args.info.l_val)
788 return (true);
789 break;
790 case COMP_LT:
791 if (stat_buf->st_ino < pred_ptr->args.info.l_val)
792 return (true);
793 break;
794 case COMP_EQ:
795 if (stat_buf->st_ino == pred_ptr->args.info.l_val)
796 return (true);
797 break;
799 return (false);
802 boolean
803 pred_ipath (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
805 if (fnmatch (pred_ptr->args.str, pathname, FNM_CASEFOLD) == 0)
806 return (true);
807 return (false);
810 boolean
811 pred_links (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
813 switch (pred_ptr->args.info.kind)
815 case COMP_GT:
816 if (stat_buf->st_nlink > pred_ptr->args.info.l_val)
817 return (true);
818 break;
819 case COMP_LT:
820 if (stat_buf->st_nlink < pred_ptr->args.info.l_val)
821 return (true);
822 break;
823 case COMP_EQ:
824 if (stat_buf->st_nlink == pred_ptr->args.info.l_val)
825 return (true);
826 break;
828 return (false);
831 boolean
832 pred_lname (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
834 return insert_lname (pathname, stat_buf, pred_ptr, false);
837 static boolean
838 insert_lname (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr, boolean ignore_case)
840 boolean ret = false;
841 #ifdef S_ISLNK
842 if (S_ISLNK (stat_buf->st_mode))
844 char *linkname = get_link_name (pathname, rel_pathname);
845 if (linkname)
847 if (fnmatch (pred_ptr->args.str, linkname,
848 ignore_case ? FNM_CASEFOLD : 0) == 0)
849 ret = true;
850 free (linkname);
853 #endif /* S_ISLNK */
854 return (ret);
857 boolean
858 pred_ls (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
860 list_file (pathname, rel_pathname, stat_buf, start_time,
861 output_block_size, stdout);
862 return (true);
865 boolean
866 pred_mmin (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
868 switch (pred_ptr->args.info.kind)
870 case COMP_GT:
871 if (stat_buf->st_mtime > (time_t) pred_ptr->args.info.l_val)
872 return (true);
873 break;
874 case COMP_LT:
875 if (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val)
876 return (true);
877 break;
878 case COMP_EQ:
879 if ((stat_buf->st_mtime >= (time_t) pred_ptr->args.info.l_val)
880 && (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val + 60))
881 return (true);
882 break;
884 return (false);
887 boolean
888 pred_mtime (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
890 switch (pred_ptr->args.info.kind)
892 case COMP_GT:
893 if (stat_buf->st_mtime > (time_t) pred_ptr->args.info.l_val)
894 return (true);
895 break;
896 case COMP_LT:
897 if (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val)
898 return (true);
899 break;
900 case COMP_EQ:
901 if ((stat_buf->st_mtime >= (time_t) pred_ptr->args.info.l_val)
902 && (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val
903 + DAYSECS))
904 return (true);
905 break;
907 return (false);
910 boolean
911 pred_name (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
913 const char *base;
915 base = base_name (pathname);
916 if (fnmatch (pred_ptr->args.str, base, FNM_PERIOD) == 0)
917 return (true);
918 return (false);
921 boolean
922 pred_negate (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
924 /* Check whether we need a stat here. */
925 if (pred_ptr->need_stat)
927 if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
929 error (0, errno, "%s", pathname);
930 exit_status = 1;
931 return (false);
933 have_stat = true;
935 return (!(*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
936 pred_ptr->pred_right));
939 boolean
940 pred_newer (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
942 if (stat_buf->st_mtime > pred_ptr->args.time)
943 return (true);
944 return (false);
947 boolean
948 pred_nogroup (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
950 #ifdef CACHE_IDS
951 extern char *gid_unused;
953 return gid_unused[(unsigned) stat_buf->st_gid];
954 #else
955 return getgrgid (stat_buf->st_gid) == NULL;
956 #endif
959 boolean
960 pred_nouser (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
962 #ifdef CACHE_IDS
963 extern char *uid_unused;
965 return uid_unused[(unsigned) stat_buf->st_uid];
966 #else
967 return getpwuid (stat_buf->st_uid) == NULL;
968 #endif
971 boolean
972 pred_ok (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
974 int i, yes;
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 i = getchar ();
986 yes = (i == 'y' || i == 'Y');
987 while (i != EOF && i != '\n')
988 i = getchar ();
989 if (!yes)
990 return (false);
991 return pred_exec (pathname, stat_buf, pred_ptr);
994 boolean
995 pred_open (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
997 return (true);
1000 boolean
1001 pred_or (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1003 if (pred_ptr->pred_left == NULL
1004 || !(*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
1005 pred_ptr->pred_left))
1007 /* Check whether we need a stat here. */
1008 if (pred_ptr->need_stat)
1010 if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
1012 error (0, errno, "%s", pathname);
1013 exit_status = 1;
1014 return (false);
1016 have_stat = true;
1018 return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
1019 pred_ptr->pred_right));
1021 else
1022 return (true);
1025 boolean
1026 pred_path (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1028 if (fnmatch (pred_ptr->args.str, pathname, 0) == 0)
1029 return (true);
1030 return (false);
1033 boolean
1034 pred_perm (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1036 switch (pred_ptr->args.perm.kind)
1038 case PERM_AT_LEAST:
1039 return (stat_buf->st_mode & pred_ptr->args.perm.val) == pred_ptr->args.perm.val;
1040 break;
1042 case PERM_ANY:
1043 return (stat_buf->st_mode & pred_ptr->args.perm.val) != 0;
1044 break;
1046 case PERM_EXACT:
1047 return (stat_buf->st_mode & MODE_ALL) == pred_ptr->args.perm.val;
1048 break;
1050 default:
1051 abort ();
1052 break;
1056 boolean
1057 pred_print (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1059 puts (pathname);
1060 return (true);
1063 boolean
1064 pred_print0 (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1066 fputs (pathname, stdout);
1067 putc (0, stdout);
1068 return (true);
1071 boolean
1072 pred_prune (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1074 stop_at_current_level = true;
1075 return (do_dir_first); /* This is what SunOS find seems to do. */
1078 boolean
1079 pred_regex (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1081 int len = strlen (pathname);
1082 if (re_match (pred_ptr->args.regex, pathname, len, 0,
1083 (struct re_registers *) NULL) == len)
1084 return (true);
1085 return (false);
1088 boolean
1089 pred_size (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1091 uintmax_t f_val;
1093 f_val = ((stat_buf->st_size / pred_ptr->args.size.blocksize)
1094 + (stat_buf->st_size % pred_ptr->args.size.blocksize != 0));
1095 switch (pred_ptr->args.size.kind)
1097 case COMP_GT:
1098 if (f_val > pred_ptr->args.size.size)
1099 return (true);
1100 break;
1101 case COMP_LT:
1102 if (f_val < pred_ptr->args.size.size)
1103 return (true);
1104 break;
1105 case COMP_EQ:
1106 if (f_val == pred_ptr->args.size.size)
1107 return (true);
1108 break;
1110 return (false);
1113 boolean
1114 pred_true (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1116 return (true);
1119 boolean
1120 pred_type (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1122 mode_t mode = stat_buf->st_mode;
1123 mode_t type = pred_ptr->args.type;
1125 #ifndef S_IFMT
1126 /* POSIX system; check `mode' the slow way. */
1127 if ((S_ISBLK (mode) && type == S_IFBLK)
1128 || (S_ISCHR (mode) && type == S_IFCHR)
1129 || (S_ISDIR (mode) && type == S_IFDIR)
1130 || (S_ISREG (mode) && type == S_IFREG)
1131 #ifdef S_IFLNK
1132 || (S_ISLNK (mode) && type == S_IFLNK)
1133 #endif
1134 #ifdef S_IFIFO
1135 || (S_ISFIFO (mode) && type == S_IFIFO)
1136 #endif
1137 #ifdef S_IFSOCK
1138 || (S_ISSOCK (mode) && type == S_IFSOCK)
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 #ifndef HAVE_FCHDIR
1270 if (chdir (starting_dir) < 0)
1272 error (0, errno, "%s", starting_dir);
1273 _exit (1);
1275 #else
1276 if (fchdir (starting_desc) < 0)
1278 error (0, errno, _("cannot return to starting directory"));
1279 _exit (1);
1281 #endif
1282 execvp (execp->vec[0], execp->vec);
1283 error (0, errno, "%s", execp->vec[0]);
1284 _exit (1);
1288 while (waitpid (child_pid, &status, 0) == (pid_t) -1)
1289 if (errno != EINTR)
1291 error (0, errno, _("error waiting for %s"), execp->vec[0]);
1292 exit_status = 1;
1293 return false;
1295 if (WIFSIGNALED (status))
1297 error (0, 0, _("%s terminated by signal %d"),
1298 execp->vec[0], WTERMSIG (status));
1299 exit_status = 1;
1300 return (false);
1302 return (!WEXITSTATUS (status));
1305 /* Return a static string formatting the time WHEN according to the
1306 strftime format character KIND. */
1308 static char *
1309 format_date (time_t when, int kind)
1311 static char buf[MAX (LONGEST_HUMAN_READABLE + 2, 64)];
1312 struct tm *tm;
1313 char fmt[3];
1315 fmt[0] = '%';
1316 fmt[1] = kind;
1317 fmt[2] = '\0';
1319 if (kind != '@'
1320 && (tm = localtime (&when))
1321 && strftime (buf, sizeof buf, fmt, tm))
1322 return buf;
1323 else
1325 uintmax_t w = when;
1326 char *p = human_readable (when < 0 ? -w : w, buf + 1, 1, 1);
1327 if (when < 0)
1328 *--p = '-';
1329 return p;
1333 static char *
1334 ctime_format (when)
1335 time_t when;
1337 char *r = ctime (&when);
1338 if (!r)
1340 /* The time cannot be represented as a struct tm.
1341 Output it as an integer. */
1342 return format_date (when, '@');
1344 else
1346 /* Remove the trailing newline from the ctime output,
1347 being careful not to assume that the output is fixed-width. */
1348 *strchr (r, '\n') = '\0';
1349 return r;
1353 #ifdef DEBUG
1354 /* Return a pointer to the string representation of
1355 the predicate function PRED_FUNC. */
1357 char *
1358 find_pred_name (pred_func)
1359 PFB pred_func;
1361 int i;
1363 for (i = 0; pred_table[i].pred_func != 0; i++)
1364 if (pred_table[i].pred_func == pred_func)
1365 break;
1366 return (pred_table[i].pred_name);
1369 static char *
1370 type_name (type)
1371 short type;
1373 int i;
1375 for (i = 0; type_table[i].type != (short) -1; i++)
1376 if (type_table[i].type == type)
1377 break;
1378 return (type_table[i].type_name);
1381 static char *
1382 prec_name (prec)
1383 short prec;
1385 int i;
1387 for (i = 0; prec_table[i].prec != (short) -1; i++)
1388 if (prec_table[i].prec == prec)
1389 break;
1390 return (prec_table[i].prec_name);
1393 /* Walk the expression tree NODE to stdout.
1394 INDENT is the number of levels to indent the left margin. */
1396 void
1397 print_tree (node, indent)
1398 struct predicate *node;
1399 int indent;
1401 int i;
1403 if (node == NULL)
1404 return;
1405 for (i = 0; i < indent; i++)
1406 printf (" ");
1407 printf ("pred = %s type = %s prec = %s addr = %x\n",
1408 find_pred_name (node->pred_func),
1409 type_name (node->p_type), prec_name (node->p_prec), node);
1410 for (i = 0; i < indent; i++)
1411 printf (" ");
1412 printf (_("left:\n"));
1413 print_tree (node->pred_left, indent + 1);
1414 for (i = 0; i < indent; i++)
1415 printf (" ");
1416 printf (_("right:\n"));
1417 print_tree (node->pred_right, indent + 1);
1420 /* Copy STR into BUF and trim blanks from the end of BUF.
1421 Return BUF. */
1423 static char *
1424 blank_rtrim (str, buf)
1425 char *str;
1426 char *buf;
1428 int i;
1430 if (str == NULL)
1431 return (NULL);
1432 strcpy (buf, str);
1433 i = strlen (buf) - 1;
1434 while ((i >= 0) && ((buf[i] == ' ') || buf[i] == '\t'))
1435 i--;
1436 buf[++i] = '\0';
1437 return (buf);
1440 /* Print out the predicate list starting at NODE. */
1442 void
1443 print_list (node)
1444 struct predicate *node;
1446 struct predicate *cur;
1447 char name[256];
1449 cur = node;
1450 while (cur != NULL)
1452 printf ("%s ", blank_rtrim (find_pred_name (cur->pred_func), name));
1453 cur = cur->pred_next;
1455 printf ("\n");
1457 #endif /* DEBUG */