+
+int crond_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int crond_main(int argc UNUSED_PARAM, char **argv)
+{
+ time_t t2;
+ unsigned rescan;
+ unsigned sleep_time;
+ unsigned opts;
+
+ INIT_G();
+
+ opts = getopt32(argv, "^"
+ "l:L:fbSc:" IF_FEATURE_CROND_D("d:")
+ "\0"
+ /* "-b after -f is ignored", and so on for every pair a-b */
+ "f-b:b-f:S-L:L-S" IF_FEATURE_CROND_D(":d-l")
+ /* -l and -d have numeric param */
+ ":l+" IF_FEATURE_CROND_D(":d+")
+ ,
+ &G.log_level, &G.log_filename, &G.crontab_dir_name
+ IF_FEATURE_CROND_D(,&G.log_level)
+ );
+ /* both -d N and -l N set the same variable: G.log_level */
+
+ 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) && G.log_filename == NULL) {
+ /* logging to syslog */
+ openlog(applet_name, LOG_CONS | LOG_PID, LOG_CRON);
+ logmode = LOGMODE_SYSLOG;
+ }
+
+ //signal(SIGHUP, SIG_IGN); /* ? original crond dies on HUP... */
+
+ reopen_logfile_to_stderr();
+ xchdir(G.crontab_dir_name);
+ /* $SHELL, or current UID's shell, or DEFAULT_SHELL */
+ /* Useful on Android where DEFAULT_SHELL /bin/sh may not exist */
+ G.default_shell = xstrdup(get_shell_name());
+
+ log8("crond (busybox "BB_VER") started, log level %d", G.log_level);
+ rescan_crontab_dir();
+ write_pidfile(CONFIG_PID_FILE_PATH "/crond.pid");
+#if ENABLE_FEATURE_CROND_SPECIAL_TIMES
+ if (touch_reboot_file())
+ start_jobs(START_ME_REBOOT); /* start @reboot entries, if any */
+#endif
+
+ /* Main loop */
+ t2 = time(NULL);
+ rescan = 60;
+ sleep_time = 60;
+ for (;;) {
+ struct stat sbuf;
+ time_t t1;
+ long dt;
+
+ /* Synchronize to 1 minute, minimum 1 second */
+ t1 = t2;
+ sleep(sleep_time - (time(NULL) % sleep_time));
+ t2 = time(NULL);
+ dt = (long)t2 - (long)t1;
+
+ reopen_logfile_to_stderr();
+
+ /*
+ * 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 (stat(G.crontab_dir_name, &sbuf) != 0)
+ sbuf.st_mtime = 0; /* force update (once) if dir was deleted */
+ if (G.crontab_dir_mtime != sbuf.st_mtime) {
+ G.crontab_dir_mtime = sbuf.st_mtime;
+ rescan = 1;
+ }
+ if (--rescan == 0) {
+ rescan = 60;
+ rescan_crontab_dir();
+ }
+ process_cron_update_file();
+ log5("wakeup dt=%ld", dt);
+ if (dt < -60 * 60 || dt > 60 * 60) {
+ bb_error_msg("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 forward, as expected */
+ flag_starting_jobs(t1, t2);
+ start_jobs(START_ME_NORMAL);
+ sleep_time = 60;
+ if (check_completions() > 0) {
+ /* some jobs are still running */
+ sleep_time = 10;
+ }
+ }
+ /* else: time jumped back, do not run any jobs */
+ } /* for (;;) */
+
+ return 0; /* not reached */
+}