xref: /titanic_44/usr/src/lib/libdiskmgt/common/entry.c (revision 22ca5eba2a84a9612aa439c234327fda99608f01)
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 	if (media_attrs)
720 		nvlist_free(media_attrs);
721 	if (slice_attrs)
722 		nvlist_free(slice_attrs);
723 
724 	if (slices)
725 		dm_free_descriptors(slices);
726 	if (media)
727 		dm_free_descriptors(media);
728 	if (slice)
729 		dm_free_descriptor(slice);
730 
731 	return (ret);
732 }
733 
734 /*
735  * Get the full list of swap entries.  Returns -1 on error, or >= 0 to
736  * indicate the number of entries in the list.  Callers are responsible
737  * for calling dm_free_swapentries() to deallocate memory.  If this
738  * returns 0, the swaptbl_t still needs to be freed.
739  */
740 int
741 dm_get_swapentries(swaptbl_t **stp, int *errp)
742 {
743 	int count, i;
744 	swaptbl_t *tbl;
745 	char *ptr;
746 
747 	*stp = NULL;
748 
749 	/* get number of swap entries */
750 	if ((count = swapctl(SC_GETNSWP, NULL)) < 0) {
751 		*errp = errno;
752 		return (-1);
753 	}
754 
755 	if (count == 0) {
756 		return (0);
757 	}
758 
759 	/* allocate space */
760 	tbl = calloc(1, sizeof (int) + count * sizeof (swapent_t));
761 	if (tbl == NULL) {
762 		*errp = ENOMEM;
763 		return (-1);
764 	}
765 
766 	ptr = calloc(1, count * MAXPATHLEN);
767 	if (ptr == NULL) {
768 		*errp = ENOMEM;
769 		free(tbl);
770 		return (-1);
771 	}
772 
773 	/* set up pointers to the pathnames */
774 	tbl->swt_n = count;
775 	for (i = 0; i < count; i++) {
776 		tbl->swt_ent[i].ste_path = ptr;
777 		ptr += MAXPATHLEN;
778 	}
779 
780 	/* get list of swap paths */
781 	count = swapctl(SC_LIST, tbl);
782 	if (count < 0) {
783 		*errp = errno;
784 		free(ptr);
785 		free(tbl);
786 		return (-1);
787 	}
788 
789 	*stp = tbl;
790 	return (count);
791 }
792 
793 /* ARGSUSED */
794 void
795 dm_free_swapentries(swaptbl_t *stp)
796 {
797 	ASSERT(stp != NULL);
798 
799 	free(stp->swt_ent[0].ste_path);
800 	free(stp);
801 }
802 
803 /*
804  * Check a slice to see if it's being used by swap.
805  */
806 int
807 dm_inuse_swap(const char *dev_name, int *errp)
808 {
809 	int count;
810 	int found;
811 	swaptbl_t *tbl = NULL;
812 
813 	*errp = 0;
814 
815 	count = dm_get_swapentries(&tbl, errp);
816 	if (count < 0 || *errp) {
817 		if (tbl)
818 			dm_free_swapentries(tbl);
819 		return (-1);
820 	}
821 
822 	/* if there are no swap entries, we're done */
823 	if (!count) {
824 		return (0);
825 	}
826 
827 	ASSERT(tbl != NULL);
828 
829 	found = 0;
830 	while (count--) {
831 		if (strcmp(dev_name, tbl->swt_ent[count].ste_path) == 0) {
832 			found = 1;
833 			break;
834 		}
835 	}
836 
837 	dm_free_swapentries(tbl);
838 	return (found);
839 }
840 
841 /*
842  * Returns 'in use' details, if found, about a specific dev_name,
843  * based on the caller(who). It is important to note that it is possible
844  * for there to be more than one 'in use' statistic regarding a dev_name.
845  * The **msg parameter returns a list of 'in use' details. This message
846  * is formatted via gettext().
847  */
848 int
849 dm_inuse(char *dev_name, char **msg, dm_who_type_t who, int *errp)
850 {
851 	nvlist_t *dev_stats = NULL;
852 	char *by, *data;
853 	nvpair_t *nvwhat = NULL;
854 	nvpair_t *nvdesc = NULL;
855 	int	found = 0;
856 	int	err;
857 	char	*dname = NULL;
858 
859 	*errp = 0;
860 	*msg = NULL;
861 
862 	/*
863 	 * If the user doesn't want to do in use checking, return.
864 	 */
865 
866 	if (NOINUSE_SET)
867 		return (0);
868 
869 	dname = getfullblkname(dev_name);
870 	/*
871 	 * If we cannot find the block name, we cannot check the device
872 	 * for in use statistics. So, return found, which is == 0.
873 	 */
874 	if (dname == NULL || *dname == '\0') {
875 		return (found);
876 	}
877 
878 	/*
879 	 * Slice stats for swap devices are only returned if mounted
880 	 * (e.g. /tmp).  Other devices or files being used for swap
881 	 * are ignored, so we add a special check here to use swapctl(2)
882 	 * to perform in-use checking.
883 	 */
884 	if (ANY_ZPOOL_USE(who) && (err = dm_inuse_swap(dname, errp))) {
885 
886 		/* on error, dm_inuse_swap sets errp */
887 		if (err < 0) {
888 			free(dname);
889 			return (err);
890 		}
891 
892 		/* simulate a mounted swap device */
893 		(void) build_usage_string(dname, DM_USE_MOUNT, "swap", msg,
894 		    &found, errp);
895 
896 		/* if this fails, dm_get_usage_string changed */
897 		ASSERT(found == 1);
898 
899 		free(dname);
900 		return (found);
901 	}
902 
903 	dm_get_slice_stats(dname, &dev_stats, errp);
904 	if (dev_stats == NULL) {
905 		/*
906 		 * If there is an error, but it isn't a no device found error
907 		 * return the error as recorded. Otherwise, with a full
908 		 * block name, we might not be able to get the slice
909 		 * associated, and will get an ENODEV error.
910 		 */
911 		if (*errp == ENODEV)
912 			*errp = 0;
913 		free(dname);
914 		return (found);
915 	}
916 
917 	for (;;) {
918 
919 		nvwhat = nvlist_next_nvpair(dev_stats, nvdesc);
920 		nvdesc = nvlist_next_nvpair(dev_stats, nvwhat);
921 
922 		/*
923 		 * End of the list found.
924 		 */
925 		if (nvwhat == NULL || nvdesc == NULL) {
926 			break;
927 		}
928 		/*
929 		 * Otherwise, we check to see if this client(who) cares
930 		 * about this in use scenario
931 		 */
932 
933 		ASSERT(strcmp(nvpair_name(nvwhat), DM_USED_BY) == 0);
934 		ASSERT(strcmp(nvpair_name(nvdesc), DM_USED_NAME) == 0);
935 		/*
936 		 * If we error getting the string value continue on
937 		 * to the next pair(if there is one)
938 		 */
939 		if (nvpair_value_string(nvwhat, &by)) {
940 			continue;
941 		}
942 		if (nvpair_value_string(nvdesc, &data)) {
943 			continue;
944 		}
945 
946 		switch (who) {
947 			case DM_WHO_MKFS:
948 				/*
949 				 * mkfs is not in use for these cases.
950 				 * All others are in use.
951 				 */
952 				if (strcmp(by, DM_USE_LU) == 0 ||
953 				    strcmp(by, DM_USE_FS) == 0 ||
954 				    strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0) {
955 					break;
956 				}
957 				if (build_usage_string(dname,
958 				    by, data, msg, &found, errp) != 0) {
959 					if (*errp) {
960 						goto out;
961 					}
962 				}
963 				break;
964 			case DM_WHO_SWAP:
965 				/*
966 				 * Not in use for this.
967 				 */
968 				if (strcmp(by, DM_USE_DUMP) == 0 ||
969 				    strcmp(by, DM_USE_FS) == 0 ||
970 				    strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0) {
971 					break;
972 				}
973 				if (strcmp(by, DM_USE_LU) == 0 &&
974 				    strcmp(data, "-") == 0) {
975 					break;
976 				}
977 				if (strcmp(by, DM_USE_VFSTAB) == 0 &&
978 				    strcmp(data, "") == 0) {
979 					break;
980 				}
981 				if (build_usage_string(dname,
982 				    by, data, msg, &found, errp) != 0) {
983 					if (*errp) {
984 						goto out;
985 					}
986 				}
987 				break;
988 			case DM_WHO_DUMP:
989 				/*
990 				 * Not in use for this.
991 				 */
992 				if ((strcmp(by, DM_USE_MOUNT) == 0 &&
993 				    strcmp(data, "swap") == 0) ||
994 				    strcmp(by, DM_USE_DUMP) == 0 ||
995 				    strcmp(by, DM_USE_FS) == 0 ||
996 				    strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0) {
997 					break;
998 				}
999 				if (build_usage_string(dname,
1000 				    by, data, msg, &found, errp)) {
1001 					if (*errp) {
1002 						goto out;
1003 					}
1004 				}
1005 				break;
1006 
1007 			case DM_WHO_FORMAT:
1008 				if (strcmp(by, DM_USE_FS) == 0 ||
1009 				    strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0)
1010 					break;
1011 				if (build_usage_string(dname,
1012 				    by, data, msg, &found, errp) != 0) {
1013 					if (*errp) {
1014 						goto out;
1015 					}
1016 				}
1017 				break;
1018 
1019 			case DM_WHO_ZPOOL_FORCE:
1020 				if (strcmp(by, DM_USE_FS) == 0 ||
1021 				    strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0)
1022 					break;
1023 				/* FALLTHROUGH */
1024 			case DM_WHO_ZPOOL:
1025 				if (build_usage_string(dname,
1026 				    by, data, msg, &found, errp) != 0) {
1027 					if (*errp)
1028 						goto out;
1029 				}
1030 				break;
1031 
1032 			case DM_WHO_ZPOOL_SPARE:
1033 				if (strcmp(by, DM_USE_SPARE_ZPOOL) != 0) {
1034 					if (build_usage_string(dname, by,
1035 					    data, msg, &found, errp) != 0) {
1036 						if (*errp)
1037 							goto out;
1038 					}
1039 				}
1040 				break;
1041 
1042 			default:
1043 				/*
1044 				 * nothing found in use for this client
1045 				 * of libdiskmgt. Default is 'not in use'.
1046 				 */
1047 				break;
1048 		}
1049 	}
1050 out:
1051 	if (dname != NULL)
1052 		free(dname);
1053 	if (dev_stats != NULL)
1054 		nvlist_free(dev_stats);
1055 
1056 	return (found);
1057 }
1058 
1059 void
1060 dm_get_usage_string(char *what, char *how, char **usage_string)
1061 {
1062 
1063 
1064 	if (usage_string == NULL || what == NULL) {
1065 		return;
1066 	}
1067 	*usage_string = NULL;
1068 
1069 	if (strcmp(what, DM_USE_MOUNT) == 0) {
1070 		if (strcmp(how, "swap") == 0) {
1071 			*usage_string = dgettext(TEXT_DOMAIN,
1072 			    "%s is currently used by swap. Please see swap(1M)."
1073 			    "\n");
1074 		} else {
1075 			*usage_string = dgettext(TEXT_DOMAIN,
1076 			    "%s is currently mounted on %s."
1077 			    " Please see umount(1M).\n");
1078 		}
1079 	} else if (strcmp(what, DM_USE_VFSTAB) == 0) {
1080 		*usage_string = dgettext(TEXT_DOMAIN,
1081 		    "%s is normally mounted on %s according to /etc/vfstab. "
1082 		    "Please remove this entry to use this device.\n");
1083 	} else if (strcmp(what, DM_USE_FS) == 0) {
1084 		*usage_string = dgettext(TEXT_DOMAIN,
1085 		    "%s contains a %s filesystem.\n");
1086 	} else if (strcmp(what, DM_USE_VXVM) == 0) {
1087 		*usage_string = dgettext(TEXT_DOMAIN,
1088 		    "%s is part of VxVM volume %s.\n");
1089 	} else if (strcmp(what, DM_USE_LU) == 0) {
1090 		*usage_string = dgettext(TEXT_DOMAIN,
1091 		    "%s is in use for live upgrade %s. Please see ludelete(1M)."
1092 		    "\n");
1093 	} else if (strcmp(what, DM_USE_DUMP) == 0) {
1094 		*usage_string = dgettext(TEXT_DOMAIN,
1095 		    "%s is in use by %s. Please see dumpadm(1M)."
1096 		    "\n");
1097 	} else if (strcmp(what, DM_USE_EXPORTED_ZPOOL) == 0) {
1098 		*usage_string = dgettext(TEXT_DOMAIN,
1099 		    "%s is part of exported or potentially active ZFS pool %s. "
1100 		    "Please see zpool(1M).\n");
1101 	} else if (strcmp(what, DM_USE_ACTIVE_ZPOOL) == 0) {
1102 		*usage_string = dgettext(TEXT_DOMAIN,
1103 		    "%s is part of active ZFS pool %s. Please see zpool(1M)."
1104 		    "\n");
1105 	} else if (strcmp(what, DM_USE_SPARE_ZPOOL) == 0) {
1106 		*usage_string = dgettext(TEXT_DOMAIN,
1107 		    "%s is reserved as a hot spare for ZFS pool %s.  Please "
1108 		    "see zpool(1M).\n");
1109 	} else if (strcmp(what, DM_USE_L2CACHE_ZPOOL) == 0) {
1110 		*usage_string = dgettext(TEXT_DOMAIN,
1111 		    "%s is in use as a cache device for ZFS pool %s.  "
1112 		    "Please see zpool(1M).\n");
1113 	}
1114 }
1115 void
1116 libdiskmgt_add_str(nvlist_t *attrs, char *name, char *val, int *errp)
1117 {
1118 	if (*errp == 0) {
1119 		*errp = nvlist_add_string(attrs, name, val);
1120 	}
1121 }
1122 
1123 descriptor_t **
1124 libdiskmgt_empty_desc_array(int *errp)
1125 {
1126 	descriptor_t	**empty;
1127 
1128 	empty = (descriptor_t **)calloc(1, sizeof (descriptor_t *));
1129 	if (empty == NULL) {
1130 		*errp = ENOMEM;
1131 		return (NULL);
1132 	}
1133 	empty[0] = NULL;
1134 
1135 	*errp = 0;
1136 	return (empty);
1137 }
1138 
1139 void
1140 libdiskmgt_init_debug()
1141 {
1142 	char	*valp;
1143 
1144 	if ((valp = getenv(DM_DEBUG)) != NULL) {
1145 		dm_debug = atoi(valp);
1146 	}
1147 }
1148 
1149 int
1150 libdiskmgt_str_eq(char *nm1, char *nm2)
1151 {
1152 	if (nm1 == NULL) {
1153 		if (dm_debug) {
1154 			(void) fprintf(stderr, "WARNING: str_eq nm1 NULL\n");
1155 		}
1156 
1157 		if (nm2 == NULL) {
1158 			return (1);
1159 		} else {
1160 			return (0);
1161 		}
1162 	}
1163 
1164 	/* nm1 != NULL */
1165 
1166 	if (nm2 == NULL) {
1167 		if (dm_debug) {
1168 			(void) fprintf(stderr, "WARNING: str_eq nm2 NULL\n");
1169 		}
1170 		return (0);
1171 	}
1172 
1173 	if (strcmp(nm1, nm2) == 0) {
1174 		return (1);
1175 	}
1176 
1177 	return (0);
1178 }
1179 
1180 /*ARGSUSED*/
1181 static descriptor_t **
1182 desc_array_to_ptr_array(dm_descriptor_t *descs, int *errp)
1183 {
1184 #ifdef _LP64
1185 	return ((descriptor_t **)descs);
1186 #else
1187 	/* convert the 64 bit descriptors to 32 bit ptrs */
1188 	int	cnt;
1189 	int	i;
1190 	descriptor_t **da;
1191 
1192 	for (cnt = 0; descs[cnt]; cnt++)
1193 		;
1194 
1195 	da = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
1196 	if (da == NULL) {
1197 		*errp = ENOMEM;
1198 		return (NULL);
1199 	}
1200 
1201 	for (i = 0; descs[i]; i++) {
1202 		da[i] = (descriptor_t *)(uintptr_t)descs[i];
1203 	}
1204 	*errp = 0;
1205 	free(descs);
1206 
1207 	return (da);
1208 #endif
1209 }
1210 
1211 /*ARGSUSED*/
1212 static dm_descriptor_t *
1213 ptr_array_to_desc_array(descriptor_t **ptrs, int *errp)
1214 {
1215 #ifdef _LP64
1216 	return ((dm_descriptor_t *)ptrs);
1217 #else
1218 	/* convert the 32 bit ptrs to the 64 bit descriptors */
1219 	int	cnt;
1220 	int	i;
1221 	dm_descriptor_t *da;
1222 
1223 	if (*errp != 0 || ptrs == NULL) {
1224 		return (NULL);
1225 	}
1226 
1227 	for (cnt = 0; ptrs[cnt]; cnt++)
1228 		;
1229 
1230 	da = (dm_descriptor_t *)calloc(cnt + 1, sizeof (dm_descriptor_t));
1231 	if (da == NULL) {
1232 		*errp = ENOMEM;
1233 		return (NULL);
1234 	}
1235 
1236 	for (i = 0; ptrs[i]; i++) {
1237 		da[i] = (uintptr_t)ptrs[i];
1238 	}
1239 	*errp = 0;
1240 	free(ptrs);
1241 
1242 	return (da);
1243 #endif
1244 }
1245 /*
1246  * Build the usage string for the in use data. Return the build string in
1247  * the msg parameter. This function takes care of reallocing all the memory
1248  * for this usage string. Usage string is returned already formatted for
1249  * localization.
1250  */
1251 static int
1252 build_usage_string(char *dname, char *by, char *data, char **msg,
1253     int *found, int *errp)
1254 {
1255 	int	len0;
1256 	int	len1;
1257 	char	*use;
1258 	char	*p;
1259 
1260 	*errp = 0;
1261 
1262 	dm_get_usage_string(by, data, &use);
1263 	if (!use) {
1264 		return (-1);
1265 	}
1266 
1267 	if (*msg)
1268 		len0 = strlen(*msg);
1269 	else
1270 		len0 = 0;
1271 	/* LINTED */
1272 	len1 = snprintf(NULL, 0, use, dname, data);
1273 
1274 	/*
1275 	 * If multiple in use details they
1276 	 * are listed 1 per line for ease of
1277 	 * reading. dm_find_usage_string
1278 	 * formats these appropriately.
1279 	 */
1280 	if ((p = realloc(*msg, len0 + len1 + 1)) == NULL) {
1281 		*errp = errno;
1282 		free(*msg);
1283 		return (-1);
1284 	}
1285 	*msg = p;
1286 
1287 	/* LINTED */
1288 	(void) snprintf(*msg + len0, len1 + 1, use, dname, data);
1289 	(*found)++;
1290 	return (0);
1291 }
1292