1/* vi: set sw=4 ts=4: */ 2/* fdisk.c -- Partition table manipulator for Linux. 3 * 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) 6 * 7 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. 8 */ 9 10#ifndef _LARGEFILE64_SOURCE 11/* For lseek64 */ 12# define _LARGEFILE64_SOURCE 13#endif 14#include <assert.h> /* assert */ 15#include <sys/mount.h> 16#if !defined(BLKSSZGET) 17# define BLKSSZGET _IO(0x12, 104) 18#endif 19#if !defined(BLKGETSIZE64) 20# define BLKGETSIZE64 _IOR(0x12,114,size_t) 21#endif 22#include "libbb.h" 23 24#if BB_LITTLE_ENDIAN 25# define inline_if_little_endian ALWAYS_INLINE 26#else 27# define inline_if_little_endian /* nothing */ 28#endif 29 30 31/* Looks like someone forgot to add this to config system */ 32#ifndef ENABLE_FEATURE_FDISK_BLKSIZE 33# define ENABLE_FEATURE_FDISK_BLKSIZE 0 34# define IF_FEATURE_FDISK_BLKSIZE(a) 35#endif 36 37#define DEFAULT_SECTOR_SIZE 512 38#define DEFAULT_SECTOR_SIZE_STR "512" 39#define MAX_SECTOR_SIZE 2048 40#define SECTOR_SIZE 512 /* still used in osf/sgi/sun code */ 41#define MAXIMUM_PARTS 60 42 43#define ACTIVE_FLAG 0x80 44 45#define EXTENDED 0x05 46#define WIN98_EXTENDED 0x0f 47#define LINUX_PARTITION 0x81 48#define LINUX_SWAP 0x82 49#define LINUX_NATIVE 0x83 50#define LINUX_EXTENDED 0x85 51#define LINUX_LVM 0x8e 52#define LINUX_RAID 0xfd 53 54 55enum { 56 OPT_b = 1 << 0, 57 OPT_C = 1 << 1, 58 OPT_H = 1 << 2, 59 OPT_l = 1 << 3, 60 OPT_S = 1 << 4, 61 OPT_u = 1 << 5, 62 OPT_s = (1 << 6) * ENABLE_FEATURE_FDISK_BLKSIZE, 63}; 64 65 66typedef unsigned long long ullong; 67/* Used for sector numbers. Partition formats we know 68 * do not support more than 2^32 sectors 69 */ 70typedef uint32_t sector_t; 71#if UINT_MAX == 4294967295 72# define SECT_FMT "" 73#elif ULONG_MAX == 4294967295 74# define SECT_FMT "l" 75#else 76# error Cant detect sizeof(uint32_t) 77#endif 78 79struct hd_geometry { 80 unsigned char heads; 81 unsigned char sectors; 82 unsigned short cylinders; 83 unsigned long start; 84}; 85 86#define HDIO_GETGEO 0x0301 /* get device geometry */ 87 88static const char msg_building_new_label[] ALIGN1 = 89"Building a new %s. Changes will remain in memory only,\n" 90"until you decide to write them. After that the previous content\n" 91"won't be recoverable.\n\n"; 92 93static const char msg_part_already_defined[] ALIGN1 = 94"Partition %u is already defined, delete it before re-adding\n"; 95 96 97struct partition { 98 unsigned char boot_ind; /* 0x80 - active */ 99 unsigned char head; /* starting head */ 100 unsigned char sector; /* starting sector */ 101 unsigned char cyl; /* starting cylinder */ 102 unsigned char sys_ind; /* what partition type */ 103 unsigned char end_head; /* end head */ 104 unsigned char end_sector; /* end sector */ 105 unsigned char end_cyl; /* end cylinder */ 106 unsigned char start4[4]; /* starting sector counting from 0 */ 107 unsigned char size4[4]; /* nr of sectors in partition */ 108} PACKED; 109 110#define unable_to_open "can't open '%s'" 111#define unable_to_read "can't read from %s" 112#define unable_to_seek "can't seek on %s" 113 114enum label_type { 115 LABEL_DOS, LABEL_SUN, LABEL_SGI, LABEL_AIX, LABEL_OSF 116}; 117 118#define LABEL_IS_DOS (LABEL_DOS == current_label_type) 119 120#if ENABLE_FEATURE_SUN_LABEL 121#define LABEL_IS_SUN (LABEL_SUN == current_label_type) 122#define STATIC_SUN static 123#else 124#define LABEL_IS_SUN 0 125#define STATIC_SUN extern 126#endif 127 128#if ENABLE_FEATURE_SGI_LABEL 129#define LABEL_IS_SGI (LABEL_SGI == current_label_type) 130#define STATIC_SGI static 131#else 132#define LABEL_IS_SGI 0 133#define STATIC_SGI extern 134#endif 135 136#if ENABLE_FEATURE_AIX_LABEL 137#define LABEL_IS_AIX (LABEL_AIX == current_label_type) 138#define STATIC_AIX static 139#else 140#define LABEL_IS_AIX 0 141#define STATIC_AIX extern 142#endif 143 144#if ENABLE_FEATURE_OSF_LABEL 145#define LABEL_IS_OSF (LABEL_OSF == current_label_type) 146#define STATIC_OSF static 147#else 148#define LABEL_IS_OSF 0 149#define STATIC_OSF extern 150#endif 151 152enum action { OPEN_MAIN, TRY_ONLY, CREATE_EMPTY_DOS, CREATE_EMPTY_SUN }; 153 154static void update_units(void); 155#if ENABLE_FEATURE_FDISK_WRITABLE 156static void change_units(void); 157static void reread_partition_table(int leave); 158static void delete_partition(int i); 159static unsigned get_partition(int warn, unsigned max); 160static void list_types(const char *const *sys); 161static sector_t read_int(sector_t low, sector_t dflt, sector_t high, sector_t base, const char *mesg); 162#endif 163static const char *partition_type(unsigned char type); 164static void get_geometry(void); 165#if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE 166static int get_boot(enum action what); 167#else 168static int get_boot(void); 169#endif 170 171#define PLURAL 0 172#define SINGULAR 1 173 174static sector_t get_start_sect(const struct partition *p); 175static sector_t get_nr_sects(const struct partition *p); 176 177/* 178 * per partition table entry data 179 * 180 * The four primary partitions have the same sectorbuffer (MBRbuffer) 181 * and have NULL ext_pointer. 182 * Each logical partition table entry has two pointers, one for the 183 * partition and one link to the next one. 184 */ 185struct pte { 186 struct partition *part_table; /* points into sectorbuffer */ 187 struct partition *ext_pointer; /* points into sectorbuffer */ 188 sector_t offset_from_dev_start; /* disk sector number */ 189 char *sectorbuffer; /* disk sector contents */ 190#if ENABLE_FEATURE_FDISK_WRITABLE 191 char changed; /* boolean */ 192#endif 193}; 194 195/* DOS partition types */ 196 197static const char *const i386_sys_types[] = { 198 "\x00" "Empty", 199 "\x01" "FAT12", 200 "\x04" "FAT16 <32M", 201 "\x05" "Extended", /* DOS 3.3+ extended partition */ 202 "\x06" "FAT16", /* DOS 16-bit >=32M */ 203 "\x07" "HPFS/NTFS", /* OS/2 IFS, eg, HPFS or NTFS or QNX */ 204 "\x0a" "OS/2 Boot Manager",/* OS/2 Boot Manager */ 205 "\x0b" "Win95 FAT32", 206 "\x0c" "Win95 FAT32 (LBA)",/* LBA really is 'Extended Int 13h' */ 207 "\x0e" "Win95 FAT16 (LBA)", 208 "\x0f" "Win95 Ext'd (LBA)", 209 "\x11" "Hidden FAT12", 210 "\x12" "Compaq diagnostics", 211 "\x14" "Hidden FAT16 <32M", 212 "\x16" "Hidden FAT16", 213 "\x17" "Hidden HPFS/NTFS", 214 "\x1b" "Hidden Win95 FAT32", 215 "\x1c" "Hidden W95 FAT32 (LBA)", 216 "\x1e" "Hidden W95 FAT16 (LBA)", 217 "\x3c" "Part.Magic recovery", 218 "\x41" "PPC PReP Boot", 219 "\x42" "SFS", 220 "\x63" "GNU HURD or SysV", /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */ 221 "\x80" "Old Minix", /* Minix 1.4a and earlier */ 222 "\x81" "Minix / old Linux",/* Minix 1.4b and later */ 223 "\x82" "Linux swap", /* also Solaris */ 224 "\x83" "Linux", 225 "\x84" "OS/2 hidden C: drive", 226 "\x85" "Linux extended", 227 "\x86" "NTFS volume set", 228 "\x87" "NTFS volume set", 229 "\x8e" "Linux LVM", 230 "\x9f" "BSD/OS", /* BSDI */ 231 "\xa0" "Thinkpad hibernation", 232 "\xa5" "FreeBSD", /* various BSD flavours */ 233 "\xa6" "OpenBSD", 234 "\xa8" "Darwin UFS", 235 "\xa9" "NetBSD", 236 "\xab" "Darwin boot", 237 "\xb7" "BSDI fs", 238 "\xb8" "BSDI swap", 239 "\xbe" "Solaris boot", 240 "\xeb" "BeOS fs", 241 "\xee" "EFI GPT", /* Intel EFI GUID Partition Table */ 242 "\xef" "EFI (FAT-12/16/32)", /* Intel EFI System Partition */ 243 "\xf0" "Linux/PA-RISC boot", /* Linux/PA-RISC boot loader */ 244 "\xf2" "DOS secondary", /* DOS 3.3+ secondary */ 245 "\xfd" "Linux raid autodetect", /* New (2.2.x) raid partition with 246 autodetect using persistent 247 superblock */ 248#if 0 /* ENABLE_WEIRD_PARTITION_TYPES */ 249 "\x02" "XENIX root", 250 "\x03" "XENIX usr", 251 "\x08" "AIX", /* AIX boot (AIX -- PS/2 port) or SplitDrive */ 252 "\x09" "AIX bootable", /* AIX data or Coherent */ 253 "\x10" "OPUS", 254 "\x18" "AST SmartSleep", 255 "\x24" "NEC DOS", 256 "\x39" "Plan 9", 257 "\x40" "Venix 80286", 258 "\x4d" "QNX4.x", 259 "\x4e" "QNX4.x 2nd part", 260 "\x4f" "QNX4.x 3rd part", 261 "\x50" "OnTrack DM", 262 "\x51" "OnTrack DM6 Aux1", /* (or Novell) */ 263 "\x52" "CP/M", /* CP/M or Microport SysV/AT */ 264 "\x53" "OnTrack DM6 Aux3", 265 "\x54" "OnTrackDM6", 266 "\x55" "EZ-Drive", 267 "\x56" "Golden Bow", 268 "\x5c" "Priam Edisk", 269 "\x61" "SpeedStor", 270 "\x64" "Novell Netware 286", 271 "\x65" "Novell Netware 386", 272 "\x70" "DiskSecure Multi-Boot", 273 "\x75" "PC/IX", 274 "\x93" "Amoeba", 275 "\x94" "Amoeba BBT", /* (bad block table) */ 276 "\xa7" "NeXTSTEP", 277 "\xbb" "Boot Wizard hidden", 278 "\xc1" "DRDOS/sec (FAT-12)", 279 "\xc4" "DRDOS/sec (FAT-16 < 32M)", 280 "\xc6" "DRDOS/sec (FAT-16)", 281 "\xc7" "Syrinx", 282 "\xda" "Non-FS data", 283 "\xdb" "CP/M / CTOS / ...",/* CP/M or Concurrent CP/M or 284 Concurrent DOS or CTOS */ 285 "\xde" "Dell Utility", /* Dell PowerEdge Server utilities */ 286 "\xdf" "BootIt", /* BootIt EMBRM */ 287 "\xe1" "DOS access", /* DOS access or SpeedStor 12-bit FAT 288 extended partition */ 289 "\xe3" "DOS R/O", /* DOS R/O or SpeedStor */ 290 "\xe4" "SpeedStor", /* SpeedStor 16-bit FAT extended 291 partition < 1024 cyl. */ 292 "\xf1" "SpeedStor", 293 "\xf4" "SpeedStor", /* SpeedStor large partition */ 294 "\xfe" "LANstep", /* SpeedStor >1024 cyl. or LANstep */ 295 "\xff" "BBT", /* Xenix Bad Block Table */ 296#endif 297 NULL 298}; 299 300enum { 301 dev_fd = 3 /* the disk */ 302}; 303 304/* Globals */ 305struct globals { 306 char *line_ptr; 307 308 const char *disk_device; 309 int g_partitions; // = 4; /* maximum partition + 1 */ 310 unsigned units_per_sector; // = 1; 311 unsigned sector_size; // = DEFAULT_SECTOR_SIZE; 312 unsigned user_set_sector_size; 313 unsigned sector_offset; // = 1; 314 unsigned g_heads, g_sectors, g_cylinders; 315 smallint /* enum label_type */ current_label_type; 316 smallint display_in_cyl_units; // = 1; 317#if ENABLE_FEATURE_OSF_LABEL 318 smallint possibly_osf_label; 319#endif 320 321 smallint listing; /* no aborts for fdisk -l */ 322 smallint dos_compatible_flag; // = 1; 323#if ENABLE_FEATURE_FDISK_WRITABLE 324 //int dos_changed; 325 smallint nowarn; /* no warnings for fdisk -l/-s */ 326#endif 327 int ext_index; /* the prime extended partition */ 328 unsigned user_cylinders, user_heads, user_sectors; 329 unsigned pt_heads, pt_sectors; 330 unsigned kern_heads, kern_sectors; 331 sector_t extended_offset; /* offset of link pointers */ 332 sector_t total_number_of_sectors; 333 334 jmp_buf listingbuf; 335 char line_buffer[80]; 336 char partname_buffer[80]; 337 /* Raw disk label. For DOS-type partition tables the MBR, 338 * with descriptions of the primary partitions. */ 339 char MBRbuffer[MAX_SECTOR_SIZE]; 340 /* Partition tables */ 341 struct pte ptes[MAXIMUM_PARTS]; 342}; 343#define G (*ptr_to_globals) 344#define line_ptr (G.line_ptr ) 345#define disk_device (G.disk_device ) 346#define g_partitions (G.g_partitions ) 347#define units_per_sector (G.units_per_sector ) 348#define sector_size (G.sector_size ) 349#define user_set_sector_size (G.user_set_sector_size) 350#define sector_offset (G.sector_offset ) 351#define g_heads (G.g_heads ) 352#define g_sectors (G.g_sectors ) 353#define g_cylinders (G.g_cylinders ) 354#define current_label_type (G.current_label_type ) 355#define display_in_cyl_units (G.display_in_cyl_units) 356#define possibly_osf_label (G.possibly_osf_label ) 357#define listing (G.listing ) 358#define dos_compatible_flag (G.dos_compatible_flag ) 359#define nowarn (G.nowarn ) 360#define ext_index (G.ext_index ) 361#define user_cylinders (G.user_cylinders ) 362#define user_heads (G.user_heads ) 363#define user_sectors (G.user_sectors ) 364#define pt_heads (G.pt_heads ) 365#define pt_sectors (G.pt_sectors ) 366#define kern_heads (G.kern_heads ) 367#define kern_sectors (G.kern_sectors ) 368#define extended_offset (G.extended_offset ) 369#define total_number_of_sectors (G.total_number_of_sectors) 370#define listingbuf (G.listingbuf ) 371#define line_buffer (G.line_buffer ) 372#define partname_buffer (G.partname_buffer) 373#define MBRbuffer (G.MBRbuffer ) 374#define ptes (G.ptes ) 375#define INIT_G() do { \ 376 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ 377 sector_size = DEFAULT_SECTOR_SIZE; \ 378 sector_offset = 1; \ 379 g_partitions = 4; \ 380 display_in_cyl_units = 1; \ 381 units_per_sector = 1; \ 382 dos_compatible_flag = 1; \ 383} while (0) 384 385 386/* TODO: move to libbb? */ 387/* TODO: return unsigned long long, FEATURE_FDISK_BLKSIZE _can_ handle 388 * disks > 2^32 sectors 389 */ 390static sector_t bb_BLKGETSIZE_sectors(int fd) 391{ 392 uint64_t v64; 393 unsigned long longsectors; 394 395 if (ioctl(fd, BLKGETSIZE64, &v64) == 0) { 396 /* Got bytes, convert to 512 byte sectors */ 397 v64 >>= 9; 398 if (v64 != (sector_t)v64) { 399 ret_trunc: 400 /* Not only DOS, but all other partition tables 401 * we support can't record more than 32 bit 402 * sector counts or offsets 403 */ 404 bb_error_msg("device has more than 2^32 sectors, can't use all of them"); 405 v64 = (uint32_t)-1L; 406 } 407 return v64; 408 } 409 /* Needs temp of type long */ 410 if (ioctl(fd, BLKGETSIZE, &longsectors)) { 411 /* Perhaps this is a disk image */ 412 off_t sz = lseek(fd, 0, SEEK_END); 413 longsectors = 0; 414 if (sz > 0) 415 longsectors = (uoff_t)sz / sector_size; 416 lseek(fd, 0, SEEK_SET); 417 } 418 if (sizeof(long) > sizeof(sector_t) 419 && longsectors != (sector_t)longsectors 420 ) { 421 goto ret_trunc; 422 } 423 return longsectors; 424} 425 426 427#define IS_EXTENDED(i) \ 428 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED) 429 430#define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n)) 431 432#define scround(x) (((x)+units_per_sector-1)/units_per_sector) 433 434#define pt_offset(b, n) \ 435 ((struct partition *)((b) + 0x1be + (n) * sizeof(struct partition))) 436 437#define sector(s) ((s) & 0x3f) 438 439#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2)) 440 441#define hsc2sector(h,s,c) \ 442 (sector(s) - 1 + sectors * ((h) + heads * cylinder(s,c))) 443 444static void 445close_dev_fd(void) 446{ 447 /* Not really closing, but making sure it is open, and to harmless place */ 448 xmove_fd(xopen(bb_dev_null, O_RDONLY), dev_fd); 449} 450 451/* 452 * Return partition name - uses static storage 453 */ 454static const char * 455partname(const char *dev, int pno, int lth) 456{ 457 const char *p; 458 int w, wp; 459 int bufsiz; 460 char *bufp; 461 462 bufp = partname_buffer; 463 bufsiz = sizeof(partname_buffer); 464 465 w = strlen(dev); 466 p = ""; 467 468 if (isdigit(dev[w-1])) 469 p = "p"; 470 471 /* devfs kludge - note: fdisk partition names are not supposed 472 to equal kernel names, so there is no reason to do this */ 473 if (strcmp(dev + w - 4, "disc") == 0) { 474 w -= 4; 475 p = "part"; 476 } 477 478 wp = strlen(p); 479 480 if (lth) { 481 snprintf(bufp, bufsiz, "%*.*s%s%-2u", 482 lth-wp-2, w, dev, p, pno); 483 } else { 484 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno); 485 } 486 return bufp; 487} 488 489static ALWAYS_INLINE struct partition * 490get_part_table(int i) 491{ 492 return ptes[i].part_table; 493} 494 495static const char * 496str_units(int n) 497{ /* n==1: use singular */ 498 if (n == 1) 499 return display_in_cyl_units ? "cylinder" : "sector"; 500 return display_in_cyl_units ? "cylinders" : "sectors"; 501} 502 503static int 504valid_part_table_flag(const char *mbuffer) 505{ 506 return (mbuffer[510] == 0x55 && (uint8_t)mbuffer[511] == 0xaa); 507} 508 509static void fdisk_fatal(const char *why) 510{ 511 if (listing) { 512 close_dev_fd(); 513 longjmp(listingbuf, 1); 514 } 515 bb_error_msg_and_die(why, disk_device); 516} 517 518static void 519seek_sector(sector_t secno) 520{ 521#if ENABLE_FDISK_SUPPORT_LARGE_DISKS 522 off64_t off = (off64_t)secno * sector_size; 523 if (lseek64(dev_fd, off, SEEK_SET) == (off64_t) -1) 524 fdisk_fatal(unable_to_seek); 525#else 526 uint64_t off = (uint64_t)secno * sector_size; 527 if (off > MAXINT(off_t) 528 || lseek(dev_fd, (off_t)off, SEEK_SET) == (off_t) -1 529 ) { 530 fdisk_fatal(unable_to_seek); 531 } 532#endif 533} 534 535#if ENABLE_FEATURE_FDISK_WRITABLE 536/* Read line; return 0 or first printable char */ 537static int 538read_line(const char *prompt) 539{ 540 int sz; 541 542 sz = read_line_input(prompt, line_buffer, sizeof(line_buffer), NULL); 543 if (sz <= 0) 544 exit(EXIT_SUCCESS); /* Ctrl-D or Ctrl-C */ 545 546 if (line_buffer[sz-1] == '\n') 547 line_buffer[--sz] = '\0'; 548 549 line_ptr = line_buffer; 550 while (*line_ptr != '\0' && (unsigned char)*line_ptr <= ' ') 551 line_ptr++; 552 return *line_ptr; 553} 554 555static void 556set_all_unchanged(void) 557{ 558 int i; 559 560 for (i = 0; i < MAXIMUM_PARTS; i++) 561 ptes[i].changed = 0; 562} 563 564static ALWAYS_INLINE void 565set_changed(int i) 566{ 567 ptes[i].changed = 1; 568} 569 570static ALWAYS_INLINE void 571write_part_table_flag(char *b) 572{ 573 b[510] = 0x55; 574 b[511] = 0xaa; 575} 576 577static char 578read_nonempty(const char *mesg) 579{ 580 while (!read_line(mesg)) 581 continue; 582 return *line_ptr; 583} 584 585static char 586read_maybe_empty(const char *mesg) 587{ 588 if (!read_line(mesg)) { 589 line_ptr = line_buffer; 590 line_ptr[0] = '\n'; 591 line_ptr[1] = '\0'; 592 } 593 return line_ptr[0]; 594} 595 596static int 597read_hex(const char *const *sys) 598{ 599 unsigned long v; 600 while (1) { 601 read_nonempty("Hex code (type L to list codes): "); 602 if ((line_ptr[0] | 0x20) == 'l') { 603 list_types(sys); 604 continue; 605 } 606 v = bb_strtoul(line_ptr, NULL, 16); 607 if (v <= 0xff) 608 return v; 609 } 610} 611 612static void 613write_sector(sector_t secno, const void *buf) 614{ 615 seek_sector(secno); 616 xwrite(dev_fd, buf, sector_size); 617} 618#endif /* FEATURE_FDISK_WRITABLE */ 619 620 621#include "fdisk_aix.c" 622 623struct sun_partition { 624 unsigned char info[128]; /* Informative text string */ 625 unsigned char spare0[14]; 626 struct sun_info { 627 unsigned char spare1; 628 unsigned char id; 629 unsigned char spare2; 630 unsigned char flags; 631 } infos[8]; 632 unsigned char spare1[246]; /* Boot information etc. */ 633 unsigned short rspeed; /* Disk rotational speed */ 634 unsigned short pcylcount; /* Physical cylinder count */ 635 unsigned short sparecyl; /* extra sects per cylinder */ 636 unsigned char spare2[4]; /* More magic... */ 637 unsigned short ilfact; /* Interleave factor */ 638 unsigned short ncyl; /* Data cylinder count */ 639 unsigned short nacyl; /* Alt. cylinder count */ 640 unsigned short ntrks; /* Tracks per cylinder */ 641 unsigned short nsect; /* Sectors per track */ 642 unsigned char spare3[4]; /* Even more magic... */ 643 struct sun_partinfo { 644 uint32_t start_cylinder; 645 uint32_t num_sectors; 646 } partitions[8]; 647 unsigned short magic; /* Magic number */ 648 unsigned short csum; /* Label xor'd checksum */ 649} FIX_ALIASING; 650typedef struct sun_partition sun_partition; 651#define sunlabel ((sun_partition *)MBRbuffer) 652STATIC_OSF void bsd_select(void); 653STATIC_OSF void xbsd_print_disklabel(int); 654#include "fdisk_osf.c" 655 656#if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL 657static uint16_t 658fdisk_swap16(uint16_t x) 659{ 660 return (x << 8) | (x >> 8); 661} 662 663static uint32_t 664fdisk_swap32(uint32_t x) 665{ 666 return (x << 24) | 667 ((x & 0xFF00) << 8) | 668 ((x & 0xFF0000) >> 8) | 669 (x >> 24); 670} 671#endif 672 673STATIC_SGI const char *const sgi_sys_types[]; 674STATIC_SGI unsigned sgi_get_num_sectors(int i); 675STATIC_SGI int sgi_get_sysid(int i); 676STATIC_SGI void sgi_delete_partition(int i); 677STATIC_SGI void sgi_change_sysid(int i, int sys); 678STATIC_SGI void sgi_list_table(int xtra); 679#if ENABLE_FEATURE_FDISK_ADVANCED 680STATIC_SGI void sgi_set_xcyl(void); 681#endif 682STATIC_SGI int verify_sgi(int verbose); 683STATIC_SGI void sgi_add_partition(int n, int sys); 684STATIC_SGI void sgi_set_swappartition(int i); 685STATIC_SGI const char *sgi_get_bootfile(void); 686STATIC_SGI void sgi_set_bootfile(const char* aFile); 687STATIC_SGI void create_sgiinfo(void); 688STATIC_SGI void sgi_write_table(void); 689STATIC_SGI void sgi_set_bootpartition(int i); 690#include "fdisk_sgi.c" 691 692STATIC_SUN const char *const sun_sys_types[]; 693STATIC_SUN void sun_delete_partition(int i); 694STATIC_SUN void sun_change_sysid(int i, int sys); 695STATIC_SUN void sun_list_table(int xtra); 696STATIC_SUN void add_sun_partition(int n, int sys); 697#if ENABLE_FEATURE_FDISK_ADVANCED 698STATIC_SUN void sun_set_alt_cyl(void); 699STATIC_SUN void sun_set_ncyl(int cyl); 700STATIC_SUN void sun_set_xcyl(void); 701STATIC_SUN void sun_set_ilfact(void); 702STATIC_SUN void sun_set_rspeed(void); 703STATIC_SUN void sun_set_pcylcount(void); 704#endif 705STATIC_SUN void toggle_sunflags(int i, unsigned char mask); 706STATIC_SUN void verify_sun(void); 707STATIC_SUN void sun_write_table(void); 708#include "fdisk_sun.c" 709 710 711static inline_if_little_endian unsigned 712read4_little_endian(const unsigned char *cp) 713{ 714 uint32_t v; 715 move_from_unaligned32(v, cp); 716 return SWAP_LE32(v); 717} 718 719static sector_t 720get_start_sect(const struct partition *p) 721{ 722 return read4_little_endian(p->start4); 723} 724 725static sector_t 726get_nr_sects(const struct partition *p) 727{ 728 return read4_little_endian(p->size4); 729} 730 731#if ENABLE_FEATURE_FDISK_WRITABLE 732/* start_sect and nr_sects are stored little endian on all machines */ 733/* moreover, they are not aligned correctly */ 734static inline_if_little_endian void 735store4_little_endian(unsigned char *cp, unsigned val) 736{ 737 uint32_t v = SWAP_LE32(val); 738 move_to_unaligned32(cp, v); 739} 740 741static void 742set_start_sect(struct partition *p, unsigned start_sect) 743{ 744 store4_little_endian(p->start4, start_sect); 745} 746 747static void 748set_nr_sects(struct partition *p, unsigned nr_sects) 749{ 750 store4_little_endian(p->size4, nr_sects); 751} 752#endif 753 754/* Allocate a buffer and read a partition table sector */ 755static void 756read_pte(struct pte *pe, sector_t offset) 757{ 758 pe->offset_from_dev_start = offset; 759 pe->sectorbuffer = xzalloc(sector_size); 760 seek_sector(offset); 761 /* xread would make us abort - bad for fdisk -l */ 762 if (full_read(dev_fd, pe->sectorbuffer, sector_size) != sector_size) 763 fdisk_fatal(unable_to_read); 764#if ENABLE_FEATURE_FDISK_WRITABLE 765 pe->changed = 0; 766#endif 767 pe->part_table = pe->ext_pointer = NULL; 768} 769 770static sector_t 771get_partition_start_from_dev_start(const struct pte *pe) 772{ 773 return pe->offset_from_dev_start + get_start_sect(pe->part_table); 774} 775 776#if ENABLE_FEATURE_FDISK_WRITABLE 777/* 778 * Avoid warning about DOS partitions when no DOS partition was changed. 779 * Here a heuristic "is probably dos partition". 780 * We might also do the opposite and warn in all cases except 781 * for "is probably nondos partition". 782 */ 783#ifdef UNUSED 784static int 785is_dos_partition(int t) 786{ 787 return (t == 1 || t == 4 || t == 6 || 788 t == 0x0b || t == 0x0c || t == 0x0e || 789 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 || 790 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 || 791 t == 0xc1 || t == 0xc4 || t == 0xc6); 792} 793#endif 794 795static void 796menu(void) 797{ 798 puts("Command Action"); 799 if (LABEL_IS_SUN) { 800 puts("a\ttoggle a read only flag"); /* sun */ 801 puts("b\tedit bsd disklabel"); 802 puts("c\ttoggle the mountable flag"); /* sun */ 803 puts("d\tdelete a partition"); 804 puts("l\tlist known partition types"); 805 puts("n\tadd a new partition"); 806 puts("o\tcreate a new empty DOS partition table"); 807 puts("p\tprint the partition table"); 808 puts("q\tquit without saving changes"); 809 puts("s\tcreate a new empty Sun disklabel"); /* sun */ 810 puts("t\tchange a partition's system id"); 811 puts("u\tchange display/entry units"); 812 puts("v\tverify the partition table"); 813 puts("w\twrite table to disk and exit"); 814#if ENABLE_FEATURE_FDISK_ADVANCED 815 puts("x\textra functionality (experts only)"); 816#endif 817 } else if (LABEL_IS_SGI) { 818 puts("a\tselect bootable partition"); /* sgi flavour */ 819 puts("b\tedit bootfile entry"); /* sgi */ 820 puts("c\tselect sgi swap partition"); /* sgi flavour */ 821 puts("d\tdelete a partition"); 822 puts("l\tlist known partition types"); 823 puts("n\tadd a new partition"); 824 puts("o\tcreate a new empty DOS partition table"); 825 puts("p\tprint the partition table"); 826 puts("q\tquit without saving changes"); 827 puts("s\tcreate a new empty Sun disklabel"); /* sun */ 828 puts("t\tchange a partition's system id"); 829 puts("u\tchange display/entry units"); 830 puts("v\tverify the partition table"); 831 puts("w\twrite table to disk and exit"); 832 } else if (LABEL_IS_AIX) { 833 puts("o\tcreate a new empty DOS partition table"); 834 puts("q\tquit without saving changes"); 835 puts("s\tcreate a new empty Sun disklabel"); /* sun */ 836 } else { 837 puts("a\ttoggle a bootable flag"); 838 puts("b\tedit bsd disklabel"); 839 puts("c\ttoggle the dos compatibility flag"); 840 puts("d\tdelete a partition"); 841 puts("l\tlist known partition types"); 842 puts("n\tadd a new partition"); 843 puts("o\tcreate a new empty DOS partition table"); 844 puts("p\tprint the partition table"); 845 puts("q\tquit without saving changes"); 846 puts("s\tcreate a new empty Sun disklabel"); /* sun */ 847 puts("t\tchange a partition's system id"); 848 puts("u\tchange display/entry units"); 849 puts("v\tverify the partition table"); 850 puts("w\twrite table to disk and exit"); 851#if ENABLE_FEATURE_FDISK_ADVANCED 852 puts("x\textra functionality (experts only)"); 853#endif 854 } 855} 856#endif /* FEATURE_FDISK_WRITABLE */ 857 858 859#if ENABLE_FEATURE_FDISK_ADVANCED 860static void 861xmenu(void) 862{ 863 puts("Command Action"); 864 if (LABEL_IS_SUN) { 865 puts("a\tchange number of alternate cylinders"); /*sun*/ 866 puts("c\tchange number of cylinders"); 867 puts("d\tprint the raw data in the partition table"); 868 puts("e\tchange number of extra sectors per cylinder");/*sun*/ 869 puts("h\tchange number of heads"); 870 puts("i\tchange interleave factor"); /*sun*/ 871 puts("o\tchange rotation speed (rpm)"); /*sun*/ 872 puts("p\tprint the partition table"); 873 puts("q\tquit without saving changes"); 874 puts("r\treturn to main menu"); 875 puts("s\tchange number of sectors/track"); 876 puts("v\tverify the partition table"); 877 puts("w\twrite table to disk and exit"); 878 puts("y\tchange number of physical cylinders"); /*sun*/ 879 } else if (LABEL_IS_SGI) { 880 puts("b\tmove beginning of data in a partition"); /* !sun */ 881 puts("c\tchange number of cylinders"); 882 puts("d\tprint the raw data in the partition table"); 883 puts("e\tlist extended partitions"); /* !sun */ 884 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */ 885 puts("h\tchange number of heads"); 886 puts("p\tprint the partition table"); 887 puts("q\tquit without saving changes"); 888 puts("r\treturn to main menu"); 889 puts("s\tchange number of sectors/track"); 890 puts("v\tverify the partition table"); 891 puts("w\twrite table to disk and exit"); 892 } else if (LABEL_IS_AIX) { 893 puts("b\tmove beginning of data in a partition"); /* !sun */ 894 puts("c\tchange number of cylinders"); 895 puts("d\tprint the raw data in the partition table"); 896 puts("e\tlist extended partitions"); /* !sun */ 897 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */ 898 puts("h\tchange number of heads"); 899 puts("p\tprint the partition table"); 900 puts("q\tquit without saving changes"); 901 puts("r\treturn to main menu"); 902 puts("s\tchange number of sectors/track"); 903 puts("v\tverify the partition table"); 904 puts("w\twrite table to disk and exit"); 905 } else { 906 puts("b\tmove beginning of data in a partition"); /* !sun */ 907 puts("c\tchange number of cylinders"); 908 puts("d\tprint the raw data in the partition table"); 909 puts("e\tlist extended partitions"); /* !sun */ 910 puts("f\tfix partition order"); /* !sun, !aix, !sgi */ 911#if ENABLE_FEATURE_SGI_LABEL 912 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */ 913#endif 914 puts("h\tchange number of heads"); 915 puts("p\tprint the partition table"); 916 puts("q\tquit without saving changes"); 917 puts("r\treturn to main menu"); 918 puts("s\tchange number of sectors/track"); 919 puts("v\tverify the partition table"); 920 puts("w\twrite table to disk and exit"); 921 } 922} 923#endif /* ADVANCED mode */ 924 925#if ENABLE_FEATURE_FDISK_WRITABLE 926static const char *const * 927get_sys_types(void) 928{ 929 return ( 930 LABEL_IS_SUN ? sun_sys_types : 931 LABEL_IS_SGI ? sgi_sys_types : 932 i386_sys_types); 933} 934#else 935#define get_sys_types() i386_sys_types 936#endif 937 938static const char * 939partition_type(unsigned char type) 940{ 941 int i; 942 const char *const *types = get_sys_types(); 943 944 for (i = 0; types[i]; i++) 945 if ((unsigned char)types[i][0] == type) 946 return types[i] + 1; 947 948 return "Unknown"; 949} 950 951static int 952is_cleared_partition(const struct partition *p) 953{ 954 /* We consider partition "cleared" only if it has only zeros */ 955 const char *cp = (const char *)p; 956 int cnt = sizeof(*p); 957 char bits = 0; 958 while (--cnt >= 0) 959 bits |= *cp++; 960 return (bits == 0); 961} 962 963static void 964clear_partition(struct partition *p) 965{ 966 if (p) 967 memset(p, 0, sizeof(*p)); 968} 969 970#if ENABLE_FEATURE_FDISK_WRITABLE 971static int 972get_sysid(int i) 973{ 974 return LABEL_IS_SUN ? sunlabel->infos[i].id : 975 (LABEL_IS_SGI ? sgi_get_sysid(i) : 976 ptes[i].part_table->sys_ind); 977} 978 979static void 980list_types(const char *const *sys) 981{ 982 enum { COLS = 3 }; 983 984 unsigned last[COLS]; 985 unsigned done, next, size; 986 int i; 987 988 for (size = 0; sys[size]; size++) 989 continue; 990 991 done = 0; 992 for (i = COLS-1; i >= 0; i--) { 993 done += (size + i - done) / (i + 1); 994 last[COLS-1 - i] = done; 995 } 996 997 i = done = next = 0; 998 do { 999 printf("%c%2x %-22.22s", i ? ' ' : '\n', 1000 (unsigned char)sys[next][0], 1001 sys[next] + 1); 1002 next = last[i++] + done; 1003 if (i >= COLS || next >= last[i]) { 1004 i = 0; 1005 next = ++done; 1006 } 1007 } while (done < last[0]); 1008 bb_putchar('\n'); 1009} 1010 1011#define set_hsc(h, s, c, sector) do \ 1012{ \ 1013 s = sector % g_sectors + 1; \ 1014 sector /= g_sectors; \ 1015 h = sector % g_heads; \ 1016 sector /= g_heads; \ 1017 c = sector & 0xff; \ 1018 s |= (sector >> 2) & 0xc0; \ 1019} while (0) 1020 1021static void set_hsc_start_end(struct partition *p, sector_t start, sector_t stop) 1022{ 1023 if (dos_compatible_flag && (start / (g_sectors * g_heads) > 1023)) 1024 start = g_heads * g_sectors * 1024 - 1; 1025 set_hsc(p->head, p->sector, p->cyl, start); 1026 1027 if (dos_compatible_flag && (stop / (g_sectors * g_heads) > 1023)) 1028 stop = g_heads * g_sectors * 1024 - 1; 1029 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop); 1030} 1031 1032static void 1033set_partition(int i, int doext, sector_t start, sector_t stop, int sysid) 1034{ 1035 struct partition *p; 1036 sector_t offset; 1037 1038 if (doext) { 1039 p = ptes[i].ext_pointer; 1040 offset = extended_offset; 1041 } else { 1042 p = ptes[i].part_table; 1043 offset = ptes[i].offset_from_dev_start; 1044 } 1045 p->boot_ind = 0; 1046 p->sys_ind = sysid; 1047 set_start_sect(p, start - offset); 1048 set_nr_sects(p, stop - start + 1); 1049 set_hsc_start_end(p, start, stop); 1050 ptes[i].changed = 1; 1051} 1052#endif 1053 1054static int 1055warn_geometry(void) 1056{ 1057 if (g_heads && g_sectors && g_cylinders) 1058 return 0; 1059 1060 printf("Unknown value(s) for:"); 1061 if (!g_heads) 1062 printf(" heads"); 1063 if (!g_sectors) 1064 printf(" sectors"); 1065 if (!g_cylinders) 1066 printf(" cylinders"); 1067 printf( 1068#if ENABLE_FEATURE_FDISK_WRITABLE 1069 " (settable in the extra functions menu)" 1070#endif 1071 "\n"); 1072 return 1; 1073} 1074 1075static void 1076update_units(void) 1077{ 1078 int cyl_units = g_heads * g_sectors; 1079 1080 if (display_in_cyl_units && cyl_units) 1081 units_per_sector = cyl_units; 1082 else 1083 units_per_sector = 1; /* in sectors */ 1084} 1085 1086#if ENABLE_FEATURE_FDISK_WRITABLE 1087static void 1088warn_cylinders(void) 1089{ 1090 if (LABEL_IS_DOS && g_cylinders > 1024 && !nowarn) 1091 printf("\n" 1092"The number of cylinders for this disk is set to %u.\n" 1093"There is nothing wrong with that, but this is larger than 1024,\n" 1094"and could in certain setups cause problems with:\n" 1095"1) software that runs at boot time (e.g., old versions of LILO)\n" 1096"2) booting and partitioning software from other OSs\n" 1097" (e.g., DOS FDISK, OS/2 FDISK)\n", 1098 g_cylinders); 1099} 1100#endif 1101 1102static void 1103read_extended(int ext) 1104{ 1105 int i; 1106 struct pte *pex; 1107 struct partition *p, *q; 1108 1109 ext_index = ext; 1110 pex = &ptes[ext]; 1111 pex->ext_pointer = pex->part_table; 1112 1113 p = pex->part_table; 1114 if (!get_start_sect(p)) { 1115 printf("Bad offset in primary extended partition\n"); 1116 return; 1117 } 1118 1119 while (IS_EXTENDED(p->sys_ind)) { 1120 struct pte *pe = &ptes[g_partitions]; 1121 1122 if (g_partitions >= MAXIMUM_PARTS) { 1123 /* This is not a Linux restriction, but 1124 this program uses arrays of size MAXIMUM_PARTS. 1125 Do not try to 'improve' this test. */ 1126 struct pte *pre = &ptes[g_partitions - 1]; 1127#if ENABLE_FEATURE_FDISK_WRITABLE 1128 printf("Warning: deleting partitions after %u\n", 1129 g_partitions); 1130 pre->changed = 1; 1131#endif 1132 clear_partition(pre->ext_pointer); 1133 return; 1134 } 1135 1136 read_pte(pe, extended_offset + get_start_sect(p)); 1137 1138 if (!extended_offset) 1139 extended_offset = get_start_sect(p); 1140 1141 q = p = pt_offset(pe->sectorbuffer, 0); 1142 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) { 1143 if (IS_EXTENDED(p->sys_ind)) { 1144 if (pe->ext_pointer) 1145 printf("Warning: extra link " 1146 "pointer in partition table" 1147 " %u\n", g_partitions + 1); 1148 else 1149 pe->ext_pointer = p; 1150 } else if (p->sys_ind) { 1151 if (pe->part_table) 1152 printf("Warning: ignoring extra " 1153 "data in partition table" 1154 " %u\n", g_partitions + 1); 1155 else 1156 pe->part_table = p; 1157 } 1158 } 1159 1160 /* very strange code here... */ 1161 if (!pe->part_table) { 1162 if (q != pe->ext_pointer) 1163 pe->part_table = q; 1164 else 1165 pe->part_table = q + 1; 1166 } 1167 if (!pe->ext_pointer) { 1168 if (q != pe->part_table) 1169 pe->ext_pointer = q; 1170 else 1171 pe->ext_pointer = q + 1; 1172 } 1173 1174 p = pe->ext_pointer; 1175 g_partitions++; 1176 } 1177 1178#if ENABLE_FEATURE_FDISK_WRITABLE 1179 /* remove empty links */ 1180 remove: 1181 for (i = 4; i < g_partitions; i++) { 1182 struct pte *pe = &ptes[i]; 1183 1184 if (!get_nr_sects(pe->part_table) 1185 && (g_partitions > 5 || ptes[4].part_table->sys_ind) 1186 ) { 1187 printf("Omitting empty partition (%u)\n", i+1); 1188 delete_partition(i); 1189 goto remove; /* numbering changed */ 1190 } 1191 } 1192#endif 1193} 1194 1195#if ENABLE_FEATURE_FDISK_WRITABLE 1196static void 1197create_doslabel(void) 1198{ 1199 printf(msg_building_new_label, "DOS disklabel"); 1200 1201 current_label_type = LABEL_DOS; 1202#if ENABLE_FEATURE_OSF_LABEL 1203 possibly_osf_label = 0; 1204#endif 1205 g_partitions = 4; 1206 1207 memset(&MBRbuffer[510 - 4*16], 0, 4*16); 1208 write_part_table_flag(MBRbuffer); 1209 extended_offset = 0; 1210 set_all_unchanged(); 1211 set_changed(0); 1212 get_boot(CREATE_EMPTY_DOS); 1213} 1214#endif 1215 1216static void 1217get_sectorsize(void) 1218{ 1219 if (!user_set_sector_size) { 1220 int arg; 1221 if (ioctl(dev_fd, BLKSSZGET, &arg) == 0) 1222 sector_size = arg; 1223 if (sector_size != DEFAULT_SECTOR_SIZE) 1224 printf("Note: sector size is %u " 1225 "(not " DEFAULT_SECTOR_SIZE_STR ")\n", 1226 sector_size); 1227 } 1228} 1229 1230static void 1231get_kernel_geometry(void) 1232{ 1233 struct hd_geometry geometry; 1234 1235 if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) { 1236 kern_heads = geometry.heads; 1237 kern_sectors = geometry.sectors; 1238 /* never use geometry.cylinders - it is truncated */ 1239 } 1240} 1241 1242static void 1243get_partition_table_geometry(void) 1244{ 1245 const unsigned char *bufp = (const unsigned char *)MBRbuffer; 1246 struct partition *p; 1247 int i, h, s, hh, ss; 1248 int first = 1; 1249 int bad = 0; 1250 1251 if (!(valid_part_table_flag((char*)bufp))) 1252 return; 1253 1254 hh = ss = 0; 1255 for (i = 0; i < 4; i++) { 1256 p = pt_offset(bufp, i); 1257 if (p->sys_ind != 0) { 1258 h = p->end_head + 1; 1259 s = (p->end_sector & 077); 1260 if (first) { 1261 hh = h; 1262 ss = s; 1263 first = 0; 1264 } else if (hh != h || ss != s) 1265 bad = 1; 1266 } 1267 } 1268 1269 if (!first && !bad) { 1270 pt_heads = hh; 1271 pt_sectors = ss; 1272 } 1273} 1274 1275static void 1276get_geometry(void) 1277{ 1278 int sec_fac; 1279 1280 get_sectorsize(); 1281 sec_fac = sector_size / 512; 1282#if ENABLE_FEATURE_SUN_LABEL 1283 guess_device_type(); 1284#endif 1285 g_heads = g_cylinders = g_sectors = 0; 1286 kern_heads = kern_sectors = 0; 1287 pt_heads = pt_sectors = 0; 1288 1289 get_kernel_geometry(); 1290 get_partition_table_geometry(); 1291 1292 g_heads = user_heads ? user_heads : 1293 pt_heads ? pt_heads : 1294 kern_heads ? kern_heads : 255; 1295 g_sectors = user_sectors ? user_sectors : 1296 pt_sectors ? pt_sectors : 1297 kern_sectors ? kern_sectors : 63; 1298 total_number_of_sectors = bb_BLKGETSIZE_sectors(dev_fd); 1299 1300 sector_offset = 1; 1301 if (dos_compatible_flag) 1302 sector_offset = g_sectors; 1303 1304 g_cylinders = total_number_of_sectors / (g_heads * g_sectors * sec_fac); 1305 if (!g_cylinders) 1306 g_cylinders = user_cylinders; 1307} 1308 1309/* 1310 * Opens disk_device and optionally reads MBR. 1311 * FIXME: document what each 'what' value will do! 1312 * Returns: 1313 * -1: no 0xaa55 flag present (possibly entire disk BSD) 1314 * 0: found or created label 1315 * 1: I/O error 1316 */ 1317#if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE 1318static int get_boot(enum action what) 1319#else 1320static int get_boot(void) 1321#define get_boot(what) get_boot() 1322#endif 1323{ 1324 int i, fd; 1325 1326 g_partitions = 4; 1327 for (i = 0; i < 4; i++) { 1328 struct pte *pe = &ptes[i]; 1329 pe->part_table = pt_offset(MBRbuffer, i); 1330 pe->ext_pointer = NULL; 1331 pe->offset_from_dev_start = 0; 1332 pe->sectorbuffer = MBRbuffer; 1333#if ENABLE_FEATURE_FDISK_WRITABLE 1334 pe->changed = (what == CREATE_EMPTY_DOS); 1335#endif 1336 } 1337 1338#if ENABLE_FEATURE_FDISK_WRITABLE 1339// ALERT! highly idiotic design! 1340// We end up here when we call get_boot() recursively 1341// via get_boot() [table is bad] -> create_doslabel() -> get_boot(CREATE_EMPTY_DOS). 1342// or get_boot() [table is bad] -> create_sunlabel() -> get_boot(CREATE_EMPTY_SUN). 1343// (just factor out re-init of ptes[0,1,2,3] in a separate fn instead?) 1344// So skip opening device _again_... 1345 if (what == CREATE_EMPTY_DOS IF_FEATURE_SUN_LABEL(|| what == CREATE_EMPTY_SUN)) 1346 goto created_table; 1347 1348 fd = open(disk_device, (option_mask32 & OPT_l) ? O_RDONLY : O_RDWR); 1349 1350 if (fd < 0) { 1351 fd = open(disk_device, O_RDONLY); 1352 if (fd < 0) { 1353 if (what == TRY_ONLY) 1354 return 1; 1355 fdisk_fatal(unable_to_open); 1356 } 1357 printf("'%s' is opened for read only\n", disk_device); 1358 } 1359 xmove_fd(fd, dev_fd); 1360 if (512 != full_read(dev_fd, MBRbuffer, 512)) { 1361 if (what == TRY_ONLY) { 1362 close_dev_fd(); 1363 return 1; 1364 } 1365 fdisk_fatal(unable_to_read); 1366 } 1367#else 1368 fd = open(disk_device, O_RDONLY); 1369 if (fd < 0) 1370 return 1; 1371 if (512 != full_read(fd, MBRbuffer, 512)) { 1372 close(fd); 1373 return 1; 1374 } 1375 xmove_fd(fd, dev_fd); 1376#endif 1377 1378 get_geometry(); 1379 update_units(); 1380 1381#if ENABLE_FEATURE_SUN_LABEL 1382 if (check_sun_label()) 1383 return 0; 1384#endif 1385#if ENABLE_FEATURE_SGI_LABEL 1386 if (check_sgi_label()) 1387 return 0; 1388#endif 1389#if ENABLE_FEATURE_AIX_LABEL 1390 if (check_aix_label()) 1391 return 0; 1392#endif 1393#if ENABLE_FEATURE_OSF_LABEL 1394 if (check_osf_label()) { 1395 possibly_osf_label = 1; 1396 if (!valid_part_table_flag(MBRbuffer)) { 1397 current_label_type = LABEL_OSF; 1398 return 0; 1399 } 1400 printf("This disk has both DOS and BSD magic.\n" 1401 "Give the 'b' command to go to BSD mode.\n"); 1402 } 1403#endif 1404 1405#if !ENABLE_FEATURE_FDISK_WRITABLE 1406 if (!valid_part_table_flag(MBRbuffer)) 1407 return -1; 1408#else 1409 if (!valid_part_table_flag(MBRbuffer)) { 1410 if (what == OPEN_MAIN) { 1411 printf("Device contains neither a valid DOS " 1412 "partition table, nor Sun, SGI or OSF " 1413 "disklabel\n"); 1414#ifdef __sparc__ 1415 IF_FEATURE_SUN_LABEL(create_sunlabel();) 1416#else 1417 create_doslabel(); 1418#endif 1419 return 0; 1420 } 1421 /* TRY_ONLY: */ 1422 return -1; 1423 } 1424 created_table: 1425#endif /* FEATURE_FDISK_WRITABLE */ 1426 1427 1428 IF_FEATURE_FDISK_WRITABLE(warn_cylinders();) 1429 warn_geometry(); 1430 1431 for (i = 0; i < 4; i++) { 1432 if (IS_EXTENDED(ptes[i].part_table->sys_ind)) { 1433 if (g_partitions != 4) 1434 printf("Ignoring extra extended " 1435 "partition %u\n", i + 1); 1436 else 1437 read_extended(i); 1438 } 1439 } 1440 1441 for (i = 3; i < g_partitions; i++) { 1442 struct pte *pe = &ptes[i]; 1443 if (!valid_part_table_flag(pe->sectorbuffer)) { 1444 printf("Warning: invalid flag 0x%02x,0x%02x of partition " 1445 "table %u will be corrected by w(rite)\n", 1446 pe->sectorbuffer[510], 1447 pe->sectorbuffer[511], 1448 i + 1); 1449 IF_FEATURE_FDISK_WRITABLE(pe->changed = 1;) 1450 } 1451 } 1452 1453 return 0; 1454} 1455 1456#if ENABLE_FEATURE_FDISK_WRITABLE 1457/* 1458 * Print the message MESG, then read an integer between LOW and HIGH (inclusive). 1459 * If the user hits Enter, DFLT is returned. 1460 * Answers like +10 are interpreted as offsets from BASE. 1461 * 1462 * There is no default if DFLT is not between LOW and HIGH. 1463 */ 1464static sector_t 1465read_int(sector_t low, sector_t dflt, sector_t high, sector_t base, const char *mesg) 1466{ 1467 sector_t value; 1468 int default_ok = 1; 1469 const char *fmt = "%s (%u-%u, default %u): "; 1470 1471 if (dflt < low || dflt > high) { 1472 fmt = "%s (%u-%u): "; 1473 default_ok = 0; 1474 } 1475 1476 while (1) { 1477 int use_default = default_ok; 1478 1479 /* ask question and read answer */ 1480 do { 1481 printf(fmt, mesg, low, high, dflt); 1482 read_maybe_empty(""); 1483 } while (*line_ptr != '\n' && !isdigit(*line_ptr) 1484 && *line_ptr != '-' && *line_ptr != '+'); 1485 1486 if (*line_ptr == '+' || *line_ptr == '-') { 1487 int minus = (*line_ptr == '-'); 1488 int absolute = 0; 1489 1490 value = atoi(line_ptr + 1); 1491 1492 /* (1) if 2nd char is digit, use_default = 0. 1493 * (2) move line_ptr to first non-digit. */ 1494 while (isdigit(*++line_ptr)) 1495 use_default = 0; 1496 1497 switch (*line_ptr) { 1498 case 'c': 1499 case 'C': 1500 if (!display_in_cyl_units) 1501 value *= g_heads * g_sectors; 1502 break; 1503 case 'K': 1504 absolute = 1024; 1505 break; 1506 case 'k': 1507 absolute = 1000; 1508 break; 1509 case 'm': 1510 case 'M': 1511 absolute = 1000000; 1512 break; 1513 case 'g': 1514 case 'G': 1515 absolute = 1000000000; 1516 break; 1517 default: 1518 break; 1519 } 1520 if (absolute) { 1521 ullong bytes; 1522 unsigned long unit; 1523 1524 bytes = (ullong) value * absolute; 1525 unit = sector_size * units_per_sector; 1526 bytes += unit/2; /* round */ 1527 bytes /= unit; 1528 value = bytes; 1529 } 1530 if (minus) 1531 value = -value; 1532 value += base; 1533 } else { 1534 value = atoi(line_ptr); 1535 while (isdigit(*line_ptr)) { 1536 line_ptr++; 1537 use_default = 0; 1538 } 1539 } 1540 if (use_default) { 1541 value = dflt; 1542 printf("Using default value %u\n", value); 1543 } 1544 if (value >= low && value <= high) 1545 break; 1546 printf("Value is out of range\n"); 1547 } 1548 return value; 1549} 1550 1551static unsigned 1552get_partition(int warn, unsigned max) 1553{ 1554 struct pte *pe; 1555 unsigned i; 1556 1557 i = read_int(1, 0, max, 0, "Partition number") - 1; 1558 pe = &ptes[i]; 1559 1560 if (warn) { 1561 if ((!LABEL_IS_SUN && !LABEL_IS_SGI && !pe->part_table->sys_ind) 1562 || (LABEL_IS_SUN && (!sunlabel->partitions[i].num_sectors || !sunlabel->infos[i].id)) 1563 || (LABEL_IS_SGI && !sgi_get_num_sectors(i)) 1564 ) { 1565 printf("Warning: partition %u has empty type\n", i+1); 1566 } 1567 } 1568 return i; 1569} 1570 1571static int 1572get_existing_partition(int warn, unsigned max) 1573{ 1574 int pno = -1; 1575 unsigned i; 1576 1577 for (i = 0; i < max; i++) { 1578 struct pte *pe = &ptes[i]; 1579 struct partition *p = pe->part_table; 1580 1581 if (p && !is_cleared_partition(p)) { 1582 if (pno >= 0) 1583 goto not_unique; 1584 pno = i; 1585 } 1586 } 1587 if (pno >= 0) { 1588 printf("Selected partition %u\n", pno+1); 1589 return pno; 1590 } 1591 printf("No partition is defined yet!\n"); 1592 return -1; 1593 1594 not_unique: 1595 return get_partition(warn, max); 1596} 1597 1598static int 1599get_nonexisting_partition(int warn, unsigned max) 1600{ 1601 int pno = -1; 1602 unsigned i; 1603 1604 for (i = 0; i < max; i++) { 1605 struct pte *pe = &ptes[i]; 1606 struct partition *p = pe->part_table; 1607 1608 if (p && is_cleared_partition(p)) { 1609 if (pno >= 0) 1610 goto not_unique; 1611 pno = i; 1612 } 1613 } 1614 if (pno >= 0) { 1615 printf("Selected partition %u\n", pno+1); 1616 return pno; 1617 } 1618 printf("All primary partitions have been defined already!\n"); 1619 return -1; 1620 1621 not_unique: 1622 return get_partition(warn, max); 1623} 1624 1625 1626static void 1627change_units(void) 1628{ 1629 display_in_cyl_units = !display_in_cyl_units; 1630 update_units(); 1631 printf("Changing display/entry units to %s\n", 1632 str_units(PLURAL)); 1633} 1634 1635static void 1636toggle_active(int i) 1637{ 1638 struct pte *pe = &ptes[i]; 1639 struct partition *p = pe->part_table; 1640 1641 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind) 1642 printf("WARNING: Partition %u is an extended partition\n", i + 1); 1643 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG); 1644 pe->changed = 1; 1645} 1646 1647static void 1648toggle_dos_compatibility_flag(void) 1649{ 1650 dos_compatible_flag = 1 - dos_compatible_flag; 1651 if (dos_compatible_flag) { 1652 sector_offset = g_sectors; 1653 printf("DOS Compatibility flag is set\n"); 1654 } else { 1655 sector_offset = 1; 1656 printf("DOS Compatibility flag is not set\n"); 1657 } 1658} 1659 1660static void 1661delete_partition(int i) 1662{ 1663 struct pte *pe = &ptes[i]; 1664 struct partition *p = pe->part_table; 1665 struct partition *q = pe->ext_pointer; 1666 1667/* Note that for the fifth partition (i == 4) we don't actually 1668 * decrement partitions. 1669 */ 1670 1671 if (warn_geometry()) 1672 return; /* C/H/S not set */ 1673 pe->changed = 1; 1674 1675 if (LABEL_IS_SUN) { 1676 sun_delete_partition(i); 1677 return; 1678 } 1679 if (LABEL_IS_SGI) { 1680 sgi_delete_partition(i); 1681 return; 1682 } 1683 1684 if (i < 4) { 1685 if (IS_EXTENDED(p->sys_ind) && i == ext_index) { 1686 g_partitions = 4; 1687 ptes[ext_index].ext_pointer = NULL; 1688 extended_offset = 0; 1689 } 1690 clear_partition(p); 1691 return; 1692 } 1693 1694 if (!q->sys_ind && i > 4) { 1695 /* the last one in the chain - just delete */ 1696 --g_partitions; 1697 --i; 1698 clear_partition(ptes[i].ext_pointer); 1699 ptes[i].changed = 1; 1700 } else { 1701 /* not the last one - further ones will be moved down */ 1702 if (i > 4) { 1703 /* delete this link in the chain */ 1704 p = ptes[i-1].ext_pointer; 1705 *p = *q; 1706 set_start_sect(p, get_start_sect(q)); 1707 set_nr_sects(p, get_nr_sects(q)); 1708 ptes[i-1].changed = 1; 1709 } else if (g_partitions > 5) { /* 5 will be moved to 4 */ 1710 /* the first logical in a longer chain */ 1711 pe = &ptes[5]; 1712 1713 if (pe->part_table) /* prevent SEGFAULT */ 1714 set_start_sect(pe->part_table, 1715 get_partition_start_from_dev_start(pe) - 1716 extended_offset); 1717 pe->offset_from_dev_start = extended_offset; 1718 pe->changed = 1; 1719 } 1720 1721 if (g_partitions > 5) { 1722 g_partitions--; 1723 while (i < g_partitions) { 1724 ptes[i] = ptes[i+1]; 1725 i++; 1726 } 1727 } else { 1728 /* the only logical: clear only */ 1729 clear_partition(ptes[i].part_table); 1730 } 1731 } 1732} 1733 1734static void 1735change_sysid(void) 1736{ 1737 int i, sys, origsys; 1738 struct partition *p; 1739 1740 /* If sgi_label then don't use get_existing_partition, 1741 let the user select a partition, since get_existing_partition() 1742 only works for Linux like partition tables. */ 1743 if (!LABEL_IS_SGI) { 1744 i = get_existing_partition(0, g_partitions); 1745 } else { 1746 i = get_partition(0, g_partitions); 1747 } 1748 if (i == -1) 1749 return; 1750 p = ptes[i].part_table; 1751 origsys = sys = get_sysid(i); 1752 1753 /* if changing types T to 0 is allowed, then 1754 the reverse change must be allowed, too */ 1755 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN && !get_nr_sects(p)) { 1756 printf("Partition %u does not exist yet!\n", i + 1); 1757 return; 1758 } 1759 while (1) { 1760 sys = read_hex(get_sys_types()); 1761 1762 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN) { 1763 printf("Type 0 means free space to many systems\n" 1764 "(but not to Linux). Having partitions of\n" 1765 "type 0 is probably unwise.\n"); 1766 /* break; */ 1767 } 1768 1769 if (!LABEL_IS_SUN && !LABEL_IS_SGI) { 1770 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) { 1771 printf("You cannot change a partition into" 1772 " an extended one or vice versa\n"); 1773 break; 1774 } 1775 } 1776 1777 if (sys < 256) { 1778#if ENABLE_FEATURE_SUN_LABEL 1779 if (LABEL_IS_SUN && i == 2 && sys != SUN_WHOLE_DISK) 1780 printf("Consider leaving partition 3 " 1781 "as Whole disk (5),\n" 1782 "as SunOS/Solaris expects it and " 1783 "even Linux likes it\n\n"); 1784#endif 1785#if ENABLE_FEATURE_SGI_LABEL 1786 if (LABEL_IS_SGI && 1787 ( 1788 (i == 10 && sys != SGI_ENTIRE_DISK) || 1789 (i == 8 && sys != 0) 1790 ) 1791 ) { 1792 printf("Consider leaving partition 9 " 1793 "as volume header (0),\nand " 1794 "partition 11 as entire volume (6)" 1795 "as IRIX expects it\n\n"); 1796 } 1797#endif 1798 if (sys == origsys) 1799 break; 1800 if (LABEL_IS_SUN) { 1801 sun_change_sysid(i, sys); 1802 } else if (LABEL_IS_SGI) { 1803 sgi_change_sysid(i, sys); 1804 } else 1805 p->sys_ind = sys; 1806 1807 printf("Changed system type of partition %u " 1808 "to %x (%s)\n", i + 1, sys, 1809 partition_type(sys)); 1810 ptes[i].changed = 1; 1811 //if (is_dos_partition(origsys) || is_dos_partition(sys)) 1812 // dos_changed = 1; 1813 break; 1814 } 1815 } 1816} 1817#endif /* FEATURE_FDISK_WRITABLE */ 1818 1819 1820/* check_consistency() and linear2chs() added Sat Mar 6 12:28:16 1993, 1821 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross, 1822 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S. 1823 * Lubkin Oct. 1991). */ 1824 1825static void 1826linear2chs(unsigned ls, unsigned *c, unsigned *h, unsigned *s) 1827{ 1828 int spc = g_heads * g_sectors; 1829 1830 *c = ls / spc; 1831 ls = ls % spc; 1832 *h = ls / g_sectors; 1833 *s = ls % g_sectors + 1; /* sectors count from 1 */ 1834} 1835 1836static void 1837check_consistency(const struct partition *p, int partition) 1838{ 1839 unsigned pbc, pbh, pbs; /* physical beginning c, h, s */ 1840 unsigned pec, peh, pes; /* physical ending c, h, s */ 1841 unsigned lbc, lbh, lbs; /* logical beginning c, h, s */ 1842 unsigned lec, leh, les; /* logical ending c, h, s */ 1843 1844 if (!g_heads || !g_sectors || (partition >= 4)) 1845 return; /* do not check extended partitions */ 1846 1847/* physical beginning c, h, s */ 1848 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300); 1849 pbh = p->head; 1850 pbs = p->sector & 0x3f; 1851 1852/* physical ending c, h, s */ 1853 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300); 1854 peh = p->end_head; 1855 pes = p->end_sector & 0x3f; 1856 1857/* compute logical beginning (c, h, s) */ 1858 linear2chs(get_start_sect(p), &lbc, &lbh, &lbs); 1859 1860/* compute logical ending (c, h, s) */ 1861 linear2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les); 1862 1863/* Same physical / logical beginning? */ 1864 if (g_cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) { 1865 printf("Partition %u has different physical/logical " 1866 "beginnings (non-Linux?):\n", partition + 1); 1867 printf(" phys=(%u, %u, %u) ", pbc, pbh, pbs); 1868 printf("logical=(%u, %u, %u)\n", lbc, lbh, lbs); 1869 } 1870 1871/* Same physical / logical ending? */ 1872 if (g_cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) { 1873 printf("Partition %u has different physical/logical " 1874 "endings:\n", partition + 1); 1875 printf(" phys=(%u, %u, %u) ", pec, peh, pes); 1876 printf("logical=(%u, %u, %u)\n", lec, leh, les); 1877 } 1878 1879/* Ending on cylinder boundary? */ 1880 if (peh != (g_heads - 1) || pes != g_sectors) { 1881 printf("Partition %u does not end on cylinder boundary\n", 1882 partition + 1); 1883 } 1884} 1885 1886static void 1887list_disk_geometry(void) 1888{ 1889 ullong bytes = ((ullong)total_number_of_sectors << 9); 1890 long megabytes = bytes / 1000000; 1891 1892 if (megabytes < 10000) 1893 printf("\nDisk %s: %lu MB, %llu bytes\n", 1894 disk_device, megabytes, bytes); 1895 else 1896 printf("\nDisk %s: %lu.%lu GB, %llu bytes\n", 1897 disk_device, megabytes/1000, (megabytes/100)%10, bytes); 1898 printf("%u heads, %u sectors/track, %u cylinders", 1899 g_heads, g_sectors, g_cylinders); 1900 if (units_per_sector == 1) 1901 printf(", total %"SECT_FMT"u sectors", 1902 total_number_of_sectors / (sector_size/512)); 1903 printf("\nUnits = %s of %u * %u = %u bytes\n\n", 1904 str_units(PLURAL), 1905 units_per_sector, sector_size, units_per_sector * sector_size); 1906} 1907 1908/* 1909 * Check whether partition entries are ordered by their starting positions. 1910 * Return 0 if OK. Return i if partition i should have been earlier. 1911 * Two separate checks: primary and logical partitions. 1912 */ 1913static int 1914wrong_p_order(int *prev) 1915{ 1916 const struct pte *pe; 1917 const struct partition *p; 1918 sector_t last_p_start_pos = 0, p_start_pos; 1919 unsigned i, last_i = 0; 1920 1921 for (i = 0; i < g_partitions; i++) { 1922 if (i == 4) { 1923 last_i = 4; 1924 last_p_start_pos = 0; 1925 } 1926 pe = &ptes[i]; 1927 p = pe->part_table; 1928 if (p->sys_ind) { 1929 p_start_pos = get_partition_start_from_dev_start(pe); 1930 1931 if (last_p_start_pos > p_start_pos) { 1932 if (prev) 1933 *prev = last_i; 1934 return i; 1935 } 1936 1937 last_p_start_pos = p_start_pos; 1938 last_i = i; 1939 } 1940 } 1941 return 0; 1942} 1943 1944#if ENABLE_FEATURE_FDISK_ADVANCED 1945/* 1946 * Fix the chain of logicals. 1947 * extended_offset is unchanged, the set of sectors used is unchanged 1948 * The chain is sorted so that sectors increase, and so that 1949 * starting sectors increase. 1950 * 1951 * After this it may still be that cfdisk doesnt like the table. 1952 * (This is because cfdisk considers expanded parts, from link to 1953 * end of partition, and these may still overlap.) 1954 * Now 1955 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda 1956 * may help. 1957 */ 1958static void 1959fix_chain_of_logicals(void) 1960{ 1961 int j, oj, ojj, sj, sjj; 1962 struct partition *pj,*pjj,tmp; 1963 1964 /* Stage 1: sort sectors but leave sector of part 4 */ 1965 /* (Its sector is the global extended_offset.) */ 1966 stage1: 1967 for (j = 5; j < g_partitions - 1; j++) { 1968 oj = ptes[j].offset_from_dev_start; 1969 ojj = ptes[j+1].offset_from_dev_start; 1970 if (oj > ojj) { 1971 ptes[j].offset_from_dev_start = ojj; 1972 ptes[j+1].offset_from_dev_start = oj; 1973 pj = ptes[j].part_table; 1974 set_start_sect(pj, get_start_sect(pj)+oj-ojj); 1975 pjj = ptes[j+1].part_table; 1976 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj); 1977 set_start_sect(ptes[j-1].ext_pointer, 1978 ojj-extended_offset); 1979 set_start_sect(ptes[j].ext_pointer, 1980 oj-extended_offset); 1981 goto stage1; 1982 } 1983 } 1984 1985 /* Stage 2: sort starting sectors */ 1986 stage2: 1987 for (j = 4; j < g_partitions - 1; j++) { 1988 pj = ptes[j].part_table; 1989 pjj = ptes[j+1].part_table; 1990 sj = get_start_sect(pj); 1991 sjj = get_start_sect(pjj); 1992 oj = ptes[j].offset_from_dev_start; 1993 ojj = ptes[j+1].offset_from_dev_start; 1994 if (oj+sj > ojj+sjj) { 1995 tmp = *pj; 1996 *pj = *pjj; 1997 *pjj = tmp; 1998 set_start_sect(pj, ojj+sjj-oj); 1999 set_start_sect(pjj, oj+sj-ojj); 2000 goto stage2; 2001 } 2002 } 2003 2004 /* Probably something was changed */ 2005 for (j = 4; j < g_partitions; j++) 2006 ptes[j].changed = 1; 2007} 2008 2009 2010static void 2011fix_partition_table_order(void) 2012{ 2013 struct pte *pei, *pek; 2014 int i,k; 2015 2016 if (!wrong_p_order(NULL)) { 2017 printf("Ordering is already correct\n\n"); 2018 return; 2019 } 2020 2021 while ((i = wrong_p_order(&k)) != 0 && i < 4) { 2022 /* partition i should have come earlier, move it */ 2023 /* We have to move data in the MBR */ 2024 struct partition *pi, *pk, *pe, pbuf; 2025 pei = &ptes[i]; 2026 pek = &ptes[k]; 2027 2028 pe = pei->ext_pointer; 2029 pei->ext_pointer = pek->ext_pointer; 2030 pek->ext_pointer = pe; 2031 2032 pi = pei->part_table; 2033 pk = pek->part_table; 2034 2035 memmove(&pbuf, pi, sizeof(struct partition)); 2036 memmove(pi, pk, sizeof(struct partition)); 2037 memmove(pk, &pbuf, sizeof(struct partition)); 2038 2039 pei->changed = pek->changed = 1; 2040 } 2041 2042 if (i) 2043 fix_chain_of_logicals(); 2044 2045 printf("Done.\n"); 2046 2047} 2048#endif 2049 2050static void 2051list_table(int xtra) 2052{ 2053 const struct partition *p; 2054 int i, w; 2055 2056 if (LABEL_IS_SUN) { 2057 sun_list_table(xtra); 2058 return; 2059 } 2060 if (LABEL_IS_SUN) { 2061 sgi_list_table(xtra); 2062 return; 2063 } 2064 2065 list_disk_geometry(); 2066 2067 if (LABEL_IS_OSF) { 2068 xbsd_print_disklabel(xtra); 2069 return; 2070 } 2071 2072 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3, 2073 but if the device name ends in a digit, say /dev/foo1, 2074 then the partition is called /dev/foo1p3. */ 2075 w = strlen(disk_device); 2076 if (w && isdigit(disk_device[w-1])) 2077 w++; 2078 if (w < 5) 2079 w = 5; 2080 2081 // 1 12345678901 12345678901 12345678901 12 2082 printf("%*s Boot Start End Blocks Id System\n", 2083 w+1, "Device"); 2084 2085 for (i = 0; i < g_partitions; i++) { 2086 const struct pte *pe = &ptes[i]; 2087 sector_t psects; 2088 sector_t pblocks; 2089 unsigned podd; 2090 2091 p = pe->part_table; 2092 if (!p || is_cleared_partition(p)) 2093 continue; 2094 2095 psects = get_nr_sects(p); 2096 pblocks = psects; 2097 podd = 0; 2098 2099 if (sector_size < 1024) { 2100 pblocks /= (1024 / sector_size); 2101 podd = psects % (1024 / sector_size); 2102 } 2103 if (sector_size > 1024) 2104 pblocks *= (sector_size / 1024); 2105 2106 printf("%s %c %11"SECT_FMT"u %11"SECT_FMT"u %11"SECT_FMT"u%c %2x %s\n", 2107 partname(disk_device, i+1, w+2), 2108 !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG /* boot flag */ 2109 ? '*' : '?', 2110 cround(get_partition_start_from_dev_start(pe)), /* start */ 2111 cround(get_partition_start_from_dev_start(pe) + psects /* end */ 2112 - (psects ? 1 : 0)), 2113 pblocks, podd ? '+' : ' ', /* odd flag on end */ 2114 p->sys_ind, /* type id */ 2115 partition_type(p->sys_ind)); /* type name */ 2116 2117 check_consistency(p, i); 2118 } 2119 2120 /* Is partition table in disk order? It need not be, but... */ 2121 /* partition table entries are not checked for correct order 2122 * if this is a sgi, sun or aix labeled disk... */ 2123 if (LABEL_IS_DOS && wrong_p_order(NULL)) { 2124 /* FIXME */ 2125 printf("\nPartition table entries are not in disk order\n"); 2126 } 2127} 2128 2129#if ENABLE_FEATURE_FDISK_ADVANCED 2130static void 2131x_list_table(int extend) 2132{ 2133 const struct pte *pe; 2134 const struct partition *p; 2135 int i; 2136 2137 printf("\nDisk %s: %u heads, %u sectors, %u cylinders\n\n", 2138 disk_device, g_heads, g_sectors, g_cylinders); 2139 printf("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n"); 2140 for (i = 0; i < g_partitions; i++) { 2141 pe = &ptes[i]; 2142 p = (extend ? pe->ext_pointer : pe->part_table); 2143 if (p != NULL) { 2144 printf("%2u %02x%4u%4u%5u%4u%4u%5u%11"SECT_FMT"u%11"SECT_FMT"u %02x\n", 2145 i + 1, p->boot_ind, p->head, 2146 sector(p->sector), 2147 cylinder(p->sector, p->cyl), p->end_head, 2148 sector(p->end_sector), 2149 cylinder(p->end_sector, p->end_cyl), 2150 get_start_sect(p), get_nr_sects(p), 2151 p->sys_ind); 2152 if (p->sys_ind) 2153 check_consistency(p, i); 2154 } 2155 } 2156} 2157#endif 2158 2159#if ENABLE_FEATURE_FDISK_WRITABLE 2160static void 2161fill_bounds(sector_t *first, sector_t *last) 2162{ 2163 unsigned i; 2164 const struct pte *pe = &ptes[0]; 2165 const struct partition *p; 2166 2167 for (i = 0; i < g_partitions; pe++,i++) { 2168 p = pe->part_table; 2169 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) { 2170 first[i] = 0xffffffff; 2171 last[i] = 0; 2172 } else { 2173 first[i] = get_partition_start_from_dev_start(pe); 2174 last[i] = first[i] + get_nr_sects(p) - 1; 2175 } 2176 } 2177} 2178 2179static void 2180check(int n, unsigned h, unsigned s, unsigned c, sector_t start) 2181{ 2182 sector_t total, real_s, real_c; 2183 2184 real_s = sector(s) - 1; 2185 real_c = cylinder(s, c); 2186 total = (real_c * g_sectors + real_s) * g_heads + h; 2187 if (!total) 2188 printf("Partition %u contains sector 0\n", n); 2189 if (h >= g_heads) 2190 printf("Partition %u: head %u greater than maximum %u\n", 2191 n, h + 1, g_heads); 2192 if (real_s >= g_sectors) 2193 printf("Partition %u: sector %u greater than " 2194 "maximum %u\n", n, s, g_sectors); 2195 if (real_c >= g_cylinders) 2196 printf("Partition %u: cylinder %"SECT_FMT"u greater than " 2197 "maximum %u\n", n, real_c + 1, g_cylinders); 2198 if (g_cylinders <= 1024 && start != total) 2199 printf("Partition %u: previous sectors %"SECT_FMT"u disagrees with " 2200 "total %"SECT_FMT"u\n", n, start, total); 2201} 2202 2203static void 2204verify(void) 2205{ 2206 int i, j; 2207 sector_t total = 1; 2208 sector_t first[g_partitions], last[g_partitions]; 2209 struct partition *p; 2210 2211 if (warn_geometry()) 2212 return; 2213 2214 if (LABEL_IS_SUN) { 2215 verify_sun(); 2216 return; 2217 } 2218 if (LABEL_IS_SGI) { 2219 verify_sgi(1); 2220 return; 2221 } 2222 2223 fill_bounds(first, last); 2224 for (i = 0; i < g_partitions; i++) { 2225 struct pte *pe = &ptes[i]; 2226 2227 p = pe->part_table; 2228 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) { 2229 check_consistency(p, i); 2230 if (get_partition_start_from_dev_start(pe) < first[i]) 2231 printf("Warning: bad start-of-data in " 2232 "partition %u\n", i + 1); 2233 check(i + 1, p->end_head, p->end_sector, p->end_cyl, 2234 last[i]); 2235 total += last[i] + 1 - first[i]; 2236 for (j = 0; j < i; j++) { 2237 if ((first[i] >= first[j] && first[i] <= last[j]) 2238 || ((last[i] <= last[j] && last[i] >= first[j]))) { 2239 printf("Warning: partition %u overlaps " 2240 "partition %u\n", j + 1, i + 1); 2241 total += first[i] >= first[j] ? 2242 first[i] : first[j]; 2243 total -= last[i] <= last[j] ? 2244 last[i] : last[j]; 2245 } 2246 } 2247 } 2248 } 2249 2250 if (extended_offset) { 2251 struct pte *pex = &ptes[ext_index]; 2252 sector_t e_last = get_start_sect(pex->part_table) + 2253 get_nr_sects(pex->part_table) - 1; 2254 2255 for (i = 4; i < g_partitions; i++) { 2256 total++; 2257 p = ptes[i].part_table; 2258 if (!p->sys_ind) { 2259 if (i != 4 || i + 1 < g_partitions) 2260 printf("Warning: partition %u " 2261 "is empty\n", i + 1); 2262 } else if (first[i] < extended_offset || last[i] > e_last) { 2263 printf("Logical partition %u not entirely in " 2264 "partition %u\n", i + 1, ext_index + 1); 2265 } 2266 } 2267 } 2268 2269 if (total > g_heads * g_sectors * g_cylinders) 2270 printf("Total allocated sectors %u greater than the maximum " 2271 "%u\n", total, g_heads * g_sectors * g_cylinders); 2272 else { 2273 total = g_heads * g_sectors * g_cylinders - total; 2274 if (total != 0) 2275 printf("%"SECT_FMT"u unallocated sectors\n", total); 2276 } 2277} 2278 2279static void 2280add_partition(int n, int sys) 2281{ 2282 char mesg[256]; /* 48 does not suffice in Japanese */ 2283 int i, num_read = 0; 2284 struct partition *p = ptes[n].part_table; 2285 struct partition *q = ptes[ext_index].part_table; 2286 sector_t limit, temp; 2287 sector_t start, stop = 0; 2288 sector_t first[g_partitions], last[g_partitions]; 2289 2290 if (p && p->sys_ind) { 2291 printf(msg_part_already_defined, n + 1); 2292 return; 2293 } 2294 fill_bounds(first, last); 2295 if (n < 4) { 2296 start = sector_offset; 2297 if (display_in_cyl_units || !total_number_of_sectors) 2298 limit = (sector_t) g_heads * g_sectors * g_cylinders - 1; 2299 else 2300 limit = total_number_of_sectors - 1; 2301 if (extended_offset) { 2302 first[ext_index] = extended_offset; 2303 last[ext_index] = get_start_sect(q) + 2304 get_nr_sects(q) - 1; 2305 } 2306 } else { 2307 start = extended_offset + sector_offset; 2308 limit = get_start_sect(q) + get_nr_sects(q) - 1; 2309 } 2310 if (display_in_cyl_units) 2311 for (i = 0; i < g_partitions; i++) 2312 first[i] = (cround(first[i]) - 1) * units_per_sector; 2313 2314 snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR)); 2315 do { 2316 temp = start; 2317 for (i = 0; i < g_partitions; i++) { 2318 int lastplusoff; 2319 2320 if (start == ptes[i].offset_from_dev_start) 2321 start += sector_offset; 2322 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset); 2323 if (start >= first[i] && start <= lastplusoff) 2324 start = lastplusoff + 1; 2325 } 2326 if (start > limit) 2327 break; 2328 if (start >= temp+units_per_sector && num_read) { 2329 printf("Sector %"SECT_FMT"u is already allocated\n", temp); 2330 temp = start; 2331 num_read = 0; 2332 } 2333 if (!num_read && start == temp) { 2334 sector_t saved_start; 2335 2336 saved_start = start; 2337 start = read_int(cround(saved_start), cround(saved_start), cround(limit), 0, mesg); 2338 if (display_in_cyl_units) { 2339 start = (start - 1) * units_per_sector; 2340 if (start < saved_start) 2341 start = saved_start; 2342 } 2343 num_read = 1; 2344 } 2345 } while (start != temp || !num_read); 2346 if (n > 4) { /* NOT for fifth partition */ 2347 struct pte *pe = &ptes[n]; 2348 2349 pe->offset_from_dev_start = start - sector_offset; 2350 if (pe->offset_from_dev_start == extended_offset) { /* must be corrected */ 2351 pe->offset_from_dev_start++; 2352 if (sector_offset == 1) 2353 start++; 2354 } 2355 } 2356 2357 for (i = 0; i < g_partitions; i++) { 2358 struct pte *pe = &ptes[i]; 2359 2360 if (start < pe->offset_from_dev_start && limit >= pe->offset_from_dev_start) 2361 limit = pe->offset_from_dev_start - 1; 2362 if (start < first[i] && limit >= first[i]) 2363 limit = first[i] - 1; 2364 } 2365 if (start > limit) { 2366 printf("No free sectors available\n"); 2367 if (n > 4) 2368 g_partitions--; 2369 return; 2370 } 2371 if (cround(start) == cround(limit)) { 2372 stop = limit; 2373 } else { 2374 snprintf(mesg, sizeof(mesg), 2375 "Last %s or +size or +sizeM or +sizeK", 2376 str_units(SINGULAR)); 2377 stop = read_int(cround(start), cround(limit), cround(limit), cround(start), mesg); 2378 if (display_in_cyl_units) { 2379 stop = stop * units_per_sector - 1; 2380 if (stop >limit) 2381 stop = limit; 2382 } 2383 } 2384 2385 set_partition(n, 0, start, stop, sys); 2386 if (n > 4) 2387 set_partition(n - 1, 1, ptes[n].offset_from_dev_start, stop, EXTENDED); 2388 2389 if (IS_EXTENDED(sys)) { 2390 struct pte *pe4 = &ptes[4]; 2391 struct pte *pen = &ptes[n]; 2392 2393 ext_index = n; 2394 pen->ext_pointer = p; 2395 pe4->offset_from_dev_start = extended_offset = start; 2396 pe4->sectorbuffer = xzalloc(sector_size); 2397 pe4->part_table = pt_offset(pe4->sectorbuffer, 0); 2398 pe4->ext_pointer = pe4->part_table + 1; 2399 pe4->changed = 1; 2400 g_partitions = 5; 2401 } 2402} 2403 2404static void 2405add_logical(void) 2406{ 2407 if (g_partitions > 5 || ptes[4].part_table->sys_ind) { 2408 struct pte *pe = &ptes[g_partitions]; 2409 2410 pe->sectorbuffer = xzalloc(sector_size); 2411 pe->part_table = pt_offset(pe->sectorbuffer, 0); 2412 pe->ext_pointer = pe->part_table + 1; 2413 pe->offset_from_dev_start = 0; 2414 pe->changed = 1; 2415 g_partitions++; 2416 } 2417 add_partition(g_partitions - 1, LINUX_NATIVE); 2418} 2419 2420static void 2421new_partition(void) 2422{ 2423 int i, free_primary = 0; 2424 2425 if (warn_geometry()) 2426 return; 2427 2428 if (LABEL_IS_SUN) { 2429 add_sun_partition(get_partition(0, g_partitions), LINUX_NATIVE); 2430 return; 2431 } 2432 if (LABEL_IS_SGI) { 2433 sgi_add_partition(get_partition(0, g_partitions), LINUX_NATIVE); 2434 return; 2435 } 2436 if (LABEL_IS_AIX) { 2437 printf("Sorry - this fdisk cannot handle AIX disk labels.\n" 2438"If you want to add DOS-type partitions, create a new empty DOS partition\n" 2439"table first (use 'o'). This will destroy the present disk contents.\n"); 2440 return; 2441 } 2442 2443 for (i = 0; i < 4; i++) 2444 free_primary += !ptes[i].part_table->sys_ind; 2445 2446 if (!free_primary && g_partitions >= MAXIMUM_PARTS) { 2447 printf("The maximum number of partitions has been created\n"); 2448 return; 2449 } 2450 2451 if (!free_primary) { 2452 if (extended_offset) 2453 add_logical(); 2454 else 2455 printf("You must delete some partition and add " 2456 "an extended partition first\n"); 2457 } else { 2458 char c, line[80]; 2459 snprintf(line, sizeof(line), 2460 "Command action\n" 2461 " %s\n" 2462 " p primary partition (1-4)\n", 2463 (extended_offset ? 2464 "l logical (5 or over)" : "e extended")); 2465 while (1) { 2466 c = read_nonempty(line); 2467 if ((c | 0x20) == 'p') { 2468 i = get_nonexisting_partition(0, 4); 2469 if (i >= 0) 2470 add_partition(i, LINUX_NATIVE); 2471 return; 2472 } 2473 if (c == 'l' && extended_offset) { 2474 add_logical(); 2475 return; 2476 } 2477 if (c == 'e' && !extended_offset) { 2478 i = get_nonexisting_partition(0, 4); 2479 if (i >= 0) 2480 add_partition(i, EXTENDED); 2481 return; 2482 } 2483 printf("Invalid partition number " 2484 "for type '%c'\n", c); 2485 } 2486 } 2487} 2488 2489static void 2490write_table(void) 2491{ 2492 int i; 2493 2494 if (LABEL_IS_DOS) { 2495 for (i = 0; i < 3; i++) 2496 if (ptes[i].changed) 2497 ptes[3].changed = 1; 2498 for (i = 3; i < g_partitions; i++) { 2499 struct pte *pe = &ptes[i]; 2500 2501 if (pe->changed) { 2502 write_part_table_flag(pe->sectorbuffer); 2503 write_sector(pe->offset_from_dev_start, pe->sectorbuffer); 2504 } 2505 } 2506 } 2507 else if (LABEL_IS_SGI) { 2508 /* no test on change? the printf below might be mistaken */ 2509 sgi_write_table(); 2510 } 2511 else if (LABEL_IS_SUN) { 2512 int needw = 0; 2513 2514 for (i = 0; i < 8; i++) 2515 if (ptes[i].changed) 2516 needw = 1; 2517 if (needw) 2518 sun_write_table(); 2519 } 2520 2521 printf("The partition table has been altered!\n\n"); 2522 reread_partition_table(1); 2523} 2524 2525static void 2526reread_partition_table(int leave) 2527{ 2528 int i; 2529 2530 printf("Calling ioctl() to re-read partition table\n"); 2531 sync(); 2532 /* sleep(2); Huh? */ 2533 i = ioctl_or_perror(dev_fd, BLKRRPART, NULL, 2534 "WARNING: rereading partition table " 2535 "failed, kernel still uses old table"); 2536#if 0 2537 if (dos_changed) 2538 printf( 2539 "\nWARNING: If you have created or modified any DOS 6.x\n" 2540 "partitions, please see the fdisk manual page for additional\n" 2541 "information\n"); 2542#endif 2543 2544 if (leave) { 2545 if (ENABLE_FEATURE_CLEAN_UP) 2546 close_dev_fd(); 2547 exit(i != 0); 2548 } 2549} 2550#endif /* FEATURE_FDISK_WRITABLE */ 2551 2552#if ENABLE_FEATURE_FDISK_ADVANCED 2553#define MAX_PER_LINE 16 2554static void 2555print_buffer(char *pbuffer) 2556{ 2557 int i,l; 2558 2559 for (i = 0, l = 0; i < sector_size; i++, l++) { 2560 if (l == 0) 2561 printf("0x%03X:", i); 2562 printf(" %02X", (unsigned char) pbuffer[i]); 2563 if (l == MAX_PER_LINE - 1) { 2564 bb_putchar('\n'); 2565 l = -1; 2566 } 2567 } 2568 if (l > 0) 2569 bb_putchar('\n'); 2570 bb_putchar('\n'); 2571} 2572 2573static void 2574print_raw(void) 2575{ 2576 int i; 2577 2578 printf("Device: %s\n", disk_device); 2579 if (LABEL_IS_SGI || LABEL_IS_SUN) 2580 print_buffer(MBRbuffer); 2581 else { 2582 for (i = 3; i < g_partitions; i++) 2583 print_buffer(ptes[i].sectorbuffer); 2584 } 2585} 2586 2587static void 2588move_begin(unsigned i) 2589{ 2590 struct pte *pe = &ptes[i]; 2591 struct partition *p = pe->part_table; 2592 sector_t new, first, nr_sects; 2593 2594 if (warn_geometry()) 2595 return; 2596 nr_sects = get_nr_sects(p); 2597 if (!p->sys_ind || !nr_sects || IS_EXTENDED(p->sys_ind)) { 2598 printf("Partition %u has no data area\n", i + 1); 2599 return; 2600 } 2601 first = get_partition_start_from_dev_start(pe); /* == pe->offset_from_dev_start + get_start_sect(p) */ 2602 new = read_int(0 /*was:first*/, first, first + nr_sects - 1, first, "New beginning of data"); 2603 if (new != first) { 2604 sector_t new_relative = new - pe->offset_from_dev_start; 2605 nr_sects += (get_start_sect(p) - new_relative); 2606 set_start_sect(p, new_relative); 2607 set_nr_sects(p, nr_sects); 2608 read_nonempty("Recalculate C/H/S values? (Y/N): "); 2609 if ((line_ptr[0] | 0x20) == 'y') 2610 set_hsc_start_end(p, new, new + nr_sects - 1); 2611 pe->changed = 1; 2612 } 2613} 2614 2615static void 2616xselect(void) 2617{ 2618 char c; 2619 2620 while (1) { 2621 bb_putchar('\n'); 2622 c = 0x20 | read_nonempty("Expert command (m for help): "); 2623 switch (c) { 2624 case 'a': 2625 if (LABEL_IS_SUN) 2626 sun_set_alt_cyl(); 2627 break; 2628 case 'b': 2629 if (LABEL_IS_DOS) 2630 move_begin(get_partition(0, g_partitions)); 2631 break; 2632 case 'c': 2633 user_cylinders = g_cylinders = 2634 read_int(1, g_cylinders, 1048576, 0, 2635 "Number of cylinders"); 2636 if (LABEL_IS_SUN) 2637 sun_set_ncyl(g_cylinders); 2638 if (LABEL_IS_DOS) 2639 warn_cylinders(); 2640 break; 2641 case 'd': 2642 print_raw(); 2643 break; 2644 case 'e': 2645 if (LABEL_IS_SGI) 2646 sgi_set_xcyl(); 2647 else if (LABEL_IS_SUN) 2648 sun_set_xcyl(); 2649 else if (LABEL_IS_DOS) 2650 x_list_table(1); 2651 break; 2652 case 'f': 2653 if (LABEL_IS_DOS) 2654 fix_partition_table_order(); 2655 break; 2656 case 'g': 2657#if ENABLE_FEATURE_SGI_LABEL 2658 create_sgilabel(); 2659#endif 2660 break; 2661 case 'h': 2662 user_heads = g_heads = read_int(1, g_heads, 256, 0, "Number of heads"); 2663 update_units(); 2664 break; 2665 case 'i': 2666 if (LABEL_IS_SUN) 2667 sun_set_ilfact(); 2668 break; 2669 case 'o': 2670 if (LABEL_IS_SUN) 2671 sun_set_rspeed(); 2672 break; 2673 case 'p': 2674 if (LABEL_IS_SUN) 2675 list_table(1); 2676 else 2677 x_list_table(0); 2678 break; 2679 case 'q': 2680 if (ENABLE_FEATURE_CLEAN_UP) 2681 close_dev_fd(); 2682 bb_putchar('\n'); 2683 exit(EXIT_SUCCESS); 2684 case 'r': 2685 return; 2686 case 's': 2687 user_sectors = g_sectors = read_int(1, g_sectors, 63, 0, "Number of sectors"); 2688 if (dos_compatible_flag) { 2689 sector_offset = g_sectors; 2690 printf("Warning: setting sector offset for DOS " 2691 "compatiblity\n"); 2692 } 2693 update_units(); 2694 break; 2695 case 'v': 2696 verify(); 2697 break; 2698 case 'w': 2699 write_table(); /* does not return */ 2700 break; 2701 case 'y': 2702 if (LABEL_IS_SUN) 2703 sun_set_pcylcount(); 2704 break; 2705 default: 2706 xmenu(); 2707 } 2708 } 2709} 2710#endif /* ADVANCED mode */ 2711 2712static int 2713is_ide_cdrom_or_tape(const char *device) 2714{ 2715 FILE *procf; 2716 char buf[100]; 2717 struct stat statbuf; 2718 int is_ide = 0; 2719 2720 /* No device was given explicitly, and we are trying some 2721 likely things. But opening /dev/hdc may produce errors like 2722 "hdc: tray open or drive not ready" 2723 if it happens to be a CD-ROM drive. It even happens that 2724 the process hangs on the attempt to read a music CD. 2725 So try to be careful. This only works since 2.1.73. */ 2726 2727 if (strncmp("/dev/hd", device, 7)) 2728 return 0; 2729 2730 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5); 2731 procf = fopen_for_read(buf); 2732 if (procf != NULL && fgets(buf, sizeof(buf), procf)) 2733 is_ide = (!strncmp(buf, "cdrom", 5) || 2734 !strncmp(buf, "tape", 4)); 2735 else 2736 /* Now when this proc file does not exist, skip the 2737 device when it is read-only. */ 2738 if (stat(device, &statbuf) == 0) 2739 is_ide = ((statbuf.st_mode & 0222) == 0); 2740 2741 if (procf) 2742 fclose(procf); 2743 return is_ide; 2744} 2745 2746 2747static void 2748open_list_and_close(const char *device, int user_specified) 2749{ 2750 int gb; 2751 2752 disk_device = device; 2753 if (setjmp(listingbuf)) 2754 return; 2755 if (!user_specified) 2756 if (is_ide_cdrom_or_tape(device)) 2757 return; 2758 2759 /* Open disk_device, save file descriptor to dev_fd */ 2760 errno = 0; 2761 gb = get_boot(TRY_ONLY); 2762 if (gb > 0) { /* I/O error */ 2763 /* Ignore other errors, since we try IDE 2764 and SCSI hard disks which may not be 2765 installed on the system. */ 2766 if (user_specified || errno == EACCES) 2767 bb_perror_msg("can't open '%s'", device); 2768 return; 2769 } 2770 2771 if (gb < 0) { /* no DOS signature */ 2772 list_disk_geometry(); 2773 if (LABEL_IS_AIX) 2774 goto ret; 2775#if ENABLE_FEATURE_OSF_LABEL 2776 if (bsd_trydev(device) < 0) 2777#endif 2778 printf("Disk %s doesn't contain a valid " 2779 "partition table\n", device); 2780 } else { 2781 list_table(0); 2782#if ENABLE_FEATURE_FDISK_WRITABLE 2783 if (!LABEL_IS_SUN && g_partitions > 4) { 2784 delete_partition(ext_index); 2785 } 2786#endif 2787 } 2788 ret: 2789 close_dev_fd(); 2790} 2791 2792/* for fdisk -l: try all things in /proc/partitions 2793 that look like a partition name (do not end in a digit) */ 2794static void 2795list_devs_in_proc_partititons(void) 2796{ 2797 FILE *procpt; 2798 char line[100], ptname[100], devname[120], *s; 2799 int ma, mi, sz; 2800 2801 procpt = fopen_or_warn("/proc/partitions", "r"); 2802 2803 while (fgets(line, sizeof(line), procpt)) { 2804 if (sscanf(line, " %u %u %u %[^\n ]", 2805 &ma, &mi, &sz, ptname) != 4) 2806 continue; 2807 if (!strncmp(ptname, "mtdblock", 8)) 2808 continue; 2809 for (s = ptname; *s; s++) 2810 continue; 2811 /* note: excluding '0': e.g. mmcblk0 is not a partition name! */ 2812 if (s[-1] >= '1' && s[-1] <= '9') 2813 continue; 2814 sprintf(devname, "/dev/%s", ptname); 2815 open_list_and_close(devname, 0); 2816 } 2817#if ENABLE_FEATURE_CLEAN_UP 2818 fclose(procpt); 2819#endif 2820} 2821 2822#if ENABLE_FEATURE_FDISK_WRITABLE 2823static void 2824unknown_command(int c) 2825{ 2826 printf("%c: unknown command\n", c); 2827} 2828#endif 2829 2830int fdisk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 2831int fdisk_main(int argc UNUSED_PARAM, char **argv) 2832{ 2833 unsigned opt; 2834 /* 2835 * fdisk -v 2836 * fdisk -l [-b sectorsize] [-u] device ... 2837 * fdisk -s [partition] ... 2838 * fdisk [-b sectorsize] [-u] device 2839 * 2840 * Options -C, -H, -S set the geometry. 2841 */ 2842 INIT_G(); 2843 2844 close_dev_fd(); /* needed: fd 3 must not stay closed */ 2845 2846 opt_complementary = "b+:C+:H+:S+"; /* numeric params */ 2847 opt = getopt32(argv, "b:C:H:lS:u" IF_FEATURE_FDISK_BLKSIZE("s"), 2848 §or_size, &user_cylinders, &user_heads, &user_sectors); 2849 argv += optind; 2850 if (opt & OPT_b) { 2851 /* Ugly: this sector size is really per device, 2852 * so cannot be combined with multiple disks, 2853 * and the same goes for the C/H/S options. 2854 */ 2855 if (sector_size < 512 2856 || sector_size > 0x10000 2857 || (sector_size & (sector_size-1)) /* not power of 2 */ 2858 ) { 2859 bb_show_usage(); 2860 } 2861 sector_offset = 2; 2862 user_set_sector_size = 1; 2863 } 2864 if (user_heads <= 0 || user_heads >= 256) 2865 user_heads = 0; 2866 if (user_sectors <= 0 || user_sectors >= 64) 2867 user_sectors = 0; 2868 if (opt & OPT_u) 2869 display_in_cyl_units = 0; // -u 2870 2871#if ENABLE_FEATURE_FDISK_WRITABLE 2872 if (opt & OPT_l) { 2873 nowarn = 1; 2874#endif 2875 if (*argv) { 2876 listing = 1; 2877 do { 2878 open_list_and_close(*argv, 1); 2879 } while (*++argv); 2880 } else { 2881 /* we don't have device names, */ 2882 /* use /proc/partitions instead */ 2883 list_devs_in_proc_partititons(); 2884 } 2885 return 0; 2886#if ENABLE_FEATURE_FDISK_WRITABLE 2887 } 2888#endif 2889 2890#if ENABLE_FEATURE_FDISK_BLKSIZE 2891 if (opt & OPT_s) { 2892 int j; 2893 2894 nowarn = 1; 2895 if (!argv[0]) 2896 bb_show_usage(); 2897 for (j = 0; argv[j]; j++) { 2898 unsigned long long size; 2899 fd = xopen(argv[j], O_RDONLY); 2900 size = bb_BLKGETSIZE_sectors(fd) / 2; 2901 close(fd); 2902 if (argv[1]) 2903 printf("%llu\n", size); 2904 else 2905 printf("%s: %llu\n", argv[j], size); 2906 } 2907 return 0; 2908 } 2909#endif 2910 2911#if ENABLE_FEATURE_FDISK_WRITABLE 2912 if (!argv[0] || argv[1]) 2913 bb_show_usage(); 2914 2915 disk_device = argv[0]; 2916 get_boot(OPEN_MAIN); 2917 2918 if (LABEL_IS_OSF) { 2919 /* OSF label, and no DOS label */ 2920 printf("Detected an OSF/1 disklabel on %s, entering " 2921 "disklabel mode\n", disk_device); 2922 bsd_select(); 2923 /*Why do we do this? It seems to be counter-intuitive*/ 2924 current_label_type = LABEL_DOS; 2925 /* If we return we may want to make an empty DOS label? */ 2926 } 2927 2928 while (1) { 2929 int c; 2930 bb_putchar('\n'); 2931 c = 0x20 | read_nonempty("Command (m for help): "); 2932 switch (c) { 2933 case 'a': 2934 if (LABEL_IS_DOS) 2935 toggle_active(get_partition(1, g_partitions)); 2936 else if (LABEL_IS_SUN) 2937 toggle_sunflags(get_partition(1, g_partitions), 2938 0x01); 2939 else if (LABEL_IS_SGI) 2940 sgi_set_bootpartition( 2941 get_partition(1, g_partitions)); 2942 else 2943 unknown_command(c); 2944 break; 2945 case 'b': 2946 if (LABEL_IS_SGI) { 2947 printf("\nThe current boot file is: %s\n", 2948 sgi_get_bootfile()); 2949 if (read_maybe_empty("Please enter the name of the " 2950 "new boot file: ") == '\n') 2951 printf("Boot file unchanged\n"); 2952 else 2953 sgi_set_bootfile(line_ptr); 2954 } 2955#if ENABLE_FEATURE_OSF_LABEL 2956 else 2957 bsd_select(); 2958#endif 2959 break; 2960 case 'c': 2961 if (LABEL_IS_DOS) 2962 toggle_dos_compatibility_flag(); 2963 else if (LABEL_IS_SUN) 2964 toggle_sunflags(get_partition(1, g_partitions), 2965 0x10); 2966 else if (LABEL_IS_SGI) 2967 sgi_set_swappartition( 2968 get_partition(1, g_partitions)); 2969 else 2970 unknown_command(c); 2971 break; 2972 case 'd': 2973 { 2974 int j; 2975 /* If sgi_label then don't use get_existing_partition, 2976 let the user select a partition, since 2977 get_existing_partition() only works for Linux-like 2978 partition tables */ 2979 if (!LABEL_IS_SGI) { 2980 j = get_existing_partition(1, g_partitions); 2981 } else { 2982 j = get_partition(1, g_partitions); 2983 } 2984 if (j >= 0) 2985 delete_partition(j); 2986 } 2987 break; 2988 case 'i': 2989 if (LABEL_IS_SGI) 2990 create_sgiinfo(); 2991 else 2992 unknown_command(c); 2993 case 'l': 2994 list_types(get_sys_types()); 2995 break; 2996 case 'm': 2997 menu(); 2998 break; 2999 case 'n': 3000 new_partition(); 3001 break; 3002 case 'o': 3003 create_doslabel(); 3004 break; 3005 case 'p': 3006 list_table(0); 3007 break; 3008 case 'q': 3009 if (ENABLE_FEATURE_CLEAN_UP) 3010 close_dev_fd(); 3011 bb_putchar('\n'); 3012 return 0; 3013 case 's': 3014#if ENABLE_FEATURE_SUN_LABEL 3015 create_sunlabel(); 3016#endif 3017 break; 3018 case 't': 3019 change_sysid(); 3020 break; 3021 case 'u': 3022 change_units(); 3023 break; 3024 case 'v': 3025 verify(); 3026 break; 3027 case 'w': 3028 write_table(); /* does not return */ 3029 break; 3030#if ENABLE_FEATURE_FDISK_ADVANCED 3031 case 'x': 3032 if (LABEL_IS_SGI) { 3033 printf("\n\tSorry, no experts menu for SGI " 3034 "partition tables available\n\n"); 3035 } else 3036 xselect(); 3037 break; 3038#endif 3039 default: 3040 unknown_command(c); 3041 menu(); 3042 } 3043 } 3044 return 0; 3045#endif /* FEATURE_FDISK_WRITABLE */ 3046} 3047