Home | History | Annotate | Download | only in diskomizer
      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