Minix1.5/commands/cron.c

Compare this file to the similar file:
Show the results in this format:

/* Cron - clock daemon			Author: S.R. Sampson */

/*	Cron is the clock daemon.  It is typically started up from the
 *	/etc/rc file by the line:
 *		/usr/bin/cron
 *	Cron automatically puts itself in the background, so no & is needed.
 *	If cron is used, it runs all day, spending most of its time asleep.
 *	Once a minute it wakes up and examines /usr/lib/crontab to see if there
 *	are any commands to be executed.  The format of this table is the same
 *	as in UNIX, except that % is not allowed to indicate 'new line.'
 *
 *	Each crontab entry has six fields:
 *	   minute    hour  day-of-the-month  month  day-of-the-week  command
 *	Each entry is checked in turn, and any entry matching the current time
 *	is executed.  The entry * matches anything.  Some examples:
 *
 *   min hr dat mo day   command
 *    *  *   *  *   *    /usr/bin/date >/dev/tty0   #print date every minute
 *    0  *   *  *   *    /usr/bin/date >/dev/tty0   #print date on the hour
 *   30  4   *  *  1-5   /bin/backup /dev/fd1       #do backup Mon-Fri at 0430
 *   30 19   *  *  1,3,5 /etc/backup /dev/fd1       #Mon, Wed, Fri at 1930
 *    0  9  25 12   *    /usr/bin/sing >/dev/tty0   #Xmas morning at 0900 only
 *
 * Version 1.6  SrT  90/04/08
 *      Added casting fixes by Ralf Wenk, and integrated net
 *      changes that release current directory, and use the
 *      1.5.5 include files.  Altered assign, so no temporary
 *	buffer is needed.
 *
 * Version 1.5  SrT  89/04/10
 *	Changed sleep code, to type SRS sent me.
 *
 * Version 1.4  SrT  89/03/17
 *	Fixed a pointer problem, when reloading crontab.
 *
 * Version 1.3  SrT  89/03/16
 *	Loads crontab, into memory and only rereads the disk
 *	version if it changes.  (Free up those clock cycles!)
 *
 * Fixed 03/10/89, by Simmule Turner, simmy@nu.cs.fsu.edu
 *	Now correctly cleans up zombie processes
 *	Logs actions to /usr/adm/cronlog
 *	Syncs with clock after each minute
 *	Comments allowed in crontab
 *	Fixed bug that prevented month, from matching
*/


#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <time.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>

#ifndef DEBUG
#define CRONTAB "/usr/lib/crontab"
#define LOGFILE "/usr/adm/cronlog"
#else
#define LOGFILE "/usr/adm/cronlog.dbg"
#define CRONTAB "/usr/adm/crontab.dbg"
#endif

#define NULLDEV "/dev/null"
#define SEPARATOR " \t"
#define CRONSIZE  2048
#define CRONSTRUCT struct cron_entry

#define	TRUE	1
#define	FALSE	0

struct cron_entry {
  char *mn;
  char *hr;
  char *day;
  char *mon;
  char *wkd;
  char *cmd;
  struct cron_entry *next;
} *head, *entry_ptr;

char crontab[CRONSIZE];
FILE *cronlog;

int wakeup(), ret();

time_t previous_time = 0L;

main()
{
  int status;
  time_t clock;

  status = fork();
  if (status == -1) {
	fprintf(stderr, "Can't fork cron\n");
	exit(1);
  }

  if (status > 0) exit(0);

  signal(SIGINT, SIG_IGN);
  signal(SIGHUP, SIG_IGN);
  signal(SIGQUIT, SIG_IGN);

  close(0);
  close(1);
  close(2);

  chdir("/");

  open(NULLDEV, O_RDONLY);
  if ((cronlog = fopen(LOGFILE, "a")) == (FILE *) NULL) {
	open(NULLDEV, O_WRONLY);
	open(NULLDEV, O_WRONLY);
  } else {
	setbuf(cronlog, (char *) NULL);
	dup(fileno(cronlog));
  }

  entry_ptr = (CRONSTRUCT *) malloc(sizeof(CRONSTRUCT));
  entry_ptr->next = (CRONSTRUCT *) NULL;
  head = entry_ptr;

  while (TRUE) {
	signal(SIGALRM, wakeup);
	time(&clock);
	alarm((unsigned) (60 - clock % 60));
	pause();

	signal(SIGALRM, ret);
	alarm(1);
	while (wait((int *) NULL) != (-1));
  }
}

int ret() {}

wakeup()
{
  register struct tm *tm;
  time_t cur_time;
  CRONSTRUCT *this_entry = head;

  load_crontab();

  time(&cur_time);
  tm = localtime(&cur_time);

  while (this_entry->next && this_entry->mn) {
	if (match(this_entry->mn, tm->tm_min) &&
	    match(this_entry->hr, tm->tm_hour) &&
	    match(this_entry->day, tm->tm_mday) &&
	    match(this_entry->mon, tm->tm_mon + 1) &&
	    match(this_entry->wkd, tm->tm_wday)) {
		fprintf(cronlog, "%02d/%02d-%02d:%02d  %s\n",
			tm->tm_mon + 1, tm->tm_mday, tm->tm_hour,
			tm->tm_min, this_entry->cmd);
		if (fork() == 0) {
			execl("/bin/sh", "/bin/sh", "-c",
	                      this_entry->cmd, (char *) 0);
			exit(1);
		}
	}
	this_entry = this_entry->next;
  }
}

/*
 *	This routine will match the left string with the right number.
 *
 *	The string can contain the following syntax *
 *	*		This will return TRUE for any number
 *	x,y [,z, ...]	This will return TRUE for any number given.
 *	x-y		This will return TRUE for any number within
 *			the range of x thru y.
 */

match(left, right)
register char *left;
register int right;
{
  register int n;
  register char c;

  n = 0;
  if (!strcmp(left, "*")) return(TRUE);

  while ((c = *left++) && (c >= '0') && (c <= '9')) n = (n * 10) + c - '0';

  switch (c) {
      case '\0':
	return(right == n);

      case ',':
	if (right == n) return(TRUE);
	do {
		n = 0;
		while ((c = *left++) && (c >= '0') && (c <= '9'))
			n = (n * 10) + c - '0';

		if (right == n) return(TRUE);
	} while (c == ',');
	return(FALSE);

      case '-':
	if (right < n) return(FALSE);

	n = 0;
	while ((c = *left++) && (c >= '0') && (c <= '9'))
		n = (n * 10) + c - '0';

	return(right <= n);
  }
}

load_crontab()
{
  int pos = 0;
  FILE *cfp;
  struct stat buf;

  if (stat(CRONTAB, &buf)) {
	if (previous_time == 0L) printf("Can't stat crontab\n");
	previous_time = 0L;
	return;
  }
#ifdef DEBUG
  printf("Crontab Time:%ld In_Core:%ld\n", buf.st_mtime, previous_time);
#endif

  if (buf.st_mtime <= previous_time) return;

  if ((cfp = fopen(CRONTAB, "r")) == (FILE *) NULL) {
	if (previous_time == 0L) printf("Can't open crontab\n");
	previous_time = 0L;
	return;
  }
  previous_time = buf.st_mtime;

  entry_ptr = head;
  while (fgets(&crontab[pos], CRONSIZE - pos, cfp) != (char *) NULL) {
	int len;

	if (crontab[pos] == '#') continue;
	len = strlen(&crontab[pos]);
	if (crontab[pos + len - 1] == '\n') {
		len--;
		crontab[pos + len] = '\0';
	}
	assign(entry_ptr, &crontab[pos]);
	if (entry_ptr->next == (CRONSTRUCT *) NULL) {
		entry_ptr->next = (CRONSTRUCT *) malloc(sizeof(CRONSTRUCT));
		entry_ptr->next->next = (CRONSTRUCT *) NULL;
	}
	entry_ptr = entry_ptr->next;
	pos += ++len;
	if (pos >= CRONSIZE) break;
  }
  fclose(cfp);

  while (entry_ptr) {
	entry_ptr->mn = (char *) NULL;
	entry_ptr = entry_ptr->next;
  }

#ifdef DEBUG
  printf("Crontab uses %d/%d bytes\n", pos, CRONSIZE);
  {
	CRONSTRUCT *start = head;
	dumptable(start);
  }
#endif
}

assign(entry, line)
CRONSTRUCT *entry;
char *line;
{
  entry->mn = strtok(line, SEPARATOR);
  entry->hr = strtok((char *) NULL, SEPARATOR);
  entry->day = strtok((char *) NULL, SEPARATOR);
  entry->mon = strtok((char *) NULL, SEPARATOR);
  entry->wkd = strtok((char *) NULL, SEPARATOR);
  entry->cmd = strchr(entry->wkd,'\0') + 1;
}

#ifdef DEBUG
dumptable(table)
CRONSTRUCT *table;
{
  time_t clock;
  time(&clock);

  printf("\nContents of crontab at: %s", ctime(&clock));
  printf("Minute\tHour\tDay\tMonth\tWeekday\tCommand\n");
  while (table->next && table->mn) {
	printf("%s\t%s\t%s\t%s\t%s\t%s\n",
	       table->mn, table->hr, table->day, table->mon,
	       table->wkd, table->cmd);
	table = table->next;
  }
}
#endif