From c1474594dcb3fa741d00966630cb5770e4e504b0 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Sun, 7 Mar 2021 19:58:33 +0100 Subject: [PATCH] alsactl: add dump-cfg and dump-state commands Signed-off-by: Jaroslav Kysela --- alsactl/alsactl.1 | 4 ++++ alsactl/alsactl.c | 51 ++++++++++++++++++++++++++++++++++++++++++-- alsactl/alsactl.h | 3 +++ alsactl/clean.c | 1 - alsactl/daemon.c | 1 - alsactl/init_parse.c | 1 - alsactl/state.c | 32 +++++---------------------- alsactl/utils.c | 44 ++++++++++++++++++++++++++++++++++++-- 8 files changed, 103 insertions(+), 34 deletions(-) diff --git a/alsactl/alsactl.1 b/alsactl/alsactl.1 index 1c9c9b9..5452ef5 100644 --- a/alsactl/alsactl.1 +++ b/alsactl/alsactl.1 @@ -41,6 +41,10 @@ control device. \fIclean\fP clean the controls created by applications. +\fIdump-state\fP dump the current state (all cards). + +\fIdump-cfg\fP dump the current configuration (all cards, hooks are evaluated). + If no soundcards are specified, setup for all cards will be saved, loaded or monitored. diff --git a/alsactl/alsactl.c b/alsactl/alsactl.c index a3a6bfa..1d2ff3e 100644 --- a/alsactl/alsactl.c +++ b/alsactl/alsactl.c @@ -29,7 +29,6 @@ #include #include #include -#include #include "alsactl.h" #ifndef SYS_ASOUNDRC @@ -111,6 +110,8 @@ static struct arg args[] = { { CARDCMD, "rdaemon", "like daemon but do the state restore at first" }, { KILLCMD, "kill", "notify daemon to quit, rescan or save_and_quit" }, { CARDCMD, "monitor", "monitor control events" }, +{ EMPCMD, "dump-state", "dump the state (for all cards)" }, +{ EMPCMD, "dump-cfg", "dump the configuration (expanded, for all cards)" }, { 0, NULL, NULL } }; @@ -139,7 +140,7 @@ static void help(void) strcat(buf, ""); else if (sarg & KILLCMD) strcat(buf, ""); - printf(" %-8s %-6s %s\n", larg ? larg : "", + printf(" %-10s %-6s %s\n", larg ? larg : "", buf, a->comment); continue; } @@ -154,6 +155,48 @@ static void help(void) } } +static int dump_config_tree(snd_config_t *top) +{ + snd_output_t *out; + int err; + + err = snd_output_stdio_attach(&out, stdout, 0); + if (err < 0) + return err; + err = snd_config_save(top, out); + snd_output_close(out); + return 0; +} + +static int dump_state(const char *file) +{ + snd_config_t *top; + int err; + + err = load_configuration(file, &top, NULL); + if (err < 0) + return err; + err = dump_config_tree(top); + snd_config_delete(top); + snd_config_update_free_global(); + return err; +} + +static int dump_configuration(void) +{ + snd_config_t *top, *cfg2; + int err; + + err = snd_config_update_ref(&top); + if (err < 0) + return err; + /* expand cards.* tree */ + snd_config_search_definition(top, "cards", "dummy", &cfg2); + err = dump_config_tree(top); + snd_config_unref(top); + return err; +} + #define NO_NICE (-100000) static void do_nice(int use_nice, int sched_idle) @@ -399,6 +442,10 @@ int main(int argc, char *argv[]) res = monitor(cardname); } else if (!strcmp(cmd, "clean")) { res = clean(cardname, extra_args); + } else if (!strcmp(cmd, "dump-state")) { + res = dump_state(cfgfile); + } else if (!strcmp(cmd, "dump-cfg")) { + res = dump_configuration(); } else { fprintf(stderr, "alsactl: Unknown command '%s'...\n", cmd); res = -ENODEV; diff --git a/alsactl/alsactl.h b/alsactl/alsactl.h index 74079de..119e3b4 100644 --- a/alsactl/alsactl.h +++ b/alsactl/alsactl.h @@ -1,3 +1,5 @@ +#include + extern int debugflag; extern int force_restore; extern int ignore_nocards; @@ -28,6 +30,7 @@ void error_handler(const char *file, int line, const char *function, int err, co #define FLAG_UCM_DISABLED (1<<0) #define FLAG_UCM_DEFAULTS (1<<1) +int load_configuration(const char *file, snd_config_t **top, int *open_failed); int init(const char *file, int flags, const char *cardname); int init_ucm(int flags, int cardno); int state_lock(const char *file, int timeout); diff --git a/alsactl/clean.c b/alsactl/clean.c index b74714f..4808225 100644 --- a/alsactl/clean.c +++ b/alsactl/clean.c @@ -26,7 +26,6 @@ #include #include #include -#include #include "alsactl.h" static int clean_one_control(snd_ctl_t *handle, snd_ctl_elem_id_t *elem_id, diff --git a/alsactl/daemon.c b/alsactl/daemon.c index ee03991..5109015 100644 --- a/alsactl/daemon.c +++ b/alsactl/daemon.c @@ -29,7 +29,6 @@ #include #include #include -#include #include "alsactl.h" struct id_list { diff --git a/alsactl/init_parse.c b/alsactl/init_parse.c index 7a6402a..e7b352c 100644 --- a/alsactl/init_parse.c +++ b/alsactl/init_parse.c @@ -37,7 +37,6 @@ #include #include #include -#include #include "aconfig.h" #include "alsactl.h" #include "list.h" diff --git a/alsactl/state.c b/alsactl/state.c index ea1d3bc..71e5465 100644 --- a/alsactl/state.c +++ b/alsactl/state.c @@ -27,7 +27,6 @@ #include #include #include -#include #include "alsactl.h" @@ -1648,38 +1647,17 @@ out: int load_state(const char *file, const char *initfile, int initflags, const char *cardname, int do_init) { - int err, finalerr = 0; + int err, finalerr = 0, open_failed; snd_config_t *config; - snd_input_t *in; - int stdio, lock_fd = -EINVAL; - err = snd_config_top(&config); - if (err < 0) { - error("snd_config_top error: %s", snd_strerror(err)); + err = load_configuration(file, &config, &open_failed); + if (err < 0 && !open_failed) return err; - } - stdio = !strcmp(file, "-"); - if (stdio) { - err = snd_input_stdio_attach(&in, stdin, 0); - } else { - lock_fd = state_lock(file, 10); - err = lock_fd >= 0 ? snd_input_stdio_open(&in, file, "r") : lock_fd; - } - if (err >= 0) { - err = snd_config_load(config, in); - snd_input_close(in); - if (lock_fd >= 0) - state_unlock(lock_fd, file); - if (err < 0) { - error("snd_config_load error: %s", snd_strerror(err)); - goto out; - } - } else { + + if (open_failed) { int card, first = 1; char cardname1[16]; - if (lock_fd >= 0) - state_unlock(lock_fd, file); error("Cannot open %s for reading: %s", file, snd_strerror(err)); finalerr = err; if (cardname) { diff --git a/alsactl/utils.c b/alsactl/utils.c index f67421d..ede7319 100644 --- a/alsactl/utils.c +++ b/alsactl/utils.c @@ -30,8 +30,6 @@ #include #include #include - -#include #include "alsactl.h" int file_map(const char *filename, char **buf, size_t *bufsize) @@ -193,3 +191,45 @@ void error_handler(const char *file, int line, const char *function, int err, co fprintf(stderr, "alsa-lib %s:%i:(%s) %s%s%s\n", file, line, function, buf, err ? ": " : "", err ? snd_strerror(err) : ""); } + +int load_configuration(const char *file, snd_config_t **top, int *open_failed) +{ + snd_config_t *config; + snd_input_t *in; + int err, stdio_flag, lock_fd = -EINVAL; + + *top = NULL; + if (open_failed) + *open_failed = 0; + err = snd_config_top(&config); + if (err < 0) { + error("snd_config_top error: %s", snd_strerror(err)); + return err; + } + stdio_flag = !strcmp(file, "-"); + if (stdio_flag) { + err = snd_input_stdio_attach(&in, stdin, 0); + } else { + lock_fd = state_lock(file, 10); + err = lock_fd >= 0 ? snd_input_stdio_open(&in, file, "r") : lock_fd; + } + if (err < 0) { + if (open_failed) + *open_failed = 1; + goto out; + } + err = snd_config_load(config, in); + snd_input_close(in); + if (lock_fd >= 0) + state_unlock(lock_fd, file); + if (err < 0) { + error("snd_config_load error: %s", snd_strerror(err)); +out: + snd_config_delete(config); + snd_config_update_free_global(); + return err; + } else { + *top = config; + return 0; + } +}