• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
file_map(const char * filename,char ** buf,size_t * bufsize)36 int 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 
file_unmap(void * buf,size_t bufsize)63 void file_unmap(void *buf, size_t bufsize)
64 {
65 	munmap(buf, bufsize);
66 }
67 
line_width(const char * buf,size_t bufsize,size_t pos)68 size_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 
initfailed(int cardnumber,const char * reason,int exitcode)82 void 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 
syslog_(int prio,const char * fcn,long line,const char * fmt,va_list ap)104 static 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 
info_(const char * fcn,long line,const char * fmt,...)116 void 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 
error_(const char * fcn,long line,const char * fmt,...)131 void 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 
cerror_(const char * fcn,long line,int cond,const char * fmt,...)146 void 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 
dbg_(const char * fcn,long line,const char * fmt,...)163 void 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 
error_handler(const char * file,int line,const char * function,int err,const char * fmt,...)180 void 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 
load_configuration(const char * file,snd_config_t ** top,int * open_failed)196 int 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, 10);
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));
226 out:
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 
snd_card_iterator_init(struct snd_card_iterator * iter,int cardno)240 void 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 
snd_card_iterator_sinit(struct snd_card_iterator * iter,const char * cardname)248 int 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 
snd_card_iterator_next(struct snd_card_iterator * iter)265 const 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;
282 retval:
283 	snprintf(iter->name, sizeof(iter->name), "hw:%d", iter->card);
284 
285 	return (const char *)iter->name;
286 }
287 
snd_card_iterator_error(struct snd_card_iterator * iter)288 int snd_card_iterator_error(struct snd_card_iterator *iter)
289 {
290 	return iter->first ? (ignore_nocards ? 0 : -ENODEV) : 0;
291 }
292 
cleanup_filename_filter(const struct dirent * dirent)293 static 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 
snd_card_clean_cfgdir(const char * cfgdir,int cardno)312 int 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