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