xref: /illumos-gate/usr/src/lib/libdhcpagent/common/dhcpagent_util.c (revision 150d2c5288c645a1c1a7d2bee61199a3729406c7)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <sys/time.h>
31 #include <unistd.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include "dhcpagent_ipc.h"
36 #include "dhcpagent_util.h"
37 
38 /*
39  * Strings returned by dhcp_status_hdr_string() and
40  * dhcp_status_reply_to_string(). The first define is the header line, and
41  * the second defines line printed underneath.
42  * The spacing of fields must match.
43  */
44 #define	DHCP_STATUS_HDR	"Interface  State         Sent  Recv  Declined  Flags\n"
45 #define	DHCP_STATUS_STR	"%-10s %-12s %5d %5d %9d  "
46 
47 static const char *time_to_string(time_t abs_time);
48 
49 /*
50  * dhcp_state_to_string(): given a state, provides the state's name
51  *
52  *    input: DHCPSTATE: the state to get the name of
53  *   output: const char *: the state's name
54  */
55 
56 const char *
57 dhcp_state_to_string(DHCPSTATE state)
58 {
59 	const char *states[] = {
60 		"INIT",
61 		"SELECTING",
62 		"REQUESTING",
63 		"PRE_BOUND",
64 		"BOUND",
65 		"RENEWING",
66 		"REBINDING",
67 		"INFORMATION",
68 		"INIT_REBOOT",
69 		"ADOPTING",
70 		"INFORM_SENT",
71 		"DECLINING",
72 		"RELEASING"
73 	};
74 
75 	if (state < 0 || state >= DHCP_NSTATES)
76 		return ("<unknown>");
77 
78 	return (states[state]);
79 }
80 
81 /*
82  * dhcp_string_to_request(): maps a string into a request code
83  *
84  *    input: const char *: the string to map
85  *   output: dhcp_ipc_type_t: the request code, or -1 if unknown
86  */
87 
88 dhcp_ipc_type_t
89 dhcp_string_to_request(const char *request)
90 {
91 	static struct {
92 		const char	*string;
93 		dhcp_ipc_type_t  type;
94 	} types[] = {
95 		{ "drop",	DHCP_DROP	},
96 		{ "extend",	DHCP_EXTEND	},
97 		{ "inform",	DHCP_INFORM	},
98 		{ "ping",	DHCP_PING	},
99 		{ "release",	DHCP_RELEASE	},
100 		{ "start",	DHCP_START	},
101 		{ "status",	DHCP_STATUS	}
102 	};
103 
104 	unsigned int	i;
105 
106 	for (i = 0; i < (sizeof (types) / sizeof (*types)); i++)
107 		if (strcmp(types[i].string, request) == 0)
108 			return (types[i].type);
109 
110 	return (-1);
111 }
112 
113 /*
114  * dhcp_start_agent(): starts the agent if not already running
115  *
116  *   input: int: number of seconds to wait for agent to start (-1 is forever)
117  *  output: int: 0 on success, -1 on failure
118  */
119 
120 int
121 dhcp_start_agent(int timeout)
122 {
123 	int			error;
124 	time_t			start_time = time(NULL);
125 	dhcp_ipc_request_t	*request;
126 	dhcp_ipc_reply_t	*reply;
127 
128 	/*
129 	 * just send a dummy request to the agent to find out if it's
130 	 * up.  we do this instead of directly connecting to it since
131 	 * we want to make sure we follow its IPC conventions
132 	 * (otherwise, it will log warnings to syslog).
133 	 */
134 
135 	request = dhcp_ipc_alloc_request(DHCP_PING, "", NULL, 0,
136 	    DHCP_TYPE_NONE);
137 	if (request == NULL)
138 		return (-1);
139 
140 	error = dhcp_ipc_make_request(request, &reply, 0);
141 	if (error == 0) {
142 		free(reply);
143 		free(request);
144 		return (0);
145 	}
146 	if (error != DHCP_IPC_E_CONNECT) {
147 		free(request);
148 		return (-1);
149 	}
150 
151 	switch (fork()) {
152 
153 	case -1:
154 		free(request);
155 		return (-1);
156 
157 	case  0:
158 		(void) execl(DHCP_AGENT_PATH, DHCP_AGENT_PATH, (char *)0);
159 		_exit(EXIT_FAILURE);
160 
161 	default:
162 		break;
163 	}
164 
165 	while ((timeout != -1) && (time(NULL) - start_time < timeout)) {
166 		error = dhcp_ipc_make_request(request, &reply, 0);
167 		if (error == 0) {
168 			free(reply);
169 			free(request);
170 			return (0);
171 		} else if (error != DHCP_IPC_E_CONNECT)
172 			break;
173 		(void) sleep(1);
174 	}
175 
176 	free(request);
177 	return (-1);
178 }
179 
180 /*
181  * dhcp_status_hdr_string(): Return a string suitable to use as the header
182  *			     when printing DHCP_STATUS reply.
183  *  output: const char *: newline terminated printable string
184  */
185 const char *
186 dhcp_status_hdr_string(void)
187 {
188 	return (DHCP_STATUS_HDR);
189 }
190 
191 /*
192  * time_to_string(): Utility routine for printing time
193  *
194  *   input: time_t *: time_t to stringify
195  *  output: const char *: printable time
196  */
197 static const char *
198 time_to_string(time_t abs_time)
199 {
200 	static char time_buf[24];
201 	time_t tm = abs_time;
202 
203 	if (tm == DHCP_PERM)
204 		return ("Never");
205 
206 	if (strftime(time_buf, sizeof (time_buf), "%m/%d/%Y %R",
207 	    localtime(&tm)) == 0)
208 		return ("<unknown>");
209 
210 	return (time_buf);
211 }
212 
213 /*
214  * dhcp_status_reply_to_string(): Return DHCP IPC reply of type DHCP_STATUS
215  *				  as a printable string
216  *
217  *   input: dhcp_reply_t *: contains the status structure to print
218  *  output: const char *: newline terminated printable string
219  */
220 const char *
221 dhcp_status_reply_to_string(dhcp_ipc_reply_t *reply)
222 {
223 	static char str[1024];
224 	size_t reply_size;
225 	dhcp_status_t *status;
226 
227 	status = dhcp_ipc_get_data(reply, &reply_size, NULL);
228 	if (reply_size < DHCP_STATUS_VER1_SIZE)
229 		return ("<Internal error: status msg size>\n");
230 
231 	(void) snprintf(str, sizeof (str), DHCP_STATUS_STR,
232 	    status->if_name, dhcp_state_to_string(status->if_state),
233 	    status->if_sent, status->if_recv, status->if_bad_offers);
234 
235 	if (status->if_dflags & DHCP_IF_PRIMARY)
236 		(void) strlcat(str, "[PRIMARY] ", sizeof (str));
237 
238 	if (status->if_dflags & DHCP_IF_BOOTP)
239 		(void) strlcat(str, "[BOOTP] ", sizeof (str));
240 
241 	if (status->if_dflags & DHCP_IF_FAILED)
242 		(void) strlcat(str, "[FAILED] ", sizeof (str));
243 
244 	if (status->if_dflags & DHCP_IF_BUSY)
245 		(void) strlcat(str, "[BUSY] ", sizeof (str));
246 
247 	if (status->if_dflags & DHCP_IF_V6)
248 		(void) strlcat(str, "[V6] ", sizeof (str));
249 
250 	(void) strlcat(str, "\n", sizeof (str));
251 
252 	switch (status->if_state) {
253 	case BOUND:
254 	case RENEWING:
255 	case REBINDING:
256 		break;
257 	default:
258 		return (str);
259 	}
260 
261 	(void) strlcat(str, "(Began, Expires, Renew) = (", sizeof (str));
262 	(void) strlcat(str, time_to_string(status->if_began), sizeof (str));
263 	(void) strlcat(str, ", ", sizeof (str));
264 	(void) strlcat(str, time_to_string(status->if_lease), sizeof (str));
265 	(void) strlcat(str, ", ", sizeof (str));
266 	(void) strlcat(str, time_to_string(status->if_t1), sizeof (str));
267 	(void) strlcat(str, ")\n", sizeof (str));
268 	return (str);
269 }
270