1: #ifndef lint 2: static char *sccsid = "@(#)cron.c 4.12 (Berkeley) 5/27/86"; 3: #endif 4: 5: #include <sys/types.h> 6: #include <stdio.h> 7: #include <ctype.h> 8: #include <signal.h> 9: #include <sys/time.h> 10: #include <sys/stat.h> 11: #include <sys/wait.h> 12: #include <sys/ioctl.h> 13: #include <sys/file.h> 14: #include <pwd.h> 15: #include <fcntl.h> 16: 17: #define LISTS (2*BUFSIZ) 18: #define MAXLIN BUFSIZ 19: 20: #ifndef CRONTAB 21: #define CRONTAB "/usr/lib/crontab" 22: #endif 23: 24: #ifndef CRONTABLOC 25: #define CRONTABLOC "/usr/lib/crontab.local" 26: #endif 27: 28: #define EXACT 100 29: #define ANY 101 30: #define LIST 102 31: #define RANGE 103 32: #define EOS 104 33: 34: char crontab[] = CRONTAB; 35: char loc_crontab[] = CRONTABLOC; 36: time_t itime; 37: struct tm *loct; 38: struct tm *localtime(); 39: char *malloc(); 40: char *realloc(); 41: int reapchild(); 42: int flag; 43: char *list; 44: char *listend; 45: unsigned listsize; 46: 47: FILE *debug; 48: #define dprintf if (debug) fprintf 49: 50: main(argc, argv) 51: int argc; 52: char **argv; 53: { 54: register char *cp; 55: char *cmp(); 56: time_t filetime = 0; 57: time_t lfiletime = 0; 58: char c; 59: extern char *optarg; 60: 61: if (fork()) 62: exit(0); 63: c = getopt(argc, argv, "d:"); 64: if (c == 'd') { 65: debug = fopen(optarg, "w"); 66: if (debug == NULL) 67: exit(1); 68: fcntl(fileno(debug), F_SETFL, FAPPEND); 69: } 70: chdir("/"); 71: freopen("/", "r", stdout); 72: freopen("/", "r", stderr); 73: untty(); 74: signal(SIGHUP, SIG_IGN); 75: signal(SIGINT, SIG_IGN); 76: signal(SIGQUIT, SIG_IGN); 77: signal(SIGCHLD, reapchild); 78: time(&itime); 79: itime -= localtime(&itime)->tm_sec; 80: 81: for (;; itime+=60, slp()) { 82: struct stat cstat, lcstat; 83: int newcron, newloc; 84: 85: newcron = 0; 86: if (stat(crontab, &cstat) < 0) 87: cstat.st_mtime = 1; 88: if (cstat.st_mtime != filetime) { 89: filetime = cstat.st_mtime; 90: newcron++; 91: } 92: 93: newloc = 0; 94: if (stat(loc_crontab, &lcstat) < 0) 95: lcstat.st_mtime = 1; 96: if (lcstat.st_mtime != lfiletime) { 97: lfiletime = lcstat.st_mtime; 98: newloc++; 99: } 100: 101: if (newcron || newloc) { 102: init(); 103: append(crontab); 104: append(loc_crontab); 105: *listend++ = EOS; 106: *listend++ = EOS; 107: } 108: 109: loct = localtime(&itime); 110: loct->tm_mon++; /* 1-12 for month */ 111: if (loct->tm_wday == 0) 112: loct->tm_wday = 7; /* sunday is 7, not 0 */ 113: for(cp = list; *cp != EOS;) { 114: flag = 0; 115: cp = cmp(cp, loct->tm_min); 116: cp = cmp(cp, loct->tm_hour); 117: cp = cmp(cp, loct->tm_mday); 118: cp = cmp(cp, loct->tm_mon); 119: cp = cmp(cp, loct->tm_wday); 120: if(flag == 0) 121: ex(cp); 122: while(*cp++ != 0) 123: ; 124: } 125: } 126: } 127: 128: char * 129: cmp(p, v) 130: char *p; 131: { 132: register char *cp; 133: 134: cp = p; 135: switch(*cp++) { 136: 137: case EXACT: 138: if (*cp++ != v) 139: flag++; 140: return(cp); 141: 142: case ANY: 143: return(cp); 144: 145: case LIST: 146: while(*cp != LIST) 147: if(*cp++ == v) { 148: while(*cp++ != LIST) 149: ; 150: return(cp); 151: } 152: flag++; 153: return(cp+1); 154: 155: case RANGE: 156: if(*cp > v || cp[1] < v) 157: flag++; 158: return(cp+2); 159: } 160: if(cp[-1] != v) 161: flag++; 162: return(cp); 163: } 164: 165: slp() 166: { 167: register i; 168: time_t t; 169: 170: time(&t); 171: i = itime - t; 172: if(i < -60 * 60 || i > 60 * 60) { 173: itime = t; 174: i = 60 - localtime(&itime)->tm_sec; 175: itime += i; 176: } 177: if(i > 0) 178: sleep(i); 179: } 180: 181: ex(s) 182: char *s; 183: { 184: int st; 185: register struct passwd *pwd; 186: char user[BUFSIZ]; 187: char *c = user; 188: int pid; 189: 190: if (fork()) { 191: return; 192: } 193: 194: pid = getpid(); 195: while(*s != ' ' && *s != '\t') 196: *c++ = *s++; 197: *c = '\0'; 198: s++; 199: if ((pwd = getpwnam(user)) == NULL) { 200: dprintf(debug, "%d: cannot find %s\n", pid, user), 201: fflush(debug); 202: exit(1); 203: } 204: (void) setgid(pwd->pw_gid); 205: initgroups(pwd->pw_name, pwd->pw_gid); 206: (void) setuid(pwd->pw_uid); 207: freopen("/", "r", stdin); 208: dprintf(debug, "%d: executing %s", pid, s), fflush (debug); 209: execl("/bin/sh", "sh", "-c", s, 0); 210: dprintf(debug, "%d: cannot execute sh\n", pid), fflush (debug); 211: exit(0); 212: } 213: 214: init() 215: { 216: /* 217: * Don't free in case was longer than LISTS. Trades off 218: * the rare case of crontab shrinking vs. the common case of 219: * extra realloc's needed in append() for a large crontab. 220: */ 221: if (list == 0) { 222: list = malloc(LISTS); 223: listsize = LISTS; 224: } 225: listend = list; 226: } 227: 228: append(fn) 229: char *fn; 230: { 231: register i, c; 232: register char *cp; 233: register char *ocp; 234: register int n; 235: 236: if (freopen(fn, "r", stdin) == NULL) 237: return; 238: cp = listend; 239: loop: 240: if(cp > list+listsize-MAXLIN) { 241: int length = cp - list; 242: 243: listsize += LISTS; 244: list = realloc(list, listsize); 245: cp = list + length; 246: } 247: ocp = cp; 248: for(i=0;; i++) { 249: do 250: c = getchar(); 251: while(c == ' ' || c == '\t') 252: ; 253: if(c == EOF || c == '\n') 254: goto ignore; 255: if(i == 5) 256: break; 257: if(c == '*') { 258: *cp++ = ANY; 259: continue; 260: } 261: if ((n = number(c)) < 0) 262: goto ignore; 263: c = getchar(); 264: if(c == ',') 265: goto mlist; 266: if(c == '-') 267: goto mrange; 268: if(c != '\t' && c != ' ') 269: goto ignore; 270: *cp++ = EXACT; 271: *cp++ = n; 272: continue; 273: 274: mlist: 275: *cp++ = LIST; 276: *cp++ = n; 277: do { 278: if ((n = number(getchar())) < 0) 279: goto ignore; 280: *cp++ = n; 281: c = getchar(); 282: } while (c==','); 283: if(c != '\t' && c != ' ') 284: goto ignore; 285: *cp++ = LIST; 286: continue; 287: 288: mrange: 289: *cp++ = RANGE; 290: *cp++ = n; 291: if ((n = number(getchar())) < 0) 292: goto ignore; 293: c = getchar(); 294: if(c != '\t' && c != ' ') 295: goto ignore; 296: *cp++ = n; 297: } 298: while(c != '\n') { 299: if(c == EOF) 300: goto ignore; 301: if(c == '%') 302: c = '\n'; 303: *cp++ = c; 304: c = getchar(); 305: } 306: *cp++ = '\n'; 307: *cp++ = 0; 308: goto loop; 309: 310: ignore: 311: cp = ocp; 312: while(c != '\n') { 313: if(c == EOF) { 314: fclose(stdin); 315: listend = cp; 316: return; 317: } 318: c = getchar(); 319: } 320: goto loop; 321: } 322: 323: number(c) 324: register c; 325: { 326: register n = 0; 327: 328: while (isdigit(c)) { 329: n = n*10 + c - '0'; 330: c = getchar(); 331: } 332: ungetc(c, stdin); 333: if (n>=100) 334: return(-1); 335: return(n); 336: } 337: 338: reapchild() 339: { 340: union wait status; 341: int pid; 342: 343: while ((pid = wait3(&status, WNOHANG, 0)) > 0) 344: dprintf(debug, "%d: child exits with signal %d status %d\n", 345: pid, status.w_termsig, status.w_retcode), 346: fflush (debug); 347: } 348: 349: untty() 350: { 351: int i; 352: 353: i = open("/dev/tty", O_RDWR); 354: if (i >= 0) { 355: ioctl(i, TIOCNOTTY, (char *)0); 356: (void) close(i); 357: } 358: }