Magellan Linux

Diff of /trunk/mkinitrd-magellan/busybox/miscutils/crond.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 983 by niro, Fri Apr 24 18:33:46 2009 UTC revision 984 by niro, Sun May 30 11:32:42 2010 UTC
# Line 23  Line 23 
23  #endif  #endif
24    
25    
26  #ifndef CRONTABS  #define TMPDIR          CONFIG_FEATURE_CROND_DIR
27  #define CRONTABS        "/var/spool/cron/crontabs"  #define CRONTABS        CONFIG_FEATURE_CROND_DIR "/crontabs"
 #endif  
 #ifndef TMPDIR  
 #define TMPDIR          "/var/spool/cron"  
 #endif  
28  #ifndef SENDMAIL  #ifndef SENDMAIL
29  #define SENDMAIL        "sendmail"  #define SENDMAIL        "sendmail"
30  #endif  #endif
31  #ifndef SENDMAIL_ARGS  #ifndef SENDMAIL_ARGS
32  #define SENDMAIL_ARGS   "-ti", "oem"  #define SENDMAIL_ARGS   "-ti", NULL
33  #endif  #endif
34  #ifndef CRONUPDATE  #ifndef CRONUPDATE
35  #define CRONUPDATE      "cron.update"  #define CRONUPDATE      "cron.update"
# Line 59  typedef struct CronLine { Line 55  typedef struct CronLine {
55  #if ENABLE_FEATURE_CROND_CALL_SENDMAIL  #if ENABLE_FEATURE_CROND_CALL_SENDMAIL
56   int cl_MailPos;         /* 'empty file' size                    */   int cl_MailPos;         /* 'empty file' size                    */
57   smallint cl_MailFlag;   /* running pid is for mail              */   smallint cl_MailFlag;   /* running pid is for mail              */
58   char *cl_MailTo; /* whom to mail results */   char *cl_MailTo; /* whom to mail results                 */
59  #endif  #endif
60   /* ordered by size, not in natural order. makes code smaller: */   /* ordered by size, not in natural order. makes code smaller: */
61   char cl_Dow[7];         /* 0-6, beginning sunday                */   char cl_Dow[7];         /* 0-6, beginning sunday                */
# Line 126  static void EndJob(const char *user, Cro Line 122  static void EndJob(const char *user, Cro
122  static void DeleteFile(const char *userName);  static void DeleteFile(const char *userName);
123    
124    
125    /* 0 is the most verbose, default 8 */
126  #define LVL5  "\x05"  #define LVL5  "\x05"
127  #define LVL7  "\x07"  #define LVL7  "\x07"
128  #define LVL8  "\x08"  #define LVL8  "\x08"
 #define LVL9  "\x09"  
129  #define WARN9 "\x49"  #define WARN9 "\x49"
130  #define DIE9  "\xc9"  #define DIE9  "\xc9"
131  /* level >= 20 is "error" */  /* level >= 20 is "error" */
132  #define ERR20 "\x14"  #define ERR20 "\x14"
133    
134    static void crondlog(const char *ctl, ...) __attribute__ ((format (printf, 1, 2)));
135  static void crondlog(const char *ctl, ...)  static void crondlog(const char *ctl, ...)
136  {  {
137   va_list va;   va_list va;
# Line 146  static void crondlog(const char *ctl, .. Line 143  static void crondlog(const char *ctl, ..
143   /* Syslog mode: all to syslog (logmode = LOGMODE_SYSLOG), */   /* Syslog mode: all to syslog (logmode = LOGMODE_SYSLOG), */
144   if (!DebugOpt && LogFile) {   if (!DebugOpt && LogFile) {
145   /* Otherwise (log to file): we reopen log file at every write: */   /* Otherwise (log to file): we reopen log file at every write: */
146   int logfd = open3_or_warn(LogFile, O_WRONLY | O_CREAT | O_APPEND, 0600);   int logfd = open3_or_warn(LogFile, O_WRONLY | O_CREAT | O_APPEND, 0666);
147   if (logfd >= 0)   if (logfd >= 0)
148   xmove_fd(logfd, STDERR_FILENO);   xmove_fd(logfd, STDERR_FILENO);
149   }   }
150  // TODO: ERR -> error, WARN -> warning, LVL -> info   /* When we log to syslog, level > 8 is logged at LOG_ERR
151   bb_verror_msg(ctl + 1, va, /* strerr: */ NULL);   * syslog level, level <= 8 is logged at LOG_INFO. */
152     if (level > 8) {
153     bb_verror_msg(ctl + 1, va, /* strerr: */ NULL);
154     } else {
155     char *msg = NULL;
156     vasprintf(&msg, ctl + 1, va);
157     bb_info_msg("%s: %s", applet_name, msg);
158     free(msg);
159     }
160   }   }
161   va_end(va);   va_end(va);
162   if (ctl[0] & 0x80)   if (ctl[0] & 0x80)
# Line 161  static void crondlog(const char *ctl, .. Line 166  static void crondlog(const char *ctl, ..
166  int crond_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;  int crond_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
167  int crond_main(int argc UNUSED_PARAM, char **argv)  int crond_main(int argc UNUSED_PARAM, char **argv)
168  {  {
169   unsigned opt;   unsigned opts;
170    
171   INIT_G();   INIT_G();
172    
173   /* "-b after -f is ignored", and so on for every pair a-b */   /* "-b after -f is ignored", and so on for every pair a-b */
174   opt_complementary = "f-b:b-f:S-L:L-S" USE_FEATURE_CROND_D(":d-l")   opt_complementary = "f-b:b-f:S-L:L-S" IF_FEATURE_CROND_D(":d-l")
175   ":l+:d+"; /* -l and -d have numeric param */   ":l+:d+"; /* -l and -d have numeric param */
176   opt = getopt32(argv, "l:L:fbSc:" USE_FEATURE_CROND_D("d:"),   opts = getopt32(argv, "l:L:fbSc:" IF_FEATURE_CROND_D("d:"),
177   &LogLevel, &LogFile, &CDir   &LogLevel, &LogFile, &CDir
178   USE_FEATURE_CROND_D(,&LogLevel));   IF_FEATURE_CROND_D(,&LogLevel));
179   /* both -d N and -l N set the same variable: LogLevel */   /* both -d N and -l N set the same variable: LogLevel */
180    
181   if (!(opt & OPT_f)) {   if (!(opts & OPT_f)) {
182   /* close stdin, stdout, stderr.   /* close stdin, stdout, stderr.
183   * close unused descriptors - don't need them. */   * close unused descriptors - don't need them. */
184   bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv);   bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv);
185   }   }
186    
187   if (!DebugOpt && LogFile == NULL) {   if (!(opts & OPT_d) && LogFile == NULL) {
188   /* logging to syslog */   /* logging to syslog */
189   openlog(applet_name, LOG_CONS | LOG_PID, LOG_CRON);   openlog(applet_name, LOG_CONS | LOG_PID, LOG_CRON);
190   logmode = LOGMODE_SYSLOG;   logmode = LOGMODE_SYSLOG;
# Line 188  int crond_main(int argc UNUSED_PARAM, ch Line 193  int crond_main(int argc UNUSED_PARAM, ch
193   xchdir(CDir);   xchdir(CDir);
194   //signal(SIGHUP, SIG_IGN); /* ? original crond dies on HUP... */   //signal(SIGHUP, SIG_IGN); /* ? original crond dies on HUP... */
195   xsetenv("SHELL", DEFAULT_SHELL); /* once, for all future children */   xsetenv("SHELL", DEFAULT_SHELL); /* once, for all future children */
196   crondlog(LVL9 "crond (busybox "BB_VER") started, log level %d", LogLevel);   crondlog(LVL8 "crond (busybox "BB_VER") started, log level %d", LogLevel);
197   SynchronizeDir();   SynchronizeDir();
198    
199   /* main loop - synchronize to 1 second after the minute, minimum sleep   /* main loop - synchronize to 1 second after the minute, minimum sleep
200   * of 1 second. */   * of 1 second. */
201   {   {
202   time_t t1 = time(NULL);   time_t t1 = time(NULL);
  time_t t2;  
  long dt;  
203   int rescan = 60;   int rescan = 60;
204   int sleep_time = 60;   int sleep_time = 60;
205    
206   write_pidfile("/var/run/crond.pid");   write_pidfile("/var/run/crond.pid");
207   for (;;) {   for (;;) {
208     time_t t2;
209     long dt;
210    
211   sleep((sleep_time + 1) - (time(NULL) % sleep_time));   sleep((sleep_time + 1) - (time(NULL) % sleep_time));
212    
213   t2 = time(NULL);   t2 = time(NULL);
# Line 231  int crond_main(int argc UNUSED_PARAM, ch Line 237  int crond_main(int argc UNUSED_PARAM, ch
237   if (DebugOpt)   if (DebugOpt)
238   crondlog(LVL5 "wakeup dt=%ld", dt);   crondlog(LVL5 "wakeup dt=%ld", dt);
239   if (dt < -60 * 60 || dt > 60 * 60) {   if (dt < -60 * 60 || dt > 60 * 60) {
240   crondlog(WARN9 "time disparity of %d minutes detected", dt / 60);   crondlog(WARN9 "time disparity of %ld minutes detected", dt / 60);
241   } else if (dt > 0) {   } else if (dt > 0) {
242   TestJobs(t1, t2);   TestJobs(t1, t2);
243   RunJobs();   RunJobs();
# Line 243  int crond_main(int argc UNUSED_PARAM, ch Line 249  int crond_main(int argc UNUSED_PARAM, ch
249   }   }
250   }   }
251   t1 = t2;   t1 = t2;
252   }   } /* for (;;) */
253   }   }
254    
255   return 0; /* not reached */   return 0; /* not reached */
256  }  }
257    
# Line 252  int crond_main(int argc UNUSED_PARAM, ch Line 259  int crond_main(int argc UNUSED_PARAM, ch
259  /* We set environment *before* vfork (because we want to use vfork),  /* We set environment *before* vfork (because we want to use vfork),
260   * so we cannot use setenv() - repeated calls to setenv() may leak memory!   * so we cannot use setenv() - repeated calls to setenv() may leak memory!
261   * Using putenv(), and freeing memory after unsetenv() won't leak */   * Using putenv(), and freeing memory after unsetenv() won't leak */
262  static void safe_setenv4(char **pvar_val, const char *var, const char *val /*, int len*/)  static void safe_setenv(char **pvar_val, const char *var, const char *val)
263  {  {
  const int len = 4; /* both var names are 4 char long */  
264   char *var_val = *pvar_val;   char *var_val = *pvar_val;
265    
266   if (var_val) {   if (var_val) {
267   var_val[len] = '\0'; /* nuke '=' */   bb_unsetenv(var_val);
  unsetenv(var_val);  
268   free(var_val);   free(var_val);
269   }   }
270   *pvar_val = xasprintf("%s=%s", var, val);   *pvar_val = xasprintf("%s=%s", var, val);
# Line 270  static void safe_setenv4(char **pvar_val Line 275  static void safe_setenv4(char **pvar_val
275  static void SetEnv(struct passwd *pas)  static void SetEnv(struct passwd *pas)
276  {  {
277  #if SETENV_LEAKS  #if SETENV_LEAKS
278   safe_setenv4(&env_var_user, "USER", pas->pw_name);   safe_setenv(&env_var_user, "USER", pas->pw_name);
279   safe_setenv4(&env_var_home, "HOME", pas->pw_dir);   safe_setenv(&env_var_home, "HOME", pas->pw_dir);
280   /* if we want to set user's shell instead: */   /* if we want to set user's shell instead: */
281   /*safe_setenv(env_var_user, "SHELL", pas->pw_shell, 5);*/   /*safe_setenv(env_var_user, "SHELL", pas->pw_shell);*/
282  #else  #else
283   xsetenv("USER", pas->pw_name);   xsetenv("USER", pas->pw_name);
284   xsetenv("HOME", pas->pw_dir);   xsetenv("HOME", pas->pw_dir);
# Line 287  static void ChangeUser(struct passwd *pa Line 292  static void ChangeUser(struct passwd *pa
292   /* careful: we're after vfork! */   /* careful: we're after vfork! */
293   change_identity(pas); /* - initgroups, setgid, setuid */   change_identity(pas); /* - initgroups, setgid, setuid */
294   if (chdir(pas->pw_dir) < 0) {   if (chdir(pas->pw_dir) < 0) {
295   crondlog(LVL9 "can't chdir(%s)", pas->pw_dir);   crondlog(WARN9 "can't chdir(%s)", pas->pw_dir);
296   if (chdir(TMPDIR) < 0) {   if (chdir(TMPDIR) < 0) {
297   crondlog(DIE9 "can't chdir(%s)", TMPDIR); /* exits */   crondlog(DIE9 "can't chdir(%s)", TMPDIR); /* exits */
298   }   }
# Line 326  static void ParseField(char *user, char Line 331  static void ParseField(char *user, char
331   skip = 1;   skip = 1;
332   ++ptr;   ++ptr;
333   } else if (isdigit(*ptr)) {   } else if (isdigit(*ptr)) {
334     char *endp;
335   if (n1 < 0) {   if (n1 < 0) {
336   n1 = strtol(ptr, &ptr, 10) + off;   n1 = strtol(ptr, &endp, 10) + off;
337   } else {   } else {
338   n2 = strtol(ptr, &ptr, 10) + off;   n2 = strtol(ptr, &endp, 10) + off;
339   }   }
340     ptr = endp; /* gcc likes temp var for &endp */
341   skip = 1;   skip = 1;
342   } else if (names) {   } else if (names) {
343   int i;   int i;
# Line 367  static void ParseField(char *user, char Line 374  static void ParseField(char *user, char
374   n2 = n1;   n2 = n1;
375   }   }
376   if (*ptr == '/') {   if (*ptr == '/') {
377   skip = strtol(ptr + 1, &ptr, 10);   char *endp;
378     skip = strtol(ptr + 1, &endp, 10);
379     ptr = endp; /* gcc likes temp var for &endp */
380   }   }
381    
382   /*   /*
# Line 645  static int TestJobs(time_t t1, time_t t2 Line 654  static int TestJobs(time_t t1, time_t t2
654   /* Find jobs > t1 and <= t2 */   /* Find jobs > t1 and <= t2 */
655    
656   for (t = t1 - t1 % 60; t <= t2; t += 60) {   for (t = t1 - t1 % 60; t <= t2; t += 60) {
657   struct tm *tp;   struct tm *ptm;
658   CronFile *file;   CronFile *file;
659   CronLine *line;   CronLine *line;
660    
661   if (t <= t1)   if (t <= t1)
662   continue;   continue;
663    
664   tp = localtime(&t);   ptm = localtime(&t);
665   for (file = FileBase; file; file = file->cf_Next) {   for (file = FileBase; file; file = file->cf_Next) {
666   if (DebugOpt)   if (DebugOpt)
667   crondlog(LVL5 "file %s:", file->cf_User);   crondlog(LVL5 "file %s:", file->cf_User);
# Line 661  static int TestJobs(time_t t1, time_t t2 Line 670  static int TestJobs(time_t t1, time_t t2
670   for (line = file->cf_LineBase; line; line = line->cl_Next) {   for (line = file->cf_LineBase; line; line = line->cl_Next) {
671   if (DebugOpt)   if (DebugOpt)
672   crondlog(LVL5 " line %s", line->cl_Shell);   crondlog(LVL5 " line %s", line->cl_Shell);
673   if (line->cl_Mins[tp->tm_min] && line->cl_Hrs[tp->tm_hour]   if (line->cl_Mins[ptm->tm_min] && line->cl_Hrs[ptm->tm_hour]
674   && (line->cl_Days[tp->tm_mday] || line->cl_Dow[tp->tm_wday])   && (line->cl_Days[ptm->tm_mday] || line->cl_Dow[ptm->tm_wday])
675   && line->cl_Mons[tp->tm_mon]   && line->cl_Mons[ptm->tm_mon]
676   ) {   ) {
677   if (DebugOpt) {   if (DebugOpt) {
678   crondlog(LVL5 " job: %d %s",   crondlog(LVL5 " job: %d %s",
# Line 762  ForkJob(const char *user, CronLine *line Line 771  ForkJob(const char *user, CronLine *line
771   /* prepare things before vfork */   /* prepare things before vfork */
772   pas = getpwnam(user);   pas = getpwnam(user);
773   if (!pas) {   if (!pas) {
774   crondlog(LVL9 "can't get uid for %s", user);   crondlog(WARN9 "can't get uid for %s", user);
775   goto err;   goto err;
776   }   }
777   SetEnv(pas);   SetEnv(pas);
# Line 781  ForkJob(const char *user, CronLine *line Line 790  ForkJob(const char *user, CronLine *line
790   }   }
791   /* crond 3.0pl1-100 puts tasks in separate process groups */   /* crond 3.0pl1-100 puts tasks in separate process groups */
792   bb_setpgrp();   bb_setpgrp();
793   execlp(prog, prog, cmd, arg, NULL);   execlp(prog, prog, cmd, arg, (char *) NULL);
794   crondlog(ERR20 "can't exec, user %s cmd %s %s %s", user, prog, cmd, arg);   crondlog(ERR20 "can't exec, user %s cmd %s %s %s", user, prog, cmd, arg);
795   if (mail_filename) {   if (mail_filename) {
796   fdprintf(1, "Exec failed: %s -c %s\n", prog, arg);   fdprintf(1, "Exec failed: %s -c %s\n", prog, arg);
# Line 836  static void RunJob(const char *user, Cro Line 845  static void RunJob(const char *user, Cro
845   line->cl_Shell);   line->cl_Shell);
846   line->cl_MailPos = lseek(mailFd, 0, SEEK_CUR);   line->cl_MailPos = lseek(mailFd, 0, SEEK_CUR);
847   } else {   } else {
848   crondlog(ERR20 "cannot create mail file %s for user %s, "   crondlog(ERR20 "can't create mail file %s for user %s, "
849   "discarding output", mailFile, user);   "discarding output", mailFile, user);
850   }   }
851   }   }
# Line 902  static void RunJob(const char *user, Cro Line 911  static void RunJob(const char *user, Cro
911   /* prepare things before vfork */   /* prepare things before vfork */
912   pas = getpwnam(user);   pas = getpwnam(user);
913   if (!pas) {   if (!pas) {
914   crondlog(LVL9 "can't get uid for %s", user);   crondlog(WARN9 "can't get uid for %s", user);
915   goto err;   goto err;
916   }   }
917   SetEnv(pas);   SetEnv(pas);
# Line 918  static void RunJob(const char *user, Cro Line 927  static void RunJob(const char *user, Cro
927   }   }
928   /* crond 3.0pl1-100 puts tasks in separate process groups */   /* crond 3.0pl1-100 puts tasks in separate process groups */
929   bb_setpgrp();   bb_setpgrp();
930   execl(DEFAULT_SHELL, DEFAULT_SHELL, "-c", line->cl_Shell, NULL);   execl(DEFAULT_SHELL, DEFAULT_SHELL, "-c", line->cl_Shell, (char *) NULL);
931   crondlog(ERR20 "can't exec, user %s cmd %s %s %s", user,   crondlog(ERR20 "can't exec, user %s cmd %s %s %s", user,
932   DEFAULT_SHELL, "-c", line->cl_Shell);   DEFAULT_SHELL, "-c", line->cl_Shell);
933   _exit(EXIT_SUCCESS);   _exit(EXIT_SUCCESS);

Legend:
Removed from v.983  
changed lines
  Added in v.984