10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*8276SJiri.Cervenka@Sun.COM  * Common Development and Distribution License (the "License").
6*8276SJiri.Cervenka@Sun.COM  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21*8276SJiri.Cervenka@Sun.COM 
220Sstevel@tonic-gate /*
23*8276SJiri.Cervenka@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate  * Attempt to dynamically link in the Veritas libvxvmsc.so so that we can
290Sstevel@tonic-gate  * see if there are any Veritas volumes on any of the slices.
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include <stdlib.h>
330Sstevel@tonic-gate #include <stdio.h>
340Sstevel@tonic-gate #include <strings.h>
350Sstevel@tonic-gate #include <sys/param.h>
360Sstevel@tonic-gate #include <sys/errno.h>
370Sstevel@tonic-gate #include <thread.h>
380Sstevel@tonic-gate #include <synch.h>
390Sstevel@tonic-gate #include <dlfcn.h>
400Sstevel@tonic-gate #include <link.h>
410Sstevel@tonic-gate #include <ctype.h>
420Sstevel@tonic-gate 
430Sstevel@tonic-gate #include "libdiskmgt.h"
440Sstevel@tonic-gate #include "disks_private.h"
450Sstevel@tonic-gate 
46*8276SJiri.Cervenka@Sun.COM #define	VXVM_LIB_NAME	"libvxvmsc.so"
47*8276SJiri.Cervenka@Sun.COM 
480Sstevel@tonic-gate #define	VXVM_NAME_SIZE	1
490Sstevel@tonic-gate #define	VXVM_PATH_SIZE	2
500Sstevel@tonic-gate 
510Sstevel@tonic-gate typedef char	*vm_name_t;
520Sstevel@tonic-gate typedef char	*vm_path_t;
530Sstevel@tonic-gate 
540Sstevel@tonic-gate /*
550Sstevel@tonic-gate  * Pointers to libvxvmsc.so functions that we dynamically resolve.
560Sstevel@tonic-gate  */
570Sstevel@tonic-gate static int (*vxdl_libvxvm_get_version)(int version);
580Sstevel@tonic-gate static int (*vxdl_libvxvm_get_conf)(int param);
590Sstevel@tonic-gate static int (*vxdl_libvxvm_get_dgs)(int len, vm_name_t namep[]);
600Sstevel@tonic-gate static int (*vxdl_libvxvm_get_disks)(vm_name_t dgname, int len,
610Sstevel@tonic-gate 		vm_path_t pathp[]);
620Sstevel@tonic-gate 
630Sstevel@tonic-gate #define	MAX_DISK_GROUPS 128
640Sstevel@tonic-gate #define	MAX_DISKS_DG 1024
650Sstevel@tonic-gate 
660Sstevel@tonic-gate struct vxvm_list {
670Sstevel@tonic-gate 	struct vxvm_list	*next;
680Sstevel@tonic-gate 	char			*slice;
690Sstevel@tonic-gate };
700Sstevel@tonic-gate 
710Sstevel@tonic-gate static struct vxvm_list	*vxvm_listp = NULL;
720Sstevel@tonic-gate static time_t		timestamp = 0;
730Sstevel@tonic-gate static mutex_t		vxvm_lock = DEFAULTMUTEX;
740Sstevel@tonic-gate 
750Sstevel@tonic-gate static int	add_use_record(char *devname);
760Sstevel@tonic-gate static void	free_vxvm();
770Sstevel@tonic-gate static void	*init_vxvm();
780Sstevel@tonic-gate static int	is_ctds(char *name);
790Sstevel@tonic-gate static int	load_vxvm();
800Sstevel@tonic-gate 
810Sstevel@tonic-gate int
820Sstevel@tonic-gate inuse_vxvm(char *slice, nvlist_t *attrs, int *errp)
830Sstevel@tonic-gate {
840Sstevel@tonic-gate 	int		found = 0;
850Sstevel@tonic-gate 	time_t		curr_time;
860Sstevel@tonic-gate 	char		*sp = NULL;
870Sstevel@tonic-gate 
880Sstevel@tonic-gate 	*errp = 0;
890Sstevel@tonic-gate 	if (slice == NULL) {
90*8276SJiri.Cervenka@Sun.COM 		return (found);
910Sstevel@tonic-gate 	}
920Sstevel@tonic-gate 
930Sstevel@tonic-gate 	/*
940Sstevel@tonic-gate 	 * Since vxvm "encapsulates" the disk we need to match on any
950Sstevel@tonic-gate 	 * slice passed in.  Strip the slice component from the devname.
960Sstevel@tonic-gate 	 */
970Sstevel@tonic-gate 	if (is_ctds(slice)) {
98*8276SJiri.Cervenka@Sun.COM 		if ((sp = strrchr(slice, '/')) == NULL)
99*8276SJiri.Cervenka@Sun.COM 			sp = slice;
1000Sstevel@tonic-gate 
101*8276SJiri.Cervenka@Sun.COM 		while (*sp && *sp != 's')
102*8276SJiri.Cervenka@Sun.COM 			sp++;
1030Sstevel@tonic-gate 
104*8276SJiri.Cervenka@Sun.COM 		if (*sp)
105*8276SJiri.Cervenka@Sun.COM 			*sp = 0;
106*8276SJiri.Cervenka@Sun.COM 		else
107*8276SJiri.Cervenka@Sun.COM 			sp = NULL;
1080Sstevel@tonic-gate 	}
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 	(void) mutex_lock(&vxvm_lock);
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	curr_time = time(NULL);
1130Sstevel@tonic-gate 	if (timestamp < curr_time && (curr_time - timestamp) > 60) {
114*8276SJiri.Cervenka@Sun.COM 		free_vxvm();		/* free old entries */
115*8276SJiri.Cervenka@Sun.COM 		*errp = load_vxvm();	/* load the cache */
1160Sstevel@tonic-gate 
117*8276SJiri.Cervenka@Sun.COM 		timestamp = curr_time;
1180Sstevel@tonic-gate 	}
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 	if (*errp == 0) {
121*8276SJiri.Cervenka@Sun.COM 		struct vxvm_list	*listp;
1220Sstevel@tonic-gate 
123*8276SJiri.Cervenka@Sun.COM 		listp = vxvm_listp;
124*8276SJiri.Cervenka@Sun.COM 		while (listp != NULL) {
125*8276SJiri.Cervenka@Sun.COM 			if (strcmp(slice, listp->slice) == 0) {
126*8276SJiri.Cervenka@Sun.COM 				libdiskmgt_add_str(attrs, DM_USED_BY,
127*8276SJiri.Cervenka@Sun.COM 				    DM_USE_VXVM, errp);
128*8276SJiri.Cervenka@Sun.COM 				libdiskmgt_add_str(attrs, DM_USED_NAME,
129*8276SJiri.Cervenka@Sun.COM 				    "", errp);
130*8276SJiri.Cervenka@Sun.COM 				found = 1;
131*8276SJiri.Cervenka@Sun.COM 				break;
132*8276SJiri.Cervenka@Sun.COM 			}
133*8276SJiri.Cervenka@Sun.COM 			listp = listp->next;
1340Sstevel@tonic-gate 		}
1350Sstevel@tonic-gate 	}
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate 	(void) mutex_unlock(&vxvm_lock);
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate 	/* restore slice name to orignal value */
1400Sstevel@tonic-gate 	if (sp != NULL)
141*8276SJiri.Cervenka@Sun.COM 		*sp = 's';
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 	return (found);
1440Sstevel@tonic-gate }
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate static int
1470Sstevel@tonic-gate add_use_record(char *devname)
1480Sstevel@tonic-gate {
1490Sstevel@tonic-gate 	struct vxvm_list *sp;
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate 	sp = (struct vxvm_list *)malloc(sizeof (struct vxvm_list));
1520Sstevel@tonic-gate 	if (sp == NULL) {
153*8276SJiri.Cervenka@Sun.COM 		return (ENOMEM);
1540Sstevel@tonic-gate 	}
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 	if ((sp->slice = strdup(devname)) == NULL) {
157*8276SJiri.Cervenka@Sun.COM 		free(sp);
158*8276SJiri.Cervenka@Sun.COM 		return (ENOMEM);
1590Sstevel@tonic-gate 	}
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 	sp->next = vxvm_listp;
1620Sstevel@tonic-gate 	vxvm_listp = sp;
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 	/*
1650Sstevel@tonic-gate 	 * Since vxvm "encapsulates" the disk we need to match on any
1660Sstevel@tonic-gate 	 * slice passed in.  Strip the slice component from the devname.
1670Sstevel@tonic-gate 	 */
1680Sstevel@tonic-gate 	if (is_ctds(sp->slice)) {
169*8276SJiri.Cervenka@Sun.COM 		char	*dp;
1700Sstevel@tonic-gate 
171*8276SJiri.Cervenka@Sun.COM 		if ((dp = strrchr(sp->slice, '/')) == NULL)
172*8276SJiri.Cervenka@Sun.COM 			dp = sp->slice;
1730Sstevel@tonic-gate 
174*8276SJiri.Cervenka@Sun.COM 		while (*dp && *dp != 's')
175*8276SJiri.Cervenka@Sun.COM 			dp++;
176*8276SJiri.Cervenka@Sun.COM 		*dp = 0;
1770Sstevel@tonic-gate 	}
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 	return (0);
1800Sstevel@tonic-gate }
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate /*
1830Sstevel@tonic-gate  * If the input name is in c[t]ds format then return 1, otherwise return 0.
1840Sstevel@tonic-gate  */
1850Sstevel@tonic-gate static int
1860Sstevel@tonic-gate is_ctds(char *name)
1870Sstevel@tonic-gate {
1880Sstevel@tonic-gate 	char	*p;
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate 	if ((p = strrchr(name, '/')) == NULL)
191*8276SJiri.Cervenka@Sun.COM 		p = name;
1920Sstevel@tonic-gate 	else
193*8276SJiri.Cervenka@Sun.COM 		p++;
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	if (*p++ != 'c') {
196*8276SJiri.Cervenka@Sun.COM 		return (0);
1970Sstevel@tonic-gate 	}
1980Sstevel@tonic-gate 	/* skip controller digits */
1990Sstevel@tonic-gate 	while (isdigit(*p)) {
200*8276SJiri.Cervenka@Sun.COM 		p++;
2010Sstevel@tonic-gate 	}
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	/* handle optional target */
2040Sstevel@tonic-gate 	if (*p == 't') {
2050Sstevel@tonic-gate 		p++;
206*8276SJiri.Cervenka@Sun.COM 		/* skip over target */
207*8276SJiri.Cervenka@Sun.COM 		while (isdigit(*p) || isupper(*p)) {
208*8276SJiri.Cervenka@Sun.COM 			p++;
209*8276SJiri.Cervenka@Sun.COM 		}
2100Sstevel@tonic-gate 	}
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 	if (*p++ != 'd') {
213*8276SJiri.Cervenka@Sun.COM 		return (0);
2140Sstevel@tonic-gate 	}
2150Sstevel@tonic-gate 	while (isdigit(*p)) {
216*8276SJiri.Cervenka@Sun.COM 		p++;
2170Sstevel@tonic-gate 	}
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	if (*p++ != 's') {
220*8276SJiri.Cervenka@Sun.COM 		return (0);
2210Sstevel@tonic-gate 	}
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate 	/* check the slice number */
2240Sstevel@tonic-gate 	while (isdigit(*p)) {
225*8276SJiri.Cervenka@Sun.COM 		p++;
2260Sstevel@tonic-gate 	}
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 	if (*p != 0) {
229*8276SJiri.Cervenka@Sun.COM 		return (0);
2300Sstevel@tonic-gate 	}
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 	return (1);
2330Sstevel@tonic-gate }
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate /*
2360Sstevel@tonic-gate  * Free the list of vxvm entries.
2370Sstevel@tonic-gate  */
2380Sstevel@tonic-gate static void
2390Sstevel@tonic-gate free_vxvm()
2400Sstevel@tonic-gate {
2410Sstevel@tonic-gate 	struct vxvm_list	*listp = vxvm_listp;
2420Sstevel@tonic-gate 	struct vxvm_list	*nextp;
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 	while (listp != NULL) {
245*8276SJiri.Cervenka@Sun.COM 		nextp = listp->next;
246*8276SJiri.Cervenka@Sun.COM 		free((void *)listp->slice);
247*8276SJiri.Cervenka@Sun.COM 		free((void *)listp);
248*8276SJiri.Cervenka@Sun.COM 		listp = nextp;
2490Sstevel@tonic-gate 	}
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 	vxvm_listp = NULL;
2520Sstevel@tonic-gate }
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate /*
2550Sstevel@tonic-gate  * Try to dynamically link the vxvm functions we need.
2560Sstevel@tonic-gate  */
2570Sstevel@tonic-gate static void *
2580Sstevel@tonic-gate init_vxvm()
2590Sstevel@tonic-gate {
2600Sstevel@tonic-gate 	void	*lh;
2610Sstevel@tonic-gate 
262*8276SJiri.Cervenka@Sun.COM 	if ((lh = dlopen(VXVM_LIB_NAME, RTLD_NOW)) == NULL) {
263*8276SJiri.Cervenka@Sun.COM 		return (NULL);
2640Sstevel@tonic-gate 	}
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	if ((vxdl_libvxvm_get_version = (int (*)(int))dlsym(lh,
2670Sstevel@tonic-gate 	    "libvxvm_get_version")) == NULL) {
268*8276SJiri.Cervenka@Sun.COM 		(void) dlclose(lh);
269*8276SJiri.Cervenka@Sun.COM 		return (NULL);
2700Sstevel@tonic-gate 	}
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	if ((vxdl_libvxvm_get_conf = (int (*)(int))dlsym(lh,
2730Sstevel@tonic-gate 	    "libvxvm_get_conf")) == NULL) {
274*8276SJiri.Cervenka@Sun.COM 		(void) dlclose(lh);
275*8276SJiri.Cervenka@Sun.COM 		return (NULL);
2760Sstevel@tonic-gate 	}
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	if ((vxdl_libvxvm_get_dgs = (int (*)(int, vm_name_t []))dlsym(lh,
2790Sstevel@tonic-gate 	    "libvxvm_get_dgs")) == NULL) {
280*8276SJiri.Cervenka@Sun.COM 		(void) dlclose(lh);
281*8276SJiri.Cervenka@Sun.COM 		return (NULL);
2820Sstevel@tonic-gate 	}
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 	if ((vxdl_libvxvm_get_disks = (int (*)(vm_name_t, int, vm_path_t []))
2850Sstevel@tonic-gate 	    dlsym(lh, "libvxvm_get_disks")) == NULL) {
286*8276SJiri.Cervenka@Sun.COM 		(void) dlclose(lh);
287*8276SJiri.Cervenka@Sun.COM 		return (NULL);
2880Sstevel@tonic-gate 	}
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate 	return (lh);
2910Sstevel@tonic-gate }
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate static int
2940Sstevel@tonic-gate load_vxvm()
2950Sstevel@tonic-gate {
2960Sstevel@tonic-gate 	void		*lh;
2970Sstevel@tonic-gate 	int		vers;
2980Sstevel@tonic-gate 	int		nsize;
2990Sstevel@tonic-gate 	int		psize;
3000Sstevel@tonic-gate 	int		n_disk_groups;
3010Sstevel@tonic-gate 	vm_name_t	*namep;
3020Sstevel@tonic-gate 	char		*pnp;
3030Sstevel@tonic-gate 	vm_path_t	*pathp;
3040Sstevel@tonic-gate 	int		i;
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	if ((lh = init_vxvm()) == NULL) {
307*8276SJiri.Cervenka@Sun.COM 		/* No library. */
308*8276SJiri.Cervenka@Sun.COM 		return (0);
3090Sstevel@tonic-gate 	}
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 	vers = (vxdl_libvxvm_get_version)(1 << 8);
3120Sstevel@tonic-gate 	if (vers == -1) {
313*8276SJiri.Cervenka@Sun.COM 		/* unsupported version */
314*8276SJiri.Cervenka@Sun.COM 		(void) dlclose(lh);
315*8276SJiri.Cervenka@Sun.COM 		return (0);
3160Sstevel@tonic-gate 	}
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 	nsize = (vxdl_libvxvm_get_conf)(VXVM_NAME_SIZE);
3190Sstevel@tonic-gate 	psize = (vxdl_libvxvm_get_conf)(VXVM_PATH_SIZE);
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	if (nsize == -1 || psize == -1) {
322*8276SJiri.Cervenka@Sun.COM 		(void) dlclose(lh);
323*8276SJiri.Cervenka@Sun.COM 		return (0);
3240Sstevel@tonic-gate 	}
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 	namep = (vm_name_t *)calloc(MAX_DISK_GROUPS, nsize);
3270Sstevel@tonic-gate 	if (namep == NULL) {
328*8276SJiri.Cervenka@Sun.COM 		(void) dlclose(lh);
329*8276SJiri.Cervenka@Sun.COM 		return (ENOMEM);
3300Sstevel@tonic-gate 	}
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	pathp = (vm_path_t *)calloc(MAX_DISKS_DG, psize);
3330Sstevel@tonic-gate 	if (pathp == NULL) {
334*8276SJiri.Cervenka@Sun.COM 		(void) dlclose(lh);
335*8276SJiri.Cervenka@Sun.COM 		free(namep);
336*8276SJiri.Cervenka@Sun.COM 		return (ENOMEM);
3370Sstevel@tonic-gate 	}
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	n_disk_groups = (vxdl_libvxvm_get_dgs)(MAX_DISK_GROUPS, namep);
3400Sstevel@tonic-gate 	if (n_disk_groups < 0) {
341*8276SJiri.Cervenka@Sun.COM 		(void) dlclose(lh);
342*8276SJiri.Cervenka@Sun.COM 		free(namep);
343*8276SJiri.Cervenka@Sun.COM 		free(pathp);
344*8276SJiri.Cervenka@Sun.COM 		return (0);
3450Sstevel@tonic-gate 	}
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 	pnp = (char *)namep;
3480Sstevel@tonic-gate 	for (i = 0; i < n_disk_groups; i++) {
349*8276SJiri.Cervenka@Sun.COM 		int n_disks;
3500Sstevel@tonic-gate 
351*8276SJiri.Cervenka@Sun.COM 		n_disks = (vxdl_libvxvm_get_disks)(pnp, MAX_DISKS_DG, pathp);
3520Sstevel@tonic-gate 
353*8276SJiri.Cervenka@Sun.COM 		if (n_disks >= 0) {
354*8276SJiri.Cervenka@Sun.COM 			int	j;
355*8276SJiri.Cervenka@Sun.COM 			char	*ppp;
3560Sstevel@tonic-gate 
357*8276SJiri.Cervenka@Sun.COM 			ppp = (char *)pathp;
358*8276SJiri.Cervenka@Sun.COM 			for (j = 0; j < n_disks; j++) {
3590Sstevel@tonic-gate 
360*8276SJiri.Cervenka@Sun.COM 				if (strncmp(ppp, "/dev/vx/", 8) == 0) {
361*8276SJiri.Cervenka@Sun.COM 					char	*pslash;
362*8276SJiri.Cervenka@Sun.COM 					char	nm[MAXPATHLEN];
3630Sstevel@tonic-gate 
364*8276SJiri.Cervenka@Sun.COM 					pslash = strrchr(ppp, '/');
365*8276SJiri.Cervenka@Sun.COM 					pslash++;
3660Sstevel@tonic-gate 
367*8276SJiri.Cervenka@Sun.COM 					(void) snprintf(nm, sizeof (nm),
368*8276SJiri.Cervenka@Sun.COM 					    "/dev/dsk/%s", pslash);
369*8276SJiri.Cervenka@Sun.COM 					if (add_use_record(nm)) {
370*8276SJiri.Cervenka@Sun.COM 						(void) dlclose(lh);
371*8276SJiri.Cervenka@Sun.COM 						free(pathp);
372*8276SJiri.Cervenka@Sun.COM 						free(namep);
373*8276SJiri.Cervenka@Sun.COM 						return (ENOMEM);
374*8276SJiri.Cervenka@Sun.COM 					}
375*8276SJiri.Cervenka@Sun.COM 				} else {
376*8276SJiri.Cervenka@Sun.COM 					if (add_use_record(ppp)) {
377*8276SJiri.Cervenka@Sun.COM 						(void) dlclose(lh);
378*8276SJiri.Cervenka@Sun.COM 						free(pathp);
379*8276SJiri.Cervenka@Sun.COM 						free(namep);
380*8276SJiri.Cervenka@Sun.COM 						return (ENOMEM);
381*8276SJiri.Cervenka@Sun.COM 					}
382*8276SJiri.Cervenka@Sun.COM 				}
383*8276SJiri.Cervenka@Sun.COM 
384*8276SJiri.Cervenka@Sun.COM 				ppp += psize;
3850Sstevel@tonic-gate 			}
386*8276SJiri.Cervenka@Sun.COM 		}
3870Sstevel@tonic-gate 
388*8276SJiri.Cervenka@Sun.COM 		pnp += nsize;
3890Sstevel@tonic-gate 	}
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 	(void) dlclose(lh);
3920Sstevel@tonic-gate 	free(pathp);
3930Sstevel@tonic-gate 	free(namep);
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 	return (0);
3960Sstevel@tonic-gate }
397