Annotation of src/usr.bin/at/at.c, Revision 1.27
1.27 ! millert 1: /* $OpenBSD: at.c,v 1.26 2002/05/11 23:16:44 millert Exp $ */
1.1 deraadt 2: /* $NetBSD: at.c,v 1.4 1995/03/25 18:13:31 glass Exp $ */
3:
4: /*
1.7 millert 5: * at.c : Put file into atrun queue
6: * Copyright (C) 1993, 1994 Thomas Koenig
1.1 deraadt 7: *
1.7 millert 8: * Atrun & Atq modifications
9: * Copyright (C) 1993 David Parsons
1.1 deraadt 10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. The name of the author(s) may not be used to endorse or promote
17: * products derived from this software without specific prior written
18: * permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
21: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1.7 millert 23: * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
1.1 deraadt 24: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27: * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30: */
31:
32: /* System Headers */
1.7 millert 33: #include <sys/param.h>
1.1 deraadt 34: #include <sys/stat.h>
1.25 millert 35: #include <sys/time.h>
1.1 deraadt 36: #include <ctype.h>
37: #include <dirent.h>
38: #include <errno.h>
39: #include <fcntl.h>
40: #include <pwd.h>
41: #include <signal.h>
42: #include <stddef.h>
43: #include <stdio.h>
44: #include <stdlib.h>
45: #include <string.h>
46: #include <time.h>
47: #include <unistd.h>
1.7 millert 48: #include <utmp.h>
49: #include <locale.h>
1.16 mickey 50: #include <err.h>
1.7 millert 51:
52: #if (MAXLOGNAME-1) > UT_NAMESIZE
53: #define LOGNAMESIZE UT_NAMESIZE
54: #else
55: #define LOGNAMESIZE (MAXLOGNAME-1)
56: #endif
1.1 deraadt 57:
58: /* Local headers */
59: #include "at.h"
60: #include "panic.h"
61: #include "parsetime.h"
1.7 millert 62: #include "perm.h"
1.1 deraadt 63: #include "pathnames.h"
64: #define MAIN
65: #include "privs.h"
66:
67: /* Macros */
68: #define ALARMC 10 /* Number of seconds to wait for timeout */
69:
70: #define TIMESIZE 50
71:
72: /* File scope variables */
73: #ifndef lint
1.27 ! millert 74: static const char rcsid[] = "$OpenBSD: at.c,v 1.26 2002/05/11 23:16:44 millert Exp $";
1.1 deraadt 75: #endif
76:
77: char *no_export[] =
78: {
79: "TERM", "TERMCAP", "DISPLAY", "_"
80: };
1.16 mickey 81: static int send_mail = 0;
1.1 deraadt 82:
83: /* External variables */
1.7 millert 84:
1.1 deraadt 85: extern char **environ;
86: int fcreated;
1.27 ! millert 87: int program = AT; /* default program mode */
1.1 deraadt 88: char atfile[FILENAME_MAX];
89:
1.7 millert 90: char *atinput = (char *)0; /* where to get input from */
1.1 deraadt 91: char atqueue = 0; /* which queue to examine for jobs (atq) */
92: char atverify = 0; /* verify time instead of queuing job */
93:
94: /* Function declarations */
1.7 millert 95:
1.21 millert 96: static void sigc(int);
97: static void alarmc(int);
98: static char *cwdname(void);
99: static void writefile(time_t, char);
100: static void list_jobs(void);
1.25 millert 101: static time_t ttime(const char *);
1.1 deraadt 102:
103: /* Signal catching functions */
104:
105: static void
1.26 millert 106: sigc(int signo)
1.1 deraadt 107: {
1.7 millert 108: /* If the user presses ^C, remove the spool file and exit. */
1.1 deraadt 109: if (fcreated) {
1.26 millert 110: PRIV_START;
1.7 millert 111: (void)unlink(atfile);
1.26 millert 112: PRIV_END;
1.1 deraadt 113: }
114:
1.20 deraadt 115: _exit(EXIT_FAILURE);
1.1 deraadt 116: }
117:
118: static void
1.26 millert 119: alarmc(int signo)
1.1 deraadt 120: {
1.20 deraadt 121: char buf[1024];
122:
1.7 millert 123: /* Time out after some seconds. */
1.25 millert 124: strlcpy(buf, __progname, sizeof(buf));
1.20 deraadt 125: strlcat(buf, ": File locking timed out\n", sizeof(buf));
126: write(STDERR_FILENO, buf, strlen(buf));
127: if (fcreated) {
1.26 millert 128: PRIV_START;
1.20 deraadt 129: unlink(atfile);
1.26 millert 130: PRIV_END;
1.20 deraadt 131: }
132: _exit(EXIT_FAILURE);
1.1 deraadt 133: }
134:
135: /* Local functions */
136:
137: static char *
1.26 millert 138: cwdname(void)
1.1 deraadt 139: {
1.7 millert 140: /*
141: * Read in the current directory; the name will be overwritten on
142: * subsequent calls.
143: */
144: static char path[MAXPATHLEN];
1.1 deraadt 145:
1.7 millert 146: return (getcwd(path, sizeof(path)));
147: }
1.1 deraadt 148:
1.7 millert 149: static int
1.26 millert 150: nextjob(void)
1.7 millert 151: {
152: int jobno;
153: FILE *fid;
1.1 deraadt 154:
1.22 millert 155: /* We require that the sequence file already exist. */
156: if ((fid = fopen(_PATH_SEQFILE, "r+")) == NULL)
157: return (EOF);
158:
159: if (fscanf(fid, "%5x", &jobno) == 1)
160: jobno = (jobno + 1) % 0xfffff; /* 2^20 jobs enough? */
161: else
162: jobno = 1;
163: (void)rewind(fid);
164: (void)fprintf(fid, "%05x\n", jobno);
165: (void)fclose(fid);
166:
167: return (jobno);
1.1 deraadt 168: }
169:
170: static void
1.26 millert 171: writefile(time_t runtimer, char queue)
1.1 deraadt 172: {
173: /*
174: * This does most of the work if at or batch are invoked for
175: * writing a job.
176: */
1.7 millert 177: int jobno;
1.1 deraadt 178: char *ap, *ppos, *mailname;
179: struct passwd *pass_entry;
180: struct stat statbuf;
181: int fdes, lockdes, fd2;
182: FILE *fp, *fpin;
183: struct sigaction act;
184: char **atenv;
185: int ch;
186: mode_t cmask;
187: struct flock lock;
188:
1.7 millert 189: (void)setlocale(LC_TIME, "");
190:
1.1 deraadt 191: /*
192: * Install the signal handler for SIGINT; terminate after removing the
193: * spool file if necessary
194: */
1.15 deraadt 195: memset(&act, 0, sizeof act);
1.1 deraadt 196: act.sa_handler = sigc;
197: sigemptyset(&(act.sa_mask));
198: act.sa_flags = 0;
199:
200: sigaction(SIGINT, &act, NULL);
201:
1.17 deraadt 202: (void)strlcpy(atfile, _PATH_ATJOBS, sizeof atfile);
1.7 millert 203: ppos = atfile + strlen(atfile);
1.1 deraadt 204:
205: /*
206: * Loop over all possible file names for running something at this
1.7 millert 207: * particular time, see if a file is there; the first empty slot at
1.22 millert 208: * any particular time is used. Lock the jobs directory first
1.7 millert 209: * to make sure we're alone when doing this.
1.1 deraadt 210: */
211:
1.26 millert 212: PRIV_START;
1.1 deraadt 213:
1.22 millert 214: /*
215: * Set an alarm so we don't sleep forever waiting on the lock.
216: * If we don't succeed with ALARMC seconds, something is wrong...
217: */
1.1 deraadt 218: act.sa_handler = alarmc;
219: sigemptyset(&(act.sa_mask));
220: act.sa_flags = 0;
221: sigaction(SIGALRM, &act, NULL);
222: alarm(ALARMC);
1.22 millert 223: lockdes = open(_PATH_ATJOBS, O_RDONLY|O_EXLOCK, 0);
1.1 deraadt 224: alarm(0);
225:
1.22 millert 226: if (lockdes < 0)
227: perr("Cannot lock jobs dir");
228:
1.7 millert 229: if ((jobno = nextjob()) == EOF)
1.22 millert 230: perr("Cannot generate job number");
1.7 millert 231:
1.8 millert 232: (void)snprintf(ppos, sizeof(atfile) - (ppos - atfile),
233: "%c%5x%8x", queue, jobno, (unsigned) (runtimer/60));
1.1 deraadt 234:
1.7 millert 235: for (ap = ppos; *ap != '\0'; ap++)
236: if (*ap == ' ')
237: *ap = '0';
238:
239: if (stat(atfile, &statbuf) != 0)
240: if (errno != ENOENT)
241: perr2("Cannot access ", _PATH_ATJOBS);
1.1 deraadt 242:
243: /*
244: * Create the file. The x bit is only going to be set after it has
245: * been completely written out, to make sure it is not executed in
246: * the meantime. To make sure they do not get deleted, turn off
247: * their r bit. Yes, this is a kluge.
248: */
249: cmask = umask(S_IRUSR | S_IWUSR | S_IXUSR);
1.23 millert 250: if ((fdes = open(atfile, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR)) == -1)
1.1 deraadt 251: perr("Cannot create atjob file");
252:
253: if ((fd2 = dup(fdes)) < 0)
254: perr("Error in dup() of job file");
255:
1.7 millert 256: if (fchown(fd2, real_uid, real_gid) != 0)
1.1 deraadt 257: perr("Cannot give away file");
258:
1.26 millert 259: PRIV_END;
1.1 deraadt 260:
261: /*
262: * We've successfully created the file; let's set the flag so it
263: * gets removed in case of an interrupt or error.
264: */
265: fcreated = 1;
266:
267: /* Now we can release the lock, so other people can access it */
268: lock.l_type = F_UNLCK;
269: lock.l_whence = SEEK_SET;
270: lock.l_start = 0;
271: lock.l_len = 0;
1.7 millert 272: (void)fcntl(lockdes, F_SETLKW, &lock);
273: (void)close(lockdes);
1.1 deraadt 274:
275: if ((fp = fdopen(fdes, "w")) == NULL)
276: panic("Cannot reopen atjob file");
277:
278: /*
1.18 millert 279: * Get the userid to mail to, first by trying getlogin(), which asks
280: * the kernel, then from $LOGNAME or $USER, finally from getpwuid().
1.1 deraadt 281: */
282: mailname = getlogin();
1.5 millert 283: if (mailname == NULL && (mailname = getenv("LOGNAME")) == NULL)
284: mailname = getenv("USER");
1.1 deraadt 285:
1.7 millert 286: if ((mailname == NULL) || (mailname[0] == '\0') ||
287: (strlen(mailname) > LOGNAMESIZE) || (getpwnam(mailname) == NULL)) {
288: pass_entry = getpwuid(real_uid);
1.1 deraadt 289: if (pass_entry != NULL)
290: mailname = pass_entry->pw_name;
291: }
292:
1.13 kstailey 293: if (atinput != NULL) {
1.1 deraadt 294: fpin = freopen(atinput, "r", stdin);
295: if (fpin == NULL)
296: perr("Cannot open input file");
297: }
1.7 millert 298: (void)fprintf(fp, "#!/bin/sh\n# atrun uid=%u gid=%u\n# mail %*s %d\n",
299: real_uid, real_gid, LOGNAMESIZE, mailname, send_mail);
1.1 deraadt 300:
301: /* Write out the umask at the time of invocation */
1.7 millert 302: (void)fprintf(fp, "umask %o\n", cmask);
1.1 deraadt 303:
304: /*
305: * Write out the environment. Anything that may look like a special
306: * character to the shell is quoted, except for \n, which is done
307: * with a pair of "'s. Dont't export the no_export list (such as
308: * TERM or DISPLAY) because we don't want these.
309: */
310: for (atenv = environ; *atenv != NULL; atenv++) {
311: int export = 1;
312: char *eqp;
313:
314: eqp = strchr(*atenv, '=');
1.19 millert 315: if (eqp == NULL)
1.1 deraadt 316: eqp = *atenv;
317: else {
318: int i;
319:
320: for (i = 0;i < sizeof(no_export) /
321: sizeof(no_export[0]); i++) {
322: export = export
323: && (strncmp(*atenv, no_export[i],
324: (size_t) (eqp - *atenv)) != 0);
325: }
326: eqp++;
327: }
328:
329: if (export) {
1.7 millert 330: (void)fwrite(*atenv, sizeof(char), eqp - *atenv, fp);
1.1 deraadt 331: for (ap = eqp; *ap != '\0'; ap++) {
332: if (*ap == '\n')
1.7 millert 333: (void)fprintf(fp, "\"\n\"");
1.1 deraadt 334: else {
1.7 millert 335: if (!isalnum(*ap)) {
336: switch (*ap) {
337: case '%': case '/': case '{':
338: case '[': case ']': case '=':
339: case '}': case '@': case '+':
340: case '#': case ',': case '.':
341: case ':': case '-': case '_':
342: break;
343: default:
344: (void)fputc('\\', fp);
345: break;
346: }
347: }
348: (void)fputc(*ap, fp);
1.1 deraadt 349: }
350: }
1.7 millert 351: (void)fputs("; export ", fp);
352: (void)fwrite(*atenv, sizeof(char), eqp - *atenv - 1, fp);
353: (void)fputc('\n', fp);
354: }
355: }
356: /*
357: * Cd to the directory at the time and write out all the
358: * commands the user supplies from stdin.
359: */
1.18 millert 360: if ((ap = cwdname()) == NULL)
361: perr("Cannot get current working directory");
1.7 millert 362: (void)fputs("cd ", fp);
1.18 millert 363: for (; *ap != '\0'; ap++) {
1.7 millert 364: if (*ap == '\n')
365: fprintf(fp, "\"\n\"");
366: else {
367: if (*ap != '/' && !isalnum(*ap))
368: (void)fputc('\\', fp);
1.1 deraadt 369:
1.7 millert 370: (void)fputc(*ap, fp);
1.1 deraadt 371: }
372: }
373: /*
1.7 millert 374: * Test cd's exit status: die if the original directory has been
375: * removed, become unreadable or whatever.
1.1 deraadt 376: */
1.7 millert 377: (void)fprintf(fp, " || {\n\t echo 'Execution directory inaccessible' >&2\n\t exit 1\n}\n");
1.1 deraadt 378:
1.3 millert 379: if ((ch = getchar()) == EOF)
380: panic("Input error");
381:
382: do {
1.7 millert 383: (void)fputc(ch, fp);
1.3 millert 384: } while ((ch = getchar()) != EOF);
1.1 deraadt 385:
1.7 millert 386: (void)fprintf(fp, "\n");
1.1 deraadt 387: if (ferror(fp))
388: panic("Output error");
389:
390: if (ferror(stdin))
391: panic("Input error");
392:
1.7 millert 393: (void)fclose(fp);
1.1 deraadt 394:
395: /*
396: * Set the x bit so that we're ready to start executing
397: */
398: if (fchmod(fd2, S_IRUSR | S_IWUSR | S_IXUSR) < 0)
399: perr("Cannot give away file");
400:
1.7 millert 401: (void)close(fd2);
402: (void)fprintf(stderr, "Job %d will be executed using /bin/sh\n", jobno);
1.1 deraadt 403: }
404:
405: static void
1.26 millert 406: list_jobs(void)
1.1 deraadt 407: {
408: /*
409: * List all a user's jobs in the queue, by looping through
410: * _PATH_ATJOBS, or everybody's if we are root
411: */
412: struct passwd *pw;
413: DIR *spool;
414: struct dirent *dirent;
415: struct stat buf;
416: struct tm runtime;
417: unsigned long ctm;
418: char queue;
1.7 millert 419: int jobno;
1.1 deraadt 420: time_t runtimer;
421: char timestr[TIMESIZE];
422: int first = 1;
423:
1.26 millert 424: PRIV_START;
1.1 deraadt 425:
1.7 millert 426: if (chdir(_PATH_ATJOBS) != 0)
1.1 deraadt 427: perr2("Cannot change to ", _PATH_ATJOBS);
428:
429: if ((spool = opendir(".")) == NULL)
430: perr2("Cannot open ", _PATH_ATJOBS);
431:
432: /* Loop over every file in the directory */
433: while ((dirent = readdir(spool)) != NULL) {
434: if (stat(dirent->d_name, &buf) != 0)
435: perr2("Cannot stat in ", _PATH_ATJOBS);
436:
437: /*
438: * See it's a regular file and has its x bit turned on and
439: * is the user's
440: */
441: if (!S_ISREG(buf.st_mode)
442: || ((buf.st_uid != real_uid) && !(real_uid == 0))
443: || !(S_IXUSR & buf.st_mode || atverify))
444: continue;
445:
1.7 millert 446: if (sscanf(dirent->d_name, "%c%5x%8lx", &queue, &jobno, &ctm) != 3)
1.1 deraadt 447: continue;
448:
449: if (atqueue && (queue != atqueue))
450: continue;
451:
452: runtimer = 60 * (time_t) ctm;
453: runtime = *localtime(&runtimer);
1.27 ! millert 454: strftime(timestr, TIMESIZE, "%a %b %e %T %Y", &runtime);
1.1 deraadt 455: if (first) {
1.25 millert 456: (void)printf("Date\t\t\t\tOwner\t\tQueue\tJob#\n");
1.1 deraadt 457: first = 0;
458: }
459: pw = getpwuid(buf.st_uid);
460:
1.25 millert 461: (void)printf("%s\t%-16s%c%s\t%d\n",
1.1 deraadt 462: timestr,
463: pw ? pw->pw_name : "???",
464: queue,
465: (S_IXUSR & buf.st_mode) ? "" : "(done)",
1.7 millert 466: jobno);
1.1 deraadt 467: }
1.26 millert 468: PRIV_END;
1.1 deraadt 469: }
470:
471: static void
1.26 millert 472: process_jobs(int argc, char **argv, int what)
1.1 deraadt 473: {
474: /* Delete every argument (job - ID) given */
475: int i;
476: struct stat buf;
1.7 millert 477: DIR *spool;
478: struct dirent *dirent;
479: unsigned long ctm;
480: char queue;
481: int jobno;
1.9 millert 482:
1.26 millert 483: PRIV_START;
1.1 deraadt 484:
1.7 millert 485: if (chdir(_PATH_ATJOBS) != 0)
1.1 deraadt 486: perr2("Cannot change to ", _PATH_ATJOBS);
487:
1.7 millert 488: if ((spool = opendir(".")) == NULL)
489: perr2("Cannot open ", _PATH_ATJOBS);
490:
1.26 millert 491: PRIV_END;
1.7 millert 492:
493: /* Loop over every file in the directory */
494: while((dirent = readdir(spool)) != NULL) {
495:
1.26 millert 496: PRIV_START;
1.7 millert 497: if (stat(dirent->d_name, &buf) != 0)
498: perr2("Cannot stat in ", _PATH_ATJOBS);
1.26 millert 499: PRIV_END;
1.7 millert 500:
501: if (sscanf(dirent->d_name, "%c%5x%8lx", &queue, &jobno, &ctm) !=3)
502: continue;
503:
504: for (i = optind; i < argc; i++) {
505: if (atoi(argv[i]) == jobno) {
1.16 mickey 506: if ((buf.st_uid != real_uid) && !(real_uid == 0))
507: errx(EXIT_FAILURE,
508: "%s: Not owner\n", argv[i]);
1.7 millert 509: switch (what) {
510: case ATRM:
1.26 millert 511: PRIV_START;
1.7 millert 512:
513: if (unlink(dirent->d_name) != 0)
514: perr(dirent->d_name);
515:
1.26 millert 516: PRIV_END;
1.7 millert 517:
518: break;
519:
520: case CAT:
521: {
522: FILE *fp;
523: int ch;
524:
1.26 millert 525: PRIV_START;
1.7 millert 526:
527: fp = fopen(dirent->d_name, "r");
528:
1.26 millert 529: PRIV_END;
1.7 millert 530:
531: if (!fp)
532: perr("Cannot open file");
533:
534: while((ch = getc(fp)) != EOF)
535: putchar(ch);
536: }
537: break;
538:
539: default:
1.16 mickey 540: errx(EXIT_FAILURE,
541: "Internal error, process_jobs = %d",
1.7 millert 542: what);
543: break;
544: }
545: }
1.1 deraadt 546: }
547: }
548: } /* delete_jobs */
549:
1.25 millert 550: #define ATOI2(s) ((s) += 2, ((s)[-2] - '0') * 10 + ((s)[-1] - '0'))
551:
552: static time_t
553: ttime(const char *arg)
554: {
555: /*
556: * This is pretty much a copy of stime_arg1() from touch.c. I changed
557: * the return value and the argument list because it's more convenient
558: * (IMO) to do everything in one place. - Joe Halpin
559: */
560: struct timeval tv[2];
561: time_t now;
562: struct tm *t;
563: int yearset;
564: char *p;
565:
566: if (gettimeofday(&tv[0], NULL))
567: panic("Cannot get current time");
568:
569: /* Start with the current time. */
570: now = tv[0].tv_sec;
571: if ((t = localtime(&now)) == NULL)
572: panic("localtime");
573: /* [[CC]YY]MMDDhhmm[.SS] */
574: if ((p = strchr(arg, '.')) == NULL)
575: t->tm_sec = 0; /* Seconds defaults to 0. */
576: else {
577: if (strlen(p + 1) != 2)
578: goto terr;
579: *p++ = '\0';
580: t->tm_sec = ATOI2(p);
581: }
582:
583: yearset = 0;
584: switch(strlen(arg)) {
585: case 12: /* CCYYMMDDhhmm */
586: t->tm_year = ATOI2(arg);
587: t->tm_year *= 100;
588: yearset = 1;
589: /* FALLTHROUGH */
590: case 10: /* YYMMDDhhmm */
591: if (yearset) {
592: yearset = ATOI2(arg);
593: t->tm_year += yearset;
594: } else {
595: yearset = ATOI2(arg);
596: t->tm_year = yearset + 2000;
597: }
598: t->tm_year -= 1900; /* Convert to UNIX time. */
599: /* FALLTHROUGH */
600: case 8: /* MMDDhhmm */
601: t->tm_mon = ATOI2(arg);
602: --t->tm_mon; /* Convert from 01-12 to 00-11 */
603: t->tm_mday = ATOI2(arg);
604: t->tm_hour = ATOI2(arg);
605: t->tm_min = ATOI2(arg);
606: break;
607: default:
608: goto terr;
609: }
610:
611: t->tm_isdst = -1; /* Figure out DST. */
612: tv[0].tv_sec = tv[1].tv_sec = mktime(t);
613: if (tv[0].tv_sec != -1)
614: return (tv[0].tv_sec);
615: else
616: terr:
617: panic("out of range or illegal time specification: "
618: "[[CC]YY]MMDDhhmm[.SS]");
619: }
620:
1.1 deraadt 621: /* Global functions */
622:
623: int
1.26 millert 624: main(int argc, char **argv)
1.1 deraadt 625: {
626: int c;
1.7 millert 627: char queue = DEFAULT_AT_QUEUE;
628: char queue_set = 0;
1.25 millert 629: char *options = "q:f:t:bcdlmrv"; /* default options for at */
1.1 deraadt 630: time_t timer;
1.25 millert 631: int tflag = 0;
1.1 deraadt 632:
1.26 millert 633: RELINQUISH_PRIVS;
1.1 deraadt 634:
635: /* find out what this program is supposed to do */
1.25 millert 636: if (strcmp(__progname, "atq") == 0) {
1.1 deraadt 637: program = ATQ;
1.24 millert 638: options = "q:v";
1.25 millert 639: } else if (strcmp(__progname, "atrm") == 0) {
1.1 deraadt 640: program = ATRM;
1.24 millert 641: options = "";
1.25 millert 642: } else if (strcmp(__progname, "batch") == 0) {
1.1 deraadt 643: program = BATCH;
1.24 millert 644: options = "f:q:mv";
1.1 deraadt 645: }
646:
647: /* process whatever options we can process */
648: opterr = 1;
1.6 millert 649: while ((c = getopt(argc, argv, options)) != -1)
1.1 deraadt 650: switch (c) {
651: case 'v': /* verify time settings */
652: atverify = 1;
653: break;
654:
655: case 'm': /* send mail when job is complete */
656: send_mail = 1;
657: break;
658:
659: case 'f':
660: atinput = optarg;
661: break;
662:
663: case 'q': /* specify queue */
664: if (strlen(optarg) > 1)
665: usage();
666:
667: atqueue = queue = *optarg;
1.7 millert 668: if (!(islower(queue) || isupper(queue)))
1.1 deraadt 669: usage();
1.7 millert 670:
671: queue_set = 1;
672: break;
673:
1.25 millert 674: case 'd': /* for backwards compatibility */
675: case 'r':
1.7 millert 676: if (program != AT)
677: usage();
678:
679: program = ATRM;
1.24 millert 680: options = "";
1.7 millert 681: break;
682:
1.25 millert 683: case 't':
684: if (program != AT)
685: usage();
686: tflag++;
687: timer = ttime(optarg);
688: break;
689:
1.7 millert 690: case 'l':
691: if (program != AT)
692: usage();
693:
694: program = ATQ;
1.24 millert 695: options = "q:v";
1.7 millert 696: break;
697:
698: case 'b':
699: if (program != AT)
700: usage();
701:
702: program = BATCH;
1.24 millert 703: options = "f:q:mv";
1.7 millert 704: break;
705:
706: case 'c':
707: program = CAT;
708: options = "";
1.1 deraadt 709: break;
710:
711: default:
712: usage();
713: break;
714: }
715: /* end of options eating */
1.7 millert 716:
1.16 mickey 717: if (!check_permission())
718: errx(EXIT_FAILURE, "You do not have permission to use %s.",
1.25 millert 719: __progname);
1.7 millert 720:
1.1 deraadt 721: /* select our program */
722: switch (program) {
723: case ATQ:
1.10 millert 724: if (optind != argc)
725: usage();
1.1 deraadt 726: list_jobs();
727: break;
728:
729: case ATRM:
1.7 millert 730: case CAT:
1.10 millert 731: if (optind == argc)
732: usage();
1.11 millert 733: process_jobs(argc, argv, program);
1.1 deraadt 734: break;
735:
736: case AT:
1.25 millert 737: /* Time may have been specified via the -t flag. */
738: if (!tflag)
739: timer = parsetime(argc, argv);
1.1 deraadt 740: if (atverify) {
741: struct tm *tm = localtime(&timer);
1.7 millert 742: (void)fprintf(stderr, "%s\n", asctime(tm));
1.1 deraadt 743: }
744: writefile(timer, queue);
745: break;
746:
747: case BATCH:
1.7 millert 748: if (queue_set)
749: queue = toupper(queue);
750: else
751: queue = DEFAULT_BATCH_QUEUE;
752:
753: if (argc > optind)
754: timer = parsetime(argc, argv);
755: else
756: timer = time(NULL);
757:
758: if (atverify) {
759: struct tm *tm = localtime(&timer);
760: (void)fprintf(stderr, "%s\n", asctime(tm));
761: }
762:
763: writefile(timer, queue);
1.1 deraadt 764: break;
765:
766: default:
767: panic("Internal error");
768: break;
769: }
770: exit(EXIT_SUCCESS);
771: }