/*
* This file is part of DisOrder.
- * Copyright (C) 2004, 2005, 2007, 2008 Richard Kettlewell
+ * Copyright (C) 2004, 2005, 2007-2011 Richard Kettlewell
*
* 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
*/
#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' },
{ "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 }
};
" --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);
|| 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);
}
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));
}
}
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,
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 */
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) {
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;
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;
}
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;
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;
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;
}
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;
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;
}
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;
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;
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;
|| 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);
}
|| 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");
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");
- trackdb_init(recover|TRACKDB_MAY_CREATE);
- trackdb_open(TRACKDB_NO_UPGRADE);
+ if(config_read(0, NULL))
+ disorder_fatal(0, "cannot read configuration");
if(dump) {
/* We write to a temporary file and rename into place. We make
* 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);
+ trackdb_init(recover|TRACKDB_MAY_CREATE);
+ trackdb_open(TRACKDB_NO_UPGRADE);
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");
+ trackdb_init(recover|TRACKDB_MAY_CREATE);
+ trackdb_open(TRACKDB_NO_UPGRADE);
do_undump(fp, path, remove_pathless);
xfclose(fp);
} else if(recompute) {
do_recompute(remove_pathless);
}
trackdb_close();
- trackdb_deinit();
+ trackdb_deinit(NULL);
return 0;
}