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