Annotation of src/usr.bin/cvs/log.c, Revision 1.19
1.19 ! joris 1: /* $OpenBSD: log.c,v 1.18 2005/06/02 20:16:48 joris 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:
1.19 ! joris 68: static int send_m = 1;
1.1 jfb 69: static u_int cvs_log_dest = LD_STD;
70: static u_int cvs_log_flags = 0;
71:
1.10 jfb 72: static struct syslog_data cvs_sl = SYSLOG_DATA_INIT;
1.1 jfb 73:
1.9 jfb 74: /* filter manipulation macros */
75: #define CVS_LOG_FLTRRST() (cvs_log_filters = 0)
76: #define CVS_LOG_FLTRSET(l) (cvs_log_filters |= (1 << l))
77: #define CVS_LOG_FLTRGET(l) (cvs_log_filters & (1 << l))
78: #define CVS_LOG_FLTRCLR(l) (cvs_log_filters &= ~(1 << l))
1.1 jfb 79:
1.9 jfb 80: static u_int cvs_log_filters;
1.1 jfb 81:
82:
83: /*
84: * cvs_log_init()
85: *
86: * Initialize the logging facility of the server.
87: * Returns 0 on success, or -1 on failure.
88: */
89: int
90: cvs_log_init(u_int dest, u_int flags)
91: {
92: int slopt;
93:
94: cvs_log_dest = dest;
95: cvs_log_flags = flags;
96:
97: /* by default, filter only LP_DEBUG and LP_INFO levels */
1.9 jfb 98: CVS_LOG_FLTRRST();
99: CVS_LOG_FLTRSET(LP_DEBUG);
100: CVS_LOG_FLTRSET(LP_INFO);
1.1 jfb 101:
1.8 jfb 102: /* traces are enabled with the -t command-line option */
1.9 jfb 103: CVS_LOG_FLTRSET(LP_TRACE);
1.8 jfb 104:
1.1 jfb 105: if (dest & LD_SYSLOG) {
106: slopt = 0;
107:
108: if (dest & LD_CONS)
109: slopt |= LOG_CONS;
110: if (flags & LF_PID)
111: slopt |= LOG_PID;
112:
113: openlog_r(__progname, slopt, LOG_DAEMON, &cvs_sl);
114: }
115:
116: return (0);
117: }
118:
119:
120: /*
121: * cvs_log_cleanup()
122: *
123: * Cleanup the logging facility.
124: */
125: void
126: cvs_log_cleanup(void)
127: {
1.7 tedu 128:
1.1 jfb 129: closelog_r(&cvs_sl);
130: }
131:
132:
133: /*
134: * cvs_log_filter()
135: *
136: * Apply or remove filters on the logging facility. The exact operation is
137: * specified by the <how> and <level> arguments. The <how> arguments tells
138: * how the filters will be affected, and <level> gives the log levels that
139: * will be affected by the change.
140: * Returns 0 on success, or -1 on failure.
141: */
142:
143: int
144: cvs_log_filter(u_int how, u_int level)
145: {
146: u_int i;
147:
148: if ((level > LP_MAX) && (level != LP_ALL)) {
149: cvs_log(LP_ERR, "invalid log level for filter");
150: return (-1);
151: }
152:
153: switch (how) {
154: case LP_FILTER_SET:
155: if (level == LP_ALL)
1.9 jfb 156: for (i = 0; i <= LP_MAX; i++)
157: CVS_LOG_FLTRSET(i);
1.1 jfb 158: else
1.9 jfb 159: CVS_LOG_FLTRSET(level);
1.1 jfb 160: break;
161: case LP_FILTER_UNSET:
162: if (level == LP_ALL)
1.9 jfb 163: CVS_LOG_FLTRRST();
1.1 jfb 164: else
1.9 jfb 165: CVS_LOG_FLTRCLR(level);
1.1 jfb 166: break;
167: default:
168: return (-1);
169: }
170:
171: return (0);
172: }
173:
174:
175: /*
176: * cvs_log()
177: *
178: * Log the format-string message
179: * The <fmt> argument should not have a terminating newline, as this is taken
180: * care of by the logging facility.
181: */
182: int
183: cvs_log(u_int level, const char *fmt, ...)
184: {
185: int ret;
186: va_list vap;
187:
188: va_start(vap, fmt);
189: ret = cvs_vlog(level, fmt, vap);
190: va_end(vap);
191:
192: return (ret);
193: }
194:
195:
196: /*
197: * cvs_vlog()
198: *
199: * The <fmt> argument should not have a terminating newline, as this is taken
200: * care of by the logging facility.
201: */
202: int
203: cvs_vlog(u_int level, const char *fmt, va_list vap)
204: {
205: int ecp;
206: char prefix[64], buf[1024], ebuf[32];
207: FILE *out;
208:
1.13 jfb 209: if (level > LP_MAX)
1.4 jfb 210: return (-1);
1.1 jfb 211:
212: /* apply any filters */
1.9 jfb 213: if (CVS_LOG_FLTRGET(level))
1.1 jfb 214: return (0);
215:
216: if (level == LP_ERRNO)
217: ecp = errno;
1.4 jfb 218: else
219: ecp = 0;
1.1 jfb 220:
1.3 jfb 221: #ifdef CVS
1.17 xsa 222: struct cvs_cmd *cmdp;
223:
224: /* always use the command name in error messages, not aliases */
225: cmdp = cvs_findcmd(cvs_command);
226:
1.3 jfb 227: /* The cvs program appends the command name to the program name */
1.8 jfb 228: if (level == LP_TRACE) {
229: strlcpy(prefix, " -> ", sizeof(prefix));
230: if (cvs_cmdop == CVS_OP_SERVER)
231: prefix[0] = 'S';
232: } else if (cvs_command != NULL) {
1.4 jfb 233: if (level == LP_ABORT)
234: snprintf(prefix, sizeof(prefix), "%s [%s aborted]",
1.17 xsa 235: __progname, cmdp->cmd_name);
1.4 jfb 236: else
237: snprintf(prefix, sizeof(prefix), "%s %s", __progname,
1.17 xsa 238: cmdp->cmd_name);
1.6 deraadt 239: } else /* just use the standard strlcpy */
1.3 jfb 240: #endif
241: strlcpy(prefix, __progname, sizeof(prefix));
242:
1.8 jfb 243: if ((cvs_log_flags & LF_PID) && (level != LP_TRACE)) {
1.1 jfb 244: snprintf(buf, sizeof(buf), "[%d]", (int)getpid());
245: strlcat(prefix, buf, sizeof(prefix));
246: }
247:
248: vsnprintf(buf, sizeof(buf), fmt, vap);
249: if (level == LP_ERRNO) {
250: snprintf(ebuf, sizeof(ebuf), ": %s", strerror(errno));
251: strlcat(buf, ebuf, sizeof(buf));
252: }
253:
254: if (cvs_log_dest & LD_STD) {
255: if (level <= LP_NOTICE)
256: out = stdout;
257: else
258: out = stderr;
1.3 jfb 259:
260: #ifdef CVS
261: if (cvs_cmdop == CVS_OP_SERVER) {
262: if (out == stdout)
263: putc('M', out);
1.11 jfb 264: else {
265: out = stdout;
1.3 jfb 266: putc('E', out);
1.11 jfb 267: }
1.3 jfb 268: putc(' ', out);
269: }
270: #endif
1.1 jfb 271:
1.8 jfb 272: fputs(prefix, out);
273: if (level != LP_TRACE)
274: fputs(": ", out);
275: fputs(buf, out);
276: fputc('\n', out);
1.1 jfb 277: }
278:
279: if (cvs_log_dest & LD_SYSLOG)
280: syslog_r(cvs_slpriomap[level], &cvs_sl, "%s", buf);
281:
282: /* preserve it just in case we changed it? */
283: if (level == LP_ERRNO)
284: errno = ecp;
285:
286: return (0);
1.2 jfb 287: }
288:
289:
1.15 jfb 290: #ifdef CVS
1.2 jfb 291: /*
292: * cvs_printf()
293: *
1.14 jfb 294: * Wrapper function around printf() that prepends a 'M' command when
1.2 jfb 295: * the program is acting as server.
296: */
297: int
298: cvs_printf(const char *fmt, ...)
299: {
300: int ret;
1.14 jfb 301: char *nstr, *dp, *sp;
1.2 jfb 302: va_list vap;
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.19 ! joris 339:
! 340: void
! 341: cvs_putchar(int c)
! 342: {
! 343: if (cvs_cmdop == CVS_OP_SERVER && send_m) {
! 344: send_m = 0;
! 345: putc('M', stdout);
! 346: putc(' ', stdout);
! 347: }
! 348:
! 349: putc(c, stdout);
! 350:
! 351: if (cvs_cmdop == CVS_OP_SERVER && c == '\n')
! 352: send_m = 1;
! 353: }
! 354:
1.15 jfb 355: #endif