xref: /original-bsd/usr.bin/at/at/at.c (revision 552e81d8)
1 static char *sccsid = "@(#)at.c	4.1 (Berkeley) 10/01/80";
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 	c = uyear%4==0? 366: 365;
83 	if (uday >= c) {
84 		uday -= c;
85 		uyear++;
86 	}
87 	filename(THISDAY, uyear, uday, utime);
88 	/* Create file, then change UIDS */
89 	close(creat(fname,0644));
90 	chown(fname,getuid(),getgid());
91 	setuid(getuid());
92 	ifile = stdin;
93 	if (argc > larg)
94 		ifile = fopen(argv[larg], "r");
95 	if (ifile == NULL) {
96 		fprintf(stderr, "at: cannot open input: %s\n", argv[larg]);
97 		exit(1);
98 	}
99 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
100 		signal(SIGINT, onintr);
101 	file = fopen(fname, "w");
102 	if (file == NULL) {
103 		fprintf(stderr, "at: cannot open memo file\n");
104 		exit(1);
105 	}
106 	if ((pwfil = popen("pwd", "r")) == NULL) {
107 		fprintf(stderr, "at: can't execute pwd\n");
108 		exit(1);
109 	}
110 	fgets(pwbuf, 100, pwfil);
111 	pclose(pwfil);
112 	fprintf(file, "cd %s", pwbuf);
113 	c = umask(0);
114 	umask(c);
115 	fprintf(file, "umask %.1o\n", c);
116 	if (environ) {
117 		char **ep = environ;
118 		while(*ep)
119 		{
120 			char *cp;
121 			for (tmp = *ep, cp = "TERMCAP"; *tmp==*cp; tmp++,cp++);
122 			if (*cp == 0 && *tmp== '=') {
123 				ep++;
124 				continue;
125 			}
126 			for(tmp = *ep ; *tmp != '=' ; tmp++) putc(*tmp,file);
127 			putc('=', file);
128 			putc('\'', file);
129 			for (tmp++; *tmp; tmp++) {
130 				if (*tmp == '\'')
131 					putc('\\', file);
132 				putc(*tmp, file);
133 			}
134 			putc('\'', file);
135 			fprintf(file, "\nexport ");
136 			for(tmp = *ep ; *tmp != '=' ; tmp++) putc(*tmp,file);
137 			putc('\n',file);
138 			ep++;
139 		}
140 	}
141 	/*
142 	 * see if the SHELL variable in the current enviroment is /bin/csh
143 	 * and in that case, use the csh as the shell
144 	 */
145 	tmp = getenv("SHELL");
146 	if (strcmp(tmp+strlen(tmp)-3, "csh") == 0)
147 		fprintf(file, "%s %s\n", tmp, "<< 'xxFUNNYxx'");
148 	while((c = getc(ifile)) != EOF) {
149 		putc(c, file);
150 	}
151 	if (strcmp(tmp+strlen(tmp)-3, "csh") == 0)
152 		fprintf(file, "%s\n", "xxFUNNYxx");
153 	exit(0);
154 }
155 
156 makeutime(pp)
157 char *pp;
158 {
159 	register val;
160 	register char *p;
161 
162 	/* p points to a user time */
163 	p = pp;
164 	val = 0;
165 	while(isdigit(*p)) {
166 		val = val*10+(*p++ -'0');
167 	}
168 	if (p-pp < 3)
169 		val *= HOUR;
170 
171 	for (;;) {
172 		switch(*p) {
173 
174 		case ':':
175 			++p;
176 			if (isdigit(*p)) {
177 				if (isdigit(p[1])) {
178 					val +=(10* *p + p[1] - 11*'0');
179 					p += 2;
180 					continue;
181 				}
182 			}
183 			fprintf(stderr, "at: bad time format:\n");
184 			exit(1);
185 
186 		case 'A':
187 		case 'a':
188 			if (val >= HALFDAY+HOUR)
189 				val = DAY+1;  /* illegal */
190 			if (val >= HALFDAY && val <(HALFDAY+HOUR))
191 				val -= HALFDAY;
192 			break;
193 
194 		case 'P':
195 		case 'p':
196 			if (val >= HALFDAY+HOUR)
197 				val = DAY+1;  /* illegal */
198 			if (val < HALFDAY)
199 				val += HALFDAY;
200 			break;
201 
202 		case 'n':
203 		case 'N':
204 			val = HALFDAY;
205 			break;
206 
207 		case 'M':
208 		case 'm':
209 			val = 0;
210 			break;
211 
212 
213 		case '\0':
214 		case ' ':
215 			/* 24 hour time */
216 			if (val == DAY)
217 				val -= DAY;
218 			break;
219 
220 		default:
221 			fprintf(stderr, "at: bad time format\n");
222 			exit(1);
223 
224 		}
225 		break;
226 	}
227 	if (val < 0 || val >= DAY) {
228 		fprintf(stderr, "at: time out of range\n");
229 		exit(1);
230 	}
231 	if (val%HOUR >= 60) {
232 		fprintf(stderr, "at: illegal minute field\n");
233 		exit(1);
234 	}
235 	utime = val;
236 }
237 
238 
239 makeuday(argc,argv)
240 char **argv;
241 {
242 	/* the presumption is that argv[2], argv[3] are either
243 	   month day OR weekday [week].  Returns either 2 or 3 as last
244 	   argument used */
245 	/* first of all, what's today */
246 	long tm;
247 	int found = -1;
248 	char **ps;
249 	struct tm *detail, *localtime();
250 	struct monstr *pt;
251 
252 	time(&tm);
253 	detail = localtime(&tm);
254 	uday = today = detail->tm_yday;
255 	uyear = detail->tm_year;
256 	now = detail->tm_hour*100+detail->tm_min;
257 	if (argc<=2)
258 		return(1);
259 	/* is the next argument a month name ? */
260 	for (pt=months; pt->mname; pt++) {
261 		if (prefix(argv[2], pt->mname)) {
262 			if (found<0)
263 				found = pt-months;
264 			else {
265 				fprintf(stderr, "at: ambiguous month\n");
266 				exit(1);
267 			}
268 		}
269 	}
270 	if (found>=0) {
271 		if (argc<=3)
272 			return(2);
273 		uday = atoi(argv[3]) - 1;
274 		if (uday<0) {
275 			fprintf(stderr, "at: illegal day\n");
276 			exit(1);
277 		}
278 		while(--found>=0)
279 			uday += months[found].mlen;
280 		if (detail->tm_year%4==0 && uday>59)
281 			uday += 1;
282 		return(3);
283 	}
284 	/* not a month, try day of week */
285 	found = -1;
286 	for (ps=days; ps<days+7; ps++) {
287 		if (prefix(argv[2], *ps)) {
288 			if (found<0)
289 				found = ps-days;
290 			else {
291 				fprintf(stderr, "at: ambiguous day of week\n");
292 				exit(1);
293 			}
294 		}
295 	}
296 	if (found<0)
297 		return(1);
298 	/* find next day of this sort */
299 	uday = found - detail->tm_wday;
300 	if (uday<=0)
301 		uday += 7;
302 	uday += today;
303 	if (argc>3 && strcmp("week", argv[3])==0) {
304 		uday += 7;
305 		return(3);
306 	}
307 	return(2);
308 }
309 
310 char *
311 prefix(begin, full)
312 char *begin, *full;
313 {
314 	int c;
315 	while (c = *begin++) {
316 		if (isupper(c))
317 			c = tolower(c);
318 		if (*full != c)
319 			return(0);
320 		else
321 			full++;
322 	}
323 	return(full);
324 }
325 
326 filename(dir, y, d, t)
327 char *dir;
328 {
329 	register i;
330 
331 	for (i=0; ; i += 53) {
332 		sprintf(fname, "%s/%.2d%.3d%.4d%.2d", dir, y, d, t,
333 		   (getpid()+i)%100);
334 		if (access(fname, 0) == -1)
335 			return;
336 	}
337 }
338 
339 onintr()
340 {
341 	unlink(fname);
342 	exit(1);
343 }
344