home *** CD-ROM | disk | FTP | other *** search
- #if !defined(lint) && !defined(LINT)
- 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 $";
- #endif
-
- /* Copyright 1988,1990 by Paul Vixie
- * All rights reserved
- *
- * Distribute freely, except: don't remove my name from the source or
- * documentation (don't take credit for my work), mark your changes (don't
- * get me blamed for your possible bugs), don't alter or remove this
- * notice. May be sold if buildable source is provided to buyer. No
- * warrantee of any kind, express or implied, is included with this
- * software; use at your own risk, responsibility for damages (if any) to
- * anyone resulting from the use of this software rests entirely with the
- * user.
- *
- * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
- * I'll try to keep a version up to date. I can be reached as follows:
- * Paul Vixie, 329 Noe Street, San Francisco, CA, 94114, (415) 864-7013,
- * paul@vixie.sf.ca.us || {hoptoad,pacbell,decwrl,crash}!vixie!paul
- */
-
-
- #define MAIN_PROGRAM
-
-
- #include "cron.h"
- #include <sys/time.h>
- #include <sys/signal.h>
- #include <sys/types.h>
- #if defined(BSD)
- # include <sys/wait.h>
- # include <sys/resource.h>
- #endif /*BSD*/
-
- extern int fprintf(), fork(), unlink();
- extern time_t time();
- extern void exit();
- extern unsigned sleep();
-
- void
- usage()
- {
- (void) fprintf(stderr, "usage: %s [-x debugflag[,...]]\n", ProgramName);
- (void) exit(ERROR_EXIT);
- }
-
-
- int
- main(argc, argv)
- int argc;
- char *argv[];
- {
- extern void set_cron_uid(), be_different(), load_database(),
- set_cron_cwd(), open_logfile();
-
- static int sigchld_handler();
- static void cron_tick(), cron_sleep(), cron_sync(),
- parse_args(), run_reboot_jobs();
-
- auto cron_db database;
-
- ProgramName = argv[0];
-
- #if defined(BSD)
- setlinebuf(stdout);
- setlinebuf(stderr);
- #endif
-
- parse_args(argc, argv);
-
- # if DEBUGGING
- /* if there are no debug flags turned on, fork as a daemon should.
- */
- if (DebugFlags)
- {
- (void) fprintf(stderr, "[%d] crond started\n", getpid());
- }
- else
- # endif /*DEBUGGING*/
- {
- switch (fork())
- {
- case -1:
- log_it("CROND",getpid(),"DEATH","can't fork");
- exit(0);
- break;
- case 0:
- /* child process */
- be_different();
- break;
- default:
- /* parent process should just die */
- _exit(0);
- }
- }
-
- #if defined(BSD)
- (void) signal(SIGCHLD, sigchld_handler);
- #endif /*BSD*/
-
- #if defined(ATT)
- (void) signal(SIGCLD, SIG_IGN);
- #endif /*ATT*/
-
- acquire_daemonlock();
- set_cron_uid();
- set_cron_cwd();
- database.head = NULL;
- database.tail = NULL;
- database.mtime = (time_t) 0;
- load_database(&database);
- run_reboot_jobs(&database);
- cron_sync();
- while (TRUE)
- {
- # if DEBUGGING
- if (!(DebugFlags & DTEST))
- # endif /*DEBUGGING*/
- cron_sleep();
-
- load_database(&database);
-
- /* do this iteration
- */
- cron_tick(&database);
-
- /* sleep 1 minute
- */
- TargetTime += 60;
- }
- }
-
-
- static void
- run_reboot_jobs(db)
- cron_db *db;
- {
- extern void job_add();
- extern int job_runqueue();
- register user *u;
- register entry *e;
-
- for (u = db->head; u != NULL; u = u->next) {
- for (e = u->crontab; e != NULL; e = e->next) {
- if (e->flags & WHEN_REBOOT) {
- job_add(e->cmd, u);
- }
- }
- }
- (void) job_runqueue();
- }
-
-
- static void
- cron_tick(db)
- cron_db *db;
- {
- extern void job_add();
- extern char *env_get();
- extern struct tm *localtime();
- register struct tm *tm = localtime(&TargetTime);
- local int minute, hour, dom, month, dow;
- register user *u;
- register entry *e;
-
- /* make 0-based values out of these so we can use them as indicies
- */
- minute = tm->tm_min -FIRST_MINUTE;
- hour = tm->tm_hour -FIRST_HOUR;
- dom = tm->tm_mday -FIRST_DOM;
- month = tm->tm_mon +1 /* 0..11 -> 1..12 */ -FIRST_MONTH;
- dow = tm->tm_wday -FIRST_DOW;
-
- Debug(DSCH, ("[%d] tick(%d,%d,%d,%d,%d)\n",
- getpid(), minute, hour, dom, month, dow))
-
- /* the dom/dow situation is odd. '* * 1,15 * Sun' will run on the
- * first and fifteenth AND every Sunday; '* * * * Sun' will run *only*
- * on Sundays; '* * 1,15 * *' will run *only* the 1st and 15th. this
- * is why we keep 'e->dow_star' and 'e->dom_star'. yes, it's bizarre.
- * like many bizarre things, it's the standard.
- */
- for (u = db->head; u != NULL; u = u->next) {
- Debug(DSCH|DEXT, ("user [%s:%d:%d:...]\n",
- env_get(USERENV,u->envp), u->uid, u->gid))
- for (e = u->crontab; e != NULL; e = e->next) {
- Debug(DSCH|DEXT, ("entry [%s]\n", e->cmd))
- if (bit_test(e->minute, minute)
- && bit_test(e->hour, hour)
- && bit_test(e->month, month)
- && ( ((e->flags & DOM_STAR) || (e->flags & DOW_STAR))
- ? (bit_test(e->dow,dow) && bit_test(e->dom,dom))
- : (bit_test(e->dow,dow) || bit_test(e->dom,dom))
- )
- ) {
- job_add(e->cmd, u);
- }
- }
- }
- }
-
-
- /* the task here is to figure out how long it's going to be until :00 of the
- * following minute and initialize TargetTime to this value. TargetTime
- * will subsequently slide 60 seconds at a time, with correction applied
- * implicitly in cron_sleep(). it would be nice to let crond execute in
- * the "current minute" before going to sleep, but by restarting cron you
- * could then get it to execute a given minute's jobs more than once.
- * instead we have the chance of missing a minute's jobs completely, but
- * that's something sysadmin's know to expect what with crashing computers..
- */
- static void
- cron_sync()
- {
- extern struct tm *localtime();
- register struct tm *tm;
-
- TargetTime = time((time_t*)0);
- tm = localtime(&TargetTime);
- TargetTime += (60 - tm->tm_sec);
- }
-
-
- static void
- cron_sleep()
- {
- extern void do_command();
- extern int job_runqueue();
- register int seconds_to_wait;
-
- do {
- seconds_to_wait = (int) (TargetTime - time((time_t*)0));
- Debug(DSCH, ("[%d] TargetTime=%ld, sec-to-wait=%d\n",
- getpid(), TargetTime, seconds_to_wait))
-
- /* if we intend to sleep, this means that it's finally
- * time to empty the job queue (execute it).
- *
- * if we run any jobs, we'll probably screw up our timing,
- * so go recompute.
- *
- * note that we depend here on the left-to-right nature
- * of &&, and the short-circuiting.
- */
- } while (seconds_to_wait > 0 && job_runqueue());
-
- if (seconds_to_wait > 0)
- {
- Debug(DSCH, ("[%d] sleeping for %d seconds\n",
- getpid(), seconds_to_wait))
- (void) sleep((unsigned int) seconds_to_wait);
- }
- }
-
-
- #if defined(BSD)
- static int
- sigchld_handler()
- {
- static void x_sigchld_handler();
- x_sigchld_handler();
- return 0;
- }
- static void
- x_sigchld_handler()
- {
- union wait waiter;
- int pid;
-
- for (;;)
- {
- pid = wait3(&waiter, WNOHANG, (struct rusage *)0);
- switch (pid)
- {
- case -1:
- Debug(DPROC,
- ("[%d] sigchld...no children\n", getpid()))
- return;
- case 0:
- Debug(DPROC,
- ("[%d] sigchld...no dead kids\n", getpid()))
- return;
- default:
- Debug(DPROC,
- ("[%d] sigchld...pid #%d died, stat=%d\n",
- getpid(), pid, waiter.w_status))
- }
- }
- }
- #endif /*BSD*/
-
-
- static void
- parse_args(argc, argv)
- int argc;
- char *argv[];
- {
- extern int optind, getopt();
- extern void usage();
- extern char *optarg;
-
- int argch;
-
- while (EOF != (argch = getopt(argc, argv, "x:")))
- {
- switch (argch)
- {
- default:
- usage();
- case 'x':
- if (!set_debug_flags(optarg))
- usage();
- break;
- }
- }
- }
-