1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "@(#)log.c 1.20 09/05/26 SMI" 28 29 /* 30 * logging routines. 31 */ 32 #ifndef _LARGEFILE64_SOURCE 33 #define _LARGEFILE64_SOURCE 34 #endif 35 #include <stdio.h> 36 #include <stdarg.h> 37 #include <thread.h> 38 #include <stdlib.h> 39 #include <unistd.h> 40 #include <errno.h> 41 #include <strings.h> 42 #include <sys/types.h> 43 #include <ctype.h> 44 #include "diskomizer64mpism.h" 45 #include <diskomizer/log.h> 46 #include "args.h" 47 #include "locks.h" 48 #include "time.h" 49 50 struct log { 51 FILE *fp; 52 long log_instance; 53 int log_depth; 54 }; 55 56 static struct facility { 57 char *str; 58 int fac; 59 } faclities[] = { 60 "kern", LOG_KERN, 61 "user", LOG_USER, 62 "mail", LOG_MAIL, 63 "daemon", LOG_DAEMON, 64 "auth", LOG_AUTH, 65 "lpr", LOG_LPR, 66 "news", LOG_NEWS, 67 "uucp", LOG_UUCP, 68 "cron", LOG_CRON, 69 "local0", LOG_LOCAL0, 70 "local1", LOG_LOCAL1, 71 "local2", LOG_LOCAL2, 72 "local3", LOG_LOCAL3, 73 "local4", LOG_LOCAL4, 74 "local5", LOG_LOCAL5, 75 "local6", LOG_LOCAL6, 76 "local7", LOG_LOCAL7, 77 NULL, -1 78 }; 79 /* 80 * This is ordered so dont insert any elements or change the 81 * order. 82 */ 83 static struct priority { 84 char *str; 85 int pri; 86 } priorities[] = { 87 {"EMERG", LOG_EMERG}, 88 {"ALERT", LOG_ALERT}, 89 {"CRIT", LOG_CRIT}, 90 {"ERR", LOG_ERR}, 91 {"WARNING", LOG_WARNING}, 92 {"NOTICE", LOG_NOTICE}, 93 {"INFO", LOG_INFO}, 94 {"DEBUG", LOG_DEBUG}, 95 {NULL, -1} 96 }; 97 98 static int stderr_pri = LOG_WARNING; 99 static int stdout_pri = LOG_INFO; 100 static struct log log; 101 static char time_error_str[1024]; 102 static void vlog_syslog(int priority, const char *message, va_list ap); 103 static void vlog_nosyslog(int priority, const char *message, va_list ap); 104 105 static void (*do_vlog)(int priority, const char *message, va_list ap) = 106 vlog_nosyslog; 107 #define LOG_INSTANCE(A) ((A.log_instance * opts.nprocs) + this_proc()) 108 109 void 110 vlog(int pri, const char *fmt, va_list ap) 111 { 112 do_vlog(pri, fmt, ap); 113 } 114 115 /*PRINTFLIKE2*/ 116 void 117 plog(int pri, const char *fmt, ...) 118 { 119 va_list ap; 120 va_start(ap, fmt); 121 do_vlog(pri, fmt, ap); 122 } 123 124 /*PRINTFLIKE2*/ 125 void 126 dlog(int pri, const char *fmt, ...) 127 { 128 va_list ap; 129 va_start(ap, fmt); 130 if (opts.debug_report_errors_as_discovered) { 131 do_vlog(pri, fmt, ap); 132 } 133 } 134 135 static void 136 vtime_log(int pri, time_t tyme, const char *fmt, va_list ap) 137 { 138 const char *nfmt; 139 char *timestr = alloc_time_str(tyme); 140 int len = strlen(fmt); 141 142 while (len && isspace(fmt[len-1])) { 143 len--; 144 } 145 146 if (timestr == NULL || (nfmt = (char *)malloc(strlen(timestr) + 4 + 147 len)) == NULL) { 148 nfmt = fmt; 149 } else { 150 (void) sprintf((char *)nfmt, "%.*s: %s\n", len, fmt, timestr); 151 free(timestr); 152 } 153 154 do_vlog(pri, nfmt, ap); 155 156 if (nfmt != fmt) 157 free((char *)nfmt); 158 } 159 160 /*PRINTFLIKE3*/ 161 void 162 time_log(int pri, time_t tyme, const char *fmt, ...) 163 { 164 va_list ap; 165 va_start(ap, fmt); 166 167 vtime_log(pri, tyme, fmt, ap); 168 } 169 170 /*PRINTFLIKE3*/ 171 void 172 dtime_log(int pri, time_t tyme, const char *fmt, ...) 173 { 174 va_list ap; 175 va_start(ap, fmt); 176 177 if (opts.debug_report_errors_as_discovered) { 178 vtime_log(pri, tyme, fmt, ap); 179 } 180 } 181 182 /*PRINTFLIKE2*/ 183 void 184 time_now_log(int pri, const char *fmt, ...) 185 { 186 struct timeval tv; 187 va_list ap; 188 va_start(ap, fmt); 189 190 while (my_gettimeofday(&tv, NULL) == -1) 191 pperror("gettimeofday"); 192 vtime_log(pri, tv.tv_sec, fmt, ap); 193 } 194 195 void 196 new_log_transaction(FILE *fp) 197 { 198 199 if (log.log_depth != 0) { 200 char *log_time = alloc_time_now(); 201 if (log_time == NULL) { 202 struct timeval tv; 203 if (my_gettimeofday(&tv, NULL) == -1) 204 tv.tv_sec = 0; 205 206 log_time = time_error_str; 207 (void) snprintf(time_error_str, 208 sizeof (time_error_str), "%ld", tv.tv_sec); 209 } 210 pfprintf(log.fp, "ERROR %ld end: %s\n", LOG_INSTANCE(log), 211 log_time); 212 pfprintf(log.fp, "\n"); 213 214 #ifndef __lint 215 if (log_time != time_error_str) { 216 free(log_time); 217 } 218 #endif /* __lint */ 219 log.log_depth = 0; 220 log.log_instance++; 221 } 222 log.fp = fp; 223 } 224 225 int 226 get_error_instance_number() 227 { 228 return (LOG_INSTANCE(log)); 229 } 230 231 static void 232 vtfprintf(FILE *fd, const char *fmt, va_list ap) 233 { 234 const char *nfmt; 235 if ((nfmt = (char *)malloc(20 + strlen(fmt))) == NULL) { 236 nfmt = fmt; 237 } else { 238 (void) sprintf((char *)nfmt, "PID %d: %s", getpid(), fmt); 239 } 240 241 (void) vfprintf(fd, nfmt, ap); 242 (void) fflush(fd); 243 (void) fsync(fileno(fd)); 244 if (nfmt != fmt) 245 free((char *)nfmt); 246 } 247 248 static void 249 ptfprintf(FILE *fd, char *fmt, ...) 250 { 251 va_list ap; 252 va_start(ap, fmt); 253 vtfprintf(fd, fmt, ap); 254 } 255 256 static void 257 start_log(FILE *fp) 258 { 259 if (log.fp == fp && log.log_depth == 0) { 260 char *log_time = alloc_time_now(); 261 if (log_time == NULL) { 262 struct timeval tv; 263 if (my_gettimeofday(&tv, NULL) == -1) 264 tv.tv_sec = 0; 265 266 log_time = time_error_str; 267 (void) snprintf(time_error_str, 268 sizeof (time_error_str), "%ld", tv.tv_sec); 269 } 270 ptfprintf(log.fp, "ERROR %ld begin: %s\n", LOG_INSTANCE(log), 271 log_time); 272 #ifndef __lint 273 if (log_time != time_error_str) { 274 free(log_time); 275 } 276 #endif 277 log.log_depth++; 278 } 279 } 280 281 static void 282 vpfprintf(FILE *fd, const char *fmt, va_list ap) 283 { 284 void (*lock_enter)(void); 285 void (*lock_exit)(void); 286 287 if (fd == stdout) { 288 lock_enter = mutex->stdout_enter; 289 lock_exit = mutex->stdout_exit; 290 } else { 291 lock_enter = mutex->stderr_enter; 292 lock_exit = mutex->stderr_exit; 293 } 294 lock_enter(); 295 296 start_log(fd); 297 298 vtfprintf(fd, fmt, ap); 299 300 lock_exit(); 301 } 302 303 /* 304 * pprintf and pfprintf. 305 * 306 * Old style interfaces. The new way is to log all messages using plog() 307 * and tlog() with a priority that will route it into the correct file 308 * and or syslog 309 */ 310 /*PRINTFLIKE1*/ 311 void 312 pprintf(char *fmt, ...) 313 { 314 va_list ap; 315 va_start(ap, fmt); 316 317 do_vlog(stdout_pri, fmt, ap); 318 } 319 320 /*PRINTFLIKE2*/ 321 void 322 pfprintf(FILE *fp, const char *fmt, ...) 323 { 324 va_list ap; 325 va_start(ap, fmt); 326 327 if (fp == stderr || fp == stdout) 328 do_vlog(stderr_pri, fmt, ap); 329 else 330 vpfprintf(fp, fmt, ap); 331 } 332 333 /*PRINTFLIKE2*/ 334 void 335 dfprintf(FILE *fp, const char *fmt, ...) 336 { 337 va_list ap; 338 va_start(ap, fmt); 339 340 341 if (opts.debug_report_errors_as_discovered) { 342 if (fp == stderr || fp == stdout) { 343 do_vlog(stderr_pri, fmt, ap); 344 } else { 345 vpfprintf(fp, fmt, ap); 346 } 347 } 348 } 349 350 /*PRINTFLIKE1*/ 351 void 352 pperror(char *fmt, ...) 353 { 354 char *nfmt; 355 char *errstr = strerror(errno); 356 va_list ap; 357 va_start(ap, fmt); 358 359 if ((nfmt = (char *)malloc(4 + strlen(errstr) + strlen(fmt))) == 360 NULL) { 361 nfmt = fmt; 362 } else { 363 (void) sprintf(nfmt, "%s: %s\n", fmt, errstr); 364 } 365 do_vlog(LOG_ERR, nfmt, ap); 366 if (nfmt != fmt) 367 free(nfmt); 368 } 369 370 /*PRINTFLIKE1*/ 371 static void 372 debug_printf(const char *fmt, ...) 373 { 374 va_list ap; 375 va_start(ap, fmt); 376 do_vlog(LOG_DEBUG, fmt, ap); 377 } 378 379 static void 380 vlog_nosyslog(int pri, const char *fmt, va_list ap) 381 { 382 char buf[1024]; 383 char *nfmt; 384 385 if (opts.obscure_report_priority) { 386 (void) snprintf(buf, sizeof (buf), 387 "%s %s", priorities[pri].str, fmt); 388 nfmt = buf; 389 } else { 390 nfmt = (char *)fmt; 391 } 392 if (pri <= stderr_pri) { 393 vpfprintf(stderr, nfmt, ap); 394 } else if (pri <= stdout_pri) { 395 vpfprintf(stdout, nfmt, ap); 396 } 397 } 398 399 static void 400 vlog_syslog(int priority, const char *message, va_list ap) 401 { 402 vsyslog(priority, message, ap); 403 vlog_nosyslog(priority, message, ap); 404 } 405 static int 406 get_priority(const char *str) 407 { 408 struct priority *pri; 409 for (pri = &priorities[0]; pri->str != NULL; pri++) { 410 if (strcasecmp(pri->str, str) == 0) { 411 return (pri->pri); 412 } 413 } 414 plog(LOG_ERR, "Unknown priority %s\n", str); 415 return (-1); 416 } 417 static void 418 get_facility(const char *str, const char *ident) 419 { 420 struct facility *fac; 421 for (fac = &faclities[0]; fac->str != NULL; fac++) { 422 if (strcasecmp(fac->str, str) == 0) { 423 int i; 424 do_vlog = vlog_syslog; 425 openlog(ident, LOG_NDELAY|LOG_PID, fac->fac); 426 if ((i = get_priority( 427 opts.syslog_log_upto_priority)) != -1) { 428 (void) setlogmask(LOG_UPTO(i)); 429 } 430 return; 431 } 432 } 433 } 434 void 435 popenlog(const char *ident) 436 { 437 int i; 438 if ((i = get_priority(opts.stderr_priority)) != -1) 439 stderr_pri = i; 440 if ((i = get_priority(opts.stdout_priority)) != -1) 441 stdout_pri = i; 442 443 if (opts.syslog_facility != NULL) { 444 get_facility(opts.syslog_facility, ident); 445 } 446 } 447 void 448 plog_number_of_bytes(int pri, unsigned long long x, 449 char *singular, char *plural) 450 { 451 char *str = x != 1 ? plural : singular; 452 const char *units; 453 long long save = x; 454 int j; 455 int after_decimal_point; 456 /* 457 * All the units that fit in 64 bits: 458 * kilo, mega, giga, tera, peta, exa 459 */ 460 static const char *all_units[] = { "K", "M", "G", "T", "P", "E" }; 461 462 units = NULL; 463 464 for (j = 0; j < (sizeof (all_units) / sizeof (all_units[0])); j++) { 465 if (x / 1024) { 466 after_decimal_point = ((x * 1000) / 1024) % 1000; 467 x = x / 1024; 468 units = all_units[j]; 469 } else { 470 break; 471 } 472 } 473 474 if (units) { 475 /* Round up it necessary */ 476 if (after_decimal_point % 10 >= 5) { 477 after_decimal_point += 10; 478 } 479 /* loose the least significant digit */ 480 after_decimal_point /= 10; 481 482 plog(pri, "%#llx, %lld, %s (%lld.%.2d %s)\n", 483 save, save, str, x, after_decimal_point, units); 484 } else { 485 plog(pri, "%#llx, %lld, %s\n", save, save, str); 486 } 487 488 } 489