source: trunk/third/ifplugd/src/ifplugd.c @ 20388

Revision 20388, 25.6 KB checked in by amb, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20387, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; tab-width: 4; indent-tabs-mode: f; c-basic-offset: 4 -*- */
2/* $Id: ifplugd.c,v 1.1.1.1 2004-04-09 20:09:13 amb Exp $ */
3
4/*
5 * This file is part of ifplugd.
6 *
7 * ifplugd is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * ifplugd is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with ifplugd; if not, write to the Free Software Foundation,
19 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
20 */
21
22#define _GNU_SOURCE
23
24#include <stdlib.h>
25#include <stdio.h>
26#include <string.h>
27#include <signal.h>
28#include <unistd.h>
29#include <sys/wait.h>
30#include <errno.h>
31#include <sys/stat.h>
32#include <getopt.h>
33#include <stdarg.h>
34#include <syslog.h>
35#include <fcntl.h>
36#include <linux/kd.h>
37#include <sys/ioctl.h>
38#include <limits.h>
39#include <net/if.h>
40#include <linux/sockios.h>
41#include <sys/types.h>
42#include <ctype.h>
43#include <sys/time.h>
44#include <time.h>
45
46#include <libdaemon/dlog.h>
47#include <libdaemon/dpid.h>
48#include <libdaemon/dsignal.h>
49#include <libdaemon/dfork.h>
50
51#include "ethtool-local.h"
52#include "interface.h"
53#include "nlapi.h"
54#include "ifmonitor.h"
55#include "svn-revision.h"
56
57#ifdef HAVE_CONFIG_H
58#include <config.h>
59#endif
60
61#define VARRUN "/var/run"
62#define IFPLUGD_ENV_PREVIOUS "IFPLUGD_PREVIOUS"
63#define IFPLUGD_ENV_CURRENT "IFPLUGD_CURRENT"
64
65int interface_auto_up = 1,
66        interface_do_message = 1;
67
68char *interface = NULL;
69char *run = SYSCONFDIR"/ifplugd/ifplugd.action";
70char *extra_arg = NULL;
71
72int polltime = 1,
73        delay_up = 0,
74        delay_down = 5;
75
76int daemonize = 1,
77        use_beep = 1,
78        no_shutdown_script = 0,
79        wait_on_fork = 0,
80        wait_on_kill = 0,
81        use_syslog = 1,
82        ignore_retval = 0,
83        initial_down = 0,
84        use_ifmonitor = 0;
85
86int disabled = 0;
87
88interface_status_t failure_status = IFSTATUS_ERR;
89
90enum { API_AUTO, API_ETHTOOL, API_MII, API_PRIVATE, API_WLAN } api_mode = API_AUTO;
91
92interface_status_t (*detect_beat_func)(int, char*);
93interface_status_t (*cached_detect_beat_func)(int, char*) = NULL;
94
95// 0: high, 1: low, 2: very low
96void beep(int b) {
97    int fd = -1, argp;
98
99    if (!use_beep)
100        return;
101   
102    if ((fd = open("/dev/tty1", O_WRONLY|O_NOCTTY)) < 0) {
103        use_beep = 0;
104        daemon_log(LOG_WARNING, "Could not open /dev/tty, cannot beep.");
105        goto finish;
106    }
107
108    switch (b) {
109        case 0: argp = (100<<16) + 0x637; break;
110        case 1: argp = (100<<16) + 0x937; break;
111        default: argp = (100<<16) + 0x1237; break;
112    }
113
114    if (ioctl(fd, KDMKTONE, argp) != 0) {
115        use_beep = 0;
116        daemon_log(LOG_WARNING, "Beep failure, disabled.");
117        goto finish;
118    }
119
120    usleep((argp >> 16)*1000);
121   
122finish:
123
124    if (fd >= 0)
125        close(fd);
126
127    return;
128}
129
130const char *pid_file_proc() {
131    static char fn[PATH_MAX];
132    snprintf(fn, sizeof(fn), "%s/ifplugd.%s.pid", VARRUN, interface);
133    return fn;
134}
135
136int action(interface_status_t status) {
137    pid_t pid;
138    int _pipe[2];
139    unsigned n = 0;
140    static char buf[256];
141    char *arg = (status == IFSTATUS_UP ? "up" : "down");
142    int sigfd, r;
143    fd_set rfds;
144
145    daemon_log(LOG_INFO, "Executing '%s %s %s'.", run, interface, arg);
146   
147    if (pipe(_pipe) < 0) {
148        daemon_log(LOG_ERR, "pipe() failed: %s", strerror(errno));
149        return -1;
150    }
151
152    if ((pid = fork()) < 0) {
153        daemon_log(LOG_ERR, "fork() failed: %s", strerror(errno));
154        return -1;
155           
156    } else if (pid == 0) {
157        dup2(_pipe[1], 1);
158        dup2(_pipe[1], 2);
159       
160        if (_pipe[0] > 2)
161            close(_pipe[0]);
162
163        if (_pipe[1] > 2)
164            close(_pipe[1]);
165
166                umask(0022); /* Set up a sane umask */
167       
168        execl(run, run, interface, arg, extra_arg, 0);
169
170        _exit(EXIT_FAILURE);
171    }
172
173    close(_pipe[1]);
174
175    FD_ZERO(&rfds);
176    FD_SET(_pipe[0], &rfds);
177    FD_SET(sigfd = daemon_signal_fd(), &rfds);   
178
179    n = 0;
180
181    for (;;) {
182        fd_set wrfds = rfds;
183
184        if (select(FD_SETSIZE, &wrfds, NULL, NULL, NULL) < 0) {
185
186            if (errno == EINTR)
187                continue;
188
189            break;
190        }
191
192
193        if (FD_ISSET(_pipe[0], &wrfds)) {
194            char c;
195
196            if (read(_pipe[0], &c, 1) != 1)
197                break;
198
199            buf[n] = c;
200           
201            if (c == '\n' || n >= sizeof(buf) - 2) {
202                if (c != '\n') n++;
203                buf[n] = 0;
204
205                if (buf[0])
206                    daemon_log(LOG_WARNING, "client: %s", buf);
207           
208                n = 0;
209            } else
210                n++;
211        }
212
213        if (FD_ISSET(sigfd, &wrfds)) {
214            int sig;
215           
216            if ((sig = daemon_signal_next()) < 0) {
217                daemon_log(LOG_ERR, "daemon_signal_next(): %s", strerror(errno));
218                break;
219            }
220
221            if (sig != SIGCHLD) {
222                daemon_log(LOG_WARNING, "Killing child.");
223                kill(pid, SIGTERM);
224            }
225        }
226       
227    }
228
229    if (n > 0) {
230        buf[n] = 0;
231        daemon_log(LOG_WARNING, "client: %s", buf);
232    }
233
234    waitpid(pid, &r, 0);
235
236    close(_pipe[0]);
237
238    if (!WIFEXITED(r) || WEXITSTATUS(r) != 0) {
239        if (status == IFSTATUS_UP)
240            beep(2);
241        daemon_log(LOG_ERR, "Program execution failed, return value is %i.", WEXITSTATUS(r));
242
243        return ignore_retval ? 0 : -1;
244    } else {
245        if (status == IFSTATUS_UP)
246            beep(0);
247
248        daemon_log(LOG_INFO, "Program executed successfully.");
249        return 0;
250    }
251}
252
253interface_status_t detect_beat_auto(int fd, char *iface) {
254    interface_status_t status;
255
256    if (cached_detect_beat_func && (status = cached_detect_beat_func(fd, iface)) != IFSTATUS_ERR)
257        return status;
258   
259    if ((status = interface_detect_beat_mii(fd, iface)) != IFSTATUS_ERR) {
260        cached_detect_beat_func = interface_detect_beat_mii;
261        daemon_log(LOG_INFO, "Using detection mode: SIOCGMIIPHY");
262        return status;
263    }
264   
265    if ((status = interface_detect_beat_ethtool(fd, iface)) != IFSTATUS_ERR) {
266        cached_detect_beat_func = interface_detect_beat_ethtool;
267        daemon_log(LOG_INFO, "Using detection mode: SIOCETHTOOL");
268        return status;
269    }
270
271    if ((status = interface_detect_beat_wlan(fd, iface)) != IFSTATUS_ERR) {
272        cached_detect_beat_func = interface_detect_beat_wlan;
273        daemon_log(LOG_INFO, "Using detection mode: wireless extension");
274        return status;
275    }
276
277    if ((status = interface_detect_beat_priv(fd, iface)) != IFSTATUS_ERR) {
278        cached_detect_beat_func = interface_detect_beat_priv;
279        daemon_log(LOG_INFO, "Using detection mode: SIOCDEVPRIVATE");
280        return status;
281    }
282
283    return IFSTATUS_ERR;
284}
285
286char *strstatus(interface_status_t s) {
287    switch(s) {
288        case IFSTATUS_UP: return "up";
289        case IFSTATUS_DOWN: return "down";
290        case IFSTATUS_ERR: return "error";
291        default: return "disabled";
292    }
293}
294
295interface_status_t detect_beat(int fd, char*iface) {
296    interface_status_t status;
297    static interface_status_t last_status = (interface_status_t) -1;
298
299        if (disabled)
300                return IFSTATUS_DOWN;
301       
302    if ((status = detect_beat_func(fd, iface)) == IFSTATUS_ERR)
303        status = failure_status;
304
305    if (status == IFSTATUS_ERR && detect_beat_func == detect_beat_auto)
306        daemon_log(LOG_INFO, "Failed to detect plug status of %s", interface);
307   
308    if (status != last_status) {
309        setenv(IFPLUGD_ENV_PREVIOUS, strstatus(last_status), 1);
310        setenv(IFPLUGD_ENV_CURRENT, strstatus(status), 1);
311        last_status = status;
312    }
313   
314    return status;
315}
316
317int welcome_iface(int fd, char *iface) {
318    struct ifreq ifr;
319    struct ethtool_drvinfo drvinfo;
320    char txt[256];
321
322    if (interface_auto_up)
323        interface_up(fd, iface);
324   
325    memset(&ifr, 0, sizeof(ifr));
326    strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)-1);
327   
328    if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1)
329        snprintf(txt, sizeof(txt)-1, "Using interface %s", iface);
330    else
331        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);
332
333    memset(&ifr, 0, sizeof(ifr));
334    strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)-1);
335
336    drvinfo.cmd = ETHTOOL_GDRVINFO;
337    ifr.ifr_data = (caddr_t) &drvinfo;
338   
339    if (ioctl(fd, SIOCETHTOOL, &ifr) != -1)
340        daemon_log(LOG_INFO, "%s with driver <%s> (version: %s)", txt, drvinfo.driver, drvinfo.version);
341    else
342        daemon_log(LOG_INFO, "%s", txt);
343
344        cached_detect_beat_func = NULL;
345       
346    return 0;
347}
348
349int ifmonitor_cb(int b, int index, unsigned short type, const char *name) {
350        if (!name)
351                return 0;
352
353        if (!strcmp(name, interface))
354                disabled = !b;
355
356        return 0;
357}
358
359int is_iface_available(int s, char *p) {
360    struct ifreq req;
361    int r;
362
363    memset(&req, 0, sizeof(req));
364    strncpy(req.ifr_name, p, IFNAMSIZ);
365   
366    if ((r = ioctl(s, SIOCGIFINDEX, &req)) < 0 && errno != ENODEV) {
367        daemon_log(LOG_ERR, "SIOCGIFINDEX failed: %s\n", strerror(errno));
368        return -1;
369    }
370    return r >= 0 && req.ifr_ifindex >= 0;
371}
372
373void work(void) {
374    interface_status_t status;
375    int fd = -1;
376    fd_set fds;
377    int sigfd;
378    time_t t = 0;
379    int send_retval = 1;
380    int paused = 0;
381    static char log_ident[256];
382
383    snprintf(log_ident, sizeof(log_ident), "ifplugd(%s)", interface);
384
385    daemon_log_ident = log_ident;
386
387    daemon_log(LOG_INFO, "ifplugd "VERSION" initializing%s.", use_ifmonitor ? ", using NETLINK device monitoring" : "");
388
389    if (daemon_pid_file_create() < 0) {
390        daemon_log(LOG_ERR, "Could not create PID file %s.", daemon_pid_file_proc());
391        goto finish;
392    }
393
394    if (daemon_signal_init(SIGINT, SIGTERM, SIGQUIT, SIGHUP, SIGCHLD, SIGUSR1, SIGUSR2, -1) < 0) {
395        daemon_log(LOG_ERR, "Could not register signal handler: %s", strerror(errno));
396        goto finish;
397    }
398
399    switch (api_mode) {
400        case API_ETHTOOL: detect_beat_func = interface_detect_beat_ethtool; break;
401        case API_MII: detect_beat_func = interface_detect_beat_mii; break;
402        case API_PRIVATE: detect_beat_func = interface_detect_beat_priv; break;
403        case API_WLAN: detect_beat_func = interface_detect_beat_wlan;break;
404           
405        default:
406            detect_beat_func = detect_beat_auto;
407            interface_do_message = 0;
408            break;
409    }
410
411        if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
412        daemon_log(LOG_ERR, "socket(): %s", strerror(errno));
413                goto finish;
414    }
415
416        if (use_ifmonitor) {
417                int b;
418                if ((b = is_iface_available(fd, interface)) < 0) {
419                        daemon_log(LOG_ERR, "Failed to check interface availabilty!");
420                        goto finish;
421                }
422               
423                disabled = !b;
424
425                if (nlapi_open(RTMGRP_LINK) < 0)
426                        goto finish;
427
428                if (ifmonitor_init(ifmonitor_cb) < 0)
429                        goto finish;
430        } else
431                disabled = 0;
432
433        if (!disabled) {
434                if (welcome_iface(fd, interface) < 0)
435                        goto finish;
436        }
437
438    if ((status = detect_beat(fd, interface)) == IFSTATUS_ERR)
439        goto finish;
440   
441    daemon_log(LOG_INFO, "Initialization complete, link beat %sdetected%s.", status == IFSTATUS_UP ? "" : "not ", use_ifmonitor ? (disabled ? ", interface disabled" : ", interface enabled") : "");
442    beep(status == IFSTATUS_UP ? 0 : 1);
443
444    if (status == IFSTATUS_UP || initial_down)
445        if (action(status) < 0)
446            goto finish;
447
448    if (send_retval && daemonize && wait_on_fork) {
449        char c = status == IFSTATUS_UP ? 2 : (status == IFSTATUS_DOWN ? 3 : 1);
450        daemon_retval_send(c);
451        send_retval = 0;
452    }
453
454    FD_ZERO(&fds);
455    FD_SET(sigfd = daemon_signal_fd(), &fds);
456
457        if (use_ifmonitor)
458                FD_SET(nlapi_fd, &fds);
459
460    for (;;) {
461        interface_status_t s;
462        fd_set qfds = fds;
463                int d;
464        struct timeval tv = { polltime, 0 };
465       
466        if (select(FD_SETSIZE, &qfds, NULL, NULL, &tv) < 0) {
467            if (errno == EINTR)
468                continue;
469
470            daemon_log(LOG_ERR, "select(): %s", strerror(errno));
471            goto finish;
472        }
473
474                //daemon_log(LOG_INFO, "select()");
475               
476                d = disabled;
477                s = status;
478               
479                if (use_ifmonitor) {
480
481                        if (FD_ISSET(nlapi_fd, &qfds)) {
482                                if (nlapi_work(0) < 0)
483                                        goto finish;
484                        }
485
486                        if (d && !disabled) {
487                                daemon_log(LOG_INFO, "Interface enabled");
488                                welcome_iface(fd, interface);
489                                status = IFSTATUS_DOWN;
490                        }
491                       
492                        if (!d && disabled) {
493                                daemon_log(LOG_INFO, "Interface disabled");
494                                status = IFSTATUS_DOWN;
495                        }
496                }
497           
498
499        if (!paused && !disabled) {
500                        //daemon_log(LOG_INFO, "detect");
501            if ((status = detect_beat(fd, interface)) == IFSTATUS_ERR) {
502                                if (!use_ifmonitor)
503                                        goto finish;
504
505                                status = IFSTATUS_DOWN;
506                        }
507                }
508
509                if (status != s) {
510                        daemon_log(LOG_INFO, "Link beat %s.", status == IFSTATUS_DOWN ? "lost" : "detected");
511                        beep(status == IFSTATUS_UP ? 0 : 1);
512                       
513                        if (t)
514                                t = 0;
515                        else {
516                                t = time(NULL);
517                               
518                                if (status == IFSTATUS_UP)
519                                        t += delay_up;
520                               
521                                if (status == IFSTATUS_DOWN)
522                                        t += delay_down;
523            }
524        }
525
526        if (FD_ISSET(sigfd, &qfds)) {
527            int sig;
528
529            if ((sig = daemon_signal_next()) < 0) {
530                daemon_log(LOG_ERR, "daemon_signal_next(): %s", strerror(errno));
531                goto finish;
532            }
533
534            switch (sig) {
535
536                case SIGINT:
537                case SIGTERM:
538                    goto cleanup;
539                   
540                case SIGQUIT:
541                    goto finish;
542                   
543                case SIGCHLD:
544                    break;
545
546                case SIGHUP:
547                    daemon_log(LOG_INFO, "SIGHUP: %s, link detected on %s: %s", paused ? "Suspended" : "Running", interface, status == IFSTATUS_DOWN ? "no" : "yes");
548
549                                        if (use_ifmonitor)
550                                                daemon_log(LOG_INFO, "SIGHUP: Interface %s", disabled ? "disabled" : "enabled");
551                    break;
552                   
553                case SIGUSR1:
554                    daemon_log(LOG_INFO, "SIGUSR1: Daemon suspended (#%i)", ++paused);
555                    break;
556
557                case SIGUSR2:
558                    if (paused > 0) {
559                        daemon_log(LOG_INFO, "SIGUSR2: Daemon resumed (#%i)", paused);
560                        paused --;
561                    }
562                   
563                    break;
564                   
565                default:
566                    daemon_log(LOG_INFO, "Ignoring unknown signal %s", strsignal(sig));
567                    break;
568            }
569        }
570
571                if (t && t < time(NULL)) {
572            t = 0;
573
574            if (action(status) < 0)
575                goto finish;
576        }
577    }
578
579cleanup:
580        if (!no_shutdown_script && (status == IFSTATUS_UP || (status == IFSTATUS_DOWN && t))) {
581        setenv(IFPLUGD_ENV_PREVIOUS, strstatus(status), 1);
582        setenv(IFPLUGD_ENV_CURRENT, strstatus(-1), 1);
583        action(IFSTATUS_DOWN);
584        beep(1);
585    }
586   
587finish:
588
589    if (fd >= 0)
590        close(fd);
591
592        if (use_ifmonitor)
593                nlapi_close();
594       
595    if (send_retval && daemonize && wait_on_fork)
596        daemon_retval_send(255);
597
598    daemon_pid_file_remove();
599    daemon_signal_done();
600   
601    daemon_log(LOG_INFO, "Exiting.");
602}
603
604void usage(char *p) {
605    char *m;
606
607    switch (api_mode) {
608        case API_ETHTOOL: m = "ethtool"; break;
609        case API_MII: m = "mii"; break;
610        case API_PRIVATE: m = "priv"; break;
611        case API_WLAN: m = "wlan"; break;
612        default: m = "auto";
613    }
614   
615    if (strrchr(p, '/'))
616        p = strchr(p, '/')+1;
617
618    printf("%s -- Network Interface Plug Detection Daemon\n\n"
619                   "Usage: %s [options]\n\n"
620                   "Options:\n"
621           "   -a --no-auto              Do not enable interface automatically (%s)\n"
622           "   -n --no-daemon            Do not daemonize (for debugging) (%s)\n"
623           "   -s --no-syslog            Do not use syslog, use stderr instead (for debugging) (%s)\n"
624           "   -b --no-beep              Do not beep (%s)\n"
625           "   -f --ignore-fail          Ignore detection failure, retry instead (failure is treated as DOWN) (%s)\n"
626           "   -F --ignore-fail-positive Ignore detection failure, retry instead (failure is treated as UP) (%s)\n"
627           "   -i --iface=IFACE          Specify ethernet interface (%s)\n"
628           "   -r --run=EXEC             Specify program to execute (%s)\n"
629           "   -I --ignore-retval        Don't exit on nonzero return value of program executed (%s)\n"
630           "   -t --poll-time=SECS       Specify poll time in seconds (%i)\n"
631           "   -u --delay-up=SECS        Specify delay for configuring interface (%i)\n"
632           "   -d --delay-down=SECS      Specify delay for deconfiguring interface (%i)\n"
633           "   -m --api-mode=MODE        Force API mode (mii, priv, ethtool, wlan, auto) (%s)\n"
634           "   -q --no-shutdown          Don't run script on daemon quit (%s)\n"
635                   "   -l --initial-down         Run \"down\" script on startup if now cable is detected (%s)\n"
636           "   -w --wait-on-fork         Wait until daemon fork finished (%s)\n"
637                   "   -W --wait-on-kill         When run with -k, wait until the daemon died (%s)\n"
638                   "   -x --extra-arg            Specify an extra argument for action script\n"
639                   "   -M --monitor              Use interface monitoring (%s)\n"
640           "   -h --help                 Show this help\n"
641           "   -k --kill                 Kill a running daemon\n"
642                   "   -c --check-running        Check if a daemon is currently running\n"
643           "   -v --version              Show version\n"
644           "   -S --suspend              Suspend running daemon\n"
645           "   -R --resume               Resume running daemon\n"
646           "   -z --info                 Write status of running daemon to syslog\n",
647           p, p,
648           !interface_auto_up ? "on" : "off",
649           !daemonize ? "on" : "off",
650           !use_syslog ? "on" : "off",
651           !use_beep ? "on" : "off",
652           failure_status == IFSTATUS_DOWN ? "on" : "off",
653           failure_status == IFSTATUS_UP ? "on" : "off",
654           interface,
655           run,
656           ignore_retval ? "on" : "off",
657           polltime,
658           delay_up,
659           delay_down,
660           m,
661           no_shutdown_script ? "on" : "off",
662                   initial_down ? "on" : "off",
663           wait_on_fork ? "on" : "off",
664                   wait_on_kill ? "on" : "off",
665                   use_ifmonitor ? "on" : "off");
666}
667
668void parse_args(int argc, char *argv[]) {
669    static struct option long_options[] = {
670        {"no-auto",              no_argument, 0, 'a'},
671        {"no-daemon",            no_argument, 0, 'n'},
672        {"no-syslog",            no_argument, 0, 's'},
673        {"no-beep",              no_argument, 0, 'b'},
674        {"ignore-fail",          no_argument, 0, 'f'},
675        {"ignore-fail-positive", no_argument, 0, 'F'},
676        {"ignore-retval",        no_argument, 0, 'I'},
677        {"iface",                required_argument, 0, 'i'},
678        {"run",                  required_argument, 0, 'r'},
679        {"poll-time",            required_argument, 0, 't'},
680        {"delay-up",             required_argument, 0, 'u'},
681        {"delay-down",           required_argument, 0, 'd'},
682        {"api-mode",             required_argument, 0, 'm'},
683        {"wait-on-fork",         no_argument, 0, 'w'},
684                {"wait-on-kill",         no_argument, 0, 'W'},
685        {"no-shutdown",          no_argument, 0, 'q'},
686        {"help",                 no_argument, 0, 'h'},
687        {"kill",                 no_argument, 0, 'k'},
688        {"check-running",        no_argument, 0, 'c'},
689        {"version",              no_argument, 0, 'v'},
690        {"extra-arg",            required_argument, 0, 'x'},
691        {"suspend",              no_argument, 0, 'S'},
692        {"resume",               no_argument, 0, 'R'},
693        {"info",                 no_argument, 0, 'z'},
694                {"inital-down",              no_argument, 0, 'l'},
695                {"monitor",              no_argument, 0, 'M'},
696        {0, 0, 0, 0}
697    };
698    int option_index = 0;
699    int help = 0, _kill = 0, _check = 0, _version = 0, _suspend = 0, _resume = 0, _info = 0;
700   
701    for (;;) {
702        int c;
703       
704        if ((c = getopt_long(argc, argv, "asni:r:t:u:d:hkbfFvm:qwx:cISRzlMW", long_options, &option_index)) < 0)
705            break;
706
707        switch (c) {
708            case 'a' :
709                interface_auto_up = !interface_auto_up;
710                break;
711            case 's' :
712                use_syslog = !use_syslog;
713                break;
714            case 'n' :
715                daemonize = !daemonize;
716                break;
717            case 'i' :
718                                if (interface)
719                                        free(interface);
720                interface = strdup(optarg);
721                break;
722            case 'r':
723                run = strdup(optarg);
724                break;
725            case 'I':
726                ignore_retval = !ignore_retval;
727                break;
728            case 't':
729                polltime = atoi(optarg);
730                if (polltime < 0) polltime = 0;
731                break;
732            case 'u':
733                delay_up = atoi(optarg);
734                break;
735            case 'd':
736                delay_down = atoi(optarg);
737                break;
738            case 'h':
739                help = 1;
740                break;
741            case 'k':
742                _kill = 1;
743                break;
744            case 'c':
745                _check = 1;
746                break;
747            case 'v':
748                _version = 1;
749                break;
750            case 'b':
751                use_beep = !use_beep;
752                break;
753            case 'f':
754                failure_status = IFSTATUS_DOWN;
755                break;
756            case 'F':
757                failure_status = IFSTATUS_UP;
758                break;
759            case 'm':
760                switch (tolower(optarg[0])) {
761                    case 'e': api_mode = API_ETHTOOL; break;
762                    case 'm': api_mode = API_MII; break;
763                    case 'p': api_mode = API_PRIVATE; break;
764                    case 'w': api_mode = API_WLAN; break;
765                    case 'a': api_mode = API_AUTO; break;
766                    default:
767                        daemon_log(LOG_ERR, "Unknown API mode: %s", optarg);
768                        exit(2);
769                }
770                break;
771            case 'q':
772                no_shutdown_script = !no_shutdown_script;
773                break;
774                        case 'l':
775                                initial_down = !initial_down;
776                                break;
777            case 'w':
778                wait_on_fork = !wait_on_fork;
779                break;
780            case 'W':
781                wait_on_kill = !wait_on_kill;
782                break;
783                        case 'x':
784                extra_arg = strdup(optarg);
785                break;
786            case 'S':
787                _suspend = 1;
788                break;
789            case 'R':
790                _resume = 1;
791                break;
792            case 'z':
793                _info = 1;
794                break;
795                        case 'M':
796                                use_ifmonitor = !use_ifmonitor;
797                                break;
798            default:
799                daemon_log(LOG_ERR, "Unknown parameter.");
800                exit(1);
801        }
802    }
803
804
805        if (!interface)
806                interface = strdup("eth0");
807    if (!use_syslog)
808        daemon_log_use = DAEMON_LOG_STDERR;
809   
810
811    if (help) {
812        usage(argv[0]);
813        exit(0);
814    }
815
816    if (_kill || _resume || _suspend || _info) {
817                int rv;
818               
819                if (_kill && wait_on_kill)
820                        rv = daemon_pid_file_kill_wait(SIGINT, 5);
821                else
822                        rv = daemon_pid_file_kill(_kill ? SIGINT : (_resume ? SIGUSR2 : (_info ? SIGHUP : SIGUSR1)));
823
824                if (rv < 0) {
825            daemon_log(LOG_ERR, "Failed to kill daemon. (%s)", strerror(errno));
826            exit(6);
827        }
828
829        exit(0);
830    }
831
832    if (_version) {
833
834#ifdef SVN_REVISION
835        printf("ifplugd "VERSION" (SVN: "SVN_REVISION")\n");
836#else
837        printf("ifplugd "VERSION"\n");
838#endif
839
840        exit(0);
841    }
842
843    if (_check) {
844        pid_t pid = daemon_pid_file_is_running();
845
846        if (pid == (pid_t) -1 || pid == 0) {
847            printf("ifplugd not running.\n");
848                        exit(255);
849                } else {
850            printf("ifplugd process for device %s running as pid %u.\n", interface, pid);
851                        exit(0);
852                }
853    }
854   
855}
856
857static volatile int alarmed = 0;
858
859void sigalrm() {
860    alarmed = 1;
861}
862
863int main(int argc, char* argv[]) {
864
865    daemon_pid_file_proc = pid_file_proc;
866
867    if ((daemon_log_ident = strrchr(argv[0], '/')))
868        daemon_log_ident++;
869    else
870        daemon_log_ident = argv[0];
871
872    parse_args(argc, argv);
873
874    if (geteuid() != 0) {
875        daemon_log(LOG_ERR, "Sorry, you need to be root to run this binary.");
876        return 2;
877    }
878
879        if (daemon_pid_file_is_running() >= 0) {
880        daemon_log(LOG_ERR, "Sorry, there is already an instance of ifplugd for %s running.", interface);
881        return 4;
882    }
883   
884    if (daemonize) {
885        pid_t pid;
886
887        if (wait_on_fork)
888            if (daemon_retval_init() < 0) {
889                daemon_log(LOG_ERR, "Sorry, could not create pipe: %s", strerror(errno));
890                return 4;
891            }
892       
893        if ((pid = daemon_fork()) < 0)
894            return 3;
895
896        if (pid) {
897            int c = 0;
898           
899            // Parent process
900
901            if (wait_on_fork)
902                if ((c = daemon_retval_wait(60)) < 0) {
903                    daemon_log(LOG_WARNING, "Killing background process.");
904                    kill(pid, SIGTERM);
905                }
906           
907                        if (c > 3)
908                                daemon_log(LOG_ERR, "Daemon failed with error condition #%i. See syslog for details", c);
909                       
910            return c;
911        }
912    }
913
914    // Let's go
915    work();
916    return 0;
917}
Note: See TracBrowser for help on using the repository browser.