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