diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2010-07-08 04:07:54 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2010-07-08 04:07:54 +0200 |
commit | dfc870fab711b3ee85341f8cd8e7c8e0799d2da7 (patch) | |
tree | c5c3241d76a5c759c009324bd025f5da2bb09d87 | |
parent | 4a09aefae2523bf242039e45c9f85bd1f35b72ad (diff) | |
download | busybox-w32-dfc870fab711b3ee85341f8cd8e7c8e0799d2da7.tar.gz busybox-w32-dfc870fab711b3ee85341f8cd8e7c8e0799d2da7.tar.bz2 busybox-w32-dfc870fab711b3ee85341f8cd8e7c8e0799d2da7.zip |
crond: check mtime on crontab dir every minute, and reread if changed
function old new delta
crond_main 1417 1460 +43
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | miscutils/crond.c | 75 |
1 files changed, 36 insertions, 39 deletions
diff --git a/miscutils/crond.c b/miscutils/crond.c index 06d72ced9..481830f4d 100644 --- a/miscutils/crond.c +++ b/miscutils/crond.c | |||
@@ -87,6 +87,7 @@ enum { | |||
87 | 87 | ||
88 | struct globals { | 88 | struct globals { |
89 | unsigned LogLevel; /* = 8; */ | 89 | unsigned LogLevel; /* = 8; */ |
90 | time_t CDir_mtime; | ||
90 | const char *LogFile; | 91 | const char *LogFile; |
91 | const char *CDir; /* = CRONTABS; */ | 92 | const char *CDir; /* = CRONTABS; */ |
92 | CronFile *FileBase; | 93 | CronFile *FileBase; |
@@ -96,15 +97,9 @@ struct globals { | |||
96 | #endif | 97 | #endif |
97 | } FIX_ALIASING; | 98 | } FIX_ALIASING; |
98 | #define G (*(struct globals*)&bb_common_bufsiz1) | 99 | #define G (*(struct globals*)&bb_common_bufsiz1) |
99 | #define LogLevel (G.LogLevel ) | ||
100 | #define LogFile (G.LogFile ) | ||
101 | #define CDir (G.CDir ) | ||
102 | #define FileBase (G.FileBase ) | ||
103 | #define env_var_user (G.env_var_user ) | ||
104 | #define env_var_home (G.env_var_home ) | ||
105 | #define INIT_G() do { \ | 100 | #define INIT_G() do { \ |
106 | LogLevel = 8; \ | 101 | G.LogLevel = 8; \ |
107 | CDir = CRONTABS; \ | 102 | G.CDir = CRONTABS; \ |
108 | } while (0) | 103 | } while (0) |
109 | 104 | ||
110 | 105 | ||
@@ -124,12 +119,12 @@ static void crondlog(const char *ctl, ...) | |||
124 | int level = (ctl[0] & 0x1f); | 119 | int level = (ctl[0] & 0x1f); |
125 | 120 | ||
126 | va_start(va, ctl); | 121 | va_start(va, ctl); |
127 | if (level >= (int)LogLevel) { | 122 | if (level >= (int)G.LogLevel) { |
128 | /* Debug mode: all to (non-redirected) stderr, */ | 123 | /* Debug mode: all to (non-redirected) stderr, */ |
129 | /* Syslog mode: all to syslog (logmode = LOGMODE_SYSLOG), */ | 124 | /* Syslog mode: all to syslog (logmode = LOGMODE_SYSLOG), */ |
130 | if (!DebugOpt && LogFile) { | 125 | if (!DebugOpt && G.LogFile) { |
131 | /* Otherwise (log to file): we reopen log file at every write: */ | 126 | /* Otherwise (log to file): we reopen log file at every write: */ |
132 | int logfd = open3_or_warn(LogFile, O_WRONLY | O_CREAT | O_APPEND, 0666); | 127 | int logfd = open3_or_warn(G.LogFile, O_WRONLY | O_CREAT | O_APPEND, 0666); |
133 | if (logfd >= 0) | 128 | if (logfd >= 0) |
134 | xmove_fd(logfd, STDERR_FILENO); | 129 | xmove_fd(logfd, STDERR_FILENO); |
135 | } | 130 | } |
@@ -168,10 +163,10 @@ static void safe_setenv(char **pvar_val, const char *var, const char *val) | |||
168 | static void SetEnv(struct passwd *pas) | 163 | static void SetEnv(struct passwd *pas) |
169 | { | 164 | { |
170 | #if SETENV_LEAKS | 165 | #if SETENV_LEAKS |
171 | safe_setenv(&env_var_user, "USER", pas->pw_name); | 166 | safe_setenv(&G.env_var_user, "USER", pas->pw_name); |
172 | safe_setenv(&env_var_home, "HOME", pas->pw_dir); | 167 | safe_setenv(&G.env_var_home, "HOME", pas->pw_dir); |
173 | /* if we want to set user's shell instead: */ | 168 | /* if we want to set user's shell instead: */ |
174 | /*safe_setenv(env_var_shell, "SHELL", pas->pw_shell);*/ | 169 | /*safe_setenv(G.env_var_shell, "SHELL", pas->pw_shell);*/ |
175 | #else | 170 | #else |
176 | xsetenv("USER", pas->pw_name); | 171 | xsetenv("USER", pas->pw_name); |
177 | xsetenv("HOME", pas->pw_dir); | 172 | xsetenv("HOME", pas->pw_dir); |
@@ -308,7 +303,7 @@ static void ParseField(char *user, char *ary, int modvalue, int off, | |||
308 | return; | 303 | return; |
309 | } | 304 | } |
310 | 305 | ||
311 | if (DebugOpt && (LogLevel <= 5)) { /* like LVL5 */ | 306 | if (DebugOpt && (G.LogLevel <= 5)) { /* like LVL5 */ |
312 | /* can't use crondlog, it inserts '\n' */ | 307 | /* can't use crondlog, it inserts '\n' */ |
313 | int i; | 308 | int i; |
314 | for (i = 0; i < modvalue; ++i) | 309 | for (i = 0; i < modvalue; ++i) |
@@ -351,7 +346,7 @@ static void FixDayDow(CronLine *line) | |||
351 | */ | 346 | */ |
352 | static void DeleteFile(const char *userName) | 347 | static void DeleteFile(const char *userName) |
353 | { | 348 | { |
354 | CronFile **pfile = &FileBase; | 349 | CronFile **pfile = &G.FileBase; |
355 | CronFile *file; | 350 | CronFile *file; |
356 | 351 | ||
357 | while ((file = *pfile) != NULL) { | 352 | while ((file = *pfile) != NULL) { |
@@ -462,8 +457,8 @@ static void SynchronizeFile(const char *fileName) | |||
462 | } | 457 | } |
463 | *pline = NULL; | 458 | *pline = NULL; |
464 | 459 | ||
465 | file->cf_Next = FileBase; | 460 | file->cf_Next = G.FileBase; |
466 | FileBase = file; | 461 | G.FileBase = file; |
467 | 462 | ||
468 | if (maxLines == 0) { | 463 | if (maxLines == 0) { |
469 | crondlog(WARN9 "user %s: too many lines", fileName); | 464 | crondlog(WARN9 "user %s: too many lines", fileName); |
@@ -493,7 +488,7 @@ static void SynchronizeDir(void) | |||
493 | CronFile *file; | 488 | CronFile *file; |
494 | /* Attempt to delete the database. */ | 489 | /* Attempt to delete the database. */ |
495 | again: | 490 | again: |
496 | for (file = FileBase; file; file = file->cf_Next) { | 491 | for (file = G.FileBase; file; file = file->cf_Next) { |
497 | if (!file->cf_Deleted) { | 492 | if (!file->cf_Deleted) { |
498 | DeleteFile(file->cf_User); | 493 | DeleteFile(file->cf_User); |
499 | goto again; | 494 | goto again; |
@@ -509,8 +504,8 @@ static void SynchronizeDir(void) | |||
509 | * scan directory and add associated users | 504 | * scan directory and add associated users |
510 | */ | 505 | */ |
511 | unlink(CRONUPDATE); | 506 | unlink(CRONUPDATE); |
512 | if (chdir(CDir) < 0) { | 507 | if (chdir(G.CDir) < 0) { |
513 | crondlog(DIE9 "chdir(%s)", CDir); | 508 | crondlog(DIE9 "chdir(%s)", G.CDir); |
514 | } | 509 | } |
515 | { | 510 | { |
516 | DIR *dir = opendir("."); | 511 | DIR *dir = opendir("."); |
@@ -537,9 +532,8 @@ static void SynchronizeDir(void) | |||
537 | * period is about a minute (one scan). Worst case it will be one | 532 | * period is about a minute (one scan). Worst case it will be one |
538 | * hour (60 scans). | 533 | * hour (60 scans). |
539 | */ | 534 | */ |
540 | static int TestJobs(time_t t1, time_t t2) | 535 | static void TestJobs(time_t t1, time_t t2) |
541 | { | 536 | { |
542 | int nJobs = 0; | ||
543 | time_t t; | 537 | time_t t; |
544 | 538 | ||
545 | /* Find jobs > t1 and <= t2 */ | 539 | /* Find jobs > t1 and <= t2 */ |
@@ -553,7 +547,7 @@ static int TestJobs(time_t t1, time_t t2) | |||
553 | continue; | 547 | continue; |
554 | 548 | ||
555 | ptm = localtime(&t); | 549 | ptm = localtime(&t); |
556 | for (file = FileBase; file; file = file->cf_Next) { | 550 | for (file = G.FileBase; file; file = file->cf_Next) { |
557 | if (DebugOpt) | 551 | if (DebugOpt) |
558 | crondlog(LVL5 "file %s:", file->cf_User); | 552 | crondlog(LVL5 "file %s:", file->cf_User); |
559 | if (file->cf_Deleted) | 553 | if (file->cf_Deleted) |
@@ -575,13 +569,11 @@ static int TestJobs(time_t t1, time_t t2) | |||
575 | } else if (line->cl_Pid == 0) { | 569 | } else if (line->cl_Pid == 0) { |
576 | line->cl_Pid = -1; | 570 | line->cl_Pid = -1; |
577 | file->cf_Ready = 1; | 571 | file->cf_Ready = 1; |
578 | ++nJobs; | ||
579 | } | 572 | } |
580 | } | 573 | } |
581 | } | 574 | } |
582 | } | 575 | } |
583 | } | 576 | } |
584 | return nJobs; | ||
585 | } | 577 | } |
586 | 578 | ||
587 | #if ENABLE_FEATURE_CROND_CALL_SENDMAIL | 579 | #if ENABLE_FEATURE_CROND_CALL_SENDMAIL |
@@ -650,7 +642,7 @@ static int CheckJobs(void) | |||
650 | CronLine *line; | 642 | CronLine *line; |
651 | int nStillRunning = 0; | 643 | int nStillRunning = 0; |
652 | 644 | ||
653 | for (file = FileBase; file; file = file->cf_Next) { | 645 | for (file = G.FileBase; file; file = file->cf_Next) { |
654 | if (file->cf_Running) { | 646 | if (file->cf_Running) { |
655 | file->cf_Running = 0; | 647 | file->cf_Running = 0; |
656 | 648 | ||
@@ -819,7 +811,7 @@ static void RunJobs(void) | |||
819 | CronFile *file; | 811 | CronFile *file; |
820 | CronLine *line; | 812 | CronLine *line; |
821 | 813 | ||
822 | for (file = FileBase; file; file = file->cf_Next) { | 814 | for (file = G.FileBase; file; file = file->cf_Next) { |
823 | if (!file->cf_Ready) | 815 | if (!file->cf_Ready) |
824 | continue; | 816 | continue; |
825 | 817 | ||
@@ -854,9 +846,9 @@ int crond_main(int argc UNUSED_PARAM, char **argv) | |||
854 | opt_complementary = "f-b:b-f:S-L:L-S" IF_FEATURE_CROND_D(":d-l") | 846 | opt_complementary = "f-b:b-f:S-L:L-S" IF_FEATURE_CROND_D(":d-l") |
855 | ":l+:d+"; /* -l and -d have numeric param */ | 847 | ":l+:d+"; /* -l and -d have numeric param */ |
856 | opts = getopt32(argv, "l:L:fbSc:" IF_FEATURE_CROND_D("d:"), | 848 | opts = getopt32(argv, "l:L:fbSc:" IF_FEATURE_CROND_D("d:"), |
857 | &LogLevel, &LogFile, &CDir | 849 | &G.LogLevel, &G.LogFile, &G.CDir |
858 | IF_FEATURE_CROND_D(,&LogLevel)); | 850 | IF_FEATURE_CROND_D(,&G.LogLevel)); |
859 | /* both -d N and -l N set the same variable: LogLevel */ | 851 | /* both -d N and -l N set the same variable: G.LogLevel */ |
860 | 852 | ||
861 | if (!(opts & OPT_f)) { | 853 | if (!(opts & OPT_f)) { |
862 | /* close stdin, stdout, stderr. | 854 | /* close stdin, stdout, stderr. |
@@ -864,30 +856,32 @@ int crond_main(int argc UNUSED_PARAM, char **argv) | |||
864 | bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv); | 856 | bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv); |
865 | } | 857 | } |
866 | 858 | ||
867 | if (!(opts & OPT_d) && LogFile == NULL) { | 859 | if (!(opts & OPT_d) && G.LogFile == NULL) { |
868 | /* logging to syslog */ | 860 | /* logging to syslog */ |
869 | openlog(applet_name, LOG_CONS | LOG_PID, LOG_CRON); | 861 | openlog(applet_name, LOG_CONS | LOG_PID, LOG_CRON); |
870 | logmode = LOGMODE_SYSLOG; | 862 | logmode = LOGMODE_SYSLOG; |
871 | } | 863 | } |
872 | 864 | ||
873 | xchdir(CDir); | 865 | xchdir(G.CDir); |
874 | //signal(SIGHUP, SIG_IGN); /* ? original crond dies on HUP... */ | 866 | //signal(SIGHUP, SIG_IGN); /* ? original crond dies on HUP... */ |
875 | xsetenv("SHELL", DEFAULT_SHELL); /* once, for all future children */ | 867 | xsetenv("SHELL", DEFAULT_SHELL); /* once, for all future children */ |
876 | crondlog(LVL8 "crond (busybox "BB_VER") started, log level %d", LogLevel); | 868 | crondlog(LVL8 "crond (busybox "BB_VER") started, log level %d", G.LogLevel); |
877 | SynchronizeDir(); | 869 | SynchronizeDir(); |
878 | write_pidfile("/var/run/crond.pid"); | 870 | write_pidfile("/var/run/crond.pid"); |
879 | 871 | ||
880 | /* main loop - synchronize to 1 second after the minute, minimum sleep | 872 | /* Main loop */ |
881 | * of 1 second. */ | ||
882 | t2 = time(NULL); | 873 | t2 = time(NULL); |
883 | rescan = 60; | 874 | rescan = 60; |
884 | sleep_time = 60; | 875 | sleep_time = 60; |
885 | for (;;) { | 876 | for (;;) { |
877 | struct stat sbuf; | ||
886 | time_t t1; | 878 | time_t t1; |
887 | long dt; | 879 | long dt; |
888 | 880 | ||
889 | t1 = t2; | 881 | t1 = t2; |
890 | sleep((sleep_time + 1) - (time(NULL) % sleep_time)); | 882 | |
883 | /* Synchronize to 1 minute, minimum 1 second */ | ||
884 | sleep(sleep_time - (time(NULL) % sleep_time) + 1); | ||
891 | 885 | ||
892 | t2 = time(NULL); | 886 | t2 = time(NULL); |
893 | dt = (long)t2 - (long)t1; | 887 | dt = (long)t2 - (long)t1; |
@@ -908,6 +902,10 @@ int crond_main(int argc UNUSED_PARAM, char **argv) | |||
908 | * When running jobs, the inequality used is greater but not | 902 | * When running jobs, the inequality used is greater but not |
909 | * equal to t1, and less then or equal to t2. | 903 | * equal to t1, and less then or equal to t2. |
910 | */ | 904 | */ |
905 | if (stat(G.CDir, &sbuf) == 0 && G.CDir_mtime != sbuf.st_mtime) { | ||
906 | G.CDir_mtime = sbuf.st_mtime; | ||
907 | rescan = 1; | ||
908 | } | ||
911 | if (--rescan == 0) { | 909 | if (--rescan == 0) { |
912 | rescan = 60; | 910 | rescan = 60; |
913 | SynchronizeDir(); | 911 | SynchronizeDir(); |
@@ -919,10 +917,9 @@ int crond_main(int argc UNUSED_PARAM, char **argv) | |||
919 | crondlog(WARN9 "time disparity of %ld minutes detected", dt / 60); | 917 | crondlog(WARN9 "time disparity of %ld minutes detected", dt / 60); |
920 | /* and we do not run any jobs in this case */ | 918 | /* and we do not run any jobs in this case */ |
921 | } else if (dt > 0) { | 919 | } else if (dt > 0) { |
922 | /* Usual case: time advances forwad, as expected */ | 920 | /* Usual case: time advances forward, as expected */ |
923 | TestJobs(t1, t2); | 921 | TestJobs(t1, t2); |
924 | RunJobs(); | 922 | RunJobs(); |
925 | sleep(5); | ||
926 | if (CheckJobs() > 0) { | 923 | if (CheckJobs() > 0) { |
927 | sleep_time = 10; | 924 | sleep_time = 10; |
928 | } else { | 925 | } else { |