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