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., 9 Temple Place - Suite 330, Boston, MA 02111-1307,
27 #include "../gnulib/lib/dirname.h"
28 #include "../gnulib/lib/human.h"
34 # define _(Text) gettext (Text)
39 # define N_(String) gettext_noop (String)
41 /* See locate.c for explanation as to why not use (String) */
42 # define N_(String) String
45 #if !defined(SIGCHLD) && defined(SIGCLD)
46 #define SIGCHLD SIGCLD
51 # define NAMLEN(dirent) strlen((dirent)->d_name)
53 # define dirent direct
54 # define NAMLEN(dirent) (dirent)->d_namlen
56 # include <sys/ndir.h>
67 /* Fake a return value. */
68 #define CLOSEDIR(d) (closedir (d), 0)
70 #define CLOSEDIR(d) closedir (d)
76 /* Get or fake the disk device blocksize.
77 Usually defined by sys/param.h (if at all). */
80 # define DEV_BSIZE BSIZE
82 # define DEV_BSIZE 4096
84 #endif /* !DEV_BSIZE */
86 /* Extract or fake data from a `struct stat'.
87 ST_BLKSIZE: Preferred I/O blocksize for the file, in bytes.
88 ST_NBLOCKS: Number of blocks in the file, including indirect blocks.
89 ST_NBLOCKSIZE: Size of blocks used when calculating ST_NBLOCKS. */
90 #ifndef HAVE_STRUCT_STAT_ST_BLOCKS
91 # define ST_BLKSIZE(statbuf) DEV_BSIZE
92 # if defined(_POSIX_SOURCE) || !defined(BSIZE) /* fileblocks.c uses BSIZE. */
93 # define ST_NBLOCKS(statbuf) \
94 (S_ISREG ((statbuf).st_mode) \
95 || S_ISDIR ((statbuf).st_mode) \
96 ? (statbuf).st_size / ST_NBLOCKSIZE + ((statbuf).st_size % ST_NBLOCKSIZE != 0) : 0)
97 # else /* !_POSIX_SOURCE && BSIZE */
98 # define ST_NBLOCKS(statbuf) \
99 (S_ISREG ((statbuf).st_mode) \
100 || S_ISDIR ((statbuf).st_mode) \
101 ? st_blocks ((statbuf).st_size) : 0)
102 # endif /* !_POSIX_SOURCE && BSIZE */
103 #else /* HAVE_STRUCT_STAT_ST_BLOCKS */
104 /* Some systems, like Sequents, return st_blksize of 0 on pipes. */
105 # define ST_BLKSIZE(statbuf) ((statbuf).st_blksize > 0 \
106 ? (statbuf).st_blksize : DEV_BSIZE)
107 # if defined(hpux) || defined(__hpux__) || defined(__hpux)
108 /* HP-UX counts st_blocks in 1024-byte units.
109 This loses when mixing HP-UX and BSD filesystems with NFS. */
110 # define ST_NBLOCKSIZE 1024
112 # if defined(_AIX) && defined(_I386)
113 /* AIX PS/2 counts st_blocks in 4K units. */
114 # define ST_NBLOCKSIZE (4 * 1024)
115 # else /* not AIX PS/2 */
117 # define ST_NBLOCKS(statbuf) \
118 (S_ISREG ((statbuf).st_mode) \
119 || S_ISDIR ((statbuf).st_mode) \
120 ? (statbuf).st_blocks * ST_BLKSIZE(statbuf)/ST_NBLOCKSIZE : 0)
122 # endif /* not AIX PS/2 */
124 #endif /* HAVE_STRUCT_STAT_ST_BLOCKS */
127 # define ST_NBLOCKS(statbuf) \
128 (S_ISREG ((statbuf).st_mode) \
129 || S_ISDIR ((statbuf).st_mode) \
130 ? (statbuf).st_blocks : 0)
133 #ifndef ST_NBLOCKSIZE
134 # define ST_NBLOCKSIZE 512
138 #define MAX(a, b) ((a) > (b) ? (a) : (b))
140 static boolean insert_lname
PARAMS((char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
, boolean ignore_case
));
141 static boolean launch
PARAMS((struct predicate
*pred_ptr
));
142 static char *format_date
PARAMS((time_t when
, int kind
));
143 static char *ctime_format
PARAMS((time_t when
));
152 struct pred_assoc pred_table
[] =
154 {pred_amin
, "amin "},
156 {pred_anewer
, "anewer "},
157 {pred_atime
, "atime "},
159 {pred_amin
, "cmin "},
160 {pred_cnewer
, "cnewer "},
162 {pred_ctime
, "ctime "},
163 {pred_empty
, "empty "},
164 {pred_exec
, "exec "},
165 {pred_false
, "false "},
166 {pred_fprint
, "fprint "},
167 {pred_fprint0
, "fprint0 "},
168 {pred_fprintf
, "fprintf "},
169 {pred_fstype
, "fstype "},
171 {pred_group
, "group "},
172 {pred_ilname
, "ilname "},
173 {pred_iname
, "iname "},
174 {pred_inum
, "inum "},
175 {pred_ipath
, "ipath "},
176 {pred_links
, "links "},
177 {pred_lname
, "lname "},
179 {pred_amin
, "mmin "},
180 {pred_mtime
, "mtime "},
181 {pred_name
, "name "},
182 {pred_negate
, "not "},
183 {pred_newer
, "newer "},
184 {pred_nogroup
, "nogroup "},
185 {pred_nouser
, "nouser "},
189 {pred_path
, "path "},
190 {pred_perm
, "perm "},
191 {pred_print
, "print "},
192 {pred_print0
, "print0 "},
193 {pred_prune
, "prune "},
194 {pred_regex
, "regex "},
195 {pred_size
, "size "},
196 {pred_true
, "true "},
197 {pred_type
, "type "},
199 {pred_used
, "used "},
200 {pred_user
, "user "},
201 {pred_xtype
, "xtype "},
211 struct op_assoc type_table
[] =
214 {PRIMARY_TYPE
, "primary "},
217 {OPEN_PAREN
, "open_paren "},
218 {CLOSE_PAREN
, "close_paren "},
228 struct prec_assoc prec_table
[] =
231 {COMMA_PREC
, "comma "},
234 {NEGATE_PREC
, "negate "},
240 /* Predicate processing routines.
242 PATHNAME is the full pathname of the file being checked.
243 *STAT_BUF contains information about PATHNAME.
244 *PRED_PTR contains information for applying the predicate.
246 Return true if the file passes this predicate, false if not. */
249 pred_amin (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
251 switch (pred_ptr
->args
.info
.kind
)
254 if (stat_buf
->st_atime
> (time_t) pred_ptr
->args
.info
.l_val
)
258 if (stat_buf
->st_atime
< (time_t) pred_ptr
->args
.info
.l_val
)
262 if ((stat_buf
->st_atime
>= (time_t) pred_ptr
->args
.info
.l_val
)
263 && (stat_buf
->st_atime
< (time_t) pred_ptr
->args
.info
.l_val
+ 60))
271 pred_and (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
273 if (pred_ptr
->pred_left
== NULL
274 || (*pred_ptr
->pred_left
->pred_func
) (pathname
, stat_buf
,
275 pred_ptr
->pred_left
))
277 /* Check whether we need a stat here. */
278 if (pred_ptr
->need_stat
)
280 if (!have_stat
&& (*xstat
) (rel_pathname
, stat_buf
) != 0)
282 error (0, errno
, "%s", pathname
);
288 return ((*pred_ptr
->pred_right
->pred_func
) (pathname
, stat_buf
,
289 pred_ptr
->pred_right
));
296 pred_anewer (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
298 if (stat_buf
->st_atime
> pred_ptr
->args
.time
)
304 pred_atime (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
306 switch (pred_ptr
->args
.info
.kind
)
309 if (stat_buf
->st_atime
> (time_t) pred_ptr
->args
.info
.l_val
)
313 if (stat_buf
->st_atime
< (time_t) pred_ptr
->args
.info
.l_val
)
317 if ((stat_buf
->st_atime
>= (time_t) pred_ptr
->args
.info
.l_val
)
318 && (stat_buf
->st_atime
< (time_t) pred_ptr
->args
.info
.l_val
327 pred_close (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
333 pred_cmin (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
335 switch (pred_ptr
->args
.info
.kind
)
338 if (stat_buf
->st_ctime
> (time_t) pred_ptr
->args
.info
.l_val
)
342 if (stat_buf
->st_ctime
< (time_t) pred_ptr
->args
.info
.l_val
)
346 if ((stat_buf
->st_ctime
>= (time_t) pred_ptr
->args
.info
.l_val
)
347 && (stat_buf
->st_ctime
< (time_t) pred_ptr
->args
.info
.l_val
+ 60))
355 pred_cnewer (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
357 if (stat_buf
->st_ctime
> pred_ptr
->args
.time
)
363 pred_comma (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
365 if (pred_ptr
->pred_left
!= NULL
)
366 (*pred_ptr
->pred_left
->pred_func
) (pathname
, stat_buf
,
367 pred_ptr
->pred_left
);
368 /* Check whether we need a stat here. */
369 if (pred_ptr
->need_stat
)
371 if (!have_stat
&& (*xstat
) (rel_pathname
, stat_buf
) != 0)
373 error (0, errno
, "%s", pathname
);
379 return ((*pred_ptr
->pred_right
->pred_func
) (pathname
, stat_buf
,
380 pred_ptr
->pred_right
));
384 pred_ctime (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
386 switch (pred_ptr
->args
.info
.kind
)
389 if (stat_buf
->st_ctime
> (time_t) pred_ptr
->args
.info
.l_val
)
393 if (stat_buf
->st_ctime
< (time_t) pred_ptr
->args
.info
.l_val
)
397 if ((stat_buf
->st_ctime
>= (time_t) pred_ptr
->args
.info
.l_val
)
398 && (stat_buf
->st_ctime
< (time_t) pred_ptr
->args
.info
.l_val
407 pred_empty (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
409 if (S_ISDIR (stat_buf
->st_mode
))
413 boolean empty
= true;
416 d
= opendir (rel_pathname
);
419 error (0, errno
, "%s", pathname
);
423 for (dp
= readdir (d
); dp
; dp
= readdir (d
))
425 if (dp
->d_name
[0] != '.'
426 || (dp
->d_name
[1] != '\0'
427 && (dp
->d_name
[1] != '.' || dp
->d_name
[2] != '\0')))
435 error (0, errno
, "%s", pathname
);
441 else if (S_ISREG (stat_buf
->st_mode
))
442 return (stat_buf
->st_size
== 0);
448 pred_exec (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
452 struct exec_val
*execp
; /* Pointer for efficiency. */
454 execp
= &pred_ptr
->args
.exec_vec
;
456 /* Replace "{}" with the real path in each affected arg. */
457 for (path_pos
= 0; execp
->paths
[path_pos
].offset
>= 0; path_pos
++)
459 register char *from
, *to
;
461 i
= execp
->paths
[path_pos
].offset
;
463 xmalloc (strlen (execp
->paths
[path_pos
].origarg
) + 1
464 + (strlen (pathname
) - 2) * execp
->paths
[path_pos
].count
);
465 for (from
= execp
->paths
[path_pos
].origarg
, to
= execp
->vec
[i
]; *from
; )
466 if (from
[0] == '{' && from
[1] == '}')
468 to
= stpcpy (to
, pathname
);
473 *to
= *from
; /* Copy null. */
476 i
= launch (pred_ptr
);
478 /* Free the temporary args. */
479 for (path_pos
= 0; execp
->paths
[path_pos
].offset
>= 0; path_pos
++)
480 free (execp
->vec
[execp
->paths
[path_pos
].offset
]);
486 pred_false (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
492 pred_fls (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
494 list_file (pathname
, rel_pathname
, stat_buf
, start_time
,
495 output_block_size
, pred_ptr
->args
.stream
);
500 pred_fprint (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
502 fputs (pathname
, pred_ptr
->args
.stream
);
503 putc ('\n', pred_ptr
->args
.stream
);
508 pred_fprint0 (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
510 fputs (pathname
, pred_ptr
->args
.stream
);
511 putc (0, pred_ptr
->args
.stream
);
516 pred_fprintf (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
518 FILE *fp
= pred_ptr
->args
.printf_vec
.stream
;
519 struct segment
*segment
;
521 char hbuf
[LONGEST_HUMAN_READABLE
+ 1];
523 for (segment
= pred_ptr
->args
.printf_vec
.segment
; segment
;
524 segment
= segment
->next
)
526 if (segment
->kind
& 0xff00) /* Component of date. */
530 switch (segment
->kind
& 0xff)
533 t
= stat_buf
->st_atime
;
536 t
= stat_buf
->st_ctime
;
539 t
= stat_buf
->st_mtime
;
544 fprintf (fp
, segment
->text
,
545 format_date (t
, (segment
->kind
>> 8) & 0xff));
549 switch (segment
->kind
)
551 case KIND_PLAIN
: /* Plain text string (no % conversion). */
552 fwrite (segment
->text
, 1, segment
->text_len
, fp
);
554 case KIND_STOP
: /* Terminate argument and flush output. */
555 fwrite (segment
->text
, 1, segment
->text_len
, fp
);
558 case 'a': /* atime in `ctime' format. */
559 fprintf (fp
, segment
->text
, ctime_format (stat_buf
->st_atime
));
561 case 'b': /* size in 512-byte blocks */
562 fprintf (fp
, segment
->text
,
563 human_readable ((uintmax_t) ST_NBLOCKS (*stat_buf
),
565 ST_NBLOCKSIZE
, 512));
567 case 'c': /* ctime in `ctime' format */
568 fprintf (fp
, segment
->text
, ctime_format (stat_buf
->st_ctime
));
570 case 'd': /* depth in search tree */
571 fprintf (fp
, segment
->text
, curdepth
);
573 case 'f': /* basename of path */
574 fprintf (fp
, segment
->text
, base_name (pathname
));
576 case 'F': /* filesystem type */
577 fprintf (fp
, segment
->text
,
578 filesystem_type (pathname
, rel_pathname
, stat_buf
));
580 case 'g': /* group name */
584 g
= getgrgid (stat_buf
->st_gid
);
587 segment
->text
[segment
->text_len
] = 's';
588 fprintf (fp
, segment
->text
, g
->gr_name
);
593 case 'G': /* GID number */
594 fprintf (fp
, segment
->text
,
595 human_readable ((uintmax_t) stat_buf
->st_gid
, hbuf
,
596 human_ceiling
, 1, 1));
598 case 'h': /* leading directories part of path */
602 cp
= strrchr (pathname
, '/');
603 if (cp
== NULL
) /* No leading directories. */
607 fprintf (fp
, segment
->text
, pathname
);
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
;
620 case 'i': /* inode number */
621 fprintf (fp
, segment
->text
,
622 human_readable ((uintmax_t) stat_buf
->st_ino
, hbuf
,
626 case 'k': /* size in 1K blocks */
627 fprintf (fp
, segment
->text
,
628 human_readable ((uintmax_t) ST_NBLOCKS (*stat_buf
),
630 ST_NBLOCKSIZE
, 1024));
632 case 'l': /* object of symlink */
637 if (S_ISLNK (stat_buf
->st_mode
))
639 linkname
= get_link_name (pathname
, rel_pathname
);
645 fprintf (fp
, segment
->text
, linkname
);
649 fprintf (fp
, segment
->text
, "");
653 case 'm': /* mode as octal number (perms only) */
655 /* Output the mode portably using the traditional numbers,
656 even if the host unwisely uses some other numbering
657 scheme. But help the compiler in the common case where
658 the host uses the traditional numbering scheme. */
659 mode_t m
= stat_buf
->st_mode
;
660 boolean traditional_numbering_scheme
=
661 (S_ISUID
== 04000 && S_ISGID
== 02000 && S_ISVTX
== 01000
662 && S_IRUSR
== 00400 && S_IWUSR
== 00200 && S_IXUSR
== 00100
663 && S_IRGRP
== 00040 && S_IWGRP
== 00020 && S_IXGRP
== 00010
664 && S_IROTH
== 00004 && S_IWOTH
== 00002 && S_IXOTH
== 00001);
665 fprintf (fp
, segment
->text
,
666 (traditional_numbering_scheme
668 : ((m
& S_ISUID
? 04000 : 0)
669 | (m
& S_ISGID
? 02000 : 0)
670 | (m
& S_ISVTX
? 01000 : 0)
671 | (m
& S_IRUSR
? 00400 : 0)
672 | (m
& S_IWUSR
? 00200 : 0)
673 | (m
& S_IXUSR
? 00100 : 0)
674 | (m
& S_IRGRP
? 00040 : 0)
675 | (m
& S_IWGRP
? 00020 : 0)
676 | (m
& S_IXGRP
? 00010 : 0)
677 | (m
& S_IROTH
? 00004 : 0)
678 | (m
& S_IWOTH
? 00002 : 0)
679 | (m
& S_IXOTH
? 00001 : 0))));
682 case 'n': /* number of links */
683 fprintf (fp
, segment
->text
,
684 human_readable ((uintmax_t) stat_buf
->st_nlink
,
689 case 'p': /* pathname */
690 fprintf (fp
, segment
->text
, pathname
);
692 case 'P': /* pathname with ARGV element stripped */
695 cp
= pathname
+ path_length
;
697 /* Move past the slash between the ARGV element
698 and the rest of the pathname. But if the ARGV element
699 ends in a slash, we didn't add another, so we've
700 already skipped past it. */
705 fprintf (fp
, segment
->text
, cp
);
707 case 's': /* size in bytes */
708 fprintf (fp
, segment
->text
,
709 human_readable ((uintmax_t) stat_buf
->st_size
,
710 hbuf
, human_ceiling
, 1, 1));
712 case 't': /* mtime in `ctime' format */
713 fprintf (fp
, segment
->text
, ctime_format (stat_buf
->st_mtime
));
715 case 'u': /* user name */
719 p
= getpwuid (stat_buf
->st_uid
);
722 segment
->text
[segment
->text_len
] = 's';
723 fprintf (fp
, segment
->text
, p
->pw_name
);
728 case 'U': /* UID number */
729 fprintf (fp
, segment
->text
,
730 human_readable ((uintmax_t) stat_buf
->st_uid
, hbuf
,
731 human_ceiling
, 1, 1));
739 pred_fstype (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
741 if (strcmp (filesystem_type (pathname
, rel_pathname
, stat_buf
),
742 pred_ptr
->args
.str
) == 0)
748 pred_gid (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
750 switch (pred_ptr
->args
.info
.kind
)
753 if (stat_buf
->st_gid
> pred_ptr
->args
.info
.l_val
)
757 if (stat_buf
->st_gid
< pred_ptr
->args
.info
.l_val
)
761 if (stat_buf
->st_gid
== pred_ptr
->args
.info
.l_val
)
769 pred_group (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
771 if (pred_ptr
->args
.gid
== stat_buf
->st_gid
)
778 pred_ilname (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
780 return insert_lname (pathname
, stat_buf
, pred_ptr
, true);
784 pred_iname (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
788 /* FNM_PERIOD is not used here because POSIX requires that it not be.
789 * See http://standards.ieee.org/reading/ieee/interp/1003-2-92_int/pasc-1003.2-126.html
791 base
= base_name (pathname
);
792 if (fnmatch (pred_ptr
->args
.str
, base
, FNM_CASEFOLD
) == 0)
798 pred_inum (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
800 switch (pred_ptr
->args
.info
.kind
)
803 if (stat_buf
->st_ino
> pred_ptr
->args
.info
.l_val
)
807 if (stat_buf
->st_ino
< pred_ptr
->args
.info
.l_val
)
811 if (stat_buf
->st_ino
== pred_ptr
->args
.info
.l_val
)
819 pred_ipath (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
821 if (fnmatch (pred_ptr
->args
.str
, pathname
, FNM_CASEFOLD
) == 0)
827 pred_links (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
829 switch (pred_ptr
->args
.info
.kind
)
832 if (stat_buf
->st_nlink
> pred_ptr
->args
.info
.l_val
)
836 if (stat_buf
->st_nlink
< pred_ptr
->args
.info
.l_val
)
840 if (stat_buf
->st_nlink
== pred_ptr
->args
.info
.l_val
)
848 pred_lname (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
850 return insert_lname (pathname
, stat_buf
, pred_ptr
, false);
854 insert_lname (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
, boolean ignore_case
)
858 if (S_ISLNK (stat_buf
->st_mode
))
860 char *linkname
= get_link_name (pathname
, rel_pathname
);
863 if (fnmatch (pred_ptr
->args
.str
, linkname
,
864 ignore_case
? FNM_CASEFOLD
: 0) == 0)
874 pred_ls (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
876 list_file (pathname
, rel_pathname
, stat_buf
, start_time
,
877 output_block_size
, stdout
);
882 pred_mmin (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
884 switch (pred_ptr
->args
.info
.kind
)
887 if (stat_buf
->st_mtime
> (time_t) pred_ptr
->args
.info
.l_val
)
891 if (stat_buf
->st_mtime
< (time_t) pred_ptr
->args
.info
.l_val
)
895 if ((stat_buf
->st_mtime
>= (time_t) pred_ptr
->args
.info
.l_val
)
896 && (stat_buf
->st_mtime
< (time_t) pred_ptr
->args
.info
.l_val
+ 60))
904 pred_mtime (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
906 switch (pred_ptr
->args
.info
.kind
)
909 if (stat_buf
->st_mtime
> (time_t) pred_ptr
->args
.info
.l_val
)
913 if (stat_buf
->st_mtime
< (time_t) pred_ptr
->args
.info
.l_val
)
917 if ((stat_buf
->st_mtime
>= (time_t) pred_ptr
->args
.info
.l_val
)
918 && (stat_buf
->st_mtime
< (time_t) pred_ptr
->args
.info
.l_val
927 pred_name (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
931 base
= base_name (pathname
);
933 /* FNM_PERIOD is not used here because POSIX requires that it not be.
934 * See http://standards.ieee.org/reading/ieee/interp/1003-2-92_int/pasc-1003.2-126.html
936 if (fnmatch (pred_ptr
->args
.str
, base
, 0) == 0)
942 pred_negate (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
944 /* Check whether we need a stat here. */
945 if (pred_ptr
->need_stat
)
947 if (!have_stat
&& (*xstat
) (rel_pathname
, stat_buf
) != 0)
949 error (0, errno
, "%s", pathname
);
955 return (!(*pred_ptr
->pred_right
->pred_func
) (pathname
, stat_buf
,
956 pred_ptr
->pred_right
));
960 pred_newer (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
962 if (stat_buf
->st_mtime
> pred_ptr
->args
.time
)
968 pred_nogroup (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
971 extern char *gid_unused
;
973 return gid_unused
[(unsigned) stat_buf
->st_gid
];
975 return getgrgid (stat_buf
->st_gid
) == NULL
;
980 pred_nouser (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
983 extern char *uid_unused
;
985 return uid_unused
[(unsigned) stat_buf
->st_uid
];
987 return getpwuid (stat_buf
->st_uid
) == NULL
;
992 pred_ok (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
995 /* The draft open standard requires that, in the POSIX locale,
996 the last non-blank character of this prompt be '?'.
997 The exact format is not specified.
998 This standard does not have requirements for locales other than POSIX
1000 fprintf (stderr
, _("< %s ... %s > ? "),
1001 pred_ptr
->args
.exec_vec
.vec
[0], pathname
);
1004 return pred_exec (pathname
, stat_buf
, pred_ptr
);
1010 pred_open (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1016 pred_or (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1018 if (pred_ptr
->pred_left
== NULL
1019 || !(*pred_ptr
->pred_left
->pred_func
) (pathname
, stat_buf
,
1020 pred_ptr
->pred_left
))
1022 /* Check whether we need a stat here. */
1023 if (pred_ptr
->need_stat
)
1025 if (!have_stat
&& (*xstat
) (rel_pathname
, stat_buf
) != 0)
1027 error (0, errno
, "%s", pathname
);
1033 return ((*pred_ptr
->pred_right
->pred_func
) (pathname
, stat_buf
,
1034 pred_ptr
->pred_right
));
1041 pred_path (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1043 if (fnmatch (pred_ptr
->args
.str
, pathname
, 0) == 0)
1049 pred_perm (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1051 switch (pred_ptr
->args
.perm
.kind
)
1054 return (stat_buf
->st_mode
& pred_ptr
->args
.perm
.val
) == pred_ptr
->args
.perm
.val
;
1058 return (stat_buf
->st_mode
& pred_ptr
->args
.perm
.val
) != 0;
1062 return (stat_buf
->st_mode
& MODE_ALL
) == pred_ptr
->args
.perm
.val
;
1072 pred_print (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1079 pred_print0 (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1081 fputs (pathname
, stdout
);
1087 pred_prune (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1089 stop_at_current_level
= true;
1090 return (do_dir_first
); /* This is what SunOS find seems to do. */
1094 pred_regex (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1096 int len
= strlen (pathname
);
1097 if (re_match (pred_ptr
->args
.regex
, pathname
, len
, 0,
1098 (struct re_registers
*) NULL
) == len
)
1104 pred_size (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1108 f_val
= ((stat_buf
->st_size
/ pred_ptr
->args
.size
.blocksize
)
1109 + (stat_buf
->st_size
% pred_ptr
->args
.size
.blocksize
!= 0));
1110 switch (pred_ptr
->args
.size
.kind
)
1113 if (f_val
> pred_ptr
->args
.size
.size
)
1117 if (f_val
< pred_ptr
->args
.size
.size
)
1121 if (f_val
== pred_ptr
->args
.size
.size
)
1129 pred_true (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1135 pred_type (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1137 mode_t mode
= stat_buf
->st_mode
;
1138 mode_t type
= pred_ptr
->args
.type
;
1141 /* POSIX system; check `mode' the slow way. */
1142 if ((S_ISBLK (mode
) && type
== S_IFBLK
)
1143 || (S_ISCHR (mode
) && type
== S_IFCHR
)
1144 || (S_ISDIR (mode
) && type
== S_IFDIR
)
1145 || (S_ISREG (mode
) && type
== S_IFREG
)
1147 || (S_ISLNK (mode
) && type
== S_IFLNK
)
1150 || (S_ISFIFO (mode
) && type
== S_IFIFO
)
1153 || (S_ISSOCK (mode
) && type
== S_IFSOCK
)
1156 || (S_ISDOOR (mode
) && type
== S_IFDOOR
)
1160 /* Unix system; check `mode' the fast way. */
1161 if ((mode
& S_IFMT
) == type
)
1169 pred_uid (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1171 switch (pred_ptr
->args
.info
.kind
)
1174 if (stat_buf
->st_uid
> pred_ptr
->args
.info
.l_val
)
1178 if (stat_buf
->st_uid
< pred_ptr
->args
.info
.l_val
)
1182 if (stat_buf
->st_uid
== pred_ptr
->args
.info
.l_val
)
1190 pred_used (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1194 delta
= stat_buf
->st_atime
- stat_buf
->st_ctime
; /* Use difftime? */
1195 switch (pred_ptr
->args
.info
.kind
)
1198 if (delta
> (time_t) pred_ptr
->args
.info
.l_val
)
1202 if (delta
< (time_t) pred_ptr
->args
.info
.l_val
)
1206 if ((delta
>= (time_t) pred_ptr
->args
.info
.l_val
)
1207 && (delta
< (time_t) pred_ptr
->args
.info
.l_val
+ DAYSECS
))
1215 pred_user (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1217 if (pred_ptr
->args
.uid
== stat_buf
->st_uid
)
1224 pred_xtype (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1229 ystat
= xstat
== lstat
? stat
: lstat
;
1230 if ((*ystat
) (rel_pathname
, &sbuf
) != 0)
1232 if (ystat
== stat
&& errno
== ENOENT
)
1233 /* Mimic behavior of ls -lL. */
1234 return (pred_type (pathname
, stat_buf
, pred_ptr
));
1235 error (0, errno
, "%s", pathname
);
1239 return (pred_type (pathname
, &sbuf
, pred_ptr
));
1242 /* 1) fork to get a child; parent remembers the child pid
1243 2) child execs the command requested
1244 3) parent waits for child; checks for proper pid of child
1248 ret errno status(h) status(l)
1250 pid x signal# 0177 stopped
1251 pid x exit arg 0 term by _exit
1252 pid x 0 signal # term by signal
1253 -1 EINTR parent got signal
1254 -1 other some other kind of error
1256 Return true only if the pid matches, status(l) is
1257 zero, and the exit arg (status high) is 0.
1258 Otherwise return false, possibly printing an error message. */
1261 launch (struct predicate
*pred_ptr
)
1265 struct exec_val
*execp
; /* Pointer for efficiency. */
1266 static int first_time
= 1;
1268 execp
= &pred_ptr
->args
.exec_vec
;
1270 /* Make sure output of command doesn't get mixed with find output. */
1274 /* Make sure to listen for the kids. */
1278 signal (SIGCHLD
, SIG_DFL
);
1281 child_pid
= fork ();
1282 if (child_pid
== -1)
1283 error (1, errno
, _("cannot fork"));
1286 /* We be the child. */
1287 if (starting_desc
< 0
1288 ? chdir (starting_dir
) != 0
1289 : fchdir (starting_desc
) != 0)
1291 error (0, errno
, "%s", starting_dir
);
1294 execvp (execp
->vec
[0], execp
->vec
);
1295 error (0, errno
, "%s", execp
->vec
[0]);
1300 while (waitpid (child_pid
, &status
, 0) == (pid_t
) -1)
1303 error (0, errno
, _("error waiting for %s"), execp
->vec
[0]);
1307 if (WIFSIGNALED (status
))
1309 error (0, 0, _("%s terminated by signal %d"),
1310 execp
->vec
[0], WTERMSIG (status
));
1314 return (!WEXITSTATUS (status
));
1317 /* Return a static string formatting the time WHEN according to the
1318 strftime format character KIND. */
1321 format_date (time_t when
, int kind
)
1323 static char buf
[MAX (LONGEST_HUMAN_READABLE
+ 2, 64)];
1332 && (tm
= localtime (&when
))
1333 && strftime (buf
, sizeof buf
, fmt
, tm
))
1338 char *p
= human_readable (when
< 0 ? -w
: w
, buf
+ 1,
1339 human_ceiling
, 1, 1);
1350 char *r
= ctime (&when
);
1353 /* The time cannot be represented as a struct tm.
1354 Output it as an integer. */
1355 return format_date (when
, '@');
1359 /* Remove the trailing newline from the ctime output,
1360 being careful not to assume that the output is fixed-width. */
1361 *strchr (r
, '\n') = '\0';
1367 /* Return a pointer to the string representation of
1368 the predicate function PRED_FUNC. */
1371 find_pred_name (pred_func
)
1376 for (i
= 0; pred_table
[i
].pred_func
!= 0; i
++)
1377 if (pred_table
[i
].pred_func
== pred_func
)
1379 return (pred_table
[i
].pred_name
);
1388 for (i
= 0; type_table
[i
].type
!= (short) -1; i
++)
1389 if (type_table
[i
].type
== type
)
1391 return (type_table
[i
].type_name
);
1400 for (i
= 0; prec_table
[i
].prec
!= (short) -1; i
++)
1401 if (prec_table
[i
].prec
== prec
)
1403 return (prec_table
[i
].prec_name
);
1406 /* Walk the expression tree NODE to stdout.
1407 INDENT is the number of levels to indent the left margin. */
1410 print_tree (node
, indent
)
1411 struct predicate
*node
;
1418 for (i
= 0; i
< indent
; i
++)
1420 printf ("pred = %s type = %s prec = %s addr = %x\n",
1421 find_pred_name (node
->pred_func
),
1422 type_name (node
->p_type
), prec_name (node
->p_prec
), node
);
1423 for (i
= 0; i
< indent
; i
++)
1425 printf (_("left:\n"));
1426 print_tree (node
->pred_left
, indent
+ 1);
1427 for (i
= 0; i
< indent
; i
++)
1429 printf (_("right:\n"));
1430 print_tree (node
->pred_right
, indent
+ 1);
1433 /* Copy STR into BUF and trim blanks from the end of BUF.
1437 blank_rtrim (str
, buf
)
1446 i
= strlen (buf
) - 1;
1447 while ((i
>= 0) && ((buf
[i
] == ' ') || buf
[i
] == '\t'))
1453 /* Print out the predicate list starting at NODE. */
1457 struct predicate
*node
;
1459 struct predicate
*cur
;
1465 printf ("%s ", blank_rtrim (find_pred_name (cur
->pred_func
), name
));
1466 cur
= cur
->pred_next
;