1c72fcc34Sopenharmony_ci/* 2c72fcc34Sopenharmony_ci * Advanced Linux Sound Architecture Control Program - Support routines 3c72fcc34Sopenharmony_ci * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 4c72fcc34Sopenharmony_ci * 5c72fcc34Sopenharmony_ci * 6c72fcc34Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 7c72fcc34Sopenharmony_ci * it under the terms of the GNU General Public License as published by 8c72fcc34Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 9c72fcc34Sopenharmony_ci * (at your option) any later version. 10c72fcc34Sopenharmony_ci * 11c72fcc34Sopenharmony_ci * This program is distributed in the hope that it will be useful, 12c72fcc34Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 13c72fcc34Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14c72fcc34Sopenharmony_ci * GNU General Public License for more details. 15c72fcc34Sopenharmony_ci * 16c72fcc34Sopenharmony_ci * You should have received a copy of the GNU General Public License 17c72fcc34Sopenharmony_ci * along with this program; if not, write to the Free Software 18c72fcc34Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19c72fcc34Sopenharmony_ci * 20c72fcc34Sopenharmony_ci */ 21c72fcc34Sopenharmony_ci 22c72fcc34Sopenharmony_ci#include <stdlib.h> 23c72fcc34Sopenharmony_ci#include <stdio.h> 24c72fcc34Sopenharmony_ci#include <stddef.h> 25c72fcc34Sopenharmony_ci#include <unistd.h> 26c72fcc34Sopenharmony_ci#include <fcntl.h> 27c72fcc34Sopenharmony_ci#include <errno.h> 28c72fcc34Sopenharmony_ci#include <ctype.h> 29c72fcc34Sopenharmony_ci#include <dirent.h> 30c72fcc34Sopenharmony_ci#include <syslog.h> 31c72fcc34Sopenharmony_ci#include <sys/stat.h> 32c72fcc34Sopenharmony_ci#include <sys/mman.h> 33c72fcc34Sopenharmony_ci#include <limits.h> 34c72fcc34Sopenharmony_ci#include "alsactl.h" 35c72fcc34Sopenharmony_ci 36c72fcc34Sopenharmony_ciint file_map(const char *filename, char **buf, size_t *bufsize) 37c72fcc34Sopenharmony_ci{ 38c72fcc34Sopenharmony_ci struct stat stats; 39c72fcc34Sopenharmony_ci int fd; 40c72fcc34Sopenharmony_ci 41c72fcc34Sopenharmony_ci fd = open(filename, O_RDONLY); 42c72fcc34Sopenharmony_ci if (fd < 0) { 43c72fcc34Sopenharmony_ci return -1; 44c72fcc34Sopenharmony_ci } 45c72fcc34Sopenharmony_ci 46c72fcc34Sopenharmony_ci if (fstat(fd, &stats) < 0) { 47c72fcc34Sopenharmony_ci close(fd); 48c72fcc34Sopenharmony_ci return -1; 49c72fcc34Sopenharmony_ci } 50c72fcc34Sopenharmony_ci 51c72fcc34Sopenharmony_ci *buf = mmap(NULL, stats.st_size, PROT_READ, MAP_SHARED, fd, 0); 52c72fcc34Sopenharmony_ci if (*buf == MAP_FAILED) { 53c72fcc34Sopenharmony_ci close(fd); 54c72fcc34Sopenharmony_ci return -1; 55c72fcc34Sopenharmony_ci } 56c72fcc34Sopenharmony_ci *bufsize = stats.st_size; 57c72fcc34Sopenharmony_ci 58c72fcc34Sopenharmony_ci close(fd); 59c72fcc34Sopenharmony_ci 60c72fcc34Sopenharmony_ci return 0; 61c72fcc34Sopenharmony_ci} 62c72fcc34Sopenharmony_ci 63c72fcc34Sopenharmony_civoid file_unmap(void *buf, size_t bufsize) 64c72fcc34Sopenharmony_ci{ 65c72fcc34Sopenharmony_ci munmap(buf, bufsize); 66c72fcc34Sopenharmony_ci} 67c72fcc34Sopenharmony_ci 68c72fcc34Sopenharmony_cisize_t line_width(const char *buf, size_t bufsize, size_t pos) 69c72fcc34Sopenharmony_ci{ 70c72fcc34Sopenharmony_ci int esc = 0; 71c72fcc34Sopenharmony_ci size_t count; 72c72fcc34Sopenharmony_ci 73c72fcc34Sopenharmony_ci for (count = pos; count < bufsize; count++) { 74c72fcc34Sopenharmony_ci if (!esc && buf[count] == '\n') 75c72fcc34Sopenharmony_ci break; 76c72fcc34Sopenharmony_ci esc = buf[count] == '\\'; 77c72fcc34Sopenharmony_ci } 78c72fcc34Sopenharmony_ci 79c72fcc34Sopenharmony_ci return count - pos; 80c72fcc34Sopenharmony_ci} 81c72fcc34Sopenharmony_ci 82c72fcc34Sopenharmony_civoid initfailed(int cardnumber, const char *reason, int exitcode) 83c72fcc34Sopenharmony_ci{ 84c72fcc34Sopenharmony_ci int fp; 85c72fcc34Sopenharmony_ci char *str; 86c72fcc34Sopenharmony_ci char sexitcode[16]; 87c72fcc34Sopenharmony_ci 88c72fcc34Sopenharmony_ci if (statefile == NULL) 89c72fcc34Sopenharmony_ci return; 90c72fcc34Sopenharmony_ci if (snd_card_get_name(cardnumber, &str) < 0) 91c72fcc34Sopenharmony_ci return; 92c72fcc34Sopenharmony_ci sprintf(sexitcode, "%i", exitcode); 93c72fcc34Sopenharmony_ci fp = open(statefile, O_WRONLY|O_CREAT|O_APPEND, 0644); 94c72fcc34Sopenharmony_ci (void)write(fp, str, strlen(str)); 95c72fcc34Sopenharmony_ci (void)write(fp, ":", 1); 96c72fcc34Sopenharmony_ci (void)write(fp, reason, strlen(reason)); 97c72fcc34Sopenharmony_ci (void)write(fp, ":", 1); 98c72fcc34Sopenharmony_ci (void)write(fp, sexitcode, strlen(sexitcode)); 99c72fcc34Sopenharmony_ci (void)write(fp, "\n", 1); 100c72fcc34Sopenharmony_ci close(fp); 101c72fcc34Sopenharmony_ci free(str); 102c72fcc34Sopenharmony_ci} 103c72fcc34Sopenharmony_ci 104c72fcc34Sopenharmony_cistatic void syslog_(int prio, const char *fcn, long line, 105c72fcc34Sopenharmony_ci const char *fmt, va_list ap) 106c72fcc34Sopenharmony_ci{ 107c72fcc34Sopenharmony_ci char buf[1024]; 108c72fcc34Sopenharmony_ci 109c72fcc34Sopenharmony_ci snprintf(buf, sizeof(buf), "%s: %s:%ld: ", command, fcn, line); 110c72fcc34Sopenharmony_ci buf[sizeof(buf)-1] = '\0'; 111c72fcc34Sopenharmony_ci vsnprintf(buf + strlen(buf), sizeof(buf)-strlen(buf), fmt, ap); 112c72fcc34Sopenharmony_ci buf[sizeof(buf)-1] = '\0'; 113c72fcc34Sopenharmony_ci syslog(prio, "%s", buf); 114c72fcc34Sopenharmony_ci} 115c72fcc34Sopenharmony_ci 116c72fcc34Sopenharmony_civoid info_(const char *fcn, long line, const char *fmt, ...) 117c72fcc34Sopenharmony_ci{ 118c72fcc34Sopenharmony_ci va_list ap; 119c72fcc34Sopenharmony_ci 120c72fcc34Sopenharmony_ci va_start(ap, fmt); 121c72fcc34Sopenharmony_ci if (use_syslog) { 122c72fcc34Sopenharmony_ci syslog_(LOG_INFO, fcn, line, fmt, ap); 123c72fcc34Sopenharmony_ci } else { 124c72fcc34Sopenharmony_ci fprintf(stdout, "%s: %s:%ld: ", command, fcn, line); 125c72fcc34Sopenharmony_ci vfprintf(stdout, fmt, ap); 126c72fcc34Sopenharmony_ci putc('\n', stdout); 127c72fcc34Sopenharmony_ci } 128c72fcc34Sopenharmony_ci va_end(ap); 129c72fcc34Sopenharmony_ci} 130c72fcc34Sopenharmony_ci 131c72fcc34Sopenharmony_civoid error_(const char *fcn, long line, const char *fmt, ...) 132c72fcc34Sopenharmony_ci{ 133c72fcc34Sopenharmony_ci va_list ap; 134c72fcc34Sopenharmony_ci 135c72fcc34Sopenharmony_ci va_start(ap, fmt); 136c72fcc34Sopenharmony_ci if (use_syslog) { 137c72fcc34Sopenharmony_ci syslog_(LOG_ERR, fcn, line, fmt, ap); 138c72fcc34Sopenharmony_ci } else { 139c72fcc34Sopenharmony_ci fprintf(stderr, "%s: %s:%ld: ", command, fcn, line); 140c72fcc34Sopenharmony_ci vfprintf(stderr, fmt, ap); 141c72fcc34Sopenharmony_ci putc('\n', stderr); 142c72fcc34Sopenharmony_ci } 143c72fcc34Sopenharmony_ci va_end(ap); 144c72fcc34Sopenharmony_ci} 145c72fcc34Sopenharmony_ci 146c72fcc34Sopenharmony_civoid cerror_(const char *fcn, long line, int cond, const char *fmt, ...) 147c72fcc34Sopenharmony_ci{ 148c72fcc34Sopenharmony_ci va_list ap; 149c72fcc34Sopenharmony_ci 150c72fcc34Sopenharmony_ci if (!cond && !debugflag) 151c72fcc34Sopenharmony_ci return; 152c72fcc34Sopenharmony_ci va_start(ap, fmt); 153c72fcc34Sopenharmony_ci if (use_syslog) { 154c72fcc34Sopenharmony_ci syslog_(LOG_ERR, fcn, line, fmt, ap); 155c72fcc34Sopenharmony_ci } else { 156c72fcc34Sopenharmony_ci fprintf(stderr, "%s: %s:%ld: ", command, fcn, line); 157c72fcc34Sopenharmony_ci vfprintf(stderr, fmt, ap); 158c72fcc34Sopenharmony_ci putc('\n', stderr); 159c72fcc34Sopenharmony_ci } 160c72fcc34Sopenharmony_ci va_end(ap); 161c72fcc34Sopenharmony_ci} 162c72fcc34Sopenharmony_ci 163c72fcc34Sopenharmony_civoid dbg_(const char *fcn, long line, const char *fmt, ...) 164c72fcc34Sopenharmony_ci{ 165c72fcc34Sopenharmony_ci va_list ap; 166c72fcc34Sopenharmony_ci 167c72fcc34Sopenharmony_ci if (!debugflag) 168c72fcc34Sopenharmony_ci return; 169c72fcc34Sopenharmony_ci va_start(ap, fmt); 170c72fcc34Sopenharmony_ci if (use_syslog) { 171c72fcc34Sopenharmony_ci syslog_(LOG_DEBUG, fcn, line, fmt, ap); 172c72fcc34Sopenharmony_ci } else { 173c72fcc34Sopenharmony_ci fprintf(stderr, "%s: %s:%ld: ", command, fcn, line); 174c72fcc34Sopenharmony_ci vfprintf(stderr, fmt, ap); 175c72fcc34Sopenharmony_ci putc('\n', stderr); 176c72fcc34Sopenharmony_ci } 177c72fcc34Sopenharmony_ci va_end(ap); 178c72fcc34Sopenharmony_ci} 179c72fcc34Sopenharmony_ci 180c72fcc34Sopenharmony_civoid error_handler(const char *file, int line, const char *function, int err, const char *fmt, ...) 181c72fcc34Sopenharmony_ci{ 182c72fcc34Sopenharmony_ci char buf[2048]; 183c72fcc34Sopenharmony_ci va_list arg; 184c72fcc34Sopenharmony_ci 185c72fcc34Sopenharmony_ci va_start(arg, fmt); 186c72fcc34Sopenharmony_ci vsnprintf(buf, sizeof(buf), fmt, arg); 187c72fcc34Sopenharmony_ci va_end(arg); 188c72fcc34Sopenharmony_ci if (use_syslog) 189c72fcc34Sopenharmony_ci syslog(LOG_ERR, "alsa-lib %s:%i:(%s) %s%s%s\n", file, line, function, 190c72fcc34Sopenharmony_ci buf, err ? ": " : "", err ? snd_strerror(err) : ""); 191c72fcc34Sopenharmony_ci else 192c72fcc34Sopenharmony_ci fprintf(stderr, "alsa-lib %s:%i:(%s) %s%s%s\n", file, line, function, 193c72fcc34Sopenharmony_ci buf, err ? ": " : "", err ? snd_strerror(err) : ""); 194c72fcc34Sopenharmony_ci} 195c72fcc34Sopenharmony_ci 196c72fcc34Sopenharmony_ciint load_configuration(const char *file, snd_config_t **top, int *open_failed) 197c72fcc34Sopenharmony_ci{ 198c72fcc34Sopenharmony_ci snd_config_t *config; 199c72fcc34Sopenharmony_ci snd_input_t *in; 200c72fcc34Sopenharmony_ci int err, stdio_flag, lock_fd = -EINVAL; 201c72fcc34Sopenharmony_ci 202c72fcc34Sopenharmony_ci *top = NULL; 203c72fcc34Sopenharmony_ci if (open_failed) 204c72fcc34Sopenharmony_ci *open_failed = 0; 205c72fcc34Sopenharmony_ci err = snd_config_top(&config); 206c72fcc34Sopenharmony_ci if (err < 0) { 207c72fcc34Sopenharmony_ci error("snd_config_top error: %s", snd_strerror(err)); 208c72fcc34Sopenharmony_ci return err; 209c72fcc34Sopenharmony_ci } 210c72fcc34Sopenharmony_ci stdio_flag = !strcmp(file, "-"); 211c72fcc34Sopenharmony_ci if (stdio_flag) { 212c72fcc34Sopenharmony_ci err = snd_input_stdio_attach(&in, stdin, 0); 213c72fcc34Sopenharmony_ci } else { 214c72fcc34Sopenharmony_ci lock_fd = state_lock(file, LOCK_TIMEOUT); 215c72fcc34Sopenharmony_ci err = lock_fd >= 0 ? snd_input_stdio_open(&in, file, "r") : lock_fd; 216c72fcc34Sopenharmony_ci } 217c72fcc34Sopenharmony_ci if (err < 0) { 218c72fcc34Sopenharmony_ci if (open_failed) 219c72fcc34Sopenharmony_ci *open_failed = 1; 220c72fcc34Sopenharmony_ci goto out; 221c72fcc34Sopenharmony_ci } 222c72fcc34Sopenharmony_ci err = snd_config_load(config, in); 223c72fcc34Sopenharmony_ci snd_input_close(in); 224c72fcc34Sopenharmony_ci if (err < 0) { 225c72fcc34Sopenharmony_ci error("snd_config_load error: %s", snd_strerror(err)); 226c72fcc34Sopenharmony_ciout: 227c72fcc34Sopenharmony_ci if (lock_fd >= 0) 228c72fcc34Sopenharmony_ci state_unlock(lock_fd, file); 229c72fcc34Sopenharmony_ci snd_config_delete(config); 230c72fcc34Sopenharmony_ci snd_config_update_free_global(); 231c72fcc34Sopenharmony_ci return err; 232c72fcc34Sopenharmony_ci } else { 233c72fcc34Sopenharmony_ci if (lock_fd >= 0) 234c72fcc34Sopenharmony_ci state_unlock(lock_fd, file); 235c72fcc34Sopenharmony_ci *top = config; 236c72fcc34Sopenharmony_ci return 0; 237c72fcc34Sopenharmony_ci } 238c72fcc34Sopenharmony_ci} 239c72fcc34Sopenharmony_ci 240c72fcc34Sopenharmony_civoid snd_card_iterator_init(struct snd_card_iterator *iter, int cardno) 241c72fcc34Sopenharmony_ci{ 242c72fcc34Sopenharmony_ci iter->card = cardno; 243c72fcc34Sopenharmony_ci iter->single = cardno >= 0; 244c72fcc34Sopenharmony_ci iter->first = true; 245c72fcc34Sopenharmony_ci iter->name[0] = '\0'; 246c72fcc34Sopenharmony_ci} 247c72fcc34Sopenharmony_ci 248c72fcc34Sopenharmony_ciint snd_card_iterator_sinit(struct snd_card_iterator *iter, const char *cardname) 249c72fcc34Sopenharmony_ci{ 250c72fcc34Sopenharmony_ci int cardno = -1; 251c72fcc34Sopenharmony_ci 252c72fcc34Sopenharmony_ci if (cardname) { 253c72fcc34Sopenharmony_ci if (strncmp(cardname, "hw:", 3) == 0) 254c72fcc34Sopenharmony_ci cardname += 3; 255c72fcc34Sopenharmony_ci cardno = snd_card_get_index(cardname); 256c72fcc34Sopenharmony_ci if (cardno < 0) { 257c72fcc34Sopenharmony_ci error("Cannot find soundcard '%s'...", cardname); 258c72fcc34Sopenharmony_ci return cardno; 259c72fcc34Sopenharmony_ci } 260c72fcc34Sopenharmony_ci } 261c72fcc34Sopenharmony_ci snd_card_iterator_init(iter, cardno); 262c72fcc34Sopenharmony_ci return 0; 263c72fcc34Sopenharmony_ci} 264c72fcc34Sopenharmony_ci 265c72fcc34Sopenharmony_ciconst char *snd_card_iterator_next(struct snd_card_iterator *iter) 266c72fcc34Sopenharmony_ci{ 267c72fcc34Sopenharmony_ci if (iter->single) { 268c72fcc34Sopenharmony_ci if (iter->first) { 269c72fcc34Sopenharmony_ci iter->first = false; 270c72fcc34Sopenharmony_ci goto retval; 271c72fcc34Sopenharmony_ci } 272c72fcc34Sopenharmony_ci return NULL; 273c72fcc34Sopenharmony_ci } 274c72fcc34Sopenharmony_ci if (snd_card_next(&iter->card) < 0) { 275c72fcc34Sopenharmony_ci if (!ignore_nocards && iter->first) 276c72fcc34Sopenharmony_ci error("No soundcards found..."); 277c72fcc34Sopenharmony_ci return NULL; 278c72fcc34Sopenharmony_ci } 279c72fcc34Sopenharmony_ci iter->first = false; 280c72fcc34Sopenharmony_ci if (iter->card < 0) 281c72fcc34Sopenharmony_ci return NULL; 282c72fcc34Sopenharmony_ciretval: 283c72fcc34Sopenharmony_ci snprintf(iter->name, sizeof(iter->name), "hw:%d", iter->card); 284c72fcc34Sopenharmony_ci 285c72fcc34Sopenharmony_ci return (const char *)iter->name; 286c72fcc34Sopenharmony_ci} 287c72fcc34Sopenharmony_ci 288c72fcc34Sopenharmony_ciint snd_card_iterator_error(struct snd_card_iterator *iter) 289c72fcc34Sopenharmony_ci{ 290c72fcc34Sopenharmony_ci return iter->first ? (ignore_nocards ? 0 : -ENODEV) : 0; 291c72fcc34Sopenharmony_ci} 292c72fcc34Sopenharmony_ci 293c72fcc34Sopenharmony_cistatic int cleanup_filename_filter(const struct dirent *dirent) 294c72fcc34Sopenharmony_ci{ 295c72fcc34Sopenharmony_ci size_t flen; 296c72fcc34Sopenharmony_ci 297c72fcc34Sopenharmony_ci if (dirent == NULL) 298c72fcc34Sopenharmony_ci return 0; 299c72fcc34Sopenharmony_ci if (dirent->d_type == DT_DIR) 300c72fcc34Sopenharmony_ci return 0; 301c72fcc34Sopenharmony_ci 302c72fcc34Sopenharmony_ci flen = strlen(dirent->d_name); 303c72fcc34Sopenharmony_ci if (flen <= 5) 304c72fcc34Sopenharmony_ci return 0; 305c72fcc34Sopenharmony_ci 306c72fcc34Sopenharmony_ci if (strncmp(&dirent->d_name[flen-5], ".conf", 5) == 0) 307c72fcc34Sopenharmony_ci return 1; 308c72fcc34Sopenharmony_ci 309c72fcc34Sopenharmony_ci return 0; 310c72fcc34Sopenharmony_ci} 311c72fcc34Sopenharmony_ci 312c72fcc34Sopenharmony_ciint snd_card_clean_cfgdir(const char *cfgdir, int cardno) 313c72fcc34Sopenharmony_ci{ 314c72fcc34Sopenharmony_ci char path[PATH_MAX]; 315c72fcc34Sopenharmony_ci struct dirent **list; 316c72fcc34Sopenharmony_ci int lasterr = 0, n, j; 317c72fcc34Sopenharmony_ci 318c72fcc34Sopenharmony_ci snprintf(path, sizeof(path), "%s/card%d.conf.d", cfgdir, cardno); 319c72fcc34Sopenharmony_ci n = scandir(path, &list, cleanup_filename_filter, NULL); 320c72fcc34Sopenharmony_ci if (n < 0) { 321c72fcc34Sopenharmony_ci if (errno == ENOENT) 322c72fcc34Sopenharmony_ci return 0; 323c72fcc34Sopenharmony_ci return -errno; 324c72fcc34Sopenharmony_ci } 325c72fcc34Sopenharmony_ci for (j = 0; j < n; j++) { 326c72fcc34Sopenharmony_ci snprintf(path, sizeof(path), "%s/card%d.conf.d/%s", cfgdir, cardno, list[j]->d_name); 327c72fcc34Sopenharmony_ci if (remove(path)) { 328c72fcc34Sopenharmony_ci error("Unable to remove file '%s'", path); 329c72fcc34Sopenharmony_ci lasterr = -errno; 330c72fcc34Sopenharmony_ci } 331c72fcc34Sopenharmony_ci } 332c72fcc34Sopenharmony_ci 333c72fcc34Sopenharmony_ci return lasterr; 334c72fcc34Sopenharmony_ci} 335