1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * Attempt to dynamically link in the Veritas libvxvmsc.so so that we can
31*0Sstevel@tonic-gate  * see if there are any Veritas volumes on any of the slices.
32*0Sstevel@tonic-gate  */
33*0Sstevel@tonic-gate 
34*0Sstevel@tonic-gate #include <stdlib.h>
35*0Sstevel@tonic-gate #include <stdio.h>
36*0Sstevel@tonic-gate #include <strings.h>
37*0Sstevel@tonic-gate #include <sys/param.h>
38*0Sstevel@tonic-gate #include <sys/errno.h>
39*0Sstevel@tonic-gate #include <thread.h>
40*0Sstevel@tonic-gate #include <synch.h>
41*0Sstevel@tonic-gate #include <dlfcn.h>
42*0Sstevel@tonic-gate #include <link.h>
43*0Sstevel@tonic-gate #include <ctype.h>
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate #include "libdiskmgt.h"
46*0Sstevel@tonic-gate #include "disks_private.h"
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate #define	VXVM_NAME_SIZE	1
49*0Sstevel@tonic-gate #define	VXVM_PATH_SIZE	2
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate typedef char	*vm_name_t;
52*0Sstevel@tonic-gate typedef char	*vm_path_t;
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate /*
55*0Sstevel@tonic-gate  * Pointers to libvxvmsc.so functions that we dynamically resolve.
56*0Sstevel@tonic-gate  */
57*0Sstevel@tonic-gate static int (*vxdl_libvxvm_get_version)(int version);
58*0Sstevel@tonic-gate static int (*vxdl_libvxvm_get_conf)(int param);
59*0Sstevel@tonic-gate static int (*vxdl_libvxvm_get_dgs)(int len, vm_name_t namep[]);
60*0Sstevel@tonic-gate static int (*vxdl_libvxvm_get_disks)(vm_name_t dgname, int len,
61*0Sstevel@tonic-gate 		vm_path_t pathp[]);
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate #define	MAX_DISK_GROUPS 128
64*0Sstevel@tonic-gate #define	MAX_DISKS_DG 1024
65*0Sstevel@tonic-gate 
66*0Sstevel@tonic-gate struct vxvm_list {
67*0Sstevel@tonic-gate 	struct vxvm_list	*next;
68*0Sstevel@tonic-gate 	char			*slice;
69*0Sstevel@tonic-gate };
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate static struct vxvm_list	*vxvm_listp = NULL;
72*0Sstevel@tonic-gate static time_t		timestamp = 0;
73*0Sstevel@tonic-gate static mutex_t		vxvm_lock = DEFAULTMUTEX;
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate static int	add_use_record(char *devname);
76*0Sstevel@tonic-gate static void	free_vxvm();
77*0Sstevel@tonic-gate static void	*init_vxvm();
78*0Sstevel@tonic-gate static int	is_ctds(char *name);
79*0Sstevel@tonic-gate static int	load_vxvm();
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate int
82*0Sstevel@tonic-gate inuse_vxvm(char *slice, nvlist_t *attrs, int *errp)
83*0Sstevel@tonic-gate {
84*0Sstevel@tonic-gate 	int		found = 0;
85*0Sstevel@tonic-gate 	time_t		curr_time;
86*0Sstevel@tonic-gate 	char		*sp = NULL;
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate 	*errp = 0;
89*0Sstevel@tonic-gate 	if (slice == NULL) {
90*0Sstevel@tonic-gate 	    return (found);
91*0Sstevel@tonic-gate 	}
92*0Sstevel@tonic-gate 
93*0Sstevel@tonic-gate 	/*
94*0Sstevel@tonic-gate 	 * Since vxvm "encapsulates" the disk we need to match on any
95*0Sstevel@tonic-gate 	 * slice passed in.  Strip the slice component from the devname.
96*0Sstevel@tonic-gate 	 */
97*0Sstevel@tonic-gate 	if (is_ctds(slice)) {
98*0Sstevel@tonic-gate 	    if ((sp = strrchr(slice, '/')) == NULL)
99*0Sstevel@tonic-gate 		sp = slice;
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate 	    while (*sp && *sp != 's')
102*0Sstevel@tonic-gate 		sp++;
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate 	    if (*sp)
105*0Sstevel@tonic-gate 		*sp = 0;
106*0Sstevel@tonic-gate 	    else
107*0Sstevel@tonic-gate 		sp = NULL;
108*0Sstevel@tonic-gate 	}
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate 	(void) mutex_lock(&vxvm_lock);
111*0Sstevel@tonic-gate 
112*0Sstevel@tonic-gate 	curr_time = time(NULL);
113*0Sstevel@tonic-gate 	if (timestamp < curr_time && (curr_time - timestamp) > 60) {
114*0Sstevel@tonic-gate 	    free_vxvm();		/* free old entries */
115*0Sstevel@tonic-gate 	    *errp = load_vxvm();	/* load the cache */
116*0Sstevel@tonic-gate 
117*0Sstevel@tonic-gate 	    timestamp = curr_time;
118*0Sstevel@tonic-gate 	}
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate 	if (*errp == 0) {
121*0Sstevel@tonic-gate 	    struct vxvm_list	*listp;
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate 	    listp = vxvm_listp;
124*0Sstevel@tonic-gate 	    while (listp != NULL) {
125*0Sstevel@tonic-gate 		if (strcmp(slice, listp->slice) == 0) {
126*0Sstevel@tonic-gate 		    libdiskmgt_add_str(attrs, DM_USED_BY, DM_USE_VXVM, errp);
127*0Sstevel@tonic-gate 		    libdiskmgt_add_str(attrs, DM_USED_NAME, "", errp);
128*0Sstevel@tonic-gate 		    found = 1;
129*0Sstevel@tonic-gate 		    break;
130*0Sstevel@tonic-gate 		}
131*0Sstevel@tonic-gate 		listp = listp->next;
132*0Sstevel@tonic-gate 	    }
133*0Sstevel@tonic-gate 	}
134*0Sstevel@tonic-gate 
135*0Sstevel@tonic-gate 	(void) mutex_unlock(&vxvm_lock);
136*0Sstevel@tonic-gate 
137*0Sstevel@tonic-gate 	/* restore slice name to orignal value */
138*0Sstevel@tonic-gate 	if (sp != NULL)
139*0Sstevel@tonic-gate 	    *sp = 's';
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate 	return (found);
142*0Sstevel@tonic-gate }
143*0Sstevel@tonic-gate 
144*0Sstevel@tonic-gate static int
145*0Sstevel@tonic-gate add_use_record(char *devname)
146*0Sstevel@tonic-gate {
147*0Sstevel@tonic-gate 	struct vxvm_list *sp;
148*0Sstevel@tonic-gate 
149*0Sstevel@tonic-gate 	sp = (struct vxvm_list *)malloc(sizeof (struct vxvm_list));
150*0Sstevel@tonic-gate 	if (sp == NULL) {
151*0Sstevel@tonic-gate 	    return (ENOMEM);
152*0Sstevel@tonic-gate 	}
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate 	if ((sp->slice = strdup(devname)) == NULL) {
155*0Sstevel@tonic-gate 	    free(sp);
156*0Sstevel@tonic-gate 	    return (ENOMEM);
157*0Sstevel@tonic-gate 	}
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate 	sp->next = vxvm_listp;
160*0Sstevel@tonic-gate 	vxvm_listp = sp;
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate 	/*
163*0Sstevel@tonic-gate 	 * Since vxvm "encapsulates" the disk we need to match on any
164*0Sstevel@tonic-gate 	 * slice passed in.  Strip the slice component from the devname.
165*0Sstevel@tonic-gate 	 */
166*0Sstevel@tonic-gate 	if (is_ctds(sp->slice)) {
167*0Sstevel@tonic-gate 	    char	*dp;
168*0Sstevel@tonic-gate 
169*0Sstevel@tonic-gate 	    if ((dp = strrchr(sp->slice, '/')) == NULL)
170*0Sstevel@tonic-gate 		dp = sp->slice;
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate 	    while (*dp && *dp != 's')
173*0Sstevel@tonic-gate 		dp++;
174*0Sstevel@tonic-gate 	    *dp = 0;
175*0Sstevel@tonic-gate 	}
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate 	return (0);
178*0Sstevel@tonic-gate }
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate /*
181*0Sstevel@tonic-gate  * If the input name is in c[t]ds format then return 1, otherwise return 0.
182*0Sstevel@tonic-gate  */
183*0Sstevel@tonic-gate static int
184*0Sstevel@tonic-gate is_ctds(char *name)
185*0Sstevel@tonic-gate {
186*0Sstevel@tonic-gate 	char	*p;
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate 	if ((p = strrchr(name, '/')) == NULL)
189*0Sstevel@tonic-gate 	    p = name;
190*0Sstevel@tonic-gate 	else
191*0Sstevel@tonic-gate 	    p++;
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate 	if (*p++ != 'c') {
194*0Sstevel@tonic-gate 	    return (0);
195*0Sstevel@tonic-gate 	}
196*0Sstevel@tonic-gate 	/* skip controller digits */
197*0Sstevel@tonic-gate 	while (isdigit(*p)) {
198*0Sstevel@tonic-gate 	    p++;
199*0Sstevel@tonic-gate 	}
200*0Sstevel@tonic-gate 
201*0Sstevel@tonic-gate 	/* handle optional target */
202*0Sstevel@tonic-gate 	if (*p == 't') {
203*0Sstevel@tonic-gate 	    p++;
204*0Sstevel@tonic-gate 	    /* skip over target */
205*0Sstevel@tonic-gate 	    while (isdigit(*p) || isupper(*p)) {
206*0Sstevel@tonic-gate 		p++;
207*0Sstevel@tonic-gate 	    }
208*0Sstevel@tonic-gate 	}
209*0Sstevel@tonic-gate 
210*0Sstevel@tonic-gate 	if (*p++ != 'd') {
211*0Sstevel@tonic-gate 	    return (0);
212*0Sstevel@tonic-gate 	}
213*0Sstevel@tonic-gate 	while (isdigit(*p)) {
214*0Sstevel@tonic-gate 	    p++;
215*0Sstevel@tonic-gate 	}
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate 	if (*p++ != 's') {
218*0Sstevel@tonic-gate 	    return (0);
219*0Sstevel@tonic-gate 	}
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate 	/* check the slice number */
222*0Sstevel@tonic-gate 	while (isdigit(*p)) {
223*0Sstevel@tonic-gate 	    p++;
224*0Sstevel@tonic-gate 	}
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate 	if (*p != 0) {
227*0Sstevel@tonic-gate 	    return (0);
228*0Sstevel@tonic-gate 	}
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate 	return (1);
231*0Sstevel@tonic-gate }
232*0Sstevel@tonic-gate 
233*0Sstevel@tonic-gate /*
234*0Sstevel@tonic-gate  * Free the list of vxvm entries.
235*0Sstevel@tonic-gate  */
236*0Sstevel@tonic-gate static void
237*0Sstevel@tonic-gate free_vxvm()
238*0Sstevel@tonic-gate {
239*0Sstevel@tonic-gate 	struct vxvm_list	*listp = vxvm_listp;
240*0Sstevel@tonic-gate 	struct vxvm_list	*nextp;
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate 	while (listp != NULL) {
243*0Sstevel@tonic-gate 	    nextp = listp->next;
244*0Sstevel@tonic-gate 	    free((void *)listp->slice);
245*0Sstevel@tonic-gate 	    free((void *)listp);
246*0Sstevel@tonic-gate 	    listp = nextp;
247*0Sstevel@tonic-gate 	}
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate 	vxvm_listp = NULL;
250*0Sstevel@tonic-gate }
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate /*
253*0Sstevel@tonic-gate  * Try to dynamically link the vxvm functions we need.
254*0Sstevel@tonic-gate  */
255*0Sstevel@tonic-gate static void *
256*0Sstevel@tonic-gate init_vxvm()
257*0Sstevel@tonic-gate {
258*0Sstevel@tonic-gate 	void	*lh;
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate 	if ((lh = dlopen("libvxvmsc.so", RTLD_NOW)) == NULL) {
261*0Sstevel@tonic-gate 	    return (lh);
262*0Sstevel@tonic-gate 	}
263*0Sstevel@tonic-gate 
264*0Sstevel@tonic-gate 	if ((vxdl_libvxvm_get_version = (int (*)(int))dlsym(lh,
265*0Sstevel@tonic-gate 	    "libvxvm_get_version")) == NULL) {
266*0Sstevel@tonic-gate 	    (void) dlclose(lh);
267*0Sstevel@tonic-gate 	    return (NULL);
268*0Sstevel@tonic-gate 	}
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate 	if ((vxdl_libvxvm_get_conf = (int (*)(int))dlsym(lh,
271*0Sstevel@tonic-gate 	    "libvxvm_get_conf")) == NULL) {
272*0Sstevel@tonic-gate 	    (void) dlclose(lh);
273*0Sstevel@tonic-gate 	    return (NULL);
274*0Sstevel@tonic-gate 	}
275*0Sstevel@tonic-gate 
276*0Sstevel@tonic-gate 	if ((vxdl_libvxvm_get_dgs = (int (*)(int, vm_name_t []))dlsym(lh,
277*0Sstevel@tonic-gate 	    "libvxvm_get_dgs")) == NULL) {
278*0Sstevel@tonic-gate 	    (void) dlclose(lh);
279*0Sstevel@tonic-gate 	    return (NULL);
280*0Sstevel@tonic-gate 	}
281*0Sstevel@tonic-gate 
282*0Sstevel@tonic-gate 	if ((vxdl_libvxvm_get_disks = (int (*)(vm_name_t, int, vm_path_t []))
283*0Sstevel@tonic-gate 	    dlsym(lh, "libvxvm_get_disks")) == NULL) {
284*0Sstevel@tonic-gate 	    (void) dlclose(lh);
285*0Sstevel@tonic-gate 	    return (NULL);
286*0Sstevel@tonic-gate 	}
287*0Sstevel@tonic-gate 
288*0Sstevel@tonic-gate 	return (lh);
289*0Sstevel@tonic-gate }
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate static int
292*0Sstevel@tonic-gate load_vxvm()
293*0Sstevel@tonic-gate {
294*0Sstevel@tonic-gate 	void		*lh;
295*0Sstevel@tonic-gate 	int		vers;
296*0Sstevel@tonic-gate 	int		nsize;
297*0Sstevel@tonic-gate 	int		psize;
298*0Sstevel@tonic-gate 	int		n_disk_groups;
299*0Sstevel@tonic-gate 	vm_name_t	*namep;
300*0Sstevel@tonic-gate 	char		*pnp;
301*0Sstevel@tonic-gate 	vm_path_t	*pathp;
302*0Sstevel@tonic-gate 	int		i;
303*0Sstevel@tonic-gate 
304*0Sstevel@tonic-gate 	if ((lh = init_vxvm()) == NULL) {
305*0Sstevel@tonic-gate 	    /* No library. */
306*0Sstevel@tonic-gate 	    return (0);
307*0Sstevel@tonic-gate 	}
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate 	vers = (vxdl_libvxvm_get_version)(1 << 8);
310*0Sstevel@tonic-gate 	if (vers == -1) {
311*0Sstevel@tonic-gate 	    /* unsupported version */
312*0Sstevel@tonic-gate 	    (void) dlclose(lh);
313*0Sstevel@tonic-gate 	    return (0);
314*0Sstevel@tonic-gate 	}
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 	nsize = (vxdl_libvxvm_get_conf)(VXVM_NAME_SIZE);
317*0Sstevel@tonic-gate 	psize = (vxdl_libvxvm_get_conf)(VXVM_PATH_SIZE);
318*0Sstevel@tonic-gate 
319*0Sstevel@tonic-gate 	if (nsize == -1 || psize == -1) {
320*0Sstevel@tonic-gate 	    (void) dlclose(lh);
321*0Sstevel@tonic-gate 	    return (0);
322*0Sstevel@tonic-gate 	}
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate 	namep = (vm_name_t *)calloc(MAX_DISK_GROUPS, nsize);
325*0Sstevel@tonic-gate 	if (namep == NULL) {
326*0Sstevel@tonic-gate 	    (void) dlclose(lh);
327*0Sstevel@tonic-gate 	    return (ENOMEM);
328*0Sstevel@tonic-gate 	}
329*0Sstevel@tonic-gate 
330*0Sstevel@tonic-gate 	pathp = (vm_path_t *)calloc(MAX_DISKS_DG, psize);
331*0Sstevel@tonic-gate 	if (pathp == NULL) {
332*0Sstevel@tonic-gate 	    (void) dlclose(lh);
333*0Sstevel@tonic-gate 	    free(namep);
334*0Sstevel@tonic-gate 	    return (ENOMEM);
335*0Sstevel@tonic-gate 	}
336*0Sstevel@tonic-gate 
337*0Sstevel@tonic-gate 	n_disk_groups = (vxdl_libvxvm_get_dgs)(MAX_DISK_GROUPS, namep);
338*0Sstevel@tonic-gate 	if (n_disk_groups < 0) {
339*0Sstevel@tonic-gate 	    (void) dlclose(lh);
340*0Sstevel@tonic-gate 	    free(namep);
341*0Sstevel@tonic-gate 	    free(pathp);
342*0Sstevel@tonic-gate 	    return (0);
343*0Sstevel@tonic-gate 	}
344*0Sstevel@tonic-gate 
345*0Sstevel@tonic-gate 	pnp = (char *)namep;
346*0Sstevel@tonic-gate 	for (i = 0; i < n_disk_groups; i++) {
347*0Sstevel@tonic-gate 	    int n_disks;
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate 	    n_disks = (vxdl_libvxvm_get_disks)(pnp, MAX_DISKS_DG, pathp);
350*0Sstevel@tonic-gate 
351*0Sstevel@tonic-gate 	    if (n_disks >= 0) {
352*0Sstevel@tonic-gate 		int	j;
353*0Sstevel@tonic-gate 		char	*ppp;
354*0Sstevel@tonic-gate 
355*0Sstevel@tonic-gate 		ppp = (char *)pathp;
356*0Sstevel@tonic-gate 		for (j = 0; j < n_disks; j++) {
357*0Sstevel@tonic-gate 
358*0Sstevel@tonic-gate 		    if (strncmp(ppp, "/dev/vx/", 8) == 0) {
359*0Sstevel@tonic-gate 			char	*pslash;
360*0Sstevel@tonic-gate 			char	nm[MAXPATHLEN];
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate 			pslash = strrchr(ppp, '/');
363*0Sstevel@tonic-gate 			pslash++;
364*0Sstevel@tonic-gate 
365*0Sstevel@tonic-gate 			(void) snprintf(nm, sizeof (nm), "/dev/dsk/%s", pslash);
366*0Sstevel@tonic-gate 			if (add_use_record(nm)) {
367*0Sstevel@tonic-gate 			    (void) dlclose(lh);
368*0Sstevel@tonic-gate 			    free(pathp);
369*0Sstevel@tonic-gate 			    free(namep);
370*0Sstevel@tonic-gate 			    return (ENOMEM);
371*0Sstevel@tonic-gate 			}
372*0Sstevel@tonic-gate 		    } else {
373*0Sstevel@tonic-gate 			if (add_use_record(ppp)) {
374*0Sstevel@tonic-gate 			    (void) dlclose(lh);
375*0Sstevel@tonic-gate 			    free(pathp);
376*0Sstevel@tonic-gate 			    free(namep);
377*0Sstevel@tonic-gate 			    return (ENOMEM);
378*0Sstevel@tonic-gate 			}
379*0Sstevel@tonic-gate 		    }
380*0Sstevel@tonic-gate 
381*0Sstevel@tonic-gate 		    ppp += psize;
382*0Sstevel@tonic-gate 		}
383*0Sstevel@tonic-gate 	    }
384*0Sstevel@tonic-gate 
385*0Sstevel@tonic-gate 	    pnp += nsize;
386*0Sstevel@tonic-gate 	}
387*0Sstevel@tonic-gate 
388*0Sstevel@tonic-gate 	(void) dlclose(lh);
389*0Sstevel@tonic-gate 	free(pathp);
390*0Sstevel@tonic-gate 	free(namep);
391*0Sstevel@tonic-gate 
392*0Sstevel@tonic-gate 	return (0);
393*0Sstevel@tonic-gate }
394