1767Ssjelinek /* 2767Ssjelinek * CDDL HEADER START 3767Ssjelinek * 4767Ssjelinek * The contents of this file are subject to the terms of the 5767Ssjelinek * Common Development and Distribution License, Version 1.0 only 6767Ssjelinek * (the "License"). You may not use this file except in compliance 7767Ssjelinek * with the License. 8767Ssjelinek * 9767Ssjelinek * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10767Ssjelinek * or http://www.opensolaris.org/os/licensing. 11767Ssjelinek * See the License for the specific language governing permissions 12767Ssjelinek * and limitations under the License. 13767Ssjelinek * 14767Ssjelinek * When distributing Covered Code, include this CDDL HEADER in each 15767Ssjelinek * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16767Ssjelinek * If applicable, add the following below this CDDL HEADER, with the 17767Ssjelinek * fields enclosed by brackets "[]" replaced with your own identifying 18767Ssjelinek * information: Portions Copyright [yyyy] [name of copyright owner] 19767Ssjelinek * 20767Ssjelinek * CDDL HEADER END 21767Ssjelinek */ 22767Ssjelinek /* 23767Ssjelinek * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24767Ssjelinek * Use is subject to license terms. 25767Ssjelinek */ 26767Ssjelinek 27767Ssjelinek 28767Ssjelinek #pragma ident "%Z%%M% %I% %E% SMI" 29767Ssjelinek 30767Ssjelinek /* 31767Ssjelinek * This file contains miscellaneous device validation routines. 32767Ssjelinek */ 33767Ssjelinek 34767Ssjelinek #include "global.h" 35767Ssjelinek #include <sys/mnttab.h> 36767Ssjelinek #include <sys/mntent.h> 37767Ssjelinek #include <sys/autoconf.h> 38767Ssjelinek 39767Ssjelinek #include <signal.h> 40767Ssjelinek #include <malloc.h> 41767Ssjelinek #include <unistd.h> 42767Ssjelinek #include <string.h> 43767Ssjelinek #include <errno.h> 44767Ssjelinek #include <fcntl.h> 45767Ssjelinek #include <sys/ioctl.h> 46767Ssjelinek #include <sys/fcntl.h> 47767Ssjelinek #include <sys/stat.h> 48767Ssjelinek #include <sys/swap.h> 49767Ssjelinek #include <sys/sysmacros.h> 50767Ssjelinek #include <ctype.h> 51767Ssjelinek #include <libdiskmgt.h> 52767Ssjelinek #include <libnvpair.h> 53767Ssjelinek #include "misc.h" 54767Ssjelinek #include "checkdev.h" 55767Ssjelinek 56767Ssjelinek /* Function prototypes */ 57767Ssjelinek #ifdef __STDC__ 58767Ssjelinek 59767Ssjelinek static struct swaptable *getswapentries(void); 60767Ssjelinek static void freeswapentries(struct swaptable *); 61767Ssjelinek static int getpartition(char *pathname); 62767Ssjelinek static int checkpartitions(int bm_mounted); 63767Ssjelinek 64767Ssjelinek #else /* __STDC__ */ 65767Ssjelinek 66767Ssjelinek static struct swaptable *getswapentries(); 67767Ssjelinek static void freeswapentries(); 68767Ssjelinek static int getpartition(); 69767Ssjelinek static int checkpartitions(); 70767Ssjelinek 71767Ssjelinek #endif /* __STDC__ */ 72767Ssjelinek 73767Ssjelinek extern char *getfullname(); 74767Ssjelinek 75767Ssjelinek static struct swaptable * 76767Ssjelinek getswapentries(void) 77767Ssjelinek { 78767Ssjelinek register struct swaptable *st; 79767Ssjelinek register struct swapent *swapent; 80767Ssjelinek int i, num; 81767Ssjelinek char fullpathname[MAXPATHLEN]; 82767Ssjelinek 83767Ssjelinek /* 84767Ssjelinek * get the number of swap entries 85767Ssjelinek */ 86767Ssjelinek if ((num = swapctl(SC_GETNSWP, (void *)NULL)) == -1) { 87767Ssjelinek err_print("swapctl error "); 88767Ssjelinek fullabort(); 89767Ssjelinek } 90767Ssjelinek if (num == 0) 91767Ssjelinek return (NULL); 92767Ssjelinek if ((st = (swaptbl_t *)malloc(num * sizeof (swapent_t) + sizeof (int))) 93767Ssjelinek == NULL) { 94767Ssjelinek err_print("getswapentries: malloc failed.\n"); 95767Ssjelinek fullabort(); 96767Ssjelinek } 97767Ssjelinek swapent = st->swt_ent; 98767Ssjelinek for (i = 0; i < num; i++, swapent++) { 99767Ssjelinek if ((swapent->ste_path = malloc(MAXPATHLEN)) == NULL) { 100767Ssjelinek err_print("getswapentries: malloc failed.\n"); 101767Ssjelinek fullabort(); 102767Ssjelinek } 103767Ssjelinek } 104767Ssjelinek st->swt_n = num; 105767Ssjelinek if ((num = swapctl(SC_LIST, (void *)st)) == -1) { 106767Ssjelinek err_print("swapctl error "); 107767Ssjelinek fullabort(); 108767Ssjelinek } 109767Ssjelinek swapent = st->swt_ent; 110767Ssjelinek for (i = 0; i < num; i++, swapent++) { 111767Ssjelinek if (*swapent->ste_path != '/') { 112767Ssjelinek (void) snprintf(fullpathname, sizeof (fullpathname), 113767Ssjelinek "/dev/%s", swapent->ste_path); 114767Ssjelinek (void) strcpy(swapent->ste_path, fullpathname); 115767Ssjelinek } 116767Ssjelinek } 117767Ssjelinek return (st); 118767Ssjelinek } 119767Ssjelinek 120767Ssjelinek static void 121767Ssjelinek freeswapentries(st) 122767Ssjelinek struct swaptable *st; 123767Ssjelinek { 124767Ssjelinek register struct swapent *swapent; 125767Ssjelinek int i; 126767Ssjelinek 127767Ssjelinek swapent = st->swt_ent; 128767Ssjelinek for (i = 0; i < st->swt_n; i++, swapent++) 129767Ssjelinek free(swapent->ste_path); 130767Ssjelinek free(st); 131767Ssjelinek 132767Ssjelinek } 133767Ssjelinek 134767Ssjelinek /* 135767Ssjelinek * function getpartition: 136767Ssjelinek */ 137767Ssjelinek static int 138767Ssjelinek getpartition(pathname) 139767Ssjelinek char *pathname; 140767Ssjelinek { 141767Ssjelinek int mfd; 142767Ssjelinek struct dk_cinfo dkinfo; 143767Ssjelinek struct stat stbuf; 144767Ssjelinek char raw_device[MAXPATHLEN]; 145767Ssjelinek int found = -1; 146767Ssjelinek 147767Ssjelinek /* 148767Ssjelinek * Map the block device name to the raw device name. 149767Ssjelinek * If it doesn't appear to be a device name, skip it. 150767Ssjelinek */ 151767Ssjelinek if (match_substr(pathname, "/dev/") == 0) 152767Ssjelinek return (found); 153767Ssjelinek (void) strcpy(raw_device, "/dev/r"); 154767Ssjelinek (void) strcat(raw_device, pathname + strlen("/dev/")); 155767Ssjelinek /* 156767Ssjelinek * Determine if this appears to be a disk device. 157767Ssjelinek * First attempt to open the device. If if fails, skip it. 158767Ssjelinek */ 159767Ssjelinek if ((mfd = open(raw_device, O_RDWR | O_NDELAY)) < 0) { 160767Ssjelinek return (found); 161767Ssjelinek } 162767Ssjelinek /* 163767Ssjelinek * Must be a character device 164767Ssjelinek */ 165767Ssjelinek if (fstat(mfd, &stbuf) == -1 || !S_ISCHR(stbuf.st_mode)) { 166767Ssjelinek (void) close(mfd); 167767Ssjelinek return (found); 168767Ssjelinek } 169767Ssjelinek /* 170767Ssjelinek * Attempt to read the configuration info on the disk. 171767Ssjelinek */ 172767Ssjelinek if (ioctl(mfd, DKIOCINFO, &dkinfo) < 0) { 173767Ssjelinek (void) close(mfd); 174767Ssjelinek return (found); 175767Ssjelinek } 176767Ssjelinek /* 177767Ssjelinek * Finished with the opened device 178767Ssjelinek */ 179767Ssjelinek (void) close(mfd); 180767Ssjelinek 181767Ssjelinek /* 182767Ssjelinek * If it's not the disk we're interested in, it doesn't apply. 183767Ssjelinek */ 184767Ssjelinek if (cur_disk->disk_dkinfo.dki_ctype != dkinfo.dki_ctype || 185767Ssjelinek cur_disk->disk_dkinfo.dki_cnum != dkinfo.dki_cnum || 186767Ssjelinek cur_disk->disk_dkinfo.dki_unit != dkinfo.dki_unit || 187767Ssjelinek strcmp(cur_disk->disk_dkinfo.dki_dname, 188767Ssjelinek dkinfo.dki_dname) != 0) { 189767Ssjelinek return (found); 190767Ssjelinek } 191767Ssjelinek 192767Ssjelinek /* 193767Ssjelinek * Extract the partition that is mounted. 194767Ssjelinek */ 195767Ssjelinek return (PARTITION(stbuf.st_rdev)); 196767Ssjelinek } 197767Ssjelinek 198767Ssjelinek /* 199767Ssjelinek * This Routine checks to see if there are partitions used for swapping overlaps 200767Ssjelinek * a given portion of a disk. If the start parameter is < 0, it means 201767Ssjelinek * that the entire disk should be checked 202767Ssjelinek */ 203767Ssjelinek int 204767Ssjelinek checkswap(start, end) 205767Ssjelinek diskaddr_t start, end; 206767Ssjelinek { 207767Ssjelinek struct swaptable *st; 208767Ssjelinek struct swapent *swapent; 209767Ssjelinek int i; 210767Ssjelinek int found = 0; 211767Ssjelinek struct dk_map32 *map; 212767Ssjelinek int part; 213767Ssjelinek 214767Ssjelinek /* 215767Ssjelinek * If we are only checking part of the disk, the disk must 216767Ssjelinek * have a partition map to check against. If it doesn't, 217767Ssjelinek * we hope for the best. 218767Ssjelinek */ 219767Ssjelinek if (cur_parts == NULL) 220767Ssjelinek return (0); 221767Ssjelinek 222767Ssjelinek /* 223767Ssjelinek * check for swap entries 224767Ssjelinek */ 225767Ssjelinek st = getswapentries(); 226767Ssjelinek /* 227767Ssjelinek * if there are no swap entries return. 228767Ssjelinek */ 229767Ssjelinek if (st == (struct swaptable *)NULL) 230767Ssjelinek return (0); 231767Ssjelinek swapent = st->swt_ent; 232767Ssjelinek for (i = 0; i < st->swt_n; i++, swapent++) { 233767Ssjelinek if ((part = getpartition(swapent->ste_path)) != -1) { 234767Ssjelinek if (start == UINT_MAX64) { 235767Ssjelinek found = -1; 236767Ssjelinek break; 237767Ssjelinek } 238767Ssjelinek map = &cur_parts->pinfo_map[part]; 239767Ssjelinek if ((start >= (int)(map->dkl_cylno * spc() + 240767Ssjelinek map->dkl_nblk)) || (end < (int)(map->dkl_cylno 241767Ssjelinek * spc()))) { 242767Ssjelinek continue; 243767Ssjelinek } 244767Ssjelinek found = -1; 245767Ssjelinek break; 246767Ssjelinek }; 247767Ssjelinek } 248767Ssjelinek freeswapentries(st); 249767Ssjelinek /* 250767Ssjelinek * If we found trouble and we're running from a command file, 251767Ssjelinek * quit before doing something we really regret. 252767Ssjelinek */ 253767Ssjelinek 254767Ssjelinek if (found && option_f) { 255767Ssjelinek err_print( 256767Ssjelinek "Operation on disks being used for swapping must be interactive.\n"); 257767Ssjelinek cmdabort(SIGINT); 258767Ssjelinek } 259767Ssjelinek 260767Ssjelinek return (found); 261767Ssjelinek 262767Ssjelinek 263767Ssjelinek } 264767Ssjelinek /* 265767Ssjelinek * Determines if there are partitions that are a part of an SVM, VxVM, zpool 266767Ssjelinek * volume or a live upgrade device, overlapping a given portion of a disk. 267767Ssjelinek * Mounts and swap devices are checked in legacy format code. 268767Ssjelinek */ 269767Ssjelinek int 270767Ssjelinek checkdevinuse(char *cur_disk_path, diskaddr_t start, diskaddr_t end, int print, 271767Ssjelinek int check_label) 272767Ssjelinek { 273767Ssjelinek 274767Ssjelinek int error; 275767Ssjelinek int found = 0; 276767Ssjelinek int check = 0; 277767Ssjelinek int i; 278767Ssjelinek int bm_inuse = 0; 279767Ssjelinek int part = 0; 280767Ssjelinek uint64_t slice_start, slice_size; 281767Ssjelinek dm_descriptor_t *slices = NULL; 282767Ssjelinek nvlist_t *attrs = NULL; 283767Ssjelinek char *usage; 284767Ssjelinek char *name; 285767Ssjelinek 286767Ssjelinek /* 287*1107Ssjelinek * If the user does not want to do in use checking, return immediately. 288*1107Ssjelinek * Normally, this is handled in libdiskmgt. For format, there is more 289*1107Ssjelinek * processing required, so we want to bypass the in use checking 290*1107Ssjelinek * here. 291*1107Ssjelinek */ 292*1107Ssjelinek 293*1107Ssjelinek if (NOINUSE_SET) 294*1107Ssjelinek return (0); 295*1107Ssjelinek 296*1107Ssjelinek /* 297767Ssjelinek * For format, we get basic 'in use' details from libdiskmgt. After 298767Ssjelinek * that we must do the appropriate checking to see if the 'in use' 299767Ssjelinek * details require a bit of additional work. 300767Ssjelinek */ 301767Ssjelinek 302767Ssjelinek dm_get_slices(cur_disk_path, &slices, &error); 303767Ssjelinek if (error) { 304767Ssjelinek err_print("Error occurred with device in use checking: %s\n", 305767Ssjelinek strerror(error)); 306767Ssjelinek return (found); 307767Ssjelinek } 308767Ssjelinek if (slices == NULL) 309767Ssjelinek return (found); 310767Ssjelinek 311767Ssjelinek for (i = 0; slices[i] != NULL; i++) { 312767Ssjelinek /* 313767Ssjelinek * If we are checking the whole disk 314767Ssjelinek * then any and all in use data is 315767Ssjelinek * relevant. 316767Ssjelinek */ 317767Ssjelinek if (start == UINT_MAX64) { 318767Ssjelinek name = dm_get_name(slices[i], &error); 319767Ssjelinek if (error != 0 || !name) { 320767Ssjelinek err_print("Error occurred with device " 321767Ssjelinek "in use checking: %s\n", 322767Ssjelinek strerror(error)); 323767Ssjelinek continue; 324767Ssjelinek } 325767Ssjelinek if (dm_inuse(name, &usage, DM_WHO_FORMAT, &error) || 326767Ssjelinek error) { 327767Ssjelinek if (error != 0) { 328767Ssjelinek dm_free_name(name); 329767Ssjelinek name = NULL; 330767Ssjelinek err_print("Error occurred with device " 331767Ssjelinek "in use checking: %s\n", 332767Ssjelinek strerror(error)); 333767Ssjelinek continue; 334767Ssjelinek } 335767Ssjelinek dm_free_name(name); 336767Ssjelinek name = NULL; 337767Ssjelinek /* 338767Ssjelinek * If this is a dump device, then it is 339767Ssjelinek * a failure. You cannot format a slice 340767Ssjelinek * that is a dedicated dump device. 341767Ssjelinek */ 342767Ssjelinek 343767Ssjelinek if (strstr(usage, DM_USE_DUMP)) { 344767Ssjelinek if (print) { 345767Ssjelinek err_print(usage); 346767Ssjelinek free(usage); 347767Ssjelinek } 348767Ssjelinek dm_free_descriptors(slices); 349767Ssjelinek return (1); 350767Ssjelinek } 351767Ssjelinek /* 352767Ssjelinek * We really found a device that is in use. 353767Ssjelinek * Set 'found' for the return value, and set 354767Ssjelinek * 'check' to indicate below that we must 355767Ssjelinek * get the partition number to set bm_inuse 356767Ssjelinek * in the event we are trying to label this 357767Ssjelinek * device. check_label is set when we are 358767Ssjelinek * checking modifications for in use slices 359767Ssjelinek * on the device. 360767Ssjelinek */ 361767Ssjelinek found ++; 362767Ssjelinek check = 1; 363767Ssjelinek if (print) { 364767Ssjelinek err_print(usage); 365767Ssjelinek free(usage); 366767Ssjelinek } 367767Ssjelinek } 368767Ssjelinek } else { 369767Ssjelinek /* 370767Ssjelinek * Before getting the in use data, verify that the 371767Ssjelinek * current slice is within the range we are checking. 372767Ssjelinek */ 373767Ssjelinek attrs = dm_get_attributes(slices[i], &error); 374767Ssjelinek if (error) { 375767Ssjelinek err_print("Error occurred with device in use " 376767Ssjelinek "checking: %s\n", strerror(error)); 377767Ssjelinek continue; 378767Ssjelinek } 379767Ssjelinek if (attrs == NULL) { 380767Ssjelinek continue; 381767Ssjelinek } 382767Ssjelinek 383767Ssjelinek (void) nvlist_lookup_uint64(attrs, DM_START, 384767Ssjelinek &slice_start); 385767Ssjelinek (void) nvlist_lookup_uint64(attrs, DM_SIZE, 386767Ssjelinek &slice_size); 387767Ssjelinek if (start >= (slice_start + slice_size) || 388767Ssjelinek (end < slice_start)) { 389767Ssjelinek nvlist_free(attrs); 390767Ssjelinek attrs = NULL; 391767Ssjelinek continue; 392767Ssjelinek } 393767Ssjelinek name = dm_get_name(slices[i], &error); 394767Ssjelinek if (error != 0 || !name) { 395767Ssjelinek err_print("Error occurred with device " 396767Ssjelinek "in use checking: %s\n", 397767Ssjelinek strerror(error)); 398767Ssjelinek nvlist_free(attrs); 399767Ssjelinek attrs = NULL; 400767Ssjelinek continue; 401767Ssjelinek } 402767Ssjelinek if (dm_inuse(name, &usage, 403767Ssjelinek DM_WHO_FORMAT, &error) || error) { 404767Ssjelinek if (error != 0) { 405767Ssjelinek dm_free_name(name); 406767Ssjelinek name = NULL; 407767Ssjelinek err_print("Error occurred with device " 408767Ssjelinek "in use checking: %s\n", 409767Ssjelinek strerror(error)); 410767Ssjelinek nvlist_free(attrs); 411767Ssjelinek attrs = NULL; 412767Ssjelinek continue; 413767Ssjelinek } 414767Ssjelinek dm_free_name(name); 415767Ssjelinek name = NULL; 416767Ssjelinek /* 417767Ssjelinek * If this is a dump device, then it is 418767Ssjelinek * a failure. You cannot format a slice 419767Ssjelinek * that is a dedicated dump device. 420767Ssjelinek */ 421767Ssjelinek if (strstr(usage, DM_USE_DUMP)) { 422767Ssjelinek if (print) { 423767Ssjelinek err_print(usage); 424767Ssjelinek free(usage); 425767Ssjelinek } 426767Ssjelinek dm_free_descriptors(slices); 427767Ssjelinek nvlist_free(attrs); 428767Ssjelinek return (1); 429767Ssjelinek } 430767Ssjelinek /* 431767Ssjelinek * We really found a device that is in use. 432767Ssjelinek * Set 'found' for the return value, and set 433767Ssjelinek * 'check' to indicate below that we must 434767Ssjelinek * get the partition number to set bm_inuse 435767Ssjelinek * in the event we are trying to label this 436767Ssjelinek * device. check_label is set when we are 437767Ssjelinek * checking modifications for in use slices 438767Ssjelinek * on the device. 439767Ssjelinek */ 440767Ssjelinek found ++; 441767Ssjelinek check = 1; 442767Ssjelinek if (print) { 443767Ssjelinek err_print(usage); 444767Ssjelinek free(usage); 445767Ssjelinek } 446767Ssjelinek } 447767Ssjelinek } 448767Ssjelinek /* 449767Ssjelinek * If check is set it means we found a slice(the current slice) 450767Ssjelinek * on this device in use in some way. We potentially want 451767Ssjelinek * to check this slice when labeling is 452767Ssjelinek * requested. We set bm_inuse with this partition value 453767Ssjelinek * for use later if check_label was set when called. 454767Ssjelinek */ 455767Ssjelinek if (check) { 456767Ssjelinek name = dm_get_name(slices[i], &error); 457767Ssjelinek if (error != 0 || !name) { 458767Ssjelinek err_print("Error occurred with device " 459767Ssjelinek "in use checking: %s\n", 460767Ssjelinek strerror(error)); 461767Ssjelinek nvlist_free(attrs); 462767Ssjelinek attrs = NULL; 463767Ssjelinek continue; 464767Ssjelinek } 465767Ssjelinek part = getpartition(name); 466767Ssjelinek dm_free_name(name); 467767Ssjelinek name = NULL; 468767Ssjelinek if (part != -1) { 469767Ssjelinek bm_inuse |= 1 << part; 470767Ssjelinek } 471767Ssjelinek check = 0; 472767Ssjelinek } 473767Ssjelinek /* 474767Ssjelinek * If we have attributes then we have successfully 475767Ssjelinek * found the slice we were looking for and we also 476767Ssjelinek * know this means we are not searching the whole 477767Ssjelinek * disk so break out of the loop 478767Ssjelinek * now. 479767Ssjelinek */ 480767Ssjelinek if (attrs) { 481767Ssjelinek nvlist_free(attrs); 482767Ssjelinek break; 483767Ssjelinek } 484767Ssjelinek } 485767Ssjelinek 486767Ssjelinek if (slices) { 487767Ssjelinek dm_free_descriptors(slices); 488767Ssjelinek } 489767Ssjelinek 490767Ssjelinek /* 491767Ssjelinek * The user is trying to label the disk. We have to do special 492767Ssjelinek * checking here to ensure they are not trying to modify a slice 493767Ssjelinek * that is in use in an incompatible way. 494767Ssjelinek */ 495767Ssjelinek if (check_label && bm_inuse) { 496767Ssjelinek /* 497767Ssjelinek * !0 indicates that we found a 498767Ssjelinek * problem. In this case, we have overloaded 499767Ssjelinek * the use of checkpartitions to work for 500767Ssjelinek * in use devices. bm_inuse is representative 501767Ssjelinek * of the slice that is in use, not that 502767Ssjelinek * is mounted as is in the case of the normal 503767Ssjelinek * use of checkpartitions. 504767Ssjelinek * 505767Ssjelinek * The call to checkpartitions will return !0 if 506767Ssjelinek * we are trying to shrink a device that we have found 507767Ssjelinek * to be in use above. 508767Ssjelinek */ 509767Ssjelinek return (checkpartitions(bm_inuse)); 510767Ssjelinek } 511767Ssjelinek 512767Ssjelinek return (found); 513767Ssjelinek } 514767Ssjelinek /* 515767Ssjelinek * This routine checks to see if there are mounted partitions overlapping 516767Ssjelinek * a given portion of a disk. If the start parameter is < 0, it means 517767Ssjelinek * that the entire disk should be checked. 518767Ssjelinek */ 519767Ssjelinek int 520767Ssjelinek checkmount(start, end) 521767Ssjelinek diskaddr_t start, end; 522767Ssjelinek { 523767Ssjelinek FILE *fp; 524767Ssjelinek int found = 0; 525767Ssjelinek struct dk_map32 *map; 526767Ssjelinek int part; 527767Ssjelinek struct mnttab mnt_record; 528767Ssjelinek struct mnttab *mp = &mnt_record; 529767Ssjelinek 530767Ssjelinek /* 531767Ssjelinek * If we are only checking part of the disk, the disk must 532767Ssjelinek * have a partition map to check against. If it doesn't, 533767Ssjelinek * we hope for the best. 534767Ssjelinek */ 535767Ssjelinek if (cur_parts == NULL) 536767Ssjelinek return (0); 537767Ssjelinek 538767Ssjelinek /* 539767Ssjelinek * Lock out interrupts because of the mntent protocol. 540767Ssjelinek */ 541767Ssjelinek enter_critical(); 542767Ssjelinek /* 543767Ssjelinek * Open the mount table. 544767Ssjelinek */ 545767Ssjelinek fp = fopen(MNTTAB, "r"); 546767Ssjelinek if (fp == NULL) { 547767Ssjelinek err_print("Unable to open mount table.\n"); 548767Ssjelinek fullabort(); 549767Ssjelinek } 550767Ssjelinek /* 551767Ssjelinek * Loop through the mount table until we run out of entries. 552767Ssjelinek */ 553767Ssjelinek while ((getmntent(fp, mp)) != -1) { 554767Ssjelinek 555767Ssjelinek if ((part = getpartition(mp->mnt_special)) == -1) 556767Ssjelinek continue; 557767Ssjelinek 558767Ssjelinek /* 559767Ssjelinek * It's a mount on the disk we're checking. If we are 560767Ssjelinek * checking whole disk, then we found trouble. We can 561767Ssjelinek * quit searching. 562767Ssjelinek */ 563767Ssjelinek if (start == UINT_MAX64) { 564767Ssjelinek found = -1; 565767Ssjelinek break; 566767Ssjelinek } 567767Ssjelinek 568767Ssjelinek /* 569767Ssjelinek * If the partition overlaps the zone we're checking, 570767Ssjelinek * then we found trouble. We can quit searching. 571767Ssjelinek */ 572767Ssjelinek map = &cur_parts->pinfo_map[part]; 573767Ssjelinek if ((start >= (int)(map->dkl_cylno * spc() + map->dkl_nblk)) || 574767Ssjelinek (end < (int)(map->dkl_cylno * spc()))) { 575767Ssjelinek continue; 576767Ssjelinek } 577767Ssjelinek found = -1; 578767Ssjelinek break; 579767Ssjelinek } 580767Ssjelinek /* 581767Ssjelinek * Close down the mount table. 582767Ssjelinek */ 583767Ssjelinek (void) fclose(fp); 584767Ssjelinek exit_critical(); 585767Ssjelinek 586767Ssjelinek /* 587767Ssjelinek * If we found trouble and we're running from a command file, 588767Ssjelinek * quit before doing something we really regret. 589767Ssjelinek */ 590767Ssjelinek 591767Ssjelinek if (found && option_f) { 592767Ssjelinek err_print("Operation on mounted disks must be interactive.\n"); 593767Ssjelinek cmdabort(SIGINT); 594767Ssjelinek } 595767Ssjelinek /* 596767Ssjelinek * Return the result. 597767Ssjelinek */ 598767Ssjelinek return (found); 599767Ssjelinek } 600767Ssjelinek 601767Ssjelinek int 602767Ssjelinek check_label_with_swap() 603767Ssjelinek { 604767Ssjelinek int i; 605767Ssjelinek struct swaptable *st; 606767Ssjelinek struct swapent *swapent; 607767Ssjelinek int part; 608767Ssjelinek int bm_swap = 0; 609767Ssjelinek 610767Ssjelinek /* 611767Ssjelinek * If we are only checking part of the disk, the disk must 612767Ssjelinek * have a partition map to check against. If it doesn't, 613767Ssjelinek * we hope for the best. 614767Ssjelinek */ 615767Ssjelinek if (cur_parts == NULL) 616767Ssjelinek return (0); /* Will be checked later */ 617767Ssjelinek 618767Ssjelinek /* 619767Ssjelinek * Check for swap entries 620767Ssjelinek */ 621767Ssjelinek st = getswapentries(); 622767Ssjelinek /* 623767Ssjelinek * if there are no swap entries return. 624767Ssjelinek */ 625767Ssjelinek if (st == (struct swaptable *)NULL) 626767Ssjelinek return (0); 627767Ssjelinek swapent = st->swt_ent; 628767Ssjelinek for (i = 0; i < st->swt_n; i++, swapent++) 629767Ssjelinek if ((part = getpartition(swapent->ste_path)) != -1) 630767Ssjelinek bm_swap |= (1 << part); 631767Ssjelinek freeswapentries(st); 632767Ssjelinek 633767Ssjelinek return (checkpartitions(bm_swap)); 634767Ssjelinek } 635767Ssjelinek 636767Ssjelinek /* 637767Ssjelinek * Check the new label with the existing label on the disk, 638767Ssjelinek * to make sure that any mounted partitions are not being 639767Ssjelinek * affected by writing the new label. 640767Ssjelinek */ 641767Ssjelinek int 642767Ssjelinek check_label_with_mount() 643767Ssjelinek { 644767Ssjelinek FILE *fp; 645767Ssjelinek int part; 646767Ssjelinek struct mnttab mnt_record; 647767Ssjelinek struct mnttab *mp = &mnt_record; 648767Ssjelinek int bm_mounted = 0; 649767Ssjelinek 650767Ssjelinek 651767Ssjelinek /* 652767Ssjelinek * If we are only checking part of the disk, the disk must 653767Ssjelinek * have a partition map to check against. If it doesn't, 654767Ssjelinek * we hope for the best. 655767Ssjelinek */ 656767Ssjelinek if (cur_parts == NULL) 657767Ssjelinek return (0); /* Will be checked later */ 658767Ssjelinek 659767Ssjelinek /* 660767Ssjelinek * Lock out interrupts because of the mntent protocol. 661767Ssjelinek */ 662767Ssjelinek enter_critical(); 663767Ssjelinek /* 664767Ssjelinek * Open the mount table. 665767Ssjelinek */ 666767Ssjelinek fp = fopen(MNTTAB, "r"); 667767Ssjelinek if (fp == NULL) { 668767Ssjelinek err_print("Unable to open mount table.\n"); 669767Ssjelinek fullabort(); 670767Ssjelinek } 671767Ssjelinek /* 672767Ssjelinek * Loop through the mount table until we run out of entries. 673767Ssjelinek */ 674767Ssjelinek while ((getmntent(fp, mp)) != -1) { 675767Ssjelinek if ((part = getpartition(mp->mnt_special)) != -1) 676767Ssjelinek bm_mounted |= (1 << part); 677767Ssjelinek } 678767Ssjelinek /* 679767Ssjelinek * Close down the mount table. 680767Ssjelinek */ 681767Ssjelinek (void) fclose(fp); 682767Ssjelinek exit_critical(); 683767Ssjelinek 684767Ssjelinek return (checkpartitions(bm_mounted)); 685767Ssjelinek 686767Ssjelinek } 687767Ssjelinek 688767Ssjelinek /* 689767Ssjelinek * This Routine checks if any partitions specified 690767Ssjelinek * are affected by writing the new label 691767Ssjelinek */ 692767Ssjelinek static int 693767Ssjelinek checkpartitions(int bm_mounted) 694767Ssjelinek { 695767Ssjelinek struct dk_map32 *n; 696767Ssjelinek struct dk_map *o; 697767Ssjelinek struct dk_allmap old_map; 698767Ssjelinek int i, found = 0; 699767Ssjelinek 700767Ssjelinek /* 701767Ssjelinek * Now we need to check that the current partition list and the 702767Ssjelinek * previous partition list (which there must be if we actually 703767Ssjelinek * have partitions mounted) overlap in any way on the mounted 704767Ssjelinek * partitions 705767Ssjelinek */ 706767Ssjelinek 707767Ssjelinek /* 708767Ssjelinek * Get the "real" (on-disk) version of the partition table 709767Ssjelinek */ 710767Ssjelinek if (ioctl(cur_file, DKIOCGAPART, &old_map) == -1) { 711767Ssjelinek err_print("Unable to get current partition map.\n"); 712767Ssjelinek return (-1); 713767Ssjelinek } 714767Ssjelinek for (i = 0; i < NDKMAP; i++) { 715767Ssjelinek if (bm_mounted & (1 << i)) { 716767Ssjelinek /* 717767Ssjelinek * This partition is mounted 718767Ssjelinek */ 719767Ssjelinek o = &old_map.dka_map[i]; 720767Ssjelinek n = &cur_parts->pinfo_map[i]; 721767Ssjelinek #ifdef DEBUG 722767Ssjelinek fmt_print( 723767Ssjelinek "checkpartitions :checking partition '%c' \n", i + PARTITION_BASE); 724767Ssjelinek #endif 725767Ssjelinek /* 726767Ssjelinek * If partition is identical, we're fine. 727767Ssjelinek * If the partition grows, we're also fine, because 728767Ssjelinek * the routines in partition.c check for overflow. 729767Ssjelinek * It will (ultimately) be up to the routines in 730767Ssjelinek * partition.c to warn about creation of overlapping 731767Ssjelinek * partitions 732767Ssjelinek */ 733767Ssjelinek if (o->dkl_cylno == n->dkl_cylno && 734767Ssjelinek o->dkl_nblk <= n->dkl_nblk) { 735767Ssjelinek #ifdef DEBUG 736767Ssjelinek if (o->dkl_nblk < n->dkl_nblk) { 737767Ssjelinek fmt_print( 738767Ssjelinek "- new partition larger by %d blocks", n->dkl_nblk-o->dkl_nblk); 739767Ssjelinek } 740767Ssjelinek fmt_print("\n"); 741767Ssjelinek #endif 742767Ssjelinek continue; 743767Ssjelinek } 744767Ssjelinek #ifdef DEBUG 745767Ssjelinek fmt_print("- changes; old (%d,%d)->new (%d,%d)\n", 746767Ssjelinek o->dkl_cylno, o->dkl_nblk, n->dkl_cylno, 747767Ssjelinek n->dkl_nblk); 748767Ssjelinek #endif 749767Ssjelinek found = -1; 750767Ssjelinek } 751767Ssjelinek if (found) 752767Ssjelinek break; 753767Ssjelinek } 754767Ssjelinek 755767Ssjelinek /* 756767Ssjelinek * If we found trouble and we're running from a command file, 757767Ssjelinek * quit before doing something we really regret. 758767Ssjelinek */ 759767Ssjelinek 760767Ssjelinek if (found && option_f) { 761767Ssjelinek err_print("Operation on mounted disks or \ 762767Ssjelinek disks currently being used for swapping must be interactive.\n"); 763767Ssjelinek cmdabort(SIGINT); 764767Ssjelinek } 765767Ssjelinek /* 766767Ssjelinek * Return the result. 767767Ssjelinek */ 768767Ssjelinek return (found); 769767Ssjelinek } 770