X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=afs.c;h=46af53f8b81e78d41d25a12200c5888f6171198f;hp=c40537466fd9480265815d034050b745dc2f45d3;hb=030a9d5c9fe28328d5db977bf2c8ddbf7302673d;hpb=9bf6dc2eaf7b3252fb7db73ed8ead6f568bbb0ec diff --git a/afs.c b/afs.c index c4053746..46af53f8 100644 --- a/afs.c +++ b/afs.c @@ -130,7 +130,7 @@ extern uint32_t afs_socket_cookie; */ struct callback_query { /** The function to be called. */ - callback_function *handler; + afs_callback *handler; /** The number of bytes of the query */ size_t query_size; }; @@ -166,13 +166,8 @@ static int dispatch_result(int result_shmid, callback_result_handler *handler, } result.size = cr->result_size; result.data = result_shm + sizeof(*cr); - if (result.size) { - assert(handler); - ret = handler(&result, cr->band, private_result_data); - if (ret < 0) - PARA_NOTICE_LOG("result handler error: %s\n", - para_strerror(-ret)); - } + assert(handler); + ret = handler(&result, cr->band, private_result_data); ret2 = shm_detach(result_shm); if (ret2 < 0) { PARA_ERROR_LOG("detach failed: %s\n", para_strerror(-ret2)); @@ -206,7 +201,7 @@ static int dispatch_result(int result_shmid, callback_result_handler *handler, * * \sa send_option_arg_callback_request(), send_standard_callback_request(). */ -int send_callback_request(callback_function *f, struct osl_object *query, +int send_callback_request(afs_callback *f, struct osl_object *query, callback_result_handler *result_handler, void *private_result_data) { @@ -261,12 +256,10 @@ int send_callback_request(callback_function *f, struct osl_object *query, ret = *(int *) buf; assert(ret > 0); result_shmid = ret; - if (!dispatch_error) { - ret = dispatch_result(result_shmid, result_handler, - private_result_data); - if (ret < 0) - dispatch_error = 1; - } + ret = dispatch_result(result_shmid, result_handler, + private_result_data); + if (ret < 0 && dispatch_error >= 0) + dispatch_error = ret; ret = shm_destroy(result_shmid); if (ret < 0) PARA_CRIT_LOG("destroy result failed: %s\n", @@ -278,8 +271,11 @@ out: PARA_CRIT_LOG("shm destroy error\n"); if (fd >= 0) close(fd); -// PARA_DEBUG_LOG("callback_ret: %d\n", ret); - return ret < 0? ret : num_dispatched; + if (dispatch_error < 0) + return dispatch_error; + if (ret < 0) + return ret; + return num_dispatched; } /** @@ -303,7 +299,7 @@ out: * \sa send_standard_callback_request(), send_callback_request(). */ int send_option_arg_callback_request(struct osl_object *options, - int argc, char * const * const argv, callback_function *f, + int argc, char * const * const argv, afs_callback *f, callback_result_handler *result_handler, void *private_result_data) { @@ -345,7 +341,7 @@ int send_option_arg_callback_request(struct osl_object *options, * send_option_arg_callback_request(). */ int send_standard_callback_request(int argc, char * const * const argv, - callback_function *f, callback_result_handler *result_handler, + afs_callback *f, callback_result_handler *result_handler, void *private_result_data) { return send_option_arg_callback_request(NULL, argc, argv, f, result_handler, @@ -505,6 +501,7 @@ static int activate_mood_or_playlist(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; @@ -559,52 +556,70 @@ int afs_cb_result_handler(struct osl_object *result, uint8_t band, struct command_context *cc = private; assert(cc); - if (!result->size) - return 1; - return send_sb(&cc->scc, result->data, result->size, band, true); + switch (band) { + case SBD_OUTPUT: + case SBD_DEBUG_LOG: + case SBD_INFO_LOG: + case SBD_NOTICE_LOG: + case SBD_WARNING_LOG: + case SBD_ERROR_LOG: + case SBD_CRIT_LOG: + case SBD_EMERG_LOG: + assert(result->size > 0); + return send_sb(&cc->scc, result->data, result->size, band, true); + case SBD_AFS_CB_FAILURE: + return *(int *)(result->data); + default: + return -E_BAD_BAND; + } } -static void com_select_callback(int fd, const struct osl_object *query) +static void flush_and_free_pb(struct para_buffer *pb) { - struct para_buffer pb = { - .max_size = shm_get_shmmax(), - .private_data = &(struct afs_max_size_handler_data) { - .fd = fd, - .band = SBD_OUTPUT - }, - .max_size_handler = afs_max_size_handler, - }; - char *arg = query->data; - int num_admissible, ret, ret2; + int ret; + struct afs_max_size_handler_data *amshd = pb->private_data; + + if (pb->buf && pb->size > 0) { + ret = pass_buffer_as_shm(amshd->fd, amshd->band, pb->buf, + pb->offset); + if (ret < 0) + PARA_ERROR_LOG("%s\n", para_strerror(-ret)); + } + free(pb->buf); +} + +static int com_select_callback(struct afs_callback_arg *aca) +{ + char *arg = aca->query.data; + int num_admissible, ret; ret = clear_score_table(); if (ret < 0) { - ret2 = para_printf(&pb, "%s\n", para_strerror(-ret)); - goto out; + para_printf(&aca->pbout, "could not clear score table: %s\n", + para_strerror(-ret)); + return ret; } if (current_play_mode == PLAY_MODE_MOOD) close_current_mood(); else playlist_close(); ret = activate_mood_or_playlist(arg, &num_admissible); - if (ret < 0) { - ret2 = para_printf(&pb, "%s\nswitching back to %s\n", - para_strerror(-ret), current_mop? - current_mop : "dummy"); - ret = activate_mood_or_playlist(current_mop, &num_admissible); - if (ret < 0) { - if (ret2 >= 0) - ret2 = para_printf(&pb, "failed, switching to dummy\n"); - activate_mood_or_playlist(NULL, &num_admissible); - } - } else - ret2 = para_printf(&pb, "activated %s (%d admissible files)\n", - current_mop? current_mop : "dummy mood", - num_admissible); + 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)); + activate_mood_or_playlist(NULL, &num_admissible); out: - if (ret2 >= 0 && pb.offset) - pass_buffer_as_shm(fd, SBD_OUTPUT, pb.buf, pb.offset); - free(pb.buf); + para_printf(&aca->pbout, "activated %s (%d admissible files)\n", + current_mop? current_mop : "dummy mood", num_admissible); + return ret; } int com_select(struct command_context *cc) @@ -795,8 +810,8 @@ int pass_buffer_as_shm(int fd, uint8_t band, const char *buf, size_t size) void *shm; struct callback_result *cr; - if (!buf || !size) - return 0; + if (size == 0) + assert(band != SBD_OUTPUT); ret = shm_new(size + sizeof(*cr)); if (ret < 0) return ret; @@ -807,7 +822,8 @@ int pass_buffer_as_shm(int fd, uint8_t band, const char *buf, size_t size) cr = shm; cr->result_size = size; cr->band = band; - memcpy(shm + sizeof(*cr), buf, size); + if (size > 0) + memcpy(shm + sizeof(*cr), buf, size); ret = shm_detach(shm); if (ret < 0) goto err; @@ -820,26 +836,43 @@ err: return ret; } -/* - * On errors, negative value is written to fd. - * On success: If query produced a result, the result_shmid is written to fd. - * Otherwise, zero is written. - */ static int call_callback(int fd, int query_shmid) { void *query_shm; struct callback_query *cq; - struct osl_object query; - int ret; + int ret, ret2; + struct afs_callback_arg aca = {.fd = fd}; ret = shm_attach(query_shmid, ATTACH_RW, &query_shm); if (ret < 0) return ret; cq = query_shm; - query.data = (char *)query_shm + sizeof(*cq); - query.size = cq->query_size; - cq->handler(fd, &query); - return shm_detach(query_shm); + aca.query.data = (char *)query_shm + sizeof(*cq); + aca.query.size = cq->query_size; + aca.pbout.max_size = shm_get_shmmax(); + aca.pbout.max_size_handler = afs_max_size_handler; + aca.pbout.private_data = &(struct afs_max_size_handler_data) { + .fd = fd, + .band = SBD_OUTPUT + }; + ret = cq->handler(&aca); + ret2 = shm_detach(query_shm); + if (ret2 < 0) { + if (ret < 0) /* ignore (but log) detach error */ + PARA_ERROR_LOG("could not detach sma: %s\n", + para_strerror(-ret2)); + else + ret = ret2; + } + flush_and_free_pb(&aca.pbout); + if (ret < 0) { + ret2 = pass_buffer_as_shm(fd, SBD_AFS_CB_FAILURE, + (const char *)&ret, sizeof(ret)); + if (ret2 < 0) + PARA_ERROR_LOG("could not pass cb failure packet: %s\n", + para_strerror(-ret)); + } + return ret; } static int execute_server_command(fd_set *rfds) @@ -998,17 +1031,10 @@ out: exit(EXIT_FAILURE); } -static void create_tables_callback(int fd, const struct osl_object *query) +static int com_init_callback(struct afs_callback_arg *aca) { - uint32_t table_mask = *(uint32_t *)query->data; + uint32_t table_mask = *(uint32_t *)aca->query.data; int i, ret; - struct para_buffer pb = { - .max_size = shm_get_shmmax(), - .private_data = &(struct afs_max_size_handler_data) { - .fd = fd, - .band = SBD_OUTPUT - } - }; close_afs_tables(); for (i = 0; i < NUM_AFS_TABLES; i++) { @@ -1019,17 +1045,19 @@ static void create_tables_callback(int fd, const struct osl_object *query) if (!t->create) continue; ret = t->create(database_dir); - if (ret < 0) + if (ret < 0) { + para_printf(&aca->pbout, "cannot create table %s\n", + t->name); goto out; - para_printf(&pb, "successfully created %s table\n", t->name); + } + para_printf(&aca->pbout, "successfully created %s table\n", + t->name); } ret = open_afs_tables(); -out: if (ret < 0) - para_printf(&pb, "%s\n", para_strerror(-ret)); - if (pb.buf) - pass_buffer_as_shm(fd, SBD_OUTPUT, pb.buf, pb.offset); - free(pb.buf); + para_printf(&aca->pbout, "cannot open afs tables\n"); +out: + return ret; } int com_init(struct command_context *cc) @@ -1057,9 +1085,8 @@ int com_init(struct command_context *cc) return -E_BAD_TABLE_NAME; } } - ret = send_callback_request(create_tables_callback, &query, + return send_callback_request(com_init_callback, &query, afs_cb_result_handler, cc); - return ret; } /** @@ -1073,7 +1100,9 @@ enum com_check_flags { /** Check the mood table. */ CHECK_MOODS = 2, /** Check the playlist table. */ - CHECK_PLAYLISTS = 4 + CHECK_PLAYLISTS = 4, + /** Check the attribute table against the audio file table. */ + CHECK_ATTS = 8 }; int com_check(struct command_context *cc) @@ -1093,6 +1122,10 @@ int com_check(struct command_context *cc) flags |= CHECK_AFT; continue; } + if (!strcmp(arg, "-A")) { + flags |= CHECK_ATTS; + continue; + } if (!strcmp(arg, "-p")) { flags |= CHECK_PLAYLISTS; continue; @@ -1113,6 +1146,12 @@ int com_check(struct command_context *cc) if (ret < 0) return ret; } + if (flags & CHECK_ATTS) { + ret = send_callback_request(attribute_check_callback, NULL, + afs_cb_result_handler, cc); + if (ret < 0) + return ret; + } if (flags & CHECK_PLAYLISTS) { ret = send_callback_request(playlist_check_callback, NULL, afs_cb_result_handler, cc); @@ -1135,10 +1174,14 @@ int com_check(struct command_context *cc) * \param pb May be \p NULL. * \param data Type depends on \a event. * - * This function calls the table handlers of all tables and passes \a pb and \a - * data verbatim. It's up to the handlers to interpret the \a data pointer. + * This function calls each table event handler, passing \a pb and \a data + * verbatim. It's up to the handlers to interpret the \a data pointer. If a + * handler returns negative, the loop is aborted. + * + * \return The (negative) error code of the first handler that failed, or non-negative + * if all handlers succeeded. */ -void afs_event(enum afs_events event, struct para_buffer *pb, +__must_check int afs_event(enum afs_events event, struct para_buffer *pb, void *data) { int i, ret; @@ -1148,10 +1191,13 @@ void afs_event(enum afs_events event, struct para_buffer *pb, if (!t->event_handler) continue; ret = t->event_handler(event, pb, data); - if (ret < 0) + if (ret < 0) { PARA_CRIT_LOG("table %s, event %d: %s\n", t->name, event, para_strerror(-ret)); + return ret; + } } + return 1; } /**