home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / RESCUE / FDISK.C next >
Encoding:
C/C++ Source or Header  |  1995-04-20  |  32.8 KB  |  1,355 lines

  1. /* fdisk.c -- Partition table manipulator for Linux.
  2.  *
  3.  * Copyright (C) 1992  A. V. Le Blanc (LeBlanc@mcc.ac.uk)
  4.  *
  5.  * This program is free software.  You can redistribute it and/or
  6.  * modify it under the terms of the GNU General Public License as
  7.  * published by the Free Software Foundation: either version 1 or
  8.  * (at your option) any later version.
  9.  *
  10.  * Before Linux version 0.95c, this program requires a kernel patch.
  11.  *
  12.  * Modified, Tue Feb  2 18:46:49 1993, faith@cs.unc.edu to better support SCSI.
  13.  * Modified, Sat Feb 27 18:11:27 1993, faith@cs.unc.edu: added extfs support.
  14.  * Modified, Sat Mar  6 10:14:12 1993, faith@cs.unc.edu: added more comments.
  15.  * Modified, Sat Mar  6 12:25:45 1993, faith@cs.unc.edu:
  16.  *    Added patches from Michael Bischoff (i1041905@ws.rz.tu-bs.de
  17.  *    or mbi@mo.math.nat.tu-bs.de) to fix the following problems:
  18.  *    1) Incorrect mapping of head/sector/cylinder to absolute sector
  19.  *    2) Odd sector count causes one sector to be lost
  20.  * Modified, Sat Mar  6 12:25:52 1993, faith@cs.unc.edu: improved verification.
  21.  * Modified, Sat Apr 17 15:00:00 1993, LeBlanc@mcc.ac.uk: add -s, fix -l.
  22.  * Modified, Sat Apr 24 10:00:00 1993, LeBlanc@mcc.ac.uk: fix overlap bug.
  23.  * Modified, Wed May  5 21:30:00 1993, LeBlanc@mcc.ac.uk: errors to stderr.
  24.  * Modified, Mon Mar 21 20:00:00 1994, LeBlanc@mcc.ac.uk:
  25.  *    more stderr for messages, avoid division by 0, and
  26.  *    give reboot message only if ioctl(fd, BLKRRPART) fails.
  27.  * Modified, Mon Apr 25 01:01:05 1994, martin@cs.unc.edu:
  28.  *    1) Added support for DOS, OS/2, ... compatibility.  We should be able
  29.  *       use this fdisk to partition our drives for other operating systems.
  30.  *    2) Added a print the raw data in the partition table command.
  31.  * Modified, Wed Jun 22 21:05:30 1994, faith@cs.unc.edu:
  32.  *    Added/changed a few partition type names to conform to cfdisk.
  33.  *    (suggested by Sujal, smpatel@wam.umd.edu)
  34.  */
  35.  
  36.  
  37. #include <unistd.h>
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <string.h>
  41. #include <fcntl.h>
  42. #include <ctype.h>
  43. #include <setjmp.h>
  44. #include <errno.h>
  45.  
  46. #include <sys/ioctl.h>
  47.  
  48. #include <linux/genhd.h>
  49. #include <linux/hdreg.h>
  50. #include <linux/fs.h>
  51.  
  52. #if defined(__GNUC__) || defined(HAS_LONG_LONG)
  53. typedef long long ext2_loff_t;
  54. #else
  55. typedef long      ext2_loff_t;
  56. #endif
  57.  
  58. extern ext2_loff_t ext2_llseek(unsigned int fd,
  59.                    ext2_loff_t offset,
  60.                    unsigned int origin);
  61.  
  62. #define hex_val(c)    ({ \
  63.                 char _c = (c); \
  64.                 isdigit(_c) ? _c - '0' : \
  65.                 tolower(_c) + 10 - 'a'; \
  66.             })
  67.  
  68.  
  69. #define VERSION    "2.0 (>2GB)"
  70.  
  71. #define DEFAULT_DEVICE    "/dev/hda"
  72. #define ALTERNATE_DEVICE "/dev/sda"
  73. #define LINE_LENGTH    80
  74. #define MAXIMUM_PARTS    60
  75. #define SECTOR_SIZE    512
  76. #define PART_TABLE_FLAG    0xaa55
  77. #define table_check(b)    ((unsigned short *)((b) + 0x1fe))
  78. #define offset(b, n)    ((struct partition *)((b) + 0x1be + \
  79.                 (n) * sizeof(struct partition)))
  80. #define sector(s)    ((s) & 0x3f)
  81. #define cylinder(s, c)    ((c) | (((s) & 0xc0) << 2))
  82.  
  83. #define calculate(h,s,c) (sector(s) - 1 + sectors * \
  84.                 ((h) + heads * cylinder(s,c)))
  85. #define set_hsc(h,s,c,sector) { \
  86.                 s = sector % sectors + 1;    \
  87.                 sector /= sectors;    \
  88.                 h = sector % heads;    \
  89.                 sector /= heads;    \
  90.                 c = sector & 0xff;    \
  91.                 s |= (sector >> 2) & 0xc0;    \
  92.             }
  93.  
  94. #define cround(n)    (((n) + display_factor * unit_flag) / display_factor)
  95. #define ACTIVE_FLAG    0x80
  96. #define EXTENDED    5
  97.  
  98. #define LINUX_PARTITION    0x81
  99. #define LINUX_SWAP    0x82
  100. #define LINUX_NATIVE    0x83
  101.  
  102. enum failure {usage, unable_to_open, unable_to_read, unable_to_seek,
  103.     unable_to_write, out_of_memory};
  104.  
  105. char    *disk_device = DEFAULT_DEVICE,    /* hda, unless specified */
  106.     *line_ptr,            /* interactive input */
  107.     line_buffer[LINE_LENGTH],
  108.     changed[MAXIMUM_PARTS],        /* marks changed buffers */
  109.     buffer[SECTOR_SIZE],        /* first four partitions */
  110.     *buffers[MAXIMUM_PARTS]        /* pointers to buffers */
  111.         = {buffer, buffer, buffer, buffer};
  112.  
  113. int    fd,                /* the disk */
  114.     ext_index,            /* the prime extended partition */
  115.     listing = 0,            /* no aborts for fdisk -l */
  116.     size_flag = 0,
  117.     dos_compatible_flag = ~0,
  118.     partitions = 4;            /* maximum partition + 1 */
  119.  
  120. uint    heads,
  121.     sectors,
  122.     cylinders,
  123.     sector_offset = 1,
  124.     display_factor = 1,        /* in units/sector */
  125.     unit_flag = 1,
  126.     full_bits = 0,            /* 1024 cylinders in sectors */
  127.     extended_offset = 0,        /* offset of link pointers */
  128.     offsets[MAXIMUM_PARTS] = {0, 0, 0, 0};
  129.  
  130. struct    partition *part_table[MAXIMUM_PARTS]    /* partitions */
  131.         = {offset(buffer, 0), offset(buffer, 1),
  132.         offset(buffer, 2), offset(buffer, 3)},
  133.     *ext_pointers[MAXIMUM_PARTS]        /* link pointers */
  134.         = {NULL, NULL, NULL, NULL};
  135.  
  136. struct systypes {
  137.     unsigned char index;
  138.     char *name;
  139.     } sys_types[] = {
  140.         {0, "Empty"},
  141.         {1, "DOS 12-bit FAT"},
  142.         {2, "XENIX root"},
  143.         {3, "XENIX usr"},
  144.         {4, "DOS 16-bit <32M"},
  145.         {EXTENDED, "Extended"},
  146.         {6, "DOS 16-bit >=32M"},
  147.         {7, "OS/2 HPFS"},        /* or QNX? */
  148.         {8, "AIX"},
  149.         {9, "AIX bootable"},
  150.         {10, "OS/2 Boot Manager"},
  151.         {0x40, "Venix 80286"},
  152.         {0x51, "Novell?"},
  153.         {0x52, "Microport"},        /* or CPM? */
  154.         {0x63, "GNU HURD"},        /* or System V/386? */
  155.         {0x64, "Novell"},
  156.         {0x75, "PC/IX"},
  157.         {0x80, "Old MINIX"},        /* Minix 1.4a and earlier */
  158.  
  159.         {LINUX_PARTITION, "Linux/MINIX"}, /* Minix 1.4b and later */
  160.         {LINUX_SWAP, "Linux swap"},
  161.         {LINUX_NATIVE, "Linux native"},
  162.  
  163.         {0x93, "Amoeba"},
  164.         {0x94, "Amoeba BBT"},        /* (bad block table) */
  165.         {0xa5, "BSD/386"},
  166.         {0xb7, "BSDI fs"},
  167.         {0xb8, "BSDI swap"},
  168.         {0xc7, "Syrinx"},
  169.         {0xdb, "CP/M"},            /* or Concurrent DOS? */
  170.         {0xe1, "DOS access"},
  171.         {0xe3, "DOS R/O"},
  172.         {0xf2, "DOS secondary"},
  173.         {0xff, "BBT"}            /* (bad track table) */
  174.     };
  175.  
  176. jmp_buf listingbuf;
  177.  
  178. void fatal(enum failure why)
  179. {
  180.     char    error[LINE_LENGTH],
  181.         *message = error;
  182.  
  183.     if (listing) {
  184.         close(fd);
  185.         longjmp(listingbuf, 1);
  186.     }
  187.  
  188.     switch (why) {
  189.         case usage: message =
  190.             "Usage: fdisk [-l] [-v] [-s /dev/hdxn] [/dev/hdx]\n";
  191.             break;
  192.         case unable_to_open:
  193.             sprintf(error, "Unable to open %s\n", disk_device);
  194.             break;
  195.         case unable_to_read:
  196.             sprintf(error, "Unable to read %s\n", disk_device);
  197.             break;
  198.         case unable_to_seek:
  199.             sprintf(error, "Unable to seek on %s\n", disk_device);
  200.             break;
  201.         case unable_to_write:
  202.             sprintf(error, "Unable to write %s\n", disk_device);
  203.             break;
  204.         case out_of_memory:
  205.             message = "Unable to allocate any more memory\n";
  206.             break;
  207.         default: message = "Fatal error\n";
  208.     }
  209.  
  210.     if ( listing != 1 ) {
  211.         fputc('\n', stderr);
  212.         fputs(message, stderr);
  213.     }
  214.     exit(1);
  215. }
  216.  
  217. void menu(void)
  218. {
  219.     puts("Command action\n"
  220.         "   a   toggle a bootable flag\n"
  221.         "   c   toggle the dos compatiblity flag\n"
  222.         "   d   delete a partition\n"
  223.         "   l   list known partition types\n"
  224.         "   m   print this menu\n"
  225.         "   n   add a new partition\n"
  226.         "   p   print the partition table\n"
  227.         "   q   quit without saving changes\n"
  228.         "   t   change a partition's system id\n"
  229.         "   u   change display/entry units\n"
  230.         "   v   verify the partition table\n"
  231.         "   w   write table to disk and exit\n"
  232.         "   x   extra functionality (experts only)"
  233.     );
  234. }
  235.  
  236. void xmenu(void)
  237. {
  238.     puts("Command action\n"
  239.         "   b   move beginning of data in a partition\n"
  240.         "   c   change number of cylinders\n"
  241.         "   d   print the raw data in the partition table\n"
  242.         "   e   list extended partitions\n"
  243.         "   h   change number of heads\n"
  244.         "   m   print this menu\n"
  245.         "   p   print the partition table\n"
  246.         "   q   quit without saving changes\n"
  247.         "   r   return to main menu\n"
  248.         "   s   change number of sectors\n"
  249.         "   w   write table to disk and exit"
  250.     );
  251. }
  252.  
  253. char *partition_type(unsigned char type)
  254. {
  255.     int high = sizeof(sys_types) / sizeof(struct systypes),
  256.         low = 0, mid;
  257.     uint tmp;
  258.  
  259.     while (high >= low) {
  260.         mid = (high + low) >> 1;
  261.         if ((tmp = sys_types[mid].index) == type)
  262.             return sys_types[mid].name;
  263.         else if (tmp < type)
  264.             low = mid + 1;
  265.         else high = mid - 1;
  266.     }
  267.     return NULL;
  268. }
  269.  
  270. void list_types(void)
  271. {
  272.     uint last[4], done = 0, next = 0,
  273.         size = sizeof(sys_types) / sizeof(struct systypes);
  274.     int i;
  275.  
  276.     for (i = 3; i >= 0; i--)
  277.         last[3 - i] = done += (size + i - done) / (i + 1);
  278.     i = done = 0;
  279.  
  280.     do {
  281.         printf("%c%2x  %-15.15s", i ? ' ' : '\n',
  282.             sys_types[next].index, sys_types[next].name);
  283.         next = last[i++] + done;
  284.         if (i > 3 || next >= last[i]) {
  285.             i = 0;
  286.             next = ++done;
  287.         }
  288.     } while (done < last[0]);
  289.     putchar('\n');
  290. }
  291.  
  292. void clear_partition(struct partition *p)
  293. {
  294.     p->boot_ind = 0;
  295.     p->head = 0;
  296.     p->sector = 0;
  297.     p->cyl = 0;
  298.     p->sys_ind = 0;
  299.     p->end_head = 0;
  300.     p->end_sector = 0;
  301.     p->end_cyl = 0;
  302.     p->start_sect = 0;
  303.     p->nr_sects = 0;
  304. }
  305.  
  306. void set_partition(int i, struct partition *p, uint start, uint stop,
  307.     int sys, uint offset)
  308. {
  309.     p->boot_ind = 0;
  310.     p->sys_ind = sys;
  311.     p->start_sect = start - offset;
  312.     p->nr_sects = stop - start + 1;
  313.     if (dos_compatible_flag && (start/(sectors*heads) > 1023))
  314.         start = heads*sectors*1024 - 1;
  315.     set_hsc(p->head, p->sector, p->cyl, start);
  316.     if (dos_compatible_flag && (stop/(sectors*heads) > 1023))
  317.         stop = heads*sectors*1024 - 1;
  318.     set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
  319.     changed[i] = 1;
  320. }
  321.  
  322. int test_c(char **m, char *mesg)
  323. {
  324.     int val = 0;
  325.     if (!*m)
  326.         if ( listing != 1 ) {
  327.             fprintf(stderr, "You must set");
  328.         }
  329.     else {
  330.         if ( listing != 1 ) {
  331.             fprintf(stderr, " %s", *m);
  332.         }
  333.         val = 1;
  334.     }
  335.     *m = mesg;
  336.     return val;
  337. }
  338.  
  339. int warn_geometry(void)
  340. {
  341.     char *m = NULL;
  342.     int prev = 0;
  343.     if (!heads)
  344.         prev = test_c(&m, "heads");
  345.     if (!sectors)
  346.         prev = test_c(&m, "sectors");
  347.     if (!cylinders)
  348.         prev = test_c(&m, "cylinders");
  349.     if (!m)
  350.         return 0;
  351.     if ( listing != 1 ) {
  352.         fprintf(stderr,
  353.         "%s%s.\nYou can do this from the extra functions menu.\n",
  354.         prev ? " and " : " ", m);
  355.     }
  356.     return 1;
  357. }
  358.  
  359. uint rounded(uint calcul, uint start)
  360. {
  361.     uint i;
  362.     if (!full_bits)
  363.         return calcul;
  364.     while ((i = calcul + full_bits) <= start)
  365.         calcul = i;
  366.     return calcul;
  367. }
  368.  
  369. void update_units(void)
  370. {
  371.     full_bits = 1024 * heads * sectors;
  372.     if (unit_flag && full_bits)
  373.         display_factor = full_bits >> 10;
  374.     else display_factor = 1;
  375. }
  376.  
  377. void warn_cylinders(void)
  378. {
  379.     update_units();
  380.     if (cylinders > 1024)
  381.         if ( listing != 1 ) {
  382.             fprintf(stderr, "The number of cylinders for this disk is "
  383.             "set to %d.\nThis is larger than 1024, and may cause "
  384.             "problems with:\n"
  385.             "1) software that runs at boot time (e.g., LILO)\n"
  386.             "2) booting and partitioning software form other OSs\n"
  387.             "   (e.g., DOS FDISK, OS/2 FDISK)\n",
  388.             cylinders);
  389.         }
  390. }
  391.  
  392. void read_extended(struct partition *p)
  393. {
  394.     int i;
  395.     struct partition *q;
  396.  
  397.     ext_pointers[ext_index] = part_table[ext_index];
  398.     if (!p->start_sect)
  399.         if ( listing != 1 ) {
  400.             fprintf(stderr, "Bad offset in primary extended partition\n");
  401.         }
  402.     else while (p->sys_ind == EXTENDED) {
  403.         if (partitions >= MAXIMUM_PARTS) {
  404.             if ( listing != 1 ) {
  405.                 fprintf(stderr,
  406.                 "Warning: deleting partitions after %d\n",
  407.                 partitions);
  408.             }
  409.             clear_partition(ext_pointers[partitions - 1]);
  410.             changed[partitions - 1] = 1;
  411.             return;
  412.         }
  413.         offsets[partitions] = extended_offset + p->start_sect;
  414.         if (!extended_offset)
  415.             extended_offset = p->start_sect;
  416.         if (ext2_llseek(fd, offsets[partitions]
  417.                    * SECTOR_SIZE, SEEK_SET) < 0)
  418.             fatal(unable_to_seek);
  419.         if (!(buffers[partitions] = (char *) malloc(SECTOR_SIZE)))
  420.             fatal(out_of_memory);
  421.         if (SECTOR_SIZE != read(fd, buffers[partitions], SECTOR_SIZE))
  422.             fatal(unable_to_read);
  423.         part_table[partitions] = ext_pointers[partitions] = NULL;
  424.         q = p = offset(buffers[partitions], 0);
  425.         for (i = 0; i < 4; i++, p++) {
  426.             if (p->sys_ind == EXTENDED)
  427.                 if (ext_pointers[partitions])
  428.                     fprintf(stderr, "Warning: extra link "
  429.                         "pointer in partition table "
  430.                         "%d\n", partitions + 1);
  431.                 else
  432.                     ext_pointers[partitions] = p;
  433.             else if (p->sys_ind)
  434.                 if (!part_table[partitions])
  435.                     part_table[partitions] = p;
  436.         }
  437.         if (!part_table[partitions])
  438.             if (q != ext_pointers[partitions])
  439.                 part_table[partitions] = q;
  440.             else part_table[partitions] = q + 1;
  441.         if (!ext_pointers[partitions])
  442.             if (q != part_table[partitions])
  443.                 ext_pointers[partitions] = q;
  444.             else ext_pointers[partitions] = q + 1;
  445.         p = ext_pointers[partitions++];
  446.     }
  447. }
  448.  
  449. void get_boot(void)
  450. {
  451.     int i;
  452.     struct hd_geometry geometry;
  453.  
  454.     partitions = 4;
  455.     if ((fd = open(disk_device, O_RDWR)) < 0)
  456.         fatal(unable_to_open);
  457.     if (SECTOR_SIZE != read(fd, buffer, SECTOR_SIZE))
  458.         fatal(unable_to_read);
  459.     if (!ioctl(fd, HDIO_REQ, &geometry)) {
  460.         heads = geometry.heads;
  461.         sectors = geometry.sectors;
  462.         cylinders = geometry.cylinders;
  463.         if (dos_compatible_flag)
  464.             sector_offset = sectors;
  465.         warn_cylinders();
  466.     }
  467.     else update_units();
  468.     warn_geometry();
  469.  
  470.     for (i = 0; i < 4; i++)
  471.         if(part_table[i]->sys_ind == EXTENDED)
  472.             if (partitions != 4)
  473.                 fprintf(stderr, "Ignoring extra extended "
  474.                     "partition %d\n", i + 1);
  475.             else read_extended(part_table[ext_index = i]);
  476.  
  477.     for (i = 3; i < partitions; i++)
  478.         if (*table_check(buffers[i]) != PART_TABLE_FLAG) {
  479.             if ( listing != 1 ) {
  480.                 fprintf(stderr, "Warning: invalid flag %04x of parti"
  481.                 "tion table %d will be corrected by w(rite)\n",
  482.                 *table_check(buffers[i]), i + 1);
  483.             }
  484.             changed[i] = 1;
  485.         }
  486. }
  487.  
  488. int read_line(void)
  489. {
  490.     if (!fgets(line_buffer, LINE_LENGTH, stdin))
  491.         return 0;
  492.     line_ptr = line_buffer;
  493.     while (*line_ptr && !isgraph(*line_ptr))
  494.         line_ptr++;
  495.     return *line_ptr;
  496. }
  497.  
  498. char read_char(char *mesg)
  499. {
  500.     do
  501.         fputs(mesg, stdout);
  502.     while (!read_line());
  503.     return *line_ptr;
  504. }
  505.  
  506. uint read_int(uint low, uint high, char *mesg)
  507. {
  508.     uint i;
  509.     char ms[70];
  510.     sprintf(ms, "%s (%d-%d): ", mesg, low, high);
  511.  
  512.     while (1) {
  513.         while (!isdigit(read_char(ms)) &&
  514.             (!size_flag || *line_ptr != '+'));
  515.         if (*line_ptr == '+') {
  516.             i = atoi(++line_ptr);
  517.             while (isdigit(*line_ptr))
  518.                 line_ptr++;
  519.             switch (*line_ptr) {
  520.                 case 'c':
  521.                 case 'C': if (!unit_flag)
  522.                         i *= heads * sectors;
  523.                     break;
  524.                 case 'k':
  525.                 case 'K': i *= 2;
  526.                     i /= display_factor;
  527.                     break;
  528.                 case 'm':
  529.                 case 'M': i *= 2048;
  530.                     i /= display_factor;
  531.                     break;
  532.                 default: break;
  533.             }
  534.             i += low;
  535.         }
  536.         else i = atoi(line_ptr);
  537.         if (i >= low && i <= high)
  538.             break;
  539.     }
  540.     size_flag = 0;
  541.     return i;
  542. }
  543.  
  544. int get_partition(int warn, int max)
  545. {
  546.     int i = read_int(1, max, "Partition number") - 1;
  547.  
  548.     if (warn && !part_table[i]->sys_ind)
  549.         if ( listing != 1 ) {
  550.             fprintf(stderr, "Warning: partition %d has empty type\n",
  551.             i + 1);
  552.         }
  553.     return i;
  554. }
  555.  
  556. char *const str_units(void)
  557. {
  558.     return unit_flag ? "cylinder" : "sector";
  559. }
  560.  
  561. void change_units(void)
  562. {
  563.     if (unit_flag = !unit_flag)
  564.         display_factor = 1;
  565.     else display_factor = heads * sectors;
  566.     update_units();
  567.     printf("Changing display/entry units to %ss\n",
  568.         str_units());
  569. }
  570.  
  571. void toggle_active(int i)
  572. {
  573.     struct partition *p = part_table[i];
  574.  
  575.     if (p->sys_ind == EXTENDED && !p->boot_ind)
  576.         fprintf(stderr,
  577.             "WARNING: Partition %d is an extended partition\n",
  578.             i + 1);
  579.     if (p->boot_ind)
  580.         p->boot_ind = 0;
  581.     else p->boot_ind = ACTIVE_FLAG;
  582.     changed[i] = 1;
  583. }
  584.  
  585. void toggle_dos(void)
  586. {
  587.     dos_compatible_flag = ~dos_compatible_flag;
  588.     printf("DOS Compatibility flag is ");
  589.     if (dos_compatible_flag)
  590.         sector_offset = sectors;
  591.     else {
  592.         sector_offset = 1;
  593.         printf("not ");
  594.     }
  595.     printf("set\n");
  596. }
  597.  
  598. void delete_partition(int i)
  599. {
  600.     struct partition *p = part_table[i], *q = ext_pointers[i];
  601.  
  602. /* Note that for the fifth partition (i == 4) we don't actually
  603.  * decrement partitions.
  604.  */
  605.  
  606.     if (warn_geometry())
  607.         return;
  608.     changed[i] = 1;
  609.     if (i < 4) {
  610.         if (p->sys_ind == EXTENDED && i == ext_index) {
  611.             while (partitions > 4)
  612.                 free(buffers[--partitions]);
  613.             ext_pointers[ext_index] = NULL;
  614.             extended_offset = 0;
  615.         }
  616.         clear_partition(p);
  617.     }
  618.     else if (!q->sys_ind && i > 4) {
  619.         free(buffers[--partitions]);
  620.         clear_partition(ext_pointers[--i]);
  621.     }
  622.     else if (i > 3) {
  623.         if (i > 4) {
  624.             p = ext_pointers[i - 1];
  625.             p->boot_ind = 0;
  626.             p->head = q->head;
  627.             p->sector = q->sector;
  628.             p->cyl = q->cyl;
  629.             p->sys_ind = EXTENDED;
  630.             p->end_head = q->end_head;
  631.             p->end_sector = q->end_sector;
  632.             p->end_cyl = q->end_cyl;
  633.             p->start_sect = q->start_sect;
  634.             p->nr_sects = q->nr_sects;
  635.             changed[i - 1] = 1;
  636.         }
  637.         else {
  638.             part_table[5]->start_sect +=
  639.                 offsets[5] - extended_offset;
  640.             offsets[5] = extended_offset;
  641.             changed[5] = 1;
  642.         }
  643.         if (partitions > 5) {
  644.             partitions--;
  645.             free(buffers[i]);
  646.             while (i < partitions) {
  647.                 changed[i] = changed[i + 1];
  648.                 buffers[i] = buffers[i + 1];
  649.                 offsets[i] = offsets[i + 1];
  650.                 part_table[i] = part_table[i + 1];
  651.                 ext_pointers[i] = ext_pointers[i + 1];
  652.                 i++;
  653.             }
  654.         }
  655.         else
  656.             clear_partition(part_table[i]);
  657.     }
  658. }
  659.  
  660. void change_sysid(void)
  661. {
  662.     char *temp;
  663.     int i = get_partition(0, partitions), sys;
  664.     struct partition *p = part_table[i];
  665.  
  666.     if ((sys = p->sys_ind) == EXTENDED)
  667.         printf("Partition %d is extended.  Delete it\n", i + 1);
  668.     else if (!sys)
  669.         printf("Partition %d does not exist yet!\n", i + 1);
  670.     else while (1) {
  671.         read_char("Hex code (type L to list codes): ");
  672.         if (tolower(*line_ptr) == 'l')
  673.             list_types();
  674.         else if (isxdigit(*line_ptr)) {
  675.             sys = 0;
  676.             do
  677.                 sys = sys << 4 | hex_val(*line_ptr++);
  678.             while (isxdigit(*line_ptr));
  679.             if (!sys) {
  680.                 delete_partition(i);
  681.                 break;
  682.             }
  683.             else if (sys == EXTENDED) {
  684.                 printf("You may not change a partition "
  685.                     "to be an extended partition\n");
  686.                 break;
  687.             }
  688.             else if (sys < 256) {
  689.                 if (sys == p->sys_ind)
  690.                     break;
  691.                 part_table[i]->sys_ind = sys;
  692.                 printf ("Changed system type of partition %d "
  693.                     "to %x (%s)\n", i + 1, sys,
  694.                     (temp = partition_type(sys)) ? temp :
  695.                     "Unknown");
  696.                 changed[i] = 1;
  697.                 break;
  698.             }
  699.         }
  700.     }
  701. }
  702.  
  703. /* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
  704.  * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
  705.  * Jan.  1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
  706.  * Lubkin Oct.  1991). */
  707.  
  708. static void long2chs(ulong ls, uint *c, uint *h, uint *s)
  709. {
  710.     int    spc = heads * sectors;
  711.  
  712.     *c = ls / spc;
  713.     ls = ls % spc;
  714.     *h = ls / sectors;
  715.     *s = ls % sectors + 1;    /* sectors count from 1 */
  716. }
  717.  
  718. static void check_consistency(struct partition *p, int partition)
  719. {
  720.     uint    pbc, pbh, pbs;        /* physical beginning c, h, s */
  721.     uint    pec, peh, pes;        /* physical ending c, h, s */
  722.     uint    lbc, lbh, lbs;        /* logical beginning c, h, s */
  723.     uint    lec, leh, les;        /* logical ending c, h, s */
  724.  
  725.     if (!heads || !sectors || (partition >= 4))
  726.         return;        /* do not check extended partitions */
  727.  
  728. /* physical beginning c, h, s */
  729.     pbc = p->cyl & 0xff | (p->sector << 2) & 0x300;
  730.     pbh = p->head;
  731.     pbs = p->sector & 0x3f;
  732.  
  733. /* physical ending c, h, s */
  734.     pec = p->end_cyl & 0xff | (p->end_sector << 2) & 0x300;
  735.     peh = p->end_head;
  736.     pes = p->end_sector & 0x3f;
  737.  
  738. /* compute logical beginning (c, h, s) */
  739.     long2chs(p->start_sect, &lbc, &lbh, &lbs);
  740.  
  741. /* compute logical ending (c, h, s) */
  742.     long2chs(p->start_sect + p->nr_sects - 1, &lec, &leh, &les);
  743.  
  744. /* Same physical / logical beginning? */
  745.     if (pbc != lbc || pbh != lbh || pbs != lbs) {
  746.         printf("Partition %d has different physical/logical "
  747.             "beginnings (non-Linux?):\n", partition + 1);
  748.         printf("     phys=(%d, %d, %d) ", pbc, pbh, pbs);
  749.         printf("logical=(%d, %d, %d)\n",lbc, lbh, lbs);
  750.     }
  751.  
  752. /* Same physical / logical ending? */
  753.     if (pec != lec || peh != leh || pes != les) {
  754.         printf("Partition %d has different physical/logical "
  755.             "endings:\n", partition + 1);
  756.         printf("     phys=(%d, %d, %d) ", pec, peh, pes);
  757.         printf("logical=(%d, %d, %d)\n",lec, leh, les);
  758.     }
  759.  
  760. /* Beginning on cylinder boundary? */
  761.     if (pbh != !pbc || pbs != 1) {
  762.         printf("Partition %i does not start on cylinder "
  763.             "boundary:\n", partition + 1);
  764.         printf("     phys=(%d, %d, %d) ", pbc, pbh, pbs);
  765.         printf("should be (%d, %d, 1)\n", pbc, !pbc);
  766.     }
  767.  
  768. /* Ending on cylinder boundary? */
  769.     if (peh != (heads - 1) || pes != sectors) {
  770.         printf("Partition %i does not end on cylinder boundary:\n",
  771.             partition + 1);
  772.         printf("     phys=(%d, %d, %d) ", pec, peh, pes);
  773.         printf("should be (%d, %d, %d)\n",
  774.         pec, heads - 1, sectors);
  775.     }
  776. }
  777.  
  778. void list_table(void)
  779. {
  780.     struct partition *p;
  781.     char *type;
  782.     int i, w = strlen(disk_device);
  783.  
  784.     printf("\nDisk %s: %d heads, %d sectors, %d cylinders\nUnits = "
  785.         "%ss of %d * 512 bytes\n\n", disk_device, heads, sectors,
  786.         cylinders, str_units(), display_factor);
  787.     if (w < 5)
  788.         w = 5;
  789.     printf("%*s Boot  Begin   Start     End  Blocks   Id  System\n",
  790.         w + 1, "Device");
  791.     for (i = 0 ; i < partitions; i++)
  792.         if ((p = part_table[i])->sys_ind) {
  793.             printf("%*s%-2d  %c%8d%8d%8d%8d%c  %2x  %s\n", w,
  794.             disk_device, i + 1,
  795.             !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
  796.             ? '*' : '?',
  797.             cround(rounded( calculate(p->head, p->sector, p->cyl),
  798.                 p->start_sect + offsets[i])),
  799.             cround(p->start_sect + offsets[i]),
  800.             cround(p->start_sect + offsets[i] + p->nr_sects
  801.                 - (p->nr_sects ? 1: 0)),
  802.             p->nr_sects / 2, p->nr_sects & 1 ? '+' : ' ',
  803.             p->sys_ind,
  804.             (type = partition_type(p->sys_ind)) ?
  805.             type : "Unknown");
  806.             check_consistency(p, i);
  807.         }
  808.  
  809. }
  810.  
  811. void x_list_table(int extend)
  812. {
  813.     struct partition *p, **q;
  814.     int i;
  815.  
  816.     if (extend)
  817.         q = ext_pointers;
  818.     else
  819.         q = part_table;
  820.     printf("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n",
  821.         disk_device, heads, sectors, cylinders);
  822.         printf("Nr AF  Hd Sec  Cyl  Hd Sec  Cyl   Start    Size ID\n");
  823.     for (i = 0 ; i < partitions; i++)
  824.         if (p = q[i]) {
  825.                         printf("%2d %02x%4d%4d%5d%4d%4d%5d%8d%8d %02x\n",
  826.                 i + 1, p->boot_ind, p->head,
  827.                 sector(p->sector),
  828.                 cylinder(p->sector, p->cyl), p->end_head,
  829.                 sector(p->end_sector),
  830.                 cylinder(p->end_sector, p->end_cyl),
  831.                 p->start_sect, p->nr_sects, p->sys_ind);
  832.             if (p->sys_ind)
  833.                 check_consistency(p, i);
  834.         }
  835. }
  836.  
  837. void check_bounds(uint *first, uint *last)
  838. {
  839.     int i;
  840.     uint max = 256 * 63 * 1024;
  841.     struct partition *p = part_table[0];
  842.  
  843.     for (i = 0; i < partitions; p = part_table[++i])
  844.         if (!p->sys_ind || p->sys_ind == EXTENDED) {
  845.             first[i] = max;
  846.             last[i] = 0;
  847.         }
  848.         else {
  849.             first[i] = rounded(calculate(p->head, p->sector,
  850.                 p->cyl), p->start_sect + offsets[i]);
  851.             last[i] = p->start_sect + offsets[i] + p->nr_sects - 1;
  852.         }
  853. }
  854.  
  855. void check(int n, uint h, uint s, uint c, uint start)
  856. {
  857.     uint total, real_s, real_c, i;
  858.  
  859.     real_s = sector(s) - 1;
  860.     real_c = cylinder(s, c);
  861.     total = (real_c * sectors + real_s) * heads + h;
  862.     if (full_bits)
  863.         while ((i = total + full_bits) <= start) {
  864.             real_c += 1024;
  865.             total = i;
  866.         }
  867.     if (!total)
  868.         fprintf(stderr, "Warning: partition %d contains sector 0\n", n);
  869.     if (h >= heads)
  870.         fprintf(stderr,
  871.             "Partition %d: head %d greater than maximum %d\n",
  872.             n, h + 1, heads);
  873.     if (real_s >= sectors)
  874.         fprintf(stderr, "Partition %d: sector %d greater than "
  875.             "maximum %d\n", n, s, sectors);
  876.     if (real_c >= cylinders)
  877.         fprintf(stderr, "Partitions %d: cylinder %d greater than "
  878.             "maximum %d\n", n, real_c + 1, cylinders);
  879.     if (start != total)
  880.         fprintf(stderr,
  881.             "Partition %d: previous sectors %d disagrees with "
  882.             "total %d\n", n, start, total);
  883. }
  884.  
  885.  
  886. void verify(void)
  887. {
  888.     int i, j;
  889.     uint total = 1,
  890.         first[partitions], last[partitions];
  891.     struct partition *p = part_table[0];
  892.  
  893.     if (warn_geometry())
  894.         return;
  895.  
  896.     check_bounds(first, last);
  897.     for (i = 0; i < partitions; p = part_table[++i])
  898.         if (p->sys_ind && (p->sys_ind != EXTENDED)) {
  899.             check_consistency(p, i);
  900.             if (p->start_sect + offsets[i] < first[i])
  901.                 printf("Warning: bad start-of-data in "
  902.                     "partition %d\n", i + 1);
  903.             check(i + 1, p->end_head, p->end_sector, p->end_cyl,
  904.                 last[i]);
  905.             total += last[i] + 1 - first[i];
  906.             for (j = 0; j < i; j++)
  907.             if (first[i] >= first[j] && first[i] <= last[j]
  908.                     || (last[i] <= last[j] &&
  909.                     last[i] >= first[j])) {
  910.                 printf("Warning: partition %d overlaps "
  911.                     "partition %d.\n", j + 1, i + 1);
  912.                 total += first[i] >= first[j] ?
  913.                     first[i] : first[j];
  914.                 total -= last[i] <= last[j] ?
  915.                     last[i] : last[j];
  916.             }
  917.         }
  918.  
  919.     if (extended_offset) {
  920.         uint e_last = part_table[ext_index]->start_sect +
  921.             part_table[ext_index]->nr_sects - 1;
  922.  
  923.         for (p = part_table[i = 4]; i < partitions;
  924.                 p = part_table[++i]) {
  925.             total++;
  926.             if (!p->sys_ind) {
  927.                 if (i != 4 || i + 1 < partitions)
  928.                     printf("Warning: partition %d "
  929.                         "is empty\n", i + 1);
  930.             }
  931.             else if (first[i] < extended_offset ||
  932.                     last[i] > e_last)
  933.                 printf("Logical partition %d not entirely in "
  934.                     "partition %d\n", i + 1, ext_index + 1);
  935.         }
  936.     }
  937.  
  938.     if (total > heads * sectors * cylinders)
  939.         printf("Total allocated sectors %d greater than the maximum "
  940.             "%d\n", total, heads * sectors * cylinders);
  941.     else if (total = heads * sectors * cylinders - total)
  942.         printf("%d unallocated sectors\n", total);
  943. }
  944.  
  945. void add_partition(int n, int sys)
  946. {
  947.     char mesg[48];
  948.     int i, read = 0;
  949.     struct partition *p = part_table[n], *q = part_table[ext_index];
  950.     uint start, stop = 0, limit, temp,
  951.         first[partitions], last[partitions];
  952.  
  953.     if (p->sys_ind) {
  954.         printf("Partition %d is already defined.  Delete "
  955.             "it before re-adding it.\n", n + 1);
  956.         return;
  957.     }
  958.     check_bounds(first, last);
  959.     if (n < 4) {
  960.         start = sector_offset;
  961.         limit = heads * sectors * cylinders - 1;
  962.         if (extended_offset) {
  963.             first[ext_index] = extended_offset;
  964.             last[ext_index] = q->start_sect + q->nr_sects - 1;
  965.         }
  966.     }
  967.     else {
  968.         start = extended_offset + sector_offset;
  969.         limit = q->start_sect + q->nr_sects - 1;
  970.     }
  971.     if (unit_flag)
  972.         for (i = 0; i < partitions; i++)
  973.             first[i] = (cround(first[i]) - 1) * display_factor;
  974.  
  975.     sprintf(mesg, "First %s", str_units());
  976.     do {
  977.         temp = start;
  978.         for (i = 0; i < partitions; i++) {
  979.             if (start == offsets[i])
  980.                 start += sector_offset;
  981.             if (start >= first[i] && start <= last[i])
  982.                 if (n < 4)
  983.                     start = last[i] + 1;
  984.                 else
  985.                     start = last[i] + sector_offset;
  986.         }
  987.         if (start > limit)
  988.             break;
  989.         if (start != temp && read) {
  990.             printf("Sector %d is already allocated\n", temp);
  991.             temp = start = stop;
  992.             read = 0;
  993.         }
  994.         if (!read && start == temp) {
  995.             uint i;
  996.             temp = 0;
  997.             start = read_int(cround(i = (stop = start) + (n > 4)),
  998.                 cround(limit), mesg);
  999.             if (unit_flag) {
  1000.                 start = (start - 1) * display_factor;
  1001.                 if (start < i) start = i;
  1002.                 }
  1003.             read = 1;
  1004.         }
  1005.     } while (start != temp || !read);
  1006.     if (n > 4)            /* NOT for fifth partition */
  1007.         offsets[n] = start - sector_offset;
  1008.  
  1009.     for (i = 0; i < partitions; i++) {
  1010.         if (start < offsets[i] && limit >= offsets[i])
  1011.             limit = offsets[i] - 1;
  1012.         if (start < first[i] && limit >= first[i])
  1013.             limit = first[i] - 1;
  1014.     }
  1015.     if (start > limit) {
  1016.         printf("No free sectors available\n");
  1017.         if (n > 4) {
  1018.             free(buffers[n]);
  1019.             partitions--;
  1020.         }
  1021.         return;
  1022.     }
  1023.     if (cround(start) == cround(limit))
  1024.         stop = start;
  1025.     else {
  1026.         sprintf(mesg, "Last %s or +size or +sizeM or +sizeK",
  1027.             str_units());
  1028.         size_flag = 1;
  1029.         stop = read_int(cround(start), cround(limit), mesg);
  1030.         if (unit_flag) {
  1031.             stop = stop * display_factor - 1;
  1032.             if (stop >limit)
  1033.                 stop = limit;
  1034.         }
  1035.     }
  1036.  
  1037.     set_partition(n, p, start, stop, sys, offsets[n]);
  1038.  
  1039.     if (sys == EXTENDED) {
  1040.         ext_index = n;
  1041.         offsets[4] = extended_offset = start;
  1042.         ext_pointers[n] = p;
  1043.         if (!(buffers[4] = calloc(1, SECTOR_SIZE)))
  1044.             fatal(out_of_memory);
  1045.         part_table[4] = offset(buffers[4], 0);
  1046.         ext_pointers[4] = part_table[4] + 1;
  1047.         changed[4] = 1;
  1048.         partitions = 5;
  1049.     }
  1050.     else {
  1051.         if (n > 4)
  1052.             set_partition(n - 1, ext_pointers[n - 1],
  1053.                 start - sector_offset, stop, EXTENDED,
  1054.                 extended_offset);
  1055. #if 0
  1056.         if ((limit = p->nr_sects) & 1)
  1057.             printf("Warning: partition %d has an odd "
  1058.                 "number of sectors.\n", n + 1);
  1059. #endif
  1060.     }
  1061. }
  1062.  
  1063. void add_logical(void)
  1064. {
  1065.     if (partitions > 5 || part_table[4]->sys_ind) {
  1066.         if (!(buffers[partitions] = calloc(1, SECTOR_SIZE)))
  1067.             fatal(out_of_memory);
  1068.         part_table[partitions] = offset(buffers[partitions], 0);
  1069.         ext_pointers[partitions] = part_table[partitions] + 1;
  1070.         offsets[partitions] = 0;
  1071.         partitions++;
  1072.     }
  1073.     add_partition(partitions - 1, LINUX_NATIVE);
  1074. }
  1075.  
  1076. void new_partition(void)
  1077. {
  1078.     int i, free_primary = 0;
  1079.  
  1080.     if (warn_geometry())
  1081.         return;
  1082.     if (partitions >= MAXIMUM_PARTS) {
  1083.         printf("The maximum number of partitions has been created\n");
  1084.         return;
  1085.     }
  1086.  
  1087.     for (i = 0; i < 4; i++)
  1088.         free_primary += !part_table[i]->sys_ind;
  1089.     if (!free_primary)
  1090.         if (extended_offset)
  1091.             add_logical();
  1092.         else
  1093.             printf("You must delete some partition and add "
  1094.                 "an extended partition first\n");
  1095.     else {
  1096.         char c, line[LINE_LENGTH];
  1097.         sprintf(line, "Command action\n   %s\n   p   primary "
  1098.             "partition (1-4)\n", extended_offset ?
  1099.             "l   logical (5 or over)" : "e   extended");
  1100.         while (1)
  1101.             if ((c = tolower(read_char(line))) == 'p') {
  1102.                 add_partition(get_partition(0, 4),
  1103.                     LINUX_NATIVE);
  1104.                 return;
  1105.             }
  1106.             else if (c == 'l' && extended_offset) {
  1107.                 add_logical();
  1108.                 return;
  1109.             }
  1110.             else if (c == 'e' && !extended_offset) {
  1111.                 add_partition(get_partition(0, 4),
  1112.                     EXTENDED);
  1113.                 return;
  1114.             }
  1115.     }
  1116. }
  1117.  
  1118. void write_table(void)
  1119. {
  1120.     int i, error = 0;
  1121.  
  1122.     changed[3] = changed[0] || changed[1] || changed[2] || changed[3];
  1123.     for (i = 3; i < partitions; i++)
  1124.         if (changed[i]) {
  1125.             *table_check(buffers[i]) = PART_TABLE_FLAG;
  1126.             if (ext2_llseek(fd, offsets[i]
  1127.                        * SECTOR_SIZE, SEEK_SET) < 0)
  1128.                 fatal(unable_to_seek);
  1129.             if (write(fd, buffers[i], SECTOR_SIZE) != SECTOR_SIZE)
  1130.                 fatal(unable_to_write);
  1131.     }
  1132.  
  1133.     printf("The partition table has been altered!\n\n");
  1134.  
  1135.     printf("Calling ioctl() to re-read partition table.\n"
  1136.            "(Reboot to ensure the partition table has been updated.)\n");
  1137.     sync();
  1138.     sleep(2);
  1139.     if (i = ioctl(fd, BLKRRPART))
  1140.         error = errno;
  1141.     close(fd);
  1142.  
  1143.     printf("Syncing disks.\n");
  1144.     sync();
  1145.     sleep(4);        /* for sync() */
  1146.  
  1147.     if (i)
  1148.         printf("Re-read table failed with error %d: %s.\nReboot your "
  1149.             "system to ensure the partition table is updated.\n",
  1150.             error, strerror(error));
  1151.  
  1152.     printf( "\nWARNING: If you have created or modified any DOS 6.x\n"
  1153.         "partitions, please see the fdisk manual page for additional\n"
  1154.         "information.\n" );
  1155.  
  1156.     exit(0);
  1157. }
  1158.  
  1159. #define MAX_PER_LINE    16
  1160. void print_buffer(char buffer[])
  1161. {
  1162.     int    i,
  1163.         l;
  1164.  
  1165.     for (i = 0, l = 0; i < SECTOR_SIZE; i++, l++) {
  1166.         if (l == 0)
  1167.             printf("0x%03X:", i);
  1168.         printf(" %02X", (unsigned char) buffer[i]);
  1169.         if (l == MAX_PER_LINE - 1) {
  1170.             printf("\n");
  1171.             l = -1;
  1172.         }
  1173.     }
  1174.     if (l > 0)
  1175.         printf("\n");
  1176.     printf("\n");
  1177. }
  1178.  
  1179. void print_raw(void)
  1180. {
  1181.     int i;
  1182.  
  1183.     printf("Device: %s\n", disk_device);
  1184.     for (i = 3; i < partitions; i++)
  1185.         print_buffer(buffers[i]);
  1186. }
  1187.  
  1188. void move_begin(int i)
  1189. {
  1190.     struct partition *p = part_table[i];
  1191.     uint new, first;
  1192.  
  1193.     if (warn_geometry())
  1194.         return;
  1195.     if (!p->sys_ind || !p->nr_sects || p->sys_ind == EXTENDED) {
  1196.         printf("Partition %d has no data area\n", i + 1);
  1197.         return;
  1198.     }
  1199.     first = rounded(calculate(p->head, p->sector, p->cyl), p->start_sect +
  1200.         offsets[i]);
  1201.     new = read_int(first, p->start_sect + p->nr_sects + offsets[i] - 1,
  1202.         "New beginning of data") - offsets[i];
  1203.  
  1204.     if (new != p->nr_sects) {
  1205.         first = p->nr_sects + p->start_sect - new;
  1206.         p->nr_sects = first;
  1207.         p->start_sect = new;
  1208.         changed[i] = 1;
  1209.     }
  1210. }
  1211.  
  1212. void xselect(void)
  1213. {
  1214.     while(1) {
  1215.         putchar('\n');
  1216.         switch (tolower(read_char("Expert command (m for help): "))) {
  1217.             case 'b': move_begin(get_partition(0, partitions));
  1218.                 break;
  1219.             case 'c': cylinders = read_int(1, 65535,
  1220.                     "Number of cylinders");
  1221.                 warn_cylinders();
  1222.                 break;
  1223.             case 'd': print_raw();
  1224.                 break;
  1225.             case 'e': x_list_table(1);
  1226.                 break;
  1227.             case 'h': heads = read_int(1, 256, "Number of heads");
  1228.                 update_units();
  1229.                 break;
  1230.             case 'p': x_list_table(0);
  1231.                 break;
  1232.             case 'q': close(fd);
  1233.                 exit(0);
  1234.             case 'r': return;
  1235.             case 's': sectors = read_int(1, 63,
  1236.                     "Number of sectors");
  1237.                 if (dos_compatible_flag) {
  1238.                     sector_offset = sectors;
  1239.                     if ( listing != 1 ) {
  1240.                         fprintf(stderr, "Warning: setting "
  1241.                         "sector offset for DOS "
  1242.                         "compatiblity\n");
  1243.                     }
  1244.                 }
  1245.                 update_units();
  1246.                 break;
  1247.             case 'w': write_table();
  1248.             default: xmenu();
  1249.         }
  1250.     }
  1251. }
  1252.  
  1253. void try(char *device)
  1254. {
  1255.     disk_device = device;
  1256.     if (!setjmp(listingbuf))
  1257.         if ((fd = open(disk_device, O_RDWR)) >= 0) {
  1258.             close(fd);
  1259.             get_boot();
  1260.             list_table();
  1261.             if (partitions > 4)
  1262.                 delete_partition(ext_index);
  1263.         }
  1264. }
  1265.  
  1266. void main(int argc, char **argv)
  1267. {
  1268.     if (argc > 3)
  1269.         fatal(usage);
  1270.     if (argc > 1 && *argv[1] == '-') {
  1271.         switch (*(argv[1] + 1)) {
  1272.             case 'v':
  1273.                 printf("fdisk v" VERSION "\n");
  1274.                 exit(0);
  1275.             case 'l':
  1276.                 listing = 1;
  1277.                 try("/dev/hda");
  1278.                 try("/dev/hdb");
  1279.                 try("/dev/hdc");
  1280.                 try("/dev/hdd");
  1281.                 try("/dev/sda");
  1282.                 try("/dev/sdb");
  1283.                 try("/dev/sdc");
  1284.                 try("/dev/sdd");
  1285.                 try("/dev/sde");
  1286.                 try("/dev/sdf");
  1287.                 try("/dev/sdg");
  1288.                 try("/dev/sdh");
  1289.                 exit(0);
  1290.             case 's': {
  1291.                 int i;
  1292.                 if (argc < 3)
  1293.                     fatal(usage);
  1294.                 if (!(i = atoi(argv[2] + 8)))
  1295.                     fatal(usage);
  1296.                 disk_device = (char *) malloc(9);
  1297.                 strncpy(disk_device, argv[2], 8);
  1298.                 if ((fd = open(disk_device, O_RDWR)) >= 0) {
  1299.                     close(fd);
  1300.                     get_boot();
  1301.                 if (i > partitions) exit(1);
  1302.                 if (part_table[--i]->sys_ind > 10)
  1303.                     printf("%d\n",
  1304.                         part_table[i]->nr_sects / 2);
  1305.                 else exit(1);
  1306.                 exit(0);
  1307.             }
  1308.     }
  1309.             default:
  1310.                 fatal(usage);
  1311.         }
  1312.     }
  1313.     if (argc > 1)
  1314.         disk_device = argv[argc - 1];
  1315.     else if ((fd = open(DEFAULT_DEVICE, O_RDWR)) < 0)
  1316.         disk_device = ALTERNATE_DEVICE;
  1317.     else close(fd);
  1318.  
  1319.     get_boot();
  1320.     if (argc == 1)
  1321.         printf("Using %s as default device!\n", disk_device);
  1322.  
  1323.     while (1) {
  1324.         putchar('\n');
  1325.         switch (tolower(read_char("Command (m for help): "))) {
  1326.             case 'a': toggle_active(get_partition(1, partitions));
  1327.                 break;
  1328.             case 'c':
  1329.                 toggle_dos();
  1330.                 break;
  1331.             case 'd': delete_partition(
  1332.                     get_partition(1, partitions));
  1333.                 break;
  1334.             case 'l': list_types();
  1335.                 break;
  1336.             case 'n': new_partition();
  1337.                 break;
  1338.             case 'p': list_table();
  1339.                 break;
  1340.             case 'q': close(fd);
  1341.                 exit(0);
  1342.             case 't': change_sysid();
  1343.                 break;
  1344.             case 'u': change_units();
  1345.                 break;
  1346.             case 'v': verify();
  1347.                 break;
  1348.             case 'w': write_table();
  1349.             case 'x': xselect();
  1350.                 break;
  1351.             default: menu();
  1352.         }
  1353.     }
  1354. }
  1355.