2 * FCRON - periodic command scheduler
4 * Copyright 2000-2014 Thibault Godouet <fcron@free.fr>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * The GNU General Public License can also be found in the file
21 * `LICENSE' that comes with the fcron source distribution.
25 /* This code was originally inspired by Anacron's sources of
26 Itai Tzur <itzur@actcom.co.il> */
33 #include <sys/types.h>
34 #include <sys/socket.h>
37 char debug_opt = 1; /* set to 1 if we are in debug mode */
39 char debug_opt = 0; /* set to 1 if we are in debug mode */
42 char *logfile_path = NULL;
45 char *make_msg(const char *append, char *fmt, va_list args);
46 void log_syslog_str(int priority, char *msg);
47 void log_file_str(int priority, char *msg);
48 void log_console_str(int priority, char *msg);
49 void log_fd_str(int fd, char *msg);
50 static void print_line_prefix(FILE * logfile, int priority);
51 static void xlog(int priority, int fd, char *fmt, va_list args);
52 static void xlog_e(int priority, int fd, char *fmt, va_list args);
54 static void log_pame(int priority, pam_handle_t * pamh, int pamerrno,
55 char *fmt, va_list args);
58 static char truncated[] = " (truncated)";
59 static int log_open = 0;
60 static FILE *logfile = NULL;
63 /* Initialise logging to either syslog or a file specified in fcron.conf,
64 * or take no action if logging is suppressed.
65 * This function will be called automatically if you attempt to log something,
66 * however you may have to call it explicitely as it needs to run before the
67 * program becomes a daemon so as it can print an error on the console
68 * if it can't open the logs correctly. */
75 /* we MUST set log_open to 1 before doing anything else. That way,
76 * if we call a function that logs something, which calls xopenlog,
77 * then we won't end up in a nasty loop */
80 // are we logging to a file or using syslog or not logging at all?
82 openlog(prog_name, LOG_PID, SYSLOG_FACILITY);
85 if (logfile_path != NULL) {
86 logfile = fopen(logfile_path, "a");
87 if (logfile == NULL) {
88 int saved_errno = errno;
91 /* we have already called openlog() which cannot fail */
92 syslog(COMPLAIN_LEVEL, "Could not fopen log file '%s': %s",
93 logfile_path, strerror(saved_errno));
96 print_line_prefix(stderr, COMPLAIN_LEVEL);
97 fprintf(stderr, "Could not fopen log file '%s': %s\n", logfile_path,
98 strerror(saved_errno));
111 // check whether we need to close syslog, or a file.
112 if (logfile != NULL) {
113 /* we must NOT use xfclose_check() in log.c to avoid infinite loops */
114 if (xfclose(&logfile) != 0) {
115 int saved_errno = errno;
117 syslog(COMPLAIN_LEVEL, "Error while closing log file '%s': %s",
118 logfile_path, strerror(saved_errno));
120 if (foreground == 1) {
121 print_line_prefix(stderr, COMPLAIN_LEVEL);
122 fprintf(stderr, "Error while closing log file '%s': %s\n",
123 logfile_path, strerror(saved_errno));
136 /* Construct the message string from its parts, and append a string to it */
138 make_msg(const char *append, char *fmt, va_list args)
143 if ((msg = calloc(1, MAX_MSG + 1)) == NULL)
145 /* There's some confusion in the documentation about what vsnprintf
146 * returns when the buffer overflows. Hmmm... */
147 len = vsnprintf(msg, MAX_MSG + 1, fmt, args);
148 if (append != NULL) {
149 size_t size_to_cat = ((MAX_MSG - len) > 0) ? (MAX_MSG - len) : 0;
150 strncat(msg, ": ", size_to_cat);
151 strncat(msg, append, size_to_cat);
152 len += 2 + strlen(append);
155 strcpy(msg + (MAX_MSG - 1) - sizeof(truncated), truncated);
161 /* log a simple string to syslog if needed */
163 log_syslog_str(int priority, char *msg)
167 syslog(priority, "%s", msg);
171 /* log a simple string to a log file if needed */
173 log_file_str(int priority, char *msg)
177 /* we may have failed to open the logfile - check if
178 * it does exist *after* xopenlog() */
179 if (logfile != NULL) {
180 print_line_prefix(logfile, priority);
181 fprintf(logfile, "%s\n", msg);
187 /* log a simple string to console if needed */
189 log_console_str(int priority, char *msg)
191 if (foreground == 1) {
192 print_line_prefix(stderr, priority);
193 fprintf(stderr, "%s\n", msg);
197 /* log a simple string to fd if needed */
199 log_fd_str(int fd, char *msg)
202 send(fd, msg, strlen(msg), 0);
203 send(fd, "\n", strlen("\n"), 0);
207 /* Log a message, described by "fmt" and "args", with the specified
209 /* write it also to fd if positive, and to stderr if foreground==1 */
211 xlog(int priority, int fd, char *fmt, va_list args)
215 if ((msg = make_msg(NULL, fmt, args)) == NULL)
218 log_syslog_str(priority, msg);
219 log_file_str(priority, msg);
220 log_console_str(priority, msg);
226 /* Same as xlog(), but also appends an error description corresponding
229 xlog_e(int priority, int fd, char *fmt, va_list args)
236 if ((msg = make_msg(strerror(saved_errno), fmt, args)) == NULL)
239 log_syslog_str(priority, msg);
240 log_file_str(priority, msg);
241 log_console_str(priority, msg);
247 /* write a message to the file specified by logfile. */
249 print_line_prefix(FILE * logfile, int priority)
251 time_t t = time(NULL);
256 // print the current time as a string.
259 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", ft);
261 // is it an info/warning/error/debug message?
276 type = "UNKNOWN_SEVERITY";
279 // print the log message.
280 fprintf(logfile, "%s %s ", date, type);
285 /* Same as log_syslog(), but also appends an error description corresponding
286 * to the pam_error. */
288 log_pame(int priority, pam_handle_t * pamh, int pamerrno, char *fmt,
293 if ((msg = make_msg(pam_strerror(pamh, pamerrno), fmt, args)) == NULL)
296 log_syslog_str(priority, msg);
297 log_console_str(priority, msg);
306 /* Log an "explain" level message */
308 explain(char *fmt, ...)
313 xlog(EXPLAIN_LEVEL, -1, fmt, args);
317 /* as explain(), but also write message to fd if positive */
319 explain_fd(int fd, char *fmt, ...)
324 xlog(EXPLAIN_LEVEL, fd, fmt, args);
329 /* Log an "explain" level message, with an error description */
331 explain_e(char *fmt, ...)
336 xlog_e(EXPLAIN_LEVEL, -1, fmt, args);
341 /* Log a "warning" level message */
348 xlog(WARNING_LEVEL, -1, fmt, args);
352 /* as warn(), but also write message to fd if positive */
354 warn_fd(int fd, char *fmt, ...)
359 xlog(WARNING_LEVEL, fd, fmt, args);
364 /* Log a "warning" level message, with an error description */
366 warn_e(char *fmt, ...)
371 xlog_e(WARNING_LEVEL, -1, fmt, args);
376 /* Log a "complain" level message */
378 error(char *fmt, ...)
383 xlog(COMPLAIN_LEVEL, -1, fmt, args);
387 /* as error(), but also write message to fd if positive */
389 error_fd(int fd, char *fmt, ...)
394 xlog(COMPLAIN_LEVEL, fd, fmt, args);
399 /* Log a "complain" level message, with an error description */
401 error_e(char *fmt, ...)
406 xlog_e(COMPLAIN_LEVEL, -1, fmt, args);
412 /* Log a "complain" level message, with a PAM error description */
414 error_pame(pam_handle_t * pamh, int pamerrno, char *fmt, ...)
418 xcloselog(); /* PAM is likely to have used openlog() */
421 log_pame(COMPLAIN_LEVEL, pamh, pamerrno, fmt, args);
426 /* Log a "complain" level message, and exit */
433 xlog(COMPLAIN_LEVEL, -1, fmt, args);
435 if (getpid() == daemon_pid) {
439 error("fcron child aborted: this does not affect the main fcron daemon,"
440 " but this may prevent a job from being run or an email from being sent.");
448 /* Log a "complain" level message, with an error description, and exit */
450 die_e(char *fmt, ...)
458 xlog_e(COMPLAIN_LEVEL, -1, fmt, args);
460 if (getpid() == daemon_pid) {
464 error("fcron child aborted: this does not affect the main fcron daemon,"
465 " but this may prevent a job from being run or an email from being sent.");
474 /* Log a "complain" level message, with a PAM error description, and exit */
476 die_pame(pam_handle_t * pamh, int pamerrno, char *fmt, ...)
480 xcloselog(); /* PAM is likely to have used openlog() */
483 log_pame(COMPLAIN_LEVEL, pamh, pamerrno, fmt, args);
485 pam_end(pamh, pamerrno);
486 if (getpid() == daemon_pid)
494 /* Log a "debug" level message */
496 Debug(char *fmt, ...)
501 xlog(DEBUG_LEVEL, -1, fmt, args);
505 /* write message to fd, and to syslog in "debug" level message if debug_opt */
507 send_msg_fd_debug(int fd, char *fmt, ...)
515 if ((msg = make_msg(NULL, fmt, args)) == NULL)
519 log_syslog_str(DEBUG_LEVEL, msg);
528 /* write message to fd */
530 send_msg_fd(int fd, char *fmt, ...)
538 if ((msg = make_msg(NULL, fmt, args)) == NULL)