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