/*************************************************************/
/* Small utility to identify hardware watchdog               */
/* 							     */
/* Idea and most of the implementation by		     */
/* Corey Minyard <minyard@acm.org>			     */
/*                                                           */
/* The rest was written by me, Michael Meskes                */
/* meskes@debian.org                                         */
/*                                                           */
/*************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <errno.h>
#include <stdio.h>
#include <linux/watchdog.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <libgen.h>
#include <getopt.h>
#include <unistd.h>
#include <sys/ioctl.h>

#define DEVICE		"watchdog-device"

int watchdog = -1;
char *devname = NULL, *progname = NULL;

static void usage(void)
{
    fprintf(stderr, "%s version %d.%d, usage:\n", progname, MAJOR_VERSION, MINOR_VERSION);
    fprintf(stderr, "%s \n", progname);
    exit(1);
}

void terminate(void)
{
	if (watchdog != -1) {
	    if (write(watchdog, "V", 1) < 0 )
		perror(progname);

	    if (close(watchdog) == -1)
		perror(progname);
	}

	exit(0);
}

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 *configfile, char *progname)
{
    FILE *wc;

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

    while ( !feof(wc) ) {
	char *line = NULL;
	size_t n;

	if (getline(&line, &n, wc) == -1) {
            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, DEVICE, strlen(DEVICE)) == 0 ) {
                if ( spool(line, &i, strlen(DEVICE)) )
                    devname = NULL;
                else
                    devname = strdup(line + i);
	    } 
            else {
                /*
		 * do not print an error message here because we usually use
		 * watchdog's config file which may contain far more valid
		 * options than we understand 
		 */
		/* fprintf(stderr, "Ignoring config line: %s\n", line); */
            }
        }
    }

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


int main(int argc, char *const argv[])
{
    char *configfile = CONFIG_FILENAME;
    int c;
    struct watchdog_info ident;
    char *opts = "c:";
    struct option long_options[] =
    {
	{"config-file", required_argument, NULL, 'c'},
	{NULL, 0, NULL, 0}
    };

    progname = basename(argv[0]);

    /* check for the one option we understand */
    while ((c = getopt_long(argc, argv, opts, long_options, NULL)) != EOF) {
	if (c == -1)
	    break;
	switch (c) {
	case 'c':
	    configfile = optarg;
	    break;
	default:
	    usage();
	}
    }

    read_config(configfile, progname);

    /* this program has no other function than iidentifying the hardware behind
     * this device i.e. if there is no device given we better punt */
    if ( devname == NULL )
	exit(0);

    /* open the device */
    watchdog = open(devname, O_WRONLY);
    if ( watchdog == -1 ) {
            perror(progname);
            exit(1);
    }

    /* Print watchdog identity */
    if (ioctl(watchdog, WDIOC_GETSUPPORT, &ident) < 0) {
	perror(progname);
    }
    else {
	ident.identity[sizeof(ident.identity) - 1] = '\0'; /* Be sure */
	printf("%s\n", ident.identity);
    }

    if (write(watchdog, "V", 1) < 0 )
	perror(progname);

    if (close(watchdog) == -1)
	perror(progname);

    exit(0);
}


