From 24fe765fa6aa07c9f48879a92ebdb941cc9d8612 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 13 Aug 2008 20:49:07 +0200 Subject: [PATCH] alsactl init configuration syntax changes - change SYSFS_DEVICE to CONFIG{sysfs_device} - INCLUDE key now handles also directories - RESULT key can assign value now - EXIT="return" operation returns from included file immediately Default 00main and hda configuration files changes: - handle preinit and postinit directories Signed-off-by: Jaroslav Kysela --- alsactl/alsactl_init.xml | 40 ++++++++++-- alsactl/init/00main | 33 +++++++++- alsactl/init/hda | 11 ++-- alsactl/init_parse.c | 133 +++++++++++++++++++++++++++++++++------ 4 files changed, 182 insertions(+), 35 deletions(-) diff --git a/alsactl/alsactl_init.xml b/alsactl/alsactl_init.xml index d4b65fd..f0ed9a4 100644 --- a/alsactl/alsactl_init.xml +++ b/alsactl/alsactl_init.xml @@ -257,7 +257,7 @@ - + The relative path to sysfs subsystem specifying the root directory of a soundcard device. Usually, @@ -271,7 +271,7 @@ Match sysfs attribute values of the soundcard device. The relative path to sysfs tree must be defined by - SYSFS_DEVICE key. Trailing whitespace in the attribute + CONFIG{sysfs_device} key. Trailing whitespace in the attribute values is ignored, if the specified match value does not contain trailing whitespace itself. Depending on the type of operator, this key is also used to set @@ -391,6 +391,16 @@ + + + + Set RESULT variable. Note that PROGRAM also sets + this variable, but setting this variable manually + might be useful to change code execution order (included + files). + + + @@ -406,7 +416,21 @@ - + + + Include specified filename or all files in specified directory + + + + + + + Check if specified file or directory exists + + + + + The relative path to sysfs subsystem specifying the root directory of a soundcard device. Usually, @@ -432,15 +456,19 @@ - Exit immediately and set program exit code to value (should be integer). + Exit immediately and set program exit code to value + (should be integer). If value is "return" string, + parser leaves current included file and returns to parent + configuration file. - The , , + The , , + , , , - , + , fields support simple printf-like string substitutions. It allows the use of the complete environment set by earlier matching rules. For all other fields, substitutions are applied while the individual rule is diff --git a/alsactl/init/00main b/alsactl/init/00main index daac952..3d289cb 100644 --- a/alsactl/init/00main +++ b/alsactl/init/00main @@ -2,7 +2,7 @@ # See 'man alsactl_init' for syntax. # set root device directory in sysfs for soundcard for ATTR{} command -SYSFS_DEVICE="/class/sound/controlC$cardinfo{card}/device" +CONFIG{sysfs_device}="/class/sound/controlC$cardinfo{card}/device" # test for extra commands ENV{CMD}=="help", INCLUDE="help", GOTO="00main_end" @@ -11,6 +11,33 @@ ENV{CMD}=="test", INCLUDE="test", GOTO="00main_end" ENV{CMD}=="*", ERROR="Unknown command '$env{CMD}'\n", GOTO="00main_end" # include files with real configuration -CARDINFO{driver}=="HDA-Intel", INCLUDE="hda", GOTO="00main_end" -CARDINFO{driver}=="Test", INCLUDE="test", GOTO="00main_end" +# +# steps are: +# 1) look for preinit subdirectory and parse all files in it +# 2) if RESULT=="skip", skip ALSA standard configuration files +# 3) do ALSA standard configuration +# 4) look for postinit subdirectory and parse all files in it +# 5) if RESULT!="true", print an error message and return with exit code 99 +# 6) return with exit code 0 (success) +# + +RESULT="unknown" +ACCESS=="preinit", INCLUDE="preinit" +RESULT=="skip", GOTO="init_end" + +# real ALSA configuration database +CARDINFO{driver}=="HDA-Intel", INCLUDE="hda", GOTO="init_end" +CARDINFO{driver}=="Test", INCLUDE="test", GOTO="init_end" + +LABEL="init_end" +ACCESS=="postinit", INCLUDE="postinit" +RESULT=="true", GOTO="00_mainend" +ERROR="Unknown hardware: \"$cardinfo{driver}\" \"$cardinfo{mixername}\" \"$cardinfo{components}\" \"$attr{subsystem_vendor}\" \"$attr{subsystem_device}\"\n" +ERROR="Hardware is left uninitialized\n" +EXIT="99" + +# +# label identifying end of main file +# + LABEL="00main_end" diff --git a/alsactl/init/hda b/alsactl/init/hda index 9396418..9c33123 100644 --- a/alsactl/init/hda +++ b/alsactl/init/hda @@ -6,11 +6,8 @@ CARDINFO{mixername}=="Realtek ALC880", \ CARDINFO{mixername}=="Analog Devices AD1984", \ ATTR{subsystem_vendor}=="0x17aa", ATTR{subsystem_device}=="0x20ac", \ GOTO="Lenovo T61" - -ERROR="Unknown hardware: \"$cardinfo{mixername}\" \"$cardinfo{components}\" \"$attr{subsystem_vendor}" \"$attr{subsystem_device}\"\n" -ERROR="Hardware is left uninitialized\n" -EXIT="99" - +RESULT="false", EXIT="return" + LABEL="Acer Travelmate 8100" # playback CTL{reset}="mixer" @@ -22,7 +19,7 @@ CTL{name}="PCM Playback Volume", CTL{value}="150,150" CTL{name}="Input Source", CTL{value}="0" CTL{name}="Capture Volume", CTL{value}="65,65" CTL{name}="Capture Switch", CTL{value}="on,on" -EXIT="0" +RESULT="true", EXIT="return" LABEL="Lenovo T61" # playback @@ -34,4 +31,4 @@ CTL{name}="Input Source", CTL{value}="1" CTL{name}="Internal Mic Boost", CTL{value}="1" CTL{name}="Capture Volume", CTL{value}="45,45" CTL{name}="Capture Switch", CTL{value}="on,on" -EXIT="0" +RESULT="true", EXIT="return" diff --git a/alsactl/init_parse.c b/alsactl/init_parse.c index a99362d..96caf46 100644 --- a/alsactl/init_parse.c +++ b/alsactl/init_parse.c @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include #include "aconfig.h" #include "alsactl.h" @@ -41,6 +43,7 @@ #define PATH_SIZE 512 #define NAME_SIZE 128 +#define EJUSTRETURN 0x7fffffff enum key_op { KEY_OP_UNSET, @@ -946,7 +949,7 @@ found: const char *value = NULL; size_t size; - pair = value_find(space, "SYSFS_DEVICE"); + pair = value_find(space, "sysfs_device"); if (pair == NULL) break; value = sysfs_attr_get_value(pair->value, attr); @@ -1215,7 +1218,17 @@ static int parse_line(struct space *space, char *line, size_t linesize) if (op == KEY_OP_MATCH || op == KEY_OP_NOMATCH) { if (!do_match(key, op, value, space->program_result)) break; - } else { + } else if (op == KEY_OP_ASSIGN) { + if (space->program_result) { + free(space->program_result); + space->program_result = NULL; + } + strlcpy(string, value, sizeof(string)); + apply_format(space, string, sizeof(string)); + space->program_result = strdup(string); + if (space->program_result == NULL) + break; + } else { Perror(space, "invalid RESULT operation"); goto invalid; } @@ -1274,7 +1287,7 @@ static int parse_line(struct space *space, char *line, size_t linesize) goto invalid; } if (op == KEY_OP_MATCH || op == KEY_OP_NOMATCH) { - pair = value_find(space, "SYSFS_DEVICE"); + pair = value_find(space, "sysfs_device"); if (pair == NULL) break; dbg("sysfs_attr: '%s' '%s'", pair->value, attr); @@ -1319,6 +1332,8 @@ static int parse_line(struct space *space, char *line, size_t linesize) if (strcasecmp(key, "INCLUDE") == 0) { char *rootdir, *go_to; const char *filename; + struct dirent *dirent; + DIR *dir; int linenum; if (op != KEY_OP_ASSIGN) { Perror(space, "invalid INCLUDE operation"); @@ -1335,16 +1350,41 @@ static int parse_line(struct space *space, char *line, size_t linesize) go_to = space->go_to; filename = space->filename; linenum = space->linenum; - space->go_to = NULL; - space->rootdir = new_root_dir(string); - if (space->rootdir) { - err = parse(space, string); - free(space->rootdir); - } else - err = -ENOMEM; - if (space->go_to) { - Perror(space, "unterminated GOTO '%s'", space->go_to); - free(space->go_to); + dir = opendir(string); + if (dir) { + count = strlen(string); + while ((dirent = readdir(dir)) != NULL) { + if (strcmp(dirent->d_name, ".") == 0 || + strcmp(dirent->d_name, "..") == 0) + continue; + string[count] = '\0'; + strlcat(string, "/", sizeof(string)); + strlcat(string, dirent->d_name, sizeof(string)); + space->go_to = NULL; + space->rootdir = new_root_dir(string); + if (space->rootdir) { + err = parse(space, string); + free(space->rootdir); + } else + err = -ENOMEM; + if (space->go_to) { + Perror(space, "unterminated GOTO '%s'", space->go_to); + free(space->go_to); + } + } + closedir(dir); + } else { + space->go_to = NULL; + space->rootdir = new_root_dir(string); + if (space->rootdir) { + err = parse(space, string); + free(space->rootdir); + } else + err = -ENOMEM; + if (space->go_to) { + Perror(space, "unterminated GOTO '%s'", space->go_to); + free(space->go_to); + } } space->go_to = go_to; space->rootdir = rootdir; @@ -1354,31 +1394,82 @@ static int parse_line(struct space *space, char *line, size_t linesize) break; continue; } + if (strncasecmp(key, "ACCESS", 6) == 0) { + if (op == KEY_OP_MATCH || op == KEY_OP_NOMATCH) { + if (value[0] != '/') { + strlcpy(string, space->rootdir, sizeof(string)); + strlcat(string, "/", sizeof(string)); + strlcat(string, value, sizeof(string)); + } else { + strlcat(string, value, sizeof(string)); + } + count = access(string, F_OK); + dbg("access(%s) = %i", value, count); + if (op == KEY_OP_MATCH && count != 0) + break; + if (op == KEY_OP_NOMATCH && count == 0) + break; + } else { + Perror(space, "invalid ACCESS operation"); + goto invalid; + } + continue; + } if (strncasecmp(key, "PRINT", 5) == 0) { + if (op != KEY_OP_ASSIGN) { + Perror(space, "invalid PRINT operation"); + goto invalid; + } strlcpy(string, value, sizeof(string)); apply_format(space, string, sizeof(string)); fwrite(string, strlen(string), 1, stdout); continue; } if (strncasecmp(key, "ERROR", 5) == 0) { + if (op != KEY_OP_ASSIGN) { + Perror(space, "invalid ERROR operation"); + goto invalid; + } strlcpy(string, value, sizeof(string)); apply_format(space, string, sizeof(string)); fwrite(string, strlen(string), 1, stderr); continue; } if (strncasecmp(key, "EXIT", 4) == 0) { + if (op != KEY_OP_ASSIGN) { + Perror(space, "invalid EXIT operation"); + goto invalid; + } strlcpy(string, value, sizeof(string)); apply_format(space, string, sizeof(string)); + if (strcmp(string, "return") == 0) + return -EJUSTRETURN; space->exit_code = strtol(string, NULL, 0); space->quit = 1; break; } - if (strncasecmp(key, "SYSFS_DEVICE", 12) == 0) { - strlcpy(string, value, sizeof(string)); - apply_format(space, string, sizeof(string)); - err = value_set(space, key, string); - dbg("SYSFS_DEVICE='%s'", string); - break; + if (strncasecmp(key, "CONFIG{", 7) == 0) { + attr = get_key_attribute(space, key + 6, string, sizeof(string)); + if (attr == NULL) { + Perror(space, "error parsing CONFIG attribute"); + goto invalid; + } + strlcpy(result, value, sizeof(result)); + apply_format(space, result, sizeof(result)); + if (op == KEY_OP_ASSIGN) { + err = value_set(space, attr, result); + dbg("CONFIG{%s}='%s'", attr, result); + break; + } else if (op == KEY_OP_MATCH || op == KEY_OP_NOMATCH) { + pair = value_find(space, attr); + if (pair == NULL) + break; + if (!do_match(key, op, result, pair->value)) + break; + } else { + Perror(space, "invalid CONFIG{} operation"); + goto invalid; + } } Perror(space, "unknown key '%s'", key); @@ -1460,6 +1551,10 @@ static int parse(struct space *space, const char *filename) dbg("read (%i) '%s'", linenum, line); space->linenum = linenum; err = parse_line(space, line, linesize); + if (err == -EJUSTRETURN) { + err = 0; + break; + } linenum += linenum_adj; } -- 2.47.1