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
dm_free_descriptor(dm_descriptor_t desc)68 dm_free_descriptor(dm_descriptor_t desc)
69 {
70 descriptor_t *dp;
71
72 if (desc == 0) {
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
dm_free_descriptors(dm_descriptor_t * desc_list)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
dm_free_name(char * name)104 dm_free_name(char *name)
105 {
106 free(name);
107 }
108
109 dm_descriptor_t *
dm_get_associated_descriptors(dm_descriptor_t desc,dm_desc_type_t type,int * errp)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 *
dm_get_associated_types(dm_desc_type_t type)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 *
dm_get_attributes(dm_descriptor_t desc,int * errp)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
dm_get_descriptor_by_name(dm_desc_type_t desc_type,char * name,int * errp)254 dm_get_descriptor_by_name(dm_desc_type_t desc_type, char *name, int *errp)
255 {
256 dm_descriptor_t desc = 0;
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 *
dm_get_descriptors(dm_desc_type_t type,int filter[],int * errp)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 *
dm_get_name(dm_descriptor_t desc,int * errp)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 *
dm_get_stats(dm_descriptor_t desc,int stat_type,int * errp)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
dm_get_type(dm_descriptor_t desc)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
dm_get_slices(char * drive,dm_descriptor_t ** slices,int * errp)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 != 0) {
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
dm_get_slice_stats(char * slice,nvlist_t ** dev_stats,int * errp)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 != 0) {
555 *dev_stats = dm_get_stats(devp, DM_SLICE_STAT_USE, errp);
556 dm_free_descriptor(devp);
557 }
558 }
559
560 /*
561 * Checks for overlapping slices. If the given device is a slice, and it
562 * overlaps with any non-backup slice on the disk, return true with a detailed
563 * description similar to dm_inuse().
564 */
565 int
dm_isoverlapping(char * slicename,char ** overlaps_with,int * errp)566 dm_isoverlapping(char *slicename, char **overlaps_with, int *errp)
567 {
568 dm_descriptor_t slice = 0;
569 dm_descriptor_t *media = NULL;
570 dm_descriptor_t *slices = NULL;
571 int i = 0;
572 uint32_t in_snum;
573 uint64_t start_block = 0;
574 uint64_t end_block = 0;
575 uint64_t media_size = 0;
576 uint64_t size = 0;
577 nvlist_t *media_attrs = NULL;
578 nvlist_t *slice_attrs = NULL;
579 int ret = 0;
580
581 slice = dm_get_descriptor_by_name(DM_SLICE, slicename, errp);
582 if (slice == 0)
583 goto out;
584
585 /*
586 * Get the list of slices be fetching the associated media, and then all
587 * associated slices.
588 */
589 media = dm_get_associated_descriptors(slice, DM_MEDIA, errp);
590 if (media == NULL || *media == 0 || *errp != 0)
591 goto out;
592
593 slices = dm_get_associated_descriptors(*media, DM_SLICE, errp);
594 if (slices == NULL || *slices == 0 || *errp != 0)
595 goto out;
596
597 media_attrs = dm_get_attributes(*media, errp);
598 if (media_attrs == NULL || *errp)
599 goto out;
600
601 *errp = nvlist_lookup_uint64(media_attrs, DM_NACCESSIBLE, &media_size);
602 if (*errp != 0)
603 goto out;
604
605 slice_attrs = dm_get_attributes(slice, errp);
606 if (slice_attrs == NULL || *errp != 0)
607 goto out;
608
609 *errp = nvlist_lookup_uint64(slice_attrs, DM_START, &start_block);
610 if (*errp != 0)
611 goto out;
612
613 *errp = nvlist_lookup_uint64(slice_attrs, DM_SIZE, &size);
614 if (*errp != 0)
615 goto out;
616
617 *errp = nvlist_lookup_uint32(slice_attrs, DM_INDEX, &in_snum);
618 if (*errp != 0)
619 goto out;
620
621 end_block = (start_block + size) - 1;
622
623 for (i = 0; slices[i]; i ++) {
624 uint64_t other_start;
625 uint64_t other_end;
626 uint64_t other_size;
627 uint32_t snum;
628
629 nvlist_t *other_attrs = dm_get_attributes(slices[i], errp);
630
631 if (other_attrs == NULL)
632 continue;
633
634 if (*errp != 0)
635 goto out;
636
637 *errp = nvlist_lookup_uint64(other_attrs, DM_START,
638 &other_start);
639 if (*errp) {
640 nvlist_free(other_attrs);
641 goto out;
642 }
643
644 *errp = nvlist_lookup_uint64(other_attrs, DM_SIZE,
645 &other_size);
646
647 if (*errp) {
648 nvlist_free(other_attrs);
649 ret = -1;
650 goto out;
651 }
652
653 other_end = (other_size + other_start) - 1;
654
655 *errp = nvlist_lookup_uint32(other_attrs, DM_INDEX,
656 &snum);
657
658 if (*errp) {
659 nvlist_free(other_attrs);
660 ret = -1;
661 goto out;
662 }
663
664 /*
665 * Check to see if there are > 2 overlapping regions
666 * on this media in the same region as this slice.
667 * This is done by assuming the following:
668 * Slice 2 is the backup slice if it is the size
669 * of the whole disk
670 * If slice 2 is the overlap and slice 2 is the size of
671 * the whole disk, continue. If another slice is found
672 * that overlaps with our slice, return it.
673 * There is the potential that there is more than one slice
674 * that our slice overlaps with, however, we only return
675 * the first overlapping slice we find.
676 *
677 */
678 if (start_block >= other_start && start_block <= other_end) {
679 if ((snum == 2 && (other_size == media_size)) ||
680 snum == in_snum) {
681 continue;
682 } else {
683 char *str = dm_get_name(slices[i], errp);
684 if (*errp != 0) {
685 nvlist_free(other_attrs);
686 ret = -1;
687 goto out;
688 }
689 *overlaps_with = strdup(str);
690 dm_free_name(str);
691 nvlist_free(other_attrs);
692 ret = 1;
693 goto out;
694 }
695 } else if (other_start >= start_block &&
696 other_start <= end_block) {
697 if ((snum == 2 && (other_size == media_size)) ||
698 snum == in_snum) {
699 continue;
700 } else {
701 char *str = dm_get_name(slices[i], errp);
702 if (*errp != 0) {
703 nvlist_free(other_attrs);
704 ret = -1;
705 goto out;
706 }
707 *overlaps_with = strdup(str);
708 dm_free_name(str);
709 nvlist_free(other_attrs);
710 ret = 1;
711 goto out;
712 }
713 }
714 nvlist_free(other_attrs);
715 }
716
717 out:
718 nvlist_free(media_attrs);
719 nvlist_free(slice_attrs);
720
721 if (slices)
722 dm_free_descriptors(slices);
723 if (media)
724 dm_free_descriptors(media);
725 if (slice)
726 dm_free_descriptor(slice);
727
728 return (ret);
729 }
730
731 /*
732 * Get the full list of swap entries. Returns -1 on error, or >= 0 to
733 * indicate the number of entries in the list. Callers are responsible
734 * for calling dm_free_swapentries() to deallocate memory. If this
735 * returns 0, the swaptbl_t still needs to be freed.
736 */
737 int
dm_get_swapentries(swaptbl_t ** stp,int * errp)738 dm_get_swapentries(swaptbl_t **stp, int *errp)
739 {
740 int count, i;
741 swaptbl_t *tbl;
742 char *ptr;
743
744 *stp = NULL;
745
746 /* get number of swap entries */
747 if ((count = swapctl(SC_GETNSWP, NULL)) < 0) {
748 *errp = errno;
749 return (-1);
750 }
751
752 if (count == 0) {
753 return (0);
754 }
755
756 /* allocate space */
757 tbl = calloc(1, sizeof (int) + count * sizeof (swapent_t));
758 if (tbl == NULL) {
759 *errp = ENOMEM;
760 return (-1);
761 }
762
763 ptr = calloc(1, count * MAXPATHLEN);
764 if (ptr == NULL) {
765 *errp = ENOMEM;
766 free(tbl);
767 return (-1);
768 }
769
770 /* set up pointers to the pathnames */
771 tbl->swt_n = count;
772 for (i = 0; i < count; i++) {
773 tbl->swt_ent[i].ste_path = ptr;
774 ptr += MAXPATHLEN;
775 }
776
777 /* get list of swap paths */
778 count = swapctl(SC_LIST, tbl);
779 if (count < 0) {
780 *errp = errno;
781 free(ptr);
782 free(tbl);
783 return (-1);
784 }
785
786 *stp = tbl;
787 return (count);
788 }
789
790 /* ARGSUSED */
791 void
dm_free_swapentries(swaptbl_t * stp)792 dm_free_swapentries(swaptbl_t *stp)
793 {
794 ASSERT(stp != NULL);
795
796 free(stp->swt_ent[0].ste_path);
797 free(stp);
798 }
799
800 /*
801 * Check a slice to see if it's being used by swap.
802 */
803 int
dm_inuse_swap(const char * dev_name,int * errp)804 dm_inuse_swap(const char *dev_name, int *errp)
805 {
806 int count;
807 int found;
808 swaptbl_t *tbl = NULL;
809
810 *errp = 0;
811
812 count = dm_get_swapentries(&tbl, errp);
813 if (count < 0 || *errp) {
814 if (tbl)
815 dm_free_swapentries(tbl);
816 return (-1);
817 }
818
819 /* if there are no swap entries, we're done */
820 if (!count) {
821 return (0);
822 }
823
824 ASSERT(tbl != NULL);
825
826 found = 0;
827 while (count--) {
828 if (strcmp(dev_name, tbl->swt_ent[count].ste_path) == 0) {
829 found = 1;
830 break;
831 }
832 }
833
834 dm_free_swapentries(tbl);
835 return (found);
836 }
837
838 /*
839 * Returns 'in use' details, if found, about a specific dev_name,
840 * based on the caller(who). It is important to note that it is possible
841 * for there to be more than one 'in use' statistic regarding a dev_name.
842 * The **msg parameter returns a list of 'in use' details. This message
843 * is formatted via gettext().
844 */
845 int
dm_inuse(char * dev_name,char ** msg,dm_who_type_t who,int * errp)846 dm_inuse(char *dev_name, char **msg, dm_who_type_t who, int *errp)
847 {
848 nvlist_t *dev_stats = NULL;
849 char *by, *data;
850 nvpair_t *nvwhat = NULL;
851 nvpair_t *nvdesc = NULL;
852 int found = 0;
853 int err;
854 char *dname = NULL;
855
856 *errp = 0;
857 *msg = NULL;
858
859 /*
860 * If the user doesn't want to do in use checking, return.
861 */
862
863 if (NOINUSE_SET)
864 return (0);
865
866 dname = getfullblkname(dev_name);
867 /*
868 * If we cannot find the block name, we cannot check the device
869 * for in use statistics. So, return found, which is == 0.
870 */
871 if (dname == NULL || *dname == '\0') {
872 return (found);
873 }
874
875 /*
876 * Slice stats for swap devices are only returned if mounted
877 * (e.g. /tmp). Other devices or files being used for swap
878 * are ignored, so we add a special check here to use swapctl(2)
879 * to perform in-use checking.
880 */
881 if (ANY_ZPOOL_USE(who) && (err = dm_inuse_swap(dname, errp))) {
882
883 /* on error, dm_inuse_swap sets errp */
884 if (err < 0) {
885 free(dname);
886 return (err);
887 }
888
889 /* simulate a mounted swap device */
890 (void) build_usage_string(dname, DM_USE_MOUNT, "swap", msg,
891 &found, errp);
892
893 /* if this fails, dm_get_usage_string changed */
894 ASSERT(found == 1);
895
896 free(dname);
897 return (found);
898 }
899
900 dm_get_slice_stats(dname, &dev_stats, errp);
901 if (dev_stats == NULL) {
902 /*
903 * If there is an error, but it isn't a no device found error
904 * return the error as recorded. Otherwise, with a full
905 * block name, we might not be able to get the slice
906 * associated, and will get an ENODEV error.
907 */
908 if (*errp == ENODEV)
909 *errp = 0;
910 free(dname);
911 return (found);
912 }
913
914 for (;;) {
915
916 nvwhat = nvlist_next_nvpair(dev_stats, nvdesc);
917 nvdesc = nvlist_next_nvpair(dev_stats, nvwhat);
918
919 /*
920 * End of the list found.
921 */
922 if (nvwhat == NULL || nvdesc == NULL) {
923 break;
924 }
925 /*
926 * Otherwise, we check to see if this client(who) cares
927 * about this in use scenario
928 */
929
930 ASSERT(strcmp(nvpair_name(nvwhat), DM_USED_BY) == 0);
931 ASSERT(strcmp(nvpair_name(nvdesc), DM_USED_NAME) == 0);
932 /*
933 * If we error getting the string value continue on
934 * to the next pair(if there is one)
935 */
936 if (nvpair_value_string(nvwhat, &by)) {
937 continue;
938 }
939 if (nvpair_value_string(nvdesc, &data)) {
940 continue;
941 }
942
943 switch (who) {
944 case DM_WHO_MKFS:
945 /*
946 * mkfs is not in use for these cases.
947 * All others are in use.
948 */
949 if (strcmp(by, DM_USE_LU) == 0 ||
950 strcmp(by, DM_USE_FS) == 0 ||
951 strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0) {
952 break;
953 }
954 if (build_usage_string(dname,
955 by, data, msg, &found, errp) != 0) {
956 if (*errp) {
957 goto out;
958 }
959 }
960 break;
961 case DM_WHO_SWAP:
962 /*
963 * Not in use for this.
964 */
965 if (strcmp(by, DM_USE_DUMP) == 0 ||
966 strcmp(by, DM_USE_FS) == 0 ||
967 strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0) {
968 break;
969 }
970 if (strcmp(by, DM_USE_LU) == 0 &&
971 strcmp(data, "-") == 0) {
972 break;
973 }
974 if (strcmp(by, DM_USE_VFSTAB) == 0 &&
975 strcmp(data, "") == 0) {
976 break;
977 }
978 if (build_usage_string(dname,
979 by, data, msg, &found, errp) != 0) {
980 if (*errp) {
981 goto out;
982 }
983 }
984 break;
985 case DM_WHO_DUMP:
986 /*
987 * Not in use for this.
988 */
989 if ((strcmp(by, DM_USE_MOUNT) == 0 &&
990 strcmp(data, "swap") == 0) ||
991 strcmp(by, DM_USE_DUMP) == 0 ||
992 strcmp(by, DM_USE_FS) == 0 ||
993 strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0) {
994 break;
995 }
996 if (build_usage_string(dname,
997 by, data, msg, &found, errp)) {
998 if (*errp) {
999 goto out;
1000 }
1001 }
1002 break;
1003
1004 case DM_WHO_FORMAT:
1005 if (strcmp(by, DM_USE_FS) == 0 ||
1006 strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0)
1007 break;
1008 if (build_usage_string(dname,
1009 by, data, msg, &found, errp) != 0) {
1010 if (*errp) {
1011 goto out;
1012 }
1013 }
1014 break;
1015
1016 case DM_WHO_ZPOOL_FORCE:
1017 if (strcmp(by, DM_USE_FS) == 0 ||
1018 strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0)
1019 break;
1020 /* FALLTHROUGH */
1021 case DM_WHO_ZPOOL:
1022 if (build_usage_string(dname,
1023 by, data, msg, &found, errp) != 0) {
1024 if (*errp)
1025 goto out;
1026 }
1027 break;
1028
1029 case DM_WHO_ZPOOL_SPARE:
1030 if (strcmp(by, DM_USE_SPARE_ZPOOL) != 0) {
1031 if (build_usage_string(dname, by,
1032 data, msg, &found, errp) != 0) {
1033 if (*errp)
1034 goto out;
1035 }
1036 }
1037 break;
1038
1039 default:
1040 /*
1041 * nothing found in use for this client
1042 * of libdiskmgt. Default is 'not in use'.
1043 */
1044 break;
1045 }
1046 }
1047 out:
1048 if (dname != NULL)
1049 free(dname);
1050 nvlist_free(dev_stats);
1051
1052 return (found);
1053 }
1054
1055 void
dm_get_usage_string(char * what,char * how,char ** usage_string)1056 dm_get_usage_string(char *what, char *how, char **usage_string)
1057 {
1058
1059
1060 if (usage_string == NULL || what == NULL) {
1061 return;
1062 }
1063 *usage_string = NULL;
1064
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(8)."
1069 "\n");
1070 } else {
1071 *usage_string = dgettext(TEXT_DOMAIN,
1072 "%s is currently mounted on %s."
1073 " Please see umount(8).\n");
1074 }
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(8)."
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(8)."
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(8).\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(8)."
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(8).\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(8).\n");
1109 }
1110 }
1111 void
libdiskmgt_add_str(nvlist_t * attrs,char * name,char * val,int * errp)1112 libdiskmgt_add_str(nvlist_t *attrs, char *name, char *val, int *errp)
1113 {
1114 if (*errp == 0) {
1115 *errp = nvlist_add_string(attrs, name, val);
1116 }
1117 }
1118
1119 descriptor_t **
libdiskmgt_empty_desc_array(int * errp)1120 libdiskmgt_empty_desc_array(int *errp)
1121 {
1122 descriptor_t **empty;
1123
1124 empty = (descriptor_t **)calloc(1, sizeof (descriptor_t *));
1125 if (empty == NULL) {
1126 *errp = ENOMEM;
1127 return (NULL);
1128 }
1129 empty[0] = NULL;
1130
1131 *errp = 0;
1132 return (empty);
1133 }
1134
1135 void
libdiskmgt_init_debug()1136 libdiskmgt_init_debug()
1137 {
1138 char *valp;
1139
1140 if ((valp = getenv(DM_DEBUG)) != NULL) {
1141 dm_debug = atoi(valp);
1142 }
1143 }
1144
1145 int
libdiskmgt_str_eq(char * nm1,char * nm2)1146 libdiskmgt_str_eq(char *nm1, char *nm2)
1147 {
1148 if (nm1 == NULL) {
1149 if (dm_debug) {
1150 (void) fprintf(stderr, "WARNING: str_eq nm1 NULL\n");
1151 }
1152
1153 if (nm2 == NULL) {
1154 return (1);
1155 } else {
1156 return (0);
1157 }
1158 }
1159
1160 /* nm1 != NULL */
1161
1162 if (nm2 == NULL) {
1163 if (dm_debug) {
1164 (void) fprintf(stderr, "WARNING: str_eq nm2 NULL\n");
1165 }
1166 return (0);
1167 }
1168
1169 if (strcmp(nm1, nm2) == 0) {
1170 return (1);
1171 }
1172
1173 return (0);
1174 }
1175
1176 /*ARGSUSED*/
1177 static descriptor_t **
desc_array_to_ptr_array(dm_descriptor_t * descs,int * errp)1178 desc_array_to_ptr_array(dm_descriptor_t *descs, int *errp)
1179 {
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;
1187
1188 for (cnt = 0; descs[cnt]; cnt++)
1189 ;
1190
1191 da = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
1192 if (da == NULL) {
1193 *errp = ENOMEM;
1194 return (NULL);
1195 }
1196
1197 for (i = 0; descs[i]; i++) {
1198 da[i] = (descriptor_t *)(uintptr_t)descs[i];
1199 }
1200 *errp = 0;
1201 free(descs);
1202
1203 return (da);
1204 #endif
1205 }
1206
1207 /*ARGSUSED*/
1208 static dm_descriptor_t *
ptr_array_to_desc_array(descriptor_t ** ptrs,int * errp)1209 ptr_array_to_desc_array(descriptor_t **ptrs, int *errp)
1210 {
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;
1218
1219 if (*errp != 0 || ptrs == NULL) {
1220 return (NULL);
1221 }
1222
1223 for (cnt = 0; ptrs[cnt]; cnt++)
1224 ;
1225
1226 da = (dm_descriptor_t *)calloc(cnt + 1, sizeof (dm_descriptor_t));
1227 if (da == NULL) {
1228 *errp = ENOMEM;
1229 return (NULL);
1230 }
1231
1232 for (i = 0; ptrs[i]; i++) {
1233 da[i] = (uintptr_t)ptrs[i];
1234 }
1235 *errp = 0;
1236 free(ptrs);
1237
1238 return (da);
1239 #endif
1240 }
1241 /*
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.
1246 */
1247 static int
build_usage_string(char * dname,char * by,char * data,char ** msg,int * found,int * errp)1248 build_usage_string(char *dname, char *by, char *data, char **msg,
1249 int *found, int *errp)
1250 {
1251 int len0;
1252 int len1;
1253 char *use;
1254 char *p;
1255
1256 *errp = 0;
1257
1258 dm_get_usage_string(by, data, &use);
1259 if (!use) {
1260 return (-1);
1261 }
1262
1263 if (*msg)
1264 len0 = strlen(*msg);
1265 else
1266 len0 = 0;
1267 /* LINTED */
1268 len1 = snprintf(NULL, 0, use, dname, data);
1269
1270 /*
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.
1275 */
1276 if ((p = realloc(*msg, len0 + len1 + 1)) == NULL) {
1277 *errp = errno;
1278 free(*msg);
1279 return (-1);
1280 }
1281 *msg = p;
1282
1283 /* LINTED */
1284 (void) snprintf(*msg + len0, len1 + 1, use, dname, data);
1285 (*found)++;
1286 return (0);
1287 }
1288