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