1 /* vi: set sw=4 ts=4: */
2 /* fdisk.c -- Partition table manipulator for Linux.
4 * Copyright (C) 1992 A. V. Le Blanc (LeBlanc@mcc.ac.uk)
5 * Copyright (C) 2001,2002 Vladimir Oleynik <dzo@simtreas.ru> (initial bb port)
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
10 /* Looks like someone forgot to add this to config system */
11 //usage:#ifndef ENABLE_FEATURE_FDISK_BLKSIZE
12 //usage:# define ENABLE_FEATURE_FDISK_BLKSIZE 0
13 //usage:# define IF_FEATURE_FDISK_BLKSIZE(a)
16 //usage:#define fdisk_trivial_usage
17 //usage: "[-ul" IF_FEATURE_FDISK_BLKSIZE("s") "] "
18 //usage: "[-C CYLINDERS] [-H HEADS] [-S SECTORS] [-b SSZ] DISK"
19 //usage:#define fdisk_full_usage "\n\n"
20 //usage: "Change partition table\n"
21 //usage: "\n -u Start and End are in sectors (instead of cylinders)"
22 //usage: "\n -l Show partition table for each DISK, then exit"
23 //usage: IF_FEATURE_FDISK_BLKSIZE(
24 //usage: "\n -s Show partition sizes in kb for each DISK, then exit"
26 //usage: "\n -b 2048 (for certain MO disks) use 2048-byte sectors"
27 //usage: "\n -C CYLINDERS Set number of cylinders/heads/sectors"
28 //usage: "\n -H HEADS"
29 //usage: "\n -S SECTORS"
31 #ifndef _LARGEFILE64_SOURCE
33 # define _LARGEFILE64_SOURCE
35 #include <assert.h> /* assert */
36 #include <sys/mount.h>
37 #if !defined(BLKSSZGET)
38 # define BLKSSZGET _IO(0x12, 104)
40 #if !defined(BLKGETSIZE64)
41 # define BLKGETSIZE64 _IOR(0x12,114,size_t)
46 # define inline_if_little_endian ALWAYS_INLINE
48 # define inline_if_little_endian /* nothing */
52 /* Looks like someone forgot to add this to config system */
53 #ifndef ENABLE_FEATURE_FDISK_BLKSIZE
54 # define ENABLE_FEATURE_FDISK_BLKSIZE 0
55 # define IF_FEATURE_FDISK_BLKSIZE(a)
58 #define DEFAULT_SECTOR_SIZE 512
59 #define DEFAULT_SECTOR_SIZE_STR "512"
60 #define MAX_SECTOR_SIZE 2048
61 #define SECTOR_SIZE 512 /* still used in osf/sgi/sun code */
62 #define MAXIMUM_PARTS 60
64 #define ACTIVE_FLAG 0x80
67 #define WIN98_EXTENDED 0x0f
68 #define LINUX_PARTITION 0x81
69 #define LINUX_SWAP 0x82
70 #define LINUX_NATIVE 0x83
71 #define LINUX_EXTENDED 0x85
72 #define LINUX_LVM 0x8e
73 #define LINUX_RAID 0xfd
83 OPT_s
= (1 << 6) * ENABLE_FEATURE_FDISK_BLKSIZE
,
87 typedef unsigned long long ullong
;
88 /* Used for sector numbers. Partition formats we know
89 * do not support more than 2^32 sectors
91 typedef uint32_t sector_t
;
92 #if UINT_MAX == 4294967295
94 #elif ULONG_MAX == 4294967295
97 # error Cant detect sizeof(uint32_t)
102 unsigned char sectors
;
103 unsigned short cylinders
;
107 #define HDIO_GETGEO 0x0301 /* get device geometry */
109 static const char msg_building_new_label
[] ALIGN1
=
110 "Building a new %s. Changes will remain in memory only,\n"
111 "until you decide to write them. After that the previous content\n"
112 "won't be recoverable.\n\n";
114 static const char msg_part_already_defined
[] ALIGN1
=
115 "Partition %u is already defined, delete it before re-adding\n";
119 unsigned char boot_ind
; /* 0x80 - active */
120 unsigned char head
; /* starting head */
121 unsigned char sector
; /* starting sector */
122 unsigned char cyl
; /* starting cylinder */
123 unsigned char sys_ind
; /* what partition type */
124 unsigned char end_head
; /* end head */
125 unsigned char end_sector
; /* end sector */
126 unsigned char end_cyl
; /* end cylinder */
127 unsigned char start4
[4]; /* starting sector counting from 0 */
128 unsigned char size4
[4]; /* nr of sectors in partition */
132 * per partition table entry data
134 * The four primary partitions have the same sectorbuffer (MBRbuffer)
135 * and have NULL ext_pointer.
136 * Each logical partition table entry has two pointers, one for the
137 * partition and one link to the next one.
140 struct partition
*part_table
; /* points into sectorbuffer */
141 struct partition
*ext_pointer
; /* points into sectorbuffer */
142 sector_t offset_from_dev_start
; /* disk sector number */
143 char *sectorbuffer
; /* disk sector contents */
144 #if ENABLE_FEATURE_FDISK_WRITABLE
145 char changed
; /* boolean */
149 #define unable_to_open "can't open '%s'"
150 #define unable_to_read "can't read from %s"
151 #define unable_to_seek "can't seek on %s"
154 LABEL_DOS
, LABEL_SUN
, LABEL_SGI
, LABEL_AIX
, LABEL_OSF
, LABEL_GPT
157 #define LABEL_IS_DOS (LABEL_DOS == current_label_type)
159 #if ENABLE_FEATURE_SUN_LABEL
160 #define LABEL_IS_SUN (LABEL_SUN == current_label_type)
161 #define STATIC_SUN static
163 #define LABEL_IS_SUN 0
164 #define STATIC_SUN extern
167 #if ENABLE_FEATURE_SGI_LABEL
168 #define LABEL_IS_SGI (LABEL_SGI == current_label_type)
169 #define STATIC_SGI static
171 #define LABEL_IS_SGI 0
172 #define STATIC_SGI extern
175 #if ENABLE_FEATURE_AIX_LABEL
176 #define LABEL_IS_AIX (LABEL_AIX == current_label_type)
177 #define STATIC_AIX static
179 #define LABEL_IS_AIX 0
180 #define STATIC_AIX extern
183 #if ENABLE_FEATURE_OSF_LABEL
184 #define LABEL_IS_OSF (LABEL_OSF == current_label_type)
185 #define STATIC_OSF static
187 #define LABEL_IS_OSF 0
188 #define STATIC_OSF extern
191 #if ENABLE_FEATURE_GPT_LABEL
192 #define LABEL_IS_GPT (LABEL_GPT == current_label_type)
193 #define STATIC_GPT static
195 #define LABEL_IS_GPT 0
196 #define STATIC_GPT extern
199 enum action
{ OPEN_MAIN
, TRY_ONLY
, CREATE_EMPTY_DOS
, CREATE_EMPTY_SUN
};
201 static void update_units(void);
202 #if ENABLE_FEATURE_FDISK_WRITABLE
203 static void change_units(void);
204 static void reread_partition_table(int leave
);
205 static void delete_partition(int i
);
206 static unsigned get_partition(int warn
, unsigned max
);
207 static void list_types(const char *const *sys
);
208 static sector_t
read_int(sector_t low
, sector_t dflt
, sector_t high
, sector_t base
, const char *mesg
);
210 static const char *partition_type(unsigned char type
);
211 static void get_geometry(void);
212 static void read_pte(struct pte
*pe
, sector_t offset
);
213 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
214 static int get_boot(enum action what
);
216 static int get_boot(void);
222 static sector_t
get_start_sect(const struct partition
*p
);
223 static sector_t
get_nr_sects(const struct partition
*p
);
225 /* DOS partition types */
227 static const char *const i386_sys_types
[] = {
231 "\x05" "Extended", /* DOS 3.3+ extended partition */
232 "\x06" "FAT16", /* DOS 16-bit >=32M */
233 "\x07" "HPFS/NTFS", /* OS/2 IFS, eg, HPFS or NTFS or QNX */
234 "\x0a" "OS/2 Boot Manager",/* OS/2 Boot Manager */
235 "\x0b" "Win95 FAT32",
236 "\x0c" "Win95 FAT32 (LBA)",/* LBA really is 'Extended Int 13h' */
237 "\x0e" "Win95 FAT16 (LBA)",
238 "\x0f" "Win95 Ext'd (LBA)",
239 "\x11" "Hidden FAT12",
240 "\x12" "Compaq diagnostics",
241 "\x14" "Hidden FAT16 <32M",
242 "\x16" "Hidden FAT16",
243 "\x17" "Hidden HPFS/NTFS",
244 "\x1b" "Hidden Win95 FAT32",
245 "\x1c" "Hidden W95 FAT32 (LBA)",
246 "\x1e" "Hidden W95 FAT16 (LBA)",
247 "\x3c" "Part.Magic recovery",
248 "\x41" "PPC PReP Boot",
250 "\x63" "GNU HURD or SysV", /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
251 "\x80" "Old Minix", /* Minix 1.4a and earlier */
252 "\x81" "Minix / old Linux",/* Minix 1.4b and later */
253 "\x82" "Linux swap", /* also Solaris */
255 "\x84" "OS/2 hidden C: drive",
256 "\x85" "Linux extended",
257 "\x86" "NTFS volume set",
258 "\x87" "NTFS volume set",
260 "\x9f" "BSD/OS", /* BSDI */
261 "\xa0" "Thinkpad hibernation",
262 "\xa5" "FreeBSD", /* various BSD flavours */
266 "\xab" "Darwin boot",
269 "\xbe" "Solaris boot",
271 "\xee" "EFI GPT", /* Intel EFI GUID Partition Table */
272 "\xef" "EFI (FAT-12/16/32)", /* Intel EFI System Partition */
273 "\xf0" "Linux/PA-RISC boot", /* Linux/PA-RISC boot loader */
274 "\xf2" "DOS secondary", /* DOS 3.3+ secondary */
275 "\xfd" "Linux raid autodetect", /* New (2.2.x) raid partition with
276 autodetect using persistent
278 #if 0 /* ENABLE_WEIRD_PARTITION_TYPES */
281 "\x08" "AIX", /* AIX boot (AIX -- PS/2 port) or SplitDrive */
282 "\x09" "AIX bootable", /* AIX data or Coherent */
284 "\x18" "AST SmartSleep",
287 "\x40" "Venix 80286",
289 "\x4e" "QNX4.x 2nd part",
290 "\x4f" "QNX4.x 3rd part",
292 "\x51" "OnTrack DM6 Aux1", /* (or Novell) */
293 "\x52" "CP/M", /* CP/M or Microport SysV/AT */
294 "\x53" "OnTrack DM6 Aux3",
298 "\x5c" "Priam Edisk",
300 "\x64" "Novell Netware 286",
301 "\x65" "Novell Netware 386",
302 "\x70" "DiskSecure Multi-Boot",
305 "\x94" "Amoeba BBT", /* (bad block table) */
307 "\xbb" "Boot Wizard hidden",
308 "\xc1" "DRDOS/sec (FAT-12)",
309 "\xc4" "DRDOS/sec (FAT-16 < 32M)",
310 "\xc6" "DRDOS/sec (FAT-16)",
312 "\xda" "Non-FS data",
313 "\xdb" "CP/M / CTOS / ...",/* CP/M or Concurrent CP/M or
314 Concurrent DOS or CTOS */
315 "\xde" "Dell Utility", /* Dell PowerEdge Server utilities */
316 "\xdf" "BootIt", /* BootIt EMBRM */
317 "\xe1" "DOS access", /* DOS access or SpeedStor 12-bit FAT
318 extended partition */
319 "\xe3" "DOS R/O", /* DOS R/O or SpeedStor */
320 "\xe4" "SpeedStor", /* SpeedStor 16-bit FAT extended
321 partition < 1024 cyl. */
323 "\xf4" "SpeedStor", /* SpeedStor large partition */
324 "\xfe" "LANstep", /* SpeedStor >1024 cyl. or LANstep */
325 "\xff" "BBT", /* Xenix Bad Block Table */
331 dev_fd
= 3 /* the disk */
338 const char *disk_device
;
339 int g_partitions
; // = 4; /* maximum partition + 1 */
340 unsigned units_per_sector
; // = 1;
341 unsigned sector_size
; // = DEFAULT_SECTOR_SIZE;
342 unsigned user_set_sector_size
;
343 unsigned sector_offset
; // = 1;
344 unsigned g_heads
, g_sectors
, g_cylinders
;
345 smallint
/* enum label_type */ current_label_type
;
346 smallint display_in_cyl_units
; // = 1;
347 #if ENABLE_FEATURE_OSF_LABEL
348 smallint possibly_osf_label
;
351 smallint listing
; /* no aborts for fdisk -l */
352 smallint dos_compatible_flag
; // = 1;
353 #if ENABLE_FEATURE_FDISK_WRITABLE
355 smallint nowarn
; /* no warnings for fdisk -l/-s */
357 int ext_index
; /* the prime extended partition */
358 unsigned user_cylinders
, user_heads
, user_sectors
;
359 unsigned pt_heads
, pt_sectors
;
360 unsigned kern_heads
, kern_sectors
;
361 sector_t extended_offset
; /* offset of link pointers */
362 sector_t total_number_of_sectors
;
365 char line_buffer
[80];
366 char partname_buffer
[80];
367 /* Raw disk label. For DOS-type partition tables the MBR,
368 * with descriptions of the primary partitions. */
369 char MBRbuffer
[MAX_SECTOR_SIZE
];
370 /* Partition tables */
371 struct pte ptes
[MAXIMUM_PARTS
];
373 #define G (*ptr_to_globals)
374 #define line_ptr (G.line_ptr )
375 #define disk_device (G.disk_device )
376 #define g_partitions (G.g_partitions )
377 #define units_per_sector (G.units_per_sector )
378 #define sector_size (G.sector_size )
379 #define user_set_sector_size (G.user_set_sector_size)
380 #define sector_offset (G.sector_offset )
381 #define g_heads (G.g_heads )
382 #define g_sectors (G.g_sectors )
383 #define g_cylinders (G.g_cylinders )
384 #define current_label_type (G.current_label_type )
385 #define display_in_cyl_units (G.display_in_cyl_units)
386 #define possibly_osf_label (G.possibly_osf_label )
387 #define listing (G.listing )
388 #define dos_compatible_flag (G.dos_compatible_flag )
389 #define nowarn (G.nowarn )
390 #define ext_index (G.ext_index )
391 #define user_cylinders (G.user_cylinders )
392 #define user_heads (G.user_heads )
393 #define user_sectors (G.user_sectors )
394 #define pt_heads (G.pt_heads )
395 #define pt_sectors (G.pt_sectors )
396 #define kern_heads (G.kern_heads )
397 #define kern_sectors (G.kern_sectors )
398 #define extended_offset (G.extended_offset )
399 #define total_number_of_sectors (G.total_number_of_sectors)
400 #define listingbuf (G.listingbuf )
401 #define line_buffer (G.line_buffer )
402 #define partname_buffer (G.partname_buffer)
403 #define MBRbuffer (G.MBRbuffer )
404 #define ptes (G.ptes )
405 #define INIT_G() do { \
406 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
407 sector_size = DEFAULT_SECTOR_SIZE; \
410 display_in_cyl_units = 1; \
411 units_per_sector = 1; \
412 dos_compatible_flag = 1; \
416 /* TODO: move to libbb? */
417 /* TODO: return unsigned long long, FEATURE_FDISK_BLKSIZE _can_ handle
418 * disks > 2^32 sectors
420 static sector_t
bb_BLKGETSIZE_sectors(int fd
)
423 unsigned long longsectors
;
425 if (ioctl(fd
, BLKGETSIZE64
, &v64
) == 0) {
426 /* Got bytes, convert to sectors */
428 if (v64
!= (sector_t
)v64
) {
430 /* Not only DOS, but all other partition tables
431 * we support can't record more than 32 bit
432 * sector counts or offsets
434 bb_error_msg("device has more than 2^32 sectors, can't use all of them");
439 /* Needs temp of type long */
440 if (ioctl(fd
, BLKGETSIZE
, &longsectors
)) {
441 /* Perhaps this is a disk image */
442 off_t sz
= lseek(fd
, 0, SEEK_END
);
445 longsectors
= (uoff_t
)sz
/ sector_size
;
446 lseek(fd
, 0, SEEK_SET
);
448 if (sizeof(long) > sizeof(sector_t
)
449 && longsectors
!= (sector_t
)longsectors
457 #define IS_EXTENDED(i) \
458 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
460 #define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
462 #define scround(x) (((x)+units_per_sector-1)/units_per_sector)
464 #define pt_offset(b, n) \
465 ((struct partition *)((b) + 0x1be + (n) * sizeof(struct partition)))
467 #define sector(s) ((s) & 0x3f)
469 #define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
471 #define hsc2sector(h,s,c) \
472 (sector(s) - 1 + sectors * ((h) + heads * cylinder(s,c)))
477 /* Not really closing, but making sure it is open, and to harmless place */
478 xmove_fd(xopen(bb_dev_null
, O_RDONLY
), dev_fd
);
482 * Return partition name - uses static storage
485 partname(const char *dev
, int pno
, int lth
)
492 bufp
= partname_buffer
;
493 bufsiz
= sizeof(partname_buffer
);
498 if (isdigit(dev
[w
-1]))
501 /* devfs kludge - note: fdisk partition names are not supposed
502 to equal kernel names, so there is no reason to do this */
503 if (strcmp(dev
+ w
- 4, "disc") == 0) {
511 snprintf(bufp
, bufsiz
, "%*.*s%s%-2u",
512 lth
-wp
-2, w
, dev
, p
, pno
);
514 snprintf(bufp
, bufsiz
, "%.*s%s%-2u", w
, dev
, p
, pno
);
519 static ALWAYS_INLINE
struct partition
*
520 get_part_table(int i
)
522 return ptes
[i
].part_table
;
527 { /* n==1: use singular */
529 return display_in_cyl_units
? "cylinder" : "sector";
530 return display_in_cyl_units
? "cylinders" : "sectors";
534 valid_part_table_flag(const char *mbuffer
)
536 return (mbuffer
[510] == 0x55 && (uint8_t)mbuffer
[511] == 0xaa);
539 static void fdisk_fatal(const char *why
)
543 longjmp(listingbuf
, 1);
545 bb_error_msg_and_die(why
, disk_device
);
549 seek_sector(sector_t secno
)
551 #if ENABLE_FDISK_SUPPORT_LARGE_DISKS
552 off64_t off
= (off64_t
)secno
* sector_size
;
553 if (lseek64(dev_fd
, off
, SEEK_SET
) == (off64_t
) -1)
554 fdisk_fatal(unable_to_seek
);
556 uint64_t off
= (uint64_t)secno
* sector_size
;
557 if (off
> MAXINT(off_t
)
558 || lseek(dev_fd
, (off_t
)off
, SEEK_SET
) == (off_t
) -1
560 fdisk_fatal(unable_to_seek
);
565 #if ENABLE_FEATURE_FDISK_WRITABLE
566 /* Read line; return 0 or first printable char */
568 read_line(const char *prompt
)
572 sz
= read_line_input(NULL
, prompt
, line_buffer
, sizeof(line_buffer
), /*timeout*/ -1);
574 exit(EXIT_SUCCESS
); /* Ctrl-D or Ctrl-C */
576 if (line_buffer
[sz
-1] == '\n')
577 line_buffer
[--sz
] = '\0';
579 line_ptr
= line_buffer
;
580 while (*line_ptr
!= '\0' && (unsigned char)*line_ptr
<= ' ')
586 set_all_unchanged(void)
590 for (i
= 0; i
< MAXIMUM_PARTS
; i
++)
594 static ALWAYS_INLINE
void
600 static ALWAYS_INLINE
void
601 write_part_table_flag(char *b
)
608 read_nonempty(const char *mesg
)
610 while (!read_line(mesg
))
616 read_maybe_empty(const char *mesg
)
618 if (!read_line(mesg
)) {
619 line_ptr
= line_buffer
;
627 read_hex(const char *const *sys
)
631 read_nonempty("Hex code (type L to list codes): ");
632 if ((line_ptr
[0] | 0x20) == 'l') {
636 v
= bb_strtoul(line_ptr
, NULL
, 16);
643 write_sector(sector_t secno
, const void *buf
)
646 xwrite(dev_fd
, buf
, sector_size
);
648 #endif /* FEATURE_FDISK_WRITABLE */
651 #include "fdisk_aix.c"
653 struct sun_partition
{
654 unsigned char info
[128]; /* Informative text string */
655 unsigned char spare0
[14];
657 unsigned char spare1
;
659 unsigned char spare2
;
662 unsigned char spare1
[246]; /* Boot information etc. */
663 unsigned short rspeed
; /* Disk rotational speed */
664 unsigned short pcylcount
; /* Physical cylinder count */
665 unsigned short sparecyl
; /* extra sects per cylinder */
666 unsigned char spare2
[4]; /* More magic... */
667 unsigned short ilfact
; /* Interleave factor */
668 unsigned short ncyl
; /* Data cylinder count */
669 unsigned short nacyl
; /* Alt. cylinder count */
670 unsigned short ntrks
; /* Tracks per cylinder */
671 unsigned short nsect
; /* Sectors per track */
672 unsigned char spare3
[4]; /* Even more magic... */
673 struct sun_partinfo
{
674 uint32_t start_cylinder
;
675 uint32_t num_sectors
;
677 unsigned short magic
; /* Magic number */
678 unsigned short csum
; /* Label xor'd checksum */
680 typedef struct sun_partition sun_partition
;
681 #define sunlabel ((sun_partition *)MBRbuffer)
682 STATIC_OSF
void bsd_select(void);
683 STATIC_OSF
void xbsd_print_disklabel(int);
684 #include "fdisk_osf.c"
686 STATIC_GPT
void gpt_list_table(int xtra
);
687 #include "fdisk_gpt.c"
689 #if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL
691 fdisk_swap16(uint16_t x
)
693 return (x
<< 8) | (x
>> 8);
697 fdisk_swap32(uint32_t x
)
700 ((x
& 0xFF00) << 8) |
701 ((x
& 0xFF0000) >> 8) |
706 STATIC_SGI
const char *const sgi_sys_types
[];
707 STATIC_SGI
unsigned sgi_get_num_sectors(int i
);
708 STATIC_SGI
int sgi_get_sysid(int i
);
709 STATIC_SGI
void sgi_delete_partition(int i
);
710 STATIC_SGI
void sgi_change_sysid(int i
, int sys
);
711 STATIC_SGI
void sgi_list_table(int xtra
);
712 #if ENABLE_FEATURE_FDISK_ADVANCED
713 STATIC_SGI
void sgi_set_xcyl(void);
715 STATIC_SGI
int verify_sgi(int verbose
);
716 STATIC_SGI
void sgi_add_partition(int n
, int sys
);
717 STATIC_SGI
void sgi_set_swappartition(int i
);
718 STATIC_SGI
const char *sgi_get_bootfile(void);
719 STATIC_SGI
void sgi_set_bootfile(const char* aFile
);
720 STATIC_SGI
void create_sgiinfo(void);
721 STATIC_SGI
void sgi_write_table(void);
722 STATIC_SGI
void sgi_set_bootpartition(int i
);
723 #include "fdisk_sgi.c"
725 STATIC_SUN
const char *const sun_sys_types
[];
726 STATIC_SUN
void sun_delete_partition(int i
);
727 STATIC_SUN
void sun_change_sysid(int i
, int sys
);
728 STATIC_SUN
void sun_list_table(int xtra
);
729 STATIC_SUN
void add_sun_partition(int n
, int sys
);
730 #if ENABLE_FEATURE_FDISK_ADVANCED
731 STATIC_SUN
void sun_set_alt_cyl(void);
732 STATIC_SUN
void sun_set_ncyl(int cyl
);
733 STATIC_SUN
void sun_set_xcyl(void);
734 STATIC_SUN
void sun_set_ilfact(void);
735 STATIC_SUN
void sun_set_rspeed(void);
736 STATIC_SUN
void sun_set_pcylcount(void);
738 STATIC_SUN
void toggle_sunflags(int i
, unsigned char mask
);
739 STATIC_SUN
void verify_sun(void);
740 STATIC_SUN
void sun_write_table(void);
741 #include "fdisk_sun.c"
744 static inline_if_little_endian
unsigned
745 read4_little_endian(const unsigned char *cp
)
748 move_from_unaligned32(v
, cp
);
753 get_start_sect(const struct partition
*p
)
755 return read4_little_endian(p
->start4
);
759 get_nr_sects(const struct partition
*p
)
761 return read4_little_endian(p
->size4
);
764 #if ENABLE_FEATURE_FDISK_WRITABLE
765 /* start_sect and nr_sects are stored little endian on all machines */
766 /* moreover, they are not aligned correctly */
767 static inline_if_little_endian
void
768 store4_little_endian(unsigned char *cp
, unsigned val
)
770 uint32_t v
= SWAP_LE32(val
);
771 move_to_unaligned32(cp
, v
);
775 set_start_sect(struct partition
*p
, unsigned start_sect
)
777 store4_little_endian(p
->start4
, start_sect
);
781 set_nr_sects(struct partition
*p
, unsigned nr_sects
)
783 store4_little_endian(p
->size4
, nr_sects
);
787 /* Allocate a buffer and read a partition table sector */
789 read_pte(struct pte
*pe
, sector_t offset
)
791 pe
->offset_from_dev_start
= offset
;
792 pe
->sectorbuffer
= xzalloc(sector_size
);
794 /* xread would make us abort - bad for fdisk -l */
795 if (full_read(dev_fd
, pe
->sectorbuffer
, sector_size
) != sector_size
)
796 fdisk_fatal(unable_to_read
);
797 #if ENABLE_FEATURE_FDISK_WRITABLE
800 pe
->part_table
= pe
->ext_pointer
= NULL
;
804 get_partition_start_from_dev_start(const struct pte
*pe
)
806 return pe
->offset_from_dev_start
+ get_start_sect(pe
->part_table
);
809 #if ENABLE_FEATURE_FDISK_WRITABLE
811 * Avoid warning about DOS partitions when no DOS partition was changed.
812 * Here a heuristic "is probably dos partition".
813 * We might also do the opposite and warn in all cases except
814 * for "is probably nondos partition".
818 is_dos_partition(int t
)
820 return (t
== 1 || t
== 4 || t
== 6 ||
821 t
== 0x0b || t
== 0x0c || t
== 0x0e ||
822 t
== 0x11 || t
== 0x12 || t
== 0x14 || t
== 0x16 ||
823 t
== 0x1b || t
== 0x1c || t
== 0x1e || t
== 0x24 ||
824 t
== 0xc1 || t
== 0xc4 || t
== 0xc6);
831 puts("Command Action");
833 puts("a\ttoggle a read only flag"); /* sun */
834 puts("b\tedit bsd disklabel");
835 puts("c\ttoggle the mountable flag"); /* sun */
836 puts("d\tdelete a partition");
837 puts("l\tlist known partition types");
838 puts("n\tadd a new partition");
839 puts("o\tcreate a new empty DOS partition table");
840 puts("p\tprint the partition table");
841 puts("q\tquit without saving changes");
842 puts("s\tcreate a new empty Sun disklabel"); /* sun */
843 puts("t\tchange a partition's system id");
844 puts("u\tchange display/entry units");
845 puts("v\tverify the partition table");
846 puts("w\twrite table to disk and exit");
847 #if ENABLE_FEATURE_FDISK_ADVANCED
848 puts("x\textra functionality (experts only)");
850 } else if (LABEL_IS_SGI
) {
851 puts("a\tselect bootable partition"); /* sgi flavour */
852 puts("b\tedit bootfile entry"); /* sgi */
853 puts("c\tselect sgi swap partition"); /* sgi flavour */
854 puts("d\tdelete a partition");
855 puts("l\tlist known partition types");
856 puts("n\tadd a new partition");
857 puts("o\tcreate a new empty DOS partition table");
858 puts("p\tprint the partition table");
859 puts("q\tquit without saving changes");
860 puts("s\tcreate a new empty Sun disklabel"); /* sun */
861 puts("t\tchange a partition's system id");
862 puts("u\tchange display/entry units");
863 puts("v\tverify the partition table");
864 puts("w\twrite table to disk and exit");
865 } else if (LABEL_IS_AIX
) {
866 puts("o\tcreate a new empty DOS partition table");
867 puts("q\tquit without saving changes");
868 puts("s\tcreate a new empty Sun disklabel"); /* sun */
869 } else if (LABEL_IS_GPT
) {
870 puts("o\tcreate a new empty DOS partition table");
871 puts("p\tprint the partition table");
872 puts("q\tquit without saving changes");
873 puts("s\tcreate a new empty Sun disklabel"); /* sun */
875 puts("a\ttoggle a bootable flag");
876 puts("b\tedit bsd disklabel");
877 puts("c\ttoggle the dos compatibility flag");
878 puts("d\tdelete a partition");
879 puts("l\tlist known partition types");
880 puts("n\tadd a new partition");
881 puts("o\tcreate a new empty DOS partition table");
882 puts("p\tprint the partition table");
883 puts("q\tquit without saving changes");
884 puts("s\tcreate a new empty Sun disklabel"); /* sun */
885 puts("t\tchange a partition's system id");
886 puts("u\tchange display/entry units");
887 puts("v\tverify the partition table");
888 puts("w\twrite table to disk and exit");
889 #if ENABLE_FEATURE_FDISK_ADVANCED
890 puts("x\textra functionality (experts only)");
894 #endif /* FEATURE_FDISK_WRITABLE */
897 #if ENABLE_FEATURE_FDISK_ADVANCED
901 puts("Command Action");
903 puts("a\tchange number of alternate cylinders"); /*sun*/
904 puts("c\tchange number of cylinders");
905 puts("d\tprint the raw data in the partition table");
906 puts("e\tchange number of extra sectors per cylinder");/*sun*/
907 puts("h\tchange number of heads");
908 puts("i\tchange interleave factor"); /*sun*/
909 puts("o\tchange rotation speed (rpm)"); /*sun*/
910 puts("p\tprint the partition table");
911 puts("q\tquit without saving changes");
912 puts("r\treturn to main menu");
913 puts("s\tchange number of sectors/track");
914 puts("v\tverify the partition table");
915 puts("w\twrite table to disk and exit");
916 puts("y\tchange number of physical cylinders"); /*sun*/
917 } else if (LABEL_IS_SGI
) {
918 puts("b\tmove beginning of data in a partition"); /* !sun */
919 puts("c\tchange number of cylinders");
920 puts("d\tprint the raw data in the partition table");
921 puts("e\tlist extended partitions"); /* !sun */
922 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
923 puts("h\tchange number of heads");
924 puts("p\tprint the partition table");
925 puts("q\tquit without saving changes");
926 puts("r\treturn to main menu");
927 puts("s\tchange number of sectors/track");
928 puts("v\tverify the partition table");
929 puts("w\twrite table to disk and exit");
930 } else if (LABEL_IS_AIX
) {
931 puts("b\tmove beginning of data in a partition"); /* !sun */
932 puts("c\tchange number of cylinders");
933 puts("d\tprint the raw data in the partition table");
934 puts("e\tlist extended partitions"); /* !sun */
935 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
936 puts("h\tchange number of heads");
937 puts("p\tprint the partition table");
938 puts("q\tquit without saving changes");
939 puts("r\treturn to main menu");
940 puts("s\tchange number of sectors/track");
941 puts("v\tverify the partition table");
942 puts("w\twrite table to disk and exit");
944 puts("b\tmove beginning of data in a partition"); /* !sun */
945 puts("c\tchange number of cylinders");
946 puts("d\tprint the raw data in the partition table");
947 puts("e\tlist extended partitions"); /* !sun */
948 puts("f\tfix partition order"); /* !sun, !aix, !sgi */
949 #if ENABLE_FEATURE_SGI_LABEL
950 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
952 puts("h\tchange number of heads");
953 puts("p\tprint the partition table");
954 puts("q\tquit without saving changes");
955 puts("r\treturn to main menu");
956 puts("s\tchange number of sectors/track");
957 puts("v\tverify the partition table");
958 puts("w\twrite table to disk and exit");
961 #endif /* ADVANCED mode */
963 #if ENABLE_FEATURE_FDISK_WRITABLE
964 static const char *const *
968 LABEL_IS_SUN
? sun_sys_types
:
969 LABEL_IS_SGI
? sgi_sys_types
:
973 #define get_sys_types() i386_sys_types
977 partition_type(unsigned char type
)
980 const char *const *types
= get_sys_types();
982 for (i
= 0; types
[i
]; i
++)
983 if ((unsigned char)types
[i
][0] == type
)
990 is_cleared_partition(const struct partition
*p
)
992 /* We consider partition "cleared" only if it has only zeros */
993 const char *cp
= (const char *)p
;
994 int cnt
= sizeof(*p
);
1002 clear_partition(struct partition
*p
)
1005 memset(p
, 0, sizeof(*p
));
1008 #if ENABLE_FEATURE_FDISK_WRITABLE
1012 return LABEL_IS_SUN
? sunlabel
->infos
[i
].id
:
1013 (LABEL_IS_SGI
? sgi_get_sysid(i
) :
1014 ptes
[i
].part_table
->sys_ind
);
1018 list_types(const char *const *sys
)
1022 unsigned last
[COLS
];
1023 unsigned done
, next
, size
;
1026 for (size
= 0; sys
[size
]; size
++)
1030 for (i
= COLS
-1; i
>= 0; i
--) {
1031 done
+= (size
+ i
- done
) / (i
+ 1);
1032 last
[COLS
-1 - i
] = done
;
1035 i
= done
= next
= 0;
1037 printf("%c%2x %-22.22s", i
? ' ' : '\n',
1038 (unsigned char)sys
[next
][0],
1040 next
= last
[i
++] + done
;
1041 if (i
>= COLS
|| next
>= last
[i
]) {
1045 } while (done
< last
[0]);
1049 #define set_hsc(h, s, c, sector) do \
1051 s = sector % g_sectors + 1; \
1052 sector /= g_sectors; \
1053 h = sector % g_heads; \
1054 sector /= g_heads; \
1055 c = sector & 0xff; \
1056 s |= (sector >> 2) & 0xc0; \
1059 static void set_hsc_start_end(struct partition
*p
, sector_t start
, sector_t stop
)
1061 if (dos_compatible_flag
&& (start
/ (g_sectors
* g_heads
) > 1023))
1062 start
= g_heads
* g_sectors
* 1024 - 1;
1063 set_hsc(p
->head
, p
->sector
, p
->cyl
, start
);
1065 if (dos_compatible_flag
&& (stop
/ (g_sectors
* g_heads
) > 1023))
1066 stop
= g_heads
* g_sectors
* 1024 - 1;
1067 set_hsc(p
->end_head
, p
->end_sector
, p
->end_cyl
, stop
);
1071 set_partition(int i
, int doext
, sector_t start
, sector_t stop
, int sysid
)
1073 struct partition
*p
;
1077 p
= ptes
[i
].ext_pointer
;
1078 offset
= extended_offset
;
1080 p
= ptes
[i
].part_table
;
1081 offset
= ptes
[i
].offset_from_dev_start
;
1085 set_start_sect(p
, start
- offset
);
1086 set_nr_sects(p
, stop
- start
+ 1);
1087 set_hsc_start_end(p
, start
, stop
);
1088 ptes
[i
].changed
= 1;
1095 if (g_heads
&& g_sectors
&& g_cylinders
)
1098 printf("Unknown value(s) for:");
1104 printf(" cylinders");
1105 #if ENABLE_FEATURE_FDISK_WRITABLE
1106 puts(" (settable in the extra functions menu)");
1116 int cyl_units
= g_heads
* g_sectors
;
1118 if (display_in_cyl_units
&& cyl_units
)
1119 units_per_sector
= cyl_units
;
1121 units_per_sector
= 1; /* in sectors */
1124 #if ENABLE_FEATURE_FDISK_WRITABLE
1126 warn_cylinders(void)
1128 if (LABEL_IS_DOS
&& g_cylinders
> 1024 && !nowarn
)
1130 "The number of cylinders for this disk is set to %u.\n"
1131 "There is nothing wrong with that, but this is larger than 1024,\n"
1132 "and could in certain setups cause problems with:\n"
1133 "1) software that runs at boot time (e.g., old versions of LILO)\n"
1134 "2) booting and partitioning software from other OSs\n"
1135 " (e.g., DOS FDISK, OS/2 FDISK)\n",
1141 read_extended(int ext
)
1145 struct partition
*p
, *q
;
1149 pex
->ext_pointer
= pex
->part_table
;
1151 p
= pex
->part_table
;
1152 if (!get_start_sect(p
)) {
1153 puts("Bad offset in primary extended partition");
1157 while (IS_EXTENDED(p
->sys_ind
)) {
1158 struct pte
*pe
= &ptes
[g_partitions
];
1160 if (g_partitions
>= MAXIMUM_PARTS
) {
1161 /* This is not a Linux restriction, but
1162 this program uses arrays of size MAXIMUM_PARTS.
1163 Do not try to 'improve' this test. */
1164 struct pte
*pre
= &ptes
[g_partitions
- 1];
1165 #if ENABLE_FEATURE_FDISK_WRITABLE
1166 printf("Warning: deleting partitions after %u\n",
1170 clear_partition(pre
->ext_pointer
);
1174 read_pte(pe
, extended_offset
+ get_start_sect(p
));
1176 if (!extended_offset
)
1177 extended_offset
= get_start_sect(p
);
1179 q
= p
= pt_offset(pe
->sectorbuffer
, 0);
1180 for (i
= 0; i
< 4; i
++, p
++) if (get_nr_sects(p
)) {
1181 if (IS_EXTENDED(p
->sys_ind
)) {
1182 if (pe
->ext_pointer
)
1183 printf("Warning: extra link "
1184 "pointer in partition table"
1185 " %u\n", g_partitions
+ 1);
1187 pe
->ext_pointer
= p
;
1188 } else if (p
->sys_ind
) {
1190 printf("Warning: ignoring extra "
1191 "data in partition table"
1192 " %u\n", g_partitions
+ 1);
1198 /* very strange code here... */
1199 if (!pe
->part_table
) {
1200 if (q
!= pe
->ext_pointer
)
1203 pe
->part_table
= q
+ 1;
1205 if (!pe
->ext_pointer
) {
1206 if (q
!= pe
->part_table
)
1207 pe
->ext_pointer
= q
;
1209 pe
->ext_pointer
= q
+ 1;
1212 p
= pe
->ext_pointer
;
1216 #if ENABLE_FEATURE_FDISK_WRITABLE
1217 /* remove empty links */
1219 for (i
= 4; i
< g_partitions
; i
++) {
1220 struct pte
*pe
= &ptes
[i
];
1222 if (!get_nr_sects(pe
->part_table
)
1223 && (g_partitions
> 5 || ptes
[4].part_table
->sys_ind
)
1225 printf("Omitting empty partition (%u)\n", i
+1);
1226 delete_partition(i
);
1227 goto remove
; /* numbering changed */
1233 #if ENABLE_FEATURE_FDISK_WRITABLE
1235 create_doslabel(void)
1237 printf(msg_building_new_label
, "DOS disklabel");
1239 current_label_type
= LABEL_DOS
;
1240 #if ENABLE_FEATURE_OSF_LABEL
1241 possibly_osf_label
= 0;
1245 memset(&MBRbuffer
[510 - 4*16], 0, 4*16);
1246 write_part_table_flag(MBRbuffer
);
1247 extended_offset
= 0;
1248 set_all_unchanged();
1250 get_boot(CREATE_EMPTY_DOS
);
1255 get_sectorsize(void)
1257 if (!user_set_sector_size
) {
1259 if (ioctl(dev_fd
, BLKSSZGET
, &arg
) == 0)
1261 if (sector_size
!= DEFAULT_SECTOR_SIZE
)
1262 printf("Note: sector size is %u "
1263 "(not " DEFAULT_SECTOR_SIZE_STR
")\n",
1269 get_kernel_geometry(void)
1271 struct hd_geometry geometry
;
1273 if (!ioctl(dev_fd
, HDIO_GETGEO
, &geometry
)) {
1274 kern_heads
= geometry
.heads
;
1275 kern_sectors
= geometry
.sectors
;
1276 /* never use geometry.cylinders - it is truncated */
1281 get_partition_table_geometry(void)
1283 const unsigned char *bufp
= (const unsigned char *)MBRbuffer
;
1284 struct partition
*p
;
1285 int i
, h
, s
, hh
, ss
;
1289 if (!(valid_part_table_flag((char*)bufp
)))
1293 for (i
= 0; i
< 4; i
++) {
1294 p
= pt_offset(bufp
, i
);
1295 if (p
->sys_ind
!= 0) {
1296 h
= p
->end_head
+ 1;
1297 s
= (p
->end_sector
& 077);
1302 } else if (hh
!= h
|| ss
!= s
)
1307 if (!first
&& !bad
) {
1319 sec_fac
= sector_size
/ 512;
1320 #if ENABLE_FEATURE_SUN_LABEL
1321 guess_device_type();
1323 g_heads
= g_cylinders
= g_sectors
= 0;
1324 kern_heads
= kern_sectors
= 0;
1325 pt_heads
= pt_sectors
= 0;
1327 get_kernel_geometry();
1328 get_partition_table_geometry();
1330 g_heads
= user_heads
? user_heads
:
1331 pt_heads
? pt_heads
:
1332 kern_heads
? kern_heads
: 255;
1333 g_sectors
= user_sectors
? user_sectors
:
1334 pt_sectors
? pt_sectors
:
1335 kern_sectors
? kern_sectors
: 63;
1336 total_number_of_sectors
= bb_BLKGETSIZE_sectors(dev_fd
);
1339 if (dos_compatible_flag
)
1340 sector_offset
= g_sectors
;
1342 g_cylinders
= total_number_of_sectors
/ (g_heads
* g_sectors
* sec_fac
);
1344 g_cylinders
= user_cylinders
;
1348 * Opens disk_device and optionally reads MBR.
1349 * If what == OPEN_MAIN:
1350 * Open device, read MBR. Abort program on short read. Create empty
1351 * disklabel if the on-disk structure is invalid (WRITABLE mode).
1352 * If what == TRY_ONLY:
1353 * Open device, read MBR. Return an error if anything is out of place.
1354 * Do not create an empty disklabel. This is used for the "list"
1355 * operations: "fdisk -l /dev/sda" and "fdisk -l" (all devices).
1356 * If what == CREATE_EMPTY_*:
1357 * This means that get_boot() was called recursively from create_*label().
1358 * Do not re-open the device; just set up the ptes array and print
1359 * geometry warnings.
1362 * -1: no 0xaa55 flag present (possibly entire disk BSD)
1363 * 0: found or created label
1366 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
1367 static int get_boot(enum action what
)
1369 static int get_boot(void)
1370 #define get_boot(what) get_boot()
1376 for (i
= 0; i
< 4; i
++) {
1377 struct pte
*pe
= &ptes
[i
];
1378 pe
->part_table
= pt_offset(MBRbuffer
, i
);
1379 pe
->ext_pointer
= NULL
;
1380 pe
->offset_from_dev_start
= 0;
1381 pe
->sectorbuffer
= MBRbuffer
;
1382 #if ENABLE_FEATURE_FDISK_WRITABLE
1383 pe
->changed
= (what
== CREATE_EMPTY_DOS
);
1387 #if ENABLE_FEATURE_FDISK_WRITABLE
1388 // ALERT! highly idiotic design!
1389 // We end up here when we call get_boot() recursively
1390 // via get_boot() [table is bad] -> create_doslabel() -> get_boot(CREATE_EMPTY_DOS).
1391 // or get_boot() [table is bad] -> create_sunlabel() -> get_boot(CREATE_EMPTY_SUN).
1392 // (just factor out re-init of ptes[0,1,2,3] in a separate fn instead?)
1393 // So skip opening device _again_...
1394 if (what
== CREATE_EMPTY_DOS
IF_FEATURE_SUN_LABEL(|| what
== CREATE_EMPTY_SUN
))
1397 fd
= open(disk_device
, (option_mask32
& OPT_l
) ? O_RDONLY
: O_RDWR
);
1400 fd
= open(disk_device
, O_RDONLY
);
1402 if (what
== TRY_ONLY
)
1404 fdisk_fatal(unable_to_open
);
1406 printf("'%s' is opened for read only\n", disk_device
);
1408 xmove_fd(fd
, dev_fd
);
1409 if (512 != full_read(dev_fd
, MBRbuffer
, 512)) {
1410 if (what
== TRY_ONLY
) {
1414 fdisk_fatal(unable_to_read
);
1417 fd
= open(disk_device
, O_RDONLY
);
1420 if (512 != full_read(fd
, MBRbuffer
, 512)) {
1424 xmove_fd(fd
, dev_fd
);
1430 #if ENABLE_FEATURE_SUN_LABEL
1431 if (check_sun_label())
1434 #if ENABLE_FEATURE_SGI_LABEL
1435 if (check_sgi_label())
1438 #if ENABLE_FEATURE_AIX_LABEL
1439 if (check_aix_label())
1442 #if ENABLE_FEATURE_GPT_LABEL
1443 if (check_gpt_label())
1446 #if ENABLE_FEATURE_OSF_LABEL
1447 if (check_osf_label()) {
1448 possibly_osf_label
= 1;
1449 if (!valid_part_table_flag(MBRbuffer
)) {
1450 current_label_type
= LABEL_OSF
;
1453 puts("This disk has both DOS and BSD magic.\n"
1454 "Give the 'b' command to go to BSD mode.");
1458 #if !ENABLE_FEATURE_FDISK_WRITABLE
1459 if (!valid_part_table_flag(MBRbuffer
))
1462 if (!valid_part_table_flag(MBRbuffer
)) {
1463 if (what
== OPEN_MAIN
) {
1464 puts("Device contains neither a valid DOS "
1465 "partition table, nor Sun, SGI, OSF or GPT "
1468 IF_FEATURE_SUN_LABEL(create_sunlabel();)
1478 #endif /* FEATURE_FDISK_WRITABLE */
1481 IF_FEATURE_FDISK_WRITABLE(warn_cylinders();)
1484 for (i
= 0; i
< 4; i
++) {
1485 if (IS_EXTENDED(ptes
[i
].part_table
->sys_ind
)) {
1486 if (g_partitions
!= 4)
1487 printf("Ignoring extra extended "
1488 "partition %u\n", i
+ 1);
1494 for (i
= 3; i
< g_partitions
; i
++) {
1495 struct pte
*pe
= &ptes
[i
];
1496 if (!valid_part_table_flag(pe
->sectorbuffer
)) {
1497 printf("Warning: invalid flag 0x%02x,0x%02x of partition "
1498 "table %u will be corrected by w(rite)\n",
1499 pe
->sectorbuffer
[510],
1500 pe
->sectorbuffer
[511],
1502 IF_FEATURE_FDISK_WRITABLE(pe
->changed
= 1;)
1509 #if ENABLE_FEATURE_FDISK_WRITABLE
1511 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
1512 * If the user hits Enter, DFLT is returned.
1513 * Answers like +10 are interpreted as offsets from BASE.
1515 * There is no default if DFLT is not between LOW and HIGH.
1518 read_int(sector_t low
, sector_t dflt
, sector_t high
, sector_t base
, const char *mesg
)
1522 const char *fmt
= "%s (%u-%u, default %u): ";
1524 if (dflt
< low
|| dflt
> high
) {
1525 fmt
= "%s (%u-%u): ";
1530 int use_default
= default_ok
;
1532 /* ask question and read answer */
1534 printf(fmt
, mesg
, low
, high
, dflt
);
1535 read_maybe_empty("");
1536 } while (*line_ptr
!= '\n' && !isdigit(*line_ptr
)
1537 && *line_ptr
!= '-' && *line_ptr
!= '+');
1539 if (*line_ptr
== '+' || *line_ptr
== '-') {
1540 int minus
= (*line_ptr
== '-');
1543 value
= atoi(line_ptr
+ 1);
1545 /* (1) if 2nd char is digit, use_default = 0.
1546 * (2) move line_ptr to first non-digit. */
1547 while (isdigit(*++line_ptr
))
1550 switch (*line_ptr
) {
1553 if (!display_in_cyl_units
)
1554 value
*= g_heads
* g_sectors
;
1568 absolute
= 1000000000;
1577 bytes
= (ullong
) value
* absolute
;
1578 unit
= sector_size
* units_per_sector
;
1579 bytes
+= unit
/2; /* round */
1587 value
= atoi(line_ptr
);
1588 while (isdigit(*line_ptr
)) {
1595 printf("Using default value %u\n", value
);
1597 if (value
>= low
&& value
<= high
)
1599 puts("Value is out of range");
1605 get_partition(int warn
, unsigned max
)
1610 i
= read_int(1, 0, max
, 0, "Partition number") - 1;
1614 if ((!LABEL_IS_SUN
&& !LABEL_IS_SGI
&& !pe
->part_table
->sys_ind
)
1615 || (LABEL_IS_SUN
&& (!sunlabel
->partitions
[i
].num_sectors
|| !sunlabel
->infos
[i
].id
))
1616 || (LABEL_IS_SGI
&& !sgi_get_num_sectors(i
))
1618 printf("Warning: partition %u has empty type\n", i
+1);
1625 get_existing_partition(int warn
, unsigned max
)
1630 for (i
= 0; i
< max
; i
++) {
1631 struct pte
*pe
= &ptes
[i
];
1632 struct partition
*p
= pe
->part_table
;
1634 if (p
&& !is_cleared_partition(p
)) {
1641 printf("Selected partition %u\n", pno
+1);
1644 puts("No partition is defined yet!");
1648 return get_partition(warn
, max
);
1652 get_nonexisting_partition(int warn
, unsigned max
)
1657 for (i
= 0; i
< max
; i
++) {
1658 struct pte
*pe
= &ptes
[i
];
1659 struct partition
*p
= pe
->part_table
;
1661 if (p
&& is_cleared_partition(p
)) {
1668 printf("Selected partition %u\n", pno
+1);
1671 puts("All primary partitions have been defined already!");
1675 return get_partition(warn
, max
);
1682 display_in_cyl_units
= !display_in_cyl_units
;
1684 printf("Changing display/entry units to %s\n",
1689 toggle_active(int i
)
1691 struct pte
*pe
= &ptes
[i
];
1692 struct partition
*p
= pe
->part_table
;
1694 if (IS_EXTENDED(p
->sys_ind
) && !p
->boot_ind
)
1695 printf("WARNING: Partition %u is an extended partition\n", i
+ 1);
1696 p
->boot_ind
= (p
->boot_ind
? 0 : ACTIVE_FLAG
);
1701 toggle_dos_compatibility_flag(void)
1703 dos_compatible_flag
= 1 - dos_compatible_flag
;
1704 if (dos_compatible_flag
) {
1705 sector_offset
= g_sectors
;
1706 printf("DOS Compatibility flag is %sset\n", "");
1709 printf("DOS Compatibility flag is %sset\n", "not ");
1714 delete_partition(int i
)
1716 struct pte
*pe
= &ptes
[i
];
1717 struct partition
*p
= pe
->part_table
;
1718 struct partition
*q
= pe
->ext_pointer
;
1720 /* Note that for the fifth partition (i == 4) we don't actually
1721 * decrement partitions.
1724 if (warn_geometry())
1725 return; /* C/H/S not set */
1729 sun_delete_partition(i
);
1733 sgi_delete_partition(i
);
1738 if (IS_EXTENDED(p
->sys_ind
) && i
== ext_index
) {
1740 ptes
[ext_index
].ext_pointer
= NULL
;
1741 extended_offset
= 0;
1747 if (!q
->sys_ind
&& i
> 4) {
1748 /* the last one in the chain - just delete */
1751 clear_partition(ptes
[i
].ext_pointer
);
1752 ptes
[i
].changed
= 1;
1754 /* not the last one - further ones will be moved down */
1756 /* delete this link in the chain */
1757 p
= ptes
[i
-1].ext_pointer
;
1759 set_start_sect(p
, get_start_sect(q
));
1760 set_nr_sects(p
, get_nr_sects(q
));
1761 ptes
[i
-1].changed
= 1;
1762 } else if (g_partitions
> 5) { /* 5 will be moved to 4 */
1763 /* the first logical in a longer chain */
1766 if (pe
->part_table
) /* prevent SEGFAULT */
1767 set_start_sect(pe
->part_table
,
1768 get_partition_start_from_dev_start(pe
) -
1770 pe
->offset_from_dev_start
= extended_offset
;
1774 if (g_partitions
> 5) {
1776 while (i
< g_partitions
) {
1777 ptes
[i
] = ptes
[i
+1];
1781 /* the only logical: clear only */
1782 clear_partition(ptes
[i
].part_table
);
1790 int i
, sys
, origsys
;
1791 struct partition
*p
;
1793 /* If sgi_label then don't use get_existing_partition,
1794 let the user select a partition, since get_existing_partition()
1795 only works for Linux like partition tables. */
1796 if (!LABEL_IS_SGI
) {
1797 i
= get_existing_partition(0, g_partitions
);
1799 i
= get_partition(0, g_partitions
);
1803 p
= ptes
[i
].part_table
;
1804 origsys
= sys
= get_sysid(i
);
1806 /* if changing types T to 0 is allowed, then
1807 the reverse change must be allowed, too */
1808 if (!sys
&& !LABEL_IS_SGI
&& !LABEL_IS_SUN
&& !get_nr_sects(p
)) {
1809 printf("Partition %u does not exist yet!\n", i
+ 1);
1813 sys
= read_hex(get_sys_types());
1815 if (!sys
&& !LABEL_IS_SGI
&& !LABEL_IS_SUN
) {
1816 puts("Type 0 means free space to many systems\n"
1817 "(but not to Linux). Having partitions of\n"
1818 "type 0 is probably unwise.");
1822 if (!LABEL_IS_SUN
&& !LABEL_IS_SGI
) {
1823 if (IS_EXTENDED(sys
) != IS_EXTENDED(p
->sys_ind
)) {
1824 puts("You cannot change a partition into"
1825 " an extended one or vice versa");
1831 #if ENABLE_FEATURE_SUN_LABEL
1832 if (LABEL_IS_SUN
&& i
== 2 && sys
!= SUN_WHOLE_DISK
)
1833 puts("Consider leaving partition 3 "
1834 "as Whole disk (5),\n"
1835 "as SunOS/Solaris expects it and "
1836 "even Linux likes it\n");
1838 #if ENABLE_FEATURE_SGI_LABEL
1841 (i
== 10 && sys
!= SGI_ENTIRE_DISK
) ||
1842 (i
== 8 && sys
!= 0)
1845 puts("Consider leaving partition 9 "
1846 "as volume header (0),\nand "
1847 "partition 11 as entire volume (6)"
1848 "as IRIX expects it\n");
1854 sun_change_sysid(i
, sys
);
1855 } else if (LABEL_IS_SGI
) {
1856 sgi_change_sysid(i
, sys
);
1860 printf("Changed system type of partition %u "
1861 "to %x (%s)\n", i
+ 1, sys
,
1862 partition_type(sys
));
1863 ptes
[i
].changed
= 1;
1864 //if (is_dos_partition(origsys) || is_dos_partition(sys))
1870 #endif /* FEATURE_FDISK_WRITABLE */
1873 /* check_consistency() and linear2chs() added Sat Mar 6 12:28:16 1993,
1874 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
1875 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
1876 * Lubkin Oct. 1991). */
1879 linear2chs(unsigned ls
, unsigned *c
, unsigned *h
, unsigned *s
)
1881 int spc
= g_heads
* g_sectors
;
1885 *h
= ls
/ g_sectors
;
1886 *s
= ls
% g_sectors
+ 1; /* sectors count from 1 */
1890 check_consistency(const struct partition
*p
, int partition
)
1892 unsigned pbc
, pbh
, pbs
; /* physical beginning c, h, s */
1893 unsigned pec
, peh
, pes
; /* physical ending c, h, s */
1894 unsigned lbc
, lbh
, lbs
; /* logical beginning c, h, s */
1895 unsigned lec
, leh
, les
; /* logical ending c, h, s */
1897 if (!g_heads
|| !g_sectors
|| (partition
>= 4))
1898 return; /* do not check extended partitions */
1900 /* physical beginning c, h, s */
1901 pbc
= (p
->cyl
& 0xff) | ((p
->sector
<< 2) & 0x300);
1903 pbs
= p
->sector
& 0x3f;
1905 /* physical ending c, h, s */
1906 pec
= (p
->end_cyl
& 0xff) | ((p
->end_sector
<< 2) & 0x300);
1908 pes
= p
->end_sector
& 0x3f;
1910 /* compute logical beginning (c, h, s) */
1911 linear2chs(get_start_sect(p
), &lbc
, &lbh
, &lbs
);
1913 /* compute logical ending (c, h, s) */
1914 linear2chs(get_start_sect(p
) + get_nr_sects(p
) - 1, &lec
, &leh
, &les
);
1916 /* Same physical / logical beginning? */
1917 if (g_cylinders
<= 1024 && (pbc
!= lbc
|| pbh
!= lbh
|| pbs
!= lbs
)) {
1918 printf("Partition %u has different physical/logical "
1919 "beginnings (non-Linux?):\n", partition
+ 1);
1920 printf(" phys=(%u, %u, %u) ", pbc
, pbh
, pbs
);
1921 printf("logical=(%u, %u, %u)\n", lbc
, lbh
, lbs
);
1924 /* Same physical / logical ending? */
1925 if (g_cylinders
<= 1024 && (pec
!= lec
|| peh
!= leh
|| pes
!= les
)) {
1926 printf("Partition %u has different physical/logical "
1927 "endings:\n", partition
+ 1);
1928 printf(" phys=(%u, %u, %u) ", pec
, peh
, pes
);
1929 printf("logical=(%u, %u, %u)\n", lec
, leh
, les
);
1932 /* Ending on cylinder boundary? */
1933 if (peh
!= (g_heads
- 1) || pes
!= g_sectors
) {
1934 printf("Partition %u does not end on cylinder boundary\n",
1940 list_disk_geometry(void)
1942 ullong bytes
= ((ullong
)total_number_of_sectors
* sector_size
);
1943 long megabytes
= bytes
/ 1000000;
1945 if (megabytes
< 10000)
1946 printf("\nDisk %s: %lu MB, %llu bytes\n",
1947 disk_device
, megabytes
, bytes
);
1949 printf("\nDisk %s: %lu.%lu GB, %llu bytes\n",
1950 disk_device
, megabytes
/1000, (megabytes
/100)%10, bytes
);
1951 printf("%u heads, %u sectors/track, %u cylinders",
1952 g_heads
, g_sectors
, g_cylinders
);
1953 if (units_per_sector
== 1)
1954 printf(", total %"SECT_FMT
"u sectors",
1955 total_number_of_sectors
);
1956 printf("\nUnits = %s of %u * %u = %u bytes\n\n",
1958 units_per_sector
, sector_size
, units_per_sector
* sector_size
);
1962 * Check whether partition entries are ordered by their starting positions.
1963 * Return 0 if OK. Return i if partition i should have been earlier.
1964 * Two separate checks: primary and logical partitions.
1967 wrong_p_order(int *prev
)
1969 const struct pte
*pe
;
1970 const struct partition
*p
;
1971 sector_t last_p_start_pos
= 0, p_start_pos
;
1972 unsigned i
, last_i
= 0;
1974 for (i
= 0; i
< g_partitions
; i
++) {
1977 last_p_start_pos
= 0;
1982 p_start_pos
= get_partition_start_from_dev_start(pe
);
1984 if (last_p_start_pos
> p_start_pos
) {
1990 last_p_start_pos
= p_start_pos
;
1997 #if ENABLE_FEATURE_FDISK_ADVANCED
1999 * Fix the chain of logicals.
2000 * extended_offset is unchanged, the set of sectors used is unchanged
2001 * The chain is sorted so that sectors increase, and so that
2002 * starting sectors increase.
2004 * After this it may still be that cfdisk doesnt like the table.
2005 * (This is because cfdisk considers expanded parts, from link to
2006 * end of partition, and these may still overlap.)
2008 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
2012 fix_chain_of_logicals(void)
2014 int j
, oj
, ojj
, sj
, sjj
;
2015 struct partition
*pj
,*pjj
,tmp
;
2017 /* Stage 1: sort sectors but leave sector of part 4 */
2018 /* (Its sector is the global extended_offset.) */
2020 for (j
= 5; j
< g_partitions
- 1; j
++) {
2021 oj
= ptes
[j
].offset_from_dev_start
;
2022 ojj
= ptes
[j
+1].offset_from_dev_start
;
2024 ptes
[j
].offset_from_dev_start
= ojj
;
2025 ptes
[j
+1].offset_from_dev_start
= oj
;
2026 pj
= ptes
[j
].part_table
;
2027 set_start_sect(pj
, get_start_sect(pj
)+oj
-ojj
);
2028 pjj
= ptes
[j
+1].part_table
;
2029 set_start_sect(pjj
, get_start_sect(pjj
)+ojj
-oj
);
2030 set_start_sect(ptes
[j
-1].ext_pointer
,
2031 ojj
-extended_offset
);
2032 set_start_sect(ptes
[j
].ext_pointer
,
2033 oj
-extended_offset
);
2038 /* Stage 2: sort starting sectors */
2040 for (j
= 4; j
< g_partitions
- 1; j
++) {
2041 pj
= ptes
[j
].part_table
;
2042 pjj
= ptes
[j
+1].part_table
;
2043 sj
= get_start_sect(pj
);
2044 sjj
= get_start_sect(pjj
);
2045 oj
= ptes
[j
].offset_from_dev_start
;
2046 ojj
= ptes
[j
+1].offset_from_dev_start
;
2047 if (oj
+sj
> ojj
+sjj
) {
2051 set_start_sect(pj
, ojj
+sjj
-oj
);
2052 set_start_sect(pjj
, oj
+sj
-ojj
);
2057 /* Probably something was changed */
2058 for (j
= 4; j
< g_partitions
; j
++)
2059 ptes
[j
].changed
= 1;
2064 fix_partition_table_order(void)
2066 struct pte
*pei
, *pek
;
2069 if (!wrong_p_order(NULL
)) {
2070 puts("Ordering is already correct\n");
2074 while ((i
= wrong_p_order(&k
)) != 0 && i
< 4) {
2075 /* partition i should have come earlier, move it */
2076 /* We have to move data in the MBR */
2077 struct partition
*pi
, *pk
, *pe
, pbuf
;
2081 pe
= pei
->ext_pointer
;
2082 pei
->ext_pointer
= pek
->ext_pointer
;
2083 pek
->ext_pointer
= pe
;
2085 pi
= pei
->part_table
;
2086 pk
= pek
->part_table
;
2088 memmove(&pbuf
, pi
, sizeof(struct partition
));
2089 memmove(pi
, pk
, sizeof(struct partition
));
2090 memmove(pk
, &pbuf
, sizeof(struct partition
));
2092 pei
->changed
= pek
->changed
= 1;
2096 fix_chain_of_logicals();
2103 list_table(int xtra
)
2105 const struct partition
*p
;
2109 sun_list_table(xtra
);
2113 sgi_list_table(xtra
);
2117 gpt_list_table(xtra
);
2121 list_disk_geometry();
2124 xbsd_print_disklabel(xtra
);
2128 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
2129 but if the device name ends in a digit, say /dev/foo1,
2130 then the partition is called /dev/foo1p3. */
2131 w
= strlen(disk_device
);
2132 if (w
&& isdigit(disk_device
[w
-1]))
2137 // 1 12345678901 12345678901 12345678901 12
2138 printf("%*s Boot Start End Blocks Id System\n",
2141 for (i
= 0; i
< g_partitions
; i
++) {
2142 const struct pte
*pe
= &ptes
[i
];
2148 if (!p
|| is_cleared_partition(p
))
2151 psects
= get_nr_sects(p
);
2155 if (sector_size
< 1024) {
2156 pblocks
/= (1024 / sector_size
);
2157 podd
= psects
% (1024 / sector_size
);
2159 if (sector_size
> 1024)
2160 pblocks
*= (sector_size
/ 1024);
2162 printf("%s %c %11"SECT_FMT
"u %11"SECT_FMT
"u %11"SECT_FMT
"u%c %2x %s\n",
2163 partname(disk_device
, i
+1, w
+2),
2164 !p
->boot_ind
? ' ' : p
->boot_ind
== ACTIVE_FLAG
/* boot flag */
2166 cround(get_partition_start_from_dev_start(pe
)), /* start */
2167 cround(get_partition_start_from_dev_start(pe
) + psects
/* end */
2168 - (psects
? 1 : 0)),
2169 pblocks
, podd
? '+' : ' ', /* odd flag on end */
2170 p
->sys_ind
, /* type id */
2171 partition_type(p
->sys_ind
)); /* type name */
2173 check_consistency(p
, i
);
2176 /* Is partition table in disk order? It need not be, but... */
2177 /* partition table entries are not checked for correct order
2178 * if this is a sgi, sun or aix labeled disk... */
2179 if (LABEL_IS_DOS
&& wrong_p_order(NULL
)) {
2181 puts("\nPartition table entries are not in disk order");
2185 #if ENABLE_FEATURE_FDISK_ADVANCED
2187 x_list_table(int extend
)
2189 const struct pte
*pe
;
2190 const struct partition
*p
;
2193 printf("\nDisk %s: %u heads, %u sectors, %u cylinders\n\n",
2194 disk_device
, g_heads
, g_sectors
, g_cylinders
);
2195 puts("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID");
2196 for (i
= 0; i
< g_partitions
; i
++) {
2198 p
= (extend
? pe
->ext_pointer
: pe
->part_table
);
2200 printf("%2u %02x%4u%4u%5u%4u%4u%5u%11"SECT_FMT
"u%11"SECT_FMT
"u %02x\n",
2201 i
+ 1, p
->boot_ind
, p
->head
,
2203 cylinder(p
->sector
, p
->cyl
), p
->end_head
,
2204 sector(p
->end_sector
),
2205 cylinder(p
->end_sector
, p
->end_cyl
),
2206 get_start_sect(p
), get_nr_sects(p
),
2209 check_consistency(p
, i
);
2215 #if ENABLE_FEATURE_FDISK_WRITABLE
2217 fill_bounds(sector_t
*first
, sector_t
*last
)
2220 const struct pte
*pe
= &ptes
[0];
2221 const struct partition
*p
;
2223 for (i
= 0; i
< g_partitions
; pe
++,i
++) {
2225 if (!p
->sys_ind
|| IS_EXTENDED(p
->sys_ind
)) {
2226 first
[i
] = 0xffffffff;
2229 first
[i
] = get_partition_start_from_dev_start(pe
);
2230 last
[i
] = first
[i
] + get_nr_sects(p
) - 1;
2236 check(int n
, unsigned h
, unsigned s
, unsigned c
, sector_t start
)
2238 sector_t total
, real_s
, real_c
;
2240 real_s
= sector(s
) - 1;
2241 real_c
= cylinder(s
, c
);
2242 total
= (real_c
* g_sectors
+ real_s
) * g_heads
+ h
;
2244 printf("Partition %u contains sector 0\n", n
);
2246 printf("Partition %u: head %u greater than maximum %u\n",
2248 if (real_s
>= g_sectors
)
2249 printf("Partition %u: sector %u greater than "
2250 "maximum %u\n", n
, s
, g_sectors
);
2251 if (real_c
>= g_cylinders
)
2252 printf("Partition %u: cylinder %"SECT_FMT
"u greater than "
2253 "maximum %u\n", n
, real_c
+ 1, g_cylinders
);
2254 if (g_cylinders
<= 1024 && start
!= total
)
2255 printf("Partition %u: previous sectors %"SECT_FMT
"u disagrees with "
2256 "total %"SECT_FMT
"u\n", n
, start
, total
);
2264 sector_t first
[g_partitions
], last
[g_partitions
];
2265 struct partition
*p
;
2267 if (warn_geometry())
2279 fill_bounds(first
, last
);
2280 for (i
= 0; i
< g_partitions
; i
++) {
2281 struct pte
*pe
= &ptes
[i
];
2284 if (p
->sys_ind
&& !IS_EXTENDED(p
->sys_ind
)) {
2285 check_consistency(p
, i
);
2286 if (get_partition_start_from_dev_start(pe
) < first
[i
])
2287 printf("Warning: bad start-of-data in "
2288 "partition %u\n", i
+ 1);
2289 check(i
+ 1, p
->end_head
, p
->end_sector
, p
->end_cyl
,
2291 total
+= last
[i
] + 1 - first
[i
];
2292 for (j
= 0; j
< i
; j
++) {
2293 if ((first
[i
] >= first
[j
] && first
[i
] <= last
[j
])
2294 || ((last
[i
] <= last
[j
] && last
[i
] >= first
[j
]))) {
2295 printf("Warning: partition %u overlaps "
2296 "partition %u\n", j
+ 1, i
+ 1);
2297 total
+= first
[i
] >= first
[j
] ?
2298 first
[i
] : first
[j
];
2299 total
-= last
[i
] <= last
[j
] ?
2306 if (extended_offset
) {
2307 struct pte
*pex
= &ptes
[ext_index
];
2308 sector_t e_last
= get_start_sect(pex
->part_table
) +
2309 get_nr_sects(pex
->part_table
) - 1;
2311 for (i
= 4; i
< g_partitions
; i
++) {
2313 p
= ptes
[i
].part_table
;
2315 if (i
!= 4 || i
+ 1 < g_partitions
)
2316 printf("Warning: partition %u "
2317 "is empty\n", i
+ 1);
2318 } else if (first
[i
] < extended_offset
|| last
[i
] > e_last
) {
2319 printf("Logical partition %u not entirely in "
2320 "partition %u\n", i
+ 1, ext_index
+ 1);
2325 if (total
> g_heads
* g_sectors
* g_cylinders
)
2326 printf("Total allocated sectors %u greater than the maximum "
2327 "%u\n", total
, g_heads
* g_sectors
* g_cylinders
);
2329 total
= g_heads
* g_sectors
* g_cylinders
- total
;
2331 printf("%"SECT_FMT
"u unallocated sectors\n", total
);
2336 add_partition(int n
, int sys
)
2338 char mesg
[256]; /* 48 does not suffice in Japanese */
2339 int i
, num_read
= 0;
2340 struct partition
*p
= ptes
[n
].part_table
;
2341 struct partition
*q
= ptes
[ext_index
].part_table
;
2342 sector_t limit
, temp
;
2343 sector_t start
, stop
= 0;
2344 sector_t first
[g_partitions
], last
[g_partitions
];
2346 if (p
&& p
->sys_ind
) {
2347 printf(msg_part_already_defined
, n
+ 1);
2350 fill_bounds(first
, last
);
2352 start
= sector_offset
;
2353 if (display_in_cyl_units
|| !total_number_of_sectors
)
2354 limit
= (sector_t
) g_heads
* g_sectors
* g_cylinders
- 1;
2356 limit
= total_number_of_sectors
- 1;
2357 if (extended_offset
) {
2358 first
[ext_index
] = extended_offset
;
2359 last
[ext_index
] = get_start_sect(q
) +
2360 get_nr_sects(q
) - 1;
2363 start
= extended_offset
+ sector_offset
;
2364 limit
= get_start_sect(q
) + get_nr_sects(q
) - 1;
2366 if (display_in_cyl_units
)
2367 for (i
= 0; i
< g_partitions
; i
++)
2368 first
[i
] = (cround(first
[i
]) - 1) * units_per_sector
;
2370 snprintf(mesg
, sizeof(mesg
), "First %s", str_units(SINGULAR
));
2373 for (i
= 0; i
< g_partitions
; i
++) {
2376 if (start
== ptes
[i
].offset_from_dev_start
)
2377 start
+= sector_offset
;
2378 lastplusoff
= last
[i
] + ((n
< 4) ? 0 : sector_offset
);
2379 if (start
>= first
[i
] && start
<= lastplusoff
)
2380 start
= lastplusoff
+ 1;
2384 if (start
>= temp
+units_per_sector
&& num_read
) {
2385 printf("Sector %"SECT_FMT
"u is already allocated\n", temp
);
2389 if (!num_read
&& start
== temp
) {
2390 sector_t saved_start
;
2392 saved_start
= start
;
2393 start
= read_int(cround(saved_start
), cround(saved_start
), cround(limit
), 0, mesg
);
2394 if (display_in_cyl_units
) {
2395 start
= (start
- 1) * units_per_sector
;
2396 if (start
< saved_start
)
2397 start
= saved_start
;
2401 } while (start
!= temp
|| !num_read
);
2402 if (n
> 4) { /* NOT for fifth partition */
2403 struct pte
*pe
= &ptes
[n
];
2405 pe
->offset_from_dev_start
= start
- sector_offset
;
2406 if (pe
->offset_from_dev_start
== extended_offset
) { /* must be corrected */
2407 pe
->offset_from_dev_start
++;
2408 if (sector_offset
== 1)
2413 for (i
= 0; i
< g_partitions
; i
++) {
2414 struct pte
*pe
= &ptes
[i
];
2416 if (start
< pe
->offset_from_dev_start
&& limit
>= pe
->offset_from_dev_start
)
2417 limit
= pe
->offset_from_dev_start
- 1;
2418 if (start
< first
[i
] && limit
>= first
[i
])
2419 limit
= first
[i
] - 1;
2421 if (start
> limit
) {
2422 puts("No free sectors available");
2427 if (cround(start
) == cround(limit
)) {
2430 snprintf(mesg
, sizeof(mesg
),
2431 "Last %s or +size or +sizeM or +sizeK",
2432 str_units(SINGULAR
));
2433 stop
= read_int(cround(start
), cround(limit
), cround(limit
), cround(start
), mesg
);
2434 if (display_in_cyl_units
) {
2435 stop
= stop
* units_per_sector
- 1;
2441 set_partition(n
, 0, start
, stop
, sys
);
2443 set_partition(n
- 1, 1, ptes
[n
].offset_from_dev_start
, stop
, EXTENDED
);
2445 if (IS_EXTENDED(sys
)) {
2446 struct pte
*pe4
= &ptes
[4];
2447 struct pte
*pen
= &ptes
[n
];
2450 pen
->ext_pointer
= p
;
2451 pe4
->offset_from_dev_start
= extended_offset
= start
;
2452 pe4
->sectorbuffer
= xzalloc(sector_size
);
2453 pe4
->part_table
= pt_offset(pe4
->sectorbuffer
, 0);
2454 pe4
->ext_pointer
= pe4
->part_table
+ 1;
2463 if (g_partitions
> 5 || ptes
[4].part_table
->sys_ind
) {
2464 struct pte
*pe
= &ptes
[g_partitions
];
2466 pe
->sectorbuffer
= xzalloc(sector_size
);
2467 pe
->part_table
= pt_offset(pe
->sectorbuffer
, 0);
2468 pe
->ext_pointer
= pe
->part_table
+ 1;
2469 pe
->offset_from_dev_start
= 0;
2473 add_partition(g_partitions
- 1, LINUX_NATIVE
);
2479 int i
, free_primary
= 0;
2481 if (warn_geometry())
2485 add_sun_partition(get_partition(0, g_partitions
), LINUX_NATIVE
);
2489 sgi_add_partition(get_partition(0, g_partitions
), LINUX_NATIVE
);
2493 puts("Sorry - this fdisk cannot handle AIX disk labels.\n"
2494 "If you want to add DOS-type partitions, create a new empty DOS partition\n"
2495 "table first (use 'o'). This will destroy the present disk contents.");
2499 for (i
= 0; i
< 4; i
++)
2500 free_primary
+= !ptes
[i
].part_table
->sys_ind
;
2502 if (!free_primary
&& g_partitions
>= MAXIMUM_PARTS
) {
2503 puts("The maximum number of partitions has been created");
2507 if (!free_primary
) {
2508 if (extended_offset
)
2511 puts("You must delete some partition and add "
2512 "an extended partition first");
2515 snprintf(line
, sizeof(line
),
2518 " p primary partition (1-4)\n",
2520 "l logical (5 or over)" : "e extended"));
2522 c
= read_nonempty(line
);
2523 if ((c
| 0x20) == 'p') {
2524 i
= get_nonexisting_partition(0, 4);
2526 add_partition(i
, LINUX_NATIVE
);
2529 if (c
== 'l' && extended_offset
) {
2533 if (c
== 'e' && !extended_offset
) {
2534 i
= get_nonexisting_partition(0, 4);
2536 add_partition(i
, EXTENDED
);
2539 printf("Invalid partition number "
2540 "for type '%c'\n", c
);
2546 reread_partition_table(int leave
)
2550 puts("Calling ioctl() to re-read partition table");
2552 /* Users with slow external USB disks on a 320MHz ARM system (year 2011)
2553 * report that sleep is needed, otherwise BLKRRPART may fail with -EIO:
2556 i
= ioctl_or_perror(dev_fd
, BLKRRPART
, NULL
,
2557 "WARNING: rereading partition table "
2558 "failed, kernel still uses old table");
2562 "\nWARNING: If you have created or modified any DOS 6.x\n"
2563 "partitions, please see the fdisk manual page for additional\n"
2568 if (ENABLE_FEATURE_CLEAN_UP
)
2580 for (i
= 0; i
< 3; i
++)
2581 if (ptes
[i
].changed
)
2582 ptes
[3].changed
= 1;
2583 for (i
= 3; i
< g_partitions
; i
++) {
2584 struct pte
*pe
= &ptes
[i
];
2586 write_part_table_flag(pe
->sectorbuffer
);
2587 write_sector(pe
->offset_from_dev_start
, pe
->sectorbuffer
);
2591 else if (LABEL_IS_SGI
) {
2592 /* no test on change? the "altered" msg below might be mistaken */
2595 else if (LABEL_IS_SUN
) {
2596 for (i
= 0; i
< 8; i
++) {
2597 if (ptes
[i
].changed
) {
2604 puts("The partition table has been altered.");
2605 reread_partition_table(1);
2607 #endif /* FEATURE_FDISK_WRITABLE */
2609 #if ENABLE_FEATURE_FDISK_ADVANCED
2610 #define MAX_PER_LINE 16
2612 print_buffer(char *pbuffer
)
2616 for (i
= 0, l
= 0; i
< sector_size
; i
++, l
++) {
2618 printf("0x%03X:", i
);
2619 printf(" %02X", (unsigned char) pbuffer
[i
]);
2620 if (l
== MAX_PER_LINE
- 1) {
2635 printf("Device: %s\n", disk_device
);
2636 if (LABEL_IS_SGI
|| LABEL_IS_SUN
)
2637 print_buffer(MBRbuffer
);
2639 for (i
= 3; i
< g_partitions
; i
++)
2640 print_buffer(ptes
[i
].sectorbuffer
);
2645 move_begin(unsigned i
)
2647 struct pte
*pe
= &ptes
[i
];
2648 struct partition
*p
= pe
->part_table
;
2649 sector_t
new, first
, nr_sects
;
2651 if (warn_geometry())
2653 nr_sects
= get_nr_sects(p
);
2654 if (!p
->sys_ind
|| !nr_sects
|| IS_EXTENDED(p
->sys_ind
)) {
2655 printf("Partition %u has no data area\n", i
+ 1);
2658 first
= get_partition_start_from_dev_start(pe
); /* == pe->offset_from_dev_start + get_start_sect(p) */
2659 new = read_int(0 /*was:first*/, first
, first
+ nr_sects
- 1, first
, "New beginning of data");
2661 sector_t new_relative
= new - pe
->offset_from_dev_start
;
2662 nr_sects
+= (get_start_sect(p
) - new_relative
);
2663 set_start_sect(p
, new_relative
);
2664 set_nr_sects(p
, nr_sects
);
2665 read_nonempty("Recalculate C/H/S values? (Y/N): ");
2666 if ((line_ptr
[0] | 0x20) == 'y')
2667 set_hsc_start_end(p
, new, new + nr_sects
- 1);
2679 c
= 0x20 | read_nonempty("Expert command (m for help): ");
2687 move_begin(get_partition(0, g_partitions
));
2690 user_cylinders
= g_cylinders
=
2691 read_int(1, g_cylinders
, 1048576, 0,
2692 "Number of cylinders");
2694 sun_set_ncyl(g_cylinders
);
2704 else if (LABEL_IS_SUN
)
2706 else if (LABEL_IS_DOS
)
2711 fix_partition_table_order();
2714 #if ENABLE_FEATURE_SGI_LABEL
2719 user_heads
= g_heads
= read_int(1, g_heads
, 256, 0, "Number of heads");
2737 if (ENABLE_FEATURE_CLEAN_UP
)
2744 user_sectors
= g_sectors
= read_int(1, g_sectors
, 63, 0, "Number of sectors");
2745 if (dos_compatible_flag
) {
2746 sector_offset
= g_sectors
;
2747 puts("Warning: setting sector offset for DOS "
2756 write_table(); /* does not return */
2760 sun_set_pcylcount();
2767 #endif /* ADVANCED mode */
2770 is_ide_cdrom_or_tape(const char *device
)
2774 struct stat statbuf
;
2777 /* No device was given explicitly, and we are trying some
2778 likely things. But opening /dev/hdc may produce errors like
2779 "hdc: tray open or drive not ready"
2780 if it happens to be a CD-ROM drive. It even happens that
2781 the process hangs on the attempt to read a music CD.
2782 So try to be careful. This only works since 2.1.73. */
2784 if (!is_prefixed_with(device
, "/dev/hd"))
2787 snprintf(buf
, sizeof(buf
), "/proc/ide/%s/media", device
+5);
2788 procf
= fopen_for_read(buf
);
2789 if (procf
!= NULL
&& fgets(buf
, sizeof(buf
), procf
))
2790 is_ide
= (is_prefixed_with(buf
, "cdrom") ||
2791 is_prefixed_with(buf
, "tape"));
2793 /* Now when this proc file does not exist, skip the
2794 device when it is read-only. */
2795 if (stat(device
, &statbuf
) == 0)
2796 is_ide
= ((statbuf
.st_mode
& 0222) == 0);
2805 open_list_and_close(const char *device
, int user_specified
)
2809 disk_device
= device
;
2810 if (setjmp(listingbuf
))
2812 if (!user_specified
)
2813 if (is_ide_cdrom_or_tape(device
))
2816 /* Open disk_device, save file descriptor to dev_fd */
2818 gb
= get_boot(TRY_ONLY
);
2819 if (gb
> 0) { /* I/O error */
2820 /* Ignore other errors, since we try IDE
2821 and SCSI hard disks which may not be
2822 installed on the system. */
2823 if (user_specified
|| errno
== EACCES
)
2824 bb_perror_msg("can't open '%s'", device
);
2828 if (gb
< 0) { /* no DOS signature */
2829 list_disk_geometry();
2832 #if ENABLE_FEATURE_OSF_LABEL
2833 if (bsd_trydev(device
) < 0)
2835 printf("Disk %s doesn't contain a valid "
2836 "partition table\n", device
);
2839 #if ENABLE_FEATURE_FDISK_WRITABLE
2840 if (!LABEL_IS_SUN
&& g_partitions
> 4) {
2841 delete_partition(ext_index
);
2849 /* Is it a whole disk? The digit check is still useful
2850 for Xen devices for example. */
2851 static int is_whole_disk(const char *disk
)
2854 int fd
= open(disk
, O_RDONLY
);
2857 struct hd_geometry geometry
;
2858 int err
= ioctl(fd
, HDIO_GETGEO
, &geometry
);
2861 return (geometry
.start
== 0);
2864 /* Treat "nameN" as a partition name, not whole disk */
2865 /* note: mmcblk0 should work from the geometry check above */
2867 if (len
!= 0 && isdigit(disk
[len
- 1]))
2873 /* for fdisk -l: try all things in /proc/partitions
2874 that look like a partition name (do not end in a digit) */
2876 list_devs_in_proc_partititons(void)
2879 char line
[100], ptname
[100], devname
[120];
2882 procpt
= fopen_or_warn("/proc/partitions", "r");
2884 while (fgets(line
, sizeof(line
), procpt
)) {
2885 if (sscanf(line
, " %u %u %u %[^\n ]",
2886 &ma
, &mi
, &sz
, ptname
) != 4)
2889 sprintf(devname
, "/dev/%s", ptname
);
2890 if (is_whole_disk(devname
))
2891 open_list_and_close(devname
, 0);
2893 #if ENABLE_FEATURE_CLEAN_UP
2898 #if ENABLE_FEATURE_FDISK_WRITABLE
2900 unknown_command(int c
)
2902 printf("%c: unknown command\n", c
);
2906 int fdisk_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
2907 int fdisk_main(int argc UNUSED_PARAM
, char **argv
)
2912 * fdisk -l [-b sectorsize] [-u] device ...
2913 * fdisk -s [partition] ...
2914 * fdisk [-b sectorsize] [-u] device
2916 * Options -C, -H, -S set the geometry.
2920 close_dev_fd(); /* needed: fd 3 must not stay closed */
2922 opt_complementary
= "b+:C+:H+:S+"; /* numeric params */
2923 opt
= getopt32(argv
, "b:C:H:lS:u" IF_FEATURE_FDISK_BLKSIZE("s"),
2924 §or_size
, &user_cylinders
, &user_heads
, &user_sectors
);
2927 /* Ugly: this sector size is really per device,
2928 * so cannot be combined with multiple disks,
2929 * and the same goes for the C/H/S options.
2931 if (sector_size
< 512
2932 || sector_size
> 0x10000
2933 || (sector_size
& (sector_size
-1)) /* not power of 2 */
2938 user_set_sector_size
= 1;
2940 if (user_heads
<= 0 || user_heads
>= 256)
2942 if (user_sectors
<= 0 || user_sectors
>= 64)
2945 display_in_cyl_units
= 0; // -u
2947 #if ENABLE_FEATURE_FDISK_WRITABLE
2954 open_list_and_close(*argv
, 1);
2957 /* we don't have device names, */
2958 /* use /proc/partitions instead */
2959 list_devs_in_proc_partititons();
2962 #if ENABLE_FEATURE_FDISK_WRITABLE
2966 #if ENABLE_FEATURE_FDISK_BLKSIZE
2973 for (j
= 0; argv
[j
]; j
++) {
2974 unsigned long long size
;
2975 fd
= xopen(argv
[j
], O_RDONLY
);
2976 size
= bb_BLKGETSIZE_sectors(fd
) / 2;
2979 printf("%llu\n", size
);
2981 printf("%s: %llu\n", argv
[j
], size
);
2987 #if ENABLE_FEATURE_FDISK_WRITABLE
2988 if (!argv
[0] || argv
[1])
2991 disk_device
= argv
[0];
2992 get_boot(OPEN_MAIN
);
2995 /* OSF label, and no DOS label */
2996 printf("Detected an OSF/1 disklabel on %s, entering "
2997 "disklabel mode\n", disk_device
);
2999 /*Why do we do this? It seems to be counter-intuitive*/
3000 current_label_type
= LABEL_DOS
;
3001 /* If we return we may want to make an empty DOS label? */
3007 c
= 0x20 | read_nonempty("Command (m for help): ");
3011 toggle_active(get_partition(1, g_partitions
));
3012 else if (LABEL_IS_SUN
)
3013 toggle_sunflags(get_partition(1, g_partitions
),
3015 else if (LABEL_IS_SGI
)
3016 sgi_set_bootpartition(
3017 get_partition(1, g_partitions
));
3023 printf("\nThe current boot file is: %s\n",
3024 sgi_get_bootfile());
3025 if (read_maybe_empty("Please enter the name of the "
3026 "new boot file: ") == '\n')
3027 puts("Boot file unchanged");
3029 sgi_set_bootfile(line_ptr
);
3031 #if ENABLE_FEATURE_OSF_LABEL
3038 toggle_dos_compatibility_flag();
3039 else if (LABEL_IS_SUN
)
3040 toggle_sunflags(get_partition(1, g_partitions
),
3042 else if (LABEL_IS_SGI
)
3043 sgi_set_swappartition(
3044 get_partition(1, g_partitions
));
3051 /* If sgi_label then don't use get_existing_partition,
3052 let the user select a partition, since
3053 get_existing_partition() only works for Linux-like
3055 if (!LABEL_IS_SGI
) {
3056 j
= get_existing_partition(1, g_partitions
);
3058 j
= get_partition(1, g_partitions
);
3061 delete_partition(j
);
3070 list_types(get_sys_types());
3085 if (ENABLE_FEATURE_CLEAN_UP
)
3090 #if ENABLE_FEATURE_SUN_LABEL
3104 write_table(); /* does not return */
3106 #if ENABLE_FEATURE_FDISK_ADVANCED
3109 puts("\n\tSorry, no experts menu for SGI "
3110 "partition tables available\n");
3121 #endif /* FEATURE_FDISK_WRITABLE */