X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/ba39faf632da43d64106536f256153c2092346e4..0590cedca75c01811972b2f694f60f24028ee973:/lib/trackdb.c diff --git a/lib/trackdb.c b/lib/trackdb.c index 3694748..8945ec3 100644 --- a/lib/trackdb.c +++ b/lib/trackdb.c @@ -1,6 +1,6 @@ /* * This file is part of DisOrder - * Copyright (C) 2005, 2006, 2007 Richard Kettlewell + * Copyright (C) 2005-2008 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 @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ -/** @file server/trackdb.c +/** @file lib/trackdb.c * @brief Track database * * This file is getting in desparate need of splitting up... @@ -64,7 +64,7 @@ #include "hash.h" #include "unicode.h" #include "unidata.h" -#include "mime.h" +#include "base64.h" #define RESCAN "disorder-rescan" #define DEADLOCK "disorder-deadlock" @@ -113,7 +113,7 @@ DB *trackdb_prefsdb; * - Values are UTF-8(NFC(unicode(path name))) * - There can be more than one value per key * - Presence of key,value means that path matches the search terms - * - Only tracks fond in @ref tracks_tracksdb are represented here + * - Only tracks fond in @ref trackdb_tracksdb are represented here * - This database can be reconstructed, it contains no user data */ DB *trackdb_searchdb; @@ -259,10 +259,23 @@ static int reap_db_deadlock(ev_source attribute((unused)) *ev, return 0; } -static pid_t subprogram(ev_source *ev, const char *prog, - int outputfd) { +static pid_t subprogram(ev_source *ev, int outputfd, const char *prog, + ...) { pid_t pid; - + va_list ap; + const char *args[1024], **argp, *a; + + argp = args; + *argp++ = prog; + *argp++ = "--config"; + *argp++ = configfile; + *argp++ = debugging ? "--debug" : "--no-debug"; + *argp++ = log_default == &log_syslog ? "--syslog" : "--no-syslog"; + va_start(ap, prog); + while((a = va_arg(ap, const char *))) + *argp++ = a; + va_end(ap); + *argp = 0; /* If we're in the background then trap subprocess stdout/stderr */ if(!(pid = xfork())) { exitfn = _exit; @@ -279,10 +292,7 @@ static pid_t subprogram(ev_source *ev, const char *prog, /* If we were negatively niced, undo it. We don't bother checking for * error, it's not that important. */ setpriority(PRIO_PROCESS, 0, 0); - execlp(prog, prog, "--config", configfile, - debugging ? "--debug" : "--no-debug", - log_default == &log_syslog ? "--syslog" : "--no-syslog", - (char *)0); + execvp(prog, (char **)args); fatal(errno, "error invoking %s", prog); } return pid; @@ -291,7 +301,7 @@ static pid_t subprogram(ev_source *ev, const char *prog, /* start deadlock manager */ void trackdb_master(ev_source *ev) { assert(db_deadlock_pid == -1); - db_deadlock_pid = subprogram(ev, DEADLOCK, -1); + db_deadlock_pid = subprogram(ev, -1, DEADLOCK, (char *)0); ev_child(ev, db_deadlock_pid, 0, reap_db_deadlock, 0); D(("started deadlock manager")); } @@ -308,10 +318,18 @@ void trackdb_deinit(void) { if((err = trackdb_env->close(trackdb_env, 0))) fatal(0, "trackdb_env->close: %s", db_strerror(err)); - if(rescan_pid != -1 && kill(rescan_pid, SIGTERM) < 0) - fatal(errno, "error killing rescanner"); + if(rescan_pid != -1) { + /* shut down the rescanner */ + if(kill(rescan_pid, SIGTERM) < 0) + fatal(errno, "error killing rescanner"); + /* wait for the rescanner to finish */ + while(waitpid(rescan_pid, &err, 0) == -1 && errno == EINTR) + ; + } + + /* TODO kill any stats subprocesses */ - /* terminate the deadlock manager */ + /* finally terminate the deadlock manager */ if(db_deadlock_pid != -1 && kill(db_deadlock_pid, SIGTERM) < 0) fatal(errno, "error killing deadlock manager"); db_deadlock_pid = -1; @@ -349,7 +367,7 @@ static DB *open_db(const char *path, } /** @brief Open track databases - * @param Flags flags word + * @param flags Flags flags word * * @p flags should have one of: * - @p TRACKDB_NO_UPGRADE, if no upgrade should be attempted @@ -396,7 +414,7 @@ void trackdb_open(int flags) { /* This database needs upgrading */ info("invoking disorder-dbupgrade to upgrade from %ld to %ld", oldversion, config->dbversion); - pid = subprogram(0, "disorder-dbupgrade", -1); + pid = subprogram(0, -1, "disorder-dbupgrade", (char *)0); while(waitpid(pid, &err, 0) == -1 && errno == EINTR) ; if(err) @@ -423,6 +441,9 @@ void trackdb_open(int flags) { trackdb_existing_database = 0; } /* open the databases */ + if(!(trackdb_usersdb = open_db("users.db", + 0, DB_HASH, dbflags, 0600))) + fatal(0, "cannot open users.db"); trackdb_tracksdb = open_db("tracks.db", DB_RECNUM, DB_BTREE, dbflags, 0666); trackdb_searchdb = open_db("search.db", @@ -433,8 +454,6 @@ void trackdb_open(int flags) { trackdb_globaldb = open_db("global.db", 0, DB_HASH, dbflags, 0666); trackdb_noticeddb = open_db("noticed.db", DB_DUPSORT, DB_BTREE, dbflags, 0666); - trackdb_usersdb = open_db("users.db", - 0, DB_HASH, dbflags, 0600); if(!trackdb_existing_database) { /* Stash the database version */ char buf[32]; @@ -1353,7 +1372,7 @@ void trackdb_stats_subprocess(ev_source *ev, d->done = done; d->u = u; xpipe(p); - pid = subprogram(ev, "disorder-stats", p[1]); + pid = subprogram(ev, p[1], "disorder-stats", (char *)0); xclose(p[1]); ev_child(ev, pid, 0, stats_finished, d); ev_reader_new(ev, p[0], stats_read, stats_error, d, "disorder-stats reader"); @@ -2146,14 +2165,20 @@ static int reap_rescan(ev_source attribute((unused)) *ev, return 0; } -void trackdb_rescan(ev_source *ev) { +/** @brief Initiate a rescan + * @param ev Event loop or 0 to block + * @param recheck 1 to recheck lengths, 0 to suppress check + */ +void trackdb_rescan(ev_source *ev, int recheck) { int w; if(rescan_pid != -1) { error(0, "rescan already underway"); return; } - rescan_pid = subprogram(ev, RESCAN, -1); + rescan_pid = subprogram(ev, -1, RESCAN, + recheck ? "--check" : "--no-check", + (char *)0); if(ev) { ev_child(ev, rescan_pid, 0, reap_rescan, 0); D(("started rescanner")); @@ -2459,6 +2484,10 @@ static int create_user(const char *user, error(0, "invalid username '%s'", user); return -1; } + if(parse_rights(rights, 0, 1)) { + error(0, "invalid rights string"); + return -1; + } /* data for this user */ if(password) kvp_set(&k, "password", password); @@ -2485,10 +2514,16 @@ static int one_old_user(const char *user, const char *password, /* pick rights */ if(!strcmp(user, "root")) rights = "all"; - else if(trusted(user)) - rights = rights_string(config->default_rights|RIGHT_ADMIN|RIGHT_RESCAN); - else - rights = rights_string(config->default_rights); + else if(trusted(user)) { + rights_type r; + + parse_rights(config->default_rights, &r, 1); + r &= ~(rights_type)(RIGHT_SCRATCH__MASK|RIGHT_MOVE__MASK|RIGHT_REMOVE__MASK); + r |= (RIGHT_ADMIN|RIGHT_RESCAN + |RIGHT_SCRATCH_ANY|RIGHT_MOVE_ANY|RIGHT_REMOVE_ANY); + rights = rights_string(r); + } else + rights = config->default_rights; return create_user(user, password, rights, 0/*email*/, 0/*confirmation*/, tid, DB_NOOVERWRITE); } @@ -2564,35 +2599,35 @@ const char *trackdb_get_password(const char *user) { * @param user Username * @param password Password or NULL * @param rights Initial rights - * @param email Email address + * @param email Email address or NULL + * @param confirmation Confirmation string or NULL * @return 0 on success, non-0 on error */ int trackdb_adduser(const char *user, const char *password, - rights_type rights, + const char *rights, const char *email, const char *confirmation) { int e; - const char *r = rights_string(rights); - WITH_TRANSACTION(create_user(user, password, r, email, confirmation, + WITH_TRANSACTION(create_user(user, password, rights, email, confirmation, tid, DB_NOOVERWRITE)); if(e) { - error(0, "cannot created user '%s' because they already exist", user); + error(0, "cannot create user '%s' because they already exist", user); return -1; } else { if(email) info("created user '%s' with rights '%s' and email address '%s'", - user, r, email); + user, rights, email); else - info("created user '%s' with rights '%s'", user, r); + info("created user '%s' with rights '%s'", user, rights); return 0; } } /** @brief Delete a user * @param user User to delete - * @param 0 on success, non-0 if the user didn't exist anyway + * @return 0 on success, non-0 if the user didn't exist anyway */ int trackdb_deluser(const char *user) { int e; @@ -2658,7 +2693,7 @@ int trackdb_edituserinfo(const char *user, error(0, "cannot remove 'rights' key from user '%s'", user); return -1; } - if(parse_rights(value, 0)) { + if(parse_rights(value, 0, 1)) { error(0, "invalid rights string"); return -1; } @@ -2695,11 +2730,20 @@ char **trackdb_listusers(void) { return v->vec; } +/** @brief Confirm a user registration + * @param user Username + * @param confirmation Confirmation string + * @param rightsp Where to put user rights + * @param tid Transaction ID + * @return 0 on success, non-0 on error + */ static int trackdb_confirm_tid(const char *user, const char *confirmation, + rights_type *rightsp, DB_TXN *tid) { const char *stored_confirmation; struct kvp *k; int e; + const char *rights; if((e = trackdb_getdata(trackdb_usersdb, user, &k, tid))) return e; @@ -2708,6 +2752,12 @@ static int trackdb_confirm_tid(const char *user, const char *confirmation, /* DB claims -30,800 to -30,999 so -1 should be a safe bet */ return -1; } + if(!(rights = kvp_get(k, "rights"))) { + error(0, "no rights for unconfirmed user '%s'", user); + return -1; + } + if(parse_rights(rights, rightsp, 1)) + return -1; if(strcmp(confirmation, stored_confirmation)) { error(0, "wrong confirmation string for user '%s'", user); return -1; @@ -2720,12 +2770,14 @@ static int trackdb_confirm_tid(const char *user, const char *confirmation, /** @brief Confirm a user registration * @param user Username * @param confirmation Confirmation string + * @param rightsp Where to put user rights * @return 0 on success, non-0 on error */ -int trackdb_confirm(const char *user, const char *confirmation) { +int trackdb_confirm(const char *user, const char *confirmation, + rights_type *rightsp) { int e; - WITH_TRANSACTION(trackdb_confirm_tid(user, confirmation, tid)); + WITH_TRANSACTION(trackdb_confirm_tid(user, confirmation, rightsp, tid)); switch(e) { case 0: info("registration confirmed for user '%s'", user);