1*3e1bd7a2Ssjelinek /* 2*3e1bd7a2Ssjelinek * CDDL HEADER START 3*3e1bd7a2Ssjelinek * 4*3e1bd7a2Ssjelinek * The contents of this file are subject to the terms of the 5*3e1bd7a2Ssjelinek * Common Development and Distribution License, Version 1.0 only 6*3e1bd7a2Ssjelinek * (the "License"). You may not use this file except in compliance 7*3e1bd7a2Ssjelinek * with the License. 8*3e1bd7a2Ssjelinek * 9*3e1bd7a2Ssjelinek * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*3e1bd7a2Ssjelinek * or http://www.opensolaris.org/os/licensing. 11*3e1bd7a2Ssjelinek * See the License for the specific language governing permissions 12*3e1bd7a2Ssjelinek * and limitations under the License. 13*3e1bd7a2Ssjelinek * 14*3e1bd7a2Ssjelinek * When distributing Covered Code, include this CDDL HEADER in each 15*3e1bd7a2Ssjelinek * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*3e1bd7a2Ssjelinek * If applicable, add the following below this CDDL HEADER, with the 17*3e1bd7a2Ssjelinek * fields enclosed by brackets "[]" replaced with your own identifying 18*3e1bd7a2Ssjelinek * information: Portions Copyright [yyyy] [name of copyright owner] 19*3e1bd7a2Ssjelinek * 20*3e1bd7a2Ssjelinek * CDDL HEADER END 21*3e1bd7a2Ssjelinek */ 22*3e1bd7a2Ssjelinek /* 23*3e1bd7a2Ssjelinek * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*3e1bd7a2Ssjelinek * Use is subject to license terms. 25*3e1bd7a2Ssjelinek */ 26*3e1bd7a2Ssjelinek 27*3e1bd7a2Ssjelinek 28*3e1bd7a2Ssjelinek #pragma ident "%Z%%M% %I% %E% SMI" 29*3e1bd7a2Ssjelinek 30*3e1bd7a2Ssjelinek /* 31*3e1bd7a2Ssjelinek * This file contains miscellaneous device validation routines. 32*3e1bd7a2Ssjelinek */ 33*3e1bd7a2Ssjelinek 34*3e1bd7a2Ssjelinek #include "global.h" 35*3e1bd7a2Ssjelinek #include <sys/mnttab.h> 36*3e1bd7a2Ssjelinek #include <sys/mntent.h> 37*3e1bd7a2Ssjelinek #include <sys/autoconf.h> 38*3e1bd7a2Ssjelinek 39*3e1bd7a2Ssjelinek #include <signal.h> 40*3e1bd7a2Ssjelinek #include <malloc.h> 41*3e1bd7a2Ssjelinek #include <unistd.h> 42*3e1bd7a2Ssjelinek #include <string.h> 43*3e1bd7a2Ssjelinek #include <errno.h> 44*3e1bd7a2Ssjelinek #include <fcntl.h> 45*3e1bd7a2Ssjelinek #include <sys/ioctl.h> 46*3e1bd7a2Ssjelinek #include <sys/fcntl.h> 47*3e1bd7a2Ssjelinek #include <sys/stat.h> 48*3e1bd7a2Ssjelinek #include <sys/swap.h> 49*3e1bd7a2Ssjelinek #include <sys/sysmacros.h> 50*3e1bd7a2Ssjelinek #include <ctype.h> 51*3e1bd7a2Ssjelinek #include <libdiskmgt.h> 52*3e1bd7a2Ssjelinek #include <libnvpair.h> 53*3e1bd7a2Ssjelinek #include "misc.h" 54*3e1bd7a2Ssjelinek #include "checkdev.h" 55*3e1bd7a2Ssjelinek 56*3e1bd7a2Ssjelinek /* Function prototypes */ 57*3e1bd7a2Ssjelinek #ifdef __STDC__ 58*3e1bd7a2Ssjelinek 59*3e1bd7a2Ssjelinek static struct swaptable *getswapentries(void); 60*3e1bd7a2Ssjelinek static void freeswapentries(struct swaptable *); 61*3e1bd7a2Ssjelinek static int getpartition(char *pathname); 62*3e1bd7a2Ssjelinek static int checkpartitions(int bm_mounted); 63*3e1bd7a2Ssjelinek 64*3e1bd7a2Ssjelinek #else /* __STDC__ */ 65*3e1bd7a2Ssjelinek 66*3e1bd7a2Ssjelinek static struct swaptable *getswapentries(); 67*3e1bd7a2Ssjelinek static void freeswapentries(); 68*3e1bd7a2Ssjelinek static int getpartition(); 69*3e1bd7a2Ssjelinek static int checkpartitions(); 70*3e1bd7a2Ssjelinek 71*3e1bd7a2Ssjelinek #endif /* __STDC__ */ 72*3e1bd7a2Ssjelinek 73*3e1bd7a2Ssjelinek extern char *getfullname(); 74*3e1bd7a2Ssjelinek 75*3e1bd7a2Ssjelinek static struct swaptable * 76*3e1bd7a2Ssjelinek getswapentries(void) 77*3e1bd7a2Ssjelinek { 78*3e1bd7a2Ssjelinek register struct swaptable *st; 79*3e1bd7a2Ssjelinek register struct swapent *swapent; 80*3e1bd7a2Ssjelinek int i, num; 81*3e1bd7a2Ssjelinek char fullpathname[MAXPATHLEN]; 82*3e1bd7a2Ssjelinek 83*3e1bd7a2Ssjelinek /* 84*3e1bd7a2Ssjelinek * get the number of swap entries 85*3e1bd7a2Ssjelinek */ 86*3e1bd7a2Ssjelinek if ((num = swapctl(SC_GETNSWP, (void *)NULL)) == -1) { 87*3e1bd7a2Ssjelinek err_print("swapctl error "); 88*3e1bd7a2Ssjelinek fullabort(); 89*3e1bd7a2Ssjelinek } 90*3e1bd7a2Ssjelinek if (num == 0) 91*3e1bd7a2Ssjelinek return (NULL); 92*3e1bd7a2Ssjelinek if ((st = (swaptbl_t *)malloc(num * sizeof (swapent_t) + sizeof (int))) 93*3e1bd7a2Ssjelinek == NULL) { 94*3e1bd7a2Ssjelinek err_print("getswapentries: malloc failed.\n"); 95*3e1bd7a2Ssjelinek fullabort(); 96*3e1bd7a2Ssjelinek } 97*3e1bd7a2Ssjelinek swapent = st->swt_ent; 98*3e1bd7a2Ssjelinek for (i = 0; i < num; i++, swapent++) { 99*3e1bd7a2Ssjelinek if ((swapent->ste_path = malloc(MAXPATHLEN)) == NULL) { 100*3e1bd7a2Ssjelinek err_print("getswapentries: malloc failed.\n"); 101*3e1bd7a2Ssjelinek fullabort(); 102*3e1bd7a2Ssjelinek } 103*3e1bd7a2Ssjelinek } 104*3e1bd7a2Ssjelinek st->swt_n = num; 105*3e1bd7a2Ssjelinek if ((num = swapctl(SC_LIST, (void *)st)) == -1) { 106*3e1bd7a2Ssjelinek err_print("swapctl error "); 107*3e1bd7a2Ssjelinek fullabort(); 108*3e1bd7a2Ssjelinek } 109*3e1bd7a2Ssjelinek swapent = st->swt_ent; 110*3e1bd7a2Ssjelinek for (i = 0; i < num; i++, swapent++) { 111*3e1bd7a2Ssjelinek if (*swapent->ste_path != '/') { 112*3e1bd7a2Ssjelinek (void) snprintf(fullpathname, sizeof (fullpathname), 113*3e1bd7a2Ssjelinek "/dev/%s", swapent->ste_path); 114*3e1bd7a2Ssjelinek (void) strcpy(swapent->ste_path, fullpathname); 115*3e1bd7a2Ssjelinek } 116*3e1bd7a2Ssjelinek } 117*3e1bd7a2Ssjelinek return (st); 118*3e1bd7a2Ssjelinek } 119*3e1bd7a2Ssjelinek 120*3e1bd7a2Ssjelinek static void 121*3e1bd7a2Ssjelinek freeswapentries(st) 122*3e1bd7a2Ssjelinek struct swaptable *st; 123*3e1bd7a2Ssjelinek { 124*3e1bd7a2Ssjelinek register struct swapent *swapent; 125*3e1bd7a2Ssjelinek int i; 126*3e1bd7a2Ssjelinek 127*3e1bd7a2Ssjelinek swapent = st->swt_ent; 128*3e1bd7a2Ssjelinek for (i = 0; i < st->swt_n; i++, swapent++) 129*3e1bd7a2Ssjelinek free(swapent->ste_path); 130*3e1bd7a2Ssjelinek free(st); 131*3e1bd7a2Ssjelinek 132*3e1bd7a2Ssjelinek } 133*3e1bd7a2Ssjelinek 134*3e1bd7a2Ssjelinek /* 135*3e1bd7a2Ssjelinek * function getpartition: 136*3e1bd7a2Ssjelinek */ 137*3e1bd7a2Ssjelinek static int 138*3e1bd7a2Ssjelinek getpartition(pathname) 139*3e1bd7a2Ssjelinek char *pathname; 140*3e1bd7a2Ssjelinek { 141*3e1bd7a2Ssjelinek int mfd; 142*3e1bd7a2Ssjelinek struct dk_cinfo dkinfo; 143*3e1bd7a2Ssjelinek struct stat stbuf; 144*3e1bd7a2Ssjelinek char raw_device[MAXPATHLEN]; 145*3e1bd7a2Ssjelinek int found = -1; 146*3e1bd7a2Ssjelinek 147*3e1bd7a2Ssjelinek /* 148*3e1bd7a2Ssjelinek * Map the block device name to the raw device name. 149*3e1bd7a2Ssjelinek * If it doesn't appear to be a device name, skip it. 150*3e1bd7a2Ssjelinek */ 151*3e1bd7a2Ssjelinek if (match_substr(pathname, "/dev/") == 0) 152*3e1bd7a2Ssjelinek return (found); 153*3e1bd7a2Ssjelinek (void) strcpy(raw_device, "/dev/r"); 154*3e1bd7a2Ssjelinek (void) strcat(raw_device, pathname + strlen("/dev/")); 155*3e1bd7a2Ssjelinek /* 156*3e1bd7a2Ssjelinek * Determine if this appears to be a disk device. 157*3e1bd7a2Ssjelinek * First attempt to open the device. If if fails, skip it. 158*3e1bd7a2Ssjelinek */ 159*3e1bd7a2Ssjelinek if ((mfd = open(raw_device, O_RDWR | O_NDELAY)) < 0) { 160*3e1bd7a2Ssjelinek return (found); 161*3e1bd7a2Ssjelinek } 162*3e1bd7a2Ssjelinek /* 163*3e1bd7a2Ssjelinek * Must be a character device 164*3e1bd7a2Ssjelinek */ 165*3e1bd7a2Ssjelinek if (fstat(mfd, &stbuf) == -1 || !S_ISCHR(stbuf.st_mode)) { 166*3e1bd7a2Ssjelinek (void) close(mfd); 167*3e1bd7a2Ssjelinek return (found); 168*3e1bd7a2Ssjelinek } 169*3e1bd7a2Ssjelinek /* 170*3e1bd7a2Ssjelinek * Attempt to read the configuration info on the disk. 171*3e1bd7a2Ssjelinek */ 172*3e1bd7a2Ssjelinek if (ioctl(mfd, DKIOCINFO, &dkinfo) < 0) { 173*3e1bd7a2Ssjelinek (void) close(mfd); 174*3e1bd7a2Ssjelinek return (found); 175*3e1bd7a2Ssjelinek } 176*3e1bd7a2Ssjelinek /* 177*3e1bd7a2Ssjelinek * Finished with the opened device 178*3e1bd7a2Ssjelinek */ 179*3e1bd7a2Ssjelinek (void) close(mfd); 180*3e1bd7a2Ssjelinek 181*3e1bd7a2Ssjelinek /* 182*3e1bd7a2Ssjelinek * If it's not the disk we're interested in, it doesn't apply. 183*3e1bd7a2Ssjelinek */ 184*3e1bd7a2Ssjelinek if (cur_disk->disk_dkinfo.dki_ctype != dkinfo.dki_ctype || 185*3e1bd7a2Ssjelinek cur_disk->disk_dkinfo.dki_cnum != dkinfo.dki_cnum || 186*3e1bd7a2Ssjelinek cur_disk->disk_dkinfo.dki_unit != dkinfo.dki_unit || 187*3e1bd7a2Ssjelinek strcmp(cur_disk->disk_dkinfo.dki_dname, 188*3e1bd7a2Ssjelinek dkinfo.dki_dname) != 0) { 189*3e1bd7a2Ssjelinek return (found); 190*3e1bd7a2Ssjelinek } 191*3e1bd7a2Ssjelinek 192*3e1bd7a2Ssjelinek /* 193*3e1bd7a2Ssjelinek * Extract the partition that is mounted. 194*3e1bd7a2Ssjelinek */ 195*3e1bd7a2Ssjelinek return (PARTITION(stbuf.st_rdev)); 196*3e1bd7a2Ssjelinek } 197*3e1bd7a2Ssjelinek 198*3e1bd7a2Ssjelinek /* 199*3e1bd7a2Ssjelinek * This Routine checks to see if there are partitions used for swapping overlaps 200*3e1bd7a2Ssjelinek * a given portion of a disk. If the start parameter is < 0, it means 201*3e1bd7a2Ssjelinek * that the entire disk should be checked 202*3e1bd7a2Ssjelinek */ 203*3e1bd7a2Ssjelinek int 204*3e1bd7a2Ssjelinek checkswap(start, end) 205*3e1bd7a2Ssjelinek diskaddr_t start, end; 206*3e1bd7a2Ssjelinek { 207*3e1bd7a2Ssjelinek struct swaptable *st; 208*3e1bd7a2Ssjelinek struct swapent *swapent; 209*3e1bd7a2Ssjelinek int i; 210*3e1bd7a2Ssjelinek int found = 0; 211*3e1bd7a2Ssjelinek struct dk_map32 *map; 212*3e1bd7a2Ssjelinek int part; 213*3e1bd7a2Ssjelinek 214*3e1bd7a2Ssjelinek /* 215*3e1bd7a2Ssjelinek * If we are only checking part of the disk, the disk must 216*3e1bd7a2Ssjelinek * have a partition map to check against. If it doesn't, 217*3e1bd7a2Ssjelinek * we hope for the best. 218*3e1bd7a2Ssjelinek */ 219*3e1bd7a2Ssjelinek if (cur_parts == NULL) 220*3e1bd7a2Ssjelinek return (0); 221*3e1bd7a2Ssjelinek 222*3e1bd7a2Ssjelinek /* 223*3e1bd7a2Ssjelinek * check for swap entries 224*3e1bd7a2Ssjelinek */ 225*3e1bd7a2Ssjelinek st = getswapentries(); 226*3e1bd7a2Ssjelinek /* 227*3e1bd7a2Ssjelinek * if there are no swap entries return. 228*3e1bd7a2Ssjelinek */ 229*3e1bd7a2Ssjelinek if (st == (struct swaptable *)NULL) 230*3e1bd7a2Ssjelinek return (0); 231*3e1bd7a2Ssjelinek swapent = st->swt_ent; 232*3e1bd7a2Ssjelinek for (i = 0; i < st->swt_n; i++, swapent++) { 233*3e1bd7a2Ssjelinek if ((part = getpartition(swapent->ste_path)) != -1) { 234*3e1bd7a2Ssjelinek if (start == UINT_MAX64) { 235*3e1bd7a2Ssjelinek found = -1; 236*3e1bd7a2Ssjelinek break; 237*3e1bd7a2Ssjelinek } 238*3e1bd7a2Ssjelinek map = &cur_parts->pinfo_map[part]; 239*3e1bd7a2Ssjelinek if ((start >= (int)(map->dkl_cylno * spc() + 240*3e1bd7a2Ssjelinek map->dkl_nblk)) || (end < (int)(map->dkl_cylno 241*3e1bd7a2Ssjelinek * spc()))) { 242*3e1bd7a2Ssjelinek continue; 243*3e1bd7a2Ssjelinek } 244*3e1bd7a2Ssjelinek found = -1; 245*3e1bd7a2Ssjelinek break; 246*3e1bd7a2Ssjelinek }; 247*3e1bd7a2Ssjelinek } 248*3e1bd7a2Ssjelinek freeswapentries(st); 249*3e1bd7a2Ssjelinek /* 250*3e1bd7a2Ssjelinek * If we found trouble and we're running from a command file, 251*3e1bd7a2Ssjelinek * quit before doing something we really regret. 252*3e1bd7a2Ssjelinek */ 253*3e1bd7a2Ssjelinek 254*3e1bd7a2Ssjelinek if (found && option_f) { 255*3e1bd7a2Ssjelinek err_print( 256*3e1bd7a2Ssjelinek "Operation on disks being used for swapping must be interactive.\n"); 257*3e1bd7a2Ssjelinek cmdabort(SIGINT); 258*3e1bd7a2Ssjelinek } 259*3e1bd7a2Ssjelinek 260*3e1bd7a2Ssjelinek return (found); 261*3e1bd7a2Ssjelinek 262*3e1bd7a2Ssjelinek 263*3e1bd7a2Ssjelinek } 264*3e1bd7a2Ssjelinek /* 265*3e1bd7a2Ssjelinek * Determines if there are partitions that are a part of an SVM, VxVM, zpool 266*3e1bd7a2Ssjelinek * volume or a live upgrade device, overlapping a given portion of a disk. 267*3e1bd7a2Ssjelinek * Mounts and swap devices are checked in legacy format code. 268*3e1bd7a2Ssjelinek */ 269*3e1bd7a2Ssjelinek int 270*3e1bd7a2Ssjelinek checkdevinuse(char *cur_disk_path, diskaddr_t start, diskaddr_t end, int print, 271*3e1bd7a2Ssjelinek int check_label) 272*3e1bd7a2Ssjelinek { 273*3e1bd7a2Ssjelinek 274*3e1bd7a2Ssjelinek int error; 275*3e1bd7a2Ssjelinek int found = 0; 276*3e1bd7a2Ssjelinek int check = 0; 277*3e1bd7a2Ssjelinek int i; 278*3e1bd7a2Ssjelinek int bm_inuse = 0; 279*3e1bd7a2Ssjelinek int part = 0; 280*3e1bd7a2Ssjelinek uint64_t slice_start, slice_size; 281*3e1bd7a2Ssjelinek dm_descriptor_t *slices = NULL; 282*3e1bd7a2Ssjelinek nvlist_t *attrs = NULL; 283*3e1bd7a2Ssjelinek char *usage; 284*3e1bd7a2Ssjelinek char *name; 285*3e1bd7a2Ssjelinek 286*3e1bd7a2Ssjelinek /* 287*3e1bd7a2Ssjelinek * For format, we get basic 'in use' details from libdiskmgt. After 288*3e1bd7a2Ssjelinek * that we must do the appropriate checking to see if the 'in use' 289*3e1bd7a2Ssjelinek * details require a bit of additional work. 290*3e1bd7a2Ssjelinek */ 291*3e1bd7a2Ssjelinek 292*3e1bd7a2Ssjelinek dm_get_slices(cur_disk_path, &slices, &error); 293*3e1bd7a2Ssjelinek if (error) { 294*3e1bd7a2Ssjelinek err_print("Error occurred with device in use checking: %s\n", 295*3e1bd7a2Ssjelinek strerror(error)); 296*3e1bd7a2Ssjelinek return (found); 297*3e1bd7a2Ssjelinek } 298*3e1bd7a2Ssjelinek if (slices == NULL) 299*3e1bd7a2Ssjelinek return (found); 300*3e1bd7a2Ssjelinek 301*3e1bd7a2Ssjelinek for (i = 0; slices[i] != NULL; i++) { 302*3e1bd7a2Ssjelinek /* 303*3e1bd7a2Ssjelinek * If we are checking the whole disk 304*3e1bd7a2Ssjelinek * then any and all in use data is 305*3e1bd7a2Ssjelinek * relevant. 306*3e1bd7a2Ssjelinek */ 307*3e1bd7a2Ssjelinek if (start == UINT_MAX64) { 308*3e1bd7a2Ssjelinek name = dm_get_name(slices[i], &error); 309*3e1bd7a2Ssjelinek if (error != 0 || !name) { 310*3e1bd7a2Ssjelinek err_print("Error occurred with device " 311*3e1bd7a2Ssjelinek "in use checking: %s\n", 312*3e1bd7a2Ssjelinek strerror(error)); 313*3e1bd7a2Ssjelinek continue; 314*3e1bd7a2Ssjelinek } 315*3e1bd7a2Ssjelinek if (dm_inuse(name, &usage, DM_WHO_FORMAT, &error) || 316*3e1bd7a2Ssjelinek error) { 317*3e1bd7a2Ssjelinek if (error != 0) { 318*3e1bd7a2Ssjelinek dm_free_name(name); 319*3e1bd7a2Ssjelinek name = NULL; 320*3e1bd7a2Ssjelinek err_print("Error occurred with device " 321*3e1bd7a2Ssjelinek "in use checking: %s\n", 322*3e1bd7a2Ssjelinek strerror(error)); 323*3e1bd7a2Ssjelinek continue; 324*3e1bd7a2Ssjelinek } 325*3e1bd7a2Ssjelinek dm_free_name(name); 326*3e1bd7a2Ssjelinek name = NULL; 327*3e1bd7a2Ssjelinek /* 328*3e1bd7a2Ssjelinek * If this is a dump device, then it is 329*3e1bd7a2Ssjelinek * a failure. You cannot format a slice 330*3e1bd7a2Ssjelinek * that is a dedicated dump device. 331*3e1bd7a2Ssjelinek */ 332*3e1bd7a2Ssjelinek 333*3e1bd7a2Ssjelinek if (strstr(usage, DM_USE_DUMP)) { 334*3e1bd7a2Ssjelinek if (print) { 335*3e1bd7a2Ssjelinek err_print(usage); 336*3e1bd7a2Ssjelinek free(usage); 337*3e1bd7a2Ssjelinek } 338*3e1bd7a2Ssjelinek dm_free_descriptors(slices); 339*3e1bd7a2Ssjelinek return (1); 340*3e1bd7a2Ssjelinek } 341*3e1bd7a2Ssjelinek /* 342*3e1bd7a2Ssjelinek * We really found a device that is in use. 343*3e1bd7a2Ssjelinek * Set 'found' for the return value, and set 344*3e1bd7a2Ssjelinek * 'check' to indicate below that we must 345*3e1bd7a2Ssjelinek * get the partition number to set bm_inuse 346*3e1bd7a2Ssjelinek * in the event we are trying to label this 347*3e1bd7a2Ssjelinek * device. check_label is set when we are 348*3e1bd7a2Ssjelinek * checking modifications for in use slices 349*3e1bd7a2Ssjelinek * on the device. 350*3e1bd7a2Ssjelinek */ 351*3e1bd7a2Ssjelinek found ++; 352*3e1bd7a2Ssjelinek check = 1; 353*3e1bd7a2Ssjelinek if (print) { 354*3e1bd7a2Ssjelinek err_print(usage); 355*3e1bd7a2Ssjelinek free(usage); 356*3e1bd7a2Ssjelinek } 357*3e1bd7a2Ssjelinek } 358*3e1bd7a2Ssjelinek } else { 359*3e1bd7a2Ssjelinek /* 360*3e1bd7a2Ssjelinek * Before getting the in use data, verify that the 361*3e1bd7a2Ssjelinek * current slice is within the range we are checking. 362*3e1bd7a2Ssjelinek */ 363*3e1bd7a2Ssjelinek attrs = dm_get_attributes(slices[i], &error); 364*3e1bd7a2Ssjelinek if (error) { 365*3e1bd7a2Ssjelinek err_print("Error occurred with device in use " 366*3e1bd7a2Ssjelinek "checking: %s\n", strerror(error)); 367*3e1bd7a2Ssjelinek continue; 368*3e1bd7a2Ssjelinek } 369*3e1bd7a2Ssjelinek if (attrs == NULL) { 370*3e1bd7a2Ssjelinek continue; 371*3e1bd7a2Ssjelinek } 372*3e1bd7a2Ssjelinek 373*3e1bd7a2Ssjelinek (void) nvlist_lookup_uint64(attrs, DM_START, 374*3e1bd7a2Ssjelinek &slice_start); 375*3e1bd7a2Ssjelinek (void) nvlist_lookup_uint64(attrs, DM_SIZE, 376*3e1bd7a2Ssjelinek &slice_size); 377*3e1bd7a2Ssjelinek if (start >= (slice_start + slice_size) || 378*3e1bd7a2Ssjelinek (end < slice_start)) { 379*3e1bd7a2Ssjelinek nvlist_free(attrs); 380*3e1bd7a2Ssjelinek attrs = NULL; 381*3e1bd7a2Ssjelinek continue; 382*3e1bd7a2Ssjelinek } 383*3e1bd7a2Ssjelinek name = dm_get_name(slices[i], &error); 384*3e1bd7a2Ssjelinek if (error != 0 || !name) { 385*3e1bd7a2Ssjelinek err_print("Error occurred with device " 386*3e1bd7a2Ssjelinek "in use checking: %s\n", 387*3e1bd7a2Ssjelinek strerror(error)); 388*3e1bd7a2Ssjelinek nvlist_free(attrs); 389*3e1bd7a2Ssjelinek attrs = NULL; 390*3e1bd7a2Ssjelinek continue; 391*3e1bd7a2Ssjelinek } 392*3e1bd7a2Ssjelinek if (dm_inuse(name, &usage, 393*3e1bd7a2Ssjelinek DM_WHO_FORMAT, &error) || error) { 394*3e1bd7a2Ssjelinek if (error != 0) { 395*3e1bd7a2Ssjelinek dm_free_name(name); 396*3e1bd7a2Ssjelinek name = NULL; 397*3e1bd7a2Ssjelinek err_print("Error occurred with device " 398*3e1bd7a2Ssjelinek "in use checking: %s\n", 399*3e1bd7a2Ssjelinek strerror(error)); 400*3e1bd7a2Ssjelinek nvlist_free(attrs); 401*3e1bd7a2Ssjelinek attrs = NULL; 402*3e1bd7a2Ssjelinek continue; 403*3e1bd7a2Ssjelinek } 404*3e1bd7a2Ssjelinek dm_free_name(name); 405*3e1bd7a2Ssjelinek name = NULL; 406*3e1bd7a2Ssjelinek /* 407*3e1bd7a2Ssjelinek * If this is a dump device, then it is 408*3e1bd7a2Ssjelinek * a failure. You cannot format a slice 409*3e1bd7a2Ssjelinek * that is a dedicated dump device. 410*3e1bd7a2Ssjelinek */ 411*3e1bd7a2Ssjelinek if (strstr(usage, DM_USE_DUMP)) { 412*3e1bd7a2Ssjelinek if (print) { 413*3e1bd7a2Ssjelinek err_print(usage); 414*3e1bd7a2Ssjelinek free(usage); 415*3e1bd7a2Ssjelinek } 416*3e1bd7a2Ssjelinek dm_free_descriptors(slices); 417*3e1bd7a2Ssjelinek nvlist_free(attrs); 418*3e1bd7a2Ssjelinek return (1); 419*3e1bd7a2Ssjelinek } 420*3e1bd7a2Ssjelinek /* 421*3e1bd7a2Ssjelinek * We really found a device that is in use. 422*3e1bd7a2Ssjelinek * Set 'found' for the return value, and set 423*3e1bd7a2Ssjelinek * 'check' to indicate below that we must 424*3e1bd7a2Ssjelinek * get the partition number to set bm_inuse 425*3e1bd7a2Ssjelinek * in the event we are trying to label this 426*3e1bd7a2Ssjelinek * device. check_label is set when we are 427*3e1bd7a2Ssjelinek * checking modifications for in use slices 428*3e1bd7a2Ssjelinek * on the device. 429*3e1bd7a2Ssjelinek */ 430*3e1bd7a2Ssjelinek found ++; 431*3e1bd7a2Ssjelinek check = 1; 432*3e1bd7a2Ssjelinek if (print) { 433*3e1bd7a2Ssjelinek err_print(usage); 434*3e1bd7a2Ssjelinek free(usage); 435*3e1bd7a2Ssjelinek } 436*3e1bd7a2Ssjelinek } 437*3e1bd7a2Ssjelinek } 438*3e1bd7a2Ssjelinek /* 439*3e1bd7a2Ssjelinek * If check is set it means we found a slice(the current slice) 440*3e1bd7a2Ssjelinek * on this device in use in some way. We potentially want 441*3e1bd7a2Ssjelinek * to check this slice when labeling is 442*3e1bd7a2Ssjelinek * requested. We set bm_inuse with this partition value 443*3e1bd7a2Ssjelinek * for use later if check_label was set when called. 444*3e1bd7a2Ssjelinek */ 445*3e1bd7a2Ssjelinek if (check) { 446*3e1bd7a2Ssjelinek name = dm_get_name(slices[i], &error); 447*3e1bd7a2Ssjelinek if (error != 0 || !name) { 448*3e1bd7a2Ssjelinek err_print("Error occurred with device " 449*3e1bd7a2Ssjelinek "in use checking: %s\n", 450*3e1bd7a2Ssjelinek strerror(error)); 451*3e1bd7a2Ssjelinek nvlist_free(attrs); 452*3e1bd7a2Ssjelinek attrs = NULL; 453*3e1bd7a2Ssjelinek continue; 454*3e1bd7a2Ssjelinek } 455*3e1bd7a2Ssjelinek part = getpartition(name); 456*3e1bd7a2Ssjelinek dm_free_name(name); 457*3e1bd7a2Ssjelinek name = NULL; 458*3e1bd7a2Ssjelinek if (part != -1) { 459*3e1bd7a2Ssjelinek bm_inuse |= 1 << part; 460*3e1bd7a2Ssjelinek } 461*3e1bd7a2Ssjelinek check = 0; 462*3e1bd7a2Ssjelinek } 463*3e1bd7a2Ssjelinek /* 464*3e1bd7a2Ssjelinek * If we have attributes then we have successfully 465*3e1bd7a2Ssjelinek * found the slice we were looking for and we also 466*3e1bd7a2Ssjelinek * know this means we are not searching the whole 467*3e1bd7a2Ssjelinek * disk so break out of the loop 468*3e1bd7a2Ssjelinek * now. 469*3e1bd7a2Ssjelinek */ 470*3e1bd7a2Ssjelinek if (attrs) { 471*3e1bd7a2Ssjelinek nvlist_free(attrs); 472*3e1bd7a2Ssjelinek break; 473*3e1bd7a2Ssjelinek } 474*3e1bd7a2Ssjelinek } 475*3e1bd7a2Ssjelinek 476*3e1bd7a2Ssjelinek if (slices) { 477*3e1bd7a2Ssjelinek dm_free_descriptors(slices); 478*3e1bd7a2Ssjelinek } 479*3e1bd7a2Ssjelinek 480*3e1bd7a2Ssjelinek /* 481*3e1bd7a2Ssjelinek * The user is trying to label the disk. We have to do special 482*3e1bd7a2Ssjelinek * checking here to ensure they are not trying to modify a slice 483*3e1bd7a2Ssjelinek * that is in use in an incompatible way. 484*3e1bd7a2Ssjelinek */ 485*3e1bd7a2Ssjelinek if (check_label && bm_inuse) { 486*3e1bd7a2Ssjelinek /* 487*3e1bd7a2Ssjelinek * !0 indicates that we found a 488*3e1bd7a2Ssjelinek * problem. In this case, we have overloaded 489*3e1bd7a2Ssjelinek * the use of checkpartitions to work for 490*3e1bd7a2Ssjelinek * in use devices. bm_inuse is representative 491*3e1bd7a2Ssjelinek * of the slice that is in use, not that 492*3e1bd7a2Ssjelinek * is mounted as is in the case of the normal 493*3e1bd7a2Ssjelinek * use of checkpartitions. 494*3e1bd7a2Ssjelinek * 495*3e1bd7a2Ssjelinek * The call to checkpartitions will return !0 if 496*3e1bd7a2Ssjelinek * we are trying to shrink a device that we have found 497*3e1bd7a2Ssjelinek * to be in use above. 498*3e1bd7a2Ssjelinek */ 499*3e1bd7a2Ssjelinek return (checkpartitions(bm_inuse)); 500*3e1bd7a2Ssjelinek } 501*3e1bd7a2Ssjelinek 502*3e1bd7a2Ssjelinek return (found); 503*3e1bd7a2Ssjelinek } 504*3e1bd7a2Ssjelinek /* 505*3e1bd7a2Ssjelinek * This routine checks to see if there are mounted partitions overlapping 506*3e1bd7a2Ssjelinek * a given portion of a disk. If the start parameter is < 0, it means 507*3e1bd7a2Ssjelinek * that the entire disk should be checked. 508*3e1bd7a2Ssjelinek */ 509*3e1bd7a2Ssjelinek int 510*3e1bd7a2Ssjelinek checkmount(start, end) 511*3e1bd7a2Ssjelinek diskaddr_t start, end; 512*3e1bd7a2Ssjelinek { 513*3e1bd7a2Ssjelinek FILE *fp; 514*3e1bd7a2Ssjelinek int found = 0; 515*3e1bd7a2Ssjelinek struct dk_map32 *map; 516*3e1bd7a2Ssjelinek int part; 517*3e1bd7a2Ssjelinek struct mnttab mnt_record; 518*3e1bd7a2Ssjelinek struct mnttab *mp = &mnt_record; 519*3e1bd7a2Ssjelinek 520*3e1bd7a2Ssjelinek /* 521*3e1bd7a2Ssjelinek * If we are only checking part of the disk, the disk must 522*3e1bd7a2Ssjelinek * have a partition map to check against. If it doesn't, 523*3e1bd7a2Ssjelinek * we hope for the best. 524*3e1bd7a2Ssjelinek */ 525*3e1bd7a2Ssjelinek if (cur_parts == NULL) 526*3e1bd7a2Ssjelinek return (0); 527*3e1bd7a2Ssjelinek 528*3e1bd7a2Ssjelinek /* 529*3e1bd7a2Ssjelinek * Lock out interrupts because of the mntent protocol. 530*3e1bd7a2Ssjelinek */ 531*3e1bd7a2Ssjelinek enter_critical(); 532*3e1bd7a2Ssjelinek /* 533*3e1bd7a2Ssjelinek * Open the mount table. 534*3e1bd7a2Ssjelinek */ 535*3e1bd7a2Ssjelinek fp = fopen(MNTTAB, "r"); 536*3e1bd7a2Ssjelinek if (fp == NULL) { 537*3e1bd7a2Ssjelinek err_print("Unable to open mount table.\n"); 538*3e1bd7a2Ssjelinek fullabort(); 539*3e1bd7a2Ssjelinek } 540*3e1bd7a2Ssjelinek /* 541*3e1bd7a2Ssjelinek * Loop through the mount table until we run out of entries. 542*3e1bd7a2Ssjelinek */ 543*3e1bd7a2Ssjelinek while ((getmntent(fp, mp)) != -1) { 544*3e1bd7a2Ssjelinek 545*3e1bd7a2Ssjelinek if ((part = getpartition(mp->mnt_special)) == -1) 546*3e1bd7a2Ssjelinek continue; 547*3e1bd7a2Ssjelinek 548*3e1bd7a2Ssjelinek /* 549*3e1bd7a2Ssjelinek * It's a mount on the disk we're checking. If we are 550*3e1bd7a2Ssjelinek * checking whole disk, then we found trouble. We can 551*3e1bd7a2Ssjelinek * quit searching. 552*3e1bd7a2Ssjelinek */ 553*3e1bd7a2Ssjelinek if (start == UINT_MAX64) { 554*3e1bd7a2Ssjelinek found = -1; 555*3e1bd7a2Ssjelinek break; 556*3e1bd7a2Ssjelinek } 557*3e1bd7a2Ssjelinek 558*3e1bd7a2Ssjelinek /* 559*3e1bd7a2Ssjelinek * If the partition overlaps the zone we're checking, 560*3e1bd7a2Ssjelinek * then we found trouble. We can quit searching. 561*3e1bd7a2Ssjelinek */ 562*3e1bd7a2Ssjelinek map = &cur_parts->pinfo_map[part]; 563*3e1bd7a2Ssjelinek if ((start >= (int)(map->dkl_cylno * spc() + map->dkl_nblk)) || 564*3e1bd7a2Ssjelinek (end < (int)(map->dkl_cylno * spc()))) { 565*3e1bd7a2Ssjelinek continue; 566*3e1bd7a2Ssjelinek } 567*3e1bd7a2Ssjelinek found = -1; 568*3e1bd7a2Ssjelinek break; 569*3e1bd7a2Ssjelinek } 570*3e1bd7a2Ssjelinek /* 571*3e1bd7a2Ssjelinek * Close down the mount table. 572*3e1bd7a2Ssjelinek */ 573*3e1bd7a2Ssjelinek (void) fclose(fp); 574*3e1bd7a2Ssjelinek exit_critical(); 575*3e1bd7a2Ssjelinek 576*3e1bd7a2Ssjelinek /* 577*3e1bd7a2Ssjelinek * If we found trouble and we're running from a command file, 578*3e1bd7a2Ssjelinek * quit before doing something we really regret. 579*3e1bd7a2Ssjelinek */ 580*3e1bd7a2Ssjelinek 581*3e1bd7a2Ssjelinek if (found && option_f) { 582*3e1bd7a2Ssjelinek err_print("Operation on mounted disks must be interactive.\n"); 583*3e1bd7a2Ssjelinek cmdabort(SIGINT); 584*3e1bd7a2Ssjelinek } 585*3e1bd7a2Ssjelinek /* 586*3e1bd7a2Ssjelinek * Return the result. 587*3e1bd7a2Ssjelinek */ 588*3e1bd7a2Ssjelinek return (found); 589*3e1bd7a2Ssjelinek } 590*3e1bd7a2Ssjelinek 591*3e1bd7a2Ssjelinek int 592*3e1bd7a2Ssjelinek check_label_with_swap() 593*3e1bd7a2Ssjelinek { 594*3e1bd7a2Ssjelinek int i; 595*3e1bd7a2Ssjelinek struct swaptable *st; 596*3e1bd7a2Ssjelinek struct swapent *swapent; 597*3e1bd7a2Ssjelinek int part; 598*3e1bd7a2Ssjelinek int bm_swap = 0; 599*3e1bd7a2Ssjelinek 600*3e1bd7a2Ssjelinek /* 601*3e1bd7a2Ssjelinek * If we are only checking part of the disk, the disk must 602*3e1bd7a2Ssjelinek * have a partition map to check against. If it doesn't, 603*3e1bd7a2Ssjelinek * we hope for the best. 604*3e1bd7a2Ssjelinek */ 605*3e1bd7a2Ssjelinek if (cur_parts == NULL) 606*3e1bd7a2Ssjelinek return (0); /* Will be checked later */ 607*3e1bd7a2Ssjelinek 608*3e1bd7a2Ssjelinek /* 609*3e1bd7a2Ssjelinek * Check for swap entries 610*3e1bd7a2Ssjelinek */ 611*3e1bd7a2Ssjelinek st = getswapentries(); 612*3e1bd7a2Ssjelinek /* 613*3e1bd7a2Ssjelinek * if there are no swap entries return. 614*3e1bd7a2Ssjelinek */ 615*3e1bd7a2Ssjelinek if (st == (struct swaptable *)NULL) 616*3e1bd7a2Ssjelinek return (0); 617*3e1bd7a2Ssjelinek swapent = st->swt_ent; 618*3e1bd7a2Ssjelinek for (i = 0; i < st->swt_n; i++, swapent++) 619*3e1bd7a2Ssjelinek if ((part = getpartition(swapent->ste_path)) != -1) 620*3e1bd7a2Ssjelinek bm_swap |= (1 << part); 621*3e1bd7a2Ssjelinek freeswapentries(st); 622*3e1bd7a2Ssjelinek 623*3e1bd7a2Ssjelinek return (checkpartitions(bm_swap)); 624*3e1bd7a2Ssjelinek } 625*3e1bd7a2Ssjelinek 626*3e1bd7a2Ssjelinek /* 627*3e1bd7a2Ssjelinek * Check the new label with the existing label on the disk, 628*3e1bd7a2Ssjelinek * to make sure that any mounted partitions are not being 629*3e1bd7a2Ssjelinek * affected by writing the new label. 630*3e1bd7a2Ssjelinek */ 631*3e1bd7a2Ssjelinek int 632*3e1bd7a2Ssjelinek check_label_with_mount() 633*3e1bd7a2Ssjelinek { 634*3e1bd7a2Ssjelinek FILE *fp; 635*3e1bd7a2Ssjelinek int part; 636*3e1bd7a2Ssjelinek struct mnttab mnt_record; 637*3e1bd7a2Ssjelinek struct mnttab *mp = &mnt_record; 638*3e1bd7a2Ssjelinek int bm_mounted = 0; 639*3e1bd7a2Ssjelinek 640*3e1bd7a2Ssjelinek 641*3e1bd7a2Ssjelinek /* 642*3e1bd7a2Ssjelinek * If we are only checking part of the disk, the disk must 643*3e1bd7a2Ssjelinek * have a partition map to check against. If it doesn't, 644*3e1bd7a2Ssjelinek * we hope for the best. 645*3e1bd7a2Ssjelinek */ 646*3e1bd7a2Ssjelinek if (cur_parts == NULL) 647*3e1bd7a2Ssjelinek return (0); /* Will be checked later */ 648*3e1bd7a2Ssjelinek 649*3e1bd7a2Ssjelinek /* 650*3e1bd7a2Ssjelinek * Lock out interrupts because of the mntent protocol. 651*3e1bd7a2Ssjelinek */ 652*3e1bd7a2Ssjelinek enter_critical(); 653*3e1bd7a2Ssjelinek /* 654*3e1bd7a2Ssjelinek * Open the mount table. 655*3e1bd7a2Ssjelinek */ 656*3e1bd7a2Ssjelinek fp = fopen(MNTTAB, "r"); 657*3e1bd7a2Ssjelinek if (fp == NULL) { 658*3e1bd7a2Ssjelinek err_print("Unable to open mount table.\n"); 659*3e1bd7a2Ssjelinek fullabort(); 660*3e1bd7a2Ssjelinek } 661*3e1bd7a2Ssjelinek /* 662*3e1bd7a2Ssjelinek * Loop through the mount table until we run out of entries. 663*3e1bd7a2Ssjelinek */ 664*3e1bd7a2Ssjelinek while ((getmntent(fp, mp)) != -1) { 665*3e1bd7a2Ssjelinek if ((part = getpartition(mp->mnt_special)) != -1) 666*3e1bd7a2Ssjelinek bm_mounted |= (1 << part); 667*3e1bd7a2Ssjelinek } 668*3e1bd7a2Ssjelinek /* 669*3e1bd7a2Ssjelinek * Close down the mount table. 670*3e1bd7a2Ssjelinek */ 671*3e1bd7a2Ssjelinek (void) fclose(fp); 672*3e1bd7a2Ssjelinek exit_critical(); 673*3e1bd7a2Ssjelinek 674*3e1bd7a2Ssjelinek return (checkpartitions(bm_mounted)); 675*3e1bd7a2Ssjelinek 676*3e1bd7a2Ssjelinek } 677*3e1bd7a2Ssjelinek 678*3e1bd7a2Ssjelinek /* 679*3e1bd7a2Ssjelinek * This Routine checks if any partitions specified 680*3e1bd7a2Ssjelinek * are affected by writing the new label 681*3e1bd7a2Ssjelinek */ 682*3e1bd7a2Ssjelinek static int 683*3e1bd7a2Ssjelinek checkpartitions(int bm_mounted) 684*3e1bd7a2Ssjelinek { 685*3e1bd7a2Ssjelinek struct dk_map32 *n; 686*3e1bd7a2Ssjelinek struct dk_map *o; 687*3e1bd7a2Ssjelinek struct dk_allmap old_map; 688*3e1bd7a2Ssjelinek int i, found = 0; 689*3e1bd7a2Ssjelinek 690*3e1bd7a2Ssjelinek /* 691*3e1bd7a2Ssjelinek * Now we need to check that the current partition list and the 692*3e1bd7a2Ssjelinek * previous partition list (which there must be if we actually 693*3e1bd7a2Ssjelinek * have partitions mounted) overlap in any way on the mounted 694*3e1bd7a2Ssjelinek * partitions 695*3e1bd7a2Ssjelinek */ 696*3e1bd7a2Ssjelinek 697*3e1bd7a2Ssjelinek /* 698*3e1bd7a2Ssjelinek * Get the "real" (on-disk) version of the partition table 699*3e1bd7a2Ssjelinek */ 700*3e1bd7a2Ssjelinek if (ioctl(cur_file, DKIOCGAPART, &old_map) == -1) { 701*3e1bd7a2Ssjelinek err_print("Unable to get current partition map.\n"); 702*3e1bd7a2Ssjelinek return (-1); 703*3e1bd7a2Ssjelinek } 704*3e1bd7a2Ssjelinek for (i = 0; i < NDKMAP; i++) { 705*3e1bd7a2Ssjelinek if (bm_mounted & (1 << i)) { 706*3e1bd7a2Ssjelinek /* 707*3e1bd7a2Ssjelinek * This partition is mounted 708*3e1bd7a2Ssjelinek */ 709*3e1bd7a2Ssjelinek o = &old_map.dka_map[i]; 710*3e1bd7a2Ssjelinek n = &cur_parts->pinfo_map[i]; 711*3e1bd7a2Ssjelinek #ifdef DEBUG 712*3e1bd7a2Ssjelinek fmt_print( 713*3e1bd7a2Ssjelinek "checkpartitions :checking partition '%c' \n", i + PARTITION_BASE); 714*3e1bd7a2Ssjelinek #endif 715*3e1bd7a2Ssjelinek /* 716*3e1bd7a2Ssjelinek * If partition is identical, we're fine. 717*3e1bd7a2Ssjelinek * If the partition grows, we're also fine, because 718*3e1bd7a2Ssjelinek * the routines in partition.c check for overflow. 719*3e1bd7a2Ssjelinek * It will (ultimately) be up to the routines in 720*3e1bd7a2Ssjelinek * partition.c to warn about creation of overlapping 721*3e1bd7a2Ssjelinek * partitions 722*3e1bd7a2Ssjelinek */ 723*3e1bd7a2Ssjelinek if (o->dkl_cylno == n->dkl_cylno && 724*3e1bd7a2Ssjelinek o->dkl_nblk <= n->dkl_nblk) { 725*3e1bd7a2Ssjelinek #ifdef DEBUG 726*3e1bd7a2Ssjelinek if (o->dkl_nblk < n->dkl_nblk) { 727*3e1bd7a2Ssjelinek fmt_print( 728*3e1bd7a2Ssjelinek "- new partition larger by %d blocks", n->dkl_nblk-o->dkl_nblk); 729*3e1bd7a2Ssjelinek } 730*3e1bd7a2Ssjelinek fmt_print("\n"); 731*3e1bd7a2Ssjelinek #endif 732*3e1bd7a2Ssjelinek continue; 733*3e1bd7a2Ssjelinek } 734*3e1bd7a2Ssjelinek #ifdef DEBUG 735*3e1bd7a2Ssjelinek fmt_print("- changes; old (%d,%d)->new (%d,%d)\n", 736*3e1bd7a2Ssjelinek o->dkl_cylno, o->dkl_nblk, n->dkl_cylno, 737*3e1bd7a2Ssjelinek n->dkl_nblk); 738*3e1bd7a2Ssjelinek #endif 739*3e1bd7a2Ssjelinek found = -1; 740*3e1bd7a2Ssjelinek } 741*3e1bd7a2Ssjelinek if (found) 742*3e1bd7a2Ssjelinek break; 743*3e1bd7a2Ssjelinek } 744*3e1bd7a2Ssjelinek 745*3e1bd7a2Ssjelinek /* 746*3e1bd7a2Ssjelinek * If we found trouble and we're running from a command file, 747*3e1bd7a2Ssjelinek * quit before doing something we really regret. 748*3e1bd7a2Ssjelinek */ 749*3e1bd7a2Ssjelinek 750*3e1bd7a2Ssjelinek if (found && option_f) { 751*3e1bd7a2Ssjelinek err_print("Operation on mounted disks or \ 752*3e1bd7a2Ssjelinek disks currently being used for swapping must be interactive.\n"); 753*3e1bd7a2Ssjelinek cmdabort(SIGINT); 754*3e1bd7a2Ssjelinek } 755*3e1bd7a2Ssjelinek /* 756*3e1bd7a2Ssjelinek * Return the result. 757*3e1bd7a2Ssjelinek */ 758*3e1bd7a2Ssjelinek return (found); 759*3e1bd7a2Ssjelinek } 760