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