xref: /openbsd-src/usr.bin/sndiod/utils.c (revision 7b6392009e6e5a7f8e494c162a4d259ea5e13a62)
1*7b639200Sratchov /*	$OpenBSD: utils.c,v 1.9 2024/12/20 07:35:56 ratchov Exp $	*/
287bc9f6aSratchov /*
387bc9f6aSratchov  * Copyright (c) 2003-2012 Alexandre Ratchov <alex@caoua.org>
487bc9f6aSratchov  *
587bc9f6aSratchov  * Permission to use, copy, modify, and distribute this software for any
687bc9f6aSratchov  * purpose with or without fee is hereby granted, provided that the above
787bc9f6aSratchov  * copyright notice and this permission notice appear in all copies.
887bc9f6aSratchov  *
987bc9f6aSratchov  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1087bc9f6aSratchov  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1187bc9f6aSratchov  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1287bc9f6aSratchov  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1387bc9f6aSratchov  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1487bc9f6aSratchov  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1587bc9f6aSratchov  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1687bc9f6aSratchov  */
1787bc9f6aSratchov /*
18*7b639200Sratchov  * logx() quickly stores traces into a trace buffer.
19202bc2e6Sratchov  * This allows traces to be collected during time sensitive operations without
2087bc9f6aSratchov  * disturbing them. The buffer can be flushed on standard error later, when
2187bc9f6aSratchov  * slow syscalls are no longer disruptive, e.g. at the end of the poll() loop.
2287bc9f6aSratchov  */
23*7b639200Sratchov #include <errno.h>
2487bc9f6aSratchov #include <signal.h>
25*7b639200Sratchov #include <stdarg.h>
26*7b639200Sratchov #include <stdint.h>
27*7b639200Sratchov #include <stdio.h>
2887bc9f6aSratchov #include <stdlib.h>
2987bc9f6aSratchov #include <string.h>
3087bc9f6aSratchov #include <unistd.h>
3187bc9f6aSratchov #include <fcntl.h>
3287bc9f6aSratchov #include "utils.h"
3387bc9f6aSratchov 
3487bc9f6aSratchov /*
3587bc9f6aSratchov  * log buffer size
3687bc9f6aSratchov  */
3787bc9f6aSratchov #define LOG_BUFSZ	8192
3887bc9f6aSratchov 
3987bc9f6aSratchov char log_buf[LOG_BUFSZ];	/* buffer where traces are stored */
40*7b639200Sratchov size_t log_used = 0;		/* bytes used in the buffer */
4187bc9f6aSratchov unsigned int log_sync = 1;	/* if true, flush after each '\n' */
4287bc9f6aSratchov 
4387bc9f6aSratchov /*
4487bc9f6aSratchov  * write the log buffer on stderr
4587bc9f6aSratchov  */
4687bc9f6aSratchov void
4787bc9f6aSratchov log_flush(void)
4887bc9f6aSratchov {
4987bc9f6aSratchov 	if (log_used == 0)
5087bc9f6aSratchov 		return;
5187bc9f6aSratchov 	write(STDERR_FILENO, log_buf, log_used);
5287bc9f6aSratchov 	log_used = 0;
5387bc9f6aSratchov }
5487bc9f6aSratchov 
5587bc9f6aSratchov /*
56*7b639200Sratchov  * log a single line to stderr
5787bc9f6aSratchov  */
5887bc9f6aSratchov void
59*7b639200Sratchov log_do(const char *fmt, ...)
6087bc9f6aSratchov {
61*7b639200Sratchov 	va_list ap;
62*7b639200Sratchov 	int n, save_errno = errno;
6387bc9f6aSratchov 
64*7b639200Sratchov 	va_start(ap, fmt);
65*7b639200Sratchov 	n = vsnprintf(log_buf + log_used, sizeof(log_buf) - log_used, fmt, ap);
66*7b639200Sratchov 	va_end(ap);
67*7b639200Sratchov 
68*7b639200Sratchov 	if (n != -1) {
69*7b639200Sratchov 		log_used += n;
70*7b639200Sratchov 
71*7b639200Sratchov 		if (log_used >= sizeof(log_buf))
72*7b639200Sratchov 			log_used = sizeof(log_buf) - 1;
73*7b639200Sratchov 		log_buf[log_used++] = '\n';
74*7b639200Sratchov 
75*7b639200Sratchov 		if (log_sync)
7687bc9f6aSratchov 			log_flush();
7787bc9f6aSratchov 	}
78*7b639200Sratchov 	errno = save_errno;
7987bc9f6aSratchov }
8087bc9f6aSratchov 
8187bc9f6aSratchov /*
8287bc9f6aSratchov  * abort program execution after a fatal error
8387bc9f6aSratchov  */
8487bc9f6aSratchov void
8587bc9f6aSratchov panic(void)
8687bc9f6aSratchov {
8787bc9f6aSratchov 	log_flush();
8887bc9f6aSratchov 	(void)kill(getpid(), SIGABRT);
8987bc9f6aSratchov 	_exit(1);
9087bc9f6aSratchov }
9187bc9f6aSratchov 
9287bc9f6aSratchov /*
93202bc2e6Sratchov  * allocate 'size' bytes of memory (with size > 0). This functions never
94202bc2e6Sratchov  * fails (and never returns NULL), if there isn't enough memory then
95202bc2e6Sratchov  * abort the program.
9687bc9f6aSratchov  */
9787bc9f6aSratchov void *
9887bc9f6aSratchov xmalloc(size_t size)
9987bc9f6aSratchov {
10087bc9f6aSratchov 	void *p;
10187bc9f6aSratchov 
10287bc9f6aSratchov 	p = malloc(size);
10387bc9f6aSratchov 	if (p == NULL) {
104*7b639200Sratchov 		logx(0, "failed to allocate %zu bytes", size);
10587bc9f6aSratchov 		panic();
10687bc9f6aSratchov 	}
10787bc9f6aSratchov 	return p;
10887bc9f6aSratchov }
10987bc9f6aSratchov 
11087bc9f6aSratchov /*
11187bc9f6aSratchov  * free memory allocated with xmalloc()
11287bc9f6aSratchov  */
11387bc9f6aSratchov void
11487bc9f6aSratchov xfree(void *p)
11587bc9f6aSratchov {
116f7084eecSratchov #ifdef DEBUG
117f7084eecSratchov 	if (p == NULL) {
118*7b639200Sratchov 		logx(0, "xfree with NULL arg");
119f7084eecSratchov 		panic();
120f7084eecSratchov 	}
121f7084eecSratchov #endif
12287bc9f6aSratchov 	free(p);
12387bc9f6aSratchov }
12487bc9f6aSratchov 
12587bc9f6aSratchov /*
12687bc9f6aSratchov  * xmalloc-style strdup(3)
12787bc9f6aSratchov  */
12887bc9f6aSratchov char *
12987bc9f6aSratchov xstrdup(char *s)
13087bc9f6aSratchov {
13187bc9f6aSratchov 	size_t size;
13287bc9f6aSratchov 	void *p;
13387bc9f6aSratchov 
13487bc9f6aSratchov 	size = strlen(s) + 1;
13587bc9f6aSratchov 	p = xmalloc(size);
13687bc9f6aSratchov 	memcpy(p, s, size);
13787bc9f6aSratchov 	return p;
13887bc9f6aSratchov }
139