Exemple #1
0
int
main(int argc, char *argv[]) {
	int exitstatus;

	setprogname(argv[0]);
	Pid = getpid();
	(void)setlocale(LC_ALL, "");

	euid = geteuid();
	egid = getegid();
	ruid = getuid();
	rgid = getgid();

	if (euid == ruid && ruid != 0)
		errx(ERROR_EXIT, "Not installed setuid root");

	(void)setvbuf(stderr, NULL, _IOLBF, 0);
	parse_args(argc, argv);		/* sets many globals, opens a file */
	set_cron_cwd();
	if (!allowed(RealUser, CRON_ALLOW, CRON_DENY)) {
		(void)fprintf(stderr,
			"You `%s' are not allowed to use this program `%s'\n",
			User, getprogname());
		(void)fprintf(stderr, "See crontab(1) for more information\n");
		log_it(RealUser, Pid, "AUTH", "crontab command not allowed");
		exit(ERROR_EXIT);
	}
	exitstatus = OK_EXIT;
	switch (Option) {
	case opt_unknown:
		usage("unrecognized option");
		exitstatus = ERROR_EXIT;
		break;
	case opt_list:
		list_cmd();
		break;
	case opt_delete:
		delete_cmd();
		break;
	case opt_edit:
		edit_cmd();
		break;
	case opt_replace:
		if (replace_cmd() < 0)
			exitstatus = ERROR_EXIT;
		break;
	default:
		abort();
	}
	exit(exitstatus);
	/*NOTREACHED*/
}
Exemple #2
0
int
main (int argc, char *argv[])
{
  int exitstatus;
  char *config_file;		/* Name of our configuration file;  NULL if none */

  Pid = getpid ();
  ProgramName = argv[0];

#if defined(POSIX)
  setlocale (LC_ALL, "");
#endif

#if HAVE_SETLINEBUF
  setlinebuf (stderr);
#endif /*HAVE_SETLINEBUF */
  parse_args (argc, argv, &config_file);	/* sets many globals, opens a file */

  read_config (config_file, &allow_only_root, &log_syslog, &allow_file,
	       &deny_file, &crondir, &spool_dir, &log_file, &syscrontab,
	       &lastrun_file, &pidfile, &mailprog, &mailargs);

  set_cron_cwd ();
  if (!allowed (User))
    {
      fprintf (stderr,
	       "You (%s) are not allowed to use this program (%s)\n",
	       User, ProgramName);
      fprintf (stderr, "See crontab(1) for more information\n");
      log_it (RealUser, Pid, "AUTH", "crontab command not allowed");
      exit (ERROR_EXIT);
    }
  exitstatus = OK_EXIT;
  switch (Option)
    {
    case opt_list:
      list_cmd ();
      break;
    case opt_delete:
      delete_cmd ();
      break;
    case opt_edit:
      edit_cmd ();
      break;
    case opt_replace:
      if (replace_cmd () < 0)
	exitstatus = ERROR_EXIT;
      break;
    }
  exit (0);
 /*NOTREACHED*/}
Exemple #3
0
int
main(int argc, char *argv[])
{
	int	exitstatus;

	Pid = getpid();
	ProgramName = argv[0];

#if defined(POSIX)
	setlocale(LC_ALL, "");
#endif

#if defined(BSD)
	setlinebuf(stderr);
#endif
	parse_args(argc, argv);		/* sets many globals, opens a file */
	set_cron_uid();
	set_cron_cwd();
	if (!allowed(User)) {
		warnx("you (%s) are not allowed to use this program", User);
		log_it(RealUser, Pid, "AUTH", "crontab command not allowed");
		exit(ERROR_EXIT);
	}
	exitstatus = OK_EXIT;
	switch (Option) {
	case opt_list:		list_cmd();
				break;
	case opt_delete:	delete_cmd();
				break;
	case opt_edit:		edit_cmd();
				break;
	case opt_replace:	if (replace_cmd() < 0)
					exitstatus = ERROR_EXIT;
				break;
	case opt_unknown:
				break;
	}
	exit(exitstatus);
	/*NOTREACHED*/
}
Exemple #4
0
int
main (int argc, char *argv[])
{
  cron_db database;
  char *config_file;		/*Name of our configuration file; NULL if none */
  struct sigaction my_sigaction;

  /* We need to put Program_Name in its own storage because later we will
   * modify argv[0] in an attempt to change the process name.
   */
  ProcessName = argv[0];
  ProgramName = strdup (argv[0]);

#if HAVE_SETLINEBUF
  setlinebuf (stdout);
  setlinebuf (stderr);
#endif /*HAVE_SETLINEBUF */

  parse_args (argc, argv, &pass_environment, &config_file);

  read_config (config_file, &allow_only_root, &log_syslog, &allow_file,
	       &deny_file, &crondir, &spool_dir, &log_file, &syscrontab,
	       &lastrun_file, &pidfile, &mailprog, &mailargs);

#ifdef USE_SIGCHLD
  memset (&my_sigaction, 0, sizeof (my_sigaction));
  my_sigaction.sa_handler = sigchld_handler;
  my_sigaction.sa_flags |= SA_NOCLDSTOP | SA_NODEFER;
  if (sigaction (SIGCHLD, &my_sigaction, NULL))
    perror ("sigaction");
#else
  (void) signal (SIGCHLD, SIG_IGN);
#endif

  memset (&my_sigaction, 0, sizeof (my_sigaction));
  my_sigaction.sa_handler = sigterm_handler;
  if (sigaction (SIGTERM, &my_sigaction, NULL))
    perror ("sigaction");

  memset (&my_sigaction, 0, sizeof (my_sigaction));
  my_sigaction.sa_handler = sighup_handler;
  if (sigaction (SIGHUP, &my_sigaction, NULL))
    perror ("sigaction");

  acquire_daemonlock (0);
  set_cron_uid ();
  set_cron_cwd ();

#if HAVE_SETENV
  if (!pass_environment)
    setenv ("PATH", _PATH_DEFPATH, 1);
#endif

  /* if there are no debug flags turned on, fork as a daemon should. */

#if DEBUGGING
  if (DebugFlags)
    {
#else
  if (0)
    {
#endif
      (void) fprintf (stderr, "[%d] cron started\n", getpid ());
    }
  else
    {
      switch (fork ())
	{
	case -1:
	  log_it ("CRON", getpid (), "DEATH", "can't fork");
	  exit (0);
	  break;
	case 0:
	  /* child process */
	  log_it ("CRON", getpid (), "STARTUP", "fork ok");
	  (void) setsid ();
	  break;
	default:
	  /* parent process should just die */
	  _exit (0);
	}
    }

  acquire_daemonlock (0);

  /* initialize waiting for busy disk */
  init_diskload ();

  database.head = NULL;
  database.tail = NULL;
  database.mtime = (time_t) 0;

  Debug (DMISC, ("about to load database"));
  load_database (&database);
  Debug (DMISC, ("about to build catch up list"));
  build_cu_list (&database, &CatchUpList);
  Debug (DMISC, ("about to run reboot jobs"));
  run_reboot_jobs (&database);

  while (TRUE)
    {
      cron_sync (); 
# if DEBUGGING
      if (!(DebugFlags & DTEST))
# endif	 /*DEBUGGING*/
	  cron_sleep ();

      load_database (&database);

      /* first catch up any jobs that are on the CatchUpList */
      if (CatchUpList && (!jhead))
	CatchUpList = run_cu_list (CatchUpList);
      /* then run the regular jobs for this minute */
      cron_tick (&database);
    }
}


static void
run_reboot_jobs (cron_db * db)
{
  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, u);
	    }
	}
    }
  (void) job_runqueue ();
}


static void
cron_tick (cron_db * db)
{
  register struct tm *tm = localtime (&TargetTime);
  register 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)
    {
      for (e = u->crontab; e != NULL; e = e->next)
	{
	  Debug (DSCH | DEXT, ("user [%s:%d:%d:...] cmd=\"%s\"\n",
			       env_get ("LOGNAME", e->envp),
			       e->uid, e->gid, 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, 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 cron 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..
 * 
 * Patch from <*****@*****.**>:
 *   Do cron_sync() before each cron_sleep(), to handle changes to the system
 *   time.
 */
static void
cron_sync (void)
{
  register struct tm *tm;

  TargetTime = time ((time_t *) 0);
  tm = localtime (&TargetTime);
  TargetTime += (60 - tm->tm_sec);
}


static void
cron_sleep (void)
{
  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 ());

  while (seconds_to_wait > 0)
    {
      Debug (DSCH, ("[%d] sleeping for %d seconds\n",
		    getpid (), seconds_to_wait));
      seconds_to_wait = (int) sleep ((unsigned int) seconds_to_wait);
    }
}


#ifdef USE_SIGCHLD
static RETSIGTYPE
sigchld_handler (int x)
{
  WAIT_T waiter;
  pid_t pid;

  for (;;)
    {
#if 1
      pid = waitpid (-1, &waiter, WNOHANG);
#else
      pid = wait3 (&waiter, WNOHANG, (struct rusage *) 0);
#endif
      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, WEXITSTATUS (waiter)));
	  save_lastrun (CatchUpList);
	}
    }
}
Exemple #5
0
int
main(int argc, char *argv[]) {
	struct sigaction sact;
	cron_db	database;

	setprogname(argv[0]);
	(void)setlocale(LC_ALL, "");

	(void)setvbuf(stdout, NULL, _IOLBF, 0);
	(void)setvbuf(stderr, NULL, _IOLBF, 0);

	NoFork = 0;
	parse_args(argc, argv);

	(void)memset(&sact, 0, sizeof sact);
	(void)sigemptyset(&sact.sa_mask);
	sact.sa_flags = 0;
#ifdef SA_RESTART
	sact.sa_flags |= SA_RESTART;
#endif
	sact.sa_handler = sigchld_handler;
	(void) sigaction(SIGCHLD, &sact, NULL);
	sact.sa_handler = sighup_handler;
	(void) sigaction(SIGHUP, &sact, NULL);
	sact.sa_handler = quit;
	(void) sigaction(SIGINT, &sact, NULL);
	(void) sigaction(SIGTERM, &sact, NULL);

	acquire_daemonlock(0);
	set_cron_uid();
	set_cron_cwd();

	if (setenv("PATH", _PATH_DEFPATH, 1) < 0) {
		log_it("CRON", getpid(), "DEATH", "can't malloc");
		exit(1);
	}

	/* if there are no debug flags turned on, fork as a daemon should.
	 */
	if (DebugFlags) {
#if DEBUGGING
		(void)fprintf(stderr, "[%ld] cron started\n", (long)getpid());
#endif
	} else if (NoFork == 0) {
		if (daemon(1, 0)) {
			log_it("CRON",getpid(),"DEATH","can't fork");
			exit(1);
		}
	}

	acquire_daemonlock(0);
	database.head = NULL;
	database.tail = NULL;
	database.mtime = (time_t) 0;
	load_database(&database);
	set_time(TRUE);
	run_reboot_jobs(&database);
	timeRunning = virtualTime = clockTime;

	/*
	 * Too many clocks, not enough time (Al. Einstein)
	 * These clocks are in minutes since the epoch, adjusted for timezone.
	 * virtualTime: is the time it *would* be if we woke up
	 * promptly and nobody ever changed the clock. It is
	 * monotonically increasing... unless a timejump happens.
	 * At the top of the loop, all jobs for 'virtualTime' have run.
	 * timeRunning: is the time we last awakened.
	 * clockTime: is the time when set_time was last called.
	 */
	for (;;) {
		int timeDiff;
		enum timejump wakeupKind;

		/* ... wait for the time (in minutes) to change ... */
		do {
			cron_sleep(timeRunning + 1);
			set_time(FALSE);
		} while (clockTime == timeRunning);
		timeRunning = clockTime;

		/*
		 * Calculate how the current time differs from our virtual
		 * clock.  Classify the change into one of 4 cases.
		 */
		timeDiff = timeRunning - virtualTime;

		/* shortcut for the most common case */
		if (timeDiff == 1) {
			virtualTime = timeRunning;
			find_jobs(virtualTime, &database, TRUE, TRUE);
		} else {
			if (timeDiff > (3*MINUTE_COUNT) ||
			    timeDiff < -(3*MINUTE_COUNT))
				wakeupKind = large;
			else if (timeDiff > 5)
				wakeupKind = medium;
			else if (timeDiff > 0)
				wakeupKind = small;
			else
				wakeupKind = negative;

			switch (wakeupKind) {
			case small:
				/*
				 * case 1: timeDiff is a small positive number
				 * (wokeup late) run jobs for each virtual
				 * minute until caught up.
				 */
				Debug(DSCH, ("[%ld], normal case %d minutes to go\n",
				    (long)getpid(), timeDiff));
				do {
					if (job_runqueue())
						(void)sleep(10);
					virtualTime++;
					find_jobs(virtualTime, &database,
					    TRUE, TRUE);
				} while (virtualTime < timeRunning);
				break;

			case medium:
				/*
				 * case 2: timeDiff is a medium-sized positive
				 * number, for example because we went to DST
				 * run wildcard jobs once, then run any
				 * fixed-time jobs that would otherwise be
				 * skipped if we use up our minute (possible,
				 * if there are a lot of jobs to run) go
				 * around the loop again so that wildcard jobs
				 * have a chance to run, and we do our
				 * housekeeping.
				 */
				Debug(DSCH, ("[%ld], DST begins %d minutes to go\n",
				    (long)getpid(), timeDiff));
				/* run wildcard jobs for current minute */
				find_jobs(timeRunning, &database, TRUE, FALSE);
	
				/* run fixed-time jobs for each minute missed */
				do {
					if (job_runqueue())
						(void)sleep(10);
					virtualTime++;
					find_jobs(virtualTime, &database,
					    FALSE, TRUE);
					set_time(FALSE);
				} while (virtualTime < timeRunning &&
				    clockTime == timeRunning);
				break;
	
			case negative:
				/*
				 * case 3: timeDiff is a small or medium-sized
				 * negative num, eg. because of DST ending.
				 * Just run the wildcard jobs. The fixed-time
				 * jobs probably have already run, and should
				 * not be repeated.  Virtual time does not
				 * change until we are caught up.
				 */
				Debug(DSCH, ("[%ld], DST ends %d minutes to go\n",
				    (long)getpid(), timeDiff));
				find_jobs(timeRunning, &database, TRUE, FALSE);
				break;
			default:
				/*
				 * other: time has changed a *lot*,
				 * jump virtual time, and run everything
				 */
				Debug(DSCH, ("[%ld], clock jumped\n",
				    (long)getpid()));
				virtualTime = timeRunning;
				find_jobs(timeRunning, &database, TRUE, TRUE);
			}
		}

		/* Jobs to be run (if any) are loaded; clear the queue. */
		(void)job_runqueue();

		/* Check to see if we received a signal while running jobs. */
		if (got_sighup) {
			got_sighup = 0;
			log_close();
		}
		if (got_sigchld) {
			got_sigchld = 0;
			sigchld_reaper();
		}
		load_database(&database);
	}
}