Build with debug symbols enabled.
[oweals/cde.git] / cde / lib / DtSvc / DtUtil2 / MsgLog.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* 
24  * (c) Copyright 1995 Digital Equipment Corporation.
25  * (c) Copyright 1995 Hewlett-Packard Company.
26  * (c) Copyright 1995 International Business Machines Corp.
27  * (c) Copyright 1995 Sun Microsystems, Inc.
28  * (c) Copyright 1995 Novell, Inc. 
29  * (c) Copyright 1995 FUJITSU LIMITED.
30  * (c) Copyright 1995 Hitachi.
31  *
32  * MsgLog.c - public interfaces for the Message Logging Service
33  *
34  * NOTE: the cpp define MSGLOG_CLIENT_ONLY is not defined when this
35  *       file is compiled for the DtSvc library.  MSGLOG_CLIENT_ONLY
36  *       is only defined when an application intends to use these
37  *       routines directly because the application does not to build
38  *       in a dependecy to the DtSvc library (e.g. dtexec).
39  *
40  * $TOG: MsgLog.c /main/21 1998/10/26 17:23:21 mgreess $
41  *
42  */
43
44 #include <stdio.h>
45 #include <string.h>
46 #include <stdlib.h>
47 #include <unistd.h>
48 #define X_INCLUDE_PWD_H
49 #define X_INCLUDE_TIME_H
50 #define XOS_USE_XT_LOCKING
51 #include <X11/Xos_r.h>
52 #include <sys/param.h>
53 #include <limits.h>
54
55 #include <Dt/DtPStrings.h>
56 #ifndef MSGLOG_CLIENT_ONLY
57 # include <Dt/UserMsg.h>
58 # include <DtSvcLock.h>
59 #endif /* MSGLOG_CLIENT_ONLY */
60 #include <Dt/DtGetMessageP.h>
61 #include <Dt/MsgLog.h>
62 #include <Dt/MsgLogI.h>
63
64 #define MAX_DATE_TIME_STRING    256
65
66 /* 
67  * Static variables
68  */
69 static char             * information_string = NULL;
70 static char             * stderr_string = NULL;
71 static char             * debug_string = NULL;
72 static char             * warning_string = NULL;
73 static char             * error_string = NULL;
74 static char             * unknown_string = NULL;
75 #ifndef MSGLOG_CLIENT_ONLY
76 static DtMsgLogHandler  saved_msglog_handler    = NULL;
77 #endif /* MSGLOG_CLIENT_ONLY */
78
79
80 /*
81  * Static constants
82  */
83 static const char       * LOGFILE_NAME          = DtERRORLOG_FILE;
84 static const char       * TMP_DIR               = "/tmp";
85 static const char       * OPEN_FLAG             = "a+";
86 static const int        SET_NUM                 = 50;
87
88 #ifdef CDE_LOGFILES_TOP
89 static const char       * CDE_VAR_TMP_DIR       = CDE_LOGFILES_TOP ;
90 #else
91 static const char       * CDE_VAR_TMP_DIR       = "/var/dt/tmp";
92 #endif
93
94
95 /*
96  * Static function forward declarations
97  */
98 static char * get_file_name (
99         const char      * type,
100         FILE            ** fp,
101         const char      * format,
102         ... );
103 static char * check_possible_files (
104         const char      * type,
105         FILE            ** fp );
106 static void initialize_message_strings (void);
107
108
109 /*
110  * initialize_message_string - 
111  *
112  * Modified: initializes the static message string variables
113  *   
114  */
115 static void initialize_message_strings (void)
116 {
117       information_string = strdup (Dt11GETMESSAGE (SET_NUM, 1, "INFORMATION"));
118       stderr_string      = strdup (Dt11GETMESSAGE (SET_NUM, 2, "STDERR"));
119       debug_string       = strdup (Dt11GETMESSAGE (SET_NUM, 3, "DEBUG"));
120       warning_string     = strdup (Dt11GETMESSAGE (SET_NUM, 4, "WARNING"));
121       error_string       = strdup (Dt11GETMESSAGE (SET_NUM, 5, "ERROR"));
122       unknown_string     = strdup (Dt11GETMESSAGE (SET_NUM, 6, "UNKNOWN"));
123 }
124
125
126 /*
127  * get_file_name - given a sprintf-like format and a variable
128  *    list of args, create a filename and open the file.  
129  *
130  * Modified:
131  *     
132  *      fp              - set to the opened file or NULL if the open 
133  *                        fails
134  *
135  * Returns: a filename or NULL if the filename cannot be opened
136  *    with mode 'type'.
137  */
138 static char * get_file_name (
139         const char      * type,
140         FILE            ** fp,          /* MODIFIED */
141         const char      * format,
142         ... )
143 {
144         char            *file, *rtn;
145         va_list         args;
146
147         file = malloc(MAXPATHLEN+1);
148         if (! file) return;
149
150         Va_start (args, format);
151
152         (void) vsprintf (file, format, args);
153         va_end (args);
154
155         if ((*fp = fopen (file, type)) == NULL)
156                 return (NULL);
157                
158         rtn = strdup (file);
159         free(file);
160         return rtn;
161 }
162
163
164 /*
165  * check_possible_files - generates possible filenames to use for
166  *    the message logging.
167  *
168  *    The first one of the following files that is append'able is
169  *    returned:
170  *
171  *       o $HOME/DtPERSONAL_CONFIG_DIRECTORY/LOGFILE_NAME
172  *
173  *       o CDE_VAR_TMP_DIR/$DTUSERSESSION/LOGFILE_NAME
174  *
175  *       o TMP_DIR/<login_name_from_passwd_file>/LOGFILE_NAME
176  *
177  * Note: #2 is only checked if $DTUSERSESSION is defined
178  *
179  * Modified:
180  *
181  *      fp              - set to the opened file or NULL if the open 
182  *                        fails
183  *
184  * Returns: a filename if one if found that is append'able or NULL
185  *    if such a file cannot be determined.
186  */
187 static char * check_possible_files (
188         const char      * type,
189         FILE            ** fp )         /* MODIFIED */
190 {
191         char            * file;
192         char            * env;
193         _Xgetpwparams   pwd_buf;
194         struct passwd   * pwd_ret;
195
196         if ((file = get_file_name (type,
197                                    fp,
198                                    "%s/%s/%s",
199                                    getenv("HOME"),
200                                    DtPERSONAL_CONFIG_DIRECTORY,
201                                    LOGFILE_NAME)) != NULL)
202                 return (file);
203
204         if ((env = getenv ("DTUSERSESSION")) != NULL) {
205                 if ((file = get_file_name (type,
206                                            fp,
207                                            "%s/%s/%s",
208                                            CDE_VAR_TMP_DIR,
209                                            env,
210                                            LOGFILE_NAME)) != NULL)
211                         return (file);
212         }
213
214         if ((env = getenv ("LOGNAME")) != NULL) {
215                 if ((file = get_file_name (type,
216                                            fp,
217                                            "%s/%s.%s",
218                                            TMP_DIR,
219                                            env,
220                                            LOGFILE_NAME)) != NULL)
221                         return (file);
222         }
223
224         if ((env = getenv ("USER")) != NULL) {
225                 if ((file = get_file_name (type,
226                                            fp,
227                                            "%s/%s.%s",
228                                            TMP_DIR,
229                                            env,
230                                            LOGFILE_NAME)) != NULL)
231                         return (file);
232         }
233
234         if ((pwd_ret = _XGetpwuid (getuid(), pwd_buf)) != NULL) {
235                 if ((file = get_file_name (type,
236                                            fp,
237                                            "%s/%s.%s",
238                                            TMP_DIR,
239                                            pwd_ret->pw_name,
240                                            LOGFILE_NAME)) != NULL)
241                         return (file);
242         }
243
244         return (NULL);
245 }
246
247 /*
248  * DtMsgLogMessage -
249  *
250  * Returns: 0 if the message is successfully logged or 1 if an
251  *    error occurs and the message is not logged.
252  */
253 void DtMsgLogMessage (
254         const char              * program_name,
255         DtMsgLogType            msg_type,
256         const char              * format,
257         ... )
258 {
259         va_list                 args;
260         FILE                    * fp = NULL;
261         char                    * file = NULL;
262         time_t                  now;
263         char                    * msg_string;  /* temp msg type string */
264         int                     num_bytes;
265         char                    buf[MAX_DATE_TIME_STRING];
266 #ifdef NLS16
267         char                    * tmp_format;
268 #endif
269         _Xctimeparams           ctime_buf;
270         char                    * result;
271         _Xltimeparams           localtime_buf;
272         struct tm               * current_time;
273
274         Va_start (args, format);
275
276 #ifndef MSGLOG_CLIENT_ONLY
277         _DtSvcProcessLock();
278         if (saved_msglog_handler != NULL) {
279
280                 (*saved_msglog_handler) (program_name ? program_name : 
281                                          DtProgName, 
282                                          msg_type,
283                                          format,
284                                          args);
285                 _DtSvcProcessUnlock();
286                 va_end (args);
287
288                 return;
289         }
290         _DtSvcProcessUnlock();
291 #endif /* MSGLOG_CLIENT_ONLY */
292
293         if (!information_string) {
294 #ifndef MSGLOG_CLIENT_ONLY
295                 _DtSvcProcessLock();
296 #endif /* MSGLOG_CLIENT_ONLY */
297                 if (!information_string)
298                         initialize_message_strings ();
299 #ifndef MSGLOG_CLIENT_ONLY
300                 _DtSvcProcessUnlock();
301 #endif /* MSGLOG_CLIENT_ONLY */
302         }
303
304         /*
305          * Need to get a copy of the string in case another 
306          * thread calls catgets and puts a different
307          * string in catgets's static buffer before 
308          * msg_string is output
309          */
310         switch (msg_type) {
311                 case    DtMsgLogInformation:
312                         msg_string = information_string;
313                         break;
314                 case    DtMsgLogStderr:
315                         msg_string = stderr_string;
316                         break;
317                 case    DtMsgLogDebug:
318                         msg_string = debug_string;
319                         break;
320                 case    DtMsgLogWarning:
321                         msg_string = warning_string;
322                         break;
323                 case    DtMsgLogError:
324                         msg_string = error_string;
325                         break;
326                 default:
327                         msg_string = unknown_string;
328                         break;
329         }
330
331         now = time ((time_t)0);
332
333         /*
334          * Write to stderr if a log file cannot be determined
335          * or if it isn't writeable.
336          */
337         if ((fp = DtMsgLogOpenFile (OPEN_FLAG, &file)) == NULL)
338                 fp = stderr;
339 #ifdef NLS16
340
341         current_time = _XLocaltime(&now, localtime_buf);
342         /*
343          * Need to save format because the next call to catgets
344          * may overwrite it on some platforms (if format itself 
345          * is the result of a call to catgets).
346          */
347         tmp_format = strdup ((char *) format);
348
349         (void) strftime (buf, 
350                          MAX_DATE_TIME_STRING, 
351                          Dt11GETMESSAGE (48, 1, "%a %b %d %H:%M:%S %Y\n"), 
352                          current_time);
353
354         num_bytes = fprintf (fp, "*** %s(%d): %s: PID %d: %s", 
355                         msg_string, msg_type, 
356 #ifndef MSGLOG_CLIENT_ONLY
357                         program_name ? program_name : DtProgName, 
358 #else
359                         program_name ? program_name : "", 
360 #endif /* MSGLOG_CLIENT_ONLY */
361                         getpid(), buf);
362 #else
363         result = _XCtime(&now, ctime_buf);
364         num_bytes = fprintf (fp, "*** %s(%d): %s: PID %ld: %s", 
365                         msg_string, msg_type, 
366 #ifndef MSGLOG_CLIENT_ONLY
367                         program_name ? program_name : DtProgName, 
368 #else
369                         program_name ? program_name : "", 
370 #endif /* MSGLOG_CLIENT_ONLY */
371                         (long)getpid(), result);
372 #endif
373
374 #ifdef NLS16
375         num_bytes += vfprintf (fp, tmp_format, args);
376         free (tmp_format);
377 #else
378         num_bytes += vfprintf (fp, format, args);
379 #endif
380         va_end (args);
381
382         fprintf (fp, "\n*** [%d]\n\n", num_bytes);
383
384         if (fp != stderr) {
385                 (void) fflush (fp);
386                 (void) fclose(fp);
387         }
388
389         if (file)
390                 free (file);
391 }
392
393
394 #ifndef MSGLOG_CLIENT_ONLY
395 /*
396  * DtMsgLogSetHandler - caches an alternate message logging
397  *    handler
398  *
399  * Modified:
400  *
401  *    saved_msglog_handler - set to the given handler
402  *
403  * Returns: if handler is NULL, the default handler is restored;
404  *    returns a pointer to the previous handler
405  *
406  */
407 DtMsgLogHandler DtMsgLogSetHandler (
408         DtMsgLogHandler         handler )
409 {
410         DtMsgLogHandler         previous_handler;
411
412         _DtSvcProcessLock();
413         if (handler == NULL) {
414                 if (saved_msglog_handler) {
415                         previous_handler = saved_msglog_handler;
416                         saved_msglog_handler = NULL;
417                         return (previous_handler);
418                 }
419                 else {
420                         saved_msglog_handler = NULL;
421                         return  (DtMsgLogHandler) DtMsgLogMessage;
422                 }
423         }
424
425         if (saved_msglog_handler)
426                 previous_handler = saved_msglog_handler;
427         else
428                 previous_handler = (DtMsgLogHandler) DtMsgLogMessage;
429
430         saved_msglog_handler = handler;
431         _DtSvcProcessUnlock();
432         return (previous_handler);
433 }
434 #endif /* MSGLOG_CLIENT_ONLY */
435
436
437 /*
438  * DtMsgLogOpenFile - opens the logfile 
439  *
440  * Returns: returns a pointer to the opened logfile; if a logfile
441  *    cannot be opened, stderr is returned
442  *
443  * Modified:  
444  *
445  *    fp - is set to the opened file
446  *
447  *    filename_return - will be set to the filename if it
448  *       if it is not NULL and a file is opened.  If filename_return
449  *       is not NULL and and a file is opened, the calling function
450  *       should free the space allocated for the filename.
451  */
452 FILE * DtMsgLogOpenFile (
453         const char              * type,
454         char                    ** filename_return)     /* MODIFIED */
455 {
456         FILE            * fp = NULL;
457         char            * pch;
458
459         pch = check_possible_files (type, &fp);
460
461         if (filename_return)
462                 *filename_return = pch;
463         else if (pch)
464                 free (pch);
465
466         if (!fp)
467                 fp = stderr;
468
469         return (fp);    
470 }