1 /* $NetBSD: log.c,v 1.1.1.1 2008/12/22 00:17:52 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 void init_log_fn(lvm2_log_fn_t log_fn) 44 { 45 if (log_fn) 46 _lvm2_log_fn = log_fn; 47 else 48 _lvm2_log_fn = NULL; 49 } 50 51 void init_log_file(const char *log_file, int append) 52 { 53 const char *open_mode = append ? "a" : "w"; 54 55 if (!(_log_file = fopen(log_file, open_mode))) { 56 log_sys_error("fopen", log_file); 57 return; 58 } 59 60 _log_to_file = 1; 61 } 62 63 void init_log_direct(const char *log_file, int append) 64 { 65 int open_flags = append ? 0 : O_TRUNC; 66 67 dev_create_file(log_file, &_log_dev, &_log_dev_alias, 1); 68 if (!dev_open_flags(&_log_dev, O_RDWR | O_CREAT | open_flags, 1, 0)) 69 return; 70 71 _log_direct = 1; 72 } 73 74 void init_log_while_suspended(int log_while_suspended) 75 { 76 _log_while_suspended = log_while_suspended; 77 } 78 79 void init_syslog(int facility) 80 { 81 openlog("lvm", LOG_PID, facility); 82 _syslog = 1; 83 } 84 85 int log_suppress(int suppress) 86 { 87 int old_suppress = _log_suppress; 88 89 _log_suppress = suppress; 90 91 return old_suppress; 92 } 93 94 void release_log_memory(void) 95 { 96 if (!_log_direct) 97 return; 98 99 dm_free((char *) _log_dev_alias.str); 100 _log_dev_alias.str = "activate_log file"; 101 } 102 103 void fin_log(void) 104 { 105 if (_log_direct) { 106 dev_close(&_log_dev); 107 _log_direct = 0; 108 } 109 110 if (_log_to_file) { 111 if (dm_fclose(_log_file)) { 112 if (errno) 113 fprintf(stderr, "failed to write log file: %s\n", 114 strerror(errno)); 115 else 116 fprintf(stderr, "failed to write log file\n"); 117 118 } 119 _log_to_file = 0; 120 } 121 } 122 123 void fin_syslog() 124 { 125 if (_syslog) 126 closelog(); 127 _syslog = 0; 128 } 129 130 void init_msg_prefix(const char *prefix) 131 { 132 strncpy(_msg_prefix, prefix, sizeof(_msg_prefix)); 133 _msg_prefix[sizeof(_msg_prefix) - 1] = '\0'; 134 } 135 136 void init_indent(int indent) 137 { 138 _indent = indent; 139 } 140 141 void print_log(int level, const char *file, int line, const char *format, ...) 142 { 143 va_list ap; 144 char buf[1024], buf2[4096], locn[4096]; 145 int bufused, n; 146 const char *message; 147 const char *trformat; /* Translated format string */ 148 int use_stderr = level & _LOG_STDERR; 149 150 level &= ~_LOG_STDERR; 151 152 if (_log_suppress == 2) 153 return; 154 155 if (level <= _LOG_ERR) 156 init_error_message_produced(1); 157 158 trformat = _(format); 159 160 if (_lvm2_log_fn) { 161 va_start(ap, format); 162 n = vsnprintf(buf2, sizeof(buf2) - 1, trformat, ap); 163 va_end(ap); 164 165 if (n < 0) { 166 fprintf(stderr, _("vsnprintf failed: skipping external " 167 "logging function")); 168 goto log_it; 169 } 170 171 buf2[sizeof(buf2) - 1] = '\0'; 172 message = &buf2[0]; 173 174 _lvm2_log_fn(level, file, line, message); 175 176 return; 177 } 178 179 log_it: 180 if (!_log_suppress) { 181 if (verbose_level() > _LOG_DEBUG) 182 dm_snprintf(locn, sizeof(locn), "#%s:%d ", 183 file, line); 184 else 185 locn[0] = '\0'; 186 187 va_start(ap, format); 188 switch (level) { 189 case _LOG_DEBUG: 190 if (!strcmp("<backtrace>", format) && 191 verbose_level() <= _LOG_DEBUG) 192 break; 193 if (verbose_level() >= _LOG_DEBUG) { 194 fprintf(stderr, "%s%s%s", locn, log_command_name(), 195 _msg_prefix); 196 if (_indent) 197 fprintf(stderr, " "); 198 vfprintf(stderr, trformat, ap); 199 fputc('\n', stderr); 200 } 201 break; 202 203 case _LOG_INFO: 204 if (verbose_level() >= _LOG_INFO) { 205 fprintf(stderr, "%s%s%s", locn, log_command_name(), 206 _msg_prefix); 207 if (_indent) 208 fprintf(stderr, " "); 209 vfprintf(stderr, trformat, ap); 210 fputc('\n', stderr); 211 } 212 break; 213 case _LOG_NOTICE: 214 if (verbose_level() >= _LOG_NOTICE) { 215 fprintf(stderr, "%s%s%s", locn, log_command_name(), 216 _msg_prefix); 217 if (_indent) 218 fprintf(stderr, " "); 219 vfprintf(stderr, trformat, ap); 220 fputc('\n', stderr); 221 } 222 break; 223 case _LOG_WARN: 224 if (verbose_level() >= _LOG_WARN) { 225 fprintf(use_stderr ? stderr : stdout, "%s%s", 226 log_command_name(), _msg_prefix); 227 vfprintf(use_stderr ? stderr : stdout, trformat, ap); 228 fputc('\n', use_stderr ? stderr : stdout); 229 } 230 break; 231 case _LOG_ERR: 232 if (verbose_level() >= _LOG_ERR) { 233 fprintf(stderr, "%s%s%s", locn, log_command_name(), 234 _msg_prefix); 235 vfprintf(stderr, trformat, ap); 236 fputc('\n', stderr); 237 } 238 break; 239 case _LOG_FATAL: 240 default: 241 if (verbose_level() >= _LOG_FATAL) { 242 fprintf(stderr, "%s%s%s", locn, log_command_name(), 243 _msg_prefix); 244 vfprintf(stderr, trformat, ap); 245 fputc('\n', stderr); 246 } 247 break; 248 } 249 va_end(ap); 250 } 251 252 if (level > debug_level()) 253 return; 254 255 if (_log_to_file && (_log_while_suspended || !memlock())) { 256 fprintf(_log_file, "%s:%d %s%s", file, line, log_command_name(), 257 _msg_prefix); 258 259 va_start(ap, format); 260 vfprintf(_log_file, trformat, ap); 261 va_end(ap); 262 263 fprintf(_log_file, "\n"); 264 fflush(_log_file); 265 } 266 267 if (_syslog && (_log_while_suspended || !memlock())) { 268 va_start(ap, format); 269 vsyslog(level, trformat, ap); 270 va_end(ap); 271 } 272 273 /* FIXME This code is unfinished - pre-extend & condense. */ 274 if (!_already_logging && _log_direct && memlock()) { 275 _already_logging = 1; 276 memset(&buf, ' ', sizeof(buf)); 277 bufused = 0; 278 if ((n = dm_snprintf(buf, sizeof(buf) - bufused - 1, 279 "%s:%d %s%s", file, line, log_command_name(), 280 _msg_prefix)) == -1) 281 goto done; 282 283 bufused += n; 284 285 va_start(ap, format); 286 n = vsnprintf(buf + bufused - 1, sizeof(buf) - bufused - 1, 287 trformat, ap); 288 va_end(ap); 289 bufused += n; 290 291 done: 292 buf[bufused - 1] = '\n'; 293 buf[bufused] = '\n'; 294 buf[sizeof(buf) - 1] = '\n'; 295 /* FIXME real size bufused */ 296 dev_append(&_log_dev, sizeof(buf), buf); 297 _already_logging = 0; 298 } 299 } 300