1/* 2 * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. 3 * Copyright (c) 2002-2006 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_log.h> 48#include <stdlib.h> 49#include <stdio.h> 50#include <stdarg.h> 51#include <fcntl.h> 52#include <sys/types.h> 53#include <sys/stat.h> 54#include <errno.h> 55 56static int log_exit_count = 0; 57 58#ifndef WIN32 59#include <sys/time.h> 60#include <unistd.h> 61#include <complib/cl_timer.h> 62 63static char *month_str[] = { 64 "Jan", 65 "Feb", 66 "Mar", 67 "Apr", 68 "May", 69 "Jun", 70 "Jul", 71 "Aug", 72 "Sep", 73 "Oct", 74 "Nov", 75 "Dec" 76}; 77#else 78void OsmReportState(IN const char *p_str); 79#endif /* ndef WIN32 */ 80 81#ifndef WIN32 82 83static void truncate_log_file(osm_log_t * const p_log) 84{ 85 int fd = fileno(p_log->out_port); 86 if (ftruncate(fd, 0) < 0) 87 fprintf(stderr, "truncate_log_file: cannot truncate: %s\n", 88 strerror(errno)); 89 if (lseek(fd, 0, SEEK_SET) < 0) 90 fprintf(stderr, "truncate_log_file: cannot rewind: %s\n", 91 strerror(errno)); 92 p_log->count = 0; 93} 94 95#else /* Windows */ 96 97static void truncate_log_file(osm_log_t * const p_log) 98{ 99 fprintf(stderr, 100 "truncate_log_file: cannot truncate on windows system (yet)\n"); 101} 102#endif /* ndef WIN32 */ 103 104void osm_log(IN osm_log_t * const p_log, 105 IN const osm_log_level_t verbosity, IN const char *p_str, ...) 106{ 107 char buffer[LOG_ENTRY_SIZE_MAX]; 108 va_list args; 109 int ret; 110#ifdef WIN32 111 SYSTEMTIME st; 112 uint32_t pid = GetCurrentThreadId(); 113#else 114 pid_t pid = 0; 115 time_t tim; 116 struct tm result; 117 uint64_t time_usecs; 118 uint32_t usecs; 119#endif /* WIN32 */ 120 121 /* If this is a call to syslog - always print it */ 122 if (!(verbosity & (OSM_LOG_SYS | p_log->level))) 123 return; 124 125 va_start(args, p_str); 126 vsprintf(buffer, p_str, args); 127 va_end(args); 128 129 /* this is a call to the syslog */ 130 if (verbosity & OSM_LOG_SYS) { 131 syslog(LOG_INFO, "%s\n", buffer); 132 133 /* SYSLOG should go to stdout too */ 134 if (p_log->out_port != stdout) { 135 printf("%s\n", buffer); 136 fflush(stdout); 137 } 138#ifdef WIN32 139 OsmReportState(buffer); 140#endif /* WIN32 */ 141 } 142 143 /* regular log to default out_port */ 144 cl_spinlock_acquire(&p_log->lock); 145 146 if (p_log->max_size && p_log->count > p_log->max_size) { 147 /* truncate here */ 148 fprintf(stderr, 149 "osm_log: log file exceeds the limit %lu. Truncating.\n", 150 p_log->max_size); 151 truncate_log_file(p_log); 152 } 153#ifdef WIN32 154 GetLocalTime(&st); 155_retry: 156 ret = 157 fprintf(p_log->out_port, 158 "[%02d:%02d:%02d:%03d][%04X] 0x%02x -> %s", 159 st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, 160 pid, verbosity, buffer); 161#else 162 time_usecs = cl_get_time_stamp(); 163 tim = time_usecs / 1000000; 164 usecs = time_usecs % 1000000; 165 localtime_r(&tim, &result); 166 pid = pthread_self(); 167_retry: 168 ret = 169 fprintf(p_log->out_port, 170 "%s %02d %02d:%02d:%02d %06d [%04X] 0x%02x -> %s", 171 (result.tm_mon < 172 12 ? month_str[result.tm_mon] : "???"), 173 result.tm_mday, result.tm_hour, result.tm_min, 174 result.tm_sec, usecs, pid, verbosity, buffer); 175#endif 176 177 /* flush log */ 178 if (ret > 0 && 179 (p_log->flush || (verbosity & (OSM_LOG_ERROR | OSM_LOG_SYS))) 180 && fflush(p_log->out_port) < 0) 181 ret = -1; 182 183 if (ret >= 0) { 184 log_exit_count = 0; 185 p_log->count += ret; 186 } else if (log_exit_count < 3) { 187 log_exit_count++; 188 if (errno == ENOSPC && p_log->max_size) { 189 fprintf(stderr, 190 "osm_log: write failed: %s. Truncating log file.\n", 191 strerror(errno)); 192 truncate_log_file(p_log); 193 goto _retry; 194 } 195 fprintf(stderr, "osm_log: write failed: %s\n", strerror(errno)); 196 } 197 198 cl_spinlock_release(&p_log->lock); 199} 200 201void osm_log_raw(IN osm_log_t * const p_log, 202 IN const osm_log_level_t verbosity, IN const char *p_buf) 203{ 204 if (p_log->level & verbosity) { 205 cl_spinlock_acquire(&p_log->lock); 206 printf("%s", p_buf); 207 cl_spinlock_release(&p_log->lock); 208 209 /* 210 Flush log on errors too. 211 */ 212 if (p_log->flush || (verbosity & OSM_LOG_ERROR)) 213 fflush(stdout); 214 } 215} 216 217void osm_log_msg_box(IN osm_log_t * log, osm_log_level_t level, 218 const char *func_name, const char *msg) 219{ 220#define MSG_BOX_LENGTH 66 221 char buf[MSG_BOX_LENGTH + 1]; 222 int i, n; 223 224 if (!osm_log_is_active(log, level)) 225 return; 226 227 n = (MSG_BOX_LENGTH - strlen(msg)) / 2 - 1; 228 if (n < 0) 229 n = 0; 230 for (i = 0; i < n; i++) 231 sprintf(buf + i, "*"); 232 n += snprintf(buf + n, sizeof(buf) - n, " %s ", msg); 233 for (i = n; i < MSG_BOX_LENGTH; i++) 234 buf[i] = '*'; 235 buf[i] = '\0'; 236 237 osm_log(log, level, "%s:\n\n\n" 238 "*********************************************" 239 "*********************\n%s\n" 240 "*********************************************" 241 "*********************\n\n\n", func_name, buf); 242} 243 244boolean_t osm_is_debug(void) 245{ 246#if defined( _DEBUG_ ) 247 return TRUE; 248#else 249 return FALSE; 250#endif /* defined( _DEBUG_ ) */ 251} 252 253static int open_out_port(IN osm_log_t * p_log) 254{ 255 struct stat st; 256 257 if (p_log->accum_log_file) 258 p_log->out_port = fopen(p_log->log_file_name, "a+"); 259 else 260 p_log->out_port = fopen(p_log->log_file_name, "w+"); 261 262 if (!p_log->out_port) { 263 syslog(LOG_CRIT, "Cannot open file \'%s\' for %s: %s\n", 264 p_log->log_file_name, 265 p_log->accum_log_file ? "appending" : "writing", 266 strerror(errno)); 267 fprintf(stderr, "Cannot open file \'%s\': %s\n", 268 p_log->log_file_name, strerror(errno)); 269 return -1; 270 } 271 272 if (fstat(fileno(p_log->out_port), &st) == 0) 273 p_log->count = st.st_size; 274 275 syslog(LOG_NOTICE, "%s log file opened\n", p_log->log_file_name); 276 277 if (p_log->daemon) { 278 dup2(fileno(p_log->out_port), 0); 279 dup2(fileno(p_log->out_port), 1); 280 dup2(fileno(p_log->out_port), 2); 281 } 282 283 return 0; 284} 285 286int osm_log_reopen_file(osm_log_t * p_log) 287{ 288 int ret; 289 290 if (p_log->out_port == stdout || p_log->out_port == stderr) 291 return 0; 292 cl_spinlock_acquire(&p_log->lock); 293 fclose(p_log->out_port); 294 ret = open_out_port(p_log); 295 cl_spinlock_release(&p_log->lock); 296 return ret; 297} 298 299ib_api_status_t osm_log_init_v2(IN osm_log_t * const p_log, 300 IN const boolean_t flush, 301 IN const uint8_t log_flags, 302 IN const char *log_file, 303 IN const unsigned long max_size, 304 IN const boolean_t accum_log_file) 305{ 306 p_log->level = log_flags; 307 p_log->flush = flush; 308 p_log->count = 0; 309 p_log->max_size = max_size; 310 p_log->accum_log_file = accum_log_file; 311 p_log->log_file_name = (char *)log_file; 312 313 openlog("OpenSM", LOG_CONS | LOG_PID, LOG_USER); 314 315 if (log_file == NULL || !strcmp(log_file, "-") || 316 !strcmp(log_file, "stdout")) 317 p_log->out_port = stdout; 318 else if (!strcmp(log_file, "stderr")) 319 p_log->out_port = stderr; 320 else if (open_out_port(p_log)) 321 return IB_ERROR; 322 323 if (cl_spinlock_init(&p_log->lock) == CL_SUCCESS) 324 return IB_SUCCESS; 325 else 326 return IB_ERROR; 327} 328 329ib_api_status_t osm_log_init(IN osm_log_t * const p_log, 330 IN const boolean_t flush, 331 IN const uint8_t log_flags, 332 IN const char *log_file, 333 IN const boolean_t accum_log_file) 334{ 335 return osm_log_init_v2(p_log, flush, log_flags, log_file, 0, 336 accum_log_file); 337} 338