* (version 2.3.2)
* Vladimir Oleynik <dzo@simtreas.ru> (C) 2002
*
- * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
*/
+//usage:#define crond_trivial_usage
+//usage: "-fbS -l N " IF_FEATURE_CROND_D("-d N ") "-L LOGFILE -c DIR"
+//usage:#define crond_full_usage "\n\n"
+//usage: " -f Foreground"
+//usage: "\n -b Background (default)"
+//usage: "\n -S Log to syslog (default)"
+//usage: "\n -l Set log level. 0 is the most verbose, default 8"
+//usage: IF_FEATURE_CROND_D(
+//usage: "\n -d Set log level, log to stderr"
+//usage: )
+//usage: "\n -L Log to file"
+//usage: "\n -c Working dir"
+
#include "libbb.h"
#include <syslog.h>
# define SENDMAIL "sendmail"
#endif
#ifndef SENDMAIL_ARGS
-# define SENDMAIL_ARGS "-ti", NULL
+# define SENDMAIL_ARGS "-ti"
#endif
#ifndef CRONUPDATE
# define CRONUPDATE "cron.update"
#endif
#ifndef MAXLINES
-# define MAXLINES 256 /* max lines in non-root crontabs */
+# define MAXLINES 256 /* max lines in non-root crontabs */
#endif
char *cl_cmd; /* shell command */
pid_t cl_pid; /* >0:running, <0:needs to be started in this minute, 0:dormant */
#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
- int cl_empty_mail_size; /* size of mail header only */
+ int cl_empty_mail_size; /* size of mail header only, 0 if no mailfile */
char *cl_mailto; /* whom to mail results, may be NULL */
- smallint cl_mail_result; /* mail file is created, need to send it on completion */
#endif
/* ordered by size, not in natural order. makes code smaller: */
char cl_Dow[7]; /* 0-6, beginning sunday */
/* Syslog mode: all to syslog (logmode = LOGMODE_SYSLOG), */
if (!DebugOpt && G.log_filename) {
/* Otherwise (log to file): we reopen log file at every write: */
- int logfd = open3_or_warn(G.log_filename, O_WRONLY | O_CREAT | O_APPEND, 0666);
+ int logfd = open_or_warn(G.log_filename, O_WRONLY | O_CREAT | O_APPEND);
if (logfd >= 0)
xmove_fd(logfd, STDERR_FILENO);
}
/* Handle numeric digit or symbol or '*' */
if (*ptr == '*') {
- n1 = 0; /* everything will be filled */
+ n1 = 0; /* everything will be filled */
n2 = modvalue - 1;
skip = 1;
++ptr;
goto err;
}
} while (n1 != n2);
-
}
if (*ptr != ',') {
break;
//if crontab was reloaded: crond thinks that "new" job is different from "old"
//even if they are in fact completely the same. Example
//Crontab was:
-// 0-59 * * * job1
-// 0-59 * * * long_running_job2
+// 0-59 * * * * job1
+// 0-59 * * * * long_running_job2
//User edits crontab to:
-// 0-59 * * * job1_updated
-// 0-59 * * * long_running_job2
+// 0-59 * * * * job1_updated
+// 0-59 * * * * long_running_job2
//Bug: crond can now start another long_running_job2 even if old one
//is still running.
+//OTOH most other versions of cron do not wait for job termination anyway,
+//they end up with multiple copies of jobs if they don't terminate soon enough.
static void delete_cronfile(const char *userName)
{
CronFile **pfile = &G.cron_files;
// TODO: sendmail should be _run-time_ option, not compile-time!
#if ENABLE_FEATURE_CROND_CALL_SENDMAIL
-//TODO: return pid (and stop passing line);
-// stop passing mail_filename here but process it in caller
-static void
-fork_job(const char *user, CronLine *line, int mailFd,
- const char *prog, const char *cmd, const char *arg,
- const char *mail_filename)
-{
+static pid_t
+fork_job(const char *user, int mailFd,
+ const char *prog,
+ const char *shell_cmd /* if NULL, we run sendmail */
+) {
struct passwd *pas;
pid_t pid;
crondlog(LVL5 "child running %s", prog);
}
if (mailFd >= 0) {
- xmove_fd(mailFd, mail_filename ? 1 : 0);
+ xmove_fd(mailFd, shell_cmd ? 1 : 0);
dup2(1, 2);
}
/* crond 3.0pl1-100 puts tasks in separate process groups */
bb_setpgrp();
- execlp(prog, prog, cmd, arg, (char *) NULL);
- crondlog(ERR20 "can't exec, user %s cmd %s %s %s", user, prog, cmd, arg);
- if (mail_filename) {
- fdprintf(1, "Exec failed: %s -c %s\n", prog, arg);
+ execlp(prog, prog, (shell_cmd ? "-c" : SENDMAIL_ARGS), shell_cmd, (char *) NULL);
+ crondlog(ERR20 "can't execute '%s' for user %s", prog, user);
+ if (shell_cmd) {
+ fdprintf(1, "Exec failed: %s -c %s\n", prog, shell_cmd);
}
_exit(EXIT_SUCCESS);
}
- line->cl_pid = pid;
if (pid < 0) {
/* FORK FAILED */
crondlog(ERR20 "can't vfork");
err:
- line->cl_pid = 0;
- if (mail_filename) {
- unlink(mail_filename);
- }
- } else {
- /* PARENT, FORK SUCCESS */
- if (mail_filename) {
- /* rename mail-file based on pid of process */
- char *mailFile2 = xasprintf("%s/cron.%s.%d", TMPDIR, user, (int)pid);
- rename(mail_filename, mailFile2); // TODO: xrename?
- free(mailFile2);
- }
- }
+ pid = 0;
+ } /* else: PARENT, FORK SUCCESS */
/*
* Close the mail file descriptor.. we can't just leave it open in
if (mailFd >= 0) {
close(mailFd);
}
+ return pid;
}
static void start_one_job(const char *user, CronLine *line)
int mailFd = -1;
line->cl_pid = 0;
- line->cl_mail_result = 0;
+ line->cl_empty_mail_size = 0;
if (line->cl_mailto) {
/* Open mail file (owner is root so nobody can screw with it) */
mailFd = open(mailFile, O_CREAT | O_TRUNC | O_WRONLY | O_EXCL | O_APPEND, 0600);
if (mailFd >= 0) {
- line->cl_mail_result = 1;
fdprintf(mailFd, "To: %s\nSubject: cron: %s\n\n", line->cl_mailto,
line->cl_cmd);
line->cl_empty_mail_size = lseek(mailFd, 0, SEEK_CUR);
}
}
- fork_job(user, line, mailFd, DEFAULT_SHELL, "-c", line->cl_cmd, mailFile);
+ line->cl_pid = fork_job(user, mailFd, DEFAULT_SHELL, line->cl_cmd);
+ if (mailFd >= 0) {
+ if (line->cl_pid <= 0) {
+ unlink(mailFile);
+ } else {
+ /* rename mail-file based on pid of process */
+ char *mailFile2 = xasprintf("%s/cron.%s.%d", TMPDIR, user, (int)line->cl_pid);
+ rename(mailFile, mailFile2); // TODO: xrename?
+ free(mailFile2);
+ }
+ }
}
/*
/* No job */
return;
}
- if (line->cl_mail_result == 0) {
+ if (line->cl_empty_mail_size <= 0) {
/* End of job and no mail file, or end of sendmail job */
return;
}
- line->cl_mail_result = 0;
/*
* End of primary job - check for mail file.
close(mailFd);
return;
}
- /* if (line->cl_mailto) - always true if cl_mail_result was true */
- fork_job(user, line, mailFd, SENDMAIL, SENDMAIL_ARGS, NULL);
+ line->cl_empty_mail_size = 0;
+ /* if (line->cl_mailto) - always true if cl_empty_mail_size was nonzero */
+ line->cl_pid = fork_job(user, mailFd, SENDMAIL, NULL);
}
#else /* !ENABLE_FEATURE_CROND_CALL_SENDMAIL */
/* "-b after -f is ignored", and so on for every pair a-b */
opt_complementary = "f-b:b-f:S-L:L-S" IF_FEATURE_CROND_D(":d-l")
- ":l+:d+"; /* -l and -d have numeric param */
+ /* -l and -d have numeric param */
+ ":l+" IF_FEATURE_CROND_D(":d+");
opts = getopt32(argv, "l:L:fbSc:" IF_FEATURE_CROND_D("d:"),
&G.log_level, &G.log_filename, &G.crontab_dir_name
IF_FEATURE_CROND_D(,&G.log_level));
xsetenv("SHELL", DEFAULT_SHELL); /* once, for all future children */
crondlog(LVL8 "crond (busybox "BB_VER") started, log level %d", G.log_level);
rescan_crontab_dir();
- write_pidfile("/var/run/crond.pid");
+ write_pidfile(CONFIG_PID_FILE_PATH "/crond.pid");
/* Main loop */
t2 = time(NULL);