/* lwatch is (c) by G. Caronni in '97            <gec@acm.org> */
/* It is free software, and covered by the GNU public license, */
/* version 2 or later. Provided AS IS, no warranty or support. */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>
#include <string.h>


#define VERSION         "1.1"
#define STOP_LOAD       1.6
#define RUN_LOAD        0.6
#define INTERVALL       60 /* seconds */
#define UPTIME          "/usr/ucb/uptime"

char *subprog[] = { "/home/caronni/desclient", "desclient", 
    "-s", "keymaster.des.sollentuna.se", 
    "-e", "gec@acm.org", "-n", "20", NULL};


int pid=0;
int verbose=0;

float getload(void)
{
    char buf[1024], *t;
    float load;
    FILE *p=popen(UPTIME,"r");

    if (!p) {
        perror("popen");
        if (verbose) printf("Collecting load stats failed.\n");
        if (verbose) printf("Terminating child...\n");
        kill (pid,SIGTERM);
        exit(2);
    }
    fgets(buf,sizeof(buf),p);
    pclose(p);
    t=strstr(buf,"load average");
    if (t) t=strtok(t,",");
    if (t) t=strtok(NULL,", ");
    if (t && sscanf(t,"%f",&load)==1) {
        if (verbose) printf("Scanned load: %0.2f\n",load);
    } else {
        if (verbose) printf("Parsing load stats failed.\n");
        if (verbose) printf("Terminating child...\n");
        kill (pid,SIGTERM);
        exit(2);
    }
    return load;
}


int main(int argc, char *argv[], char *envp[])
{

    extern int optind;
    extern char *optarg;
    int c;
    int errflg = 0;
    float stop_load, run_load;
    char **sprog=subprog;
 
    *envp=NULL;

    stop_load=run_load=0.0;

    while ((c = getopt(argc, argv, "vs:r:")) != EOF) {
        switch (c) {
            case 'v':
                verbose++;
                break;
            case 's':
                if (sscanf(optarg,"%f",&stop_load)!=1) errflg++;
                break;
            case 'r':
                if (sscanf(optarg,"%f",&run_load)!=1) errflg++;
                break;
            case '?':
                errflg++;
        }
    }
    if (!stop_load) {
        stop_load=STOP_LOAD;
        if (!run_load) run_load=RUN_LOAD;
    } else if (!run_load) run_load=stop_load;
    
    if (stop_load <= 1.0) errflg++;
    if (run_load > stop_load) errflg++;
    if (errflg) {
        (void)fprintf(stderr, 
            "Usage: %s [-v] [-s stopload] [-r runload] [command to
call]\n"
            "       -v          verbose\n"
            "       -s stopload process will be stopped if load
surpassed\n"
            "                   load specified must be higer than 1.0\n"
            "       -r runload  process will be restarted at this
load\n"
            "                   load specified must be lower than
stopload\n"
        ,argv[0]);     
        exit(1);
    }
    if (optind < argc) sprog = &(argv[optind]); 

    if (verbose) {
        int i=0;
        printf("Load watcher (%s), runload: %0.2f, stopload: %0.2f, "
               "command to be executed:\n",
               VERSION, run_load,stop_load);
        while(sprog[i]) printf("%s ",sprog[i++]);
        printf("\n");
    }
    signal(SIGCHLD,SIG_IGN);

    /* ============================================ */
    if (!(pid=fork())) {
        execv(*sprog,sprog);
        perror("execv");
        exit(-1);
    }
    /* ============================================ */

    if (pid<0) {
        perror("fork");
        exit(-1);
    }
    sleep(1);
    
    while (1) {
        if (kill(pid,0)) {
            if (verbose) {
                perror("kill(pid,0)");
                fprintf(stderr, "Child process unreachable.
Terminating...\n");
            }
            break;
        } 

        if (getload()>stop_load) {
            if (verbose) printf("Maximum load exceeded. Idling...\n");
            if (kill(pid,SIGSTOP)) {
                if (verbose) {
                    perror("kill(pid,SIGSTOP)");
                    fprintf(stderr,
                           "Child process unreachable.
Terminating...\n");
                }
                break;
            }
            while(getload()>run_load) sleep (INTERVALL);
            if (verbose) printf("Load below threshold.
Continuing...\n");
            if (kill(pid,SIGCONT)) {
                if (verbose) {
                    perror("kill(pid,SIGCONT)");
                    fprintf(stderr,
                           "Child process unreachable.
Terminating...\n");
                }
                break;
            }
        }
        sleep(INTERVALL);
    }
    return 0;
}

/* EOT */

