xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.sbin/ndd.c (revision 7257d1b4)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Copyright (c) 1990  Mentat Inc.
28  * ndd.c 2.1, last change 11/14/90
29  */
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 #include <stdio.h>
34 #include <errno.h>
35 #include <ctype.h>
36 #include <stdarg.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <sys/types.h>
40 #include <stropts.h>
41 #include <inet/nd.h>
42 #include <string.h>
43 #include <stdlib.h>
44 #include <libdllink.h>
45 #include <libintl.h>
46 
47 static boolean_t do_getset(int fd, int cmd, char *buf, int buf_len);
48 static int	get_value(char *msg, char *buf, int buf_len);
49 static void	name_print(char *buf);
50 static void	getset_interactive(int fd);
51 static int	open_device(void);
52 static char	*errmsg(int err);
53 static void	fatal(char *fmt, ...);
54 static void	printe(boolean_t print_errno, char *fmt, ...);
55 
56 static char	gbuf[65536];	/* Need 20k for 160 IREs ... */
57 static char	usage_str[] =	"usage: ndd -set device_name name value\n"
58 				"       ndd [-get] device_name name [name ...]";
59 
60 static void
61 gldv3_warning(char *module)
62 {
63 	datalink_id_t	linkid;
64 	dladm_status_t	status;
65 	char		buf[DLADM_PROP_VAL_MAX], *cp;
66 	uint_t		cnt;
67 	char		*link;
68 
69 	link = strrchr(module, '/');
70 	if (link == NULL)
71 		return;
72 	status = dladm_name2info(++link, &linkid,
73 	    NULL, NULL, NULL);
74 	if (status != DLADM_STATUS_OK)
75 		return;
76 	cp = buf;
77 	status = dladm_get_linkprop(linkid, DLADM_PROP_VAL_CURRENT, "flowctrl",
78 	    &cp, &cnt);
79 	if (status != DLADM_STATUS_OK)
80 		return;
81 	(void) fprintf(stderr, gettext(
82 	    "WARNING: The ndd commands for datalink administration "
83 	    "are obsolete and may be removed in a future release of "
84 	    "Solaris. Use dladm(1M) to manage datalink tunables.\n"));
85 }
86 
87 /* ARGSUSED */
88 int
89 main(int argc, char **argv)
90 {
91 	char	*cp, *value;
92 	int	cmd;
93 	int	fd;
94 
95 
96 	if (!(cp = *++argv)) {
97 		while ((fd = open_device()) != -1) {
98 			getset_interactive(fd);
99 			(void) close(fd);
100 		}
101 		return (EXIT_SUCCESS);
102 	}
103 
104 	cmd = ND_GET;
105 	if (cp[0] == '-') {
106 		if (strncmp(&cp[1], "set", 3) == 0)
107 			cmd = ND_SET;
108 		else if (strncmp(&cp[1], "get", 3) != 0)
109 			fatal(usage_str);
110 		if (!(cp = *++argv))
111 			fatal(usage_str);
112 	}
113 	gldv3_warning(cp);
114 	if ((fd = open(cp, O_RDWR)) == -1)
115 		fatal("open of %s failed: %s", cp, errmsg(errno));
116 
117 	if (!isastream(fd))
118 		fatal("%s is not a streams device", cp);
119 
120 	if (!(cp = *++argv)) {
121 		getset_interactive(fd);
122 		(void) close(fd);
123 		return (EXIT_SUCCESS);
124 	}
125 
126 	if (cmd == ND_SET) {
127 		if (!(value = *++argv))
128 			fatal(usage_str);
129 		(void) snprintf(gbuf, sizeof (gbuf), "%s%c%s%c", cp, '\0',
130 		    value, '\0');
131 		if (!do_getset(fd, cmd, gbuf, sizeof (gbuf)))
132 			return (EXIT_FAILURE);
133 	} else {
134 		do {
135 			(void) memset(gbuf, '\0', sizeof (gbuf));
136 			(void) strlcpy(gbuf, cp, sizeof (gbuf));
137 			if (!do_getset(fd, cmd, gbuf, sizeof (gbuf)))
138 				return (EXIT_FAILURE);
139 			if (cp = *++argv)
140 				(void) putchar('\n');
141 		} while (cp);
142 	}
143 
144 	(void) close(fd);
145 	return (EXIT_SUCCESS);
146 }
147 
148 static void
149 name_print(char *buf)
150 {
151 	char *cp, *rwtag;
152 
153 	for (cp = buf; cp[0]; ) {
154 		for (rwtag = cp; !isspace(*rwtag); rwtag++)
155 			;
156 		*rwtag++ = '\0';
157 		while (isspace(*rwtag))
158 			rwtag++;
159 		(void) printf("%-30s%s\n", cp, rwtag);
160 		for (cp = rwtag; *cp++; )
161 			;
162 	}
163 }
164 
165 /*
166  * This function is vile, but it's better here than in the kernel.
167  */
168 static boolean_t
169 is_obsolete(const char *param)
170 {
171 	if (strcmp(param, "ip_enable_group_ifs") == 0 ||
172 	    strcmp(param, "ifgrp_status") == 0) {
173 		(void) fprintf(stderr, "The \"%s\" tunable has been superseded "
174 		    "by IP Multipathing.\nPlease see the IP Network "
175 		    "Multipathing Administration Guide for details.\n", param);
176 		return (B_TRUE);
177 	}
178 	return (B_FALSE);
179 }
180 
181 static boolean_t
182 do_getset(int fd, int cmd, char *buf, int buf_len)
183 {
184 	char	*cp;
185 	struct strioctl	stri;
186 	boolean_t	is_name_get;
187 
188 	if (is_obsolete(buf))
189 		return (B_TRUE);
190 
191 	stri.ic_cmd = cmd;
192 	stri.ic_timout = 0;
193 	stri.ic_len = buf_len;
194 	stri.ic_dp = buf;
195 	is_name_get = stri.ic_cmd == ND_GET && buf[0] == '?' && buf[1] == '\0';
196 
197 	if (ioctl(fd, I_STR, &stri) == -1) {
198 		if (errno == ENOENT)
199 			(void) printf("name is non-existent for this module\n"
200 			    "for a list of valid names, use name '?'\n");
201 		else
202 			(void) printf("operation failed: %s\n", errmsg(errno));
203 		return (B_FALSE);
204 	}
205 	if (is_name_get)
206 		name_print(buf);
207 	else if (stri.ic_cmd == ND_GET) {
208 		for (cp = buf; *cp != '\0'; cp += strlen(cp) + 1)
209 			(void) puts(cp);
210 	}
211 	(void) fflush(stdout);
212 	return (B_TRUE);
213 }
214 
215 static int
216 get_value(char *msg, char *buf, int buf_len)
217 {
218 	int	len;
219 
220 	(void) printf("%s", msg);
221 	(void) fflush(stdout);
222 
223 	buf[buf_len-1] = '\0';
224 	if (fgets(buf, buf_len-1, stdin) == NULL)
225 		exit(EXIT_SUCCESS);
226 	len = strlen(buf);
227 	if (buf[len-1] == '\n')
228 		buf[len - 1] = '\0';
229 	else
230 		len++;
231 	return (len);
232 }
233 
234 static void
235 getset_interactive(int fd)
236 {
237 	int	cmd;
238 	char	*cp;
239 	int	len, buf_len;
240 	char	len_buf[10];
241 
242 	for (;;) {
243 		(void) memset(gbuf, '\0', sizeof (gbuf));
244 		len = get_value("name to get/set ? ", gbuf, sizeof (gbuf));
245 		if (len == 1 || (gbuf[0] == 'q' && gbuf[1] == '\0'))
246 			return;
247 		for (cp = gbuf; cp < &gbuf[len]; cp++) {
248 			if (isspace(*cp))
249 				*cp = '\0';
250 		}
251 		cmd = ND_GET;
252 		if (gbuf[0] != '?' &&
253 		    get_value("value ? ", &gbuf[len], sizeof (gbuf) - len) > 1)
254 			cmd = ND_SET;
255 		if (cmd == ND_GET && gbuf[0] != '?' &&
256 		    get_value("length ? ", len_buf, sizeof (len_buf)) > 1) {
257 			if (!isdigit(len_buf[0])) {
258 				(void) printf("invalid length\n");
259 				continue;
260 			}
261 			buf_len = atoi(len_buf);
262 		} else
263 			buf_len = sizeof (gbuf);
264 		(void) do_getset(fd, cmd, gbuf, buf_len);
265 	}
266 }
267 
268 static void
269 printe(boolean_t print_errno, char *fmt, ...)
270 {
271 	va_list	ap;
272 	int error = errno;
273 
274 	va_start(ap, fmt);
275 	(void) printf("*ERROR* ");
276 	(void) vprintf(fmt, ap);
277 	va_end(ap);
278 
279 	if (print_errno)
280 		(void) printf(": %s\n", errmsg(error));
281 	else
282 		(void) printf("\n");
283 }
284 
285 
286 static int
287 open_device(void)
288 {
289 	char	name[80];
290 	int	fd, len;
291 
292 	for (;;) {
293 		len = get_value("module to query ? ", name, sizeof (name));
294 		if (len <= 1 ||
295 		    (len == 2 && (name[0] == 'q' || name[0] == 'Q')))
296 			return (-1);
297 
298 		if ((fd = open(name, O_RDWR)) == -1) {
299 			printe(B_TRUE, "open of %s failed", name);
300 			continue;
301 		}
302 
303 		gldv3_warning(name);
304 
305 		if (isastream(fd))
306 			return (fd);
307 
308 		(void) close(fd);
309 		printe(B_FALSE, "%s is not a streams device", name);
310 	}
311 }
312 
313 static void
314 fatal(char *fmt, ...)
315 {
316 	va_list	ap;
317 
318 	va_start(ap, fmt);
319 	(void) vfprintf(stderr, fmt, ap);
320 	va_end(ap);
321 	(void) fprintf(stderr, "\n");
322 
323 	exit(EXIT_FAILURE);
324 }
325 
326 static char *
327 errmsg(int error)
328 {
329 	char *msg = strerror(error);
330 
331 	return (msg != NULL ? msg : "unknown error");
332 }
333