1/* $OpenBSD: debugutil.c,v 1.7 2024/02/26 08:25:51 yasuoka Exp $ */ 2/*- 3 * Copyright (c) 2009 Internet Initiative Japan Inc. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27#include <sys/types.h> 28#include <stdio.h> 29#include <errno.h> 30#include <string.h> 31#include <syslog.h> 32#include <stdarg.h> 33#include <stdlib.h> 34#include <time.h> 35 36#include "debugutil.h" 37 38#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) 39#define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b)) 40 41int debuglevel = 0; 42FILE *debugfp = NULL; 43static int prio_idx_inititialized = 0; 44 45static void set_prio_idx_init(void); 46 47#ifndef countof 48#define countof(x) (sizeof((x)) / sizeof((x)[0])) 49#endif 50#define VAL_NAME(x) { (x), #x} 51 52#ifndef LOG_PRI 53#define LOG_PRI(p) ((p) & LOG_PRIMASK) 54#endif 55 56static int use_syslog = 1; 57static int no_debuglog = 0; 58static int syslog_level_adjust = 0; 59 60static struct { 61 int prio; 62 const char *name; 63} prio_name[] = { 64 VAL_NAME(LOG_EMERG), 65 VAL_NAME(LOG_ALERT), 66 VAL_NAME(LOG_CRIT), 67 VAL_NAME(LOG_ERR), 68 VAL_NAME(LOG_WARNING), 69 VAL_NAME(LOG_NOTICE), 70 VAL_NAME(LOG_INFO), 71 VAL_NAME(LOG_DEBUG) 72}; 73 74static const char *prio_name_idx[16]; 75 76static void 77set_prio_idx_init() 78{ 79 int i; 80 81 if (prio_idx_inititialized) 82 return; 83 for (i = 0; i < (int)countof(prio_name); i++) { 84 ASSERT(prio_name[i].prio < countof(prio_name_idx)); 85 if (prio_name[i].prio >= (int)countof(prio_name_idx)) 86 continue; 87 prio_name_idx[prio_name[i].prio] = &prio_name[i].name[4]; 88 } 89 prio_idx_inititialized = 1; 90} 91 92void 93debug_set_debugfp(FILE *fp) 94{ 95 debugfp = fp; 96} 97 98void 99debug_use_syslog(int b) 100{ 101 if (b) 102 use_syslog = 1; 103 else 104 use_syslog = 0; 105} 106 107void 108debug_set_no_debuglog(int no_debuglog0) 109{ 110 if (no_debuglog0) 111 no_debuglog = 1; 112 else 113 no_debuglog = 0; 114} 115 116FILE * 117debug_get_debugfp() 118{ 119 return debugfp; 120} 121 122#define DL(p) ((p) >> 24 & 0xff) 123int 124vlog_printf(uint32_t prio, const char *format, va_list ap) 125{ 126 int status = 0, i, fmtoff = 0, state = 0, fmtlen, saved_errno, level; 127 char fmt[8192]; 128 struct tm *lt; 129 time_t now; 130 131 ASSERT(format != NULL); 132 ASSERT(format[0] != '\0'); 133 if (DL(prio) > 0 && debuglevel < (int)DL(prio)) 134 return -1; 135 if (no_debuglog && LOG_PRI(prio) >= LOG_DEBUG) 136 return -1; 137 138 if (!prio_idx_inititialized) 139 set_prio_idx_init(); 140 if (use_syslog && DL(prio) == 0) { 141 level = LOG_PRI(prio) + syslog_level_adjust; 142 if (!no_debuglog || level < LOG_DEBUG) { 143 level = MINIMUM(LOG_DEBUG, level); 144 level = MAXIMUM(LOG_EMERG, level); 145 level |= (prio & LOG_FACMASK); 146 vsyslog(level, format, ap); 147 } 148 } 149 150 if (debugfp == NULL) 151 return -1; 152 153 time(&now); 154 lt = localtime(&now); 155 156 fmtlen = strlen(format); 157 for (i = 0; i < fmtlen; i++) { 158 /* 2 chars in this block and 2 chars after this block */ 159 if (sizeof(fmt) - fmtoff < 4) 160 break; 161 switch(state) { 162 case 0: 163 switch(format[i]) { 164 case '%': 165 state = 1; 166 goto copy_loop; 167 case '\n': 168 fmt[fmtoff++] = '\n'; 169 fmt[fmtoff++] = '\t'; 170 goto copy_loop; 171 } 172 break; 173 case 1: 174 switch(format[i]) { 175 default: 176 case '%': 177 fmt[fmtoff++] = '%'; 178 state = 0; 179 break; 180 case 'm': 181 fmt[fmtoff] = '\0'; 182 saved_errno = errno; 183 /* -1 is to reserve for '\n' */ 184 strlcat(fmt, strerror(errno), sizeof(fmt) - 1); 185 errno = saved_errno; 186 fmtoff = strlen(fmt); 187 state = 0; 188 goto copy_loop; 189 } 190 } 191 fmt[fmtoff++] = format[i]; 192copy_loop: 193 continue; 194 } 195 /* remove trailing TAB */ 196 if (fmtoff > 0 && fmt[fmtoff - 1] == '\t') 197 fmtoff--; 198 /* append new line char */ 199 if (fmtoff == 0 || fmt[fmtoff-1] != '\n') 200 fmt[fmtoff++] = '\n'; 201 202 fmt[fmtoff] = '\0'; 203 204 ASSERT(0 <= LOG_PRI(prio) 205 && LOG_PRI(prio) < countof(prio_name_idx) 206 && prio_name_idx[LOG_PRI(prio)] != NULL); 207 ftell(debugfp); 208 fprintf(debugfp, 209 "%04d-%02d-%02d %02d:%02d:%02d:%s: " 210 , lt->tm_year + 1900 211 , lt->tm_mon + 1 212 , lt->tm_mday 213 , lt->tm_hour 214 , lt->tm_min 215 , lt->tm_sec 216 , (prio & 0xff000000) ? "DEBUG" : prio_name_idx[LOG_PRI(prio)] 217 ); 218 status = vfprintf(debugfp, fmt, ap); 219 fflush(debugfp); 220 221 return status; 222} 223 224int 225log_printf(int prio, const char *fmt, ...) 226{ 227 int status; 228 va_list ap; 229 230 va_start(ap, fmt); 231 status = vlog_printf((uint32_t)prio, fmt, ap); 232 va_end(ap); 233 234 return status; 235} 236 237void 238debug_set_syslog_level_adjust(int adjust) 239{ 240 syslog_level_adjust = adjust; 241} 242 243int 244debug_get_syslog_level_adjust(void) 245{ 246 return syslog_level_adjust; 247} 248 249 250/* 251 * show_hd - 252 * print hexadecimal/ascii dump for debug 253 * 254 * usage: 255 * show_hd(stderr, buf, sizeof(buf)); 256 */ 257void 258show_hd(FILE *file, const u_char *buf, int len) 259{ 260 int i, o = 0; 261 int hd_cnt = 0; 262 char linebuf[80]; 263 char asciibuf[17]; 264 265 memset(asciibuf, ' ', sizeof(asciibuf)); 266 asciibuf[sizeof(asciibuf)-1] = '\0'; 267 268 for (i = 0; i < len; i++) { 269 if (0x20 <= *(buf+i) && *(buf+i) <= 0x7e) 270 asciibuf[hd_cnt % 16] = *(buf+i); 271 else 272 asciibuf[hd_cnt % 16] = '.'; 273 274 switch (hd_cnt % 16) { 275 case 0: 276 o += snprintf(linebuf + o, sizeof(linebuf) - o, 277 "%04x %02x", hd_cnt, 278 (unsigned char)*(buf+i)); 279 break; 280 case 15: 281 o += snprintf(linebuf + o, sizeof(linebuf) - o, 282 "%02x", (unsigned char)*(buf+i)); 283 if (file) 284 fprintf(file, "\t%-47s |%s|\n", linebuf, 285 asciibuf); 286 else 287 syslog(LOG_ERR, "%-47s |%s|\n", linebuf, 288 asciibuf); 289 memset(asciibuf, ' ', sizeof(asciibuf)); 290 asciibuf[sizeof(asciibuf)-1] = '\0'; 291 o = 0; 292 break; 293 case 8: 294 o += snprintf(linebuf + o, sizeof(linebuf) - o, 295 "- %02x", (unsigned char)*(buf+i)); 296 break; 297 default: 298 if (hd_cnt % 2 == 1) 299 o += snprintf(linebuf + o, sizeof(linebuf) - o, 300 "%02x ", (unsigned char)*(buf+i)); 301 else 302 o += snprintf(linebuf + o, sizeof(linebuf) - o, 303 "%02x", (unsigned char)*(buf+i)); 304 break; 305 } 306 hd_cnt++; 307 } 308 if (hd_cnt > 0 && (hd_cnt % 16) != 0) { 309 if (file) 310 fprintf(file, "\t%-47s |%s|\n", linebuf, asciibuf); 311 else 312 syslog(LOG_ERR, "%-47s |%s|\n", linebuf, asciibuf); 313 } 314 if (file) 315 fflush(file); 316} 317