From 10985f36115d85667e032809617a63a167fee4ee Mon Sep 17 00:00:00 2001 From: Thibault Godouet Date: Tue, 1 Jan 2013 17:33:53 +0000 Subject: [PATCH] tweaked fcron logging to file - only enabled for fcron via a command line option (rather than fcron.conf) I doubt people need this feature for command line tools, and we would need to manage the log file perms more closely to allow all tools to write to it - reworked log.c/log.h: more sensible function names, better error checks - changed the line format when logging to files/console - added documentation on logging to file --- convert-fcrontab.c | 1 - doc/en/fcron.8.sgml | 11 +++ exe_list_test.c | 1 - fcron.c | 14 +++- fcron.h | 1 - fcronconf.c | 2 - fcronconf.h | 1 - fcrondyn.c | 1 - fcrondyn.h | 1 - fcronsighup.c | 1 - fcrontab.c | 1 - fcrontab.h | 1 - log.c | 171 +++++++++++++++++++++++++++----------------- log.h | 3 + 14 files changed, 132 insertions(+), 78 deletions(-) diff --git a/convert-fcrontab.c b/convert-fcrontab.c index c9414ea..f8acddf 100644 --- a/convert-fcrontab.c +++ b/convert-fcrontab.c @@ -41,7 +41,6 @@ char foreground = 1; pid_t daemon_pid = 0; uid_t rootuid = 0; gid_t rootgid = 0; -char dosyslog = 1; void info(void) diff --git a/doc/en/fcron.8.sgml b/doc/en/fcron.8.sgml index deb181e..b57d364 100644 --- a/doc/en/fcron.8.sgml +++ b/doc/en/fcron.8.sgml @@ -39,6 +39,7 @@ A copy of the license is included in gfdl.sgml. -f -o -y + -p file -l time @@ -168,6 +169,16 @@ May be especially useful when used with options and in foreground. + + file + +file + + If set, log to the file given as argument. &fcron; will + log to both that file and syslog in parallel unless + is also set. + + time diff --git a/exe_list_test.c b/exe_list_test.c index a1210f0..9fce062 100644 --- a/exe_list_test.c +++ b/exe_list_test.c @@ -5,7 +5,6 @@ /* required by log.c */ char debug_opt = 1; char *prog_name = NULL; -char dosyslog = 1; char foreground = 1; pid_t daemon_pid = 0; uid_t rootuid = 0; diff --git a/fcron.c b/fcron.c index 62edf3d..1fbb84c 100644 --- a/fcron.c +++ b/fcron.c @@ -61,7 +61,6 @@ time_t first_sleep = FIRST_SLEEP; time_t save_time = SAVE; char once = 0; /* set to 1 if fcron shall return immediately after running * all jobs that are due at the time when fcron is started */ -char dosyslog = 1; /* set to 1 when we log messages to syslog, else 0 */ /* Get the default locale character set for the mail * "Content-Type: ...; charset=" header */ @@ -149,6 +148,7 @@ usage(void) " -f --foreground Stay in foreground.\n" " -b --background Go to background.\n" " -y --nosyslog Don't log to syslog at all.\n" + " -p --logfilepath If set, log to the file given as argument.\n" " -o --once Execute all jobs that need to be run, wait for " "them,\n then return. Sets firstsleep to 0.\n" " Especially useful with -f and -y.\n" @@ -312,6 +312,7 @@ parseopt(int argc, char *argv[]) {"foreground", 0, NULL, 'f'}, {"background", 0, NULL, 'b'}, {"nosyslog", 0, NULL, 'y'}, + {"logfilepath", 1, NULL, 'p'}, {"help", 0, NULL, 'h'}, {"version", 0, NULL, 'V'}, {"once", 0, NULL, 'o'}, @@ -332,9 +333,9 @@ parseopt(int argc, char *argv[]) while(1) { #ifdef HAVE_GETOPT_LONG - c = getopt_long(argc, argv, "dfbyhVos:l:m:c:n:q:", opt, NULL); + c = getopt_long(argc, argv, "dfbyp:hVos:l:m:c:n:q:", opt, NULL); #else - c = getopt(argc, argv, "dfbyhVos:l:m:c:n:q:"); + c = getopt(argc, argv, "dfbyp:hVos:l:m:c:n:q:"); #endif /* HAVE_GETOPT_LONG */ if ( c == EOF ) break; switch ( (char)c ) { @@ -356,6 +357,10 @@ parseopt(int argc, char *argv[]) case 'y': dosyslog = 0; break; + + case 'p': + logfile_path = strdup2(optarg); + break; case 'o': once = 1; first_sleep = 0; break; @@ -539,6 +544,9 @@ main(int argc, char **argv) /* read fcron.conf and update global parameters */ read_conf(); + /* initialize the logs before we become a daemon */ + xopenlog(); + /* change directory */ if (chdir(fcrontabs) != 0) diff --git a/fcron.h b/fcron.h index e78fb94..846d3e4 100644 --- a/fcron.h +++ b/fcron.h @@ -64,7 +64,6 @@ /* global variables */ extern time_t now; extern char foreground; -extern char dosyslog; extern char default_mail_charset[TERM_LEN]; extern time_t first_sleep; extern char *cdir; diff --git a/fcronconf.c b/fcronconf.c index 1bf8c54..cbfeb19 100644 --- a/fcronconf.c +++ b/fcronconf.c @@ -40,7 +40,6 @@ char *pidfile = NULL; char *fifofile = NULL; char *fcronallow = NULL; char *fcrondeny = NULL; -char *fcronlogfile = NULL; char *shell = NULL; char *sendmail = NULL; char *editor = NULL; @@ -161,7 +160,6 @@ read_conf(void) else if ( strncmp(ptr1, "fifofile", namesize) == 0 ) { Set(fifofile , ptr2); } else if ( strncmp(ptr1, "fcronallow", namesize) == 0 ) { Set(fcronallow , ptr2); } else if ( strncmp(ptr1, "fcrondeny", namesize) == 0 ) { Set(fcrondeny , ptr2); } - else if ( strncmp(ptr1, "fcronlog", namesize) == 0 ) { Set(fcronlogfile, ptr2); } else if ( strncmp(ptr1, "shell", namesize) == 0 ) { Set(shell , ptr2); } else if ( strncmp(ptr1, "sendmail", namesize) == 0 ) { Set(sendmail , ptr2); } else if ( strncmp(ptr1, "editor", namesize) == 0 ) { Set(editor , ptr2); } diff --git a/fcronconf.h b/fcronconf.h index fc06fe4..d211419 100644 --- a/fcronconf.h +++ b/fcronconf.h @@ -33,7 +33,6 @@ extern char *fcronconf; extern char *fcronallow; extern char *fcrondeny; extern char *fcrontabs; -extern char *fcronlogfile; extern char *pidfile; extern char *fifofile; extern char *editor; diff --git a/fcrondyn.c b/fcrondyn.c index 84c3f33..4d08f58 100644 --- a/fcrondyn.c +++ b/fcrondyn.c @@ -57,7 +57,6 @@ char *cmd_str = NULL; /* needed by log part : */ char *prog_name = NULL; char foreground = 1; -char dosyslog = 1; pid_t daemon_pid = 0; /* uid/gid of user/group root diff --git a/fcrondyn.h b/fcrondyn.h index ca63136..d0bdf72 100644 --- a/fcrondyn.h +++ b/fcrondyn.h @@ -30,7 +30,6 @@ #include "fcronconf.h" /* global variables */ -extern char dosyslog; extern pid_t daemon_pid; extern uid_t rootuid; extern gid_t rootgid; diff --git a/fcronsighup.c b/fcronsighup.c index 7c6f603..aa4c80d 100644 --- a/fcronsighup.c +++ b/fcronsighup.c @@ -40,7 +40,6 @@ gid_t rootgid = 0; /* needed by log part : */ char *prog_name = NULL; char foreground = 1; -char dosyslog = 1; pid_t daemon_pid = 0; diff --git a/fcrontab.c b/fcrontab.c index bf84e1e..63e681a 100644 --- a/fcrontab.c +++ b/fcrontab.c @@ -85,7 +85,6 @@ char file[PATH_LEN]; /* needed by log part : */ char *prog_name = NULL; char foreground = 1; -char dosyslog = 1; pid_t daemon_pid = 0; #ifdef HAVE_LIBPAM diff --git a/fcrontab.h b/fcrontab.h index 08a9cdb..37ae617 100644 --- a/fcrontab.h +++ b/fcrontab.h @@ -31,7 +31,6 @@ /* global variables */ extern pid_t daemon_pid; -extern char dosyslog; extern struct cf_t *file_base; extern char *user; extern char *runas; diff --git a/log.c b/log.c index 69ee691..06e3c72 100644 --- a/log.c +++ b/log.c @@ -22,7 +22,7 @@ */ -/* This code is inspired by Anacron's sources of +/* This code was originally inspired by Anacron's sources of Itai Tzur */ @@ -38,16 +38,18 @@ char debug_opt = 1; /* set to 1 if we are in debug mode */ #else char debug_opt = 0; /* set to 1 if we are in debug mode */ #endif +int dosyslog = 1; +char *logfile_path = NULL; -static void xopenlog(void); char* make_msg(const char *append, char *fmt, va_list args); void log_syslog_str(int priority, char *msg); -void log_console_str(char *msg); +void log_file_str(FILE *logfile, int priority, char *msg); +void log_console_str(int priority, char *msg); void log_fd_str(int fd, char *msg); -static void log_syslog(int priority, int fd, char *fmt, va_list args); -static void log_e(int priority, char *fmt, va_list args); -static void fcronlog(int priority, char *msg); +static void print_line_prefix(FILE *logfile, int priority); +static void xlog(int priority, int fd, char *fmt, va_list args); +static void xlog_e(int priority, int fd, char *fmt, va_list args); #ifdef HAVE_LIBPAM static void log_pame(int priority, pam_handle_t *pamh, int pamerrno, char *fmt, va_list args); @@ -55,26 +57,46 @@ static void log_pame(int priority, pam_handle_t *pamh, int pamerrno, static char truncated[] = " (truncated)"; static int log_open = 0; -static FILE *logfd = NULL; +static FILE *logfile = NULL; /* Initialise logging to either syslog or a file specified in fcron.conf, * or take no action if logging is suppressed. + * This function will be called automatically if you attempt to log something, + * however you may have to call it explicitely as it needs to run before the + * program becomes a daemon so as it can print any errors on the console. */ -static void +void xopenlog(void) { if (log_open) return; - // are we using syslog? - if (dosyslog && (fcronlogfile == NULL)) { - openlog(prog_name, LOG_PID, SYSLOG_FACILITY); - } else if (fcronlogfile != NULL) { - logfd = fopen(fcronlogfile, "a+"); + /* we MUST set log_open to 1 before doing anything else. That way, + * if we call a function that logs something, which calls xopenlog, + * then we won't end up in a nasty loop */ + log_open = 1; + + // are we logging to a file or using syslog or not logging at all? + if (dosyslog) { + openlog(prog_name, LOG_PID, SYSLOG_FACILITY); + } + + if (logfile_path != NULL) { + logfile = fopen(logfile_path, "a"); + if (logfile == NULL) { + int saved_errno = errno; + + if (dosyslog) { + /* we have already called openlog() which cannot fail */ + syslog(COMPLAIN_LEVEL, "Could not fopen log file '%s': %s", logfile_path, strerror(saved_errno)); + } + + print_line_prefix(stderr, COMPLAIN_LEVEL); + fprintf(stderr, "Could not fopen log file '%s': %s\n", logfile_path, strerror(saved_errno)); + } } - log_open = 1; } @@ -85,10 +107,21 @@ xcloselog() return; // check whether we need to close syslog, or a file. - if (dosyslog && (fcronlogfile == NULL)) { + if (logfile != NULL) { + if (fclose(logfile)!= 0) { + int saved_errno = errno; + + syslog(COMPLAIN_LEVEL, "Error while closing log file '%s': %s", logfile_path, strerror(saved_errno)); + + if (foreground == 1) { + print_line_prefix(stderr, COMPLAIN_LEVEL); + fprintf(stderr, "Error while closing log file '%s': %s\n", logfile_path, strerror(saved_errno)); + } + } + } + + if (dosyslog) { closelog(); - } else if (fcronlogfile != NULL) { - fclose(logfd); } log_open = 0; @@ -120,34 +153,38 @@ make_msg(const char *append, char *fmt, va_list args) } -/* log a simple string to syslog/log file if needed */ +/* log a simple string to syslog if needed */ void log_syslog_str(int priority, char *msg) { xopenlog(); - if (dosyslog && (logfd == NULL)) { + if (dosyslog) { syslog(priority, "%s", msg); - } else if (logfd != NULL) { - fcronlog(priority, msg); + } +} + +/* log a simple string to a log file if needed */ +void +log_file_str(FILE *logfile, int priority, char *msg) +{ + xopenlog(); + + if (logfile != NULL) { + print_line_prefix(logfile, priority); + fprintf(logfile, "%s\n", msg); + fflush(logfile); } } /* log a simple string to console if needed */ void -log_console_str(char *msg) +log_console_str(int priority, char *msg) { if (foreground == 1) { - time_t t = time(NULL); - struct tm *ft; - char date[30]; - - ft = localtime(&t); - date[0] = '\0'; - strftime(date, sizeof(date), "%H:%M:%S", ft); - fprintf(stderr, "%s %s\n", date, msg); - + print_line_prefix(stderr, priority); + fprintf(stderr, "%s\n", msg); } } @@ -165,7 +202,7 @@ log_fd_str(int fd, char *msg) * "priority". */ /* write it also to fd if positive, and to stderr if foreground==1 */ static void -log_syslog(int priority, int fd, char *fmt, va_list args) +xlog(int priority, int fd, char *fmt, va_list args) { char *msg; @@ -173,16 +210,17 @@ log_syslog(int priority, int fd, char *fmt, va_list args) return; log_syslog_str(priority, msg); - log_console_str(msg); + log_file_str(logfile, priority, msg); + log_console_str(priority, msg); log_fd_str(fd, msg); Free_safe(msg); } -/* Same as log_syslog(), but also appends an error description corresponding +/* Same as xlog(), but also appends an error description corresponding * to "errno". */ static void -log_e(int priority, char *fmt, va_list args) +xlog_e(int priority, int fd, char *fmt, va_list args) { int saved_errno; char *msg; @@ -193,14 +231,16 @@ log_e(int priority, char *fmt, va_list args) return ; log_syslog_str(priority, msg); - log_console_str(msg); + log_file_str(logfile, priority, msg); + log_console_str(priority, msg); + log_fd_str(fd, msg); Free_safe(msg); } -/* write a message to the file specified by logfd. */ +/* write a message to the file specified by logfile. */ static void -fcronlog(int priority, char *msg) +print_line_prefix(FILE *logfile, int priority) { time_t t = time(NULL); struct tm *ft; @@ -210,25 +250,28 @@ fcronlog(int priority, char *msg) // print the current time as a string. ft = localtime(&t); date[0] = '\0'; - strftime(date, sizeof(date), "%H:%M:%S", ft); + strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", ft); // is it an info/warning/error/debug message? switch(priority) { - case EXPLAIN_LEVEL: - type = "Information"; - break; - case WARNING_LEVEL: - type = "Warning"; - break; - case COMPLAIN_LEVEL: - type = "Error"; - break; - case DEBUG_LEVEL: - type = "Debug"; + case EXPLAIN_LEVEL: + type = " INFO"; + break; + case WARNING_LEVEL: + type = " WARN"; + break; + case COMPLAIN_LEVEL: + type = "ERROR"; + break; + case DEBUG_LEVEL: + type = "DEBUG"; + break; + default: + type = "UNKNOWN_SEVERITY"; } // print the log message. - fprintf(logfd, "%s [ %s ]:\n%s\n\n", date, type, msg); + fprintf(logfile, "%s %s ", date, type); } @@ -244,7 +287,7 @@ log_pame(int priority, pam_handle_t *pamh, int pamerrno, char *fmt, va_list args return ; log_syslog_str(priority, msg); - log_console_str(msg); + log_console_str(priority, msg); xcloselog(); @@ -260,7 +303,7 @@ explain(char *fmt, ...) va_list args; va_start(args, fmt); - log_syslog(EXPLAIN_LEVEL, -1, fmt, args); + xlog(EXPLAIN_LEVEL, -1, fmt, args); va_end(args); } @@ -271,7 +314,7 @@ explain_fd(int fd, char *fmt, ...) va_list args; va_start(args, fmt); - log_syslog(EXPLAIN_LEVEL, fd, fmt, args); + xlog(EXPLAIN_LEVEL, fd, fmt, args); va_end(args); } @@ -283,7 +326,7 @@ explain_e(char *fmt, ...) va_list args; va_start(args, fmt); - log_e(EXPLAIN_LEVEL, fmt, args); + xlog_e(EXPLAIN_LEVEL, -1, fmt, args); va_end(args); } @@ -295,7 +338,7 @@ warn(char *fmt, ...) va_list args; va_start(args, fmt); - log_syslog(WARNING_LEVEL, -1, fmt, args); + xlog(WARNING_LEVEL, -1, fmt, args); va_end(args); } @@ -306,7 +349,7 @@ warn_fd(int fd, char *fmt, ...) va_list args; va_start(args, fmt); - log_syslog(WARNING_LEVEL, fd, fmt, args); + xlog(WARNING_LEVEL, fd, fmt, args); va_end(args); } @@ -318,7 +361,7 @@ warn_e(char *fmt, ...) va_list args; va_start(args, fmt); - log_e(WARNING_LEVEL, fmt, args); + xlog_e(WARNING_LEVEL, -1, fmt, args); va_end(args); } @@ -330,7 +373,7 @@ error(char *fmt, ...) va_list args; va_start(args, fmt); - log_syslog(COMPLAIN_LEVEL, -1, fmt, args); + xlog(COMPLAIN_LEVEL, -1, fmt, args); va_end(args); } @@ -341,7 +384,7 @@ error_fd(int fd, char *fmt, ...) va_list args; va_start(args, fmt); - log_syslog(COMPLAIN_LEVEL, fd, fmt, args); + xlog(COMPLAIN_LEVEL, fd, fmt, args); va_end(args); } @@ -353,7 +396,7 @@ error_e(char *fmt, ...) va_list args; va_start(args, fmt); - log_e(COMPLAIN_LEVEL, fmt, args); + xlog_e(COMPLAIN_LEVEL, -1, fmt, args); va_end(args); } @@ -380,7 +423,7 @@ die(char *fmt, ...) va_list args; va_start(args, fmt); - log_syslog(COMPLAIN_LEVEL, -1, fmt, args); + xlog(COMPLAIN_LEVEL, -1, fmt, args); va_end(args); if (getpid() == daemon_pid) { error("Aborted"); @@ -405,7 +448,7 @@ die_e(char *fmt, ...) err_no = errno; va_start(args, fmt); - log_e(COMPLAIN_LEVEL, fmt, args); + xlog_e(COMPLAIN_LEVEL, -1, fmt, args); va_end(args); if (getpid() == daemon_pid) { error("Aborted"); @@ -447,7 +490,7 @@ Debug(char *fmt, ...) va_list args; va_start(args, fmt); - log_syslog(DEBUG_LEVEL, -1, fmt, args); + xlog(DEBUG_LEVEL, -1, fmt, args); va_end(args); } diff --git a/log.h b/log.h index 5bf643a..d18e5c3 100644 --- a/log.h +++ b/log.h @@ -26,8 +26,11 @@ #define __LOG_H__ extern char debug_opt; +extern char *logfile_path; /* path to a file to log to. Set to NULL to disable logging to a file */ +extern int dosyslog; /* set to 1 when we log messages to syslog, else 0 */ /* functions prototypes */ +extern void xopenlog(void); extern void xcloselog(void); extern void explain(char *fmt, ...); extern void explain_fd(int fd, char *fmt, ...); -- 2.40.0