xref: /titanic_52/usr/src/cmd/cmd-inet/sbin/dhcpinfo/dhcpinfo.c (revision c2580b931007758eab8cb5ae8726ebe1588e259b)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright (c) 1999-2001 by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <ctype.h>
33 #include <dhcpagent_ipc.h>
34 #include <dhcp_inittab.h>
35 #include <dhcp_symbol.h>
36 
37 #define	DHCP_INFO_VENDOR_START	256
38 
39 static void
40 usage(const char *program)
41 {
42 	(void) fprintf(stderr,
43 	    "usage: %s [-i interface] [-n limit] [-c] code\n"
44 	    "       %s [-i interface] [-n limit] [-c] identifier\n",
45 	    program, program);
46 
47 	exit(DHCP_EXIT_BADARGS);
48 }
49 
50 int
51 main(int argc, char **argv)
52 {
53 	ssize_t			max_lines = -1;
54 	size_t			gran, n_spaces = 0;
55 	dhcp_optnum_t		optnum;
56 	dhcp_ipc_request_t	*request;
57 	dhcp_ipc_reply_t	*reply;
58 	int			c, error, i;
59 	char			*ifname = "";
60 	char			*value, *valuep;
61 	dhcp_symbol_t		*entry;
62 	DHCP_OPT		*opt;
63 	size_t			opt_len;
64 	boolean_t		is_canonical = B_FALSE;
65 
66 	while ((c = getopt(argc, argv, "cn:i:")) != EOF) {
67 
68 		switch (c) {
69 
70 		case 'c':
71 			is_canonical = B_TRUE;
72 			break;
73 
74 		case 'i':
75 			ifname = optarg;
76 			break;
77 
78 		case 'n':
79 			max_lines = strtoul(optarg, NULL, 0);
80 			break;
81 
82 		case '?':
83 			usage(argv[0]);
84 
85 		default:
86 			break;
87 		}
88 	}
89 
90 	if (argc - optind != 1)
91 		usage(argv[0]);
92 
93 	/*
94 	 * we either have a code or an identifer.  if we have a code,
95 	 * then values over 256 indicate a vendor option.  if we have
96 	 * an identifier, then use inittab_getbyname() to turn the
97 	 * identifier into a code, then send the request over the wire.
98 	 */
99 
100 	if (isalpha(*argv[optind])) {
101 
102 		entry = inittab_getbyname(ITAB_CAT_SITE|ITAB_CAT_STANDARD|
103 		    ITAB_CAT_VENDOR|ITAB_CAT_FIELD, ITAB_CONS_INFO,
104 		    argv[optind]);
105 
106 		if (entry == NULL) {
107 			(void) fprintf(stderr, "%s: unknown identifier `%s'\n",
108 			    argv[0], argv[optind]);
109 			return (DHCP_EXIT_BADARGS);
110 		}
111 
112 		optnum.code	= entry->ds_code;
113 		optnum.category = entry->ds_category;
114 
115 	} else {
116 
117 		optnum.code	= strtoul(argv[optind], 0, 0);
118 		optnum.category = ITAB_CAT_STANDARD|ITAB_CAT_SITE;
119 
120 		/*
121 		 * sigh.  this is a hack, but it's needed for backward
122 		 * compatibility with the CA dhcpinfo program.
123 		 */
124 
125 		if (optnum.code > DHCP_INFO_VENDOR_START) {
126 			optnum.code    -= DHCP_INFO_VENDOR_START;
127 			optnum.category = ITAB_CAT_VENDOR;
128 		}
129 
130 		entry = inittab_getbycode(optnum.category, ITAB_CONS_INFO,
131 		    optnum.code);
132 
133 		if (entry == NULL) {
134 			(void) fprintf(stderr, "%s: unknown code `%s'\n",
135 			    argv[0], argv[optind]);
136 			return (DHCP_EXIT_BADARGS);
137 		}
138 		optnum.category = entry->ds_category;
139 	}
140 
141 	optnum.size = entry->ds_max * inittab_type_to_size(entry);
142 
143 	/*
144 	 * send the request to the agent and reap the reply
145 	 */
146 
147 	request = dhcp_ipc_alloc_request(DHCP_GET_TAG, ifname, &optnum,
148 	    sizeof (dhcp_optnum_t), DHCP_TYPE_OPTNUM);
149 
150 	if (request == NULL)
151 		return (DHCP_EXIT_SYSTEM);
152 
153 	error = dhcp_ipc_make_request(request, &reply, DHCP_IPC_WAIT_DEFAULT);
154 	if (error != 0 || reply->return_code != 0) {
155 
156 		if (error == 0)
157 			error = reply->return_code;
158 
159 		(void) fprintf(stderr, "%s: %s\n", argv[0],
160 		    dhcp_ipc_strerror(error));
161 
162 		if (error == DHCP_IPC_E_TIMEOUT)
163 			return (DHCP_EXIT_TIMEOUT);
164 
165 		return (DHCP_EXIT_FAILURE);
166 	}
167 
168 	opt = dhcp_ipc_get_data(reply, &opt_len, NULL);
169 
170 	/*
171 	 * no data means that the client has an ACK but has no information
172 	 * about the specified option; return success
173 	 */
174 
175 	if (opt_len == 0)
176 		return (DHCP_EXIT_SUCCESS);
177 
178 	/*
179 	 * check for protocol error
180 	 */
181 
182 	if (opt_len < 2 || (opt_len - 2 != opt->len))
183 		return (DHCP_EXIT_FAILURE);
184 
185 	if (is_canonical) {
186 
187 		value = malloc(opt->len * (sizeof ("0xNN") + 1));
188 		if (value == NULL) {
189 			(void) fprintf(stderr, "%s: out of memory\n", argv[0]);
190 			return (DHCP_EXIT_FAILURE);
191 		}
192 
193 		for (i = 0, valuep = value; i < opt->len; i++)
194 			valuep += sprintf(valuep, "0x%02X ", opt->value[i]);
195 
196 		valuep[-1] = '\0';
197 		gran = 1;
198 
199 	} else {
200 
201 		value = inittab_decode(entry, opt->value, opt->len, B_TRUE);
202 		if (value == NULL) {
203 			(void) fprintf(stderr, "%s: cannot decode agent's "
204 			    "reply\n", argv[0]);
205 			return (DHCP_EXIT_FAILURE);
206 		}
207 
208 		gran = entry->ds_gran;
209 	}
210 
211 	/*
212 	 * now display `gran' items per line, printing at most `max_lines'.
213 	 */
214 
215 	for (i = 0; value[i] != '\0'; i++) {
216 		if (value[i] == ' ') {
217 			if ((++n_spaces % gran) == 0) {
218 				value[i] = '\n';
219 				if (max_lines != -1 && --max_lines == 0) {
220 					value[i] = '\0';
221 					break;
222 				}
223 			}
224 		}
225 	}
226 
227 	(void) printf("%s\n", value);
228 
229 	return (DHCP_EXIT_SUCCESS);
230 }
231