xref: /illumos-gate/usr/src/lib/libdiskmgt/common/entry.c (revision bc1f688b4872ace323eaddbb1a6365d054e7bf56)
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.
908 		 */
909 		if (*errp == ENODEV)
910 			*errp = 0;
911 		free(dname);
912 		return (found);
913 	}
914 
915 	for (;;) {
916 
917 		nvwhat = nvlist_next_nvpair(dev_stats, nvdesc);
918 		nvdesc = nvlist_next_nvpair(dev_stats, nvwhat);
919 
920 		/*
921 		 * End of the list found.
922 		 */
923 		if (nvwhat == NULL || nvdesc == NULL) {
924 			break;
925 		}
926 		/*
927 		 * Otherwise, we check to see if this client(who) cares
928 		 * about this in use scenario
929 		 */
930 
931 		ASSERT(strcmp(nvpair_name(nvwhat), DM_USED_BY) == 0);
932 		ASSERT(strcmp(nvpair_name(nvdesc), DM_USED_NAME) == 0);
933 		/*
934 		 * If we error getting the string value continue on
935 		 * to the next pair(if there is one)
936 		 */
937 		if (nvpair_value_string(nvwhat, &by)) {
938 			continue;
939 		}
940 		if (nvpair_value_string(nvdesc, &data)) {
941 			continue;
942 		}
943 
944 		switch (who) {
945 			case DM_WHO_MKFS:
946 				/*
947 				 * mkfs is not in use for these cases.
948 				 * All others are in use.
949 				 */
950 				if (strcmp(by, DM_USE_LU) == 0 ||
951 				    strcmp(by, DM_USE_FS) == 0 ||
952 				    strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0) {
953 					break;
954 				}
955 				if (build_usage_string(dname,
956 				    by, data, msg, &found, errp) != 0) {
957 					if (*errp) {
958 						goto out;
959 					}
960 				}
961 				break;
962 			case DM_WHO_SWAP:
963 				/*
964 				 * Not in use for this.
965 				 */
966 				if (strcmp(by, DM_USE_DUMP) == 0 ||
967 				    strcmp(by, DM_USE_FS) == 0 ||
968 				    strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0) {
969 					break;
970 				}
971 				if (strcmp(by, DM_USE_LU) == 0 &&
972 				    strcmp(data, "-") == 0) {
973 					break;
974 				}
975 				if (strcmp(by, DM_USE_VFSTAB) == 0 &&
976 				    strcmp(data, "") == 0) {
977 					break;
978 				}
979 				if (build_usage_string(dname,
980 				    by, data, msg, &found, errp) != 0) {
981 					if (*errp) {
982 						goto out;
983 					}
984 				}
985 				break;
986 			case DM_WHO_DUMP:
987 				/*
988 				 * Not in use for this.
989 				 */
990 				if ((strcmp(by, DM_USE_MOUNT) == 0 &&
991 				    strcmp(data, "swap") == 0) ||
992 				    strcmp(by, DM_USE_DUMP) == 0 ||
993 				    strcmp(by, DM_USE_FS) == 0 ||
994 				    strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0) {
995 					break;
996 				}
997 				if (build_usage_string(dname,
998 				    by, data, msg, &found, errp)) {
999 					if (*errp) {
1000 						goto out;
1001 					}
1002 				}
1003 				break;
1004 
1005 			case DM_WHO_FORMAT:
1006 				if (strcmp(by, DM_USE_FS) == 0 ||
1007 				    strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0)
1008 					break;
1009 				if (build_usage_string(dname,
1010 				    by, data, msg, &found, errp) != 0) {
1011 					if (*errp) {
1012 						goto out;
1013 					}
1014 				}
1015 				break;
1016 
1017 			case DM_WHO_ZPOOL_FORCE:
1018 				if (strcmp(by, DM_USE_FS) == 0 ||
1019 				    strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0)
1020 					break;
1021 				/* FALLTHROUGH */
1022 			case DM_WHO_ZPOOL:
1023 				if (build_usage_string(dname,
1024 				    by, data, msg, &found, errp) != 0) {
1025 					if (*errp)
1026 						goto out;
1027 				}
1028 				break;
1029 
1030 			case DM_WHO_ZPOOL_SPARE:
1031 				if (strcmp(by, DM_USE_SPARE_ZPOOL) != 0) {
1032 					if (build_usage_string(dname, by,
1033 					    data, msg, &found, errp) != 0) {
1034 						if (*errp)
1035 							goto out;
1036 					}
1037 				}
1038 				break;
1039 
1040 			default:
1041 				/*
1042 				 * nothing found in use for this client
1043 				 * of libdiskmgt. Default is 'not in use'.
1044 				 */
1045 				break;
1046 		}
1047 	}
1048 out:
1049 	if (dname != NULL)
1050 		free(dname);
1051 	nvlist_free(dev_stats);
1052 
1053 	return (found);
1054 }
1055 
1056 void
1057 dm_get_usage_string(char *what, char *how, char **usage_string)
1058 {
1059 
1060 
1061 	if (usage_string == NULL || what == NULL) {
1062 		return;
1063 	}
1064 	*usage_string = NULL;
1065 
1066 	if (strcmp(what, DM_USE_MOUNT) == 0) {
1067 		if (strcmp(how, "swap") == 0) {
1068 			*usage_string = dgettext(TEXT_DOMAIN,
1069 			    "%s is currently used by swap. Please see swap(1M)."
1070 			    "\n");
1071 		} else {
1072 			*usage_string = dgettext(TEXT_DOMAIN,
1073 			    "%s is currently mounted on %s."
1074 			    " Please see umount(1M).\n");
1075 		}
1076 	} else if (strcmp(what, DM_USE_VFSTAB) == 0) {
1077 		*usage_string = dgettext(TEXT_DOMAIN,
1078 		    "%s is normally mounted on %s according to /etc/vfstab. "
1079 		    "Please remove this entry to use this device.\n");
1080 	} else if (strcmp(what, DM_USE_FS) == 0) {
1081 		*usage_string = dgettext(TEXT_DOMAIN,
1082 		    "%s contains a %s filesystem.\n");
1083 	} else if (strcmp(what, DM_USE_VXVM) == 0) {
1084 		*usage_string = dgettext(TEXT_DOMAIN,
1085 		    "%s is part of VxVM volume %s.\n");
1086 	} else if (strcmp(what, DM_USE_LU) == 0) {
1087 		*usage_string = dgettext(TEXT_DOMAIN,
1088 		    "%s is in use for live upgrade %s. Please see ludelete(1M)."
1089 		    "\n");
1090 	} else if (strcmp(what, DM_USE_DUMP) == 0) {
1091 		*usage_string = dgettext(TEXT_DOMAIN,
1092 		    "%s is in use by %s. Please see dumpadm(1M)."
1093 		    "\n");
1094 	} else if (strcmp(what, DM_USE_EXPORTED_ZPOOL) == 0) {
1095 		*usage_string = dgettext(TEXT_DOMAIN,
1096 		    "%s is part of exported or potentially active ZFS pool %s. "
1097 		    "Please see zpool(1M).\n");
1098 	} else if (strcmp(what, DM_USE_ACTIVE_ZPOOL) == 0) {
1099 		*usage_string = dgettext(TEXT_DOMAIN,
1100 		    "%s is part of active ZFS pool %s. Please see zpool(1M)."
1101 		    "\n");
1102 	} else if (strcmp(what, DM_USE_SPARE_ZPOOL) == 0) {
1103 		*usage_string = dgettext(TEXT_DOMAIN,
1104 		    "%s is reserved as a hot spare for ZFS pool %s.  Please "
1105 		    "see zpool(1M).\n");
1106 	} else if (strcmp(what, DM_USE_L2CACHE_ZPOOL) == 0) {
1107 		*usage_string = dgettext(TEXT_DOMAIN,
1108 		    "%s is in use as a cache device for ZFS pool %s.  "
1109 		    "Please see zpool(1M).\n");
1110 	}
1111 }
1112 void
1113 libdiskmgt_add_str(nvlist_t *attrs, char *name, char *val, int *errp)
1114 {
1115 	if (*errp == 0) {
1116 		*errp = nvlist_add_string(attrs, name, val);
1117 	}
1118 }
1119 
1120 descriptor_t **
1121 libdiskmgt_empty_desc_array(int *errp)
1122 {
1123 	descriptor_t	**empty;
1124 
1125 	empty = (descriptor_t **)calloc(1, sizeof (descriptor_t *));
1126 	if (empty == NULL) {
1127 		*errp = ENOMEM;
1128 		return (NULL);
1129 	}
1130 	empty[0] = NULL;
1131 
1132 	*errp = 0;
1133 	return (empty);
1134 }
1135 
1136 void
1137 libdiskmgt_init_debug()
1138 {
1139 	char	*valp;
1140 
1141 	if ((valp = getenv(DM_DEBUG)) != NULL) {
1142 		dm_debug = atoi(valp);
1143 	}
1144 }
1145 
1146 int
1147 libdiskmgt_str_eq(char *nm1, char *nm2)
1148 {
1149 	if (nm1 == NULL) {
1150 		if (dm_debug) {
1151 			(void) fprintf(stderr, "WARNING: str_eq nm1 NULL\n");
1152 		}
1153 
1154 		if (nm2 == NULL) {
1155 			return (1);
1156 		} else {
1157 			return (0);
1158 		}
1159 	}
1160 
1161 	/* nm1 != NULL */
1162 
1163 	if (nm2 == NULL) {
1164 		if (dm_debug) {
1165 			(void) fprintf(stderr, "WARNING: str_eq nm2 NULL\n");
1166 		}
1167 		return (0);
1168 	}
1169 
1170 	if (strcmp(nm1, nm2) == 0) {
1171 		return (1);
1172 	}
1173 
1174 	return (0);
1175 }
1176 
1177 /*ARGSUSED*/
1178 static descriptor_t **
1179 desc_array_to_ptr_array(dm_descriptor_t *descs, int *errp)
1180 {
1181 #ifdef _LP64
1182 	return ((descriptor_t **)descs);
1183 #else
1184 	/* convert the 64 bit descriptors to 32 bit ptrs */
1185 	int	cnt;
1186 	int	i;
1187 	descriptor_t **da;
1188 
1189 	for (cnt = 0; descs[cnt]; cnt++)
1190 		;
1191 
1192 	da = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
1193 	if (da == NULL) {
1194 		*errp = ENOMEM;
1195 		return (NULL);
1196 	}
1197 
1198 	for (i = 0; descs[i]; i++) {
1199 		da[i] = (descriptor_t *)(uintptr_t)descs[i];
1200 	}
1201 	*errp = 0;
1202 	free(descs);
1203 
1204 	return (da);
1205 #endif
1206 }
1207 
1208 /*ARGSUSED*/
1209 static dm_descriptor_t *
1210 ptr_array_to_desc_array(descriptor_t **ptrs, int *errp)
1211 {
1212 #ifdef _LP64
1213 	return ((dm_descriptor_t *)ptrs);
1214 #else
1215 	/* convert the 32 bit ptrs to the 64 bit descriptors */
1216 	int	cnt;
1217 	int	i;
1218 	dm_descriptor_t *da;
1219 
1220 	if (*errp != 0 || ptrs == NULL) {
1221 		return (NULL);
1222 	}
1223 
1224 	for (cnt = 0; ptrs[cnt]; cnt++)
1225 		;
1226 
1227 	da = (dm_descriptor_t *)calloc(cnt + 1, sizeof (dm_descriptor_t));
1228 	if (da == NULL) {
1229 		*errp = ENOMEM;
1230 		return (NULL);
1231 	}
1232 
1233 	for (i = 0; ptrs[i]; i++) {
1234 		da[i] = (uintptr_t)ptrs[i];
1235 	}
1236 	*errp = 0;
1237 	free(ptrs);
1238 
1239 	return (da);
1240 #endif
1241 }
1242 /*
1243  * Build the usage string for the in use data. Return the build string in
1244  * the msg parameter. This function takes care of reallocing all the memory
1245  * for this usage string. Usage string is returned already formatted for
1246  * localization.
1247  */
1248 static int
1249 build_usage_string(char *dname, char *by, char *data, char **msg,
1250     int *found, int *errp)
1251 {
1252 	int	len0;
1253 	int	len1;
1254 	char	*use;
1255 	char	*p;
1256 
1257 	*errp = 0;
1258 
1259 	dm_get_usage_string(by, data, &use);
1260 	if (!use) {
1261 		return (-1);
1262 	}
1263 
1264 	if (*msg)
1265 		len0 = strlen(*msg);
1266 	else
1267 		len0 = 0;
1268 	/* LINTED */
1269 	len1 = snprintf(NULL, 0, use, dname, data);
1270 
1271 	/*
1272 	 * If multiple in use details they
1273 	 * are listed 1 per line for ease of
1274 	 * reading. dm_find_usage_string
1275 	 * formats these appropriately.
1276 	 */
1277 	if ((p = realloc(*msg, len0 + len1 + 1)) == NULL) {
1278 		*errp = errno;
1279 		free(*msg);
1280 		return (-1);
1281 	}
1282 	*msg = p;
1283 
1284 	/* LINTED */
1285 	(void) snprintf(*msg + len0, len1 + 1, use, dname, data);
1286 	(*found)++;
1287 	return (0);
1288 }
1289