dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / fdisk / fdisk.c
blob86b5f7459fbf988ad1988c172975b2028fd5006a
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
26 /* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */
28 /* All Rights Reserved */
30 /* Copyright (c) 1987, 1988 Microsoft Corporation */
31 /* All Rights Reserved */
34 * PROGRAM: fdisk(1M)
35 * This program reads the partition table on the specified device and
36 * also reads the drive parameters. The user can perform various
37 * operations from a supplied menu or from the command line. Diagnostic
38 * options are also available.
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <ctype.h>
47 #include <sys/stat.h>
48 #include <sys/types.h>
49 #include <limits.h>
50 #include <sys/param.h>
51 #include <sys/systeminfo.h>
52 #include <sys/efi_partition.h>
53 #include <sys/byteorder.h>
54 #include <sys/systeminfo.h>
56 #include <sys/dktp/fdisk.h>
57 #include <sys/dkio.h>
58 #include <sys/vtoc.h>
59 #ifdef i386
60 #include <sys/tty.h>
61 #include <libfdisk.h>
62 #endif
64 #define CLR_SCR "\e[1;1H\e[0J"
65 #define CLR_LIN "\e[0K"
66 #define HOME "\e[1;1H\e[0K\e[2;1H\e[0K\e[3;1H\e[0K\e[4;1H\e[0K\e[5;1H\e[0K" \
67 "\e[6;1H\e[0K\e[7;1H\e[0K\e[8;1H\e[0K\e[9;1H\e[0K\e[10;1H\e[0K\e[1;1H"
68 #define Q_LINE "\e[22;1H\e[0K\e[21;1H\e[0K\e[20;1H\e[0K"
70 #ifdef i386
71 #define W_LINE "\e[11;1H\e[0K"
72 #else
73 #define W_LINE "\e[12;1H\e[0K\e[11;1H\e[0K"
74 #endif
76 #define E_LINE "\e[24;1H\e[0K\e[23;1H\e[0K"
78 #ifdef i386
79 #define M_LINE "\e[12;1H\e[0K\e[13;1H\e[0K\e[14;1H\e[0K\e[15;1H\e[0K" \
80 "\e[16;1H\e[0K\e[17;1H\e[0K\e[18;1H\e[0K\e[19;1H\e[0K\e[12;1H"
81 #else
82 #define M_LINE "\e[13;1H\e[0K\e[14;1H\e[0K\e[15;1H\e[0K\e[16;1H\e[0K\e[17;1H" \
83 "\e[0K\e[18;1H\e[0K\e[19;1H\e[0K\e[13;1H"
84 #endif
86 #define T_LINE "\e[1;1H\e[0K"
88 #define DEFAULT_PATH "/dev/rdsk/"
90 /* XXX - should be in fdisk.h, used by sd as well */
93 * the MAX values are the maximum usable values for BIOS chs values
94 * The MAX_CYL value of 1022 is the maximum usable value
95 * the value of 1023 is a fence value,
96 * indicating no CHS geometry exists for the corresponding LBA value.
97 * HEAD range [ 0 .. MAX_HEAD ], so number of heads is (MAX_HEAD + 1)
98 * SECT range [ 1 .. MAX_SECT ], so number of sectors is (MAX_SECT)
100 #define MAX_SECT (63)
101 #define MAX_CYL (1022)
102 #define MAX_HEAD (254)
104 #define DK_MAX_2TB UINT32_MAX /* Max # of sectors in 2TB */
106 /* for clear_vtoc() */
107 #define OLD 0
108 #define NEW 1
110 /* readvtoc/writevtoc return codes */
111 #define VTOC_OK 0 /* Good VTOC */
112 #define VTOC_INVAL 1 /* invalid VTOC */
113 #define VTOC_NOTSUP 2 /* operation not supported - EFI label */
114 #define VTOC_RWERR 3 /* couldn't read or write VTOC */
117 * Support for fdisk(1M) on the SPARC platform
118 * In order to convert little endian values to big endian for SPARC,
119 * byte/short and long values must be swapped.
120 * These swapping macros will be used to access information in the
121 * mboot and ipart structures.
124 #ifdef sparc
125 #define les(val) ((((val)&0xFF)<<8)|(((val)>>8)&0xFF))
126 #define lel(val) (((unsigned)(les((val)&0x0000FFFF))<<16) | \
127 (les((unsigned)((val)&0xffff0000)>>16)))
128 #else
129 #define les(val) (val)
130 #define lel(val) (val)
131 #endif
133 #if defined(_SUNOS_VTOC_16)
134 #define VTOC_OFFSET 1
135 #elif defined(_SUNOS_VTOC_8)
136 #define VTOC_OFFSET 0
137 #else
138 #error No VTOC format defined.
139 #endif
141 #ifdef i386
142 #define FDISK_KB (1024)
143 #define FDISK_MB (FDISK_KB * 1024)
144 #define FDISK_GB (FDISK_MB * 1024)
145 #define TRUE 1
147 #define FDISK_MAX_VALID_PART_ID 255
148 #define FDISK_MAX_VALID_PART_NUM_DIGITS 2
149 #define FDISK_MAX_VALID_PART_ID_DIGITS 3
151 /* Maximum number of digits for a valid partition size */
152 #define FDISK_MAX_VALID_CYL_NUM_DIGITS 10
154 /* Minimum partition size in cylinders */
155 #define FDISK_MIN_PART_SIZE 1
156 #endif
158 static char Usage[] = "Usage: fdisk\n"
159 "[ -A id:act:bhead:bsect:bcyl:ehead:esect:ecyl:rsect:numsect ]\n"
160 "[ -b masterboot ]\n"
161 "[ -D id:act:bhead:bsect:bcyl:ehead:esect:ecyl:rsect:numsect ]\n"
162 "[ -F fdisk_file ] [ -h ] [ -o offset ] [ -P fill_patt ] [ -s size ]\n"
163 "[ -S geom_file ] [ [ -v ] -W { creat_fdisk_file | - } ]\n"
164 "[ -w | r | d | n | I | B | E | g | G | R | t | T ] rdevice";
166 static char Usage1[] = " Partition options:\n"
167 " -A id:act:bhead:bsect:bcyl:ehead:esect:ecyl:rsect:numsect\n"
168 " Create a partition with specific attributes:\n"
169 " id = system id number (fdisk.h) for the partition type\n"
170 " act = active partition flag (0 is off and 128 is on)\n"
171 " bhead = beginning head for start of partition\n"
172 " bsect = beginning sector for start of partition\n"
173 " bcyl = beginning cylinder for start of partition\n"
174 " ehead = ending head for end of partition\n"
175 " esect = ending sector for end of partition\n"
176 " ecyl = ending cylinder for end of partition\n"
177 " rsect = sector number from start of disk for\n"
178 " start of partition\n"
179 " numsect = partition size in sectors\n"
180 " -b master_boot\n"
181 " Use master_boot as the master boot file.\n"
182 " -B Create one Solaris partition that uses the entire disk.\n"
183 " -E Create one EFI partition that uses the entire disk.\n"
184 " -D id:act:bhead:bsect:bcyl:ehead:esect:ecyl:rsect:numsect\n"
185 " Delete a partition. See attribute definitions for -A.\n"
186 " -F fdisk_file\n"
187 " Use fdisk_file to initialize on-line fdisk table.\n"
188 " -I Forego device checks. Generate a file image of what would go\n"
189 " on a disk using the geometry specified with the -S option.\n"
190 " -n Do not run in interactive mode.\n"
191 " -R Open the disk device as read-only.\n"
192 " -t Check and adjust VTOC to be consistent with fdisk table.\n"
193 " VTOC slices exceeding the partition size will be truncated.\n"
194 " -T Check and adjust VTOC to be consistent with fdisk table.\n"
195 " VTOC slices exceeding the partition size will be removed.\n"
196 " -W fdisk_file\n"
197 " Write on-disk table to fdisk_file.\n"
198 " -W - Write on-disk table to standard output.\n"
199 " -v Display virtual geometry. Must be used with the -W option.\n"
200 " Diagnostic options:\n"
201 " -d Activate debug information about progress.\n"
202 " -g Write label geometry to standard output:\n"
203 " PCYL number of physical cylinders\n"
204 " NCYL number of usable cylinders\n"
205 " ACYL number of alternate cylinders\n"
206 " BCYL cylinder offset\n"
207 " NHEADS number of heads\n"
208 " NSECTORS number of sectors per track\n"
209 " SECTSIZ size of a sector in bytes\n"
210 " -G Write physical geometry to standard output (see -g).\n"
211 " -h Issue this verbose help message.\n"
212 " -o offset\n"
213 " Block offset from start of disk (default 0). Ignored if\n"
214 " -P # specified.\n"
215 " -P fill_patt\n"
216 " Fill disk with pattern fill_patt. fill_patt can be decimal or\n"
217 " hexadecimal and is used as number for constant long word\n"
218 " pattern. If fill_patt is \"#\" then pattern of block #\n"
219 " for each block. Pattern is put in each block as long words\n"
220 " and fills each block (see -o and -s).\n"
221 " -r Read from a disk to stdout (see -o and -s).\n"
222 " -s size Number of blocks on which to perform operation (see -o).\n"
223 " -S geom_file\n"
224 " Use geom_file to set the label geometry (see -g).\n"
225 " -w Write to a disk from stdin (see -o and -s).";
227 static char Ostr[] = "Other OS";
228 static char Dstr[] = "DOS12";
229 static char D16str[] = "DOS16";
230 static char DDstr[] = "DOS-DATA";
231 static char EDstr[] = "EXT-DOS";
232 static char DBstr[] = "DOS-BIG";
233 static char PCstr[] = "PCIX";
234 static char Ustr[] = "UNIX System";
235 static char SUstr[] = "Solaris";
236 static char SU2str[] = "Solaris2";
237 static char X86str[] = "x86 Boot";
238 static char DIAGstr[] = "Diagnostic";
239 static char IFSstr[] = "IFS: NTFS";
240 static char AIXstr[] = "AIX Boot";
241 static char AIXDstr[] = "AIX Data";
242 static char OS2str[] = "OS/2 Boot";
243 static char WINstr[] = "Win95 FAT32";
244 static char EWINstr[] = "Ext Win95";
245 static char FAT95str[] = "FAT16 LBA";
246 static char EXTLstr[] = "EXT LBA";
247 static char LINUXstr[] = "Linux";
248 static char CPMstr[] = "CP/M";
249 static char NOV2str[] = "Netware 286";
250 static char NOVstr[] = "Netware 3.x+";
251 static char QNXstr[] = "QNX 4.x";
252 static char QNX2str[] = "QNX part 2";
253 static char QNX3str[] = "QNX part 3";
254 static char LINNATstr[] = "Linux native";
255 #ifdef i386
256 static char LINSWAPstr[] = "Linux swap";
257 #endif
258 static char NTFSVOL1str[] = "NT volset 1";
259 static char NTFSVOL2str[] = "NT volset 2";
260 static char BSDstr[] = "BSD OS";
261 static char NEXTSTEPstr[] = "NeXTSTEP";
262 static char BSDIFSstr[] = "BSDI FS";
263 static char BSDISWAPstr[] = "BSDI swap";
264 static char Actvstr[] = "Active";
265 static char EFIstr[] = "EFI";
266 static char NAstr[] = " ";
268 /* All the user options and flags */
269 static char *Dfltdev; /* name of fixed disk drive */
271 /* Diagnostic options */
272 static int io_wrt = 0; /* write stdin to disk (-w) */
273 static int io_rd = 0; /* read disk and write stdout (-r) */
274 static char *io_fatt; /* user supplied pattern (-P pattern) */
275 static int io_patt = 0; /* write pattern to disk (-P pattern) */
276 static int io_lgeom = 0; /* get label geometry (-g) */
277 static int io_pgeom = 0; /* get drive physical geometry (-G) */
278 static char *io_sgeom = 0; /* set label geometry (-S geom_file) */
279 static int io_readonly = 0; /* do not write to disk (-R) */
281 /* The -o offset and -s size options specify the area of the disk on */
282 /* which to perform the particular operation; i.e., -P, -r, or -w. */
283 static off_t io_offset = 0; /* offset sector (-o offset) */
284 static off_t io_size = 0; /* size in sectors (-s size) */
286 /* Partition table flags */
287 static int v_flag = 0; /* virtual geometry-HBA flag (-v) */
288 static int stdo_flag = 0; /* stdout flag (-W -) */
289 static int io_fdisk = 0; /* do fdisk operation */
290 static int io_ifdisk = 0; /* interactive partition */
291 static int io_nifdisk = 0; /* non-interactive partition (-n) */
293 static int io_adjt = 0; /* check/adjust VTOC (truncate (-t)) */
294 static int io_ADJT = 0; /* check/adjust VTOC (delete (-T)) */
295 static char *io_ffdisk = 0; /* input fdisk file name (-F file) */
296 static char *io_Wfdisk = 0; /* output fdisk file name (-W file) */
297 static char *io_Afdisk = 0; /* add entry to partition table (-A) */
298 static char *io_Dfdisk = 0; /* delete entry from part. table (-D) */
300 static char *io_mboot = 0; /* master boot record (-b boot_file) */
302 static struct mboot BootCod; /* buffer for master boot record */
304 static int io_wholedisk = 0; /* use whole disk for Solaris (-B) */
305 static int io_EFIdisk = 0; /* use whole disk for EFI (-E) */
306 static int io_debug = 0; /* activate verbose mode (-d) */
307 static int io_image = 0; /* create image using geometry (-I) */
309 static struct mboot *Bootblk; /* pointer to cut/paste sector zero */
310 static char *Bootsect; /* pointer to sector zero buffer */
311 static char *Nullsect;
312 static struct extvtoc disk_vtoc; /* verify VTOC table */
313 static int vt_inval = 0;
314 static int no_virtgeom_ioctl = 0; /* ioctl for virtual geometry failed */
315 static int no_physgeom_ioctl = 0; /* ioctl for physical geometry failed */
317 static struct ipart Table[FD_NUMPART];
318 static struct ipart Old_Table[FD_NUMPART];
319 static int skip_verify[FD_NUMPART]; /* special case skip sz chk */
321 /* Disk geometry information */
322 static struct dk_minfo minfo;
323 static struct dk_geom disk_geom;
325 static int Dev; /* fd for open device */
327 static diskaddr_t dev_capacity; /* number of blocks on device */
328 static diskaddr_t chs_capacity; /* Numcyl_usable * heads * sectors */
330 static int Numcyl_usable; /* Number of usable cylinders */
331 /* used to limit fdisk to 2TB */
333 /* Physical geometry for the drive */
334 static int Numcyl; /* number of cylinders */
335 static int heads; /* number of heads */
336 static int sectors; /* number of sectors per track */
337 static int acyl; /* number of alternate sectors */
339 /* HBA (virtual) geometry for the drive */
340 static int hba_Numcyl; /* number of cylinders */
341 static int hba_heads; /* number of heads */
342 static int hba_sectors; /* number of sectors per track */
344 static int sectsiz; /* sector size */
346 /* Load functions for fdisk table modification */
347 #define LOADFILE 0 /* load fdisk from file */
348 #define LOADDEL 1 /* delete an fdisk entry */
349 #define LOADADD 2 /* add an fdisk entry */
351 #define CBUFLEN 80
352 static char s[CBUFLEN];
354 #ifdef i386
356 * Complete list of all the 255 partition types. Some are unknown types
357 * and some entries are known to be unused.
359 * Courtesy of http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
361 char *fdisk_part_types[] = {
362 "Empty", /* 0 */
363 "FAT12", /* 1 */
364 "XENIX /", /* 2 */
365 "XENIX /usr", /* 3 */
366 "FAT16 (Upto 32M)", /* 4 */
367 "DOS Extended", /* 5 */
368 "FAT16 (>32M, HUGEDOS)", /* 6 */
369 "IFS: NTFS", /* 7 */
370 "AIX Boot/QNX(qny)", /* 8 */
371 "AIX Data/QNX(qnz)", /* 9 */
372 "OS/2 Boot/Coherent swap", /* 10 */
373 "WIN95 FAT32(Upto 2047GB)", /* 11 */
374 "WIN95 FAT32(LBA)", /* 12 */
375 "Unused", /* 13 */
376 "WIN95 FAT16(LBA)", /* 14 */
377 "WIN95 Extended(LBA)", /* 15 */
378 "OPUS", /* 16 */
379 "Hidden FAT12", /* 17 */
380 "Diagnostic", /* 18 */
381 "Unknown", /* 19 */
382 "Hidden FAT16(Upto 32M)", /* 20 */
383 "Unknown", /* 21 */
384 "Hidden FAT16(>=32M)", /* 22 */
385 "Hidden IFS: HPFS", /* 23 */
386 "AST SmartSleep Partition", /* 24 */
387 "Unused/Willowtech Photon", /* 25 */
388 "Unknown", /* 26 */
389 "Hidden FAT32", /* 27 */
390 "Hidden FAT32(LBA)", /* 28 */
391 "Unused", /* 29 */
392 "Hidden FAT16(LBA)", /* 30 */
393 "Unknown", /* 31 */
394 "Unused/OSF1", /* 32 */
395 "Reserved/FSo2(Oxygen FS)", /* 33 */
396 "Unused/(Oxygen EXT)", /* 34 */
397 "Reserved", /* 35 */
398 "NEC DOS 3.x", /* 36 */
399 "Unknown", /* 37 */
400 "Reserved", /* 38 */
401 "Unknown", /* 39 */
402 "Unknown", /* 40 */
403 "Unknown", /* 41 */
404 "AtheOS File System", /* 42 */
405 "SyllableSecure", /* 43 */
406 "Unknown", /* 44 */
407 "Unknown", /* 45 */
408 "Unknown", /* 46 */
409 "Unknown", /* 47 */
410 "Unknown", /* 48 */
411 "Reserved", /* 49 */
412 "NOS", /* 50 */
413 "Reserved", /* 51 */
414 "Reserved", /* 52 */
415 "JFS on OS/2", /* 53 */
416 "Reserved", /* 54 */
417 "Unknown", /* 55 */
418 "THEOS 3.2 2GB", /* 56 */
419 "Plan9/THEOS 4", /* 57 */
420 "THEOS 4 4GB", /* 58 */
421 "THEOS 4 Extended", /* 59 */
422 "PartitionMagic Recovery", /* 60 */
423 "Hidden NetWare", /* 61 */
424 "Unknown", /* 62 */
425 "Unknown", /* 63 */
426 "Venix 80286", /* 64 */
427 "MINIX/PPC PReP Boot", /* 65 */
428 "Win2K Dynamic Disk/SFS(DOS)", /* 66 */
429 "Linux+DRDOS shared", /* 67 */
430 "GoBack partition", /* 68 */
431 "Boot-US boot manager", /* 69 */
432 "EUMEL/Elan", /* 70 */
433 "EUMEL/Elan", /* 71 */
434 "EUMEL/Elan", /* 72 */
435 "Unknown", /* 73 */
436 "ALFS/THIN FS for DOS", /* 74 */
437 "Unknown", /* 75 */
438 "Oberon partition", /* 76 */
439 "QNX 4,x", /* 77 */
440 "QNX 4,x 2nd Part", /* 78 */
441 "QNX 4,x 3rd Part", /* 79 */
442 "OnTrack DM R/O, Lynx RTOS", /* 80 */
443 "OnTrack DM R/W, Novell", /* 81 */
444 "CP/M", /* 82 */
445 "Disk Manager 6.0 Aux3", /* 83 */
446 "Disk Manager 6.0 DDO", /* 84 */
447 "EZ-Drive", /* 85 */
448 "Golden Bow VFeature/AT&T MS-DOS", /* 86 */
449 "DrivePro", /* 87 */
450 "Unknown", /* 88 */
451 "Unknown", /* 89 */
452 "Unknown", /* 90 */
453 "Unknown", /* 91 */
454 "Priam EDisk", /* 92 */
455 "Unknown", /* 93 */
456 "Unknown", /* 94 */
457 "Unknown", /* 95 */
458 "Unknown", /* 96 */
459 "SpeedStor", /* 97 */
460 "Unknown", /* 98 */
461 "Unix SysV, Mach, GNU Hurd", /* 99 */
462 "PC-ARMOUR, Netware 286", /* 100 */
463 "Netware 386", /* 101 */
464 "Netware SMS", /* 102 */
465 "Novell", /* 103 */
466 "Novell", /* 104 */
467 "Netware NSS", /* 105 */
468 "Unknown", /* 106 */
469 "Unknown", /* 107 */
470 "Unknown", /* 108 */
471 "Unknown", /* 109 */
472 "Unknown", /* 110 */
473 "Unknown", /* 111 */
474 "DiskSecure Multi-Boot", /* 112 */
475 "Reserved", /* 113 */
476 "Unknown", /* 114 */
477 "Reserved", /* 115 */
478 "Scramdisk partition", /* 116 */
479 "IBM PC/IX", /* 117 */
480 "Reserved", /* 118 */
481 "M2FS/M2CS,Netware VNDI", /* 119 */
482 "XOSL FS", /* 120 */
483 "Unknown", /* 121 */
484 "Unknown", /* 122 */
485 "Unknown", /* 123 */
486 "Unknown", /* 124 */
487 "Unknown", /* 125 */
488 "Unused", /* 126 */
489 "Unused", /* 127 */
490 "MINIX until 1.4a", /* 128 */
491 "MINIX since 1.4b, early Linux", /* 129 */
492 "Solaris/Linux swap", /* 130 */
493 "Linux native", /* 131 */
494 "OS/2 hidden,Win Hibernation", /* 132 */
495 "Linux extended", /* 133 */
496 "Old Linux RAID,NT FAT16 RAID", /* 134 */
497 "NTFS volume set", /* 135 */
498 "Linux plaintext part table", /* 136 */
499 "Unknown", /* 137 */
500 "Linux Kernel Partition", /* 138 */
501 "Fault Tolerant FAT32 volume", /* 139 */
502 "Fault Tolerant FAT32 volume", /* 140 */
503 "Free FDISK hidden PDOS FAT12", /* 141 */
504 "Linux LVM partition", /* 142 */
505 "Unknown", /* 143 */
506 "Free FDISK hidden PDOS FAT16", /* 144 */
507 "Free FDISK hidden DOS EXT", /* 145 */
508 "Free FDISK hidden FAT16 Large", /* 146 */
509 "Hidden Linux native, Amoeba", /* 147 */
510 "Amoeba Bad Block Table", /* 148 */
511 "MIT EXOPC Native", /* 149 */
512 "Unknown", /* 150 */
513 "Free FDISK hidden PDOS FAT32", /* 151 */
514 "Free FDISK hidden FAT32 LBA", /* 152 */
515 "DCE376 logical drive", /* 153 */
516 "Free FDISK hidden FAT16 LBA", /* 154 */
517 "Free FDISK hidden DOS EXT", /* 155 */
518 "Unknown", /* 156 */
519 "Unknown", /* 157 */
520 "Unknown", /* 158 */
521 "BSD/OS", /* 159 */
522 "Laptop hibernation", /* 160 */
523 "Laptop hibernate,HP SpeedStor", /* 161 */
524 "Unknown", /* 162 */
525 "HP SpeedStor", /* 163 */
526 "HP SpeedStor", /* 164 */
527 "BSD/386,386BSD,NetBSD,FreeBSD", /* 165 */
528 "OpenBSD,HP SpeedStor", /* 166 */
529 "NeXTStep", /* 167 */
530 "Mac OS-X", /* 168 */
531 "NetBSD", /* 169 */
532 "Olivetti FAT12 1.44MB Service", /* 170 */
533 "Mac OS-X Boot", /* 171 */
534 "Unknown", /* 172 */
535 "Unknown", /* 173 */
536 "ShagOS filesystem", /* 174 */
537 "ShagOS swap", /* 175 */
538 "BootStar Dummy", /* 176 */
539 "HP SpeedStor", /* 177 */
540 "Unknown", /* 178 */
541 "HP SpeedStor", /* 179 */
542 "HP SpeedStor", /* 180 */
543 "Unknown", /* 181 */
544 "Corrupted FAT16 NT Mirror Set", /* 182 */
545 "Corrupted NTFS NT Mirror Set", /* 183 */
546 "Old BSDI BSD/386 swap", /* 184 */
547 "Unknown", /* 185 */
548 "Unknown", /* 186 */
549 "Boot Wizard hidden", /* 187 */
550 "Unknown", /* 188 */
551 "Unknown", /* 189 */
552 "Solaris x86 boot", /* 190 */
553 "Solaris2", /* 191 */
554 "REAL/32 or Novell DOS secured", /* 192 */
555 "DRDOS/secured(FAT12)", /* 193 */
556 "Hidden Linux", /* 194 */
557 "Hidden Linux swap", /* 195 */
558 "DRDOS/secured(FAT16,< 32M)", /* 196 */
559 "DRDOS/secured(Extended)", /* 197 */
560 "NT corrupted FAT16 volume", /* 198 */
561 "NT corrupted NTFS volume", /* 199 */
562 "DRDOS8.0+", /* 200 */
563 "DRDOS8.0+", /* 201 */
564 "DRDOS8.0+", /* 202 */
565 "DRDOS7.04+ secured FAT32(CHS)", /* 203 */
566 "DRDOS7.04+ secured FAT32(LBA)", /* 204 */
567 "CTOS Memdump", /* 205 */
568 "DRDOS7.04+ FAT16X(LBA)", /* 206 */
569 "DRDOS7.04+ secure EXT DOS(LBA)", /* 207 */
570 "REAL/32 secure big, MDOS", /* 208 */
571 "Old MDOS secure FAT12", /* 209 */
572 "Unknown", /* 210 */
573 "Unknown", /* 211 */
574 "Old MDOS secure FAT16 <32M", /* 212 */
575 "Old MDOS secure EXT", /* 213 */
576 "Old MDOS secure FAT16 >=32M", /* 214 */
577 "Unknown", /* 215 */
578 "CP/M-86", /* 216 */
579 "Unknown", /* 217 */
580 "Non-FS Data", /* 218 */
581 "CP/M,Concurrent DOS,CTOS", /* 219 */
582 "Unknown", /* 220 */
583 "Hidden CTOS memdump", /* 221 */
584 "Dell PowerEdge utilities(FAT)", /* 222 */
585 "DG/UX virtual disk manager", /* 223 */
586 "ST AVFS(STMicroelectronics)", /* 224 */
587 "SpeedStor 12-bit FAT EXT", /* 225 */
588 "Unknown", /* 226 */
589 "SpeedStor", /* 227 */
590 "SpeedStor 16-bit FAT EXT", /* 228 */
591 "Tandy MSDOS", /* 229 */
592 "Storage Dimensions SpeedStor", /* 230 */
593 "Unknown", /* 231 */
594 "Unknown", /* 232 */
595 "Unknown", /* 233 */
596 "Unknown", /* 234 */
597 "BeOS BFS", /* 235 */
598 "SkyOS SkyFS", /* 236 */
599 "Unused", /* 237 */
600 "EFI Header Indicator", /* 238 */
601 "EFI Filesystem", /* 239 */
602 "Linux/PA-RISC boot loader", /* 240 */
603 "SpeedStor", /* 241 */
604 "DOS 3.3+ secondary", /* 242 */
605 "SpeedStor Reserved", /* 243 */
606 "SpeedStor Large", /* 244 */
607 "Prologue multi-volume", /* 245 */
608 "SpeedStor", /* 246 */
609 "Unused", /* 247 */
610 "Unknown", /* 248 */
611 "pCache", /* 249 */
612 "Bochs", /* 250 */
613 "VMware File System", /* 251 */
614 "VMware swap", /* 252 */
615 "Linux raid autodetect", /* 253 */
616 "NT Disk Administrator hidden", /* 254 */
617 "Xenix Bad Block Table" /* 255 */
620 /* Allowed extended partition menu options */
621 static char ext_part_menu_opts[] = "adhipr";
624 * Structure holding all information about the extended partition
625 * NOTE : As of now, there will be just one instance of ext_part_t, since most
626 * known systems allow only one extended dos partition per disk.
628 static ext_part_t *epp;
629 #endif
631 static void update_disk_and_exit(boolean_t table_changed);
632 int main(int argc, char *argv[]);
633 static int read_geom(char *sgeom);
634 static void dev_mboot_read(void);
635 static void dev_mboot_write(off_t sect, char *buff, int bootsiz);
636 static void mboot_read(void);
637 static void fill_patt(void);
638 static void abs_read(void);
639 static void abs_write(void);
640 static void load(int funct, char *file);
641 static void Set_Table_CHS_Values(int ti);
642 static int nopartdefined();
643 static int insert_tbl(int id, int act,
644 int bhead, int bsect, int bcyl,
645 int ehead, int esect, int ecyl,
646 uint32_t rsect, uint32_t numsect, int startindex);
647 static int entry_from_old_table(int id, int act,
648 int bhead, int bsect, int bcyl,
649 int ehead, int esect, int ecyl,
650 uint32_t rsect, uint32_t numsect, int startindex);
651 static int verify_tbl(void);
652 static int pars_fdisk(char *line,
653 int *id, int *act,
654 int *bhead, int *bsect, int *bcyl,
655 int *ehead, int *esect, int *ecyl,
656 uint32_t *rsect, uint32_t *numsect);
657 static int validate_part(int id, uint32_t rsect, uint32_t numsect);
658 static void stage0(void);
659 static int pcreate(void);
660 static int specify(uchar_t tsystid);
661 static void dispmenu(void);
662 static int pchange(void);
663 static int ppartid(void);
664 static char pdelete(void);
665 static void rm_blanks(char *s);
666 static int getcyl(void);
667 static void disptbl(void);
668 static void print_Table(void);
669 static void copy_Table_to_Old_Table(void);
670 static void nulltbl(void);
671 static void copy_Bootblk_to_Table(void);
672 static void fill_ipart(char *bootptr, struct ipart *partp);
673 #ifdef sparc
674 uchar_t getbyte(char **bp);
675 uint32_t getlong(char **bp);
676 #endif
677 static void copy_Table_to_Bootblk(void);
678 static int TableChanged(void);
679 static void ffile_write(char *file);
680 static void fix_slice(void);
681 static int yesno(void);
682 static int readvtoc(void);
683 static int writevtoc(void);
684 static int efi_ioctl(int fd, int cmd, dk_efi_t *dk_ioc);
685 static int clear_efi(void);
686 static void clear_vtoc(int table, int part);
687 static int lecture_and_query(char *warning, char *devname);
688 static void sanity_check_provided_device(char *devname, int fd);
689 static char *get_node(char *devname);
691 #ifdef i386
692 static void id_to_name(uchar_t sysid, char *buffer);
693 static void ext_read_input(char *buf);
694 static int ext_read_options(char *buf);
695 static int ext_invalid_option(char ch);
696 static void ext_read_valid_part_num(int *pno);
697 static void ext_read_valid_part_id(uchar_t *partid);
698 static int ext_read_valid_partition_start(uint32_t *begsec);
699 static void ext_read_valid_partition_size(uint32_t begsec, uint32_t *endsec);
700 static void ext_part_menu();
701 static void add_logical_drive();
702 static void delete_logical_drive();
703 static void ext_print_help_menu();
704 static void ext_change_logical_drive_id();
705 static void ext_print_part_types();
706 static void ext_print_logical_drive_layout();
707 static void preach_and_continue();
708 #ifdef DEBUG
709 static void ext_print_logdrive_layout_debug();
710 #endif /* DEBUG */
711 #endif /* i386 */
714 * This function is called only during the non-interactive mode.
715 * It is touchy and does not tolerate any errors. If there are
716 * mounted logical drives, changes to the partition table
717 * is disallowed.
719 static void
720 update_disk_and_exit(boolean_t table_changed)
722 #ifdef i386
723 int rval;
724 #endif
725 if (table_changed) {
727 * Copy the new table back to the sector buffer
728 * and write it to disk
730 copy_Table_to_Bootblk();
731 dev_mboot_write(0, Bootsect, sectsiz);
734 /* If the VTOC table is wrong fix it (truncation only) */
735 if (io_adjt)
736 fix_slice();
738 #ifdef i386
739 if (!io_readonly) {
740 rval = fdisk_commit_ext_part(epp);
741 switch (rval) {
742 case FDISK_SUCCESS:
743 /* Success */
744 break;
745 case FDISK_ENOEXTPART:
746 /* Nothing to do */
747 break;
748 default:
749 (void) fprintf(stderr, "Error in"
750 " fdisk_commit_ext_part\n");
751 exit(rval);
754 libfdisk_fini(&epp);
755 #endif
756 exit(0);
760 * main
761 * Process command-line options.
764 main(int argc, char *argv[])
766 int c, i;
767 extern int optind;
768 extern char *optarg;
769 int errflg = 0;
770 int diag_cnt = 0;
771 int openmode;
772 #ifdef i386
773 int rval;
774 int lf_op_flag = 0;
775 #endif
777 setbuf(stderr, 0); /* so all output gets out on exit */
778 setbuf(stdout, 0);
780 /* Process the options. */
781 while ((c = getopt(argc, argv, "o:s:P:F:b:A:D:W:S:tTIhwvrndgGRBE"))
782 != EOF) {
783 switch (c) {
785 case 'o':
786 io_offset = (off_t)strtoull(optarg, 0, 0);
787 continue;
788 case 's':
789 io_size = (off_t)strtoull(optarg, 0, 0);
790 continue;
791 case 'P':
792 diag_cnt++;
793 io_patt++;
794 io_fatt = optarg;
795 continue;
796 case 'w':
797 diag_cnt++;
798 io_wrt++;
799 continue;
800 case 'r':
801 diag_cnt++;
802 io_rd++;
803 continue;
804 case 'd':
805 io_debug++;
806 continue;
807 case 'I':
808 io_image++;
809 continue;
810 case 'R':
811 io_readonly++;
812 continue;
813 case 'S':
814 diag_cnt++;
815 io_sgeom = optarg;
816 continue;
817 case 'T':
818 io_ADJT++;
819 /* FALLTHRU */
820 case 't':
821 io_adjt++;
822 continue;
823 case 'B':
824 io_wholedisk++;
825 io_fdisk++;
826 continue;
827 case 'E':
828 io_EFIdisk++;
829 io_fdisk++;
830 continue;
831 case 'g':
832 diag_cnt++;
833 io_lgeom++;
834 continue;
835 case 'G':
836 diag_cnt++;
837 io_pgeom++;
838 continue;
839 case 'n':
840 io_nifdisk++;
841 io_fdisk++;
842 continue;
843 case 'F':
844 io_fdisk++;
845 io_ffdisk = optarg;
846 continue;
847 case 'b':
848 io_mboot = optarg;
849 continue;
850 case 'W':
852 * If '-' is the -W argument, then write
853 * to standard output, otherwise write
854 * to the specified file.
856 if (strncmp(optarg, "-", 1) == 0)
857 stdo_flag = 1;
858 else
859 io_Wfdisk = optarg;
860 io_fdisk++;
861 continue;
862 case 'A':
863 io_fdisk++;
864 io_Afdisk = optarg;
865 continue;
866 case 'D':
867 io_fdisk++;
868 io_Dfdisk = optarg;
869 continue;
870 case 'h':
871 (void) fprintf(stderr, "%s\n", Usage);
872 (void) fprintf(stderr, "%s\n", Usage1);
873 exit(0);
874 /* FALLTHRU */
875 case 'v':
876 v_flag = 1;
877 continue;
878 case '?':
879 errflg++;
880 break;
882 break;
885 if (io_image && io_sgeom && diag_cnt == 1) {
886 diag_cnt = 0;
889 /* User option checking */
891 /* By default, run in interactive mode */
892 if (!io_fdisk && !diag_cnt && !io_nifdisk) {
893 io_ifdisk++;
894 io_fdisk++;
896 if (((io_fdisk || io_adjt) && diag_cnt) || (diag_cnt > 1)) {
897 errflg++;
900 /* Was any error detected? */
901 if (errflg || argc == optind) {
902 (void) fprintf(stderr, "%s\n", Usage);
903 (void) fprintf(stderr,
904 "\nDetailed help is available with the -h option.\n");
905 exit(2);
909 /* Figure out the correct device node to open */
910 Dfltdev = get_node(argv[optind]);
912 if (io_readonly)
913 openmode = O_RDONLY;
914 else
915 openmode = O_RDWR|O_CREAT;
917 if ((Dev = open(Dfltdev, openmode, 0666)) == -1) {
918 (void) fprintf(stderr,
919 "fdisk: Cannot open device %s.\n",
920 Dfltdev);
921 exit(1);
924 * not all disk (or disklike) drivers support DKIOCGMEDIAINFO
925 * in that case leave the minfo structure zeroed
927 if (ioctl(Dev, DKIOCGMEDIAINFO, &minfo)) {
928 (void) memset(&minfo, 0, sizeof (minfo));
931 /* Get the disk geometry */
932 if (!io_image) {
933 /* Get disk's HBA (virtual) geometry */
934 errno = 0;
935 if (ioctl(Dev, DKIOCG_VIRTGEOM, &disk_geom)) {
938 * If ioctl isn't implemented on this platform, then
939 * turn off flag to print out virtual geometry (-v),
940 * otherwise use the virtual geometry.
943 if (errno == ENOTTY) {
944 v_flag = 0;
945 no_virtgeom_ioctl = 1;
946 } else if (errno == EINVAL) {
948 * This means that the ioctl exists, but
949 * is invalid for this disk, meaning the
950 * disk doesn't have an HBA geometry
951 * (like, say, it's larger than 8GB).
953 v_flag = 0;
954 hba_Numcyl = hba_heads = hba_sectors = 0;
955 } else {
956 (void) fprintf(stderr,
957 "%s: Cannot get virtual disk geometry.\n",
958 argv[optind]);
959 exit(1);
961 } else {
962 /* save virtual geometry values obtained by ioctl */
963 hba_Numcyl = disk_geom.dkg_ncyl;
964 hba_heads = disk_geom.dkg_nhead;
965 hba_sectors = disk_geom.dkg_nsect;
968 errno = 0;
969 if (ioctl(Dev, DKIOCG_PHYGEOM, &disk_geom)) {
970 if (errno == ENOTTY) {
971 no_physgeom_ioctl = 1;
972 } else {
973 (void) fprintf(stderr,
974 "%s: Cannot get physical disk geometry.\n",
975 argv[optind]);
976 exit(1);
981 * Call DKIOCGGEOM if the ioctls for physical and virtual
982 * geometry fail. Get both from this generic call.
984 if (no_virtgeom_ioctl && no_physgeom_ioctl) {
985 errno = 0;
986 if (ioctl(Dev, DKIOCGGEOM, &disk_geom)) {
987 (void) fprintf(stderr,
988 "%s: Cannot get disk label geometry.\n",
989 argv[optind]);
990 exit(1);
994 Numcyl = disk_geom.dkg_ncyl;
995 heads = disk_geom.dkg_nhead;
996 sectors = disk_geom.dkg_nsect;
998 if (minfo.dki_lbsize != 0)
999 sectsiz = minfo.dki_lbsize;
1000 else
1001 sectsiz = 512;
1003 acyl = disk_geom.dkg_acyl;
1006 * if hba geometry was not set by DKIOC_VIRTGEOM
1007 * or we got an invalid hba geometry
1008 * then set hba geometry based on max values
1010 if (no_virtgeom_ioctl ||
1011 disk_geom.dkg_ncyl == 0 ||
1012 disk_geom.dkg_nhead == 0 ||
1013 disk_geom.dkg_nsect == 0 ||
1014 disk_geom.dkg_ncyl > MAX_CYL ||
1015 disk_geom.dkg_nhead > MAX_HEAD ||
1016 disk_geom.dkg_nsect > MAX_SECT) {
1019 * turn off flag to print out virtual geometry (-v)
1021 v_flag = 0;
1022 hba_sectors = MAX_SECT;
1023 hba_heads = MAX_HEAD + 1;
1024 hba_Numcyl = (Numcyl * heads * sectors) /
1025 (hba_sectors * hba_heads);
1028 if (io_debug) {
1029 (void) fprintf(stderr, "Physical Geometry:\n");
1030 (void) fprintf(stderr,
1031 " cylinders[%d] heads[%d] sectors[%d]\n"
1032 " sector size[%d] blocks[%d] mbytes[%d]\n",
1033 Numcyl,
1034 heads,
1035 sectors,
1036 sectsiz,
1037 Numcyl * heads * sectors,
1038 (Numcyl * heads * sectors * sectsiz) / 1048576);
1039 (void) fprintf(stderr, "Virtual (HBA) Geometry:\n");
1040 (void) fprintf(stderr,
1041 " cylinders[%d] heads[%d] sectors[%d]\n"
1042 " sector size[%d] blocks[%d] mbytes[%d]\n",
1043 hba_Numcyl,
1044 hba_heads,
1045 hba_sectors,
1046 sectsiz,
1047 hba_Numcyl * hba_heads * hba_sectors,
1048 (hba_Numcyl * hba_heads * hba_sectors * sectsiz) /
1049 1048576);
1053 /* If user has requested a geometry report just do it and exit */
1054 if (io_lgeom) {
1055 if (ioctl(Dev, DKIOCGGEOM, &disk_geom)) {
1056 (void) fprintf(stderr,
1057 "%s: Cannot get disk label geometry.\n",
1058 argv[optind]);
1059 exit(1);
1061 Numcyl = disk_geom.dkg_ncyl;
1062 heads = disk_geom.dkg_nhead;
1063 sectors = disk_geom.dkg_nsect;
1064 if (minfo.dki_lbsize != 0)
1065 sectsiz = minfo.dki_lbsize;
1066 else
1067 sectsiz = 512;
1069 acyl = disk_geom.dkg_acyl;
1070 (void) printf("* Label geometry for device %s\n", Dfltdev);
1071 (void) printf(
1072 "* PCYL NCYL ACYL BCYL NHEAD NSECT"
1073 " SECSIZ\n");
1074 (void) printf(" %-8d %-8d %-8d %-8d %-5d %-5d %-6d\n",
1075 Numcyl,
1076 disk_geom.dkg_ncyl,
1077 disk_geom.dkg_acyl,
1078 disk_geom.dkg_bcyl,
1079 heads,
1080 sectors,
1081 sectsiz);
1082 exit(0);
1083 } else if (io_pgeom) {
1084 if (ioctl(Dev, DKIOCG_PHYGEOM, &disk_geom)) {
1085 (void) fprintf(stderr,
1086 "%s: Cannot get physical disk geometry.\n",
1087 argv[optind]);
1088 exit(1);
1090 (void) printf("* Physical geometry for device %s\n", Dfltdev);
1091 (void) printf(
1092 "* PCYL NCYL ACYL BCYL NHEAD NSECT"
1093 " SECSIZ\n");
1094 (void) printf(" %-8d %-8d %-8d %-8d %-5d %-5d %-6d\n",
1095 disk_geom.dkg_pcyl,
1096 disk_geom.dkg_ncyl,
1097 disk_geom.dkg_acyl,
1098 disk_geom.dkg_bcyl,
1099 disk_geom.dkg_nhead,
1100 disk_geom.dkg_nsect,
1101 sectsiz);
1102 exit(0);
1103 } else if (io_sgeom) {
1104 if (read_geom(io_sgeom)) {
1105 exit(1);
1106 } else if (!io_image) {
1107 exit(0);
1112 * some drivers may not support DKIOCGMEDIAINFO
1113 * in that case use CHS
1115 chs_capacity = (diskaddr_t)Numcyl * heads * sectors;
1116 dev_capacity = chs_capacity;
1117 Numcyl_usable = Numcyl;
1119 if (chs_capacity > DK_MAX_2TB) {
1120 /* limit to 2TB */
1121 Numcyl_usable = DK_MAX_2TB / (heads * sectors);
1122 chs_capacity = (diskaddr_t)Numcyl_usable * heads * sectors;
1125 if (minfo.dki_capacity > 0)
1126 dev_capacity = minfo.dki_capacity;
1128 /* Allocate memory to hold three complete sectors */
1129 Bootsect = (char *)calloc(3 * sectsiz, 1);
1130 if (Bootsect == NULL) {
1131 (void) fprintf(stderr,
1132 "fdisk: Unable to obtain enough buffer memory"
1133 " (%d bytes).\n",
1134 3 * sectsiz);
1135 exit(1);
1138 Nullsect = Bootsect + sectsiz;
1139 /* Zero out the "NULL" sector */
1140 for (i = 0; i < sectsiz; i++) {
1141 Nullsect[i] = 0;
1144 /* Find out what the user wants done */
1145 if (io_rd) { /* abs disk read */
1146 abs_read(); /* will not return */
1147 } else if (io_wrt && !io_readonly) {
1148 abs_write(); /* will not return */
1149 } else if (io_patt && !io_readonly) {
1150 fill_patt(); /* will not return */
1154 /* This is the fdisk edit, the real reason for the program. */
1156 sanity_check_provided_device(Dfltdev, Dev);
1158 /* Get the new BOOT program in case we write a new fdisk table */
1159 mboot_read();
1161 /* Read from disk master boot */
1162 dev_mboot_read();
1165 * Verify and copy the device's fdisk table. This will be used
1166 * as the prototype mboot if the device's mboot looks invalid.
1168 Bootblk = (struct mboot *)Bootsect;
1169 copy_Bootblk_to_Table();
1171 /* save away a copy of Table in Old_Table for sensing changes */
1172 copy_Table_to_Old_Table();
1174 #ifdef i386
1176 * Read extended partition only when the fdisk table is not
1177 * supplied from a file
1179 if (!io_ffdisk) {
1180 lf_op_flag |= FDISK_READ_DISK;
1182 if ((rval = libfdisk_init(&epp, Dfltdev, &Table[0], lf_op_flag))
1183 != FDISK_SUCCESS) {
1184 switch (rval) {
1186 * FDISK_EBADLOGDRIVE, FDISK_ENOLOGDRIVE and
1187 * FDISK_EBADMAGIC can be considered as
1188 * soft errors and hence we do not exit
1190 case FDISK_EBADLOGDRIVE:
1191 break;
1192 case FDISK_ENOLOGDRIVE:
1193 break;
1194 case FDISK_EBADMAGIC:
1195 break;
1196 case FDISK_ENOVGEOM:
1197 (void) fprintf(stderr, "Could not get virtual"
1198 " geometry for this device\n");
1199 exit(1);
1200 break;
1201 case FDISK_ENOPGEOM:
1202 (void) fprintf(stderr, "Could not get physical"
1203 " geometry for this device\n");
1204 exit(1);
1205 break;
1206 case FDISK_ENOLGEOM:
1207 (void) fprintf(stderr, "Could not get label"
1208 " geometry for this device\n");
1209 exit(1);
1210 break;
1211 default:
1212 perror("Failed to initialise libfdisk.\n");
1213 exit(1);
1214 break;
1217 #endif
1219 /* Load fdisk table from specified file (-F fdisk_file) */
1220 if (io_ffdisk) {
1221 /* Load and verify user-specified table parameters */
1222 load(LOADFILE, io_ffdisk);
1225 /* Does user want to delete or add an entry? */
1226 if (io_Dfdisk) {
1227 load(LOADDEL, io_Dfdisk);
1229 if (io_Afdisk) {
1230 load(LOADADD, io_Afdisk);
1233 if (!io_ffdisk && !io_Afdisk && !io_Dfdisk) {
1234 /* Check if there is no fdisk table */
1235 if (nopartdefined() || io_wholedisk || io_EFIdisk) {
1236 if (io_ifdisk && !io_wholedisk && !io_EFIdisk) {
1237 (void) printf(
1238 "No fdisk table exists. The default"
1239 " partition for the disk is:\n\n"
1240 " a 100%% \"SOLARIS System\" "
1241 "partition\n\n"
1242 "Type \"y\" to accept the default "
1243 "partition, otherwise type \"n\" to "
1244 "edit the\n partition table.\n");
1246 if (Numcyl > Numcyl_usable)
1247 (void) printf("WARNING: Disk is larger"
1248 " than 2TB. Solaris partition will"
1249 " be limited to 2 TB.\n");
1252 /* Edit the partition table as directed */
1253 if (io_wholedisk ||(io_ifdisk && yesno())) {
1255 /* Default scenario */
1256 nulltbl();
1257 /* now set up UNIX System partition */
1258 Table[0].bootid = ACTIVE;
1259 Table[0].relsect = LE_32(heads * sectors);
1261 Table[0].numsect =
1262 LE_32((ulong_t)((Numcyl_usable - 1) *
1263 heads * sectors));
1265 Table[0].systid = SUNIXOS2; /* Solaris */
1267 /* calculate CHS values for table entry 0 */
1268 Set_Table_CHS_Values(0);
1269 update_disk_and_exit(B_TRUE);
1270 } else if (io_EFIdisk) {
1271 /* create an EFI partition for the whole disk */
1272 nulltbl();
1273 i = insert_tbl(EFI_PMBR, 0, 0, 0, 0, 0, 0, 0, 1,
1274 (dev_capacity > DK_MAX_2TB) ? DK_MAX_2TB :
1275 (dev_capacity - 1), 0);
1276 if (i != 0) {
1277 (void) fprintf(stderr,
1278 "Error creating EFI partition\n");
1279 exit(1);
1281 update_disk_and_exit(B_TRUE);
1286 /* Display complete fdisk table entries for debugging purposes */
1287 if (io_debug) {
1288 (void) fprintf(stderr, "Partition Table Entry Values:\n");
1289 print_Table();
1290 if (io_ifdisk) {
1291 (void) fprintf(stderr, "\n");
1292 (void) fprintf(stderr, "Press Enter to continue.\n");
1293 (void) fgets(s, sizeof (s), stdin);
1297 /* Interactive fdisk mode */
1298 if (io_ifdisk) {
1299 (void) printf(CLR_SCR);
1300 disptbl();
1301 for (;;) {
1302 stage0();
1303 copy_Bootblk_to_Table();
1304 disptbl();
1308 /* If user wants to write the table to a file, do it */
1309 if (io_Wfdisk)
1310 ffile_write(io_Wfdisk);
1311 else if (stdo_flag)
1312 ffile_write((char *)stdout);
1314 update_disk_and_exit(TableChanged() == 1);
1315 return (0);
1319 * read_geom
1320 * Read geometry from specified file (-S).
1323 static int
1324 read_geom(char *sgeom)
1326 char line[256];
1327 FILE *fp;
1329 /* open the prototype file */
1330 if ((fp = fopen(sgeom, "r")) == NULL) {
1331 (void) fprintf(stderr, "fdisk: Cannot open file %s.\n",
1332 io_sgeom);
1333 return (1);
1336 /* Read a line from the file */
1337 while (fgets(line, sizeof (line) - 1, fp)) {
1338 if (line[0] == '\0' || line[0] == '\n' || line[0] == '*')
1339 continue;
1340 else {
1341 line[strlen(line)] = '\0';
1342 if (sscanf(line, "%hu %hu %hu %hu %hu %hu %d",
1343 &disk_geom.dkg_pcyl,
1344 &disk_geom.dkg_ncyl,
1345 &disk_geom.dkg_acyl,
1346 &disk_geom.dkg_bcyl,
1347 &disk_geom.dkg_nhead,
1348 &disk_geom.dkg_nsect,
1349 &sectsiz) != 7) {
1350 (void) fprintf(stderr,
1351 "Syntax error:\n \"%s\".\n",
1352 line);
1353 return (1);
1355 break;
1356 } /* else */
1357 } /* while (fgets(line, sizeof (line) - 1, fp)) */
1359 if (!io_image) {
1360 if (ioctl(Dev, DKIOCSGEOM, &disk_geom)) {
1361 (void) fprintf(stderr,
1362 "fdisk: Cannot set label geometry.\n");
1363 return (1);
1365 } else {
1366 Numcyl = hba_Numcyl = disk_geom.dkg_ncyl;
1367 heads = hba_heads = disk_geom.dkg_nhead;
1368 sectors = hba_sectors = disk_geom.dkg_nsect;
1369 acyl = disk_geom.dkg_acyl;
1372 (void) fclose(fp);
1373 return (0);
1377 * dev_mboot_read
1378 * Read the master boot sector from the device.
1380 static void
1381 dev_mboot_read(void)
1383 if ((ioctl(Dev, DKIOCGMBOOT, Bootsect) < 0) && (errno != ENOTTY)) {
1384 perror("Error in ioctl DKIOCGMBOOT");
1386 if (errno == 0)
1387 return;
1388 if (lseek(Dev, 0, SEEK_SET) == -1) {
1389 (void) fprintf(stderr,
1390 "fdisk: Error seeking to partition table on %s.\n",
1391 Dfltdev);
1392 if (!io_image)
1393 exit(1);
1395 if (read(Dev, Bootsect, sectsiz) != sectsiz) {
1396 (void) fprintf(stderr,
1397 "fdisk: Error reading partition table from %s.\n",
1398 Dfltdev);
1399 if (!io_image)
1400 exit(1);
1405 * dev_mboot_write
1406 * Write the master boot sector to the device.
1408 static void
1409 dev_mboot_write(off_t sect, char *buff, int bootsiz)
1411 int new_pt, old_pt, error;
1412 int clr_efi = -1;
1414 if (io_readonly)
1415 return;
1417 if (io_debug) {
1418 (void) fprintf(stderr, "About to write fdisk table:\n");
1419 print_Table();
1420 if (io_ifdisk) {
1421 (void) fprintf(stderr, "Press Enter to continue.\n");
1422 (void) fgets(s, sizeof (s), stdin);
1427 * If the new table has any Solaris partitions and the old
1428 * table does not have an entry that describes it
1429 * exactly then clear the old vtoc (if any).
1431 for (new_pt = 0; new_pt < FD_NUMPART; new_pt++) {
1433 /* We only care about potential Solaris parts. */
1434 if (Table[new_pt].systid != SUNIXOS &&
1435 Table[new_pt].systid != SUNIXOS2)
1436 continue;
1438 /* Does the old table have an exact entry for the new entry? */
1439 for (old_pt = 0; old_pt < FD_NUMPART; old_pt++) {
1441 /* We only care about old Solaris partitions. */
1442 if ((Old_Table[old_pt].systid == SUNIXOS) ||
1443 (Old_Table[old_pt].systid == SUNIXOS2)) {
1445 /* Is this old one the same as a new one? */
1446 if ((Old_Table[old_pt].relsect ==
1447 Table[new_pt].relsect) &&
1448 (Old_Table[old_pt].numsect ==
1449 Table[new_pt].numsect))
1450 break; /* Yes */
1454 /* Did a solaris partition change location or size? */
1455 if (old_pt >= FD_NUMPART) {
1456 /* Yes clear old vtoc */
1457 if (io_debug) {
1458 (void) fprintf(stderr,
1459 "Clearing VTOC labels from NEW"
1460 " table\n");
1462 clear_vtoc(NEW, new_pt);
1467 /* see if the old table had EFI */
1468 for (old_pt = 0; old_pt < FD_NUMPART; old_pt++) {
1469 if (Old_Table[old_pt].systid == EFI_PMBR) {
1470 clr_efi = old_pt;
1474 /* look to see if a EFI partition changed in relsect/numsect */
1475 for (new_pt = 0; new_pt < FD_NUMPART; new_pt++) {
1476 if (Table[new_pt].systid != EFI_PMBR)
1477 continue;
1478 for (old_pt = 0; old_pt < FD_NUMPART; old_pt++) {
1479 if ((Old_Table[old_pt].systid ==
1480 Table[new_pt].systid) &&
1481 (Old_Table[old_pt].relsect ==
1482 Table[new_pt].relsect) &&
1483 (Old_Table[old_pt].numsect ==
1484 Table[new_pt].numsect))
1485 break;
1489 * if EFI partition changed, set the flag to clear
1490 * the EFI GPT
1492 if (old_pt == FD_NUMPART && Table[new_pt].begcyl != 0) {
1493 clr_efi = 0;
1495 break;
1498 /* clear labels if necessary */
1499 if (clr_efi >= 0) {
1500 if (io_debug) {
1501 (void) fprintf(stderr, "Clearing EFI labels\n");
1503 if ((error = clear_efi()) != 0) {
1504 if (io_debug) {
1505 (void) fprintf(stderr,
1506 "\tError %d clearing EFI labels"
1507 " (probably no EFI labels exist)\n",
1508 error);
1513 if ((ioctl(Dev, DKIOCSMBOOT, buff) == -1) && (errno != ENOTTY)) {
1514 (void) fprintf(stderr,
1515 "fdisk: Error in ioctl DKIOCSMBOOT on %s.\n",
1516 Dfltdev);
1518 if (errno == 0)
1519 return;
1521 /* write to disk drive */
1522 if (lseek(Dev, sect, SEEK_SET) == -1) {
1523 (void) fprintf(stderr,
1524 "fdisk: Error seeking to master boot record on %s.\n",
1525 Dfltdev);
1526 exit(1);
1528 if (write(Dev, buff, bootsiz) != bootsiz) {
1529 (void) fprintf(stderr,
1530 "fdisk: Error writing master boot record to %s.\n",
1531 Dfltdev);
1532 exit(1);
1537 * mboot_read
1538 * Read the prototype boot records from the files.
1540 static void
1541 mboot_read(void)
1543 int mDev, i;
1544 struct ipart *part;
1546 #if defined(i386) || defined(sparc)
1548 * If the master boot file hasn't been specified, use the
1549 * implementation architecture name to generate the default one.
1551 if (io_mboot == NULL) {
1553 * Bug ID 1249035:
1554 * The mboot file must be delivered on all platforms
1555 * and installed in a non-platform-dependent
1556 * directory; i.e., /usr/lib/fs/ufs.
1558 io_mboot = "/usr/lib/fs/ufs/mboot";
1561 /* First read in the master boot record */
1563 /* Open the master boot proto file */
1564 if ((mDev = open(io_mboot, O_RDONLY, 0666)) == -1) {
1565 (void) fprintf(stderr,
1566 "fdisk: Cannot open master boot file %s.\n",
1567 io_mboot);
1568 exit(1);
1571 /* Read the master boot program */
1572 if (read(mDev, &BootCod, sizeof (struct mboot)) != sizeof
1573 (struct mboot)) {
1574 (void) fprintf(stderr,
1575 "fdisk: Cannot read master boot file %s.\n",
1576 io_mboot);
1577 exit(1);
1580 /* Is this really a master boot record? */
1581 if (LE_16(BootCod.signature) != MBB_MAGIC) {
1582 (void) fprintf(stderr,
1583 "fdisk: Invalid master boot file %s.\n", io_mboot);
1584 (void) fprintf(stderr,
1585 "Bad magic number: is %x, but should be %x.\n",
1586 LE_16(BootCod.signature), MBB_MAGIC);
1587 exit(1);
1590 (void) close(mDev);
1591 #else
1592 #error fdisk needs to be ported to new architecture
1593 #endif
1595 /* Zero out the partitions part of this record */
1596 part = (struct ipart *)BootCod.parts;
1597 for (i = 0; i < FD_NUMPART; i++, part++) {
1598 (void) memset(part, 0, sizeof (struct ipart));
1604 * fill_patt
1605 * Fill the disk with user/sector number pattern.
1607 static void
1608 fill_patt(void)
1610 int *buff_ptr, i;
1611 off_t *off_ptr;
1612 int io_fpatt = 0;
1613 int io_ipatt = 0;
1615 if (strncmp(io_fatt, "#", 1) != 0) {
1616 io_fpatt++;
1617 io_ipatt = strtoul(io_fatt, 0, 0);
1618 buff_ptr = (int *)Bootsect;
1619 for (i = 0; i < sectsiz; i += 4, buff_ptr++)
1620 *buff_ptr = io_ipatt;
1624 * Fill disk with pattern based on block number.
1625 * Write to the disk at absolute relative block io_offset
1626 * for io_size blocks.
1628 while (io_size--) {
1629 off_ptr = (off_t *)Bootsect;
1630 if (!io_fpatt) {
1631 for (i = 0; i < sectsiz;
1632 i += sizeof (off_t), off_ptr++)
1633 *off_ptr = io_offset;
1635 /* Write the data to disk */
1636 if (lseek(Dev, (off_t)(sectsiz * io_offset++),
1637 SEEK_SET) == -1) {
1638 (void) fprintf(stderr, "fdisk: Error seeking on %s.\n",
1639 Dfltdev);
1640 exit(1);
1642 if (write(Dev, Bootsect, sectsiz) != sectsiz) {
1643 (void) fprintf(stderr, "fdisk: Error writing %s.\n",
1644 Dfltdev);
1645 exit(1);
1647 } /* while (--io_size); */
1651 * abs_read
1652 * Read from the disk at absolute relative block io_offset for
1653 * io_size blocks. Write the data to standard ouput (-r).
1655 static void
1656 abs_read(void)
1658 int c;
1660 while (io_size--) {
1661 if (lseek(Dev, (off_t)(sectsiz * io_offset++),
1662 SEEK_SET) == -1) {
1663 (void) fprintf(stderr, "fdisk: Error seeking on %s.\n",
1664 Dfltdev);
1665 exit(1);
1667 if (read(Dev, Bootsect, sectsiz) != sectsiz) {
1668 (void) fprintf(stderr, "fdisk: Error reading %s.\n",
1669 Dfltdev);
1670 exit(1);
1673 /* Write to standard ouptut */
1674 if ((c = write(1, Bootsect, (unsigned)sectsiz)) != sectsiz) {
1675 if (c >= 0) {
1676 if (io_debug)
1677 (void) fprintf(stderr,
1678 "fdisk: Output warning: %d of %d"
1679 " characters written.\n",
1680 c, sectsiz);
1681 exit(2);
1682 } else {
1683 perror("write error on output file.");
1684 exit(2);
1686 } /* if ((c = write(1, Bootsect, (unsigned)sectsiz)) */
1687 /* != sectsiz) */
1688 } /* while (--io_size); */
1689 exit(0);
1693 * abs_write
1694 * Read the data from standard input. Write to the disk at
1695 * absolute relative block io_offset for io_size blocks (-w).
1697 static void
1698 abs_write(void)
1700 int c, i;
1702 while (io_size--) {
1703 int part_exit = 0;
1704 /* Read from standard input */
1705 if ((c = read(0, Bootsect, (unsigned)sectsiz)) != sectsiz) {
1706 if (c >= 0) {
1707 if (io_debug)
1708 (void) fprintf(stderr,
1709 "fdisk: WARNING: Incomplete read (%d of"
1710 " %d characters read) on input file.\n",
1711 c, sectsiz);
1712 /* Fill pattern to mark partial sector in buf */
1713 for (i = c; i < sectsiz; ) {
1714 Bootsect[i++] = 0x41;
1715 Bootsect[i++] = 0x62;
1716 Bootsect[i++] = 0x65;
1717 Bootsect[i++] = 0;
1719 part_exit++;
1720 } else {
1721 perror("read error on input file.");
1722 exit(2);
1726 /* Write to disk drive */
1727 if (lseek(Dev, (off_t)(sectsiz * io_offset++),
1728 SEEK_SET) == -1) {
1729 (void) fprintf(stderr, "fdisk: Error seeking on %s.\n",
1730 Dfltdev);
1731 exit(1);
1733 if (write(Dev, Bootsect, sectsiz) != sectsiz) {
1734 (void) fprintf(stderr, "fdisk: Error writing %s.\n",
1735 Dfltdev);
1736 exit(1);
1738 if (part_exit)
1739 exit(0);
1740 } /* while (--io_size); */
1741 exit(1);
1746 * load
1747 * Load will either read the fdisk table from a file or add or
1748 * delete an entry (-A, -D, -F).
1751 static void
1752 load(int funct, char *file)
1754 int id;
1755 int act;
1756 int bhead;
1757 int bsect;
1758 int bcyl;
1759 int ehead;
1760 int esect;
1761 int ecyl;
1762 uint32_t rsect;
1763 uint32_t numsect;
1764 char line[256];
1765 int i = 0;
1766 FILE *fp;
1767 int startindex = 0;
1768 int tmpindex = 0;
1769 #ifdef i386
1770 int ext_part_present = 0;
1771 uint32_t begsec, endsec, relsect;
1772 logical_drive_t *temp;
1773 int part_count = 0, ldcnt = 0;
1774 uint32_t ext_beg_sec;
1775 uint32_t old_ext_beg_sec = 0, old_ext_num_sec = 0;
1776 uint32_t new_ext_beg_sec = 0, new_ext_num_sec = 0;
1777 int ext_part_inited = 0;
1778 uchar_t systid;
1779 #endif
1781 switch (funct) {
1783 case LOADFILE:
1786 * Zero out the table before loading it, which will
1787 * force it to be updated on disk later (-F
1788 * fdisk_file).
1790 nulltbl();
1792 /* Open the prototype file */
1793 if ((fp = fopen(file, "r")) == NULL) {
1794 (void) fprintf(stderr,
1795 "fdisk: Cannot open prototype partition file %s.\n",
1796 file);
1797 exit(1);
1800 /* Read a line from the file */
1801 while (fgets(line, sizeof (line) - 1, fp)) {
1802 if (pars_fdisk(line, &id, &act, &bhead, &bsect,
1803 &bcyl, &ehead, &esect, &ecyl, &rsect, &numsect)) {
1804 continue;
1806 #ifdef i386
1807 part_count++;
1809 if (fdisk_is_dos_extended((uchar_t)id)) {
1810 if (ext_part_present) {
1811 (void) fprintf(stderr,
1812 "Extended partition"
1813 " already exists\n");
1814 (void) fprintf(stderr, "fdisk: Error on"
1815 " entry \"%s\".\n", line);
1816 exit(1);
1818 ext_part_present = 1;
1820 * If the existing extended partition's start
1821 * and size matches the new one, do not
1822 * initialize the extended partition EBR
1823 * (Extended Boot Record) because there could
1824 * be existing logical drives.
1826 for (i = 0; i < FD_NUMPART; i++) {
1827 systid = Old_Table[i].systid;
1828 if (fdisk_is_dos_extended(systid)) {
1829 old_ext_beg_sec =
1830 Old_Table[i].relsect;
1831 old_ext_num_sec =
1832 Old_Table[i].numsect;
1833 break;
1836 new_ext_beg_sec = rsect;
1837 new_ext_num_sec = numsect;
1838 if ((old_ext_beg_sec != new_ext_beg_sec) ||
1839 (old_ext_num_sec != new_ext_num_sec)) {
1840 (void) fdisk_init_ext_part(epp,
1841 new_ext_beg_sec, new_ext_num_sec);
1842 ext_part_inited = 1;
1846 if (part_count > FD_NUMPART) {
1847 /* This line should be logical drive info */
1848 int offset = MAX_LOGDRIVE_OFFSET;
1849 if (!ext_part_present) {
1850 /* Erroneous input file */
1851 (void) fprintf(stderr,
1852 "More than 4 primary"
1853 " partitions found in input\n");
1854 (void) fprintf(stderr, "Exiting...\n");
1855 exit(1);
1858 if (numsect == 0) {
1859 continue;
1863 * If the start and size of the existing
1864 * extended partition matches the new one and
1865 * new logical drives are being defined via
1866 * the input file, initialize the EBR.
1868 if (!ext_part_inited) {
1869 (void) fdisk_init_ext_part(epp,
1870 new_ext_beg_sec, new_ext_num_sec);
1871 ext_part_inited = 1;
1874 begsec = rsect - offset;
1875 if ((ldcnt =
1876 fdisk_get_logical_drive_count(epp)) == 0) {
1877 /* Adding the first logical drive */
1879 * Make sure that begsec doesnt wrap
1880 * around. This can happen if rsect is
1881 * less than offset.
1883 if (rsect < offset) {
1884 (void) fprintf(stderr,
1885 "Minimum of "
1886 "63 free sectors required "
1887 "before the beginning of "
1888 "a logical drive.");
1889 exit(1);
1892 * Check if the first logical drive
1893 * is out of order. In that case, do
1894 * not subtract MAX_LOGDRIVE_OFFSET
1895 * from the given start of partition.
1897 if (begsec != new_ext_beg_sec) {
1898 begsec = rsect;
1899 offset = 0;
1902 if (ldcnt >= MAX_EXT_PARTS) {
1903 (void) fprintf(stderr,
1904 "\nError : Number of "
1905 "logical drives exceeds limit of "
1906 "%d.\n", MAX_EXT_PARTS);
1907 exit(1);
1910 if (id > FDISK_MAX_VALID_PART_ID) {
1911 (void) fprintf(stderr,
1912 "Invalid partition ID\n");
1913 (void) fprintf(stderr, "fdisk: Error on"
1914 " entry \"%s\".\n", line);
1915 exit(1);
1918 endsec = rsect + numsect - 1;
1919 if (fdisk_validate_logical_drive(epp,
1920 begsec, offset, numsect) == 0) {
1921 if (id == EFI_PMBR) {
1922 (void) fprintf(stderr, "EFI "
1923 "partitions not supported "
1924 "inside extended "
1925 "partition\n");
1926 exit(1);
1928 fdisk_add_logical_drive(epp, begsec,
1929 endsec, id);
1930 continue;
1931 } else {
1932 (void) fprintf(stderr, "fdisk: Error on"
1933 " entry \"%s\".\n", line);
1934 exit(1);
1937 #endif
1940 * Validate the partition. It cannot start at sector
1941 * 0 unless it is UNUSED or already exists
1943 if (validate_part(id, rsect, numsect) < 0) {
1944 (void) fprintf(stderr,
1945 "fdisk: Error on entry \"%s\".\n",
1946 line);
1947 exit(1);
1950 if ((tmpindex = entry_from_old_table(id, act, bhead,
1951 bsect, bcyl, ehead, esect, ecyl, rsect, numsect,
1952 startindex)) != -1) {
1954 * If we got here it means we copied an
1955 * unmodified entry. So there is no need
1956 * to insert it in the table or do any
1957 * checks against disk size.
1959 * This is a work around on the following
1960 * situation (for IDE disks, at least):
1961 * Different operation systems calculate
1962 * disk size different ways, of which there
1963 * are two main ways.
1965 * The first, rounds the disk size to modulo
1966 * cylinder size (virtual made-up cylinder
1967 * usually based on maximum number of heads
1968 * and sectors in partition table fields).
1969 * Our OS's (for IDE) and most other "Unix"
1970 * type OS's do this.
1972 * The second, uses every single block
1973 * on the disk (to maximize available space).
1974 * Since disk manufactures do not know about
1975 * "virtual cylinders", there are some number
1976 * of blocks that make up a partial cylinder
1977 * at the end of the disk.
1979 * The difference between these two methods
1980 * is where the problem is. When one
1981 * tries to install Solaris/OpenSolaris on
1982 * a disk that has another OS using that
1983 * "partial cylinder", install fails. It fails
1984 * since fdisk thinks its asked to create a
1985 * partition with the -F option that contains
1986 * a partition that runs off the end of the
1987 * disk.
1989 startindex = tmpindex + 1;
1990 continue;
1994 * Find an unused entry to use and put the entry
1995 * in table
1997 if ((startindex = insert_tbl(id, act, bhead, bsect,
1998 bcyl, ehead, esect, ecyl, rsect, numsect,
1999 startindex)) < 0) {
2000 (void) fprintf(stderr,
2001 "fdisk: Error on entry \"%s\".\n",
2002 line);
2003 exit(1);
2005 startindex++;
2006 } /* while (fgets(line, sizeof (line) - 1, fp)) */
2008 if (verify_tbl() < 0) {
2009 (void) fprintf(stderr,
2010 "fdisk: Cannot create partition table\n");
2011 exit(1);
2014 (void) fclose(fp);
2015 return;
2017 case LOADDEL:
2019 /* Parse the user-supplied deletion line (-D) */
2020 if (pars_fdisk(file, &id, &act, &bhead, &bsect, &bcyl,
2021 &ehead, &esect, &ecyl, &rsect, &numsect)) {
2022 (void) fprintf(stderr,
2023 "fdisk: Syntax error \"%s\"\n", file);
2024 exit(1);
2027 /* Find the exact entry in the table */
2028 for (i = 0; i < FD_NUMPART; i++) {
2029 if (Table[i].systid == id &&
2030 Table[i].bootid == act &&
2031 Table[i].beghead == bhead &&
2032 Table[i].begsect == ((bsect & 0x3f) |
2033 (uchar_t)((bcyl>>2) & 0xc0)) &&
2034 Table[i].begcyl == (uchar_t)(bcyl & 0xff) &&
2035 Table[i].endhead == ehead &&
2036 Table[i].endsect == ((esect & 0x3f) |
2037 (uchar_t)((ecyl>>2) & 0xc0)) &&
2038 Table[i].endcyl == (uchar_t)(ecyl & 0xff) &&
2039 Table[i].relsect == LE_32(rsect) &&
2040 Table[i].numsect == LE_32(numsect)) {
2042 (void) memset(&Table[i], 0,
2043 sizeof (struct ipart));
2044 #ifdef i386
2045 if (fdisk_is_dos_extended(id)) {
2046 (void) fdisk_delete_ext_part(epp);
2048 #endif
2049 return;
2053 #ifdef i386
2054 ldcnt = FD_NUMPART + 1;
2055 for (temp = fdisk_get_ld_head(epp); temp != NULL;
2056 temp = temp->next) {
2057 relsect = temp->abs_secnum + temp->logdrive_offset;
2058 if (temp->parts[0].systid == id &&
2059 temp->parts[0].bootid == act &&
2060 temp->parts[0].beghead == bhead &&
2061 temp->parts[0].begsect == ((bsect & 0x3f) |
2062 (uchar_t)((bcyl>>2) & 0xc0)) &&
2063 temp->parts[0].begcyl == (uchar_t)(bcyl & 0xff) &&
2064 temp->parts[0].endhead == ehead &&
2065 temp->parts[0].endsect == ((esect & 0x3f) |
2066 (uchar_t)((ecyl>>2) & 0xc0)) &&
2067 temp->parts[0].endcyl == (uchar_t)(ecyl & 0xff) &&
2068 relsect == LE_32(rsect) &&
2069 temp->parts[0].numsect == LE_32(numsect)) {
2070 fdisk_delete_logical_drive(epp, ldcnt);
2071 return;
2073 ldcnt++;
2075 #endif
2077 (void) fprintf(stderr,
2078 "fdisk: Entry does not match any existing partition:\n"
2079 " \"%s\"\n",
2080 file);
2081 exit(1);
2082 /* FALLTHRU */
2084 case LOADADD:
2086 /* Parse the user-supplied addition line (-A) */
2087 if (pars_fdisk(file, &id, &act, &bhead, &bsect, &bcyl, &ehead,
2088 &esect, &ecyl, &rsect, &numsect)) {
2089 (void) fprintf(stderr,
2090 "fdisk: Syntax error \"%s\"\n", file);
2091 exit(1);
2094 /* Validate the partition. It cannot start at sector 0 */
2095 if (rsect == 0) {
2096 (void) fprintf(stderr,
2097 "fdisk: New partition cannot start at sector 0:\n"
2098 " \"%s\".\n",
2099 file);
2100 exit(1);
2104 * if the user wishes to add an EFI partition, we need
2105 * more extensive validation. rsect should be 1, and
2106 * numsect should equal the entire disk capacity - 1
2109 if (id == EFI_PMBR) {
2110 if (rsect != 1) {
2111 (void) fprintf(stderr,
2112 "fdisk: EFI partitions must start at sector"
2113 " 1 (input rsect = %d)\n", rsect);
2114 exit(1);
2118 if (dev_capacity > DK_MAX_2TB) {
2119 if (numsect != DK_MAX_2TB) {
2120 (void) fprintf(stderr,
2121 "fdisk: EFI partitions must "
2122 "encompass the entire maximum 2 TB "
2123 "(input numsect: %u - max: %llu)\n",
2124 numsect, (diskaddr_t)DK_MAX_2TB);
2125 exit(1);
2127 } else if (numsect != dev_capacity - 1) {
2128 (void) fprintf(stderr,
2129 "fdisk: EFI partitions must encompass the "
2130 "entire disk\n"
2131 "(input numsect: %u - avail: %llu)\n",
2132 numsect,
2133 dev_capacity - 1);
2134 exit(1);
2138 #ifdef i386
2139 if (id > FDISK_MAX_VALID_PART_ID) {
2140 (void) printf("Invalid partition ID\n");
2141 exit(1);
2144 if ((fdisk_ext_part_exists(epp)) &&
2145 (fdisk_is_dos_extended(id))) {
2146 (void) fprintf(stderr,
2147 "Extended partition already exists.\n");
2148 (void) fprintf(stderr,
2149 "fdisk: Invalid entry could not be "
2150 "inserted:\n \"%s\"\n", file);
2151 exit(1);
2154 if (fdisk_ext_part_exists(epp) &&
2155 (rsect >= (ext_beg_sec = fdisk_get_ext_beg_sec(epp))) &&
2156 (rsect <= (fdisk_get_ext_end_sec(epp)))) {
2157 int offset = MAX_LOGDRIVE_OFFSET;
2160 * Make sure that begsec doesnt wrap around.
2161 * This can happen if rsect is less than offset
2163 if (rsect < offset) {
2164 return;
2166 begsec = rsect - offset;
2167 if ((ldcnt = fdisk_get_logical_drive_count(epp)) == 0) {
2169 * Adding the first logical drive
2170 * Check if the first logical drive
2171 * is out of order. In that case, do
2172 * not subtract MAX_LOGDRIVE_OFFSET
2173 * from the given start of partition.
2175 if (begsec != ext_beg_sec) {
2176 begsec = rsect;
2177 offset = 0;
2181 if (ldcnt >= MAX_EXT_PARTS) {
2182 (void) printf("\nNumber of logical drives "
2183 "exceeds limit of %d.\n", MAX_EXT_PARTS);
2184 (void) printf("Failing further additions.\n");
2185 exit(1);
2188 if (numsect == 0) {
2189 (void) fprintf(stderr,
2190 "fdisk: Partition size cannot be zero:\n"
2191 " \"%s\".\n",
2192 file);
2193 exit(1);
2195 endsec = rsect + numsect - 1;
2196 if (fdisk_validate_logical_drive(epp, begsec,
2197 offset, numsect) == 0) {
2198 /* Valid logical drive */
2199 fdisk_add_logical_drive(epp, begsec, endsec,
2200 id);
2201 return;
2202 } else {
2203 (void) fprintf(stderr,
2204 "fdisk: Invalid entry could not be "
2205 "inserted:\n \"%s\"\n", file);
2206 exit(1);
2209 #endif
2211 /* Find unused entry for use and put entry in table */
2212 if (insert_tbl(id, act, bhead, bsect, bcyl, ehead, esect,
2213 ecyl, rsect, numsect, 0) < 0) {
2214 (void) fprintf(stderr,
2215 "fdisk: Invalid entry could not be inserted:\n"
2216 " \"%s\"\n",
2217 file);
2218 exit(1);
2221 /* Make sure new entry does not overlap existing entry */
2222 if (verify_tbl() < 0) {
2223 (void) fprintf(stderr,
2224 "fdisk: Cannot create partition \"%s\"\n", file);
2225 exit(1);
2227 } /* switch funct */
2231 * Set_Table_CHS_Values
2233 * This will calculate the CHS values for beginning and ending CHS
2234 * for a single partition table entry (ti) based on the relsect
2235 * and numsect values contained in the partion table entry.
2237 * hba_heads and hba_sectors contain the number of heads and sectors.
2239 * If the number of cylinders exceeds the MAX_CYL,
2240 * then maximum values will be placed in the corresponding chs entry.
2242 static void
2243 Set_Table_CHS_Values(int ti)
2245 uint32_t lba, cy, hd, sc;
2247 lba = (uint32_t)Table[ti].relsect;
2248 if (lba >= hba_heads * hba_sectors * MAX_CYL) {
2250 * the lba address cannot be expressed in CHS value
2251 * so store the maximum CHS field values in the CHS fields.
2253 cy = MAX_CYL + 1;
2254 hd = MAX_HEAD;
2255 sc = MAX_SECT;
2256 } else {
2257 cy = lba / hba_sectors / hba_heads;
2258 hd = lba / hba_sectors % hba_heads;
2259 sc = lba % hba_sectors + 1;
2261 Table[ti].begcyl = cy & 0xff;
2262 Table[ti].beghead = (uchar_t)hd;
2263 Table[ti].begsect = (uchar_t)(((cy >> 2) & 0xc0) | sc);
2266 * This code is identical to the code above
2267 * except that it works on ending CHS values
2269 lba = (uint32_t)(Table[ti].relsect + Table[ti].numsect - 1);
2270 if (lba >= hba_heads * hba_sectors * MAX_CYL) {
2271 cy = MAX_CYL + 1;
2272 hd = MAX_HEAD;
2273 sc = MAX_SECT;
2274 } else {
2275 cy = lba / hba_sectors / hba_heads;
2276 hd = lba / hba_sectors % hba_heads;
2277 sc = lba % hba_sectors + 1;
2279 Table[ti].endcyl = cy & 0xff;
2280 Table[ti].endhead = (uchar_t)hd;
2281 Table[ti].endsect = (uchar_t)(((cy >> 2) & 0xc0) | sc);
2285 * insert_tbl
2286 * Insert entry into fdisk table. Check all user-supplied values
2287 * for the entry, but not the validity relative to other table
2288 * entries!
2290 static int
2291 insert_tbl(
2292 int id, int act,
2293 int bhead, int bsect, int bcyl,
2294 int ehead, int esect, int ecyl,
2295 uint32_t rsect, uint32_t numsect, int startindex)
2297 int i;
2299 /* validate partition size */
2300 if (((diskaddr_t)rsect + numsect) > dev_capacity) {
2301 (void) fprintf(stderr,
2302 "fdisk: Partition table exceeds the size of the disk.\n");
2303 return (-1);
2307 /* find UNUSED partition table entry */
2308 for (i = startindex; i < FD_NUMPART; i++) {
2309 if (Table[i].systid == UNUSED) {
2310 break;
2313 if (i >= FD_NUMPART) {
2314 (void) fprintf(stderr, "fdisk: Partition table is full.\n");
2315 return (-1);
2319 Table[i].systid = (uchar_t)id;
2320 Table[i].bootid = (uchar_t)act;
2321 Table[i].numsect = LE_32(numsect);
2322 Table[i].relsect = LE_32(rsect);
2324 if (id == UNUSED) {
2325 (void) memset(&Table[i], 0, sizeof (struct ipart));
2326 } else if (0 < bsect && bsect <= MAX_SECT &&
2327 0 <= bhead && bhead <= MAX_HEAD &&
2328 0 < esect && esect <= MAX_SECT &&
2329 0 <= ehead && ehead <= MAX_HEAD) {
2332 * If we have been called with a valid geometry, use it
2333 * valid means non-zero values that fit in the BIOS fields
2335 if (bcyl > MAX_CYL)
2336 bcyl = MAX_CYL + 1;
2337 if (ecyl > MAX_CYL)
2338 ecyl = MAX_CYL + 1;
2339 Table[i].begcyl = bcyl & 0xff;
2340 Table[i].endcyl = ecyl & 0xff;
2341 Table[i].beghead = (uchar_t)bhead;
2342 Table[i].endhead = (uchar_t)ehead;
2343 Table[i].begsect = (uchar_t)(((bcyl >> 2) & 0xc0) | bsect);
2344 Table[i].endsect = ((ecyl >> 2) & 0xc0) | esect;
2345 } else {
2348 * The specified values are invalid,
2349 * so calculate the values based on hba_heads, hba_sectors
2351 Set_Table_CHS_Values(i);
2355 * return partition index
2357 return (i);
2361 * entry_from_old_table
2362 * If the specified entry is in the old table and is not a Solaris entry
2363 * then insert same entry into new fdisk table. If we do this then
2364 * all checks are skipped for that entry!
2366 static int
2367 entry_from_old_table(
2368 int id, int act,
2369 int bhead, int bsect, int bcyl,
2370 int ehead, int esect, int ecyl,
2371 uint32_t rsect, uint32_t numsect, int startindex)
2373 uint32_t i, j;
2375 if (id == SUNIXOS || id == SUNIXOS2 || id == UNUSED)
2376 return (-1);
2377 for (i = 0; i < FD_NUMPART; i++) {
2378 if (Old_Table[i].systid == id &&
2379 Old_Table[i].bootid == act &&
2380 Old_Table[i].beghead == bhead &&
2381 Old_Table[i].begsect == ((bsect & 0x3f) |
2382 (uchar_t)((bcyl>>2) & 0xc0)) &&
2383 Old_Table[i].begcyl == (uchar_t)(bcyl & 0xff) &&
2384 Old_Table[i].endhead == ehead &&
2385 Old_Table[i].endsect == ((esect & 0x3f) |
2386 (uchar_t)((ecyl>>2) & 0xc0)) &&
2387 Old_Table[i].endcyl == (uchar_t)(ecyl & 0xff) &&
2388 Old_Table[i].relsect == lel(rsect) &&
2389 Old_Table[i].numsect == lel(numsect)) {
2390 /* find UNUSED partition table entry */
2391 for (j = startindex; j < FD_NUMPART; j++) {
2392 if (Table[j].systid == UNUSED) {
2393 (void) memcpy(&Table[j], &Old_Table[i],
2394 sizeof (Table[0]));
2395 skip_verify[j] = 1;
2396 return (j);
2400 return (-1);
2404 return (-1);
2408 * verify_tbl
2409 * Verify that no partition entries overlap or exceed the size of
2410 * the disk.
2412 static int
2413 verify_tbl(void)
2415 uint32_t i, j, rsect, numsect;
2416 int noMoreParts = 0;
2417 int numParts = 0;
2419 /* Make sure new entry does not overlap an existing entry */
2420 for (i = 0; i < FD_NUMPART - 1; i++) {
2421 if (Table[i].systid != UNUSED) {
2422 numParts++;
2424 * No valid partitions allowed after EFI_PMBR part
2426 if (noMoreParts) {
2427 return (-1);
2430 if (Table[i].systid == EFI_PMBR) {
2432 * EFI_PMBR partition must be the only
2433 * partition
2435 noMoreParts = 1;
2437 if (Table[i].relsect != 1) {
2438 (void) fprintf(stderr, "ERROR: "
2439 "Invalid starting sector "
2440 "for EFI_PMBR partition:\n"
2441 "relsect %d "
2442 "(should be 1)\n",
2443 Table[i].relsect);
2445 return (-1);
2448 if (Table[i].numsect !=
2449 ((dev_capacity > DK_MAX_2TB) ? DK_MAX_2TB:
2450 (dev_capacity - 1))) {
2452 (void) fprintf(stderr, "ERROR: "
2453 "EFI_PMBR partition must "
2454 "encompass the entire");
2456 if (dev_capacity > DK_MAX_2TB)
2457 (void) fprintf(stderr,
2458 "maximum 2 TB.\n "
2459 "numsect %u - "
2460 "actual %llu\n",
2461 Table[i].numsect,
2462 (diskaddr_t)DK_MAX_2TB);
2464 else
2465 (void) fprintf(stderr,
2466 "disk.\n numsect %u - "
2467 "actual %llu\n",
2468 Table[i].numsect,
2469 dev_capacity - 1);
2471 return (-1);
2475 /* make sure the partition isn't larger than the disk */
2476 rsect = LE_32(Table[i].relsect);
2477 numsect = LE_32(Table[i].numsect);
2479 if ((((diskaddr_t)rsect + numsect) > dev_capacity) ||
2480 (((diskaddr_t)rsect + numsect) > DK_MAX_2TB)) {
2481 if (!skip_verify[i])
2482 return (-1);
2485 for (j = i + 1; j < FD_NUMPART; j++) {
2486 if (Table[j].systid != UNUSED) {
2487 uint32_t t_relsect =
2488 LE_32(Table[j].relsect);
2489 uint32_t t_numsect =
2490 LE_32(Table[j].numsect);
2492 if (noMoreParts) {
2493 (void) fprintf(stderr,
2494 "Cannot add partition to "
2495 "table; no more partitions "
2496 "allowed\n");
2498 if (io_debug) {
2499 (void) fprintf(stderr,
2500 "DEBUG: Current "
2501 "partition:\t"
2502 "%d:%d:%d:%d:%d:"
2503 "%d:%d:%d:%d:%d\n"
2504 " Next "
2505 "partition:\t\t"
2506 "%d:%d:%d:%d:%d:"
2507 "%d:%d:%d:%d:%d\n",
2508 Table[i].systid,
2509 Table[i].bootid,
2510 Table[i].begcyl,
2511 Table[i].beghead,
2512 Table[i].begsect,
2513 Table[i].endcyl,
2514 Table[i].endhead,
2515 Table[i].endsect,
2516 Table[i].relsect,
2517 Table[i].numsect,
2518 Table[j].systid,
2519 Table[j].bootid,
2520 Table[j].begcyl,
2521 Table[j].beghead,
2522 Table[j].begsect,
2523 Table[j].endcyl,
2524 Table[j].endhead,
2525 Table[j].endsect,
2526 Table[j].relsect,
2527 Table[j].numsect);
2530 return (-1);
2532 if ((rsect >=
2533 (t_relsect + t_numsect)) ||
2534 ((rsect + numsect) <= t_relsect)) {
2535 continue;
2536 } else {
2537 (void) fprintf(stderr, "ERROR: "
2538 "current partition overlaps"
2539 " following partition\n");
2541 return (-1);
2547 if (Table[i].systid != UNUSED) {
2548 if (noMoreParts)
2549 return (-1);
2550 if (!skip_verify[i] &&
2551 ((((diskaddr_t)lel(Table[i].relsect) +
2552 lel(Table[i].numsect)) > dev_capacity) ||
2553 (((diskaddr_t)lel(Table[i].relsect) +
2554 lel(Table[i].numsect)) > DK_MAX_2TB))) {
2555 return (-1);
2559 return (numParts);
2563 * pars_fdisk
2564 * Parse user-supplied data to set up fdisk partitions
2565 * (-A, -D, -F).
2567 static int
2568 pars_fdisk(
2569 char *line,
2570 int *id, int *act,
2571 int *bhead, int *bsect, int *bcyl,
2572 int *ehead, int *esect, int *ecyl,
2573 uint32_t *rsect, uint32_t *numsect)
2575 int i;
2576 int64_t test;
2577 char *tok, *p;
2578 char buf[256];
2580 if (line[0] == '\0' || line[0] == '\n' || line[0] == '*')
2581 return (1);
2582 line[strlen(line)] = '\0';
2583 for (i = 0; i < strlen(line); i++) {
2584 if (line[i] == '\0') {
2585 break;
2586 } else if (line[i] == ':') {
2587 line[i] = ' ';
2590 (void) strncpy(buf, line, 256);
2591 errno = 0;
2592 tok = strtok(buf, ": \t\n");
2593 while (tok != NULL) {
2594 for (p = tok; *p != '\0'; p++) {
2595 if (!isdigit(*p)) {
2596 (void) printf("Invalid input %s in line %s.\n",
2597 tok, line);
2598 exit(1);
2602 test = strtoll(tok, (char **)NULL, 10);
2603 if ((test < 0) || (test > 0xFFFFFFFF) || (errno != 0)) {
2604 (void) printf("Invalid input %s in line %s.\n", tok,
2605 line);
2606 exit(1);
2608 tok = strtok(NULL, ": \t\n");
2610 if (sscanf(line, "%d %d %d %d %d %d %d %d %u %u",
2611 id, act, bhead, bsect, bcyl, ehead, esect, ecyl,
2612 rsect, numsect) != 10) {
2613 (void) fprintf(stderr, "Syntax error:\n \"%s\".\n", line);
2614 exit(1);
2616 return (0);
2620 * validate_part
2621 * Validate that a new partition does not start at sector 0. Only UNUSED
2622 * partitions and previously existing partitions are allowed to start at 0.
2624 static int
2625 validate_part(int id, uint32_t rsect, uint32_t numsect)
2627 int i;
2628 if ((id != UNUSED) && (rsect == 0)) {
2629 for (i = 0; i < FD_NUMPART; i++) {
2630 if ((Old_Table[i].systid == id) &&
2631 (Old_Table[i].relsect == LE_32(rsect)) &&
2632 (Old_Table[i].numsect == LE_32(numsect)))
2633 return (0);
2635 (void) fprintf(stderr,
2636 "New partition cannot start at sector 0\n");
2637 return (-1);
2639 #ifdef i386
2640 if (id > FDISK_MAX_VALID_PART_ID) {
2641 (void) fprintf(stderr, "Invalid partition ID\n");
2642 return (-1);
2644 #endif
2645 return (0);
2649 * stage0
2650 * Print out interactive menu and process user input.
2652 static void
2653 stage0(void)
2655 #ifdef i386
2656 int rval;
2657 #endif
2658 dispmenu();
2659 for (;;) {
2660 (void) printf(Q_LINE);
2661 (void) printf("Enter Selection: ");
2662 (void) fgets(s, sizeof (s), stdin);
2663 rm_blanks(s);
2664 #ifdef i386
2665 while (!((s[0] > '0') && (s[0] < '8') &&
2666 ((s[1] == '\0') || (s[1] == '\n')))) {
2667 #else
2668 while (!((s[0] > '0') && (s[0] < '7') &&
2669 ((s[1] == '\0') || (s[1] == '\n')))) {
2670 #endif
2671 (void) printf(E_LINE); /* Clear any previous error */
2672 #ifdef i386
2673 (void) printf(
2674 "\aEnter a one-digit number between 1 and 7.");
2675 #else
2676 (void) printf(
2677 "\aEnter a one-digit number between 1 and 6.");
2678 #endif
2679 (void) printf(Q_LINE);
2680 (void) printf("Enter Selection: ");
2681 (void) fgets(s, sizeof (s), stdin);
2682 rm_blanks(s);
2684 (void) printf(E_LINE);
2685 switch (s[0]) {
2686 case '1':
2687 if (pcreate() == -1)
2688 return;
2689 break;
2690 case '2':
2691 if (pchange() == -1)
2692 return;
2693 break;
2694 case '3':
2695 if (pdelete() == -1)
2696 return;
2697 break;
2698 case '4':
2699 if (ppartid() == -1)
2700 return;
2701 break;
2702 #ifdef i386
2703 case '5':
2704 if (fdisk_ext_part_exists(epp)) {
2705 ext_part_menu();
2706 } else {
2707 (void) printf(Q_LINE);
2708 (void) printf("\nNo extended partition"
2709 " found\n");
2710 (void) printf("Press enter to "
2711 "continue\n");
2712 ext_read_input(s);
2714 break;
2715 case '6':
2716 /* update disk partition table, if changed */
2717 if (TableChanged() == 1) {
2718 copy_Table_to_Bootblk();
2719 dev_mboot_write(0, Bootsect, sectsiz);
2723 * If the VTOC table is wrong fix it
2724 * (truncate only)
2726 if (io_adjt) {
2727 fix_slice();
2729 if (!io_readonly) {
2730 rval = fdisk_commit_ext_part(epp);
2731 switch (rval) {
2732 case FDISK_SUCCESS:
2733 /* Success */
2734 /* Fallthrough */
2735 case FDISK_ENOEXTPART:
2736 /* Nothing to do */
2737 break;
2738 case FDISK_EMOUNTED:
2739 (void) printf(Q_LINE);
2740 preach_and_continue();
2741 continue;
2742 default:
2743 perror("Commit failed");
2744 exit(1);
2746 libfdisk_fini(&epp);
2748 (void) close(Dev);
2749 exit(0);
2750 /* NOTREACHED */
2751 #else
2752 case '5':
2753 /* update disk partition table, if changed */
2754 if (TableChanged() == 1) {
2755 copy_Table_to_Bootblk();
2756 dev_mboot_write(0, Bootsect, sectsiz);
2759 * If the VTOC table is wrong fix it
2760 * (truncate only)
2762 if (io_adjt) {
2763 fix_slice();
2765 (void) close(Dev);
2766 exit(0);
2767 /* FALLTHRU */
2768 #endif
2769 #ifdef i386
2770 case '7':
2771 #else
2772 case '6':
2773 #endif
2775 * If the VTOC table is wrong fix it
2776 * (truncate only)
2778 if (io_adjt) {
2779 fix_slice();
2781 (void) close(Dev);
2782 exit(0);
2783 /* FALLTHRU */
2784 default:
2785 break;
2787 copy_Table_to_Bootblk();
2788 disptbl();
2789 dispmenu();
2794 * pcreate
2795 * Create partition entry in the table (interactive mode).
2797 static int
2798 pcreate(void)
2800 uchar_t tsystid = 'z';
2801 int i, j;
2802 uint32_t numsect;
2803 int retCode = 0;
2804 #ifdef i386
2805 int ext_part_present = 0;
2806 #endif
2808 i = 0;
2809 for (;;) {
2810 if (i == FD_NUMPART) {
2811 (void) printf(E_LINE);
2812 (void) printf(
2813 "\aThe partition table is full!\n"
2814 "You must delete a partition before creating"
2815 " a new one.\n");
2816 return (-1);
2818 if (Table[i].systid == UNUSED) {
2819 break;
2821 i++;
2824 numsect = 0;
2825 for (i = 0; i < FD_NUMPART; i++) {
2826 if (Table[i].systid != UNUSED) {
2827 numsect += LE_32(Table[i].numsect);
2829 #ifdef i386
2830 /* Check if an extended partition already exists */
2831 if (fdisk_is_dos_extended(Table[i].systid)) {
2832 ext_part_present = 1;
2834 #endif
2835 if (numsect >= chs_capacity) {
2836 (void) printf(E_LINE);
2837 (void) printf("\aThere is no more room on the disk for"
2838 " another partition.\n");
2839 (void) printf(
2840 "You must delete a partition before creating"
2841 " a new one.\n");
2842 return (-1);
2845 while (tsystid == 'z') {
2848 * The question here is expanding to more than what is
2849 * allocated for question lines (Q_LINE) which garbles
2850 * at least warning line. Clearing warning line as workaround
2851 * for now.
2854 (void) printf(W_LINE);
2855 (void) printf(Q_LINE);
2856 (void) printf(
2857 "Select the partition type to create:\n"
2858 " 1=SOLARIS2 2=UNIX 3=PCIXOS 4=Other\n"
2859 " 5=DOS12 6=DOS16 7=DOSEXT 8=DOSBIG\n"
2860 " 9=DOS16LBA A=x86 Boot B=Diagnostic C=FAT32\n"
2861 " D=FAT32LBA E=DOSEXTLBA F=EFI 0=Exit? ");
2862 (void) fgets(s, sizeof (s), stdin);
2863 rm_blanks(s);
2864 if ((s[1] != '\0') && (s[1] != '\n')) {
2865 (void) printf(E_LINE);
2866 (void) printf("Invalid selection, try again.");
2867 continue;
2869 switch (s[0]) {
2870 case '0': /* exit */
2871 (void) printf(E_LINE);
2872 return (-1);
2873 case '1': /* Solaris partition */
2874 tsystid = SUNIXOS2;
2875 break;
2876 case '2': /* UNIX partition */
2877 tsystid = UNIXOS;
2878 break;
2879 case '3': /* PCIXOS partition */
2880 tsystid = PCIXOS;
2881 break;
2882 case '4': /* OTHEROS System partition */
2883 tsystid = OTHEROS;
2884 break;
2885 case '5':
2886 tsystid = DOSOS12; /* DOS 12 bit fat */
2887 break;
2888 case '6':
2889 tsystid = DOSOS16; /* DOS 16 bit fat */
2890 break;
2891 case '7':
2892 #ifdef i386
2893 if (ext_part_present) {
2894 (void) printf(Q_LINE);
2895 (void) printf(E_LINE);
2896 (void) fprintf(stderr,
2897 "Extended partition already exists\n");
2898 (void) fprintf(stderr,
2899 "Press enter to continue\n");
2900 ext_read_input(s);
2901 continue;
2903 #endif
2904 tsystid = EXTDOS;
2905 break;
2906 case '8':
2907 tsystid = DOSHUGE;
2908 break;
2909 case '9':
2910 tsystid = FDISK_FAT95; /* FAT16, need extended int13 */
2911 break;
2912 case 'a': /* x86 Boot partition */
2913 case 'A':
2914 tsystid = X86BOOT;
2915 break;
2916 case 'b': /* Diagnostic boot partition */
2917 case 'B':
2918 tsystid = DIAGPART;
2919 break;
2920 case 'c': /* FAT32 */
2921 case 'C':
2922 tsystid = FDISK_WINDOWS;
2923 break;
2924 case 'd': /* FAT32 and need extended int13 */
2925 case 'D':
2926 tsystid = FDISK_EXT_WIN;
2927 break;
2928 case 'e': /* Extended partition, need extended int13 */
2929 case 'E':
2930 #ifdef i386
2931 if (ext_part_present) {
2932 (void) printf(Q_LINE);
2933 (void) printf(E_LINE);
2934 (void) fprintf(stderr,
2935 "Extended partition already exists\n");
2936 (void) fprintf(stderr,
2937 "Press enter to continue\n");
2938 ext_read_input(s);
2939 continue;
2941 #endif
2942 tsystid = FDISK_EXTLBA;
2943 break;
2944 case 'f':
2945 case 'F':
2946 tsystid = EFI_PMBR;
2947 break;
2948 default:
2949 (void) printf(E_LINE);
2950 (void) printf("Invalid selection, try again.");
2951 continue;
2955 (void) printf(E_LINE);
2957 if (tsystid != EFI_PMBR) {
2958 (void) printf(W_LINE);
2959 if ((dev_capacity > DK_MAX_2TB))
2960 (void) printf("WARNING: Disk is larger than 2 TB. "
2961 "Upper limit is 2 TB for non-EFI partition ID\n");
2963 /* create the new partition */
2964 i = specify(tsystid);
2966 if (i != -1) {
2967 /* see if it should be the active partition */
2968 (void) printf(E_LINE);
2969 (void) printf(Q_LINE);
2971 (void) printf(
2972 "Should this become the active partition? If "
2973 "yes, it will be activated\n"
2974 "each time the computer is reset or turned on.\n"
2975 "Please type \"y\" or \"n\". ");
2977 if (yesno()) {
2978 (void) printf(E_LINE);
2979 for (j = 0; j < FD_NUMPART; j++) {
2980 if (j == i) {
2981 Table[j].bootid = ACTIVE;
2982 (void) printf(E_LINE);
2983 (void) printf(
2984 "Partition %d is now "
2985 "the active partition.",
2986 j + 1);
2987 } else {
2988 Table[j].bootid = 0;
2991 } else {
2992 Table[i].bootid = 0;
2995 #ifdef i386
2997 * If partition created is an extended partition, null
2998 * out the first sector of the first cylinder of the
2999 * extended partition
3001 if (fdisk_is_dos_extended(Table[i].systid)) {
3002 (void) fdisk_init_ext_part(epp,
3003 LE_32(Table[i].relsect),
3004 LE_32(Table[i].numsect));
3006 #endif
3007 /* set up the return code */
3008 i = 1;
3010 } else {
3012 * partitions of type EFI_PMBR must be the only partitions in
3013 * the table
3015 * First, make sure there were no errors the table is
3016 * empty
3018 retCode = verify_tbl();
3020 if (retCode < 0) {
3021 (void) fprintf(stderr,
3022 "fdisk: Cannot create EFI partition table; \n"
3023 "current partition table is invalid.\n");
3024 return (-1);
3025 } else if (retCode > 0) {
3026 (void) printf(
3027 "An EFI partition must be the only partition on "
3028 "disk. You may manually delete existing\n"
3029 "partitions, or fdisk can do it.\n"
3030 "Do you want fdisk to destroy existing "
3031 "partitions?\n"
3032 "Please type \"y\" or \"n\". ");
3034 if (yesno()) {
3035 nulltbl();
3036 } else {
3037 return (-1);
3041 /* create the table entry - i should be 0 */
3042 i = insert_tbl(tsystid, 0, 0, 0, 0, 0, 0, 0, 1,
3043 (dev_capacity > DK_MAX_2TB) ? DK_MAX_2TB:
3044 (dev_capacity - 1), 0);
3046 if (i != 0) {
3047 (void) printf("Error creating EFI partition!!!\n");
3048 i = -1;
3049 } else {
3051 /* EFI partitions are currently never active */
3052 Table[i].bootid = 0;
3054 /* set up the return code */
3055 i = 1;
3059 return (i);
3063 * specify
3064 * Query the user to specify the size of the new partition in
3065 * terms of percentage of the disk or by specifying the starting
3066 * cylinder and length in cylinders.
3068 static int
3069 specify(uchar_t tsystid)
3071 int i, j, percent = -1;
3072 int cyl, cylen;
3073 diskaddr_t first_free, size_free;
3074 diskaddr_t max_free;
3075 int cyl_size;
3076 struct ipart *partition[FD_NUMPART];
3077 struct ipart localpart[FD_NUMPART];
3079 cyl_size = heads * sectors;
3082 * make a local copy of the partition table
3083 * and sort it into relsect order
3087 for (i = 0, j = 0; i < FD_NUMPART; i++) {
3088 if (Table[i].systid != UNUSED) {
3089 localpart[j] = Table[i];
3090 j++;
3094 while (j < FD_NUMPART) {
3095 (void) memset(&localpart[j], 0, sizeof (struct ipart));
3096 j++;
3099 for (i = 0; i < FD_NUMPART; i++)
3100 partition[i] = &localpart[i];
3102 for (i = 0; i < FD_NUMPART - 1; i++) {
3103 if (partition[i]->systid == UNUSED)
3104 break;
3105 for (j = i + 1; j < FD_NUMPART; j++) {
3106 if (partition[j]->systid == UNUSED)
3107 break;
3108 if (LE_32(partition[j]->relsect) <
3109 LE_32(partition[i]->relsect)) {
3110 struct ipart *temp = partition[i];
3111 partition[i] = partition[j];
3112 partition[j] = temp;
3118 (void) printf(Q_LINE);
3119 (void) printf(
3120 "Specify the percentage of disk to use for this partition\n"
3121 "(or type \"c\" to specify the size in cylinders). ");
3122 (void) fgets(s, sizeof (s), stdin);
3123 rm_blanks(s);
3124 if (s[0] != 'c') { /* Specify size in percentage of disk */
3125 i = 0;
3126 while ((s[i] != '\0') && (s[i] != '\n')) {
3127 if (s[i] < '0' || s[i] > '9') {
3128 (void) printf(E_LINE);
3129 (void) printf("\aInvalid percentage value "
3130 "specified; retry the operation.");
3131 return (-1);
3133 i++;
3134 if (i > 3) {
3135 (void) printf(E_LINE);
3136 (void) printf("\aInvalid percentage value "
3137 "specified; retry the operation.");
3138 return (-1);
3141 if ((percent = atoi(s)) > 100) {
3142 (void) printf(E_LINE);
3143 (void) printf(
3144 "\aPercentage value is too large. The value must be"
3145 " between 1 and 100;\nretry the operation.\n");
3146 return (-1);
3148 if (percent < 1) {
3149 (void) printf(E_LINE);
3150 (void) printf(
3151 "\aPercentage value is too small. The value must be"
3152 " between 1 and 100;\nretry the operation.\n");
3153 return (-1);
3156 if (percent == 100)
3157 cylen = Numcyl_usable - 1;
3158 else
3159 cylen = (Numcyl_usable * percent) / 100;
3161 /* Verify DOS12 partition doesn't exceed max size of 32MB. */
3162 if ((tsystid == DOSOS12) &&
3163 ((long)((long)cylen * cyl_size) > MAXDOS)) {
3164 int n;
3165 n = MAXDOS * 100 / (int)(cyl_size) / Numcyl_usable;
3166 (void) printf(E_LINE);
3167 (void) printf("\aMaximum size for a DOS partition "
3168 "is %d%%; retry the operation.",
3169 n <= 100 ? n : 100);
3170 return (-1);
3174 max_free = 0;
3175 for (i = 0; i < FD_NUMPART; i++) {
3178 * check for free space before partition i
3179 * where i varies from 0 to 3
3181 * freespace after partition 3 is unusable
3182 * because there are no free partitions
3184 * freespace begins at the end of previous partition
3185 * or cylinder 1
3187 if (i) {
3188 /* Not an empty table */
3189 first_free = LE_32(partition[i - 1]->relsect) +
3190 LE_32(partition[i - 1]->numsect);
3191 } else {
3192 first_free = cyl_size;
3196 * freespace ends before the current partition
3197 * or the end of the disk (chs end)
3199 if (partition[i]->systid == UNUSED) {
3200 size_free = chs_capacity - first_free;
3201 } else {
3203 * Partition might start before cylinder 1.
3204 * Make sure free space is not negative.
3206 size_free =
3207 (LE_32(partition[i]->relsect > first_free))
3208 ? (LE_32(partition[i]->relsect) -
3209 first_free) : 0;
3212 /* save largest free space */
3213 if (max_free < size_free)
3214 max_free = size_free;
3216 if (((uint64_t)cylen * cyl_size) <= size_free) {
3217 /* We found a place to use */
3218 break;
3220 if (partition[i]->systid == UNUSED) {
3221 (void) printf(E_LINE);
3222 max_free /= (cyl_size);
3223 (void) fprintf(stderr, "fdisk: "
3224 "Maximum percentage available is %lld\n",
3225 100 * max_free / Numcyl_usable);
3226 return (-1);
3230 (void) printf(E_LINE);
3231 if (i >= FD_NUMPART) {
3232 (void) fprintf(stderr,
3233 "fdisk: Partition table is full.\n");
3234 return (-1);
3237 if ((i = insert_tbl(tsystid, 0, 0, 0, 0, 0, 0, 0,
3238 first_free, cylen * cyl_size, 0)) >= 0) {
3239 return (i);
3241 return (-1);
3242 } else {
3244 /* Specifying size in cylinders */
3245 (void) printf(E_LINE);
3246 (void) printf(Q_LINE);
3247 (void) printf("Enter starting cylinder number: ");
3248 if ((cyl = getcyl()) == -1) {
3249 (void) printf(E_LINE);
3250 (void) printf("Invalid number; retry the operation.");
3251 return (-1);
3253 if (cyl == 0) {
3254 (void) printf(E_LINE);
3255 (void) printf(
3256 "\aNew partition cannot start at cylinder 0.\n");
3257 return (-1);
3261 if (cyl >= Numcyl_usable) {
3262 (void) printf(E_LINE);
3263 (void) printf(
3264 "\aCylinder %d is out of bounds, "
3265 "the maximum is %d.\n",
3266 cyl, Numcyl_usable - 1);
3267 return (-1);
3270 (void) printf(Q_LINE);
3271 (void) printf("Enter partition size in cylinders: ");
3272 if ((cylen = getcyl()) == -1) {
3273 (void) printf(E_LINE);
3274 (void) printf("Invalid number, retry the operation.");
3275 return (-1);
3278 for (i = 0; i < FD_NUMPART; i++) {
3279 uint32_t t_relsect, t_numsect;
3281 if (partition[i]->systid == UNUSED)
3282 break;
3283 t_relsect = LE_32(partition[i]->relsect);
3284 t_numsect = LE_32(partition[i]->numsect);
3286 if (cyl * cyl_size >= t_relsect &&
3287 cyl * cyl_size < t_relsect + t_numsect) {
3288 (void) printf(E_LINE);
3289 (void) printf(
3290 "Cylinder %d is already allocated"
3291 "\nretry the operation.",
3292 cyl);
3293 return (-1);
3296 if (cyl * cyl_size < t_relsect &&
3297 (cyl + cylen - 1) * cyl_size > t_relsect) {
3298 (void) printf(E_LINE);
3299 (void) printf(
3300 "Maximum size for partition is %u cylinders"
3301 "\nretry the operation.",
3302 (t_relsect - cyl * cyl_size) / cyl_size);
3303 return (-1);
3307 /* Verify partition doesn't exceed disk size or 2 TB */
3308 if (cyl + cylen > Numcyl_usable) {
3309 (void) printf(E_LINE);
3310 if (Numcyl > Numcyl_usable) {
3311 (void) printf(
3312 "Maximum size for partition is %d "
3313 "cylinders; \nretry the operation.",
3314 Numcyl_usable - cyl);
3315 } else {
3316 (void) printf(
3317 "Maximum size for partition is %d "
3318 "cylinders; \nretry the operation.",
3319 Numcyl_usable - cyl);
3321 return (-1);
3324 /* Verify DOS12 partition doesn't exceed max size of 32MB. */
3325 if ((tsystid == DOSOS12) &&
3326 ((long)((long)cylen * cyl_size) > MAXDOS)) {
3327 (void) printf(E_LINE);
3328 (void) printf(
3329 "Maximum size for a %s partition is %ld cylinders;"
3330 "\nretry the operation.",
3331 Dstr, MAXDOS / (int)(cyl_size));
3332 return (-1);
3335 (void) printf(E_LINE);
3336 i = insert_tbl(tsystid, 0, 0, 0, 0, 0, 0, 0,
3337 cyl * cyl_size, cylen * cyl_size, 0);
3338 if (i < 0)
3339 return (-1);
3341 if (verify_tbl() < 0) {
3342 (void) printf(E_LINE);
3343 (void) printf("fdisk: Cannot create partition table\n");
3344 return (-1);
3347 return (i);
3352 * dispmenu
3353 * Display command menu (interactive mode).
3355 static void
3356 dispmenu(void)
3358 (void) printf(M_LINE);
3359 #ifdef i386
3360 (void) printf(
3361 "SELECT ONE OF THE FOLLOWING:\n"
3362 " 1. Create a partition\n"
3363 " 2. Specify the active partition\n"
3364 " 3. Delete a partition\n"
3365 " 4. Change between Solaris and Solaris2 Partition IDs\n"
3366 " 5. Edit/View extended partitions\n"
3367 " 6. Exit (update disk configuration and exit)\n"
3368 " 7. Cancel (exit without updating disk configuration)\n");
3369 #else
3370 (void) printf(
3371 "SELECT ONE OF THE FOLLOWING:\n"
3372 " 1. Create a partition\n"
3373 " 2. Specify the active partition\n"
3374 " 3. Delete a partition\n"
3375 " 4. Change between Solaris and Solaris2 Partition IDs\n"
3376 " 5. Exit (update disk configuration and exit)\n"
3377 " 6. Cancel (exit without updating disk configuration)\n");
3378 #endif
3382 * pchange
3383 * Change the ACTIVE designation of a partition.
3385 static int
3386 pchange(void)
3388 char s[80];
3389 int i, j;
3391 for (;;) {
3392 (void) printf(Q_LINE);
3394 (void) printf(
3395 "Specify the partition number to boot from"
3396 " (or specify 0 for none): ");
3398 (void) fgets(s, sizeof (s), stdin);
3399 rm_blanks(s);
3400 if (((s[1] != '\0') && (s[1] != '\n')) ||
3401 (s[0] < '0') || (s[0] > '4')) {
3402 (void) printf(E_LINE);
3403 (void) printf(
3404 "\aInvalid response, please specify a number"
3405 " between 0 and 4.\n");
3406 } else {
3407 break;
3410 if (s[0] == '0') { /* No active partitions */
3411 for (i = 0; i < FD_NUMPART; i++) {
3412 if (Table[i].systid != UNUSED &&
3413 Table[i].bootid == ACTIVE)
3414 Table[i].bootid = 0;
3416 (void) printf(E_LINE);
3417 (void) printf(
3418 "\aNo partition is currently marked as active.");
3419 return (0);
3420 } else { /* User has selected a partition to be active */
3422 i = s[0] - '1';
3424 if (Table[i].systid == UNUSED) {
3425 (void) printf(E_LINE);
3426 (void) printf("\aPartition does not exist.");
3427 return (-1);
3429 /* a DOS-DATA or EXT-DOS partition cannot be active */
3430 else if ((Table[i].systid == DOSDATA) ||
3431 (Table[i].systid == EXTDOS) ||
3432 (Table[i].systid == FDISK_EXTLBA)) {
3433 (void) printf(E_LINE);
3434 (void) printf(
3435 "DOS-DATA, EXT_DOS and EXT_DOS_LBA partitions "
3436 "cannot be made active.\n");
3437 (void) printf("Select another partition.");
3438 return (-1);
3440 Table[i].bootid = ACTIVE;
3441 for (j = 0; j < FD_NUMPART; j++) {
3442 if (j != i)
3443 Table[j].bootid = 0;
3446 (void) printf(E_LINE);
3448 (void) printf(
3449 "Partition %d is now active. The system will start up"
3450 " from this\n", i + 1);
3451 (void) printf("partition after the next reboot.");
3453 return (1);
3457 * Change between SOLARIS and SOLARIS2 partition id
3459 static int
3460 ppartid(void)
3462 char *p, s[80];
3463 int i;
3465 for (;;) {
3466 (void) printf(Q_LINE);
3467 (void) printf("Specify the partition number to change"
3468 " (or enter 0 to exit): ");
3469 if (!fgets(s, sizeof (s), stdin))
3470 return (1);
3471 i = strtol(s, &p, 10);
3473 if (*p != '\n' || i < 0 || i > FD_NUMPART) {
3474 (void) printf(E_LINE);
3475 (void) printf(
3476 "Invalid response, retry the operation.\n");
3477 continue;
3480 if (i == 0) {
3481 /* exit delete command */
3482 (void) printf(E_LINE); /* clear error message */
3483 return (1);
3486 i -= 1;
3488 if (Table[i].systid == SUNIXOS) {
3489 Table[i].systid = SUNIXOS2;
3490 } else if (Table[i].systid == SUNIXOS2) {
3491 Table[i].systid = SUNIXOS;
3492 } else {
3493 (void) printf(E_LINE);
3494 (void) printf(
3495 "Partition %d is not a Solaris partition.",
3496 i + 1);
3497 continue;
3500 (void) printf(E_LINE);
3501 (void) printf("Partition %d has been changed.", i + 1);
3502 return (1);
3507 * pdelete
3508 * Remove partition entry from the table (interactive mode).
3510 static char
3511 pdelete(void)
3513 char s[80];
3514 int i;
3515 char pactive;
3517 DEL1: (void) printf(Q_LINE);
3518 (void) printf("Specify the partition number to delete"
3519 " (or enter 0 to exit): ");
3520 (void) fgets(s, sizeof (s), stdin);
3521 rm_blanks(s);
3522 if ((s[0] == '0')) { /* exit delete command */
3523 (void) printf(E_LINE); /* clear error message */
3524 return (1);
3526 /* Accept only a single digit between 1 and 4 */
3527 if (((s[1] != '\0') && (s[1] != '\n')) ||
3528 (i = atoi(s)) < 1 || i > FD_NUMPART) {
3529 (void) printf(E_LINE);
3530 (void) printf("Invalid response, retry the operation.\n");
3531 goto DEL1;
3532 } else { /* Found a digit between 1 and 4 */
3533 --i; /* Structure begins with element 0 */
3536 if (Table[i].systid == UNUSED) {
3537 (void) printf(E_LINE);
3538 (void) printf("\aPartition %d does not exist.", i + 1);
3539 return (-1);
3542 #ifdef i386
3543 if (fdisk_is_dos_extended(Table[i].systid) &&
3544 (Table[i].relsect == fdisk_get_ext_beg_sec(epp)) &&
3545 fdisk_get_logical_drive_count(epp)) {
3546 (void) printf(Q_LINE);
3547 (void) printf("There are logical drives inside the"
3548 " extended partition\n");
3549 (void) printf("Are you sure of proceeding with deletion ?"
3550 " (type \"y\" or \"n\") ");
3552 (void) printf(E_LINE);
3553 if (! yesno()) {
3554 return (1);
3556 if (fdisk_mounted_logical_drives(epp) == FDISK_EMOUNTED) {
3557 (void) printf(Q_LINE);
3558 (void) printf("There are mounted logical drives. "
3559 "Committing changes now can cause data loss or "
3560 "corruption. Unmount all logical drives and then "
3561 "try committing the changes again.\n");
3562 (void) printf("Press enter to continue.\n");
3563 ext_read_input(s);
3564 return (1);
3566 (void) fdisk_delete_ext_part(epp);
3567 } else {
3568 #endif
3569 (void) printf(Q_LINE);
3570 (void) printf("Are you sure you want to delete partition %d?"
3571 " This will make all files and \n", i + 1);
3572 (void) printf("programs in this partition inaccessible (type"
3573 " \"y\" or \"n\"). ");
3575 (void) printf(E_LINE);
3576 if (! yesno()) {
3577 return (1);
3579 #ifdef i386
3581 #endif
3583 if (Table[i].bootid == ACTIVE) {
3584 pactive = 1;
3585 } else {
3586 pactive = 0;
3589 (void) memset(&Table[i], 0, sizeof (struct ipart));
3591 (void) printf(E_LINE);
3592 (void) printf("Partition %d has been deleted.", i + 1);
3594 if (pactive) {
3595 (void) printf(" This was the active partition.");
3598 return (1);
3602 * rm_blanks
3603 * Remove blanks from strings of user responses.
3605 static void
3606 rm_blanks(char *s)
3608 register int i, j;
3610 for (i = 0; i < CBUFLEN; i++) {
3611 if ((s[i] == ' ') || (s[i] == '\t'))
3612 continue;
3613 else
3614 /* Found first non-blank character of the string */
3615 break;
3617 for (j = 0; i < CBUFLEN; j++, i++) {
3618 if ((s[j] = s[i]) == '\0') {
3619 /* Reached end of string */
3620 return;
3626 * getcyl
3627 * Take the user-specified cylinder number and convert it from a
3628 * string to a decimal value.
3630 static int
3631 getcyl(void)
3633 int slen, i, j;
3634 unsigned int cyl;
3635 (void) fgets(s, sizeof (s), stdin);
3636 rm_blanks(s);
3637 slen = strlen(s);
3638 if (s[slen - 1] == '\n')
3639 slen--;
3640 j = 1;
3641 cyl = 0;
3642 for (i = slen - 1; i >= 0; i--) {
3643 if (s[i] < '0' || s[i] > '9') {
3644 return (-1);
3646 cyl += (j * (s[i] - '0'));
3647 j *= 10;
3649 return (cyl);
3653 * disptbl
3654 * Display the current fdisk table; determine percentage
3655 * of the disk used for each partition.
3657 static void
3658 disptbl(void)
3660 int i;
3661 unsigned int startcyl, endcyl, length, percent, remainder;
3662 char *stat, *type;
3663 int is_pmbr = 0;
3665 if ((heads == 0) || (sectors == 0)) {
3666 (void) printf("WARNING: critical disk geometry information"
3667 " missing!\n");
3668 (void) printf("\theads = %d, sectors = %d\n", heads, sectors);
3669 exit(1);
3672 (void) printf(HOME);
3673 (void) printf(T_LINE);
3674 (void) printf(" Total disk size is %d cylinders\n", Numcyl);
3675 (void) printf(" Cylinder size is %d (%d byte) blocks\n\n",
3676 heads * sectors, sectsiz);
3677 (void) printf(
3678 " Cylinders\n");
3679 (void) printf(
3680 " Partition Status Type Start End Length"
3681 " %%\n");
3682 (void) printf(
3683 " ========= ====== ============ ===== === ======"
3684 " ===");
3687 for (i = 0; i < FD_NUMPART; i++) {
3689 if (Table[i].systid == UNUSED) {
3690 continue;
3693 if (Table[i].bootid == ACTIVE)
3694 stat = Actvstr;
3695 else
3696 stat = NAstr;
3697 switch (Table[i].systid) {
3698 case UNIXOS:
3699 type = Ustr;
3700 break;
3701 case SUNIXOS:
3702 type = SUstr;
3703 #ifdef i386
3704 if (fdisk_is_linux_swap(epp, Table[i].relsect,
3705 NULL) == 0)
3706 type = LINSWAPstr;
3707 #endif
3708 break;
3709 case SUNIXOS2:
3710 type = SU2str;
3711 break;
3712 case X86BOOT:
3713 type = X86str;
3714 break;
3715 case DOSOS12:
3716 type = Dstr;
3717 break;
3718 case DOSOS16:
3719 type = D16str;
3720 break;
3721 case EXTDOS:
3722 type = EDstr;
3723 break;
3724 case DOSDATA:
3725 type = DDstr;
3726 break;
3727 case DOSHUGE:
3728 type = DBstr;
3729 break;
3730 case PCIXOS:
3731 type = PCstr;
3732 break;
3733 case DIAGPART:
3734 type = DIAGstr;
3735 break;
3736 case FDISK_IFS:
3737 type = IFSstr;
3738 break;
3739 case FDISK_AIXBOOT:
3740 type = AIXstr;
3741 break;
3742 case FDISK_AIXDATA:
3743 type = AIXDstr;
3744 break;
3745 case FDISK_OS2BOOT:
3746 type = OS2str;
3747 break;
3748 case FDISK_WINDOWS:
3749 type = WINstr;
3750 break;
3751 case FDISK_EXT_WIN:
3752 type = EWINstr;
3753 break;
3754 case FDISK_FAT95:
3755 type = FAT95str;
3756 break;
3757 case FDISK_EXTLBA:
3758 type = EXTLstr;
3759 break;
3760 case FDISK_LINUX:
3761 type = LINUXstr;
3762 break;
3763 case FDISK_CPM:
3764 type = CPMstr;
3765 break;
3766 case FDISK_NOVELL2:
3767 type = NOV2str;
3768 break;
3769 case FDISK_NOVELL3:
3770 type = NOVstr;
3771 break;
3772 case FDISK_QNX4:
3773 type = QNXstr;
3774 break;
3775 case FDISK_QNX42:
3776 type = QNX2str;
3777 break;
3778 case FDISK_QNX43:
3779 type = QNX3str;
3780 break;
3781 case FDISK_LINUXNAT:
3782 type = LINNATstr;
3783 break;
3784 case FDISK_NTFSVOL1:
3785 type = NTFSVOL1str;
3786 break;
3787 case FDISK_NTFSVOL2:
3788 type = NTFSVOL2str;
3789 break;
3790 case FDISK_BSD:
3791 type = BSDstr;
3792 break;
3793 case FDISK_NEXTSTEP:
3794 type = NEXTSTEPstr;
3795 break;
3796 case FDISK_BSDIFS:
3797 type = BSDIFSstr;
3798 break;
3799 case FDISK_BSDISWAP:
3800 type = BSDISWAPstr;
3801 break;
3802 case EFI_PMBR:
3803 type = EFIstr;
3804 if (LE_32(Table[i].numsect) == DK_MAX_2TB)
3805 is_pmbr = 1;
3807 break;
3808 default:
3809 type = Ostr;
3810 break;
3812 startcyl = LE_32(Table[i].relsect) /
3813 (unsigned long)(heads * sectors);
3815 if (LE_32(Table[i].numsect) == DK_MAX_2TB) {
3816 endcyl = Numcyl - 1;
3817 length = endcyl - startcyl + 1;
3818 } else {
3819 length = LE_32(Table[i].numsect) /
3820 (unsigned long)(heads * sectors);
3821 if (LE_32(Table[i].numsect) %
3822 (unsigned long)(heads * sectors))
3823 length++;
3824 endcyl = startcyl + length - 1;
3827 percent = length * 100 / Numcyl_usable;
3828 if ((remainder = (length * 100 % Numcyl_usable)) != 0) {
3829 if ((remainder * 100 / Numcyl_usable) > 50) {
3830 /* round up */
3831 percent++;
3833 /* Else leave the percent as is since it's already */
3834 /* rounded down */
3836 if (percent > 100)
3837 percent = 100;
3838 (void) printf(
3839 "\n %d %s %-12.12s %4d %4d %4d"
3840 " %3d",
3841 i + 1, stat, type, startcyl, endcyl, length, percent);
3844 /* Print warning message if table is empty */
3845 if (nopartdefined()) {
3846 (void) printf(W_LINE);
3847 (void) printf("WARNING: no partitions are defined!");
3848 } else {
3849 /* Clear the warning line */
3850 (void) printf(W_LINE);
3852 /* Print warning if disk > 2TB and is not EFI PMBR */
3853 if (!is_pmbr && (dev_capacity > DK_MAX_2TB))
3854 (void) printf("WARNING: Disk is larger than 2 TB. "
3855 "Upper limit is 2 TB for non-EFI partition ID\n");
3860 * print_Table
3861 * Write the detailed fdisk table to standard error for
3862 * the selected disk device.
3864 static void
3865 print_Table(void)
3867 int i;
3869 (void) fprintf(stderr,
3870 " SYSID ACT BHEAD BSECT BEGCYL EHEAD ESECT ENDCYL RELSECT"
3871 " NUMSECT\n");
3873 for (i = 0; i < FD_NUMPART; i++) {
3874 (void) fprintf(stderr, " %-5d ", Table[i].systid);
3875 (void) fprintf(stderr, "%-3d ", Table[i].bootid);
3876 (void) fprintf(stderr, "%-5d ", Table[i].beghead);
3877 (void) fprintf(stderr, "%-5d ", Table[i].begsect & 0x3f);
3878 (void) fprintf(stderr, "%-8d ",
3879 (((uint_t)Table[i].begsect & 0xc0) << 2) + Table[i].begcyl);
3881 (void) fprintf(stderr, "%-5d ", Table[i].endhead);
3882 (void) fprintf(stderr, "%-5d ", Table[i].endsect & 0x3f);
3883 (void) fprintf(stderr, "%-8d ",
3884 (((uint_t)Table[i].endsect & 0xc0) << 2) + Table[i].endcyl);
3885 (void) fprintf(stderr, "%-10u ", LE_32(Table[i].relsect));
3886 (void) fprintf(stderr, "%-10u\n", LE_32(Table[i].numsect));
3892 * copy_Table_to_Old_Table
3893 * Copy Table into Old_Table. The function only copies the systid,
3894 * numsect, relsect, and bootid values because they are the only
3895 * ones compared when determining if Table has changed.
3897 static void
3898 copy_Table_to_Old_Table(void)
3900 int i;
3901 for (i = 0; i < FD_NUMPART; i++) {
3902 (void) memcpy(&Old_Table[i], &Table[i], sizeof (Table[0]));
3907 * nulltbl
3908 * Zero out the systid, numsect, relsect, and bootid values in the
3909 * fdisk table.
3911 static void
3912 nulltbl(void)
3914 int i;
3916 for (i = 0; i < FD_NUMPART; i++) {
3917 Table[i].systid = UNUSED;
3918 Table[i].numsect = LE_32(UNUSED);
3919 Table[i].relsect = LE_32(UNUSED);
3920 Table[i].bootid = 0;
3921 skip_verify[i] = 0;
3926 * copy_Bootblk_to_Table
3927 * Copy the bytes from the boot record to an internal "Table".
3928 * All unused are padded with zeros starting at offset 446.
3930 static void
3931 copy_Bootblk_to_Table(void)
3933 int i;
3934 char *bootptr;
3935 struct ipart iparts[FD_NUMPART];
3937 /* Get an aligned copy of the partition tables */
3938 (void) memcpy(iparts, Bootblk->parts, sizeof (iparts));
3939 bootptr = (char *)iparts; /* Points to start of partition table */
3940 if (LE_16(Bootblk->signature) != MBB_MAGIC) {
3941 /* Signature is missing */
3942 nulltbl();
3943 (void) memcpy(Bootblk->bootinst, &BootCod, BOOTSZ);
3944 return;
3947 * When the DOS fdisk command deletes a partition, it is not
3948 * recognized by the old algorithm. The algorithm that
3949 * follows looks at each entry in the Bootrec and copies all
3950 * those that are valid.
3952 for (i = 0; i < FD_NUMPART; i++) {
3953 if (iparts[i].systid == 0) {
3954 /* Null entry */
3955 (void) memset(&Table[i], 0, sizeof (struct ipart));
3956 } else {
3957 fill_ipart(bootptr, &Table[i]);
3959 bootptr += sizeof (struct ipart);
3962 /* For now, always replace the bootcode with ours */
3963 (void) memcpy(Bootblk->bootinst, &BootCod, BOOTSZ);
3964 copy_Table_to_Bootblk();
3968 * fill_ipart
3969 * Initialize ipart structure values.
3971 static void
3972 fill_ipart(char *bootptr, struct ipart *partp)
3974 #ifdef sparc
3975 /* Packing struct ipart for Sparc */
3976 partp->bootid = getbyte(&bootptr);
3977 partp->beghead = getbyte(&bootptr);
3978 partp->begsect = getbyte(&bootptr);
3979 partp->begcyl = getbyte(&bootptr);
3980 partp->systid = getbyte(&bootptr);
3981 partp->endhead = getbyte(&bootptr);
3982 partp->endsect = getbyte(&bootptr);
3983 partp->endcyl = getbyte(&bootptr);
3984 partp->relsect = (int32_t)getlong(&bootptr);
3985 partp->numsect = (int32_t)getlong(&bootptr);
3986 #else
3987 *partp = *(struct ipart *)bootptr;
3988 #endif
3992 * getbyte, getlong
3993 * Get a byte, a short, or a long (SPARC only).
3995 #ifdef sparc
3996 uchar_t
3997 getbyte(char **bp)
3999 uchar_t b;
4001 b = (uchar_t)**bp;
4002 *bp = *bp + 1;
4003 return (b);
4006 uint32_t
4007 getlong(char **bp)
4009 int32_t b, bh, bl;
4011 bh = ((**bp) << 8) | *(*bp + 1);
4012 *bp += 2;
4013 bl = ((**bp) << 8) | *(*bp + 1);
4014 *bp += 2;
4016 b = (bh << 16) | bl;
4017 return ((uint32_t)b);
4019 #endif
4022 * copy_Table_to_Bootblk
4023 * Copy the table into the boot record. Note that the unused
4024 * entries will always be the last ones in the table and they are
4025 * marked with 100 in sysind. The the unused portion of the table
4026 * is padded with zeros in the bytes after the used entries.
4028 static void
4029 copy_Table_to_Bootblk(void)
4031 struct ipart *boot_ptr, *tbl_ptr;
4033 boot_ptr = (struct ipart *)Bootblk->parts;
4034 tbl_ptr = (struct ipart *)&Table[0].bootid;
4035 for (; tbl_ptr < (struct ipart *)&Table[FD_NUMPART].bootid;
4036 tbl_ptr++, boot_ptr++) {
4037 if (tbl_ptr->systid == UNUSED)
4038 (void) memset(boot_ptr, 0, sizeof (struct ipart));
4039 else
4040 (void) memcpy(boot_ptr, tbl_ptr, sizeof (struct ipart));
4042 Bootblk->signature = LE_16(MBB_MAGIC);
4046 * TableChanged
4047 * Check for any changes in the partition table.
4049 static int
4050 TableChanged(void)
4052 int i, changed;
4054 changed = 0;
4055 for (i = 0; i < FD_NUMPART; i++) {
4056 if (memcmp(&Old_Table[i], &Table[i], sizeof (Table[0])) != 0) {
4057 /* Partition table changed, write back to disk */
4058 changed = 1;
4062 return (changed);
4066 * ffile_write
4067 * Display contents of partition table to standard output or
4068 * another file name without writing it to the disk (-W file).
4070 static void
4071 ffile_write(char *file)
4073 register int i;
4074 FILE *fp;
4077 * If file isn't standard output, then it's a file name.
4078 * Open file and write it.
4080 if (file != (char *)stdout) {
4081 if ((fp = fopen(file, "w")) == NULL) {
4082 (void) fprintf(stderr,
4083 "fdisk: Cannot open output file %s.\n",
4084 file);
4085 exit(1);
4088 else
4089 fp = stdout;
4092 * Write the fdisk table information
4094 (void) fprintf(fp, "\n* %s default fdisk table\n", Dfltdev);
4095 (void) fprintf(fp, "* Dimensions:\n");
4096 (void) fprintf(fp, "* %4d bytes/sector\n", sectsiz);
4097 (void) fprintf(fp, "* %4d sectors/track\n", sectors);
4098 (void) fprintf(fp, "* %4d tracks/cylinder\n", heads);
4099 (void) fprintf(fp, "* %4d cylinders\n", Numcyl);
4100 (void) fprintf(fp, "*\n");
4101 /* Write virtual (HBA) geometry, if required */
4102 if (v_flag) {
4103 (void) fprintf(fp, "* HBA Dimensions:\n");
4104 (void) fprintf(fp, "* %4d bytes/sector\n", sectsiz);
4105 (void) fprintf(fp, "* %4d sectors/track\n", hba_sectors);
4106 (void) fprintf(fp, "* %4d tracks/cylinder\n", hba_heads);
4107 (void) fprintf(fp, "* %4d cylinders\n", hba_Numcyl);
4108 (void) fprintf(fp, "*\n");
4110 (void) fprintf(fp, "* systid:\n");
4111 (void) fprintf(fp, "* 1: DOSOS12\n");
4112 (void) fprintf(fp, "* 2: PCIXOS\n");
4113 (void) fprintf(fp, "* 4: DOSOS16\n");
4114 (void) fprintf(fp, "* 5: EXTDOS\n");
4115 (void) fprintf(fp, "* 6: DOSBIG\n");
4116 (void) fprintf(fp, "* 7: FDISK_IFS\n");
4117 (void) fprintf(fp, "* 8: FDISK_AIXBOOT\n");
4118 (void) fprintf(fp, "* 9: FDISK_AIXDATA\n");
4119 (void) fprintf(fp, "* 10: FDISK_0S2BOOT\n");
4120 (void) fprintf(fp, "* 11: FDISK_WINDOWS\n");
4121 (void) fprintf(fp, "* 12: FDISK_EXT_WIN\n");
4122 (void) fprintf(fp, "* 14: FDISK_FAT95\n");
4123 (void) fprintf(fp, "* 15: FDISK_EXTLBA\n");
4124 (void) fprintf(fp, "* 18: DIAGPART\n");
4125 (void) fprintf(fp, "* 65: FDISK_LINUX\n");
4126 (void) fprintf(fp, "* 82: FDISK_CPM\n");
4127 (void) fprintf(fp, "* 86: DOSDATA\n");
4128 (void) fprintf(fp, "* 98: OTHEROS\n");
4129 (void) fprintf(fp, "* 99: UNIXOS\n");
4130 (void) fprintf(fp, "* 100: FDISK_NOVELL2\n");
4131 (void) fprintf(fp, "* 101: FDISK_NOVELL3\n");
4132 (void) fprintf(fp, "* 119: FDISK_QNX4\n");
4133 (void) fprintf(fp, "* 120: FDISK_QNX42\n");
4134 (void) fprintf(fp, "* 121: FDISK_QNX43\n");
4135 (void) fprintf(fp, "* 130: SUNIXOS\n");
4136 (void) fprintf(fp, "* 131: FDISK_LINUXNAT\n");
4137 (void) fprintf(fp, "* 134: FDISK_NTFSVOL1\n");
4138 (void) fprintf(fp, "* 135: FDISK_NTFSVOL2\n");
4139 (void) fprintf(fp, "* 165: FDISK_BSD\n");
4140 (void) fprintf(fp, "* 167: FDISK_NEXTSTEP\n");
4141 (void) fprintf(fp, "* 183: FDISK_BSDIFS\n");
4142 (void) fprintf(fp, "* 184: FDISK_BSDISWAP\n");
4143 (void) fprintf(fp, "* 190: X86BOOT\n");
4144 (void) fprintf(fp, "* 191: SUNIXOS2\n");
4145 (void) fprintf(fp, "* 238: EFI_PMBR\n");
4146 (void) fprintf(fp, "* 239: EFI_FS\n");
4147 (void) fprintf(fp, "*\n");
4148 (void) fprintf(fp,
4149 "\n* Id Act Bhead Bsect Bcyl Ehead Esect Ecyl"
4150 " Rsect Numsect\n");
4152 for (i = 0; i < FD_NUMPART; i++) {
4153 (void) fprintf(fp,
4154 " %-5d %-4d %-6d %-6d %-7d %-6d %-6d %-7d %-10u"
4155 " %-10u\n",
4156 Table[i].systid,
4157 Table[i].bootid,
4158 Table[i].beghead,
4159 Table[i].begsect & 0x3f,
4160 ((Table[i].begcyl & 0xff) | ((Table[i].begsect &
4161 0xc0) << 2)),
4162 Table[i].endhead,
4163 Table[i].endsect & 0x3f,
4164 ((Table[i].endcyl & 0xff) | ((Table[i].endsect &
4165 0xc0) << 2)),
4166 LE_32(Table[i].relsect),
4167 LE_32(Table[i].numsect));
4169 #ifdef i386
4170 if (fdisk_ext_part_exists(epp)) {
4171 struct ipart ext_tab;
4172 logical_drive_t *temp;
4173 uint32_t rsect, numsect, tempsect = 0;
4174 for (temp = fdisk_get_ld_head(epp); temp != NULL;
4175 temp = temp->next) {
4176 ext_tab = temp->parts[0];
4177 rsect = tempsect + LE_32(ext_tab.relsect) +
4178 fdisk_get_ext_beg_sec(epp);
4179 numsect = LE_32(ext_tab.numsect);
4180 tempsect = LE_32(temp->parts[1].relsect);
4181 (void) fprintf(fp,
4182 " %-5d %-4d %-6d %-6d %-7d %-6d %-6d "
4183 "%-7d %-8u %-8u\n",
4184 ext_tab.systid,
4185 ext_tab.bootid,
4186 ext_tab.beghead,
4187 ext_tab.begsect & 0x3f,
4188 ((ext_tab.begcyl & 0xff) |
4189 ((ext_tab.begsect & 0xc0) << 2)),
4190 ext_tab.endhead,
4191 ext_tab.endsect & 0x3f,
4192 ((ext_tab.endcyl & 0xff) |
4193 ((ext_tab.endsect & 0xc0) << 2)),
4194 rsect,
4195 numsect);
4198 #endif
4200 if (fp != stdout)
4201 (void) fclose(fp);
4205 * fix_slice
4206 * Read the VTOC table on the Solaris partition and check that no
4207 * slices exist that extend past the end of the Solaris partition.
4208 * If no Solaris partition exists, nothing is done.
4210 static void
4211 fix_slice(void)
4213 int i;
4214 uint32_t numsect;
4216 if (io_image) {
4217 return;
4220 for (i = 0; i < FD_NUMPART; i++) {
4221 if (Table[i].systid == SUNIXOS || Table[i].systid == SUNIXOS2) {
4223 * Only the size matters (not starting point), since
4224 * VTOC entries are relative to the start of
4225 * the partition.
4227 numsect = LE_32(Table[i].numsect);
4228 break;
4232 if (i >= FD_NUMPART) {
4233 if (!io_nifdisk) {
4234 (void) fprintf(stderr,
4235 "fdisk: No Solaris partition found - VTOC not"
4236 " checked.\n");
4238 return;
4241 if (readvtoc() != VTOC_OK) {
4242 exit(1); /* Failed to read the VTOC */
4244 for (i = 0; i < V_NUMPAR; i++) {
4245 /* Special case for slice two (entire disk) */
4246 if (i == 2) {
4247 if (disk_vtoc.v_part[i].p_start != 0) {
4248 (void) fprintf(stderr,
4249 "slice %d starts at %llu, is not at"
4250 " start of partition",
4251 i, disk_vtoc.v_part[i].p_start);
4252 if (!io_nifdisk) {
4253 (void) printf(" adjust ?:");
4254 if (yesno())
4255 disk_vtoc.v_part[i].p_start = 0;
4256 } else {
4257 disk_vtoc.v_part[i].p_start = 0;
4258 (void) fprintf(stderr, " adjusted!\n");
4262 if (disk_vtoc.v_part[i].p_size != numsect) {
4263 (void) fprintf(stderr,
4264 "slice %d size %llu does not cover"
4265 " complete partition",
4266 i, disk_vtoc.v_part[i].p_size);
4267 if (!io_nifdisk) {
4268 (void) printf(" adjust ?:");
4269 if (yesno())
4270 disk_vtoc.v_part[i].p_size =
4271 numsect;
4272 } else {
4273 disk_vtoc.v_part[i].p_size = numsect;
4274 (void) fprintf(stderr, " adjusted!\n");
4277 if (disk_vtoc.v_part[i].p_tag != V_BACKUP) {
4278 (void) fprintf(stderr,
4279 "slice %d tag was %d should be %d",
4280 i, disk_vtoc.v_part[i].p_tag,
4281 V_BACKUP);
4282 if (!io_nifdisk) {
4283 (void) printf(" fix ?:");
4284 if (yesno())
4285 disk_vtoc.v_part[i].p_tag =
4286 V_BACKUP;
4287 } else {
4288 disk_vtoc.v_part[i].p_tag = V_BACKUP;
4289 (void) fprintf(stderr, " fixed!\n");
4292 continue;
4294 if (io_ADJT) {
4295 if (disk_vtoc.v_part[i].p_start > numsect ||
4296 disk_vtoc.v_part[i].p_start +
4297 disk_vtoc.v_part[i].p_size > numsect) {
4298 (void) fprintf(stderr,
4299 "slice %d (start %llu, end %llu)"
4300 " is larger than the partition",
4301 i, disk_vtoc.v_part[i].p_start,
4302 disk_vtoc.v_part[i].p_start +
4303 disk_vtoc.v_part[i].p_size);
4304 if (!io_nifdisk) {
4305 (void) printf(" remove ?:");
4306 if (yesno()) {
4307 disk_vtoc.v_part[i].p_size = 0;
4308 disk_vtoc.v_part[i].p_start = 0;
4309 disk_vtoc.v_part[i].p_tag = 0;
4310 disk_vtoc.v_part[i].p_flag = 0;
4312 } else {
4313 disk_vtoc.v_part[i].p_size = 0;
4314 disk_vtoc.v_part[i].p_start = 0;
4315 disk_vtoc.v_part[i].p_tag = 0;
4316 disk_vtoc.v_part[i].p_flag = 0;
4317 (void) fprintf(stderr,
4318 " removed!\n");
4321 continue;
4323 if (disk_vtoc.v_part[i].p_start > numsect) {
4324 (void) fprintf(stderr,
4325 "slice %d (start %llu) is larger than the "
4326 "partition", i, disk_vtoc.v_part[i].p_start);
4327 if (!io_nifdisk) {
4328 (void) printf(" remove ?:");
4329 if (yesno()) {
4330 disk_vtoc.v_part[i].p_size = 0;
4331 disk_vtoc.v_part[i].p_start = 0;
4332 disk_vtoc.v_part[i].p_tag = 0;
4333 disk_vtoc.v_part[i].p_flag = 0;
4335 } else {
4336 disk_vtoc.v_part[i].p_size = 0;
4337 disk_vtoc.v_part[i].p_start = 0;
4338 disk_vtoc.v_part[i].p_tag = 0;
4339 disk_vtoc.v_part[i].p_flag = 0;
4340 (void) fprintf(stderr,
4341 " removed!\n");
4343 } else if (disk_vtoc.v_part[i].p_start
4344 + disk_vtoc.v_part[i].p_size > numsect) {
4345 (void) fprintf(stderr,
4346 "slice %d (end %llu) is larger"
4347 " than the partition",
4349 disk_vtoc.v_part[i].p_start +
4350 disk_vtoc.v_part[i].p_size);
4351 if (!io_nifdisk) {
4352 (void) printf(" adjust ?:");
4353 if (yesno()) {
4354 disk_vtoc.v_part[i].p_size = numsect;
4356 } else {
4357 disk_vtoc.v_part[i].p_size = numsect;
4358 (void) fprintf(stderr, " adjusted!\n");
4362 #if 1 /* bh for now */
4363 /* Make the VTOC look sane - ha ha */
4364 disk_vtoc.v_version = V_VERSION;
4365 disk_vtoc.v_sanity = VTOC_SANE;
4366 disk_vtoc.v_nparts = V_NUMPAR;
4367 if (disk_vtoc.v_sectorsz == 0)
4368 disk_vtoc.v_sectorsz = NBPSCTR;
4369 #endif
4371 /* Write the VTOC back to the disk */
4372 if (!io_readonly)
4373 (void) writevtoc();
4377 * yesno
4378 * Get yes or no answer. Return 1 for yes and 0 for no.
4381 static int
4382 yesno(void)
4384 char s[80];
4386 for (;;) {
4387 (void) fgets(s, sizeof (s), stdin);
4388 rm_blanks(s);
4389 if (((s[1] != '\0') && (s[1] != '\n')) ||
4390 ((s[0] != 'y') && (s[0] != 'n'))) {
4391 (void) printf(E_LINE);
4392 (void) printf("Please answer with \"y\" or \"n\": ");
4393 continue;
4395 if (s[0] == 'y')
4396 return (1);
4397 else
4398 return (0);
4403 * readvtoc
4404 * Read the VTOC from the Solaris partition of the device.
4406 static int
4407 readvtoc(void)
4409 int i;
4410 int retval = VTOC_OK;
4412 if ((i = read_extvtoc(Dev, &disk_vtoc)) < VTOC_OK) {
4413 if (i == VT_EINVAL) {
4414 (void) fprintf(stderr, "fdisk: Invalid VTOC.\n");
4415 vt_inval++;
4416 retval = VTOC_INVAL;
4417 } else if (i == VT_ENOTSUP) {
4418 (void) fprintf(stderr, "fdisk: partition may have EFI "
4419 "GPT\n");
4420 retval = VTOC_NOTSUP;
4421 } else {
4422 (void) fprintf(stderr, "fdisk: Cannot read VTOC.\n");
4423 retval = VTOC_RWERR;
4426 return (retval);
4430 * writevtoc
4431 * Write the VTOC to the Solaris partition on the device.
4433 static int
4434 writevtoc(void)
4436 int i;
4437 int retval = 0;
4439 if ((i = write_extvtoc(Dev, &disk_vtoc)) != 0) {
4440 if (i == VT_EINVAL) {
4441 (void) fprintf(stderr,
4442 "fdisk: Invalid entry exists in VTOC.\n");
4443 retval = VTOC_INVAL;
4444 } else if (i == VT_ENOTSUP) {
4445 (void) fprintf(stderr, "fdisk: partition may have EFI "
4446 "GPT\n");
4447 retval = VTOC_NOTSUP;
4448 } else {
4449 (void) fprintf(stderr, "fdisk: Cannot write VTOC.\n");
4450 retval = VTOC_RWERR;
4453 return (retval);
4457 * efi_ioctl
4458 * issues DKIOCSETEFI IOCTL
4459 * (duplicate of private efi_ioctl() in rdwr_efi.c
4461 static int
4462 efi_ioctl(int fd, int cmd, dk_efi_t *dk_ioc)
4464 void *data = dk_ioc->dki_data;
4465 int error;
4467 dk_ioc->dki_data_64 = (uintptr_t)data;
4468 error = ioctl(fd, cmd, (void *)dk_ioc);
4470 return (error);
4474 * clear_efi
4475 * Clear EFI labels from the EFI_PMBR partition on the device
4476 * This function is modeled on the libefi(3LIB) call efi_write()
4478 static int
4479 clear_efi(void)
4481 struct dk_gpt *efi_vtoc;
4482 dk_efi_t dk_ioc;
4485 * see if we can read the EFI label
4487 if (efi_alloc_and_read(Dev, &efi_vtoc) < 0) {
4488 return (VT_ERROR);
4492 * set up the dk_ioc structure for writing
4494 dk_ioc.dki_lba = 1;
4495 dk_ioc.dki_length = EFI_MIN_ARRAY_SIZE + efi_vtoc->efi_lbasize;
4497 if ((dk_ioc.dki_data = calloc(dk_ioc.dki_length, 1)) == NULL) {
4498 return (VT_ERROR);
4502 * clear the primary label
4504 if (io_debug) {
4505 (void) fprintf(stderr,
4506 "\tClearing primary EFI label at block %lld\n",
4507 dk_ioc.dki_lba);
4510 if (efi_ioctl(Dev, DKIOCSETEFI, &dk_ioc) == -1) {
4511 free(dk_ioc.dki_data);
4512 switch (errno) {
4513 case EIO:
4514 return (VT_EIO);
4515 case EINVAL:
4516 return (VT_EINVAL);
4517 default:
4518 return (VT_ERROR);
4523 * clear the backup partition table
4525 dk_ioc.dki_lba = efi_vtoc->efi_last_u_lba + 1;
4526 dk_ioc.dki_length -= efi_vtoc->efi_lbasize;
4527 dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data +
4528 efi_vtoc->efi_lbasize);
4529 if (io_debug) {
4530 (void) fprintf(stderr,
4531 "\tClearing backup partition table at block %lld\n",
4532 dk_ioc.dki_lba);
4535 if (efi_ioctl(Dev, DKIOCSETEFI, &dk_ioc) == -1) {
4536 (void) fprintf(stderr, "\tUnable to clear backup EFI label at "
4537 "block %llu; errno %d\n", efi_vtoc->efi_last_u_lba + 1,
4538 errno);
4542 * clear the backup label
4544 dk_ioc.dki_lba = efi_vtoc->efi_last_lba;
4545 dk_ioc.dki_length = efi_vtoc->efi_lbasize;
4546 dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data -
4547 efi_vtoc->efi_lbasize);
4548 if (io_debug) {
4549 (void) fprintf(stderr, "\tClearing backup label at block "
4550 "%lld\n", dk_ioc.dki_lba);
4553 if (efi_ioctl(Dev, DKIOCSETEFI, &dk_ioc) == -1) {
4554 (void) fprintf(stderr,
4555 "\tUnable to clear backup EFI label at "
4556 "block %llu; errno %d\n",
4557 efi_vtoc->efi_last_lba,
4558 errno);
4561 free(dk_ioc.dki_data);
4562 efi_free(efi_vtoc);
4564 return (0);
4568 * clear_vtoc
4569 * Clear the VTOC from the current or previous Solaris partition on the
4570 * device.
4572 static void
4573 clear_vtoc(int table, int part)
4575 struct ipart *clr_table;
4576 char *disk_label;
4577 uint32_t pcyl, ncyl, count;
4578 diskaddr_t backup_block, solaris_offset;
4579 ssize_t bytes;
4580 off_t seek_byte;
4582 #ifdef DEBUG
4583 char *read_label;
4584 #endif /* DEBUG */
4586 if (table == OLD) {
4587 clr_table = &Old_Table[part];
4588 } else {
4589 clr_table = &Table[part];
4592 disk_label = (char *)calloc(sectsiz, 1);
4593 if (disk_label == NULL) {
4594 return;
4597 seek_byte = (off_t)(LE_32(clr_table->relsect) + VTOC_OFFSET) * sectsiz;
4599 if (io_debug) {
4600 (void) fprintf(stderr,
4601 "\tClearing primary VTOC at byte %llu (block %llu)\n",
4602 (uint64_t)seek_byte,
4603 (uint64_t)(LE_32(clr_table->relsect) + VTOC_OFFSET));
4606 if (lseek(Dev, seek_byte, SEEK_SET) == -1) {
4607 (void) fprintf(stderr,
4608 "\tError seeking to primary label at byte %llu\n",
4609 (uint64_t)seek_byte);
4610 free(disk_label);
4611 return;
4614 bytes = write(Dev, disk_label, sectsiz);
4616 if (bytes != sectsiz) {
4617 (void) fprintf(stderr,
4618 "\tWarning: only %d bytes written to clear primary"
4619 " VTOC!\n", bytes);
4622 #ifdef DEBUG
4623 if (lseek(Dev, seek_byte, SEEK_SET) == -1) {
4624 (void) fprintf(stderr,
4625 "DEBUG: Error seeking to primary label at byte %llu\n",
4626 (uint64_t)seek_byte);
4627 free(disk_label);
4628 return;
4629 } else {
4630 (void) fprintf(stderr,
4631 "DEBUG: Successful lseek() to byte %llu\n",
4632 (uint64_t)seek_byte);
4635 read_label = (char *)calloc(sectsiz, 1);
4636 if (read_label == NULL) {
4637 free(disk_label);
4638 return;
4641 bytes = read(Dev, read_label, sectsiz);
4643 if (bytes != sectsiz) {
4644 (void) fprintf(stderr,
4645 "DEBUG: Warning: only %d bytes read of label\n",
4646 bytes);
4649 if (memcmp(disk_label, read_label, sectsiz) != 0) {
4650 (void) fprintf(stderr,
4651 "DEBUG: Warning: disk_label and read_label differ!!!\n");
4652 } else {
4653 (void) fprintf(stderr, "DEBUG Good compare of disk_label and "
4654 "read_label\n");
4656 #endif /* DEBUG */
4658 /* Clear backup label */
4659 pcyl = LE_32(clr_table->numsect) / (heads * sectors);
4660 solaris_offset = LE_32(clr_table->relsect);
4661 ncyl = pcyl - acyl;
4663 backup_block = ((ncyl + acyl - 1) *
4664 (heads * sectors)) + ((heads - 1) * sectors) + 1;
4666 for (count = 1; count < 6; count++) {
4667 seek_byte = (off_t)(solaris_offset + backup_block) * sectsiz;
4669 if (lseek(Dev, seek_byte, SEEK_SET) == -1) {
4670 (void) fprintf(stderr,
4671 "\tError seeking to backup label at byte %llu on "
4672 "%s.\n", (uint64_t)seek_byte, Dfltdev);
4673 free(disk_label);
4674 #ifdef DEBUG
4675 free(read_label);
4676 #endif /* DEBUG */
4677 return;
4680 if (io_debug) {
4681 (void) fprintf(stderr, "\tClearing backup VTOC at"
4682 " byte %llu (block %llu)\n",
4683 (uint64_t)seek_byte,
4684 (uint64_t)(solaris_offset + backup_block));
4687 bytes = write(Dev, disk_label, sectsiz);
4689 if (bytes != sectsiz) {
4690 (void) fprintf(stderr,
4691 "\t\tWarning: only %d bytes written to "
4692 "clear backup VTOC at block %llu!\n", bytes,
4693 (uint64_t)(solaris_offset + backup_block));
4696 #ifdef DEBUG
4697 if (lseek(Dev, seek_byte, SEEK_SET) == -1) {
4698 (void) fprintf(stderr,
4699 "DEBUG: Error seeking to backup label at byte %llu\n",
4700 (uint64_t)seek_byte);
4701 free(disk_label);
4702 free(read_label);
4703 return;
4704 } else {
4705 (void) fprintf(stderr,
4706 "DEBUG: Successful lseek() to byte %llu\n",
4707 (uint64_t)seek_byte);
4710 bytes = read(Dev, read_label, sectsiz);
4712 if (bytes != sectsiz) {
4713 (void) fprintf(stderr,
4714 "DEBUG: Warning: only %d bytes read of backup label\n",
4715 bytes);
4718 if (memcmp(disk_label, read_label, sectsiz) != 0) {
4719 (void) fprintf(stderr,
4720 "DEBUG: Warning: disk_label and read_label differ!!!\n");
4721 } else {
4722 (void) fprintf(stderr,
4723 "DEBUG: Good compare of disk_label and backup "
4724 "read_label\n");
4727 #endif /* DEBUG */
4729 backup_block += 2;
4732 #ifdef DEBUG
4733 free(read_label);
4734 #endif /* DEBUG */
4735 free(disk_label);
4738 #define FDISK_STANDARD_LECTURE \
4739 "Fdisk is normally used with the device that " \
4740 "represents the entire fixed disk.\n" \
4741 "(For example, /dev/rdsk/c0d0p0 on x86 or " \
4742 "/dev/rdsk/c0t5d0s2 on sparc).\n"
4744 #define FDISK_LECTURE_NOT_SECTOR_ZERO \
4745 "The device does not appear to include absolute\n" \
4746 "sector 0 of the PHYSICAL disk " \
4747 "(the normal location for an fdisk table).\n"
4749 #define FDISK_LECTURE_NOT_FULL \
4750 "The device does not appear to encompass the entire PHYSICAL disk.\n"
4752 #define FDISK_LECTURE_NO_VTOC \
4753 "Unable to find a volume table of contents.\n" \
4754 "Cannot verify the device encompasses the full PHYSICAL disk.\n"
4756 #define FDISK_LECTURE_NO_GEOM \
4757 "Unable to get geometry from device.\n" \
4758 "Cannot verify the device encompasses the full PHYSICAL disk.\n"
4760 #define FDISK_SHALL_I_CONTINUE \
4761 "Are you sure you want to continue? (y/n) "
4764 * lecture_and_query
4765 * Called when a sanity check fails. This routine gives a warning
4766 * specific to the check that fails, followed by a generic lecture
4767 * about the "right" device to supply as input. Then, if appropriate,
4768 * it will prompt the user on whether or not they want to continue.
4769 * Inappropriate times for prompting are when the user has selected
4770 * non-interactive mode or read-only mode.
4772 static int
4773 lecture_and_query(char *warning, char *devname)
4775 if (io_nifdisk)
4776 return (0);
4778 (void) fprintf(stderr, "WARNING: Device %s: \n", devname);
4779 (void) fprintf(stderr, "%s", warning);
4780 (void) fprintf(stderr, FDISK_STANDARD_LECTURE);
4781 (void) fprintf(stderr, FDISK_SHALL_I_CONTINUE);
4783 return (yesno());
4786 static void
4787 sanity_check_provided_device(char *devname, int fd)
4789 struct extvtoc v;
4790 struct dk_geom d;
4791 struct part_info pi;
4792 struct extpart_info extpi;
4793 diskaddr_t totsize;
4794 int idx = -1;
4797 * First try the PARTINFO ioctl. If it works, we will be able
4798 * to tell if they've specified the full disk partition by checking
4799 * to see if they've specified a partition that starts at sector 0.
4801 if (ioctl(fd, DKIOCEXTPARTINFO, &extpi) != -1) {
4802 if (extpi.p_start != 0) {
4803 if (!lecture_and_query(FDISK_LECTURE_NOT_SECTOR_ZERO,
4804 devname)) {
4805 (void) close(fd);
4806 exit(1);
4809 } else if (ioctl(fd, DKIOCPARTINFO, &pi) != -1) {
4810 if (pi.p_start != 0) {
4811 if (!lecture_and_query(FDISK_LECTURE_NOT_SECTOR_ZERO,
4812 devname)) {
4813 (void) close(fd);
4814 exit(1);
4817 } else {
4818 if ((idx = read_extvtoc(fd, &v)) < 0) {
4819 if (!lecture_and_query(FDISK_LECTURE_NO_VTOC,
4820 devname)) {
4821 (void) close(fd);
4822 exit(1);
4824 return;
4826 if (ioctl(fd, DKIOCGGEOM, &d) == -1) {
4827 perror(devname);
4828 if (!lecture_and_query(FDISK_LECTURE_NO_GEOM,
4829 devname)) {
4830 (void) close(fd);
4831 exit(1);
4833 return;
4835 totsize = (diskaddr_t)d.dkg_ncyl * d.dkg_nhead * d.dkg_nsect;
4836 if (v.v_part[idx].p_size != totsize) {
4837 if (!lecture_and_query(FDISK_LECTURE_NOT_FULL,
4838 devname)) {
4839 (void) close(fd);
4840 exit(1);
4848 * get_node
4849 * Called from main to construct the name of the device node to open.
4850 * Initially tries to stat the node exactly as provided, if that fails
4851 * we prepend the default path (/dev/rdsk/).
4853 static char *
4854 get_node(char *devname)
4856 char *node;
4857 struct stat statbuf;
4858 size_t space;
4860 /* Don't do anything if we are skipping device checks */
4861 if (io_image)
4862 return (devname);
4864 node = devname;
4866 /* Try the node as provided first */
4867 if (stat(node, (struct stat *)&statbuf) == -1) {
4869 * Copy the passed in string to a new buffer, prepend the
4870 * default path and try again.
4872 space = strlen(DEFAULT_PATH) + strlen(devname) + 1;
4874 if ((node = malloc(space)) == NULL) {
4875 (void) fprintf(stderr, "fdisk: Unable to obtain memory "
4876 "for device node.\n");
4877 exit(1);
4880 /* Copy over the default path and the provided node */
4881 (void) strncpy(node, DEFAULT_PATH, strlen(DEFAULT_PATH));
4882 space -= strlen(DEFAULT_PATH);
4883 (void) strlcpy(node + strlen(DEFAULT_PATH), devname, space);
4885 /* Try to stat it again */
4886 if (stat(node, (struct stat *)&statbuf) == -1) {
4887 /* Failed all options, give up */
4888 (void) fprintf(stderr,
4889 "fdisk: Cannot stat device %s.\n",
4890 devname);
4891 exit(1);
4895 /* Make sure the device specified is the raw device */
4896 if ((statbuf.st_mode & S_IFMT) != S_IFCHR) {
4897 (void) fprintf(stderr,
4898 "fdisk: %s must be a raw device.\n", node);
4899 exit(1);
4902 return (node);
4905 #ifdef i386
4906 static void
4907 preach_and_continue()
4909 (void) fprintf(stderr, "There are mounted logical drives. Committing "
4910 "changes now can lead to inconsistancy in internal system state "
4911 "which can eventually cause data loss or corruption. Unmount all "
4912 "logical drives and try committing the changes again.\n");
4913 ext_read_input(s);
4917 * Convert a given partition ID to an descriptive string.
4918 * Just an index into the partition types table.
4920 void
4921 id_to_name(uchar_t sysid, char *buffer)
4923 (void) strcpy(buffer, fdisk_part_types[sysid]);
4927 * Procedure to check the validity of the extended partition menu option
4928 * entered by the user
4930 static int
4931 ext_invalid_option(char ch)
4933 char *p;
4935 p = strchr(ext_part_menu_opts, tolower(ch));
4937 if (p == NULL) {
4938 return (1);
4940 return (0);
4944 * Read 16 bytes of the input (assuming that no valid user input spans more
4945 * than that). Flush the input stream, so that the next read does not reap
4946 * stale data from the previous input that was not processed.
4947 * Note that fgets also reads the trailing '\n'
4949 static void
4950 ext_read_input(char *buf)
4952 (void) fgets(buf, 16, stdin);
4953 (void) fflush(stdin);
4957 * Procedure to read and validate the user option at the extended partition menu
4959 static int
4960 ext_read_options(char *buf)
4962 ext_read_input(buf);
4963 if ((strlen(buf) != 2) || (ext_invalid_option(buf[0]))) {
4964 (void) printf("\nUnknown Command\n");
4965 return (-1);
4967 return (0);
4971 * Procedure to print the list of known partition types and their IDs
4973 static void
4974 ext_print_part_types()
4976 int i, rowmax, rowcount = 1;
4977 struct winsize ws;
4978 char buf[80];
4980 /* Get the current window dimensions */
4981 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0) {
4982 perror("ioctl");
4983 rowmax = 20;
4984 } else {
4986 * Accommodate the initial headings by reducing the number of
4987 * partition IDs being printed.
4989 rowmax = ws.ws_row - 5;
4992 if (rowmax < 3) {
4993 (void) fprintf(stderr, "Window size too small."
4994 " Try resizing the window\n");
4995 return;
4998 (void) printf("List of known partition types : \n");
4999 (void) printf("PartID Partition Type\n");
5000 (void) printf("====== ==============\n");
5001 for (i = 0; i <= FDISK_MAX_VALID_PART_ID; i++) {
5002 (void) printf("%-3d %s\n", i, fdisk_part_types[i]);
5003 rowcount++;
5004 if (rowcount == rowmax) {
5006 * After the initial screen, use all the rows for
5007 * printing the partition IDs, but one.
5009 rowmax = ws.ws_row - 1;
5010 (void) fprintf(stderr, "\nPress enter to see next "
5011 "page or 'q' to quit : ");
5012 ext_read_input(buf);
5013 if ((strlen(buf) == 2) && (tolower(buf[0]) == 'q')) {
5014 return;
5016 rowcount = 1;
5021 static void
5022 ext_read_valid_part_num(int *pno)
5024 char buf[80];
5025 int len, i;
5027 for (;;) {
5028 (void) printf("Enter the partition number : ");
5029 ext_read_input(buf);
5031 len = strlen(buf);
5033 /* Check length of the input */
5034 if ((len < 2) || (len > (FDISK_MAX_VALID_PART_NUM_DIGITS+1))) {
5035 goto print_error_and_continue;
5038 /* Check if there is a non-digit in the input */
5039 for (i = 0; i < len-1; i++) {
5040 if (!isdigit(buf[i])) {
5041 goto print_error_and_continue;
5045 *pno = atoi(buf);
5047 if ((*pno <= FD_NUMPART) ||
5048 *pno > (fdisk_get_logical_drive_count(epp) + FD_NUMPART)) {
5049 goto print_error_and_continue;
5052 break;
5053 print_error_and_continue:
5054 (void) printf("Invalid partition number\n");
5055 continue;
5059 static void
5060 ext_read_valid_part_id(uchar_t *partid)
5062 char buf[80];
5063 int len, i, id;
5065 for (;;) {
5066 (void) printf("Enter the ID ( Type I for list of "
5067 "partition IDs ) : ");
5068 ext_read_input(buf);
5069 len = strlen(buf);
5071 if ((len < 2) || (len > (FDISK_MAX_VALID_PART_ID_DIGITS + 1))) {
5072 (void) printf("Invalid partition ID\n");
5073 continue;
5076 if ((len == 2) && (toupper(buf[0]) == 'I')) {
5077 ext_print_part_types();
5078 continue;
5081 /* Check if there is a non-digit in the input */
5082 for (i = 0; i < len-1; i++) {
5083 if (!isdigit(buf[i])) {
5084 (void) printf("Invalid partition ID\n");
5085 break;
5089 if (i < len - 1) {
5090 continue;
5093 /* Check if the (now) valid number is greater than the limit */
5094 if ((id = atoi(buf)) > FDISK_MAX_VALID_PART_ID) {
5095 (void) printf("Invalid partition ID\n");
5096 continue;
5099 *partid = (uchar_t)id;
5101 /* Disallow multiple extended partitions */
5102 if (fdisk_is_dos_extended(*partid)) {
5103 (void) printf("Multiple extended partitions not "
5104 "allowed\n");
5105 continue;
5108 /* Disallow EFI partitions within extended partition */
5109 if (*partid == EFI_PMBR) {
5110 (void) printf("EFI partitions within an extended "
5111 "partition is not allowed\n");
5112 continue;
5115 return; /* Valid partition ID is in partid */
5119 static void
5120 delete_logical_drive()
5122 int pno;
5124 if (!fdisk_get_logical_drive_count(epp)) {
5125 (void) printf("\nNo logical drives defined.\n");
5126 return;
5129 (void) printf("\n");
5130 ext_read_valid_part_num(&pno);
5131 fdisk_delete_logical_drive(epp, pno);
5132 (void) printf("Partition %d deleted\n", pno);
5135 static int
5136 ext_read_valid_partition_start(uint32_t *begsec)
5138 char buf[80];
5139 int ret, len, i;
5140 uint32_t begcyl;
5141 uint32_t first_free_cyl;
5142 uint32_t first_free_sec;
5144 ret = fdisk_ext_find_first_free_sec(epp, &first_free_sec);
5145 if (ret != FDISK_SUCCESS) {
5146 return (ret);
5149 first_free_cyl = FDISK_SECT_TO_CYL(epp, first_free_sec);
5150 for (;;) {
5151 (void) printf("Enter the beginning cylinder (Default - %d) : ",
5152 first_free_cyl);
5153 ext_read_input(buf);
5154 len = strlen(buf);
5155 if (len == 1) { /* User accepted the default value */
5156 *begsec = first_free_sec;
5157 return (FDISK_SUCCESS);
5160 if (len > (FDISK_MAX_VALID_CYL_NUM_DIGITS + 1)) {
5161 (void) printf("Input too long\n");
5162 (void) printf("Invalid beginning cylinder number\n");
5163 continue;
5165 /* Check if there is a non-digit in the input */
5166 for (i = 0; i < len - 1; i++) {
5167 if (!isdigit(buf[i])) {
5168 (void) printf("Invalid beginning cylinder "
5169 "number\n");
5170 break;
5173 if (i < len - 1) {
5174 continue;
5177 begcyl = atoi(buf);
5178 ret = fdisk_ext_validate_part_start(epp, begcyl, begsec);
5179 switch (ret) {
5180 case FDISK_SUCCESS:
5182 * Success.
5183 * Valid beginning sector is in begsec
5185 break;
5187 case FDISK_EOVERLAP:
5188 (void) printf("Partition boundary overlaps "
5189 "with ");
5190 (void) printf("existing partitions\n");
5191 (void) printf("Invalid beginning cylinder "
5192 "number\n");
5193 continue;
5195 case FDISK_EOOBOUND:
5196 (void) printf("Cylinder boundary beyond the "
5197 "limits\n");
5198 (void) printf("Invalid beginning cylinder "
5199 "number\n");
5200 continue;
5202 return (FDISK_SUCCESS);
5207 * Algorithm :
5208 * 1. Check if the first character is a +
5209 * a) If yes, check if the last character is 'k', 'm' or 'g'
5210 * 2. If not, check if there are any non-digits
5211 * 3. Check for the length of the numeral string
5212 * 4. atoi the numeral string
5213 * 5. In case of data entered in KB, MB or GB, convert it to number of cylinders
5214 * a) Adjust size to be cylinder boundary aligned
5215 * 6. If size specifies is zero, flag error
5216 * 7. Check if the size is less than 1 cylinder
5217 * a) If yes, default the size FDISK_MIN_PART_SIZE
5218 * b) If no, Check if the size is within endcyl - begcyl
5220 static void
5221 ext_read_valid_partition_size(uint32_t begsec, uint32_t *endsec)
5223 char buf[80];
5224 uint32_t last_free_sec;
5225 uint32_t last_free_cyl;
5226 int i, len, ch, mbgb = 0, scale = FDISK_SECTS_PER_CYL(epp);
5227 uint64_t size = 0;
5228 int copy_len;
5229 char numbuf[FDISK_MAX_VALID_CYL_NUM_DIGITS + 1];
5230 int sectsize = fdisk_get_disk_geom(epp, PHYSGEOM, SSIZE);
5231 uint32_t remdr, spc, poss_end;
5233 if (sectsize == EINVAL) {
5234 (void) fprintf(stderr, "Unsupported geometry statistics.\n");
5235 exit(1);
5238 last_free_sec = fdisk_ext_find_last_free_sec(epp, begsec);
5239 last_free_cyl = FDISK_SECT_TO_CYL(epp, last_free_sec);
5241 for (;;) {
5242 (void) printf("Enter the size in cylinders (Default End "
5243 "Cylinder -");
5244 (void) printf(" %u)\n", last_free_cyl);
5245 (void) printf("Type +<size>K, +<size>M or +<size>G to enter "
5246 "size in");
5247 (void) printf("KB, MB or GB : ");
5248 ext_read_input(buf);
5249 len = strlen(buf);
5250 mbgb = 0;
5251 scale = FDISK_SECTS_PER_CYL(epp);
5253 if (len == 1) { /* User accepted the default value */
5254 *endsec = last_free_sec;
5255 return;
5258 copy_len = len - 1;
5260 if ((buf[0] == '+') && (isdigit(buf[1]))) {
5261 copy_len--;
5262 if ((ch = toupper(buf[len - 2])) == 'B') {
5263 ch = toupper(buf[len - 3]);
5264 copy_len--;
5267 if (!((ch == 'K') || (ch == 'M') || (ch == 'G'))) {
5268 (void) printf("Invalid partition size\n");
5269 continue;
5272 copy_len--;
5273 mbgb = 1;
5274 scale = ((ch == 'K') ? FDISK_KB :
5275 ((ch == 'M') ? FDISK_MB : FDISK_GB));
5278 if (copy_len > FDISK_MAX_VALID_CYL_NUM_DIGITS) {
5279 (void) printf("Input too long\n");
5280 (void) printf("Invalid partition size\n");
5281 continue;
5284 (void) strncpy(numbuf, &buf[mbgb], copy_len);
5285 numbuf[copy_len] = '\0';
5287 for (i = mbgb; i < copy_len + mbgb; i++) {
5288 if (!isdigit(buf[i])) {
5289 break;
5293 if (i < copy_len + mbgb) {
5294 (void) printf("Invalid partition size\n");
5295 continue;
5298 size = (atoll(numbuf) * (scale));
5300 if (size == 0) {
5301 (void) printf("Zero size is invalid\n");
5302 (void) printf("Invalid partition size\n");
5303 continue;
5306 if (mbgb) {
5307 size /= sectsize;
5310 if (size > (last_free_sec - begsec + 1)) {
5311 (void) printf("Cylinder boundary beyond the limits");
5312 (void) printf(" or overlaps with existing");
5313 (void) printf(" partitions\n");
5314 (void) printf("Invalid partition size\n");
5315 continue;
5319 * Adjust the ending sector such that there are no partial
5320 * cylinders allocated. But at the same time, make sure it
5321 * doesn't over shoot boundaries.
5323 spc = FDISK_SECTS_PER_CYL(epp);
5324 poss_end = begsec + size - 1;
5325 if ((remdr = (poss_end % spc)) != 0) {
5326 poss_end += spc - remdr - 1;
5328 *endsec = (poss_end > last_free_sec) ? last_free_sec :
5329 poss_end;
5331 return;
5336 * ALGORITHM:
5337 * 1. Get the starting and ending sectors/cylinder of the extended partition.
5338 * 2. Keep track of the first free sector/cylinder
5339 * 3. Allow the user to specify the beginning cylinder of the new partition
5340 * 4. Check for the validity of the entered data
5341 * a) If it is non-numeric
5342 * b) If it is beyond the extended partition limits
5343 * c) If it overlaps with the current logical drives
5344 * 5. Allow the user to specify the size in cylinders/ human readable form
5345 * 6. Check for the validity of the entered data
5346 * a) If it is non-numeric
5347 * b) If it is beyond the extended partition limits
5348 * c) If it overlaps with the current logical drives
5349 * d) If it is a number lesser than the starting cylinder
5350 * 7. Request partition ID for the new partition.
5351 * 8. Update the first free cylinder available
5352 * 9. Display Success message
5355 static void
5356 add_logical_drive()
5358 uint32_t begsec, endsec;
5359 uchar_t partid;
5360 char buf[80];
5361 int rval;
5363 if (fdisk_get_logical_drive_count(epp) >= MAX_EXT_PARTS) {
5364 (void) printf("\nNumber of logical drives exceeds limit of "
5365 "%d.\n", MAX_EXT_PARTS);
5366 (void) printf("Command did not succeed. Press enter to "
5367 "continue\n");
5368 ext_read_input(buf);
5369 return;
5372 (void) printf("\n");
5373 rval = ext_read_valid_partition_start(&begsec);
5374 switch (rval) {
5375 case FDISK_SUCCESS:
5376 break;
5378 case FDISK_EOOBOUND:
5379 (void) printf("\nNo space left in the extended "
5380 "partition\n");
5381 (void) printf("Press enter to continue\n");
5382 ext_read_input(buf);
5383 return;
5386 ext_read_valid_partition_size(begsec, &endsec);
5387 ext_read_valid_part_id(&partid);
5388 fdisk_add_logical_drive(epp, begsec, endsec, partid);
5390 (void) printf("New partition with ID %d added\n", partid);
5393 static void
5394 ext_change_logical_drive_id()
5396 int pno;
5397 uchar_t partid;
5399 if (!fdisk_get_logical_drive_count(epp)) {
5400 (void) printf("\nNo logical drives defined.\n");
5401 return;
5404 (void) printf("\n");
5405 ext_read_valid_part_num(&pno);
5406 ext_read_valid_part_id(&partid);
5407 fdisk_change_logical_drive_id(epp, pno, partid);
5409 (void) printf("Partition ID of partition %d changed to %d\n", pno,
5410 partid);
5413 #ifdef DEBUG
5414 static void
5415 ext_print_logdrive_layout_debug()
5417 int pno;
5418 char namebuff[255];
5419 logical_drive_t *head = fdisk_get_ld_head(epp);
5420 logical_drive_t *temp;
5422 if (!fdisk_get_logical_drive_count(epp)) {
5423 (void) printf("\nNo logical drives defined.\n");
5424 return;
5427 (void) printf("\n\n");
5428 puts("# start block end block abs start abs end OSType");
5429 for (temp = head, pno = 5; temp != NULL; temp = temp->next, pno++) {
5430 /* Print the logical drive details */
5431 id_to_name(temp->parts[0].systid, namebuff);
5432 (void) printf("%d: %.10u %.10u %.10u %.10u",
5433 pno,
5434 LE_32(temp->parts[0].relsect),
5435 LE_32(temp->parts[0].numsect),
5436 temp->abs_secnum,
5437 temp->abs_secnum + temp->numsect - 1 +
5438 MAX_LOGDRIVE_OFFSET);
5439 (void) printf(" %s\n", namebuff);
5441 * Print the second entry in the EBR which is information
5442 * about the location and the size of the next extended
5443 * partition.
5445 id_to_name(temp->parts[1].systid, namebuff);
5446 (void) printf("%d: %.10u %.10u %.10s %.10s",
5447 pno,
5448 LE_32(temp->parts[1].relsect),
5449 LE_32(temp->parts[1].numsect),
5450 " ", " ");
5451 (void) printf(" %s\n", namebuff);
5454 #endif
5456 static void
5457 ext_print_logical_drive_layout()
5459 int sysid;
5460 unsigned int startcyl, endcyl, length, percent, remainder;
5461 logical_drive_t *temp;
5462 uint32_t part_start;
5463 struct ipart *fpart;
5464 char namebuff[255];
5465 int numcyl = fdisk_get_disk_geom(epp, PHYSGEOM, NCYL);
5466 int pno;
5468 if (numcyl == EINVAL) {
5469 (void) fprintf(stderr, "Unsupported geometry statistics.\n");
5470 exit(1);
5473 if (!fdisk_get_logical_drive_count(epp)) {
5474 (void) printf("\nNo logical drives defined.\n");
5475 return;
5478 (void) printf("\n");
5479 (void) printf("Number of cylinders in disk : %u\n",
5480 numcyl);
5481 (void) printf("Beginning cylinder of extended partition : %u\n",
5482 fdisk_get_ext_beg_cyl(epp));
5483 (void) printf("Ending cylinder of extended partition : %u\n",
5484 fdisk_get_ext_end_cyl(epp));
5485 (void) printf("\n");
5486 (void) printf("Part# StartCyl EndCyl Length %% "
5487 "Part ID (Type)\n");
5488 (void) printf("===== ======== ======== ======= ==="
5489 " ==============\n");
5490 for (temp = fdisk_get_ld_head(epp), pno = 5; temp != NULL;
5491 temp = temp->next, pno++) {
5492 /* Print the logical drive details */
5493 fpart = &temp->parts[0];
5494 sysid = fpart->systid;
5496 * Check if partition id 0x82 is Solaris
5497 * or a Linux swap. Print the string
5498 * accordingly.
5500 if (sysid == SUNIXOS) {
5501 part_start = temp->abs_secnum +
5502 temp->logdrive_offset;
5503 if (fdisk_is_linux_swap(epp, part_start,
5504 NULL) == 0)
5505 (void) strcpy(namebuff, LINSWAPstr);
5506 else
5507 (void) strcpy(namebuff, SUstr);
5508 } else {
5509 id_to_name(sysid, namebuff);
5511 startcyl = temp->begcyl;
5512 endcyl = temp->endcyl;
5513 if (startcyl == endcyl) {
5514 length = 1;
5515 } else {
5516 length = endcyl - startcyl + 1;
5518 percent = length * 100 / numcyl;
5519 if ((remainder = (length * 100 % numcyl)) != 0) {
5520 if ((remainder * 100 / numcyl) > 50) {
5521 /* round up */
5522 percent++;
5524 /* Else leave the percent as is since it's already */
5525 /* rounded down */
5527 if (percent > 100) {
5528 percent = 100;
5530 (void) printf("%-5d %-8u %-8u %-7u %-3d "
5531 "%-3d (%-.28s)\n",
5532 pno, startcyl, endcyl, length, percent, sysid, namebuff);
5534 #ifdef DEBUG
5535 ext_print_logdrive_layout_debug();
5536 #endif
5537 (void) printf("\n");
5540 static void
5541 ext_print_help_menu()
5543 (void) printf("\n");
5544 (void) printf("a Add a logical drive\n");
5545 (void) printf("d Delete a logical drive\n");
5546 (void) printf("h Print this help menu\n");
5547 (void) printf("i Change the id of the logical drive\n");
5548 (void) printf("p Print the logical drive layout\n");
5549 (void) printf("r Return to the main fdisk menu\n");
5550 (void) printf(" (To commit or cancel the changes)\n");
5551 (void) printf("\n");
5554 static void
5555 ext_part_menu()
5557 char buf[80];
5558 uchar_t *bbsigp;
5559 static int bbsig_disp_flag = 1;
5561 int i;
5563 (void) printf(CLR_SCR);
5565 if (fdisk_corrupt_logical_drives(epp)) {
5566 (void) printf("One or more logical drives seem to be "
5567 "corrupt.\n");
5568 (void) printf("Displaying only sane logical drives.\n");
5571 if (bbsig_disp_flag && fdisk_invalid_bb_sig(epp, &bbsigp)) {
5572 (void) printf("The following logical drives have a wrong "
5573 "boot block signature :\n\n");
5574 for (i = 0; bbsigp[i]; i++) {
5575 (void) printf("%d ", bbsigp[i]);
5577 (void) printf("\n\n");
5578 (void) printf("They will be corrected when you choose to "
5579 "commit\n");
5580 bbsig_disp_flag = 0;
5583 (void) printf("Extended partition menu\n");
5585 for (;;) {
5586 (void) printf("\nEnter Command (Type h for help) : ");
5587 if ((ext_read_options(buf)) < 0) {
5588 (void) printf("\nCommand Options : \n");
5589 ext_print_help_menu();
5590 continue;
5592 switch (buf[0]) {
5593 case 'a':
5594 add_logical_drive();
5595 break;
5596 case 'd':
5597 delete_logical_drive();
5598 break;
5599 case 'h':
5600 ext_print_help_menu();
5601 break;
5602 case 'i':
5603 ext_change_logical_drive_id();
5604 break;
5605 case 'p':
5606 ext_print_logical_drive_layout();
5607 break;
5608 case 'r':
5609 (void) printf(CLR_SCR);
5610 return;
5611 default : /* NOTREACHED */
5612 break;
5616 #endif /* i386 */
5618 static int
5619 nopartdefined()
5621 int i;
5623 for (i = 0; i < FD_NUMPART; i++)
5624 if (Table[i].systid != UNUSED)
5625 return (0);
5626 return (1);