xref: /openbsd-src/usr.bin/sndiod/utils.c (revision 7b6392009e6e5a7f8e494c162a4d259ea5e13a62)
1 /*	$OpenBSD: utils.c,v 1.9 2024/12/20 07:35:56 ratchov Exp $	*/
2 /*
3  * Copyright (c) 2003-2012 Alexandre Ratchov <alex@caoua.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 /*
18  * logx() quickly stores traces into a trace buffer.
19  * This allows traces to be collected during time sensitive operations without
20  * disturbing them. The buffer can be flushed on standard error later, when
21  * slow syscalls are no longer disruptive, e.g. at the end of the poll() loop.
22  */
23 #include <errno.h>
24 #include <signal.h>
25 #include <stdarg.h>
26 #include <stdint.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include "utils.h"
33 
34 /*
35  * log buffer size
36  */
37 #define LOG_BUFSZ	8192
38 
39 char log_buf[LOG_BUFSZ];	/* buffer where traces are stored */
40 size_t log_used = 0;		/* bytes used in the buffer */
41 unsigned int log_sync = 1;	/* if true, flush after each '\n' */
42 
43 /*
44  * write the log buffer on stderr
45  */
46 void
47 log_flush(void)
48 {
49 	if (log_used == 0)
50 		return;
51 	write(STDERR_FILENO, log_buf, log_used);
52 	log_used = 0;
53 }
54 
55 /*
56  * log a single line to stderr
57  */
58 void
59 log_do(const char *fmt, ...)
60 {
61 	va_list ap;
62 	int n, save_errno = errno;
63 
64 	va_start(ap, fmt);
65 	n = vsnprintf(log_buf + log_used, sizeof(log_buf) - log_used, fmt, ap);
66 	va_end(ap);
67 
68 	if (n != -1) {
69 		log_used += n;
70 
71 		if (log_used >= sizeof(log_buf))
72 			log_used = sizeof(log_buf) - 1;
73 		log_buf[log_used++] = '\n';
74 
75 		if (log_sync)
76 			log_flush();
77 	}
78 	errno = save_errno;
79 }
80 
81 /*
82  * abort program execution after a fatal error
83  */
84 void
85 panic(void)
86 {
87 	log_flush();
88 	(void)kill(getpid(), SIGABRT);
89 	_exit(1);
90 }
91 
92 /*
93  * allocate 'size' bytes of memory (with size > 0). This functions never
94  * fails (and never returns NULL), if there isn't enough memory then
95  * abort the program.
96  */
97 void *
98 xmalloc(size_t size)
99 {
100 	void *p;
101 
102 	p = malloc(size);
103 	if (p == NULL) {
104 		logx(0, "failed to allocate %zu bytes", size);
105 		panic();
106 	}
107 	return p;
108 }
109 
110 /*
111  * free memory allocated with xmalloc()
112  */
113 void
114 xfree(void *p)
115 {
116 #ifdef DEBUG
117 	if (p == NULL) {
118 		logx(0, "xfree with NULL arg");
119 		panic();
120 	}
121 #endif
122 	free(p);
123 }
124 
125 /*
126  * xmalloc-style strdup(3)
127  */
128 char *
129 xstrdup(char *s)
130 {
131 	size_t size;
132 	void *p;
133 
134 	size = strlen(s) + 1;
135 	p = xmalloc(size);
136 	memcpy(p, s, size);
137 	return p;
138 }
139