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