mirror of
https://github.com/alsa-project/alsa-utils
synced 2024-11-10 00:25:43 +01:00
alsactl: Improved command line argument handling...
Improve command line argument handling for future extensions. Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
parent
cc5c3357cf
commit
067f4f3256
3 changed files with 141 additions and 65 deletions
|
@ -46,66 +46,102 @@ int use_syslog = 0;
|
||||||
char *command;
|
char *command;
|
||||||
char *statefile = NULL;
|
char *statefile = NULL;
|
||||||
|
|
||||||
|
#define TITLE 0x0100
|
||||||
|
#define HEADER 0x0200
|
||||||
|
#define FILEARG 0x0400
|
||||||
|
#define ENVARG 0x0800
|
||||||
|
#define INTARG 0x1000
|
||||||
|
#define EMPCMD 0x2000
|
||||||
|
#define CARDCMD 0x4000
|
||||||
|
#define KILLCMD 0x8000
|
||||||
|
|
||||||
|
struct arg {
|
||||||
|
int sarg;
|
||||||
|
char *larg;
|
||||||
|
char *comment;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct arg args[] = {
|
||||||
|
{ TITLE, NULL, "Usage: alsactl <options> command" },
|
||||||
|
{ HEADER, NULL, "global options:" },
|
||||||
|
{ 'h', "help", "this help" },
|
||||||
|
{ 'd', "debug", "debug mode" },
|
||||||
|
{ 'v', "version", "print version of this program" },
|
||||||
|
{ HEADER, NULL, "Available state options:" },
|
||||||
|
{ FILEARG | 'f', "file", "configuration file (default " SYS_ASOUNDRC ")" },
|
||||||
|
{ 'l', "lock", "use file locking to serialize concurrent access" },
|
||||||
|
{ 'F', "force", "try to restore the matching controls as much as possible" },
|
||||||
|
{ 0, NULL, " (default mode)" },
|
||||||
|
{ 'g', "ignore", "ignore 'No soundcards found' error" },
|
||||||
|
{ 'P', "pedantic", "do not restore mismatching controls (old default)" },
|
||||||
|
{ 'I', "no-init-fallback", "" },
|
||||||
|
{ 0, NULL, "don't initialize even if restore fails" },
|
||||||
|
{ FILEARG | 'r', "runstate", "save restore and init state to this file (only errors)" },
|
||||||
|
{ 0, NULL, " default settings is 'no file set'" },
|
||||||
|
{ 'R', "remove", "remove runstate file at first, otherwise append errors" },
|
||||||
|
{ INTARG | 'p', "period", "store period in seconds for the daemon command" },
|
||||||
|
{ FILEARG | 'e', "pid-file", "pathname for the process id (daemon mode)" },
|
||||||
|
{ HEADER, NULL, "Available init options:" },
|
||||||
|
{ ENVARG | 'E', "env", "set environment variable for init phase (NAME=VALUE)" },
|
||||||
|
{ FILEARG | 'i', "initfile", "main configuation file for init phase" },
|
||||||
|
{ 0, NULL, " (default " DATADIR "/init/00main)" },
|
||||||
|
{ 'b', "background", "run daemon in background" },
|
||||||
|
{ 's', "syslog", "use syslog for messages" },
|
||||||
|
{ HEADER, NULL, "Available commands:" },
|
||||||
|
{ CARDCMD, "store", "save current driver setup for one or each soundcards" },
|
||||||
|
{ EMPCMD, NULL, " to configuration file" },
|
||||||
|
{ CARDCMD, "restore", "load current driver setup for one or each soundcards" },
|
||||||
|
{ EMPCMD, NULL, " from configuration file" },
|
||||||
|
{ CARDCMD, "nrestore", "like restore, but notify the daemon to rescan soundcards" },
|
||||||
|
{ CARDCMD, "init", "initialize driver to a default state" },
|
||||||
|
{ CARDCMD, "daemon", "store state periodically for one or each soundcards" },
|
||||||
|
{ CARDCMD, "rdaemon", "like daemon but do the state restore at first" },
|
||||||
|
{ KILLCMD, "kill", "notify daemon to quit, rescan or save_and_quit" },
|
||||||
|
{ 0, NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
static void help(void)
|
static void help(void)
|
||||||
{
|
{
|
||||||
printf("Usage: alsactl <options> command\n");
|
struct arg *n = args, *a;
|
||||||
printf("\nAvailable global options:\n");
|
char *larg, sa[4], buf[32];
|
||||||
printf(" -h,--help this help\n");
|
int sarg;
|
||||||
printf(" -d,--debug debug mode\n");
|
|
||||||
printf(" -v,--version print version of this program\n");
|
sa[0] = '-';
|
||||||
printf("\nAvailable state options:\n");
|
sa[2] = ',';
|
||||||
printf(" -f,--file # configuration file (default " SYS_ASOUNDRC ")\n");
|
sa[3] = '\0';
|
||||||
printf(" -l,--lock use file locking to serialize concurrent access\n");
|
while (n->comment) {
|
||||||
printf(" -F,--force try to restore the matching controls as much as possible\n");
|
a = n;
|
||||||
printf(" (default mode)\n");
|
n++;
|
||||||
printf(" -g,--ignore ignore 'No soundcards found' error\n");
|
sarg = a->sarg;
|
||||||
printf(" -P,--pedantic do not restore mismatching controls (old default)\n");
|
if (sarg & (HEADER|TITLE)) {
|
||||||
printf(" -I,--no-init-fallback\n"
|
printf("%s%s\n", (sarg & HEADER) != 0 ? "\n" : "",
|
||||||
" don't initialize even if restore fails\n");
|
a->comment);
|
||||||
printf(" -r,--runstate # save restore and init state to this file (only errors)\n");
|
continue;
|
||||||
printf(" default settings is 'no file set'\n");
|
}
|
||||||
printf(" -R,--remove remove runstate file at first, otherwise append errors\n");
|
buf[0] = '\0';
|
||||||
printf(" -p,--period store period in seconds for the daemon command\n");
|
larg = a->larg;
|
||||||
printf(" -e,--pid-file pathname for the process id (daemon mode)\n");
|
if (sarg & (EMPCMD|CARDCMD|KILLCMD)) {
|
||||||
printf("\nAvailable init options:\n");
|
if (sarg & CARDCMD)
|
||||||
printf(" -E,--env #=# set environment variable for init phase (NAME=VALUE)\n");
|
strcat(buf, "<card>");
|
||||||
printf(" -i,--initfile # main configuation file for init phase (default " DATADIR "/init/00main)\n");
|
else if (sarg & KILLCMD)
|
||||||
printf("\n");
|
strcat(buf, "<cmd>");
|
||||||
printf("\nAvailable commands:\n");
|
printf(" %-8s %-6s %s\n", larg ? larg : "",
|
||||||
printf(" store <card #> save current driver setup for one or each soundcards\n");
|
buf, a->comment);
|
||||||
printf(" to configuration file\n");
|
continue;
|
||||||
printf(" restore <card #> load current driver setup for one or each soundcards\n");
|
}
|
||||||
printf(" from configuration file\n");
|
sa[1] = a->sarg;
|
||||||
printf(" nrestore <card #> like restore, but notify the daemon to rescan soundcards\n");
|
sprintf(buf, "%s%s%s", sa[1] ? sa : "",
|
||||||
printf(" init <card #> initialize driver to a default state\n");
|
larg ? "--" : "", larg ? larg : "");
|
||||||
printf(" daemon <card #> store state periodically for one or each soundcards\n");
|
if (sarg & ENVARG)
|
||||||
printf(" rdaemon <card #> like daemon but do the state restore at first\n");
|
strcat(buf, " #=#");
|
||||||
printf(" kill <cmd> notify daemon to quit, rescan or save_and_quit\n");
|
else if (sarg & (FILEARG|INTARG))
|
||||||
|
strcat(buf, " #");
|
||||||
|
printf(" %-15s %s\n", buf, a->comment);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
static const struct option long_option[] =
|
|
||||||
{
|
|
||||||
{"help", 0, NULL, 'h'},
|
|
||||||
{"file", 1, NULL, 'f'},
|
|
||||||
{"lock", 0, NULL, 'l'},
|
|
||||||
{"env", 1, NULL, 'E'},
|
|
||||||
{"initfile", 1, NULL, 'i'},
|
|
||||||
{"no-init-fallback", 0, NULL, 'I'},
|
|
||||||
{"force", 0, NULL, 'F'},
|
|
||||||
{"ignore", 0, NULL, 'g'},
|
|
||||||
{"pedantic", 0, NULL, 'P'},
|
|
||||||
{"runstate", 0, NULL, 'r'},
|
|
||||||
{"remove", 0, NULL, 'R'},
|
|
||||||
{"period", 1, NULL, 'p'},
|
|
||||||
{"pid-file", 1, NULL, 'e'},
|
|
||||||
{"background", 0, NULL, 'b'},
|
|
||||||
{"syslog", 0, NULL, 's'},
|
|
||||||
{"debug", 0, NULL, 'd'},
|
|
||||||
{"version", 0, NULL, 'v'},
|
|
||||||
{NULL, 0, NULL, 0},
|
|
||||||
};
|
|
||||||
static const char *const devfiles[] = {
|
static const char *const devfiles[] = {
|
||||||
"/dev/snd/controlC",
|
"/dev/snd/controlC",
|
||||||
"/dev/snd/pcmC",
|
"/dev/snd/pcmC",
|
||||||
|
@ -123,18 +159,48 @@ int main(int argc, char *argv[])
|
||||||
int init_fallback = 1; /* new default behavior */
|
int init_fallback = 1; /* new default behavior */
|
||||||
int period = 5*60;
|
int period = 5*60;
|
||||||
int background = 0;
|
int background = 0;
|
||||||
int res;
|
struct arg *a;
|
||||||
|
struct option *o;
|
||||||
|
int i, j, k, res;
|
||||||
|
struct option *long_option;
|
||||||
|
char *short_option;
|
||||||
|
|
||||||
|
long_option = calloc(ARRAY_SIZE(args), sizeof(struct option));
|
||||||
|
if (long_option == NULL)
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
short_option = malloc(128);
|
||||||
|
if (short_option == NULL) {
|
||||||
|
free(long_option);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
for (i = j = k = 0; i < ARRAY_SIZE(args); i++) {
|
||||||
|
a = &args[i];
|
||||||
|
if ((a->sarg & 0xff) == 0)
|
||||||
|
continue;
|
||||||
|
o = &long_option[j];
|
||||||
|
o->name = args->larg;
|
||||||
|
o->has_arg = (a->sarg & (ENVARG|FILEARG|INTARG)) != 0;
|
||||||
|
o->flag = NULL;
|
||||||
|
o->val = a->sarg & 0xff;
|
||||||
|
j++;
|
||||||
|
short_option[k++] = o->val;
|
||||||
|
if (o->has_arg)
|
||||||
|
short_option[k++] = ':';
|
||||||
|
}
|
||||||
|
short_option[k] = '\0';
|
||||||
command = argv[0];
|
command = argv[0];
|
||||||
|
printf("short_option = '%s'\n", short_option);
|
||||||
while (1) {
|
while (1) {
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
if ((c = getopt_long(argc, argv, "hdvf:lFgE:i:IPr:Rp:e:bs", long_option, NULL)) < 0)
|
if ((c = getopt_long(argc, argv, short_option, long_option,
|
||||||
|
NULL)) < 0)
|
||||||
break;
|
break;
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'h':
|
case 'h':
|
||||||
help();
|
help();
|
||||||
return EXIT_SUCCESS;
|
res = EXIT_SUCCESS;
|
||||||
|
goto out;
|
||||||
case 'f':
|
case 'f':
|
||||||
cfgfile = optarg;
|
cfgfile = optarg;
|
||||||
break;
|
break;
|
||||||
|
@ -150,7 +216,8 @@ int main(int argc, char *argv[])
|
||||||
case 'E':
|
case 'E':
|
||||||
if (putenv(optarg)) {
|
if (putenv(optarg)) {
|
||||||
fprintf(stderr, "environment string '%s' is wrong\n", optarg);
|
fprintf(stderr, "environment string '%s' is wrong\n", optarg);
|
||||||
return EXIT_FAILURE;
|
res = EXIT_FAILURE;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
|
@ -189,19 +256,24 @@ int main(int argc, char *argv[])
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
printf("alsactl version " SND_UTIL_VERSION_STR "\n");
|
printf("alsactl version " SND_UTIL_VERSION_STR "\n");
|
||||||
return EXIT_SUCCESS;
|
res = EXIT_SUCCESS;
|
||||||
|
goto out;
|
||||||
case '?': // error msg already printed
|
case '?': // error msg already printed
|
||||||
help();
|
help();
|
||||||
return EXIT_FAILURE;
|
res = EXIT_FAILURE;
|
||||||
break;
|
goto out;
|
||||||
default: // should never happen
|
default: // should never happen
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Invalid option '%c' (%d) not handled??\n", c, c);
|
"Invalid option '%c' (%d) not handled??\n", c, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
free(short_option);
|
||||||
|
free(long_option);
|
||||||
|
long_option = NULL;
|
||||||
if (argc - optind <= 0) {
|
if (argc - optind <= 0) {
|
||||||
fprintf(stderr, "alsactl: Specify command...\n");
|
fprintf(stderr, "alsactl: Specify command...\n");
|
||||||
return 0;
|
res = 0;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
cardname = argc - optind > 1 ? argv[optind + 1] : NULL;
|
cardname = argc - optind > 1 ? argv[optind + 1] : NULL;
|
||||||
|
@ -261,4 +333,9 @@ int main(int argc, char *argv[])
|
||||||
closelog();
|
closelog();
|
||||||
}
|
}
|
||||||
return res < 0 ? -res : 0;
|
return res < 0 ? -res : 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(short_option);
|
||||||
|
free(long_option);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,3 +52,5 @@ static inline int hextodigit(int c)
|
||||||
return -1;
|
return -1;
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define ARRAY_SIZE(a) (sizeof (a) / sizeof (a)[0])
|
||||||
|
|
|
@ -31,9 +31,6 @@
|
||||||
#include "alsactl.h"
|
#include "alsactl.h"
|
||||||
|
|
||||||
|
|
||||||
#define ARRAY_SIZE(a) (sizeof (a) / sizeof (a)[0])
|
|
||||||
|
|
||||||
|
|
||||||
static char *id_str(snd_ctl_elem_id_t *id)
|
static char *id_str(snd_ctl_elem_id_t *id)
|
||||||
{
|
{
|
||||||
static char str[128];
|
static char str[128];
|
||||||
|
|
Loading…
Reference in a new issue