Annotation of src/usr.bin/cvs/log.c, Revision 1.18
1.18 ! joris 1: /* $OpenBSD: log.c,v 1.17 2005/06/02 16:05:38 xsa 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>
1.16 xsa 31: #include <stdlib.h>
1.1 jfb 32: #include <string.h>
1.16 xsa 33: #include <syslog.h>
1.1 jfb 34: #include <unistd.h>
35:
1.16 xsa 36: #include "cvs.h"
1.1 jfb 37: #include "log.h"
38:
39: extern char *__progname;
40:
1.3 jfb 41:
1.2 jfb 42: #ifdef unused
1.13 jfb 43: static char *cvs_log_levels[LP_MAX + 1] = {
1.1 jfb 44: "debug",
45: "info",
46: "notice",
47: "warning",
48: "error",
49: "alert",
1.4 jfb 50: "error",
51: "abort",
1.13 jfb 52: "trace",
1.1 jfb 53: };
1.2 jfb 54: #endif
1.1 jfb 55:
1.13 jfb 56: static int cvs_slpriomap[LP_MAX + 1] = {
1.1 jfb 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.13 jfb 65: LOG_DEBUG,
1.1 jfb 66: };
67:
68: static u_int cvs_log_dest = LD_STD;
69: static u_int cvs_log_flags = 0;
70:
1.10 jfb 71: static struct syslog_data cvs_sl = SYSLOG_DATA_INIT;
1.1 jfb 72:
1.9 jfb 73: /* filter manipulation macros */
74: #define CVS_LOG_FLTRRST() (cvs_log_filters = 0)
75: #define CVS_LOG_FLTRSET(l) (cvs_log_filters |= (1 << l))
76: #define CVS_LOG_FLTRGET(l) (cvs_log_filters & (1 << l))
77: #define CVS_LOG_FLTRCLR(l) (cvs_log_filters &= ~(1 << l))
1.1 jfb 78:
1.9 jfb 79: static u_int cvs_log_filters;
1.1 jfb 80:
81:
82: /*
83: * cvs_log_init()
84: *
85: * Initialize the logging facility of the server.
86: * Returns 0 on success, or -1 on failure.
87: */
88: int
89: cvs_log_init(u_int dest, u_int flags)
90: {
91: int slopt;
92:
93: cvs_log_dest = dest;
94: cvs_log_flags = flags;
95:
96: /* by default, filter only LP_DEBUG and LP_INFO levels */
1.9 jfb 97: CVS_LOG_FLTRRST();
98: CVS_LOG_FLTRSET(LP_DEBUG);
99: CVS_LOG_FLTRSET(LP_INFO);
1.1 jfb 100:
1.8 jfb 101: /* traces are enabled with the -t command-line option */
1.9 jfb 102: CVS_LOG_FLTRSET(LP_TRACE);
1.8 jfb 103:
1.1 jfb 104: if (dest & LD_SYSLOG) {
105: slopt = 0;
106:
107: if (dest & LD_CONS)
108: slopt |= LOG_CONS;
109: if (flags & LF_PID)
110: slopt |= LOG_PID;
111:
112: openlog_r(__progname, slopt, LOG_DAEMON, &cvs_sl);
113: }
114:
115: return (0);
116: }
117:
118:
119: /*
120: * cvs_log_cleanup()
121: *
122: * Cleanup the logging facility.
123: */
124: void
125: cvs_log_cleanup(void)
126: {
1.7 tedu 127:
1.1 jfb 128: closelog_r(&cvs_sl);
129: }
130:
131:
132: /*
133: * cvs_log_filter()
134: *
135: * Apply or remove filters on the logging facility. The exact operation is
136: * specified by the <how> and <level> arguments. The <how> arguments tells
137: * how the filters will be affected, and <level> gives the log levels that
138: * will be affected by the change.
139: * Returns 0 on success, or -1 on failure.
140: */
141:
142: int
143: cvs_log_filter(u_int how, u_int level)
144: {
145: u_int i;
146:
147: if ((level > LP_MAX) && (level != LP_ALL)) {
148: cvs_log(LP_ERR, "invalid log level for filter");
149: return (-1);
150: }
151:
152: switch (how) {
153: case LP_FILTER_SET:
154: if (level == LP_ALL)
1.9 jfb 155: for (i = 0; i <= LP_MAX; i++)
156: CVS_LOG_FLTRSET(i);
1.1 jfb 157: else
1.9 jfb 158: CVS_LOG_FLTRSET(level);
1.1 jfb 159: break;
160: case LP_FILTER_UNSET:
161: if (level == LP_ALL)
1.9 jfb 162: CVS_LOG_FLTRRST();
1.1 jfb 163: else
1.9 jfb 164: CVS_LOG_FLTRCLR(level);
1.1 jfb 165: break;
166: default:
167: return (-1);
168: }
169:
170: return (0);
171: }
172:
173:
174: /*
175: * cvs_log()
176: *
177: * Log the format-string message
178: * The <fmt> argument should not have a terminating newline, as this is taken
179: * care of by the logging facility.
180: */
181: int
182: cvs_log(u_int level, const char *fmt, ...)
183: {
184: int ret;
185: va_list vap;
186:
187: va_start(vap, fmt);
188: ret = cvs_vlog(level, fmt, vap);
189: va_end(vap);
190:
191: return (ret);
192: }
193:
194:
195: /*
196: * cvs_vlog()
197: *
198: * The <fmt> argument should not have a terminating newline, as this is taken
199: * care of by the logging facility.
200: */
201: int
202: cvs_vlog(u_int level, const char *fmt, va_list vap)
203: {
204: int ecp;
205: char prefix[64], buf[1024], ebuf[32];
206: FILE *out;
207:
1.13 jfb 208: if (level > LP_MAX)
1.4 jfb 209: return (-1);
1.1 jfb 210:
211: /* apply any filters */
1.9 jfb 212: if (CVS_LOG_FLTRGET(level))
1.1 jfb 213: return (0);
214:
215: if (level == LP_ERRNO)
216: ecp = errno;
1.4 jfb 217: else
218: ecp = 0;
1.1 jfb 219:
1.3 jfb 220: #ifdef CVS
1.17 xsa 221: struct cvs_cmd *cmdp;
222:
223: /* always use the command name in error messages, not aliases */
224: cmdp = cvs_findcmd(cvs_command);
225:
1.3 jfb 226: /* The cvs program appends the command name to the program name */
1.8 jfb 227: if (level == LP_TRACE) {
228: strlcpy(prefix, " -> ", sizeof(prefix));
229: if (cvs_cmdop == CVS_OP_SERVER)
230: prefix[0] = 'S';
231: } else if (cvs_command != NULL) {
1.4 jfb 232: if (level == LP_ABORT)
233: snprintf(prefix, sizeof(prefix), "%s [%s aborted]",
1.17 xsa 234: __progname, cmdp->cmd_name);
1.4 jfb 235: else
236: snprintf(prefix, sizeof(prefix), "%s %s", __progname,
1.17 xsa 237: cmdp->cmd_name);
1.6 deraadt 238: } else /* just use the standard strlcpy */
1.3 jfb 239: #endif
240: strlcpy(prefix, __progname, sizeof(prefix));
241:
1.8 jfb 242: if ((cvs_log_flags & LF_PID) && (level != LP_TRACE)) {
1.1 jfb 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);
1.11 jfb 263: else {
264: out = stdout;
1.3 jfb 265: putc('E', out);
1.11 jfb 266: }
1.3 jfb 267: putc(' ', out);
268: }
269: #endif
1.1 jfb 270:
1.8 jfb 271: fputs(prefix, out);
272: if (level != LP_TRACE)
273: fputs(": ", out);
274: fputs(buf, out);
275: fputc('\n', out);
1.1 jfb 276: }
277:
278: if (cvs_log_dest & LD_SYSLOG)
279: syslog_r(cvs_slpriomap[level], &cvs_sl, "%s", buf);
280:
281: /* preserve it just in case we changed it? */
282: if (level == LP_ERRNO)
283: errno = ecp;
284:
285: return (0);
1.2 jfb 286: }
287:
288:
1.15 jfb 289: #ifdef CVS
1.2 jfb 290: /*
291: * cvs_printf()
292: *
1.14 jfb 293: * Wrapper function around printf() that prepends a 'M' command when
1.2 jfb 294: * the program is acting as server.
295: */
296: int
297: cvs_printf(const char *fmt, ...)
298: {
299: int ret;
1.14 jfb 300: char *nstr, *dp, *sp;
1.2 jfb 301: va_list vap;
1.18 ! joris 302: static int send_m = 1;
1.2 jfb 303:
304: va_start(vap, fmt);
1.14 jfb 305:
306: if (cvs_cmdop == CVS_OP_SERVER) {
307: ret = vasprintf(&nstr, fmt, vap);
308: if (ret != -1) {
309: for (dp = nstr; *dp != '\0';) {
310: sp = strchr(dp, '\n');
311: if (sp == NULL)
312: for (sp = dp; *sp != '\0'; sp++)
313: ;
314:
1.18 ! joris 315: if (send_m) {
! 316: send_m = 0;
! 317: putc('M', stdout);
! 318: putc(' ', stdout);
! 319: }
! 320:
1.14 jfb 321: fwrite(dp, sizeof(char), (size_t)(sp - dp),
322: stdout);
323:
324: if (*sp != '\n')
325: break;
326:
327: putc('\n', stdout);
1.18 ! joris 328: send_m = 1;
1.14 jfb 329: dp = sp + 1;
330: }
331: free(nstr);
332: }
333: } else
334: ret = vprintf(fmt, vap);
335:
1.2 jfb 336: va_end(vap);
337: return (ret);
1.1 jfb 338: }
1.15 jfb 339: #endif