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: 142654012fSReza Sabdar * - Redistributions of source code must retain the above copyright 152654012fSReza Sabdar * notice, this list of conditions and the following disclaimer. 162654012fSReza Sabdar * 172654012fSReza Sabdar * - 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 */ 41*faac71c0SJan Kryl /* 42*faac71c0SJan Kryl * Copyright 2014 Nexenta Systems, Inc. All rights reserved. 43*faac71c0SJan 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 62*faac71c0SJan 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*faac71c0SJan Kryl static boolean_t debug = B_FALSE; 69*faac71c0SJan Kryl static boolean_t log_to_stderr = B_FALSE; 702654012fSReza Sabdar static FILE *logfp; 712654012fSReza Sabdar static int ndmp_synclog = 1; 722654012fSReza Sabdar 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 */ 80*faac71c0SJan 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 * 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 107*faac71c0SJan 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 1252654012fSReza Sabdar openlogfile(char *fname, char *mode) 1262654012fSReza Sabdar { 127*faac71c0SJan Kryl assert(fname != NULL && *fname != '\0' && 128*faac71c0SJan Kryl mode != NULL && *mode != '\0'); 1292654012fSReza Sabdar 130*faac71c0SJan Kryl if ((logfp = fopen(fname, mode)) == NULL) { 131*faac71c0SJan Kryl perror("Error opening logfile"); 1322654012fSReza Sabdar return (-1); 1332654012fSReza Sabdar } 134*faac71c0SJan Kryl (void) mutex_init(&log_lock, 0, NULL); 1352654012fSReza Sabdar 136*faac71c0SJan 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 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 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 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 * 191*faac71c0SJan Kryl * Open the log file either for append or write mode. This function should 192*faac71c0SJan Kryl * be called while ndmpd is still running single-threaded and in foreground. 1932654012fSReza Sabdar */ 1942654012fSReza Sabdar int 195*faac71c0SJan Kryl ndmp_log_open_file(boolean_t to_stderr, boolean_t override_debug) 1962654012fSReza Sabdar { 197*faac71c0SJan Kryl char *fname, *mode, *lpath; 1982654012fSReza Sabdar char oldfname[PATH_MAX]; 19986c48bbfSReza Sabdar struct stat64 st; 2002654012fSReza Sabdar int i; 2012654012fSReza Sabdar 202*faac71c0SJan Kryl log_to_stderr = to_stderr; 203*faac71c0SJan Kryl 204*faac71c0SJan Kryl /* read debug property if it isn't overriden by cmd line option */ 205*faac71c0SJan Kryl if (override_debug) 206*faac71c0SJan Kryl debug = B_TRUE; 207*faac71c0SJan Kryl else 208*faac71c0SJan Kryl debug = ndmpd_get_prop_yorn(NDMP_DEBUG_MODE) ? B_TRUE : B_FALSE; 209*faac71c0SJan Kryl 210*faac71c0SJan Kryl /* Create the debug path if it doesn't exist */ 21186c48bbfSReza Sabdar lpath = ndmpd_get_prop(NDMP_DEBUG_PATH); 21286c48bbfSReza Sabdar if ((lpath == NULL) || (*lpath == NULL)) 213*faac71c0SJan Kryl lpath = LOG_PATH; 21486c48bbfSReza Sabdar 21586c48bbfSReza Sabdar if (stat64(lpath, &st) < 0) { 21686c48bbfSReza Sabdar if (mkdirp(lpath, 0755) < 0) { 217*faac71c0SJan Kryl (void) fprintf(stderr, 218*faac71c0SJan Kryl "Could not create log path %s: %s\n", 219*faac71c0SJan 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 */ 232*faac71c0SJan 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)) 244*faac71c0SJan Kryl (void) fprintf(stderr, 245*faac71c0SJan Kryl "Could not rename %s to %s: %s\n", 246*faac71c0SJan 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 */ 256*faac71c0SJan 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 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 } 276*faac71c0SJan Kryl (void) mutex_destroy(&log_lock); 2772654012fSReza Sabdar } 2782654012fSReza Sabdar 2792654012fSReza Sabdar void 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 290*faac71c0SJan 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 349*faac71c0SJan Kryl /* if ndmpd is running in foreground print log message to stderr */ 350*faac71c0SJan Kryl if (log_to_stderr) 351*faac71c0SJan Kryl (void) fprintf(stderr, "%s\n", ndmp_log_buf); 352*faac71c0SJan Kryl 3532654012fSReza Sabdar (void) mutex_unlock(&log_lock); 3542654012fSReza Sabdar } 355