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