1219820Sjeff/* 2219820Sjeff * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. 3219820Sjeff * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. 4219820Sjeff * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. 5219820Sjeff * 6219820Sjeff * This software is available to you under a choice of one of two 7219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 8219820Sjeff * General Public License (GPL) Version 2, available from the file 9219820Sjeff * COPYING in the main directory of this source tree, or the 10219820Sjeff * OpenIB.org BSD license below: 11219820Sjeff * 12219820Sjeff * Redistribution and use in source and binary forms, with or 13219820Sjeff * without modification, are permitted provided that the following 14219820Sjeff * conditions are met: 15219820Sjeff * 16219820Sjeff * - Redistributions of source code must retain the above 17219820Sjeff * copyright notice, this list of conditions and the following 18219820Sjeff * disclaimer. 19219820Sjeff * 20219820Sjeff * - Redistributions in binary form must reproduce the above 21219820Sjeff * copyright notice, this list of conditions and the following 22219820Sjeff * disclaimer in the documentation and/or other materials 23219820Sjeff * provided with the distribution. 24219820Sjeff * 25219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32219820Sjeff * SOFTWARE. 33219820Sjeff * 34219820Sjeff */ 35219820Sjeff 36219820Sjeff/* 37219820Sjeff * Abstract: 38219820Sjeff * Implementation of osm_log_t. 39219820Sjeff * This object represents the log file. 40219820Sjeff * This object is part of the opensm family of objects. 41219820Sjeff */ 42219820Sjeff 43219820Sjeff#if HAVE_CONFIG_H 44219820Sjeff# include <config.h> 45219820Sjeff#endif /* HAVE_CONFIG_H */ 46219820Sjeff 47219820Sjeff#include <opensm/osm_log.h> 48219820Sjeff#include <stdlib.h> 49219820Sjeff#include <stdio.h> 50219820Sjeff#include <stdarg.h> 51219820Sjeff#include <fcntl.h> 52219820Sjeff#include <sys/types.h> 53219820Sjeff#include <sys/stat.h> 54219820Sjeff#include <errno.h> 55219820Sjeff 56219820Sjeffstatic int log_exit_count = 0; 57219820Sjeff 58219820Sjeff#ifndef WIN32 59219820Sjeff#include <sys/time.h> 60219820Sjeff#include <unistd.h> 61219820Sjeff#include <complib/cl_timer.h> 62219820Sjeff 63219820Sjeffstatic char *month_str[] = { 64219820Sjeff "Jan", 65219820Sjeff "Feb", 66219820Sjeff "Mar", 67219820Sjeff "Apr", 68219820Sjeff "May", 69219820Sjeff "Jun", 70219820Sjeff "Jul", 71219820Sjeff "Aug", 72219820Sjeff "Sep", 73219820Sjeff "Oct", 74219820Sjeff "Nov", 75219820Sjeff "Dec" 76219820Sjeff}; 77219820Sjeff#else 78219820Sjeffvoid OsmReportState(IN const char *p_str); 79219820Sjeff#endif /* ndef WIN32 */ 80219820Sjeff 81219820Sjeff#ifndef WIN32 82219820Sjeff 83219820Sjeffstatic void truncate_log_file(osm_log_t * const p_log) 84219820Sjeff{ 85219820Sjeff int fd = fileno(p_log->out_port); 86219820Sjeff if (ftruncate(fd, 0) < 0) 87219820Sjeff fprintf(stderr, "truncate_log_file: cannot truncate: %s\n", 88219820Sjeff strerror(errno)); 89219820Sjeff if (lseek(fd, 0, SEEK_SET) < 0) 90219820Sjeff fprintf(stderr, "truncate_log_file: cannot rewind: %s\n", 91219820Sjeff strerror(errno)); 92219820Sjeff p_log->count = 0; 93219820Sjeff} 94219820Sjeff 95219820Sjeff#else /* Windows */ 96219820Sjeff 97219820Sjeffstatic void truncate_log_file(osm_log_t * const p_log) 98219820Sjeff{ 99219820Sjeff fprintf(stderr, 100219820Sjeff "truncate_log_file: cannot truncate on windows system (yet)\n"); 101219820Sjeff} 102219820Sjeff#endif /* ndef WIN32 */ 103219820Sjeff 104219820Sjeffvoid osm_log(IN osm_log_t * const p_log, 105219820Sjeff IN const osm_log_level_t verbosity, IN const char *p_str, ...) 106219820Sjeff{ 107219820Sjeff char buffer[LOG_ENTRY_SIZE_MAX]; 108219820Sjeff va_list args; 109219820Sjeff int ret; 110219820Sjeff#ifdef WIN32 111219820Sjeff SYSTEMTIME st; 112219820Sjeff uint32_t pid = GetCurrentThreadId(); 113219820Sjeff#else 114219820Sjeff pid_t pid = 0; 115219820Sjeff time_t tim; 116219820Sjeff struct tm result; 117219820Sjeff uint64_t time_usecs; 118219820Sjeff uint32_t usecs; 119219820Sjeff#endif /* WIN32 */ 120219820Sjeff 121219820Sjeff /* If this is a call to syslog - always print it */ 122219820Sjeff if (!(verbosity & (OSM_LOG_SYS | p_log->level))) 123219820Sjeff return; 124219820Sjeff 125219820Sjeff va_start(args, p_str); 126219820Sjeff vsprintf(buffer, p_str, args); 127219820Sjeff va_end(args); 128219820Sjeff 129219820Sjeff /* this is a call to the syslog */ 130219820Sjeff if (verbosity & OSM_LOG_SYS) { 131219820Sjeff syslog(LOG_INFO, "%s\n", buffer); 132219820Sjeff 133219820Sjeff /* SYSLOG should go to stdout too */ 134219820Sjeff if (p_log->out_port != stdout) { 135219820Sjeff printf("%s\n", buffer); 136219820Sjeff fflush(stdout); 137219820Sjeff } 138219820Sjeff#ifdef WIN32 139219820Sjeff OsmReportState(buffer); 140219820Sjeff#endif /* WIN32 */ 141219820Sjeff } 142219820Sjeff 143219820Sjeff /* regular log to default out_port */ 144219820Sjeff cl_spinlock_acquire(&p_log->lock); 145219820Sjeff 146219820Sjeff if (p_log->max_size && p_log->count > p_log->max_size) { 147219820Sjeff /* truncate here */ 148219820Sjeff fprintf(stderr, 149219820Sjeff "osm_log: log file exceeds the limit %lu. Truncating.\n", 150219820Sjeff p_log->max_size); 151219820Sjeff truncate_log_file(p_log); 152219820Sjeff } 153219820Sjeff#ifdef WIN32 154219820Sjeff GetLocalTime(&st); 155219820Sjeff_retry: 156219820Sjeff ret = 157219820Sjeff fprintf(p_log->out_port, 158219820Sjeff "[%02d:%02d:%02d:%03d][%04X] 0x%02x -> %s", 159219820Sjeff st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, 160219820Sjeff pid, verbosity, buffer); 161219820Sjeff#else 162219820Sjeff time_usecs = cl_get_time_stamp(); 163219820Sjeff tim = time_usecs / 1000000; 164219820Sjeff usecs = time_usecs % 1000000; 165219820Sjeff localtime_r(&tim, &result); 166219820Sjeff pid = pthread_self(); 167219820Sjeff_retry: 168219820Sjeff ret = 169219820Sjeff fprintf(p_log->out_port, 170219820Sjeff "%s %02d %02d:%02d:%02d %06d [%04X] 0x%02x -> %s", 171219820Sjeff (result.tm_mon < 172219820Sjeff 12 ? month_str[result.tm_mon] : "???"), 173219820Sjeff result.tm_mday, result.tm_hour, result.tm_min, 174219820Sjeff result.tm_sec, usecs, pid, verbosity, buffer); 175219820Sjeff#endif 176219820Sjeff 177219820Sjeff /* flush log */ 178219820Sjeff if (ret > 0 && 179219820Sjeff (p_log->flush || (verbosity & (OSM_LOG_ERROR | OSM_LOG_SYS))) 180219820Sjeff && fflush(p_log->out_port) < 0) 181219820Sjeff ret = -1; 182219820Sjeff 183219820Sjeff if (ret >= 0) { 184219820Sjeff log_exit_count = 0; 185219820Sjeff p_log->count += ret; 186219820Sjeff } else if (log_exit_count < 3) { 187219820Sjeff log_exit_count++; 188219820Sjeff if (errno == ENOSPC && p_log->max_size) { 189219820Sjeff fprintf(stderr, 190219820Sjeff "osm_log: write failed: %s. Truncating log file.\n", 191219820Sjeff strerror(errno)); 192219820Sjeff truncate_log_file(p_log); 193219820Sjeff goto _retry; 194219820Sjeff } 195219820Sjeff fprintf(stderr, "osm_log: write failed: %s\n", strerror(errno)); 196219820Sjeff } 197219820Sjeff 198219820Sjeff cl_spinlock_release(&p_log->lock); 199219820Sjeff} 200219820Sjeff 201219820Sjeffvoid osm_log_raw(IN osm_log_t * const p_log, 202219820Sjeff IN const osm_log_level_t verbosity, IN const char *p_buf) 203219820Sjeff{ 204219820Sjeff if (p_log->level & verbosity) { 205219820Sjeff cl_spinlock_acquire(&p_log->lock); 206219820Sjeff printf("%s", p_buf); 207219820Sjeff cl_spinlock_release(&p_log->lock); 208219820Sjeff 209219820Sjeff /* 210219820Sjeff Flush log on errors too. 211219820Sjeff */ 212219820Sjeff if (p_log->flush || (verbosity & OSM_LOG_ERROR)) 213219820Sjeff fflush(stdout); 214219820Sjeff } 215219820Sjeff} 216219820Sjeff 217219820Sjeffvoid osm_log_msg_box(IN osm_log_t * log, osm_log_level_t level, 218219820Sjeff const char *func_name, const char *msg) 219219820Sjeff{ 220219820Sjeff#define MSG_BOX_LENGTH 66 221219820Sjeff char buf[MSG_BOX_LENGTH + 1]; 222219820Sjeff int i, n; 223219820Sjeff 224219820Sjeff if (!osm_log_is_active(log, level)) 225219820Sjeff return; 226219820Sjeff 227219820Sjeff n = (MSG_BOX_LENGTH - strlen(msg)) / 2 - 1; 228219820Sjeff if (n < 0) 229219820Sjeff n = 0; 230219820Sjeff for (i = 0; i < n; i++) 231219820Sjeff sprintf(buf + i, "*"); 232219820Sjeff n += snprintf(buf + n, sizeof(buf) - n, " %s ", msg); 233219820Sjeff for (i = n; i < MSG_BOX_LENGTH; i++) 234219820Sjeff buf[i] = '*'; 235219820Sjeff buf[i] = '\0'; 236219820Sjeff 237219820Sjeff osm_log(log, level, "%s:\n\n\n" 238219820Sjeff "*********************************************" 239219820Sjeff "*********************\n%s\n" 240219820Sjeff "*********************************************" 241219820Sjeff "*********************\n\n\n", func_name, buf); 242219820Sjeff} 243219820Sjeff 244219820Sjeffboolean_t osm_is_debug(void) 245219820Sjeff{ 246219820Sjeff#if defined( _DEBUG_ ) 247219820Sjeff return TRUE; 248219820Sjeff#else 249219820Sjeff return FALSE; 250219820Sjeff#endif /* defined( _DEBUG_ ) */ 251219820Sjeff} 252219820Sjeff 253219820Sjeffstatic int open_out_port(IN osm_log_t * p_log) 254219820Sjeff{ 255219820Sjeff struct stat st; 256219820Sjeff 257219820Sjeff if (p_log->accum_log_file) 258219820Sjeff p_log->out_port = fopen(p_log->log_file_name, "a+"); 259219820Sjeff else 260219820Sjeff p_log->out_port = fopen(p_log->log_file_name, "w+"); 261219820Sjeff 262219820Sjeff if (!p_log->out_port) { 263219820Sjeff syslog(LOG_CRIT, "Cannot open file \'%s\' for %s: %s\n", 264219820Sjeff p_log->log_file_name, 265219820Sjeff p_log->accum_log_file ? "appending" : "writing", 266219820Sjeff strerror(errno)); 267219820Sjeff fprintf(stderr, "Cannot open file \'%s\': %s\n", 268219820Sjeff p_log->log_file_name, strerror(errno)); 269219820Sjeff return -1; 270219820Sjeff } 271219820Sjeff 272219820Sjeff if (fstat(fileno(p_log->out_port), &st) == 0) 273219820Sjeff p_log->count = st.st_size; 274219820Sjeff 275219820Sjeff syslog(LOG_NOTICE, "%s log file opened\n", p_log->log_file_name); 276219820Sjeff 277219820Sjeff if (p_log->daemon) { 278219820Sjeff dup2(fileno(p_log->out_port), 0); 279219820Sjeff dup2(fileno(p_log->out_port), 1); 280219820Sjeff dup2(fileno(p_log->out_port), 2); 281219820Sjeff } 282219820Sjeff 283219820Sjeff return 0; 284219820Sjeff} 285219820Sjeff 286219820Sjeffint osm_log_reopen_file(osm_log_t * p_log) 287219820Sjeff{ 288219820Sjeff int ret; 289219820Sjeff 290219820Sjeff if (p_log->out_port == stdout || p_log->out_port == stderr) 291219820Sjeff return 0; 292219820Sjeff cl_spinlock_acquire(&p_log->lock); 293219820Sjeff fclose(p_log->out_port); 294219820Sjeff ret = open_out_port(p_log); 295219820Sjeff cl_spinlock_release(&p_log->lock); 296219820Sjeff return ret; 297219820Sjeff} 298219820Sjeff 299219820Sjeffib_api_status_t osm_log_init_v2(IN osm_log_t * const p_log, 300219820Sjeff IN const boolean_t flush, 301219820Sjeff IN const uint8_t log_flags, 302219820Sjeff IN const char *log_file, 303219820Sjeff IN const unsigned long max_size, 304219820Sjeff IN const boolean_t accum_log_file) 305219820Sjeff{ 306219820Sjeff p_log->level = log_flags; 307219820Sjeff p_log->flush = flush; 308219820Sjeff p_log->count = 0; 309219820Sjeff p_log->max_size = max_size; 310219820Sjeff p_log->accum_log_file = accum_log_file; 311219820Sjeff p_log->log_file_name = (char *)log_file; 312219820Sjeff 313219820Sjeff openlog("OpenSM", LOG_CONS | LOG_PID, LOG_USER); 314219820Sjeff 315219820Sjeff if (log_file == NULL || !strcmp(log_file, "-") || 316219820Sjeff !strcmp(log_file, "stdout")) 317219820Sjeff p_log->out_port = stdout; 318219820Sjeff else if (!strcmp(log_file, "stderr")) 319219820Sjeff p_log->out_port = stderr; 320219820Sjeff else if (open_out_port(p_log)) 321219820Sjeff return IB_ERROR; 322219820Sjeff 323219820Sjeff if (cl_spinlock_init(&p_log->lock) == CL_SUCCESS) 324219820Sjeff return IB_SUCCESS; 325219820Sjeff else 326219820Sjeff return IB_ERROR; 327219820Sjeff} 328219820Sjeff 329219820Sjeffib_api_status_t osm_log_init(IN osm_log_t * const p_log, 330219820Sjeff IN const boolean_t flush, 331219820Sjeff IN const uint8_t log_flags, 332219820Sjeff IN const char *log_file, 333219820Sjeff IN const boolean_t accum_log_file) 334219820Sjeff{ 335219820Sjeff return osm_log_init_v2(p_log, flush, log_flags, log_file, 0, 336219820Sjeff accum_log_file); 337219820Sjeff} 338