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