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