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