summaryrefslogtreecommitdiffstats
path: root/src/ifplugd.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2003-07-31 13:00:31 +0000
committerLennart Poettering <lennart@poettering.net>2003-07-31 13:00:31 +0000
commit86add5ad710adde499af6d08fe5479098dadaf29 (patch)
treec0358f501a174b66363c183f0b87540f5509b715 /src/ifplugd.c
parentd2fd8fc1f819883d092b715b31d393295a9bc4e2 (diff)
moved to trunk
git-svn-id: file:///home/lennart/svn/public/ifplugd/trunk@26 2bf48fe7-cfc1-0310-909f-d9042e1e0fef
Diffstat (limited to 'src/ifplugd.c')
-rw-r--r--src/ifplugd.c792
1 files changed, 792 insertions, 0 deletions
diff --git a/src/ifplugd.c b/src/ifplugd.c
new file mode 100644
index 0000000..9445383
--- /dev/null
+++ b/src/ifplugd.c
@@ -0,0 +1,792 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* $Id: ifplugd.c 1.12 Sat, 01 Feb 2003 03:00:07 +0100 lennart $ */
+
+/*
+ * This file is part of ifplugd.
+ *
+ * ifplugd 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 of the License, or
+ * (at your option) any later version.
+ *
+ * ifplugd 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 ifplugd; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <linux/kd.h>
+#include <sys/ioctl.h>
+#include <limits.h>
+#include <net/if.h>
+#include <linux/sockios.h>
+#include <sys/types.h>
+#include <ctype.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include <libdaemon/dlog.h>
+#include <libdaemon/dpid.h>
+#include <libdaemon/dsignal.h>
+#include <libdaemon/dfork.h>
+
+#include "ethtool-local.h"
+#include "interface.h"
+#include "svn-revision.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define VARRUN "/var/run"
+#define IFPLUGD_ENV_PREVIOUS "IFPLUGD_PREVIOUS"
+#define IFPLUGD_ENV_CURRENT "IFPLUGD_CURRENT"
+
+int interface_auto_up = 1, interface_do_message = 1;
+
+char *interface = "eth0";
+char *run = SYSCONFDIR"/ifplugd/ifplugd.action";
+char *extra_arg = NULL;
+int polltime = 1, delay_up = 0, delay_down = 5;
+int daemonize = 1, use_beep = 1, no_shutdown_script = 0, wait_on_fork = 0, use_syslog = 1, ignore_retval = 0, initial_down = 0;
+interface_status_t failure_status = IFSTATUS_ERR;
+
+enum { API_AUTO, API_ETHTOOL, API_MII, API_PRIVATE, API_WLAN } api_mode = API_AUTO;
+interface_status_t (*detect_beat_func)(int, char*);
+
+// 0: high, 1: low, 2: very low
+void beep(int b) {
+ int fd = -1, argp;
+
+ if (!use_beep)
+ return;
+
+ if ((fd = open("/dev/tty1", O_WRONLY)) < 0) {
+ use_beep = 0;
+ daemon_log(LOG_WARNING, "Could not open /dev/tty, cannot beep.");
+ goto finish;
+ }
+
+ switch (b) {
+ case 0: argp = (100<<16) + 0x637; break;
+ case 1: argp = (100<<16) + 0x937; break;
+ default: argp = (100<<16) + 0x1237; break;
+ }
+
+ if (ioctl(fd, KDMKTONE, argp) != 0) {
+ use_beep = 0;
+ daemon_log(LOG_WARNING, "Beep failure, disabled.");
+ goto finish;
+ }
+
+ usleep((argp >> 16)*1000);
+
+finish:
+
+ if (fd >= 0)
+ close(fd);
+
+ return;
+}
+
+const char *pid_file_proc() {
+ static char fn[PATH_MAX];
+ snprintf(fn, sizeof(fn), "%s/ifplugd.%s.pid", VARRUN, interface);
+ return fn;
+}
+
+int action(interface_status_t status) {
+ pid_t pid;
+ int _pipe[2];
+ unsigned n = 0;
+ static char buf[256];
+ char *arg = (status == IFSTATUS_UP ? "up" : "down");
+ int sigfd, r;
+ fd_set rfds;
+
+ daemon_log(LOG_INFO, "Executing '%s %s %s'.", run, interface, arg);
+
+ if (pipe(_pipe) < 0) {
+ daemon_log(LOG_ERR, "pipe() failed: %s", strerror(errno));
+ return -1;
+ }
+
+ if ((pid = fork()) < 0) {
+ daemon_log(LOG_ERR, "fork() failed: %s", strerror(errno));
+ return -1;
+
+ } else if (pid == 0) {
+ dup2(_pipe[1], 1);
+ dup2(_pipe[1], 2);
+
+ if (_pipe[0] > 2)
+ close(_pipe[0]);
+
+ if (_pipe[1] > 2)
+ close(_pipe[1]);
+
+ umask(0022); // Set up a sane umask
+
+ execl(run, run, interface, arg, extra_arg, 0);
+
+ _exit(EXIT_FAILURE);
+ }
+
+ close(_pipe[1]);
+
+ FD_ZERO(&rfds);
+ FD_SET(_pipe[0], &rfds);
+ FD_SET(sigfd = daemon_signal_fd(), &rfds);
+
+ n = 0;
+
+ for (;;) {
+ fd_set wrfds = rfds;
+
+ if (select(FD_SETSIZE, &wrfds, NULL, NULL, NULL) < 0) {
+
+ if (errno == EINTR)
+ continue;
+
+ break;
+ }
+
+
+ if (FD_ISSET(_pipe[0], &wrfds)) {
+ char c;
+
+ if (read(_pipe[0], &c, 1) != 1)
+ break;
+
+ buf[n] = c;
+
+ if (c == '\n' || n >= sizeof(buf) - 2) {
+ if (c != '\n') n++;
+ buf[n] = 0;
+
+ if (buf[0])
+ daemon_log(LOG_WARNING, "client: %s", buf);
+
+ n = 0;
+ } else
+ n++;
+ }
+
+ if (FD_ISSET(sigfd, &wrfds)) {
+ int sig;
+
+ if ((sig = daemon_signal_next()) < 0) {
+ daemon_log(LOG_ERR, "daemon_signal_next(): %s", strerror(errno));
+ break;
+ }
+
+ if (sig != SIGCHLD) {
+ daemon_log(LOG_WARNING, "Killing child.");
+ kill(pid, SIGTERM);
+ }
+
+ break;
+ }
+
+ }
+
+ if (n > 0) {
+ buf[n] = 0;
+ daemon_log(LOG_WARNING, "client: %s", buf);
+ }
+
+ waitpid(pid, &r, 0);
+
+ close(_pipe[0]);
+
+ if (!WIFEXITED(r) || WEXITSTATUS(r) != 0) {
+ if (status == IFSTATUS_UP)
+ beep(2);
+ daemon_log(LOG_ERR, "Program execution failed, return value is %i.", WEXITSTATUS(r));
+
+ return ignore_retval ? 0 : -1;
+ } else {
+ if (status == IFSTATUS_UP)
+ beep(0);
+
+ daemon_log(LOG_INFO, "Program executed successfully.");
+ return 0;
+ }
+}
+
+interface_status_t detect_beat_auto(int fd, char *iface) {
+ interface_status_t status;
+ static interface_status_t (*cached_func)(int, char*) = NULL;
+
+ if (cached_func && (status = cached_func(fd, iface)) != IFSTATUS_ERR)
+ return status;
+
+ if ((status = interface_detect_beat_mii(fd, iface)) != IFSTATUS_ERR) {
+ cached_func = interface_detect_beat_mii;
+ daemon_log(LOG_INFO, "Using detection mode: SIOCGMIIPHY");
+ return status;
+ }
+
+ if ((status = interface_detect_beat_ethtool(fd, iface)) != IFSTATUS_ERR) {
+ cached_func = interface_detect_beat_ethtool;
+ daemon_log(LOG_INFO, "Using detection mode: SIOCETHTOOL");
+ return status;
+ }
+
+ if ((status = interface_detect_beat_wlan(fd, iface)) != IFSTATUS_ERR) {
+ cached_func = interface_detect_beat_wlan;
+ daemon_log(LOG_INFO, "Using detection mode: wireless extension");
+ return status;
+ }
+
+ if ((status = interface_detect_beat_priv(fd, iface)) != IFSTATUS_ERR) {
+ cached_func = interface_detect_beat_priv;
+ daemon_log(LOG_INFO, "Using detection mode: SIOCDEVPRIVATE");
+ return status;
+ }
+
+ return IFSTATUS_ERR;
+}
+
+char *strstatus(interface_status_t s) {
+ switch(s) {
+ case IFSTATUS_UP: return "up";
+ case IFSTATUS_DOWN: return "down";
+ case IFSTATUS_ERR: return "error";
+ default: return "disabled";
+ }
+}
+
+interface_status_t detect_beat(int fd, char*iface) {
+ interface_status_t status;
+ static interface_status_t last_status = (interface_status_t) -1;
+
+ if ((status = detect_beat_func(fd, iface)) == IFSTATUS_ERR)
+ status = failure_status;
+
+ if (status == IFSTATUS_ERR && detect_beat_func == detect_beat_auto)
+ daemon_log(LOG_INFO, "Failed to find working plug detection mode for %s", interface);
+
+ if (status != last_status) {
+ setenv(IFPLUGD_ENV_PREVIOUS, strstatus(last_status), 1);
+ setenv(IFPLUGD_ENV_CURRENT, strstatus(status), 1);
+ last_status = status;
+ }
+
+ return status;
+}
+
+int open_iface(char *iface) {
+ int fd;
+ struct ifreq ifr;
+ struct ethtool_drvinfo drvinfo;
+ char txt[256];
+
+ if ((fd = interface_open(iface)) < 0) {
+ daemon_log(LOG_ERR, "Could not create socket: %s", strerror(errno));
+ return fd;
+ }
+
+ if (interface_auto_up)
+ interface_up(fd, iface);
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)-1);
+
+ if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1)
+ snprintf(txt, sizeof(txt)-1, "Using interface %s", iface);
+ else
+ snprintf(txt, sizeof(txt)-1, "Using interface %s/%02X:%02X:%02X:%02X:%02X:%02X", iface, ifr.ifr_hwaddr.sa_data[0] & 0xFF, ifr.ifr_hwaddr.sa_data[1] & 0xFF, ifr.ifr_hwaddr.sa_data[2] & 0xFF, ifr.ifr_hwaddr.sa_data[3] & 0xFF, ifr.ifr_hwaddr.sa_data[4] & 0xFF, ifr.ifr_hwaddr.sa_data[5] & 0xFF);
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)-1);
+
+ drvinfo.cmd = ETHTOOL_GDRVINFO;
+ ifr.ifr_data = (caddr_t) &drvinfo;
+
+ if (ioctl(fd, SIOCETHTOOL, &ifr) != -1)
+ daemon_log(LOG_INFO, "%s with driver <%s> (version: %s)", txt, drvinfo.driver, drvinfo.version);
+ else
+ daemon_log(LOG_INFO, "%s", txt);
+
+ return fd;
+}
+
+void work() {
+ interface_status_t status;
+ int fd = -1;
+ fd_set rfds;
+ int sigfd;
+ time_t t = 0;
+ int send_retval = 1;
+ int paused = 0;
+ static char log_ident[256];
+
+ snprintf(log_ident, sizeof(log_ident), "ifplugd(%s)", interface);
+
+ daemon_log_ident = log_ident;
+
+
+ if (daemon_pid_file_create() < 0) {
+ daemon_log(LOG_ERR, "Could not create PID file %s.", daemon_pid_file_proc());
+ goto finish;
+ }
+
+ if (daemon_signal_init(SIGINT, SIGTERM, SIGQUIT, SIGHUP, SIGCHLD, SIGUSR1, SIGUSR2, -1) < 0) {
+ daemon_log(LOG_ERR, "Could not register signal handler: %s", strerror(errno));
+ goto finish;
+ }
+
+ switch (api_mode) {
+ case API_ETHTOOL: detect_beat_func = interface_detect_beat_ethtool; break;
+ case API_MII: detect_beat_func = interface_detect_beat_mii; break;
+ case API_PRIVATE: detect_beat_func = interface_detect_beat_priv; break;
+ case API_WLAN: detect_beat_func = interface_detect_beat_wlan;break;
+
+ default:
+ detect_beat_func = detect_beat_auto;
+ interface_do_message = 0;
+ break;
+ }
+
+ if ((fd = open_iface(interface)) < 0)
+ goto finish;
+
+ if ((status = detect_beat(fd, interface)) == IFSTATUS_ERR)
+ goto finish;
+
+ daemon_log(LOG_INFO, "ifplugd "VERSION" successfully initialized, link beat %sdetected.", status == IFSTATUS_UP ? "" : "not ");
+ beep(status == IFSTATUS_UP ? 0 : 1);
+
+ if (status == IFSTATUS_UP || initial_down)
+ if (action(status) < 0)
+ goto finish;
+
+ if (daemonize && wait_on_fork) {
+ char c = status == IFSTATUS_UP ? 2 : (status == IFSTATUS_DOWN ? 3 : 1);
+ daemon_retval_send(c);
+ send_retval = 0;
+ }
+
+ FD_ZERO(&rfds);
+ FD_SET(sigfd = daemon_signal_fd(), &rfds);
+
+ for (;;) {
+ interface_status_t r;
+ fd_set wrfds = rfds;
+ struct timeval tv = { polltime, 0 };
+
+ if (select(FD_SETSIZE, &wrfds, NULL, NULL, &tv) < 0) {
+ if (errno == EINTR)
+ continue;
+
+ daemon_log(LOG_ERR, "select(): %s", strerror(errno));
+ goto finish;
+ }
+
+
+ if (FD_ISSET(sigfd, &wrfds)) {
+ int sig;
+
+ if ((sig = daemon_signal_next()) < 0) {
+ daemon_log(LOG_ERR, "daemon_signal_next(): %s", strerror(errno));
+ goto finish;
+ }
+
+
+ switch (sig) {
+
+ case SIGINT:
+ case SIGTERM:
+ goto cleanup;
+
+ case SIGQUIT:
+ goto finish;
+
+ case SIGCHLD:
+ break;
+
+ case SIGHUP:
+ daemon_log(LOG_INFO, "SIGHUP: %s, link detected on %s: %s", paused ? "Suspended" : "Running", interface, status == IFSTATUS_DOWN ? "no" : "yes");
+ break;
+
+ case SIGUSR1:
+ daemon_log(LOG_INFO, "SIGUSR1: Daemon suspended (#%i)", ++paused);
+ break;
+
+ case SIGUSR2:
+ if (paused > 0) {
+ daemon_log(LOG_INFO, "SIGUSR2: Daemon resumed (#%i)", paused);
+ paused --;
+ }
+
+ break;
+
+ default:
+ daemon_log(LOG_INFO, "Ignoring unknown signal %s", strsignal(sig));
+ break;
+ }
+ }
+
+
+ if (!paused) {
+ if ((r = detect_beat(fd, interface)) == IFSTATUS_ERR)
+ break;
+
+ if (status != r) {
+ status = r;
+
+ daemon_log(LOG_INFO, "Link beat %s.", status == IFSTATUS_DOWN ? "lost" : "detected");
+ beep(status == IFSTATUS_UP ? 0 : 1);
+
+
+ if (t)
+ t = 0;
+ else {
+ t = time(NULL);
+
+ if (status == IFSTATUS_UP)
+ t += delay_up;
+
+ if (status == IFSTATUS_DOWN)
+ t += delay_down;
+ }
+ }
+ }
+
+
+ if (t && t < time(NULL)) {
+ t = 0;
+
+ if (action(status) < 0)
+ goto finish;
+ }
+ }
+
+cleanup:
+ if (!no_shutdown_script && status == IFSTATUS_UP) {
+ setenv(IFPLUGD_ENV_PREVIOUS, strstatus(status), 1);
+ setenv(IFPLUGD_ENV_CURRENT, strstatus(-1), 1);
+ action(IFSTATUS_DOWN);
+ beep(1);
+ }
+
+finish:
+
+ if (fd >= 0)
+ close(fd);
+
+ if (send_retval && daemonize && wait_on_fork)
+ daemon_retval_send(1);
+
+ daemon_pid_file_remove();
+ daemon_signal_done();
+
+ daemon_log(LOG_INFO, "Exiting.");
+}
+
+void usage(char *p) {
+ char *m;
+
+ switch (api_mode) {
+ case API_ETHTOOL: m = "ethtool"; break;
+ case API_MII: m = "mii"; break;
+ case API_PRIVATE: m = "priv"; break;
+ case API_WLAN: m = "wlan"; break;
+ default: m = "auto";
+ }
+
+ if (strrchr(p, '/'))
+ p = strchr(p, '/')+1;
+
+ printf("%s [options]\n"
+ " -a --no-auto Do not enable interface automatically (%s)\n"
+ " -n --no-daemon Do not daemonize (for debugging) (%s)\n"
+ " -s --no-syslog Do not use syslog, use stderr instead (for debugging) (%s)\n"
+ " -b --no-beep Do not beep (%s)\n"
+ " -f --ignore-fail Ignore detection failure, retry instead (failure is treated as DOWN) (%s)\n"
+ " -F --ignore-fail-positive Ignore detection failure, retry instead (failure is treated as UP) (%s)\n"
+ " -i --iface=IFACE Specify ethernet interface (%s)\n"
+ " -r --run=EXEC Specify program to execute (%s)\n"
+ " -I --ignore-retval Don't exit on nonzero return value of program executed (%s)\n"
+ " -t --poll-time=SECS Specify poll time in seconds (%i)\n"
+ " -u --delay-up=SECS Specify delay for configuring interface (%i)\n"
+ " -d --delay-down=SECS Specify delay for deconfiguring interface (%i)\n"
+ " -m --api-mode=MODE Force API mode (mii, priv, ethtool, wlan, auto) (%s)\n"
+ " -q --no-shutdown Don't run script on daemon quit (%s)\n"
+ " -l --initial-down Run \"down\" script on startup if now cable is detected (%s)\n"
+ " -w --wait-on-fork Wait until daemon fork finished (%s)\n"
+ " -x --extra-arg Specify an extra argument for action script\n"
+ " -h --help Show this help\n"
+ " -k --kill Kill a running daemon\n"
+ " -c --check-running Check if a daemon is currently running\n"
+ " -v --version Show version\n"
+ " -S --suspend Suspend running daemon\n"
+ " -R --resume Resume running daemon\n"
+ " -z --info Write status of running daemon to syslog\n",
+ p,
+ !interface_auto_up ? "on" : "off",
+ !daemonize ? "on" : "off",
+ !use_syslog ? "on" : "off",
+ !use_beep ? "on" : "off",
+ failure_status == IFSTATUS_DOWN ? "on" : "off",
+ failure_status == IFSTATUS_UP ? "on" : "off",
+ interface,
+ run,
+ ignore_retval ? "on" : "off",
+ polltime,
+ delay_up,
+ delay_down,
+ m,
+ no_shutdown_script ? "on" : "off",
+ initial_down ? "on" : "off",
+ wait_on_fork ? "on" : "off");
+}
+
+void parse_args(int argc, char *argv[]) {
+ static struct option long_options[] = {
+ {"no-auto", no_argument, 0, 'a'},
+ {"no-daemon", no_argument, 0, 'n'},
+ {"no-syslog", no_argument, 0, 's'},
+ {"no-beep", no_argument, 0, 'b'},
+ {"ignore-fail", no_argument, 0, 'f'},
+ {"ignore-fail-positive", no_argument, 0, 'F'},
+ {"ignore-retval", no_argument, 0, 'I'},
+ {"iface", required_argument, 0, 'i'},
+ {"run", required_argument, 0, 'r'},
+ {"poll-time", required_argument, 0, 't'},
+ {"delay-up", required_argument, 0, 'u'},
+ {"delay-down", required_argument, 0, 'd'},
+ {"api-mode", required_argument, 0, 'm'},
+ {"wait-on-fork", no_argument, 0, 'w'},
+ {"no-shutdown", no_argument, 0, 'q'},
+ {"help", no_argument, 0, 'h'},
+ {"kill", no_argument, 0, 'k'},
+ {"check-running", no_argument, 0, 'c'},
+ {"version", no_argument, 0, 'v'},
+ {"extra-arg", required_argument, 0, 'x'},
+ {"suspend", no_argument, 0, 'S'},
+ {"resume", no_argument, 0, 'R'},
+ {"info", no_argument, 0, 'z'},
+ {"inital-down", no_argument, 0, 'l'},
+ {0, 0, 0, 0}
+ };
+ int option_index = 0;
+ int help = 0, _kill = 0, _check = 0, _version = 0, _suspend = 0, _resume = 0, _info = 0;
+
+ for (;;) {
+ int c;
+
+ if ((c = getopt_long(argc, argv, "asni:r:t:u:d:hkbfFvm:qwx:cISRzl", long_options, &option_index)) < 0)
+ break;
+
+ switch (c) {
+ case 'a' :
+ interface_auto_up = !interface_auto_up;
+ break;
+ case 's' :
+ use_syslog = !use_syslog;
+ break;
+ case 'n' :
+ daemonize = !daemonize;
+ break;
+ case 'i' :
+ interface = strdup(optarg);
+ break;
+ case 'r':
+ run = strdup(optarg);
+ break;
+ case 'I':
+ ignore_retval = !ignore_retval;
+ break;
+ case 't':
+ polltime = atoi(optarg);
+ if (polltime < 0) polltime = 0;
+ break;
+ case 'u':
+ delay_up = atoi(optarg);
+ break;
+ case 'd':
+ delay_down = atoi(optarg);
+ break;
+ case 'h':
+ help = 1;
+ break;
+ case 'k':
+ _kill = 1;
+ break;
+ case 'c':
+ _check = 1;
+ break;
+ case 'v':
+ _version = 1;
+ break;
+ case 'b':
+ use_beep = !use_beep;
+ break;
+ case 'f':
+ failure_status = IFSTATUS_DOWN;
+ break;
+ case 'F':
+ failure_status = IFSTATUS_UP;
+ break;
+ case 'm':
+ switch (tolower(optarg[0])) {
+ case 'e': api_mode = API_ETHTOOL; break;
+ case 'm': api_mode = API_MII; break;
+ case 'p': api_mode = API_PRIVATE; break;
+ case 'w': api_mode = API_WLAN; break;
+ case 'a': api_mode = API_AUTO; break;
+ default:
+ fprintf(stderr, "Unknown API mode: %s\n", optarg);
+ exit(2);
+ }
+ break;
+ case 'q':
+ no_shutdown_script = !no_shutdown_script;
+ break;
+ case 'l':
+ initial_down = !initial_down;
+ break;
+ case 'w':
+ wait_on_fork = !wait_on_fork;
+ break;
+ case 'x':
+ extra_arg = strdup(optarg);
+ break;
+ case 'S':
+ _suspend = 1;
+ break;
+ case 'R':
+ _resume = 1;
+ break;
+ case 'z':
+ _info = 1;
+ break;
+ default:
+ fprintf(stderr, "Unknown parameter.\n");
+ exit(1);
+ }
+ }
+
+
+ if (!use_syslog)
+ daemon_log_use = DAEMON_LOG_STDERR;
+
+
+ if (help) {
+ usage(argv[0]);
+ exit(0);
+ }
+
+ if (_kill || _resume || _suspend || _info) {
+ if (daemon_pid_file_kill(_kill ? SIGINT : (_resume ? SIGUSR2 : (_info ? SIGHUP : SIGUSR1))) < 0) {
+ daemon_log(LOG_ERR, "Failed to kill daemon. (%s)", strerror(errno));
+ exit(6);
+ }
+
+ exit(0);
+ }
+
+ if (_version) {
+
+#ifdef SVN_REVISION
+ printf("ifplugd "VERSION" (SVN: "SVN_REVISION")\n");
+#else
+ printf("ifplugd "VERSION"\n");
+#endif
+
+ exit(0);
+ }
+
+ if (_check) {
+ pid_t pid = daemon_pid_file_is_running();
+
+ if (pid == (pid_t) -1)
+ printf("ifplugd not running.\n");
+ else
+ printf("ifplugd process for device %s running as pid %u.\n", interface, pid);
+
+ exit(pid == 0 ? 255 : 0);
+ }
+
+}
+
+static volatile int alarmed = 0;
+
+void sigalrm() {
+ alarmed = 1;
+}
+
+int main(int argc, char* argv[]) {
+
+ daemon_pid_file_proc = pid_file_proc;
+
+ if ((daemon_log_ident = strrchr(argv[0], '/')))
+ daemon_log_ident++;
+ else
+ daemon_log_ident = argv[0];
+
+ parse_args(argc, argv);
+
+ if (geteuid() != 0) {
+ daemon_log(LOG_ERR, "Sorry, you need to be root to run this binary.");
+ return 2;
+ }
+
+
+ if (daemon_pid_file_is_running() >= 0) {
+ daemon_log(LOG_ERR, "Sorry, there is already an instance of ifplugd for %s running.", interface);
+ return 4;
+ }
+
+ if (daemonize) {
+ pid_t pid;
+
+ if (wait_on_fork)
+ if (daemon_retval_init() < 0) {
+ daemon_log(LOG_ERR, "Sorry, could not create pipe: %s", strerror(errno));
+ return 4;
+ }
+
+ if ((pid = daemon_fork()) < 0)
+ return 3;
+
+ if (pid) {
+ int c = 0;
+
+ // Parent process
+
+ if (wait_on_fork)
+ if ((c = daemon_retval_wait(60)) < 0) {
+ daemon_log(LOG_WARNING, "Killing background process.");
+ kill(pid, SIGTERM);
+ }
+
+
+ return c;
+ }
+ }
+
+ // Let's go
+ work();
+ return 0;
+}