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)
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,
26 #include "../gnulib/lib/xalloc.h"
27 #include "../gnulib/lib/dirname.h"
28 #include "../gnulib/lib/human.h"
35 # define _(Text) gettext (Text)
40 # define N_(String) gettext_noop (String)
42 /* See locate.c for explanation as to why not use (String) */
43 # define N_(String) String
46 #if !defined(SIGCHLD) && defined(SIGCLD)
47 #define SIGCHLD SIGCLD
52 # define NAMLEN(dirent) strlen((dirent)->d_name)
54 # define dirent direct
55 # define NAMLEN(dirent) (dirent)->d_namlen
57 # include <sys/ndir.h>
68 /* Fake a return value. */
69 #define CLOSEDIR(d) (closedir (d), 0)
71 #define CLOSEDIR(d) closedir (d)
77 /* Get or fake the disk device blocksize.
78 Usually defined by sys/param.h (if at all). */
81 # define DEV_BSIZE BSIZE
83 # define DEV_BSIZE 4096
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
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 */
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)
123 # endif /* not AIX PS/2 */
125 #endif /* HAVE_STRUCT_STAT_ST_BLOCKS */
128 # define ST_NBLOCKS(statbuf) \
129 (S_ISREG ((statbuf).st_mode) \
130 || S_ISDIR ((statbuf).st_mode) \
131 ? (statbuf).st_blocks : 0)
134 #ifndef ST_NBLOCKSIZE
135 # define ST_NBLOCKSIZE 512
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
));
153 struct pred_assoc pred_table
[] =
155 {pred_amin
, "amin "},
157 {pred_anewer
, "anewer "},
158 {pred_atime
, "atime "},
160 {pred_amin
, "cmin "},
161 {pred_cnewer
, "cnewer "},
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 "},
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 "},
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 "},
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 "},
201 {pred_used
, "used "},
202 {pred_user
, "user "},
203 {pred_xtype
, "xtype "},
213 struct op_assoc type_table
[] =
216 {PRIMARY_TYPE
, "primary "},
219 {OPEN_PAREN
, "open_paren "},
220 {CLOSE_PAREN
, "close_paren "},
230 struct prec_assoc prec_table
[] =
233 {COMMA_PREC
, "comma "},
236 {NEGATE_PREC
, "negate "},
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. */
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.
259 pred_timewindow(time_t the_time
, struct predicate
const *pred_ptr
, int window
)
261 switch (pred_ptr
->args
.info
.kind
)
264 if (the_time
> (time_t) pred_ptr
->args
.info
.l_val
)
268 if (the_time
< (time_t) pred_ptr
->args
.info
.l_val
)
272 if ((the_time
>= (time_t) pred_ptr
->args
.info
.l_val
)
273 && (the_time
< (time_t) pred_ptr
->args
.info
.l_val
+ window
))
282 pred_amin (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
285 return pred_timewindow(stat_buf
->st_atime
, pred_ptr
, 60);
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
);
306 return ((*pred_ptr
->pred_right
->pred_func
) (pathname
, stat_buf
,
307 pred_ptr
->pred_right
));
314 pred_anewer (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
318 if (stat_buf
->st_atime
> pred_ptr
->args
.time
)
324 pred_atime (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
327 return pred_timewindow(stat_buf
->st_atime
, pred_ptr
, DAYSECS
);
331 pred_close (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
341 pred_cmin (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
344 return pred_timewindow(stat_buf
->st_ctime
, pred_ptr
, 60);
348 pred_cnewer (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
352 if (stat_buf
->st_ctime
> pred_ptr
->args
.time
)
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
);
375 return ((*pred_ptr
->pred_right
->pred_func
) (pathname
, stat_buf
,
376 pred_ptr
->pred_right
));
380 pred_ctime (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
383 return pred_timewindow(stat_buf
->st_ctime
, pred_ptr
, DAYSECS
);
387 pred_delete (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
391 if (strcmp (rel_pathname
, "."))
393 if (0 != remove (rel_pathname
))
395 error (0, errno
, "cannot delete %s", pathname
);
409 pred_empty (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
414 if (S_ISDIR (stat_buf
->st_mode
))
418 boolean empty
= true;
421 d
= opendir (rel_pathname
);
424 error (0, errno
, "%s", pathname
);
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')))
440 error (0, errno
, "%s", pathname
);
446 else if (S_ISREG (stat_buf
->st_mode
))
447 return (stat_buf
->st_size
== 0);
453 pred_exec (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
457 struct exec_val
*execp
; /* Pointer for efficiency. */
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
;
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
);
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
]);
494 pred_false (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
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
);
513 pred_fprint (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
518 fputs (pathname
, pred_ptr
->args
.stream
);
519 putc ('\n', pred_ptr
->args
.stream
);
524 pred_fprint0 (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
529 fputs (pathname
, pred_ptr
->args
.stream
);
530 putc (0, pred_ptr
->args
.stream
);
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
;
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. */
549 switch (segment
->kind
& 0xff)
552 t
= stat_buf
->st_atime
;
555 t
= stat_buf
->st_ctime
;
558 t
= stat_buf
->st_mtime
;
563 fprintf (fp
, segment
->text
,
564 format_date (t
, (segment
->kind
>> 8) & 0xff));
568 switch (segment
->kind
)
570 case KIND_PLAIN
: /* Plain text string (no % conversion). */
571 fwrite (segment
->text
, 1, segment
->text_len
, fp
);
573 case KIND_STOP
: /* Terminate argument and flush output. */
574 fwrite (segment
->text
, 1, segment
->text_len
, fp
);
577 case 'a': /* atime in `ctime' format. */
578 fprintf (fp
, segment
->text
, ctime_format (stat_buf
->st_atime
));
580 case 'b': /* size in 512-byte blocks */
581 fprintf (fp
, segment
->text
,
582 human_readable ((uintmax_t) ST_NBLOCKS (*stat_buf
),
584 ST_NBLOCKSIZE
, 512));
586 case 'c': /* ctime in `ctime' format */
587 fprintf (fp
, segment
->text
, ctime_format (stat_buf
->st_ctime
));
589 case 'd': /* depth in search tree */
590 fprintf (fp
, segment
->text
, curdepth
);
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));
597 case 'f': /* basename of path */
598 fprintf (fp
, segment
->text
, base_name (pathname
));
600 case 'F': /* filesystem type */
601 fprintf (fp
, segment
->text
,
602 filesystem_type (pathname
, rel_pathname
, stat_buf
));
604 case 'g': /* group name */
608 g
= getgrgid (stat_buf
->st_gid
);
611 segment
->text
[segment
->text_len
] = 's';
612 fprintf (fp
, segment
->text
, g
->gr_name
);
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));
622 case 'h': /* leading directories part of path */
626 cp
= strrchr (pathname
, '/');
627 if (cp
== NULL
) /* No leading directories. */
631 fprintf (fp
, segment
->text
, pathname
);
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
;
644 case 'i': /* inode number */
645 fprintf (fp
, segment
->text
,
646 human_readable ((uintmax_t) stat_buf
->st_ino
, hbuf
,
650 case 'k': /* size in 1K blocks */
651 fprintf (fp
, segment
->text
,
652 human_readable ((uintmax_t) ST_NBLOCKS (*stat_buf
),
654 ST_NBLOCKSIZE
, 1024));
656 case 'l': /* object of symlink */
661 if (S_ISLNK (stat_buf
->st_mode
))
663 linkname
= get_link_name (pathname
, rel_pathname
);
669 fprintf (fp
, segment
->text
, linkname
);
673 fprintf (fp
, segment
->text
, "");
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
);
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
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))));
717 case 'n': /* number of links */
718 fprintf (fp
, segment
->text
,
719 human_readable ((uintmax_t) stat_buf
->st_nlink
,
724 case 'p': /* pathname */
725 fprintf (fp
, segment
->text
, pathname
);
727 case 'P': /* pathname with ARGV element stripped */
730 cp
= pathname
+ path_length
;
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. */
740 fprintf (fp
, segment
->text
, cp
);
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));
747 case 't': /* mtime in `ctime' format */
748 fprintf (fp
, segment
->text
, ctime_format (stat_buf
->st_mtime
));
750 case 'u': /* user name */
754 p
= getpwuid (stat_buf
->st_uid
);
757 segment
->text
[segment
->text_len
] = 's';
758 fprintf (fp
, segment
->text
, p
->pw_name
);
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));
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 */
774 if (S_ISLNK (stat_buf
->st_mode
))
778 ystat
= xstat
== lstat
? stat
: lstat
;
779 if ((*ystat
) (rel_pathname
, &sbuf
) != 0)
781 if ( errno
== ENOENT
) {
782 fprintf (fp
, segment
->text
, "N");
785 if ( errno
== ELOOP
) {
786 fprintf (fp
, segment
->text
, "L");
789 error (0, errno
, "%s", pathname
);
793 stat_buf
->st_mode
= sbuf
.st_mode
;
800 mode_t m
= stat_buf
->st_mode
& S_IFMT
;
802 fprintf (fp
, segment
->text
,
803 ( m
== S_IFSOCK
? "s" :
810 m
== S_IFDOOR
? "D" :
812 m
== S_IFIFO
? "p" : "U" ) );
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)
831 pred_gid (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
835 switch (pred_ptr
->args
.info
.kind
)
838 if (stat_buf
->st_gid
> pred_ptr
->args
.info
.l_val
)
842 if (stat_buf
->st_gid
< pred_ptr
->args
.info
.l_val
)
846 if (stat_buf
->st_gid
== pred_ptr
->args
.info
.l_val
)
854 pred_group (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
858 if (pred_ptr
->args
.gid
== stat_buf
->st_gid
)
865 pred_ilname (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
867 return insert_lname (pathname
, stat_buf
, pred_ptr
, true);
871 pred_iname (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
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)
887 pred_inum (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
891 switch (pred_ptr
->args
.info
.kind
)
894 if (stat_buf
->st_ino
> pred_ptr
->args
.info
.l_val
)
898 if (stat_buf
->st_ino
< pred_ptr
->args
.info
.l_val
)
902 if (stat_buf
->st_ino
== pred_ptr
->args
.info
.l_val
)
910 pred_ipath (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
914 if (fnmatch (pred_ptr
->args
.str
, pathname
, FNM_CASEFOLD
) == 0)
920 pred_links (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
924 switch (pred_ptr
->args
.info
.kind
)
927 if (stat_buf
->st_nlink
> pred_ptr
->args
.info
.l_val
)
931 if (stat_buf
->st_nlink
< pred_ptr
->args
.info
.l_val
)
935 if (stat_buf
->st_nlink
== pred_ptr
->args
.info
.l_val
)
943 pred_lname (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
945 return insert_lname (pathname
, stat_buf
, pred_ptr
, false);
949 insert_lname (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
, boolean ignore_case
)
953 if (S_ISLNK (stat_buf
->st_mode
))
955 char *linkname
= get_link_name (pathname
, rel_pathname
);
958 if (fnmatch (pred_ptr
->args
.str
, linkname
,
959 ignore_case
? FNM_CASEFOLD
: 0) == 0)
969 pred_ls (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
973 list_file (pathname
, rel_pathname
, stat_buf
, start_time
,
974 output_block_size
, stdout
);
979 pred_mmin (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
982 return pred_timewindow(stat_buf
->st_mtime
, pred_ptr
, 60);
986 pred_mtime (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
989 return pred_timewindow(stat_buf
->st_mtime
, pred_ptr
, DAYSECS
);
993 pred_name (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
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)
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
);
1022 return (!(*pred_ptr
->pred_right
->pred_func
) (pathname
, stat_buf
,
1023 pred_ptr
->pred_right
));
1027 pred_newer (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1031 if (stat_buf
->st_mtime
> pred_ptr
->args
.time
)
1037 pred_nogroup (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1043 extern char *gid_unused
;
1045 return gid_unused
[(unsigned) stat_buf
->st_gid
];
1047 return getgrgid (stat_buf
->st_gid
) == NULL
;
1052 pred_nouser (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1055 extern char *uid_unused
;
1062 return uid_unused
[(unsigned) stat_buf
->st_uid
];
1064 return getpwuid (stat_buf
->st_uid
) == NULL
;
1069 pred_ok (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
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
);
1081 return pred_exec (pathname
, stat_buf
, pred_ptr
);
1087 pred_open (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
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
);
1113 return ((*pred_ptr
->pred_right
->pred_func
) (pathname
, stat_buf
,
1114 pred_ptr
->pred_right
));
1121 pred_path (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1124 if (fnmatch (pred_ptr
->args
.str
, pathname
, 0) == 0)
1130 pred_perm (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1133 switch (pred_ptr
->args
.perm
.kind
)
1136 return (stat_buf
->st_mode
& pred_ptr
->args
.perm
.val
) == pred_ptr
->args
.perm
.val
;
1140 return (stat_buf
->st_mode
& pred_ptr
->args
.perm
.val
) != 0;
1144 return (stat_buf
->st_mode
& MODE_ALL
) == pred_ptr
->args
.perm
.val
;
1154 pred_print (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1163 pred_print0 (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1167 fputs (pathname
, stdout
);
1173 pred_prune (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1178 stop_at_current_level
= true;
1179 return (do_dir_first
); /* This is what SunOS find seems to do. */
1183 pred_quit (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1192 pred_regex (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1194 int len
= strlen (pathname
);
1196 if (re_match (pred_ptr
->args
.regex
, pathname
, len
, 0,
1197 (struct re_registers
*) NULL
) == len
)
1203 pred_size (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
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
)
1213 if (f_val
> pred_ptr
->args
.size
.size
)
1217 if (f_val
< pred_ptr
->args
.size
.size
)
1221 if (f_val
== pred_ptr
->args
.size
.size
)
1229 pred_true (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
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
;
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
)
1252 || (S_ISLNK (mode
) && type
== S_IFLNK
)
1255 || (S_ISFIFO (mode
) && type
== S_IFIFO
)
1258 || (S_ISSOCK (mode
) && type
== S_IFSOCK
)
1261 || (S_ISDOOR (mode
) && type
== S_IFDOOR
)
1265 /* Unix system; check `mode' the fast way. */
1266 if ((mode
& S_IFMT
) == type
)
1274 pred_uid (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1277 switch (pred_ptr
->args
.info
.kind
)
1280 if (stat_buf
->st_uid
> pred_ptr
->args
.info
.l_val
)
1284 if (stat_buf
->st_uid
< pred_ptr
->args
.info
.l_val
)
1288 if (stat_buf
->st_uid
== pred_ptr
->args
.info
.l_val
)
1296 pred_used (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1301 delta
= stat_buf
->st_atime
- stat_buf
->st_ctime
; /* Use difftime? */
1302 return pred_timewindow(delta
, pred_ptr
, DAYSECS
);
1306 pred_user (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1309 if (pred_ptr
->args
.uid
== stat_buf
->st_uid
)
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
));
1342 error (0, errno
, "%s", pathname
);
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
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. */
1372 launch (struct predicate
*pred_ptr
)
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. */
1385 /* Make sure to listen for the kids. */
1389 signal (SIGCHLD
, SIG_DFL
);
1392 child_pid
= fork ();
1393 if (child_pid
== -1)
1394 error (1, errno
, _("cannot fork"));
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
);
1405 execvp (execp
->vec
[0], execp
->vec
);
1406 error (0, errno
, "%s", execp
->vec
[0]);
1411 while (waitpid (child_pid
, &status
, 0) == (pid_t
) -1)
1414 error (0, errno
, _("error waiting for %s"), execp
->vec
[0]);
1418 if (WIFSIGNALED (status
))
1420 error (0, 0, _("%s terminated by signal %d"),
1421 execp
->vec
[0], WTERMSIG (status
));
1425 return (!WEXITSTATUS (status
));
1428 /* Return a static string formatting the time WHEN according to the
1429 strftime format character KIND. */
1432 format_date (time_t when
, int kind
)
1434 static char buf
[MAX (LONGEST_HUMAN_READABLE
+ 2, 64)];
1442 strcpy (fmt
, "%F+%T");
1445 && (tm
= localtime (&when
))
1446 && strftime (buf
, sizeof buf
, fmt
, tm
))
1451 char *p
= human_readable (when
< 0 ? -w
: w
, buf
+ 1,
1452 human_ceiling
, 1, 1);
1463 char *r
= ctime (&when
);
1466 /* The time cannot be represented as a struct tm.
1467 Output it as an integer. */
1468 return format_date (when
, '@');
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';
1480 /* Return a pointer to the string representation of
1481 the predicate function PRED_FUNC. */
1484 find_pred_name (pred_func
)
1489 for (i
= 0; pred_table
[i
].pred_func
!= 0; i
++)
1490 if (pred_table
[i
].pred_func
== pred_func
)
1492 return (pred_table
[i
].pred_name
);
1501 for (i
= 0; type_table
[i
].type
!= (short) -1; i
++)
1502 if (type_table
[i
].type
== type
)
1504 return (type_table
[i
].type_name
);
1513 for (i
= 0; prec_table
[i
].prec
!= (short) -1; i
++)
1514 if (prec_table
[i
].prec
== prec
)
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. */
1523 print_tree (node
, indent
)
1524 struct predicate
*node
;
1531 for (i
= 0; i
< indent
; i
++)
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
++)
1538 printf (_("left:\n"));
1539 print_tree (node
->pred_left
, indent
+ 1);
1540 for (i
= 0; i
< indent
; i
++)
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.
1550 blank_rtrim (str
, buf
)
1559 i
= strlen (buf
) - 1;
1560 while ((i
>= 0) && ((buf
[i
] == ' ') || buf
[i
] == '\t'))
1566 /* Print out the predicate list starting at NODE. */
1570 struct predicate
*node
;
1572 struct predicate
*cur
;
1578 printf ("%s ", blank_rtrim (find_pred_name (cur
->pred_func
), name
));
1579 cur
= cur
->pred_next
;