*** empty log message ***
[findutils.git] / find / pred.c
blob74481a12306074d856abff8a57a64835c73e2e0e
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) != 0;
1041 case PERM_ANY:
1042 return (stat_buf->st_mode & pred_ptr->args.perm.val) != 0;
1044 case PERM_EXACT:
1045 return (stat_buf->st_mode & MODE_ALL) == pred_ptr->args.perm.val;
1047 default:
1048 abort ();
1052 boolean
1053 pred_print (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1055 puts (pathname);
1056 return (true);
1059 boolean
1060 pred_print0 (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1062 fputs (pathname, stdout);
1063 putc (0, stdout);
1064 return (true);
1067 boolean
1068 pred_prune (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1070 stop_at_current_level = true;
1071 return (do_dir_first); /* This is what SunOS find seems to do. */
1074 boolean
1075 pred_regex (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1077 int len = strlen (pathname);
1078 if (re_match (pred_ptr->args.regex, pathname, len, 0,
1079 (struct re_registers *) NULL) == len)
1080 return (true);
1081 return (false);
1084 boolean
1085 pred_size (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1087 uintmax_t f_val;
1089 f_val = ((stat_buf->st_size / pred_ptr->args.size.blocksize)
1090 + (stat_buf->st_size % pred_ptr->args.size.blocksize != 0));
1091 switch (pred_ptr->args.size.kind)
1093 case COMP_GT:
1094 if (f_val > pred_ptr->args.size.size)
1095 return (true);
1096 break;
1097 case COMP_LT:
1098 if (f_val < pred_ptr->args.size.size)
1099 return (true);
1100 break;
1101 case COMP_EQ:
1102 if (f_val == pred_ptr->args.size.size)
1103 return (true);
1104 break;
1106 return (false);
1109 boolean
1110 pred_true (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1112 return (true);
1115 boolean
1116 pred_type (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1118 mode_t mode = stat_buf->st_mode;
1119 mode_t type = pred_ptr->args.type;
1121 #ifndef S_IFMT
1122 /* POSIX system; check `mode' the slow way. */
1123 if ((S_ISBLK (mode) && type == S_IFBLK)
1124 || (S_ISCHR (mode) && type == S_IFCHR)
1125 || (S_ISDIR (mode) && type == S_IFDIR)
1126 || (S_ISREG (mode) && type == S_IFREG)
1127 #ifdef S_IFLNK
1128 || (S_ISLNK (mode) && type == S_IFLNK)
1129 #endif
1130 #ifdef S_IFIFO
1131 || (S_ISFIFO (mode) && type == S_IFIFO)
1132 #endif
1133 #ifdef S_IFSOCK
1134 || (S_ISSOCK (mode) && type == S_IFSOCK)
1135 #endif
1137 #else /* S_IFMT */
1138 /* Unix system; check `mode' the fast way. */
1139 if ((mode & S_IFMT) == type)
1140 #endif /* S_IFMT */
1141 return (true);
1142 else
1143 return (false);
1146 boolean
1147 pred_uid (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1149 switch (pred_ptr->args.info.kind)
1151 case COMP_GT:
1152 if (stat_buf->st_uid > pred_ptr->args.info.l_val)
1153 return (true);
1154 break;
1155 case COMP_LT:
1156 if (stat_buf->st_uid < pred_ptr->args.info.l_val)
1157 return (true);
1158 break;
1159 case COMP_EQ:
1160 if (stat_buf->st_uid == pred_ptr->args.info.l_val)
1161 return (true);
1162 break;
1164 return (false);
1167 boolean
1168 pred_used (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1170 time_t delta;
1172 delta = stat_buf->st_atime - stat_buf->st_ctime; /* Use difftime? */
1173 switch (pred_ptr->args.info.kind)
1175 case COMP_GT:
1176 if (delta > (time_t) pred_ptr->args.info.l_val)
1177 return (true);
1178 break;
1179 case COMP_LT:
1180 if (delta < (time_t) pred_ptr->args.info.l_val)
1181 return (true);
1182 break;
1183 case COMP_EQ:
1184 if ((delta >= (time_t) pred_ptr->args.info.l_val)
1185 && (delta < (time_t) pred_ptr->args.info.l_val + DAYSECS))
1186 return (true);
1187 break;
1189 return (false);
1192 boolean
1193 pred_user (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1195 if (pred_ptr->args.uid == stat_buf->st_uid)
1196 return (true);
1197 else
1198 return (false);
1201 boolean
1202 pred_xtype (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1204 struct stat sbuf;
1205 int (*ystat) ();
1207 ystat = xstat == lstat ? stat : lstat;
1208 if ((*ystat) (rel_pathname, &sbuf) != 0)
1210 if (ystat == stat && errno == ENOENT)
1211 /* Mimic behavior of ls -lL. */
1212 return (pred_type (pathname, stat_buf, pred_ptr));
1213 error (0, errno, "%s", pathname);
1214 exit_status = 1;
1215 return (false);
1217 return (pred_type (pathname, &sbuf, pred_ptr));
1220 /* 1) fork to get a child; parent remembers the child pid
1221 2) child execs the command requested
1222 3) parent waits for child; checks for proper pid of child
1224 Possible returns:
1226 ret errno status(h) status(l)
1228 pid x signal# 0177 stopped
1229 pid x exit arg 0 term by _exit
1230 pid x 0 signal # term by signal
1231 -1 EINTR parent got signal
1232 -1 other some other kind of error
1234 Return true only if the pid matches, status(l) is
1235 zero, and the exit arg (status high) is 0.
1236 Otherwise return false, possibly printing an error message. */
1238 static boolean
1239 launch (struct predicate *pred_ptr)
1241 int status;
1242 pid_t child_pid;
1243 struct exec_val *execp; /* Pointer for efficiency. */
1244 static int first_time = 1;
1246 execp = &pred_ptr->args.exec_vec;
1248 /* Make sure output of command doesn't get mixed with find output. */
1249 fflush (stdout);
1250 fflush (stderr);
1252 /* Make sure to listen for the kids. */
1253 if (first_time)
1255 first_time = 0;
1256 signal (SIGCHLD, SIG_DFL);
1259 child_pid = fork ();
1260 if (child_pid == -1)
1261 error (1, errno, _("cannot fork"));
1262 if (child_pid == 0)
1264 /* We be the child. */
1265 #ifndef HAVE_FCHDIR
1266 if (chdir (starting_dir) < 0)
1268 error (0, errno, "%s", starting_dir);
1269 _exit (1);
1271 #else
1272 if (fchdir (starting_desc) < 0)
1274 error (0, errno, _("cannot return to starting directory"));
1275 _exit (1);
1277 #endif
1278 execvp (execp->vec[0], execp->vec);
1279 error (0, errno, "%s", execp->vec[0]);
1280 _exit (1);
1284 while (waitpid (child_pid, &status, 0) == (pid_t) -1)
1285 if (errno != EINTR)
1287 error (0, errno, _("error waiting for %s"), execp->vec[0]);
1288 exit_status = 1;
1289 return false;
1291 if (WIFSIGNALED (status))
1293 error (0, 0, _("%s terminated by signal %d"),
1294 execp->vec[0], WTERMSIG (status));
1295 exit_status = 1;
1296 return (false);
1298 return (!WEXITSTATUS (status));
1301 /* Return a static string formatting the time WHEN according to the
1302 strftime format character KIND. */
1304 static char *
1305 format_date (time_t when, int kind)
1307 static char buf[MAX (LONGEST_HUMAN_READABLE + 2, 64)];
1308 struct tm *tm;
1309 char fmt[3];
1311 fmt[0] = '%';
1312 fmt[1] = kind;
1313 fmt[2] = '\0';
1315 if (kind != '@'
1316 && (tm = localtime (&when))
1317 && strftime (buf, sizeof buf, fmt, tm))
1318 return buf;
1319 else
1321 uintmax_t w = when;
1322 char *p = human_readable (when < 0 ? -w : w, buf + 1, 1, 1);
1323 if (when < 0)
1324 *--p = '-';
1325 return p;
1329 static char *
1330 ctime_format (when)
1331 time_t when;
1333 char *r = ctime (&when);
1334 if (!r)
1336 /* The time cannot be represented as a struct tm.
1337 Output it as an integer. */
1338 return format_date (when, '@');
1340 else
1342 /* Remove the trailing newline from the ctime output,
1343 being careful not to assume that the output is fixed-width. */
1344 *strchr (r, '\n') = '\0';
1345 return r;
1349 #ifdef DEBUG
1350 /* Return a pointer to the string representation of
1351 the predicate function PRED_FUNC. */
1353 char *
1354 find_pred_name (pred_func)
1355 PFB pred_func;
1357 int i;
1359 for (i = 0; pred_table[i].pred_func != 0; i++)
1360 if (pred_table[i].pred_func == pred_func)
1361 break;
1362 return (pred_table[i].pred_name);
1365 static char *
1366 type_name (type)
1367 short type;
1369 int i;
1371 for (i = 0; type_table[i].type != (short) -1; i++)
1372 if (type_table[i].type == type)
1373 break;
1374 return (type_table[i].type_name);
1377 static char *
1378 prec_name (prec)
1379 short prec;
1381 int i;
1383 for (i = 0; prec_table[i].prec != (short) -1; i++)
1384 if (prec_table[i].prec == prec)
1385 break;
1386 return (prec_table[i].prec_name);
1389 /* Walk the expression tree NODE to stdout.
1390 INDENT is the number of levels to indent the left margin. */
1392 void
1393 print_tree (node, indent)
1394 struct predicate *node;
1395 int indent;
1397 int i;
1399 if (node == NULL)
1400 return;
1401 for (i = 0; i < indent; i++)
1402 printf (" ");
1403 printf ("pred = %s type = %s prec = %s addr = %x\n",
1404 find_pred_name (node->pred_func),
1405 type_name (node->p_type), prec_name (node->p_prec), node);
1406 for (i = 0; i < indent; i++)
1407 printf (" ");
1408 printf (_("left:\n"));
1409 print_tree (node->pred_left, indent + 1);
1410 for (i = 0; i < indent; i++)
1411 printf (" ");
1412 printf (_("right:\n"));
1413 print_tree (node->pred_right, indent + 1);
1416 /* Copy STR into BUF and trim blanks from the end of BUF.
1417 Return BUF. */
1419 static char *
1420 blank_rtrim (str, buf)
1421 char *str;
1422 char *buf;
1424 int i;
1426 if (str == NULL)
1427 return (NULL);
1428 strcpy (buf, str);
1429 i = strlen (buf) - 1;
1430 while ((i >= 0) && ((buf[i] == ' ') || buf[i] == '\t'))
1431 i--;
1432 buf[++i] = '\0';
1433 return (buf);
1436 /* Print out the predicate list starting at NODE. */
1438 void
1439 print_list (node)
1440 struct predicate *node;
1442 struct predicate *cur;
1443 char name[256];
1445 cur = node;
1446 while (cur != NULL)
1448 printf ("%s ", blank_rtrim (find_pred_name (cur->pred_func), name));
1449 cur = cur->pred_next;
1451 printf ("\n");
1453 #endif /* DEBUG */