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