xref: /original-bsd/usr.bin/at/at/at.c (revision f0fd5f8a)
1 static char *sccsid = "@(#)at.c	4.4 (Berkeley) 06/28/82";
2 /*
3  * at time mon day
4  * at time wday
5  * at time wday 'week'
6  *
7  */
8 #include <stdio.h>
9 #include <ctype.h>
10 #include <time.h>
11 #include <signal.h>
12 
13 #define HOUR 100
14 #define HALFDAY	(12*HOUR)
15 #define DAY	(24*HOUR)
16 #define THISDAY "/usr/spool/at"
17 
18 char *days[] = {
19 	"sunday",
20 	"monday",
21 	"tuesday",
22 	"wednesday",
23 	"thursday",
24 	"friday",
25 	"saturday",
26 };
27 
28 struct monstr {
29 	char *mname;
30 	int mlen;
31 } months[] = {
32 	{ "january", 31 },
33 	{ "february", 28 },
34 	{ "march", 31 },
35 	{ "april", 30 },
36 	{ "may", 31 },
37 	{ "june", 30 },
38 	{ "july", 31 },
39 	{ "august", 31 },
40 	{ "september", 30 },
41 	{ "october", 31 },
42 	{ "november", 30 },
43 	{ "december", 31 },
44 	{ 0, 0 },
45 };
46 
47 char	fname[100];
48 int	utime;  /* requested time in grains */
49 int	now;	/* when is it */
50 int	uday; /* day of year to be done */
51 int	uyear; /* year */
52 int	today; /* day of year today */
53 FILE	*file;
54 FILE	*ifile;
55 char	**environ;
56 char	*prefix();
57 char    *getenv();
58 FILE	*popen();
59 
60 main(argc, argv)
61 char **argv;
62 {
63 	extern onintr();
64 	register c;
65 	char pwbuf[100];
66 	FILE *pwfil;
67 	int larg;
68 	char *tmp;
69 
70 	/* argv[1] is the user's time: e.g.,  3AM */
71 	/* argv[2] is a month name or day of week */
72 	/* argv[3] is day of month or 'week' */
73 	/* another argument might be an input file */
74 	if (argc < 2) {
75 		fprintf(stderr, "at: arg count\n");
76 		exit(1);
77 	}
78 	makeutime(argv[1]);
79 	larg = makeuday(argc,argv)+1;
80 	if (uday==today && larg<=2 && utime<=now)
81 		uday++;
82 	if (uday < today)
83 		uyear++;
84 	c = uyear%4==0? 366: 365;
85 	if (uday >= c) {
86 		uday -= c;
87 		uyear++;
88 	}
89 	filename(THISDAY, uyear, uday, utime);
90 	/* Create file, then change UIDS */
91 	close(creat(fname,0644));
92 	chown(fname,getuid(),getgid());
93 	setuid(getuid());
94 	ifile = stdin;
95 	if (argc > larg)
96 		ifile = fopen(argv[larg], "r");
97 	if (ifile == NULL) {
98 		fprintf(stderr, "at: cannot open input: %s\n", argv[larg]);
99 		exit(1);
100 	}
101 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
102 		signal(SIGINT, onintr);
103 	file = fopen(fname, "w");
104 	if (file == NULL) {
105 		fprintf(stderr, "at: cannot open memo file\n");
106 		exit(1);
107 	}
108 	if ((pwfil = popen("pwd", "r")) == NULL) {
109 		fprintf(stderr, "at: can't execute pwd\n");
110 		exit(1);
111 	}
112 	fgets(pwbuf, 100, pwfil);
113 	pclose(pwfil);
114 	fprintf(file, "cd %s", pwbuf);
115 	c = umask(0);
116 	umask(c);
117 	fprintf(file, "umask %.1o\n", c);
118 	if (environ) {
119 		char **ep = environ;
120 		while(*ep)
121 		{
122 			char *cp;
123 			for (tmp = *ep, cp = "TERMCAP"; *tmp==*cp; tmp++,cp++);
124 			if (*cp == 0 && *tmp== '=') {
125 				ep++;
126 				continue;
127 			}
128 			for(tmp = *ep ; *tmp != '=' ; tmp++) putc(*tmp,file);
129 			putc('=', file);
130 			putc('\'', file);
131 			for (tmp++; *tmp; tmp++) {
132 				if (*tmp == '\'')
133 					fputs("'\\''", file);
134 				else
135 					putc(*tmp, file);
136 			}
137 			putc('\'', file);
138 			fprintf(file, "\nexport ");
139 			for(tmp = *ep ; *tmp != '=' ; tmp++) putc(*tmp,file);
140 			putc('\n',file);
141 			ep++;
142 		}
143 	}
144 	/*
145 	 * see if the SHELL variable in the current enviroment is /bin/csh
146 	 * and in that case, use the csh as the shell
147 	 */
148 	tmp = getenv("SHELL");
149 	if (strcmp(tmp+strlen(tmp)-3, "csh") == 0)
150 		fprintf(file, "%s %s\n", tmp, "<< 'xxFUNNYxx'");
151 	while((c = getc(ifile)) != EOF) {
152 		putc(c, file);
153 	}
154 	if (strcmp(tmp+strlen(tmp)-3, "csh") == 0)
155 		fprintf(file, "%s\n", "xxFUNNYxx");
156 	exit(0);
157 }
158 
159 makeutime(pp)
160 char *pp;
161 {
162 	register val;
163 	register char *p;
164 
165 	/* p points to a user time */
166 	p = pp;
167 	val = 0;
168 	while(isdigit(*p)) {
169 		val = val*10+(*p++ -'0');
170 	}
171 	if (p-pp < 3)
172 		val *= HOUR;
173 
174 	for (;;) {
175 		switch(*p) {
176 
177 		case ':':
178 			++p;
179 			if (isdigit(*p)) {
180 				if (isdigit(p[1])) {
181 					val +=(10* *p + p[1] - 11*'0');
182 					p += 2;
183 					continue;
184 				}
185 			}
186 			fprintf(stderr, "at: bad time format:\n");
187 			exit(1);
188 
189 		case 'A':
190 		case 'a':
191 			if (val >= HALFDAY+HOUR)
192 				val = DAY+1;  /* illegal */
193 			if (val >= HALFDAY && val <(HALFDAY+HOUR))
194 				val -= HALFDAY;
195 			break;
196 
197 		case 'P':
198 		case 'p':
199 			if (val >= HALFDAY+HOUR)
200 				val = DAY+1;  /* illegal */
201 			if (val < HALFDAY)
202 				val += HALFDAY;
203 			break;
204 
205 		case 'n':
206 		case 'N':
207 			val = HALFDAY;
208 			break;
209 
210 		case 'M':
211 		case 'm':
212 			val = 0;
213 			break;
214 
215 
216 		case '\0':
217 		case ' ':
218 			/* 24 hour time */
219 			if (val == DAY)
220 				val -= DAY;
221 			break;
222 
223 		default:
224 			fprintf(stderr, "at: bad time format\n");
225 			exit(1);
226 
227 		}
228 		break;
229 	}
230 	if (val < 0 || val >= DAY) {
231 		fprintf(stderr, "at: time out of range\n");
232 		exit(1);
233 	}
234 	if (val%HOUR >= 60) {
235 		fprintf(stderr, "at: illegal minute field\n");
236 		exit(1);
237 	}
238 	utime = val;
239 }
240 
241 
242 makeuday(argc,argv)
243 char **argv;
244 {
245 	/* the presumption is that argv[2], argv[3] are either
246 	   month day OR weekday [week].  Returns either 2 or 3 as last
247 	   argument used */
248 	/* first of all, what's today */
249 	long tm;
250 	int found = -1;
251 	char **ps;
252 	struct tm *detail, *localtime();
253 	struct monstr *pt;
254 
255 	time(&tm);
256 	detail = localtime(&tm);
257 	uday = today = detail->tm_yday;
258 	uyear = detail->tm_year;
259 	now = detail->tm_hour*100+detail->tm_min;
260 	if (argc<=2)
261 		return(1);
262 	/* is the next argument a month name ? */
263 	for (pt=months; pt->mname; pt++) {
264 		if (prefix(argv[2], pt->mname)) {
265 			if (found<0)
266 				found = pt-months;
267 			else {
268 				fprintf(stderr, "at: ambiguous month\n");
269 				exit(1);
270 			}
271 		}
272 	}
273 	if (found>=0) {
274 		if (argc<=3)
275 			return(2);
276 		uday = atoi(argv[3]) - 1;
277 		if (uday<0) {
278 			fprintf(stderr, "at: illegal day\n");
279 			exit(1);
280 		}
281 		while(--found>=0)
282 			uday += months[found].mlen;
283 		if (detail->tm_year%4==0 && uday>59)
284 			uday += 1;
285 		return(3);
286 	}
287 	/* not a month, try day of week */
288 	found = -1;
289 	for (ps=days; ps<days+7; ps++) {
290 		if (prefix(argv[2], *ps)) {
291 			if (found<0)
292 				found = ps-days;
293 			else {
294 				fprintf(stderr, "at: ambiguous day of week\n");
295 				exit(1);
296 			}
297 		}
298 	}
299 	if (found<0)
300 		return(1);
301 	/* find next day of this sort */
302 	uday = found - detail->tm_wday;
303 	if (uday<=0)
304 		uday += 7;
305 	uday += today;
306 	if (argc>3 && strcmp("week", argv[3])==0) {
307 		uday += 7;
308 		return(3);
309 	}
310 	return(2);
311 }
312 
313 char *
314 prefix(begin, full)
315 char *begin, *full;
316 {
317 	int c;
318 	while (c = *begin++) {
319 		if (isupper(c))
320 			c = tolower(c);
321 		if (*full != c)
322 			return(0);
323 		else
324 			full++;
325 	}
326 	return(full);
327 }
328 
329 filename(dir, y, d, t)
330 char *dir;
331 {
332 	register i;
333 
334 	for (i=0; ; i += 53) {
335 		sprintf(fname, "%s/%02d.%03d.%04d.%02d", dir, y, d, t,
336 		   (getpid()+i)%100);
337 		if (access(fname, 0) == -1)
338 			return;
339 	}
340 }
341 
342 onintr()
343 {
344 	unlink(fname);
345 	exit(1);
346 }
347