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