]> arthur.barton.de Git - netatalk.git/blob - libatalk/util/logger.c
big merge for db frontend and unicode.
[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 #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     MakeLog has 1 main flaws:
518       The message in its entirity, must fit into the tempbuffer.  
519       So it must be shorter than MAXLOGSIZE
520    ------------------------------------------------------------------------- */
521 void make_log_entry(enum loglevels loglevel, enum logtypes logtype, 
522                     char *message, ...)
523 {
524   va_list args;
525   char log_buffer[MAXLOGSIZE];
526 #ifndef DISABLE_LOGGER
527   char log_details_buffer[MAXLOGSIZE];
528 #ifdef OPEN_LOGS_AS_UID
529   uid_t process_uid;
530 #endif
531   log_file_data_pair *logs;
532
533   log_init();
534
535   logs = log_file_arr[logtype];
536
537   if (logs==NULL)
538   {
539     logs = log_file_arr[logtype_default];
540   }
541 #ifdef DEBUG_OUTPUT_TO_SCREEN
542   printf("Making Log\n");
543 #endif
544   
545 #endif /* DISABLE_LOGGER */
546
547   /* Initialise the Messages */
548   va_start(args, message);
549
550   vsnprintf(log_buffer, sizeof(log_buffer), message, args);
551
552   /* Finished with args for now */
553   va_end(args);
554
555 #ifdef DISABLE_LOGGER
556   syslog(get_syslog_equivalent(loglevel), "%s", log_buffer);
557 #else /* DISABLE_LOGGER */
558
559 #ifdef DO_SYSLOG
560   /* check if sysloglevel is high enough */
561   if ((*logs)[0].log_level>=loglevel)
562   {
563     int sysloglevel = get_syslog_equivalent(loglevel);
564
565     generate_message_details(log_details_buffer, sizeof(log_details_buffer),
566                               &(*logs)[0], loglevel, logtype);
567
568 #ifdef DEBUG_OUTPUT_TO_SCREEN
569     printf("About to log %s %s\n", log_details_buffer, log_buffer);
570     printf("about to do syslog\n");
571     printf("done onw syslog\n");
572 #endif
573     syslog(sysloglevel, "%s: %s", log_details_buffer, log_buffer);
574     /* 
575        syslog(sysloglevel, "%s:%s: %s", log_levelString, 
576               log_typeString, LogBuffer); 
577      */
578   }
579 #endif
580
581 #ifdef DO_FILELOG
582 #ifdef DEBUG_OUTPUT_TO_SCREEN
583   printf("about to do the filelog\n");
584 #endif
585   /* check if log_level is high enough */
586   if ((*logs)[1].log_level>=loglevel) {    
587  
588 #ifdef DEBUG_OUTPUT_TO_SCREEN
589     printf("Open the Log, FILE* is %p\n", (*logs)[1].log_file);
590 #endif
591     /* if log isn't open, open it */
592     if ((*logs)[1].log_file==NULL) {
593 #ifdef DEBUG_OUTPUT_TO_SCREEN
594       printf("Opening the Log, filename is %s\n", (*logs)[1].log_filename);
595 #endif
596 #ifdef OPEN_LOGS_AS_UID
597    process_uid = getuid();
598    setuid(OPEN_LOGS_AS_UID);
599 #endif
600       (*logs)[1].log_file     = fopen((*logs)[1].log_filename, "at");
601 #ifdef OPEN_LOGS_AS_UID
602    setuid(process_uid);
603 #endif
604       if ((*logs)[1].log_file == NULL)
605       {
606         (*logs)[1].log_file = stdout;
607         LOG(log_severe, logtype_logger, "can't open Logfile %s", 
608             (*logs)[1].log_filename
609             );
610         return;
611       }
612     }
613     generate_message_details(log_details_buffer, sizeof(log_details_buffer),
614                              &(*logs)[1], loglevel, logtype);
615
616 #ifdef DEBUG_OUTPUT_TO_SCREEN
617     printf("Files open, lets log\n");
618     printf("FILE* is %p\n", (*logs)[1].log_file);
619     printf("%s: %s\n", log_details_buffer, log_buffer);
620 #endif
621
622     fprintf((*logs)[1].log_file, "%s: %s\n", log_details_buffer, log_buffer);
623
624 #ifndef KEEP_LOGFILES_OPEN
625     if ((*logs)[1].log_file != stdout)
626     {
627 #ifdef DEBUG_OUTPUT_TO_SCREEN
628       printf("Closing %s\n", (*logs)[1].log_filename);
629 #endif
630       fclose((*logs)[1].log_file);
631       (*logs)[1].log_file = NULL;
632 #ifdef DEBUG_OUTPUT_TO_SCREEN
633       printf("Closed\n");
634 #endif
635     }
636 #else // KEEP_LOGFILES_OPEN
637     fflush((*logs)[1].log_file);
638 #endif // KEEP_LOGFILES_OPEN
639   }
640 #endif
641
642   global_log_data.temp_src_filename = NULL;
643   global_log_data.temp_src_linenumber = 0;
644 #endif /* DISABLE_LOGGER */
645 }
646
647 #ifndef DISABLE_LOGGER
648 void load_proccessname_from_proc()
649 {
650   pid_t pid = getpid();
651   char buffer[PATH_MAX];
652   char procname[16];
653   FILE * statfile;
654   char *ptr;
655
656   sprintf(buffer, "/proc/%d/stat", pid);
657   statfile = fopen(buffer, "rt");
658   fgets(buffer, PATH_MAX-1, statfile);
659   fclose(statfile);
660
661   ptr = (char *)strrchr(buffer, ')');
662   *ptr = '\0';
663   memset(procname, 0, sizeof procname);
664   sscanf(buffer, "%d (%15c", &pid, procname);   /* comm[16] in kernel */
665
666   set_processname(procname);
667 }
668
669 /* =========================================================================
670     Internal function definitions
671    ========================================================================= */
672
673 static char *get_command_name(char *commandpath)
674 {
675   char *ptr;
676 #ifdef DEBUG_OUTPUT_TO_SCREEN
677   printf("getting command name %s\n",commandpath);
678 #endif
679   ptr = (char *)strrchr(commandpath, '/');
680   if (ptr==NULL)
681     ptr = commandpath;
682   else
683     ptr++;
684
685 #ifdef DEBUG_OUTPUT_TO_SCREEN
686   printf("Concluded %s\n", ptr);
687 #endif
688   return ptr;
689 }
690
691 void  workout_what_to_print(struct what_to_print_array *what_to_print, 
692                             struct tag_log_file_data *log_struct)
693 {
694   /* is this a syslog entry? */
695   if (log_struct->log_filename[0]==0)
696   {
697     what_to_print->print_datetime = false;
698     what_to_print->print_processname = false;
699     what_to_print->print_pid = false;
700   }
701   else
702   {
703     what_to_print->print_datetime = true;
704     what_to_print->print_processname = true;
705  
706     /* pid is dealt with at the syslog level if we're syslogging */
707     what_to_print->print_pid = 
708       (((log_struct->display_options & logoption_pid) == 0)?false:true);
709   }
710
711   what_to_print->print_srcfile = 
712     (((log_struct->display_options & logoption_nfile) == 0)?true:false);
713   what_to_print->print_srcline = 
714     (((log_struct->display_options & logoption_nline) == 0)?true:false);
715   
716   what_to_print->print_errlevel = true;
717   what_to_print->print_errtype = true;
718 }
719
720 void generate_message_details(char *message_details_buffer, 
721                               int message_details_buffer_length,
722                               struct tag_log_file_data *log_struct,
723                               enum loglevels loglevel, enum logtypes logtype)
724 {
725   char datebuffer[32];
726   char processinfo[64];
727
728   char *ptr = message_details_buffer;
729   int   templen;
730   int   len = message_details_buffer_length;
731
732   char log_buffer[MAXLOGSIZE];
733   const char *logtype_string;
734
735   char loglevel_string[12]; /* max int size is 2 billion, or 10 digits */
736
737   struct what_to_print_array what_to_print;
738
739   workout_what_to_print(&what_to_print, log_struct);
740
741 #ifdef DEBUG_OUTPUT_TO_SCREEN
742   printf("Making MessageDetails\n");
743 #endif
744
745   *ptr = 0;
746   /*
747   datebuffer[0] = 0;
748   ptr = datebuffer;
749   */
750
751   if (what_to_print.print_datetime)
752   {
753     time_t thetime;
754     time(&thetime);
755
756   /* some people might prefer localtime() to gmtime() */
757     strftime(ptr, len, "%b %d %H:%M:%S", localtime(&thetime));
758 #ifdef DEBUG_OUTPUT_TO_SCREEN
759     printf("date is %s\n", ptr);
760 #endif
761
762     templen = strlen(ptr);
763     len -= templen;
764     if (what_to_print.print_processname || what_to_print.print_pid)
765       strncat(ptr, " ", len);
766     else
767       strncat(ptr, ":", len);
768
769     templen++;
770     len --;
771     ptr += templen;
772   }
773
774   /*
775   processinfo[0] = 0;
776   ptr = processinfo;
777   */
778
779   if (what_to_print.print_processname)
780   {
781     strncpy(ptr, global_log_data.processname, len);
782
783     templen = strlen(ptr);
784     len -= templen;
785     ptr += templen;
786   }
787
788   if (what_to_print.print_pid)
789   {
790     pid_t pid = getpid();
791
792     sprintf(ptr, "[%d]", pid);
793
794     templen = strlen(ptr);
795     len -= templen;
796     ptr += templen;
797   }
798
799   if (what_to_print.print_srcfile || what_to_print.print_srcline)
800   {
801     char sprintf_buffer[8];
802     char *buff_ptr;
803
804     sprintf_buffer[0] = '[';
805     if (what_to_print.print_srcfile)
806     {
807       strcpy(&sprintf_buffer[1], "%s");
808       buff_ptr = &sprintf_buffer[3];
809     }
810     if (what_to_print.print_srcfile && what_to_print.print_srcline)
811     {
812       strcpy(&sprintf_buffer[3], ":");
813       buff_ptr = &sprintf_buffer[4];
814     }
815     if (what_to_print.print_srcline)
816     {
817       strcpy(buff_ptr, "%d");
818       buff_ptr = &buff_ptr[2];
819     }
820     strcpy(buff_ptr, "]");
821
822     /* 
823        ok sprintf string is ready, now is the 1st parameter src or linenumber
824      */
825     if (what_to_print.print_srcfile)
826     {
827       sprintf(ptr, sprintf_buffer, 
828               global_log_data.temp_src_filename, 
829               global_log_data.temp_src_linenumber);
830     }
831     else
832     {
833       sprintf(ptr, sprintf_buffer, global_log_data.temp_src_linenumber);
834     }
835
836 #ifdef DEBUG_OUTPUT_TO_SCREEN
837     printf("Process info is %s\n", ptr);
838 #endif
839
840     templen = strlen(ptr);
841     len -= templen;
842     ptr += templen;
843
844   }
845
846   if (what_to_print.print_processname || what_to_print.print_pid ||
847       what_to_print.print_srcfile || what_to_print.print_srcline)
848   {
849     strncat(ptr, ": ", len);
850     len -= 2;
851     ptr += 2;
852   }
853
854 /*
855   loglevel_string[0] = 0;
856   ptr = loglevel_string;
857 */
858
859   if (what_to_print.print_errlevel)
860   {
861     if ((loglevel/10) >= (num_loglevel_chars-1))
862     {
863       sprintf(ptr, "%c%d", arr_loglevel_chars[num_loglevel_chars-1],
864                                        loglevel/10);
865     }
866     else
867     {
868       sprintf(ptr, "%c", arr_loglevel_chars[loglevel/10]);
869     }
870
871     templen = strlen(ptr);
872     len -= templen;
873     ptr += templen;    
874   }
875
876   if (what_to_print.print_errtype)
877   {
878     const char *logtype_string;
879
880     /* get string represnetation of the Log Type */
881     if (logtype<num_logtype_strings)
882       logtype_string = arr_logtype_strings[logtype];
883     else
884       logtype_string = "";
885
886     if (what_to_print.print_errlevel)
887     {
888       strncat(ptr, ":", len);
889       ptr++;
890     }
891
892     sprintf(ptr, "%s", logtype_string);
893   }
894
895   message_details_buffer[message_details_buffer_length-1] = 0;
896
897 #ifdef DEBUG_OUTPUT_TO_SCREEN
898     printf("Message Details are %s\n", message_details_buffer);
899 #endif
900 }
901 #endif /* DISABLE_LOGGER */
902
903 int get_syslog_equivalent(enum loglevels loglevel)
904 {
905   switch (loglevel/10)
906   {
907     /* The question is we know how bad it is for us,
908                     but how should that translate in the syslogs?  */
909     case 0: /* severe */
910       return LOG_ERR;
911     case 1: /* error */
912       return LOG_ERR;
913     case 2: /* warning */
914       return LOG_WARNING;
915     case 3: /* note */
916       return LOG_NOTICE;
917     case 4: /* information */
918       return LOG_INFO;
919     default: /* debug */
920       return LOG_DEBUG;
921   }
922 }
923
924 /* void setuplog(char *logsource, char *logtype, char *loglevel, char *filename) */
925 void setuplog(char *logtype, char *loglevel, char *filename)
926 {
927 #ifndef DISABLE_LOGGER 
928   /* -[un]setuplog <logtype> <loglevel> [<filename>]*/
929   /*
930     This should be rewritten so that somehow logsource is assumed and everything
931     can be taken from default if needs be.  
932    */
933   /* const char* sources[] = {"syslog", "filelog"}; */
934   const char *null = "";
935   int sourcenum, typenum, levelnum;
936   log_file_data_pair *logs = log_file_arr[logtype_default];
937
938   /*
939   LOG(log_extradebug, logtype_logger, "Attempting setuplog: %s %s %s %s", 
940       logsource, logtype, loglevel, filename);
941   */
942   LOG(log_info, logtype_logger, "setuplog is parsing logtype:%s, loglevel:%s, filename:%s", 
943       logtype, loglevel, filename);
944
945   if (logtype==NULL)
946   {
947     LOG(log_note, logtype_logger, "no logsource given, default is assumed");
948     typenum=0;
949   }
950   else
951   {
952     for(typenum=0;typenum<num_logtype_strings;typenum++)
953     {
954       if (strcasecmp(logtype, arr_logtype_strings[typenum])==0)
955         break;
956     }
957     if (typenum>=num_logtype_strings)
958     {
959       LOG(log_warning, logtype_logger, "%s is not a valid log type", logtype);
960     }
961   }
962
963   if (loglevel==NULL)
964   {
965     LOG(log_note, logtype_logger, "no loglevel given, severe is assumed");
966     levelnum=0;
967   }
968   else
969   {
970     for(levelnum=0;levelnum<num_loglevel_strings;levelnum++)
971     {
972       if (strcasecmp(loglevel, arr_loglevel_strings[levelnum])==0)
973         break;
974     }
975     if (levelnum>=num_loglevel_strings)
976     {
977       LOG(log_warning, logtype_logger, "%s is not a valid log level", loglevel);
978     }
979   }
980
981   /* sanity check */
982   if ((typenum>=num_logtype_strings) || (levelnum>=num_loglevel_strings))
983   {
984     LOG(log_warning, logtype_logger, "sanity check failed: (%s:%d), (%s:%d)", 
985                     logtype, typenum, loglevel, levelnum);
986     return;
987   }
988
989   /* now match the order of the text string with the actual enum value (10 times) */
990   levelnum*=10;
991   
992   /* is this a syslog setup or a filelog setup */
993   if (filename==NULL) /* must be syslog */
994   {
995     LOG(log_debug6, logtype_logger, "calling syslog_setup(%d, %d, ...)", levelnum, typenum);
996     syslog_setup(levelnum, typenum, 
997                  (*logs)[0].display_options,
998                  global_log_data.facility);
999   }
1000   else /* this must be a filelog */
1001   {
1002     LOG(log_debug6, logtype_logger, "calling log_setup(%s, %d, %d, ...)", filename, levelnum, typenum);
1003     log_setup(filename, levelnum, typenum, 
1004               (*logs)[0].display_options);
1005   };  
1006   return;
1007 #endif /* DISABLE_LOGGER */
1008 }
1009
1010
1011
1012
1013
1014
1015