1 /* pred.c -- execute the expression tree.
2 Copyright (C) 1990, 91, 92, 93, 94, 2000 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
32 # define _(Text) gettext (Text)
37 # define N_(String) gettext_noop (String)
39 # define N_(String) (String)
42 #if !defined(SIGCHLD) && defined(SIGCLD)
43 #define SIGCHLD SIGCLD
48 # define NAMLEN(dirent) strlen((dirent)->d_name)
50 # define dirent direct
51 # define NAMLEN(dirent) (dirent)->d_namlen
53 # include <sys/ndir.h>
64 /* Fake a return value. */
65 #define CLOSEDIR(d) (closedir (d), 0)
67 #define CLOSEDIR(d) closedir (d)
71 /* Get or fake the disk device blocksize.
72 Usually defined by sys/param.h (if at all). */
75 # define DEV_BSIZE BSIZE
77 # define DEV_BSIZE 4096
79 #endif /* !DEV_BSIZE */
81 /* Extract or fake data from a `struct stat'.
82 ST_BLKSIZE: Preferred I/O blocksize for the file, in bytes.
83 ST_NBLOCKS: Number of blocks in the file, including indirect blocks.
84 ST_NBLOCKSIZE: Size of blocks used when calculating ST_NBLOCKS. */
85 #ifndef HAVE_STRUCT_STAT_ST_BLOCKS
86 # define ST_BLKSIZE(statbuf) DEV_BSIZE
87 # if defined(_POSIX_SOURCE) || !defined(BSIZE) /* fileblocks.c uses BSIZE. */
88 # define ST_NBLOCKS(statbuf) \
89 (S_ISREG ((statbuf).st_mode) \
90 || S_ISDIR ((statbuf).st_mode) \
91 ? (statbuf).st_size / ST_NBLOCKSIZE + ((statbuf).st_size % ST_NBLOCKSIZE != 0) : 0)
92 # else /* !_POSIX_SOURCE && BSIZE */
93 # define ST_NBLOCKS(statbuf) \
94 (S_ISREG ((statbuf).st_mode) \
95 || S_ISDIR ((statbuf).st_mode) \
96 ? st_blocks ((statbuf).st_size) : 0)
97 # endif /* !_POSIX_SOURCE && BSIZE */
98 #else /* HAVE_STRUCT_STAT_ST_BLOCKS */
99 /* Some systems, like Sequents, return st_blksize of 0 on pipes. */
100 # define ST_BLKSIZE(statbuf) ((statbuf).st_blksize > 0 \
101 ? (statbuf).st_blksize : DEV_BSIZE)
102 # if defined(hpux) || defined(__hpux__) || defined(__hpux)
103 /* HP-UX counts st_blocks in 1024-byte units.
104 This loses when mixing HP-UX and BSD filesystems with NFS. */
105 # define ST_NBLOCKSIZE 1024
107 # if defined(_AIX) && defined(_I386)
108 /* AIX PS/2 counts st_blocks in 4K units. */
109 # define ST_NBLOCKSIZE (4 * 1024)
110 # else /* not AIX PS/2 */
112 # define ST_NBLOCKS(statbuf) \
113 (S_ISREG ((statbuf).st_mode) \
114 || S_ISDIR ((statbuf).st_mode) \
115 ? (statbuf).st_blocks * ST_BLKSIZE(statbuf)/ST_NBLOCKSIZE : 0)
117 # endif /* not AIX PS/2 */
119 #endif /* HAVE_STRUCT_STAT_ST_BLOCKS */
122 # define ST_NBLOCKS(statbuf) \
123 (S_ISREG ((statbuf).st_mode) \
124 || S_ISDIR ((statbuf).st_mode) \
125 ? (statbuf).st_blocks : 0)
128 #ifndef ST_NBLOCKSIZE
129 # define ST_NBLOCKSIZE 512
133 #define MAX(a, b) ((a) > (b) ? (a) : (b))
135 static boolean insert_lname
PARAMS((char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
, boolean ignore_case
));
136 static boolean launch
PARAMS((struct predicate
*pred_ptr
));
137 static char *format_date
PARAMS((time_t when
, int kind
));
138 static char *ctime_format
PARAMS((time_t when
));
147 struct pred_assoc pred_table
[] =
149 {pred_amin
, "amin "},
151 {pred_anewer
, "anewer "},
152 {pred_atime
, "atime "},
154 {pred_amin
, "cmin "},
155 {pred_cnewer
, "cnewer "},
157 {pred_ctime
, "ctime "},
158 {pred_empty
, "empty "},
159 {pred_exec
, "exec "},
160 {pred_false
, "false "},
161 {pred_fprint
, "fprint "},
162 {pred_fprint0
, "fprint0 "},
163 {pred_fprintf
, "fprintf "},
164 {pred_fstype
, "fstype "},
166 {pred_group
, "group "},
167 {pred_ilname
, "ilname "},
168 {pred_iname
, "iname "},
169 {pred_inum
, "inum "},
170 {pred_ipath
, "ipath "},
171 {pred_links
, "links "},
172 {pred_lname
, "lname "},
174 {pred_amin
, "mmin "},
175 {pred_mtime
, "mtime "},
176 {pred_name
, "name "},
177 {pred_negate
, "not "},
178 {pred_newer
, "newer "},
179 {pred_nogroup
, "nogroup "},
180 {pred_nouser
, "nouser "},
184 {pred_path
, "path "},
185 {pred_perm
, "perm "},
186 {pred_print
, "print "},
187 {pred_print0
, "print0 "},
188 {pred_prune
, "prune "},
189 {pred_regex
, "regex "},
190 {pred_size
, "size "},
191 {pred_true
, "true "},
192 {pred_type
, "type "},
194 {pred_used
, "used "},
195 {pred_user
, "user "},
196 {pred_xtype
, "xtype "},
206 struct op_assoc type_table
[] =
209 {PRIMARY_TYPE
, "primary "},
212 {OPEN_PAREN
, "open_paren "},
213 {CLOSE_PAREN
, "close_paren "},
223 struct prec_assoc prec_table
[] =
226 {COMMA_PREC
, "comma "},
229 {NEGATE_PREC
, "negate "},
235 /* Predicate processing routines.
237 PATHNAME is the full pathname of the file being checked.
238 *STAT_BUF contains information about PATHNAME.
239 *PRED_PTR contains information for applying the predicate.
241 Return true if the file passes this predicate, false if not. */
244 pred_amin (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
246 switch (pred_ptr
->args
.info
.kind
)
249 if (stat_buf
->st_atime
> (time_t) pred_ptr
->args
.info
.l_val
)
253 if (stat_buf
->st_atime
< (time_t) pred_ptr
->args
.info
.l_val
)
257 if ((stat_buf
->st_atime
>= (time_t) pred_ptr
->args
.info
.l_val
)
258 && (stat_buf
->st_atime
< (time_t) pred_ptr
->args
.info
.l_val
+ 60))
266 pred_and (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
268 if (pred_ptr
->pred_left
== NULL
269 || (*pred_ptr
->pred_left
->pred_func
) (pathname
, stat_buf
,
270 pred_ptr
->pred_left
))
272 /* Check whether we need a stat here. */
273 if (pred_ptr
->need_stat
)
275 if (!have_stat
&& (*xstat
) (rel_pathname
, stat_buf
) != 0)
277 error (0, errno
, "%s", pathname
);
283 return ((*pred_ptr
->pred_right
->pred_func
) (pathname
, stat_buf
,
284 pred_ptr
->pred_right
));
291 pred_anewer (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
293 if (stat_buf
->st_atime
> pred_ptr
->args
.time
)
299 pred_atime (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
301 switch (pred_ptr
->args
.info
.kind
)
304 if (stat_buf
->st_atime
> (time_t) pred_ptr
->args
.info
.l_val
)
308 if (stat_buf
->st_atime
< (time_t) pred_ptr
->args
.info
.l_val
)
312 if ((stat_buf
->st_atime
>= (time_t) pred_ptr
->args
.info
.l_val
)
313 && (stat_buf
->st_atime
< (time_t) pred_ptr
->args
.info
.l_val
322 pred_close (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
328 pred_cmin (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
330 switch (pred_ptr
->args
.info
.kind
)
333 if (stat_buf
->st_ctime
> (time_t) pred_ptr
->args
.info
.l_val
)
337 if (stat_buf
->st_ctime
< (time_t) pred_ptr
->args
.info
.l_val
)
341 if ((stat_buf
->st_ctime
>= (time_t) pred_ptr
->args
.info
.l_val
)
342 && (stat_buf
->st_ctime
< (time_t) pred_ptr
->args
.info
.l_val
+ 60))
350 pred_cnewer (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
352 if (stat_buf
->st_ctime
> pred_ptr
->args
.time
)
358 pred_comma (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
360 if (pred_ptr
->pred_left
!= NULL
)
361 (*pred_ptr
->pred_left
->pred_func
) (pathname
, stat_buf
,
362 pred_ptr
->pred_left
);
363 /* Check whether we need a stat here. */
364 if (pred_ptr
->need_stat
)
366 if (!have_stat
&& (*xstat
) (rel_pathname
, stat_buf
) != 0)
368 error (0, errno
, "%s", pathname
);
374 return ((*pred_ptr
->pred_right
->pred_func
) (pathname
, stat_buf
,
375 pred_ptr
->pred_right
));
379 pred_ctime (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
381 switch (pred_ptr
->args
.info
.kind
)
384 if (stat_buf
->st_ctime
> (time_t) pred_ptr
->args
.info
.l_val
)
388 if (stat_buf
->st_ctime
< (time_t) pred_ptr
->args
.info
.l_val
)
392 if ((stat_buf
->st_ctime
>= (time_t) pred_ptr
->args
.info
.l_val
)
393 && (stat_buf
->st_ctime
< (time_t) pred_ptr
->args
.info
.l_val
402 pred_empty (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
404 if (S_ISDIR (stat_buf
->st_mode
))
408 boolean empty
= true;
411 d
= opendir (rel_pathname
);
414 error (0, errno
, "%s", pathname
);
418 for (dp
= readdir (d
); dp
; dp
= readdir (d
))
420 if (dp
->d_name
[0] != '.'
421 || (dp
->d_name
[1] != '\0'
422 && (dp
->d_name
[1] != '.' || dp
->d_name
[2] != '\0')))
430 error (0, errno
, "%s", pathname
);
436 else if (S_ISREG (stat_buf
->st_mode
))
437 return (stat_buf
->st_size
== 0);
443 pred_exec (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
447 struct exec_val
*execp
; /* Pointer for efficiency. */
449 execp
= &pred_ptr
->args
.exec_vec
;
451 /* Replace "{}" with the real path in each affected arg. */
452 for (path_pos
= 0; execp
->paths
[path_pos
].offset
>= 0; path_pos
++)
454 register char *from
, *to
;
456 i
= execp
->paths
[path_pos
].offset
;
458 xmalloc (strlen (execp
->paths
[path_pos
].origarg
) + 1
459 + (strlen (pathname
) - 2) * execp
->paths
[path_pos
].count
);
460 for (from
= execp
->paths
[path_pos
].origarg
, to
= execp
->vec
[i
]; *from
; )
461 if (from
[0] == '{' && from
[1] == '}')
463 to
= stpcpy (to
, pathname
);
468 *to
= *from
; /* Copy null. */
471 i
= launch (pred_ptr
);
473 /* Free the temporary args. */
474 for (path_pos
= 0; execp
->paths
[path_pos
].offset
>= 0; path_pos
++)
475 free (execp
->vec
[execp
->paths
[path_pos
].offset
]);
481 pred_false (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
487 pred_fls (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
489 list_file (pathname
, rel_pathname
, stat_buf
, start_time
,
490 output_block_size
, pred_ptr
->args
.stream
);
495 pred_fprint (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
497 fputs (pathname
, pred_ptr
->args
.stream
);
498 putc ('\n', pred_ptr
->args
.stream
);
503 pred_fprint0 (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
505 fputs (pathname
, pred_ptr
->args
.stream
);
506 putc (0, pred_ptr
->args
.stream
);
511 pred_fprintf (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
513 FILE *fp
= pred_ptr
->args
.printf_vec
.stream
;
514 struct segment
*segment
;
516 char hbuf
[LONGEST_HUMAN_READABLE
+ 1];
518 for (segment
= pred_ptr
->args
.printf_vec
.segment
; segment
;
519 segment
= segment
->next
)
521 if (segment
->kind
& 0xff00) /* Component of date. */
525 switch (segment
->kind
& 0xff)
528 t
= stat_buf
->st_atime
;
531 t
= stat_buf
->st_ctime
;
534 t
= stat_buf
->st_mtime
;
539 fprintf (fp
, segment
->text
,
540 format_date (t
, (segment
->kind
>> 8) & 0xff));
544 switch (segment
->kind
)
546 case KIND_PLAIN
: /* Plain text string (no % conversion). */
547 fwrite (segment
->text
, 1, segment
->text_len
, fp
);
549 case KIND_STOP
: /* Terminate argument and flush output. */
550 fwrite (segment
->text
, 1, segment
->text_len
, fp
);
553 case 'a': /* atime in `ctime' format. */
554 fprintf (fp
, segment
->text
, ctime_format (stat_buf
->st_atime
));
556 case 'b': /* size in 512-byte blocks */
557 fprintf (fp
, segment
->text
,
558 human_readable ((uintmax_t) ST_NBLOCKS (*stat_buf
),
559 hbuf
, ST_NBLOCKSIZE
, 512));
561 case 'c': /* ctime in `ctime' format */
562 fprintf (fp
, segment
->text
, ctime_format (stat_buf
->st_ctime
));
564 case 'd': /* depth in search tree */
565 fprintf (fp
, segment
->text
, curdepth
);
567 case 'f': /* basename of path */
568 fprintf (fp
, segment
->text
, base_name (pathname
));
570 case 'F': /* filesystem type */
571 fprintf (fp
, segment
->text
,
572 filesystem_type (pathname
, rel_pathname
, stat_buf
));
574 case 'g': /* group name */
578 g
= getgrgid (stat_buf
->st_gid
);
581 segment
->text
[segment
->text_len
] = 's';
582 fprintf (fp
, segment
->text
, g
->gr_name
);
587 case 'G': /* GID number */
588 fprintf (fp
, segment
->text
,
589 human_readable ((uintmax_t) stat_buf
->st_gid
, hbuf
, 1, 1));
591 case 'h': /* leading directories part of path */
595 cp
= strrchr (pathname
, '/');
596 if (cp
== NULL
) /* No leading directories. */
600 fprintf (fp
, segment
->text
, pathname
);
604 case 'H': /* ARGV element file was found under */
606 char cc
= pathname
[path_length
];
608 pathname
[path_length
] = '\0';
609 fprintf (fp
, segment
->text
, pathname
);
610 pathname
[path_length
] = cc
;
613 case 'i': /* inode number */
614 fprintf (fp
, segment
->text
,
615 human_readable ((uintmax_t) stat_buf
->st_ino
, hbuf
, 1, 1));
617 case 'k': /* size in 1K blocks */
618 fprintf (fp
, segment
->text
,
619 human_readable ((uintmax_t) ST_NBLOCKS (*stat_buf
),
620 hbuf
, ST_NBLOCKSIZE
, 1024));
622 case 'l': /* object of symlink */
627 if (S_ISLNK (stat_buf
->st_mode
))
629 linkname
= get_link_name (pathname
, rel_pathname
);
635 fprintf (fp
, segment
->text
, linkname
);
639 fprintf (fp
, segment
->text
, "");
643 case 'm': /* mode as octal number (perms only) */
645 /* Output the mode portably using the traditional numbers,
646 even if the host unwisely uses some other numbering
647 scheme. But help the compiler in the common case where
648 the host uses the traditional numbering scheme. */
649 mode_t m
= stat_buf
->st_mode
;
650 boolean traditional_numbering_scheme
=
651 (S_ISUID
== 04000 && S_ISGID
== 02000 && S_ISVTX
== 01000
652 && S_IRUSR
== 00400 && S_IWUSR
== 00200 && S_IXUSR
== 00100
653 && S_IRGRP
== 00040 && S_IWGRP
== 00020 && S_IXGRP
== 00010
654 && S_IROTH
== 00004 && S_IWOTH
== 00002 && S_IXOTH
== 00001);
655 fprintf (fp
, segment
->text
,
656 (traditional_numbering_scheme
658 : ((m
& S_ISUID
? 04000 : 0)
659 | (m
& S_ISGID
? 02000 : 0)
660 | (m
& S_ISVTX
? 01000 : 0)
661 | (m
& S_IRUSR
? 00400 : 0)
662 | (m
& S_IWUSR
? 00200 : 0)
663 | (m
& S_IXUSR
? 00100 : 0)
664 | (m
& S_IRGRP
? 00040 : 0)
665 | (m
& S_IWGRP
? 00020 : 0)
666 | (m
& S_IXGRP
? 00010 : 0)
667 | (m
& S_IROTH
? 00004 : 0)
668 | (m
& S_IWOTH
? 00002 : 0)
669 | (m
& S_IXOTH
? 00001 : 0))));
672 case 'n': /* number of links */
673 fprintf (fp
, segment
->text
,
674 human_readable ((uintmax_t) stat_buf
->st_nlink
,
677 case 'p': /* pathname */
678 fprintf (fp
, segment
->text
, pathname
);
680 case 'P': /* pathname with ARGV element stripped */
683 cp
= pathname
+ path_length
;
685 /* Move past the slash between the ARGV element
686 and the rest of the pathname. But if the ARGV element
687 ends in a slash, we didn't add another, so we've
688 already skipped past it. */
693 fprintf (fp
, segment
->text
, cp
);
695 case 's': /* size in bytes */
696 fprintf (fp
, segment
->text
,
697 human_readable ((uintmax_t) stat_buf
->st_size
,
700 case 't': /* mtime in `ctime' format */
701 fprintf (fp
, segment
->text
, ctime_format (stat_buf
->st_mtime
));
703 case 'u': /* user name */
707 p
= getpwuid (stat_buf
->st_uid
);
710 segment
->text
[segment
->text_len
] = 's';
711 fprintf (fp
, segment
->text
, p
->pw_name
);
716 case 'U': /* UID number */
717 fprintf (fp
, segment
->text
,
718 human_readable ((uintmax_t) stat_buf
->st_uid
, hbuf
, 1, 1));
726 pred_fstype (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
728 if (strcmp (filesystem_type (pathname
, rel_pathname
, stat_buf
),
729 pred_ptr
->args
.str
) == 0)
735 pred_gid (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
737 switch (pred_ptr
->args
.info
.kind
)
740 if (stat_buf
->st_gid
> pred_ptr
->args
.info
.l_val
)
744 if (stat_buf
->st_gid
< pred_ptr
->args
.info
.l_val
)
748 if (stat_buf
->st_gid
== pred_ptr
->args
.info
.l_val
)
756 pred_group (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
758 if (pred_ptr
->args
.gid
== stat_buf
->st_gid
)
765 pred_ilname (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
767 return insert_lname (pathname
, stat_buf
, pred_ptr
, true);
771 pred_iname (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
775 base
= base_name (pathname
);
776 if (fnmatch (pred_ptr
->args
.str
, base
, FNM_PERIOD
| FNM_CASEFOLD
) == 0)
782 pred_inum (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
784 switch (pred_ptr
->args
.info
.kind
)
787 if (stat_buf
->st_ino
> pred_ptr
->args
.info
.l_val
)
791 if (stat_buf
->st_ino
< pred_ptr
->args
.info
.l_val
)
795 if (stat_buf
->st_ino
== pred_ptr
->args
.info
.l_val
)
803 pred_ipath (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
805 if (fnmatch (pred_ptr
->args
.str
, pathname
, FNM_CASEFOLD
) == 0)
811 pred_links (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
813 switch (pred_ptr
->args
.info
.kind
)
816 if (stat_buf
->st_nlink
> pred_ptr
->args
.info
.l_val
)
820 if (stat_buf
->st_nlink
< pred_ptr
->args
.info
.l_val
)
824 if (stat_buf
->st_nlink
== pred_ptr
->args
.info
.l_val
)
832 pred_lname (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
834 return insert_lname (pathname
, stat_buf
, pred_ptr
, false);
838 insert_lname (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
, boolean ignore_case
)
842 if (S_ISLNK (stat_buf
->st_mode
))
844 char *linkname
= get_link_name (pathname
, rel_pathname
);
847 if (fnmatch (pred_ptr
->args
.str
, linkname
,
848 ignore_case
? FNM_CASEFOLD
: 0) == 0)
858 pred_ls (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
860 list_file (pathname
, rel_pathname
, stat_buf
, start_time
,
861 output_block_size
, stdout
);
866 pred_mmin (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
868 switch (pred_ptr
->args
.info
.kind
)
871 if (stat_buf
->st_mtime
> (time_t) pred_ptr
->args
.info
.l_val
)
875 if (stat_buf
->st_mtime
< (time_t) pred_ptr
->args
.info
.l_val
)
879 if ((stat_buf
->st_mtime
>= (time_t) pred_ptr
->args
.info
.l_val
)
880 && (stat_buf
->st_mtime
< (time_t) pred_ptr
->args
.info
.l_val
+ 60))
888 pred_mtime (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
890 switch (pred_ptr
->args
.info
.kind
)
893 if (stat_buf
->st_mtime
> (time_t) pred_ptr
->args
.info
.l_val
)
897 if (stat_buf
->st_mtime
< (time_t) pred_ptr
->args
.info
.l_val
)
901 if ((stat_buf
->st_mtime
>= (time_t) pred_ptr
->args
.info
.l_val
)
902 && (stat_buf
->st_mtime
< (time_t) pred_ptr
->args
.info
.l_val
911 pred_name (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
915 base
= base_name (pathname
);
916 if (fnmatch (pred_ptr
->args
.str
, base
, FNM_PERIOD
) == 0)
922 pred_negate (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
924 /* Check whether we need a stat here. */
925 if (pred_ptr
->need_stat
)
927 if (!have_stat
&& (*xstat
) (rel_pathname
, stat_buf
) != 0)
929 error (0, errno
, "%s", pathname
);
935 return (!(*pred_ptr
->pred_right
->pred_func
) (pathname
, stat_buf
,
936 pred_ptr
->pred_right
));
940 pred_newer (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
942 if (stat_buf
->st_mtime
> pred_ptr
->args
.time
)
948 pred_nogroup (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
951 extern char *gid_unused
;
953 return gid_unused
[(unsigned) stat_buf
->st_gid
];
955 return getgrgid (stat_buf
->st_gid
) == NULL
;
960 pred_nouser (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
963 extern char *uid_unused
;
965 return uid_unused
[(unsigned) stat_buf
->st_uid
];
967 return getpwuid (stat_buf
->st_uid
) == NULL
;
972 pred_ok (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
977 /* The draft open standard requires that, in the POSIX locale,
978 the last non-blank character of this prompt be '?'.
979 The exact format is not specified.
980 This standard does not have requirements for locales other than POSIX
982 fprintf (stderr
, _("< %s ... %s > ? "),
983 pred_ptr
->args
.exec_vec
.vec
[0], pathname
);
986 yes
= (i
== 'y' || i
== 'Y');
987 while (i
!= EOF
&& i
!= '\n')
991 return pred_exec (pathname
, stat_buf
, pred_ptr
);
995 pred_open (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1001 pred_or (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1003 if (pred_ptr
->pred_left
== NULL
1004 || !(*pred_ptr
->pred_left
->pred_func
) (pathname
, stat_buf
,
1005 pred_ptr
->pred_left
))
1007 /* Check whether we need a stat here. */
1008 if (pred_ptr
->need_stat
)
1010 if (!have_stat
&& (*xstat
) (rel_pathname
, stat_buf
) != 0)
1012 error (0, errno
, "%s", pathname
);
1018 return ((*pred_ptr
->pred_right
->pred_func
) (pathname
, stat_buf
,
1019 pred_ptr
->pred_right
));
1026 pred_path (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1028 if (fnmatch (pred_ptr
->args
.str
, pathname
, 0) == 0)
1034 pred_perm (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1036 switch (pred_ptr
->args
.perm
.kind
)
1039 return (~stat_buf
->st_mode
& pred_ptr
->args
.perm
.val
) != 0;
1042 return (stat_buf
->st_mode
& pred_ptr
->args
.perm
.val
) != 0;
1045 return (stat_buf
->st_mode
& MODE_ALL
) == pred_ptr
->args
.perm
.val
;
1053 pred_print (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1060 pred_print0 (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1062 fputs (pathname
, stdout
);
1068 pred_prune (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1070 stop_at_current_level
= true;
1071 return (do_dir_first
); /* This is what SunOS find seems to do. */
1075 pred_regex (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1077 int len
= strlen (pathname
);
1078 if (re_match (pred_ptr
->args
.regex
, pathname
, len
, 0,
1079 (struct re_registers
*) NULL
) == len
)
1085 pred_size (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1089 f_val
= ((stat_buf
->st_size
/ pred_ptr
->args
.size
.blocksize
)
1090 + (stat_buf
->st_size
% pred_ptr
->args
.size
.blocksize
!= 0));
1091 switch (pred_ptr
->args
.size
.kind
)
1094 if (f_val
> pred_ptr
->args
.size
.size
)
1098 if (f_val
< pred_ptr
->args
.size
.size
)
1102 if (f_val
== pred_ptr
->args
.size
.size
)
1110 pred_true (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1116 pred_type (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1118 mode_t mode
= stat_buf
->st_mode
;
1119 mode_t type
= pred_ptr
->args
.type
;
1122 /* POSIX system; check `mode' the slow way. */
1123 if ((S_ISBLK (mode
) && type
== S_IFBLK
)
1124 || (S_ISCHR (mode
) && type
== S_IFCHR
)
1125 || (S_ISDIR (mode
) && type
== S_IFDIR
)
1126 || (S_ISREG (mode
) && type
== S_IFREG
)
1128 || (S_ISLNK (mode
) && type
== S_IFLNK
)
1131 || (S_ISFIFO (mode
) && type
== S_IFIFO
)
1134 || (S_ISSOCK (mode
) && type
== S_IFSOCK
)
1138 /* Unix system; check `mode' the fast way. */
1139 if ((mode
& S_IFMT
) == type
)
1147 pred_uid (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1149 switch (pred_ptr
->args
.info
.kind
)
1152 if (stat_buf
->st_uid
> pred_ptr
->args
.info
.l_val
)
1156 if (stat_buf
->st_uid
< pred_ptr
->args
.info
.l_val
)
1160 if (stat_buf
->st_uid
== pred_ptr
->args
.info
.l_val
)
1168 pred_used (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1172 delta
= stat_buf
->st_atime
- stat_buf
->st_ctime
; /* Use difftime? */
1173 switch (pred_ptr
->args
.info
.kind
)
1176 if (delta
> (time_t) pred_ptr
->args
.info
.l_val
)
1180 if (delta
< (time_t) pred_ptr
->args
.info
.l_val
)
1184 if ((delta
>= (time_t) pred_ptr
->args
.info
.l_val
)
1185 && (delta
< (time_t) pred_ptr
->args
.info
.l_val
+ DAYSECS
))
1193 pred_user (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1195 if (pred_ptr
->args
.uid
== stat_buf
->st_uid
)
1202 pred_xtype (char *pathname
, struct stat
*stat_buf
, struct predicate
*pred_ptr
)
1207 ystat
= xstat
== lstat
? stat
: lstat
;
1208 if ((*ystat
) (rel_pathname
, &sbuf
) != 0)
1210 if (ystat
== stat
&& errno
== ENOENT
)
1211 /* Mimic behavior of ls -lL. */
1212 return (pred_type (pathname
, stat_buf
, pred_ptr
));
1213 error (0, errno
, "%s", pathname
);
1217 return (pred_type (pathname
, &sbuf
, pred_ptr
));
1220 /* 1) fork to get a child; parent remembers the child pid
1221 2) child execs the command requested
1222 3) parent waits for child; checks for proper pid of child
1226 ret errno status(h) status(l)
1228 pid x signal# 0177 stopped
1229 pid x exit arg 0 term by _exit
1230 pid x 0 signal # term by signal
1231 -1 EINTR parent got signal
1232 -1 other some other kind of error
1234 Return true only if the pid matches, status(l) is
1235 zero, and the exit arg (status high) is 0.
1236 Otherwise return false, possibly printing an error message. */
1239 launch (struct predicate
*pred_ptr
)
1243 struct exec_val
*execp
; /* Pointer for efficiency. */
1244 static int first_time
= 1;
1246 execp
= &pred_ptr
->args
.exec_vec
;
1248 /* Make sure output of command doesn't get mixed with find output. */
1252 /* Make sure to listen for the kids. */
1256 signal (SIGCHLD
, SIG_DFL
);
1259 child_pid
= fork ();
1260 if (child_pid
== -1)
1261 error (1, errno
, _("cannot fork"));
1264 /* We be the child. */
1266 if (chdir (starting_dir
) < 0)
1268 error (0, errno
, "%s", starting_dir
);
1272 if (fchdir (starting_desc
) < 0)
1274 error (0, errno
, _("cannot return to starting directory"));
1278 execvp (execp
->vec
[0], execp
->vec
);
1279 error (0, errno
, "%s", execp
->vec
[0]);
1284 while (waitpid (child_pid
, &status
, 0) == (pid_t
) -1)
1287 error (0, errno
, _("error waiting for %s"), execp
->vec
[0]);
1291 if (WIFSIGNALED (status
))
1293 error (0, 0, _("%s terminated by signal %d"),
1294 execp
->vec
[0], WTERMSIG (status
));
1298 return (!WEXITSTATUS (status
));
1301 /* Return a static string formatting the time WHEN according to the
1302 strftime format character KIND. */
1305 format_date (time_t when
, int kind
)
1307 static char buf
[MAX (LONGEST_HUMAN_READABLE
+ 2, 64)];
1316 && (tm
= localtime (&when
))
1317 && strftime (buf
, sizeof buf
, fmt
, tm
))
1322 char *p
= human_readable (when
< 0 ? -w
: w
, buf
+ 1, 1, 1);
1333 char *r
= ctime (&when
);
1336 /* The time cannot be represented as a struct tm.
1337 Output it as an integer. */
1338 return format_date (when
, '@');
1342 /* Remove the trailing newline from the ctime output,
1343 being careful not to assume that the output is fixed-width. */
1344 *strchr (r
, '\n') = '\0';
1350 /* Return a pointer to the string representation of
1351 the predicate function PRED_FUNC. */
1354 find_pred_name (pred_func
)
1359 for (i
= 0; pred_table
[i
].pred_func
!= 0; i
++)
1360 if (pred_table
[i
].pred_func
== pred_func
)
1362 return (pred_table
[i
].pred_name
);
1371 for (i
= 0; type_table
[i
].type
!= (short) -1; i
++)
1372 if (type_table
[i
].type
== type
)
1374 return (type_table
[i
].type_name
);
1383 for (i
= 0; prec_table
[i
].prec
!= (short) -1; i
++)
1384 if (prec_table
[i
].prec
== prec
)
1386 return (prec_table
[i
].prec_name
);
1389 /* Walk the expression tree NODE to stdout.
1390 INDENT is the number of levels to indent the left margin. */
1393 print_tree (node
, indent
)
1394 struct predicate
*node
;
1401 for (i
= 0; i
< indent
; i
++)
1403 printf ("pred = %s type = %s prec = %s addr = %x\n",
1404 find_pred_name (node
->pred_func
),
1405 type_name (node
->p_type
), prec_name (node
->p_prec
), node
);
1406 for (i
= 0; i
< indent
; i
++)
1408 printf (_("left:\n"));
1409 print_tree (node
->pred_left
, indent
+ 1);
1410 for (i
= 0; i
< indent
; i
++)
1412 printf (_("right:\n"));
1413 print_tree (node
->pred_right
, indent
+ 1);
1416 /* Copy STR into BUF and trim blanks from the end of BUF.
1420 blank_rtrim (str
, buf
)
1429 i
= strlen (buf
) - 1;
1430 while ((i
>= 0) && ((buf
[i
] == ' ') || buf
[i
] == '\t'))
1436 /* Print out the predicate list starting at NODE. */
1440 struct predicate
*node
;
1442 struct predicate
*cur
;
1448 printf ("%s ", blank_rtrim (find_pred_name (cur
->pred_func
), name
));
1449 cur
= cur
->pred_next
;