xref: /illumos-gate/usr/src/cmd/ndmpd/ndmp/ndmpd_log.c (revision b0d8599c)
12654012fSReza Sabdar /*
286c48bbfSReza Sabdar  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
32654012fSReza Sabdar  * Use is subject to license terms.
42654012fSReza Sabdar  */
52654012fSReza Sabdar 
62654012fSReza Sabdar /*
72654012fSReza Sabdar  * BSD 3 Clause License
82654012fSReza Sabdar  *
92654012fSReza Sabdar  * Copyright (c) 2007, The Storage Networking Industry Association.
102654012fSReza Sabdar  *
112654012fSReza Sabdar  * Redistribution and use in source and binary forms, with or without
122654012fSReza Sabdar  * modification, are permitted provided that the following conditions
132654012fSReza Sabdar  * are met:
1478d23b23SToomas Soome  *	- Redistributions of source code must retain the above copyright
152654012fSReza Sabdar  *	  notice, this list of conditions and the following disclaimer.
162654012fSReza Sabdar  *
1778d23b23SToomas Soome  *	- Redistributions in binary form must reproduce the above copyright
182654012fSReza Sabdar  *	  notice, this list of conditions and the following disclaimer in
192654012fSReza Sabdar  *	  the documentation and/or other materials provided with the
202654012fSReza Sabdar  *	  distribution.
212654012fSReza Sabdar  *
222654012fSReza Sabdar  *	- Neither the name of The Storage Networking Industry Association (SNIA)
232654012fSReza Sabdar  *	  nor the names of its contributors may be used to endorse or promote
242654012fSReza Sabdar  *	  products derived from this software without specific prior written
252654012fSReza Sabdar  *	  permission.
262654012fSReza Sabdar  *
272654012fSReza Sabdar  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
282654012fSReza Sabdar  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
292654012fSReza Sabdar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
302654012fSReza Sabdar  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
312654012fSReza Sabdar  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
322654012fSReza Sabdar  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
332654012fSReza Sabdar  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
342654012fSReza Sabdar  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
352654012fSReza Sabdar  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
362654012fSReza Sabdar  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
372654012fSReza Sabdar  * POSSIBILITY OF SUCH DAMAGE.
382654012fSReza Sabdar  */
392654012fSReza Sabdar /* Copyright (c) 2007, The Storage Networking Industry Association. */
402654012fSReza Sabdar /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
41faac71c0SJan Kryl /*
42faac71c0SJan Kryl  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
43faac71c0SJan Kryl  */
442654012fSReza Sabdar 
452654012fSReza Sabdar #include <errno.h>
462654012fSReza Sabdar #include <limits.h>
472654012fSReza Sabdar #include <stdarg.h>
482654012fSReza Sabdar #include <stdio.h>
492654012fSReza Sabdar #include <stdlib.h>
502654012fSReza Sabdar #include <syslog.h>
512654012fSReza Sabdar #include <time.h>
522654012fSReza Sabdar #include <string.h>
532654012fSReza Sabdar #include <sys/stat.h>
542654012fSReza Sabdar #include <unistd.h>
5586c48bbfSReza Sabdar #include <libgen.h>
562654012fSReza Sabdar #include <pthread.h>
572654012fSReza Sabdar #include <errno.h>
582654012fSReza Sabdar #include "ndmpd_log.h"
592654012fSReza Sabdar #include "ndmpd.h"
602654012fSReza Sabdar #include "ndmpd_common.h"
612654012fSReza Sabdar 
62faac71c0SJan Kryl #define	LOG_PATH	"/var/log/ndmp"
632654012fSReza Sabdar #define	LOG_FNAME	"ndmplog.%d"
642654012fSReza Sabdar #define	LOG_FILE_CNT	5
652654012fSReza Sabdar #define	LOG_FILE_SIZE	4 * 1024 * 1024
662654012fSReza Sabdar #define	LOG_SIZE_INT	256
672654012fSReza Sabdar 
68*b0d8599cSToomas Soome char ndmp_log_info[256];
69faac71c0SJan Kryl static boolean_t debug = B_FALSE;
70faac71c0SJan Kryl static boolean_t log_to_stderr = B_FALSE;
712654012fSReza Sabdar static FILE *logfp;
722654012fSReza Sabdar static int ndmp_synclog = 1;
732654012fSReza Sabdar 
742654012fSReza Sabdar /*
752654012fSReza Sabdar  * Since we use buffered file I/O for log file, the thread may lose CPU.
762654012fSReza Sabdar  * At this time, another thread can destroy the contents of the buffer
772654012fSReza Sabdar  * that must be written to the log file.  The following mutex is used
782654012fSReza Sabdar  * to allow only one thread to write into the log file.
792654012fSReza Sabdar  */
80faac71c0SJan Kryl static mutex_t log_lock;
812654012fSReza Sabdar 
822654012fSReza Sabdar static char *priority_str[] = {
832654012fSReza Sabdar 	"EMERGENCY",
842654012fSReza Sabdar 	"ALERT",
852654012fSReza Sabdar 	"CRITICAL",
862654012fSReza Sabdar 	"ERROR",
872654012fSReza Sabdar 	"WARNING",
882654012fSReza Sabdar 	"NOTICE",
892654012fSReza Sabdar 	"INFO",
902654012fSReza Sabdar 	"DEBUG",
912654012fSReza Sabdar };
922654012fSReza Sabdar 
932654012fSReza Sabdar 
942654012fSReza Sabdar /*
952654012fSReza Sabdar  * mk_pathname
962654012fSReza Sabdar  *
972654012fSReza Sabdar  * Append the NDMP working directory path to the specified file
982654012fSReza Sabdar  */
992654012fSReza Sabdar static char *
mk_pathname(char * fname,char * path,int idx)10086c48bbfSReza Sabdar mk_pathname(char *fname, char *path, int idx)
1012654012fSReza Sabdar {
1022654012fSReza Sabdar 	static char buf[PATH_MAX];
1032654012fSReza Sabdar 	static char name[NAME_MAX];
10486c48bbfSReza Sabdar 	char *fmt;
1052654012fSReza Sabdar 	int len;
1062654012fSReza Sabdar 
107faac71c0SJan Kryl 	len = strnlen(path, PATH_MAX);
1082654012fSReza Sabdar 	fmt = (path[len - 1] == '/') ? "%s%s" : "%s/%s";
1092654012fSReza Sabdar 
1102654012fSReza Sabdar 	/* LINTED variable format specifier */
1112654012fSReza Sabdar 	(void) snprintf(name, NAME_MAX, fname, idx);
1122654012fSReza Sabdar 
1132654012fSReza Sabdar 	/* LINTED variable format specifier */
1142654012fSReza Sabdar 	(void) snprintf(buf, PATH_MAX, fmt, path, name);
1152654012fSReza Sabdar 	return (buf);
1162654012fSReza Sabdar }
1172654012fSReza Sabdar 
1182654012fSReza Sabdar 
1192654012fSReza Sabdar /*
1202654012fSReza Sabdar  * openlogfile
1212654012fSReza Sabdar  *
1222654012fSReza Sabdar  * Open the NDMP log file
1232654012fSReza Sabdar  */
1242654012fSReza Sabdar static int
openlogfile(char * fname,char * mode)1252654012fSReza Sabdar openlogfile(char *fname, char *mode)
1262654012fSReza Sabdar {
127faac71c0SJan Kryl 	assert(fname != NULL && *fname != '\0' &&
128faac71c0SJan Kryl 	    mode != NULL && *mode != '\0');
1292654012fSReza Sabdar 
130faac71c0SJan Kryl 	if ((logfp = fopen(fname, mode)) == NULL) {
131faac71c0SJan Kryl 		perror("Error opening logfile");
1322654012fSReza Sabdar 		return (-1);
1332654012fSReza Sabdar 	}
134faac71c0SJan Kryl 	(void) mutex_init(&log_lock, 0, NULL);
1352654012fSReza Sabdar 
136faac71c0SJan Kryl 	return (0);
1372654012fSReza Sabdar }
1382654012fSReza Sabdar 
1392654012fSReza Sabdar 
1402654012fSReza Sabdar /*
1412654012fSReza Sabdar  * log_write_cur_time
1422654012fSReza Sabdar  *
1432654012fSReza Sabdar  * Add the current time for each log entry
1442654012fSReza Sabdar  */
1452654012fSReza Sabdar static void
log_write_cur_time(void)1462654012fSReza Sabdar log_write_cur_time(void)
1472654012fSReza Sabdar {
1482654012fSReza Sabdar 	struct tm tm;
1492654012fSReza Sabdar 	time_t secs;
1502654012fSReza Sabdar 
1512654012fSReza Sabdar 	secs = time(NULL);
1522654012fSReza Sabdar 	(void) localtime_r(&secs, &tm);
1532654012fSReza Sabdar 	(void) fprintf(logfp, "%2d/%02d %2d:%02d:%02d ",
1542654012fSReza Sabdar 	    tm.tm_mon + 1, tm.tm_mday,
1552654012fSReza Sabdar 	    tm.tm_hour, tm.tm_min, tm.tm_sec);
1562654012fSReza Sabdar }
1572654012fSReza Sabdar 
1582654012fSReza Sabdar 
1592654012fSReza Sabdar /*
1602654012fSReza Sabdar  * add_newline
1612654012fSReza Sabdar  *
1622654012fSReza Sabdar  * The new line at the end of each log
1632654012fSReza Sabdar  */
1642654012fSReza Sabdar static void
add_newline(char * fmt)1652654012fSReza Sabdar add_newline(char *fmt)
1662654012fSReza Sabdar {
1672654012fSReza Sabdar 	if (fmt[strlen(fmt) - 1] != '\n')
1682654012fSReza Sabdar 		(void) fputc('\n', logfp);
1692654012fSReza Sabdar }
1702654012fSReza Sabdar 
1712654012fSReza Sabdar 
1722654012fSReza Sabdar /*
1732654012fSReza Sabdar  * log_append
1742654012fSReza Sabdar  *
1752654012fSReza Sabdar  * Append the message to the end of the log
1762654012fSReza Sabdar  */
1772654012fSReza Sabdar static void
log_append(char * msg)1782654012fSReza Sabdar log_append(char *msg)
1792654012fSReza Sabdar {
1802654012fSReza Sabdar 	log_write_cur_time();
1812654012fSReza Sabdar 	(void) fwrite(msg, 1, strlen(msg), logfp);
1822654012fSReza Sabdar 	add_newline(msg);
1832654012fSReza Sabdar 	if (ndmp_synclog)
1842654012fSReza Sabdar 		(void) fflush(logfp);
1852654012fSReza Sabdar }
1862654012fSReza Sabdar 
1872654012fSReza Sabdar 
1882654012fSReza Sabdar /*
1892654012fSReza Sabdar  * ndmp_log_openfile
1902654012fSReza Sabdar  *
191faac71c0SJan Kryl  * Open the log file either for append or write mode. This function should
192faac71c0SJan Kryl  * be called while ndmpd is still running single-threaded and in foreground.
1932654012fSReza Sabdar  */
1942654012fSReza Sabdar int
ndmp_log_open_file(boolean_t to_stderr,boolean_t override_debug)195faac71c0SJan Kryl ndmp_log_open_file(boolean_t to_stderr, boolean_t override_debug)
1962654012fSReza Sabdar {
197faac71c0SJan Kryl 	char *fname, *mode, *lpath;
1982654012fSReza Sabdar 	char oldfname[PATH_MAX];
19986c48bbfSReza Sabdar 	struct stat64 st;
2002654012fSReza Sabdar 	int i;
2012654012fSReza Sabdar 
202faac71c0SJan Kryl 	log_to_stderr = to_stderr;
203faac71c0SJan Kryl 
204faac71c0SJan Kryl 	/* read debug property if it isn't overriden by cmd line option */
205faac71c0SJan Kryl 	if (override_debug)
206faac71c0SJan Kryl 		debug = B_TRUE;
207faac71c0SJan Kryl 	else
208faac71c0SJan Kryl 		debug = ndmpd_get_prop_yorn(NDMP_DEBUG_MODE) ? B_TRUE : B_FALSE;
209faac71c0SJan Kryl 
210faac71c0SJan Kryl 	/* Create the debug path if it doesn't exist */
21186c48bbfSReza Sabdar 	lpath = ndmpd_get_prop(NDMP_DEBUG_PATH);
21278d23b23SToomas Soome 	if ((lpath == NULL) || (*lpath == '\0'))
213faac71c0SJan Kryl 		lpath = LOG_PATH;
21486c48bbfSReza Sabdar 
21586c48bbfSReza Sabdar 	if (stat64(lpath, &st) < 0) {
21686c48bbfSReza Sabdar 		if (mkdirp(lpath, 0755) < 0) {
217faac71c0SJan Kryl 			(void) fprintf(stderr,
218faac71c0SJan Kryl 			    "Could not create log path %s: %s\n",
219faac71c0SJan Kryl 			    lpath, strerror(errno));
22086c48bbfSReza Sabdar 			lpath = "/var";
22186c48bbfSReza Sabdar 		}
22286c48bbfSReza Sabdar 	}
22386c48bbfSReza Sabdar 
2242654012fSReza Sabdar 	/*
2252654012fSReza Sabdar 	 * NDMP log file name will be {logfilename}.0 to {logfilename}.5, where
2262654012fSReza Sabdar 	 * {logfilename}.0 will always be the latest and the {logfilename}.5
2272654012fSReza Sabdar 	 * will be the oldest available file on the system. We keep maximum of 5
2282654012fSReza Sabdar 	 * log files. With the new session the files are shifted to next number
2292654012fSReza Sabdar 	 * and if the last file {logfilename}.5 exist, it will be overwritten
2302654012fSReza Sabdar 	 * with {logfilename}.4.
2312654012fSReza Sabdar 	 */
232faac71c0SJan Kryl 	if (debug) {
2332654012fSReza Sabdar 		i = LOG_FILE_CNT - 1;
2342654012fSReza Sabdar 		while (i >= 0) {
23586c48bbfSReza Sabdar 			fname = mk_pathname(LOG_FNAME, lpath, i);
2362654012fSReza Sabdar 			(void) strncpy(oldfname, fname, PATH_MAX);
23786c48bbfSReza Sabdar 			if (stat64(oldfname, &st) == -1) {
2382654012fSReza Sabdar 				i--;
2392654012fSReza Sabdar 				continue;
2402654012fSReza Sabdar 			}
2412654012fSReza Sabdar 
24286c48bbfSReza Sabdar 			fname = mk_pathname(LOG_FNAME, lpath, i + 1);
2432654012fSReza Sabdar 			if (rename(oldfname, fname))
244faac71c0SJan Kryl 				(void) fprintf(stderr,
245faac71c0SJan Kryl 				    "Could not rename %s to %s: %s\n",
246faac71c0SJan Kryl 				    oldfname, fname, strerror(errno));
2472654012fSReza Sabdar 			i--;
2482654012fSReza Sabdar 		}
2492654012fSReza Sabdar 	}
2502654012fSReza Sabdar 
25186c48bbfSReza Sabdar 	fname = mk_pathname(LOG_FNAME, lpath, 0);
2522654012fSReza Sabdar 
2532654012fSReza Sabdar 	/*
2542654012fSReza Sabdar 	 * Append only if debug is not enable.
2552654012fSReza Sabdar 	 */
256faac71c0SJan Kryl 	if (debug)
2572654012fSReza Sabdar 		mode = "w";
2582654012fSReza Sabdar 	else
2592654012fSReza Sabdar 		mode = "a";
2602654012fSReza Sabdar 
2612654012fSReza Sabdar 	return (openlogfile(fname, mode));
2622654012fSReza Sabdar }
2632654012fSReza Sabdar 
2642654012fSReza Sabdar /*
2652654012fSReza Sabdar  * ndmp_log_close_file
2662654012fSReza Sabdar  *
2672654012fSReza Sabdar  * Close the log file
2682654012fSReza Sabdar  */
2692654012fSReza Sabdar void
ndmp_log_close_file(void)2702654012fSReza Sabdar ndmp_log_close_file(void)
2712654012fSReza Sabdar {
2722654012fSReza Sabdar 	if (logfp != NULL) {
2732654012fSReza Sabdar 		(void) fclose(logfp);
2742654012fSReza Sabdar 		logfp = NULL;
2752654012fSReza Sabdar 	}
276faac71c0SJan Kryl 	(void) mutex_destroy(&log_lock);
2772654012fSReza Sabdar }
2782654012fSReza Sabdar 
2792654012fSReza Sabdar void
ndmp_log(ulong_t priority,char * ndmp_log_info,char * fmt,...)2802654012fSReza Sabdar ndmp_log(ulong_t priority, char *ndmp_log_info, char *fmt, ...)
2812654012fSReza Sabdar {
2822654012fSReza Sabdar 	int c;
2832654012fSReza Sabdar 	va_list args;
2842654012fSReza Sabdar 	char *f, *b;
2852654012fSReza Sabdar 	char ndmp_log_buf[PATH_MAX+KILOBYTE];
2862654012fSReza Sabdar 	char ndmp_syslog_buf[PATH_MAX+KILOBYTE];
2872654012fSReza Sabdar 	char buf[PATH_MAX+KILOBYTE];
2882654012fSReza Sabdar 	char *errstr;
2892654012fSReza Sabdar 
290faac71c0SJan Kryl 	if ((priority == LOG_DEBUG) && !debug)
2912654012fSReza Sabdar 		return;
2922654012fSReza Sabdar 
2932654012fSReza Sabdar 	(void) mutex_lock(&log_lock);
2942654012fSReza Sabdar 
2952654012fSReza Sabdar 	if (priority > 7)
2962654012fSReza Sabdar 		priority = LOG_ERR;
2972654012fSReza Sabdar 
2982654012fSReza Sabdar 	va_start(args, fmt);
2992654012fSReza Sabdar 	/* Replace text error messages if fmt contains %m */
3002654012fSReza Sabdar 	b = buf;
3012654012fSReza Sabdar 	f = fmt;
3022654012fSReza Sabdar 	while (((c = *f++) != '\0') && (c != '\n') &&
3032654012fSReza Sabdar 	    (b < &buf[PATH_MAX+KILOBYTE])) {
3042654012fSReza Sabdar 		if (c != '%') {
3052654012fSReza Sabdar 			*b++ = c;
3062654012fSReza Sabdar 			continue;
3072654012fSReza Sabdar 		}
3082654012fSReza Sabdar 		if ((c = *f++) != 'm') {
3092654012fSReza Sabdar 			*b++ = '%';
3102654012fSReza Sabdar 			*b++ = c;
3112654012fSReza Sabdar 			continue;
3122654012fSReza Sabdar 		}
3132654012fSReza Sabdar 
3142654012fSReza Sabdar 		if ((errstr = strerror(errno)) == NULL) {
3152654012fSReza Sabdar 			(void) snprintf(b, &buf[PATH_MAX+KILOBYTE] - b,
3162654012fSReza Sabdar 			    "error %d", errno);
3172654012fSReza Sabdar 		} else {
3182654012fSReza Sabdar 			while ((*errstr != '\0') &&
3192654012fSReza Sabdar 			    (b < &buf[PATH_MAX+KILOBYTE])) {
3202654012fSReza Sabdar 				if (*errstr == '%') {
3212654012fSReza Sabdar 					(void) strncpy(b, "%%", 2);
3222654012fSReza Sabdar 					b += 2;
3232654012fSReza Sabdar 				} else {
3242654012fSReza Sabdar 					*b++ = *errstr;
3252654012fSReza Sabdar 				}
3262654012fSReza Sabdar 				errstr++;
3272654012fSReza Sabdar 			}
3282654012fSReza Sabdar 			*b = '\0';
3292654012fSReza Sabdar 		}
3302654012fSReza Sabdar 		b += strlen(b);
3312654012fSReza Sabdar 	}
3322654012fSReza Sabdar 	*b = '\0';
3332654012fSReza Sabdar 
3342654012fSReza Sabdar 	/* LINTED variable format specifier */
3352654012fSReza Sabdar 	(void) vsnprintf(ndmp_syslog_buf, sizeof (ndmp_syslog_buf), buf, args);
3362654012fSReza Sabdar 	va_end(args);
3372654012fSReza Sabdar 
3382654012fSReza Sabdar 	/* Send all logs other than debug, to syslog log file. */
3392654012fSReza Sabdar 	if (priority != LOG_DEBUG)
3402654012fSReza Sabdar 		syslog(priority, "%s", ndmp_syslog_buf);
3412654012fSReza Sabdar 
3422654012fSReza Sabdar 	/* ndmp_log_buf will have priority string and log info also */
3432654012fSReza Sabdar 	(void) snprintf(ndmp_log_buf, sizeof (ndmp_log_buf), "%s: %s:%s",
3442654012fSReza Sabdar 	    priority_str[priority], ndmp_log_info, ndmp_syslog_buf);
3452654012fSReza Sabdar 
3462654012fSReza Sabdar 	if (logfp != NULL)
3472654012fSReza Sabdar 		log_append(ndmp_log_buf);
3482654012fSReza Sabdar 
349faac71c0SJan Kryl 	/* if ndmpd is running in foreground print log message to stderr */
350faac71c0SJan Kryl 	if (log_to_stderr)
351faac71c0SJan Kryl 		(void) fprintf(stderr, "%s\n", ndmp_log_buf);
352faac71c0SJan Kryl 
3532654012fSReza Sabdar 	(void) mutex_unlock(&log_lock);
3542654012fSReza Sabdar }
355