source: trunk/essentials/sys-apps/findutils/find/util.c

Last change on this file was 3170, checked in by bird, 18 years ago

findutils 4.3.2

File size: 18.1 KB
Line 
1/* util.c -- functions for initializing new tree elements, and other things.
2 Copyright (C) 1990, 91, 92, 93, 94, 2000, 2003, 2004, 2005 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
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.
13
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
17 USA.
18*/
19
20#include "defs.h"
21
22#ifdef HAVE_FCNTL_H
23#include <fcntl.h>
24#else
25#include <sys/file.h>
26#endif
27#ifdef HAVE_SYS_UTSNAME_H
28#include <sys/utsname.h>
29#endif
30
31#include "xalloc.h"
32#include "quotearg.h"
33
34
35#if ENABLE_NLS
36# include <libintl.h>
37# define _(Text) gettext (Text)
38#else
39# define _(Text) Text
40#endif
41#ifdef gettext_noop
42# define N_(String) gettext_noop (String)
43#else
44/* See locate.c for explanation as to why not use (String) */
45# define N_(String) String
46#endif
47
48#include <ctype.h>
49#include <string.h>
50#include <limits.h>
51#include <assert.h>
52
53
54
55struct debug_option_assoc
56{
57 char *name;
58 int val;
59 char *docstring;
60};
61static struct debug_option_assoc debugassoc[] =
62 {
63 { "help", DebugHelp, "Explain the various -D options" },
64 { "tree", DebugExpressionTree, "Display the expression tree" },
65 { "search",DebugSearch, "Navigate the directory tree verbosely" },
66 { "stat", DebugStat, "Trace calls to stat(2) and lstat(2)" },
67 { "opt", DebugExpressionTree|DebugTreeOpt, "Show diagnostic information relating to optimisation" }
68 };
69#define N_DEBUGASSOC (sizeof(debugassoc)/sizeof(debugassoc[0]))
70
71
72
73
74
75/* Add a primary of predicate type PRED_FUNC (described by ENTRY) to the predicate input list.
76
77 Return a pointer to the predicate node just inserted.
78
79 Fills in the following cells of the new predicate node:
80
81 pred_func PRED_FUNC
82 args(.str) NULL
83 p_type PRIMARY_TYPE
84 p_prec NO_PREC
85
86 Other cells that need to be filled in are defaulted by
87 get_new_pred_chk_op, which is used to insure that the prior node is
88 either not there at all (we are the very first node) or is an
89 operator. */
90
91struct predicate *
92insert_primary_withpred (const struct parser_table *entry, PRED_FUNC pred_func)
93{
94 struct predicate *new_pred;
95
96 new_pred = get_new_pred_chk_op (entry);
97 new_pred->pred_func = pred_func;
98 new_pred->p_name = entry->parser_name;
99 new_pred->args.str = NULL;
100 new_pred->p_type = PRIMARY_TYPE;
101 new_pred->p_prec = NO_PREC;
102 return new_pred;
103}
104
105/* Add a primary described by ENTRY to the predicate input list.
106
107 Return a pointer to the predicate node just inserted.
108
109 Fills in the following cells of the new predicate node:
110
111 pred_func PRED_FUNC
112 args(.str) NULL
113 p_type PRIMARY_TYPE
114 p_prec NO_PREC
115
116 Other cells that need to be filled in are defaulted by
117 get_new_pred_chk_op, which is used to insure that the prior node is
118 either not there at all (we are the very first node) or is an
119 operator. */
120struct predicate *
121insert_primary (const struct parser_table *entry)
122{
123 assert(entry->pred_func != NULL);
124 return insert_primary_withpred(entry, entry->pred_func);
125}
126
127
128
129
130static void
131show_valid_debug_options(FILE *fp, int full)
132{
133 int i;
134 if (full)
135 {
136 fprintf(fp, "Valid arguments for -D:\n");
137 for (i=0; i<N_DEBUGASSOC; ++i)
138 {
139 fprintf(fp, "%-10s %s\n",
140 debugassoc[i].name,
141 debugassoc[i].docstring);
142 }
143 }
144 else
145 {
146 for (i=0; i<N_DEBUGASSOC; ++i)
147 {
148 fprintf(fp, "%s%s", (i>0 ? "|" : ""), debugassoc[i].name);
149 }
150 }
151}
152
153
154void
155usage (FILE *fp, int status, char *msg)
156{
157 size_t i;
158
159 if (msg)
160 fprintf (fp, "%s: %s\n", program_name, msg);
161
162 fprintf (fp, _("Usage: %s [-H] [-L] [-P] [-Olevel] [-D "), program_name);
163 show_valid_debug_options(fp, 0);
164 fprintf (fp, _("] [path...] [expression]\n"));
165 if (0 != status)
166 exit (status);
167}
168
169
170
171/* Get the stat information for a file, if it is
172 * not already known.
173 */
174int
175get_statinfo (const char *pathname, const char *name, struct stat *p)
176{
177 if (!state.have_stat && (*options.xstat) (name, p) != 0)
178 {
179 if (!options.ignore_readdir_race || (errno != ENOENT) )
180 {
181 error (0, errno, "%s", pathname);
182 state.exit_status = 1;
183 }
184 return -1;
185 }
186 state.have_stat = true;
187 state.have_type = true;
188 state.type = p->st_mode;
189 return 0;
190}
191
192
193
194
195/* Get the stat/type information for a file, if it is
196 * not already known.
197 */
198int
199get_info (const char *pathname,
200 const char *name,
201 struct stat *p,
202 struct predicate *pred_ptr)
203{
204 /* If we need the full stat info, or we need the type info but don't
205 * already have it, stat the file now.
206 */
207 (void) name;
208 if (pred_ptr->need_stat)
209 {
210 return get_statinfo(pathname, state.rel_pathname, p);
211 }
212 if ((pred_ptr->need_type && (0 == state.have_type)))
213 {
214 return get_statinfo(pathname, state.rel_pathname, p);
215 }
216 return 0;
217}
218
219
220/* Determine if we can use O_NOFOLLOW.
221 */
222#if defined(O_NOFOLLOW)
223boolean
224check_nofollow(void)
225{
226 struct utsname uts;
227 float release;
228
229 if (0 == uname(&uts))
230 {
231 /* POSIX requires that atof() ignore "unrecognised suffixes". */
232 release = atof(uts.release);
233
234 if (0 == strcmp("Linux", uts.sysname))
235 {
236 /* Linux kernels 2.1.126 and earlier ignore the O_NOFOLLOW flag. */
237 return release >= 2.2; /* close enough */
238 }
239 else if (0 == strcmp("FreeBSD", uts.sysname))
240 {
241 /* FreeBSD 3.0-CURRENT and later support it */
242 return release >= 3.1;
243 }
244 }
245
246 /* Well, O_NOFOLLOW was defined, so we'll try to use it. */
247 return true;
248}
249#endif
250
251
252
253
254/* Examine the predicate list for instances of -execdir or -okdir
255 * which have been terminated with '+' (build argument list) rather
256 * than ';' (singles only). If there are any, run them (this will
257 * have no effect if there are no arguments waiting).
258 */
259void
260complete_pending_execdirs(struct predicate *p)
261{
262#if defined(NEW_EXEC)
263 if (NULL == p)
264 return;
265
266 complete_pending_execdirs(p->pred_left);
267
268 if (p->pred_func == pred_execdir || p->pred_func == pred_okdir)
269 {
270 /* It's an exec-family predicate. p->args.exec_val is valid. */
271 if (p->args.exec_vec.multiple)
272 {
273 struct exec_val *execp = &p->args.exec_vec;
274
275 /* This one was terminated by '+' and so might have some
276 * left... Run it if necessary.
277 */
278 if (execp->state.todo)
279 {
280 /* There are not-yet-executed arguments. */
281 launch (&execp->ctl, &execp->state);
282 }
283 }
284 }
285
286 complete_pending_execdirs(p->pred_right);
287#else
288 /* nothing to do. */
289 return;
290#endif
291}
292
293
294
295/* Examine the predicate list for instances of -exec which have been
296 * terminated with '+' (build argument list) rather than ';' (singles
297 * only). If there are any, run them (this will have no effect if
298 * there are no arguments waiting).
299 */
300void
301complete_pending_execs(struct predicate *p)
302{
303#if defined(NEW_EXEC)
304 if (NULL == p)
305 return;
306
307 complete_pending_execs(p->pred_left);
308
309 /* It's an exec-family predicate then p->args.exec_val is valid
310 * and we can check it.
311 */
312 if (p->pred_func == pred_exec && p->args.exec_vec.multiple)
313 {
314 struct exec_val *execp = &p->args.exec_vec;
315
316 /* This one was terminated by '+' and so might have some
317 * left... Run it if necessary. Set state.exit_status if
318 * there are any problems.
319 */
320 if (execp->state.todo)
321 {
322 /* There are not-yet-executed arguments. */
323 launch (&execp->ctl, &execp->state);
324 }
325 }
326
327 complete_pending_execs(p->pred_right);
328#else
329 /* nothing to do. */
330 return;
331#endif
332}
333
334
335
336/* Complete any outstanding commands.
337 */
338void
339cleanup(void)
340{
341 struct predicate *eval_tree = get_eval_tree();
342 if (eval_tree)
343 {
344 complete_pending_execs(eval_tree);
345 complete_pending_execdirs(eval_tree);
346 }
347}
348
349
350
351static int
352fallback_stat(const char *name, struct stat *p, int prev_rv)
353{
354 /* Our original stat() call failed. Perhaps we can't follow a
355 * symbolic link. If that might be the problem, lstat() the link.
356 * Otherwise, admit defeat.
357 */
358 switch (errno)
359 {
360 case ENOENT:
361 case ENOTDIR:
362 if (options.debug_options & DebugStat)
363 fprintf(stderr, "fallback_stat(): stat(%s) failed; falling back on lstat()\n", name);
364 return lstat(name, p);
365
366 case EACCES:
367 case EIO:
368 case ELOOP:
369 case ENAMETOOLONG:
370#ifdef EOVERFLOW
371 case EOVERFLOW: /* EOVERFLOW is not #defined on UNICOS. */
372#endif
373 default:
374 return prev_rv;
375 }
376}
377
378
379
380/* optionh_stat() implements the stat operation when the -H option is
381 * in effect.
382 *
383 * If the item to be examined is a command-line argument, we follow
384 * symbolic links. If the stat() call fails on the command-line item,
385 * we fall back on the properties of the symbolic link.
386 *
387 * If the item to be examined is not a command-line argument, we
388 * examine the link itself.
389 */
390int
391optionh_stat(const char *name, struct stat *p)
392{
393 if (0 == state.curdepth)
394 {
395 /* This file is from the command line; deference the link (if it
396 * is a link).
397 */
398 int rv = stat(name, p);
399 if (0 == rv)
400 return 0; /* success */
401 else
402 return fallback_stat(name, p, rv);
403 }
404 else
405 {
406 /* Not a file on the command line; do not dereference the link.
407 */
408 return lstat(name, p);
409 }
410}
411
412
413/* optionl_stat() implements the stat operation when the -L option is
414 * in effect. That option makes us examine the thing the symbolic
415 * link points to, not the symbolic link itself.
416 */
417int
418optionl_stat(const char *name, struct stat *p)
419{
420 int rv = stat(name, p);
421 if (0 == rv)
422 return 0; /* normal case. */
423 else
424 return fallback_stat(name, p, rv);
425}
426
427
428/* optionp_stat() implements the stat operation when the -P option is
429 * in effect (this is also the default). That option makes us examine
430 * the symbolic link itself, not the thing it points to.
431 */
432int
433optionp_stat(const char *name, struct stat *p)
434{
435 return lstat(name, p);
436}
437
438
439
440static uintmax_t stat_count = 0u;
441
442int
443debug_stat (const char *file, struct stat *bufp)
444{
445 ++stat_count;
446 fprintf (stderr, "debug_stat (%s)\n", file);
447 switch (options.symlink_handling)
448 {
449 case SYMLINK_ALWAYS_DEREF:
450 return optionl_stat(file, bufp);
451 case SYMLINK_DEREF_ARGSONLY:
452 return optionh_stat(file, bufp);
453 case SYMLINK_NEVER_DEREF:
454 return optionp_stat(file, bufp);
455 }
456 /*NOTREACHED*/
457 assert(false);
458 return -1;
459}
460
461
462
463int
464following_links(void)
465{
466 switch (options.symlink_handling)
467 {
468 case SYMLINK_ALWAYS_DEREF:
469 return 1;
470 case SYMLINK_DEREF_ARGSONLY:
471 return (state.curdepth == 0);
472 case SYMLINK_NEVER_DEREF:
473 default:
474 return 0;
475 }
476}
477
478
479
480/* Take a "mode" indicator and fill in the files of 'state'.
481 */
482int
483digest_mode(mode_t mode,
484 const char *pathname,
485 const char *name,
486 struct stat *pstat,
487 boolean leaf)
488{
489 /* If we know the type of the directory entry, and it is not a
490 * symbolic link, we may be able to avoid a stat() or lstat() call.
491 */
492 if (mode)
493 {
494 if (S_ISLNK(mode) && following_links())
495 {
496 /* mode is wrong because we should have followed the symlink. */
497 if (get_statinfo(pathname, name, pstat) != 0)
498 return 0;
499 mode = state.type = pstat->st_mode;
500 state.have_type = true;
501 }
502 else
503 {
504 state.have_type = true;
505 pstat->st_mode = state.type = mode;
506 }
507 }
508 else
509 {
510 /* Mode is not yet known; may have to stat the file unless we
511 * can deduce that it is not a directory (which is all we need to
512 * know at this stage)
513 */
514 if (leaf)
515 {
516 state.have_stat = false;
517 state.have_type = false;;
518 state.type = 0;
519 }
520 else
521 {
522 if (get_statinfo(pathname, name, pstat) != 0)
523 return 0;
524
525 /* If -L is in effect and we are dealing with a symlink,
526 * st_mode is the mode of the pointed-to file, while mode is
527 * the mode of the directory entry (S_IFLNK). Hence now
528 * that we have the stat information, override "mode".
529 */
530 state.type = pstat->st_mode;
531 state.have_type = true;
532 }
533 }
534
535 /* success. */
536 return 1;
537}
538
539
540
541/* Return true if there are no predicates with no_default_print in
542 predicate list PRED, false if there are any.
543 Returns true if default print should be performed */
544
545boolean
546default_prints (struct predicate *pred)
547{
548 while (pred != NULL)
549 {
550 if (pred->no_default_print)
551 return (false);
552 pred = pred->pred_next;
553 }
554 return (true);
555}
556
557boolean
558looks_like_expression(const char *arg, boolean leading)
559{
560 switch (arg[0])
561 {
562 case '-':
563 if (arg[1]) /* "-foo" is an expression. */
564 return true;
565 else
566 return false; /* Just "-" is a filename. */
567 break;
568
569 case ')':
570 case ',':
571 if (arg[1])
572 return false; /* )x and ,z are not expressions */
573 else
574 return !leading; /* A leading ) or , is not either */
575
576 /* ( and ! are part of an expression, but (2 and !foo are
577 * filenames.
578 */
579 case '!':
580 case '(':
581 if (arg[1])
582 return false;
583 else
584 return true;
585
586 default:
587 return false;
588 }
589}
590
591
592static void
593process_debug_options(char *arg)
594{
595 const char *p;
596 char *token_context = NULL;
597 const char delimiters[] = ",";
598 boolean empty = true;
599 size_t i;
600
601 p = strtok_r(arg, delimiters, &token_context);
602 while (p)
603 {
604 empty = false;
605
606 for (i=0; i<N_DEBUGASSOC; ++i)
607 {
608 if (0 == strcmp(debugassoc[i].name, p))
609 {
610 options.debug_options |= debugassoc[i].val;
611 break;
612 }
613 }
614 if (i >= N_DEBUGASSOC)
615 {
616 error(0, 0, _("Ignoring unrecognised debug flag %s"),
617 quotearg_n_style(0, locale_quoting_style, arg));
618 }
619 p = strtok_r(NULL, delimiters, &token_context);
620 }
621 if (empty)
622 {
623 error(1, 0, _("Empty argument to the -D option."));
624 }
625 else if (options.debug_options & DebugHelp)
626 {
627 show_valid_debug_options(stdout, 1);
628 exit(0);
629 }
630}
631
632
633static void
634process_optimisation_option(const char *arg)
635{
636 if (0 == arg[0])
637 {
638 error(1, 0, _("The -O option must be immediately followed by a decimal integer"));
639 }
640 else
641 {
642 unsigned long opt_level;
643 char *end;
644
645 if (!isdigit( (unsigned char) arg[0] ))
646 {
647 error(1, 0, _("Please specify a decimal number immediately after -O"));
648 }
649 else
650 {
651 int prev_errno = errno;
652 errno = 0;
653
654 opt_level = strtoul(arg, &end, 10);
655 if ( (0==opt_level) && (end==arg) )
656 {
657 error(1, 0, _("Please specify a decimal number immediately after -O"));
658 }
659 else if (*end)
660 {
661 /* unwanted trailing characters. */
662 error(1, 0, _("Invalid optimisation level %s"), arg);
663 }
664 else if ( (ULONG_MAX==opt_level) && errno)
665 {
666 error(1, errno, _("Invalid optimisation level %s"), arg);
667 }
668 else if (opt_level > USHRT_MAX)
669 {
670 /* tricky to test, as on some platforms USHORT_MAX and ULONG_MAX
671 * can have the same value, though this is unusual.
672 */
673 error(1, 0, _("Optimisation level %lu is too high. "
674 "If you want to find files very quickly, "
675 "consider using GNU locate."),
676 opt_level);
677 }
678 else
679 {
680 options.optimisation_level = opt_level;
681 errno = prev_errno;
682 }
683 }
684 }
685}
686
687
688int
689process_leading_options(int argc, char *argv[])
690{
691 int i, end_of_leading_options;
692
693 for (i=1; (end_of_leading_options = i) < argc; ++i)
694 {
695 if (0 == strcmp("-H", argv[i]))
696 {
697 /* Meaning: dereference symbolic links on command line, but nowhere else. */
698 set_follow_state(SYMLINK_DEREF_ARGSONLY);
699 }
700 else if (0 == strcmp("-L", argv[i]))
701 {
702 /* Meaning: dereference all symbolic links. */
703 set_follow_state(SYMLINK_ALWAYS_DEREF);
704 }
705 else if (0 == strcmp("-P", argv[i]))
706 {
707 /* Meaning: never dereference symbolic links (default). */
708 set_follow_state(SYMLINK_NEVER_DEREF);
709 }
710 else if (0 == strcmp("--", argv[i]))
711 {
712 /* -- signifies the end of options. */
713 end_of_leading_options = i+1; /* Next time start with the next option */
714 break;
715 }
716 else if (0 == strcmp("-D", argv[i]))
717 {
718 process_debug_options(argv[i+1]);
719 ++i; /* skip the argument too. */
720 }
721 else if (0 == strncmp("-O", argv[i], 2))
722 {
723 process_optimisation_option(argv[i]+2);
724 }
725 else
726 {
727 /* Hmm, must be one of
728 * (a) A path name
729 * (b) A predicate
730 */
731 end_of_leading_options = i; /* Next time start with this option */
732 break;
733 }
734 }
735 return end_of_leading_options;
736}
737
738
739void
740set_option_defaults(struct options *p)
741{
742 /* We call check_nofollow() before setlocale() because the numbers
743 * for which we check (in the results of uname) definitiely have "."
744 * as the decimal point indicator even under locales for which that
745 * is not normally true. Hence atof() would do the wrong thing
746 * if we call it after setlocale().
747 */
748#ifdef O_NOFOLLOW
749 p->open_nofollow_available = check_nofollow();
750#else
751 p->open_nofollow_available = false;
752#endif
753
754 p->regex_options = RE_SYNTAX_EMACS;
755
756 if (isatty(0))
757 {
758 p->warnings = true;
759 p->literal_control_chars = false;
760 }
761 else
762 {
763 p->warnings = false;
764 p->literal_control_chars = false; /* may change */
765 }
766
767
768 p->do_dir_first = true;
769 p->maxdepth = p->mindepth = -1;
770 p->start_time = time (NULL);
771 p->cur_day_start = p->start_time - DAYSECS;
772 p->full_days = false;
773 p->stay_on_filesystem = false;
774 p->ignore_readdir_race = false;
775
776 if (getenv("POSIXLY_CORRECT"))
777 p->output_block_size = 512;
778 else
779 p->output_block_size = 1024;
780
781 p->debug_options = 0uL;
782 p->optimisation_level = 0;
783
784 if (getenv("FIND_BLOCK_SIZE"))
785 {
786 error (1, 0, _("The environment variable FIND_BLOCK_SIZE is not supported, the only thing that affects the block size is the POSIXLY_CORRECT environment variable"));
787 }
788
789#if LEAF_OPTIMISATION
790 /* The leaf optimisation is enabled. */
791 p->no_leaf_check = false;
792#else
793 /* The leaf optimisation is disabled. */
794 p->no_leaf_check = true;
795#endif
796
797 set_follow_state(SYMLINK_NEVER_DEREF); /* The default is equivalent to -P. */
798}
Note: See TracBrowser for help on using the repository browser.