]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/ofed/management/opensm/opensm/osm_log.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / ofed / management / opensm / opensm / osm_log.c
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
56 static 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
63 static 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
78 void OsmReportState(IN const char *p_str);
79 #endif                          /* ndef WIN32 */
80
81 #ifndef WIN32
82
83 static 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
97 static 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
104 void 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
201 void 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
217 void 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
244 boolean_t osm_is_debug(void)
245 {
246 #if defined( _DEBUG_ )
247         return TRUE;
248 #else
249         return FALSE;
250 #endif                          /* defined( _DEBUG_ ) */
251 }
252
253 static 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
286 int 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
299 ib_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
329 ib_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 }