chiark / gitweb /
Tidy up trackdb_deinit() further, and include disorder-choose in
[disorder] / lib / trackdb.c
1 /*
2  * This file is part of DisOrder
3  * Copyright (C) 2005-2008 Richard Kettlewell
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 /** @file lib/trackdb.c
19  * @brief Track database
20  *
21  * This file is getting in desparate need of splitting up...
22  */
23
24 #include "common.h"
25
26 #include <db.h>
27 #include <sys/socket.h>
28 #include <pcre.h>
29 #include <unistd.h>
30 #include <errno.h>
31 #include <stddef.h>
32 #include <sys/time.h>
33 #include <sys/resource.h>
34 #include <time.h>
35 #include <arpa/inet.h>
36 #include <dirent.h>
37 #include <sys/stat.h>
38 #include <gcrypt.h>
39
40 #include "event.h"
41 #include "mem.h"
42 #include "kvp.h"
43 #include "log.h"
44 #include "vector.h"
45 #include "rights.h"
46 #include "trackdb.h"
47 #include "configuration.h"
48 #include "syscalls.h"
49 #include "wstat.h"
50 #include "printf.h"
51 #include "filepart.h"
52 #include "trackname.h"
53 #include "trackdb-int.h"
54 #include "logfd.h"
55 #include "cache.h"
56 #include "eventlog.h"
57 #include "hash.h"
58 #include "unicode.h"
59 #include "unidata.h"
60 #include "base64.h"
61 #include "sendmail.h"
62
63 #define RESCAN "disorder-rescan"
64 #define DEADLOCK "disorder-deadlock"
65
66 static const char *getpart(const char *track,
67                            const char *context,
68                            const char *part,
69                            const struct kvp *p,
70                            int *used_db);
71 static char **trackdb_new_tid(int *ntracksp,
72                               int maxtracks,
73                               DB_TXN *tid);
74 static int trackdb_expire_noticed_tid(time_t earliest, DB_TXN *tid);
75 static char *normalize_tag(const char *s, size_t ns);
76
77 const struct cache_type cache_files_type = { 86400 };
78 unsigned long cache_files_hits, cache_files_misses;
79
80 /** @brief Set by trackdb_open() */
81 int trackdb_existing_database;
82
83 /* setup and teardown ********************************************************/
84
85 static const char *home;                /* home had better not change */
86 DB_ENV *trackdb_env;                    /* db environment */
87
88 /** @brief The tracks database
89  * - Keys are UTF-8(NFC(unicode(path name)))
90  * - Values are encoded key-value pairs
91  * - Data is reconstructable data about tracks that currently exist
92  */
93 DB *trackdb_tracksdb;
94
95 /** @brief The preferences database
96  *
97  * - Keys are UTF-8(NFC(unicode(path name)))
98  * - Values are encoded key-value pairs
99  * - Data is user data about tracks (that might not exist any more)
100  * and cannot be reconstructed
101  */
102 DB *trackdb_prefsdb;
103
104 /** @brief The search database
105  *
106  * - Keys are UTF-8(NFKC(casefold(search term)))
107  * - Values are UTF-8(NFC(unicode(path name)))
108  * - There can be more than one value per key
109  * - Presence of key,value means that path matches the search terms
110  * - Only tracks fond in @ref trackdb_tracksdb are represented here
111  * - This database can be reconstructed, it contains no user data
112  */
113 DB *trackdb_searchdb;
114
115 /** @brief The tags database
116  *
117  * - Keys are UTF-8(NFKC(casefold(tag)))
118  * - Values are UTF-8(NFC(unicode(path name)))
119  * - There can be more than one value per key
120  * - Presence of key,value means that path matches the tag
121  * - This is always in sync with the tags preference
122  * - This database can be reconstructed, it contains no user data
123  */
124 DB *trackdb_tagsdb;                     /* the tags database */
125
126 /** @brief The global preferences database
127  * - Keys are UTF-8(NFC(preference))
128  * - Values are global preference values
129  * - Data is user data and cannot be reconstructed
130  */
131 DB *trackdb_globaldb;                   /* global preferences */
132
133 /** @brief The noticed database
134  * - Keys are 64-bit big-endian timestamps
135  * - Values are UTF-8(NFC(unicode(path name)))
136  * - There can be more than one value per key
137  * - Presence of key,value means that path was added at the given time
138  * - Data cannot be reconstructed (but isn't THAT important)
139  */
140 DB *trackdb_noticeddb;                   /* when track noticed */
141
142 /** @brief The schedule database
143  *
144  * - Keys are ID strings, generated at random
145  * - Values are encoded key-value pairs
146  * - There can be more than one value per key
147  * - Data cannot be reconstructed
148  *
149  * See @ref server/schedule.c for further information.
150  */
151 DB *trackdb_scheduledb;
152
153 /** @brief The user database
154  * - Keys are usernames
155  * - Values are encoded key-value pairs
156  * - Data is user data and cannot be reconstructed
157  */
158 DB *trackdb_usersdb;
159
160 /** @brief The playlists database
161  * - Keys are playlist names
162  * - Values are encoded key-value pairs
163  * - Data is user data and cannot be reconstructed
164  */
165 DB *trackdb_playlistsdb;
166
167 static pid_t db_deadlock_pid = -1;      /* deadlock manager PID */
168 static pid_t rescan_pid = -1;           /* rescanner PID */
169 static int initialized, opened;         /* state */
170
171 /** @brief Current stats subprocess PIDs */
172 static hash *stats_pids;
173
174 static pid_t choose_pid = -1;
175 static int choose_fd;
176 static random_callback *choose_callback;
177 static struct dynstr choose_output;
178 static unsigned choose_complete;
179 static int choose_status;
180 #define CHOOSE_RUNNING 1
181 #define CHOOSE_READING 2
182
183 /* comparison function for keys */
184 static int compare(DB attribute((unused)) *db_,
185                    const DBT *a, const DBT *b) {
186   return compare_path_raw(a->data, a->size, b->data, b->size);
187 }
188
189 /** @brief Test whether the track database can be read
190  * @return 1 if it can, 0 if it cannot
191  */
192 int trackdb_readable(void) {
193   char *usersdb;
194
195   byte_xasprintf(&usersdb, "%s/users.db", config->home);
196   return access(usersdb, R_OK) == 0;
197 }
198
199 /** @brief Open database environment
200  * @param flags Flags word
201  *
202  * Flags should be one of:
203  * - @ref TRACKDB_NO_RECOVER
204  * - @ref TRACKDB_NORMAL_RECOVER
205  * - @ref TRACKDB_FATAL_RECOVER
206  * - @ref TRACKDB_MAY_CREATE
207  */
208 void trackdb_init(int flags) {
209   int err;
210   const int recover = flags & TRACKDB_RECOVER_MASK;
211   static int recover_type[] = { 0, DB_RECOVER, DB_RECOVER_FATAL };
212
213   /* sanity checks */
214   assert(initialized == 0);
215   ++initialized;
216   if(home) {
217     if(strcmp(home, config->home))
218       fatal(0, "cannot change db home without server restart");
219     home = config->home;
220   }
221
222   if(flags & TRACKDB_MAY_CREATE) {
223     DIR *dp;
224     struct dirent *de;
225     struct stat st;
226     char *p;
227
228     /* Remove world/group permissions on any regular files already in the
229      * database directory.  Actually we don't care about all of them but it's
230      * easier to just do the lot.  This can be revisited if it's a serious
231      * practical inconvenience for anyone.
232      *
233      * The socket, not being a regular file, is excepted.
234      */
235     if(!(dp = opendir(config->home)))
236       fatal(errno, "error reading %s", config->home);
237     while((de = readdir(dp))) {
238       byte_xasprintf(&p, "%s/%s", config->home, de->d_name);
239       if(lstat(p, &st) == 0
240          && S_ISREG(st.st_mode)
241          && (st.st_mode & 077)) {
242         if(chmod(p, st.st_mode & 07700) < 0)
243           fatal(errno, "cannot chmod %s", p);
244       }
245       xfree(p);
246     }
247     closedir(dp);
248   }
249
250   /* create environment */
251   if((err = db_env_create(&trackdb_env, 0))) fatal(0, "db_env_create: %s",
252                                                    db_strerror(err));
253   if((err = trackdb_env->set_alloc(trackdb_env,
254                                    xmalloc_noptr, xrealloc_noptr, xfree)))
255     fatal(0, "trackdb_env->set_alloc: %s", db_strerror(err));
256   if((err = trackdb_env->set_lk_max_locks(trackdb_env, 10000)))
257     fatal(0, "trackdb_env->set_lk_max_locks: %s", db_strerror(err));
258   if((err = trackdb_env->set_lk_max_objects(trackdb_env, 10000)))
259     fatal(0, "trackdb_env->set_lk_max_objects: %s", db_strerror(err));
260   if((err = trackdb_env->open(trackdb_env, config->home,
261                               DB_INIT_LOG
262                               |DB_INIT_LOCK
263                               |DB_INIT_MPOOL
264                               |DB_INIT_TXN
265                               |DB_CREATE
266                               |recover_type[recover],
267                               0600)))
268     fatal(0, "trackdb_env->open %s: %s", config->home, db_strerror(err));
269   trackdb_env->set_errpfx(trackdb_env, "DB");
270   trackdb_env->set_errfile(trackdb_env, stderr);
271   trackdb_env->set_verbose(trackdb_env, DB_VERB_DEADLOCK, 1);
272   trackdb_env->set_verbose(trackdb_env, DB_VERB_RECOVERY, 1);
273   trackdb_env->set_verbose(trackdb_env, DB_VERB_REPLICATION, 1);
274   D(("initialized database environment"));
275 }
276
277 /* called when deadlock manager terminates */
278 static int reap_db_deadlock(ev_source attribute((unused)) *ev,
279                             pid_t attribute((unused)) pid,
280                             int status,
281                             const struct rusage attribute((unused)) *rusage,
282                             void attribute((unused)) *u) {
283   db_deadlock_pid = -1;
284   if(initialized)
285     fatal(0, "deadlock manager unexpectedly terminated: %s",
286           wstat(status));
287   else
288     D(("deadlock manager terminated: %s", wstat(status)));
289   return 0;
290 }
291
292 static pid_t subprogram(ev_source *ev, int outputfd, const char *prog,
293                         ...) {
294   pid_t pid;
295   va_list ap;
296   const char *args[1024], **argp, *a;
297
298   argp = args;
299   *argp++ = prog;
300   *argp++ = "--config";
301   *argp++ = configfile;
302   *argp++ = debugging ? "--debug" : "--no-debug";
303   *argp++ = log_default == &log_syslog ? "--syslog" : "--no-syslog";
304   va_start(ap, prog);
305   while((a = va_arg(ap, const char *)))
306     *argp++ = a;
307   va_end(ap);
308   *argp = 0;
309   /* If we're in the background then trap subprocess stdout/stderr */
310   if(!(pid = xfork())) {
311     exitfn = _exit;
312     if(ev)
313       ev_signal_atfork(ev);
314     signal(SIGPIPE, SIG_DFL);
315     if(outputfd != -1) {
316       xdup2(outputfd, 1);
317       xclose(outputfd);
318     }
319     /* ensure we don't leak privilege anywhere */
320     if(setuid(geteuid()) < 0)
321       fatal(errno, "error calling setuid");
322     /* If we were negatively niced, undo it.  We don't bother checking for 
323     * error, it's not that important. */
324     setpriority(PRIO_PROCESS, 0, 0);
325     execvp(prog, (char **)args);
326     fatal(errno, "error invoking %s", prog);
327   }
328   return pid;
329 }
330
331 /* start deadlock manager */
332 void trackdb_master(ev_source *ev) {
333   assert(db_deadlock_pid == -1);
334   db_deadlock_pid = subprogram(ev, -1, DEADLOCK, (char *)0);
335   ev_child(ev, db_deadlock_pid, 0, reap_db_deadlock, 0);
336   D(("started deadlock manager"));
337 }
338
339 static void terminate_and_wait(ev_source *ev,
340                                pid_t pid,
341                                const char *what) {
342   int err;
343
344   if(pid == -1)
345     return;
346   if(kill(pid, SIGTERM) < 0)
347     fatal(errno, "error killing %s", what);
348   /* wait for the rescanner to finish */
349   while(waitpid(pid, &err, 0) == -1 && errno == EINTR)
350     ;
351   if(ev)
352     ev_child_cancel(ev, pid);
353 }
354
355 /* close environment */
356 void trackdb_deinit(ev_source *ev) {
357   int err;
358
359   /* sanity checks */
360   assert(initialized == 1);
361   --initialized;
362
363   /* close the environment */
364   if((err = trackdb_env->close(trackdb_env, 0)))
365     fatal(0, "trackdb_env->close: %s", db_strerror(err));
366
367   terminate_and_wait(ev, rescan_pid, "disorder-rescan");
368   rescan_pid = -1;
369   terminate_and_wait(ev, choose_pid, "disorder-choose");
370   choose_pid = -1;
371
372   if(stats_pids) {
373     char **ks = hash_keys(stats_pids);
374
375     while(*ks) {
376       pid_t pid = atoi(*ks++);
377       terminate_and_wait(ev, pid, "disorder-stats");
378     }
379     stats_pids = NULL;
380   }
381
382   terminate_and_wait(ev, db_deadlock_pid, "disorder-deadlock");
383   db_deadlock_pid = -1;
384   D(("deinitialized database environment"));
385 }
386
387 /* open a specific database */
388 static DB *open_db(const char *path,
389                    u_int32_t dbflags,
390                    DBTYPE dbtype,
391                    u_int32_t openflags,
392                    int mode) {
393   int err, err2;
394   DB *db;
395
396   D(("open %s", path));
397   path = config_get_file(path);
398   if((err = db_create(&db, trackdb_env, 0)))
399     fatal(0, "db_create %s: %s", path, db_strerror(err));
400   if(dbflags)
401     if((err = db->set_flags(db, dbflags)))
402       fatal(0, "db->set_flags %s: %s", path, db_strerror(err));
403   if(dbtype == DB_BTREE)
404     if((err = db->set_bt_compare(db, compare)))
405       fatal(0, "db->set_bt_compare %s: %s", path, db_strerror(err));
406   if((err = db->open(db, 0, path, 0, dbtype,
407                      openflags | DB_AUTO_COMMIT, mode))) {
408     if((openflags & DB_CREATE) || errno != ENOENT) {
409       if((err2 = db->close(db, 0)))
410         error(0, "db->close: %s", db_strerror(err2));
411       trackdb_close();
412       trackdb_env->close(trackdb_env,0);
413       trackdb_env = 0;
414       fatal(0, "db->open %s: %s", path, db_strerror(err));
415     }
416     db->close(db, 0);
417     db = 0;
418   }
419   return db;
420 }
421
422 /** @brief Open track databases
423  * @param flags Flags flags word
424  *
425  * @p flags should have one of:
426  * - @p TRACKDB_NO_UPGRADE, if no upgrade should be attempted
427  * - @p TRACKDB_CAN_UPGRADE, if an upgrade may be attempted
428  * - @p TRACKDB_OPEN_FOR_UPGRADE, if this is disorder-dbupgrade
429  * Also it may have:
430  * - @p TRACKDB_READ_ONLY, read only access
431  */
432 void trackdb_open(int flags) {
433   int err;
434   pid_t pid;
435   uint32_t dbflags = flags & TRACKDB_READ_ONLY ? DB_RDONLY : DB_CREATE;
436
437   /* sanity checks */
438   assert(opened == 0);
439   ++opened;
440   /* check the database version first */
441   trackdb_globaldb = open_db("global.db", 0, DB_HASH, DB_RDONLY, 0666);
442   if(trackdb_globaldb) {
443     /* This is an existing database */
444     const char *s;
445     long oldversion;
446
447     s = trackdb_get_global("_dbversion");
448     /* Close the database again,  we'll open it property below */
449     if((err = trackdb_globaldb->close(trackdb_globaldb, 0)))
450       fatal(0, "error closing global.db: %s", db_strerror(err));
451     trackdb_globaldb = 0;
452     /* Convert version string to an integer */
453     oldversion = s ? atol(s) : 1;
454     if(oldversion > config->dbversion) {
455       /* Database is from the future; we never allow this. */
456       fatal(0, "this version of DisOrder is too old for database version %ld",
457             oldversion);
458     }
459     if(oldversion < config->dbversion) {
460       /* Database version is out of date */
461       switch(flags & TRACKDB_UPGRADE_MASK) {
462       case TRACKDB_NO_UPGRADE:
463         /* This database needs upgrading but this is not permitted */
464         fatal(0, "database needs upgrading from %ld to %ld",
465               oldversion, config->dbversion);
466       case TRACKDB_CAN_UPGRADE:
467         /* This database needs upgrading */
468         info("invoking disorder-dbupgrade to upgrade from %ld to %ld",
469              oldversion, config->dbversion);
470         pid = subprogram(0, -1, "disorder-dbupgrade", (char *)0);
471         while(waitpid(pid, &err, 0) == -1 && errno == EINTR)
472           ;
473         if(err)
474           fatal(0, "disorder-dbupgrade %s", wstat(err));
475         info("disorder-dbupgrade succeeded");
476         break;
477       case TRACKDB_OPEN_FOR_UPGRADE:
478         break;
479       default:
480         abort();
481       }
482     }
483     if(oldversion == config->dbversion && (flags & TRACKDB_OPEN_FOR_UPGRADE)) {
484       /* This doesn't make any sense */
485       fatal(0, "database is already at current version");
486     }
487     trackdb_existing_database = 1;
488   } else {
489     if(flags & TRACKDB_OPEN_FOR_UPGRADE) {
490       /* Cannot upgrade a new database */
491       fatal(0, "cannot upgrade a database that does not exist");
492     }
493     /* This is a brand new database */
494     trackdb_existing_database = 0;
495   }
496   /* open the databases */
497   if(!(trackdb_usersdb = open_db("users.db",
498                                  0, DB_HASH, dbflags, 0600)))
499     fatal(0, "cannot open users.db");
500   trackdb_tracksdb = open_db("tracks.db",
501                              DB_RECNUM, DB_BTREE, dbflags, 0666);
502   trackdb_searchdb = open_db("search.db",
503                              DB_DUP|DB_DUPSORT, DB_HASH, dbflags, 0666);
504   trackdb_tagsdb = open_db("tags.db",
505                            DB_DUP|DB_DUPSORT, DB_HASH, dbflags, 0666);
506   trackdb_prefsdb = open_db("prefs.db", 0, DB_HASH, dbflags, 0666);
507   trackdb_globaldb = open_db("global.db", 0, DB_HASH, dbflags, 0666);
508   trackdb_noticeddb = open_db("noticed.db",
509                              DB_DUPSORT, DB_BTREE, dbflags, 0666);
510   trackdb_scheduledb = open_db("schedule.db", 0, DB_HASH, dbflags, 0666);
511   trackdb_playlistsdb = open_db("playlists.db", 0, DB_HASH, dbflags, 0666);
512   if(!trackdb_existing_database && !(flags & TRACKDB_READ_ONLY)) {
513     /* Stash the database version */
514     char buf[32];
515
516     assert(!(flags & TRACKDB_OPEN_FOR_UPGRADE));
517     snprintf(buf, sizeof buf, "%ld", config->dbversion);
518     trackdb_set_global("_dbversion", buf, 0);
519   }
520   D(("opened databases"));
521 }
522
523 /* close track databases */
524 void trackdb_close(void) {
525   int err;
526
527   /* sanity checks */
528   assert(opened == 1);
529   --opened;
530 #define CLOSE(N, V) do {                                        \
531   if(V && (err = V->close(V, 0)))                               \
532     fatal(0, "error closing %s: %s", N, db_strerror(err));      \
533   V = 0;                                                        \
534 } while(0)
535   CLOSE("tracks.db", trackdb_tracksdb);
536   CLOSE("search.db", trackdb_searchdb);
537   CLOSE("tags.db", trackdb_tagsdb);
538   CLOSE("prefs.db", trackdb_prefsdb);
539   CLOSE("global.db", trackdb_globaldb);
540   CLOSE("noticed.db", trackdb_noticeddb);
541   CLOSE("schedule.db", trackdb_scheduledb);
542   CLOSE("users.db", trackdb_usersdb);
543   CLOSE("playlists.db", trackdb_playlistsdb);
544   D(("closed databases"));
545 }
546
547 /* generic db routines *******************************************************/
548
549 /** @brief Fetch and decode a database entry
550  * @param db Database
551  * @param track Track name
552  * @param kp Where to put decoded list (or NULL if you don't care)
553  * @param tid Owning transaction
554  * @return 0, @c DB_NOTFOUND or @c DB_LOCK_DEADLOCK
555  */
556 int trackdb_getdata(DB *db,
557                     const char *track,
558                     struct kvp **kp,
559                     DB_TXN *tid) {
560   int err;
561   DBT key, data;
562
563   switch(err = db->get(db, tid, make_key(&key, track),
564                        prepare_data(&data), 0)) {
565   case 0:
566     if(kp)
567       *kp = kvp_urldecode(data.data, data.size);
568     return 0;
569   case DB_NOTFOUND:
570     if(kp)
571       *kp = 0;
572     return err;
573   case DB_LOCK_DEADLOCK:
574     error(0, "error querying database: %s", db_strerror(err));
575     return err;
576   default:
577     fatal(0, "error querying database: %s", db_strerror(err));
578   }
579 }
580
581 /* encode and store a database entry.  Returns 0, DB_KEYEXIST or
582  * DB_LOCK_DEADLOCK. */
583 int trackdb_putdata(DB *db,
584                     const char *track,
585                     const struct kvp *k,
586                     DB_TXN *tid,
587                     u_int32_t flags) {
588   int err;
589   DBT key, data;
590
591   switch(err = db->put(db, tid, make_key(&key, track),
592                        encode_data(&data, k), flags)) {
593   case 0:
594   case DB_KEYEXIST:
595     return err;
596   case DB_LOCK_DEADLOCK:
597     error(0, "error updating database: %s", db_strerror(err));
598     return err;
599   default:
600     fatal(0, "error updating database: %s", db_strerror(err));
601   }
602 }
603
604 /** @brief Delete a database entry
605  * @param db Database
606  * @param track Key to delete
607  * @param tid Transaction ID
608  * @return 0, DB_NOTFOUND or DB_LOCK_DEADLOCK
609  */
610 int trackdb_delkey(DB *db,
611                    const char *track,
612                    DB_TXN *tid) {
613   int err;
614
615   DBT key;
616   switch(err = db->del(db, tid, make_key(&key, track), 0)) {
617   case 0:
618   case DB_NOTFOUND:
619     return 0;
620   case DB_LOCK_DEADLOCK:
621     error(0, "error updating database: %s", db_strerror(err));
622     return err;
623   default:
624     fatal(0, "error updating database: %s", db_strerror(err));
625   }
626 }
627
628 /* open a database cursor */
629 DBC *trackdb_opencursor(DB *db, DB_TXN *tid) {
630   int err;
631   DBC *c;
632
633   switch(err = db->cursor(db, tid, &c, 0)) {
634   case 0: break;
635   default: fatal(0, "error creating cursor: %s", db_strerror(err));
636   }
637   return c;
638 }
639
640 /* close a database cursor; returns 0 or DB_LOCK_DEADLOCK */
641 int trackdb_closecursor(DBC *c) {
642   int err;
643
644   if(!c) return 0;
645   switch(err = c->c_close(c)) {
646   case 0:
647     return err;
648   case DB_LOCK_DEADLOCK:
649     error(0, "error closing cursor: %s", db_strerror(err));
650     return err;
651   default:
652     fatal(0, "error closing cursor: %s", db_strerror(err));
653   }
654 }
655
656 /* delete a (key,data) pair.  Returns 0, DB_NOTFOUND or DB_LOCK_DEADLOCK. */
657 int trackdb_delkeydata(DB *db,
658                        const char *word,
659                        const char *track,
660                        DB_TXN *tid) {
661   int err;
662   DBC *c;
663   DBT key, data;
664
665   c = trackdb_opencursor(db, tid);
666   switch(err = c->c_get(c, make_key(&key, word),
667                         make_key(&data, track), DB_GET_BOTH)) {
668   case 0:
669     switch(err = c->c_del(c, 0)) {
670     case 0:
671       break;
672     case DB_KEYEMPTY:
673       err = 0;
674       break;
675     case DB_LOCK_DEADLOCK:
676       error(0, "error updating database: %s", db_strerror(err));
677       break;
678     default:
679       fatal(0, "c->c_del: %s", db_strerror(err));
680     }
681     break;
682   case DB_NOTFOUND:
683     break;
684   case DB_LOCK_DEADLOCK:
685     error(0, "error updating database: %s", db_strerror(err));
686     break;
687   default:
688     fatal(0, "c->c_get: %s", db_strerror(err));
689   }
690   if(trackdb_closecursor(c)) err = DB_LOCK_DEADLOCK;
691   return err;
692 }
693
694 /* start a transaction */
695 DB_TXN *trackdb_begin_transaction(void) {
696   DB_TXN *tid;
697   int err;
698
699   if((err = trackdb_env->txn_begin(trackdb_env, 0, &tid, 0)))
700     fatal(0, "trackdb_env->txn_begin: %s", db_strerror(err));
701   return tid;
702 }
703
704 /* abort transaction */
705 void trackdb_abort_transaction(DB_TXN *tid) {
706   int err;
707
708   if(tid)
709     if((err = tid->abort(tid)))
710       fatal(0, "tid->abort: %s", db_strerror(err));
711 }
712
713 /* commit transaction */
714 void trackdb_commit_transaction(DB_TXN *tid) {
715   int err;
716
717   if((err = tid->commit(tid, 0)))
718     fatal(0, "tid->commit: %s", db_strerror(err));
719 }
720
721 /* search/tags shared code ***************************************************/
722
723 /* comparison function used by dedupe() */
724 static int wordcmp(const void *a, const void *b) {
725   return strcmp(*(const char **)a, *(const char **)b);
726 }
727
728 /* sort and de-dupe VEC */
729 static char **dedupe(char **vec, int nvec) {
730   int m, n;
731
732   qsort(vec, nvec, sizeof (char *), wordcmp);
733   m = n = 0;
734   if(nvec) {
735     vec[m++] = vec[0];
736     for(n = 1; n < nvec; ++n)
737       if(strcmp(vec[n], vec[m - 1]))
738         vec[m++] = vec[n];
739   }
740   vec[m] = 0;
741   return vec;
742 }
743
744 /* update a key/track database.  Returns 0 or DB_DEADLOCK. */
745 static int register_word(DB *db, const char *what,
746                          const char *track, const char *word,
747                          DB_TXN *tid) {
748   int err;
749   DBT key, data;
750
751   switch(err = db->put(db, tid, make_key(&key, word),
752                        make_key(&data, track), DB_NODUPDATA)) {
753   case 0:
754   case DB_KEYEXIST:
755     return 0;
756   case DB_LOCK_DEADLOCK:
757     error(0, "error updating %s.db: %s", what, db_strerror(err));
758     return err;
759   default:
760     fatal(0, "error updating %s.db: %s", what,  db_strerror(err));
761   }
762 }
763
764 /* search primitives *********************************************************/
765
766 /* return true iff NAME is a trackname_display_ pref */
767 static int is_display_pref(const char *name) {
768   static const char prefix[] = "trackname_display_";
769   return !strncmp(name, prefix, (sizeof prefix) - 1);
770 }
771
772 /** @brief Word_Break property tailor that treats underscores as spaces */
773 static int tailor_underscore_Word_Break_Other(uint32_t c) {
774   switch(c) {
775   default:
776     return -1;
777   case 0x005F: /* LOW LINE (SPACING UNDERSCORE) */
778     return unicode_Word_Break_Other;
779   }
780 }
781
782 /** @brief Remove all combining characters in-place
783  * @param s Pointer to start of string
784  * @param ns Length of string
785  * @return New, possiblby reduced, length
786  */
787 static size_t remove_combining_chars(uint32_t *s, size_t ns) {
788   uint32_t *start = s, *t = s, *end = s + ns;
789
790   while(s < end) {
791     const uint32_t c = *s++;
792     if(!utf32_combining_class(c))
793       *t++ = c;
794   }
795   return t - start;
796 }
797
798 /** @brief Normalize and split a string using a given tailoring */
799 static void word_split(struct vector *v,
800                        const char *s,
801                        unicode_property_tailor *pt) {
802   size_t nw, nt32, i;
803   uint32_t *t32, **w32;
804
805   /* Convert to UTF-32 */
806   if(!(t32 = utf8_to_utf32(s, strlen(s), &nt32)))
807     return;
808   /* Erase case distinctions */
809   if(!(t32 = utf32_casefold_compat(t32, nt32, &nt32)))
810     return;
811   /* Drop combining characters */
812   nt32 = remove_combining_chars(t32, nt32);
813   /* Split into words, treating _ as a space */
814   w32 = utf32_word_split(t32, nt32, &nw, pt);
815   /* Convert words back to UTF-8 and append to result */
816   for(i = 0; i < nw; ++i)
817     vector_append(v, utf32_to_utf8(w32[i], utf32_len(w32[i]), 0));
818 }
819
820 /** @brief Normalize a tag
821  * @param s Tag
822  * @param ns Length of tag
823  * @return Normalized string or NULL on error
824  *
825  * The return value will be:
826  * - case-folded
827  * - have no leading or trailing space
828  * - have no combining characters
829  * - all spacing between words will be a single U+0020 SPACE
830  */
831 static char *normalize_tag(const char *s, size_t ns) {
832   uint32_t *s32, **w32;
833   size_t ns32, nw32, i;
834   struct dynstr d[1];
835
836   if(!(s32 = utf8_to_utf32(s, ns, &ns32)))
837     return 0;
838   if(!(s32 = utf32_casefold_compat(s32, ns32, &ns32))) /* ->NFKD */
839     return 0;
840   ns32 = remove_combining_chars(s32, ns32);
841   /* Split into words, no Word_Break tailoring */
842   w32 = utf32_word_split(s32, ns32, &nw32, 0);
843   /* Compose back into a string */
844   dynstr_init(d);
845   for(i = 0; i < nw32; ++i) {
846     if(i)
847       dynstr_append(d, ' ');
848     dynstr_append_string(d, utf32_to_utf8(w32[i], utf32_len(w32[i]), 0));
849   }
850   dynstr_terminate(d);
851   return d->vec;
852 }
853
854 /* compute the words of a track name */
855 static char **track_to_words(const char *track,
856                              const struct kvp *p) {
857   struct vector v;
858   const char *rootless = track_rootless(track);
859
860   if(!rootless)
861     rootless = track;                   /* bodge */
862   vector_init(&v);
863   rootless = strip_extension(rootless);
864   word_split(&v, strip_extension(rootless), tailor_underscore_Word_Break_Other);
865   for(; p; p = p->next)
866     if(is_display_pref(p->name))
867       word_split(&v, p->value, 0);
868   vector_terminate(&v);
869   return dedupe(v.vec, v.nvec);
870 }
871
872 /* return nonzero iff WORD is a stopword */
873 static int stopword(const char *word) {
874   int n;
875
876   for(n = 0; n < config->stopword.n
877         && strcmp(word, config->stopword.s[n]); ++n)
878     ;
879   return n < config->stopword.n;
880 }
881
882 /* record that WORD appears in TRACK.  Returns 0 or DB_LOCK_DEADLOCK. */
883 static int register_search_word(const char *track, const char *word,
884                                 DB_TXN *tid) {
885   if(stopword(word)) return 0;
886   return register_word(trackdb_searchdb, "search", track, word, tid);
887 }
888
889 /* Tags **********************************************************************/
890
891 /* Return nonzero if C is a valid tag character */
892 static int tagchar(int c) {
893   switch(c) {
894   case ',':
895     return 0;
896   default:
897     return c >= ' ';
898   }
899 }
900
901 /* Parse and de-dupe a tag list.  If S=0 then assumes "". */
902 char **parsetags(const char *s) {
903   const char *t;
904   struct vector v;
905
906   vector_init(&v);
907   if(s) {
908     /* skip initial separators */
909     while(*s && (!tagchar(*s) || *s == ' '))
910       ++s;
911     while(*s) {
912       /* find the extent of the tag */
913       t = s;
914       while(*s && tagchar(*s))
915         ++s;
916       /* strip trailing spaces */
917       while(s > t && s[-1] == ' ')
918         --s;
919       /* add tag to list */
920       vector_append(&v, normalize_tag(t, (size_t)(s - t)));
921       /* skip intermediate and trailing separators */
922       while(*s && (!tagchar(*s) || *s == ' '))
923         ++s;
924     }
925   }
926   vector_terminate(&v);
927   return dedupe(v.vec, v.nvec);
928 }
929
930 /* Record that TRACK has TAG.  Returns 0 or DB_LOCK_DEADLOCK. */
931 static int register_tag(const char *track, const char *tag, DB_TXN *tid) {
932   return register_word(trackdb_tagsdb, "tags", track, tag, tid);
933 }
934
935 /* aliases *******************************************************************/
936
937 /* compute the alias and store at aliasp.  Returns 0 or DB_LOCK_DEADLOCK.  If
938  * there is no alias sets *aliasp to 0. */
939 static int compute_alias(char **aliasp,
940                          const char *track,
941                          const struct kvp *p,
942                          DB_TXN *tid) {
943   struct dynstr d;
944   const char *s = config->alias, *t, *expansion, *part;
945   int c, used_db = 0, slash_prefix, err;
946   struct kvp *at;
947   const char *const root = find_track_root(track);
948
949   if(!root) {
950     /* Bodge for tracks with no root */
951     *aliasp = 0;
952     return 0;
953   }
954   dynstr_init(&d);
955   dynstr_append_string(&d, root);
956   while((c = (unsigned char)*s++)) {
957     if(c != '{') {
958       dynstr_append(&d, c);
959       continue;
960     }
961     if((slash_prefix = (*s == '/')))
962       s++;
963     t = strchr(s, '}');
964     assert(t != 0);                     /* validated at startup */
965     part = xstrndup(s, t - s);
966     expansion = getpart(track, "display", part, p, &used_db);
967     if(*expansion) {
968       if(slash_prefix) dynstr_append(&d, '/');
969       dynstr_append_string(&d, expansion);
970     }
971     s = t + 1;                          /* skip {part} */
972   }
973   /* only admit to the alias if we used the db... */
974   if(!used_db) {
975     *aliasp = 0;
976     return 0;
977   }
978   dynstr_terminate(&d);
979   /* ...and the answer differs from the original... */
980   if(!strcmp(track, d.vec)) {
981     *aliasp = 0;
982     return 0;
983   }
984   /* ...and there isn't already a different track with that name (including as
985    * an alias) */
986   switch(err = trackdb_getdata(trackdb_tracksdb, d.vec, &at, tid)) {
987   case 0:
988     if((s = kvp_get(at, "_alias_for"))
989        && !strcmp(s, track)) {
990     case DB_NOTFOUND:
991       *aliasp = d.vec;
992     } else {
993       *aliasp = 0;
994     }
995     return 0;
996   default:
997     return err;
998   }
999 }
1000
1001 /* get track and prefs data (if tp/pp not null pointers).  Returns 0 on
1002  * success, DB_NOTFOUND if the track does not exist or DB_LOCK_DEADLOCK.
1003  * Always sets the return values, even if only to null pointers. */
1004 static int gettrackdata(const char *track,
1005                         struct kvp **tp,
1006                         struct kvp **pp,
1007                         const char **actualp,
1008                         unsigned flags,
1009 #define GTD_NOALIAS 0x0001
1010                         DB_TXN *tid) {
1011   int err;
1012   const char *actual = track;
1013   struct kvp *t = 0, *p = 0;
1014
1015   if((err = trackdb_getdata(trackdb_tracksdb, track, &t, tid))) goto done;
1016   if((actual = kvp_get(t, "_alias_for"))) {
1017     if(flags & GTD_NOALIAS) {
1018       error(0, "alias passed to gettrackdata where real path required");
1019       abort();
1020     }
1021     if((err = trackdb_getdata(trackdb_tracksdb, actual, &t, tid))) goto done;
1022   } else
1023     actual = track;
1024   assert(actual != 0);
1025   if(pp) {
1026     if((err = trackdb_getdata(trackdb_prefsdb, actual, &p, tid)) == DB_LOCK_DEADLOCK)
1027       goto done;
1028   }
1029   err = 0;
1030 done:
1031   if(actualp) *actualp = actual;
1032   if(tp) *tp = t;
1033   if(pp) *pp = p;
1034   return err;
1035 }
1036
1037 /* trackdb_notice() **********************************************************/
1038
1039 /** @brief notice a possibly new track
1040  * @return @c DB_NOTFOUND if new, 0 if already known
1041  */
1042 int trackdb_notice(const char *track,
1043                    const char *path) {
1044   int err;
1045   DB_TXN *tid;
1046
1047   for(;;) {
1048     tid = trackdb_begin_transaction();
1049     err = trackdb_notice_tid(track, path, tid);
1050     if((err == DB_LOCK_DEADLOCK)) goto fail;
1051     break;
1052   fail:
1053     trackdb_abort_transaction(tid);
1054   }
1055   trackdb_commit_transaction(tid);
1056   return err;
1057 }
1058
1059 /** @brief notice a possibly new track
1060  * @param track NFC UTF-8 track name
1061  * @param path Raw path name
1062  * @param tid Transaction ID
1063  * @return @c DB_NOTFOUND if new, 0 if already known, @c DB_LOCK_DEADLOCK also
1064  */
1065 int trackdb_notice_tid(const char *track,
1066                        const char *path,
1067                        DB_TXN *tid) {
1068   int err, n;
1069   struct kvp *t, *a, *p;
1070   int t_changed, ret;
1071   char *alias, **w, *noticed;
1072   time_t now;
1073
1074   /* notice whether the tracks.db entry changes */
1075   t_changed = 0;
1076   /* get any existing tracks entry */
1077   if((err = gettrackdata(track, &t, &p, 0, 0, tid)) == DB_LOCK_DEADLOCK)
1078     return err;
1079   ret = err;                            /* 0 or DB_NOTFOUND */
1080   /* this is a real track */
1081   t_changed += kvp_set(&t, "_alias_for", 0);
1082   t_changed += kvp_set(&t, "_path", path);
1083   xtime(&now);
1084   if(ret == DB_NOTFOUND) {
1085     /* It's a new track; record the time */
1086     byte_xasprintf(&noticed, "%lld", (long long)now);
1087     t_changed += kvp_set(&t, "_noticed", noticed);
1088   }
1089   /* if we have an alias record it in the database */
1090   if((err = compute_alias(&alias, track, p, tid))) return err;
1091   if(alias) {
1092     /* won't overwrite someone else's alias as compute_alias() checks */
1093     D(("%s: alias %s", track, alias));
1094     a = 0;
1095     kvp_set(&a, "_alias_for", track);
1096     if((err = trackdb_putdata(trackdb_tracksdb, alias, a, tid, 0))) return err;
1097   }
1098   /* update search.db */
1099   w = track_to_words(track, p);
1100   for(n = 0; w[n]; ++n)
1101     if((err = register_search_word(track, w[n], tid)))
1102       return err;
1103   /* update tags.db */
1104   w = parsetags(kvp_get(p, "tags"));
1105   for(n = 0; w[n]; ++n)
1106     if((err = register_tag(track, w[n], tid)))
1107       return err;
1108   /* only store the tracks.db entry if it has changed */
1109   if(t_changed && (err = trackdb_putdata(trackdb_tracksdb, track, t, tid, 0)))
1110     return err;
1111   if(ret == DB_NOTFOUND) {
1112     uint32_t timestamp[2];
1113     DBT key, data;
1114
1115     timestamp[0] = htonl((uint64_t)now >> 32);
1116     timestamp[1] = htonl((uint32_t)now);
1117     memset(&key, 0, sizeof key);
1118     key.data = timestamp;
1119     key.size = sizeof timestamp;
1120     switch(err = trackdb_noticeddb->put(trackdb_noticeddb, tid, &key,
1121                                         make_key(&data, track), 0)) {
1122     case 0: break;
1123     case DB_LOCK_DEADLOCK: return err;
1124     default: fatal(0, "error updating noticed.db: %s", db_strerror(err));
1125     }
1126   }
1127   return ret;
1128 }
1129
1130 /* trackdb_obsolete() ********************************************************/
1131
1132 /* obsolete a track */
1133 int trackdb_obsolete(const char *track, DB_TXN *tid) {
1134   int err, n;
1135   struct kvp *p;
1136   char *alias, **w;
1137
1138   if((err = gettrackdata(track, 0, &p, 0,
1139                          GTD_NOALIAS, tid)) == DB_LOCK_DEADLOCK)
1140     return err;
1141   else if(err == DB_NOTFOUND) return 0;
1142   /* compute the alias, if any, and delete it */
1143   if((err = compute_alias(&alias, track, p, tid))) return err;
1144   if(alias) {
1145     /* if the alias points to some other track then compute_alias won't
1146      * return it */
1147     if((err = trackdb_delkey(trackdb_tracksdb, alias, tid))
1148        && err != DB_NOTFOUND)
1149       return err;
1150   }
1151   /* update search.db */
1152   w = track_to_words(track, p);
1153   for(n = 0; w[n]; ++n)
1154     if(trackdb_delkeydata(trackdb_searchdb,
1155                           w[n], track, tid) == DB_LOCK_DEADLOCK)
1156       return err;
1157   /* update tags.db */
1158   w = parsetags(kvp_get(p, "tags"));
1159   for(n = 0; w[n]; ++n)
1160     if(trackdb_delkeydata(trackdb_tagsdb,
1161                           w[n], track, tid) == DB_LOCK_DEADLOCK)
1162       return err;
1163   /* update tracks.db */
1164   if(trackdb_delkey(trackdb_tracksdb, track, tid) == DB_LOCK_DEADLOCK)
1165     return err;
1166   /* We don't delete the prefs, so they survive temporary outages of the
1167    * (possibly virtual) track filesystem */
1168   return 0;
1169 }
1170
1171 /* trackdb_stats() ***********************************************************/
1172
1173 #define H(name) { #name, offsetof(DB_HASH_STAT, name) }
1174 #define B(name) { #name, offsetof(DB_BTREE_STAT, name) }
1175
1176 static const struct statinfo {
1177   const char *name;
1178   size_t offset;
1179 } statinfo_hash[] = {
1180   H(hash_magic),
1181   H(hash_version),
1182   H(hash_nkeys),
1183   H(hash_ndata),
1184   H(hash_pagesize),
1185   H(hash_ffactor),
1186   H(hash_buckets),
1187   H(hash_free),
1188   H(hash_bfree),
1189   H(hash_bigpages),
1190   H(hash_big_bfree),
1191   H(hash_overflows),
1192   H(hash_ovfl_free),
1193   H(hash_dup),
1194   H(hash_dup_free),
1195 }, statinfo_btree[] = {
1196   B(bt_magic),
1197   B(bt_version),
1198   B(bt_nkeys),
1199   B(bt_ndata),
1200   B(bt_pagesize),
1201   B(bt_minkey),
1202   B(bt_re_len),
1203   B(bt_re_pad),
1204   B(bt_levels),
1205   B(bt_int_pg),
1206   B(bt_leaf_pg),
1207   B(bt_dup_pg),
1208   B(bt_over_pg),
1209   B(bt_free),
1210   B(bt_int_pgfree),
1211   B(bt_leaf_pgfree),
1212   B(bt_dup_pgfree),
1213   B(bt_over_pgfree),
1214 };
1215
1216 /* look up stats for DB */
1217 static int get_stats(struct vector *v,
1218                      DB *database,
1219                      const struct statinfo *si,
1220                      size_t nsi,
1221                      DB_TXN *tid) {
1222   void *sp;
1223   size_t n;
1224   char *str;
1225   int err;
1226
1227   if(database) {
1228     switch(err = database->stat(database, tid, &sp, 0)) {
1229     case 0:
1230       break;
1231     case DB_LOCK_DEADLOCK:
1232       error(0, "error querying database: %s", db_strerror(err));
1233       return err;
1234     default:
1235       fatal(0, "error querying database: %s", db_strerror(err));
1236     }
1237     for(n = 0; n < nsi; ++n) {
1238       byte_xasprintf(&str, "%s=%"PRIuMAX, si[n].name,
1239                      (uintmax_t)*(u_int32_t *)((char *)sp + si[n].offset));
1240       vector_append(v, str);
1241     }
1242   }
1243   return 0;
1244 }
1245
1246 /** @brief One entry in the search league */
1247 struct search_entry {
1248   char *word;
1249   int n;
1250 };
1251
1252 /** @brief Add a word to the search league
1253  * @param se Pointer to search league
1254  * @param count Maximum size for search league
1255  * @param nse Current size of search league
1256  * @param word New word, or NULL
1257  * @param n How often @p word appears
1258  * @return New size of search league
1259  */
1260 static int register_search_entry(struct search_entry *se,
1261                                  int count,
1262                                  int nse,
1263                                  char *word,
1264                                  int n) {
1265   int i;
1266
1267   if(word && (nse < count || n > se[nse - 1].n)) {
1268     /* Find the starting point */
1269     if(nse == count)
1270       i = nse - 1;
1271     else
1272       i = nse++;
1273     /* Find the insertion point */
1274     while(i > 0 && n > se[i - 1].n)
1275       --i;
1276     memmove(&se[i + 1], &se[i], (nse - i - 1) * sizeof *se);
1277     se[i].word = word;
1278     se[i].n = n;
1279   }
1280   return nse;
1281 }
1282
1283 /* find the top COUNT words in the search database */
1284 static int search_league(struct vector *v, int count, DB_TXN *tid) {
1285   struct search_entry *se;
1286   DBT k, d;
1287   DBC *cursor;
1288   int err, n = 0, nse = 0, i;
1289   char *word = 0;
1290   size_t wl = 0;
1291   char *str;
1292
1293   cursor = trackdb_opencursor(trackdb_searchdb, tid);
1294   se = xmalloc(count * sizeof *se);
1295   /* Walk across the whole database counting up the number of times each
1296    * word appears. */
1297   while(!(err = cursor->c_get(cursor, prepare_data(&k), prepare_data(&d),
1298                               DB_NEXT))) {
1299     if(word && wl == k.size && !strncmp(word, k.data, wl))
1300       ++n;                              /* same word again */
1301     else {
1302       nse = register_search_entry(se, count, nse, word, n);
1303       word = xstrndup(k.data, wl = k.size);
1304       n = 1;
1305     }
1306   }
1307   switch(err) {
1308   case DB_NOTFOUND:
1309     err = 0;
1310     break;
1311   case DB_LOCK_DEADLOCK:
1312     error(0, "error querying search database: %s", db_strerror(err));
1313     break;
1314   default:
1315     fatal(0, "error querying search database: %s", db_strerror(err));
1316   }
1317   if(trackdb_closecursor(cursor)) err = DB_LOCK_DEADLOCK;
1318   if(err) return err;
1319   nse = register_search_entry(se, count, nse, word, n);
1320   byte_xasprintf(&str, "Top %d search words:", nse);
1321   vector_append(v, str);
1322   for(i = 0; i < nse; ++i) {
1323     byte_xasprintf(&str, "%4d: %5d %s", i + 1, se[i].n, se[i].word);
1324     vector_append(v, str);
1325   }
1326   return 0;
1327 }
1328
1329 #define SI(what) statinfo_##what, \
1330                  sizeof statinfo_##what / sizeof (struct statinfo)
1331
1332 /* return a list of database stats */
1333 char **trackdb_stats(int *nstatsp) {
1334   DB_TXN *tid;
1335   struct vector v;
1336
1337   vector_init(&v);
1338   for(;;) {
1339     tid = trackdb_begin_transaction();
1340     v.nvec = 0;
1341     vector_append(&v, (char *)"Tracks database stats:");
1342     if(get_stats(&v, trackdb_tracksdb, SI(btree), tid)) goto fail;
1343     vector_append(&v, (char *)"");
1344     vector_append(&v, (char *)"Search database stats:");
1345     if(get_stats(&v, trackdb_searchdb, SI(hash), tid)) goto fail;
1346     vector_append(&v, (char *)"");
1347     vector_append(&v, (char *)"Prefs database stats:");
1348     if(get_stats(&v, trackdb_prefsdb, SI(hash), tid)) goto fail;
1349     vector_append(&v, (char *)"");
1350     if(search_league(&v, 10, tid)) goto fail;
1351     vector_terminate(&v);
1352     break;
1353 fail:
1354     trackdb_abort_transaction(tid);
1355   }
1356   trackdb_commit_transaction(tid);
1357   if(nstatsp) *nstatsp = v.nvec;
1358   return v.vec;
1359 }
1360
1361 struct stats_details {
1362   void (*done)(char *data, void *u);
1363   void *u;
1364   int exited;                           /* subprocess exited */
1365   int closed;                           /* pipe close */
1366   int wstat;                            /* wait status from subprocess */
1367   struct dynstr data[1];                /* data read from pipe */
1368 };
1369
1370 static void stats_complete(struct stats_details *d) {
1371   char *s;
1372
1373   if(!(d->exited && d->closed))
1374     return;
1375   byte_xasprintf(&s, "\n"
1376                  "Server stats:\n"
1377                  "track lookup cache hits: %lu\n"
1378                  "track lookup cache misses: %lu\n",
1379                  cache_files_hits,
1380                  cache_files_misses);
1381   dynstr_append_string(d->data, s);
1382   dynstr_terminate(d->data);
1383   d->done(d->data->vec, d->u);
1384 }
1385
1386 static int stats_finished(ev_source attribute((unused)) *ev,
1387                           pid_t pid,
1388                           int status,
1389                           const struct rusage attribute((unused)) *rusage,
1390                           void *u) {
1391   struct stats_details *const d = u;
1392
1393   d->exited = 1;
1394   if(status)
1395     error(0, "disorder-stats %s", wstat(status));
1396   stats_complete(d);
1397   char *k;
1398   byte_xasprintf(&k, "%lu", (unsigned long)pid);
1399   hash_remove(stats_pids, k);
1400   return 0;
1401 }
1402
1403 static int stats_read(ev_source attribute((unused)) *ev,
1404                       ev_reader *reader,
1405                       void *ptr,
1406                       size_t bytes,
1407                       int eof,
1408                       void *u) {
1409   struct stats_details *const d = u;
1410
1411   dynstr_append_bytes(d->data, ptr, bytes);
1412   ev_reader_consume(reader, bytes);
1413   if(eof)
1414     d->closed = 1;
1415   stats_complete(d);
1416   return 0;
1417 }
1418
1419 static int stats_error(ev_source attribute((unused)) *ev,
1420                        int errno_value,
1421                        void *u) {
1422   struct stats_details *const d = u;
1423
1424   error(errno_value, "error reading from pipe to disorder-stats");
1425   d->closed = 1;
1426   stats_complete(d);
1427   return 0;
1428 }
1429
1430 void trackdb_stats_subprocess(ev_source *ev,
1431                               void (*done)(char *data, void *u),
1432                               void *u) {
1433   int p[2];
1434   pid_t pid;
1435   struct stats_details *d = xmalloc(sizeof *d);
1436
1437   dynstr_init(d->data);
1438   d->done = done;
1439   d->u = u;
1440   xpipe(p);
1441   pid = subprogram(ev, p[1], "disorder-stats", (char *)0);
1442   xclose(p[1]);
1443   ev_child(ev, pid, 0, stats_finished, d);
1444   if(!ev_reader_new(ev, p[0], stats_read, stats_error, d,
1445                     "disorder-stats reader"))
1446     fatal(0, "ev_reader_new for disorder-stats reader failed");
1447   /* Remember the PID */
1448   if(!stats_pids)
1449     stats_pids = hash_new(1);
1450   char *k;
1451   byte_xasprintf(&k, "%lu", (unsigned long)pid);
1452   hash_add(stats_pids, k, "", HASH_INSERT);
1453 }
1454
1455 /** @brief Parse a track name part preference
1456  * @param name Preference name
1457  * @param partp Where to store part name
1458  * @param contextp Where to store context name
1459  * @return 0 on success, non-0 if parse fails
1460  */
1461 static int trackdb__parse_namepref(const char *name,
1462                                    char **partp,
1463                                    char **contextp) {
1464   char *c;
1465   static const char prefix[] = "trackname_";
1466   
1467   if(strncmp(name, prefix, strlen(prefix)))
1468     return -1;                          /* not trackname_* at all */
1469   name += strlen(prefix);
1470   /* There had better be a _ between context and part */
1471   c = strchr(name, '_');
1472   if(!c)
1473     return -1;
1474   /* Context is first in the pref name even though most APIs have the part
1475    * first.  Confusing; sorry. */
1476   *contextp = xstrndup(name, c - name);
1477   ++c;
1478   /* There had better NOT be a second _ */
1479   if(strchr(c, '_'))
1480     return -1;
1481   *partp = xstrdup(c);
1482   return 0;
1483 }
1484
1485 /** @brief Compute the default value for a track preference
1486  * @param track Track name
1487  * @param name Preference name
1488  * @return Default value or 0 if none/not known
1489  */
1490 static const char *trackdb__default(const char *track, const char *name) {
1491   char *context, *part;
1492   
1493   if(!trackdb__parse_namepref(name, &part, &context)) {
1494     /* We can work out the default for a trackname_ pref */
1495     return trackname_part(track, context, part);
1496   } else if(!strcmp(name, "weight")) {
1497     /* We know the default weight */
1498     return "90000";
1499   } else if(!strcmp(name, "pick_at_random")) {
1500     /* By default everything is eligible for picking at random */
1501     return "1";
1502   } else if(!strcmp(name, "tags")) {
1503     /* By default everything no track has any tags */
1504     return "";
1505   }
1506   return 0;
1507 }
1508
1509 /* set a pref (remove if value=0) */
1510 int trackdb_set(const char *track,
1511                 const char *name,
1512                 const char *value) {
1513   struct kvp *t, *p, *a;
1514   DB_TXN *tid;
1515   int err, cmp;
1516   char *oldalias, *newalias, **oldtags = 0, **newtags;
1517   const char *def;
1518
1519   /* If the value matches the default then unset instead, to keep the database
1520    * tidy.  Older versions did not have this feature so your database may yet
1521    * have some default values stored in it. */
1522   if(value) {
1523     def = trackdb__default(track, name);
1524     if(def && !strcmp(value, def))
1525       value = 0;
1526   }
1527
1528   for(;;) {
1529     tid = trackdb_begin_transaction();
1530     if((err = gettrackdata(track, &t, &p, 0,
1531                            0, tid)) == DB_LOCK_DEADLOCK)
1532       goto fail;
1533     if(err == DB_NOTFOUND) break;
1534     if(name[0] == '_') {
1535       if(kvp_set(&t, name, value))
1536         if(trackdb_putdata(trackdb_tracksdb, track, t, tid, 0))
1537           goto fail;
1538     } else {
1539       /* get the old alias name */
1540       if(compute_alias(&oldalias, track, p, tid)) goto fail;
1541       /* get the old tags */
1542       if(!strcmp(name, "tags"))
1543         oldtags = parsetags(kvp_get(p, "tags"));
1544       /* set the value */
1545       if(kvp_set(&p, name, value))
1546         if(trackdb_putdata(trackdb_prefsdb, track, p, tid, 0))
1547           goto fail;
1548       /* compute the new alias name */
1549       if((err = compute_alias(&newalias, track, p, tid))) goto fail;
1550       /* check whether alias has changed */
1551       if(!(oldalias == newalias
1552            || (oldalias && newalias && !strcmp(oldalias, newalias)))) {
1553         /* adjust alias records to fit change */
1554         if(oldalias
1555            && trackdb_delkey(trackdb_tracksdb, oldalias, tid) == DB_LOCK_DEADLOCK)
1556           goto fail;
1557         if(newalias) {
1558           a = 0;
1559           kvp_set(&a, "_alias_for", track);
1560           if(trackdb_putdata(trackdb_tracksdb, newalias, a, tid, 0)) goto fail;
1561         }
1562       }
1563       /* check whether tags have changed */
1564       if(!strcmp(name, "tags")) {
1565         newtags = parsetags(value);
1566         while(*oldtags || *newtags) {
1567           if(*oldtags && *newtags) {
1568             cmp = strcmp(*oldtags, *newtags);
1569             if(!cmp) {
1570               /* keeping this tag */
1571               ++oldtags;
1572               ++newtags;
1573             } else if(cmp < 0)
1574               /* old tag fits into a gap in the new list, so delete old */
1575               goto delete_old;
1576             else
1577               /* new tag fits into a gap in the old list, so insert new */
1578               goto insert_new;
1579           } else if(*oldtags) {
1580             /* we've run out of new tags, so remaining old ones are to be
1581              * deleted */
1582           delete_old:
1583             if(trackdb_delkeydata(trackdb_tagsdb,
1584                                   *oldtags, track, tid) == DB_LOCK_DEADLOCK)
1585               goto fail;
1586             ++oldtags;
1587           } else {
1588             /* we've run out of old tags, so remainig new ones are to be
1589              * inserted */
1590           insert_new:
1591             if(register_tag(track, *newtags, tid)) goto fail;
1592             ++newtags;
1593           }
1594         }
1595       }
1596     }
1597     err = 0;
1598     break;
1599 fail:
1600     trackdb_abort_transaction(tid);
1601   }
1602   trackdb_commit_transaction(tid);
1603   return err == 0 ? 0 : -1;
1604 }
1605
1606 /* get a pref */
1607 const char *trackdb_get(const char *track,
1608                         const char *name) {
1609   return kvp_get(trackdb_get_all(track), name);
1610 }
1611
1612 /* get all prefs as a 0-terminated array */
1613 struct kvp *trackdb_get_all(const char *track) {
1614   struct kvp *t, *p, **pp;
1615   DB_TXN *tid;
1616
1617   for(;;) {
1618     tid = trackdb_begin_transaction();
1619     if(gettrackdata(track, &t, &p, 0, 0, tid) == DB_LOCK_DEADLOCK)
1620       goto fail;
1621     break;
1622 fail:
1623     trackdb_abort_transaction(tid);
1624   }
1625   trackdb_commit_transaction(tid);
1626   for(pp = &p; *pp; pp = &(*pp)->next)
1627     ;
1628   *pp = t;
1629   return p;
1630 }
1631
1632 /* resolve alias */
1633 const char *trackdb_resolve(const char *track) {
1634   DB_TXN *tid;
1635   const char *actual;
1636
1637   for(;;) {
1638     tid = trackdb_begin_transaction();
1639     if(gettrackdata(track, 0, 0, &actual, 0, tid) == DB_LOCK_DEADLOCK)
1640       goto fail;
1641     break;
1642 fail:
1643     trackdb_abort_transaction(tid);
1644   }
1645   trackdb_commit_transaction(tid);
1646   return actual;
1647 }
1648
1649 int trackdb_isalias(const char *track) {
1650   const char *actual = trackdb_resolve(track);
1651
1652   return strcmp(actual, track);
1653 }
1654
1655 /* test whether a track exists (perhaps an alias) */
1656 int trackdb_exists(const char *track) {
1657   DB_TXN *tid;
1658   int err;
1659
1660   for(;;) {
1661     tid = trackdb_begin_transaction();
1662     /* unusually, here we want the return value */
1663     if((err = gettrackdata(track, 0, 0, 0, 0, tid)) == DB_LOCK_DEADLOCK)
1664       goto fail;
1665     break;
1666 fail:
1667     trackdb_abort_transaction(tid);
1668   }
1669   trackdb_commit_transaction(tid);
1670   return (err == 0);
1671 }
1672
1673 /* return the list of tags */
1674 char **trackdb_alltags(void) {
1675   int e;
1676   struct vector v[1];
1677
1678   vector_init(v);
1679   WITH_TRANSACTION(trackdb_listkeys(trackdb_tagsdb, v, tid));
1680   return v->vec;
1681 }
1682
1683 /** @brief List all the keys in @p db
1684  * @param db Database
1685  * @param v Vector to store keys in
1686  * @param tid Transaction ID
1687  * @return 0 or DB_LOCK_DEADLOCK
1688  */
1689 int trackdb_listkeys(DB *db, struct vector *v, DB_TXN *tid) {
1690   int e;
1691   DBT k, d;
1692   DBC *const c = trackdb_opencursor(db, tid);
1693
1694   v->nvec = 0;
1695   memset(&k, 0, sizeof k);
1696   while(!(e = c->c_get(c, &k, prepare_data(&d), DB_NEXT_NODUP)))
1697     vector_append(v, xstrndup(k.data, k.size));
1698   switch(e) {
1699   case DB_NOTFOUND:
1700     break;
1701   case DB_LOCK_DEADLOCK:
1702     return e;
1703   default:
1704     fatal(0, "c->c_get: %s", db_strerror(e));
1705   }
1706   if((e = trackdb_closecursor(c)))
1707     return e;
1708   vector_terminate(v);
1709   return 0;
1710 }
1711
1712 /* return 1 iff sorted tag lists A and B have at least one member in common */
1713 int tag_intersection(char **a, char **b) {
1714   int cmp;
1715
1716   /* Same sort of logic as trackdb_set() above */
1717   while(*a && *b) {
1718     if(!(cmp = strcmp(*a, *b))) return 1;
1719     else if(cmp < 0) ++a;
1720     else ++b;
1721   }
1722   return 0;
1723 }
1724
1725 static void choose_finished(ev_source *ev, unsigned which) {
1726   choose_complete |= which;
1727   if(choose_complete != (CHOOSE_RUNNING|CHOOSE_READING))
1728     return;
1729   choose_pid = -1;
1730   if(choose_status == 0 && choose_output.nvec > 0) {
1731     dynstr_terminate(&choose_output);
1732     choose_callback(ev, xstrdup(choose_output.vec));
1733   } else
1734     choose_callback(ev, 0);
1735 }
1736
1737 /** @brief Called when @c disorder-choose terminates */
1738 static int choose_exited(ev_source *ev,
1739                          pid_t attribute((unused)) pid,
1740                          int status,
1741                          const struct rusage attribute((unused)) *rusage,
1742                          void attribute((unused)) *u) {
1743   if(status)
1744     error(0, "disorder-choose %s", wstat(status));
1745   choose_status = status;
1746   choose_finished(ev, CHOOSE_RUNNING);
1747   return 0;
1748 }
1749
1750 /** @brief Called with data from @c disorder-choose pipe */
1751 static int choose_readable(ev_source *ev,
1752                            ev_reader *reader,
1753                            void *ptr,
1754                            size_t bytes,
1755                            int eof,
1756                            void attribute((unused)) *u) {
1757   dynstr_append_bytes(&choose_output, ptr, bytes);
1758   ev_reader_consume(reader, bytes);
1759   if(eof)
1760     choose_finished(ev, CHOOSE_READING);
1761   return 0;
1762 }
1763
1764 static int choose_read_error(ev_source *ev,
1765                              int errno_value,
1766                              void attribute((unused)) *u) {
1767   error(errno_value, "error reading disorder-choose pipe");
1768   choose_finished(ev, CHOOSE_READING);
1769   return 0;
1770 }
1771
1772 /** @brief Request a random track
1773  * @param ev Event source
1774  * @param callback Called with random track or NULL
1775  * @return 0 if a request was initiated, else -1
1776  *
1777  * Initiates a random track choice.  @p callback will later be called back with
1778  * the choice (or NULL on error).  If a choice is already underway then -1 is
1779  * returned and there will be no additional callback.
1780  *
1781  * The caller shouldn't assume that the track returned actually exists (it
1782  * might be removed between the choice and the callback, or between being added
1783  * to the queue and being played).
1784  */
1785 int trackdb_request_random(ev_source *ev,
1786                            random_callback *callback) {
1787   int p[2];
1788   
1789   if(choose_pid != -1)
1790     return -1;                          /* don't run concurrent chooses */
1791   xpipe(p);
1792   cloexec(p[0]);
1793   choose_pid = subprogram(ev, p[1], "disorder-choose", (char *)0);
1794   choose_fd = p[0];
1795   xclose(p[1]);
1796   choose_callback = callback;
1797   choose_output.nvec = 0;
1798   choose_complete = 0;
1799   if(!ev_reader_new(ev, p[0], choose_readable, choose_read_error, 0,
1800                     "disorder-choose reader")) /* owns p[0] */
1801     fatal(0, "ev_reader_new for disorder-choose reader failed");
1802   ev_child(ev, choose_pid, 0, choose_exited, 0); /* owns the subprocess */
1803   return 0;
1804 }
1805
1806 /* get a track name given the prefs.  Set *used_db to 1 if we got the answer
1807  * from the prefs. */
1808 static const char *getpart(const char *track,
1809                            const char *context,
1810                            const char *part,
1811                            const struct kvp *p,
1812                            int *used_db) {
1813   const char *result;
1814   char *pref;
1815
1816   byte_xasprintf(&pref, "trackname_%s_%s", context, part);
1817   if((result = kvp_get(p, pref)))
1818     *used_db = 1;
1819   else
1820     result = trackname_part(track, context, part);
1821   assert(result != 0);
1822   return result;
1823 }
1824
1825 /* get a track name part, like trackname_part(), but taking the database into
1826  * account. */
1827 const char *trackdb_getpart(const char *track,
1828                             const char *context,
1829                             const char *part) {
1830   struct kvp *p;
1831   DB_TXN *tid;
1832   char *pref;
1833   const char *actual;
1834   int used_db, err;
1835
1836   /* construct the full pref */
1837   byte_xasprintf(&pref, "trackname_%s_%s", context, part);
1838   for(;;) {
1839     tid = trackdb_begin_transaction();
1840     if((err = gettrackdata(track, 0, &p, &actual, 0, tid)) == DB_LOCK_DEADLOCK)
1841       goto fail;
1842     break;
1843 fail:
1844     trackdb_abort_transaction(tid);
1845   }
1846   trackdb_commit_transaction(tid);
1847   return getpart(actual, context, part, p, &used_db);
1848 }
1849
1850 /* get the raw path name for @track@ (might be an alias) */
1851 const char *trackdb_rawpath(const char *track) {
1852   DB_TXN *tid;
1853   struct kvp *t;
1854   const char *path;
1855
1856   for(;;) {
1857     tid = trackdb_begin_transaction();
1858     if(gettrackdata(track, &t, 0, 0, 0, tid) == DB_LOCK_DEADLOCK)
1859       goto fail;
1860     break;
1861 fail:
1862     trackdb_abort_transaction(tid);
1863   }
1864   trackdb_commit_transaction(tid);
1865   if(!(path = kvp_get(t, "_path"))) path = track;
1866   return path;
1867 }
1868
1869 /* trackdb_list **************************************************************/
1870
1871 /* this is incredibly ugly, sorry, perhaps it will be rewritten to be actually
1872  * readable at some point */
1873
1874 /* return true if the basename of TRACK[0..TL-1], as defined by DL, matches RE.
1875  * If RE is a null pointer then it matches everything. */
1876 static int track_matches(size_t dl, const char *track, size_t tl,
1877                          const pcre *re) {
1878   int ovec[3], rc;
1879
1880   if(!re)
1881     return 1;
1882   track += dl + 1;
1883   tl -= (dl + 1);
1884   switch(rc = pcre_exec(re, 0, track, tl, 0, 0, ovec, 3)) {
1885   case PCRE_ERROR_NOMATCH: return 0;
1886   default:
1887     if(rc < 0) {
1888       error(0, "pcre_exec returned %d, subject '%s'", rc, track);
1889       return 0;
1890     }
1891     return 1;
1892   }
1893 }
1894
1895 static int do_list(struct vector *v, const char *dir,
1896                    enum trackdb_listable what, const pcre *re, DB_TXN *tid) {
1897   DBC *cursor;
1898   DBT k, d;
1899   size_t dl;
1900   char *ptr;
1901   int err;
1902   size_t l, last_dir_len = 0;
1903   char *last_dir = 0, *track;
1904   struct kvp *p;
1905
1906   dl = strlen(dir);
1907   cursor = trackdb_opencursor(trackdb_tracksdb, tid);
1908   make_key(&k, dir);
1909   prepare_data(&d);
1910   /* find the first key >= dir */
1911   err = cursor->c_get(cursor, &k, &d, DB_SET_RANGE);
1912   /* keep going while we're dealing with <dir/anything> */
1913   while(err == 0
1914         && k.size > dl
1915         && ((char *)k.data)[dl] == '/'
1916         && !memcmp(k.data, dir, dl)) {
1917     ptr = memchr((char *)k.data + dl + 1, '/', k.size - (dl + 1));
1918     if(ptr) {
1919       /* we have <dir/component/anything>, so <dir/component> is a directory */
1920       l = ptr - (char *)k.data;
1921       if(what & trackdb_directories)
1922         if(!(last_dir
1923              && l == last_dir_len
1924              && !memcmp(last_dir, k.data, l))) {
1925           last_dir = xstrndup(k.data, last_dir_len = l);
1926           if(track_matches(dl, k.data, l, re))
1927             vector_append(v, last_dir);
1928         }
1929     } else {
1930       /* found a plain file */
1931       if((what & trackdb_files)) {
1932         track = xstrndup(k.data, k.size);
1933         if((err = trackdb_getdata(trackdb_prefsdb,
1934                                   track, &p, tid)) == DB_LOCK_DEADLOCK)
1935           goto deadlocked;
1936         /* There's an awkward question here...
1937          *
1938          * If a track shares a directory with its alias then we could
1939          * do one of three things:
1940          * - report both.  Looks ridiculuous in most UIs.
1941          * - report just the alias.  Remarkably inconvenient to write
1942          *   UI code for!
1943          * - report just the real name.  Ugly if the UI doesn't prettify
1944          *   names via the name parts.
1945          */
1946 #if 1
1947         /* If this file is an alias for a track in the same directory then we
1948          * skip it */
1949         struct kvp *t = kvp_urldecode(d.data, d.size);
1950         const char *alias_target = kvp_get(t, "_alias_for");
1951         if(!(alias_target
1952              && !strcmp(d_dirname(alias_target),
1953                         d_dirname(track))))
1954           if(track_matches(dl, k.data, k.size, re))
1955             vector_append(v, track);
1956 #else
1957         /* if this file has an alias in the same directory then we skip it */
1958            char *alias;
1959         if((err = compute_alias(&alias, track, p, tid)))
1960           goto deadlocked;
1961         if(!(alias && !strcmp(d_dirname(alias), d_dirname(track))))
1962           if(track_matches(dl, k.data, k.size, re))
1963             vector_append(v, track);
1964 #endif
1965       }
1966     }
1967     err = cursor->c_get(cursor, &k, &d, DB_NEXT);
1968   }
1969   switch(err) {
1970   case 0:
1971     break;
1972   case DB_NOTFOUND:
1973     err = 0;
1974     break;
1975   case DB_LOCK_DEADLOCK:
1976     error(0, "error querying database: %s", db_strerror(err));
1977     break;
1978   default:
1979     fatal(0, "error querying database: %s", db_strerror(err));
1980   }
1981 deadlocked:
1982   if(trackdb_closecursor(cursor)) err = DB_LOCK_DEADLOCK;
1983   return err;
1984 }
1985
1986 /* return the directories or files below @dir@ */
1987 char **trackdb_list(const char *dir, int *np, enum trackdb_listable what,
1988                     const pcre *re) {
1989   DB_TXN *tid;
1990   int n;
1991   struct vector v;
1992
1993   vector_init(&v);
1994   for(;;) {
1995     tid = trackdb_begin_transaction();
1996     v.nvec = 0;
1997     if(dir) {
1998       if(do_list(&v, dir, what, re, tid))
1999         goto fail;
2000     } else {
2001       for(n = 0; n < config->collection.n; ++n)
2002         if(do_list(&v, config->collection.s[n].root, what, re, tid))
2003           goto fail;
2004     }
2005     break;
2006 fail:
2007     trackdb_abort_transaction(tid);
2008   }
2009   trackdb_commit_transaction(tid);
2010   vector_terminate(&v);
2011   if(np)
2012     *np = v.nvec;
2013   return v.vec;
2014 }
2015
2016 /* If S is tag:something, return something.  Else return 0. */
2017 static const char *checktag(const char *s) {
2018   if(!strncmp(s, "tag:", 4))
2019     return s + 4;
2020   else
2021     return 0;
2022 }
2023
2024 /* return a list of tracks containing all of the words given.  If you
2025  * ask for only stopwords you get no tracks. */
2026 char **trackdb_search(char **wordlist, int nwordlist, int *ntracks) {
2027   const char **w, *best = 0, *tag;
2028   char **twords, **tags;
2029   char *istag;
2030   int i, j, n, err, what;
2031   DBC *cursor = 0;
2032   DBT k, d;
2033   struct vector u, v;
2034   DB_TXN *tid;
2035   struct kvp *p;
2036   int ntags = 0;
2037   DB *db;
2038   const char *dbname;
2039
2040   *ntracks = 0;                         /* for early returns */
2041   /* normalize all the words */
2042   w = xmalloc(nwordlist * sizeof (char *));
2043   istag = xmalloc_noptr(nwordlist);
2044   for(n = 0; n < nwordlist; ++n) {
2045     uint32_t *w32;
2046     size_t nw32;
2047
2048     w[n] = utf8_casefold_compat(wordlist[n], strlen(wordlist[n]), 0);
2049     if(checktag(w[n])) {
2050       ++ntags;         /* count up tags */
2051       /* Normalize the tag */
2052       w[n] = normalize_tag(w[n] + 4, strlen(w[n] + 4));
2053       istag[n] = 1;
2054     } else {
2055       /* Normalize the search term by removing combining characters */
2056       if(!(w32 = utf8_to_utf32(w[n], strlen(w[n]), &nw32)))
2057         return 0;
2058       nw32 = remove_combining_chars(w32, nw32);
2059       if(!(w[n] = utf32_to_utf8(w32, nw32, 0)))
2060         return 0;
2061       istag[n] = 0;
2062     }
2063   }
2064   /* find the longest non-stopword */
2065   for(n = 0; n < nwordlist; ++n)
2066     if(!istag[n] && !stopword(w[n]))
2067       if(!best || strlen(w[n]) > strlen(best))
2068         best = w[n];
2069   /* TODO: we should at least in principal be able to identify the word or tag
2070    * with the least matches in log time, and choose that as our primary search
2071    * term. */
2072   if(ntags && !best) {
2073     /* Only tags are listed.  We limit to the first and narrow down with the
2074      * rest. */
2075     best = istag[0] ? w[0] : 0;
2076     db = trackdb_tagsdb;
2077     dbname = "tags";
2078   } else if(best) {
2079     /* We can limit to some word. */
2080     db = trackdb_searchdb;
2081     dbname = "search";
2082   } else {
2083     /* Only stopwords */
2084     return 0;
2085   }
2086   vector_init(&u);
2087   vector_init(&v);
2088   for(;;) {
2089     tid = trackdb_begin_transaction();
2090     /* find all the tracks that have that word */
2091     make_key(&k, best);
2092     prepare_data(&d);
2093     what = DB_SET;
2094     v.nvec = 0;
2095     cursor = trackdb_opencursor(db, tid);
2096     while(!(err = cursor->c_get(cursor, &k, &d, what))) {
2097       vector_append(&v, xstrndup(d.data, d.size));
2098       what = DB_NEXT_DUP;
2099     }
2100     switch(err) {
2101     case DB_NOTFOUND:
2102       err = 0;
2103       break;
2104     case DB_LOCK_DEADLOCK:
2105       error(0, "error querying %s database: %s", dbname, db_strerror(err));
2106       break;
2107     default:
2108       fatal(0, "error querying %s database: %s", dbname, db_strerror(err));
2109     }
2110     if(trackdb_closecursor(cursor)) err = DB_LOCK_DEADLOCK;
2111     cursor = 0;
2112     /* do a naive search over that (hopefuly fairly small) list of tracks */
2113     u.nvec = 0;
2114     for(n = 0; n < v.nvec; ++n) {
2115       if((err = gettrackdata(v.vec[n], 0, &p, 0, 0, tid) == DB_LOCK_DEADLOCK))
2116         goto fail;
2117       else if(err) {
2118         error(0, "track %s unexpected error: %s", v.vec[n], db_strerror(err));
2119         continue;
2120       }
2121       twords = track_to_words(v.vec[n], p);
2122       tags = parsetags(kvp_get(p, "tags"));
2123       for(i = 0; i < nwordlist; ++i) {
2124         if(istag[i]) {
2125           tag = w[i];
2126           /* Track must have this tag */
2127           for(j = 0; tags[j]; ++j)
2128             if(!strcmp(tag, tags[j])) break; /* tag found */
2129           if(!tags[j]) break;           /* tag not found */
2130         } else {
2131           /* Track must contain this word */
2132           for(j = 0; twords[j]; ++j)
2133             if(!strcmp(w[i], twords[j])) break; /* word found */
2134           if(!twords[j]) break;         /* word not found */
2135         }
2136       }
2137       if(i >= nwordlist)                /* all words found */
2138         vector_append(&u, v.vec[n]);
2139     }
2140     break;
2141   fail:
2142     trackdb_closecursor(cursor);
2143     cursor = 0;
2144     trackdb_abort_transaction(tid);
2145     info("retrying search");
2146   }
2147   trackdb_commit_transaction(tid);
2148   vector_terminate(&u);
2149   if(ntracks)
2150     *ntracks = u.nvec;
2151   return u.vec;
2152 }
2153
2154 /* trackdb_scan **************************************************************/
2155
2156 int trackdb_scan(const char *root,
2157                  int (*callback)(const char *track,
2158                                  struct kvp *data,
2159                                  struct kvp *prefs,
2160                                  void *u,
2161                                  DB_TXN *tid),
2162                  void *u,
2163                  DB_TXN *tid) {
2164   DBC *cursor;
2165   DBT k, d, pd;
2166   const size_t root_len = root ? strlen(root) : 0;
2167   int err, cberr;
2168   struct kvp *data, *prefs;
2169   const char *track;
2170
2171   cursor = trackdb_opencursor(trackdb_tracksdb, tid);
2172   if(root)
2173     err = cursor->c_get(cursor, make_key(&k, root), prepare_data(&d),
2174                         DB_SET_RANGE);
2175   else {
2176     memset(&k, 0, sizeof k);
2177     err = cursor->c_get(cursor, &k, prepare_data(&d),
2178                         DB_FIRST);
2179   }
2180   while(!err) {
2181     if(!root
2182        || (k.size > root_len
2183            && !strncmp(k.data, root, root_len)
2184            && ((char *)k.data)[root_len] == '/')) {
2185       data = kvp_urldecode(d.data, d.size);
2186       if(kvp_get(data, "_path")) {
2187         track = xstrndup(k.data, k.size);
2188         /* TODO: trackdb_prefsdb is currently a DB_HASH.  This means we have to
2189          * do a lookup for every single track.  In fact this is quite quick:
2190          * with around 10,000 tracks a complete scan is around 0.3s on my
2191          * 2.2GHz Athlon.  However, if it were a DB_BTREE, we could do the same
2192          * linear walk as we already do over trackdb_tracksdb, and probably get
2193          * even higher performance.  That would require upgrade logic to
2194          * translate old databases though.
2195          */
2196         switch(err = trackdb_prefsdb->get(trackdb_prefsdb, tid, &k,
2197                                           prepare_data(&pd), 0)) {
2198         case 0:
2199           prefs = kvp_urldecode(pd.data, pd.size);
2200           break;
2201         case DB_NOTFOUND:
2202           prefs = 0;
2203           break;
2204         case DB_LOCK_DEADLOCK:
2205           error(0, "getting prefs: %s", db_strerror(err));
2206           trackdb_closecursor(cursor);
2207           return err;
2208         default:
2209           fatal(0, "getting prefs: %s", db_strerror(err));
2210         }
2211         /* Advance to the next track before the callback so that the callback
2212          * may safely delete the track */
2213         err = cursor->c_get(cursor, &k, &d, DB_NEXT);
2214         if((cberr = callback(track, data, prefs, u, tid))) {
2215           err = cberr;
2216           break;
2217         }
2218       } else
2219         err = cursor->c_get(cursor, &k, &d, DB_NEXT);
2220     } else
2221       break;
2222   }
2223   trackdb_closecursor(cursor);
2224   switch(err) {
2225   case EINTR:
2226     return err;
2227   case 0:
2228   case DB_NOTFOUND:
2229     return 0;
2230   case DB_LOCK_DEADLOCK:
2231     error(0, "c->c_get: %s", db_strerror(err));
2232     return err;
2233   default:
2234     fatal(0, "c->c_get: %s", db_strerror(err));
2235   }
2236 }
2237
2238 /* trackdb_rescan ************************************************************/
2239
2240 /** @brief Node in the list of rescan-complete callbacks */
2241 struct rescanned_node {
2242   struct rescanned_node *next;
2243   void (*rescanned)(void *ru);
2244   void *ru;
2245 };
2246
2247 /** @brief List of rescan-complete callbacks */
2248 static struct rescanned_node *rescanned_list;
2249
2250 /** @brief Add a rescan completion callback */
2251 void trackdb_add_rescanned(void (*rescanned)(void *ru),
2252                            void *ru) {
2253   if(rescanned) {
2254     struct rescanned_node *n = xmalloc(sizeof *n);
2255     n->next = rescanned_list;
2256     n->rescanned = rescanned;
2257     n->ru = ru;
2258     rescanned_list = n;
2259   }
2260 }
2261
2262 /* called when the rescanner terminates */
2263 static int reap_rescan(ev_source attribute((unused)) *ev,
2264                        pid_t pid,
2265                        int status,
2266                        const struct rusage attribute((unused)) *rusage,
2267                        void attribute((unused)) *u) {
2268   if(pid == rescan_pid) rescan_pid = -1;
2269   if(status)
2270     error(0, RESCAN": %s", wstat(status));
2271   else
2272     D((RESCAN" terminated: %s", wstat(status)));
2273   /* Our cache of file lookups is out of date now */
2274   cache_clean(&cache_files_type);
2275   eventlog("rescanned", (char *)0);
2276   /* Call rescanned callbacks */
2277   while(rescanned_list) {
2278     void (*rescanned)(void *u_) = rescanned_list->rescanned;
2279     void *ru = rescanned_list->ru;
2280
2281     rescanned_list = rescanned_list->next;
2282     rescanned(ru);
2283   }
2284   return 0;
2285 }
2286
2287 /** @brief Initiate a rescan
2288  * @param ev Event loop or 0 to block
2289  * @param recheck 1 to recheck lengths, 0 to suppress check
2290  * @param rescanned Called on completion (if not NULL)
2291  * @param ru Passed to @p rescanned
2292  */
2293 void trackdb_rescan(ev_source *ev, int recheck,
2294                     void (*rescanned)(void *ru),
2295                     void *ru) {
2296   int w;
2297
2298   if(rescan_pid != -1) {
2299     trackdb_add_rescanned(rescanned, ru);
2300     error(0, "rescan already underway");
2301     return;
2302   }
2303   rescan_pid = subprogram(ev, -1, RESCAN,
2304                           recheck ? "--check" : "--no-check",
2305                           (char *)0);
2306   trackdb_add_rescanned(rescanned, ru);
2307   if(ev) {
2308     ev_child(ev, rescan_pid, 0, reap_rescan, 0);
2309     D(("started rescanner"));
2310   } else {
2311     /* This is the first rescan, we block until it is complete */
2312     while(waitpid(rescan_pid, &w, 0) < 0 && errno == EINTR)
2313       ;
2314     reap_rescan(0, rescan_pid, w, 0, 0);
2315   }
2316 }
2317
2318 int trackdb_rescan_cancel(void) {
2319   if(rescan_pid == -1) return 0;
2320   if(kill(rescan_pid, SIGTERM) < 0)
2321     fatal(errno, "error killing rescanner");
2322   rescan_pid = -1;
2323   return 1;
2324 }
2325
2326 /** @brief Return true if a rescan is underway */
2327 int trackdb_rescan_underway(void) {
2328   return rescan_pid != -1;
2329 }
2330
2331 /* global prefs **************************************************************/
2332
2333 void trackdb_set_global(const char *name,
2334                         const char *value,
2335                         const char *who) {
2336   DB_TXN *tid;
2337   int err;
2338   int state;
2339
2340   for(;;) {
2341     tid = trackdb_begin_transaction();
2342     if(!(err = trackdb_set_global_tid(name, value, tid)))
2343       break;
2344     trackdb_abort_transaction(tid);
2345   }
2346   trackdb_commit_transaction(tid);
2347   /* log important state changes */
2348   if(!strcmp(name, "playing")) {
2349     state = !value || !strcmp(value, "yes");
2350     info("playing %s by %s",
2351          state ? "enabled" : "disabled",
2352          who ? who : "-");
2353     eventlog("state", state ? "enable_play" : "disable_play", (char *)0);
2354   }
2355   if(!strcmp(name, "random-play")) {
2356     state = !value || !strcmp(value, "yes");
2357     info("random play %s by %s",
2358          state ? "enabled" : "disabled",
2359          who ? who : "-");
2360     eventlog("state", state ? "enable_random" : "disable_random", (char *)0);
2361   }
2362 }
2363
2364 int trackdb_set_global_tid(const char *name,
2365                            const char *value,
2366                            DB_TXN *tid) {
2367   DBT k, d;
2368   int err;
2369
2370   memset(&k, 0, sizeof k);
2371   memset(&d, 0, sizeof d);
2372   k.data = (void *)name;
2373   k.size = strlen(name);
2374   if(value) {
2375     d.data = (void *)value;
2376     d.size = strlen(value);
2377   }
2378   if(value)
2379     err = trackdb_globaldb->put(trackdb_globaldb, tid, &k, &d, 0);
2380   else
2381     err = trackdb_globaldb->del(trackdb_globaldb, tid, &k, 0);
2382   if(err == DB_LOCK_DEADLOCK) return err;
2383   if(err)
2384     fatal(0, "error updating database: %s", db_strerror(err));
2385   return 0;
2386 }
2387
2388 const char *trackdb_get_global(const char *name) {
2389   DB_TXN *tid;
2390   int err;
2391   const char *r;
2392
2393   for(;;) {
2394     tid = trackdb_begin_transaction();
2395     if(!(err = trackdb_get_global_tid(name, tid, &r)))
2396       break;
2397     trackdb_abort_transaction(tid);
2398   }
2399   trackdb_commit_transaction(tid);
2400   return r;
2401 }
2402
2403 int trackdb_get_global_tid(const char *name,
2404                            DB_TXN *tid,
2405                            const char **rp) {
2406   DBT k, d;
2407   int err;
2408
2409   memset(&k, 0, sizeof k);
2410   k.data = (void *)name;
2411   k.size = strlen(name);
2412   switch(err = trackdb_globaldb->get(trackdb_globaldb, tid, &k,
2413                                      prepare_data(&d), 0)) {
2414   case 0:
2415     *rp = xstrndup(d.data, d.size);
2416     return 0;
2417   case DB_NOTFOUND:
2418     *rp = 0;
2419     return 0;
2420   case DB_LOCK_DEADLOCK:
2421     return err;
2422   default:
2423     fatal(0, "error reading database: %s", db_strerror(err));
2424   }
2425 }
2426
2427 /** @brief Retrieve the most recently added tracks
2428  * @param ntracksp Where to put count, or 0
2429  * @param maxtracks Maximum number of tracks to retrieve
2430  * @return null-terminated array of track names
2431  *
2432  * The most recently added track is first in the array.
2433  */
2434 char **trackdb_new(int *ntracksp,
2435                    int maxtracks) {
2436   DB_TXN *tid;
2437   char **tracks;
2438
2439   for(;;) {
2440     tid = trackdb_begin_transaction();
2441     tracks = trackdb_new_tid(ntracksp, maxtracks, tid);
2442     if(tracks)
2443       break;
2444     trackdb_abort_transaction(tid);
2445   }
2446   trackdb_commit_transaction(tid);
2447   return tracks;
2448 }
2449
2450 /** @brief Retrieve the most recently added tracks
2451  * @param ntracksp Where to put count, or 0
2452  * @param maxtracks Maximum number of tracks to retrieve, or 0 for all
2453  * @param tid Transaction ID
2454  * @return null-terminated array of track names, or NULL on deadlock
2455  *
2456  * The most recently added track is first in the array.
2457  */
2458 static char **trackdb_new_tid(int *ntracksp,
2459                               int maxtracks,
2460                               DB_TXN *tid) {
2461   DBC *c;
2462   DBT k, d;
2463   int err = 0;
2464   struct vector tracks[1];
2465   hash *h = hash_new(1);
2466
2467   vector_init(tracks);
2468   c = trackdb_opencursor(trackdb_noticeddb, tid);
2469   while((maxtracks <= 0 || tracks->nvec < maxtracks)
2470         && !(err = c->c_get(c, prepare_data(&k), prepare_data(&d), DB_PREV))) {
2471     char *const track = xstrndup(d.data, d.size);
2472     /* Don't add any track more than once */
2473     if(hash_add(h, track, "", HASH_INSERT))
2474       continue;
2475     /* See if the track still exists */
2476     err = trackdb_getdata(trackdb_tracksdb, track, NULL/*kp*/, tid);
2477     if(err == DB_NOTFOUND)
2478       continue;                         /* It doesn't, skip it */
2479     if(err == DB_LOCK_DEADLOCK)
2480       break;                            /* Doh */
2481     vector_append(tracks, track);
2482   }
2483   switch(err) {
2484   case 0:                               /* hit maxtracks */
2485   case DB_NOTFOUND:                     /* ran out of tracks */
2486     break;
2487   case DB_LOCK_DEADLOCK:
2488     trackdb_closecursor(c);
2489     return 0;
2490   default:
2491     fatal(0, "error reading noticed.db: %s", db_strerror(err));
2492   }
2493   if((err = trackdb_closecursor(c)))
2494     return 0;                           /* deadlock */
2495   vector_terminate(tracks);
2496   if(ntracksp)
2497     *ntracksp = tracks->nvec;
2498   return tracks->vec;
2499 }
2500
2501 /** @brief Expire noticed.db
2502  * @param earliest Earliest timestamp to keep
2503  */
2504 void trackdb_expire_noticed(time_t earliest) {
2505   DB_TXN *tid;
2506
2507   for(;;) {
2508     tid = trackdb_begin_transaction();
2509     if(!trackdb_expire_noticed_tid(earliest, tid))
2510       break;
2511     trackdb_abort_transaction(tid);
2512   }
2513   trackdb_commit_transaction(tid);
2514 }
2515
2516 /** @brief Expire noticed.db
2517  * @param earliest Earliest timestamp to keep
2518  * @param tid Transaction ID
2519  * @return 0 or DB_LOCK_DEADLOCK
2520  */
2521 static int trackdb_expire_noticed_tid(time_t earliest, DB_TXN *tid) {
2522   DBC *c;
2523   DBT k, d;
2524   int err = 0, ret;
2525   time_t when;
2526   uint32_t *kk;
2527   int count = 0;
2528
2529   c = trackdb_opencursor(trackdb_noticeddb, tid);
2530   while(!(err = c->c_get(c, prepare_data(&k), prepare_data(&d), DB_NEXT))) {
2531     kk = k.data;
2532     when = (time_t)(((uint64_t)ntohl(kk[0]) << 32) + ntohl(kk[1]));
2533     if(when >= earliest)
2534       break;
2535     if((err = c->c_del(c, 0))) {
2536       if(err != DB_LOCK_DEADLOCK)
2537         fatal(0, "error deleting expired noticed.db entry: %s",
2538               db_strerror(err));
2539       break;
2540     }
2541     ++count;
2542   }
2543   if(err == DB_NOTFOUND)
2544     err = 0;
2545   if(err && err != DB_LOCK_DEADLOCK)
2546     fatal(0, "error expiring noticed.db: %s", db_strerror(err));
2547   ret = err;
2548   if((err = trackdb_closecursor(c))) {
2549     if(err != DB_LOCK_DEADLOCK)
2550       fatal(0, "error closing cursor: %s", db_strerror(err));
2551     ret = err;
2552   }
2553   if(!ret && count)
2554     info("expired %d tracks from noticed.db", count);
2555   return ret;
2556 }
2557
2558 /* tidying up ****************************************************************/
2559
2560 void trackdb_gc(void) {
2561   int err;
2562   char **logfiles;
2563
2564   if((err = trackdb_env->txn_checkpoint(trackdb_env,
2565                                         config->checkpoint_kbyte,
2566                                         config->checkpoint_min,
2567                                         0)))
2568     fatal(0, "trackdb_env->txn_checkpoint: %s", db_strerror(err));
2569   if((err = trackdb_env->log_archive(trackdb_env, &logfiles, DB_ARCH_REMOVE)))
2570     fatal(0, "trackdb_env->log_archive: %s", db_strerror(err));
2571   /* This makes catastrophic recovery impossible.  However, the user can still
2572    * preserve the important data by using disorder-dump to snapshot their
2573    * prefs, and later to restore it.  This is likely to have much small
2574    * long-term storage requirements than record the db logfiles. */
2575 }
2576
2577 /* user database *************************************************************/
2578
2579 /** @brief Return true if @p user is trusted */
2580 static int trusted(const char *user) {
2581   int n;
2582
2583   for(n = 0; (n < config->trust.n
2584               && strcmp(config->trust.s[n], user)); ++n)
2585     ;
2586   return n < config->trust.n;
2587 }
2588
2589 /** @brief Return non-zero for a valid username
2590  *
2591  * Currently we only allow the letters and digits in ASCII.  We could be more
2592  * liberal than this but it is a nice simple test.  It is critical that
2593  * semicolons are never allowed.
2594  *
2595  * NB also used by playlist_parse_name() to validate playlist names!
2596  */
2597 int valid_username(const char *user) {
2598   if(!*user)
2599     return 0;
2600   while(*user) {
2601     const uint8_t c = *user++;
2602     /* For now we are very strict */
2603     if((c >= 'a' && c <= 'z')
2604        || (c >= 'A' && c <= 'Z')
2605        || (c >= '0' && c <= '9'))
2606       /* ok */;
2607     else
2608       return 0;
2609   }
2610   return 1;
2611 }
2612
2613 /** @brief Add a user */
2614 static int create_user(const char *user,
2615                        const char *password,
2616                        const char *rights,
2617                        const char *email,
2618                        const char *confirmation,
2619                        DB_TXN *tid,
2620                        uint32_t flags) {
2621   struct kvp *k = 0;
2622   char s[64];
2623
2624   /* sanity check user */
2625   if(!valid_username(user)) {
2626     error(0, "invalid username '%s'", user);
2627     return -1;
2628   }
2629   if(parse_rights(rights, 0, 1)) {
2630     error(0, "invalid rights string");
2631     return -1;
2632   }
2633   /* data for this user */
2634   if(password)
2635     kvp_set(&k, "password", password);
2636   kvp_set(&k, "rights", rights);
2637   if(email)
2638     kvp_set(&k, "email", email);
2639   if(confirmation)
2640     kvp_set(&k, "confirmation", confirmation);
2641   snprintf(s, sizeof s, "%jd", (intmax_t)xtime(0));
2642   kvp_set(&k, "created", s);
2643   return trackdb_putdata(trackdb_usersdb, user, k, tid, flags);
2644 }
2645
2646 /** @brief Add one pre-existing user */
2647 static int one_old_user(const char *user, const char *password,
2648                         DB_TXN *tid) {
2649   const char *rights;
2650
2651   /* www-data doesn't get added */
2652   if(!strcmp(user, "www-data")) {
2653     info("not adding www-data to user database");
2654     return 0;
2655   }
2656   /* pick rights */
2657   if(!strcmp(user, "root"))
2658     rights = "all";
2659   else if(trusted(user)) {
2660     rights_type r;
2661
2662     parse_rights(config->default_rights, &r, 1);
2663     r &= ~(rights_type)(RIGHT_SCRATCH__MASK|RIGHT_MOVE__MASK|RIGHT_REMOVE__MASK);
2664     r |= (RIGHT_ADMIN|RIGHT_RESCAN
2665           |RIGHT_SCRATCH_ANY|RIGHT_MOVE_ANY|RIGHT_REMOVE_ANY);
2666     rights = rights_string(r);
2667   } else
2668     rights = config->default_rights;
2669   return create_user(user, password, rights, 0/*email*/, 0/*confirmation*/,
2670                      tid, DB_NOOVERWRITE);
2671 }
2672
2673 static int trackdb_old_users_tid(DB_TXN *tid) {
2674   int n;
2675
2676   for(n = 0; n < config->allow.n; ++n) {
2677     switch(one_old_user(config->allow.s[n].s[0], config->allow.s[n].s[1],
2678                         tid)) {
2679     case 0:
2680       info("created user %s from 'allow' directive", config->allow.s[n].s[0]);
2681       break;
2682     case DB_KEYEXIST:
2683       error(0, "user %s already exists, delete 'allow' directive",
2684             config->allow.s[n].s[0]);
2685           /* This won't ever become fatal - eventually 'allow' will be
2686            * disabled. */
2687       break;
2688     case DB_LOCK_DEADLOCK:
2689       return DB_LOCK_DEADLOCK;
2690     }
2691   }
2692   return 0;
2693 }
2694
2695 /** @brief Read old 'allow' directives and copy them to the users database */
2696 void trackdb_old_users(void) {
2697   int e;
2698
2699   if(config->allow.n)
2700     WITH_TRANSACTION(trackdb_old_users_tid(tid));
2701 }
2702
2703 /** @brief Create a root user in the user database if there is none */
2704 void trackdb_create_root(void) {
2705   int e;
2706   uint8_t pwbin[12];
2707   char *pw;
2708
2709   /* Choose a new root password */
2710   gcry_randomize(pwbin, sizeof pwbin, GCRY_STRONG_RANDOM);
2711   pw = mime_to_base64(pwbin, sizeof pwbin);
2712   /* Create the root user if it does not exist */
2713   WITH_TRANSACTION(create_user("root", pw, "all",
2714                                0/*email*/, 0/*confirmation*/,
2715                                tid, DB_NOOVERWRITE));
2716   if(e == 0)
2717     info("created root user");
2718 }
2719
2720 /** @brief Find a user's password from the database
2721  * @param user Username
2722  * @return Password or NULL
2723  *
2724  * Only works if running as a user that can read the database!
2725  *
2726  * If the user exists but has no password, "" is returned.
2727  */
2728 const char *trackdb_get_password(const char *user) {
2729   int e;
2730   struct kvp *k;
2731   const char *password;
2732
2733   WITH_TRANSACTION(trackdb_getdata(trackdb_usersdb, user, &k, tid));
2734   if(e)
2735     return 0;
2736   password = kvp_get(k, "password");
2737   return password ? password : "";
2738 }
2739
2740 /** @brief Add a new user
2741  * @param user Username
2742  * @param password Password or NULL
2743  * @param rights Initial rights
2744  * @param email Email address or NULL
2745  * @param confirmation Confirmation string or NULL
2746  * @return 0 on success, non-0 on error
2747  */
2748 int trackdb_adduser(const char *user,
2749                     const char *password,
2750                     const char *rights,
2751                     const char *email,
2752                     const char *confirmation) {
2753   int e;
2754
2755   WITH_TRANSACTION(create_user(user, password, rights, email, confirmation,
2756                                tid, DB_NOOVERWRITE));
2757   if(e) {
2758     error(0, "cannot create user '%s' because they already exist", user);
2759     return -1;
2760   } else {
2761     if(email)
2762       info("created user '%s' with rights '%s' and email address '%s'",
2763            user, rights, email);
2764     else
2765       info("created user '%s' with rights '%s'", user, rights);
2766     eventlog("user_add", user, (char *)0);
2767     return 0;
2768   }
2769 }
2770
2771 /** @brief Delete a user
2772  * @param user User to delete
2773  * @return 0 on success, non-0 if the user didn't exist anyway
2774  */
2775 int trackdb_deluser(const char *user) {
2776   int e;
2777
2778   WITH_TRANSACTION(trackdb_delkey(trackdb_usersdb, user, tid));
2779   if(e) {
2780     error(0, "cannot delete user '%s' because they do not exist", user);
2781     return -1;
2782   }
2783   info("deleted user '%s'", user);
2784   eventlog("user_delete", user, (char *)0);
2785   return 0;
2786 }
2787
2788 /** @brief Get user information
2789  * @param user User to query
2790  * @return Linked list of user information or NULL if user does not exist
2791  *
2792  * Every user has at least a @c rights entry so NULL can be used to mean no
2793  * such user safely.
2794  */
2795 struct kvp *trackdb_getuserinfo(const char *user) {
2796   int e;
2797   struct kvp *k;
2798
2799   WITH_TRANSACTION(trackdb_getdata(trackdb_usersdb, user, &k, tid));
2800   if(e)
2801     return 0;
2802   else
2803     return k;
2804 }
2805
2806 /** @brief Edit user information
2807  * @param user User to edit
2808  * @param key Key to change
2809  * @param value Value to set, or NULL to remove
2810  * @param tid Transaction ID
2811  * @return 0, DB_LOCK_DEADLOCK or DB_NOTFOUND
2812  */
2813 static int trackdb_edituserinfo_tid(const char *user, const char *key,
2814                                     const char *value, DB_TXN *tid) {
2815   struct kvp *k;
2816   int e;
2817
2818   if((e = trackdb_getdata(trackdb_usersdb, user, &k, tid)))
2819     return e;
2820   if(!kvp_set(&k, key, value))
2821     return 0;                           /* no change */
2822   return trackdb_putdata(trackdb_usersdb, user, k, tid, 0);
2823 }
2824
2825 /** @brief Edit user information
2826  * @param user User to edit
2827  * @param key Key to change
2828  * @param value Value to set, or NULL to remove
2829  * @return 0 on success, non-0 on error
2830  */
2831 int trackdb_edituserinfo(const char *user,
2832                          const char *key, const char *value) {
2833   int e;
2834
2835   if(!strcmp(key, "rights")) {
2836     if(!value) {
2837       error(0, "cannot remove 'rights' key from user '%s'", user);
2838       return -1;
2839     }
2840     if(parse_rights(value, 0, 1)) {
2841       error(0, "invalid rights string");
2842       return -1;
2843     }
2844   } else if(!strcmp(key, "email")) {
2845     if(*value) {
2846       if(!email_valid(value)) {
2847         error(0, "invalid email address '%s' for user '%s'", value, user);
2848         return -1;
2849       }
2850     } else
2851       value = 0;                        /* no email -> remove key */
2852   } else if(!strcmp(key, "created")) {
2853     error(0, "cannot change creation date for user '%s'", user);
2854     return -1;
2855   } else if(strcmp(key, "password")
2856             && !strcmp(key, "confirmation")) {
2857     error(0, "unknown user info key '%s' for user '%s'", key, user);
2858     return -1;
2859   }
2860   WITH_TRANSACTION(trackdb_edituserinfo_tid(user, key, value, tid));
2861   if(e) {
2862     error(0, "unknown user '%s'", user);
2863     return -1;
2864   } else {
2865     eventlog("user_edit", user, key, (char *)0);
2866     return 0;
2867   }
2868 }
2869
2870 /** @brief List all users
2871  * @return NULL-terminated list of users
2872  */
2873 char **trackdb_listusers(void) {
2874   int e;
2875   struct vector v[1];
2876
2877   vector_init(v);
2878   WITH_TRANSACTION(trackdb_listkeys(trackdb_usersdb, v, tid));
2879   return v->vec;
2880 }
2881
2882 /** @brief Confirm a user registration
2883  * @param user Username
2884  * @param confirmation Confirmation string
2885  * @param rightsp Where to put user rights
2886  * @param tid Transaction ID
2887  * @return 0 on success, non-0 on error
2888  */
2889 static int trackdb_confirm_tid(const char *user, const char *confirmation,
2890                                rights_type *rightsp,
2891                                DB_TXN *tid) {
2892   const char *stored_confirmation;
2893   struct kvp *k;
2894   int e;
2895   const char *rights;
2896   
2897   if((e = trackdb_getdata(trackdb_usersdb, user, &k, tid)))
2898     return e;
2899   if(!(stored_confirmation = kvp_get(k, "confirmation"))) {
2900     error(0, "already confirmed user '%s'", user);
2901     /* DB claims -30,800 to -30,999 so -1 should be a safe bet */
2902     return -1;
2903   }
2904   if(!(rights = kvp_get(k, "rights"))) {
2905     error(0, "no rights for unconfirmed user '%s'", user);
2906     return -1;
2907   }
2908   if(parse_rights(rights, rightsp, 1))
2909     return -1;
2910   if(strcmp(confirmation, stored_confirmation)) {
2911     error(0, "wrong confirmation string for user '%s'", user);
2912     return -1;
2913   }
2914   /* 'sall good */
2915   kvp_set(&k, "confirmation", 0);
2916   return trackdb_putdata(trackdb_usersdb, user, k, tid, 0);
2917 }
2918
2919 /** @brief Confirm a user registration
2920  * @param user Username
2921  * @param confirmation Confirmation string
2922  * @param rightsp Where to put user rights
2923  * @return 0 on success, non-0 on error
2924  */
2925 int trackdb_confirm(const char *user, const char *confirmation,
2926                     rights_type *rightsp) {
2927   int e;
2928
2929   WITH_TRANSACTION(trackdb_confirm_tid(user, confirmation, rightsp, tid));
2930   switch(e) {
2931   case 0:
2932     info("registration confirmed for user '%s'", user);
2933     eventlog("user_confirm", user, (char *)0);
2934     return 0;
2935   case DB_NOTFOUND:
2936     error(0, "confirmation for nonexistent user '%s'", user);
2937     return -1;
2938   default:                              /* already reported */
2939     return -1;
2940   }
2941 }
2942
2943 /*
2944 Local Variables:
2945 c-basic-offset:2
2946 comment-column:40
2947 fill-column:79
2948 indent-tabs-mode:nil
2949 End:
2950 */