com_ls: Don't use FNM_PATHNAME.
[paraslash.git] / afs.c
1 /*
2  * Copyright (C) 2007 Andre Noll <maan@systemlinux.org>
3  *
4  * Licensed under the GPL v2. For licencing details see COPYING.
5  */
6
7 /** \file afs.c Paraslash's audio file selector. */
8
9 #include <fnmatch.h>
10 #include "server.cmdline.h"
11 #include "para.h"
12 #include "afh.h"
13 #include "server.h"
14 #include "error.h"
15 #include <dirent.h> /* readdir() */
16 #include <sys/mman.h>
17 #include <sys/time.h>
18 #include "net.h"
19 #include "afs.h"
20 #include "ipc.h"
21 #include "string.h"
22 #include "list.h"
23 #include "sched.h"
24 #include "signal.h"
25 #include "fd.h"
26
27 /** The osl tables used by afs. \sa blob.c. */
28 enum afs_table_num {
29         /** Contains audio file information. See aft.c. */
30         TBLNUM_AUDIO_FILES,
31         /** The table for the paraslash attributes. See attribute.c. */
32         TBLNUM_ATTRIBUTES,
33         /**
34          * Paraslash's scoring system is based on Gaussian normal
35          * distributions, and the relevant data is stored in the rbtrees of an
36          * osl table containing only volatile columns.  See score.c for
37          * details.
38          */
39         TBLNUM_SCORES,
40         /**
41          * A standard blob table containing the mood definitions. For details
42          * see mood.c.
43          */
44         TBLNUM_MOODS,
45         /** A blob table containing lyrics on a per-song basis. */
46         TBLNUM_LYRICS,
47         /** Another blob table for images (for example album cover art). */
48         TBLNUM_IMAGES,
49         /** Yet another blob table for storing standard playlists. */
50         TBLNUM_PLAYLIST,
51         /** How many tables are in use? */
52         NUM_AFS_TABLES
53 };
54
55 static struct table_info afs_tables[NUM_AFS_TABLES];
56
57 struct command_task {
58         /** The file descriptor for the local socket. */
59         int fd;
60         /**
61          * Value sent by the command handlers to identify themselves as
62          * children of the running para_server.
63          */
64         uint32_t cookie;
65         /** The associated task structure. */
66         struct task task;
67 };
68
69 /**
70  * A random number used to "authenticate" the connection.
71  *
72  * para_server picks this number by random before forking the afs process.  The
73  * command handlers write this number together with the id of the shared memory
74  * area containing the query. This way, a malicious local user has to know this
75  * number to be able to cause the afs process to crash by sending fake queries.
76  */
77 extern uint32_t afs_socket_cookie;
78
79 /**
80  * Struct to let command handlers execute a callback in afs context.
81  *
82  * Commands that need to change the state of afs can't change the relevant data
83  * structures directly because commands are executed in a child process, i.e.
84  * they get their own virtual address space.
85  *
86  * This structure is used by \p send_callback_request() (executed from handler
87  * context) in order to let the afs process call the specified function. An
88  * instance of that structure is written to a shared memory area together with
89  * the arguments to the callback function. The identifier of the shared memory
90  * area is written to the command socket.
91  *
92  * The afs process accepts connections on the command socket and reads the
93  * shared memory id, attaches the corresponing area, calls the given handler to
94  * perform the desired action and to optionally compute a result.
95  *
96  * The result and a \p callback_result structure is then written to another
97  * shared memory area. The identifier for that area is written to the handler's
98  * command socket, so that the handler process can read the id, attach the
99  * shared memory area and use the result.
100  *
101  * \sa struct callback_result.
102  */
103 struct callback_query {
104         /** The function to be called. */
105         callback_function *handler;
106         /** The number of bytes of the query */
107         size_t query_size;
108 };
109
110 /**
111  * Structure embedded in the result of a callback.
112  *
113  * If the callback produced a result, an instance of that structure is embeeded
114  * into the shared memory area holding the result, mainly to let the command
115  * handler know the size of the result.
116  *
117  * \sa struct callback_query.
118  */
119 struct callback_result {
120         /** The number of bytes of the result. */
121         size_t result_size;
122 };
123
124 /**
125  * Ask the parent process to call a given function.
126  *
127  * \param f The function to be called.
128  * \param query Pointer to arbitrary data for the callback.
129  * \param result Callback result will be stored here.
130  *
131  * This function creates a shared memory area, copies the buffer pointed to by
132  * \a buf to that area and notifies the afs process that \a f should be
133  * called ASAP.
134  *
135  * \return Negative, on errors, the return value of the callback function
136  * otherwise.
137  *
138  * \sa send_option_arg_callback_request(), send_standard_callback_request().
139  */
140 int send_callback_request(callback_function *f, struct osl_object *query,
141                 struct osl_object *result)
142 {
143         struct callback_query *cq;
144         struct callback_result *cr;
145         int ret, fd = -1, query_shmid, result_shmid;
146         void *query_shm, *result_shm;
147         char buf[sizeof(afs_socket_cookie) + sizeof(int)];
148         struct sockaddr_un unix_addr;
149         size_t query_shm_size = sizeof(*cq);
150
151         if (query)
152                 query_shm_size += query->size;
153         ret = shm_new(query_shm_size);
154         if (ret < 0)
155                 return ret;
156         query_shmid = ret;
157         ret = shm_attach(query_shmid, ATTACH_RW, &query_shm);
158         if (ret < 0)
159                 goto out;
160         cq = query_shm;
161         cq->handler = f;
162         cq->query_size = query_shm_size - sizeof(*cq);
163
164         if (query)
165                 memcpy(query_shm + sizeof(*cq), query->data, query->size);
166         ret = shm_detach(query_shm);
167         if (ret < 0)
168                 goto out;
169
170         *(uint32_t *) buf = afs_socket_cookie;
171         *(int *) (buf + sizeof(afs_socket_cookie)) = query_shmid;
172
173         ret = get_stream_socket(PF_UNIX);
174         if (ret < 0)
175                 goto out;
176         fd = ret;
177         ret = init_unix_addr(&unix_addr, conf.afs_socket_arg);
178         if (ret < 0)
179                 goto out;
180         ret = PARA_CONNECT(fd, &unix_addr);
181         if (ret < 0)
182                 goto out;
183         ret = send_bin_buffer(fd, buf, sizeof(buf));
184         if (ret < 0)
185                 goto out;
186         ret = recv_bin_buffer(fd, buf, sizeof(buf));
187         if (ret < 0)
188                 goto out;
189         if (ret != sizeof(int)) {
190                 ret = -E_RECV;
191                 goto out;
192         }
193         ret = *(int *) buf;
194         if (ret <= 0)
195                 goto out;
196         result_shmid = ret;
197         ret = shm_attach(result_shmid, ATTACH_RO, &result_shm);
198         if (ret >= 0) {
199                 assert(result);
200                 cr = result_shm;
201                 result->size = cr->result_size;
202                 result->data = para_malloc(result->size);
203                 memcpy(result->data, result_shm + sizeof(*cr), result->size);
204                 ret = shm_detach(result_shm);
205                 if (ret < 0)
206                         PARA_ERROR_LOG("can not detach result\n");
207         } else
208                 PARA_ERROR_LOG("attach result failed: %d\n", ret);
209         if (shm_destroy(result_shmid) < 0)
210                 PARA_ERROR_LOG("destroy result failed\n");
211         ret = 1;
212 out:
213         if (shm_destroy(query_shmid) < 0)
214                 PARA_ERROR_LOG("%s\n", "shm destroy error");
215         if (fd >= 0)
216                 close(fd);
217 //      PARA_DEBUG_LOG("callback_ret: %d\n", ret);
218         return ret;
219 }
220
221 /**
222  * Send a callback request passing an options structure and an argument vector.
223  *
224  * \param options pointer to an arbitrary data structure.
225  * \param argc Argument count.
226  * \param argv Standard argument vector.
227  * \param f The callback function.
228  * \param result The result of the query is stored here.
229  *
230  * Some commands have a couple of options that are parsed in child context for
231  * syntactic correctness and are stored in a special options structure for that
232  * command. This function allows to pass such a structure together with a list
233  * of further arguments (often a list of audio files) to the parent process.
234  *
235  * \sa send_standard_callback_request(), send_callback_request().
236  */
237 int send_option_arg_callback_request(struct osl_object *options,
238                 int argc,  char * const * const argv, callback_function *f,
239                 struct osl_object *result)
240 {
241         char *p;
242         int i, ret;
243         struct osl_object query = {.size = options? options->size : 0};
244
245         for (i = 0; i < argc; i++)
246                 query.size += strlen(argv[i]) + 1;
247         query.data = para_malloc(query.size);
248         p = query.data;
249         if (options) {
250                 memcpy(query.data, options->data, options->size);
251                 p += options->size;
252         }
253         for (i = 0; i < argc; i++) {
254                 strcpy(p, argv[i]); /* OK */
255                 p += strlen(argv[i]) + 1;
256         }
257         ret = send_callback_request(f, &query, result);
258         free(query.data);
259         return ret;
260 }
261
262 /**
263  * Send a callback request with an argument vector only.
264  *
265  * \param argc The same meaning as in send_option_arg_callback_request().
266  * \param argv The same meaning as in send_option_arg_callback_request().
267  * \param f The same meaning as in send_option_arg_callback_request().
268  * \param result The same meaning as in send_option_arg_callback_request().
269  *
270  * This is similar to send_option_arg_callback_request(), but no options buffer
271  * is passed to the parent process.
272  *
273  * \return The return value of the underlying call to
274  * send_option_arg_callback_request().
275  */
276 int send_standard_callback_request(int argc,  char * const * const argv,
277                 callback_function *f, struct osl_object *result)
278 {
279         return send_option_arg_callback_request(NULL, argc, argv, f, result);
280 }
281
282 static int action_if_pattern_matches(struct osl_row *row, void *data)
283 {
284         struct pattern_match_data *pmd = data;
285         struct osl_object name_obj;
286         const char *p, *name;
287         int ret = osl_get_object(pmd->table, row, pmd->match_col_num, &name_obj);
288         const char *pattern_txt = (const char *)pmd->patterns.data;
289
290         if (ret < 0)
291                 return ret;
292         name = (char *)name_obj.data;
293         if ((!name || !*name) && (pmd->pm_flags & PM_SKIP_EMPTY_NAME))
294                 return 1;
295         if (!pmd->patterns.size && (pmd->pm_flags & PM_NO_PATTERN_MATCHES_EVERYTHING))
296                 return pmd->action(pmd->table, row, name, pmd->data);
297         for (p = pattern_txt; p < pattern_txt + pmd->patterns.size;
298                         p += strlen(p) + 1) {
299                 ret = fnmatch(p, name, pmd->fnmatch_flags);
300                 if (ret == FNM_NOMATCH)
301                         continue;
302                 if (ret)
303                         return -E_FNMATCH;
304                 return pmd->action(pmd->table, row, name, pmd->data);
305         }
306         return 1;
307 }
308
309 int for_each_matching_row(struct pattern_match_data *pmd)
310 {
311         if (pmd->pm_flags & PM_REVERSE_LOOP)
312                 return osl_rbtree_loop_reverse(pmd->table, pmd->loop_col_num, pmd,
313                         action_if_pattern_matches);
314         return osl_rbtree_loop(pmd->table, pmd->loop_col_num, pmd,
315                         action_if_pattern_matches);
316 }
317
318 /**
319  * Compare two osl objects of string type.
320  *
321  * \param obj1 Pointer to the first object.
322  * \param obj2 Pointer to the second object.
323  *
324  * In any case, only \p MIN(obj1->size, obj2->size) characters of each string
325  * are taken into account.
326  *
327  * \return It returns an integer less than, equal to, or greater than zero if
328  * \a obj1 is found, respectively, to be less than, to match, or be greater than
329  * obj2.
330  *
331  * \sa strcmp(3), strncmp(3), osl_compare_func.
332  */
333 int string_compare(const struct osl_object *obj1, const struct osl_object *obj2)
334 {
335         const char *str1 = (const char *)obj1->data;
336         const char *str2 = (const char *)obj2->data;
337         return strncmp(str1, str2, PARA_MIN(obj1->size, obj2->size));
338 }
339
340 /*
341  * write input from fd to dynamically allocated buffer,
342  * but maximal max_size byte.
343  */
344 static int fd2buf(int fd, unsigned max_size, struct osl_object *obj)
345 {
346         const size_t chunk_size = 1024;
347         size_t size = 2048, received = 0;
348         int ret;
349         char *buf = para_malloc(size);
350
351         for (;;) {
352                 ret = recv_bin_buffer(fd, buf + received, chunk_size);
353                 if (ret <= 0)
354                         break;
355                 received += ret;
356                 if (received + chunk_size >= size) {
357                         size *= 2;
358                         ret = -E_INPUT_TOO_LARGE;
359                         if (size > max_size)
360                                 break;
361                         buf = para_realloc(buf, size);
362                 }
363         }
364         obj->data = buf;
365         obj->size = received;
366         if (ret < 0)
367                 free(buf);
368         return ret;
369 }
370
371 /**
372  * Read data from a file descriptor, and send it to the afs process.
373  *
374  * \param fd File descriptor to read data from.
375  * \param arg_obj Pointer to the arguments to \a f.
376  * \param f The callback function.
377  * \param max_len Don't read more than that many bytes from stdin.
378  * \param result The result of the query is stored here.
379  *
380  * This function is used by commands that wish to let para_server store
381  * arbitrary data specified by the user (for instance the add_blob family of
382  * commands). First, at most \a max_len bytes are read from \a fd, the result
383  * is concatenated with the buffer given by \a arg_obj, and the combined buffer
384  * is made available to the parent process via shared memory.
385  *
386  * \return Negative on errors, the return value of the underlying call to
387  * send_callback_request() otherwise.
388  */
389 int stdin_command(int fd, struct osl_object *arg_obj, callback_function *f,
390                 unsigned max_len, struct osl_object *result)
391 {
392         struct osl_object query, stdin_obj;
393         int ret;
394
395         ret = send_buffer(fd, AWAITING_DATA_MSG);
396         if (ret < 0)
397                 return ret;
398         ret = fd2buf(fd, max_len, &stdin_obj);
399         if (ret < 0)
400                 return ret;
401         query.size = arg_obj->size + stdin_obj.size;
402         query.data = para_malloc(query.size);
403         memcpy(query.data, arg_obj->data, arg_obj->size);
404         memcpy((char *)query.data + arg_obj->size, stdin_obj.data, stdin_obj.size);
405         free(stdin_obj.data);
406         ret = send_callback_request(f, &query, result);
407         free(query.data);
408         return ret;
409 }
410
411 /**
412  * Open the audio file with highest score.
413  *
414  * \param afd Audio file data is returned here.
415  *
416  * This stores all information for streaming the "best" audio file
417  * in the \a afd structure.
418  *
419  * \return Positive on success, negative on errors.
420  *
421  * \sa close_audio_file(), open_and_update_audio_file().
422  */
423 int open_next_audio_file(struct audio_file_data *afd)
424 {
425         struct osl_row *aft_row;
426         int ret;
427         for (;;) {
428                 ret = score_get_best(&aft_row, &afd->score);
429                 if (ret < 0)
430                         return ret;
431                 ret = open_and_update_audio_file(aft_row, afd);
432                 if (ret >= 0)
433                         return ret;
434         }
435 }
436
437 /**
438  * Free all resources which were allocated by open_next_audio_file().
439  *
440  * \param afd The structure previously filled in by open_next_audio_file().
441  *
442  * \return The return value of the underlying call to para_munmap().
443  *
444  * \sa open_next_audio_file().
445  */
446 int close_audio_file(struct audio_file_data *afd)
447 {
448         free(afd->afhi.chunk_table);
449         return para_munmap(afd->map.data, afd->map.size);
450 }
451
452 #if 0
453 static void play_loop(enum play_mode current_play_mode)
454 {
455         int i, ret;
456         struct audio_file_data afd;
457
458         afd.current_play_mode = current_play_mode;
459         for (i = 0; i < 0; i++) {
460                 ret = open_next_audio_file(&afd);
461                 if (ret < 0) {
462                         PARA_ERROR_LOG("failed to open next audio file: %d\n", ret);
463                         return;
464                 }
465                 PARA_NOTICE_LOG("next audio file: %s, score: %li\n", afd.path, afd.score);
466                 sleep(1);
467                 close_audio_file(&afd);
468         }
469 }
470 #endif
471
472
473 static enum play_mode init_admissible_files(void)
474 {
475         int ret;
476         char *given_mood, *given_playlist;
477
478         given_mood = "mood_that_was_given_at_the_command_line";
479         given_playlist = "given_playlist";
480
481         if (given_mood) {
482                 ret = change_current_mood(given_mood);
483                 if (ret >= 0) {
484                         if (given_playlist)
485                                 PARA_WARNING_LOG("ignoring playlist %s\n",
486                                         given_playlist);
487                         return PLAY_MODE_MOOD;
488                 }
489         }
490         if (given_playlist) {
491                 ret = playlist_open(given_playlist);
492                 if (ret >= 0)
493                         return PLAY_MODE_PLAYLIST;
494         }
495         ret = change_current_mood(NULL); /* open first available mood */
496         if (ret >= 0)
497                 return PLAY_MODE_MOOD;
498         change_current_mood(""); /* open dummy mood, always successful */
499         return PLAY_MODE_MOOD;
500 }
501
502 static int setup_command_socket_or_die(void)
503 {
504         int ret;
505         char *socket_name = conf.afs_socket_arg;
506         struct sockaddr_un unix_addr;
507
508         unlink(socket_name);
509         ret = create_local_socket(socket_name, &unix_addr,
510                 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IWOTH);
511         if (ret < 0) {
512                 PARA_EMERG_LOG("%s: %s\n", PARA_STRERROR(-ret), socket_name);
513                 exit(EXIT_FAILURE);
514         }
515         if (listen(ret , 5) < 0) {
516                 PARA_EMERG_LOG("%s", "can not listen on socket\n");
517                 exit(EXIT_FAILURE);
518         }
519         PARA_INFO_LOG("listening on command socket %s (fd %d)\n", socket_name,
520                 ret);
521         return ret;
522 }
523
524 static int server_socket;
525 static struct command_task command_task_struct;
526 static struct signal_task signal_task_struct;
527
528 static void unregister_tasks(void)
529 {
530         unregister_task(&command_task_struct.task);
531         unregister_task(&signal_task_struct.task);
532 }
533
534 static void close_afs_tables(enum osl_close_flags flags)
535 {
536         PARA_NOTICE_LOG("closing afs_tables\n");
537         score_shutdown(flags);
538         attribute_shutdown(flags);
539         close_current_mood();
540         playlist_close();
541         moods_shutdown(flags);
542         playlists_shutdown(flags);
543         lyrics_shutdown(flags);
544         images_shutdown(flags);
545         aft_shutdown(flags);
546 }
547
548 static void signal_pre_select(struct sched *s, struct task *t)
549 {
550         struct signal_task *st = t->private_data;
551         t->ret = 1;
552         para_fd_set(st->fd, &s->rfds, &s->max_fileno);
553 }
554
555 static void signal_post_select(struct sched *s, struct task *t)
556 {
557         struct signal_task *st = t->private_data;
558         t->ret = 1;
559         if (!FD_ISSET(st->fd, &s->rfds))
560                 return;
561         st->signum = para_next_signal();
562         t->ret = 1;
563         if (st->signum == SIGUSR1)
564                 return; /* ignore SIGUSR1 */
565         PARA_NOTICE_LOG("caught signal %d\n", st->signum);
566         t->ret = -E_SIGNAL_CAUGHT;
567         unregister_tasks();
568 }
569
570 static void register_signal_task(void)
571 {
572         struct signal_task *st = &signal_task_struct;
573         st->fd = para_signal_init();
574         PARA_INFO_LOG("signal pipe: fd %d\n", st->fd);
575         para_install_sighandler(SIGINT);
576         para_install_sighandler(SIGTERM);
577         para_install_sighandler(SIGPIPE);
578
579         st->task.pre_select = signal_pre_select;
580         st->task.post_select = signal_post_select;
581         st->task.private_data = st;
582         sprintf(st->task.status, "signal task");
583         register_task(&st->task);
584 }
585
586 static void command_pre_select(struct sched *s, struct task *t)
587 {
588         struct command_task *ct = t->private_data;
589         t->ret = 1;
590         para_fd_set(ct->fd, &s->rfds, &s->max_fileno);
591 }
592
593 /*
594  * On errors, negative value is written to fd.
595  * On success: If query produced a result, the result_shmid is written to fd.
596  * Otherwise, zero is written.
597  */
598 static int call_callback(int fd, int query_shmid)
599 {
600         void *query_shm, *result_shm;
601         struct callback_query *cq;
602         struct callback_result *cr;
603         struct osl_object query, result = {.data = NULL};
604         int result_shmid = -1, ret, ret2;
605
606         ret = shm_attach(query_shmid, ATTACH_RW, &query_shm);
607         if (ret < 0)
608                 goto out;
609         cq = query_shm;
610         query.data = (char *)query_shm + sizeof(*cq);
611         query.size = cq->query_size;
612         ret = cq->handler(&query, &result);
613         ret2 = shm_detach(query_shm);
614         if (ret2 < 0 && ret >= 0)
615                 ret = ret2;
616         if (ret < 0)
617                 goto out;
618         ret = 0;
619         if (!result.data || !result.size)
620                 goto out;
621         ret = shm_new(result.size + sizeof(struct callback_result));
622         if (ret < 0)
623                 goto out;
624         result_shmid = ret;
625         ret = shm_attach(result_shmid, ATTACH_RW, &result_shm);
626         if (ret < 0)
627                 goto out;
628         cr = result_shm;
629         cr->result_size = result.size;
630         memcpy(result_shm + sizeof(*cr), result.data, result.size);
631         ret = shm_detach(result_shm);
632         if (ret < 0)
633                 goto out;
634         ret = result_shmid;
635 out:
636         free(result.data);
637         ret2 = send_bin_buffer(fd, (char *)&ret, sizeof(int));
638         if (ret < 0 || ret2 < 0) {
639                 if (result_shmid >= 0)
640                         if (shm_destroy(result_shmid) < 0)
641                                 PARA_ERROR_LOG("destroy result failed\n");
642                 if (ret >= 0)
643                         ret = ret2;
644         }
645         return ret;
646 }
647
648 static void command_post_select(struct sched *s, struct task *t)
649 {
650         struct command_task *ct = t->private_data;
651         struct sockaddr_un unix_addr;
652         char buf[sizeof(uint32_t) + sizeof(int)];
653         uint32_t cookie;
654         int query_shmid, fd;
655
656         t->ret = 1;
657         if (!FD_ISSET(ct->fd, &s->rfds))
658                 return;
659         t->ret = para_accept(ct->fd, &unix_addr, sizeof(unix_addr));
660         if (t->ret < 0)
661                 return;
662         /*
663          * The following errors may be caused by a malicious local user. So do
664          * not return an error in this case as this would terminate  para_afs
665          * and para_server.
666          */
667         fd = t->ret;
668         /* FIXME: This is easily dosable (peer doesn't send data) */
669         t->ret = recv_bin_buffer(fd, buf, sizeof(buf));
670         if (t->ret < 0) {
671                 PARA_NOTICE_LOG("%s (%d)\n", PARA_STRERROR(-t->ret), t->ret);
672                 goto out;
673         }
674         if (t->ret != sizeof(buf)) {
675                 PARA_NOTICE_LOG("short read (%d bytes, expected %lu)\n",
676                         t->ret, (long unsigned) sizeof(buf));
677                 goto out;
678         }
679         cookie = *(uint32_t *)buf;
680         if (cookie != ct->cookie) {
681                 PARA_NOTICE_LOG("received invalid cookie(got %u, expected %u)\n",
682                         (unsigned)cookie, (unsigned)ct->cookie);
683                 goto out;
684         }
685         query_shmid = *(int *)(buf + sizeof(cookie));
686         if (query_shmid < 0) {
687                 PARA_WARNING_LOG("received invalid query shmid %d)\n",
688                         query_shmid);
689                 goto out;
690         }
691         /* Ignore return value: Errors might be ok here. */
692         call_callback(fd, query_shmid);
693 out:
694         t->ret = 1;
695         close(fd);
696 }
697
698 static void register_command_task(uint32_t cookie)
699 {
700         struct command_task *ct = &command_task_struct;
701         ct->fd = setup_command_socket_or_die();
702         ct->cookie = cookie;
703
704         ct->task.pre_select = command_pre_select;
705         ct->task.post_select = command_post_select;
706         ct->task.private_data = ct;
707         sprintf(ct->task.status, "command task");
708         register_task(&ct->task);
709 }
710
711 void register_tasks(uint32_t cookie)
712 {
713         register_signal_task();
714         register_command_task(cookie);
715 }
716
717 static char *database_dir;
718
719 static int make_database_dir(void)
720 {
721         int ret;
722
723         if (!database_dir) {
724                 if (conf.afs_database_dir_given)
725                         database_dir = para_strdup(conf.afs_database_dir_arg);
726                 else {
727                         char *home = para_homedir();
728                         database_dir = make_message(
729                                 "%s/.paraslash/afs_database", home);
730                         free(home);
731                 }
732         }
733         PARA_INFO_LOG("afs_database dir %s\n", database_dir);
734         ret = para_mkdir(database_dir, 0777);
735         if (ret >= 0 || ret == -E_EXIST)
736                 return 1;
737         free(database_dir);
738         database_dir = NULL;
739         return ret;
740 }
741
742 static int open_afs_tables(void)
743 {
744         int ret = make_database_dir();
745
746         if (ret < 0)
747                 return ret;
748         ret = attribute_init(&afs_tables[TBLNUM_ATTRIBUTES], database_dir);
749         if (ret < 0)
750                 return ret;
751         ret = moods_init(&afs_tables[TBLNUM_MOODS], database_dir);
752         if (ret < 0)
753                 goto moods_init_error;
754         ret = playlists_init(&afs_tables[TBLNUM_PLAYLIST], database_dir);
755         if (ret < 0)
756                 goto playlists_init_error;
757         ret = lyrics_init(&afs_tables[TBLNUM_LYRICS], database_dir);
758         if (ret < 0)
759                 goto lyrics_init_error;
760         ret = images_init(&afs_tables[TBLNUM_IMAGES], database_dir);
761         if (ret < 0)
762                 goto images_init_error;
763         ret = score_init(&afs_tables[TBLNUM_SCORES], database_dir);
764         if (ret < 0)
765                 goto score_init_error;
766         ret = aft_init(&afs_tables[TBLNUM_AUDIO_FILES], database_dir);
767         if (ret < 0)
768                 goto aft_init_error;
769         return 1;
770
771 aft_init_error:
772         score_shutdown(OSL_MARK_CLEAN);
773 score_init_error:
774         images_shutdown(OSL_MARK_CLEAN);
775 images_init_error:
776         lyrics_shutdown(OSL_MARK_CLEAN);
777 lyrics_init_error:
778         playlists_shutdown(OSL_MARK_CLEAN);
779 playlists_init_error:
780         moods_shutdown(OSL_MARK_CLEAN);
781 moods_init_error:
782         attribute_shutdown(OSL_MARK_CLEAN);
783         return ret;
784 }
785
786 __noreturn int afs_init(uint32_t cookie, int socket_fd)
787 {
788         enum play_mode current_play_mode;
789         struct sched s;
790         int ret = open_afs_tables();
791
792         if (ret < 0) {
793                 PARA_EMERG_LOG("%s\n", PARA_STRERROR(-ret));
794                 exit(EXIT_FAILURE);
795         }
796         server_socket = socket_fd;
797         ret = mark_fd_nonblock(server_socket);
798         if (ret < 0)
799                 exit(EXIT_FAILURE);
800         PARA_INFO_LOG("server_socket: %d, afs_socket_cookie: %u\n",
801                 server_socket, (unsigned) cookie);
802         current_play_mode = init_admissible_files();
803         register_tasks(cookie);
804         s.default_timeout.tv_sec = 0;
805         s.default_timeout.tv_usec = 99 * 1000;
806         ret = sched(&s);
807         if (ret < 0)
808                 PARA_EMERG_LOG("%s\n", PARA_STRERROR(-ret));
809         close_afs_tables(OSL_MARK_CLEAN);
810         exit(EXIT_FAILURE);
811 }
812
813 static int create_tables_callback(const struct osl_object *query,
814                 __a_unused struct osl_object *result)
815 {
816         uint32_t table_mask = *(uint32_t *)query->data;
817         int i, ret;
818
819         close_afs_tables(OSL_MARK_CLEAN);
820         for (i = 0; i < NUM_AFS_TABLES; i++) {
821                 struct table_info *ti = afs_tables + i;
822
823                 if (ti->flags & TBLFLAG_SKIP_CREATE)
824                         continue;
825                 if (!(table_mask & (1 << i)))
826                         continue;
827                 ret = osl_create_table(ti->desc);
828                 if (ret < 0)
829                         return ret;
830         }
831         ret = open_afs_tables();
832         return ret < 0? ret: 0;
833 }
834
835 int com_init(int fd, int argc, char * const * const argv)
836 {
837         int i, j, ret;
838         uint32_t table_mask = (1 << (NUM_AFS_TABLES + 1)) - 1;
839         struct osl_object query = {.data = &table_mask,
840                 .size = sizeof(table_mask)};
841
842         if (argc != 1) {
843                 table_mask = 0;
844                 for (i = 1; i < argc; i++) {
845                         for (j = 0; j < NUM_AFS_TABLES; j++) {
846                                 struct table_info *ti = afs_tables + j;
847
848                                 if (ti->flags & TBLFLAG_SKIP_CREATE)
849                                         continue;
850                                 if (strcmp(argv[i], ti->desc->name))
851                                         continue;
852                                 table_mask |= (1 << j);
853                                 break;
854                         }
855                         if (j == NUM_AFS_TABLES)
856                                 return -E_BAD_TABLE_NAME;
857                 }
858         }
859         ret = send_callback_request(create_tables_callback, &query, NULL);
860         if (ret < 0)
861                 return ret;
862         return send_va_buffer(fd, "successfully created afs table(s)\n");
863 }
864
865 enum com_check_flags {
866         CHECK_AFT = 1,
867         CHECK_MOODS = 2,
868         CHECK_PLAYLISTS = 4
869 };
870
871 int com_check(int fd, int argc, char * const * const argv)
872 {
873         unsigned flags = 0;
874         int i, ret;
875         struct osl_object result;
876
877         for (i = 1; i < argc; i++) {
878                 const char *arg = argv[i];
879                 if (arg[0] != '-')
880                         break;
881                 if (!strcmp(arg, "--")) {
882                         i++;
883                         break;
884                 }
885                 if (!strcmp(arg, "-a")) {
886                         flags |= CHECK_AFT;
887                         continue;
888                 }
889                 if (!strcmp(arg, "-p")) {
890                         flags |= CHECK_PLAYLISTS;
891                         continue;
892                 }
893                 if (!strcmp(arg, "-m")) {
894                         flags |= CHECK_MOODS;
895                         continue;
896                 }
897                 return -E_AFS_SYNTAX;
898         }
899         if (i < argc)
900                 return -E_AFS_SYNTAX;
901         if (!flags)
902                 flags = ~0U;
903         if (flags & CHECK_AFT) {
904                 ret = send_callback_request(aft_check_callback, NULL, &result);
905                 if (ret < 0)
906                         return ret;
907                 if (ret > 0) {
908                         ret = send_buffer(fd, (char *) result.data);
909                         free(result.data);
910                         if (ret < 0)
911                                 return ret;
912                 }
913         }
914         if (flags & CHECK_PLAYLISTS) {
915                 ret = send_callback_request(playlist_check_callback, NULL, &result);
916                 if (ret < 0)
917                         return ret;
918                 if (ret > 0) {
919                         ret = send_buffer(fd, (char *) result.data);
920                         free(result.data);
921                         if (ret < 0)
922                                 return ret;
923                 }
924         }
925         if (flags & CHECK_MOODS) {
926                 ret = send_callback_request(mood_check_callback, NULL, &result);
927                 if (ret < 0)
928                         return ret;
929                 if (ret > 0) {
930                         ret = send_buffer(fd, (char *) result.data);
931                         free(result.data);
932                         if (ret < 0)
933                                 return ret;
934                 }
935         }
936         return 1;
937 }