From 3f226f42bfc7c11c5d1230d0a72201b684499bd5 Mon Sep 17 00:00:00 2001
From: Leslie P. Polzer
Date: Mon, 24 Mar 2008 00:50:52 +0000
Subject: [PATCH] Merge Leslie Polzer's SOC 2007 changes implementing updatedb in C.
To: address@hidden
2008-03-24 Leslie Polzer
Merge Leslie Polzer's updatedb enhancements to xargs which were
produced as part of the Google Summer of Code 2007.
* locate/updatedb.c: New file, implementing updatedb.
* po/POTFILES.in: Add updatedb.c.
* locate/updatedb.sh: No longer used.
* locate/Makefile.am (updatedb_SOURCES): updatedb is now a C
program, not a shell script.
(_FIND): New macro; the name of the installed find binary
(_FRCODE): Likewise for frcode.
(_BIGRAM): Likewise for bigram.
(_CODE): Likewise for code.
(INCLUDES): Add extra includes for building updatedb (FIND,
FRCODE, etc.)
(updatedb): Now built by automake-generated rules, not by
processing updatedb.sh.
* locate/pipeline.c: New file, implementing run_pipeline, a
function which launches a set of processes connected via pipes.
* locate/locatedb.h: Include , .
(run_pipeline): Declare this function.
* import-gnulib.config (modules): Add euidaccess, tempname,
strsep.
---
import-gnulib.config | 4 +
locate/Makefile.am | 65 ++--
locate/locatedb.h | 5 +
locate/pipeline.c | 443 +++++++++++++++++++++
locate/updatedb.c | 1076 ++++++++++++++++++++++++++++++++++++++++++++++++++
locate/updatedb.sh | 183 +--------
po/POTFILES.in | 1 +
7 files changed, 1588 insertions(+), 189 deletions(-)
create mode 100644 locate/pipeline.c
create mode 100644 locate/updatedb.c
diff --git a/import-gnulib.config b/import-gnulib.config
index 287c2d8..1089692 100644
--- a/import-gnulib.config
+++ b/import-gnulib.config
@@ -36,6 +36,7 @@ closein
closeout
dirname
error
+euidaccess
fchdir
fcntl
fdl
@@ -74,11 +75,13 @@ stpcpy
strcasestr
strdup
strftime
+strsep
strtol
strtoul
strtoull
strtoumax
sys_stat
+tempname
timespec
verify
version-etc
@@ -92,3 +95,4 @@ xstrtol
xstrtoumax
yesno
'
+
diff --git a/locate/Makefile.am b/locate/Makefile.am
index fd9f1f5..b95505b 100644
--- a/locate/Makefile.am
+++ b/locate/Makefile.am
@@ -7,42 +7,59 @@ AM_INSTALLCHECK_STD_OPTIONS_EXEMPT = \
frcode$(EXEEXT) \
code$(EXEEXT) \
bigram$(EXEEXT)
-bin_PROGRAMS = locate
+bin_PROGRAMS = locate updatedb
libexec_PROGRAMS = frcode code bigram
-bin_SCRIPTS = updatedb
+#bin_SCRIPTS = updatedb
man_MANS = locate.1 updatedb.1 locatedb.5
BUILT_SOURCES = dblocation.texi
-EXTRA_DIST = locatedb.h updatedb.sh $(man_MANS)
+EXTRA_DIST = locatedb.h $(man_MANS)
CLEANFILES = updatedb dblocation.texi
locate_SOURCES = locate.c word_io.c
code_SOURCES = code.c word_io.c
+updatedb_SOURCES = updatedb.c pipeline.c
+
+_FIND=`echo find | sed '$(transform)'`
+_FRCODE=`echo frcode | sed '$(transform)'`
+_BIGRAM=`echo bigram | sed '$(transform)'`
+_CODE=`echo code | sed '$(transform)'`
+
+INCLUDES = -I$(top_srcdir)/lib -I../gnulib/lib -I$(top_srcdir)/gnulib/lib -I../intl \
+ -DLOCATE_DB=\"$(LOCATE_DB)\" \
+ -DLOCALEDIR=\"$(localedir)\" \
+ -DLIBEXECDIR=\"$(libexecdir)\" \
+ -DBINDIR=\"$(bindir)\" \
+ -DVERSION=\"@address@hidden" \
+ -DSORT_SUPPORTS_Z=\"$(SORT_SUPPORTS_Z)\" \
+ -DFIND=\"$(_FIND)\" \
+ -DFRCODE=\"$(_FRCODE)\" \
+ -DBIGRAM=\"$(_BIGRAM)\" \
+ -DCODE=\"$(_CODE)\"
-INCLUDES = -I$(top_srcdir)/lib -I../gnulib/lib -I$(top_srcdir)/gnulib/lib -I../intl -DLOCATE_DB=\"$(LOCATE_DB)\" -DLOCALEDIR=\"$(localedir)\"
LDADD = ../lib/libfind.a ../gnulib/lib/libgnulib.a @INTLLIBS@
$(PROGRAMS) $(LIBPROGRAMS): ../lib/libfind.a ../gnulib/lib/libgnulib.a
-updatedb: updatedb.sh
- rm -f $@
- find=`echo find|sed '$(transform)'`; \
- frcode=`echo frcode|sed '$(transform)'`; \
- bigram=`echo bigram|sed '$(transform)'`; \
- code=`echo code|sed '$(transform)'`; \
- sed \
- -e "s,@""bindir""@,$(bindir)," \
- -e "s,@""libexecdir""@,$(libexecdir)," \
- -e "s,@""LOCATE_DB""@,$(LOCATE_DB)," \
- -e "s,@""VERSION""@,@VERSION@," \
- -e "s,@""PACKAGE_NAME""@,@PACKAGE_NAME@," \
- -e "s,@""find""@,$${find}," \
- -e "s,@""frcode""@,$${frcode}," \
- -e "s,@""bigram""@,$${bigram}," \
- -e "s,@""code""@,$${code}," \
- -e "s,@""SORT""@,$(SORT)," \
- -e "s,@""SORT_SUPPORTS_Z""@,$(SORT_SUPPORTS_Z)," \
- $(srcdir)/updatedb.sh > $@
- chmod +x $@
+#updatedb: updatedb.sh
+# rm -f $@
+# find=`echo find|sed '$(transform)'`; \
+# frcode=`echo frcode|sed '$(transform)'`; \
+# bigram=`echo bigram|sed '$(transform)'`; \
+# code=`echo code|sed '$(transform)'`; \
+# sed \
+# -e "s,@""bindir""@,$(bindir)," \
+# -e "s,@""libexecdir""@,$(libexecdir)," \
+# -e "s,@""LOCATE_DB""@,$(LOCATE_DB)," \
+# -e "s,@""VERSION""@,@VERSION@," \
+# -e "s,@""PACKAGE_NAME""@,@PACKAGE_NAME@," \
+# -e "s,@""find""@,$${find}," \
+# -e "s,@""frcode""@,$${frcode}," \
+# -e "s,@""bigram""@,$${bigram}," \
+# -e "s,@""code""@,$${code}," \
+# -e "s,@""SORT""@,$(SORT)," \
+# -e "s,@""SORT_SUPPORTS_Z""@,$(SORT_SUPPORTS_Z)," \
+# $(srcdir)/updatedb.sh > $@
+# chmod +x $@
install-data-hook:
$(top_srcdir)/build-aux/mkinstalldirs $(DESTDIR)$(localstatedir)
diff --git a/locate/locatedb.h b/locate/locatedb.h
index a4a7289..cdc8669 100644
--- a/locate/locatedb.h
+++ b/locate/locatedb.h
@@ -18,6 +18,9 @@
#ifndef _LOCATEDB_H
#define _LOCATEDB_H 1
+#include
+#include
+
/* The magic string at the start of a locate database, to make sure
it's in the right format. The 02 is the database format version number.
This string has the same format as a database entry, but you can't
@@ -74,6 +77,8 @@ int getword (FILE *fp, const char *filename,
bool putword (FILE *fp, int word,
GetwordEndianState endian_state_flag);
+int run_pipeline (char * const **args, int do_setuid, uid_t uid,
+ int *exit_status, int inputfd, int outputfd);
#define SLOCATE_DB_MAGIC_LEN 2
diff --git a/locate/pipeline.c b/locate/pipeline.c
new file mode 100644
index 0000000..eff1d57
--- /dev/null
+++ b/locate/pipeline.c
@@ -0,0 +1,443 @@
+/*
+ pipeline.c -- run a command pipeline
+
+ Copyright (C) 2007 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 2, 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA.
+
+ Written by James Youngman.
+*/
+
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include /* SIZE_MAX */
+
+#include "error.h"
+#include "locatedb.h"
+
+
+
+struct command
+{
+ int is_running;
+ pid_t pid;
+ int exit_status;
+ const char **args;
+};
+
+
+static int
+mark_close_on_exec (int fd, int silent_errors)
+{
+ long flags;
+
+ flags = fcntl (fd, F_GETFD);
+ flags |= FD_CLOEXEC;
+ if (fcntl (fd, F_SETFD, flags) < 0)
+ {
+ if (!silent_errors)
+ error (0, errno, "fcntl");
+ return 0; /* failed. */
+ }
+ return 1;
+}
+
+
+static void
+xclose (int *fd)
+{
+ assert (0 == close (*fd));
+ *fd = -1;
+}
+
+/* Invoke a command. Return the PID of the command we started,
+ * or zero if we were unable to run the command.
+ *
+ * Many of the parameters are obvious and are described in an inline
+ * comment. However, the following are more complex:
+ *
+ * If fork() fails, we call the function FAILURE_CALLBACK, passing it
+ * the argument OPAQUE_CONTEXT. The caller can use this feature to
+ * limit retries, arrange for pausing between retries, and so on.
+ * If FAILURE_CALLBACK is NULL, no retries will be attempted.
+ *
+ * If fork() succeeded, the PID of the child is returned. If the
+ * exec succeeded, *CHILD_ERRNO_VALUE is set to 0. Otherwise, that
+ * location is set to the errno value which explains why exec failed.
+ */
+static pid_t
+start_command (int silent_errors, /* turns off error messages */
+ int use_path, /* search $PATH for the command */
+ char * const * args, /* arguments (including name of binary) */
+ int do_setuid, /* whether to change the uid */
+ uid_t uid, /* uid to change to */
+ int stdin_fd, /* standard input */
+ int stdout_fd, /* standard output */
+ int *child_errno_value, /* See above */
+ int (*failure_callback)(void*), /* See above */
+ void *opaque_context) /* See above */
+{
+ int saved_errno;
+ int pipefd[2];
+ int (*fn_exec)(const char *, char *const[]);
+
+ assert (args);
+ assert (args[0]);
+
+ if (use_path)
+ fn_exec = execvp;
+ else
+ fn_exec = execv;
+
+ /* Create a pipe for transmitting the value of errno back from
+ * a child which has failed to exec() into the parent. Both the
+ * parent and child are the same binary at the point this happens,
+ * so there is no need to worry about data representation issues.
+ */
+ if (0 != pipe (pipefd))
+ {
+ if (!silent_errors)
+ error (0, errno, "pipe");
+ return 0; /* failed. */
+ }
+ /* Set the write end of the pipe to close-on-exec */
+ mark_close_on_exec (pipefd[1], silent_errors);
+
+ for (;;)
+ {
+ pid_t child_pid;
+
+ child_pid = fork ();
+ if (0 == child_pid)
+ {
+ /* We are the child. */
+ xclose (&pipefd[0]); /* close read end of pipe */
+
+ /* Do the redirections. Close the old file descriptors first,
+ * in case we are very close to a file descriptor resource limit.
+ */
+ close (STDIN_FILENO);
+ if (dup (stdin_fd) >= 0)
+ {
+ xclose (&stdin_fd);
+ close (STDOUT_FILENO);
+ if (dup (stdout_fd) >= 0)
+ {
+ xclose (&stdout_fd);
+
+ /* Run the indicated command. */
+ if (do_setuid)
+ {
+ //fprintf(stderr, "%s: setuid to %d requested.\n", args[0], uid);
+ if (setuid (uid) == -1)
+ {
+ //fprintf(stderr, "%s: but failed.\n", args[0]);
+ error (0, errno, "failed to set UID to %d", uid);
+ }
+ else
+ {
+ //fprintf(stderr, "%s: and was successful; about to exec with uid %d.\n", args[0], getuid());
+ execvp (args[0], args);
+ }
+ }
+ execvp (args[0], args);
+ saved_errno = errno;
+ }
+ else
+ {
+ saved_errno = errno;
+ }
+ }
+ else
+ {
+ saved_errno = errno;
+ }
+
+ /* If we get to here, the exec failed. Tell the parent why
+ * by sending them our errno value.
+ */
+ write (pipefd[1], &saved_errno, sizeof (saved_errno));
+ _exit (1);
+ }
+ else if (child_pid > 0)
+ {
+ /* We are the parent. */
+ int nbytes;
+
+ /* Close the copies of the child's file descriptors that the
+ * parent has. Child 1 will only be able to exit when its input
+ * pipe has no remaining writers, so we have to ensure that the
+ * parent doesn't hold the write end open.
+ */
+
+ close (pipefd[1]); /* close write end of pipe */
+ nbytes = read (pipefd[0], &saved_errno, sizeof (saved_errno));
+ if (nbytes == sizeof (saved_errno))
+ {
+ /* The exec failed. We know why, too. */
+ if (child_errno_value)
+ *child_errno_value = saved_errno;
+ if (!silent_errors)
+ error (0, saved_errno, args[0]);
+ return child_pid;
+ }
+ else
+ {
+ /* We could not read data from the pipe. That means that it is
+ * closed. We marked the write end of the pipe as FD_CLOEXEC,
+ * so the exec must have succeeded.
+ */
+ *child_errno_value = 0;
+ return child_pid;
+ }
+ }
+ else
+ {
+ /* fork() failed; we are the parent, there is no child. */
+ saved_errno = errno;
+
+ if (failure_callback)
+ {
+ /* Call the failure callback. It decides if we should retry.
+ * Its context pointer allows it to figure out how many times
+ * it retried so far (if it needs to know).
+ */
+ if (!failure_callback (opaque_context))
+ {
+ /* Caller does not want us to retry. */
+ errno = saved_errno;
+ return 0;
+ }
+ }
+ else
+ {
+ /* No failure callback. Hence no retry. */
+ if (!silent_errors)
+ error (0, saved_errno, "fork");
+ errno = saved_errno;
+ return 0;
+ }
+ /* If we get to here, the failure callback indicated we should retry. */
+ }
+ /* We get to here if we are going to retry. */
+ }
+}
+
+
+/* Retry strategy function that always declines to perform a retry. */
+static int
+alwaysfail (void* context)
+{
+ return 0;
+}
+
+/* Returns nonzero if the indicated status value denotes a failure */
+static int
+childfailed (int status)
+{
+ return !WIFEXITED(status) || WEXITSTATUS(status);
+}
+
+/* Count the length of an argument list */
+static unsigned int
+countargs (char * const *v[])
+{
+ unsigned int n = 0;
+ while (*v)
+ {
+ v++;
+ n++;
+ }
+ return n;
+}
+
+/* Send a (normally) fatal signal to a list of (child) processes */
+static void
+stopkids (const pid_t * pids, unsigned int n)
+{
+ int i;
+
+ for (i=0; i= N.
+ * The exit status for each child is placed into exit_status[].
+ *
+ * If DO_SETUID is true, attempt to change the uid to UID for this command.
+ *
+ * INPUT and OUTPUT are the file descriptors for the stdandard input of the first
+ * command in the pipeline and the standard output of the last, respectively.
+ *
+ * Note: We use the clumsy DO_SETUID to avoid messing around with setuid() when
+ * there's no need to.
+ */
+int
+run_pipeline (char * const **args, int do_setuid, uid_t uid,
+ int *exit_status, int input, int output)
+{
+ int debugflag = 0;
+ unsigned int i, j;
+ int n;
+ pid_t *child_pids;
+ int result = 1;
+ int *input_fds, *output_fds;
+ size_t sizmax = (size_t)~0uL;
+
+ n = countargs (args);
+ assert (args);
+ assert (exit_status);
+ assert (input >= 0);
+ assert (output >= 0);
+
+ assert (n > 0);
+ assert ((SIZE_MAX / sizeof(pid_t)) > n);
+ assert ((SIZE_MAX / (2*sizeof (int))) > n);
+
+ child_pids = malloc (sizeof (pid_t) * n);
+ input_fds = malloc (sizeof (int) * n);
+ output_fds = malloc (sizeof (int) * n);
+
+ for (i=0; i= 0);
+ assert (arglist);
+ assert (arglist[0]);
+
+ if (debugflag)
+ {
+ fprintf (stderr, "starting %s\n", arglist[0]);
+ }
+ child_pids[i] = start_command (0, 0, arglist,
+ do_setuid, uid,
+ input_fds[i], output_fds[i],
+ &child_errno, alwaysfail, NULL);
+ xclose (&input_fds[i]);
+ xclose (&output_fds[i]);
+
+ if (0 == child_pids[i])
+ {
+ /* Oh dear. Failed. */
+ stopkids (child_pids, 1+i);
+ result = 0;
+ }
+ }
+ if (debugflag)
+ {
+ fprintf (stderr, "started all commands.\n");
+ }
+
+ input_fds [0] = output_fds[n-1] = -1;
+
+ /* OK, we launched all the children. Wait for them to finish.
+ * We actually launched (1+i) processes (in the success case, of
+ * course n==1+i).
+ */
+ for (j=0u; j 0)
+ {
+ pid = waitpid (child_pids[j], &exit_status[j], 0);
+ assert(pid != 0);
+ assert(pid > 0);
+ assert (child_pids[j] == pid);
+ if (childfailed (exit_status[j]))
+ result = 0;
+ }
+ }
+ }
+
+ for (i=0u; i= 0)
+ xclose (&input_fds[i]);
+ if (output_fds[i] >= 0)
+ xclose (&output_fds[i]);
+ }
+
+ free (child_pids);
+ free (input_fds);
+ free (output_fds);
+
+ return result;
+}
+
diff --git a/locate/updatedb.c b/locate/updatedb.c
new file mode 100644
index 0000000..aa7ebf6
--- /dev/null
+++ b/locate/updatedb.c
@@ -0,0 +1,1076 @@
+/*
+ updatedb -- build a locate pathname database
+
+ Copyright (C) 2007 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 2, 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ USA.
+
+ csh original by James Woods; sh conversion by David MacKenzie.
+ Rewrite in C by Leslie P. Polzer and James Youngman.
+ Based on a proposal by James Youngman.
+
+*/
+
+#define _GNU_SOURCE
+
+#ifndef DEBUG
+#define STR(a) do{}while (0);
+#else
+#define STR(a) fprintf(stderr, "STR: %s=%s\n", #a, a);
+#endif
+
+#include
+
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+
+#ifdef HAVE_LOCALE_H
+#include
+#endif
+
+#if ENABLE_NLS
+# include
+# define _(Text) gettext (Text)
+#else
+# define _(Text) Text
+#define textdomain(Domain)
+#define bindtextdomain(Package, Directory)
+#endif
+#ifdef gettext_noop
+# define N_(String) gettext_noop (String)
+#else
+/* We used to use (String) instead of just String, but apparently ISO C
+ * doesn't allow this (at least, that's what HP said when someone reported
+ * this as a compiler bug). This is HP case number 1205608192. See
+ * also http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11250 (which references
+ * ANSI 3.5.7p14-15). The Intel icc compiler also rejects constructs
+ * like: static const char buf[] = ("string");
+ */
+# define N_(String) String
+#endif
+
+#include "quote.h"
+#include "quotearg.h"
+#include "printquoted.h"
+#include "gnulib-version.h"
+
+#include "../gnulib/lib/error.h"
+#include "../gnulib/lib/idcache.c"
+#include "../gnulib/lib/string.h"
+#include "../gnulib/lib/tempname.h"
+#include "tempname.h"
+#include "findutils-version.h"
+#include "locatedb.h"
+
+/*
+ * TODO:
+ *
+ * * install signal handlers for cleanup
+ *
+ * * support spaces in paths (e.g. prunepaths)
+ * - use char** for those
+ * - support 'prunepath'-style command line args
+ *
+ */
+
+typedef enum { OLD, LOCATE02, SLOCATE } DBFORMAT;
+
+
+
+struct map
+{
+ char *key;
+ char *value;
+};
+
+
+struct config
+{
+ char *findoptions;
+ char *shell;
+ char *searchpaths;
+ char *netpaths;
+ char *prunepaths;
+ char *pruneregex;
+ char *prunefs;
+ char *locate_db;
+ DBFORMAT dbformat;
+ char *localuser;
+ char *netuser;
+ char *libexecdir;
+ char *bindir;
+ char *changeto;
+ int quiet;
+
+ char *find;
+ char *frcode;
+ char *bigram;
+ char *code;
+};
+
+static struct config CFG =
+{
+ "", /* findoptions */
+ "/bin/sh", /* shell */
+ "/", /* searchpaths */
+ "", /* netpaths */
+ "/tmp /usr/tmp /var/tmp /afs /amd /sfs /proc", /* prunepaths */
+ "", /* pruneregex */
+ "nfs NFS proc afs proc smbfs autofs iso9660 ncpfs coda devpts ftpfs devfs mfs sysfs shfs", /* prunefs */
+ LOCATE_DB, /* locate_db */
+ LOCATE02, /* dbformat */
+ "", /* localuser */
+ "daemon", /* netuser */
+ LIBEXECDIR, /* libexecdir */
+ BINDIR, /* bindir */
+ "/", /* changeto */
+ 0, /* quiet */
+
+ FIND,
+ FRCODE,
+ BIGRAM,
+ CODE
+};
+
+static char** temps;
+static int ntemps = 0;
+
+static void
+add_temp_file (const char* tempfile)
+{
+ ++ntemps;
+ temps = realloc (temps, (ntemps)*sizeof(char*));
+ temps[ntemps-1] = strdup (tempfile);
+}
+
+static void
+cleanup_temp_files (void)
+{
+ int i;
+ for (i=0; i= 0)
+ {
+ saved_errno = errno;
+ if (0 != unlink(tempname_template))
+ {
+ close(fd);
+ errno = saved_errno;
+ return -1;
+ }
+ }
+ return fd;
+}
+
+
+int
+prunepaths_has_trailing_slashes (const char* prunepaths)
+{
+ char* paths = strdup (prunepaths);
+
+ while (paths)
+ {
+ char* path = strsep (&paths, " "); /* FIXME doesn't work for paths with spaces */
+
+ if (path[strlen(path)-1] == '/')
+ return 1;
+
+ }
+
+ free (paths);
+
+ return 0;
+}
+
+
+char*
+strcat_alloc (const char *string1, ...)
+{
+ int l;
+ va_list args;
+ char *s;
+ char *concat;
+ char *ptr;
+
+
+ if (!string1)
+ return NULL;
+
+ l = 1 + strlen (string1);
+ va_start (args, string1);
+ s = va_arg (args, char*);
+ while (s)
+ {
+ l += strlen (s);
+ s = va_arg (args, char*);
+ }
+ va_end (args);
+
+ concat = malloc (l);
+ ptr = concat;
+
+ ptr = stpcpy (ptr, string1);
+ va_start (args, string1);
+ s = va_arg (args, char*);
+ while (s)
+ {
+ ptr = stpcpy (ptr, s);
+ s = va_arg (args, char*);
+ }
+ va_end (args);
+
+ return concat;
+}
+
+
+static void
+is_regular_executable (const char *file)
+{
+ struct stat sbuf;
+
+ if (!file)
+ return;
+
+ if (stat (file, &sbuf) == -1)
+ error (1, errno, _("couldn't stat %s"),
+ quotearg_n_style (0, locale_quoting_style, file));
+
+ if (!S_ISREG (sbuf.st_mode))
+ error (1, 0, _("%s is not a regular file"), quotearg_n_style (0, locale_quoting_style, file));
+
+ if (!euidaccess (file, X_OK) == 0)
+ error (1, 0, _("no executable permission for %s"), quotearg_n_style (0, locale_quoting_style, file));
+
+ return;
+}
+
+
+static void
+check_executables (const char *file, ...)
+{
+ va_list args;
+ char *vf = NULL;
+
+ is_regular_executable (file);
+
+ va_start (args, file);
+ while (vf = va_arg (args, char*))
+ is_regular_executable (vf);
+ va_end (args);
+}
+
+
+static void
+usage (FILE* out)
+{
+ fprintf (out, "%s",
+ _("Usage: updatedb [--findoptions='-option1 -option2...']\n"
+ "\t[--localpaths='dir1 dir2...'] [--netpaths='dir1 dir2...']\n"
+ "\t[--prunepaths='dir1 dir2...'] [--prunefs='fs1 fs2...']\n"
+ "\t[--output=dbfile] [--changecwd=dir]\n"
+ "\t[--netuser=user] [--localuser=user]\n"
+ "\t[--old-format] [--quiet] [--version] [--help]\n"
+ "\n"
+ "Report bugs to .\n"));
+}
+
+
+static void
+parse_options (int* ac, char*** av)
+{
+ enum option_ids /* return values for getopt_long */
+ {
+ OPT_FINDOPTIONS,
+ OPT_SHELL,
+ OPT_SEARCHPATHS,
+ OPT_NETPATHS,
+ OPT_PRUNEPATHS,
+ OPT_PRUNEREGEX,
+ OPT_PRUNEFS,
+ OPT_LOCATE_DB,
+ OPT_LOCALUSER,
+ OPT_NETUSER,
+ OPT_LIBEXECDIR,
+ OPT_BINDIR,
+ OPT_CHANGECWD,
+ OPT_DBFORMAT,
+ OPT_OLDFORMAT
+ };
+
+ static struct option const longopts[] =
+ {
+ {"findoptions", required_argument, NULL, OPT_FINDOPTIONS},
+ {"shell", required_argument, NULL, OPT_SHELL},
+ {"localpaths", required_argument, NULL, OPT_SEARCHPATHS},
+ {"netpaths", required_argument, NULL, OPT_NETPATHS},
+ {"prunepaths", required_argument, NULL, OPT_PRUNEPATHS},
+ {"pruneregex", required_argument, NULL, OPT_PRUNEREGEX},
+ {"prunefs", required_argument, NULL, OPT_PRUNEFS},
+ {"output", required_argument, NULL, OPT_LOCATE_DB},
+ {"localuser", required_argument, NULL, OPT_LOCALUSER},
+ {"netuser", required_argument, NULL, OPT_NETUSER},
+ {"libexecdir", required_argument, NULL, OPT_LIBEXECDIR},
+ {"bindir", required_argument, NULL, OPT_BINDIR},
+ {"changecwd", required_argument, NULL, OPT_CHANGECWD},
+ {"dbformat", required_argument, NULL, OPT_DBFORMAT},
+ {"old-format", no_argument, NULL, OPT_OLDFORMAT},
+
+ {"help", no_argument, NULL, 'h'},
+ {"version", no_argument, NULL, 'v'},
+ {"quiet", no_argument, NULL, 'q'},
+
+ {NULL, no_argument, NULL, 0}
+ };
+
+ int optc;
+
+ /* environment processing */
+
+#define FROM_ENV(var, env) \
+ if (getenv (#env)) \
+ CFG.var = strdup (getenv (#env));
+
+
+ FROM_ENV (findoptions, FINDOPTIONS);
+ FROM_ENV (shell, SHELL);
+ FROM_ENV (searchpaths, SEARCHPATHS);
+ FROM_ENV (netpaths, NETPATHS);
+ FROM_ENV (prunepaths, PRUNEPATHS);
+ FROM_ENV (pruneregex, PRUNEREGEX);
+ FROM_ENV (prunefs, PRUNEFS);
+ FROM_ENV (locate_db, LOCATE_DB);
+ FROM_ENV (localuser, LOCALUSER);
+ FROM_ENV (netuser, NETUSER);
+ FROM_ENV (libexecdir, LIBEXECDIR);
+ FROM_ENV (bindir, BINDIR);
+ FROM_ENV (changeto, CHANGETO);
+
+
+ /* command-line processing */
+
+ while ((optc = getopt_long (*ac, *av, "h", longopts, (int *) 0)) != -1)
+ switch (optc)
+ {
+ case 'h':
+ usage (stdout);
+ exit (EXIT_SUCCESS);
+ break;
+
+ case 'v':
+ display_findutils_version("updatedb");
+ exit(EXIT_SUCCESS);
+ break;
+
+ case 'q':
+ CFG.quiet = 1; /* XXX this doesn't have any effect right now,
+ but will be useful in the future. */
+ break;
+
+ case OPT_FINDOPTIONS:
+ CFG.findoptions = optarg;
+ break;
+
+ case OPT_SHELL:
+ CFG.shell = optarg;
+ break;
+
+ case OPT_SEARCHPATHS:
+ CFG.searchpaths = optarg;
+ break;
+
+ case OPT_NETPATHS:
+ CFG.netpaths = optarg;
+ break;
+
+ case OPT_PRUNEPATHS:
+ if (prunepaths_has_trailing_slashes (optarg))
+ {
+ fprintf (stderr, _("pruned paths must not contain trailing slashes\n"));
+ exit (EXIT_FAILURE);
+ }
+ break;
+
+ case OPT_PRUNEREGEX:
+ CFG.pruneregex = optarg;
+ break;
+
+ case OPT_PRUNEFS:
+ CFG.prunefs = optarg;
+ break;
+
+ case OPT_LOCATE_DB:
+ CFG.locate_db = optarg;
+ break;
+
+ case OPT_LOCALUSER:
+ CFG.localuser = optarg;
+ break;
+
+ case OPT_NETUSER:
+ CFG.netuser = optarg;
+ break;
+
+ case OPT_LIBEXECDIR:
+ CFG.shell = optarg;
+ break;
+
+ case OPT_BINDIR:
+ CFG.bindir = optarg;
+ break;
+
+ case OPT_CHANGECWD:
+ CFG.changeto = optarg;
+ break;
+
+ case OPT_DBFORMAT:
+ if (strcasecmp ("locate02", optarg) == 0)
+ {
+ CFG.dbformat = LOCATE02;
+ }
+ else if (strcasecmp ("slocate", optarg) == 0)
+ {
+ CFG.dbformat = SLOCATE;
+ }
+ else if (strcasecmp ("old", optarg) == 0)
+ {
+ CFG.dbformat = OLD;
+ }
+ else
+ {
+ fprintf (stderr, _("Unsupported database format %s.\n"
+ "Supported formats are: LOCATE02 SLOCATE OLD\n"),
+ quotearg_n_style (0, locale_quoting_style, optarg));
+ exit (EXIT_FAILURE);
+ }
+ break;
+
+ case OPT_OLDFORMAT:
+ CFG.dbformat = OLD;
+ break;
+
+ default:
+ usage (stderr);
+ exit (EXIT_FAILURE);
+ }
+
+ STR (CFG.bindir);
+ STR (CFG.libexecdir);
+
+ CFG.find = strcat_alloc (CFG.bindir, "/" FIND, 0);
+ CFG.frcode = strcat_alloc (CFG.libexecdir, "/" FRCODE, 0);
+ CFG.bigram = strcat_alloc (CFG.libexecdir, "/" BIGRAM, 0);
+ CFG.code = strcat_alloc (CFG.libexecdir, "/" CODE, 0);
+}
+
+
+/* cmd represents a set of arguments that we will eventually pass to
+ * an exec function. We use this prepresentation for conveniently
+ * appending extra arguments.
+ *
+ * We don't have a separate filename and argv[0]. The argv[0]
+ * value we use should be the actual filename of the executable.
+ *
+ * The argument vector is allocated (and extended) by us, but we
+ * assume that the actual arguments are owned by somebody else.
+ */
+struct cmd
+{
+ char ** args;
+ int nargs;
+};
+
+/* Add an argument to a command. */
+static void
+addarg (struct cmd* ctl, const char *arg)
+{
+ ctl->args = realloc (ctl->args, (ctl->nargs+1)*sizeof(char*));
+ ctl->args[ctl->nargs] = (char*)arg;
+ ++ctl->nargs;
+}
+
+/* Create a new command. To begin with, there is not even an executable name. */
+static struct cmd*
+newcmd (void)
+{
+ struct cmd *ctl = malloc(sizeof(struct cmd));
+ ctl->args = NULL;
+ ctl->nargs = 0;
+ return ctl;
+}
+
+/* Delete a command structure. */
+static void
+delcmd (struct cmd *p)
+{
+ /* Assume we do not own the individual arguments. */
+ free (p->args);
+ free (p);
+}
+
+/* Copy arguments out of one cmd into another */
+static void
+appendargs (struct cmd *ctl, struct cmd* extra)
+{
+ int i;
+ for (i=0; inargs; ++i)
+ {
+ addarg (ctl, extra->args[i]);
+ }
+}
+
+
+/* Split a string on spaces and append each element of the result to
+ * the arguments of a command.
+ */
+static void
+split_and_append_args (struct cmd* ctl, const char *s)
+{
+ if (strlen(s))
+ {
+ char *p = strdup(s);
+ if (s)
+ {
+ char *tmp;
+ while (tmp = strsep (&p, " "))
+ {
+ addarg (ctl, tmp);
+ }
+ }
+ free(p);
+ }
+}
+
+/* Build a find command to search a specific list of directories
+ * taking into a accoutn a set of prune conditions.
+ */
+static struct cmd*
+build_find_cmd (int null_terminate,
+ const char* executable,
+ const char* paths,
+ const char* options,
+ struct cmd* prune_paths)
+{
+ struct cmd *p = newcmd();
+ int n;
+
+ addarg (p, executable);
+ n = p->nargs;
+ split_and_append_args (p, paths);
+ if (n == p->nargs)
+ {
+ delcmd (p);
+ return NULL;
+ }
+ split_and_append_args (p, options);
+ addarg (p, "(");
+ appendargs (p, prune_paths);
+ addarg (p, ")");
+ addarg (p, "-prune");
+ addarg (p, "-o");
+ if (null_terminate)
+ addarg (p, "-print0");
+ else
+ addarg (p, "-print");
+ return p;
+}
+
+
+/* Given a list of paths a list of filesystems to
+ * avoid, build a set of find tests which will
+ * prune the search tree appropriately.
+ */
+struct cmd*
+build_prune_test_list(const char *c_prunepaths,
+ const char *c_prunefs)
+{
+ char* prune_items;
+ char *s, *tmp;
+ struct cmd* p;
+ int prune_item_added = 0;
+
+ p = newcmd();
+
+ STR (c_prunepaths);
+ s = prune_items = strdup (c_prunepaths);
+ while (tmp = strsep (&s, " "))
+ {
+ STR (tmp);
+ if (prune_item_added)
+ addarg (p, "-o");
+ addarg (p, "-type");
+ addarg (p, "d");
+ addarg (p, "-wholename");
+ addarg (p, strdup(tmp));
+ prune_item_added = 1;
+ }
+ free(prune_items);
+
+ /* prunefs */
+ STR (c_prunefs);
+ s = prune_items = strdup (c_prunefs);
+ while (tmp = strsep (&s, " "))
+ {
+ STR (tmp);
+ if (prune_item_added)
+ addarg (p, "-o");
+ addarg (p, "-fstype");
+ addarg (p, strdup(tmp));
+ prune_item_added = 1;
+ }
+ free (prune_items);
+ return p;
+}
+
+
+/* Analyse the exit status of a program. If it exited unsuccessfully,
+ * print a suitable error message.
+ */
+static int
+diagnose (const char *command,
+ int status)
+{
+ if (WIFEXITED(status))
+ {
+ int rv = WEXITSTATUS(status);
+ if (rv)
+ {
+ error(0, 0,
+ _("%s returned exit status %d"),
+ command, rv);
+ }
+ return rv;
+ }
+ else if (WIFSIGNALED(status))
+ {
+ int rv = 128+WTERMSIG(status);
+ error(0, 0,
+ _("%s was killed by signal %d"),
+ command, WTERMSIG(status));
+ return rv;
+ }
+ else
+ {
+ error(0, 0,
+ _("%s was killed by signal %d"),
+ command, WTERMSIG(status));
+ return -1;
+ }
+}
+
+/* Diagnose the exit statuses of the elements of a pipeline. */
+static int
+diagnose_pipeline (char *const **commands,
+ const int *statusinfo)
+{
+ int worst = 0;
+ while (*commands)
+ {
+ int status = diagnose (commands[0][0], *statusinfo);
+ if (status > worst)
+ worst = status;
+ ++commands;
+ ++statusinfo;
+ }
+ return worst;
+}
+
+
+/*
+ * Encode a file list with frcode, producing a LOCATE02 format (or an slocate format)
+ * locate database.
+ */
+static int
+encode_with_frcode (int null_terminate, int file_list_fd, int output_fd)
+{
+ enum { NCOMMANDS = 3 };
+ char * const * frcode_pipeline[NCOMMANDS];
+ struct cmd* command[NCOMMANDS];
+ int status[NCOMMANDS];
+ int i;
+
+
+ i = 0;
+ assert(i+1 < NCOMMANDS);
+ command[i] = newcmd();
+ addarg (command[i], "sort");
+ addarg (command[i], "-f");
+ if (null_terminate)
+ addarg (command[i], "-z");
+
+
+ assert(i+1 < NCOMMANDS);
+ command[++i] = newcmd();
+ addarg (command[i], CFG.frcode);
+ if (null_terminate)
+ addarg (command[i], "-0");
+
+ if (SLOCATE == CFG.dbformat)
+ {
+ addarg (command[i], "-S");
+ addarg (command[i], "1");
+ }
+
+ assert(i+1 < NCOMMANDS);
+ command[++i] = NULL;
+
+ for (i=0; iargs;
+ }
+ else
+ {
+ frcode_pipeline[i] = NULL;
+ }
+ }
+
+ run_pipeline (frcode_pipeline, 0, 0, status, file_list_fd, output_fd);
+ return diagnose_pipeline (frcode_pipeline, status);
+}
+
+
+/*
+ * Encode a file list with bigram and code, producing an old format
+ * locate database.
+ */
+static int
+encode_with_bigram(int null_terminate, int file_list_fd, int output_fd)
+{
+ char bigram_template[] = "/tmp/updatedb-bigrams.XXXXXX";
+ unsigned int i;
+ int rv, saved_errno;
+ enum { NCOMMANDS = 7 };
+ char * const * bigram_pipeline[NCOMMANDS];
+ struct cmd* command[NCOMMANDS];
+ int status[NCOMMANDS];
+ int bigram_fd;
+
+ assert (0 == null_terminate);
+
+ if (0 != lseek (file_list_fd, 0, SEEK_SET))
+ error (1, errno, _("lseek failed on file list"));
+
+ i = 0;
+ assert(0 < NCOMMANDS);
+ command[i] = newcmd();
+ addarg (command[i], CFG.bigram);
+
+ assert(i+1 < NCOMMANDS);
+ command[++i] = newcmd();
+ addarg (command[i], "sort");
+
+ assert(i+1 < NCOMMANDS);
+ command[++i] = newcmd();
+ addarg (command[i], "uniq");
+ addarg (command[i], "-c");
+
+ assert(i+1 < NCOMMANDS);
+ command[++i] = newcmd();
+ addarg (command[i], "sort");
+ addarg (command[i], "-n");
+ addarg (command[i], "-r");
+
+ assert(i+1 < NCOMMANDS);
+ command[++i] = newcmd();
+ addarg (command[i], "awk");
+ addarg (command[i], "{ if (NR <= 128) print $2 }");
+
+ assert(i+1 < NCOMMANDS);
+ command[++i] = newcmd();
+ addarg (command[i], "tr");
+ addarg (command[i], "-d");
+ addarg (command[i], "\\012");
+
+ assert(i+1 < NCOMMANDS);
+ command[++i] = NULL;
+ assert(i == NCOMMANDS-1);
+
+ for (i=0; iargs;
+ }
+ else
+ {
+ bigram_pipeline[i] = NULL;
+ }
+ status[i] = 0;
+ }
+
+ /* Create the bigram file. */
+ bigram_fd = gen_tempname (bigram_template, GT_FILE);
+ if (bigram_fd < 0)
+ {
+ saved_errno = errno;
+ error(0, errno, _("failed to create temporary file"));
+ return 1;
+ }
+
+ /* Compute and save the bigram list. */
+ run_pipeline (bigram_pipeline, 0, 0, status, file_list_fd, bigram_fd);
+ if (diagnose_pipeline (bigram_pipeline, status))
+ {
+ saved_errno = errno;
+ unlink (bigram_template);
+ errno = saved_errno;
+ return 1;
+ }
+
+ /* Clean up the pipeline */
+ for (i=0; iargs;
+
+ command[++i] = newcmd ();
+ addarg (command[i], CFG.code);
+ addarg (command[i], bigram_template);
+ addarg (command[i], NULL);
+ bigram_pipeline[i] = command[i]->args;
+
+ bigram_pipeline[++i] = NULL;
+
+ run_pipeline(bigram_pipeline, 0, 0, status, file_list_fd, output_fd);
+ rv = 0;
+ if (diagnose_pipeline (bigram_pipeline, status))
+ rv = 1;
+
+ if (0 != unlink (bigram_template))
+ {
+ error(0, errno, _("failed to delete %s"), bigram_template);
+ rv = 1;
+ }
+ return rv;
+}
+
+
+/* small specialization of run_pipeline */
+static int
+run_pipeline_as_user (char * const **args, const char* user,
+ int *exit_status, int input, int output)
+{
+ int do_setuid = 0;
+ uid_t uid, *puid;
+
+ uid = geteuid ();
+ if (user[0])
+ {
+ puid = getuidbyname (user);
+ if (NULL == puid)
+ {
+ error (1, errno, _("could not get UID for user %s"),
+ quotearg_n_style (0, locale_quoting_style, user));
+ /*NOTREACHED*/
+ }
+ else
+ {
+ do_setuid = (*puid != uid);
+ uid = *puid;
+ }
+ }
+ return run_pipeline (args, do_setuid, uid, exit_status, input, output);
+}
+
+
+int
+main (int argc, char **argv)
+{
+ char * const * db_pipeline[] = {NULL, NULL, NULL};
+ int tmpfile_fd, output_fd, saved_errno;
+ size_t dbfilename_len;
+ int status[3];
+ char *tmpdb, *codefile;
+ struct cmd *sort=NULL, *local_find=NULL, *net_find=NULL;
+ struct cmd *prune_paths=NULL;
+ int (*encoder)(int nullterminate, int input, int output);
+ int null_terminate;
+
+
+#ifdef HAVE_SETLOCALE
+ setlocale (LC_ALL, "");
+#endif
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ parse_options (&argc, &argv);
+
+ STR (CFG.find);
+ STR (CFG.frcode);
+ STR (CFG.bigram);
+ STR (CFG.code);
+
+ check_executables (CFG.find, CFG.frcode, CFG.bigram, CFG.code, 0);
+
+ prune_paths = newcmd();
+
+#if 0
+ prune_old_temporaries();
+ setup_signal_handlers(); /* remove $LOCATE_DB.n on HUP & TERM */
+#endif
+
+ chdir (CFG.changeto);
+
+
+ if (CFG.dbformat == OLD)
+ {
+ encoder = encode_with_bigram;
+ null_terminate = 0;
+ }
+ else
+ {
+ encoder = encode_with_frcode;
+#ifdef SORT_SUPPORTS_Z
+ null_terminate = 1;
+#else
+ null_terminate = 0;
+#endif
+ }
+
+ prune_paths = build_prune_test_list (CFG.prunepaths, CFG.prunefs);
+ local_find = build_find_cmd (null_terminate, CFG.find, CFG.searchpaths, CFG.findoptions, prune_paths);
+ net_find = build_find_cmd (null_terminate, CFG.find, CFG.netpaths, CFG.findoptions, prune_paths);
+
+ atexit (cleanup_temp_files);
+ tmpfile_fd = scratchfile();
+ if (tmpfile_fd < 0)
+ error(1, errno, _("failed to create temporary file"));
+
+ if (local_find)
+ {
+ addarg (local_find, NULL);
+ db_pipeline[0] = local_find->args;
+ db_pipeline[1] = NULL;
+
+ run_pipeline_as_user (db_pipeline, CFG.localuser, status, STDIN_FILENO, tmpfile_fd);
+
+ if (diagnose_pipeline (db_pipeline, status))
+ return 1;
+ }
+ if (net_find)
+ {
+ addarg (net_find, NULL);
+ db_pipeline[0] = net_find->args;
+ db_pipeline[1] = NULL;
+ run_pipeline_as_user (db_pipeline, CFG.netuser, status, STDIN_FILENO, tmpfile_fd);
+
+ if (diagnose_pipeline (db_pipeline, status))
+ return 1;
+ }
+ /* rewind output file to use it as input */
+ if (0 != lseek(tmpfile_fd, 0, SEEK_SET))
+ error (1, errno, _("lseek failed on temporary file"));
+
+ dbfilename_len = 1+strlen (CFG.locate_db)+2;
+ tmpdb = malloc (dbfilename_len);
+ sprintf (tmpdb, "%s.n", CFG.locate_db);
+
+ output_fd = open (tmpdb, O_WRONLY|O_CREAT, 0644);
+ if (output_fd < 0)
+ error (1, errno, CFG.locate_db);
+
+ if (0 != encoder (null_terminate, tmpfile_fd, output_fd))
+ {
+ unlink (tmpdb);
+ return 1;
+ }
+ else
+ {
+ /* Delete the old database, but don't fail if it
+ * didn't exist anyway.
+ */
+ if (0 != unlink (CFG.locate_db))
+ {
+ saved_errno = errno;
+ if (ENOENT != errno)
+ {
+ unlink (tmpdb);
+ error (1, saved_errno, CFG.locate_db);
+ }
+ }
+ if (0 != rename (tmpdb, CFG.locate_db))
+ {
+ saved_errno = errno;
+ unlink (tmpdb);
+ error (1, saved_errno, tmpdb);
+ }
+ }
+ free (tmpdb);
+ return 0;
+}
+
diff --git a/locate/updatedb.sh b/locate/updatedb.sh
index 9f4e4d9..2c572ca 100644
--- a/locate/updatedb.sh
+++ b/locate/updatedb.sh
@@ -1,22 +1,5 @@
#! /bin/sh
-# updatedb -- build a locate pathname database
-# Copyright (C) 1994, 1996, 1997, 2000, 2001, 2003, 2004, 2005, 2006
-# 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 .
-
-# csh original by James Woods; sh conversion by David MacKenzie.
+
#exec 2> /tmp/updatedb-trace.txt
#set -x
@@ -174,108 +157,48 @@ done
test -z "$PRUNEREGEX" &&
PRUNEREGEX=`echo $PRUNEPATHS|sed -e 's,^,\\\(^,' -e 's, ,$\\\)\\\|\\\(^,g' -e 's,$,$\\\),'`
-# The database file to build.
-: address@hidden@}
-
-# Directory to hold intermediate files.
-if test -d /var/tmp; then
- : ${TMPDIR=/var/tmp}
-elif test -d /usr/tmp; then
- : ${TMPDIR=/usr/tmp}
-else
- : ${TMPDIR=/tmp}
-fi
-export TMPDIR
-
-# The user to search network directories as.
-: ${NETUSER=daemon}
-
-# The directory containing the subprograms.
-if test -n "$LIBEXECDIR" ; then
- : LIBEXECDIR already set, do nothing
-else
- : address@hidden@}
-fi
-
-# The directory containing find.
-if test -n "$BINDIR" ; then
- : BINDIR already set, do nothing
-else
- : address@hidden@}
-fi
-
-# The names of the utilities to run to build the database.
-: ${find:=${BINDIR}/@address@hidden
-: ${frcode:=${LIBEXECDIR}/@address@hidden
-: ${bigram:=${LIBEXECDIR}/@address@hidden
-: ${code:=${LIBEXECDIR}/@address@hidden
-
-checkbinary () {
- if test -x "$1" ; then
- : ok
+ if test -n "$PRUNEFS"; then
+ # findify prunefs
+ prunefs_exp=`echo $PRUNEFS |sed -e 's/\([^ ][^ ]*\)/-o -fstype \1/g' \
+ -e 's/-o //' -e 's/$/ -o/'`
else
- eval echo "updatedb needs to be able to execute $1, but cannot." >&2
- exit 1
+ prunefs_exp=''
fi
-}
-
-for binary in $find $frcode $bigram $code
-do
- checkbinary $binary
-done
-
-
-PATH=/bin:/usr/bin:${BINDIR}; export PATH
-
-: ${PRUNEFS="nfs NFS proc afs proc smbfs autofs iso9660 ncpfs coda devpts ftpfs devfs mfs sysfs shfs"}
-if test -n "$PRUNEFS"; then
-prunefs_exp=`echo $PRUNEFS |sed -e 's/\([^ ][^ ]*\)/-o -fstype \1/g' \
- -e 's/-o //' -e 's/$/ -o/'`
-else
- prunefs_exp=''
-fi
# Make and code the file list.
# Sort case insensitively for users' convenience.
-rm -f $LOCATE_DB.n
-trap 'rm -f $LOCATE_DB.n; exit' HUP TERM
-
-if test $old = no; then
-# LOCATE02 or slocate format
if {
-cd "$changeto"
-if test -n "$SEARCHPATHS"; then
+ cd "$changeto"
+ if test -n "$SEARCHPATHS"; then
if [ "$LOCALUSER" != "" ]; then
- # : A1
su $LOCALUSER `select_shell $LOCALUSER` -c \
"$find $SEARCHPATHS $FINDOPTIONS \
\\( $prunefs_exp \
-type d -regex '$PRUNEREGEX' \\) -prune -o $print_option"
else
- # : A2
$find $SEARCHPATHS $FINDOPTIONS \
\( $prunefs_exp \
-type d -regex "$PRUNEREGEX" \) -prune -o $print_option
fi
-fi
+ fi # SEARCHPATHS
-if test -n "$NETPATHS"; then
-myuid=`getuid`
-if [ "$myuid" = 0 ]; then
- # : A3
+ if test -n "$NETPATHS"; then
+ myuid=`getuid`
+ if [ "$myuid" = 0 ]; then
su $NETUSER `select_shell $NETUSER` -c \
"$find $NETPATHS $FINDOPTIONS \\( -type d -regex '$PRUNEREGEX' -prune \\) -o $print_option" ||
exit $?
else
- # : A4
$find $NETPATHS $FINDOPTIONS \( -type d -regex "$PRUNEREGEX" -prune \) -o $print_option ||
exit $?
fi
-fi
+ fi # NETPATHS
+
} | $sort -f | $frcode $frcode_options > $LOCATE_DB.n
+
then
: OK so far
true
@@ -289,82 +212,12 @@ fi
# To avoid breaking locate while this script is running, put the
# results in a temp file, then rename it atomically.
if test -s $LOCATE_DB.n; then
- chmod 644 ${LOCATE_DB}.n
- mv ${LOCATE_DB}.n $LOCATE_DB
+ rm -f $LOCATE_DB
+ mv $LOCATE_DB.n $LOCATE_DB
+ chmod 644 $LOCATE_DB
else
echo "updatedb: new database would be empty" >&2
rm -f $LOCATE_DB.n
fi
-else # old
-
-if ! bigrams=`mktemp -t updatedbXXXXXXXXX`; then
- echo mktemp failed >&2
- exit 1
-fi
-
-if ! filelist=`mktemp -t updatedbXXXXXXXXX`; then
- echo mktemp failed >&2
- exit 1
-fi
-
-rm -f $LOCATE_DB.n
-trap 'rm -f $bigrams $filelist $LOCATE_DB.n; exit' HUP TERM
-
-# Alphabetize subdirectories before file entries using tr. James Woods says:
-# "to get everything in monotonic collating sequence, to avoid some
-# breakage i'll have to think about."
-{
-cd "$changeto"
-if test -n "$SEARCHPATHS"; then
- if [ "$LOCALUSER" != "" ]; then
- # : A5
- su $LOCALUSER `select_shell $LOCALUSER` -c \
- "$find $SEARCHPATHS $FINDOPTIONS \
- \( $prunefs_exp \
- -type d -regex '$PRUNEREGEX' \) -prune -o $print_option" || exit $?
- else
- # : A6
- $find $SEARCHPATHS $FINDOPTIONS \
- \( $prunefs_exp \
- -type d -regex "$PRUNEREGEX" \) -prune -o $print_option || exit $?
- fi
-fi
-
-if test -n "$NETPATHS"; then
- myuid=`getuid`
- if [ "$myuid" = 0 ]; then
- # : A7
- su $NETUSER `select_shell $NETUSER` -c \
- "$find $NETPATHS $FINDOPTIONS \\( -type d -regex '$PRUNEREGEX' -prune \\) -o $print_option" ||
- exit $?
- else
- # : A8
- $find $NETPATHS $FINDOPTIONS \( -type d -regex "$PRUNEREGEX" -prune \) -o $print_option ||
- exit $?
- fi
-fi
-} | tr / '\001' | $sort -f | tr '\001' / > $filelist
-
-# Compute the (at most 128) most common bigrams in the file list.
-$bigram $bigram_opts < $filelist | sort | uniq -c | sort -nr |
- awk '{ if (NR <= 128) print $2 }' | tr -d '\012' > $bigrams
-
-# Code the file list.
-$code $bigrams < $filelist > $LOCATE_DB.n
-
-rm -f $bigrams $filelist
-
-# To reduce the chances of breaking locate while this script is running,
-# put the results in a temp file, then rename it atomically.
-if test -s $LOCATE_DB.n; then
- chmod 644 ${LOCATE_DB}.n
- mv ${LOCATE_DB}.n $LOCATE_DB
-else
- echo "updatedb: new database would be empty" >&2
- rm -f $LOCATE_DB.n
-fi
-
-fi
-
exit 0
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 0afb2c7..3491eb8 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -37,4 +37,5 @@ locate/code.c
locate/frcode.c
locate/locate.c
locate/word_io.c
+locate/updatedb.c
xargs/xargs.c
--
1.5.3.8