OSDN Git Service

deleted ASSERTs and added many checks, also cleanup the codes
[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 #ifdef HAVE_CATGETS
108 #include <nl_types.h>
109 nl_catd catd;
110 #endif
111 #endif
112
113 /* external variables for logging macros */
114 int debugBits = 0;
115 int verbosity = 0;
116
117 /* global variables for this file */
118 static int logLocation = OPENPTS_LOG_UNDEFINED;
119 static char logFileName[256];
120 static FILE *logFile = NULL;
121 static int logFileFd = -1;
122 static int alreadyWarnedAboutLogFile = 0;
123
124 static int openLogFile(void);
125 static void addToLog(char* log_entry);
126
127 static char * command_name = NULL;
128
129 /**
130  *
131  */
132 void initCatalog(void) {
133 #ifdef ENABLE_NLS
134     (void) setlocale(LC_ALL, "");
135 #ifdef HAVE_CATGETS
136     catd = catopen(MF_OPENPTS, NL_CAT_LOCALE);
137 #else
138     bindtextdomain(PACKAGE, LOCALEDIR);
139     textdomain(PACKAGE);
140 #endif
141 #endif
142 }
143
144 /**
145  *
146  */
147 static void expandLogFilePath(char *unexpandedPath) {
148     char *srcPtr = unexpandedPath;
149     char *destPtr = logFileName;
150     char *destEnd = destPtr + 255; /* leave space for '\0' */
151     char *homeDir = NULL;
152     int homeDirLen = 0;
153
154     while ((destPtr < destEnd) && ('\0' != srcPtr[0])) {
155         int destCharsWritten;
156         if ('~' == srcPtr[0]) {
157             int destSpaceLeft = destEnd - destPtr;
158             if (NULL == homeDir) {
159                 homeDir = getenv("HOME");
160                 homeDirLen = strlen(homeDir);
161             }
162             destCharsWritten = MIN(destSpaceLeft, homeDirLen);
163             memcpy(destPtr, homeDir, destCharsWritten);
164         } else {
165             destPtr[0] = srcPtr[0];
166             destCharsWritten = 1;
167         }
168         srcPtr++;
169         destPtr += destCharsWritten;
170     }
171
172     destPtr[0] = '\0';
173 }
174
175 /**
176  * set LogLocation by ENV
177  *
178  * export OPENPTS_LOG_FILE=/tmp/openpts.log
179  * export OPENPTS_LOG_CONSOLE=1
180  * export OPENPTS_LOG_SYSLOG=1
181  * export OPENPTS_DEBUG_MODE=0x01
182  */
183 void determineLogLocationByEnv(void) {
184     char *tempLogFileName = NULL;
185     char *tempDebugMode = NULL;
186
187
188
189     /* Location */
190     if (getenv("OPENPTS_LOG_SYSLOG") != NULL) {
191         logLocation = OPENPTS_LOG_SYSLOG;
192     } else if (getenv("OPENPTS_LOG_CONSOLE") != NULL) {
193         logLocation = OPENPTS_LOG_CONSOLE;
194         logFile = stderr;
195     } else if ((tempLogFileName = getenv("OPENPTS_LOG_FILE")) != NULL) {
196         logLocation = OPENPTS_LOG_FILE;
197     } else if (getenv("OPENPTS_LOG_NULL") != NULL) {
198         logLocation = OPENPTS_LOG_NULL;
199     } else {
200         logLocation = DEFAULT_LOG_LOCATION;
201         tempLogFileName = DEFAULT_LOG_FILE;
202     }
203
204     if (logLocation == OPENPTS_LOG_FILE) {
205         expandLogFilePath(tempLogFileName);
206     }
207
208     /* debug mode => debugBits */
209     if ((tempDebugMode = getenv("OPENPTS_DEBUG_MODE")) != NULL) {
210         debugBits = (int) strtol(tempDebugMode,NULL,16);
211         DEBUG("DEBUG FLAG(0x%x) set by ENV\n", debugBits);
212     }
213 }
214
215 /**
216  * Force custom log location by app itself
217  */
218 void setLogLocation(int ll, char *filename) {
219     logLocation = ll;
220
221     if (ll == OPENPTS_LOG_FILE) {
222         expandLogFilePath(filename);
223     }
224 }
225
226 void setSyslogCommandName(char *name) {
227     command_name = name;
228 }
229
230 /**
231  * return loglocation in String (char*)
232  */
233 char *getLogLocationString() {
234     if (logLocation == OPENPTS_LOG_SYSLOG) {
235         return "syslog";
236     } else if (logLocation == OPENPTS_LOG_CONSOLE) {
237         return "console(stderr)";
238     } else if (logLocation == OPENPTS_LOG_NULL) {
239         return "n/a";
240     } else if (logLocation == OPENPTS_LOG_FILE) {
241         return logFileName;
242     } else {
243         ERROR("logLocation %d\n", logLocation);
244         return "TBD";
245     }
246 }
247
248 /**
249  *
250  */
251 static void createLogEntry(
252     int priority,
253     char *buf,
254     int bufLen,
255     const char *format,
256     va_list list) {
257
258     const char *priorities[1 + LOG_DEBUG] = {
259         "[EMERGENCY] ",
260         "[ALERT] ",
261         "[CRITICAL] ",
262         "[ERROR] ",
263         "[WARNING] ",
264         "[NOTICE] ",
265         "[INFO]  ",
266         "[DEBUG] "
267     };
268     /* number of chars written (not including '\0') */
269     int charsWritten = 0;
270
271     if (priority > LOG_DEBUG) {
272         charsWritten = snprintf(buf, bufLen, "[UNKNOWN (%d)] ", priority);
273     } else {
274         charsWritten = snprintf(buf, bufLen, "%s", priorities[priority]);
275     }
276
277     if ( charsWritten >= bufLen ) {
278         /* string was truncated */
279         return;
280     }
281
282     charsWritten += vsnprintf(&buf[charsWritten], bufLen - charsWritten, format, list);
283
284     if ( charsWritten >= bufLen ) {
285         /* string was truncated */
286         return;
287     }
288
289     if ( (charsWritten + 1) < bufLen ) {
290         buf[charsWritten] = '\n';
291         buf[++charsWritten] = '\0';
292     }
293 }
294
295 /**
296  *
297  */
298 void writeLog(int priority, const char *format, ...) {
299     int len;
300     char *format2 = NULL;
301     va_list list;
302     // char buf[SYSLOG_BUF_SIZE];
303     va_start(list, format);
304
305
306     if (logLocation == OPENPTS_LOG_UNDEFINED) {
307         determineLogLocationByEnv();
308         // fprintf(stderr, "logLocation == OPENPTS_LOG_UNDEFINED\n");
309         return;
310     }
311
312     if (logLocation == OPENPTS_LOG_NULL) {
313         return;
314     }
315
316     // TODO \n
317     /* remove \n */
318     len = strlen(format);
319     if (format[len - 1] == '\n') {
320         // format2 = malloc(len + 1);  // +1 space
321         format2 = (char *) malloc(len);
322         if (format2 != NULL) {
323             memcpy(format2, format, len - 1);
324             format2[len - 1] = 0;
325             format = format2;
326         }
327     }
328
329     switch (logLocation) {
330     case OPENPTS_LOG_SYSLOG:
331         {
332             char buf[SYSLOG_BUF_SIZE];
333
334             /* ptsc -m (IF-M) -> syslog */
335             if (command_name == NULL) {
336                 openlog("ptsc", LOG_NDELAY|LOG_PID, LOG_LOCAL5);
337             } else {
338                 openlog(command_name, LOG_NDELAY|LOG_PID, LOG_LOCAL5);
339             }
340
341             /* vsyslog is not supported by some unix */
342             vsnprintf(buf, SYSLOG_BUF_SIZE, format, list);
343
344             /* priority is controlled by syslog conf */
345             /* for DEBUG, use OPENPTS_LOG_FILE */
346             syslog(priority, "%s", buf);
347
348             closelog();
349             break;
350         }
351     case OPENPTS_LOG_FILE:
352         {
353             if (openLogFile() == -1) {
354                 if ( !alreadyWarnedAboutLogFile ) {
355                     fprintf(stderr, NLS(MS_OPENPTS, OPENPTS_CANNOT_OPEN_LOGFILE,
356                         "Unable to open logfile '%s'\n"), logFileName);
357                     alreadyWarnedAboutLogFile = 1;
358                 }
359                 /* fall through to next case */
360             } else {
361                 char logEntry[1024];
362                 createLogEntry(priority, logEntry, 1024, format, list);
363                 addToLog(logEntry);
364                 break;
365             }
366         }
367     case OPENPTS_LOG_CONSOLE:
368         {
369             char logEntry[1024];
370             createLogEntry(priority, logEntry, 1024, format, list);
371             fprintf(stderr, "%s", logEntry);
372             break;
373         }
374     // TODO default?
375     }
376
377
378 #if 0
379     va_start(list, format);
380
381     // if (getenv("PTSCD_DAEMON") != NULL) {
382     if (getenv("OPENPTS_SYSLOG") != NULL) {
383         /* daemon -> syslog */
384         openlog("ptsc", LOG_NDELAY|LOG_PID, LOG_LOCAL5);
385
386         // 2011-04-11 SM shows verbose messages
387         if (priority == LOG_DEBUG) priority = LOG_INFO;
388
389         // vsyslog is not supported by some unix
390         vsnprintf(buf, SYSLOG_BUF_SIZE, format, list);
391         syslog(priority, "%s", buf);
392
393         closelog();
394     } else {
395         /* foregrond -> stdout */
396         if (priority == LOG_INFO) {
397             fprintf(stdout, "INFO:");
398         } else if (priority == LOG_ERR) {
399             fprintf(stdout, "ERROR:");
400         } else {
401             fprintf(stdout, "%d:", priority);
402         }
403         vfprintf(stdout, format, list);
404         fprintf(stdout, "\n");
405     }
406     va_end(list);
407 #endif
408
409
410     if (format2 != NULL) free(format2);
411 }
412
413
414
415 static int openLogFile(void) {
416     if (logFileFd != -1) {
417         return logFileFd;
418     }
419
420     //logFileFd = open(logFileName, O_RDWR|O_CREAT|O_TRUNC, DEFAULT_LOG_FILE_PERM);
421     logFileFd = open(logFileName, O_WRONLY|O_CREAT|O_APPEND, DEFAULT_LOG_FILE_PERM);
422     return logFileFd;
423 }
424
425 static void addToLog(char* log_entry) {
426     /* Warnings are treated as errors so need this ugly code to build */
427     ssize_t n = write(logFileFd, log_entry, strlen(log_entry));
428     (void)n;
429 }
430
431