]> arthur.barton.de Git - netatalk.git/blob - libatalk/util/logger.c
altereed code to keep open logfiles, and flush then instead of closing after each...
[netatalk.git] / libatalk / util / logger.c
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 /* =========================================================================
6
7        logger.c is part of the utils section in the libatalk library, 
8         which is part of the netatalk project.  
9
10        logger.c was written by Simon Bazley (sibaz@sibaz.com)
11
12        I believe libatalk is released under the L/GPL licence.  
13
14        Just incase, it is, thats the licence I'm applying to this file.
15
16        Netatalk 2001 (c)
17
18    ==========================================================================
19
20        Logger.c is intended as an alternative to syslog for logging
21
22        ---------------------------------------------------------------
23
24    The initial plan is to create a structure for general information needed
25     to log to a file.  
26
27    Initally I'll hard code the neccesary stuff to start a log, this should
28     probably be moved elsewhere when some code is written to read the log
29     file locations from the config files.  
30
31    As a more longterm idea, I'll code this so that the data struct can be
32     duplicated to allow multiple concurrent log files, although this is 
33     probably a recipe for wasted resources. 
34
35    ========================================================================= */
36
37 #include <stdio.h>
38 #include <limits.h>
39 #include <stdarg.h>
40 #include <string.h>
41 #include <stdlib.h>
42 #include <syslog.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <unistd.h>
46 #include <time.h>
47
48 #include <atalk/boolean.h>
49 #include <atalk/logger.h>
50
51 #define COUNT_ARRAY(array) (sizeof((array))/sizeof((array)[0]))
52 #define NUMOF COUNT_ARRAY
53 #define KEEP_LOGFILES_OPEN
54 #define DO_SYSLOG
55 #define DO_FILELOG
56
57 #undef  DEBUG_OUTPUT_TO_SCREEN
58 #undef  CHECK_STAT_ON_NEW_FILES 
59 #undef  CHECK_ACCESS_ON_NEW_FILES 
60 #define OPEN_LOGS_AS_UID 0
61
62 /* =========================================================================
63     External function declarations
64    ========================================================================= */
65
66 /* setup the internal variables used by the logger (called automatically) */
67 void log_init();
68
69 /* Setup the log filename and the loglevel, and the type of log it is. */
70 bool log_setup(char *filename, enum loglevels loglevel, enum logtypes logtype, 
71                int display_options);
72
73 /* Setup the Level and type of log that will be logged to syslog. */
74 void syslog_setup(enum loglevels loglevel, enum logtypes logtype, 
75                   int display_options, int facility);
76
77 /* finish up and close the logs */
78 void log_close();
79
80 /* This function sets up the processname */
81 void set_processname(char *processname);
82
83 /* Log a Message */
84 void make_log(enum loglevels loglevel, enum logtypes logtype, 
85               char *message, ...);
86 #ifndef DISABLE_LOGGER
87 make_log_func set_log_location(char *srcfilename, int srclinenumber);
88
89 /* ========================================================================= 
90     Structure definitions
91    ========================================================================= */
92
93 /* A structure containing object level stuff */
94 struct tag_log_file_data {
95   char log_filename[PATH_MAX];  /* Name of file */
96   FILE *log_file;      /* FILE pointer to file */
97   enum loglevels   log_level;     /* Log Level to put in this file */
98   int  display_options;
99 };
100
101 typedef struct tag_log_file_data log_file_data_pair[2];
102
103 /* A structure containg class level stuff */
104 struct tag_global_log_data {
105   int   struct_size;
106
107   char *temp_src_filename;
108   int   temp_src_linenumber;
109   char  processname[16];
110   
111   int   facility;
112   char *log_file_directory;  /* Path of directory containing log files */
113   log_file_data_pair **logs;
114 };
115
116 struct what_to_print_array {
117   bool print_datetime;
118   bool print_processname;
119   bool print_pid;
120   bool print_srcfile;
121   bool print_srcline;
122   bool print_errlevel;
123   bool print_errtype;
124 };
125
126 /* =========================================================================
127     Internal function declarations
128    ========================================================================= */
129
130 void generate_message_details(char *message_details_buffer,
131                               int message_details_buffer_length,
132                               struct tag_log_file_data *log_struct,
133                               enum loglevels loglevel, enum logtypes logtype);
134
135 int get_syslog_equivalent(enum loglevels loglevel);
136
137 static char *get_command_name(char *commandpath);
138
139 /* =========================================================================
140     Instanciated data
141    ========================================================================= */
142
143 /* A populated instance */
144
145 static log_file_data_pair default_log_file_data_pair = {
146 {
147   log_filename:    "\0\0\0\0\0\0\0\0",
148   log_file:        NULL,
149   log_level:       log_debug,
150   display_options: logoption_pid
151 },
152 {
153   log_filename:     LOGFILEPATH,
154   log_file:         NULL,
155   log_level:        log_debug,
156   display_options:  logoption_pid
157 }};
158
159 static log_file_data_pair logger_log_file_data_pair = {
160 {
161   log_filename:    "\0\0\0\0\0\0\0\0",
162   log_file:        NULL,
163   log_level:       log_warning,
164   display_options: logoption_pid
165 },
166 {
167   log_filename:     LOGFILEPATH,
168   log_file:         NULL,
169   log_level:        log_maxdebug,
170   display_options:  logoption_pid
171 }};
172
173 static log_file_data_pair *log_file_data_array[logtype_end_of_list_marker] = 
174 {&default_log_file_data_pair};
175
176 /* The class (populated) */
177 static struct tag_global_log_data global_log_data = {
178   struct_size:         sizeof(struct tag_global_log_data),
179   temp_src_filename:   NULL,
180   temp_src_linenumber: 0,
181   processname:         "",
182   facility:            logfacility_daemon,
183   log_file_directory:  "",
184   logs:                NULL,
185 };
186
187 /* macro to get access to the array */
188 #define log_file_arr (global_log_data.logs)
189
190 /* Array to store text to list given a log type */
191 static const char * arr_logtype_strings[] =  LOGTYPE_STRING_IDENTIFIERS;
192 static const int num_logtype_strings = COUNT_ARRAY(arr_logtype_strings);
193
194 /* Array for charachters representing log severity in the log file */
195 static const char arr_loglevel_chars[] = {'S', 'E', 'W', 'N', 'I', 'D'};
196 static const int num_loglevel_chars = COUNT_ARRAY(arr_loglevel_chars);
197
198 static const char * arr_loglevel_strings[] = LOGLEVEL_STRING_IDENTIFIERS;
199 static const int num_loglevel_strings = COUNT_ARRAY(arr_loglevel_strings);
200
201 #else /* #ifndef DISABLE_LOGGER */
202   char *disabled_logger_processname=NULL;
203 #endif /* DISABLE_LOGGER */
204 /* =========================================================================
205     Global function definitions
206    ========================================================================= */
207
208 #ifndef DISABLE_LOGGER
209
210 /* remember I'm keeping a copy of the actual char * Filename, so you mustn't
211    delete it, until you've finished with the log.  Also you're responsible
212    for deleting it when you have finished with it. */
213 void log_init()
214 {
215   if (global_log_data.logs==NULL)
216   {
217     /* first check default_log_file_data_pair */
218
219     /* next clear out the log_file_data_array */
220     memset(log_file_data_array, 0, sizeof(log_file_data_array));
221     /* now set default_log_file_data_pairs */
222     log_file_data_array[logtype_default] = &default_log_file_data_pair;
223     log_file_data_array[logtype_logger]  = &logger_log_file_data_pair;
224
225     /* now setup the global_log_data struct */
226     global_log_data.logs = log_file_data_array;
227
228     /* make_log_entry(log_debug, logtype_logger, "log_init ran for the first time"); */
229   }
230 }
231 #endif /* #ifndef DISABLE_LOGGER */
232
233 bool log_setup(char *filename, enum loglevels loglevel, enum logtypes logtype, 
234                int display_options)
235 {
236 #ifndef DISABLE_LOGGER
237
238   struct stat statbuf;
239   int firstattempt;
240   int retval;
241   gid_t gid;
242   uid_t uid;
243   int access;
244   char lastchar[2];
245
246   log_file_data_pair *logs;
247
248   log_init();
249
250   logs = log_file_arr[logtype];
251   
252   LOG(log_info, logtype_logger, "doing log_setup, type %d, level %d, filename \"%s\"", logtype, loglevel, filename);
253
254   /* LOG(log_extradebug+10, logtype_logger, "checking array for logtype is malloc'd"); */
255   /* has the given logtype already been assigned memory? */
256   if (logs==NULL)
257   {
258     logs = (log_file_data_pair *)malloc(sizeof(log_file_data_pair));
259     if (logs==NULL)
260     {
261       LOG(log_severe, logtype_logger, "can't calloc in log_setup");
262     }
263     else
264     {
265     /*
266       memcpy(logs, log_file_arr[logtype_default], sizeof(log_file_data_pair));
267      */
268       log_file_arr[logtype] = logs;
269       (*logs)[1].log_file = NULL;
270     }
271   }
272
273   /* I think this checks if we're logging to stdout or not.  Probably unused */
274   if ( ((*logs)[1].log_file == stdout) && ((*logs)[1].log_file != NULL) )
275   {
276     fclose((*logs)[1].log_file);
277     (*logs)[1].log_file = NULL;
278   }
279
280   /* check if we need to append the given filename to a directory */
281   if (strlen(global_log_data.log_file_directory)>0)
282   {
283     lastchar[0] = global_log_data.
284       log_file_directory[strlen(global_log_data.log_file_directory)-1];
285
286     if (lastchar[0] == '/' || lastchar[0] == '\\' || lastchar[0] == ':')
287       lastchar[0] = 0;
288     else
289       /* this should probably be a platform specific path separator */
290       lastchar[0] = '/';
291
292     lastchar[1] = 0;
293   }
294   else
295     lastchar[0] = 0;
296   
297 #ifdef DEBUG_OUTPUT_TO_SCREEN
298   printf("filename is %s stored at location %p\n", (*logs)[1].log_filename, 
299                                                    (*logs)[1].log_filename);
300 #endif /* DEBUG_OUTPUT_TO_SCREEN */
301   if (filename == NULL)
302   {
303     strncpy((*logs)[1].log_filename, 
304             (*(log_file_arr[0]))[1].log_filename, PATH_MAX);
305   }
306   else
307   {
308     sprintf((*logs)[1].log_filename, "%s%s%s", 
309             global_log_data.log_file_directory,
310             lastchar, filename);
311   }
312   (*logs)[1].log_level    = loglevel;
313   (*logs)[1].display_options = display_options;
314
315 #ifdef DEBUG_OUTPUT_TO_SCREEN
316   printf("filename is %s stored at location %p\n", (*logs)[1].log_filename, 
317                                                    (*logs)[1].log_filename);
318 #endif /* DEBUG_OUTPUT_TO_SCREEN */
319
320 #ifdef CHECK_STAT_ON_NEW_FILES
321   uid = geteuid(); 
322   gid = getegid();
323   
324 #ifdef DEBUG_OUTPUT_TO_SCREEN
325   printf("about to stat file %s\n", (*logs)[1].log_filename);
326 #endif
327   firstattempt = stat((*logs)[1].log_filename, &statbuf);
328
329   if (firstattempt == -1)
330   {
331 #ifdef DEBUG_OUTPUT_TO_SCREEN
332     printf("about to call Log with %d, %d, %s, %s\n", 
333            log_note, logtype_logger, 
334            "can't stat Logfile", 
335            (*logs)[1].log_filename
336            );
337 #endif
338
339     /* syslog(LOG_INFO, "stat failed"); */
340     LOG(log_warning, logtype_logger, "stat fails on file %s",
341                      (*logs)[1].log_filename);
342
343     if (strlen(global_log_data.log_file_directory)>0)
344     {
345       retval = stat(global_log_data.log_file_directory, &statbuf);
346       if (retval == -1)
347       {
348 #ifdef DEBUG_OUTPUT_TO_SCREEN
349         printf("can't stat dir either so I'm giving up\n");
350 #endif
351         LOG(log_severe, logtype_logger, "can't stat directory %s either",
352                          global_log_data.log_file_directory);
353         return false;
354       } 
355     }
356   }
357
358 #ifdef CHECK_ACCESS_ON_NEW_FILES
359   access = ((statbuf.st_uid == uid)?(statbuf.st_mode & S_IWUSR):0) + 
360            ((statbuf.st_gid == gid)?(statbuf.st_mode & S_IWGRP):0) +
361            (statbuf.st_mode & S_IWOTH);
362
363   if (access==0)
364   {
365 #ifdef DEBUG_OUTPUT_TO_SCREEN
366     printf("failing with %d, %d, %s, %s\n", log_note, logtype_logger,
367            "can't access Logfile %s",    (*logs)[1].log_filename);
368 #endif
369
370     LOG(log_note, logtype_logger, "can't access file %s", 
371                      (*logs)[1].log_filename);
372     return false;
373   }
374 #endif /* CHECK_ACCESS_ON_NEW_FILES */
375 #endif /* CHECK_STAT_ON_NEW_FILES */
376 /*
377 #ifdef KEEP_LOGFILES_OPEN
378   if ((*logs)[1].log_file!=NULL)
379     fclose((*logs)[1].log_file);
380
381   (*logs)[1].log_file     = fopen((*logs)[1].log_filename, "at");
382   if ((*logs)[1].log_file == NULL)
383   {
384     LOG(log_severe, logtype_logger, "can't open Logfile %s", 
385         (*logs)[1].log_filename
386         );
387     return false;
388   }
389 #endif
390 */
391
392   LOG(log_debug7, logtype_logger, "log_file_arr[%d] now contains: "
393                                   "{log_filename:%s, log_file:%p, log_level: %d}", logtype,
394                                    (*logs)[1].log_filename, (*logs)[1].log_file, (*logs)[1].log_level);
395   LOG(log_debug, logtype_logger, "log_setup[%d] done", logtype);
396
397 #endif /* DISABLE_LOGGER */
398   return true;
399 }
400
401
402 void syslog_setup(enum loglevels loglevel, enum logtypes logtype, 
403                   int display_options, int facility)
404 {
405 #ifndef DISABLE_LOGGER
406   log_file_data_pair *logs;
407
408   log_init();
409
410   logs = log_file_arr[logtype];
411
412   LOG(log_info, logtype_logger, "doing syslog_setup, type %d, level %d", logtype, loglevel);
413
414   if (logs==NULL)
415   {
416     logs = (log_file_data_pair *)malloc(sizeof(log_file_data_pair));    
417     if (logs==NULL)
418     {
419       LOG(log_severe, logtype_logger, "can't calloc in log_setup");
420     }
421     else
422     {
423       memcpy(logs, log_file_arr[logtype_default], sizeof(log_file_data_pair));
424       log_file_arr[logtype] = logs;
425     }
426   }
427
428   (*logs)[0].log_file        = NULL;
429   (*logs)[0].log_filename[0] = 0;
430   (*logs)[0].log_level       = loglevel;
431   (*logs)[0].display_options = display_options;
432   global_log_data.facility   = facility;
433
434   openlog(global_log_data.processname, (*logs)[0].display_options, 
435           global_log_data.facility);
436
437   LOG(log_debug7, logtype_logger, "log_file_arr[%d] now contains: "
438                                   "{log_filename:%s, log_file:%p, log_level: %d}", logtype,
439                                   (*logs)[0].log_filename, (*logs)[0].log_file, (*logs)[0].log_level);
440   LOG(log_debug, logtype_logger, "syslog_setup[%d] done", logtype);
441 #else /* DISABLE_LOGGER */
442 /* behave like a normal openlog call */
443   openlog(disabled_logger_processname, display_options, facility);
444 #endif /* DISABLE_LOGGER */
445 }
446
447 void log_close()
448 {
449 #ifndef DISABLE_LOGGER
450   log_file_data_pair *logs;
451   int n;
452
453   LOG(log_info, logtype_logger, "log_close called");
454
455   for(n=(sizeof(log_file_arr)-1);n>0;n--)
456   {
457     logs = log_file_arr[n];
458 #ifdef KEEP_LOGFILES_OPEN
459     if ((*logs)[1].log_file!=NULL)
460       fclose((*logs)[1].log_file);
461 #endif /* KEEP_LOGFILES_OPEN */
462     if (logs!=NULL)
463     {
464       LOG(log_debug, logtype_logger, "freeing log entry at %d", n);
465 #ifdef DEBUG_OUTPUT_TO_SCREEN
466       printf("Freeing log_data %d, stored at %p\n", n, logs);
467       printf("\t(filename) %s\t(type) %s\n", (*logs)[1].log_filename, 
468              ((n<num_logtype_strings)?arr_logtype_strings[n]:""));
469 #endif /* DEBUG_OUTPUT_TO_SCREEN */
470       free(logs);
471     }
472     log_file_arr[n] = NULL;
473   }
474 #ifdef DEBUG_OUTPUT_TO_SCREEN
475       printf("Freeing log_data %d, stored at %p\n", n, log_file_arr[n]);
476       printf("\t(filename) %s\t(type) %s\n", 
477              (*(log_file_arr[n]))[1].log_filename, 
478              ((n<num_logtype_strings)?arr_logtype_strings[n]:"")
479              );
480 #endif /* DEBUG_OUTPUT_TO_SCREEN */
481 #endif /* DISABLE_LOGGER */
482
483   LOG(log_debug, logtype_logger, "log_close done");
484
485   closelog();
486 }
487
488 /* This function sets up the processname */
489 void set_processname(char *processname)
490 {
491 #ifndef DISABLE_LOGGER
492   /* strncpy(global_log_data.processname, GetCommandName(processname), 15); */
493   strncpy(global_log_data.processname, processname, 15);
494   global_log_data.processname[15] = 0;
495 #else /* DISABLE_LOGGER */
496   disabled_logger_processname = processname;
497 #endif /* DISABLE_LOGGER */
498 }
499
500 #ifndef DISABLE_LOGGER
501 /* This is called by the macro so set the location of the caller of Log */
502 make_log_func set_log_location(char *srcfilename, int srclinenumber)
503 {
504 #ifdef DEBUG_OUTPUT_TO_SCREEN
505   printf("Setting Log Location\n");
506 #endif
507   global_log_data.temp_src_filename = srcfilename;
508   global_log_data.temp_src_linenumber = srclinenumber;
509
510   return make_log_entry;
511 }
512 #endif /* DISABLE_LOGGER */
513
514 /* -------------------------------------------------------------------------
515     MakeLog has 1 main flaws:
516       The message in its entirity, must fit into the tempbuffer.  
517       So it must be shorter than MAXLOGSIZE
518    ------------------------------------------------------------------------- */
519 void make_log_entry(enum loglevels loglevel, enum logtypes logtype, 
520                     char *message, ...)
521 {
522   va_list args;
523   char log_buffer[MAXLOGSIZE];
524 #ifndef DISABLE_LOGGER
525   char log_details_buffer[MAXLOGSIZE];
526 #ifdef OPEN_LOGS_AS_UID
527   uid_t process_uid;
528 #endif
529   log_file_data_pair *logs;
530
531   log_init();
532
533   logs = log_file_arr[logtype];
534
535   if (logs==NULL)
536   {
537     logs = log_file_arr[logtype_default];
538   }
539 #ifdef DEBUG_OUTPUT_TO_SCREEN
540   printf("Making Log\n");
541 #endif
542   
543 #endif /* DISABLE_LOGGER */
544
545   /* Initialise the Messages */
546   va_start(args, message);
547
548   vsnprintf(log_buffer, sizeof(log_buffer), message, args);
549
550   /* Finished with args for now */
551   va_end(args);
552
553 #ifdef DISABLE_LOGGER
554   syslog(get_syslog_equivalent(loglevel), "%s", log_buffer);
555 #else /* DISABLE_LOGGER */
556
557 #ifdef DO_SYSLOG
558   /* check if sysloglevel is high enough */
559   if ((*logs)[0].log_level>=loglevel)
560   {
561     int sysloglevel = get_syslog_equivalent(loglevel);
562
563     generate_message_details(log_details_buffer, sizeof(log_details_buffer),
564                               &(*logs)[0], loglevel, logtype);
565
566 #ifdef DEBUG_OUTPUT_TO_SCREEN
567     printf("About to log %s %s\n", log_details_buffer, log_buffer);
568     printf("about to do syslog\n");
569     printf("done onw syslog\n");
570 #endif
571     syslog(sysloglevel, "%s: %s", log_details_buffer, log_buffer);
572     /* 
573        syslog(sysloglevel, "%s:%s: %s", log_levelString, 
574               log_typeString, LogBuffer); 
575      */
576   }
577 #endif
578
579 #ifdef DO_FILELOG
580 #ifdef DEBUG_OUTPUT_TO_SCREEN
581   printf("about to do the filelog\n");
582 #endif
583   /* check if log_level is high enough */
584   if ((*logs)[1].log_level>=loglevel) {    
585  
586 #ifdef DEBUG_OUTPUT_TO_SCREEN
587     printf("Open the Log, FILE* is %p\n", (*logs)[1].log_file);
588 #endif
589     /* if log isn't open, open it */
590     if ((*logs)[1].log_file==NULL) {
591 #ifdef DEBUG_OUTPUT_TO_SCREEN
592       printf("Opening the Log, filename is %s\n", (*logs)[1].log_filename);
593 #endif
594 #ifdef OPEN_LOGS_AS_UID
595    process_uid = getuid();
596    setuid(OPEN_LOGS_AS_UID);
597 #endif
598       (*logs)[1].log_file     = fopen((*logs)[1].log_filename, "at");
599 #ifdef OPEN_LOGS_AS_UID
600    setuid(process_uid);
601 #endif
602       if ((*logs)[1].log_file == NULL)
603       {
604         (*logs)[1].log_file = stdout;
605         LOG(log_severe, logtype_logger, "can't open Logfile %s", 
606             (*logs)[1].log_filename
607             );
608         return;
609       }
610     }
611     generate_message_details(log_details_buffer, sizeof(log_details_buffer),
612                              &(*logs)[1], loglevel, logtype);
613
614 #ifdef DEBUG_OUTPUT_TO_SCREEN
615     printf("Files open, lets log\n");
616     printf("FILE* is %p\n", (*logs)[1].log_file);
617     printf("%s: %s\n", log_details_buffer, log_buffer);
618 #endif
619
620     fprintf((*logs)[1].log_file, "%s: %s\n", log_details_buffer, log_buffer);
621
622 #ifndef KEEP_LOGFILES_OPEN
623     if ((*logs)[1].log_file != stdout)
624     {
625 #ifdef DEBUG_OUTPUT_TO_SCREEN
626       printf("Closing %s\n", (*logs)[1].log_filename);
627 #endif
628       fclose((*logs)[1].log_file);
629       (*logs)[1].log_file = NULL;
630 #ifdef DEBUG_OUTPUT_TO_SCREEN
631       printf("Closed\n");
632 #endif
633     }
634 #else // KEEP_LOGFILES_OPEN
635     fflush((*logs)[1].log_file);
636 #endif // KEEP_LOGFILES_OPEN
637   }
638 #endif
639
640   global_log_data.temp_src_filename = NULL;
641   global_log_data.temp_src_linenumber = 0;
642 #endif /* DISABLE_LOGGER */
643 }
644
645 #ifndef DISABLE_LOGGER
646 void load_proccessname_from_proc()
647 {
648   pid_t pid = getpid();
649   char buffer[PATH_MAX];
650   char procname[16];
651   FILE * statfile;
652   char *ptr;
653
654   sprintf(buffer, "/proc/%d/stat", pid);
655   statfile = fopen(buffer, "rt");
656   fgets(buffer, PATH_MAX-1, statfile);
657   fclose(statfile);
658
659   ptr = (char *)strrchr(buffer, ')');
660   *ptr = '\0';
661   memset(procname, 0, sizeof procname);
662   sscanf(buffer, "%d (%15c", &pid, procname);   /* comm[16] in kernel */
663
664   set_processname(procname);
665 }
666
667 /* =========================================================================
668     Internal function definitions
669    ========================================================================= */
670
671 static char *get_command_name(char *commandpath)
672 {
673   char *ptr;
674 #ifdef DEBUG_OUTPUT_TO_SCREEN
675   printf("getting command name %s\n",commandpath);
676 #endif
677   ptr = (char *)strrchr(commandpath, '/');
678   if (ptr==NULL)
679     ptr = commandpath;
680   else
681     ptr++;
682
683 #ifdef DEBUG_OUTPUT_TO_SCREEN
684   printf("Concluded %s\n", ptr);
685 #endif
686   return ptr;
687 }
688
689 void  workout_what_to_print(struct what_to_print_array *what_to_print, 
690                             struct tag_log_file_data *log_struct)
691 {
692   /* is this a syslog entry? */
693   if (log_struct->log_filename[0]==0)
694   {
695     what_to_print->print_datetime = false;
696     what_to_print->print_processname = false;
697     what_to_print->print_pid = false;
698   }
699   else
700   {
701     what_to_print->print_datetime = true;
702     what_to_print->print_processname = true;
703  
704     /* pid is dealt with at the syslog level if we're syslogging */
705     what_to_print->print_pid = 
706       (((log_struct->display_options & logoption_pid) == 0)?false:true);
707   }
708
709   what_to_print->print_srcfile = 
710     (((log_struct->display_options & logoption_nfile) == 0)?true:false);
711   what_to_print->print_srcline = 
712     (((log_struct->display_options & logoption_nline) == 0)?true:false);
713   
714   what_to_print->print_errlevel = true;
715   what_to_print->print_errtype = true;
716 }
717
718 void generate_message_details(char *message_details_buffer, 
719                               int message_details_buffer_length,
720                               struct tag_log_file_data *log_struct,
721                               enum loglevels loglevel, enum logtypes logtype)
722 {
723   char datebuffer[32];
724   char processinfo[64];
725
726   char *ptr = message_details_buffer;
727   int   templen;
728   int   len = message_details_buffer_length;
729
730   char log_buffer[MAXLOGSIZE];
731   const char *logtype_string;
732
733   char loglevel_string[12]; /* max int size is 2 billion, or 10 digits */
734
735   struct what_to_print_array what_to_print;
736
737   workout_what_to_print(&what_to_print, log_struct);
738
739 #ifdef DEBUG_OUTPUT_TO_SCREEN
740   printf("Making MessageDetails\n");
741 #endif
742
743   *ptr = 0;
744   /*
745   datebuffer[0] = 0;
746   ptr = datebuffer;
747   */
748
749   if (what_to_print.print_datetime)
750   {
751     time_t thetime;
752     time(&thetime);
753
754   /* some people might prefer localtime() to gmtime() */
755     strftime(ptr, len, "%b %d %H:%M:%S", localtime(&thetime));
756 #ifdef DEBUG_OUTPUT_TO_SCREEN
757     printf("date is %s\n", ptr);
758 #endif
759
760     templen = strlen(ptr);
761     len -= templen;
762     if (what_to_print.print_processname || what_to_print.print_pid)
763       strncat(ptr, " ", len);
764     else
765       strncat(ptr, ":", len);
766
767     templen++;
768     len --;
769     ptr += templen;
770   }
771
772   /*
773   processinfo[0] = 0;
774   ptr = processinfo;
775   */
776
777   if (what_to_print.print_processname)
778   {
779     strncpy(ptr, global_log_data.processname, len);
780
781     templen = strlen(ptr);
782     len -= templen;
783     ptr += templen;
784   }
785
786   if (what_to_print.print_pid)
787   {
788     pid_t pid = getpid();
789
790     sprintf(ptr, "[%d]", pid);
791
792     templen = strlen(ptr);
793     len -= templen;
794     ptr += templen;
795   }
796
797   if (what_to_print.print_srcfile || what_to_print.print_srcline)
798   {
799     char sprintf_buffer[8];
800     char *buff_ptr;
801
802     sprintf_buffer[0] = '[';
803     if (what_to_print.print_srcfile)
804     {
805       strcpy(&sprintf_buffer[1], "%s");
806       buff_ptr = &sprintf_buffer[3];
807     }
808     if (what_to_print.print_srcfile && what_to_print.print_srcline)
809     {
810       strcpy(&sprintf_buffer[3], ":");
811       buff_ptr = &sprintf_buffer[4];
812     }
813     if (what_to_print.print_srcline)
814     {
815       strcpy(buff_ptr, "%d");
816       buff_ptr = &buff_ptr[2];
817     }
818     strcpy(buff_ptr, "]");
819
820     /* 
821        ok sprintf string is ready, now is the 1st parameter src or linenumber
822      */
823     if (what_to_print.print_srcfile)
824     {
825       sprintf(ptr, sprintf_buffer, 
826               global_log_data.temp_src_filename, 
827               global_log_data.temp_src_linenumber);
828     }
829     else
830     {
831       sprintf(ptr, sprintf_buffer, global_log_data.temp_src_linenumber);
832     }
833
834 #ifdef DEBUG_OUTPUT_TO_SCREEN
835     printf("Process info is %s\n", ptr);
836 #endif
837
838     templen = strlen(ptr);
839     len -= templen;
840     ptr += templen;
841
842   }
843
844   if (what_to_print.print_processname || what_to_print.print_pid ||
845       what_to_print.print_srcfile || what_to_print.print_srcline)
846   {
847     strncat(ptr, ": ", len);
848     len -= 2;
849     ptr += 2;
850   }
851
852 /*
853   loglevel_string[0] = 0;
854   ptr = loglevel_string;
855 */
856
857   if (what_to_print.print_errlevel)
858   {
859     if ((loglevel/10) >= (num_loglevel_chars-1))
860     {
861       sprintf(ptr, "%c%d", arr_loglevel_chars[num_loglevel_chars-1],
862                                        loglevel/10);
863     }
864     else
865     {
866       sprintf(ptr, "%c", arr_loglevel_chars[loglevel/10]);
867     }
868
869     templen = strlen(ptr);
870     len -= templen;
871     ptr += templen;    
872   }
873
874   if (what_to_print.print_errtype)
875   {
876     const char *logtype_string;
877
878     /* get string represnetation of the Log Type */
879     if (logtype<num_logtype_strings)
880       logtype_string = arr_logtype_strings[logtype];
881     else
882       logtype_string = "";
883
884     if (what_to_print.print_errlevel)
885     {
886       strncat(ptr, ":", len);
887       ptr++;
888     }
889
890     sprintf(ptr, "%s", logtype_string);
891   }
892
893   message_details_buffer[message_details_buffer_length-1] = 0;
894
895 #ifdef DEBUG_OUTPUT_TO_SCREEN
896     printf("Message Details are %s\n", message_details_buffer);
897 #endif
898 }
899 #endif /* DISABLE_LOGGER */
900
901 int get_syslog_equivalent(enum loglevels loglevel)
902 {
903   switch (loglevel/10)
904   {
905     /* The question is we know how bad it is for us,
906                     but how should that translate in the syslogs?  */
907     case 0: /* severe */
908       return LOG_ERR;
909     case 1: /* error */
910       return LOG_ERR;
911     case 2: /* warning */
912       return LOG_WARNING;
913     case 3: /* note */
914       return LOG_NOTICE;
915     case 4: /* information */
916       return LOG_INFO;
917     default: /* debug */
918       return LOG_DEBUG;
919   }
920 }
921
922 /* void setuplog(char *logsource, char *logtype, char *loglevel, char *filename) */
923 void setuplog(char *logtype, char *loglevel, char *filename)
924 {
925 #ifndef DISABLE_LOGGER 
926   /* -[un]setuplog <logtype> <loglevel> [<filename>]*/
927   /*
928     This should be rewritten so that somehow logsource is assumed and everything
929     can be taken from default if needs be.  
930    */
931   /* const char* sources[] = {"syslog", "filelog"}; */
932   const char *null = "";
933   int sourcenum, typenum, levelnum;
934   log_file_data_pair *logs = log_file_arr[logtype_default];
935
936   /*
937   LOG(log_extradebug, logtype_logger, "Attempting setuplog: %s %s %s %s", 
938       logsource, logtype, loglevel, filename);
939   */
940   LOG(log_info, logtype_logger, "setuplog is parsing logtype:%s, loglevel:%s, filename:%s", 
941       logtype, loglevel, filename);
942
943   if (logtype==NULL)
944   {
945     LOG(log_note, logtype_logger, "no logsource given, default is assumed");
946     typenum=0;
947   }
948   else
949   {
950     for(typenum=0;typenum<num_logtype_strings;typenum++)
951     {
952       if (strcasecmp(logtype, arr_logtype_strings[typenum])==0)
953         break;
954     }
955     if (typenum>=num_logtype_strings)
956     {
957       LOG(log_warning, logtype_logger, "%s is not a valid log type", logtype);
958     }
959   }
960
961   if (loglevel==NULL)
962   {
963     LOG(log_note, logtype_logger, "no loglevel given, severe is assumed");
964     levelnum=0;
965   }
966   else
967   {
968     for(levelnum=0;levelnum<num_loglevel_strings;levelnum++)
969     {
970       if (strcasecmp(loglevel, arr_loglevel_strings[levelnum])==0)
971         break;
972     }
973     if (levelnum>=num_loglevel_strings)
974     {
975       LOG(log_warning, logtype_logger, "%s is not a valid log level", loglevel);
976     }
977   }
978
979   /* sanity check */
980   if ((typenum>=num_logtype_strings) || (levelnum>=num_loglevel_strings))
981   {
982     LOG(log_warning, logtype_logger, "sanity check failed: (%s:%d), (%s:%d)", 
983                     logtype, typenum, loglevel, levelnum);
984     return;
985   }
986
987   /* now match the order of the text string with the actual enum value (10 times) */
988   levelnum*=10;
989   
990   /* is this a syslog setup or a filelog setup */
991   if (filename==NULL) /* must be syslog */
992   {
993     LOG(log_debug6, logtype_logger, "calling syslog_setup(%d, %d, ...)", levelnum, typenum);
994     syslog_setup(levelnum, typenum, 
995                  (*logs)[0].display_options,
996                  global_log_data.facility);
997   }
998   else /* this must be a filelog */
999   {
1000     LOG(log_debug6, logtype_logger, "calling log_setup(%s, %d, %d, ...)", filename, levelnum, typenum);
1001     log_setup(filename, levelnum, typenum, 
1002               (*logs)[0].display_options);
1003   };  
1004   return;
1005 #endif /* DISABLE_LOGGER */
1006 }
1007
1008
1009
1010
1011
1012
1013