crond: reorder functions to follow usual order: "main last"
No binary (build failed)
—
(log yok)
| @@ -17,25 +17,25 @@ | |
| /* glibc frees previous setenv'ed value when we do next setenv() | |
| * of the same variable. uclibc does not do this! */ | |
| #if (defined(__GLIBC__) && !defined(__UCLIBC__)) /* || OTHER_SAFE_LIBC... */ | |
| - | #define SETENV_LEAKS 0 |
| + | # define SETENV_LEAKS 0 |
| #else | |
| - | #define SETENV_LEAKS 1 |
| + | # define SETENV_LEAKS 1 |
| #endif | |
| #define TMPDIR CONFIG_FEATURE_CROND_DIR | |
| #define CRONTABS CONFIG_FEATURE_CROND_DIR "/crontabs" | |
| #ifndef SENDMAIL | |
| - | #define SENDMAIL "sendmail" |
| + | # define SENDMAIL "sendmail" |
| #endif | |
| #ifndef SENDMAIL_ARGS | |
| - | #define SENDMAIL_ARGS "-ti", NULL |
| + | # define SENDMAIL_ARGS "-ti", NULL |
| #endif | |
| #ifndef CRONUPDATE | |
| - | #define CRONUPDATE "cron.update" |
| + | # 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 | |
| @@ -108,20 +108,6 @@ struct globals { | |
| } while (0) | |
| - | static void CheckUpdates(void); |
| - | static void SynchronizeDir(void); |
| - | static int TestJobs(time_t t1, time_t t2); |
| - | static void RunJobs(void); |
| - | static int CheckJobs(void); |
| - | static void RunJob(const char *user, CronLine *line); |
| - | #if ENABLE_FEATURE_CROND_CALL_SENDMAIL |
| - | static void EndJob(const char *user, CronLine *line); |
| - | #else |
| - | #define EndJob(user, line) ((line)->cl_Pid = 0) |
| - | #endif |
| - | static void DeleteFile(const char *userName); |
| - | |
| - | |
| /* 0 is the most verbose, default 8 */ | |
| #define LVL5 "\x05" | |
| #define LVL7 "\x07" | |
| @@ -163,101 +149,6 @@ static void crondlog(const char *ctl, ...) | |
| exit(20); | |
| } | |
| - | int crond_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
| - | int crond_main(int argc UNUSED_PARAM, char **argv) |
| - | { |
| - | time_t t2; |
| - | int rescan; |
| - | int sleep_time; |
| - | unsigned opts; |
| - | |
| - | INIT_G(); |
| - | |
| - | /* "-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 */ |
| - | opts = getopt32(argv, "l:L:fbSc:" IF_FEATURE_CROND_D("d:"), |
| - | &LogLevel, &LogFile, &CDir |
| - | IF_FEATURE_CROND_D(,&LogLevel)); |
| - | /* both -d N and -l N set the same variable: LogLevel */ |
| - | |
| - | if (!(opts & OPT_f)) { |
| - | /* close stdin, stdout, stderr. |
| - | * close unused descriptors - don't need them. */ |
| - | bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv); |
| - | } |
| - | |
| - | if (!(opts & OPT_d) && LogFile == NULL) { |
| - | /* logging to syslog */ |
| - | openlog(applet_name, LOG_CONS | LOG_PID, LOG_CRON); |
| - | logmode = LOGMODE_SYSLOG; |
| - | } |
| - | |
| - | xchdir(CDir); |
| - | //signal(SIGHUP, SIG_IGN); /* ? original crond dies on HUP... */ |
| - | xsetenv("SHELL", DEFAULT_SHELL); /* once, for all future children */ |
| - | crondlog(LVL8 "crond (busybox "BB_VER") started, log level %d", LogLevel); |
| - | SynchronizeDir(); |
| - | write_pidfile("/var/run/crond.pid"); |
| - | |
| - | /* main loop - synchronize to 1 second after the minute, minimum sleep |
| - | * of 1 second. */ |
| - | t2 = time(NULL); |
| - | rescan = 60; |
| - | sleep_time = 60; |
| - | for (;;) { |
| - | time_t t1; |
| - | long dt; |
| - | |
| - | t1 = t2; |
| - | sleep((sleep_time + 1) - (time(NULL) % sleep_time)); |
| - | |
| - | t2 = time(NULL); |
| - | dt = (long)t2 - (long)t1; |
| - | |
| - | /* |
| - | * The file 'cron.update' is checked to determine new cron |
| - | * jobs. The directory is rescanned once an hour to deal |
| - | * with any screwups. |
| - | * |
| - | * Check for time jump. Disparities over an hour either way |
| - | * result in resynchronization. A negative disparity |
| - | * less than an hour causes us to effectively sleep until we |
| - | * match the original time (i.e. no re-execution of jobs that |
| - | * have just been run). A positive disparity less than |
| - | * an hour causes intermediate jobs to be run, but only once |
| - | * in the worst case. |
| - | * |
| - | * When running jobs, the inequality used is greater but not |
| - | * equal to t1, and less then or equal to t2. |
| - | */ |
| - | if (--rescan == 0) { |
| - | rescan = 60; |
| - | SynchronizeDir(); |
| - | } |
| - | CheckUpdates(); |
| - | if (DebugOpt) |
| - | crondlog(LVL5 "wakeup dt=%ld", dt); |
| - | if (dt < -60 * 60 || dt > 60 * 60) { |
| - | crondlog(WARN9 "time disparity of %ld minutes detected", dt / 60); |
| - | /* and we do not run any jobs in this case */ |
| - | } else if (dt > 0) { |
| - | /* Usual case: time advances forwad, as expected */ |
| - | TestJobs(t1, t2); |
| - | RunJobs(); |
| - | sleep(5); |
| - | if (CheckJobs() > 0) { |
| - | sleep_time = 10; |
| - | } else { |
| - | sleep_time = 60; |
| - | } |
| - | } |
| - | /* else: time jumped back, do not run any jobs */ |
| - | } /* for (;;) */ |
| - | |
| - | return 0; /* not reached */ |
| - | } |
| - | |
| #if SETENV_LEAKS | |
| /* We set environment *before* vfork (because we want to use vfork), | |
| * so we cannot use setenv() - repeated calls to setenv() may leak memory! | |
| @@ -452,6 +343,48 @@ static void FixDayDow(CronLine *line) | |
| } | |
| } | |
| + | /* |
| + | * DeleteFile() - delete user database |
| + | * |
| + | * Note: multiple entries for same user may exist if we were unable to |
| + | * completely delete a database due to running processes. |
| + | */ |
| + | static void DeleteFile(const char *userName) |
| + | { |
| + | CronFile **pfile = &FileBase; |
| + | CronFile *file; |
| + | |
| + | while ((file = *pfile) != NULL) { |
| + | if (strcmp(userName, file->cf_User) == 0) { |
| + | CronLine **pline = &file->cf_LineBase; |
| + | CronLine *line; |
| + | |
| + | file->cf_Running = 0; |
| + | file->cf_Deleted = 1; |
| + | |
| + | while ((line = *pline) != NULL) { |
| + | if (line->cl_Pid > 0) { |
| + | file->cf_Running = 1; |
| + | pline = &line->cl_Next; |
| + | } else { |
| + | *pline = line->cl_Next; |
| + | free(line->cl_Shell); |
| + | free(line); |
| + | } |
| + | } |
| + | if (file->cf_Running == 0) { |
| + | *pfile = file->cf_Next; |
| + | free(file->cf_User); |
| + | free(file); |
| + | } else { |
| + | pfile = &file->cf_Next; |
| + | } |
| + | } else { |
| + | pfile = &file->cf_Next; |
| + | } |
| + | } |
| + | } |
| + | |
| static void SynchronizeFile(const char *fileName) | |
| { | |
| struct parser_t *parser; | |
| @@ -600,51 +533,7 @@ static void SynchronizeDir(void) | |
| } | |
| /* | |
| - | * DeleteFile() - delete user database |
| - | * |
| - | * Note: multiple entries for same user may exist if we were unable to |
| - | * completely delete a database due to running processes. |
| - | */ |
| - | static void DeleteFile(const char *userName) |
| - | { |
| - | CronFile **pfile = &FileBase; |
| - | CronFile *file; |
| - | |
| - | while ((file = *pfile) != NULL) { |
| - | if (strcmp(userName, file->cf_User) == 0) { |
| - | CronLine **pline = &file->cf_LineBase; |
| - | CronLine *line; |
| - | |
| - | file->cf_Running = 0; |
| - | file->cf_Deleted = 1; |
| - | |
| - | while ((line = *pline) != NULL) { |
| - | if (line->cl_Pid > 0) { |
| - | file->cf_Running = 1; |
| - | pline = &line->cl_Next; |
| - | } else { |
| - | *pline = line->cl_Next; |
| - | free(line->cl_Shell); |
| - | free(line); |
| - | } |
| - | } |
| - | if (file->cf_Running == 0) { |
| - | *pfile = file->cf_Next; |
| - | free(file->cf_User); |
| - | free(file); |
| - | } else { |
| - | pfile = &file->cf_Next; |
| - | } |
| - | } else { |
| - | pfile = &file->cf_Next; |
| - | } |
| - | } |
| - | } |
| - | |
| - | /* |
| - | * TestJobs() |
| - | * |
| - | * determine which jobs need to be run. Under normal conditions, the |
| + | * Determine which jobs need to be run. Under normal conditions, the |
| * period is about a minute (one scan). Worst case it will be one | |
| * hour (60 scans). | |
| */ | |
| @@ -695,35 +584,63 @@ static int TestJobs(time_t t1, time_t t2) | |
| return nJobs; | |
| } | |
| - | static void RunJobs(void) |
| + | #if ENABLE_FEATURE_CROND_CALL_SENDMAIL |
| + | static void |
| + | ForkJob(const char *user, CronLine *line, int mailFd, |
| + | const char *prog, const char *cmd, const char *arg, |
| + | const char *mail_filename); |
| + | /* |
| + | * EndJob - called when job terminates and when mail terminates |
| + | */ |
| + | static void EndJob(const char *user, CronLine *line) |
| { | |
| - | CronFile *file; |
| - | CronLine *line; |
| + | int mailFd; |
| + | char mailFile[128]; |
| + | struct stat sbuf; |
| - | for (file = FileBase; file; file = file->cf_Next) { |
| - | if (!file->cf_Ready) |
| - | continue; |
| + | /* No job */ |
| + | if (line->cl_Pid <= 0) { |
| + | line->cl_Pid = 0; |
| + | return; |
| + | } |
| - | file->cf_Ready = 0; |
| - | for (line = file->cf_LineBase; line; line = line->cl_Next) { |
| - | if (line->cl_Pid >= 0) |
| - | continue; |
| + | /* |
| + | * End of job and no mail file |
| + | * End of sendmail job |
| + | */ |
| + | snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d", TMPDIR, user, line->cl_Pid); |
| + | line->cl_Pid = 0; |
| - | RunJob(file->cf_User, line); |
| - | crondlog(LVL8 "USER %s pid %3d cmd %s", |
| - | file->cf_User, (int)line->cl_Pid, line->cl_Shell); |
| - | if (line->cl_Pid < 0) { |
| - | file->cf_Ready = 1; |
| - | } else if (line->cl_Pid > 0) { |
| - | file->cf_Running = 1; |
| - | } |
| - | } |
| + | if (line->cl_MailFlag == 0) { |
| + | return; |
| } | |
| + | line->cl_MailFlag = 0; |
| + | |
| + | /* |
| + | * End of primary job - check for mail file. If size has increased and |
| + | * the file is still valid, we sendmail it. |
| + | */ |
| + | mailFd = open(mailFile, O_RDONLY); |
| + | unlink(mailFile); |
| + | if (mailFd < 0) { |
| + | return; |
| + | } |
| + | |
| + | if (fstat(mailFd, &sbuf) < 0 || sbuf.st_uid != DaemonUid |
| + | || sbuf.st_nlink != 0 || sbuf.st_size == line->cl_MailPos |
| + | || !S_ISREG(sbuf.st_mode) |
| + | ) { |
| + | close(mailFd); |
| + | return; |
| + | } |
| + | if (line->cl_MailTo) |
| + | ForkJob(user, line, mailFd, SENDMAIL, SENDMAIL_ARGS, NULL); |
| } | |
| + | #else |
| + | # define EndJob(user, line) ((line)->cl_Pid = 0) |
| + | #endif |
| /* | |
| - | * CheckJobs() - check for job completion |
| - | * |
| * Check for job completion, return number of jobs still running after | |
| * all done. | |
| */ | |
| @@ -855,55 +772,7 @@ static void RunJob(const char *user, CronLine *line) | |
| ForkJob(user, line, mailFd, DEFAULT_SHELL, "-c", line->cl_Shell, mailFile); | |
| } | |
| - | /* |
| - | * EndJob - called when job terminates and when mail terminates |
| - | */ |
| - | static void EndJob(const char *user, CronLine *line) |
| - | { |
| - | int mailFd; |
| - | char mailFile[128]; |
| - | struct stat sbuf; |
| - | |
| - | /* No job */ |
| - | if (line->cl_Pid <= 0) { |
| - | line->cl_Pid = 0; |
| - | return; |
| - | } |
| - | |
| - | /* |
| - | * End of job and no mail file |
| - | * End of sendmail job |
| - | */ |
| - | snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d", TMPDIR, user, line->cl_Pid); |
| - | line->cl_Pid = 0; |
| - | |
| - | if (line->cl_MailFlag == 0) { |
| - | return; |
| - | } |
| - | line->cl_MailFlag = 0; |
| - | |
| - | /* |
| - | * End of primary job - check for mail file. If size has increased and |
| - | * the file is still valid, we sendmail it. |
| - | */ |
| - | mailFd = open(mailFile, O_RDONLY); |
| - | unlink(mailFile); |
| - | if (mailFd < 0) { |
| - | return; |
| - | } |
| - | |
| - | if (fstat(mailFd, &sbuf) < 0 || sbuf.st_uid != DaemonUid |
| - | || sbuf.st_nlink != 0 || sbuf.st_size == line->cl_MailPos |
| - | || !S_ISREG(sbuf.st_mode) |
| - | ) { |
| - | close(mailFd); |
| - | return; |
| - | } |
| - | if (line->cl_MailTo) |
| - | ForkJob(user, line, mailFd, SENDMAIL, SENDMAIL_ARGS, NULL); |
| - | } |
| - | |
| - | #else /* crond without sendmail */ |
| + | #else /* !ENABLE_FEATURE_CROND_CALL_SENDMAIL */ |
| static void RunJob(const char *user, CronLine *line) | |
| { | |
| @@ -943,4 +812,125 @@ static void RunJob(const char *user, CronLine *line) | |
| line->cl_Pid = pid; | |
| } | |
| - | #endif /* ENABLE_FEATURE_CROND_CALL_SENDMAIL */ |
| + | #endif /* !ENABLE_FEATURE_CROND_CALL_SENDMAIL */ |
| + | |
| + | static void RunJobs(void) |
| + | { |
| + | CronFile *file; |
| + | CronLine *line; |
| + | |
| + | for (file = FileBase; file; file = file->cf_Next) { |
| + | if (!file->cf_Ready) |
| + | continue; |
| + | |
| + | file->cf_Ready = 0; |
| + | for (line = file->cf_LineBase; line; line = line->cl_Next) { |
| + | if (line->cl_Pid >= 0) |
| + | continue; |
| + | |
| + | RunJob(file->cf_User, line); |
| + | crondlog(LVL8 "USER %s pid %3d cmd %s", |
| + | file->cf_User, (int)line->cl_Pid, line->cl_Shell); |
| + | if (line->cl_Pid < 0) { |
| + | file->cf_Ready = 1; |
| + | } else if (line->cl_Pid > 0) { |
| + | file->cf_Running = 1; |
| + | } |
| + | } |
| + | } |
| + | } |
| + | |
| + | int crond_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
| + | int crond_main(int argc UNUSED_PARAM, char **argv) |
| + | { |
| + | time_t t2; |
| + | int rescan; |
| + | int sleep_time; |
| + | unsigned opts; |
| + | |
| + | INIT_G(); |
| + | |
| + | /* "-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 */ |
| + | opts = getopt32(argv, "l:L:fbSc:" IF_FEATURE_CROND_D("d:"), |
| + | &LogLevel, &LogFile, &CDir |
| + | IF_FEATURE_CROND_D(,&LogLevel)); |
| + | /* both -d N and -l N set the same variable: LogLevel */ |
| + | |
| + | if (!(opts & OPT_f)) { |
| + | /* close stdin, stdout, stderr. |
| + | * close unused descriptors - don't need them. */ |
| + | bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv); |
| + | } |
| + | |
| + | if (!(opts & OPT_d) && LogFile == NULL) { |
| + | /* logging to syslog */ |
| + | openlog(applet_name, LOG_CONS | LOG_PID, LOG_CRON); |
| + | logmode = LOGMODE_SYSLOG; |
| + | } |
| + | |
| + | xchdir(CDir); |
| + | //signal(SIGHUP, SIG_IGN); /* ? original crond dies on HUP... */ |
| + | xsetenv("SHELL", DEFAULT_SHELL); /* once, for all future children */ |
| + | crondlog(LVL8 "crond (busybox "BB_VER") started, log level %d", LogLevel); |
| + | SynchronizeDir(); |
| + | write_pidfile("/var/run/crond.pid"); |
| + | |
| + | /* main loop - synchronize to 1 second after the minute, minimum sleep |
| + | * of 1 second. */ |
| + | t2 = time(NULL); |
| + | rescan = 60; |
| + | sleep_time = 60; |
| + | for (;;) { |
| + | time_t t1; |
| + | long dt; |
| + | |
| + | t1 = t2; |
| + | sleep((sleep_time + 1) - (time(NULL) % sleep_time)); |
| + | |
| + | t2 = time(NULL); |
| + | dt = (long)t2 - (long)t1; |
| + | |
| + | /* |
| + | * The file 'cron.update' is checked to determine new cron |
| + | * jobs. The directory is rescanned once an hour to deal |
| + | * with any screwups. |
| + | * |
| + | * Check for time jump. Disparities over an hour either way |
| + | * result in resynchronization. A negative disparity |
| + | * less than an hour causes us to effectively sleep until we |
| + | * match the original time (i.e. no re-execution of jobs that |
| + | * have just been run). A positive disparity less than |
| + | * an hour causes intermediate jobs to be run, but only once |
| + | * in the worst case. |
| + | * |
| + | * When running jobs, the inequality used is greater but not |
| + | * equal to t1, and less then or equal to t2. |
| + | */ |
| + | if (--rescan == 0) { |
| + | rescan = 60; |
| + | SynchronizeDir(); |
| + | } |
| + | CheckUpdates(); |
| + | if (DebugOpt) |
| + | crondlog(LVL5 "wakeup dt=%ld", dt); |
| + | if (dt < -60 * 60 || dt > 60 * 60) { |
| + | crondlog(WARN9 "time disparity of %ld minutes detected", dt / 60); |
| + | /* and we do not run any jobs in this case */ |
| + | } else if (dt > 0) { |
| + | /* Usual case: time advances forwad, as expected */ |
| + | TestJobs(t1, t2); |
| + | RunJobs(); |
| + | sleep(5); |
| + | if (CheckJobs() > 0) { |
| + | sleep_time = 10; |
| + | } else { |
| + | sleep_time = 60; |
| + | } |
| + | } |
| + | /* else: time jumped back, do not run any jobs */ |
| + | } /* for (;;) */ |
| + | |
| + | return 0; /* not reached */ |
| + | } |