[BusyBox] udhcpc troubles

Ilguiz Latypov ilatypov at superbt.com
Tue Jul 16 08:56:03 UTC 2002


Please ignore the rest if your embedded platform's CPU has MMU.

I didn't have a chance to try udhcp client/server application or
user/dhcpcd module from uClinux distribution.  I managed to get the
non-embedded client dhcpcd work by hacking its code.

I changed the code to emulate the daemon mode by automatic restart of the
executable file.  This is a dangerous technique as the data segment will
not be the same in two processes.  With dhcpcd this was luckily
circumvented because the code implements a state machine.

If you want to try dhcpcd, download it from
http://www.phystech.com/download/, apply the attached patch and run

    aclocal && automake && autoconf
    ./configure --host=YOUR_TARGET_HOST_STRING \
                --build=i686-pc-linux-gnu --with-kernel=YOUR_KERNEL
    make

Ilguiz

On Tue, 16 Jul 2002, Michael Hauser wrote:

> If i start the client the first client process terminates and a second
> client process starts immimmediately.

========================================================================
Index: client.c
===================================================================
RCS file: /usr/local/cvsroot/user/dhcpcd/client.c,v
retrieving revision 1.1.1.1
retrieving revision 1.3
diff -u -r1.1.1.1 -r1.3
--- client.c	14 Apr 2002 07:07:20 -0000	1.1.1.1
+++ client.c	21 Apr 2002 04:57:16 -0000	1.3
@@ -49,6 +49,7 @@
 #include "buildmsg.h"
 #include "udpipgen.h"
 #include "pathnames.h"
+#include "config.h"
 
 #include <linux/version.h>
 
@@ -148,10 +149,10 @@
 	        {
 		  DhcpOptions.len[*p] = p[1];
 	          if ( DhcpOptions.val[*p] )
-	            free(DhcpOptions.val[*p]);
+	            xfree(DhcpOptions.val[*p]);
 	      	  else
 		    DhcpOptions.num++;
-	      	  DhcpOptions.val[*p] = malloc(p[1]+1);
+	      	  DhcpOptions.val[*p] = xmalloc(p[1]+1);
 		  memset(DhcpOptions.val[*p],0,p[1]+1);
 	  	  memcpy(DhcpOptions.val[*p],p+2,p[1]);
 	        }
@@ -233,7 +234,7 @@
   if ( ! DhcpMsgRecv->yiaddr ) DhcpMsgRecv->yiaddr=DhcpMsgSend->ciaddr;
   if ( ! DhcpOptions.val[dhcpServerIdentifier] ) /* did not get dhcpServerIdentifier */
     {	/* make it the same as IP address of the sender */
-      DhcpOptions.val[dhcpServerIdentifier] = malloc(4);
+      DhcpOptions.val[dhcpServerIdentifier] = xmalloc(4);
       memcpy(DhcpOptions.val[dhcpServerIdentifier],&ipRecv->ip_src.s_addr,4);
       DhcpOptions.len[dhcpServerIdentifier] = 4;
       DhcpOptions.num++;
@@ -247,7 +248,7 @@
     }
   if ( ! DhcpOptions.val[dns] ) /* did not get DNS */
     {	/* make it the same as dhcpServerIdentifier */
-      DhcpOptions.val[dns] = malloc(4);
+      DhcpOptions.val[dns] = xmalloc(4);
       memcpy(DhcpOptions.val[dns],DhcpOptions.val[dhcpServerIdentifier],4);
       DhcpOptions.len[dns] = 4;
       DhcpOptions.num++;
@@ -261,7 +262,7 @@
     }
   if ( ! DhcpOptions.val[subnetMask] ) /* did not get subnetMask */
     {
-      DhcpOptions.val[subnetMask] = malloc(4);
+      DhcpOptions.val[subnetMask] = xmalloc(4);
       ((unsigned char *)DhcpOptions.val[subnetMask])[0] = 255;
       if ( ((unsigned char *)&DhcpMsgRecv->yiaddr)[0] < 128 )
 	{
@@ -290,7 +291,7 @@
   if ( ! DhcpOptions.val[broadcastAddr] ) /* did not get broadcastAddr */
     {
       int br = DhcpMsgRecv->yiaddr | ~*((int *)DhcpOptions.val[subnetMask]);
-      DhcpOptions.val[broadcastAddr] = malloc(4);
+      DhcpOptions.val[broadcastAddr] = xmalloc(4);
       memcpy(DhcpOptions.val[broadcastAddr],&br,4);
       DhcpOptions.len[broadcastAddr] = 4;
       DhcpOptions.num++;
@@ -305,7 +306,7 @@
 #if 0
   if ( ! DhcpOptions.val[routersOnSubnet] )
     {
-      DhcpOptions.val[routersOnSubnet] = malloc(4);
+      DhcpOptions.val[routersOnSubnet] = xmalloc(4);
       if ( DhcpMsgRecv->giaddr )
       	memcpy(DhcpOptions.val[routersOnSubnet],&DhcpMsgRecv->giaddr,4);
       else
@@ -332,7 +333,7 @@
     }
   else /* did not get dhcpIPaddrLeaseTime */
     {
-      DhcpOptions.val[dhcpIPaddrLeaseTime] = malloc(4);
+      DhcpOptions.val[dhcpIPaddrLeaseTime] = xmalloc(4);
       memcpy(DhcpOptions.val[dhcpIPaddrLeaseTime],&nleaseTime,4);
       DhcpOptions.len[dhcpIPaddrLeaseTime] = 4;
       DhcpOptions.num++;
@@ -355,7 +356,7 @@
     {
       unsigned t2 = 0.5*ntohl(*(unsigned int *)DhcpOptions.val[dhcpIPaddrLeaseTime]);
       int t1 = htonl(t2);
-      DhcpOptions.val[dhcpT1value] = malloc(4);
+      DhcpOptions.val[dhcpT1value] = xmalloc(4);
       memcpy(DhcpOptions.val[dhcpT1value],&t1,4);
       DhcpOptions.len[dhcpT1value] = 4;
       DhcpOptions.num++;
@@ -378,7 +379,7 @@
     {
       unsigned t2 = 0.875*ntohl(*(unsigned int *)DhcpOptions.val[dhcpIPaddrLeaseTime]);
       int t1 = htonl(t2);
-      DhcpOptions.val[dhcpT2value] = malloc(4);
+      DhcpOptions.val[dhcpT2value] = xmalloc(4);
       memcpy(DhcpOptions.val[dhcpT2value],&t1,4);
       DhcpOptions.len[dhcpT2value] = 4;
       DhcpOptions.num++;
@@ -911,7 +912,7 @@
 #endif
 		  dname++;
 	      dname_len=dname-hp->h_name;
-	      DhcpOptions.val[hostName]=(char *)malloc(dname_len+1);
+	      DhcpOptions.val[hostName]=(char *)xmalloc(dname_len+1);
 	      DhcpOptions.len[hostName]=dname_len;
 	      memcpy((char *)DhcpOptions.val[hostName],
 	      hp->h_name,dname_len);
@@ -972,7 +973,7 @@
 		  dname_len=strlen(dname);
 		  if ( dname_len )
 		    {
-		      DhcpOptions.val[domainName]=(char *)malloc(dname_len+1);
+		      DhcpOptions.val[domainName]=(char *)xmalloc(dname_len+1);
 		      DhcpOptions.len[domainName]=dname_len;
 		      memcpy((char *)DhcpOptions.val[domainName],
 		      dname,dname_len);
Index: configure.in
===================================================================
RCS file: /usr/local/cvsroot/user/dhcpcd/configure.in,v
retrieving revision 1.1.1.1
retrieving revision 1.4
diff -u -r1.1.1.1 -r1.4
--- configure.in	14 Apr 2002 07:07:20 -0000	1.1.1.1
+++ configure.in	21 May 2002 16:24:21 -0000	1.4
@@ -1,10 +1,11 @@
 dnl Process this file with autoconf to produce a configure script.
-AC_INIT(peekfd.c)
+AC_INIT(dhcpcd, 1.3.22)
+AM_CONFIG_HEADER(config.h)
 
 dnl
 dnl Version
 dnl
-DHCPCD_VERSION=1.3.22
+DHCPCD_VERSION="$PACKAGE_VERSION"
 AC_SUBST(DHCPCD_VERSION)
 
 dnl
@@ -47,7 +48,7 @@
 		;;
 esac
 
-LDFLAGS="-s -O2"
+LDFLAGS="$LDFLAGS -s -O2"
 
 dnl
 dnl Checks for programs.
@@ -78,5 +79,50 @@
 AC_PROG_GCC_TRADITIONAL
 AC_FUNC_MEMCMP
 AC_CHECK_FUNCS(select socket uname)
+
+dnl uClinux has only a stub fork() which calls vfork().  This fact
+dnl is not reflected in autoconf-2.53.
+AC_DEFUN([AC_FORK_IS_A_STUB_IN_UCLINUX],
+[AC_BEFORE([$0], [AC_FUNC_FORK])dnl
+case $host in
+    (*-uClinux | *-uclinux)
+        ac_cv_func_fork=no
+	AC_MSG_NOTICE([uClinux has only a stub fork() that calls vfork()])
+	AC_DEFINE(HAVE_VFORK, 1, 
+		[indicates that the vfork() call is available])dnl
+	AC_DEFINE(HAVE_WORKING_VFORK, 1, 
+		[indicates that the vfork() call works as expected])dnl
+        ;;
+    (*)
+	# Check for presence of fork() and vfork() in the C library
+	# and define HAVE_FORK and HAVE_VFORK accordingly.
+	# Also, run tests if compiling native code or make assumptions
+	# to determine if fork() and vfork() work when they exist.
+	# Set or unset HAVE_WORKING_FORK and HAVE_WORKING_VFORK.
+	AC_FUNC_FORK[]dnl
+	;;
+esac
+])# AC_FORK_IS_A_STUB_IN_UCLINUX
+AC_FORK_IS_A_STUB_IN_UCLINUX
+
+AH_BOTTOM([
+#ifdef HAVE_WORKING_FORK
+
+/* fork() exists and works */
+#  define FINISHVOID(code)    _exit(code)
+#  define FINISH(code)        _exit(code)
+
+#elif defined(HAVE_WORKING_VFORK)
+
+#  define fork                vfork
+#  define FINISHVOID(code)    return
+#  define FINISH(code)        return (!code)
+
+#else
+
+#  error fork() or vfork() are not found in the standard C library \
+         or are not working or are assumed to not work on the target \
+         platform.
+#endif])
 
 AC_OUTPUT([Makefile dhcpcd.spec])
Index: dhcpcd.c
===================================================================
RCS file: /usr/local/cvsroot/user/dhcpcd/dhcpcd.c,v
retrieving revision 1.1.1.1
retrieving revision 1.7
diff -u -r1.1.1.1 -r1.7
--- dhcpcd.c	14 Apr 2002 07:07:20 -0000	1.1.1.1
+++ dhcpcd.c	22 Apr 2002 23:31:48 -0000	1.7
@@ -32,10 +32,31 @@
 #include <arpa/inet.h>
 #include <errno.h>
 #include <ctype.h>
+#include "config.h"
 #include "pathnames.h"
 #include "client.h"
 #include "signals.h"
 
+/* #define DEBUG_EXEC 1 */
+
+#if DEBUG_EXEC - 0
+#  include <stdio.h>
+#  define DEBUG_LOG(fmt, args...)    do { \
+	char c; \
+	fprintf(stderr, "%s (%d): " fmt, \
+		__FUNCTION__, __LINE__ , ##args); \
+	read(0, &c, 1); \
+	} while (0)
+#  define D(x) x
+
+#else
+
+#  define DEBUG_LOG(fmt, args...)  do { } while (0)
+#  define D(x)
+#endif
+
+#define DEBUG_MARK()  DEBUG_LOG("debug mark")
+
 struct in_addr  inform_ipaddr;
 char		*ProgramName	=	NULL;
 char            **ProgramEnviron=       NULL;
@@ -91,6 +112,12 @@
   int s			=	1;
   int k			=	1;
   int i			=	1;
+#ifndef HAVE_WORKING_FORK
+  int spawned		=	0;
+# define ISSPAWNED	( spawned )
+#else
+# define ISSPAWNED	( 0 )
+#endif		/* !HAVE_WORKING_FORK */
  
   if ( getuid() )
     {
@@ -108,7 +135,7 @@
 	    break;
 	  case 'k':
 	    s++;
-	    killFlag=SIGHUP;
+	    killFlag=SIGTERM;
 	    goto prgs;
 	  case 'n':
 	    s++;
@@ -272,6 +299,12 @@
 	    s++;
 	    TestCase=1;
 	    goto prgs;
+#ifndef HAVE_WORKING_FORK
+	  case 'f':
+	    s++;
+	    spawned=1;
+	    goto prgs;
+#endif			/* !HAVE_WORKING_FORK */
 	  case 'l':
 	    if ( argc[i][s+1] ) goto usage;
 	    i++;
@@ -301,7 +334,7 @@
       while ( IfNameExt[s] )
 	if ( IfNameExt[s] == ':' )
 	  {
-	    IfName=(char *)malloc(s+1);
+	    IfName=(char *)xmalloc(s+1);
 	    memcpy(IfName,IfNameExt,s);
 	    IfName[s]=0;
 	    IfName_len=s;
@@ -313,11 +346,12 @@
   ProgramName=argc[0];
   ProgramEnviron=argv;
   umask(022);
-  if ( killFlag ) killPid(killFlag);
-  if ( ! TestCase ) checkIfAlreadyRunning();
-  if ( versionFlag ) print_version();
+  if ( ! ISSPAWNED && killFlag ) killPid(killFlag);
+  if ( ! ISSPAWNED && ! TestCase ) checkIfAlreadyRunning();
+  if ( ! ISSPAWNED && versionFlag ) print_version();
   openlog(PROGRAM_NAME,LOG_PID|LOG_CONS,LOG_LOCAL0);
   signalSetup();
+  signal(SIGHUP, SIG_IGN);
   if ( mkdir(ConfigDir,S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) && errno != EEXIST )
     {
       syslog(LOG_ERR,"mkdir(\"%s\",0): %m\n",ConfigDir);
@@ -326,22 +360,63 @@
   magic_cookie = htonl(MAGIC_COOKIE);
   dhcpMsgSize = htons(sizeof(dhcpMessage));
   nleaseTime = htonl(LeaseTime);
-  alarm(TimeOut);
-  do
-    if ( (currState=(void *(*)())currState()) == NULL ) exit(1);
-  while ( currState != &dhcpBound );
+  if ( ! ISSPAWNED )
+    {
+      alarm(TimeOut);
+      do
+        if ( (currState=(void *(*)())currState()) == NULL ) exit(1);
+      while ( currState != &dhcpBound );
+      alarm(0);
+    }
 #if 0
   if ( TestCase ) exit(0);
 #endif
-  alarm(0);
+  DEBUG_MARK();
 #ifdef DEBUG
   writePidFile(getpid());
 #else
-  s=fork();
-  if ( s )
+
+  if ( ! ISSPAWNED )
     {
-      writePidFile(s);
-      exit(0); /* got into bound state. */
+      DEBUG_MARK();
+      s=fork();
+      if ( s )
+        {
+          DEBUG_MARK();
+          writePidFile(s);
+#ifndef HAVE_WORKING_FORK
+          /* I added this delay to let the child configure the interface 
+             again.  This is necessary because fork() is not available,
+             and we execute the same binary in the child process.  The
+             second instance of dhcpcd will have to go through "reboot"
+             state because I don't see any other way to ensure that the
+             data segment is in the same state with parent.
+           */
+          usleep(1000000L);
+#endif
+          exit(0); /* got into bound state. */
+        }
+# ifndef HAVE_WORKING_FORK
+      {
+        char **newargc;
+        newargc = xmalloc((argn + 1) * sizeof(char *));
+	if ( newargc != NULL )
+	  {
+            memcpy(newargc, argc, argn * sizeof(char *));
+            newargc[argn] = "-f";
+            newargc[argn + 1] = NULL;
+            DEBUG_MARK();
+            signal(SIGHUP, SIG_IGN);
+            execvp(newargc[0], newargc);
+            fprintf(stderr, "Could not start %s in child mode\n", newargc[0]);
+	  }
+	else
+	  {
+	    fprintf(stderr, "Could not allocate %d pointers\n", argn + 1);
+	  }
+        exit(127);
+      }
+# endif		/* !HAVE_WORKING_FORK */
     }
   setsid();
   if ( (i=open("/dev/null",O_RDWR,0)) >= 0 )
@@ -351,7 +426,8 @@
       (void)dup2(i,STDERR_FILENO);
       if ( i > 2 ) (void)close(i);
     }
-#endif
+
+#endif		/* DEBUG */
   chdir("/");
   do currState=(void *(*)())currState(); while ( currState );
   deletePidFile();
Index: dhcpcd.h
===================================================================
RCS file: /usr/local/cvsroot/user/dhcpcd/dhcpcd.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- dhcpcd.h	14 Apr 2002 07:07:20 -0000	1.1.1.1
+++ dhcpcd.h	21 Apr 2002 00:28:58 -0000	1.2
@@ -38,4 +38,59 @@
 #define DEFAULT_TIMEOUT		60
 #define DEFAULT_LEASETIME	0xffffffff	/* infinite lease time */
 
+/*
+#define DEBUG_EXEC 1
+#define DEBUG_MALLOC 1
+*/
+
+#if DEBUG_EXEC - 0
+#  include <stdio.h>
+#  define DEBUG_LOG(fmt, args...)    do { \
+	syslog(LOG_INFO, "%s (%d): " fmt "\n", \
+		__FUNCTION__, __LINE__ , ##args); \
+	} while (0)
+#  define D(x) x
+
+#else
+
+#  define DEBUG_LOG(fmt, args...)  do { } while (0)
+#  define D(x)
+#endif
+
+#define DEBUG_MARK()  DEBUG_LOG("debug mark")
+
+#if DEBUG_MALLOC - 0
+#  define xmalloc(n)	( { \
+	void *ptr; \
+	ptr = malloc(n); \
+	syslog(LOG_INFO, "%s (%d): malloc(%ld) %p\n", \
+		__FUNCTION__, __LINE__ , (long)n, ptr); \
+	ptr ; \
+	} )
+#  define xstrdup(s)	( { \
+	char *ptr; \
+	ptr = strdup(s); \
+	syslog(LOG_INFO, "%s (%d): strdup(%s) %p\n", \
+		__FUNCTION__, __LINE__ , s, ptr); \
+	ptr ; \
+	} )
+#  define xfree(p)	( \
+	syslog(LOG_INFO, "%s (%d): free %p\n", \
+		__FUNCTION__, __LINE__ , p), \
+	free(p), \
+	p = NULL \
+	)
+#  define DEBUG_MALLOC_LOG(fmt, args...)    do { \
+	syslog(LOG_INFO, "%s (%d): " fmt "\n", \
+		__FUNCTION__, __LINE__ , ##args); \
+	} while (0)
+#else
+#  define xmalloc(n)	malloc(n)
+#  define xstrdup(s)	strdup(s)
+#  define xfree(p)	free(p)
+#  define DEBUG_MALLOC_LOG(fmt, args...)  do { } while (0)
+#endif
+
+
+
 #endif
Index: pathnames.h
===================================================================
RCS file: /usr/local/cvsroot/user/dhcpcd/pathnames.h,v
retrieving revision 1.1.1.1
retrieving revision 1.3
diff -u -r1.1.1.1 -r1.3
--- pathnames.h	14 Apr 2002 07:07:20 -0000	1.1.1.1
+++ pathnames.h	19 Apr 2002 16:21:35 -0000	1.3
@@ -26,13 +26,22 @@
 #include <paths.h>
 #include "dhcpcd.h"
 
+#ifdef EMBED
+#  define CONFIG_DIR		"/var/dhcpc"
+#  define EXEC_ON_CHANGE	"/etc/"PROGRAM_NAME".exe"
+#  define RESOLV_CONF		"/etc/config/resolv.conf"
+#  define NIS_CONF		"/etc/config/yp.conf"
+#  define NTP_CONF		"/etc/config/ntp.conf"
+#else
+#  define CONFIG_DIR		"/etc/dhcpc"
+#  define EXEC_ON_CHANGE	"%s/"PROGRAM_NAME".exe"
+#  define RESOLV_CONF		"/etc/resolv.conf"
+#  define NIS_CONF		"/etc/yp.conf"
+#  define NTP_CONF		"/etc/ntp.conf"
+#endif
+
 #define PID_FILE_PATH		"%s/"PROGRAM_NAME"-%s.pid"
-#define CONFIG_DIR		"/etc/dhcpc"
 #define DHCP_CACHE_FILE		"%s/"PROGRAM_NAME"-%s.cache"
 #define DHCP_HOSTINFO		"%s/"PROGRAM_NAME"-%s.info"
-#define EXEC_ON_CHANGE		"%s/"PROGRAM_NAME".exe"
-#define RESOLV_CONF		"/etc/resolv.conf"
-#define NIS_CONF		"/etc/yp.conf"
-#define NTP_CONF		"/etc/ntp.conf"
 
 #endif
========================================================================





More information about the busybox mailing list