28
28
#include <assert.h>
30
32
#include <alsa/asoundlib.h>
31
33
#include "alsactl.h"
33
35
#ifndef SYS_ASOUNDRC
34
36
#define SYS_ASOUNDRC "/var/lib/alsa/asound.state"
39
#define SYS_PIDFILE "/var/run/alsactl.pid"
38
43
int force_restore = 1;
39
44
int ignore_nocards = 0;
41
48
char *statefile = NULL;
52
#define FILEARG 0x0400
56
#define CARDCMD 0x4000
57
#define KILLCMD 0x8000
65
static struct arg args[] = {
66
{ TITLE, NULL, "Usage: alsactl <options> command" },
67
{ HEADER, NULL, "global options:" },
68
{ 'h', "help", "this help" },
69
{ 'd', "debug", "debug mode" },
70
{ 'v', "version", "print version of this program" },
71
{ HEADER, NULL, "Available state options:" },
72
{ FILEARG | 'f', "file", "configuration file (default " SYS_ASOUNDRC ")" },
73
{ 'l', "lock", "use file locking to serialize concurrent access" },
74
{ 'F', "force", "try to restore the matching controls as much as possible" },
75
{ 0, NULL, " (default mode)" },
76
{ 'g', "ignore", "ignore 'No soundcards found' error" },
77
{ 'P', "pedantic", "do not restore mismatching controls (old default)" },
78
{ 'I', "no-init-fallback", "" },
79
{ 0, NULL, "don't initialize even if restore fails" },
80
{ FILEARG | 'r', "runstate", "save restore and init state to this file (only errors)" },
81
{ 0, NULL, " default settings is 'no file set'" },
82
{ 'R', "remove", "remove runstate file at first, otherwise append errors" },
83
{ INTARG | 'p', "period", "store period in seconds for the daemon command" },
84
{ FILEARG | 'e', "pid-file", "pathname for the process id (daemon mode)" },
85
{ HEADER, NULL, "Available init options:" },
86
{ ENVARG | 'E', "env", "set environment variable for init phase (NAME=VALUE)" },
87
{ FILEARG | 'i', "initfile", "main configuation file for init phase" },
88
{ 0, NULL, " (default " DATADIR "/init/00main)" },
89
{ 'b', "background", "run daemon in background" },
90
{ 's', "syslog", "use syslog for messages" },
91
{ INTARG | 'n', "nice", "set the process priority (see 'man nice')" },
92
{ 'c', "sched-idle", "set the process scheduling policy to idle (SCHED_IDLE)" },
93
{ HEADER, NULL, "Available commands:" },
94
{ CARDCMD, "store", "save current driver setup for one or each soundcards" },
95
{ EMPCMD, NULL, " to configuration file" },
96
{ CARDCMD, "restore", "load current driver setup for one or each soundcards" },
97
{ EMPCMD, NULL, " from configuration file" },
98
{ CARDCMD, "nrestore", "like restore, but notify the daemon to rescan soundcards" },
99
{ CARDCMD, "init", "initialize driver to a default state" },
100
{ CARDCMD, "daemon", "store state periodically for one or each soundcards" },
101
{ CARDCMD, "rdaemon", "like daemon but do the state restore at first" },
102
{ KILLCMD, "kill", "notify daemon to quit, rescan or save_and_quit" },
43
106
static void help(void)
45
printf("Usage: alsactl <options> command\n");
46
printf("\nAvailable global options:\n");
47
printf(" -h,--help this help\n");
48
printf(" -d,--debug debug mode\n");
49
printf(" -v,--version print version of this program\n");
50
printf("\nAvailable state options:\n");
51
printf(" -f,--file # configuration file (default " SYS_ASOUNDRC ")\n");
52
printf(" -F,--force try to restore the matching controls as much as possible\n");
53
printf(" (default mode)\n");
54
printf(" -g,--ignore ignore 'No soundcards found' error\n");
55
printf(" -P,--pedantic do not restore mismatching controls (old default)\n");
56
printf(" -I,--no-init-fallback\n"
57
" don't initialize even if restore fails\n");
58
printf(" -r,--runstate # save restore and init state to this file (only errors)\n");
59
printf(" default settings is 'no file set'\n");
60
printf(" -R,--remove remove runstate file at first, otherwise append errors\n");
61
printf("\nAvailable init options:\n");
62
printf(" -E,--env #=# set environment variable for init phase (NAME=VALUE)\n");
63
printf(" -i,--initfile # main configuation file for init phase (default " DATADIR "/init/00main)\n");
65
printf("\nAvailable commands:\n");
66
printf(" store <card #> save current driver setup for one or each soundcards\n");
67
printf(" to configuration file\n");
68
printf(" restore <card #> load current driver setup for one or each soundcards\n");
69
printf(" from configuration file\n");
70
printf(" init <card #> initialize driver to a default state\n");
108
struct arg *n = args, *a;
109
char *larg, sa[4], buf[32];
119
if (sarg & (HEADER|TITLE)) {
120
printf("%s%s\n", (sarg & HEADER) != 0 ? "\n" : "",
126
if (sarg & (EMPCMD|CARDCMD|KILLCMD)) {
128
strcat(buf, "<card>");
129
else if (sarg & KILLCMD)
130
strcat(buf, "<cmd>");
131
printf(" %-8s %-6s %s\n", larg ? larg : "",
136
sprintf(buf, "%s%s%s", sa[1] ? sa : "",
137
larg ? "--" : "", larg ? larg : "");
140
else if (sarg & (FILEARG|INTARG))
142
printf(" %-15s %s\n", buf, a->comment);
146
#define NO_NICE (-100000)
148
static void do_nice(int use_nice, int sched_idle)
150
struct sched_param sched_param;
152
if (use_nice != NO_NICE && nice(use_nice) < 0)
153
error("nice(%i): %s", use_nice, strerror(errno));
155
if (sched_getparam(0, &sched_param) >= 0) {
156
sched_param.sched_priority = 0;
157
if (!sched_setscheduler(0, SCHED_RR, &sched_param))
158
error("sched_setparam failed: %s", strerror(errno));
160
error("sched_getparam failed: %s", strerror(errno));
73
165
int main(int argc, char *argv[])
75
static const struct option long_option[] =
77
{"help", 0, NULL, 'h'},
78
{"file", 1, NULL, 'f'},
79
{"env", 1, NULL, 'E'},
80
{"initfile", 1, NULL, 'i'},
81
{"no-init-fallback", 0, NULL, 'I'},
82
{"force", 0, NULL, 'F'},
83
{"ignore", 0, NULL, 'g'},
84
{"pedantic", 0, NULL, 'P'},
85
{"runstate", 0, NULL, 'r'},
86
{"remove", 0, NULL, 'R'},
87
{"debug", 0, NULL, 'd'},
88
{"version", 0, NULL, 'v'},
91
167
static const char *const devfiles[] = {
92
168
"/dev/snd/controlC",
177
if (!strcmp(argv[optind], "init")) {
325
/* the global system file should be always locked */
326
if (strcmp(cfgfile, SYS_ASOUNDRC) == 0)
329
/* when running in background, use syslog for reports */
336
daemoncmd = strcmp(cmd, "daemon") == 0 || strcmp(cmd, "rdaemon") == 0;
339
openlog("alsactl", LOG_CONS|LOG_PID, LOG_DAEMON);
341
syslog(LOG_INFO, "alsactl " SND_UTIL_VERSION_STR " daemon started");
344
if (!strcmp(cmd, "init")) {
178
345
res = init(initfile, cardname);
179
} else if (!strcmp(argv[optind], "store")) {
346
snd_config_update_free_global();
347
} else if (!strcmp(cmd, "store")) {
180
348
res = save_state(cfgfile, cardname);
181
} else if (!strcmp(argv[optind], "restore")) {
349
} else if (!strcmp(cmd, "restore") ||
350
!strcmp(cmd, "rdaemon") ||
351
!strcmp(cmd, "nrestore")) {
183
353
remove(statefile);
184
354
res = load_state(cfgfile, initfile, cardname, init_fallback);
355
if (!strcmp(cmd, "rdaemon")) {
356
do_nice(use_nice, sched_idle);
357
res = state_daemon(cfgfile, cardname, period, pidfile);
359
if (!strcmp(cmd, "nrestore"))
360
res = state_daemon_kill(pidfile, "rescan");
361
} else if (!strcmp(cmd, "daemon")) {
362
do_nice(use_nice, sched_idle);
363
res = state_daemon(cfgfile, cardname, period, pidfile);
364
} else if (!strcmp(cmd, "kill")) {
365
res = state_daemon_kill(pidfile, cardname);
186
fprintf(stderr, "alsactl: Unknown command '%s'...\n",
367
fprintf(stderr, "alsactl: Unknown command '%s'...\n", cmd);
191
371
snd_config_update_free_global();
374
syslog(LOG_INFO, "alsactl daemon stopped");
192
377
return res < 0 ? -res : 0;