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