summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/accessdb.c8
-rw-r--r--src/catman.c32
-rw-r--r--src/check_mandirs.c130
-rw-r--r--src/check_mandirs.h8
-rw-r--r--src/man.c13
-rw-r--r--src/mandb.c80
-rw-r--r--src/straycats.c16
-rw-r--r--src/straycats.h4
-rw-r--r--src/tests/Makefile.am6
-rw-r--r--src/tests/get-mtime.c74
-rwxr-xr-xsrc/tests/mandb-purge-updates-timestamp67
-rw-r--r--src/whatis.c26
12 files changed, 284 insertions, 180 deletions
diff --git a/src/accessdb.c b/src/accessdb.c
index dcd81ea2..dadca86b 100644
--- a/src/accessdb.c
+++ b/src/accessdb.c
@@ -132,9 +132,9 @@ int main (int argc, char *argv[])
if (argp_parse (&argp, argc, argv, 0, 0, 0))
exit (FAIL);
- dbf = MYDBM_RDOPEN (database);
- if (dbf && dbver_rd (dbf)) {
- MYDBM_CLOSE (dbf);
+ dbf = MYDBM_NEW (database);
+ if (!MYDBM_RDOPEN (dbf) || dbver_rd (dbf)) {
+ MYDBM_FREE (dbf);
dbf = NULL;
}
if (!dbf)
@@ -172,6 +172,6 @@ next:
key = nextkey;
}
- MYDBM_CLOSE (dbf);
+ MYDBM_FREE (dbf);
exit (ret);
}
diff --git a/src/catman.c b/src/catman.c
index 9a396354..4be5f7bf 100644
--- a/src/catman.c
+++ b/src/catman.c
@@ -173,8 +173,7 @@ static gl_list_t manpathlist;
static void post_fork (void)
{
pop_all_cleanups ();
- if (dbf_close_post_fork)
- MYDBM_CLOSE (dbf_close_post_fork);
+ MYDBM_FREE (dbf_close_post_fork);
}
/* Execute man with the appropriate catman args. Always frees cmd. */
@@ -225,26 +224,14 @@ static size_t add_arg (pipecmd *cmd, datum key)
/* find all pages that are in the supplied manpath and section and that are
ultimate source files. */
-static int parse_for_sec (const char *database,
+static int parse_for_sec (MYDBM_FILE dbf,
const char *manpath, const char *section)
{
- MYDBM_FILE dbf;
pipecmd *basecmd, *cmd;
datum key;
size_t arg_size, initial_bit;
int message = 1, first_arg;
- dbf = MYDBM_RDOPEN (database);
- if (!dbf) {
- error (0, errno, _("cannot read database %s"), database);
- return 1;
- }
- if (dbver_rd (dbf)) {
- MYDBM_CLOSE (dbf);
- return 1;
- }
- dbf_close_post_fork = dbf;
-
basecmd = pipecmd_new (MAN);
pipecmd_clearenv (basecmd);
@@ -344,8 +331,6 @@ static int parse_for_sec (const char *database,
key = nextkey;
}
- dbf_close_post_fork = NULL;
- MYDBM_CLOSE (dbf);
if (pipecmd_get_nargs (cmd) > first_arg)
catman (cmd);
else
@@ -407,6 +392,7 @@ int main (int argc, char *argv[])
GL_LIST_FOREACH (manpathlist, mp) {
char *catpath, *database;
+ MYDBM_FILE dbf;
size_t len;
catpath = get_catpath (mp, SYSTEM_CAT | USER_CAT);
@@ -423,6 +409,13 @@ int main (int argc, char *argv[])
database = mkdbname (mp);
catpath = xstrdup (mp);
}
+ dbf = MYDBM_NEW (database);
+ if (!MYDBM_RDOPEN (dbf) || dbver_rd (dbf)) {
+ error (0, errno, _("cannot read database %s"),
+ database);
+ goto next;
+ }
+ dbf_close_post_fork = dbf;
len = strlen (catpath);
@@ -433,12 +426,15 @@ int main (int argc, char *argv[])
continue;
if (check_access (catpath))
continue;
- if (parse_for_sec (database, mp, *sp)) {
+ if (parse_for_sec (dbf, mp, *sp)) {
error (0, 0, _("unable to update %s"), mp);
break;
}
}
+next:
+ dbf_close_post_fork = NULL;
+ MYDBM_FREE (dbf);
free (database);
free (catpath);
}
diff --git a/src/check_mandirs.c b/src/check_mandirs.c
index d604d90b..3e3be20d 100644
--- a/src/check_mandirs.c
+++ b/src/check_mandirs.c
@@ -120,21 +120,32 @@ static inline bool is_eagain (int err)
}
#pragma GCC diagnostic pop
-static void gripe_rwopen_failed (const char *database)
+static void gripe_rwopen_failed (MYDBM_FILE dbf)
{
if (errno == EACCES || errno == EROFS)
- debug ("database %s is read-only\n", database);
+ debug ("database %s is read-only\n", dbf->name);
else if (is_eagain (errno))
- debug ("database %s is locked by another process\n", database);
+ debug ("database %s is locked by another process\n", dbf->name);
else {
#ifdef MAN_DB_UPDATES
if (!quiet)
#endif /* MAN_DB_UPDATES */
error (0, errno, _("can't update index cache %s"),
- database);
+ dbf->name);
}
}
+static bool ensure_db_open (MYDBM_FILE dbf)
+{
+ if (dbf->file)
+ return true;
+ if (!MYDBM_RWOPEN (dbf)) {
+ gripe_rwopen_failed (dbf);
+ return false;
+ }
+ return true;
+}
+
/* Take absolute filename and path (for ult_src) and do sanity checks on
* file. Also check that file is non-zero in length and is not already in
* the db. If not, find its ult_src() and see if we have the whatis cached,
@@ -501,8 +512,7 @@ static void fix_permissions_tree (const char *catdir)
* any dirs of the tree that have been modified (ie added to) will then be
* scanned for new files, which are then added to the db.
*/
-static int testmandirs (const char *database,
- const char *path, const char *catpath,
+static int testmandirs (MYDBM_FILE dbf, const char *path, const char *catpath,
struct timespec last, bool create)
{
DIR *dir;
@@ -530,7 +540,6 @@ static int testmandirs (const char *database,
while( (mandir = readdir (dir)) ) {
struct stat stbuf;
struct timespec mtime;
- MYDBM_FILE dbf;
if (strncmp (mandir->d_name, "man", 3) != 0)
continue;
@@ -563,17 +572,16 @@ static int testmandirs (const char *database,
/* Open the db in CTRW mode to store the $ver$ ID */
- dbf = MYDBM_CTRWOPEN (database);
- if (dbf == NULL) {
+ if (!MYDBM_CTRWOPEN (dbf)) {
if (errno == EACCES || errno == EROFS) {
debug ("database %s is read-only\n",
- database);
+ dbf->name);
closedir (dir);
return 0;
} else {
error (0, errno,
_("can't create index cache %s"),
- database);
+ dbf->name);
closedir (dir);
return -1;
}
@@ -582,11 +590,7 @@ static int testmandirs (const char *database,
dbver_wr (dbf);
created = true;
- } else
- dbf = MYDBM_RWOPEN(database);
-
- if (!dbf) {
- gripe_rwopen_failed (database);
+ } else if (!ensure_db_open (dbf)) {
closedir (dir);
return 0;
}
@@ -603,7 +607,6 @@ static int testmandirs (const char *database,
fprintf (stderr, "\n");
}
add_dir_entries (dbf, path, mandir->d_name);
- MYDBM_CLOSE (dbf);
amount++;
}
closedir (dir);
@@ -611,56 +614,20 @@ static int testmandirs (const char *database,
return amount;
}
-/* update the modification timestamp of `database' */
-static void update_db_time (const char *database)
-{
- MYDBM_FILE dbf;
- struct timespec now;
-
- /* Open the db in RW to update its mtime */
- /* we know that this should succeed because we just updated the db! */
- dbf = MYDBM_RWOPEN (database);
- if (dbf == NULL) {
- if (is_eagain (errno))
- /* Another mandb process is probably running. With
- * any luck it will update the mtime ...
- */
- debug ("database %s is locked by another process\n",
- database);
- else {
-#ifdef MAN_DB_UPDATES
- if (!quiet)
-#endif /* MAN_DB_UPDATES */
- error (0, errno,
- _("can't update index cache %s"),
- database);
- }
- return;
- }
- now.tv_sec = 0;
- now.tv_nsec = UTIME_NOW;
- MYDBM_SET_TIME (dbf, now);
-
- MYDBM_CLOSE (dbf);
-}
-
/* routine to prepare/create the db prior to calling testmandirs() */
-int create_db (const char *database, const char *manpath, const char *catpath)
+int create_db (MYDBM_FILE dbf, const char *manpath, const char *catpath)
{
struct timespec time_zero;
int amount;
- debug ("create_db(%s): %s\n", manpath, database);
+ debug ("create_db(%s): %s\n", manpath, dbf->name);
time_zero.tv_sec = 0;
time_zero.tv_nsec = 0;
- amount = testmandirs (database, manpath, catpath, time_zero, true);
+ amount = testmandirs (dbf, manpath, catpath, time_zero, true);
- if (amount > 0) {
- update_db_time (database);
- if (!quiet)
- fputs (_("done.\n"), stderr);
- }
+ if (amount > 0 && !quiet)
+ fputs (_("done.\n"), stderr);
return amount;
}
@@ -700,33 +667,23 @@ static bool sanity_check_db (MYDBM_FILE dbf)
/* routine to update the db, ensure that it is consistent with the
filesystem */
-int update_db (const char *database, const char *manpath, const char *catpath)
+int update_db (MYDBM_FILE dbf, const char *manpath, const char *catpath)
{
- MYDBM_FILE dbf;
struct timespec mtime;
int new;
- dbf = MYDBM_RDOPEN (database);
- if (dbf && !sanity_check_db (dbf)) {
- MYDBM_CLOSE (dbf);
- dbf = NULL;
- }
- if (!dbf) {
- debug ("failed to open %s O_RDONLY\n", database);
+ if (!ensure_db_open (dbf) || !sanity_check_db (dbf)) {
+ debug ("failed to open %s O_RDONLY\n", dbf->name);
return -1;
}
mtime = MYDBM_GET_TIME (dbf);
- MYDBM_CLOSE (dbf);
debug ("update_db(): %ld.%09ld\n",
(long) mtime.tv_sec, (long) mtime.tv_nsec);
- new = testmandirs (database, manpath, catpath, mtime, false);
+ new = testmandirs (dbf, manpath, catpath, mtime, false);
- if (new > 0) {
- update_db_time (database);
- if (!quiet)
- fputs (_("done.\n"), stderr);
- }
+ if (new > 0 && !quiet)
+ fputs (_("done.\n"), stderr);
return new;
}
@@ -972,25 +929,23 @@ static int check_multi_key (const char *name, const char *content)
/* Go through the database and purge references to man pages that no longer
* exist.
*/
-int purge_missing (const char *database,
- const char *manpath, const char *catpath)
+int purge_missing (MYDBM_FILE dbf, const char *manpath, const char *catpath)
{
#ifdef NDBM
char *dirfile;
#endif
struct stat st;
bool db_exists;
- MYDBM_FILE dbf;
datum key;
int count = 0;
struct timespec db_mtime;
#ifdef NDBM
- dirfile = xasprintf ("%s.dir", database);
+ dirfile = xasprintf ("%s.dir", dbf->name);
db_exists = stat (dirfile, &st) == 0;
free (dirfile);
#else
- db_exists = stat (database, &st) == 0;
+ db_exists = stat (dbf->name, &st) == 0;
#endif
if (!db_exists)
/* nothing to purge */
@@ -999,14 +954,8 @@ int purge_missing (const char *database,
if (!quiet)
printf (_("Purging old database entries in %s...\n"), manpath);
- dbf = MYDBM_RWOPEN (database);
- if (!dbf) {
- gripe_rwopen_failed (database);
- return 0;
- }
- if (!sanity_check_db (dbf)) {
- MYDBM_CLOSE (dbf);
- dbf = NULL;
+ if (!ensure_db_open (dbf) || !sanity_check_db (dbf)) {
+ gripe_rwopen_failed (dbf);
return 0;
}
db_mtime = MYDBM_GET_TIME (dbf);
@@ -1102,12 +1051,5 @@ int purge_missing (const char *database,
key = nextkey;
}
- MYDBM_REORG (dbf);
- /* Reset mtime to avoid confusing mandb into not running.
- * TODO: It would be better to avoid this by only opening the
- * database once between here and mandb.
- */
- MYDBM_SET_TIME (dbf, db_mtime);
- MYDBM_CLOSE (dbf);
return count;
}
diff --git a/src/check_mandirs.h b/src/check_mandirs.h
index 475229e5..d89ca986 100644
--- a/src/check_mandirs.h
+++ b/src/check_mandirs.h
@@ -22,15 +22,15 @@
#include <stdbool.h>
-#include "db_storage.h"
+#include "mydbm.h"
/* check_mandirs.c */
extern void test_manfile (MYDBM_FILE dbf, const char *file, const char *path);
extern void chown_if_possible (const char *path);
-extern int create_db (const char *database,
+extern int create_db (MYDBM_FILE dbf,
const char *manpath, const char *catpath);
-extern int update_db (const char *database,
+extern int update_db (MYDBM_FILE dbf,
const char *manpath, const char *catpath);
extern void purge_pointers (MYDBM_FILE dbf, const char *name);
-extern int purge_missing (const char *database,
+extern int purge_missing (MYDBM_FILE dbf,
const char *manpath, const char *catpath);
diff --git a/src/man.c b/src/man.c
index 8a4ed1dd..03e0da16 100644
--- a/src/man.c
+++ b/src/man.c
@@ -3213,13 +3213,13 @@ static void dbdelete_wrapper (const char *page, struct mandata *info,
catpath = get_catpath (manpath,
global_manpath ? SYSTEM_CAT : USER_CAT);
database = mkdbname (catpath ? catpath : manpath);
- dbf = MYDBM_RWOPEN (database);
- if (dbf) {
+ dbf = MYDBM_NEW (database);
+ if (MYDBM_RWOPEN (dbf)) {
if (dbdelete (dbf, page, info) == 1)
debug ("%s(%s) not in db!\n", page, info->ext);
- MYDBM_CLOSE (dbf);
}
+ MYDBM_FREE (dbf);
free (database);
free (catpath);
}
@@ -3445,8 +3445,8 @@ static int try_db (const char *manpath, const char *sec, const char *name,
/* If we haven't looked here already, do so now. */
if (!gl_map_search (db_map, manpath, (const void **) &matches)) {
- dbf = MYDBM_RDOPEN (database);
- if (dbf && !dbver_rd (dbf)) {
+ dbf = MYDBM_NEW (database);
+ if (MYDBM_RDOPEN (dbf) && !dbver_rd (dbf)) {
debug ("Succeeded in opening %s O_RDONLY\n", database);
/* if section is set, only return those that match,
@@ -3514,8 +3514,7 @@ static int try_db (const char *manpath, const char *sec, const char *name,
0, name, manpath, NULL, loc);
out:
- if (dbf)
- MYDBM_CLOSE (dbf);
+ MYDBM_FREE (dbf);
free (database);
free (catpath);
return found;
diff --git a/src/mandb.c b/src/mandb.c
index 021d74a9..f29b3c84 100644
--- a/src/mandb.c
+++ b/src/mandb.c
@@ -349,13 +349,10 @@ static void do_chown (struct dbpaths *dbpaths)
#endif /* MAN_OWNER */
/* Update a single file in an existing database. */
-static int update_one_file (const char *database,
+static int update_one_file (MYDBM_FILE dbf,
const char *manpath, const char *filename)
{
- MYDBM_FILE dbf;
-
- dbf = MYDBM_RWOPEN (database);
- if (dbf) {
+ if (dbf->file || MYDBM_RWOPEN (dbf)) {
struct mandata info;
char *manpage;
@@ -370,25 +367,24 @@ static int update_one_file (const char *database,
test_manfile (dbf, filename, manpath);
}
- MYDBM_CLOSE (dbf);
return 1;
}
/* dont actually create any dbs, just do an update */
-static int update_db_wrapper (const char *database,
+static int update_db_wrapper (MYDBM_FILE dbf,
const char *manpath, const char *catpath)
{
int amount;
if (single_filename)
- return update_one_file (database, manpath, single_filename);
+ return update_one_file (dbf, manpath, single_filename);
- amount = update_db (database, manpath, catpath);
+ amount = update_db (dbf, manpath, catpath);
if (amount >= 0)
return amount;
- return create_db (database, manpath, catpath);
+ return create_db (dbf, manpath, catpath);
}
/* remove incomplete databases */
@@ -452,17 +448,13 @@ static int mandb (struct dbpaths *dbpaths,
char *database;
int amount;
char *dbname;
+ MYDBM_FILE dbf;
bool should_create;
+ int purged_here = 0;
dbname = mkdbname (catpath);
database = xasprintf ("%s/%d", catpath, getpid ());
-
- force_rescan = false;
- if (purge)
- purged += purge_missing (dbname, manpath, catpath);
-
- if (!quiet)
- printf (_("Processing manual pages under %s...\n"), manpath);
+ dbf = MYDBM_NEW (database);
if (!STREQ (catpath, manpath)) {
char *cachedir_tag;
@@ -495,7 +487,7 @@ static int mandb (struct dbpaths *dbpaths,
free (cachedir_tag);
}
- should_create = (create || force_rescan || opt_test);
+ should_create = (create || opt_test);
#ifdef NDBM
# ifdef BERKELEY_DB
@@ -533,14 +525,52 @@ static int mandb (struct dbpaths *dbpaths,
check_remove (dbpaths->xtmpfile);
#endif /* NDBM */
+ if (!should_create) {
+ force_rescan = false;
+ if (purge) {
+ purged_here = purge_missing (dbf, manpath, catpath);
+ purged += purged_here;
+ }
+
+ if (force_rescan) {
+ /* We have an existing database and hadn't been
+ * going to recreate it, but purge_missing has
+ * discovered some kind of consistency problem and
+ * requested that we do so anyway. Close the
+ * database and remove temporary copies so that we
+ * start from scratch.
+ */
+ MYDBM_FREE (dbf);
+#ifdef NDBM
+# ifdef BERKELEY_DB
+ check_remove (dbpaths->tmpdbfile);
+# else /* !BERKELEY_DB NDBM */
+ check_remove (dbpaths->tmpdirfile);
+ check_remove (dbpaths->tmppagfile);
+# endif /* BERKELEY_DB NDBM */
+#else /* !NDBM */
+ check_remove (dbpaths->xtmpfile);
+#endif /* NDBM */
+ dbf = MYDBM_NEW (database);
+ should_create = true;
+ }
+ }
+
+ if (!quiet)
+ printf (_("Processing manual pages under %s...\n"), manpath);
+
if (should_create)
- amount = create_db (database, manpath, catpath);
+ amount = create_db (dbf, manpath, catpath);
else
- amount = update_db_wrapper (database, manpath, catpath);
+ amount = update_db_wrapper (dbf, manpath, catpath);
if (check_for_strays && amount > 0)
- strays += straycats (database, manpath);
+ strays += straycats (dbf, manpath);
+
+ if (purged_here)
+ MYDBM_REORG (dbf);
+ MYDBM_FREE (dbf);
free (database);
free (dbname);
return amount;
@@ -555,6 +585,8 @@ static int process_manpath (const char *manpath, bool global_manpath,
bool run_mandb = false;
struct dbpaths *dbpaths = NULL;
int amount = 0;
+ bool new_purged = false;
+ bool new_strays = false;
if (global_manpath) { /* system db */
catpath = get_catpath (manpath, SYSTEM_CAT);
@@ -589,15 +621,19 @@ static int process_manpath (const char *manpath, bool global_manpath,
push_cleanup (cleanup, dbpaths, 0);
push_cleanup (cleanup_sigsafe, dbpaths, 1);
if (run_mandb) {
+ int purged_before = purged;
+ int strays_before = strays;
int ret = mandb (dbpaths, catpath, manpath, global_manpath);
if (ret < 0) {
amount = ret;
goto out;
}
amount += ret;
+ new_purged = purged != purged_before;
+ new_strays = strays != strays_before;
}
- if (!opt_test && amount)
+ if (!opt_test && (amount || new_purged || new_strays))
finish_up (dbpaths);
#ifdef MAN_OWNER
if (global_manpath)
diff --git a/src/straycats.c b/src/straycats.c
index dff2ec69..1315345b 100644
--- a/src/straycats.c
+++ b/src/straycats.c
@@ -28,6 +28,7 @@
# include "config.h"
#endif /* HAVE_CONFIG_H */
+#include <assert.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
@@ -328,22 +329,12 @@ static int open_catdir (MYDBM_FILE dbf)
return strays;
}
-int straycats (const char *database, const char *manpath)
+int straycats (MYDBM_FILE dbf, const char *manpath)
{
- MYDBM_FILE dbf;
char *catpath;
int strays;
- dbf = MYDBM_RWOPEN (database);
- if (dbf && dbver_rd (dbf)) {
- MYDBM_CLOSE (dbf);
- dbf = NULL;
- }
- if (!dbf) {
- error (0, errno, _("warning: can't update index cache %s"),
- database);
- return 0;
- }
+ assert (dbf->file);
catpath = get_catpath (manpath, SYSTEM_CAT | USER_CAT);
@@ -370,6 +361,5 @@ int straycats (const char *database, const char *manpath)
free (catpath);
- MYDBM_CLOSE (dbf);
return strays;
}
diff --git a/src/straycats.h b/src/straycats.h
index 77e11b15..cb82f08e 100644
--- a/src/straycats.h
+++ b/src/straycats.h
@@ -21,4 +21,6 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-extern int straycats (const char *database, const char *manpath);
+#include "mydbm.h"
+
+extern int straycats (MYDBM_FILE dbf, const char *manpath);
diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
index 3fdd74d6..096fbaac 100644
--- a/src/tests/Makefile.am
+++ b/src/tests/Makefile.am
@@ -50,6 +50,7 @@ ALL_TESTS = \
mandb-bogus-symlink \
mandb-cachedir-tag \
mandb-empty-page \
+ mandb-purge-updates-timestamp \
mandb-regular-file-symlink-changes \
mandb-symlink-beats-whatis-ref \
mandb-whatis-broken-link-changes \
@@ -64,10 +65,13 @@ AM_CPPFLAGS = \
-I$(top_builddir)/gl/lib \
-I$(top_srcdir)/gl/lib
AM_CFLAGS = $(WARN_CFLAGS)
-check_PROGRAMS = fspause
+check_PROGRAMS = fspause get-mtime
+
fspause_SOURCES = fspause.c
fspause_LDADD = \
$(top_builddir)/gl/lib/libgnu.la \
$(LIB_NANOSLEEP)
+get_mtime_SOURCES = get-mtime.c
+get_mtime_LDADD = $(top_builddir)/gl/lib/libgnu.la
dist_check_SCRIPTS = testlib.sh $(ALL_TESTS)
diff --git a/src/tests/get-mtime.c b/src/tests/get-mtime.c
new file mode 100644
index 00000000..9ab201e5
--- /dev/null
+++ b/src/tests/get-mtime.c
@@ -0,0 +1,74 @@
+/*
+ * get-mtime.c: get a file's modification time
+ *
+ * Copyright (C) 2022 Colin Watson.
+ *
+ * This file is part of man-db.
+ *
+ * man-db 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 of the License, or
+ * (at your option) any later version.
+ *
+ * man-db 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 man-db; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include "argp.h"
+#include "error.h"
+#include "progname.h"
+#include "stat-time.h"
+
+#include "manconfig.h"
+
+char *path;
+
+static const char args_doc[] = "PATH";
+
+static error_t parse_opt (int key, char *arg, struct argp_state *state)
+{
+ switch (key) {
+ case ARGP_KEY_ARG:
+ if (path)
+ argp_usage (state);
+ path = arg;
+ return 0;
+ case ARGP_KEY_NO_ARGS:
+ argp_usage (state);
+ break;
+ }
+ return ARGP_ERR_UNKNOWN;
+}
+
+static struct argp argp = { NULL, parse_opt, args_doc };
+
+int main (int argc, char **argv)
+{
+ struct stat st;
+ struct timespec ts;
+
+ set_program_name (argv[0]);
+
+ if (argp_parse (&argp, argc, argv, 0, 0, 0))
+ exit (FAIL);
+
+ if (stat (path, &st) < 0)
+ error (FATAL, errno, "can't stat %s", path);
+ ts = get_stat_mtime (&st);
+ printf ("%ld.%09ld\n", (long) ts.tv_sec, ts.tv_nsec);
+
+ exit (OK);
+}
diff --git a/src/tests/mandb-purge-updates-timestamp b/src/tests/mandb-purge-updates-timestamp
new file mode 100755
index 00000000..806673cf
--- /dev/null
+++ b/src/tests/mandb-purge-updates-timestamp
@@ -0,0 +1,67 @@
+#! /bin/sh
+
+# If mandb purges missing pages, it updates the database's timestamp,
+# without confusing itself into not scanning for newer pages.
+
+: ${srcdir=.}
+. "$srcdir/testlib.sh"
+
+: ${MANDB=mandb}
+: ${ACCESSDB=accessdb}
+
+init
+fake_config /usr/share/man
+MANPATH="$tmpdir/usr/share/man"
+export MANPATH
+db_ext="$(db_ext)"
+case $DBTYPE in
+ ndbm) full_db_ext=.pag ;;
+ *) full_db_ext="$db_ext" ;;
+esac
+
+write_page test1 1 "$tmpdir/usr/share/man/man1/test1.1.gz" \
+ UTF-8 gz t 'test1 \- test1(1)'
+write_page test2 1 "$tmpdir/usr/share/man/man1/test2.1.gz" \
+ UTF-8 gz t 'test2 \- test2(1)'
+write_page test3 1 "$tmpdir/usr/share/man/man1/test3.1.gz" \
+ UTF-8 gz t 'test3 \- test3(1)'
+run $MANDB -C "$tmpdir/manpath.config" -u -q "$tmpdir/usr/share/man"
+cat >"$tmpdir/1.exp" <<EOF
+test1 -> "- 1 1 MTIME A - - gz test1(1)"
+test2 -> "- 1 1 MTIME A - - gz test2(1)"
+test3 -> "- 1 1 MTIME A - - gz test3(1)"
+EOF
+accessdb_filter "$tmpdir/usr/share/man/index$db_ext" >"$tmpdir/1.out"
+expect_pass 'setup' 'diff -u "$tmpdir/1.exp" "$tmpdir/1.out"'
+mtime1="$(./get-mtime "$tmpdir/usr/share/man/index$full_db_ext")"
+
+./fspause
+rm -f "$tmpdir/usr/share/man/man1/test3.1.gz"
+# Fool mandb into believing that this directory was not modified. It will
+# still run its purge step.
+touch -r "$tmpdir/usr/share/man/index$db_ext" "$tmpdir/usr/share/man/man1"
+run $MANDB -C "$tmpdir/manpath.config" -u -q "$tmpdir/usr/share/man"
+cat >"$tmpdir/2.exp" <<EOF
+test1 -> "- 1 1 MTIME A - - gz test1(1)"
+test2 -> "- 1 1 MTIME A - - gz test2(1)"
+EOF
+accessdb_filter "$tmpdir/usr/share/man/index$db_ext" >"$tmpdir/2.out"
+expect_pass 'remove test3' 'diff -u "$tmpdir/2.exp" "$tmpdir/2.out"'
+mtime2="$(./get-mtime "$tmpdir/usr/share/man/index$full_db_ext")"
+expect_pass 'mtime changed (1)' 'test "$mtime1" != "$mtime2"'
+
+./fspause
+rm -f "$tmpdir/usr/share/man/man1/test2.1.gz"
+write_page test4 1 "$tmpdir/usr/share/man/man1/test4.1.gz" \
+ UTF-8 gz t 'test4 \- test4(1)'
+run $MANDB -C "$tmpdir/manpath.config" -u -q "$tmpdir/usr/share/man"
+cat >"$tmpdir/3.exp" <<EOF
+test1 -> "- 1 1 MTIME A - - gz test1(1)"
+test4 -> "- 1 1 MTIME A - - gz test4(1)"
+EOF
+accessdb_filter "$tmpdir/usr/share/man/index$db_ext" >"$tmpdir/3.out"
+expect_pass 'remove test2, add test4' 'diff -u "$tmpdir/3.exp" "$tmpdir/3.out"'
+mtime3="$(./get-mtime "$tmpdir/usr/share/man/index$full_db_ext")"
+expect_pass 'mtime changed (2)' 'test "$mtime2" != "$mtime3"'
+
+finish
diff --git a/src/whatis.c b/src/whatis.c
index 0dc1391b..81958aed 100644
--- a/src/whatis.c
+++ b/src/whatis.c
@@ -788,32 +788,23 @@ nextpage:
static bool search (const char * const *pages, int num_pages)
{
bool *found = XCALLOC (num_pages, bool);
- char *catpath, *mp;
+ char *mp;
bool any_found;
int i;
GL_LIST_FOREACH (manpathlist, mp) {
- char *database;
+ char *catpath, *database;
MYDBM_FILE dbf;
catpath = get_catpath (mp, SYSTEM_CAT | USER_CAT);
-
- if (catpath) {
- database = mkdbname (catpath);
- free (catpath);
- } else
- database = mkdbname (mp);
+ database = mkdbname (catpath ? catpath : mp);
debug ("path=%s\n", mp);
- dbf = MYDBM_RDOPEN (database);
- if (dbf && dbver_rd (dbf)) {
- MYDBM_CLOSE (dbf);
- dbf = NULL;
- }
- if (!dbf) {
+ dbf = MYDBM_NEW (database);
+ if (!MYDBM_RDOPEN (dbf) || dbver_rd (dbf)) {
use_grep (pages, num_pages, mp, found);
- continue;
+ goto next;
}
if (am_apropos)
@@ -824,8 +815,11 @@ static bool search (const char * const *pages, int num_pages)
else
do_whatis (dbf, pages, num_pages, mp, found);
}
- MYDBM_CLOSE (dbf);
+
+next:
+ MYDBM_FREE (dbf);
free (database);
+ free (catpath);
}
any_found = false;