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