/* * at time mon day * at time wday * at time wday 'week' * */ #include <stdio.h> #include <ctype.h> #include <time.h> #include <signal.h> #include <sys/types.h> #include <sys/stat.h> #include <dir.h> #define HOUR 100 #define HALFDAY (12*HOUR) #define DAY (24*HOUR) #define THISDAY "/usr/spool/at" char *days[] = { "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", }; struct monstr { char *mname; int mlen; } months[] = { { "january", 31 }, { "february", 28 }, { "march", 31 }, { "april", 30 }, { "may", 31 }, { "june", 30 }, { "july", 31 }, { "august", 31 }, { "september", 30 }, { "october", 31 }, { "november", 30 }, { "december", 31 }, { 0, 0 }, }; char fname[100]; int utime; /* requested time in grains */ int now; /* when is it */ int uday; /* day of year to be done */ int uyear; /* year */ int today; /* day of year today */ int thisyear; /* this year */ FILE *file; FILE *ifile; char **environ; char *prefix(); char *idend(); char *strchr(); FILE *popen(); extern int optind; char lflg; char rflg; char errflg; void prdir(), prfile(), delfile(), vprint(); int readdir(); char *pathdate(); #define EXP 10 main(argc, argv) char **argv; { extern onintr(); register c; char pwbuf[100]; FILE *pwfil; int larg; static char stdbuf[BUFSIZ]; setbuf (stdout, stdbuf); while ((c = getopt (argc, argv, "rl")) != EOF) { switch (c) { case 'l': lflg = 1; break; case 'r': rflg = 1; break; default: errflg = 1; break; } } if (errflg) { fprintf (stderr, "usage: at [lr] time [filename]\n"); exit (1); } /* argv[optind] is the user's time: e.g., 3AM */ /* argv[optind+1] is a month name or day of week */ /* argv[optind+2] is day of month or 'week' */ /* another argument might be an input file */ if (argc < optind+1) { if (lflg && !rflg) { (void) readdir("", prdir); exit (0); } fprintf(stderr, "at: arg count\n"); exit(1); } makeutime(argv[optind]); larg = makeuday(argc-optind+1,argv+optind-1)+optind; if (uday==today && larg<=optind+1 && utime<=now) uday++; c = uyear%4==0? 366: 365; /* The way makeuday is written, the following "if" is rarely satisfied. This makes a problem, which is fixed below. */ if (uday >= c) { uday -= c; uyear++; } /* Due to problem described above, "at" schedules a Jan call in Dec for LAST Jan. Line below fixes that. */ if(uday<today && uyear==thisyear) uyear++; if (lflg || rflg) { char prefix[50]; sprintf (prefix, "%.2d.%.3d.%.4d", uyear, uday, utime); if (lflg) { if (readdir (prefix, prfile) == 0) exit (0); if (rflg) putchar ('\n'); } if (rflg) { (void) readdir (prefix, delfile); } exit (0); } filename(THISDAY, uyear, uday, utime); /* Create file, then change UIDS */ close(creat(fname, 0644)); file = fopen(fname, "w"); if (file == NULL) { fprintf(stderr, "at: cannot open memo file\n"); exit(1); } chown(fname, getuid(), getgid()); setuid(getuid()); ifile = stdin; if (argc > larg) ifile = fopen(argv[larg], "r"); if (ifile == NULL) { fprintf(stderr, "at: cannot open input: %s\n", argv[larg]); exit(1); } if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, onintr); if ((pwfil = popen("pwd", "r")) == NULL) { fprintf(stderr, "at: can't execute pwd\n"); exit(1); } fgets(pwbuf, 100, pwfil); pclose(pwfil); fprintf(file, "cd %s", pwbuf); c = umask(0); umask(c); fprintf(file, "umask %#o\n", c); if (environ) { register int pass; char *explist[EXP]; int explen[EXP]; register int exp = 0; register int i; for (pass = 1; pass <= 2; pass++) { register char **ep; for (ep = environ; *ep; ep++) { if (pass == 1) { vprint(file, *ep); putc('\n', file); } else { char *ix; ix = idend(*ep); if (*ix) { explen[exp] = ix-*ep; explist[exp++] = *ep; if (exp >= EXP) { fprintf(file,"export"); for (i=0; i<EXP; i++) { putc(' ',file); fprintf(file, "%.*s",explen[i],explist[i]); } putc ('\n', file); exp = 0; } } } } if (exp > 0) { fprintf(file,"export"); for (i = 0; i < exp; i++) { putc(' ',file); fprintf(file, "%.*s",explen[i],explist[i]); } putc ('\n', file); } } } while((c = getc(ifile)) != EOF) { putc(c, file); } exit(0); } makeutime(pp) char *pp; { register val; register char *p; /* p points to a user time */ p = pp; val = 0; while(isdigit(*p)) { val = val*10+(*p++ -'0'); } if (p-pp < 3) val *= HOUR; for (;;) { switch(*p) { case ':': ++p; if (isdigit(*p)) { if (isdigit(p[1])) { val +=(10* *p + p[1] - 11*'0'); p += 2; continue; } } fprintf(stderr, "at: bad time format:\n"); exit(1); case 'A': case 'a': if (val >= HALFDAY+HOUR) val = DAY+1; /* illegal */ if (val >= HALFDAY && val <(HALFDAY+HOUR)) val -= HALFDAY; break; case 'P': case 'p': if (val >= HALFDAY+HOUR) val = DAY+1; /* illegal */ if (val < HALFDAY) val += HALFDAY; break; case 'n': case 'N': val = HALFDAY; break; case 'M': case 'm': val = 0; break; case '\0': case ' ': /* 24 hour time */ if (val == DAY) val -= DAY; break; default: fprintf(stderr, "at: bad time format\n"); exit(1); } break; } if (val < 0 || val >= DAY) { fprintf(stderr, "at: time out of range\n"); exit(1); } if (val%HOUR >= 60) { fprintf(stderr, "at: illegal minute field\n"); exit(1); } utime = val; } makeuday(argc,argv) char **argv; { /* the presumption is that argv[2], argv[3] are either month day OR weekday [week]. Returns 2, 3, or 4 as last argument used */ /* first of all, what's today */ long tm; int found = -1; char **ps; struct tm *detail, *localtime(); struct monstr *pt; time(&tm); detail = localtime(&tm); uday = today = detail->tm_yday; thisyear = uyear = detail->tm_year; now = detail->tm_hour*100+detail->tm_min; if (argc<=2) return(1); /* is the next argument a month name ? */ for (pt=months; pt->mname; pt++) { if (prefix(argv[2], pt->mname)) { if (found<0) found = pt-months; else { fprintf(stderr, "at: ambiguous month\n"); exit(1); } } } if (found>=0) { if (argc<=3) return(2); uday = atoi(argv[3]) - 1; if (uday<0) { fprintf(stderr, "at: illegal day\n"); exit(1); } if (found > 1 && detail->tm_year%4==0) uday++; /* because next loop will include Feb */ while(--found>=0) uday += months[found].mlen; /* this is bogus... if (detail->tm_year%4==0 && uday>59) uday += 1; */ if(argc>4) { int t = atoi(argv[4])-1900; if(t<100 && (t>uyear || t==uyear && ( uday>today || uday==today && utime>now))) { uyear = t; return(4); } } if (uday == today && utime < now) { fprintf(stderr, "at: Warning: time specified is past; assuming next year....\n"); ++uyear; } return(3); } /* not a month, try day of week */ found = -1; for (ps=days; ps<days+7; ps++) { if (prefix(argv[2], *ps)) { if (found<0) found = ps-days; else { fprintf(stderr, "at: ambiguous day of week\n"); exit(1); } } } if (found<0) return(1); /* find next day of this sort */ uday = found - detail->tm_wday; if (uday<=0) uday += 7; uday += today; /* Bogus... if (detail->tm_year%4==0 && uday>59) uday += 1; */ if (argc>3 && strcmp("week", argv[3])==0) { uday += 7; return(3); } return(2); } char * prefix(begin, full) char *begin, *full; { int c; while (c = *begin++) { if (isupper(c)) c = tolower(c); if (*full != c) return(0); else full++; } return(full); } filename(dir, y, d, t) char *dir; { register i; for (i=0; ; i += 53) { sprintf(fname, "%s/%.2d.%.3d.%.4d.%.2d", dir, y, d, t, (getpid()+i)%100); if (access(fname, 0) == -1) return; } } onintr() { unlink(fname); exit(1); } /* hand "fn" all path names in spool directory starting with "prefix" */ int readdir(prefix, fn) char *prefix; void (*fn)(); { struct dir dbuf; register FILE *f; register int count = 0; f = fopen (THISDAY, "r"); if (f == NULL) { fprintf (stderr, "cannot open %s\n", THISDAY); return; } while (fread (&dbuf, sizeof dbuf, 1, f) == 1) { if (dbuf.d_ino != 0 && dbuf.d_name[0] != '.' && strncmp (dbuf.d_name, prefix, strlen(prefix)) == 0) { char file[sizeof (THISDAY) + DIRSIZ + 1]; struct stat sb; strcpy (file, THISDAY); strcat (file, "/"); strncat (file, dbuf.d_name, DIRSIZ); if (stat (file, &sb) >= 0 && sb.st_uid == getuid()) { count++; (*fn) (file); } } } fclose (f); if (count == 0) fprintf (stderr, "no items\n"); } /* * return pointer to (static) area containing date and time * for activation of file, or argument if invalid format. */ char * pathdate (path) char *path; { int month, mday, yday, year, tm, junk; register int i; register char *p, *q; static char res[50]; /* point p at last component of path name */ p = q = path; while (*q) if (*q++ == '/') p = q; /* break out the fields */ if (sscanf(p, "%2d.%3d.%4d.%2d", &year, &yday, &tm, &junk) != 4) return path; /* determine the month and day of month */ month = 0; mday = yday + 1; while (months[month].mlen && mday > months[month].mlen) { mday -= months[month].mlen; month++; } /* check for impossible date */ if (++month > 12) return path; /* check for leap year */ if (month > 2 && year % 4 == 0 && --mday <= 0) { mday = months[--month - 1].mlen; if (month == 2) mday++; } /* build the result */ sprintf (res, "%.4d %s %d 19%d", tm, months[month-1].mname, mday, year); return res; } void prdir (path) register char *path; { printf ("%s\n", pathdate (path)); } void prfile (path) register char *path; { register FILE *f; printf ("\n%s:", pathdate (path)); f = fopen (path, "r"); if (f == NULL) { fprintf (stderr, " cannot open %s\n", path); } else { register int c; printf ("\n\n"); while ((c = getc(f)) != EOF) putchar (c); } fclose (f); } void delfile(path) register char *path; { if (unlink(path) < 0) fprintf (stderr, "cannot remove %s\n", path); else fprintf (stderr, "remove %s\n", pathdate(path)); } char * idend(s) char *s; { while(*s && *s!='=' && *s!='(') s++; return s; } /* print a shell variable with quoting */ void vprint (f, str) register FILE *f; register char *str; { if(*idend(str)=='(') /* function; the shell's already quoted it right */ fputs(str, f); else while (*str) { if (strchr (" \t\b\n\f$\\[]*?'\"`&|#()^<>;", *str)) putc ('\\', f); putc (*str++, f); } }