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
log_flush(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
log_do(const char * fmt,...)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
panic(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 *
xmalloc(size_t size)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
xfree(void * p)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 *
xstrdup(char * s)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