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