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 59static 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 66static 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 81void OsmReportState(IN const char *p_str); 82#endif /* ndef __WIN__ */ 83 84#ifndef __WIN__ 85 86static 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 100static 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 113void 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 224void 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 340void 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 356void 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 383void 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 411boolean_t osm_is_debug(void) 412{ 413#if defined( _DEBUG_ ) 414 return TRUE; 415#else 416 return FALSE; 417#endif /* defined( _DEBUG_ ) */ 418} 419 420static 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 453int 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 466ib_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 495ib_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 503osm_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 509void 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 515void 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