xref: /openbsd-src/usr.sbin/npppd/common/debugutil.c (revision 9b9d2a55a62c8e82206c25f94fcc7f4e2765250e)
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