X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=audiod_command.c;h=8a87d91e108f4470f127d35538bb16ef920f5c76;hp=22b47cf3eda16070079856f725611b38171ea58f;hb=534a94f441767947874cb15d18211edf758e9277;hpb=074b80bb23b8fa610464bd98dc4bc7dd2babc88a diff --git a/audiod_command.c b/audiod_command.c index 22b47cf3..8a87d91e 100644 --- a/audiod_command.c +++ b/audiod_command.c @@ -13,10 +13,11 @@ #include #include #include +#include #include "para.h" +#include "audiod_cmd.lsg.h" #include "audiod.cmdline.h" -#include "audiod.command_list.h" #include "list.h" #include "sched.h" #include "ggo.h" @@ -35,29 +36,23 @@ extern struct sched sched; extern char *stat_item_values[NUM_STAT_ITEMS]; -typedef int audiod_command_handler_t(int, int, char **); -static audiod_command_handler_t AUDIOD_COMMAND_HANDLERS; - -/* Defines one command of para_audiod. */ -struct audiod_command { - const char *name; - /* Pointer to the function that handles the command. */ - audiod_command_handler_t *handler; - /* One-line description. */ - const char *description; - /* Summary of the command line options. */ - const char *usage; - /* The long help text. */ - const char *help; -}; +/** The maximal number of simultaneous connections. */ +#define MAX_STAT_CLIENTS 50 -static struct audiod_command audiod_cmds[] = {DEFINE_AUDIOD_CMD_ARRAY}; +/** Pointer to a command handler function. */ +typedef int (*audiod_cmd_handler_t)(int, struct lls_parse_result *); -/** Iterate over the array of all audiod commands. */ -#define FOR_EACH_COMMAND(c) for (c = 0; audiod_cmds[c].name; c++) +/** The lopsub user_data pointer. Only the command handler at the moment. */ +struct audiod_command_info { + audiod_cmd_handler_t handler; /**< Implementation of the command. */ +}; -/** The maximal number of simultaneous connections. */ -#define MAX_STAT_CLIENTS 50 +/** Define the user_data pointer as expected by lopsub. */ +#define EXPORT_AUDIOD_CMD_HANDLER(_cmd) \ + /** Implementation of _cmd. */ \ + const struct audiod_command_info lsg_audiod_cmd_com_ ## _cmd ## _user_data = { \ + .handler = com_ ## _cmd \ + }; /** Flags used for the stat command of para_audiod. */ enum stat_client_flags { @@ -183,8 +178,7 @@ void stat_client_write_item(int item_num) continue; b = (sc->flags & SCF_PARSER_FRIENDLY)? &pfpb : &pb; if (!b->buf) - (void)WRITE_STATUS_ITEM(b, item_num, "%s\n", - msg? msg : ""); + WRITE_STATUS_ITEM(b, item_num, "%s\n", msg? msg : ""); ret = write(sc->fd, b->buf, b->offset); if (ret == b->offset) continue; @@ -240,10 +234,11 @@ static int dump_commands(int fd) char *buf = para_strdup(""), *tmp = NULL; int i; ssize_t ret; + const struct lls_command *cmd; - FOR_EACH_COMMAND(i) { - tmp = make_message("%s%s\t%s\n", buf, audiod_cmds[i].name, - audiod_cmds[i].description); + for (i = 1; (cmd = lls_cmd(i, audiod_cmd_suite)); i++) { + tmp = make_message("%s%s\t%s\n", buf, lls_command_name(cmd), + lls_purpose(cmd)); free(buf); buf = tmp; } @@ -252,74 +247,80 @@ static int dump_commands(int fd) return ret; } -static int com_help(int fd, int argc, char **argv) +static int com_help(int fd, struct lls_parse_result *lpr) { - int i, ret; - char *buf; - const char *dflt = "No such command. Available commands:\n"; - - if (argc < 2) + int ret; + char *buf, *errctx; + const struct lls_command *cmd; + + ret = lls(lls_check_arg_count(lpr, 0, 1, &errctx)); + if (ret < 0) { + if (errctx) { + buf = make_message("%s\n", errctx); + client_write(fd, buf); + free(buf); + free(errctx); + } + return ret; + } + if (lls_num_inputs(lpr) == 0) return dump_commands(fd); - FOR_EACH_COMMAND(i) { - if (strcmp(audiod_cmds[i].name, argv[1])) - continue; - buf = make_message( - "NAME\n\t%s -- %s\n" - "SYNOPSIS\n\tpara_audioc %s\n" - "DESCRIPTION\n%s\n", - argv[1], - audiod_cmds[i].description, - audiod_cmds[i].usage, - audiod_cmds[i].help - ); - ret = client_write(fd, buf); + ret = lls(lls_lookup_subcmd(lls_input(0, lpr), audiod_cmd_suite, + &errctx)); + if (ret < 0) { + buf = make_message("%s: %s\nAvailable commands:\n", errctx? + errctx : lls_input(0, lpr), para_strerror(-ret)); + if (client_write(fd, buf) >= 0) + dump_commands(fd); + free(errctx); free(buf); - return ret; + goto out; } - ret = client_write(fd, dflt); - if (ret > 0) - ret = dump_commands(fd); - return ret; + cmd = lls_cmd(ret, audiod_cmd_suite); + buf = lls_long_help(cmd); + assert(buf); + ret = client_write(fd, buf); + free(buf); +out: + return ret < 0? ret : 0; } +EXPORT_AUDIOD_CMD_HANDLER(help) -static int com_tasks(int fd, __a_unused int argc, __a_unused char **argv) +static int com_tasks(int fd, __a_unused struct lls_parse_result *lpr) { + int ret; char *tl = get_task_list(&sched); - int ret = 1; - if (tl) - ret = client_write(fd, tl); + if (!tl) /* no tasks registered yet */ + return 0; + ret = client_write(fd, tl); free(tl); return ret; } +EXPORT_AUDIOD_CMD_HANDLER(tasks) -static int com_stat(int fd, int argc, char **argv) +static int com_stat(int fd, struct lls_parse_result *lpr) { int i, ret, parser_friendly = 0; uint64_t mask = 0; const uint64_t one = 1; struct para_buffer b = {.flags = 0}; + const struct lls_opt_result *r; + unsigned num_inputs; ret = mark_fd_nonblocking(fd); if (ret < 0) return ret; - for (i = 1; i < argc; i++) { - const char *arg = argv[i]; - if (arg[0] != '-') - break; - if (!strcmp(arg, "--")) { - i++; - break; - } - if (!strncmp(arg, "-p", 2)) { - parser_friendly = 1; - b.flags = PBF_SIZE_PREFIX; - } + r = lls_opt_result(LSG_AUDIOD_CMD_STAT_OPT_PARSER_FRIENDLY, lpr); + if (lls_opt_given(r) > 0) { + parser_friendly = 1; + b.flags = PBF_SIZE_PREFIX; } - if (i >= argc) + num_inputs = lls_num_inputs(lpr); + if (num_inputs == 0) mask--; /* set all bits */ - for (; i < argc; i++) { - ret = stat_item_valid(argv[i]); + for (i = 0; i < num_inputs; i++) { + ret = stat_item_valid(lls_input(i, lpr)); if (ret < 0) return ret; mask |= (one << ret); @@ -329,91 +330,83 @@ static int com_stat(int fd, int argc, char **argv) char *item = stat_item_values[i]; if (!((one << i) & mask)) continue; - (void)WRITE_STATUS_ITEM(&b, i, "%s\n", item? item : ""); + WRITE_STATUS_ITEM(&b, i, "%s\n", item? item : ""); } ret = client_write(fd, b.buf); if (ret >= 0) ret = stat_client_add(fd, mask, parser_friendly); free(b.buf); - return ret; + return ret < 0? ret : 0; } +EXPORT_AUDIOD_CMD_HANDLER(stat) -static int com_grab(int fd, int argc, char **argv) +static int com_grab(int fd, struct lls_parse_result *lpr) { - return grab_client_new(fd, argc, argv, &sched); + int ret = grab_client_new(fd, lpr, &sched); + return ret < 0? ret : 0; } +EXPORT_AUDIOD_CMD_HANDLER(grab) -static int com_term(__a_unused int fd, __a_unused int argc, __a_unused char **argv) +static int com_term(__a_unused int fd, __a_unused struct lls_parse_result *lpr) { return -E_AUDIOD_TERM; } +EXPORT_AUDIOD_CMD_HANDLER(term) -static int com_on(__a_unused int fd, __a_unused int argc, __a_unused char **argv) +static int com_on(__a_unused int fd, __a_unused struct lls_parse_result *lpr) { audiod_status = AUDIOD_ON; return 1; } +EXPORT_AUDIOD_CMD_HANDLER(on) -static int com_off(__a_unused int fd, __a_unused int argc, __a_unused char **argv) +static int com_off(__a_unused int fd, __a_unused struct lls_parse_result *lpr) { audiod_status = AUDIOD_OFF; return 1; } +EXPORT_AUDIOD_CMD_HANDLER(off) -static int com_sb(__a_unused int fd, __a_unused int argc, __a_unused char **argv) +static int com_sb(__a_unused int fd, __a_unused struct lls_parse_result *lpr) { audiod_status = AUDIOD_STANDBY; return 1; } +EXPORT_AUDIOD_CMD_HANDLER(sb) -static int com_cycle(__a_unused int fd, int argc, char **argv) +static int com_cycle(__a_unused int fd, __a_unused struct lls_parse_result *lpr) { switch (audiod_status) { - case AUDIOD_ON: - return com_sb(fd, argc, argv); - break; - case AUDIOD_OFF: - return com_on(fd, argc, argv); - break; - case AUDIOD_STANDBY: - return com_off(fd, argc, argv); - break; + case AUDIOD_ON: audiod_status = AUDIOD_STANDBY; break; + case AUDIOD_OFF: audiod_status = AUDIOD_ON; break; + case AUDIOD_STANDBY: audiod_status = AUDIOD_OFF; break; } return 1; } +EXPORT_AUDIOD_CMD_HANDLER(cycle) -static int com_version(int fd, int argc, char **argv) +static int com_version(int fd, struct lls_parse_result *lpr) { int ret; char *msg; + const struct lls_opt_result *r_v; - if (argc > 1 && strcmp(argv[1], "-v") == 0) + r_v = lls_opt_result(LSG_AUDIOD_CMD_VERSION_OPT_VERBOSE, lpr); + if (lls_opt_given(r_v)) msg = make_message("%s", version_text("audiod")); else msg = make_message("%s\n", version_single_line("audiod")); ret = client_write(fd, msg); free(msg); - return ret; -} - -static int check_perms(uid_t uid, uid_t *whitelist) -{ - int i; - - if (!conf.user_allow_given) - return 1; - for (i = 0; i < conf.user_allow_given; i++) - if (uid == whitelist[i]) - return 1; - return -E_UCRED_PERM; + return ret < 0? ret : 0; } +EXPORT_AUDIOD_CMD_HANDLER(version) /** * Handle arriving connections on the local socket. * * \param accept_fd The fd to accept connections on. * \param rfds If \a accept_fd is not set in \a rfds, do nothing. - * \param uid_whitelist Array of UIDs which are allowed to connect. * * This is called in each iteration of the select loop. If there is an incoming * connection on \a accept_fd, this function reads the command sent by the peer, @@ -426,12 +419,16 @@ static int check_perms(uid_t uid, uid_t *whitelist) * * \sa para_accept(), recv_cred_buffer() * */ -int handle_connect(int accept_fd, fd_set *rfds, uid_t *uid_whitelist) +int handle_connect(int accept_fd, fd_set *rfds) { - int i, argc, ret, clifd; + int argc, ret, clifd; char buf[MAXLINE], **argv = NULL; struct sockaddr_un unix_addr; uid_t uid; + const struct lls_command *cmd; + struct lls_parse_result *lpr; + char *errctx; + const struct audiod_command_info *aci; ret = para_accept(accept_fd, rfds, &unix_addr, sizeof(struct sockaddr_un), &clifd); if (ret <= 0) @@ -440,26 +437,35 @@ int handle_connect(int accept_fd, fd_set *rfds, uid_t *uid_whitelist) if (ret < 0) goto out; uid = ret; - PARA_INFO_LOG("connection from user %i, buf: %s\n", ret, buf); - ret = check_perms(uid, uid_whitelist); - if (ret < 0) + PARA_INFO_LOG("connection from UID %d, buf: %s\n", ret, buf); + ret = -E_UCRED_PERM; + if (!uid_is_whitelisted(uid)) goto out; ret = create_argv(buf, "\n", &argv); if (ret <= 0) goto out; argc = ret; - //PARA_INFO_LOG("argv[0]: %s, argc = %d\n", argv[0], argc); - FOR_EACH_COMMAND(i) { - if (strcmp(audiod_cmds[i].name, argv[0])) - continue; - ret = audiod_cmds[i].handler(clifd, argc, argv); + ret = lls(lls_lookup_subcmd(argv[0], audiod_cmd_suite, &errctx)); + if (ret < 0) goto out; - } - ret = -E_INVALID_AUDIOD_CMD; + cmd = lls_cmd(ret, audiod_cmd_suite); + ret = lls(lls_parse(argc, argv, cmd, &lpr, &errctx)); + if (ret < 0) + goto out; + aci = lls_user_data(cmd); + ret = aci->handler(clifd, lpr); + lls_free_parse_result(lpr, cmd); out: free_argv(argv); if (ret < 0 && ret != -E_CLIENT_WRITE) { - char *tmp = make_message("%s\n", para_strerror(-ret)); + char *tmp; + if (errctx) { + tmp = make_message("%s\n", errctx); + free(errctx); + client_write(clifd, tmp); + free(tmp); + } + tmp = make_message("%s\n", para_strerror(-ret)); client_write(clifd, tmp); free(tmp); }