1 /*
2 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
3 * Copyright (c) 2002-2007 Mellanox Technologies LTD. All rights reserved.
4 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5 *
6 * This software is available to you under a choice of one of two
7 * licenses. You may choose to be licensed under the terms of the GNU
8 * General Public License (GPL) Version 2, available from the file
9 * COPYING in the main directory of this source tree, or the
10 * OpenIB.org BSD license below:
11 *
12 * Redistribution and use in source and binary forms, with or
13 * without modification, are permitted provided that the following
14 * conditions are met:
15 *
16 * - Redistributions of source code must retain the above
17 * copyright notice, this list of conditions and the following
18 * disclaimer.
19 *
20 * - Redistributions in binary form must reproduce the above
21 * copyright notice, this list of conditions and the following
22 * disclaimer in the documentation and/or other materials
23 * provided with the distribution.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32 * SOFTWARE.
33 *
34 */
35
36 /*
37 * Abstract:
38 * Implementation of osm_log_t.
39 * This object represents the log file.
40 * This object is part of the opensm family of objects.
41 */
42
43 #if HAVE_CONFIG_H
44 # include <config.h>
45 #endif /* HAVE_CONFIG_H */
46
47 #include <opensm/osm_file_ids.h>
48 #define FILE_ID OSM_FILE_LOG_C
49 #include <opensm/osm_log.h>
50 #include <stdlib.h>
51 #include <stdio.h>
52 #include <stdarg.h>
53 #include <fcntl.h>
54 #include <sys/types.h>
55 #include <sys/stat.h>
56 #include <errno.h>
57 #include <pthread_np.h>
58
59 static int log_exit_count = 0;
60
61 #ifndef __WIN__
62 #include <sys/time.h>
63 #include <unistd.h>
64 #include <complib/cl_timer.h>
65
66 static const char *month_str[] = {
67 "Jan",
68 "Feb",
69 "Mar",
70 "Apr",
71 "May",
72 "Jun",
73 "Jul",
74 "Aug",
75 "Sep",
76 "Oct",
77 "Nov",
78 "Dec"
79 };
80 #else
81 void OsmReportState(IN const char *p_str);
82 #endif /* ndef __WIN__ */
83
84 #ifndef __WIN__
85
truncate_log_file(osm_log_t * p_log)86 static void truncate_log_file(osm_log_t * p_log)
87 {
88 int fd = fileno(p_log->out_port);
89 if (ftruncate(fd, 0) < 0)
90 fprintf(stderr, "truncate_log_file: cannot truncate: %s\n",
91 strerror(errno));
92 if (lseek(fd, 0, SEEK_SET) < 0)
93 fprintf(stderr, "truncate_log_file: cannot rewind: %s\n",
94 strerror(errno));
95 p_log->count = 0;
96 }
97
98 #else /* Windows */
99
truncate_log_file(osm_log_t * p_log)100 static void truncate_log_file(osm_log_t * p_log)
101 {
102 int fd = _fileno(p_log->out_port);
103 HANDLE hFile = (HANDLE) _get_osfhandle(fd);
104
105 if (_lseek(fd, 0, SEEK_SET) < 0)
106 fprintf(stderr, "truncate_log_file: cannot rewind: %s\n",
107 strerror(errno));
108 SetEndOfFile(hFile);
109 p_log->count = 0;
110 }
111 #endif /* ndef __WIN__ */
112
osm_log(IN osm_log_t * p_log,IN osm_log_level_t verbosity,IN const char * p_str,...)113 void osm_log(IN osm_log_t * p_log, IN osm_log_level_t verbosity,
114 IN const char *p_str, ...)
115 {
116 char buffer[LOG_ENTRY_SIZE_MAX];
117 va_list args;
118 int ret;
119 #ifdef __WIN__
120 SYSTEMTIME st;
121 uint32_t pid = GetCurrentThreadId();
122 #else
123 pid_t pid;
124 time_t tim;
125 struct tm result;
126 uint64_t time_usecs;
127 uint32_t usecs;
128 #endif /* __WIN__ */
129
130 /* If this is a call to syslog - always print it */
131 if (!(verbosity & p_log->level))
132 return;
133
134 va_start(args, p_str);
135 #ifndef __WIN__
136 if (p_log->log_prefix == NULL)
137 vsprintf(buffer, p_str, args);
138 else {
139 int n = snprintf(buffer, sizeof(buffer), "%s: ", p_log->log_prefix);
140 vsprintf(buffer + n, p_str, args);
141 }
142 #else
143 if (p_log->log_prefix == NULL)
144 _vsnprintf(buffer, 1024, (LPSTR)p_str, args);
145 else {
146 int n = snprintf(buffer, sizeof(buffer), "%s: ", p_log->log_prefix);
147 _vsnprintf(buffer + n, (1024 - n), (LPSTR)p_str, args);
148 }
149 #endif
150 va_end(args);
151
152 /* this is a call to the syslog */
153 if (verbosity & OSM_LOG_SYS) {
154 syslog(LOG_INFO, "%s\n", buffer);
155
156 /* SYSLOG should go to stdout too */
157 if (p_log->out_port != stdout) {
158 printf("%s\n", buffer);
159 fflush(stdout);
160 }
161 #ifdef __WIN__
162 OsmReportState(buffer);
163 #endif /* __WIN__ */
164 }
165
166 /* regular log to default out_port */
167 cl_spinlock_acquire(&p_log->lock);
168
169 if (p_log->max_size && p_log->count > p_log->max_size) {
170 /* truncate here */
171 fprintf(stderr,
172 "osm_log: log file exceeds the limit %lu. Truncating.\n",
173 p_log->max_size);
174 truncate_log_file(p_log);
175 }
176 #ifdef __WIN__
177 GetLocalTime(&st);
178 _retry:
179 ret =
180 fprintf(p_log->out_port,
181 "[%02d:%02d:%02d:%03d][%04X] 0x%02x -> %s",
182 st.wHour, st.wMinute, st.wSecond, st.wMilliseconds,
183 pid, verbosity, buffer);
184 #else
185 time_usecs = cl_get_time_stamp();
186 tim = time_usecs / 1000000;
187 usecs = time_usecs % 1000000;
188 localtime_r(&tim, &result);
189 pid = pthread_getthreadid_np();
190 _retry:
191 ret =
192 fprintf(p_log->out_port,
193 "%s %02d %02d:%02d:%02d %06d [%04X] 0x%02x -> %s",
194 (result.tm_mon <
195 12 ? month_str[result.tm_mon] : "???"),
196 result.tm_mday, result.tm_hour, result.tm_min,
197 result.tm_sec, usecs, pid, verbosity, buffer);
198 #endif
199
200 /* flush log */
201 if (ret > 0 &&
202 (p_log->flush || (verbosity & (OSM_LOG_ERROR | OSM_LOG_SYS)))
203 && fflush(p_log->out_port) < 0)
204 ret = -1;
205
206 if (ret >= 0) {
207 log_exit_count = 0;
208 p_log->count += ret;
209 } else if (log_exit_count < 3) {
210 log_exit_count++;
211 if (errno == ENOSPC && p_log->max_size) {
212 fprintf(stderr,
213 "osm_log: write failed: %s. Truncating log file.\n",
214 strerror(errno));
215 truncate_log_file(p_log);
216 goto _retry;
217 }
218 fprintf(stderr, "osm_log: write failed: %s\n", strerror(errno));
219 }
220
221 cl_spinlock_release(&p_log->lock);
222 }
223
osm_log_v2(IN osm_log_t * p_log,IN osm_log_level_t verbosity,IN const int file_id,IN const char * p_str,...)224 void osm_log_v2(IN osm_log_t * p_log, IN osm_log_level_t verbosity,
225 IN const int file_id, IN const char *p_str, ...)
226 {
227 char buffer[LOG_ENTRY_SIZE_MAX];
228 va_list args;
229 int ret;
230 #ifdef __WIN__
231 SYSTEMTIME st;
232 uint32_t pid = GetCurrentThreadId();
233 #else
234 struct timeval tv;
235 pid_t pid = 0;
236 time_t tim;
237 struct tm result;
238 uint64_t time_usecs;
239 uint32_t usecs;
240 #endif /* __WIN__ */
241
242 /* If this is a call to syslog - always print it */
243 if (!(verbosity & p_log->level)) {
244 if (!(verbosity & p_log->per_mod_log_tbl[file_id]))
245 return;
246 }
247
248 va_start(args, p_str);
249 #ifndef __WIN__
250 if (p_log->log_prefix == NULL)
251 vsprintf(buffer, p_str, args);
252 else {
253 int n = snprintf(buffer, sizeof(buffer), "%s: ", p_log->log_prefix);
254 vsprintf(buffer + n, p_str, args);
255 }
256 #else
257 if (p_log->log_prefix == NULL)
258 _vsnprintf(buffer, 1024, (LPSTR)p_str, args);
259 else {
260 int n = snprintf(buffer, sizeof(buffer), "%s: ", p_log->log_prefix);
261 _vsnprintf(buffer + n, (1024 - n), (LPSTR)p_str, args);
262 }
263 #endif
264 va_end(args);
265
266 /* this is a call to the syslog */
267 if (verbosity & OSM_LOG_SYS) {
268 syslog(LOG_INFO, "%s\n", buffer);
269
270 /* SYSLOG should go to stdout too */
271 if (p_log->out_port != stdout) {
272 printf("%s\n", buffer);
273 fflush(stdout);
274 }
275 #ifdef __WIN__
276 OsmReportState(buffer);
277 #endif /* __WIN__ */
278 }
279
280 /* regular log to default out_port */
281 cl_spinlock_acquire(&p_log->lock);
282
283 if (p_log->max_size && p_log->count > p_log->max_size) {
284 /* truncate here */
285 fprintf(stderr,
286 "osm_log: log file exceeds the limit %lu. Truncating.\n",
287 p_log->max_size);
288 truncate_log_file(p_log);
289 }
290 #ifdef __WIN__
291 GetLocalTime(&st);
292 _retry:
293 ret =
294 fprintf(p_log->out_port,
295 "[%02d:%02d:%02d:%03d][%04X] 0x%02x -> %s",
296 st.wHour, st.wMinute, st.wSecond, st.wMilliseconds,
297 pid, verbosity, buffer);
298 #else
299 gettimeofday(&tv, NULL);
300 /* Convert the time of day into a microsecond timestamp */
301 time_usecs = ((uint64_t) tv.tv_sec * 1000000) + (uint64_t) tv.tv_usec;
302 tim = time_usecs / 1000000;
303 usecs = time_usecs % 1000000;
304 localtime_r(&tim, &result);
305 pid = pthread_getthreadid_np();
306 _retry:
307 ret =
308 fprintf(p_log->out_port,
309 "%s %02d %02d:%02d:%02d %06d [%04X] 0x%02x -> %s",
310 (result.tm_mon <
311 12 ? month_str[result.tm_mon] : "???"),
312 result.tm_mday, result.tm_hour, result.tm_min,
313 result.tm_sec, usecs, pid, verbosity, buffer);
314 #endif
315
316 /* flush log */
317 if (ret > 0 &&
318 (p_log->flush || (verbosity & (OSM_LOG_ERROR | OSM_LOG_SYS)))
319 && fflush(p_log->out_port) < 0)
320 ret = -1;
321
322 if (ret >= 0) {
323 log_exit_count = 0;
324 p_log->count += ret;
325 } else if (log_exit_count < 3) {
326 log_exit_count++;
327 if (errno == ENOSPC && p_log->max_size) {
328 fprintf(stderr,
329 "osm_log: write failed: %s. Truncating log file.\n",
330 strerror(errno));
331 truncate_log_file(p_log);
332 goto _retry;
333 }
334 fprintf(stderr, "osm_log: write failed: %s\n", strerror(errno));
335 }
336
337 cl_spinlock_release(&p_log->lock);
338 }
339
osm_log_raw(IN osm_log_t * p_log,IN osm_log_level_t verbosity,IN const char * p_buf)340 void osm_log_raw(IN osm_log_t * p_log, IN osm_log_level_t verbosity,
341 IN const char *p_buf)
342 {
343 if (p_log->level & verbosity) {
344 cl_spinlock_acquire(&p_log->lock);
345 printf("%s", p_buf);
346 cl_spinlock_release(&p_log->lock);
347
348 /*
349 Flush log on errors too.
350 */
351 if (p_log->flush || (verbosity & OSM_LOG_ERROR))
352 fflush(stdout);
353 }
354 }
355
osm_log_msg_box(IN osm_log_t * log,osm_log_level_t level,const char * func_name,const char * msg)356 void osm_log_msg_box(IN osm_log_t * log, osm_log_level_t level,
357 const char *func_name, const char *msg)
358 {
359 #define MSG_BOX_LENGTH 66
360 char buf[MSG_BOX_LENGTH + 1];
361 int i, n;
362
363 if (!osm_log_is_active(log, level))
364 return;
365
366 n = (MSG_BOX_LENGTH - strlen(msg)) / 2 - 1;
367 if (n < 0)
368 n = 0;
369 for (i = 0; i < n; i++)
370 sprintf(buf + i, "*");
371 n += snprintf(buf + n, sizeof(buf) - n, " %s ", msg);
372 for (i = n; i < MSG_BOX_LENGTH; i++)
373 buf[i] = '*';
374 buf[i] = '\0';
375
376 osm_log(log, level, "%s:\n\n\n"
377 "*********************************************"
378 "*********************\n%s\n"
379 "*********************************************"
380 "*********************\n\n\n", func_name, buf);
381 }
382
osm_log_msg_box_v2(IN osm_log_t * log,osm_log_level_t level,const int file_id,const char * func_name,const char * msg)383 void osm_log_msg_box_v2(IN osm_log_t * log, osm_log_level_t level,
384 const int file_id, const char *func_name,
385 const char *msg)
386 {
387 #define MSG_BOX_LENGTH 66
388 char buf[MSG_BOX_LENGTH + 1];
389 int i, n;
390
391 if (!osm_log_is_active_v2(log, level, file_id))
392 return;
393
394 n = (MSG_BOX_LENGTH - strlen(msg)) / 2 - 1;
395 if (n < 0)
396 n = 0;
397 for (i = 0; i < n; i++)
398 sprintf(buf + i, "*");
399 n += snprintf(buf + n, sizeof(buf) - n, " %s ", msg);
400 for (i = n; i < MSG_BOX_LENGTH; i++)
401 buf[i] = '*';
402 buf[i] = '\0';
403
404 osm_log_v2(log, level, file_id, "%s:\n\n\n"
405 "*********************************************"
406 "*********************\n%s\n"
407 "*********************************************"
408 "*********************\n\n\n", func_name, buf);
409 }
410
osm_is_debug(void)411 boolean_t osm_is_debug(void)
412 {
413 #if defined( _DEBUG_ )
414 return TRUE;
415 #else
416 return FALSE;
417 #endif /* defined( _DEBUG_ ) */
418 }
419
open_out_port(IN osm_log_t * p_log)420 static int open_out_port(IN osm_log_t * p_log)
421 {
422 struct stat st;
423
424 if (p_log->accum_log_file)
425 p_log->out_port = fopen(p_log->log_file_name, "a+");
426 else
427 p_log->out_port = fopen(p_log->log_file_name, "w+");
428
429 if (!p_log->out_port) {
430 syslog(LOG_CRIT, "Cannot open file \'%s\' for %s: %s\n",
431 p_log->log_file_name,
432 p_log->accum_log_file ? "appending" : "writing",
433 strerror(errno));
434 fprintf(stderr, "Cannot open file \'%s\': %s\n",
435 p_log->log_file_name, strerror(errno));
436 return -1;
437 }
438
439 if (fstat(fileno(p_log->out_port), &st) == 0)
440 p_log->count = st.st_size;
441
442 syslog(LOG_NOTICE, "%s log file opened\n", p_log->log_file_name);
443
444 if (p_log->daemon) {
445 dup2(fileno(p_log->out_port), 0);
446 dup2(fileno(p_log->out_port), 1);
447 dup2(fileno(p_log->out_port), 2);
448 }
449
450 return 0;
451 }
452
osm_log_reopen_file(osm_log_t * p_log)453 int osm_log_reopen_file(osm_log_t * p_log)
454 {
455 int ret;
456
457 if (p_log->out_port == stdout || p_log->out_port == stderr)
458 return 0;
459 cl_spinlock_acquire(&p_log->lock);
460 fclose(p_log->out_port);
461 ret = open_out_port(p_log);
462 cl_spinlock_release(&p_log->lock);
463 return ret;
464 }
465
osm_log_init_v2(IN osm_log_t * p_log,IN boolean_t flush,IN uint8_t log_flags,IN const char * log_file,IN unsigned long max_size,IN boolean_t accum_log_file)466 ib_api_status_t osm_log_init_v2(IN osm_log_t * p_log, IN boolean_t flush,
467 IN uint8_t log_flags, IN const char *log_file,
468 IN unsigned long max_size,
469 IN boolean_t accum_log_file)
470 {
471 p_log->level = log_flags | OSM_LOG_SYS;
472 p_log->flush = flush;
473 p_log->count = 0;
474 p_log->max_size = max_size << 20; /* convert size in MB to bytes */
475 p_log->accum_log_file = accum_log_file;
476 p_log->log_file_name = (char *)log_file;
477 memset(p_log->per_mod_log_tbl, 0, sizeof(p_log->per_mod_log_tbl));
478
479 openlog("OpenSM", LOG_CONS | LOG_PID, LOG_USER);
480
481 if (log_file == NULL || !strcmp(log_file, "-") ||
482 !strcmp(log_file, "stdout"))
483 p_log->out_port = stdout;
484 else if (!strcmp(log_file, "stderr"))
485 p_log->out_port = stderr;
486 else if (open_out_port(p_log))
487 return IB_ERROR;
488
489 if (cl_spinlock_init(&p_log->lock) == CL_SUCCESS)
490 return IB_SUCCESS;
491 else
492 return IB_ERROR;
493 }
494
osm_log_init(IN osm_log_t * p_log,IN boolean_t flush,IN uint8_t log_flags,IN const char * log_file,IN boolean_t accum_log_file)495 ib_api_status_t osm_log_init(IN osm_log_t * p_log, IN boolean_t flush,
496 IN uint8_t log_flags, IN const char *log_file,
497 IN boolean_t accum_log_file)
498 {
499 return osm_log_init_v2(p_log, flush, log_flags, log_file, 0,
500 accum_log_file);
501 }
502
osm_get_log_per_module(IN osm_log_t * p_log,IN const int file_id)503 osm_log_level_t osm_get_log_per_module(IN osm_log_t * p_log,
504 IN const int file_id)
505 {
506 return p_log->per_mod_log_tbl[file_id];
507 }
508
osm_set_log_per_module(IN osm_log_t * p_log,IN const int file_id,IN osm_log_level_t level)509 void osm_set_log_per_module(IN osm_log_t * p_log, IN const int file_id,
510 IN osm_log_level_t level)
511 {
512 p_log->per_mod_log_tbl[file_id] = level;
513 }
514
osm_reset_log_per_module(IN osm_log_t * p_log)515 void osm_reset_log_per_module(IN osm_log_t * p_log)
516 {
517 memset(p_log->per_mod_log_tbl, 0, sizeof(p_log->per_mod_log_tbl));
518 }
519