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