xref: /illumos-gate/usr/src/lib/libdiskmgt/common/entry.c (revision a07094369b21309434206d9b3601d162693466fc)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <fcntl.h>
30 #include <libdevinfo.h>
31 #include <stdio.h>
32 #include <sys/sunddi.h>
33 #include <sys/types.h>
34 #include <unistd.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <libintl.h>
38 #include <locale.h>
39 #include <sys/debug.h>
40 
41 #include "libdiskmgt.h"
42 #include "disks_private.h"
43 #include "partition.h"
44 
45 extern	char	*getfullblkname();
46 
47 
48 extern dm_desc_type_t drive_assoc_types[];
49 extern dm_desc_type_t bus_assoc_types[];
50 extern dm_desc_type_t controller_assoc_types[];
51 extern dm_desc_type_t media_assoc_types[];
52 extern dm_desc_type_t slice_assoc_types[];
53 extern dm_desc_type_t partition_assoc_types[];
54 extern dm_desc_type_t path_assoc_types[];
55 extern dm_desc_type_t alias_assoc_types[];
56 
57 
58 static dm_descriptor_t *ptr_array_to_desc_array(descriptor_t **ptrs, int *errp);
59 static descriptor_t **desc_array_to_ptr_array(dm_descriptor_t *da, int *errp);
60 static int build_usage_string(char *dname, char *by, char *data, char **use,
61 	int *found, int *errp);
62 
63 void
64 dm_free_descriptor(dm_descriptor_t desc)
65 {
66 	descriptor_t	*dp;
67 
68 	if (desc == NULL) {
69 	    return;
70 	}
71 	dp = (descriptor_t *)(uintptr_t)desc;
72 
73 	cache_wlock();
74 	cache_free_descriptor(dp);
75 	cache_unlock();
76 }
77 
78 void
79 dm_free_descriptors(dm_descriptor_t *desc_list)
80 {
81 	descriptor_t	**dp;
82 	int		error;
83 
84 	if (desc_list == NULL) {
85 	    return;
86 	}
87 	dp = desc_array_to_ptr_array(desc_list, &error);
88 	if (error != 0) {
89 	    free(desc_list);
90 	    return;
91 	}
92 
93 	cache_wlock();
94 	cache_free_descriptors(dp);
95 	cache_unlock();
96 }
97 
98 /*ARGSUSED*/
99 void
100 dm_free_name(char *name)
101 {
102 	free(name);
103 }
104 
105 dm_descriptor_t *
106 dm_get_associated_descriptors(dm_descriptor_t desc, dm_desc_type_t type,
107     int *errp)
108 {
109 	descriptor_t **descs = NULL;
110 	descriptor_t  *dp;
111 
112 
113 	dp = (descriptor_t *)(uintptr_t)desc;
114 
115 	cache_wlock();
116 
117 	if (!cache_is_valid_desc(dp)) {
118 	    cache_unlock();
119 	    *errp = EBADF;
120 	    return (NULL);
121 	}
122 
123 	/* verify that the descriptor is still valid */
124 	if (dp->p.generic == NULL) {
125 	    cache_unlock();
126 	    *errp = ENODEV;
127 	    return (NULL);
128 	}
129 
130 	switch (dp->type) {
131 	case DM_DRIVE:
132 	    descs = drive_get_assoc_descriptors(dp, type, errp);
133 	    break;
134 	case DM_BUS:
135 	    descs = bus_get_assoc_descriptors(dp, type, errp);
136 	    break;
137 	case DM_CONTROLLER:
138 	    descs = controller_get_assoc_descriptors(dp, type, errp);
139 	    break;
140 	case DM_MEDIA:
141 	    descs = media_get_assoc_descriptors(dp, type, errp);
142 	    break;
143 	case DM_SLICE:
144 	    descs = slice_get_assoc_descriptors(dp, type, errp);
145 	    break;
146 	case DM_PARTITION:
147 	    descs = partition_get_assoc_descriptors(dp, type, errp);
148 	    break;
149 	case DM_PATH:
150 	    descs = path_get_assoc_descriptors(dp, type, errp);
151 	    break;
152 	case DM_ALIAS:
153 	    descs = alias_get_assoc_descriptors(dp, type, errp);
154 	    break;
155 	default:
156 	    *errp = EINVAL;
157 	    break;
158 	}
159 
160 	cache_unlock();
161 
162 	return (ptr_array_to_desc_array(descs, errp));
163 }
164 
165 dm_desc_type_t *
166 dm_get_associated_types(dm_desc_type_t type)
167 {
168 	switch (type) {
169 	case DM_DRIVE:
170 	    return (drive_assoc_types);
171 	case DM_BUS:
172 	    return (bus_assoc_types);
173 	case DM_CONTROLLER:
174 	    return (controller_assoc_types);
175 	case DM_MEDIA:
176 	    return (media_assoc_types);
177 	case DM_SLICE:
178 	    return (slice_assoc_types);
179 	case DM_PARTITION:
180 	    return (partition_assoc_types);
181 	case DM_PATH:
182 	    return (path_assoc_types);
183 	case DM_ALIAS:
184 	    return (alias_assoc_types);
185 	}
186 
187 	return (NULL);
188 }
189 
190 nvlist_t *
191 dm_get_attributes(dm_descriptor_t desc, int *errp)
192 {
193 	descriptor_t	*dp;
194 	nvlist_t	*attrs = NULL;
195 
196 
197 	dp = (descriptor_t *)(uintptr_t)desc;
198 
199 	cache_rlock();
200 
201 	if (!cache_is_valid_desc(dp)) {
202 	    cache_unlock();
203 	    *errp = EBADF;
204 	    return (NULL);
205 	}
206 
207 	/* verify that the descriptor is still valid */
208 	if (dp->p.generic == NULL) {
209 	    cache_unlock();
210 	    *errp = ENODEV;
211 	    return (NULL);
212 	}
213 
214 	switch (dp->type) {
215 	case DM_DRIVE:
216 	    attrs = drive_get_attributes(dp, errp);
217 	    break;
218 	case DM_BUS:
219 	    attrs = bus_get_attributes(dp, errp);
220 	    break;
221 	case DM_CONTROLLER:
222 	    attrs = controller_get_attributes(dp, errp);
223 	    break;
224 	case DM_MEDIA:
225 	    attrs = media_get_attributes(dp, errp);
226 	    break;
227 	case DM_SLICE:
228 	    attrs = slice_get_attributes(dp, errp);
229 	    break;
230 	case DM_PARTITION:
231 	    attrs = partition_get_attributes(dp, errp);
232 	    break;
233 	case DM_PATH:
234 	    attrs = path_get_attributes(dp, errp);
235 	    break;
236 	case DM_ALIAS:
237 	    attrs = alias_get_attributes(dp, errp);
238 	    break;
239 	default:
240 	    *errp = EINVAL;
241 	    break;
242 	}
243 
244 	cache_unlock();
245 
246 	return (attrs);
247 }
248 
249 dm_descriptor_t
250 dm_get_descriptor_by_name(dm_desc_type_t desc_type, char *name, int *errp)
251 {
252 	dm_descriptor_t desc = NULL;
253 
254 
255 	cache_wlock();
256 
257 	switch (desc_type) {
258 	case DM_DRIVE:
259 	    desc = (uintptr_t)drive_get_descriptor_by_name(name, errp);
260 	    break;
261 	case DM_BUS:
262 	    desc = (uintptr_t)bus_get_descriptor_by_name(name, errp);
263 	    break;
264 	case DM_CONTROLLER:
265 	    desc = (uintptr_t)controller_get_descriptor_by_name(name,
266 		errp);
267 	    break;
268 	case DM_MEDIA:
269 	    desc = (uintptr_t)media_get_descriptor_by_name(name, errp);
270 	    break;
271 	case DM_SLICE:
272 	    desc = (uintptr_t)slice_get_descriptor_by_name(name, errp);
273 	    break;
274 	case DM_PARTITION:
275 	    desc = (uintptr_t)partition_get_descriptor_by_name(name,
276 		errp);
277 	    break;
278 	case DM_PATH:
279 	    desc = (uintptr_t)path_get_descriptor_by_name(name, errp);
280 	    break;
281 	case DM_ALIAS:
282 	    desc = (uintptr_t)alias_get_descriptor_by_name(name, errp);
283 	    break;
284 	default:
285 	    *errp = EINVAL;
286 	    break;
287 	}
288 
289 	cache_unlock();
290 
291 	return (desc);
292 }
293 
294 dm_descriptor_t *
295 dm_get_descriptors(dm_desc_type_t type, int filter[], int *errp)
296 {
297 	descriptor_t **descs = NULL;
298 
299 
300 	cache_wlock();
301 
302 	switch (type) {
303 	case DM_DRIVE:
304 	    descs = drive_get_descriptors(filter, errp);
305 	    break;
306 	case DM_BUS:
307 	    descs = bus_get_descriptors(filter, errp);
308 	    break;
309 	case DM_CONTROLLER:
310 	    descs = controller_get_descriptors(filter, errp);
311 	    break;
312 	case DM_MEDIA:
313 	    descs = media_get_descriptors(filter, errp);
314 	    break;
315 	case DM_SLICE:
316 	    descs = slice_get_descriptors(filter, errp);
317 	    break;
318 	case DM_PARTITION:
319 	    descs = partition_get_descriptors(filter, errp);
320 	    break;
321 	case DM_PATH:
322 	    descs = path_get_descriptors(filter, errp);
323 	    break;
324 	case DM_ALIAS:
325 	    descs = alias_get_descriptors(filter, errp);
326 	    break;
327 	default:
328 	    *errp = EINVAL;
329 	    break;
330 	}
331 
332 	cache_unlock();
333 
334 	return (ptr_array_to_desc_array(descs, errp));
335 }
336 
337 char *
338 dm_get_name(dm_descriptor_t desc, int *errp)
339 {
340 	descriptor_t	*dp;
341 	char		*nm = NULL;
342 	char		*name = NULL;
343 
344 	dp = (descriptor_t *)(uintptr_t)desc;
345 
346 	cache_rlock();
347 
348 	if (!cache_is_valid_desc(dp)) {
349 	    cache_unlock();
350 	    *errp = EBADF;
351 	    return (NULL);
352 	}
353 
354 	/* verify that the descriptor is still valid */
355 	if (dp->p.generic == NULL) {
356 	    cache_unlock();
357 	    *errp = ENODEV;
358 	    return (NULL);
359 	}
360 
361 	switch (dp->type) {
362 	case DM_DRIVE:
363 	    nm = (drive_get_name(dp));
364 	    break;
365 	case DM_BUS:
366 	    nm = (bus_get_name(dp));
367 	    break;
368 	case DM_CONTROLLER:
369 	    nm = (controller_get_name(dp));
370 	    break;
371 	case DM_MEDIA:
372 	    nm = (media_get_name(dp));
373 	    break;
374 	case DM_SLICE:
375 	    nm = (slice_get_name(dp));
376 	    break;
377 	case DM_PARTITION:
378 	    nm = (partition_get_name(dp));
379 	    break;
380 	case DM_PATH:
381 	    nm = (path_get_name(dp));
382 	    break;
383 	case DM_ALIAS:
384 	    nm = (alias_get_name(dp));
385 	    break;
386 	}
387 
388 	cache_unlock();
389 
390 	*errp = 0;
391 	if (nm != NULL) {
392 	    name = strdup(nm);
393 	    if (name == NULL) {
394 		*errp = ENOMEM;
395 		return (NULL);
396 	    }
397 	    return (name);
398 	}
399 	return (NULL);
400 }
401 
402 nvlist_t *
403 dm_get_stats(dm_descriptor_t desc, int stat_type, int *errp)
404 {
405 	descriptor_t  *dp;
406 	nvlist_t	*stats = NULL;
407 
408 
409 	dp = (descriptor_t *)(uintptr_t)desc;
410 
411 	cache_rlock();
412 
413 	if (!cache_is_valid_desc(dp)) {
414 		cache_unlock();
415 		*errp = EBADF;
416 		return (NULL);
417 	}
418 
419 	/* verify that the descriptor is still valid */
420 	if (dp->p.generic == NULL) {
421 		cache_unlock();
422 		*errp = ENODEV;
423 		return (NULL);
424 	}
425 
426 	switch (dp->type) {
427 	case DM_DRIVE:
428 		stats = drive_get_stats(dp, stat_type, errp);
429 		break;
430 	case DM_BUS:
431 		stats = bus_get_stats(dp, stat_type, errp);
432 		break;
433 	case DM_CONTROLLER:
434 		stats = controller_get_stats(dp, stat_type, errp);
435 		break;
436 	case DM_MEDIA:
437 		stats = media_get_stats(dp, stat_type, errp);
438 		break;
439 	case DM_SLICE:
440 		if (stat_type == DM_SLICE_STAT_USE) {
441 			/*
442 			 * If NOINUSE_CHECK is set, we do not perform
443 			 * the in use checking if the user has set stat_type
444 			 * DM_SLICE_STAT_USE
445 			 */
446 			if (NOINUSE_SET) {
447 				stats = NULL;
448 				break;
449 			}
450 		}
451 		stats = slice_get_stats(dp, stat_type, errp);
452 		break;
453 	case DM_PARTITION:
454 		stats = partition_get_stats(dp, stat_type, errp);
455 		break;
456 	case DM_PATH:
457 		stats = path_get_stats(dp, stat_type, errp);
458 		break;
459 	case DM_ALIAS:
460 		stats = alias_get_stats(dp, stat_type, errp);
461 		break;
462 	default:
463 		*errp = EINVAL;
464 		break;
465 	}
466 
467 	cache_unlock();
468 
469 	return (stats);
470 }
471 
472 dm_desc_type_t
473 dm_get_type(dm_descriptor_t desc)
474 {
475 	descriptor_t  *dp;
476 
477 	dp = (descriptor_t *)(uintptr_t)desc;
478 
479 	cache_rlock();
480 
481 	if (!cache_is_valid_desc(dp)) {
482 	    cache_unlock();
483 	    return (-1);
484 	}
485 
486 	cache_unlock();
487 
488 	return (dp->type);
489 }
490 /*
491  * Returns, via slices paramater, a dm_descriptor_t list of
492  * slices for the named disk drive.
493  */
494 void
495 dm_get_slices(char *drive, dm_descriptor_t **slices, int *errp)
496 {
497 	dm_descriptor_t alias;
498 	dm_descriptor_t	*media;
499 	dm_descriptor_t *disk;
500 
501 	*slices = NULL;
502 	*errp = 0;
503 
504 	if (drive == NULL) {
505 		return;
506 	}
507 
508 	alias = dm_get_descriptor_by_name(DM_ALIAS, drive, errp);
509 
510 	/*
511 	 * Errors must be handled by the caller. The dm_descriptor_t *
512 	 * values will be NULL if an error occured in these calls.
513 	 */
514 
515 	if (alias != NULL) {
516 		disk = dm_get_associated_descriptors(alias, DM_DRIVE, errp);
517 		dm_free_descriptor(alias);
518 		if (disk != NULL) {
519 			media = dm_get_associated_descriptors(*disk,
520 			    DM_MEDIA, errp);
521 			dm_free_descriptors(disk);
522 			if (media != NULL) {
523 				*slices = dm_get_associated_descriptors(*media,
524 				    DM_SLICE, errp);
525 				dm_free_descriptors(media);
526 			}
527 		}
528 	}
529 }
530 /*
531  * Convenience function to get slice stats
532  */
533 void
534 dm_get_slice_stats(char *slice, nvlist_t **dev_stats, int *errp)
535 {
536 	dm_descriptor_t	devp;
537 
538 	*dev_stats = NULL;
539 	*errp = 0;
540 
541 	if (slice == NULL) {
542 		return;
543 	}
544 
545 	/*
546 	 * Errors must be handled by the caller. The dm_descriptor_t *
547 	 * values will be NULL if an error occured in these calls.
548 	 */
549 	devp = dm_get_descriptor_by_name(DM_SLICE, slice, errp);
550 	if (devp != NULL) {
551 		*dev_stats = dm_get_stats(devp, DM_SLICE_STAT_USE,
552 		    errp);
553 		dm_free_descriptor(devp);
554 	}
555 }
556 
557 /*
558  * Checks for overlapping slices.   If the given device is a slice, and it
559  * overlaps with any non-backup slice on the disk, return true with a detailed
560  * description similar to dm_inuse().
561  */
562 int
563 dm_isoverlapping(char *slicename, char **overlaps_with, int *errp)
564 {
565 	dm_descriptor_t slice = NULL;
566 	dm_descriptor_t *media = NULL;
567 	dm_descriptor_t *slices = NULL;
568 	int 		i = 0;
569 	uint32_t	in_snum;
570 	uint64_t 	start_block = 0;
571 	uint64_t 	end_block = 0;
572 	uint64_t 	media_size = 0;
573 	uint64_t 	size = 0;
574 	nvlist_t 	*media_attrs = NULL;
575 	nvlist_t 	*slice_attrs = NULL;
576 	int		ret = 0;
577 
578 	slice = dm_get_descriptor_by_name(DM_SLICE, slicename, errp);
579 	if (slice == NULL)
580 		goto out;
581 
582 	/*
583 	 * Get the list of slices be fetching the associated media, and then all
584 	 * associated slices.
585 	 */
586 	media = dm_get_associated_descriptors(slice, DM_MEDIA, errp);
587 	if (media == NULL || *media == NULL || *errp != 0)
588 		goto out;
589 
590 	slices = dm_get_associated_descriptors(*media, DM_SLICE, errp);
591 	if (slices == NULL || *slices == NULL || *errp != 0)
592 		goto out;
593 
594 	media_attrs = dm_get_attributes(*media, errp);
595 	if (media_attrs == NULL || *errp)
596 		goto out;
597 
598 	*errp = nvlist_lookup_uint64(media_attrs, DM_NACCESSIBLE, &media_size);
599 	if (*errp != 0)
600 		goto out;
601 
602 	slice_attrs = dm_get_attributes(slice, errp);
603 	if (slice_attrs == NULL || *errp != 0)
604 		goto out;
605 
606 	*errp = nvlist_lookup_uint64(slice_attrs, DM_START, &start_block);
607 	if (*errp != 0)
608 		goto out;
609 
610 	*errp = nvlist_lookup_uint64(slice_attrs, DM_SIZE, &size);
611 	if (*errp != 0)
612 		goto out;
613 
614 	*errp = nvlist_lookup_uint32(slice_attrs, DM_INDEX, &in_snum);
615 	if (*errp != 0)
616 		goto out;
617 
618 	end_block = (start_block + size) - 1;
619 
620 	for (i = 0; slices[i]; i ++) {
621 		uint64_t other_start;
622 		uint64_t other_end;
623 		uint64_t other_size;
624 		uint32_t snum;
625 
626 		nvlist_t *other_attrs = dm_get_attributes(slices[i], errp);
627 
628 		if (other_attrs == NULL)
629 			continue;
630 
631 		if (*errp != 0)
632 			goto out;
633 
634 		*errp = nvlist_lookup_uint64(other_attrs, DM_START,
635 		    &other_start);
636 		if (*errp) {
637 			nvlist_free(other_attrs);
638 			goto out;
639 		}
640 
641 		*errp = nvlist_lookup_uint64(other_attrs, DM_SIZE,
642 		    &other_size);
643 
644 		if (*errp) {
645 			nvlist_free(other_attrs);
646 			ret = -1;
647 			goto out;
648 		}
649 
650 		other_end = (other_size + other_start) - 1;
651 
652 		*errp = nvlist_lookup_uint32(other_attrs, DM_INDEX,
653 		    &snum);
654 
655 		if (*errp) {
656 			nvlist_free(other_attrs);
657 			ret = -1;
658 			goto out;
659 		}
660 
661 		/*
662 		 * Check to see if there are > 2 overlapping regions
663 		 * on this media in the same region as this slice.
664 		 * This is done by assuming the following:
665 		 *   	Slice 2 is the backup slice if it is the size
666 		 *	of the whole disk
667 		 * If slice 2 is the overlap and slice 2 is the size of
668 		 * the whole disk, continue. If another slice is found
669 		 * that overlaps with our slice, return it.
670 		 * There is the potential that there is more than one slice
671 		 * that our slice overlaps with, however, we only return
672 		 * the first overlapping slice we find.
673 		 *
674 		 */
675 		if (start_block >= other_start && start_block <= other_end) {
676 			if ((snum == 2 && (other_size == media_size)) ||
677 			    snum == in_snum) {
678 				continue;
679 			} else {
680 				char *str = dm_get_name(slices[i], errp);
681 				if (*errp != 0) {
682 					nvlist_free(other_attrs);
683 					ret = -1;
684 					goto out;
685 				}
686 				*overlaps_with = strdup(str);
687 				dm_free_name(str);
688 				nvlist_free(other_attrs);
689 				ret = 1;
690 				goto out;
691 			}
692 		} else if (other_start >= start_block &&
693 		    other_start <= end_block) {
694 			if ((snum == 2 && (other_size == media_size)) ||
695 			    snum == in_snum) {
696 				continue;
697 			} else {
698 				char *str = dm_get_name(slices[i], errp);
699 				if (*errp != 0) {
700 					nvlist_free(other_attrs);
701 					ret = -1;
702 					goto out;
703 				}
704 				*overlaps_with = strdup(str);
705 				dm_free_name(str);
706 				nvlist_free(other_attrs);
707 				ret = 1;
708 				goto out;
709 			}
710 		}
711 		nvlist_free(other_attrs);
712 	}
713 
714 out:
715 	if (media_attrs)
716 		nvlist_free(media_attrs);
717 	if (slice_attrs)
718 		nvlist_free(slice_attrs);
719 
720 	if (slices)
721 		dm_free_descriptors(slices);
722 	if (media)
723 		dm_free_descriptors(media);
724 	if (slice)
725 		dm_free_descriptor(slice);
726 
727 	return (ret);
728 }
729 
730 /*
731  * Returns 'in use' details, if found, about a specific dev_name,
732  * based on the caller(who). It is important to note that it is possible
733  * for there to be more than one 'in use' statistic regarding a dev_name.
734  * The **msg parameter returns a list of 'in use' details. This message
735  * is formatted via gettext().
736  */
737 int
738 dm_inuse(char *dev_name, char **msg, dm_who_type_t who, int *errp)
739 {
740 	nvlist_t *dev_stats = NULL;
741 	char *by, *data;
742 	nvpair_t *nvwhat = NULL;
743 	nvpair_t *nvdesc = NULL;
744 	int	found = 0;
745 	char	*dname = NULL;
746 
747 
748 	*errp = 0;
749 	*msg = NULL;
750 
751 	/*
752 	 * If the user doesn't want to do in use checking, return.
753 	 */
754 
755 	if (NOINUSE_SET)
756 		return (0);
757 
758 	dname = getfullblkname(dev_name);
759 	/*
760 	 * If we cannot find the block name, we cannot check the device
761 	 * for in use statistics. So, return found, which is == 0.
762 	 */
763 	if (dname == NULL || *dname == '\0') {
764 		return (found);
765 	}
766 
767 	dm_get_slice_stats(dname, &dev_stats, errp);
768 	if (dev_stats == NULL) {
769 		/*
770 		 * If there is an error, but it isn't a no device found error
771 		 * return the error as recorded. Otherwise, with a full
772 		 * block name, we might not be able to get the slice
773 		 * associated, and will get an ENODEV error. For example,
774 		 * an SVM metadevice will return a value from getfullblkname()
775 		 * but libdiskmgt won't be able to find this device for
776 		 * statistics gathering. This is expected and we should not
777 		 * report errnoneous errors.
778 		 */
779 		if (*errp) {
780 			if (*errp == ENODEV) {
781 				*errp = 0;
782 			}
783 		}
784 		free(dname);
785 		return (found);
786 	}
787 
788 	for (;;) {
789 
790 		nvwhat = nvlist_next_nvpair(dev_stats, nvdesc);
791 		nvdesc = nvlist_next_nvpair(dev_stats, nvwhat);
792 
793 		/*
794 		 * End of the list found.
795 		 */
796 		if (nvwhat == NULL || nvdesc == NULL) {
797 			break;
798 		}
799 		/*
800 		 * Otherwise, we check to see if this client(who) cares
801 		 * about this in use scenario
802 		 */
803 
804 		ASSERT(strcmp(nvpair_name(nvwhat), DM_USED_BY) == 0);
805 		ASSERT(strcmp(nvpair_name(nvdesc), DM_USED_NAME) == 0);
806 		/*
807 		 * If we error getting the string value continue on
808 		 * to the next pair(if there is one)
809 		 */
810 		if (nvpair_value_string(nvwhat, &by)) {
811 			continue;
812 		}
813 		if (nvpair_value_string(nvdesc, &data)) {
814 			continue;
815 		}
816 
817 		switch (who) {
818 			case DM_WHO_MKFS:
819 				/*
820 				 * mkfs is not in use for these cases.
821 				 * All others are in use.
822 				 */
823 				if (strcmp(by, DM_USE_LU) == 0 ||
824 				    strcmp(by, DM_USE_FS) == 0 ||
825 				    strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0) {
826 					break;
827 				}
828 				if (build_usage_string(dname,
829 				    by, data, msg, &found, errp) != 0) {
830 					if (*errp) {
831 						goto out;
832 					}
833 				}
834 				break;
835 			case DM_WHO_SWAP:
836 				/*
837 				 * Not in use for this.
838 				 */
839 				if (strcmp(by, DM_USE_DUMP) == 0 ||
840 				    strcmp(by, DM_USE_FS) == 0 ||
841 				    strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0) {
842 					break;
843 				}
844 
845 				if (build_usage_string(dname,
846 				    by, data, msg, &found, errp) != 0) {
847 					if (*errp) {
848 						goto out;
849 					}
850 				}
851 				break;
852 			case DM_WHO_DUMP:
853 				/*
854 				 * Not in use for this.
855 				 */
856 				if ((strcmp(by, DM_USE_MOUNT) == 0 &&
857 				    strcmp(data, "swap") == 0) ||
858 				    strcmp(by, DM_USE_DUMP) == 0 ||
859 				    strcmp(by, DM_USE_FS) == 0 ||
860 				    strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0) {
861 					break;
862 				}
863 				if (build_usage_string(dname,
864 				    by, data, msg, &found, errp)) {
865 					if (*errp) {
866 						goto out;
867 					}
868 				}
869 				break;
870 
871 			case DM_WHO_FORMAT:
872 				if (strcmp(by, DM_USE_FS) == 0 ||
873 				    strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0)
874 					break;
875 				if (build_usage_string(dname,
876 				    by, data, msg, &found, errp) != 0) {
877 					if (*errp) {
878 						goto out;
879 					}
880 				}
881 				break;
882 
883 			case DM_WHO_ZPOOL_FORCE:
884 				if (strcmp(by, DM_USE_FS) == 0 ||
885 				    strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0)
886 					break;
887 				/* FALLTHROUGH */
888 			case DM_WHO_ZPOOL:
889 				if (build_usage_string(dname,
890 				    by, data, msg, &found, errp) != 0) {
891 					if (*errp)
892 						goto out;
893 				}
894 				break;
895 
896 			default:
897 				/*
898 				 * nothing found in use for this client
899 				 * of libdiskmgt. Default is 'not in use'.
900 				 */
901 				break;
902 		}
903 	}
904 out:
905 	if (dname != NULL)
906 		free(dname);
907 	if (dev_stats != NULL)
908 		nvlist_free(dev_stats);
909 
910 	return (found);
911 }
912 
913 void
914 dm_get_usage_string(char *what, char *how, char **usage_string)
915 {
916 
917 
918 	if (usage_string == NULL || what == NULL) {
919 		return;
920 	}
921 	*usage_string = NULL;
922 
923 	if (strcmp(what, DM_USE_MOUNT) == 0) {
924 		if (strcmp(how, "swap") == 0) {
925 			*usage_string = dgettext(TEXT_DOMAIN,
926 			    "%s is currently used by swap. Please see swap(1M)."
927 			    "\n");
928 		} else {
929 			*usage_string = dgettext(TEXT_DOMAIN,
930 			    "%s is currently mounted on %s."
931 			    " Please see umount(1M).\n");
932 		}
933 	} else if (strcmp(what, DM_USE_VFSTAB) == 0) {
934 		*usage_string = dgettext(TEXT_DOMAIN,
935 		    "%s is normally mounted on %s according to /etc/vfstab. "
936 		    "Please remove this entry to use this device.\n");
937 	} else if (strcmp(what, DM_USE_FS) == 0) {
938 		*usage_string = dgettext(TEXT_DOMAIN,
939 		    "%s contains a %s filesystem.\n");
940 	} else if (strcmp(what, DM_USE_SVM) == 0) {
941 		if (strcmp(how, "mdb") == 0) {
942 			*usage_string = dgettext(TEXT_DOMAIN,
943 			    "%s contains an SVM %s. Please see "
944 			    "metadb(1M).\n");
945 		} else {
946 			*usage_string = dgettext(TEXT_DOMAIN,
947 			    "%s is part of SVM volume %s. "
948 			    "Please see metaclear(1M).\n");
949 		}
950 	} else if (strcmp(what, DM_USE_VXVM) == 0) {
951 		*usage_string = dgettext(TEXT_DOMAIN,
952 		    "%s is part of VxVM volume %s.\n");
953 	} else if (strcmp(what, DM_USE_LU) == 0) {
954 		*usage_string = dgettext(TEXT_DOMAIN,
955 		    "%s is in use for live upgrade %s. Please see ludelete(1M)."
956 		    "\n");
957 	} else if (strcmp(what, DM_USE_DUMP) == 0) {
958 		*usage_string = dgettext(TEXT_DOMAIN,
959 		    "%s is in use by %s. Please see dumpadm(1M)."
960 		    "\n");
961 	} else if (strcmp(what, DM_USE_EXPORTED_ZPOOL) == 0) {
962 		*usage_string = dgettext(TEXT_DOMAIN,
963 		    "%s is part of exported or potentially active ZFS pool %s. "
964 		    "Please see zpool(1M).\n");
965 	} else if (strcmp(what, DM_USE_ACTIVE_ZPOOL) == 0) {
966 		*usage_string = dgettext(TEXT_DOMAIN,
967 		    "%s is part of active ZFS pool %s. Please see zpool(1M)."
968 		    "\n");
969 	}
970 }
971 void
972 libdiskmgt_add_str(nvlist_t *attrs, char *name, char *val, int *errp)
973 {
974 	if (*errp == 0) {
975 		*errp = nvlist_add_string(attrs, name, val);
976 	}
977 }
978 
979 descriptor_t **
980 libdiskmgt_empty_desc_array(int *errp)
981 {
982 	descriptor_t	**empty;
983 
984 	empty = (descriptor_t **)calloc(1, sizeof (descriptor_t *));
985 	if (empty == NULL) {
986 	    *errp = ENOMEM;
987 	    return (NULL);
988 	}
989 	empty[0] = NULL;
990 
991 	*errp = 0;
992 	return (empty);
993 }
994 
995 void
996 libdiskmgt_init_debug()
997 {
998 	char	*valp;
999 
1000 	if ((valp = getenv(DM_DEBUG)) != NULL) {
1001 	    dm_debug = atoi(valp);
1002 	}
1003 }
1004 
1005 int
1006 libdiskmgt_str_eq(char *nm1, char *nm2)
1007 {
1008 	if (nm1 == NULL) {
1009 	    if (dm_debug) {
1010 		(void) fprintf(stderr, "WARNING: str_eq nm1 NULL\n");
1011 	    }
1012 
1013 	    if (nm2 == NULL) {
1014 		return (1);
1015 	    } else {
1016 		return (0);
1017 	    }
1018 	}
1019 
1020 	/* nm1 != NULL */
1021 
1022 	if (nm2 == NULL) {
1023 	    if (dm_debug) {
1024 		(void) fprintf(stderr, "WARNING: str_eq nm2 NULL\n");
1025 	    }
1026 	    return (0);
1027 	}
1028 
1029 	if (strcmp(nm1, nm2) == 0) {
1030 	    return (1);
1031 	}
1032 
1033 	return (0);
1034 }
1035 
1036 /*ARGSUSED*/
1037 static descriptor_t **
1038 desc_array_to_ptr_array(dm_descriptor_t *descs, int *errp)
1039 {
1040 #ifdef _LP64
1041 	return ((descriptor_t **)descs);
1042 #else
1043 	/* convert the 64 bit descriptors to 32 bit ptrs */
1044 	int	cnt;
1045 	int	i;
1046 	descriptor_t **da;
1047 
1048 	for (cnt = 0; descs[cnt]; cnt++);
1049 
1050 	da = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
1051 	if (da == NULL) {
1052 	    *errp = ENOMEM;
1053 	    return (NULL);
1054 	}
1055 
1056 	for (i = 0; descs[i]; i++) {
1057 	    da[i] = (descriptor_t *)(uintptr_t)descs[i];
1058 	}
1059 	*errp = 0;
1060 	free(descs);
1061 
1062 	return (da);
1063 #endif
1064 }
1065 
1066 /*ARGSUSED*/
1067 static dm_descriptor_t *
1068 ptr_array_to_desc_array(descriptor_t **ptrs, int *errp)
1069 {
1070 #ifdef _LP64
1071 	return ((dm_descriptor_t *)ptrs);
1072 #else
1073 	/* convert the 32 bit ptrs to the 64 bit descriptors */
1074 	int	cnt;
1075 	int	i;
1076 	dm_descriptor_t *da;
1077 
1078 	if (*errp != 0 || ptrs == NULL) {
1079 	    return (NULL);
1080 	}
1081 
1082 	for (cnt = 0; ptrs[cnt]; cnt++);
1083 
1084 	da = (dm_descriptor_t *)calloc(cnt + 1, sizeof (dm_descriptor_t));
1085 	if (da == NULL) {
1086 	    *errp = ENOMEM;
1087 	    return (NULL);
1088 	}
1089 
1090 	for (i = 0; ptrs[i]; i++) {
1091 	    da[i] = (uintptr_t)ptrs[i];
1092 	}
1093 	*errp = 0;
1094 	free(ptrs);
1095 
1096 	return (da);
1097 #endif
1098 }
1099 /*
1100  * Build the usage string for the in use data. Return the build string in
1101  * the msg parameter. This function takes care of reallocing all the memory
1102  * for this usage string. Usage string is returned already formatted for
1103  * localization.
1104  */
1105 static int
1106 build_usage_string(char *dname, char *by, char *data, char **msg,
1107     int *found, int *errp)
1108 {
1109 	int	len0;
1110 	int	len1;
1111 	char	*use;
1112 	char	*p;
1113 
1114 	*errp = 0;
1115 
1116 	dm_get_usage_string(by, data, &use);
1117 	if (!use) {
1118 		return (-1);
1119 	}
1120 
1121 	if (*msg)
1122 		len0 = strlen(*msg);
1123 	else
1124 		len0 = 0;
1125 	/* LINTED */
1126 	len1 = snprintf(NULL, 0, use, dname, data);
1127 
1128 	/*
1129 	 * If multiple in use details they
1130 	 * are listed 1 per line for ease of
1131 	 * reading. dm_find_usage_string
1132 	 * formats these appropriately.
1133 	 */
1134 	if ((p = realloc(*msg, len0 + len1 + 1)) == NULL) {
1135 		*errp = errno;
1136 		free(*msg);
1137 		return (-1);
1138 	}
1139 	*msg = p;
1140 
1141 	/* LINTED */
1142 	(void) snprintf(*msg + len0, len1 + 1, use, dname, data);
1143 	(*found)++;
1144 	return (0);
1145 }
1146