xref: /titanic_50/usr/src/cmd/devctl/devctl.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 2004 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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate /*
31*7c478bd9Sstevel@tonic-gate  * devctl - device control utility
32*7c478bd9Sstevel@tonic-gate  *
33*7c478bd9Sstevel@tonic-gate  * to compile:
34*7c478bd9Sstevel@tonic-gate  * cc -o devctl -ldevice -ldevinfo devctl.c
35*7c478bd9Sstevel@tonic-gate  *
36*7c478bd9Sstevel@tonic-gate  * usage: devctl [-v] command [device/bus pathname]
37*7c478bd9Sstevel@tonic-gate  *
38*7c478bd9Sstevel@tonic-gate  * Commands:
39*7c478bd9Sstevel@tonic-gate  * 	list		- list all controllers exporting the devctl interface
40*7c478bd9Sstevel@tonic-gate  *	online		- online a device
41*7c478bd9Sstevel@tonic-gate  *	offline		- offline a device
42*7c478bd9Sstevel@tonic-gate  *	remove  	- remove a device from the device tree
43*7c478bd9Sstevel@tonic-gate  * 	quiesce		- quiesce the bus
44*7c478bd9Sstevel@tonic-gate  *	unquiesce	- resume bus activity
45*7c478bd9Sstevel@tonic-gate  *	configure	- configure a bus's child devices
46*7c478bd9Sstevel@tonic-gate  *	unconfigure	- unconfigure a bus's child devices
47*7c478bd9Sstevel@tonic-gate  *	bus-reset	- reset a bus
48*7c478bd9Sstevel@tonic-gate  *	dev-reset	- reset a device
49*7c478bd9Sstevel@tonic-gate  * 	bus-getstate	- return the current state of the bus
50*7c478bd9Sstevel@tonic-gate  *	dev-getstate	- return the current state of the device
51*7c478bd9Sstevel@tonic-gate  *	bus-devcreate	- create a new device, bus specific
52*7c478bd9Sstevel@tonic-gate  *	dev-raisepower		- power up a device via pm_raise_power() (pm)
53*7c478bd9Sstevel@tonic-gate  *	dev-idlecomp		- idle a device's component 0 (pm)
54*7c478bd9Sstevel@tonic-gate  *	dev-busycomp		- busy a device's component 0 (pm)
55*7c478bd9Sstevel@tonic-gate  *	dev-testbusy		- test a device's component 0's busy state (pm)
56*7c478bd9Sstevel@tonic-gate  *	dev-changepowerhigh	- power up a device via pm_power_has_changed()
57*7c478bd9Sstevel@tonic-gate  *				  (pm)
58*7c478bd9Sstevel@tonic-gate  *	dev-changepowerlow	- power off a device via pm_power_has_changed()
59*7c478bd9Sstevel@tonic-gate  *				  (pm)
60*7c478bd9Sstevel@tonic-gate  *	dev-failsuspend		- fail DDI_SUSPEND (pm)
61*7c478bd9Sstevel@tonic-gate  *	dev-changeonresume	- issue pm_power_has_changed() vs,
62*7c478bd9Sstevel@tonic-gate  *				  pm_raise_power() on device resume (pm)
63*7c478bd9Sstevel@tonic-gate  *	dev-nolowerpower	- don't call pm_lower_power() on detach (pm)
64*7c478bd9Sstevel@tonic-gate  *	dev-promprintf		- issue a prom_printf() call (pm)
65*7c478bd9Sstevel@tonic-gate  *	bus-raisepower		- power up a bus via pm_raise_power() (pm)
66*7c478bd9Sstevel@tonic-gate  *	bus-idlecomp		- idle a bus' component (pm)
67*7c478bd9Sstevel@tonic-gate  *	bus-busycomp		- busy a bus' component (pm)
68*7c478bd9Sstevel@tonic-gate  *	bus-testbusy		- test a bus' component busy state (pm)
69*7c478bd9Sstevel@tonic-gate  *	bus-changepowerhigh	- power up a bus via pm_power_has_changed() (pm)
70*7c478bd9Sstevel@tonic-gate  *	bus-changepowerlow	- power off a bus via pm_power_has_changed()
71*7c478bd9Sstevel@tonic-gate  *				  (pm)
72*7c478bd9Sstevel@tonic-gate  *	bus-failsuspend		- fail DDI_SUSPEND (pm)
73*7c478bd9Sstevel@tonic-gate  *	bus-teststrict		- test is bus driver is  strict or involved (pm)
74*7c478bd9Sstevel@tonic-gate  *	bus-noinvol		- mark idle twice when child detaches
75*7c478bd9Sstevel@tonic-gate  *
76*7c478bd9Sstevel@tonic-gate  *
77*7c478bd9Sstevel@tonic-gate  * Returns:
78*7c478bd9Sstevel@tonic-gate  *	- Success
79*7c478bd9Sstevel@tonic-gate  *	- Operation not supported by device
80*7c478bd9Sstevel@tonic-gate  *	- No Permission
81*7c478bd9Sstevel@tonic-gate  *	- No Such Device
82*7c478bd9Sstevel@tonic-gate  *
83*7c478bd9Sstevel@tonic-gate  * Examples:
84*7c478bd9Sstevel@tonic-gate  *	devctl list - list all controllers exporting a :devctl node
85*7c478bd9Sstevel@tonic-gate  *	devctl offline /dev/dsk/c0t3d0s0  - offline disk
86*7c478bd9Sstevel@tonic-gate  *	devctl dev-getstate  /devices/sbus@1f,0/espdma@e,8400000/esp@e,8800000\
87*7c478bd9Sstevel@tonic-gate  * sd@3,0
88*7c478bd9Sstevel@tonic-gate  *
89*7c478bd9Sstevel@tonic-gate  */
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate #include <stdio.h>
92*7c478bd9Sstevel@tonic-gate #include <string.h>
93*7c478bd9Sstevel@tonic-gate #include <unistd.h>
94*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
95*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
96*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
97*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
98*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
99*7c478bd9Sstevel@tonic-gate #include <libdevice.h>
100*7c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
101*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate typedef struct cmds {
104*7c478bd9Sstevel@tonic-gate 	char *cmdname;
105*7c478bd9Sstevel@tonic-gate 	int (*cmdf)(devctl_hdl_t);
106*7c478bd9Sstevel@tonic-gate } cmds_t;
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate extern int errno;
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate static void setprogname(char *name);
111*7c478bd9Sstevel@tonic-gate static void print_bus_state(char *devname, uint_t state);
112*7c478bd9Sstevel@tonic-gate static void print_dev_state(char *devname, uint_t state);
113*7c478bd9Sstevel@tonic-gate static int dev_getstate(devctl_hdl_t);
114*7c478bd9Sstevel@tonic-gate static int bus_getstate(devctl_hdl_t);
115*7c478bd9Sstevel@tonic-gate static int bus_devcreate(devctl_hdl_t);
116*7c478bd9Sstevel@tonic-gate static void run_list_ctlrs(void);
117*7c478bd9Sstevel@tonic-gate static struct cmds *dc_cmd();
118*7c478bd9Sstevel@tonic-gate static int nexif(di_node_t din, di_minor_t dim, void *arg);
119*7c478bd9Sstevel@tonic-gate static void *s_malloc(size_t);
120*7c478bd9Sstevel@tonic-gate static void *s_realloc(void *, size_t);
121*7c478bd9Sstevel@tonic-gate static char *s_strdup(char *);
122*7c478bd9Sstevel@tonic-gate static int dev_pm_testbusy(devctl_hdl_t);
123*7c478bd9Sstevel@tonic-gate static int bus_pm_teststrict(devctl_hdl_t);
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate static char *devctl_device;
126*7c478bd9Sstevel@tonic-gate static char *orig_path;
127*7c478bd9Sstevel@tonic-gate static char *devctl_cmdname;
128*7c478bd9Sstevel@tonic-gate static char *progname;
129*7c478bd9Sstevel@tonic-gate static int  verbose;
130*7c478bd9Sstevel@tonic-gate static int  debug;
131*7c478bd9Sstevel@tonic-gate static char *dev_name;
132*7c478bd9Sstevel@tonic-gate static char **dev_props;
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate static const char *usage = "%s [-v] list | online | offline | remove |\n"
135*7c478bd9Sstevel@tonic-gate 	"\tquiesce | unquiesce | configure | unconfigure |\n"
136*7c478bd9Sstevel@tonic-gate 	"\t{bus,dev}-reset {bus,dev}-getstate | {bus,dev}-raisepower |\n"
137*7c478bd9Sstevel@tonic-gate 	"\t{bus,dev}-idlecomp | {bus,dev}-busycomp |\n"
138*7c478bd9Sstevel@tonic-gate 	"\t{bus,dev}-changepowerhigh | {bus,dev}-changepowerlow |\n"
139*7c478bd9Sstevel@tonic-gate 	"\t{bus,dev}-testbusy | {bus,dev}-failsuspend | dev-changeonresume |\n"
140*7c478bd9Sstevel@tonic-gate 	"\tdev-promprintf | dev-nolowerpower | bus-teststrict |\n"
141*7c478bd9Sstevel@tonic-gate 	"\tbus-noinvol [/dev/... | /devices/...]\n";
142*7c478bd9Sstevel@tonic-gate 
143*7c478bd9Sstevel@tonic-gate static struct cmds device_cmds[] = {
144*7c478bd9Sstevel@tonic-gate 	{"online", devctl_device_online},
145*7c478bd9Sstevel@tonic-gate 	{"offline", devctl_device_offline},
146*7c478bd9Sstevel@tonic-gate 	{"remove", devctl_device_remove},
147*7c478bd9Sstevel@tonic-gate 	{"dev-reset", devctl_device_reset},
148*7c478bd9Sstevel@tonic-gate 	{"dev-getstate", dev_getstate},
149*7c478bd9Sstevel@tonic-gate 	{"dev-raisepower", devctl_pm_raisepower},
150*7c478bd9Sstevel@tonic-gate 	{"dev-busycomp", devctl_pm_busycomponent},
151*7c478bd9Sstevel@tonic-gate 	{"dev-idlecomp", devctl_pm_idlecomponent},
152*7c478bd9Sstevel@tonic-gate 	{"dev-testbusy", dev_pm_testbusy},
153*7c478bd9Sstevel@tonic-gate 	{"dev-changepowerlow", devctl_pm_changepowerlow},
154*7c478bd9Sstevel@tonic-gate 	{"dev-changepowerhigh", devctl_pm_changepowerhigh},
155*7c478bd9Sstevel@tonic-gate 	{"dev-failsuspend", devctl_pm_failsuspend},
156*7c478bd9Sstevel@tonic-gate 	{"dev-changeonresume", devctl_pm_device_changeonresume},
157*7c478bd9Sstevel@tonic-gate 	{"dev-promprintf", devctl_pm_device_promprintf},
158*7c478bd9Sstevel@tonic-gate 	{"dev-nolowerpower", devctl_pm_device_no_lower_power},
159*7c478bd9Sstevel@tonic-gate 	{NULL, NULL},
160*7c478bd9Sstevel@tonic-gate };
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate static struct cmds bus_cmds[] = {
163*7c478bd9Sstevel@tonic-gate 	{"quiesce", devctl_bus_quiesce},
164*7c478bd9Sstevel@tonic-gate 	{"unquiesce", devctl_bus_unquiesce},
165*7c478bd9Sstevel@tonic-gate 	{"bus-reset", devctl_bus_reset},
166*7c478bd9Sstevel@tonic-gate 	{"configure", devctl_bus_configure},
167*7c478bd9Sstevel@tonic-gate 	{"unconfigure", devctl_bus_unconfigure},
168*7c478bd9Sstevel@tonic-gate 	{"bus-getstate", bus_getstate},
169*7c478bd9Sstevel@tonic-gate 	{"bus-devcreate", bus_devcreate},
170*7c478bd9Sstevel@tonic-gate 	{"bus-raisepower", devctl_pm_raisepower},
171*7c478bd9Sstevel@tonic-gate 	{"bus-busycomp", devctl_pm_busycomponent},
172*7c478bd9Sstevel@tonic-gate 	{"bus-idlecomp", devctl_pm_idlecomponent},
173*7c478bd9Sstevel@tonic-gate 	{"bus-changepowerlow", devctl_pm_changepowerlow},
174*7c478bd9Sstevel@tonic-gate 	{"bus-changepowerhigh", devctl_pm_changepowerhigh},
175*7c478bd9Sstevel@tonic-gate 	{"bus-testbusy", dev_pm_testbusy},
176*7c478bd9Sstevel@tonic-gate 	{"bus-failsuspend", devctl_pm_failsuspend},
177*7c478bd9Sstevel@tonic-gate 	{"bus-teststrict", bus_pm_teststrict},
178*7c478bd9Sstevel@tonic-gate 	{"bus-noinvol", devctl_pm_bus_no_invol},
179*7c478bd9Sstevel@tonic-gate 	{NULL, NULL},
180*7c478bd9Sstevel@tonic-gate };
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate void
185*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
186*7c478bd9Sstevel@tonic-gate {
187*7c478bd9Sstevel@tonic-gate 	int	c;
188*7c478bd9Sstevel@tonic-gate 	int 	rv;
189*7c478bd9Sstevel@tonic-gate 	int	pathlen;
190*7c478bd9Sstevel@tonic-gate 	struct cmds *dcmd;
191*7c478bd9Sstevel@tonic-gate 	devctl_hdl_t dcp;
192*7c478bd9Sstevel@tonic-gate 	struct stat stat_buf;
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate 	setprogname(argv[0]);
195*7c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "vd")) != -1)  {
196*7c478bd9Sstevel@tonic-gate 		switch (c)  {
197*7c478bd9Sstevel@tonic-gate 		case 'v':
198*7c478bd9Sstevel@tonic-gate 			++verbose;
199*7c478bd9Sstevel@tonic-gate 			break;
200*7c478bd9Sstevel@tonic-gate 		case 'd':
201*7c478bd9Sstevel@tonic-gate 			++debug;
202*7c478bd9Sstevel@tonic-gate 			(void) putenv("LIBDEVICE_DEBUG");
203*7c478bd9Sstevel@tonic-gate 			break;
204*7c478bd9Sstevel@tonic-gate 		default:
205*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, usage, progname);
206*7c478bd9Sstevel@tonic-gate 			exit(1);
207*7c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
208*7c478bd9Sstevel@tonic-gate 		}
209*7c478bd9Sstevel@tonic-gate 	}
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate 	if (optind == argc) {
212*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, usage, progname);
213*7c478bd9Sstevel@tonic-gate 		exit(-1);
214*7c478bd9Sstevel@tonic-gate 	}
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate 	devctl_cmdname = argv[optind++];
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate 	if (strcmp(devctl_cmdname, "list") == 0) {
219*7c478bd9Sstevel@tonic-gate 		run_list_ctlrs();
220*7c478bd9Sstevel@tonic-gate 		exit(0);
221*7c478bd9Sstevel@tonic-gate 	}
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate 	/*
224*7c478bd9Sstevel@tonic-gate 	 * any command other than "list" requires a device path
225*7c478bd9Sstevel@tonic-gate 	 */
226*7c478bd9Sstevel@tonic-gate 	if (((optind + 1) > argc)) {
227*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, usage, progname);
228*7c478bd9Sstevel@tonic-gate 		exit(-1);
229*7c478bd9Sstevel@tonic-gate 	}
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 	orig_path = s_strdup(argv[optind]);
232*7c478bd9Sstevel@tonic-gate 	devctl_device = s_malloc(MAXPATHLEN);
233*7c478bd9Sstevel@tonic-gate 	(void) strcpy(devctl_device, orig_path);
234*7c478bd9Sstevel@tonic-gate 
235*7c478bd9Sstevel@tonic-gate 	/*
236*7c478bd9Sstevel@tonic-gate 	 * Additional properties follow for bus-devcreate
237*7c478bd9Sstevel@tonic-gate 	 */
238*7c478bd9Sstevel@tonic-gate 	if ((optind + 1 < argc) &&
239*7c478bd9Sstevel@tonic-gate 	    strcmp(devctl_cmdname, "bus-devcreate") == 0) {
240*7c478bd9Sstevel@tonic-gate 		int i;
241*7c478bd9Sstevel@tonic-gate 		optind++;
242*7c478bd9Sstevel@tonic-gate 		dev_name = s_strdup(argv[optind]);
243*7c478bd9Sstevel@tonic-gate 		i = argc - optind;
244*7c478bd9Sstevel@tonic-gate 		dev_props = s_malloc(i * sizeof (char *));
245*7c478bd9Sstevel@tonic-gate 		while (--i) {
246*7c478bd9Sstevel@tonic-gate 			dev_props[i - 1] = s_strdup(argv[optind + i]);
247*7c478bd9Sstevel@tonic-gate 		}
248*7c478bd9Sstevel@tonic-gate 	}
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate 	/*
251*7c478bd9Sstevel@tonic-gate 	 * if the device is a logical name, get the physical name
252*7c478bd9Sstevel@tonic-gate 	 */
253*7c478bd9Sstevel@tonic-gate 	if (lstat(orig_path, &stat_buf) == 0) {
254*7c478bd9Sstevel@tonic-gate 		if ((stat_buf.st_mode & S_IFLNK) == S_IFLNK) {
255*7c478bd9Sstevel@tonic-gate 			if ((pathlen = readlink(orig_path, devctl_device,
256*7c478bd9Sstevel@tonic-gate 			    MAXPATHLEN)) == -1)  {
257*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
258*7c478bd9Sstevel@tonic-gate 					"devctl: readlink(%s) - %s\n",
259*7c478bd9Sstevel@tonic-gate 					orig_path, strerror(errno));
260*7c478bd9Sstevel@tonic-gate 				exit(-1);
261*7c478bd9Sstevel@tonic-gate 			}
262*7c478bd9Sstevel@tonic-gate 			devctl_device[pathlen] = '\0';
263*7c478bd9Sstevel@tonic-gate 		}
264*7c478bd9Sstevel@tonic-gate 	}
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate 	if ((dcmd = dc_cmd(device_cmds, devctl_cmdname)) == NULL) {
267*7c478bd9Sstevel@tonic-gate 		dcmd = dc_cmd(bus_cmds, devctl_cmdname);
268*7c478bd9Sstevel@tonic-gate 		if (dcmd == NULL) {
269*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "unrecognized command (%s)\n",
270*7c478bd9Sstevel@tonic-gate 			    devctl_cmdname);
271*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, usage, progname);
272*7c478bd9Sstevel@tonic-gate 			exit(1);
273*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(devctl_cmdname, "bus-raisepower") == 0 ||
274*7c478bd9Sstevel@tonic-gate 		    strcmp(devctl_cmdname, "bus-changepowerlow") == 0 ||
275*7c478bd9Sstevel@tonic-gate 		    strcmp(devctl_cmdname, "bus-changepowerhigh") == 0 ||
276*7c478bd9Sstevel@tonic-gate 		    strcmp(devctl_cmdname, "bus-idlecomp") == 0 ||
277*7c478bd9Sstevel@tonic-gate 		    strcmp(devctl_cmdname, "bus-busycomp") == 0 ||
278*7c478bd9Sstevel@tonic-gate 		    strcmp(devctl_cmdname, "bus-testbusy") == 0 ||
279*7c478bd9Sstevel@tonic-gate 		    strcmp(devctl_cmdname, "bus-failsuspend") == 0 ||
280*7c478bd9Sstevel@tonic-gate 		    strcmp(devctl_cmdname, "bus-teststrict") == 0 ||
281*7c478bd9Sstevel@tonic-gate 		    strcmp(devctl_cmdname, "bus-noinvol") == 0) {
282*7c478bd9Sstevel@tonic-gate 			dcp = devctl_pm_bus_acquire(devctl_device, 0);
283*7c478bd9Sstevel@tonic-gate 			if (dcp == NULL) {
284*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
285*7c478bd9Sstevel@tonic-gate 				    "devctl: device_pm_bus_acquire %s - %s\n",
286*7c478bd9Sstevel@tonic-gate 				    devctl_device, strerror(errno));
287*7c478bd9Sstevel@tonic-gate 				exit(-1);
288*7c478bd9Sstevel@tonic-gate 			}
289*7c478bd9Sstevel@tonic-gate 		} else {
290*7c478bd9Sstevel@tonic-gate 			dcp = devctl_bus_acquire(devctl_device, 0);
291*7c478bd9Sstevel@tonic-gate 			if (dcp == NULL) {
292*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "devctl: bus_acquire "
293*7c478bd9Sstevel@tonic-gate 				    "%s - %s\n",
294*7c478bd9Sstevel@tonic-gate 				    devctl_device, strerror(errno));
295*7c478bd9Sstevel@tonic-gate 				exit(-1);
296*7c478bd9Sstevel@tonic-gate 			}
297*7c478bd9Sstevel@tonic-gate 		}
298*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(devctl_cmdname, "dev-raisepower") == 0 ||
299*7c478bd9Sstevel@tonic-gate 	    strcmp(devctl_cmdname, "dev-changepowerlow") == 0 ||
300*7c478bd9Sstevel@tonic-gate 	    strcmp(devctl_cmdname, "dev-changepowerhigh") == 0 ||
301*7c478bd9Sstevel@tonic-gate 	    strcmp(devctl_cmdname, "dev-idlecomp") == 0 ||
302*7c478bd9Sstevel@tonic-gate 	    strcmp(devctl_cmdname, "dev-busycomp") == 0 ||
303*7c478bd9Sstevel@tonic-gate 	    strcmp(devctl_cmdname, "dev-testbusy") == 0 ||
304*7c478bd9Sstevel@tonic-gate 	    strcmp(devctl_cmdname, "dev-failsuspend") == 0 ||
305*7c478bd9Sstevel@tonic-gate 	    strcmp(devctl_cmdname, "dev-changeonresume") == 0 ||
306*7c478bd9Sstevel@tonic-gate 	    strcmp(devctl_cmdname, "dev-promprintf") == 0 ||
307*7c478bd9Sstevel@tonic-gate 	    strcmp(devctl_cmdname, "dev-nolowerpower") == 0) {
308*7c478bd9Sstevel@tonic-gate 		dcp = devctl_pm_dev_acquire(devctl_device, 0);
309*7c478bd9Sstevel@tonic-gate 		if (dcp == NULL) {
310*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
311*7c478bd9Sstevel@tonic-gate 				"devctl: device_pm_dev_acquire %s - %s\n",
312*7c478bd9Sstevel@tonic-gate 				devctl_device, strerror(errno));
313*7c478bd9Sstevel@tonic-gate 			exit(-1);
314*7c478bd9Sstevel@tonic-gate 		}
315*7c478bd9Sstevel@tonic-gate 	} else {
316*7c478bd9Sstevel@tonic-gate 		dcp = devctl_device_acquire(devctl_device, 0);
317*7c478bd9Sstevel@tonic-gate 		if (dcp == NULL) {
318*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
319*7c478bd9Sstevel@tonic-gate 				"devctl: device_acquire %s - %s\n",
320*7c478bd9Sstevel@tonic-gate 				devctl_device, strerror(errno));
321*7c478bd9Sstevel@tonic-gate 			exit(-1);
322*7c478bd9Sstevel@tonic-gate 		}
323*7c478bd9Sstevel@tonic-gate 	}
324*7c478bd9Sstevel@tonic-gate 
325*7c478bd9Sstevel@tonic-gate 	if (verbose)
326*7c478bd9Sstevel@tonic-gate 		(void) printf("devctl: cmd (%s) device (%s)\n",
327*7c478bd9Sstevel@tonic-gate 		    devctl_cmdname, orig_path);
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 	(void) fflush(NULL);	/* get output out of the way */
330*7c478bd9Sstevel@tonic-gate 
331*7c478bd9Sstevel@tonic-gate 	rv = (dcmd->cmdf)(dcp);
332*7c478bd9Sstevel@tonic-gate 
333*7c478bd9Sstevel@tonic-gate 	if (rv == -1) {
334*7c478bd9Sstevel@tonic-gate 		perror("devctl");
335*7c478bd9Sstevel@tonic-gate 		exit(-1);
336*7c478bd9Sstevel@tonic-gate 	}
337*7c478bd9Sstevel@tonic-gate 	exit(0);
338*7c478bd9Sstevel@tonic-gate } /* main */
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate static int
341*7c478bd9Sstevel@tonic-gate dev_pm_testbusy(devctl_hdl_t dcp)
342*7c478bd9Sstevel@tonic-gate {
343*7c478bd9Sstevel@tonic-gate 	int rv;
344*7c478bd9Sstevel@tonic-gate 	uint_t *busyp;
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate 	busyp = s_malloc(sizeof (uint_t));
347*7c478bd9Sstevel@tonic-gate 	rv = devctl_pm_testbusy(dcp, busyp);
348*7c478bd9Sstevel@tonic-gate 	if (rv != -1)
349*7c478bd9Sstevel@tonic-gate 		(void) printf("%s: busy state %d\n", orig_path, *busyp);
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate 	return (0);
352*7c478bd9Sstevel@tonic-gate }
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate static int
355*7c478bd9Sstevel@tonic-gate bus_pm_teststrict(devctl_hdl_t dcp)
356*7c478bd9Sstevel@tonic-gate {
357*7c478bd9Sstevel@tonic-gate 	int rv;
358*7c478bd9Sstevel@tonic-gate 	uint_t *strict;
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 	strict = s_malloc(sizeof (uint_t));
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 	rv = devctl_pm_bus_teststrict(dcp, strict);
363*7c478bd9Sstevel@tonic-gate 	if (rv != -1)
364*7c478bd9Sstevel@tonic-gate 		(void) printf("%s: strict %d\n", orig_path, *strict);
365*7c478bd9Sstevel@tonic-gate 
366*7c478bd9Sstevel@tonic-gate 	return (0);
367*7c478bd9Sstevel@tonic-gate }
368*7c478bd9Sstevel@tonic-gate 
369*7c478bd9Sstevel@tonic-gate static int
370*7c478bd9Sstevel@tonic-gate dev_getstate(devctl_hdl_t dcp)
371*7c478bd9Sstevel@tonic-gate {
372*7c478bd9Sstevel@tonic-gate 	int rv;
373*7c478bd9Sstevel@tonic-gate 	uint_t state;
374*7c478bd9Sstevel@tonic-gate 
375*7c478bd9Sstevel@tonic-gate 	rv = devctl_device_getstate(dcp, &state);
376*7c478bd9Sstevel@tonic-gate 	if (rv != -1)
377*7c478bd9Sstevel@tonic-gate 		print_dev_state(orig_path, state);
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate 	return (0);
380*7c478bd9Sstevel@tonic-gate }
381*7c478bd9Sstevel@tonic-gate 
382*7c478bd9Sstevel@tonic-gate static int
383*7c478bd9Sstevel@tonic-gate bus_getstate(devctl_hdl_t dcp)
384*7c478bd9Sstevel@tonic-gate {
385*7c478bd9Sstevel@tonic-gate 	int rv;
386*7c478bd9Sstevel@tonic-gate 	uint_t state;
387*7c478bd9Sstevel@tonic-gate 
388*7c478bd9Sstevel@tonic-gate 	rv = devctl_bus_getstate(dcp, &state);
389*7c478bd9Sstevel@tonic-gate 	if (rv != -1)
390*7c478bd9Sstevel@tonic-gate 		print_bus_state(orig_path, state);
391*7c478bd9Sstevel@tonic-gate 
392*7c478bd9Sstevel@tonic-gate 	return (0);
393*7c478bd9Sstevel@tonic-gate }
394*7c478bd9Sstevel@tonic-gate 
395*7c478bd9Sstevel@tonic-gate /*
396*7c478bd9Sstevel@tonic-gate  * Only string property is supported now.
397*7c478bd9Sstevel@tonic-gate  * Will add more later.
398*7c478bd9Sstevel@tonic-gate  */
399*7c478bd9Sstevel@tonic-gate static void
400*7c478bd9Sstevel@tonic-gate add_prop(devctl_ddef_t ddef_hdl, char *prop_str)
401*7c478bd9Sstevel@tonic-gate {
402*7c478bd9Sstevel@tonic-gate 	char *pname, *pval, *tmp;
403*7c478bd9Sstevel@tonic-gate 	char **strs = NULL;
404*7c478bd9Sstevel@tonic-gate 	int nstr;
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate 	tmp = strchr(prop_str, '=');
407*7c478bd9Sstevel@tonic-gate 	if (tmp == NULL) {
408*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "invalid property %s", prop_str);
409*7c478bd9Sstevel@tonic-gate 		exit(-1);
410*7c478bd9Sstevel@tonic-gate 	}
411*7c478bd9Sstevel@tonic-gate 
412*7c478bd9Sstevel@tonic-gate 	(void) printf("prop string: %s\n", prop_str);
413*7c478bd9Sstevel@tonic-gate 	pname = prop_str;
414*7c478bd9Sstevel@tonic-gate 	*tmp++ = '\0';
415*7c478bd9Sstevel@tonic-gate 	if (*tmp != '"') {
416*7c478bd9Sstevel@tonic-gate 		(void) devctl_ddef_string(ddef_hdl, pname, tmp);
417*7c478bd9Sstevel@tonic-gate 		return;
418*7c478bd9Sstevel@tonic-gate 	}
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate 	nstr = 0;
421*7c478bd9Sstevel@tonic-gate 	while (*tmp != '\0') {
422*7c478bd9Sstevel@tonic-gate 		pval = tmp + 1;
423*7c478bd9Sstevel@tonic-gate 		tmp = strchr(pval, '"');
424*7c478bd9Sstevel@tonic-gate 		if (tmp == NULL) {
425*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "missing quote in %s", tmp);
426*7c478bd9Sstevel@tonic-gate 			exit(-1);
427*7c478bd9Sstevel@tonic-gate 		}
428*7c478bd9Sstevel@tonic-gate 		nstr++;
429*7c478bd9Sstevel@tonic-gate 		strs = (char **)s_realloc(strs, nstr * sizeof (char *));
430*7c478bd9Sstevel@tonic-gate 		strs[nstr - 1] = pval;
431*7c478bd9Sstevel@tonic-gate 		*tmp++ = '\0';
432*7c478bd9Sstevel@tonic-gate 		(void) printf("string[%d] = %s\n", nstr - 1, pval);
433*7c478bd9Sstevel@tonic-gate 		if (*tmp)
434*7c478bd9Sstevel@tonic-gate 			tmp = strchr(tmp, '"');
435*7c478bd9Sstevel@tonic-gate 		if (tmp == NULL) {
436*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "string not ending with quote");
437*7c478bd9Sstevel@tonic-gate 			exit(-1);
438*7c478bd9Sstevel@tonic-gate 		}
439*7c478bd9Sstevel@tonic-gate 	}
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate 	(void) devctl_ddef_string_array(ddef_hdl, pname, nstr, strs);
442*7c478bd9Sstevel@tonic-gate 	free(strs);
443*7c478bd9Sstevel@tonic-gate }
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate static int
446*7c478bd9Sstevel@tonic-gate bus_devcreate(devctl_hdl_t bus_dcp)
447*7c478bd9Sstevel@tonic-gate {
448*7c478bd9Sstevel@tonic-gate 	int rv;
449*7c478bd9Sstevel@tonic-gate 	char **propp = dev_props;
450*7c478bd9Sstevel@tonic-gate 	devctl_ddef_t ddef_hdl = NULL;
451*7c478bd9Sstevel@tonic-gate 	devctl_hdl_t dev_hdl = NULL;
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate 	ddef_hdl = devctl_ddef_alloc(dev_name, 0);
454*7c478bd9Sstevel@tonic-gate 	if (dev_props == NULL) {
455*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "dev-create: missing device props\n");
456*7c478bd9Sstevel@tonic-gate 		return (-1);
457*7c478bd9Sstevel@tonic-gate 	}
458*7c478bd9Sstevel@tonic-gate 
459*7c478bd9Sstevel@tonic-gate 	while (*propp) {
460*7c478bd9Sstevel@tonic-gate 		add_prop(ddef_hdl, *propp);
461*7c478bd9Sstevel@tonic-gate 		propp++;
462*7c478bd9Sstevel@tonic-gate 	}
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate 	if (devctl_bus_dev_create(bus_dcp, ddef_hdl, 0, &dev_hdl)) {
465*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
466*7c478bd9Sstevel@tonic-gate 		    "bus-devcreate: failed to create device node\n");
467*7c478bd9Sstevel@tonic-gate 		rv = -1;
468*7c478bd9Sstevel@tonic-gate 	} else if (devctl_get_pathname(dev_hdl, devctl_device, MAXPATHLEN)
469*7c478bd9Sstevel@tonic-gate 	    == NULL) {
470*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
471*7c478bd9Sstevel@tonic-gate 		    "bus-devcreate: failed to get device path\n");
472*7c478bd9Sstevel@tonic-gate 		rv = -1;
473*7c478bd9Sstevel@tonic-gate 	} else {
474*7c478bd9Sstevel@tonic-gate 		(void) printf("created device %s\n", devctl_device);
475*7c478bd9Sstevel@tonic-gate 		rv = 0;
476*7c478bd9Sstevel@tonic-gate 	}
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate 	devctl_ddef_free(ddef_hdl);
479*7c478bd9Sstevel@tonic-gate 	if (dev_hdl)
480*7c478bd9Sstevel@tonic-gate 		devctl_release(dev_hdl);
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate 	return (rv);
483*7c478bd9Sstevel@tonic-gate }
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate static void
486*7c478bd9Sstevel@tonic-gate print_bus_state(char *devname, uint_t state)
487*7c478bd9Sstevel@tonic-gate {
488*7c478bd9Sstevel@tonic-gate 	(void) printf("\t%s: ", devname);
489*7c478bd9Sstevel@tonic-gate 	if (state == BUS_QUIESCED)
490*7c478bd9Sstevel@tonic-gate 		(void) printf("Quiesced");
491*7c478bd9Sstevel@tonic-gate 	else if (state == BUS_ACTIVE)
492*7c478bd9Sstevel@tonic-gate 		(void) printf("Active");
493*7c478bd9Sstevel@tonic-gate 	else if (state == BUS_SHUTDOWN)
494*7c478bd9Sstevel@tonic-gate 		(void) printf("Shutdown");
495*7c478bd9Sstevel@tonic-gate 	(void) printf("\n");
496*7c478bd9Sstevel@tonic-gate }
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate static void
499*7c478bd9Sstevel@tonic-gate print_dev_state(char *devname, uint_t state)
500*7c478bd9Sstevel@tonic-gate {
501*7c478bd9Sstevel@tonic-gate 	(void) printf("\t%s: ", devname);
502*7c478bd9Sstevel@tonic-gate 	if (state & DEVICE_ONLINE) {
503*7c478bd9Sstevel@tonic-gate 		(void) printf("Online");
504*7c478bd9Sstevel@tonic-gate 		if (state & DEVICE_BUSY)
505*7c478bd9Sstevel@tonic-gate 			(void) printf(" Busy");
506*7c478bd9Sstevel@tonic-gate 		if (state & DEVICE_DOWN)
507*7c478bd9Sstevel@tonic-gate 			(void) printf(" Down");
508*7c478bd9Sstevel@tonic-gate 	} else {
509*7c478bd9Sstevel@tonic-gate 		if (state & DEVICE_OFFLINE) {
510*7c478bd9Sstevel@tonic-gate 			(void) printf("Offline");
511*7c478bd9Sstevel@tonic-gate 			if (state & DEVICE_DOWN)
512*7c478bd9Sstevel@tonic-gate 				(void) printf(" Down");
513*7c478bd9Sstevel@tonic-gate 		}
514*7c478bd9Sstevel@tonic-gate 	}
515*7c478bd9Sstevel@tonic-gate 	(void) printf("\n");
516*7c478bd9Sstevel@tonic-gate }
517*7c478bd9Sstevel@tonic-gate 
518*7c478bd9Sstevel@tonic-gate static void
519*7c478bd9Sstevel@tonic-gate setprogname(char *name)
520*7c478bd9Sstevel@tonic-gate {
521*7c478bd9Sstevel@tonic-gate 	register char *p;
522*7c478bd9Sstevel@tonic-gate 
523*7c478bd9Sstevel@tonic-gate 	if (p = strrchr(name, '/'))
524*7c478bd9Sstevel@tonic-gate 		progname = p + 1;
525*7c478bd9Sstevel@tonic-gate 	else
526*7c478bd9Sstevel@tonic-gate 		progname = name;
527*7c478bd9Sstevel@tonic-gate }
528*7c478bd9Sstevel@tonic-gate 
529*7c478bd9Sstevel@tonic-gate static struct cmds *
530*7c478bd9Sstevel@tonic-gate dc_cmd(struct cmds *cmd_tbl, char *devctl_cmdname)
531*7c478bd9Sstevel@tonic-gate {
532*7c478bd9Sstevel@tonic-gate 	int i;
533*7c478bd9Sstevel@tonic-gate 
534*7c478bd9Sstevel@tonic-gate 	for (i = 0; cmd_tbl[i].cmdname != NULL; i++) {
535*7c478bd9Sstevel@tonic-gate 		if (strcasecmp(cmd_tbl[i].cmdname, devctl_cmdname) == 0)
536*7c478bd9Sstevel@tonic-gate 			return (&cmd_tbl[i]);
537*7c478bd9Sstevel@tonic-gate 	}
538*7c478bd9Sstevel@tonic-gate 
539*7c478bd9Sstevel@tonic-gate 	return (NULL);
540*7c478bd9Sstevel@tonic-gate }
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate /*
543*7c478bd9Sstevel@tonic-gate  * list all nexus drivers exporting the :devctl minor device
544*7c478bd9Sstevel@tonic-gate  */
545*7c478bd9Sstevel@tonic-gate static void
546*7c478bd9Sstevel@tonic-gate run_list_ctlrs(void)
547*7c478bd9Sstevel@tonic-gate {
548*7c478bd9Sstevel@tonic-gate 	di_node_t dinode;
549*7c478bd9Sstevel@tonic-gate 
550*7c478bd9Sstevel@tonic-gate 	if ((dinode = di_init("/", DINFOSUBTREE|DINFOMINOR)) == NULL) {
551*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: di_init() failed\n",
552*7c478bd9Sstevel@tonic-gate 		    progname);
553*7c478bd9Sstevel@tonic-gate 		exit(-1);
554*7c478bd9Sstevel@tonic-gate 	}
555*7c478bd9Sstevel@tonic-gate 	(void) di_walk_minor(dinode, DDI_NT_NEXUS, NULL, 0, &nexif);
556*7c478bd9Sstevel@tonic-gate 	di_fini(dinode);
557*7c478bd9Sstevel@tonic-gate 	exit(0);
558*7c478bd9Sstevel@tonic-gate }
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
561*7c478bd9Sstevel@tonic-gate static int
562*7c478bd9Sstevel@tonic-gate nexif(di_node_t din, di_minor_t dim, void *arg)
563*7c478bd9Sstevel@tonic-gate {
564*7c478bd9Sstevel@tonic-gate 	char *devname;
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate 	if ((devname = di_devfs_path(din)) != NULL) {
567*7c478bd9Sstevel@tonic-gate 		(void) printf("%s%d: /devices%s\n", di_driver_name(din),
568*7c478bd9Sstevel@tonic-gate 		    di_instance(din), devname);
569*7c478bd9Sstevel@tonic-gate 		di_devfs_path_free(devname);
570*7c478bd9Sstevel@tonic-gate 	}
571*7c478bd9Sstevel@tonic-gate 
572*7c478bd9Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
573*7c478bd9Sstevel@tonic-gate }
574*7c478bd9Sstevel@tonic-gate 
575*7c478bd9Sstevel@tonic-gate void *
576*7c478bd9Sstevel@tonic-gate s_malloc(size_t len)
577*7c478bd9Sstevel@tonic-gate {
578*7c478bd9Sstevel@tonic-gate 	void *buf = malloc(len);
579*7c478bd9Sstevel@tonic-gate 
580*7c478bd9Sstevel@tonic-gate 	if (buf == NULL) {
581*7c478bd9Sstevel@tonic-gate 		perror("s_malloc failed");
582*7c478bd9Sstevel@tonic-gate 		exit(-1);
583*7c478bd9Sstevel@tonic-gate 	}
584*7c478bd9Sstevel@tonic-gate 	return (buf);
585*7c478bd9Sstevel@tonic-gate }
586*7c478bd9Sstevel@tonic-gate 
587*7c478bd9Sstevel@tonic-gate void *
588*7c478bd9Sstevel@tonic-gate s_realloc(void *ptr, size_t len)
589*7c478bd9Sstevel@tonic-gate {
590*7c478bd9Sstevel@tonic-gate 	void *buf = realloc(ptr, len);
591*7c478bd9Sstevel@tonic-gate 
592*7c478bd9Sstevel@tonic-gate 	if (buf == NULL) {
593*7c478bd9Sstevel@tonic-gate 		perror("s_realloc failed");
594*7c478bd9Sstevel@tonic-gate 		exit(-1);
595*7c478bd9Sstevel@tonic-gate 	}
596*7c478bd9Sstevel@tonic-gate 	return (buf);
597*7c478bd9Sstevel@tonic-gate }
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate char *
600*7c478bd9Sstevel@tonic-gate s_strdup(char *str)
601*7c478bd9Sstevel@tonic-gate {
602*7c478bd9Sstevel@tonic-gate 	char *buf = strdup(str);
603*7c478bd9Sstevel@tonic-gate 
604*7c478bd9Sstevel@tonic-gate 	if (buf == NULL) {
605*7c478bd9Sstevel@tonic-gate 		perror("s_malloc failed");
606*7c478bd9Sstevel@tonic-gate 		exit(-1);
607*7c478bd9Sstevel@tonic-gate 	}
608*7c478bd9Sstevel@tonic-gate 	return (buf);
609*7c478bd9Sstevel@tonic-gate }
610