* lib/splitstring.c: New file; defines splitstring(), which will non-destructively locate character-separated fields in a string. * lib/splitstring.h: New file; declares splitstring. * lib/test_splitstring.c: New file; unit test for splitstring.c. * lib/nextelem.c: Delete (obsoleted by splitstring.c). * lib/nextelem.h: Delete (obsoleted by splitstring.h). * lib/Makefile.am (libfind_a_SOURCES): Add splitstring.c, splitstring.c. Remove nextelem.c, nextelem.h. (check_PROGRAMS): Add test_splitstring. (TESTS): Add test_splitstring. (test_splitstring_SOURCES): Sources for the test_splitstring unit test. * locate/locate.c: Include splitstring.h rather than nextelem.h. (dolocate): Use splitstring rather than next_element. In places where we need a nul-terminated string, use strndup() to create it. Convert some space-tab sequences to regular spacing. * find/parser.c: Include splitstring.h rather than nextelem.h. (check_path_safety): Use splitstring rather than next_element. * import-gnulib.config (modules): Depend on the module strndup. * cfg.mk: Exempt lib/test_splitstring.c from calling bindtextdomain or set_program_name. --- ChangeLog | 25 ++++++ cfg.mk | 4 +- find/parser.c | 32 +++++--- import-gnulib.config | 1 + lib/Makefile.am | 14 ++-- lib/nextelem.c | 85 -------------------- lib/nextelem.h | 26 ------ lib/splitstring.c | 60 ++++++++++++++ lib/splitstring.h | 40 ++++++++++ lib/test_splitstring.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++++ locate/locate.c | 61 +++++++++----- 11 files changed, 396 insertions(+), 153 deletions(-) delete mode 100644 lib/nextelem.c delete mode 100644 lib/nextelem.h create mode 100644 lib/splitstring.c create mode 100644 lib/splitstring.h create mode 100644 lib/test_splitstring.c
diff --git a/ChangeLog b/ChangeLog index 827ea60..7b2dd52 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,30 @@ 2011-06-13 James Youngman <[email protected]> + Split strings into fields nondestructively. + * lib/splitstring.c: New file; defines splitstring(), which will + non-destructively locate character-separated fields in a string. + * lib/splitstring.h: New file; declares splitstring. + * lib/test_splitstring.c: New file; unit test for splitstring.c. + * lib/nextelem.c: Delete (obsoleted by splitstring.c). + * lib/nextelem.h: Delete (obsoleted by splitstring.h). + * lib/Makefile.am (libfind_a_SOURCES): Add splitstring.c, + splitstring.c. Remove nextelem.c, nextelem.h. + (check_PROGRAMS): Add test_splitstring. + (TESTS): Add test_splitstring. + (test_splitstring_SOURCES): Sources for the + test_splitstring unit test. + * locate/locate.c: Include splitstring.h rather than nextelem.h. + (dolocate): Use splitstring rather than next_element. In places + where we need a nul-terminated string, use strndup() to create it. + Convert some space-tab sequences to regular spacing. + * find/parser.c: Include splitstring.h rather than nextelem.h. + (check_path_safety): Use splitstring rather than next_element. + * import-gnulib.config (modules): Depend on the module strndup. + * cfg.mk: Exempt lib/test_splitstring.c from calling + bindtextdomain or set_program_name. + +2011-06-13 James Youngman <[email protected]> + Fix compilation failure in bigram.c by including <locale.h>. * locate/bigram.c: Include <locale.h>. diff --git a/cfg.mk b/cfg.mk index f301884..121c337 100644 --- a/cfg.mk +++ b/cfg.mk @@ -36,13 +36,15 @@ exclude_file_name_regexp--sc_trailing_blank = \ exclude_file_name_regexp--sc_prohibit_empty_lines_at_EOF = \ ^(.*/testsuite/.*\.(xo|xi|xe))|COPYING|doc/regexprops\.texi|m4/order-(bad|good)\.bin$$ exclude_file_name_regexp--sc_bindtextdomain = \ - ^lib/regexprops\.c$$ + ^lib/(regexprops|test_splitstring)\.c$$ exclude_file_name_regexp--sc_prohibit_always_true_header_tests = \ ^(build-aux/src-sniff\.py)|ChangeLog$$ exclude_file_name_regexp--sc_prohibit_test_minus_ao = \ ^(ChangeLog)|((find|locate|xargs)/testsuite/.*\.exp)$$ exclude_file_name_regexp--sc_prohibit_doubled_word = \ ^(xargs/testsuite/xargs\.sysv/iquotes\.xo)|ChangeLog|po/.*\.po$$ +exclude_file_name_regexp--sc_program_name = \ + ^lib/test_splitstring\.c$$ # sc_texinfo_acronym: perms.texi from coreutils uses @acronym{GNU}. exclude_file_name_regexp--sc_texinfo_acronym = doc/perm\.texi diff --git a/find/parser.c b/find/parser.c index 7b82ae7..ea676bd 100644 --- a/find/parser.c +++ b/find/parser.c @@ -34,7 +34,6 @@ #include "xalloc.h" #include "quotearg.h" #include "buildcmd.h" -#include "nextelem.h" #include "regextype.h" #include "stat-time.h" #include "xstrtod.h" @@ -44,6 +43,7 @@ #include "findutils-version.h" #include "safe-atoi.h" #include "fdleak.h" +#include "splitstring.h" #include <fcntl.h> @@ -3227,11 +3227,16 @@ make_segment (struct segment **segment, return &(*segment)->next; } + + + static void check_path_safety (const char *action, char **argv) { - char *s; const char *path = getenv ("PATH"); + const char *path_separators = ":"; + size_t pos, len; + if (NULL == path) { /* $PATH is not set. Assume the OS default is safe. @@ -3242,34 +3247,35 @@ check_path_safety (const char *action, char **argv) return; } - (void)argv; - - s = next_element (path, 1); - while ((s = next_element ((char *) NULL, 1)) != NULL) + splitstring (path, path_separators, true, &pos, &len); + do { - if (0 == strcmp (s, ".")) + if (0 == len || (1 == len && path[pos] == '.')) { + /* empty field signifies . */ error (EXIT_FAILURE, 0, _("The current directory is included in the PATH " "environment variable, which is insecure in " "combination with the %s action of find. " "Please remove the current directory from your " - "$PATH (that is, remove \".\" or leading or trailing " - "colons)"), + "$PATH (that is, remove \".\", doubled colons, " + "or leading or trailing colons)"), action); } - else if ('/' != s[0]) + else if (path[pos] != '/') { - /* Relative paths are also dangerous in $PATH. */ + char *relpath = strndup (&path[pos], len); error (EXIT_FAILURE, 0, _("The relative path %s is included in the PATH " "environment variable, which is insecure in " "combination with the %s action of find. " "Please remove that entry from $PATH"), - safely_quote_err_filename (0, s), + safely_quote_err_filename (0, relpath ? relpath : &path[pos]), action); + /*NOTREACHED*/ + free (relpath); } - } + } while (splitstring (path, path_separators, false, &pos, &len)); } diff --git a/import-gnulib.config b/import-gnulib.config index 5fb46c2..567d66c 100644 --- a/import-gnulib.config +++ b/import-gnulib.config @@ -132,6 +132,7 @@ strcasestr strdup-posix strftime string +strndup strtol strtoul strtoull diff --git a/lib/Makefile.am b/lib/Makefile.am index f8ff625..5450e9a 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -6,7 +6,7 @@ AM_CFLAGS = $(WARN_CFLAGS) noinst_LIBRARIES = libfind.a -check_PROGRAMS = regexprops +check_PROGRAMS = regexprops test_splitstring check_SCRIPTS = check-regexprops regexprops_SOURCES = regexprops.c regextype.c @@ -15,7 +15,7 @@ if CROSS_COMPILING # The regexprops program needs to be a native executable, so we # can't build it with a cross-compiler. else -TESTS += check-regexprops +TESTS += check-regexprops test_splitstring endif libfind_a_SOURCES = findutils-version.c @@ -32,11 +32,11 @@ MAINTAINERCLEANFILES = INCLUDES = -I../gl/lib -I$(top_srcdir)/gl/lib LDADD = ../gl/lib/libgnulib.a $(LIBINTL) -libfind_a_SOURCES += nextelem.h printquoted.h listfile.h \ - regextype.h dircallback.h safe-atoi.h -libfind_a_SOURCES += listfile.c nextelem.c extendbuf.c buildcmd.c savedirinfo.c \ +libfind_a_SOURCES += printquoted.h listfile.h \ + regextype.h dircallback.h safe-atoi.h splitstring.h +libfind_a_SOURCES += listfile.c extendbuf.c buildcmd.c savedirinfo.c \ forcefindlib.c qmark.c printquoted.c regextype.c dircallback.c fdleak.c \ - safe-atoi.c + safe-atoi.c splitstring.c EXTRA_DIST += waitpid.c forcefindlib.c TESTS_ENVIRONMENT = REGEXPROPS=regexprops$(EXEEXT) @@ -46,3 +46,5 @@ libfind_a_DEPENDENCIES = $(FINDLIBOBJS) check-regexprops: check-regexprops.sh cp $(srcdir)/check-regexprops.sh check-regexprops chmod +x check-regexprops + +test_splitstring_SOURCES = test_splitstring.c splitstring.c diff --git a/lib/nextelem.c b/lib/nextelem.c deleted file mode 100644 index 3e9246c..0000000 --- a/lib/nextelem.c +++ /dev/null @@ -1,85 +0,0 @@ -/* Return the next element of a path. - Copyright (C) 1992, 2005, 2010, 2011 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -/* Written by David MacKenzie <[email protected]>, - inspired by John P. Rouillard <[email protected]>. */ - -#include <config.h> - - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> - - -#include "nextelem.h" - - -/* Return the next element of a colon-separated path. - A null entry in the path is equivalent to "." (the current directory). - - If NEW_PATH is non-NULL, set the path and return NULL. - If NEW_PATH is NULL, return the next item in the string, or - return NULL if there are no more elements. */ - -char * -next_element (const char *new_path, int curdir_ok) -{ - static char *path = NULL; /* Freshly allocated copy of NEW_PATH. */ - static char *end; /* Start of next element to return. */ - static int final_colon; /* If zero, path didn't end with a colon. */ - char *start; /* Start of path element to return. */ - - if (new_path) - { - free (path); - end = path = strdup (new_path); - final_colon = 0; - return NULL; - } - - if (*end == '\0') - { - if (final_colon) - { - final_colon = 0; - return curdir_ok ? "." : ""; - } - return NULL; - } - - start = end; - final_colon = 1; /* Maybe there will be one. */ - - end = strchr (start, ':'); - if (end == start) - { - /* An empty path element. */ - *end++ = '\0'; - return curdir_ok ? "." : ""; - } - else if (end == NULL) - { - /* The last path element. */ - end = strchr (start, '\0'); - final_colon = 0; - } - else - *end++ = '\0'; - - return start; -} diff --git a/lib/nextelem.h b/lib/nextelem.h deleted file mode 100644 index 00ffcfe..0000000 --- a/lib/nextelem.h +++ /dev/null @@ -1,26 +0,0 @@ -/* Return the next element of a path. - Copyright (C) 1992, 2010, 2011 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -/* Written by David MacKenzie <[email protected]>, - inspired by John P. Rouillard <[email protected]>. */ - -#ifndef INC_NEXTELEM_H -#define INC_NEXTELEM_H 1 - -char *next_element (const char *path, int curdir_ok); - -#endif diff --git a/lib/splitstring.c b/lib/splitstring.c new file mode 100644 index 0000000..e706d9c --- /dev/null +++ b/lib/splitstring.c @@ -0,0 +1,60 @@ +/* splitstring.c -- split a const string into fields. + Copyright (C) 2011 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ +/* + * Written by James Youngman. + */ + +#include <config.h> +#include <stdbool.h> +#include <string.h> + +#include "splitstring.h" + +static size_t +field_length (const char *str, const char *separators) +{ + /* if there are no separators, the whole input is one field. */ + if (*separators) + { + const char *end = strpbrk (str, separators); + if (end) + return end - str; + } + return strlen (str); +} + + +bool +splitstring(const char *s, const char *separators, bool first, + size_t *pos, size_t *len) +{ + if (first) + { + *pos = 0u; + *len = 0u; + } + else + { + *pos += *len; /* advance to the next field. */ + if (s[*pos]) + ++*pos; /* skip the separator */ + else + return false; /* we reached the end. */ + } + *len = field_length (&s[*pos], separators); + return true; +} diff --git a/lib/splitstring.h b/lib/splitstring.h new file mode 100644 index 0000000..c91f7e7 --- /dev/null +++ b/lib/splitstring.h @@ -0,0 +1,40 @@ +/* splitstring.h -- split a const string into fields. + Copyright (C) 2011 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ +/* + * Written by James Youngman. + */ + +/* Split a string into fields. The string is never modified. + * + * A false return value indicates that there are no more fields. + * Otherwise the next field is at the poisition indicated by *POS and + * has length *LEN. + * + * Set FIRST to true only on the first call for any given value of s. + * *POS and *LEN do not need to be initialised in this case. + * On subsequent calls, these values should be left at the values + * set by the last call. + * + * Any character in SEPARATORS is taken to be a field separator. + * Consecutive field separators are taken to indicate the presence of + * an empty field. + */ +#include <stdbool.h> +#include <stddef.h> + +bool splitstring(const char *s, const char *separators, + bool first, size_t *pos, size_t *len); diff --git a/lib/test_splitstring.c b/lib/test_splitstring.c new file mode 100644 index 0000000..9dedb7c --- /dev/null +++ b/lib/test_splitstring.c @@ -0,0 +1,201 @@ +/* test_splitstring.c -- unit test for splitstring() + Copyright (C) 2011 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ +#include <config.h> +#include <stdio.h> +#include <assert.h> + +#include "splitstring.h" + +static void +assertEqualFunc(const char *file, int line, const char *label, + size_t expected, size_t got) +{ + if (expected != got) + fprintf(stderr, "%s line %d: %s: expected %lu, got %lu\n", + file, line, label, (unsigned long)expected, (unsigned long)got); +} +#define ASSERT_EQUAL(expected,got) \ + do{ \ + assertEqualFunc(__FILE__,__LINE__,"ASSERT_EQUAL",expected,got); \ + assert (expected == got); \ + } while (0); + + +static void +test_empty (void) +{ + size_t len, pos; + bool result; + const char *empty = ""; + + result = splitstring (empty, ":", true, &pos, &len); + assert (result); + ASSERT_EQUAL (0, pos); + ASSERT_EQUAL (0, len); + result = splitstring (empty, ":", false, &pos, &len); + assert (!result); +} + +static void test_onefield (void) +{ + size_t len, pos; + bool result; + const char *input = "aaa"; + + result = splitstring (input, ":", true, &pos, &len); + assert (result); + ASSERT_EQUAL (0, pos); + ASSERT_EQUAL (3, len); + result = splitstring (input, ":", false, &pos, &len); + assert (!result); +} + +static void test_not_colon (void) +{ + size_t len, pos; + bool result; + const char *separators = "!"; + const char *input = "aa!b"; + + result = splitstring (input, separators, true, &pos, &len); + assert (result); + ASSERT_EQUAL (0, pos); + ASSERT_EQUAL (2, len); + + result = splitstring (input, separators, false, &pos, &len); + assert (result); + ASSERT_EQUAL (3, pos); + ASSERT_EQUAL (1, len); + + result = splitstring (input, separators, false, &pos, &len); + assert (!result); +} + +static void test_empty_back (void) +{ + size_t len, pos; + bool result; + const char *input = "aa:"; + + result = splitstring (input, ":", true, &pos, &len); + assert (result); + ASSERT_EQUAL (0, pos); + ASSERT_EQUAL (2, len); + result = splitstring (input, ":", false, &pos, &len); + assert (result); + ASSERT_EQUAL (3, pos); + ASSERT_EQUAL (0, len); + result = splitstring (input, ":", false, &pos, &len); + assert (!result); +} + +static void test_empty_front (void) +{ + size_t len, pos; + bool result; + const char *input = ":aaa"; + + result = splitstring (input, ":", true, &pos, &len); + assert (result); + ASSERT_EQUAL (0, pos); + ASSERT_EQUAL (0, len); + result = splitstring (input, ":", false, &pos, &len); + assert (result); + ASSERT_EQUAL (1, pos); + ASSERT_EQUAL (3, len); + result = splitstring (input, ":", false, &pos, &len); + assert (!result); +} + +static void test_twofields (void) +{ + size_t len, pos; + bool result; + const char *input = "aaa:bb"; + + result = splitstring (input, ":", true, &pos, &len); + assert (result); + ASSERT_EQUAL (0, pos); + ASSERT_EQUAL (3, len); + result = splitstring (input, ":", false, &pos, &len); + assert (result); + ASSERT_EQUAL (4, pos); + ASSERT_EQUAL (2, len); + result = splitstring (input, ":", false, &pos, &len); + assert (!result); +} + +static void test_twoseparators (void) +{ + size_t len, pos; + bool result; + const char *input = "a:bb!c"; + + result = splitstring (input, ":!", true, &pos, &len); + assert (result); + ASSERT_EQUAL (0, pos); + ASSERT_EQUAL (1, len); + result = splitstring (input, ":!", false, &pos, &len); + assert (result); + ASSERT_EQUAL (2, pos); + ASSERT_EQUAL (2, len); + result = splitstring (input, ":!", false, &pos, &len); + assert (result); + ASSERT_EQUAL (5, pos); + ASSERT_EQUAL (1, len); + result = splitstring (input, ":!", false, &pos, &len); + assert (!result); +} + +static void test_consecutive_empty (void) +{ + size_t len, pos; + bool result; + const char *input = "a::b"; + const char *separators = ":"; + + result = splitstring (input, separators, true, &pos, &len); + assert (result); + ASSERT_EQUAL (0, pos); + ASSERT_EQUAL (1, len); + + result = splitstring (input, separators, false, &pos, &len); + assert (result); + ASSERT_EQUAL (2, pos); + ASSERT_EQUAL (0, len); + + result = splitstring (input, separators, false, &pos, &len); + assert (result); + ASSERT_EQUAL (3, pos); + ASSERT_EQUAL (1, len); + + result = splitstring (input, separators, false, &pos, &len); + assert (!result); +} + +int main (int argc, char *argv[]) +{ + test_empty (); + test_onefield (); + test_not_colon (); + test_empty_back (); + test_empty_front (); + test_twofields (); + test_twoseparators (); + test_consecutive_empty (); + return 0; +} diff --git a/locate/locate.c b/locate/locate.c index ad7b56a..42089ee 100644 --- a/locate/locate.c +++ b/locate/locate.c @@ -123,11 +123,11 @@ #include "human.h" #include "dirname.h" #include "closeout.h" -#include "nextelem.h" #include "regex.h" #include "quotearg.h" #include "printquoted.h" #include "regextype.h" +#include "splitstring.h" #include "findutils-version.h" /* Note that this evaluates Ch many times. */ @@ -1555,7 +1555,11 @@ opendb (const char *name) int dolocate (int argc, char **argv, int secure_db_fd) { - char *dbpath; + char *path_element; + size_t path_element_pos, path_element_len; + const char *locate_path; + const char *db_name; + const char *path_separators = ":"; unsigned long int found = 0uL; int ignore_case = 0; int print = 0; @@ -1593,11 +1597,9 @@ dolocate (int argc, char **argv, int secure_db_fd) * setuid-access-controlled database,, since that could cause a leak * of private data. */ - dbpath = getenv ("LOCATE_PATH"); - if (dbpath) - { + locate_path = getenv ("LOCATE_PATH"); + if (locate_path) they_chose_db = 1; - } check_existence = ACCEPT_EITHER; @@ -1629,7 +1631,7 @@ dolocate (int argc, char **argv, int secure_db_fd) break; case 'd': - dbpath = optarg; + locate_path = optarg; they_chose_db = 1; break; @@ -1753,7 +1755,8 @@ dolocate (int argc, char **argv, int secure_db_fd) stdout_is_a_tty = false; if (they_chose_db) - next_element (dbpath, 0); /* Initialize. */ + splitstring (locate_path, path_separators, true, + &path_element_pos, &path_element_len); /* Bail out early if limit already reached. */ while (!use_limit || limits.limit > limits.items_accepted) @@ -1772,11 +1775,7 @@ dolocate (int argc, char **argv, int secure_db_fd) if (they_chose_db) { /* Take the next element from the list of databases */ - e = next_element ((char *) NULL, 0); - if (NULL == e) - break; - - if (0 == strcmp (e, "-")) + if (1 == path_element_len && '-' == locate_path[path_element_pos]) { if (did_stdin) { @@ -1793,17 +1792,25 @@ dolocate (int argc, char **argv, int secure_db_fd) } else { - if (0 == strlen (e) || 0 == strcmp (e, ".")) + if (0 == path_element_len + || (1 == path_element_len + && '.' == locate_path[path_element_pos])) + { + db_name = LOCATE_DB; + } + else { - e = LOCATE_DB; + path_element = strndup (&locate_path[path_element_pos], + path_element_len); + db_name = path_element; } /* open the database */ - fd = opendb (e); + fd = opendb (db_name); if (fd < 0) { error (0, errno, "%s", - quotearg_n_style (0, locale_quoting_style, e)); + quotearg_n_style (0, locale_quoting_style, db_name)); return 0; } } @@ -1817,7 +1824,7 @@ dolocate (int argc, char **argv, int secure_db_fd) } else { - e = selected_secure_db; + db_name = selected_secure_db; fd = secure_db_fd; secure_db_fd = -1; } @@ -1827,7 +1834,7 @@ dolocate (int argc, char **argv, int secure_db_fd) if (fstat (fd, &st)) { error (0, errno, "%s", - quotearg_n_style (0, locale_quoting_style, e)); + quotearg_n_style (0, locale_quoting_style, db_name)); /* continue anyway */ filesize = (off_t)0; } @@ -1855,7 +1862,7 @@ dolocate (int argc, char **argv, int secure_db_fd) warning: database `fred' is more than 8 days old (actual age is 10 days)*/ error (0, 0, _("warning: database %s is more than %d %s old (actual age is %.1f %s)"), - quotearg_n_style (0, locale_quoting_style, e), + quotearg_n_style (0, locale_quoting_style, db_name), warn_number_units, _(warn_name_units), (age/(double)SECONDS_PER_UNIT), _(warn_name_units)); } @@ -1866,7 +1873,7 @@ dolocate (int argc, char **argv, int secure_db_fd) if (NULL == fp) { error (0, errno, "%s", - quotearg_n_style (0, locale_quoting_style, e)); + quotearg_n_style (0, locale_quoting_style, db_name)); return 0; } @@ -1881,9 +1888,19 @@ dolocate (int argc, char **argv, int secure_db_fd) if (fclose (fp) == EOF) { error (0, errno, "%s", - quotearg_n_style (0, locale_quoting_style, e)); + quotearg_n_style (0, locale_quoting_style, db_name)); return 0; } + if (path_element) + { + free (path_element); + path_element = NULL; + } + if (!splitstring (locate_path, path_separators, false, + &path_element_pos, &path_element_len)) + { + break; + } } if (just_count) -- 1.7.2.5
