xref: /illumos-gate/usr/src/lib/libdiskmgt/common/entry.c (revision 46657f8d750bdb71753495ce2919170f126b8e34)
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 2007 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 	*errp = 0;
747 	*msg = NULL;
748 
749 	/*
750 	 * If the user doesn't want to do in use checking, return.
751 	 */
752 
753 	if (NOINUSE_SET)
754 		return (0);
755 
756 	dname = getfullblkname(dev_name);
757 	/*
758 	 * If we cannot find the block name, we cannot check the device
759 	 * for in use statistics. So, return found, which is == 0.
760 	 */
761 	if (dname == NULL || *dname == '\0') {
762 		return (found);
763 	}
764 
765 	dm_get_slice_stats(dname, &dev_stats, errp);
766 	if (dev_stats == NULL) {
767 		/*
768 		 * If there is an error, but it isn't a no device found error
769 		 * return the error as recorded. Otherwise, with a full
770 		 * block name, we might not be able to get the slice
771 		 * associated, and will get an ENODEV error. For example,
772 		 * an SVM metadevice will return a value from getfullblkname()
773 		 * but libdiskmgt won't be able to find this device for
774 		 * statistics gathering. This is expected and we should not
775 		 * report errnoneous errors.
776 		 */
777 		if (*errp) {
778 			if (*errp == ENODEV) {
779 				*errp = 0;
780 			}
781 		}
782 		free(dname);
783 		return (found);
784 	}
785 
786 	for (;;) {
787 
788 		nvwhat = nvlist_next_nvpair(dev_stats, nvdesc);
789 		nvdesc = nvlist_next_nvpair(dev_stats, nvwhat);
790 
791 		/*
792 		 * End of the list found.
793 		 */
794 		if (nvwhat == NULL || nvdesc == NULL) {
795 			break;
796 		}
797 		/*
798 		 * Otherwise, we check to see if this client(who) cares
799 		 * about this in use scenario
800 		 */
801 
802 		ASSERT(strcmp(nvpair_name(nvwhat), DM_USED_BY) == 0);
803 		ASSERT(strcmp(nvpair_name(nvdesc), DM_USED_NAME) == 0);
804 		/*
805 		 * If we error getting the string value continue on
806 		 * to the next pair(if there is one)
807 		 */
808 		if (nvpair_value_string(nvwhat, &by)) {
809 			continue;
810 		}
811 		if (nvpair_value_string(nvdesc, &data)) {
812 			continue;
813 		}
814 
815 		switch (who) {
816 			case DM_WHO_MKFS:
817 				/*
818 				 * mkfs is not in use for these cases.
819 				 * All others are in use.
820 				 */
821 				if (strcmp(by, DM_USE_LU) == 0 ||
822 				    strcmp(by, DM_USE_FS) == 0 ||
823 				    strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0) {
824 					break;
825 				}
826 				if (build_usage_string(dname,
827 				    by, data, msg, &found, errp) != 0) {
828 					if (*errp) {
829 						goto out;
830 					}
831 				}
832 				break;
833 			case DM_WHO_SWAP:
834 				/*
835 				 * Not in use for this.
836 				 */
837 				if (strcmp(by, DM_USE_DUMP) == 0 ||
838 				    strcmp(by, DM_USE_FS) == 0 ||
839 				    strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0) {
840 					break;
841 				}
842 
843 				if (build_usage_string(dname,
844 				    by, data, msg, &found, errp) != 0) {
845 					if (*errp) {
846 						goto out;
847 					}
848 				}
849 				break;
850 			case DM_WHO_DUMP:
851 				/*
852 				 * Not in use for this.
853 				 */
854 				if ((strcmp(by, DM_USE_MOUNT) == 0 &&
855 				    strcmp(data, "swap") == 0) ||
856 				    strcmp(by, DM_USE_DUMP) == 0 ||
857 				    strcmp(by, DM_USE_FS) == 0 ||
858 				    strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0) {
859 					break;
860 				}
861 				if (build_usage_string(dname,
862 				    by, data, msg, &found, errp)) {
863 					if (*errp) {
864 						goto out;
865 					}
866 				}
867 				break;
868 
869 			case DM_WHO_FORMAT:
870 				if (strcmp(by, DM_USE_FS) == 0 ||
871 				    strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0)
872 					break;
873 				if (build_usage_string(dname,
874 				    by, data, msg, &found, errp) != 0) {
875 					if (*errp) {
876 						goto out;
877 					}
878 				}
879 				break;
880 
881 			case DM_WHO_ZPOOL_FORCE:
882 				if (strcmp(by, DM_USE_FS) == 0 ||
883 				    strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0)
884 					break;
885 				/* FALLTHROUGH */
886 			case DM_WHO_ZPOOL:
887 				if (build_usage_string(dname,
888 				    by, data, msg, &found, errp) != 0) {
889 					if (*errp)
890 						goto out;
891 				}
892 				break;
893 
894 			case DM_WHO_ZPOOL_SPARE:
895 				if (strcmp(by, DM_USE_SPARE_ZPOOL) != 0) {
896 					if (build_usage_string(dname, by,
897 					    data, msg, &found, errp) != 0) {
898 						if (*errp)
899 							goto out;
900 					}
901 				}
902 				break;
903 
904 			default:
905 				/*
906 				 * nothing found in use for this client
907 				 * of libdiskmgt. Default is 'not in use'.
908 				 */
909 				break;
910 		}
911 	}
912 out:
913 	if (dname != NULL)
914 		free(dname);
915 	if (dev_stats != NULL)
916 		nvlist_free(dev_stats);
917 
918 	return (found);
919 }
920 
921 void
922 dm_get_usage_string(char *what, char *how, char **usage_string)
923 {
924 
925 
926 	if (usage_string == NULL || what == NULL) {
927 		return;
928 	}
929 	*usage_string = NULL;
930 
931 	if (strcmp(what, DM_USE_MOUNT) == 0) {
932 		if (strcmp(how, "swap") == 0) {
933 			*usage_string = dgettext(TEXT_DOMAIN,
934 			    "%s is currently used by swap. Please see swap(1M)."
935 			    "\n");
936 		} else {
937 			*usage_string = dgettext(TEXT_DOMAIN,
938 			    "%s is currently mounted on %s."
939 			    " Please see umount(1M).\n");
940 		}
941 	} else if (strcmp(what, DM_USE_VFSTAB) == 0) {
942 		*usage_string = dgettext(TEXT_DOMAIN,
943 		    "%s is normally mounted on %s according to /etc/vfstab. "
944 		    "Please remove this entry to use this device.\n");
945 	} else if (strcmp(what, DM_USE_FS) == 0) {
946 		*usage_string = dgettext(TEXT_DOMAIN,
947 		    "%s contains a %s filesystem.\n");
948 	} else if (strcmp(what, DM_USE_SVM) == 0) {
949 		if (strcmp(how, "mdb") == 0) {
950 			*usage_string = dgettext(TEXT_DOMAIN,
951 			    "%s contains an SVM %s. Please see "
952 			    "metadb(1M).\n");
953 		} else {
954 			*usage_string = dgettext(TEXT_DOMAIN,
955 			    "%s is part of SVM volume %s. "
956 			    "Please see metaclear(1M).\n");
957 		}
958 	} else if (strcmp(what, DM_USE_VXVM) == 0) {
959 		*usage_string = dgettext(TEXT_DOMAIN,
960 		    "%s is part of VxVM volume %s.\n");
961 	} else if (strcmp(what, DM_USE_LU) == 0) {
962 		*usage_string = dgettext(TEXT_DOMAIN,
963 		    "%s is in use for live upgrade %s. Please see ludelete(1M)."
964 		    "\n");
965 	} else if (strcmp(what, DM_USE_DUMP) == 0) {
966 		*usage_string = dgettext(TEXT_DOMAIN,
967 		    "%s is in use by %s. Please see dumpadm(1M)."
968 		    "\n");
969 	} else if (strcmp(what, DM_USE_EXPORTED_ZPOOL) == 0) {
970 		*usage_string = dgettext(TEXT_DOMAIN,
971 		    "%s is part of exported or potentially active ZFS pool %s. "
972 		    "Please see zpool(1M).\n");
973 	} else if (strcmp(what, DM_USE_ACTIVE_ZPOOL) == 0) {
974 		*usage_string = dgettext(TEXT_DOMAIN,
975 		    "%s is part of active ZFS pool %s. Please see zpool(1M)."
976 		    "\n");
977 	} else if (strcmp(what, DM_USE_SPARE_ZPOOL) == 0) {
978 		*usage_string = dgettext(TEXT_DOMAIN,
979 		    "%s is reserved as a hot spare for ZFS pool %s.  Please "
980 		    "see zpool(1M).\n");
981 	}
982 }
983 void
984 libdiskmgt_add_str(nvlist_t *attrs, char *name, char *val, int *errp)
985 {
986 	if (*errp == 0) {
987 		*errp = nvlist_add_string(attrs, name, val);
988 	}
989 }
990 
991 descriptor_t **
992 libdiskmgt_empty_desc_array(int *errp)
993 {
994 	descriptor_t	**empty;
995 
996 	empty = (descriptor_t **)calloc(1, sizeof (descriptor_t *));
997 	if (empty == NULL) {
998 	    *errp = ENOMEM;
999 	    return (NULL);
1000 	}
1001 	empty[0] = NULL;
1002 
1003 	*errp = 0;
1004 	return (empty);
1005 }
1006 
1007 void
1008 libdiskmgt_init_debug()
1009 {
1010 	char	*valp;
1011 
1012 	if ((valp = getenv(DM_DEBUG)) != NULL) {
1013 	    dm_debug = atoi(valp);
1014 	}
1015 }
1016 
1017 int
1018 libdiskmgt_str_eq(char *nm1, char *nm2)
1019 {
1020 	if (nm1 == NULL) {
1021 	    if (dm_debug) {
1022 		(void) fprintf(stderr, "WARNING: str_eq nm1 NULL\n");
1023 	    }
1024 
1025 	    if (nm2 == NULL) {
1026 		return (1);
1027 	    } else {
1028 		return (0);
1029 	    }
1030 	}
1031 
1032 	/* nm1 != NULL */
1033 
1034 	if (nm2 == NULL) {
1035 	    if (dm_debug) {
1036 		(void) fprintf(stderr, "WARNING: str_eq nm2 NULL\n");
1037 	    }
1038 	    return (0);
1039 	}
1040 
1041 	if (strcmp(nm1, nm2) == 0) {
1042 	    return (1);
1043 	}
1044 
1045 	return (0);
1046 }
1047 
1048 /*ARGSUSED*/
1049 static descriptor_t **
1050 desc_array_to_ptr_array(dm_descriptor_t *descs, int *errp)
1051 {
1052 #ifdef _LP64
1053 	return ((descriptor_t **)descs);
1054 #else
1055 	/* convert the 64 bit descriptors to 32 bit ptrs */
1056 	int	cnt;
1057 	int	i;
1058 	descriptor_t **da;
1059 
1060 	for (cnt = 0; descs[cnt]; cnt++);
1061 
1062 	da = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
1063 	if (da == NULL) {
1064 	    *errp = ENOMEM;
1065 	    return (NULL);
1066 	}
1067 
1068 	for (i = 0; descs[i]; i++) {
1069 	    da[i] = (descriptor_t *)(uintptr_t)descs[i];
1070 	}
1071 	*errp = 0;
1072 	free(descs);
1073 
1074 	return (da);
1075 #endif
1076 }
1077 
1078 /*ARGSUSED*/
1079 static dm_descriptor_t *
1080 ptr_array_to_desc_array(descriptor_t **ptrs, int *errp)
1081 {
1082 #ifdef _LP64
1083 	return ((dm_descriptor_t *)ptrs);
1084 #else
1085 	/* convert the 32 bit ptrs to the 64 bit descriptors */
1086 	int	cnt;
1087 	int	i;
1088 	dm_descriptor_t *da;
1089 
1090 	if (*errp != 0 || ptrs == NULL) {
1091 	    return (NULL);
1092 	}
1093 
1094 	for (cnt = 0; ptrs[cnt]; cnt++);
1095 
1096 	da = (dm_descriptor_t *)calloc(cnt + 1, sizeof (dm_descriptor_t));
1097 	if (da == NULL) {
1098 	    *errp = ENOMEM;
1099 	    return (NULL);
1100 	}
1101 
1102 	for (i = 0; ptrs[i]; i++) {
1103 	    da[i] = (uintptr_t)ptrs[i];
1104 	}
1105 	*errp = 0;
1106 	free(ptrs);
1107 
1108 	return (da);
1109 #endif
1110 }
1111 /*
1112  * Build the usage string for the in use data. Return the build string in
1113  * the msg parameter. This function takes care of reallocing all the memory
1114  * for this usage string. Usage string is returned already formatted for
1115  * localization.
1116  */
1117 static int
1118 build_usage_string(char *dname, char *by, char *data, char **msg,
1119     int *found, int *errp)
1120 {
1121 	int	len0;
1122 	int	len1;
1123 	char	*use;
1124 	char	*p;
1125 
1126 	*errp = 0;
1127 
1128 	dm_get_usage_string(by, data, &use);
1129 	if (!use) {
1130 		return (-1);
1131 	}
1132 
1133 	if (*msg)
1134 		len0 = strlen(*msg);
1135 	else
1136 		len0 = 0;
1137 	/* LINTED */
1138 	len1 = snprintf(NULL, 0, use, dname, data);
1139 
1140 	/*
1141 	 * If multiple in use details they
1142 	 * are listed 1 per line for ease of
1143 	 * reading. dm_find_usage_string
1144 	 * formats these appropriately.
1145 	 */
1146 	if ((p = realloc(*msg, len0 + len1 + 1)) == NULL) {
1147 		*errp = errno;
1148 		free(*msg);
1149 		return (-1);
1150 	}
1151 	*msg = p;
1152 
1153 	/* LINTED */
1154 	(void) snprintf(*msg + len0, len1 + 1, use, dname, data);
1155 	(*found)++;
1156 	return (0);
1157 }
1158