\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
#include <sched.h>
#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"
{ '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 ")" },
"/dev/snd/hwC",
NULL
};
+ char *cfgdir = SYS_ASOUND_DIR;
char *cfgfile = SYS_ASOUNDRC;
char *initfile = DATADIR "/init/00main";
char *pidfile = SYS_PIDFILE;
case 'f':
cfgfile = optarg;
break;
+ case 'a':
+ cfgdir = optarg;
+ break;
case 'l':
do_lock = 1;
break;
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);
!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);
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);
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 */
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;
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;
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;
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);
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;
{
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;
+}