/* -*- Mode: C; tab-width: 4; indent-tabs-mode: f; c-basic-offset: 4 -*- */ /* $Id: ifplugd.c 123 2005-06-04 16:07:11Z 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. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ethtool-local.h" #include "interface.h" #include "nlapi.h" #include "ifmonitor.h" #include "svn-revision.h" #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 = NULL; char *run = SYSCONFDIR"/ifplugd/ifplugd.action"; char *extra_arg = NULL; int polltime = 1, pollutime = 0, delay_up = 0, delay_down = 5; int daemonize = 1, use_beep = 1, beep_on_up = 1, beep_on_down = 1, no_startup_script = 0, no_shutdown_script = 0, wait_on_fork = 0, wait_on_kill = 0, use_syslog = 1, ignore_retval = 0, initial_down = 0, use_ifmonitor = 0; int disabled = 0; interface_status_t failure_status = IFSTATUS_ERR; enum { API_AUTO, API_ETHTOOL, API_MII, API_PRIVATE, API_WLAN, API_IFF } api_mode = API_AUTO; interface_status_t (*detect_beat_func)(int, char*); interface_status_t (*cached_detect_beat_func)(int, char*) = NULL; // 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|O_NOCTTY)) < 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; } static void beep_up(int b) { if(!beep_on_up) return; beep(b); } static void beep_down(int b) { if(!beep_on_down) return; beep(b); } 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, (char *) NULL); _exit(EXIT_FAILURE); } close(_pipe[1]); FD_ZERO(&rfds); FD_SET(_pipe[0], &rfds); sigfd = daemon_signal_fd(); FD_SET(sigfd, &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); } } } 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_up(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_up(0); daemon_log(LOG_INFO, "Program executed successfully."); return 0; } } interface_status_t detect_beat_auto(int fd, char *iface) { interface_status_t status; if (cached_detect_beat_func && (status = cached_detect_beat_func(fd, iface)) != IFSTATUS_ERR) return status; if ((status = interface_detect_beat_ethtool(fd, iface)) != IFSTATUS_ERR) { cached_detect_beat_func = interface_detect_beat_ethtool; daemon_log(LOG_INFO, "Using detection mode: SIOCETHTOOL"); return status; } if ((status = interface_detect_beat_mii(fd, iface)) != IFSTATUS_ERR) { cached_detect_beat_func = interface_detect_beat_mii; daemon_log(LOG_INFO, "Using detection mode: SIOCGMIIPHY"); return status; } if ((status = interface_detect_beat_wlan(fd, iface)) != IFSTATUS_ERR) { cached_detect_beat_func = interface_detect_beat_wlan; daemon_log(LOG_INFO, "Using detection mode: wireless extension"); return status; } if ((status = interface_detect_beat_iff(fd, iface)) != IFSTATUS_ERR) { cached_detect_beat_func = interface_detect_beat_iff; daemon_log(LOG_INFO, "Using detection mode: IFF_RUNNING"); 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 (disabled) return IFSTATUS_DOWN; 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 detect plug status of %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 welcome_iface(int fd, char *iface) { struct ifreq ifr; struct ethtool_drvinfo drvinfo; char txt[256]; 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); cached_detect_beat_func = NULL; return 0; } int ifmonitor_cb(int b, int index, unsigned short type, const char *name) { if (!name) return 0; if (!strcmp(name, interface)) disabled = !b; return 0; } int is_iface_available(int s, char *p) { struct ifreq req; int r; memset(&req, 0, sizeof(req)); strncpy(req.ifr_name, p, IFNAMSIZ); if ((r = ioctl(s, SIOCGIFINDEX, &req)) < 0 && errno != ENODEV) { daemon_log(LOG_ERR, "SIOCGIFINDEX failed: %s\n", strerror(errno)); return -1; } return r >= 0 && req.ifr_ifindex >= 0; } void work(void) { interface_status_t status; int fd = -1; fd_set fds; 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; daemon_log(LOG_INFO, "ifplugd "VERSION" initializing%s.", use_ifmonitor ? ", using NETLINK device monitoring" : ""); 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; case API_IFF: detect_beat_func = interface_detect_beat_iff; break; default: detect_beat_func = detect_beat_auto; interface_do_message = 0; break; } if ((fd = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) { daemon_log(LOG_ERR, "socket(): %s", strerror(errno)); goto finish; } if (use_ifmonitor) { int b; if ((b = is_iface_available(fd, interface)) < 0) { daemon_log(LOG_ERR, "Failed to check interface availabilty!"); goto finish; } disabled = !b; if (nlapi_open(RTMGRP_LINK) < 0) goto finish; if (ifmonitor_init(ifmonitor_cb) < 0) goto finish; } else disabled = 0; if (!disabled) { if (welcome_iface(fd, interface) < 0) goto finish; } if ((status = detect_beat(fd, interface)) == IFSTATUS_ERR) goto finish; daemon_log(LOG_INFO, "Initialization complete, link beat %sdetected%s.", status == IFSTATUS_UP ? "" : "not ", use_ifmonitor ? (disabled ? ", interface disabled" : ", interface enabled") : ""); if(status == IFSTATUS_UP) beep_up(0); else beep_down(1); if ((!no_startup_script && status == IFSTATUS_UP) || initial_down) if (action(status) < 0) goto finish; if (send_retval && daemonize && wait_on_fork) { char c = status == IFSTATUS_UP ? 2 : (status == IFSTATUS_DOWN ? 3 : 1); daemon_retval_send(c); send_retval = 0; } FD_ZERO(&fds); sigfd = daemon_signal_fd(); FD_SET(sigfd, &fds); if (use_ifmonitor) FD_SET(nlapi_fd, &fds); for (;;) { interface_status_t s; fd_set qfds = fds; int d; struct timeval tv; tv.tv_sec = polltime; tv.tv_usec = pollutime; if (t) { int delay = t - time(NULL); if (delay < 0) tv.tv_sec = 0; else if (delay < tv.tv_sec) tv.tv_sec = delay; } if (select(FD_SETSIZE, &qfds, NULL, NULL, &tv) < 0) { if (errno == EINTR) continue; daemon_log(LOG_ERR, "select(): %s", strerror(errno)); goto finish; } //daemon_log(LOG_INFO, "select()"); d = disabled; s = status; if (use_ifmonitor) { if (FD_ISSET(nlapi_fd, &qfds)) { if (nlapi_work(0) < 0) goto finish; } if (d && !disabled) { daemon_log(LOG_INFO, "Interface enabled"); welcome_iface(fd, interface); status = IFSTATUS_DOWN; } if (!d && disabled) { daemon_log(LOG_INFO, "Interface disabled"); status = IFSTATUS_DOWN; } } if (!paused && !disabled) { //daemon_log(LOG_INFO, "detect"); if ((status = detect_beat(fd, interface)) == IFSTATUS_ERR) { if (!use_ifmonitor) goto finish; status = IFSTATUS_DOWN; } } if (status != s) { daemon_log(LOG_INFO, "Link beat %s.", status == IFSTATUS_DOWN ? "lost" : "detected"); if(status == IFSTATUS_UP) beep_up(0); else beep_down(1); if (t) t = 0; else { t = time(NULL); if (status == IFSTATUS_UP) t += delay_up; if (status == IFSTATUS_DOWN) t += delay_down; } } if (FD_ISSET(sigfd, &qfds)) { 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"); if (use_ifmonitor) daemon_log(LOG_INFO, "SIGHUP: Interface %s", disabled ? "disabled" : "enabled"); 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 (t && t <= time(NULL)) { t = 0; if (action(status) < 0) goto finish; } } cleanup: if (!no_shutdown_script && (status == IFSTATUS_UP || (status == IFSTATUS_DOWN && t))) { setenv(IFPLUGD_ENV_PREVIOUS, strstatus(status), 1); setenv(IFPLUGD_ENV_CURRENT, strstatus(-1), 1); action(IFSTATUS_DOWN); beep_down(1); } finish: if (fd >= 0) close(fd); if (use_ifmonitor) nlapi_close(); if (send_retval && daemonize && wait_on_fork) daemon_retval_send(255); 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; case API_IFF: m = "iff"; break; default: m = "auto"; } if (strrchr(p, '/')) p = strchr(p, '/')+1; printf("%s -- Network Interface Plug Detection Daemon\n\n" "Usage: %s [options]\n\n" "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" " -U --no-beep-up Do not beep on interface up (%s)\n" " -D --no-beep-down Do not beep on interface down (%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" " -T --poll-utime=USECS Specify poll time in microseconds, add to -t (%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" " -p --no-startup Don't run script on daemon startup (%s)\n" " -q --no-shutdown Don't run script on daemon quit (%s)\n" " -l --initial-down Run \"down\" script on startup if no cable is detected (%s)\n" " -w --wait-on-fork Wait until daemon fork finished (%s)\n" " -W --wait-on-kill When run with -k, wait until the daemon died (%s)\n" " -x --extra-arg Specify an extra argument for action script\n" " -M --monitor Use interface monitoring (%s)\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, p, !interface_auto_up ? "on" : "off", !daemonize ? "on" : "off", !use_syslog ? "on" : "off", !use_beep ? "on" : "off", !beep_on_up ? "on" : "off", !beep_on_down ? "on" : "off", failure_status == IFSTATUS_DOWN ? "on" : "off", failure_status == IFSTATUS_UP ? "on" : "off", interface, run, ignore_retval ? "on" : "off", polltime, pollutime, delay_up, delay_down, m, no_startup_script ? "on" : "off", no_shutdown_script ? "on" : "off", initial_down ? "on" : "off", wait_on_fork ? "on" : "off", wait_on_kill ? "on" : "off", use_ifmonitor ? "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'}, {"no-beep-up", no_argument, 0, 'U'}, {"no-beep-down", no_argument, 0, 'D'}, {"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'}, {"poll-utime", 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'}, {"wait-on-kill", no_argument, 0, 'W'}, {"no-startup", no_argument, 0, 'p'}, {"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'}, {"initial-down", no_argument, 0, 'l'}, {"monitor", no_argument, 0, 'M'}, {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:T:u:d:hkbUDfFvm:pqwx:cISRzlMW", 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' : if (interface) free(interface); 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 'T': pollutime = atoi(optarg); if (pollutime < 0) pollutime = 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 'U': beep_on_up = !beep_on_up; break; case 'D': beep_on_down = !beep_on_down; 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; case 'i': api_mode = API_IFF; break; default: daemon_log(LOG_ERR, "Unknown API mode: %s", optarg); exit(2); } break; case 'p': no_startup_script = !no_startup_script; 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 'W': wait_on_kill = !wait_on_kill; break; case 'x': extra_arg = strdup(optarg); break; case 'S': _suspend = 1; break; case 'R': _resume = 1; break; case 'z': _info = 1; break; case 'M': use_ifmonitor = !use_ifmonitor; break; default: daemon_log(LOG_ERR, "Unknown parameter."); exit(1); } } if (!interface) interface = strdup("eth0"); if (!use_syslog) daemon_log_use = DAEMON_LOG_STDERR; if (help) { usage(argv[0]); exit(0); } if (_kill || _resume || _suspend || _info) { int rv; if (_kill && wait_on_kill) rv = daemon_pid_file_kill_wait(SIGINT, 5); else rv = daemon_pid_file_kill(_kill ? SIGINT : (_resume ? SIGUSR2 : (_info ? SIGHUP : SIGUSR1))); if (rv < 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 || pid == 0) { printf("ifplugd not running.\n"); exit(255); } else { printf("ifplugd process for device %s running as pid %u.\n", interface, pid); exit(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); } if (c > 3) daemon_log(LOG_ERR, "Daemon failed with error condition #%i. See syslog for details", c); return c; } } // Let's go work(); return 0; }