X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/61b761862db3feb9bd0135a64ac3729f70917f89..e5af9e8ddd1ec06cceee9bafeb164da081912c80:/server/dump.c diff --git a/server/dump.c b/server/dump.c index 1cee366..74f1c46 100644 --- a/server/dump.c +++ b/server/dump.c @@ -20,6 +20,10 @@ */ #include "disorder-server.h" +enum { + NO_SETUID = UCHAR_MAX + 1, +}; + static const struct option options[] = { { "help", no_argument, 0, 'h' }, { "version", no_argument, 0, 'V' }, @@ -31,6 +35,7 @@ static const struct option options[] = { { "recover-fatal", no_argument, 0, 'R' }, { "recompute-aliases", no_argument, 0, 'a' }, { "remove-pathless", no_argument, 0, 'P' }, + { "no-setuid", no_argument, 0, NO_SETUID }, { 0, 0, 0, 0 } }; @@ -48,6 +53,7 @@ static void help(void) { " --recover, -r Run database recovery\n" " --recompute-aliases, -a Recompute aliases\n" " --remove-pathless, -P Remove pathless tracks\n" + " --no-setuid Do not become jukebox user\n" " --debug Debug mode\n"); xfclose(stdout); exit(0); @@ -82,7 +88,7 @@ static int dump_one(struct sink *s, || sink_writec(s, '\n') < 0 || urlencode(s, d.data, d.size) || sink_writec(s, '\n') < 0) - fatal(errno, "error writing to %s", tag); + disorder_fatal(errno, "error writing to %s", tag); err = cursor->c_get(cursor, prepare_data(&k), prepare_data(&d), DB_NEXT); } @@ -95,7 +101,7 @@ static int dump_one(struct sink *s, case 0: assert(!"cannot happen"); default: - fatal(0, "error reading %s: %s", dbname, db_strerror(err)); + disorder_fatal(0, "error reading %s: %s", dbname, db_strerror(err)); } } @@ -121,13 +127,13 @@ static void do_dump(FILE *fp, const char *tag) { for(;;) { tid = trackdb_begin_transaction(); if(fseek(fp, 0, SEEK_SET) < 0) - fatal(errno, "error calling fseek"); + disorder_fatal(errno, "error calling fseek"); if(fflush(fp) < 0) - fatal(errno, "error calling fflush"); + disorder_fatal(errno, "error calling fflush"); if(ftruncate(fileno(fp), 0) < 0) - fatal(errno, "error calling ftruncate"); + disorder_fatal(errno, "error calling ftruncate"); if(fprintf(fp, "V0") < 0) - fatal(errno, "error writing to %s", tag); + disorder_fatal(errno, "error writing to %s", tag); for(size_t n = 0; n < NDBTABLE; ++n) if(dump_one(s, tag, dbtable[n].letter, dbtable[n].dbname, *dbtable[n].db, @@ -135,16 +141,16 @@ static void do_dump(FILE *fp, const char *tag) { goto fail; if(fputs("E\n", fp) < 0) - fatal(errno, "error writing to %s", tag); + disorder_fatal(errno, "error writing to %s", tag); break; fail: - info("aborting transaction and retrying dump"); + disorder_info("aborting transaction and retrying dump"); trackdb_abort_transaction(tid); } trackdb_commit_transaction(tid); - if(fflush(fp) < 0) fatal(errno, "error writing to %s", tag); + if(fflush(fp) < 0) disorder_fatal(errno, "error writing to %s", tag); /* caller might not be paranoid so we are paranoid on their behalf */ - if(fsync(fileno(fp)) < 0) fatal(errno, "error syncing %s", tag); + if(fsync(fileno(fp)) < 0) disorder_fatal(errno, "error syncing %s", tag); } /* delete all aliases prefs, return 0 or DB_LOCK_DEADLOCK */ @@ -155,11 +161,11 @@ static int remove_aliases(DB_TXN *tid, int remove_pathless) { struct kvp *data; int alias, pathless; - info("removing aliases"); + disorder_info("removing aliases"); cursor = trackdb_opencursor(trackdb_tracksdb, tid); if((err = cursor->c_get(cursor, prepare_data(&k), prepare_data(&d), DB_FIRST)) == DB_LOCK_DEADLOCK) { - error(0, "cursor->c_get: %s", db_strerror(err)); + disorder_error(0, "cursor->c_get: %s", db_strerror(err)); goto done; } while(err == 0) { @@ -167,24 +173,25 @@ static int remove_aliases(DB_TXN *tid, int remove_pathless) { alias = !!kvp_get(data, "_alias_for"); pathless = !kvp_get(data, "_path"); if(pathless && !remove_pathless) - info("no _path for %s", utf82mb(xstrndup(k.data, k.size))); + disorder_info("no _path for %s", utf82mb(xstrndup(k.data, k.size))); if(alias || (remove_pathless && pathless)) { switch(err = cursor->c_del(cursor, 0)) { case 0: break; case DB_LOCK_DEADLOCK: - error(0, "cursor->c_get: %s", db_strerror(err)); + disorder_error(0, "cursor->c_get: %s", db_strerror(err)); goto done; default: - fatal(0, "cursor->c_del: %s", db_strerror(err)); + disorder_fatal(0, "cursor->c_del: %s", db_strerror(err)); } } err = cursor->c_get(cursor, prepare_data(&k), prepare_data(&d), DB_NEXT); } if(err == DB_LOCK_DEADLOCK) { - error(0, "cursor operation: %s", db_strerror(err)); + disorder_error(0, "cursor operation: %s", db_strerror(err)); goto done; } - if(err != DB_NOTFOUND) fatal(0, "cursor->c_get: %s", db_strerror(err)); + if(err != DB_NOTFOUND) + disorder_fatal(0, "cursor->c_get: %s", db_strerror(err)); err = 0; done: if(trackdb_closecursor(cursor) && !err) err = DB_LOCK_DEADLOCK; @@ -199,10 +206,10 @@ static int truncdb(DB_TXN *tid, DB *db) { switch(err = db->truncate(db, tid, &count, 0)) { case 0: break; case DB_LOCK_DEADLOCK: - error(0, "db->truncate: %s", db_strerror(err)); + disorder_error(0, "db->truncate: %s", db_strerror(err)); break; default: - fatal(0, "db->truncate: %s", db_strerror(err)); + disorder_fatal(0, "db->truncate: %s", db_strerror(err)); } return err; } @@ -215,7 +222,7 @@ static int undump_dbt(FILE *fp, const char *tag, DBT *dbt) { if(inputline(tag, fp, &s, '\n')) return -1; dynstr_init(&d); if(urldecode(sink_dynstr(&d), s, strlen(s))) - fatal(0, "invalid URL-encoded data in %s", tag); + disorder_fatal(0, "invalid URL-encoded data in %s", tag); dbt->data = d.vec; dbt->size = d.nvec; return 0; @@ -225,9 +232,9 @@ static int undump_dbt(FILE *fp, const char *tag, DBT *dbt) { static int undump_from_fp(DB_TXN *tid, FILE *fp, const char *tag) { int err, c; - info("undumping"); + disorder_info("undumping"); if(fseek(fp, 0, SEEK_SET) < 0) - fatal(errno, "error calling fseek on %s", tag); + disorder_fatal(errno, "error calling fseek on %s", tag); if((err = truncdb(tid, trackdb_prefsdb))) return err; if((err = truncdb(tid, trackdb_globaldb))) return err; if((err = truncdb(tid, trackdb_searchdb))) return err; @@ -249,10 +256,10 @@ static int undump_from_fp(DB_TXN *tid, FILE *fp, const char *tag) { case 0: break; case DB_LOCK_DEADLOCK: - error(0, "error updating %s: %s", dbname, db_strerror(err)); + disorder_error(0, "error updating %s: %s", dbname, db_strerror(err)); return err; default: - fatal(0, "error updating %s: %s", dbname, db_strerror(err)); + disorder_fatal(0, "error updating %s: %s", dbname, db_strerror(err)); } goto next; } @@ -262,7 +269,7 @@ static int undump_from_fp(DB_TXN *tid, FILE *fp, const char *tag) { case 'V': c = getc(fp); if(c != '0') - fatal(0, "unknown version '%c'", c); + disorder_fatal(0, "unknown version '%c'", c); break; case 'E': return 0; @@ -270,17 +277,17 @@ static int undump_from_fp(DB_TXN *tid, FILE *fp, const char *tag) { break; default: if(c >= 32 && c <= 126) - fatal(0, "unexpected character '%c'", c); + disorder_fatal(0, "unexpected character '%c'", c); else - fatal(0, "unexpected character 0x%02X", c); + disorder_fatal(0, "unexpected character 0x%02X", c); } next: c = getc(fp); } if(ferror(fp)) - fatal(errno, "error reading %s", tag); + disorder_fatal(errno, "error reading %s", tag); else - fatal(0, "unexpected EOF reading %s", tag); + disorder_fatal(0, "unexpected EOF reading %s", tag); return 0; } @@ -293,7 +300,7 @@ static int recompute_aliases(DB_TXN *tid) { struct kvp *data; const char *path, *track; - info("recomputing aliases"); + disorder_info("recomputing aliases"); cursor = trackdb_opencursor(trackdb_tracksdb, tid); if((err = cursor->c_get(cursor, prepare_data(&k), prepare_data(&d), DB_FIRST)) == DB_LOCK_DEADLOCK) goto done; @@ -302,7 +309,7 @@ static int recompute_aliases(DB_TXN *tid) { track = xstrndup(k.data, k.size); if(!kvp_get(data, "_alias_for")) { if(!(path = kvp_get(data, "_path"))) - error(0, "%s is not an alias but has no path", utf82mb(track)); + disorder_error(0, "%s is not an alias but has no path", utf82mb(track)); else if((err = trackdb_notice_tid(track, path, tid)) == DB_LOCK_DEADLOCK) goto done; @@ -319,7 +326,7 @@ static int recompute_aliases(DB_TXN *tid) { case DB_LOCK_DEADLOCK: break; default: - fatal(0, "cursor->c_get: %s", db_strerror(err)); + disorder_fatal(0, "cursor->c_get: %s", db_strerror(err)); } done: if(trackdb_closecursor(cursor) && !err) err = DB_LOCK_DEADLOCK; @@ -337,10 +344,10 @@ static void do_undump(FILE *fp, const char *tag, int remove_pathless) { || recompute_aliases(tid)) goto fail; break; fail: - info("aborting transaction and retrying undump"); + disorder_info("aborting transaction and retrying undump"); trackdb_abort_transaction(tid); } - info("committing undump"); + disorder_info("committing undump"); trackdb_commit_transaction(tid); } @@ -354,22 +361,23 @@ static void do_recompute(int remove_pathless) { || recompute_aliases(tid)) goto fail; break; fail: - info("aborting transaction and retrying recomputation"); + disorder_info("aborting transaction and retrying recomputation"); trackdb_abort_transaction(tid); } - info("committing recomputed aliases"); + disorder_info("committing recomputed aliases"); trackdb_commit_transaction(tid); } int main(int argc, char **argv) { int n, dump = 0, undump = 0, recover = TRACKDB_NO_RECOVER, recompute = 0; int remove_pathless = 0, fd; + int changeuid = !getuid(); const char *path; char *tmp; FILE *fp; mem_init(); - while((n = getopt_long(argc, argv, "hVc:dDurRaP", options, 0)) >= 0) { + while((n = getopt_long(argc, argv, "hVc:dDurRaPR", options, 0)) >= 0) { switch(n) { case 'h': help(); case 'V': version("disorder-dump"); @@ -377,27 +385,29 @@ int main(int argc, char **argv) { case 'd': dump = 1; break; case 'u': undump = 1; break; case 'D': debugging = 1; break; - case 'r': recover = TRACKDB_NORMAL_RECOVER; - case 'R': recover = TRACKDB_FATAL_RECOVER; + case 'r': recover = TRACKDB_NORMAL_RECOVER; break; + case 'R': recover = TRACKDB_FATAL_RECOVER; break; case 'a': recompute = 1; break; case 'P': remove_pathless = 1; break; - default: fatal(0, "invalid option"); + case NO_SETUID: changeuid = 0; break; + default: disorder_fatal(0, "invalid option"); } } if(dump + undump + recompute != 1) - fatal(0, "choose exactly one of --dump, --undump or --recompute-aliases"); + disorder_fatal(0, "choose exactly one of --dump, --undump or --recompute-aliases"); if(recompute) { if(optind != argc) - fatal(0, "--recompute-aliases does not take a filename"); + disorder_fatal(0, "--recompute-aliases does not take a filename"); path = 0; } else { if(optind >= argc) - fatal(0, "missing dump file name"); + disorder_fatal(0, "missing dump file name"); if(optind + 1 < argc) - fatal(0, "specify only a dump file name"); + disorder_fatal(0, "specify only a dump file name"); path = argv[optind]; } - if(config_read(0, NULL)) fatal(0, "cannot read configuration"); + if(config_read(0, NULL)) + disorder_fatal(0, "cannot read configuration"); trackdb_init(recover|TRACKDB_MAY_CREATE); trackdb_open(TRACKDB_NO_UPGRADE); if(dump) { @@ -405,25 +415,30 @@ int main(int argc, char **argv) { * sure the permissions are tight from the start. */ byte_xasprintf(&tmp, "%s.%lx.tmp", path, (unsigned long)getpid()); if((fd = open(tmp, O_CREAT|O_TRUNC|O_WRONLY, 0600)) < 0) - fatal(errno, "error opening %s", tmp); + disorder_fatal(errno, "error opening %s", tmp); if(!(fp = fdopen(fd, "w"))) - fatal(errno, "fdopen on %s", tmp); + disorder_fatal(errno, "fdopen on %s", tmp); do_dump(fp, tmp); - if(fclose(fp) < 0) fatal(errno, "error closing %s", tmp); + if(fclose(fp) < 0) disorder_fatal(errno, "error closing %s", tmp); if(rename(tmp, path) < 0) - fatal(errno, "error renaming %s to %s", tmp, path); + disorder_fatal(errno, "error renaming %s to %s", tmp, path); } else if(undump) { + /* Open the dump file before changing UID */ + if(!(fp = fopen(path, "r"))) + disorder_fatal(errno, "error opening %s", path); + if(changeuid) + become_mortal(); /* the databases or logfiles might end up with wrong permissions * if new ones are created */ - if(getuid() == 0) info("you might need to chown database files"); - if(!(fp = fopen(path, "r"))) fatal(errno, "error opening %s", path); + if(getuid() == 0) + disorder_info("you might need to chown database files"); do_undump(fp, path, remove_pathless); xfclose(fp); } else if(recompute) { do_recompute(remove_pathless); } trackdb_close(); - trackdb_deinit(); + trackdb_deinit(NULL); return 0; }