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