INFO1112 2020 Assignment
This assignment involves developing a system to run programs at scheduled times.
This is similar to the Unix and Linux "cron" system.
Your program will read a configuration file that specifies what programs are to be run
and when. You will be able to specify that a given program is run periodically at
particular times, for example every Tuesday at 1pm, run a certain script. Alternatively
you could specify that a program be run at 8am, 12noon, 2pm and 4pm everyday.
Your system will consist of two programs:
● A program (runner.py) that will run in the background, reading the
configuration file that specifies what programs (with parameters) it should run
and when they should be started. Normally runner.py would be started
when the system is initialised, but for this assignment you can run the
program as a background process..
● The second command (runstatus.py) that is designed to get the current
status from runner.py and send it to the standard output.
Programs like runner.py are normally called "daemons" (pronounced the same
as "demon") and run in the background. There are many examples of daemons in
INFO1112 2020 Assignment 1 1
Linux, for example a printer daemon will manage a queue of files to send to the
printer. The configuration file for runner.py will be named $HOME/.runner.conf
and contains a list of programs to start, what time to start them and if they should be
run at that time regularly. The configuration file is described in more detail below.
The runner.py program should keep information about the current status: what
programs need to be run, what time they last ran, and when they are next due to be
run. If runner.py receives the SIGUSR1 signal it should open the file
$HOME/.runner.status and write the status information in a human readable
form to it, then close the file. This will be read by runstatus.py
At startup, runner.py should write its process ID into the file
$HOME/.runner.pid and check that the status file $HOME/.runner.status
exists. If the status file does not exist it should be created by runner.py.
The second command (runstatus.py) is designed to get the current status from
the system. It should send the SIGUSR1 signal to the runner.py program (using
the PID stored in $HOME/.runner.pid) and then open and read the status file
$HOME/.runner.status and send the contents to the standard output. Then
close the status file, reopen it in write mode to truncate it to zero length, close it
again and finally terminate. It should give an error message if anything fails, such as
$HOME/.runner.pid or $HOME/.runner.status missing, or nothing appears
in the file $HOME/.runner.status after 5 seconds. See error handling section
below.
Configuration File
The configuration file for runner.py will contain one line for each program that is to be
run. Each line has the following parts:
timespec program-path parameters
❏ timespec is the specification of the time that the program should be run
❏ program-path is a full path name of a program to run and the specified
time(s)
❏ parameters are the parameters for the program.
The timespec has the following format:
[every|on day[,day…]] at HHMM[,HHMM…] run
INFO1112 2020 Assignment 1 2
Square brackets mean the term is optional, vertical bar means alternative, three dots
means repeated. Terms in bold are keywords. Times are in 24 hour clock format.
Days are full day names that are case sensitive and start with capital letter.
Examples:
every Tuesday at 1100 run /bin/echo hello
- every tuesday at 11am run "echo hello"
on Tuesday at 1100 run /bin/echo hello
- on the next tuesday only, at 11am run "echo hello"
every Monday,Wednesday,Friday at 0900,1200,1500 run
/home/bob/myscript.sh
- every monday, wednesday and friday at 9am, noon and 3pm run myscript.sh
at 0900,1200 run /home/bob/myprog
- runs /home/bob/myprog at 9am and noon only. If 9am is already passed then
Status Messages
Status messages are
● a line of text for each time a program has been run or there was an error
● a line showing the next time it will be run.
The format for the output lines is:
ran date-time program-path parameters
error date-time program-path parameters
will run at date-time program-path parameters
where words in bold are fixed, date-time is a string in python time.ctime() format,
program-path is the full path of the program and parameters are the parameters
used.
Error handling
Your program should do detailed error checking. In particular,
● if you cannot open the configuration file you should print "configuration file not
found"
INFO1112 2020 Assignment 1 3
● if an error is detected in the configuration file you should print "error in
configuration: line" where line is the line of the file containing the error
● if the configuration file is empty, you should print "configuration file empty"
● if an error occurs during the fork/exec of a program, this should be noted in
the time record and the "error date-time program-path parameters" message
produced in the status
● if a file such as .runner.pid or .runner.status cannot be created or is not found,
or has some other error you should print: "file file-name error-message" where
file-name is the file that caused the error and error-message is an informative
message
● if the status does not arrive in 5 seconds print "status timeout"
● if runner.py has no programs to run (this will eventually occur if there are no
"every" lines in the configuration) then print the message "nothing left to run"
and terminate.
Your programs should never crash. If an error occurs a suitable message or status
produced. All error messages should be sent to stderr.
If any error is detected you need to report it. This includes failures of fork/exec,
creating a file, not finding a file that should be there etc.
An experienced programmer checks for as many error conditions as they can.
Thinking that "this can never happen therefore I won't check for it" is a bad idea.
You can assume processes finish inside 60 seconds and wait for each process to
complete before running the next. [Note that this would not be acceptable for a real
"cron" program. In order to handle all cases you would need to use the "waitpid"
function that is non-blocking, and check regularly.]