1c72fcc34Sopenharmony_ci/* 2c72fcc34Sopenharmony_ci * Advanced Linux Sound Architecture Control Program - Parse initialization files 3c72fcc34Sopenharmony_ci * Copyright (c) by Jaroslav Kysela <perex@perex.cz>, 4c72fcc34Sopenharmony_ci * Greg Kroah-Hartman <greg@kroah.com>, 5c72fcc34Sopenharmony_ci * Kay Sievers <kay.sievers@vrfy.org> 6c72fcc34Sopenharmony_ci * 7c72fcc34Sopenharmony_ci * 8c72fcc34Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 9c72fcc34Sopenharmony_ci * it under the terms of the GNU General Public License as published by 10c72fcc34Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 11c72fcc34Sopenharmony_ci * (at your option) any later version. 12c72fcc34Sopenharmony_ci * 13c72fcc34Sopenharmony_ci * This program is distributed in the hope that it will be useful, 14c72fcc34Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 15c72fcc34Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16c72fcc34Sopenharmony_ci * GNU General Public License for more details. 17c72fcc34Sopenharmony_ci * 18c72fcc34Sopenharmony_ci * You should have received a copy of the GNU General Public License 19c72fcc34Sopenharmony_ci * along with this program; if not, write to the Free Software 20c72fcc34Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21c72fcc34Sopenharmony_ci * 22c72fcc34Sopenharmony_ci */ 23c72fcc34Sopenharmony_ci 24c72fcc34Sopenharmony_ci#include <stdlib.h> 25c72fcc34Sopenharmony_ci#include <stdio.h> 26c72fcc34Sopenharmony_ci#include <stddef.h> 27c72fcc34Sopenharmony_ci#include <unistd.h> 28c72fcc34Sopenharmony_ci#include <string.h> 29c72fcc34Sopenharmony_ci#include <fcntl.h> 30c72fcc34Sopenharmony_ci#include <ctype.h> 31c72fcc34Sopenharmony_ci#include <errno.h> 32c72fcc34Sopenharmony_ci#include <fnmatch.h> 33c72fcc34Sopenharmony_ci#include <sys/stat.h> 34c72fcc34Sopenharmony_ci#include <sys/un.h> 35c72fcc34Sopenharmony_ci#include <sys/wait.h> 36c72fcc34Sopenharmony_ci#include <sys/select.h> 37c72fcc34Sopenharmony_ci#include <sys/types.h> 38c72fcc34Sopenharmony_ci#include <dirent.h> 39c72fcc34Sopenharmony_ci#include <math.h> 40c72fcc34Sopenharmony_ci#include "aconfig.h" 41c72fcc34Sopenharmony_ci#include "alsactl.h" 42c72fcc34Sopenharmony_ci#include "list.h" 43c72fcc34Sopenharmony_ci 44c72fcc34Sopenharmony_ci#define PATH_SIZE 512 45c72fcc34Sopenharmony_ci#define NAME_SIZE 128 46c72fcc34Sopenharmony_ci#define EJUSTRETURN 0x7fffffff 47c72fcc34Sopenharmony_ci 48c72fcc34Sopenharmony_cienum key_op { 49c72fcc34Sopenharmony_ci KEY_OP_UNSET, 50c72fcc34Sopenharmony_ci KEY_OP_MATCH, 51c72fcc34Sopenharmony_ci KEY_OP_NOMATCH, 52c72fcc34Sopenharmony_ci KEY_OP_ADD, 53c72fcc34Sopenharmony_ci KEY_OP_ASSIGN, 54c72fcc34Sopenharmony_ci KEY_OP_ASSIGN_FINAL 55c72fcc34Sopenharmony_ci}; 56c72fcc34Sopenharmony_ci 57c72fcc34Sopenharmony_cistruct pair { 58c72fcc34Sopenharmony_ci char *key; 59c72fcc34Sopenharmony_ci char *value; 60c72fcc34Sopenharmony_ci struct pair *next; 61c72fcc34Sopenharmony_ci}; 62c72fcc34Sopenharmony_ci 63c72fcc34Sopenharmony_cistruct space { 64c72fcc34Sopenharmony_ci struct pair *pairs; 65c72fcc34Sopenharmony_ci char *rootdir; 66c72fcc34Sopenharmony_ci char *go_to; 67c72fcc34Sopenharmony_ci char *program_result; 68c72fcc34Sopenharmony_ci const char *filename; 69c72fcc34Sopenharmony_ci int linenum; 70c72fcc34Sopenharmony_ci int log_run; 71c72fcc34Sopenharmony_ci int exit_code; 72c72fcc34Sopenharmony_ci int quit; 73c72fcc34Sopenharmony_ci unsigned int ctl_id_changed; 74c72fcc34Sopenharmony_ci snd_hctl_t *ctl_handle; 75c72fcc34Sopenharmony_ci snd_ctl_card_info_t *ctl_card_info; 76c72fcc34Sopenharmony_ci snd_ctl_elem_id_t *ctl_id; 77c72fcc34Sopenharmony_ci snd_ctl_elem_info_t *ctl_info; 78c72fcc34Sopenharmony_ci snd_ctl_elem_value_t *ctl_value; 79c72fcc34Sopenharmony_ci}; 80c72fcc34Sopenharmony_ci 81c72fcc34Sopenharmony_cistatic void Perror(struct space *space, const char *fmt, ...) 82c72fcc34Sopenharmony_ci{ 83c72fcc34Sopenharmony_ci va_list arg; 84c72fcc34Sopenharmony_ci va_start(arg, fmt); 85c72fcc34Sopenharmony_ci fprintf(stderr, "%s:%i: ", space->filename, space->linenum); 86c72fcc34Sopenharmony_ci vfprintf(stderr, fmt, arg); 87c72fcc34Sopenharmony_ci putc('\n', stderr); 88c72fcc34Sopenharmony_ci va_end(arg); 89c72fcc34Sopenharmony_ci} 90c72fcc34Sopenharmony_ci 91c72fcc34Sopenharmony_ci#include "init_sysdeps.c" 92c72fcc34Sopenharmony_ci#include "init_utils_string.c" 93c72fcc34Sopenharmony_ci#include "init_utils_run.c" 94c72fcc34Sopenharmony_ci#include "init_sysfs.c" 95c72fcc34Sopenharmony_ci 96c72fcc34Sopenharmony_cistatic void free_space(struct space *space) 97c72fcc34Sopenharmony_ci{ 98c72fcc34Sopenharmony_ci struct pair *pair = space->pairs; 99c72fcc34Sopenharmony_ci struct pair *next = pair; 100c72fcc34Sopenharmony_ci 101c72fcc34Sopenharmony_ci while (next) { 102c72fcc34Sopenharmony_ci pair = next; 103c72fcc34Sopenharmony_ci next = pair->next; 104c72fcc34Sopenharmony_ci free(pair->value); 105c72fcc34Sopenharmony_ci free(pair->key); 106c72fcc34Sopenharmony_ci free(pair); 107c72fcc34Sopenharmony_ci } 108c72fcc34Sopenharmony_ci space->pairs = NULL; 109c72fcc34Sopenharmony_ci if (space->ctl_value) { 110c72fcc34Sopenharmony_ci snd_ctl_elem_value_free(space->ctl_value); 111c72fcc34Sopenharmony_ci space->ctl_value = NULL; 112c72fcc34Sopenharmony_ci } 113c72fcc34Sopenharmony_ci if (space->ctl_info) { 114c72fcc34Sopenharmony_ci snd_ctl_elem_info_free(space->ctl_info); 115c72fcc34Sopenharmony_ci space->ctl_info = NULL; 116c72fcc34Sopenharmony_ci } 117c72fcc34Sopenharmony_ci if (space->ctl_id) { 118c72fcc34Sopenharmony_ci snd_ctl_elem_id_free(space->ctl_id); 119c72fcc34Sopenharmony_ci space->ctl_id = NULL; 120c72fcc34Sopenharmony_ci } 121c72fcc34Sopenharmony_ci if (space->ctl_card_info) { 122c72fcc34Sopenharmony_ci snd_ctl_card_info_free(space->ctl_card_info); 123c72fcc34Sopenharmony_ci space->ctl_card_info = NULL; 124c72fcc34Sopenharmony_ci } 125c72fcc34Sopenharmony_ci if (space->ctl_handle) { 126c72fcc34Sopenharmony_ci snd_hctl_close(space->ctl_handle); 127c72fcc34Sopenharmony_ci space->ctl_handle = NULL; 128c72fcc34Sopenharmony_ci } 129c72fcc34Sopenharmony_ci if (space->rootdir) 130c72fcc34Sopenharmony_ci free(space->rootdir); 131c72fcc34Sopenharmony_ci if (space->program_result) 132c72fcc34Sopenharmony_ci free(space->program_result); 133c72fcc34Sopenharmony_ci if (space->go_to) 134c72fcc34Sopenharmony_ci free(space->go_to); 135c72fcc34Sopenharmony_ci free(space); 136c72fcc34Sopenharmony_ci} 137c72fcc34Sopenharmony_ci 138c72fcc34Sopenharmony_cistatic struct pair *value_find(struct space *space, const char *key) 139c72fcc34Sopenharmony_ci{ 140c72fcc34Sopenharmony_ci struct pair *pair = space->pairs; 141c72fcc34Sopenharmony_ci 142c72fcc34Sopenharmony_ci while (pair && strcmp(pair->key, key) != 0) 143c72fcc34Sopenharmony_ci pair = pair->next; 144c72fcc34Sopenharmony_ci return pair; 145c72fcc34Sopenharmony_ci} 146c72fcc34Sopenharmony_ci 147c72fcc34Sopenharmony_cistatic int value_set(struct space *space, const char *key, const char *value) 148c72fcc34Sopenharmony_ci{ 149c72fcc34Sopenharmony_ci struct pair *pair; 150c72fcc34Sopenharmony_ci 151c72fcc34Sopenharmony_ci pair = value_find(space, key); 152c72fcc34Sopenharmony_ci if (pair) { 153c72fcc34Sopenharmony_ci free(pair->value); 154c72fcc34Sopenharmony_ci pair->value = strdup(value); 155c72fcc34Sopenharmony_ci if (pair->value == NULL) 156c72fcc34Sopenharmony_ci return -ENOMEM; 157c72fcc34Sopenharmony_ci } else { 158c72fcc34Sopenharmony_ci pair = malloc(sizeof(struct pair)); 159c72fcc34Sopenharmony_ci if (pair == NULL) 160c72fcc34Sopenharmony_ci return -ENOMEM; 161c72fcc34Sopenharmony_ci pair->key = strdup(key); 162c72fcc34Sopenharmony_ci if (pair->key == NULL) { 163c72fcc34Sopenharmony_ci free(pair); 164c72fcc34Sopenharmony_ci return -ENOMEM; 165c72fcc34Sopenharmony_ci } 166c72fcc34Sopenharmony_ci pair->value = strdup(value); 167c72fcc34Sopenharmony_ci if (pair->value == NULL) { 168c72fcc34Sopenharmony_ci free(pair->key); 169c72fcc34Sopenharmony_ci free(pair); 170c72fcc34Sopenharmony_ci return -ENOMEM; 171c72fcc34Sopenharmony_ci } 172c72fcc34Sopenharmony_ci pair->next = space->pairs; 173c72fcc34Sopenharmony_ci space->pairs = pair; 174c72fcc34Sopenharmony_ci } 175c72fcc34Sopenharmony_ci return 0; 176c72fcc34Sopenharmony_ci} 177c72fcc34Sopenharmony_ci 178c72fcc34Sopenharmony_cistatic int init_space(struct space **space, int card) 179c72fcc34Sopenharmony_ci{ 180c72fcc34Sopenharmony_ci struct space *res; 181c72fcc34Sopenharmony_ci char device[16]; 182c72fcc34Sopenharmony_ci int err; 183c72fcc34Sopenharmony_ci 184c72fcc34Sopenharmony_ci res = calloc(1, sizeof(struct space)); 185c72fcc34Sopenharmony_ci if (res == NULL) 186c72fcc34Sopenharmony_ci return -ENOMEM; 187c72fcc34Sopenharmony_ci res->ctl_id_changed = ~0; 188c72fcc34Sopenharmony_ci res->linenum = -1; 189c72fcc34Sopenharmony_ci sprintf(device, "hw:%d", card); 190c72fcc34Sopenharmony_ci err = snd_hctl_open(&res->ctl_handle, device, 0); 191c72fcc34Sopenharmony_ci if (err < 0) 192c72fcc34Sopenharmony_ci goto error; 193c72fcc34Sopenharmony_ci err = snd_hctl_load(res->ctl_handle); 194c72fcc34Sopenharmony_ci if (err < 0) 195c72fcc34Sopenharmony_ci goto error; 196c72fcc34Sopenharmony_ci err = snd_ctl_card_info_malloc(&res->ctl_card_info); 197c72fcc34Sopenharmony_ci if (err < 0) 198c72fcc34Sopenharmony_ci goto error; 199c72fcc34Sopenharmony_ci err = snd_ctl_card_info(snd_hctl_ctl(res->ctl_handle), res->ctl_card_info); 200c72fcc34Sopenharmony_ci if (err < 0) 201c72fcc34Sopenharmony_ci goto error; 202c72fcc34Sopenharmony_ci err = snd_ctl_elem_id_malloc(&res->ctl_id); 203c72fcc34Sopenharmony_ci if (err < 0) 204c72fcc34Sopenharmony_ci goto error; 205c72fcc34Sopenharmony_ci err = snd_ctl_elem_info_malloc(&res->ctl_info); 206c72fcc34Sopenharmony_ci if (err < 0) 207c72fcc34Sopenharmony_ci goto error; 208c72fcc34Sopenharmony_ci err = snd_ctl_elem_value_malloc(&res->ctl_value); 209c72fcc34Sopenharmony_ci if (err < 0) 210c72fcc34Sopenharmony_ci goto error; 211c72fcc34Sopenharmony_ci *space = res; 212c72fcc34Sopenharmony_ci return 0; 213c72fcc34Sopenharmony_ci error: 214c72fcc34Sopenharmony_ci free_space(res); 215c72fcc34Sopenharmony_ci return err; 216c72fcc34Sopenharmony_ci} 217c72fcc34Sopenharmony_ci 218c72fcc34Sopenharmony_cistatic const char *cardinfo_get(struct space *space, const char *attr) 219c72fcc34Sopenharmony_ci{ 220c72fcc34Sopenharmony_ci if (strncasecmp(attr, "CARD", 4) == 0) { 221c72fcc34Sopenharmony_ci static char res[16]; 222c72fcc34Sopenharmony_ci sprintf(res, "%u", snd_ctl_card_info_get_card(space->ctl_card_info)); 223c72fcc34Sopenharmony_ci return res; 224c72fcc34Sopenharmony_ci } 225c72fcc34Sopenharmony_ci if (strncasecmp(attr, "ID", 2) == 0) 226c72fcc34Sopenharmony_ci return snd_ctl_card_info_get_id(space->ctl_card_info); 227c72fcc34Sopenharmony_ci if (strncasecmp(attr, "DRIVER", 6) == 0) 228c72fcc34Sopenharmony_ci return snd_ctl_card_info_get_driver(space->ctl_card_info); 229c72fcc34Sopenharmony_ci if (strncasecmp(attr, "NAME", 4) == 0) 230c72fcc34Sopenharmony_ci return snd_ctl_card_info_get_name(space->ctl_card_info); 231c72fcc34Sopenharmony_ci if (strncasecmp(attr, "LONGNAME", 8) == 0) 232c72fcc34Sopenharmony_ci return snd_ctl_card_info_get_longname(space->ctl_card_info); 233c72fcc34Sopenharmony_ci if (strncasecmp(attr, "MIXERNAME", 9) == 0) 234c72fcc34Sopenharmony_ci return snd_ctl_card_info_get_mixername(space->ctl_card_info); 235c72fcc34Sopenharmony_ci if (strncasecmp(attr, "COMPONENTS", 10) == 0) 236c72fcc34Sopenharmony_ci return snd_ctl_card_info_get_components(space->ctl_card_info); 237c72fcc34Sopenharmony_ci Perror(space, "unknown cardinfo{} attribute '%s'", attr); 238c72fcc34Sopenharmony_ci return NULL; 239c72fcc34Sopenharmony_ci} 240c72fcc34Sopenharmony_ci 241c72fcc34Sopenharmony_cistatic int check_id_changed(struct space *space, unsigned int what) 242c72fcc34Sopenharmony_ci{ 243c72fcc34Sopenharmony_ci snd_hctl_elem_t *elem; 244c72fcc34Sopenharmony_ci int err; 245c72fcc34Sopenharmony_ci 246c72fcc34Sopenharmony_ci if ((space->ctl_id_changed & what & 1) != 0) { 247c72fcc34Sopenharmony_ci snd_ctl_elem_id_set_numid(space->ctl_id, 0); 248c72fcc34Sopenharmony_ci elem = snd_hctl_find_elem(space->ctl_handle, space->ctl_id); 249c72fcc34Sopenharmony_ci if (!elem) 250c72fcc34Sopenharmony_ci return -ENOENT; 251c72fcc34Sopenharmony_ci err = snd_hctl_elem_info(elem, space->ctl_info); 252c72fcc34Sopenharmony_ci if (err == 0) 253c72fcc34Sopenharmony_ci space->ctl_id_changed &= ~1; 254c72fcc34Sopenharmony_ci return err; 255c72fcc34Sopenharmony_ci } 256c72fcc34Sopenharmony_ci if ((space->ctl_id_changed & what & 2) != 0) { 257c72fcc34Sopenharmony_ci snd_ctl_elem_id_set_numid(space->ctl_id, 0); 258c72fcc34Sopenharmony_ci elem = snd_hctl_find_elem(space->ctl_handle, space->ctl_id); 259c72fcc34Sopenharmony_ci if (!elem) 260c72fcc34Sopenharmony_ci return -ENOENT; 261c72fcc34Sopenharmony_ci err = snd_hctl_elem_read(elem, space->ctl_value); 262c72fcc34Sopenharmony_ci if (err == 0) 263c72fcc34Sopenharmony_ci space->ctl_id_changed &= ~2; 264c72fcc34Sopenharmony_ci return err; 265c72fcc34Sopenharmony_ci } 266c72fcc34Sopenharmony_ci return 0; 267c72fcc34Sopenharmony_ci} 268c72fcc34Sopenharmony_ci 269c72fcc34Sopenharmony_cistatic const char *get_ctl_value(struct space *space) 270c72fcc34Sopenharmony_ci{ 271c72fcc34Sopenharmony_ci snd_ctl_elem_type_t type; 272c72fcc34Sopenharmony_ci unsigned int idx, count; 273c72fcc34Sopenharmony_ci static char res[1024], tmp[16]; 274c72fcc34Sopenharmony_ci static const char hex[] = "0123456789abcdef"; 275c72fcc34Sopenharmony_ci char *pos; 276c72fcc34Sopenharmony_ci const char *pos1; 277c72fcc34Sopenharmony_ci 278c72fcc34Sopenharmony_ci type = snd_ctl_elem_info_get_type(space->ctl_info); 279c72fcc34Sopenharmony_ci count = snd_ctl_elem_info_get_count(space->ctl_info); 280c72fcc34Sopenharmony_ci res[0] = '\0'; 281c72fcc34Sopenharmony_ci switch (type) { 282c72fcc34Sopenharmony_ci case SND_CTL_ELEM_TYPE_BOOLEAN: 283c72fcc34Sopenharmony_ci for (idx = 0; idx < count; idx++) { 284c72fcc34Sopenharmony_ci if (idx > 0) 285c72fcc34Sopenharmony_ci strlcat(res, ",", sizeof(res)); 286c72fcc34Sopenharmony_ci strlcat(res, snd_ctl_elem_value_get_boolean(space->ctl_value, idx) ? "on" : "off", sizeof(res)); 287c72fcc34Sopenharmony_ci } 288c72fcc34Sopenharmony_ci break; 289c72fcc34Sopenharmony_ci case SND_CTL_ELEM_TYPE_INTEGER: 290c72fcc34Sopenharmony_ci for (idx = 0; idx < count; idx++) { 291c72fcc34Sopenharmony_ci if (idx > 0) 292c72fcc34Sopenharmony_ci strlcat(res, ",", sizeof(res)); 293c72fcc34Sopenharmony_ci snprintf(tmp, sizeof(tmp), "%li", snd_ctl_elem_value_get_integer(space->ctl_value, idx)); 294c72fcc34Sopenharmony_ci strlcat(res, tmp, sizeof(res)); 295c72fcc34Sopenharmony_ci } 296c72fcc34Sopenharmony_ci break; 297c72fcc34Sopenharmony_ci case SND_CTL_ELEM_TYPE_INTEGER64: 298c72fcc34Sopenharmony_ci for (idx = 0; idx < count; idx++) { 299c72fcc34Sopenharmony_ci if (idx > 0) 300c72fcc34Sopenharmony_ci strlcat(res, ",", sizeof(res)); 301c72fcc34Sopenharmony_ci snprintf(tmp, sizeof(tmp), "%lli", snd_ctl_elem_value_get_integer64(space->ctl_value, idx)); 302c72fcc34Sopenharmony_ci strlcat(res, tmp, sizeof(res)); 303c72fcc34Sopenharmony_ci } 304c72fcc34Sopenharmony_ci break; 305c72fcc34Sopenharmony_ci case SND_CTL_ELEM_TYPE_ENUMERATED: 306c72fcc34Sopenharmony_ci for (idx = 0; idx < count; idx++) { 307c72fcc34Sopenharmony_ci if (idx > 0) 308c72fcc34Sopenharmony_ci strlcat(res, ",", sizeof(res)); 309c72fcc34Sopenharmony_ci snprintf(tmp, sizeof(tmp), "%u", snd_ctl_elem_value_get_enumerated(space->ctl_value, idx)); 310c72fcc34Sopenharmony_ci strlcat(res, tmp, sizeof(res)); 311c72fcc34Sopenharmony_ci } 312c72fcc34Sopenharmony_ci break; 313c72fcc34Sopenharmony_ci case SND_CTL_ELEM_TYPE_BYTES: 314c72fcc34Sopenharmony_ci case SND_CTL_ELEM_TYPE_IEC958: 315c72fcc34Sopenharmony_ci if (type == SND_CTL_ELEM_TYPE_IEC958) 316c72fcc34Sopenharmony_ci count = sizeof(snd_aes_iec958_t); 317c72fcc34Sopenharmony_ci if (count > (sizeof(res)-1)/2) 318c72fcc34Sopenharmony_ci count = (sizeof(res)-1/2); 319c72fcc34Sopenharmony_ci pos = res; 320c72fcc34Sopenharmony_ci pos1 = snd_ctl_elem_value_get_bytes(space->ctl_value); 321c72fcc34Sopenharmony_ci while (count > 0) { 322c72fcc34Sopenharmony_ci idx = *pos1++; 323c72fcc34Sopenharmony_ci *pos++ = hex[idx >> 4]; 324c72fcc34Sopenharmony_ci *pos++ = hex[idx & 0x0f]; 325c72fcc34Sopenharmony_ci count++; 326c72fcc34Sopenharmony_ci } 327c72fcc34Sopenharmony_ci *pos++ = '\0'; 328c72fcc34Sopenharmony_ci break; 329c72fcc34Sopenharmony_ci default: 330c72fcc34Sopenharmony_ci Perror(space, "unknown element type '%i'", type); 331c72fcc34Sopenharmony_ci return NULL; 332c72fcc34Sopenharmony_ci } 333c72fcc34Sopenharmony_ci return res; 334c72fcc34Sopenharmony_ci} 335c72fcc34Sopenharmony_ci 336c72fcc34Sopenharmony_ci/* Function to convert from percentage to volume. val = percentage */ 337c72fcc34Sopenharmony_ci#define convert_prange1(val, min, max) \ 338c72fcc34Sopenharmony_ci ceil((val) * ((max) - (min)) * 0.01 + (min)) 339c72fcc34Sopenharmony_ci 340c72fcc34Sopenharmony_cistatic int set_ctl_value(struct space *space, const char *value, int all) 341c72fcc34Sopenharmony_ci{ 342c72fcc34Sopenharmony_ci snd_ctl_elem_type_t type; 343c72fcc34Sopenharmony_ci unsigned int idx, idx2, count, items; 344c72fcc34Sopenharmony_ci const char *pos, *pos2; 345c72fcc34Sopenharmony_ci snd_hctl_elem_t *elem; 346c72fcc34Sopenharmony_ci int val; 347c72fcc34Sopenharmony_ci long lval; 348c72fcc34Sopenharmony_ci 349c72fcc34Sopenharmony_ci type = snd_ctl_elem_info_get_type(space->ctl_info); 350c72fcc34Sopenharmony_ci count = snd_ctl_elem_info_get_count(space->ctl_info); 351c72fcc34Sopenharmony_ci switch (type) { 352c72fcc34Sopenharmony_ci case SND_CTL_ELEM_TYPE_BOOLEAN: 353c72fcc34Sopenharmony_ci for (idx = 0; idx < count; idx++) { 354c72fcc34Sopenharmony_ci while (*value == ' ') 355c72fcc34Sopenharmony_ci value++; 356c72fcc34Sopenharmony_ci if (*value == '\0') 357c72fcc34Sopenharmony_ci goto missing; 358c72fcc34Sopenharmony_ci val = strncasecmp(value, "true", 4) == 0 || 359c72fcc34Sopenharmony_ci strncasecmp(value, "yes", 3) == 0 || 360c72fcc34Sopenharmony_ci strncasecmp(value, "on", 2) == 0 || 361c72fcc34Sopenharmony_ci strncasecmp(value, "1", 1) == 0; 362c72fcc34Sopenharmony_ci snd_ctl_elem_value_set_boolean(space->ctl_value, idx, val); 363c72fcc34Sopenharmony_ci if (all) 364c72fcc34Sopenharmony_ci continue; 365c72fcc34Sopenharmony_ci pos = strchr(value, ','); 366c72fcc34Sopenharmony_ci value = pos ? pos + 1 : value + strlen(value) - 1; 367c72fcc34Sopenharmony_ci } 368c72fcc34Sopenharmony_ci break; 369c72fcc34Sopenharmony_ci case SND_CTL_ELEM_TYPE_INTEGER: 370c72fcc34Sopenharmony_ci for (idx = 0; idx < count; idx++) { 371c72fcc34Sopenharmony_ci while (*value == ' ') 372c72fcc34Sopenharmony_ci value++; 373c72fcc34Sopenharmony_ci pos = strchr(value, ','); 374c72fcc34Sopenharmony_ci if (pos) 375c72fcc34Sopenharmony_ci *(char *)pos = '\0'; 376c72fcc34Sopenharmony_ci remove_trailing_chars((char *)value, ' '); 377c72fcc34Sopenharmony_ci items = pos ? (unsigned)(pos - value) : (unsigned)strlen(value); 378c72fcc34Sopenharmony_ci if (items > 1 && value[items-1] == '%') { 379c72fcc34Sopenharmony_ci 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)); 380c72fcc34Sopenharmony_ci snd_ctl_elem_value_set_integer(space->ctl_value, idx, val); 381c72fcc34Sopenharmony_ci } else if (items > 2 && value[items-2] == 'd' && value[items-1] == 'B') { 382c72fcc34Sopenharmony_ci val = strtol(value, NULL, 0) * 100; 383c72fcc34Sopenharmony_ci if ((pos2 = strchr(value, '.')) != NULL) { 384c72fcc34Sopenharmony_ci if (isdigit(*(pos2-1)) && isdigit(*(pos2-2))) { 385c72fcc34Sopenharmony_ci if (val < 0) 386c72fcc34Sopenharmony_ci val -= strtol(pos2 + 1, NULL, 0); 387c72fcc34Sopenharmony_ci else 388c72fcc34Sopenharmony_ci val += strtol(pos2 + 1, NULL, 0); 389c72fcc34Sopenharmony_ci } else if (isdigit(*(pos2-1))) { 390c72fcc34Sopenharmony_ci if (val < 0) 391c72fcc34Sopenharmony_ci val -= strtol(pos2 + 1, NULL, 0) * 10; 392c72fcc34Sopenharmony_ci else 393c72fcc34Sopenharmony_ci val += strtol(pos2 + 1, NULL, 0) * 10; 394c72fcc34Sopenharmony_ci } 395c72fcc34Sopenharmony_ci } 396c72fcc34Sopenharmony_ci val = snd_ctl_convert_from_dB(snd_hctl_ctl(space->ctl_handle), space->ctl_id, val, &lval, -1); 397c72fcc34Sopenharmony_ci if (val < 0) { 398c72fcc34Sopenharmony_ci dbg("unable to convert dB value '%s' to internal integer range", value); 399c72fcc34Sopenharmony_ci return val; 400c72fcc34Sopenharmony_ci } 401c72fcc34Sopenharmony_ci snd_ctl_elem_value_set_integer(space->ctl_value, idx, lval); 402c72fcc34Sopenharmony_ci } else { 403c72fcc34Sopenharmony_ci snd_ctl_elem_value_set_integer(space->ctl_value, idx, strtol(value, NULL, 0)); 404c72fcc34Sopenharmony_ci } 405c72fcc34Sopenharmony_ci if (all) 406c72fcc34Sopenharmony_ci continue; 407c72fcc34Sopenharmony_ci value = pos ? pos + 1 : value + strlen(value) - 1; 408c72fcc34Sopenharmony_ci } 409c72fcc34Sopenharmony_ci break; 410c72fcc34Sopenharmony_ci case SND_CTL_ELEM_TYPE_INTEGER64: 411c72fcc34Sopenharmony_ci for (idx = 0; idx < count; idx++) { 412c72fcc34Sopenharmony_ci while (*value == ' ') 413c72fcc34Sopenharmony_ci value++; 414c72fcc34Sopenharmony_ci snd_ctl_elem_value_set_integer64(space->ctl_value, idx, strtoll(value, NULL, 0)); 415c72fcc34Sopenharmony_ci if (all) 416c72fcc34Sopenharmony_ci continue; 417c72fcc34Sopenharmony_ci pos = strchr(value, ','); 418c72fcc34Sopenharmony_ci value = pos ? pos + 1 : value + strlen(value) - 1; 419c72fcc34Sopenharmony_ci } 420c72fcc34Sopenharmony_ci break; 421c72fcc34Sopenharmony_ci case SND_CTL_ELEM_TYPE_ENUMERATED: 422c72fcc34Sopenharmony_ci for (idx = 0; idx < count; idx++) { 423c72fcc34Sopenharmony_ci while (*value == ' ') 424c72fcc34Sopenharmony_ci value++; 425c72fcc34Sopenharmony_ci pos = strchr(value, ','); 426c72fcc34Sopenharmony_ci if (isdigit(value[0]) || value[0] == '-') { 427c72fcc34Sopenharmony_ci snd_ctl_elem_value_set_enumerated(space->ctl_value, idx, strtol(value, NULL, 0)); 428c72fcc34Sopenharmony_ci } else { 429c72fcc34Sopenharmony_ci if (pos) 430c72fcc34Sopenharmony_ci *(char *)pos = '\0'; 431c72fcc34Sopenharmony_ci remove_trailing_chars((char *)value, ' '); 432c72fcc34Sopenharmony_ci items = snd_ctl_elem_info_get_items(space->ctl_info); 433c72fcc34Sopenharmony_ci for (idx2 = 0; idx2 < items; idx2++) { 434c72fcc34Sopenharmony_ci snd_ctl_elem_info_set_item(space->ctl_info, idx2); 435c72fcc34Sopenharmony_ci elem = snd_hctl_find_elem(space->ctl_handle, space->ctl_id); 436c72fcc34Sopenharmony_ci if (elem == NULL) 437c72fcc34Sopenharmony_ci return -ENOENT; 438c72fcc34Sopenharmony_ci val = snd_hctl_elem_info(elem, space->ctl_info); 439c72fcc34Sopenharmony_ci if (val < 0) 440c72fcc34Sopenharmony_ci return val; 441c72fcc34Sopenharmony_ci if (strcasecmp(snd_ctl_elem_info_get_item_name(space->ctl_info), value) == 0) { 442c72fcc34Sopenharmony_ci snd_ctl_elem_value_set_enumerated(space->ctl_value, idx, idx2); 443c72fcc34Sopenharmony_ci break; 444c72fcc34Sopenharmony_ci } 445c72fcc34Sopenharmony_ci } 446c72fcc34Sopenharmony_ci if (idx2 >= items) { 447c72fcc34Sopenharmony_ci Perror(space, "wrong enum identifier '%s'", value); 448c72fcc34Sopenharmony_ci return -EINVAL; 449c72fcc34Sopenharmony_ci } 450c72fcc34Sopenharmony_ci } 451c72fcc34Sopenharmony_ci if (all) 452c72fcc34Sopenharmony_ci continue; 453c72fcc34Sopenharmony_ci value = pos ? pos + 1 : value + strlen(value) - 1; 454c72fcc34Sopenharmony_ci } 455c72fcc34Sopenharmony_ci break; 456c72fcc34Sopenharmony_ci case SND_CTL_ELEM_TYPE_BYTES: 457c72fcc34Sopenharmony_ci case SND_CTL_ELEM_TYPE_IEC958: 458c72fcc34Sopenharmony_ci if (type == SND_CTL_ELEM_TYPE_IEC958) 459c72fcc34Sopenharmony_ci count = sizeof(snd_aes_iec958_t); 460c72fcc34Sopenharmony_ci while (*value == ' ') 461c72fcc34Sopenharmony_ci value++; 462c72fcc34Sopenharmony_ci if (strlen(value) != count * 2) { 463c72fcc34Sopenharmony_ci Perror(space, "bad ctl value hexa length (should be %u bytes)", count); 464c72fcc34Sopenharmony_ci return -EINVAL; 465c72fcc34Sopenharmony_ci } 466c72fcc34Sopenharmony_ci for (idx = 0; idx < count; idx += 2) { 467c72fcc34Sopenharmony_ci int nibble1 = hextodigit(*(value++)); 468c72fcc34Sopenharmony_ci int nibble2 = hextodigit(*(value++)); 469c72fcc34Sopenharmony_ci if (nibble1 < 0 || nibble2 < 0) { 470c72fcc34Sopenharmony_ci Perror(space, "bad ctl hexa value"); 471c72fcc34Sopenharmony_ci return -EINVAL; 472c72fcc34Sopenharmony_ci } 473c72fcc34Sopenharmony_ci val = (nibble1 << 4) | nibble2; 474c72fcc34Sopenharmony_ci snd_ctl_elem_value_set_byte(space->ctl_value, idx, val); 475c72fcc34Sopenharmony_ci } 476c72fcc34Sopenharmony_ci break; 477c72fcc34Sopenharmony_ci default: 478c72fcc34Sopenharmony_ci Perror(space, "unknown element type '%i'", type); 479c72fcc34Sopenharmony_ci return -EINVAL; 480c72fcc34Sopenharmony_ci } 481c72fcc34Sopenharmony_ci return 0; 482c72fcc34Sopenharmony_ci missing: 483c72fcc34Sopenharmony_ci Perror(space, "missing some ctl values (line %i)", space->linenum); 484c72fcc34Sopenharmony_ci return -EINVAL; 485c72fcc34Sopenharmony_ci} 486c72fcc34Sopenharmony_ci 487c72fcc34Sopenharmony_cistatic int do_match(const char *key, enum key_op op, 488c72fcc34Sopenharmony_ci const char *key_value, const char *value) 489c72fcc34Sopenharmony_ci{ 490c72fcc34Sopenharmony_ci int match; 491c72fcc34Sopenharmony_ci 492c72fcc34Sopenharmony_ci if (value == NULL) 493c72fcc34Sopenharmony_ci return 0; 494c72fcc34Sopenharmony_ci dbg("match %s '%s' <-> '%s'", key, key_value, value); 495c72fcc34Sopenharmony_ci match = fnmatch(key_value, value, 0) == 0; 496c72fcc34Sopenharmony_ci if (match && op == KEY_OP_MATCH) { 497c72fcc34Sopenharmony_ci dbg("%s is true (matching value)", key); 498c72fcc34Sopenharmony_ci return 1; 499c72fcc34Sopenharmony_ci } 500c72fcc34Sopenharmony_ci if (!match && op == KEY_OP_NOMATCH) { 501c72fcc34Sopenharmony_ci dbg("%s is true (non-matching value)", key); 502c72fcc34Sopenharmony_ci return 1; 503c72fcc34Sopenharmony_ci } 504c72fcc34Sopenharmony_ci dbg("%s is false", key); 505c72fcc34Sopenharmony_ci return 0; 506c72fcc34Sopenharmony_ci} 507c72fcc34Sopenharmony_ci 508c72fcc34Sopenharmony_cistatic int ctl_match(snd_ctl_elem_id_t *pattern, snd_ctl_elem_id_t *id) 509c72fcc34Sopenharmony_ci{ 510c72fcc34Sopenharmony_ci if ((int)snd_ctl_elem_id_get_interface(pattern) != -1 && 511c72fcc34Sopenharmony_ci snd_ctl_elem_id_get_interface(pattern) != snd_ctl_elem_id_get_interface(id)) 512c72fcc34Sopenharmony_ci return 0; 513c72fcc34Sopenharmony_ci if ((int)snd_ctl_elem_id_get_device(pattern) != -1 && 514c72fcc34Sopenharmony_ci snd_ctl_elem_id_get_device(pattern) != snd_ctl_elem_id_get_device(id)) 515c72fcc34Sopenharmony_ci return 0; 516c72fcc34Sopenharmony_ci if ((int)snd_ctl_elem_id_get_subdevice(pattern) != -1 && 517c72fcc34Sopenharmony_ci snd_ctl_elem_id_get_subdevice(pattern) != snd_ctl_elem_id_get_subdevice(id)) 518c72fcc34Sopenharmony_ci return 0; 519c72fcc34Sopenharmony_ci if ((int)snd_ctl_elem_id_get_index(pattern) != -1 && 520c72fcc34Sopenharmony_ci snd_ctl_elem_id_get_index(pattern) != snd_ctl_elem_id_get_index(id)) 521c72fcc34Sopenharmony_ci return 0; 522c72fcc34Sopenharmony_ci if (fnmatch(snd_ctl_elem_id_get_name(pattern), snd_ctl_elem_id_get_name(id), 0) != 0) 523c72fcc34Sopenharmony_ci return 0; 524c72fcc34Sopenharmony_ci return 1; 525c72fcc34Sopenharmony_ci} 526c72fcc34Sopenharmony_ci 527c72fcc34Sopenharmony_cistatic const char *elemid_get(struct space *space, const char *attr) 528c72fcc34Sopenharmony_ci{ 529c72fcc34Sopenharmony_ci long long val; 530c72fcc34Sopenharmony_ci snd_ctl_elem_type_t type; 531c72fcc34Sopenharmony_ci static char res[256]; 532c72fcc34Sopenharmony_ci 533c72fcc34Sopenharmony_ci if (strncasecmp(attr, "numid", 5) == 0) { 534c72fcc34Sopenharmony_ci val = snd_ctl_elem_id_get_numid(space->ctl_id); 535c72fcc34Sopenharmony_ci goto value; 536c72fcc34Sopenharmony_ci } 537c72fcc34Sopenharmony_ci if (strncasecmp(attr, "iface", 5) == 0 || 538c72fcc34Sopenharmony_ci strncasecmp(attr, "interface", 9) == 0) 539c72fcc34Sopenharmony_ci return snd_ctl_elem_iface_name(snd_ctl_elem_id_get_interface(space->ctl_id)); 540c72fcc34Sopenharmony_ci if (strncasecmp(attr, "device", 6) == 0) { 541c72fcc34Sopenharmony_ci val = snd_ctl_elem_id_get_device(space->ctl_id); 542c72fcc34Sopenharmony_ci goto value; 543c72fcc34Sopenharmony_ci } 544c72fcc34Sopenharmony_ci if (strncasecmp(attr, "subdev", 6) == 0) { 545c72fcc34Sopenharmony_ci val = snd_ctl_elem_id_get_subdevice(space->ctl_id); 546c72fcc34Sopenharmony_ci goto value; 547c72fcc34Sopenharmony_ci } 548c72fcc34Sopenharmony_ci if (strncasecmp(attr, "name", 4) == 0) 549c72fcc34Sopenharmony_ci return snd_ctl_elem_id_get_name(space->ctl_id); 550c72fcc34Sopenharmony_ci if (strncasecmp(attr, "index", 5) == 0) { 551c72fcc34Sopenharmony_ci val = snd_ctl_elem_id_get_index(space->ctl_id); 552c72fcc34Sopenharmony_ci goto value; 553c72fcc34Sopenharmony_ci } 554c72fcc34Sopenharmony_ci if (strncasecmp(attr, "type", 4) == 0) { 555c72fcc34Sopenharmony_ci if (check_id_changed(space, 1)) 556c72fcc34Sopenharmony_ci return NULL; 557c72fcc34Sopenharmony_ci return snd_ctl_elem_type_name(snd_ctl_elem_info_get_type(space->ctl_info)); 558c72fcc34Sopenharmony_ci } 559c72fcc34Sopenharmony_ci if (strncasecmp(attr, "attr", 4) == 0) { 560c72fcc34Sopenharmony_ci if (check_id_changed(space, 1)) 561c72fcc34Sopenharmony_ci return NULL; 562c72fcc34Sopenharmony_ci res[0] = '\0'; 563c72fcc34Sopenharmony_ci if (snd_ctl_elem_info_is_readable(space->ctl_info)) 564c72fcc34Sopenharmony_ci strcat(res, "r"); 565c72fcc34Sopenharmony_ci if (snd_ctl_elem_info_is_writable(space->ctl_info)) 566c72fcc34Sopenharmony_ci strcat(res, "w"); 567c72fcc34Sopenharmony_ci if (snd_ctl_elem_info_is_volatile(space->ctl_info)) 568c72fcc34Sopenharmony_ci strcat(res, "v"); 569c72fcc34Sopenharmony_ci if (snd_ctl_elem_info_is_inactive(space->ctl_info)) 570c72fcc34Sopenharmony_ci strcat(res, "i"); 571c72fcc34Sopenharmony_ci if (snd_ctl_elem_info_is_locked(space->ctl_info)) 572c72fcc34Sopenharmony_ci strcat(res, "l"); 573c72fcc34Sopenharmony_ci if (snd_ctl_elem_info_is_tlv_readable(space->ctl_info)) 574c72fcc34Sopenharmony_ci strcat(res, "R"); 575c72fcc34Sopenharmony_ci if (snd_ctl_elem_info_is_tlv_writable(space->ctl_info)) 576c72fcc34Sopenharmony_ci strcat(res, "W"); 577c72fcc34Sopenharmony_ci if (snd_ctl_elem_info_is_tlv_commandable(space->ctl_info)) 578c72fcc34Sopenharmony_ci strcat(res, "C"); 579c72fcc34Sopenharmony_ci if (snd_ctl_elem_info_is_owner(space->ctl_info)) 580c72fcc34Sopenharmony_ci strcat(res, "o"); 581c72fcc34Sopenharmony_ci if (snd_ctl_elem_info_is_user(space->ctl_info)) 582c72fcc34Sopenharmony_ci strcat(res, "u"); 583c72fcc34Sopenharmony_ci return res; 584c72fcc34Sopenharmony_ci } 585c72fcc34Sopenharmony_ci if (strncasecmp(attr, "owner", 5) == 0) { 586c72fcc34Sopenharmony_ci if (check_id_changed(space, 1)) 587c72fcc34Sopenharmony_ci return NULL; 588c72fcc34Sopenharmony_ci val = snd_ctl_elem_info_get_owner(space->ctl_info); 589c72fcc34Sopenharmony_ci goto value; 590c72fcc34Sopenharmony_ci } 591c72fcc34Sopenharmony_ci if (strncasecmp(attr, "count", 5) == 0) { 592c72fcc34Sopenharmony_ci if (check_id_changed(space, 1)) 593c72fcc34Sopenharmony_ci return NULL; 594c72fcc34Sopenharmony_ci val = snd_ctl_elem_info_get_count(space->ctl_info); 595c72fcc34Sopenharmony_ci goto value; 596c72fcc34Sopenharmony_ci } 597c72fcc34Sopenharmony_ci if (strncasecmp(attr, "min", 3) == 0) { 598c72fcc34Sopenharmony_ci if (check_id_changed(space, 1)) 599c72fcc34Sopenharmony_ci return NULL; 600c72fcc34Sopenharmony_ci type = snd_ctl_elem_info_get_type(space->ctl_info); 601c72fcc34Sopenharmony_ci if (type == SND_CTL_ELEM_TYPE_INTEGER64) 602c72fcc34Sopenharmony_ci val = snd_ctl_elem_info_get_min64(space->ctl_info); 603c72fcc34Sopenharmony_ci else if (type == SND_CTL_ELEM_TYPE_INTEGER) 604c72fcc34Sopenharmony_ci val = snd_ctl_elem_info_get_min(space->ctl_info); 605c72fcc34Sopenharmony_ci else 606c72fcc34Sopenharmony_ci goto empty; 607c72fcc34Sopenharmony_ci goto value; 608c72fcc34Sopenharmony_ci } 609c72fcc34Sopenharmony_ci if (strncasecmp(attr, "max", 3) == 0) { 610c72fcc34Sopenharmony_ci if (check_id_changed(space, 1)) 611c72fcc34Sopenharmony_ci return NULL; 612c72fcc34Sopenharmony_ci type = snd_ctl_elem_info_get_type(space->ctl_info); 613c72fcc34Sopenharmony_ci if (type == SND_CTL_ELEM_TYPE_INTEGER64) 614c72fcc34Sopenharmony_ci val = snd_ctl_elem_info_get_max64(space->ctl_info); 615c72fcc34Sopenharmony_ci else if (type == SND_CTL_ELEM_TYPE_INTEGER) 616c72fcc34Sopenharmony_ci val = snd_ctl_elem_info_get_max(space->ctl_info); 617c72fcc34Sopenharmony_ci else 618c72fcc34Sopenharmony_ci goto empty; 619c72fcc34Sopenharmony_ci goto value; 620c72fcc34Sopenharmony_ci } 621c72fcc34Sopenharmony_ci if (strncasecmp(attr, "step", 3) == 0) { 622c72fcc34Sopenharmony_ci if (check_id_changed(space, 1)) 623c72fcc34Sopenharmony_ci return NULL; 624c72fcc34Sopenharmony_ci type = snd_ctl_elem_info_get_type(space->ctl_info); 625c72fcc34Sopenharmony_ci if (type == SND_CTL_ELEM_TYPE_INTEGER64) 626c72fcc34Sopenharmony_ci val = snd_ctl_elem_info_get_step64(space->ctl_info); 627c72fcc34Sopenharmony_ci else if (type == SND_CTL_ELEM_TYPE_INTEGER) 628c72fcc34Sopenharmony_ci val = snd_ctl_elem_info_get_step(space->ctl_info); 629c72fcc34Sopenharmony_ci else 630c72fcc34Sopenharmony_ci goto empty; 631c72fcc34Sopenharmony_ci goto value; 632c72fcc34Sopenharmony_ci } 633c72fcc34Sopenharmony_ci if (strncasecmp(attr, "items", 5) == 0) { 634c72fcc34Sopenharmony_ci if (check_id_changed(space, 1)) 635c72fcc34Sopenharmony_ci return NULL; 636c72fcc34Sopenharmony_ci if (snd_ctl_elem_info_get_type(space->ctl_info) == SND_CTL_ELEM_TYPE_ENUMERATED) 637c72fcc34Sopenharmony_ci val = snd_ctl_elem_info_get_items(space->ctl_info); 638c72fcc34Sopenharmony_ci else { 639c72fcc34Sopenharmony_ci empty: 640c72fcc34Sopenharmony_ci res[0] = '\0'; 641c72fcc34Sopenharmony_ci return res; 642c72fcc34Sopenharmony_ci } 643c72fcc34Sopenharmony_ci goto value; 644c72fcc34Sopenharmony_ci } 645c72fcc34Sopenharmony_ci if (strncasecmp(attr, "value", 5) == 0) { 646c72fcc34Sopenharmony_ci if (check_id_changed(space, 3)) 647c72fcc34Sopenharmony_ci return NULL; 648c72fcc34Sopenharmony_ci return get_ctl_value(space); 649c72fcc34Sopenharmony_ci } 650c72fcc34Sopenharmony_ci if (strncasecmp(attr, "dBmin", 5) == 0) { 651c72fcc34Sopenharmony_ci long min, max; 652c72fcc34Sopenharmony_ci if (check_id_changed(space, 1)) 653c72fcc34Sopenharmony_ci return NULL; 654c72fcc34Sopenharmony_ci if (snd_ctl_get_dB_range(snd_hctl_ctl(space->ctl_handle), space->ctl_id, &min, &max) < 0) 655c72fcc34Sopenharmony_ci goto empty; 656c72fcc34Sopenharmony_ci val = min; 657c72fcc34Sopenharmony_cidbvalue: 658c72fcc34Sopenharmony_ci sprintf(res, "%li.%02lidB", (long)(val / 100), labs(val % 100)); 659c72fcc34Sopenharmony_ci return res; 660c72fcc34Sopenharmony_ci } 661c72fcc34Sopenharmony_ci if (strncasecmp(attr, "dBmax", 5) == 0) { 662c72fcc34Sopenharmony_ci long min, max; 663c72fcc34Sopenharmony_ci if (check_id_changed(space, 1)) 664c72fcc34Sopenharmony_ci return NULL; 665c72fcc34Sopenharmony_ci if (snd_ctl_get_dB_range(snd_hctl_ctl(space->ctl_handle), space->ctl_id, &min, &max) < 0) 666c72fcc34Sopenharmony_ci goto empty; 667c72fcc34Sopenharmony_ci val = max; 668c72fcc34Sopenharmony_ci goto dbvalue; 669c72fcc34Sopenharmony_ci } 670c72fcc34Sopenharmony_ci if (strncasecmp(attr, "enums", 5) == 0) { 671c72fcc34Sopenharmony_ci unsigned int idx, items; 672c72fcc34Sopenharmony_ci snd_hctl_elem_t *elem; 673c72fcc34Sopenharmony_ci if (check_id_changed(space, 1)) 674c72fcc34Sopenharmony_ci return NULL; 675c72fcc34Sopenharmony_ci if (snd_ctl_elem_info_get_type(space->ctl_info) != SND_CTL_ELEM_TYPE_ENUMERATED) 676c72fcc34Sopenharmony_ci goto empty; 677c72fcc34Sopenharmony_ci items = snd_ctl_elem_info_get_items(space->ctl_info); 678c72fcc34Sopenharmony_ci strcpy(res, "|"); 679c72fcc34Sopenharmony_ci for (idx = 0; idx < items; idx++) { 680c72fcc34Sopenharmony_ci snd_ctl_elem_info_set_item(space->ctl_info, idx); 681c72fcc34Sopenharmony_ci elem = snd_hctl_find_elem(space->ctl_handle, space->ctl_id); 682c72fcc34Sopenharmony_ci if (elem == NULL) 683c72fcc34Sopenharmony_ci break; 684c72fcc34Sopenharmony_ci if (snd_hctl_elem_info(elem, space->ctl_info) < 0) 685c72fcc34Sopenharmony_ci break; 686c72fcc34Sopenharmony_ci strlcat(res, snd_ctl_elem_info_get_item_name(space->ctl_info), sizeof(res)); 687c72fcc34Sopenharmony_ci strlcat(res, "|", sizeof(res)); 688c72fcc34Sopenharmony_ci } 689c72fcc34Sopenharmony_ci return res; 690c72fcc34Sopenharmony_ci } 691c72fcc34Sopenharmony_ci if (strncasecmp(attr, "do_search", 9) == 0) { 692c72fcc34Sopenharmony_ci int err, index = 0; 693c72fcc34Sopenharmony_ci snd_hctl_elem_t *elem; 694c72fcc34Sopenharmony_ci snd_ctl_elem_id_t *id; 695c72fcc34Sopenharmony_ci char *pos = strchr(attr, ' '); 696c72fcc34Sopenharmony_ci if (pos) 697c72fcc34Sopenharmony_ci index = strtol(pos, NULL, 0); 698c72fcc34Sopenharmony_ci err = snd_ctl_elem_id_malloc(&id); 699c72fcc34Sopenharmony_ci if (err < 0) 700c72fcc34Sopenharmony_ci return NULL; 701c72fcc34Sopenharmony_ci elem = snd_hctl_first_elem(space->ctl_handle); 702c72fcc34Sopenharmony_ci while (elem) { 703c72fcc34Sopenharmony_ci snd_hctl_elem_get_id(elem, id); 704c72fcc34Sopenharmony_ci if (!ctl_match(space->ctl_id, id)) 705c72fcc34Sopenharmony_ci goto next_search; 706c72fcc34Sopenharmony_ci if (index > 0) { 707c72fcc34Sopenharmony_ci index--; 708c72fcc34Sopenharmony_ci goto next_search; 709c72fcc34Sopenharmony_ci } 710c72fcc34Sopenharmony_ci strcpy(res, "1"); 711c72fcc34Sopenharmony_ci snd_ctl_elem_id_copy(space->ctl_id, id); 712c72fcc34Sopenharmony_ci snd_ctl_elem_id_free(id); 713c72fcc34Sopenharmony_ci dbg("do_ctl_search found a control"); 714c72fcc34Sopenharmony_ci return res; 715c72fcc34Sopenharmony_ci next_search: 716c72fcc34Sopenharmony_ci elem = snd_hctl_elem_next(elem); 717c72fcc34Sopenharmony_ci } 718c72fcc34Sopenharmony_ci snd_ctl_elem_id_free(id); 719c72fcc34Sopenharmony_ci strcpy(res, "0"); 720c72fcc34Sopenharmony_ci return res; 721c72fcc34Sopenharmony_ci } 722c72fcc34Sopenharmony_ci if (strncasecmp(attr, "do_count", 8) == 0) { 723c72fcc34Sopenharmony_ci int err, index = 0; 724c72fcc34Sopenharmony_ci snd_hctl_elem_t *elem; 725c72fcc34Sopenharmony_ci snd_ctl_elem_id_t *id; 726c72fcc34Sopenharmony_ci err = snd_ctl_elem_id_malloc(&id); 727c72fcc34Sopenharmony_ci if (err < 0) 728c72fcc34Sopenharmony_ci return NULL; 729c72fcc34Sopenharmony_ci elem = snd_hctl_first_elem(space->ctl_handle); 730c72fcc34Sopenharmony_ci while (elem) { 731c72fcc34Sopenharmony_ci snd_hctl_elem_get_id(elem, id); 732c72fcc34Sopenharmony_ci if (ctl_match(space->ctl_id, id)) 733c72fcc34Sopenharmony_ci index++; 734c72fcc34Sopenharmony_ci elem = snd_hctl_elem_next(elem); 735c72fcc34Sopenharmony_ci } 736c72fcc34Sopenharmony_ci snd_ctl_elem_id_free(id); 737c72fcc34Sopenharmony_ci sprintf(res, "%d", index); 738c72fcc34Sopenharmony_ci dbg("do_ctl_count found %s controls", res); 739c72fcc34Sopenharmony_ci return res; 740c72fcc34Sopenharmony_ci } 741c72fcc34Sopenharmony_ci Perror(space, "unknown ctl{} attribute '%s'", attr); 742c72fcc34Sopenharmony_ci return NULL; 743c72fcc34Sopenharmony_ci value: 744c72fcc34Sopenharmony_ci sprintf(res, "%lli", val); 745c72fcc34Sopenharmony_ci return res; 746c72fcc34Sopenharmony_ci} 747c72fcc34Sopenharmony_ci 748c72fcc34Sopenharmony_cistatic int elemid_set(struct space *space, const char *attr, const char *value) 749c72fcc34Sopenharmony_ci{ 750c72fcc34Sopenharmony_ci unsigned int val; 751c72fcc34Sopenharmony_ci void (*fcn)(snd_ctl_elem_id_t *, unsigned int); 752c72fcc34Sopenharmony_ci snd_ctl_elem_iface_t iface; 753c72fcc34Sopenharmony_ci int err; 754c72fcc34Sopenharmony_ci 755c72fcc34Sopenharmony_ci if (strncasecmp(attr, "numid", 5) == 0) { 756c72fcc34Sopenharmony_ci fcn = snd_ctl_elem_id_set_numid; 757c72fcc34Sopenharmony_ci goto value; 758c72fcc34Sopenharmony_ci } 759c72fcc34Sopenharmony_ci if (strncasecmp(attr, "iface", 5) == 0 || 760c72fcc34Sopenharmony_ci strncasecmp(attr, "interface", 9) == 0 || 761c72fcc34Sopenharmony_ci strncasecmp(attr, "reset", 5) == 0 || 762c72fcc34Sopenharmony_ci strncasecmp(attr, "search", 6) == 0) { 763c72fcc34Sopenharmony_ci if (strlen(value) == 0 && strncasecmp(attr, "search", 6) == 0) { 764c72fcc34Sopenharmony_ci iface = 0; 765c72fcc34Sopenharmony_ci goto search; 766c72fcc34Sopenharmony_ci } 767c72fcc34Sopenharmony_ci for (iface = 0; iface <= SND_CTL_ELEM_IFACE_LAST; iface++) { 768c72fcc34Sopenharmony_ci if (strcasecmp(value, snd_ctl_elem_iface_name(iface)) == 0) { 769c72fcc34Sopenharmony_ci if (strncasecmp(attr, "reset", 5) == 0) 770c72fcc34Sopenharmony_ci snd_ctl_elem_id_clear(space->ctl_id); 771c72fcc34Sopenharmony_ci if (strncasecmp(attr, "search", 5) == 0) { 772c72fcc34Sopenharmony_ci search: 773c72fcc34Sopenharmony_ci snd_ctl_elem_id_clear(space->ctl_id); 774c72fcc34Sopenharmony_ci /* -1 means all */ 775c72fcc34Sopenharmony_ci snd_ctl_elem_id_set_interface(space->ctl_id, -1); 776c72fcc34Sopenharmony_ci snd_ctl_elem_id_set_device(space->ctl_id, -1); 777c72fcc34Sopenharmony_ci snd_ctl_elem_id_set_subdevice(space->ctl_id, -1); 778c72fcc34Sopenharmony_ci snd_ctl_elem_id_set_name(space->ctl_id, "*"); 779c72fcc34Sopenharmony_ci snd_ctl_elem_id_set_index(space->ctl_id, -1); 780c72fcc34Sopenharmony_ci if (strlen(value) == 0) 781c72fcc34Sopenharmony_ci return 0; 782c72fcc34Sopenharmony_ci } 783c72fcc34Sopenharmony_ci snd_ctl_elem_id_set_interface(space->ctl_id, iface); 784c72fcc34Sopenharmony_ci space->ctl_id_changed = ~0; 785c72fcc34Sopenharmony_ci return 0; 786c72fcc34Sopenharmony_ci } 787c72fcc34Sopenharmony_ci } 788c72fcc34Sopenharmony_ci Perror(space, "unknown control interface name '%s'", value); 789c72fcc34Sopenharmony_ci return -EINVAL; 790c72fcc34Sopenharmony_ci } 791c72fcc34Sopenharmony_ci if (strncasecmp(attr, "device", 6) == 0) { 792c72fcc34Sopenharmony_ci fcn = snd_ctl_elem_id_set_device; 793c72fcc34Sopenharmony_ci goto value; 794c72fcc34Sopenharmony_ci } 795c72fcc34Sopenharmony_ci if (strncasecmp(attr, "subdev", 6) == 0) { 796c72fcc34Sopenharmony_ci fcn = snd_ctl_elem_id_set_subdevice; 797c72fcc34Sopenharmony_ci goto value; 798c72fcc34Sopenharmony_ci } 799c72fcc34Sopenharmony_ci if (strncasecmp(attr, "name", 4) == 0) { 800c72fcc34Sopenharmony_ci snd_ctl_elem_id_set_name(space->ctl_id, value); 801c72fcc34Sopenharmony_ci space->ctl_id_changed = ~0; 802c72fcc34Sopenharmony_ci return 0; 803c72fcc34Sopenharmony_ci } 804c72fcc34Sopenharmony_ci if (strncasecmp(attr, "index", 5) == 0) { 805c72fcc34Sopenharmony_ci fcn = snd_ctl_elem_id_set_index; 806c72fcc34Sopenharmony_ci goto value; 807c72fcc34Sopenharmony_ci } 808c72fcc34Sopenharmony_ci if (strncasecmp(attr, "values", 6) == 0 || 809c72fcc34Sopenharmony_ci strncasecmp(attr, "value", 5) == 0) { 810c72fcc34Sopenharmony_ci err = check_id_changed(space, 1); 811c72fcc34Sopenharmony_ci if (err < 0) { 812c72fcc34Sopenharmony_ci Perror(space, "control element not found"); 813c72fcc34Sopenharmony_ci return err; 814c72fcc34Sopenharmony_ci } 815c72fcc34Sopenharmony_ci err = set_ctl_value(space, value, strncasecmp(attr, "values", 6) == 0); 816c72fcc34Sopenharmony_ci if (err < 0) { 817c72fcc34Sopenharmony_ci space->ctl_id_changed |= 2; 818c72fcc34Sopenharmony_ci } else { 819c72fcc34Sopenharmony_ci space->ctl_id_changed &= ~2; 820c72fcc34Sopenharmony_ci snd_ctl_elem_value_set_id(space->ctl_value, space->ctl_id); 821c72fcc34Sopenharmony_ci err = snd_ctl_elem_write(snd_hctl_ctl(space->ctl_handle), space->ctl_value); 822c72fcc34Sopenharmony_ci if (err < 0) { 823c72fcc34Sopenharmony_ci Perror(space, "value write error: %s", snd_strerror(err)); 824c72fcc34Sopenharmony_ci return err; 825c72fcc34Sopenharmony_ci } 826c72fcc34Sopenharmony_ci } 827c72fcc34Sopenharmony_ci return err; 828c72fcc34Sopenharmony_ci } 829c72fcc34Sopenharmony_ci Perror(space, "unknown CTL{} attribute '%s'", attr); 830c72fcc34Sopenharmony_ci return -EINVAL; 831c72fcc34Sopenharmony_ci value: 832c72fcc34Sopenharmony_ci val = (unsigned int)strtol(value, NULL, 0); 833c72fcc34Sopenharmony_ci fcn(space->ctl_id, val); 834c72fcc34Sopenharmony_ci space->ctl_id_changed = ~0; 835c72fcc34Sopenharmony_ci return 0; 836c72fcc34Sopenharmony_ci} 837c72fcc34Sopenharmony_ci 838c72fcc34Sopenharmony_cistatic int get_key(char **line, char **key, enum key_op *op, char **value) 839c72fcc34Sopenharmony_ci{ 840c72fcc34Sopenharmony_ci char *linepos; 841c72fcc34Sopenharmony_ci char *temp; 842c72fcc34Sopenharmony_ci 843c72fcc34Sopenharmony_ci linepos = *line; 844c72fcc34Sopenharmony_ci if (linepos == NULL && linepos[0] == '\0') 845c72fcc34Sopenharmony_ci return -EINVAL; 846c72fcc34Sopenharmony_ci 847c72fcc34Sopenharmony_ci /* skip whitespace */ 848c72fcc34Sopenharmony_ci while (isspace(linepos[0]) || linepos[0] == ',') 849c72fcc34Sopenharmony_ci linepos++; 850c72fcc34Sopenharmony_ci 851c72fcc34Sopenharmony_ci /* get the key */ 852c72fcc34Sopenharmony_ci if (linepos[0] == '\0') 853c72fcc34Sopenharmony_ci return -EINVAL; 854c72fcc34Sopenharmony_ci *key = linepos; 855c72fcc34Sopenharmony_ci 856c72fcc34Sopenharmony_ci while (1) { 857c72fcc34Sopenharmony_ci linepos++; 858c72fcc34Sopenharmony_ci if (linepos[0] == '\0') 859c72fcc34Sopenharmony_ci return -1; 860c72fcc34Sopenharmony_ci if (isspace(linepos[0])) 861c72fcc34Sopenharmony_ci break; 862c72fcc34Sopenharmony_ci if (linepos[0] == '=') 863c72fcc34Sopenharmony_ci break; 864c72fcc34Sopenharmony_ci if (linepos[0] == '+') 865c72fcc34Sopenharmony_ci break; 866c72fcc34Sopenharmony_ci if (linepos[0] == '!') 867c72fcc34Sopenharmony_ci break; 868c72fcc34Sopenharmony_ci if (linepos[0] == ':') 869c72fcc34Sopenharmony_ci break; 870c72fcc34Sopenharmony_ci } 871c72fcc34Sopenharmony_ci 872c72fcc34Sopenharmony_ci /* remember end of key */ 873c72fcc34Sopenharmony_ci temp = linepos; 874c72fcc34Sopenharmony_ci 875c72fcc34Sopenharmony_ci /* skip whitespace after key */ 876c72fcc34Sopenharmony_ci while (isspace(linepos[0])) 877c72fcc34Sopenharmony_ci linepos++; 878c72fcc34Sopenharmony_ci if (linepos[0] == '\0') 879c72fcc34Sopenharmony_ci return -EINVAL; 880c72fcc34Sopenharmony_ci 881c72fcc34Sopenharmony_ci /* get operation type */ 882c72fcc34Sopenharmony_ci if (linepos[0] == '=' && linepos[1] == '=') { 883c72fcc34Sopenharmony_ci *op = KEY_OP_MATCH; 884c72fcc34Sopenharmony_ci linepos += 2; 885c72fcc34Sopenharmony_ci dbg("operator=match"); 886c72fcc34Sopenharmony_ci } else if (linepos[0] == '!' && linepos[1] == '=') { 887c72fcc34Sopenharmony_ci *op = KEY_OP_NOMATCH; 888c72fcc34Sopenharmony_ci linepos += 2; 889c72fcc34Sopenharmony_ci dbg("operator=nomatch"); 890c72fcc34Sopenharmony_ci } else if (linepos[0] == '+' && linepos[1] == '=') { 891c72fcc34Sopenharmony_ci *op = KEY_OP_ADD; 892c72fcc34Sopenharmony_ci linepos += 2; 893c72fcc34Sopenharmony_ci dbg("operator=add"); 894c72fcc34Sopenharmony_ci } else if (linepos[0] == '=') { 895c72fcc34Sopenharmony_ci *op = KEY_OP_ASSIGN; 896c72fcc34Sopenharmony_ci linepos++; 897c72fcc34Sopenharmony_ci dbg("operator=assign"); 898c72fcc34Sopenharmony_ci } else if (linepos[0] == ':' && linepos[1] == '=') { 899c72fcc34Sopenharmony_ci *op = KEY_OP_ASSIGN_FINAL; 900c72fcc34Sopenharmony_ci linepos += 2; 901c72fcc34Sopenharmony_ci dbg("operator=assign_final"); 902c72fcc34Sopenharmony_ci } else 903c72fcc34Sopenharmony_ci return -EINVAL; 904c72fcc34Sopenharmony_ci 905c72fcc34Sopenharmony_ci /* terminate key */ 906c72fcc34Sopenharmony_ci temp[0] = '\0'; 907c72fcc34Sopenharmony_ci dbg("key='%s'", *key); 908c72fcc34Sopenharmony_ci 909c72fcc34Sopenharmony_ci /* skip whitespace after operator */ 910c72fcc34Sopenharmony_ci while (isspace(linepos[0])) 911c72fcc34Sopenharmony_ci linepos++; 912c72fcc34Sopenharmony_ci if (linepos[0] == '\0') 913c72fcc34Sopenharmony_ci return -EINVAL; 914c72fcc34Sopenharmony_ci 915c72fcc34Sopenharmony_ci /* get the value*/ 916c72fcc34Sopenharmony_ci if (linepos[0] != '"') 917c72fcc34Sopenharmony_ci return -EINVAL; 918c72fcc34Sopenharmony_ci linepos++; 919c72fcc34Sopenharmony_ci *value = linepos; 920c72fcc34Sopenharmony_ci 921c72fcc34Sopenharmony_ci while (1) { 922c72fcc34Sopenharmony_ci temp = strchr(linepos, '"'); 923c72fcc34Sopenharmony_ci if (temp && temp[-1] == '\\') { 924c72fcc34Sopenharmony_ci linepos = temp + 1; 925c72fcc34Sopenharmony_ci continue; 926c72fcc34Sopenharmony_ci } 927c72fcc34Sopenharmony_ci break; 928c72fcc34Sopenharmony_ci } 929c72fcc34Sopenharmony_ci if (!temp) 930c72fcc34Sopenharmony_ci return -EINVAL; 931c72fcc34Sopenharmony_ci temp[0] = '\0'; 932c72fcc34Sopenharmony_ci temp++; 933c72fcc34Sopenharmony_ci dbg("value='%s'", *value); 934c72fcc34Sopenharmony_ci 935c72fcc34Sopenharmony_ci /* move line to next key */ 936c72fcc34Sopenharmony_ci *line = temp; 937c72fcc34Sopenharmony_ci 938c72fcc34Sopenharmony_ci return 0; 939c72fcc34Sopenharmony_ci} 940c72fcc34Sopenharmony_ci 941c72fcc34Sopenharmony_ci/* extract possible KEY{attr} */ 942c72fcc34Sopenharmony_cistatic char *get_key_attribute(struct space *space, char *str, char *res, size_t ressize) 943c72fcc34Sopenharmony_ci{ 944c72fcc34Sopenharmony_ci char *pos; 945c72fcc34Sopenharmony_ci char *attr; 946c72fcc34Sopenharmony_ci 947c72fcc34Sopenharmony_ci attr = strchr(str, '{'); 948c72fcc34Sopenharmony_ci if (attr != NULL) { 949c72fcc34Sopenharmony_ci attr++; 950c72fcc34Sopenharmony_ci pos = strchr(attr, '}'); 951c72fcc34Sopenharmony_ci if (pos == NULL) { 952c72fcc34Sopenharmony_ci Perror(space, "missing closing brace for format"); 953c72fcc34Sopenharmony_ci return NULL; 954c72fcc34Sopenharmony_ci } 955c72fcc34Sopenharmony_ci pos[0] = '\0'; 956c72fcc34Sopenharmony_ci strlcpy(res, attr, ressize); 957c72fcc34Sopenharmony_ci pos[0] = '}'; 958c72fcc34Sopenharmony_ci dbg("attribute='%s'", res); 959c72fcc34Sopenharmony_ci return res; 960c72fcc34Sopenharmony_ci } 961c72fcc34Sopenharmony_ci 962c72fcc34Sopenharmony_ci return NULL; 963c72fcc34Sopenharmony_ci} 964c72fcc34Sopenharmony_ci 965c72fcc34Sopenharmony_ci/* extract possible {attr} and move str behind it */ 966c72fcc34Sopenharmony_cistatic char *get_format_attribute(struct space *space, char **str) 967c72fcc34Sopenharmony_ci{ 968c72fcc34Sopenharmony_ci char *pos; 969c72fcc34Sopenharmony_ci char *attr = NULL; 970c72fcc34Sopenharmony_ci 971c72fcc34Sopenharmony_ci if (*str[0] == '{') { 972c72fcc34Sopenharmony_ci pos = strchr(*str, '}'); 973c72fcc34Sopenharmony_ci if (pos == NULL) { 974c72fcc34Sopenharmony_ci Perror(space, "missing closing brace for format"); 975c72fcc34Sopenharmony_ci return NULL; 976c72fcc34Sopenharmony_ci } 977c72fcc34Sopenharmony_ci pos[0] = '\0'; 978c72fcc34Sopenharmony_ci attr = *str+1; 979c72fcc34Sopenharmony_ci *str = pos+1; 980c72fcc34Sopenharmony_ci dbg("attribute='%s', str='%s'", attr, *str); 981c72fcc34Sopenharmony_ci } 982c72fcc34Sopenharmony_ci return attr; 983c72fcc34Sopenharmony_ci} 984c72fcc34Sopenharmony_ci 985c72fcc34Sopenharmony_ci/* extract possible format length and move str behind it*/ 986c72fcc34Sopenharmony_cistatic int get_format_len(struct space *space, char **str) 987c72fcc34Sopenharmony_ci{ 988c72fcc34Sopenharmony_ci int num; 989c72fcc34Sopenharmony_ci char *tail; 990c72fcc34Sopenharmony_ci 991c72fcc34Sopenharmony_ci if (isdigit(*str[0])) { 992c72fcc34Sopenharmony_ci num = (int) strtoul(*str, &tail, 10); 993c72fcc34Sopenharmony_ci if (num > 0) { 994c72fcc34Sopenharmony_ci *str = tail; 995c72fcc34Sopenharmony_ci dbg("format length=%i", num); 996c72fcc34Sopenharmony_ci return num; 997c72fcc34Sopenharmony_ci } else { 998c72fcc34Sopenharmony_ci Perror(space, "format parsing error '%s'", *str); 999c72fcc34Sopenharmony_ci } 1000c72fcc34Sopenharmony_ci } 1001c72fcc34Sopenharmony_ci return -1; 1002c72fcc34Sopenharmony_ci} 1003c72fcc34Sopenharmony_ci 1004c72fcc34Sopenharmony_cistatic void apply_format(struct space *space, char *string, size_t maxsize) 1005c72fcc34Sopenharmony_ci{ 1006c72fcc34Sopenharmony_ci char temp[PATH_SIZE]; 1007c72fcc34Sopenharmony_ci char temp2[PATH_SIZE]; 1008c72fcc34Sopenharmony_ci char *head, *tail, *pos, *cpos, *attr, *rest; 1009c72fcc34Sopenharmony_ci struct pair *pair; 1010c72fcc34Sopenharmony_ci int len; 1011c72fcc34Sopenharmony_ci int i; 1012c72fcc34Sopenharmony_ci int count; 1013c72fcc34Sopenharmony_ci enum subst_type { 1014c72fcc34Sopenharmony_ci SUBST_UNKNOWN, 1015c72fcc34Sopenharmony_ci SUBST_CARDINFO, 1016c72fcc34Sopenharmony_ci SUBST_CTL, 1017c72fcc34Sopenharmony_ci SUBST_RESULT, 1018c72fcc34Sopenharmony_ci SUBST_ATTR, 1019c72fcc34Sopenharmony_ci SUBST_SYSFSROOT, 1020c72fcc34Sopenharmony_ci SUBST_ENV, 1021c72fcc34Sopenharmony_ci SUBST_CONFIG, 1022c72fcc34Sopenharmony_ci }; 1023c72fcc34Sopenharmony_ci static const struct subst_map { 1024c72fcc34Sopenharmony_ci char *name; 1025c72fcc34Sopenharmony_ci char fmt; 1026c72fcc34Sopenharmony_ci enum subst_type type; 1027c72fcc34Sopenharmony_ci } map[] = { 1028c72fcc34Sopenharmony_ci { .name = "cardinfo", .fmt = 'i', .type = SUBST_CARDINFO }, 1029c72fcc34Sopenharmony_ci { .name = "ctl", .fmt = 'C', .type = SUBST_CTL }, 1030c72fcc34Sopenharmony_ci { .name = "result", .fmt = 'c', .type = SUBST_RESULT }, 1031c72fcc34Sopenharmony_ci { .name = "attr", .fmt = 's', .type = SUBST_ATTR }, 1032c72fcc34Sopenharmony_ci { .name = "sysfsroot", .fmt = 'r', .type = SUBST_SYSFSROOT }, 1033c72fcc34Sopenharmony_ci { .name = "env", .fmt = 'E', .type = SUBST_ENV }, 1034c72fcc34Sopenharmony_ci { .name = "config", .fmt = 'g', .type = SUBST_CONFIG }, 1035c72fcc34Sopenharmony_ci { NULL, '\0', 0 } 1036c72fcc34Sopenharmony_ci }; 1037c72fcc34Sopenharmony_ci enum subst_type type; 1038c72fcc34Sopenharmony_ci const struct subst_map *subst; 1039c72fcc34Sopenharmony_ci 1040c72fcc34Sopenharmony_ci head = string; 1041c72fcc34Sopenharmony_ci while (1) { 1042c72fcc34Sopenharmony_ci len = -1; 1043c72fcc34Sopenharmony_ci while (head[0] != '\0') { 1044c72fcc34Sopenharmony_ci if (head[0] == '$') { 1045c72fcc34Sopenharmony_ci /* substitute named variable */ 1046c72fcc34Sopenharmony_ci if (head[1] == '\0') 1047c72fcc34Sopenharmony_ci break; 1048c72fcc34Sopenharmony_ci if (head[1] == '$') { 1049c72fcc34Sopenharmony_ci strlcpy(temp, head+2, sizeof(temp)); 1050c72fcc34Sopenharmony_ci strlcpy(head+1, temp, maxsize); 1051c72fcc34Sopenharmony_ci head++; 1052c72fcc34Sopenharmony_ci continue; 1053c72fcc34Sopenharmony_ci } 1054c72fcc34Sopenharmony_ci head[0] = '\0'; 1055c72fcc34Sopenharmony_ci for (subst = map; subst->name; subst++) { 1056c72fcc34Sopenharmony_ci if (strncasecmp(&head[1], subst->name, strlen(subst->name)) == 0) { 1057c72fcc34Sopenharmony_ci type = subst->type; 1058c72fcc34Sopenharmony_ci tail = head + strlen(subst->name)+1; 1059c72fcc34Sopenharmony_ci dbg("will substitute format name '%s'", subst->name); 1060c72fcc34Sopenharmony_ci goto found; 1061c72fcc34Sopenharmony_ci } 1062c72fcc34Sopenharmony_ci } 1063c72fcc34Sopenharmony_ci } else if (head[0] == '%') { 1064c72fcc34Sopenharmony_ci /* substitute format char */ 1065c72fcc34Sopenharmony_ci if (head[1] == '\0') 1066c72fcc34Sopenharmony_ci break; 1067c72fcc34Sopenharmony_ci if (head[1] == '%') { 1068c72fcc34Sopenharmony_ci strlcpy(temp, head+2, sizeof(temp)); 1069c72fcc34Sopenharmony_ci strlcpy(head+1, temp, maxsize); 1070c72fcc34Sopenharmony_ci head++; 1071c72fcc34Sopenharmony_ci continue; 1072c72fcc34Sopenharmony_ci } 1073c72fcc34Sopenharmony_ci head[0] = '\0'; 1074c72fcc34Sopenharmony_ci tail = head+1; 1075c72fcc34Sopenharmony_ci len = get_format_len(space, &tail); 1076c72fcc34Sopenharmony_ci for (subst = map; subst->name; subst++) { 1077c72fcc34Sopenharmony_ci if (tail[0] == subst->fmt) { 1078c72fcc34Sopenharmony_ci type = subst->type; 1079c72fcc34Sopenharmony_ci tail++; 1080c72fcc34Sopenharmony_ci dbg("will substitute format char '%c'", subst->fmt); 1081c72fcc34Sopenharmony_ci goto found; 1082c72fcc34Sopenharmony_ci } 1083c72fcc34Sopenharmony_ci } 1084c72fcc34Sopenharmony_ci } 1085c72fcc34Sopenharmony_ci head++; 1086c72fcc34Sopenharmony_ci } 1087c72fcc34Sopenharmony_ci break; 1088c72fcc34Sopenharmony_cifound: 1089c72fcc34Sopenharmony_ci attr = get_format_attribute(space, &tail); 1090c72fcc34Sopenharmony_ci strlcpy(temp, tail, sizeof(temp)); 1091c72fcc34Sopenharmony_ci dbg("format=%i, string='%s', tail='%s'", type ,string, tail); 1092c72fcc34Sopenharmony_ci 1093c72fcc34Sopenharmony_ci switch (type) { 1094c72fcc34Sopenharmony_ci case SUBST_CARDINFO: 1095c72fcc34Sopenharmony_ci if (attr == NULL) 1096c72fcc34Sopenharmony_ci Perror(space, "missing identification parametr for cardinfo"); 1097c72fcc34Sopenharmony_ci else { 1098c72fcc34Sopenharmony_ci const char *value = cardinfo_get(space, attr); 1099c72fcc34Sopenharmony_ci if (value == NULL) 1100c72fcc34Sopenharmony_ci break; 1101c72fcc34Sopenharmony_ci strlcat(string, value, maxsize); 1102c72fcc34Sopenharmony_ci dbg("substitute cardinfo{%s} '%s'", attr, value); 1103c72fcc34Sopenharmony_ci } 1104c72fcc34Sopenharmony_ci break; 1105c72fcc34Sopenharmony_ci case SUBST_CTL: 1106c72fcc34Sopenharmony_ci if (attr == NULL) 1107c72fcc34Sopenharmony_ci Perror(space, "missing identification parametr for ctl"); 1108c72fcc34Sopenharmony_ci else { 1109c72fcc34Sopenharmony_ci const char *value = elemid_get(space, attr); 1110c72fcc34Sopenharmony_ci if (value == NULL) 1111c72fcc34Sopenharmony_ci break; 1112c72fcc34Sopenharmony_ci strlcat(string, value, maxsize); 1113c72fcc34Sopenharmony_ci dbg("substitute ctl{%s} '%s'", attr, value); 1114c72fcc34Sopenharmony_ci } 1115c72fcc34Sopenharmony_ci break; 1116c72fcc34Sopenharmony_ci case SUBST_RESULT: 1117c72fcc34Sopenharmony_ci if (space->program_result == NULL) 1118c72fcc34Sopenharmony_ci break; 1119c72fcc34Sopenharmony_ci /* get part part of the result string */ 1120c72fcc34Sopenharmony_ci i = 0; 1121c72fcc34Sopenharmony_ci if (attr != NULL) 1122c72fcc34Sopenharmony_ci i = strtoul(attr, &rest, 10); 1123c72fcc34Sopenharmony_ci if (i > 0) { 1124c72fcc34Sopenharmony_ci dbg("request part #%d of result string", i); 1125c72fcc34Sopenharmony_ci cpos = space->program_result; 1126c72fcc34Sopenharmony_ci while (--i) { 1127c72fcc34Sopenharmony_ci while (cpos[0] != '\0' && !isspace(cpos[0])) 1128c72fcc34Sopenharmony_ci cpos++; 1129c72fcc34Sopenharmony_ci while (isspace(cpos[0])) 1130c72fcc34Sopenharmony_ci cpos++; 1131c72fcc34Sopenharmony_ci } 1132c72fcc34Sopenharmony_ci if (i > 0) { 1133c72fcc34Sopenharmony_ci Perror(space, "requested part of result string not found"); 1134c72fcc34Sopenharmony_ci break; 1135c72fcc34Sopenharmony_ci } 1136c72fcc34Sopenharmony_ci strlcpy(temp2, cpos, sizeof(temp2)); 1137c72fcc34Sopenharmony_ci /* %{2+}c copies the whole string from the second part on */ 1138c72fcc34Sopenharmony_ci if (rest[0] != '+') { 1139c72fcc34Sopenharmony_ci cpos = strchr(temp2, ' '); 1140c72fcc34Sopenharmony_ci if (cpos) 1141c72fcc34Sopenharmony_ci cpos[0] = '\0'; 1142c72fcc34Sopenharmony_ci } 1143c72fcc34Sopenharmony_ci strlcat(string, temp2, maxsize); 1144c72fcc34Sopenharmony_ci dbg("substitute part of result string '%s'", temp2); 1145c72fcc34Sopenharmony_ci } else { 1146c72fcc34Sopenharmony_ci strlcat(string, space->program_result, maxsize); 1147c72fcc34Sopenharmony_ci dbg("substitute result string '%s'", space->program_result); 1148c72fcc34Sopenharmony_ci } 1149c72fcc34Sopenharmony_ci break; 1150c72fcc34Sopenharmony_ci case SUBST_ATTR: 1151c72fcc34Sopenharmony_ci if (attr == NULL) 1152c72fcc34Sopenharmony_ci Perror(space, "missing file parameter for attr"); 1153c72fcc34Sopenharmony_ci else { 1154c72fcc34Sopenharmony_ci const char *value = NULL; 1155c72fcc34Sopenharmony_ci size_t size; 1156c72fcc34Sopenharmony_ci 1157c72fcc34Sopenharmony_ci pair = value_find(space, "sysfs_device"); 1158c72fcc34Sopenharmony_ci if (pair == NULL) 1159c72fcc34Sopenharmony_ci break; 1160c72fcc34Sopenharmony_ci value = sysfs_attr_get_value(pair->value, attr); 1161c72fcc34Sopenharmony_ci 1162c72fcc34Sopenharmony_ci if (value == NULL) 1163c72fcc34Sopenharmony_ci break; 1164c72fcc34Sopenharmony_ci 1165c72fcc34Sopenharmony_ci /* strip trailing whitespace and replace untrusted characters of sysfs value */ 1166c72fcc34Sopenharmony_ci size = strlcpy(temp2, value, sizeof(temp2)); 1167c72fcc34Sopenharmony_ci if (size >= sizeof(temp2)) 1168c72fcc34Sopenharmony_ci size = sizeof(temp2)-1; 1169c72fcc34Sopenharmony_ci while (size > 0 && isspace(temp2[size-1])) 1170c72fcc34Sopenharmony_ci temp2[--size] = '\0'; 1171c72fcc34Sopenharmony_ci count = replace_untrusted_chars(temp2); 1172c72fcc34Sopenharmony_ci if (count > 0) 1173c72fcc34Sopenharmony_ci Perror(space, "%i untrusted character(s) replaced" , count); 1174c72fcc34Sopenharmony_ci strlcat(string, temp2, maxsize); 1175c72fcc34Sopenharmony_ci dbg("substitute sysfs value '%s'", temp2); 1176c72fcc34Sopenharmony_ci } 1177c72fcc34Sopenharmony_ci break; 1178c72fcc34Sopenharmony_ci case SUBST_SYSFSROOT: 1179c72fcc34Sopenharmony_ci strlcat(string, sysfs_path, maxsize); 1180c72fcc34Sopenharmony_ci dbg("substitute sysfs_path '%s'", sysfs_path); 1181c72fcc34Sopenharmony_ci break; 1182c72fcc34Sopenharmony_ci case SUBST_ENV: 1183c72fcc34Sopenharmony_ci if (attr == NULL) { 1184c72fcc34Sopenharmony_ci dbg("missing attribute"); 1185c72fcc34Sopenharmony_ci break; 1186c72fcc34Sopenharmony_ci } 1187c72fcc34Sopenharmony_ci pos = getenv(attr); 1188c72fcc34Sopenharmony_ci if (pos == NULL) { 1189c72fcc34Sopenharmony_ci dbg("env '%s' not available", attr); 1190c72fcc34Sopenharmony_ci break; 1191c72fcc34Sopenharmony_ci } 1192c72fcc34Sopenharmony_ci dbg("substitute env '%s=%s'", attr, pos); 1193c72fcc34Sopenharmony_ci strlcat(string, pos, maxsize); 1194c72fcc34Sopenharmony_ci break; 1195c72fcc34Sopenharmony_ci case SUBST_CONFIG: 1196c72fcc34Sopenharmony_ci if (attr == NULL) { 1197c72fcc34Sopenharmony_ci dbg("missing attribute"); 1198c72fcc34Sopenharmony_ci break; 1199c72fcc34Sopenharmony_ci } 1200c72fcc34Sopenharmony_ci pair = value_find(space, attr); 1201c72fcc34Sopenharmony_ci if (pair == NULL) 1202c72fcc34Sopenharmony_ci break; 1203c72fcc34Sopenharmony_ci strlcat(string, pair->value, maxsize); 1204c72fcc34Sopenharmony_ci break; 1205c72fcc34Sopenharmony_ci default: 1206c72fcc34Sopenharmony_ci Perror(space, "unknown substitution type=%i", type); 1207c72fcc34Sopenharmony_ci break; 1208c72fcc34Sopenharmony_ci } 1209c72fcc34Sopenharmony_ci /* possibly truncate to format-char specified length */ 1210c72fcc34Sopenharmony_ci if (len != -1) { 1211c72fcc34Sopenharmony_ci head[len] = '\0'; 1212c72fcc34Sopenharmony_ci dbg("truncate to %i chars, subtitution string becomes '%s'", len, head); 1213c72fcc34Sopenharmony_ci } 1214c72fcc34Sopenharmony_ci strlcat(string, temp, maxsize); 1215c72fcc34Sopenharmony_ci } 1216c72fcc34Sopenharmony_ci /* unescape strings */ 1217c72fcc34Sopenharmony_ci head = tail = string; 1218c72fcc34Sopenharmony_ci while (*head != '\0') { 1219c72fcc34Sopenharmony_ci if (*head == '\\') { 1220c72fcc34Sopenharmony_ci head++; 1221c72fcc34Sopenharmony_ci if (*head == '\0') 1222c72fcc34Sopenharmony_ci break; 1223c72fcc34Sopenharmony_ci switch (*head) { 1224c72fcc34Sopenharmony_ci case 'a': *tail++ = '\a'; break; 1225c72fcc34Sopenharmony_ci case 'b': *tail++ = '\b'; break; 1226c72fcc34Sopenharmony_ci case 'n': *tail++ = '\n'; break; 1227c72fcc34Sopenharmony_ci case 'r': *tail++ = '\r'; break; 1228c72fcc34Sopenharmony_ci case 't': *tail++ = '\t'; break; 1229c72fcc34Sopenharmony_ci case 'v': *tail++ = '\v'; break; 1230c72fcc34Sopenharmony_ci case '\\': *tail++ = '\\'; break; 1231c72fcc34Sopenharmony_ci default: *tail++ = *head; break; 1232c72fcc34Sopenharmony_ci } 1233c72fcc34Sopenharmony_ci head++; 1234c72fcc34Sopenharmony_ci continue; 1235c72fcc34Sopenharmony_ci } 1236c72fcc34Sopenharmony_ci if (*head) 1237c72fcc34Sopenharmony_ci *tail++ = *head++; 1238c72fcc34Sopenharmony_ci } 1239c72fcc34Sopenharmony_ci *tail = 0; 1240c72fcc34Sopenharmony_ci} 1241c72fcc34Sopenharmony_ci 1242c72fcc34Sopenharmony_cistatic 1243c72fcc34Sopenharmony_ciint run_program1(struct space *space, 1244c72fcc34Sopenharmony_ci const char *command0, char *result, 1245c72fcc34Sopenharmony_ci size_t ressize, size_t *reslen ATTRIBUTE_UNUSED, 1246c72fcc34Sopenharmony_ci int log ATTRIBUTE_UNUSED) 1247c72fcc34Sopenharmony_ci{ 1248c72fcc34Sopenharmony_ci if (strncmp(command0, "__ctl_search", 12) == 0) { 1249c72fcc34Sopenharmony_ci const char *res = elemid_get(space, "do_search"); 1250c72fcc34Sopenharmony_ci if (res == NULL || strcmp(res, "1") != 0) 1251c72fcc34Sopenharmony_ci return EXIT_FAILURE; 1252c72fcc34Sopenharmony_ci return EXIT_SUCCESS; 1253c72fcc34Sopenharmony_ci } 1254c72fcc34Sopenharmony_ci if (strncmp(command0, "__ctl_count", 11) == 0) { 1255c72fcc34Sopenharmony_ci const char *res = elemid_get(space, "do_count"); 1256c72fcc34Sopenharmony_ci if (res == NULL || strcmp(res, "0") == 0) 1257c72fcc34Sopenharmony_ci return EXIT_FAILURE; 1258c72fcc34Sopenharmony_ci strlcpy(result, res, ressize); 1259c72fcc34Sopenharmony_ci return EXIT_SUCCESS; 1260c72fcc34Sopenharmony_ci } 1261c72fcc34Sopenharmony_ci Perror(space, "unknown buildin command '%s'", command0); 1262c72fcc34Sopenharmony_ci return EXIT_FAILURE; 1263c72fcc34Sopenharmony_ci} 1264c72fcc34Sopenharmony_ci 1265c72fcc34Sopenharmony_cistatic int parse(struct space *space, const char *filename); 1266c72fcc34Sopenharmony_ci 1267c72fcc34Sopenharmony_cistatic char *new_root_dir(const char *filename) 1268c72fcc34Sopenharmony_ci{ 1269c72fcc34Sopenharmony_ci char *res, *tmp; 1270c72fcc34Sopenharmony_ci 1271c72fcc34Sopenharmony_ci res = strdup(filename); 1272c72fcc34Sopenharmony_ci if (res) { 1273c72fcc34Sopenharmony_ci tmp = strrchr(res, '/'); 1274c72fcc34Sopenharmony_ci if (tmp) 1275c72fcc34Sopenharmony_ci *tmp = '\0'; 1276c72fcc34Sopenharmony_ci } 1277c72fcc34Sopenharmony_ci dbg("new_root_dir '%s' '%s'", filename, res); 1278c72fcc34Sopenharmony_ci return res; 1279c72fcc34Sopenharmony_ci} 1280c72fcc34Sopenharmony_ci 1281c72fcc34Sopenharmony_ci/* return non-zero if the file name has the extension ".conf" */ 1282c72fcc34Sopenharmony_cistatic int conf_name_filter(const struct dirent *d) 1283c72fcc34Sopenharmony_ci{ 1284c72fcc34Sopenharmony_ci char *ext = strrchr(d->d_name, '.'); 1285c72fcc34Sopenharmony_ci return ext && !strcmp(ext, ".conf"); 1286c72fcc34Sopenharmony_ci} 1287c72fcc34Sopenharmony_ci 1288c72fcc34Sopenharmony_cistatic int parse_line(struct space *space, char *line, size_t linesize ATTRIBUTE_UNUSED) 1289c72fcc34Sopenharmony_ci{ 1290c72fcc34Sopenharmony_ci char *linepos; 1291c72fcc34Sopenharmony_ci char *key, *value, *attr, *temp; 1292c72fcc34Sopenharmony_ci struct pair *pair; 1293c72fcc34Sopenharmony_ci enum key_op op; 1294c72fcc34Sopenharmony_ci int err = 0, count; 1295c72fcc34Sopenharmony_ci char string[PATH_SIZE]; 1296c72fcc34Sopenharmony_ci char result[PATH_SIZE]; 1297c72fcc34Sopenharmony_ci 1298c72fcc34Sopenharmony_ci linepos = line; 1299c72fcc34Sopenharmony_ci while (*linepos != '\0') { 1300c72fcc34Sopenharmony_ci op = KEY_OP_UNSET; 1301c72fcc34Sopenharmony_ci 1302c72fcc34Sopenharmony_ci err = get_key(&linepos, &key, &op, &value); 1303c72fcc34Sopenharmony_ci if (err < 0) 1304c72fcc34Sopenharmony_ci goto invalid; 1305c72fcc34Sopenharmony_ci 1306c72fcc34Sopenharmony_ci if (strncasecmp(key, "LABEL", 5) == 0) { 1307c72fcc34Sopenharmony_ci if (op != KEY_OP_ASSIGN) { 1308c72fcc34Sopenharmony_ci Perror(space, "invalid LABEL operation"); 1309c72fcc34Sopenharmony_ci goto invalid; 1310c72fcc34Sopenharmony_ci } 1311c72fcc34Sopenharmony_ci if (space->go_to && strcmp(space->go_to, value) == 0) { 1312c72fcc34Sopenharmony_ci free(space->go_to); 1313c72fcc34Sopenharmony_ci space->go_to = NULL; 1314c72fcc34Sopenharmony_ci } 1315c72fcc34Sopenharmony_ci continue; 1316c72fcc34Sopenharmony_ci } 1317c72fcc34Sopenharmony_ci 1318c72fcc34Sopenharmony_ci if (space->go_to) { 1319c72fcc34Sopenharmony_ci dbg("skip (GOTO '%s')", space->go_to); 1320c72fcc34Sopenharmony_ci break; /* not for us */ 1321c72fcc34Sopenharmony_ci } 1322c72fcc34Sopenharmony_ci 1323c72fcc34Sopenharmony_ci if (strncasecmp(key, "CTL{", 4) == 0) { 1324c72fcc34Sopenharmony_ci attr = get_key_attribute(space, key + 3, string, sizeof(string)); 1325c72fcc34Sopenharmony_ci if (attr == NULL) { 1326c72fcc34Sopenharmony_ci Perror(space, "error parsing CTL attribute"); 1327c72fcc34Sopenharmony_ci goto invalid; 1328c72fcc34Sopenharmony_ci } 1329c72fcc34Sopenharmony_ci if (op == KEY_OP_ASSIGN) { 1330c72fcc34Sopenharmony_ci strlcpy(result, value, sizeof(result)); 1331c72fcc34Sopenharmony_ci apply_format(space, result, sizeof(result)); 1332c72fcc34Sopenharmony_ci dbg("ctl assign: '%s' '%s'", value, attr); 1333c72fcc34Sopenharmony_ci err = elemid_set(space, attr, result); 1334c72fcc34Sopenharmony_ci if (space->program_result) { 1335c72fcc34Sopenharmony_ci free(space->program_result); 1336c72fcc34Sopenharmony_ci space->program_result = NULL; 1337c72fcc34Sopenharmony_ci } 1338c72fcc34Sopenharmony_ci snprintf(string, sizeof(string), "%i", err); 1339c72fcc34Sopenharmony_ci space->program_result = strdup(string); 1340c72fcc34Sopenharmony_ci err = 0; 1341c72fcc34Sopenharmony_ci if (space->program_result == NULL) 1342c72fcc34Sopenharmony_ci break; 1343c72fcc34Sopenharmony_ci } else if (op == KEY_OP_MATCH || op == KEY_OP_NOMATCH) { 1344c72fcc34Sopenharmony_ci if (strncmp(attr, "write", 5) == 0) { 1345c72fcc34Sopenharmony_ci strlcpy(result, value, sizeof(result)); 1346c72fcc34Sopenharmony_ci apply_format(space, result, sizeof(result)); 1347c72fcc34Sopenharmony_ci dbg("ctl write: '%s' '%s'", value, attr); 1348c72fcc34Sopenharmony_ci err = elemid_set(space, "values", result); 1349c72fcc34Sopenharmony_ci if (err == 0 && op == KEY_OP_NOMATCH) 1350c72fcc34Sopenharmony_ci break; 1351c72fcc34Sopenharmony_ci if (err != 0 && op == KEY_OP_MATCH) 1352c72fcc34Sopenharmony_ci break; 1353c72fcc34Sopenharmony_ci } else { 1354c72fcc34Sopenharmony_ci temp = (char *)elemid_get(space, attr); 1355c72fcc34Sopenharmony_ci dbg("ctl match: '%s' '%s' '%s'", attr, value, temp); 1356c72fcc34Sopenharmony_ci if (!do_match(key, op, value, temp)) 1357c72fcc34Sopenharmony_ci break; 1358c72fcc34Sopenharmony_ci } 1359c72fcc34Sopenharmony_ci } else { 1360c72fcc34Sopenharmony_ci Perror(space, "invalid CTL{} operation"); 1361c72fcc34Sopenharmony_ci goto invalid; 1362c72fcc34Sopenharmony_ci } 1363c72fcc34Sopenharmony_ci continue; 1364c72fcc34Sopenharmony_ci } 1365c72fcc34Sopenharmony_ci if (strcasecmp(key, "RESULT") == 0) { 1366c72fcc34Sopenharmony_ci if (op == KEY_OP_MATCH || op == KEY_OP_NOMATCH) { 1367c72fcc34Sopenharmony_ci if (!do_match(key, op, value, space->program_result)) 1368c72fcc34Sopenharmony_ci break; 1369c72fcc34Sopenharmony_ci } else if (op == KEY_OP_ASSIGN) { 1370c72fcc34Sopenharmony_ci if (space->program_result) { 1371c72fcc34Sopenharmony_ci free(space->program_result); 1372c72fcc34Sopenharmony_ci space->program_result = NULL; 1373c72fcc34Sopenharmony_ci } 1374c72fcc34Sopenharmony_ci strlcpy(string, value, sizeof(string)); 1375c72fcc34Sopenharmony_ci apply_format(space, string, sizeof(string)); 1376c72fcc34Sopenharmony_ci space->program_result = strdup(string); 1377c72fcc34Sopenharmony_ci if (space->program_result == NULL) 1378c72fcc34Sopenharmony_ci break; 1379c72fcc34Sopenharmony_ci } else { 1380c72fcc34Sopenharmony_ci Perror(space, "invalid RESULT operation"); 1381c72fcc34Sopenharmony_ci goto invalid; 1382c72fcc34Sopenharmony_ci } 1383c72fcc34Sopenharmony_ci continue; 1384c72fcc34Sopenharmony_ci } 1385c72fcc34Sopenharmony_ci if (strcasecmp(key, "PROGRAM") == 0) { 1386c72fcc34Sopenharmony_ci if (op == KEY_OP_UNSET) 1387c72fcc34Sopenharmony_ci continue; 1388c72fcc34Sopenharmony_ci strlcpy(string, value, sizeof(string)); 1389c72fcc34Sopenharmony_ci apply_format(space, string, sizeof(string)); 1390c72fcc34Sopenharmony_ci if (space->program_result) { 1391c72fcc34Sopenharmony_ci free(space->program_result); 1392c72fcc34Sopenharmony_ci space->program_result = NULL; 1393c72fcc34Sopenharmony_ci } 1394c72fcc34Sopenharmony_ci if (run_program(space, string, result, sizeof(result), NULL, space->log_run) != 0) { 1395c72fcc34Sopenharmony_ci dbg("PROGRAM '%s' is false", string); 1396c72fcc34Sopenharmony_ci if (op != KEY_OP_NOMATCH) 1397c72fcc34Sopenharmony_ci break; 1398c72fcc34Sopenharmony_ci } else { 1399c72fcc34Sopenharmony_ci remove_trailing_chars(result, '\n'); 1400c72fcc34Sopenharmony_ci count = replace_untrusted_chars(result); 1401c72fcc34Sopenharmony_ci if (count) 1402c72fcc34Sopenharmony_ci info("%i untrusted character(s) replaced", count); 1403c72fcc34Sopenharmony_ci dbg("PROGRAM '%s' result is '%s'", string, result); 1404c72fcc34Sopenharmony_ci space->program_result = strdup(result); 1405c72fcc34Sopenharmony_ci if (space->program_result == NULL) 1406c72fcc34Sopenharmony_ci break; 1407c72fcc34Sopenharmony_ci dbg("PROGRAM returned successful"); 1408c72fcc34Sopenharmony_ci if (op == KEY_OP_NOMATCH) 1409c72fcc34Sopenharmony_ci break; 1410c72fcc34Sopenharmony_ci } 1411c72fcc34Sopenharmony_ci dbg("PROGRAM key is true"); 1412c72fcc34Sopenharmony_ci continue; 1413c72fcc34Sopenharmony_ci } 1414c72fcc34Sopenharmony_ci if (strncasecmp(key, "CARDINFO{", 9) == 0) { 1415c72fcc34Sopenharmony_ci attr = get_key_attribute(space, key + 8, string, sizeof(string)); 1416c72fcc34Sopenharmony_ci if (attr == NULL) { 1417c72fcc34Sopenharmony_ci Perror(space, "error parsing CARDINFO attribute"); 1418c72fcc34Sopenharmony_ci goto invalid; 1419c72fcc34Sopenharmony_ci } 1420c72fcc34Sopenharmony_ci if (op == KEY_OP_MATCH || op == KEY_OP_NOMATCH) { 1421c72fcc34Sopenharmony_ci dbg("cardinfo: '%s' '%s'", value, attr); 1422c72fcc34Sopenharmony_ci temp = (char *)cardinfo_get(space, attr); 1423c72fcc34Sopenharmony_ci if (!do_match(key, op, value, temp)) 1424c72fcc34Sopenharmony_ci break; 1425c72fcc34Sopenharmony_ci } else { 1426c72fcc34Sopenharmony_ci Perror(space, "invalid CARDINFO{} operation"); 1427c72fcc34Sopenharmony_ci goto invalid; 1428c72fcc34Sopenharmony_ci } 1429c72fcc34Sopenharmony_ci continue; 1430c72fcc34Sopenharmony_ci } 1431c72fcc34Sopenharmony_ci if (strncasecmp(key, "ATTR{", 5) == 0) { 1432c72fcc34Sopenharmony_ci attr = get_key_attribute(space, key + 4, string, sizeof(string)); 1433c72fcc34Sopenharmony_ci if (attr == NULL) { 1434c72fcc34Sopenharmony_ci Perror(space, "error parsing ATTR attribute"); 1435c72fcc34Sopenharmony_ci goto invalid; 1436c72fcc34Sopenharmony_ci } 1437c72fcc34Sopenharmony_ci if (op == KEY_OP_MATCH || op == KEY_OP_NOMATCH) { 1438c72fcc34Sopenharmony_ci pair = value_find(space, "sysfs_device"); 1439c72fcc34Sopenharmony_ci if (pair == NULL) 1440c72fcc34Sopenharmony_ci break; 1441c72fcc34Sopenharmony_ci dbg("sysfs_attr: '%s' '%s'", pair->value, attr); 1442c72fcc34Sopenharmony_ci temp = sysfs_attr_get_value(pair->value, attr); 1443c72fcc34Sopenharmony_ci if (!do_match(key, op, value, temp)) 1444c72fcc34Sopenharmony_ci break; 1445c72fcc34Sopenharmony_ci } else { 1446c72fcc34Sopenharmony_ci Perror(space, "invalid ATTR{} operation"); 1447c72fcc34Sopenharmony_ci goto invalid; 1448c72fcc34Sopenharmony_ci } 1449c72fcc34Sopenharmony_ci continue; 1450c72fcc34Sopenharmony_ci } 1451c72fcc34Sopenharmony_ci if (strncasecmp(key, "ENV{", 4) == 0) { 1452c72fcc34Sopenharmony_ci attr = get_key_attribute(space, key + 3, string, sizeof(string)); 1453c72fcc34Sopenharmony_ci if (attr == NULL) { 1454c72fcc34Sopenharmony_ci Perror(space, "error parsing ENV attribute"); 1455c72fcc34Sopenharmony_ci goto invalid; 1456c72fcc34Sopenharmony_ci } 1457c72fcc34Sopenharmony_ci if (op == KEY_OP_MATCH || op == KEY_OP_NOMATCH) { 1458c72fcc34Sopenharmony_ci temp = getenv(attr); 1459c72fcc34Sopenharmony_ci dbg("env: '%s' '%s'", attr, temp); 1460c72fcc34Sopenharmony_ci if (!do_match(key, op, value, temp)) 1461c72fcc34Sopenharmony_ci break; 1462c72fcc34Sopenharmony_ci } else if (op == KEY_OP_ASSIGN || 1463c72fcc34Sopenharmony_ci op == KEY_OP_ASSIGN_FINAL) { 1464c72fcc34Sopenharmony_ci strlcpy(result, value, sizeof(result)); 1465c72fcc34Sopenharmony_ci apply_format(space, result, sizeof(result)); 1466c72fcc34Sopenharmony_ci dbg("env set: '%s' '%s'", attr, result); 1467c72fcc34Sopenharmony_ci if (setenv(attr, result, op == KEY_OP_ASSIGN_FINAL)) 1468c72fcc34Sopenharmony_ci break; 1469c72fcc34Sopenharmony_ci } else { 1470c72fcc34Sopenharmony_ci Perror(space, "invalid ENV{} operation"); 1471c72fcc34Sopenharmony_ci goto invalid; 1472c72fcc34Sopenharmony_ci } 1473c72fcc34Sopenharmony_ci continue; 1474c72fcc34Sopenharmony_ci } 1475c72fcc34Sopenharmony_ci if (strcasecmp(key, "GOTO") == 0) { 1476c72fcc34Sopenharmony_ci if (op != KEY_OP_ASSIGN) { 1477c72fcc34Sopenharmony_ci Perror(space, "invalid GOTO operation"); 1478c72fcc34Sopenharmony_ci goto invalid; 1479c72fcc34Sopenharmony_ci } 1480c72fcc34Sopenharmony_ci space->go_to = strdup(value); 1481c72fcc34Sopenharmony_ci if (space->go_to == NULL) { 1482c72fcc34Sopenharmony_ci err = -ENOMEM; 1483c72fcc34Sopenharmony_ci break; 1484c72fcc34Sopenharmony_ci } 1485c72fcc34Sopenharmony_ci continue; 1486c72fcc34Sopenharmony_ci } 1487c72fcc34Sopenharmony_ci if (strcasecmp(key, "INCLUDE") == 0) { 1488c72fcc34Sopenharmony_ci char *rootdir, *go_to; 1489c72fcc34Sopenharmony_ci const char *filename; 1490c72fcc34Sopenharmony_ci struct stat st; 1491c72fcc34Sopenharmony_ci int linenum; 1492c72fcc34Sopenharmony_ci if (op != KEY_OP_ASSIGN) { 1493c72fcc34Sopenharmony_ci Perror(space, "invalid INCLUDE operation"); 1494c72fcc34Sopenharmony_ci goto invalid; 1495c72fcc34Sopenharmony_ci } 1496c72fcc34Sopenharmony_ci if (value[0] == '/') 1497c72fcc34Sopenharmony_ci strlcpy(string, value, sizeof(string)); 1498c72fcc34Sopenharmony_ci else { 1499c72fcc34Sopenharmony_ci strlcpy(string, space->rootdir, sizeof(string)); 1500c72fcc34Sopenharmony_ci strlcat(string, "/", sizeof(string)); 1501c72fcc34Sopenharmony_ci strlcat(string, value, sizeof(string)); 1502c72fcc34Sopenharmony_ci } 1503c72fcc34Sopenharmony_ci rootdir = space->rootdir; 1504c72fcc34Sopenharmony_ci go_to = space->go_to; 1505c72fcc34Sopenharmony_ci filename = space->filename; 1506c72fcc34Sopenharmony_ci linenum = space->linenum; 1507c72fcc34Sopenharmony_ci if (stat(string, &st)) { 1508c72fcc34Sopenharmony_ci Perror(space, "invalid filename '%s'", string); 1509c72fcc34Sopenharmony_ci continue; 1510c72fcc34Sopenharmony_ci } 1511c72fcc34Sopenharmony_ci if (S_ISDIR(st.st_mode)) { 1512c72fcc34Sopenharmony_ci struct dirent **list; 1513c72fcc34Sopenharmony_ci int i, num; 1514c72fcc34Sopenharmony_ci num = scandir(string, &list, conf_name_filter, 1515c72fcc34Sopenharmony_ci alphasort); 1516c72fcc34Sopenharmony_ci if (num < 0) { 1517c72fcc34Sopenharmony_ci Perror(space, "invalid directory '%s'", string); 1518c72fcc34Sopenharmony_ci continue; 1519c72fcc34Sopenharmony_ci } 1520c72fcc34Sopenharmony_ci count = strlen(string); 1521c72fcc34Sopenharmony_ci for (i = 0; i < num; i++) { 1522c72fcc34Sopenharmony_ci string[count] = '\0'; 1523c72fcc34Sopenharmony_ci strlcat(string, "/", sizeof(string)); 1524c72fcc34Sopenharmony_ci strlcat(string, list[i]->d_name, sizeof(string)); 1525c72fcc34Sopenharmony_ci space->go_to = NULL; 1526c72fcc34Sopenharmony_ci space->rootdir = new_root_dir(string); 1527c72fcc34Sopenharmony_ci free(list[i]); 1528c72fcc34Sopenharmony_ci if (space->rootdir) { 1529c72fcc34Sopenharmony_ci err = parse(space, string); 1530c72fcc34Sopenharmony_ci free(space->rootdir); 1531c72fcc34Sopenharmony_ci } else 1532c72fcc34Sopenharmony_ci err = -ENOMEM; 1533c72fcc34Sopenharmony_ci if (space->go_to) { 1534c72fcc34Sopenharmony_ci Perror(space, "unterminated GOTO '%s'", space->go_to); 1535c72fcc34Sopenharmony_ci free(space->go_to); 1536c72fcc34Sopenharmony_ci } 1537c72fcc34Sopenharmony_ci if (err) 1538c72fcc34Sopenharmony_ci break; 1539c72fcc34Sopenharmony_ci } 1540c72fcc34Sopenharmony_ci free(list); 1541c72fcc34Sopenharmony_ci } else { 1542c72fcc34Sopenharmony_ci space->go_to = NULL; 1543c72fcc34Sopenharmony_ci space->rootdir = new_root_dir(string); 1544c72fcc34Sopenharmony_ci if (space->rootdir) { 1545c72fcc34Sopenharmony_ci err = parse(space, string); 1546c72fcc34Sopenharmony_ci free(space->rootdir); 1547c72fcc34Sopenharmony_ci } else 1548c72fcc34Sopenharmony_ci err = -ENOMEM; 1549c72fcc34Sopenharmony_ci if (space->go_to) { 1550c72fcc34Sopenharmony_ci Perror(space, "unterminated GOTO '%s'", space->go_to); 1551c72fcc34Sopenharmony_ci free(space->go_to); 1552c72fcc34Sopenharmony_ci } 1553c72fcc34Sopenharmony_ci } 1554c72fcc34Sopenharmony_ci space->go_to = go_to; 1555c72fcc34Sopenharmony_ci space->rootdir = rootdir; 1556c72fcc34Sopenharmony_ci space->filename = filename; 1557c72fcc34Sopenharmony_ci space->linenum = linenum; 1558c72fcc34Sopenharmony_ci if (space->quit) 1559c72fcc34Sopenharmony_ci break; 1560c72fcc34Sopenharmony_ci if (err) 1561c72fcc34Sopenharmony_ci break; 1562c72fcc34Sopenharmony_ci continue; 1563c72fcc34Sopenharmony_ci } 1564c72fcc34Sopenharmony_ci if (strncasecmp(key, "ACCESS", 6) == 0) { 1565c72fcc34Sopenharmony_ci if (op == KEY_OP_MATCH || op == KEY_OP_NOMATCH) { 1566c72fcc34Sopenharmony_ci if (value[0] == '$') { 1567c72fcc34Sopenharmony_ci strlcpy(string, value, sizeof(string)); 1568c72fcc34Sopenharmony_ci apply_format(space, string, sizeof(string)); 1569c72fcc34Sopenharmony_ci if (string[0] == '/') 1570c72fcc34Sopenharmony_ci goto __access1; 1571c72fcc34Sopenharmony_ci } 1572c72fcc34Sopenharmony_ci if (value[0] != '/') { 1573c72fcc34Sopenharmony_ci strlcpy(string, space->rootdir, sizeof(string)); 1574c72fcc34Sopenharmony_ci strlcat(string, "/", sizeof(string)); 1575c72fcc34Sopenharmony_ci strlcat(string, value, sizeof(string)); 1576c72fcc34Sopenharmony_ci } else { 1577c72fcc34Sopenharmony_ci strlcpy(string, value, sizeof(string)); 1578c72fcc34Sopenharmony_ci } 1579c72fcc34Sopenharmony_ci apply_format(space, string, sizeof(string)); 1580c72fcc34Sopenharmony_ci __access1: 1581c72fcc34Sopenharmony_ci count = access(string, F_OK); 1582c72fcc34Sopenharmony_ci dbg("access(%s) = %i (%s)", string, count, value); 1583c72fcc34Sopenharmony_ci if (op == KEY_OP_MATCH && count != 0) 1584c72fcc34Sopenharmony_ci break; 1585c72fcc34Sopenharmony_ci if (op == KEY_OP_NOMATCH && count == 0) 1586c72fcc34Sopenharmony_ci break; 1587c72fcc34Sopenharmony_ci } else { 1588c72fcc34Sopenharmony_ci Perror(space, "invalid ACCESS operation"); 1589c72fcc34Sopenharmony_ci goto invalid; 1590c72fcc34Sopenharmony_ci } 1591c72fcc34Sopenharmony_ci continue; 1592c72fcc34Sopenharmony_ci } 1593c72fcc34Sopenharmony_ci if (strncasecmp(key, "PRINT", 5) == 0) { 1594c72fcc34Sopenharmony_ci if (op != KEY_OP_ASSIGN) { 1595c72fcc34Sopenharmony_ci Perror(space, "invalid PRINT operation"); 1596c72fcc34Sopenharmony_ci goto invalid; 1597c72fcc34Sopenharmony_ci } 1598c72fcc34Sopenharmony_ci strlcpy(string, value, sizeof(string)); 1599c72fcc34Sopenharmony_ci apply_format(space, string, sizeof(string)); 1600c72fcc34Sopenharmony_ci fwrite(string, strlen(string), 1, stdout); 1601c72fcc34Sopenharmony_ci continue; 1602c72fcc34Sopenharmony_ci } 1603c72fcc34Sopenharmony_ci if (strncasecmp(key, "ERROR", 5) == 0) { 1604c72fcc34Sopenharmony_ci if (op != KEY_OP_ASSIGN) { 1605c72fcc34Sopenharmony_ci Perror(space, "invalid ERROR operation"); 1606c72fcc34Sopenharmony_ci goto invalid; 1607c72fcc34Sopenharmony_ci } 1608c72fcc34Sopenharmony_ci strlcpy(string, value, sizeof(string)); 1609c72fcc34Sopenharmony_ci apply_format(space, string, sizeof(string)); 1610c72fcc34Sopenharmony_ci fwrite(string, strlen(string), 1, stderr); 1611c72fcc34Sopenharmony_ci continue; 1612c72fcc34Sopenharmony_ci } 1613c72fcc34Sopenharmony_ci if (strncasecmp(key, "EXIT", 4) == 0) { 1614c72fcc34Sopenharmony_ci if (op != KEY_OP_ASSIGN) { 1615c72fcc34Sopenharmony_ci Perror(space, "invalid EXIT operation"); 1616c72fcc34Sopenharmony_ci goto invalid; 1617c72fcc34Sopenharmony_ci } 1618c72fcc34Sopenharmony_ci strlcpy(string, value, sizeof(string)); 1619c72fcc34Sopenharmony_ci apply_format(space, string, sizeof(string)); 1620c72fcc34Sopenharmony_ci if (strcmp(string, "return") == 0) 1621c72fcc34Sopenharmony_ci return -EJUSTRETURN; 1622c72fcc34Sopenharmony_ci space->exit_code = strtol(string, NULL, 0); 1623c72fcc34Sopenharmony_ci space->quit = 1; 1624c72fcc34Sopenharmony_ci break; 1625c72fcc34Sopenharmony_ci } 1626c72fcc34Sopenharmony_ci if (strncasecmp(key, "CONFIG{", 7) == 0) { 1627c72fcc34Sopenharmony_ci attr = get_key_attribute(space, key + 6, string, sizeof(string)); 1628c72fcc34Sopenharmony_ci if (attr == NULL) { 1629c72fcc34Sopenharmony_ci Perror(space, "error parsing CONFIG attribute"); 1630c72fcc34Sopenharmony_ci goto invalid; 1631c72fcc34Sopenharmony_ci } 1632c72fcc34Sopenharmony_ci strlcpy(result, value, sizeof(result)); 1633c72fcc34Sopenharmony_ci apply_format(space, result, sizeof(result)); 1634c72fcc34Sopenharmony_ci if (op == KEY_OP_ASSIGN) { 1635c72fcc34Sopenharmony_ci err = value_set(space, attr, result); 1636c72fcc34Sopenharmony_ci dbg("CONFIG{%s}='%s'", attr, result); 1637c72fcc34Sopenharmony_ci break; 1638c72fcc34Sopenharmony_ci } else if (op == KEY_OP_MATCH || op == KEY_OP_NOMATCH) { 1639c72fcc34Sopenharmony_ci pair = value_find(space, attr); 1640c72fcc34Sopenharmony_ci if (pair == NULL) 1641c72fcc34Sopenharmony_ci break; 1642c72fcc34Sopenharmony_ci if (!do_match(key, op, result, pair->value)) 1643c72fcc34Sopenharmony_ci break; 1644c72fcc34Sopenharmony_ci } else { 1645c72fcc34Sopenharmony_ci Perror(space, "invalid CONFIG{} operation"); 1646c72fcc34Sopenharmony_ci goto invalid; 1647c72fcc34Sopenharmony_ci } 1648c72fcc34Sopenharmony_ci } 1649c72fcc34Sopenharmony_ci 1650c72fcc34Sopenharmony_ci Perror(space, "unknown key '%s'", key); 1651c72fcc34Sopenharmony_ci } 1652c72fcc34Sopenharmony_ci return err; 1653c72fcc34Sopenharmony_ci 1654c72fcc34Sopenharmony_ciinvalid: 1655c72fcc34Sopenharmony_ci Perror(space, "invalid rule"); 1656c72fcc34Sopenharmony_ci return -EINVAL; 1657c72fcc34Sopenharmony_ci} 1658c72fcc34Sopenharmony_ci 1659c72fcc34Sopenharmony_cistatic int parse(struct space *space, const char *filename) 1660c72fcc34Sopenharmony_ci{ 1661c72fcc34Sopenharmony_ci char *buf, *bufline, *line; 1662c72fcc34Sopenharmony_ci size_t bufsize, pos, count, linesize; 1663c72fcc34Sopenharmony_ci unsigned int linenum, i, j, linenum_adj; 1664c72fcc34Sopenharmony_ci int err; 1665c72fcc34Sopenharmony_ci 1666c72fcc34Sopenharmony_ci dbg("start of file '%s'", filename); 1667c72fcc34Sopenharmony_ci 1668c72fcc34Sopenharmony_ci if (file_map(filename, &buf, &bufsize) != 0) { 1669c72fcc34Sopenharmony_ci err = errno; 1670c72fcc34Sopenharmony_ci error("Unable to open file '%s': %s", filename, strerror(err)); 1671c72fcc34Sopenharmony_ci return -err; 1672c72fcc34Sopenharmony_ci } 1673c72fcc34Sopenharmony_ci 1674c72fcc34Sopenharmony_ci err = 0; 1675c72fcc34Sopenharmony_ci pos = 0; 1676c72fcc34Sopenharmony_ci linenum = 0; 1677c72fcc34Sopenharmony_ci linesize = 128; 1678c72fcc34Sopenharmony_ci line = malloc(linesize); 1679c72fcc34Sopenharmony_ci if (line == NULL) { 1680c72fcc34Sopenharmony_ci file_unmap(buf, bufsize); 1681c72fcc34Sopenharmony_ci return -ENOMEM; 1682c72fcc34Sopenharmony_ci } 1683c72fcc34Sopenharmony_ci space->filename = filename; 1684c72fcc34Sopenharmony_ci while (!err && pos < bufsize && !space->quit) { 1685c72fcc34Sopenharmony_ci count = line_width(buf, bufsize, pos); 1686c72fcc34Sopenharmony_ci bufline = buf + pos; 1687c72fcc34Sopenharmony_ci pos += count + 1; 1688c72fcc34Sopenharmony_ci linenum++; 1689c72fcc34Sopenharmony_ci 1690c72fcc34Sopenharmony_ci /* skip whitespaces */ 1691c72fcc34Sopenharmony_ci while (count > 0 && isspace(bufline[0])) { 1692c72fcc34Sopenharmony_ci bufline++; 1693c72fcc34Sopenharmony_ci count--; 1694c72fcc34Sopenharmony_ci } 1695c72fcc34Sopenharmony_ci if (count == 0) 1696c72fcc34Sopenharmony_ci continue; 1697c72fcc34Sopenharmony_ci 1698c72fcc34Sopenharmony_ci /* comment check */ 1699c72fcc34Sopenharmony_ci if (bufline[0] == '#') 1700c72fcc34Sopenharmony_ci continue; 1701c72fcc34Sopenharmony_ci 1702c72fcc34Sopenharmony_ci if (count > linesize - 1) { 1703c72fcc34Sopenharmony_ci free(line); 1704c72fcc34Sopenharmony_ci line = NULL; 1705c72fcc34Sopenharmony_ci linesize = (count + 127 + 1) & ~127; 1706c72fcc34Sopenharmony_ci if (linesize > 2048) { 1707c72fcc34Sopenharmony_ci error("file %s, line %i too long", filename, linenum); 1708c72fcc34Sopenharmony_ci err = -EINVAL; 1709c72fcc34Sopenharmony_ci break; 1710c72fcc34Sopenharmony_ci } 1711c72fcc34Sopenharmony_ci line = malloc(linesize); 1712c72fcc34Sopenharmony_ci if (line == NULL) { 1713c72fcc34Sopenharmony_ci err = -EINVAL; 1714c72fcc34Sopenharmony_ci break; 1715c72fcc34Sopenharmony_ci } 1716c72fcc34Sopenharmony_ci } 1717c72fcc34Sopenharmony_ci 1718c72fcc34Sopenharmony_ci /* skip backslash and newline from multiline rules */ 1719c72fcc34Sopenharmony_ci linenum_adj = 0; 1720c72fcc34Sopenharmony_ci for (i = j = 0; i < count; i++) { 1721c72fcc34Sopenharmony_ci if (bufline[i] == '\\' && bufline[i+1] == '\n') { 1722c72fcc34Sopenharmony_ci linenum_adj++; 1723c72fcc34Sopenharmony_ci continue; 1724c72fcc34Sopenharmony_ci } 1725c72fcc34Sopenharmony_ci line[j++] = bufline[i]; 1726c72fcc34Sopenharmony_ci } 1727c72fcc34Sopenharmony_ci line[j] = '\0'; 1728c72fcc34Sopenharmony_ci 1729c72fcc34Sopenharmony_ci dbg("read (%i) '%s'", linenum, line); 1730c72fcc34Sopenharmony_ci space->linenum = linenum; 1731c72fcc34Sopenharmony_ci err = parse_line(space, line, linesize); 1732c72fcc34Sopenharmony_ci if (err == -EJUSTRETURN) { 1733c72fcc34Sopenharmony_ci err = 0; 1734c72fcc34Sopenharmony_ci break; 1735c72fcc34Sopenharmony_ci } 1736c72fcc34Sopenharmony_ci linenum += linenum_adj; 1737c72fcc34Sopenharmony_ci } 1738c72fcc34Sopenharmony_ci 1739c72fcc34Sopenharmony_ci free(line); 1740c72fcc34Sopenharmony_ci space->filename = NULL; 1741c72fcc34Sopenharmony_ci space->linenum = -1; 1742c72fcc34Sopenharmony_ci file_unmap(buf, bufsize); 1743c72fcc34Sopenharmony_ci dbg("end of file '%s'", filename); 1744c72fcc34Sopenharmony_ci return err ? err : -abs(space->exit_code); 1745c72fcc34Sopenharmony_ci} 1746c72fcc34Sopenharmony_ci 1747c72fcc34Sopenharmony_ciint init(const char *cfgdir, const char *filename, int flags, const char *cardname) 1748c72fcc34Sopenharmony_ci{ 1749c72fcc34Sopenharmony_ci struct space *space; 1750c72fcc34Sopenharmony_ci struct snd_card_iterator iter; 1751c72fcc34Sopenharmony_ci int err = 0, lasterr = 0; 1752c72fcc34Sopenharmony_ci 1753c72fcc34Sopenharmony_ci sysfs_init(); 1754c72fcc34Sopenharmony_ci err = snd_card_iterator_sinit(&iter, cardname); 1755c72fcc34Sopenharmony_ci if (err < 0) 1756c72fcc34Sopenharmony_ci goto out; 1757c72fcc34Sopenharmony_ci while (snd_card_iterator_next(&iter)) { 1758c72fcc34Sopenharmony_ci err = snd_card_clean_cfgdir(cfgdir, iter.card); 1759c72fcc34Sopenharmony_ci if (err < 0) { 1760c72fcc34Sopenharmony_ci if (lasterr == 0) 1761c72fcc34Sopenharmony_ci lasterr = err; 1762c72fcc34Sopenharmony_ci continue; 1763c72fcc34Sopenharmony_ci } 1764c72fcc34Sopenharmony_ci err = init_ucm(flags, iter.card); 1765c72fcc34Sopenharmony_ci if (err == 0) 1766c72fcc34Sopenharmony_ci continue; 1767c72fcc34Sopenharmony_ci err = init_space(&space, iter.card); 1768c72fcc34Sopenharmony_ci if (err != 0) 1769c72fcc34Sopenharmony_ci continue; 1770c72fcc34Sopenharmony_ci space->rootdir = new_root_dir(filename); 1771c72fcc34Sopenharmony_ci if (space->rootdir != NULL) { 1772c72fcc34Sopenharmony_ci err = parse(space, filename); 1773c72fcc34Sopenharmony_ci if (!cardname && err <= -99) { /* non-fatal errors */ 1774c72fcc34Sopenharmony_ci if (lasterr == 0) 1775c72fcc34Sopenharmony_ci lasterr = err; 1776c72fcc34Sopenharmony_ci err = 0; 1777c72fcc34Sopenharmony_ci } 1778c72fcc34Sopenharmony_ci } 1779c72fcc34Sopenharmony_ci free_space(space); 1780c72fcc34Sopenharmony_ci if (err < 0) 1781c72fcc34Sopenharmony_ci goto out; 1782c72fcc34Sopenharmony_ci } 1783c72fcc34Sopenharmony_ci err = lasterr ? lasterr : snd_card_iterator_error(&iter); 1784c72fcc34Sopenharmony_ciout: 1785c72fcc34Sopenharmony_ci sysfs_cleanup(); 1786c72fcc34Sopenharmony_ci return err; 1787c72fcc34Sopenharmony_ci} 1788