1 /* $NetBSD: log.c,v 1.1.1.2 2009/12/02 00:26:22 haad Exp $ */ 2 3 /* 4 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. 5 * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. 6 * 7 * This file is part of LVM2. 8 * 9 * This copyrighted material is made available to anyone wishing to use, 10 * modify, copy, or redistribute it subject to the terms and conditions 11 * of the GNU Lesser General Public License v.2.1. 12 * 13 * You should have received a copy of the GNU Lesser General Public License 14 * along with this program; if not, write to the Free Software Foundation, 15 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 16 */ 17 18 #include "lib.h" 19 #include "device.h" 20 #include "memlock.h" 21 #include "lvm-string.h" 22 #include "lvm-file.h" 23 #include "defaults.h" 24 25 #include <stdarg.h> 26 #include <syslog.h> 27 28 static FILE *_log_file; 29 static struct device _log_dev; 30 static struct str_list _log_dev_alias; 31 32 static int _syslog = 0; 33 static int _log_to_file = 0; 34 static int _log_direct = 0; 35 static int _log_while_suspended = 0; 36 static int _indent = 1; 37 static int _log_suppress = 0; 38 static char _msg_prefix[30] = " "; 39 static int _already_logging = 0; 40 41 static lvm2_log_fn_t _lvm2_log_fn = NULL; 42 43 static int _lvm_errno = 0; 44 static int _store_errmsg = 0; 45 static char *_lvm_errmsg = NULL; 46 47 void init_log_fn(lvm2_log_fn_t log_fn) 48 { 49 if (log_fn) 50 _lvm2_log_fn = log_fn; 51 else 52 _lvm2_log_fn = NULL; 53 } 54 55 void init_log_file(const char *log_file, int append) 56 { 57 const char *open_mode = append ? "a" : "w"; 58 59 if (!(_log_file = fopen(log_file, open_mode))) { 60 log_sys_error("fopen", log_file); 61 return; 62 } 63 64 _log_to_file = 1; 65 } 66 67 void init_log_direct(const char *log_file, int append) 68 { 69 int open_flags = append ? 0 : O_TRUNC; 70 71 dev_create_file(log_file, &_log_dev, &_log_dev_alias, 1); 72 if (!dev_open_flags(&_log_dev, O_RDWR | O_CREAT | open_flags, 1, 0)) 73 return; 74 75 _log_direct = 1; 76 } 77 78 void init_log_while_suspended(int log_while_suspended) 79 { 80 _log_while_suspended = log_while_suspended; 81 } 82 83 void init_syslog(int facility) 84 { 85 openlog("lvm", LOG_PID, facility); 86 _syslog = 1; 87 } 88 89 int log_suppress(int suppress) 90 { 91 int old_suppress = _log_suppress; 92 93 _log_suppress = suppress; 94 95 return old_suppress; 96 } 97 98 void release_log_memory(void) 99 { 100 if (!_log_direct) 101 return; 102 103 dm_free((char *) _log_dev_alias.str); 104 _log_dev_alias.str = "activate_log file"; 105 } 106 107 void fin_log(void) 108 { 109 if (_log_direct) { 110 dev_close(&_log_dev); 111 _log_direct = 0; 112 } 113 114 if (_log_to_file) { 115 if (dm_fclose(_log_file)) { 116 if (errno) 117 fprintf(stderr, "failed to write log file: %s\n", 118 strerror(errno)); 119 else 120 fprintf(stderr, "failed to write log file\n"); 121 122 } 123 _log_to_file = 0; 124 } 125 } 126 127 void fin_syslog() 128 { 129 if (_syslog) 130 closelog(); 131 _syslog = 0; 132 } 133 134 void init_msg_prefix(const char *prefix) 135 { 136 strncpy(_msg_prefix, prefix, sizeof(_msg_prefix)); 137 _msg_prefix[sizeof(_msg_prefix) - 1] = '\0'; 138 } 139 140 void init_indent(int indent) 141 { 142 _indent = indent; 143 } 144 145 void reset_lvm_errno(int store_errmsg) 146 { 147 _lvm_errno = 0; 148 149 if (_lvm_errmsg) { 150 dm_free(_lvm_errmsg); 151 _lvm_errmsg = NULL; 152 } 153 154 _store_errmsg = store_errmsg; 155 } 156 157 int stored_errno(void) 158 { 159 return _lvm_errno; 160 } 161 162 const char *stored_errmsg(void) 163 { 164 return _lvm_errmsg ? : ""; 165 } 166 167 void print_log(int level, const char *file, int line, int dm_errno, 168 const char *format, ...) 169 { 170 va_list ap; 171 char buf[1024], buf2[4096], locn[4096]; 172 int bufused, n; 173 const char *message; 174 const char *trformat; /* Translated format string */ 175 char *newbuf; 176 int use_stderr = level & _LOG_STDERR; 177 178 level &= ~_LOG_STDERR; 179 180 if (_log_suppress == 2) 181 return; 182 183 if (level <= _LOG_ERR) 184 init_error_message_produced(1); 185 186 trformat = _(format); 187 188 if (dm_errno && !_lvm_errno) 189 _lvm_errno = dm_errno; 190 191 if (_lvm2_log_fn || (_store_errmsg && (level <= _LOG_ERR))) { 192 va_start(ap, format); 193 n = vsnprintf(buf2, sizeof(buf2) - 1, trformat, ap); 194 va_end(ap); 195 196 if (n < 0) { 197 fprintf(stderr, _("vsnprintf failed: skipping external " 198 "logging function")); 199 goto log_it; 200 } 201 202 buf2[sizeof(buf2) - 1] = '\0'; 203 message = &buf2[0]; 204 } 205 206 if (_store_errmsg && (level <= _LOG_ERR)) { 207 if (!_lvm_errmsg) 208 _lvm_errmsg = dm_strdup(message); 209 else if ((newbuf = dm_realloc(_lvm_errmsg, 210 strlen(_lvm_errmsg) + 211 strlen(message) + 2))) { 212 _lvm_errmsg = strcat(newbuf, "\n"); 213 _lvm_errmsg = strcat(newbuf, message); 214 } 215 } 216 217 if (_lvm2_log_fn) { 218 _lvm2_log_fn(level, file, line, 0, message); 219 220 return; 221 } 222 223 log_it: 224 if (!_log_suppress) { 225 if (verbose_level() > _LOG_DEBUG) 226 dm_snprintf(locn, sizeof(locn), "#%s:%d ", 227 file, line); 228 else 229 locn[0] = '\0'; 230 231 va_start(ap, format); 232 switch (level) { 233 case _LOG_DEBUG: 234 if (!strcmp("<backtrace>", format) && 235 verbose_level() <= _LOG_DEBUG) 236 break; 237 if (verbose_level() >= _LOG_DEBUG) { 238 fprintf(stderr, "%s%s%s", locn, log_command_name(), 239 _msg_prefix); 240 if (_indent) 241 fprintf(stderr, " "); 242 vfprintf(stderr, trformat, ap); 243 fputc('\n', stderr); 244 } 245 break; 246 247 case _LOG_INFO: 248 if (verbose_level() >= _LOG_INFO) { 249 fprintf(stderr, "%s%s%s", locn, log_command_name(), 250 _msg_prefix); 251 if (_indent) 252 fprintf(stderr, " "); 253 vfprintf(stderr, trformat, ap); 254 fputc('\n', stderr); 255 } 256 break; 257 case _LOG_NOTICE: 258 if (verbose_level() >= _LOG_NOTICE) { 259 fprintf(stderr, "%s%s%s", locn, log_command_name(), 260 _msg_prefix); 261 if (_indent) 262 fprintf(stderr, " "); 263 vfprintf(stderr, trformat, ap); 264 fputc('\n', stderr); 265 } 266 break; 267 case _LOG_WARN: 268 if (verbose_level() >= _LOG_WARN) { 269 fprintf(use_stderr ? stderr : stdout, "%s%s", 270 log_command_name(), _msg_prefix); 271 vfprintf(use_stderr ? stderr : stdout, trformat, ap); 272 fputc('\n', use_stderr ? stderr : stdout); 273 } 274 break; 275 case _LOG_ERR: 276 if (verbose_level() >= _LOG_ERR) { 277 fprintf(stderr, "%s%s%s", locn, log_command_name(), 278 _msg_prefix); 279 vfprintf(stderr, trformat, ap); 280 fputc('\n', stderr); 281 } 282 break; 283 case _LOG_FATAL: 284 default: 285 if (verbose_level() >= _LOG_FATAL) { 286 fprintf(stderr, "%s%s%s", locn, log_command_name(), 287 _msg_prefix); 288 vfprintf(stderr, trformat, ap); 289 fputc('\n', stderr); 290 } 291 break; 292 } 293 va_end(ap); 294 } 295 296 if (level > debug_level()) 297 return; 298 299 if (_log_to_file && (_log_while_suspended || !memlock())) { 300 fprintf(_log_file, "%s:%d %s%s", file, line, log_command_name(), 301 _msg_prefix); 302 303 va_start(ap, format); 304 vfprintf(_log_file, trformat, ap); 305 va_end(ap); 306 307 fprintf(_log_file, "\n"); 308 fflush(_log_file); 309 } 310 311 if (_syslog && (_log_while_suspended || !memlock())) { 312 va_start(ap, format); 313 vsyslog(level, trformat, ap); 314 va_end(ap); 315 } 316 317 /* FIXME This code is unfinished - pre-extend & condense. */ 318 if (!_already_logging && _log_direct && memlock()) { 319 _already_logging = 1; 320 memset(&buf, ' ', sizeof(buf)); 321 bufused = 0; 322 if ((n = dm_snprintf(buf, sizeof(buf) - bufused - 1, 323 "%s:%d %s%s", file, line, log_command_name(), 324 _msg_prefix)) == -1) 325 goto done; 326 327 bufused += n; 328 329 va_start(ap, format); 330 n = vsnprintf(buf + bufused - 1, sizeof(buf) - bufused - 1, 331 trformat, ap); 332 va_end(ap); 333 bufused += n; 334 335 done: 336 buf[bufused - 1] = '\n'; 337 buf[bufused] = '\n'; 338 buf[sizeof(buf) - 1] = '\n'; 339 /* FIXME real size bufused */ 340 dev_append(&_log_dev, sizeof(buf), buf); 341 _already_logging = 0; 342 } 343 } 344