1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Author: Tatu Ylonen <ylo@cs.hut.fi>
3*0Sstevel@tonic-gate  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4*0Sstevel@tonic-gate  *                    All rights reserved
5*0Sstevel@tonic-gate  *
6*0Sstevel@tonic-gate  * As far as I am concerned, the code I have written for this software
7*0Sstevel@tonic-gate  * can be used freely for any purpose.  Any derived versions of this
8*0Sstevel@tonic-gate  * software must be clearly marked as such, and if the derived work is
9*0Sstevel@tonic-gate  * incompatible with the protocol description in the RFC file, it must be
10*0Sstevel@tonic-gate  * called by a name other than "ssh" or "Secure Shell".
11*0Sstevel@tonic-gate  */
12*0Sstevel@tonic-gate /*
13*0Sstevel@tonic-gate  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
14*0Sstevel@tonic-gate  *
15*0Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
16*0Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
17*0Sstevel@tonic-gate  * are met:
18*0Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
19*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
20*0Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
21*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
22*0Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
23*0Sstevel@tonic-gate  *
24*0Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25*0Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26*0Sstevel@tonic-gate  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27*0Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28*0Sstevel@tonic-gate  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29*0Sstevel@tonic-gate  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30*0Sstevel@tonic-gate  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31*0Sstevel@tonic-gate  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32*0Sstevel@tonic-gate  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33*0Sstevel@tonic-gate  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34*0Sstevel@tonic-gate  */
35*0Sstevel@tonic-gate /*
36*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
37*0Sstevel@tonic-gate  * Use is subject to license terms.
38*0Sstevel@tonic-gate  */
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate #include "includes.h"
41*0Sstevel@tonic-gate RCSID("$OpenBSD: log.c,v 1.24 2002/07/19 15:43:33 markus Exp $");
42*0Sstevel@tonic-gate 
43*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate #include "log.h"
46*0Sstevel@tonic-gate #include "xmalloc.h"
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate #include <syslog.h>
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate static LogLevel log_level = SYSLOG_LEVEL_INFO;
51*0Sstevel@tonic-gate static int log_on_stderr = 1;
52*0Sstevel@tonic-gate static int log_facility = LOG_AUTH;
53*0Sstevel@tonic-gate static char *argv0;
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate extern char *__progname;
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate static const char *log_txt_prefix = "";
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate /* textual representation of log-facilities/levels */
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate static struct {
62*0Sstevel@tonic-gate 	const char *name;
63*0Sstevel@tonic-gate 	SyslogFacility val;
64*0Sstevel@tonic-gate } log_facilities[] = {
65*0Sstevel@tonic-gate 	{ "DAEMON",	SYSLOG_FACILITY_DAEMON },
66*0Sstevel@tonic-gate 	{ "USER",	SYSLOG_FACILITY_USER },
67*0Sstevel@tonic-gate 	{ "AUTH",	SYSLOG_FACILITY_AUTH },
68*0Sstevel@tonic-gate #ifdef LOG_AUTHPRIV
69*0Sstevel@tonic-gate 	{ "AUTHPRIV",	SYSLOG_FACILITY_AUTHPRIV },
70*0Sstevel@tonic-gate #endif
71*0Sstevel@tonic-gate 	{ "LOCAL0",	SYSLOG_FACILITY_LOCAL0 },
72*0Sstevel@tonic-gate 	{ "LOCAL1",	SYSLOG_FACILITY_LOCAL1 },
73*0Sstevel@tonic-gate 	{ "LOCAL2",	SYSLOG_FACILITY_LOCAL2 },
74*0Sstevel@tonic-gate 	{ "LOCAL3",	SYSLOG_FACILITY_LOCAL3 },
75*0Sstevel@tonic-gate 	{ "LOCAL4",	SYSLOG_FACILITY_LOCAL4 },
76*0Sstevel@tonic-gate 	{ "LOCAL5",	SYSLOG_FACILITY_LOCAL5 },
77*0Sstevel@tonic-gate 	{ "LOCAL6",	SYSLOG_FACILITY_LOCAL6 },
78*0Sstevel@tonic-gate 	{ "LOCAL7",	SYSLOG_FACILITY_LOCAL7 },
79*0Sstevel@tonic-gate 	{ NULL,		SYSLOG_FACILITY_NOT_SET }
80*0Sstevel@tonic-gate };
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate static struct {
83*0Sstevel@tonic-gate 	const char *name;
84*0Sstevel@tonic-gate 	LogLevel val;
85*0Sstevel@tonic-gate } log_levels[] =
86*0Sstevel@tonic-gate {
87*0Sstevel@tonic-gate 	{ "QUIET",	SYSLOG_LEVEL_QUIET },
88*0Sstevel@tonic-gate 	{ "FATAL",	SYSLOG_LEVEL_FATAL },
89*0Sstevel@tonic-gate 	{ "ERROR",	SYSLOG_LEVEL_ERROR },
90*0Sstevel@tonic-gate 	{ "NOTICE",	SYSLOG_LEVEL_NOTICE },
91*0Sstevel@tonic-gate 	{ "INFO",	SYSLOG_LEVEL_INFO },
92*0Sstevel@tonic-gate 	{ "VERBOSE",	SYSLOG_LEVEL_VERBOSE },
93*0Sstevel@tonic-gate 	{ "DEBUG",	SYSLOG_LEVEL_DEBUG1 },
94*0Sstevel@tonic-gate 	{ "DEBUG1",	SYSLOG_LEVEL_DEBUG1 },
95*0Sstevel@tonic-gate 	{ "DEBUG2",	SYSLOG_LEVEL_DEBUG2 },
96*0Sstevel@tonic-gate 	{ "DEBUG3",	SYSLOG_LEVEL_DEBUG3 },
97*0Sstevel@tonic-gate 	{ NULL,		SYSLOG_LEVEL_NOT_SET }
98*0Sstevel@tonic-gate };
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate SyslogFacility
101*0Sstevel@tonic-gate log_facility_number(char *name)
102*0Sstevel@tonic-gate {
103*0Sstevel@tonic-gate 	int i;
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate 	if (name != NULL)
106*0Sstevel@tonic-gate 		for (i = 0; log_facilities[i].name; i++)
107*0Sstevel@tonic-gate 			if (strcasecmp(log_facilities[i].name, name) == 0)
108*0Sstevel@tonic-gate 				return log_facilities[i].val;
109*0Sstevel@tonic-gate 	return SYSLOG_FACILITY_NOT_SET;
110*0Sstevel@tonic-gate }
111*0Sstevel@tonic-gate 
112*0Sstevel@tonic-gate LogLevel
113*0Sstevel@tonic-gate log_level_number(char *name)
114*0Sstevel@tonic-gate {
115*0Sstevel@tonic-gate 	int i;
116*0Sstevel@tonic-gate 
117*0Sstevel@tonic-gate 	if (name != NULL)
118*0Sstevel@tonic-gate 		for (i = 0; log_levels[i].name; i++)
119*0Sstevel@tonic-gate 			if (strcasecmp(log_levels[i].name, name) == 0)
120*0Sstevel@tonic-gate 				return log_levels[i].val;
121*0Sstevel@tonic-gate 	return SYSLOG_LEVEL_NOT_SET;
122*0Sstevel@tonic-gate }
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate void
125*0Sstevel@tonic-gate set_log_txt_prefix(const char *txt)
126*0Sstevel@tonic-gate {
127*0Sstevel@tonic-gate 	log_txt_prefix = txt;
128*0Sstevel@tonic-gate }
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate /* Error messages that should be logged. */
131*0Sstevel@tonic-gate 
132*0Sstevel@tonic-gate void
133*0Sstevel@tonic-gate error(const char *fmt,...)
134*0Sstevel@tonic-gate {
135*0Sstevel@tonic-gate 	va_list args;
136*0Sstevel@tonic-gate 
137*0Sstevel@tonic-gate 	va_start(args, fmt);
138*0Sstevel@tonic-gate 	do_log(SYSLOG_LEVEL_ERROR, fmt, args);
139*0Sstevel@tonic-gate 	va_end(args);
140*0Sstevel@tonic-gate }
141*0Sstevel@tonic-gate 
142*0Sstevel@tonic-gate void
143*0Sstevel@tonic-gate notice(const char *fmt,...)
144*0Sstevel@tonic-gate {
145*0Sstevel@tonic-gate 	va_list args;
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate 	va_start(args, fmt);
148*0Sstevel@tonic-gate 	do_log(SYSLOG_LEVEL_NOTICE, fmt, args);
149*0Sstevel@tonic-gate 	va_end(args);
150*0Sstevel@tonic-gate }
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate /* Log this message (information that usually should go to the log). */
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate void
155*0Sstevel@tonic-gate log(const char *fmt,...)
156*0Sstevel@tonic-gate {
157*0Sstevel@tonic-gate 	va_list args;
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate 	va_start(args, fmt);
160*0Sstevel@tonic-gate 	do_log(SYSLOG_LEVEL_INFO, fmt, args);
161*0Sstevel@tonic-gate 	va_end(args);
162*0Sstevel@tonic-gate }
163*0Sstevel@tonic-gate 
164*0Sstevel@tonic-gate /* More detailed messages (information that does not need to go to the log). */
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate void
167*0Sstevel@tonic-gate verbose(const char *fmt,...)
168*0Sstevel@tonic-gate {
169*0Sstevel@tonic-gate 	va_list args;
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate 	va_start(args, fmt);
172*0Sstevel@tonic-gate 	do_log(SYSLOG_LEVEL_VERBOSE, fmt, args);
173*0Sstevel@tonic-gate 	va_end(args);
174*0Sstevel@tonic-gate }
175*0Sstevel@tonic-gate 
176*0Sstevel@tonic-gate /* Debugging messages that should not be logged during normal operation. */
177*0Sstevel@tonic-gate 
178*0Sstevel@tonic-gate void
179*0Sstevel@tonic-gate debug(const char *fmt,...)
180*0Sstevel@tonic-gate {
181*0Sstevel@tonic-gate 	va_list args;
182*0Sstevel@tonic-gate 
183*0Sstevel@tonic-gate 	va_start(args, fmt);
184*0Sstevel@tonic-gate 	do_log(SYSLOG_LEVEL_DEBUG1, fmt, args);
185*0Sstevel@tonic-gate 	va_end(args);
186*0Sstevel@tonic-gate }
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate void
189*0Sstevel@tonic-gate debug2(const char *fmt,...)
190*0Sstevel@tonic-gate {
191*0Sstevel@tonic-gate 	va_list args;
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate 	va_start(args, fmt);
194*0Sstevel@tonic-gate 	do_log(SYSLOG_LEVEL_DEBUG2, fmt, args);
195*0Sstevel@tonic-gate 	va_end(args);
196*0Sstevel@tonic-gate }
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate void
199*0Sstevel@tonic-gate debug3(const char *fmt,...)
200*0Sstevel@tonic-gate {
201*0Sstevel@tonic-gate 	va_list args;
202*0Sstevel@tonic-gate 
203*0Sstevel@tonic-gate 	va_start(args, fmt);
204*0Sstevel@tonic-gate 	do_log(SYSLOG_LEVEL_DEBUG3, fmt, args);
205*0Sstevel@tonic-gate 	va_end(args);
206*0Sstevel@tonic-gate }
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate /* Fatal cleanup */
209*0Sstevel@tonic-gate 
210*0Sstevel@tonic-gate struct fatal_cleanup {
211*0Sstevel@tonic-gate 	struct fatal_cleanup *next;
212*0Sstevel@tonic-gate 	void (*proc) (void *);
213*0Sstevel@tonic-gate 	void *context;
214*0Sstevel@tonic-gate };
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate static struct fatal_cleanup *fatal_cleanups = NULL;
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate /* Registers a cleanup function to be called by fatal() before exiting. */
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate void
221*0Sstevel@tonic-gate fatal_add_cleanup(void (*proc) (void *), void *context)
222*0Sstevel@tonic-gate {
223*0Sstevel@tonic-gate 	struct fatal_cleanup *cu;
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate 	cu = xmalloc(sizeof(*cu));
226*0Sstevel@tonic-gate 	cu->proc = proc;
227*0Sstevel@tonic-gate 	cu->context = context;
228*0Sstevel@tonic-gate 	cu->next = fatal_cleanups;
229*0Sstevel@tonic-gate 	fatal_cleanups = cu;
230*0Sstevel@tonic-gate }
231*0Sstevel@tonic-gate 
232*0Sstevel@tonic-gate /* Removes a cleanup frunction to be called at fatal(). */
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate void
235*0Sstevel@tonic-gate fatal_remove_cleanup(void (*proc) (void *context), void *context)
236*0Sstevel@tonic-gate {
237*0Sstevel@tonic-gate 	struct fatal_cleanup **cup, *cu;
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate 	for (cup = &fatal_cleanups; *cup; cup = &cu->next) {
240*0Sstevel@tonic-gate 		cu = *cup;
241*0Sstevel@tonic-gate 		if (cu->proc == proc && cu->context == context) {
242*0Sstevel@tonic-gate 			*cup = cu->next;
243*0Sstevel@tonic-gate 			xfree(cu);
244*0Sstevel@tonic-gate 			return;
245*0Sstevel@tonic-gate 		}
246*0Sstevel@tonic-gate 	}
247*0Sstevel@tonic-gate 	debug3("fatal_remove_cleanup: no such cleanup function: 0x%lx 0x%lx",
248*0Sstevel@tonic-gate 	    (u_long) proc, (u_long) context);
249*0Sstevel@tonic-gate }
250*0Sstevel@tonic-gate 
251*0Sstevel@tonic-gate /* Remove all cleanups, to be called after fork() */
252*0Sstevel@tonic-gate void
253*0Sstevel@tonic-gate fatal_remove_all_cleanups(void)
254*0Sstevel@tonic-gate {
255*0Sstevel@tonic-gate 	struct fatal_cleanup *cu, *next_cu;
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate 	for (cu = fatal_cleanups; cu; cu = next_cu) {
258*0Sstevel@tonic-gate 		next_cu = cu->next;
259*0Sstevel@tonic-gate 		xfree(cu);
260*0Sstevel@tonic-gate 	}
261*0Sstevel@tonic-gate 
262*0Sstevel@tonic-gate 	fatal_cleanups = NULL;
263*0Sstevel@tonic-gate }
264*0Sstevel@tonic-gate 
265*0Sstevel@tonic-gate /* Cleanup and exit */
266*0Sstevel@tonic-gate void
267*0Sstevel@tonic-gate fatal_cleanup(void)
268*0Sstevel@tonic-gate {
269*0Sstevel@tonic-gate 	struct fatal_cleanup *cu, *next_cu;
270*0Sstevel@tonic-gate 	static int called = 0;
271*0Sstevel@tonic-gate 
272*0Sstevel@tonic-gate 	if (called)
273*0Sstevel@tonic-gate 		exit(255);
274*0Sstevel@tonic-gate 	called = 1;
275*0Sstevel@tonic-gate 	/* Call cleanup functions. */
276*0Sstevel@tonic-gate 	for (cu = fatal_cleanups; cu; cu = next_cu) {
277*0Sstevel@tonic-gate 		next_cu = cu->next;
278*0Sstevel@tonic-gate 		debug("Calling cleanup 0x%lx(0x%lx)",
279*0Sstevel@tonic-gate 		    (u_long) cu->proc, (u_long) cu->context);
280*0Sstevel@tonic-gate 		(*cu->proc) (cu->context);
281*0Sstevel@tonic-gate 	}
282*0Sstevel@tonic-gate 	exit(255);
283*0Sstevel@tonic-gate }
284*0Sstevel@tonic-gate 
285*0Sstevel@tonic-gate 
286*0Sstevel@tonic-gate /*
287*0Sstevel@tonic-gate  * Initialize the log.
288*0Sstevel@tonic-gate  */
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate void
291*0Sstevel@tonic-gate log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr)
292*0Sstevel@tonic-gate {
293*0Sstevel@tonic-gate 	argv0 = av0;
294*0Sstevel@tonic-gate 
295*0Sstevel@tonic-gate 	switch (level) {
296*0Sstevel@tonic-gate 	case SYSLOG_LEVEL_QUIET:
297*0Sstevel@tonic-gate 	case SYSLOG_LEVEL_FATAL:
298*0Sstevel@tonic-gate 	case SYSLOG_LEVEL_ERROR:
299*0Sstevel@tonic-gate 	case SYSLOG_LEVEL_NOTICE:
300*0Sstevel@tonic-gate 	case SYSLOG_LEVEL_INFO:
301*0Sstevel@tonic-gate 	case SYSLOG_LEVEL_VERBOSE:
302*0Sstevel@tonic-gate 	case SYSLOG_LEVEL_DEBUG1:
303*0Sstevel@tonic-gate 	case SYSLOG_LEVEL_DEBUG2:
304*0Sstevel@tonic-gate 	case SYSLOG_LEVEL_DEBUG3:
305*0Sstevel@tonic-gate 		log_level = level;
306*0Sstevel@tonic-gate 		break;
307*0Sstevel@tonic-gate 	default:
308*0Sstevel@tonic-gate 		fprintf(stderr, "Unrecognized internal syslog level code %d\n",
309*0Sstevel@tonic-gate 		    (int) level);
310*0Sstevel@tonic-gate 		exit(1);
311*0Sstevel@tonic-gate 	}
312*0Sstevel@tonic-gate 
313*0Sstevel@tonic-gate 	log_on_stderr = on_stderr;
314*0Sstevel@tonic-gate 	if (on_stderr)
315*0Sstevel@tonic-gate 		return;
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate 	switch (facility) {
318*0Sstevel@tonic-gate 	case SYSLOG_FACILITY_DAEMON:
319*0Sstevel@tonic-gate 		log_facility = LOG_DAEMON;
320*0Sstevel@tonic-gate 		break;
321*0Sstevel@tonic-gate 	case SYSLOG_FACILITY_USER:
322*0Sstevel@tonic-gate 		log_facility = LOG_USER;
323*0Sstevel@tonic-gate 		break;
324*0Sstevel@tonic-gate 	case SYSLOG_FACILITY_AUTH:
325*0Sstevel@tonic-gate 		log_facility = LOG_AUTH;
326*0Sstevel@tonic-gate 		break;
327*0Sstevel@tonic-gate #ifdef LOG_AUTHPRIV
328*0Sstevel@tonic-gate 	case SYSLOG_FACILITY_AUTHPRIV:
329*0Sstevel@tonic-gate 		log_facility = LOG_AUTHPRIV;
330*0Sstevel@tonic-gate 		break;
331*0Sstevel@tonic-gate #endif
332*0Sstevel@tonic-gate 	case SYSLOG_FACILITY_LOCAL0:
333*0Sstevel@tonic-gate 		log_facility = LOG_LOCAL0;
334*0Sstevel@tonic-gate 		break;
335*0Sstevel@tonic-gate 	case SYSLOG_FACILITY_LOCAL1:
336*0Sstevel@tonic-gate 		log_facility = LOG_LOCAL1;
337*0Sstevel@tonic-gate 		break;
338*0Sstevel@tonic-gate 	case SYSLOG_FACILITY_LOCAL2:
339*0Sstevel@tonic-gate 		log_facility = LOG_LOCAL2;
340*0Sstevel@tonic-gate 		break;
341*0Sstevel@tonic-gate 	case SYSLOG_FACILITY_LOCAL3:
342*0Sstevel@tonic-gate 		log_facility = LOG_LOCAL3;
343*0Sstevel@tonic-gate 		break;
344*0Sstevel@tonic-gate 	case SYSLOG_FACILITY_LOCAL4:
345*0Sstevel@tonic-gate 		log_facility = LOG_LOCAL4;
346*0Sstevel@tonic-gate 		break;
347*0Sstevel@tonic-gate 	case SYSLOG_FACILITY_LOCAL5:
348*0Sstevel@tonic-gate 		log_facility = LOG_LOCAL5;
349*0Sstevel@tonic-gate 		break;
350*0Sstevel@tonic-gate 	case SYSLOG_FACILITY_LOCAL6:
351*0Sstevel@tonic-gate 		log_facility = LOG_LOCAL6;
352*0Sstevel@tonic-gate 		break;
353*0Sstevel@tonic-gate 	case SYSLOG_FACILITY_LOCAL7:
354*0Sstevel@tonic-gate 		log_facility = LOG_LOCAL7;
355*0Sstevel@tonic-gate 		break;
356*0Sstevel@tonic-gate 	default:
357*0Sstevel@tonic-gate 		fprintf(stderr,
358*0Sstevel@tonic-gate 		    "Unrecognized internal syslog facility code %d\n",
359*0Sstevel@tonic-gate 		    (int) facility);
360*0Sstevel@tonic-gate 		exit(1);
361*0Sstevel@tonic-gate 	}
362*0Sstevel@tonic-gate }
363*0Sstevel@tonic-gate 
364*0Sstevel@tonic-gate #define MSGBUFSIZ 1024
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate /* PRINTFLIKE2 */
367*0Sstevel@tonic-gate void
368*0Sstevel@tonic-gate do_log(LogLevel level, const char *fmt, va_list args)
369*0Sstevel@tonic-gate {
370*0Sstevel@tonic-gate 	char msgbuf[MSGBUFSIZ];
371*0Sstevel@tonic-gate 	char fmtbuf[MSGBUFSIZ];
372*0Sstevel@tonic-gate 	char *txt = NULL;
373*0Sstevel@tonic-gate 	int pri = LOG_INFO;
374*0Sstevel@tonic-gate 	int do_gettext = log_on_stderr; /*
375*0Sstevel@tonic-gate 					 * Localize user messages - not
376*0Sstevel@tonic-gate 					 * syslog()ed messages.
377*0Sstevel@tonic-gate 					 */
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate 	if (level > log_level)
380*0Sstevel@tonic-gate 		return;
381*0Sstevel@tonic-gate 
382*0Sstevel@tonic-gate 	switch (level) {
383*0Sstevel@tonic-gate 	case SYSLOG_LEVEL_FATAL:
384*0Sstevel@tonic-gate 		if (!log_on_stderr)
385*0Sstevel@tonic-gate 			txt = "fatal";
386*0Sstevel@tonic-gate 		pri = LOG_CRIT;
387*0Sstevel@tonic-gate 		break;
388*0Sstevel@tonic-gate 	case SYSLOG_LEVEL_ERROR:
389*0Sstevel@tonic-gate 		if (!log_on_stderr)
390*0Sstevel@tonic-gate 			txt = "error";
391*0Sstevel@tonic-gate 		pri = LOG_ERR;
392*0Sstevel@tonic-gate 		break;
393*0Sstevel@tonic-gate 	case SYSLOG_LEVEL_NOTICE:
394*0Sstevel@tonic-gate 		pri = LOG_NOTICE;
395*0Sstevel@tonic-gate 		break;
396*0Sstevel@tonic-gate 	case SYSLOG_LEVEL_INFO:
397*0Sstevel@tonic-gate 		pri = LOG_INFO;
398*0Sstevel@tonic-gate 		break;
399*0Sstevel@tonic-gate 	case SYSLOG_LEVEL_VERBOSE:
400*0Sstevel@tonic-gate 		pri = LOG_INFO;
401*0Sstevel@tonic-gate 		break;
402*0Sstevel@tonic-gate 	case SYSLOG_LEVEL_DEBUG1:
403*0Sstevel@tonic-gate 		txt = "debug1";
404*0Sstevel@tonic-gate 		pri = LOG_DEBUG;
405*0Sstevel@tonic-gate 		/*
406*0Sstevel@tonic-gate 		 * Don't localize debug messages - such are not intended
407*0Sstevel@tonic-gate 		 * for users but for support staff whose preferred
408*0Sstevel@tonic-gate 		 * language is unknown, therefore we default to the
409*0Sstevel@tonic-gate 		 * language used in the source code: English.
410*0Sstevel@tonic-gate 		 */
411*0Sstevel@tonic-gate 		do_gettext = 0;
412*0Sstevel@tonic-gate 		break;
413*0Sstevel@tonic-gate 	case SYSLOG_LEVEL_DEBUG2:
414*0Sstevel@tonic-gate 		txt = "debug2";
415*0Sstevel@tonic-gate 		pri = LOG_DEBUG;
416*0Sstevel@tonic-gate 		do_gettext = 0;	    /* Don't localize debug messages. */
417*0Sstevel@tonic-gate 		break;
418*0Sstevel@tonic-gate 	case SYSLOG_LEVEL_DEBUG3:
419*0Sstevel@tonic-gate 		txt = "debug3";
420*0Sstevel@tonic-gate 		pri = LOG_DEBUG;
421*0Sstevel@tonic-gate 		do_gettext = 0;	    /* Don't localize debug messages. */
422*0Sstevel@tonic-gate 		break;
423*0Sstevel@tonic-gate 	default:
424*0Sstevel@tonic-gate 		txt = "internal error";
425*0Sstevel@tonic-gate 		pri = LOG_ERR;
426*0Sstevel@tonic-gate 		break;
427*0Sstevel@tonic-gate 	}
428*0Sstevel@tonic-gate 	if (txt != NULL) {
429*0Sstevel@tonic-gate 		snprintf(fmtbuf, sizeof(fmtbuf), "%s%s: %s", log_txt_prefix,
430*0Sstevel@tonic-gate 			 do_gettext ? gettext(txt) : txt,
431*0Sstevel@tonic-gate 			 do_gettext ? gettext(fmt) : fmt);
432*0Sstevel@tonic-gate 		vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args);
433*0Sstevel@tonic-gate 	} else {
434*0Sstevel@tonic-gate 		vsnprintf(msgbuf, sizeof(msgbuf),
435*0Sstevel@tonic-gate 			  do_gettext ? gettext(fmt) : fmt,
436*0Sstevel@tonic-gate 			  args);
437*0Sstevel@tonic-gate 	}
438*0Sstevel@tonic-gate 	if (log_on_stderr) {
439*0Sstevel@tonic-gate 		fprintf(stderr, "%s\r\n", msgbuf);
440*0Sstevel@tonic-gate 	} else {
441*0Sstevel@tonic-gate 		openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility);
442*0Sstevel@tonic-gate 		syslog(pri, "%.500s", msgbuf);
443*0Sstevel@tonic-gate 		closelog();
444*0Sstevel@tonic-gate 	}
445*0Sstevel@tonic-gate }
446