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