xref: /titanic_44/usr/src/cmd/cmd-inet/usr.sbin/ndd.c (revision 6e91bba0d6c6bdabbba62cefae583715a4a58e2a)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
54045d941Ssowmini  * Common Development and Distribution License (the "License").
64045d941Ssowmini  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*6e91bba0SGirish Moodalbail  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * Copyright (c) 1990  Mentat Inc.
287c478bd9Sstevel@tonic-gate  * ndd.c 2.1, last change 11/14/90
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <stdio.h>
327c478bd9Sstevel@tonic-gate #include <errno.h>
337c478bd9Sstevel@tonic-gate #include <ctype.h>
347c478bd9Sstevel@tonic-gate #include <stdarg.h>
357c478bd9Sstevel@tonic-gate #include <fcntl.h>
367c478bd9Sstevel@tonic-gate #include <unistd.h>
377c478bd9Sstevel@tonic-gate #include <sys/types.h>
387c478bd9Sstevel@tonic-gate #include <stropts.h>
39*6e91bba0SGirish Moodalbail #include <inet/tunables.h>
407c478bd9Sstevel@tonic-gate #include <inet/nd.h>
417c478bd9Sstevel@tonic-gate #include <string.h>
42*6e91bba0SGirish Moodalbail #include <strings.h>
437c478bd9Sstevel@tonic-gate #include <stdlib.h>
444045d941Ssowmini #include <libdllink.h>
454045d941Ssowmini #include <libintl.h>
46*6e91bba0SGirish Moodalbail #include <libipadm.h>
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate static boolean_t do_getset(int fd, int cmd, char *buf, int buf_len);
497c478bd9Sstevel@tonic-gate static int	get_value(char *msg, char *buf, int buf_len);
507c478bd9Sstevel@tonic-gate static void	name_print(char *buf);
517c478bd9Sstevel@tonic-gate static void	getset_interactive(int fd);
52a924b63fSVasumathi Sundaram - Sun Microsystems static int	open_device(void);
537c478bd9Sstevel@tonic-gate static char	*errmsg(int err);
547c478bd9Sstevel@tonic-gate static void	fatal(char *fmt, ...);
557c478bd9Sstevel@tonic-gate static void	printe(boolean_t print_errno, char *fmt, ...);
567c478bd9Sstevel@tonic-gate 
57*6e91bba0SGirish Moodalbail static char	modpath[128];	/* path to module */
58*6e91bba0SGirish Moodalbail static char	gbuf[65536];	/* need large buffer to retrieve all names */
597c478bd9Sstevel@tonic-gate static char	usage_str[] =	"usage: ndd -set device_name name value\n"
607c478bd9Sstevel@tonic-gate 				"       ndd [-get] device_name name [name ...]";
617c478bd9Sstevel@tonic-gate 
62149b7eb2SSowmini Varadhan /*
63*6e91bba0SGirish Moodalbail  * Maps old ndd_name to the new ipadm_name. Any ndd property that is moved to
64*6e91bba0SGirish Moodalbail  * libipadm should have an entry here to ensure backward compatibility
65*6e91bba0SGirish Moodalbail  */
66*6e91bba0SGirish Moodalbail typedef struct ndd2ipadm_map {
67*6e91bba0SGirish Moodalbail 	char	*ndd_name;
68*6e91bba0SGirish Moodalbail 	char	*ipadm_name;
69*6e91bba0SGirish Moodalbail 	uint_t	ipadm_proto;
70*6e91bba0SGirish Moodalbail 	uint_t	ipadm_flags;
71*6e91bba0SGirish Moodalbail 	uint_t	ndd_perm;
72*6e91bba0SGirish Moodalbail } ndd2ipadm_map_t;
73*6e91bba0SGirish Moodalbail 
74*6e91bba0SGirish Moodalbail static ndd2ipadm_map_t map[] = {
75*6e91bba0SGirish Moodalbail 	{ "ip_def_ttl",			"ttl",		MOD_PROTO_IPV4, 0, 0 },
76*6e91bba0SGirish Moodalbail 	{ "ip6_def_hops",		"hoplimit",	MOD_PROTO_IPV6, 0, 0 },
77*6e91bba0SGirish Moodalbail 	{ "ip_forwarding",		"forwarding",	MOD_PROTO_IPV4, 0, 0 },
78*6e91bba0SGirish Moodalbail 	{ "ip6_forwarding",		"forwarding",	MOD_PROTO_IPV6, 0, 0 },
79*6e91bba0SGirish Moodalbail 	{ "icmp_recv_hiwat",		"recv_maxbuf",	MOD_PROTO_RAWIP, 0, 0 },
80*6e91bba0SGirish Moodalbail 	{ "icmp_xmit_hiwat",		"send_maxbuf",	MOD_PROTO_RAWIP, 0, 0 },
81*6e91bba0SGirish Moodalbail 	{ "tcp_ecn_permitted",		"ecn",		MOD_PROTO_TCP, 0, 0 },
82*6e91bba0SGirish Moodalbail 	{ "tcp_extra_priv_ports_add",	"extra_priv_ports",	MOD_PROTO_TCP,
83*6e91bba0SGirish Moodalbail 	    IPADM_OPT_APPEND, MOD_PROP_PERM_WRITE },
84*6e91bba0SGirish Moodalbail 	{ "tcp_extra_priv_ports_del",	"extra_priv_ports",	MOD_PROTO_TCP,
85*6e91bba0SGirish Moodalbail 	    IPADM_OPT_REMOVE, MOD_PROP_PERM_WRITE },
86*6e91bba0SGirish Moodalbail 	{ "tcp_extra_priv_ports",	"extra_priv_ports",	MOD_PROTO_TCP,
87*6e91bba0SGirish Moodalbail 	    0, MOD_PROP_PERM_READ },
88*6e91bba0SGirish Moodalbail 	{ "tcp_largest_anon_port",	"largest_anon_port",	MOD_PROTO_TCP,
89*6e91bba0SGirish Moodalbail 	    0, 0 },
90*6e91bba0SGirish Moodalbail 	{ "tcp_recv_hiwat",		"recv_maxbuf",	MOD_PROTO_TCP, 0, 0 },
91*6e91bba0SGirish Moodalbail 	{ "tcp_sack_permitted",		"sack",		MOD_PROTO_TCP, 0, 0 },
92*6e91bba0SGirish Moodalbail 	{ "tcp_xmit_hiwat",		"send_maxbuf",	MOD_PROTO_TCP, 0, 0 },
93*6e91bba0SGirish Moodalbail 	{ "tcp_smallest_anon_port",	"smallest_anon_port",	MOD_PROTO_TCP,
94*6e91bba0SGirish Moodalbail 	    0, 0 },
95*6e91bba0SGirish Moodalbail 	{ "tcp_smallest_nonpriv_port",	"smallest_nonpriv_port", MOD_PROTO_TCP,
96*6e91bba0SGirish Moodalbail 	    0, 0 },
97*6e91bba0SGirish Moodalbail 	{ "udp_extra_priv_ports_add",	"extra_priv_ports",	MOD_PROTO_UDP,
98*6e91bba0SGirish Moodalbail 	    IPADM_OPT_APPEND, MOD_PROP_PERM_WRITE },
99*6e91bba0SGirish Moodalbail 	{ "udp_extra_priv_ports_del",	"extra_priv_ports",	MOD_PROTO_UDP,
100*6e91bba0SGirish Moodalbail 	    IPADM_OPT_REMOVE, MOD_PROP_PERM_WRITE },
101*6e91bba0SGirish Moodalbail 	{ "udp_extra_priv_ports",	"extra_priv_ports",	MOD_PROTO_UDP,
102*6e91bba0SGirish Moodalbail 	    0, MOD_PROP_PERM_READ },
103*6e91bba0SGirish Moodalbail 	{ "udp_largest_anon_port",	"largest_anon_port",    MOD_PROTO_UDP,
104*6e91bba0SGirish Moodalbail 	    0, 0 },
105*6e91bba0SGirish Moodalbail 	{ "udp_recv_hiwat",		"recv_maxbuf",	MOD_PROTO_UDP, 0, 0 },
106*6e91bba0SGirish Moodalbail 	{ "udp_xmit_hiwat",		"send_maxbuf",	MOD_PROTO_UDP, 0, 0 },
107*6e91bba0SGirish Moodalbail 	{ "udp_smallest_anon_port",	"smallest_anon_port",	MOD_PROTO_UDP,
108*6e91bba0SGirish Moodalbail 	    0, 0 },
109*6e91bba0SGirish Moodalbail 	{ "udp_smallest_nonpriv_port",	"smallest_nonpriv_port", MOD_PROTO_UDP,
110*6e91bba0SGirish Moodalbail 	    0, 0 },
111*6e91bba0SGirish Moodalbail 	{ "sctp_extra_priv_ports_add",	"extra_priv_ports",	MOD_PROTO_SCTP,
112*6e91bba0SGirish Moodalbail 	    IPADM_OPT_APPEND, MOD_PROP_PERM_WRITE },
113*6e91bba0SGirish Moodalbail 	{ "sctp_extra_priv_ports_del",	"extra_priv_ports",	MOD_PROTO_SCTP,
114*6e91bba0SGirish Moodalbail 	    IPADM_OPT_REMOVE, MOD_PROP_PERM_WRITE },
115*6e91bba0SGirish Moodalbail 	{ "sctp_extra_priv_ports",	"extra_priv_ports",	MOD_PROTO_SCTP,
116*6e91bba0SGirish Moodalbail 	    0, MOD_PROP_PERM_READ },
117*6e91bba0SGirish Moodalbail 	{ "sctp_largest_anon_port",	"largest_anon_port",	MOD_PROTO_SCTP,
118*6e91bba0SGirish Moodalbail 	    0, 0 },
119*6e91bba0SGirish Moodalbail 	{ "sctp_recv_hiwat",		"recv_maxbuf",	MOD_PROTO_SCTP, 0, 0 },
120*6e91bba0SGirish Moodalbail 	{ "sctp_xmit_hiwat",		"send_maxbuf",	MOD_PROTO_SCTP, 0, 0 },
121*6e91bba0SGirish Moodalbail 	{ "sctp_smallest_anon_port",	"smallest_anon_port",	MOD_PROTO_SCTP,
122*6e91bba0SGirish Moodalbail 	    0, 0 },
123*6e91bba0SGirish Moodalbail 	{ "sctp_smallest_nonpriv_port",	"smallest_nonpriv_port", MOD_PROTO_SCTP,
124*6e91bba0SGirish Moodalbail 	    0, 0 },
125*6e91bba0SGirish Moodalbail 	{ NULL, NULL, 0, 0, 0 }
126*6e91bba0SGirish Moodalbail };
127*6e91bba0SGirish Moodalbail 
128*6e91bba0SGirish Moodalbail static uint_t
129*6e91bba0SGirish Moodalbail ndd_str2proto(const char *protostr)
130*6e91bba0SGirish Moodalbail {
131*6e91bba0SGirish Moodalbail 	if (strcmp(protostr, "tcp") == 0 ||
132*6e91bba0SGirish Moodalbail 	    strcmp(protostr, "tcp6") == 0) {
133*6e91bba0SGirish Moodalbail 		return (MOD_PROTO_TCP);
134*6e91bba0SGirish Moodalbail 	} else if (strcmp(protostr, "udp") == 0 ||
135*6e91bba0SGirish Moodalbail 	    strcmp(protostr, "udp6") == 0) {
136*6e91bba0SGirish Moodalbail 		return (MOD_PROTO_UDP);
137*6e91bba0SGirish Moodalbail 	} else if (strcmp(protostr, "ip") == 0 ||
138*6e91bba0SGirish Moodalbail 	    strcmp(protostr, "ip6") == 0 ||
139*6e91bba0SGirish Moodalbail 	    strcmp(protostr, "arp") == 0) {
140*6e91bba0SGirish Moodalbail 		return (MOD_PROTO_IP);
141*6e91bba0SGirish Moodalbail 	} else if (strcmp(protostr, "icmp") == 0 ||
142*6e91bba0SGirish Moodalbail 	    strcmp(protostr, "icmp6") == 0) {
143*6e91bba0SGirish Moodalbail 		return (MOD_PROTO_RAWIP);
144*6e91bba0SGirish Moodalbail 	} else if (strcmp(protostr, "sctp") == 0 ||
145*6e91bba0SGirish Moodalbail 	    strcmp(protostr, "sctp6") == 0) {
146*6e91bba0SGirish Moodalbail 		return (MOD_PROTO_SCTP);
147*6e91bba0SGirish Moodalbail 	}
148*6e91bba0SGirish Moodalbail 	return (MOD_PROTO_NONE);
149*6e91bba0SGirish Moodalbail }
150*6e91bba0SGirish Moodalbail 
151*6e91bba0SGirish Moodalbail static char *
152*6e91bba0SGirish Moodalbail ndd_perm2str(uint_t perm)
153*6e91bba0SGirish Moodalbail {
154*6e91bba0SGirish Moodalbail 	switch (perm) {
155*6e91bba0SGirish Moodalbail 	case MOD_PROP_PERM_READ:
156*6e91bba0SGirish Moodalbail 		return ("read only");
157*6e91bba0SGirish Moodalbail 	case MOD_PROP_PERM_WRITE:
158*6e91bba0SGirish Moodalbail 		return ("write only");
159*6e91bba0SGirish Moodalbail 	case MOD_PROP_PERM_RW:
160*6e91bba0SGirish Moodalbail 		return ("read and write");
161*6e91bba0SGirish Moodalbail 	}
162*6e91bba0SGirish Moodalbail 
163*6e91bba0SGirish Moodalbail 	return (NULL);
164*6e91bba0SGirish Moodalbail }
165*6e91bba0SGirish Moodalbail 
166*6e91bba0SGirish Moodalbail /*
167*6e91bba0SGirish Moodalbail  * This function converts any new property names to old ndd name by consulting
168*6e91bba0SGirish Moodalbail  * ndd2ipadm_map_t. This is done to preserve backward compatibility.
169*6e91bba0SGirish Moodalbail  */
170*6e91bba0SGirish Moodalbail static void
171*6e91bba0SGirish Moodalbail print_ipadm2ndd(char *oldbuf, uint_t obufsize)
172*6e91bba0SGirish Moodalbail {
173*6e91bba0SGirish Moodalbail 	ndd2ipadm_map_t	*nimap;
174*6e91bba0SGirish Moodalbail 	char		*pname, *rwtag, *protostr;
175*6e91bba0SGirish Moodalbail 	uint_t		proto, perm;
176*6e91bba0SGirish Moodalbail 	boolean_t	matched;
177*6e91bba0SGirish Moodalbail 
178*6e91bba0SGirish Moodalbail 	pname = oldbuf;
179*6e91bba0SGirish Moodalbail 	while (pname[0] && pname < (oldbuf + obufsize - 1)) {
180*6e91bba0SGirish Moodalbail 		for (protostr = pname; !isspace(*protostr); protostr++)
181*6e91bba0SGirish Moodalbail 			;
182*6e91bba0SGirish Moodalbail 		*protostr++ = '\0';
183*6e91bba0SGirish Moodalbail 		/* protostr now points to protocol */
184*6e91bba0SGirish Moodalbail 
185*6e91bba0SGirish Moodalbail 		for (rwtag = protostr; !isspace(*rwtag); rwtag++)
186*6e91bba0SGirish Moodalbail 			;
187*6e91bba0SGirish Moodalbail 		*rwtag++ = '\0';
188*6e91bba0SGirish Moodalbail 		/* rwtag now points to permissions */
189*6e91bba0SGirish Moodalbail 
190*6e91bba0SGirish Moodalbail 		proto = atoi(protostr);
191*6e91bba0SGirish Moodalbail 		perm = atoi(rwtag);
192*6e91bba0SGirish Moodalbail 		matched = B_FALSE;
193*6e91bba0SGirish Moodalbail 		for (nimap = map; nimap->ndd_name != NULL; nimap++) {
194*6e91bba0SGirish Moodalbail 			if (strcmp(pname, nimap->ipadm_name) != 0 ||
195*6e91bba0SGirish Moodalbail 			    !(nimap->ipadm_proto & proto))
196*6e91bba0SGirish Moodalbail 				continue;
197*6e91bba0SGirish Moodalbail 
198*6e91bba0SGirish Moodalbail 			matched = B_TRUE;
199*6e91bba0SGirish Moodalbail 			if (nimap->ndd_perm != 0)
200*6e91bba0SGirish Moodalbail 				perm = nimap->ndd_perm;
201*6e91bba0SGirish Moodalbail 			(void) printf("%-30s (%s)\n", nimap->ndd_name,
202*6e91bba0SGirish Moodalbail 			    ndd_perm2str(perm));
203*6e91bba0SGirish Moodalbail 		}
204*6e91bba0SGirish Moodalbail 		if (!matched)
205*6e91bba0SGirish Moodalbail 			(void) printf("%-30s (%s)\n", pname,
206*6e91bba0SGirish Moodalbail 			    ndd_perm2str(perm));
207*6e91bba0SGirish Moodalbail 		for (pname = rwtag; *pname++; )
208*6e91bba0SGirish Moodalbail 			;
209*6e91bba0SGirish Moodalbail 	}
210*6e91bba0SGirish Moodalbail }
211*6e91bba0SGirish Moodalbail 
212*6e91bba0SGirish Moodalbail /*
213*6e91bba0SGirish Moodalbail  * get/set the value for a given property by calling into libipadm. The
214*6e91bba0SGirish Moodalbail  * IPH_LEGACY flag is used by libipadm for special handling. For some
215*6e91bba0SGirish Moodalbail  * properties, libipadm.so displays strings (for e.g., on/off,
216*6e91bba0SGirish Moodalbail  * never/passive/active, et al) instead of numerals. However ndd(1M) always
217*6e91bba0SGirish Moodalbail  * printed numberals. This flag will help in avoiding printing strings.
218*6e91bba0SGirish Moodalbail  */
219*6e91bba0SGirish Moodalbail static boolean_t
220*6e91bba0SGirish Moodalbail do_ipadm_getset(int cmd, char *buf, int buflen)
221*6e91bba0SGirish Moodalbail {
222*6e91bba0SGirish Moodalbail 	ndd2ipadm_map_t	*nimap;
223*6e91bba0SGirish Moodalbail 	ipadm_handle_t	iph = NULL;
224*6e91bba0SGirish Moodalbail 	ipadm_status_t	status;
225*6e91bba0SGirish Moodalbail 	char		*mod;
226*6e91bba0SGirish Moodalbail 	uint_t		proto, perm = 0, flags = 0;
227*6e91bba0SGirish Moodalbail 	char		*pname, *pvalp;
228*6e91bba0SGirish Moodalbail 	int		i;
229*6e91bba0SGirish Moodalbail 
230*6e91bba0SGirish Moodalbail 	if ((mod = strrchr(modpath, '/')) == NULL)
231*6e91bba0SGirish Moodalbail 		mod = modpath;
232*6e91bba0SGirish Moodalbail 	else
233*6e91bba0SGirish Moodalbail 		++mod;
234*6e91bba0SGirish Moodalbail 	if ((proto = ndd_str2proto(mod)) == MOD_PROTO_NONE)
235*6e91bba0SGirish Moodalbail 		return (B_FALSE);
236*6e91bba0SGirish Moodalbail 
237*6e91bba0SGirish Moodalbail 	if ((status = ipadm_open(&iph, IPH_LEGACY)) != IPADM_SUCCESS)
238*6e91bba0SGirish Moodalbail 		goto fail;
239*6e91bba0SGirish Moodalbail 
240*6e91bba0SGirish Moodalbail 	pname = buf;
241*6e91bba0SGirish Moodalbail 	for (nimap = map; nimap->ndd_name != NULL; nimap++) {
242*6e91bba0SGirish Moodalbail 		if (strcmp(pname, nimap->ndd_name) == 0)
243*6e91bba0SGirish Moodalbail 			break;
244*6e91bba0SGirish Moodalbail 	}
245*6e91bba0SGirish Moodalbail 	if (nimap->ndd_name != NULL) {
246*6e91bba0SGirish Moodalbail 		pname = nimap->ipadm_name;
247*6e91bba0SGirish Moodalbail 		proto = nimap->ipadm_proto;
248*6e91bba0SGirish Moodalbail 		flags = nimap->ipadm_flags;
249*6e91bba0SGirish Moodalbail 		perm = nimap->ndd_perm;
250*6e91bba0SGirish Moodalbail 	}
251*6e91bba0SGirish Moodalbail 	if (cmd == ND_GET) {
252*6e91bba0SGirish Moodalbail 		char		propval[MAXPROPVALLEN], allprop[64536];
253*6e91bba0SGirish Moodalbail 		uint_t		pvalsz;
254*6e91bba0SGirish Moodalbail 		sa_family_t	af = AF_UNSPEC;
255*6e91bba0SGirish Moodalbail 		int		err;
256*6e91bba0SGirish Moodalbail 
257*6e91bba0SGirish Moodalbail 		if (perm == MOD_PROP_PERM_WRITE)
258*6e91bba0SGirish Moodalbail 			fatal("operation failed: Permission denied");
259*6e91bba0SGirish Moodalbail 
260*6e91bba0SGirish Moodalbail 		if (strcmp(pname, "?") == 0) {
261*6e91bba0SGirish Moodalbail 			pvalp = allprop;
262*6e91bba0SGirish Moodalbail 			pvalsz = sizeof (allprop);
263*6e91bba0SGirish Moodalbail 		} else {
264*6e91bba0SGirish Moodalbail 			pvalp = propval;
265*6e91bba0SGirish Moodalbail 			pvalsz = sizeof (propval);
266*6e91bba0SGirish Moodalbail 		}
267*6e91bba0SGirish Moodalbail 
268*6e91bba0SGirish Moodalbail 		status = ipadm_get_prop(iph, pname, pvalp, &pvalsz, proto,
269*6e91bba0SGirish Moodalbail 		    IPADM_OPT_ACTIVE);
270*6e91bba0SGirish Moodalbail 		if (status != IPADM_SUCCESS)
271*6e91bba0SGirish Moodalbail 			goto fail;
272*6e91bba0SGirish Moodalbail 
273*6e91bba0SGirish Moodalbail 		if (strcmp(pname, "?") == 0) {
274*6e91bba0SGirish Moodalbail 			(void) print_ipadm2ndd(pvalp, pvalsz);
275*6e91bba0SGirish Moodalbail 		} else {
276*6e91bba0SGirish Moodalbail 			char *tmp = pvalp;
277*6e91bba0SGirish Moodalbail 
278*6e91bba0SGirish Moodalbail 			/*
279*6e91bba0SGirish Moodalbail 			 * For backward compatibility if there are multiple
280*6e91bba0SGirish Moodalbail 			 * values print each value in it's own line.
281*6e91bba0SGirish Moodalbail 			 */
282*6e91bba0SGirish Moodalbail 			while (*tmp != '\0') {
283*6e91bba0SGirish Moodalbail 				if (*tmp == ',')
284*6e91bba0SGirish Moodalbail 					*tmp = '\n';
285*6e91bba0SGirish Moodalbail 				tmp++;
286*6e91bba0SGirish Moodalbail 			}
287*6e91bba0SGirish Moodalbail 			(void) printf("%s\n", pvalp);
288*6e91bba0SGirish Moodalbail 		}
289*6e91bba0SGirish Moodalbail 		(void) fflush(stdout);
290*6e91bba0SGirish Moodalbail 	} else {
291*6e91bba0SGirish Moodalbail 		if (perm == MOD_PROP_PERM_READ)
292*6e91bba0SGirish Moodalbail 			fatal("operation failed: Permission denied");
293*6e91bba0SGirish Moodalbail 
294*6e91bba0SGirish Moodalbail 		/* walk past the property name to find the property value */
295*6e91bba0SGirish Moodalbail 		for (i = 0; buf[i] != '\0'; i++)
296*6e91bba0SGirish Moodalbail 			;
297*6e91bba0SGirish Moodalbail 
298*6e91bba0SGirish Moodalbail 		pvalp = &buf[++i];
299*6e91bba0SGirish Moodalbail 		status = ipadm_set_prop(iph, pname, pvalp, proto,
300*6e91bba0SGirish Moodalbail 		    flags|IPADM_OPT_ACTIVE);
301*6e91bba0SGirish Moodalbail 	}
302*6e91bba0SGirish Moodalbail fail:
303*6e91bba0SGirish Moodalbail 	ipadm_close(iph);
304*6e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS)
305*6e91bba0SGirish Moodalbail 		fatal("operation failed: %s", ipadm_status2str(status));
306*6e91bba0SGirish Moodalbail 	return (B_TRUE);
307*6e91bba0SGirish Moodalbail }
308*6e91bba0SGirish Moodalbail 
309*6e91bba0SGirish Moodalbail /*
310149b7eb2SSowmini Varadhan  * gldv3_warning() catches the case of /sbin/ndd abuse to administer
311149b7eb2SSowmini Varadhan  * ethernet/MII props. Note that /sbin/ndd has not been abused
312149b7eb2SSowmini Varadhan  * for administration of other datalink types, which makes it permissible
313149b7eb2SSowmini Varadhan  * to test for support of the flowctrl property.
314149b7eb2SSowmini Varadhan  */
3154045d941Ssowmini static void
316a924b63fSVasumathi Sundaram - Sun Microsystems gldv3_warning(char *module)
3174045d941Ssowmini {
3184045d941Ssowmini 	datalink_id_t	linkid;
3194045d941Ssowmini 	dladm_status_t	status;
3204045d941Ssowmini 	char		buf[DLADM_PROP_VAL_MAX], *cp;
321149b7eb2SSowmini Varadhan 	uint_t		cnt = 1;
3224045d941Ssowmini 	char		*link;
323a924b63fSVasumathi Sundaram - Sun Microsystems 	dladm_handle_t	handle;
3244045d941Ssowmini 
3254045d941Ssowmini 	link = strrchr(module, '/');
3264045d941Ssowmini 	if (link == NULL)
3274045d941Ssowmini 		return;
328a924b63fSVasumathi Sundaram - Sun Microsystems 
329a924b63fSVasumathi Sundaram - Sun Microsystems 	if (dladm_open(&handle) != DLADM_STATUS_OK)
330a924b63fSVasumathi Sundaram - Sun Microsystems 		return;
331a924b63fSVasumathi Sundaram - Sun Microsystems 
3324ac67f02SAnurag S. Maskey 	status = dladm_name2info(handle, ++link, &linkid, NULL, NULL, NULL);
333a924b63fSVasumathi Sundaram - Sun Microsystems 	if (status == DLADM_STATUS_OK) {
3344045d941Ssowmini 		cp = buf;
335a924b63fSVasumathi Sundaram - Sun Microsystems 		status = dladm_get_linkprop(handle, linkid,
336a924b63fSVasumathi Sundaram - Sun Microsystems 		    DLADM_PROP_VAL_CURRENT, "flowctrl", &cp, &cnt);
337a924b63fSVasumathi Sundaram - Sun Microsystems 		if (status == DLADM_STATUS_OK) {
3384045d941Ssowmini 			(void) fprintf(stderr, gettext(
339a924b63fSVasumathi Sundaram - Sun Microsystems 			    "WARNING: The ndd commands for datalink "
340a924b63fSVasumathi Sundaram - Sun Microsystems 			    "administration are obsolete and may be "
341a924b63fSVasumathi Sundaram - Sun Microsystems 			    "removed in a future release of Solaris. "
342a924b63fSVasumathi Sundaram - Sun Microsystems 			    "Use dladm(1M) to manage datalink tunables.\n"));
343a924b63fSVasumathi Sundaram - Sun Microsystems 		}
344a924b63fSVasumathi Sundaram - Sun Microsystems 	}
345a924b63fSVasumathi Sundaram - Sun Microsystems 	dladm_close(handle);
3464045d941Ssowmini }
3474045d941Ssowmini 
3487c478bd9Sstevel@tonic-gate /* ARGSUSED */
3497c478bd9Sstevel@tonic-gate int
3507c478bd9Sstevel@tonic-gate main(int argc, char **argv)
3517c478bd9Sstevel@tonic-gate {
352*6e91bba0SGirish Moodalbail 	char	*cp, *value, *mod;
3537c478bd9Sstevel@tonic-gate 	int	cmd;
354*6e91bba0SGirish Moodalbail 	int	fd = 0;
3554045d941Ssowmini 
3567c478bd9Sstevel@tonic-gate 	if (!(cp = *++argv)) {
357a924b63fSVasumathi Sundaram - Sun Microsystems 		while ((fd = open_device()) != -1) {
3587c478bd9Sstevel@tonic-gate 			getset_interactive(fd);
3597c478bd9Sstevel@tonic-gate 			(void) close(fd);
3607c478bd9Sstevel@tonic-gate 		}
3617c478bd9Sstevel@tonic-gate 		return (EXIT_SUCCESS);
3627c478bd9Sstevel@tonic-gate 	}
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	cmd = ND_GET;
3657c478bd9Sstevel@tonic-gate 	if (cp[0] == '-') {
3667c478bd9Sstevel@tonic-gate 		if (strncmp(&cp[1], "set", 3) == 0)
3677c478bd9Sstevel@tonic-gate 			cmd = ND_SET;
3687c478bd9Sstevel@tonic-gate 		else if (strncmp(&cp[1], "get", 3) != 0)
3697c478bd9Sstevel@tonic-gate 			fatal(usage_str);
3707c478bd9Sstevel@tonic-gate 		if (!(cp = *++argv))
3717c478bd9Sstevel@tonic-gate 			fatal(usage_str);
3727c478bd9Sstevel@tonic-gate 	}
373*6e91bba0SGirish Moodalbail 
374a924b63fSVasumathi Sundaram - Sun Microsystems 	gldv3_warning(cp);
3754ac67f02SAnurag S. Maskey 
376*6e91bba0SGirish Moodalbail 	mod = strrchr(cp, '/');
377*6e91bba0SGirish Moodalbail 	if (mod != NULL)
378*6e91bba0SGirish Moodalbail 		mod++;
379*6e91bba0SGirish Moodalbail 	else
380*6e91bba0SGirish Moodalbail 		mod = cp;
381*6e91bba0SGirish Moodalbail 
382*6e91bba0SGirish Moodalbail 	if (ndd_str2proto(mod) == MOD_PROTO_NONE) {
3837c478bd9Sstevel@tonic-gate 		if ((fd = open(cp, O_RDWR)) == -1)
3847c478bd9Sstevel@tonic-gate 			fatal("open of %s failed: %s", cp, errmsg(errno));
3857c478bd9Sstevel@tonic-gate 		if (!isastream(fd))
3867c478bd9Sstevel@tonic-gate 			fatal("%s is not a streams device", cp);
387*6e91bba0SGirish Moodalbail 	}
3887c478bd9Sstevel@tonic-gate 
389*6e91bba0SGirish Moodalbail 	(void) strlcpy(modpath, cp, sizeof (modpath));
3907c478bd9Sstevel@tonic-gate 	if (!(cp = *++argv)) {
3917c478bd9Sstevel@tonic-gate 		getset_interactive(fd);
3927c478bd9Sstevel@tonic-gate 		(void) close(fd);
3937c478bd9Sstevel@tonic-gate 		return (EXIT_SUCCESS);
3947c478bd9Sstevel@tonic-gate 	}
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	if (cmd == ND_SET) {
3977c478bd9Sstevel@tonic-gate 		if (!(value = *++argv))
3987c478bd9Sstevel@tonic-gate 			fatal(usage_str);
3997c478bd9Sstevel@tonic-gate 		(void) snprintf(gbuf, sizeof (gbuf), "%s%c%s%c", cp, '\0',
4007c478bd9Sstevel@tonic-gate 		    value, '\0');
4017c478bd9Sstevel@tonic-gate 		if (!do_getset(fd, cmd, gbuf, sizeof (gbuf)))
4027c478bd9Sstevel@tonic-gate 			return (EXIT_FAILURE);
4037c478bd9Sstevel@tonic-gate 	} else {
4047c478bd9Sstevel@tonic-gate 		do {
4057c478bd9Sstevel@tonic-gate 			(void) memset(gbuf, '\0', sizeof (gbuf));
4067c478bd9Sstevel@tonic-gate 			(void) strlcpy(gbuf, cp, sizeof (gbuf));
4077c478bd9Sstevel@tonic-gate 			if (!do_getset(fd, cmd, gbuf, sizeof (gbuf)))
4087c478bd9Sstevel@tonic-gate 				return (EXIT_FAILURE);
4097c478bd9Sstevel@tonic-gate 			if (cp = *++argv)
4107c478bd9Sstevel@tonic-gate 				(void) putchar('\n');
4117c478bd9Sstevel@tonic-gate 		} while (cp);
4127c478bd9Sstevel@tonic-gate 	}
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	(void) close(fd);
4157c478bd9Sstevel@tonic-gate 	return (EXIT_SUCCESS);
4167c478bd9Sstevel@tonic-gate }
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate static void
4197c478bd9Sstevel@tonic-gate name_print(char *buf)
4207c478bd9Sstevel@tonic-gate {
4217c478bd9Sstevel@tonic-gate 	char *cp, *rwtag;
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	for (cp = buf; cp[0]; ) {
4247c478bd9Sstevel@tonic-gate 		for (rwtag = cp; !isspace(*rwtag); rwtag++)
4257c478bd9Sstevel@tonic-gate 			;
4267c478bd9Sstevel@tonic-gate 		*rwtag++ = '\0';
4277c478bd9Sstevel@tonic-gate 		while (isspace(*rwtag))
4287c478bd9Sstevel@tonic-gate 			rwtag++;
4297c478bd9Sstevel@tonic-gate 		(void) printf("%-30s%s\n", cp, rwtag);
4307c478bd9Sstevel@tonic-gate 		for (cp = rwtag; *cp++; )
4317c478bd9Sstevel@tonic-gate 			;
4327c478bd9Sstevel@tonic-gate 	}
4337c478bd9Sstevel@tonic-gate }
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate /*
4367c478bd9Sstevel@tonic-gate  * This function is vile, but it's better here than in the kernel.
4377c478bd9Sstevel@tonic-gate  */
4387c478bd9Sstevel@tonic-gate static boolean_t
4397c478bd9Sstevel@tonic-gate is_obsolete(const char *param)
4407c478bd9Sstevel@tonic-gate {
4417c478bd9Sstevel@tonic-gate 	if (strcmp(param, "ip_enable_group_ifs") == 0 ||
4427c478bd9Sstevel@tonic-gate 	    strcmp(param, "ifgrp_status") == 0) {
4437c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "The \"%s\" tunable has been superseded "
4447c478bd9Sstevel@tonic-gate 		    "by IP Multipathing.\nPlease see the IP Network "
4457c478bd9Sstevel@tonic-gate 		    "Multipathing Administration Guide for details.\n", param);
4467c478bd9Sstevel@tonic-gate 		return (B_TRUE);
4477c478bd9Sstevel@tonic-gate 	}
4487c478bd9Sstevel@tonic-gate 	return (B_FALSE);
4497c478bd9Sstevel@tonic-gate }
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate static boolean_t
4527c478bd9Sstevel@tonic-gate do_getset(int fd, int cmd, char *buf, int buf_len)
4537c478bd9Sstevel@tonic-gate {
4547c478bd9Sstevel@tonic-gate 	char	*cp;
4557c478bd9Sstevel@tonic-gate 	struct strioctl	stri;
4567c478bd9Sstevel@tonic-gate 	boolean_t	is_name_get;
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	if (is_obsolete(buf))
4597c478bd9Sstevel@tonic-gate 		return (B_TRUE);
4607c478bd9Sstevel@tonic-gate 
461*6e91bba0SGirish Moodalbail 	/*
462*6e91bba0SGirish Moodalbail 	 * See if libipadm can handle this request, i.e., properties on
463*6e91bba0SGirish Moodalbail 	 * following modules arp, ip, ipv4, ipv6, tcp, udp and sctp
464*6e91bba0SGirish Moodalbail 	 */
465*6e91bba0SGirish Moodalbail 	if (do_ipadm_getset(cmd, buf, buf_len))
466*6e91bba0SGirish Moodalbail 		return (B_TRUE);
467*6e91bba0SGirish Moodalbail 
4687c478bd9Sstevel@tonic-gate 	stri.ic_cmd = cmd;
4697c478bd9Sstevel@tonic-gate 	stri.ic_timout = 0;
4707c478bd9Sstevel@tonic-gate 	stri.ic_len = buf_len;
4717c478bd9Sstevel@tonic-gate 	stri.ic_dp = buf;
4727c478bd9Sstevel@tonic-gate 	is_name_get = stri.ic_cmd == ND_GET && buf[0] == '?' && buf[1] == '\0';
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 	if (ioctl(fd, I_STR, &stri) == -1) {
4757c478bd9Sstevel@tonic-gate 		if (errno == ENOENT)
4767c478bd9Sstevel@tonic-gate 			(void) printf("name is non-existent for this module\n"
4777c478bd9Sstevel@tonic-gate 			    "for a list of valid names, use name '?'\n");
4787c478bd9Sstevel@tonic-gate 		else
4797c478bd9Sstevel@tonic-gate 			(void) printf("operation failed: %s\n", errmsg(errno));
4807c478bd9Sstevel@tonic-gate 		return (B_FALSE);
4817c478bd9Sstevel@tonic-gate 	}
4827c478bd9Sstevel@tonic-gate 	if (is_name_get)
4837c478bd9Sstevel@tonic-gate 		name_print(buf);
4847c478bd9Sstevel@tonic-gate 	else if (stri.ic_cmd == ND_GET) {
4857c478bd9Sstevel@tonic-gate 		for (cp = buf; *cp != '\0'; cp += strlen(cp) + 1)
4867c478bd9Sstevel@tonic-gate 			(void) puts(cp);
4877c478bd9Sstevel@tonic-gate 	}
4887c478bd9Sstevel@tonic-gate 	(void) fflush(stdout);
4897c478bd9Sstevel@tonic-gate 	return (B_TRUE);
4907c478bd9Sstevel@tonic-gate }
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate static int
4937c478bd9Sstevel@tonic-gate get_value(char *msg, char *buf, int buf_len)
4947c478bd9Sstevel@tonic-gate {
4957c478bd9Sstevel@tonic-gate 	int	len;
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	(void) printf("%s", msg);
4987c478bd9Sstevel@tonic-gate 	(void) fflush(stdout);
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 	buf[buf_len-1] = '\0';
5017c478bd9Sstevel@tonic-gate 	if (fgets(buf, buf_len-1, stdin) == NULL)
5027c478bd9Sstevel@tonic-gate 		exit(EXIT_SUCCESS);
5037c478bd9Sstevel@tonic-gate 	len = strlen(buf);
5047c478bd9Sstevel@tonic-gate 	if (buf[len-1] == '\n')
5057c478bd9Sstevel@tonic-gate 		buf[len - 1] = '\0';
5067c478bd9Sstevel@tonic-gate 	else
5077c478bd9Sstevel@tonic-gate 		len++;
5087c478bd9Sstevel@tonic-gate 	return (len);
5097c478bd9Sstevel@tonic-gate }
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate static void
5127c478bd9Sstevel@tonic-gate getset_interactive(int fd)
5137c478bd9Sstevel@tonic-gate {
5147c478bd9Sstevel@tonic-gate 	int	cmd;
5157c478bd9Sstevel@tonic-gate 	char	*cp;
5167c478bd9Sstevel@tonic-gate 	int	len, buf_len;
5177c478bd9Sstevel@tonic-gate 	char	len_buf[10];
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 	for (;;) {
5207c478bd9Sstevel@tonic-gate 		(void) memset(gbuf, '\0', sizeof (gbuf));
5217c478bd9Sstevel@tonic-gate 		len = get_value("name to get/set ? ", gbuf, sizeof (gbuf));
5227c478bd9Sstevel@tonic-gate 		if (len == 1 || (gbuf[0] == 'q' && gbuf[1] == '\0'))
5237c478bd9Sstevel@tonic-gate 			return;
5247c478bd9Sstevel@tonic-gate 		for (cp = gbuf; cp < &gbuf[len]; cp++) {
5257c478bd9Sstevel@tonic-gate 			if (isspace(*cp))
5267c478bd9Sstevel@tonic-gate 				*cp = '\0';
5277c478bd9Sstevel@tonic-gate 		}
5287c478bd9Sstevel@tonic-gate 		cmd = ND_GET;
5297c478bd9Sstevel@tonic-gate 		if (gbuf[0] != '?' &&
5307c478bd9Sstevel@tonic-gate 		    get_value("value ? ", &gbuf[len], sizeof (gbuf) - len) > 1)
5317c478bd9Sstevel@tonic-gate 			cmd = ND_SET;
5327c478bd9Sstevel@tonic-gate 		if (cmd == ND_GET && gbuf[0] != '?' &&
5337c478bd9Sstevel@tonic-gate 		    get_value("length ? ", len_buf, sizeof (len_buf)) > 1) {
5347c478bd9Sstevel@tonic-gate 			if (!isdigit(len_buf[0])) {
5357c478bd9Sstevel@tonic-gate 				(void) printf("invalid length\n");
5367c478bd9Sstevel@tonic-gate 				continue;
5377c478bd9Sstevel@tonic-gate 			}
5387c478bd9Sstevel@tonic-gate 			buf_len = atoi(len_buf);
5397c478bd9Sstevel@tonic-gate 		} else
5407c478bd9Sstevel@tonic-gate 			buf_len = sizeof (gbuf);
5417c478bd9Sstevel@tonic-gate 		(void) do_getset(fd, cmd, gbuf, buf_len);
5427c478bd9Sstevel@tonic-gate 	}
5437c478bd9Sstevel@tonic-gate }
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate static void
5467c478bd9Sstevel@tonic-gate printe(boolean_t print_errno, char *fmt, ...)
5477c478bd9Sstevel@tonic-gate {
5487c478bd9Sstevel@tonic-gate 	va_list	ap;
5497c478bd9Sstevel@tonic-gate 	int error = errno;
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
5527c478bd9Sstevel@tonic-gate 	(void) printf("*ERROR* ");
5537c478bd9Sstevel@tonic-gate 	(void) vprintf(fmt, ap);
5547c478bd9Sstevel@tonic-gate 	va_end(ap);
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 	if (print_errno)
5577c478bd9Sstevel@tonic-gate 		(void) printf(": %s\n", errmsg(error));
5587c478bd9Sstevel@tonic-gate 	else
5597c478bd9Sstevel@tonic-gate 		(void) printf("\n");
5607c478bd9Sstevel@tonic-gate }
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate static int
563a924b63fSVasumathi Sundaram - Sun Microsystems open_device()
5647c478bd9Sstevel@tonic-gate {
5657c478bd9Sstevel@tonic-gate 	int	fd, len;
566*6e91bba0SGirish Moodalbail 	char	*mod;
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 	for (;;) {
569*6e91bba0SGirish Moodalbail 		len = get_value("module to query ? ", modpath,
570*6e91bba0SGirish Moodalbail 		    sizeof (modpath));
5717c478bd9Sstevel@tonic-gate 		if (len <= 1 ||
572*6e91bba0SGirish Moodalbail 		    (len == 2 && (modpath[0] == 'q' || modpath[0] == 'Q')))
5737c478bd9Sstevel@tonic-gate 			return (-1);
5747c478bd9Sstevel@tonic-gate 
575*6e91bba0SGirish Moodalbail 		mod = strrchr(modpath, '/');
576*6e91bba0SGirish Moodalbail 		if (mod != NULL)
577*6e91bba0SGirish Moodalbail 			mod++;
578*6e91bba0SGirish Moodalbail 		else
579*6e91bba0SGirish Moodalbail 			mod = modpath;
580*6e91bba0SGirish Moodalbail 		if (ndd_str2proto(mod) == MOD_PROTO_NONE) {
581*6e91bba0SGirish Moodalbail 			if ((fd = open(modpath, O_RDWR)) == -1) {
582*6e91bba0SGirish Moodalbail 				printe(B_TRUE, "open of %s failed", modpath);
5837c478bd9Sstevel@tonic-gate 				continue;
5847c478bd9Sstevel@tonic-gate 			}
585*6e91bba0SGirish Moodalbail 		} else {
586*6e91bba0SGirish Moodalbail 			return (0);
587*6e91bba0SGirish Moodalbail 		}
5887c478bd9Sstevel@tonic-gate 
589*6e91bba0SGirish Moodalbail 		gldv3_warning(modpath);
5904045d941Ssowmini 
5917c478bd9Sstevel@tonic-gate 		if (isastream(fd))
5927c478bd9Sstevel@tonic-gate 			return (fd);
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 		(void) close(fd);
595*6e91bba0SGirish Moodalbail 		printe(B_FALSE, "%s is not a streams device", modpath);
5967c478bd9Sstevel@tonic-gate 	}
5977c478bd9Sstevel@tonic-gate }
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate static void
6007c478bd9Sstevel@tonic-gate fatal(char *fmt, ...)
6017c478bd9Sstevel@tonic-gate {
6027c478bd9Sstevel@tonic-gate 	va_list	ap;
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
6057c478bd9Sstevel@tonic-gate 	(void) vfprintf(stderr, fmt, ap);
6067c478bd9Sstevel@tonic-gate 	va_end(ap);
6077c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\n");
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	exit(EXIT_FAILURE);
6107c478bd9Sstevel@tonic-gate }
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate static char *
6137c478bd9Sstevel@tonic-gate errmsg(int error)
6147c478bd9Sstevel@tonic-gate {
6157c478bd9Sstevel@tonic-gate 	char *msg = strerror(error);
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate 	return (msg != NULL ? msg : "unknown error");
6187c478bd9Sstevel@tonic-gate }
619