Blame alsactl/init_parse.c

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