root/src/cron.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. reset_watches
  2. set_cron_unwatched
  3. set_cron_watched
  4. handle_signals
  5. usage
  6. main
  7. run_reboot_jobs
  8. find_jobs
  9. set_time
  10. cron_sleep
  11. sighup_handler
  12. sigchld_handler
  13. sigintterm_handler
  14. sigchld_reaper
  15. parse_args

   1 /* Copyright 1988,1990,1993,1994 by Paul Vixie
   2  * All rights reserved
   3  */
   4 
   5 /*
   6  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
   7  * Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
   8  *
   9  * Permission to use, copy, modify, and distribute this software for any
  10  * purpose with or without fee is hereby granted, provided that the above
  11  * copyright notice and this permission notice appear in all copies.
  12  *
  13  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
  14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  15  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
  16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
  19  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  20  */
  21 
  22 /*
  23  * Modified 2010/09/12 by Colin Dean, Durham University IT Service,
  24  * to add clustering support.
  25  */
  26 
  27 #include "config.h"
  28 
  29 #define MAIN_PROGRAM
  30 
  31 #include <errno.h>
  32 #include <langinfo.h>
  33 #include <locale.h>
  34 #include <pwd.h>
  35 #include <signal.h>
  36 #include <stdlib.h>
  37 #include <string.h>
  38 #include <sys/stat.h>
  39 #include <sys/types.h>
  40 #include <sys/wait.h>
  41 #include <unistd.h>
  42 #include <sys/time.h>
  43 
  44 #ifdef WITH_INOTIFY
  45 # include <sys/inotify.h>
  46 #endif
  47 
  48 #ifdef HAVE_SYS_FCNTL_H
  49 # include <sys/fcntl.h>
  50 #endif
  51 
  52 #include "cronie_common.h"
  53 #include "funcs.h"
  54 #include "globals.h"
  55 #include "pathnames.h"
  56 
  57 #if defined WITH_INOTIFY
  58 int inotify_enabled;
  59 #else
  60 # define inotify_enabled 0
  61 #endif
  62 
  63 enum timejump { negative, small, medium, large };
  64 
  65 static void usage(void) ATTRIBUTE_NORETURN,
  66 run_reboot_jobs(cron_db *),
  67 find_jobs(int, cron_db *, int, int, long),
  68 set_time(int),
  69 cron_sleep(int, cron_db *),
  70 sigchld_handler(int),
  71 sighup_handler(int),
  72 sigchld_reaper(void), sigintterm_handler(int), parse_args(int c, char *v[]);
  73 
  74 static volatile sig_atomic_t got_sighup, got_sigchld, got_sigintterm;
  75 static int timeRunning, virtualTime, clockTime;
  76 static long GMToff;
  77 static int DisableInotify;
  78 
  79 #if defined WITH_INOTIFY
  80 
  81 /*
  82  * Note that inotify isn't safe to use with clustering, as changes made
  83  * to a shared filesystem on one system cannot be relied on to be notified
  84  * on another system, so use of inotify is disabled at runtime if run with
  85  * clustering enabled.
  86  */
  87 
  88 # if defined ENABLE_SYSCRONTAB
  89 #       define NUM_WATCHES 3
  90 
  91 int wd[NUM_WATCHES];
  92 const char *watchpaths[NUM_WATCHES] = {SPOOL_DIR, SYS_CROND_DIR, SYSCRONTAB};
  93 # else
  94 #       define NUM_WATCHES 2
  95 int wd[NUM_WATCHES];
  96 const char *watchpaths[NUM_WATCHES] = {SPOOL_DIR, SYS_CROND_DIR};
  97 # endif
  98 
  99 static void reset_watches(void) {
     /* [previous][next][first][last][top][bottom][index][help]  */
 100         size_t i;
 101 
 102         for (i = 0; i < sizeof (wd) / sizeof (wd[0]); ++i) {
 103                 wd[i] = -2;
 104         }
 105 }
 106 
 107 void set_cron_unwatched(int fd) {
     /* [previous][next][first][last][top][bottom][index][help]  */
 108         size_t i;
 109 
 110         for (i = 0; i < sizeof (wd) / sizeof (wd[0]); ++i) {
 111                 if (wd[i] > 0) {
 112                         inotify_rm_watch(fd, wd[i]);
 113                         wd[i] = -1;
 114                 }
 115         }
 116 }
 117 
 118 void set_cron_watched(int fd) {
     /* [previous][next][first][last][top][bottom][index][help]  */
 119         pid_t pid = getpid();
 120         size_t i;
 121 
 122         if (fd < 0) {
 123                 inotify_enabled = 0;
 124                 return;
 125         }
 126 
 127         for (i = 0; i < sizeof (wd) / sizeof (wd[0]); ++i) {
 128                 int w;
 129 
 130                 w = inotify_add_watch(fd, watchpaths[i],
 131                         IN_CREATE | IN_CLOSE_WRITE | IN_ATTRIB | IN_MODIFY | IN_MOVED_TO |
 132                         IN_MOVED_FROM | IN_MOVE_SELF | IN_DELETE | IN_DELETE_SELF);
 133                 if (w < 0 && errno != ENOENT) {
 134                         if (wd[i] != -1) {
 135                                 log_it("CRON", pid, "This directory or file can't be watched",
 136                                         watchpaths[i], errno);
 137                                 log_it("CRON", pid, "INFO", "running without inotify support",
 138                                         0);
 139                         }
 140                         inotify_enabled = 0;
 141                         set_cron_unwatched(fd);
 142                         return;
 143                 }
 144                 wd[i] = w;
 145         }
 146 
 147         if (!inotify_enabled) {
 148                 log_it("CRON", pid, "INFO", "running with inotify support", 0);
 149         }
 150 
 151         inotify_enabled = 1;
 152 }
 153 #endif
 154 
 155 static void handle_signals(cron_db * database) {
     /* [previous][next][first][last][top][bottom][index][help]  */
 156         if (got_sighup) {
 157                 got_sighup = 0;
 158 #if defined WITH_INOTIFY
 159                 /* watches must be reinstated on reload */
 160                 if (inotify_enabled && (EnableClustering != 1)) {
 161                         set_cron_unwatched(database->ifd);
 162                         reset_watches();
 163                         inotify_enabled = 0;
 164                 }
 165 #endif
 166                 database->mtime = (time_t) 0;
 167                 log_close();
 168         }
 169 
 170         if (got_sigchld) {
 171                 got_sigchld = 0;
 172                 sigchld_reaper();
 173         }
 174 }
 175 
 176 static void usage(void) {
     /* [previous][next][first][last][top][bottom][index][help]  */
 177         const char **dflags;
 178 
 179         fprintf(stderr, "Usage:\n");
 180         fprintf(stderr, " %s [options]\n", ProgramName);
 181         fprintf(stderr, "\n");
 182         fprintf(stderr, "Options:\n");
 183         fprintf(stderr, " -h         print this message \n");
 184         fprintf(stderr, " -i         deamon runs without inotify support\n");
 185         fprintf(stderr, " -m <comm>  off, or specify preferred client for sending mails\n");
 186         fprintf(stderr, " -n         run in foreground\n");
 187         fprintf(stderr, " -p         permit any crontab\n");
 188         fprintf(stderr, " -P         use PATH=\"%s\"\n", _PATH_DEFPATH);
 189         fprintf(stderr, " -c         enable clustering support\n");
 190         fprintf(stderr, " -s         log into syslog instead of sending mails\n");
 191         fprintf(stderr, " -V         print version and exit\n");
 192         fprintf(stderr, " -x <flag>  print debug information\n");
 193         fprintf(stderr, "\n");
 194         fprintf(stderr, "Debugging flags are: ");
 195         for (dflags = DebugFlagNames; *dflags; dflags++)
 196                 fprintf(stderr, "%s%s", *dflags, dflags[1] ? "," : "\n");
 197         exit(ERROR_EXIT);
 198 }
 199 
 200 int main(int argc, char *argv[]) {
     /* [previous][next][first][last][top][bottom][index][help]  */
 201         struct sigaction sact;
 202         cron_db database;
 203         int fd;
 204         char *cs;
 205         pid_t pid = getpid();
 206         long oldGMToff;
 207         struct timeval tv;
 208         struct timezone tz;
 209         char buf[256];
 210 
 211         if ((ProgramName=strrchr(argv[0], '/')) == NULL) {
 212                 ProgramName = argv[0];
 213         }
 214         else {
 215                 ++ProgramName;
 216         }
 217 
 218         MailCmd[0] = '\0';
 219         cron_default_mail_charset[0] = '\0';
 220 
 221         setlocale(LC_ALL, "");
 222 
 223 #if defined(BSD)
 224         setlinebuf(stdout);
 225         setlinebuf(stderr);
 226 #endif
 227 
 228         SyslogOutput = 0;
 229         NoFork = 0;
 230         ChangePath = 1;
 231         parse_args(argc, argv);
 232 
 233         memset((char *) &sact, 0, sizeof sact);
 234         sigemptyset(&sact.sa_mask);
 235         sact.sa_flags = 0;
 236 #ifdef SA_RESTART
 237         sact.sa_flags |= SA_RESTART;
 238 #endif
 239         sact.sa_handler = sigchld_handler;
 240         (void) sigaction(SIGCHLD, &sact, NULL);
 241         sact.sa_handler = sighup_handler;
 242         (void) sigaction(SIGHUP, &sact, NULL);
 243         sact.sa_handler = sigintterm_handler;
 244         (void) sigaction(SIGINT, &sact, NULL);
 245         (void) sigaction(SIGTERM, &sact, NULL);
 246 
 247         acquire_daemonlock(0);
 248         set_cron_uid();
 249         check_spool_dir();
 250 
 251         if (ChangePath) {
 252                 if (setenv("PATH", _PATH_DEFPATH, 1) < 0) {
 253                         log_it("CRON", pid, "DEATH", "can't setenv PATH",
 254                                 errno);
 255                         exit(1);
 256                 }
 257         }
 258 
 259         /* Get the default locale character set for the mail 
 260          * "Content-Type: ...; charset=" header
 261          */
 262         setlocale(LC_ALL, "");  /* set locale to system defaults or to
 263                                                          * that specified by any  LC_* env vars */
 264         if ((cs = nl_langinfo(CODESET)) != 0L)
 265                 strncpy(cron_default_mail_charset, cs, MAX_ENVSTR-1);
 266         else
 267                 strcpy(cron_default_mail_charset, "US-ASCII");
 268 
 269         /* if there are no debug flags turned on, fork as a daemon should.
 270          */
 271         if (DebugFlags) {
 272 #if DEBUGGING
 273                 (void) fprintf(stderr, "[%ld] cron started\n", (long) getpid());
 274 #endif
 275         }
 276         else if (NoFork == 0) {
 277                 switch (fork()) {
 278                 case -1:
 279                         log_it("CRON", pid, "DEATH", "can't fork", errno);
 280                         exit(0);
 281                         break;
 282                 case 0:
 283                         /* child process */
 284                         (void) setsid();
 285                         if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) >= 0) {
 286                                 (void) dup2(fd, STDIN);
 287                                 (void) dup2(fd, STDOUT);
 288                                 (void) dup2(fd, STDERR);
 289                                 if (fd != STDERR)
 290                                         (void) close(fd);
 291                         }
 292                         break;
 293                 default:
 294                         /* parent process should just die */
 295                         _exit(0);
 296                 }
 297         }
 298 
 299         log_it("CRON", getpid(), "STARTUP", PACKAGE_VERSION, 0);
 300 
 301         if (!SyslogOutput && MailCmd[0] == '\0' && access("/usr/sbin/sendmail", X_OK) != 0) {
 302                 SyslogOutput=1;
 303                 log_it("CRON", pid, "INFO","Syslog will be used instead of sendmail.", 0);
 304         }
 305 
 306         pid = getpid();
 307 
 308         /* obtain a random scaling factor for RANDOM_DELAY */
 309         if (gettimeofday(&tv, &tz) != 0)
 310                 tv.tv_usec = 0;
 311         srandom((unsigned int)(pid + tv.tv_usec));
 312         RandomScale = (double)random() / (double)RAND_MAX;
 313         snprintf(buf, sizeof(buf), "RANDOM_DELAY will be scaled with factor %d%% if used.", (int)(RandomScale*100));
 314         log_it("CRON", pid, "INFO", buf, 0);
 315 
 316         acquire_daemonlock(0);
 317         database.head = NULL;
 318         database.tail = NULL;
 319         database.mtime = (time_t) 0;
 320 
 321         load_database(&database);
 322 
 323         fd = -1;
 324 #if defined WITH_INOTIFY
 325         if (DisableInotify || EnableClustering) {
 326                 log_it("CRON", getpid(), "No inotify - daemon runs with -i or -c option", 
 327                         "", 0);
 328         }
 329         else {
 330                 reset_watches();
 331                 database.ifd = fd = inotify_init();
 332                 fcntl(fd, F_SETFD, FD_CLOEXEC);
 333                 if (fd < 0)
 334                         log_it("CRON", pid, "INFO", "Inotify init failed", errno);
 335                 set_cron_watched(fd);
 336         }
 337 #endif
 338 
 339         set_time(TRUE);
 340         run_reboot_jobs(&database);
 341         timeRunning = virtualTime = clockTime;
 342         oldGMToff = GMToff;
 343 
 344         /*
 345          * Too many clocks, not enough time (Al. Einstein)
 346          * These clocks are in minutes since the epoch, adjusted for timezone.
 347          * virtualTime: is the time it *would* be if we woke up
 348          * promptly and nobody ever changed the clock. It is
 349          * monotonically increasing... unless a timejump happens.
 350          * At the top of the loop, all jobs for 'virtualTime' have run.
 351          * timeRunning: is the time we last awakened.
 352          * clockTime: is the time when set_time was last called.
 353          */
 354         while (!got_sigintterm) {
 355                 int timeDiff;
 356                 enum timejump wakeupKind;
 357 
 358                 /* ... wait for the time (in minutes) to change ... */
 359                 do {
 360                         cron_sleep(timeRunning + 1, &database);
 361                         set_time(FALSE);
 362                 } while (!got_sigintterm && clockTime == timeRunning);
 363                 if (got_sigintterm)
 364                         break;
 365                 timeRunning = clockTime;
 366 
 367                 /*
 368                  * Calculate how the current time differs from our virtual
 369                  * clock.  Classify the change into one of 4 cases.
 370                  */
 371                 timeDiff = timeRunning - virtualTime;
 372                 check_orphans(&database);
 373 #if defined WITH_INOTIFY
 374                 if (inotify_enabled) {
 375                         check_inotify_database(&database);
 376                 }
 377                 else {
 378                         if (load_database(&database) && (EnableClustering != 1))
 379                                 /* try reinstating the watches */
 380                                 set_cron_watched(fd);
 381                 }
 382 #else
 383                 load_database(&database);
 384 #endif
 385 
 386                 /* shortcut for the most common case */
 387                 if (timeDiff == 1) {
 388                         virtualTime = timeRunning;
 389                         oldGMToff = GMToff;
 390                         find_jobs(virtualTime, &database, TRUE, TRUE, oldGMToff);
 391                 }
 392                 else {
 393                         if (timeDiff > (3 * MINUTE_COUNT) || timeDiff < -(3 * MINUTE_COUNT))
 394                                 wakeupKind = large;
 395                         else if (timeDiff > 5)
 396                                 wakeupKind = medium;
 397                         else if (timeDiff > 0)
 398                                 wakeupKind = small;
 399                         else
 400                                 wakeupKind = negative;
 401 
 402                         switch (wakeupKind) {
 403                         case small:
 404                                 /*
 405                                  * case 1: timeDiff is a small positive number
 406                                  * (wokeup late) run jobs for each virtual
 407                                  * minute until caught up.
 408                                  */
 409                                 Debug(DSCH, ("[%ld], normal case %d minutes to go\n",
 410                                                 (long) pid, timeDiff));
 411                                 do {
 412                                         if (job_runqueue())
 413                                                 sleep(10);
 414                                         virtualTime++;
 415                                         if (virtualTime >= timeRunning)
 416                                                 /* always run also the other timezone jobs in the last step */
 417                                                 oldGMToff = GMToff;
 418                                         find_jobs(virtualTime, &database, TRUE, TRUE, oldGMToff);
 419                                 } while (virtualTime < timeRunning);
 420                                 break;
 421 
 422                         case medium:
 423                                 /*
 424                                  * case 2: timeDiff is a medium-sized positive
 425                                  * number, for example because we went to DST
 426                                  * run wildcard jobs once, then run any
 427                                  * fixed-time jobs that would otherwise be
 428                                  * skipped if we use up our minute (possible,
 429                                  * if there are a lot of jobs to run) go
 430                                  * around the loop again so that wildcard jobs
 431                                  * have a chance to run, and we do our
 432                                  * housekeeping.
 433                                  */
 434                                 Debug(DSCH, ("[%ld], DST begins %d minutes to go\n",
 435                                                 (long) pid, timeDiff));
 436                                 /* run wildcard jobs for current minute */
 437                                 find_jobs(timeRunning, &database, TRUE, FALSE, GMToff);
 438 
 439                                 /* run fixed-time jobs for each minute missed */
 440                                 do {
 441                                         if (job_runqueue())
 442                                                 sleep(10);
 443                                         virtualTime++;
 444                                         if (virtualTime >= timeRunning) 
 445                                                 /* always run also the other timezone jobs in the last step */
 446                                                 oldGMToff = GMToff;
 447                                         find_jobs(virtualTime, &database, FALSE, TRUE, oldGMToff);
 448                                         set_time(FALSE);
 449                                 } while (virtualTime < timeRunning && clockTime == timeRunning);
 450                                 break;
 451 
 452                         case negative:
 453                                 /*
 454                                  * case 3: timeDiff is a small or medium-sized
 455                                  * negative num, eg. because of DST ending.
 456                                  * Just run the wildcard jobs. The fixed-time
 457                                  * jobs probably have already run, and should
 458                                  * not be repeated.  Virtual time does not
 459                                  * change until we are caught up.
 460                                  */
 461                                 Debug(DSCH, ("[%ld], DST ends %d minutes to go\n",
 462                                                 (long) pid, timeDiff));
 463                                 find_jobs(timeRunning, &database, TRUE, FALSE, GMToff);
 464                                 break;
 465                         default:
 466                                 /*
 467                                  * other: time has changed a *lot*,
 468                                  * jump virtual time, and run everything
 469                                  */
 470                                 Debug(DSCH, ("[%ld], clock jumped\n", (long) pid));
 471                                 virtualTime = timeRunning;
 472                                 oldGMToff = GMToff;
 473                                 find_jobs(timeRunning, &database, TRUE, TRUE, GMToff);
 474                         }
 475                 }
 476 
 477                 /* Jobs to be run (if any) are loaded; clear the queue. */
 478                 job_runqueue();
 479 
 480                 handle_signals(&database);
 481         }
 482 
 483 #if defined WITH_INOTIFY
 484         if (inotify_enabled && (EnableClustering != 1))
 485                 set_cron_unwatched(fd);
 486 
 487         if (fd >= 0 && close(fd) < 0)
 488                 log_it("CRON", pid, "INFO", "Inotify close failed", errno);
 489 #endif
 490 
 491         log_it("CRON", pid, "INFO", "Shutting down", 0);
 492 
 493         (void) unlink(_PATH_CRON_PID);
 494 
 495         return 0;
 496 }
 497 
 498 static void run_reboot_jobs(cron_db * db) {
     /* [previous][next][first][last][top][bottom][index][help]  */
 499         user *u;
 500         entry *e;
 501         int reboot;
 502         pid_t pid = getpid();
 503 
 504         /* lock exist - skip reboot jobs */
 505         if (access(REBOOT_LOCK, F_OK) == 0) {
 506                 log_it("CRON", pid, "INFO",
 507                         "@reboot jobs will be run at computer's startup.", 0);
 508                 return;
 509         }
 510         /* lock doesn't exist - create lock, run reboot jobs */
 511         if ((reboot = creat(REBOOT_LOCK, S_IRUSR & S_IWUSR)) < 0)
 512                 log_it("CRON", pid, "INFO", "Can't create lock for reboot jobs.",
 513                         errno);
 514         else
 515                 close(reboot);
 516 
 517         for (u = db->head; u != NULL; u = u->next) {
 518                 for (e = u->crontab; e != NULL; e = e->next) {
 519                         if (e->flags & WHEN_REBOOT)
 520                                 job_add(e, u);
 521                 }
 522         }
 523         (void) job_runqueue();
 524 }
 525 
 526 static void find_jobs(int vtime, cron_db * db, int doWild, int doNonWild, long vGMToff) {
     /* [previous][next][first][last][top][bottom][index][help]  */
 527         char *orig_tz, *job_tz;
 528         struct tm *tm;
 529         int minute, hour, dom, month, dow;
 530         user *u;
 531         entry *e;
 532 
 533         /* The support for the job-specific timezones is not perfect. There will
 534          * be jobs missed or run twice during the DST change in the job timezone.
 535          * It is recommended not to schedule any jobs during the hour when
 536          * the DST changes happen if job-specific timezones are used.
 537          *
 538          * Make 0-based values out of tm values so we can use them as indicies
 539          */
 540 #define maketime(tz1, tz2) do { \
 541         char *t = tz1; \
 542         if (t != NULL && *t != '\0') { \
 543                 setenv("TZ", t, 1); \
 544                 tm = localtime(&virtualGMTSecond); \
 545         } else { if ((tz2) != NULL) \
 546                         setenv("TZ", (tz2), 1); \
 547                 else \
 548                         unsetenv("TZ"); \
 549                 tm = gmtime(&virtualSecond); \
 550         } \
 551         minute = tm->tm_min -FIRST_MINUTE; \
 552         hour = tm->tm_hour -FIRST_HOUR; \
 553         dom = tm->tm_mday -FIRST_DOM; \
 554         month = tm->tm_mon +1 /* 0..11 -> 1..12 */ -FIRST_MONTH; \
 555         dow = tm->tm_wday -FIRST_DOW; \
 556         } while (0)
 557 
 558         orig_tz = getenv("TZ");
 559 
 560         /* the dom/dow situation is odd.  '* * 1,15 * Sun' will run on the
 561          * first and fifteenth AND every Sunday;  '* * * * Sun' will run *only*
 562          * on Sundays;  '* * 1,15 * *' will run *only* the 1st and 15th.  this
 563          * is why we keep 'e->dow_star' and 'e->dom_star'.  yes, it's bizarre.
 564          * like many bizarre things, it's the standard.
 565          */
 566         for (u = db->head; u != NULL; u = u->next) {
 567                 for (e = u->crontab; e != NULL; e = e->next) {
 568                         time_t virtualSecond = (time_t)(vtime - e->delay) * (time_t)SECONDS_PER_MINUTE;
 569                         time_t virtualGMTSecond = virtualSecond - vGMToff;
 570                         job_tz = env_get("CRON_TZ", e->envp);
 571                         maketime(job_tz, orig_tz);
 572 
 573                         /* here we test whether time is NOW */
 574                         if (bit_test(e->minute, minute) &&
 575                                 bit_test(e->hour, hour) &&
 576                                 bit_test(e->month, month) &&
 577                                 (((e->flags & DOM_STAR) || (e->flags & DOW_STAR))
 578                                         ? (bit_test(e->dow, dow) && bit_test(e->dom, dom))
 579                                                 : (bit_test(e->dow, dow) || bit_test(e->dom, dom))
 580                                 )
 581                         ) {
 582                                 if (job_tz != NULL && vGMToff != GMToff)
 583                                         /* do not try to run the jobs from different timezones
 584                                          * during the DST switch of the default timezone.
 585                                          */
 586                                         continue;
 587 
 588                                 if ((doNonWild &&
 589                                                 !(e->flags & (MIN_STAR | HR_STAR))) ||
 590                                         (doWild && (e->flags & (MIN_STAR | HR_STAR))))
 591                                         job_add(e, u);  /*will add job, if it isn't in queue already for NOW. */
 592                         }
 593                 }
 594         }
 595         if (orig_tz != NULL)
 596                 setenv("TZ", orig_tz, 1);
 597         else
 598                 unsetenv("TZ");
 599 }
 600 
 601 /*
 602  * Set StartTime and clockTime to the current time.
 603  * These are used for computing what time it really is right now.
 604  * Note that clockTime is a unix wallclock time converted to minutes.
 605  */
 606 static void set_time(int initialize) {
     /* [previous][next][first][last][top][bottom][index][help]  */
 607         struct tm tm;
 608         static int isdst;
 609 
 610         StartTime = time(NULL);
 611 
 612         /* We adjust the time to GMT so we can catch DST changes. */
 613         tm = *localtime(&StartTime);
 614         if (initialize || tm.tm_isdst != isdst) {
 615                 isdst = tm.tm_isdst;
 616                 GMToff = get_gmtoff(&StartTime, &tm);
 617                 Debug(DSCH, ("[%ld] GMToff=%ld\n", (long) getpid(), (long) GMToff));
 618         }
 619         clockTime = (int)((StartTime + GMToff) / (time_t) SECONDS_PER_MINUTE);
 620 }
 621 
 622 /*
 623  * Try to just hit the next minute.
 624  */
 625 static void cron_sleep(int target, cron_db * db) {
     /* [previous][next][first][last][top][bottom][index][help]  */
 626         time_t t1, t2;
 627         int seconds_to_wait;
 628 
 629         t1 = time(NULL) + GMToff;
 630         seconds_to_wait = (int) (target * SECONDS_PER_MINUTE - t1) + 1;
 631         Debug(DSCH, ("[%ld] Target time=%ld, sec-to-wait=%d\n",
 632                         (long) getpid(), (long) target * SECONDS_PER_MINUTE,
 633                         seconds_to_wait));
 634 
 635         while (seconds_to_wait > 0 && seconds_to_wait < 65) {
 636                 sleep((unsigned int) seconds_to_wait);
 637 
 638                 if (got_sigintterm)
 639                         return;
 640 
 641                 /*
 642                  * Check to see if we were interrupted by a signal.
 643                  * If so, service the signal(s) then continue sleeping
 644                  * where we left off.
 645                  */
 646                 handle_signals(db);
 647 
 648                 t2 = time(NULL) + GMToff;
 649                 seconds_to_wait -= (int) (t2 - t1);
 650                 t1 = t2;
 651         }
 652 }
 653 
 654 static void sighup_handler(int x) {
     /* [previous][next][first][last][top][bottom][index][help]  */
 655         got_sighup = 1;
 656 }
 657 
 658 static void sigchld_handler(int x) {
     /* [previous][next][first][last][top][bottom][index][help]  */
 659         got_sigchld = 1;
 660 }
 661 
 662 static void sigintterm_handler(int x) {
     /* [previous][next][first][last][top][bottom][index][help]  */
 663         got_sigintterm = 1;
 664 }
 665 
 666 static void sigchld_reaper(void) {
     /* [previous][next][first][last][top][bottom][index][help]  */
 667         WAIT_T waiter;
 668         PID_T pid;
 669 
 670         do {
 671                 pid = waitpid(-1, &waiter, WNOHANG);
 672                 switch (pid) {
 673                 case -1:
 674                         if (errno == EINTR)
 675                                 continue;
 676                         Debug(DPROC, ("[%ld] sigchld...no children\n", (long) getpid()));
 677                         break;
 678                 case 0:
 679                         Debug(DPROC, ("[%ld] sigchld...no dead kids\n", (long) getpid()));
 680                         break;
 681                 default:
 682                         Debug(DPROC,
 683                                 ("[%ld] sigchld...pid #%ld died, stat=%d\n",
 684                                         (long) getpid(), (long) pid, WEXITSTATUS(waiter)));
 685                         break;
 686                 }
 687         } while (pid > 0);
 688 }
 689 
 690 static void parse_args(int argc, char *argv[]) {
     /* [previous][next][first][last][top][bottom][index][help]  */
 691         int argch;
 692 
 693         while (-1 != (argch = getopt(argc, argv, "hnpsiPx:m:cV"))) {
 694                 switch (argch) {
 695                         case 'x':
 696                                 if (!set_debug_flags(optarg))
 697                                         usage();
 698                                 break;
 699                         case 'n':
 700                                 NoFork = 1;
 701                                 break;
 702                         case 'p':
 703                                 PermitAnyCrontab = 1;
 704                                 break;
 705                         case 's':
 706                                 SyslogOutput = 1;
 707                                 break;
 708                         case 'i':
 709                                 DisableInotify = 1;
 710                                 break;
 711                         case 'P':
 712                                 ChangePath = 0;
 713                                 break;
 714                         case 'm':
 715                                 strncpy(MailCmd, optarg, MAX_COMMAND);
 716                                 break;
 717                         case 'c':
 718                                 EnableClustering = 1;
 719                                 break;
 720                         case 'V':
 721                                 puts(PACKAGE_STRING);
 722                                 exit(EXIT_SUCCESS);
 723                         case 'h':
 724                         default:
 725                                 usage();
 726                                 break;
 727                 }
 728         }
 729 }

/* [previous][next][first][last][top][bottom][index][help]  */