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