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