OSDN Git Service

bd8bbc2aadf9afedeb3a92d5030943a60fd6c7e6
[openpts/openpts.git] / src / log.c
1 /*
2  * This file is part of the OpenPTS project.
3  *
4  * The Initial Developer of the Original Code is International
5  * Business Machines Corporation. Portions created by IBM
6  * Corporation are Copyright (C) 2010, 2011 International Business
7  * Machines Corporation. All Rights Reserved.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the Common Public License as published by
11  * IBM Corporation; either version 1 of the License, or (at your option)
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * Common Public License for more details.
18  *
19  * You should have received a copy of the Common Public License
20  * along with this program; if not, a copy can be viewed at
21  * http://www.opensource.org/licenses/cpl1.0.php.
22  */
23
24 /**
25  * \file src/log.c
26  * \brief logging functions
27  * @author Seiji Munetoh <munetoh@users.sourceforge.jp>
28  * @date 2010-05-07
29  * cleanup 2011-01-22 SM
30  * cleanup 2011-12-28 SM
31  *
32  *  Verbose  OUTPUT    VERBOSE       LOGGING
33  *   Level   (stdout)  (stderr)      (console/syslog/file)
34  *  --------------------------------------------------
35  *     0     ON        ERROR msg.    ERROR/INFO
36  *     1     ON        +verbose msg. ERROR/INFO
37  *     2     ON                      ERROR/INFO+DEBUG
38  *  --------------------------------------------------
39  *
40  *   LOG
41  *    off
42  *    error
43  *    on/debug
44  *
45  *  Config
46  *    verbose=0
47  *    logging.location=console|syslog|file
48  *    logging.file=./ptsc.log
49  *    debug.mode=0x01
50  *
51  *   Priority
52  *    1. Commandline option (location/file must be given by conf)
53  *    2. ENV
54  *    3. Conf file 
55  *
56  *  LOG("msg",format)
57  *
58  *  OUTPUT   console/stderr
59  *  VERBOSE  console/stderr
60  *  ASSERT   console/stderr
61  *
62  *  ERROR    console|file|syslog
63  *  INFO     console|file|syslog
64  *  TODO     console|file|syslog
65  *  DEBUG    console|file|syslog
66  *
67  */
68
69 #include <stdio.h>
70 #include <string.h>
71 #include <stdlib.h> /* getenv */
72 #include <stdarg.h> /* va_ */
73 #include <syslog.h>
74
75 #include <sys/param.h>
76 #include <sys/stat.h>
77 #include <sys/shm.h>
78 #include <errno.h>
79 #include <fcntl.h>
80 #include <unistd.h>
81
82 #include <openpts_log.h>
83
84 #define SYSLOG_BUF_SIZE 1024
85
86 #ifdef AIX
87
88 #ifndef DEFAULT_LOG_LOCATION
89 #define DEFAULT_LOG_LOCATION   OPENPTS_LOG_FILE
90 #endif
91 #ifndef DEFAULT_LOG_FILE
92 #define DEFAULT_LOG_FILE       "/var/adm/ras/openpts/log"
93 #endif
94 #define DEFAULT_LOG_FILE_PERM  (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH)
95 #define DEFAULT_LOG_FILE_SIZE  0x100000
96
97 #else  // !AIX
98
99 #define DEFAULT_LOG_LOCATION   OPENPTS_LOG_FILE
100 #define DEFAULT_LOG_FILE       "~/.openpts/openpts.log"
101 #define DEFAULT_LOG_FILE_PERM  (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH)
102 #define DEFAULT_LOG_FILE_SIZE  0x100000
103
104 #endif  // AIX
105
106 #ifdef ENABLE_NLS
107 #include <locale.h>
108 #ifdef HAVE_CATGETS
109 #include <nl_types.h>
110 nl_catd catd;
111 #endif
112 #endif
113
114 /* external variables for logging macros */
115 int debugBits = 0;
116 int verbosity = 0;
117
118 /* global variables for this file */
119 static int logLocation = OPENPTS_LOG_UNDEFINED;
120 static char logFileName[256];
121 static FILE *logFile = NULL;
122 static int logFileFd = -1;
123 static int alreadyWarnedAboutLogFile = 0;
124
125 static int openLogFile(void);
126 static void addToLog(char* log_entry);
127
128 static char * command_name = NULL;
129
130 /**
131  *
132  */
133 void initCatalog(void) {
134 #ifdef ENABLE_NLS
135     (void) setlocale(LC_ALL, "");
136 #ifdef HAVE_CATGETS
137     catd = catopen(MF_OPENPTS, NL_CAT_LOCALE);
138 #else
139     bindtextdomain(PACKAGE, LOCALEDIR);
140     textdomain(PACKAGE);
141 #endif
142 #endif
143 }
144
145 /**
146  *
147  */
148 static void expandLogFilePath(char *unexpandedPath) {
149     char *srcPtr = unexpandedPath;
150     char *destPtr = logFileName;
151     char *destEnd = destPtr + 255; /* leave space for '\0' */
152     char *homeDir = NULL;
153     int homeDirLen = 0;
154
155     while ((destPtr < destEnd) && ('\0' != srcPtr[0])) {
156         int destCharsWritten;
157         if ('~' == srcPtr[0]) {
158             int destSpaceLeft = destEnd - destPtr;
159             if (NULL == homeDir) {
160                 homeDir = getenv("HOME");
161                 homeDirLen = strlen(homeDir);
162             }
163             destCharsWritten = MIN(destSpaceLeft, homeDirLen);
164             memcpy(destPtr, homeDir, destCharsWritten);
165         } else {
166             destPtr[0] = srcPtr[0];
167             destCharsWritten = 1;
168         }
169         srcPtr++;
170         destPtr += destCharsWritten;
171     }
172
173     destPtr[0] = '\0';
174 }
175
176 /**
177  * set LogLocation by ENV
178  *
179  * export OPENPTS_LOG_FILE=/tmp/openpts.log
180  * export OPENPTS_LOG_CONSOLE=1
181  * export OPENPTS_LOG_SYSLOG=1
182  * export OPENPTS_DEBUG_MODE=0x01
183  */
184 void determineLogLocationByEnv(void) {
185     char *tempLogFileName = NULL;
186     char *tempDebugMode = NULL;
187
188     /* Location */
189     if (getenv("OPENPTS_LOG_SYSLOG") != NULL) {
190         logLocation = OPENPTS_LOG_SYSLOG;
191     } else if (getenv("OPENPTS_LOG_CONSOLE") != NULL) {
192         logLocation = OPENPTS_LOG_CONSOLE;
193         logFile = stderr;
194     } else if ((tempLogFileName = getenv("OPENPTS_LOG_FILE")) != NULL) {
195         logLocation = OPENPTS_LOG_FILE;
196     } else if (getenv("OPENPTS_LOG_NULL") != NULL) {
197         logLocation = OPENPTS_LOG_NULL;
198     } else {
199         logLocation = DEFAULT_LOG_LOCATION;
200         tempLogFileName = DEFAULT_LOG_FILE;
201     }
202
203     if (logLocation == OPENPTS_LOG_FILE) {
204         expandLogFilePath(tempLogFileName);
205     }
206
207     /* debug mode => debugBits */
208     if ((tempDebugMode = getenv("OPENPTS_DEBUG_MODE")) != NULL) {
209         debugBits = (int) strtol(tempDebugMode,NULL,16);
210         DEBUG("DEBUG FLAG(0x%x) set by ENV\n", debugBits);
211     }
212 }
213
214 /**
215  * Force custom log location by app itself
216  */
217 void setLogLocation(int ll, char *filename) {
218     logLocation = ll;
219
220     if (ll == OPENPTS_LOG_FILE) {
221         if (logFileFd != -1) {
222             char * oldlog;
223             /* already open */
224             LOG(LOG_INFO, "Logfile changed from %s to %s\n", logFileName, filename);
225             oldlog=strdup(logFileName);
226             if (oldlog == NULL) {
227                 LOG(LOG_ERR, "no memory");
228                 return;
229             }
230             close(logFileFd);
231             logFileFd = -1;
232             expandLogFilePath(filename);
233             LOG(LOG_INFO, "Logfile changed from %s to %s\n", oldlog, logFileName);
234             free(oldlog);
235         } else {
236             if (filename != NULL) {
237                 expandLogFilePath(filename);
238             } else {
239                 expandLogFilePath(DEFAULT_LOG_FILE);
240             }
241         }
242     }
243 }
244
245 void setSyslogCommandName(char *name) {
246     command_name = name;
247 }
248
249 /**
250  * return loglocation in String (char*)
251  */
252 char *getLogLocationString() {
253     if (logLocation == OPENPTS_LOG_SYSLOG) {
254         return "syslog";
255     } else if (logLocation == OPENPTS_LOG_CONSOLE) {
256         return "console(stderr)";
257     } else if (logLocation == OPENPTS_LOG_NULL) {
258         return "n/a";
259     } else if (logLocation == OPENPTS_LOG_FILE) {
260         return logFileName;
261     } else {
262         LOG(LOG_ERR, "logLocation %d\n", logLocation);
263         return "TBD";
264     }
265 }
266
267 /**
268  *
269  */
270 static void createLogEntry(
271     int priority,
272     char *buf,
273     int bufLen,
274     const char *format,
275     va_list list) {
276
277     const char *priorities[1 + LOG_DEBUG] = {
278         "[EMERGENCY] ",
279         "[ALERT] ",
280         "[CRITICAL] ",
281         "[ERROR] ",
282         "[WARNING] ",
283         "[NOTICE] ",
284         "[INFO]  ",
285         "[DEBUG] "
286     };
287     /* number of chars written (not including '\0') */
288     int charsWritten = 0;
289
290     if (priority > LOG_DEBUG) {
291         charsWritten = snprintf(buf, bufLen, "[UNKNOWN (%d)] ", priority);
292     } else {
293         charsWritten = snprintf(buf, bufLen, "%s", priorities[priority]);
294     }
295
296     if ( charsWritten >= bufLen ) {
297         /* string was truncated */
298         return;
299     }
300
301     charsWritten += vsnprintf(&buf[charsWritten], bufLen - charsWritten, format, list);
302
303     if ( charsWritten >= bufLen ) {
304         /* string was truncated */
305         return;
306     }
307
308     if ( (charsWritten + 1) < bufLen ) {
309         buf[charsWritten] = '\n';
310         buf[++charsWritten] = '\0';
311     }
312 }
313
314 /**
315  *
316  */
317 void writeLog(int priority, const char *format, ...) {
318     int len;
319     char *format2 = NULL;
320     va_list list;
321     va_start(list, format);
322
323     /* check def */
324     if (logLocation == OPENPTS_LOG_UNDEFINED) {
325         determineLogLocationByEnv();
326         return;
327     }
328
329     if (logLocation == OPENPTS_LOG_NULL) {
330         /* disable logging */
331         return;
332     }
333
334     // TODO \n
335     /* remove \n */
336     len = strlen(format);
337     if (format[len - 1] == '\n') {
338         // format2 = malloc(len + 1);  // +1 space
339         format2 = (char *) malloc(len);
340         if (format2 != NULL) {
341             memcpy(format2, format, len - 1);
342             format2[len - 1] = 0;
343             format = format2;
344         }
345     }
346
347     switch (logLocation) {
348     case OPENPTS_LOG_SYSLOG:
349         {
350             char buf[SYSLOG_BUF_SIZE];
351
352             /* ptsc -m (IF-M) -> syslog */
353             if (command_name == NULL) {
354                 openlog("ptsc", LOG_NDELAY|LOG_PID, LOG_LOCAL5);
355             } else {
356                 openlog(command_name, LOG_NDELAY|LOG_PID, LOG_LOCAL5);
357             }
358
359             /* vsyslog is not supported by some unix */
360             vsnprintf(buf, SYSLOG_BUF_SIZE, format, list);
361
362             /* priority is controlled by syslog conf */
363             /* for DEBUG, use OPENPTS_LOG_FILE */
364             syslog(priority, "%s", buf);
365
366             closelog();
367             break;
368         }
369     case OPENPTS_LOG_FILE:
370         {
371             if (openLogFile() == -1) {
372                 if ( !alreadyWarnedAboutLogFile ) {
373                     fprintf(stderr, NLS(MS_OPENPTS, OPENPTS_CANNOT_OPEN_LOGFILE,
374                         "Unable to open logfile '%s'\n"), logFileName);
375                     alreadyWarnedAboutLogFile = 1;
376                 }
377                 /* fall through to next case */
378             } else {
379                 char logEntry[1024];
380                 createLogEntry(priority, logEntry, 1024, format, list);
381                 addToLog(logEntry);
382                 break;
383             }
384         }
385     case OPENPTS_LOG_CONSOLE:
386         {
387             char logEntry[1024];
388             createLogEntry(priority, logEntry, 1024, format, list);
389             fprintf(stderr, "%s", logEntry);
390             break;
391         }
392     // TODO default?
393     }
394
395
396 #if 0
397     va_start(list, format);
398
399     // if (getenv("PTSCD_DAEMON") != NULL) {
400     if (getenv("OPENPTS_SYSLOG") != NULL) {
401         /* daemon -> syslog */
402         openlog("ptsc", LOG_NDELAY|LOG_PID, LOG_LOCAL5);
403
404         // 2011-04-11 SM shows verbose messages
405         if (priority == LOG_DEBUG) priority = LOG_INFO;
406
407         // vsyslog is not supported by some unix
408         vsnprintf(buf, SYSLOG_BUF_SIZE, format, list);
409         syslog(priority, "%s", buf);
410
411         closelog();
412     } else {
413         /* foregrond -> stdout */
414         if (priority == LOG_INFO) {
415             fprintf(stdout, "INFO:");
416         } else if (priority == LOG_ERR) {
417             fprintf(stdout, "ERROR:");
418         } else {
419             fprintf(stdout, "%d:", priority);
420         }
421         vfprintf(stdout, format, list);
422         fprintf(stdout, "\n");
423     }
424     va_end(list);
425 #endif
426
427
428     if (format2 != NULL) free(format2);
429 }
430
431
432
433 static int openLogFile(void) {
434     if (logFileFd != -1) {
435         return logFileFd;
436     }
437
438     //logFileFd = open(logFileName, O_RDWR|O_CREAT|O_TRUNC, DEFAULT_LOG_FILE_PERM);
439     logFileFd = open(logFileName, O_WRONLY|O_CREAT|O_APPEND, DEFAULT_LOG_FILE_PERM);
440     return logFileFd;
441 }
442
443 static void addToLog(char* log_entry) {
444     /* Warnings are treated as errors so need this ugly code to build */
445     ssize_t n = write(logFileFd, log_entry, strlen(log_entry));
446     (void)n;
447 }
448
449