X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=afs.c;h=92c58cc8cbe142a4f403b6bd0654c21f8136757e;hp=46af53f8b81e78d41d25a12200c5888f6171198f;hb=3f696a82bbb79cb07bfdb8e510bb4f3515570cec;hpb=030a9d5c9fe28328d5db977bf2c8ddbf7302673d diff --git a/afs.c b/afs.c index 46af53f8..92c58cc8 100644 --- a/afs.c +++ b/afs.c @@ -12,9 +12,11 @@ #include #include #include +#include #include #include #include +#include #include "server.cmdline.h" #include "para.h" @@ -97,10 +99,11 @@ static char *current_mop; /* mode or playlist specifier. NULL means dummy mood * /** * A random number used to "authenticate" the connection. * - * para_server picks this number by random before forking the afs process. The - * command handlers write this number together with the id of the shared memory - * area containing the query. This way, a malicious local user has to know this - * number to be able to cause the afs process to crash by sending fake queries. + * para_server picks this number by random before it forks the afs process. The + * command handlers know this number as well and write it to the afs socket, + * together with the id of the shared memory area which contains the payload of + * the afs command. A local process has to know this number to abuse the afs + * service provided by the local socket. */ extern uint32_t afs_socket_cookie; @@ -278,6 +281,36 @@ out: return num_dispatched; } +/** + * Wrapper for send_callback_request() which passes a lopsub parse result. + * + * \param f The callback function. + * \param cmd Needed for (de-)serialization. + * \param lpr Must match cmd. + * \param private_result_data Passed to send_callback_request(). + * + * This function serializes the parse result given by the lpr pointer into a + * buffer. The buffer is sent as the query to the afs process with the callback + * mechanism. + * + * \return The return value of the underlying call to send_callback_request(). + */ +int send_lls_callback_request(afs_callback *f, + const struct lls_command * const cmd, + struct lls_parse_result *lpr, void *private_result_data) +{ + struct osl_object query; + char *buf = NULL; + int ret = lls_serialize_parse_result(lpr, cmd, &buf, &query.size); + + assert(ret >= 0); + query.data = buf; + ret = send_callback_request(f, &query, afs_cb_result_handler, + private_result_data); + free(buf); + return ret; +} + /** * Send a callback request passing an options structure and an argument vector. * @@ -353,7 +386,7 @@ static int action_if_pattern_matches(struct osl_row *row, void *data) struct pattern_match_data *pmd = data; struct osl_object name_obj; const char *p, *name; - int ret = osl(osl_get_object(pmd->table, row, pmd->match_col_num, &name_obj)); + int i, ret = osl(osl_get_object(pmd->table, row, pmd->match_col_num, &name_obj)); const char *pattern_txt = (const char *)pmd->patterns.data; if (ret < 0) @@ -361,22 +394,37 @@ static int action_if_pattern_matches(struct osl_row *row, void *data) name = (char *)name_obj.data; if ((!name || !*name) && (pmd->pm_flags & PM_SKIP_EMPTY_NAME)) return 1; - if (pmd->patterns.size == 0 && - (pmd->pm_flags & PM_NO_PATTERN_MATCHES_EVERYTHING)) { - pmd->num_matches++; - return pmd->action(pmd->table, row, name, pmd->data); + if ((pmd->lpr && lls_num_inputs(pmd->lpr) == 0) || pmd->patterns.size == 0) { + if (pmd->pm_flags & PM_NO_PATTERN_MATCHES_EVERYTHING) { + pmd->num_matches++; + return pmd->action(pmd->table, row, name, pmd->data); + } } - for (p = pattern_txt; p < pattern_txt + pmd->patterns.size; - p += strlen(p) + 1) { + p = pattern_txt; + i = pmd->input_skip; + for (;;) { + if (pmd->lpr) { + if (i >= lls_num_inputs(pmd->lpr)) + break; + p = lls_input(i, pmd->lpr); + } else { + if (p >= pattern_txt + pmd->patterns.size) + break; + } ret = fnmatch(p, name, pmd->fnmatch_flags); - if (ret == FNM_NOMATCH) - continue; - if (ret) - return -E_FNMATCH; - ret = pmd->action(pmd->table, row, name, pmd->data); - if (ret >= 0) - pmd->num_matches++; - return ret; + if (ret != FNM_NOMATCH) { + if (ret != 0) + return -E_FNMATCH; + ret = pmd->action(pmd->table, row, name, pmd->data); + if (ret >= 0) + pmd->num_matches++; + return ret; + + } + if (pmd->lpr) + i++; + else + p += strlen(p) + 1; } return 1; } @@ -423,7 +471,7 @@ static int pass_afd(int fd, char *buf, size_t size) { struct msghdr msg = {.msg_iov = NULL}; struct cmsghdr *cmsg; - char control[255]; + char control[255] __a_aligned(8); int ret; struct iovec iov; @@ -496,12 +544,11 @@ no_admissible_files: } /* Never fails if arg == NULL */ -static int activate_mood_or_playlist(char *arg, int *num_admissible) +static int activate_mood_or_playlist(const char *arg, int *num_admissible) { enum play_mode mode; int ret; - PARA_INFO_LOG("new playlist: %s\n", arg); if (!arg) { ret = change_current_mood(NULL); /* always successful */ mode = PLAY_MODE_MOOD; @@ -590,7 +637,7 @@ static void flush_and_free_pb(struct para_buffer *pb) static int com_select_callback(struct afs_callback_arg *aca) { - char *arg = aca->query.data; + const char *arg = aca->query.data; int num_admissible, ret; ret = clear_score_table(); @@ -607,14 +654,17 @@ static int com_select_callback(struct afs_callback_arg *aca) if (ret >= 0) goto out; /* ignore subsequent errors (but log them) */ - para_printf(&aca->pbout, "could not activate %s: %s\n" - "switching back to %s\n", - arg, para_strerror(-ret), current_mop? current_mop : "dummy"); - ret = activate_mood_or_playlist(current_mop, &num_admissible); - if (ret >= 0) - goto out; - para_printf(&aca->pbout, "could not activate %s: %s\nswitching to dummy\n", - current_mop, para_strerror(-ret)); + para_printf(&aca->pbout, "could not activate %s\n", arg); + if (current_mop) { + int ret2; + para_printf(&aca->pbout, "switching back to %s\n", current_mop); + ret2 = activate_mood_or_playlist(current_mop, &num_admissible); + if (ret2 >= 0) + goto out; + para_printf(&aca->pbout, "could not reactivate %s: %s\n", + current_mop, para_strerror(-ret2)); + } + para_printf(&aca->pbout, "activating dummy mood\n"); activate_mood_or_playlist(NULL, &num_admissible); out: para_printf(&aca->pbout, "activated %s (%d admissible files)\n", @@ -649,7 +699,7 @@ static int setup_command_socket_or_die(void) ret = create_local_socket(socket_name, 0); if (ret < 0) { ret = create_local_socket(socket_name, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IWOTH); + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IROTH); if (ret < 0) { PARA_EMERG_LOG("%s: %s\n", para_strerror(-ret), socket_name); @@ -703,7 +753,7 @@ static int open_afs_tables(void) int i, ret; get_database_dir(); - PARA_NOTICE_LOG("opening %u osl tables in %s\n", NUM_AFS_TABLES, + PARA_NOTICE_LOG("opening %d osl tables in %s\n", NUM_AFS_TABLES, database_dir); for (i = 0; i < NUM_AFS_TABLES; i++) { ret = afs_tables[i].open(database_dir); @@ -885,7 +935,7 @@ static int execute_server_command(fd_set *rfds) return ret; buf[n] = '\0'; if (strcmp(buf, "new")) - return -E_BAD_CMD; + return -ERRNO_TO_PARA_ERROR(EINVAL); return open_next_audio_file(); } @@ -1021,6 +1071,13 @@ __noreturn void afs_init(uint32_t cookie, int socket_fd) register_command_task(cookie, &s); s.default_timeout.tv_sec = 0; s.default_timeout.tv_usec = 999 * 1000; + ret = write(socket_fd, "\0", 1); + if (ret != 1) { + if (ret == 0) + errno = EINVAL; + ret = -ERRNO_TO_PARA_ERROR(errno); + goto out_close; + } ret = schedule(&s); sched_shutdown(&s); out_close: @@ -1060,23 +1117,24 @@ out: return ret; } -int com_init(struct command_context *cc) +static int com_init(struct command_context *cc, struct lls_parse_result *lpr) { int i, j, ret; uint32_t table_mask = (1 << (NUM_AFS_TABLES + 1)) - 1; struct osl_object query = {.data = &table_mask, .size = sizeof(table_mask)}; + unsigned num_inputs = lls_num_inputs(lpr); ret = make_database_dir(); if (ret < 0) return ret; - if (cc->argc != 1) { + if (num_inputs > 0) { table_mask = 0; - for (i = 1; i < cc->argc; i++) { + for (i = 0; i < num_inputs; i++) { for (j = 0; j < NUM_AFS_TABLES; j++) { struct afs_table *t = &afs_tables[j]; - if (strcmp(cc->argv[i], t->name)) + if (strcmp(lls_input(i, lpr), t->name)) continue; table_mask |= (1 << j); break; @@ -1088,6 +1146,7 @@ int com_init(struct command_context *cc) return send_callback_request(com_init_callback, &query, afs_cb_result_handler, cc); } +EXPORT_SERVER_CMD_HANDLER(init); /** * Flags for the check command. @@ -1192,7 +1251,7 @@ __must_check int afs_event(enum afs_events event, struct para_buffer *pb, continue; ret = t->event_handler(event, pb, data); if (ret < 0) { - PARA_CRIT_LOG("table %s, event %d: %s\n", t->name, + PARA_CRIT_LOG("table %s, event %u: %s\n", t->name, event, para_strerror(-ret)); return ret; }