diff options
author | Ingo Schwarze <schwarze@openbsd.org> | 2014-03-18 16:56:10 +0000 |
---|---|---|
committer | Ingo Schwarze <schwarze@openbsd.org> | 2014-03-18 16:56:10 +0000 |
commit | 3868c0e69fda640025525113006a7ab108fa0fef (patch) | |
tree | d5cd925e9722ca109f5a14d092c241da216c5a76 /mandocdb.c | |
parent | 4c1341e91af6443c15b87a1ec441a3f2a44cf2c8 (diff) | |
download | mandoc-3868c0e69fda640025525113006a7ab108fa0fef.tar.gz |
Allow checking that databases are up to date even when you have no write
permission on the databases, as requested by espie@ quite some time ago.
But make sure to not slow database generation down when you do have write
permission, and to not delay error reporting in -Q mode.
Diffstat (limited to 'mandocdb.c')
-rw-r--r-- | mandocdb.c | 114 |
1 files changed, 94 insertions, 20 deletions
@@ -20,6 +20,7 @@ #endif #include <sys/stat.h> +#include <sys/wait.h> #include <assert.h> #include <ctype.h> @@ -168,6 +169,7 @@ static int set_basedir(const char *); static int treescan(void); static size_t utf8(unsigned int, char [7]); +static char tempfilename[32]; static char *progname; static int nodb; /* no database changes */ static int quick; /* abort the parse early */ @@ -1874,6 +1876,8 @@ static void dbclose(int real) { size_t i; + int status; + pid_t child; if (nodb) return; @@ -1889,9 +1893,59 @@ dbclose(int real) if (real) return; - if (-1 == rename(MANDOC_DB "~", MANDOC_DB)) { + if ('\0' == *tempfilename) { + if (-1 == rename(MANDOC_DB "~", MANDOC_DB)) { + exitcode = (int)MANDOCLEVEL_SYSERR; + say(MANDOC_DB, "%s", strerror(errno)); + } + return; + } + + switch (child = fork()) { + case (-1): + exitcode = (int)MANDOCLEVEL_SYSERR; + say("fork cmp", "%s", strerror(errno)); + return; + case (0): + execlp("cmp", "cmp", "-s", + tempfilename, MANDOC_DB, NULL); + say("exec cmp", "%s", strerror(errno)); + exit(0); + default: + break; + } + if (-1 == waitpid(child, &status, 0)) { + exitcode = (int)MANDOCLEVEL_SYSERR; + say("wait cmp", "%s", strerror(errno)); + } else if (WIFSIGNALED(status)) { + exitcode = (int)MANDOCLEVEL_SYSERR; + say("cmp", "Died from a signal"); + } else if (WEXITSTATUS(status)) { exitcode = (int)MANDOCLEVEL_SYSERR; - say(MANDOC_DB, NULL); + say(MANDOC_DB, + "Data changed, but cannot replace database"); + } + + *strrchr(tempfilename, '/') = '\0'; + switch (child = fork()) { + case (-1): + exitcode = (int)MANDOCLEVEL_SYSERR; + say("fork rm", "%s", strerror(errno)); + return; + case (0): + execlp("rm", "rm", "-rf", tempfilename, NULL); + say("exec rm", "%s", strerror(errno)); + exit((int)MANDOCLEVEL_SYSERR); + default: + break; + } + if (-1 == waitpid(child, &status, 0)) { + exitcode = (int)MANDOCLEVEL_SYSERR; + say("wait rm", "%s", strerror(errno)); + } else if (WIFSIGNALED(status) || WEXITSTATUS(status)) { + exitcode = (int)MANDOCLEVEL_SYSERR; + say(tempfilename, + "Cannot remove temporary directory"); } } @@ -1906,42 +1960,62 @@ dbclose(int real) static int dbopen(int real) { - const char *file, *sql; + const char *sql; int rc, ofl; if (nodb) return(1); + *tempfilename = '\0'; ofl = SQLITE_OPEN_READWRITE; - if (0 == real) { - file = MANDOC_DB "~"; - if (-1 == remove(file) && ENOENT != errno) { + + if (real) { + rc = sqlite3_open_v2(MANDOC_DB, &db, ofl, NULL); + if (SQLITE_OK != rc) { exitcode = (int)MANDOCLEVEL_SYSERR; - say(file, NULL); + say(MANDOC_DB, "%s", sqlite3_errmsg(db)); return(0); } - ofl |= SQLITE_OPEN_EXCLUSIVE; - } else - file = MANDOC_DB; + goto prepare_statements; + } - rc = sqlite3_open_v2(file, &db, ofl, NULL); + ofl |= SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE; + + remove(MANDOC_DB "~"); + rc = sqlite3_open_v2(MANDOC_DB "~", &db, ofl, NULL); if (SQLITE_OK == rc) - goto prepare_statements; - if (SQLITE_CANTOPEN != rc) { + goto create_tables; + if (quick) { exitcode = (int)MANDOCLEVEL_SYSERR; - say(file, NULL); + say(MANDOC_DB "~", "%s", sqlite3_errmsg(db)); return(0); } - sqlite3_close(db); - db = NULL; - - if (SQLITE_OK != (rc = sqlite3_open(file, &db))) { + if (strlcpy(tempfilename, "/tmp/mandocdb.XXXXXX", + sizeof(tempfilename)) >= sizeof(tempfilename)) { exitcode = (int)MANDOCLEVEL_SYSERR; - say(file, NULL); + say("/tmp/mandocdb.XXXXXX", "Filename too long"); + return(0); + } + if (NULL == mkdtemp(tempfilename)) { + exitcode = (int)MANDOCLEVEL_SYSERR; + say(tempfilename, "%s", strerror(errno)); + return(0); + } + if (strlcat(tempfilename, "/" MANDOC_DB, + sizeof(tempfilename)) >= sizeof(tempfilename)) { + exitcode = (int)MANDOCLEVEL_SYSERR; + say(tempfilename, "Filename too long"); + return(0); + } + rc = sqlite3_open_v2(tempfilename, &db, ofl, NULL); + if (SQLITE_OK != rc) { + exitcode = (int)MANDOCLEVEL_SYSERR; + say(tempfilename, "%s", sqlite3_errmsg(db)); return(0); } +create_tables: sql = "CREATE TABLE \"mpages\" (\n" " \"form\" INTEGER NOT NULL,\n" " \"id\" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL\n" @@ -1964,7 +2038,7 @@ dbopen(int real) if (SQLITE_OK != sqlite3_exec(db, sql, NULL, NULL, NULL)) { exitcode = (int)MANDOCLEVEL_SYSERR; - say(file, "%s", sqlite3_errmsg(db)); + say(MANDOC_DB, "%s", sqlite3_errmsg(db)); return(0); } |