]> arthur.barton.de Git - netatalk.git/blob - libatalk/util/logger.c
- merge branch-netatalk-afp-3x-dev, HEAD was tagged before
[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 int get_syslog_equivalent(enum loglevels loglevel);
87
88 #ifndef DISABLE_LOGGER
89 make_log_func set_log_location(char *srcfilename, int srclinenumber);
90
91 /* ========================================================================= 
92     Structure definitions
93    ========================================================================= */
94
95 /* A structure containing object level stuff */
96 struct tag_log_file_data {
97   char log_filename[PATH_MAX];  /* Name of file */
98   FILE *log_file;      /* FILE pointer to file */
99   enum loglevels   log_level;     /* Log Level to put in this file */
100   int  display_options;
101 };
102
103 typedef struct tag_log_file_data log_file_data_pair[2];
104
105 /* A structure containg class level stuff */
106 struct tag_global_log_data {
107   int   struct_size;
108
109   char *temp_src_filename;
110   int   temp_src_linenumber;
111   char  processname[16];
112   
113   int   facility;
114   char *log_file_directory;  /* Path of directory containing log files */
115   log_file_data_pair **logs;
116 };
117
118 struct what_to_print_array {
119   bool print_datetime;
120   bool print_processname;
121   bool print_pid;
122   bool print_srcfile;
123   bool print_srcline;
124   bool print_errlevel;
125   bool print_errtype;
126 };
127
128 /* =========================================================================
129     Internal function declarations
130    ========================================================================= */
131
132 void generate_message_details(char *message_details_buffer,
133                               int message_details_buffer_length,
134                               struct tag_log_file_data *log_struct,
135                               enum loglevels loglevel, enum logtypes logtype);
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 #ifdef CHECK_STAT_ON_NEW_FILES
239   struct stat statbuf;
240   int firstattempt;
241   int retval;
242   gid_t gid;
243   uid_t uid;
244   int access;
245 #endif
246   char lastchar[2];
247
248   log_file_data_pair *logs;
249   
250   log_init();
251
252   logs = log_file_arr[logtype];
253   
254   LOG(log_info, logtype_logger, "doing log_setup, type %d, level %d, filename \"%s\"", logtype, loglevel, filename);
255
256   /* LOG(log_extradebug+10, logtype_logger, "checking array for logtype is malloc'd"); */
257   /* has the given logtype already been assigned memory? */
258   if (logs==NULL)
259   {
260     logs = (log_file_data_pair *)malloc(sizeof(log_file_data_pair));
261     if (logs==NULL)
262     {
263       LOG(log_severe, logtype_logger, "can't calloc in log_setup");
264     }
265     else
266     {
267     /*
268       memcpy(logs, log_file_arr[logtype_default], sizeof(log_file_data_pair));
269      */
270       log_file_arr[logtype] = logs;
271       (*logs)[1].log_file = NULL;
272     }
273   }
274
275   /* I think this checks if we're logging to stdout or not.  Probably unused */
276   if ( ((*logs)[1].log_file == stdout) && ((*logs)[1].log_file != NULL) )
277   {
278     fclose((*logs)[1].log_file);
279     (*logs)[1].log_file = NULL;
280   }
281
282   /* check if we need to append the given filename to a directory */
283   if (strlen(global_log_data.log_file_directory)>0)
284   {
285     lastchar[0] = global_log_data.
286       log_file_directory[strlen(global_log_data.log_file_directory)-1];
287
288     if (lastchar[0] == '/' || lastchar[0] == '\\' || lastchar[0] == ':')
289       lastchar[0] = 0;
290     else
291       /* this should probably be a platform specific path separator */
292       lastchar[0] = '/';
293
294     lastchar[1] = 0;
295   }
296   else
297     lastchar[0] = 0;
298   
299 #ifdef DEBUG_OUTPUT_TO_SCREEN
300   printf("filename is %s stored at location %p\n", (*logs)[1].log_filename, 
301                                                    (*logs)[1].log_filename);
302 #endif /* DEBUG_OUTPUT_TO_SCREEN */
303   if (filename == NULL)
304   {
305     strncpy((*logs)[1].log_filename, 
306             (*(log_file_arr[0]))[1].log_filename, PATH_MAX);
307   }
308   else
309   {
310     sprintf((*logs)[1].log_filename, "%s%s%s", 
311             global_log_data.log_file_directory,
312             lastchar, filename);
313   }
314   (*logs)[1].log_level    = loglevel;
315   (*logs)[1].display_options = display_options;
316
317 #ifdef DEBUG_OUTPUT_TO_SCREEN
318   printf("filename is %s stored at location %p\n", (*logs)[1].log_filename, 
319                                                    (*logs)[1].log_filename);
320 #endif /* DEBUG_OUTPUT_TO_SCREEN */
321
322 #ifdef CHECK_STAT_ON_NEW_FILES
323   uid = geteuid(); 
324   gid = getegid();
325   
326 #ifdef DEBUG_OUTPUT_TO_SCREEN
327   printf("about to stat file %s\n", (*logs)[1].log_filename);
328 #endif
329   firstattempt = stat((*logs)[1].log_filename, &statbuf);
330
331   if (firstattempt == -1)
332   {
333 #ifdef DEBUG_OUTPUT_TO_SCREEN
334     printf("about to call Log with %d, %d, %s, %s\n", 
335            log_note, logtype_logger, 
336            "can't stat Logfile", 
337            (*logs)[1].log_filename
338            );
339 #endif
340
341     /* syslog(LOG_INFO, "stat failed"); */
342     LOG(log_warning, logtype_logger, "stat fails on file %s",
343                      (*logs)[1].log_filename);
344
345     if (strlen(global_log_data.log_file_directory)>0)
346     {
347       retval = stat(global_log_data.log_file_directory, &statbuf);
348       if (retval == -1)
349       {
350 #ifdef DEBUG_OUTPUT_TO_SCREEN
351         printf("can't stat dir either so I'm giving up\n");
352 #endif
353         LOG(log_severe, logtype_logger, "can't stat directory %s either",
354                          global_log_data.log_file_directory);
355         return false;
356       } 
357     }
358   }
359
360 #ifdef CHECK_ACCESS_ON_NEW_FILES
361   access = ((statbuf.st_uid == uid)?(statbuf.st_mode & S_IWUSR):0) + 
362            ((statbuf.st_gid == gid)?(statbuf.st_mode & S_IWGRP):0) +
363            (statbuf.st_mode & S_IWOTH);
364
365   if (access==0)
366   {
367 #ifdef DEBUG_OUTPUT_TO_SCREEN
368     printf("failing with %d, %d, %s, %s\n", log_note, logtype_logger,
369            "can't access Logfile %s",    (*logs)[1].log_filename);
370 #endif
371
372     LOG(log_note, logtype_logger, "can't access file %s", 
373                      (*logs)[1].log_filename);
374     return false;
375   }
376 #endif /* CHECK_ACCESS_ON_NEW_FILES */
377 #endif /* CHECK_STAT_ON_NEW_FILES */
378 /*
379 #ifdef KEEP_LOGFILES_OPEN
380   if ((*logs)[1].log_file!=NULL)
381     fclose((*logs)[1].log_file);
382
383   (*logs)[1].log_file     = fopen((*logs)[1].log_filename, "at");
384   if ((*logs)[1].log_file == NULL)
385   {
386     LOG(log_severe, logtype_logger, "can't open Logfile %s", 
387         (*logs)[1].log_filename
388         );
389     return false;
390   }
391 #endif
392 */
393
394   LOG(log_debug7, logtype_logger, "log_file_arr[%d] now contains: "
395                                   "{log_filename:%s, log_file:%p, log_level: %d}", logtype,
396                                    (*logs)[1].log_filename, (*logs)[1].log_file, (*logs)[1].log_level);
397   LOG(log_debug, logtype_logger, "log_setup[%d] done", logtype);
398
399 #endif /* DISABLE_LOGGER */
400   return true;
401 }
402
403
404 void syslog_setup(enum loglevels loglevel, enum logtypes logtype, 
405                   int display_options, int facility)
406 {
407 #ifndef DISABLE_LOGGER
408   log_file_data_pair *logs;
409
410   log_init();
411
412   logs = log_file_arr[logtype];
413
414   LOG(log_info, logtype_logger, "doing syslog_setup, type %d, level %d", logtype, loglevel);
415
416   if (logs==NULL)
417   {
418     logs = (log_file_data_pair *)malloc(sizeof(log_file_data_pair));    
419     if (logs==NULL)
420     {
421       LOG(log_severe, logtype_logger, "can't calloc in log_setup");
422     }
423     else
424     {
425       memcpy(logs, log_file_arr[logtype_default], sizeof(log_file_data_pair));
426       log_file_arr[logtype] = logs;
427     }
428   }
429
430   (*logs)[0].log_file        = NULL;
431   (*logs)[0].log_filename[0] = 0;
432   (*logs)[0].log_level       = loglevel;
433   (*logs)[0].display_options = display_options;
434   global_log_data.facility   = facility;
435
436   openlog(global_log_data.processname, (*logs)[0].display_options, 
437           global_log_data.facility);
438
439   LOG(log_debug7, logtype_logger, "log_file_arr[%d] now contains: "
440                                   "{log_filename:%s, log_file:%p, log_level: %d}", logtype,
441                                   (*logs)[0].log_filename, (*logs)[0].log_file, (*logs)[0].log_level);
442   LOG(log_debug, logtype_logger, "syslog_setup[%d] done", logtype);
443 #else /* DISABLE_LOGGER */
444 /* behave like a normal openlog call */
445   openlog(disabled_logger_processname, display_options, facility);
446 #endif /* DISABLE_LOGGER */
447 }
448
449 void log_close()
450 {
451 #ifndef DISABLE_LOGGER
452   log_file_data_pair *logs;
453   int n;
454
455   LOG(log_info, logtype_logger, "log_close called");
456
457   for(n=(sizeof(log_file_arr)-1);n>0;n--)
458   {
459     logs = log_file_arr[n];
460 #ifdef KEEP_LOGFILES_OPEN
461     if ((*logs)[1].log_file!=NULL)
462       fclose((*logs)[1].log_file);
463 #endif /* KEEP_LOGFILES_OPEN */
464     if (logs!=NULL)
465     {
466       LOG(log_debug, logtype_logger, "freeing log entry at %d", n);
467 #ifdef DEBUG_OUTPUT_TO_SCREEN
468       printf("Freeing log_data %d, stored at %p\n", n, logs);
469       printf("\t(filename) %s\t(type) %s\n", (*logs)[1].log_filename, 
470              ((n<num_logtype_strings)?arr_logtype_strings[n]:""));
471 #endif /* DEBUG_OUTPUT_TO_SCREEN */
472       free(logs);
473     }
474     log_file_arr[n] = NULL;
475   }
476 #ifdef DEBUG_OUTPUT_TO_SCREEN
477       printf("Freeing log_data %d, stored at %p\n", n, log_file_arr[n]);
478       printf("\t(filename) %s\t(type) %s\n", 
479              (*(log_file_arr[n]))[1].log_filename, 
480              ((n<num_logtype_strings)?arr_logtype_strings[n]:"")
481              );
482 #endif /* DEBUG_OUTPUT_TO_SCREEN */
483 #endif /* DISABLE_LOGGER */
484
485   LOG(log_debug, logtype_logger, "log_close done");
486
487   closelog();
488 }
489
490 /* This function sets up the processname */
491 void set_processname(char *processname)
492 {
493 #ifndef DISABLE_LOGGER
494   /* strncpy(global_log_data.processname, GetCommandName(processname), 15); */
495   strncpy(global_log_data.processname, processname, 15);
496   global_log_data.processname[15] = 0;
497 #else /* DISABLE_LOGGER */
498   disabled_logger_processname = processname;
499 #endif /* DISABLE_LOGGER */
500 }
501
502 #ifndef DISABLE_LOGGER
503 /* This is called by the macro so set the location of the caller of Log */
504 make_log_func set_log_location(char *srcfilename, int srclinenumber)
505 {
506 #ifdef DEBUG_OUTPUT_TO_SCREEN
507   printf("Setting Log Location\n");
508 #endif
509   global_log_data.temp_src_filename = srcfilename;
510   global_log_data.temp_src_linenumber = srclinenumber;
511
512   return make_log_entry;
513 }
514 #endif /* DISABLE_LOGGER */
515
516 /* ---------------------- 
517  * chainsawed from ethereal
518 */
519 #ifdef isprint
520 #undef isprint
521 #endif
522 #define isprint(c) ((c) >= 0x20 && (c) < 0x7f)
523
524 static char *format_text(char *fmtbuf, const char *string)
525 {
526   int column;
527   const char *stringend = string + strlen(string);
528   char c;
529   int i;
530
531   column = 0;
532   while (string < stringend) {
533     c = *string++;
534
535     if (isprint(c)) {
536       fmtbuf[column] = c;
537       column++;
538     } else {
539       fmtbuf[column] =  '\\';
540       column++;
541       switch (c) {
542       case '\\':
543         fmtbuf[column] = '\\';
544         column++;
545         break;
546       case '\a':
547         fmtbuf[column] = 'a';
548         column++;
549         break;
550       case '\b':
551         fmtbuf[column] = 'b';
552         column++;
553         break;
554       case '\f':
555         fmtbuf[column] = 'f';
556         column++;
557         break;
558       case '\n':
559         fmtbuf[column] = 'n';
560         column++;
561         break;
562       case '\r':
563         fmtbuf[column] = 'r';
564         column++;
565         break;
566       case '\t':
567         fmtbuf[column] = 't';
568         column++;
569         break;
570       case '\v':
571         fmtbuf[column] = 'v';
572         column++;
573         break;
574       default:
575         i = (c>>6)&03;
576         fmtbuf[column] = i + '0';
577         column++;
578         i = (c>>3)&07;
579         fmtbuf[column] = i + '0';
580         column++;
581         i = (c>>0)&07;
582         fmtbuf[column] = i + '0';
583         column++;
584         break;
585       }
586     }
587   }
588   fmtbuf[column] = '\0';
589   return fmtbuf;
590 }
591 /* -------------------------------------------------------------------------
592     MakeLog has 1 main flaws:
593       The message in its entirity, must fit into the tempbuffer.  
594       So it must be shorter than MAXLOGSIZE
595    ------------------------------------------------------------------------- */
596 void make_log_entry(enum loglevels loglevel, enum logtypes logtype, 
597                     char *message, ...)
598 {
599   va_list args;
600   char temp_buffer[MAXLOGSIZE];
601   char log_buffer[4*MAXLOGSIZE];
602   /* fn is not reentrant but is used in signal handler 
603    * with LOGGER it's a little late source name and line number
604    * are already changed.
605   */
606   static int inlog = 0;
607
608 #ifndef DISABLE_LOGGER
609   char log_details_buffer[MAXLOGSIZE];
610 #ifdef OPEN_LOGS_AS_UID
611   uid_t process_uid;
612 #endif
613   log_file_data_pair *logs;
614 #endif
615
616   if (inlog)
617      return;
618   inlog = 1;
619   
620 #ifndef DISABLE_LOGGER
621   log_init();
622
623   logs = log_file_arr[logtype];
624
625   if (logs==NULL)
626   {
627     logs = log_file_arr[logtype_default];
628   }
629 #ifdef DEBUG_OUTPUT_TO_SCREEN
630   printf("Making Log\n");
631 #endif
632   
633 #endif /* DISABLE_LOGGER */
634
635   /* Initialise the Messages */
636   va_start(args, message);
637
638   vsnprintf(temp_buffer, sizeof(temp_buffer), message, args);
639
640   /* Finished with args for now */
641   va_end(args);
642   format_text(log_buffer, temp_buffer);
643
644 #ifdef DISABLE_LOGGER
645   syslog(get_syslog_equivalent(loglevel), "%s", log_buffer);
646 #else /* DISABLE_LOGGER */
647
648 #ifdef DO_SYSLOG
649   /* check if sysloglevel is high enough */
650   if ((*logs)[0].log_level>=loglevel)
651   {
652     int sysloglevel = get_syslog_equivalent(loglevel);
653
654     generate_message_details(log_details_buffer, sizeof(log_details_buffer),
655                               &(*logs)[0], loglevel, logtype);
656
657 #ifdef DEBUG_OUTPUT_TO_SCREEN
658     printf("About to log %s %s\n", log_details_buffer, log_buffer);
659     printf("about to do syslog\n");
660     printf("done onw syslog\n");
661 #endif
662     syslog(sysloglevel, "%s: %s", log_details_buffer, log_buffer);
663     /* 
664        syslog(sysloglevel, "%s:%s: %s", log_levelString, 
665               log_typeString, LogBuffer); 
666      */
667   }
668 #endif
669
670 #ifdef DO_FILELOG
671 #ifdef DEBUG_OUTPUT_TO_SCREEN
672   printf("about to do the filelog\n");
673 #endif
674   /* check if log_level is high enough */
675   if ((*logs)[1].log_level>=loglevel) {    
676  
677 #ifdef DEBUG_OUTPUT_TO_SCREEN
678     printf("Open the Log, FILE* is %p\n", (*logs)[1].log_file);
679 #endif
680     /* if log isn't open, open it */
681     if ((*logs)[1].log_file==NULL) {
682 #ifdef DEBUG_OUTPUT_TO_SCREEN
683       printf("Opening the Log, filename is %s\n", (*logs)[1].log_filename);
684 #endif
685 #ifdef OPEN_LOGS_AS_UID
686    process_uid = getuid();
687    setuid(OPEN_LOGS_AS_UID);
688 #endif
689       (*logs)[1].log_file     = fopen((*logs)[1].log_filename, "at");
690 #ifdef OPEN_LOGS_AS_UID
691    setuid(process_uid);
692 #endif
693       if ((*logs)[1].log_file == NULL)
694       {
695         (*logs)[1].log_file = stdout;
696         LOG(log_severe, logtype_logger, "can't open Logfile %s", 
697             (*logs)[1].log_filename
698             );
699         inlog = 0;
700         return;
701       }
702     }
703     generate_message_details(log_details_buffer, sizeof(log_details_buffer),
704                              &(*logs)[1], loglevel, logtype);
705
706 #ifdef DEBUG_OUTPUT_TO_SCREEN
707     printf("Files open, lets log\n");
708     printf("FILE* is %p\n", (*logs)[1].log_file);
709     printf("%s: %s\n", log_details_buffer, log_buffer);
710 #endif
711
712     fprintf((*logs)[1].log_file, "%s: %s\n", log_details_buffer, log_buffer);
713
714 #ifndef KEEP_LOGFILES_OPEN
715     if ((*logs)[1].log_file != stdout)
716     {
717 #ifdef DEBUG_OUTPUT_TO_SCREEN
718       printf("Closing %s\n", (*logs)[1].log_filename);
719 #endif
720       fclose((*logs)[1].log_file);
721       (*logs)[1].log_file = NULL;
722 #ifdef DEBUG_OUTPUT_TO_SCREEN
723       printf("Closed\n");
724 #endif
725     }
726 #else // KEEP_LOGFILES_OPEN
727     fflush((*logs)[1].log_file);
728 #endif // KEEP_LOGFILES_OPEN
729   }
730 #endif
731
732   global_log_data.temp_src_filename = NULL;
733   global_log_data.temp_src_linenumber = 0;
734 #endif /* DISABLE_LOGGER */
735   inlog = 0;
736 }
737
738 #ifndef DISABLE_LOGGER
739 void load_proccessname_from_proc()
740 {
741   pid_t pid = getpid();
742   char buffer[PATH_MAX];
743   char procname[16];
744   FILE * statfile;
745   char *ptr;
746
747   sprintf(buffer, "/proc/%d/stat", pid);
748   statfile = fopen(buffer, "rt");
749   fgets(buffer, PATH_MAX-1, statfile);
750   fclose(statfile);
751
752   ptr = (char *)strrchr(buffer, ')');
753   *ptr = '\0';
754   memset(procname, 0, sizeof procname);
755   sscanf(buffer, "%d (%15c", &pid, procname);   /* comm[16] in kernel */
756
757   set_processname(procname);
758 }
759
760 /* =========================================================================
761     Internal function definitions
762    ========================================================================= */
763
764 static char *get_command_name(char *commandpath)
765 {
766   char *ptr;
767 #ifdef DEBUG_OUTPUT_TO_SCREEN
768   printf("getting command name %s\n",commandpath);
769 #endif
770   ptr = (char *)strrchr(commandpath, '/');
771   if (ptr==NULL)
772     ptr = commandpath;
773   else
774     ptr++;
775
776 #ifdef DEBUG_OUTPUT_TO_SCREEN
777   printf("Concluded %s\n", ptr);
778 #endif
779   return ptr;
780 }
781
782 void  workout_what_to_print(struct what_to_print_array *what_to_print, 
783                             struct tag_log_file_data *log_struct)
784 {
785   /* is this a syslog entry? */
786   if (log_struct->log_filename[0]==0)
787   {
788     what_to_print->print_datetime = false;
789     what_to_print->print_processname = false;
790     what_to_print->print_pid = false;
791   }
792   else
793   {
794     what_to_print->print_datetime = true;
795     what_to_print->print_processname = true;
796  
797     /* pid is dealt with at the syslog level if we're syslogging */
798     what_to_print->print_pid = 
799       (((log_struct->display_options & logoption_pid) == 0)?false:true);
800   }
801
802   what_to_print->print_srcfile = 
803     (((log_struct->display_options & logoption_nfile) == 0)?true:false);
804   what_to_print->print_srcline = 
805     (((log_struct->display_options & logoption_nline) == 0)?true:false);
806   
807   what_to_print->print_errlevel = true;
808   what_to_print->print_errtype = true;
809 }
810
811 void generate_message_details(char *message_details_buffer, 
812                               int message_details_buffer_length,
813                               struct tag_log_file_data *log_struct,
814                               enum loglevels loglevel, enum logtypes logtype)
815 {
816 #if 0
817   char datebuffer[32];
818   char processinfo[64];
819   char log_buffer[MAXLOGSIZE];
820   const char *logtype_string;
821
822   char loglevel_string[12]; /* max int size is 2 billion, or 10 digits */
823 #endif
824
825   char *ptr = message_details_buffer;
826   int   templen;
827   int   len = message_details_buffer_length;
828
829
830   struct what_to_print_array what_to_print;
831
832   workout_what_to_print(&what_to_print, log_struct);
833
834 #ifdef DEBUG_OUTPUT_TO_SCREEN
835   printf("Making MessageDetails\n");
836 #endif
837
838   *ptr = 0;
839   /*
840   datebuffer[0] = 0;
841   ptr = datebuffer;
842   */
843
844   if (what_to_print.print_datetime)
845   {
846     time_t thetime;
847     time(&thetime);
848
849   /* some people might prefer localtime() to gmtime() */
850     strftime(ptr, len, "%b %d %H:%M:%S", localtime(&thetime));
851 #ifdef DEBUG_OUTPUT_TO_SCREEN
852     printf("date is %s\n", ptr);
853 #endif
854
855     templen = strlen(ptr);
856     len -= templen;
857     if (what_to_print.print_processname || what_to_print.print_pid)
858       strncat(ptr, " ", len);
859     else
860       strncat(ptr, ":", len);
861
862     templen++;
863     len --;
864     ptr += templen;
865   }
866
867   /*
868   processinfo[0] = 0;
869   ptr = processinfo;
870   */
871
872   if (what_to_print.print_processname)
873   {
874     strncpy(ptr, global_log_data.processname, len);
875
876     templen = strlen(ptr);
877     len -= templen;
878     ptr += templen;
879   }
880
881   if (what_to_print.print_pid)
882   {
883     pid_t pid = getpid();
884
885     sprintf(ptr, "[%d]", pid);
886
887     templen = strlen(ptr);
888     len -= templen;
889     ptr += templen;
890   }
891
892   if (what_to_print.print_srcfile || what_to_print.print_srcline)
893   {
894     char sprintf_buffer[8];
895     char *buff_ptr=NULL;
896
897     sprintf_buffer[0] = '[';
898     if (what_to_print.print_srcfile)
899     {
900       strcpy(&sprintf_buffer[1], "%s");
901       buff_ptr = &sprintf_buffer[3];
902     }
903     if (what_to_print.print_srcfile && what_to_print.print_srcline)
904     {
905       strcpy(&sprintf_buffer[3], ":");
906       buff_ptr = &sprintf_buffer[4];
907     }
908     if (what_to_print.print_srcline)
909     {
910       strcpy(buff_ptr, "%d");
911       buff_ptr = &buff_ptr[2];
912     }
913     strcpy(buff_ptr, "]");
914
915     /* 
916        ok sprintf string is ready, now is the 1st parameter src or linenumber
917      */
918     if (what_to_print.print_srcfile)
919     {
920       sprintf(ptr, sprintf_buffer, 
921               global_log_data.temp_src_filename, 
922               global_log_data.temp_src_linenumber);
923     }
924     else
925     {
926       sprintf(ptr, sprintf_buffer, global_log_data.temp_src_linenumber);
927     }
928
929 #ifdef DEBUG_OUTPUT_TO_SCREEN
930     printf("Process info is %s\n", ptr);
931 #endif
932
933     templen = strlen(ptr);
934     len -= templen;
935     ptr += templen;
936
937   }
938
939   if (what_to_print.print_processname || what_to_print.print_pid ||
940       what_to_print.print_srcfile || what_to_print.print_srcline)
941   {
942     strncat(ptr, ": ", len);
943     len -= 2;
944     ptr += 2;
945   }
946
947 /*
948   loglevel_string[0] = 0;
949   ptr = loglevel_string;
950 */
951
952   if (what_to_print.print_errlevel)
953   {
954     if ((loglevel/10) >= (num_loglevel_chars-1))
955     {
956       sprintf(ptr, "%c%d", arr_loglevel_chars[num_loglevel_chars-1],
957                                        loglevel/10);
958     }
959     else
960     {
961       sprintf(ptr, "%c", arr_loglevel_chars[loglevel/10]);
962     }
963
964     templen = strlen(ptr);
965     len -= templen;
966     ptr += templen;    
967   }
968
969   if (what_to_print.print_errtype)
970   {
971     const char *logtype_string;
972
973     /* get string represnetation of the Log Type */
974     if (logtype<num_logtype_strings)
975       logtype_string = arr_logtype_strings[logtype];
976     else
977       logtype_string = "";
978
979     if (what_to_print.print_errlevel)
980     {
981       strncat(ptr, ":", len);
982       ptr++;
983     }
984
985     sprintf(ptr, "%s", logtype_string);
986   }
987
988   message_details_buffer[message_details_buffer_length-1] = 0;
989
990 #ifdef DEBUG_OUTPUT_TO_SCREEN
991     printf("Message Details are %s\n", message_details_buffer);
992 #endif
993 }
994 #endif /* DISABLE_LOGGER */
995
996 int get_syslog_equivalent(enum loglevels loglevel)
997 {
998   switch (loglevel/10)
999   {
1000     /* The question is we know how bad it is for us,
1001                     but how should that translate in the syslogs?  */
1002     case 0: /* severe */
1003       return LOG_ERR;
1004     case 1: /* error */
1005       return LOG_ERR;
1006     case 2: /* warning */
1007       return LOG_WARNING;
1008     case 3: /* note */
1009       return LOG_NOTICE;
1010     case 4: /* information */
1011       return LOG_INFO;
1012     default: /* debug */
1013       return LOG_DEBUG;
1014   }
1015 }
1016
1017 /* void setuplog(char *logsource, char *logtype, char *loglevel, char *filename) */
1018 void setuplog(char *logtype, char *loglevel, char *filename)
1019 {
1020 #ifndef DISABLE_LOGGER 
1021   /* -[un]setuplog <logtype> <loglevel> [<filename>]*/
1022   /*
1023     This should be rewritten so that somehow logsource is assumed and everything
1024     can be taken from default if needs be.  
1025    */
1026   /* const char* sources[] = {"syslog", "filelog"}; */
1027   int typenum, levelnum;
1028   log_file_data_pair *logs = log_file_arr[logtype_default];
1029
1030   /*
1031   LOG(log_extradebug, logtype_logger, "Attempting setuplog: %s %s %s %s", 
1032       logsource, logtype, loglevel, filename);
1033   */
1034   LOG(log_info, logtype_logger, "setuplog is parsing logtype:%s, loglevel:%s, filename:%s", 
1035       logtype, loglevel, filename);
1036
1037   if (logtype==NULL)
1038   {
1039     LOG(log_note, logtype_logger, "no logsource given, default is assumed");
1040     typenum=0;
1041   }
1042   else
1043   {
1044     for(typenum=0;typenum<num_logtype_strings;typenum++)
1045     {
1046       if (strcasecmp(logtype, arr_logtype_strings[typenum])==0)
1047         break;
1048     }
1049     if (typenum>=num_logtype_strings)
1050     {
1051       LOG(log_warning, logtype_logger, "%s is not a valid log type", logtype);
1052     }
1053   }
1054
1055   if (loglevel==NULL)
1056   {
1057     LOG(log_note, logtype_logger, "no loglevel given, severe is assumed");
1058     levelnum=0;
1059   }
1060   else
1061   {
1062     for(levelnum=0;levelnum<num_loglevel_strings;levelnum++)
1063     {
1064       if (strcasecmp(loglevel, arr_loglevel_strings[levelnum])==0)
1065         break;
1066     }
1067     if (levelnum>=num_loglevel_strings)
1068     {
1069       LOG(log_warning, logtype_logger, "%s is not a valid log level", loglevel);
1070     }
1071   }
1072
1073   /* sanity check */
1074   if ((typenum>=num_logtype_strings) || (levelnum>=num_loglevel_strings))
1075   {
1076     LOG(log_warning, logtype_logger, "sanity check failed: (%s:%d), (%s:%d)", 
1077                     logtype, typenum, loglevel, levelnum);
1078     return;
1079   }
1080
1081   /* now match the order of the text string with the actual enum value (10 times) */
1082   levelnum*=10;
1083   
1084   /* is this a syslog setup or a filelog setup */
1085   if (filename==NULL) /* must be syslog */
1086   {
1087     LOG(log_debug6, logtype_logger, "calling syslog_setup(%d, %d, ...)", levelnum, typenum);
1088     syslog_setup(levelnum, typenum, 
1089                  (*logs)[0].display_options,
1090                  global_log_data.facility);
1091   }
1092   else /* this must be a filelog */
1093   {
1094     LOG(log_debug6, logtype_logger, "calling log_setup(%s, %d, %d, ...)", filename, levelnum, typenum);
1095     log_setup(filename, levelnum, typenum, 
1096               (*logs)[0].display_options);
1097   };  
1098   return;
1099 #endif /* DISABLE_LOGGER */
1100 }
1101
1102
1103
1104
1105
1106
1107