X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=libatalk%2Futil%2Flogger.c;h=0664b09c2e694e278494ee7620e87547ba721eaf;hb=50d754b2f4cca707e1165cc3dbc5deaded1fead5;hp=f8cb503a25b58ce5ac905ae6bc572474a43581ea;hpb=ee147214d3fe2c3fb084dfe25c0fa7e5cf51871e;p=netatalk.git diff --git a/libatalk/util/logger.c b/libatalk/util/logger.c index f8cb503a..0664b09c 100644 --- a/libatalk/util/logger.c +++ b/libatalk/util/logger.c @@ -4,35 +4,13 @@ /* ========================================================================= - logger.c is part of the utils section in the libatalk library, - which is part of the netatalk project. +logger.c was written by Simon Bazley (sibaz@sibaz.com) - logger.c was written by Simon Bazley (sibaz@sibaz.com) +I believe libatalk is released under the L/GPL licence. +Just incase, it is, thats the licence I'm applying to this file. +Netatalk 2001 (c) - I believe libatalk is released under the L/GPL licence. - - Just incase, it is, thats the licence I'm applying to this file. - - Netatalk 2001 (c) - - ========================================================================== - - Logger.c is intended as an alternative to syslog for logging - - --------------------------------------------------------------- - - The initial plan is to create a structure for general information needed - to log to a file. - - Initally I'll hard code the neccesary stuff to start a log, this should - probably be moved elsewhere when some code is written to read the log - file locations from the config files. - - As a more longterm idea, I'll code this so that the data struct can be - duplicated to allow multiple concurrent log files, although this is - probably a recipe for wasted resources. - - ========================================================================= */ +========================================================================= */ #include #include @@ -42,903 +20,583 @@ #include #include #include +#include +#include #include +#include #include +#include +#include #include -#include - -#define COUNT_ARRAY(array) (sizeof((array))/sizeof((array)[0])) -#define NUMOF COUNT_ARRAY -#undef KEEP_LOGFILES_OPEN -#define DO_SYSLOG -#define DO_FILELOG +#include -#undef DEBUG_OUTPUT_TO_SCREEN -#undef CHECK_STAT_ON_NEW_FILES -#undef CHECK_ACCESS_ON_NEW_FILES - -/* ========================================================================= - External function declarations - ========================================================================= */ - -/* setup the internal variables used by the logger (called automatically) */ -void log_init(); - -/* Setup the log filename and the loglevel, and the type of log it is. */ -bool log_setup(char *filename, enum loglevels loglevel, enum logtypes logtype, - int display_options); - -/* Setup the Level and type of log that will be logged to syslog. */ -void syslog_setup(enum loglevels loglevel, enum logtypes logtype, - int display_options, int facility); +#include -/* finish up and close the logs */ -void log_close(); +#define OPEN_LOGS_AS_UID 0 -/* This function sets up the processname */ -void set_processname(char *processname); +#define COUNT_ARRAY(array) (sizeof((array))/sizeof((array)[0])) -/* Log a Message */ -void make_log(enum loglevels loglevel, enum logtypes logtype, - char *message, ...); -#ifndef DISABLE_LOGGER -make_log_func set_log_location(char *srcfilename, int srclinenumber); +#define MAXLOGSIZE 512 + +#define LOGLEVEL_STRING_IDENTIFIERS { \ + "LOG_NOTHING", \ + "LOG_SEVERE", \ + "LOG_ERROR", \ + "LOG_WARN", \ + "LOG_NOTE", \ + "LOG_INFO", \ + "LOG_DEBUG", \ + "LOG_DEBUG6", \ + "LOG_DEBUG7", \ + "LOG_DEBUG8", \ + "LOG_DEBUG9", \ + "LOG_MAXDEBUG"} + +/* these are the string identifiers corresponding to each logtype */ +#define LOGTYPE_STRING_IDENTIFIERS { \ + "Default", \ + "Core", \ + "Logger", \ + "CNID", \ + "AFPDaemon", \ + "ATalkDaemon", \ + "PAPDaemon", \ + "UAMSDaemon", \ + "Console", \ + "end_of_list_marker"} \ /* ========================================================================= Structure definitions ========================================================================= */ -/* A structure containing object level stuff */ -struct tag_log_file_data { - char log_filename[PATH_MAX]; /* Name of file */ - FILE *log_file; /* FILE pointer to file */ - enum loglevels log_level; /* Log Level to put in this file */ - int display_options; -}; - -typedef struct tag_log_file_data log_file_data_pair[2]; - -/* A structure containg class level stuff */ -struct tag_global_log_data { - int struct_size; - - char *temp_src_filename; - int temp_src_linenumber; - char processname[16]; - - int facility; - char *log_file_directory; /* Path of directory containing log files */ - log_file_data_pair **logs; -}; - -struct what_to_print_array { - bool print_datetime; - bool print_processname; - bool print_pid; - bool print_srcfile; - bool print_srcline; - bool print_errlevel; - bool print_errtype; -}; - -/* ========================================================================= - Internal function declarations - ========================================================================= */ - -void generate_message_details(char *message_details_buffer, - int message_details_buffer_length, - struct tag_log_file_data *log_struct, - enum loglevels loglevel, enum logtypes logtype); - -int get_syslog_equivalent(enum loglevels loglevel); - -static char *get_command_name(char *commandpath); +/* Main log config */ +typedef struct { + int inited; /* file log config initialized ? */ + int filelogging; /* Any level set to filelogging ? */ + /* Deactivates syslog logging */ + char processname[16]; + int syslog_opened; /* syslog opened ? */ + int facility; /* syslog facility to use */ + int syslog_display_options; + enum loglevels syslog_level; /* Log Level to send to syslog */ + int console; /* if logging to console from a cli util */ +} log_config_t; + +/* This stores the config and options for one filelog type (e.g. logger, afpd etc.) */ +typedef struct { + int set; /* set individually ? yes: changing default + * doesnt change it. no: it changes it.*/ + char *filename; /* Name of file */ + int fd; /* logfiles fd */ + enum loglevels level; /* Log Level to put in this file */ + int display_options; +} filelog_conf_t; /* ========================================================================= - Instanciated data + Config ========================================================================= */ -/* A populated instance */ +/* Main log config container */ +static log_config_t log_config = { + 0, /* Initialized ? 0 = no */ + 0, /* No filelogging setup yet */ + {0}, /* processname */ + 0, /* syslog opened ? */ + logfacility_daemon, /* syslog facility to use */ + logoption_ndelay|logoption_pid, /* logging options for syslog */ + 0, /* log level for syslog */ + 0 /* not logging to console */ +}; -static log_file_data_pair default_log_file_data_pair = { -{ - log_filename: "\0\0\0\0\0\0\0\0", - log_file: NULL, - log_level: log_debug, - display_options: logoption_pid -}, -{ - log_filename: LOGFILEPATH, - log_file: NULL, - log_level: log_debug, - display_options: logoption_pid -}}; - -static log_file_data_pair *log_file_data_array[logtype_end_of_list_marker] = -{&default_log_file_data_pair}; - -/* The class (populated) */ -static struct tag_global_log_data global_log_data = { - struct_size: sizeof(struct tag_global_log_data), - temp_src_filename: NULL, - temp_src_linenumber: 0, - processname: "", - facility: logfacility_daemon, - log_file_directory: "", - logs: NULL, +/* Default log config: log nothing to files. + 0: not set individually + NULL: Name of file + -1: logfiles fd + 0: Log Level + 0: Display options */ +#define DEFAULT_LOG_CONFIG {0, NULL, -1, 0, 0} + +static filelog_conf_t file_configs[logtype_end_of_list_marker] = { + DEFAULT_LOG_CONFIG, /* logtype_default */ + DEFAULT_LOG_CONFIG, /* logtype_core */ + DEFAULT_LOG_CONFIG, /* logtype_logger */ + DEFAULT_LOG_CONFIG, /* logtype_cnid */ + DEFAULT_LOG_CONFIG, /* logtype_afpd */ + DEFAULT_LOG_CONFIG, /* logtype_atalkd */ + DEFAULT_LOG_CONFIG, /* logtype_papd */ + DEFAULT_LOG_CONFIG, /* logtype_uams */ + DEFAULT_LOG_CONFIG /* logtype_console */ }; -/* macro to get access to the array */ -#define log_file_arr (global_log_data.logs) +/* These are used by the LOG macro to store __FILE__ and __LINE__ */ +static const char *log_src_filename; +static int log_src_linenumber; /* Array to store text to list given a log type */ -static const char * arr_logtype_strings[] = LOGTYPE_STRING_IDENTIFIERS; -static const int num_logtype_strings = COUNT_ARRAY(arr_logtype_strings); +static const char *arr_logtype_strings[] = LOGTYPE_STRING_IDENTIFIERS; +static const unsigned int num_logtype_strings = COUNT_ARRAY(arr_logtype_strings); /* Array for charachters representing log severity in the log file */ -static const char arr_loglevel_chars[] = {'S', 'E', 'W', 'N', 'I', 'D'}; -static const int num_loglevel_chars = COUNT_ARRAY(arr_loglevel_chars); +static const char arr_loglevel_chars[] = {'-','S', 'E', 'W', 'N', 'I', 'D'}; +static const unsigned int num_loglevel_chars = COUNT_ARRAY(arr_loglevel_chars); -static const char * arr_loglevel_strings[] = LOGLEVEL_STRING_IDENTIFIERS; -static const int num_loglevel_strings = COUNT_ARRAY(arr_loglevel_strings); +static const char *arr_loglevel_strings[] = LOGLEVEL_STRING_IDENTIFIERS; +static const unsigned int num_loglevel_strings = COUNT_ARRAY(arr_loglevel_strings); -#else /* #ifndef DISABLE_LOGGER */ - char *disabled_logger_processname=NULL; -#endif /* DISABLE_LOGGER */ /* ========================================================================= - Global function definitions + Internal function definitions ========================================================================= */ -#ifndef DISABLE_LOGGER - -/* remember I'm keeping a copy of the actual char * Filename, so you mustn't - delete it, until you've finished with the log. Also you're responsible - for deleting it when you have finished with it. */ -void log_init() -{ - if (global_log_data.logs==NULL) - { - /* first check default_log_file_data_pair */ - - /* next clear out the log_file_data_array */ - memset(log_file_data_array, 0, sizeof(log_file_data_array)); - /* now set default_log_file_data_pairs */ - log_file_data_array[0] = &default_log_file_data_pair; - - /* now setup the global_log_data struct */ - global_log_data.logs = log_file_data_array; - } -} -#endif /* #ifndef DISABLE_LOGGER */ - -bool log_setup(char *filename, enum loglevels loglevel, enum logtypes logtype, - int display_options) +/* + * If filename == NULL its for syslog logging, otherwise its for file-logging. + * "unsetuplog" calls with loglevel == NULL. + * loglevel == NULL means: + * if logtype == default + * disable logging + * else + * set to default logging + */ + +/* -[un]setuplog []*/ +static void setuplog_internal(const char *loglevel, const char *logtype, const char *filename) { -#ifndef DISABLE_LOGGER - - struct stat statbuf; - int firstattempt; - int retval; - gid_t gid; - uid_t uid; - int access; - char lastchar[2]; + unsigned int typenum, levelnum; - log_file_data_pair *logs; - - log_init(); - - logs = log_file_arr[logtype]; - - if (logs==NULL) - { - logs = (log_file_data_pair *)malloc(sizeof(log_file_data_pair)); - if (logs==NULL) - { - LOG(log_severe, logtype_logger, "can't calloc in log_setup"); + /* Parse logtype */ + for( typenum=0; typenum < num_logtype_strings; typenum++) { + if (strcasecmp(logtype, arr_logtype_strings[typenum]) == 0) + break; } - else - { - /* - memcpy(logs, log_file_arr[logtype_default], sizeof(log_file_data_pair)); - */ - log_file_arr[logtype] = logs; - (*logs)[1].log_file = NULL; + if (typenum >= num_logtype_strings) { + return; } - } - - if ( ((*logs)[1].log_file == stdout) && ((*logs)[1].log_file != NULL) ) - { - fclose((*logs)[1].log_file); - (*logs)[1].log_file = NULL; - } - - if (strlen(global_log_data.log_file_directory)>0) - { - lastchar[0] = global_log_data. - log_file_directory[strlen(global_log_data.log_file_directory)-1]; - - if (lastchar[0] == '/' || lastchar[0] == '\\' || lastchar[0] == ':') - lastchar[0] = 0; - else - /* this should probably be a platform specific path separator */ - lastchar[0] = '/'; - - lastchar[1] = 0; - } - else - lastchar[0] = 0; - -#ifdef DEBUG_OUTPUT_TO_SCREEN - printf("filename is %s stored at location %p\n", (*logs)[1].log_filename, - (*logs)[1].log_filename); -#endif /* DEBUG_OUTPUT_TO_SCREEN */ - if (filename == NULL) - { - strncpy((*logs)[1].log_filename, - (*(log_file_arr[0]))[1].log_filename, PATH_MAX); - } - else - { - sprintf((*logs)[1].log_filename, "%s%s%s", - global_log_data.log_file_directory, - lastchar, filename); - } - (*logs)[1].log_level = loglevel; - (*logs)[1].display_options = display_options; - -#ifdef DEBUG_OUTPUT_TO_SCREEN - printf("filename is %s stored at location %p\n", (*logs)[1].log_filename, - (*logs)[1].log_filename); -#endif /* DEBUG_OUTPUT_TO_SCREEN */ - -#ifdef CHECK_STAT_ON_NEW_FILES - uid = geteuid(); - gid = getegid(); - -#ifdef DEBUG_OUTPUT_TO_SCREEN - printf("about to stat file %s\n", (*logs)[1].log_filename); -#endif - firstattempt = stat((*logs)[1].log_filename, &statbuf); - - if (firstattempt == -1) - { -#ifdef DEBUG_OUTPUT_TO_SCREEN - printf("about to call Log with %d, %d, %s, %s\n", - log_note, logtype_logger, - "can't stat Logfile", - (*logs)[1].log_filename - ); -#endif - /* syslog(LOG_INFO, "stat failed"); */ - LOG(log_warning, logtype_logger, "stat fails on file %s", - (*logs)[1].log_filename); - - if (strlen(global_log_data.log_file_directory)>0) - { - retval = stat(global_log_data.log_file_directory, &statbuf); - if (retval == -1) - { -#ifdef DEBUG_OUTPUT_TO_SCREEN - printf("can't stat dir either so I'm giving up\n"); -#endif - LOG(log_severe, logtype_logger, "can't stat directory %s either", - global_log_data.log_file_directory); - return false; - } + /* Parse loglevel */ + if (loglevel == NULL) { + levelnum = 0; + } else { + for(levelnum=1; levelnum < num_loglevel_strings; levelnum++) { + if (strcasecmp(loglevel, arr_loglevel_strings[levelnum]) == 0) + break; + } + if (levelnum >= num_loglevel_strings) { + return; + } } - } - -#ifdef CHECK_ACCESS_ON_NEW_FILES - access = ((statbuf.st_uid == uid)?(statbuf.st_mode & S_IWUSR):0) + - ((statbuf.st_gid == gid)?(statbuf.st_mode & S_IWGRP):0) + - (statbuf.st_mode & S_IWOTH); - - if (access==0) - { -#ifdef DEBUG_OUTPUT_TO_SCREEN - printf("failing with %d, %d, %s, %s\n", log_note, logtype_logger, - "can't access Logfile %s", (*logs)[1].log_filename); -#endif - - LOG(log_note, logtype_logger, "can't access file %s", - (*logs)[1].log_filename); - return false; - } -#endif /* CHECK_ACCESS_ON_NEW_FILES */ -#endif /* CHECK_STAT_ON_NEW_FILES */ -#ifdef KEEP_LOGFILES_OPEN - if ((*logs)[1].log_file!=NULL) - fclose((*logs)[1].log_file); - - (*logs)[1].log_file = fopen((*logs)[1].log_filename, "at"); - if ((*logs)[1].log_file == NULL) - { - LOG(log_severe, logtype_logger, "can't open Logfile %s", - (*logs)[1].log_filename - ); - return false; - } -#endif - LOG(log_info, logtype_logger, "Log setup complete"); + /* is this a syslog setup or a filelog setup ? */ + if (filename == NULL) { + /* must be syslog */ + syslog_setup(levelnum, 0, + log_config.syslog_display_options, + log_config.facility); + } else { + /* this must be a filelog */ + log_setup(filename, levelnum, typenum); + } -#endif /* DISABLE_LOGGER */ - return true; + return; } - -void syslog_setup(enum loglevels loglevel, enum logtypes logtype, - int display_options, int facility) +static void generate_message_details(char *message_details_buffer, + int message_details_buffer_length, + int display_options, + enum loglevels loglevel, enum logtypes logtype) { -#ifndef DISABLE_LOGGER - log_file_data_pair *logs; + char *ptr = message_details_buffer; + int templen; + int len = message_details_buffer_length; + struct timeval tv; + pid_t pid; - log_init(); + *ptr = 0; + + /* Print time */ + gettimeofday(&tv, NULL); + strftime(ptr, len, "%b %d %H:%M:%S.", localtime(&tv.tv_sec)); + templen = strlen(ptr); + len -= templen; + ptr += templen; - logs = log_file_arr[logtype]; + templen = snprintf(ptr, len, "%06u ", (int)tv.tv_usec); + if (templen == -1 || templen >= len) + return; + + len -= templen; + ptr += templen; - if (logs==NULL) - { - logs = (log_file_data_pair *)malloc(sizeof(log_file_data_pair)); - if (logs==NULL) - { - LOG(log_severe, logtype_logger, "can't calloc in log_setup"); + /* Process name && PID */ + pid = getpid(); + templen = snprintf(ptr, len, "%s[%d]", log_config.processname, pid); + if (templen == -1 || templen >= len) + return; + len -= templen; + ptr += templen; + + /* Source info ? */ + if ( ! (display_options & logoption_nsrcinfo)) { + char *basename = strrchr(log_src_filename, '/'); + if (basename) + templen = snprintf(ptr, len, " {%s:%d}", basename + 1, log_src_linenumber); + else + templen = snprintf(ptr, len, " {%s:%d}", log_src_filename, log_src_linenumber); + if (templen == -1 || templen >= len) + return; + len -= templen; + ptr += templen; } + + /* Errorlevel */ + if (loglevel >= (num_loglevel_chars - 1)) + templen = snprintf(ptr, len, " (D%d:", loglevel - 1); else - { - memcpy(logs, log_file_arr[logtype_default], sizeof(log_file_data_pair)); - log_file_arr[logtype] = logs; + templen = snprintf(ptr, len, " (%c:", arr_loglevel_chars[loglevel]); + + if (templen == -1 || templen >= len) + return; + len -= templen; + ptr += templen; + + /* Errortype */ + if (logtype= len) + return; + len -= templen; + ptr += templen; } - } - - (*logs)[0].log_file = NULL; - (*logs)[0].log_filename[0] = 0; - (*logs)[0].log_level = loglevel; - (*logs)[0].display_options = display_options; - global_log_data.facility = facility; - - openlog(global_log_data.processname, (*logs)[0].display_options, - global_log_data.facility); - - LOG(log_info, logtype_logger, "SysLog setup complete"); -#else /* DISABLE_LOGGER */ -/* behave like a normal openlog call */ - openlog(disabled_logger_processname, display_options, facility); -#endif /* DISABLE_LOGGER */ + + strncat(ptr, "): ", len); + ptr[len -1] = 0; } -void log_close() +static int get_syslog_equivalent(enum loglevels loglevel) { -#ifndef DISABLE_LOGGER - log_file_data_pair *logs; - int n; - - LOG(log_info, logtype_logger, "Closing logs"); - - for(n=(sizeof(log_file_arr)-1);n>0;n--) - { - logs = log_file_arr[n]; -#ifdef KEEP_LOGFILES_OPEN - if ((*logs)[1].log_file!=NULL) - fclose((*logs)[1].log_file); -#endif /* KEEP_LOGFILES_OPEN */ - if (logs!=NULL) + switch (loglevel) { -#ifdef DEBUG_OUTPUT_TO_SCREEN - printf("Freeing log_data %d, stored at %p\n", n, logs); - printf("\t(filename) %s\t(type) %s\n", (*logs)[1].log_filename, - ((n=loglevel) - { - int sysloglevel = get_syslog_equivalent(loglevel); + /* Resetting existing config ? */ + if (file_configs[logtype].set && file_configs[logtype].filename) { + free(file_configs[logtype].filename); + file_configs[logtype].filename = NULL; + close(file_configs[logtype].fd); + file_configs[logtype].fd = -1; + file_configs[logtype].level = 0; + file_configs[logtype].set = 0; + } - generate_message_details(log_details_buffer, sizeof(log_details_buffer), - &(*logs)[0], loglevel, logtype); + /* Check if logging to a console */ + if (logtype == logtype_console) { + log_config.console = 1; + logtype = logtype_default; + } -#ifdef DEBUG_OUTPUT_TO_SCREEN - printf("About to log %s %s\n", log_details_buffer, log_buffer); - printf("about to do syslog\n"); - printf("done onw syslog\n"); -#endif - syslog(sysloglevel, "%s: %s", log_details_buffer, log_buffer); - /* - syslog(sysloglevel, "%s:%s: %s", log_levelString, - log_typeString, LogBuffer); - */ - } -#endif + /* Set new values */ + file_configs[logtype].filename = strdup(filename); + file_configs[logtype].level = loglevel; + + + /* Open log file as OPEN_LOGS_AS_UID*/ + /* Is it /dev/tty ? */ + if (strcmp(file_configs[logtype].filename, "/dev/tty") == 0) { + file_configs[logtype].fd = 1; /* stdout */ + } else { + process_uid = geteuid(); + if (process_uid) { + if (seteuid(OPEN_LOGS_AS_UID) == -1) { + /* XXX failing silently */ + return; + } + } + file_configs[logtype].fd = open( file_configs[logtype].filename, + O_CREAT | O_WRONLY | O_APPEND, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (process_uid) { + if (seteuid(process_uid) == -1) { + LOG(log_error, logtype_logger, "can't seteuid back %s", strerror(errno)); + exit(EXITERR_SYS); + } + } + } -#ifdef DO_FILELOG -#ifdef DEBUG_OUTPUT_TO_SCREEN - printf("about to do the filelog\n"); -#endif - /* check if log_level is high enough */ - if ((*logs)[1].log_level>=loglevel) { - -#ifdef DEBUG_OUTPUT_TO_SCREEN - printf("Open the Log, FILE* is %p\n", (*logs)[1].log_file); -#endif - /* if log isn't open, open it */ - if ((*logs)[1].log_file==NULL) { -#ifdef DEBUG_OUTPUT_TO_SCREEN - printf("Opening the Log, filename is %s\n", (*logs)[1].log_filename); -#endif - (*logs)[1].log_file = fopen((*logs)[1].log_filename, "at"); - if ((*logs)[1].log_file == NULL) - { - (*logs)[1].log_file = stdout; - LOG(log_severe, logtype_logger, "can't open Logfile %s", - (*logs)[1].log_filename - ); + /* Check for error opening/creating logfile */ + if (-1 == file_configs[logtype].fd) { + free(file_configs[logtype].filename); + file_configs[logtype].filename = NULL; + file_configs[logtype].level = -1; + file_configs[logtype].set = 0; return; - } } - generate_message_details(log_details_buffer, sizeof(log_details_buffer), - &(*logs)[1], loglevel, logtype); -#ifdef DEBUG_OUTPUT_TO_SCREEN - printf("Files open, lets log\n"); - printf("FILE* is %p\n", (*logs)[1].log_file); - printf("%s: %s\n", log_details_buffer, log_buffer); -#endif - - fprintf((*logs)[1].log_file, "%s: %s\n", log_details_buffer, log_buffer); - -#ifndef KEEP_LOGFILES_OPEN - if ((*logs)[1].log_file != stdout) - { -#ifdef DEBUG_OUTPUT_TO_SCREEN - printf("Closing %s\n", (*logs)[1].log_filename); -#endif - fclose((*logs)[1].log_file); - (*logs)[1].log_file = NULL; -#ifdef DEBUG_OUTPUT_TO_SCREEN - printf("Closed\n"); -#endif + fcntl(file_configs[logtype].fd, F_SETFD, FD_CLOEXEC); + file_configs[logtype].set = 1; + log_config.filelogging = 1; + log_config.inited = 1; + + /* Here's how we make it possible to LOG to a logtype like "logtype_afpd" */ + /* which then uses the default logtype setup if it isn't setup itself: */ + /* we just copy the loglevel from default to all logtypes that are not setup. */ + /* In "make_log_entry" we then check for the logtypes if they arent setup */ + /* and use default then. We must provide accessible values for all logtypes */ + /* in order to make it easy and fast to check the loglevels in the LOG macro! */ + + if (logtype == logtype_default) { + int typeiter = 0; + while (typeiter != logtype_end_of_list_marker) { + if ( ! (file_configs[typeiter].set)) + file_configs[typeiter].level = loglevel; + typeiter++; + } } -#endif - } -#endif - global_log_data.temp_src_filename = NULL; - global_log_data.temp_src_linenumber = 0; -#endif /* DISABLE_LOGGER */ + LOG(log_debug, logtype_logger, "Setup file logging: type: %s, level: %s, file: %s", + arr_logtype_strings[logtype], arr_loglevel_strings[loglevel], file_configs[logtype].filename); } -#ifndef DISABLE_LOGGER -void load_proccessname_from_proc() +/* logtype is ignored, it's just one for all */ +void syslog_setup(int loglevel, enum logtypes logtype _U_, + int display_options, int facility) { - pid_t pid = getpid(); - char buffer[PATH_MAX]; - char procname[16]; - FILE * statfile; - char *ptr; - - sprintf(buffer, "/proc/%d/stat", pid); - statfile = fopen(buffer, "rt"); - fgets(buffer, PATH_MAX-1, statfile); - fclose(statfile); - - ptr = (char *)strrchr(buffer, ')'); - *ptr = '\0'; - memset(procname, 0, sizeof procname); - sscanf(buffer, "%d (%15c", &pid, procname); /* comm[16] in kernel */ - - set_processname(procname); -} + log_config.syslog_level = loglevel; + log_config.syslog_display_options = display_options; + log_config.facility = facility; -/* ========================================================================= - Internal function definitions - ========================================================================= */ + log_config.inited = 1; -static char *get_command_name(char *commandpath) -{ - char *ptr; -#ifdef DEBUG_OUTPUT_TO_SCREEN - printf("getting command name %s\n",commandpath); -#endif - ptr = (char *)strrchr(commandpath, '/'); - if (ptr==NULL) - ptr = commandpath; - else - ptr++; - -#ifdef DEBUG_OUTPUT_TO_SCREEN - printf("Concluded %s\n", ptr); -#endif - return ptr; + LOG(log_note, logtype_logger, "Set syslog logging to level: %s", + arr_loglevel_strings[loglevel]); } -void workout_what_to_print(struct what_to_print_array *what_to_print, - struct tag_log_file_data *log_struct) +void log_close(void) { - /* is this a syslog entry? */ - if (log_struct->log_filename[0]==0) - { - what_to_print->print_datetime = false; - what_to_print->print_processname = false; - what_to_print->print_pid = false; - } - else - { - what_to_print->print_datetime = true; - what_to_print->print_processname = true; - - /* pid is dealt with at the syslog level if we're syslogging */ - what_to_print->print_pid = - (((log_struct->display_options & logoption_pid) == 0)?false:true); - } - - what_to_print->print_srcfile = - (((log_struct->display_options & logoption_nfile) == 0)?true:false); - what_to_print->print_srcline = - (((log_struct->display_options & logoption_nline) == 0)?true:false); - - what_to_print->print_errlevel = true; - what_to_print->print_errtype = true; } -void generate_message_details(char *message_details_buffer, - int message_details_buffer_length, - struct tag_log_file_data *log_struct, - enum loglevels loglevel, enum logtypes logtype) +/* This function sets up the processname */ +void set_processname(const char *processname) { - char datebuffer[32]; - char processinfo[64]; - - char *ptr = message_details_buffer; - int templen; - int len = message_details_buffer_length; - - char log_buffer[MAXLOGSIZE]; - const char *logtype_string; - - char loglevel_string[12]; /* max int size is 2 billion, or 10 digits */ - - struct what_to_print_array what_to_print; - - workout_what_to_print(&what_to_print, log_struct); - -#ifdef DEBUG_OUTPUT_TO_SCREEN - printf("Making MessageDetails\n"); -#endif - - *ptr = 0; - /* - datebuffer[0] = 0; - ptr = datebuffer; - */ - - if (what_to_print.print_datetime) - { - time_t thetime; - time(&thetime); - - /* some people might prefer localtime() to gmtime() */ - strftime(ptr, len, "%b %d %H:%M:%S", gmtime(&thetime)); -#ifdef DEBUG_OUTPUT_TO_SCREEN - printf("date is %s\n", ptr); -#endif - - templen = strlen(ptr); - len -= templen; - if (what_to_print.print_processname || what_to_print.print_pid) - strncat(ptr, " ", len); - else - strncat(ptr, ":", len); - - templen++; - len --; - ptr += templen; - } - - /* - processinfo[0] = 0; - ptr = processinfo; - */ - - if (what_to_print.print_processname) - { - strncpy(ptr, global_log_data.processname, len); - - templen = strlen(ptr); - len -= templen; - ptr += templen; - } + strncpy(log_config.processname, processname, 15); + log_config.processname[15] = 0; +} - if (what_to_print.print_pid) - { - pid_t pid = getpid(); +/* Called by the LOG macro for syslog messages */ +static void make_syslog_entry(enum loglevels loglevel, enum logtypes logtype _U_, char *message) +{ + if ( !log_config.syslog_opened ) { + openlog(log_config.processname, log_config.syslog_display_options, + log_config.facility); + log_config.syslog_opened = 1; + } - sprintf(ptr, "[%d]", pid); + syslog(get_syslog_equivalent(loglevel), "%s", message); +} - templen = strlen(ptr); - len -= templen; - ptr += templen; - } +/* ------------------------------------------------------------------------- + make_log_entry has 1 main flaws: + The message in its entirity, must fit into the tempbuffer. + So it must be shorter than MAXLOGSIZE + ------------------------------------------------------------------------- */ +void make_log_entry(enum loglevels loglevel, enum logtypes logtype, + const char *file, int line, char *message, ...) +{ + /* fn is not reentrant but is used in signal handler + * with LOGGER it's a little late source name and line number + * are already changed. */ + static int inlog = 0; + int fd, len; + char temp_buffer[MAXLOGSIZE]; + char log_details_buffer[MAXLOGSIZE]; + va_list args; + struct iovec iov[2]; + + if (inlog) + return; - if (what_to_print.print_srcfile || what_to_print.print_srcline) - { - char sprintf_buffer[8]; - char *buff_ptr; + inlog = 1; - sprintf_buffer[0] = '['; - if (what_to_print.print_srcfile) - { - strcpy(&sprintf_buffer[1], "%s"); - buff_ptr = &sprintf_buffer[3]; + if (!log_config.inited) { + log_init(); } - if (what_to_print.print_srcfile && what_to_print.print_srcline) - { - strcpy(&sprintf_buffer[3], ":"); - buff_ptr = &sprintf_buffer[4]; + + if (file_configs[logtype].level >= loglevel) { + log_src_filename = file; + log_src_linenumber = line; } - if (what_to_print.print_srcline) - { - strcpy(buff_ptr, "%d"); - buff_ptr = &buff_ptr[2]; + else if (!log_config.filelogging && log_config.syslog_level >= loglevel) { + /* Initialise the Messages */ + va_start(args, message); + vsnprintf(temp_buffer, MAXLOGSIZE -1, message, args); + va_end(args); + temp_buffer[MAXLOGSIZE -1] = 0; + make_syslog_entry(loglevel, logtype, temp_buffer); + inlog = 0; + return; } - strcpy(buff_ptr, "]"); - - /* - ok sprintf string is ready, now is the 1st parameter src or linenumber - */ - if (what_to_print.print_srcfile) - { - sprintf(ptr, sprintf_buffer, - global_log_data.temp_src_filename, - global_log_data.temp_src_linenumber); - } - else - { - sprintf(ptr, sprintf_buffer, global_log_data.temp_src_linenumber); + else { + inlog = 0; + return; } -#ifdef DEBUG_OUTPUT_TO_SCREEN - printf("Process info is %s\n", ptr); -#endif - - templen = strlen(ptr); - len -= templen; - ptr += templen; - - } + /* Check if requested logtype is setup */ + if (file_configs[logtype].set) + /* Yes */ + fd = file_configs[logtype].fd; + else + /* No: use default */ + fd = file_configs[logtype_default].fd; - if (what_to_print.print_processname || what_to_print.print_pid || - what_to_print.print_srcfile || what_to_print.print_srcline) - { - strncat(ptr, ": ", len); - len -= 2; - ptr += 2; - } + if (fd < 0) { + /* no where to send the output, give up */ + return; + } -/* - loglevel_string[0] = 0; - ptr = loglevel_string; -*/ + /* Initialise the Messages */ + va_start(args, message); + len = vsnprintf(temp_buffer, MAXLOGSIZE -1, message, args); + va_end(args); - if (what_to_print.print_errlevel) - { - if ((loglevel/10) >= (num_loglevel_chars-1)) - { - sprintf(ptr, "%c%d", arr_loglevel_chars[num_loglevel_chars-1], - loglevel/10); + /* Append \n */ + if (len ==-1 || len >= MAXLOGSIZE -1) { + /* vsnprintf hit the buffer size*/ + temp_buffer[MAXLOGSIZE-2] = '\n'; + temp_buffer[MAXLOGSIZE-1] = 0; } - else - { - sprintf(ptr, "%c", arr_loglevel_chars[loglevel/10]); + else { + temp_buffer[len] = '\n'; + temp_buffer[len+1] = 0; } - templen = strlen(ptr); - len -= templen; - ptr += templen; - } - - if (what_to_print.print_errtype) - { - const char *logtype_string; - - /* get string represnetation of the Log Type */ - if (logtype */ - /* - This should be rewritten so that somehow logsource is assumed and everything - can be taken from default if needs be. - */ - const char* sources[] = {"syslog", "filelog"}; - int sourcenum, typenum, levelnum; - log_file_data_pair *logs = log_file_arr[logtype_default]; - - for(sourcenum=0;sourcenum=NUMOF(sources)) - { - LOG(log_warning, logtype_logger, "%s is not a valid log source", logsource); - } - if ((sourcenum>0) && (filename==NULL)) - { - LOG(log_warning, logtype_logger, - "when specifying a filelog, you must specify a valid filename"); - } - - for(typenum=0;typenum=num_logtype_strings) - { - LOG(log_warning, logtype_logger, "%s is not a valid log type", logtype); - } - - for(levelnum=0;levelnum=num_loglevel_strings) - { - LOG(log_warning, logtype_logger, "%s is not a valid log level", loglevel); - } - - /* check validity */ - if ((sourcenum>=NUMOF(sources)) || (typenum>=num_logtype_strings) || - (levelnum>=num_loglevel_strings)) - return; + char *ptr, *ptrbak, *logtype, *loglevel = NULL, *filename = NULL; + ptr = strdup(logstr); + ptrbak = ptr; + + /* logtype */ + logtype = ptr; + + /* get loglevel */ + ptr = strpbrk(ptr, " \t"); + if (ptr) { + *ptr++ = 0; + while (*ptr && isspace(*ptr)) + ptr++; + loglevel = ptr; + + /* get filename */ + ptr = strpbrk(ptr, " \t"); + if (ptr) { + *ptr++ = 0; + while (*ptr && isspace(*ptr)) + ptr++; + } + filename = ptr; + if (filename && *filename == 0) + filename = NULL; + } - switch(sourcenum) - { - case 0: /* syslog */ - syslog_setup(levelnum, typenum, - (*logs)[0].display_options, - global_log_data.facility); - break; - default: /* filelog */ - log_setup(filename, levelnum, typenum, - (*logs)[0].display_options); - }; - return; -} + /* finally call setuplog, filename can be NULL */ + setuplog_internal(loglevel, logtype, filename); + free(ptrbak); +} +void unsetuplog(const char *logstr) +{ + char *str, *logtype, *filename; + str = strdup(logstr); + /* logtype */ + logtype = str; + /* get filename, can be NULL */ + strtok(str, " \t"); + filename = strtok(NULL, " \t"); + /* finally call setuplog, filename can be NULL */ + setuplog_internal(NULL, str, filename); + free(str); +}