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