diff --git a/alsactl/alsactl.1 b/alsactl/alsactl.1 index 0bd6c1b..8296663 100644 --- a/alsactl/alsactl.1 +++ b/alsactl/alsactl.1 @@ -98,6 +98,10 @@ Print alsactl version number. \fI\-f, \-\-file\fP Select the configuration file to use. The default is /var/lib/alsa/asound.state. +.TP +\fI\-a, \-\-config-dir\fP +Select the boot / hotplug ALSA configuration directory to use. The default is /var/lib/alsa. + .TP \fI\-l, \-\-lock\fP Use the file locking to serialize the concurrent access to the state file (this diff --git a/alsactl/alsactl.c b/alsactl/alsactl.c index c800087..a011284 100644 --- a/alsactl/alsactl.c +++ b/alsactl/alsactl.c @@ -31,8 +31,11 @@ #include #include "alsactl.h" +#ifndef SYS_ASOUND_DIR +#define SYS_ASOUND_DIR "/var/lib/alsa" +#endif #ifndef SYS_ASOUNDRC -#define SYS_ASOUNDRC "/var/lib/alsa/asound.state" +#define SYS_ASOUNDRC SYS_ASOUND_DIR "/asound.state" #endif #ifndef SYS_PIDFILE #define SYS_PIDFILE "/var/run/alsactl.pid" @@ -73,6 +76,7 @@ static struct arg args[] = { { 'v', "version", "print version of this program" }, { HEADER, NULL, "Available state options:" }, { FILEARG | 'f', "file", "configuration file (default " SYS_ASOUNDRC ")" }, +{ FILEARG | 'a', "config-dir", "boot / hotplug configuration directory (default " SYS_ASOUND_DIR ")" }, { 'l', "lock", "use file locking to serialize concurrent access" }, { 'L', "no-lock", "do not use file locking to serialize concurrent access" }, { FILEARG | 'O', "lock-state-file", "state lock file path (default " SYS_LOCKFILE ")" }, @@ -227,6 +231,7 @@ int main(int argc, char *argv[]) "/dev/snd/hwC", NULL }; + char *cfgdir = SYS_ASOUND_DIR; char *cfgfile = SYS_ASOUNDRC; char *initfile = DATADIR "/init/00main"; char *pidfile = SYS_PIDFILE; @@ -286,6 +291,9 @@ int main(int argc, char *argv[]) case 'f': cfgfile = optarg; break; + case 'a': + cfgdir = optarg; + break; case 'l': do_lock = 1; break; @@ -420,7 +428,7 @@ int main(int argc, char *argv[]) snd_lib_error_set_handler(error_handler); if (!strcmp(cmd, "init")) { - res = init(initfile, initflags | FLAG_UCM_FBOOT | FLAG_UCM_BOOT, cardname); + res = init(cfgdir, initfile, initflags | FLAG_UCM_FBOOT | FLAG_UCM_BOOT, cardname); snd_config_update_free_global(); } else if (!strcmp(cmd, "store")) { res = save_state(cfgfile, cardname); @@ -429,7 +437,7 @@ int main(int argc, char *argv[]) !strcmp(cmd, "nrestore")) { if (removestate) remove(statefile); - res = load_state(cfgfile, initfile, initflags, cardname, init_fallback); + res = load_state(cfgdir, cfgfile, initfile, initflags, cardname, init_fallback); if (!strcmp(cmd, "rdaemon")) { do_nice(use_nice, sched_idle); res = state_daemon(cfgfile, cardname, period, pidfile); diff --git a/alsactl/alsactl.h b/alsactl/alsactl.h index ca723e3..bbdf6c8 100644 --- a/alsactl/alsactl.h +++ b/alsactl/alsactl.h @@ -46,12 +46,13 @@ const char *snd_card_iterator_next(struct snd_card_iterator *iter); int snd_card_iterator_error(struct snd_card_iterator *iter); 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(const char *cfgdir, const char *file, int flags, const char *cardname); int init_ucm(int flags, int cardno); int state_lock(const char *file, int timeout); int state_unlock(int fd, const char *file); int save_state(const char *file, const char *cardname); -int load_state(const char *file, const char *initfile, int initflags, +int load_state(const char *cfgdir, const char *file, + const char *initfile, int initflags, const char *cardname, int do_init); int power(const char *argv[], int argc); int monitor(const char *name); @@ -59,6 +60,7 @@ int state_daemon(const char *file, const char *cardname, int period, const char *pidfile); int state_daemon_kill(const char *pidfile, const char *cmd); int clean(const char *cardname, char *const *extra_args); +int snd_card_clean_cfgdir(const char *cfgdir, int cardno); /* utils */ diff --git a/alsactl/init_parse.c b/alsactl/init_parse.c index ab2c906..9d0f473 100644 --- a/alsactl/init_parse.c +++ b/alsactl/init_parse.c @@ -1743,7 +1743,7 @@ static int parse(struct space *space, const char *filename) return err ? err : -abs(space->exit_code); } -int init(const char *filename, int flags, const char *cardname) +int init(const char *cfgdir, const char *filename, int flags, const char *cardname) { struct space *space; struct snd_card_iterator iter; @@ -1752,6 +1752,12 @@ int init(const char *filename, int flags, const char *cardname) sysfs_init(); err = snd_card_iterator_sinit(&iter, cardname); while (snd_card_iterator_next(&iter)) { + err = snd_card_clean_cfgdir(cfgdir, iter.card); + if (err < 0) { + if (lasterr == 0) + lasterr = err; + continue; + } err = init_ucm(flags, iter.card); if (err == 0) continue; diff --git a/alsactl/state.c b/alsactl/state.c index 0612970..44fda3f 100644 --- a/alsactl/state.c +++ b/alsactl/state.c @@ -1618,7 +1618,8 @@ out: return err; } -int load_state(const char *file, const char *initfile, int initflags, +int load_state(const char *cfgdir, const char *file, + const char *initfile, int initflags, const char *cardname, int do_init) { int err, finalerr = 0, open_failed; @@ -1640,7 +1641,7 @@ int load_state(const char *file, const char *initfile, int initflags, while ((cardname1 = snd_card_iterator_next(&iter)) != NULL) { if (!do_init) break; - err = init(initfile, initflags | FLAG_UCM_FBOOT | FLAG_UCM_BOOT, cardname1); + err = init(cfgdir, initfile, initflags | FLAG_UCM_FBOOT | FLAG_UCM_BOOT, cardname1); if (err < 0) { finalerr = err; initfailed(iter.card, "init", err); @@ -1661,7 +1662,7 @@ int load_state(const char *file, const char *initfile, int initflags, init_ucm(initflags | FLAG_UCM_FBOOT, iter.card); /* do a check if controls matches state file */ if (do_init && set_controls(iter.card, config, 0)) { - err = init(initfile, initflags | FLAG_UCM_BOOT, cardname1); + err = init(cfgdir, initfile, initflags | FLAG_UCM_BOOT, cardname1); if (err < 0) { initfailed(iter.card, "init", err); finalerr = err; diff --git a/alsactl/utils.c b/alsactl/utils.c index d0b1ac6..c79fd95 100644 --- a/alsactl/utils.c +++ b/alsactl/utils.c @@ -284,3 +284,46 @@ int snd_card_iterator_error(struct snd_card_iterator *iter) { return iter->first ? (ignore_nocards ? 0 : -ENODEV) : 0; } + +static int cleanup_filename_filter(const struct dirent *dirent) +{ + size_t flen; + + if (dirent == NULL) + return 0; + if (dirent->d_type == DT_DIR) + return 0; + + flen = strlen(dirent->d_name); + if (flen <= 5) + return 0; + + if (strncmp(&dirent->d_name[flen-5], ".conf", 5) == 0) + return 1; + + return 0; +} + +int snd_card_clean_cfgdir(const char *cfgdir, int cardno) +{ + char path[PATH_MAX]; + struct dirent **list; + int lasterr = 0, n, j; + + snprintf(path, sizeof(path), "%s/card%d.conf.d", cfgdir, cardno); + n = scandir(path, &list, cleanup_filename_filter, NULL); + if (n < 0) { + if (errno == ENOENT) + return 0; + return -errno; + } + for (j = 0; j < n; j++) { + snprintf(path, sizeof(path), "%s/card%d.conf.d/%s", cfgdir, cardno, list[j]->d_name); + if (remove(path)) { + error("Unable to remove file '%s'", path); + lasterr = -errno; + } + } + + return lasterr; +}