/*
    util.c - Copyright (C) 2002 Murray Nesbitt (websrc@nesbitt.ca)

    This program is protected and licensed under the following terms and
    conditions: 1) it may not be redistributed in binary form without the
    explicit permission of the author; 2) when redistributed in source
    form, in whole or in part, this complete copyright statement must
    remain intact.
*/

#include "flasher.h"

static int console;  /* console file descriptor */
extern char *progname;

/* Set the LED state, on or off. */
int LEDstate(int led, int state)
{
    ioctl_arg_type LEDs;
    int rc = 0;

    if (ioctl(console, GET_LED_STATE, &LEDs) < 0) {
        syslog(LOG_ERR, "ioctl() get failed: %m");
        rc = -1;
    }
    else {
        LEDs = (state ? LEDs|led : (LEDs & ~led)) & LED_MASK;
#if defined(__sun)
        /* Solaris requires a pointer to the LED arg. */
        if (ioctl(console, SET_LED_STATE, &LEDs) < 0) {
#else
        if (ioctl(console, SET_LED_STATE, LEDs) < 0) {
#endif
            syslog(LOG_ERR, "ioctl() set failed: %m");
            rc = -1;
        }
    }
    return rc;
}

/* Build an absolute path to file, if necessary. */
char *absolute_path(char *file)
{
    static char *cwd;
    char *path;

    if (!cwd)
        cwd = getcwd(NULL, CWD_SIZE);

    if (file[0] != '/') {
        if ((path = malloc(strlen(cwd) + strlen(file) + 2)) == NULL) {
            perror("malloc");
            exit(EXIT_FAILURE);
        }
        sprintf(path, "%s/%s", cwd, file);
        fprintf(stderr, "%s: warning: converting '%s' to " \
            "absolute pathname '%s'.\n", progname, file, path);
        file = path;
    }
    return file;
}

void open_console(char *terminal) {

    if (!terminal)
        terminal = CONSOLE_DEVICE;

    if ((console = open(terminal, O_RDONLY|O_NOCTTY)) < 0) {
        perror(terminal);
        exit(EXIT_FAILURE);
    }
}

int console_opened(void)
{
    return console;
}

/* Set the program up to run as a daemon. */
void daemonize(void)
{
    pid_t pid;
    int i;
    FILE *f;

    if ((pid = fork()) == 0) {
        /* Since we are running as a daemon, change the current working
           directory to the root.  Otherwise, we might at some point
           prevent a mounted filesystem from being unmounted. */
        chdir("/");

        /* Start a new session. */
        setsid();

        /* Close all open descriptors, except the console. */
        for (i = 0; i < console; i++)
            close(i);

        /* There's now no controlling terminal, so any output must go
           to syslog. */
        openlog(progname, LOG_PID, LOG_USER);
        syslog(LOG_INFO, "daemon started");
    }
    else if (pid == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    }
    else {
        close(console);
        fprintf(stderr, "%s daemon started, PID %d.\n", progname, (int)pid);

        /* Write the pid to the lock file. */
        if ((f = fopen(LOCK_FILE, "w")) == NULL) {
            fprintf(stderr, "%s: warning: could not open '%s' for writing\n",
            progname, LOCK_FILE);
        }
        else {
            fprintf(f, "%d\n", (int)pid);
            fclose(f);
        }
        exit(EXIT_SUCCESS);
    }
}

/* Make sure our lock file gets removed on exit, and set
   the LEDs to match the current keyboard state. */
static void cleanup(int sig) {
#if defined(GET_KB_STATE)
    ioctl_arg_type LEDs;

    if (ioctl(console, GET_KB_STATE, &LEDs) != -1) {
        LEDstate(LED_CAP, LEDs & LED_CAP ? LED_ON : LED_OFF);
        LEDstate(LED_NUM, LEDs & LED_NUM ? LED_ON : LED_OFF);
        LEDstate(LED_SCR, LEDs & LED_SCR ? LED_ON : LED_OFF);
    }
#endif
    closelog();
    unlink(LOCK_FILE);
    exit(EXIT_FAILURE);
}

void set_sig_handlers(void)
{
    sigset_t mask;
    struct sigaction sa;

    sigemptyset(&mask);
    sigaddset(&mask, SIGHUP);
    sigaddset(&mask, SIGINT);
    sigaddset(&mask, SIGTERM);
    sa.sa_mask = mask;
    sa.sa_flags = 0;
    SIGNAL(SIGHUP, cleanup);
    SIGNAL(SIGINT, cleanup);
    SIGNAL(SIGTERM, cleanup);
}

/* Make sure another instance isn't already running. */
void check_lock(void)
{
    FILE *f;
    pid_t pid;

    if ((f = fopen(LOCK_FILE, "r")) == NULL) {
        return;
    }

    fscanf(f, "%d\n", (int *)&pid);
    fclose(f);
    
    if ((kill(pid, 0) == -1) && (errno == ESRCH)) {
        /* Was running, but appears to be gone now. */
        unlink(LOCK_FILE);
    }
    else {
        fprintf(stderr, "%s appears to be running (PID: %d). " \
        "If this is not the case, delete '%s' and try again.\n",
            progname, (int)pid, LOCK_FILE);
        exit(EXIT_FAILURE);
    }
}




syntax highlighted by Code2HTML, v. 0.9.1