home *** CD-ROM | disk | FTP | other *** search
/ Nebula / nebula.bin / SourceCode / CronVixie2.1 / crond.c < prev    next >
C/C++ Source or Header  |  1992-01-14  |  7KB  |  318 lines

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