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