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