Annotation of src/usr.bin/cvs/log.c, Revision 1.29
1.29 ! xsa 1: /* $OpenBSD: log.c,v 1.28 2005/12/10 20:27:45 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:
1.29 ! xsa 27: #include "includes.h"
1.1 jfb 28:
1.16 xsa 29: #include "cvs.h"
1.1 jfb 30: #include "log.h"
31:
32: extern char *__progname;
33:
1.3 jfb 34:
1.2 jfb 35: #ifdef unused
1.13 jfb 36: static char *cvs_log_levels[LP_MAX + 1] = {
1.1 jfb 37: "debug",
38: "info",
39: "notice",
40: "warning",
41: "error",
42: "alert",
1.4 jfb 43: "error",
44: "abort",
1.13 jfb 45: "trace",
1.1 jfb 46: };
1.2 jfb 47: #endif
1.1 jfb 48:
1.13 jfb 49: static int cvs_slpriomap[LP_MAX + 1] = {
1.1 jfb 50: LOG_DEBUG,
1.24 xsa 51: LOG_INFO,
1.23 xsa 52: LOG_NOTICE,
1.1 jfb 53: LOG_WARNING,
54: LOG_ERR,
55: LOG_ALERT,
56: LOG_ERR,
1.4 jfb 57: LOG_ERR,
1.13 jfb 58: LOG_DEBUG,
1.1 jfb 59: };
60:
1.26 niallo 61: #if !defined(RCSPROG)
1.19 joris 62: static int send_m = 1;
1.26 niallo 63: #endif
1.1 jfb 64: static u_int cvs_log_dest = LD_STD;
65: static u_int cvs_log_flags = 0;
66:
1.10 jfb 67: static struct syslog_data cvs_sl = SYSLOG_DATA_INIT;
1.1 jfb 68:
1.9 jfb 69: /* filter manipulation macros */
1.22 xsa 70: #define CVS_LOG_FLTRRST() (cvs_log_filters = 0)
71: #define CVS_LOG_FLTRSET(l) (cvs_log_filters |= (1 << l))
72: #define CVS_LOG_FLTRGET(l) (cvs_log_filters & (1 << l))
73: #define CVS_LOG_FLTRCLR(l) (cvs_log_filters &= ~(1 << l))
1.1 jfb 74:
1.9 jfb 75: static u_int cvs_log_filters;
1.1 jfb 76:
77:
78: /*
79: * cvs_log_init()
80: *
81: * Initialize the logging facility of the server.
82: * Returns 0 on success, or -1 on failure.
83: */
84: int
85: cvs_log_init(u_int dest, u_int flags)
86: {
87: int slopt;
88:
89: cvs_log_dest = dest;
90: cvs_log_flags = flags;
91:
92: /* by default, filter only LP_DEBUG and LP_INFO levels */
1.9 jfb 93: CVS_LOG_FLTRRST();
94: CVS_LOG_FLTRSET(LP_DEBUG);
95: CVS_LOG_FLTRSET(LP_INFO);
1.1 jfb 96:
1.8 jfb 97: /* traces are enabled with the -t command-line option */
1.9 jfb 98: CVS_LOG_FLTRSET(LP_TRACE);
1.8 jfb 99:
1.1 jfb 100: if (dest & LD_SYSLOG) {
101: slopt = 0;
102:
103: if (dest & LD_CONS)
104: slopt |= LOG_CONS;
105: if (flags & LF_PID)
106: slopt |= LOG_PID;
107:
108: openlog_r(__progname, slopt, LOG_DAEMON, &cvs_sl);
109: }
110:
111: return (0);
112: }
113:
114:
115: /*
116: * cvs_log_cleanup()
117: *
118: * Cleanup the logging facility.
119: */
120: void
121: cvs_log_cleanup(void)
122: {
1.7 tedu 123:
1.1 jfb 124: closelog_r(&cvs_sl);
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)
1.9 jfb 151: for (i = 0; i <= LP_MAX; i++)
152: CVS_LOG_FLTRSET(i);
1.1 jfb 153: else
1.9 jfb 154: CVS_LOG_FLTRSET(level);
1.1 jfb 155: break;
156: case LP_FILTER_UNSET:
157: if (level == LP_ALL)
1.9 jfb 158: CVS_LOG_FLTRRST();
1.1 jfb 159: else
1.9 jfb 160: CVS_LOG_FLTRCLR(level);
1.1 jfb 161: break;
162: default:
163: return (-1);
164: }
165:
166: return (0);
167: }
168:
169:
170: /*
171: * cvs_log()
172: *
173: * Log the format-string message
174: * The <fmt> argument should not have a terminating newline, as this is taken
175: * care of by the logging facility.
176: */
177: int
178: cvs_log(u_int level, const char *fmt, ...)
179: {
180: int ret;
181: va_list vap;
182:
183: va_start(vap, fmt);
184: ret = cvs_vlog(level, fmt, vap);
185: va_end(vap);
186:
187: return (ret);
188: }
189:
190:
191: /*
192: * cvs_vlog()
193: *
194: * The <fmt> argument should not have a terminating newline, as this is taken
195: * care of by the logging facility.
196: */
197: int
198: cvs_vlog(u_int level, const char *fmt, va_list vap)
199: {
200: int ecp;
1.25 xsa 201: char prefix[64], buf[1024], ebuf[255];
1.1 jfb 202: FILE *out;
1.26 niallo 203: #if !defined(RCSPROG)
1.27 joris 204: char *cmdname;
1.20 joris 205: struct cvs_cmd *cmdp;
1.26 niallo 206: #endif
1.1 jfb 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.17 xsa 220: /* always use the command name in error messages, not aliases */
1.26 niallo 221: #if !defined(RCSPROG)
1.27 joris 222: if (cvs_command == NULL)
223: cmdname = " ";
224: else {
225: cmdp = cvs_findcmd(cvs_command);
226: cmdname = cmdp->cmd_name;
227: }
1.17 xsa 228:
1.3 jfb 229: /* The cvs program appends the command name to the program name */
1.8 jfb 230: if (level == LP_TRACE) {
231: strlcpy(prefix, " -> ", sizeof(prefix));
232: if (cvs_cmdop == CVS_OP_SERVER)
233: prefix[0] = 'S';
234: } else if (cvs_command != NULL) {
1.4 jfb 235: if (level == LP_ABORT)
236: snprintf(prefix, sizeof(prefix), "%s [%s aborted]",
1.27 joris 237: __progname, cmdname);
1.4 jfb 238: else
239: snprintf(prefix, sizeof(prefix), "%s %s", __progname,
1.27 joris 240: cmdname);
1.6 deraadt 241: } else /* just use the standard strlcpy */
1.26 niallo 242: #endif
1.3 jfb 243: strlcpy(prefix, __progname, sizeof(prefix));
244:
1.8 jfb 245: if ((cvs_log_flags & LF_PID) && (level != LP_TRACE)) {
1.1 jfb 246: snprintf(buf, sizeof(buf), "[%d]", (int)getpid());
247: strlcat(prefix, buf, sizeof(prefix));
248: }
249:
250: vsnprintf(buf, sizeof(buf), fmt, vap);
251: if (level == LP_ERRNO) {
252: snprintf(ebuf, sizeof(ebuf), ": %s", strerror(errno));
253: strlcat(buf, ebuf, sizeof(buf));
254: }
255:
256: if (cvs_log_dest & LD_STD) {
1.24 xsa 257: if (level < LP_NOTICE)
1.1 jfb 258: out = stdout;
259: else
260: out = stderr;
1.3 jfb 261:
1.26 niallo 262: #if !defined(RCSPROG)
1.3 jfb 263: if (cvs_cmdop == CVS_OP_SERVER) {
264: if (out == stdout)
265: putc('M', out);
1.11 jfb 266: else {
267: out = stdout;
1.3 jfb 268: putc('E', out);
1.11 jfb 269: }
1.3 jfb 270: putc(' ', out);
271: }
1.26 niallo 272: #endif
1.1 jfb 273:
1.8 jfb 274: fputs(prefix, out);
275: if (level != LP_TRACE)
276: fputs(": ", out);
277: fputs(buf, out);
278: fputc('\n', out);
1.1 jfb 279: }
280:
281: if (cvs_log_dest & LD_SYSLOG)
282: syslog_r(cvs_slpriomap[level], &cvs_sl, "%s", buf);
283:
284: /* preserve it just in case we changed it? */
285: if (level == LP_ERRNO)
286: errno = ecp;
287:
288: return (0);
1.2 jfb 289: }
290:
291:
292: /*
293: * cvs_printf()
294: *
1.14 jfb 295: * Wrapper function around printf() that prepends a 'M' command when
1.2 jfb 296: * the program is acting as server.
297: */
298: int
299: cvs_printf(const char *fmt, ...)
300: {
301: int ret;
1.26 niallo 302: #if !defined(RCSPROG)
1.14 jfb 303: char *nstr, *dp, *sp;
1.26 niallo 304: #endif
1.2 jfb 305: va_list vap;
306:
307: va_start(vap, fmt);
1.14 jfb 308:
1.26 niallo 309: #if !defined(RCSPROG)
1.14 jfb 310: if (cvs_cmdop == CVS_OP_SERVER) {
311: ret = vasprintf(&nstr, fmt, vap);
312: if (ret != -1) {
313: for (dp = nstr; *dp != '\0';) {
314: sp = strchr(dp, '\n');
315: if (sp == NULL)
316: for (sp = dp; *sp != '\0'; sp++)
317: ;
318:
1.21 joris 319: if (send_m) {
1.18 joris 320: send_m = 0;
321: putc('M', stdout);
322: putc(' ', stdout);
323: }
324:
1.14 jfb 325: fwrite(dp, sizeof(char), (size_t)(sp - dp),
326: stdout);
327:
328: if (*sp != '\n')
329: break;
330:
331: putc('\n', stdout);
1.18 joris 332: send_m = 1;
1.14 jfb 333: dp = sp + 1;
334: }
1.28 joris 335: xfree(nstr);
1.14 jfb 336: }
337: } else
1.26 niallo 338: #endif
1.14 jfb 339: ret = vprintf(fmt, vap);
340:
1.2 jfb 341: va_end(vap);
342: return (ret);
1.1 jfb 343: }
1.19 joris 344: void
345: cvs_putchar(int c)
346: {
1.26 niallo 347: #if !defined(RCSPROG)
1.19 joris 348: if (cvs_cmdop == CVS_OP_SERVER && send_m) {
349: send_m = 0;
350: putc('M', stdout);
351: putc(' ', stdout);
352: }
1.26 niallo 353: #endif
1.19 joris 354:
355: putc(c, stdout);
356:
1.26 niallo 357: #if !defined(RCSPROG)
1.19 joris 358: if (cvs_cmdop == CVS_OP_SERVER && c == '\n')
359: send_m = 1;
1.26 niallo 360: #endif
1.19 joris 361: }