13e1bd7a2Ssjelinek /* 23e1bd7a2Ssjelinek * CDDL HEADER START 33e1bd7a2Ssjelinek * 43e1bd7a2Ssjelinek * The contents of this file are subject to the terms of the 53e1bd7a2Ssjelinek * Common Development and Distribution License, Version 1.0 only 63e1bd7a2Ssjelinek * (the "License"). You may not use this file except in compliance 73e1bd7a2Ssjelinek * with the License. 83e1bd7a2Ssjelinek * 93e1bd7a2Ssjelinek * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 103e1bd7a2Ssjelinek * or http://www.opensolaris.org/os/licensing. 113e1bd7a2Ssjelinek * See the License for the specific language governing permissions 123e1bd7a2Ssjelinek * and limitations under the License. 133e1bd7a2Ssjelinek * 143e1bd7a2Ssjelinek * When distributing Covered Code, include this CDDL HEADER in each 153e1bd7a2Ssjelinek * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 163e1bd7a2Ssjelinek * If applicable, add the following below this CDDL HEADER, with the 173e1bd7a2Ssjelinek * fields enclosed by brackets "[]" replaced with your own identifying 183e1bd7a2Ssjelinek * information: Portions Copyright [yyyy] [name of copyright owner] 193e1bd7a2Ssjelinek * 203e1bd7a2Ssjelinek * CDDL HEADER END 213e1bd7a2Ssjelinek */ 223e1bd7a2Ssjelinek /* 233e1bd7a2Ssjelinek * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 243e1bd7a2Ssjelinek * Use is subject to license terms. 253e1bd7a2Ssjelinek */ 263e1bd7a2Ssjelinek 273e1bd7a2Ssjelinek 283e1bd7a2Ssjelinek #pragma ident "%Z%%M% %I% %E% SMI" 293e1bd7a2Ssjelinek 303e1bd7a2Ssjelinek /* 313e1bd7a2Ssjelinek * This file contains miscellaneous device validation routines. 323e1bd7a2Ssjelinek */ 333e1bd7a2Ssjelinek 343e1bd7a2Ssjelinek #include "global.h" 353e1bd7a2Ssjelinek #include <sys/mnttab.h> 363e1bd7a2Ssjelinek #include <sys/mntent.h> 373e1bd7a2Ssjelinek #include <sys/autoconf.h> 383e1bd7a2Ssjelinek 393e1bd7a2Ssjelinek #include <signal.h> 403e1bd7a2Ssjelinek #include <malloc.h> 413e1bd7a2Ssjelinek #include <unistd.h> 423e1bd7a2Ssjelinek #include <string.h> 433e1bd7a2Ssjelinek #include <errno.h> 443e1bd7a2Ssjelinek #include <fcntl.h> 453e1bd7a2Ssjelinek #include <sys/ioctl.h> 463e1bd7a2Ssjelinek #include <sys/fcntl.h> 473e1bd7a2Ssjelinek #include <sys/stat.h> 483e1bd7a2Ssjelinek #include <sys/swap.h> 493e1bd7a2Ssjelinek #include <sys/sysmacros.h> 503e1bd7a2Ssjelinek #include <ctype.h> 513e1bd7a2Ssjelinek #include <libdiskmgt.h> 523e1bd7a2Ssjelinek #include <libnvpair.h> 533e1bd7a2Ssjelinek #include "misc.h" 543e1bd7a2Ssjelinek #include "checkdev.h" 553e1bd7a2Ssjelinek 563e1bd7a2Ssjelinek /* Function prototypes */ 573e1bd7a2Ssjelinek #ifdef __STDC__ 583e1bd7a2Ssjelinek 593e1bd7a2Ssjelinek static struct swaptable *getswapentries(void); 603e1bd7a2Ssjelinek static void freeswapentries(struct swaptable *); 613e1bd7a2Ssjelinek static int getpartition(char *pathname); 623e1bd7a2Ssjelinek static int checkpartitions(int bm_mounted); 633e1bd7a2Ssjelinek 643e1bd7a2Ssjelinek #else /* __STDC__ */ 653e1bd7a2Ssjelinek 663e1bd7a2Ssjelinek static struct swaptable *getswapentries(); 673e1bd7a2Ssjelinek static void freeswapentries(); 683e1bd7a2Ssjelinek static int getpartition(); 693e1bd7a2Ssjelinek static int checkpartitions(); 703e1bd7a2Ssjelinek 713e1bd7a2Ssjelinek #endif /* __STDC__ */ 723e1bd7a2Ssjelinek 733e1bd7a2Ssjelinek extern char *getfullname(); 743e1bd7a2Ssjelinek 753e1bd7a2Ssjelinek static struct swaptable * 763e1bd7a2Ssjelinek getswapentries(void) 773e1bd7a2Ssjelinek { 783e1bd7a2Ssjelinek register struct swaptable *st; 793e1bd7a2Ssjelinek register struct swapent *swapent; 803e1bd7a2Ssjelinek int i, num; 813e1bd7a2Ssjelinek char fullpathname[MAXPATHLEN]; 823e1bd7a2Ssjelinek 833e1bd7a2Ssjelinek /* 843e1bd7a2Ssjelinek * get the number of swap entries 853e1bd7a2Ssjelinek */ 863e1bd7a2Ssjelinek if ((num = swapctl(SC_GETNSWP, (void *)NULL)) == -1) { 873e1bd7a2Ssjelinek err_print("swapctl error "); 883e1bd7a2Ssjelinek fullabort(); 893e1bd7a2Ssjelinek } 903e1bd7a2Ssjelinek if (num == 0) 913e1bd7a2Ssjelinek return (NULL); 923e1bd7a2Ssjelinek if ((st = (swaptbl_t *)malloc(num * sizeof (swapent_t) + sizeof (int))) 933e1bd7a2Ssjelinek == NULL) { 943e1bd7a2Ssjelinek err_print("getswapentries: malloc failed.\n"); 953e1bd7a2Ssjelinek fullabort(); 963e1bd7a2Ssjelinek } 973e1bd7a2Ssjelinek swapent = st->swt_ent; 983e1bd7a2Ssjelinek for (i = 0; i < num; i++, swapent++) { 993e1bd7a2Ssjelinek if ((swapent->ste_path = malloc(MAXPATHLEN)) == NULL) { 1003e1bd7a2Ssjelinek err_print("getswapentries: malloc failed.\n"); 1013e1bd7a2Ssjelinek fullabort(); 1023e1bd7a2Ssjelinek } 1033e1bd7a2Ssjelinek } 1043e1bd7a2Ssjelinek st->swt_n = num; 1053e1bd7a2Ssjelinek if ((num = swapctl(SC_LIST, (void *)st)) == -1) { 1063e1bd7a2Ssjelinek err_print("swapctl error "); 1073e1bd7a2Ssjelinek fullabort(); 1083e1bd7a2Ssjelinek } 1093e1bd7a2Ssjelinek swapent = st->swt_ent; 1103e1bd7a2Ssjelinek for (i = 0; i < num; i++, swapent++) { 1113e1bd7a2Ssjelinek if (*swapent->ste_path != '/') { 1123e1bd7a2Ssjelinek (void) snprintf(fullpathname, sizeof (fullpathname), 1133e1bd7a2Ssjelinek "/dev/%s", swapent->ste_path); 1143e1bd7a2Ssjelinek (void) strcpy(swapent->ste_path, fullpathname); 1153e1bd7a2Ssjelinek } 1163e1bd7a2Ssjelinek } 1173e1bd7a2Ssjelinek return (st); 1183e1bd7a2Ssjelinek } 1193e1bd7a2Ssjelinek 1203e1bd7a2Ssjelinek static void 1213e1bd7a2Ssjelinek freeswapentries(st) 1223e1bd7a2Ssjelinek struct swaptable *st; 1233e1bd7a2Ssjelinek { 1243e1bd7a2Ssjelinek register struct swapent *swapent; 1253e1bd7a2Ssjelinek int i; 1263e1bd7a2Ssjelinek 1273e1bd7a2Ssjelinek swapent = st->swt_ent; 1283e1bd7a2Ssjelinek for (i = 0; i < st->swt_n; i++, swapent++) 1293e1bd7a2Ssjelinek free(swapent->ste_path); 1303e1bd7a2Ssjelinek free(st); 1313e1bd7a2Ssjelinek 1323e1bd7a2Ssjelinek } 1333e1bd7a2Ssjelinek 1343e1bd7a2Ssjelinek /* 1353e1bd7a2Ssjelinek * function getpartition: 1363e1bd7a2Ssjelinek */ 1373e1bd7a2Ssjelinek static int 1383e1bd7a2Ssjelinek getpartition(pathname) 1393e1bd7a2Ssjelinek char *pathname; 1403e1bd7a2Ssjelinek { 1413e1bd7a2Ssjelinek int mfd; 1423e1bd7a2Ssjelinek struct dk_cinfo dkinfo; 1433e1bd7a2Ssjelinek struct stat stbuf; 1443e1bd7a2Ssjelinek char raw_device[MAXPATHLEN]; 1453e1bd7a2Ssjelinek int found = -1; 1463e1bd7a2Ssjelinek 1473e1bd7a2Ssjelinek /* 1483e1bd7a2Ssjelinek * Map the block device name to the raw device name. 1493e1bd7a2Ssjelinek * If it doesn't appear to be a device name, skip it. 1503e1bd7a2Ssjelinek */ 1513e1bd7a2Ssjelinek if (match_substr(pathname, "/dev/") == 0) 1523e1bd7a2Ssjelinek return (found); 1533e1bd7a2Ssjelinek (void) strcpy(raw_device, "/dev/r"); 1543e1bd7a2Ssjelinek (void) strcat(raw_device, pathname + strlen("/dev/")); 1553e1bd7a2Ssjelinek /* 1563e1bd7a2Ssjelinek * Determine if this appears to be a disk device. 1573e1bd7a2Ssjelinek * First attempt to open the device. If if fails, skip it. 1583e1bd7a2Ssjelinek */ 1593e1bd7a2Ssjelinek if ((mfd = open(raw_device, O_RDWR | O_NDELAY)) < 0) { 1603e1bd7a2Ssjelinek return (found); 1613e1bd7a2Ssjelinek } 1623e1bd7a2Ssjelinek /* 1633e1bd7a2Ssjelinek * Must be a character device 1643e1bd7a2Ssjelinek */ 1653e1bd7a2Ssjelinek if (fstat(mfd, &stbuf) == -1 || !S_ISCHR(stbuf.st_mode)) { 1663e1bd7a2Ssjelinek (void) close(mfd); 1673e1bd7a2Ssjelinek return (found); 1683e1bd7a2Ssjelinek } 1693e1bd7a2Ssjelinek /* 1703e1bd7a2Ssjelinek * Attempt to read the configuration info on the disk. 1713e1bd7a2Ssjelinek */ 1723e1bd7a2Ssjelinek if (ioctl(mfd, DKIOCINFO, &dkinfo) < 0) { 1733e1bd7a2Ssjelinek (void) close(mfd); 1743e1bd7a2Ssjelinek return (found); 1753e1bd7a2Ssjelinek } 1763e1bd7a2Ssjelinek /* 1773e1bd7a2Ssjelinek * Finished with the opened device 1783e1bd7a2Ssjelinek */ 1793e1bd7a2Ssjelinek (void) close(mfd); 1803e1bd7a2Ssjelinek 1813e1bd7a2Ssjelinek /* 1823e1bd7a2Ssjelinek * If it's not the disk we're interested in, it doesn't apply. 1833e1bd7a2Ssjelinek */ 1843e1bd7a2Ssjelinek if (cur_disk->disk_dkinfo.dki_ctype != dkinfo.dki_ctype || 1853e1bd7a2Ssjelinek cur_disk->disk_dkinfo.dki_cnum != dkinfo.dki_cnum || 1863e1bd7a2Ssjelinek cur_disk->disk_dkinfo.dki_unit != dkinfo.dki_unit || 1873e1bd7a2Ssjelinek strcmp(cur_disk->disk_dkinfo.dki_dname, 1883e1bd7a2Ssjelinek dkinfo.dki_dname) != 0) { 1893e1bd7a2Ssjelinek return (found); 1903e1bd7a2Ssjelinek } 1913e1bd7a2Ssjelinek 1923e1bd7a2Ssjelinek /* 1933e1bd7a2Ssjelinek * Extract the partition that is mounted. 1943e1bd7a2Ssjelinek */ 1953e1bd7a2Ssjelinek return (PARTITION(stbuf.st_rdev)); 1963e1bd7a2Ssjelinek } 1973e1bd7a2Ssjelinek 1983e1bd7a2Ssjelinek /* 1993e1bd7a2Ssjelinek * This Routine checks to see if there are partitions used for swapping overlaps 2003e1bd7a2Ssjelinek * a given portion of a disk. If the start parameter is < 0, it means 2013e1bd7a2Ssjelinek * that the entire disk should be checked 2023e1bd7a2Ssjelinek */ 2033e1bd7a2Ssjelinek int 2043e1bd7a2Ssjelinek checkswap(start, end) 2053e1bd7a2Ssjelinek diskaddr_t start, end; 2063e1bd7a2Ssjelinek { 2073e1bd7a2Ssjelinek struct swaptable *st; 2083e1bd7a2Ssjelinek struct swapent *swapent; 2093e1bd7a2Ssjelinek int i; 2103e1bd7a2Ssjelinek int found = 0; 2113e1bd7a2Ssjelinek struct dk_map32 *map; 2123e1bd7a2Ssjelinek int part; 2133e1bd7a2Ssjelinek 2143e1bd7a2Ssjelinek /* 2153e1bd7a2Ssjelinek * If we are only checking part of the disk, the disk must 2163e1bd7a2Ssjelinek * have a partition map to check against. If it doesn't, 2173e1bd7a2Ssjelinek * we hope for the best. 2183e1bd7a2Ssjelinek */ 2193e1bd7a2Ssjelinek if (cur_parts == NULL) 2203e1bd7a2Ssjelinek return (0); 2213e1bd7a2Ssjelinek 2223e1bd7a2Ssjelinek /* 2233e1bd7a2Ssjelinek * check for swap entries 2243e1bd7a2Ssjelinek */ 2253e1bd7a2Ssjelinek st = getswapentries(); 2263e1bd7a2Ssjelinek /* 2273e1bd7a2Ssjelinek * if there are no swap entries return. 2283e1bd7a2Ssjelinek */ 2293e1bd7a2Ssjelinek if (st == (struct swaptable *)NULL) 2303e1bd7a2Ssjelinek return (0); 2313e1bd7a2Ssjelinek swapent = st->swt_ent; 2323e1bd7a2Ssjelinek for (i = 0; i < st->swt_n; i++, swapent++) { 2333e1bd7a2Ssjelinek if ((part = getpartition(swapent->ste_path)) != -1) { 2343e1bd7a2Ssjelinek if (start == UINT_MAX64) { 2353e1bd7a2Ssjelinek found = -1; 2363e1bd7a2Ssjelinek break; 2373e1bd7a2Ssjelinek } 2383e1bd7a2Ssjelinek map = &cur_parts->pinfo_map[part]; 2393e1bd7a2Ssjelinek if ((start >= (int)(map->dkl_cylno * spc() + 2403e1bd7a2Ssjelinek map->dkl_nblk)) || (end < (int)(map->dkl_cylno 2413e1bd7a2Ssjelinek * spc()))) { 2423e1bd7a2Ssjelinek continue; 2433e1bd7a2Ssjelinek } 2443e1bd7a2Ssjelinek found = -1; 2453e1bd7a2Ssjelinek break; 2463e1bd7a2Ssjelinek }; 2473e1bd7a2Ssjelinek } 2483e1bd7a2Ssjelinek freeswapentries(st); 2493e1bd7a2Ssjelinek /* 2503e1bd7a2Ssjelinek * If we found trouble and we're running from a command file, 2513e1bd7a2Ssjelinek * quit before doing something we really regret. 2523e1bd7a2Ssjelinek */ 2533e1bd7a2Ssjelinek 2543e1bd7a2Ssjelinek if (found && option_f) { 2553e1bd7a2Ssjelinek err_print( 2563e1bd7a2Ssjelinek "Operation on disks being used for swapping must be interactive.\n"); 2573e1bd7a2Ssjelinek cmdabort(SIGINT); 2583e1bd7a2Ssjelinek } 2593e1bd7a2Ssjelinek 2603e1bd7a2Ssjelinek return (found); 2613e1bd7a2Ssjelinek 2623e1bd7a2Ssjelinek 2633e1bd7a2Ssjelinek } 2643e1bd7a2Ssjelinek /* 2653e1bd7a2Ssjelinek * Determines if there are partitions that are a part of an SVM, VxVM, zpool 2663e1bd7a2Ssjelinek * volume or a live upgrade device, overlapping a given portion of a disk. 2673e1bd7a2Ssjelinek * Mounts and swap devices are checked in legacy format code. 2683e1bd7a2Ssjelinek */ 2693e1bd7a2Ssjelinek int 2703e1bd7a2Ssjelinek checkdevinuse(char *cur_disk_path, diskaddr_t start, diskaddr_t end, int print, 2713e1bd7a2Ssjelinek int check_label) 2723e1bd7a2Ssjelinek { 2733e1bd7a2Ssjelinek 2743e1bd7a2Ssjelinek int error; 2753e1bd7a2Ssjelinek int found = 0; 2763e1bd7a2Ssjelinek int check = 0; 2773e1bd7a2Ssjelinek int i; 2783e1bd7a2Ssjelinek int bm_inuse = 0; 2793e1bd7a2Ssjelinek int part = 0; 2803e1bd7a2Ssjelinek uint64_t slice_start, slice_size; 2813e1bd7a2Ssjelinek dm_descriptor_t *slices = NULL; 2823e1bd7a2Ssjelinek nvlist_t *attrs = NULL; 2833e1bd7a2Ssjelinek char *usage; 2843e1bd7a2Ssjelinek char *name; 2853e1bd7a2Ssjelinek 2863e1bd7a2Ssjelinek /* 287*82d71480Ssjelinek * If the user does not want to do in use checking, return immediately. 288*82d71480Ssjelinek * Normally, this is handled in libdiskmgt. For format, there is more 289*82d71480Ssjelinek * processing required, so we want to bypass the in use checking 290*82d71480Ssjelinek * here. 291*82d71480Ssjelinek */ 292*82d71480Ssjelinek 293*82d71480Ssjelinek if (NOINUSE_SET) 294*82d71480Ssjelinek return (0); 295*82d71480Ssjelinek 296*82d71480Ssjelinek /* 2973e1bd7a2Ssjelinek * For format, we get basic 'in use' details from libdiskmgt. After 2983e1bd7a2Ssjelinek * that we must do the appropriate checking to see if the 'in use' 2993e1bd7a2Ssjelinek * details require a bit of additional work. 3003e1bd7a2Ssjelinek */ 3013e1bd7a2Ssjelinek 3023e1bd7a2Ssjelinek dm_get_slices(cur_disk_path, &slices, &error); 3033e1bd7a2Ssjelinek if (error) { 3043e1bd7a2Ssjelinek err_print("Error occurred with device in use checking: %s\n", 3053e1bd7a2Ssjelinek strerror(error)); 3063e1bd7a2Ssjelinek return (found); 3073e1bd7a2Ssjelinek } 3083e1bd7a2Ssjelinek if (slices == NULL) 3093e1bd7a2Ssjelinek return (found); 3103e1bd7a2Ssjelinek 3113e1bd7a2Ssjelinek for (i = 0; slices[i] != NULL; i++) { 3123e1bd7a2Ssjelinek /* 3133e1bd7a2Ssjelinek * If we are checking the whole disk 3143e1bd7a2Ssjelinek * then any and all in use data is 3153e1bd7a2Ssjelinek * relevant. 3163e1bd7a2Ssjelinek */ 3173e1bd7a2Ssjelinek if (start == UINT_MAX64) { 3183e1bd7a2Ssjelinek name = dm_get_name(slices[i], &error); 3193e1bd7a2Ssjelinek if (error != 0 || !name) { 3203e1bd7a2Ssjelinek err_print("Error occurred with device " 3213e1bd7a2Ssjelinek "in use checking: %s\n", 3223e1bd7a2Ssjelinek strerror(error)); 3233e1bd7a2Ssjelinek continue; 3243e1bd7a2Ssjelinek } 3253e1bd7a2Ssjelinek if (dm_inuse(name, &usage, DM_WHO_FORMAT, &error) || 3263e1bd7a2Ssjelinek error) { 3273e1bd7a2Ssjelinek if (error != 0) { 3283e1bd7a2Ssjelinek dm_free_name(name); 3293e1bd7a2Ssjelinek name = NULL; 3303e1bd7a2Ssjelinek err_print("Error occurred with device " 3313e1bd7a2Ssjelinek "in use checking: %s\n", 3323e1bd7a2Ssjelinek strerror(error)); 3333e1bd7a2Ssjelinek continue; 3343e1bd7a2Ssjelinek } 3353e1bd7a2Ssjelinek dm_free_name(name); 3363e1bd7a2Ssjelinek name = NULL; 3373e1bd7a2Ssjelinek /* 3383e1bd7a2Ssjelinek * If this is a dump device, then it is 3393e1bd7a2Ssjelinek * a failure. You cannot format a slice 3403e1bd7a2Ssjelinek * that is a dedicated dump device. 3413e1bd7a2Ssjelinek */ 3423e1bd7a2Ssjelinek 3433e1bd7a2Ssjelinek if (strstr(usage, DM_USE_DUMP)) { 3443e1bd7a2Ssjelinek if (print) { 3453e1bd7a2Ssjelinek err_print(usage); 3463e1bd7a2Ssjelinek free(usage); 3473e1bd7a2Ssjelinek } 3483e1bd7a2Ssjelinek dm_free_descriptors(slices); 3493e1bd7a2Ssjelinek return (1); 3503e1bd7a2Ssjelinek } 3513e1bd7a2Ssjelinek /* 3523e1bd7a2Ssjelinek * We really found a device that is in use. 3533e1bd7a2Ssjelinek * Set 'found' for the return value, and set 3543e1bd7a2Ssjelinek * 'check' to indicate below that we must 3553e1bd7a2Ssjelinek * get the partition number to set bm_inuse 3563e1bd7a2Ssjelinek * in the event we are trying to label this 3573e1bd7a2Ssjelinek * device. check_label is set when we are 3583e1bd7a2Ssjelinek * checking modifications for in use slices 3593e1bd7a2Ssjelinek * on the device. 3603e1bd7a2Ssjelinek */ 3613e1bd7a2Ssjelinek found ++; 3623e1bd7a2Ssjelinek check = 1; 3633e1bd7a2Ssjelinek if (print) { 3643e1bd7a2Ssjelinek err_print(usage); 3653e1bd7a2Ssjelinek free(usage); 3663e1bd7a2Ssjelinek } 3673e1bd7a2Ssjelinek } 3683e1bd7a2Ssjelinek } else { 3693e1bd7a2Ssjelinek /* 3703e1bd7a2Ssjelinek * Before getting the in use data, verify that the 3713e1bd7a2Ssjelinek * current slice is within the range we are checking. 3723e1bd7a2Ssjelinek */ 3733e1bd7a2Ssjelinek attrs = dm_get_attributes(slices[i], &error); 3743e1bd7a2Ssjelinek if (error) { 3753e1bd7a2Ssjelinek err_print("Error occurred with device in use " 3763e1bd7a2Ssjelinek "checking: %s\n", strerror(error)); 3773e1bd7a2Ssjelinek continue; 3783e1bd7a2Ssjelinek } 3793e1bd7a2Ssjelinek if (attrs == NULL) { 3803e1bd7a2Ssjelinek continue; 3813e1bd7a2Ssjelinek } 3823e1bd7a2Ssjelinek 3833e1bd7a2Ssjelinek (void) nvlist_lookup_uint64(attrs, DM_START, 3843e1bd7a2Ssjelinek &slice_start); 3853e1bd7a2Ssjelinek (void) nvlist_lookup_uint64(attrs, DM_SIZE, 3863e1bd7a2Ssjelinek &slice_size); 3873e1bd7a2Ssjelinek if (start >= (slice_start + slice_size) || 3883e1bd7a2Ssjelinek (end < slice_start)) { 3893e1bd7a2Ssjelinek nvlist_free(attrs); 3903e1bd7a2Ssjelinek attrs = NULL; 3913e1bd7a2Ssjelinek continue; 3923e1bd7a2Ssjelinek } 3933e1bd7a2Ssjelinek name = dm_get_name(slices[i], &error); 3943e1bd7a2Ssjelinek if (error != 0 || !name) { 3953e1bd7a2Ssjelinek err_print("Error occurred with device " 3963e1bd7a2Ssjelinek "in use checking: %s\n", 3973e1bd7a2Ssjelinek strerror(error)); 3983e1bd7a2Ssjelinek nvlist_free(attrs); 3993e1bd7a2Ssjelinek attrs = NULL; 4003e1bd7a2Ssjelinek continue; 4013e1bd7a2Ssjelinek } 4023e1bd7a2Ssjelinek if (dm_inuse(name, &usage, 4033e1bd7a2Ssjelinek DM_WHO_FORMAT, &error) || error) { 4043e1bd7a2Ssjelinek if (error != 0) { 4053e1bd7a2Ssjelinek dm_free_name(name); 4063e1bd7a2Ssjelinek name = NULL; 4073e1bd7a2Ssjelinek err_print("Error occurred with device " 4083e1bd7a2Ssjelinek "in use checking: %s\n", 4093e1bd7a2Ssjelinek strerror(error)); 4103e1bd7a2Ssjelinek nvlist_free(attrs); 4113e1bd7a2Ssjelinek attrs = NULL; 4123e1bd7a2Ssjelinek continue; 4133e1bd7a2Ssjelinek } 4143e1bd7a2Ssjelinek dm_free_name(name); 4153e1bd7a2Ssjelinek name = NULL; 4163e1bd7a2Ssjelinek /* 4173e1bd7a2Ssjelinek * If this is a dump device, then it is 4183e1bd7a2Ssjelinek * a failure. You cannot format a slice 4193e1bd7a2Ssjelinek * that is a dedicated dump device. 4203e1bd7a2Ssjelinek */ 4213e1bd7a2Ssjelinek if (strstr(usage, DM_USE_DUMP)) { 4223e1bd7a2Ssjelinek if (print) { 4233e1bd7a2Ssjelinek err_print(usage); 4243e1bd7a2Ssjelinek free(usage); 4253e1bd7a2Ssjelinek } 4263e1bd7a2Ssjelinek dm_free_descriptors(slices); 4273e1bd7a2Ssjelinek nvlist_free(attrs); 4283e1bd7a2Ssjelinek return (1); 4293e1bd7a2Ssjelinek } 4303e1bd7a2Ssjelinek /* 4313e1bd7a2Ssjelinek * We really found a device that is in use. 4323e1bd7a2Ssjelinek * Set 'found' for the return value, and set 4333e1bd7a2Ssjelinek * 'check' to indicate below that we must 4343e1bd7a2Ssjelinek * get the partition number to set bm_inuse 4353e1bd7a2Ssjelinek * in the event we are trying to label this 4363e1bd7a2Ssjelinek * device. check_label is set when we are 4373e1bd7a2Ssjelinek * checking modifications for in use slices 4383e1bd7a2Ssjelinek * on the device. 4393e1bd7a2Ssjelinek */ 4403e1bd7a2Ssjelinek found ++; 4413e1bd7a2Ssjelinek check = 1; 4423e1bd7a2Ssjelinek if (print) { 4433e1bd7a2Ssjelinek err_print(usage); 4443e1bd7a2Ssjelinek free(usage); 4453e1bd7a2Ssjelinek } 4463e1bd7a2Ssjelinek } 4473e1bd7a2Ssjelinek } 4483e1bd7a2Ssjelinek /* 4493e1bd7a2Ssjelinek * If check is set it means we found a slice(the current slice) 4503e1bd7a2Ssjelinek * on this device in use in some way. We potentially want 4513e1bd7a2Ssjelinek * to check this slice when labeling is 4523e1bd7a2Ssjelinek * requested. We set bm_inuse with this partition value 4533e1bd7a2Ssjelinek * for use later if check_label was set when called. 4543e1bd7a2Ssjelinek */ 4553e1bd7a2Ssjelinek if (check) { 4563e1bd7a2Ssjelinek name = dm_get_name(slices[i], &error); 4573e1bd7a2Ssjelinek if (error != 0 || !name) { 4583e1bd7a2Ssjelinek err_print("Error occurred with device " 4593e1bd7a2Ssjelinek "in use checking: %s\n", 4603e1bd7a2Ssjelinek strerror(error)); 4613e1bd7a2Ssjelinek nvlist_free(attrs); 4623e1bd7a2Ssjelinek attrs = NULL; 4633e1bd7a2Ssjelinek continue; 4643e1bd7a2Ssjelinek } 4653e1bd7a2Ssjelinek part = getpartition(name); 4663e1bd7a2Ssjelinek dm_free_name(name); 4673e1bd7a2Ssjelinek name = NULL; 4683e1bd7a2Ssjelinek if (part != -1) { 4693e1bd7a2Ssjelinek bm_inuse |= 1 << part; 4703e1bd7a2Ssjelinek } 4713e1bd7a2Ssjelinek check = 0; 4723e1bd7a2Ssjelinek } 4733e1bd7a2Ssjelinek /* 4743e1bd7a2Ssjelinek * If we have attributes then we have successfully 4753e1bd7a2Ssjelinek * found the slice we were looking for and we also 4763e1bd7a2Ssjelinek * know this means we are not searching the whole 4773e1bd7a2Ssjelinek * disk so break out of the loop 4783e1bd7a2Ssjelinek * now. 4793e1bd7a2Ssjelinek */ 4803e1bd7a2Ssjelinek if (attrs) { 4813e1bd7a2Ssjelinek nvlist_free(attrs); 4823e1bd7a2Ssjelinek break; 4833e1bd7a2Ssjelinek } 4843e1bd7a2Ssjelinek } 4853e1bd7a2Ssjelinek 4863e1bd7a2Ssjelinek if (slices) { 4873e1bd7a2Ssjelinek dm_free_descriptors(slices); 4883e1bd7a2Ssjelinek } 4893e1bd7a2Ssjelinek 4903e1bd7a2Ssjelinek /* 4913e1bd7a2Ssjelinek * The user is trying to label the disk. We have to do special 4923e1bd7a2Ssjelinek * checking here to ensure they are not trying to modify a slice 4933e1bd7a2Ssjelinek * that is in use in an incompatible way. 4943e1bd7a2Ssjelinek */ 4953e1bd7a2Ssjelinek if (check_label && bm_inuse) { 4963e1bd7a2Ssjelinek /* 4973e1bd7a2Ssjelinek * !0 indicates that we found a 4983e1bd7a2Ssjelinek * problem. In this case, we have overloaded 4993e1bd7a2Ssjelinek * the use of checkpartitions to work for 5003e1bd7a2Ssjelinek * in use devices. bm_inuse is representative 5013e1bd7a2Ssjelinek * of the slice that is in use, not that 5023e1bd7a2Ssjelinek * is mounted as is in the case of the normal 5033e1bd7a2Ssjelinek * use of checkpartitions. 5043e1bd7a2Ssjelinek * 5053e1bd7a2Ssjelinek * The call to checkpartitions will return !0 if 5063e1bd7a2Ssjelinek * we are trying to shrink a device that we have found 5073e1bd7a2Ssjelinek * to be in use above. 5083e1bd7a2Ssjelinek */ 5093e1bd7a2Ssjelinek return (checkpartitions(bm_inuse)); 5103e1bd7a2Ssjelinek } 5113e1bd7a2Ssjelinek 5123e1bd7a2Ssjelinek return (found); 5133e1bd7a2Ssjelinek } 5143e1bd7a2Ssjelinek /* 5153e1bd7a2Ssjelinek * This routine checks to see if there are mounted partitions overlapping 5163e1bd7a2Ssjelinek * a given portion of a disk. If the start parameter is < 0, it means 5173e1bd7a2Ssjelinek * that the entire disk should be checked. 5183e1bd7a2Ssjelinek */ 5193e1bd7a2Ssjelinek int 5203e1bd7a2Ssjelinek checkmount(start, end) 5213e1bd7a2Ssjelinek diskaddr_t start, end; 5223e1bd7a2Ssjelinek { 5233e1bd7a2Ssjelinek FILE *fp; 5243e1bd7a2Ssjelinek int found = 0; 5253e1bd7a2Ssjelinek struct dk_map32 *map; 5263e1bd7a2Ssjelinek int part; 5273e1bd7a2Ssjelinek struct mnttab mnt_record; 5283e1bd7a2Ssjelinek struct mnttab *mp = &mnt_record; 5293e1bd7a2Ssjelinek 5303e1bd7a2Ssjelinek /* 5313e1bd7a2Ssjelinek * If we are only checking part of the disk, the disk must 5323e1bd7a2Ssjelinek * have a partition map to check against. If it doesn't, 5333e1bd7a2Ssjelinek * we hope for the best. 5343e1bd7a2Ssjelinek */ 5353e1bd7a2Ssjelinek if (cur_parts == NULL) 5363e1bd7a2Ssjelinek return (0); 5373e1bd7a2Ssjelinek 5383e1bd7a2Ssjelinek /* 5393e1bd7a2Ssjelinek * Lock out interrupts because of the mntent protocol. 5403e1bd7a2Ssjelinek */ 5413e1bd7a2Ssjelinek enter_critical(); 5423e1bd7a2Ssjelinek /* 5433e1bd7a2Ssjelinek * Open the mount table. 5443e1bd7a2Ssjelinek */ 5453e1bd7a2Ssjelinek fp = fopen(MNTTAB, "r"); 5463e1bd7a2Ssjelinek if (fp == NULL) { 5473e1bd7a2Ssjelinek err_print("Unable to open mount table.\n"); 5483e1bd7a2Ssjelinek fullabort(); 5493e1bd7a2Ssjelinek } 5503e1bd7a2Ssjelinek /* 5513e1bd7a2Ssjelinek * Loop through the mount table until we run out of entries. 5523e1bd7a2Ssjelinek */ 5533e1bd7a2Ssjelinek while ((getmntent(fp, mp)) != -1) { 5543e1bd7a2Ssjelinek 5553e1bd7a2Ssjelinek if ((part = getpartition(mp->mnt_special)) == -1) 5563e1bd7a2Ssjelinek continue; 5573e1bd7a2Ssjelinek 5583e1bd7a2Ssjelinek /* 5593e1bd7a2Ssjelinek * It's a mount on the disk we're checking. If we are 5603e1bd7a2Ssjelinek * checking whole disk, then we found trouble. We can 5613e1bd7a2Ssjelinek * quit searching. 5623e1bd7a2Ssjelinek */ 5633e1bd7a2Ssjelinek if (start == UINT_MAX64) { 5643e1bd7a2Ssjelinek found = -1; 5653e1bd7a2Ssjelinek break; 5663e1bd7a2Ssjelinek } 5673e1bd7a2Ssjelinek 5683e1bd7a2Ssjelinek /* 5693e1bd7a2Ssjelinek * If the partition overlaps the zone we're checking, 5703e1bd7a2Ssjelinek * then we found trouble. We can quit searching. 5713e1bd7a2Ssjelinek */ 5723e1bd7a2Ssjelinek map = &cur_parts->pinfo_map[part]; 5733e1bd7a2Ssjelinek if ((start >= (int)(map->dkl_cylno * spc() + map->dkl_nblk)) || 5743e1bd7a2Ssjelinek (end < (int)(map->dkl_cylno * spc()))) { 5753e1bd7a2Ssjelinek continue; 5763e1bd7a2Ssjelinek } 5773e1bd7a2Ssjelinek found = -1; 5783e1bd7a2Ssjelinek break; 5793e1bd7a2Ssjelinek } 5803e1bd7a2Ssjelinek /* 5813e1bd7a2Ssjelinek * Close down the mount table. 5823e1bd7a2Ssjelinek */ 5833e1bd7a2Ssjelinek (void) fclose(fp); 5843e1bd7a2Ssjelinek exit_critical(); 5853e1bd7a2Ssjelinek 5863e1bd7a2Ssjelinek /* 5873e1bd7a2Ssjelinek * If we found trouble and we're running from a command file, 5883e1bd7a2Ssjelinek * quit before doing something we really regret. 5893e1bd7a2Ssjelinek */ 5903e1bd7a2Ssjelinek 5913e1bd7a2Ssjelinek if (found && option_f) { 5923e1bd7a2Ssjelinek err_print("Operation on mounted disks must be interactive.\n"); 5933e1bd7a2Ssjelinek cmdabort(SIGINT); 5943e1bd7a2Ssjelinek } 5953e1bd7a2Ssjelinek /* 5963e1bd7a2Ssjelinek * Return the result. 5973e1bd7a2Ssjelinek */ 5983e1bd7a2Ssjelinek return (found); 5993e1bd7a2Ssjelinek } 6003e1bd7a2Ssjelinek 6013e1bd7a2Ssjelinek int 6023e1bd7a2Ssjelinek check_label_with_swap() 6033e1bd7a2Ssjelinek { 6043e1bd7a2Ssjelinek int i; 6053e1bd7a2Ssjelinek struct swaptable *st; 6063e1bd7a2Ssjelinek struct swapent *swapent; 6073e1bd7a2Ssjelinek int part; 6083e1bd7a2Ssjelinek int bm_swap = 0; 6093e1bd7a2Ssjelinek 6103e1bd7a2Ssjelinek /* 6113e1bd7a2Ssjelinek * If we are only checking part of the disk, the disk must 6123e1bd7a2Ssjelinek * have a partition map to check against. If it doesn't, 6133e1bd7a2Ssjelinek * we hope for the best. 6143e1bd7a2Ssjelinek */ 6153e1bd7a2Ssjelinek if (cur_parts == NULL) 6163e1bd7a2Ssjelinek return (0); /* Will be checked later */ 6173e1bd7a2Ssjelinek 6183e1bd7a2Ssjelinek /* 6193e1bd7a2Ssjelinek * Check for swap entries 6203e1bd7a2Ssjelinek */ 6213e1bd7a2Ssjelinek st = getswapentries(); 6223e1bd7a2Ssjelinek /* 6233e1bd7a2Ssjelinek * if there are no swap entries return. 6243e1bd7a2Ssjelinek */ 6253e1bd7a2Ssjelinek if (st == (struct swaptable *)NULL) 6263e1bd7a2Ssjelinek return (0); 6273e1bd7a2Ssjelinek swapent = st->swt_ent; 6283e1bd7a2Ssjelinek for (i = 0; i < st->swt_n; i++, swapent++) 6293e1bd7a2Ssjelinek if ((part = getpartition(swapent->ste_path)) != -1) 6303e1bd7a2Ssjelinek bm_swap |= (1 << part); 6313e1bd7a2Ssjelinek freeswapentries(st); 6323e1bd7a2Ssjelinek 6333e1bd7a2Ssjelinek return (checkpartitions(bm_swap)); 6343e1bd7a2Ssjelinek } 6353e1bd7a2Ssjelinek 6363e1bd7a2Ssjelinek /* 6373e1bd7a2Ssjelinek * Check the new label with the existing label on the disk, 6383e1bd7a2Ssjelinek * to make sure that any mounted partitions are not being 6393e1bd7a2Ssjelinek * affected by writing the new label. 6403e1bd7a2Ssjelinek */ 6413e1bd7a2Ssjelinek int 6423e1bd7a2Ssjelinek check_label_with_mount() 6433e1bd7a2Ssjelinek { 6443e1bd7a2Ssjelinek FILE *fp; 6453e1bd7a2Ssjelinek int part; 6463e1bd7a2Ssjelinek struct mnttab mnt_record; 6473e1bd7a2Ssjelinek struct mnttab *mp = &mnt_record; 6483e1bd7a2Ssjelinek int bm_mounted = 0; 6493e1bd7a2Ssjelinek 6503e1bd7a2Ssjelinek 6513e1bd7a2Ssjelinek /* 6523e1bd7a2Ssjelinek * If we are only checking part of the disk, the disk must 6533e1bd7a2Ssjelinek * have a partition map to check against. If it doesn't, 6543e1bd7a2Ssjelinek * we hope for the best. 6553e1bd7a2Ssjelinek */ 6563e1bd7a2Ssjelinek if (cur_parts == NULL) 6573e1bd7a2Ssjelinek return (0); /* Will be checked later */ 6583e1bd7a2Ssjelinek 6593e1bd7a2Ssjelinek /* 6603e1bd7a2Ssjelinek * Lock out interrupts because of the mntent protocol. 6613e1bd7a2Ssjelinek */ 6623e1bd7a2Ssjelinek enter_critical(); 6633e1bd7a2Ssjelinek /* 6643e1bd7a2Ssjelinek * Open the mount table. 6653e1bd7a2Ssjelinek */ 6663e1bd7a2Ssjelinek fp = fopen(MNTTAB, "r"); 6673e1bd7a2Ssjelinek if (fp == NULL) { 6683e1bd7a2Ssjelinek err_print("Unable to open mount table.\n"); 6693e1bd7a2Ssjelinek fullabort(); 6703e1bd7a2Ssjelinek } 6713e1bd7a2Ssjelinek /* 6723e1bd7a2Ssjelinek * Loop through the mount table until we run out of entries. 6733e1bd7a2Ssjelinek */ 6743e1bd7a2Ssjelinek while ((getmntent(fp, mp)) != -1) { 6753e1bd7a2Ssjelinek if ((part = getpartition(mp->mnt_special)) != -1) 6763e1bd7a2Ssjelinek bm_mounted |= (1 << part); 6773e1bd7a2Ssjelinek } 6783e1bd7a2Ssjelinek /* 6793e1bd7a2Ssjelinek * Close down the mount table. 6803e1bd7a2Ssjelinek */ 6813e1bd7a2Ssjelinek (void) fclose(fp); 6823e1bd7a2Ssjelinek exit_critical(); 6833e1bd7a2Ssjelinek 6843e1bd7a2Ssjelinek return (checkpartitions(bm_mounted)); 6853e1bd7a2Ssjelinek 6863e1bd7a2Ssjelinek } 6873e1bd7a2Ssjelinek 6883e1bd7a2Ssjelinek /* 6893e1bd7a2Ssjelinek * This Routine checks if any partitions specified 6903e1bd7a2Ssjelinek * are affected by writing the new label 6913e1bd7a2Ssjelinek */ 6923e1bd7a2Ssjelinek static int 6933e1bd7a2Ssjelinek checkpartitions(int bm_mounted) 6943e1bd7a2Ssjelinek { 6953e1bd7a2Ssjelinek struct dk_map32 *n; 6963e1bd7a2Ssjelinek struct dk_map *o; 6973e1bd7a2Ssjelinek struct dk_allmap old_map; 6983e1bd7a2Ssjelinek int i, found = 0; 6993e1bd7a2Ssjelinek 7003e1bd7a2Ssjelinek /* 7013e1bd7a2Ssjelinek * Now we need to check that the current partition list and the 7023e1bd7a2Ssjelinek * previous partition list (which there must be if we actually 7033e1bd7a2Ssjelinek * have partitions mounted) overlap in any way on the mounted 7043e1bd7a2Ssjelinek * partitions 7053e1bd7a2Ssjelinek */ 7063e1bd7a2Ssjelinek 7073e1bd7a2Ssjelinek /* 7083e1bd7a2Ssjelinek * Get the "real" (on-disk) version of the partition table 7093e1bd7a2Ssjelinek */ 7103e1bd7a2Ssjelinek if (ioctl(cur_file, DKIOCGAPART, &old_map) == -1) { 7113e1bd7a2Ssjelinek err_print("Unable to get current partition map.\n"); 7123e1bd7a2Ssjelinek return (-1); 7133e1bd7a2Ssjelinek } 7143e1bd7a2Ssjelinek for (i = 0; i < NDKMAP; i++) { 7153e1bd7a2Ssjelinek if (bm_mounted & (1 << i)) { 7163e1bd7a2Ssjelinek /* 7173e1bd7a2Ssjelinek * This partition is mounted 7183e1bd7a2Ssjelinek */ 7193e1bd7a2Ssjelinek o = &old_map.dka_map[i]; 7203e1bd7a2Ssjelinek n = &cur_parts->pinfo_map[i]; 7213e1bd7a2Ssjelinek #ifdef DEBUG 7223e1bd7a2Ssjelinek fmt_print( 7233e1bd7a2Ssjelinek "checkpartitions :checking partition '%c' \n", i + PARTITION_BASE); 7243e1bd7a2Ssjelinek #endif 7253e1bd7a2Ssjelinek /* 7263e1bd7a2Ssjelinek * If partition is identical, we're fine. 7273e1bd7a2Ssjelinek * If the partition grows, we're also fine, because 7283e1bd7a2Ssjelinek * the routines in partition.c check for overflow. 7293e1bd7a2Ssjelinek * It will (ultimately) be up to the routines in 7303e1bd7a2Ssjelinek * partition.c to warn about creation of overlapping 7313e1bd7a2Ssjelinek * partitions 7323e1bd7a2Ssjelinek */ 7333e1bd7a2Ssjelinek if (o->dkl_cylno == n->dkl_cylno && 7343e1bd7a2Ssjelinek o->dkl_nblk <= n->dkl_nblk) { 7353e1bd7a2Ssjelinek #ifdef DEBUG 7363e1bd7a2Ssjelinek if (o->dkl_nblk < n->dkl_nblk) { 7373e1bd7a2Ssjelinek fmt_print( 7383e1bd7a2Ssjelinek "- new partition larger by %d blocks", n->dkl_nblk-o->dkl_nblk); 7393e1bd7a2Ssjelinek } 7403e1bd7a2Ssjelinek fmt_print("\n"); 7413e1bd7a2Ssjelinek #endif 7423e1bd7a2Ssjelinek continue; 7433e1bd7a2Ssjelinek } 7443e1bd7a2Ssjelinek #ifdef DEBUG 7453e1bd7a2Ssjelinek fmt_print("- changes; old (%d,%d)->new (%d,%d)\n", 7463e1bd7a2Ssjelinek o->dkl_cylno, o->dkl_nblk, n->dkl_cylno, 7473e1bd7a2Ssjelinek n->dkl_nblk); 7483e1bd7a2Ssjelinek #endif 7493e1bd7a2Ssjelinek found = -1; 7503e1bd7a2Ssjelinek } 7513e1bd7a2Ssjelinek if (found) 7523e1bd7a2Ssjelinek break; 7533e1bd7a2Ssjelinek } 7543e1bd7a2Ssjelinek 7553e1bd7a2Ssjelinek /* 7563e1bd7a2Ssjelinek * If we found trouble and we're running from a command file, 7573e1bd7a2Ssjelinek * quit before doing something we really regret. 7583e1bd7a2Ssjelinek */ 7593e1bd7a2Ssjelinek 7603e1bd7a2Ssjelinek if (found && option_f) { 7613e1bd7a2Ssjelinek err_print("Operation on mounted disks or \ 7623e1bd7a2Ssjelinek disks currently being used for swapping must be interactive.\n"); 7633e1bd7a2Ssjelinek cmdabort(SIGINT); 7643e1bd7a2Ssjelinek } 7653e1bd7a2Ssjelinek /* 7663e1bd7a2Ssjelinek * Return the result. 7673e1bd7a2Ssjelinek */ 7683e1bd7a2Ssjelinek return (found); 7693e1bd7a2Ssjelinek } 770