aboutsummaryrefslogtreecommitdiffstats
path: root/plugin_ppp.c (unfollow)
a id='n166' href='#n166'>166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
AgeCommit message (Expand)AuthorFilesLines
2010-02-14indent.sh runmichael1-172/+171
2010-02-14plugin_huawei-fix-interval-check_V2.patch from Jarmichael1-35/+35
2010-02-12Improved config behavior.mjona1-9/+32
2010-02-12Fixed a segmentation fault bug in cfg_get().mjona1-1/+1
2010-02-11All static memory allocations were turned into dynamical ones.mjona1-128/+200
2010-02-07timer.c: two small optimizations (removed "flag"; tv_usec can't be negative)mzuther1-7/+4
2010-02-07added grouping of widgets by update interval (new file "timer_group.c")mzuther13-168/+441
2010-02-07BUG: handle negative delays in timer_process() (timer.c)mzuther1-0/+4
2010-02-06timer.c: I had forgotten how to initialize a "struct" :)mzuther1-3/+4
2010-02-06BUG: compensate timers for processing delay ("timer.c")mzuther1-1/+3
2010-02-06timer.c: exchanged "proprietary code" with timeradd() and timersub() functionsmzuther1-14/+10
2010-02-04timer.c: removed fruitless changes to variable "flag" from timer_process()mzuther1-2/+0
2010-02-04According to its man page, timercmp() is broken on some systems -- applied th...mzuther1-1/+1
2010-02-04small warning removedmichael1-1/+1
2010-02-04clear errno after creating the FIFO by Claas Hilbrechtmichael1-0/+2
/* $Id$
 * $URL$
 * $URL$
 *
 * LCD4Linux
 *
 * Copyright (C) 1999, 2000, 2001, 2002, 2003 Michael Reinelt <reinelt@eunet.at>
 * Copyright (C) 2004, 2005, 2006, 2007 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
 *
 * This file is part of LCD4Linux.
 *
 * LCD4Linux is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * LCD4Linux is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include "config.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <time.h>

#include "svn_version.h"
#include "cfg.h"
#include "debug.h"
#include "qprintf.h"
#include "pid.h"
#include "udelay.h"
#include "drv.h"
#include "timer.h"
#include "layout.h"
#include "plugin.h"
#include "thread.h"

#include "widget.h"
#include "widget_timer.h"

#ifdef WITH_DMALLOC
#include <dmalloc.h>
#endif

#define PIDFILE "/var/run/lcd4linux.pid"

static char *release = "LCD4Linux " VERSION "-" SVN_VERSION;
static char *copyright = "Copyright (C) 2005, 2006, 2007 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>";
static char **my_argv;
extern char *output;

int got_signal = 0;


static void usage(void)
{
    printf("%s\n", release);
    printf("%s\n", copyright);
    printf("usage: lcd4linux [-h]\n");
    printf("       lcd4linux [-l]\n");
    printf("       lcd4linux [-c key=value] [-i] [-f config-file] [-v] [-p pid-file]\n");
    printf("       lcd4linux [-c key=value] [-F] [-f config-file] [-o output-file] [-q] [-v]\n");
}

static void interactive_mode(void)
{
    char line[1024];
    void *tree;
    RESULT result = { 0, 0, 0, NULL };

    printf("\neval> ");
    for (fgets(line, 1024, stdin); !feof(stdin); fgets(line, 1024, stdin)) {
	if (line[strlen(line) - 1] == '\n')
	    line[strlen(line) - 1] = '\0';
	if (strlen(line) > 0) {
	    if (Compile(line, &tree) != -1) {
		Eval(tree, &result);
		if (result.type == R_NUMBER) {
		    printf("%g\n", R2N(&result));
		} else if (result.type == R_STRING) {
		    printf("'%s'\n", R2S(&result));
		} else if (result.type == (R_NUMBER | R_STRING)) {
		    printf("'%s' (%g)\n", R2S(&result), R2N(&result));
		} else {
		    printf("internal error: unknown result type %d\n", result.type);
		}
		DelResult(&result);
	    }
	    DelTree(tree);
	}
	printf("eval> ");
    }
    printf("\n");
}


void handler(int signal)
{
    debug("got signal %d", signal);
    got_signal = signal;
}


static void daemonize(void)
{

    /* thanks to Petri Damsten, we now follow the guidelines from the UNIX Programming FAQ */
    /* 1.7 How do I get my program to act like a daemon? */
    /* http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 */
    /* especially the double-fork solved the 'lcd4linux dying when called from init' problem */

    pid_t i;
    int fd;


    /* Step 1: fork() so that the parent can exit */
    i = fork();
    if (i < 0) {
	error("fork(#1) failed: %s", strerror(errno));
	exit(1);
    }
    if (i != 0)
	exit(0);

    /* Step 2: setsid() to become a process group and session group leader */
    setsid();

    /* Step 3: fork() again so the parent (the session group leader) can exit */
    i = fork();
    if (i < 0) {
	error("fork(#2) failed: %s", strerror(errno));
	exit(1);
    }
    if (i != 0)
	exit(0);

    /* Step 4: chdir("/") to ensure that our process doesn't keep any directory in use */
    if (chdir("/") != 0) {
	error("chdir(\"/\") failed: %s", strerror(errno));
	exit(1);
    }

    /* Step 5: umask(0) so that we have complete control over the permissions of anything we write */
    umask(0);

    /* Step 6: Establish new open descriptors for stdin, stdout and stderr */
    /* detach stdin */
    if (freopen("/dev/null", "r", stdin) == NULL) {
	error("freopen (/dev/null) failed: %s", strerror(errno));
	exit(1);
    }

    /* detach stdout and stderr */
    fd = open("/dev/null", O_WRONLY, 0666);
    if (fd == -1) {
	error("open (/dev/null) failed: %s", strerror(errno));
	exit(1);
    }
    fflush(stdout);
    dup2(fd, STDOUT_FILENO);
    fflush(stderr);
    dup2(fd, STDERR_FILENO);
    close(fd);

}


int main(int argc, char *argv[])
{
    char *cfg = "/etc/lcd4linux.conf";
    char *pidfile = PIDFILE;
    char *display, *driver, *layout;
    char section[32];
    int c;
    int quiet = 0;
    int interactive = 0;
    int pid;

    /* save arguments for restart */
    my_argv = malloc(sizeof(char *) * (argc + 1));
    for (c = 0; c < argc; c++) {
	my_argv[c] = strdup(argv[c]);
    }
    my_argv[c] = NULL;

    /* save original arguments pointer for threads */
    thread_argv = argv;
    thread_argc = argc;

    running_foreground = 0;
    running_background = 0;

    while ((c = getopt(argc, argv, "c:Ff:hilo:qvp:")) != EOF) {

	switch (c) {
	case 'c':
	    if (cfg_cmd(optarg) < 0) {
		fprintf(stderr, "%s: illegal argument -c '%s'\n", argv[0], optarg);
		exit(2);
	    }
	    break;
	case 'F':
	    running_foreground++;
	    break;
	case 'f':
	    cfg = optarg;
	    break;
	case 'h':
	    usage();
	    exit(0);
	case 'i':
	    interactive++;
	    break;
	case 'l':
	    printf("%s\n", release);
	    printf("%s\n", copyright);
	    drv_list();
	    exit(0);
	case 'o':
	    output = optarg;
	    break;
	case 'q':
	    quiet++;
	    break;
	case 'v':
	    verbose_level++;
	    break;
	case 'p':
	    pidfile = optarg;
	    break;
	default:
	    exit(2);
	}
    }

    if (optind < argc) {
	fprintf(stderr, "%s: illegal option %s\n", argv[0], argv[optind]);
	exit(2);
    }

    /* do not fork in interactive mode */
    if (interactive) {
	running_foreground = 1;
    }

    info("Version " VERSION "-" SVN_VERSION " starting");
    if (!running_foreground && (my_argv[0] == NULL || my_argv[0][0] != '/')) {
	info("invoked without full path; restart may not work!");
    }

    if (cfg_init(cfg) == -1)
	exit(1);

    if (plugin_init() == -1)
	exit(1);

    display = cfg_get(NULL, "Display", NULL);
    if (display == NULL || *display == '\0') {
	error("missing 'Display' entry in %s!", cfg_source());
	exit(1);
    }

    qprintf(section, sizeof(section), "Display:%s", display);
    free(display);
    driver = cfg_get(section, "Driver", NULL);
    if (driver == NULL || *driver == '\0') {
	error("missing '%s.Driver' entry in %s!", section, cfg_source());
	exit(1);
    }

    if (!running_foreground) {

	debug("going background...");

	daemonize();

	/* ignore nasty signals */
	signal(SIGINT, SIG_IGN);
	signal(SIGQUIT, SIG_IGN);

	/* create PID file */
	if ((pid = pid_init(pidfile)) != 0) {
	    error("lcd4linux already running as process %d", pid);
	    exit(1);
	}

	/* now we are a daemon */
	running_background = 1;
    }

    /* go into interactive mode before display initialization */
    if (interactive >= 2) {
	interactive_mode();
	pid_exit(pidfile);
	cfg_exit();
	exit(0);
    }

    /* check the conf to see if quiet startup is wanted  */
    if (!quiet) {
	cfg_number(NULL, "Quiet", 0, 0, 1, &quiet);
    }

    debug("initializing driver %s", driver);
    if (drv_init(section, driver, quiet) == -1) {
	pid_exit(pidfile);
	exit(1);
    }
    free(driver);

    /* register timer widget */
    widget_timer_register();

    /* go into interactive mode (display has been initialized) */
    if (interactive >= 1) {
	interactive_mode();
	drv_quit(quiet);
	pid_exit(pidfile);
	cfg_exit();
	exit(0);
    }

    /* check for new-style layout */
    layout = cfg_get(NULL, "Layout", NULL);
    if (layout == NULL || *layout == '\0') {
	error("missing 'Layout' entry in %s!", cfg_source());
	exit(1);
    }

    layout_init(layout);
    free(layout);

    debug("starting main loop");


    /* now install our own signal handler */
    signal(SIGHUP, handler);
    signal(SIGINT, handler);
    signal(SIGQUIT, handler);
    signal(SIGTERM, handler);

    while (got_signal == 0) {
	struct timespec delay;
	if (timer_process(&delay) < 0)
	    break;
	nanosleep(&delay, NULL);
    }

    debug("leaving main loop");

    drv_quit(quiet);
    pid_exit(pidfile);
    cfg_exit();
    plugin_exit();
    timer_exit();

    if (got_signal == SIGHUP) {
	long fd;
	debug("restarting...");
	/* close all files on exec */
	for (fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--) {
	    int flag;
	    if ((flag = fcntl(fd, F_GETFD, 0)) != -1)
		fcntl(fd, F_SETFD, flag | FD_CLOEXEC);
	}
	execv(my_argv[0], my_argv);
	error("execv() failed: %s", strerror(errno));
	exit(1);
    }

    for (c = 0; my_argv[c] != NULL; c++) {
	free(my_argv[c]);
    }
    free(my_argv);

    exit(0);
}