xref: /illumos-gate/usr/src/lib/libdhcpagent/common/dhcpagent_util.c (revision 437220cd296f6d8b6654d6d52508b40b1e2d1ac7)
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_start_agent(): starts the agent if not already running
83  *
84  *   input: int: number of seconds to wait for agent to start (-1 is forever)
85  *  output: int: 0 on success, -1 on failure
86  */
87 
88 int
89 dhcp_start_agent(int timeout)
90 {
91 	int			error;
92 	time_t			start_time = time(NULL);
93 	dhcp_ipc_request_t	*request;
94 	dhcp_ipc_reply_t	*reply;
95 
96 	/*
97 	 * just send a dummy request to the agent to find out if it's
98 	 * up.  we do this instead of directly connecting to it since
99 	 * we want to make sure we follow its IPC conventions
100 	 * (otherwise, it will log warnings to syslog).
101 	 */
102 
103 	request = dhcp_ipc_alloc_request(DHCP_PING, "", NULL, 0,
104 	    DHCP_TYPE_NONE);
105 	if (request == NULL)
106 		return (-1);
107 
108 	error = dhcp_ipc_make_request(request, &reply, 0);
109 	if (error == 0) {
110 		free(reply);
111 		free(request);
112 		return (0);
113 	}
114 	if (error != DHCP_IPC_E_CONNECT) {
115 		free(request);
116 		return (-1);
117 	}
118 
119 	switch (fork()) {
120 
121 	case -1:
122 		free(request);
123 		return (-1);
124 
125 	case  0:
126 		(void) execl(DHCP_AGENT_PATH, DHCP_AGENT_PATH, (char *)0);
127 		_exit(EXIT_FAILURE);
128 
129 	default:
130 		break;
131 	}
132 
133 	while ((timeout != -1) && (time(NULL) - start_time < timeout)) {
134 		error = dhcp_ipc_make_request(request, &reply, 0);
135 		if (error == 0) {
136 			free(reply);
137 			free(request);
138 			return (0);
139 		} else if (error != DHCP_IPC_E_CONNECT)
140 			break;
141 		(void) sleep(1);
142 	}
143 
144 	free(request);
145 	return (-1);
146 }
147 
148 /*
149  * dhcp_status_hdr_string(): Return a string suitable to use as the header
150  *			     when printing DHCP_STATUS reply.
151  *  output: const char *: newline terminated printable string
152  */
153 const char *
154 dhcp_status_hdr_string(void)
155 {
156 	return (DHCP_STATUS_HDR);
157 }
158 
159 /*
160  * time_to_string(): Utility routine for printing time
161  *
162  *   input: time_t *: time_t to stringify
163  *  output: const char *: printable time
164  */
165 static const char *
166 time_to_string(time_t abs_time)
167 {
168 	static char time_buf[24];
169 	time_t tm = abs_time;
170 
171 	if (tm == DHCP_PERM)
172 		return ("Never");
173 
174 	if (strftime(time_buf, sizeof (time_buf), "%m/%d/%Y %R",
175 	    localtime(&tm)) == 0)
176 		return ("<unknown>");
177 
178 	return (time_buf);
179 }
180 
181 /*
182  * dhcp_status_reply_to_string(): Return DHCP IPC reply of type DHCP_STATUS
183  *				  as a printable string
184  *
185  *   input: dhcp_reply_t *: contains the status structure to print
186  *  output: const char *: newline terminated printable string
187  */
188 const char *
189 dhcp_status_reply_to_string(dhcp_ipc_reply_t *reply)
190 {
191 	static char str[1024];
192 	size_t reply_size;
193 	dhcp_status_t *status;
194 
195 	status = dhcp_ipc_get_data(reply, &reply_size, NULL);
196 	if (reply_size < DHCP_STATUS_VER1_SIZE)
197 		return ("<Internal error: status msg size>\n");
198 
199 	(void) snprintf(str, sizeof (str), DHCP_STATUS_STR,
200 	    status->if_name, dhcp_state_to_string(status->if_state),
201 	    status->if_sent, status->if_recv, status->if_bad_offers);
202 
203 	if (status->if_dflags & DHCP_IF_PRIMARY)
204 		(void) strlcat(str, "[PRIMARY] ", sizeof (str));
205 
206 	if (status->if_dflags & DHCP_IF_BOOTP)
207 		(void) strlcat(str, "[BOOTP] ", sizeof (str));
208 
209 	if (status->if_dflags & DHCP_IF_FAILED)
210 		(void) strlcat(str, "[FAILED] ", sizeof (str));
211 
212 	if (status->if_dflags & DHCP_IF_BUSY)
213 		(void) strlcat(str, "[BUSY] ", sizeof (str));
214 
215 	if (status->if_dflags & DHCP_IF_V6)
216 		(void) strlcat(str, "[V6] ", sizeof (str));
217 
218 	(void) strlcat(str, "\n", sizeof (str));
219 
220 	switch (status->if_state) {
221 	case BOUND:
222 	case RENEWING:
223 	case REBINDING:
224 		break;
225 	default:
226 		return (str);
227 	}
228 
229 	(void) strlcat(str, "(Began, Expires, Renew) = (", sizeof (str));
230 	(void) strlcat(str, time_to_string(status->if_began), sizeof (str));
231 	(void) strlcat(str, ", ", sizeof (str));
232 	(void) strlcat(str, time_to_string(status->if_lease), sizeof (str));
233 	(void) strlcat(str, ", ", sizeof (str));
234 	(void) strlcat(str, time_to_string(status->if_t1), sizeof (str));
235 	(void) strlcat(str, ")\n", sizeof (str));
236 	return (str);
237 }
238