Brought up-to-date with change in gnulib's human.c - we now use human_readable_inexact()
[findutils.git] / find / pred.c
blob7bdaa4eaa1f7549dd408b36c6e9d495839cf056e
1 /* pred.c -- execute the expression tree.
2 Copyright (C) 1990, 91, 92, 93, 94, 2000, 2003 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 9 Temple Place - Suite 330, Boston, MA 02111-1307,
17 USA.
20 #define _GNU_SOURCE
21 #include "defs.h"
23 #include <fnmatch.h>
24 #include <signal.h>
25 #include <pwd.h>
26 #include <grp.h>
27 #include "dirname.h"
28 #include "human.h"
29 #include "modetype.h"
30 #include "wait.h"
32 #if ENABLE_NLS
33 # include <libintl.h>
34 # define _(Text) gettext (Text)
35 #else
36 # define _(Text) Text
37 #endif
38 #ifdef gettext_noop
39 # define N_(String) gettext_noop (String)
40 #else
41 # define N_(String) (String)
42 #endif
44 #if !defined(SIGCHLD) && defined(SIGCLD)
45 #define SIGCHLD SIGCLD
46 #endif
48 #if HAVE_DIRENT_H
49 # include <dirent.h>
50 # define NAMLEN(dirent) strlen((dirent)->d_name)
51 #else
52 # define dirent direct
53 # define NAMLEN(dirent) (dirent)->d_namlen
54 # if HAVE_SYS_NDIR_H
55 # include <sys/ndir.h>
56 # endif
57 # if HAVE_SYS_DIR_H
58 # include <sys/dir.h>
59 # endif
60 # if HAVE_NDIR_H
61 # include <ndir.h>
62 # endif
63 #endif
65 #ifdef CLOSEDIR_VOID
66 /* Fake a return value. */
67 #define CLOSEDIR(d) (closedir (d), 0)
68 #else
69 #define CLOSEDIR(d) closedir (d)
70 #endif
72 extern int yesno ();
75 /* Get or fake the disk device blocksize.
76 Usually defined by sys/param.h (if at all). */
77 #ifndef DEV_BSIZE
78 # ifdef BSIZE
79 # define DEV_BSIZE BSIZE
80 # else /* !BSIZE */
81 # define DEV_BSIZE 4096
82 # endif /* !BSIZE */
83 #endif /* !DEV_BSIZE */
85 /* Extract or fake data from a `struct stat'.
86 ST_BLKSIZE: Preferred I/O blocksize for the file, in bytes.
87 ST_NBLOCKS: Number of blocks in the file, including indirect blocks.
88 ST_NBLOCKSIZE: Size of blocks used when calculating ST_NBLOCKS. */
89 #ifndef HAVE_STRUCT_STAT_ST_BLOCKS
90 # define ST_BLKSIZE(statbuf) DEV_BSIZE
91 # if defined(_POSIX_SOURCE) || !defined(BSIZE) /* fileblocks.c uses BSIZE. */
92 # define ST_NBLOCKS(statbuf) \
93 (S_ISREG ((statbuf).st_mode) \
94 || S_ISDIR ((statbuf).st_mode) \
95 ? (statbuf).st_size / ST_NBLOCKSIZE + ((statbuf).st_size % ST_NBLOCKSIZE != 0) : 0)
96 # else /* !_POSIX_SOURCE && BSIZE */
97 # define ST_NBLOCKS(statbuf) \
98 (S_ISREG ((statbuf).st_mode) \
99 || S_ISDIR ((statbuf).st_mode) \
100 ? st_blocks ((statbuf).st_size) : 0)
101 # endif /* !_POSIX_SOURCE && BSIZE */
102 #else /* HAVE_STRUCT_STAT_ST_BLOCKS */
103 /* Some systems, like Sequents, return st_blksize of 0 on pipes. */
104 # define ST_BLKSIZE(statbuf) ((statbuf).st_blksize > 0 \
105 ? (statbuf).st_blksize : DEV_BSIZE)
106 # if defined(hpux) || defined(__hpux__) || defined(__hpux)
107 /* HP-UX counts st_blocks in 1024-byte units.
108 This loses when mixing HP-UX and BSD filesystems with NFS. */
109 # define ST_NBLOCKSIZE 1024
110 # else /* !hpux */
111 # if defined(_AIX) && defined(_I386)
112 /* AIX PS/2 counts st_blocks in 4K units. */
113 # define ST_NBLOCKSIZE (4 * 1024)
114 # else /* not AIX PS/2 */
115 # if defined(_CRAY)
116 # define ST_NBLOCKS(statbuf) \
117 (S_ISREG ((statbuf).st_mode) \
118 || S_ISDIR ((statbuf).st_mode) \
119 ? (statbuf).st_blocks * ST_BLKSIZE(statbuf)/ST_NBLOCKSIZE : 0)
120 # endif /* _CRAY */
121 # endif /* not AIX PS/2 */
122 # endif /* !hpux */
123 #endif /* HAVE_STRUCT_STAT_ST_BLOCKS */
125 #ifndef ST_NBLOCKS
126 # define ST_NBLOCKS(statbuf) \
127 (S_ISREG ((statbuf).st_mode) \
128 || S_ISDIR ((statbuf).st_mode) \
129 ? (statbuf).st_blocks : 0)
130 #endif
132 #ifndef ST_NBLOCKSIZE
133 # define ST_NBLOCKSIZE 512
134 #endif
136 #undef MAX
137 #define MAX(a, b) ((a) > (b) ? (a) : (b))
139 static boolean insert_lname PARAMS((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr, boolean ignore_case));
140 static boolean launch PARAMS((struct predicate *pred_ptr));
141 static char *format_date PARAMS((time_t when, int kind));
142 static char *ctime_format PARAMS((time_t when));
144 #ifdef DEBUG
145 struct pred_assoc
147 PFB pred_func;
148 char *pred_name;
151 struct pred_assoc pred_table[] =
153 {pred_amin, "amin "},
154 {pred_and, "and "},
155 {pred_anewer, "anewer "},
156 {pred_atime, "atime "},
157 {pred_close, ") "},
158 {pred_amin, "cmin "},
159 {pred_cnewer, "cnewer "},
160 {pred_comma, ", "},
161 {pred_ctime, "ctime "},
162 {pred_empty, "empty "},
163 {pred_exec, "exec "},
164 {pred_false, "false "},
165 {pred_fprint, "fprint "},
166 {pred_fprint0, "fprint0 "},
167 {pred_fprintf, "fprintf "},
168 {pred_fstype, "fstype "},
169 {pred_gid, "gid "},
170 {pred_group, "group "},
171 {pred_ilname, "ilname "},
172 {pred_iname, "iname "},
173 {pred_inum, "inum "},
174 {pred_ipath, "ipath "},
175 {pred_links, "links "},
176 {pred_lname, "lname "},
177 {pred_ls, "ls "},
178 {pred_amin, "mmin "},
179 {pred_mtime, "mtime "},
180 {pred_name, "name "},
181 {pred_negate, "not "},
182 {pred_newer, "newer "},
183 {pred_nogroup, "nogroup "},
184 {pred_nouser, "nouser "},
185 {pred_ok, "ok "},
186 {pred_open, "( "},
187 {pred_or, "or "},
188 {pred_path, "path "},
189 {pred_perm, "perm "},
190 {pred_print, "print "},
191 {pred_print0, "print0 "},
192 {pred_prune, "prune "},
193 {pred_regex, "regex "},
194 {pred_size, "size "},
195 {pred_true, "true "},
196 {pred_type, "type "},
197 {pred_uid, "uid "},
198 {pred_used, "used "},
199 {pred_user, "user "},
200 {pred_xtype, "xtype "},
201 {0, "none "}
204 struct op_assoc
206 short type;
207 char *type_name;
210 struct op_assoc type_table[] =
212 {NO_TYPE, "no "},
213 {PRIMARY_TYPE, "primary "},
214 {UNI_OP, "uni_op "},
215 {BI_OP, "bi_op "},
216 {OPEN_PAREN, "open_paren "},
217 {CLOSE_PAREN, "close_paren "},
218 {-1, "unknown "}
221 struct prec_assoc
223 short prec;
224 char *prec_name;
227 struct prec_assoc prec_table[] =
229 {NO_PREC, "no "},
230 {COMMA_PREC, "comma "},
231 {OR_PREC, "or "},
232 {AND_PREC, "and "},
233 {NEGATE_PREC, "negate "},
234 {MAX_PREC, "max "},
235 {-1, "unknown "}
237 #endif /* DEBUG */
239 /* Predicate processing routines.
241 PATHNAME is the full pathname of the file being checked.
242 *STAT_BUF contains information about PATHNAME.
243 *PRED_PTR contains information for applying the predicate.
245 Return true if the file passes this predicate, false if not. */
247 boolean
248 pred_amin (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
250 switch (pred_ptr->args.info.kind)
252 case COMP_GT:
253 if (stat_buf->st_atime > (time_t) pred_ptr->args.info.l_val)
254 return (true);
255 break;
256 case COMP_LT:
257 if (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val)
258 return (true);
259 break;
260 case COMP_EQ:
261 if ((stat_buf->st_atime >= (time_t) pred_ptr->args.info.l_val)
262 && (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val + 60))
263 return (true);
264 break;
266 return (false);
269 boolean
270 pred_and (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
272 if (pred_ptr->pred_left == NULL
273 || (*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
274 pred_ptr->pred_left))
276 /* Check whether we need a stat here. */
277 if (pred_ptr->need_stat)
279 if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
281 error (0, errno, "%s", pathname);
282 exit_status = 1;
283 return (false);
285 have_stat = true;
287 return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
288 pred_ptr->pred_right));
290 else
291 return (false);
294 boolean
295 pred_anewer (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
297 if (stat_buf->st_atime > pred_ptr->args.time)
298 return (true);
299 return (false);
302 boolean
303 pred_atime (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
305 switch (pred_ptr->args.info.kind)
307 case COMP_GT:
308 if (stat_buf->st_atime > (time_t) pred_ptr->args.info.l_val)
309 return (true);
310 break;
311 case COMP_LT:
312 if (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val)
313 return (true);
314 break;
315 case COMP_EQ:
316 if ((stat_buf->st_atime >= (time_t) pred_ptr->args.info.l_val)
317 && (stat_buf->st_atime < (time_t) pred_ptr->args.info.l_val
318 + DAYSECS))
319 return (true);
320 break;
322 return (false);
325 boolean
326 pred_close (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
328 return (true);
331 boolean
332 pred_cmin (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
334 switch (pred_ptr->args.info.kind)
336 case COMP_GT:
337 if (stat_buf->st_ctime > (time_t) pred_ptr->args.info.l_val)
338 return (true);
339 break;
340 case COMP_LT:
341 if (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val)
342 return (true);
343 break;
344 case COMP_EQ:
345 if ((stat_buf->st_ctime >= (time_t) pred_ptr->args.info.l_val)
346 && (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val + 60))
347 return (true);
348 break;
350 return (false);
353 boolean
354 pred_cnewer (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
356 if (stat_buf->st_ctime > pred_ptr->args.time)
357 return (true);
358 return (false);
361 boolean
362 pred_comma (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
364 if (pred_ptr->pred_left != NULL)
365 (*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
366 pred_ptr->pred_left);
367 /* Check whether we need a stat here. */
368 if (pred_ptr->need_stat)
370 if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
372 error (0, errno, "%s", pathname);
373 exit_status = 1;
374 return (false);
376 have_stat = true;
378 return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
379 pred_ptr->pred_right));
382 boolean
383 pred_ctime (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
385 switch (pred_ptr->args.info.kind)
387 case COMP_GT:
388 if (stat_buf->st_ctime > (time_t) pred_ptr->args.info.l_val)
389 return (true);
390 break;
391 case COMP_LT:
392 if (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val)
393 return (true);
394 break;
395 case COMP_EQ:
396 if ((stat_buf->st_ctime >= (time_t) pred_ptr->args.info.l_val)
397 && (stat_buf->st_ctime < (time_t) pred_ptr->args.info.l_val
398 + DAYSECS))
399 return (true);
400 break;
402 return (false);
405 boolean
406 pred_empty (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
408 if (S_ISDIR (stat_buf->st_mode))
410 DIR *d;
411 struct dirent *dp;
412 boolean empty = true;
414 errno = 0;
415 d = opendir (rel_pathname);
416 if (d == NULL)
418 error (0, errno, "%s", pathname);
419 exit_status = 1;
420 return (false);
422 for (dp = readdir (d); dp; dp = readdir (d))
424 if (dp->d_name[0] != '.'
425 || (dp->d_name[1] != '\0'
426 && (dp->d_name[1] != '.' || dp->d_name[2] != '\0')))
428 empty = false;
429 break;
432 if (CLOSEDIR (d))
434 error (0, errno, "%s", pathname);
435 exit_status = 1;
436 return (false);
438 return (empty);
440 else if (S_ISREG (stat_buf->st_mode))
441 return (stat_buf->st_size == 0);
442 else
443 return (false);
446 boolean
447 pred_exec (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
449 int i;
450 int path_pos;
451 struct exec_val *execp; /* Pointer for efficiency. */
453 execp = &pred_ptr->args.exec_vec;
455 /* Replace "{}" with the real path in each affected arg. */
456 for (path_pos = 0; execp->paths[path_pos].offset >= 0; path_pos++)
458 register char *from, *to;
460 i = execp->paths[path_pos].offset;
461 execp->vec[i] =
462 xmalloc (strlen (execp->paths[path_pos].origarg) + 1
463 + (strlen (pathname) - 2) * execp->paths[path_pos].count);
464 for (from = execp->paths[path_pos].origarg, to = execp->vec[i]; *from; )
465 if (from[0] == '{' && from[1] == '}')
467 to = stpcpy (to, pathname);
468 from += 2;
470 else
471 *to++ = *from++;
472 *to = *from; /* Copy null. */
475 i = launch (pred_ptr);
477 /* Free the temporary args. */
478 for (path_pos = 0; execp->paths[path_pos].offset >= 0; path_pos++)
479 free (execp->vec[execp->paths[path_pos].offset]);
481 return (i);
484 boolean
485 pred_false (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
487 return (false);
490 boolean
491 pred_fls (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
493 list_file (pathname, rel_pathname, stat_buf, start_time,
494 output_block_size, pred_ptr->args.stream);
495 return (true);
498 boolean
499 pred_fprint (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
501 fputs (pathname, pred_ptr->args.stream);
502 putc ('\n', pred_ptr->args.stream);
503 return (true);
506 boolean
507 pred_fprint0 (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
509 fputs (pathname, pred_ptr->args.stream);
510 putc (0, pred_ptr->args.stream);
511 return (true);
514 boolean
515 pred_fprintf (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
517 FILE *fp = pred_ptr->args.printf_vec.stream;
518 struct segment *segment;
519 char *cp;
520 char hbuf[LONGEST_HUMAN_READABLE + 1];
522 for (segment = pred_ptr->args.printf_vec.segment; segment;
523 segment = segment->next)
525 if (segment->kind & 0xff00) /* Component of date. */
527 time_t t;
529 switch (segment->kind & 0xff)
531 case 'A':
532 t = stat_buf->st_atime;
533 break;
534 case 'C':
535 t = stat_buf->st_ctime;
536 break;
537 case 'T':
538 t = stat_buf->st_mtime;
539 break;
540 default:
541 abort ();
543 fprintf (fp, segment->text,
544 format_date (t, (segment->kind >> 8) & 0xff));
545 continue;
548 switch (segment->kind)
550 case KIND_PLAIN: /* Plain text string (no % conversion). */
551 fwrite (segment->text, 1, segment->text_len, fp);
552 break;
553 case KIND_STOP: /* Terminate argument and flush output. */
554 fwrite (segment->text, 1, segment->text_len, fp);
555 fflush (fp);
556 return (true);
557 case 'a': /* atime in `ctime' format. */
558 fprintf (fp, segment->text, ctime_format (stat_buf->st_atime));
559 break;
560 case 'b': /* size in 512-byte blocks */
561 fprintf (fp, segment->text,
562 human_readable_inexact ((uintmax_t) ST_NBLOCKS (*stat_buf),
563 hbuf,
564 ST_NBLOCKSIZE, 512,
565 human_ceiling));
566 break;
567 case 'c': /* ctime in `ctime' format */
568 fprintf (fp, segment->text, ctime_format (stat_buf->st_ctime));
569 break;
570 case 'd': /* depth in search tree */
571 fprintf (fp, segment->text, curdepth);
572 break;
573 case 'f': /* basename of path */
574 fprintf (fp, segment->text, base_name (pathname));
575 break;
576 case 'F': /* filesystem type */
577 fprintf (fp, segment->text,
578 filesystem_type (pathname, rel_pathname, stat_buf));
579 break;
580 case 'g': /* group name */
582 struct group *g;
584 g = getgrgid (stat_buf->st_gid);
585 if (g)
587 segment->text[segment->text_len] = 's';
588 fprintf (fp, segment->text, g->gr_name);
589 break;
591 /* else fallthru */
593 case 'G': /* GID number */
594 fprintf (fp, segment->text,
595 human_readable_inexact ((uintmax_t) stat_buf->st_gid, hbuf,
596 1, 1, human_ceiling));
597 break;
598 case 'h': /* leading directories part of path */
600 char cc;
602 cp = strrchr (pathname, '/');
603 if (cp == NULL) /* No leading directories. */
604 break;
605 cc = *cp;
606 *cp = '\0';
607 fprintf (fp, segment->text, pathname);
608 *cp = cc;
609 break;
611 case 'H': /* ARGV element file was found under */
613 char cc = pathname[path_length];
615 pathname[path_length] = '\0';
616 fprintf (fp, segment->text, pathname);
617 pathname[path_length] = cc;
618 break;
620 case 'i': /* inode number */
621 fprintf (fp, segment->text,
622 human_readable_inexact ((uintmax_t) stat_buf->st_ino, hbuf,
623 1, 1,
624 human_ceiling));
625 break;
626 case 'k': /* size in 1K blocks */
627 fprintf (fp, segment->text,
628 human_readable_inexact ((uintmax_t) ST_NBLOCKS (*stat_buf),
629 hbuf,
630 ST_NBLOCKSIZE, 1024,
631 human_ceiling));
632 break;
633 case 'l': /* object of symlink */
634 #ifdef S_ISLNK
636 char *linkname = 0;
638 if (S_ISLNK (stat_buf->st_mode))
640 linkname = get_link_name (pathname, rel_pathname);
641 if (linkname == 0)
642 exit_status = 1;
644 if (linkname)
646 fprintf (fp, segment->text, linkname);
647 free (linkname);
649 else
650 fprintf (fp, segment->text, "");
652 #endif /* S_ISLNK */
653 break;
654 case 'm': /* mode as octal number (perms only) */
656 /* Output the mode portably using the traditional numbers,
657 even if the host unwisely uses some other numbering
658 scheme. But help the compiler in the common case where
659 the host uses the traditional numbering scheme. */
660 mode_t m = stat_buf->st_mode;
661 boolean traditional_numbering_scheme =
662 (S_ISUID == 04000 && S_ISGID == 02000 && S_ISVTX == 01000
663 && S_IRUSR == 00400 && S_IWUSR == 00200 && S_IXUSR == 00100
664 && S_IRGRP == 00040 && S_IWGRP == 00020 && S_IXGRP == 00010
665 && S_IROTH == 00004 && S_IWOTH == 00002 && S_IXOTH == 00001);
666 fprintf (fp, segment->text,
667 (traditional_numbering_scheme
668 ? m & MODE_ALL
669 : ((m & S_ISUID ? 04000 : 0)
670 | (m & S_ISGID ? 02000 : 0)
671 | (m & S_ISVTX ? 01000 : 0)
672 | (m & S_IRUSR ? 00400 : 0)
673 | (m & S_IWUSR ? 00200 : 0)
674 | (m & S_IXUSR ? 00100 : 0)
675 | (m & S_IRGRP ? 00040 : 0)
676 | (m & S_IWGRP ? 00020 : 0)
677 | (m & S_IXGRP ? 00010 : 0)
678 | (m & S_IROTH ? 00004 : 0)
679 | (m & S_IWOTH ? 00002 : 0)
680 | (m & S_IXOTH ? 00001 : 0))));
682 break;
683 case 'n': /* number of links */
684 fprintf (fp, segment->text,
685 human_readable_inexact ((uintmax_t) stat_buf->st_nlink,
686 hbuf,
687 1, 1,
688 human_ceiling));
689 break;
690 case 'p': /* pathname */
691 fprintf (fp, segment->text, pathname);
692 break;
693 case 'P': /* pathname with ARGV element stripped */
694 if (curdepth)
696 cp = pathname + path_length;
697 if (*cp == '/')
698 /* Move past the slash between the ARGV element
699 and the rest of the pathname. But if the ARGV element
700 ends in a slash, we didn't add another, so we've
701 already skipped past it. */
702 cp++;
704 else
705 cp = "";
706 fprintf (fp, segment->text, cp);
707 break;
708 case 's': /* size in bytes */
709 fprintf (fp, segment->text,
710 human_readable_inexact ((uintmax_t) stat_buf->st_size,
711 hbuf, 1, 1, human_ceiling));
712 break;
713 case 't': /* mtime in `ctime' format */
714 fprintf (fp, segment->text, ctime_format (stat_buf->st_mtime));
715 break;
716 case 'u': /* user name */
718 struct passwd *p;
720 p = getpwuid (stat_buf->st_uid);
721 if (p)
723 segment->text[segment->text_len] = 's';
724 fprintf (fp, segment->text, p->pw_name);
725 break;
727 /* else fallthru */
729 case 'U': /* UID number */
730 fprintf (fp, segment->text,
731 human_readable_inexact ((uintmax_t) stat_buf->st_uid, hbuf,
732 1, 1, human_ceiling));
733 break;
736 return (true);
739 boolean
740 pred_fstype (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
742 if (strcmp (filesystem_type (pathname, rel_pathname, stat_buf),
743 pred_ptr->args.str) == 0)
744 return (true);
745 return (false);
748 boolean
749 pred_gid (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
751 switch (pred_ptr->args.info.kind)
753 case COMP_GT:
754 if (stat_buf->st_gid > pred_ptr->args.info.l_val)
755 return (true);
756 break;
757 case COMP_LT:
758 if (stat_buf->st_gid < pred_ptr->args.info.l_val)
759 return (true);
760 break;
761 case COMP_EQ:
762 if (stat_buf->st_gid == pred_ptr->args.info.l_val)
763 return (true);
764 break;
766 return (false);
769 boolean
770 pred_group (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
772 if (pred_ptr->args.gid == stat_buf->st_gid)
773 return (true);
774 else
775 return (false);
778 boolean
779 pred_ilname (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
781 return insert_lname (pathname, stat_buf, pred_ptr, true);
784 boolean
785 pred_iname (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
787 const char *base;
789 base = base_name (pathname);
790 if (fnmatch (pred_ptr->args.str, base, FNM_PERIOD | FNM_CASEFOLD) == 0)
791 return (true);
792 return (false);
795 boolean
796 pred_inum (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
798 switch (pred_ptr->args.info.kind)
800 case COMP_GT:
801 if (stat_buf->st_ino > pred_ptr->args.info.l_val)
802 return (true);
803 break;
804 case COMP_LT:
805 if (stat_buf->st_ino < pred_ptr->args.info.l_val)
806 return (true);
807 break;
808 case COMP_EQ:
809 if (stat_buf->st_ino == pred_ptr->args.info.l_val)
810 return (true);
811 break;
813 return (false);
816 boolean
817 pred_ipath (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
819 if (fnmatch (pred_ptr->args.str, pathname, FNM_CASEFOLD) == 0)
820 return (true);
821 return (false);
824 boolean
825 pred_links (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
827 switch (pred_ptr->args.info.kind)
829 case COMP_GT:
830 if (stat_buf->st_nlink > pred_ptr->args.info.l_val)
831 return (true);
832 break;
833 case COMP_LT:
834 if (stat_buf->st_nlink < pred_ptr->args.info.l_val)
835 return (true);
836 break;
837 case COMP_EQ:
838 if (stat_buf->st_nlink == pred_ptr->args.info.l_val)
839 return (true);
840 break;
842 return (false);
845 boolean
846 pred_lname (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
848 return insert_lname (pathname, stat_buf, pred_ptr, false);
851 static boolean
852 insert_lname (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr, boolean ignore_case)
854 boolean ret = false;
855 #ifdef S_ISLNK
856 if (S_ISLNK (stat_buf->st_mode))
858 char *linkname = get_link_name (pathname, rel_pathname);
859 if (linkname)
861 if (fnmatch (pred_ptr->args.str, linkname,
862 ignore_case ? FNM_CASEFOLD : 0) == 0)
863 ret = true;
864 free (linkname);
867 #endif /* S_ISLNK */
868 return (ret);
871 boolean
872 pred_ls (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
874 list_file (pathname, rel_pathname, stat_buf, start_time,
875 output_block_size, stdout);
876 return (true);
879 boolean
880 pred_mmin (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
882 switch (pred_ptr->args.info.kind)
884 case COMP_GT:
885 if (stat_buf->st_mtime > (time_t) pred_ptr->args.info.l_val)
886 return (true);
887 break;
888 case COMP_LT:
889 if (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val)
890 return (true);
891 break;
892 case COMP_EQ:
893 if ((stat_buf->st_mtime >= (time_t) pred_ptr->args.info.l_val)
894 && (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val + 60))
895 return (true);
896 break;
898 return (false);
901 boolean
902 pred_mtime (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
904 switch (pred_ptr->args.info.kind)
906 case COMP_GT:
907 if (stat_buf->st_mtime > (time_t) pred_ptr->args.info.l_val)
908 return (true);
909 break;
910 case COMP_LT:
911 if (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val)
912 return (true);
913 break;
914 case COMP_EQ:
915 if ((stat_buf->st_mtime >= (time_t) pred_ptr->args.info.l_val)
916 && (stat_buf->st_mtime < (time_t) pred_ptr->args.info.l_val
917 + DAYSECS))
918 return (true);
919 break;
921 return (false);
924 boolean
925 pred_name (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
927 const char *base;
929 base = base_name (pathname);
930 if (fnmatch (pred_ptr->args.str, base, FNM_PERIOD) == 0)
931 return (true);
932 return (false);
935 boolean
936 pred_negate (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
938 /* Check whether we need a stat here. */
939 if (pred_ptr->need_stat)
941 if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
943 error (0, errno, "%s", pathname);
944 exit_status = 1;
945 return (false);
947 have_stat = true;
949 return (!(*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
950 pred_ptr->pred_right));
953 boolean
954 pred_newer (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
956 if (stat_buf->st_mtime > pred_ptr->args.time)
957 return (true);
958 return (false);
961 boolean
962 pred_nogroup (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
964 #ifdef CACHE_IDS
965 extern char *gid_unused;
967 return gid_unused[(unsigned) stat_buf->st_gid];
968 #else
969 return getgrgid (stat_buf->st_gid) == NULL;
970 #endif
973 boolean
974 pred_nouser (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
976 #ifdef CACHE_IDS
977 extern char *uid_unused;
979 return uid_unused[(unsigned) stat_buf->st_uid];
980 #else
981 return getpwuid (stat_buf->st_uid) == NULL;
982 #endif
985 boolean
986 pred_ok (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
988 fflush (stdout);
989 /* The draft open standard requires that, in the POSIX locale,
990 the last non-blank character of this prompt be '?'.
991 The exact format is not specified.
992 This standard does not have requirements for locales other than POSIX
994 fprintf (stderr, _("< %s ... %s > ? "),
995 pred_ptr->args.exec_vec.vec[0], pathname);
996 fflush (stderr);
997 if (yesno ())
998 return pred_exec (pathname, stat_buf, pred_ptr);
999 else
1000 return (false);
1003 boolean
1004 pred_open (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1006 return (true);
1009 boolean
1010 pred_or (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1012 if (pred_ptr->pred_left == NULL
1013 || !(*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
1014 pred_ptr->pred_left))
1016 /* Check whether we need a stat here. */
1017 if (pred_ptr->need_stat)
1019 if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
1021 error (0, errno, "%s", pathname);
1022 exit_status = 1;
1023 return (false);
1025 have_stat = true;
1027 return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
1028 pred_ptr->pred_right));
1030 else
1031 return (true);
1034 boolean
1035 pred_path (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1037 if (fnmatch (pred_ptr->args.str, pathname, 0) == 0)
1038 return (true);
1039 return (false);
1042 boolean
1043 pred_perm (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1045 switch (pred_ptr->args.perm.kind)
1047 case PERM_AT_LEAST:
1048 return (stat_buf->st_mode & pred_ptr->args.perm.val) == pred_ptr->args.perm.val;
1049 break;
1051 case PERM_ANY:
1052 return (stat_buf->st_mode & pred_ptr->args.perm.val) != 0;
1053 break;
1055 case PERM_EXACT:
1056 return (stat_buf->st_mode & MODE_ALL) == pred_ptr->args.perm.val;
1057 break;
1059 default:
1060 abort ();
1061 break;
1065 boolean
1066 pred_print (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1068 puts (pathname);
1069 return (true);
1072 boolean
1073 pred_print0 (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1075 fputs (pathname, stdout);
1076 putc (0, stdout);
1077 return (true);
1080 boolean
1081 pred_prune (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1083 stop_at_current_level = true;
1084 return (do_dir_first); /* This is what SunOS find seems to do. */
1087 boolean
1088 pred_regex (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1090 int len = strlen (pathname);
1091 if (re_match (pred_ptr->args.regex, pathname, len, 0,
1092 (struct re_registers *) NULL) == len)
1093 return (true);
1094 return (false);
1097 boolean
1098 pred_size (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1100 uintmax_t f_val;
1102 f_val = ((stat_buf->st_size / pred_ptr->args.size.blocksize)
1103 + (stat_buf->st_size % pred_ptr->args.size.blocksize != 0));
1104 switch (pred_ptr->args.size.kind)
1106 case COMP_GT:
1107 if (f_val > pred_ptr->args.size.size)
1108 return (true);
1109 break;
1110 case COMP_LT:
1111 if (f_val < pred_ptr->args.size.size)
1112 return (true);
1113 break;
1114 case COMP_EQ:
1115 if (f_val == pred_ptr->args.size.size)
1116 return (true);
1117 break;
1119 return (false);
1122 boolean
1123 pred_true (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1125 return (true);
1128 boolean
1129 pred_type (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1131 mode_t mode = stat_buf->st_mode;
1132 mode_t type = pred_ptr->args.type;
1134 #ifndef S_IFMT
1135 /* POSIX system; check `mode' the slow way. */
1136 if ((S_ISBLK (mode) && type == S_IFBLK)
1137 || (S_ISCHR (mode) && type == S_IFCHR)
1138 || (S_ISDIR (mode) && type == S_IFDIR)
1139 || (S_ISREG (mode) && type == S_IFREG)
1140 #ifdef S_IFLNK
1141 || (S_ISLNK (mode) && type == S_IFLNK)
1142 #endif
1143 #ifdef S_IFIFO
1144 || (S_ISFIFO (mode) && type == S_IFIFO)
1145 #endif
1146 #ifdef S_IFSOCK
1147 || (S_ISSOCK (mode) && type == S_IFSOCK)
1148 #endif
1149 #ifdef S_IFDOOR
1150 || (S_ISDOOR (mode) && type == S_IFDOOR)
1151 #endif
1153 #else /* S_IFMT */
1154 /* Unix system; check `mode' the fast way. */
1155 if ((mode & S_IFMT) == type)
1156 #endif /* S_IFMT */
1157 return (true);
1158 else
1159 return (false);
1162 boolean
1163 pred_uid (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1165 switch (pred_ptr->args.info.kind)
1167 case COMP_GT:
1168 if (stat_buf->st_uid > pred_ptr->args.info.l_val)
1169 return (true);
1170 break;
1171 case COMP_LT:
1172 if (stat_buf->st_uid < pred_ptr->args.info.l_val)
1173 return (true);
1174 break;
1175 case COMP_EQ:
1176 if (stat_buf->st_uid == pred_ptr->args.info.l_val)
1177 return (true);
1178 break;
1180 return (false);
1183 boolean
1184 pred_used (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1186 time_t delta;
1188 delta = stat_buf->st_atime - stat_buf->st_ctime; /* Use difftime? */
1189 switch (pred_ptr->args.info.kind)
1191 case COMP_GT:
1192 if (delta > (time_t) pred_ptr->args.info.l_val)
1193 return (true);
1194 break;
1195 case COMP_LT:
1196 if (delta < (time_t) pred_ptr->args.info.l_val)
1197 return (true);
1198 break;
1199 case COMP_EQ:
1200 if ((delta >= (time_t) pred_ptr->args.info.l_val)
1201 && (delta < (time_t) pred_ptr->args.info.l_val + DAYSECS))
1202 return (true);
1203 break;
1205 return (false);
1208 boolean
1209 pred_user (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1211 if (pred_ptr->args.uid == stat_buf->st_uid)
1212 return (true);
1213 else
1214 return (false);
1217 boolean
1218 pred_xtype (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1220 struct stat sbuf;
1221 int (*ystat) ();
1223 ystat = xstat == lstat ? stat : lstat;
1224 if ((*ystat) (rel_pathname, &sbuf) != 0)
1226 if (ystat == stat && errno == ENOENT)
1227 /* Mimic behavior of ls -lL. */
1228 return (pred_type (pathname, stat_buf, pred_ptr));
1229 error (0, errno, "%s", pathname);
1230 exit_status = 1;
1231 return (false);
1233 return (pred_type (pathname, &sbuf, pred_ptr));
1236 /* 1) fork to get a child; parent remembers the child pid
1237 2) child execs the command requested
1238 3) parent waits for child; checks for proper pid of child
1240 Possible returns:
1242 ret errno status(h) status(l)
1244 pid x signal# 0177 stopped
1245 pid x exit arg 0 term by _exit
1246 pid x 0 signal # term by signal
1247 -1 EINTR parent got signal
1248 -1 other some other kind of error
1250 Return true only if the pid matches, status(l) is
1251 zero, and the exit arg (status high) is 0.
1252 Otherwise return false, possibly printing an error message. */
1254 static boolean
1255 launch (struct predicate *pred_ptr)
1257 int status;
1258 pid_t child_pid;
1259 struct exec_val *execp; /* Pointer for efficiency. */
1260 static int first_time = 1;
1262 execp = &pred_ptr->args.exec_vec;
1264 /* Make sure output of command doesn't get mixed with find output. */
1265 fflush (stdout);
1266 fflush (stderr);
1268 /* Make sure to listen for the kids. */
1269 if (first_time)
1271 first_time = 0;
1272 signal (SIGCHLD, SIG_DFL);
1275 child_pid = fork ();
1276 if (child_pid == -1)
1277 error (1, errno, _("cannot fork"));
1278 if (child_pid == 0)
1280 /* We be the child. */
1281 if (starting_desc < 0
1282 ? chdir (starting_dir) != 0
1283 : fchdir (starting_desc) != 0)
1285 error (0, errno, "%s", starting_dir);
1286 _exit (1);
1288 execvp (execp->vec[0], execp->vec);
1289 error (0, errno, "%s", execp->vec[0]);
1290 _exit (1);
1294 while (waitpid (child_pid, &status, 0) == (pid_t) -1)
1295 if (errno != EINTR)
1297 error (0, errno, _("error waiting for %s"), execp->vec[0]);
1298 exit_status = 1;
1299 return false;
1301 if (WIFSIGNALED (status))
1303 error (0, 0, _("%s terminated by signal %d"),
1304 execp->vec[0], WTERMSIG (status));
1305 exit_status = 1;
1306 return (false);
1308 return (!WEXITSTATUS (status));
1311 /* Return a static string formatting the time WHEN according to the
1312 strftime format character KIND. */
1314 static char *
1315 format_date (time_t when, int kind)
1317 static char buf[MAX (LONGEST_HUMAN_READABLE + 2, 64)];
1318 struct tm *tm;
1319 char fmt[3];
1321 fmt[0] = '%';
1322 fmt[1] = kind;
1323 fmt[2] = '\0';
1325 if (kind != '@'
1326 && (tm = localtime (&when))
1327 && strftime (buf, sizeof buf, fmt, tm))
1328 return buf;
1329 else
1331 uintmax_t w = when;
1332 char *p = human_readable_inexact (when < 0 ? -w : w, buf + 1,
1333 1, 1, human_ceiling);
1334 if (when < 0)
1335 *--p = '-';
1336 return p;
1340 static char *
1341 ctime_format (when)
1342 time_t when;
1344 char *r = ctime (&when);
1345 if (!r)
1347 /* The time cannot be represented as a struct tm.
1348 Output it as an integer. */
1349 return format_date (when, '@');
1351 else
1353 /* Remove the trailing newline from the ctime output,
1354 being careful not to assume that the output is fixed-width. */
1355 *strchr (r, '\n') = '\0';
1356 return r;
1360 #ifdef DEBUG
1361 /* Return a pointer to the string representation of
1362 the predicate function PRED_FUNC. */
1364 char *
1365 find_pred_name (pred_func)
1366 PFB pred_func;
1368 int i;
1370 for (i = 0; pred_table[i].pred_func != 0; i++)
1371 if (pred_table[i].pred_func == pred_func)
1372 break;
1373 return (pred_table[i].pred_name);
1376 static char *
1377 type_name (type)
1378 short type;
1380 int i;
1382 for (i = 0; type_table[i].type != (short) -1; i++)
1383 if (type_table[i].type == type)
1384 break;
1385 return (type_table[i].type_name);
1388 static char *
1389 prec_name (prec)
1390 short prec;
1392 int i;
1394 for (i = 0; prec_table[i].prec != (short) -1; i++)
1395 if (prec_table[i].prec == prec)
1396 break;
1397 return (prec_table[i].prec_name);
1400 /* Walk the expression tree NODE to stdout.
1401 INDENT is the number of levels to indent the left margin. */
1403 void
1404 print_tree (node, indent)
1405 struct predicate *node;
1406 int indent;
1408 int i;
1410 if (node == NULL)
1411 return;
1412 for (i = 0; i < indent; i++)
1413 printf (" ");
1414 printf ("pred = %s type = %s prec = %s addr = %x\n",
1415 find_pred_name (node->pred_func),
1416 type_name (node->p_type), prec_name (node->p_prec), node);
1417 for (i = 0; i < indent; i++)
1418 printf (" ");
1419 printf (_("left:\n"));
1420 print_tree (node->pred_left, indent + 1);
1421 for (i = 0; i < indent; i++)
1422 printf (" ");
1423 printf (_("right:\n"));
1424 print_tree (node->pred_right, indent + 1);
1427 /* Copy STR into BUF and trim blanks from the end of BUF.
1428 Return BUF. */
1430 static char *
1431 blank_rtrim (str, buf)
1432 char *str;
1433 char *buf;
1435 int i;
1437 if (str == NULL)
1438 return (NULL);
1439 strcpy (buf, str);
1440 i = strlen (buf) - 1;
1441 while ((i >= 0) && ((buf[i] == ' ') || buf[i] == '\t'))
1442 i--;
1443 buf[++i] = '\0';
1444 return (buf);
1447 /* Print out the predicate list starting at NODE. */
1449 void
1450 print_list (node)
1451 struct predicate *node;
1453 struct predicate *cur;
1454 char name[256];
1456 cur = node;
1457 while (cur != NULL)
1459 printf ("%s ", blank_rtrim (find_pred_name (cur->pred_func), name));
1460 cur = cur->pred_next;
1462 printf ("\n");
1464 #endif /* DEBUG */