1 /***************************************************************************** 2 * $Id: log.c 945 2009-04-21 22:17:51Z dun $ 3 ***************************************************************************** 4 * Written by Chris Dunlap <cdunlap (at) llnl.gov>. 5 * Copyright (C) 2007-2009 Lawrence Livermore National Security, LLC. 6 * Copyright (C) 2001-2007 The Regents of the University of California. 7 * UCRL-CODE-2002-009. 8 * 9 * This file is part of ConMan: The Console Manager. 10 * For details, see <http://home.gna.org/conman/>. 11 * 12 * This is free software; you can redistribute it and/or modify it 13 * under the terms of the GNU General Public License as published by 14 * the Free Software Foundation; either version 2 of the License, or 15 * (at your option) any later version. 16 * 17 * This is distributed in the hope that it will be useful, but WITHOUT 18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 20 * for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program. If not, see <http://www.gnu.org/licenses/>. 24 ***************************************************************************** 25 * Refer to "log.h" for documentation on public functions. 26 *****************************************************************************/ 27 28 29 #ifdef HAVE_CONFIG_H 30 # include "config.h" 31 #endif /* HAVE_CONFIG_H */ 32 33 #include <assert.h> 34 #include <errno.h> 35 #include <stdarg.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <syslog.h> 40 #include <time.h> 41 #include <unistd.h> 42 #include "log.h" 43 #include "util-str.h" 44 45 46 #ifndef MAX_LINE 47 # define MAX_LINE 1024 48 #endif /* !MAX_LINE */ 49 50 51 static FILE * log_file_fp = NULL; 52 static int log_file_priority = -1; 53 static int log_file_timestamp = 0; 54 static int log_syslog = 0; 55 static int log_fd_daemonize = -1; 56 57 58 static void log_aux(int errnum, int priority, char *msgbug, int msgbuflen, 59 const char *format, va_list vargs); 60 61 static const char * log_prefix(int priority); 62 63 64 void debug_printf(int level, const char *format, ...) 65 { 66 static int debug_level = -1; 67 va_list vargs; 68 char *p; 69 int i = 0; 70 71 if (debug_level < 0) { 72 if ((p = getenv("DEBUG"))) { 73 i = atoi(p); 74 } 75 debug_level = (i > 0) ? i : 0; 76 } 77 if ((level > 0) && (level <= debug_level)) { 78 va_start(vargs, format); 79 vfprintf(stderr, format, vargs); 80 va_end(vargs); 81 } 82 return; 83 } 84 85 86 void log_set_file(FILE *fp, int priority, int timestamp) 87 { 88 if (fp && !ferror(fp)) { 89 log_file_fp = fp; 90 log_file_priority = (priority > 0) ? priority : 0; 91 log_file_timestamp = !!timestamp; 92 setvbuf(fp, NULL, _IONBF, 0); /* set stream unbuffered */ 93 } 94 else { 95 log_file_fp = NULL; 96 log_file_priority = -1; 97 log_file_timestamp = 0; 98 } 99 return; 100 } 101 102 103 void log_set_syslog(char *ident, int facility) 104 { 105 char *p; 106 107 if (ident) { 108 if ((p = strrchr(ident, '/'))) { 109 ident = p + 1; 110 } 111 openlog(ident, LOG_NDELAY | LOG_PID, facility); 112 log_syslog = 1; 113 } 114 else { 115 closelog(); 116 log_syslog = 0; 117 } 118 return; 119 } 120 121 122 void log_set_err_pipe(int fd) 123 { 124 log_fd_daemonize = (fd >= 0) ? fd : -1; 125 return; 126 } 127 128 129 void log_err(int errnum, const char *format, ...) 130 { 131 int priority = LOG_ERR; 132 va_list vargs; 133 char msg[MAX_LINE]; 134 signed char c; 135 int n; 136 char *p; 137 138 va_start(vargs, format); 139 log_aux(errnum, priority, msg, sizeof(msg), format, vargs); 140 va_end(vargs); 141 142 /* Return error priority and message across "daemonize" pipe. 143 */ 144 if (log_fd_daemonize >= 0) { 145 c = (signed char) priority; 146 n = write(log_fd_daemonize, &c, sizeof(c)); 147 if ((n > 0) && (msg[0] != '\0') && (log_file_fp != stderr)) { 148 if ((p = strchr(msg, '\n'))) { 149 *p = '\0'; 150 } 151 /* Ignore return value from write() instead of logging an error 152 * about failing to log an error. Replaced void cast with 153 * useless assignment since compilation under rhel5 complained 154 * about ignoring return value of 'write'. 155 */ 156 n = write(log_fd_daemonize, msg, strlen(msg) + 1); 157 } 158 } 159 #ifndef NDEBUG 160 /* Generate core for debugging. 161 */ 162 if (getenv("DEBUG")) { 163 abort(); 164 } 165 #endif /* !NDEBUG */ 166 167 exit(1); 168 } 169 170 171 void log_msg(int priority, const char *format, ...) 172 { 173 va_list vargs; 174 175 va_start(vargs, format); 176 log_aux(0, priority, NULL, 0, format, vargs); 177 va_end(vargs); 178 179 return; 180 } 181 182 183 static void log_aux(int errnum, int priority, char *msgbuf, int msgbuflen, 184 const char *format, va_list vargs) 185 { 186 time_t t; 187 struct tm tm; 188 const char *prefix; 189 char buf[MAX_LINE]; /* buf starting with timestamp */ 190 char *pbuf; /* buf starting with priority string */ 191 char *sbuf; /* buf starting with message */ 192 char *p; 193 int len; 194 int n; 195 196 p = sbuf = pbuf = buf; 197 len = sizeof(buf) - 1; /* reserve char for terminating '\n' */ 198 199 t = 0; 200 get_localtime(&t, &tm); 201 n = strftime(p, len, "%Y-%m-%d %H:%M:%S ", &tm); 202 if (n == 0) { 203 *p = '\0'; 204 len = 0; 205 } 206 p = sbuf = pbuf += n; 207 len -= n; 208 209 if ((prefix = log_prefix(priority))) { 210 int m = 10 - strlen(prefix); 211 if (m <= 0) { 212 m = 1; 213 } 214 assert(strlen(prefix) < 10); 215 n = snprintf(p, len, "%s:%*c", prefix, m, 0x20); 216 if ((n < 0) || (n >= len)) { 217 n = len - 1; 218 } 219 p = sbuf += n; 220 len -= n; 221 } 222 223 n = vsnprintf(p, len, format, vargs); 224 if ((n < 0) || (n >= len)) { 225 n = len - 1; 226 } 227 p += n; 228 len -= n; 229 230 if (format[strlen(format) - 1] != '\n') { 231 if ((errnum > 0) && (len > 0)) { 232 n = snprintf(p, len, ": %s", strerror(errnum)); 233 if ((n < 0) || (n >= len)) { 234 n = len - 1; 235 } 236 p += n; 237 len -= n; 238 } 239 strcat(p, "\n"); 240 } 241 242 if (msgbuf && (msgbuflen > 0)) { 243 if (sbuf) { 244 strncpy(msgbuf, sbuf, msgbuflen); 245 msgbuf[msgbuflen - 1] = '\0'; 246 } 247 else { 248 msgbuf[0] = '\0'; 249 } 250 } 251 252 if (log_syslog) { 253 syslog(priority, "%s", sbuf); 254 } 255 if (log_file_fp && (priority <= log_file_priority)) { 256 n = fprintf(log_file_fp, "%s", log_file_timestamp ? buf : pbuf); 257 if (n == EOF) { 258 syslog(LOG_CRIT, "Logging stopped due to error"); 259 log_file_fp = NULL; 260 } 261 } 262 return; 263 } 264 265 266 static const char * log_prefix(int priority) 267 { 268 switch (priority) { 269 case LOG_EMERG: 270 return("EMERGENCY"); 271 case LOG_ALERT: 272 return("ALERT"); 273 case LOG_CRIT: 274 return("CRITICAL"); 275 case LOG_ERR: 276 return("ERROR"); 277 case LOG_WARNING: 278 return("WARNING"); 279 case LOG_NOTICE: 280 return("NOTICE"); 281 case LOG_INFO: 282 return("INFO"); 283 case LOG_DEBUG: 284 return("DEBUG"); 285 default: 286 return("UNKNOWN"); 287 } 288 } 289