Skip to content

Commit

Permalink
bug 18172: Remove launchd warnings when running under Mac OS 10.6
Browse files Browse the repository at this point in the history
ipwatchd now takes configuration parameters as -oName=Value arguments.
  • Loading branch information
dleonard committed Sep 25, 2009
1 parent 2a3b886 commit 8d3a67a
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 61 deletions.
13 changes: 0 additions & 13 deletions ipwatchd/com.quest.rc.ipwatchd.plist.in
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,6 @@ com/DTDs/PropertyList-1.0.dtd">

<key>ServiceIPC</key>
<true/>

<key>ChangeProgram</key>
<string>@sbindir@/dnsupdate</string>

<key>GlobalIPv4Key</key>
<string>State:/Network/Global/IPv4</string>

<key>PrimaryIPv4KeyPattern</key>
<string>State:/Network/Service/%/IPv4</string>

<key>ChangeDelay</key>
<real>30</real>

</dict>
</plist>

78 changes: 57 additions & 21 deletions ipwatchd/ipwatchd.8
Original file line number Diff line number Diff line change
Expand Up @@ -5,44 +5,80 @@ ipwatchd \- runs a program when the primary IP address changes
.SH SYNOPSIS
.B ipwatchd
[\-d]
.RI [ ChangeProgram ]
.RI [\-o name = value ]
.RI [ change_program ]
.SH DESCRIPTION
The
.B ipwatchd
daemon watches MacOS X's dynamic System Configuration state for interface
address changes, and runs the given program with the new IP address.
.PP
The
.B ipwatchd
utility is intended to be started by the
This program is intended to be run and managed by the
launchd(8)
daemon.
.SS OPTIONS
.PP
The
.B ipwatch
daemon watches the dynamic store string at
.I State:/Network/Global/IPv4[PrimaryService]
to determine what the current "primary" interface number is
(For example, "0", which is usually en0).
From this it watches the primary service's IP address(es) at
.I State:/Network/Service/$PrimaryService/IPv4[Addresses]
and uses the first IP address as the primary address of the host.
.PP
When the primary IP address change is detected,
.B ipwatchd
then waits for a period of
quiet (the "change delay") before running the
.I change_program
with the new IP address as its first and only argument.
.SH OPTIONS
.TP
.RI \-d
This option
enables debug (verbose) mode
enables debug (verbose) mode.
It is equivalent to
.B \-oDebug=true
.TP
.RI \-o name = value
Sets a configuration option by name as described in the section below.
.TP
.I change_program
This argument is the same as
.BI \-oChangeProgram= change_program
.SS "Configuration Options"
The \-o option can be used to set named options.
Unknown options are ignored.
Known options are:
.TP
.I ChangeProgram
This argument specifies the program to execute.
.RI Debug \ (boolean)
Enables debug messages sent to standard error.
.TP
.RI ChangeProgram \ (string)
The program to execute when the IP address changes.
The executed program is given the new IP address as its first argument.
.PP
If
.B ipwatchd
is run by
.B launchd
and no
.I ChangeProgram
argument is provided, then
.B ipwatchd
will look for and use a string-valued configuration key named ChangeProgram
passed to it by
.BR ipwatchd .
This defaults to /opt/quest/sbin/dnsupdate
.TP
.RI GlobalIPv4Key \ (string)
The name of the IPv4 key in the dynamic store.
Defaults to "State:/Network/Global/IPv4"
.TP
.RI PrimaryIPv4KeyPattern \ (string)
The pattern to use when detecting interfaces.
The "%" character in this string is replaced with the primary service ID.
Defaults to "State:/Network/Service/%/IPv4".
.TP
.RI ChangeDelay \ (float)
The delay in seconds to wait for quiescence after detecting an IP address
and before running the ChangeProgram.
Values of zero or lower are interpreted as meaning immediate application.
Defaults to 30 seconds.
.SH FILES
.I /Library/LaunchDaemons/com.quest.rc.ipwatchd.plist
.SH "SEE ALSO"
dnsupdate(8),
launchd(8),
.I http://rc.vintela.com/topics/ddns/
.SH AUTHORS
David Leonard, Quest Software, Inc.
Quest Software, Inc.
96 changes: 69 additions & 27 deletions ipwatchd/ipwatchd.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,64 @@ static CFStringRef PrimaryService = NULL; /* "0" */
static CFStringRef PrimaryIPv4Key = NULL; /* "State:/Network/Service/0/IPv4" */
static CFStringRef PrimaryAddress = NULL; /* "1.2.3.4" */

static int
to_boolean(const char *s)
{
if (strcasecmp(s, "true") == 0 ||
strcasecmp(s, "on") == 0 ||
strcasecmp(s, "yes") == 0)
return TRUE;
if (strcasecmp(s, "false") == 0 ||
strcasecmp(s, "off") == 0 ||
strcasecmp(s, "no"))
return FALSE;
warnx("unknown boolean '%.100s'", s);
return FALSE;
}

/* Sets an option named name to the value. Returns TRUE on success */
static int
set_option(const char *name, const char *value)
{
if (debug)
fprintf(stderr, "set_option %s = %s\n", name, value);
if (strcmp(name, "ChangeProgram") == 0)
ChangeProgram = value;
else if (strcmp(name, "GlobalIPv4Key") == 0)
GlobalIPv4Key = value;
else if (strcmp(name, "PrimaryIPv4KeyPattern") == 0)
PrimaryIPv4KeyPattern = value;
else if (strcmp(name, "ChangeDelay") == 0)
ChangeDelay = atof(value);
else if (strcmp(name, "Debug") == 0)
debug = to_boolean(value);
else
warnx("ignoring unknown option '%.100s'", name);
return TRUE;
}

/* Split the "name=value" string on the first '=' and set the option */
static int
set_option_from_arg(const char *arg)
{
char opt_name[100];
int i;

/* Copy the beginning of arg up to the '=' into opt_name[] */
for (i = 0; arg[i] != '='; i++) {
if (arg[i] == 0) {
warnx("missing '=' in -o argument '%.100s'", arg);
return FALSE;
}
if (i >= sizeof opt_name - 1) {
warnx("option name too long");
return FALSE;
}
opt_name[i] = arg[i];
}
opt_name[i] = 0;
return set_option(opt_name, arg + i);
}

int
main(int argc, char * const argv[])
Expand All @@ -64,22 +122,28 @@ main(int argc, char * const argv[])
extern int optind;
CFStringRef key;

while ((ch = getopt(argc, argv, "d")) != -1)
while ((ch = getopt(argc, argv, "do:")) != -1)
switch (ch) {
case 'd':
debug = TRUE;
set_option("Debug", "true");
break;
case 'o':
if (!set_option_from_arg(optarg))
error = 1;
break;
case '?':
error = 1;
break;
}
if (optind < argc)
ChangeProgram = argv[optind++];
set_option("ChangeProgram", argv[optind++]);

if (optind < argc)
error = 1;
if (error) {
fprintf(stderr, "usage: %s [-d] [ChangeProgram]\n", argv[0]);
fprintf(stderr,
"usage: %s [-d] [-o opt=value] [ChangeProgram]\n",
argv[0]);
exit(1);
}

Expand Down Expand Up @@ -147,7 +211,7 @@ checkin()
}

if (!(response = launch_msg(checkin))) {
warnx("launch_msg");
warn("launch_msg");
return;
}
if (launch_data_get_type(response) == LAUNCH_DATA_ERRNO) {
Expand All @@ -159,28 +223,6 @@ checkin()
warnx("launch check-in failed: bad response");
return;
}

/* Extract the configuration parameters */

param = launch_data_dict_lookup(response, "Debug");
if (param && !debug)
debug = launch_data_get_bool(param);

param = launch_data_dict_lookup(response, "ChangeProgram");
if (param && !ChangeProgram)
ChangeProgram = launch_data_get_string(param);

param = launch_data_dict_lookup(response, "GlobalIPv4Key");
if (param && !GlobalIPv4Key)
GlobalIPv4Key = launch_data_get_string(param);

param = launch_data_dict_lookup(response, "PrimaryIPv4KeyPattern");
if (param && !PrimaryIPv4KeyPattern)
PrimaryIPv4KeyPattern = launch_data_get_string(param);

param = launch_data_dict_lookup(response, "ChangeDelay");
if (param && ChangeDelay < 0)
ChangeDelay = launch_data_get_real(param);
}

/* Returns true if two string pointers are either both NULL, or the same text.
Expand Down

0 comments on commit 8d3a67a

Please sign in to comment.