1 /* locate -- search databases for filenames that match patterns
2 Copyright (C) 1994, 1996, 1998, 1999, 2000, 2003,
3 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
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)
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.
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,
21 /* Usage: locate [options] pattern...
23 Scan a pathname list for the full pathname of a file, given only
24 a piece of the name (possibly containing shell globbing metacharacters).
25 The list has been processed with front-compression, which reduces
26 the list size by a factor of 4-5.
27 Recognizes two database formats, old and new. The old format is
28 bigram coded, which reduces space by a further 20-25% and uses the
29 following encoding of the database bytes:
31 0-28 likeliest differential counts + offset (14) to make nonnegative
32 30 escape code for out-of-range count to follow in next halfword
33 128-255 bigram codes (the 128 most common, as determined by `updatedb')
34 32-127 single character (printable) ASCII remainder
36 Earlier versions of GNU locate used to use a novel two-tiered
37 string search technique, which was described in Usenix ;login:, Vol
38 8, No 1, February/March, 1983, p. 8.
40 However, latterly code changes to provide additional functionality
41 became dificult to make with the existing reading scheme, and so
42 we no longer perform the matching as efficiently as we used to (that is,
43 we no longer use the same algorithm).
45 The old algorithm was:
47 First, match a metacharacter-free subpattern and a partial
48 pathname BACKWARDS to avoid full expansion of the pathname list.
49 The time savings is 40-50% over forward matching, which cannot
50 efficiently handle overlapped search patterns and compressed
53 Then, match the actual shell glob pattern (if in this form)
54 against the candidate pathnames using the slower shell filename
58 Written by James A. Woods <jwoods@adobe.com>.
59 Modified by David MacKenzie <djm@gnu.org>.
60 Additional work by James Youngman and Bas van Gompel.
67 #include <sys/types.h>
68 #include <grp.h> /* for setgroups() */
75 /* The presence of unistd.h is assumed by gnulib these days, so we
76 * might as well assume it too.
78 /* We need <unistd.h> for isatty(). */
106 # include <libintl.h>
107 # define _(Text) gettext (Text)
109 # define _(Text) Text
110 #define textdomain(Domain)
111 #define bindtextdomain(Package, Directory)
114 # define N_(String) gettext_noop (String)
116 /* We used to use (String) instead of just String, but apparentl;y ISO C
117 * doesn't allow this (at least, that's what HP said when someone reported
118 * this as a compiler bug). This is HP case number 1205608192. See
119 * also http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11250 (which references
120 * ANSI 3.5.7p14-15). The Intel icc compiler also rejects constructs
121 * like: static const char buf[] = ("string");
123 # define N_(String) String
126 #include "locatedb.h"
128 #include "../gnulib/lib/xalloc.h"
129 #include "../gnulib/lib/error.h"
130 #include "../gnulib/lib/human.h"
132 #include "closeout.h"
133 #include "nextelem.h"
136 #include "quotearg.h"
137 #include "printquoted.h"
138 #include "regextype.h"
139 #include "gnulib-version.h"
141 /* Note that this evaluates Ch many times. */
143 # define TOUPPER(Ch) toupper (Ch)
144 # define TOLOWER(Ch) tolower (Ch)
146 # define TOUPPER(Ch) (islower (Ch) ? toupper (Ch) : (Ch))
147 # define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
150 /* typedef enum {false, true} boolean; */
152 /* Warn if a database is older than this. 8 days allows for a weekly
153 update that takes up to a day to perform. */
154 static unsigned int warn_number_units
= 8;
156 /* Printable name of units used in WARN_SECONDS */
157 static const char warn_name_units
[] = N_("days");
158 #define SECONDS_PER_UNIT (60 * 60 * 24)
162 VISIT_CONTINUE
= 1, /* please call the next visitor */
163 VISIT_ACCEPTED
= 2, /* accepted, call no futher callbacks for this file */
164 VISIT_REJECTED
= 4, /* rejected, process next file. */
165 VISIT_ABORT
= 8 /* rejected, process no more files. */
168 enum ExistenceCheckType
170 ACCEPT_EITHER
, /* Corresponds to lack of -E/-e option */
171 ACCEPT_EXISTING
, /* Corresponds to option -e */
172 ACCEPT_NON_EXISTING
/* Corresponds to option -E */
175 /* Check for existence of files before printing them out? */
176 enum ExistenceCheckType check_existence
= ACCEPT_EITHER
;
178 static int follow_symlinks
= 1;
180 /* What to separate the results with. */
181 static int separator
= '\n';
183 static struct quoting_options
* quote_opts
= NULL
;
184 static bool stdout_is_a_tty
;
185 static bool print_quoted_filename
;
186 static bool results_were_filtered
;
188 /* static char* slocate_db_pathname = "/var/lib/slocate/slocate.db"; */
190 static const char *selected_secure_db
= NULL
;
193 /* Change the number of days old the database can be
194 * before we complain about it.
197 set_max_db_age(const char *s
)
200 unsigned long int val
;
201 /* XXX: we ignore the case where the input is negative, which is allowed(!). */
206 _("The argument argument for option --max-database-age must not be empty"));
210 /* We have to set errno here, otherwise when the function returns ULONG_MAX,
211 * we would not be able to tell if that is the correct answer, or whether it
212 * signifies an error.
215 val
= strtoul(s
, &end
, 10);
217 /* Diagnose number too large, non-numbes and trailing junk. */
218 if ((ULONG_MAX
== val
&& ERANGE
== errno
) ||
219 (0 == val
&& EINVAL
== errno
))
222 _("Invalid argument `%s' for option --max-database-age"),
227 /* errno wasn't set, don't print its message */
229 _("Invalid argument `%s' for option --max-database-age"),
234 warn_number_units
= val
;
240 /* Read in a 16-bit int, high byte first (network byte order). */
248 x
= (signed char) fgetc (fp
) << 8;
249 x
|= (fgetc (fp
) & 0xff);
253 const char * const metacharacters
= "*?[]\\";
255 /* Return nonzero if S contains any shell glob characters.
258 contains_metacharacter(const char *s
)
260 if (NULL
== strpbrk(s
, metacharacters
))
268 * Read bytes from FP into the buffer at offset OFFSET in (*BUF),
269 * until we reach DELIMITER or end-of-file. We reallocate the buffer
270 * as necessary, altering (*BUF) and (*SIZ) as appropriate. No assumption
271 * is made regarding the content of the data (i.e. the implementation is
272 * 8-bit clean, the only delimiter is DELIMITER).
274 * Written Fri May 23 18:41:16 2003 by James Youngman, because getstr()
275 * has been removed from gnulib.
277 * We call the function locate_read_str() to avoid a name clash with the curses
281 locate_read_str(char **buf
, size_t *siz
, FILE *fp
, int delimiter
, int offs
)
288 nread
= getdelim(&p
, &sz
, delimiter
, fp
);
293 needed
= offs
+ nread
+ 1u;
296 char *pnew
= realloc(*buf
, needed
);
299 return -1; /* FAIL */
307 memcpy((*buf
)+offs
, p
, nread
);
317 uintmax_t items_accepted
;
319 static struct locate_limits limits
;
324 uintmax_t compressed_bytes
;
325 uintmax_t total_filename_count
;
326 uintmax_t total_filename_length
;
327 uintmax_t whitespace_count
;
328 uintmax_t newline_count
;
329 uintmax_t highbit_filename_count
;
331 static struct locate_stats statistics
;
340 static struct stringbuf casebuf
;
343 struct regular_expression
345 struct re_pattern_buffer regex
; /* for --regex */
351 int c
; /* An input byte. */
352 char itemcount
; /* Indicates we're at the beginning of an slocate db. */
353 int count
; /* The length of the prefix shared with the previous database entry. */
355 char *original_filename
; /* The current input database entry. */
356 size_t pathsize
; /* Amount allocated for it. */
357 char *munged_filename
; /* path or base_name(path) */
358 FILE *fp
; /* The pathname database. */
359 const char *dbfile
; /* Its name, or "<stdin>" */
360 int slocatedb_format
; /* Allows us to cope with slocate's format variant */
361 /* for the old database format,
362 the first and second characters of the most common bigrams. */
368 typedef int (*visitfunc
)(struct process_data
*procdata
,
375 struct visitor
*next
;
379 static struct visitor
*inspectors
= NULL
;
380 static struct visitor
*lastinspector
= NULL
;
381 static struct visitor
*past_pat_inspector
= NULL
;
383 /* 0 or 1 pattern(s) */
385 process_simple(struct process_data
*procdata
)
387 int result
= VISIT_CONTINUE
;
388 const struct visitor
*p
= inspectors
;
390 while ( ((VISIT_CONTINUE
| VISIT_ACCEPTED
) & result
) && (NULL
!= p
) )
392 result
= (p
->inspector
)(procdata
, p
->context
);
399 /* Accept if any pattern matches. */
401 process_or (struct process_data
*procdata
)
403 int result
= VISIT_CONTINUE
;
404 const struct visitor
*p
= inspectors
;
406 while ( ((VISIT_CONTINUE
| VISIT_REJECTED
) & result
) && (past_pat_inspector
!= p
) )
408 result
= (p
->inspector
)(procdata
, p
->context
);
412 if (result
== VISIT_CONTINUE
)
413 result
= VISIT_REJECTED
;
414 if (result
& (VISIT_ABORT
| VISIT_REJECTED
))
417 p
= past_pat_inspector
;
418 result
= VISIT_CONTINUE
;
420 while ( (VISIT_CONTINUE
== result
) && (NULL
!= p
) )
422 result
= (p
->inspector
)(procdata
, p
->context
);
426 if (VISIT_CONTINUE
== result
)
427 return VISIT_ACCEPTED
;
432 /* Accept if all pattern match. */
434 process_and (struct process_data
*procdata
)
436 int result
= VISIT_CONTINUE
;
437 const struct visitor
*p
= inspectors
;
439 while ( ((VISIT_CONTINUE
| VISIT_ACCEPTED
) & result
) && (past_pat_inspector
!= p
) )
441 result
= (p
->inspector
)(procdata
, p
->context
);
445 if (result
== VISIT_CONTINUE
)
446 result
= VISIT_REJECTED
;
447 if (result
& (VISIT_ABORT
| VISIT_REJECTED
))
450 p
= past_pat_inspector
;
451 result
= VISIT_CONTINUE
;
453 while ( (VISIT_CONTINUE
== result
) && (NULL
!= p
) )
455 result
= (p
->inspector
)(procdata
, p
->context
);
459 if (VISIT_CONTINUE
== result
)
460 return VISIT_ACCEPTED
;
465 typedef int (*processfunc
)(struct process_data
*procdata
);
467 static processfunc mainprocessor
= NULL
;
470 add_visitor(visitfunc fn
, void *context
)
472 struct visitor
*p
= xmalloc(sizeof(struct visitor
));
474 p
->context
= context
;
477 if (NULL
== lastinspector
)
479 lastinspector
= inspectors
= p
;
483 lastinspector
->next
= p
;
491 visit_justprint_quoted(struct process_data
*procdata
, void *context
)
494 print_quoted (stdout
, quote_opts
, stdout_is_a_tty
,
496 procdata
->original_filename
);
498 return VISIT_CONTINUE
;
502 visit_justprint_unquoted(struct process_data
*procdata
, void *context
)
505 fputs(procdata
->original_filename
, stdout
);
507 return VISIT_CONTINUE
;
511 visit_old_format(struct process_data
*procdata
, void *context
)
516 /* Get the offset in the path where this path info starts. */
517 if (procdata
->c
== LOCATEDB_OLD_ESCAPE
)
518 procdata
->count
+= getw (procdata
->fp
) - LOCATEDB_OLD_OFFSET
;
520 procdata
->count
+= procdata
->c
- LOCATEDB_OLD_OFFSET
;
522 /* Overlay the old path with the remainder of the new. */
523 for (s
= procdata
->original_filename
+ procdata
->count
;
524 (procdata
->c
= getc (procdata
->fp
)) > LOCATEDB_OLD_ESCAPE
;)
525 if (procdata
->c
< 0200)
526 *s
++ = procdata
->c
; /* An ordinary character. */
529 /* Bigram markers have the high bit set. */
531 *s
++ = procdata
->bigram1
[procdata
->c
];
532 *s
++ = procdata
->bigram2
[procdata
->c
];
536 procdata
->munged_filename
= procdata
->original_filename
;
538 return VISIT_CONTINUE
;
543 visit_locate02_format(struct process_data
*procdata
, void *context
)
549 if (procdata
->slocatedb_format
)
551 if (procdata
->itemcount
== 0)
553 ungetc(procdata
->c
, procdata
->fp
);
557 else if (procdata
->itemcount
== 1)
559 procdata
->count
= procdata
->len
-1;
563 if (procdata
->c
== LOCATEDB_ESCAPE
)
564 procdata
->count
+= (short)get_short (procdata
->fp
);
565 else if (procdata
->c
> 127)
566 procdata
->count
+= procdata
->c
- 256;
568 procdata
->count
+= procdata
->c
;
573 if (procdata
->c
== LOCATEDB_ESCAPE
)
574 procdata
->count
+= (short)get_short (procdata
->fp
);
575 else if (procdata
->c
> 127)
576 procdata
->count
+= procdata
->c
- 256;
578 procdata
->count
+= procdata
->c
;
581 if (procdata
->count
> procdata
->len
|| procdata
->count
< 0)
583 /* This should not happen generally , but since we're
584 * reading in data which is outside our control, we
587 error(1, 0, _("locate database `%s' is corrupt or invalid"), procdata
->dbfile
);
590 /* Overlay the old path with the remainder of the new. */
591 nread
= locate_read_str (&procdata
->original_filename
, &procdata
->pathsize
,
592 procdata
->fp
, 0, procdata
->count
);
595 procdata
->c
= getc (procdata
->fp
);
596 procdata
->len
= procdata
->count
+ nread
;
597 s
= procdata
->original_filename
+ procdata
->len
- 1; /* Move to the last char in path. */
598 assert (s
[0] != '\0');
599 assert (s
[1] == '\0'); /* Our terminator. */
600 assert (s
[2] == '\0'); /* Added by locate_read_str. */
602 procdata
->munged_filename
= procdata
->original_filename
;
604 if (procdata
->slocatedb_format
)
606 /* Don't increment indefinitely, it might overflow. */
607 if (procdata
->itemcount
< 6)
609 ++(procdata
->itemcount
);
614 return VISIT_CONTINUE
;
618 visit_basename(struct process_data
*procdata
, void *context
)
621 procdata
->munged_filename
= base_name(procdata
->original_filename
);
623 return VISIT_CONTINUE
;
627 /* visit_existing_follow implements -L -e */
629 visit_existing_follow(struct process_data
*procdata
, void *context
)
634 /* munged_filename has been converted in some way (to lower case,
635 * or is just the base name of the file), and original_filename has not.
636 * Hence only original_filename is still actually the name of the file
637 * whose existence we would need to check.
639 if (stat(procdata
->original_filename
, &st
) != 0)
641 return VISIT_REJECTED
;
645 return VISIT_CONTINUE
;
649 /* visit_non_existing_follow implements -L -E */
651 visit_non_existing_follow(struct process_data
*procdata
, void *context
)
656 /* munged_filename has been converted in some way (to lower case,
657 * or is just the base name of the file), and original_filename has not.
658 * Hence only original_filename is still actually the name of the file
659 * whose existence we would need to check.
661 if (stat(procdata
->original_filename
, &st
) == 0)
663 return VISIT_REJECTED
;
667 return VISIT_CONTINUE
;
671 /* visit_existing_nofollow implements -P -e */
673 visit_existing_nofollow(struct process_data
*procdata
, void *context
)
678 /* munged_filename has been converted in some way (to lower case,
679 * or is just the base name of the file), and original_filename has not.
680 * Hence only original_filename is still actually the name of the file
681 * whose existence we would need to check.
683 if (lstat(procdata
->original_filename
, &st
) != 0)
685 return VISIT_REJECTED
;
689 return VISIT_CONTINUE
;
693 /* visit_non_existing_nofollow implements -P -E */
695 visit_non_existing_nofollow(struct process_data
*procdata
, void *context
)
700 /* munged_filename has been converted in some way (to lower case,
701 * or is just the base name of the file), and original_filename has not.
702 * Hence only original_filename is still actually the name of the file
703 * whose existence we would need to check.
705 if (lstat(procdata
->original_filename
, &st
) == 0)
707 return VISIT_REJECTED
;
711 return VISIT_CONTINUE
;
716 visit_substring_match_nocasefold(struct process_data
*procdata
, void *context
)
718 const char *pattern
= context
;
720 if (NULL
!= mbsstr(procdata
->munged_filename
, pattern
))
721 return VISIT_ACCEPTED
;
723 return VISIT_REJECTED
;
727 visit_substring_match_casefold(struct process_data
*procdata
, void *context
)
729 const char *pattern
= context
;
731 if (NULL
!= mbscasestr(procdata
->munged_filename
, pattern
))
732 return VISIT_ACCEPTED
;
734 return VISIT_REJECTED
;
739 visit_globmatch_nofold(struct process_data
*procdata
, void *context
)
741 const char *glob
= context
;
742 if (fnmatch(glob
, procdata
->munged_filename
, 0) != 0)
743 return VISIT_REJECTED
;
745 return VISIT_ACCEPTED
;
750 visit_globmatch_casefold(struct process_data
*procdata
, void *context
)
752 const char *glob
= context
;
753 if (fnmatch(glob
, procdata
->munged_filename
, FNM_CASEFOLD
) != 0)
754 return VISIT_REJECTED
;
756 return VISIT_ACCEPTED
;
761 visit_regex(struct process_data
*procdata
, void *context
)
763 struct regular_expression
*p
= context
;
764 const size_t len
= strlen(procdata
->munged_filename
);
766 int rv
= re_search (&p
->regex
, procdata
->munged_filename
,
768 (struct re_registers
*) NULL
);
771 return VISIT_REJECTED
; /* no match (-1), or internal error (-2) */
775 return VISIT_ACCEPTED
; /* match */
781 visit_stats(struct process_data
*procdata
, void *context
)
783 struct locate_stats
*p
= context
;
784 size_t len
= strlen(procdata
->original_filename
);
786 int highbit
, whitespace
, newline
;
788 ++(p
->total_filename_count
);
789 p
->total_filename_length
+= len
;
791 highbit
= whitespace
= newline
= 0;
792 for (s
=procdata
->original_filename
; *s
; ++s
)
794 if ( (int)(*s
) & 128 )
798 newline
= whitespace
= 1;
800 else if (isspace((unsigned char)*s
))
807 ++(p
->highbit_filename_count
);
809 ++(p
->whitespace_count
);
811 ++(p
->newline_count
);
813 return VISIT_CONTINUE
;
818 visit_limit(struct process_data
*procdata
, void *context
)
820 struct locate_limits
*p
= context
;
824 if (++p
->items_accepted
>= p
->limit
)
827 return VISIT_CONTINUE
;
831 visit_count(struct process_data
*procdata
, void *context
)
833 struct locate_limits
*p
= context
;
838 return VISIT_CONTINUE
;
841 /* Emit the statistics.
844 print_stats(int argc
, size_t database_file_size
)
846 char hbuf
[LONGEST_HUMAN_READABLE
+ 1];
848 printf(_("Locate database size: %s bytes\n"),
849 human_readable ((uintmax_t) database_file_size
,
850 hbuf
, human_ceiling
, 1, 1));
852 printf( (results_were_filtered
?
853 _("Matching Filenames: %s ") :
854 _("All Filenames: %s ")),
855 human_readable (statistics
.total_filename_count
,
856 hbuf
, human_ceiling
, 1, 1));
857 printf(_("with a cumulative length of %s bytes"),
858 human_readable (statistics
.total_filename_length
,
859 hbuf
, human_ceiling
, 1, 1));
861 printf(_("\n\tof which %s contain whitespace, "),
862 human_readable (statistics
.whitespace_count
,
863 hbuf
, human_ceiling
, 1, 1));
864 printf(_("\n\t%s contain newline characters, "),
865 human_readable (statistics
.newline_count
,
866 hbuf
, human_ceiling
, 1, 1));
867 printf(_("\n\tand %s contain characters with the high bit set.\n"),
868 human_readable (statistics
.highbit_filename_count
,
869 hbuf
, human_ceiling
, 1, 1));
873 if (results_were_filtered
)
875 printf(_("Some filenames may have been filtered out, "
876 "so we cannot compute the compression ratio.\n"));
880 if (statistics
.total_filename_length
)
882 printf(_("Compression ratio %4.2f%%\n"),
883 100.0 * ((double)statistics
.total_filename_length
884 - (double) database_file_size
)
885 / (double) statistics
.total_filename_length
);
889 printf(_("Compression ratio is undefined\n"));
897 * Return nonzero if the data we read in indicates that we are
898 * looking at a LOCATE02 locate database.
901 looking_at_gnu_locatedb (const char *data
, size_t len
)
903 if (len
< sizeof (LOCATEDB_MAGIC
))
905 else if (0 == memcmp (data
, LOCATEDB_MAGIC
, sizeof (LOCATEDB_MAGIC
)))
906 return 1; /* We saw the magic byte sequence */
912 * Return nonzero if the data we read in indicates that we are
913 * looking at an slocate database.
916 looking_at_slocate_locatedb (const char *filename
,
929 /* Check that the magic number is a one-byte string */
932 if (isdigit((unsigned char)data
[0]))
934 /* looks promising. */
935 *seclevel
= (data
[0] - '0');
939 /* Hmm, well it's probably an slocate database
940 * of some awsomely huge security level, like 2.
941 * We don't know how to handle those.
944 _("locate database `%s' looks like an slocate "
945 "database but it seems to have security level %c, "
946 "which GNU findutils does not currently support"),
963 /* Definitely not slocate. */
969 /* Print or count the entries in DBFILE that match shell globbing patterns in
970 ARGV. Return the number of entries matched. */
973 search_one_database (int argc
,
982 struct locate_limits
*plimit
,
988 char *pathpart
; /* A pattern to consider. */
989 int argn
; /* Index to current pattern in argv. */
990 int nread
; /* number of bytes read from an entry. */
991 struct process_data procdata
; /* Storage for data shared with visitors. */
992 int slocate_seclevel
;
993 struct visitor
* pvis
; /* temp for determining past_pat_inspector. */
994 const char *format_name
;
995 enum ExistenceCheckType do_check_existence
;
998 /* We may turn on existence checking for a given database.
999 * We ensure that we can return to the previous behaviour
1000 * by using two variables, do_check_existence (which we act on)
1001 * and check_existence (whcih indicates the default before we
1002 * adjust it on the bassis of what kind of database we;re using
1004 do_check_existence
= check_existence
;
1008 regex_options
|= RE_ICASE
;
1010 procdata
.len
= procdata
.count
= 0;
1011 procdata
.slocatedb_format
= 0;
1012 procdata
.itemcount
= 0;
1014 procdata
.dbfile
= dbfile
;
1017 /* Set up the inspection regime */
1019 lastinspector
= NULL
;
1020 past_pat_inspector
= NULL
;
1021 results_were_filtered
= false;
1023 procdata
.pathsize
= 1026; /* Increased as necessary by locate_read_str. */
1024 procdata
.original_filename
= xmalloc (procdata
.pathsize
);
1027 nread
= fread (procdata
.original_filename
, 1, SLOCATE_DB_MAGIC_LEN
,
1029 slocate_seclevel
= 0;
1030 if (looking_at_slocate_locatedb(procdata
.dbfile
,
1031 procdata
.original_filename
,
1036 _("`%s' is an slocate database. "
1037 "Support for these is new, expect problems for now "
1038 "(you are, after all, using the CVS code)."),
1041 /* slocate also uses frcode, but with a different header.
1042 * We handle the header here and then work with the data
1043 * in the normal way.
1045 if (slocate_seclevel
> 1)
1047 /* We don't know what those security levels mean,
1048 * so do nothing further
1052 else if (slocate_seclevel
> 0)
1054 /* Don't show the filenames to the user if they don't exist.
1055 * Showing stats is safe since filenames are only counted
1056 * after the existence check
1058 if (ACCEPT_NON_EXISTING
== check_existence
)
1060 /* Do not allow the user to see a list of filenames that they
1064 _("You specified the -E option, but that option "
1065 "cannot be used with slocate-format databases "
1066 "with a non-zero security level. No results will be "
1067 "generated for this database.\n"));
1070 if (ACCEPT_EXISTING
!= do_check_existence
)
1072 if (enable_print
|| stats
)
1075 _("`%s' is an slocate database. "
1076 "Turning on the '-e' option."),
1079 do_check_existence
= ACCEPT_EXISTING
;
1082 add_visitor(visit_locate02_format
, NULL
);
1083 format_name
= "slocate";
1084 procdata
.slocatedb_format
= 1;
1090 procdata
.slocatedb_format
= 0;
1091 nread2
= fread (procdata
.original_filename
+nread
, 1, sizeof (LOCATEDB_MAGIC
)-nread
,
1093 if (looking_at_gnu_locatedb(procdata
.original_filename
, nread
+nread2
))
1095 add_visitor(visit_locate02_format
, NULL
);
1096 format_name
= "GNU LOCATE02";
1098 else /* Use the old format */
1103 /* Read the list of the most common bigrams in the database. */
1106 int more_read
= fread (procdata
.original_filename
+ nread
, 1,
1107 256 - nread
, procdata
.fp
);
1108 /* XXX: check more_read+nread! */
1111 for (i
= 0; i
< 128; i
++)
1113 procdata
.bigram1
[i
] = procdata
.original_filename
[i
<< 1];
1114 procdata
.bigram2
[i
] = procdata
.original_filename
[(i
<< 1) + 1];
1116 format_name
= "old";
1117 add_visitor(visit_old_format
, NULL
);
1122 add_visitor(visit_basename
, NULL
);
1124 /* Add an inspector for each pattern we're looking for. */
1125 for ( argn
= 0; argn
< argc
; argn
++ )
1127 results_were_filtered
= true;
1128 pathpart
= argv
[argn
];
1131 struct regular_expression
*p
= xmalloc(sizeof(*p
));
1132 const char *error_message
= NULL
;
1134 memset (&p
->regex
, 0, sizeof (p
->regex
));
1136 re_set_syntax(regex_options
);
1137 p
->regex
.allocated
= 100;
1138 p
->regex
.buffer
= (unsigned char *) xmalloc (p
->regex
.allocated
);
1139 p
->regex
.fastmap
= NULL
;
1140 p
->regex
.syntax
= regex_options
;
1141 p
->regex
.translate
= NULL
;
1143 error_message
= re_compile_pattern (pathpart
, strlen (pathpart
),
1147 error (1, 0, "%s", error_message
);
1151 add_visitor(visit_regex
, p
);
1154 else if (contains_metacharacter(pathpart
))
1157 add_visitor(visit_globmatch_casefold
, pathpart
);
1159 add_visitor(visit_globmatch_nofold
, pathpart
);
1163 /* No glob characters used. Hence we match on
1164 * _any part_ of the filename, not just the
1165 * basename. This seems odd to me, but it is the
1166 * traditional behaviour.
1167 * James Youngman <jay@gnu.org>
1170 add_visitor(visit_substring_match_casefold
, pathpart
);
1172 add_visitor(visit_substring_match_nocasefold
, pathpart
);
1176 pvis
= lastinspector
;
1178 /* We add visit_existing_*() as late as possible to reduce the
1179 * number of stat() calls.
1181 switch (do_check_existence
)
1183 case ACCEPT_EXISTING
:
1184 results_were_filtered
= true;
1185 if (follow_symlinks
) /* -L, default */
1186 add_visitor(visit_existing_follow
, NULL
);
1188 add_visitor(visit_existing_nofollow
, NULL
);
1191 case ACCEPT_NON_EXISTING
:
1192 results_were_filtered
= true;
1193 if (follow_symlinks
) /* -L, default */
1194 add_visitor(visit_non_existing_follow
, NULL
);
1196 add_visitor(visit_non_existing_nofollow
, NULL
);
1199 case ACCEPT_EITHER
: /* Default, neither -E nor -e */
1200 /* do nothing; no extra processing. */
1204 /* Security issue: The stats visitor must be added immediately
1205 * before the print visitor, because otherwise the -S option would
1206 * leak information about files that the caller cannot see.
1209 add_visitor(visit_stats
, &statistics
);
1213 if (print_quoted_filename
)
1214 add_visitor(visit_justprint_quoted
, NULL
);
1216 add_visitor(visit_justprint_unquoted
, NULL
);
1221 add_visitor(visit_limit
, plimit
);
1223 add_visitor(visit_count
, plimit
);
1228 past_pat_inspector
= pvis
->next
;
1230 mainprocessor
= process_and
;
1232 mainprocessor
= process_or
;
1235 mainprocessor
= process_simple
;
1239 printf(_("Database %s is in the %s format.\n"),
1245 procdata
.c
= getc (procdata
.fp
);
1246 /* If we are searching for filename patterns, the inspector list
1247 * will contain an entry for each pattern for which we are searching.
1249 while ( (procdata
.c
!= EOF
) &&
1250 (VISIT_ABORT
!= (mainprocessor
)(&procdata
)) )
1252 /* Do nothing; all the work is done in the visitor functions. */
1258 print_stats(argc
, filesize
);
1261 if (ferror (procdata
.fp
))
1263 error (0, errno
, "%s", procdata
.dbfile
);
1266 return plimit
->items_accepted
;
1272 extern char *version_string
;
1274 /* The name this program was run with. */
1278 usage (FILE *stream
)
1280 fprintf (stream
, _("\
1281 Usage: %s [-d path | --database=path] [-e | -E | --[non-]existing]\n\
1282 [-i | --ignore-case] [-w | --wholename] [-b | --basename] \n\
1283 [--limit=N | -l N] [-S | --statistics] [-0 | --null] [-c | --count]\n\
1284 [-P | -H | --nofollow] [-L | --follow] [-m | --mmap ] [ -s | --stdio ]\n\
1285 [-A | --all] [-p | --print] [-r | --regex ] [--regextype=TYPE]\n\
1286 [--max-database-age D] [--version] [--help]\n\
1289 fputs (_("\nReport bugs to <bug-findutils@gnu.org>.\n"), stream
);
1293 REGEXTYPE_OPTION
= CHAR_MAX
+ 1,
1298 static struct option
const longopts
[] =
1300 {"database", required_argument
, NULL
, 'd'},
1301 {"existing", no_argument
, NULL
, 'e'},
1302 {"non-existing", no_argument
, NULL
, 'E'},
1303 {"ignore-case", no_argument
, NULL
, 'i'},
1304 {"all", no_argument
, NULL
, 'A'},
1305 {"help", no_argument
, NULL
, 'h'},
1306 {"version", no_argument
, NULL
, 'v'},
1307 {"null", no_argument
, NULL
, '0'},
1308 {"count", no_argument
, NULL
, 'c'},
1309 {"wholename", no_argument
, NULL
, 'w'},
1310 {"wholepath", no_argument
, NULL
, 'w'}, /* Synonym. */
1311 {"basename", no_argument
, NULL
, 'b'},
1312 {"print", no_argument
, NULL
, 'p'},
1313 {"stdio", no_argument
, NULL
, 's'},
1314 {"mmap", no_argument
, NULL
, 'm'},
1315 {"limit", required_argument
, NULL
, 'l'},
1316 {"regex", no_argument
, NULL
, 'r'},
1317 {"regextype", required_argument
, NULL
, REGEXTYPE_OPTION
},
1318 {"statistics", no_argument
, NULL
, 'S'},
1319 {"follow", no_argument
, NULL
, 'L'},
1320 {"nofollow", no_argument
, NULL
, 'P'},
1321 {"max-database-age", required_argument
, NULL
, MAX_DB_AGE
},
1322 {NULL
, no_argument
, NULL
, 0}
1329 const char * what
= "failed";
1330 const uid_t orig_euid
= geteuid();
1331 const uid_t uid
= getuid();
1332 const gid_t gid
= getgid();
1334 /* Use of setgroups() is restrcted to root only. */
1337 /* UID != 0, but EUID == 0. We're running setuid-root. */
1339 groups
[1] = getgid();
1340 if (0 != setgroups(1, groups
))
1342 what
= _("failed to drop group privileges");
1347 /* Drop any setuid privileges */
1348 if (uid
!= orig_euid
)
1352 /* We're really root anyway, but are setuid to something else. Leave it. */
1357 if (0 != setuid(getuid()))
1359 what
= _("failed to drop setuid privileges");
1363 /* Defend against the case where the attacker runs us with the
1364 * capability to call setuid() turned off, which on some systems
1365 * will cause the above attempt to drop privileges fail (leaving us
1370 /* Check that we can no longer switch bask to root */
1373 what
= _("Failed to fully drop privileges");
1374 /* The errno value here is not interesting (since
1375 * the system call we are complaining about
1376 * succeeded when we wanted it to fail). Arrange
1377 * for the call to error() not to print the errno
1378 * value by setting errno=0.
1387 /* Drop any setgid privileges */
1389 if (0 != setgid(gid
))
1391 what
= _("failed to drop setgid privileges");
1399 error(1, errno
, "%s", what
);
1407 /* deliberate infinite loop */
1412 opendb(const char *name
)
1414 int fd
= open(name
, O_RDONLY
1415 #if defined(O_LARGEFILE)
1421 /* Make sure it won't survive an exec */
1422 if (0 != fcntl(fd
, F_SETFD
, FD_CLOEXEC
))
1432 dolocate (int argc
, char **argv
, int secure_db_fd
)
1435 unsigned long int found
= 0uL;
1437 int ignore_case
= 0;
1440 int basename_only
= 0;
1443 int regex_options
= RE_SYNTAX_EMACS
;
1448 int they_chose_db
= 0;
1449 bool did_stdin
= false; /* Set to prevent rereading stdin. */
1451 program_name
= argv
[0];
1453 #ifdef HAVE_SETLOCALE
1454 setlocale (LC_ALL
, "");
1456 bindtextdomain (PACKAGE
, LOCALEDIR
);
1457 textdomain (PACKAGE
);
1458 atexit (close_stdout
);
1461 limits
.items_accepted
= 0;
1463 quote_opts
= clone_quoting_options (NULL
);
1464 print_quoted_filename
= true;
1466 /* We cannot simultaneously trust $LOCATE_PATH and use the
1467 * setuid-access-controlled database,, since that could cause a leak
1470 dbpath
= getenv ("LOCATE_PATH");
1476 check_existence
= ACCEPT_EITHER
;
1478 while ((optc
= getopt_long (argc
, argv
, "Abcd:eEil:prsm0SwHPL", longopts
, (int *) 0)) != -1)
1483 print_quoted_filename
= false; /* print filename 'raw'. */
1504 check_existence
= ACCEPT_EXISTING
;
1508 check_existence
= ACCEPT_NON_EXISTING
;
1520 /* XXX: nothing in the test suite for this option. */
1521 set_max_db_age(optarg
);
1529 printf (_("GNU locate version %s\n"), version_string
);
1530 printf (_("Built using GNU gnulib version %s\n"), gnulib_version
);
1541 case REGEXTYPE_OPTION
:
1542 regex_options
= get_regex_type(optarg
);
1550 follow_symlinks
= 1;
1553 /* In find, -P and -H differ in the way they handle paths
1554 * given on the command line. This is not relevant for
1555 * locate, but the -H option is supported because it is
1556 * probably more intuitive to do so.
1560 follow_symlinks
= 0;
1566 strtol_error err
= xstrtoumax(optarg
, &end
, 10, &limits
.limit
, NULL
);
1567 if (LONGINT_OK
!= err
)
1569 STRTOL_FATAL_ERROR(optarg
, _("argument to --limit"), err
);
1575 case 's': /* use stdio */
1576 case 'm': /* use mmap */
1577 /* These options are implemented simply for
1578 * compatibility with FreeBSD
1588 /* If the user gave the -d option or set LOCATE_PATH,
1589 * relinquish access to the secure database.
1593 if (secure_db_fd
>= 0)
1595 close(secure_db_fd
);
1600 if (!just_count
&& !stats
)
1610 if (!just_count
&& optind
== argc
)
1618 if (1 == isatty(STDOUT_FILENO
))
1619 stdout_is_a_tty
= true;
1621 stdout_is_a_tty
= false;
1624 next_element (dbpath
, 0); /* Initialize. */
1626 /* Bail out early if limit already reached. */
1627 while (!use_limit
|| limits
.limit
> limits
.items_accepted
)
1633 statistics
.compressed_bytes
=
1634 statistics
.total_filename_count
=
1635 statistics
.total_filename_length
=
1636 statistics
.whitespace_count
=
1637 statistics
.newline_count
=
1638 statistics
.highbit_filename_count
= 0u;
1642 /* Take the next element from the list of databases */
1643 e
= next_element ((char *) NULL
, 0);
1647 if (0 == strcmp (e
, "-"))
1652 _("warning: the locate database can only be read from stdin once."));
1664 if (0 == strlen(e
) || 0 == strcmp(e
, "."))
1669 /* open the database */
1673 error (0, errno
, "%s", e
);
1680 if (-1 == secure_db_fd
)
1682 /* Already searched the database, it's time to exit the loop */
1687 e
= selected_secure_db
;
1693 /* Check the database to see if it is old. */
1696 error (0, errno
, "%s", e
);
1697 /* continue anyway */
1698 filesize
= (off_t
)0;
1704 filesize
= st
.st_size
;
1706 if ((time_t)-1 == time(&now
))
1708 /* If we can't tell the time, we don't know how old the
1709 * database is. But since the message is just advisory,
1710 * we continue anyway.
1712 error (0, errno
, "time system call");
1716 double age
= difftime(now
, st
.st_mtime
);
1717 double warn_seconds
= SECONDS_PER_UNIT
* warn_number_units
;
1718 if (age
> warn_seconds
)
1721 warning: database `fred' is more than 8 days old (actual age is 10 days)*/
1723 _("warning: database `%s' is more than %d %s old (actual age is %.1f %s)"),
1725 warn_number_units
, _(warn_name_units
),
1726 (age
/(double)SECONDS_PER_UNIT
), _(warn_name_units
));
1731 fp
= fdopen(fd
, "r");
1734 error (0, errno
, "%s", e
);
1738 /* Search this database for all patterns simultaneously */
1739 found
= search_one_database (argc
- optind
, &argv
[optind
],
1741 ignore_case
, print
, basename_only
,
1742 use_limit
, &limits
, stats
,
1743 op_and
, regex
, regex_options
);
1745 /* Close the databsase (even if it is stdin) */
1746 if (fclose (fp
) == EOF
)
1748 error (0, errno
, "%s", e
);
1755 printf("%ld\n", found
);
1758 if (found
|| (use_limit
&& (limits
.limit
==0)) || stats
)
1764 #define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
1766 open_secure_db(void)
1770 const char * secure_db_list
[] =
1773 "/var/lib/slocate/slocate.db",
1776 for (i
=0; secure_db_list
[i
]; ++i
)
1778 fd
= opendb(secure_db_list
[i
]);
1781 selected_secure_db
= secure_db_list
[i
];
1789 main (int argc
, char **argv
)
1791 int dbfd
= open_secure_db();
1794 return dolocate(argc
, argv
, dbfd
);