dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libdiskmgt / common / entry.c
blob490f331fa0e60e021ce880a2879ed05de3e7ecec
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
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>
41 #include "libdiskmgt.h"
42 #include "disks_private.h"
43 #include "partition.h"
45 #define ANY_ZPOOL_USE(who) \
46 (((who) == DM_WHO_ZPOOL_FORCE) || \
47 ((who) == DM_WHO_ZPOOL) || \
48 ((who) == DM_WHO_ZPOOL_SPARE))
50 extern char *getfullblkname();
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[];
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);
67 void
68 dm_free_descriptor(dm_descriptor_t desc)
70 descriptor_t *dp;
72 if (desc == (uintptr_t)NULL) {
73 return;
75 dp = (descriptor_t *)(uintptr_t)desc;
77 cache_wlock();
78 cache_free_descriptor(dp);
79 cache_unlock();
82 void
83 dm_free_descriptors(dm_descriptor_t *desc_list)
85 descriptor_t **dp;
86 int error;
88 if (desc_list == NULL) {
89 return;
91 dp = desc_array_to_ptr_array(desc_list, &error);
92 if (error != 0) {
93 free(desc_list);
94 return;
97 cache_wlock();
98 cache_free_descriptors(dp);
99 cache_unlock();
102 /*ARGSUSED*/
103 void
104 dm_free_name(char *name)
106 free(name);
109 dm_descriptor_t *
110 dm_get_associated_descriptors(dm_descriptor_t desc, dm_desc_type_t type,
111 int *errp)
113 descriptor_t **descs = NULL;
114 descriptor_t *dp;
117 dp = (descriptor_t *)(uintptr_t)desc;
119 cache_wlock();
121 if (!cache_is_valid_desc(dp)) {
122 cache_unlock();
123 *errp = EBADF;
124 return (NULL);
127 /* verify that the descriptor is still valid */
128 if (dp->p.generic == NULL) {
129 cache_unlock();
130 *errp = ENODEV;
131 return (NULL);
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;
164 cache_unlock();
166 return (ptr_array_to_desc_array(descs, errp));
169 dm_desc_type_t *
170 dm_get_associated_types(dm_desc_type_t type)
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);
191 return (NULL);
194 nvlist_t *
195 dm_get_attributes(dm_descriptor_t desc, int *errp)
197 descriptor_t *dp;
198 nvlist_t *attrs = NULL;
201 dp = (descriptor_t *)(uintptr_t)desc;
203 cache_rlock();
205 if (!cache_is_valid_desc(dp)) {
206 cache_unlock();
207 *errp = EBADF;
208 return (NULL);
211 /* verify that the descriptor is still valid */
212 if (dp->p.generic == NULL) {
213 cache_unlock();
214 *errp = ENODEV;
215 return (NULL);
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;
248 cache_unlock();
250 return (attrs);
253 dm_descriptor_t
254 dm_get_descriptor_by_name(dm_desc_type_t desc_type, char *name, int *errp)
256 dm_descriptor_t desc = (uintptr_t)NULL;
259 cache_wlock();
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;
293 cache_unlock();
295 return (desc);
298 dm_descriptor_t *
299 dm_get_descriptors(dm_desc_type_t type, int filter[], int *errp)
301 descriptor_t **descs = NULL;
304 cache_wlock();
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;
336 cache_unlock();
338 return (ptr_array_to_desc_array(descs, errp));
341 char *
342 dm_get_name(dm_descriptor_t desc, int *errp)
344 descriptor_t *dp;
345 char *nm = NULL;
346 char *name = NULL;
348 dp = (descriptor_t *)(uintptr_t)desc;
350 cache_rlock();
352 if (!cache_is_valid_desc(dp)) {
353 cache_unlock();
354 *errp = EBADF;
355 return (NULL);
358 /* verify that the descriptor is still valid */
359 if (dp->p.generic == NULL) {
360 cache_unlock();
361 *errp = ENODEV;
362 return (NULL);
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;
392 cache_unlock();
394 *errp = 0;
395 if (nm != NULL) {
396 name = strdup(nm);
397 if (name == NULL) {
398 *errp = ENOMEM;
399 return (NULL);
401 return (name);
403 return (NULL);
406 nvlist_t *
407 dm_get_stats(dm_descriptor_t desc, int stat_type, int *errp)
409 descriptor_t *dp;
410 nvlist_t *stats = NULL;
413 dp = (descriptor_t *)(uintptr_t)desc;
415 cache_rlock();
417 if (!cache_is_valid_desc(dp)) {
418 cache_unlock();
419 *errp = EBADF;
420 return (NULL);
423 /* verify that the descriptor is still valid */
424 if (dp->p.generic == NULL) {
425 cache_unlock();
426 *errp = ENODEV;
427 return (NULL);
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) {
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
450 if (NOINUSE_SET) {
451 stats = NULL;
452 break;
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;
471 cache_unlock();
473 return (stats);
476 dm_desc_type_t
477 dm_get_type(dm_descriptor_t desc)
479 descriptor_t *dp;
481 dp = (descriptor_t *)(uintptr_t)desc;
483 cache_rlock();
485 if (!cache_is_valid_desc(dp)) {
486 cache_unlock();
487 return (-1);
490 cache_unlock();
492 return (dp->type);
495 * Returns, via slices paramater, a dm_descriptor_t list of
496 * slices for the named disk drive.
498 void
499 dm_get_slices(char *drive, dm_descriptor_t **slices, int *errp)
501 dm_descriptor_t alias;
502 dm_descriptor_t *media;
503 dm_descriptor_t *disk;
505 *slices = NULL;
506 *errp = 0;
508 if (drive == NULL) {
509 return;
512 alias = dm_get_descriptor_by_name(DM_ALIAS, drive, errp);
515 * Errors must be handled by the caller. The dm_descriptor_t *
516 * values will be NULL if an error occured in these calls.
519 if (alias != (uintptr_t)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);
535 * Convenience function to get slice stats
537 void
538 dm_get_slice_stats(char *slice, nvlist_t **dev_stats, int *errp)
540 dm_descriptor_t devp;
542 *dev_stats = NULL;
543 *errp = 0;
545 if (slice == NULL) {
546 return;
550 * Errors must be handled by the caller. The dm_descriptor_t *
551 * values will be NULL if an error occured in these calls.
553 devp = dm_get_descriptor_by_name(DM_SLICE, slice, errp);
554 if (devp != (uintptr_t)NULL) {
555 *dev_stats = dm_get_stats(devp, DM_SLICE_STAT_USE,
556 errp);
557 dm_free_descriptor(devp);
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().
567 dm_isoverlapping(char *slicename, char **overlaps_with, int *errp)
569 dm_descriptor_t slice = (uintptr_t)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;
582 slice = dm_get_descriptor_by_name(DM_SLICE, slicename, errp);
583 if (slice == (uintptr_t)NULL)
584 goto out;
587 * Get the list of slices be fetching the associated media, and then all
588 * associated slices.
590 media = dm_get_associated_descriptors(slice, DM_MEDIA, errp);
591 if (media == NULL || *media == (uintptr_t)NULL || *errp != 0)
592 goto out;
594 slices = dm_get_associated_descriptors(*media, DM_SLICE, errp);
595 if (slices == NULL || *slices == (uintptr_t)NULL || *errp != 0)
596 goto out;
598 media_attrs = dm_get_attributes(*media, errp);
599 if (media_attrs == NULL || *errp)
600 goto out;
602 *errp = nvlist_lookup_uint64(media_attrs, DM_NACCESSIBLE, &media_size);
603 if (*errp != 0)
604 goto out;
606 slice_attrs = dm_get_attributes(slice, errp);
607 if (slice_attrs == NULL || *errp != 0)
608 goto out;
610 *errp = nvlist_lookup_uint64(slice_attrs, DM_START, &start_block);
611 if (*errp != 0)
612 goto out;
614 *errp = nvlist_lookup_uint64(slice_attrs, DM_SIZE, &size);
615 if (*errp != 0)
616 goto out;
618 *errp = nvlist_lookup_uint32(slice_attrs, DM_INDEX, &in_snum);
619 if (*errp != 0)
620 goto out;
622 end_block = (start_block + size) - 1;
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;
630 nvlist_t *other_attrs = dm_get_attributes(slices[i], errp);
632 if (other_attrs == NULL)
633 continue;
635 if (*errp != 0)
636 goto out;
638 *errp = nvlist_lookup_uint64(other_attrs, DM_START,
639 &other_start);
640 if (*errp) {
641 nvlist_free(other_attrs);
642 goto out;
645 *errp = nvlist_lookup_uint64(other_attrs, DM_SIZE,
646 &other_size);
648 if (*errp) {
649 nvlist_free(other_attrs);
650 ret = -1;
651 goto out;
654 other_end = (other_size + other_start) - 1;
656 *errp = nvlist_lookup_uint32(other_attrs, DM_INDEX,
657 &snum);
659 if (*errp) {
660 nvlist_free(other_attrs);
661 ret = -1;
662 goto out;
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.
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;
690 *overlaps_with = strdup(str);
691 dm_free_name(str);
692 nvlist_free(other_attrs);
693 ret = 1;
694 goto out;
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;
708 *overlaps_with = strdup(str);
709 dm_free_name(str);
710 nvlist_free(other_attrs);
711 ret = 1;
712 goto out;
715 nvlist_free(other_attrs);
718 out:
719 nvlist_free(media_attrs);
720 nvlist_free(slice_attrs);
722 if (slices)
723 dm_free_descriptors(slices);
724 if (media)
725 dm_free_descriptors(media);
726 if (slice)
727 dm_free_descriptor(slice);
729 return (ret);
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.
739 dm_get_swapentries(swaptbl_t **stp, int *errp)
741 int count, i;
742 swaptbl_t *tbl;
743 char *ptr;
745 *stp = NULL;
747 /* get number of swap entries */
748 if ((count = swapctl(SC_GETNSWP, NULL)) < 0) {
749 *errp = errno;
750 return (-1);
753 if (count == 0) {
754 return (0);
757 /* allocate space */
758 tbl = calloc(1, sizeof (int) + count * sizeof (swapent_t));
759 if (tbl == NULL) {
760 *errp = ENOMEM;
761 return (-1);
764 ptr = calloc(1, count * MAXPATHLEN);
765 if (ptr == NULL) {
766 *errp = ENOMEM;
767 free(tbl);
768 return (-1);
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;
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);
787 *stp = tbl;
788 return (count);
791 /* ARGSUSED */
792 void
793 dm_free_swapentries(swaptbl_t *stp)
795 ASSERT(stp != NULL);
797 free(stp->swt_ent[0].ste_path);
798 free(stp);
802 * Check a slice to see if it's being used by swap.
805 dm_inuse_swap(const char *dev_name, int *errp)
807 int count;
808 int found;
809 swaptbl_t *tbl = NULL;
811 *errp = 0;
813 count = dm_get_swapentries(&tbl, errp);
814 if (count < 0 || *errp) {
815 if (tbl)
816 dm_free_swapentries(tbl);
817 return (-1);
820 /* if there are no swap entries, we're done */
821 if (!count) {
822 return (0);
825 ASSERT(tbl != NULL);
827 found = 0;
828 while (count--) {
829 if (strcmp(dev_name, tbl->swt_ent[count].ste_path) == 0) {
830 found = 1;
831 break;
835 dm_free_swapentries(tbl);
836 return (found);
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().
847 dm_inuse(char *dev_name, char **msg, dm_who_type_t who, int *errp)
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;
857 *errp = 0;
858 *msg = NULL;
861 * If the user doesn't want to do in use checking, return.
864 if (NOINUSE_SET)
865 return (0);
867 dname = getfullblkname(dev_name);
869 * If we cannot find the block name, we cannot check the device
870 * for in use statistics. So, return found, which is == 0.
872 if (dname == NULL || *dname == '\0') {
873 return (found);
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.
882 if (ANY_ZPOOL_USE(who) && (err = dm_inuse_swap(dname, errp))) {
884 /* on error, dm_inuse_swap sets errp */
885 if (err < 0) {
886 free(dname);
887 return (err);
890 /* simulate a mounted swap device */
891 (void) build_usage_string(dname, DM_USE_MOUNT, "swap", msg,
892 &found, errp);
894 /* if this fails, dm_get_usage_string changed */
895 ASSERT(found == 1);
897 free(dname);
898 return (found);
901 dm_get_slice_stats(dname, &dev_stats, errp);
902 if (dev_stats == NULL) {
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.
909 if (*errp == ENODEV)
910 *errp = 0;
911 free(dname);
912 return (found);
915 for (;;) {
917 nvwhat = nvlist_next_nvpair(dev_stats, nvdesc);
918 nvdesc = nvlist_next_nvpair(dev_stats, nvwhat);
921 * End of the list found.
923 if (nvwhat == NULL || nvdesc == NULL) {
924 break;
927 * Otherwise, we check to see if this client(who) cares
928 * about this in use scenario
931 ASSERT(strcmp(nvpair_name(nvwhat), DM_USED_BY) == 0);
932 ASSERT(strcmp(nvpair_name(nvdesc), DM_USED_NAME) == 0);
934 * If we error getting the string value continue on
935 * to the next pair(if there is one)
937 if (nvpair_value_string(nvwhat, &by)) {
938 continue;
940 if (nvpair_value_string(nvdesc, &data)) {
941 continue;
944 switch (who) {
945 case DM_WHO_MKFS:
947 * mkfs is not in use for these cases.
948 * All others are in use.
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;
955 if (build_usage_string(dname,
956 by, data, msg, &found, errp) != 0) {
957 if (*errp) {
958 goto out;
961 break;
962 case DM_WHO_SWAP:
964 * Not in use for this.
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;
971 if (strcmp(by, DM_USE_LU) == 0 &&
972 strcmp(data, "-") == 0) {
973 break;
975 if (strcmp(by, DM_USE_VFSTAB) == 0 &&
976 strcmp(data, "") == 0) {
977 break;
979 if (build_usage_string(dname,
980 by, data, msg, &found, errp) != 0) {
981 if (*errp) {
982 goto out;
985 break;
986 case DM_WHO_DUMP:
988 * Not in use for this.
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;
997 if (build_usage_string(dname,
998 by, data, msg, &found, errp)) {
999 if (*errp) {
1000 goto out;
1003 break;
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;
1015 break;
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;
1028 break;
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;
1038 break;
1040 default:
1042 * nothing found in use for this client
1043 * of libdiskmgt. Default is 'not in use'.
1045 break;
1048 out:
1049 free(dname);
1050 nvlist_free(dev_stats);
1052 return (found);
1055 void
1056 dm_get_usage_string(char *what, char *how, char **usage_string)
1060 if (usage_string == NULL || what == NULL) {
1061 return;
1063 *usage_string = NULL;
1065 if (strcmp(what, DM_USE_MOUNT) == 0) {
1066 if (strcmp(how, "swap") == 0) {
1067 *usage_string = dgettext(TEXT_DOMAIN,
1068 "%s is currently used by swap. Please see swap(1M)."
1069 "\n");
1070 } else {
1071 *usage_string = dgettext(TEXT_DOMAIN,
1072 "%s is currently mounted on %s."
1073 " Please see umount(1M).\n");
1075 } else if (strcmp(what, DM_USE_VFSTAB) == 0) {
1076 *usage_string = dgettext(TEXT_DOMAIN,
1077 "%s is normally mounted on %s according to /etc/vfstab. "
1078 "Please remove this entry to use this device.\n");
1079 } else if (strcmp(what, DM_USE_FS) == 0) {
1080 *usage_string = dgettext(TEXT_DOMAIN,
1081 "%s contains a %s filesystem.\n");
1082 } else if (strcmp(what, DM_USE_VXVM) == 0) {
1083 *usage_string = dgettext(TEXT_DOMAIN,
1084 "%s is part of VxVM volume %s.\n");
1085 } else if (strcmp(what, DM_USE_LU) == 0) {
1086 *usage_string = dgettext(TEXT_DOMAIN,
1087 "%s is in use for live upgrade %s. Please see ludelete(1M)."
1088 "\n");
1089 } else if (strcmp(what, DM_USE_DUMP) == 0) {
1090 *usage_string = dgettext(TEXT_DOMAIN,
1091 "%s is in use by %s. Please see dumpadm(1M)."
1092 "\n");
1093 } else if (strcmp(what, DM_USE_EXPORTED_ZPOOL) == 0) {
1094 *usage_string = dgettext(TEXT_DOMAIN,
1095 "%s is part of exported or potentially active ZFS pool %s. "
1096 "Please see zpool(1M).\n");
1097 } else if (strcmp(what, DM_USE_ACTIVE_ZPOOL) == 0) {
1098 *usage_string = dgettext(TEXT_DOMAIN,
1099 "%s is part of active ZFS pool %s. Please see zpool(1M)."
1100 "\n");
1101 } else if (strcmp(what, DM_USE_SPARE_ZPOOL) == 0) {
1102 *usage_string = dgettext(TEXT_DOMAIN,
1103 "%s is reserved as a hot spare for ZFS pool %s. Please "
1104 "see zpool(1M).\n");
1105 } else if (strcmp(what, DM_USE_L2CACHE_ZPOOL) == 0) {
1106 *usage_string = dgettext(TEXT_DOMAIN,
1107 "%s is in use as a cache device for ZFS pool %s. "
1108 "Please see zpool(1M).\n");
1111 void
1112 libdiskmgt_add_str(nvlist_t *attrs, char *name, char *val, int *errp)
1114 if (*errp == 0) {
1115 *errp = nvlist_add_string(attrs, name, val);
1119 descriptor_t **
1120 libdiskmgt_empty_desc_array(int *errp)
1122 descriptor_t **empty;
1124 empty = (descriptor_t **)calloc(1, sizeof (descriptor_t *));
1125 if (empty == NULL) {
1126 *errp = ENOMEM;
1127 return (NULL);
1129 empty[0] = NULL;
1131 *errp = 0;
1132 return (empty);
1135 void
1136 libdiskmgt_init_debug()
1138 char *valp;
1140 if ((valp = getenv(DM_DEBUG)) != NULL) {
1141 dm_debug = atoi(valp);
1146 libdiskmgt_str_eq(char *nm1, char *nm2)
1148 if (nm1 == NULL) {
1149 if (dm_debug) {
1150 (void) fprintf(stderr, "WARNING: str_eq nm1 NULL\n");
1153 if (nm2 == NULL) {
1154 return (1);
1155 } else {
1156 return (0);
1160 /* nm1 != NULL */
1162 if (nm2 == NULL) {
1163 if (dm_debug) {
1164 (void) fprintf(stderr, "WARNING: str_eq nm2 NULL\n");
1166 return (0);
1169 if (strcmp(nm1, nm2) == 0) {
1170 return (1);
1173 return (0);
1176 /*ARGSUSED*/
1177 static descriptor_t **
1178 desc_array_to_ptr_array(dm_descriptor_t *descs, int *errp)
1180 #ifdef _LP64
1181 return ((descriptor_t **)descs);
1182 #else
1183 /* convert the 64 bit descriptors to 32 bit ptrs */
1184 int cnt;
1185 int i;
1186 descriptor_t **da;
1188 for (cnt = 0; descs[cnt]; cnt++)
1191 da = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
1192 if (da == NULL) {
1193 *errp = ENOMEM;
1194 return (NULL);
1197 for (i = 0; descs[i]; i++) {
1198 da[i] = (descriptor_t *)(uintptr_t)descs[i];
1200 *errp = 0;
1201 free(descs);
1203 return (da);
1204 #endif
1207 /*ARGSUSED*/
1208 static dm_descriptor_t *
1209 ptr_array_to_desc_array(descriptor_t **ptrs, int *errp)
1211 #ifdef _LP64
1212 return ((dm_descriptor_t *)ptrs);
1213 #else
1214 /* convert the 32 bit ptrs to the 64 bit descriptors */
1215 int cnt;
1216 int i;
1217 dm_descriptor_t *da;
1219 if (*errp != 0 || ptrs == NULL) {
1220 return (NULL);
1223 for (cnt = 0; ptrs[cnt]; cnt++)
1226 da = (dm_descriptor_t *)calloc(cnt + 1, sizeof (dm_descriptor_t));
1227 if (da == NULL) {
1228 *errp = ENOMEM;
1229 return (NULL);
1232 for (i = 0; ptrs[i]; i++) {
1233 da[i] = (uintptr_t)ptrs[i];
1235 *errp = 0;
1236 free(ptrs);
1238 return (da);
1239 #endif
1242 * Build the usage string for the in use data. Return the build string in
1243 * the msg parameter. This function takes care of reallocing all the memory
1244 * for this usage string. Usage string is returned already formatted for
1245 * localization.
1247 static int
1248 build_usage_string(char *dname, char *by, char *data, char **msg,
1249 int *found, int *errp)
1251 int len0;
1252 int len1;
1253 char *use;
1254 char *p;
1256 *errp = 0;
1258 dm_get_usage_string(by, data, &use);
1259 if (!use) {
1260 return (-1);
1263 if (*msg)
1264 len0 = strlen(*msg);
1265 else
1266 len0 = 0;
1267 /* LINTED */
1268 len1 = snprintf(NULL, 0, use, dname, data);
1271 * If multiple in use details they
1272 * are listed 1 per line for ease of
1273 * reading. dm_find_usage_string
1274 * formats these appropriately.
1276 if ((p = realloc(*msg, len0 + len1 + 1)) == NULL) {
1277 *errp = errno;
1278 free(*msg);
1279 return (-1);
1281 *msg = p;
1283 /* LINTED */
1284 (void) snprintf(*msg + len0, len1 + 1, use, dname, data);
1285 (*found)++;
1286 return (0);