/*************************************************************/
/* Original version was an example in the kernel source tree */
/*                                                           */
/* Rest was written by me, Michael Meskes                    */
/* meskes@debian.org                                         */
/*                                                           */
/*************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <netdb.h>
#include <sched.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/mman.h>
#include <sys/wait.h>
#define __USE_GNU
#include <string.h>

#if !defined(__GLIBC__)		/* __GLIBC__ */
extern char *basename(const char *);
#endif				/* __GLIBC__ */

#include <unistd.h>

#include "watch_err.h"
#include "extern.h"

#if USE_SYSLOG
#include <syslog.h>
#endif				/* USE_SYSLOG */

static int no_act = FALSE;

#if USE_SYSLOG
int verbose = FALSE;
#endif				/* USE_SYSLOG */

#define ADMIN		"admin"
#define CHANGE		"change"
#define DEVICE		"watchdog-device"
#define	FILENAME	"file"
#define INTERFACE	"interface"
#define INTERVAL	"interval"
#define LOGTICK		"logtick"
#define MAXLOAD1	"max-load-1"
#define MAXLOAD5	"max-load-5"
#define MAXLOAD15	"max-load-15"
#define MAXTEMP		"max-temperature"
#define MINMEM		"min-memory"
#define SERVERPIDFILE	"pidfile"
#define PING		"ping"
#define PINGCOUNT	"ping-count"
#define PRIORITY	"priority"
#define REALTIME	"realtime"
#define REPAIRBIN	"repair-binary"
#define TEMP		"temperature-device"
#define TESTBIN		"test-binary"

pid_t pid;
int softboot = FALSE, watchdog = -1, load = -1, mem = -1, temp = -1, tint = 10, logtick = 1, ticker = 0, schedprio = 1;
char *tempname = NULL, *devname = NULL, *admin = "root", *progname;
int maxload1 = 0, maxload5 = 0, maxload15 = 0, minpages = 0;
int maxtemp = 120;
int pingcount = 3;

#if defined(_POSIX_MEMLOCK)
int mlocked = FALSE, realtime = FALSE;
#endif

static void usage(void)
{
    fprintf(stderr, "%s version %d.%d, usage:\n", progname, MAJOR_VERSION, MINOR_VERSION);
#if USE_SYSLOG
    fprintf(stderr, "%s [-i <interval> [-f]] [-l <max load avg>] [-v] [-s] [-b] [-m <max temperature>]\n", progname);
#else				/* USE_SYSLOG */
    fprintf(stderr, "%s [-i <interval> [-f]] [-l <max load avg>] [-v] [-b] [-m <max temperature>]\n", progname);
#endif				/* USE_SYSLOG */
    exit(1);
}

/* Try to sync */
static int sync_system(int sync_it)
{
    if (sync_it) {
	sync();
	sync();
    }
    return (0);
}

/* execute repair binary */
static int repair(char *rbinary, int result)
{
    pid_t child_pid;
    char parm[5];
    int ret;

    /* no binary given, we have to reboot */
    if (rbinary == NULL)
	return (result);

    sprintf(parm, "%d", result);

    child_pid = fork();
    if (!child_pid) {
	execl(rbinary, rbinary, parm, NULL);

	/* execl should only return in case of an error */
	/* so we return the reboot code */
	return (errno);
    } else if (child_pid < 0) {	/* fork failed */
	int err = errno;

	if (errno == EAGAIN) {	/* process table full */
#if USE_SYSLOG
	    syslog(LOG_ERR, "process table is full!");
#endif				/* USE_SYSLOG */
	    return (EREBOOT);
	} else if (softboot)
	    return (err);
	else
	    return (ENOERR);
    }
    if (waitpid(child_pid, &result, 0) != child_pid) {
	int err = errno;

#if USE_SYSLOG
	syslog(LOG_ERR, "child %d does not exist (errno = %d = '%m')", child_pid, err);
#else				/* USE_SYSLOG */
	perror(progname);
#endif				/* USE_SYSLOG */
	if (softboot)
	    return (err);
    }
    
    /* check result */
    ret = WEXITSTATUS(result);
    if (ret != 0) {
#if USE_SYSLOG
	syslog(LOG_ERR, "repair binary returned %d", ret);
#endif				/* USE_SYSLOG */

	if (ret == ERESET) /* repair script says force hard reset, we give it a try */
		sleep(TIMER_MARGIN * 4);
	
	/* for all other errors or if we still live, we let shutdown handle it */
	return (ret);
    }
    
    return (ENOERR);
}

static void wd_action(int result, char *rbinary)
{
    /* if no-action flag set, do nothing */
    /* no error, keep on working */
    if (result == ENOERR || no_act == TRUE)
	return;

    /* error that might be repairable */
    if (result != EREBOOT)
	result = repair(rbinary, result);

    /* if still error, reboot */
    if (result != ENOERR)
	do_shutdown(result);

}

static void do_check(int res, char *rbinary)
{
    wd_action(res, rbinary);
    wd_action(keep_alive(), rbinary);
}

struct list *file = NULL, *target = NULL, *pidfile = NULL, *iface = NULL;
char *tbinary, *rbinary, *admin;

static void add_list(struct list **list, char *name)
{
    struct list *new, *act;

    if ((new = (struct list *) calloc(1, sizeof(struct list))) == NULL) {
	fprintf(stderr, "%s: out of memory\n", progname);
	exit(1);
    }
    new->name = name;
    memset((char *) (&(new->parameter)), '\0', sizeof(union wdog_options));

    if (*list == NULL)
	*list = new;
    else {
	for (act = *list; act->next != NULL; act = act->next);
	act->next = new;
    }
}

static int spool(char *line, int *i, int offset)
{
    for ((*i) += offset; line[*i] == ' ' || line[*i] == '\t'; (*i)++);
    if (line[*i] == '=')
	(*i)++;
    for (; line[*i] == ' ' || line[*i] == '\t'; (*i)++);
    if (line[*i] == '\0')
    	return(1);
    else
    	return(0);
}

static void read_config(char *filename, char *progname)
{
    FILE *wc;
    int gotload5 = FALSE, gotload15 = FALSE;

    if ((wc = fopen(filename, "r")) == NULL) {
	perror(progname);
	exit(1);
    }

    while (!feof(wc)) {
	char line[CONFIG_LINE_LEN];

	if (fgets(line, CONFIG_LINE_LEN, wc) == NULL) {
	    if (!ferror(wc))
		break;
	    else {
		perror(progname);
		exit(1);
	    }
	} else {
	    int i, j;

	    /* scan the actual line for an option */
	    /* first remove the leading blanks */
	    for (i = 0; line[i] == ' ' || line[i] == '\t'; i++);

	    /* if the next sign is a '#' we have a comment */
	    if (line[i] == '#')
		continue;

	    /* also remove the trailing blanks and the \n */
	    for (j = strlen(line) - 1; line[j] == ' ' || line[j] == '\t' || line[j] == '\n'; j--);
	    line[j + 1] = '\0';

	    /* if the line is empty now, we don't have to parse it */
	    if (strlen(line + i) == 0)
		continue;

	    /* now check for an option */
	    if (strncmp(line + i, FILENAME, strlen(FILENAME)) == 0) {
		if (spool(line, &i, strlen(FILENAME)))
		    fprintf(stderr, "Ignoring invalid line in config file:\n%s\n", line);
		else
		    add_list(&file, strdup(line + i));
	    } else if (strncmp(line + i, CHANGE, strlen(CHANGE)) == 0) {
		struct list *ptr;

		if (spool(line, &i, strlen(CHANGE)))
		    continue;

		if (!file) {	/* no file entered yet */
		    fprintf(stderr, "Ignoring invalid line in config file:\n%s\n", line);
		    continue;
		}
		for (ptr = file; ptr->next != NULL; ptr = ptr->next);
		if (ptr->parameter.file.mtime != 0)
		    fprintf(stderr, "Duplicate change interval option in config file. Ignoring first entry.\n");

		file->parameter.file.mtime = atoi(line + i);
	    } else if (strncmp(line + i, SERVERPIDFILE, strlen(SERVERPIDFILE)) == 0) {
		if (spool(line, &i, strlen(SERVERPIDFILE)))
		    fprintf(stderr, "Ignoring invalid line in config file:\n%s\n", line);
		else
		    add_list(&pidfile, strdup(line + i));
	    } else if (strncmp(line + i, PING, strlen(PING)) == 0) {
		if (spool(line, &i, strlen(PING)))
		    fprintf(stderr, "Ignoring invalid line in config file:\n%s\n", line);
		else
		    add_list(&target, strdup(line + i));
	    } else if (strncmp(line + i, INTERFACE, strlen(INTERFACE)) == 0) {
		if (spool(line, &i, strlen(INTERFACE)))
		    fprintf(stderr, "Ignoring invalid line in config file:\n%s\n", line);
		else
		    add_list(&iface, strdup(line + i));
	    } else if (strncmp(line + i, REALTIME, strlen(REALTIME)) == 0) {
		(void)spool(line, &i, strlen(REALTIME));
		realtime = (strncmp(line + i, "yes", 3) == 0) ? TRUE : FALSE;
	    } else if (strncmp(line + i, PRIORITY, strlen(PRIORITY)) == 0) {
		if (spool(line, &i, strlen(PRIORITY)))
		    fprintf(stderr, "Ignoring invalid line in config file:\n%s\n", line);
		else
		    schedprio = atol(line + i);
	    } else if (strncmp(line + i, REPAIRBIN, strlen(REPAIRBIN)) == 0) {
		if (spool(line, &i, strlen(REPAIRBIN)))
			rbinary = NULL;
		else
			rbinary = strdup(line + i);
	    } else if (strncmp(line + i, TESTBIN, strlen(TESTBIN)) == 0) {
		if (spool(line, &i, strlen(TESTBIN)))
			tbinary = NULL;
		else
			tbinary = strdup(line + i);
	    } else if (strncmp(line + i, ADMIN, strlen(ADMIN)) == 0) {
		if (spool(line, &i, strlen(ADMIN)))
			admin = NULL;
		else
			admin = strdup(line + i);
	    } else if (strncmp(line + i, INTERVAL, strlen(INTERVAL)) == 0) {
		if (spool(line, &i, strlen(INTERVAL)))
		    fprintf(stderr, "Ignoring invalid line in config file:\n%s\n", line);
		else
		    tint = atol(line + i);
	    } else if (strncmp(line + i, LOGTICK, strlen(LOGTICK)) == 0) {
		if (spool(line, &i, strlen(LOGTICK)))
		    logtick = ticker = 1;
		else
		    logtick = ticker = atol(line + i);
	    } else if (strncmp(line + i, DEVICE, strlen(DEVICE)) == 0) {
		if (spool(line, &i, strlen(DEVICE)))
			devname = NULL;
		else
			devname = strdup(line + i);
	    } else if (strncmp(line + i, TEMP, strlen(TEMP)) == 0) {
		if (spool(line, &i, strlen(TEMP)))
			tempname = NULL;
		else
			tempname = strdup(line + i);
	    } else if (strncmp(line + i, MAXTEMP, strlen(MAXTEMP)) == 0) {
		if (spool(line, &i, strlen(MAXTEMP)))
			fprintf(stderr, "Ignoring invalid line in config file:\n%s\n", line);
		else
			maxtemp = atol(line + i);
	    } else if (strncmp(line + i, MAXLOAD15, strlen(MAXLOAD15)) == 0) {
		if (spool(line, &i, strlen(MAXLOAD15)))
			fprintf(stderr, "Ignoring invalid line in config file:\n%s\n", line);
		else {
			maxload15 = atol(line + i);
			gotload15 = TRUE;
		}
	    } else if (strncmp(line + i, MAXLOAD1, strlen(MAXLOAD1)) == 0) {
		if (spool(line, &i, strlen(MAXLOAD1)))
			fprintf(stderr, "Ignoring invalid line in config file:\n%s\n", line);
		else {
			maxload1 = atol(line + i);
			if (!gotload5)
			    maxload5 = maxload1 * 3 / 4;
			if (!gotload15)
			    maxload15 = maxload1 / 2;
		}
	    } else if (strncmp(line + i, MAXLOAD5, strlen(MAXLOAD5)) == 0) {
		if (spool(line, &i, strlen(MAXLOAD5)))
			fprintf(stderr, "Ignoring invalid line in config file:\n%s\n", line);
		else {
			maxload5 = atol(line + i);
			gotload5 = TRUE;
		}
	    } else if (strncmp(line + i, MINMEM, strlen(MINMEM)) == 0) {
		if (spool(line, &i, strlen(MINMEM)))
			fprintf(stderr, "Ignoring invalid line in config file:\n%s\n", line);
		else {
			minpages = atol(line + i);
		}
	    } else if (strncmp(line + i, PINGCOUNT, strlen(PINGCOUNT)) == 0) {
		if (spool(line, &i, strlen(PINGCOUNT)))
		    fprintf(stderr, "Ignoring invalid line in config file:\n%s\n", line);
		else
		    pingcount = atol(line + i);
	    } else {
		fprintf(stderr, "Ignoring invalid line in config file:\n%s\n", line);
	    }
	}
    }

    if (fclose(wc) != 0) {
	perror(progname);
	exit(1);
    }
}

static void old_option(int c, char *filename)
{
    fprintf(stderr, "Option -%c is no longer valid, please specify it in %s.\n", c, filename);
    usage();
}

int main(int argc, char *const argv[])
{
    FILE *fp;
    int c, force = FALSE, sync_it = FALSE;
    int hold;
    char *filename = CONFIG_FILENAME;
    struct list *act;
    pid_t child_pid;

#if USE_SYSLOG
    char log[256], *opts = "d:i:n:fsvbql:p:t:c:r:m:a:";
    struct option long_options[] =
    {
	{"config-file", required_argument, NULL, 'c'},
	{"force", no_argument, NULL, 'f'},
	{"sync", no_argument, NULL, 's'},
	{"no-action", no_argument, NULL, 'q'},
	{"verbose", no_argument, NULL, 'v'},
	{"softboot", no_argument, NULL, 'b'},
	{NULL, 0, NULL, 0}
    };
    long count = 0L;
#else				/* USE_SYSLOG */
    char *opts = "d:i:n:fsbql:p:t:c:r:m:a:";
    struct option long_options[] =
    {
	{"config-file", required_argument, NULL, 'c'},
	{"force", no_argument, NULL, 'f'},
	{"sync", no_argument, NULL, 's'},
	{"no-action", no_argument, NULL, 'q'},
	{"softboot", no_argument, NULL, 'b'},
	{NULL, 0, NULL, 0}
    };
#endif				/* USE_SYSLOG */

    progname = basename(argv[0]);

    /* check the options */
    /* there arn't that many any more */
    while ((c = getopt_long(argc, argv, opts, long_options, NULL)) != EOF) {
	if (c == -1)
	    break;

	switch (c) {
	case 'n':
	case 'p':
	case 'a':
	case 'r':
	case 'd':
	case 't':
	case 'l':
	case 'm':
	case 'i':
	    old_option(c, filename);
	    break;
	case 'c':
	    filename = optarg;
	    break;
	case 'f':
	    force = TRUE;
	    break;
	case 's':
	    sync_it = TRUE;
	    break;
	case 'b':
	    softboot = TRUE;
	    break;
	case 'q':
	    no_act = TRUE;
	    break;
#if USE_SYSLOG
	case 'v':
	    verbose = TRUE;
	    break;
#endif				/* USE_SYSLOG */
	default:
	    usage();
	}
    }

    read_config(filename, progname);

    if (tint < 0)
	usage();

    if (tint >= TIMER_MARGIN && !force) {
	fprintf(stderr, "%s error:\n", progname);
	fprintf(stderr, "This interval length might reboot the system while the process sleeps!\n");
	fprintf(stderr, "To force this interval length use the -f option.\n");
	exit(1);
    }
    
    if (maxload1 > 0 && maxload1 < MINLOAD && !force) {
	fprintf(stderr, "%s error:\n", progname);
	fprintf(stderr, "Using this maximal load average might reboot the system to often!\n");
	fprintf(stderr, "To force this load average use the -f option.\n");
	exit(1);
    }
    
    /* set up pinging if in ping mode */
    if (target != NULL) {
	for (act = target; act != NULL; act = act->next) {
	    struct protoent *proto;
	    struct pingmode *net = (struct pingmode *) calloc(1, sizeof(struct pingmode));

	    if (net == NULL) {
		fprintf(stderr, "%s: out of memory\n", progname);
		exit(1);
	    }
	    /* setup the socket */
	    memset(&(net->to), 0, sizeof(struct sockaddr));

	    ((struct sockaddr_in *) &(net->to))->sin_family = AF_INET;
	    if ((((struct sockaddr_in *) &(net->to))->sin_addr.s_addr = inet_addr(act->name)) == (unsigned int) -1) {
		(void) fprintf(stderr, "%s: unknown host %s\n", progname, act->name);
		exit(1);
	    }
	    if (!(net->packet = (unsigned char *) malloc((unsigned int) (DATALEN + MAXIPLEN + MAXICMPLEN)))) {
		fprintf(stderr, "%s: out of memory\n", progname);
		exit(1);
	    }
	    if (!(proto = getprotobyname("icmp"))) {
		(void) fprintf(stderr, "%s: unknown protocol icmp.\n", progname);
		exit(1);
	    }
	    if ((net->sock_fp = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) {
		perror(progname);
		exit(1);
	    }
	    
	    /* this is necessary for broadcast pings to work */
	    (void) setsockopt(net->sock_fp, SOL_SOCKET, SO_BROADCAST, (char *)&hold, sizeof(hold));
    
	    hold = 48 * 1024;
	    (void) setsockopt(net->sock_fp, SOL_SOCKET, SO_RCVBUF, (char *) &hold,
			      sizeof(hold));

	    act->parameter.net = *net;
	}
    }
    /* make sure we're on the root partition */
    if (chdir("/") < 0) {
	perror(progname);
	exit(1);
    }
#if !defined(DEBUG)
    /* fork to go into the background */
    if ((child_pid = fork()) < 0) {
	perror(progname);
	exit(1);
    } else if (child_pid > 0) {
	/* fork was okay          */
	/* wait for child to exit */
	if (waitpid(child_pid, NULL, 0) != child_pid) {
	    perror(progname);
	    exit(1);
	}
	/* and exit myself */
	exit(0);
    }
    /* and fork again to make sure we inherit all rights from init */
    if ((child_pid = fork()) < 0) {
	perror(progname);
	exit(1);
    } else if (child_pid > 0)
	exit(0);
#endif				/* !DEBUG */

    /* now we're free */
#if USE_SYSLOG
#if !defined(DEBUG)
    /* Okay, we're a daemon     */
    /* but we're still attached to the tty */
    /* create our own session */
    setsid();

    /* with USE_SYSLOG we don't do any console IO */
    close(0);
    close(1);
    close(2);
#endif				/* !DEBUG */

    /* Log the starting message */
    openlog(progname, LOG_PID, LOG_DAEMON);
    sprintf(log, "starting daemon (%d.%d):", MAJOR_VERSION, MINOR_VERSION);
    
    sprintf(log + strlen(log), " int=%ds realtime=%s sync=%s soft=%s mla=%d mem=%ld ping=",
	    tint,
	    realtime ? "yes" : "no",
	    sync_it ? "yes" : "no",
	    softboot ? "yes" : "no",
	    maxload1, minpages);
	    
    if (target == NULL)
            sprintf(log + strlen(log), "none ");
    else
            for (act = target; act != NULL; act = act->next)
            	sprintf(log + strlen(log), "%s%c", act->name, (act->next != NULL) ? ',' : ' ');
	                                        
    sprintf(log + strlen(log), "file=");
    if (file == NULL)
            sprintf(log + strlen(log), "none ");
    else
            for (act = file; act != NULL; act = act->next)
                sprintf(log + strlen(log), "%s:%d%c", act->name, act->parameter.file.mtime, (act->next != NULL) ? ',' : ' ');

    sprintf(log + strlen(log), "pidfile=");
    if (pidfile == NULL)
            sprintf(log + strlen(log), "none ");
    else
            for (act = pidfile; act != NULL; act = act->next)
                sprintf(log + strlen(log), "%s%c", act->name, (act->next != NULL) ? ',' : ' ');                

    sprintf(log + strlen(log), "iface=");
    if (iface == NULL)
            sprintf(log + strlen(log), "none ");
    else
            for (act = iface; act != NULL; act = act->next)
                sprintf(log + strlen(log), "%s%c", act->name, (act->next != NULL) ? ',' : ' ');                

    sprintf(log + strlen(log), "test=%s repair=%s alive=%s temp=%s to=%s no_act=%s",
	    (tbinary == NULL) ? "none" : tbinary,
	    (rbinary == NULL) ? "none" : rbinary,
	    (devname == NULL) ? "none" : devname,
	    (tempname == NULL) ? "none" : tempname,
	    (admin == NULL) ? "noone" : admin,
	    (no_act == TRUE) ? "yes" : "no");
    syslog(LOG_INFO, log);
#endif				/* USE_SYSLOG */


    /* open the device */
    if (devname != NULL && no_act == FALSE) {
	watchdog = open(devname, O_WRONLY);
	if (watchdog == -1) {
#if USE_SYSLOG
	    syslog(LOG_ERR, "cannot open %s (errno = %d = '%m')", devname, errno);
#else				/* USE_SYSLOG */
	    perror(progname);
#endif				/* USE_SYSLOG */
	    /* do not exit here per default */
	    /* we can use watchdog even if there is no watchdog device */
	}
    }

    if (maxload1 > 0) {
	/* open the load average file */
	load = open("/proc/loadavg", O_RDONLY);
	if (load == -1) {
#if USE_SYSLOG
		syslog(LOG_ERR, "cannot open /proc/loadavg (errno = %d = '%m')", errno);
#else				/* USE_SYSLOG */
		perror(progname);
#endif				/* USE_SYSLOG */
	}
    }

    if (minpages > 0) {
	/* open the memory info file */
	mem = open("/proc/meminfo", O_RDONLY);
	if (mem == -1) {
#if USE_SYSLOG
		syslog(LOG_ERR, "cannot open /proc/meminfo (errno = %d = '%m')", errno);
#else				/* USE_SYSLOG */
		perror(progname);
#endif				/* USE_SYSLOG */
	}
    }
    
    if (tempname != NULL && no_act == FALSE) {
	/* open the temperature file */
	temp = open(tempname, O_RDONLY);
	if (temp == -1) {
#if USE_SYSLOG
	    syslog(LOG_ERR, "cannot open %s (errno = %d = '%m')", tempname, errno);
#else				/* USE_SYSLOG */
	    perror(progname);
#endif				/* USE_SYSLOG */
	}
    }
    /* tuck my process id away */
    fp = fopen(PIDFILE, "w");
    if (fp != NULL) {
	fprintf(fp, "%d\n", pid = getpid());
	(void) fclose(fp);
    }
    /* set signal term to call terminate() */
    /* to make sure watchdog device is closed */
    signal(SIGTERM, terminate);

#if defined(_POSIX_MEMLOCK)
    if (realtime == TRUE) {
	    /* lock all actual and future pages into memory */
	    if (mlockall(MCL_CURRENT | MCL_FUTURE) != 0) {
#if USE_SYSLOG
		syslog(LOG_ERR, "cannot lock realtime memory (errno = %d = '%m')", errno);
#else				/* USE_SYSLOG */
		perror(progname);
#endif
	    } else {
		struct sched_param sp;

		/* now set the scheduler */
		sp.sched_priority = schedprio;
		    if (sched_setscheduler(0, SCHED_RR, &sp) != 0) {
#if USE_SYSLOG
		    syslog(LOG_ERR, "cannot set scheduler (errno = %d = '%m')", errno);
#else				/* USE_SYSLOG */
		    perror(progname);
#endif
		} else
		    mlocked = TRUE;
	    }
    }
#endif

    /* main loop: update after <tint> seconds */
    while (1) {
	wd_action(keep_alive(), rbinary);

	/* sync system if we have to */
	do_check(sync_system(sync_it), rbinary);

	/* check file table */
	do_check(check_file_table(), rbinary);

	/* check load average */
	do_check(check_load(), rbinary);
	
	/* check free memory */
	do_check(check_memory(), rbinary);

	/* check temperature */
	do_check(check_temp(), rbinary);

	/* in filemode stat file */
	for (act = file; act != NULL; act = act->next)
	    do_check(check_file_stat(act), rbinary);
	    
	/* in pidmode kill -0 processes */
	for (act = pidfile; act != NULL; act = act->next)
	    do_check(check_pidfile(act), rbinary);

	/* in network mode check the given devices for input */
	for (act = iface; act != NULL; act = act->next)
	    do_check(check_iface(act), rbinary);
	    
	/* in ping mode ping the ip address */
	for (act = target; act != NULL; act = act->next)
	    do_check(check_net(act->name, act->parameter.net.sock_fp, act->parameter.net.to, act->parameter.net.packet, tint , pingcount), rbinary);

	/* in user mode execute the given binary or just test fork() call */
	do_check(check_bin(tbinary), rbinary);

	/* finally sleep some seconds */
	sleep(tint);

	if(logtick && (--ticker == 0)) {
	  ticker = logtick;
	  
#if USE_SYSLOG
	/* do verbose logging */
	if (verbose) {
	    count += logtick;
		ticker = 0;
	    syslog(LOG_INFO, "still alive after %ld seconds = %ld interval(s)", count * tint, count);
	}
#endif				/* USE_SYSLOG */
	}
    }
}
