Annotation of 43BSD/usr.bin/at/at.c, revision 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.4 (Berkeley) 5/28/86";
        !            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=daemon.  So far we have been
        !           304:         * messing around in the spool directory, so we needed the
        !           305:         * daemon stuff.  Now, we want to read the users file,
        !           306:         * so we must give up the daemon protection,  but we might
        !           307:         * need the daemon's protection if the user interrupts and
        !           308:         * we need to remove the spool files.
        !           309:         * So, we fork and let the kid set the real and effective
        !           310:         * user id's to the user, so he can read everything of his
        !           311:         * own, but not his professor's final exam and not stuff
        !           312:         * owned by daemon.  If the kid exits with non-zero status,
        !           313:         * that means that the user typed interrupt, and the parent
        !           314:         * (still with daemon permissions) removes the spool file.
        !           315:         */
        !           316:        signal(SIGINT, SIG_IGN);
        !           317:        pid = fork();
        !           318:        if (pid == -1) {
        !           319:                perror("fork");
        !           320:                exit(1);
        !           321:        }
        !           322:        if (pid) {
        !           323:                int wpid, status;
        !           324: 
        !           325:                /*
        !           326:                 * We are the parent. If the kid has problems,
        !           327:                 * cleanup the spool directory.
        !           328:                 */
        !           329:                wpid = wait(&status);
        !           330:                if (wpid != pid || status) {
        !           331:                        cleanup();
        !           332:                        exit(1);
        !           333:                }
        !           334:                /*
        !           335:                 * The kid should have alread flushed the buffers.
        !           336:                 */
        !           337:                _exit(0);
        !           338:        }
        !           339: 
        !           340:        /*
        !           341:         * Exit on interrupt.
        !           342:         */
        !           343:        signal(SIGINT, SIG_DFL);
        !           344: 
        !           345:        /*
        !           346:         * We are the kid, give up daemon permissions.
        !           347:         */
        !           348:        setuid(getuid());
        !           349: 
        !           350:        /*
        !           351:         * Open the input file with the user's permissions.
        !           352:         */
        !           353:        if (!standardin) {
        !           354:                jobfile = *argv;
        !           355:                if ((inputfile = fopen(jobfile, "r")) == NULL) {
        !           356:                        perror(jobfile);
        !           357:                        exit(1);
        !           358:                }
        !           359:        }
        !           360:                
        !           361:        /*
        !           362:         * If the inputfile is not from a tty then turn off standardin
        !           363:         * If the inputfile is a tty, put out a prompt now, instead of
        !           364:         * waiting for a lot of file activity to complete.
        !           365:         */
        !           366:        if (!(isatty(fileno(inputfile)))) 
        !           367:                standardin = 0 ;
        !           368:        if (standardin) {
        !           369:                fputs("at> ", stdout);
        !           370:                fflush(stdout);
        !           371:        }
        !           372: 
        !           373:        /*
        !           374:         * Determine what shell we should use to run the job. If the user
        !           375:         * didn't explicitly request that his/her current shell be over-
        !           376:         * ridden (shflag of cshflag) then we use the current shell.
        !           377:         */
        !           378:        if ((!shflag) && (!cshflag) && (getenv("SHELL") != NULL))
        !           379:                shell = "$SHELL";
        !           380: 
        !           381:        /*
        !           382:         * Put some standard information at the top of the spoolfile.
        !           383:         * This info is used by the other "at"-oriented programs (atq,
        !           384:         * atrm, atrun).
        !           385:         */
        !           386:        fprintf(spoolfile, "# owner: %.127s\n",getname(getuid()));
        !           387:        fprintf(spoolfile, "# jobname: %.127s\n",jobfile);
        !           388:        fprintf(spoolfile, "# shell: sh\n");
        !           389:        fprintf(spoolfile, "# notify by mail: %s\n",(mailflag) ? "yes" : "no");
        !           390:        fprintf(spoolfile, "\n");
        !           391: 
        !           392:        /*
        !           393:         * Set the modes for any files created by the job being run.
        !           394:         */
        !           395:        c = umask(0);
        !           396:        umask(c);
        !           397:        fprintf(spoolfile, "umask %.1o\n", c);
        !           398: 
        !           399:        /*
        !           400:         * Get the current working directory so we know what directory to 
        !           401:         * run the job from.
        !           402:         */
        !           403:        if (getwd(pwbuf) == NULL) {
        !           404:                fprintf(stderr, "at: can't get working directory\n");
        !           405:                exit(1);
        !           406:        }
        !           407:        fprintf(spoolfile, "cd %s\n", pwbuf);
        !           408: 
        !           409:        /*
        !           410:         * Copy the user's environment to the spoolfile.
        !           411:         */
        !           412:        if (environ) {
        !           413:                copyenvironment(&spoolfile);
        !           414:        }
        !           415: 
        !           416:        /*
        !           417:         * Put in a line to run the proper shell using the rest of
        !           418:         * the file as input.  Note that 'exec'ing the shell will
        !           419:         * cause sh() to leave a /tmp/sh### file around.
        !           420:         */
        !           421:        fprintf(spoolfile,
        !           422:            "%s << '...the rest of this file is shell input'\n", shell);
        !           423: 
        !           424:        /*
        !           425:         * Now that we have all the files set up, we can start reading in
        !           426:         * the job. (I added the prompt "at>" so that the user could tell
        !           427:         * when/if he/she was supposed to enter commands from standard
        !           428:         * input. The old "at" just sat there and didn't send any kind of 
        !           429:         * message that said it was waiting for input if it was reading
        !           430:         * form standard input).
        !           431:         */
        !           432:        while (fgets(line, LINSIZ, inputfile) != NULL) {
        !           433:                fputs(line, spoolfile);
        !           434:                if (standardin)
        !           435:                        fputs("at> ", stdout);
        !           436:        }
        !           437:        if (standardin)
        !           438:                fputs("<EOT>\n", stdout);       /* clean up the final output */
        !           439: 
        !           440:        /*
        !           441:         * Close all files and change the mode of the spoolfile.
        !           442:         */
        !           443:        fclose(inputfile);
        !           444:        fclose(spoolfile);
        !           445: 
        !           446:        exit(0);
        !           447: 
        !           448: }
        !           449: 
        !           450: /*
        !           451:  * Copy the user's environment to the spoolfile in the syntax of the
        !           452:  * Bourne shell.  After the environment is set up, the proper shell
        !           453:  * will be invoked.
        !           454:  */
        !           455: copyenvironment(spoolfile)
        !           456: FILE **spoolfile;
        !           457: {
        !           458:        char *tmp;                      /* scratch pointer */
        !           459:        char **environptr = environ;    /* pointer to an environment setting */
        !           460: 
        !           461:        while(*environptr) {
        !           462:                tmp = *environptr;
        !           463: 
        !           464:                /*
        !           465:                 * We don't want the termcap or terminal entry so skip them.
        !           466:                 */
        !           467:                if ((strncmp(tmp,"TERM=",5) == 0) ||
        !           468:                    (strncmp(tmp,"TERMCAP=",8) == 0)) {
        !           469:                        ++environptr;
        !           470:                        continue;
        !           471:                }
        !           472: 
        !           473:                /*
        !           474:                 * Set up the proper syntax.
        !           475:                 */
        !           476:                while (*tmp != '=')
        !           477:                        fputc(*tmp++,*spoolfile);
        !           478:                fputc('=', *spoolfile);
        !           479:                fputc('\'' , *spoolfile);
        !           480:                ++tmp;
        !           481: 
        !           482:                /*
        !           483:                 * Now copy the entry.
        !           484:                 */
        !           485:                while (*tmp) {
        !           486:                        if (*tmp == '\'')
        !           487:                                fputs("'\\''", *spoolfile);
        !           488:                        else if (*tmp == '\n')
        !           489:                                fputs("\\",*spoolfile);
        !           490:                        else
        !           491:                                fputc(*tmp, *spoolfile);
        !           492:                        ++tmp;
        !           493:                }
        !           494:                fputc('\'' , *spoolfile);
        !           495: 
        !           496:                /*
        !           497:                 * We need to "export" environment settings.
        !           498:                 */
        !           499:                fprintf(*spoolfile, "\nexport ");
        !           500:                tmp = *environptr;
        !           501:                while (*tmp != '=')
        !           502:                        fputc(*tmp++,*spoolfile);
        !           503:                fputc('\n',*spoolfile);
        !           504:                ++environptr;
        !           505:        }
        !           506:        return;
        !           507: }
        !           508: 
        !           509: /*
        !           510:  * Create the filename for the spoolfile. The format is "yy.ddd.mmmm.??"
        !           511:  * where "yy" is the year the job will be run, "ddd" the day of year, 
        !           512:  * "mmmm" the hour and minute, and "??" a scratch value used to dis-
        !           513:  * tinguish between two files that are to be run at the same time.
        !           514:  */
        !           515: makeatfile(atfile,year,dayofyear,hour,minute)
        !           516: int year;
        !           517: int hour;
        !           518: int minute;
        !           519: int dayofyear;
        !           520: char *atfile;
        !           521: {
        !           522:        int i;                          /* scratch variable */
        !           523: 
        !           524:        for (i=0; ; i += 53) {
        !           525:                sprintf(atfile, "%s/%02d.%03d.%02d%02d.%02d", ATDIR, year,
        !           526:                        dayofyear, hour, minute, (getpid() + i) % 100);
        !           527: 
        !           528:                /*
        !           529:                 * Make sure that the file name that we've created is unique.
        !           530:                 */
        !           531:                if (access(atfile, F_OK) == -1)
        !           532:                        return;
        !           533:        }
        !           534: }
        !           535: 
        !           536: /*
        !           537:  * Has the requested time already passed for the currrent day? If so, we
        !           538:  * will run the job "tomorrow".
        !           539:  */
        !           540: istomorrow()
        !           541: {
        !           542:        if (attime.hour < nowtime.hour)
        !           543:                return(1);
        !           544:        if ((attime.hour == nowtime.hour) && (attime.min < nowtime.min))
        !           545:                return(1);
        !           546: 
        !           547:        return(0);
        !           548: }
        !           549: 
        !           550: /*
        !           551:  * Debugging wreckage.
        !           552:  */
        !           553: printit()
        !           554: {
        !           555:        printf("YEAR\tnowtime: %d\tattime: %d\n",nowtime.year,attime.year);
        !           556:        printf("YDAY\tnowtime: %d\tattime: %d\n",nowtime.yday,attime.yday);
        !           557:        printf("MON\tnowtime: %d\tattime: %d\n",nowtime.mon,attime.mon);
        !           558:        printf("MONDAY\tnowtime: %d\tattime: %d\n",nowtime.mday,attime.mday);
        !           559:        printf("WDAY\tnowtime: %d\tattime: %d\n",nowtime.wday,attime.wday);
        !           560:        printf("HOUR\tnowtime: %d\tattime: %d\n",nowtime.hour,attime.hour);
        !           561:        printf("MIN\tnowtime: %d\tattime: %d\n",nowtime.min,attime.min);
        !           562: }
        !           563: 
        !           564: /*
        !           565:  * Calculate the day of year that the job will be executed.
        !           566:  * The av,ac arguments are ptrs to argv,argc; updated as necessary.
        !           567:  */
        !           568: makedayofyear(dateindex, av, ac)
        !           569: int dateindex;
        !           570: char ***av;
        !           571: int *ac;
        !           572: {
        !           573:        char **argv = *av;      /* imitate argc,argv and update args at end */
        !           574:        int argc = *ac;
        !           575:        char *ptr;                              /* scratch pointer */
        !           576:        struct datetypes *daterequested;        /* pointer to information about
        !           577:                                                   the type of date option
        !           578:                                                   we're dealing with */
        !           579: 
        !           580:        daterequested = &dates_info[dateindex];
        !           581: 
        !           582:        /*
        !           583:         * If we're dealing with a day of week, determine the number of days
        !           584:         * in the future the next day of this type will fall on. Add this
        !           585:         * value to "attime.yday".
        !           586:         */
        !           587:        if (daterequested->type == DAY) {
        !           588:                if (attime.wday < dateindex) 
        !           589:                        attime.yday += dateindex - attime.wday;
        !           590:                else if(attime.wday > dateindex) 
        !           591:                        attime.yday += (7 - attime.wday) + dateindex;
        !           592:                else attime.yday += 7;
        !           593:        }
        !           594: 
        !           595:        /*
        !           596:         * If we're dealing with a month and day of month, determine the
        !           597:         * day of year that this date will fall on.
        !           598:         */
        !           599:        if (daterequested->type == MONTH) {
        !           600: 
        !           601:                /*
        !           602:                 * If a day of month isn't specified, print a message
        !           603:                 * and exit.
        !           604:                 */
        !           605:                if (argc <= 0) {
        !           606:                        fprintf(stderr,"day of month not specified.\n");
        !           607:                        exit(1);
        !           608:                }
        !           609: 
        !           610:                /*
        !           611:                 * Scan the day of month value and make sure that it
        !           612:                 * has no characters in it. If characters are found or
        !           613:                 * the day requested is zero, print a message and exit.
        !           614:                 */
        !           615:                ptr = *argv;
        !           616:                while (isdigit(*ptr))
        !           617:                        ++ptr;
        !           618:                if ((*ptr != '\0') || (atoi(*argv) == 0)) {
        !           619:                        fprintf(stderr,"\"%s\": illegal day of month\n",*argv);
        !           620:                        exit(1);
        !           621:                }
        !           622: 
        !           623:                /*
        !           624:                 * Set the month of year and day of month values. Since
        !           625:                 * the first 7 values in our dateinfo table do not deal
        !           626:                 * with month names, we subtract 7 from the month of year
        !           627:                 * value.
        !           628:                 */
        !           629:                attime.mon = (dateindex - 7);
        !           630:                attime.mday = (atoi(*argv) - 1);
        !           631: 
        !           632:                /*
        !           633:                 * Test the day of month value to make sure that the
        !           634:                 * value is legal.
        !           635:                 */
        !           636:                if ((attime.mday + 1) > 
        !           637:                    yeartable[isleap(attime.year)][attime.mon + 1]) {
        !           638:                        fprintf(stderr,"\"%s\": illegal day of month\n",*argv);
        !           639:                        exit(1);
        !           640:                }
        !           641: 
        !           642:                /*
        !           643:                 * Finally, we determine the day of year.
        !           644:                 */
        !           645:                attime.yday = (countdays());
        !           646:                ++argv; --argc;
        !           647:        }
        !           648: 
        !           649:        /*
        !           650:         * If 'week' is specified, add 7 to the day of year.
        !           651:         */
        !           652:        if ((argc > 0) && (strcmp(*argv,"week") == 0)) {
        !           653:                attime.yday += 7;
        !           654:                ++argv; --argc;
        !           655:        }
        !           656: 
        !           657:        /*
        !           658:         * Now that all that is done, see if the requested execution time
        !           659:         * has already passed for this year, and if it has, set execution
        !           660:         * for next year.
        !           661:         */
        !           662:        if (isnextyear())
        !           663:                ++attime.year;
        !           664:        
        !           665:        /*
        !           666:         * Finally, reflect the updated argc,argv to the caller
        !           667:         */
        !           668:        *av = argv;
        !           669:        *ac = argc;
        !           670: }
        !           671: 
        !           672: /*
        !           673:  * Should the job be run next year? We check for the following situations:
        !           674:  *
        !           675:  *     1) the requested time has already passed for the current year. 
        !           676:  *     2) the day of year is greater than the number of days in the year. 
        !           677:  *
        !           678:  * If either of these tests succeed, we increment "attime.year" by 1. 
        !           679:  * If #2 is true, we also subtract the number of days in the current year
        !           680:  * from "attime.yday". #2 can only occur if someone specifies a job to
        !           681:  * be run "tomorrow" on Dec. 31 or if they specify a job to be run a
        !           682:  * 'week' later and the date is at least Dec. 24. (I think so anyway)
        !           683:  */
        !           684: isnextyear()
        !           685: {      register daysinyear;
        !           686:        if (attime.yday < nowtime.yday)
        !           687:                return(1);
        !           688: 
        !           689:        if ((attime.yday == nowtime.yday) && (attime.hour < nowtime.hour))
        !           690:                return(1);
        !           691: 
        !           692:        daysinyear = isleap(attime.year) ? 366 : 365;
        !           693:        if (attime.yday >= daysinyear) {
        !           694:                attime.yday -= daysinyear;
        !           695:                return(1);
        !           696:        }
        !           697:        if (attime.yday > (isleap(attime.year) ? 366 : 365)) {
        !           698:                attime.yday -= (isleap(attime.year) ? 366 : 365);
        !           699:                return(1);
        !           700:        }
        !           701: 
        !           702:        return(0);
        !           703: }
        !           704: 
        !           705: /*
        !           706:  * Determine the day of year given a month and day of month value.
        !           707:  */
        !           708: countdays()
        !           709: {
        !           710:        int leap;                       /* are we dealing with a leap year? */
        !           711:        int dayofyear;                  /* the day of year after conversion */
        !           712:        int monthofyear;                /* the month of year that we are
        !           713:                                           dealing with */
        !           714: 
        !           715:        /*
        !           716:         * Are we dealing with a leap year?
        !           717:         */
        !           718:        leap = isleap(attime.year);
        !           719: 
        !           720:        monthofyear = attime.mon;
        !           721:        dayofyear = attime.mday;
        !           722: 
        !           723:        /*
        !           724:         * Determine the day of year.
        !           725:         */
        !           726:        while (monthofyear > 0)
        !           727:                dayofyear += yeartable[leap][monthofyear--];
        !           728: 
        !           729:        return(dayofyear);
        !           730: }
        !           731: 
        !           732: /*
        !           733:  * Is a year a leap year?
        !           734:  */
        !           735: isleap(year)
        !           736: int year;
        !           737: 
        !           738: {
        !           739:        return((year%4 == 0 && year%100 != 0) || year%100 == 0);
        !           740: }
        !           741: 
        !           742: getdateindex(date)
        !           743: char *date;
        !           744: {
        !           745:        int i = 0;
        !           746:        struct datetypes *ptr;
        !           747: 
        !           748:        ptr = dates_info;
        !           749: 
        !           750:        for (ptr = dates_info; ptr->type != 0; ptr++, i++) {
        !           751:                if (isprefix(date, ptr->name))
        !           752:                        return(i);
        !           753:        }
        !           754:        return(NODATEFOUND);
        !           755: }
        !           756: 
        !           757: isprefix(prefix, fullname)
        !           758: char *prefix, *fullname;
        !           759: {
        !           760:        char ch;
        !           761:        char *ptr;
        !           762:        char *ptr1;
        !           763: 
        !           764:        ptr = prefix;
        !           765:        ptr1 = fullname;
        !           766: 
        !           767:        while (*ptr) {
        !           768:                ch = *ptr;
        !           769:                if (isupper(ch))
        !           770:                        ch = tolower(ch);
        !           771: 
        !           772:                if (ch != *ptr1++)
        !           773:                        return(0);
        !           774: 
        !           775:                ++ptr;
        !           776:        }
        !           777:        return(1);
        !           778: }
        !           779: 
        !           780: getnowtime(nowtime, attime)
        !           781: struct times *nowtime;
        !           782: struct times *attime;
        !           783: {
        !           784:        struct tm *now;
        !           785:        struct timeval time;
        !           786:        struct timezone zone;
        !           787: 
        !           788:        if (gettimeofday(&time,&zone) < 0) {
        !           789:                perror("gettimeofday");
        !           790:                exit(1);
        !           791:        }
        !           792:        now = localtime(&time.tv_sec);
        !           793: 
        !           794:        attime->year = nowtime->year = now->tm_year;
        !           795:        attime->yday = nowtime->yday = now->tm_yday;
        !           796:        attime->mon = nowtime->mon = now->tm_mon;
        !           797:        attime->mday = nowtime->mday = now->tm_mday;
        !           798:        attime->wday = nowtime->wday = now->tm_wday;
        !           799:        attime->hour = nowtime->hour = now->tm_hour;
        !           800:        attime->min = nowtime->min = now->tm_min;
        !           801: }
        !           802: 
        !           803: /*
        !           804:  * This is the same routine used in the old "at", so I won't bother
        !           805:  * commenting it. It'll give you an idea of what the code looked
        !           806:  * like when I got it.
        !           807:  */
        !           808: maketime(attime,ptr)
        !           809: char *ptr;
        !           810: struct times *attime;
        !           811: {
        !           812:        int val;
        !           813:        char *p;
        !           814: 
        !           815:        p = ptr;
        !           816:        val = 0;
        !           817:        while(isdigit(*p)) {
        !           818:                val = val*10+(*p++ -'0');
        !           819:        }
        !           820:        if (p-ptr < 3)
        !           821:                val *= HOUR;
        !           822: 
        !           823:        for (;;) {
        !           824:                switch(*p) {
        !           825: 
        !           826:                case ':':
        !           827:                        ++p;
        !           828:                        if (isdigit(*p)) {
        !           829:                                if (isdigit(p[1])) {
        !           830:                                        val +=(10* *p + p[1] - 11*'0');
        !           831:                                        p += 2;
        !           832:                                        continue;
        !           833:                                }
        !           834:                        }
        !           835:                        fprintf(stderr, "bad time format:\n");
        !           836:                        exit(1);
        !           837: 
        !           838:                case 'A':
        !           839:                case 'a':
        !           840:                        if (val >= HALFDAY+HOUR)
        !           841:                                val = FULLDAY+1;  /* illegal */
        !           842:                        if (val >= HALFDAY && val <(HALFDAY+HOUR))
        !           843:                                val -= HALFDAY;
        !           844:                        break;
        !           845: 
        !           846:                case 'P':
        !           847:                case 'p':
        !           848:                        if (val >= HALFDAY+HOUR)
        !           849:                                val = FULLDAY+1;  /* illegal */
        !           850:                        if (val < HALFDAY)
        !           851:                                val += HALFDAY;
        !           852:                        break;
        !           853: 
        !           854:                case 'n':
        !           855:                case 'N':
        !           856:                        if ((val == 0) || (val == HALFDAY))
        !           857:                                val = HALFDAY;
        !           858:                        else
        !           859:                                val = FULLDAY+1;  /* illegal */
        !           860:                        break;
        !           861: 
        !           862:                case 'M':
        !           863:                case 'm':
        !           864:                        if ((val == 0) || (val == HALFDAY))
        !           865:                                val = 0;
        !           866:                        else
        !           867:                                val = FULLDAY+1;  /* illegal */
        !           868:                        break;
        !           869: 
        !           870: 
        !           871:                case '\0':
        !           872:                case ' ':
        !           873:                        /* 24 hour time */
        !           874:                        if (val == FULLDAY)
        !           875:                                val -= FULLDAY;
        !           876:                        break;
        !           877: 
        !           878:                default:
        !           879:                        fprintf(stderr, "bad time format\n");
        !           880:                        exit(1);
        !           881: 
        !           882:                }
        !           883:                break;
        !           884:        }
        !           885:        if (val < 0 || val >= FULLDAY) {
        !           886:                fprintf(stderr, "time out of range\n");
        !           887:                exit(1);
        !           888:        }
        !           889:        if (val%HOUR >= 60) {
        !           890:                fprintf(stderr, "illegal minute field\n");
        !           891:                exit(1);
        !           892:        }
        !           893:        attime->hour = val/HOUR;
        !           894:        attime->min = val%HOUR;
        !           895: }
        !           896: 
        !           897: /*
        !           898:  * Get the full login name of a person using his/her user id.
        !           899:  */
        !           900: char *
        !           901: getname(uid)
        !           902: int uid;
        !           903: {
        !           904:        struct passwd *pwdinfo;                 /* password info structure */
        !           905:        
        !           906: 
        !           907:        if ((pwdinfo = getpwuid(uid)) == 0) {
        !           908:                perror(uid);
        !           909:                exit(1);
        !           910:        }
        !           911:        return(pwdinfo->pw_name);
        !           912: }
        !           913: 
        !           914: /*
        !           915:  * Do general cleanup.
        !           916:  */
        !           917: cleanup()
        !           918: {
        !           919:        if (unlink(atfile) == -1)
        !           920:                perror(atfile);
        !           921:        exit(1);
        !           922: }
        !           923: 
        !           924: /*
        !           925:  * Print usage info and exit.
        !           926:  */
        !           927: usage()
        !           928: {
        !           929:        fprintf(stderr,"usage: at [-csm] time [date] [filename]\n");
        !           930:        exit(1);
        !           931: }
        !           932: 

unix.superglobalmegacorp.com

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