Add support to call scripts at carrier detect/drop time (on network

interfaces that report this).
Basically from Brian Grayson, fixes his PR bin/23191.
This commit is contained in:
martin 2004-01-04 22:19:51 +00:00
parent 710460b874
commit 06eb7200cc
2 changed files with 125 additions and 21 deletions

View File

@ -1,4 +1,4 @@
.\" $NetBSD: ifwatchd.8,v 1.19 2003/07/04 12:48:30 wiz Exp $
.\" $NetBSD: ifwatchd.8,v 1.20 2004/01/04 22:19:51 martin Exp $
.\"
.\" Copyright (c) 2001-2003 The NetBSD Foundation, Inc.
.\" All rights reserved.
@ -34,7 +34,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd March 5, 2003
.Dd January 4, 2004
.Os
.Dt IFWATCHD 8
.Sh NAME
@ -47,11 +47,14 @@
.Op Fl D Ar departure-script
.Op Fl d Ar down-script
.Op Fl u Ar up-script
.Op Fl c Ar carrier-script
.Op Fl n Ar no-carrier-script
.Ar ifname(s)
.Sh DESCRIPTION
.Nm
is used to monitor dynamic interfaces (for example PPP interfaces)
for address changes.
for address changes, and to monitor static interfaces for carrier
changes.
Sometimes these interfaces are accompanied by a daemon program,
which can take care of running any necessary scripts (like
.Xr pppd 8
@ -61,13 +64,15 @@ but sometimes the interfaces run completely autonomously (like
.Xr pppoe 4 ) .
.Pp
.Nm
provides a generic way to watch this type of changes.
provides a generic way to watch these types of changes.
It works by monitoring the routing socket and interpreting
.Ql RTM_NEWADDR
.Pq address added
and
.Pq address added ,
.Ql RTM_DELADDR
.Pq address deleted
and
.Ql RTM_IFINFO
.Pq carrier detect or loss of carrier
messages.
It does not need special privileges to do this.
The scripts called for up or down events are run with the same user
@ -80,6 +85,9 @@ The following options are available:
.It Fl A Ar arrival-script
Specify the command to invoke on arrival of new interfaces (like
PCMCIA cards).
.It Fl c Ar carrier-script
Specify the command to invoke when the carrier status transitions from
no carrier to carrier.
.It Fl D Ar departure-script
Specify the command to invoke when an interface departs (for example
a PCMCIA card is removed.)
@ -105,12 +113,11 @@ By default
.Nm
calls them on startup to account for this (and make the scripts
easier.)
.It Fl n Ar no-carrier-script
Specify the command to invoke when the carrier status transitions from
carrier to no carrier.
.It Fl q
Be quiet and don't log non-error messages to syslog.
.It Ar ifname(s)
The name of the interface to watch.
Multiple interfaces may be specified.
Events for other interfaces are ignored.
.It Fl u Ar up-script
Specify the command to invoke on
.Dq interface up
@ -120,11 +127,12 @@ Run in verbose debug mode and do not detach from the controlling
terminal.
Output verbose progress messages and flag errors ignored during
normal operation.
Adding more
.Fl v
increases the verbosity.
.Em You do not want to use this option in
.Pa /etc/rc.conf !
.It Ar ifname(s)
The name of the interface to watch.
Multiple interfaces may be specified.
Events for other interfaces are ignored.
.El
.Sh EXAMPLES
.Bd -literal -offset indent
@ -159,6 +167,33 @@ Use
in your
.Pa /etc/ifconfig.pppoe0
file in the on-demand case.
.Pp
The next example is for dhclient users.
.Bd -literal -offset indent
# ifwatchd -i -c /etc/dhcp/carrier-detect tlp0
.Ed
.Pp
With the above command, the carrier-detect script will be invoked when
a carrier is detected on the interface
.Ar tlp0 .
Note that the
.Ar -i
flag prevents any action based on the initial state.
A script like the following should work for most users, although it
will not work for machines with multiple interfaces running
.Cm dhclient .
.Bd -literal -offset indent
#! /bin/sh
# Arguments: ifname tty speed address destination
# If there is a dhclient already running, kill it.
# (This step could be put in a distinct no-carrier script,
# if desired.)
if [ -f /var/run/dhclient.pid ]; then
/bin/kill `/bin/cat /var/run/dhclient.pid`
fi
# Start dhclient again on this interface
/sbin/dhclient $1
.Ed
.Sh PARAMETERS PASSED TO SCRIPTS
The invoked scripts get passed these parameters:
.Bl -tag -width destination

View File

@ -1,4 +1,4 @@
/* $NetBSD: ifwatchd.c,v 1.18 2003/12/27 00:05:46 martin Exp $ */
/* $NetBSD: ifwatchd.c,v 1.19 2004/01/04 22:19:51 martin Exp $ */
/*-
* Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
@ -66,7 +66,8 @@
#include <ifaddrs.h>
#include <syslog.h>
enum event { ARRIVAL, DEPARTURE, UP, DOWN };
enum event { ARRIVAL, DEPARTURE, UP, DOWN, CARRIER, NO_CARRIER };
/* local functions */
static void usage(void);
static void dispatch(void*, size_t);
@ -74,6 +75,7 @@ static void check_addrs(char *cp, int addrs, enum event ev);
static void invoke_script(struct sockaddr *sa, struct sockaddr *dst, enum event ev, int ifindex, const char *ifname_hint);
static void list_interfaces(const char *ifnames);
static void check_announce(struct if_announcemsghdr *ifan);
static void check_carrier(int if_index, int carrier);
static void rescan_interfaces(void);
static void free_interfaces(void);
static int find_interface(int index);
@ -100,18 +102,23 @@ static const char *arrival_script = NULL;
static const char *departure_script = NULL;
static const char *up_script = NULL;
static const char *down_script = NULL;
static char DummyTTY[] = _PATH_DEVNULL;
static char DummySpeed[] = "9600";
static const char *carrier_script = NULL;
static const char *no_carrier_script = NULL;
static const char DummyTTY[] = _PATH_DEVNULL;
static const char DummySpeed[] = "9600";
static const char **scripts[] = {
&arrival_script,
&departure_script,
&up_script,
&down_script
&down_script,
&carrier_script,
&no_carrier_script
};
struct interface_data {
SLIST_ENTRY(interface_data) next;
int index;
int last_carrier_status;
char * ifname;
};
SLIST_HEAD(,interface_data) ifs = SLIST_HEAD_INITIALIZER(ifs);
@ -124,21 +131,32 @@ main(int argc, char **argv)
char msg[2048], *msgp;
openlog(argv[0], LOG_PID|LOG_CONS, LOG_DAEMON);
while ((c = getopt(argc, argv, "qvhiu:d:A:D:")) != -1)
while ((c = getopt(argc, argv, "qvhic:n:u:d:A:D:")) != -1)
switch (c) {
case 'h':
usage();
return 0;
case 'i':
inhibit_initial = 1;
break;
case 'v':
verbose++;
break;
case 'q':
quiet = 1;
break;
case 'c':
carrier_script = optarg;
break;
case 'n':
no_carrier_script = optarg;
break;
case 'u':
up_script = optarg;
break;
@ -174,6 +192,8 @@ main(int argc, char **argv)
up_script, down_script);
printf("arrival_script: %s\ndeparture_script: %s\n",
arrival_script, departure_script);
printf("carrier_script: %s\nno_carrier_script: %s\n",
carrier_script, no_carrier_script);
printf("verbosity = %d\n", verbose);
}
@ -218,11 +238,14 @@ usage()
fprintf(stderr,
"usage:\n"
"\tifwatchd [-hiqv] [-A arrival-script] [-D departure-script]\n"
"\t\t [-d down-script] [-u up-script] ifname(s)\n"
"\t\t [-d down-script] [-u up-script]\n"
"\t\t [-c carrier-script] [-n no-carrier-script] ifname(s)\n"
"\twhere:\n"
"\t -A <cmd> specify command to run on interface arrival event\n"
"\t -c <cmd> specify command to run on interface carrier-detect event\n"
"\t -D <cmd> specify command to run on interface departure event\n"
"\t -d <cmd> specify command to run on interface down event\n"
"\t -n <cmd> specify command to run on interface no-carrier-detect event\n"
"\t -h show this help message\n"
"\t -i no (!) initial run of the up script if the interface\n"
"\t is already up on ifwatchd startup\n"
@ -236,6 +259,7 @@ static void
dispatch(void *msg, size_t len)
{
struct rt_msghdr *hd = msg;
struct if_msghdr *ifmp;
struct ifa_msghdr *ifam;
enum event ev;
@ -250,6 +274,10 @@ dispatch(void *msg, size_t len)
rescan_interfaces();
check_announce((struct if_announcemsghdr *)msg);
return;
case RTM_IFINFO:
ifmp = (struct if_msghdr*)msg;
check_carrier(ifmp->ifm_index, ifmp->ifm_data.ifi_link_state);
return;
}
if (verbose)
printf("unknown message ignored\n");
@ -380,7 +408,8 @@ invoke_script(sa, dest, ev, ifindex, ifname_hint)
}
}
static void list_interfaces(const char *ifnames)
static void
list_interfaces(const char *ifnames)
{
char * names = strdup(ifnames);
char * name, *lasts;
@ -392,6 +421,7 @@ static void list_interfaces(const char *ifnames)
name = strtok_r(NULL, sep, &lasts)) {
p = malloc(sizeof(*p));
SLIST_INSERT_HEAD(&ifs, p, next);
p->last_carrier_status = -1;
p->ifname = strdup(name);
p->index = if_nametoindex(p->ifname);
if (!quiet)
@ -403,6 +433,45 @@ static void list_interfaces(const char *ifnames)
free(names);
}
static void
check_carrier(int if_index, int carrier_status)
{
struct interface_data * p;
enum event ev;
SLIST_FOREACH(p, &ifs, next)
if (p->index == if_index)
break;
if (p == NULL)
return;
/*
* Treat it as an event worth handling if:
* - the carrier status changed, or
* - this is the first time we've been called, and
* inhibit_initial is not set
*/
if ((carrier_status != p->last_carrier_status) ||
((p->last_carrier_status == -1) && !inhibit_initial)) {
switch (carrier_status) {
case LINK_STATE_UP:
ev = CARRIER;
break;
case LINK_STATE_DOWN:
ev = NO_CARRIER;
break;
default:
if (verbose)
printf("unknown link status ignored\n");
return;
}
invoke_script(NULL, NULL, ev, if_index, p->ifname);
p->last_carrier_status = carrier_status;
}
}
static void
check_announce(struct if_announcemsghdr *ifan)
{