1 | /* pred.c -- execute the expression tree.
|
---|
2 | Copyright (C) 1990, 1991, 1992, 1993, 1994, 2000, 2003,
|
---|
3 | 2004, 2005 Free Software Foundation, Inc.
|
---|
4 |
|
---|
5 | This program is free software; you can redistribute it and/or modify
|
---|
6 | it under the terms of the GNU General Public License as published by
|
---|
7 | the Free Software Foundation; either version 2, or (at your option)
|
---|
8 | any later version.
|
---|
9 |
|
---|
10 | This program is distributed in the hope that it will be useful,
|
---|
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
13 | GNU General Public License for more details.
|
---|
14 |
|
---|
15 | You should have received a copy of the GNU General Public License
|
---|
16 | along with this program; if not, write to the Free Software
|
---|
17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
---|
18 | USA.
|
---|
19 | */
|
---|
20 |
|
---|
21 | #include "defs.h"
|
---|
22 |
|
---|
23 | #include <fnmatch.h>
|
---|
24 | #include <signal.h>
|
---|
25 | #include <pwd.h>
|
---|
26 | #include <grp.h>
|
---|
27 | #include <sys/types.h>
|
---|
28 | #include <sys/stat.h>
|
---|
29 | #include <assert.h>
|
---|
30 | #include <fcntl.h>
|
---|
31 | #include "xalloc.h"
|
---|
32 | #include "dirname.h"
|
---|
33 | #include "human.h"
|
---|
34 | #include "modetype.h"
|
---|
35 | #include "filemode.h"
|
---|
36 | #include "wait.h"
|
---|
37 | #include "printquoted.h"
|
---|
38 | #include "buildcmd.h"
|
---|
39 | #include "yesno.h"
|
---|
40 | #include "listfile.h"
|
---|
41 |
|
---|
42 | #if ENABLE_NLS
|
---|
43 | # include <libintl.h>
|
---|
44 | # define _(Text) gettext (Text)
|
---|
45 | #else
|
---|
46 | # define _(Text) Text
|
---|
47 | #endif
|
---|
48 | #ifdef gettext_noop
|
---|
49 | # define N_(String) gettext_noop (String)
|
---|
50 | #else
|
---|
51 | /* See locate.c for explanation as to why not use (String) */
|
---|
52 | # define N_(String) String
|
---|
53 | #endif
|
---|
54 |
|
---|
55 | #if !defined(SIGCHLD) && defined(SIGCLD)
|
---|
56 | #define SIGCHLD SIGCLD
|
---|
57 | #endif
|
---|
58 |
|
---|
59 |
|
---|
60 |
|
---|
61 | #if HAVE_DIRENT_H
|
---|
62 | # include <dirent.h>
|
---|
63 | # define NAMLEN(dirent) strlen((dirent)->d_name)
|
---|
64 | #else
|
---|
65 | # define dirent direct
|
---|
66 | # define NAMLEN(dirent) (dirent)->d_namlen
|
---|
67 | # if HAVE_SYS_NDIR_H
|
---|
68 | # include <sys/ndir.h>
|
---|
69 | # endif
|
---|
70 | # if HAVE_SYS_DIR_H
|
---|
71 | # include <sys/dir.h>
|
---|
72 | # endif
|
---|
73 | # if HAVE_NDIR_H
|
---|
74 | # include <ndir.h>
|
---|
75 | # endif
|
---|
76 | #endif
|
---|
77 |
|
---|
78 | #ifdef CLOSEDIR_VOID
|
---|
79 | /* Fake a return value. */
|
---|
80 | #define CLOSEDIR(d) (closedir (d), 0)
|
---|
81 | #else
|
---|
82 | #define CLOSEDIR(d) closedir (d)
|
---|
83 | #endif
|
---|
84 |
|
---|
85 |
|
---|
86 |
|
---|
87 |
|
---|
88 | /* Get or fake the disk device blocksize.
|
---|
89 | Usually defined by sys/param.h (if at all). */
|
---|
90 | #ifndef DEV_BSIZE
|
---|
91 | # ifdef BSIZE
|
---|
92 | # define DEV_BSIZE BSIZE
|
---|
93 | # else /* !BSIZE */
|
---|
94 | # define DEV_BSIZE 4096
|
---|
95 | # endif /* !BSIZE */
|
---|
96 | #endif /* !DEV_BSIZE */
|
---|
97 |
|
---|
98 | /* Extract or fake data from a `struct stat'.
|
---|
99 | ST_BLKSIZE: Preferred I/O blocksize for the file, in bytes.
|
---|
100 | ST_NBLOCKS: Number of blocks in the file, including indirect blocks.
|
---|
101 | ST_NBLOCKSIZE: Size of blocks used when calculating ST_NBLOCKS. */
|
---|
102 | #ifndef HAVE_STRUCT_STAT_ST_BLOCKS
|
---|
103 | # define ST_BLKSIZE(statbuf) DEV_BSIZE
|
---|
104 | # if defined(_POSIX_SOURCE) || !defined(BSIZE) /* fileblocks.c uses BSIZE. */
|
---|
105 | # define ST_NBLOCKS(statbuf) \
|
---|
106 | (S_ISREG ((statbuf).st_mode) \
|
---|
107 | || S_ISDIR ((statbuf).st_mode) \
|
---|
108 | ? (statbuf).st_size / ST_NBLOCKSIZE + ((statbuf).st_size % ST_NBLOCKSIZE != 0) : 0)
|
---|
109 | # else /* !_POSIX_SOURCE && BSIZE */
|
---|
110 | # define ST_NBLOCKS(statbuf) \
|
---|
111 | (S_ISREG ((statbuf).st_mode) \
|
---|
112 | || S_ISDIR ((statbuf).st_mode) \
|
---|
113 | ? st_blocks ((statbuf).st_size) : 0)
|
---|
114 | # endif /* !_POSIX_SOURCE && BSIZE */
|
---|
115 | #else /* HAVE_STRUCT_STAT_ST_BLOCKS */
|
---|
116 | /* Some systems, like Sequents, return st_blksize of 0 on pipes. */
|
---|
117 | # define ST_BLKSIZE(statbuf) ((statbuf).st_blksize > 0 \
|
---|
118 | ? (statbuf).st_blksize : DEV_BSIZE)
|
---|
119 | # if defined(hpux) || defined(__hpux__) || defined(__hpux)
|
---|
120 | /* HP-UX counts st_blocks in 1024-byte units.
|
---|
121 | This loses when mixing HP-UX and BSD filesystems with NFS. */
|
---|
122 | # define ST_NBLOCKSIZE 1024
|
---|
123 | # else /* !hpux */
|
---|
124 | # if defined(_AIX) && defined(_I386)
|
---|
125 | /* AIX PS/2 counts st_blocks in 4K units. */
|
---|
126 | # define ST_NBLOCKSIZE (4 * 1024)
|
---|
127 | # else /* not AIX PS/2 */
|
---|
128 | # if defined(_CRAY)
|
---|
129 | # define ST_NBLOCKS(statbuf) \
|
---|
130 | (S_ISREG ((statbuf).st_mode) \
|
---|
131 | || S_ISDIR ((statbuf).st_mode) \
|
---|
132 | ? (statbuf).st_blocks * ST_BLKSIZE(statbuf)/ST_NBLOCKSIZE : 0)
|
---|
133 | # endif /* _CRAY */
|
---|
134 | # endif /* not AIX PS/2 */
|
---|
135 | # endif /* !hpux */
|
---|
136 | #endif /* HAVE_STRUCT_STAT_ST_BLOCKS */
|
---|
137 |
|
---|
138 | #ifndef ST_NBLOCKS
|
---|
139 | # define ST_NBLOCKS(statbuf) \
|
---|
140 | (S_ISREG ((statbuf).st_mode) \
|
---|
141 | || S_ISDIR ((statbuf).st_mode) \
|
---|
142 | ? (statbuf).st_blocks : 0)
|
---|
143 | #endif
|
---|
144 |
|
---|
145 | #ifndef ST_NBLOCKSIZE
|
---|
146 | # define ST_NBLOCKSIZE 512
|
---|
147 | #endif
|
---|
148 |
|
---|
149 |
|
---|
150 | #undef MAX
|
---|
151 | #define MAX(a, b) ((a) > (b) ? (a) : (b))
|
---|
152 |
|
---|
153 | static boolean match_lname PARAMS((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr, boolean ignore_case));
|
---|
154 |
|
---|
155 | static char *format_date PARAMS((time_t when, int kind));
|
---|
156 | static char *ctime_format PARAMS((time_t when));
|
---|
157 |
|
---|
158 | #ifdef DEBUG
|
---|
159 | struct pred_assoc
|
---|
160 | {
|
---|
161 | PRED_FUNC pred_func;
|
---|
162 | char *pred_name;
|
---|
163 | };
|
---|
164 |
|
---|
165 | struct pred_assoc pred_table[] =
|
---|
166 | {
|
---|
167 | {pred_amin, "amin "},
|
---|
168 | {pred_and, "and "},
|
---|
169 | {pred_anewer, "anewer "},
|
---|
170 | {pred_atime, "atime "},
|
---|
171 | {pred_close, ") "},
|
---|
172 | {pred_cmin, "cmin "},
|
---|
173 | {pred_cnewer, "cnewer "},
|
---|
174 | {pred_comma, ", "},
|
---|
175 | {pred_ctime, "ctime "},
|
---|
176 | {pred_delete, "delete "},
|
---|
177 | {pred_empty, "empty "},
|
---|
178 | {pred_exec, "exec "},
|
---|
179 | {pred_execdir, "execdir "},
|
---|
180 | {pred_executable, "executable "},
|
---|
181 | {pred_false, "false "},
|
---|
182 | {pred_fprint, "fprint "},
|
---|
183 | {pred_fprint0, "fprint0 "},
|
---|
184 | {pred_fprintf, "fprintf "},
|
---|
185 | {pred_fstype, "fstype "},
|
---|
186 | {pred_gid, "gid "},
|
---|
187 | {pred_group, "group "},
|
---|
188 | {pred_ilname, "ilname "},
|
---|
189 | {pred_iname, "iname "},
|
---|
190 | {pred_inum, "inum "},
|
---|
191 | {pred_ipath, "ipath "},
|
---|
192 | {pred_links, "links "},
|
---|
193 | {pred_lname, "lname "},
|
---|
194 | {pred_ls, "ls "},
|
---|
195 | {pred_mmin, "mmin "},
|
---|
196 | {pred_mtime, "mtime "},
|
---|
197 | {pred_name, "name "},
|
---|
198 | {pred_negate, "not "},
|
---|
199 | {pred_newer, "newer "},
|
---|
200 | {pred_nogroup, "nogroup "},
|
---|
201 | {pred_nouser, "nouser "},
|
---|
202 | {pred_ok, "ok "},
|
---|
203 | {pred_okdir, "okdir "},
|
---|
204 | {pred_open, "( "},
|
---|
205 | {pred_or, "or "},
|
---|
206 | {pred_path, "path "},
|
---|
207 | {pred_perm, "perm "},
|
---|
208 | {pred_print, "print "},
|
---|
209 | {pred_print0, "print0 "},
|
---|
210 | {pred_prune, "prune "},
|
---|
211 | {pred_quit, "quit "},
|
---|
212 | {pred_readable, "readable "},
|
---|
213 | {pred_regex, "regex "},
|
---|
214 | {pred_samefile,"samefile "},
|
---|
215 | {pred_size, "size "},
|
---|
216 | {pred_true, "true "},
|
---|
217 | {pred_type, "type "},
|
---|
218 | {pred_uid, "uid "},
|
---|
219 | {pred_used, "used "},
|
---|
220 | {pred_user, "user "},
|
---|
221 | {pred_writable, "writable "},
|
---|
222 | {pred_xtype, "xtype "},
|
---|
223 | {0, "none "}
|
---|
224 | };
|
---|
225 | #endif
|
---|
226 | |
---|
227 |
|
---|
228 | /* Predicate processing routines.
|
---|
229 |
|
---|
230 | PATHNAME is the full pathname of the file being checked.
|
---|
231 | *STAT_BUF contains information about PATHNAME.
|
---|
232 | *PRED_PTR contains information for applying the predicate.
|
---|
233 |
|
---|
234 | Return true if the file passes this predicate, false if not. */
|
---|
235 |
|
---|
236 |
|
---|
237 | /* pred_timewindow
|
---|
238 | *
|
---|
239 | * Returns true if THE_TIME is
|
---|
240 | * COMP_GT: after the specified time
|
---|
241 | * COMP_LT: before the specified time
|
---|
242 | * COMP_EQ: less than WINDOW seconds after the specified time.
|
---|
243 | */
|
---|
244 | static boolean
|
---|
245 | pred_timewindow(time_t the_time, struct predicate const *pred_ptr, int window)
|
---|
246 | {
|
---|
247 | switch (pred_ptr->args.info.kind)
|
---|
248 | {
|
---|
249 | case COMP_GT:
|
---|
250 | if (the_time > (time_t) pred_ptr->args.info.l_val)
|
---|
251 | return true;
|
---|
252 | break;
|
---|
253 | case COMP_LT:
|
---|
254 | if (the_time < (time_t) pred_ptr->args.info.l_val)
|
---|
255 | return true;
|
---|
256 | break;
|
---|
257 | case COMP_EQ:
|
---|
258 | if ((the_time >= (time_t) pred_ptr->args.info.l_val)
|
---|
259 | && (the_time < (time_t) pred_ptr->args.info.l_val + window))
|
---|
260 | return true;
|
---|
261 | break;
|
---|
262 | }
|
---|
263 | return false;
|
---|
264 | }
|
---|
265 |
|
---|
266 |
|
---|
267 | boolean
|
---|
268 | pred_amin (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
269 | {
|
---|
270 | (void) &pathname;
|
---|
271 | return pred_timewindow(stat_buf->st_atime, pred_ptr, 60);
|
---|
272 | }
|
---|
273 |
|
---|
274 | boolean
|
---|
275 | pred_and (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
276 | {
|
---|
277 | if (pred_ptr->pred_left == NULL
|
---|
278 | || (*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
|
---|
279 | pred_ptr->pred_left))
|
---|
280 | {
|
---|
281 | /* Check whether we need a stat here. */
|
---|
282 | if (get_info(pathname, state.rel_pathname, stat_buf, pred_ptr) != 0)
|
---|
283 | return false;
|
---|
284 | return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
|
---|
285 | pred_ptr->pred_right));
|
---|
286 | }
|
---|
287 | else
|
---|
288 | return (false);
|
---|
289 | }
|
---|
290 |
|
---|
291 | boolean
|
---|
292 | pred_anewer (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
293 | {
|
---|
294 | (void) &pathname;
|
---|
295 |
|
---|
296 | if (stat_buf->st_atime > pred_ptr->args.time)
|
---|
297 | return (true);
|
---|
298 | return (false);
|
---|
299 | }
|
---|
300 |
|
---|
301 | boolean
|
---|
302 | pred_atime (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
303 | {
|
---|
304 | (void) &pathname;
|
---|
305 | return pred_timewindow(stat_buf->st_atime, pred_ptr, DAYSECS);
|
---|
306 | }
|
---|
307 |
|
---|
308 | boolean
|
---|
309 | pred_close (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
310 | {
|
---|
311 | (void) &pathname;
|
---|
312 | (void) &stat_buf;
|
---|
313 | (void) &pred_ptr;
|
---|
314 |
|
---|
315 | return true;
|
---|
316 | }
|
---|
317 |
|
---|
318 | boolean
|
---|
319 | pred_cmin (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
320 | {
|
---|
321 | (void) pathname;
|
---|
322 | return pred_timewindow(stat_buf->st_ctime, pred_ptr, 60);
|
---|
323 | }
|
---|
324 |
|
---|
325 | boolean
|
---|
326 | pred_cnewer (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
327 | {
|
---|
328 | (void) pathname;
|
---|
329 |
|
---|
330 | if (stat_buf->st_ctime > pred_ptr->args.time)
|
---|
331 | return true;
|
---|
332 | else
|
---|
333 | return false;
|
---|
334 | }
|
---|
335 |
|
---|
336 | boolean
|
---|
337 | pred_comma (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
338 | {
|
---|
339 | if (pred_ptr->pred_left != NULL)
|
---|
340 | (*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
|
---|
341 | pred_ptr->pred_left);
|
---|
342 | /* Check whether we need a stat here. */
|
---|
343 | /* TODO: what about need_type? */
|
---|
344 | if (get_info(pathname, state.rel_pathname, stat_buf, pred_ptr) != 0)
|
---|
345 | return false;
|
---|
346 | return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
|
---|
347 | pred_ptr->pred_right));
|
---|
348 | }
|
---|
349 |
|
---|
350 | boolean
|
---|
351 | pred_ctime (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
352 | {
|
---|
353 | (void) &pathname;
|
---|
354 | return pred_timewindow(stat_buf->st_ctime, pred_ptr, DAYSECS);
|
---|
355 | }
|
---|
356 |
|
---|
357 | boolean
|
---|
358 | pred_delete (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
359 | {
|
---|
360 | (void) pred_ptr;
|
---|
361 | (void) stat_buf;
|
---|
362 | if (strcmp (state.rel_pathname, "."))
|
---|
363 | {
|
---|
364 | if (0 != remove (state.rel_pathname))
|
---|
365 | {
|
---|
366 | error (0, errno, "cannot delete %s", pathname);
|
---|
367 | return false;
|
---|
368 | }
|
---|
369 | else
|
---|
370 | {
|
---|
371 | return true;
|
---|
372 | }
|
---|
373 | }
|
---|
374 |
|
---|
375 | /* nothing to do. */
|
---|
376 | return true;
|
---|
377 | }
|
---|
378 |
|
---|
379 | boolean
|
---|
380 | pred_empty (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
381 | {
|
---|
382 | (void) pathname;
|
---|
383 | (void) pred_ptr;
|
---|
384 |
|
---|
385 | if (S_ISDIR (stat_buf->st_mode))
|
---|
386 | {
|
---|
387 | DIR *d;
|
---|
388 | struct dirent *dp;
|
---|
389 | boolean empty = true;
|
---|
390 |
|
---|
391 | errno = 0;
|
---|
392 | d = opendir (state.rel_pathname);
|
---|
393 | if (d == NULL)
|
---|
394 | {
|
---|
395 | error (0, errno, "%s", pathname);
|
---|
396 | state.exit_status = 1;
|
---|
397 | return false;
|
---|
398 | }
|
---|
399 | for (dp = readdir (d); dp; dp = readdir (d))
|
---|
400 | {
|
---|
401 | if (dp->d_name[0] != '.'
|
---|
402 | || (dp->d_name[1] != '\0'
|
---|
403 | && (dp->d_name[1] != '.' || dp->d_name[2] != '\0')))
|
---|
404 | {
|
---|
405 | empty = false;
|
---|
406 | break;
|
---|
407 | }
|
---|
408 | }
|
---|
409 | if (CLOSEDIR (d))
|
---|
410 | {
|
---|
411 | error (0, errno, "%s", pathname);
|
---|
412 | state.exit_status = 1;
|
---|
413 | return false;
|
---|
414 | }
|
---|
415 | return (empty);
|
---|
416 | }
|
---|
417 | else if (S_ISREG (stat_buf->st_mode))
|
---|
418 | return (stat_buf->st_size == 0);
|
---|
419 | else
|
---|
420 | return (false);
|
---|
421 | }
|
---|
422 |
|
---|
423 | static boolean
|
---|
424 | new_impl_pred_exec (const char *pathname, struct stat *stat_buf,
|
---|
425 | struct predicate *pred_ptr,
|
---|
426 | const char *prefix, size_t pfxlen)
|
---|
427 | {
|
---|
428 | struct exec_val *execp = &pred_ptr->args.exec_vec;
|
---|
429 | size_t len = strlen(pathname);
|
---|
430 |
|
---|
431 | (void) stat_buf;
|
---|
432 |
|
---|
433 | if (execp->multiple)
|
---|
434 | {
|
---|
435 | /* Push the argument onto the current list.
|
---|
436 | * The command may or may not be run at this point,
|
---|
437 | * depending on the command line length limits.
|
---|
438 | */
|
---|
439 | bc_push_arg(&execp->ctl,
|
---|
440 | &execp->state,
|
---|
441 | pathname, len+1,
|
---|
442 | prefix, pfxlen,
|
---|
443 | 0);
|
---|
444 |
|
---|
445 | /* POSIX: If the primary expression is punctuated by a plus
|
---|
446 | * sign, the primary shall always evaluate as true
|
---|
447 | */
|
---|
448 | return true;
|
---|
449 | }
|
---|
450 | else
|
---|
451 | {
|
---|
452 | int i;
|
---|
453 |
|
---|
454 | for (i=0; i<execp->num_args; ++i)
|
---|
455 | {
|
---|
456 | bc_do_insert(&execp->ctl,
|
---|
457 | &execp->state,
|
---|
458 | execp->replace_vec[i],
|
---|
459 | strlen(execp->replace_vec[i]),
|
---|
460 | prefix, pfxlen,
|
---|
461 | pathname, len,
|
---|
462 | 0);
|
---|
463 | }
|
---|
464 |
|
---|
465 | /* Actually invoke the command. */
|
---|
466 | return execp->ctl.exec_callback(&execp->ctl,
|
---|
467 | &execp->state);
|
---|
468 | }
|
---|
469 | }
|
---|
470 |
|
---|
471 |
|
---|
472 | boolean
|
---|
473 | pred_exec (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
474 | {
|
---|
475 | return new_impl_pred_exec(pathname, stat_buf, pred_ptr, NULL, 0);
|
---|
476 | }
|
---|
477 |
|
---|
478 | boolean
|
---|
479 | pred_execdir (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
480 | {
|
---|
481 | const char *prefix = (state.rel_pathname[0] == '/') ? NULL : "./";
|
---|
482 | (void) &pathname;
|
---|
483 | return new_impl_pred_exec (state.rel_pathname, stat_buf, pred_ptr,
|
---|
484 | prefix, (prefix ? 2 : 0));
|
---|
485 | }
|
---|
486 |
|
---|
487 | boolean
|
---|
488 | pred_false (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
489 | {
|
---|
490 | (void) &pathname;
|
---|
491 | (void) &stat_buf;
|
---|
492 | (void) &pred_ptr;
|
---|
493 |
|
---|
494 |
|
---|
495 | return (false);
|
---|
496 | }
|
---|
497 |
|
---|
498 | boolean
|
---|
499 | pred_fls (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
500 | {
|
---|
501 | list_file (pathname, state.rel_pathname, stat_buf, options.start_time,
|
---|
502 | options.output_block_size,
|
---|
503 | pred_ptr->literal_control_chars, pred_ptr->args.stream);
|
---|
504 | return true;
|
---|
505 | }
|
---|
506 |
|
---|
507 | boolean
|
---|
508 | pred_fprint (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
509 | {
|
---|
510 | (void) &pathname;
|
---|
511 | (void) &stat_buf;
|
---|
512 |
|
---|
513 | print_quoted(pred_ptr->args.printf_vec.stream,
|
---|
514 | pred_ptr->args.printf_vec.quote_opts,
|
---|
515 | pred_ptr->args.printf_vec.dest_is_tty,
|
---|
516 | "%s\n",
|
---|
517 | pathname);
|
---|
518 | return true;
|
---|
519 | }
|
---|
520 |
|
---|
521 | boolean
|
---|
522 | pred_fprint0 (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
523 | {
|
---|
524 | (void) &pathname;
|
---|
525 | (void) &stat_buf;
|
---|
526 |
|
---|
527 | fputs (pathname, pred_ptr->args.stream);
|
---|
528 | putc (0, pred_ptr->args.stream);
|
---|
529 | return (true);
|
---|
530 | }
|
---|
531 |
|
---|
532 |
|
---|
533 |
|
---|
534 | static char*
|
---|
535 | mode_to_filetype(mode_t m)
|
---|
536 | {
|
---|
537 | return
|
---|
538 | m == S_IFSOCK ? "s" :
|
---|
539 | m == S_IFLNK ? "l" :
|
---|
540 | m == S_IFREG ? "f" :
|
---|
541 | m == S_IFBLK ? "b" :
|
---|
542 | m == S_IFDIR ? "d" :
|
---|
543 | m == S_IFCHR ? "c" :
|
---|
544 | #ifdef S_IFDOOR
|
---|
545 | m == S_IFDOOR ? "D" :
|
---|
546 | #endif
|
---|
547 | m == S_IFIFO ? "p" : "U";
|
---|
548 | }
|
---|
549 |
|
---|
550 |
|
---|
551 | boolean
|
---|
552 | pred_fprintf (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
553 | {
|
---|
554 | FILE *fp = pred_ptr->args.printf_vec.stream;
|
---|
555 | const struct quoting_options *qopts = pred_ptr->args.printf_vec.quote_opts;
|
---|
556 | boolean ttyflag = pred_ptr->args.printf_vec.dest_is_tty;
|
---|
557 | struct segment *segment;
|
---|
558 | char *cp;
|
---|
559 | char hbuf[LONGEST_HUMAN_READABLE + 1];
|
---|
560 |
|
---|
561 | for (segment = pred_ptr->args.printf_vec.segment; segment;
|
---|
562 | segment = segment->next)
|
---|
563 | {
|
---|
564 | if (segment->kind & 0xff00) /* Component of date. */
|
---|
565 | {
|
---|
566 | time_t t;
|
---|
567 |
|
---|
568 | switch (segment->kind & 0xff)
|
---|
569 | {
|
---|
570 | case 'A':
|
---|
571 | t = stat_buf->st_atime;
|
---|
572 | break;
|
---|
573 | case 'C':
|
---|
574 | t = stat_buf->st_ctime;
|
---|
575 | break;
|
---|
576 | case 'T':
|
---|
577 | t = stat_buf->st_mtime;
|
---|
578 | break;
|
---|
579 | default:
|
---|
580 | abort ();
|
---|
581 | }
|
---|
582 | /* We trust the output of format_date not to contain
|
---|
583 | * nasty characters, though the value of the date
|
---|
584 | * is itself untrusted data.
|
---|
585 | */
|
---|
586 | /* trusted */
|
---|
587 | fprintf (fp, segment->text,
|
---|
588 | format_date (t, (segment->kind >> 8) & 0xff));
|
---|
589 | continue;
|
---|
590 | }
|
---|
591 |
|
---|
592 | switch (segment->kind)
|
---|
593 | {
|
---|
594 | case KIND_PLAIN: /* Plain text string (no % conversion). */
|
---|
595 | /* trusted */
|
---|
596 | fwrite (segment->text, 1, segment->text_len, fp);
|
---|
597 | break;
|
---|
598 | case KIND_STOP: /* Terminate argument and flush output. */
|
---|
599 | /* trusted */
|
---|
600 | fwrite (segment->text, 1, segment->text_len, fp);
|
---|
601 | fflush (fp);
|
---|
602 | return (true);
|
---|
603 | case 'a': /* atime in `ctime' format. */
|
---|
604 | /* UNTRUSTED, probably unexploitable */
|
---|
605 | fprintf (fp, segment->text, ctime_format (stat_buf->st_atime));
|
---|
606 | break;
|
---|
607 | case 'b': /* size in 512-byte blocks */
|
---|
608 | /* UNTRUSTED, probably unexploitable */
|
---|
609 | fprintf (fp, segment->text,
|
---|
610 | human_readable ((uintmax_t) ST_NBLOCKS (*stat_buf),
|
---|
611 | hbuf, human_ceiling,
|
---|
612 | ST_NBLOCKSIZE, 512));
|
---|
613 | break;
|
---|
614 | case 'c': /* ctime in `ctime' format */
|
---|
615 | /* UNTRUSTED, probably unexploitable */
|
---|
616 | fprintf (fp, segment->text, ctime_format (stat_buf->st_ctime));
|
---|
617 | break;
|
---|
618 | case 'd': /* depth in search tree */
|
---|
619 | /* UNTRUSTED, probably unexploitable */
|
---|
620 | fprintf (fp, segment->text, state.curdepth);
|
---|
621 | break;
|
---|
622 | case 'D': /* Device on which file exists (stat.st_dev) */
|
---|
623 | /* trusted */
|
---|
624 | fprintf (fp, segment->text,
|
---|
625 | human_readable ((uintmax_t) stat_buf->st_dev, hbuf,
|
---|
626 | human_ceiling, 1, 1));
|
---|
627 | break;
|
---|
628 | case 'f': /* base name of path */
|
---|
629 | /* sanitised */
|
---|
630 | print_quoted (fp, qopts, ttyflag, segment->text, base_name (pathname));
|
---|
631 | break;
|
---|
632 | case 'F': /* filesystem type */
|
---|
633 | /* trusted */
|
---|
634 | print_quoted (fp, qopts, ttyflag, segment->text, filesystem_type (stat_buf, pathname));
|
---|
635 | break;
|
---|
636 | case 'g': /* group name */
|
---|
637 | /* trusted */
|
---|
638 | /* (well, the actual group is selected by the user but
|
---|
639 | * its name was selected by the system administrator)
|
---|
640 | */
|
---|
641 | {
|
---|
642 | struct group *g;
|
---|
643 |
|
---|
644 | g = getgrgid (stat_buf->st_gid);
|
---|
645 | if (g)
|
---|
646 | {
|
---|
647 | segment->text[segment->text_len] = 's';
|
---|
648 | fprintf (fp, segment->text, g->gr_name);
|
---|
649 | break;
|
---|
650 | }
|
---|
651 | /* else fallthru */
|
---|
652 | }
|
---|
653 | case 'G': /* GID number */
|
---|
654 | /* UNTRUSTED, probably unexploitable */
|
---|
655 | fprintf (fp, segment->text,
|
---|
656 | human_readable ((uintmax_t) stat_buf->st_gid, hbuf,
|
---|
657 | human_ceiling, 1, 1));
|
---|
658 | break;
|
---|
659 | case 'h': /* leading directories part of path */
|
---|
660 | /* sanitised */
|
---|
661 | {
|
---|
662 | char cc;
|
---|
663 |
|
---|
664 | cp = strrchr (pathname, '/');
|
---|
665 | if (cp == NULL) /* No leading directories. */
|
---|
666 | {
|
---|
667 | /* If there is no slash in the pathname, we still
|
---|
668 | * print the string because it contains characters
|
---|
669 | * other than just '%s'. The %h expands to ".".
|
---|
670 | */
|
---|
671 | print_quoted (fp, qopts, ttyflag, segment->text, ".");
|
---|
672 | }
|
---|
673 | else
|
---|
674 | {
|
---|
675 | cc = *cp;
|
---|
676 | *cp = '\0';
|
---|
677 | print_quoted (fp, qopts, ttyflag, segment->text, pathname);
|
---|
678 | *cp = cc;
|
---|
679 | }
|
---|
680 | break;
|
---|
681 | }
|
---|
682 | case 'H': /* ARGV element file was found under */
|
---|
683 | /* trusted */
|
---|
684 | {
|
---|
685 | char cc = pathname[state.starting_path_length];
|
---|
686 |
|
---|
687 | pathname[state.starting_path_length] = '\0';
|
---|
688 | fprintf (fp, segment->text, pathname);
|
---|
689 | pathname[state.starting_path_length] = cc;
|
---|
690 | break;
|
---|
691 | }
|
---|
692 | case 'i': /* inode number */
|
---|
693 | /* UNTRUSTED, but not exploitable I think */
|
---|
694 | fprintf (fp, segment->text,
|
---|
695 | human_readable ((uintmax_t) stat_buf->st_ino, hbuf,
|
---|
696 | human_ceiling,
|
---|
697 | 1, 1));
|
---|
698 | break;
|
---|
699 | case 'k': /* size in 1K blocks */
|
---|
700 | /* UNTRUSTED, but not exploitable I think */
|
---|
701 | fprintf (fp, segment->text,
|
---|
702 | human_readable ((uintmax_t) ST_NBLOCKS (*stat_buf),
|
---|
703 | hbuf, human_ceiling,
|
---|
704 | ST_NBLOCKSIZE, 1024));
|
---|
705 | break;
|
---|
706 | case 'l': /* object of symlink */
|
---|
707 | /* sanitised */
|
---|
708 | #ifdef S_ISLNK
|
---|
709 | {
|
---|
710 | char *linkname = 0;
|
---|
711 |
|
---|
712 | if (S_ISLNK (stat_buf->st_mode))
|
---|
713 | {
|
---|
714 | linkname = get_link_name (pathname, state.rel_pathname);
|
---|
715 | if (linkname == 0)
|
---|
716 | state.exit_status = 1;
|
---|
717 | }
|
---|
718 | if (linkname)
|
---|
719 | {
|
---|
720 | print_quoted (fp, qopts, ttyflag, segment->text, linkname);
|
---|
721 | free (linkname);
|
---|
722 | }
|
---|
723 | else
|
---|
724 | print_quoted (fp, qopts, ttyflag, segment->text, "");
|
---|
725 | }
|
---|
726 | #endif /* S_ISLNK */
|
---|
727 | break;
|
---|
728 |
|
---|
729 | case 'M': /* mode as 10 chars (eg., "-rwxr-x--x" */
|
---|
730 | /* UNTRUSTED, probably unexploitable */
|
---|
731 | {
|
---|
732 | char modestring[16] ;
|
---|
733 | filemodestring (stat_buf, modestring);
|
---|
734 | modestring[10] = '\0';
|
---|
735 | fprintf (fp, segment->text, modestring);
|
---|
736 | }
|
---|
737 | break;
|
---|
738 |
|
---|
739 | case 'm': /* mode as octal number (perms only) */
|
---|
740 | /* UNTRUSTED, probably unexploitable */
|
---|
741 | {
|
---|
742 | /* Output the mode portably using the traditional numbers,
|
---|
743 | even if the host unwisely uses some other numbering
|
---|
744 | scheme. But help the compiler in the common case where
|
---|
745 | the host uses the traditional numbering scheme. */
|
---|
746 | mode_t m = stat_buf->st_mode;
|
---|
747 | boolean traditional_numbering_scheme =
|
---|
748 | (S_ISUID == 04000 && S_ISGID == 02000 && S_ISVTX == 01000
|
---|
749 | && S_IRUSR == 00400 && S_IWUSR == 00200 && S_IXUSR == 00100
|
---|
750 | && S_IRGRP == 00040 && S_IWGRP == 00020 && S_IXGRP == 00010
|
---|
751 | && S_IROTH == 00004 && S_IWOTH == 00002 && S_IXOTH == 00001);
|
---|
752 | fprintf (fp, segment->text,
|
---|
753 | (traditional_numbering_scheme
|
---|
754 | ? m & MODE_ALL
|
---|
755 | : ((m & S_ISUID ? 04000 : 0)
|
---|
756 | | (m & S_ISGID ? 02000 : 0)
|
---|
757 | | (m & S_ISVTX ? 01000 : 0)
|
---|
758 | | (m & S_IRUSR ? 00400 : 0)
|
---|
759 | | (m & S_IWUSR ? 00200 : 0)
|
---|
760 | | (m & S_IXUSR ? 00100 : 0)
|
---|
761 | | (m & S_IRGRP ? 00040 : 0)
|
---|
762 | | (m & S_IWGRP ? 00020 : 0)
|
---|
763 | | (m & S_IXGRP ? 00010 : 0)
|
---|
764 | | (m & S_IROTH ? 00004 : 0)
|
---|
765 | | (m & S_IWOTH ? 00002 : 0)
|
---|
766 | | (m & S_IXOTH ? 00001 : 0))));
|
---|
767 | }
|
---|
768 | break;
|
---|
769 |
|
---|
770 | case 'n': /* number of links */
|
---|
771 | /* UNTRUSTED, probably unexploitable */
|
---|
772 | fprintf (fp, segment->text,
|
---|
773 | human_readable ((uintmax_t) stat_buf->st_nlink,
|
---|
774 | hbuf,
|
---|
775 | human_ceiling,
|
---|
776 | 1, 1));
|
---|
777 | break;
|
---|
778 | case 'p': /* pathname */
|
---|
779 | /* sanitised */
|
---|
780 | print_quoted (fp, qopts, ttyflag, segment->text, pathname);
|
---|
781 | break;
|
---|
782 | case 'P': /* pathname with ARGV element stripped */
|
---|
783 | /* sanitised */
|
---|
784 | if (state.curdepth > 0)
|
---|
785 | {
|
---|
786 | cp = pathname + state.starting_path_length;
|
---|
787 | if (*cp == '/')
|
---|
788 | /* Move past the slash between the ARGV element
|
---|
789 | and the rest of the pathname. But if the ARGV element
|
---|
790 | ends in a slash, we didn't add another, so we've
|
---|
791 | already skipped past it. */
|
---|
792 | cp++;
|
---|
793 | }
|
---|
794 | else
|
---|
795 | cp = "";
|
---|
796 | print_quoted (fp, qopts, ttyflag, segment->text, cp);
|
---|
797 | break;
|
---|
798 | case 's': /* size in bytes */
|
---|
799 | /* UNTRUSTED, probably unexploitable */
|
---|
800 | fprintf (fp, segment->text,
|
---|
801 | human_readable ((uintmax_t) stat_buf->st_size,
|
---|
802 | hbuf, human_ceiling, 1, 1));
|
---|
803 | break;
|
---|
804 | case 't': /* mtime in `ctime' format */
|
---|
805 | /* UNTRUSTED, probably unexploitable */
|
---|
806 | fprintf (fp, segment->text, ctime_format (stat_buf->st_mtime));
|
---|
807 | break;
|
---|
808 | case 'u': /* user name */
|
---|
809 | /* trusted */
|
---|
810 | /* (well, the actual user is selected by the user on systems
|
---|
811 | * where chown is not restricted, but the user name was
|
---|
812 | * selected by the system administrator)
|
---|
813 | */
|
---|
814 | {
|
---|
815 | struct passwd *p;
|
---|
816 |
|
---|
817 | p = getpwuid (stat_buf->st_uid);
|
---|
818 | if (p)
|
---|
819 | {
|
---|
820 | segment->text[segment->text_len] = 's';
|
---|
821 | fprintf (fp, segment->text, p->pw_name);
|
---|
822 | break;
|
---|
823 | }
|
---|
824 | /* else fallthru */
|
---|
825 | }
|
---|
826 |
|
---|
827 | case 'U': /* UID number */
|
---|
828 | /* UNTRUSTED, probably unexploitable */
|
---|
829 | fprintf (fp, segment->text,
|
---|
830 | human_readable ((uintmax_t) stat_buf->st_uid, hbuf,
|
---|
831 | human_ceiling, 1, 1));
|
---|
832 | break;
|
---|
833 |
|
---|
834 | /* type of filesystem entry like `ls -l`: (d,-,l,s,p,b,c,n) n=nonexistent(symlink) */
|
---|
835 | case 'Y': /* in case of symlink */
|
---|
836 | /* trusted */
|
---|
837 | {
|
---|
838 | #ifdef S_ISLNK
|
---|
839 | if (S_ISLNK (stat_buf->st_mode))
|
---|
840 | {
|
---|
841 | struct stat sbuf;
|
---|
842 | /* If we would normally follow links, do not do so.
|
---|
843 | * If we would normally not follow links, do so.
|
---|
844 | */
|
---|
845 | if ((following_links() ? lstat : stat)
|
---|
846 | (state.rel_pathname, &sbuf) != 0)
|
---|
847 | {
|
---|
848 | if ( errno == ENOENT ) {
|
---|
849 | fprintf (fp, segment->text, "N");
|
---|
850 | break;
|
---|
851 | };
|
---|
852 | if ( errno == ELOOP ) {
|
---|
853 | fprintf (fp, segment->text, "L");
|
---|
854 | break;
|
---|
855 | };
|
---|
856 | error (0, errno, "%s", pathname);
|
---|
857 | /* exit_status = 1;
|
---|
858 | return (false); */
|
---|
859 | }
|
---|
860 | fprintf (fp, segment->text,
|
---|
861 | mode_to_filetype(sbuf.st_mode & S_IFMT));
|
---|
862 | }
|
---|
863 | #endif /* S_ISLNK */
|
---|
864 | else
|
---|
865 | {
|
---|
866 | fprintf (fp, segment->text,
|
---|
867 | mode_to_filetype(stat_buf->st_mode & S_IFMT));
|
---|
868 | }
|
---|
869 | }
|
---|
870 | break;
|
---|
871 |
|
---|
872 | case 'y':
|
---|
873 | /* trusted */
|
---|
874 | {
|
---|
875 | fprintf (fp, segment->text,
|
---|
876 | mode_to_filetype(stat_buf->st_mode & S_IFMT));
|
---|
877 | }
|
---|
878 | break;
|
---|
879 | }
|
---|
880 | }
|
---|
881 | return true;
|
---|
882 | }
|
---|
883 |
|
---|
884 | boolean
|
---|
885 | pred_fstype (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
886 | {
|
---|
887 | (void) pathname;
|
---|
888 |
|
---|
889 | if (strcmp (filesystem_type (stat_buf, pathname), pred_ptr->args.str) == 0)
|
---|
890 | return true;
|
---|
891 | else
|
---|
892 | return false;
|
---|
893 | }
|
---|
894 |
|
---|
895 | boolean
|
---|
896 | pred_gid (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
897 | {
|
---|
898 | (void) pathname;
|
---|
899 |
|
---|
900 | switch (pred_ptr->args.info.kind)
|
---|
901 | {
|
---|
902 | case COMP_GT:
|
---|
903 | if (stat_buf->st_gid > pred_ptr->args.info.l_val)
|
---|
904 | return (true);
|
---|
905 | break;
|
---|
906 | case COMP_LT:
|
---|
907 | if (stat_buf->st_gid < pred_ptr->args.info.l_val)
|
---|
908 | return (true);
|
---|
909 | break;
|
---|
910 | case COMP_EQ:
|
---|
911 | if (stat_buf->st_gid == pred_ptr->args.info.l_val)
|
---|
912 | return (true);
|
---|
913 | break;
|
---|
914 | }
|
---|
915 | return (false);
|
---|
916 | }
|
---|
917 |
|
---|
918 | boolean
|
---|
919 | pred_group (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
920 | {
|
---|
921 | (void) pathname;
|
---|
922 |
|
---|
923 | if (pred_ptr->args.gid == stat_buf->st_gid)
|
---|
924 | return (true);
|
---|
925 | else
|
---|
926 | return (false);
|
---|
927 | }
|
---|
928 |
|
---|
929 | boolean
|
---|
930 | pred_ilname (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
931 | {
|
---|
932 | return match_lname (pathname, stat_buf, pred_ptr, true);
|
---|
933 | }
|
---|
934 |
|
---|
935 | boolean
|
---|
936 | pred_iname (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
937 | {
|
---|
938 | const char *base;
|
---|
939 |
|
---|
940 | (void) stat_buf;
|
---|
941 |
|
---|
942 | /* FNM_PERIOD is not used here because POSIX requires that it not be.
|
---|
943 | * See http://standards.ieee.org/reading/ieee/interp/1003-2-92_int/pasc-1003.2-126.html
|
---|
944 | */
|
---|
945 | base = base_name (pathname);
|
---|
946 | if (fnmatch (pred_ptr->args.str, base, FNM_CASEFOLD) == 0)
|
---|
947 | return (true);
|
---|
948 | return (false);
|
---|
949 | }
|
---|
950 |
|
---|
951 | boolean
|
---|
952 | pred_inum (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
953 | {
|
---|
954 | (void) pathname;
|
---|
955 |
|
---|
956 | switch (pred_ptr->args.info.kind)
|
---|
957 | {
|
---|
958 | case COMP_GT:
|
---|
959 | if (stat_buf->st_ino > pred_ptr->args.info.l_val)
|
---|
960 | return (true);
|
---|
961 | break;
|
---|
962 | case COMP_LT:
|
---|
963 | if (stat_buf->st_ino < pred_ptr->args.info.l_val)
|
---|
964 | return (true);
|
---|
965 | break;
|
---|
966 | case COMP_EQ:
|
---|
967 | if (stat_buf->st_ino == pred_ptr->args.info.l_val)
|
---|
968 | return (true);
|
---|
969 | break;
|
---|
970 | }
|
---|
971 | return (false);
|
---|
972 | }
|
---|
973 |
|
---|
974 | boolean
|
---|
975 | pred_ipath (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
976 | {
|
---|
977 | (void) stat_buf;
|
---|
978 |
|
---|
979 | if (fnmatch (pred_ptr->args.str, pathname, FNM_CASEFOLD) == 0)
|
---|
980 | return (true);
|
---|
981 | return (false);
|
---|
982 | }
|
---|
983 |
|
---|
984 | boolean
|
---|
985 | pred_links (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
986 | {
|
---|
987 | (void) pathname;
|
---|
988 |
|
---|
989 | switch (pred_ptr->args.info.kind)
|
---|
990 | {
|
---|
991 | case COMP_GT:
|
---|
992 | if (stat_buf->st_nlink > pred_ptr->args.info.l_val)
|
---|
993 | return (true);
|
---|
994 | break;
|
---|
995 | case COMP_LT:
|
---|
996 | if (stat_buf->st_nlink < pred_ptr->args.info.l_val)
|
---|
997 | return (true);
|
---|
998 | break;
|
---|
999 | case COMP_EQ:
|
---|
1000 | if (stat_buf->st_nlink == pred_ptr->args.info.l_val)
|
---|
1001 | return (true);
|
---|
1002 | break;
|
---|
1003 | }
|
---|
1004 | return (false);
|
---|
1005 | }
|
---|
1006 |
|
---|
1007 | boolean
|
---|
1008 | pred_lname (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1009 | {
|
---|
1010 | return match_lname (pathname, stat_buf, pred_ptr, false);
|
---|
1011 | }
|
---|
1012 |
|
---|
1013 | static boolean
|
---|
1014 | match_lname (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr, boolean ignore_case)
|
---|
1015 | {
|
---|
1016 | boolean ret = false;
|
---|
1017 | #ifdef S_ISLNK
|
---|
1018 | if (S_ISLNK (stat_buf->st_mode))
|
---|
1019 | {
|
---|
1020 | char *linkname = get_link_name (pathname, state.rel_pathname);
|
---|
1021 | if (linkname)
|
---|
1022 | {
|
---|
1023 | if (fnmatch (pred_ptr->args.str, linkname,
|
---|
1024 | ignore_case ? FNM_CASEFOLD : 0) == 0)
|
---|
1025 | ret = true;
|
---|
1026 | free (linkname);
|
---|
1027 | }
|
---|
1028 | }
|
---|
1029 | #endif /* S_ISLNK */
|
---|
1030 | return ret;
|
---|
1031 | }
|
---|
1032 |
|
---|
1033 | boolean
|
---|
1034 | pred_ls (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1035 | {
|
---|
1036 | list_file (pathname, state.rel_pathname, stat_buf, options.start_time,
|
---|
1037 | options.output_block_size,
|
---|
1038 | pred_ptr->literal_control_chars,
|
---|
1039 | stdout);
|
---|
1040 | return true;
|
---|
1041 | }
|
---|
1042 |
|
---|
1043 | boolean
|
---|
1044 | pred_mmin (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1045 | {
|
---|
1046 | (void) &pathname;
|
---|
1047 | return pred_timewindow(stat_buf->st_mtime, pred_ptr, 60);
|
---|
1048 | }
|
---|
1049 |
|
---|
1050 | boolean
|
---|
1051 | pred_mtime (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1052 | {
|
---|
1053 | (void) pathname;
|
---|
1054 | return pred_timewindow(stat_buf->st_mtime, pred_ptr, DAYSECS);
|
---|
1055 | }
|
---|
1056 |
|
---|
1057 | boolean
|
---|
1058 | pred_name (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1059 | {
|
---|
1060 | const char *base;
|
---|
1061 |
|
---|
1062 | (void) stat_buf;
|
---|
1063 | base = base_name (pathname);
|
---|
1064 |
|
---|
1065 | /* FNM_PERIOD is not used here because POSIX requires that it not be.
|
---|
1066 | * See http://standards.ieee.org/reading/ieee/interp/1003-2-92_int/pasc-1003.2-126.html
|
---|
1067 | */
|
---|
1068 | if (fnmatch (pred_ptr->args.str, base, 0) == 0)
|
---|
1069 | return (true);
|
---|
1070 | return (false);
|
---|
1071 | }
|
---|
1072 |
|
---|
1073 | boolean
|
---|
1074 | pred_negate (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1075 | {
|
---|
1076 | /* Check whether we need a stat here. */
|
---|
1077 | /* TODO: what about need_type? */
|
---|
1078 | if (get_info(pathname, state.rel_pathname, stat_buf, pred_ptr) != 0)
|
---|
1079 | return false;
|
---|
1080 | return (!(*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
|
---|
1081 | pred_ptr->pred_right));
|
---|
1082 | }
|
---|
1083 |
|
---|
1084 | boolean
|
---|
1085 | pred_newer (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1086 | {
|
---|
1087 | (void) pathname;
|
---|
1088 |
|
---|
1089 | if (stat_buf->st_mtime > pred_ptr->args.time)
|
---|
1090 | return (true);
|
---|
1091 | return (false);
|
---|
1092 | }
|
---|
1093 |
|
---|
1094 | boolean
|
---|
1095 | pred_nogroup (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1096 | {
|
---|
1097 | (void) pathname;
|
---|
1098 | (void) pred_ptr;
|
---|
1099 |
|
---|
1100 | #ifdef CACHE_IDS
|
---|
1101 | extern char *gid_unused;
|
---|
1102 |
|
---|
1103 | return gid_unused[(unsigned) stat_buf->st_gid];
|
---|
1104 | #else
|
---|
1105 | return getgrgid (stat_buf->st_gid) == NULL;
|
---|
1106 | #endif
|
---|
1107 | }
|
---|
1108 |
|
---|
1109 | boolean
|
---|
1110 | pred_nouser (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1111 | {
|
---|
1112 | #ifdef CACHE_IDS
|
---|
1113 | extern char *uid_unused;
|
---|
1114 | #endif
|
---|
1115 |
|
---|
1116 | (void) pathname;
|
---|
1117 | (void) pred_ptr;
|
---|
1118 |
|
---|
1119 | #ifdef CACHE_IDS
|
---|
1120 | return uid_unused[(unsigned) stat_buf->st_uid];
|
---|
1121 | #else
|
---|
1122 | return getpwuid (stat_buf->st_uid) == NULL;
|
---|
1123 | #endif
|
---|
1124 | }
|
---|
1125 |
|
---|
1126 |
|
---|
1127 | static boolean
|
---|
1128 | is_ok(const char *program, const char *arg)
|
---|
1129 | {
|
---|
1130 | fflush (stdout);
|
---|
1131 | /* The draft open standard requires that, in the POSIX locale,
|
---|
1132 | the last non-blank character of this prompt be '?'.
|
---|
1133 | The exact format is not specified.
|
---|
1134 | This standard does not have requirements for locales other than POSIX
|
---|
1135 | */
|
---|
1136 | /* XXX: printing UNTRUSTED data here. */
|
---|
1137 | fprintf (stderr, _("< %s ... %s > ? "), program, arg);
|
---|
1138 | fflush (stderr);
|
---|
1139 | return yesno();
|
---|
1140 | }
|
---|
1141 |
|
---|
1142 | boolean
|
---|
1143 | pred_ok (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1144 | {
|
---|
1145 | if (is_ok(pred_ptr->args.exec_vec.replace_vec[0], pathname))
|
---|
1146 | return new_impl_pred_exec (pathname, stat_buf, pred_ptr, NULL, 0);
|
---|
1147 | else
|
---|
1148 | return false;
|
---|
1149 | }
|
---|
1150 |
|
---|
1151 | boolean
|
---|
1152 | pred_okdir (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1153 | {
|
---|
1154 | const char *prefix = (state.rel_pathname[0] == '/') ? NULL : "./";
|
---|
1155 | if (is_ok(pred_ptr->args.exec_vec.replace_vec[0], pathname))
|
---|
1156 | return new_impl_pred_exec (state.rel_pathname, stat_buf, pred_ptr,
|
---|
1157 | prefix, (prefix ? 2 : 0));
|
---|
1158 | else
|
---|
1159 | return false;
|
---|
1160 | }
|
---|
1161 |
|
---|
1162 | boolean
|
---|
1163 | pred_open (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1164 | {
|
---|
1165 | (void) pathname;
|
---|
1166 | (void) stat_buf;
|
---|
1167 | (void) pred_ptr;
|
---|
1168 | return true;
|
---|
1169 | }
|
---|
1170 |
|
---|
1171 | boolean
|
---|
1172 | pred_or (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1173 | {
|
---|
1174 | if (pred_ptr->pred_left == NULL
|
---|
1175 | || !(*pred_ptr->pred_left->pred_func) (pathname, stat_buf,
|
---|
1176 | pred_ptr->pred_left))
|
---|
1177 | {
|
---|
1178 | if (get_info(pathname, state.rel_pathname, stat_buf, pred_ptr) != 0)
|
---|
1179 | return false;
|
---|
1180 | return ((*pred_ptr->pred_right->pred_func) (pathname, stat_buf,
|
---|
1181 | pred_ptr->pred_right));
|
---|
1182 | }
|
---|
1183 | else
|
---|
1184 | return true;
|
---|
1185 | }
|
---|
1186 |
|
---|
1187 | boolean
|
---|
1188 | pred_path (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1189 | {
|
---|
1190 | (void) stat_buf;
|
---|
1191 | if (fnmatch (pred_ptr->args.str, pathname, 0) == 0)
|
---|
1192 | return (true);
|
---|
1193 | return (false);
|
---|
1194 | }
|
---|
1195 |
|
---|
1196 | boolean
|
---|
1197 | pred_perm (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1198 | {
|
---|
1199 | mode_t mode = stat_buf->st_mode;
|
---|
1200 | mode_t perm_val = pred_ptr->args.perm.val[S_ISDIR (mode) != 0];
|
---|
1201 | (void) pathname;
|
---|
1202 | switch (pred_ptr->args.perm.kind)
|
---|
1203 | {
|
---|
1204 | case PERM_AT_LEAST:
|
---|
1205 | return (mode & perm_val) == perm_val;
|
---|
1206 | break;
|
---|
1207 |
|
---|
1208 | case PERM_ANY:
|
---|
1209 | /* True if any of the bits set in the mask are also set in the file's mode.
|
---|
1210 | *
|
---|
1211 | *
|
---|
1212 | * Otherwise, if onum is prefixed by a hyphen, the primary shall
|
---|
1213 | * evaluate as true if at least all of the bits specified in
|
---|
1214 | * onum that are also set in the octal mask 07777 are set.
|
---|
1215 | *
|
---|
1216 | * Eric Blake's interpretation is that the mode argument is zero,
|
---|
1217 |
|
---|
1218 | */
|
---|
1219 | if (0 == perm_val)
|
---|
1220 | return true; /* Savannah bug 14748; we used to return false */
|
---|
1221 | else
|
---|
1222 | return (mode & perm_val) != 0;
|
---|
1223 | break;
|
---|
1224 |
|
---|
1225 | case PERM_EXACT:
|
---|
1226 | return (mode & MODE_ALL) == perm_val;
|
---|
1227 | break;
|
---|
1228 |
|
---|
1229 | default:
|
---|
1230 | abort ();
|
---|
1231 | break;
|
---|
1232 | }
|
---|
1233 | }
|
---|
1234 |
|
---|
1235 |
|
---|
1236 | boolean
|
---|
1237 | pred_executable (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1238 | {
|
---|
1239 | (void) pathname;
|
---|
1240 | (void) stat_buf;
|
---|
1241 | (void) pred_ptr;
|
---|
1242 |
|
---|
1243 | return 0 == access(state.rel_pathname, X_OK);
|
---|
1244 | }
|
---|
1245 |
|
---|
1246 | boolean
|
---|
1247 | pred_readable (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1248 | {
|
---|
1249 | (void) pathname;
|
---|
1250 | (void) stat_buf;
|
---|
1251 | (void) pred_ptr;
|
---|
1252 |
|
---|
1253 | return 0 == access(state.rel_pathname, R_OK);
|
---|
1254 | }
|
---|
1255 |
|
---|
1256 | boolean
|
---|
1257 | pred_writable (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1258 | {
|
---|
1259 | (void) pathname;
|
---|
1260 | (void) stat_buf;
|
---|
1261 | (void) pred_ptr;
|
---|
1262 |
|
---|
1263 | return 0 == access(state.rel_pathname, W_OK);
|
---|
1264 | }
|
---|
1265 |
|
---|
1266 | boolean
|
---|
1267 | pred_print (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1268 | {
|
---|
1269 | (void) stat_buf;
|
---|
1270 | (void) pred_ptr;
|
---|
1271 | /* puts (pathname); */
|
---|
1272 | print_quoted(pred_ptr->args.printf_vec.stream,
|
---|
1273 | pred_ptr->args.printf_vec.quote_opts,
|
---|
1274 | pred_ptr->args.printf_vec.dest_is_tty,
|
---|
1275 | "%s\n", pathname);
|
---|
1276 | return true;
|
---|
1277 | }
|
---|
1278 |
|
---|
1279 | boolean
|
---|
1280 | pred_print0 (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1281 | {
|
---|
1282 | (void) stat_buf;
|
---|
1283 | (void) pred_ptr;
|
---|
1284 | fputs (pathname, stdout);
|
---|
1285 | putc (0, stdout);
|
---|
1286 | return (true);
|
---|
1287 | }
|
---|
1288 |
|
---|
1289 | boolean
|
---|
1290 | pred_prune (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1291 | {
|
---|
1292 | (void) pathname;
|
---|
1293 | (void) pred_ptr;
|
---|
1294 |
|
---|
1295 | if (options.do_dir_first == true &&
|
---|
1296 | stat_buf != NULL &&
|
---|
1297 | S_ISDIR(stat_buf->st_mode))
|
---|
1298 | state.stop_at_current_level = true;
|
---|
1299 |
|
---|
1300 | return (options.do_dir_first); /* This is what SunOS find seems to do. */
|
---|
1301 | }
|
---|
1302 |
|
---|
1303 | boolean
|
---|
1304 | pred_quit (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1305 | {
|
---|
1306 | (void) pathname;
|
---|
1307 | (void) stat_buf;
|
---|
1308 | (void) pred_ptr;
|
---|
1309 |
|
---|
1310 | /* Run any cleanups. This includes executing any command lines
|
---|
1311 | * we have partly built but not executed.
|
---|
1312 | */
|
---|
1313 | cleanup();
|
---|
1314 |
|
---|
1315 | /* Since -exec and friends don't leave child processes running in the
|
---|
1316 | * background, there is no need to wait for them here.
|
---|
1317 | */
|
---|
1318 | exit(state.exit_status); /* 0 for success, etc. */
|
---|
1319 | }
|
---|
1320 |
|
---|
1321 | boolean
|
---|
1322 | pred_regex (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1323 | {
|
---|
1324 | int len = strlen (pathname);
|
---|
1325 | (void) stat_buf;
|
---|
1326 | if (re_match (pred_ptr->args.regex, pathname, len, 0,
|
---|
1327 | (struct re_registers *) NULL) == len)
|
---|
1328 | return (true);
|
---|
1329 | return (false);
|
---|
1330 | }
|
---|
1331 |
|
---|
1332 | boolean
|
---|
1333 | pred_size (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1334 | {
|
---|
1335 | uintmax_t f_val;
|
---|
1336 |
|
---|
1337 | (void) pathname;
|
---|
1338 | f_val = ((stat_buf->st_size / pred_ptr->args.size.blocksize)
|
---|
1339 | + (stat_buf->st_size % pred_ptr->args.size.blocksize != 0));
|
---|
1340 | switch (pred_ptr->args.size.kind)
|
---|
1341 | {
|
---|
1342 | case COMP_GT:
|
---|
1343 | if (f_val > pred_ptr->args.size.size)
|
---|
1344 | return (true);
|
---|
1345 | break;
|
---|
1346 | case COMP_LT:
|
---|
1347 | if (f_val < pred_ptr->args.size.size)
|
---|
1348 | return (true);
|
---|
1349 | break;
|
---|
1350 | case COMP_EQ:
|
---|
1351 | if (f_val == pred_ptr->args.size.size)
|
---|
1352 | return (true);
|
---|
1353 | break;
|
---|
1354 | }
|
---|
1355 | return (false);
|
---|
1356 | }
|
---|
1357 |
|
---|
1358 | boolean
|
---|
1359 | pred_samefile (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1360 | {
|
---|
1361 | /* Potential optimisation: because of the loop protection, we always
|
---|
1362 | * know the device of the current directory, hence the device number
|
---|
1363 | * of the file we're currently considering. If -L is not in effect,
|
---|
1364 | * and the device number of the file we're looking for is not the
|
---|
1365 | * same as the device number of the current directory, this
|
---|
1366 | * predicate cannot return true. Hence there would be no need to
|
---|
1367 | * stat the file we're lookingn at.
|
---|
1368 | */
|
---|
1369 | (void) pathname;
|
---|
1370 |
|
---|
1371 | return stat_buf->st_ino == pred_ptr->args.fileid.ino
|
---|
1372 | && stat_buf->st_dev == pred_ptr->args.fileid.dev;
|
---|
1373 | }
|
---|
1374 |
|
---|
1375 | boolean
|
---|
1376 | pred_true (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1377 | {
|
---|
1378 | (void) pathname;
|
---|
1379 | (void) stat_buf;
|
---|
1380 | (void) pred_ptr;
|
---|
1381 | return true;
|
---|
1382 | }
|
---|
1383 |
|
---|
1384 | boolean
|
---|
1385 | pred_type (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1386 | {
|
---|
1387 | mode_t mode;
|
---|
1388 | mode_t type = pred_ptr->args.type;
|
---|
1389 |
|
---|
1390 | assert(state.have_type);
|
---|
1391 | assert(state.type != 0);
|
---|
1392 |
|
---|
1393 | (void) pathname;
|
---|
1394 |
|
---|
1395 | if (state.have_stat)
|
---|
1396 | mode = stat_buf->st_mode;
|
---|
1397 | else
|
---|
1398 | mode = state.type;
|
---|
1399 |
|
---|
1400 | #ifndef S_IFMT
|
---|
1401 | /* POSIX system; check `mode' the slow way. */
|
---|
1402 | if ((S_ISBLK (mode) && type == S_IFBLK)
|
---|
1403 | || (S_ISCHR (mode) && type == S_IFCHR)
|
---|
1404 | || (S_ISDIR (mode) && type == S_IFDIR)
|
---|
1405 | || (S_ISREG (mode) && type == S_IFREG)
|
---|
1406 | #ifdef S_IFLNK
|
---|
1407 | || (S_ISLNK (mode) && type == S_IFLNK)
|
---|
1408 | #endif
|
---|
1409 | #ifdef S_IFIFO
|
---|
1410 | || (S_ISFIFO (mode) && type == S_IFIFO)
|
---|
1411 | #endif
|
---|
1412 | #ifdef S_IFSOCK
|
---|
1413 | || (S_ISSOCK (mode) && type == S_IFSOCK)
|
---|
1414 | #endif
|
---|
1415 | #ifdef S_IFDOOR
|
---|
1416 | || (S_ISDOOR (mode) && type == S_IFDOOR)
|
---|
1417 | #endif
|
---|
1418 | )
|
---|
1419 | #else /* S_IFMT */
|
---|
1420 | /* Unix system; check `mode' the fast way. */
|
---|
1421 | if ((mode & S_IFMT) == type)
|
---|
1422 | #endif /* S_IFMT */
|
---|
1423 | return (true);
|
---|
1424 | else
|
---|
1425 | return (false);
|
---|
1426 | }
|
---|
1427 |
|
---|
1428 | boolean
|
---|
1429 | pred_uid (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1430 | {
|
---|
1431 | (void) pathname;
|
---|
1432 | switch (pred_ptr->args.info.kind)
|
---|
1433 | {
|
---|
1434 | case COMP_GT:
|
---|
1435 | if (stat_buf->st_uid > pred_ptr->args.info.l_val)
|
---|
1436 | return (true);
|
---|
1437 | break;
|
---|
1438 | case COMP_LT:
|
---|
1439 | if (stat_buf->st_uid < pred_ptr->args.info.l_val)
|
---|
1440 | return (true);
|
---|
1441 | break;
|
---|
1442 | case COMP_EQ:
|
---|
1443 | if (stat_buf->st_uid == pred_ptr->args.info.l_val)
|
---|
1444 | return (true);
|
---|
1445 | break;
|
---|
1446 | }
|
---|
1447 | return (false);
|
---|
1448 | }
|
---|
1449 |
|
---|
1450 | boolean
|
---|
1451 | pred_used (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1452 | {
|
---|
1453 | time_t delta;
|
---|
1454 |
|
---|
1455 | (void) pathname;
|
---|
1456 | delta = stat_buf->st_atime - stat_buf->st_ctime; /* Use difftime? */
|
---|
1457 | return pred_timewindow(delta, pred_ptr, DAYSECS);
|
---|
1458 | }
|
---|
1459 |
|
---|
1460 | boolean
|
---|
1461 | pred_user (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1462 | {
|
---|
1463 | (void) pathname;
|
---|
1464 | if (pred_ptr->args.uid == stat_buf->st_uid)
|
---|
1465 | return (true);
|
---|
1466 | else
|
---|
1467 | return (false);
|
---|
1468 | }
|
---|
1469 |
|
---|
1470 | boolean
|
---|
1471 | pred_xtype (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
---|
1472 | {
|
---|
1473 | struct stat sbuf; /* local copy, not stat_buf because we're using a different stat method */
|
---|
1474 | int (*ystat) (const char*, struct stat *p);
|
---|
1475 |
|
---|
1476 | /* If we would normally stat the link itself, stat the target instead.
|
---|
1477 | * If we would normally follow the link, stat the link itself instead.
|
---|
1478 | */
|
---|
1479 | if (following_links())
|
---|
1480 | ystat = optionp_stat;
|
---|
1481 | else
|
---|
1482 | ystat = optionl_stat;
|
---|
1483 |
|
---|
1484 | if ((*ystat) (state.rel_pathname, &sbuf) != 0)
|
---|
1485 | {
|
---|
1486 | if (following_links() && errno == ENOENT)
|
---|
1487 | {
|
---|
1488 | /* If we failed to follow the symlink,
|
---|
1489 | * fall back on looking at the symlink itself.
|
---|
1490 | */
|
---|
1491 | /* Mimic behavior of ls -lL. */
|
---|
1492 | return (pred_type (pathname, stat_buf, pred_ptr));
|
---|
1493 | }
|
---|
1494 | else
|
---|
1495 | {
|
---|
1496 | error (0, errno, "%s", pathname);
|
---|
1497 | state.exit_status = 1;
|
---|
1498 | }
|
---|
1499 | return false;
|
---|
1500 | }
|
---|
1501 | /* Now that we have our stat() information, query it in the same
|
---|
1502 | * way that -type does.
|
---|
1503 | */
|
---|
1504 | return (pred_type (pathname, &sbuf, pred_ptr));
|
---|
1505 | }
|
---|
1506 | |
---|
1507 |
|
---|
1508 | /* 1) fork to get a child; parent remembers the child pid
|
---|
1509 | 2) child execs the command requested
|
---|
1510 | 3) parent waits for child; checks for proper pid of child
|
---|
1511 |
|
---|
1512 | Possible returns:
|
---|
1513 |
|
---|
1514 | ret errno status(h) status(l)
|
---|
1515 |
|
---|
1516 | pid x signal# 0177 stopped
|
---|
1517 | pid x exit arg 0 term by _exit
|
---|
1518 | pid x 0 signal # term by signal
|
---|
1519 | -1 EINTR parent got signal
|
---|
1520 | -1 other some other kind of error
|
---|
1521 |
|
---|
1522 | Return true only if the pid matches, status(l) is
|
---|
1523 | zero, and the exit arg (status high) is 0.
|
---|
1524 | Otherwise return false, possibly printing an error message. */
|
---|
1525 |
|
---|
1526 |
|
---|
1527 | static void
|
---|
1528 | prep_child_for_exec (boolean close_stdin)
|
---|
1529 | {
|
---|
1530 | if (close_stdin)
|
---|
1531 | {
|
---|
1532 | const char inputfile[] = "/dev/null";
|
---|
1533 | /* fprintf(stderr, "attaching stdin to /dev/null\n"); */
|
---|
1534 |
|
---|
1535 | close(0);
|
---|
1536 | if (open(inputfile, O_RDONLY) < 0)
|
---|
1537 | {
|
---|
1538 | /* This is not entirely fatal, since
|
---|
1539 | * executing the child with a closed
|
---|
1540 | * stdin is almost as good as executing it
|
---|
1541 | * with its stdin attached to /dev/null.
|
---|
1542 | */
|
---|
1543 | error (0, errno, "%s", inputfile);
|
---|
1544 | }
|
---|
1545 | }
|
---|
1546 | }
|
---|
1547 |
|
---|
1548 |
|
---|
1549 |
|
---|
1550 | int
|
---|
1551 | launch (const struct buildcmd_control *ctl,
|
---|
1552 | struct buildcmd_state *buildstate)
|
---|
1553 | {
|
---|
1554 | int wait_status;
|
---|
1555 | pid_t child_pid;
|
---|
1556 | static int first_time = 1;
|
---|
1557 | const struct exec_val *execp = buildstate->usercontext;
|
---|
1558 |
|
---|
1559 | /* Null terminate the arg list. */
|
---|
1560 | bc_push_arg (ctl, buildstate, (char *) NULL, 0, NULL, 0, false);
|
---|
1561 |
|
---|
1562 | /* Make sure output of command doesn't get mixed with find output. */
|
---|
1563 | fflush (stdout);
|
---|
1564 | fflush (stderr);
|
---|
1565 |
|
---|
1566 | /* Make sure to listen for the kids. */
|
---|
1567 | if (first_time)
|
---|
1568 | {
|
---|
1569 | first_time = 0;
|
---|
1570 | signal (SIGCHLD, SIG_DFL);
|
---|
1571 | }
|
---|
1572 |
|
---|
1573 | child_pid = fork ();
|
---|
1574 | if (child_pid == -1)
|
---|
1575 | error (1, errno, _("cannot fork"));
|
---|
1576 | if (child_pid == 0)
|
---|
1577 | {
|
---|
1578 | /* We be the child. */
|
---|
1579 | prep_child_for_exec(execp->close_stdin);
|
---|
1580 |
|
---|
1581 | /* For -exec and -ok, change directory back to the starting directory.
|
---|
1582 | * for -execdir and -okdir, stay in the directory we are searching
|
---|
1583 | * (the latter is more secure).
|
---|
1584 | */
|
---|
1585 | if (!execp->use_current_dir)
|
---|
1586 | {
|
---|
1587 | /* Even if DebugSearch is set, don't announce our change of
|
---|
1588 | * directory, since we're not going to emit a subsequent
|
---|
1589 | * announcement of a call to stat() anyway, as we're about
|
---|
1590 | * to exec something.
|
---|
1591 | */
|
---|
1592 | if (starting_desc < 0
|
---|
1593 | ? chdir (starting_dir) != 0
|
---|
1594 | : fchdir (starting_desc) != 0)
|
---|
1595 | {
|
---|
1596 | error (0, errno, "%s", starting_dir);
|
---|
1597 | _exit (1);
|
---|
1598 | }
|
---|
1599 | }
|
---|
1600 |
|
---|
1601 | execvp (buildstate->cmd_argv[0], buildstate->cmd_argv);
|
---|
1602 | error (0, errno, "%s", buildstate->cmd_argv[0]);
|
---|
1603 | _exit (1);
|
---|
1604 | }
|
---|
1605 |
|
---|
1606 |
|
---|
1607 | /* In parent; set up for next time. */
|
---|
1608 | bc_clear_args(ctl, buildstate);
|
---|
1609 |
|
---|
1610 |
|
---|
1611 | while (waitpid (child_pid, &wait_status, 0) == (pid_t) -1)
|
---|
1612 | {
|
---|
1613 | if (errno != EINTR)
|
---|
1614 | {
|
---|
1615 | error (0, errno, _("error waiting for %s"), buildstate->cmd_argv[0]);
|
---|
1616 | state.exit_status = 1;
|
---|
1617 | return 0; /* FAIL */
|
---|
1618 | }
|
---|
1619 | }
|
---|
1620 |
|
---|
1621 | if (WIFSIGNALED (wait_status))
|
---|
1622 | {
|
---|
1623 | error (0, 0, _("%s terminated by signal %d"),
|
---|
1624 | buildstate->cmd_argv[0], WTERMSIG (wait_status));
|
---|
1625 |
|
---|
1626 | if (execp->multiple)
|
---|
1627 | {
|
---|
1628 | /* -exec \; just returns false if the invoked command fails.
|
---|
1629 | * -exec {} + returns true if the invoked command fails, but
|
---|
1630 | * sets the program exit status.
|
---|
1631 | */
|
---|
1632 | state.exit_status = 1;
|
---|
1633 | }
|
---|
1634 |
|
---|
1635 | return 1; /* OK */
|
---|
1636 | }
|
---|
1637 |
|
---|
1638 | if (0 == WEXITSTATUS (wait_status))
|
---|
1639 | {
|
---|
1640 | return 1; /* OK */
|
---|
1641 | }
|
---|
1642 | else
|
---|
1643 | {
|
---|
1644 | if (execp->multiple)
|
---|
1645 | {
|
---|
1646 | /* -exec \; just returns false if the invoked command fails.
|
---|
1647 | * -exec {} + returns true if the invoked command fails, but
|
---|
1648 | * sets the program exit status.
|
---|
1649 | */
|
---|
1650 | state.exit_status = 1;
|
---|
1651 | }
|
---|
1652 | return 0; /* FAIL */
|
---|
1653 | }
|
---|
1654 |
|
---|
1655 | }
|
---|
1656 |
|
---|
1657 |
|
---|
1658 | /* Return a static string formatting the time WHEN according to the
|
---|
1659 | strftime format character KIND. */
|
---|
1660 |
|
---|
1661 | static char *
|
---|
1662 | format_date (time_t when, int kind)
|
---|
1663 | {
|
---|
1664 | static char buf[MAX (LONGEST_HUMAN_READABLE + 2, 64)];
|
---|
1665 | struct tm *tm;
|
---|
1666 | char fmt[6];
|
---|
1667 |
|
---|
1668 | fmt[0] = '%';
|
---|
1669 | fmt[1] = kind;
|
---|
1670 | fmt[2] = '\0';
|
---|
1671 | if (kind == '+')
|
---|
1672 | strcpy (fmt, "%F+%T");
|
---|
1673 |
|
---|
1674 | if (kind != '@'
|
---|
1675 | && (tm = localtime (&when))
|
---|
1676 | && strftime (buf, sizeof buf, fmt, tm))
|
---|
1677 | return buf;
|
---|
1678 | else
|
---|
1679 | {
|
---|
1680 | uintmax_t w = when;
|
---|
1681 | char *p = human_readable (when < 0 ? -w : w, buf + 1,
|
---|
1682 | human_ceiling, 1, 1);
|
---|
1683 | if (when < 0)
|
---|
1684 | *--p = '-';
|
---|
1685 | return p;
|
---|
1686 | }
|
---|
1687 | }
|
---|
1688 |
|
---|
1689 | static char *
|
---|
1690 | ctime_format (time_t when)
|
---|
1691 | {
|
---|
1692 | char *r = ctime (&when);
|
---|
1693 | if (!r)
|
---|
1694 | {
|
---|
1695 | /* The time cannot be represented as a struct tm.
|
---|
1696 | Output it as an integer. */
|
---|
1697 | return format_date (when, '@');
|
---|
1698 | }
|
---|
1699 | else
|
---|
1700 | {
|
---|
1701 | /* Remove the trailing newline from the ctime output,
|
---|
1702 | being careful not to assume that the output is fixed-width. */
|
---|
1703 | *strchr (r, '\n') = '\0';
|
---|
1704 | return r;
|
---|
1705 | }
|
---|
1706 | }
|
---|
1707 | |
---|
1708 |
|
---|
1709 | /* Copy STR into BUF and trim blanks from the end of BUF.
|
---|
1710 | Return BUF. */
|
---|
1711 |
|
---|
1712 | static char *
|
---|
1713 | blank_rtrim (str, buf)
|
---|
1714 | char *str;
|
---|
1715 | char *buf;
|
---|
1716 | {
|
---|
1717 | int i;
|
---|
1718 |
|
---|
1719 | if (str == NULL)
|
---|
1720 | return (NULL);
|
---|
1721 | strcpy (buf, str);
|
---|
1722 | i = strlen (buf) - 1;
|
---|
1723 | while ((i >= 0) && ((buf[i] == ' ') || buf[i] == '\t'))
|
---|
1724 | i--;
|
---|
1725 | buf[++i] = '\0';
|
---|
1726 | return (buf);
|
---|
1727 | }
|
---|
1728 | |
---|
1729 |
|
---|
1730 | /* Print out the predicate list starting at NODE. */
|
---|
1731 | void
|
---|
1732 | print_list (FILE *fp, struct predicate *node)
|
---|
1733 | {
|
---|
1734 | struct predicate *cur;
|
---|
1735 | char name[256];
|
---|
1736 |
|
---|
1737 | cur = node;
|
---|
1738 | while (cur != NULL)
|
---|
1739 | {
|
---|
1740 | fprintf (fp, "%s ", blank_rtrim (cur->p_name, name));
|
---|
1741 | cur = cur->pred_next;
|
---|
1742 | }
|
---|
1743 | fprintf (fp, "\n");
|
---|
1744 | }
|
---|
1745 | |
---|
1746 |
|
---|
1747 | /* Print out the predicate list starting at NODE. */
|
---|
1748 | static void
|
---|
1749 | print_parenthesised(FILE *fp, struct predicate *node)
|
---|
1750 | {
|
---|
1751 | int parens = 0;
|
---|
1752 |
|
---|
1753 | if (node)
|
---|
1754 | {
|
---|
1755 | if ( ( (node->pred_func == pred_or)
|
---|
1756 | || (node->pred_func == pred_and) )
|
---|
1757 | && node->pred_left == NULL)
|
---|
1758 | {
|
---|
1759 | /* We print "<nothing> or X" as just "X"
|
---|
1760 | * We print "<nothing> and X" as just "X"
|
---|
1761 | */
|
---|
1762 | print_parenthesised(fp, node->pred_right);
|
---|
1763 | }
|
---|
1764 | else
|
---|
1765 | {
|
---|
1766 | if (node->pred_left || node->pred_right)
|
---|
1767 | parens = 1;
|
---|
1768 |
|
---|
1769 | if (parens)
|
---|
1770 | fprintf(fp, "%s", " ( ");
|
---|
1771 | print_optlist(fp, node);
|
---|
1772 | if (parens)
|
---|
1773 | fprintf(fp, "%s", " ) ");
|
---|
1774 | }
|
---|
1775 | }
|
---|
1776 | }
|
---|
1777 | |
---|
1778 |
|
---|
1779 | void
|
---|
1780 | print_optlist (FILE *fp, const struct predicate *p)
|
---|
1781 | {
|
---|
1782 | if (p)
|
---|
1783 | {
|
---|
1784 | print_parenthesised(fp, p->pred_left);
|
---|
1785 | fprintf (fp,
|
---|
1786 | "%s%s",
|
---|
1787 | p->need_stat ? "[call stat] " : "",
|
---|
1788 | p->need_type ? "[need type] " : "");
|
---|
1789 | print_predicate(fp, p);
|
---|
1790 | fprintf(fp, " [%g] ", p->est_success_rate);
|
---|
1791 | print_parenthesised(fp, p->pred_right);
|
---|
1792 | }
|
---|
1793 | }
|
---|
1794 | |
---|
1795 |
|
---|
1796 | void
|
---|
1797 | pred_sanity_check(const struct predicate *predicates)
|
---|
1798 | {
|
---|
1799 | const struct predicate *p;
|
---|
1800 |
|
---|
1801 | for (p=predicates; p != NULL; p=p->pred_next)
|
---|
1802 | {
|
---|
1803 | /* All predicates must do something. */
|
---|
1804 | assert(p->pred_func != NULL);
|
---|
1805 |
|
---|
1806 | /* All predicates must have a parser table entry. */
|
---|
1807 | assert(p->parser_entry != NULL);
|
---|
1808 |
|
---|
1809 | /* If the parser table tells us that just one predicate function is
|
---|
1810 | * possible, verify that that is still the one that is in effect.
|
---|
1811 | * If the parser has NULL for the predicate function, that means that
|
---|
1812 | * the parse_xxx function fills it in, so we can't check it.
|
---|
1813 | */
|
---|
1814 | if (p->parser_entry->pred_func)
|
---|
1815 | {
|
---|
1816 | assert(p->parser_entry->pred_func == p->pred_func);
|
---|
1817 | }
|
---|
1818 |
|
---|
1819 | switch (p->parser_entry->type)
|
---|
1820 | {
|
---|
1821 | /* Options all take effect during parsing, so there should
|
---|
1822 | * be no predicate entries corresponding to them. Hence we
|
---|
1823 | * should not see any ARG_OPTION or ARG_POSITIONAL_OPTION
|
---|
1824 | * items.
|
---|
1825 | *
|
---|
1826 | * This is a silly way of coding this test, but it prevents
|
---|
1827 | * a compiler warning (i.e. otherwise it would think that
|
---|
1828 | * there would be case statements missing).
|
---|
1829 | */
|
---|
1830 | case ARG_OPTION:
|
---|
1831 | case ARG_POSITIONAL_OPTION:
|
---|
1832 | assert(p->parser_entry->type != ARG_OPTION);
|
---|
1833 | assert(p->parser_entry->type != ARG_POSITIONAL_OPTION);
|
---|
1834 | break;
|
---|
1835 |
|
---|
1836 | case ARG_ACTION:
|
---|
1837 | assert(p->side_effects); /* actions have side effects. */
|
---|
1838 | if (p->pred_func != pred_prune && p->pred_func != pred_quit)
|
---|
1839 | {
|
---|
1840 | /* actions other than -prune and -quit should
|
---|
1841 | * inhibit the default -print
|
---|
1842 | */
|
---|
1843 | assert(p->no_default_print);
|
---|
1844 | }
|
---|
1845 | break;
|
---|
1846 |
|
---|
1847 | case ARG_PUNCTUATION:
|
---|
1848 | case ARG_TEST:
|
---|
1849 | case ARG_NOOP:
|
---|
1850 | /* Punctuation and tests should have no side
|
---|
1851 | * effects and not inhibit default print.
|
---|
1852 | */
|
---|
1853 | assert(!p->no_default_print);
|
---|
1854 | assert(!p->side_effects);
|
---|
1855 | break;
|
---|
1856 |
|
---|
1857 | }
|
---|
1858 | }
|
---|
1859 | }
|
---|