|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.