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