home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 1: Amiga
/
FrozenFish-Apr94.iso
/
bbs
/
alib
/
d8xx
/
d801
/
cybercron.lha
/
CyberCron
/
RexxScripts
/
at.rexx
next >
Wrap
OS/2 REXX Batch file
|
1993-01-24
|
16KB
|
723 lines
/*rx
* at.rexx --- simulate UNIX at command. For use with CyberCron.
* By Loren J. Rittle (rittle@comm.mot.com) - Tue May 5 01:47:11 1992
* Updated to work with any AmigaOS shell - Wed May 6 03:32:00 1992
*
* Copyright © 1992 Loren J. Rittle
* Use as you will, just document your changes and keep my copyright
* notice intact. Feel free to mail enhancements to me.
*
* Modifications © 1992 by Graham Walter (gwalter@gwalter.demon.co.uk)
* Following added:
* Ability to specify date, incremental time periods
* Remove (-r option) jobs
* List (-l option)
* Schedule (-s option) - used to reschedule jobs if
* CyberCron is restarted (due to eg reboot)
*
* Usage:
* at [-q[ac-z]] time [day [month [year]] [+ increment timeperiod]
* <shell script>
* <EOF>
*
* at -qb
* <shell script>
* <EOF>
*
* at -l [<task name as given at issue time, or from list>]
* [for list current 'at' job(s)]
*
* at -r <task name as given at issue time, or from list>
* [remove an 'at' job as shown in list]
*
* at -s
* [schedule any unscheduled jobs]
*/
/* USER MODIFIABLE DEFAULT, EDIT TO TASTE */
/* AT_FILES should be somewhere that only at writes to.
T: is not a suitable location, IMHO. In the future, at.rexx
and some startup code magic might know how to requeue jobs
that should have been run while power was off or after a crash
occurred. To prepare for this, AT_FILES should be on a real
file system. */
AT_FILES = 's:at/'
CRONLOG = "T:CronLog"
/* NO GENERAL USER MODIFIABLE PARTS BELOW THIS COMMENT. */
/* Default queue to place jobs in. Remember queue 'b' is special. */
QUEUE = 'a'
HOUR = '00'
MINUTE = '00'
options results
parse arg Parameters
parse arg option line xline
if left( option, 2 ) = "-l"
then do
call ListAt line
exit
end
if left( option, 2 ) = "-r"
then do
call RemoveAt line
exit
end
if left( option, 2 ) = "-s"
then do
call ReSchedule line
exit
end
call ParseParameters Parameters
do 100 until ~ exists( AT_FILES || ID )
ID = GenerateId()
end
if exists( AT_FILES || ID )
then call ErrorExit 'at: can''t find unused ID'
scriptfile = AT_FILES || ID
if ~open('sfh', scriptfile, 'W')
then call ErrorExit 'at: can''t open' scriptfile 'for output'
call writeln('sfh', '; ****** Start of Prologue *******')
call writeln('sfh', '; ****** At Job' ID ' *******')
call writeln('sfh', 'cd' '22'x||pragma('D')||'22'x)
call writeln('sfh', 'stack' pragma('S', 4000))
if left(address(), 4) == 'WSH_'
then do
/*
* If we have a WShell under us, then try to propagate
* local environment variables. If you don't, I'm not
* sorry for you, read comments below. :-)
*/
'set | execio stem VARS.'
do i = 1 to VARS.0
if find( "PROCESS RC RESULT2", upper( word(VARS.i, 1) ) ) = 0
then call writeln('sfh', 'set' VARS.i)
end
end
else say 'warning: WShell not present under your ARexx, local environment variables can''t be propagated'
call writeln('sfh', '; ******** End of Prologue *******')
line = readln( stdin )
do while ~ eof( stdin )
call writeln('sfh', line)
line = readln(stdin)
end
call writeln('sfh', '; ****** Start of Epilogue *******')
call writeln('sfh', 'run <nil: >nil: delete' scriptfile)
call close('sfh')
address command 'protect' scriptfile '+s'
USER = getenv('USER')
if left(address(), 4) == 'WSH_' then
do
/*
* If we have a WShell under us, then try to get a local
* environment variable with the name USER to override
* the global USER setting.
* If you don't have a WShell under you, then why not? :-)
* Basically, you are less than human if you don't have a WShell
* under you. If everyone had a WShell under their ARexx,
* I wouldn't have to write such weird ARexx code. I hate you
* if you don't WShell under your ARexx, cause you make my life
* Hell! Does anyone read these comments, or I'm I wasting
* my time here? :-)
*/
/* AmigaDOG braindamage: */
'get USER >nil:'
if rc == 0 then
'get USER | execio var USERX'
else
USERX = ''
if USERX ~= '' then
USER = USERX
end
else
say 'warning: WShell not present under your ARexx, local environment variable USER can''t be checked'
if USER == ''
then do
say 'warning: USER environment variable not set, mail will be sent to root'
USER = 'root'
end
address command "filenote" scriptfile '"'USER'.'QUEUE'.'execdate'-'HOUR||MINUTE'"'
call ScheduleJob ID User Queue execdate Hour||Minute
exit
/* ***************************************************************** */
/* Functions */
/* ***************************************************************** */
ParseParameters: /* Parse the parameters specified to At */
if left(option, 2) == '-q'
then do
if length(option) ~= 3
then call ErrorExit 'at: invalid ''-q'' parameter'
QUEUE = right(option, 1)
if pos(QUEUE, xrange('a','z')) == 0
then call ErrorExit 'at: invalid queue name,' QUEUE
parse arg option line
end
else parse arg line
IncrementPart = ""
parse var line line '+' IncrementPart
parse var line line xline
parse var IncrementPart Increment Unit .
UnitNo = 1 /* default to minutes */
if Unit ~= ""
then do
AbbrevUnit = upper( left( Unit, 3 ) )
UnitNo = find( "MIN HOU DAY WEE MON YEA", AbbrevUnit )
if UnitNo = 0
then call ErrorExit "at: Invalid increment unit:" Unit
end
if Increment ~= ""
then do
if ~ datatype( Increment, "N" )
then call ErrorExit "at: Invalid increment:" Increment
end
if QUEUE == 'b'
then do
if line ~= ''
then call ErrorExit 'at: time can''t be given for use with b[atch] queue'
HOUR = '*'
MINUTE = '*'
end
else do
if line == ''
then do
say 'at: time must be given for use with' QUEUE 'queue'
exit 10
end
nowdate = date( 's' )
now = time()
nowhour = left( now, 2 )
nowminute = substr( now, 4, 2 )
if upper( line ) ~= "NOW"
then do
if length(line) > 4 | ~datatype(line, 'N')
then call ErrorExit 'at: "'line'" is not a valid time, must be of form: H, HH, HMM, HHMM'
if length(line) > 2
then do
if length( line ) < 4
then line = "0"line
MINUTE = right(line, 2)
HOUR = left(line, length(line) - 2)
end
else HOUR = line
if MINUTE < 0 | MINUTE > 59 | HOUR < 0 | HOUR > 23
then call ErrorExit 'at: "'line'" is not in the range of a valid time'
end
else do
HOUR = nowhour
MINUTE = nowminute
end
/*trace ?i*/
execdate = nowdate
if xline ~= ""
then do
parse var xline d1 d2 d3 .
if d2 ~= "" & ~ datatype( d1, "N" ) & datatype( d2, "N" )
then do
temp = d1
d1 = d2
d2 = temp
end
if d3 ~= ""
then do
if ~ datatype( d3, "N" ) | length( d3 ) > 4
then call ErrorExit "at: Invalid year -" d1
if d3 < 100 & d3 >= substr( nowdate, 3, 2 )
then execdate = "19"right( "00"d3, 2 ) || substr( execdate, 5 )
else execdate = overlay( d3, "2000", 5 - length( d3 ) ) || substr( execdate, 5 )
end
if d2 ~= ""
then do
Month = find( "JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC", upper( d2 ) )
if Month = 0
then call ErrorExit "at: Invalid month -" d2
execdate = left( execdate, 4 ) || right( "00"Month, 2 ) || right( execdate, 2 )
end
if d1 ~= ""
then do
if ~ datatype( d1, "N" )
then call ErrorExit "at: Invalid day of month -" d1
execdate = left( execdate, 6 ) || right( "00"d1, 2 )
end
end
if Increment ~= ""
then do
/*trace ?i*/
if UnitNo <= 4
then do
UDayno = date( 'i', execdate, 's' )
if UnitNo = 1
then Minute = Minute + Increment
else if UnitNo = 2
then Hour = Hour + Increment
else if UnitNo = 3
then UDayno = UDayno + Increment
else if UnitNo = 4
then UDayno = UDayno + Increment * 7
Hour = right( "00" || Hour + Minute % 60, 2 )
Minute = right( "00" || Minute // 60, 2 )
UDayno = Udayno + Hour % 24
execdate = date( 's', Udayno, 'i' )
end
else do
Year = left( execdate, 4 )
if UnitNo = 5
then do
Month = substr( execdate, 5, 2 ) + Increment
Year = Year + ( Month - 1 ) % 12
Month = right( "00" || ( Month - 1 ) // 12 + 1, 2 )
execdate = Year || Month || substr( execdate, 7 )
end
else do
execdate = Year + Increment || substr( execdate, 5 )
end
end
end
if execdate'@'Hour':'Minute <= nowdate'@'nowhour':'nowminute
then do
if xline = ""
then execdate = date( 's', date('i') + 1 )
else if d2 = ""
then do
if substr( execdate, 5, 2 ) = 12
then execdate = left( execdate, 4 ) + 1 || "01" || right( execdate, 2 )
else execdate = left( execdate, 4 ) || right( "00"substr( execdate, 5, 2 ) + 1, 2 ) || right( execdate, 2 )
end
else if d3 = ""
then do
execdate = left( execdate, 4 ) + 1 || substr( execdate, 5 )
end
else call ErrorExit "at: Too late for" date("n", execdate, "s") Hour":"Minute
end
Day = substr( execdate, 7, 2 )
Month = substr( execdate, 5, 2 )
Days = word( "31 28 31 30 31 30 31 31 30 31 30 31", Month )
if Month = 2 & left( execdate, 4 ) // 4 = 0
then Days = 29
if day > Days & UnitNo = 5
then do
day = Days
execdate = left( execdate, 6 ) || day
end
if day < 1 | day > Days
then call ErrorExit "at: Invalid day of month -" d1
/*say execdate Hour":"Minute*/
/*exit 20*/
end
return
/* ***************************************************************** */
ErrorExit:
parse arg message
say message
exit 10
/* ***************************************************************** */
GetCronEvents:
/*trace ?i*/
events = ""
if show( "ports", CYBERCRON )
then do
address CYBERCRON 'LIST_EVENTS'
eventlist = result
numwords = words(eventlist)
if (numwords > 0) & (word(eventlist,1) ~= "<None>")
then do
do j = 1 to numwords
event = word( eventlist, j )
address CYBERCRON 'SHOW_EVENT' event
events = events || '0a'x || result
end
end
end
if events ~= ""
then events = substr( events, 2 )
return events
/* ***************************************************************** */
ListJob: procedure expose AT_FILES CRONLOG NJobs Events Header
parse arg Job
if ~ datatype( NJobs, "N" )
then NJobs = 0
JobInfo = statef( AT_FILES || Job )
if JobInfo = ""
then do
say "Job" Job "not found"
return
end
parse var JobInfo . . . . fdays fmins fticks User '.' queue '.' edate '-' etime
ftime = right( "0000"etime, 4 )
ftime = left( ftime, 2)":"right( ftime, 2 )
User = strip( User )
if index( Events, AT_FILES || Job ) ~= 0
then do
jsched = "Scheduled"
if Queue = 'b'
then do
if bMax = "BMAX"
then do
address CYBERCRON GET_QUEUE_MAX b
bMax = rc /* Cybercron passes answer in rc ! */
end
if bMax = 0
then jsched = "Held"
else jsched = "Waiting"
end
jstat = ""
NJobs = NJobs + 1
end
else do
JobStartInfo = SearchCronLog( Job )
if JobStartInfo = ""
then do
jsched = "NOT SCHEDULED"
jstat = "***"
end
else do
parse var JobStartInfo '(' JobStartDate ')' . JobNo jstart JobFileName
jsched = jstart JobStartdate
end
end
if Header ~= ""
then do
say "User Job Q Date Time Status"
Header = ""
end
if Queue ~= 'b'
then jexec = date("n", edate, "s") ftime
else jexec = " "
say left( User, 16 ) Job Queue jexec jsched
return
/* ***************************************************************** */
ListAt: procedure expose AT_FILES CRONLOG
parse arg ID
NJobs = 0
Events = GetCronEvents()
if ID ~= ""
then do
Job = right( "0000"ID, 4 )
call ListJob( Job )
if open( fh, AT_FILES || Job, "r" )
then do
say "-------------------------------------------------"
do while ~eof( fh )
Line = readln( fh )
if Line = '; ******** End of Prologue *******'
then break
end
do while ~eof( fh )
Line = readln( fh )
if Line = '; ****** Start of Epilogue *******'
then break
say Line
end
call close fh
end
exit
end
Jobs = showdir( AT_FILES )
/*trace ?i*/
do i = 1 to words( Jobs )
Job = word( Jobs, i )
if upper( Job ) ~= "AT.SEQ"
then call ListJob Job
end
say NJobs "jobs waiting"
return
/* ***************************************************************** */
ScheduleJob: procedure expose AT_FILES
parse arg Job User Queue edate etime .
if Queue ~= 'b'
then do
Day = right( edate, 2 )
Month = substr( edate, 5 , 2 )
Hour = left( etime, 2 )
Minute = right( etime, 2 )
end
else do
address CYBERCRON get_queue_max b
qbmax = rc /* Cybercron passes answer in rc ! */
if qbmax = 0
then bStatus = "awaiting resources"
else bStatus = "will be scheduled soon"
address CYBERCRON 'ADD_EVENT :MAILUSER' USER ':EXECONCE :OBEYQUEUE' QUEUE '* * * * *' AT_FILES || Job
if rc = 0
then say "Job" Job bStatus
else say "Job" Job "schedule failed"
return
end
nowdate = date( 's' )
now = time()
nowtime = left( now, 2 ) || substr( now, 4, 2 )
yearstime = left( nowdate, 4 ) + 1 || substr( nowdate, 5 )
if edate'@'etime <= nowdate'@'nowtime
then do
say "at: Warning: job" Job "not scheduled - too late"
end
else if edate'@'etime < yearstime'@'now
then do
address CYBERCRON 'ADD_EVENT :MAILUSER' USER ':EXECONCE :OBEYQUEUE' QUEUE MINUTE HOUR DAY MONTH '*' AT_FILES || Job
if rc = 0
then say "Job" Job "scheduled for" date( "n", edate, "s" ) Hour":"Minute
else say "Job" Job "schedule failed"
end
else do
say "at: Warning: job" Job "not scheduled - too far in the future"
end
return
/* ***************************************************************** */
ReSchedule: procedure expose AT_FILES
parse arg ID
Jobs = showdir( AT_FILES )
Events = GetCronEvents()
do i = 1 to words( Jobs )
Job = word( Jobs, i )
if upper( Job ) = "AT.SEQ"
then iterate
if index( Events, AT_FILES || Job ) = 0
then do
JobInfo = statef( AT_FILES || Job )
if JobInfo = ""
then do
say "Job" Job "not found"
iterate
end
parse var JobInfo . . . . fdays fmins fticks User '.' queue '.' edate '-' etime
call ScheduleJob Job User Queue edate etime
end
end
return
/* ***************************************************************** */
RemoveAt: procedure expose AT_FILES
parse arg Job
Job = right( "0000"Job, 4 )
if ~ exists( AT_FILES || Job )
then call ErrorExit "at: job" Job "not found."
Events = GetCronEvents()
do while Events ~= ""
parse var Events EventLine '0a'x Events
if index( EventLine, AT_FILES || Job ) ~= 0
then break
EventLine = ""
end
if EventLine ~= ""
then do
parse var EventLine EventID .
address cybercron delete_event EventID
if rc ~= 0
then say "at: warning - couldn't remove CyberCRON event"
end
call delete AT_FILES || Job
say "Job" Job "removed."
return
/* ***************************************************************** */
GenerateID: procedure expose AT_FILES
if open( fh, AT_FILES || "at.seq", "r" )
then do
ID = readln( fh )
call close fh
end
else ID = 0
if ID > 9999
then ID = 0
ID = ID + 1
if open( fh, AT_FILES || "at.seq", "w" )
then do
call writeln( fh, id )
call close fh
end
return right( "0000"ID, 4 )
/* ***************************************************************** */
SearchCronLog: procedure expose AT_FILES CRONLOG
parse arg ID
/*trace ?i*/
if ~ exists( CRONLOG )
then return ""
/*"execio" read CRONLOG locate AT_FILES || ID var Startinfo*/
tfile = "T:at-info-" || ID
"search >"tfile CRONLOG AT_FILES || ID
if rc = 0
then do
if open( fht, tfile, "r" )
then do
Startinfo = readln( fht )
call close( fht )
end
else Startinfo = ""
end
else Startinfo = ""
call delete( tfile )
return Startinfo