diff options
Diffstat (limited to 'alsa-utils/alsactl/init_parse.c')
-rw-r--r-- | alsa-utils/alsactl/init_parse.c | 1739 |
1 files changed, 0 insertions, 1739 deletions
diff --git a/alsa-utils/alsactl/init_parse.c b/alsa-utils/alsactl/init_parse.c deleted file mode 100644 index c82797e..0000000 --- a/alsa-utils/alsactl/init_parse.c +++ /dev/null @@ -1,1739 +0,0 @@ -/* - * Advanced Linux Sound Architecture Control Program - Parse initialization files - * Copyright (c) by Jaroslav Kysela <perex@perex.cz>, - * Greg Kroah-Hartman <greg@kroah.com>, - * Kay Sievers <kay.sievers@vrfy.org> - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include <stdlib.h> -#include <stdio.h> -#include <stddef.h> -#include <unistd.h> -#include <string.h> -#include <fcntl.h> -#include <ctype.h> -#include <errno.h> -#include <fnmatch.h> -#include <sys/stat.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <sys/wait.h> -#include <sys/select.h> -#include <sys/types.h> -#include <dirent.h> -#include <math.h> -#include <alsa/asoundlib.h> -#include "aconfig.h" -#include "alsactl.h" -#include "list.h" - -#define PATH_SIZE 512 -#define NAME_SIZE 128 -#define EJUSTRETURN 0x7fffffff - -enum key_op { - KEY_OP_UNSET, - KEY_OP_MATCH, - KEY_OP_NOMATCH, - KEY_OP_ADD, - KEY_OP_ASSIGN, - KEY_OP_ASSIGN_FINAL -}; - -struct pair { - char *key; - char *value; - struct pair *next; -}; - -struct space { - struct pair *pairs; - char *rootdir; - char *go_to; - char *program_result; - const char *filename; - int linenum; - int log_run; - int exit_code; - int quit; - unsigned int ctl_id_changed; - snd_hctl_t *ctl_handle; - snd_ctl_card_info_t *ctl_card_info; - snd_ctl_elem_id_t *ctl_id; - snd_ctl_elem_info_t *ctl_info; - snd_ctl_elem_value_t *ctl_value; -}; - -static void Perror(struct space *space, const char *fmt, ...) -{ - va_list arg; - va_start(arg, fmt); - fprintf(stderr, "%s:%i: ", space->filename, space->linenum); - vfprintf(stderr, fmt, arg); - putc('\n', stderr); - va_end(arg); -} - -#include "init_sysdeps.c" -#include "init_utils_string.c" -#include "init_utils_run.c" -#include "init_sysfs.c" - -static void free_space(struct space *space) -{ - struct pair *pair = space->pairs; - struct pair *next = pair; - - while (next) { - pair = next; - next = pair->next; - free(pair->value); - free(pair->key); - free(pair); - } - space->pairs = NULL; - if (space->ctl_value) { - snd_ctl_elem_value_free(space->ctl_value); - space->ctl_value = NULL; - } - if (space->ctl_info) { - snd_ctl_elem_info_free(space->ctl_info); - space->ctl_info = NULL; - } - if (space->ctl_id) { - snd_ctl_elem_id_free(space->ctl_id); - space->ctl_id = NULL; - } - if (space->ctl_card_info) { - snd_ctl_card_info_free(space->ctl_card_info); - space->ctl_card_info = NULL; - } - if (space->ctl_handle) { - snd_hctl_close(space->ctl_handle); - space->ctl_handle = NULL; - } - if (space->rootdir) - free(space->rootdir); - if (space->program_result) - free(space->program_result); - if (space->go_to) - free(space->go_to); - free(space); -} - -static struct pair *value_find(struct space *space, const char *key) -{ - struct pair *pair = space->pairs; - - while (pair && strcmp(pair->key, key) != 0) - pair = pair->next; - return pair; -} - -static int value_set(struct space *space, const char *key, const char *value) -{ - struct pair *pair; - - pair = value_find(space, key); - if (pair) { - free(pair->value); - pair->value = strdup(value); - if (pair->value == NULL) - return -ENOMEM; - } else { - pair = malloc(sizeof(struct pair)); - if (pair == NULL) - return -ENOMEM; - pair->key = strdup(key); - if (pair->key == NULL) { - free(pair); - return -ENOMEM; - } - pair->value = strdup(value); - if (pair->value == NULL) { - free(pair->key); - free(pair); - return -ENOMEM; - } - pair->next = space->pairs; - space->pairs = pair; - } - return 0; -} - -static int init_space(struct space **space, int card) -{ - struct space *res; - char device[16]; - int err; - - res = calloc(1, sizeof(struct space)); - if (res == NULL) - return -ENOMEM; - res->ctl_id_changed = ~0; - res->linenum = -1; - sprintf(device, "hw:%u", card); - err = snd_hctl_open(&res->ctl_handle, device, 0); - if (err < 0) - goto error; - err = snd_hctl_load(res->ctl_handle); - if (err < 0) - goto error; - err = snd_ctl_card_info_malloc(&res->ctl_card_info); - if (err < 0) - goto error; - err = snd_ctl_card_info(snd_hctl_ctl(res->ctl_handle), res->ctl_card_info); - if (err < 0) - goto error; - err = snd_ctl_elem_id_malloc(&res->ctl_id); - if (err < 0) - goto error; - err = snd_ctl_elem_info_malloc(&res->ctl_info); - if (err < 0) - goto error; - err = snd_ctl_elem_value_malloc(&res->ctl_value); - if (err < 0) - goto error; - *space = res; - return 0; - error: - free_space(res); - return err; -} - -static const char *cardinfo_get(struct space *space, const char *attr) -{ - if (strncasecmp(attr, "CARD", 4) == 0) { - static char res[16]; - sprintf(res, "%u", snd_ctl_card_info_get_card(space->ctl_card_info)); - return res; - } - if (strncasecmp(attr, "ID", 2) == 0) - return snd_ctl_card_info_get_id(space->ctl_card_info); - if (strncasecmp(attr, "DRIVER", 6) == 0) - return snd_ctl_card_info_get_driver(space->ctl_card_info); - if (strncasecmp(attr, "NAME", 4) == 0) - return snd_ctl_card_info_get_name(space->ctl_card_info); - if (strncasecmp(attr, "LONGNAME", 8) == 0) - return snd_ctl_card_info_get_longname(space->ctl_card_info); - if (strncasecmp(attr, "MIXERNAME", 9) == 0) - return snd_ctl_card_info_get_mixername(space->ctl_card_info); - if (strncasecmp(attr, "COMPONENTS", 10) == 0) - return snd_ctl_card_info_get_components(space->ctl_card_info); - Perror(space, "unknown cardinfo{} attribute '%s'", attr); - return NULL; -} - -static int check_id_changed(struct space *space, unsigned int what) -{ - snd_hctl_elem_t *elem; - int err; - - if ((space->ctl_id_changed & what & 1) != 0) { - snd_ctl_elem_id_set_numid(space->ctl_id, 0); - elem = snd_hctl_find_elem(space->ctl_handle, space->ctl_id); - if (!elem) - return -ENOENT; - err = snd_hctl_elem_info(elem, space->ctl_info); - if (err == 0) - space->ctl_id_changed &= ~1; - return err; - } - if ((space->ctl_id_changed & what & 2) != 0) { - snd_ctl_elem_id_set_numid(space->ctl_id, 0); - elem = snd_hctl_find_elem(space->ctl_handle, space->ctl_id); - if (!elem) - return -ENOENT; - err = snd_hctl_elem_read(elem, space->ctl_value); - if (err == 0) - space->ctl_id_changed &= ~2; - return err; - } - return 0; -} - -static const char *get_ctl_value(struct space *space) -{ - snd_ctl_elem_type_t type; - unsigned int idx, count; - static char res[1024], tmp[16]; - static const char hex[] = "0123456789abcdef"; - char *pos; - const char *pos1; - - type = snd_ctl_elem_info_get_type(space->ctl_info); - count = snd_ctl_elem_info_get_count(space->ctl_info); - res[0] = '\0'; - switch (type) { - case SND_CTL_ELEM_TYPE_BOOLEAN: - for (idx = 0; idx < count; idx++) { - if (idx > 0) - strlcat(res, ",", sizeof(res)); - strlcat(res, snd_ctl_elem_value_get_boolean(space->ctl_value, idx) ? "on" : "off", sizeof(res)); - } - break; - case SND_CTL_ELEM_TYPE_INTEGER: - for (idx = 0; idx < count; idx++) { - if (idx > 0) - strlcat(res, ",", sizeof(res)); - snprintf(tmp, sizeof(tmp), "%li", snd_ctl_elem_value_get_integer(space->ctl_value, idx)); - strlcat(res, tmp, sizeof(res)); - } - break; - case SND_CTL_ELEM_TYPE_INTEGER64: - for (idx = 0; idx < count; idx++) { - if (idx > 0) - strlcat(res, ",", sizeof(res)); - snprintf(tmp, sizeof(tmp), "%lli", snd_ctl_elem_value_get_integer64(space->ctl_value, idx)); - strlcat(res, tmp, sizeof(res)); - } - break; - case SND_CTL_ELEM_TYPE_ENUMERATED: - for (idx = 0; idx < count; idx++) { - if (idx > 0) - strlcat(res, ",", sizeof(res)); - snprintf(tmp, sizeof(tmp), "%u", snd_ctl_elem_value_get_enumerated(space->ctl_value, idx)); - strlcat(res, tmp, sizeof(res)); - } - break; - case SND_CTL_ELEM_TYPE_BYTES: - case SND_CTL_ELEM_TYPE_IEC958: - if (type == SND_CTL_ELEM_TYPE_IEC958) - count = sizeof(snd_aes_iec958_t); - if (count > (sizeof(res)-1)/2) - count = (sizeof(res)-1/2); - pos = res; - pos1 = snd_ctl_elem_value_get_bytes(space->ctl_value); - while (count > 0) { - idx = *pos1++; - *pos++ = hex[idx >> 4]; - *pos++ = hex[idx & 0x0f]; - count++; - } - *pos++ = '\0'; - break; - default: - Perror(space, "unknown element type '%i'", type); - return NULL; - } - return res; -} - -/* Function to convert from percentage to volume. val = percentage */ -#define convert_prange1(val, min, max) \ - ceil((val) * ((max) - (min)) * 0.01 + (min)) - -static int set_ctl_value(struct space *space, const char *value, int all) -{ - snd_ctl_elem_type_t type; - unsigned int idx, idx2, count, items; - const char *pos, *pos2; - snd_hctl_elem_t *elem; - int val; - long lval; - - type = snd_ctl_elem_info_get_type(space->ctl_info); - count = snd_ctl_elem_info_get_count(space->ctl_info); - switch (type) { - case SND_CTL_ELEM_TYPE_BOOLEAN: - for (idx = 0; idx < count; idx++) { - while (*value == ' ') - value++; - if (*value == '\0') - goto missing; - val = strncasecmp(value, "true", 4) == 0 || - strncasecmp(value, "yes", 3) == 0 || - strncasecmp(value, "on", 2) == 0 || - strncasecmp(value, "1", 1) == 0; - snd_ctl_elem_value_set_boolean(space->ctl_value, idx, val); - if (all) - continue; - pos = strchr(value, ','); - value = pos ? pos + 1 : value + strlen(value) - 1; - } - break; - case SND_CTL_ELEM_TYPE_INTEGER: - for (idx = 0; idx < count; idx++) { - while (*value == ' ') - value++; - pos = strchr(value, ','); - if (pos) - *(char *)pos = '\0'; - remove_trailing_chars((char *)value, ' '); - items = pos ? pos - value : strlen(value); - if (items > 1 && value[items-1] == '%') { - val = convert_prange1(strtol(value, NULL, 0), snd_ctl_elem_info_get_min(space->ctl_info), snd_ctl_elem_info_get_max(space->ctl_info)); - snd_ctl_elem_value_set_integer(space->ctl_value, idx, val); - } else if (items > 2 && value[items-2] == 'd' && value[items-1] == 'B') { - val = strtol(value, NULL, 0) * 100; - if ((pos2 = index(value, '.')) != NULL) { - if (isdigit(*(pos2-1)) && isdigit(*(pos2-2))) { - if (val < 0) - val -= strtol(pos2 + 1, NULL, 0); - else - val += strtol(pos2 + 1, NULL, 0); - } else if (isdigit(*(pos2-1))) { - if (val < 0) - val -= strtol(pos2 + 1, NULL, 0) * 10; - else - val += strtol(pos2 + 1, NULL, 0) * 10; - } - } - val = snd_ctl_convert_from_dB(snd_hctl_ctl(space->ctl_handle), space->ctl_id, val, &lval, -1); - if (val < 0) { - Perror(space, "unable to convert dB value '%s' to internal integer range", value); - return val; - } - snd_ctl_elem_value_set_integer(space->ctl_value, idx, lval); - } else { - snd_ctl_elem_value_set_integer(space->ctl_value, idx, strtol(value, NULL, 0)); - } - if (all) - continue; - value = pos ? pos + 1 : value + strlen(value) - 1; - } - break; - case SND_CTL_ELEM_TYPE_INTEGER64: - for (idx = 0; idx < count; idx++) { - while (*value == ' ') - value++; - snd_ctl_elem_value_set_integer64(space->ctl_value, idx, strtoll(value, NULL, 0)); - if (all) - continue; - pos = strchr(value, ','); - value = pos ? pos + 1 : value + strlen(value) - 1; - } - break; - case SND_CTL_ELEM_TYPE_ENUMERATED: - for (idx = 0; idx < count; idx++) { - while (*value == ' ') - value++; - pos = strchr(value, ','); - if (isdigit(value[0]) || value[0] == '-') { - snd_ctl_elem_value_set_enumerated(space->ctl_value, idx, strtol(value, NULL, 0)); - } else { - if (pos) - *(char *)pos = '\0'; - remove_trailing_chars((char *)value, ' '); - items = snd_ctl_elem_info_get_items(space->ctl_info); - for (idx2 = 0; idx2 < items; idx2++) { - snd_ctl_elem_info_set_item(space->ctl_info, idx2); - elem = snd_hctl_find_elem(space->ctl_handle, space->ctl_id); - if (elem == NULL) - return -ENOENT; - val = snd_hctl_elem_info(elem, space->ctl_info); - if (val < 0) - return val; - if (strcasecmp(snd_ctl_elem_info_get_item_name(space->ctl_info), value) == 0) { - snd_ctl_elem_value_set_enumerated(space->ctl_value, idx, idx2); - break; - } - } - if (idx2 >= items) { - Perror(space, "wrong enum identifier '%s'", value); - return -EINVAL; - } - } - if (all) - continue; - value = pos ? pos + 1 : value + strlen(value) - 1; - } - break; - case SND_CTL_ELEM_TYPE_BYTES: - case SND_CTL_ELEM_TYPE_IEC958: - if (type == SND_CTL_ELEM_TYPE_IEC958) - count = sizeof(snd_aes_iec958_t); - while (*value == ' ') - value++; - if (strlen(value) != count * 2) { - Perror(space, "bad ctl value hexa length (should be %u bytes)", count); - return -EINVAL; - } - for (idx = 0; idx < count; idx += 2) { - val = hextodigit(*(value++)) << 4; - val |= hextodigit(*(value++)); - if (val > 255) { - Perror(space, "bad ctl hexa value"); - return -EINVAL; - } - snd_ctl_elem_value_set_byte(space->ctl_value, idx, val); - } - break; - default: - Perror(space, "unknown element type '%i'", type); - return -EINVAL; - } - return 0; - missing: - printf("%i %i\n", type, count); - Perror(space, "missing some ctl values (line %i)", space->linenum); - return -EINVAL; -} - -static const char *elemid_get(struct space *space, const char *attr) -{ - long long val; - snd_ctl_elem_type_t type; - static char res[256]; - - if (strncasecmp(attr, "numid", 5) == 0) { - val = snd_ctl_elem_id_get_numid(space->ctl_id); - goto value; - } - if (strncasecmp(attr, "iface", 5) == 0 || - strncasecmp(attr, "interface", 9) == 0) - return snd_ctl_elem_iface_name(snd_ctl_elem_id_get_interface(space->ctl_id)); - if (strncasecmp(attr, "device", 6) == 0) { - val = snd_ctl_elem_id_get_device(space->ctl_id); - goto value; - } - if (strncasecmp(attr, "subdev", 6) == 0) { - val = snd_ctl_elem_id_get_subdevice(space->ctl_id); - goto value; - } - if (strncasecmp(attr, "name", 4) == 0) - return snd_ctl_elem_id_get_name(space->ctl_id); - if (strncasecmp(attr, "index", 5) == 0) { - val = snd_ctl_elem_id_get_index(space->ctl_id); - goto value; - } - if (strncasecmp(attr, "type", 4) == 0) { - if (check_id_changed(space, 1)) - return NULL; - return snd_ctl_elem_type_name(snd_ctl_elem_info_get_type(space->ctl_info)); - } - if (strncasecmp(attr, "attr", 4) == 0) { - if (check_id_changed(space, 1)) - return NULL; - res[0] = '\0'; - if (snd_ctl_elem_info_is_readable(space->ctl_info)) - strcat(res, "r"); - if (snd_ctl_elem_info_is_writable(space->ctl_info)) - strcat(res, "w"); - if (snd_ctl_elem_info_is_volatile(space->ctl_info)) - strcat(res, "v"); - if (snd_ctl_elem_info_is_inactive(space->ctl_info)) - strcat(res, "i"); - if (snd_ctl_elem_info_is_locked(space->ctl_info)) - strcat(res, "l"); - if (snd_ctl_elem_info_is_tlv_readable(space->ctl_info)) - strcat(res, "R"); - if (snd_ctl_elem_info_is_tlv_writable(space->ctl_info)) - strcat(res, "W"); - if (snd_ctl_elem_info_is_tlv_commandable(space->ctl_info)) - strcat(res, "C"); - if (snd_ctl_elem_info_is_owner(space->ctl_info)) - strcat(res, "o"); - if (snd_ctl_elem_info_is_user(space->ctl_info)) - strcat(res, "u"); - return res; - } - if (strncasecmp(attr, "owner", 5) == 0) { - if (check_id_changed(space, 1)) - return NULL; - val = snd_ctl_elem_info_get_owner(space->ctl_info); - goto value; - } - if (strncasecmp(attr, "count", 5) == 0) { - if (check_id_changed(space, 1)) - return NULL; - val = snd_ctl_elem_info_get_count(space->ctl_info); - goto value; - } - if (strncasecmp(attr, "min", 3) == 0) { - if (check_id_changed(space, 1)) - return NULL; - type = snd_ctl_elem_info_get_type(space->ctl_info); - if (type == SND_CTL_ELEM_TYPE_INTEGER64) - val = snd_ctl_elem_info_get_min64(space->ctl_info); - else if (type == SND_CTL_ELEM_TYPE_INTEGER) - val = snd_ctl_elem_info_get_min(space->ctl_info); - else - goto empty; - goto value; - } - if (strncasecmp(attr, "max", 3) == 0) { - if (check_id_changed(space, 1)) - return NULL; - type = snd_ctl_elem_info_get_type(space->ctl_info); - if (type == SND_CTL_ELEM_TYPE_INTEGER64) - val = snd_ctl_elem_info_get_max64(space->ctl_info); - else if (type == SND_CTL_ELEM_TYPE_INTEGER) - val = snd_ctl_elem_info_get_max(space->ctl_info); - else - goto empty; - goto value; - } - if (strncasecmp(attr, "step", 3) == 0) { - if (check_id_changed(space, 1)) - return NULL; - type = snd_ctl_elem_info_get_type(space->ctl_info); - if (type == SND_CTL_ELEM_TYPE_INTEGER64) - val = snd_ctl_elem_info_get_step64(space->ctl_info); - else if (type == SND_CTL_ELEM_TYPE_INTEGER) - val = snd_ctl_elem_info_get_step(space->ctl_info); - else - goto empty; - goto value; - } - if (strncasecmp(attr, "items", 5) == 0) { - if (check_id_changed(space, 1)) - return NULL; - if (snd_ctl_elem_info_get_type(space->ctl_info) == SND_CTL_ELEM_TYPE_ENUMERATED) - val = snd_ctl_elem_info_get_items(space->ctl_info); - else { - empty: - res[0] = '\0'; - return res; - } - goto value; - } - if (strncasecmp(attr, "value", 5) == 0) { - if (check_id_changed(space, 3)) - return NULL; - return get_ctl_value(space); - } - if (strncasecmp(attr, "dBmin", 5) == 0) { - long min, max; - if (check_id_changed(space, 1)) - return NULL; - if (snd_ctl_get_dB_range(snd_hctl_ctl(space->ctl_handle), space->ctl_id, &min, &max) < 0) - goto empty; - val = min; -dbvalue: - sprintf(res, "%li.%02idB", (long)(val / 100), (int)abs(val % 100)); - return res; - } - if (strncasecmp(attr, "dBmax", 5) == 0) { - long min, max; - if (check_id_changed(space, 1)) - return NULL; - if (snd_ctl_get_dB_range(snd_hctl_ctl(space->ctl_handle), space->ctl_id, &min, &max) < 0) - goto empty; - val = max; - goto dbvalue; - } - if (strncasecmp(attr, "enums", 5) == 0) { - unsigned int idx, items; - snd_hctl_elem_t *elem; - if (check_id_changed(space, 1)) - return NULL; - if (snd_ctl_elem_info_get_type(space->ctl_info) != SND_CTL_ELEM_TYPE_ENUMERATED) - goto empty; - items = snd_ctl_elem_info_get_items(space->ctl_info); - strcpy(res, "|"); - for (idx = 0; idx < items; idx++) { - snd_ctl_elem_info_set_item(space->ctl_info, idx); - elem = snd_hctl_find_elem(space->ctl_handle, space->ctl_id); - if (elem == NULL) - break; - if (snd_hctl_elem_info(elem, space->ctl_info) < 0) - break; - strlcat(res, snd_ctl_elem_info_get_item_name(space->ctl_info), sizeof(res)); - strlcat(res, "|", sizeof(res)); - } - return res; - } - Perror(space, "unknown ctl{} attribute '%s'", attr); - return NULL; - value: - sprintf(res, "%lli", val); - return res; -} - -static int elemid_set(struct space *space, const char *attr, const char *value) -{ - unsigned int val; - void (*fcn)(snd_ctl_elem_id_t *, unsigned int); - snd_ctl_elem_iface_t iface; - int err; - - if (strncasecmp(attr, "numid", 5) == 0) { - fcn = snd_ctl_elem_id_set_numid; - goto value; - } - if (strncasecmp(attr, "iface", 5) == 0 || - strncasecmp(attr, "interface", 9) == 0 || - strncasecmp(attr, "reset", 5) == 0 || - strncasecmp(attr, "search", 6) == 0) { - if (strlen(value) == 0 && strncasecmp(attr, "search", 6) == 0) { - iface = 0; - goto search; - } - for (iface = 0; iface <= SND_CTL_ELEM_IFACE_LAST; iface++) { - if (strcasecmp(value, snd_ctl_elem_iface_name(iface)) == 0) { - if (strncasecmp(attr, "reset", 5) == 0) - snd_ctl_elem_id_clear(space->ctl_id); - if (strncasecmp(attr, "search", 5) == 0) { - search: - snd_ctl_elem_id_clear(space->ctl_id); - /* -1 means all */ - snd_ctl_elem_id_set_interface(space->ctl_id, -1); - snd_ctl_elem_id_set_device(space->ctl_id, -1); - snd_ctl_elem_id_set_subdevice(space->ctl_id, -1); - snd_ctl_elem_id_set_name(space->ctl_id, "*"); - snd_ctl_elem_id_set_index(space->ctl_id, -1); - if (strlen(value) == 0) - return 0; - } - snd_ctl_elem_id_set_interface(space->ctl_id, iface); - space->ctl_id_changed = ~0; - return 0; - } - } - Perror(space, "unknown control interface name '%s'", value); - return -EINVAL; - } - if (strncasecmp(attr, "device", 6) == 0) { - fcn = snd_ctl_elem_id_set_device; - goto value; - } - if (strncasecmp(attr, "subdev", 6) == 0) { - fcn = snd_ctl_elem_id_set_subdevice; - goto value; - } - if (strncasecmp(attr, "name", 4) == 0) { - snd_ctl_elem_id_set_name(space->ctl_id, value); - space->ctl_id_changed = ~0; - return 0; - } - if (strncasecmp(attr, "index", 5) == 0) { - fcn = snd_ctl_elem_id_set_index; - goto value; - } - if (strncasecmp(attr, "values", 6) == 0 || - strncasecmp(attr, "value", 5) == 0) { - err = check_id_changed(space, 1); - if (err < 0) { - Perror(space, "control element not found"); - return err; - } - err = set_ctl_value(space, value, strncasecmp(attr, "values", 6) == 0); - if (err < 0) { - space->ctl_id_changed |= 2; - } else { - space->ctl_id_changed &= ~2; - snd_ctl_elem_value_set_id(space->ctl_value, space->ctl_id); - err = snd_ctl_elem_write(snd_hctl_ctl(space->ctl_handle), space->ctl_value); - if (err < 0) { - Perror(space, "value write error: %s", snd_strerror(err)); - return err; - } - } - return err; - } - Perror(space, "unknown CTL{} attribute '%s'", attr); - return -EINVAL; - value: - val = (unsigned int)strtol(value, NULL, 0); - fcn(space->ctl_id, val); - space->ctl_id_changed = ~0; - return 0; -} - -static int get_key(char **line, char **key, enum key_op *op, char **value) -{ - char *linepos; - char *temp; - - linepos = *line; - if (linepos == NULL && linepos[0] == '\0') - return -EINVAL; - - /* skip whitespace */ - while (isspace(linepos[0]) || linepos[0] == ',') - linepos++; - - /* get the key */ - if (linepos[0] == '\0') - return -EINVAL; - *key = linepos; - - while (1) { - linepos++; - if (linepos[0] == '\0') - return -1; - if (isspace(linepos[0])) - break; - if (linepos[0] == '=') - break; - if (linepos[0] == '+') - break; - if (linepos[0] == '!') - break; - if (linepos[0] == ':') - break; - } - - /* remember end of key */ - temp = linepos; - - /* skip whitespace after key */ - while (isspace(linepos[0])) - linepos++; - if (linepos[0] == '\0') - return -EINVAL; - - /* get operation type */ - if (linepos[0] == '=' && linepos[1] == '=') { - *op = KEY_OP_MATCH; - linepos += 2; - dbg("operator=match"); - } else if (linepos[0] == '!' && linepos[1] == '=') { - *op = KEY_OP_NOMATCH; - linepos += 2; - dbg("operator=nomatch"); - } else if (linepos[0] == '+' && linepos[1] == '=') { - *op = KEY_OP_ADD; - linepos += 2; - dbg("operator=add"); - } else if (linepos[0] == '=') { - *op = KEY_OP_ASSIGN; - linepos++; - dbg("operator=assign"); - } else if (linepos[0] == ':' && linepos[1] == '=') { - *op = KEY_OP_ASSIGN_FINAL; - linepos += 2; - dbg("operator=assign_final"); - } else - return -EINVAL; - - /* terminate key */ - temp[0] = '\0'; - dbg("key='%s'", *key); - - /* skip whitespace after operator */ - while (isspace(linepos[0])) - linepos++; - if (linepos[0] == '\0') - return -EINVAL; - - /* get the value*/ - if (linepos[0] != '"') - return -EINVAL; - linepos++; - *value = linepos; - - while (1) { - temp = strchr(linepos, '"'); - if (temp && temp[-1] == '\\') { - linepos = temp + 1; - continue; - } - break; - } - if (!temp) - return -EINVAL; - temp[0] = '\0'; - temp++; - dbg("value='%s'", *value); - - /* move line to next key */ - *line = temp; - - return 0; -} - -/* extract possible KEY{attr} */ -static char *get_key_attribute(struct space *space, char *str, char *res, size_t ressize) -{ - char *pos; - char *attr; - - attr = strchr(str, '{'); - if (attr != NULL) { - attr++; - pos = strchr(attr, '}'); - if (pos == NULL) { - Perror(space, "missing closing brace for format"); - return NULL; - } - pos[0] = '\0'; - strlcpy(res, attr, ressize); - pos[0] = '}'; - dbg("attribute='%s'", res); - return res; - } - - return NULL; -} - -/* extract possible {attr} and move str behind it */ -static char *get_format_attribute(struct space *space, char **str) -{ - char *pos; - char *attr = NULL; - - if (*str[0] == '{') { - pos = strchr(*str, '}'); - if (pos == NULL) { - Perror(space, "missing closing brace for format"); - return NULL; - } - pos[0] = '\0'; - attr = *str+1; - *str = pos+1; - dbg("attribute='%s', str='%s'", attr, *str); - } - return attr; -} - -/* extract possible format length and move str behind it*/ -static int get_format_len(struct space *space, char **str) -{ - int num; - char *tail; - - if (isdigit(*str[0])) { - num = (int) strtoul(*str, &tail, 10); - if (num > 0) { - *str = tail; - dbg("format length=%i", num); - return num; - } else { - Perror(space, "format parsing error '%s'", *str); - } - } - return -1; -} - -static void apply_format(struct space *space, char *string, size_t maxsize) -{ - char temp[PATH_SIZE]; - char temp2[PATH_SIZE]; - char *head, *tail, *pos, *cpos, *attr, *rest; - struct pair *pair; - int len; - int i; - int count; - enum subst_type { - SUBST_UNKNOWN, - SUBST_CARDINFO, - SUBST_CTL, - SUBST_RESULT, - SUBST_ATTR, - SUBST_SYSFSROOT, - SUBST_ENV, - }; - static const struct subst_map { - char *name; - char fmt; - enum subst_type type; - } map[] = { - { .name = "cardinfo", .fmt = 'i', .type = SUBST_CARDINFO }, - { .name = "ctl", .fmt = 'C', .type = SUBST_CTL }, - { .name = "result", .fmt = 'c', .type = SUBST_RESULT }, - { .name = "attr", .fmt = 's', .type = SUBST_ATTR }, - { .name = "sysfsroot", .fmt = 'r', .type = SUBST_SYSFSROOT }, - { .name = "env", .fmt = 'E', .type = SUBST_ENV }, - { NULL, '\0', 0 } - }; - enum subst_type type; - const struct subst_map *subst; - - head = string; - while (1) { - len = -1; - while (head[0] != '\0') { - if (head[0] == '$') { - /* substitute named variable */ - if (head[1] == '\0') - break; - if (head[1] == '$') { - strlcpy(temp, head+2, sizeof(temp)); - strlcpy(head+1, temp, maxsize); - head++; - continue; - } - head[0] = '\0'; - for (subst = map; subst->name; subst++) { - if (strncasecmp(&head[1], subst->name, strlen(subst->name)) == 0) { - type = subst->type; - tail = head + strlen(subst->name)+1; - dbg("will substitute format name '%s'", subst->name); - goto found; - } - } - } else if (head[0] == '%') { - /* substitute format char */ - if (head[1] == '\0') - break; - if (head[1] == '%') { - strlcpy(temp, head+2, sizeof(temp)); - strlcpy(head+1, temp, maxsize); - head++; - continue; - } - head[0] = '\0'; - tail = head+1; - len = get_format_len(space, &tail); - for (subst = map; subst->name; subst++) { - if (tail[0] == subst->fmt) { - type = subst->type; - tail++; - dbg("will substitute format char '%c'", subst->fmt); - goto found; - } - } - } - head++; - } - break; -found: - attr = get_format_attribute(space, &tail); - strlcpy(temp, tail, sizeof(temp)); - dbg("format=%i, string='%s', tail='%s'", type ,string, tail); - - switch (type) { - case SUBST_CARDINFO: - if (attr == NULL) - Perror(space, "missing identification parametr for cardinfo"); - else { - const char *value = cardinfo_get(space, attr); - if (value == NULL) - break; - strlcat(string, value, maxsize); - dbg("substitute cardinfo{%s} '%s'", attr, value); - } - break; - case SUBST_CTL: - if (attr == NULL) - Perror(space, "missing identification parametr for ctl"); - else { - const char *value = elemid_get(space, attr); - if (value == NULL) - break; - strlcat(string, value, maxsize); - dbg("substitute ctl{%s} '%s'", attr, value); - } - break; - case SUBST_RESULT: - if (space->program_result == NULL) - break; - /* get part part of the result string */ - i = 0; - if (attr != NULL) - i = strtoul(attr, &rest, 10); - if (i > 0) { - dbg("request part #%d of result string", i); - cpos = space->program_result; - while (--i) { - while (cpos[0] != '\0' && !isspace(cpos[0])) - cpos++; - while (isspace(cpos[0])) - cpos++; - } - if (i > 0) { - Perror(space, "requested part of result string not found"); - break; - } - strlcpy(temp2, cpos, sizeof(temp2)); - /* %{2+}c copies the whole string from the second part on */ - if (rest[0] != '+') { - cpos = strchr(temp2, ' '); - if (cpos) - cpos[0] = '\0'; - } - strlcat(string, temp2, maxsize); - dbg("substitute part of result string '%s'", temp2); - } else { - strlcat(string, space->program_result, maxsize); - dbg("substitute result string '%s'", space->program_result); - } - break; - case SUBST_ATTR: - if (attr == NULL) - Perror(space, "missing file parameter for attr"); - else { - const char *value = NULL; - size_t size; - - pair = value_find(space, "sysfs_device"); - if (pair == NULL) - break; - value = sysfs_attr_get_value(pair->value, attr); - - if (value == NULL) - break; - - /* strip trailing whitespace and replace untrusted characters of sysfs value */ - size = strlcpy(temp2, value, sizeof(temp2)); - if (size >= sizeof(temp2)) - size = sizeof(temp2)-1; - while (size > 0 && isspace(temp2[size-1])) - temp2[--size] = '\0'; - count = replace_untrusted_chars(temp2); - if (count > 0) - Perror(space, "%i untrusted character(s) replaced" , count); - strlcat(string, temp2, maxsize); - dbg("substitute sysfs value '%s'", temp2); - } - break; - case SUBST_SYSFSROOT: - strlcat(string, sysfs_path, maxsize); - dbg("substitute sysfs_path '%s'", sysfs_path); - break; - case SUBST_ENV: - if (attr == NULL) { - dbg("missing attribute"); - break; - } - pos = getenv(attr); - if (pos == NULL) { - dbg("env '%s' not available", attr); - break; - } - dbg("substitute env '%s=%s'", attr, pos); - strlcat(string, pos, maxsize); - break; - default: - Perror(space, "unknown substitution type=%i", type); - break; - } - /* possibly truncate to format-char specified length */ - if (len != -1) { - head[len] = '\0'; - dbg("truncate to %i chars, subtitution string becomes '%s'", len, head); - } - strlcat(string, temp, maxsize); - } - /* unescape strings */ - head = tail = string; - while (*head != '\0') { - if (*head == '\\') { - head++; - if (*head == '\0') - break; - switch (*head) { - case 'a': *tail++ = '\a'; break; - case 'b': *tail++ = '\b'; break; - case 'n': *tail++ = '\n'; break; - case 'r': *tail++ = '\r'; break; - case 't': *tail++ = '\t'; break; - case 'v': *tail++ = '\v'; break; - case '\\': *tail++ = '\\'; break; - default: *tail++ = *head; break; - } - head++; - continue; - } - if (*head) - *tail++ = *head++; - } - *tail = 0; -} - -static int do_match(const char *key, enum key_op op, - const char *key_value, const char *value) -{ - int match; - - if (value == NULL) - return 0; - dbg("match %s '%s' <-> '%s'", key, key_value, value); - match = fnmatch(key_value, value, 0) == 0; - if (match && op == KEY_OP_MATCH) { - dbg("%s is true (matching value)", key); - return 1; - } - if (!match && op == KEY_OP_NOMATCH) { - dbg("%s is true (non-matching value)", key); - return 1; - } - dbg("%s is false", key); - return 0; -} - -static int ctl_match(snd_ctl_elem_id_t *pattern, snd_ctl_elem_id_t *id) -{ - if (snd_ctl_elem_id_get_interface(pattern) != -1 && - snd_ctl_elem_id_get_interface(pattern) != snd_ctl_elem_id_get_interface(id)) - return 0; - if (snd_ctl_elem_id_get_device(pattern) != -1 && - snd_ctl_elem_id_get_device(pattern) != snd_ctl_elem_id_get_device(id)) - return 0; - if (snd_ctl_elem_id_get_subdevice(pattern) != -1 && - snd_ctl_elem_id_get_subdevice(pattern) != snd_ctl_elem_id_get_subdevice(id)) - return 0; - if (snd_ctl_elem_id_get_index(pattern) != -1 && - snd_ctl_elem_id_get_index(pattern) != snd_ctl_elem_id_get_index(id)) - return 0; - if (fnmatch(snd_ctl_elem_id_get_name(pattern), snd_ctl_elem_id_get_name(id), 0) != 0) - return 0; - return 1; -} - -static -int run_program1(struct space *space, - const char *command0, char *result, - size_t ressize, size_t *reslen, int log) -{ - char *pos = strchr(command0, ' '); - int cmdlen = pos ? pos - command0 : strlen(command0); - int err, index; - snd_hctl_elem_t *elem; - snd_ctl_elem_id_t *id; - - if (cmdlen == 12 && strncmp(command0, "__ctl_search", 12) == 0) { - index = 0; - if (pos) - index = strtol(pos, NULL, 0); - err = snd_ctl_elem_id_malloc(&id); - if (err < 0) - return EXIT_FAILURE; - elem = snd_hctl_first_elem(space->ctl_handle); - while (elem) { - snd_hctl_elem_get_id(elem, id); - if (!ctl_match(space->ctl_id, id)) - goto next_search; - if (index > 0) { - index--; - goto next_search; - } - strlcpy(result, "0", ressize); - snd_ctl_elem_id_copy(space->ctl_id, id); - snd_ctl_elem_id_free(id); - dbg("__ctl_search found a control"); - return EXIT_SUCCESS; - next_search: - elem = snd_hctl_elem_next(elem); - } - snd_ctl_elem_id_free(id); - return EXIT_FAILURE; - } - if (cmdlen == 11 && strncmp(command0, "__ctl_count", 11) == 0) { - index = 0; - err = snd_ctl_elem_id_malloc(&id); - if (err < 0) - return EXIT_FAILURE; - elem = snd_hctl_first_elem(space->ctl_handle); - while (elem) { - snd_hctl_elem_get_id(elem, id); - if (!ctl_match(space->ctl_id, id)) - goto next_count; - index++; - next_count: - elem = snd_hctl_elem_next(elem); - } - snd_ctl_elem_id_free(id); - if (index > 0) { - snprintf(result, ressize, "%u", index); - dbg("__ctl_count found %s controls", result); - return EXIT_SUCCESS; - } - dbg("__ctl_count no match"); - return EXIT_FAILURE; - } - if (cmdlen == 11 && strncmp(command0, "__ctl_write", 11) == 0) { - } - Perror(space, "unknown buildin command '%s'", command0); - return EXIT_FAILURE; -} - -static int parse(struct space *space, const char *filename); - -static char *new_root_dir(const char *filename) -{ - char *res, *tmp; - - res = strdup(filename); - if (res) { - tmp = rindex(res, '/'); - if (tmp) - *tmp = '\0'; - } - dbg("new_root_dir '%s' '%s'", filename, res); - return res; -} - -static int parse_line(struct space *space, char *line, size_t linesize) -{ - char *linepos; - char *key, *value, *attr, *temp; - struct pair *pair; - enum key_op op; - int err = 0, count; - char string[PATH_SIZE]; - char result[PATH_SIZE]; - - linepos = line; - while (*linepos != '\0') { - op = KEY_OP_UNSET; - - err = get_key(&linepos, &key, &op, &value); - if (err < 0) - goto invalid; - - if (strncasecmp(key, "LABEL", 5) == 0) { - if (op != KEY_OP_ASSIGN) { - Perror(space, "invalid LABEL operation"); - goto invalid; - } - if (space->go_to && strcmp(space->go_to, value) == 0) { - free(space->go_to); - space->go_to = NULL; - } - continue; - } - - if (space->go_to) { - dbg("skip (GOTO '%s')", space->go_to); - break; /* not for us */ - } - - if (strncasecmp(key, "CTL{", 4) == 0) { - attr = get_key_attribute(space, key + 3, string, sizeof(string)); - if (attr == NULL) { - Perror(space, "error parsing CTL attribute"); - goto invalid; - } - if (op == KEY_OP_ASSIGN) { - strlcpy(result, value, sizeof(result)); - apply_format(space, result, sizeof(result)); - dbg("ctl assign: '%s' '%s'", value, attr); - err = elemid_set(space, attr, result); - if (space->program_result) { - free(space->program_result); - space->program_result = NULL; - } - snprintf(string, sizeof(string), "%i", err); - space->program_result = strdup(string); - if (err < 0 || space->program_result == NULL) { - err = 0; - break; - } - } else if (op == KEY_OP_MATCH || op == KEY_OP_NOMATCH) { - dbg("ctl match: '%s' '%s'", value, attr); - temp = (char *)elemid_get(space, attr); - if (!do_match(key, op, value, temp)) - break; - } else { - Perror(space, "invalid CTL{} operation"); - goto invalid; - } - continue; - } - if (strcasecmp(key, "RESULT") == 0) { - if (op == KEY_OP_MATCH || op == KEY_OP_NOMATCH) { - if (!do_match(key, op, value, space->program_result)) - break; - } 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; - } - continue; - } - if (strcasecmp(key, "PROGRAM") == 0) { - if (op == KEY_OP_UNSET) - continue; - strlcpy(string, value, sizeof(string)); - apply_format(space, string, sizeof(string)); - if (space->program_result) { - free(space->program_result); - space->program_result = NULL; - } - if (run_program(space, string, result, sizeof(result), NULL, space->log_run) != 0) { - dbg("PROGRAM '%s' is false", string); - if (op != KEY_OP_NOMATCH) - break; - } else { - remove_trailing_chars(result, '\n'); - count = replace_untrusted_chars(result); - if (count) - info("%i untrusted character(s) replaced", count); - dbg("PROGRAM '%s' result is '%s'", string, result); - space->program_result = strdup(result); - if (space->program_result == NULL) - break; - dbg("PROGRAM returned successful"); - if (op == KEY_OP_NOMATCH) - break; - } - dbg("PROGRAM key is true"); - continue; - } - if (strncasecmp(key, "CARDINFO{", 9) == 0) { - attr = get_key_attribute(space, key + 8, string, sizeof(string)); - if (attr == NULL) { - Perror(space, "error parsing CARDINFO attribute"); - goto invalid; - } - if (op == KEY_OP_MATCH || op == KEY_OP_NOMATCH) { - dbg("cardinfo: '%s' '%s'", value, attr); - temp = (char *)cardinfo_get(space, attr); - if (!do_match(key, op, value, temp)) - break; - } else { - Perror(space, "invalid CARDINFO{} operation"); - goto invalid; - } - continue; - } - if (strncasecmp(key, "ATTR{", 5) == 0) { - attr = get_key_attribute(space, key + 4, string, sizeof(string)); - if (attr == NULL) { - Perror(space, "error parsing ATTR attribute"); - goto invalid; - } - if (op == KEY_OP_MATCH || op == KEY_OP_NOMATCH) { - pair = value_find(space, "sysfs_device"); - if (pair == NULL) - break; - dbg("sysfs_attr: '%s' '%s'", pair->value, attr); - temp = sysfs_attr_get_value(pair->value, attr); - if (!do_match(key, op, value, temp)) - break; - } else { - Perror(space, "invalid ATTR{} operation"); - goto invalid; - } - continue; - } - if (strncasecmp(key, "ENV{", 4) == 0) { - attr = get_key_attribute(space, key + 3, string, sizeof(string)); - if (attr == NULL) { - Perror(space, "error parsing ENV attribute"); - goto invalid; - } - if (op == KEY_OP_MATCH || op == KEY_OP_NOMATCH) { - temp = getenv(attr); - dbg("env: '%s' '%s'", attr, temp); - if (!do_match(key, op, value, temp)) - break; - } else if (op == KEY_OP_ASSIGN || - op == KEY_OP_ASSIGN_FINAL) { - strlcpy(result, value, sizeof(result)); - apply_format(space, result, sizeof(result)); - dbg("env set: '%s' '%s'", attr, result); - if (setenv(attr, result, op == KEY_OP_ASSIGN_FINAL)) - break; - } else { - Perror(space, "invalid ENV{} operation"); - goto invalid; - } - continue; - } - if (strcasecmp(key, "GOTO") == 0) { - if (op != KEY_OP_ASSIGN) { - Perror(space, "invalid GOTO operation"); - goto invalid; - } - space->go_to = strdup(value); - if (space->go_to == NULL) { - err = -ENOMEM; - break; - } - continue; - } - 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"); - goto invalid; - } - if (value[0] == '/') - strlcpy(string, value, sizeof(string)); - else { - strlcpy(string, space->rootdir, sizeof(string)); - strlcat(string, "/", sizeof(string)); - strlcat(string, value, sizeof(string)); - } - rootdir = space->rootdir; - go_to = space->go_to; - filename = space->filename; - linenum = space->linenum; - 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); - } - if (err) - break; - } - 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; - space->filename = filename; - space->linenum = linenum; - if (space->quit) - break; - if (err) - 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, "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); - } - return err; - -invalid: - Perror(space, "invalid rule"); - return -EINVAL; -} - -static int parse(struct space *space, const char *filename) -{ - char *buf, *bufline, *line; - size_t bufsize, pos, count, linesize; - unsigned int linenum, i, j, linenum_adj; - int err; - - dbg("start of file '%s'", filename); - - if (file_map(filename, &buf, &bufsize) != 0) { - err = errno; - error("Unable to open file '%s': %s", filename, strerror(err)); - return -err; - } - - err = 0; - pos = 0; - linenum = 0; - linesize = 128; - line = malloc(linesize); - if (line == NULL) - return -ENOMEM; - space->filename = filename; - while (!err && pos < bufsize && !space->quit) { - count = line_width(buf, bufsize, pos); - bufline = buf + pos; - pos += count + 1; - linenum++; - - /* skip whitespaces */ - while (count > 0 && isspace(bufline[0])) { - bufline++; - count--; - } - if (count == 0) - continue; - - /* comment check */ - if (bufline[0] == '#') - continue; - - if (count > linesize - 1) { - free(line); - linesize = (count + 127 + 1) & ~127; - if (linesize > 2048) { - error("file %s, line %i too long", filename, linenum); - err = -EINVAL; - break; - } - line = malloc(linesize); - if (line == NULL) { - err = -EINVAL; - break; - } - } - - /* skip backslash and newline from multiline rules */ - linenum_adj = 0; - for (i = j = 0; i < count; i++) { - if (bufline[i] == '\\' && bufline[i+1] == '\n') { - linenum_adj++; - continue; - } - line[j++] = bufline[i]; - } - line[j] = '\0'; - - dbg("read (%i) '%s'", linenum, line); - space->linenum = linenum; - err = parse_line(space, line, linesize); - if (err == -EJUSTRETURN) { - err = 0; - break; - } - linenum += linenum_adj; - } - - free(line); - space->filename = NULL; - space->linenum = -1; - file_unmap(buf, bufsize); - dbg("end of file '%s'", filename); - return err ? err : -abs(space->exit_code); -} - -int init(const char *filename, const char *cardname) -{ - struct space *space; - int err = 0, card, first; - - sysfs_init(); - if (!cardname) { - first = 1; - card = -1; - while (1) { - if (snd_card_next(&card) < 0) - break; - if (card < 0) { - if (first) { - error("No soundcards found..."); - return -ENODEV; - } - break; - } - first = 0; - err = init_space(&space, card); - if (err == 0 && - (space->rootdir = new_root_dir(filename)) != NULL) - err = parse(space, filename); - free_space(space); - if (err < 0) - break; - } - } else { - card = snd_card_get_index(cardname); - if (card < 0) { - error("Cannot find soundcard '%s'...", cardname); - goto error; - } - memset(&space, 0, sizeof(space)); - err = init_space(&space, card); - if (err == 0 && - (space->rootdir = new_root_dir(filename)) != NULL) - err = parse(space, filename); - free_space(space); - } - error: - sysfs_cleanup(); - return err; -} |