[BACK]Return to at.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / at

Annotation of src/usr.bin/at/at.c, Revision 1.11

1.11    ! millert     1: /*     $OpenBSD: at.c,v 1.10 1997/03/03 03:31:10 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 */
                     33: #include <sys/types.h>
1.7       millert    34: #include <sys/param.h>
1.1       deraadt    35: #include <sys/stat.h>
                     36: #include <sys/wait.h>
                     37: #include <ctype.h>
                     38: #include <dirent.h>
                     39: #include <errno.h>
                     40: #include <fcntl.h>
                     41: #include <pwd.h>
                     42: #include <signal.h>
                     43: #include <stddef.h>
                     44: #include <stdio.h>
                     45: #include <stdlib.h>
                     46: #include <string.h>
                     47: #include <time.h>
                     48: #include <unistd.h>
1.7       millert    49: #include <utmp.h>
                     50: #include <locale.h>
                     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:
1.7       millert    72: enum { ATQ, ATRM, AT, BATCH, CAT };    /* what program we want to run */
                     73:
1.1       deraadt    74: /* File scope variables */
                     75: #ifndef lint
1.11    ! millert    76: static char rcsid[] = "$OpenBSD: at.c,v 1.10 1997/03/03 03:31:10 millert Exp $";
1.1       deraadt    77: #endif
                     78:
                     79: char *no_export[] =
                     80: {
                     81:        "TERM", "TERMCAP", "DISPLAY", "_"
                     82: };
                     83: static send_mail = 0;
                     84:
                     85: /* External variables */
1.7       millert    86:
1.1       deraadt    87: extern char **environ;
                     88: int fcreated;
                     89: char *namep;
                     90: char atfile[FILENAME_MAX];
                     91:
1.7       millert    92: char *atinput = (char *)0;     /* where to get input from */
1.1       deraadt    93: char atqueue = 0;              /* which queue to examine for jobs (atq) */
                     94: char atverify = 0;             /* verify time instead of queuing job */
                     95:
                     96: /* Function declarations */
1.7       millert    97:
                     98: static void sigc       __P((int));
                     99: static void alarmc     __P((int));
1.1       deraadt   100: static char *cwdname   __P((void));
1.7       millert   101: static void writefile  __P((time_t, char));
1.1       deraadt   102: static void list_jobs  __P((void));
                    103:
                    104: /* Signal catching functions */
                    105:
                    106: static void
                    107: sigc(signo)
                    108:        int signo;
                    109: {
1.7       millert   110:        /* If the user presses ^C, remove the spool file and exit. */
1.1       deraadt   111:        if (fcreated) {
                    112:                PRIV_START
1.7       millert   113:                (void)unlink(atfile);
1.1       deraadt   114:                PRIV_END
                    115:        }
                    116:
                    117:        exit(EXIT_FAILURE);
                    118: }
                    119:
                    120: static void
                    121: alarmc(signo)
                    122:        int signo;
                    123: {
1.7       millert   124:        /* Time out after some seconds. */
1.1       deraadt   125:        panic("File locking timed out");
                    126: }
                    127:
                    128: /* Local functions */
                    129:
                    130: static char *
                    131: cwdname()
                    132: {
1.7       millert   133:        /*
                    134:         * Read in the current directory; the name will be overwritten on
                    135:         * subsequent calls.
                    136:         */
                    137:        static char path[MAXPATHLEN];
1.1       deraadt   138:
1.7       millert   139:        return (getcwd(path, sizeof(path)));
                    140: }
1.1       deraadt   141:
1.7       millert   142: static int
                    143: nextjob()
                    144: {
                    145:        int jobno;
                    146:        FILE *fid;
1.1       deraadt   147:
1.7       millert   148:        if ((fid = fopen(_PATH_SEQFILE, "r+")) != (FILE*)0) {
                    149:                if (fscanf(fid, "%5x", &jobno) == 1) {
                    150:                        (void)rewind(fid);
                    151:                        jobno = (1+jobno) % 0xfffff;    /* 2^20 jobs enough? */
                    152:                        (void)fprintf(fid, "%05x\n", jobno);
                    153:                } else
                    154:                        jobno = EOF;
                    155:                (void)fclose(fid);
                    156:                return (jobno);
                    157:        } else if ((fid = fopen(_PATH_SEQFILE, "w")) != (FILE*)0) {
                    158:                (void)fprintf(fid, "%05x\n", jobno = 1);
                    159:                (void)fclose(fid);
                    160:                return (1);
1.1       deraadt   161:        }
1.7       millert   162:        return (EOF);
1.1       deraadt   163: }
                    164:
                    165: static void
                    166: writefile(runtimer, queue)
                    167:        time_t runtimer;
                    168:        char queue;
                    169: {
                    170:        /*
                    171:         * This does most of the work if at or batch are invoked for
                    172:         * writing a job.
                    173:         */
1.7       millert   174:        int jobno;
1.1       deraadt   175:        char *ap, *ppos, *mailname;
                    176:        struct passwd *pass_entry;
                    177:        struct stat statbuf;
                    178:        int fdes, lockdes, fd2;
                    179:        FILE *fp, *fpin;
                    180:        struct sigaction act;
                    181:        char **atenv;
                    182:        int ch;
                    183:        mode_t cmask;
                    184:        struct flock lock;
                    185:
1.7       millert   186:        (void)setlocale(LC_TIME, "");
                    187:
1.1       deraadt   188:        /*
                    189:         * Install the signal handler for SIGINT; terminate after removing the
                    190:         * spool file if necessary
                    191:         */
                    192:        act.sa_handler = sigc;
                    193:        sigemptyset(&(act.sa_mask));
                    194:        act.sa_flags = 0;
                    195:
                    196:        sigaction(SIGINT, &act, NULL);
                    197:
1.7       millert   198:        (void)strcpy(atfile, _PATH_ATJOBS);
                    199:        ppos = atfile + strlen(atfile);
1.1       deraadt   200:
                    201:        /*
                    202:         * Loop over all possible file names for running something at this
1.7       millert   203:         * particular time, see if a file is there; the first empty slot at
                    204:         * any particular time is used.  Lock the file _PATH_LOCKFILE first
                    205:         * to make sure we're alone when doing this.
1.1       deraadt   206:         */
                    207:
                    208:        PRIV_START
                    209:
1.7       millert   210:        if ((lockdes = open(_PATH_LOCKFILE, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR)) < 0)
1.1       deraadt   211:                perr2("Cannot open lockfile ", _PATH_LOCKFILE);
                    212:
                    213:        lock.l_type = F_WRLCK;
                    214:        lock.l_whence = SEEK_SET;
                    215:        lock.l_start = 0;
                    216:        lock.l_len = 0;
                    217:
                    218:        act.sa_handler = alarmc;
                    219:        sigemptyset(&(act.sa_mask));
                    220:        act.sa_flags = 0;
                    221:
                    222:        /*
                    223:         * Set an alarm so a timeout occurs after ALARMC seconds, in case
                    224:         * something is seriously broken.
                    225:         */
                    226:        sigaction(SIGALRM, &act, NULL);
                    227:        alarm(ALARMC);
                    228:        fcntl(lockdes, F_SETLKW, &lock);
                    229:        alarm(0);
                    230:
1.7       millert   231:        if ((jobno = nextjob()) == EOF)
                    232:            perr("Cannot generate job number");
                    233:
1.8       millert   234:        (void)snprintf(ppos, sizeof(atfile) - (ppos - atfile),
                    235:            "%c%5x%8x", queue, jobno, (unsigned) (runtimer/60));
1.1       deraadt   236:
1.7       millert   237:        for (ap = ppos; *ap != '\0'; ap++)
                    238:                if (*ap == ' ')
                    239:                        *ap = '0';
                    240:
                    241:        if (stat(atfile, &statbuf) != 0)
                    242:                if (errno != ENOENT)
                    243:                        perr2("Cannot access ", _PATH_ATJOBS);
1.1       deraadt   244:
                    245:        /*
                    246:         * Create the file. The x bit is only going to be set after it has
                    247:         * been completely written out, to make sure it is not executed in
                    248:         * the meantime.  To make sure they do not get deleted, turn off
                    249:         * their r bit.  Yes, this is a kluge.
                    250:         */
                    251:        cmask = umask(S_IRUSR | S_IWUSR | S_IXUSR);
1.8       millert   252:        if ((fdes = open(atfile, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR)) == -1)
1.1       deraadt   253:                perr("Cannot create atjob file");
                    254:
                    255:        if ((fd2 = dup(fdes)) < 0)
                    256:                perr("Error in dup() of job file");
                    257:
1.7       millert   258:        if (fchown(fd2, real_uid, real_gid) != 0)
1.1       deraadt   259:                perr("Cannot give away file");
                    260:
                    261:        PRIV_END
                    262:
                    263:        /*
                    264:         * We've successfully created the file; let's set the flag so it
                    265:         * gets removed in case of an interrupt or error.
                    266:         */
                    267:        fcreated = 1;
                    268:
                    269:        /* Now we can release the lock, so other people can access it */
                    270:        lock.l_type = F_UNLCK;
                    271:        lock.l_whence = SEEK_SET;
                    272:        lock.l_start = 0;
                    273:        lock.l_len = 0;
1.7       millert   274:        (void)fcntl(lockdes, F_SETLKW, &lock);
                    275:        (void)close(lockdes);
1.1       deraadt   276:
                    277:        if ((fp = fdopen(fdes, "w")) == NULL)
                    278:                panic("Cannot reopen atjob file");
                    279:
                    280:        /*
1.5       millert   281:         * Get the userid to mail to, first by trying getlogin(), which reads
                    282:         * /etc/utmp, then from $LOGNAME or $USER, finally from getpwuid().
1.1       deraadt   283:         */
                    284:        mailname = getlogin();
1.5       millert   285:        if (mailname == NULL && (mailname = getenv("LOGNAME")) == NULL)
                    286:                mailname = getenv("USER");
1.1       deraadt   287:
1.7       millert   288:        if ((mailname == NULL) || (mailname[0] == '\0') ||
                    289:            (strlen(mailname) > LOGNAMESIZE) || (getpwnam(mailname) == NULL)) {
                    290:                pass_entry = getpwuid(real_uid);
1.1       deraadt   291:                if (pass_entry != NULL)
                    292:                        mailname = pass_entry->pw_name;
                    293:        }
                    294:
                    295:        if (atinput != (char *) NULL) {
                    296:                fpin = freopen(atinput, "r", stdin);
                    297:                if (fpin == NULL)
                    298:                        perr("Cannot open input file");
                    299:        }
1.7       millert   300:        (void)fprintf(fp, "#!/bin/sh\n# atrun uid=%u gid=%u\n# mail %*s %d\n",
                    301:            real_uid, real_gid, LOGNAMESIZE, mailname, send_mail);
1.1       deraadt   302:
                    303:        /* Write out the umask at the time of invocation */
1.7       millert   304:        (void)fprintf(fp, "umask %o\n", cmask);
1.1       deraadt   305:
                    306:        /*
                    307:         * Write out the environment. Anything that may look like a special
                    308:         * character to the shell is quoted, except for \n, which is done
                    309:         * with a pair of "'s.  Dont't export the no_export list (such as
                    310:         * TERM or DISPLAY) because we don't want these.
                    311:         */
                    312:        for (atenv = environ; *atenv != NULL; atenv++) {
                    313:                int export = 1;
                    314:                char *eqp;
                    315:
                    316:                eqp = strchr(*atenv, '=');
                    317:                if (ap == NULL)
                    318:                        eqp = *atenv;
                    319:                else {
                    320:                        int i;
                    321:
                    322:                        for (i = 0;i < sizeof(no_export) /
                    323:                            sizeof(no_export[0]); i++) {
                    324:                                export = export
                    325:                                    && (strncmp(*atenv, no_export[i],
                    326:                                        (size_t) (eqp - *atenv)) != 0);
                    327:                        }
                    328:                        eqp++;
                    329:                }
                    330:
                    331:                if (export) {
1.7       millert   332:                        (void)fwrite(*atenv, sizeof(char), eqp - *atenv, fp);
1.1       deraadt   333:                        for (ap = eqp; *ap != '\0'; ap++) {
                    334:                                if (*ap == '\n')
1.7       millert   335:                                        (void)fprintf(fp, "\"\n\"");
1.1       deraadt   336:                                else {
1.7       millert   337:                                        if (!isalnum(*ap)) {
                    338:                                                switch (*ap) {
                    339:                                                case '%': case '/': case '{':
                    340:                                                case '[': case ']': case '=':
                    341:                                                case '}': case '@': case '+':
                    342:                                                case '#': case ',': case '.':
                    343:                                                case ':': case '-': case '_':
                    344:                                                        break;
                    345:                                                default:
                    346:                                                        (void)fputc('\\', fp);
                    347:                                                        break;
                    348:                                                }
                    349:                                        }
                    350:                                        (void)fputc(*ap, fp);
1.1       deraadt   351:                                }
                    352:                        }
1.7       millert   353:                        (void)fputs("; export ", fp);
                    354:                        (void)fwrite(*atenv, sizeof(char), eqp - *atenv - 1, fp);
                    355:                        (void)fputc('\n', fp);
                    356:                }
                    357:        }
                    358:        /*
                    359:         * Cd to the directory at the time and write out all the
                    360:         * commands the user supplies from stdin.
                    361:         */
                    362:        (void)fputs("cd ", fp);
                    363:        for (ap = cwdname(); *ap != '\0'; ap++) {
                    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
                    406: list_jobs()
                    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:
                    424:        PRIV_START
                    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);
                    454:                strftime(timestr, TIMESIZE, "%X %x", &runtime);
                    455:                if (first) {
1.7       millert   456:                        (void)printf("Date\t\t\tOwner\tQueue\tJob#\n");
1.1       deraadt   457:                        first = 0;
                    458:                }
                    459:                pw = getpwuid(buf.st_uid);
                    460:
1.7       millert   461:                (void)printf("%s\t%s\t%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:        }
                    468:        PRIV_END
                    469: }
                    470:
                    471: static void
1.7       millert   472: process_jobs(argc, argv, what)
1.1       deraadt   473:        int argc;
                    474:        char **argv;
1.7       millert   475:        int what;
1.1       deraadt   476: {
                    477:        /* Delete every argument (job - ID) given */
                    478:        int i;
                    479:        struct stat buf;
1.7       millert   480:        DIR *spool;
                    481:        struct dirent *dirent;
                    482:        unsigned long ctm;
                    483:        char queue;
                    484:        int jobno;
1.9       millert   485:
1.1       deraadt   486:        PRIV_START
                    487:
1.7       millert   488:        if (chdir(_PATH_ATJOBS) != 0)
1.1       deraadt   489:                perr2("Cannot change to ", _PATH_ATJOBS);
                    490:
1.7       millert   491:        if ((spool = opendir(".")) == NULL)
                    492:                perr2("Cannot open ", _PATH_ATJOBS);
                    493:
                    494:        PRIV_END
                    495:
                    496:        /* Loop over every file in the directory */
                    497:        while((dirent = readdir(spool)) != NULL) {
                    498:
                    499:                PRIV_START
                    500:                if (stat(dirent->d_name, &buf) != 0)
                    501:                        perr2("Cannot stat in ", _PATH_ATJOBS);
                    502:                PRIV_END
                    503:
                    504:                if (sscanf(dirent->d_name, "%c%5x%8lx", &queue, &jobno, &ctm) !=3)
                    505:                        continue;
                    506:
                    507:                for (i = optind; i < argc; i++) {
                    508:                        if (atoi(argv[i]) == jobno) {
                    509:                                if ((buf.st_uid != real_uid) && !(real_uid == 0)) {
                    510:                                        (void)fprintf(stderr,
                    511:                                            "%s: Not owner\n", argv[i]);
                    512:                                        exit(EXIT_FAILURE);
                    513:                                }
                    514:                                switch (what) {
                    515:                                case ATRM:
                    516:                                        PRIV_START
                    517:
                    518:                                        if (unlink(dirent->d_name) != 0)
                    519:                                                perr(dirent->d_name);
                    520:
                    521:                                        PRIV_END
                    522:
                    523:                                        break;
                    524:
                    525:                                case CAT:
                    526:                                        {
                    527:                                                FILE *fp;
                    528:                                                int ch;
                    529:
                    530:                                                PRIV_START
                    531:
                    532:                                                fp = fopen(dirent->d_name, "r");
                    533:
                    534:                                                PRIV_END
                    535:
                    536:                                                if (!fp)
                    537:                                                        perr("Cannot open file");
                    538:
                    539:                                                while((ch = getc(fp)) != EOF)
                    540:                                                        putchar(ch);
                    541:                                        }
                    542:                                        break;
                    543:
                    544:                                default:
                    545:                                        (void)fprintf(stderr,
                    546:                                            "Internal error, process_jobs = %d\n",
                    547:                                            what);
                    548:                                        exit(EXIT_FAILURE);
                    549:                                        break;
                    550:                                }
                    551:                        }
1.1       deraadt   552:                }
                    553:        }
                    554: }                              /* delete_jobs */
                    555:
                    556: /* Global functions */
                    557:
                    558: int
                    559: main(argc, argv)
                    560:        int argc;
                    561:        char **argv;
                    562: {
                    563:        int c;
1.7       millert   564:        char queue = DEFAULT_AT_QUEUE;
                    565:        char queue_set = 0;
1.1       deraadt   566:        char *pgm;
                    567:
                    568:        enum {
1.7       millert   569:                ATQ, ATRM, AT, BATCH, CAT
                    570:        };                              /* what program we want to run */
                    571:        int program = AT;               /* our default program */
                    572:        char *options = "q:f:mvldbVc";  /* default options for at */
                    573:        int disp_version = 0;
1.1       deraadt   574:        time_t timer;
                    575:
                    576:        RELINQUISH_PRIVS
                    577:
                    578:        /* Eat any leading paths */
                    579:        if ((pgm = strrchr(argv[0], '/')) == NULL)
                    580:                pgm = argv[0];
                    581:        else
                    582:                pgm++;
                    583:
                    584:        namep = pgm;
                    585:
                    586:        /* find out what this program is supposed to do */
                    587:        if (strcmp(pgm, "atq") == 0) {
                    588:                program = ATQ;
1.7       millert   589:                options = "q:vV";
1.1       deraadt   590:        } else if (strcmp(pgm, "atrm") == 0) {
                    591:                program = ATRM;
1.7       millert   592:                options = "V";
1.1       deraadt   593:        } else if (strcmp(pgm, "batch") == 0) {
                    594:                program = BATCH;
1.7       millert   595:                options = "f:q:mvV";
1.1       deraadt   596:        }
                    597:
                    598:        /* process whatever options we can process */
                    599:        opterr = 1;
1.6       millert   600:        while ((c = getopt(argc, argv, options)) != -1)
1.1       deraadt   601:                switch (c) {
                    602:                case 'v':       /* verify time settings */
                    603:                        atverify = 1;
                    604:                        break;
                    605:
                    606:                case 'm':       /* send mail when job is complete */
                    607:                        send_mail = 1;
                    608:                        break;
                    609:
                    610:                case 'f':
                    611:                        atinput = optarg;
                    612:                        break;
                    613:
                    614:                case 'q':       /* specify queue */
                    615:                        if (strlen(optarg) > 1)
                    616:                                usage();
                    617:
                    618:                        atqueue = queue = *optarg;
1.7       millert   619:                        if (!(islower(queue) || isupper(queue)))
1.1       deraadt   620:                                usage();
1.7       millert   621:
                    622:                        queue_set = 1;
                    623:                        break;
                    624:
                    625:                case 'd':
                    626:                        if (program != AT)
                    627:                                usage();
                    628:
                    629:                        program = ATRM;
                    630:                        options = "V";
                    631:                        break;
                    632:
                    633:                case 'l':
                    634:                        if (program != AT)
                    635:                                usage();
                    636:
                    637:                        program = ATQ;
                    638:                        options = "q:vV";
                    639:                        break;
                    640:
                    641:                case 'b':
                    642:                        if (program != AT)
                    643:                                usage();
                    644:
                    645:                        program = BATCH;
                    646:                        options = "f:q:mvV";
                    647:                        break;
                    648:
                    649:                case 'V':
                    650:                        disp_version = 1;
                    651:                        break;
                    652:
                    653:                case 'c':
                    654:                        program = CAT;
                    655:                        options = "";
1.1       deraadt   656:                        break;
                    657:
                    658:                default:
                    659:                        usage();
                    660:                        break;
                    661:                }
                    662:        /* end of options eating */
                    663:
1.7       millert   664:        if (disp_version)
                    665:                (void)fprintf(stderr, "%s version %.1f\n", namep, AT_VERSION);
                    666:
                    667:        if (!check_permission()) {
                    668:                (void)fprintf(stderr, "You do not have permission to use %s.\n",
                    669:                    namep);
                    670:        }
                    671:
1.1       deraadt   672:        /* select our program */
                    673:        switch (program) {
                    674:        case ATQ:
1.10      millert   675:                if (optind != argc)
                    676:                        usage();
1.1       deraadt   677:                list_jobs();
                    678:                break;
                    679:
                    680:        case ATRM:
1.7       millert   681:        case CAT:
1.10      millert   682:                if (optind == argc)
                    683:                        usage();
1.11    ! millert   684:                process_jobs(argc, argv, program);
1.1       deraadt   685:                break;
                    686:
                    687:        case AT:
                    688:                timer = parsetime(argc, argv);
                    689:                if (atverify) {
                    690:                        struct tm *tm = localtime(&timer);
1.7       millert   691:                        (void)fprintf(stderr, "%s\n", asctime(tm));
1.1       deraadt   692:                }
                    693:                writefile(timer, queue);
                    694:                break;
                    695:
                    696:        case BATCH:
1.7       millert   697:                if (queue_set)
                    698:                        queue = toupper(queue);
                    699:                else
                    700:                        queue = DEFAULT_BATCH_QUEUE;
                    701:
                    702:                if (argc > optind)
                    703:                        timer = parsetime(argc, argv);
                    704:                else
                    705:                        timer = time(NULL);
                    706:
                    707:                if (atverify) {
                    708:                        struct tm *tm = localtime(&timer);
                    709:                        (void)fprintf(stderr, "%s\n", asctime(tm));
                    710:                }
                    711:
                    712:                writefile(timer, queue);
1.1       deraadt   713:                break;
                    714:
                    715:        default:
                    716:                panic("Internal error");
                    717:                break;
                    718:        }
                    719:        exit(EXIT_SUCCESS);
                    720: }