1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */
28 /* All Rights Reserved */
29
30 /* Copyright (c) 1987, 1988 Microsoft Corporation */
31 /* All Rights Reserved */
32
33 /*
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.
39 */
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>
55
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
63
64 #define CLR_SCR "[1;1H[0J"
65 #define CLR_LIN "[0K"
66 #define HOME "[1;1H[0K[2;1H[0K[3;1H[0K[4;1H[0K[5;1H[0K" \
67 "[6;1H[0K[7;1H[0K[8;1H[0K[9;1H[0K[10;1H[0K[1;1H"
68 #define Q_LINE "[22;1H[0K[21;1H[0K[20;1H[0K"
69
70 #ifdef i386
71 #define W_LINE "[11;1H[0K"
72 #else
73 #define W_LINE "[12;1H[0K[11;1H[0K"
74 #endif
75
76 #define E_LINE "[24;1H[0K[23;1H[0K"
77
78 #ifdef i386
79 #define M_LINE "[12;1H[0K[13;1H[0K[14;1H[0K[15;1H[0K" \
80 "[16;1H[0K[17;1H[0K[18;1H[0K[19;1H[0K[12;1H"
81 #else
82 #define M_LINE "[13;1H[0K[14;1H[0K[15;1H[0K[16;1H[0K[17;1H" \
83 "[0K[18;1H[0K[19;1H[0K[13;1H"
84 #endif
85
86 #define T_LINE "[1;1H[0K"
87
88 #define DEFAULT_PATH "/dev/rdsk/"
89
90 /* XXX - should be in fdisk.h, used by sd as well */
91
92 /*
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)
99 */
100 #define MAX_SECT (63)
101 #define MAX_CYL (1022)
102 #define MAX_HEAD (254)
103
104 #define DK_MAX_2TB UINT32_MAX /* Max # of sectors in 2TB */
105
106 /* for clear_vtoc() */
107 #define OLD 0
108 #define NEW 1
109
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 */
115
116 /*
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.
122 */
123
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
132
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
140
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
146
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
150
151 /* Maximum number of digits for a valid partition size */
152 #define FDISK_MAX_VALID_CYL_NUM_DIGITS 10
153
154 /* Minimum partition size in cylinders */
155 #define FDISK_MIN_PART_SIZE 1
156 #endif
157
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";
165
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).";
226
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[] = " ";
267
268 /* All the user options and flags */
269 static char *Dfltdev; /* name of fixed disk drive */
270
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) */
280
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) */
285
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) */
292
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) */
299
300 static char *io_mboot = 0; /* master boot record (-b boot_file) */
301
302 static struct mboot BootCod; /* buffer for master boot record */
303
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) */
308
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 */
316
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 */
320
321 /* Disk geometry information */
322 static struct dk_minfo minfo;
323 static struct dk_geom disk_geom;
324
325 static int Dev; /* fd for open device */
326
327 static diskaddr_t dev_capacity; /* number of blocks on device */
328 static diskaddr_t chs_capacity; /* Numcyl_usable * heads * sectors */
329
330 static int Numcyl_usable; /* Number of usable cylinders */
331 /* used to limit fdisk to 2TB */
332
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 */
338
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 */
343
344 static int sectsiz; /* sector size */
345
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 */
350
351 #define CBUFLEN 80
352 static char s[CBUFLEN];
353
354 #ifdef i386
355 /*
356 * Complete list of all the 255 partition types. Some are unknown types
357 * and some entries are known to be unused.
358 *
359 * Courtesy of http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
360 */
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 */
618 };
619
620 /* Allowed extended partition menu options */
621 static char ext_part_menu_opts[] = "adhipr";
622
623 /*
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.
627 */
628 static ext_part_t *epp;
629 #endif
630
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);
690
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 */
712
713 /*
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.
718 */
719 static void
update_disk_and_exit(boolean_t table_changed)720 update_disk_and_exit(boolean_t table_changed)
721 {
722 #ifdef i386
723 int rval;
724 #endif
725 if (table_changed) {
726 /*
727 * Copy the new table back to the sector buffer
728 * and write it to disk
729 */
730 copy_Table_to_Bootblk();
731 dev_mboot_write(0, Bootsect, sectsiz);
732 }
733
734 /* If the VTOC table is wrong fix it (truncation only) */
735 if (io_adjt)
736 fix_slice();
737
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);
752 }
753 }
754 libfdisk_fini(&epp);
755 #endif
756 exit(0);
757 }
758
759 /*
760 * main
761 * Process command-line options.
762 */
763 int
main(int argc,char * argv[])764 main(int argc, char *argv[])
765 {
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
776
777 setbuf(stderr, 0); /* so all output gets out on exit */
778 setbuf(stdout, 0);
779
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) {
784
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':
851 /*
852 * If '-' is the -W argument, then write
853 * to standard output, otherwise write
854 * to the specified file.
855 */
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;
881 }
882 break;
883 }
884
885 if (io_image && io_sgeom && diag_cnt == 1) {
886 diag_cnt = 0;
887 }
888
889 /* User option checking */
890
891 /* By default, run in interactive mode */
892 if (!io_fdisk && !diag_cnt && !io_nifdisk) {
893 io_ifdisk++;
894 io_fdisk++;
895 }
896 if (((io_fdisk || io_adjt) && diag_cnt) || (diag_cnt > 1)) {
897 errflg++;
898 }
899
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);
906 }
907
908
909 /* Figure out the correct device node to open */
910 Dfltdev = get_node(argv[optind]);
911
912 if (io_readonly)
913 openmode = O_RDONLY;
914 else
915 openmode = O_RDWR|O_CREAT;
916
917 if ((Dev = open(Dfltdev, openmode, 0666)) == -1) {
918 (void) fprintf(stderr,
919 "fdisk: Cannot open device %s.\n",
920 Dfltdev);
921 exit(1);
922 }
923 /*
924 * not all disk (or disklike) drivers support DKIOCGMEDIAINFO
925 * in that case leave the minfo structure zeroed
926 */
927 if (ioctl(Dev, DKIOCGMEDIAINFO, &minfo)) {
928 (void) memset(&minfo, 0, sizeof (minfo));
929 }
930
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)) {
936
937 /*
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.
941 */
942
943 if (errno == ENOTTY) {
944 v_flag = 0;
945 no_virtgeom_ioctl = 1;
946 } else if (errno == EINVAL) {
947 /*
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).
952 */
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);
960 }
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;
966 }
967
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);
977 }
978
979 }
980 /*
981 * Call DKIOCGGEOM if the ioctls for physical and virtual
982 * geometry fail. Get both from this generic call.
983 */
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);
991 }
992 }
993
994 Numcyl = disk_geom.dkg_ncyl;
995 heads = disk_geom.dkg_nhead;
996 sectors = disk_geom.dkg_nsect;
997
998 if (minfo.dki_lbsize != 0)
999 sectsiz = minfo.dki_lbsize;
1000 else
1001 sectsiz = 512;
1002
1003 acyl = disk_geom.dkg_acyl;
1004
1005 /*
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
1009 */
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) {
1017
1018 /*
1019 * turn off flag to print out virtual geometry (-v)
1020 */
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);
1026 }
1027
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);
1050 }
1051 }
1052
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);
1060 }
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;
1068
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);
1089 }
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);
1108 }
1109 }
1110
1111 /*
1112 * some drivers may not support DKIOCGMEDIAINFO
1113 * in that case use CHS
1114 */
1115 chs_capacity = (diskaddr_t)Numcyl * heads * sectors;
1116 dev_capacity = chs_capacity;
1117 Numcyl_usable = Numcyl;
1118
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;
1123 }
1124
1125 if (minfo.dki_capacity > 0)
1126 dev_capacity = minfo.dki_capacity;
1127
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);
1136 }
1137
1138 Nullsect = Bootsect + sectsiz;
1139 /* Zero out the "NULL" sector */
1140 for (i = 0; i < sectsiz; i++) {
1141 Nullsect[i] = 0;
1142 }
1143
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 */
1151 }
1152
1153
1154 /* This is the fdisk edit, the real reason for the program. */
1155
1156 sanity_check_provided_device(Dfltdev, Dev);
1157
1158 /* Get the new BOOT program in case we write a new fdisk table */
1159 mboot_read();
1160
1161 /* Read from disk master boot */
1162 dev_mboot_read();
1163
1164 /*
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.
1167 */
1168 Bootblk = (struct mboot *)Bootsect;
1169 copy_Bootblk_to_Table();
1170
1171 /* save away a copy of Table in Old_Table for sensing changes */
1172 copy_Table_to_Old_Table();
1173
1174 #ifdef i386
1175 /*
1176 * Read extended partition only when the fdisk table is not
1177 * supplied from a file
1178 */
1179 if (!io_ffdisk) {
1180 lf_op_flag |= FDISK_READ_DISK;
1181 }
1182 if ((rval = libfdisk_init(&epp, Dfltdev, &Table[0], lf_op_flag))
1183 != FDISK_SUCCESS) {
1184 switch (rval) {
1185 /*
1186 * FDISK_EBADLOGDRIVE, FDISK_ENOLOGDRIVE and
1187 * FDISK_EBADMAGIC can be considered as
1188 * soft errors and hence we do not exit
1189 */
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;
1215 }
1216 }
1217 #endif
1218
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);
1223 }
1224
1225 /* Does user want to delete or add an entry? */
1226 if (io_Dfdisk) {
1227 load(LOADDEL, io_Dfdisk);
1228 }
1229 if (io_Afdisk) {
1230 load(LOADADD, io_Afdisk);
1231 }
1232
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");
1245
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");
1250 }
1251
1252 /* Edit the partition table as directed */
1253 if (io_wholedisk ||(io_ifdisk && yesno())) {
1254
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);
1260
1261 Table[0].numsect =
1262 LE_32((ulong_t)((Numcyl_usable - 1) *
1263 heads * sectors));
1264
1265 Table[0].systid = SUNIXOS2; /* Solaris */
1266
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);
1280 }
1281 update_disk_and_exit(B_TRUE);
1282 }
1283 }
1284 }
1285
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);
1294 }
1295 }
1296
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();
1305 }
1306 }
1307
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);
1313
1314 update_disk_and_exit(TableChanged() == 1);
1315 return (0);
1316 }
1317
1318 /*
1319 * read_geom
1320 * Read geometry from specified file (-S).
1321 */
1322
1323 static int
read_geom(char * sgeom)1324 read_geom(char *sgeom)
1325 {
1326 char line[256];
1327 FILE *fp;
1328
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);
1334 }
1335
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 §siz) != 7) {
1350 (void) fprintf(stderr,
1351 "Syntax error:\n \"%s\".\n",
1352 line);
1353 return (1);
1354 }
1355 break;
1356 } /* else */
1357 } /* while (fgets(line, sizeof (line) - 1, fp)) */
1358
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);
1364 }
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;
1370 }
1371
1372 (void) fclose(fp);
1373 return (0);
1374 }
1375
1376 /*
1377 * dev_mboot_read
1378 * Read the master boot sector from the device.
1379 */
1380 static void
dev_mboot_read(void)1381 dev_mboot_read(void)
1382 {
1383 if ((ioctl(Dev, DKIOCGMBOOT, Bootsect) < 0) && (errno != ENOTTY)) {
1384 perror("Error in ioctl DKIOCGMBOOT");
1385 }
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);
1394 }
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);
1401 }
1402 }
1403
1404 /*
1405 * dev_mboot_write
1406 * Write the master boot sector to the device.
1407 */
1408 static void
dev_mboot_write(off_t sect,char * buff,int bootsiz)1409 dev_mboot_write(off_t sect, char *buff, int bootsiz)
1410 {
1411 int new_pt, old_pt, error;
1412 int clr_efi = -1;
1413
1414 if (io_readonly)
1415 return;
1416
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);
1423 }
1424 }
1425
1426 /*
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).
1430 */
1431 for (new_pt = 0; new_pt < FD_NUMPART; new_pt++) {
1432
1433 /* We only care about potential Solaris parts. */
1434 if (Table[new_pt].systid != SUNIXOS &&
1435 Table[new_pt].systid != SUNIXOS2)
1436 continue;
1437
1438 /* Does the old table have an exact entry for the new entry? */
1439 for (old_pt = 0; old_pt < FD_NUMPART; old_pt++) {
1440
1441 /* We only care about old Solaris partitions. */
1442 if ((Old_Table[old_pt].systid == SUNIXOS) ||
1443 (Old_Table[old_pt].systid == SUNIXOS2)) {
1444
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 */
1451 }
1452 }
1453
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");
1461 }
1462 clear_vtoc(NEW, new_pt);
1463 }
1464 }
1465
1466
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;
1471 }
1472 }
1473
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;
1486 }
1487
1488 /*
1489 * if EFI partition changed, set the flag to clear
1490 * the EFI GPT
1491 */
1492 if (old_pt == FD_NUMPART && Table[new_pt].begcyl != 0) {
1493 clr_efi = 0;
1494 }
1495 break;
1496 }
1497
1498 /* clear labels if necessary */
1499 if (clr_efi >= 0) {
1500 if (io_debug) {
1501 (void) fprintf(stderr, "Clearing EFI labels\n");
1502 }
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);
1509 }
1510 }
1511 }
1512
1513 if ((ioctl(Dev, DKIOCSMBOOT, buff) == -1) && (errno != ENOTTY)) {
1514 (void) fprintf(stderr,
1515 "fdisk: Error in ioctl DKIOCSMBOOT on %s.\n",
1516 Dfltdev);
1517 }
1518 if (errno == 0)
1519 return;
1520
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);
1527 }
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);
1533 }
1534 }
1535
1536 /*
1537 * mboot_read
1538 * Read the prototype boot records from the files.
1539 */
1540 static void
mboot_read(void)1541 mboot_read(void)
1542 {
1543 int mDev, i;
1544 struct ipart *part;
1545
1546 #if defined(i386) || defined(sparc)
1547 /*
1548 * If the master boot file hasn't been specified, use the
1549 * implementation architecture name to generate the default one.
1550 */
1551 if (io_mboot == (char *)0) {
1552 /*
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.
1557 */
1558 io_mboot = "/usr/lib/fs/ufs/mboot";
1559 }
1560
1561 /* First read in the master boot record */
1562
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);
1569 }
1570
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);
1578 }
1579
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);
1588 }
1589
1590 (void) close(mDev);
1591 #else
1592 #error fdisk needs to be ported to new architecture
1593 #endif
1594
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));
1599 }
1600
1601 }
1602
1603 /*
1604 * fill_patt
1605 * Fill the disk with user/sector number pattern.
1606 */
1607 static void
fill_patt(void)1608 fill_patt(void)
1609 {
1610 int *buff_ptr, i;
1611 off_t *off_ptr;
1612 int io_fpatt = 0;
1613 int io_ipatt = 0;
1614
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;
1621 }
1622
1623 /*
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.
1627 */
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;
1634 }
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);
1641 }
1642 if (write(Dev, Bootsect, sectsiz) != sectsiz) {
1643 (void) fprintf(stderr, "fdisk: Error writing %s.\n",
1644 Dfltdev);
1645 exit(1);
1646 }
1647 } /* while (--io_size); */
1648 }
1649
1650 /*
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).
1654 */
1655 static void
abs_read(void)1656 abs_read(void)
1657 {
1658 int c;
1659
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);
1666 }
1667 if (read(Dev, Bootsect, sectsiz) != sectsiz) {
1668 (void) fprintf(stderr, "fdisk: Error reading %s.\n",
1669 Dfltdev);
1670 exit(1);
1671 }
1672
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);
1685 }
1686 } /* if ((c = write(1, Bootsect, (unsigned)sectsiz)) */
1687 /* != sectsiz) */
1688 } /* while (--io_size); */
1689 exit(0);
1690 }
1691
1692 /*
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).
1696 */
1697 static void
abs_write(void)1698 abs_write(void)
1699 {
1700 int c, i;
1701
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;
1718 }
1719 part_exit++;
1720 } else {
1721 perror("read error on input file.");
1722 exit(2);
1723 }
1724
1725 }
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);
1732 }
1733 if (write(Dev, Bootsect, sectsiz) != sectsiz) {
1734 (void) fprintf(stderr, "fdisk: Error writing %s.\n",
1735 Dfltdev);
1736 exit(1);
1737 }
1738 if (part_exit)
1739 exit(0);
1740 } /* while (--io_size); */
1741 exit(1);
1742 }
1743
1744
1745 /*
1746 * load
1747 * Load will either read the fdisk table from a file or add or
1748 * delete an entry (-A, -D, -F).
1749 */
1750
1751 static void
load(int funct,char * file)1752 load(int funct, char *file)
1753 {
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
1780
1781 switch (funct) {
1782
1783 case LOADFILE:
1784
1785 /*
1786 * Zero out the table before loading it, which will
1787 * force it to be updated on disk later (-F
1788 * fdisk_file).
1789 */
1790 nulltbl();
1791
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);
1798 }
1799
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;
1805 }
1806 #ifdef i386
1807 part_count++;
1808
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);
1817 }
1818 ext_part_present = 1;
1819 /*
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.
1825 */
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;
1834 }
1835 }
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;
1843 }
1844 }
1845
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);
1856 }
1857
1858 if (numsect == 0) {
1859 continue;
1860 }
1861
1862 /*
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.
1867 */
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;
1872 }
1873
1874 begsec = rsect - offset;
1875 if ((ldcnt =
1876 fdisk_get_logical_drive_count(epp)) == 0) {
1877 /* Adding the first logical drive */
1878 /*
1879 * Make sure that begsec doesnt wrap
1880 * around. This can happen if rsect is
1881 * less than offset.
1882 */
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);
1890 }
1891 /*
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.
1896 */
1897 if (begsec != new_ext_beg_sec) {
1898 begsec = rsect;
1899 offset = 0;
1900 }
1901 }
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);
1908 }
1909
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);
1916 }
1917
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);
1927 }
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);
1935 }
1936 }
1937 #endif
1938
1939 /*
1940 * Validate the partition. It cannot start at sector
1941 * 0 unless it is UNUSED or already exists
1942 */
1943 if (validate_part(id, rsect, numsect) < 0) {
1944 (void) fprintf(stderr,
1945 "fdisk: Error on entry \"%s\".\n",
1946 line);
1947 exit(1);
1948 }
1949
1950 if ((tmpindex = entry_from_old_table(id, act, bhead,
1951 bsect, bcyl, ehead, esect, ecyl, rsect, numsect,
1952 startindex)) != -1) {
1953 /*
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.
1958 *
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.
1964 *
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.
1971 *
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.
1978 *
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.
1988 */
1989 startindex = tmpindex + 1;
1990 continue;
1991 }
1992
1993 /*
1994 * Find an unused entry to use and put the entry
1995 * in table
1996 */
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);
2004 }
2005 startindex++;
2006 } /* while (fgets(line, sizeof (line) - 1, fp)) */
2007
2008 if (verify_tbl() < 0) {
2009 (void) fprintf(stderr,
2010 "fdisk: Cannot create partition table\n");
2011 exit(1);
2012 }
2013
2014 (void) fclose(fp);
2015 return;
2016
2017 case LOADDEL:
2018
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);
2025 }
2026
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)) {
2041
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);
2047 }
2048 #endif
2049 return;
2050 }
2051 }
2052
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;
2072 }
2073 ldcnt++;
2074 }
2075 #endif
2076
2077 (void) fprintf(stderr,
2078 "fdisk: Entry does not match any existing partition:\n"
2079 " \"%s\"\n",
2080 file);
2081 exit(1);
2082 /* FALLTHRU */
2083
2084 case LOADADD:
2085
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);
2092 }
2093
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);
2101 }
2102
2103 /*
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
2107 */
2108
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);
2115 }
2116
2117
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);
2126 }
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);
2135 }
2136 }
2137
2138 #ifdef i386
2139 if (id > FDISK_MAX_VALID_PART_ID) {
2140 (void) printf("Invalid partition ID\n");
2141 exit(1);
2142 }
2143
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);
2152 }
2153
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;
2158
2159 /*
2160 * Make sure that begsec doesnt wrap around.
2161 * This can happen if rsect is less than offset
2162 */
2163 if (rsect < offset) {
2164 return;
2165 }
2166 begsec = rsect - offset;
2167 if ((ldcnt = fdisk_get_logical_drive_count(epp)) == 0) {
2168 /*
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.
2174 */
2175 if (begsec != ext_beg_sec) {
2176 begsec = rsect;
2177 offset = 0;
2178 }
2179 }
2180
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);
2186 }
2187
2188 if (numsect == 0) {
2189 (void) fprintf(stderr,
2190 "fdisk: Partition size cannot be zero:\n"
2191 " \"%s\".\n",
2192 file);
2193 exit(1);
2194 }
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);
2207 }
2208 }
2209 #endif
2210
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);
2219 }
2220
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);
2226 }
2227 } /* switch funct */
2228 }
2229
2230 /*
2231 * Set_Table_CHS_Values
2232 *
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.
2236 *
2237 * hba_heads and hba_sectors contain the number of heads and sectors.
2238 *
2239 * If the number of cylinders exceeds the MAX_CYL,
2240 * then maximum values will be placed in the corresponding chs entry.
2241 */
2242 static void
Set_Table_CHS_Values(int ti)2243 Set_Table_CHS_Values(int ti)
2244 {
2245 uint32_t lba, cy, hd, sc;
2246
2247 lba = (uint32_t)Table[ti].relsect;
2248 if (lba >= hba_heads * hba_sectors * MAX_CYL) {
2249 /*
2250 * the lba address cannot be expressed in CHS value
2251 * so store the maximum CHS field values in the CHS fields.
2252 */
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;
2260 }
2261 Table[ti].begcyl = cy & 0xff;
2262 Table[ti].beghead = (uchar_t)hd;
2263 Table[ti].begsect = (uchar_t)(((cy >> 2) & 0xc0) | sc);
2264
2265 /*
2266 * This code is identical to the code above
2267 * except that it works on ending CHS values
2268 */
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;
2278 }
2279 Table[ti].endcyl = cy & 0xff;
2280 Table[ti].endhead = (uchar_t)hd;
2281 Table[ti].endsect = (uchar_t)(((cy >> 2) & 0xc0) | sc);
2282 }
2283
2284 /*
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!
2289 */
2290 static int
insert_tbl(int id,int act,int bhead,int bsect,int bcyl,int ehead,int esect,int ecyl,uint32_t rsect,uint32_t numsect,int startindex)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)
2296 {
2297 int i;
2298
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);
2304 }
2305
2306
2307 /* find UNUSED partition table entry */
2308 for (i = startindex; i < FD_NUMPART; i++) {
2309 if (Table[i].systid == UNUSED) {
2310 break;
2311 }
2312 }
2313 if (i >= FD_NUMPART) {
2314 (void) fprintf(stderr, "fdisk: Partition table is full.\n");
2315 return (-1);
2316 }
2317
2318
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);
2323
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) {
2330
2331 /*
2332 * If we have been called with a valid geometry, use it
2333 * valid means non-zero values that fit in the BIOS fields
2334 */
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 {
2346
2347 /*
2348 * The specified values are invalid,
2349 * so calculate the values based on hba_heads, hba_sectors
2350 */
2351 Set_Table_CHS_Values(i);
2352 }
2353
2354 /*
2355 * return partition index
2356 */
2357 return (i);
2358 }
2359
2360 /*
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!
2365 */
2366 static int
entry_from_old_table(int id,int act,int bhead,int bsect,int bcyl,int ehead,int esect,int ecyl,uint32_t rsect,uint32_t numsect,int startindex)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)
2372 {
2373 uint32_t i, j;
2374
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);
2397
2398 }
2399 }
2400 return (-1);
2401 }
2402
2403 }
2404 return (-1);
2405 }
2406
2407 /*
2408 * verify_tbl
2409 * Verify that no partition entries overlap or exceed the size of
2410 * the disk.
2411 */
2412 static int
verify_tbl(void)2413 verify_tbl(void)
2414 {
2415 uint32_t i, j, rsect, numsect;
2416 int noMoreParts = 0;
2417 int numParts = 0;
2418
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++;
2423 /*
2424 * No valid partitions allowed after EFI_PMBR part
2425 */
2426 if (noMoreParts) {
2427 return (-1);
2428 }
2429
2430 if (Table[i].systid == EFI_PMBR) {
2431 /*
2432 * EFI_PMBR partition must be the only
2433 * partition
2434 */
2435 noMoreParts = 1;
2436
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);
2444
2445 return (-1);
2446 }
2447
2448 if (Table[i].numsect !=
2449 ((dev_capacity > DK_MAX_2TB) ? DK_MAX_2TB:
2450 (dev_capacity - 1))) {
2451
2452 (void) fprintf(stderr, "ERROR: "
2453 "EFI_PMBR partition must "
2454 "encompass the entire");
2455
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);
2463
2464 else
2465 (void) fprintf(stderr,
2466 "disk.\n numsect %u - "
2467 "actual %llu\n",
2468 Table[i].numsect,
2469 dev_capacity - 1);
2470
2471 return (-1);
2472 }
2473 }
2474
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);
2478
2479 if ((((diskaddr_t)rsect + numsect) > dev_capacity) ||
2480 (((diskaddr_t)rsect + numsect) > DK_MAX_2TB)) {
2481 if (!skip_verify[i])
2482 return (-1);
2483 }
2484
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);
2491
2492 if (noMoreParts) {
2493 (void) fprintf(stderr,
2494 "Cannot add partition to "
2495 "table; no more partitions "
2496 "allowed\n");
2497
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);
2528 }
2529
2530 return (-1);
2531 }
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");
2540
2541 return (-1);
2542 }
2543 }
2544 }
2545 }
2546 }
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);
2556 }
2557 }
2558
2559 return (numParts);
2560 }
2561
2562 /*
2563 * pars_fdisk
2564 * Parse user-supplied data to set up fdisk partitions
2565 * (-A, -D, -F).
2566 */
2567 static int
pars_fdisk(char * line,int * id,int * act,int * bhead,int * bsect,int * bcyl,int * ehead,int * esect,int * ecyl,uint32_t * rsect,uint32_t * numsect)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)
2574 {
2575 int i;
2576 int64_t test;
2577 char *tok, *p;
2578 char buf[256];
2579
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] = ' ';
2588 }
2589 }
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);
2599 }
2600 }
2601
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);
2607 }
2608 tok = strtok(NULL, ": \t\n");
2609 }
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);
2615 }
2616 return (0);
2617 }
2618
2619 /*
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.
2623 */
2624 static int
validate_part(int id,uint32_t rsect,uint32_t numsect)2625 validate_part(int id, uint32_t rsect, uint32_t numsect)
2626 {
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);
2634 }
2635 (void) fprintf(stderr,
2636 "New partition cannot start at sector 0\n");
2637 return (-1);
2638 }
2639 #ifdef i386
2640 if (id > FDISK_MAX_VALID_PART_ID) {
2641 (void) fprintf(stderr, "Invalid partition ID\n");
2642 return (-1);
2643 }
2644 #endif
2645 return (0);
2646 }
2647
2648 /*
2649 * stage0
2650 * Print out interactive menu and process user input.
2651 */
2652 static void
stage0(void)2653 stage0(void)
2654 {
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 "Enter a one-digit number between 1 and 7.");
2675 #else
2676 (void) printf(
2677 "Enter 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);
2683 }
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);
2713 }
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);
2720 }
2721
2722 /*
2723 * If the VTOC table is wrong fix it
2724 * (truncate only)
2725 */
2726 if (io_adjt) {
2727 fix_slice();
2728 }
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);
2745 }
2746 libfdisk_fini(&epp);
2747 }
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);
2757 }
2758 /*
2759 * If the VTOC table is wrong fix it
2760 * (truncate only)
2761 */
2762 if (io_adjt) {
2763 fix_slice();
2764 }
2765 (void) close(Dev);
2766 exit(0);
2767 /* FALLTHRU */
2768 #endif
2769 #ifdef i386
2770 case '7':
2771 #else
2772 case '6':
2773 #endif
2774 /*
2775 * If the VTOC table is wrong fix it
2776 * (truncate only)
2777 */
2778 if (io_adjt) {
2779 fix_slice();
2780 }
2781 (void) close(Dev);
2782 exit(0);
2783 /* FALLTHRU */
2784 default:
2785 break;
2786 }
2787 copy_Table_to_Bootblk();
2788 disptbl();
2789 dispmenu();
2790 }
2791 }
2792
2793 /*
2794 * pcreate
2795 * Create partition entry in the table (interactive mode).
2796 */
2797 static int
2798 pcreate(void)
2799 {
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
2807
2808 i = 0;
2809 for (;;) {
2810 if (i == FD_NUMPART) {
2811 (void) printf(E_LINE);
2812 (void) printf(
2813 "The partition table is full!\n"
2814 "You must delete a partition before creating"
2815 " a new one.\n");
2816 return (-1);
2817 }
2818 if (Table[i].systid == UNUSED) {
2819 break;
2820 }
2821 i++;
2822 }
2823
2824 numsect = 0;
2825 for (i = 0; i < FD_NUMPART; i++) {
2826 if (Table[i].systid != UNUSED) {
2827 numsect += LE_32(Table[i].numsect);
2828 }
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;
2833 }
2834 #endif
2835 if (numsect >= chs_capacity) {
2836 (void) printf(E_LINE);
2837 (void) printf("There 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);
2843 }
2844 }
2845 while (tsystid == 'z') {
2846
2847 /*
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.
2852 */
2853
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;
2868 }
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;
2902 }
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;
2940 }
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;
2952 }
2953 }
2954
2955 (void) printf(E_LINE);
2956
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");
2962
2963 /* create the new partition */
2964 i = specify(tsystid);
2965
2966 if (i != -1) {
2967 /* see if it should be the active partition */
2968 (void) printf(E_LINE);
2969 (void) printf(Q_LINE);
2970
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\". ");
2976
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;
2989 }
2990 }
2991 } else {
2992 Table[i].bootid = 0;
2993 }
2994
2995 #ifdef i386
2996 /*
2997 * If partition created is an extended partition, null
2998 * out the first sector of the first cylinder of the
2999 * extended partition
3000 */
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));
3005 }
3006 #endif
3007 /* set up the return code */
3008 i = 1;
3009 }
3010 } else {
3011 /*
3012 * partitions of type EFI_PMBR must be the only partitions in
3013 * the table
3014 *
3015 * First, make sure there were no errors the table is
3016 * empty
3017 */
3018 retCode = verify_tbl();
3019
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\". ");
3033
3034 if (yesno()) {
3035 nulltbl();
3036 } else {
3037 return (-1);
3038 }
3039 }
3040
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);
3045
3046 if (i != 0) {
3047 (void) printf("Error creating EFI partition!!!\n");
3048 i = -1;
3049 } else {
3050
3051 /* EFI partitions are currently never active */
3052 Table[i].bootid = 0;
3053
3054 /* set up the return code */
3055 i = 1;
3056 }
3057 }
3058
3059 return (i);
3060 }
3061
3062 /*
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.
3067 */
3068 static int
3069 specify(uchar_t tsystid)
3070 {
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];
3078
3079 cyl_size = heads * sectors;
3080
3081 /*
3082 * make a local copy of the partition table
3083 * and sort it into relsect order
3084 */
3085
3086
3087 for (i = 0, j = 0; i < FD_NUMPART; i++) {
3088 if (Table[i].systid != UNUSED) {
3089 localpart[j] = Table[i];
3090 j++;
3091 }
3092 }
3093
3094 while (j < FD_NUMPART) {
3095 (void) memset(&localpart[j], 0, sizeof (struct ipart));
3096 j++;
3097 }
3098
3099 for (i = 0; i < FD_NUMPART; i++)
3100 partition[i] = &localpart[i];
3101
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;
3113 }
3114 }
3115 }
3116
3117
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("Invalid percentage value "
3130 "specified; retry the operation.");
3131 return (-1);
3132 }
3133 i++;
3134 if (i > 3) {
3135 (void) printf(E_LINE);
3136 (void) printf("Invalid percentage value "
3137 "specified; retry the operation.");
3138 return (-1);
3139 }
3140 }
3141 if ((percent = atoi(s)) > 100) {
3142 (void) printf(E_LINE);
3143 (void) printf(
3144 "Percentage value is too large. The value must be"
3145 " between 1 and 100;\nretry the operation.\n");
3146 return (-1);
3147 }
3148 if (percent < 1) {
3149 (void) printf(E_LINE);
3150 (void) printf(
3151 "Percentage value is too small. The value must be"
3152 " between 1 and 100;\nretry the operation.\n");
3153 return (-1);
3154 }
3155
3156 if (percent == 100)
3157 cylen = Numcyl_usable - 1;
3158 else
3159 cylen = (Numcyl_usable * percent) / 100;
3160
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("Maximum size for a DOS partition "
3168 "is %d%%; retry the operation.",
3169 n <= 100 ? n : 100);
3170 return (-1);
3171 }
3172
3173
3174 max_free = 0;
3175 for (i = 0; i < FD_NUMPART; i++) {
3176
3177 /*
3178 * check for free space before partition i
3179 * where i varies from 0 to 3
3180 *
3181 * freespace after partition 3 is unusable
3182 * because there are no free partitions
3183 *
3184 * freespace begins at the end of previous partition
3185 * or cylinder 1
3186 */
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;
3193 }
3194
3195 /*
3196 * freespace ends before the current partition
3197 * or the end of the disk (chs end)
3198 */
3199 if (partition[i]->systid == UNUSED) {
3200 size_free = chs_capacity - first_free;
3201 } else {
3202 /*
3203 * Partition might start before cylinder 1.
3204 * Make sure free space is not negative.
3205 */
3206 size_free =
3207 (LE_32(partition[i]->relsect > first_free))
3208 ? (LE_32(partition[i]->relsect) -
3209 first_free) : 0;
3210 }
3211
3212 /* save largest free space */
3213 if (max_free < size_free)
3214 max_free = size_free;
3215
3216 if (((uint64_t)cylen * cyl_size) <= size_free) {
3217 /* We found a place to use */
3218 break;
3219 }
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);
3227 }
3228 }
3229
3230 (void) printf(E_LINE);
3231 if (i >= FD_NUMPART) {
3232 (void) fprintf(stderr,
3233 "fdisk: Partition table is full.\n");
3234 return (-1);
3235 }
3236
3237 if ((i = insert_tbl(tsystid, 0, 0, 0, 0, 0, 0, 0,
3238 first_free, cylen * cyl_size, 0)) >= 0) {
3239 return (i);
3240 }
3241 return (-1);
3242 } else {
3243
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);
3252 }
3253 if (cyl == 0) {
3254 (void) printf(E_LINE);
3255 (void) printf(
3256 "New partition cannot start at cylinder 0.\n");
3257 return (-1);
3258 }
3259
3260
3261 if (cyl >= Numcyl_usable) {
3262 (void) printf(E_LINE);
3263 (void) printf(
3264 "Cylinder %d is out of bounds, "
3265 "the maximum is %d.\n",
3266 cyl, Numcyl_usable - 1);
3267 return (-1);
3268 }
3269
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);
3276 }
3277
3278 for (i = 0; i < FD_NUMPART; i++) {
3279 uint32_t t_relsect, t_numsect;
3280
3281 if (partition[i]->systid == UNUSED)
3282 break;
3283 t_relsect = LE_32(partition[i]->relsect);
3284 t_numsect = LE_32(partition[i]->numsect);
3285
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);
3294 }
3295
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);
3304 }
3305 }
3306
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);
3320 }
3321 return (-1);
3322 }
3323
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);
3333 }
3334
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);
3340
3341 if (verify_tbl() < 0) {
3342 (void) printf(E_LINE);
3343 (void) printf("fdisk: Cannot create partition table\n");
3344 return (-1);
3345 }
3346
3347 return (i);
3348 }
3349 }
3350
3351 /*
3352 * dispmenu
3353 * Display command menu (interactive mode).
3354 */
3355 static void
3356 dispmenu(void)
3357 {
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
3379 }
3380
3381 /*
3382 * pchange
3383 * Change the ACTIVE designation of a partition.
3384 */
3385 static int
3386 pchange(void)
3387 {
3388 char s[80];
3389 int i, j;
3390
3391 for (;;) {
3392 (void) printf(Q_LINE);
3393 {
3394 (void) printf(
3395 "Specify the partition number to boot from"
3396 " (or specify 0 for none): ");
3397 }
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 "Invalid response, please specify a number"
3405 " between 0 and 4.\n");
3406 } else {
3407 break;
3408 }
3409 }
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;
3415 }
3416 (void) printf(E_LINE);
3417 (void) printf(
3418 "No partition is currently marked as active.");
3419 return (0);
3420 } else { /* User has selected a partition to be active */
3421
3422 i = s[0] - '1';
3423
3424 if (Table[i].systid == UNUSED) {
3425 (void) printf(E_LINE);
3426 (void) printf("Partition does not exist.");
3427 return (-1);
3428 }
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);
3439 }
3440 Table[i].bootid = ACTIVE;
3441 for (j = 0; j < FD_NUMPART; j++) {
3442 if (j != i)
3443 Table[j].bootid = 0;
3444 }
3445 }
3446 (void) printf(E_LINE);
3447 {
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.");
3452 }
3453 return (1);
3454 }
3455
3456 /*
3457 * Change between SOLARIS and SOLARIS2 partition id
3458 */
3459 static int
3460 ppartid(void)
3461 {
3462 char *p, s[80];
3463 int i;
3464
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);
3472
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;
3478 }
3479
3480 if (i == 0) {
3481 /* exit delete command */
3482 (void) printf(E_LINE); /* clear error message */
3483 return (1);
3484 }
3485
3486 i -= 1;
3487
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;
3498 }
3499
3500 (void) printf(E_LINE);
3501 (void) printf("Partition %d has been changed.", i + 1);
3502 return (1);
3503 }
3504 }
3505
3506 /*
3507 * pdelete
3508 * Remove partition entry from the table (interactive mode).
3509 */
3510 static char
3511 pdelete(void)
3512 {
3513 char s[80];
3514 int i;
3515 char pactive;
3516
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);
3525 }
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 */
3534 }
3535
3536 if (Table[i].systid == UNUSED) {
3537 (void) printf(E_LINE);
3538 (void) printf("Partition %d does not exist.", i + 1);
3539 return (-1);
3540 }
3541
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\") ");
3551
3552 (void) printf(E_LINE);
3553 if (! yesno()) {
3554 return (1);
3555 }
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);
3565 }
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\"). ");
3574
3575 (void) printf(E_LINE);
3576 if (! yesno()) {
3577 return (1);
3578 }
3579 #ifdef i386
3580 }
3581 #endif
3582
3583 if (Table[i].bootid == ACTIVE) {
3584 pactive = 1;
3585 } else {
3586 pactive = 0;
3587 }
3588
3589 (void) memset(&Table[i], 0, sizeof (struct ipart));
3590
3591 (void) printf(E_LINE);
3592 (void) printf("Partition %d has been deleted.", i + 1);
3593
3594 if (pactive) {
3595 (void) printf(" This was the active partition.");
3596 }
3597
3598 return (1);
3599 }
3600
3601 /*
3602 * rm_blanks
3603 * Remove blanks from strings of user responses.
3604 */
3605 static void
3606 rm_blanks(char *s)
3607 {
3608 register int i, j;
3609
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;
3616 }
3617 for (j = 0; i < CBUFLEN; j++, i++) {
3618 if ((s[j] = s[i]) == '\0') {
3619 /* Reached end of string */
3620 return;
3621 }
3622 }
3623 }
3624
3625 /*
3626 * getcyl
3627 * Take the user-specified cylinder number and convert it from a
3628 * string to a decimal value.
3629 */
3630 static int
3631 getcyl(void)
3632 {
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);
3645 }
3646 cyl += (j * (s[i] - '0'));
3647 j *= 10;
3648 }
3649 return (cyl);
3650 }
3651
3652 /*
3653 * disptbl
3654 * Display the current fdisk table; determine percentage
3655 * of the disk used for each partition.
3656 */
3657 static void
3658 disptbl(void)
3659 {
3660 int i;
3661 unsigned int startcyl, endcyl, length, percent, remainder;
3662 char *stat, *type;
3663 int is_pmbr = 0;
3664
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);
3670 }
3671
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 " ===");
3685
3686
3687 for (i = 0; i < FD_NUMPART; i++) {
3688
3689 if (Table[i].systid == UNUSED) {
3690 continue;
3691 }
3692
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;
3806
3807 break;
3808 default:
3809 type = Ostr;
3810 break;
3811 }
3812 startcyl = LE_32(Table[i].relsect) /
3813 (unsigned long)(heads * sectors);
3814
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;
3825 }
3826
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++;
3832 }
3833 /* Else leave the percent as is since it's already */
3834 /* rounded down */
3835 }
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);
3842 }
3843
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);
3851
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");
3856 }
3857 }
3858
3859 /*
3860 * print_Table
3861 * Write the detailed fdisk table to standard error for
3862 * the selected disk device.
3863 */
3864 static void
3865 print_Table(void)
3866 {
3867 int i;
3868
3869 (void) fprintf(stderr,
3870 " SYSID ACT BHEAD BSECT BEGCYL EHEAD ESECT ENDCYL RELSECT"
3871 " NUMSECT\n");
3872
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);
3880
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));
3887
3888 }
3889 }
3890
3891 /*
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.
3896 */
3897 static void
3898 copy_Table_to_Old_Table(void)
3899 {
3900 int i;
3901 for (i = 0; i < FD_NUMPART; i++) {
3902 (void) memcpy(&Old_Table[i], &Table[i], sizeof (Table[0]));
3903 }
3904 }
3905
3906 /*
3907 * nulltbl
3908 * Zero out the systid, numsect, relsect, and bootid values in the
3909 * fdisk table.
3910 */
3911 static void
3912 nulltbl(void)
3913 {
3914 int i;
3915
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;
3922 }
3923 }
3924
3925 /*
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.
3929 */
3930 static void
3931 copy_Bootblk_to_Table(void)
3932 {
3933 int i;
3934 char *bootptr;
3935 struct ipart iparts[FD_NUMPART];
3936
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;
3945 }
3946 /*
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.
3951 */
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]);
3958 }
3959 bootptr += sizeof (struct ipart);
3960 }
3961
3962 /* For now, always replace the bootcode with ours */
3963 (void) memcpy(Bootblk->bootinst, &BootCod, BOOTSZ);
3964 copy_Table_to_Bootblk();
3965 }
3966
3967 /*
3968 * fill_ipart
3969 * Initialize ipart structure values.
3970 */
3971 static void
3972 fill_ipart(char *bootptr, struct ipart *partp)
3973 {
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
3989 }
3990
3991 /*
3992 * getbyte, getlong
3993 * Get a byte, a short, or a long (SPARC only).
3994 */
3995 #ifdef sparc
3996 uchar_t
3997 getbyte(char **bp)
3998 {
3999 uchar_t b;
4000
4001 b = (uchar_t)**bp;
4002 *bp = *bp + 1;
4003 return (b);
4004 }
4005
4006 uint32_t
4007 getlong(char **bp)
4008 {
4009 int32_t b, bh, bl;
4010
4011 bh = ((**bp) << 8) | *(*bp + 1);
4012 *bp += 2;
4013 bl = ((**bp) << 8) | *(*bp + 1);
4014 *bp += 2;
4015
4016 b = (bh << 16) | bl;
4017 return ((uint32_t)b);
4018 }
4019 #endif
4020
4021 /*
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.
4027 */
4028 static void
4029 copy_Table_to_Bootblk(void)
4030 {
4031 struct ipart *boot_ptr, *tbl_ptr;
4032
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));
4041 }
4042 Bootblk->signature = LE_16(MBB_MAGIC);
4043 }
4044
4045 /*
4046 * TableChanged
4047 * Check for any changes in the partition table.
4048 */
4049 static int
4050 TableChanged(void)
4051 {
4052 int i, changed;
4053
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;
4059 }
4060 }
4061
4062 return (changed);
4063 }
4064
4065 /*
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).
4069 */
4070 static void
4071 ffile_write(char *file)
4072 {
4073 register int i;
4074 FILE *fp;
4075
4076 /*
4077 * If file isn't standard output, then it's a file name.
4078 * Open file and write it.
4079 */
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);
4086 }
4087 }
4088 else
4089 fp = stdout;
4090
4091 /*
4092 * Write the fdisk table information
4093 */
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");
4109 }
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");
4151
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));
4168 }
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);
4196 }
4197 }
4198 #endif
4199
4200 if (fp != stdout)
4201 (void) fclose(fp);
4202 }
4203
4204 /*
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.
4209 */
4210 static void
4211 fix_slice(void)
4212 {
4213 int i;
4214 uint32_t numsect;
4215
4216 if (io_image) {
4217 return;
4218 }
4219
4220 for (i = 0; i < FD_NUMPART; i++) {
4221 if (Table[i].systid == SUNIXOS || Table[i].systid == SUNIXOS2) {
4222 /*
4223 * Only the size matters (not starting point), since
4224 * VTOC entries are relative to the start of
4225 * the partition.
4226 */
4227 numsect = LE_32(Table[i].numsect);
4228 break;
4229 }
4230 }
4231
4232 if (i >= FD_NUMPART) {
4233 if (!io_nifdisk) {
4234 (void) fprintf(stderr,
4235 "fdisk: No Solaris partition found - VTOC not"
4236 " checked.\n");
4237 }
4238 return;
4239 }
4240
4241 if (readvtoc() != VTOC_OK) {
4242 exit(1); /* Failed to read the VTOC */
4243 }
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");
4259 }
4260
4261 }
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");
4275 }
4276 }
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");
4290 }
4291 }
4292 continue;
4293 }
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;
4311 }
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");
4319 }
4320 }
4321 continue;
4322 }
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;
4334 }
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");
4342 }
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",
4348 i,
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;
4355 }
4356 } else {
4357 disk_vtoc.v_part[i].p_size = numsect;
4358 (void) fprintf(stderr, " adjusted!\n");
4359 }
4360 }
4361 }
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
4370
4371 /* Write the VTOC back to the disk */
4372 if (!io_readonly)
4373 (void) writevtoc();
4374 }
4375
4376 /*
4377 * yesno
4378 * Get yes or no answer. Return 1 for yes and 0 for no.
4379 */
4380
4381 static int
4382 yesno(void)
4383 {
4384 char s[80];
4385
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;
4394 }
4395 if (s[0] == 'y')
4396 return (1);
4397 else
4398 return (0);
4399 }
4400 }
4401
4402 /*
4403 * readvtoc
4404 * Read the VTOC from the Solaris partition of the device.
4405 */
4406 static int
4407 readvtoc(void)
4408 {
4409 int i;
4410 int retval = VTOC_OK;
4411
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;
4424 }
4425 }
4426 return (retval);
4427 }
4428
4429 /*
4430 * writevtoc
4431 * Write the VTOC to the Solaris partition on the device.
4432 */
4433 static int
4434 writevtoc(void)
4435 {
4436 int i;
4437 int retval = 0;
4438
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;
4451 }
4452 }
4453 return (retval);
4454 }
4455
4456 /*
4457 * efi_ioctl
4458 * issues DKIOCSETEFI IOCTL
4459 * (duplicate of private efi_ioctl() in rdwr_efi.c
4460 */
4461 static int
4462 efi_ioctl(int fd, int cmd, dk_efi_t *dk_ioc)
4463 {
4464 void *data = dk_ioc->dki_data;
4465 int error;
4466
4467 dk_ioc->dki_data_64 = (uintptr_t)data;
4468 error = ioctl(fd, cmd, (void *)dk_ioc);
4469
4470 return (error);
4471 }
4472
4473 /*
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()
4477 */
4478 static int
4479 clear_efi(void)
4480 {
4481 struct dk_gpt *efi_vtoc;
4482 dk_efi_t dk_ioc;
4483
4484 /*
4485 * see if we can read the EFI label
4486 */
4487 if (efi_alloc_and_read(Dev, &efi_vtoc) < 0) {
4488 return (VT_ERROR);
4489 }
4490
4491 /*
4492 * set up the dk_ioc structure for writing
4493 */
4494 dk_ioc.dki_lba = 1;
4495 dk_ioc.dki_length = EFI_MIN_ARRAY_SIZE + efi_vtoc->efi_lbasize;
4496
4497 if ((dk_ioc.dki_data = calloc(dk_ioc.dki_length, 1)) == NULL) {
4498 return (VT_ERROR);
4499 }
4500
4501 /*
4502 * clear the primary label
4503 */
4504 if (io_debug) {
4505 (void) fprintf(stderr,
4506 "\tClearing primary EFI label at block %lld\n",
4507 dk_ioc.dki_lba);
4508 }
4509
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);
4519 }
4520 }
4521
4522 /*
4523 * clear the backup partition table
4524 */
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);
4533 }
4534
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);
4539 }
4540
4541 /*
4542 * clear the backup label
4543 */
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);
4551 }
4552
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);
4559 }
4560
4561 free(dk_ioc.dki_data);
4562 efi_free(efi_vtoc);
4563
4564 return (0);
4565 }
4566
4567 /*
4568 * clear_vtoc
4569 * Clear the VTOC from the current or previous Solaris partition on the
4570 * device.
4571 */
4572 static void
4573 clear_vtoc(int table, int part)
4574 {
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;
4581
4582 #ifdef DEBUG
4583 char *read_label;
4584 #endif /* DEBUG */
4585
4586 if (table == OLD) {
4587 clr_table = &Old_Table[part];
4588 } else {
4589 clr_table = &Table[part];
4590 }
4591
4592 disk_label = (char *)calloc(sectsiz, 1);
4593 if (disk_label == NULL) {
4594 return;
4595 }
4596
4597 seek_byte = (off_t)(LE_32(clr_table->relsect) + VTOC_OFFSET) * sectsiz;
4598
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));
4604 }
4605
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;
4612 }
4613
4614 bytes = write(Dev, disk_label, sectsiz);
4615
4616 if (bytes != sectsiz) {
4617 (void) fprintf(stderr,
4618 "\tWarning: only %d bytes written to clear primary"
4619 " VTOC!\n", bytes);
4620 }
4621
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);
4633 }
4634
4635 read_label = (char *)calloc(sectsiz, 1);
4636 if (read_label == NULL) {
4637 free(disk_label);
4638 return;
4639 }
4640
4641 bytes = read(Dev, read_label, sectsiz);
4642
4643 if (bytes != sectsiz) {
4644 (void) fprintf(stderr,
4645 "DEBUG: Warning: only %d bytes read of label\n",
4646 bytes);
4647 }
4648
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");
4655 }
4656 #endif /* DEBUG */
4657
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;
4662
4663 backup_block = ((ncyl + acyl - 1) *
4664 (heads * sectors)) + ((heads - 1) * sectors) + 1;
4665
4666 for (count = 1; count < 6; count++) {
4667 seek_byte = (off_t)(solaris_offset + backup_block) * sectsiz;
4668
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;
4678 }
4679
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));
4685 }
4686
4687 bytes = write(Dev, disk_label, sectsiz);
4688
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));
4694 }
4695
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);
4708 }
4709
4710 bytes = read(Dev, read_label, sectsiz);
4711
4712 if (bytes != sectsiz) {
4713 (void) fprintf(stderr,
4714 "DEBUG: Warning: only %d bytes read of backup label\n",
4715 bytes);
4716 }
4717
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");
4725 }
4726
4727 #endif /* DEBUG */
4728
4729 backup_block += 2;
4730 }
4731
4732 #ifdef DEBUG
4733 free(read_label);
4734 #endif /* DEBUG */
4735 free(disk_label);
4736 }
4737
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"
4743
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"
4748
4749 #define FDISK_LECTURE_NOT_FULL \
4750 "The device does not appear to encompass the entire PHYSICAL disk.\n"
4751
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"
4755
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"
4759
4760 #define FDISK_SHALL_I_CONTINUE \
4761 "Are you sure you want to continue? (y/n) "
4762
4763 /*
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.
4771 */
4772 static int
4773 lecture_and_query(char *warning, char *devname)
4774 {
4775 if (io_nifdisk)
4776 return (0);
4777
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);
4782
4783 return (yesno());
4784 }
4785
4786 static void
4787 sanity_check_provided_device(char *devname, int fd)
4788 {
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;
4795
4796 /*
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.
4800 */
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);
4807 }
4808 }
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);
4815 }
4816 }
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);
4823 }
4824 return;
4825 }
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);
4832 }
4833 return;
4834 }
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);
4841 }
4842 }
4843 }
4844 }
4845
4846
4847 /*
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/).
4852 */
4853 static char *
4854 get_node(char *devname)
4855 {
4856 char *node;
4857 struct stat statbuf;
4858 size_t space;
4859
4860 /* Don't do anything if we are skipping device checks */
4861 if (io_image)
4862 return (devname);
4863
4864 node = devname;
4865
4866 /* Try the node as provided first */
4867 if (stat(node, (struct stat *)&statbuf) == -1) {
4868 /*
4869 * Copy the passed in string to a new buffer, prepend the
4870 * default path and try again.
4871 */
4872 space = strlen(DEFAULT_PATH) + strlen(devname) + 1;
4873
4874 if ((node = malloc(space)) == NULL) {
4875 (void) fprintf(stderr, "fdisk: Unable to obtain memory "
4876 "for device node.\n");
4877 exit(1);
4878 }
4879
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);
4884
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);
4892 }
4893 }
4894
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);
4900 }
4901
4902 return (node);
4903 }
4904
4905 #ifdef i386
4906 static void
4907 preach_and_continue()
4908 {
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);
4914 }
4915
4916 /*
4917 * Convert a given partition ID to an descriptive string.
4918 * Just an index into the partition types table.
4919 */
4920 void
4921 id_to_name(uchar_t sysid, char *buffer)
4922 {
4923 (void) strcpy(buffer, fdisk_part_types[sysid]);
4924 }
4925
4926 /*
4927 * Procedure to check the validity of the extended partition menu option
4928 * entered by the user
4929 */
4930 static int
4931 ext_invalid_option(char ch)
4932 {
4933 char *p;
4934
4935 p = strchr(ext_part_menu_opts, tolower(ch));
4936
4937 if (p == NULL) {
4938 return (1);
4939 }
4940 return (0);
4941 }
4942
4943 /*
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'
4948 */
4949 static void
4950 ext_read_input(char *buf)
4951 {
4952 (void) fgets(buf, 16, stdin);
4953 (void) fflush(stdin);
4954 }
4955
4956 /*
4957 * Procedure to read and validate the user option at the extended partition menu
4958 */
4959 static int
4960 ext_read_options(char *buf)
4961 {
4962 ext_read_input(buf);
4963 if ((strlen(buf) != 2) || (ext_invalid_option(buf[0]))) {
4964 (void) printf("\nUnknown Command\n");
4965 return (-1);
4966 }
4967 return (0);
4968 }
4969
4970 /*
4971 * Procedure to print the list of known partition types and their IDs
4972 */
4973 static void
4974 ext_print_part_types()
4975 {
4976 int i, rowmax, rowcount = 1;
4977 struct winsize ws;
4978 char buf[80];
4979
4980 /* Get the current window dimensions */
4981 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0) {
4982 perror("ioctl");
4983 rowmax = 20;
4984 } else {
4985 /*
4986 * Accommodate the initial headings by reducing the number of
4987 * partition IDs being printed.
4988 */
4989 rowmax = ws.ws_row - 5;
4990 }
4991
4992 if (rowmax < 3) {
4993 (void) fprintf(stderr, "Window size too small."
4994 " Try resizing the window\n");
4995 return;
4996 }
4997
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) {
5005 /*
5006 * After the initial screen, use all the rows for
5007 * printing the partition IDs, but one.
5008 */
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;
5015 }
5016 rowcount = 1;
5017 }
5018 }
5019 }
5020
5021 static void
5022 ext_read_valid_part_num(int *pno)
5023 {
5024 char buf[80];
5025 int len, i;
5026
5027 for (;;) {
5028 (void) printf("Enter the partition number : ");
5029 ext_read_input(buf);
5030
5031 len = strlen(buf);
5032
5033 /* Check length of the input */
5034 if ((len < 2) || (len > (FDISK_MAX_VALID_PART_NUM_DIGITS+1))) {
5035 goto print_error_and_continue;
5036 }
5037
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;
5042 }
5043 }
5044
5045 *pno = atoi(buf);
5046
5047 if ((*pno <= FD_NUMPART) ||
5048 *pno > (fdisk_get_logical_drive_count(epp) + FD_NUMPART)) {
5049 goto print_error_and_continue;
5050 }
5051
5052 break;
5053 print_error_and_continue:
5054 (void) printf("Invalid partition number\n");
5055 continue;
5056 }
5057 }
5058
5059 static void
5060 ext_read_valid_part_id(uchar_t *partid)
5061 {
5062 char buf[80];
5063 int len, i, id;
5064
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);
5070
5071 if ((len < 2) || (len > (FDISK_MAX_VALID_PART_ID_DIGITS + 1))) {
5072 (void) printf("Invalid partition ID\n");
5073 continue;
5074 }
5075
5076 if ((len == 2) && (toupper(buf[0]) == 'I')) {
5077 ext_print_part_types();
5078 continue;
5079 }
5080
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;
5086 }
5087 }
5088
5089 if (i < len - 1) {
5090 continue;
5091 }
5092
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;
5097 }
5098
5099 *partid = (uchar_t)id;
5100
5101 /* Disallow multiple extended partitions */
5102 if (fdisk_is_dos_extended(*partid)) {
5103 (void) printf("Multiple extended partitions not "
5104 "allowed\n");
5105 continue;
5106 }
5107
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;
5113 }
5114
5115 return; /* Valid partition ID is in partid */
5116 }
5117 }
5118
5119 static void
5120 delete_logical_drive()
5121 {
5122 int pno;
5123
5124 if (!fdisk_get_logical_drive_count(epp)) {
5125 (void) printf("\nNo logical drives defined.\n");
5126 return;
5127 }
5128
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);
5133 }
5134
5135 static int
5136 ext_read_valid_partition_start(uint32_t *begsec)
5137 {
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;
5143
5144 ret = fdisk_ext_find_first_free_sec(epp, &first_free_sec);
5145 if (ret != FDISK_SUCCESS) {
5146 return (ret);
5147 }
5148
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);
5158 }
5159
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;
5164 }
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;
5171 }
5172 }
5173 if (i < len - 1) {
5174 continue;
5175 }
5176
5177 begcyl = atoi(buf);
5178 ret = fdisk_ext_validate_part_start(epp, begcyl, begsec);
5179 switch (ret) {
5180 case FDISK_SUCCESS:
5181 /*
5182 * Success.
5183 * Valid beginning sector is in begsec
5184 */
5185 break;
5186
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;
5194
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;
5201 }
5202 return (FDISK_SUCCESS);
5203 }
5204 }
5205
5206 /*
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
5219 */
5220 static void
5221 ext_read_valid_partition_size(uint32_t begsec, uint32_t *endsec)
5222 {
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;
5232
5233 if (sectsize == EINVAL) {
5234 (void) fprintf(stderr, "Unsupported geometry statistics.\n");
5235 exit(1);
5236 }
5237
5238 last_free_sec = fdisk_ext_find_last_free_sec(epp, begsec);
5239 last_free_cyl = FDISK_SECT_TO_CYL(epp, last_free_sec);
5240
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);
5252
5253 if (len == 1) { /* User accepted the default value */
5254 *endsec = last_free_sec;
5255 return;
5256 }
5257
5258 copy_len = len - 1;
5259
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--;
5265 }
5266
5267 if (!((ch == 'K') || (ch == 'M') || (ch == 'G'))) {
5268 (void) printf("Invalid partition size\n");
5269 continue;
5270 }
5271
5272 copy_len--;
5273 mbgb = 1;
5274 scale = ((ch == 'K') ? FDISK_KB :
5275 ((ch == 'M') ? FDISK_MB : FDISK_GB));
5276 }
5277
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;
5282 }
5283
5284 (void) strncpy(numbuf, &buf[mbgb], copy_len);
5285 numbuf[copy_len] = '\0';
5286
5287 for (i = mbgb; i < copy_len + mbgb; i++) {
5288 if (!isdigit(buf[i])) {
5289 break;
5290 }
5291 }
5292
5293 if (i < copy_len + mbgb) {
5294 (void) printf("Invalid partition size\n");
5295 continue;
5296 }
5297
5298 size = (atoll(numbuf) * (scale));
5299
5300 if (size == 0) {
5301 (void) printf("Zero size is invalid\n");
5302 (void) printf("Invalid partition size\n");
5303 continue;
5304 }
5305
5306 if (mbgb) {
5307 size /= sectsize;
5308 }
5309
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;
5316 }
5317
5318 /*
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.
5322 */
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;
5327 }
5328 *endsec = (poss_end > last_free_sec) ? last_free_sec :
5329 poss_end;
5330
5331 return;
5332 }
5333 }
5334
5335 /*
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
5353 */
5354
5355 static void
5356 add_logical_drive()
5357 {
5358 uint32_t begsec, endsec;
5359 uchar_t partid;
5360 char buf[80];
5361 int rval;
5362
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;
5370 }
5371
5372 (void) printf("\n");
5373 rval = ext_read_valid_partition_start(&begsec);
5374 switch (rval) {
5375 case FDISK_SUCCESS:
5376 break;
5377
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;
5384 }
5385
5386 ext_read_valid_partition_size(begsec, &endsec);
5387 ext_read_valid_part_id(&partid);
5388 fdisk_add_logical_drive(epp, begsec, endsec, partid);
5389
5390 (void) printf("New partition with ID %d added\n", partid);
5391 }
5392
5393 static void
5394 ext_change_logical_drive_id()
5395 {
5396 int pno;
5397 uchar_t partid;
5398
5399 if (!fdisk_get_logical_drive_count(epp)) {
5400 (void) printf("\nNo logical drives defined.\n");
5401 return;
5402 }
5403
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);
5408
5409 (void) printf("Partition ID of partition %d changed to %d\n", pno,
5410 partid);
5411 }
5412
5413 #ifdef DEBUG
5414 static void
5415 ext_print_logdrive_layout_debug()
5416 {
5417 int pno;
5418 char namebuff[255];
5419 logical_drive_t *head = fdisk_get_ld_head(epp);
5420 logical_drive_t *temp;
5421
5422 if (!fdisk_get_logical_drive_count(epp)) {
5423 (void) printf("\nNo logical drives defined.\n");
5424 return;
5425 }
5426
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);
5440 /*
5441 * Print the second entry in the EBR which is information
5442 * about the location and the size of the next extended
5443 * partition.
5444 */
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);
5452 }
5453 }
5454 #endif
5455
5456 static void
5457 ext_print_logical_drive_layout()
5458 {
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;
5467
5468 if (numcyl == EINVAL) {
5469 (void) fprintf(stderr, "Unsupported geometry statistics.\n");
5470 exit(1);
5471 }
5472
5473 if (!fdisk_get_logical_drive_count(epp)) {
5474 (void) printf("\nNo logical drives defined.\n");
5475 return;
5476 }
5477
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;
5495 /*
5496 * Check if partition id 0x82 is Solaris
5497 * or a Linux swap. Print the string
5498 * accordingly.
5499 */
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);
5510 }
5511 startcyl = temp->begcyl;
5512 endcyl = temp->endcyl;
5513 if (startcyl == endcyl) {
5514 length = 1;
5515 } else {
5516 length = endcyl - startcyl + 1;
5517 }
5518 percent = length * 100 / numcyl;
5519 if ((remainder = (length * 100 % numcyl)) != 0) {
5520 if ((remainder * 100 / numcyl) > 50) {
5521 /* round up */
5522 percent++;
5523 }
5524 /* Else leave the percent as is since it's already */
5525 /* rounded down */
5526 }
5527 if (percent > 100) {
5528 percent = 100;
5529 }
5530 (void) printf("%-5d %-8u %-8u %-7u %-3d "
5531 "%-3d (%-.28s)\n",
5532 pno, startcyl, endcyl, length, percent, sysid, namebuff);
5533 }
5534 #ifdef DEBUG
5535 ext_print_logdrive_layout_debug();
5536 #endif
5537 (void) printf("\n");
5538 }
5539
5540 static void
5541 ext_print_help_menu()
5542 {
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");
5552 }
5553
5554 static void
5555 ext_part_menu()
5556 {
5557 char buf[80];
5558 uchar_t *bbsigp;
5559 static int bbsig_disp_flag = 1;
5560
5561 int i;
5562
5563 (void) printf(CLR_SCR);
5564
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");
5569 }
5570
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]);
5576 }
5577 (void) printf("\n\n");
5578 (void) printf("They will be corrected when you choose to "
5579 "commit\n");
5580 bbsig_disp_flag = 0;
5581 }
5582
5583 (void) printf("Extended partition menu\n");
5584
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;
5591 }
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;
5613 }
5614 }
5615 }
5616 #endif /* i386 */
5617
5618 static int
5619 nopartdefined()
5620 {
5621 int i;
5622
5623 for (i = 0; i < FD_NUMPART; i++)
5624 if (Table[i].systid != UNUSED)
5625 return (0);
5626 return (1);
5627 }
5628