which makes the binary a few k smaller.
Support OpenNTP as well as NTP.
Re-work the state engine a little, so we renew and rebind correctly.
Subsequent debug options stop dhcpcd from daemonising.
+You can now build dhcpcd without support for writing ntp, nis and info files
+which makes the binary a few k smaller.
+Support OpenNTP as well as NTP.
+Re-work the state engine a little, so we renew and rebind correctly.
+Subsequent debug options stop dhcpcd from daemonising.
When we get an invalid length for a DHCP option, try and continue anyway.
When MTU is less than 576 we now ignore it instead of setting the MTU to 576.
Build correctly on dietlibc, thanks to d00mer.
# Should work for both GNU make and BSD make
-VERSION = 3.0.16
+VERSION = 3.0.17_pre2
CFLAGS ?= -O2 -pipe
# IMPORTANT: We should be using c99 instead of gnu99 but for some reason
# generic linux headers as of 2.6.19 don't allow this in asm/types.h
CFLAGS += -pedantic -std=gnu99 \
- -Wall -Wunused -Wimplicit -Wshadow -Wformat=2 \
+ -Wall -Wextra -Wunused -Wimplicit -Wshadow -Wformat=2 \
-Wmissing-declarations -Wno-missing-prototypes -Wwrite-strings \
-Wbad-function-cast -Wnested-externs -Wcomment -Winline \
-Wchar-subscripts -Wcast-align -Wno-format-nonliteral
#include <sys/types.h>
#include <sys/select.h>
-#include <sys/wait.h>
#include <arpa/inet.h>
#ifdef __linux__
#include <netinet/ether.h>
send_message (iface, dhcp, xid, _type, options); \
}
+#define DROP_CONFIG \
+{ \
+ memset (&dhcp->address, 0, sizeof (struct in_addr)); \
+ if (iface->previous_address.s_addr != 0 && ! options->persistent) \
+ configure (options, iface, dhcp); \
+ free_dhcp (dhcp); \
+ memset (dhcp, 0, sizeof (dhcp_t)); \
+}
+
static int daemonise (const char *pidfile)
{
logger (LOG_DEBUG, "forking to background");
{
switch (sig)
{
- case SIGCHLD:
- /* Silently ignore this signal and wait for it
- This stops zombies */
- wait (0);
break;
case SIGINT:
logger (LOG_INFO, "received SIGINT, stopping");
xid = 0;
SOCKET_MODE (SOCKET_CLOSED);
if (! options->persistent)
- {
- free_dhcp (dhcp);
- memset (dhcp, 0, sizeof (dhcp_t));
- configure (options, iface, dhcp);
- }
- if (! daemonised)
- {
- retval = -1;
- goto eexit;
- }
- break;
+ DROP_CONFIG;
}
if (xid == 0)
break;
case STATE_REBINDING:
logger (LOG_ERR, "lost lease, attemping to rebind");
+ memset (&dhcp->address, 0, sizeof (struct in_addr));
SOCKET_MODE (SOCKET_OPEN);
- SEND_MESSAGE (DHCP_DISCOVER);
+ SEND_MESSAGE (DHCP_REQUEST);
timeout = dhcp->leasetime - dhcp->rebindtime;
- state = STATE_INIT;
+ state = STATE_REQUESTING;
break;
case STATE_REQUESTING:
- logger (LOG_ERR, "timed out");
- if (! daemonised)
+ if (iface->previous_address.s_addr != 0)
+ logger (LOG_ERR, "lost lease");
+ else
+ logger (LOG_ERR, "timed out");
+ if (! daemonised && options->daemonise)
goto eexit;
state = STATE_INIT;
SOCKET_MODE (SOCKET_CLOSED);
timeout = 0;
xid = 0;
- free_dhcp (dhcp);
- memset (dhcp, 0, sizeof (dhcp_t));
+ DROP_CONFIG;
break;
case STATE_RELEASED:
if (xid != message.xid)
{
logger (LOG_ERR,
- "ignoring packet with xid %d as it's not ours (%d)",
+ "ignoring packet with xid 0x%x as it's not ours (0x%x)",
message.xid, xid);
continue;
}
- logger (LOG_DEBUG, "got a packet with xid %d", message.xid);
+ logger (LOG_DEBUG, "got a packet with xid 0x%x", message.xid);
memset (new_dhcp, 0, sizeof (dhcp_t));
if ((type = parse_dhcpmessage (new_dhcp, &message)) < 0)
{
state = STATE_INIT;
timeout = 0;
xid = 0;
- free_dhcp (dhcp);
- memset (dhcp, 0, sizeof (dhcp_t));
- configure (options, iface, dhcp);
+ DROP_CONFIG;
continue;
}
SOCKET_MODE (SOCKET_OPEN);
SEND_MESSAGE (DHCP_DECLINE);
SOCKET_MODE (SOCKET_CLOSED);
-
- free_dhcp (dhcp);
- memset (dhcp, 0, sizeof (dhcp_t));
-
- if (daemonised)
- configure (options, iface, dhcp);
+ DROP_CONFIG;
xid = 0;
timeout = 0;
goto eexit;
}
- if (! daemonised)
+ if (! daemonised && options->daemonise)
{
if ((daemonise (options->pidfile)) < 0 )
{
eexit:
SOCKET_MODE (SOCKET_CLOSED);
-
- /* Remove our config if we need to */
- free_dhcp (dhcp);
- memset (dhcp, 0, sizeof (dhcp_t));
- if (iface->previous_address.s_addr != 0 && ! options->persistent && daemonised)
- configure (options, iface, dhcp);
+ DROP_CONFIG;
free (dhcp);
if (iface)
#include "logger.h"
#include "socket.h"
-static char *cleanmetas (const char *cstr)
-{
- /* The largest single element we can have is 256 bytes according to the RFC,
- so this buffer size should be safe even if it's all ' */
- static char buffer[1024];
- char *b = buffer;
-
- memset (buffer, 0, sizeof (buffer));
- if (cstr == NULL || strlen (cstr) == 0)
- return b;
-
- do
- if (*cstr == 39)
- {
- *b++ = '\'';
- *b++ = '\\';
- *b++ = '\'';
- *b++ = '\'';
- }
- else
- *b++ = *cstr;
- while (*cstr++);
-
- *b++ = 0;
- b = buffer;
-
- return b;
-}
/* IMPORTANT: Ensure that the last parameter is NULL when calling */
static int exec_cmd (const char *cmd, const char *args, ...)
if ((pid = fork ()) == 0)
{
- if (execve (cmd, argv, NULL) && errno != ENOENT)
+ if (execv (cmd, argv) && errno != ENOENT)
logger (LOG_ERR, "error executing \"%s\": %s",
cmd, strerror (errno));
exit (0);
{
struct stat buf;
+#ifdef ENABLE_INFO
if (! script || ! infofile || ! arg)
return;
+#else
+ if (! script || ! arg)
+ return ;
+#endif
if (stat (script, &buf) < 0)
{
return;
}
+#ifdef ENABLE_INFO
logger (LOG_DEBUG, "exec \"%s %s %s\"", script, infofile, arg);
exec_cmd (script, infofile, arg, NULL);
+#else
+ logger (LOG_DEBUG, "exec \"%s \"\" %s\"", script, infofile, arg);
+ exec_cmd (script, infofile, "", arg, NULL);
+#endif
}
static int make_resolv (const char *ifname, const dhcp_t *dhcp)
char resolvconf[PATH_MAX] = {0};
address_t *address;
+#ifdef RESOLVCONF
if (stat (RESOLVCONF, &buf) == 0)
{
logger (LOG_DEBUG, "sending DNS information to resolvconf");
logger (LOG_ERR, "popen: %s", strerror (errno));
}
else
+#endif
{
logger (LOG_DEBUG, "writing "RESOLVFILE);
if (! (f = fopen(RESOLVFILE, "w")))
static void restore_resolv(const char *ifname)
{
+#ifdef RESOLVCONF
struct stat buf;
if (stat (RESOLVCONF, &buf) < 0)
logger (LOG_DEBUG, "removing information from resolvconf");
exec_cmd (RESOLVCONF, "-d", ifname, NULL);
+#endif
}
-static int make_ntp (const char *ifname, const dhcp_t *dhcp)
+#ifdef ENABLE_NTP
+static int _make_ntp (const char *file, const char *ifname, const dhcp_t *dhcp)
{
FILE *f;
address_t *address;
char buffer[1024];
int tomatch = 0;
char *token;
+ bool ntp = false;
for (address = dhcp->ntpservers; address; address = address->next)
tomatch++;
/* Check that we really need to update the servers
We do this because ntp has to be restarted to work with a changed config */
- if (! (f = fopen(NTPFILE, "r")))
+ if (! (f = fopen (file, "r")))
{
if (errno != ENOENT)
{
- logger (LOG_ERR, "fopen `%s': %s", NTPFILE, strerror (errno));
+ logger (LOG_ERR, "fopen `%s': %s", file, strerror (errno));
return -1;
}
}
/* File has the same name servers that we do, so no need to restart ntp */
if (tomatch == 0)
{
- logger (LOG_DEBUG, "ntp already configured, skipping");
+ logger (LOG_DEBUG, "%s already configured, skipping", file);
return 0;
}
}
- logger (LOG_DEBUG, "writing "NTPFILE);
- if (! (f = fopen(NTPFILE, "w")))
+ logger (LOG_DEBUG, "writing %s", file);
+ if (! (f = fopen (file, "w")))
{
- logger (LOG_ERR, "fopen `%s': %s", NTPFILE, strerror (errno));
+ logger (LOG_ERR, "fopen `%s': %s", file, strerror (errno));
return -1;
}
fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname);
- fprintf (f, "restrict default noquery notrust nomodify\n");
- fprintf (f, "restrict 127.0.0.1\n");
+#ifdef NTPFILE
+ if (strcmp (file, NTPFILE) == 0)
+ {
+ ntp = true;
+ fprintf (f, "restrict default noquery notrust nomodify\n");
+ fprintf (f, "restrict 127.0.0.1\n");
+ }
+#endif
for (address = dhcp->ntpservers; address; address = address->next)
{
a = inet_ntoa (address->address);
- fprintf (f, "restrict %s nomodify notrap noquery\nserver %s\n", a, a);
+ if (ntp)
+ fprintf (f, "restrict %s nomodify notrap noquery\n", a);
+ fprintf (f, "server %s\n", a);
}
- fprintf (f, "driftfile " NTPDRIFTFILE "\n");
- fprintf (f, "logfile " NTPLOGFILE "\n");
+ if (ntp)
+ {
+ fprintf (f, "driftfile " NTPDRIFTFILE "\n");
+ fprintf (f, "logfile " NTPLOGFILE "\n");
+ }
fclose (f);
- exec_cmd (NTPSERVICE, NTPRESTARTARGS, NULL);
- return 0;
+ return 1;
+}
+
+static int make_ntp (const char *ifname, const dhcp_t *dhcp)
+{
+ /* On some systems we have only have one ntp service, but we don't know
+ which configuration file we're using. So we need to write to both and
+ restart accordingly. */
+
+ bool restart_ntp = false;
+ bool restart_openntp = false;
+ int retval = 0;
+
+#ifdef NTPFILE
+ if (_make_ntp (NTPFILE, ifname, dhcp) > 0)
+ restart_ntp = true;
+#endif
+
+#ifdef OPENNTPFILE
+ if (_make_ntp (OPENNTPFILE, ifname, dhcp) > 0)
+ restart_openntp = true;
+#endif
+
+#ifdef NTPSERVICE
+ if (restart_ntp)
+ retval += exec_cmd (NTPSERVICE, NTPRESTARTARGS, NULL);
+#endif
+
+#if defined (NTPSERVICE) && defined (OPENNTPSERVICE)
+ if (restart_openntp &&
+ (strcmp (NTPSERVICE, OPENNTPSERVICE) != 0 || ! restart_ntp))
+ retval += exec_cmd (OPENNTPSERVICE, OPENNTPRESTARTARGS, NULL);
+#elif defined (OPENNTPSERVICE) && ! defined (NTPSERVICE)
+ if (restart_openntp)
+ retval += exec_cmd (OPENNTPSERVICE, OPENNTPRESTARTARGS, NULL);
+#endif
+
+ return retval;
}
+#endif
+#ifdef ENABLE_NIS
static int make_nis (const char *ifname, const dhcp_t *dhcp)
{
FILE *f;
exec_cmd (NISSERVICE, NISRESTARTARGS, NULL);
return 0;
}
+#endif
+
+#ifdef ENABLE_INFO
+static char *cleanmetas (const char *cstr)
+{
+ /* The largest single element we can have is 256 bytes according to the RFC,
+ so this buffer size should be safe even if it's all ' */
+ static char buffer[1024];
+ char *b = buffer;
+
+ memset (buffer, 0, sizeof (buffer));
+ if (cstr == NULL || strlen (cstr) == 0)
+ return b;
+
+ do
+ if (*cstr == 39)
+ {
+ *b++ = '\'';
+ *b++ = '\\';
+ *b++ = '\'';
+ *b++ = '\'';
+ }
+ else
+ *b++ = *cstr;
+ while (*cstr++);
+
+ *b++ = 0;
+ b = buffer;
+
+ return b;
+}
static int write_info(const interface_t *iface, const dhcp_t *dhcp,
const options_t *options)
fclose (f);
return 0;
}
+#endif
int configure (const options_t *options, interface_t *iface,
const dhcp_t *dhcp)
else
logger (LOG_DEBUG, "no dns information to write");
+#ifdef ENABLE_NTP
if (options->dontp && dhcp->ntpservers)
make_ntp(iface->name, dhcp);
+#endif
+#ifdef ENABLE_NIS
if (options->donis && (dhcp->nisservers || dhcp->nisdomain))
make_nis(iface->name, dhcp);
+#endif
/* Now we have made a resolv.conf we can obtain a hostname if we need one */
if (options->dohostname && ! dhcp->hostname)
}
}
+#ifdef ENABLE_INFO
write_info (iface, dhcp, options);
+#endif
if (iface->previous_address.s_addr != dhcp->address.s_addr ||
iface->previous_netmask.s_addr != dhcp->netmask.s_addr)
#ifndef DHCPCONFIG_H
#define DHCPCONFIG_H
+/* If you disable all 3 options you can shrink the binary by around 5-10k
+ unstripped depending on platform and CFLAGS
+*/
+#define ENABLE_NTP
+#define ENABLE_NIS
+#define ENABLE_INFO
+
#include "dhcpcd.h"
#include "interface.h"
#include "dhcp.h"
memset (&message, 0, sizeof (dhcpmessage_t));
- if (iface->previous_address.s_addr != 0
- && (type == DHCP_INFORM || type == DHCP_RELEASE
- || (type == DHCP_REQUEST
- && iface->previous_address.s_addr == dhcp->address.s_addr)))
+ if (type == DHCP_INFORM ||
+ type == DHCP_RELEASE ||
+ type == DHCP_REQUEST)
{
message.ciaddr = iface->previous_address.s_addr;
from.s_addr = iface->previous_address.s_addr;
make_dhcp_packet (&packet, (unsigned char *) &message, message_length,
from, to);
- logger (LOG_DEBUG, "sending %s with xid %d", dhcp_message[(int) type], xid);
+ logger (LOG_DEBUG, "sending %s with xid 0x%x", dhcp_message[(int) type], xid);
return send_packet (iface, ETHERTYPE_IP, (unsigned char *) &packet,
message_length + sizeof (struct ip) +
sizeof (struct udphdr));
.TP
.BI \-d
Echos debugging and information messages to the console.
+Subsequent debug options stop \fBdhcpcd\fR from daemonising.
.TP
.BI \-h \ hostname
specifies a string used for the hostname option field when
int option_index = 0;
char prefix[IF_NAMESIZE + 3];
pid_t pid;
+ int debug = 0;
const struct option longopts[] =
{
options.donis = true;
options.dontp = true;
options.dogateway = true;
+ options.daemonise = true;
gethostname (options.hostname, sizeof (options.hostname));
if (strcmp (options.hostname, "(none)") == 0 ||
strcmp (options.hostname, "localhost") == 0)
options.script = optarg;
break;
case 'd':
- setloglevel(LOG_DEBUG);
+ debug++;
+ switch (debug)
+ {
+ case 1:
+ setloglevel(LOG_DEBUG);
+ break;
+ case 2:
+ options.daemonise = false;
+ break;
+ }
break;
case 'h':
if (strlen (optarg) > HOSTNAME_MAX_LEN)
{
- logger(LOG_ERR, "`%s' too long for HostName string, max is %d",
+ logger (LOG_ERR, "`%s' too long for HostName string, max is %d",
optarg, HOSTNAME_MAX_LEN);
exit (EXIT_FAILURE);
}
strcpy (options.hostname, optarg);
break;
case 'i':
- if (strlen(optarg) > CLASS_ID_MAX_LEN)
+ if (strlen (optarg) > CLASS_ID_MAX_LEN)
{
logger (LOG_ERR, "`%s' too long for ClassID string, max is %d",
optarg, CLASS_ID_MAX_LEN);
exit (EXIT_FAILURE);
}
else
- sprintf(options.classid, "%s", optarg);
+ sprintf (options.classid, "%s", optarg);
break;
case 'k':
options.signal = SIGHUP;
}
break;
case 'm':
- STRINGINT(optarg, options.metric);
+ STRINGINT (optarg, options.metric);
break;
case 'n':
options.signal = SIGALRM;
bool dodomainname;
int signal;
bool persistent;
+ bool daemonise;
char *script;
char pidfile[PATH_MAX];
#define NTPSERVICE ETCDIR "/init.d/ntpd"
#define NTPRESTARTARGS "--quiet", "conditionalrestart"
+#define OPENNTPFILE ETCDIR "/ntpd.conf"
+#define OPENNTPSERVICE ETCDIR "/init.d/ntpd"
+#define OPENNTPRESTARTARGS "--quiet", "conditionalrestart"
+
#define DEFAULT_SCRIPT ETCDIR "/" PACKAGE ".sh"
#define STATEDIR "/var"
#include <sys/socket.h>
#include <sys/select.h>
+#include <sys/wait.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
static void signal_handler (int sig)
{
+ /* Silently ignore this signal and wait for it. This stops zombies.
+ We do this here instead of client.c so that we don't spam the log file
+ with "waiting on select messages" */
+ if (sig == SIGCHLD)
+ {
+ wait (0);
+ return;
+ }
+
if (send (signal_pipe[1], &sig, sizeof (sig), MSG_DONTWAIT) < 0)
logger (LOG_ERR, "Could not send signal: %s", strerror (errno));
}