1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate * CDDL HEADER START
3*0Sstevel@tonic-gate *
4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
7*0Sstevel@tonic-gate * with the License.
8*0Sstevel@tonic-gate *
9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate * and limitations under the License.
13*0Sstevel@tonic-gate *
14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate *
20*0Sstevel@tonic-gate * CDDL HEADER END
21*0Sstevel@tonic-gate */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate * PPPoE Server-mode daemon log file support.
24*0Sstevel@tonic-gate *
25*0Sstevel@tonic-gate * Copyright (c) 2000-2001 by Sun Microsystems, Inc.
26*0Sstevel@tonic-gate * All rights reserved.
27*0Sstevel@tonic-gate */
28*0Sstevel@tonic-gate
29*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
30*0Sstevel@tonic-gate
31*0Sstevel@tonic-gate #include <stdio.h>
32*0Sstevel@tonic-gate #include <unistd.h>
33*0Sstevel@tonic-gate #include <stdarg.h>
34*0Sstevel@tonic-gate #include <alloca.h>
35*0Sstevel@tonic-gate #include <errno.h>
36*0Sstevel@tonic-gate #include <fcntl.h>
37*0Sstevel@tonic-gate #include <string.h>
38*0Sstevel@tonic-gate #include <syslog.h>
39*0Sstevel@tonic-gate #include <assert.h>
40*0Sstevel@tonic-gate #include <sys/types.h>
41*0Sstevel@tonic-gate
42*0Sstevel@tonic-gate #include "common.h"
43*0Sstevel@tonic-gate #include "logging.h"
44*0Sstevel@tonic-gate
45*0Sstevel@tonic-gate /* Not all functions are used by all applications. Let lint know this. */
46*0Sstevel@tonic-gate /*LINTLIBRARY*/
47*0Sstevel@tonic-gate
48*0Sstevel@tonic-gate const char *prog_name = "none"; /* Subsystem name for syslog */
49*0Sstevel@tonic-gate int log_level; /* Higher number for more detail. */
50*0Sstevel@tonic-gate
51*0Sstevel@tonic-gate static int curlogfd = -1; /* Current log file */
52*0Sstevel@tonic-gate static const char *curfname; /* Name of current log file */
53*0Sstevel@tonic-gate static const char *stderr_name = "stderr";
54*0Sstevel@tonic-gate
55*0Sstevel@tonic-gate #define SMALLSTR 254 /* Don't allocate for most strings. */
56*0Sstevel@tonic-gate
57*0Sstevel@tonic-gate /*
58*0Sstevel@tonic-gate * Returns -1 on error (with errno set), 0 on blocked write (file
59*0Sstevel@tonic-gate * system full), or N (buffer length) on success.
60*0Sstevel@tonic-gate */
61*0Sstevel@tonic-gate static int
dowrite(int fd,const void * buf,int len)62*0Sstevel@tonic-gate dowrite(int fd, const void *buf, int len)
63*0Sstevel@tonic-gate {
64*0Sstevel@tonic-gate int retv;
65*0Sstevel@tonic-gate const uint8_t *bp = (uint8_t *)buf;
66*0Sstevel@tonic-gate
67*0Sstevel@tonic-gate while (len > 0) {
68*0Sstevel@tonic-gate retv = write(fd, bp, len);
69*0Sstevel@tonic-gate if (retv == 0) {
70*0Sstevel@tonic-gate break;
71*0Sstevel@tonic-gate }
72*0Sstevel@tonic-gate if (retv == -1) {
73*0Sstevel@tonic-gate if (errno != EINTR)
74*0Sstevel@tonic-gate break;
75*0Sstevel@tonic-gate } else {
76*0Sstevel@tonic-gate bp += retv;
77*0Sstevel@tonic-gate len -= retv;
78*0Sstevel@tonic-gate }
79*0Sstevel@tonic-gate }
80*0Sstevel@tonic-gate if (len <= 0)
81*0Sstevel@tonic-gate return (bp - (uint8_t *)buf);
82*0Sstevel@tonic-gate return (retv);
83*0Sstevel@tonic-gate }
84*0Sstevel@tonic-gate
85*0Sstevel@tonic-gate /* A close that avoids closing stderr */
86*0Sstevel@tonic-gate static int
doclose(void)87*0Sstevel@tonic-gate doclose(void)
88*0Sstevel@tonic-gate {
89*0Sstevel@tonic-gate int retval = 0;
90*0Sstevel@tonic-gate
91*0Sstevel@tonic-gate if (curlogfd == -1)
92*0Sstevel@tonic-gate return (0);
93*0Sstevel@tonic-gate if ((curlogfd != STDERR_FILENO) || (curfname != stderr_name))
94*0Sstevel@tonic-gate retval = close(curlogfd);
95*0Sstevel@tonic-gate curlogfd = -1;
96*0Sstevel@tonic-gate return (retval);
97*0Sstevel@tonic-gate }
98*0Sstevel@tonic-gate
99*0Sstevel@tonic-gate /*
100*0Sstevel@tonic-gate * Log levels are 0 for no messages, 1 for errors, 2 for warnings, 3
101*0Sstevel@tonic-gate * for informational messages, and 4 for debugging messages.
102*0Sstevel@tonic-gate */
103*0Sstevel@tonic-gate static void
vlogat(int loglev,const char * fmt,va_list args)104*0Sstevel@tonic-gate vlogat(int loglev, const char *fmt, va_list args)
105*0Sstevel@tonic-gate {
106*0Sstevel@tonic-gate char timbuf[64];
107*0Sstevel@tonic-gate char regbuf[SMALLSTR+2];
108*0Sstevel@tonic-gate char *ostr;
109*0Sstevel@tonic-gate int timlen;
110*0Sstevel@tonic-gate int slen;
111*0Sstevel@tonic-gate char *nstr;
112*0Sstevel@tonic-gate int err1, err2;
113*0Sstevel@tonic-gate int sloglev;
114*0Sstevel@tonic-gate int retv;
115*0Sstevel@tonic-gate va_list args2;
116*0Sstevel@tonic-gate static int xlate_loglev[] = {
117*0Sstevel@tonic-gate LOG_ERR, LOG_WARNING, LOG_INFO, LOG_DEBUG
118*0Sstevel@tonic-gate };
119*0Sstevel@tonic-gate
120*0Sstevel@tonic-gate if (loglev >= log_level)
121*0Sstevel@tonic-gate return;
122*0Sstevel@tonic-gate
123*0Sstevel@tonic-gate timbuf[0] = '\0';
124*0Sstevel@tonic-gate timlen = 0;
125*0Sstevel@tonic-gate if (curlogfd >= 0) {
126*0Sstevel@tonic-gate time_t now = time(NULL);
127*0Sstevel@tonic-gate
128*0Sstevel@tonic-gate /*
129*0Sstevel@tonic-gate * Form a time/date string for file (non-syslog) logging.
130*0Sstevel@tonic-gate * Caution: string broken in two so that SCCS doesn't mangle
131*0Sstevel@tonic-gate * the %-T-% sequence.
132*0Sstevel@tonic-gate */
133*0Sstevel@tonic-gate timlen = strftime(timbuf, sizeof (timbuf), "%Y/%m/%d %T"
134*0Sstevel@tonic-gate "%Z: ", localtime(&now));
135*0Sstevel@tonic-gate }
136*0Sstevel@tonic-gate
137*0Sstevel@tonic-gate /* Try formatting once into the small buffer. */
138*0Sstevel@tonic-gate va_copy(args2, args);
139*0Sstevel@tonic-gate slen = vsnprintf(regbuf, SMALLSTR, fmt, args);
140*0Sstevel@tonic-gate if (slen < SMALLSTR) {
141*0Sstevel@tonic-gate ostr = regbuf;
142*0Sstevel@tonic-gate } else {
143*0Sstevel@tonic-gate /*
144*0Sstevel@tonic-gate * Length returned by vsnprintf doesn't include null,
145*0Sstevel@tonic-gate * and may also be missing a terminating \n.
146*0Sstevel@tonic-gate */
147*0Sstevel@tonic-gate ostr = alloca(slen + 2);
148*0Sstevel@tonic-gate slen = vsnprintf(ostr, slen + 1, fmt, args2);
149*0Sstevel@tonic-gate }
150*0Sstevel@tonic-gate
151*0Sstevel@tonic-gate /* Don't bother logging empty lines. */
152*0Sstevel@tonic-gate if (slen <= 0)
153*0Sstevel@tonic-gate return;
154*0Sstevel@tonic-gate
155*0Sstevel@tonic-gate /* Tack on a \n if needed. */
156*0Sstevel@tonic-gate if (ostr[slen - 1] != '\n') {
157*0Sstevel@tonic-gate ostr[slen++] = '\n';
158*0Sstevel@tonic-gate ostr[slen] = '\0';
159*0Sstevel@tonic-gate }
160*0Sstevel@tonic-gate
161*0Sstevel@tonic-gate /* Translate our log levels into syslog standard values */
162*0Sstevel@tonic-gate assert(loglev >= 0 && loglev < Dim(xlate_loglev));
163*0Sstevel@tonic-gate sloglev = xlate_loglev[loglev];
164*0Sstevel@tonic-gate
165*0Sstevel@tonic-gate /* Log each line separately */
166*0Sstevel@tonic-gate for (; *ostr != '\0'; ostr = nstr + 1) {
167*0Sstevel@tonic-gate nstr = strchr(ostr, '\n');
168*0Sstevel@tonic-gate
169*0Sstevel@tonic-gate /* Ignore zero-length lines. */
170*0Sstevel@tonic-gate if (nstr == ostr)
171*0Sstevel@tonic-gate continue;
172*0Sstevel@tonic-gate
173*0Sstevel@tonic-gate slen = nstr - ostr + 1;
174*0Sstevel@tonic-gate
175*0Sstevel@tonic-gate /*
176*0Sstevel@tonic-gate * If we're supposed to be logging to a file, then try
177*0Sstevel@tonic-gate * that first. Ditch the file and revert to syslog if
178*0Sstevel@tonic-gate * any errors occur.
179*0Sstevel@tonic-gate */
180*0Sstevel@tonic-gate if (curlogfd >= 0) {
181*0Sstevel@tonic-gate if ((retv = dowrite(curlogfd, timbuf, timlen)) > 0)
182*0Sstevel@tonic-gate retv = dowrite(curlogfd, ostr, slen);
183*0Sstevel@tonic-gate
184*0Sstevel@tonic-gate /*
185*0Sstevel@tonic-gate * If we've successfully logged this line,
186*0Sstevel@tonic-gate * then go do the next one.
187*0Sstevel@tonic-gate */
188*0Sstevel@tonic-gate if (retv > 0)
189*0Sstevel@tonic-gate continue;
190*0Sstevel@tonic-gate
191*0Sstevel@tonic-gate /* Save errno (if any) and close log file */
192*0Sstevel@tonic-gate err1 = errno;
193*0Sstevel@tonic-gate if (doclose() == -1)
194*0Sstevel@tonic-gate err2 = errno;
195*0Sstevel@tonic-gate else
196*0Sstevel@tonic-gate err2 = 0;
197*0Sstevel@tonic-gate
198*0Sstevel@tonic-gate /*
199*0Sstevel@tonic-gate * Recursion is safe here because we cleared
200*0Sstevel@tonic-gate * out curlogfd above.
201*0Sstevel@tonic-gate */
202*0Sstevel@tonic-gate if (retv == -1)
203*0Sstevel@tonic-gate logerr("write log %s: %s", curfname,
204*0Sstevel@tonic-gate mystrerror(err1));
205*0Sstevel@tonic-gate else
206*0Sstevel@tonic-gate logerr("cannot write %s", curfname);
207*0Sstevel@tonic-gate if (err2 == 0)
208*0Sstevel@tonic-gate logdbg("closed log %s", curfname);
209*0Sstevel@tonic-gate else
210*0Sstevel@tonic-gate logerr("closing log %s: %s", curfname,
211*0Sstevel@tonic-gate mystrerror(err2));
212*0Sstevel@tonic-gate }
213*0Sstevel@tonic-gate syslog(sloglev, "%.*s", slen, ostr);
214*0Sstevel@tonic-gate }
215*0Sstevel@tonic-gate }
216*0Sstevel@tonic-gate
217*0Sstevel@tonic-gate /* Log at debug level */
218*0Sstevel@tonic-gate void
logdbg(const char * fmt,...)219*0Sstevel@tonic-gate logdbg(const char *fmt, ...)
220*0Sstevel@tonic-gate {
221*0Sstevel@tonic-gate va_list args;
222*0Sstevel@tonic-gate
223*0Sstevel@tonic-gate va_start(args, fmt);
224*0Sstevel@tonic-gate vlogat(LOGLVL_DBG, fmt, args);
225*0Sstevel@tonic-gate va_end(args);
226*0Sstevel@tonic-gate }
227*0Sstevel@tonic-gate
228*0Sstevel@tonic-gate /* Log informational messages */
229*0Sstevel@tonic-gate void
loginfo(const char * fmt,...)230*0Sstevel@tonic-gate loginfo(const char *fmt, ...)
231*0Sstevel@tonic-gate {
232*0Sstevel@tonic-gate va_list args;
233*0Sstevel@tonic-gate
234*0Sstevel@tonic-gate va_start(args, fmt);
235*0Sstevel@tonic-gate vlogat(LOGLVL_INFO, fmt, args);
236*0Sstevel@tonic-gate va_end(args);
237*0Sstevel@tonic-gate }
238*0Sstevel@tonic-gate
239*0Sstevel@tonic-gate /* Log warning messages */
240*0Sstevel@tonic-gate void
logwarn(const char * fmt,...)241*0Sstevel@tonic-gate logwarn(const char *fmt, ...)
242*0Sstevel@tonic-gate {
243*0Sstevel@tonic-gate va_list args;
244*0Sstevel@tonic-gate
245*0Sstevel@tonic-gate va_start(args, fmt);
246*0Sstevel@tonic-gate vlogat(LOGLVL_WARN, fmt, args);
247*0Sstevel@tonic-gate va_end(args);
248*0Sstevel@tonic-gate }
249*0Sstevel@tonic-gate
250*0Sstevel@tonic-gate /* Log error messages */
251*0Sstevel@tonic-gate void
logerr(const char * fmt,...)252*0Sstevel@tonic-gate logerr(const char *fmt, ...)
253*0Sstevel@tonic-gate {
254*0Sstevel@tonic-gate va_list args;
255*0Sstevel@tonic-gate
256*0Sstevel@tonic-gate va_start(args, fmt);
257*0Sstevel@tonic-gate vlogat(LOGLVL_ERR, fmt, args);
258*0Sstevel@tonic-gate va_end(args);
259*0Sstevel@tonic-gate }
260*0Sstevel@tonic-gate
261*0Sstevel@tonic-gate /* Log a strerror message */
262*0Sstevel@tonic-gate void
logstrerror(const char * emsg)263*0Sstevel@tonic-gate logstrerror(const char *emsg)
264*0Sstevel@tonic-gate {
265*0Sstevel@tonic-gate logerr("%s: %s\n", emsg, mystrerror(errno));
266*0Sstevel@tonic-gate }
267*0Sstevel@tonic-gate
268*0Sstevel@tonic-gate void
log_to_stderr(int dbglvl)269*0Sstevel@tonic-gate log_to_stderr(int dbglvl)
270*0Sstevel@tonic-gate {
271*0Sstevel@tonic-gate log_level = dbglvl;
272*0Sstevel@tonic-gate if (curlogfd >= 0)
273*0Sstevel@tonic-gate close_log_files();
274*0Sstevel@tonic-gate curlogfd = STDERR_FILENO;
275*0Sstevel@tonic-gate curfname = stderr_name;
276*0Sstevel@tonic-gate }
277*0Sstevel@tonic-gate
278*0Sstevel@tonic-gate /*
279*0Sstevel@tonic-gate * Set indicated log file and debug level.
280*0Sstevel@tonic-gate */
281*0Sstevel@tonic-gate void
log_for_service(const char * fname,int dbglvl)282*0Sstevel@tonic-gate log_for_service(const char *fname, int dbglvl)
283*0Sstevel@tonic-gate {
284*0Sstevel@tonic-gate int err1, err2;
285*0Sstevel@tonic-gate boolean_t closed;
286*0Sstevel@tonic-gate
287*0Sstevel@tonic-gate log_level = dbglvl;
288*0Sstevel@tonic-gate if (fname != NULL &&
289*0Sstevel@tonic-gate (*fname == '\0' || strcasecmp(fname, "syslog") == 0))
290*0Sstevel@tonic-gate fname = NULL;
291*0Sstevel@tonic-gate if (fname == NULL && curfname == NULL)
292*0Sstevel@tonic-gate return;
293*0Sstevel@tonic-gate err1 = err2 = 0;
294*0Sstevel@tonic-gate closed = B_FALSE;
295*0Sstevel@tonic-gate if (curlogfd >= 0) {
296*0Sstevel@tonic-gate if (fname == curfname ||
297*0Sstevel@tonic-gate (fname != NULL && strcmp(fname, curfname) == 0)) {
298*0Sstevel@tonic-gate curfname = fname;
299*0Sstevel@tonic-gate return;
300*0Sstevel@tonic-gate }
301*0Sstevel@tonic-gate if (doclose() == -1)
302*0Sstevel@tonic-gate err1 = errno;
303*0Sstevel@tonic-gate closed = B_TRUE;
304*0Sstevel@tonic-gate }
305*0Sstevel@tonic-gate if (fname != NULL) {
306*0Sstevel@tonic-gate curlogfd = open(fname, O_WRONLY|O_APPEND|O_CREAT, 0600);
307*0Sstevel@tonic-gate if (curlogfd == -1)
308*0Sstevel@tonic-gate err2 = errno;
309*0Sstevel@tonic-gate }
310*0Sstevel@tonic-gate if (closed) {
311*0Sstevel@tonic-gate if (err1 == 0)
312*0Sstevel@tonic-gate logdbg("closed log %s", curfname);
313*0Sstevel@tonic-gate else
314*0Sstevel@tonic-gate logerr("closing log %s: %s", curfname,
315*0Sstevel@tonic-gate mystrerror(err1));
316*0Sstevel@tonic-gate }
317*0Sstevel@tonic-gate if (fname != NULL) {
318*0Sstevel@tonic-gate if (err2 == 0)
319*0Sstevel@tonic-gate logdbg("opened log %s", fname);
320*0Sstevel@tonic-gate else
321*0Sstevel@tonic-gate logerr("opening log %s: %s", fname, mystrerror(err2));
322*0Sstevel@tonic-gate }
323*0Sstevel@tonic-gate curfname = fname;
324*0Sstevel@tonic-gate }
325*0Sstevel@tonic-gate
326*0Sstevel@tonic-gate /*
327*0Sstevel@tonic-gate * Close any open log file. This is used for SIGHUP (to support log
328*0Sstevel@tonic-gate * file rotation) and when execing.
329*0Sstevel@tonic-gate */
330*0Sstevel@tonic-gate void
close_log_files(void)331*0Sstevel@tonic-gate close_log_files(void)
332*0Sstevel@tonic-gate {
333*0Sstevel@tonic-gate int err = 0;
334*0Sstevel@tonic-gate
335*0Sstevel@tonic-gate if (curlogfd >= 0) {
336*0Sstevel@tonic-gate if (doclose() == -1)
337*0Sstevel@tonic-gate err = errno;
338*0Sstevel@tonic-gate if (err == 0)
339*0Sstevel@tonic-gate logdbg("closed log %s", curfname);
340*0Sstevel@tonic-gate else
341*0Sstevel@tonic-gate logerr("closing log %s: %s", curfname,
342*0Sstevel@tonic-gate mystrerror(err));
343*0Sstevel@tonic-gate }
344*0Sstevel@tonic-gate }
345*0Sstevel@tonic-gate
346*0Sstevel@tonic-gate /*
347*0Sstevel@tonic-gate * Reopen syslog connection; in case it was closed.
348*0Sstevel@tonic-gate */
349*0Sstevel@tonic-gate void
reopen_log(void)350*0Sstevel@tonic-gate reopen_log(void)
351*0Sstevel@tonic-gate {
352*0Sstevel@tonic-gate openlog(prog_name, LOG_PID | LOG_NDELAY | LOG_NOWAIT, LOG_DAEMON);
353*0Sstevel@tonic-gate /* I control the log level */
354*0Sstevel@tonic-gate (void) setlogmask(LOG_UPTO(LOG_DEBUG));
355*0Sstevel@tonic-gate }
356