+++ /dev/null
-/* $Id: makedbz.c 6135 2003-01-19 01:15:40Z rra $
-**
-** Rebuild dbz file for history db.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-#include <pwd.h>
-#include <syslog.h>
-
-#include "dbz.h"
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "inn/qio.h"
-#include "libinn.h"
-#include "paths.h"
-#include "storage.h"
-
-/* FIXME: once we figure out how to integrate this stuff with the
- * history API this external visibility of internal voodoo should
- * go */
-#define HIS_FIELDSEP '\t'
-
-char *TextFile = NULL;
-char *HistoryDir = NULL;
-char *HISTORY = NULL;
-
-/*
-** Remove the DBZ files for the specified base text file.
-*/
-static void
-RemoveDBZFiles(char *p)
-{
- char buff[SMBUF];
-
- snprintf(buff, sizeof(buff), "%s.dir", p);
- if (unlink(buff) && errno != ENOENT)
- syswarn("cannot unlink %s", buff);
-#ifdef DO_TAGGED_HASH
- snprintf(buff, sizeof(buff), "%s.pag", p);
- if (unlink(buff) && errno != ENOENT)
- syswarn("cannot unlink %s", buff);
-#else
- snprintf(buff, sizeof(buff), "%s.index", p);
- if (unlink(buff) && errno != ENOENT)
- syswarn("cannot unlink %s", buff);
- snprintf(buff, sizeof(buff), "%s.hash", p);
- if (unlink(buff) && errno != ENOENT)
- syswarn("cannot unlink %s", buff);
-#endif
-}
-
-
-/*
-** Count lines in the history text. A long-winded way of saying "wc -l"
-*/
-static off_t
-Countlines(void)
-{
- QIOSTATE *qp;
- off_t count;
-
- /* Open the text file. */
- qp = QIOopen(TextFile);
- if (qp == NULL)
- sysdie("cannot open %s", TextFile);
-
- /* Loop through all lines in the text file. */
- count = 0;
- for (; QIOread(qp) != NULL;)
- count++;
- if (QIOerror(qp))
- sysdie("cannot read %s near line %lu", TextFile,
- (unsigned long) count);
- if (QIOtoolong(qp))
- sysdie("line %lu of %s is too long", (unsigned long) count,
- TextFile);
-
- QIOclose(qp);
- return count;
-}
-
-
-/*
-** Rebuild the DBZ file from the text file.
-*/
-static void
-Rebuild(off_t size, bool IgnoreOld, bool Overwrite)
-{
- QIOSTATE *qp;
- char *p;
- char *save;
- off_t count;
- off_t where;
- HASH key;
- char temp[SMBUF];
- dbzoptions opt;
-
- if (chdir(HistoryDir) < 0)
- sysdie("cannot chdir to %s", HistoryDir);
-
- /* If we are ignoring the old database and the user didn't specify a table
- size, determine one ourselves from the size of the text history file.
- Note that this will still use the defaults in dbz if the text file is
- empty, since size will still be left set to 0. */
- if (IgnoreOld == true && size == 0) {
- size = Countlines();
- size += (size / 10);
- if (size > 0)
- warn("no size specified, using %ld", (unsigned long) size);
- }
-
- /* Open the text file. */
- qp = QIOopen(TextFile);
- if (qp == NULL)
- sysdie("cannot open %s", TextFile);
-
- /* If using the standard history file, force DBZ to use history.n. */
- if (strcmp(TextFile, HISTORY) == 0 && !Overwrite) {
- snprintf(temp, sizeof(temp), "%s.n", HISTORY);
- if (link(HISTORY, temp) < 0)
- sysdie("cannot create temporary link to %s", temp);
- RemoveDBZFiles(temp);
- p = temp;
- }
- else {
- temp[0] = '\0';
- /*
- ** only do removedbz files if a. we're using something besides
- ** $pathdb/history, or b. we're ignoring the old db.
- */
- if (strcmp(TextFile, HISTORY) != 0 || IgnoreOld)
- RemoveDBZFiles(TextFile);
- p = TextFile;
- }
-
- /* Open the new database, using the old file if desired and possible. */
- dbzgetoptions(&opt);
- opt.pag_incore = INCORE_MEM;
-#ifndef DO_TAGGED_HASH
- opt.exists_incore = INCORE_MEM;
-#endif
- dbzsetoptions(opt);
- if (IgnoreOld) {
- if (!dbzfresh(p, dbzsize(size))) {
- syswarn("cannot do dbzfresh");
- if (temp[0])
- unlink(temp);
- exit(1);
- }
- }
- else {
- if (!dbzagain(p, HISTORY)) {
- syswarn("cannot do dbzagain");
- if (temp[0])
- unlink(temp);
- exit(1);
- }
- }
-
- /* Loop through all lines in the text file. */
- count = 0;
- for (where = QIOtell(qp); (p = QIOread(qp)) != NULL; where = QIOtell(qp)) {
- count++;
- if ((save = strchr(p, HIS_FIELDSEP)) == NULL) {
- warn("bad line #%lu: %.40s", (unsigned long) count, p);
- if (temp[0])
- unlink(temp);
- exit(1);
- }
- *save = '\0';
- switch (*p) {
- case '[':
- if (strlen(p) != ((sizeof(HASH) * 2) + 2)) {
- warn("invalid length for hash %s, skipping", p);
- continue;
- }
- key = TextToHash(p+1);
- break;
- default:
- warn("invalid message ID %s in history text", p);
- continue;
- }
- switch (dbzstore(key, where)) {
- case DBZSTORE_EXISTS:
- warn("duplicate message ID %s in history text", p);
- break;
- case DBZSTORE_ERROR:
- syswarn("cannot store %s", p);
- if (temp[0])
- unlink(temp);
- exit(1);
- default:
- break;
- }
- }
- if (QIOerror(qp)) {
- syswarn("cannot read %s near line %lu", TextFile,
- (unsigned long) count);
- if (temp[0])
- unlink(temp);
- exit(1);
- }
- if (QIOtoolong(qp)) {
- warn("line %lu is too long", (unsigned long) count);
- if (temp[0])
- unlink(temp);
- exit(1);
- }
-
- /* Close files. */
- QIOclose(qp);
- if (!dbzclose()) {
- syswarn("cannot close history");
- if (temp[0])
- unlink(temp);
- exit(1);
- }
-
- if (temp[0])
- unlink(temp);
-}
-
-static void
-Usage(void)
-{
- fprintf(stderr, "Usage: makedbz [-f histfile] [-s numlines] [-i] [-o]\n");
- exit(1);
-}
-
-
-/*
-** Change to the news user if possible, and if not, die. Used for operations
-** that may create new database files, so as not to mess up the ownership.
-*/
-static void
-setuid_news(void)
-{
- struct passwd *pwd;
-
- pwd = getpwnam(NEWSUSER);
- if (pwd == NULL)
- die("can't resolve %s to a UID (account doesn't exist?)", NEWSUSER);
- if (getuid() == 0)
- setuid(pwd->pw_uid);
- if (getuid() != pwd->pw_uid)
- die("must be run as %s", NEWSUSER);
-}
-
-
-int
-main(int argc, char **argv)
-{
- bool Overwrite;
- bool IgnoreOld;
- off_t size = 0;
- int i;
- char *p;
-
- /* First thing, set up logging and our identity. */
- openlog("makedbz", L_OPENLOG_FLAGS | LOG_PID, LOG_INN_PROG);
- message_program_name = "makedbz";
-
- /* Set defaults. */
- if (!innconf_read(NULL))
- exit(1);
- TextFile = concatpath(innconf->pathdb, _PATH_HISTORY);
- HISTORY = concatpath(innconf->pathdb, _PATH_HISTORY);
- HistoryDir = innconf->pathdb;
- IgnoreOld = false;
- Overwrite = false;
-
- while ((i = getopt(argc, argv, "s:iof:")) != EOF) {
- switch (i) {
- default:
- Usage();
- case 'f':
- TextFile = optarg;
- break;
- case 's':
- size = atol(optarg);
- IgnoreOld = true;
- break;
- case 'o':
- Overwrite = true;
- break;
- case 'i':
- IgnoreOld = true;
- break;
- }
- }
-
- argc -= optind;
- argv += optind;
- if (argc) {
- Usage();
- }
-
- if ((p = strrchr(TextFile, '/')) == NULL) {
- /* find the default history file directory */
- HistoryDir = innconf->pathdb;
- } else {
- *p = '\0';
- HistoryDir = xstrdup(TextFile);
- *p = '/';
- }
-
- if (chdir(HistoryDir) < 0)
- sysdie("cannot chdir to %s", HistoryDir);
-
- /* Change users if necessary. */
- setuid_news();
-
- Rebuild(size, IgnoreOld, Overwrite);
- closelog();
- exit(0);
-}