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