1: /* Copyright 1988,1990,1993,1994 by Paul Vixie
   2:  * All rights reserved
   3:  *
   4:  * Distribute freely, except: don't remove my name from the source or
   5:  * documentation (don't take credit for my work), mark your changes (don't
   6:  * get me blamed for your possible bugs), don't alter or remove this
   7:  * notice.  May be sold if buildable source is provided to buyer.  No
   8:  * warrantee of any kind, express or implied, is included with this
   9:  * software; use at your own risk, responsibility for damages (if any) to
  10:  * anyone resulting from the use of this software rests entirely with the
  11:  * user.
  12:  *
  13:  * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
  14:  * I'll try to keep a version up to date.  I can be reached as follows:
  15:  * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
  16:  */
  17: 
  18: #if !defined(lint) && defined(DOSCCS)
  19: static char sccsid[] = "@(#)cron.c 2.11.1 (2.11BSD) 1999/08/05";
  20: #endif
  21: 
  22: #define MAIN_PROGRAM
  23: 
  24: #include "cron.h"
  25: #include <sys/signal.h>
  26: #include <sys/time.h>
  27: 
  28: static  void    usage __P((void)),
  29:         run_reboot_jobs __P((cron_db *)),
  30:         cron_tick __P((cron_db *)),
  31:         cron_sync __P((void)),
  32:         cron_sleep __P((void)),
  33:         sigchld_handler __P((int)),
  34:         sighup_handler __P((int)),
  35:         parse_args __P((int c, char *v[]));
  36: 
  37: 
  38: static void
  39: usage() {
  40:     fprintf(stderr, "usage:  %s [-x debugflag[,...]]\n", ProgramName);
  41:     exit(ERROR_EXIT);
  42: }
  43: 
  44: 
  45: int
  46: main(argc, argv)
  47:     int argc;
  48:     char    *argv[];
  49: {
  50:     cron_db database;
  51: 
  52:     ProgramName = argv[0];
  53: 
  54:     setlinebuf(stdout);
  55:     setlinebuf(stderr);
  56: 
  57:     parse_args(argc, argv);
  58: 
  59:     (void) signal(SIGCHLD, sigchld_handler);
  60:     (void) signal(SIGHUP, sighup_handler);
  61: 
  62:     acquire_daemonlock(0);
  63:     set_cron_uid();
  64:     set_cron_cwd();
  65: 
  66:     setenv("PATH", _PATH_DEFPATH, 1);
  67: 
  68:     /* if there are no debug flags turned on, fork as a daemon should.
  69: 	 */
  70: # if DEBUGGING
  71:     if (DebugFlags) {
  72: # else
  73:     if (0) {
  74: # endif
  75:         (void) fprintf(stderr, "[%d] cron started\n", getpid());
  76:     } else {
  77:         switch (fork()) {
  78:         case -1:
  79:             log_it("CRON",getpid(),"DEATH","can't fork");
  80:             exit(0);
  81:             break;
  82:         case 0:
  83:             /* child process */
  84:             log_it("CRON",getpid(),"STARTUP","fork ok");
  85:             (void) setsid();
  86:             break;
  87:         default:
  88:             /* parent process should just die */
  89:             _exit(0);
  90:         }
  91:     }
  92: 
  93:     acquire_daemonlock(0);
  94:     database.head = NULL;
  95:     database.tail = NULL;
  96:     database.mtime = (time_t) 0;
  97:     load_database(&database);
  98:     run_reboot_jobs(&database);
  99:     cron_sync();
 100:     while (TRUE) {
 101: # if DEBUGGING
 102:         if (!(DebugFlags & DTEST))
 103: # endif /*DEBUGGING*/
 104:             cron_sleep();
 105: 
 106:         load_database(&database);
 107: 
 108:         /* do this iteration
 109: 		 */
 110:         cron_tick(&database);
 111: 
 112:         /* sleep 1 minute
 113: 		 */
 114:         TargetTime += 60;
 115:     }
 116: }
 117: 
 118: 
 119: static void
 120: run_reboot_jobs(db)
 121:     cron_db *db;
 122: {
 123:     register user       *u;
 124:     register entry      *e;
 125: 
 126:     for (u = db->head;  u != NULL;  u = u->next) {
 127:         for (e = u->crontab;  e != NULL;  e = e->next) {
 128:             if (e->flags & WHEN_REBOOT) {
 129:                 job_add(e, u);
 130:             }
 131:         }
 132:     }
 133:     (void) job_runqueue();
 134: }
 135: 
 136: 
 137: static void
 138: cron_tick(db)
 139:     cron_db *db;
 140: {
 141:     register struct tm  *tm = localtime(&TargetTime);
 142:     register int        minute, hour, dom, month, dow;
 143:     register user       *u;
 144:     register entry      *e;
 145: 
 146:     /* make 0-based values out of these so we can use them as indicies
 147: 	 */
 148:     minute = tm->tm_min -FIRST_MINUTE;
 149:     hour = tm->tm_hour -FIRST_HOUR;
 150:     dom = tm->tm_mday -FIRST_DOM;
 151:     month = tm->tm_mon +1 /* 0..11 -> 1..12 */ -FIRST_MONTH;
 152:     dow = tm->tm_wday -FIRST_DOW;
 153: 
 154:     Debug(DSCH, ("[%d] tick(%d,%d,%d,%d,%d)\n",
 155:         getpid(), minute, hour, dom, month, dow))
 156: 
 157:     /* the dom/dow situation is odd.  '* * 1,15 * Sun' will run on the
 158: 	 * first and fifteenth AND every Sunday;  '* * * * Sun' will run *only*
 159: 	 * on Sundays;  '* * 1,15 * *' will run *only* the 1st and 15th.  this
 160: 	 * is why we keep 'e->dow_star' and 'e->dom_star'.  yes, it's bizarre.
 161: 	 * like many bizarre things, it's the standard.
 162: 	 */
 163:     for (u = db->head;  u != NULL;  u = u->next) {
 164:         for (e = u->crontab;  e != NULL;  e = e->next) {
 165:             Debug(DSCH|DEXT, ("user [%s:%d:%d:...] cmd=\"%s\"\n",
 166:                       env_get("LOGNAME", e->envp),
 167:                       e->uid, e->gid, e->cmd))
 168:             if (bit_test(e->minute, minute)
 169:              && bit_test(e->hour, hour)
 170:              && bit_test(e->month, month)
 171:              && ( ((e->flags & DOM_STAR) || (e->flags & DOW_STAR))
 172:                   ? (bit_test(e->dow,dow) && bit_test(e->dom,dom))
 173:                   : (bit_test(e->dow,dow) || bit_test(e->dom,dom))
 174:                 )
 175:                ) {
 176:                 job_add(e, u);
 177:             }
 178:         }
 179:     }
 180: }
 181: 
 182: 
 183: /* the task here is to figure out how long it's going to be until :00 of the
 184:  * following minute and initialize TargetTime to this value.  TargetTime
 185:  * will subsequently slide 60 seconds at a time, with correction applied
 186:  * implicitly in cron_sleep().  it would be nice to let cron execute in
 187:  * the "current minute" before going to sleep, but by restarting cron you
 188:  * could then get it to execute a given minute's jobs more than once.
 189:  * instead we have the chance of missing a minute's jobs completely, but
 190:  * that's something sysadmin's know to expect what with crashing computers..
 191:  */
 192: static void
 193: cron_sync() {
 194:     register struct tm  *tm;
 195: 
 196:     TargetTime = time((time_t*)0);
 197:     tm = localtime(&TargetTime);
 198:     TargetTime += (60 - tm->tm_sec);
 199: }
 200: 
 201: 
 202: static void
 203: cron_sleep() {
 204:     register int    seconds_to_wait;
 205: 
 206:     do {
 207:         seconds_to_wait = (int) (TargetTime - time((time_t*)0));
 208:         Debug(DSCH, ("[%d] TargetTime=%ld, sec-to-wait=%d\n",
 209:             getpid(), TargetTime, seconds_to_wait))
 210: 
 211:         /* if we intend to sleep, this means that it's finally
 212: 		 * time to empty the job queue (execute it).
 213: 		 *
 214: 		 * if we run any jobs, we'll probably screw up our timing,
 215: 		 * so go recompute.
 216: 		 *
 217: 		 * note that we depend here on the left-to-right nature
 218: 		 * of &&, and the short-circuiting.
 219: 		 */
 220:     } while (seconds_to_wait > 0 && job_runqueue());
 221: 
 222:     while (seconds_to_wait > 0) {
 223:         Debug(DSCH, ("[%d] sleeping for %d seconds\n",
 224:             getpid(), seconds_to_wait))
 225:         seconds_to_wait = (int) sleep((unsigned int) seconds_to_wait);
 226:     }
 227: }
 228: 
 229: 
 230: static void
 231: sigchld_handler(x) {
 232:     WAIT_T      waiter;
 233:     PID_T       pid;
 234: 
 235:     for (;;) {
 236:         pid = waitpid(-1, &waiter, WNOHANG);
 237:         switch (pid) {
 238:         case -1:
 239:             Debug(DPROC,
 240:                 ("[%d] sigchld...no children\n", getpid()))
 241:             return;
 242:         case 0:
 243:             Debug(DPROC,
 244:                 ("[%d] sigchld...no dead kids\n", getpid()))
 245:             return;
 246:         default:
 247:             Debug(DPROC,
 248:                 ("[%d] sigchld...pid #%d died, stat=%d\n",
 249:                 getpid(), pid, WEXITSTATUS(waiter)))
 250:         }
 251:     }
 252: }
 253: 
 254: static void
 255: sighup_handler(x) {
 256:     log_close();
 257: }
 258: 
 259: 
 260: static void
 261: parse_args(argc, argv)
 262:     int argc;
 263:     char    *argv[];
 264: {
 265:     int argch;
 266: 
 267:     while (EOF != (argch = getopt(argc, argv, "x:"))) {
 268:         switch (argch) {
 269:         default:
 270:             usage();
 271:         case 'x':
 272:             if (!set_debug_flags(optarg))
 273:                 usage();
 274:             break;
 275:         }
 276:     }
 277: }

Defined functions

cron_sleep defined in line 202; used 1 times
cron_sync defined in line 192; used 1 times
  • in line 99
cron_tick defined in line 137; used 1 times
main defined in line 45; never used
parse_args defined in line 260; used 1 times
  • in line 57
run_reboot_jobs defined in line 119; used 1 times
  • in line 98
sigchld_handler defined in line 230; used 1 times
  • in line 59
sighup_handler defined in line 254; used 1 times
  • in line 60
usage defined in line 38; used 2 times

Defined variables

sccsid defined in line 19; never used

Defined macros

MAIN_PROGRAM defined in line 22; never used
Last modified: 1999-08-06
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3439
Valid CSS Valid XHTML 1.0 Strict