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