<Begin schedule.h>
#define NUMEVENTS 100 #define MAXFDS 20 char * host = "crabapple"; char * port = "5432"; char * tty = ""; char * option = ""; char * dbname = "jim"; char* LOGFILE = "/usr/schedule/schedlog"; void update(char*,char*);<Begin schedule.c>
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <bits/signum.h> #include <string.h> #include <time.h> #include <signal.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/wait.h> #include <bits/waitflags.h> #include <libpq-fe.h> #include <sqlca.h> #include "schedule.h" struct { char days[8]; char time[6]; char program[101]; char checkprog[101]; char didrun[2]; } schedule[NUMEVENTS]; PGconn *conn; FILE *LOG; void openlog() { LOG = fopen(LOGFILE,"w"); if(!LOG){ exit(EXIT_FAILURE); } } void logit(char * message) { fprintf(LOG,"%s\n",message); return; } int read_config() { int i; PGresult *res; char buf[100]; conn = PQsetdb(host,port,tty,option,dbname); if(PQstatus(conn) == CONNECTION_BAD){ logit("Connection to database failed."); sprintf(buf, "%s", PQerrorMessage(conn)); logit(buf); exit(EXIT_FAILURE); } res = PQexec(conn,"BEGIN"); if(PQresultStatus(res) != PGRES_COMMAND_OK){ logit("Begin command failed."); exit(EXIT_FAILURE); } PQclear(res); res = PQexec(conn,"declare mycursor cursor for select * from schedule where didrun = 'N'"); if(PQresultStatus(res) != PGRES_COMMAND_OK){ logit("Cursor command failed."); exit(EXIT_FAILURE); } PQclear(res); res = PQexec(conn,"FETCH ALL IN mycursor"); if(PQresultStatus(res) != PGRES_TUPLES_OK){ logit("Fetch failed."); exit(EXIT_FAILURE); } for(i = 0; i < NUMEVENTS; i++){ strcpy(schedule[i].didrun,"Y"); } for(i = 0;i < PQntuples(res);i++){ strncpy(schedule[i].days,PQgetvalue(res,i,0),7); schedule[i].days[PQgetlength(res,i,0) + 4] = '\0'; strncpy(schedule[i].time,PQgetvalue(res,i,1),5); schedule[i].time[PQgetlength(res,i,1) + 4] = '\0'; strncpy(schedule[i].program,PQgetvalue(res,i,2),100); schedule[i].program[PQgetlength(res,i,2) + 4] = '\0'; strncpy(schedule[i].checkprog,PQgetvalue(res,i,3),100); schedule[i].checkprog[PQgetlength(res,i,3) + 4] = '\0'; strncpy(schedule[i].didrun,PQgetvalue(res,i,4),1); schedule[i].didrun[1] = '\0'; } schedule[i].days[0] = '\0'; PQclear(res); res = PQexec(conn,"CLOSE mycursor"); PQclear(res); res = PQexec(conn,"END"); PQclear(res); PQfinish(conn); return 0; } void update(char *prog,char *state) { char buf[200]; PGresult *res; conn = PQsetdb(host,port,tty,option,dbname); if(PQstatus(conn) == CONNECTION_BAD){ logit("Connection to database failed."); exit(EXIT_FAILURE); } sprintf(buf,"update schedule set didrun = \'%s\' \ where program = \'%s\'",state,prog); res = PQexec(conn,"BEGIN"); if(PQresultStatus(res) != PGRES_COMMAND_OK){ exit(EXIT_FAILURE); } PQclear(res); res = PQexec(conn,buf); if(PQresultStatus(res) != PGRES_COMMAND_OK){ exit(EXIT_FAILURE); } PQclear(res); PQexec(conn,"COMMIT"); PQfinish(conn); return; } void dofork(int j) { int k,hour,min; char msg[120]; pid_t pid; time_t t; struct tm *tmp; time(&t); tmp = localtime(&t); hour = tmp->tm_hour; min = tmp->tm_min; pid = fork(); if(pid == 0) { /* This is the child. */ update(schedule[j].program,"P"); k = system(schedule[j].checkprog); if(k == 0){ ; } else { update(schedule[j].program,"N"); sprintf(msg,"%s failed at %02d:%02d",schedule[j].checkprog,hour,min); logit(msg); exit(EXIT_FAILURE); } k = system(schedule[j].program); time(&t); tmp = localtime(&t); hour = tmp->tm_hour; min = tmp->tm_min; if(k == 0){ update(schedule[j].program,"Y"); sprintf(msg,"%s succeeded at %02d:%02d",schedule[j].program,hour,min); logit(msg); exit(EXIT_SUCCESS); } else { update(schedule[j].program,"N"); sprintf(msg,"%s FAILED at %02d:%02d",schedule[j].program,hour,min); logit(msg); exit(EXIT_FAILURE); } } else { /* This is the parent */ sleep(30); /* Give the child some time */ read_config(); return; } } void scheduler(void) { int j = 0,day,hour,min,k,l; time_t t; struct tm *tmp; while(1){ time(&t); tmp = localtime(&t); hour = tmp->tm_hour; min = tmp->tm_min; day = tmp->tm_wday; if(schedule[j].days[day] == 'N'){ j++; if(schedule[j].days[0] == '\0'){ j = 0; sleep(60); read_config(); continue; } continue; } sscanf(schedule[j].time,"%02d:%02d",&k,&l); if((hour > k) || ((k == hour) && (min >= l))){ if(schedule[j].didrun[0] == 'N'){ dofork(j); j++; if(schedule[j].days[0] == '\0'){ j = 0; sleep(60); read_config(); continue; } continue; } else { j++; if(schedule[j].days[0] == '\0'){ j = 0; sleep(60); read_config(); continue; } continue; } } j++; if(schedule[j].days[0] == '\0'){ j = 0; sleep(60); read_config(); } } } void do_exit(int signo) { char buf[100]; time_t t; int hour,min; struct tm *tmp; if(signo != SIGUSR1){ ; } time(&t); tmp = localtime(&t); hour = tmp->tm_hour; min = tmp->tm_min; sprintf(buf,"Killed at %02d:%02d.",hour,min); logit(buf); exit(EXIT_SUCCESS); } void sig_child(int signo) { pid_t pid; int stat; if(signo != SIGCHLD){ ; } signal(SIGCHLD,sig_child); while((pid = waitpid(-1, &stat, WNOHANG)) > 0); return; } void setup() { signal(SIGHUP,SIG_IGN); signal(SIGINT,SIG_IGN); signal(SIGQUIT,SIG_IGN); signal(SIGILL,SIG_IGN); signal(SIGTRAP,SIG_IGN); signal(SIGABRT,SIG_IGN); signal(SIGIOT,SIG_IGN); signal(SIGBUS,SIG_IGN); signal(SIGFPE,SIG_IGN); signal(SIGKILL,SIG_IGN); signal(SIGUSR1,do_exit); signal(SIGSEGV,SIG_IGN); signal(SIGUSR2,SIG_IGN); signal(SIGPIPE,SIG_IGN); signal(SIGALRM,SIG_IGN); signal(SIGTERM,SIG_IGN); signal(SIGCHLD,sig_child); } void daemonize() { int i; pid_t pid; if((pid = fork()) != 0){ exit(EXIT_SUCCESS); } setsid(); if((pid = fork()) != 0){ exit(EXIT_SUCCESS); } chdir("/"); umask(0); for(i = 0; i < MAXFDS; i++){ close(i); } } int main(void) { int j; system("at -f /usr/schedule/reset.sh midnight"); daemonize(); setup(); openlog(); j = read_config(); if(j != 0){ exit(EXIT_FAILURE); } scheduler(); exit(EXIT_SUCCESS); }
<Begin Makefile>
schedule: schedule.c gcc -g -W -Wall -ansi -pedantic schedule.c -o schedule -lpq