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