2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
9 * Copyright (c) 2007, The Storage Networking Industry Association.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * - Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
17 * - Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in
19 * the documentation and/or other materials provided with the
22 * - Neither the name of The Storage Networking Industry Association (SNIA)
23 * nor the names of its contributors may be used to endorse or promote
24 * products derived from this software without specific prior written
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
39 /* Copyright (c) 2007, The Storage Networking Industry Association. */
40 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
42 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
58 #include "ndmpd_log.h"
60 #include "ndmpd_common.h"
62 #define LOG_PATH "/var/log/ndmp"
63 #define LOG_FNAME "ndmplog.%d"
64 #define LOG_FILE_CNT 5
65 #define LOG_FILE_SIZE 4 * 1024 * 1024
66 #define LOG_SIZE_INT 256
68 static boolean_t debug
= B_FALSE
;
69 static boolean_t log_to_stderr
= B_FALSE
;
71 static int ndmp_synclog
= 1;
75 * Since we use buffered file I/O for log file, the thread may lose CPU.
76 * At this time, another thread can destroy the contents of the buffer
77 * that must be written to the log file. The following mutex is used
78 * to allow only one thread to write into the log file.
80 static mutex_t log_lock
;
82 static char *priority_str
[] = {
97 * Append the NDMP working directory path to the specified file
100 mk_pathname(char *fname
, char *path
, int idx
)
102 static char buf
[PATH_MAX
];
103 static char name
[NAME_MAX
];
107 len
= strnlen(path
, PATH_MAX
);
108 fmt
= (path
[len
- 1] == '/') ? "%s%s" : "%s/%s";
110 /* LINTED variable format specifier */
111 (void) snprintf(name
, NAME_MAX
, fname
, idx
);
113 /* LINTED variable format specifier */
114 (void) snprintf(buf
, PATH_MAX
, fmt
, path
, name
);
122 * Open the NDMP log file
125 openlogfile(char *fname
, char *mode
)
127 assert(fname
!= NULL
&& *fname
!= '\0' &&
128 mode
!= NULL
&& *mode
!= '\0');
130 if ((logfp
= fopen(fname
, mode
)) == NULL
) {
131 perror("Error opening logfile");
134 (void) mutex_init(&log_lock
, 0, NULL
);
143 * Add the current time for each log entry
146 log_write_cur_time(void)
152 (void) localtime_r(&secs
, &tm
);
153 (void) fprintf(logfp
, "%2d/%02d %2d:%02d:%02d ",
154 tm
.tm_mon
+ 1, tm
.tm_mday
,
155 tm
.tm_hour
, tm
.tm_min
, tm
.tm_sec
);
162 * The new line at the end of each log
165 add_newline(char *fmt
)
167 if (fmt
[strlen(fmt
) - 1] != '\n')
168 (void) fputc('\n', logfp
);
175 * Append the message to the end of the log
178 log_append(char *msg
)
180 log_write_cur_time();
181 (void) fwrite(msg
, 1, strlen(msg
), logfp
);
184 (void) fflush(logfp
);
191 * Open the log file either for append or write mode. This function should
192 * be called while ndmpd is still running single-threaded and in foreground.
195 ndmp_log_open_file(boolean_t to_stderr
, boolean_t override_debug
)
197 char *fname
, *mode
, *lpath
;
198 char oldfname
[PATH_MAX
];
202 log_to_stderr
= to_stderr
;
204 /* read debug property if it isn't overriden by cmd line option */
208 debug
= ndmpd_get_prop_yorn(NDMP_DEBUG_MODE
) ? B_TRUE
: B_FALSE
;
210 /* Create the debug path if it doesn't exist */
211 lpath
= ndmpd_get_prop(NDMP_DEBUG_PATH
);
212 if ((lpath
== NULL
) || (*lpath
== NULL
))
215 if (stat64(lpath
, &st
) < 0) {
216 if (mkdirp(lpath
, 0755) < 0) {
217 (void) fprintf(stderr
,
218 "Could not create log path %s: %s\n",
219 lpath
, strerror(errno
));
225 * NDMP log file name will be {logfilename}.0 to {logfilename}.5, where
226 * {logfilename}.0 will always be the latest and the {logfilename}.5
227 * will be the oldest available file on the system. We keep maximum of 5
228 * log files. With the new session the files are shifted to next number
229 * and if the last file {logfilename}.5 exist, it will be overwritten
230 * with {logfilename}.4.
233 i
= LOG_FILE_CNT
- 1;
235 fname
= mk_pathname(LOG_FNAME
, lpath
, i
);
236 (void) strncpy(oldfname
, fname
, PATH_MAX
);
237 if (stat64(oldfname
, &st
) == -1) {
242 fname
= mk_pathname(LOG_FNAME
, lpath
, i
+ 1);
243 if (rename(oldfname
, fname
))
244 (void) fprintf(stderr
,
245 "Could not rename %s to %s: %s\n",
246 oldfname
, fname
, strerror(errno
));
251 fname
= mk_pathname(LOG_FNAME
, lpath
, 0);
254 * Append only if debug is not enable.
261 return (openlogfile(fname
, mode
));
265 * ndmp_log_close_file
270 ndmp_log_close_file(void)
273 (void) fclose(logfp
);
276 (void) mutex_destroy(&log_lock
);
280 ndmp_log(ulong_t priority
, char *ndmp_log_info
, char *fmt
, ...)
285 char ndmp_log_buf
[PATH_MAX
+KILOBYTE
];
286 char ndmp_syslog_buf
[PATH_MAX
+KILOBYTE
];
287 char buf
[PATH_MAX
+KILOBYTE
];
290 if ((priority
== LOG_DEBUG
) && !debug
)
293 (void) mutex_lock(&log_lock
);
299 /* Replace text error messages if fmt contains %m */
302 while (((c
= *f
++) != '\0') && (c
!= '\n') &&
303 (b
< &buf
[PATH_MAX
+KILOBYTE
])) {
308 if ((c
= *f
++) != 'm') {
314 if ((errstr
= strerror(errno
)) == NULL
) {
315 (void) snprintf(b
, &buf
[PATH_MAX
+KILOBYTE
] - b
,
318 while ((*errstr
!= '\0') &&
319 (b
< &buf
[PATH_MAX
+KILOBYTE
])) {
320 if (*errstr
== '%') {
321 (void) strncpy(b
, "%%", 2);
334 /* LINTED variable format specifier */
335 (void) vsnprintf(ndmp_syslog_buf
, sizeof (ndmp_syslog_buf
), buf
, args
);
338 /* Send all logs other than debug, to syslog log file. */
339 if (priority
!= LOG_DEBUG
)
340 syslog(priority
, "%s", ndmp_syslog_buf
);
342 /* ndmp_log_buf will have priority string and log info also */
343 (void) snprintf(ndmp_log_buf
, sizeof (ndmp_log_buf
), "%s: %s:%s",
344 priority_str
[priority
], ndmp_log_info
, ndmp_syslog_buf
);
347 log_append(ndmp_log_buf
);
349 /* if ndmpd is running in foreground print log message to stderr */
351 (void) fprintf(stderr
, "%s\n", ndmp_log_buf
);
353 (void) mutex_unlock(&log_lock
);