1 /* $OpenBSD: log.c,v 1.2 2004/07/27 16:19:41 jfb Exp $ */ 2 /* 3 * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org> 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" 38 39 extern char *__progname; 40 41 #ifdef unused 42 static char *cvs_log_levels[] = { 43 "debug", 44 "info", 45 "notice", 46 "warning", 47 "error", 48 "alert", 49 "error" 50 }; 51 #endif 52 53 static int cvs_slpriomap[] = { 54 LOG_DEBUG, 55 LOG_INFO, 56 LOG_NOTICE, 57 LOG_WARNING, 58 LOG_ERR, 59 LOG_ALERT, 60 LOG_ERR, 61 }; 62 63 64 65 static u_int cvs_log_dest = LD_STD; 66 static u_int cvs_log_flags = 0; 67 68 static u_int cvs_log_filters[LP_MAX + 1]; 69 #define NB_FILTERS sizeof(cvs_log_filters)/sizeof(cvs_log_filters[0]) 70 71 72 static struct syslog_data cvs_sl; 73 74 75 /* 76 * cvs_log_init() 77 * 78 * Initialize the logging facility of the server. 79 * Returns 0 on success, or -1 on failure. 80 */ 81 82 int 83 cvs_log_init(u_int dest, u_int flags) 84 { 85 int slopt; 86 87 cvs_log_dest = dest; 88 cvs_log_flags = flags; 89 90 /* by default, filter only LP_DEBUG and LP_INFO levels */ 91 memset(cvs_log_filters, 0, sizeof(cvs_log_filters)); 92 cvs_log_filters[LP_DEBUG] = 1; 93 cvs_log_filters[LP_INFO] = 1; 94 95 if (dest & LD_SYSLOG) { 96 slopt = 0; 97 98 if (dest & LD_CONS) 99 slopt |= LOG_CONS; 100 if (flags & LF_PID) 101 slopt |= LOG_PID; 102 103 openlog_r(__progname, slopt, LOG_DAEMON, &cvs_sl); 104 } 105 106 return (0); 107 } 108 109 110 /* 111 * cvs_log_cleanup() 112 * 113 * Cleanup the logging facility. 114 */ 115 116 void 117 cvs_log_cleanup(void) 118 { 119 closelog_r(&cvs_sl); 120 121 } 122 123 124 /* 125 * cvs_log_filter() 126 * 127 * Apply or remove filters on the logging facility. The exact operation is 128 * specified by the <how> and <level> arguments. The <how> arguments tells 129 * how the filters will be affected, and <level> gives the log levels that 130 * will be affected by the change. 131 * Returns 0 on success, or -1 on failure. 132 */ 133 134 int 135 cvs_log_filter(u_int how, u_int level) 136 { 137 u_int i; 138 139 if ((level > LP_MAX) && (level != LP_ALL)) { 140 cvs_log(LP_ERR, "invalid log level for filter"); 141 return (-1); 142 } 143 144 switch (how) { 145 case LP_FILTER_SET: 146 if (level == LP_ALL) 147 for (i = 0; i < NB_FILTERS; i++) 148 cvs_log_filters[i] = 1; 149 else 150 cvs_log_filters[level] = 1; 151 break; 152 case LP_FILTER_UNSET: 153 if (level == LP_ALL) 154 for (i = 0; i < NB_FILTERS; i++) 155 cvs_log_filters[i] = 0; 156 else 157 cvs_log_filters[level] = 0; 158 break; 159 case LP_FILTER_TOGGLE: 160 if (level == LP_ALL) 161 for (i = 0; i < NB_FILTERS; i++) 162 cvs_log_filters[i] = 163 (cvs_log_filters[i] == 0) ? 1 : 0; 164 else 165 cvs_log_filters[level] = 166 (cvs_log_filters[level] == 0) ? 1 : 0; 167 break; 168 default: 169 return (-1); 170 } 171 172 return (0); 173 } 174 175 176 /* 177 * cvs_log() 178 * 179 * Log the format-string message 180 * The <fmt> argument should not have a terminating newline, as this is taken 181 * care of by the logging facility. 182 */ 183 184 int 185 cvs_log(u_int level, const char *fmt, ...) 186 { 187 int ret; 188 va_list vap; 189 190 va_start(vap, fmt); 191 ret = cvs_vlog(level, fmt, vap); 192 va_end(vap); 193 194 return (ret); 195 } 196 197 198 /* 199 * cvs_vlog() 200 * 201 * The <fmt> argument should not have a terminating newline, as this is taken 202 * care of by the logging facility. 203 */ 204 205 int 206 cvs_vlog(u_int level, const char *fmt, va_list vap) 207 { 208 int ecp; 209 char prefix[64], buf[1024], ebuf[32]; 210 FILE *out; 211 212 ecp = 0; 213 214 if (level > LP_MAX) { 215 return (-1); 216 } 217 218 /* apply any filters */ 219 if (cvs_log_filters[level] == 1) 220 return (0); 221 222 if (level == LP_ERRNO) 223 ecp = errno; 224 225 strlcpy(prefix, __progname, sizeof(prefix)); 226 if (cvs_log_flags & LF_PID) { 227 snprintf(buf, sizeof(buf), "[%d]", (int)getpid()); 228 strlcat(prefix, buf, sizeof(prefix)); 229 } 230 231 vsnprintf(buf, sizeof(buf), fmt, vap); 232 if (level == LP_ERRNO) { 233 snprintf(ebuf, sizeof(ebuf), ": %s", strerror(errno)); 234 strlcat(buf, ebuf, sizeof(buf)); 235 } 236 237 if (cvs_log_dest & LD_STD) { 238 if (level <= LP_NOTICE) 239 out = stdout; 240 else 241 out = stderr; 242 243 fprintf(out, "%s: %s\n", prefix, buf); 244 } 245 246 if (cvs_log_dest & LD_SYSLOG) 247 syslog_r(cvs_slpriomap[level], &cvs_sl, "%s", buf); 248 249 /* preserve it just in case we changed it? */ 250 if (level == LP_ERRNO) 251 errno = ecp; 252 253 return (0); 254 } 255 256 257 /* 258 * cvs_printf() 259 * 260 * Wrapper function around printf() that prepends a 'M' or 'E' command when 261 * the program is acting as server. 262 */ 263 264 int 265 cvs_printf(const char *fmt, ...) 266 { 267 int ret; 268 va_list vap; 269 270 va_start(vap, fmt); 271 272 ret = vprintf(fmt, vap); 273 274 va_end(vap); 275 276 return (ret); 277 } 278