toybox/toys/pending/fdisk.c
<<
>>
Prefs
   1/* fdisk.c -  fdisk program to modify partitions on disk.
   2 *
   3 * Copyright 2012 Ashwini Kumar <ak.ashwini@gmail.com>
   4 * Copyright 2013 Kyungwan Han <asura321@gmail.com>
   5 *
   6 * No Standard.
   7
   8USE_FDISK(NEWTOY(fdisk, "C#<0H#<0S#<0b#<512ul", TOYFLAG_SBIN))
   9
  10config FDISK
  11  bool "fdisk"
  12  default n
  13  help
  14    usage: fdisk [-lu] [-C CYLINDERS] [-H HEADS] [-S SECTORS] [-b SECTSZ] DISK
  15
  16    Change partition table
  17
  18    -u            Start and End are in sectors (instead of cylinders)
  19    -l            Show partition table for each DISK, then exit
  20    -b size       sector size (512, 1024, 2048 or 4096)
  21    -C CYLINDERS  Set number of cylinders/heads/sectors
  22    -H HEADS
  23    -S SECTORS
  24*/
  25
  26#define FOR_fdisk
  27#include "toys.h"
  28#include <linux/hdreg.h>
  29
  30GLOBALS(
  31  long sect_sz;
  32  long sectors;
  33  long heads;
  34  long cylinders;
  35)
  36
  37#define EXTENDED        0x05                                                                      
  38#define WIN98_EXTENDED  0x0f
  39#define LINUX_NATIVE    0x83
  40#define LINUX_EXTENDED  0x85
  41
  42#define SECTOR_SIZE 512
  43#define ONE_K       1024
  44#define PARTITION_MAX  60  //partition max is modifiable
  45#define IS_EXTENDED(i) ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
  46#define sector(s) ((s) & 0x3f)
  47#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
  48
  49typedef off_t sector_t;
  50
  51struct partition {
  52  unsigned char boot_ind, head, sector, cyl, sys_ind, end_head,
  53                end_sector, end_cyl, start4[4], size4[4];
  54};
  55
  56struct part_entry {
  57  struct partition *part;
  58  char *sec_buffer;
  59  sector_t  start_offset;
  60  int modified;
  61};
  62
  63struct part_types {
  64  int id;
  65  char type[24];
  66} sys_types[] = {
  67  {0x00, "Empty"}, {0x01, "FAT12"}, {0x04, "FAT16 <32M"}, {0x05, "Extended"},
  68  {0x06, "FAT16"}, {0x07, "HPFS/NTFS"}, {0x0a, "OS/2 Boot Manager"},
  69  {0x0b, "Win95 FAT32"}, {0x0c, "Win95 FAT32 (LBA)"}, {0x0e, "Win95 FAT16 (LBA)"},
  70  {0x0f, "Win95 Ext'd (LBA)"}, {0x11, "Hidden FAT12"}, {0x12, "Compaq diagnostics"},
  71  {0x14, "Hidden FAT16 <32M"}, {0x16, "Hidden FAT16"}, {0x17, "Hidden HPFS/NTFS"},
  72  {0x1b, "Hidden Win95 FAT32"}, {0x1c, "Hidden W95 FAT32 (LBA)"}, {0x1e, "Hidden W95 FAT16 (LBA)"},
  73  {0x3c, "Part.Magic recovery"}, {0x41, "PPC PReP Boot"}, {0x42, "SFS"},
  74  {0x63, "GNU HURD or SysV"}, {0x80, "Old Minix"}, {0x81, "Minix / old Linux"},
  75  {0x82, "Linux swap"}, {0x83, "Linux"}, {0x84, "OS/2 hidden C: drive"},
  76  {0x85, "Linux extended"}, {0x86, "NTFS volume set"}, {0x87, "NTFS volume set"},
  77  {0x8e, "Linux LVM"}, {0x9f, "BSD/OS"}, {0xa0, "Thinkpad hibernation"},
  78  {0xa5, "FreeBSD"}, {0xa6, "OpenBSD"}, {0xa8, "Darwin UFS"}, {0xa9, "NetBSD"},
  79  {0xab, "Darwin boot"}, {0xb7, "BSDI fs"}, {0xb8, "BSDI swap"},
  80  {0xbe, "Solaris boot"}, {0xeb, "BeOS fs"}, {0xee, "EFI GPT"},
  81  {0xef, "EFI (FAT-12/16/32)"}, {0xf0, "Linux/PA-RISC boot"},
  82  {0xf2, "DOS secondary"}, {0xfd, "Linux raid autodetect"},
  83};
  84
  85static int num_parts, disp_unit_cyl, dos_flag, dev_fd = 3;
  86static long g_cylinders, g_heads, g_sectors, g_sect_size;
  87static sector_t total_number_sectors, extended_offset;
  88static char MBRbuf[2048], *disk_device;
  89struct part_entry partitions[PARTITION_MAX];
  90
  91static struct partition* part_offset(char *secbuf, int i)
  92{
  93  return (struct partition*)(secbuf + 0x1be + i*(sizeof(struct partition)));
  94}
  95
  96static void set_levalue(unsigned char *cp, sector_t value )
  97{
  98  uint32_t val = SWAP_LE32(value);
  99  memcpy(cp, (void*)&val, 4);
 100}
 101
 102static void set_hsc(struct partition *p, sector_t start, sector_t end)
 103{
 104  if (dos_flag && (start / (g_sectors * g_heads) > 1023))
 105    start = g_heads * g_sectors * ONE_K - 1;
 106  p->sector = (start % g_sectors) + 1;
 107  start /= g_sectors;
 108  p->head = start % g_heads;
 109  start /= g_heads;
 110  p->cyl = start & 0xFF;
 111  p->sector |= (start >> 2) & 0xc0;
 112
 113  if (dos_flag && (end / (g_sectors * g_heads) > 1023))
 114    end = g_heads * g_sectors * ONE_K - 1;
 115  p->end_sector = (end % g_sectors) + 1;
 116  end /= g_sectors;
 117  p->end_head = end % g_heads;
 118  end /= g_heads;
 119  p->end_cyl = end & 0xFF;
 120  p->end_sector |= (end >> 2) & 0xc0;
 121}
 122
 123static int chs_warn(void)
 124{
 125  if (g_heads && g_sectors && g_cylinders)
 126    return 0;
 127
 128  printf("Unknown value(s) for:");
 129  if (!g_heads) printf(" heads");
 130  if (!g_sectors) printf(" sectors");
 131  if (!g_cylinders) printf(" cylinders");
 132  printf(". can set in the expert menu.\n");
 133  return 1;
 134}
 135
 136static void list_types(void)
 137{
 138  int i, adjust = 0, size = ARRAY_LEN(sys_types);
 139 
 140  if(size % 2) adjust = 1;
 141  for (i = 0; i < (size - adjust); i+=2)
 142    xprintf("%2x %-22s\t\t%2x %-22.22s\n", sys_types[i].id, sys_types[i].type,
 143        sys_types[i+1].id, sys_types[i+1].type);
 144  if (adjust) xprintf("%2x %-22s\n",sys_types[size-1].id, sys_types[size-1].type);
 145  xputc('\n');
 146}
 147
 148static void read_sec_sz()
 149{
 150  int arg;       
 151  if (ioctl(dev_fd, BLKSSZGET, &arg) == 0) g_sect_size = arg;
 152  if (toys.optflags & FLAG_b) {
 153    if (TT.sect_sz !=  512 && TT.sect_sz != 1024 && TT.sect_sz != 2048 &&
 154        TT.sect_sz != 4096)
 155    {
 156      help_exit("bad sector size");
 157    }
 158    g_sect_size = TT.sect_sz;
 159  }
 160}
 161
 162static sector_t read_size()
 163{
 164  uint64_t sec64 = 0;
 165  unsigned long sectors = 0;
 166  if (ioctl(dev_fd, BLKGETSIZE64, &sec64) == 0) {
 167    sec64 = sec64 >> 9; //convert to 512 block size.
 168    if (sec64 != (uint32_t) sec64) {
 169      perror_msg("device has more than 2^32 sectors, can't use all of them");
 170      sec64 = (uint32_t) - 1L;
 171    }
 172    return sec64;
 173  }
 174  if (ioctl(dev_fd, BLKGETSIZE, &sectors) == 0)
 175    if (sizeof(long) > sizeof(sector_t) && sectors != (sector_t)sectors)
 176      sectors = (uint32_t) - 1L;
 177  return sectors;
 178}
 179
 180static int validate_part_buff(char *buffer)
 181{
 182  if ((buffer[510] != 0x55) || (buffer[511] != 0xAA)) return 0;
 183  return 1;
 184}
 185
 186static int is_partition_clear(struct partition* p)
 187{
 188  int i = 0;
 189  unsigned char res = 0;
 190  const char *ptr = (const char*)p;
 191
 192  for (i = 0; i < sizeof(struct partition); i++) res |= (unsigned char)ptr[i];
 193  return (res == 0x00);
 194}
 195
 196static uint32_t swap_le32toh(unsigned char *cp)
 197{
 198  uint32_t val;
 199  memcpy((void*)&val, cp, 4);
 200  return le32toh(val);
 201}
 202
 203static int check_order(void)    
 204{                              
 205  sector_t first[num_parts], last_seen_val = 0;
 206  int i;
 207  struct part_entry *pe;       
 208  struct partition *px;
 209
 210  for (i = 0; i < num_parts; i++) {
 211    if (i == 4) last_seen_val = 0;
 212    pe = &partitions[i];       
 213    px = pe->part;             
 214    if (px->sys_ind) {
 215      first[i] = swap_le32toh(px->start4) + pe->start_offset;
 216      if (last_seen_val > first[i]) return 1;
 217      last_seen_val = first[i];
 218    }
 219  }
 220  return 0;
 221}
 222
 223static void read_geometry(struct hd_geometry *disk)
 224{
 225  struct hd_geometry geometry;
 226
 227  if (ioctl(dev_fd, HDIO_GETGEO, &geometry)) return;
 228  disk->heads = geometry.heads;
 229  disk->sectors = geometry.sectors;
 230}
 231
 232/* Read the extended boot record for the 
 233 * logical partion details.
 234 */
 235static void read_ebr(int idx)
 236{
 237  char *sec_buf = NULL;
 238  sector_t offset = 0, local_start_off = 0;
 239  struct partition *p, *q;
 240
 241  q = p = partitions[idx].part;
 242  local_start_off = swap_le32toh(p->start4);
 243
 244  if (!extended_offset) extended_offset = local_start_off;
 245  do {
 246    if (num_parts >= 60) {
 247      xprintf("Warning: deleting partitions after 60\n");
 248      memset(q, 0, sizeof(struct partition)); //clear_partition
 249      partitions[num_parts-1].modified = 1;
 250      break;
 251    }
 252
 253    sec_buf = xzalloc(g_sect_size);
 254    partitions[num_parts].part = part_offset(sec_buf, 0);
 255    partitions[num_parts].sec_buffer = sec_buf;
 256    offset = swap_le32toh(q->start4);
 257
 258    if (num_parts > 4) offset += local_start_off;
 259    partitions[num_parts].start_offset = offset;
 260    xlseek(dev_fd, (off_t)(offset * g_sect_size), SEEK_SET);
 261
 262    if (g_sect_size != readall(dev_fd, sec_buf, g_sect_size)) {
 263      close(dev_fd);
 264      error_exit("Couldn't read sector zero\n");
 265    }
 266    num_parts++; //extended partions present.
 267    q = part_offset(sec_buf, 1);
 268  } while (!is_partition_clear(q) && IS_EXTENDED(q->sys_ind));
 269}
 270
 271static void physical_HS(int* h, int *s)
 272{  
 273  struct partition *p;
 274  int i, end_h, end_s, e_hh = 0, e_ss = 0, ini = 1, dirty = 0;
 275  const unsigned char *bufp = (const unsigned char *)MBRbuf;
 276
 277  if (!(validate_part_buff((char*)bufp))) return;
 278
 279  for (i = 0; i < 4; i++) {
 280    p = part_offset((char*)bufp, i);
 281    if (p->sys_ind) {
 282      end_h = p->end_head + 1;
 283      end_s = (p->end_sector & 077);
 284      if (ini) {
 285        e_hh = end_h;
 286        e_ss = end_s;
 287        ini = 0;
 288      } else if (e_hh !=end_h || e_ss != end_s)
 289        dirty = 1;
 290    }
 291  }
 292  if (!dirty && !ini) {
 293    *h = e_hh;
 294    *s = e_ss;
 295  }
 296}
 297
 298//Reset the primary partition table
 299static void reset_boot(int change)
 300{
 301  int i;
 302  for(i = 0; i < 4; i++) {
 303    struct part_entry *pe = &partitions[i];
 304    pe->part = part_offset(MBRbuf, i);
 305    pe->start_offset = 0;
 306    pe->sec_buffer = MBRbuf;
 307    pe->modified = change;
 308  }
 309}
 310
 311static inline void write_table_flag(char *buf)
 312{
 313  buf[510] = 0x55;
 314  buf[511] = 0xaa;
 315}
 316
 317/* free the buffers used for holding details of
 318 * extended logical partions
 319*/
 320static void free_bufs(void)
 321{
 322  int i = 4;
 323  for (; i < num_parts; i++) free(partitions[i].sec_buffer);
 324}
 325
 326static void create_empty_doslabel(void)
 327{
 328  xprintf("Building a new DOS Disklabel. The changes will\n"
 329      "remain in memory only, until you write it.\n");
 330
 331  num_parts = 4;
 332  extended_offset = 0;
 333  memset(&MBRbuf[510 - 4*16], 0, 4*16);
 334  write_table_flag(MBRbuf);
 335  partitions[0].modified = 1;
 336  reset_boot(1);
 337}
 338
 339/* Read the Master Boot sector of the device for the 
 340 * partition table entries/details.
 341 * If any extended partition is found then read the EBR
 342 * for logical partition details
 343 */
 344static int read_mbr(char *device, int validate)
 345{
 346  int fd, sector_fac, i, h = 0, s = 0;
 347  struct hd_geometry disk;
 348  fd = open(device, O_RDWR);
 349  if(fd < 0) {
 350    perror_msg("can't open '%s'",device);
 351    return 1;
 352  }
 353
 354  disk_device = strdup(device);
 355  if(fd != dev_fd) {
 356    if(dup2(fd, dev_fd) != dev_fd) perror_exit("Can't dup2");
 357    close(fd);
 358  }
 359
 360  //read partition table - MBR
 361  if (SECTOR_SIZE != readall(dev_fd, MBRbuf, SECTOR_SIZE)) {
 362    close(dev_fd);
 363    perror_exit("Couldn't read sector zero\n");
 364  }
 365  if (validate && !validate_part_buff(MBRbuf)) {
 366    xprintf("Device contains neither a valid DOS "
 367        "partition table, nor Sun, SGI, OSF or GPT "
 368        "disklabel\n");
 369    create_empty_doslabel();
 370  }
 371
 372  disk.heads = disk.sectors = 0;
 373  read_geometry(&disk); //CHS values
 374  total_number_sectors = read_size(); //Device size
 375  read_sec_sz();
 376  sector_fac = g_sect_size/SECTOR_SIZE; //512 is hardware sector size.
 377  physical_HS(&h, &s); //physical dimensions may be diferent from HDIO_GETGEO
 378  g_sectors = (toys.optflags & FLAG_S && TT.sectors)? TT.sectors :  s? s : disk.sectors?disk.sectors : 63;
 379  g_heads = (toys.optflags & FLAG_H && TT.heads)? TT.heads : h? h : disk.heads? disk.heads : 255;
 380  g_cylinders = total_number_sectors/(g_heads * g_sectors * sector_fac);
 381
 382  if (!g_cylinders) g_cylinders = toys.optflags & FLAG_C? TT.cylinders : 0;
 383  if ((g_cylinders > ONE_K) && !(toys.optflags & (FLAG_l | FLAG_S)))
 384    xprintf("\nThe number of cylinders for this disk is set to %lu.\n"
 385        "There is nothing wrong with that, but this is larger than 1024,\n"
 386        "and could in certain setups cause problems.\n", g_cylinders);
 387  for (i = 0; i < num_parts; i++) {
 388    if (IS_EXTENDED(partitions[i].part->sys_ind)) {
 389      read_ebr(i);
 390      break;
 391    }
 392  }
 393  chs_warn();
 394
 395  return 0;
 396}
 397
 398static char* get_type(int sys_ind)
 399{
 400  int i, size = ARRAY_LEN(sys_types);
 401  for (i = 0; i < size; i++)
 402    if (sys_ind == sys_types[i].id)
 403      return sys_types[i].type;
 404  return "Unknown";
 405}
 406
 407static void consistency_check(const struct partition *p, int partition)
 408{        
 409  unsigned physbc, physbh, physbs, physec, physeh, physes;
 410  unsigned lbc, lbh, lbs, lec, leh, les;
 411  sector_t start, end;
 412
 413  if (!g_heads || !g_sectors || (partition >= 4)) return;
 414  // physical beginning c, h, s 
 415  physbc = cylinder(p->sector,p->cyl);
 416  physbh = p->head;
 417  physbs = sector(p->sector);
 418  // physical ending c, h, s 
 419  physec = cylinder(p->end_sector, p->end_cyl);
 420  physeh = p->end_head;
 421  physes = sector(p->end_sector);
 422  // logical begin and end CHS values 
 423  start = swap_le32toh((unsigned char*)(p->start4));
 424  end = start + swap_le32toh((unsigned char*)(p->size4)) -1;
 425
 426  lbc = start/(g_sectors * g_heads);
 427  lbh = (start/g_sectors) % g_heads;
 428  lbs = (start % g_sectors) + 1;
 429
 430  lec = end/(g_sectors * g_heads);
 431  leh = (end/g_sectors) % g_heads;
 432  les = (end % g_sectors) + 1;
 433
 434  //Logical and Physical diff 
 435  if (g_cylinders <= ONE_K && (physbc != lbc || physbh != lbh || physbs != lbs)) {
 436    xprintf("Partition %u has different physical/logical beginings (Non-Linux?): \n", partition+1);
 437    xprintf("phys = (%u %u %u) ",physbc, physbh, physbs);
 438    xprintf("logical = (%u %u %u)\n", lbc, lbh, lbs);
 439  }
 440  if (g_cylinders <= ONE_K && (physec != lec || physeh != leh || physes != les)) {
 441    xprintf("Partition %u has different physical/logical endings: \n", partition+1);
 442    xprintf("phys = (%u %u %u) ",physec, physeh, physes);
 443    xprintf("logical = (%u %u %u)\n", lec, leh, les);
 444  }
 445  // Ending on cylinder boundary? 
 446  if (physeh != (g_heads - 1) || physes != g_sectors)
 447    xprintf("Partition %u does not end on cylinder boundary\n", partition + 1);
 448}
 449
 450// List the partition details
 451static void list_partitions(int validate)
 452{
 453  struct partition *p;
 454  uint32_t start_cyl, end_cyl, start_sec, end_sec, blocks, secs;
 455  char boot, lastchar = '\0', *dev = disk_device;
 456  int i = 0, len = strlen(disk_device), odds = 0;
 457
 458  if (validate && !validate_part_buff(MBRbuf)) {
 459    close(dev_fd);
 460    toys.exitval = 1;
 461    xprintf("Device %s: doesn't contain a valid partition table\n", disk_device);
 462    return;
 463  }
 464  if (isdigit(dev[len - 1])) lastchar = 'p';
 465
 466  xprintf("%*s Boot      Start         End      Blocks  Id System\n", len+1, "Device");
 467  for (i = 0; i < num_parts; i++) {
 468    p = partitions[i].part;
 469    if (is_partition_clear(p)) continue;
 470
 471    boot = ((p->boot_ind == 0x80)?'*':(!p->boot_ind)?' ':'?');
 472    start_sec = swap_le32toh(p->start4) + partitions[i].start_offset;
 473    secs = swap_le32toh(p->size4);
 474
 475    if ((start_sec + secs) == 0) end_sec = 0;
 476    else end_sec = start_sec + secs -1;
 477    start_cyl = start_sec/(g_heads * g_sectors) + 1;
 478    end_cyl = end_sec/(g_heads * g_sectors) + 1;
 479    blocks = secs;
 480    if (g_sect_size < ONE_K) {
 481      blocks /= (ONE_K/g_sect_size);
 482      odds = secs %(ONE_K/g_sect_size);
 483    } else if (g_sect_size > ONE_K) blocks *= (g_sect_size/ONE_K);
 484
 485    if (lastchar) xprintf("%s%c%d",dev, lastchar, i+1);
 486    else xprintf("%s%d",dev, i+1);
 487
 488    xprintf("   %c %11u %11u %11u%c %2x %s\n",
 489        boot,
 490        disp_unit_cyl == 0? start_sec: start_cyl,
 491        disp_unit_cyl == 0? end_sec: end_cyl,
 492        blocks,odds?'+':' ', p->sys_ind, get_type(p->sys_ind));
 493
 494    consistency_check(p, i);
 495  }
 496  if (check_order()) xprintf("\nPartition table entries are not in disk order");
 497}
 498
 499//Print device details
 500static void print_mbr(int validate)
 501{
 502  unsigned long long bytes = ((unsigned long long)total_number_sectors << 9);
 503  long mbytes = bytes/1000000;
 504
 505  if (mbytes < 10000) xprintf("Disk %s: %lu MB, %llu bytes\n", disk_device, mbytes, bytes);
 506  else xprintf("Disk %s: %lu.%lu GB, %llu bytes\n", disk_device, mbytes/1000, (mbytes/100)%10, bytes);
 507  xprintf("%ld heads, %ld sectors/track, %ld cylinders", g_heads, g_sectors, g_cylinders);
 508  if (!disp_unit_cyl) {
 509    xprintf(", total %lld sectors\n", total_number_sectors/(g_sect_size/SECTOR_SIZE));
 510    xprintf("Units = sectors of 1 * %ld = %ld bytes\n",g_sect_size, g_sect_size);
 511  } else xprintf("\nUnits = cylinders of %ld * %ld = %ld bytes\n\n",
 512      g_heads * g_sectors, g_sect_size, g_heads * g_sectors * g_sect_size);
 513  list_partitions(validate);
 514  xputc('\n');
 515}
 516
 517static void init_members(void)
 518{
 519  int i = 0;
 520  num_parts = 4; //max of primaries in a part table
 521  disp_unit_cyl = dos_flag = 1;
 522  extended_offset = 0;
 523  g_sect_size = SECTOR_SIZE;
 524  for (i = 0; i < num_parts; i++) {
 525    partitions[i].part = part_offset(MBRbuf, i);
 526    partitions[i].sec_buffer = MBRbuf;
 527    partitions[i].modified = 0;
 528    partitions[i].start_offset = 0;
 529  }
 530}
 531
 532static int read_input(char *mesg, char *outp)
 533{
 534  char *p;
 535  int size = 0;
 536  do {
 537    xprintf("%s", mesg);
 538    p = fgets(toybuf, 80, stdin);
 539  
 540    if (!p || !(size = strlen(p))) exit(0);
 541    if (p[size-1] == '\n') p[--size] = '\0';
 542  } while (!size);
 543
 544  while (*p != '\0' && *p <= ' ') p++;
 545  if (outp) memcpy(outp, p, strlen(p) + 1); //1 for nul
 546  return *p;
 547}
 548
 549static int read_hex(char *mesg)
 550{
 551  int val;
 552  char input[80], *endp;
 553  while (1) {
 554    read_input(mesg, input);
 555    if ((*input | 0x20) == 'l') {
 556      list_types();
 557      memset(input, 0, 80);
 558      continue;
 559    }
 560    val = strtoul(input, &endp, 16);
 561    if (endp && *endp) continue;
 562    if (val <= 0xff) return val;
 563  }
 564}
 565
 566/* Delete an exiting partition,
 567 * if its primary, then just clear the partition details
 568 * if extended, then clear the partition details, also for logical
 569 * if only logical, then move the later partitions backwards 1 step
 570 */
 571void delete_partition(int i)
 572{
 573  int sys_id, looper = 0;
 574  struct partition *p, *q, *ext_p, *ext_q;
 575  sector_t new_start;
 576  struct part_entry *pe = &partitions[i];
 577  
 578  if (chs_warn()) return;
 579  p = pe->part;
 580  sys_id = p->sys_ind;
 581  if (!sys_id) xprintf("Partition %u is empty\n", i+1);
 582
 583  if (i < 4 && !IS_EXTENDED(sys_id)) {
 584    memset(p, 0, sizeof(struct partition)); //clear_partition
 585    pe->modified = 1;
 586  } else if (i < 4 && IS_EXTENDED(sys_id)) {
 587    memset(p, 0, sizeof(struct partition)); //clear_partition
 588    pe->modified = 1;
 589    for (looper = 4; looper < num_parts; looper++) {
 590      pe = &partitions[looper];
 591      p = pe->part; 
 592      if (is_partition_clear(p)) break;
 593      else {
 594        memset(p, 0, sizeof(struct partition)); //clear_partition
 595        pe->modified = 1;
 596        free(pe->sec_buffer);
 597      }
 598    }
 599    extended_offset = 0;
 600    num_parts = 4;
 601  } else {
 602    //only logical is delete, need to move the rest of them backwards
 603    if (i == 4) { //move partiton# 6 to 5.
 604      partitions[i].modified = 1;
 605      if (num_parts > i+1) {
 606        q = partitions[i + 1].part;
 607        *p = *q; //copy the part table
 608        ext_p = part_offset(partitions[i].sec_buffer, 1);
 609        ext_q = part_offset(partitions[i + 1].sec_buffer, 1);
 610        *ext_p = *ext_q; //copy the extended info pointer
 611        // change the start of the 4th partiton. 
 612        new_start = partitions[i + 1].start_offset + swap_le32toh(q->start4) - extended_offset;
 613        new_start = SWAP_LE32(new_start);
 614        memcpy(p->start4, (void *)&new_start, 4);
 615      } else {
 616        memset(partitions[i].part, 0, sizeof(struct partition));
 617        return; //only logical
 618      }
 619    } else if (i > 4) {
 620      ext_p = part_offset(partitions[i-1].sec_buffer, 1);
 621      ext_q = part_offset(partitions[i].sec_buffer, 1);
 622      memcpy((void*)ext_p, (void *)ext_q, sizeof(struct partition));
 623      partitions[i-1].modified = 1;
 624    }
 625    if (i == 4) looper = i+2;
 626    else if (i > 4) looper = i+1;
 627    for (; looper < num_parts; looper++)
 628      partitions[looper-1] = partitions[looper];
 629    num_parts--;
 630  }
 631}
 632
 633static int ask_partition(int num_parts)
 634{
 635  int val;
 636  while (1) {
 637    do {
 638      xprintf("Partition (%u - %u):", 1, num_parts);
 639      fgets(toybuf, 80, stdin);
 640    } while (!isdigit(*toybuf));
 641    val = atoi(toybuf);
 642    if (val > 0 && val <= num_parts) return val;
 643    else xprintf("Invalid number entered\n");
 644  }
 645}
 646
 647static void toggle_active_flag(int i)
 648{
 649  struct partition *p = partitions[i].part;
 650  if (is_partition_clear(p)) xprintf("Partition %u is empty\n", i+1);
 651  
 652  if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
 653    xprintf("WARNING: Partition %u is an extended partition\n", i + 1);
 654  p->boot_ind = p->boot_ind == 0x80?0 : 0x80;
 655  partitions[i].modified = 1;
 656}
 657
 658//Write the partition details from Buffer to Disk.
 659void write_table(void)
 660{
 661  int i =0;
 662  struct part_entry *pe;
 663  sector_t offset;
 664
 665  for (i = 0; i < 4; i++)
 666    if (partitions[i].modified) partitions[3].modified = 1;
 667
 668  for (i = 3; i < num_parts; i++) {
 669    pe = &partitions[i];
 670    write_table_flag(pe->sec_buffer);
 671    offset = pe->start_offset;
 672    if (pe->modified == 1) {
 673      xlseek(dev_fd, offset * g_sect_size, SEEK_SET);
 674      xwrite(dev_fd, pe->sec_buffer, g_sect_size);
 675    }
 676  }
 677  xprintf("The partition table has been altered.\n");
 678  xprintf("Calling ioctl() to re-read partition table\n");
 679  sync();
 680  for (i = 4; i < num_parts; i++) free(partitions[i].sec_buffer);
 681  if(ioctl(dev_fd, BLKRRPART, NULL) < 0)
 682    perror_exit("WARNING: rereading partition table failed, kernel still uses old table");
 683
 684}
 685
 686/* try to find a partition for deletion, if only
 687 * one, then select the same, else ask from USER
 688 */
 689static int get_non_free_partition(int max)
 690{       
 691  int num = -1, i = 0;
 692
 693  for (i = 0; i < max; i++) {
 694    if (!is_partition_clear(partitions[i].part)) {
 695      if (num >= 0)
 696        return ask_partition(num_parts)-1;
 697      num = i;
 698    }
 699  }
 700  (num >= 0) ? xprintf("Selected partition %d\n",num+1):
 701    xprintf("No partition is defined yet!\n");
 702  return num;
 703}
 704
 705/* a try at autodetecting an empty partition table entry,
 706 * if multiple options then get USER's choce.
 707 */
 708static int get_free_partition(int max)
 709{
 710  int num = -1, i = 0;
 711
 712  for (i = 0; i < max; i++) {
 713    if (is_partition_clear(partitions[i].part)) {
 714      if (num >= 0)
 715        return ask_partition(4)-1;
 716      num = i;
 717    }
 718  }
 719  (num >= 0) ? xprintf("Selected partition %d\n",num+1):
 720    xprintf("All primary partitions have been defined already!\n");
 721  return num;
 722}
 723
 724//taking user input for partition start/end sectors/cyinders
 725static uint32_t ask_value(char *mesg, sector_t left, sector_t right, sector_t defalt)
 726{ 
 727  char *str = toybuf;
 728  uint32_t val;
 729  int use_default = 1;
 730
 731  while (1) {
 732    use_default = 1;
 733    do {
 734      xprintf("%s",mesg);
 735      fgets(str, 80, stdin);
 736    } while (!isdigit(*str) && (*str != '\n')
 737        && (*str != '-') && (*str != '+') && (!isblank(*str)));
 738    while (isblank(*str)) str++; //remove leading white spaces
 739    if (*str == '+' || *str == '-') {
 740      int minus = (*str == '-');
 741      int absolute = 0;
 742
 743      val = atoi(str + 1);
 744      while (isdigit(*++str)) use_default = 0;
 745
 746      switch (*str) {
 747        case 'c':
 748        case 'C':
 749          if (!disp_unit_cyl) val *= g_heads * g_sectors;
 750          break;
 751        case 'K':
 752          absolute = ONE_K;
 753          break;
 754        case 'k':
 755          absolute = 1000;
 756          break;
 757        case 'm':
 758        case 'M':
 759          absolute = 1000000;
 760          break;
 761        case 'g':
 762        case 'G':
 763          absolute = 1000000000;
 764          break;
 765        default:
 766          break;
 767      }
 768      if (absolute) {
 769        unsigned long long bytes = (unsigned long long) val * absolute;
 770        unsigned long unit = (disp_unit_cyl && (g_heads * g_sectors))? g_heads * g_sectors : 1;
 771
 772        unit = unit * g_sect_size;
 773        bytes += unit/2; // rounding
 774        bytes /= unit;
 775        val = bytes;
 776      }
 777      if (minus)
 778        val = -val;
 779      val += left;
 780    } else {
 781      val = atoi(str);
 782      while (isdigit(*str)) {
 783        str++;
 784        use_default = 0;
 785      }
 786    }
 787    if(use_default) {
 788      val = defalt;
 789      xprintf("Using default value %lld\n", defalt);
 790    }
 791    if (val >= left && val <= right) return val;
 792    else xprintf("Value out of range\n");
 793  }
 794}
 795
 796//validating if the start given falls in a limit or not
 797static int validate(int start_index, sector_t* begin,sector_t* end, sector_t start
 798    , int asked)
 799{
 800  int i, valid = 0;
 801  for (i = start_index; i < num_parts; i++) {
 802    if (start >= begin[i] && start <= end[i]) {
 803      if (asked) xprintf("Sector %lld is already allocated\n",start);
 804      valid = 0;
 805      break;
 806    } else valid = 1;
 807  }
 808  return valid;
 809}
 810
 811//get the start sector/cylinder of a new partition
 812static sector_t ask_start_sector(int idx, sector_t* begin, sector_t* end, int ext_idx)
 813{
 814  sector_t start, limit, temp = 0, start_cyl, limit_cyl, offset = 1;
 815  char mesg[256];
 816  int i, asked = 0, valid = 0, start_index = 0;
 817
 818  if (dos_flag) offset = g_sectors;
 819  start = offset;
 820  if (disp_unit_cyl) limit = (sector_t)g_sectors * g_heads * g_cylinders - 1;
 821  else limit = total_number_sectors - 1;
 822
 823  if (disp_unit_cyl) //make the begin of every partition to cylnder boundary 
 824    for (i = 0; i < num_parts; i++)
 825      begin[i] = (begin[i]/(g_heads* g_sectors)) * (g_heads* g_sectors);
 826
 827  if (idx >= 4) {
 828    if (!begin[ext_idx] && extended_offset) begin[ext_idx] = extended_offset;
 829    start = begin[ext_idx] + offset;
 830    limit = end[ext_idx];
 831    start_index = 4;
 832  }
 833  do {
 834    if (asked) valid = validate(start_index, begin, end, start, asked);
 835    if (valid) break;
 836
 837    do {
 838      for (i = start_index; i < num_parts; i++) 
 839        if (start >= begin[i] && start <= end[i])
 840          start = end[i] + 1 + ((idx >= 4)? offset : 0);
 841    } while (!validate(start_index, begin, end, start, 0));
 842
 843    start_cyl = start/(g_sectors * g_heads) + 1;
 844    limit_cyl = limit/(g_sectors * g_heads) + 1;
 845
 846    if (start > limit) break;
 847    sprintf(mesg, "First %s (%lld - %lld, default %lld): ", disp_unit_cyl? "cylinder" : "sector",
 848        (long long int)(disp_unit_cyl? start_cyl : start), 
 849        (long long int)(disp_unit_cyl? limit_cyl : limit),
 850        (long long int)(disp_unit_cyl? start_cyl : start));
 851    temp = ask_value(mesg, disp_unit_cyl? start_cyl : start, 
 852        disp_unit_cyl? limit_cyl : limit, disp_unit_cyl? start_cyl : start);
 853    asked = 1;
 854
 855    if (disp_unit_cyl) {
 856      // point to the cylinder start sector
 857      temp = (temp-1) * g_heads * g_sectors;
 858      if (temp < start) //the boundary is falling in the already used sectors.
 859        temp = start;
 860    }
 861    start = temp;
 862  } while (asked && !valid);
 863  return start;
 864}
 865
 866//get the end sector/cylinder of a new partition
 867static sector_t ask_end_sector(int idx, sector_t* begin, sector_t* end, int ext_idx, sector_t start_sec)
 868{
 869  sector_t limit, temp = 0, start_cyl, limit_cyl, start = start_sec;
 870  char mesg[256];
 871  int i;
 872
 873  if (disp_unit_cyl) limit = (sector_t)g_sectors * g_heads * g_cylinders - 1;
 874  else limit = total_number_sectors - 1;
 875
 876  if (disp_unit_cyl) //make the begin of every partition to cylnder boundary
 877    for (i = 0; i < num_parts; i++)
 878      begin[i] = (begin[i]/(g_heads* g_sectors)) * (g_heads* g_sectors);
 879
 880  if (idx >= 4) limit = end[ext_idx];
 881
 882  for (i = 0; i < num_parts; i++) {
 883    struct part_entry *pe = &partitions[i];
 884    if (start < pe->start_offset && limit >= pe->start_offset) limit = pe->start_offset - 1;
 885    if (start < begin[i] && limit >= begin[i]) limit = begin[i] - 1;
 886  }
 887
 888  start_cyl = start/(g_sectors * g_heads) + 1;
 889  limit_cyl = limit/(g_sectors * g_heads) + 1;
 890  if (limit < start) { //the boundary is falling in the already used sectors.
 891    xprintf("No Free sectors available\n");
 892    return 0;
 893  }
 894  sprintf(mesg, "Last %s or +size or +sizeM or +sizeK (%lld - %lld, default %lld): ",
 895      disp_unit_cyl? "cylinder" : "sector",
 896      (long long int)(disp_unit_cyl? start_cyl : start), 
 897      (long long int)(disp_unit_cyl? limit_cyl : limit),
 898      (long long int)(disp_unit_cyl? limit_cyl : limit));
 899  temp = ask_value(mesg, disp_unit_cyl? start_cyl : start, 
 900      disp_unit_cyl? limit_cyl : limit, disp_unit_cyl? limit_cyl : limit);
 901
 902  if (disp_unit_cyl) { // point to the cylinder start sector
 903    temp = temp * g_heads * g_sectors - 1;
 904    if (temp > limit) temp = limit;
 905  }
 906  if (temp < start) { //the boundary is falling in the already used sectors.
 907    xprintf("No Free sectors available\n");
 908    return 0;
 909  }
 910  return temp;
 911}
 912
 913// add a new partition to the partition table
 914static int add_partition(int idx, int sys_id)
 915{
 916  int i, ext_idx = -1;
 917  sector_t start, end, begin_sec[num_parts], end_sec[num_parts];
 918  struct part_entry *pe = &partitions[idx];
 919  struct partition *p = pe->part;
 920
 921  if (p && !is_partition_clear(p)) {
 922    xprintf("Partition %u is already defined, delete it to re-add\n", idx+1);
 923    return 0;
 924  }
 925  for (i = 0; i < num_parts; i++) {
 926    pe = &partitions[i];
 927    p = pe->part;
 928    if (is_partition_clear(p)) {
 929      begin_sec[i] = 0xffffffff;
 930      end_sec[i] = 0;
 931    } else {
 932      begin_sec[i] = swap_le32toh(p->start4) + pe->start_offset;
 933      end_sec[i] = begin_sec[i] + swap_le32toh(p->size4) - 1;
 934    }
 935    if (IS_EXTENDED(p->sys_ind)) ext_idx = i;
 936  }
 937  start = ask_start_sector(idx, begin_sec, end_sec, ext_idx);
 938  end = ask_end_sector(idx, begin_sec, end_sec, ext_idx, start);
 939  if (!end) return 0;
 940  //Populate partition table entry  - 16 bytes
 941  pe = &partitions[idx];
 942  p = pe->part;
 943
 944  if (idx > 4) {
 945    if (dos_flag) pe->start_offset = start - (sector_t)g_sectors;
 946    else pe->start_offset = start - 1;
 947    if (pe->start_offset == extended_offset) pe->start_offset++;
 948    if (!dos_flag) start++;
 949  }
 950 
 951  set_levalue(p->start4, start - pe->start_offset);
 952  set_levalue(p->size4, end - start + 1);
 953  set_hsc(p, start, end);
 954  p->boot_ind = 0;
 955  p->sys_ind = sys_id;
 956  pe->modified = 1;
 957
 958  if (idx > 4) {
 959    p = partitions[idx-1].part + 1; //extended pointer for logical partitions
 960    set_levalue(p->start4, pe->start_offset - extended_offset);
 961    set_levalue(p->size4, end - start + 1 + (dos_flag? g_sectors: 1));
 962    set_hsc(p, pe->start_offset, end);
 963    p->boot_ind = 0;  
 964    p->sys_ind = EXTENDED;
 965    partitions[idx-1].modified = 1;   
 966  }
 967  if (IS_EXTENDED(sys_id)) {
 968    pe = &partitions[4];
 969    pe->modified = 1; 
 970    pe->sec_buffer = xzalloc(g_sect_size);
 971    pe->part = part_offset(pe->sec_buffer, 0);
 972    pe->start_offset = extended_offset = start;
 973    num_parts = 5;
 974  }
 975  return 1;
 976}
 977
 978static void add_logical_partition(void)
 979{
 980  struct part_entry *pe;
 981  if (num_parts > 5 || !is_partition_clear(partitions[4].part)) {
 982    pe = &partitions[num_parts];
 983    pe->modified = 1;
 984    pe->sec_buffer = xzalloc(g_sect_size);
 985    pe->part = part_offset(pe->sec_buffer, 0);
 986    pe->start_offset = 0;
 987    num_parts++;
 988    if (!add_partition(num_parts - 1, LINUX_NATIVE)) {
 989      num_parts--;
 990      free(pe->sec_buffer);
 991    }
 992  } 
 993  else add_partition(num_parts -1, LINUX_NATIVE);
 994}
 995
 996/* Add a new partiton to the partition table.
 997 * MAX partitions limit is taken to be 60, can be changed
 998 */
 999static void add_new_partition(void)
1000{
1001  int choice, idx, i, free_part = 0;
1002  char *msg = NULL;
1003  
1004  if (chs_warn()) return;
1005  for (i = 0; i < 4; i++) if(is_partition_clear(partitions[i].part)) free_part++;
1006
1007  if (!free_part && num_parts >= 60) {
1008    xprintf("The maximum number of partitions has been created\n");
1009    return;       
1010  }
1011  if (!free_part) {
1012    if (extended_offset) add_logical_partition();
1013    else xprintf("You must delete some partition and add "
1014          "an extended partition first\n");
1015    return;
1016  }
1017
1018  msg = xmprintf("  %s\n  p  primary partition(1-4)\n",
1019          extended_offset? "l  logical (5 or over)" : "e  extended");
1020
1021  choice = 0x20 | read_input(msg, NULL);
1022  free(msg);
1023  if (choice == 'p') {
1024    idx = get_free_partition(4);
1025    if (idx >= 0) add_partition(idx, LINUX_NATIVE);
1026    return;
1027  }
1028  if (choice =='l' && extended_offset) {
1029    add_logical_partition();
1030    return;
1031  }
1032  if (choice == 'e' && !extended_offset) {
1033    idx = get_free_partition(4);   
1034    if (idx >= 0) add_partition(idx, EXTENDED);
1035    return;
1036  }
1037}
1038
1039static void change_systype(void )
1040{
1041  int i, sys_id;
1042  struct partition *p;
1043  struct part_entry *pe;
1044
1045  i = ask_partition(num_parts);
1046  pe = &partitions[i-1];
1047  p = pe->part;
1048  if (is_partition_clear(p)) {
1049    xprintf("Partition %d doesn't exist yet!\n", i);
1050    return;
1051  }
1052  sys_id = read_hex("Hex code (L to list codes): ");
1053  if ((IS_EXTENDED(p->sys_ind) && !IS_EXTENDED(sys_id)) ||
1054      (!IS_EXTENDED(p->sys_ind) && IS_EXTENDED(sys_id))) {
1055    xprintf("you can't change a  partition to an extended or vice-versa\n");
1056    return;
1057  }
1058
1059  xprintf("Changed system type of partition %u to %0x (%s)\n",i, sys_id, get_type(sys_id));
1060  p->sys_ind = sys_id;
1061  pe->modified = 1;
1062}
1063
1064static void check(int n, unsigned h, unsigned s, unsigned c, sector_t start)
1065{   
1066  sector_t total, real_s, real_c;
1067
1068  real_s = sector(s) - 1;
1069  real_c = cylinder(s, c);
1070  total = (real_c * g_sectors + real_s) * g_heads + h;
1071  if (!total) xprintf("Partition %u contains sector 0\n", n);
1072  if (h >= g_heads)
1073    xprintf("Partition %u: head %u greater than maximum %lu\n", n, h + 1, g_heads);
1074  if (real_s >= g_sectors)
1075    xprintf("Partition %u: sector %u greater than maximum %lu\n", n, s, g_sectors);
1076  if (real_c >= g_cylinders)
1077    xprintf("Partition %u: cylinder %lld greater than maximum %lu\n", n, real_c + 1, g_cylinders);
1078  if (g_cylinders <= ONE_K && start != total)
1079    xprintf("Partition %u: previous sectors %lld disagrees with total %lld\n", n, start, total);
1080}
1081
1082static void verify_table(void)
1083{
1084  int i, j, ext_idx = -1;
1085  sector_t begin_sec[num_parts], end_sec[num_parts], total = 1;
1086  struct part_entry *pe;
1087  struct partition *p;
1088
1089  for (i = 0; i < num_parts; i++) {
1090    pe = &partitions[i];
1091    p = pe->part;
1092    if (is_partition_clear(p) || IS_EXTENDED(p->sys_ind)) {
1093      begin_sec[i] = 0xffffffff;
1094      end_sec[i] = 0;
1095    } else {
1096      begin_sec[i] = swap_le32toh(p->start4) + pe->start_offset;
1097      end_sec[i] = begin_sec[i] + swap_le32toh(p->size4) - 1;
1098    }
1099    if (IS_EXTENDED(p->sys_ind)) ext_idx = i;
1100  }
1101  for (i = 0; i < num_parts; i++) {
1102    pe = &partitions[i];
1103    p = pe->part;
1104    if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
1105      consistency_check(p, i);
1106      if ((swap_le32toh(p->start4) + pe->start_offset) < begin_sec[i])
1107        xprintf("Warning: bad start-of-data in partition %u\n", i + 1);
1108      check(i + 1, p->end_head, p->end_sector, p->end_cyl, end_sec[i]);
1109      total += end_sec[i] + 1 - begin_sec[i];
1110      for (j = 0; j < i; j++) {
1111        if ((begin_sec[i] >= begin_sec[j] && begin_sec[i] <= end_sec[j])
1112            || ((end_sec[i] <= end_sec[j] && end_sec[i] >= begin_sec[j]))) {
1113          xprintf("Warning: partition %u overlaps partition %u\n", j + 1, i + 1);
1114          total += begin_sec[i] >= begin_sec[j] ? begin_sec[i] : begin_sec[j];
1115          total -= end_sec[i] <= end_sec[j] ? end_sec[i] : end_sec[j];
1116        }
1117      }
1118    }
1119  }  
1120  if (extended_offset) {
1121    struct part_entry *pex = &partitions[ext_idx];
1122    sector_t e_last = swap_le32toh(pex->part->start4) +
1123      swap_le32toh(pex->part->size4) - 1;
1124
1125    for (i = 4; i < num_parts; i++) {
1126      total++;
1127      p = partitions[i].part;
1128      if (!p->sys_ind) {
1129        if (i != 4 || i + 1 < num_parts)
1130          xprintf("Warning: partition %u is empty\n", i + 1);
1131      } else if (begin_sec[i] < extended_offset || end_sec[i] > e_last)
1132        xprintf("Logical partition %u not entirely in partition %u\n", i + 1, ext_idx + 1);
1133    }
1134  }
1135  if (total > g_heads * g_sectors * g_cylinders)
1136    xprintf("Total allocated sectors %lld greater than the maximum "
1137        "%lu\n", total, g_heads * g_sectors * g_cylinders);
1138  else {
1139    total = g_heads * g_sectors * g_cylinders - total;
1140    if (total) xprintf("%lld unallocated sectors\n", total);
1141  }
1142}
1143
1144static void move_begning(int idx)
1145{
1146  sector_t start, num, new_start, end;
1147  char mesg[256];
1148  struct part_entry *pe = &partitions[idx];
1149  struct partition *p = pe->part;
1150
1151  if (chs_warn()) return;
1152  start = swap_le32toh(p->start4) + pe->start_offset;
1153  num = swap_le32toh(p->size4);
1154  end = start + num -1;
1155
1156  if (!num || IS_EXTENDED(p->sys_ind)) {
1157    xprintf("Partition %u doesn't have data area\n", idx+1);
1158    return;
1159  }
1160  sprintf(mesg, "New begining of data (0 - %lld, default %lld): ", 
1161      (long long int)(end), (long long int)(start));
1162  new_start = ask_value(mesg, 0, end, start);
1163  if (new_start != start) {
1164    set_levalue(p->start4, new_start - pe->start_offset);
1165    set_levalue(p->size4, end - new_start +1);
1166    if ((read_input("Recalculate C/H/S (Y/n): ", NULL) | 0x20) == 'y')
1167      set_hsc(p, new_start, end);
1168    pe->modified = 1;
1169  }
1170}
1171
1172static void print_raw_sectors()
1173{
1174  int i, j;
1175  struct part_entry *pe;
1176
1177  xprintf("Device: %s\n", disk_device);
1178  for (i = 3; i < num_parts; i++) {
1179    pe = &partitions[i];
1180    for (j = 0; j < g_sect_size; j++) {
1181      if (!(j % 16)) xprintf("\n0x%03X: ",j);
1182      xprintf("%02X ",pe->sec_buffer[j]);
1183    }
1184    xputc('\n');
1185  }
1186}
1187
1188static void print_partitions_list(int ext)
1189{
1190  int i;                                                                                    
1191  struct part_entry *pe;
1192  struct partition *p;
1193
1194  xprintf("Disk %s: %lu heads, %lu sectors, %lu cylinders\n\n", disk_device, g_heads, g_sectors, g_cylinders);
1195  xprintf("Nr AF  Hd Sec  Cyl  Hd Sec  Cyl      Start       Size ID\n");
1196
1197  for (i = 0; i < num_parts; i++) {
1198    pe = &partitions[i];
1199    p = pe->part;
1200    if (p) {
1201      if (ext && (i >= 4)) p = pe->part + 1;
1202      if(ext && i < 4 && !IS_EXTENDED(p->sys_ind)) continue;
1203
1204      xprintf("%2u %02x%4u%4u%5u%4u%4u%5u%11u%11u %02x\n",
1205          i+1, p->boot_ind, p->head,
1206          sector(p->sector), cylinder(p->sector, p->cyl),
1207          p->end_head,           
1208          sector(p->end_sector), cylinder(p->end_sector, p->end_cyl),
1209          swap_le32toh(p->start4),
1210          swap_le32toh(p->size4),
1211          p->sys_ind);
1212      if (p->sys_ind) consistency_check(p, i);
1213    }
1214  }
1215}
1216
1217//fix the partition table order to ascending
1218static void fix_order(void)
1219{
1220  sector_t first[num_parts], min;
1221  int i, j, oj, ojj, sj, sjj;
1222  struct part_entry *pe;
1223  struct partition *px, *py, temp, *pj, *pjj, tmp;
1224
1225  for (i = 0; i < num_parts; i++) {
1226    pe = &partitions[i];
1227    px = pe->part;
1228    if (is_partition_clear(px)) first[i] = 0xffffffff;
1229    else first[i] = swap_le32toh(px->start4) + pe->start_offset;
1230  }
1231  
1232  if (!check_order()) {
1233    xprintf("Ordering is already correct\n\n");
1234    return;
1235  }
1236  for (i = 0; i < 4; i++) {
1237    for (j = 0; j < 3; j++) {
1238      if (first[j] > first[j+1]) {
1239        py = partitions[j+1].part;
1240        px = partitions[j].part;
1241        memcpy(&temp, py, sizeof(struct partition));
1242        memcpy(py, px, sizeof(struct partition));
1243        memcpy(px, &temp, sizeof(struct partition));
1244        min = first[j+1];
1245        first[j+1] = first[j];
1246        first[j] = min;
1247        partitions[j].modified = 1;
1248      }
1249    }
1250  }
1251  for (i = 5; i < num_parts; i++) {
1252    for (j = 5; j < num_parts - 1; j++) {
1253      oj = partitions[j].start_offset;
1254      ojj = partitions[j+1].start_offset;
1255      if (oj > ojj) {
1256        partitions[j].start_offset = ojj;
1257        partitions[j+1].start_offset = oj;
1258        pj = partitions[j].part;
1259        set_levalue(pj->start4, swap_le32toh(pj->start4)+oj-ojj);
1260        pjj = partitions[j+1].part;
1261        set_levalue(pjj->start4, swap_le32toh(pjj->start4)+ojj-oj);
1262        set_levalue((partitions[j-1].part+1)->start4, ojj-extended_offset);
1263        set_levalue((partitions[j].part+1)->start4, oj-extended_offset);
1264      }
1265    }
1266  }
1267  for (i = 4; i < num_parts; i++) {
1268    for (j = 4; j < num_parts - 1; j++) {
1269      pj = partitions[j].part;
1270      pjj = partitions[j+1].part;
1271      sj = swap_le32toh(pj->start4);
1272      sjj = swap_le32toh(pjj->start4);
1273      oj = partitions[j].start_offset;
1274      ojj = partitions[j+1].start_offset;
1275      if (oj+sj > ojj+sjj) {
1276        tmp = *pj;
1277        *pj = *pjj;
1278        *pjj = tmp;
1279        set_levalue(pj->start4, ojj+sjj-oj);
1280        set_levalue(pjj->start4, oj+sj-ojj);
1281      }  
1282    }    
1283  }
1284  // If anything changed 
1285  for (j = 4; j < num_parts; j++) partitions[j].modified = 1;
1286  xprintf("Done!\n");
1287}
1288
1289static void print_menu(void)
1290{
1291  xprintf("a\ttoggle a bootable flag\n"
1292  "b\tedit bsd disklabel\n"
1293  "c\ttoggle the dos compatibility flag\n"
1294  "d\tdelete a partition\n"
1295  "l\tlist known partition types\n"
1296  "n\tadd a new partition\n"
1297  "o\tcreate a new empty DOS partition table\n"
1298  "p\tprint the partition table\n"
1299  "q\tquit without saving changes\n"
1300  "s\tcreate a new empty Sun disklabel\n"
1301  "t\tchange a partition's system id\n"
1302  "u\tchange display/entry units\n"
1303  "v\tverify the partition table\n"
1304  "w\twrite table to disk and exit\n"
1305  "x\textra functionality (experts only)\n");
1306}
1307
1308static void print_xmenu(void)
1309{
1310  xprintf("b\tmove beginning of data in a partition\n"
1311  "c\tchange number of cylinders\n"
1312  "d\tprint the raw data in the partition table\n"
1313  "e\tlist extended partitions\n"
1314  "f\tfix partition order\n"  
1315  "h\tchange number of heads\n"
1316  "p\tprint the partition table\n"
1317  "q\tquit without saving changes\n"
1318  "r\treturn to main menu\n"
1319  "s\tchange number of sectors/track\n"
1320  "v\tverify the partition table\n"
1321  "w\twrite table to disk and exit\n");
1322}
1323
1324static void expert_menu(void)
1325{
1326  int choice, idx;
1327  sector_t value;
1328  char mesg[256];
1329
1330  while (1) {
1331    xputc('\n');
1332    char *msg = "Expert Command ('m' for help): ";
1333    choice = 0x20 | read_input(msg, NULL);
1334    switch (choice) {
1335      case 'b': //move data begining in partition
1336        idx = ask_partition(num_parts);
1337        move_begning(idx - 1);
1338        break;
1339      case 'c': //change cylinders
1340          sprintf(mesg, "Number of cylinders (1 - 1048576, default %lu): ", g_cylinders);
1341          value = ask_value(mesg, 1, 1048576, g_cylinders);
1342          g_cylinders = TT.cylinders = value;
1343          toys.optflags |= FLAG_C;
1344          if(g_cylinders > ONE_K)
1345            xprintf("\nThe number of cylinders for this disk is set to %lu.\n"
1346                "There is nothing wrong with that, but this is larger than 1024,\n"
1347                "and could in certain setups cause problems.\n", g_cylinders);
1348        break;
1349      case 'd': //print raw data in part tables
1350        print_raw_sectors();
1351        break;
1352      case 'e': //list extended partitions
1353        print_partitions_list(1);
1354        break;
1355      case 'f': //fix part order
1356        fix_order();
1357        break;
1358      case 'h': //change number of heads
1359          sprintf(mesg, "Number of heads (1 - 256, default %lu): ", g_heads);
1360          value = ask_value(mesg, 1, 256, g_heads);
1361          g_heads = TT.heads = value;
1362          toys.optflags |= FLAG_H;
1363        break;
1364      case 'p': //print partition table
1365        print_partitions_list(0);
1366        break;
1367      case 'q':
1368        free_bufs();
1369        close(dev_fd);
1370        xputc('\n');
1371        exit(0);
1372        break;
1373      case 'r':
1374        return;
1375        break;
1376      case 's': //change sector/track
1377          sprintf(mesg, "Number of sectors (1 - 63, default %lu): ", g_sectors);
1378          value = ask_value(mesg, 1, 63, g_sectors);
1379          g_sectors = TT.sectors = value;
1380          toys.optflags |= FLAG_H;
1381        break;
1382      case 'v':
1383        verify_table();
1384        break;
1385      case 'w':
1386        write_table();
1387        toys.exitval = 0;
1388        exit(0);
1389        break;
1390      case 'm':
1391        print_xmenu();
1392        break;
1393      default:
1394        xprintf("Unknown command '%c'\n",choice);
1395        print_xmenu();
1396        break;
1397    }
1398  } //while(1)
1399}
1400
1401static int disk_proper(const char *device)
1402{
1403  unsigned length;
1404  int fd = open(device, O_RDONLY);
1405
1406  if (fd != -1) {
1407    struct hd_geometry dev_geo;
1408    dev_geo.heads = 0;
1409    dev_geo.sectors = 0;
1410    int err = ioctl(fd, HDIO_GETGEO, &dev_geo);
1411    close(fd);
1412    if (!err) return (dev_geo.start == 0);
1413  }
1414  length = strlen(device);
1415  if (length != 0 && isdigit(device[length - 1])) return 0;
1416  return 1;
1417}
1418
1419static void reset_entries()
1420{
1421  int i;
1422
1423  memset(MBRbuf, 0, sizeof(MBRbuf));
1424  for (i = 4; i < num_parts; i++)
1425    memset(&partitions[i], 0, sizeof(struct part_entry));
1426}
1427
1428//this will keep dev_fd = 3 always alive
1429static void move_fd()
1430{
1431  int fd = xopen("/dev/null", O_RDONLY);
1432  if(fd != dev_fd) {
1433    if(dup2(fd, dev_fd) != dev_fd) perror_exit("Can't dup2");
1434    close(fd);
1435  }
1436}
1437
1438/* Read proc/partitions and then print the details
1439 * for partitions on each device
1440 */
1441static void read_and_print_parts()
1442{
1443  unsigned int ma, mi, sz;
1444  char *name = toybuf, *buffer = toybuf + ONE_K, *device = toybuf + 2048;
1445  FILE* fp = xfopen("/proc/partitions", "r");
1446
1447  while (fgets(buffer, ONE_K, fp)) {
1448    reset_entries();
1449    num_parts = 4;
1450    memset(name, 0, sizeof(name));
1451    if (sscanf(buffer, " %u %u %u %[^\n ]", &ma, &mi, &sz, name) != 4)
1452      continue;
1453      
1454    sprintf(device,"/dev/%s",name);
1455    if (disk_proper(device)) {
1456      if (read_mbr(device, 0)) continue;
1457      print_mbr(1);
1458      move_fd();
1459    }
1460  }
1461  fclose(fp);
1462}
1463
1464void fdisk_main(void)
1465{
1466  int choice, p;
1467
1468  init_members();
1469  move_fd();
1470  if (TT.heads >= 256) TT.heads = 0;
1471  if (TT.sectors >= 64) TT.sectors = 0;
1472  if (toys.optflags & FLAG_u) disp_unit_cyl = 0;
1473  if (toys.optflags & FLAG_l) {
1474    if (!toys.optc) read_and_print_parts();
1475    else {
1476      while(*toys.optargs){
1477        if (read_mbr(*toys.optargs, 0)) {
1478          toys.optargs++;
1479          continue;
1480        }
1481        print_mbr(1);
1482        move_fd();
1483        toys.optargs++;
1484      }
1485    }
1486    toys.exitval = 0;
1487    return;
1488  } else {
1489    if (toys.optc != 1) help_exit(0);
1490    if (read_mbr(toys.optargs[0], 1)) return;
1491    while (1) {
1492      xputc('\n');
1493      char *msg = "Command ('m' for help): ";
1494      choice = 0x20 | read_input(msg, NULL);
1495      switch (choice) {
1496        case 'a':
1497          p = ask_partition(num_parts);
1498          toggle_active_flag(p - 1); //partition table index start from 0.
1499          break;
1500        case 'b':
1501          break;
1502        case 'c':
1503          dos_flag = !dos_flag;
1504          xprintf("Dos compatible flag is %s\n", dos_flag?"Set" : "Not set");
1505          break;
1506        case 'd':
1507          p = get_non_free_partition(num_parts); //4 was here
1508          if(p >= 0) delete_partition(p);
1509          break;
1510        case 'l':
1511          list_types();
1512          break;
1513        case 'n': //add new partition
1514          add_new_partition();
1515          break;
1516        case 'o':
1517          create_empty_doslabel();
1518          break;
1519        case 'p':
1520          print_mbr(0);
1521          break;
1522        case 'q':
1523          free_bufs();
1524          close(dev_fd);
1525          xputc('\n');
1526          exit(0);
1527          break;
1528        case 's':
1529          break;
1530        case 't':
1531          change_systype();
1532          break;
1533        case 'u':
1534          disp_unit_cyl = !disp_unit_cyl;
1535          xprintf("Changing Display/Entry units to %s\n",disp_unit_cyl?"cylinders" : "sectors");
1536          break;
1537        case 'v':
1538          verify_table();
1539          break;
1540        case 'w':
1541          write_table();
1542          toys.exitval = 0;
1543          return;
1544          break;
1545        case 'x':
1546          expert_menu();
1547          break;
1548        case 'm':
1549          print_menu();
1550          break;
1551        default:
1552          xprintf("%c: Unknown command\n",choice);
1553          break;
1554      }
1555    } //while(1)
1556  }
1557}
1558