Annotation of 43BSDTahoe/usr.bin/at/at.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1983 Regents of the University of California.
                      3:  * All rights reserved.  The Berkeley software License Agreement
                      4:  * specifies the terms and conditions for redistribution.
                      5:  */
                      6: 
                      7: #ifndef lint
                      8: char copyright[] =
                      9: "@(#) Copyright (c) 1983 Regents of the University of California.\n\
                     10:  All rights reserved.\n";
                     11: #endif not lint
                     12: 
                     13: #ifndef lint
                     14: static char sccsid[] = "@(#)at.c       5.5 (Berkeley) 1/18/87";
                     15: #endif not lint
                     16: 
                     17: /*
                     18:  *     Synopsis:       at [-s] [-c] [-m] time [filename]
                     19:  *                                             
                     20:  * 
                     21:  *
                     22:  *     Execute commands at a later date.
                     23:  *
                     24:  *
                     25:  *     Modifications by:       Steve Wall
                     26:  *                             Computer Systems Research Group
                     27:  *                             University of California @ Berkeley
                     28:  *
                     29:  */
                     30: #include <stdio.h>
                     31: #include <ctype.h>
                     32: #include <signal.h>
                     33: #include <pwd.h>
                     34: #include <sys/param.h>
                     35: #include <sys/time.h>
                     36: #include <sys/file.h>
                     37: 
                     38: #define HOUR           100             /* 1 hour (using military time) */
                     39: #define HALFDAY                (12 * HOUR)     /* half a day (12 hours) */
                     40: #define FULLDAY                (24 * HOUR)     /* a full day (24 hours) */
                     41: 
                     42: #define WEEK           1               /* day requested is 'week' */
                     43: #define DAY            2               /* day requested is a weekday */
                     44: #define MONTH          3               /* day requested is a month */
                     45: 
                     46: #define BOURNE         "/bin/sh"       /* run commands with Bourne shell*/
                     47: #define CSHELL         "/bin/csh"      /* run commands with C shell */
                     48: 
                     49: #define NODATEFOUND    -1              /* no date was given on command line */
                     50: 
                     51: #define ATDIR          "/usr/spool/at"         /* spooling area */
                     52: 
                     53: #define LINSIZ         256             /* length of input buffer */
                     54: 
                     55: /*
                     56:  * A table to identify potential command line values for "time". 
                     57:  *
                     58:  * We need this so that we can do some decent error checking on the 
                     59:  * command line arguments. (This was inspired by the old "at", which 
                     60:  * accepted "at 900 jan 55" as valid input and other small bugs.
                     61:  */
                     62: struct datetypes {
                     63:        int type;
                     64:        char *name;
                     65: } dates_info[22] = {
                     66:        { DAY,   "sunday"    },
                     67:        { DAY,   "monday"    },
                     68:        { DAY,   "tuesday"   },
                     69:        { DAY,   "wednesday" },
                     70:        { DAY,   "thursday"  },
                     71:        { DAY,   "friday"    },
                     72:        { DAY,   "saturday"  },
                     73:        { MONTH, "january"   },
                     74:        { MONTH, "february"  },
                     75:        { MONTH, "march"     },
                     76:        { MONTH, "april"     },
                     77:        { MONTH, "may"       },
                     78:        { MONTH, "june"      },
                     79:        { MONTH, "july"      },
                     80:        { MONTH, "august"    },
                     81:        { MONTH, "september" },
                     82:        { MONTH, "october"   },
                     83:        { MONTH, "november"  },
                     84:        { MONTH, "december"  },
                     85:        { 0, ""},
                     86: };
                     87: 
                     88: /*
                     89:  * Months of the year.
                     90:  */
                     91: char *months[13] = {
                     92:        "jan", "feb", "mar", "apr", "may", "jun",
                     93:        "jul", "aug", "sep", "oct", "nov", "dec", 0,
                     94: };
                     95: 
                     96: /*
                     97:  * A table of the number of days in each month of the year.
                     98:  *
                     99:  *     yeartable[0] -- normal year
                    100:  *     yeartable[1] -- leap year
                    101:  */
                    102: static int yeartable[2][13] = {
                    103:        { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
                    104:        { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
                    105: };
                    106: 
                    107: /*
                    108:  * Structure holding the relevant values needed to create a spoolfile.
                    109:  * "attime" will contain the info about when a job is to be run, and
                    110:  * "nowtime" will contain info about what time the "at" command is in-
                    111:  * voked.
                    112:  */
                    113: struct times {
                    114:        int year;                       /* year that job is to be run */
                    115:        int yday;                       /* day of year that job is to be run */
                    116:        int mon;                        /* month of year that job is to be run*/
                    117:        int mday;                       /* day of month that job is to be run */
                    118:        int wday;                       /* day of week that job is to be run */
                    119:        int hour;                       /* hour of day that job is to be run */
                    120:        int min;                        /* min. of hour that job is to be run */
                    121: } attime, nowtime;
                    122: 
                    123: char   atfile[100];                    /* name of spoolfile "yy.ddd.hhhh.??" */
                    124: char   *getenv();                      /* get info on user's environment */
                    125: char   **environ;                      /* user's environment */
                    126: FILE   *spoolfile;                     /* spool file */
                    127: FILE   *inputfile;                     /* input file ("stdin" or "filename") */
                    128: char   *getwd();                       /* used to get current directory info */
                    129: 
                    130: 
                    131: main(argc, argv)
                    132: int argc;
                    133: char **argv;
                    134: {
                    135:        int c;                          /* scratch variable */
                    136:        int usage();                    /* print usage info and exit */
                    137:        int cleanup();                  /* do cleanup on an interrupt signal */
                    138:        int dateindex = NODATEFOUND;    /* if a day is specified, what option
                    139:                                           is it? (mon day, week, dayofweek) */
                    140:        char *shell = BOURNE;           /* what shell do we use to run job? */
                    141:        int shflag = 0;                 /* override the current shell and run
                    142:                                           job using the Bourne Shell */
                    143:        int cshflag = 0;                /* override the current shell and run 
                    144:                                           job using the Cshell */
                    145:        int mailflag = 0;               /* send mail after a job has been run?*/
                    146:        int standardin = 0;             /* are we reading from stardard input */
                    147:        char *tmp;                      /* scratch pointer */
                    148:        char line[LINSIZ];              /* a line from input file */
                    149:        char pwbuf[MAXPATHLEN];         /* the current working directory */
                    150:        char *jobfile = "stdin";        /* file containing job to be run */
                    151:        char *getname();                /* get the login name of a user */
                    152:        int pid;                        /* For forking for security reasons */
                    153: 
                    154: 
                    155: 
                    156:        argv++; argc--;
                    157: 
                    158:        /*
                    159:         * Interpret command line flags if they exist.
                    160:         */
                    161:        while (argc > 0 && **argv == '-') {
                    162:                (*argv)++;
                    163:                while (**argv) switch (*(*argv)++) {
                    164: 
                    165:                        case 'c' :      cshflag++; 
                    166:                                        shell = CSHELL;
                    167:                                        break;
                    168: 
                    169:                        case 's' :      shflag++;
                    170:                                        shell = BOURNE;
                    171:                                        break;
                    172: 
                    173:                        case 'm' :      mailflag++;
                    174:                                        break;
                    175: 
                    176:                        default  :      usage();
                    177: 
                    178:                }
                    179:                --argc, ++argv;
                    180:        }
                    181:        if (shflag && cshflag) {
                    182:                fprintf(stderr,"ambiguous shell request.\n");
                    183:                exit(1);
                    184:        }
                    185: 
                    186:        /*
                    187:         * Get the time it is when "at" is invoked. We set both nowtime and 
                    188:         * attime to this value so that as we interpret the time the job is to
                    189:         * be run we can compare the two values to determine such things as
                    190:         * whether of not the job should be run the same day the "at" command
                    191:         * is given, whether a job is to be run next year, etc.
                    192:         */
                    193:        getnowtime(&nowtime, &attime);
                    194: 
                    195: #ifdef DEBUG
                    196:        printit();
                    197: #endif
                    198: 
                    199:        if (argc <= 0)
                    200:                usage();
                    201: 
                    202:        /*
                    203:         * Interpret argv[1] and create the time of day that the job is to
                    204:         * be run. This is the same function that was used in the old "at"
                    205:         */
                    206:        maketime(&attime, *argv);
                    207:        --argc; ++argv;
                    208: 
                    209: #ifdef DEBUG
                    210:        printf("\n\nAFTER MAKETIME\n");
                    211:        printit();
                    212: #endif
                    213: 
                    214:        /*
                    215:         * If argv[(2)] exists, this is a request to run a job on a certain
                    216:         * day of year or a certain day of week.
                    217:         *
                    218:         * We send  argv to the function "getdateindex" which returns the 
                    219:         * index value of the requested day in the table "dates_info" 
                    220:         * (see line 50 for table). If 'getdateindex" returns a NODATEFOUND, 
                    221:         * then the requested day format was not found in the table (usually 
                    222:         * this means that the argument is a "filename"). If the requested 
                    223:         * day is found, we continue to process command line arguments.
                    224:         */
                    225:        if (argc > 0) {
                    226:                if ((dateindex = getdateindex(*argv)) != NODATEFOUND) {
                    227: 
                    228:                        ++argv; --argc;
                    229: 
                    230:                        /*
                    231:                         * Determine the day of year that the job will be run
                    232:                         * depending on the value of argv.
                    233:                         */
                    234:                        makedayofyear(dateindex, &argv, &argc);
                    235:                }
                    236:        }
                    237: 
                    238:        /*
                    239:         * If we get to this point and "dateindex" is set to NODATEFOUND,
                    240:         * then we are dealing with a request with only a "time" specified
                    241:         * (i.e. at 400p) and perhaps 'week' specified (i.e. at 400p week).
                    242:         * If 'week' is specified, we just set excecution for 7 days in the
                    243:         * future. Otherwise, we need to check to see if the requested time 
                    244:         * has already passed for the current day. If it has, then we add 
                    245:         * one to the day of year that the job will be executed.
                    246:         */
                    247:        if (dateindex == NODATEFOUND) {
                    248:                int daysinyear;
                    249:                if ((argc > 0) && (strcmp(*argv,"week") == 0)) {
                    250:                        attime.yday += 7;
                    251:                        ++argv; --argc;
                    252:                } else if (istomorrow())
                    253:                        ++attime.yday;
                    254: 
                    255:                daysinyear = isleap(attime.year) ? 366 : 365;
                    256:                if (attime.yday >= daysinyear) {
                    257:                        attime.yday -= daysinyear;
                    258:                        ++attime.year;
                    259:                }
                    260:        }
                    261: 
                    262:        /*
                    263:         * If no more arguments exist, then we are reading
                    264:         * from standard input. Thus, we set the standard
                    265:         * input flag (++standardin).
                    266:         */
                    267:        if (argc <= 0)
                    268:                ++standardin;
                    269: 
                    270: 
                    271: #ifdef DEBUG
                    272:        printf("\n\nAFTER ADDDAYS\n");
                    273:        printit();
                    274: #endif
                    275: 
                    276:        /*
                    277:         * Start off assuming we're going to read from standard input,
                    278:         * but if a filename has been given to read from, we will open it
                    279:         * later.
                    280:         */
                    281:        inputfile = stdin;
                    282: 
                    283:        /*
                    284:         * Create the filename for the spoolfile.
                    285:         */
                    286:        makeatfile(atfile,attime.year,attime.yday,attime.hour,attime.min);
                    287: 
                    288:        /*
                    289:         * Open the spoolfile for writing.
                    290:         */
                    291:        if ((spoolfile = fopen(atfile, "w")) == NULL){
                    292:                perror(atfile);
                    293:                exit(1);
                    294:        }
                    295: 
                    296:        /*
                    297:         * Make the file not world readable.
                    298:         */
                    299:        fchmod(fileno(spoolfile), 0400);
                    300: 
                    301:        /*
                    302:         * The protection mechanism works like this:
                    303:         * We are running ruid=user, euid=spool owner.  So far we have been
                    304:         * messing around in the spool directory, so we needed to run
                    305:         * as the owner of the spool directory.
                    306:         * We now need to switch to the user's effective uid
                    307:         * to simplify permission checking.  However, we fork first,
                    308:         * so that we can clean up if interrupted.
                    309:         */
                    310:        signal(SIGINT, SIG_IGN);
                    311:        pid = fork();
                    312:        if (pid == -1) {
                    313:                perror("fork");
                    314:                exit(1);
                    315:        }
                    316:        if (pid) {
                    317:                int wpid, status;
                    318: 
                    319:                /*
                    320:                 * We are the parent. If the kid has problems,
                    321:                 * cleanup the spool directory.
                    322:                 */
                    323:                wpid = wait(&status);
                    324:                if (wpid != pid || status) {
                    325:                        cleanup();
                    326:                        exit(1);
                    327:                }
                    328:                /*
                    329:                 * The kid should have alread flushed the buffers.
                    330:                 */
                    331:                _exit(0);
                    332:        }
                    333: 
                    334:        /*
                    335:         * Exit on interrupt.
                    336:         */
                    337:        signal(SIGINT, SIG_DFL);
                    338: 
                    339:        /*
                    340:         * We are the kid, give up special permissions.
                    341:         */
                    342:        setuid(getuid());
                    343: 
                    344:        /*
                    345:         * Open the input file with the user's permissions.
                    346:         */
                    347:        if (!standardin) {
                    348:                jobfile = *argv;
                    349:                if ((inputfile = fopen(jobfile, "r")) == NULL) {
                    350:                        perror(jobfile);
                    351:                        exit(1);
                    352:                }
                    353:        }
                    354: 
                    355:        /*
                    356:         * Determine what shell we should use to run the job. If the user
                    357:         * didn't explicitly request that his/her current shell be over-
                    358:         * ridden (shflag of cshflag) then we use the current shell.
                    359:         */
                    360:        if ((!shflag) && (!cshflag) && (getenv("SHELL") != NULL))
                    361:                shell = "$SHELL";
                    362: 
                    363:        /*
                    364:         * Put some standard information at the top of the spoolfile.
                    365:         * This info is used by the other "at"-oriented programs (atq,
                    366:         * atrm, atrun).
                    367:         */
                    368:        fprintf(spoolfile, "# owner: %.127s\n",getname(getuid()));
                    369:        fprintf(spoolfile, "# jobname: %.127s\n",jobfile);
                    370:        fprintf(spoolfile, "# shell: sh\n");
                    371:        fprintf(spoolfile, "# notify by mail: %s\n",(mailflag) ? "yes" : "no");
                    372:        fprintf(spoolfile, "\n");
                    373: 
                    374:        /*
                    375:         * Set the modes for any files created by the job being run.
                    376:         */
                    377:        c = umask(0);
                    378:        umask(c);
                    379:        fprintf(spoolfile, "umask %.1o\n", c);
                    380: 
                    381:        /*
                    382:         * Get the current working directory so we know what directory to 
                    383:         * run the job from.
                    384:         */
                    385:        if (getwd(pwbuf) == NULL) {
                    386:                fprintf(stderr, "at: can't get working directory\n");
                    387:                exit(1);
                    388:        }
                    389:        fprintf(spoolfile, "cd %s\n", pwbuf);
                    390: 
                    391:        /*
                    392:         * Copy the user's environment to the spoolfile.
                    393:         */
                    394:        if (environ) {
                    395:                copyenvironment(&spoolfile);
                    396:        }
                    397: 
                    398:        /*
                    399:         * Put in a line to run the proper shell using the rest of
                    400:         * the file as input.  Note that 'exec'ing the shell will
                    401:         * cause sh() to leave a /tmp/sh### file around.  This line
                    402:         * depends on the shells allowing EOF to end tagged input.  The
                    403:         * quotes also guarantee a quoting of the lines before EOF.
                    404:         */
                    405:        fprintf(spoolfile, "%s << 'QAZWSXEDCRFVTGBYHNUJMIKOLP'\n", shell);
                    406: 
                    407:        /*
                    408:         * Now that we have all the files set up, we can start reading in
                    409:         * the job.
                    410:         */
                    411:        while (fgets(line, LINSIZ, inputfile) != NULL)
                    412:                fputs(line, spoolfile);
                    413: 
                    414:        /*
                    415:         * Close all files and change the mode of the spoolfile.
                    416:         */
                    417:        fclose(inputfile);
                    418:        fclose(spoolfile);
                    419: 
                    420:        exit(0);
                    421: 
                    422: }
                    423: 
                    424: /*
                    425:  * Copy the user's environment to the spoolfile in the syntax of the
                    426:  * Bourne shell.  After the environment is set up, the proper shell
                    427:  * will be invoked.
                    428:  */
                    429: copyenvironment(spoolfile)
                    430: FILE **spoolfile;
                    431: {
                    432:        char *tmp;                      /* scratch pointer */
                    433:        char **environptr = environ;    /* pointer to an environment setting */
                    434: 
                    435:        while(*environptr) {
                    436:                tmp = *environptr;
                    437: 
                    438:                /*
                    439:                 * We don't want the termcap or terminal entry so skip them.
                    440:                 */
                    441:                if ((strncmp(tmp,"TERM=",5) == 0) ||
                    442:                    (strncmp(tmp,"TERMCAP=",8) == 0)) {
                    443:                        ++environptr;
                    444:                        continue;
                    445:                }
                    446: 
                    447:                /*
                    448:                 * Set up the proper syntax.
                    449:                 */
                    450:                while (*tmp != '=')
                    451:                        fputc(*tmp++,*spoolfile);
                    452:                fputc('=', *spoolfile);
                    453:                fputc('\'' , *spoolfile);
                    454:                ++tmp;
                    455: 
                    456:                /*
                    457:                 * Now copy the entry.
                    458:                 */
                    459:                while (*tmp) {
                    460:                        if (*tmp == '\'')
                    461:                                fputs("'\\''", *spoolfile);
                    462:                        else if (*tmp == '\n')
                    463:                                fputs("\\",*spoolfile);
                    464:                        else
                    465:                                fputc(*tmp, *spoolfile);
                    466:                        ++tmp;
                    467:                }
                    468:                fputc('\'' , *spoolfile);
                    469: 
                    470:                /*
                    471:                 * We need to "export" environment settings.
                    472:                 */
                    473:                fprintf(*spoolfile, "\nexport ");
                    474:                tmp = *environptr;
                    475:                while (*tmp != '=')
                    476:                        fputc(*tmp++,*spoolfile);
                    477:                fputc('\n',*spoolfile);
                    478:                ++environptr;
                    479:        }
                    480:        return;
                    481: }
                    482: 
                    483: /*
                    484:  * Create the filename for the spoolfile. The format is "yy.ddd.mmmm.??"
                    485:  * where "yy" is the year the job will be run, "ddd" the day of year, 
                    486:  * "mmmm" the hour and minute, and "??" a scratch value used to dis-
                    487:  * tinguish between two files that are to be run at the same time.
                    488:  */
                    489: makeatfile(atfile,year,dayofyear,hour,minute)
                    490: int year;
                    491: int hour;
                    492: int minute;
                    493: int dayofyear;
                    494: char *atfile;
                    495: {
                    496:        int i;                          /* scratch variable */
                    497: 
                    498:        for (i=0; ; i += 53) {
                    499:                sprintf(atfile, "%s/%02d.%03d.%02d%02d.%02d", ATDIR, year,
                    500:                        dayofyear, hour, minute, (getpid() + i) % 100);
                    501: 
                    502:                /*
                    503:                 * Make sure that the file name that we've created is unique.
                    504:                 */
                    505:                if (access(atfile, F_OK) == -1)
                    506:                        return;
                    507:        }
                    508: }
                    509: 
                    510: /*
                    511:  * Has the requested time already passed for the currrent day? If so, we
                    512:  * will run the job "tomorrow".
                    513:  */
                    514: istomorrow()
                    515: {
                    516:        if (attime.hour < nowtime.hour)
                    517:                return(1);
                    518:        if ((attime.hour == nowtime.hour) && (attime.min < nowtime.min))
                    519:                return(1);
                    520: 
                    521:        return(0);
                    522: }
                    523: 
                    524: /*
                    525:  * Debugging wreckage.
                    526:  */
                    527: printit()
                    528: {
                    529:        printf("YEAR\tnowtime: %d\tattime: %d\n",nowtime.year,attime.year);
                    530:        printf("YDAY\tnowtime: %d\tattime: %d\n",nowtime.yday,attime.yday);
                    531:        printf("MON\tnowtime: %d\tattime: %d\n",nowtime.mon,attime.mon);
                    532:        printf("MONDAY\tnowtime: %d\tattime: %d\n",nowtime.mday,attime.mday);
                    533:        printf("WDAY\tnowtime: %d\tattime: %d\n",nowtime.wday,attime.wday);
                    534:        printf("HOUR\tnowtime: %d\tattime: %d\n",nowtime.hour,attime.hour);
                    535:        printf("MIN\tnowtime: %d\tattime: %d\n",nowtime.min,attime.min);
                    536: }
                    537: 
                    538: /*
                    539:  * Calculate the day of year that the job will be executed.
                    540:  * The av,ac arguments are ptrs to argv,argc; updated as necessary.
                    541:  */
                    542: makedayofyear(dateindex, av, ac)
                    543: int dateindex;
                    544: char ***av;
                    545: int *ac;
                    546: {
                    547:        char **argv = *av;      /* imitate argc,argv and update args at end */
                    548:        int argc = *ac;
                    549:        char *ptr;                              /* scratch pointer */
                    550:        struct datetypes *daterequested;        /* pointer to information about
                    551:                                                   the type of date option
                    552:                                                   we're dealing with */
                    553: 
                    554:        daterequested = &dates_info[dateindex];
                    555: 
                    556:        /*
                    557:         * If we're dealing with a day of week, determine the number of days
                    558:         * in the future the next day of this type will fall on. Add this
                    559:         * value to "attime.yday".
                    560:         */
                    561:        if (daterequested->type == DAY) {
                    562:                if (attime.wday < dateindex) 
                    563:                        attime.yday += dateindex - attime.wday;
                    564:                else if(attime.wday > dateindex) 
                    565:                        attime.yday += (7 - attime.wday) + dateindex;
                    566:                else attime.yday += 7;
                    567:        }
                    568: 
                    569:        /*
                    570:         * If we're dealing with a month and day of month, determine the
                    571:         * day of year that this date will fall on.
                    572:         */
                    573:        if (daterequested->type == MONTH) {
                    574: 
                    575:                /*
                    576:                 * If a day of month isn't specified, print a message
                    577:                 * and exit.
                    578:                 */
                    579:                if (argc <= 0) {
                    580:                        fprintf(stderr,"day of month not specified.\n");
                    581:                        exit(1);
                    582:                }
                    583: 
                    584:                /*
                    585:                 * Scan the day of month value and make sure that it
                    586:                 * has no characters in it. If characters are found or
                    587:                 * the day requested is zero, print a message and exit.
                    588:                 */
                    589:                ptr = *argv;
                    590:                while (isdigit(*ptr))
                    591:                        ++ptr;
                    592:                if ((*ptr != '\0') || (atoi(*argv) == 0)) {
                    593:                        fprintf(stderr,"\"%s\": illegal day of month\n",*argv);
                    594:                        exit(1);
                    595:                }
                    596: 
                    597:                /*
                    598:                 * Set the month of year and day of month values. Since
                    599:                 * the first 7 values in our dateinfo table do not deal
                    600:                 * with month names, we subtract 7 from the month of year
                    601:                 * value.
                    602:                 */
                    603:                attime.mon = (dateindex - 7);
                    604:                attime.mday = (atoi(*argv) - 1);
                    605: 
                    606:                /*
                    607:                 * Test the day of month value to make sure that the
                    608:                 * value is legal.
                    609:                 */
                    610:                if ((attime.mday + 1) > 
                    611:                    yeartable[isleap(attime.year)][attime.mon + 1]) {
                    612:                        fprintf(stderr,"\"%s\": illegal day of month\n",*argv);
                    613:                        exit(1);
                    614:                }
                    615: 
                    616:                /*
                    617:                 * Finally, we determine the day of year.
                    618:                 */
                    619:                attime.yday = (countdays());
                    620:                ++argv; --argc;
                    621:        }
                    622: 
                    623:        /*
                    624:         * If 'week' is specified, add 7 to the day of year.
                    625:         */
                    626:        if ((argc > 0) && (strcmp(*argv,"week") == 0)) {
                    627:                attime.yday += 7;
                    628:                ++argv; --argc;
                    629:        }
                    630: 
                    631:        /*
                    632:         * Now that all that is done, see if the requested execution time
                    633:         * has already passed for this year, and if it has, set execution
                    634:         * for next year.
                    635:         */
                    636:        if (isnextyear())
                    637:                ++attime.year;
                    638:        
                    639:        /*
                    640:         * Finally, reflect the updated argc,argv to the caller
                    641:         */
                    642:        *av = argv;
                    643:        *ac = argc;
                    644: }
                    645: 
                    646: /*
                    647:  * Should the job be run next year? We check for the following situations:
                    648:  *
                    649:  *     1) the requested time has already passed for the current year. 
                    650:  *     2) the day of year is greater than the number of days in the year. 
                    651:  *
                    652:  * If either of these tests succeed, we increment "attime.year" by 1. 
                    653:  * If #2 is true, we also subtract the number of days in the current year
                    654:  * from "attime.yday". #2 can only occur if someone specifies a job to
                    655:  * be run "tomorrow" on Dec. 31 or if they specify a job to be run a
                    656:  * 'week' later and the date is at least Dec. 24. (I think so anyway)
                    657:  */
                    658: isnextyear()
                    659: {      register daysinyear;
                    660:        if (attime.yday < nowtime.yday)
                    661:                return(1);
                    662: 
                    663:        if ((attime.yday == nowtime.yday) && (attime.hour < nowtime.hour))
                    664:                return(1);
                    665: 
                    666:        daysinyear = isleap(attime.year) ? 366 : 365;
                    667:        if (attime.yday >= daysinyear) {
                    668:                attime.yday -= daysinyear;
                    669:                return(1);
                    670:        }
                    671:        if (attime.yday > (isleap(attime.year) ? 366 : 365)) {
                    672:                attime.yday -= (isleap(attime.year) ? 366 : 365);
                    673:                return(1);
                    674:        }
                    675: 
                    676:        return(0);
                    677: }
                    678: 
                    679: /*
                    680:  * Determine the day of year given a month and day of month value.
                    681:  */
                    682: countdays()
                    683: {
                    684:        int leap;                       /* are we dealing with a leap year? */
                    685:        int dayofyear;                  /* the day of year after conversion */
                    686:        int monthofyear;                /* the month of year that we are
                    687:                                           dealing with */
                    688: 
                    689:        /*
                    690:         * Are we dealing with a leap year?
                    691:         */
                    692:        leap = isleap(attime.year);
                    693: 
                    694:        monthofyear = attime.mon;
                    695:        dayofyear = attime.mday;
                    696: 
                    697:        /*
                    698:         * Determine the day of year.
                    699:         */
                    700:        while (monthofyear > 0)
                    701:                dayofyear += yeartable[leap][monthofyear--];
                    702: 
                    703:        return(dayofyear);
                    704: }
                    705: 
                    706: /*
                    707:  * Is a year a leap year?
                    708:  */
                    709: isleap(year)
                    710: int year;
                    711: 
                    712: {
                    713:        return((year%4 == 0 && year%100 != 0) || year%100 == 0);
                    714: }
                    715: 
                    716: getdateindex(date)
                    717: char *date;
                    718: {
                    719:        int i = 0;
                    720:        struct datetypes *ptr;
                    721: 
                    722:        ptr = dates_info;
                    723: 
                    724:        for (ptr = dates_info; ptr->type != 0; ptr++, i++) {
                    725:                if (isprefix(date, ptr->name))
                    726:                        return(i);
                    727:        }
                    728:        return(NODATEFOUND);
                    729: }
                    730: 
                    731: isprefix(prefix, fullname)
                    732: char *prefix, *fullname;
                    733: {
                    734:        char ch;
                    735:        char *ptr;
                    736:        char *ptr1;
                    737: 
                    738:        ptr = prefix;
                    739:        ptr1 = fullname;
                    740: 
                    741:        while (*ptr) {
                    742:                ch = *ptr;
                    743:                if (isupper(ch))
                    744:                        ch = tolower(ch);
                    745: 
                    746:                if (ch != *ptr1++)
                    747:                        return(0);
                    748: 
                    749:                ++ptr;
                    750:        }
                    751:        return(1);
                    752: }
                    753: 
                    754: getnowtime(nowtime, attime)
                    755: struct times *nowtime;
                    756: struct times *attime;
                    757: {
                    758:        struct tm *now;
                    759:        struct timeval time;
                    760:        struct timezone zone;
                    761: 
                    762:        if (gettimeofday(&time,&zone) < 0) {
                    763:                perror("gettimeofday");
                    764:                exit(1);
                    765:        }
                    766:        now = localtime(&time.tv_sec);
                    767: 
                    768:        attime->year = nowtime->year = now->tm_year;
                    769:        attime->yday = nowtime->yday = now->tm_yday;
                    770:        attime->mon = nowtime->mon = now->tm_mon;
                    771:        attime->mday = nowtime->mday = now->tm_mday;
                    772:        attime->wday = nowtime->wday = now->tm_wday;
                    773:        attime->hour = nowtime->hour = now->tm_hour;
                    774:        attime->min = nowtime->min = now->tm_min;
                    775: }
                    776: 
                    777: /*
                    778:  * This is the same routine used in the old "at", so I won't bother
                    779:  * commenting it. It'll give you an idea of what the code looked
                    780:  * like when I got it.
                    781:  */
                    782: maketime(attime,ptr)
                    783: char *ptr;
                    784: struct times *attime;
                    785: {
                    786:        int val;
                    787:        char *p;
                    788: 
                    789:        p = ptr;
                    790:        val = 0;
                    791:        while(isdigit(*p)) {
                    792:                val = val*10+(*p++ -'0');
                    793:        }
                    794:        if (p-ptr < 3)
                    795:                val *= HOUR;
                    796: 
                    797:        for (;;) {
                    798:                switch(*p) {
                    799: 
                    800:                case ':':
                    801:                        ++p;
                    802:                        if (isdigit(*p)) {
                    803:                                if (isdigit(p[1])) {
                    804:                                        val +=(10* *p + p[1] - 11*'0');
                    805:                                        p += 2;
                    806:                                        continue;
                    807:                                }
                    808:                        }
                    809:                        fprintf(stderr, "bad time format:\n");
                    810:                        exit(1);
                    811: 
                    812:                case 'A':
                    813:                case 'a':
                    814:                        if (val >= HALFDAY+HOUR)
                    815:                                val = FULLDAY+1;  /* illegal */
                    816:                        if (val >= HALFDAY && val <(HALFDAY+HOUR))
                    817:                                val -= HALFDAY;
                    818:                        break;
                    819: 
                    820:                case 'P':
                    821:                case 'p':
                    822:                        if (val >= HALFDAY+HOUR)
                    823:                                val = FULLDAY+1;  /* illegal */
                    824:                        if (val < HALFDAY)
                    825:                                val += HALFDAY;
                    826:                        break;
                    827: 
                    828:                case 'n':
                    829:                case 'N':
                    830:                        if ((val == 0) || (val == HALFDAY))
                    831:                                val = HALFDAY;
                    832:                        else
                    833:                                val = FULLDAY+1;  /* illegal */
                    834:                        break;
                    835: 
                    836:                case 'M':
                    837:                case 'm':
                    838:                        if ((val == 0) || (val == HALFDAY))
                    839:                                val = 0;
                    840:                        else
                    841:                                val = FULLDAY+1;  /* illegal */
                    842:                        break;
                    843: 
                    844: 
                    845:                case '\0':
                    846:                case ' ':
                    847:                        /* 24 hour time */
                    848:                        if (val == FULLDAY)
                    849:                                val -= FULLDAY;
                    850:                        break;
                    851: 
                    852:                default:
                    853:                        fprintf(stderr, "bad time format\n");
                    854:                        exit(1);
                    855: 
                    856:                }
                    857:                break;
                    858:        }
                    859:        if (val < 0 || val >= FULLDAY) {
                    860:                fprintf(stderr, "time out of range\n");
                    861:                exit(1);
                    862:        }
                    863:        if (val%HOUR >= 60) {
                    864:                fprintf(stderr, "illegal minute field\n");
                    865:                exit(1);
                    866:        }
                    867:        attime->hour = val/HOUR;
                    868:        attime->min = val%HOUR;
                    869: }
                    870: 
                    871: /*
                    872:  * Get the full login name of a person using his/her user id.
                    873:  */
                    874: char *
                    875: getname(uid)
                    876: int uid;
                    877: {
                    878:        struct passwd *pwdinfo;                 /* password info structure */
                    879:        char *logname, *getlogin();
                    880: 
                    881:        logname = getlogin();
                    882:        if (logname == NULL || (pwdinfo = getpwnam(logname)) == NULL ||
                    883:            pwdinfo->pw_uid != uid)
                    884:                pwdinfo = getpwuid(uid);
                    885:        if (pwdinfo == 0) {
                    886:                fprintf(stderr, "no name for uid %d?\n", uid);
                    887:                exit(1);
                    888:        }
                    889:        return(pwdinfo->pw_name);
                    890: }
                    891: 
                    892: /*
                    893:  * Do general cleanup.
                    894:  */
                    895: cleanup()
                    896: {
                    897:        if (unlink(atfile) == -1)
                    898:                perror(atfile);
                    899:        exit(1);
                    900: }
                    901: 
                    902: /*
                    903:  * Print usage info and exit.
                    904:  */
                    905: usage()
                    906: {
                    907:        fprintf(stderr,"usage: at [-csm] time [date] [filename]\n");
                    908:        exit(1);
                    909: }
                    910: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.