From e2d3ded3549edd58fe3b39f2254c65f0808bcac2 Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Mon, 27 Nov 2006 23:43:28 +0000 Subject: [PATCH] udhcpc: convert to getopt32 --- include/usage.h | 9 ++ networking/udhcp/dhcpc.c | 275 +++++++++++++++++---------------------- networking/udhcp/dhcpc.h | 34 ++--- networking/udhcp/dhcpd.c | 6 +- 4 files changed, 154 insertions(+), 170 deletions(-) diff --git a/include/usage.h b/include/usage.h index e7e46beab..98c802721 100644 --- a/include/usage.h +++ b/include/usage.h @@ -1,4 +1,13 @@ /* vi: set sw=4 ts=4: */ +/* + * This file suffers from chronically incorrect tabification + * of messages. Before editing this file: + * 1. Switch you editor to 8-space tab mode. + * 2. Do not use \t in messages, use real tab character. + * 3. Start each source line with message as follows: + * |<7 spaces>"text with tabs" + */ + #ifndef __BB_USAGE_H__ #define __BB_USAGE_H__ diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index 4ccd8ec34..f69b687b2 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c @@ -33,25 +33,8 @@ static int fd = -1; #define LISTEN_RAW 2 static int listen_mode; -struct client_config_t client_config = { - /* Default options. */ - .abort_if_no_lease = 0, - .foreground = 0, - .quit_after_lease = 0, - .release_on_quit = 0, - .background_if_no_lease = 0, - .interface = "eth0", - .pidfile = NULL, - .script = DEFAULT_SCRIPT, - .clientid = NULL, - .vendorclass = NULL, - .hostname = NULL, - .fqdn = NULL, - .ifindex = 0, - .retries = 3, - .timeout = 3, - .arp = "\0\0\0\0\0\0", /* appease gcc-3.0 */ -}; +struct client_config_t client_config; + /* just a little helper */ static void change_mode(int new_mode) @@ -126,139 +109,137 @@ static void client_background(void) } +static uint8_t* alloc_dhcp_option(int code, const char *str, int extra) +{ + uint8_t *storage; + int len = strlen(str); + if (len > 255) len = 255; + storage = xzalloc(len + extra + OPT_DATA); + storage[OPT_CODE] = code; + storage[OPT_LEN] = len + extra; + memcpy(storage + extra + OPT_DATA, str, len); + return storage; +} + + int udhcpc_main(int argc, char *argv[]) { uint8_t *temp, *message; + char *str_c, *str_V, *str_h, *str_F, *str_r, *str_T, *str_t; unsigned long t1 = 0, t2 = 0, xid = 0; unsigned long start = 0, lease = 0; - fd_set rfds; - int retval; - struct timeval tv; - int c, len; - struct dhcpMessage packet; - struct in_addr temp_addr; long now; + unsigned opt; int max_fd; int sig; + int retval; + int len; int no_clientid = 0; + fd_set rfds; + struct timeval tv; + struct dhcpMessage packet; + struct in_addr temp_addr; + enum { + OPT_c = 1 << 0, + OPT_C = 1 << 1, + OPT_V = 1 << 2, + OPT_f = 1 << 3, + OPT_b = 1 << 4, + OPT_H = 1 << 5, + OPT_h = 1 << 6, + OPT_F = 1 << 7, + OPT_i = 1 << 8, + OPT_n = 1 << 9, + OPT_p = 1 << 10, + OPT_q = 1 << 11, + OPT_R = 1 << 12, + OPT_r = 1 << 13, + OPT_s = 1 << 14, + OPT_T = 1 << 15, + OPT_t = 1 << 16, + OPT_v = 1 << 17, + }; static const struct option arg_options[] = { - {"clientid", required_argument, 0, 'c'}, - {"clientid-none", no_argument, 0, 'C'}, - {"vendorclass", required_argument, 0, 'V'}, - {"foreground", no_argument, 0, 'f'}, - {"background", no_argument, 0, 'b'}, - {"hostname", required_argument, 0, 'H'}, - {"hostname", required_argument, 0, 'h'}, - {"fqdn", required_argument, 0, 'F'}, - {"interface", required_argument, 0, 'i'}, - {"now", no_argument, 0, 'n'}, - {"pidfile", required_argument, 0, 'p'}, - {"quit", no_argument, 0, 'q'}, - {"release", no_argument, 0, 'R'}, - {"request", required_argument, 0, 'r'}, - {"script", required_argument, 0, 's'}, - {"timeout", required_argument, 0, 'T'}, - {"version", no_argument, 0, 'v'}, - {"retries", required_argument, 0, 't'}, - {0, 0, 0, 0} + { "clientid", required_argument, 0, 'c' }, + { "clientid-none", no_argument, 0, 'C' }, + { "vendorclass", required_argument, 0, 'V' }, + { "foreground", no_argument, 0, 'f' }, + { "background", no_argument, 0, 'b' }, + { "hostname", required_argument, 0, 'H' }, + { "hostname", required_argument, 0, 'h' }, + { "fqdn", required_argument, 0, 'F' }, + { "interface", required_argument, 0, 'i' }, + { "now", no_argument, 0, 'n' }, + { "pidfile", required_argument, 0, 'p' }, + { "quit", no_argument, 0, 'q' }, + { "release", no_argument, 0, 'R' }, + { "request", required_argument, 0, 'r' }, + { "script", required_argument, 0, 's' }, + { "timeout", required_argument, 0, 'T' }, + { "version", no_argument, 0, 'v' }, + { "retries", required_argument, 0, 't' }, + { 0, 0, 0, 0 } }; - /* get options */ - while (1) { - int option_index = 0; - c = getopt_long(argc, argv, "c:CV:fbH:h:F:i:np:qRr:s:T:t:v", arg_options, &option_index); - if (c == -1) break; + /* Default options. */ + client_config.interface = "eth0"; + client_config.script = DEFAULT_SCRIPT; + client_config.retries = 3; + client_config.timeout = 3; - switch (c) { - case 'c': - if (no_clientid) bb_show_usage(); - len = strlen(optarg) > 255 ? 255 : strlen(optarg); - free(client_config.clientid); - client_config.clientid = xmalloc(len + 2); - client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID; - client_config.clientid[OPT_LEN] = len; - client_config.clientid[OPT_DATA] = '\0'; - strncpy((char*)client_config.clientid + OPT_DATA, optarg, len); - break; - case 'C': - if (client_config.clientid) bb_show_usage(); - no_clientid = 1; - break; - case 'V': - len = strlen(optarg) > 255 ? 255 : strlen(optarg); - free(client_config.vendorclass); - client_config.vendorclass = xmalloc(len + 2); - client_config.vendorclass[OPT_CODE] = DHCP_VENDOR; - client_config.vendorclass[OPT_LEN] = len; - strncpy((char*)client_config.vendorclass + OPT_DATA, optarg, len); - break; - case 'f': - client_config.foreground = 1; - break; - case 'b': - client_config.background_if_no_lease = 1; - break; - case 'h': - case 'H': - len = strlen(optarg) > 255 ? 255 : strlen(optarg); - free(client_config.hostname); - client_config.hostname = xmalloc(len + 2); - client_config.hostname[OPT_CODE] = DHCP_HOST_NAME; - client_config.hostname[OPT_LEN] = len; - strncpy((char*)client_config.hostname + 2, optarg, len); - break; - case 'F': - len = strlen(optarg) > 255 ? 255 : strlen(optarg); - free(client_config.fqdn); - client_config.fqdn = xmalloc(len + 5); - client_config.fqdn[OPT_CODE] = DHCP_FQDN; - client_config.fqdn[OPT_LEN] = len + 3; - /* Flags: 0000NEOS - S: 1 => Client requests Server to update A RR in DNS as well as PTR - O: 1 => Server indicates to client that DNS has been updated regardless - E: 1 => Name data is DNS format, i.e. <4>host<6>domain<4>com<0> not "host.domain.com" - N: 1 => Client requests Server to not update DNS - */ - client_config.fqdn[OPT_LEN + 1] = 0x1; - client_config.fqdn[OPT_LEN + 2] = 0; - client_config.fqdn[OPT_LEN + 3] = 0; - strncpy((char*)client_config.fqdn + 5, optarg, len); - break; - case 'i': - client_config.interface = optarg; - break; - case 'n': - client_config.abort_if_no_lease = 1; - break; - case 'p': - client_config.pidfile = optarg; - break; - case 'q': - client_config.quit_after_lease = 1; - break; - case 'R': - client_config.release_on_quit = 1; - break; - case 'r': - requested_ip = inet_addr(optarg); - break; - case 's': - client_config.script = optarg; - break; - case 'T': - client_config.timeout = xatoi_u(optarg); - break; - case 't': - client_config.retries = xatoi_u(optarg); - break; - case 'v': - printf("version %s\n\n", BB_VER); - return 0; - break; - default: - bb_show_usage(); - } + /* Parse command line */ + opt_complementary = "?:c--C:C--c" // mutually exclusive + ":hH:Hh"; // -h and -H are the same + applet_long_options = arg_options; + opt = getopt32(argc, argv, "c:CV:fbH:h:F:i:np:qRr:s:T:t:v", + &str_c, &str_V, &str_h, &str_h, &str_F, + &client_config.interface, &client_config.pidfile, &str_r, + &client_config.script, &str_T, &str_t + ); + + if (opt & OPT_c) + client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, str_c, 0); + if (opt & OPT_C) + no_clientid = 1; + if (opt & OPT_V) + client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, str_V, 0); + if (opt & OPT_f) + client_config.foreground = 1; + if (opt & OPT_b) + client_config.background_if_no_lease = 1; + if (opt & OPT_h) + client_config.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0); + if (opt & OPT_F) { + client_config.fqdn = alloc_dhcp_option(DHCP_FQDN, str_F, 3); + /* Flags: 0000NEOS + S: 1 => Client requests Server to update A RR in DNS as well as PTR + O: 1 => Server indicates to client that DNS has been updated regardless + E: 1 => Name data is DNS format, i.e. <4>host<6>domain<4>com<0> not "host.domain.com" + N: 1 => Client requests Server to not update DNS + */ + client_config.fqdn[OPT_DATA + 0] = 0x1; + /* client_config.fqdn[OPT_DATA + 1] = 0; - redundant */ + /* client_config.fqdn[OPT_DATA + 2] = 0; - redundant */ + } + // if (opt & OPT_i) client_config.interface = ... + if (opt & OPT_n) + client_config.abort_if_no_lease = 1; + // if (opt & OPT_p) client_config.pidfile = ... + if (opt & OPT_q) + client_config.quit_after_lease = 1; + if (opt & OPT_R) + client_config.release_on_quit = 1; + if (opt & OPT_r) + requested_ip = inet_addr(str_r); + // if (opt & OPT_s) client_config.script = ... + if (opt & OPT_T) + client_config.timeout = xatoi_u(str_T); + if (opt & OPT_t) + client_config.retries = xatoi_u(str_t); + if (opt & OPT_v) { + printf("version %s\n\n", BB_VER); + return 0; } /* Start the log, sanitize fd's, and write a pid file */ @@ -270,22 +251,13 @@ int udhcpc_main(int argc, char *argv[]) /* if not set, and not suppressed, setup the default client ID */ if (!client_config.clientid && !no_clientid) { - client_config.clientid = xmalloc(6 + 3); - client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID; - client_config.clientid[OPT_LEN] = 7; + client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7); client_config.clientid[OPT_DATA] = 1; - memcpy(client_config.clientid + 3, client_config.arp, 6); - } - - if (!client_config.vendorclass) { - client_config.vendorclass = xmalloc(sizeof("udhcp "BB_VER) + 2); - client_config.vendorclass[OPT_CODE] = DHCP_VENDOR; - client_config.vendorclass[OPT_LEN] = sizeof("udhcp "BB_VER) - 1; - client_config.vendorclass[OPT_DATA] = 1; - memcpy(&client_config.vendorclass[OPT_DATA], - "udhcp "BB_VER, sizeof("udhcp "BB_VER) - 1); + memcpy(client_config.clientid + OPT_DATA+1, client_config.arp, 6); } + if (!client_config.vendorclass) + client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, "udhcp "BB_VER, 0); /* setup the signal pipe */ udhcp_sp_setup(); @@ -295,7 +267,6 @@ int udhcpc_main(int argc, char *argv[]) change_mode(LISTEN_RAW); for (;;) { - tv.tv_sec = timeout - uptime(); tv.tv_usec = 0; diff --git a/networking/udhcp/dhcpc.h b/networking/udhcp/dhcpc.h index d5c8a4ba5..fd17917d0 100644 --- a/networking/udhcp/dhcpc.h +++ b/networking/udhcp/dhcpc.h @@ -13,22 +13,24 @@ #define RELEASED 7 struct client_config_t { - char foreground; /* Do not fork */ - char quit_after_lease; /* Quit after obtaining lease */ - char release_on_quit; /* perform release on quit */ - char abort_if_no_lease; /* Abort if no lease */ - char background_if_no_lease; /* Fork to background if no lease */ - char *interface; /* The name of the interface to use */ - char *pidfile; /* Optionally store the process ID */ - char *script; /* User script to run at dhcp events */ - uint8_t *clientid; /* Optional client id to use */ - uint8_t *vendorclass; /* Optional vendor class-id to use */ - uint8_t *hostname; /* Optional hostname to use */ - uint8_t *fqdn; /* Optional fully qualified domain name to use */ - int ifindex; /* Index number of the interface to use */ - int retries; /* Max number of request packets */ - int timeout; /* Number of seconds to try to get a lease */ - uint8_t arp[6]; /* Our arp address */ + /* TODO: combine flag fields into single "unsigned opt" */ + /* (can be set directly to the result of getopt32) */ + char foreground; /* Do not fork */ + char quit_after_lease; /* Quit after obtaining lease */ + char release_on_quit; /* perform release on quit */ + char abort_if_no_lease; /* Abort if no lease */ + char background_if_no_lease; /* Fork to background if no lease */ + char *interface; /* The name of the interface to use */ + char *pidfile; /* Optionally store the process ID */ + char *script; /* User script to run at dhcp events */ + uint8_t *clientid; /* Optional client id to use */ + uint8_t *vendorclass; /* Optional vendor class-id to use */ + uint8_t *hostname; /* Optional hostname to use */ + uint8_t *fqdn; /* Optional fully qualified domain name to use */ + int ifindex; /* Index number of the interface to use */ + int retries; /* Max number of request packets */ + int timeout; /* Number of seconds to try to get a lease */ + uint8_t arp[6]; /* Our arp address */ }; extern struct client_config_t client_config; diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c index 0935a9453..74380367f 100644 --- a/networking/udhcp/dhcpd.c +++ b/networking/udhcp/dhcpd.c @@ -68,11 +68,13 @@ int udhcpd_main(int argc, char *argv[]) timeout_end = time(0) + server_config.auto_time; while (1) { /* loop until universe collapses */ - if (server_socket < 0) - if ((server_socket = listen_socket(INADDR_ANY, SERVER_PORT, server_config.interface)) < 0) { + if (server_socket < 0) { + server_socket = listen_socket(INADDR_ANY, SERVER_PORT, server_config.interface); + if (server_socket < 0) { bb_perror_msg("FATAL: cannot create server socket"); return 2; } + } max_sock = udhcp_sp_fd_set(&rfds, server_socket); if (server_config.auto_time) {