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