1 /* $OpenBSD: debugutil.c,v 1.6 2017/05/30 17:22:00 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 41 int debuglevel = 0; 42 FILE *debugfp = NULL; 43 static int prio_idx_inititialized = 0; 44 45 static 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 56 static int use_syslog = 1; 57 static int no_debuglog = 0; 58 static int syslog_level_adjust = 0; 59 60 static 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 74 static const char *prio_name_idx[16]; 75 76 static void 77 set_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 92 void 93 debug_set_debugfp(fp) 94 FILE *fp; 95 { 96 debugfp = fp; 97 } 98 99 void 100 debug_use_syslog(b) 101 int b; 102 { 103 if (b) 104 use_syslog = 1; 105 else 106 use_syslog = 0; 107 } 108 109 void 110 debug_set_no_debuglog(int no_debuglog0) 111 { 112 if (no_debuglog0) 113 no_debuglog = 1; 114 else 115 no_debuglog = 0; 116 } 117 118 FILE * 119 debug_get_debugfp() 120 { 121 return debugfp; 122 } 123 124 #define DL(p) ((p) >> 24 & 0xff) 125 int 126 vlog_printf(uint32_t prio, const char *format, va_list ap) 127 { 128 int status = 0, i, fmtoff = 0, state = 0, fmtlen, saved_errno, level; 129 char fmt[8192]; 130 struct tm *lt; 131 time_t now; 132 133 ASSERT(format != NULL); 134 ASSERT(format[0] != '\0'); 135 if (DL(prio) > 0 && debuglevel < (int)DL(prio)) 136 return -1; 137 if (no_debuglog && LOG_PRI(prio) >= LOG_DEBUG) 138 return -1; 139 140 if (!prio_idx_inititialized) 141 set_prio_idx_init(); 142 if (use_syslog && DL(prio) == 0) { 143 level = LOG_PRI(prio) + syslog_level_adjust; 144 if (!no_debuglog || level < LOG_DEBUG) { 145 level = MINIMUM(LOG_DEBUG, level); 146 level = MAXIMUM(LOG_EMERG, level); 147 level |= (prio & LOG_FACMASK); 148 vsyslog(level, format, ap); 149 } 150 } 151 152 if (debugfp == NULL) 153 return -1; 154 155 time(&now); 156 lt = localtime(&now); 157 158 fmtlen = strlen(format); 159 for (i = 0; i < fmtlen; i++) { 160 /* 2 chars in this block and 2 chars after this block */ 161 if (sizeof(fmt) - fmtoff < 4) 162 break; 163 switch(state) { 164 case 0: 165 switch(format[i]) { 166 case '%': 167 state = 1; 168 goto copy_loop; 169 case '\n': 170 fmt[fmtoff++] = '\n'; 171 fmt[fmtoff++] = '\t'; 172 goto copy_loop; 173 } 174 break; 175 case 1: 176 switch(format[i]) { 177 default: 178 case '%': 179 fmt[fmtoff++] = '%'; 180 state = 0; 181 break; 182 case 'm': 183 fmt[fmtoff] = '\0'; 184 saved_errno = errno; 185 /* -1 is to reserve for '\n' */ 186 strlcat(fmt, strerror(errno), sizeof(fmt) - 1); 187 errno = saved_errno; 188 fmtoff = strlen(fmt); 189 state = 0; 190 goto copy_loop; 191 } 192 } 193 fmt[fmtoff++] = format[i]; 194 copy_loop: 195 continue; 196 } 197 /* remove trailing TAB */ 198 if (fmtoff > 0 && fmt[fmtoff - 1] == '\t') 199 fmtoff--; 200 /* append new line char */ 201 if (fmtoff == 0 || fmt[fmtoff-1] != '\n') 202 fmt[fmtoff++] = '\n'; 203 204 fmt[fmtoff] = '\0'; 205 206 ASSERT(0 <= LOG_PRI(prio) 207 && LOG_PRI(prio) < countof(prio_name_idx) 208 && prio_name_idx[LOG_PRI(prio)] != NULL); 209 ftell(debugfp); 210 fprintf(debugfp, 211 "%04d-%02d-%02d %02d:%02d:%02d:%s: " 212 , lt->tm_year + 1900 213 , lt->tm_mon + 1 214 , lt->tm_mday 215 , lt->tm_hour 216 , lt->tm_min 217 , lt->tm_sec 218 , (prio & 0xff000000) ? "DEBUG" : prio_name_idx[LOG_PRI(prio)] 219 ); 220 status = vfprintf(debugfp, fmt, ap); 221 fflush(debugfp); 222 223 return status; 224 } 225 226 int 227 log_printf(int prio, const char *fmt, ...) 228 { 229 int status; 230 va_list ap; 231 232 va_start(ap, fmt); 233 status = vlog_printf((uint32_t)prio, fmt, ap); 234 va_end(ap); 235 236 return status; 237 } 238 239 void 240 debug_set_syslog_level_adjust(int adjust) 241 { 242 syslog_level_adjust = adjust; 243 } 244 245 int 246 debug_get_syslog_level_adjust(void) 247 { 248 return syslog_level_adjust; 249 } 250 251 252 /* 253 * show_hd - 254 * print hexadecimal/ascii dump for debug 255 * 256 * usage: 257 * show_hd(stderr, buf, sizeof(buf)); 258 */ 259 void 260 show_hd(FILE *file, const u_char *buf, int len) 261 { 262 int i, o = 0; 263 int hd_cnt = 0; 264 char linebuf[80]; 265 char asciibuf[17]; 266 267 memset(asciibuf, ' ', sizeof(asciibuf)); 268 asciibuf[sizeof(asciibuf)-1] = '\0'; 269 270 for (i = 0; i < len; i++) { 271 if (0x20 <= *(buf+i) && *(buf+i) <= 0x7e) 272 asciibuf[hd_cnt % 16] = *(buf+i); 273 else 274 asciibuf[hd_cnt % 16] = '.'; 275 276 switch (hd_cnt % 16) { 277 case 0: 278 o += snprintf(linebuf + o, sizeof(linebuf) - o, 279 "%04x %02x", hd_cnt, 280 (unsigned char)*(buf+i)); 281 break; 282 case 15: 283 o += snprintf(linebuf + o, sizeof(linebuf) - o, 284 "%02x", (unsigned char)*(buf+i)); 285 if (file) 286 fprintf(file, "\t%-47s |%s|\n", linebuf, 287 asciibuf); 288 else 289 syslog(LOG_ERR, "%-47s |%s|\n", linebuf, 290 asciibuf); 291 memset(asciibuf, ' ', sizeof(asciibuf)); 292 asciibuf[sizeof(asciibuf)-1] = '\0'; 293 o = 0; 294 break; 295 case 8: 296 o += snprintf(linebuf + o, sizeof(linebuf) - o, 297 "- %02x", (unsigned char)*(buf+i)); 298 break; 299 default: 300 if (hd_cnt % 2 == 1) 301 o += snprintf(linebuf + o, sizeof(linebuf) - o, 302 "%02x ", (unsigned char)*(buf+i)); 303 else 304 o += snprintf(linebuf + o, sizeof(linebuf) - o, 305 "%02x", (unsigned char)*(buf+i)); 306 break; 307 } 308 hd_cnt++; 309 } 310 if (hd_cnt > 0 && (hd_cnt % 16) != 0) { 311 if (file) 312 fprintf(file, "\t%-47s |%s|\n", linebuf, asciibuf); 313 else 314 syslog(LOG_ERR, "%-47s |%s|\n", linebuf, asciibuf); 315 } 316 if (file) 317 fflush(file); 318 } 319