xref: /openbsd-src/usr.bin/aucat/utils.c (revision b4d5e3c92baf7ae1b3dcb69a4c795856a3c74115)
1*b4d5e3c9Sratchov /*	$OpenBSD: utils.c,v 1.7 2024/12/22 14:17:45 ratchov Exp $	*/
210ba9548Sratchov /*
310ba9548Sratchov  * Copyright (c) 2003-2012 Alexandre Ratchov <alex@caoua.org>
410ba9548Sratchov  *
510ba9548Sratchov  * Permission to use, copy, modify, and distribute this software for any
610ba9548Sratchov  * purpose with or without fee is hereby granted, provided that the above
710ba9548Sratchov  * copyright notice and this permission notice appear in all copies.
810ba9548Sratchov  *
910ba9548Sratchov  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1010ba9548Sratchov  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1110ba9548Sratchov  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1210ba9548Sratchov  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1310ba9548Sratchov  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1410ba9548Sratchov  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1510ba9548Sratchov  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1610ba9548Sratchov  */
1710ba9548Sratchov /*
18*b4d5e3c9Sratchov  * logx() quickly stores traces into a trace buffer.
19202bc2e6Sratchov  * This allows traces to be collected during time sensitive operations without
2010ba9548Sratchov  * disturbing them. The buffer can be flushed on standard error later, when
2110ba9548Sratchov  * slow syscalls are no longer disruptive, e.g. at the end of the poll() loop.
2210ba9548Sratchov  */
23*b4d5e3c9Sratchov #include <errno.h>
2410ba9548Sratchov #include <signal.h>
25*b4d5e3c9Sratchov #include <stdarg.h>
26*b4d5e3c9Sratchov #include <stdint.h>
27*b4d5e3c9Sratchov #include <stdio.h>
2810ba9548Sratchov #include <stdlib.h>
2910ba9548Sratchov #include <string.h>
3010ba9548Sratchov #include <unistd.h>
31d2b3dcecSratchov #include <fcntl.h>
3210ba9548Sratchov #include "utils.h"
3310ba9548Sratchov 
3410ba9548Sratchov /*
3510ba9548Sratchov  * log buffer size
3610ba9548Sratchov  */
3710ba9548Sratchov #define LOG_BUFSZ	8192
3810ba9548Sratchov 
3910ba9548Sratchov char log_buf[LOG_BUFSZ];	/* buffer where traces are stored */
40*b4d5e3c9Sratchov size_t log_used = 0;		/* bytes used in the buffer */
4110ba9548Sratchov unsigned int log_sync = 1;	/* if true, flush after each '\n' */
4210ba9548Sratchov 
4310ba9548Sratchov /*
4410ba9548Sratchov  * write the log buffer on stderr
4510ba9548Sratchov  */
4610ba9548Sratchov void
4710ba9548Sratchov log_flush(void)
4810ba9548Sratchov {
4910ba9548Sratchov 	if (log_used == 0)
5010ba9548Sratchov 		return;
5110ba9548Sratchov 	write(STDERR_FILENO, log_buf, log_used);
5210ba9548Sratchov 	log_used = 0;
5310ba9548Sratchov }
5410ba9548Sratchov 
5510ba9548Sratchov /*
56*b4d5e3c9Sratchov  * log a single line to stderr
5710ba9548Sratchov  */
5810ba9548Sratchov void
59*b4d5e3c9Sratchov log_do(const char *fmt, ...)
6010ba9548Sratchov {
61*b4d5e3c9Sratchov 	va_list ap;
62*b4d5e3c9Sratchov 	int n, save_errno = errno;
6310ba9548Sratchov 
64*b4d5e3c9Sratchov 	va_start(ap, fmt);
65*b4d5e3c9Sratchov 	n = vsnprintf(log_buf + log_used, sizeof(log_buf) - log_used, fmt, ap);
66*b4d5e3c9Sratchov 	va_end(ap);
67*b4d5e3c9Sratchov 
68*b4d5e3c9Sratchov 	if (n != -1) {
69*b4d5e3c9Sratchov 		log_used += n;
70*b4d5e3c9Sratchov 
71*b4d5e3c9Sratchov 		if (log_used >= sizeof(log_buf))
72*b4d5e3c9Sratchov 			log_used = sizeof(log_buf) - 1;
73*b4d5e3c9Sratchov 		log_buf[log_used++] = '\n';
74*b4d5e3c9Sratchov 
75*b4d5e3c9Sratchov 		if (log_sync)
7610ba9548Sratchov 			log_flush();
7710ba9548Sratchov 	}
78*b4d5e3c9Sratchov 	errno = save_errno;
7910ba9548Sratchov }
8010ba9548Sratchov 
8110ba9548Sratchov /*
8210ba9548Sratchov  * abort program execution after a fatal error
8310ba9548Sratchov  */
8410ba9548Sratchov void
8510ba9548Sratchov panic(void)
8610ba9548Sratchov {
8710ba9548Sratchov 	log_flush();
8810ba9548Sratchov 	(void)kill(getpid(), SIGABRT);
8910ba9548Sratchov 	_exit(1);
9010ba9548Sratchov }
9110ba9548Sratchov 
9210ba9548Sratchov /*
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.
9610ba9548Sratchov  */
9710ba9548Sratchov void *
9810ba9548Sratchov xmalloc(size_t size)
9910ba9548Sratchov {
10010ba9548Sratchov 	void *p;
10110ba9548Sratchov 
10210ba9548Sratchov 	p = malloc(size);
10310ba9548Sratchov 	if (p == NULL) {
104*b4d5e3c9Sratchov 		logx(0, "failed to allocate %zu bytes", size);
10510ba9548Sratchov 		panic();
10610ba9548Sratchov 	}
10710ba9548Sratchov 	return p;
10810ba9548Sratchov }
10910ba9548Sratchov 
11010ba9548Sratchov /*
111d2b3dcecSratchov  * free memory allocated with xmalloc()
112d2b3dcecSratchov  */
113d2b3dcecSratchov void
114d2b3dcecSratchov xfree(void *p)
115d2b3dcecSratchov {
116d2b3dcecSratchov #ifdef DEBUG
117d2b3dcecSratchov 	if (p == NULL) {
118*b4d5e3c9Sratchov 		logx(0, "xfree with NULL arg");
119d2b3dcecSratchov 		panic();
120d2b3dcecSratchov 	}
121d2b3dcecSratchov #endif
122d2b3dcecSratchov 	free(p);
123d2b3dcecSratchov }
124d2b3dcecSratchov 
125d2b3dcecSratchov /*
12610ba9548Sratchov  * xmalloc-style strdup(3)
12710ba9548Sratchov  */
12810ba9548Sratchov char *
12910ba9548Sratchov xstrdup(char *s)
13010ba9548Sratchov {
13110ba9548Sratchov 	size_t size;
13210ba9548Sratchov 	void *p;
13310ba9548Sratchov 
13410ba9548Sratchov 	size = strlen(s) + 1;
13510ba9548Sratchov 	p = xmalloc(size);
13610ba9548Sratchov 	memcpy(p, s, size);
13710ba9548Sratchov 	return p;
13810ba9548Sratchov }
139