xref: /titanic_44/usr/src/cmd/fdisk/fdisk.c (revision 573ca77e53dd31dcaebef023e7eb41969e6896c1)
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 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1990, 1991 UNIX System Laboratories, Inc.	*/
28 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T	*/
29 /*	  All Rights Reserved	*/
30 
31 /*	Copyright (c) 1987, 1988 Microsoft Corporation	*/
32 /*	  All Rights Reserved	*/
33 
34 /*
35  * PROGRAM: fdisk(1M)
36  * This program reads the partition table on the specified device and
37  * also reads the drive parameters. The user can perform various
38  * operations from a supplied menu or from the command line. Diagnostic
39  * options are also available.
40  */
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <ctype.h>
48 #include <sys/stat.h>
49 #include <sys/types.h>
50 #include <limits.h>
51 #include <sys/param.h>
52 #include <sys/systeminfo.h>
53 #include <sys/efi_partition.h>
54 #include <sys/byteorder.h>
55 #include <sys/systeminfo.h>
56 
57 #include <sys/dktp/fdisk.h>
58 #include <sys/dkio.h>
59 #include <sys/vtoc.h>
60 
61 #define	CLR_SCR ""
62 #define	CLR_LIN ""
63 #define	HOME "" \
64 	""
65 #define	Q_LINE ""
66 #define	W_LINE ""
67 #define	E_LINE ""
68 #define	M_LINE "" \
69 	""
70 #define	T_LINE ""
71 
72 #define	DEFAULT_PATH	"/dev/rdsk/"
73 
74 /* XXX - should be in fdisk.h, used by sd as well */
75 
76 /*
77  * the MAX values are the maximum usable values for BIOS chs values
78  * The MAX_CYL value of 1022 is the maximum usable value
79  *   the value of 1023 is a fence value,
80  *   indicating no CHS geometry exists for the corresponding LBA value.
81  * HEAD range [ 0 .. MAX_HEAD ], so number of heads is (MAX_HEAD + 1)
82  * SECT range [ 1 .. MAX_SECT ], so number of sectors is (MAX_SECT)
83  */
84 #define	MAX_SECT	(63)
85 #define	MAX_CYL		(1022)
86 #define	MAX_HEAD	(254)
87 
88 #define	DK_MAX_2TB	UINT32_MAX	/* Max # of sectors in 2TB */
89 
90 /* for clear_vtoc() */
91 #define	OLD		0
92 #define	NEW		1
93 
94 /* readvtoc/writevtoc return codes */
95 #define	VTOC_OK		0	/* Good VTOC */
96 #define	VTOC_INVAL	1	/* invalid VTOC */
97 #define	VTOC_NOTSUP	2	/* operation not supported - EFI label */
98 #define	VTOC_RWERR	3	/* couldn't read or write VTOC */
99 
100 /*
101  * Support for fdisk(1M) on the SPARC platform
102  *	In order to convert little endian values to big endian for SPARC,
103  *	byte/short and long values must be swapped.
104  *	These swapping macros will be used to access information in the
105  *	mboot and ipart structures.
106  */
107 
108 #ifdef sparc
109 #define	les(val)	((((val)&0xFF)<<8)|(((val)>>8)&0xFF))
110 #define	lel(val)	(((unsigned)(les((val)&0x0000FFFF))<<16) | \
111 			    (les((unsigned)((val)&0xffff0000)>>16)))
112 #else
113 #define	les(val)	(val)
114 #define	lel(val)	(val)
115 #endif
116 
117 #if defined(_SUNOS_VTOC_16)
118 #define	VTOC_OFFSET	1
119 #elif defined(_SUNOS_VTOC_8)
120 #define	VTOC_OFFSET	0
121 #else
122 #error No VTOC format defined.
123 #endif
124 
125 static char Usage[] = "Usage: fdisk\n"
126 "[ -A id:act:bhead:bsect:bcyl:ehead:esect:ecyl:rsect:numsect ]\n"
127 "[ -b masterboot ]\n"
128 "[ -D id:act:bhead:bsect:bcyl:ehead:esect:ecyl:rsect:numsect ]\n"
129 "[ -F fdisk_file ] [ -h ] [ -o offset ] [ -P fill_patt ] [ -s size ]\n"
130 "[ -S geom_file ] [ [ -v ] -W { creat_fdisk_file | - } ]\n"
131 "[ -w | r | d | n | I | B | E | g | G | R | t | T ] rdevice";
132 
133 static char Usage1[] = "    Partition options:\n"
134 "	-A id:act:bhead:bsect:bcyl:ehead:esect:ecyl:rsect:numsect\n"
135 "		Create a partition with specific attributes:\n"
136 "		id      = system id number (fdisk.h) for the partition type\n"
137 "		act     = active partition flag (0 is off and 128 is on)\n"
138 "		bhead   = beginning head for start of partition\n"
139 "		bsect   = beginning sector for start of partition\n"
140 "		bcyl    = beginning cylinder for start of partition\n"
141 "		ehead   = ending head for end of partition\n"
142 "		esect   = ending sector for end of partition\n"
143 "		ecyl    = ending cylinder for end of partition\n"
144 "		rsect   = sector number from start of disk for\n"
145 "			  start of partition\n"
146 "		numsect = partition size in sectors\n"
147 "	-b master_boot\n"
148 "		Use master_boot as the master boot file.\n"
149 "	-B	Create one Solaris partition that uses the entire disk.\n"
150 "	-E	Create one EFI partition that uses the entire disk.\n"
151 "	-D id:act:bhead:bsect:bcyl:ehead:esect:ecyl:rsect:numsect\n"
152 "		Delete a partition. See attribute definitions for -A.\n"
153 "	-F fdisk_file\n"
154 "		Use fdisk_file to initialize on-line fdisk table.\n"
155 "	-I	Forego device checks. Generate a file image of what would go\n"
156 "		on a disk using the geometry specified with the -S option.\n"
157 "	-n	Do not run in interactive mode.\n"
158 "	-R	Open the disk device as read-only.\n"
159 "	-t	Check and adjust VTOC to be consistent with fdisk table.\n"
160 "		VTOC slices exceeding the partition size will be truncated.\n"
161 "	-T	Check and adjust VTOC to be consistent with fdisk table.\n"
162 "		VTOC slices exceeding the partition size will be removed.\n"
163 "	-W fdisk_file\n"
164 "		Write on-disk table to fdisk_file.\n"
165 "	-W -	Write on-disk table to standard output.\n"
166 "	-v	Display virtual geometry. Must be used with the -W option.\n"
167 "    Diagnostic options:\n"
168 "	-d	Activate debug information about progress.\n"
169 "	-g	Write label geometry to standard output:\n"
170 "		PCYL		number of physical cylinders\n"
171 "		NCYL		number of usable cylinders\n"
172 "		ACYL		number of alternate cylinders\n"
173 "		BCYL		cylinder offset\n"
174 "		NHEADS		number of heads\n"
175 "		NSECTORS	number of sectors per track\n"
176 "		SECTSIZ		size of a sector in bytes\n"
177 "	-G	Write physical geometry to standard output (see -g).\n"
178 "	-h	Issue this verbose help message.\n"
179 "	-o offset\n"
180 "		Block offset from start of disk (default 0). Ignored if\n"
181 "		-P # specified.\n"
182 "	-P fill_patt\n"
183 "		Fill disk with pattern fill_patt. fill_patt can be decimal or\n"
184 "		hexadecimal and is used as number for constant long word\n"
185 "		pattern. If fill_patt is \"#\" then pattern of block #\n"
186 "		for each block. Pattern is put in each block as long words\n"
187 "		and fills each block (see -o and -s).\n"
188 "	-r	Read from a disk to stdout (see -o and -s).\n"
189 "	-s size	Number of blocks on which to perform operation (see -o).\n"
190 "	-S geom_file\n"
191 "		Use geom_file to set the label geometry (see -g).\n"
192 "	-w	Write to a disk from stdin (see -o and -s).";
193 
194 static char Ostr[] = "Other OS";
195 static char Dstr[] = "DOS12";
196 static char D16str[] = "DOS16";
197 static char DDstr[] = "DOS-DATA";
198 static char EDstr[] = "EXT-DOS";
199 static char DBstr[] = "DOS-BIG";
200 static char PCstr[] = "PCIX";
201 static char Ustr[] = "UNIX System";
202 static char SUstr[] = "Solaris";
203 static char SU2str[] = "Solaris2";
204 static char X86str[] = "x86 Boot";
205 static char DIAGstr[] = "Diagnostic";
206 static char IFSstr[] = "IFS: NTFS";
207 static char AIXstr[] = "AIX Boot";
208 static char AIXDstr[] = "AIX Data";
209 static char OS2str[] = "OS/2 Boot";
210 static char WINstr[] = "Win95 FAT32";
211 static char EWINstr[] = "Ext Win95";
212 static char FAT95str[] = "FAT16 LBA";
213 static char EXTLstr[] = "EXT LBA";
214 static char LINUXstr[] = "Linux";
215 static char CPMstr[] = "CP/M";
216 static char NOVstr[] = "Netware 3.x+";
217 static char QNXstr[] = "QNX 4.x";
218 static char QNX2str[] = "QNX part 2";
219 static char QNX3str[] = "QNX part 3";
220 static char LINNATstr[] = "Linux native";
221 static char NTFSVOL1str[] = "NT volset 1";
222 static char NTFSVOL2str[] = "NT volset 2";
223 static char BSDstr[] = "BSD OS";
224 static char NEXTSTEPstr[] = "NeXTSTEP";
225 static char BSDIFSstr[] = "BSDI FS";
226 static char BSDISWAPstr[] = "BSDI swap";
227 static char Actvstr[] = "Active";
228 static char EFIstr[] = "EFI";
229 static char NAstr[] = "      ";
230 
231 /* All the user options and flags */
232 static char *Dfltdev;			/* name of fixed disk drive */
233 
234 /* Diagnostic options */
235 static int	io_wrt = 0;		/* write stdin to disk (-w) */
236 static int	io_rd = 0;		/* read disk and write stdout (-r) */
237 static char	*io_fatt;		/* user supplied pattern (-P pattern) */
238 static int	io_patt = 0;		/* write pattern to disk (-P pattern) */
239 static int	io_lgeom = 0;		/* get label geometry (-g) */
240 static int	io_pgeom = 0;		/* get drive physical geometry (-G) */
241 static char	*io_sgeom = 0;		/* set label geometry (-S geom_file) */
242 static int	io_readonly = 0;	/* do not write to disk (-R) */
243 
244 /* The -o offset and -s size options specify the area of the disk on */
245 /* which to perform the particular operation; i.e., -P, -r, or -w. */
246 static off_t	io_offset = 0;		/* offset sector (-o offset) */
247 static off_t	io_size = 0;		/* size in sectors (-s size) */
248 
249 /* Partition table flags */
250 static int	v_flag = 0;		/* virtual geometry-HBA flag (-v) */
251 static int 	stdo_flag = 0;		/* stdout flag (-W -) */
252 static int	io_fdisk = 0;		/* do fdisk operation */
253 static int	io_ifdisk = 0;		/* interactive partition */
254 static int	io_nifdisk = 0;		/* non-interactive partition (-n) */
255 
256 static int	io_adjt = 0;		/* check/adjust VTOC (truncate (-t)) */
257 static int	io_ADJT = 0;		/* check/adjust VTOC (delete (-T)) */
258 static char	*io_ffdisk = 0;		/* input fdisk file name (-F file) */
259 static char	*io_Wfdisk = 0;		/* output fdisk file name (-W file) */
260 static char	*io_Afdisk = 0;		/* add entry to partition table (-A) */
261 static char	*io_Dfdisk = 0;		/* delete entry from part. table (-D) */
262 
263 static char	*io_mboot = 0;		/* master boot record (-b boot_file) */
264 
265 static struct mboot BootCod;		/* buffer for master boot record */
266 
267 static int	io_wholedisk = 0;	/* use whole disk for Solaris (-B) */
268 static int	io_EFIdisk = 0;		/* use whole disk for EFI (-E) */
269 static int	io_debug = 0;		/* activate verbose mode (-d) */
270 static int	io_image = 0;		/* create image using geometry (-I) */
271 
272 static struct mboot *Bootblk;		/* pointer to cut/paste sector zero */
273 static char	*Bootsect;		/* pointer to sector zero buffer */
274 static char	*Nullsect;
275 static struct extvtoc	disk_vtoc;	/* verify VTOC table */
276 static int	vt_inval = 0;
277 static int	no_virtgeom_ioctl = 0;	/* ioctl for virtual geometry failed */
278 static int	no_physgeom_ioctl = 0;	/* ioctl for physical geometry failed */
279 
280 static struct ipart	Table[FD_NUMPART];
281 static struct ipart	Old_Table[FD_NUMPART];
282 static int		skip_verify[FD_NUMPART]; /* special case skip sz chk */
283 
284 /* Disk geometry information */
285 static struct dk_minfo	minfo;
286 static struct dk_geom	disk_geom;
287 
288 static int Dev;			/* fd for open device */
289 
290 static diskaddr_t	dev_capacity;	/* number of blocks on device */
291 static diskaddr_t	chs_capacity;	/* Numcyl_usable * heads * sectors */
292 
293 static int		Numcyl_usable;	/* Number of usable cylinders */
294 					/*  used to limit fdisk to 2TB */
295 
296 /* Physical geometry for the drive */
297 static int	Numcyl;			/* number of cylinders */
298 static int	heads;			/* number of heads */
299 static int	sectors;		/* number of sectors per track */
300 static int	acyl;			/* number of alternate sectors */
301 
302 /* HBA (virtual) geometry for the drive */
303 static int	hba_Numcyl;		/* number of cylinders */
304 static int	hba_heads;		/* number of heads */
305 static int	hba_sectors;		/* number of sectors per track */
306 
307 static int	sectsiz;		/* sector size */
308 
309 /* Load functions for fdisk table modification */
310 #define	LOADFILE	0	/* load fdisk from file */
311 #define	LOADDEL		1	/* delete an fdisk entry */
312 #define	LOADADD		2	/* add an fdisk entry */
313 
314 #define	CBUFLEN 80
315 static char s[CBUFLEN];
316 
317 static void update_disk_and_exit(boolean_t table_changed);
318 int main(int argc, char *argv[]);
319 static int read_geom(char *sgeom);
320 static void dev_mboot_read(void);
321 static void dev_mboot_write(off_t sect, char *buff, int bootsiz);
322 static void mboot_read(void);
323 static void fill_patt(void);
324 static void abs_read(void);
325 static void abs_write(void);
326 static void load(int funct, char *file);
327 static void Set_Table_CHS_Values(int ti);
328 static int insert_tbl(int id, int act,
329     int bhead, int bsect, int bcyl,
330     int ehead, int esect, int ecyl,
331     uint32_t rsect, uint32_t numsect);
332 static int entry_from_old_table(int id, int act,
333     int bhead, int bsect, int bcyl,
334     int ehead, int esect, int ecyl,
335     uint32_t rsect, uint32_t numsect);
336 static int verify_tbl(void);
337 static int pars_fdisk(char *line,
338     int *id, int *act,
339     int *bhead, int *bsect, int *bcyl,
340     int *ehead, int *esect, int *ecyl,
341     uint32_t *rsect, uint32_t *numsect);
342 static int validate_part(int id, uint32_t rsect, uint32_t numsect);
343 static void stage0(void);
344 static int pcreate(void);
345 static int specify(uchar_t tsystid);
346 static void dispmenu(void);
347 static int pchange(void);
348 static int ppartid(void);
349 static char pdelete(void);
350 static void rm_blanks(char *s);
351 static int getcyl(void);
352 static void disptbl(void);
353 static void print_Table(void);
354 static void copy_Table_to_Old_Table(void);
355 static void nulltbl(void);
356 static void copy_Bootblk_to_Table(void);
357 static void fill_ipart(char *bootptr, struct ipart *partp);
358 #ifdef sparc
359 uchar_t getbyte(char **bp);
360 uint32_t getlong(char **bp);
361 #endif
362 static void copy_Table_to_Bootblk(void);
363 static int TableChanged(void);
364 static void ffile_write(char *file);
365 static void fix_slice(void);
366 static int yesno(void);
367 static int readvtoc(void);
368 static int writevtoc(void);
369 static int efi_ioctl(int fd, int cmd, dk_efi_t *dk_ioc);
370 static int clear_efi(void);
371 static void clear_vtoc(int table, int part);
372 static int lecture_and_query(char *warning, char *devname);
373 static void sanity_check_provided_device(char *devname, int fd);
374 static char *get_node(char *devname);
375 
376 static void
377 update_disk_and_exit(boolean_t table_changed)
378 {
379 	if (table_changed) {
380 		/*
381 		 * Copy the new table back to the sector buffer
382 		 * and write it to disk
383 		 */
384 		copy_Table_to_Bootblk();
385 		dev_mboot_write(0, Bootsect, sectsiz);
386 	}
387 
388 	/* If the VTOC table is wrong fix it (truncation only) */
389 	if (io_adjt)
390 		fix_slice();
391 
392 	exit(0);
393 }
394 
395 
396 
397 /*
398  * main
399  * Process command-line options.
400  */
401 int
402 main(int argc, char *argv[])
403 {
404 	int c, i;
405 	extern	int optind;
406 	extern	char *optarg;
407 	int	errflg = 0;
408 	int	diag_cnt = 0;
409 	int openmode;
410 
411 	setbuf(stderr, 0);	/* so all output gets out on exit */
412 	setbuf(stdout, 0);
413 
414 	/* Process the options. */
415 	while ((c = getopt(argc, argv, "o:s:P:F:b:A:D:W:S:tTIhwvrndgGRBE"))
416 	    != EOF) {
417 		switch (c) {
418 
419 			case 'o':
420 				io_offset = (off_t)strtoull(optarg, 0, 0);
421 				continue;
422 			case 's':
423 				io_size = (off_t)strtoull(optarg, 0, 0);
424 				continue;
425 			case 'P':
426 				diag_cnt++;
427 				io_patt++;
428 				io_fatt = optarg;
429 				continue;
430 			case 'w':
431 				diag_cnt++;
432 				io_wrt++;
433 				continue;
434 			case 'r':
435 				diag_cnt++;
436 				io_rd++;
437 				continue;
438 			case 'd':
439 				io_debug++;
440 				continue;
441 			case 'I':
442 				io_image++;
443 				continue;
444 			case 'R':
445 				io_readonly++;
446 				continue;
447 			case 'S':
448 				diag_cnt++;
449 				io_sgeom = optarg;
450 				continue;
451 			case 'T':
452 				io_ADJT++;
453 				/* FALLTHRU */
454 			case 't':
455 				io_adjt++;
456 				continue;
457 			case 'B':
458 				io_wholedisk++;
459 				io_fdisk++;
460 				continue;
461 			case 'E':
462 				io_EFIdisk++;
463 				io_fdisk++;
464 				continue;
465 			case 'g':
466 				diag_cnt++;
467 				io_lgeom++;
468 				continue;
469 			case 'G':
470 				diag_cnt++;
471 				io_pgeom++;
472 				continue;
473 			case 'n':
474 				io_nifdisk++;
475 				io_fdisk++;
476 				continue;
477 			case 'F':
478 				io_fdisk++;
479 				io_ffdisk = optarg;
480 				continue;
481 			case 'b':
482 				io_mboot = optarg;
483 				continue;
484 			case 'W':
485 				/*
486 				 * If '-' is the -W argument, then write
487 				 * to standard output, otherwise write
488 				 * to the specified file.
489 				 */
490 				if (strncmp(optarg, "-", 1) == 0)
491 					stdo_flag = 1;
492 				else
493 					io_Wfdisk = optarg;
494 				io_fdisk++;
495 				continue;
496 			case 'A':
497 				io_fdisk++;
498 				io_Afdisk = optarg;
499 				continue;
500 			case 'D':
501 				io_fdisk++;
502 				io_Dfdisk = optarg;
503 				continue;
504 			case 'h':
505 				(void) fprintf(stderr, "%s\n", Usage);
506 				(void) fprintf(stderr, "%s\n", Usage1);
507 				exit(0);
508 				/* FALLTHRU */
509 			case 'v':
510 				v_flag = 1;
511 				continue;
512 			case '?':
513 				errflg++;
514 				break;
515 		}
516 		break;
517 	}
518 
519 	if (io_image && io_sgeom && diag_cnt == 1) {
520 		diag_cnt = 0;
521 	}
522 
523 	/* User option checking */
524 
525 	/* By default, run in interactive mode */
526 	if (!io_fdisk && !diag_cnt && !io_nifdisk) {
527 		io_ifdisk++;
528 		io_fdisk++;
529 	}
530 	if (((io_fdisk || io_adjt) && diag_cnt) || (diag_cnt > 1)) {
531 		errflg++;
532 	}
533 
534 	/* Was any error detected? */
535 	if (errflg || argc == optind) {
536 		(void) fprintf(stderr, "%s\n", Usage);
537 		(void) fprintf(stderr,
538 		    "\nDetailed help is available with the -h option.\n");
539 		exit(2);
540 	}
541 
542 
543 	/* Figure out the correct device node to open */
544 	Dfltdev = get_node(argv[optind]);
545 
546 	if (io_readonly)
547 		openmode = O_RDONLY;
548 	else
549 		openmode = O_RDWR|O_CREAT;
550 
551 	if ((Dev = open(Dfltdev, openmode, 0666)) == -1) {
552 		(void) fprintf(stderr,
553 		    "fdisk: Cannot open device %s.\n",
554 		    Dfltdev);
555 		exit(1);
556 	}
557 	/*
558 	 * not all disk (or disklike) drivers support DKIOCGMEDIAINFO
559 	 * in that case leave the minfo structure zeroed
560 	 */
561 	if (ioctl(Dev, DKIOCGMEDIAINFO, &minfo)) {
562 		memset(&minfo, 0, sizeof (minfo));
563 	}
564 
565 	/* Get the disk geometry */
566 	if (!io_image) {
567 		/* Get disk's HBA (virtual) geometry */
568 		errno = 0;
569 		if (ioctl(Dev, DKIOCG_VIRTGEOM, &disk_geom)) {
570 
571 			/*
572 			 * If ioctl isn't implemented on this platform, then
573 			 * turn off flag to print out virtual geometry (-v),
574 			 * otherwise use the virtual geometry.
575 			 */
576 
577 			if (errno == ENOTTY) {
578 				v_flag = 0;
579 				no_virtgeom_ioctl = 1;
580 			} else if (errno == EINVAL) {
581 				/*
582 				 * This means that the ioctl exists, but
583 				 * is invalid for this disk, meaning the
584 				 * disk doesn't have an HBA geometry
585 				 * (like, say, it's larger than 8GB).
586 				 */
587 				v_flag = 0;
588 				hba_Numcyl = hba_heads = hba_sectors = 0;
589 			} else {
590 				(void) fprintf(stderr,
591 				    "%s: Cannot get virtual disk geometry.\n",
592 				    argv[optind]);
593 				exit(1);
594 			}
595 		} else {
596 			/* save virtual geometry values obtained by ioctl */
597 			hba_Numcyl = disk_geom.dkg_ncyl;
598 			hba_heads = disk_geom.dkg_nhead;
599 			hba_sectors = disk_geom.dkg_nsect;
600 		}
601 
602 		errno = 0;
603 		if (ioctl(Dev, DKIOCG_PHYGEOM, &disk_geom)) {
604 			if (errno == ENOTTY) {
605 				no_physgeom_ioctl = 1;
606 			} else {
607 				(void) fprintf(stderr,
608 				    "%s: Cannot get physical disk geometry.\n",
609 				    argv[optind]);
610 				exit(1);
611 			}
612 
613 		}
614 		/*
615 		 * Call DKIOCGGEOM if the ioctls for physical and virtual
616 		 * geometry fail. Get both from this generic call.
617 		 */
618 		if (no_virtgeom_ioctl && no_physgeom_ioctl) {
619 			errno = 0;
620 			if (ioctl(Dev, DKIOCGGEOM, &disk_geom)) {
621 				(void) fprintf(stderr,
622 				    "%s: Cannot get disk label geometry.\n",
623 				    argv[optind]);
624 				exit(1);
625 			}
626 		}
627 
628 		Numcyl = disk_geom.dkg_ncyl;
629 		heads = disk_geom.dkg_nhead;
630 		sectors = disk_geom.dkg_nsect;
631 		sectsiz = 512;
632 		acyl = disk_geom.dkg_acyl;
633 
634 		/*
635 		 * if hba geometry was not set by DKIOC_VIRTGEOM
636 		 * or we got an invalid hba geometry
637 		 * then set hba geometry based on max values
638 		 */
639 		if (no_virtgeom_ioctl ||
640 		    disk_geom.dkg_ncyl == 0 ||
641 		    disk_geom.dkg_nhead == 0 ||
642 		    disk_geom.dkg_nsect == 0 ||
643 		    disk_geom.dkg_ncyl > MAX_CYL ||
644 		    disk_geom.dkg_nhead > MAX_HEAD ||
645 		    disk_geom.dkg_nsect > MAX_SECT) {
646 
647 			/*
648 			 * turn off flag to print out virtual geometry (-v)
649 			 */
650 			v_flag = 0;
651 			hba_sectors	= MAX_SECT;
652 			hba_heads	= MAX_HEAD + 1;
653 			hba_Numcyl	= (Numcyl * heads * sectors) /
654 			    (hba_sectors * hba_heads);
655 		}
656 
657 		if (io_debug) {
658 			(void) fprintf(stderr, "Physical Geometry:\n");
659 			(void) fprintf(stderr,
660 			    "  cylinders[%d] heads[%d] sectors[%d]\n"
661 			    "  sector size[%d] blocks[%d] mbytes[%d]\n",
662 			    Numcyl,
663 			    heads,
664 			    sectors,
665 			    sectsiz,
666 			    Numcyl * heads * sectors,
667 			    (Numcyl * heads * sectors * sectsiz) / 1048576);
668 			(void) fprintf(stderr, "Virtual (HBA) Geometry:\n");
669 			(void) fprintf(stderr,
670 			    "  cylinders[%d] heads[%d] sectors[%d]\n"
671 			    "  sector size[%d] blocks[%d] mbytes[%d]\n",
672 			    hba_Numcyl,
673 			    hba_heads,
674 			    hba_sectors,
675 			    sectsiz,
676 			    hba_Numcyl * hba_heads * hba_sectors,
677 			    (hba_Numcyl * hba_heads * hba_sectors * sectsiz) /
678 			    1048576);
679 		}
680 	}
681 
682 	/* If user has requested a geometry report just do it and exit */
683 	if (io_lgeom) {
684 		if (ioctl(Dev, DKIOCGGEOM, &disk_geom)) {
685 			(void) fprintf(stderr,
686 			    "%s: Cannot get disk label geometry.\n",
687 			    argv[optind]);
688 			exit(1);
689 		}
690 		Numcyl = disk_geom.dkg_ncyl;
691 		heads = disk_geom.dkg_nhead;
692 		sectors = disk_geom.dkg_nsect;
693 		sectsiz = 512;
694 		acyl = disk_geom.dkg_acyl;
695 		(void) printf("* Label geometry for device %s\n", Dfltdev);
696 		(void) printf(
697 		    "* PCYL     NCYL     ACYL     BCYL     NHEAD NSECT"
698 		    " SECSIZ\n");
699 		(void) printf("  %-8d %-8d %-8d %-8d %-5d %-5d %-6d\n",
700 		    Numcyl,
701 		    disk_geom.dkg_ncyl,
702 		    disk_geom.dkg_acyl,
703 		    disk_geom.dkg_bcyl,
704 		    heads,
705 		    sectors,
706 		    sectsiz);
707 		exit(0);
708 	} else if (io_pgeom) {
709 		if (ioctl(Dev, DKIOCG_PHYGEOM, &disk_geom)) {
710 			(void) fprintf(stderr,
711 			    "%s: Cannot get physical disk geometry.\n",
712 			    argv[optind]);
713 			exit(1);
714 		}
715 		(void) printf("* Physical geometry for device %s\n", Dfltdev);
716 		(void) printf(
717 		    "* PCYL     NCYL     ACYL     BCYL     NHEAD NSECT"
718 		    " SECSIZ\n");
719 		(void) printf("  %-8d %-8d %-8d %-8d %-5d %-5d %-6d\n",
720 		    disk_geom.dkg_pcyl,
721 		    disk_geom.dkg_ncyl,
722 		    disk_geom.dkg_acyl,
723 		    disk_geom.dkg_bcyl,
724 		    disk_geom.dkg_nhead,
725 		    disk_geom.dkg_nsect,
726 		    sectsiz);
727 		exit(0);
728 	} else if (io_sgeom) {
729 		if (read_geom(io_sgeom)) {
730 			exit(1);
731 		} else if (!io_image) {
732 			exit(0);
733 		}
734 	}
735 
736 	/*
737 	 * some drivers may not support DKIOCGMEDIAINFO
738 	 * in that case use CHS
739 	 */
740 	chs_capacity = (diskaddr_t)Numcyl * heads * sectors;
741 	dev_capacity = chs_capacity;
742 	Numcyl_usable = Numcyl;
743 
744 	if (chs_capacity > DK_MAX_2TB) {
745 		/* limit to 2TB */
746 		Numcyl_usable = DK_MAX_2TB / (heads * sectors);
747 		chs_capacity = (diskaddr_t)Numcyl_usable * heads * sectors;
748 	}
749 
750 	if (minfo.dki_capacity > 0)
751 		dev_capacity = minfo.dki_capacity;
752 
753 	/* Allocate memory to hold three complete sectors */
754 	Bootsect = (char *)malloc(3 * sectsiz);
755 	if (Bootsect == NULL) {
756 		(void) fprintf(stderr,
757 		    "fdisk: Unable to obtain enough buffer memory"
758 		    " (%d bytes).\n",
759 		    3 * sectsiz);
760 		exit(1);
761 	}
762 
763 	Nullsect = Bootsect + sectsiz;
764 	/* Zero out the "NULL" sector */
765 	for (i = 0; i < sectsiz; i++) {
766 		Nullsect[i] = 0;
767 	}
768 
769 	/* Find out what the user wants done */
770 	if (io_rd) {		/* abs disk read */
771 		abs_read();	/* will not return */
772 	} else if (io_wrt && !io_readonly) {
773 		abs_write();	/* will not return */
774 	} else if (io_patt && !io_readonly) {
775 		fill_patt();	/* will not return */
776 	}
777 
778 
779 	/* This is the fdisk edit, the real reason for the program.	*/
780 
781 	sanity_check_provided_device(Dfltdev, Dev);
782 
783 	/* Get the new BOOT program in case we write a new fdisk table */
784 	mboot_read();
785 
786 	/* Read from disk master boot */
787 	dev_mboot_read();
788 
789 	/*
790 	 * Verify and copy the device's fdisk table. This will be used
791 	 * as the prototype mboot if the device's mboot looks invalid.
792 	 */
793 	Bootblk = (struct mboot *)Bootsect;
794 	copy_Bootblk_to_Table();
795 
796 	/* save away a copy of Table in Old_Table for sensing changes */
797 	copy_Table_to_Old_Table();
798 
799 	/* Load fdisk table from specified file (-F fdisk_file) */
800 	if (io_ffdisk) {
801 		/* Load and verify user-specified table parameters */
802 		load(LOADFILE, io_ffdisk);
803 	}
804 
805 	/* Does user want to delete or add an entry? */
806 	if (io_Dfdisk) {
807 		load(LOADDEL, io_Dfdisk);
808 	}
809 	if (io_Afdisk) {
810 		load(LOADADD, io_Afdisk);
811 	}
812 
813 	if (!io_ffdisk && !io_Afdisk && !io_Dfdisk) {
814 		/* Check if there is no fdisk table */
815 		if (Table[0].systid == UNUSED || io_wholedisk || io_EFIdisk) {
816 			if (io_ifdisk && !io_wholedisk && !io_EFIdisk) {
817 				(void) printf(
818 				    "No fdisk table exists. The default"
819 				    " partition for the disk is:\n\n"
820 				    "  a 100%% \"SOLARIS System\" "
821 				    "partition\n\n"
822 				    "Type \"y\" to accept the default "
823 				    "partition,  otherwise type \"n\" to "
824 				    "edit the\n partition table.\n");
825 
826 				if (Numcyl > Numcyl_usable)
827 					(void) printf("WARNING: Disk is larger"
828 					    " than 2TB. Solaris partition will"
829 					    " be limited to 2 TB.\n");
830 			}
831 
832 			/* Edit the partition table as directed */
833 			if (io_wholedisk ||(io_ifdisk && yesno())) {
834 
835 				/* Default scenario */
836 				nulltbl();
837 				/* now set up UNIX System partition */
838 				Table[0].bootid = ACTIVE;
839 				Table[0].relsect = lel(heads * sectors);
840 
841 				Table[0].numsect =
842 				    lel((ulong_t)((Numcyl_usable - 1) *
843 				    heads * sectors));
844 
845 				Table[0].systid = SUNIXOS2;   /* Solaris */
846 
847 				/* calculate CHS values for table entry 0 */
848 				Set_Table_CHS_Values(0);
849 				update_disk_and_exit(B_TRUE);
850 			} else if (io_EFIdisk) {
851 				/* create an EFI partition for the whole disk */
852 				nulltbl();
853 				i = insert_tbl(EFI_PMBR, 0, 0, 0, 0, 0, 0, 0, 1,
854 				    (dev_capacity > DK_MAX_2TB) ? DK_MAX_2TB :
855 				    (dev_capacity - 1));
856 				if (i != 0) {
857 					(void) fprintf(stderr,
858 					    "Error creating EFI partition\n");
859 					exit(1);
860 				}
861 				update_disk_and_exit(B_TRUE);
862 			}
863 		}
864 	}
865 
866 	/* Display complete fdisk table entries for debugging purposes */
867 	if (io_debug) {
868 		(void) fprintf(stderr, "Partition Table Entry Values:\n");
869 		print_Table();
870 		if (io_ifdisk) {
871 			(void) fprintf(stderr, "\n");
872 			(void) fprintf(stderr, "Press Enter to continue.\n");
873 			(void) fgets(s, sizeof (s), stdin);
874 		}
875 	}
876 
877 	/* Interactive fdisk mode */
878 	if (io_ifdisk) {
879 		(void) printf(CLR_SCR);
880 		disptbl();
881 		for (;;) {
882 			stage0();
883 			copy_Bootblk_to_Table();
884 			disptbl();
885 		}
886 	}
887 
888 	/* If user wants to write the table to a file, do it */
889 	if (io_Wfdisk)
890 		ffile_write(io_Wfdisk);
891 	else if (stdo_flag)
892 		ffile_write((char *)stdout);
893 
894 	update_disk_and_exit(TableChanged() == 1);
895 	return (0);
896 }
897 
898 /*
899  * read_geom
900  * Read geometry from specified file (-S).
901  */
902 
903 static int
904 read_geom(char *sgeom)
905 {
906 	char	line[256];
907 	FILE *fp;
908 
909 	/* open the prototype file */
910 	if ((fp = fopen(sgeom, "r")) == NULL) {
911 		(void) fprintf(stderr, "fdisk: Cannot open file %s.\n",
912 		    io_sgeom);
913 		return (1);
914 	}
915 
916 	/* Read a line from the file */
917 	while (fgets(line, sizeof (line) - 1, fp)) {
918 		if (line[0] == '\0' || line[0] == '\n' || line[0] == '*')
919 			continue;
920 		else {
921 			line[strlen(line)] = '\0';
922 			if (sscanf(line, "%hu %hu %hu %hu %hu %hu %d",
923 			    &disk_geom.dkg_pcyl,
924 			    &disk_geom.dkg_ncyl,
925 			    &disk_geom.dkg_acyl,
926 			    &disk_geom.dkg_bcyl,
927 			    &disk_geom.dkg_nhead,
928 			    &disk_geom.dkg_nsect,
929 			    &sectsiz) != 7) {
930 				(void) fprintf(stderr,
931 				    "Syntax error:\n	\"%s\".\n",
932 				    line);
933 				return (1);
934 			}
935 			break;
936 		} /* else */
937 	} /* while (fgets(line, sizeof (line) - 1, fp)) */
938 
939 	if (!io_image) {
940 		if (ioctl(Dev, DKIOCSGEOM, &disk_geom)) {
941 			(void) fprintf(stderr,
942 			    "fdisk: Cannot set label geometry.\n");
943 			return (1);
944 		}
945 	} else {
946 		Numcyl = hba_Numcyl = disk_geom.dkg_ncyl;
947 		heads = hba_heads = disk_geom.dkg_nhead;
948 		sectors = hba_sectors = disk_geom.dkg_nsect;
949 		acyl = disk_geom.dkg_acyl;
950 	}
951 
952 	(void) fclose(fp);
953 	return (0);
954 }
955 
956 /*
957  * dev_mboot_read
958  * Read the master boot sector from the device.
959  */
960 static void
961 dev_mboot_read(void)
962 {
963 	if ((ioctl(Dev, DKIOCGMBOOT, Bootsect) < 0) && (errno != ENOTTY)) {
964 		perror("Error in ioctl DKIOCGMBOOT");
965 	}
966 	if (errno == 0)
967 		return;
968 	if (lseek(Dev, 0, SEEK_SET) == -1) {
969 		(void) fprintf(stderr,
970 		    "fdisk: Error seeking to partition table on %s.\n",
971 		    Dfltdev);
972 		if (!io_image)
973 			exit(1);
974 	}
975 	if (read(Dev, Bootsect, sectsiz) != sectsiz) {
976 		(void) fprintf(stderr,
977 		    "fdisk: Error reading partition table from %s.\n",
978 		    Dfltdev);
979 		if (!io_image)
980 			exit(1);
981 	}
982 }
983 
984 /*
985  * dev_mboot_write
986  * Write the master boot sector to the device.
987  */
988 static void
989 dev_mboot_write(off_t sect, char *buff, int bootsiz)
990 {
991 	int 	new_pt, old_pt, error;
992 	int	clr_efi = -1;
993 
994 	if (io_readonly)
995 		return;
996 
997 	if (io_debug) {
998 		(void) fprintf(stderr, "About to write fdisk table:\n");
999 		print_Table();
1000 		if (io_ifdisk) {
1001 			(void) fprintf(stderr, "Press Enter to continue.\n");
1002 			(void) fgets(s, sizeof (s), stdin);
1003 		}
1004 	}
1005 
1006 	/*
1007 	 * If the new table has any Solaris partitions and the old
1008 	 * table does not have an entry that describes it
1009 	 * exactly then clear the old vtoc (if any).
1010 	 */
1011 	for (new_pt = 0; new_pt < FD_NUMPART; new_pt++) {
1012 
1013 		/* We only care about potential Solaris parts. */
1014 		if (Table[new_pt].systid != SUNIXOS &&
1015 		    Table[new_pt].systid != SUNIXOS2)
1016 			continue;
1017 
1018 		/* Does the old table have an exact entry for the new entry? */
1019 		for (old_pt = 0; old_pt < FD_NUMPART; old_pt++) {
1020 
1021 			/* We only care about old Solaris partitions. */
1022 			if ((Old_Table[old_pt].systid == SUNIXOS) ||
1023 			    (Old_Table[old_pt].systid == SUNIXOS2)) {
1024 
1025 				/* Is this old one the same as a new one? */
1026 				if ((Old_Table[old_pt].relsect ==
1027 				    Table[new_pt].relsect) &&
1028 				    (Old_Table[old_pt].numsect ==
1029 				    Table[new_pt].numsect))
1030 					break; /* Yes */
1031 			}
1032 		}
1033 
1034 		/* Did a solaris partition change location or size? */
1035 		if (old_pt >= FD_NUMPART) {
1036 			/* Yes clear old vtoc */
1037 			if (io_debug) {
1038 				(void) fprintf(stderr,
1039 				    "Clearing VTOC labels from NEW"
1040 				    " table\n");
1041 			}
1042 			clear_vtoc(NEW, new_pt);
1043 		}
1044 	}
1045 
1046 
1047 	/* see if the old table had EFI */
1048 	for (old_pt = 0; old_pt < FD_NUMPART; old_pt++) {
1049 		if (Old_Table[old_pt].systid == EFI_PMBR) {
1050 			clr_efi = old_pt;
1051 		}
1052 	}
1053 
1054 	/* look to see if a EFI partition changed in relsect/numsect */
1055 	for (new_pt = 0; new_pt < FD_NUMPART; new_pt++) {
1056 		if (Table[new_pt].systid != EFI_PMBR)
1057 			continue;
1058 		for (old_pt = 0; old_pt < FD_NUMPART; old_pt++) {
1059 			if ((Old_Table[old_pt].systid ==
1060 			    Table[new_pt].systid) &&
1061 			    (Old_Table[old_pt].relsect ==
1062 			    Table[new_pt].relsect) &&
1063 			    (Old_Table[old_pt].numsect ==
1064 			    Table[new_pt].numsect))
1065 				break;
1066 		}
1067 
1068 		/*
1069 		 * if EFI partition changed, set the flag to clear
1070 		 * the EFI GPT
1071 		 */
1072 		if (old_pt == FD_NUMPART && Table[new_pt].begcyl != 0) {
1073 			clr_efi = 0;
1074 		}
1075 		break;
1076 	}
1077 
1078 	/* clear labels if necessary */
1079 	if (clr_efi >= 0) {
1080 		if (io_debug) {
1081 			(void) fprintf(stderr, "Clearing EFI labels\n");
1082 		}
1083 		if ((error = clear_efi()) != 0) {
1084 			if (io_debug) {
1085 				(void) fprintf(stderr,
1086 				    "\tError %d clearing EFI labels"
1087 				    " (probably no EFI labels exist)\n",
1088 				    error);
1089 			}
1090 		}
1091 	}
1092 
1093 	if ((ioctl(Dev, DKIOCSMBOOT, buff) == -1) && (errno != ENOTTY)) {
1094 		(void) fprintf(stderr,
1095 		    "fdisk: Error in ioctl DKIOCSMBOOT on %s.\n",
1096 		    Dfltdev);
1097 	}
1098 	if (errno == 0)
1099 		return;
1100 
1101 	/* write to disk drive */
1102 	if (lseek(Dev, sect, SEEK_SET) == -1) {
1103 		(void) fprintf(stderr,
1104 		    "fdisk: Error seeking to master boot record on %s.\n",
1105 		    Dfltdev);
1106 		exit(1);
1107 	}
1108 	if (write(Dev, buff, bootsiz) != bootsiz) {
1109 		(void) fprintf(stderr,
1110 		    "fdisk: Error writing master boot record to %s.\n",
1111 		    Dfltdev);
1112 		exit(1);
1113 	}
1114 }
1115 
1116 /*
1117  * mboot_read
1118  * Read the prototype boot records from the files.
1119  */
1120 static void
1121 mboot_read(void)
1122 {
1123 	int mDev, i;
1124 	struct ipart *part;
1125 
1126 #if defined(i386) || defined(sparc)
1127 	/*
1128 	 * If the master boot file hasn't been specified, use the
1129 	 * implementation architecture name to generate the default one.
1130 	 */
1131 	if (io_mboot == (char *)0) {
1132 		/*
1133 		 * Bug ID 1249035:
1134 		 *	The mboot file must be delivered on all platforms
1135 		 *	and installed in a non-platform-dependent
1136 		 *	directory; i.e., /usr/lib/fs/ufs.
1137 		 */
1138 		io_mboot = "/usr/lib/fs/ufs/mboot";
1139 	}
1140 
1141 	/* First read in the master boot record */
1142 
1143 	/* Open the master boot proto file */
1144 	if ((mDev = open(io_mboot, O_RDONLY, 0666)) == -1) {
1145 		(void) fprintf(stderr,
1146 		    "fdisk: Cannot open master boot file %s.\n",
1147 		    io_mboot);
1148 		exit(1);
1149 	}
1150 
1151 	/* Read the master boot program */
1152 	if (read(mDev, &BootCod, sizeof (struct mboot)) != sizeof
1153 	    (struct mboot)) {
1154 		(void) fprintf(stderr,
1155 		    "fdisk: Cannot read master boot file %s.\n",
1156 		    io_mboot);
1157 		exit(1);
1158 	}
1159 
1160 	/* Is this really a master boot record? */
1161 	if (les(BootCod.signature) != MBB_MAGIC) {
1162 		(void) fprintf(stderr,
1163 		    "fdisk: Invalid master boot file %s.\n", io_mboot);
1164 		(void) fprintf(stderr,
1165 		    "Bad magic number: is %x, but should be %x.\n",
1166 		    les(BootCod.signature), MBB_MAGIC);
1167 		exit(1);
1168 	}
1169 
1170 	(void) close(mDev);
1171 #else
1172 #error	fdisk needs to be ported to new architecture
1173 #endif
1174 
1175 	/* Zero out the partitions part of this record */
1176 	part = (struct ipart *)BootCod.parts;
1177 	for (i = 0; i < FD_NUMPART; i++, part++) {
1178 		(void) memset(part, 0, sizeof (struct ipart));
1179 	}
1180 
1181 }
1182 
1183 /*
1184  * fill_patt
1185  * Fill the disk with user/sector number pattern.
1186  */
1187 static void
1188 fill_patt(void)
1189 {
1190 	int	*buff_ptr, i;
1191 	off_t	*off_ptr;
1192 	int	io_fpatt = 0;
1193 	int	io_ipatt = 0;
1194 
1195 	if (strncmp(io_fatt, "#", 1) != 0) {
1196 		io_fpatt++;
1197 		io_ipatt = strtoul(io_fatt, 0, 0);
1198 		buff_ptr = (int *)Bootsect;
1199 		for (i = 0; i < sectsiz; i += 4, buff_ptr++)
1200 			*buff_ptr = io_ipatt;
1201 	}
1202 
1203 	/*
1204 	 * Fill disk with pattern based on block number.
1205 	 * Write to the disk at absolute relative block io_offset
1206 	 * for io_size blocks.
1207 	 */
1208 	while (io_size--) {
1209 		off_ptr = (off_t *)Bootsect;
1210 		if (!io_fpatt) {
1211 			for (i = 0; i < sectsiz;
1212 			    i += sizeof (off_t), off_ptr++)
1213 				*off_ptr = io_offset;
1214 		}
1215 		/* Write the data to disk */
1216 		if (lseek(Dev, (off_t)(sectsiz * io_offset++),
1217 		    SEEK_SET) == -1) {
1218 			(void) fprintf(stderr, "fdisk: Error seeking on %s.\n",
1219 			    Dfltdev);
1220 			exit(1);
1221 		}
1222 		if (write(Dev, Bootsect, sectsiz) != sectsiz) {
1223 			(void) fprintf(stderr, "fdisk: Error writing %s.\n",
1224 			    Dfltdev);
1225 			exit(1);
1226 		}
1227 	} /* while (--io_size); */
1228 }
1229 
1230 /*
1231  * abs_read
1232  * Read from the disk at absolute relative block io_offset for
1233  * io_size blocks. Write the data to standard ouput (-r).
1234  */
1235 static void
1236 abs_read(void)
1237 {
1238 	int c;
1239 
1240 	while (io_size--) {
1241 		if (lseek(Dev, (off_t)(sectsiz * io_offset++),
1242 		    SEEK_SET) == -1) {
1243 			(void) fprintf(stderr, "fdisk: Error seeking on %s.\n",
1244 			    Dfltdev);
1245 			exit(1);
1246 		}
1247 		if (read(Dev, Bootsect, sectsiz) != sectsiz) {
1248 			(void) fprintf(stderr, "fdisk: Error reading %s.\n",
1249 			    Dfltdev);
1250 			exit(1);
1251 		}
1252 
1253 		/* Write to standard ouptut */
1254 		if ((c = write(1, Bootsect, (unsigned)sectsiz)) != sectsiz) {
1255 			if (c >= 0) {
1256 				if (io_debug)
1257 					(void) fprintf(stderr,
1258 					    "fdisk: Output warning: %d of %d"
1259 					    " characters written.\n",
1260 					    c, sectsiz);
1261 				exit(2);
1262 			} else {
1263 				perror("write error on output file.");
1264 				exit(2);
1265 			}
1266 		} /* if ((c = write(1, Bootsect, (unsigned)sectsiz)) */
1267 			/* != sectsiz) */
1268 	} /* while (--io_size); */
1269 	exit(0);
1270 }
1271 
1272 /*
1273  * abs_write
1274  * Read the data from standard input. Write to the disk at
1275  * absolute relative block io_offset for io_size blocks (-w).
1276  */
1277 static void
1278 abs_write(void)
1279 {
1280 	int c, i;
1281 
1282 	while (io_size--) {
1283 		int part_exit = 0;
1284 		/* Read from standard input */
1285 		if ((c = read(0, Bootsect, (unsigned)sectsiz)) != sectsiz) {
1286 			if (c >= 0) {
1287 				if (io_debug)
1288 				(void) fprintf(stderr,
1289 				    "fdisk: WARNING: Incomplete read (%d of"
1290 				    " %d characters read) on input file.\n",
1291 				    c, sectsiz);
1292 				/* Fill pattern to mark partial sector in buf */
1293 				for (i = c; i < sectsiz; ) {
1294 					Bootsect[i++] = 0x41;
1295 					Bootsect[i++] = 0x62;
1296 					Bootsect[i++] = 0x65;
1297 					Bootsect[i++] = 0;
1298 				}
1299 				part_exit++;
1300 			} else {
1301 				perror("read error on input file.");
1302 				exit(2);
1303 			}
1304 
1305 		}
1306 		/* Write to disk drive */
1307 		if (lseek(Dev, (off_t)(sectsiz * io_offset++),
1308 		    SEEK_SET) == -1) {
1309 			(void) fprintf(stderr, "fdisk: Error seeking on %s.\n",
1310 			    Dfltdev);
1311 			exit(1);
1312 		}
1313 		if (write(Dev, Bootsect, sectsiz) != sectsiz) {
1314 			(void) fprintf(stderr, "fdisk: Error writing %s.\n",
1315 			    Dfltdev);
1316 			exit(1);
1317 		}
1318 		if (part_exit)
1319 		exit(0);
1320 	} /* while (--io_size); */
1321 	exit(1);
1322 }
1323 
1324 
1325 /*
1326  * load
1327  * Load will either read the fdisk table from a file or add or
1328  * delete an entry (-A, -D, -F).
1329  */
1330 
1331 static void
1332 load(int funct, char *file)
1333 {
1334 	int	id;
1335 	int	act;
1336 	int	bhead;
1337 	int	bsect;
1338 	int	bcyl;
1339 	int	ehead;
1340 	int	esect;
1341 	int	ecyl;
1342 	uint32_t	rsect;
1343 	uint32_t	numsect;
1344 	char	line[256];
1345 	int	i = 0;
1346 	int	j;
1347 	FILE *fp;
1348 
1349 	switch (funct) {
1350 
1351 	case LOADFILE:
1352 
1353 		/*
1354 		 * Zero out the table before loading it, which will
1355 		 * force it to be updated on disk later (-F
1356 		 * fdisk_file).
1357 		 */
1358 		nulltbl();
1359 
1360 		/* Open the prototype file */
1361 		if ((fp = fopen(file, "r")) == NULL) {
1362 			(void) fprintf(stderr,
1363 			    "fdisk: Cannot open prototype partition file %s.\n",
1364 			    file);
1365 			exit(1);
1366 		}
1367 
1368 		/* Read a line from the file */
1369 		while (fgets(line, sizeof (line) - 1, fp)) {
1370 			if (pars_fdisk(line, &id, &act, &bhead, &bsect,
1371 			    &bcyl, &ehead, &esect, &ecyl, &rsect, &numsect)) {
1372 				continue;
1373 			}
1374 
1375 			/*
1376 			 * Validate the partition. It cannot start at sector
1377 			 * 0 unless it is UNUSED or already exists
1378 			 */
1379 			if (validate_part(id, rsect, numsect) < 0) {
1380 				(void) fprintf(stderr,
1381 				    "fdisk: Error on entry \"%s\".\n",
1382 				    line);
1383 				exit(1);
1384 			}
1385 
1386 			if (entry_from_old_table(id, act, bhead, bsect,
1387 			    bcyl, ehead, esect, ecyl, rsect, numsect)) {
1388 				/*
1389 				 * If we got here it means we copied an
1390 				 * unmodified entry. So there is no need
1391 				 * to insert it in the table or do any
1392 				 * checks against disk size.
1393 				 *
1394 				 * This is a work around on the following
1395 				 * situation (for IDE disks, at least):
1396 				 * Different operation systems calculate
1397 				 * disk size different ways, of which there
1398 				 * are two main ways.
1399 				 *
1400 				 * The first, rounds the disk size to modulo
1401 				 * cylinder size (virtual made-up cylinder
1402 				 * usually based on maximum number of heads
1403 				 * and sectors in partition table fields).
1404 				 * Our OS's (for IDE) and most other "Unix"
1405 				 * type OS's do this.
1406 				 *
1407 				 * The second, uses every single block
1408 				 * on the disk (to maximize available space).
1409 				 * Since disk manufactures do not know about
1410 				 * "virtual cylinders", there are some number
1411 				 * of blocks that make up a partial cylinder
1412 				 * at the end of the disk.
1413 				 *
1414 				 * The difference between these two methods
1415 				 * is where the problem is. When one
1416 				 * tries to install Solaris/OpenSolaris on
1417 				 * a disk that has another OS using that
1418 				 * "partial cylinder", install fails. It fails
1419 				 * since fdisk thinks its asked to create a
1420 				 * partition with the -F option that contains
1421 				 * a partition that runs off the end of the
1422 				 * disk.
1423 				 */
1424 				continue;
1425 			}
1426 
1427 			/*
1428 			 * Find an unused entry to use and put the entry
1429 			 * in table
1430 			 */
1431 			if (insert_tbl(id, act, bhead, bsect, bcyl, ehead,
1432 			    esect, ecyl, rsect, numsect) < 0) {
1433 				(void) fprintf(stderr,
1434 				    "fdisk: Error on entry \"%s\".\n",
1435 				    line);
1436 				exit(1);
1437 			}
1438 		} /* while (fgets(line, sizeof (line) - 1, fp)) */
1439 
1440 		if (verify_tbl() < 0) {
1441 			(void) fprintf(stderr,
1442 			    "fdisk: Cannot create partition table\n");
1443 			exit(1);
1444 		}
1445 
1446 		(void) fclose(fp);
1447 		return;
1448 
1449 	case LOADDEL:
1450 
1451 		/* Parse the user-supplied deletion line (-D) */
1452 		if (pars_fdisk(file, &id, &act, &bhead, &bsect, &bcyl,
1453 		    &ehead, &esect, &ecyl, &rsect, &numsect)) {
1454 			(void) fprintf(stderr,
1455 			    "fdisk: Syntax error \"%s\"\n", file);
1456 			exit(1);
1457 		}
1458 
1459 		/* Find the exact entry in the table */
1460 		for (i = 0; i < FD_NUMPART; i++) {
1461 			if (Table[i].systid == id &&
1462 			    Table[i].bootid == act &&
1463 			    Table[i].beghead == bhead &&
1464 			    Table[i].begsect == ((bsect & 0x3f) |
1465 			    (uchar_t)((bcyl>>2) & 0xc0)) &&
1466 			    Table[i].begcyl == (uchar_t)(bcyl & 0xff) &&
1467 			    Table[i].endhead == ehead &&
1468 			    Table[i].endsect == ((esect & 0x3f) |
1469 			    (uchar_t)((ecyl>>2) & 0xc0)) &&
1470 			    Table[i].endcyl == (uchar_t)(ecyl & 0xff) &&
1471 			    Table[i].relsect == lel(rsect) &&
1472 			    Table[i].numsect == lel(numsect)) {
1473 
1474 				/*
1475 				 * Found the entry. Now move rest of
1476 				 * entries up toward the top of the
1477 				 * table, leaving available entries at
1478 				 * the end of the fdisk table.
1479 				 */
1480 				for (j = i; j < FD_NUMPART - 1; j++) {
1481 					Table[j].systid = Table[j + 1].systid;
1482 					Table[j].bootid = Table[j + 1].bootid;
1483 					Table[j].beghead = Table[j + 1].beghead;
1484 					Table[j].begsect = Table[j + 1].begsect;
1485 					Table[j].begcyl = Table[j + 1].begcyl;
1486 					Table[j].endhead = Table[j + 1].endhead;
1487 					Table[j].endsect = Table[j + 1].endsect;
1488 					Table[j].endcyl = Table[j + 1].endcyl;
1489 					Table[j].relsect = Table[j + 1].relsect;
1490 					Table[j].numsect = Table[j + 1].numsect;
1491 				}
1492 
1493 				/*
1494 				 * Mark the last entry as unused in case
1495 				 * all table entries were in use prior
1496 				 * to the deletion.
1497 				 */
1498 
1499 				Table[FD_NUMPART - 1].systid = UNUSED;
1500 				Table[FD_NUMPART - 1].bootid = 0;
1501 				return;
1502 			}
1503 		}
1504 		(void) fprintf(stderr,
1505 		    "fdisk: Entry does not match any existing partition:\n"
1506 		    "	\"%s\"\n",
1507 		    file);
1508 		exit(1);
1509 		/* FALLTHRU */
1510 
1511 	case LOADADD:
1512 
1513 		/* Parse the user-supplied addition line (-A) */
1514 		if (pars_fdisk(file, &id, &act, &bhead, &bsect, &bcyl, &ehead,
1515 		    &esect, &ecyl, &rsect, &numsect)) {
1516 			(void) fprintf(stderr,
1517 			    "fdisk: Syntax error \"%s\"\n", file);
1518 			exit(1);
1519 		}
1520 
1521 		/* Validate the partition. It cannot start at sector 0 */
1522 		if (rsect == 0) {
1523 			(void) fprintf(stderr,
1524 			    "fdisk: New partition cannot start at sector 0:\n"
1525 			    "   \"%s\".\n",
1526 			    file);
1527 			exit(1);
1528 		}
1529 
1530 		/*
1531 		 * if the user wishes to add an EFI partition, we need
1532 		 * more extensive validation.  rsect should be 1, and
1533 		 * numsect should equal the entire disk capacity - 1
1534 		 */
1535 
1536 		if (id == EFI_PMBR) {
1537 			if (rsect != 1) {
1538 				(void) fprintf(stderr,
1539 				    "fdisk: EFI partitions must start at sector"
1540 				    " 1 (input rsect = %d)\n", rsect);
1541 				exit(1);
1542 			}
1543 
1544 
1545 			if (dev_capacity > DK_MAX_2TB) {
1546 				if (numsect != DK_MAX_2TB) {
1547 					(void) fprintf(stderr,
1548 					    "fdisk: EFI partitions must "
1549 					    "encompass the entire maximum 2 TB "
1550 					    "(input numsect: %u - max: %llu)\n",
1551 					    numsect, (diskaddr_t)DK_MAX_2TB);
1552 				exit(1);
1553 				}
1554 			} else if (numsect != dev_capacity - 1) {
1555 				(void) fprintf(stderr,
1556 				    "fdisk: EFI partitions must encompass the "
1557 				    "entire disk\n"
1558 				    "(input numsect: %u - avail: %llu)\n",
1559 				    numsect,
1560 				    dev_capacity - 1);
1561 				exit(1);
1562 			}
1563 		}
1564 
1565 		/* Find unused entry for use and put entry in table */
1566 		if (insert_tbl(id, act, bhead, bsect, bcyl, ehead, esect,
1567 		    ecyl, rsect, numsect) < 0) {
1568 			(void) fprintf(stderr,
1569 			    "fdisk: Invalid entry could not be inserted:\n"
1570 			    "	\"%s\"\n",
1571 			    file);
1572 			exit(1);
1573 		}
1574 
1575 		/* Make sure new entry does not overlap existing entry */
1576 		if (verify_tbl() < 0) {
1577 			(void) fprintf(stderr,
1578 			    "fdisk: Cannot create partition \"%s\"\n", file);
1579 			exit(1);
1580 		}
1581 	} /* switch funct */
1582 }
1583 
1584 /*
1585  * Set_Table_CHS_Values
1586  *
1587  * This will calculate the CHS values for beginning and ending CHS
1588  * for a single partition table entry (ti) based on the relsect
1589  * and numsect values contained in the partion table entry.
1590  *
1591  * hba_heads and hba_sectors contain the number of heads and sectors.
1592  *
1593  * If the number of cylinders exceeds the MAX_CYL,
1594  * then maximum values will be placed in the corresponding chs entry.
1595  */
1596 static void
1597 Set_Table_CHS_Values(int ti)
1598 {
1599 	uint32_t	lba, cy, hd, sc;
1600 
1601 	lba = (uint32_t)Table[ti].relsect;
1602 	if (lba >= hba_heads * hba_sectors * MAX_CYL) {
1603 		/*
1604 		 * the lba address cannot be expressed in CHS value
1605 		 * so store the maximum CHS field values in the CHS fields.
1606 		 */
1607 		cy = MAX_CYL + 1;
1608 		hd = MAX_HEAD;
1609 		sc = MAX_SECT;
1610 	} else {
1611 		cy = lba / hba_sectors / hba_heads;
1612 		hd = lba / hba_sectors % hba_heads;
1613 		sc = lba % hba_sectors + 1;
1614 	}
1615 	Table[ti].begcyl = cy & 0xff;
1616 	Table[ti].beghead = (uchar_t)hd;
1617 	Table[ti].begsect = (uchar_t)(((cy >> 2) & 0xc0) | sc);
1618 
1619 	/*
1620 	 * This code is identical to the code above
1621 	 * except that it works on ending CHS values
1622 	 */
1623 	lba = (uint32_t)(Table[ti].relsect + Table[ti].numsect - 1);
1624 	if (lba >= hba_heads * hba_sectors * MAX_CYL) {
1625 		cy = MAX_CYL + 1;
1626 		hd = MAX_HEAD;
1627 		sc = MAX_SECT;
1628 	} else {
1629 		cy = lba / hba_sectors / hba_heads;
1630 		hd = lba / hba_sectors % hba_heads;
1631 		sc = lba % hba_sectors + 1;
1632 	}
1633 	Table[ti].endcyl = cy & 0xff;
1634 	Table[ti].endhead = (uchar_t)hd;
1635 	Table[ti].endsect = (uchar_t)(((cy >> 2) & 0xc0) | sc);
1636 }
1637 
1638 /*
1639  * insert_tbl
1640  * 	Insert entry into fdisk table. Check all user-supplied values
1641  *	for the entry, but not the validity relative to other table
1642  *	entries!
1643  */
1644 static int
1645 insert_tbl(
1646     int id, int act,
1647     int bhead, int bsect, int bcyl,
1648     int ehead, int esect, int ecyl,
1649     uint32_t rsect, uint32_t numsect)
1650 {
1651 	int	i;
1652 
1653 	/* validate partition size */
1654 	if (((diskaddr_t)rsect + numsect) > dev_capacity) {
1655 		(void) fprintf(stderr,
1656 		    "fdisk: Partition table exceeds the size of the disk.\n");
1657 		return (-1);
1658 	}
1659 
1660 
1661 	/* find UNUSED partition table entry */
1662 	for (i = 0; i < FD_NUMPART; i++) {
1663 		if (Table[i].systid == UNUSED) {
1664 			break;
1665 		}
1666 	}
1667 	if (i >= FD_NUMPART) {
1668 		(void) fprintf(stderr, "fdisk: Partition table is full.\n");
1669 		return (-1);
1670 	}
1671 
1672 
1673 	Table[i].systid = (uchar_t)id;
1674 	Table[i].bootid = (uchar_t)act;
1675 	Table[i].numsect = lel(numsect);
1676 	Table[i].relsect = lel(rsect);
1677 
1678 	/*
1679 	 * If we have been called with a valid geometry, use it
1680 	 * valid means non-zero values that fit in the BIOS fields
1681 	 */
1682 	if (0 < bsect && bsect <= MAX_SECT &&
1683 	    0 <= bhead && bhead <= MAX_HEAD &&
1684 	    0 < esect && esect <= MAX_SECT &&
1685 	    0 <= ehead && ehead <= MAX_HEAD) {
1686 		if (bcyl > MAX_CYL)
1687 			bcyl = MAX_CYL + 1;
1688 		if (ecyl > MAX_CYL)
1689 			ecyl = MAX_CYL + 1;
1690 		Table[i].begcyl = bcyl & 0xff;
1691 		Table[i].endcyl = ecyl & 0xff;
1692 		Table[i].beghead = (uchar_t)bhead;
1693 		Table[i].endhead = (uchar_t)ehead;
1694 		Table[i].begsect = (uchar_t)(((bcyl >> 2) & 0xc0) | bsect);
1695 		Table[i].endsect = ((ecyl >> 2) & 0xc0) | esect;
1696 	} else {
1697 
1698 		/*
1699 		 * The specified values are invalid,
1700 		 * so calculate the values based on hba_heads, hba_sectors
1701 		 */
1702 		Set_Table_CHS_Values(i);
1703 	}
1704 
1705 	/*
1706 	 * return partition index
1707 	 */
1708 	return (i);
1709 }
1710 
1711 /*
1712  * entry_from_old_table
1713  *	If the specified entry is in the old table and is not a Solaris entry
1714  *	then insert same entry into new fdisk table. If we do this then
1715  *	all checks are skipped for that entry!
1716  */
1717 static int
1718 entry_from_old_table(
1719     int id, int act,
1720     int bhead, int bsect, int bcyl,
1721     int ehead, int esect, int ecyl,
1722     uint32_t rsect, uint32_t numsect)
1723 {
1724 	uint32_t	i, j;
1725 
1726 	if (id == SUNIXOS || id == SUNIXOS2)
1727 		return (0);
1728 	for (i = 0; i < FD_NUMPART - 1; i++) {
1729 		if (Old_Table[i].systid == id &&
1730 		    Old_Table[i].bootid == act &&
1731 		    Old_Table[i].beghead == bhead &&
1732 		    Old_Table[i].begsect == ((bsect & 0x3f) |
1733 		    (uchar_t)((bcyl>>2) & 0xc0)) &&
1734 		    Old_Table[i].begcyl == (uchar_t)(bcyl & 0xff) &&
1735 		    Old_Table[i].endhead == ehead &&
1736 		    Old_Table[i].endsect == ((esect & 0x3f) |
1737 		    (uchar_t)((ecyl>>2) & 0xc0)) &&
1738 		    Old_Table[i].endcyl == (uchar_t)(ecyl & 0xff) &&
1739 		    Old_Table[i].relsect == lel(rsect) &&
1740 		    Old_Table[i].numsect == lel(numsect)) {
1741 			/* find UNUSED partition table entry */
1742 			for (j = 0; j < FD_NUMPART; j++) {
1743 				if (Table[j].systid == UNUSED) {
1744 					(void) memcpy(&Table[j], &Old_Table[i],
1745 					    sizeof (Table[0]));
1746 					skip_verify[j] = 1;
1747 					return (1);
1748 
1749 				}
1750 			}
1751 			return (0);
1752 		}
1753 
1754 	}
1755 	return (0);
1756 }
1757 
1758 /*
1759  * verify_tbl
1760  * Verify that no partition entries overlap or exceed the size of
1761  * the disk.
1762  */
1763 static int
1764 verify_tbl(void)
1765 {
1766 	uint32_t	i, j, rsect, numsect;
1767 	int	noMoreParts = 0;
1768 	int	numParts = 0;
1769 
1770 	/* Make sure new entry does not overlap an existing entry */
1771 	for (i = 0; i < FD_NUMPART - 1; i++) {
1772 		if (Table[i].systid != UNUSED) {
1773 			numParts++;
1774 			/*
1775 			 * No valid partitions allowed after an UNUSED  or
1776 			 * EFI_PMBR part
1777 			 */
1778 			if (noMoreParts) {
1779 				return (-1);
1780 			}
1781 
1782 			/*
1783 			 * EFI_PMBR partitions must be the only partition
1784 			 * and must be Table entry 0
1785 			 */
1786 			if (Table[i].systid == EFI_PMBR) {
1787 				if (i == 0) {
1788 					noMoreParts = 1;
1789 				} else {
1790 					return (-1);
1791 				}
1792 
1793 				if (Table[i].relsect != 1) {
1794 					(void) fprintf(stderr, "ERROR: "
1795 					    "Invalid starting sector "
1796 					    "for EFI_PMBR partition:\n"
1797 					    "relsect %d "
1798 					    "(should be 1)\n",
1799 					    Table[i].relsect);
1800 
1801 					return (-1);
1802 				}
1803 
1804 				if (Table[i].numsect != dev_capacity - 1) {
1805 					(void) fprintf(stderr, "ERROR: "
1806 					    "EFI_PMBR partition must "
1807 					    "encompass the entire "
1808 					    "disk.\n numsect %d - "
1809 					    "actual %llu\n",
1810 					    Table[i].numsect,
1811 					    dev_capacity - 1);
1812 
1813 					return (-1);
1814 				}
1815 			}
1816 
1817 			/* make sure the partition isn't larger than the disk */
1818 			rsect = lel(Table[i].relsect);
1819 			numsect = lel(Table[i].numsect);
1820 
1821 			if ((((diskaddr_t)rsect + numsect) > dev_capacity) ||
1822 			    (((diskaddr_t)rsect + numsect) > DK_MAX_2TB)) {
1823 				if (!skip_verify[i])
1824 					return (-1);
1825 			}
1826 
1827 			for (j = i + 1; j < FD_NUMPART; j++) {
1828 				if (Table[j].systid != UNUSED) {
1829 					uint32_t t_relsect =
1830 					    lel(Table[j].relsect);
1831 					uint32_t t_numsect =
1832 					    lel(Table[j].numsect);
1833 
1834 					if (noMoreParts) {
1835 						(void) fprintf(stderr,
1836 						    "Cannot add partition to "
1837 						    "table; no more partitions "
1838 						    "allowed\n");
1839 
1840 						if (io_debug) {
1841 							(void) fprintf(stderr,
1842 							    "DEBUG: Current "
1843 							    "partition:\t"
1844 							    "%d:%d:%d:%d:%d:"
1845 							    "%d:%d:%d:%d:%d\n"
1846 							    "       Next "
1847 							    "partition:\t\t"
1848 							    "%d:%d:%d:%d:%d:"
1849 							    "%d:%d:%d:%d:%d\n",
1850 							    Table[i].systid,
1851 							    Table[i].bootid,
1852 							    Table[i].begcyl,
1853 							    Table[i].beghead,
1854 							    Table[i].begsect,
1855 							    Table[i].endcyl,
1856 							    Table[i].endhead,
1857 							    Table[i].endsect,
1858 							    Table[i].relsect,
1859 							    Table[i].numsect,
1860 							    Table[j].systid,
1861 							    Table[j].bootid,
1862 							    Table[j].begcyl,
1863 							    Table[j].beghead,
1864 							    Table[j].begsect,
1865 							    Table[j].endcyl,
1866 							    Table[j].endhead,
1867 							    Table[j].endsect,
1868 							    Table[j].relsect,
1869 							    Table[j].numsect);
1870 						}
1871 
1872 						return (-1);
1873 					}
1874 					if ((rsect >=
1875 					    (t_relsect + t_numsect)) ||
1876 					    ((rsect + numsect) <= t_relsect)) {
1877 						continue;
1878 					} else {
1879 						(void) fprintf(stderr, "ERROR: "
1880 						    "current partition overlaps"
1881 						    " following partition\n");
1882 
1883 						return (-1);
1884 					}
1885 				}
1886 			}
1887 		} else {
1888 			noMoreParts = 1;
1889 		}
1890 	}
1891 	if (Table[i].systid != UNUSED) {
1892 		if (noMoreParts)
1893 			return (-1);
1894 		if (!skip_verify[i] &&
1895 		    ((((diskaddr_t)lel(Table[i].relsect) +
1896 		    lel(Table[i].numsect)) > dev_capacity) ||
1897 		    (((diskaddr_t)lel(Table[i].relsect) +
1898 		    lel(Table[i].numsect)) > DK_MAX_2TB))) {
1899 			return (-1);
1900 		}
1901 	}
1902 
1903 	return (numParts);
1904 }
1905 
1906 /*
1907  * pars_fdisk
1908  * Parse user-supplied data to set up fdisk partitions
1909  * (-A, -D, -F).
1910  */
1911 static int
1912 pars_fdisk(
1913     char *line,
1914     int *id, int *act,
1915     int *bhead, int *bsect, int *bcyl,
1916     int *ehead, int *esect, int *ecyl,
1917     uint32_t *rsect, uint32_t *numsect)
1918 {
1919 	int	i;
1920 	if (line[0] == '\0' || line[0] == '\n' || line[0] == '*')
1921 		return (1);
1922 	line[strlen(line)] = '\0';
1923 	for (i = 0; i < strlen(line); i++) {
1924 		if (line[i] == '\0') {
1925 			break;
1926 		} else if (line[i] == ':') {
1927 			line[i] = ' ';
1928 		}
1929 	}
1930 	if (sscanf(line, "%d %d %d %d %d %d %d %d %u %u",
1931 	    id, act, bhead, bsect, bcyl, ehead, esect, ecyl,
1932 	    rsect, numsect) != 10) {
1933 		(void) fprintf(stderr, "Syntax error:\n	\"%s\".\n", line);
1934 		exit(1);
1935 	}
1936 	return (0);
1937 }
1938 
1939 /*
1940  * validate_part
1941  * Validate that a new partition does not start at sector 0. Only UNUSED
1942  * partitions and previously existing partitions are allowed to start at 0.
1943  */
1944 static int
1945 validate_part(int id, uint32_t rsect, uint32_t numsect)
1946 {
1947 	int i;
1948 	if ((id != UNUSED) && (rsect == 0)) {
1949 		for (i = 0; i < FD_NUMPART; i++) {
1950 			if ((Old_Table[i].systid == id) &&
1951 			    (Old_Table[i].relsect == lel(rsect)) &&
1952 			    (Old_Table[i].numsect == lel(numsect)))
1953 				return (0);
1954 		}
1955 		(void) fprintf(stderr,
1956 		    "New partition cannot start at sector 0\n");
1957 		return (-1);
1958 	}
1959 	return (0);
1960 }
1961 
1962 /*
1963  * stage0
1964  * Print out interactive menu and process user input.
1965  */
1966 static void
1967 stage0(void)
1968 {
1969 	dispmenu();
1970 	for (;;) {
1971 		(void) printf(Q_LINE);
1972 		(void) printf("Enter Selection: ");
1973 		(void) fgets(s, sizeof (s), stdin);
1974 		rm_blanks(s);
1975 		while (!((s[0] > '0') && (s[0] < '7') &&
1976 		    ((s[1] == '\0') || (s[1] == '\n')))) {
1977 			(void) printf(E_LINE); /* Clear any previous error */
1978 			(void) printf(
1979 			    "Enter a one-digit number between 1 and 6.");
1980 			(void) printf(Q_LINE);
1981 			(void) printf("Enter Selection: ");
1982 			(void) fgets(s, sizeof (s), stdin);
1983 			rm_blanks(s);
1984 		}
1985 		(void) printf(E_LINE);
1986 		switch (s[0]) {
1987 			case '1':
1988 				if (pcreate() == -1)
1989 					return;
1990 				break;
1991 			case '2':
1992 				if (pchange() == -1)
1993 					return;
1994 				break;
1995 			case '3':
1996 				if (pdelete() == -1)
1997 					return;
1998 				break;
1999 			case '4':
2000 				if (ppartid() == -1)
2001 					return;
2002 				break;
2003 			case '5':
2004 				/* update disk partition table, if changed */
2005 				if (TableChanged() == 1) {
2006 					copy_Table_to_Bootblk();
2007 					dev_mboot_write(0, Bootsect, sectsiz);
2008 				}
2009 				/*
2010 				 * If the VTOC table is wrong fix it
2011 				 * (truncate only)
2012 				 */
2013 				if (io_adjt) {
2014 					fix_slice();
2015 				}
2016 				(void) close(Dev);
2017 				exit(0);
2018 				/* FALLTHRU */
2019 			case '6':
2020 				/*
2021 				 * If the VTOC table is wrong fix it
2022 				 * (truncate only)
2023 				 */
2024 				if (io_adjt) {
2025 					fix_slice();
2026 				}
2027 				(void) close(Dev);
2028 				exit(0);
2029 				/* FALLTHRU */
2030 			default:
2031 				break;
2032 		}
2033 		copy_Table_to_Bootblk();
2034 		disptbl();
2035 		dispmenu();
2036 	}
2037 }
2038 
2039 /*
2040  * pcreate
2041  * Create partition entry in the table (interactive mode).
2042  */
2043 static int
2044 pcreate(void)
2045 {
2046 	uchar_t tsystid = 'z';
2047 	int i, j;
2048 	uint32_t numsect;
2049 	int retCode = 0;
2050 
2051 	i = 0;
2052 	for (;;) {
2053 		if (i == FD_NUMPART) {
2054 			(void) printf(E_LINE);
2055 			(void) printf(
2056 			    "The partition table is full!\n"
2057 			    "You must delete a partition before creating"
2058 			    " a new one.\n");
2059 			return (-1);
2060 		}
2061 		if (Table[i].systid == UNUSED) {
2062 			break;
2063 		}
2064 		i++;
2065 	}
2066 
2067 	numsect = 0;
2068 	for (i = 0; i < FD_NUMPART; i++) {
2069 		if (Table[i].systid != UNUSED) {
2070 			numsect += lel(Table[i].numsect);
2071 		}
2072 		if (numsect >= chs_capacity) {
2073 			(void) printf(E_LINE);
2074 			(void) printf("There is no more room on the disk for"
2075 			    " another partition.\n");
2076 			(void) printf(
2077 			    "You must delete a partition before creating"
2078 			    " a new one.\n");
2079 			return (-1);
2080 		}
2081 	}
2082 	while (tsystid == 'z') {
2083 
2084 		/*
2085 		 * The question here is expanding to more than what is
2086 		 * allocated for question lines (Q_LINE) which garbles
2087 		 * at least warning line. Clearing warning line as workaround
2088 		 * for now.
2089 		 */
2090 
2091 		(void) printf(W_LINE);
2092 		(void) printf(Q_LINE);
2093 		(void) printf(
2094 		    "Select the partition type to create:\n"
2095 		    "   1=SOLARIS2  2=UNIX        3=PCIXOS     4=Other\n"
2096 		    "   5=DOS12     6=DOS16       7=DOSEXT     8=DOSBIG\n"
2097 		    "   9=DOS16LBA  A=x86 Boot    B=Diagnostic C=FAT32\n"
2098 		    "   D=FAT32LBA  E=DOSEXTLBA   F=EFI        0=Exit? ");
2099 		(void) fgets(s, sizeof (s), stdin);
2100 		rm_blanks(s);
2101 		if ((s[1] != '\0') && (s[1] != '\n')) {
2102 			(void) printf(E_LINE);
2103 			(void) printf("Invalid selection, try again.");
2104 			continue;
2105 		}
2106 		switch (s[0]) {
2107 		case '0':		/* exit */
2108 			(void) printf(E_LINE);
2109 			return (-1);
2110 		case '1':		/* Solaris partition */
2111 			tsystid = SUNIXOS2;
2112 			break;
2113 		case '2':		/* UNIX partition */
2114 			tsystid = UNIXOS;
2115 			break;
2116 		case '3':		/* PCIXOS partition */
2117 			tsystid = PCIXOS;
2118 			break;
2119 		case '4':		/* OTHEROS System partition */
2120 			tsystid = OTHEROS;
2121 			break;
2122 		case '5':
2123 			tsystid = DOSOS12; /* DOS 12 bit fat */
2124 			break;
2125 		case '6':
2126 			tsystid = DOSOS16; /* DOS 16 bit fat */
2127 			break;
2128 		case '7':
2129 			tsystid = EXTDOS;
2130 			break;
2131 		case '8':
2132 			tsystid = DOSHUGE;
2133 			break;
2134 		case '9':
2135 			tsystid = FDISK_FAT95;  /* FAT16, need extended int13 */
2136 			break;
2137 		case 'a':		/* x86 Boot partition */
2138 		case 'A':
2139 			tsystid = X86BOOT;
2140 			break;
2141 		case 'b':		/* Diagnostic boot partition */
2142 		case 'B':
2143 			tsystid = DIAGPART;
2144 			break;
2145 		case 'c':		/* FAT32 */
2146 		case 'C':
2147 			tsystid = FDISK_WINDOWS;
2148 			break;
2149 		case 'd':		/* FAT32 and need extended int13 */
2150 		case 'D':
2151 			tsystid = FDISK_EXT_WIN;
2152 			break;
2153 		case 'e':	/* Extended partition, need extended int13 */
2154 		case 'E':
2155 			tsystid = FDISK_EXTLBA;
2156 			break;
2157 		case 'f':
2158 		case 'F':
2159 			tsystid = EFI_PMBR;
2160 			break;
2161 		default:
2162 			(void) printf(E_LINE);
2163 			(void) printf("Invalid selection, try again.");
2164 			continue;
2165 		}
2166 	}
2167 
2168 	(void) printf(E_LINE);
2169 
2170 	if (tsystid != EFI_PMBR) {
2171 		(void) printf(W_LINE);
2172 		if ((dev_capacity > DK_MAX_2TB))
2173 			(void) printf("WARNING: Disk is larger than 2 TB. "
2174 			    "Upper limit is 2 TB for non-EFI partition ID\n");
2175 
2176 		/* create the new partition */
2177 		i = specify(tsystid);
2178 
2179 		if (i != -1) {
2180 			/* see if it should be the active partition */
2181 			(void) printf(E_LINE);
2182 			(void) printf(Q_LINE);
2183 
2184 			(void) printf(
2185 			    "Should this become the active partition? If "
2186 			    "yes, it  will be activated\n"
2187 			    "each time the computer is reset or turned on.\n"
2188 			    "Please type \"y\" or \"n\". ");
2189 
2190 			if (yesno()) {
2191 				(void) printf(E_LINE);
2192 				for (j = 0; j < FD_NUMPART; j++) {
2193 					if (j == i) {
2194 						Table[j].bootid = ACTIVE;
2195 						(void) printf(E_LINE);
2196 						(void) printf(
2197 						    "Partition %d is now "
2198 						    "the active partition.",
2199 						    j + 1);
2200 					} else {
2201 						Table[j].bootid = 0;
2202 					}
2203 				}
2204 			} else {
2205 				Table[i].bootid = 0;
2206 			}
2207 
2208 			/* set up the return code */
2209 			i = 1;
2210 		}
2211 	} else {
2212 		/*
2213 		 * partitions of type EFI_PMBR must be the only partitions in
2214 		 * the table
2215 		 *
2216 		 * First, make sure there were no errors the table is
2217 		 * empty
2218 		 */
2219 		retCode = verify_tbl();
2220 
2221 		if (retCode < 0) {
2222 			(void) fprintf(stderr,
2223 			    "fdisk: Cannot create EFI partition table; \n"
2224 			    "current partition table is invalid.\n");
2225 			return (-1);
2226 		} else if (retCode > 0) {
2227 			(void) printf(
2228 			    "An EFI partition must be the only partition on "
2229 			    "disk.  You may manually delete existing\n"
2230 			    "partitions, or fdisk can do it.\n"
2231 			    "Do you want fdisk to destroy existing "
2232 			    "partitions?\n"
2233 			    "Please type \"y\" or \"n\". ");
2234 
2235 			if (yesno()) {
2236 				nulltbl();
2237 			} else {
2238 				return (-1);
2239 			}
2240 		}
2241 
2242 		/* create the table entry - i should be 0 */
2243 		i = insert_tbl(tsystid, 0, 0, 0, 0, 0, 0, 0, 1,
2244 		    (dev_capacity > DK_MAX_2TB) ? DK_MAX_2TB:
2245 		    (dev_capacity - 1));
2246 
2247 		if (i != 0) {
2248 			(void) printf("Error creating EFI partition!!!\n");
2249 			i = -1;
2250 		} else {
2251 
2252 			/* EFI partitions are currently never active */
2253 			Table[i].bootid = 0;
2254 
2255 			/* set up the return code */
2256 			i = 1;
2257 		}
2258 	}
2259 
2260 	return (i);
2261 }
2262 
2263 /*
2264  * specify
2265  * Query the user to specify the size of the new partition in
2266  * terms of percentage of the disk or by specifying the starting
2267  * cylinder and length in cylinders.
2268  */
2269 static int
2270 specify(uchar_t tsystid)
2271 {
2272 	int	i, j, percent = -1;
2273 	int	cyl, cylen;
2274 	diskaddr_t first_free, size_free;
2275 	diskaddr_t max_free;
2276 	int	cyl_size;
2277 	struct ipart *partition[FD_NUMPART];
2278 
2279 	cyl_size = heads * sectors;
2280 
2281 	/*
2282 	 * make a local copy of the partition table
2283 	 * and sort it into relsect order
2284 	 */
2285 	for (i = 0; i < FD_NUMPART; i++)
2286 		partition[i] = &Table[i];
2287 
2288 	for (i = 0; i < FD_NUMPART - 1; i++) {
2289 		if (partition[i]->systid == UNUSED)
2290 			break;
2291 		for (j = i + 1; j < FD_NUMPART; j++) {
2292 			if (partition[j]->systid == UNUSED)
2293 				break;
2294 			if (lel(partition[j]->relsect) <
2295 			    lel(partition[i]->relsect)) {
2296 				struct ipart *temp = partition[i];
2297 				partition[i] = partition[j];
2298 				partition[j] = temp;
2299 			}
2300 		}
2301 	}
2302 
2303 
2304 	(void) printf(Q_LINE);
2305 	(void) printf(
2306 	    "Specify the percentage of disk to use for this partition\n"
2307 	    "(or type \"c\" to specify the size in cylinders). ");
2308 	(void) fgets(s, sizeof (s), stdin);
2309 	rm_blanks(s);
2310 	if (s[0] != 'c') {	/* Specify size in percentage of disk */
2311 		i = 0;
2312 		while ((s[i] != '\0') && (s[i] != '\n')) {
2313 			if (s[i] < '0' || s[i] > '9') {
2314 				(void) printf(E_LINE);
2315 				(void) printf("Invalid percentage value "
2316 				    "specified; retry the operation.");
2317 				return (-1);
2318 			}
2319 			i++;
2320 			if (i > 3) {
2321 				(void) printf(E_LINE);
2322 				(void) printf("Invalid percentage value "
2323 				    "specified; retry the operation.");
2324 				return (-1);
2325 			}
2326 		}
2327 		if ((percent = atoi(s)) > 100) {
2328 			(void) printf(E_LINE);
2329 			(void) printf(
2330 			    "Percentage value is too large. The value must be"
2331 			    " between 1 and 100;\nretry the operation.\n");
2332 			return (-1);
2333 		}
2334 		if (percent < 1) {
2335 			(void) printf(E_LINE);
2336 			(void) printf(
2337 			    "Percentage value is too small. The value must be"
2338 			    " between 1 and 100;\nretry the operation.\n");
2339 			return (-1);
2340 		}
2341 
2342 		if (percent == 100)
2343 			cylen = Numcyl_usable - 1;
2344 		else
2345 			cylen = (Numcyl_usable * percent) / 100;
2346 
2347 		/* Verify DOS12 partition doesn't exceed max size of 32MB. */
2348 		if ((tsystid == DOSOS12) &&
2349 		    ((long)((long)cylen * cyl_size) > MAXDOS)) {
2350 			int n;
2351 			n = MAXDOS * 100 / (int)(cyl_size) / Numcyl_usable;
2352 			(void) printf(E_LINE);
2353 			(void) printf("Maximum size for a DOS partition "
2354 			    "is %d%%; retry the operation.",
2355 			    n <= 100 ? n : 100);
2356 			return (-1);
2357 		}
2358 
2359 
2360 		max_free = 0;
2361 		for (i = 0; i < FD_NUMPART; i++) {
2362 
2363 			/*
2364 			 * check for free space before partition i
2365 			 * where i varies from 0 to 3
2366 			 *
2367 			 * freespace after partition 3 is unusable
2368 			 * because there are no free partitions
2369 			 *
2370 			 * freespace begins at the end of previous partition
2371 			 * or cylinder 1
2372 			 */
2373 			if (i) {
2374 				/* Not an empty table */
2375 				first_free = lel(partition[i - 1]->relsect) +
2376 				    lel(partition[i - 1]->numsect);
2377 			} else {
2378 				first_free = cyl_size;
2379 			}
2380 
2381 			/*
2382 			 * freespace ends before the current partition
2383 			 * or the end of the disk (chs end)
2384 			 */
2385 			if (partition[i]->systid == UNUSED) {
2386 				size_free = chs_capacity - first_free;
2387 			} else {
2388 				/*
2389 				 * Partition might start before cylinder 1.
2390 				 * Make sure free space is not negative.
2391 				 */
2392 				size_free =
2393 				    (lel(partition[i]->relsect > first_free)) ?
2394 				    (lel(partition[i]->relsect) - first_free) :
2395 				    0;
2396 			}
2397 
2398 			/* save largest free space */
2399 			if (max_free < size_free)
2400 				max_free = size_free;
2401 
2402 			if (((uint64_t)cylen * cyl_size) <= size_free) {
2403 				/* We found a place to use */
2404 				break;
2405 			}
2406 			if (partition[i]->systid == UNUSED) {
2407 				(void) printf(E_LINE);
2408 				max_free /= (cyl_size);
2409 				(void) fprintf(stderr, "fdisk: "
2410 				    "Maximum percentage available is %lld\n",
2411 				    100 * max_free / Numcyl_usable);
2412 				return (-1);
2413 			}
2414 		}
2415 
2416 		(void) printf(E_LINE);
2417 		if (i >= FD_NUMPART) {
2418 			(void) fprintf(stderr,
2419 			    "fdisk: Partition table is full.\n");
2420 			return (-1);
2421 		}
2422 
2423 		if ((i = insert_tbl(tsystid, 0, 0, 0, 0, 0, 0, 0,
2424 		    first_free, cylen * cyl_size)) >= 0)  {
2425 			return (i);
2426 		}
2427 		return (-1);
2428 	} else {
2429 
2430 		/* Specifying size in cylinders */
2431 		(void) printf(E_LINE);
2432 		(void) printf(Q_LINE);
2433 		(void) printf("Enter starting cylinder number: ");
2434 		if ((cyl = getcyl()) == -1) {
2435 			(void) printf(E_LINE);
2436 			(void) printf("Invalid number; retry the operation.");
2437 			return (-1);
2438 		}
2439 		if (cyl == 0) {
2440 			(void) printf(E_LINE);
2441 			(void) printf(
2442 			    "New partition cannot start at cylinder 0.\n");
2443 			return (-1);
2444 		}
2445 
2446 
2447 		if (cyl >= Numcyl_usable) {
2448 			(void) printf(E_LINE);
2449 			(void) printf(
2450 			    "Cylinder %d is out of bounds, "
2451 			    "the maximum is %d.\n",
2452 			    cyl, Numcyl_usable - 1);
2453 			return (-1);
2454 		}
2455 
2456 		(void) printf(Q_LINE);
2457 		(void) printf("Enter partition size in cylinders: ");
2458 		if ((cylen = getcyl()) == -1) {
2459 			(void) printf(E_LINE);
2460 			(void) printf("Invalid number, retry the operation.");
2461 			return (-1);
2462 		}
2463 
2464 		for (i = 0; i < FD_NUMPART; i++) {
2465 			uint32_t	t_relsect, t_numsect;
2466 
2467 			if (partition[i]->systid == UNUSED)
2468 				break;
2469 			t_relsect = lel(partition[i]->relsect);
2470 			t_numsect = lel(partition[i]->numsect);
2471 
2472 			if (cyl * cyl_size >= t_relsect &&
2473 			    cyl * cyl_size < t_relsect + t_numsect) {
2474 				(void) printf(E_LINE);
2475 				(void) printf(
2476 				    "Cylinder %d is already allocated"
2477 				    "\nretry the operation.",
2478 				    cyl);
2479 				return (-1);
2480 			}
2481 
2482 			if (cyl * cyl_size < t_relsect &&
2483 			    (cyl + cylen - 1) * cyl_size > t_relsect) {
2484 				(void) printf(E_LINE);
2485 				(void) printf(
2486 				    "Maximum size for partition is %u cylinders"
2487 				    "\nretry the operation.",
2488 				    (t_relsect - cyl * cyl_size) / cyl_size);
2489 				return (-1);
2490 			}
2491 		}
2492 
2493 		/* Verify partition doesn't exceed disk size or 2 TB */
2494 		if (cyl + cylen > Numcyl_usable) {
2495 			(void) printf(E_LINE);
2496 			if (Numcyl > Numcyl_usable) {
2497 				(void) printf(
2498 				    "Maximum size for partition is %d "
2499 				    "cylinders; \nretry the operation.",
2500 				    Numcyl_usable - cyl);
2501 			} else {
2502 				(void) printf(
2503 				    "Maximum size for partition is %d "
2504 				    "cylinders; \nretry the operation.",
2505 				    Numcyl_usable - cyl);
2506 			}
2507 			return (-1);
2508 		}
2509 
2510 		/* Verify DOS12 partition doesn't exceed max size of 32MB. */
2511 		if ((tsystid == DOSOS12) &&
2512 		    ((long)((long)cylen * cyl_size) > MAXDOS)) {
2513 			(void) printf(E_LINE);
2514 			(void) printf(
2515 			    "Maximum size for a %s partition is %ld cylinders;"
2516 			    "\nretry the operation.",
2517 			    Dstr, MAXDOS / (int)(cyl_size));
2518 			return (-1);
2519 		}
2520 
2521 		(void) printf(E_LINE);
2522 		i = insert_tbl(tsystid, 0, 0, 0, 0, 0, 0, 0,
2523 		    cyl * cyl_size, cylen * cyl_size);
2524 		if (i < 0)
2525 			return (-1);
2526 
2527 		if (verify_tbl() < 0) {
2528 			(void) printf(E_LINE);
2529 			(void) printf("fdisk: Cannot create partition table\n");
2530 			return (-1);
2531 		}
2532 
2533 		return (i);
2534 	}
2535 }
2536 
2537 /*
2538  * dispmenu
2539  * Display command menu (interactive mode).
2540  */
2541 static void
2542 dispmenu(void)
2543 {
2544 	(void) printf(M_LINE);
2545 	(void) printf(
2546 	    "SELECT ONE OF THE FOLLOWING:\n"
2547 	    "   1. Create a partition\n"
2548 	    "   2. Specify the active partition\n"
2549 	    "   3. Delete a partition\n"
2550 	    "   4. Change between Solaris and Solaris2 Partition IDs\n"
2551 	    "   5. Exit (update disk configuration and exit)\n"
2552 	    "   6. Cancel (exit without updating disk configuration)\n");
2553 }
2554 
2555 /*
2556  * pchange
2557  * Change the ACTIVE designation of a partition.
2558  */
2559 static int
2560 pchange(void)
2561 {
2562 	char s[80];
2563 	int i, j;
2564 
2565 	for (;;) {
2566 		(void) printf(Q_LINE);
2567 			{
2568 			(void) printf(
2569 			    "Specify the partition number to boot from"
2570 			    " (or specify 0 for none): ");
2571 			}
2572 		(void) fgets(s, sizeof (s), stdin);
2573 		rm_blanks(s);
2574 		if (((s[1] != '\0') && (s[1] != '\n')) ||
2575 		    (s[0] < '0') || (s[0] > '4')) {
2576 			(void) printf(E_LINE);
2577 			(void) printf(
2578 			    "Invalid response, please specify a number"
2579 			    " between 0 and 4.\n");
2580 		} else {
2581 			break;
2582 		}
2583 	}
2584 	if (s[0] == '0') {	/* No active partitions */
2585 		for (i = 0; i < FD_NUMPART; i++) {
2586 			if (Table[i].systid != UNUSED &&
2587 			    Table[i].bootid == ACTIVE)
2588 				Table[i].bootid = 0;
2589 		}
2590 		(void) printf(E_LINE);
2591 			(void) printf(
2592 			    "No partition is currently marked as active.");
2593 		return (0);
2594 	} else {	/* User has selected a partition to be active */
2595 		i = s[0] - '1';
2596 		if (Table[i].systid == UNUSED) {
2597 			(void) printf(E_LINE);
2598 			(void) printf("Partition does not exist.");
2599 			return (-1);
2600 		}
2601 		/* a DOS-DATA or EXT-DOS partition cannot be active */
2602 		else if ((Table[i].systid == DOSDATA) ||
2603 		    (Table[i].systid == EXTDOS) ||
2604 		    (Table[i].systid == FDISK_EXTLBA)) {
2605 			(void) printf(E_LINE);
2606 			(void) printf(
2607 			    "DOS-DATA, EXT_DOS and EXT_DOS_LBA partitions "
2608 			    "cannot be made active.\n");
2609 			(void) printf("Select another partition.");
2610 			return (-1);
2611 		}
2612 		Table[i].bootid = ACTIVE;
2613 		for (j = 0; j < FD_NUMPART; j++) {
2614 			if (j != i)
2615 			Table[j].bootid = 0;
2616 		}
2617 	}
2618 	(void) printf(E_LINE);
2619 		{
2620 		(void) printf(
2621 		    "Partition %d is now active. The system will start up"
2622 		    " from this\n", i + 1);
2623 		(void) printf("partition after the next reboot.");
2624 		}
2625 	return (1);
2626 }
2627 
2628 /*
2629  * Change between SOLARIS and SOLARIS2 partition id
2630  */
2631 static int
2632 ppartid(void)
2633 {
2634 	char	*p, s[80];
2635 	int	i;
2636 
2637 	for (;;) {
2638 		(void) printf(Q_LINE);
2639 		(void) printf("Specify the partition number to change"
2640 		    " (or enter 0 to exit): ");
2641 		if (!fgets(s, sizeof (s), stdin))
2642 			return (1);
2643 		i = strtol(s, &p, 10);
2644 
2645 		if (*p != '\n' || i < 0 || i > FD_NUMPART) {
2646 			(void) printf(E_LINE);
2647 			(void) printf(
2648 			    "Invalid response, retry the operation.\n");
2649 			continue;
2650 		}
2651 
2652 		if (i == 0) {
2653 			/* exit delete command */
2654 			(void) printf(E_LINE); /* clear error message */
2655 			return (1);
2656 		}
2657 
2658 		i -= 1;
2659 		if (Table[i].systid == SUNIXOS) {
2660 			Table[i].systid = SUNIXOS2;
2661 		} else if (Table[i].systid == SUNIXOS2) {
2662 			Table[i].systid = SUNIXOS;
2663 		} else {
2664 			(void) printf(E_LINE);
2665 			(void) printf(
2666 			    "Partition %d is not a Solaris partition.",
2667 			    i + 1);
2668 			continue;
2669 		}
2670 
2671 		(void) printf(E_LINE);
2672 		(void) printf("Partition %d has been changed.", i + 1);
2673 		return (1);
2674 	}
2675 }
2676 
2677 /*
2678  * pdelete
2679  * Remove partition entry from the table (interactive mode).
2680  */
2681 static char
2682 pdelete(void)
2683 {
2684 	char s[80];
2685 	int i, j;
2686 	char pactive;
2687 
2688 DEL1:	(void) printf(Q_LINE);
2689 	(void) printf("Specify the partition number to delete"
2690 	    " (or enter 0 to exit): ");
2691 	(void) fgets(s, sizeof (s), stdin);
2692 	rm_blanks(s);
2693 	if ((s[0] == '0')) {	/* exit delete command */
2694 		(void) printf(E_LINE);	/* clear error message */
2695 		return (1);
2696 	}
2697 	/* Accept only a single digit between 1 and 4 */
2698 	if (((s[1] != '\0') && (s[1] != '\n')) ||
2699 	    (i = atoi(s)) < 1 || i > FD_NUMPART) {
2700 		(void) printf(E_LINE);
2701 		(void) printf("Invalid response, retry the operation.\n");
2702 		goto DEL1;
2703 	} else {		/* Found a digit between 1 and 4 */
2704 		--i;	/* Structure begins with element 0 */
2705 	}
2706 
2707 	if (Table[i].systid == UNUSED) {
2708 		(void) printf(E_LINE);
2709 		(void) printf("Partition %d does not exist.", i + 1);
2710 		return (-1);
2711 	}
2712 
2713 	(void) printf(Q_LINE);
2714 	(void) printf("Are you sure you want to delete partition %d?"
2715 	    " This will make all files and \n", i + 1);
2716 	(void) printf("programs in this partition inaccessible (type"
2717 	    " \"y\" or \"n\"). ");
2718 
2719 	(void) printf(E_LINE);
2720 	if (! yesno()) {
2721 		return (1);
2722 	}
2723 
2724 	if (Table[i].bootid == ACTIVE) {
2725 		pactive = 1;
2726 	} else {
2727 		pactive = 0;
2728 	}
2729 
2730 	for (j = i; j < FD_NUMPART - 1; j++) {
2731 		Table[j] = Table[j + 1];
2732 	}
2733 
2734 	Table[j].systid = UNUSED;
2735 	Table[j].numsect = 0;
2736 	Table[j].relsect = 0;
2737 	Table[j].bootid = 0;
2738 	(void) printf(E_LINE);
2739 	(void) printf("Partition %d has been deleted.", i + 1);
2740 
2741 	if (pactive) {
2742 		(void) printf(" This was the active partition.");
2743 	}
2744 
2745 	return (1);
2746 }
2747 
2748 /*
2749  * rm_blanks
2750  * Remove blanks from strings of user responses.
2751  */
2752 static void
2753 rm_blanks(char *s)
2754 {
2755 	register int i, j;
2756 
2757 	for (i = 0; i < CBUFLEN; i++) {
2758 		if ((s[i] == ' ') || (s[i] == '\t'))
2759 			continue;
2760 		else
2761 			/* Found first non-blank character of the string */
2762 			break;
2763 	}
2764 	for (j = 0; i < CBUFLEN; j++, i++) {
2765 		if ((s[j] = s[i]) == '\0') {
2766 			/* Reached end of string */
2767 			return;
2768 		}
2769 	}
2770 }
2771 
2772 /*
2773  * getcyl
2774  * Take the user-specified cylinder number and convert it from a
2775  * string to a decimal value.
2776  */
2777 static int
2778 getcyl(void)
2779 {
2780 int slen, i, j;
2781 unsigned int cyl;
2782 	(void) fgets(s, sizeof (s), stdin);
2783 	rm_blanks(s);
2784 	slen = strlen(s);
2785 	if (s[slen - 1] == '\n')
2786 		slen--;
2787 	j = 1;
2788 	cyl = 0;
2789 	for (i = slen - 1; i >= 0; i--) {
2790 		if (s[i] < '0' || s[i] > '9') {
2791 			return (-1);
2792 		}
2793 		cyl += (j * (s[i] - '0'));
2794 		j *= 10;
2795 	}
2796 	return (cyl);
2797 }
2798 
2799 /*
2800  * disptbl
2801  * Display the current fdisk table; determine percentage
2802  * of the disk used for each partition.
2803  */
2804 static void
2805 disptbl(void)
2806 {
2807 	int i;
2808 	unsigned int startcyl, endcyl, length, percent, remainder;
2809 	char *stat, *type;
2810 	int is_pmbr = 0;
2811 
2812 	if ((heads == 0) || (sectors == 0)) {
2813 		(void) printf("WARNING: critical disk geometry information"
2814 		    " missing!\n");
2815 		(void) printf("\theads = %d, sectors = %d\n", heads, sectors);
2816 		exit(1);
2817 	}
2818 
2819 	(void) printf(HOME);
2820 	(void) printf(T_LINE);
2821 	(void) printf("             Total disk size is %d cylinders\n", Numcyl);
2822 	(void) printf("             Cylinder size is %d (512 byte) blocks\n\n",
2823 	    heads * sectors);
2824 	(void) printf(
2825 	    "                                               Cylinders\n");
2826 	(void) printf(
2827 	    "      Partition   Status    Type          Start   End   Length"
2828 	    "    %%\n");
2829 	(void) printf(
2830 	    "      =========   ======    ============  =====   ===   ======"
2831 	    "   ===");
2832 	for (i = 0; i < FD_NUMPART; i++) {
2833 		if (Table[i].systid == UNUSED) {
2834 			(void) printf("\n");
2835 			(void) printf(CLR_LIN);
2836 			continue;
2837 		}
2838 		if (Table[i].bootid == ACTIVE)
2839 			stat = Actvstr;
2840 		else
2841 			stat = NAstr;
2842 		switch (Table[i].systid) {
2843 		case UNIXOS:
2844 			type = Ustr;
2845 			break;
2846 		case SUNIXOS:
2847 			type = SUstr;
2848 			break;
2849 		case SUNIXOS2:
2850 			type = SU2str;
2851 			break;
2852 		case X86BOOT:
2853 			type = X86str;
2854 			break;
2855 		case DOSOS12:
2856 			type = Dstr;
2857 			break;
2858 		case DOSOS16:
2859 			type = D16str;
2860 			break;
2861 		case EXTDOS:
2862 			type = EDstr;
2863 			break;
2864 		case DOSDATA:
2865 			type = DDstr;
2866 			break;
2867 		case DOSHUGE:
2868 			type = DBstr;
2869 			break;
2870 		case PCIXOS:
2871 			type = PCstr;
2872 			break;
2873 		case DIAGPART:
2874 			type = DIAGstr;
2875 			break;
2876 		case FDISK_IFS:
2877 			type = IFSstr;
2878 			break;
2879 		case FDISK_AIXBOOT:
2880 			type = AIXstr;
2881 			break;
2882 		case FDISK_AIXDATA:
2883 			type = AIXDstr;
2884 			break;
2885 		case FDISK_OS2BOOT:
2886 			type = OS2str;
2887 			break;
2888 		case FDISK_WINDOWS:
2889 			type = WINstr;
2890 			break;
2891 		case FDISK_EXT_WIN:
2892 			type = EWINstr;
2893 			break;
2894 		case FDISK_FAT95:
2895 			type = FAT95str;
2896 			break;
2897 		case FDISK_EXTLBA:
2898 			type = EXTLstr;
2899 			break;
2900 		case FDISK_LINUX:
2901 			type = LINUXstr;
2902 			break;
2903 		case FDISK_CPM:
2904 			type = CPMstr;
2905 			break;
2906 		case FDISK_NOVELL3:
2907 			type = NOVstr;
2908 			break;
2909 		case FDISK_QNX4:
2910 			type = QNXstr;
2911 			break;
2912 		case FDISK_QNX42:
2913 			type = QNX2str;
2914 			break;
2915 		case FDISK_QNX43:
2916 			type = QNX3str;
2917 			break;
2918 		case FDISK_LINUXNAT:
2919 			type = LINNATstr;
2920 			break;
2921 		case FDISK_NTFSVOL1:
2922 			type = NTFSVOL1str;
2923 			break;
2924 		case FDISK_NTFSVOL2:
2925 			type = NTFSVOL2str;
2926 			break;
2927 		case FDISK_BSD:
2928 			type = BSDstr;
2929 			break;
2930 		case FDISK_NEXTSTEP:
2931 			type = NEXTSTEPstr;
2932 			break;
2933 		case FDISK_BSDIFS:
2934 			type = BSDIFSstr;
2935 			break;
2936 		case FDISK_BSDISWAP:
2937 			type = BSDISWAPstr;
2938 			break;
2939 		case EFI_PMBR:
2940 			type = EFIstr;
2941 			if (lel(Table[i].numsect) == DK_MAX_2TB)
2942 				is_pmbr = 1;
2943 
2944 			break;
2945 		default:
2946 			type = Ostr;
2947 			break;
2948 		}
2949 		startcyl = lel(Table[i].relsect) /
2950 		    (unsigned long)(heads * sectors);
2951 
2952 		if (lel(Table[i].numsect) == DK_MAX_2TB) {
2953 			endcyl = Numcyl - 1;
2954 			length = endcyl - startcyl + 1;
2955 		} else {
2956 			length = lel(Table[i].numsect) /
2957 			    (unsigned long)(heads * sectors);
2958 			if (lel(Table[i].numsect) %
2959 			    (unsigned long)(heads * sectors))
2960 				length++;
2961 			endcyl = startcyl + length - 1;
2962 		}
2963 
2964 		percent = length * 100 / Numcyl_usable;
2965 		if ((remainder = (length * 100 % Numcyl_usable)) != 0) {
2966 			if ((remainder * 100 / Numcyl_usable) > 50) {
2967 				/* round up */
2968 				percent++;
2969 			}
2970 			/* Else leave the percent as is since it's already */
2971 			/* rounded down */
2972 		}
2973 		if (percent > 100)
2974 			percent = 100;
2975 		(void) printf(
2976 		    "\n          %d       %s    %-12.12s   %4d  %4d    %4d"
2977 		    "    %3d",
2978 		    i + 1, stat, type, startcyl, endcyl, length, percent);
2979 	}
2980 
2981 	/* Print warning message if table is empty */
2982 	if (Table[0].systid == UNUSED) {
2983 		(void) printf(W_LINE);
2984 		(void) printf("WARNING: no partitions are defined!");
2985 	} else {
2986 		/* Clear the warning line */
2987 		(void) printf(W_LINE);
2988 
2989 		/* Print warning if disk > 2TB and is not EFI PMBR */
2990 		if (!is_pmbr && (dev_capacity > DK_MAX_2TB))
2991 			(void) printf("WARNING: Disk is larger than 2 TB. "
2992 			    "Upper limit is 2 TB for non-EFI partition ID\n");
2993 	}
2994 }
2995 
2996 /*
2997  * print_Table
2998  * Write the detailed fdisk table to standard error for
2999  * the selected disk device.
3000  */
3001 static void
3002 print_Table(void)
3003 {
3004 	int i;
3005 
3006 	(void) fprintf(stderr,
3007 	    "  SYSID ACT BHEAD BSECT BEGCYL   EHEAD ESECT ENDCYL   RELSECT"
3008 	    "   NUMSECT\n");
3009 
3010 	for (i = 0; i < FD_NUMPART; i++) {
3011 		(void) fprintf(stderr, "  %-5d ", Table[i].systid);
3012 		(void) fprintf(stderr, "%-3d ", Table[i].bootid);
3013 		(void) fprintf(stderr, "%-5d ", Table[i].beghead);
3014 		(void) fprintf(stderr, "%-5d ", Table[i].begsect & 0x3f);
3015 		(void) fprintf(stderr, "%-8d ",
3016 		    (((uint_t)Table[i].begsect & 0xc0) << 2) + Table[i].begcyl);
3017 
3018 		(void) fprintf(stderr, "%-5d ", Table[i].endhead);
3019 		(void) fprintf(stderr, "%-5d ", Table[i].endsect & 0x3f);
3020 		(void) fprintf(stderr, "%-8d ",
3021 		    (((uint_t)Table[i].endsect & 0xc0) << 2) + Table[i].endcyl);
3022 		(void) fprintf(stderr, "%-10u ", lel(Table[i].relsect));
3023 		(void) fprintf(stderr, "%-10u\n", lel(Table[i].numsect));
3024 
3025 	}
3026 }
3027 
3028 /*
3029  * copy_Table_to_Old_Table
3030  * Copy Table into Old_Table. The function only copies the systid,
3031  * numsect, relsect, and bootid values because they are the only
3032  * ones compared when determining if Table has changed.
3033  */
3034 static void
3035 copy_Table_to_Old_Table(void)
3036 {
3037 	int i;
3038 	for (i = 0; i < FD_NUMPART; i++)  {
3039 		(void) memcpy(&Old_Table[i], &Table[i], sizeof (Table[0]));
3040 	}
3041 }
3042 
3043 /*
3044  * nulltbl
3045  * Zero out the systid, numsect, relsect, and bootid values in the
3046  * fdisk table.
3047  */
3048 static void
3049 nulltbl(void)
3050 {
3051 	int i;
3052 
3053 	for (i = 0; i < FD_NUMPART; i++)  {
3054 		Table[i].systid = UNUSED;
3055 		Table[i].numsect = lel(UNUSED);
3056 		Table[i].relsect = lel(UNUSED);
3057 		Table[i].bootid = 0;
3058 		skip_verify[i] = 0;
3059 	}
3060 }
3061 
3062 /*
3063  * copy_Bootblk_to_Table
3064  * Copy the bytes from the boot record to an internal "Table".
3065  * All unused are padded with zeros starting at offset 446.
3066  */
3067 static void
3068 copy_Bootblk_to_Table(void)
3069 {
3070 	int i, j;
3071 	char *bootptr;
3072 	struct ipart iparts[FD_NUMPART];
3073 
3074 	/* Get an aligned copy of the partition tables */
3075 	(void) memcpy(iparts, Bootblk->parts, sizeof (iparts));
3076 	bootptr = (char *)iparts;	/* Points to start of partition table */
3077 	if (les(Bootblk->signature) != MBB_MAGIC)  {
3078 		/* Signature is missing */
3079 		nulltbl();
3080 		(void) memcpy(Bootblk->bootinst, &BootCod, BOOTSZ);
3081 		return;
3082 	}
3083 	/*
3084 	 * When the DOS fdisk command deletes a partition, it is not
3085 	 * recognized by the old algorithm.  The algorithm that
3086 	 * follows looks at each entry in the Bootrec and copies all
3087 	 * those that are valid.
3088 	 */
3089 	j = 0;
3090 	for (i = 0; i < FD_NUMPART; i++) {
3091 		if (iparts[i].systid == 0) {
3092 			/* Null entry */
3093 			bootptr += sizeof (struct ipart);
3094 		} else {
3095 			fill_ipart(bootptr, &Table[j]);
3096 			j++;
3097 			bootptr += sizeof (struct ipart);
3098 		}
3099 	}
3100 	for (i = j; i < FD_NUMPART; i++) {
3101 		Table[i].systid = UNUSED;
3102 		Table[i].numsect = lel(UNUSED);
3103 		Table[i].relsect = lel(UNUSED);
3104 		Table[i].bootid = 0;
3105 
3106 	}
3107 	/* For now, always replace the bootcode with ours */
3108 	(void) memcpy(Bootblk->bootinst, &BootCod, BOOTSZ);
3109 	copy_Table_to_Bootblk();
3110 }
3111 
3112 /*
3113  * fill_ipart
3114  * Initialize ipart structure values.
3115  */
3116 static void
3117 fill_ipart(char *bootptr, struct ipart *partp)
3118 {
3119 #ifdef sparc
3120 	/* Packing struct ipart for Sparc */
3121 	partp->bootid	= getbyte(&bootptr);
3122 	partp->beghead	= getbyte(&bootptr);
3123 	partp->begsect	= getbyte(&bootptr);
3124 	partp->begcyl	= getbyte(&bootptr);
3125 	partp->systid	= getbyte(&bootptr);
3126 	partp->endhead	= getbyte(&bootptr);
3127 	partp->endsect	= getbyte(&bootptr);
3128 	partp->endcyl	= getbyte(&bootptr);
3129 	partp->relsect	= (int32_t)getlong(&bootptr);
3130 	partp->numsect	= (int32_t)getlong(&bootptr);
3131 #else
3132 	*partp = *(struct ipart *)bootptr;
3133 #endif
3134 }
3135 
3136 /*
3137  * getbyte, getlong
3138  * 	Get a byte, a short, or a long (SPARC only).
3139  */
3140 #ifdef sparc
3141 uchar_t
3142 getbyte(char **bp)
3143 {
3144 	uchar_t	b;
3145 
3146 	b = (uchar_t)**bp;
3147 	*bp = *bp + 1;
3148 	return (b);
3149 }
3150 
3151 uint32_t
3152 getlong(char **bp)
3153 {
3154 	int32_t	b, bh, bl;
3155 
3156 	bh = ((**bp) << 8) | *(*bp + 1);
3157 	*bp += 2;
3158 	bl = ((**bp) << 8) | *(*bp + 1);
3159 	*bp += 2;
3160 
3161 	b = (bh << 16) | bl;
3162 	return ((uint32_t)b);
3163 }
3164 #endif
3165 
3166 /*
3167  * copy_Table_to_Bootblk
3168  * Copy the table into the 512 boot record. Note that the unused
3169  * entries will always be the last ones in the table and they are
3170  * marked with 100 in sysind. The the unused portion of the table
3171  * is padded with zeros in the bytes after the used entries.
3172  */
3173 static void
3174 copy_Table_to_Bootblk(void)
3175 {
3176 	struct ipart *boot_ptr, *tbl_ptr;
3177 
3178 	boot_ptr = (struct ipart *)Bootblk->parts;
3179 	tbl_ptr = (struct ipart *)&Table[0].bootid;
3180 	for (; tbl_ptr < (struct ipart *)&Table[FD_NUMPART].bootid;
3181 	    tbl_ptr++, boot_ptr++) {
3182 		if (tbl_ptr->systid == UNUSED)
3183 			(void) memset(boot_ptr, 0, sizeof (struct ipart));
3184 		else
3185 			(void) memcpy(boot_ptr, tbl_ptr, sizeof (struct ipart));
3186 	}
3187 	Bootblk->signature = les(MBB_MAGIC);
3188 }
3189 
3190 /*
3191  * TableChanged
3192  * 	Check for any changes in the partition table.
3193  */
3194 static int
3195 TableChanged(void)
3196 {
3197 	int i, changed;
3198 
3199 	changed = 0;
3200 	for (i = 0; i < FD_NUMPART; i++) {
3201 		if (memcmp(&Old_Table[i], &Table[i], sizeof (Table[0])) != 0) {
3202 			/* Partition table changed, write back to disk */
3203 			changed = 1;
3204 		}
3205 	}
3206 
3207 	return (changed);
3208 }
3209 
3210 /*
3211  * ffile_write
3212  * 	Display contents of partition table to standard output or
3213  *	another file name without writing it to the disk (-W file).
3214  */
3215 static void
3216 ffile_write(char *file)
3217 {
3218 	register int	i;
3219 	FILE *fp;
3220 
3221 	/*
3222 	 * If file isn't standard output, then it's a file name.
3223 	 * Open file and write it.
3224 	 */
3225 	if (file != (char *)stdout) {
3226 		if ((fp = fopen(file, "w")) == NULL) {
3227 			(void) fprintf(stderr,
3228 			    "fdisk: Cannot open output file %s.\n",
3229 			    file);
3230 			exit(1);
3231 		}
3232 	}
3233 	else
3234 		fp = stdout;
3235 
3236 	/*
3237 	 * Write the fdisk table information
3238 	 */
3239 	(void) fprintf(fp, "\n* %s default fdisk table\n", Dfltdev);
3240 	(void) fprintf(fp, "* Dimensions:\n");
3241 	(void) fprintf(fp, "*   %4d bytes/sector\n", sectsiz);
3242 	(void) fprintf(fp, "*   %4d sectors/track\n", sectors);
3243 	(void) fprintf(fp, "*   %4d tracks/cylinder\n", heads);
3244 	(void) fprintf(fp, "*   %4d cylinders\n", Numcyl);
3245 	(void) fprintf(fp, "*\n");
3246 	/* Write virtual (HBA) geometry, if required	*/
3247 	if (v_flag) {
3248 		(void) fprintf(fp, "* HBA Dimensions:\n");
3249 		(void) fprintf(fp, "*   %4d bytes/sector\n", sectsiz);
3250 		(void) fprintf(fp, "*   %4d sectors/track\n", hba_sectors);
3251 		(void) fprintf(fp, "*   %4d tracks/cylinder\n", hba_heads);
3252 		(void) fprintf(fp, "*   %4d cylinders\n", hba_Numcyl);
3253 		(void) fprintf(fp, "*\n");
3254 	}
3255 	(void) fprintf(fp, "* systid:\n");
3256 	(void) fprintf(fp, "*    1: DOSOS12\n");
3257 	(void) fprintf(fp, "*    2: PCIXOS\n");
3258 	(void) fprintf(fp, "*    4: DOSOS16\n");
3259 	(void) fprintf(fp, "*    5: EXTDOS\n");
3260 	(void) fprintf(fp, "*    6: DOSBIG\n");
3261 	(void) fprintf(fp, "*    7: FDISK_IFS\n");
3262 	(void) fprintf(fp, "*    8: FDISK_AIXBOOT\n");
3263 	(void) fprintf(fp, "*    9: FDISK_AIXDATA\n");
3264 	(void) fprintf(fp, "*   10: FDISK_0S2BOOT\n");
3265 	(void) fprintf(fp, "*   11: FDISK_WINDOWS\n");
3266 	(void) fprintf(fp, "*   12: FDISK_EXT_WIN\n");
3267 	(void) fprintf(fp, "*   14: FDISK_FAT95\n");
3268 	(void) fprintf(fp, "*   15: FDISK_EXTLBA\n");
3269 	(void) fprintf(fp, "*   18: DIAGPART\n");
3270 	(void) fprintf(fp, "*   65: FDISK_LINUX\n");
3271 	(void) fprintf(fp, "*   82: FDISK_CPM\n");
3272 	(void) fprintf(fp, "*   86: DOSDATA\n");
3273 	(void) fprintf(fp, "*   98: OTHEROS\n");
3274 	(void) fprintf(fp, "*   99: UNIXOS\n");
3275 	(void) fprintf(fp, "*  101: FDISK_NOVELL3\n");
3276 	(void) fprintf(fp, "*  119: FDISK_QNX4\n");
3277 	(void) fprintf(fp, "*  120: FDISK_QNX42\n");
3278 	(void) fprintf(fp, "*  121: FDISK_QNX43\n");
3279 	(void) fprintf(fp, "*  130: SUNIXOS\n");
3280 	(void) fprintf(fp, "*  131: FDISK_LINUXNAT\n");
3281 	(void) fprintf(fp, "*  134: FDISK_NTFSVOL1\n");
3282 	(void) fprintf(fp, "*  135: FDISK_NTFSVOL2\n");
3283 	(void) fprintf(fp, "*  165: FDISK_BSD\n");
3284 	(void) fprintf(fp, "*  167: FDISK_NEXTSTEP\n");
3285 	(void) fprintf(fp, "*  183: FDISK_BSDIFS\n");
3286 	(void) fprintf(fp, "*  184: FDISK_BSDISWAP\n");
3287 	(void) fprintf(fp, "*  190: X86BOOT\n");
3288 	(void) fprintf(fp, "*  191: SUNIXOS2\n");
3289 	(void) fprintf(fp, "*  238: EFI_PMBR\n");
3290 	(void) fprintf(fp, "*  239: EFI_FS\n");
3291 	(void) fprintf(fp, "*\n");
3292 	(void) fprintf(fp,
3293 	    "\n* Id    Act  Bhead  Bsect  Bcyl    Ehead  Esect  Ecyl"
3294 	    "    Rsect      Numsect\n");
3295 
3296 	for (i = 0; i < FD_NUMPART; i++) {
3297 		if (Table[i].systid != UNUSED)
3298 			(void) fprintf(fp,
3299 			    "  %-5d %-4d %-6d %-6d %-7d %-6d %-6d %-7d %-10u"
3300 			    " %-10u\n",
3301 			    Table[i].systid,
3302 			    Table[i].bootid,
3303 			    Table[i].beghead,
3304 			    Table[i].begsect & 0x3f,
3305 			    ((Table[i].begcyl & 0xff) | ((Table[i].begsect &
3306 			    0xc0) << 2)),
3307 			    Table[i].endhead,
3308 			    Table[i].endsect & 0x3f,
3309 			    ((Table[i].endcyl & 0xff) | ((Table[i].endsect &
3310 			    0xc0) << 2)),
3311 			    lel(Table[i].relsect),
3312 			    lel(Table[i].numsect));
3313 	}
3314 	if (fp != stdout)
3315 		(void) fclose(fp);
3316 }
3317 
3318 /*
3319  * fix_slice
3320  * 	Read the VTOC table on the Solaris partition and check that no
3321  *	slices exist that extend past the end of the Solaris partition.
3322  *	If no Solaris partition exists, nothing is done.
3323  */
3324 static void
3325 fix_slice(void)
3326 {
3327 	int	i;
3328 	uint32_t	numsect;
3329 
3330 	if (io_image) {
3331 		return;
3332 	}
3333 
3334 	for (i = 0; i < FD_NUMPART; i++) {
3335 		if (Table[i].systid == SUNIXOS || Table[i].systid == SUNIXOS2) {
3336 			/*
3337 			 * Only the size matters (not starting point), since
3338 			 * VTOC entries are relative to the start of
3339 			 * the partition.
3340 			 */
3341 			numsect = lel(Table[i].numsect);
3342 			break;
3343 		}
3344 	}
3345 
3346 	if (i >= FD_NUMPART) {
3347 		if (!io_nifdisk) {
3348 			(void) fprintf(stderr,
3349 			    "fdisk: No Solaris partition found - VTOC not"
3350 			    " checked.\n");
3351 		}
3352 		return;
3353 	}
3354 
3355 	if (readvtoc() != VTOC_OK) {
3356 		exit(1);		/* Failed to read the VTOC */
3357 	}
3358 	for (i = 0; i < V_NUMPAR; i++) {
3359 		/* Special case for slice two (entire disk) */
3360 		if (i == 2) {
3361 			if (disk_vtoc.v_part[i].p_start != 0) {
3362 				(void) fprintf(stderr,
3363 				    "slice %d starts at %llu, is not at"
3364 				    " start of partition",
3365 				    i, disk_vtoc.v_part[i].p_start);
3366 				if (!io_nifdisk) {
3367 					(void) printf(" adjust ?:");
3368 					if (yesno())
3369 						disk_vtoc.v_part[i].p_start = 0;
3370 				} else {
3371 					disk_vtoc.v_part[i].p_start = 0;
3372 					(void) fprintf(stderr, " adjusted!\n");
3373 				}
3374 
3375 			}
3376 			if (disk_vtoc.v_part[i].p_size != numsect) {
3377 				(void) fprintf(stderr,
3378 				    "slice %d size %llu does not cover"
3379 				    " complete partition",
3380 				    i, disk_vtoc.v_part[i].p_size);
3381 				if (!io_nifdisk) {
3382 					(void) printf(" adjust ?:");
3383 					if (yesno())
3384 						disk_vtoc.v_part[i].p_size =
3385 						    numsect;
3386 				} else {
3387 					disk_vtoc.v_part[i].p_size = numsect;
3388 					(void) fprintf(stderr, " adjusted!\n");
3389 				}
3390 			}
3391 			if (disk_vtoc.v_part[i].p_tag != V_BACKUP) {
3392 				(void) fprintf(stderr,
3393 				    "slice %d tag was %d should be %d",
3394 				    i, disk_vtoc.v_part[i].p_tag,
3395 				    V_BACKUP);
3396 				if (!io_nifdisk) {
3397 					(void) printf(" fix ?:");
3398 					if (yesno())
3399 						disk_vtoc.v_part[i].p_tag =
3400 						    V_BACKUP;
3401 				} else {
3402 					disk_vtoc.v_part[i].p_tag = V_BACKUP;
3403 					(void) fprintf(stderr, " fixed!\n");
3404 				}
3405 			}
3406 			continue;
3407 		}
3408 		if (io_ADJT) {
3409 			if (disk_vtoc.v_part[i].p_start > numsect ||
3410 			    disk_vtoc.v_part[i].p_start +
3411 			    disk_vtoc.v_part[i].p_size > numsect) {
3412 				(void) fprintf(stderr,
3413 				    "slice %d (start %llu, end %llu)"
3414 				    " is larger than the partition",
3415 				    i, disk_vtoc.v_part[i].p_start,
3416 				    disk_vtoc.v_part[i].p_start +
3417 				    disk_vtoc.v_part[i].p_size);
3418 				if (!io_nifdisk) {
3419 					(void) printf(" remove ?:");
3420 					if (yesno()) {
3421 						disk_vtoc.v_part[i].p_size = 0;
3422 						disk_vtoc.v_part[i].p_start = 0;
3423 						disk_vtoc.v_part[i].p_tag = 0;
3424 						disk_vtoc.v_part[i].p_flag = 0;
3425 					}
3426 				} else {
3427 					disk_vtoc.v_part[i].p_size = 0;
3428 					disk_vtoc.v_part[i].p_start = 0;
3429 					disk_vtoc.v_part[i].p_tag = 0;
3430 					disk_vtoc.v_part[i].p_flag = 0;
3431 					(void) fprintf(stderr,
3432 					    " removed!\n");
3433 				}
3434 			}
3435 			continue;
3436 		}
3437 		if (disk_vtoc.v_part[i].p_start > numsect) {
3438 			(void) fprintf(stderr,
3439 			    "slice %d (start %llu) is larger than the "
3440 			    "partition", i, disk_vtoc.v_part[i].p_start);
3441 			if (!io_nifdisk) {
3442 				(void) printf(" remove ?:");
3443 				if (yesno()) {
3444 					disk_vtoc.v_part[i].p_size = 0;
3445 					disk_vtoc.v_part[i].p_start = 0;
3446 					disk_vtoc.v_part[i].p_tag = 0;
3447 					disk_vtoc.v_part[i].p_flag = 0;
3448 				}
3449 			} else {
3450 				disk_vtoc.v_part[i].p_size = 0;
3451 				disk_vtoc.v_part[i].p_start = 0;
3452 				disk_vtoc.v_part[i].p_tag = 0;
3453 				disk_vtoc.v_part[i].p_flag = 0;
3454 				(void) fprintf(stderr,
3455 				" removed!\n");
3456 			}
3457 		} else if (disk_vtoc.v_part[i].p_start
3458 		    + disk_vtoc.v_part[i].p_size > numsect) {
3459 			(void) fprintf(stderr,
3460 			    "slice %d (end %llu) is larger"
3461 			    " than the partition",
3462 			    i,
3463 			    disk_vtoc.v_part[i].p_start +
3464 			    disk_vtoc.v_part[i].p_size);
3465 			if (!io_nifdisk) {
3466 				(void) printf(" adjust ?:");
3467 				if (yesno()) {
3468 					disk_vtoc.v_part[i].p_size = numsect;
3469 				}
3470 			} else {
3471 				disk_vtoc.v_part[i].p_size = numsect;
3472 				(void) fprintf(stderr, " adjusted!\n");
3473 			}
3474 		}
3475 	}
3476 #if 1		/* bh for now */
3477 	/* Make the VTOC look sane - ha ha */
3478 	disk_vtoc.v_version = V_VERSION;
3479 	disk_vtoc.v_sanity = VTOC_SANE;
3480 	disk_vtoc.v_nparts = V_NUMPAR;
3481 	if (disk_vtoc.v_sectorsz == 0)
3482 		disk_vtoc.v_sectorsz = NBPSCTR;
3483 #endif
3484 
3485 	/* Write the VTOC back to the disk */
3486 	if (!io_readonly)
3487 		(void) writevtoc();
3488 }
3489 
3490 /*
3491  * yesno
3492  * Get yes or no answer. Return 1 for yes and 0 for no.
3493  */
3494 
3495 static int
3496 yesno(void)
3497 {
3498 	char	s[80];
3499 
3500 	for (;;) {
3501 		(void) fgets(s, sizeof (s), stdin);
3502 		rm_blanks(s);
3503 		if (((s[1] != '\0') && (s[1] != '\n')) ||
3504 		    ((s[0] != 'y') && (s[0] != 'n'))) {
3505 			(void) printf(E_LINE);
3506 			(void) printf("Please answer with \"y\" or \"n\": ");
3507 			continue;
3508 		}
3509 		if (s[0] == 'y')
3510 			return (1);
3511 		else
3512 			return (0);
3513 	}
3514 }
3515 
3516 /*
3517  * readvtoc
3518  * 	Read the VTOC from the Solaris partition of the device.
3519  */
3520 static int
3521 readvtoc(void)
3522 {
3523 	int	i;
3524 	int	retval = VTOC_OK;
3525 
3526 	if ((i = read_extvtoc(Dev, &disk_vtoc)) < VTOC_OK) {
3527 		if (i == VT_EINVAL) {
3528 			(void) fprintf(stderr, "fdisk: Invalid VTOC.\n");
3529 			vt_inval++;
3530 			retval = VTOC_INVAL;
3531 		} else if (i == VT_ENOTSUP) {
3532 			(void) fprintf(stderr, "fdisk: partition may have EFI "
3533 			    "GPT\n");
3534 			retval = VTOC_NOTSUP;
3535 		} else {
3536 			(void) fprintf(stderr, "fdisk: Cannot read VTOC.\n");
3537 			retval = VTOC_RWERR;
3538 		}
3539 	}
3540 	return (retval);
3541 }
3542 
3543 /*
3544  * writevtoc
3545  * 	Write the VTOC to the Solaris partition on the device.
3546  */
3547 static int
3548 writevtoc(void)
3549 {
3550 	int	i;
3551 	int	retval = 0;
3552 
3553 	if ((i = write_extvtoc(Dev, &disk_vtoc)) != 0) {
3554 		if (i == VT_EINVAL) {
3555 			(void) fprintf(stderr,
3556 			    "fdisk: Invalid entry exists in VTOC.\n");
3557 			retval = VTOC_INVAL;
3558 		} else if (i == VT_ENOTSUP) {
3559 			(void) fprintf(stderr, "fdisk: partition may have EFI "
3560 			    "GPT\n");
3561 			retval = VTOC_NOTSUP;
3562 		} else {
3563 			(void) fprintf(stderr, "fdisk: Cannot write VTOC.\n");
3564 			retval = VTOC_RWERR;
3565 		}
3566 	}
3567 	return (retval);
3568 }
3569 
3570 /*
3571  * efi_ioctl
3572  * issues DKIOCSETEFI IOCTL
3573  * (duplicate of private efi_ioctl() in rdwr_efi.c
3574  */
3575 static int
3576 efi_ioctl(int fd, int cmd, dk_efi_t *dk_ioc)
3577 {
3578 	void *data = dk_ioc->dki_data;
3579 	int error;
3580 
3581 	dk_ioc->dki_data_64 = (uintptr_t)data;
3582 	error = ioctl(fd, cmd, (void *)dk_ioc);
3583 
3584 	return (error);
3585 }
3586 
3587 /*
3588  * clear_efi
3589  * Clear EFI labels from the EFI_PMBR partition on the device
3590  * This function is modeled on the libefi(3LIB) call efi_write()
3591  */
3592 static int
3593 clear_efi(void)
3594 {
3595 	struct dk_gpt	*efi_vtoc;
3596 	dk_efi_t	dk_ioc;
3597 
3598 	/*
3599 	 * see if we can read the EFI label
3600 	 */
3601 	if (efi_alloc_and_read(Dev, &efi_vtoc) < 0) {
3602 		return (VT_ERROR);
3603 	}
3604 
3605 	/*
3606 	 * set up the dk_ioc structure for writing
3607 	 */
3608 	dk_ioc.dki_lba = 1;
3609 	dk_ioc.dki_length = EFI_MIN_ARRAY_SIZE + efi_vtoc->efi_lbasize;
3610 
3611 	if ((dk_ioc.dki_data = calloc(dk_ioc.dki_length, 1)) == NULL) {
3612 		return (VT_ERROR);
3613 	}
3614 
3615 	/*
3616 	 * clear the primary label
3617 	 */
3618 	if (io_debug) {
3619 		(void) fprintf(stderr,
3620 		    "\tClearing primary EFI label at block %lld\n",
3621 		    dk_ioc.dki_lba);
3622 	}
3623 
3624 	if (efi_ioctl(Dev, DKIOCSETEFI, &dk_ioc) == -1) {
3625 		free(dk_ioc.dki_data);
3626 		switch (errno) {
3627 			case EIO:
3628 				return (VT_EIO);
3629 			case EINVAL:
3630 				return (VT_EINVAL);
3631 			default:
3632 				return (VT_ERROR);
3633 		}
3634 	}
3635 
3636 	/*
3637 	 * clear the backup partition table
3638 	 */
3639 	dk_ioc.dki_lba = efi_vtoc->efi_last_u_lba + 1;
3640 	dk_ioc.dki_length -= efi_vtoc->efi_lbasize;
3641 	dk_ioc.dki_data++;
3642 	if (io_debug) {
3643 		(void) fprintf(stderr,
3644 		    "\tClearing backup partition table at block %lld\n",
3645 		    dk_ioc.dki_lba);
3646 	}
3647 
3648 	if (efi_ioctl(Dev, DKIOCSETEFI, &dk_ioc) == -1) {
3649 		(void) fprintf(stderr, "\tUnable to clear backup EFI label at "
3650 		    "block %llu; errno %d\n", efi_vtoc->efi_last_u_lba + 1,
3651 		    errno);
3652 	}
3653 
3654 	/*
3655 	 * clear the backup label
3656 	 */
3657 	dk_ioc.dki_lba = efi_vtoc->efi_last_lba;
3658 	dk_ioc.dki_length = efi_vtoc->efi_lbasize;
3659 	dk_ioc.dki_data--;
3660 	if (io_debug) {
3661 		(void) fprintf(stderr, "\tClearing backup label at block "
3662 		    "%lld\n", dk_ioc.dki_lba);
3663 	}
3664 
3665 	if (efi_ioctl(Dev, DKIOCSETEFI, &dk_ioc) == -1) {
3666 		(void) fprintf(stderr,
3667 		    "\tUnable to clear backup EFI label at "
3668 		    "block %llu; errno %d\n",
3669 		    efi_vtoc->efi_last_lba,
3670 		    errno);
3671 	}
3672 
3673 	free(dk_ioc.dki_data);
3674 	efi_free(efi_vtoc);
3675 
3676 	return (0);
3677 }
3678 
3679 /*
3680  * clear_vtoc
3681  * 	Clear the VTOC from the current or previous Solaris partition on the
3682  *      device.
3683  */
3684 static void
3685 clear_vtoc(int table, int part)
3686 {
3687 	struct ipart *clr_table;
3688 	struct dk_label disk_label;
3689 	uint32_t pcyl, ncyl, count;
3690 	diskaddr_t backup_block, solaris_offset;
3691 	ssize_t bytes;
3692 	off_t seek_byte;
3693 
3694 #ifdef DEBUG
3695 	struct dk_label	read_label;
3696 #endif /* DEBUG */
3697 
3698 	if (table == OLD) {
3699 		clr_table = &Old_Table[part];
3700 	} else {
3701 		clr_table = &Table[part];
3702 	}
3703 
3704 	(void) memset(&disk_label, 0, sizeof (struct dk_label));
3705 
3706 	seek_byte = (off_t)(lel(clr_table->relsect) + VTOC_OFFSET) * sectsiz;
3707 
3708 	if (io_debug) {
3709 		(void) fprintf(stderr,
3710 		    "\tClearing primary VTOC at byte %llu (block %llu)\n",
3711 		    (uint64_t)seek_byte,
3712 		    (uint64_t)(lel(clr_table->relsect) + VTOC_OFFSET));
3713 	}
3714 
3715 	if (lseek(Dev, seek_byte, SEEK_SET) == -1) {
3716 		(void) fprintf(stderr,
3717 		    "\tError seeking to primary label at byte %llu\n",
3718 		    (uint64_t)seek_byte);
3719 		return;
3720 	}
3721 
3722 	bytes = write(Dev, &disk_label, sizeof (struct dk_label));
3723 
3724 	if (bytes != sizeof (struct dk_label)) {
3725 		(void) fprintf(stderr,
3726 		    "\tWarning: only %d bytes written to clear primary"
3727 		    " VTOC!\n", bytes);
3728 	}
3729 
3730 #ifdef DEBUG
3731 	if (lseek(Dev, seek_byte, SEEK_SET) == -1) {
3732 		(void) fprintf(stderr,
3733 		    "DEBUG: Error seeking to primary label at byte %llu\n",
3734 		    (uint64_t)seek_byte);
3735 		return;
3736 	} else {
3737 		(void) fprintf(stderr,
3738 		    "DEBUG: Successful lseek() to byte %llu\n",
3739 		    (uint64_t)seek_byte);
3740 	}
3741 
3742 	bytes = read(Dev, &read_label, sizeof (struct dk_label));
3743 
3744 	if (bytes != sizeof (struct dk_label)) {
3745 		(void) fprintf(stderr,
3746 		    "DEBUG: Warning: only %d bytes read of label\n",
3747 		    bytes);
3748 	}
3749 
3750 	if (memcmp(&disk_label, &read_label, sizeof (struct dk_label)) != 0) {
3751 		(void) fprintf(stderr,
3752 		    "DEBUG: Warning: disk_label and read_label differ!!!\n");
3753 	} else {
3754 		(void) fprintf(stderr, "DEBUG Good compare of disk_label and "
3755 		    "read_label\n");
3756 	}
3757 #endif /* DEBUG */
3758 
3759 	/* Clear backup label */
3760 	pcyl = lel(clr_table->numsect) / (heads * sectors);
3761 	solaris_offset = lel(clr_table->relsect);
3762 	ncyl = pcyl - acyl;
3763 
3764 	backup_block = ((ncyl + acyl - 1) *
3765 	    (heads * sectors)) + ((heads - 1) * sectors) + 1;
3766 
3767 	for (count = 1; count < 6; count++) {
3768 		seek_byte = (off_t)(solaris_offset + backup_block) * 512;
3769 
3770 		if (lseek(Dev, seek_byte, SEEK_SET) == -1) {
3771 			(void) fprintf(stderr,
3772 			    "\tError seeking to backup label at byte %llu on "
3773 			    "%s.\n", (uint64_t)seek_byte, Dfltdev);
3774 			return;
3775 		}
3776 
3777 		if (io_debug) {
3778 			(void) fprintf(stderr, "\tClearing backup VTOC at"
3779 			    " byte %llu (block %llu)\n",
3780 			    (uint64_t)seek_byte,
3781 			    (uint64_t)(solaris_offset + backup_block));
3782 		}
3783 
3784 		bytes = write(Dev, &disk_label, sizeof (struct dk_label));
3785 
3786 		if (bytes != sizeof (struct dk_label)) {
3787 			(void) fprintf(stderr,
3788 			    "\t\tWarning: only %d bytes written to "
3789 			    "clear backup VTOC at block %llu!\n", bytes,
3790 			    (uint64_t)(solaris_offset + backup_block));
3791 		}
3792 
3793 #ifdef DEBUG
3794 	if (lseek(Dev, seek_byte, SEEK_SET) == -1) {
3795 		(void) fprintf(stderr,
3796 		    "DEBUG: Error seeking to backup label at byte %llu\n",
3797 		    (uint64_t)seek_byte);
3798 		return;
3799 	} else {
3800 		(void) fprintf(stderr,
3801 		    "DEBUG: Successful lseek() to byte %llu\n",
3802 		    (uint64_t)seek_byte);
3803 	}
3804 
3805 	bytes = read(Dev, &read_label, sizeof (struct dk_label));
3806 
3807 	if (bytes != sizeof (struct dk_label)) {
3808 		(void) fprintf(stderr,
3809 		    "DEBUG: Warning: only %d bytes read of backup label\n",
3810 		    bytes);
3811 	}
3812 
3813 	if (memcmp(&disk_label, &read_label, sizeof (struct dk_label)) != 0) {
3814 		(void) fprintf(stderr,
3815 		    "DEBUG: Warning: disk_label and read_label differ!!!\n");
3816 	} else {
3817 		(void) fprintf(stderr,
3818 		    "DEBUG: Good compare of disk_label and backup "
3819 		    "read_label\n");
3820 	}
3821 #endif /* DEBUG */
3822 
3823 		backup_block += 2;
3824 	}
3825 }
3826 
3827 #define	FDISK_STANDARD_LECTURE \
3828 	"Fdisk is normally used with the device that " \
3829 	"represents the entire fixed disk.\n" \
3830 	"(For example, /dev/rdsk/c0d0p0 on x86 or " \
3831 	"/dev/rdsk/c0t5d0s2 on sparc).\n"
3832 
3833 #define	FDISK_LECTURE_NOT_SECTOR_ZERO \
3834 	"The device does not appear to include absolute\n" \
3835 	"sector 0 of the PHYSICAL disk " \
3836 	"(the normal location for an fdisk table).\n"
3837 
3838 #define	FDISK_LECTURE_NOT_FULL \
3839 	"The device does not appear to encompass the entire PHYSICAL disk.\n"
3840 
3841 #define	FDISK_LECTURE_NO_VTOC \
3842 	"Unable to find a volume table of contents.\n" \
3843 	"Cannot verify the device encompasses the full PHYSICAL disk.\n"
3844 
3845 #define	FDISK_LECTURE_NO_GEOM \
3846 	"Unable to get geometry from device.\n" \
3847 	"Cannot verify the device encompasses the full PHYSICAL disk.\n"
3848 
3849 #define	FDISK_SHALL_I_CONTINUE \
3850 	"Are you sure you want to continue? (y/n) "
3851 
3852 /*
3853  *  lecture_and_query
3854  *	Called when a sanity check fails.  This routine gives a warning
3855  *	specific to the check that fails, followed by a generic lecture
3856  *	about the "right" device to supply as input.  Then, if appropriate,
3857  *	it will prompt the user on whether or not they want to continue.
3858  *	Inappropriate times for prompting are when the user has selected
3859  *	non-interactive mode or read-only mode.
3860  */
3861 static int
3862 lecture_and_query(char *warning, char *devname)
3863 {
3864 	if (io_nifdisk)
3865 		return (0);
3866 
3867 	(void) fprintf(stderr, "WARNING: Device %s: \n", devname);
3868 	(void) fprintf(stderr, "%s", warning);
3869 	(void) fprintf(stderr, FDISK_STANDARD_LECTURE);
3870 	(void) fprintf(stderr, FDISK_SHALL_I_CONTINUE);
3871 
3872 	return (yesno());
3873 }
3874 
3875 static void
3876 sanity_check_provided_device(char *devname, int fd)
3877 {
3878 	struct extvtoc v;
3879 	struct dk_geom d;
3880 	struct part_info pi;
3881 	struct extpart_info extpi;
3882 	diskaddr_t totsize;
3883 	int idx = -1;
3884 
3885 	/*
3886 	 *  First try the PARTINFO ioctl.  If it works, we will be able
3887 	 *  to tell if they've specified the full disk partition by checking
3888 	 *  to see if they've specified a partition that starts at sector 0.
3889 	 */
3890 	if (ioctl(fd, DKIOCEXTPARTINFO, &extpi) != -1) {
3891 		if (extpi.p_start != 0) {
3892 			if (!lecture_and_query(FDISK_LECTURE_NOT_SECTOR_ZERO,
3893 			    devname)) {
3894 				(void) close(fd);
3895 				exit(1);
3896 			}
3897 		}
3898 	} else if (ioctl(fd, DKIOCPARTINFO, &pi) != -1) {
3899 		if (pi.p_start != 0) {
3900 			if (!lecture_and_query(FDISK_LECTURE_NOT_SECTOR_ZERO,
3901 			    devname)) {
3902 				(void) close(fd);
3903 				exit(1);
3904 			}
3905 		}
3906 	} else {
3907 		if ((idx = read_extvtoc(fd, &v)) < 0) {
3908 			if (!lecture_and_query(FDISK_LECTURE_NO_VTOC,
3909 			    devname)) {
3910 				(void) close(fd);
3911 				exit(1);
3912 			}
3913 			return;
3914 		}
3915 		if (ioctl(fd, DKIOCGGEOM, &d) == -1) {
3916 			perror(devname);
3917 			if (!lecture_and_query(FDISK_LECTURE_NO_GEOM,
3918 			    devname)) {
3919 				(void) close(fd);
3920 				exit(1);
3921 			}
3922 			return;
3923 		}
3924 		totsize = (diskaddr_t)d.dkg_ncyl * d.dkg_nhead * d.dkg_nsect;
3925 		if (v.v_part[idx].p_size != totsize) {
3926 			if (!lecture_and_query(FDISK_LECTURE_NOT_FULL,
3927 			    devname)) {
3928 				(void) close(fd);
3929 				exit(1);
3930 			}
3931 		}
3932 	}
3933 }
3934 
3935 
3936 /*
3937  * get_node
3938  * Called from main to construct the name of the device node to open.
3939  * Initially tries to stat the node exactly as provided, if that fails
3940  * we prepend the default path (/dev/rdsk/).
3941  */
3942 static char *
3943 get_node(char *devname)
3944 {
3945 	char *node;
3946 	struct stat statbuf;
3947 	size_t space;
3948 
3949 	/* Don't do anything if we are skipping device checks */
3950 	if (io_image)
3951 		return (devname);
3952 
3953 	node = devname;
3954 
3955 	/* Try the node as provided first */
3956 	if (stat(node, (struct stat *)&statbuf) == -1) {
3957 		/*
3958 		 * Copy the passed in string to a new buffer, prepend the
3959 		 * default path and try again.
3960 		 */
3961 		space = strlen(DEFAULT_PATH) + strlen(devname) + 1;
3962 
3963 		if ((node = malloc(space)) == NULL) {
3964 			(void) fprintf(stderr, "fdisk: Unable to obtain memory "
3965 			    "for device node.\n");
3966 			exit(1);
3967 		}
3968 
3969 		/* Copy over the default path and the provided node */
3970 		(void) strncpy(node, DEFAULT_PATH, strlen(DEFAULT_PATH));
3971 		space -= strlen(DEFAULT_PATH);
3972 		(void) strlcpy(node + strlen(DEFAULT_PATH), devname, space);
3973 
3974 		/* Try to stat it again */
3975 		if (stat(node, (struct stat *)&statbuf) == -1) {
3976 			/* Failed all options, give up */
3977 			(void) fprintf(stderr,
3978 			    "fdisk: Cannot stat device %s.\n",
3979 			    devname);
3980 			exit(1);
3981 		}
3982 	}
3983 
3984 	/* Make sure the device specified is the raw device */
3985 	if ((statbuf.st_mode & S_IFMT) != S_IFCHR) {
3986 		(void) fprintf(stderr,
3987 		    "fdisk: %s must be a raw device.\n", node);
3988 		exit(1);
3989 	}
3990 
3991 	return (node);
3992 }
3993