Udhcpc uses scripts to perform many system dependent tasks. The return value
of these scripts isn't checked and udhcpc will continue on assuming that
they've worked.

It may also be advantage to be able to abort should certain situations
arise. In our case, we implement a basic RFC5227 check using scripts and we
wish for DHCP configuration to abort when certain circumstances are met.

Return an error so that the udhcpc caller knows the scripts have failed.

Signed-off-by: Martyn Welch <[email protected]>
Signed-off-by: Fabien Lahoudere <[email protected]>
---
 networking/udhcp/dhcpc.c | 92 ++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 73 insertions(+), 19 deletions(-)

diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index 55f21c187..da0b28a26 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -561,10 +561,11 @@ static char **fill_envp(struct dhcp_packet *packet)
 }
 
 /* Call a script with a par file and env vars */
-static void udhcp_run_script(struct dhcp_packet *packet, const char *name)
+static int udhcp_run_script(struct dhcp_packet *packet, const char *name)
 {
        char **envp, **curr;
        char *argv[3];
+       int retval;
 
        envp = fill_envp(packet);
 
@@ -573,13 +574,15 @@ static void udhcp_run_script(struct dhcp_packet *packet, 
const char *name)
        argv[0] = (char*) client_config.script;
        argv[1] = (char*) name;
        argv[2] = NULL;
-       spawn_and_wait(argv);
+       retval = spawn_and_wait(argv);
 
        for (curr = envp; *curr; curr++) {
                log2(" %s", *curr);
                bb_unsetenv_and_free(*curr);
        }
        free(envp);
+
+       return retval;
 }
 
 
@@ -1111,8 +1114,10 @@ static void change_listen_mode(int new_mode)
 }
 
 /* Called only on SIGUSR1 */
-static void perform_renew(void)
+static int perform_renew(void)
 {
+       int retval = 0;
+
        bb_error_msg("performing DHCP renew");
        switch (state) {
        case BOUND:
@@ -1122,7 +1127,11 @@ static void perform_renew(void)
                state = RENEW_REQUESTED;
                break;
        case RENEW_REQUESTED: /* impatient are we? fine, square 1 */
-               udhcp_run_script(NULL, "deconfig");
+               retval = udhcp_run_script(NULL, "deconfig");
+               if (retval != 0) {
+                       bb_error_msg("Action scripts failed for deconfig: %d", 
retval);
+                       return retval;
+               }
        case REQUESTING:
        case RELEASED:
                change_listen_mode(LISTEN_RAW);
@@ -1131,12 +1140,15 @@ static void perform_renew(void)
        case INIT_SELECTING:
                break;
        }
+
+       return retval;
 }
 
-static void perform_release(uint32_t server_addr, uint32_t requested_ip)
+static int perform_release(uint32_t server_addr, uint32_t requested_ip)
 {
        char buffer[sizeof("255.255.255.255")];
        struct in_addr temp_addr;
+       int retval = 0;
 
        /* send release packet */
        if (state == BOUND
@@ -1158,10 +1170,15 @@ static void perform_release(uint32_t server_addr, 
uint32_t requested_ip)
  * Users requested to be notified in all cases, even if not in one
  * of the states above.
  */
-       udhcp_run_script(NULL, "deconfig");
+       retval = udhcp_run_script(NULL, "deconfig");
+       if (retval != 0) {
+               bb_error_msg("Action scripts failed for deconfig: %d", retval);
+               return retval;
+       }
 
        change_listen_mode(LISTEN_NONE);
        state = RELEASED;
+       return retval;
 }
 
 static uint8_t* alloc_dhcp_option(int code, const char *str, int extra)
@@ -1398,7 +1415,11 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
        srand(monotonic_us());
 
        state = INIT_SELECTING;
-       udhcp_run_script(NULL, "deconfig");
+       retval = udhcp_run_script(NULL, "deconfig");
+       if (retval != 0) {
+               bb_error_msg("Action scripts failed for deconfig: %d", retval);
+               goto ret;
+       }
        change_listen_mode(LISTEN_RAW);
        packet_num = 0;
        timeout = 0;
@@ -1478,7 +1499,11 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
                                        continue;
                                }
  leasefail:
-                               udhcp_run_script(NULL, "leasefail");
+                               retval = udhcp_run_script(NULL, "leasefail");
+                               if (retval != 0) {
+                                       bb_error_msg("Action scripts failed for 
leasefail: %d", retval);
+                                       goto ret;
+                               }
 #if BB_MMU /* -b is not supported on NOMMU */
                                if (opt & OPT_b) { /* background if no lease */
                                        bb_error_msg("no lease, forking to 
background");
@@ -1565,7 +1590,11 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
                                }
                                /* Timed out, enter init state */
                                bb_error_msg("lease lost, entering init state");
-                               udhcp_run_script(NULL, "deconfig");
+                               retval = udhcp_run_script(NULL, "deconfig");
+                               if (retval != 0) {
+                                       bb_error_msg("Action scripts failed for 
deconfig: %d", retval);
+                                       goto ret;
+                               }
                                state = INIT_SELECTING;
                                client_config.first_secs = 0; /* make secs 
field count from 0 */
                                /*timeout = 0; - already is */
@@ -1586,7 +1615,9 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
                case SIGUSR1:
                        client_config.first_secs = 0; /* make secs field count 
from 0 */
                        already_waited_sec = 0;
-                       perform_renew();
+                       retval = perform_renew();
+                       if (retval != 0)
+                               goto ret;
                        if (state == RENEW_REQUESTED) {
                                /* We might be either on the same network
                                 * (in which case renew might work),
@@ -1608,7 +1639,9 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
                        timeout = 0;
                        continue;
                case SIGUSR2:
-                       perform_release(server_addr, requested_ip);
+                       retval = perform_release(server_addr, requested_ip);
+                       if (retval != 0)
+                               goto ret;
                        timeout = INT_MAX;
                        continue;
                case SIGTERM:
@@ -1757,8 +1790,13 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
                                                        "(got ARP reply), 
declining");
                                                send_decline(/*xid,*/ 
server_addr, packet.yiaddr);
 
-                                               if (state != REQUESTING)
-                                                       udhcp_run_script(NULL, 
"deconfig");
+                                               if (state != REQUESTING) {
+                                                       retval = 
udhcp_run_script(NULL, "deconfig");
+                                                       if (retval != 0) {
+                                                               
bb_error_msg("Action scripts failed for deconfig: %d", retval);
+                                                               goto ret;
+                                                       }
+                                               }
                                                change_listen_mode(LISTEN_RAW);
                                                state = INIT_SELECTING;
                                                client_config.first_secs = 0; 
/* make secs field count from 0 */
@@ -1777,7 +1815,13 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
                                requested_ip = packet.yiaddr;
 
                                start = monotonic_sec();
-                               udhcp_run_script(&packet, state == REQUESTING ? 
"bound" : "renew");
+                               retval = udhcp_run_script(&packet, state == 
REQUESTING ? "bound" : "renew");
+                               if (retval != 0) { /* quit if script fails */
+                                       bb_error_msg("Action scripts failed for 
%s: %d",
+                                                       state == REQUESTING ? 
"bound" : "renew", retval);
+                                       goto ret;
+                               }
+
                                already_waited_sec = (unsigned)monotonic_sec() 
- start;
                                timeout = lease_seconds / 2;
                                if ((unsigned)timeout < already_waited_sec) {
@@ -1826,9 +1870,18 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
                                }
                                /* return to init state */
                                bb_error_msg("received %s", "DHCP NAK");
-                               udhcp_run_script(&packet, "nak");
-                               if (state != REQUESTING)
-                                       udhcp_run_script(NULL, "deconfig");
+                               retval = udhcp_run_script(&packet, "nak");
+                               if (retval != 0) {
+                                       bb_error_msg("Action scripts failed for 
nak: %d", retval);
+                                       goto ret;
+                               }
+                               if (state != REQUESTING) {
+                                       retval = udhcp_run_script(NULL, 
"deconfig");
+                                       if (retval != 0) {
+                                               bb_error_msg("Action scripts 
failed for deconfig: %d", retval);
+                                               goto ret;
+                                       }
+                               }
                                change_listen_mode(LISTEN_RAW);
                                sleep(3); /* avoid excessive network traffic */
                                state = INIT_SELECTING;
@@ -1847,8 +1900,9 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
 
  ret0:
        if (opt & OPT_R) /* release on quit */
-               perform_release(server_addr, requested_ip);
-       retval = 0;
+               retval = perform_release(server_addr, requested_ip);
+       else
+               retval = 0;
  ret:
        /*if (client_config.pidfile) - remove_pidfile has its own check */
                remove_pidfile(client_config.pidfile);
-- 
2.11.0

_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to