-int crond_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int crond_main(int argc UNUSED_PARAM, char **argv)
-{
- unsigned opt;
-
- 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" USE_DEBUG_CROND_OPTION(":d-l")
- ":l+:d+"; /* -l and -d have numeric param */
- opt = getopt32(argv, "l:L:fbSc:" USE_DEBUG_CROND_OPTION("d:"),
- &LogLevel, &LogFile, &CDir
- USE_DEBUG_CROND_OPTION(,&LogLevel));
- /* both -d N and -l N set the same variable: LogLevel */
-
- if (!(opt & OPT_f)) {
- /* close stdin, stdout, stderr.
- * close unused descriptors - don't need them. */
- bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv);
- }
-
- if (!DebugOpt && 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... */
- setenv("SHELL", DEFAULT_SHELL, 1); /* once, for all future children */
- crondlog(LVL9 "crond (busybox "BB_VER") started, log level %d", LogLevel);
- SynchronizeDir();
-
- /* main loop - synchronize to 1 second after the minute, minimum sleep
- * of 1 second. */
- {
- time_t t1 = time(NULL);
- time_t t2;
- long dt;
- int rescan = 60;
- int sleep_time = 60;
-
- write_pidfile("/var/run/crond.pid");
- for (;;) {
- 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 disparity. Disparities over an hour either way
- * result in resynchronization. A reverse-indexed disparity
- * less then 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 forward-indexed disparity less then
- * 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 %d minutes detected", dt / 60);
- } else if (dt > 0) {
- TestJobs(t1, t2);
- RunJobs();
- sleep(5);
- if (CheckJobs() > 0) {
- sleep_time = 10;
- } else {
- sleep_time = 60;
- }
- }
- t1 = t2;
- }
- }
- 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!
- * Using putenv(), and freeing memory after unsetenv() won't leak */
-static void safe_setenv4(char **pvar_val, const char *var, const char *val /*, int len*/)
-{
- const int len = 4; /* both var names are 4 char long */
- char *var_val = *pvar_val;
-
- if (var_val) {
- var_val[len] = '\0'; /* nuke '=' */
- unsetenv(var_val);
- free(var_val);
- }
- *pvar_val = xasprintf("%s=%s", var, val);
- putenv(*pvar_val);
-}
-#endif
-
-static void SetEnv(struct passwd *pas)
-{
-#if SETENV_LEAKS
- safe_setenv4(&env_var_user, "USER", pas->pw_name);
- safe_setenv4(&env_var_home, "HOME", pas->pw_dir);
- /* if we want to set user's shell instead: */
- /*safe_setenv(env_var_user, "SHELL", pas->pw_shell, 5);*/
-#else
- setenv("USER", pas->pw_name, 1);
- setenv("HOME", pas->pw_dir, 1);
-#endif
- /* currently, we use constant one: */
- /*setenv("SHELL", DEFAULT_SHELL, 1); - done earlier */
-}
-
-static void ChangeUser(struct passwd *pas)
-{
- /* careful: we're after vfork! */
- change_identity(pas); /* - initgroups, setgid, setuid */
- if (chdir(pas->pw_dir) < 0) {
- crondlog(LVL9 "can't chdir(%s)", pas->pw_dir);
- if (chdir(TMPDIR) < 0) {
- crondlog(DIE9 "can't chdir(%s)", TMPDIR); /* exits */
- }
- }
-}
-