fatal-signal: Run signal hooks outside of actual signal handlers.
[openvswitch] / tests / test-dhcp-client.c
1 /*
2  * Copyright (c) 2008, 2009 Nicira Networks.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <config.h>
18 #include "dhcp-client.h"
19 #include <arpa/inet.h>
20 #include <getopt.h>
21 #include <stdlib.h>
22 #include <limits.h>
23 #include "command-line.h"
24 #include "dhcp.h"
25 #include "fatal-signal.h"
26 #include "fault.h"
27 #include "poll-loop.h"
28 #include "util.h"
29 #include "vlog.h"
30
31 /* --request-ip: IP address to request from server.  If zero, then do not
32  * request a specific IP address. */
33 static struct in_addr request_ip;
34
35 /* --vendor-class: Vendor class string to include in request.  If null, no
36  * vendor class string is included. */
37 static const char *vendor_class;
38
39 /* --no-resolv-conf: Update /etc/resolv.conf to match DHCP reply? */
40 static bool update_resolv_conf = true;
41
42 static void parse_options(int argc, char *argv[]);
43 static void usage(void);
44 static void release(void *cli_);
45 static void modify_dhcp_request(struct dhcp_msg *, void *aux);
46
47 int
48 main(int argc, char *argv[])
49 {
50     struct dhclient *cli;
51     int error;
52
53     set_program_name(argv[0]);
54     register_fault_handlers();
55     vlog_init();
56     parse_options(argc, argv);
57
58     argc -= optind;
59     argv += optind;
60     if (argc != 1) {
61         ovs_fatal(0, "exactly one non-option argument required; "
62                   "use --help for help");
63     }
64
65     error = dhclient_create(argv[0], modify_dhcp_request, NULL, NULL, &cli);
66     if (error) {
67         ovs_fatal(error, "dhclient_create failed");
68     }
69     dhclient_init(cli, request_ip.s_addr);
70     fatal_signal_add_hook(release, cli, true);
71
72     for (;;) {
73         dhclient_run(cli);
74         if (dhclient_changed(cli)) {
75             dhclient_configure_netdev(cli);
76             if (update_resolv_conf) {
77                 dhclient_update_resolv_conf(cli);
78             }
79         }
80         dhclient_wait(cli);
81         poll_block();
82     }
83 }
84
85 static void
86 release(void *cli_)
87 {
88     struct dhclient *cli = cli_;
89     dhclient_release(cli);
90     if (dhclient_changed(cli)) {
91         dhclient_configure_netdev(cli);
92     }
93 }
94
95 static void
96 modify_dhcp_request(struct dhcp_msg *msg, void *aux UNUSED)
97 {
98     if (vendor_class) {
99         dhcp_msg_put_string(msg, DHCP_CODE_VENDOR_CLASS, vendor_class);
100     }
101 }
102
103 static void
104 parse_options(int argc, char *argv[])
105 {
106     enum {
107         OPT_REQUEST_IP = UCHAR_MAX + 1,
108         OPT_VENDOR_CLASS,
109         OPT_NO_RESOLV_CONF
110     };
111     static struct option long_options[] = {
112         {"request-ip",  required_argument, 0, OPT_REQUEST_IP },
113         {"vendor-class", required_argument, 0, OPT_VENDOR_CLASS },
114         {"no-resolv-conf", no_argument, 0, OPT_NO_RESOLV_CONF},
115         {"verbose",     optional_argument, 0, 'v'},
116         {"help",        no_argument, 0, 'h'},
117         {"version",     no_argument, 0, 'V'},
118         {0, 0, 0, 0},
119     };
120     char *short_options = long_options_to_short_options(long_options);
121
122     for (;;) {
123         int c;
124
125         c = getopt_long(argc, argv, short_options, long_options, NULL);
126         if (c == -1) {
127             break;
128         }
129
130         switch (c) {
131         case OPT_REQUEST_IP:
132             if (!inet_aton(optarg, &request_ip)) {
133                 ovs_fatal(0,
134                           "--request-ip argument is not a valid IP address");
135             }
136             break;
137
138         case OPT_VENDOR_CLASS:
139             vendor_class = optarg;
140             break;
141
142         case OPT_NO_RESOLV_CONF:
143             update_resolv_conf = false;
144             break;
145
146         case 'h':
147             usage();
148
149         case 'V':
150             printf("%s %s compiled "__DATE__" "__TIME__"\n",
151                    program_name, VERSION BUILDNR);
152             exit(EXIT_SUCCESS);
153
154         case 'v':
155             vlog_set_verbosity(optarg);
156             break;
157
158         case '?':
159             exit(EXIT_FAILURE);
160
161         default:
162             abort();
163         }
164     }
165     free(short_options);
166 }
167
168 static void
169 usage(void)
170 {
171     printf("%s: standalone program for testing Open vSwitch DHCP client.\n"
172            "usage: %s [OPTIONS] NETDEV\n"
173            "where NETDEV is a network device (e.g. eth0).\n"
174            "\nDHCP options:\n"
175            "  --request-ip=IP         request specified IP address (default:\n"
176            "                          do not request a specific IP)\n"
177            "  --vendor-class=STRING   use STRING as vendor class; use\n"
178            "                          OpenFlow to imitate ovs-openflowd\n"
179            "  --no-resolv-conf        do not update /etc/resolv.conf\n",
180            program_name, program_name);
181     vlog_usage();
182     printf("\nOther options:\n"
183            "  -h, --help              display this help message\n"
184            "  -V, --version           display version information\n");
185     exit(EXIT_SUCCESS);
186 }
187