xref: /original-bsd/usr.bin/at/at/at.c (revision 1f3a482a)
1 static char *sccsid = "@(#)at.c	4.3 (Berkeley) 07/03/81";
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 					fputs("'\\''", file);
132 				else
133 					putc(*tmp, file);
134 			}
135 			putc('\'', file);
136 			fprintf(file, "\nexport ");
137 			for(tmp = *ep ; *tmp != '=' ; tmp++) putc(*tmp,file);
138 			putc('\n',file);
139 			ep++;
140 		}
141 	}
142 	/*
143 	 * see if the SHELL variable in the current enviroment is /bin/csh
144 	 * and in that case, use the csh as the shell
145 	 */
146 	tmp = getenv("SHELL");
147 	if (strcmp(tmp+strlen(tmp)-3, "csh") == 0)
148 		fprintf(file, "%s %s\n", tmp, "<< 'xxFUNNYxx'");
149 	while((c = getc(ifile)) != EOF) {
150 		putc(c, file);
151 	}
152 	if (strcmp(tmp+strlen(tmp)-3, "csh") == 0)
153 		fprintf(file, "%s\n", "xxFUNNYxx");
154 	exit(0);
155 }
156 
157 makeutime(pp)
158 char *pp;
159 {
160 	register val;
161 	register char *p;
162 
163 	/* p points to a user time */
164 	p = pp;
165 	val = 0;
166 	while(isdigit(*p)) {
167 		val = val*10+(*p++ -'0');
168 	}
169 	if (p-pp < 3)
170 		val *= HOUR;
171 
172 	for (;;) {
173 		switch(*p) {
174 
175 		case ':':
176 			++p;
177 			if (isdigit(*p)) {
178 				if (isdigit(p[1])) {
179 					val +=(10* *p + p[1] - 11*'0');
180 					p += 2;
181 					continue;
182 				}
183 			}
184 			fprintf(stderr, "at: bad time format:\n");
185 			exit(1);
186 
187 		case 'A':
188 		case 'a':
189 			if (val >= HALFDAY+HOUR)
190 				val = DAY+1;  /* illegal */
191 			if (val >= HALFDAY && val <(HALFDAY+HOUR))
192 				val -= HALFDAY;
193 			break;
194 
195 		case 'P':
196 		case 'p':
197 			if (val >= HALFDAY+HOUR)
198 				val = DAY+1;  /* illegal */
199 			if (val < HALFDAY)
200 				val += HALFDAY;
201 			break;
202 
203 		case 'n':
204 		case 'N':
205 			val = HALFDAY;
206 			break;
207 
208 		case 'M':
209 		case 'm':
210 			val = 0;
211 			break;
212 
213 
214 		case '\0':
215 		case ' ':
216 			/* 24 hour time */
217 			if (val == DAY)
218 				val -= DAY;
219 			break;
220 
221 		default:
222 			fprintf(stderr, "at: bad time format\n");
223 			exit(1);
224 
225 		}
226 		break;
227 	}
228 	if (val < 0 || val >= DAY) {
229 		fprintf(stderr, "at: time out of range\n");
230 		exit(1);
231 	}
232 	if (val%HOUR >= 60) {
233 		fprintf(stderr, "at: illegal minute field\n");
234 		exit(1);
235 	}
236 	utime = val;
237 }
238 
239 
240 makeuday(argc,argv)
241 char **argv;
242 {
243 	/* the presumption is that argv[2], argv[3] are either
244 	   month day OR weekday [week].  Returns either 2 or 3 as last
245 	   argument used */
246 	/* first of all, what's today */
247 	long tm;
248 	int found = -1;
249 	char **ps;
250 	struct tm *detail, *localtime();
251 	struct monstr *pt;
252 
253 	time(&tm);
254 	detail = localtime(&tm);
255 	uday = today = detail->tm_yday;
256 	uyear = detail->tm_year;
257 	now = detail->tm_hour*100+detail->tm_min;
258 	if (argc<=2)
259 		return(1);
260 	/* is the next argument a month name ? */
261 	for (pt=months; pt->mname; pt++) {
262 		if (prefix(argv[2], pt->mname)) {
263 			if (found<0)
264 				found = pt-months;
265 			else {
266 				fprintf(stderr, "at: ambiguous month\n");
267 				exit(1);
268 			}
269 		}
270 	}
271 	if (found>=0) {
272 		if (argc<=3)
273 			return(2);
274 		uday = atoi(argv[3]) - 1;
275 		if (uday<0) {
276 			fprintf(stderr, "at: illegal day\n");
277 			exit(1);
278 		}
279 		while(--found>=0)
280 			uday += months[found].mlen;
281 		if (detail->tm_year%4==0 && uday>59)
282 			uday += 1;
283 		return(3);
284 	}
285 	/* not a month, try day of week */
286 	found = -1;
287 	for (ps=days; ps<days+7; ps++) {
288 		if (prefix(argv[2], *ps)) {
289 			if (found<0)
290 				found = ps-days;
291 			else {
292 				fprintf(stderr, "at: ambiguous day of week\n");
293 				exit(1);
294 			}
295 		}
296 	}
297 	if (found<0)
298 		return(1);
299 	/* find next day of this sort */
300 	uday = found - detail->tm_wday;
301 	if (uday<=0)
302 		uday += 7;
303 	uday += today;
304 	if (argc>3 && strcmp("week", argv[3])==0) {
305 		uday += 7;
306 		return(3);
307 	}
308 	return(2);
309 }
310 
311 char *
312 prefix(begin, full)
313 char *begin, *full;
314 {
315 	int c;
316 	while (c = *begin++) {
317 		if (isupper(c))
318 			c = tolower(c);
319 		if (*full != c)
320 			return(0);
321 		else
322 			full++;
323 	}
324 	return(full);
325 }
326 
327 filename(dir, y, d, t)
328 char *dir;
329 {
330 	register i;
331 
332 	for (i=0; ; i += 53) {
333 		sprintf(fname, "%s/%02d.%03d.%04d.%02d", dir, y, d, t,
334 		   (getpid()+i)%100);
335 		if (access(fname, 0) == -1)
336 			return;
337 	}
338 }
339 
340 onintr()
341 {
342 	unlink(fname);
343 	exit(1);
344 }
345