Annotation of src/usr.bin/cvs/log.c, Revision 1.6
1.6 ! deraadt 1: /* $OpenBSD: log.c,v 1.5 2004/11/28 15:12:17 pat Exp $ */
1.1 jfb 2: /*
1.2 jfb 3: * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
1.1 jfb 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: *
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. The name of the author may not be used to endorse or promote products
13: * derived from this software without specific prior written permission.
14: *
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
16: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
17: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
18: * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25: */
26:
27: #include <sys/types.h>
28:
29: #include <errno.h>
30: #include <stdio.h>
31: #include <string.h>
32: #include <stdlib.h>
33: #include <unistd.h>
34: #include <stdarg.h>
35: #include <syslog.h>
36:
37: #include "log.h"
1.3 jfb 38: #include "cvs.h"
1.1 jfb 39:
40: extern char *__progname;
41:
1.3 jfb 42:
1.2 jfb 43: #ifdef unused
1.1 jfb 44: static char *cvs_log_levels[] = {
45: "debug",
46: "info",
47: "notice",
48: "warning",
49: "error",
50: "alert",
1.4 jfb 51: "error",
52: "abort",
1.1 jfb 53: };
1.2 jfb 54: #endif
1.1 jfb 55:
56: static int cvs_slpriomap[] = {
57: LOG_DEBUG,
58: LOG_INFO,
59: LOG_NOTICE,
60: LOG_WARNING,
61: LOG_ERR,
62: LOG_ALERT,
63: LOG_ERR,
1.4 jfb 64: LOG_ERR,
1.1 jfb 65: };
66:
67:
68:
69: static u_int cvs_log_dest = LD_STD;
70: static u_int cvs_log_flags = 0;
71:
72: static u_int cvs_log_filters[LP_MAX + 1];
73: #define NB_FILTERS sizeof(cvs_log_filters)/sizeof(cvs_log_filters[0])
74:
75:
76: static struct syslog_data cvs_sl;
77:
78:
79: /*
80: * cvs_log_init()
81: *
82: * Initialize the logging facility of the server.
83: * Returns 0 on success, or -1 on failure.
84: */
85:
86: int
87: cvs_log_init(u_int dest, u_int flags)
88: {
89: int slopt;
90:
91: cvs_log_dest = dest;
92: cvs_log_flags = flags;
93:
94: /* by default, filter only LP_DEBUG and LP_INFO levels */
95: memset(cvs_log_filters, 0, sizeof(cvs_log_filters));
96: cvs_log_filters[LP_DEBUG] = 1;
97: cvs_log_filters[LP_INFO] = 1;
98:
99: if (dest & LD_SYSLOG) {
100: slopt = 0;
101:
102: if (dest & LD_CONS)
103: slopt |= LOG_CONS;
104: if (flags & LF_PID)
105: slopt |= LOG_PID;
106:
107: openlog_r(__progname, slopt, LOG_DAEMON, &cvs_sl);
108: }
109:
110: return (0);
111: }
112:
113:
114: /*
115: * cvs_log_cleanup()
116: *
117: * Cleanup the logging facility.
118: */
119:
120: void
121: cvs_log_cleanup(void)
122: {
123: closelog_r(&cvs_sl);
124:
125: }
126:
127:
128: /*
129: * cvs_log_filter()
130: *
131: * Apply or remove filters on the logging facility. The exact operation is
132: * specified by the <how> and <level> arguments. The <how> arguments tells
133: * how the filters will be affected, and <level> gives the log levels that
134: * will be affected by the change.
135: * Returns 0 on success, or -1 on failure.
136: */
137:
138: int
139: cvs_log_filter(u_int how, u_int level)
140: {
141: u_int i;
142:
143: if ((level > LP_MAX) && (level != LP_ALL)) {
144: cvs_log(LP_ERR, "invalid log level for filter");
145: return (-1);
146: }
147:
148: switch (how) {
149: case LP_FILTER_SET:
150: if (level == LP_ALL)
151: for (i = 0; i < NB_FILTERS; i++)
152: cvs_log_filters[i] = 1;
153: else
154: cvs_log_filters[level] = 1;
155: break;
156: case LP_FILTER_UNSET:
157: if (level == LP_ALL)
158: for (i = 0; i < NB_FILTERS; i++)
159: cvs_log_filters[i] = 0;
160: else
161: cvs_log_filters[level] = 0;
162: break;
163: case LP_FILTER_TOGGLE:
164: if (level == LP_ALL)
165: for (i = 0; i < NB_FILTERS; i++)
166: cvs_log_filters[i] =
167: (cvs_log_filters[i] == 0) ? 1 : 0;
168: else
169: cvs_log_filters[level] =
170: (cvs_log_filters[level] == 0) ? 1 : 0;
171: break;
172: default:
173: return (-1);
174: }
175:
176: return (0);
177: }
178:
179:
180: /*
181: * cvs_log()
182: *
183: * Log the format-string message
184: * The <fmt> argument should not have a terminating newline, as this is taken
185: * care of by the logging facility.
186: */
187:
188: int
189: cvs_log(u_int level, const char *fmt, ...)
190: {
191: int ret;
192: va_list vap;
193:
194: va_start(vap, fmt);
195: ret = cvs_vlog(level, fmt, vap);
196: va_end(vap);
197:
198: return (ret);
199: }
200:
201:
202: /*
203: * cvs_vlog()
204: *
205: * The <fmt> argument should not have a terminating newline, as this is taken
206: * care of by the logging facility.
207: */
208:
209: int
210: cvs_vlog(u_int level, const char *fmt, va_list vap)
211: {
212: int ecp;
213: char prefix[64], buf[1024], ebuf[32];
214: FILE *out;
215:
1.4 jfb 216: if (level > LP_MAX)
217: return (-1);
1.1 jfb 218:
219:
220: /* apply any filters */
1.4 jfb 221: if (cvs_log_filters[level] != 0)
1.1 jfb 222: return (0);
223:
224: if (level == LP_ERRNO)
225: ecp = errno;
1.4 jfb 226: else
227: ecp = 0;
1.1 jfb 228:
1.3 jfb 229: #ifdef CVS
230: /* The cvs program appends the command name to the program name */
231: if (cvs_command != NULL) {
1.4 jfb 232: if (level == LP_ABORT)
233: snprintf(prefix, sizeof(prefix), "%s [%s aborted]",
234: __progname, cvs_command);
235: else
236: snprintf(prefix, sizeof(prefix), "%s %s", __progname,
237: cvs_command);
1.6 ! deraadt 238: } else /* just use the standard strlcpy */
1.3 jfb 239: #endif
240: strlcpy(prefix, __progname, sizeof(prefix));
241:
1.1 jfb 242: if (cvs_log_flags & LF_PID) {
243: snprintf(buf, sizeof(buf), "[%d]", (int)getpid());
244: strlcat(prefix, buf, sizeof(prefix));
245: }
246:
247: vsnprintf(buf, sizeof(buf), fmt, vap);
248: if (level == LP_ERRNO) {
249: snprintf(ebuf, sizeof(ebuf), ": %s", strerror(errno));
250: strlcat(buf, ebuf, sizeof(buf));
251: }
252:
253: if (cvs_log_dest & LD_STD) {
254: if (level <= LP_NOTICE)
255: out = stdout;
256: else
257: out = stderr;
1.3 jfb 258:
259: #ifdef CVS
260: if (cvs_cmdop == CVS_OP_SERVER) {
261: if (out == stdout)
262: putc('M', out);
263: else
264: putc('E', out);
265: putc(' ', out);
266: }
267: #endif
1.1 jfb 268:
269: fprintf(out, "%s: %s\n", prefix, buf);
270: }
271:
272: if (cvs_log_dest & LD_SYSLOG)
273: syslog_r(cvs_slpriomap[level], &cvs_sl, "%s", buf);
274:
275: /* preserve it just in case we changed it? */
276: if (level == LP_ERRNO)
277: errno = ecp;
278:
279: return (0);
1.2 jfb 280: }
281:
282:
283: /*
284: * cvs_printf()
285: *
286: * Wrapper function around printf() that prepends a 'M' or 'E' command when
287: * the program is acting as server.
288: */
289:
290: int
291: cvs_printf(const char *fmt, ...)
292: {
293: int ret;
294: va_list vap;
295:
296: va_start(vap, fmt);
297: ret = vprintf(fmt, vap);
298: va_end(vap);
299:
300: return (ret);
1.1 jfb 301: }