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