2.9BSD/usr/src/cmd/at.c

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

/*
 * at time mon day
 * at time wday
 * at time wday 'week'
 *
 */
/*! Modified by PLWard, USGS 10/30/80 for csh and mail options */

#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include <signal.h>
#include <pwd.h>

#define MAIL	"Mail"
#define CD  	"cd"
#define RM  	"/bin/rm"
#define PWD 	"/bin/pwd"
#define PAST	"/usr/spool/at/past"
#define THISDAY	"/usr/spool/at"
#define HOUR 	100
#define HALFDAY	(12*HOUR)
#define DAY	(24*HOUR)

int	sendmail = 1;	/* default to send mail = 1, else = 0. */

char *days[] = {
	"sunday",
	"monday",
	"tuesday",
	"wednesday",
	"thursday",
	"friday",
	"saturday",
};

struct monstr {
	char *mname; 
	int mlen;
} months[] = {
	{ "january", 31 },
	{ "february", 28 },
	{ "march", 31 },
	{ "april", 30 },
	{ "may", 31 },
	{ "june", 30 },
	{ "july", 31 },
	{ "august", 31 },
	{ "september", 30 },
	{ "october", 31 },
	{ "november", 30 },
	{ "december", 31 },
	{ 0, 0 },
};

char	fname[100];
char	fileout[100];
char	temp[15];
int	utime;          /* requested time in grains */
int	now;        	/* when is it */
int	uday;           /* day of year to be done */
int	uyear;          /* year */
int	today;          /* day of year today */
FILE	*file;
FILE	*ifile;
char	**environ;
char	*prefix();
FILE	*popen();
struct  passwd *user;

main(argc, argv)
char **argv;
{
	extern onintr();
	register c;
	char pwbuf[100];
	FILE *pwfil;
	int larg;
	int csh;
	int i,eq;
	char *tmp;
	char **ep;
	char *cp;

	if(argv[1][0] == '-'){
		sendmail=sendmail ? 0 : 1;
		for(i=2;i<=argc;i++)argv[i-1]=argv[i];
		argc--;
	}
	/* argv[1] is the user's time: e.g.,  3AM */
	/* argv[2] is a month name or day of week */
	/* argv[3] is day of month or 'week' */
	/* another argument might be an input file */
	if (argc < 2) {
		fprintf(stderr, "at: arg count\n");
		exit(1);
	}
	makeutime(argv[1]);
	larg = makeuday(argc,argv)+1;
	if (uday==today && larg<=2 && utime<=now)
		uday++;
	c = uyear%4==0? 366: 365;
	if (uday >= c) {
		uday -= c;
		uyear++;
	}
	filename(THISDAY, uyear, uday, utime);
	/* Create file and then change uids */
	close(creat(fname,0755));
	chown(fname,getuid(),getgid());
/*	fix so that root can use at */
	setuid(getuid());
	user=getpwuid(getuid());
	ifile = stdin;
	if (argc > larg)
		ifile = fopen(argv[larg], "r");
	else argv[larg]="from stdin";
	if (ifile == NULL) {
		fprintf(stderr, "at: cannot open input: %s\n", argv[larg]);
		exit(1);
	}
	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
		signal(SIGINT, onintr);
	file = fopen(fname, "w");
	if (file == NULL) {
		fprintf(stderr, "at: cannot open file in %s.\n",THISDAY);
		exit(1);
	}
	/* Decide if this is a cshell file */
	if(ifile == stdin){
		tmp=getenv("SHELL");
		csh = (strcmp(tmp+strlen(tmp)-3,"csh")==0) ? 1 : 0;
	}
	else {
		csh = ((c=getc(ifile)) == '#') ? 1 : 0;
		fseek(ifile,0,0);
	}
	if (csh) fprintf(file,"#at:cshell\n");
	if ((pwfil = popen(PWD, "r")) == NULL) {
		fprintf(stderr, "at: can't execute pwd\n");
		exit(1);
	}
	fgets(pwbuf, 100, pwfil);
	pclose(pwfil);
	fprintf(file, "%s %s",CD, pwbuf);
	c=umask(0);
	umask(c);
	fprintf(file,"umask %.1o\n",c);
	if (environ) {
		ep = environ;
		while (*ep){
			for (tmp = *ep, cp = "TERMCAP"; *tmp==*cp; tmp++,cp++);
			if (*cp == 0 && *tmp== '=') {
				ep++;
				continue;
			}
			if (csh) fprintf(file,"setenv ");
			for(tmp = *ep ; *tmp != '=' ; tmp++) putc(*tmp,file);
			if (csh) putc(' ', file);
			else putc(*tmp,file);
			putc('\'', file);
			for (tmp++; *tmp; tmp++) {
				if (*tmp == '\'')
					putc('\\', file);
				putc(*tmp, file);
			}
			putc('\'', file);
			putc('\n',file);
			ep++;
		}
	if (csh) fprintf(file,"source %s/.cshrc\n",getenv("HOME"));
	}
	fprintf(file,"echo 'Began executing at' `date`\n");
	while((c = getc(ifile)) != EOF) {
		putc(c, file);
	}
	fprintf(file,"%s %s\n",CD,PAST);
	fprintf(file,"echo 'Done  executing at' `date`\n");
	if(sendmail)fprintf(file,"%s -s 'at: ran program %s.' %s < %s\n",
		MAIL,argv[larg],user->pw_name,fileout);
	fprintf(file,"%s %s\n",RM,fileout);
	exit(0);
}

makeutime(pp)
char *pp; 
{
	register val;
	register char *p;

	/* p points to a user time */
	p = pp;
	val = 0;
	while(isdigit(*p)) {
		val = val*10+(*p++ -'0');
	}
	if (p-pp < 3)
		val *= HOUR;

	for (;;) {
		switch(*p) {

		case ':':
			++p;
			if (isdigit(*p)) {
				if (isdigit(p[1])) {
					val +=(10* *p + p[1] - 11*'0');
					p += 2;
					continue;
				}
			}
			fprintf(stderr, "at: bad time format:\n");
			exit(1);

		case 'A':
		case 'a':
			if (val >= HALFDAY+HOUR)
				val = DAY+1;  /* illegal */
			if (val >= HALFDAY && val <(HALFDAY+HOUR))
				val -= HALFDAY;
			break;

		case 'P':
		case 'p':
			if (val >= HALFDAY+HOUR)
				val = DAY+1;  /* illegal */
			if (val < HALFDAY)
				val += HALFDAY;
			break;

		case 'n':
		case 'N':
			val = HALFDAY;
			break;

		case 'M':
		case 'm':
			val = 0;
			break;


		case '\0':
		case ' ':
			/* 24 hour time */
			if (val == DAY)
				val -= DAY;
			break;

		default:
			fprintf(stderr, "at: bad time format\n");
			exit(1);

		}
		break;
	}
	if (val < 0 || val >= DAY) {
		fprintf(stderr, "at: time out of range\n");
		exit(1);
	}
	if (val%HOUR >= 60) {
		fprintf(stderr, "at: illegal minute field\n");
		exit(1);
	}
	utime = val;
}


makeuday(argc,argv)
char **argv;
{
	/* the presumption is that argv[2], argv[3] are either
	   month day OR weekday [week].  Returns either 2 or 3 as last
	   argument used */
	/* first of all, what's today */
	long tm;
	int found = -1;
	char **ps;
	struct tm *detail, *localtime();
	struct monstr *pt;

	time(&tm);
	detail = localtime(&tm);
	uday = today = detail->tm_yday;
	uyear = detail->tm_year;
	now = detail->tm_hour*100+detail->tm_min;
	if (argc<=2)
		return(1);
	/* is the next argument a month name ? */
	for (pt=months; pt->mname; pt++) {
		if (prefix(argv[2], pt->mname)) {
			if (found<0)
				found = pt-months;
			else {
				fprintf(stderr, "at: ambiguous month\n");
				exit(1);
			}
		}
	}
	if (found>=0) {
		if (argc<=3)
			return(2);
		uday = atoi(argv[3]) - 1;
		if (uday<0) {
			fprintf(stderr, "at: illegal day\n");
			exit(1);
		}
		while(--found>=0)
			uday += months[found].mlen;
		if (detail->tm_year%4==0 && uday>59)
			uday += 1;
		return(3);
	}
	/* not a month, try day of week */
	found = -1;
	for (ps=days; ps<days+7; ps++) {
		if (prefix(argv[2], *ps)) {
			if (found<0)
				found = ps-days;
			else {
				fprintf(stderr, "at: ambiguous day of week\n");
				exit(1);
			}
		}
	}
	if (found<0)
		return(1);
	/* find next day of this sort */
	uday = found - detail->tm_wday;
	if (uday<=0)
		uday += 7;
	uday += today;
	if (argc>3 && strcmp("week", argv[3])==0) {
		uday += 7;
		return(3);
	}
	return(2);
}

char *
prefix(begin, full)
char *begin, *full;
{
	int c;
	while (c = *begin++) {
		if (isupper(c))
			c = tolower(c);
		if (*full != c)
			return(0);
		else
			full++;
	}
	return(full);
}

filename(dir, y, d, t)
char *dir;
{
	register i;

	for (i=0; ; i += 53) {
		sprintf(temp,"%02d.%03d.%04d.%02d",y,d,t,(getpid()+i)%100);
		sprintf(fname,"%s/%s",dir,temp);
		temp[0]='M';
		sprintf(fileout,"%s/%s",PAST,temp);
		if (access(fname, 0) == -1)
			return;
	}
}

onintr()
{
	unlink(fname);
	exit(1);
}