Fixed Savannah bug #3919: use mktemp instead of tempfile
[findutils.git] / find / pred.c
blob38508a87a6aee09ac3734856039d5d33b815c0f9
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17 USA.
20 #include "defs.h"
22 #include <fnmatch.h>
23 #include <signal.h>
24 #include <pwd.h>
25 #include <grp.h>
26 #include "../gnulib/lib/xalloc.h"
27 #include "../gnulib/lib/dirname.h"
28 #include "../gnulib/lib/human.h"
29 #include "modetype.h"
30 #include "filemode.h"
31 #include "wait.h"
33 #if ENABLE_NLS
34 # include <libintl.h>
35 # define _(Text) gettext (Text)
36 #else
37 # define _(Text) Text
38 #endif
39 #ifdef gettext_noop
40 # define N_(String) gettext_noop (String)
41 #else
42 /* See locate.c for explanation as to why not use (String) */
43 # define N_(String) String
44 #endif
46 #if !defined(SIGCHLD) && defined(SIGCLD)
47 #define SIGCHLD SIGCLD
48 #endif
50 #if HAVE_DIRENT_H
51 # include <dirent.h>
52 # define NAMLEN(dirent) strlen((dirent)->d_name)
53 #else
54 # define dirent direct
55 # define NAMLEN(dirent) (dirent)->d_namlen
56 # if HAVE_SYS_NDIR_H
57 # include <sys/ndir.h>
58 # endif
59 # if HAVE_SYS_DIR_H
60 # include <sys/dir.h>
61 # endif
62 # if HAVE_NDIR_H
63 # include <ndir.h>
64 # endif
65 #endif
67 #ifdef CLOSEDIR_VOID
68 /* Fake a return value. */
69 #define CLOSEDIR(d) (closedir (d), 0)
70 #else
71 #define CLOSEDIR(d) closedir (d)
72 #endif
74 extern int yesno ();
77 /* Get or fake the disk device blocksize.
78 Usually defined by sys/param.h (if at all). */
79 #ifndef DEV_BSIZE
80 # ifdef BSIZE
81 # define DEV_BSIZE BSIZE
82 # else /* !BSIZE */
83 # define DEV_BSIZE 4096
84 # endif /* !BSIZE */
85 #endif /* !DEV_BSIZE */
87 /* Extract or fake data from a `struct stat'.
88 ST_BLKSIZE: Preferred I/O blocksize for the file, in bytes.
89 ST_NBLOCKS: Number of blocks in the file, including indirect blocks.
90 ST_NBLOCKSIZE: Size of blocks used when calculating ST_NBLOCKS. */
91 #ifndef HAVE_STRUCT_STAT_ST_BLOCKS
92 # define ST_BLKSIZE(statbuf) DEV_BSIZE
93 # if defined(_POSIX_SOURCE) || !defined(BSIZE) /* fileblocks.c uses BSIZE. */
94 # define ST_NBLOCKS(statbuf) \
95 (S_ISREG ((statbuf).st_mode) \
96 || S_ISDIR ((statbuf).st_mode) \
97 ? (statbuf).st_size / ST_NBLOCKSIZE + ((statbuf).st_size % ST_NBLOCKSIZE != 0) : 0)
98 # else /* !_POSIX_SOURCE && BSIZE */
99 # define ST_NBLOCKS(statbuf) \
100 (S_ISREG ((statbuf).st_mode) \
101 || S_ISDIR ((statbuf).st_mode) \
102 ? st_blocks ((statbuf).st_size) : 0)
103 # endif /* !_POSIX_SOURCE && BSIZE */
104 #else /* HAVE_STRUCT_STAT_ST_BLOCKS */
105 /* Some systems, like Sequents, return st_blksize of 0 on pipes. */
106 # define ST_BLKSIZE(statbuf) ((statbuf).st_blksize > 0 \
107 ? (statbuf).st_blksize : DEV_BSIZE)
108 # if defined(hpux) || defined(__hpux__) || defined(__hpux)
109 /* HP-UX counts st_blocks in 1024-byte units.
110 This loses when mixing HP-UX and BSD filesystems with NFS. */
111 # define ST_NBLOCKSIZE 1024
112 # else /* !hpux */
113 # if defined(_AIX) && defined(_I386)
114 /* AIX PS/2 counts st_blocks in 4K units. */
115 # define ST_NBLOCKSIZE (4 * 1024)
116 # else /* not AIX PS/2 */
117 # if defined(_CRAY)
118 # define ST_NBLOCKS(statbuf) \
119 (S_ISREG ((statbuf).st_mode) \
120 || S_ISDIR ((statbuf).st_mode) \
121 ? (statbuf).st_blocks * ST_BLKSIZE(statbuf)/ST_NBLOCKSIZE : 0)
122 # endif /* _CRAY */
123 # endif /* not AIX PS/2 */
124 # endif /* !hpux */
125 #endif /* HAVE_STRUCT_STAT_ST_BLOCKS */
127 #ifndef ST_NBLOCKS
128 # define ST_NBLOCKS(statbuf) \
129 (S_ISREG ((statbuf).st_mode) \
130 || S_ISDIR ((statbuf).st_mode) \
131 ? (statbuf).st_blocks : 0)
132 #endif
134 #ifndef ST_NBLOCKSIZE
135 # define ST_NBLOCKSIZE 512
136 #endif
138 #undef MAX
139 #define MAX(a, b) ((a) > (b) ? (a) : (b))
141 static boolean insert_lname PARAMS((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr, boolean ignore_case));
142 static boolean launch PARAMS((struct predicate *pred_ptr));
143 static char *format_date PARAMS((time_t when, int kind));
144 static char *ctime_format PARAMS((time_t when));
146 #ifdef DEBUG
147 struct pred_assoc
149 PFB pred_func;
150 char *pred_name;
153 struct pred_assoc pred_table[] =
155 {pred_amin, "amin "},
156 {pred_and, "and "},
157 {pred_anewer, "anewer "},
158 {pred_atime, "atime "},
159 {pred_close, ") "},
160 {pred_amin, "cmin "},
161 {pred_cnewer, "cnewer "},
162 {pred_comma, ", "},
163 {pred_ctime, "ctime "},
164 {pred_delete, "delete "},
165 {pred_empty, "empty "},
166 {pred_exec, "exec "},
167 {pred_false, "false "},
168 {pred_fprint, "fprint "},
169 {pred_fprint0, "fprint0 "},
170 {pred_fprintf, "fprintf "},
171 {pred_fstype, "fstype "},
172 {pred_gid, "gid "},
173 {pred_group, "group "},
174 {pred_ilname, "ilname "},
175 {pred_iname, "iname "},
176 {pred_inum, "inum "},
177 {pred_ipath, "ipath "},
178 {pred_links, "links "},
179 {pred_lname, "lname "},
180 {pred_ls, "ls "},
181 {pred_amin, "mmin "},
182 {pred_mtime, "mtime "},
183 {pred_name, "name "},
184 {pred_negate, "not "},
185 {pred_newer, "newer "},
186 {pred_nogroup, "nogroup "},
187 {pred_nouser, "nouser "},
188 {pred_ok, "ok "},
189 {pred_open, "( "},
190 {pred_or, "or "},
191 {pred_path, "path "},
192 {pred_perm, "perm "},
193 {pred_print, "print "},
194 {pred_print0, "print0 "},
195 {pred_prune, "prune "},
196 {pred_regex, "regex "},
197 {pred_size, "size "},
198 {pred_true, "true "},
199 {pred_type, "type "},
200 {pred_uid, "uid "},
201 {pred_used, "used "},
202 {pred_user, "user "},
203 {pred_xtype, "xtype "},
204 {0, "none "}
207 struct op_assoc
209 short type;
210 char *type_name;
213 struct op_assoc type_table[] =
215 {NO_TYPE, "no "},
216 {PRIMARY_TYPE, "primary "},
217 {UNI_OP, "uni_op "},
218 {BI_OP, "bi_op "},
219 {OPEN_PAREN, "open_paren "},
220 {CLOSE_PAREN, "close_paren "},
221 {-1, "unknown "}
224 struct prec_assoc
226 short prec;
227 char *prec_name;
230 struct prec_assoc prec_table[] =
232 {NO_PREC, "no "},
233 {COMMA_PREC, "comma "},
234 {OR_PREC, "or "},
235 {AND_PREC, "and "},
236 {NEGATE_PREC, "negate "},
237 {MAX_PREC, "max "},
238 {-1, "unknown "}
240 #endif /* DEBUG */
242 /* Predicate processing routines.
244 PATHNAME is the full pathname of the file being checked.
245 *STAT_BUF contains information about PATHNAME.
246 *PRED_PTR contains information for applying the predicate.
248 Return true if the file passes this predicate, false if not. */
251 /* pred_timewindow
253 * Returns true if THE_TIME is
254 * COMP_GT: after the specified time
255 * COMP_LT: before the specified time
256 * COMP_EQ: less than WINDOW seconds after the specified time.
258 static boolean
259 pred_timewindow(time_t the_time, struct predicate const *pred_ptr, int window)
261 switch (pred_ptr->args.info.kind)
263 case COMP_GT:
264 if (the_time > (time_t) pred_ptr->args.info.l_val)
265 return true;
266 break;
267 case COMP_LT:
268 if (the_time < (time_t) pred_ptr->args.info.l_val)
269 return true;
270 break;
271 case COMP_EQ:
272 if ((the_time >= (time_t) pred_ptr->args.info.l_val)
273 && (the_time < (time_t) pred_ptr->args.info.l_val + window))
274 return true;
275 break;
277 return false;
281 boolean
282 pred_amin (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
284 (void) &pathname;
285 return pred_timewindow(stat_buf->st_atime, pred_ptr, 60);
288 boolean
289 pred_and (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
291 if (pred_ptr->pred_left == NULL
292 || (*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
293 pred_ptr->pred_left))
295 /* Check whether we need a stat here. */
296 if (pred_ptr->need_stat)
298 if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
300 error (0, errno, "%s", pathname);
301 exit_status = 1;
302 return (false);
304 have_stat = true;
306 return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
307 pred_ptr->pred_right));
309 else
310 return (false);
313 boolean
314 pred_anewer (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
316 (void) &pathname;
318 if (stat_buf->st_atime > pred_ptr->args.time)
319 return (true);
320 return (false);
323 boolean
324 pred_atime (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
326 (void) &pathname;
327 return pred_timewindow(stat_buf->st_atime, pred_ptr, DAYSECS);
330 boolean
331 pred_close (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
333 (void) &pathname;
334 (void) &stat_buf;
335 (void) &pred_ptr;
337 return true;
340 boolean
341 pred_cmin (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
343 (void) pathname;
344 return pred_timewindow(stat_buf->st_ctime, pred_ptr, 60);
347 boolean
348 pred_cnewer (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
350 (void) pathname;
352 if (stat_buf->st_ctime > pred_ptr->args.time)
353 return true;
354 else
355 return false;
358 boolean
359 pred_comma (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
361 if (pred_ptr->pred_left != NULL)
362 (*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
363 pred_ptr->pred_left);
364 /* Check whether we need a stat here. */
365 if (pred_ptr->need_stat)
367 if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
369 error (0, errno, "%s", pathname);
370 exit_status = 1;
371 return (false);
373 have_stat = true;
375 return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
376 pred_ptr->pred_right));
379 boolean
380 pred_ctime (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
382 (void) &pathname;
383 return pred_timewindow(stat_buf->st_ctime, pred_ptr, DAYSECS);
386 boolean
387 pred_delete (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
389 (void) pred_ptr;
390 (void) stat_buf;
391 if (strcmp (rel_pathname, "."))
393 if (0 != remove (rel_pathname))
395 error (0, errno, "cannot delete %s", pathname);
396 return false;
398 else
400 return true;
404 /* nothing to do. */
405 return true;
408 boolean
409 pred_empty (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
411 (void) pathname;
412 (void) pred_ptr;
414 if (S_ISDIR (stat_buf->st_mode))
416 DIR *d;
417 struct dirent *dp;
418 boolean empty = true;
420 errno = 0;
421 d = opendir (rel_pathname);
422 if (d == NULL)
424 error (0, errno, "%s", pathname);
425 exit_status = 1;
426 return (false);
428 for (dp = readdir (d); dp; dp = readdir (d))
430 if (dp->d_name[0] != '.'
431 || (dp->d_name[1] != '\0'
432 && (dp->d_name[1] != '.' || dp->d_name[2] != '\0')))
434 empty = false;
435 break;
438 if (CLOSEDIR (d))
440 error (0, errno, "%s", pathname);
441 exit_status = 1;
442 return (false);
444 return (empty);
446 else if (S_ISREG (stat_buf->st_mode))
447 return (stat_buf->st_size == 0);
448 else
449 return (false);
452 boolean
453 pred_exec (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
455 int i;
456 int path_pos;
457 struct exec_val *execp; /* Pointer for efficiency. */
459 (void) pathname;
460 (void) stat_buf;
462 execp = &pred_ptr->args.exec_vec;
464 /* Replace "{}" with the real path in each affected arg. */
465 for (path_pos = 0; execp->paths[path_pos].offset >= 0; path_pos++)
467 register char *from, *to;
469 i = execp->paths[path_pos].offset;
470 execp->vec[i] =
471 xmalloc (strlen (execp->paths[path_pos].origarg) + 1
472 + (strlen (pathname) - 2) * execp->paths[path_pos].count);
473 for (from = execp->paths[path_pos].origarg, to = execp->vec[i]; *from; )
474 if (from[0] == '{' && from[1] == '}')
476 to = stpcpy (to, pathname);
477 from += 2;
479 else
480 *to++ = *from++;
481 *to = *from; /* Copy null. */
484 i = launch (pred_ptr);
486 /* Free the temporary args. */
487 for (path_pos = 0; execp->paths[path_pos].offset >= 0; path_pos++)
488 free (execp->vec[execp->paths[path_pos].offset]);
490 return (i);
493 boolean
494 pred_false (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
496 (void) &pathname;
497 (void) &stat_buf;
498 (void) &pred_ptr;
501 return (false);
504 boolean
505 pred_fls (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
507 list_file (pathname, rel_pathname, stat_buf, start_time,
508 output_block_size, pred_ptr->args.stream);
509 return (true);
512 boolean
513 pred_fprint (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
515 (void) &pathname;
516 (void) &stat_buf;
518 fputs (pathname, pred_ptr->args.stream);
519 putc ('\n', pred_ptr->args.stream);
520 return (true);
523 boolean
524 pred_fprint0 (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
526 (void) &pathname;
527 (void) &stat_buf;
529 fputs (pathname, pred_ptr->args.stream);
530 putc (0, pred_ptr->args.stream);
531 return (true);
534 boolean
535 pred_fprintf (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
537 FILE *fp = pred_ptr->args.printf_vec.stream;
538 struct segment *segment;
539 char *cp;
540 char hbuf[LONGEST_HUMAN_READABLE + 1];
542 for (segment = pred_ptr->args.printf_vec.segment; segment;
543 segment = segment->next)
545 if (segment->kind & 0xff00) /* Component of date. */
547 time_t t;
549 switch (segment->kind & 0xff)
551 case 'A':
552 t = stat_buf->st_atime;
553 break;
554 case 'C':
555 t = stat_buf->st_ctime;
556 break;
557 case 'T':
558 t = stat_buf->st_mtime;
559 break;
560 default:
561 abort ();
563 fprintf (fp, segment->text,
564 format_date (t, (segment->kind >> 8) & 0xff));
565 continue;
568 switch (segment->kind)
570 case KIND_PLAIN: /* Plain text string (no % conversion). */
571 fwrite (segment->text, 1, segment->text_len, fp);
572 break;
573 case KIND_STOP: /* Terminate argument and flush output. */
574 fwrite (segment->text, 1, segment->text_len, fp);
575 fflush (fp);
576 return (true);
577 case 'a': /* atime in `ctime' format. */
578 fprintf (fp, segment->text, ctime_format (stat_buf->st_atime));
579 break;
580 case 'b': /* size in 512-byte blocks */
581 fprintf (fp, segment->text,
582 human_readable ((uintmax_t) ST_NBLOCKS (*stat_buf),
583 hbuf, human_ceiling,
584 ST_NBLOCKSIZE, 512));
585 break;
586 case 'c': /* ctime in `ctime' format */
587 fprintf (fp, segment->text, ctime_format (stat_buf->st_ctime));
588 break;
589 case 'd': /* depth in search tree */
590 fprintf (fp, segment->text, curdepth);
591 break;
592 case 'D': /* Device on which file exists (stat.st_dev) */
593 fprintf (fp, segment->text,
594 human_readable ((uintmax_t) stat_buf->st_dev, hbuf,
595 human_ceiling, 1, 1));
596 break;
597 case 'f': /* basename of path */
598 fprintf (fp, segment->text, base_name (pathname));
599 break;
600 case 'F': /* filesystem type */
601 fprintf (fp, segment->text,
602 filesystem_type (pathname, rel_pathname, stat_buf));
603 break;
604 case 'g': /* group name */
606 struct group *g;
608 g = getgrgid (stat_buf->st_gid);
609 if (g)
611 segment->text[segment->text_len] = 's';
612 fprintf (fp, segment->text, g->gr_name);
613 break;
615 /* else fallthru */
617 case 'G': /* GID number */
618 fprintf (fp, segment->text,
619 human_readable ((uintmax_t) stat_buf->st_gid, hbuf,
620 human_ceiling, 1, 1));
621 break;
622 case 'h': /* leading directories part of path */
624 char cc;
626 cp = strrchr (pathname, '/');
627 if (cp == NULL) /* No leading directories. */
628 break;
629 cc = *cp;
630 *cp = '\0';
631 fprintf (fp, segment->text, pathname);
632 *cp = cc;
633 break;
635 case 'H': /* ARGV element file was found under */
637 char cc = pathname[path_length];
639 pathname[path_length] = '\0';
640 fprintf (fp, segment->text, pathname);
641 pathname[path_length] = cc;
642 break;
644 case 'i': /* inode number */
645 fprintf (fp, segment->text,
646 human_readable ((uintmax_t) stat_buf->st_ino, hbuf,
647 human_ceiling,
648 1, 1));
649 break;
650 case 'k': /* size in 1K blocks */
651 fprintf (fp, segment->text,
652 human_readable ((uintmax_t) ST_NBLOCKS (*stat_buf),
653 hbuf, human_ceiling,
654 ST_NBLOCKSIZE, 1024));
655 break;
656 case 'l': /* object of symlink */
657 #ifdef S_ISLNK
659 char *linkname = 0;
661 if (S_ISLNK (stat_buf->st_mode))
663 linkname = get_link_name (pathname, rel_pathname);
664 if (linkname == 0)
665 exit_status = 1;
667 if (linkname)
669 fprintf (fp, segment->text, linkname);
670 free (linkname);
672 else
673 fprintf (fp, segment->text, "");
675 #endif /* S_ISLNK */
676 break;
678 case 'M': /* mode as 10 chars (eg., "-rwxr-x--x" */
680 char modestring[16] ;
681 mode_string (stat_buf->st_mode, modestring);
682 modestring[10] = '\0';
683 fprintf (fp, segment->text, modestring);
685 break;
687 case 'm': /* mode as octal number (perms only) */
689 /* Output the mode portably using the traditional numbers,
690 even if the host unwisely uses some other numbering
691 scheme. But help the compiler in the common case where
692 the host uses the traditional numbering scheme. */
693 mode_t m = stat_buf->st_mode;
694 boolean traditional_numbering_scheme =
695 (S_ISUID == 04000 && S_ISGID == 02000 && S_ISVTX == 01000
696 && S_IRUSR == 00400 && S_IWUSR == 00200 && S_IXUSR == 00100
697 && S_IRGRP == 00040 && S_IWGRP == 00020 && S_IXGRP == 00010
698 && S_IROTH == 00004 && S_IWOTH == 00002 && S_IXOTH == 00001);
699 fprintf (fp, segment->text,
700 (traditional_numbering_scheme
701 ? m & MODE_ALL
702 : ((m & S_ISUID ? 04000 : 0)
703 | (m & S_ISGID ? 02000 : 0)
704 | (m & S_ISVTX ? 01000 : 0)
705 | (m & S_IRUSR ? 00400 : 0)
706 | (m & S_IWUSR ? 00200 : 0)
707 | (m & S_IXUSR ? 00100 : 0)
708 | (m & S_IRGRP ? 00040 : 0)
709 | (m & S_IWGRP ? 00020 : 0)
710 | (m & S_IXGRP ? 00010 : 0)
711 | (m & S_IROTH ? 00004 : 0)
712 | (m & S_IWOTH ? 00002 : 0)
713 | (m & S_IXOTH ? 00001 : 0))));
715 break;
717 case 'n': /* number of links */
718 fprintf (fp, segment->text,
719 human_readable ((uintmax_t) stat_buf->st_nlink,
720 hbuf,
721 human_ceiling,
722 1, 1));
723 break;
724 case 'p': /* pathname */
725 fprintf (fp, segment->text, pathname);
726 break;
727 case 'P': /* pathname with ARGV element stripped */
728 if (curdepth)
730 cp = pathname + path_length;
731 if (*cp == '/')
732 /* Move past the slash between the ARGV element
733 and the rest of the pathname. But if the ARGV element
734 ends in a slash, we didn't add another, so we've
735 already skipped past it. */
736 cp++;
738 else
739 cp = "";
740 fprintf (fp, segment->text, cp);
741 break;
742 case 's': /* size in bytes */
743 fprintf (fp, segment->text,
744 human_readable ((uintmax_t) stat_buf->st_size,
745 hbuf, human_ceiling, 1, 1));
746 break;
747 case 't': /* mtime in `ctime' format */
748 fprintf (fp, segment->text, ctime_format (stat_buf->st_mtime));
749 break;
750 case 'u': /* user name */
752 struct passwd *p;
754 p = getpwuid (stat_buf->st_uid);
755 if (p)
757 segment->text[segment->text_len] = 's';
758 fprintf (fp, segment->text, p->pw_name);
759 break;
761 /* else fallthru */
764 case 'U': /* UID number */
765 fprintf (fp, segment->text,
766 human_readable ((uintmax_t) stat_buf->st_uid, hbuf,
767 human_ceiling, 1, 1));
768 break;
770 /* type of filesystem entry like `ls -l`: (d,-,l,s,p,b,c,n) n=nonexistent(symlink) */
771 case 'Y': /* in case of symlink */
773 #ifdef S_ISLNK
774 if (S_ISLNK (stat_buf->st_mode))
776 struct stat sbuf;
777 int (*ystat) ();
778 ystat = xstat == lstat ? stat : lstat;
779 if ((*ystat) (rel_pathname, &sbuf) != 0)
781 if ( errno == ENOENT ) {
782 fprintf (fp, segment->text, "N");
783 break;
785 if ( errno == ELOOP ) {
786 fprintf (fp, segment->text, "L");
787 break;
789 error (0, errno, "%s", pathname);
790 /* exit_status = 1;
791 return (false); */
793 stat_buf->st_mode = sbuf.st_mode;
795 #endif /* S_ISLNK */
797 /* FALLTHROUGH */
798 case 'y':
800 mode_t m = stat_buf->st_mode & S_IFMT;
802 fprintf (fp, segment->text,
803 ( m == S_IFSOCK ? "s" :
804 m == S_IFLNK ? "l" :
805 m == S_IFREG ? "f" :
806 m == S_IFBLK ? "b" :
807 m == S_IFDIR ? "d" :
808 m == S_IFCHR ? "c" :
809 #ifdef S_IFDOOR
810 m == S_IFDOOR ? "D" :
811 #endif
812 m == S_IFIFO ? "p" : "U" ) );
815 break;
818 return (true);
821 boolean
822 pred_fstype (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
824 if (strcmp (filesystem_type (pathname, rel_pathname, stat_buf),
825 pred_ptr->args.str) == 0)
826 return (true);
827 return (false);
830 boolean
831 pred_gid (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
833 (void) pathname;
835 switch (pred_ptr->args.info.kind)
837 case COMP_GT:
838 if (stat_buf->st_gid > pred_ptr->args.info.l_val)
839 return (true);
840 break;
841 case COMP_LT:
842 if (stat_buf->st_gid < pred_ptr->args.info.l_val)
843 return (true);
844 break;
845 case COMP_EQ:
846 if (stat_buf->st_gid == pred_ptr->args.info.l_val)
847 return (true);
848 break;
850 return (false);
853 boolean
854 pred_group (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
856 (void) pathname;
858 if (pred_ptr->args.gid == stat_buf->st_gid)
859 return (true);
860 else
861 return (false);
864 boolean
865 pred_ilname (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
867 return insert_lname (pathname, stat_buf, pred_ptr, true);
870 boolean
871 pred_iname (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
873 const char *base;
875 (void) stat_buf;
877 /* FNM_PERIOD is not used here because POSIX requires that it not be.
878 * See http://standards.ieee.org/reading/ieee/interp/1003-2-92_int/pasc-1003.2-126.html
880 base = base_name (pathname);
881 if (fnmatch (pred_ptr->args.str, base, FNM_CASEFOLD) == 0)
882 return (true);
883 return (false);
886 boolean
887 pred_inum (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
889 (void) pathname;
891 switch (pred_ptr->args.info.kind)
893 case COMP_GT:
894 if (stat_buf->st_ino > pred_ptr->args.info.l_val)
895 return (true);
896 break;
897 case COMP_LT:
898 if (stat_buf->st_ino < pred_ptr->args.info.l_val)
899 return (true);
900 break;
901 case COMP_EQ:
902 if (stat_buf->st_ino == pred_ptr->args.info.l_val)
903 return (true);
904 break;
906 return (false);
909 boolean
910 pred_ipath (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
912 (void) stat_buf;
914 if (fnmatch (pred_ptr->args.str, pathname, FNM_CASEFOLD) == 0)
915 return (true);
916 return (false);
919 boolean
920 pred_links (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
922 (void) pathname;
924 switch (pred_ptr->args.info.kind)
926 case COMP_GT:
927 if (stat_buf->st_nlink > pred_ptr->args.info.l_val)
928 return (true);
929 break;
930 case COMP_LT:
931 if (stat_buf->st_nlink < pred_ptr->args.info.l_val)
932 return (true);
933 break;
934 case COMP_EQ:
935 if (stat_buf->st_nlink == pred_ptr->args.info.l_val)
936 return (true);
937 break;
939 return (false);
942 boolean
943 pred_lname (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
945 return insert_lname (pathname, stat_buf, pred_ptr, false);
948 static boolean
949 insert_lname (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr, boolean ignore_case)
951 boolean ret = false;
952 #ifdef S_ISLNK
953 if (S_ISLNK (stat_buf->st_mode))
955 char *linkname = get_link_name (pathname, rel_pathname);
956 if (linkname)
958 if (fnmatch (pred_ptr->args.str, linkname,
959 ignore_case ? FNM_CASEFOLD : 0) == 0)
960 ret = true;
961 free (linkname);
964 #endif /* S_ISLNK */
965 return (ret);
968 boolean
969 pred_ls (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
971 (void) pred_ptr;
973 list_file (pathname, rel_pathname, stat_buf, start_time,
974 output_block_size, stdout);
975 return (true);
978 boolean
979 pred_mmin (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
981 (void) &pathname;
982 return pred_timewindow(stat_buf->st_mtime, pred_ptr, 60);
985 boolean
986 pred_mtime (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
988 (void) pathname;
989 return pred_timewindow(stat_buf->st_mtime, pred_ptr, DAYSECS);
992 boolean
993 pred_name (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
995 const char *base;
997 (void) stat_buf;
998 base = base_name (pathname);
1000 /* FNM_PERIOD is not used here because POSIX requires that it not be.
1001 * See http://standards.ieee.org/reading/ieee/interp/1003-2-92_int/pasc-1003.2-126.html
1003 if (fnmatch (pred_ptr->args.str, base, 0) == 0)
1004 return (true);
1005 return (false);
1008 boolean
1009 pred_negate (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1011 /* Check whether we need a stat here. */
1012 if (pred_ptr->need_stat)
1014 if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
1016 error (0, errno, "%s", pathname);
1017 exit_status = 1;
1018 return (false);
1020 have_stat = true;
1022 return (!(*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
1023 pred_ptr->pred_right));
1026 boolean
1027 pred_newer (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1029 (void) pathname;
1031 if (stat_buf->st_mtime > pred_ptr->args.time)
1032 return (true);
1033 return (false);
1036 boolean
1037 pred_nogroup (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1039 (void) pathname;
1040 (void) pred_ptr;
1042 #ifdef CACHE_IDS
1043 extern char *gid_unused;
1045 return gid_unused[(unsigned) stat_buf->st_gid];
1046 #else
1047 return getgrgid (stat_buf->st_gid) == NULL;
1048 #endif
1051 boolean
1052 pred_nouser (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1054 #ifdef CACHE_IDS
1055 extern char *uid_unused;
1056 #endif
1058 (void) pathname;
1059 (void) pred_ptr;
1061 #ifdef CACHE_IDS
1062 return uid_unused[(unsigned) stat_buf->st_uid];
1063 #else
1064 return getpwuid (stat_buf->st_uid) == NULL;
1065 #endif
1068 boolean
1069 pred_ok (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1071 fflush (stdout);
1072 /* The draft open standard requires that, in the POSIX locale,
1073 the last non-blank character of this prompt be '?'.
1074 The exact format is not specified.
1075 This standard does not have requirements for locales other than POSIX
1077 fprintf (stderr, _("< %s ... %s > ? "),
1078 pred_ptr->args.exec_vec.vec[0], pathname);
1079 fflush (stderr);
1080 if (yesno ())
1081 return pred_exec (pathname, stat_buf, pred_ptr);
1082 else
1083 return (false);
1086 boolean
1087 pred_open (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1089 (void) pathname;
1090 (void) stat_buf;
1091 (void) pred_ptr;
1092 return true;
1095 boolean
1096 pred_or (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1098 if (pred_ptr->pred_left == NULL
1099 || !(*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
1100 pred_ptr->pred_left))
1102 /* Check whether we need a stat here. */
1103 if (pred_ptr->need_stat)
1105 if (!have_stat && (*xstat) (rel_pathname, stat_buf) != 0)
1107 error (0, errno, "%s", pathname);
1108 exit_status = 1;
1109 return (false);
1111 have_stat = true;
1113 return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
1114 pred_ptr->pred_right));
1116 else
1117 return (true);
1120 boolean
1121 pred_path (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1123 (void) stat_buf;
1124 if (fnmatch (pred_ptr->args.str, pathname, 0) == 0)
1125 return (true);
1126 return (false);
1129 boolean
1130 pred_perm (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1132 (void) pathname;
1133 switch (pred_ptr->args.perm.kind)
1135 case PERM_AT_LEAST:
1136 return (stat_buf->st_mode & pred_ptr->args.perm.val) == pred_ptr->args.perm.val;
1137 break;
1139 case PERM_ANY:
1140 return (stat_buf->st_mode & pred_ptr->args.perm.val) != 0;
1141 break;
1143 case PERM_EXACT:
1144 return (stat_buf->st_mode & MODE_ALL) == pred_ptr->args.perm.val;
1145 break;
1147 default:
1148 abort ();
1149 break;
1153 boolean
1154 pred_print (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1156 (void) stat_buf;
1157 (void) pred_ptr;
1158 puts (pathname);
1159 return true;
1162 boolean
1163 pred_print0 (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1165 (void) stat_buf;
1166 (void) pred_ptr;
1167 fputs (pathname, stdout);
1168 putc (0, stdout);
1169 return (true);
1172 boolean
1173 pred_prune (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1175 (void) pathname;
1176 (void) stat_buf;
1177 (void) pred_ptr;
1178 stop_at_current_level = true;
1179 return (do_dir_first); /* This is what SunOS find seems to do. */
1182 boolean
1183 pred_quit (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1185 (void) pathname;
1186 (void) stat_buf;
1187 (void) pred_ptr;
1188 exit(0);
1191 boolean
1192 pred_regex (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1194 int len = strlen (pathname);
1195 (void) stat_buf;
1196 if (re_match (pred_ptr->args.regex, pathname, len, 0,
1197 (struct re_registers *) NULL) == len)
1198 return (true);
1199 return (false);
1202 boolean
1203 pred_size (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1205 uintmax_t f_val;
1207 (void) pathname;
1208 f_val = ((stat_buf->st_size / pred_ptr->args.size.blocksize)
1209 + (stat_buf->st_size % pred_ptr->args.size.blocksize != 0));
1210 switch (pred_ptr->args.size.kind)
1212 case COMP_GT:
1213 if (f_val > pred_ptr->args.size.size)
1214 return (true);
1215 break;
1216 case COMP_LT:
1217 if (f_val < pred_ptr->args.size.size)
1218 return (true);
1219 break;
1220 case COMP_EQ:
1221 if (f_val == pred_ptr->args.size.size)
1222 return (true);
1223 break;
1225 return (false);
1228 boolean
1229 pred_true (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1231 (void) pathname;
1232 (void) stat_buf;
1233 (void) pred_ptr;
1234 return true;
1237 boolean
1238 pred_type (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1240 mode_t mode = stat_buf->st_mode;
1241 mode_t type = pred_ptr->args.type;
1243 (void) pathname;
1245 #ifndef S_IFMT
1246 /* POSIX system; check `mode' the slow way. */
1247 if ((S_ISBLK (mode) && type == S_IFBLK)
1248 || (S_ISCHR (mode) && type == S_IFCHR)
1249 || (S_ISDIR (mode) && type == S_IFDIR)
1250 || (S_ISREG (mode) && type == S_IFREG)
1251 #ifdef S_IFLNK
1252 || (S_ISLNK (mode) && type == S_IFLNK)
1253 #endif
1254 #ifdef S_IFIFO
1255 || (S_ISFIFO (mode) && type == S_IFIFO)
1256 #endif
1257 #ifdef S_IFSOCK
1258 || (S_ISSOCK (mode) && type == S_IFSOCK)
1259 #endif
1260 #ifdef S_IFDOOR
1261 || (S_ISDOOR (mode) && type == S_IFDOOR)
1262 #endif
1264 #else /* S_IFMT */
1265 /* Unix system; check `mode' the fast way. */
1266 if ((mode & S_IFMT) == type)
1267 #endif /* S_IFMT */
1268 return (true);
1269 else
1270 return (false);
1273 boolean
1274 pred_uid (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1276 (void) pathname;
1277 switch (pred_ptr->args.info.kind)
1279 case COMP_GT:
1280 if (stat_buf->st_uid > pred_ptr->args.info.l_val)
1281 return (true);
1282 break;
1283 case COMP_LT:
1284 if (stat_buf->st_uid < pred_ptr->args.info.l_val)
1285 return (true);
1286 break;
1287 case COMP_EQ:
1288 if (stat_buf->st_uid == pred_ptr->args.info.l_val)
1289 return (true);
1290 break;
1292 return (false);
1295 boolean
1296 pred_used (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1298 time_t delta;
1300 (void) pathname;
1301 delta = stat_buf->st_atime - stat_buf->st_ctime; /* Use difftime? */
1302 return pred_timewindow(delta, pred_ptr, DAYSECS);
1305 boolean
1306 pred_user (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1308 (void) pathname;
1309 if (pred_ptr->args.uid == stat_buf->st_uid)
1310 return (true);
1311 else
1312 return (false);
1315 boolean
1316 pred_xtype (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1318 struct stat sbuf; /* local copy, not stat_buf because we're using a different stat method */
1319 int (*ystat) (const char*, struct stat *p);
1321 switch (symlink_handling)
1323 case SYMLINK_ALWAYS_DEREF:
1324 ystat = optionl_stat;
1325 case SYMLINK_DEREF_ARGSONLY:
1326 case SYMLINK_NEVER_DEREF:
1327 ystat = optionp_stat;
1330 if ((*ystat) (rel_pathname, &sbuf) != 0)
1332 if (ystat == optionl_stat && errno == ENOENT)
1334 /* If we failed to follow the symlink,
1335 * fall back on looking at the symlink itself.
1337 /* Mimic behavior of ls -lL. */
1338 return (pred_type (pathname, stat_buf, pred_ptr));
1340 else
1342 error (0, errno, "%s", pathname);
1343 exit_status = 1;
1345 return false;
1347 /* Now that we have our stat() information, query it in the same
1348 * way that -type does.
1350 return (pred_type (pathname, &sbuf, pred_ptr));
1353 /* 1) fork to get a child; parent remembers the child pid
1354 2) child execs the command requested
1355 3) parent waits for child; checks for proper pid of child
1357 Possible returns:
1359 ret errno status(h) status(l)
1361 pid x signal# 0177 stopped
1362 pid x exit arg 0 term by _exit
1363 pid x 0 signal # term by signal
1364 -1 EINTR parent got signal
1365 -1 other some other kind of error
1367 Return true only if the pid matches, status(l) is
1368 zero, and the exit arg (status high) is 0.
1369 Otherwise return false, possibly printing an error message. */
1371 static boolean
1372 launch (struct predicate *pred_ptr)
1374 int status;
1375 pid_t child_pid;
1376 struct exec_val *execp; /* Pointer for efficiency. */
1377 static int first_time = 1;
1379 execp = &pred_ptr->args.exec_vec;
1381 /* Make sure output of command doesn't get mixed with find output. */
1382 fflush (stdout);
1383 fflush (stderr);
1385 /* Make sure to listen for the kids. */
1386 if (first_time)
1388 first_time = 0;
1389 signal (SIGCHLD, SIG_DFL);
1392 child_pid = fork ();
1393 if (child_pid == -1)
1394 error (1, errno, _("cannot fork"));
1395 if (child_pid == 0)
1397 /* We be the child. */
1398 if (starting_desc < 0
1399 ? chdir (starting_dir) != 0
1400 : fchdir (starting_desc) != 0)
1402 error (0, errno, "%s", starting_dir);
1403 _exit (1);
1405 execvp (execp->vec[0], execp->vec);
1406 error (0, errno, "%s", execp->vec[0]);
1407 _exit (1);
1411 while (waitpid (child_pid, &status, 0) == (pid_t) -1)
1412 if (errno != EINTR)
1414 error (0, errno, _("error waiting for %s"), execp->vec[0]);
1415 exit_status = 1;
1416 return false;
1418 if (WIFSIGNALED (status))
1420 error (0, 0, _("%s terminated by signal %d"),
1421 execp->vec[0], WTERMSIG (status));
1422 exit_status = 1;
1423 return (false);
1425 return (!WEXITSTATUS (status));
1428 /* Return a static string formatting the time WHEN according to the
1429 strftime format character KIND. */
1431 static char *
1432 format_date (time_t when, int kind)
1434 static char buf[MAX (LONGEST_HUMAN_READABLE + 2, 64)];
1435 struct tm *tm;
1436 char fmt[6];
1438 fmt[0] = '%';
1439 fmt[1] = kind;
1440 fmt[2] = '\0';
1441 if (kind == '+')
1442 strcpy (fmt, "%F+%T");
1444 if (kind != '@'
1445 && (tm = localtime (&when))
1446 && strftime (buf, sizeof buf, fmt, tm))
1447 return buf;
1448 else
1450 uintmax_t w = when;
1451 char *p = human_readable (when < 0 ? -w : w, buf + 1,
1452 human_ceiling, 1, 1);
1453 if (when < 0)
1454 *--p = '-';
1455 return p;
1459 static char *
1460 ctime_format (when)
1461 time_t when;
1463 char *r = ctime (&when);
1464 if (!r)
1466 /* The time cannot be represented as a struct tm.
1467 Output it as an integer. */
1468 return format_date (when, '@');
1470 else
1472 /* Remove the trailing newline from the ctime output,
1473 being careful not to assume that the output is fixed-width. */
1474 *strchr (r, '\n') = '\0';
1475 return r;
1479 #ifdef DEBUG
1480 /* Return a pointer to the string representation of
1481 the predicate function PRED_FUNC. */
1483 char *
1484 find_pred_name (pred_func)
1485 PFB pred_func;
1487 int i;
1489 for (i = 0; pred_table[i].pred_func != 0; i++)
1490 if (pred_table[i].pred_func == pred_func)
1491 break;
1492 return (pred_table[i].pred_name);
1495 static char *
1496 type_name (type)
1497 short type;
1499 int i;
1501 for (i = 0; type_table[i].type != (short) -1; i++)
1502 if (type_table[i].type == type)
1503 break;
1504 return (type_table[i].type_name);
1507 static char *
1508 prec_name (prec)
1509 short prec;
1511 int i;
1513 for (i = 0; prec_table[i].prec != (short) -1; i++)
1514 if (prec_table[i].prec == prec)
1515 break;
1516 return (prec_table[i].prec_name);
1519 /* Walk the expression tree NODE to stdout.
1520 INDENT is the number of levels to indent the left margin. */
1522 void
1523 print_tree (node, indent)
1524 struct predicate *node;
1525 int indent;
1527 int i;
1529 if (node == NULL)
1530 return;
1531 for (i = 0; i < indent; i++)
1532 printf (" ");
1533 printf ("pred = %s type = %s prec = %s addr = %x\n",
1534 find_pred_name (node->pred_func),
1535 type_name (node->p_type), prec_name (node->p_prec), node);
1536 for (i = 0; i < indent; i++)
1537 printf (" ");
1538 printf (_("left:\n"));
1539 print_tree (node->pred_left, indent + 1);
1540 for (i = 0; i < indent; i++)
1541 printf (" ");
1542 printf (_("right:\n"));
1543 print_tree (node->pred_right, indent + 1);
1546 /* Copy STR into BUF and trim blanks from the end of BUF.
1547 Return BUF. */
1549 static char *
1550 blank_rtrim (str, buf)
1551 char *str;
1552 char *buf;
1554 int i;
1556 if (str == NULL)
1557 return (NULL);
1558 strcpy (buf, str);
1559 i = strlen (buf) - 1;
1560 while ((i >= 0) && ((buf[i] == ' ') || buf[i] == '\t'))
1561 i--;
1562 buf[++i] = '\0';
1563 return (buf);
1566 /* Print out the predicate list starting at NODE. */
1568 void
1569 print_list (node)
1570 struct predicate *node;
1572 struct predicate *cur;
1573 char name[256];
1575 cur = node;
1576 while (cur != NULL)
1578 printf ("%s ", blank_rtrim (find_pred_name (cur->pred_func), name));
1579 cur = cur->pred_next;
1581 printf ("\n");
1583 #endif /* DEBUG */