ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/src/trunk/usr.sbin/cron/cron/cron.c
(Generate patch)

Comparing trunk/usr.sbin/cron/cron/cron.c (file contents):
Revision 10826 by laffer1, Fri Dec 20 23:33:19 2013 UTC vs.
Revision 10827 by laffer1, Sun Jun 10 20:31:17 2018 UTC

# Line 1 | Line 1
1 + /* $MidnightBSD$ */
2   /* Copyright 1988,1990,1993,1994 by Paul Vixie
3   * All rights reserved
4   *
# Line 13 | Line 14
14   * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
15   * I'll try to keep a version up to date.  I can be reached as follows:
16   * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
16 * $FreeBSD: src/usr.sbin/cron/cron/cron.c,v 1.15.8.1 2006/01/15 17:50:36 delphij Exp $
17   */
18  
19   #if !defined(lint) && !defined(LINT)
20   static const char rcsid[] =
21 <  "$MidnightBSD: src/usr.sbin/cron/cron/cron.c,v 1.2 2007/08/18 06:59:04 laffer1 Exp $";
21 >  "$FreeBSD: stable/10/usr.sbin/cron/cron/cron.c 321237 2017-07-19 19:41:13Z ngie $";
22   #endif
23  
24   #define MAIN_PROGRAM
# Line 36 | Line 36 | static const char rcsid[] =
36  
37   static  void    usage(void),
38                  run_reboot_jobs(cron_db *),
39 <                cron_tick(cron_db *),
40 <                cron_sync(void),
41 <                cron_sleep(cron_db *),
39 >                cron_tick(cron_db *, int),
40 >                cron_sync(int),
41 >                cron_sleep(cron_db *, int),
42                  cron_clean(cron_db *),
43   #ifdef USE_SIGCHLD
44                  sigchld_handler(int),
# Line 46 | Line 46 | static void    usage(void),
46                  sighup_handler(int),
47                  parse_args(int c, char *v[]);
48  
49 + static int      run_at_secres(cron_db *);
50 +
51   static time_t   last_time = 0;
52   static int      dst_enabled = 0;
53 + static int      dont_daemonize = 0;
54   struct pidfh *pfh;
55  
56   static void
57   usage() {
58 + #if DEBUGGING
59      char **dflags;
60 + #endif
61  
62          fprintf(stderr, "usage: cron [-j jitter] [-J rootjitter] "
63 <                        "[-m mailto] [-s] [-o] [-x debugflag[,...]]\n");
63 >                        "[-m mailto] [-n] [-s] [-o] [-x debugflag[,...]]\n");
64 > #if DEBUGGING
65          fprintf(stderr, "\ndebugflags: ");
66  
67          for(dflags = DebugFlagNames; *dflags; dflags++) {
68                  fprintf(stderr, "%s ", *dflags);
69          }
70          fprintf(stderr, "\n");
71 + #endif
72  
73          exit(ERROR_EXIT);
74   }
# Line 95 | Line 102 | main(argc, argv)
102          char    *argv[];
103   {
104          cron_db database;
105 +        int runnum;
106 +        int secres1, secres2;
107 +        struct tm *tm;
108  
109          ProgramName = argv[0];
110  
# Line 128 | Line 138 | main(argc, argv)
138          if (0) {
139   # endif
140                  (void) fprintf(stderr, "[%d] cron started\n", getpid());
141 <        } else {
141 >        } else if (dont_daemonize == 0) {
142                  if (daemon(1, 0) == -1) {
143                          pidfile_remove(pfh);
144                          log_it("CRON",getpid(),"DEATH","can't become daemon");
# Line 144 | Line 154 | main(argc, argv)
154          database.tail = NULL;
155          database.mtime = (time_t) 0;
156          load_database(&database);
157 +        secres1 = secres2 = run_at_secres(&database);
158          run_reboot_jobs(&database);
159 <        cron_sync();
159 >        cron_sync(secres1);
160 >        runnum = 0;
161          while (TRUE) {
162   # if DEBUGGING
163              /* if (!(DebugFlags & DTEST)) */
164   # endif /*DEBUGGING*/
165 <                        cron_sleep(&database);
165 >                        cron_sleep(&database, secres1);
166  
167 <                load_database(&database);
167 >                if (secres1 == 0 || runnum % 60 == 0) {
168 >                        load_database(&database);
169 >                        secres2 = run_at_secres(&database);
170 >                        if (secres2 != secres1) {
171 >                                secres1 = secres2;
172 >                                if (secres1 != 0) {
173 >                                        runnum = 0;
174 >                                } else {
175 >                                        /*
176 >                                         * Going from 1 sec to 60 sec res. If we
177 >                                         * are already at minute's boundary, so
178 >                                         * let it run, otherwise schedule for the
179 >                                         * next minute.
180 >                                         */
181 >                                        tm = localtime(&TargetTime);
182 >                                        if (tm->tm_sec > 0)  {
183 >                                                cron_sync(secres2);
184 >                                                continue;
185 >                                        }
186 >                                }
187 >                        }
188 >                }
189  
190                  /* do this iteration
191                   */
192 <                cron_tick(&database);
192 >                cron_tick(&database, secres1);
193  
194 <                /* sleep 1 minute
194 >                /* sleep 1 or 60 seconds
195                   */
196 <                TargetTime += 60;
196 >                TargetTime += (secres1 != 0) ? 1 : 60;
197 >                runnum += 1;
198          }
199   }
200  
# Line 184 | Line 218 | run_reboot_jobs(db)
218  
219  
220   static void
221 < cron_tick(db)
188 <        cron_db *db;
221 > cron_tick(cron_db *db, int secres)
222   {
223          static struct tm        lasttm;
224          static time_t   diff = 0, /* time difference in seconds from the last offset change */
225                  difflimit = 0; /* end point for the time zone correction */
226          struct tm       otztm; /* time in the old time zone */
227 <        int             otzminute, otzhour, otzdom, otzmonth, otzdow;
227 >        int             otzsecond, otzminute, otzhour, otzdom, otzmonth, otzdow;
228          register struct tm      *tm = localtime(&TargetTime);
229 <        register int            minute, hour, dom, month, dow;
229 >        register int            second, minute, hour, dom, month, dow;
230          register user           *u;
231          register entry          *e;
232  
233          /* make 0-based values out of these so we can use them as indicies
234           */
235 +        second = (secres == 0) ? 0 : tm->tm_sec -FIRST_SECOND;
236          minute = tm->tm_min -FIRST_MINUTE;
237          hour = tm->tm_hour -FIRST_HOUR;
238          dom = tm->tm_mday -FIRST_DOM;
239          month = tm->tm_mon +1 /* 0..11 -> 1..12 */ -FIRST_MONTH;
240          dow = tm->tm_wday -FIRST_DOW;
241  
242 <        Debug(DSCH, ("[%d] tick(%d,%d,%d,%d,%d)\n",
243 <                getpid(), minute, hour, dom, month, dow))
242 >        Debug(DSCH, ("[%d] tick(%d,%d,%d,%d,%d,%d)\n",
243 >                getpid(), second, minute, hour, dom, month, dow))
244  
245          if (dst_enabled && last_time != 0
246          && TargetTime > last_time /* exclude stepping back */
# Line 259 | Line 293 | cron_tick(db)
293  
294                          /* make 0-based values out of these so we can use them as indicies
295                           */
296 +                        otzsecond = (secres == 0) ? 0 : otztm.tm_sec -FIRST_SECOND;
297                          otzminute = otztm.tm_min -FIRST_MINUTE;
298                          otzhour = otztm.tm_hour -FIRST_HOUR;
299                          otzdom = otztm.tm_mday -FIRST_DOM;
# Line 280 | Line 315 | cron_tick(db)
315                                            e->uid, e->gid, e->cmd))
316  
317                          if ( diff != 0 && (e->flags & (RUN_AT|NOT_UNTIL)) ) {
318 <                                if (bit_test(e->minute, otzminute)
318 >                                if (bit_test(e->second, otzsecond)
319 >                                 && bit_test(e->minute, otzminute)
320                                   && bit_test(e->hour, otzhour)
321                                   && bit_test(e->month, otzmonth)
322                                   && ( ((e->flags & DOM_STAR) || (e->flags & DOW_STAR))
# Line 299 | Line 335 | cron_tick(db)
335                                          continue;
336                          }
337  
338 <                        if (bit_test(e->minute, minute)
338 >                        if (bit_test(e->second, second)
339 >                         && bit_test(e->minute, minute)
340                           && bit_test(e->hour, hour)
341                           && bit_test(e->month, month)
342                           && ( ((e->flags & DOM_STAR) || (e->flags & DOW_STAR))
# Line 329 | Line 366 | cron_tick(db)
366   * that's something sysadmin's know to expect what with crashing computers..
367   */
368   static void
369 < cron_sync() {
370 <        register struct tm      *tm;
369 > cron_sync(int secres) {
370 >        struct tm *tm;
371  
372          TargetTime = time((time_t*)0);
373 <        tm = localtime(&TargetTime);
374 <        TargetTime += (60 - tm->tm_sec);
373 >        if (secres != 0) {
374 >                TargetTime += 1;
375 >        } else {
376 >                tm = localtime(&TargetTime);
377 >                TargetTime += (60 - tm->tm_sec);
378 >        }
379   }
380  
381 + static void
382 + timespec_subtract(struct timespec *result, struct timespec *x,
383 +    struct timespec *y)
384 + {
385 +        *result = *x;
386 +        result->tv_sec -= y->tv_sec;
387 +        result->tv_nsec -= y->tv_nsec;
388 +        if (result->tv_nsec < 0) {
389 +                result->tv_sec--;
390 +                result->tv_nsec += 1000000000;
391 +        }
392 + }
393  
394   static void
395 < cron_sleep(db)
343 <        cron_db *db;
395 > cron_sleep(cron_db *db, int secres)
396   {
397 <        int     seconds_to_wait = 0;
397 >        int seconds_to_wait;
398 >        int rval;
399 >        struct timespec ctime, ttime, stime, remtime;
400  
401          /*
402           * Loop until we reach the top of the next minute, sleep when possible.
403           */
404  
405          for (;;) {
406 <                seconds_to_wait = (int) (TargetTime - time((time_t*)0));
406 >                clock_gettime(CLOCK_REALTIME, &ctime);
407 >                ttime.tv_sec = TargetTime;
408 >                ttime.tv_nsec = 0;
409 >                timespec_subtract(&stime, &ttime, &ctime);
410  
411                  /*
412                   * If the seconds_to_wait value is insane, jump the cron
413                   */
414  
415 <                if (seconds_to_wait < -600 || seconds_to_wait > 600) {
415 >                if (stime.tv_sec < -600 || stime.tv_sec > 600) {
416                          cron_clean(db);
417 <                        cron_sync();
417 >                        cron_sync(secres);
418                          continue;
419                  }
420  
421 +                seconds_to_wait = (stime.tv_nsec > 0) ? stime.tv_sec + 1 :
422 +                    stime.tv_sec;
423 +
424                  Debug(DSCH, ("[%d] TargetTime=%ld, sec-to-wait=%d\n",
425                          getpid(), (long)TargetTime, seconds_to_wait))
426  
# Line 369 | Line 429 | cron_sleep(db)
429                   * to run, break
430                   */
431  
432 <                if (seconds_to_wait <= 0)
432 >                if (stime.tv_sec < 0)
433                          break;
434                  if (job_runqueue() == 0) {
435                          Debug(DSCH, ("[%d] sleeping for %d seconds\n",
436                                  getpid(), seconds_to_wait))
437  
438 <                        sleep(seconds_to_wait);
438 >                        for (;;) {
439 >                                rval = nanosleep(&stime, &remtime);
440 >                                if (rval == 0 || errno != EINTR)
441 >                                        break;
442 >                                stime.tv_sec = remtime.tv_sec;
443 >                                stime.tv_nsec = remtime.tv_nsec;
444 >                        }
445                  }
446          }
447   }
# Line 448 | Line 514 | parse_args(argc, argv)
514          int     argch;
515          char    *endp;
516  
517 <        while ((argch = getopt(argc, argv, "j:J:m:osx:")) != -1) {
517 >        while ((argch = getopt(argc, argv, "j:J:m:nosx:")) != -1) {
518                  switch (argch) {
519                  case 'j':
520                          Jitter = strtoul(optarg, &endp, 10);
# Line 465 | Line 531 | parse_args(argc, argv)
531                  case 'm':
532                          defmailto = optarg;
533                          break;
534 +                case 'n':
535 +                        dont_daemonize = 1;
536 +                        break;
537                  case 'o':
538                          dst_enabled = 0;
539                          break;
# Line 481 | Line 550 | parse_args(argc, argv)
550          }
551   }
552  
553 + static int
554 + run_at_secres(cron_db *db)
555 + {
556 +        user *u;
557 +        entry *e;
558 +
559 +        for (u = db->head;  u != NULL;  u = u->next) {
560 +                for (e = u->crontab;  e != NULL;  e = e->next) {
561 +                        if ((e->flags & SEC_RES) != 0)
562 +                                return 1;
563 +                }
564 +        }
565 +        return 0;
566 + }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines