repost: cron(1m) facility incl at(1) batch(1) crontab(1) part 4 of 4
Donald Lashomb
donlash at uncle.uucp
Wed Jan 16 07:01:25 AEST 1991
It seems that part 4 of 4 of my cron program somehow was lost in space.
I have recieved email from 3 widely separated sites who are missing it,
so here is a repost. Sorry about the bandwith to those who got it the
first time.
----
Don
---- Cut Here and unpack ----
#!/bin/sh
# This is part 04 of a multipart archive
if touch 2>&1 | fgrep '[-amc]' > /dev/null
then TOUCH=touch
else TOUCH=true
fi
# ============= parsesched.c ==============
if test X"$1" != X"-c" -a -f 'parsesched.c'; then
echo "File already exists: skipping 'parsesched.c'"
else
echo "x - extracting parsesched.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > parsesched.c &&
X/* parse: cronjob <schedule>
X *
X * <schedule> = <mm> <hh> <DD> <MM> <ww>
X *
X * <mm> = <intlist>
X *
X * <hh> = <intlist>
X *
X * <DD> = <intlist>
X *
X * <MM> = <intlist>
X * |<monthlist>
X *
X * <ww> = <intlist>
X * |<wdaylist>
X *
X * <intlist> = <number>
X * |<number>,<intlist>
X *
X * <number> = <digits>
X * |<digits>-<digits>
X *
X */
X
X#include <stdio.h>
X#include <string.h>
X#include <ctype.h>
X#include <memory.h>
X#include <setjmp.h>
X#include "cron.h"
X#include "job.h"
X
X
X/* =============== hooks to the caller of parsesched() ================ */
X
X/* parsesched() returns pointer to static SCHED struct or NULL if bad */
X/* sets caller's char *str --> rest of the line in static area */
X
Xextern int optind;
Xstatic SCHED sched;
X
X/* ==================================================================== */
X
X
Xextern void longjmp();
Xstatic jmp_buf parsebad;
X#define badsched() longjmp(parsebad,-1)
X
Xstatic char line[LINESIZ];
Xstatic char *lin;
X
Xstatic void markstring();
Xstatic void list();
Xstatic int nocvt();
Xstatic int mocvt();
Xstatic int wkcvt();
Xstatic int compare();
Xstatic void eatword();
X/* ==================================================================== */
X
XSCHED *parsesched(argc,argv,strp)
X int argc;
X char **argv;
X char **strp;
X {
X char *mm,*hh,*DD,*MM,*ww;
X
X if(setjmp(parsebad)) return((SCHED *)NULL);
X
X /* put command line back together, always put " " at end */
X *line = '\0';
X while(optind < argc) {
X strncat(line,argv[optind],
X LINESIZ-1-strlen(line)-strlen(argv[optind]));
X strncat(line," ",
X LINESIZ-1-strlen(line)-strlen(argv[optind]));
X ++optind;
X }
X lin = line;
X
X /* now break command line into 5 strings */
X markstring(&mm);
X markstring(&hh);
X markstring(&DD);
X markstring(&MM);
X markstring(&ww);
X while(isspace(*lin)) ++lin;
X *strp = lin; /* pass back pointer to rest of line */
X
X list(mm,sched.min,0,60,0,nocvt);
X list(hh,sched.hour,0,24,0,nocvt);
X list(DD,sched.mday,1,32,0,nocvt);
X list(MM,sched.mon,0,12,1,mocvt);
X list(ww,sched.wday,0,7,0,wkcvt);
X
X/* if specify '*' for only one "days" field
X * then only the other one counts
X */
X if((*DD == '*') && (*ww != '*'))
X memset(sched.mday,'\0',32);
X if((*ww == '*') && (*DD != '*'))
X memset(sched.wday,'\0',7);
X
X/* note: things like Feb 31st are not checked for
X * the resched() routine takes care of these
X */
X return(&sched);
X }
X
X
X/* mark separate strings -------------------------------------- */
X
Xstatic void markstring(str)
X char **str;
X {
X while(isspace(*lin)) ++lin;
X if(*lin == '\0') badsched();
X *str = lin;
X while(!isspace(*lin)) ++lin;
X *lin++ = '\0';
X }
X
X/* set arrays from ascii "lists" ------------------------------ */
X
Xstatic void list(asc,ary,beg,end,off,cvt)
X char *asc;
X char ary[];
X int beg;
X int end;
X int off;
X int (*cvt)();
X {
X register int i,b,e;
X
X if(strcmp(asc,"*") == 0) {
X memset(ary,'\001',end);
X return;
X }
X memset(ary,'\0',end);
X while(1) {
X if(isdigit(*asc)) {
X b = atoi(asc)-off;
X while(isdigit(*asc)) ++asc;
X }
X else
X b = (*cvt)(&asc);
X
X if(*asc == '-') {
X ++asc;
X if(isdigit(*asc)) {
X e = atoi(asc)-off;
X while(isdigit(*asc)) ++asc;
X }
X else
X e = (*cvt)(&asc);
X }
X else
X e = b;
X
X for(i=b;i<=e;++i) {
X if((i < beg) || (i > end))
X badsched();
X ary[i] = '\001';
X }
X switch(*asc) {
X case '\0':
X return;
X case ',':
X ++asc;
X continue;
X }
X badsched();
X }
X }
X
Xstatic int nocvt(ascp)
X char **ascp;
X {
X badsched();
X /*NOTREACHED*/
X }
X
X
Xstatic char *months[] = {
X "January","February","March","April",
X "May","June","July","August",
X "September","October","November","December"
X };
Xstatic int mocvt(ascp)
X register char **ascp;
X {
X register int i;
X register char *p;
X
X /* check month names */
X for(i=0;i<12;++i) {
X p = months[i];
X if(compare(*ascp,p,3) == 0) {
X eatword(ascp,p);
X break;
X }
X }
X if(i > 11) badsched();
X return(i);
X }
X
X
Xstatic char *wdays[] = {
X "Sunday","Monday","Tuesday","Wednesday",
X "Thursday","Friday","Saturday"
X };
Xstatic int wkcvt(ascp)
X register char **ascp;
X {
X register int i;
X register char *p;
X
X /* check weekday names */
X for(i=0;i<7;++i) {
X p = wdays[i];
X if(compare(*ascp,p,3) == 0) {
X eatword(ascp,p);
X break;
X }
X }
X if(i > 6) badsched();
X return(i);
X }
X
Xstatic int compare(p,q,n)
X register char *p,*q;
X register int n;
X {
X while(n--)
X if(tolower(*p++) != tolower(*q++)) return(-1);
X return(0);
X }
X
Xstatic void eatword(ascp,p)
X register char **ascp;
X register char *p;
X {
X while(tolower(**ascp) == tolower(*p)) { ++(*ascp); ++p; }
X }
SHAR_EOF
$TOUCH -am 1007171790 parsesched.c &&
chmod 0644 parsesched.c ||
echo "restore of parsesched.c failed"
set `wc -c parsesched.c`;Wc_c=$1
if test "$Wc_c" != "4523"; then
echo original size 4523, current size $Wc_c
fi
fi
# ============= parsetime.c ==============
if test X"$1" != X"-c" -a -f 'parsetime.c'; then
echo "File already exists: skipping 'parsetime.c'"
else
echo "x - extracting parsetime.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > parsetime.c &&
X/* parse: at <time>[ <date>][ <increment>]
X *
X * <sched> = <time>
X * |<time> <date>
X * |<time> +<increment>
X * |<time> + <increment>
X * |<time> <date> +<increment>
X * |<time> <date> + <increment>
X *
X * <time> = <clock>|noon|midnight|now|next|nxt|this this=next=now
X *
X * <clock> = <clk>|<clk><csufx>|<clk> <csufx>
X * <clk> = <hour>|<hour><min>|<hour>:<min>
X * <csufx> = am|pm|zulu
X * <hour> = <digit>|<digit><digit>
X * <min> = <digit><digit>
X *
X * <date> = <month> <day>
X * |<month> <day> <year>
X * |<month> <day>,<year>
X * |<month> <day>, <year>
X * |<week>
X * |next <month> <day>
X * |next <week>
X * |nxt <month> <day>
X * |nxt <week>
X * |this <month> <day>
X * |this <week>
X * |today|tomorrow
X *
X * <month> = January|Feburary ....
X * <day> = <digit>|<digit><digit> 1-31
X * <year> = <digit><digit><digit><digit> 1970-2037
X * <week> = Monday|Tuesday ....
X *
X * <increment> = +<number><incr>
X * |+<number> <incr>
X * |+ <number><incr>
X * |+ <number> <incr>
X *
X * <number> = <digit>|<digit><number>
X * <incr> = minutes|hours|days|weeks|months|years
X * |hrs|wks|mos|yrs
X *
X * notes: words only have to match first three characters
X * words can be upper or lower case
X * next|nxt|this must have <date>
X * can't use <year>|today|tomorrow with next|nxt|this
X */
X
X/* ------------------------- NOTICE -----------------------------
X
X parsetime
X (c) copyright March 29, 1989 by Donald Lashomb
X (c) copyright October 16, 1990 by Donald Lashomb
X
X This program is free. Use it, modify it, copy it, give a copy
X to a friend; I simply request the following provisions be observed:
X
X 1. My name as original author and this notice remain intact.
X 2. This program (or any modification of it) is not to be sold
X for profit.
X 3. If this program is included in commercial products, there be
X no charge for it.
X 4. This program must be distributed with source code. Compiled-
X only or binary-only distribution of this program is not allowed.
X The administrator of any system that uses this program must have
X full access to the source code.
X 5. If you enhance this program, discover a bug, have any comments
X about it (or flames) please let me know.
X
X Donald Lashomb
X Main Street
X Cranberry Lake, NY 12927
X
X -------------------------------------------------------------- */
X
X
X/* =============== hooks to the caller of parsetime() ================= */
X
X/* parsetime() returns sec.s since Jan 1, 1970 gmt or -1L if bad */
X
Xextern int optind;
X
X/* ==================================================================== */
X
X#include <stdio.h>
X#include <time.h>
X#include <memory.h>
X#include <string.h>
X#include <ctype.h>
X#include <setjmp.h>
X#include "cron.h"
X
X
Xextern long time();
Xextern struct tm *localtime();
Xextern struct tm *gmtime();
Xextern void tzset();
Xextern long timezone;
Xextern int daylight;
Xextern void longjmp();
X
Xstatic jmp_buf parsebad;
X#define badsched() longjmp(parsebad,-1)
X
Xstatic char line[LINESIZ];
Xstatic char *lin;
Xstatic long now;
Xstatic struct tm nowtm;
X
X /* timcvt() line[] struct tm */
Xstatic int YY; /* 70-137 1970-2037 70-137 */
Xstatic int MM; /* 0-11 Jan-Dec 0-11 */
Xstatic int DD; /* 1-31 1-31 1-31 */
X /* weekday --- Sun-Sat 0-6 */
Xstatic int hh; /* 0-23 1-12ampm 0-23 */
Xstatic int mm; /* 0-59 0-59 0-59 */
Xstatic int ss; /* 0-59 --- 0-59 */
Xstatic int gmtflag = 0;
Xstatic int nxtflag = 0;
Xstatic int thiflag = 0;
X
X#define chr (*lin)
X#define gchr (*lin++)
X
Xstatic char copyright[] = "parsetime - (c)1989,1990 D.Lashomb";
X
Xstatic void hour();
Xstatic void year();
Xstatic int increment();
Xstatic void eatword();
Xstatic int compare();
Xstatic long timcvt();
X/* ==================================================================== */
X
Xlong parsetime(argc,argv)
X int argc;
X char **argv;
X {
X register char *p;
X int dateflag;
X
X /* put command line back together, always put " " at end */
X *line = '\0';
X while(optind < argc) {
X strncat(line,argv[optind],
X LINESIZ-1-strlen(line)-strlen(argv[optind]));
X strncat(line," ",
X LINESIZ-1-strlen(line)-strlen(argv[optind]));
X ++optind;
X }
X lin = line;
X now = time((long *)0);
X memcpy(&nowtm,localtime(&now),sizeof(struct tm));
X tzset();
X YY = nowtm.tm_year;
X MM = nowtm.tm_mon;
X DD = nowtm.tm_mday;
X hh = nowtm.tm_hour;
X mm = nowtm.tm_min;
X#ifdef ZEROSECS
X ss = 0;
X#else
X ss = nowtm.tm_sec;
X#endif
X
X if(setjmp(parsebad)) return(-1L);
X
X if(isdigit(chr)) hour();
X
X else if(compare(lin,(p="noon"),3) == 0) {
X eatword(p);
X hh = 12;
X mm = 0;
X }
X else if(compare(lin,(p="midnight"),3) == 0) {
X eatword(p);
X hh = 0;
X mm = 0;
X }
X else if(compare(lin,(p="now"),3) == 0) {
X eatword(p);
X ss = nowtm.tm_sec;
X /* default now */
X }
X else if((compare(lin,(p="next"),3) == 0) ||
X (compare(lin,(p="nxt"),3) == 0)) {
X eatword(p);
X nxtflag = 1;
X }
X else if(compare(lin,(p="this"),3) == 0) {
X eatword(p);
X thiflag = 1;
X }
X else badsched();
X
X dateflag = date();
X if(!dateflag) {
X if((hh < nowtm.tm_hour) ||
X ((hh == nowtm.tm_hour) && (mm < nowtm.tm_min))) {
X /* tommorrow */
X ++DD;
X }
X }
X increment();
X if(chr != '\0') badsched();
X if((nxtflag || thiflag) && (!dateflag)) badsched();
X return(timcvt());
X }
X
X/* ==================================================================== */
X
Xstatic void hour()
X {
X char digits[5];
X register int i;
X register char *p;
X
X for(i=0;i<5; ) {
X if(isdigit(chr)) digits[i++] = gchr;
X else if(chr == ':') ++lin;
X else break;
X }
X digits[i] = '\0';
X if(i > 2) {
X if((mm = atoi(&digits[i-2])) > 59) badsched();
X digits[i-2] = '\0';
X }
X else
X mm = 0;
X
X hh = atoi(digits);
X
X if(chr == ' ') ++lin;
X if(compare(lin,(p="am"),2) == 0) {
X eatword(p);
X if(hh > 12) badsched();
X if(hh == 12) hh = 0;
X }
X else if(compare(lin,(p="pm"),2) == 0) {
X eatword(p);
X if(hh != 12) hh += 12;
X }
X else if(compare(lin,(p="zulu"),3) == 0) {
X eatword(p);
X gmtflag = 1;
X memcpy(&nowtm,gmtime(&now),sizeof(struct tm));
X YY = nowtm.tm_year;
X MM = nowtm.tm_mon;
X DD = nowtm.tm_mday;
X }
X else if(*(lin-1) != ' ') badsched();
X
X if(hh > 23) badsched();
X }
X
X/* ==================================================================== */
X
Xstatic char *months[] = {
X "January","February","March","April",
X "May","June","July","August",
X "September","October","November","December"
X };
X
Xstatic char *wdays[] = {
X "Sunday","Monday","Tuesday","Wednesday",
X "Thursday","Friday","Saturday"
X };
X
Xstatic int date() /* strips trailing space */
X {
X register int i;
X register char *p;
X
X /* check for "next" and "this" */
X if((compare(lin,(p="next"),3) == 0) ||
X (compare(lin,(p="nxt"),3) == 0)) {
X eatword(p);
X nxtflag = 1;
X }
X else if(compare(lin,(p="this"),3) == 0) {
X eatword(p);
X thiflag = 1;
X }
X
X /* check month names */
X for(i=0;i<12;++i) {
X p = months[i];
X if(compare(lin,p,3) == 0) {
X eatword(p);
X break;
X }
X }
X if(i <= 11) {
X MM = i;
X if(!isdigit(chr)) badsched();
X DD = atoi(lin);
X if(DD > 31) badsched();
X while(isdigit(chr)) ++lin;
X if(chr == ',') {
X ++lin;
X if(chr == ' ') ++lin;
X if(!isdigit(chr)) badsched();
X year();
X return(1);
X }
X if(gchr != ' ') badsched();
X if(isdigit(chr)) year();
X if((nxtflag) ||
X ((!thiflag) && (MM < nowtm.tm_mon)))
X ++YY;
X return(1);
X }
X
X /* check weekday names */
X for(i=0;i<7;++i) {
X p = wdays[i];
X if(compare(lin,p,3) == 0) {
X eatword(p);
X break;
X }
X }
X if(i <= 6) {
X if(nxtflag) DD += (i - nowtm.tm_wday) + 7;
X else if(thiflag) DD += (i - nowtm.tm_wday);
X else DD += (7 + (i - nowtm.tm_wday)) % 7;
X return(1);
X }
X
X /* check "today" or "tomorrow" */
X if(nxtflag || thiflag) badsched();
X p = "today";
X if(compare(lin,p,3) == 0) {
X eatword(p);
X return(1);
X }
X p = "tomorrow";
X if(compare(lin,p,3) == 0) {
X eatword(p);
X ++DD;
X return(1);
X }
X
X return(0);
X }
X
X/* ==================================================================== */
X
Xstatic void year()
X {
X if(nxtflag || thiflag) badsched();
X if(((YY = atoi(lin)) < 1970) || (YY > 2037)) badsched();
X lin += 4;
X if(gchr != ' ') badsched();
X YY -= 1900;
X }
X
X/* ==================================================================== */
X
Xstatic int increment()
X {
X register int i;
X register char *p;
X
X if(chr != '+') return(0);
X ++lin; /* gobble up '+' */
X if(chr == ' ') ++lin;
X if(!isdigit(chr)) badsched();
X i = atoi(lin);
X while(isdigit(chr)) ++lin;
X if(chr == ' ') ++lin;
X
X if(compare(lin,(p="minutes"),3) == 0) { eatword(p); mm += i; }
X else if(compare(lin,(p="hours"),3) == 0) { eatword(p); hh += i; }
X else if(compare(lin,(p="hrs"),3) == 0) { eatword(p); hh += i; }
X else if(compare(lin,(p="days"),3) == 0) { eatword(p); DD += i; }
X else if(compare(lin,(p="weeks"),3) == 0) { eatword(p); DD += 7*i; }
X else if(compare(lin,(p="wks"),3) == 0) { eatword(p); DD += 7*i; }
X else if(compare(lin,(p="months"),3) == 0) { eatword(p); MM += i; }
X else if(compare(lin,(p="mos"),3) == 0) { eatword(p); MM += i; }
X else if(compare(lin,(p="years"),3) == 0) { eatword(p); YY += i; }
X else if(compare(lin,(p="yrs"),3) == 0) { eatword(p); YY += i; }
X else badsched();
X return(1);
X }
X
X/* ==================================================================== */
X
Xstatic void eatword(p)
X register char *p;
X {
X while(tolower(chr) == tolower(*p)) { ++lin; ++p; }
X if(gchr != ' ') badsched();
X }
X
X/* ==================================================================== */
X
Xstatic int compare(p,q,n)
X register char *p,*q;
X register int n;
X {
X while(n--)
X if(tolower(*p++) != tolower(*q++)) return(-1);
X return(0);
X }
X
X/* ==================================================================== */
X
Xstatic int thirty[2][12] = {31,28,31,30,31,30,31,31,30,31,30,31,
X 31,29,31,30,31,30,31,31,30,31,30,31};
X
Xstatic int modays[2][12] = {0,31,59,90,120,151,181,212,243,273,304,334,
X 0,31,60,91,121,152,182,213,244,274,305,335};
X
Xstatic long timcvt()
X {
X long secs,days;
X int isleap;
X struct tm *when;
X
X /* roll forward the hands of time */
X hh += mm/60; mm %= 60;
X DD += hh/24; hh %= 24;
X while(1) {
X YY += MM/12; MM %= 12;
X /* leapyear = (div4 except(100 except(400))); 2000 is! */
X isleap = ((YY%4)==0)? 1: 0;
X if(DD <= thirty[isleap][MM])
X break;
X DD -= thirty[isleap][MM];
X ++MM;
X }
X
X days = (((YY-70)*365)+((YY-69)/4) + modays[isleap][MM]);
X secs = (((days+DD-1)*24L*3600L) + (hh*3600L) + (mm*60) + ss);
X
X if(!gmtflag) {
X secs += timezone;
X when = localtime(&secs);
X if(when->tm_isdst) secs -= 3600;
X }
X return(secs);
X }
SHAR_EOF
$TOUCH -am 1016221090 parsetime.c &&
chmod 0644 parsetime.c ||
echo "restore of parsetime.c failed"
set `wc -c parsetime.c`;Wc_c=$1
if test "$Wc_c" != "10619"; then
echo original size 10619, current size $Wc_c
fi
fi
# ============= resched.c ==============
if test X"$1" != X"-c" -a -f 'resched.c'; then
echo "File already exists: skipping 'resched.c'"
else
echo "x - extracting resched.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > resched.c &&
X/* ------------------------------------------------------------
X reschedule a cron job:
X
X Resched scans the scheduling information in the global JOB
X structure, jjj, comparing it to jtime, and determines the
X next time that a job is supposed to run. It returns the
X answer or -1L if the scheduling info is invalid.
X
X This is a weird algorithm. You'd think there would be a more
X elegant way, maybe some matrix calculations. But, anyway, it
X is fairly fast. It's an O-sum rather than O-product method
X because, eg., minutes are reset if hours need searching.
X ------------------------------------------------------------ */
X
X#include <time.h>
X#include <setjmp.h>
X#include "job.h"
X
Xextern struct tm *localtime();
Xextern void tzset();
Xextern long timezone;
Xextern void longjmp();
X
Xextern JOB jjj; /* global JOB struct */
X
X
Xstatic int thirty[2][12] = {31,28,31,30,31,30,31,31,30,31,30,31,
X 31,29,31,30,31,30,31,31,30,31,30,31};
X
Xstatic int modays[2][12] = {0,31,59,90,120,151,181,212,243,273,304,334,
X 0,31,60,91,121,152,182,213,244,274,305,335};
X
Xstatic int ss;
Xstatic int mm;
Xstatic int hh;
Xstatic int DD;
Xstatic int MM;
Xstatic int YY;
Xstatic int ww;
Xstatic int chk;
Xstatic struct tm *sched;
Xstatic int isleap;
Xstatic long days;
Xstatic long jtime;
Xstatic jmp_buf bad;
X#define badsched() longjmp(bad,-1)
X
Xstatic void incmon()
X {
X MM = (++MM)%12;
X if(MM == 0) {
X ++YY;
X isleap = ((YY%4)==0)? 1: 0;
X }
X }
X
Xstatic void chkmon()
X {
X if(jjj.mon[MM] == '\0') {
X ss = mm = hh = 0;
X DD = 1;
X do {
X if(--chk < 0) badsched();
X incmon();
X } while(jjj.mon[MM] == '\0');
X
X /* find day of the week: 00:00 Jan 1 1970 GMT was Thursday */
X days = (((YY-70)*365)+((YY-69)/4) + modays[isleap][MM]);
X ww = (int)((days+4)%7);
X }
X }
X
Xstatic void incday()
X {
X ww = (++ww)%7;
X ++DD;
X if(DD > thirty[isleap][MM]) {
X DD = 1;
X incmon();
X chkmon();
X }
X }
X
Xstatic void chkday()
X {
X if((jjj.wday[ww] == '\0') && (jjj.mday[DD] == '\0')) {
X ss = mm = hh = 0;
X do {
X if(--chk < 0) badsched();
X incday();
X } while((jjj.wday[ww]=='\0') && (jjj.mday[DD]=='\0'));
X }
X }
X
Xstatic void inchour()
X {
X hh = (++hh)%24;
X if(hh == 0) {
X incday();
X chkday();
X }
X }
X
Xstatic void chkhour()
X {
X if(jjj.hour[hh] == '\0') {
X ss = mm = 0;
X do {
X if(--chk < 0) badsched();
X inchour();
X } while(jjj.hour[hh] == '\0');
X }
X }
X
Xstatic void incmin()
X {
X mm = (++mm)%60;
X if(mm == 0) {
X inchour();
X chkhour();
X }
X }
X
Xstatic void chkmin()
X {
X if(jjj.min[mm] == '\0') {
X ss = 0;
X do {
X if(--chk < 0) badsched();
X incmin();
X } while(jjj.min[mm] == '\0');
X }
X }
X
X/* ------------------------------------------------------------ */
X
Xlong resched(tim)
X long tim;
X {
X jtime = tim + 60; /* kick ahead 1 min */
X
X/* check that sched arrays are valid
X * if takes more than 60+24+31+12 loops
X * then schedule is invalid
X */
X chk = (60+24+31+12)*2;
X if(setjmp(bad)) return(-1L);
X
X tzset();
X sched = localtime(&jtime);
X ss = sched->tm_sec;
X mm = sched->tm_min;
X hh = sched->tm_hour;
X DD = sched->tm_mday;
X MM = sched->tm_mon;
X YY = sched->tm_year;
X ww = sched->tm_wday;
X isleap = ((YY%4)==0)? 1: 0; /* works for year 2000 */
X
X chkmon();
X chkday();
X chkhour();
X chkmin();
X
X days = (((YY-70)*365)+((YY-69)/4) + modays[isleap][MM]);
X jtime = (((days+DD-1)*24L*3600L)+(hh*3600L)+(mm*60)+ss+timezone);
X sched = localtime(&jtime);
X if(sched->tm_isdst) jtime -= 3600;
X if(jtime <= tim) jtime += 3600; /* kludge around 2:00am dst */
X return(jtime);
X }
X
SHAR_EOF
$TOUCH -am 1009070890 resched.c &&
chmod 0644 resched.c ||
echo "restore of resched.c failed"
set `wc -c resched.c`;Wc_c=$1
if test "$Wc_c" != "3496"; then
echo original size 3496, current size $Wc_c
fi
fi
# ============= version ==============
if test X"$1" != X"-c" -a -f 'version'; then
echo "File already exists: skipping 'version'"
else
echo "x - extracting version (Text)"
sed 's/^X//' << 'SHAR_EOF' > version &&
X****************************************************
X************ cron facility by D.Lashomb ************
X****************************************************
X
XThis is an informal revision history for the cron facility:
X
X1.0 March 89 minimal daemon. at(1) and batch(1) working
X
X2.0 April 89 source code is broken into multiple files for
X easier dev and maint. added cronjob(1).
X
X2.5 April 89 added crontab(1). incr number of jobs facility
X can handle by decr bytes passed thru fifo and
X stored in mem. multiple forms of JOB struct.
X added MAXKIDS param. daemon's sleep/wake cycle
X now adjusts for time used while awake. many
X other tweeks - first *real* version
X
X2.6 April 89 fixed minor bug in cleanlog with uid=cron.
X released to jbm at uncle
X
X2.7 May 17, 89 faster day of week calc in resched.c and kludge
X around resched problem at 2:00am d.s.t. changes
X
X2.8 June 19, 89 fixed align() in daemon.c
X
X2.8.1 July 3, 89 crontab must run as SUID=root because of bug in
X setuid() with uid=0. changed README and Install
X
X2.9 July 16, 89 fixed problem in at.c concerning getpwnam() - I
X forgot that it uses static area of memory. This
X bug was introduced in ver 2.6 when I put in code
X for getpwnam("cron"). Cosmetic changes to cron.h
X and README file.
X
X3.0 July 26, 89 Runtime speedup: user's shell is now put in job file
X by at(1) ... crontab(1) instead of daemon having to
X search passwd file to get this info. At(1) ... have
X to check the passwd file in order validate LOGNAME
X anyway, so this is much more effecient.
X
X Added SET_LOGNAME code to putenv("LOGNAME=root")
X for uid=0 when normal LOGNAME check fails for at(1)
X ... crontab(1) commands. Thanks to John Milton for
X this suggestion. Pulled allow/deny checking out of
X at.c and crontab.c and put it in a new file allow.c
X
X Cleanup and reorganized use of some globals. Minor
X additions to makefile. Fixed man pages re: LOGNAME
X
X3.0.1 Dec 21, 89 Added caveats to README file, released to usenet.
X
X4.0 Sep-Oct, 90 New getwd() code fixes read() bug not reading until
X newline from /bin/pwd.
X
X Added "all" arg to -l option for symmetry with -r
X
X Pulled getwd and dir code out of at.c into new files
X getwd.c and dir.c
X
X Sprinkled the code with register variables.
X
X Tried to cleanup the use of global/static variables.
X
X Streamlined allow mechanism for at.c and crontab.c
X Handles degenerate case of LOGNAME=root better and
X is faster. One login() routine does it all. Code
X is in file login.c, formerly called allow.c
X
X Fixed execlp() in crontab.c - was missing NULL last
X arg. Why this didn't cause any problem before, I
X don't know; just lucky I guess.
X
X Used dir.c routines in initlist() memlist.c instead
X of using popen to ls(1) command.
X
X rdfifo() and wrfifo() always used global jjj JOB
X struct, so no need of passing &jjj to them at every
X call. Changed to use global jjj.
X
X insert() in memlist.c always called with &jjj, too.
X Changed to use global jjj.
X
X Added -x option to execute jobs at will. This req'd
X changes to at.c, daemon.c, job.h and job.c to support
X the new EXECUT msg type.
X
X Better checking of numeric jobnumber/filename in at.c
X
X A new scheme for marking completed job files is used.
X Previously AT_JOBs, BATCHJobs and CR_JOBs were marked
X with an extra newline and a "# job done\n" as the
X last act of writing a new job file. This was done to
X insure that only complete jobs would be executed.
X The new scheme uses the first 4 bytes in the file as
X a magic number. The magic number is initialized to
X NOMAGIC when working on the job file. As the last
X act of writing a new job file, the file is rewound
X and the magic number, MAGIC, is written in the file.
X The envc and envz fields of the header also play a
X role similar to the magic in the new scheme.
X
X Added throwaway program, convertjob, to ease the
X upgrading old style jobs to the new scheme.
X
X The new scheme fixes the problem of at's -u option
X displaying the extra newline.
X
X Removed the requirement for having to have a crontab
X file in place in order for CR_TAB jobs to survive a
X reboot.
X
X Better checking of job files by openjob() in daemon.c
X
X Made the daemon a little smarter about handling
X changes to the system clock. If someone changes the
X system clock more than just a little bit, the daemon
X resets its idea of the time.
X
X Fixed man pages to reflect the above changes.
X Split off Design_Notes from README file.
SHAR_EOF
$TOUCH -am 1016214790 version &&
chmod 0644 version ||
echo "restore of version failed"
set `wc -c version`;Wc_c=$1
if test "$Wc_c" != "4537"; then
echo original size 4537, current size $Wc_c
fi
fi
exit 0
More information about the Alt.sources
mailing list