home *** CD-ROM | disk | FTP | other *** search
/ Chip 1995 March / CHIP3.mdf / slackwar / a / util / util-lin.2 / util-lin / util-linux-2.2 / disk-utils / cfdisk.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-22  |  60.7 KB  |  2,331 lines

  1. /****************************************************************************
  2.  *
  3.  *     CFDISK
  4.  *
  5.  * cfdisk is a curses based disk drive partitioning program that can
  6.  * create partitions for a wide variety of operating systems including
  7.  * Linux, MS-DOS and OS/2.
  8.  *
  9.  * cfdisk was inspired by the fdisk program, by A. V. Le Blanc
  10.  * (LeBlanc@mcc.ac.uk).
  11.  *
  12.  *     Copyright (C) 1994 Kevin E. Martin (martin@cs.unc.edu)
  13.  *
  14.  * cfdisk is free software; you can redistribute it and/or modify it
  15.  * under the terms of the GNU General Public License as published by
  16.  * the Free Software Foundation; either version 2 of the License, or
  17.  * (at your option) any later version.
  18.  *
  19.  * cfdisk is distributed in the hope that it will be useful, but
  20.  * WITHOUT ANY WARRANTY; without even the implied warranty of
  21.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  22.  * General Public License for more details.
  23.  *
  24.  * You should have received a copy of the GNU General Public License
  25.  * along with cfdisk; if not, write to the Free Software Foundation,
  26.  * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  27.  *
  28.  * Created:    Fri Jan 28 22:46:58 1994, martin@cs.unc.edu
  29.  * >2GB patches: Sat Feb 11 09:08:10 1995, faith@cs.unc.edu
  30.  * Prettier menus: Sat Feb 11 09:08:25 1995, Janne Kukonlehto
  31.  *                                           <jtklehto@stekt.oulu.fi>
  32.  *
  33.  ****************************************************************************/
  34.  
  35. #include <stdlib.h>
  36. #include <stdio.h>
  37. #include <stdarg.h>
  38. #include <unistd.h>
  39. #include <ctype.h>
  40. #include <errno.h>
  41. #include <getopt.h>
  42. #include <fcntl.h>
  43. #include <curses.h>
  44. #include <signal.h>
  45. #include <math.h>
  46. #include <sys/ioctl.h>
  47. #include <linux/genhd.h>
  48. #include <linux/hdreg.h>
  49. #include <linux/fs.h>        /* for BLKRRPART */
  50.  
  51. #if defined(__GNUC__) || defined(HAS_LONG_LONG)
  52. typedef long long ext2_loff_t;
  53. #else
  54. typedef long      ext2_loff_t;
  55. #endif
  56.  
  57. extern ext2_loff_t ext2_llseek(unsigned int fd,
  58.                    ext2_loff_t offset,
  59.                    unsigned int origin);
  60.  
  61.  
  62. #define VERSION "0.8a BETA (>2GB)"
  63.  
  64. #define DEFAULT_DEVICE "/dev/hda"
  65. #define ALTERNATE_DEVICE "/dev/sda"
  66.  
  67. #define LINE_LENGTH 80
  68. #define MAXIMUM_PARTS 60
  69.  
  70. #define SECTOR_SIZE 512
  71.  
  72. #define MAX_CYLINDERS 65535
  73. #define MAX_HEADS 255
  74. #define MAX_SECTORS 63
  75.  
  76. #define ACTIVE_FLAG 0x80
  77. #define PART_TABLE_FLAG 0xAA55
  78.  
  79. #define UNUSABLE -1
  80. #define FREE_SPACE 0x00
  81. #define EXTENDED 0x05
  82. #define LINUX_MINIX 0x81
  83. #define LINUX_SWAP 0x82
  84. #define LINUX 0x83
  85.  
  86. #define ADD_EXISTS "This partition is already in use"
  87. #define ADD_UNUSABLE "This partition is unusable"
  88. #define DEL_EMPTY "Cannot delete an empty partition"
  89. #define ID_EMPTY "Cannot change FS Type to empty"
  90. #define ID_EXT "Cannot change FS Type to extended"
  91. #define NEED_EXT "No room to create the extended partition"
  92. #define NO_FLAGS "Cannot make this partition bootable"
  93. #define NO_MORE_PARTS "No more partitions"
  94. #define PRINT_OPEN_ERR "Cannot open file '%s'"
  95. #define TWO_EXTENDEDS "Cannot create logical drive here -- would create two extended partitions"
  96. #define TYPE_EMPTY "Cannot change the type of an empty partition"
  97. #define BAD_COMMAND "Illegal command"
  98. #define MAX_UNMAXABLE "Cannot maximize this partition"
  99. #define BAD_OPEN "Cannot open disk drive"
  100. #define BAD_SEEK "Cannot seek on disk drive"
  101. #define BAD_READ "Cannot read disk drive"
  102. #define BAD_WRITE "Cannot write disk drive"
  103. #define BAD_GEOMETRY "Cannot read disk drive geometry"
  104. #define BAD_PRIMARY "Bad primary partition"
  105. #define BAD_LOGICAL "Bad logical partition"
  106. #define BAD_CYLINDERS "Illegal cylinders value"
  107. #define BAD_HEADS "Illegal heads value"
  108. #define BAD_SECTORS "Illegal sectors value"
  109. #define WRITE_WARN "Warning!!  This may destroy data on your disk!"
  110. #define YES_NO "Please enter `yes' or `no'"
  111. #define WRITING_PART "Writing partition table to disk..."
  112. #define YES_WRITE "Wrote partition table to disk"
  113. #define NO_WRITE "Did not write partition table to disk"
  114. #define RRPART_FAILED "Wrote partition table, but re-read table failed.  Reboot to update table."
  115.  
  116. #define PRI_OR_LOG -1
  117. #define PRIMARY -2
  118. #define LOGICAL -3
  119.  
  120. #define COL_ID_WIDTH 20
  121.  
  122. #define CR '\015'
  123. #define ESC '\033'
  124. #define DEL '\177'
  125. #define BELL '\007'
  126. /* '\014' == ^L */
  127. #define REDRAWKEY '\014'
  128.  
  129. /* Display units */
  130. #define MEGABYTES 1
  131. #define SECTORS 2
  132. #define CYLINDERS 3
  133.  
  134. #define GS_DEFAULT -1
  135. #define GS_ESCAPE -2
  136.  
  137. #define PRINT_RAW_TABLE 1
  138. #define PRINT_SECTOR_TABLE 2
  139. #define PRINT_PARTITION_TABLE 4
  140.  
  141. #define IS_PRIMARY(p) ((p) >= 0 && (p) < 4)
  142. #define IS_LOGICAL(p) ((p) > 3)
  143.  
  144. #define round_int(d) ((double)((int)(d+0.5)))
  145. #define ceiling(d) ((double)(((d) != (int)(d)) ? (int)(d+1.0) : (int)(d)))
  146.  
  147. #define set_hsc(h,s,c,sector) \
  148. { \
  149.       s = sector % sectors + 1;    \
  150.       sector /= sectors;    \
  151.       h = sector % heads;    \
  152.       sector /= heads;        \
  153.       c = sector & 0xFF;    \
  154.       s |= (sector >> 2) & 0xC0;\
  155. }
  156.  
  157. #define ALIGNMENT 2
  158. typedef union {
  159.     struct {
  160.     unsigned char align[ALIGNMENT];
  161.     unsigned char b[SECTOR_SIZE];
  162.     } c;
  163.     struct {
  164.     unsigned char align[ALIGNMENT];
  165.     unsigned char buffer[0x1BE];
  166.     struct partition part[4];
  167.     unsigned short flag;
  168.     } p;
  169. } partition_table;
  170.  
  171. typedef struct {
  172.     int first_sector;    /* first sector in partition */
  173.     int last_sector;    /* last sector in partition */
  174.     int offset;        /* offset from first sector to start of data */
  175.     int flags;        /* active == 0x80 */
  176.     int id;        /* filesystem type */
  177.     int num;        /* number of partition -- primary vs. logical */
  178. } partition_info;
  179.  
  180. char *disk_device = DEFAULT_DEVICE;
  181. int fd;
  182. int heads = 0;
  183. int sectors = 0;
  184. int cylinders = 0;
  185. int changed = FALSE;
  186. int opened = FALSE;
  187.  
  188. partition_info p_info[MAXIMUM_PARTS];
  189. partition_info ext_info;
  190. int num_parts = 0;
  191.  
  192. int logical = 0;
  193. int logical_sectors[MAXIMUM_PARTS];
  194.  
  195. __sighandler_t old_SIGINT, old_SIGTERM;
  196.  
  197. int arrow_cursor = FALSE;
  198. int display_units = MEGABYTES;
  199. int zero_table = FALSE;
  200. int print_only = 0;
  201.  
  202. /* Curses screen information */
  203. int cur_part = 0;
  204. int warning_last_time = FALSE;
  205. int defined = FALSE;
  206. int COLUMNS = 80;
  207. int NUM_ON_SCREEN = 1;
  208.  
  209. /* Y coordinates */
  210. int HEADER_START = 0;
  211. int DISK_TABLE_START = 5;
  212. int WARNING_START = 23;
  213. int COMMAND_LINE_Y = 21;
  214.  
  215. /* X coordinates */
  216. int NAME_START = 4;
  217. int FLAGS_START = 16;
  218. int PTYPE_START = 30;
  219. int FSTYPE_START = 45;
  220. int SIZE_START = 70;
  221. int COMMAND_LINE_X = 5;
  222.  
  223. #define NUM_PART_TYPES 256
  224. char *partition_type[NUM_PART_TYPES] = {
  225.     [LINUX_MINIX] = "Linux/MINIX",
  226.     [LINUX_SWAP]  = "Linux Swap",
  227.     [LINUX]       = "Linux",
  228.     [FREE_SPACE]  = "Free Space",
  229.     [EXTENDED]    = "Extended",
  230.     [0x01]        = "DOS 12-bit FAT",
  231.     [0x04]        = "DOS 16-bit < 32Mb",
  232.     [0x06]        = "DOS 16-bit >=32Mb",
  233.     [0x07]        = "OS/2 HPFS",
  234.     [0x0A]        = "OS/2 Boot Manager",
  235.     [0xA5]        = "BSD/386",
  236.  
  237. /* The rest of these are taken from A. V. Le Blanc's (LeBlanc@mcc.ac.uk)
  238.  * fdisk program.  I do not know where they came from, but I include
  239.  * them for completeness.
  240.  */
  241.  
  242.     [0x02]        = "XENIX root",
  243.     [0x03]        = "XENIX usr",
  244.     [0x08]        = "AIX",
  245.     [0x09]        = "AIX bootable",
  246.     [0x40]        = "Venix 80286",
  247.     [0x51]        = "Novell?",
  248.     [0x52]        = "Microport",
  249.     [0x63]        = "GNU HURD",
  250.     [0x64]        = "Novell",
  251.     [0x75]        = "PC/IX",
  252.     [0x80]        = "Old MINIX",
  253.     [0x93]        = "Amoeba",
  254.     [0x94]        = "Amoeba BBT",
  255.     [0xB7]        = "BSDI fs",
  256.     [0xB8]        = "BSDI swap",
  257.     [0xC7]        = "Syrinx",
  258.     [0xDB]        = "CP/M",
  259.     [0xE1]        = "DOS access",
  260.     [0xE3]        = "DOS R/O",
  261.     [0xF2]        = "DOS secondary",
  262.     [0xFF]        = "BBT"
  263. };
  264.  
  265. void fdexit(int ret)
  266. {
  267.     if (opened)
  268.     close(fd);
  269.  
  270.     if (changed) {
  271.     fprintf(stderr, "Disk has been changed.\n");
  272.     fprintf(stderr, "Reboot the system to ensure the partition "
  273.             "table is correctly updated.\n");
  274.     
  275.     fprintf( stderr, "\nWARNING: If you have created or modified any\n"
  276.                  "DOS 6.x partitions, please see the cfdisk manual\n"
  277.                  "page for additional information.\n" );
  278.     }
  279.  
  280.  
  281.     exit(ret);
  282. }
  283.  
  284. int get_string(char *str, int len, char *def)
  285. {
  286.     char c;
  287.     int i = 0;
  288.     int x, y;
  289.     int use_def = FALSE;
  290.  
  291.     getyx(stdscr, y, x);
  292.     clrtoeol();
  293.  
  294.     str[i] = 0;
  295.  
  296.     if (def != NULL) {
  297.     mvaddstr(y, x, def);
  298.     move(y, x);
  299.     use_def = TRUE;
  300.     }
  301.  
  302.     refresh();
  303.     while ((c = getch()) != '\n' && c != CR) {
  304.     switch (c) {
  305.     case ESC:
  306.         move(y, x);
  307.         clrtoeol();
  308.         refresh();
  309.         return GS_ESCAPE;
  310.     case DEL:
  311.     case '\b':
  312.         if (i > 0) {
  313.         str[--i] = 0;
  314.         mvaddch(y, x+i, ' ');
  315.         move(y, x+i);
  316.         } else if (use_def) {
  317.         clrtoeol();
  318.         use_def = FALSE;
  319.         } else
  320.         putchar(BELL);
  321.         break;
  322.     default:
  323.         if (i < len && isprint(c)) {
  324.         mvaddch(y, x+i, c);
  325.         if (use_def) {
  326.             clrtoeol();
  327.             use_def = FALSE;
  328.         }
  329.         str[i++] = c;
  330.         str[i] = 0;
  331.         } else
  332.         putchar(BELL);
  333.     }
  334.     refresh();
  335.     }
  336.  
  337.     if (use_def)
  338.     return GS_DEFAULT;
  339.     else
  340.     return i;
  341. }
  342.  
  343. void clear_warning(void)
  344. {
  345.     int i;
  346.  
  347.     if (!warning_last_time)
  348.     return;
  349.  
  350.     move(WARNING_START,0);
  351.     for (i = 0; i < COLS; i++)
  352.     addch(' ');
  353.  
  354.     warning_last_time = FALSE;
  355. }
  356.  
  357. void print_warning(char *s)
  358. {
  359.     mvaddstr(WARNING_START, (COLS-strlen(s))/2, s);
  360.     putchar(BELL); /* CTRL-G */
  361.  
  362.     warning_last_time = TRUE;
  363. }
  364.  
  365. void fatal(char *s)
  366. {
  367.     char str[LINE_LENGTH];
  368.  
  369.     sprintf(str, "FATAL ERROR: %s", s);
  370.     mvaddstr(WARNING_START, (COLS-strlen(str))/2, str);
  371.     sprintf(str, "Press any key to exit fdisk");
  372.     mvaddstr(WARNING_START+1, (COLS-strlen(str))/2, str);
  373.     putchar(BELL); /* CTRL-G */
  374.  
  375.     refresh();
  376.  
  377.     (void)getch();
  378.  
  379.     signal(SIGINT, old_SIGINT);
  380.     signal(SIGTERM, old_SIGTERM);
  381.     mvcur(0, COLS-1, LINES-1, 0);
  382.     nl();
  383.     endwin();
  384.     fdexit(1);
  385. }
  386.  
  387. void read_sector(char *buffer, int sect_num)
  388. {
  389.     if (ext2_llseek(fd, sect_num*SECTOR_SIZE, SEEK_SET) < 0)
  390.     fatal(BAD_SEEK);
  391.     if (read(fd, buffer, SECTOR_SIZE) != SECTOR_SIZE)
  392.     fatal(BAD_READ);
  393. }
  394.  
  395. void write_sector(char *buffer, int sect_num)
  396. {
  397.     if (ext2_llseek(fd, sect_num*SECTOR_SIZE, SEEK_SET) < 0)
  398.     fatal(BAD_SEEK);
  399.     if (write(fd, buffer, SECTOR_SIZE) != SECTOR_SIZE)
  400.     fatal(BAD_WRITE);
  401. }
  402.  
  403. void check_part_info(void)
  404. {
  405.     int i, pri = 0, log = 0;
  406.  
  407.     for (i = 0; i < num_parts; i++)
  408.     if (p_info[i].id > 0 && IS_PRIMARY(p_info[i].num))
  409.         pri++;
  410.     else if (p_info[i].id > 0 && IS_LOGICAL(p_info[i].num))
  411.         log++;
  412.     if (ext_info.id == EXTENDED)
  413.     if (log > 0)
  414.         pri++;
  415.     else {
  416.         ext_info.first_sector = 0;
  417.         ext_info.last_sector = 0;
  418.         ext_info.offset = 0;
  419.         ext_info.flags = 0;
  420.         ext_info.id = FREE_SPACE;
  421.         ext_info.num = PRIMARY;
  422.     }
  423.  
  424.     if (pri >= 4)
  425.     for (i = 0; i < num_parts; i++)
  426.         if (p_info[i].id == FREE_SPACE || p_info[i].id == UNUSABLE)
  427.         if (ext_info.id == EXTENDED)
  428.             if (p_info[i].first_sector >= ext_info.first_sector &&
  429.             p_info[i].last_sector <= ext_info.last_sector) {
  430.             p_info[i].id = FREE_SPACE;
  431.             p_info[i].num = LOGICAL;
  432.             } else if (i > 0 &&
  433.                    p_info[i-1].first_sector >=
  434.                    ext_info.first_sector &&
  435.                    p_info[i-1].last_sector <=
  436.                    ext_info.last_sector) {
  437.             p_info[i].id = FREE_SPACE;
  438.             p_info[i].num = LOGICAL;
  439.             } else if (i < num_parts-1 &&
  440.                    p_info[i+1].first_sector >=
  441.                    ext_info.first_sector &&
  442.                    p_info[i+1].last_sector <=
  443.                    ext_info.last_sector) {
  444.             p_info[i].id = FREE_SPACE;
  445.             p_info[i].num = LOGICAL;
  446.             } else
  447.             p_info[i].id = UNUSABLE;
  448.         else /* if (ext_info.id != EXTENDED) */
  449.             p_info[i].id = UNUSABLE;
  450.         else /* if (p_info[i].id > 0) */
  451.         while (0); /* Leave these alone */
  452.     else /* if (pri < 4) */
  453.     for (i = 0; i < num_parts; i++) {
  454.         if (p_info[i].id == UNUSABLE)
  455.         p_info[i].id = FREE_SPACE;
  456.         if (p_info[i].id == FREE_SPACE)
  457.         if (ext_info.id == EXTENDED)
  458.             if (p_info[i].first_sector >= ext_info.first_sector &&
  459.             p_info[i].last_sector <= ext_info.last_sector)
  460.             p_info[i].num = LOGICAL;
  461.             else if (i > 0 &&
  462.                  p_info[i-1].first_sector >=
  463.                  ext_info.first_sector &&
  464.                  p_info[i-1].last_sector <=
  465.                  ext_info.last_sector)
  466.             p_info[i].num = PRI_OR_LOG;
  467.             else if (i < num_parts-1 &&
  468.                  p_info[i+1].first_sector >=
  469.                  ext_info.first_sector &&
  470.                  p_info[i+1].last_sector <=
  471.                  ext_info.last_sector)
  472.             p_info[i].num = PRI_OR_LOG;
  473.             else
  474.             p_info[i].num = PRIMARY;
  475.         else /* if (ext_info.id != EXTENDED) */
  476.             p_info[i].num = PRI_OR_LOG;
  477.         else /* if (p_info[i].id > 0) */
  478.         while (0); /* Leave these alone */
  479.     }
  480. }
  481.  
  482. void remove_part(int i)
  483. {
  484.     int p;
  485.  
  486.     for (p = i; p < num_parts; p++)
  487.     p_info[p] = p_info[p+1];
  488.  
  489.     num_parts--;
  490. }
  491.  
  492. void insert_part(int i, int num, int id, int flags, int first, int last,
  493.          int offset)
  494. {
  495.     int p;
  496.  
  497.     for (p = num_parts; p > i; p--)
  498.      p_info[p] = p_info[p-1];
  499.  
  500.     p_info[i].first_sector = first;
  501.     p_info[i].last_sector = last;
  502.     p_info[i].offset = offset;
  503.     p_info[i].flags = flags;
  504.     p_info[i].id = id;
  505.     p_info[i].num = num;
  506.  
  507.     num_parts++;
  508. }
  509.  
  510. void del_part(int i)
  511. {
  512.     int num = p_info[i].num;
  513.  
  514.     if (i > 0 && (p_info[i-1].id == FREE_SPACE ||
  515.           p_info[i-1].id == UNUSABLE)) {
  516.     /* Merge with previous partition */
  517.     p_info[i-1].last_sector = p_info[i].last_sector;
  518.     remove_part(i--);
  519.     }
  520.  
  521.     if (i < num_parts - 1 && (p_info[i+1].id == FREE_SPACE ||
  522.                   p_info[i+1].id == UNUSABLE)) {
  523.     /* Merge with next partition */
  524.     p_info[i+1].first_sector = p_info[i].first_sector;
  525.     remove_part(i);
  526.     }
  527.  
  528.     if (i > 0)
  529.     p_info[i].first_sector = p_info[i-1].last_sector + 1;
  530.     else
  531.     p_info[i].first_sector = 0;
  532.  
  533.     if (i < num_parts - 1)
  534.     p_info[i].last_sector = p_info[i+1].first_sector - 1;
  535.     else
  536.     p_info[i].last_sector = sectors*heads*cylinders - 1;
  537.  
  538.     p_info[i].offset = 0;
  539.     p_info[i].flags = 0;
  540.     p_info[i].id = FREE_SPACE;
  541.     p_info[i].num = PRI_OR_LOG;
  542.  
  543.     if (IS_LOGICAL(num)) {
  544.     /* We have a logical partition --> shrink the extended partition
  545.      * if (1) this is the first logical drive, or (2) this is the
  546.      * last logical drive; and if there are any other logical drives
  547.      * then renumber the ones after "num".
  548.      */
  549.     if (i == 0 || (i > 0 && IS_PRIMARY(p_info[i-1].num)))
  550.         ext_info.first_sector = p_info[i].last_sector + 1;
  551.     if (i == num_parts-1 ||
  552.         (i < num_parts-1 && IS_PRIMARY(p_info[i+1].num)))
  553.         ext_info.last_sector = p_info[i].first_sector - 1;
  554.     for (i = 0; i < num_parts; i++)
  555.         if (p_info[i].num > num)
  556.         p_info[i].num--;
  557.     }
  558.  
  559.     /* Clean up the rest of the partitions */
  560.     check_part_info();
  561. }
  562.  
  563. int add_part(int num, int id, int flags, int first, int last, int offset)
  564. {
  565.     int i, pri = 0, log = 0;
  566.  
  567.     if (num_parts == MAXIMUM_PARTS ||
  568.     first < 0 ||
  569.     first >= cylinders*heads*sectors ||
  570.     last < 0 ||
  571.     last >= cylinders*heads*sectors)
  572.     return -1;
  573.  
  574.     for (i = 0; i < num_parts; i++)
  575.     if (p_info[i].id > 0 && IS_PRIMARY(p_info[i].num))
  576.         pri++;
  577.     else if (p_info[i].id > 0 && IS_LOGICAL(p_info[i].num))
  578.         log++;
  579.     if (ext_info.id == EXTENDED && log > 0)
  580.     pri++;
  581.  
  582.     if (IS_PRIMARY(num))
  583.     if (pri >= 4)
  584.         return -1;
  585.     else
  586.         pri++;
  587.  
  588.     for (i = 0; p_info[i].last_sector < first; i++);
  589.  
  590.     if (p_info[i].id != FREE_SPACE || last > p_info[i].last_sector)
  591.     return -1;
  592.  
  593.     if (id == EXTENDED)
  594.     if (ext_info.id != FREE_SPACE)
  595.         return -1;
  596.     else if (IS_PRIMARY(num)) {
  597.         ext_info.first_sector = first;
  598.         ext_info.last_sector = last;
  599.         ext_info.offset = offset;
  600.         ext_info.flags = flags;
  601.         ext_info.id = EXTENDED;
  602.         ext_info.num = num;
  603.  
  604.         return 0;
  605.     } else
  606.         return -1;
  607.  
  608.     if (IS_LOGICAL(num)) {
  609.     if (ext_info.id != EXTENDED) {
  610.         print_warning("!!!! Internal error creating logical "
  611.               "drive with no extended partition !!!!");
  612.     } else {
  613.         /* We might have a logical partition outside of the extended
  614.          * partition's range --> we have to extend the extended
  615.          * partition's range to encompass this new partition, but we
  616.          * must make sure that there are no primary partitions between
  617.          * it and the closest logical drive in extended partition.
  618.          */
  619.         if (first < ext_info.first_sector) {
  620.         if (i < num_parts-1 && IS_PRIMARY(p_info[i+1].num)) {
  621.             print_warning(TWO_EXTENDEDS);
  622.             return -1;
  623.         } else {
  624.             if (first == 0) {
  625.             ext_info.first_sector = 0;
  626.             ext_info.offset = first = offset;
  627.             } else
  628.             ext_info.first_sector = first;
  629.         }
  630.         } else if (last > ext_info.last_sector) {
  631.         if (i > 0 && IS_PRIMARY(p_info[i-1].num)) {
  632.             print_warning(TWO_EXTENDEDS);
  633.             return -1;
  634.         } else
  635.             ext_info.last_sector = last;
  636.         }
  637.     }
  638.     }
  639.  
  640.     if (first != p_info[i].first_sector &&
  641.     !(IS_LOGICAL(num) && first == offset)) {
  642.     insert_part(i, PRI_OR_LOG, FREE_SPACE, 0,
  643.             p_info[i].first_sector, first-1, 0);
  644.     i++;
  645.     }
  646.  
  647.     if (last != p_info[i].last_sector)
  648.     insert_part(i+1, PRI_OR_LOG, FREE_SPACE, 0,
  649.             last+1, p_info[i].last_sector, 0);
  650.  
  651.     p_info[i].first_sector = first;
  652.     p_info[i].last_sector = last;
  653.     p_info[i].offset = offset;
  654.     p_info[i].flags = flags;
  655.     p_info[i].id = id;
  656.     p_info[i].num = num;
  657.  
  658.     check_part_info();
  659.  
  660.     return 0;
  661. }
  662.  
  663. int find_primary(void)
  664. {
  665.     int num = 0, cur = 0;
  666.  
  667.     while (cur < num_parts && IS_PRIMARY(num))
  668.     if ((p_info[cur].id > 0 && p_info[cur].num == num) ||
  669.         (ext_info.id == EXTENDED && ext_info.num == num)) {
  670.         num++;
  671.         cur = 0;
  672.     } else
  673.         cur++;
  674.  
  675.     if (!IS_PRIMARY(num))
  676.     return -1;
  677.     else
  678.     return num;
  679. }
  680.  
  681. int find_logical(int i)
  682. {
  683.     int num = -1;
  684.     int j;
  685.  
  686.     for (j = i; j < num_parts && num == -1; j++)
  687.     if (p_info[j].id > 0 && IS_LOGICAL(p_info[j].num))
  688.         num = p_info[j].num;
  689.  
  690.     if (num == -1) {
  691.     num = 4;
  692.     for (j = 0; j < num_parts; j++)
  693.         if (p_info[j].id > 0 && p_info[j].num == num)
  694.         num++;
  695.     }
  696.  
  697.     return num;
  698. }
  699.  
  700. void inc_logical(int i)
  701. {
  702.     int j;
  703.  
  704.     for (j = i; j < num_parts; j++)
  705.     if (p_info[j].id > 0 && IS_LOGICAL(p_info[j].num))
  706.         p_info[j].num++;
  707. }
  708.  
  709. /* Command menu support by Janne Kukonlehto <jtklehto@phoenix.oulu.fi> September 1994 */
  710.  
  711. /* Constants for menuType parameter of menuSelect function */
  712. #define MENU_HORIZ 1
  713. #define MENU_VERT 2
  714. #define MENU_ACCEPT_OTHERS 4
  715. #define MENU_BUTTON 8
  716. /* Miscellenous constants */
  717. #define MENU_SPACING 2
  718. #define MENU_MAX_ITEMS 256 /* for simpleMenu function */
  719. #define MENU_UP 1
  720. #define MENU_DOWN 2
  721. #define MENU_RIGHT 3
  722. #define MENU_LEFT 4
  723.  
  724. struct MenuItem
  725. {
  726.     char key; /* Keyboard shortcut; if zero, then there is no more items in the menu item table */
  727.     char *name; /* Item name, should be eight characters with current implementation */
  728.     char *desc; /* Item description to be printed when item is selected */
  729. };
  730.  
  731. /* Actual function which prints the button bar and highlights the active button *
  732.  * Should not be called directly. Call function menuSelect instead.             */
  733.  
  734. int menuUpdate( int y, int x, struct MenuItem *menuItems, int itemLength, char *available, int menuType, int current )
  735. {
  736.     int i, lmargin = x, ymargin = y;
  737.     /* Print available buttons */
  738.     move( y, x ); clrtoeol();
  739.     for( i = 0; menuItems[i].key; i++ )
  740.     {
  741.         char buff[20];
  742.         int lenName;
  743.         /* Search next available button */
  744.         while( menuItems[i].key && !strchr(available, menuItems[i].key) )
  745.         {
  746.             i++;
  747.         }
  748.         if( !menuItems[i].key ) break; /* No more menu items */
  749.         /* If selected item is not available and we have bypassed it, make current item selected */
  750.         if( current < i && menuItems[current].key < 0 ) current = i;
  751.         /* If current item is selected, highlight it */
  752.         if( current == i ) /*attron( A_REVERSE )*/ standout ();
  753.         /* Print item */
  754.         lenName = strlen( menuItems[i].name );
  755.         if(lenName > itemLength)
  756.             print_warning("Menu item too long. Menu may look odd.");
  757.         if( menuType & MENU_BUTTON )
  758.             sprintf( buff, "[%*s%-*s]", (itemLength - lenName) / 2, "",
  759.                 (itemLength - lenName + 1) / 2 + lenName, menuItems[i].name );
  760.         else
  761.             sprintf( buff, "%*s%-*s", (itemLength - lenName) / 2, "",
  762.                 (itemLength - lenName + 1) / 2 + lenName, menuItems[i].name );
  763.         mvaddstr( y, x, buff );
  764.         /* Lowlight after selected item */
  765.         if( current == i ) /*attroff( A_REVERSE )*/ standend ();
  766.         /* Calculate position for the next item */
  767.         if( menuType & MENU_VERT )
  768.         {
  769.             y += 1;
  770.             if( y >= WARNING_START )
  771.             {
  772.                 y = ymargin;
  773.                 x += itemLength + MENU_SPACING;
  774.                 if( menuType & MENU_BUTTON ) x += 2;
  775.             }
  776.         }
  777.         else
  778.         {
  779.             x += itemLength + MENU_SPACING;
  780.             if( menuType & MENU_BUTTON ) x += 2;
  781.             if( x > COLUMNS - lmargin - 12 )
  782.             {
  783.                 x = lmargin;
  784.                 y ++ ;
  785.             }
  786.         }
  787.     }
  788.     /* Print the description of selected item */
  789.     mvaddstr( WARNING_START + 1, (COLUMNS - strlen( menuItems[current].desc )) / 2, menuItems[current].desc );
  790.     return y;
  791. }
  792.  
  793. /* This function takes a list of menu items, lets the user choose one of them *
  794.  * and returns the value keyboard shortcut of the selected menu item          */
  795.  
  796. int menuSelect( int y, int x, struct MenuItem *menuItems, int itemLength, char *available, int menuType, int menuDefault )
  797. {
  798.     int i, ylast = y, key = 0, current = menuDefault;
  799.     if( !( menuType & ( MENU_HORIZ | MENU_VERT ) ) )    
  800.     {
  801.         print_warning("Menu without direction. Defaulting horizontal.");
  802.         menuType |= MENU_HORIZ;
  803.     }
  804.     /* Make sure that the current is one of the available items */
  805.     while( !strchr(available, menuItems[current].key) )
  806.     {
  807.         current ++ ;
  808.         if( !menuItems[current].key ) current = 0;
  809.     }
  810.     /* Repeat until allowable choice has been made */
  811.     while( !key )
  812.     {
  813.         /* Display the menu */
  814.         ylast = menuUpdate( y, x, menuItems, itemLength, available, menuType, current );
  815.         refresh();
  816.         key = getch();
  817.         /* Clear out all prompts and such */
  818.         clear_warning();
  819.         for( i = y; i < ylast; i ++ )
  820.         {
  821.             move( i, x );
  822.             clrtoeol();
  823.         }
  824.         move( WARNING_START + 1, 0 );
  825.         clrtoeol();
  826.         /* Cursor keys */
  827.         if( key == ESC )
  828.         {
  829.             /* Check whether this is a real ESC or one of extended keys */
  830.             /*nodelay(stdscr, TRUE);*/
  831.             key = getch();
  832.             /*nodelay(stdscr, FALSE);*/
  833.             if( key == /*ERR*/ ESC )
  834.             {
  835.                 /* This is a real ESC */
  836.                 key = ESC;
  837.             }
  838.             if( key == '[' )
  839.             {
  840.                 /* This is one extended keys */
  841.                 switch( getch() )
  842.                 {
  843.                     case 'A': /* Up arrow */
  844.                         if( menuType & MENU_VERT )
  845.                         {
  846.                             do {
  847.                                 current -- ;
  848.                                 if( current < 0 ) while( menuItems[current+1].key ) current ++ ;
  849.                             } while( !strchr( available, menuItems[current].key ) );
  850.                             key = 0;
  851.                         }
  852.                         else
  853.                             key = MENU_UP;
  854.                         break;
  855.                     case 'B': /* Down arrow */
  856.                         if( menuType & MENU_VERT )
  857.                         {
  858.                             do {
  859.                                 current ++ ;
  860.                                 if( !menuItems[current].key ) current = 0 ;
  861.                             } while( !strchr( available, menuItems[current].key ) );
  862.                             key = 0;
  863.                         }
  864.                         else
  865.                             key = MENU_DOWN;
  866.                         break;
  867.                     case 'C': /* Right arrow */
  868.                         if( menuType & MENU_HORIZ )
  869.                         {
  870.                             do {
  871.                                 current ++ ;
  872.                                 if( !menuItems[current].key ) 
  873.                                 {
  874.                                     current = 0 ;
  875.                                 }
  876.                             } while( !strchr( available, menuItems[current].key ) );
  877.                             key = 0;
  878.                         }
  879.                         else
  880.                             key = MENU_RIGHT;
  881.                         break;
  882.                     case 'D': /* Left arrow */
  883.                         if( menuType & MENU_HORIZ )
  884.                         {
  885.                             do {
  886.                                 current -- ;
  887.                                 if( current < 0 )
  888.                                 {
  889.                                     while( menuItems[current + 1].key ) current ++ ;
  890.                                 }
  891.                             } while( !strchr( available, menuItems[current].key ) );
  892.                             key = 0;
  893.                         }
  894.                         else
  895.                             key = MENU_LEFT;
  896.                         break;
  897.                 }
  898.             }
  899.         }
  900.         /* Enter equals to the keyboard shortcut of current menu item */
  901.         if( key == 13 )
  902.         {
  903.             key = menuItems[current].key;
  904.         }
  905.         /* Should all keys to be accepted? */
  906.         if( key && (menuType & MENU_ACCEPT_OTHERS) ) break;
  907.         /* Is pressed key among acceptable ones */
  908.         if( key && (strchr(available, tolower(key)) || strchr(available, key)) ) break;
  909.         /* The key has not been accepted so far -> let's reject it */
  910.         if( key )
  911.         {
  912.             key = 0;
  913.             putchar( BELL );
  914.             print_warning("Illegal key");
  915.         }
  916.     }
  917.     /* Clear out prompts and such */
  918.     clear_warning();
  919.     for( i = y; i <= ylast; i ++ )
  920.     {
  921.         move( i, x );
  922.         clrtoeol();
  923.     }
  924.     move( WARNING_START + 1, 0 );
  925.     clrtoeol();
  926.     return key;
  927. }
  928.  
  929. /* A function which displays "Press a key to continue" and waits for a keypress *
  930.  * Perhaps calling function menuSelect is a bit overkill but who cares?         */
  931.  
  932. void menuContinue(void)
  933. {
  934.     static struct MenuItem menuContinueBtn[]=
  935.     {
  936.         { 'c', "", "Press a key to continue" },
  937.         { 0, NULL, NULL }
  938.     };
  939.  
  940.     menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X,
  941.     menuContinueBtn, 0, "c", MENU_HORIZ | MENU_ACCEPT_OTHERS, 0 );
  942. }
  943.  
  944. /* Function menuSelect takes way too many parameters  *
  945.  * Luckily, most of time we can do with this function */
  946.  
  947. int menuSimple(struct MenuItem *menuItems, int menuDefault)
  948. {
  949.     int i, j, itemLength = 0;
  950.     char available[MENU_MAX_ITEMS];
  951.     for(i = 0; menuItems[i].key; i++)
  952.     {
  953.         j = strlen( menuItems[i].name );
  954.         if( j > itemLength ) itemLength = j;
  955.         available[i] = menuItems[i].key;
  956.     }
  957.     available[i] = 0;
  958.     return menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuItems, itemLength,
  959.         available, MENU_HORIZ | MENU_BUTTON, menuDefault);
  960. }
  961.  
  962. /* End of command menu support code */
  963.  
  964. void new_part(int i)
  965. {
  966.     char response[LINE_LENGTH], def[LINE_LENGTH];
  967.     char c;
  968.     int first = p_info[i].first_sector;
  969.     int last = p_info[i].last_sector;
  970.     int offset = 0;
  971.     int flags = 0;
  972.     int id = LINUX;
  973.     int num = -1;
  974.     int num_sects = last - first + 1;
  975.     int len, ext, j;
  976.  
  977.     if (p_info[i].num == PRI_OR_LOG) {
  978.         static struct MenuItem menuPartType[]=
  979.         {
  980.             { 'p', "Primary", "Create a new primary partition" },
  981.             { 'l', "Logical", "Create a new logical partition" },
  982.             { ESC, "Cancel", "Don't create a partition" },
  983.             { 0, NULL, NULL }
  984.         };
  985.         
  986.     c = menuSimple( menuPartType, 0 );
  987.     if (toupper(c) == 'P')
  988.         num = find_primary();
  989.     else if (toupper(c) == 'L')
  990.         num = find_logical(i);
  991.     else
  992.         return;
  993.     } else if (p_info[i].num == PRIMARY)
  994.     num = find_primary();
  995.     else if (p_info[i].num == LOGICAL)
  996.     num = find_logical(i);
  997.     else
  998.     print_warning("!!! Internal error !!!");
  999.  
  1000.     sprintf(def, "%.2f", ceiling(num_sects/20.48)/100);
  1001.     mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Size (in MB): ");
  1002.     if ((len = get_string(response, LINE_LENGTH, def)) <= 0 &&
  1003.     len != GS_DEFAULT)
  1004.     return;
  1005.     else if (len > 0) {
  1006. #define num_cyls(bytes) (round_int(bytes/SECTOR_SIZE/(sectors*heads)))
  1007.     for (j = 0;
  1008.          j < len-1 && (isdigit(response[j]) || response[j] == '.');
  1009.          j++);
  1010.     if (toupper(response[j]) == 'K') {
  1011.         num_sects = num_cyls(atof(response)*1024)*sectors*heads;
  1012.     } else if (toupper(response[j]) == 'M') {
  1013.         num_sects = num_cyls(atof(response)*1024*1024)*sectors*heads;
  1014.     } else if (toupper(response[j]) == 'C') {
  1015.         num_sects = round_int(atof(response))*sectors*heads;
  1016.     } else if (toupper(response[j]) == 'S') {
  1017.         num_sects = round_int(atof(response));
  1018.     } else {
  1019.         num_sects = num_cyls(atof(response)*1024*1024)*sectors*heads;
  1020.     }
  1021.     }
  1022.  
  1023.     if (num_sects <= 0 ||
  1024.     num_sects > p_info[i].last_sector - p_info[i].first_sector + 1)
  1025.     return;
  1026.  
  1027.     move( COMMAND_LINE_Y, COMMAND_LINE_X ); clrtoeol();
  1028.     if (num_sects < p_info[i].last_sector - p_info[i].first_sector + 1) {
  1029.     /* Determine where inside free space to put partition.
  1030.      */
  1031.     static struct MenuItem menuPlace[]=
  1032.     {
  1033.         { 'b', "Beginning", "Add partition at beginning of free space" },
  1034.         { 'e', "End", "Add partition at end of free space" },
  1035.         { ESC, "Cancel", "Don't create a partition" },
  1036.         { 0, NULL, NULL }
  1037.     };
  1038.     c = menuSimple( menuPlace, 0 );
  1039.     if (toupper(c) == 'B')
  1040.         last = first + num_sects - 1;
  1041.     else if (toupper(c) == 'E')
  1042.         first = last - num_sects + 1;
  1043.     else
  1044.         return;
  1045.     }
  1046.  
  1047.     if (IS_LOGICAL(num) && ext_info.id != EXTENDED) {
  1048.     /* We want to add a logical partition, but need to create an
  1049.      * extended partition first.
  1050.      */
  1051.     if ((ext = find_primary()) < 0) {
  1052.         print_warning(NEED_EXT);
  1053.         return;
  1054.     }
  1055.     (void)add_part(ext, EXTENDED, 0, first, last,
  1056.                (first == 0 ? sectors : 0));
  1057.     }
  1058.  
  1059.     if (IS_LOGICAL(num))
  1060.     inc_logical(i);
  1061.  
  1062.     /* Now we have a complete partition to ourselves */
  1063.     if (first == 0 || IS_LOGICAL(num))
  1064.     offset = sectors;
  1065.  
  1066.     (void)add_part(num, id, flags, first, last, offset);
  1067. }
  1068.  
  1069. void clear_p_info(void)
  1070. {
  1071.     num_parts = 1;
  1072.     p_info[0].first_sector = 0;
  1073.     p_info[0].last_sector = sectors*heads*cylinders - 1;
  1074.     p_info[0].offset = 0;
  1075.     p_info[0].flags = 0;
  1076.     p_info[0].id = FREE_SPACE;
  1077.     p_info[0].num = PRI_OR_LOG;
  1078.  
  1079.     ext_info.first_sector = 0;
  1080.     ext_info.last_sector = 0;
  1081.     ext_info.offset = 0;
  1082.     ext_info.flags = 0;
  1083.     ext_info.id = FREE_SPACE;
  1084.     ext_info.num = PRIMARY;
  1085. }
  1086.  
  1087. void fill_p_info(void)
  1088. {
  1089.     int p, i;
  1090.     struct hd_geometry geometry;
  1091.     partition_table buffer;
  1092.     partition_info tmp_ext = { 0, 0, 0, 0, FREE_SPACE, PRIMARY };
  1093.  
  1094.     if ((fd = open(disk_device, O_RDWR)) < 0)
  1095.     fatal(BAD_OPEN);
  1096.     read_sector(buffer.c.b, 0);
  1097.  
  1098.     if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
  1099.     if (!heads)
  1100.         heads = geometry.heads;
  1101.     if (!sectors)
  1102.         sectors = geometry.sectors;
  1103.     if (!cylinders)
  1104.         cylinders = geometry.cylinders;
  1105.     }
  1106.  
  1107.     if (!heads || !sectors || !cylinders)
  1108.     fatal(BAD_GEOMETRY);
  1109.  
  1110.     clear_p_info();
  1111.  
  1112.     if (!zero_table) {
  1113.     for (i = 0; i < 4; i++) {
  1114.         if (buffer.p.part[i].sys_ind > 0 &&
  1115.         add_part(i,
  1116.              buffer.p.part[i].sys_ind,
  1117.              buffer.p.part[i].boot_ind,
  1118.              ((buffer.p.part[i].start_sect <= sectors) ?
  1119.               0 : buffer.p.part[i].start_sect),
  1120.              buffer.p.part[i].start_sect +
  1121.              buffer.p.part[i].nr_sects - 1,
  1122.              ((buffer.p.part[i].start_sect <= sectors) ?
  1123.               buffer.p.part[i].start_sect : 0))) {
  1124.         fatal(BAD_PRIMARY);
  1125.         }
  1126.         if (buffer.p.part[i].sys_ind == EXTENDED)
  1127.         tmp_ext = ext_info;
  1128.     }
  1129.  
  1130.     if (tmp_ext.id == EXTENDED) {
  1131.         ext_info = tmp_ext;
  1132.         logical_sectors[logical] = ext_info.first_sector;
  1133.         read_sector(buffer.c.b, logical_sectors[logical++]);
  1134.         i = 4;
  1135.         do {
  1136.         for (p = 0;
  1137.              p < 4 && (!buffer.p.part[p].sys_ind ||
  1138.                    buffer.p.part[p].sys_ind == 5);
  1139.              p++);
  1140.         if (p > 3)
  1141.             fatal(BAD_LOGICAL);
  1142.  
  1143.         if (add_part(i++,
  1144.                  buffer.p.part[p].sys_ind,
  1145.                  buffer.p.part[p].boot_ind,
  1146.                  logical_sectors[logical-1],
  1147.                  logical_sectors[logical-1] +
  1148.                  buffer.p.part[p].start_sect +
  1149.                  buffer.p.part[p].nr_sects - 1,
  1150.                  buffer.p.part[p].start_sect)) {
  1151.             fatal(BAD_LOGICAL);
  1152.         }
  1153.  
  1154.         for (p = 0;
  1155.              p < 4 && buffer.p.part[p].sys_ind != 5;
  1156.              p++);
  1157.         if (p < 4) {
  1158.             logical_sectors[logical] =
  1159.             ext_info.first_sector + buffer.p.part[p].start_sect;
  1160.             read_sector(buffer.c.b, logical_sectors[logical++]);
  1161.         }
  1162.         } while (p < 4 && logical < MAXIMUM_PARTS-4);
  1163.     }
  1164.     }
  1165. }
  1166.  
  1167. void fill_part_table(struct partition *p, partition_info *pi)
  1168. {
  1169.     int sects;
  1170.  
  1171.     p->boot_ind = pi->flags;
  1172.     p->sys_ind = pi->id;
  1173.     if (IS_LOGICAL(pi->num))
  1174.     p->start_sect = pi->offset;
  1175.     else
  1176.     p->start_sect = pi->first_sector + pi->offset;
  1177.     p->nr_sects = pi->last_sector - (pi->first_sector+pi->offset) + 1;
  1178.     sects = (((pi->first_sector+pi->offset)/(sectors*heads) > 1023) ?
  1179.          heads*sectors*1024 - 1 : pi->first_sector+pi->offset);
  1180.     set_hsc(p->head, p->sector, p->cyl, sects);
  1181.     sects = ((pi->last_sector/(sectors*heads) > 1023) ?
  1182.          heads*sectors*1024 - 1 : pi->last_sector);
  1183.     set_hsc(p->end_head, p->end_sector, p->end_cyl, sects);
  1184. }
  1185.  
  1186. void fill_primary_table(partition_table *buffer)
  1187. {
  1188.     int i;
  1189.  
  1190.     /* Zero out existing table */
  1191.     for (i = 0x1BE; i < SECTOR_SIZE; i++)
  1192.     buffer->c.b[i] = 0;
  1193.  
  1194.     for (i = 0; i < num_parts; i++)
  1195.     if (IS_PRIMARY(p_info[i].num))
  1196.         fill_part_table(&(buffer->p.part[p_info[i].num]), &(p_info[i]));
  1197.  
  1198.     if (ext_info.id == EXTENDED)
  1199.     fill_part_table(&(buffer->p.part[ext_info.num]), &ext_info);
  1200.  
  1201.     buffer->p.flag = PART_TABLE_FLAG;
  1202. }
  1203.  
  1204. void fill_logical_table(partition_table *buffer, partition_info *pi)
  1205. {
  1206.     struct partition *p;
  1207.     int i, sects;
  1208.  
  1209.     for (i = 0; i < logical && pi->first_sector != logical_sectors[i]; i++);
  1210.     if (i == logical || buffer->p.flag != (unsigned short)PART_TABLE_FLAG)
  1211.     for (i = 0; i < SECTOR_SIZE; i++)
  1212.         buffer->c.b[i] = 0;
  1213.  
  1214.     /* Zero out existing table */
  1215.     for (i = 0x1BE; i < SECTOR_SIZE; i++)
  1216.     buffer->c.b[i] = 0;
  1217.  
  1218.     fill_part_table(&(buffer->p.part[0]), pi);
  1219.  
  1220.     for (i = 0;
  1221.      i < num_parts && pi->num != p_info[i].num - 1;
  1222.      i++);
  1223.  
  1224.     if (i < num_parts) {
  1225.     p = &(buffer->p.part[1]);
  1226.     pi = &(p_info[i]);
  1227.  
  1228.     p->boot_ind = 0;
  1229.     p->sys_ind = 5;
  1230.     p->start_sect = pi->first_sector - ext_info.first_sector;
  1231.     p->nr_sects = pi->last_sector - pi->first_sector + 1;
  1232.     sects = ((pi->first_sector/(sectors*heads) > 1023) ?
  1233.          heads*sectors*1024 - 1 : pi->first_sector);
  1234.     set_hsc(p->head, p->sector, p->cyl, sects);
  1235.     sects = ((pi->last_sector/(sectors*heads) > 1023) ?
  1236.          heads*sectors*1024 - 1 : pi->last_sector);
  1237.     set_hsc(p->end_head, p->end_sector, p->end_cyl, sects);
  1238.     }
  1239.  
  1240.     buffer->p.flag = PART_TABLE_FLAG;
  1241. }
  1242.  
  1243. void write_part_table(void)
  1244. {
  1245.     int i, done = FALSE, len;
  1246.     partition_table buffer;
  1247.     char response[LINE_LENGTH];
  1248.  
  1249.     print_warning(WRITE_WARN);
  1250.  
  1251.     while (!done) {
  1252.     mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X,
  1253.          "Are you sure you want write the partition table to disk? (yes or no): ");
  1254.     
  1255.     len = get_string(response, LINE_LENGTH, NULL);
  1256.  
  1257.     clear_warning();
  1258.  
  1259.     if (len == GS_ESCAPE)
  1260.         return;
  1261.     else if (len == 2 &&
  1262.          toupper(response[0]) == 'N' &&
  1263.          toupper(response[1]) == 'O') {
  1264.         print_warning(NO_WRITE);
  1265.         return;
  1266.     } else if (len == 3 &&
  1267.            toupper(response[0]) == 'Y' &&
  1268.            toupper(response[1]) == 'E' &&
  1269.            toupper(response[2]) == 'S')
  1270.         done = TRUE;
  1271.     else
  1272.         print_warning(YES_NO);
  1273.     }
  1274.  
  1275.     clear_warning();
  1276.     print_warning(WRITING_PART);
  1277.     refresh();
  1278.     
  1279.     read_sector(buffer.c.b, 0);
  1280.     fill_primary_table(&buffer);
  1281.     write_sector(buffer.c.b, 0);
  1282.  
  1283.     for (i = 0; i < num_parts; i++)
  1284.     if (IS_LOGICAL(p_info[i].num)) {
  1285.         /* Read the extended partition table from disk ??? KEM */
  1286.         read_sector(buffer.c.b, p_info[i].first_sector);
  1287.         fill_logical_table(&buffer, &(p_info[i]));
  1288.         write_sector(buffer.c.b, p_info[i].first_sector);
  1289.     }
  1290.  
  1291.     sync();
  1292.     sleep(2);
  1293.     if (!ioctl(fd,BLKRRPART))
  1294.     changed = TRUE;
  1295.     sync();
  1296.     sleep(4);
  1297.  
  1298.     clear_warning();
  1299.     if (changed)
  1300.     print_warning(YES_WRITE);
  1301.     else
  1302.     print_warning(RRPART_FAILED);
  1303. }
  1304.  
  1305. void fp_printf(FILE *fp, char *format, ...)
  1306. {
  1307.     va_list args;
  1308.     char buf[1024];
  1309.     int y, x;
  1310.  
  1311.     va_start(args, format);
  1312.     vsprintf(buf, format, args);
  1313.     va_end(args);
  1314.  
  1315.     if (fp == NULL) {
  1316.     /* The following works best if the string to be printed has at
  1317.            most only one newline. */
  1318.     printw("%s", buf);
  1319.     getyx(stdscr, y, x);
  1320.     if (y >= COMMAND_LINE_Y-2) {
  1321.         menuContinue();
  1322.         erase();
  1323.         move(0, 0);
  1324.     }
  1325.     } else
  1326.     fprintf(fp, "%s", buf);
  1327. }
  1328.  
  1329. #define MAX_PER_LINE 16
  1330. void print_file_buffer(FILE *fp, char *buffer)
  1331. {
  1332.     int i,l;
  1333.  
  1334.     for (i = 0, l = 0; i < SECTOR_SIZE; i++, l++) {
  1335.     if (l == 0)
  1336.         fp_printf(fp, "0x%03X:", i);
  1337.     fp_printf(fp, " %02X", (unsigned char) buffer[i]);
  1338.     if (l == MAX_PER_LINE - 1) {
  1339.         fp_printf(fp, "\n");
  1340.         l = -1;
  1341.     }
  1342.     }
  1343.     if (l > 0)
  1344.     fp_printf(fp, "\n");
  1345.     fp_printf(fp, "\n");
  1346. }
  1347.  
  1348. void print_raw_table(void)
  1349. {
  1350.     int i, to_file;
  1351.     partition_table buffer;
  1352.     char fname[LINE_LENGTH];
  1353.     FILE *fp;
  1354.  
  1355.     if (print_only) {
  1356.     fp = stdout;
  1357.     to_file = TRUE;
  1358.     } else {
  1359.     mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X,
  1360.          "Enter filename or press RETURN to display on screen: ");
  1361.  
  1362.     if ((to_file = get_string(fname, LINE_LENGTH, NULL)) < 0)
  1363.         return;
  1364.  
  1365.     if (to_file) {
  1366.         if ((fp = fopen(fname, "w")) == NULL) {
  1367.         char errstr[LINE_LENGTH];
  1368.         sprintf(errstr, PRINT_OPEN_ERR, fname);
  1369.         print_warning(errstr);
  1370.         return;
  1371.         }
  1372.     } else {
  1373.         fp = NULL;
  1374.         erase();
  1375.         move(0, 0);
  1376.     }
  1377.     }
  1378.  
  1379.     fp_printf(fp, "Disk Drive: %s\n", disk_device);
  1380.  
  1381.     read_sector(buffer.c.b, 0);
  1382.     fill_primary_table(&buffer);
  1383.     print_file_buffer(fp, buffer.c.b);
  1384.  
  1385.     for (i = 0; i < num_parts; i++)
  1386.     if (IS_LOGICAL(p_info[i].num)) {
  1387.         read_sector(buffer.c.b, p_info[i].first_sector);
  1388.         fill_logical_table(&buffer, &(p_info[i]));
  1389.         print_file_buffer(fp, buffer.c.b);
  1390.     }
  1391.  
  1392.     if (to_file) {
  1393.     if (!print_only)
  1394.         fclose(fp);
  1395.     } else {
  1396.         menuContinue();
  1397.     }
  1398. }
  1399.  
  1400. void print_p_info_entry(FILE *fp, partition_info *p)
  1401. {
  1402.     int size;
  1403.     char part_str[21];
  1404.  
  1405.     if (p->id == UNUSABLE)
  1406.     fp_printf(fp, "   None   ");
  1407.     else if (p->id == FREE_SPACE && p->num == PRI_OR_LOG)
  1408.     fp_printf(fp, "   Pri/Log");
  1409.     else if (p->id == FREE_SPACE && p->num == PRIMARY)
  1410.     fp_printf(fp, "   Primary");
  1411.     else if (p->id == FREE_SPACE && p->num == LOGICAL)
  1412.     fp_printf(fp, "   Logical");
  1413.     else
  1414.     fp_printf(fp, "%2d %-7.7s", p->num+1,
  1415.           IS_LOGICAL(p->num) ? "Logical" : "Primary");
  1416.  
  1417.     fp_printf(fp, " ");
  1418.  
  1419.     fp_printf(fp, "%7d%c", p->first_sector,
  1420.           ((p->first_sector/(sectors*heads)) !=
  1421.            ((float)p->first_sector/(sectors*heads)) ?
  1422.            '*' : ' '));
  1423.  
  1424.     fp_printf(fp, " ");
  1425.  
  1426.     fp_printf(fp, "%7d%c", p->last_sector,
  1427.           (((p->last_sector+1)/(sectors*heads)) !=
  1428.            ((float)(p->last_sector+1)/(sectors*heads)) ?
  1429.            '*' : ' '));
  1430.  
  1431.     fp_printf(fp, " ");
  1432.  
  1433.     fp_printf(fp, "%6d%c", p->offset,
  1434.           ((((p->first_sector == 0 || IS_LOGICAL(p->num)) &&
  1435.          (p->offset != sectors)) ||
  1436.         (p->first_sector != 0 && IS_PRIMARY(p->num) &&
  1437.          p->offset != 0)) ?
  1438.            '#' : ' '));
  1439.  
  1440.     fp_printf(fp, " ");
  1441.  
  1442.     size = p->last_sector - p->first_sector + 1;
  1443.     fp_printf(fp, "%7d%c", size,
  1444.           ((size/(sectors*heads)) != ((float)size/(sectors*heads)) ?
  1445.            '*' : ' '));
  1446.  
  1447.     fp_printf(fp, " ");
  1448.  
  1449.     if (p->id == UNUSABLE)
  1450.     sprintf(part_str, "%.16s", "Unusable");
  1451.     else if (p->id == FREE_SPACE)
  1452.     sprintf(part_str, "%.16s", "Free Space");
  1453.     else if (partition_type[p->id])
  1454.     sprintf(part_str, "%.16s (%02X)", partition_type[p->id], p->id);
  1455.     else
  1456.     sprintf(part_str, "%.16s (%02X)", "Unknown", p->id);
  1457.     fp_printf(fp, "%-21.21s", part_str);
  1458.  
  1459.     fp_printf(fp, " ");
  1460.  
  1461.     if (p->flags == ACTIVE_FLAG)
  1462.     fp_printf(fp, "Boot (%02X)", p->flags);
  1463.     else if (p->flags != 0)
  1464.     fp_printf(fp, "Unknown (%02X)", p->flags);
  1465.     else
  1466.     fp_printf(fp, "None (%02X)", p->flags);
  1467.  
  1468.     fp_printf(fp, "\n");
  1469. }
  1470.  
  1471. void print_p_info(void)
  1472. {
  1473.     char fname[LINE_LENGTH];
  1474.     FILE *fp;
  1475.     int i, to_file, pext = (ext_info.id == EXTENDED);
  1476.  
  1477.     if (print_only) {
  1478.     fp = stdout;
  1479.     to_file = TRUE;
  1480.     } else {
  1481.     mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X,
  1482.          "Enter filename or press RETURN to display on screen: ");
  1483.  
  1484.     if ((to_file = get_string(fname, LINE_LENGTH, NULL)) < 0)
  1485.         return;
  1486.  
  1487.     if (to_file) {
  1488.         if ((fp = fopen(fname, "w")) == NULL) {
  1489.         char errstr[LINE_LENGTH];
  1490.         sprintf(errstr, PRINT_OPEN_ERR, fname);
  1491.         print_warning(errstr);
  1492.         return;
  1493.         }
  1494.     } else {
  1495.         fp = NULL;
  1496.         erase();
  1497.         move(0, 0);
  1498.     }
  1499.     }
  1500.  
  1501.     fp_printf(fp, "Partition Table for %s\n", disk_device);
  1502.     fp_printf(fp, "\n");
  1503.     fp_printf(fp, "           First    Last\n");
  1504.     fp_printf(fp, " # Type    Sector   Sector   Offset  Length   Filesystem Type (ID)  Flags\n");
  1505.     fp_printf(fp, "-- ------- -------- -------- ------- -------- --------------------- ---------\n");
  1506.  
  1507.     for (i = 0; i < num_parts; i++) {
  1508.     if (pext && (p_info[i].first_sector >= ext_info.first_sector)) {
  1509.         print_p_info_entry(fp,&ext_info);
  1510.         pext = FALSE;
  1511.     }
  1512.     print_p_info_entry(fp, &(p_info[i]));
  1513.     }
  1514.  
  1515.     if (to_file) {
  1516.     if (!print_only)
  1517.         fclose(fp);
  1518.     } else {
  1519.         menuContinue();
  1520.     }
  1521. }
  1522.  
  1523. void print_part_entry(FILE *fp, int num, partition_info *pi)
  1524. {
  1525.     int first = 0, start = 0, end = 0, size = 0;
  1526.     int ss = 0, sh = 0, sc = 0;
  1527.     int es = 0, eh = 0, ec = 0;
  1528.     int flags = 0, id = 0;
  1529.  
  1530.     if (pi != NULL) {
  1531.     flags = pi->flags;
  1532.     id = pi->id;
  1533.  
  1534.     if (IS_LOGICAL(num))
  1535.         first = pi->offset;
  1536.     else
  1537.         first = pi->first_sector + pi->offset;
  1538.  
  1539.     start = pi->first_sector + pi->offset;
  1540.     end = pi->last_sector;
  1541.     size = end - start + 1;
  1542.     if ((start/(sectors*heads)) > 1023)
  1543.         start = heads*sectors*1024 - 1;
  1544.     if ((end/(sectors*heads)) > 1023)
  1545.         end = heads*sectors*1024 - 1;
  1546.  
  1547.     ss = start % sectors + 1;
  1548.     start /= sectors;
  1549.     sh = start % heads;
  1550.     sc = start / heads;
  1551.  
  1552.     es = end % sectors + 1;
  1553.     end /= sectors;
  1554.     eh = end % heads;
  1555.     ec = end / heads;
  1556.     }
  1557.  
  1558.     fp_printf(fp, "%2d  0x%02X %4d %4d %4d 0x%02X %4d %4d %4d %7d %7d\n",
  1559.           num+1, flags, sh, ss, sc, id, eh, es, ec, first, size);
  1560. }
  1561.  
  1562.  
  1563. void print_part_table(void)
  1564. {
  1565.     int i, j, to_file;
  1566.     char fname[LINE_LENGTH];
  1567.     FILE *fp;
  1568.  
  1569.     if (print_only) {
  1570.     fp = stdout;
  1571.     to_file = TRUE;
  1572.     } else {
  1573.     mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X,
  1574.          "Enter filename or press RETURN to display on screen: ");
  1575.  
  1576.     if ((to_file = get_string(fname, LINE_LENGTH, NULL)) < 0)
  1577.         return;
  1578.  
  1579.     if (to_file) {
  1580.         if ((fp = fopen(fname, "w")) == NULL) {
  1581.         char errstr[LINE_LENGTH];
  1582.         sprintf(errstr, PRINT_OPEN_ERR, fname);
  1583.         print_warning(errstr);
  1584.         return;
  1585.         }
  1586.     } else {
  1587.         fp = NULL;
  1588.         erase();
  1589.         move(0, 0);
  1590.     }
  1591.     }
  1592.  
  1593.     fp_printf(fp, "Partition Table for %s\n", disk_device);
  1594.     fp_printf(fp, "\n");
  1595.     fp_printf(fp, "         ---Starting---      ----Ending---- Start   Number\n");
  1596.     fp_printf(fp, " # Flags Head Sect Cyl   ID  Head Sect Cyl  Sector  Sectors\n");
  1597.     fp_printf(fp, "-- ----- ---- ---- ---- ---- ---- ---- ---- ------- -------\n");
  1598.  
  1599.     for (i = 0; i < 4; i++) {
  1600.     for (j = 0;
  1601.          j < num_parts && (p_info[j].id <= 0 || p_info[j].num != i);
  1602.          j++);
  1603.     if (j < num_parts) {
  1604.         print_part_entry(fp, i, &(p_info[j]));
  1605.     } else if (ext_info.id == EXTENDED && ext_info.num == i) {
  1606.         print_part_entry(fp, i, &ext_info);
  1607.     } else {
  1608.         print_part_entry(fp, i, NULL);
  1609.     }
  1610.     }
  1611.  
  1612.     for (i = 0; i < num_parts; i++)
  1613.     if (IS_LOGICAL(p_info[i].num))
  1614.         print_part_entry(fp, p_info[i].num, &(p_info[i]));
  1615.  
  1616.     if (to_file) {
  1617.     if (!print_only)
  1618.         fclose(fp);
  1619.     } else {
  1620.         menuContinue();
  1621.     }
  1622. }
  1623.  
  1624. void print_tables(void)
  1625. {
  1626.     int done = FALSE;
  1627.  
  1628.     static struct MenuItem menuFormat[]=
  1629.     {
  1630.         { 'r', "Raw", "Print the table using raw data format" },
  1631.         { 's', "Sectors", "Print the table ordered by sectors" },
  1632.         { 't', "Table", "Just print the partition table" },
  1633.         { ESC, "Cancel", "Don't print the table" },
  1634.         { 0, NULL, NULL }
  1635.     };
  1636.     
  1637.     while (!done)
  1638.     switch ( toupper(menuSimple( menuFormat, 2)) ) {
  1639.     case 'R':
  1640.         print_raw_table();
  1641.         done = TRUE;
  1642.         break;
  1643.     case 'S':
  1644.         print_p_info();
  1645.         done = TRUE;
  1646.         break;
  1647.     case 'T':
  1648.         print_part_table();
  1649.         done = TRUE;
  1650.         break;
  1651.     case ESC:
  1652.         done = TRUE;
  1653.         break;
  1654.     }
  1655. }
  1656.  
  1657. #define END_OF_HELP "EOHS!"
  1658. #define NEW_HELP_SCREEN "SNHS!"
  1659. void display_help()
  1660. {
  1661.     char *help_text[] = {
  1662.     "Help Screen for cfdisk " VERSION,
  1663.     "",
  1664.     "This is cfdisk, a curses based disk partitioning programs, which",
  1665.     "allows you to create, delete and modify partitions on your hard",
  1666.     "disk drive.",
  1667.     "",
  1668.     "Copyright (C) 1994 Kevin E. Martin",
  1669.     "",
  1670.     "Command      Meaning",
  1671.     "-------      -------",
  1672.     "  b          Toggle bootable flag of the current partition",
  1673.     "  d          Delete the current partition",
  1674.     "  g          Change cylinders, heads, sectors-per-track parameters",
  1675.     "             WARNING: This option should only be used by people who",
  1676.     "             know what they are doing.",
  1677.     "  h          Print this screen",
  1678.     "  m          Maximize disk usage of the current partition",
  1679.     "             Note: This may make the partition incompatible with",
  1680.     "             DOS, OS/2, ...",
  1681.     "  n          Create new partition from free space",
  1682.     "  p          Print partition table to the screen or to a file",
  1683.     "             There are several different formats for the partition",
  1684.     "             that you can choose from:",
  1685.     "                r - Raw data (exactly what would be written to disk)",
  1686.     "                s - Table ordered by sectors",
  1687.     "                t - Table in raw format",
  1688.     "  q          Quit program without writing partition table",
  1689.     "  t          Change the filesystem type",
  1690.     "  u          Change units of the partition size display",
  1691.     "             Rotates through Mb, sectors and cylinders",
  1692.     "  W          Write partition table to disk (must enter upper case W)",
  1693.         "             Since this might destroy data on the disk, you must",
  1694.     "             either confirm or deny the write by entering `yes' or",
  1695.     "             `no'",
  1696.     "Up Arrow     Move cursor to the previous partition",
  1697.     "Down Arrow   Move cursor to the next partition",
  1698.     "CTRL-L       Redraws the screen",
  1699.     "  ?          Print this screen",
  1700.     "",
  1701.     "Note: All of the commands can be entered with either upper or lower",
  1702.     "case letters (except for Writes).",
  1703.     END_OF_HELP
  1704.     };
  1705.  
  1706.     int cur_line = 0;
  1707.     FILE *fp = NULL;
  1708.  
  1709.     erase();
  1710.     move(0, 0);
  1711.     while (strcmp(help_text[cur_line], END_OF_HELP))
  1712.     if (!strcmp(help_text[cur_line], NEW_HELP_SCREEN)) {
  1713.         menuContinue();
  1714.         erase();
  1715.         move(0, 0);
  1716.         cur_line++;
  1717.     } else
  1718.         fp_printf(fp, "%s\n", help_text[cur_line++]);
  1719.  
  1720.     menuContinue();
  1721. }
  1722.  
  1723. int change_geometry(void)
  1724. {
  1725.     int ret_val = FALSE;
  1726.     int done = FALSE;
  1727.     char def[LINE_LENGTH];
  1728.     char response[LINE_LENGTH];
  1729.     int tmp_val;
  1730.  
  1731.     while (!done) {
  1732.         static struct MenuItem menuGeometry[]=
  1733.         {
  1734.             { 'c', "Cylinders", "Change cylinder geometry" },
  1735.             { 'h', "Heads", "Change head geometry" },
  1736.             { 's', "Sectors", "Change sector geometry" },
  1737.             { 'd', "Done", "Done with changing geometry" },
  1738.             { 0, NULL, NULL }
  1739.         };
  1740.     move(COMMAND_LINE_Y, COMMAND_LINE_X);
  1741.     clrtoeol();
  1742.     refresh();
  1743.  
  1744.     clear_warning();
  1745.  
  1746.     switch (toupper( menuSimple(menuGeometry, 3) )) {
  1747.     case 'C':
  1748.         sprintf(def, "%d", cylinders);
  1749.         mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X,
  1750.              "Enter the number of cylinders: ");
  1751.         if (get_string(response, LINE_LENGTH, def) > 0) {
  1752.         tmp_val = atoi(response);
  1753.         if (tmp_val > 0 && tmp_val <= MAX_CYLINDERS) {
  1754.             cylinders = tmp_val;
  1755.             ret_val = TRUE;
  1756.         } else
  1757.             print_warning(BAD_CYLINDERS);
  1758.         }
  1759.         break;
  1760.     case 'H':
  1761.         sprintf(def, "%d", heads);
  1762.         mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X,
  1763.              "Enter the number of heads: ");
  1764.         if (get_string(response, LINE_LENGTH, def) > 0) {
  1765.         tmp_val = atoi(response);
  1766.         if (tmp_val > 0 && tmp_val <= MAX_HEADS) {
  1767.             heads = tmp_val;
  1768.             ret_val = TRUE;
  1769.         } else
  1770.             print_warning(BAD_HEADS);
  1771.         }
  1772.         break;
  1773.     case 'S':
  1774.         sprintf(def, "%d", sectors);
  1775.         mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X,
  1776.              "Enter the number of sectors per track: ");
  1777.         if (get_string(response, LINE_LENGTH, def) > 0) {
  1778.         tmp_val = atoi(response);
  1779.         if (tmp_val > 0 && tmp_val <= MAX_SECTORS) {
  1780.             sectors = tmp_val;
  1781.             ret_val = TRUE;
  1782.         } else
  1783.             print_warning(BAD_SECTORS);
  1784.         }
  1785.         break;
  1786.     case ESC:
  1787.     case 'D':
  1788.         done = TRUE;
  1789.         break;
  1790.     default:
  1791.         putchar(BELL);
  1792.         break;
  1793.     }
  1794.     }
  1795.  
  1796.     if (ret_val) {
  1797.     if (p_info[num_parts-1].last_sector > heads*sectors*cylinders-1) {
  1798.         while (p_info[num_parts-1].first_sector > heads*sectors*cylinders-1) {
  1799.         if (p_info[num_parts-1].id == FREE_SPACE ||
  1800.             p_info[num_parts-1].id == UNUSABLE)
  1801.             remove_part(num_parts-1);
  1802.         else
  1803.             del_part(num_parts-1);
  1804.         }
  1805.  
  1806.         p_info[num_parts-1].last_sector = heads*sectors*cylinders - 1;
  1807.  
  1808.         if (ext_info.last_sector > heads*sectors*cylinders-1)
  1809.         ext_info.last_sector = heads*sectors*cylinders - 1;
  1810.     } else if (p_info[num_parts-1].last_sector < heads*sectors*cylinders-1) {
  1811.         if (p_info[num_parts-1].id == FREE_SPACE ||
  1812.         p_info[num_parts-1].id == UNUSABLE) {
  1813.         p_info[num_parts-1].last_sector = heads*sectors*cylinders - 1;
  1814.         } else {
  1815.         insert_part(num_parts, PRI_OR_LOG, FREE_SPACE, 0,
  1816.                 p_info[num_parts-1].last_sector+1,
  1817.                 heads*sectors*cylinders-1, 0);
  1818.         }
  1819.     }
  1820.  
  1821.     /* Make sure the partitions are correct */
  1822.     check_part_info();
  1823.     }
  1824.  
  1825.     return ret_val;
  1826. }
  1827.  
  1828. void change_id(int i)
  1829. {
  1830.     char id[LINE_LENGTH], def[LINE_LENGTH];
  1831.     int num_types = 0;
  1832.     int num_across, num_down;
  1833.     int len, new_id = LINUX;
  1834.     int y_start, y_end;
  1835.     int j, pos;
  1836.  
  1837.     for (num_types = 0, j = 1; j < NUM_PART_TYPES; j++)
  1838.     if (partition_type[j])
  1839.         num_types++;
  1840.  
  1841.     num_across = COLS/COL_ID_WIDTH;
  1842.     num_down = (((float)num_types)/num_across + 1);
  1843.     y_start = COMMAND_LINE_Y - 1 - num_down;
  1844.     if (y_start > DISK_TABLE_START+cur_part+4)
  1845.     y_start = DISK_TABLE_START+cur_part+4;
  1846.     y_end = y_start + num_down - 1;
  1847.  
  1848.     for (j = y_start - 1; j <= y_end + 1; j++) {
  1849.     move(j, 0);
  1850.     clrtoeol();
  1851.     }
  1852.  
  1853.     for (pos = 0, j = 1; j < NUM_PART_TYPES; j++)
  1854.     if (partition_type[j]) {
  1855.         move(y_start + pos % num_down, (pos/num_down)*COL_ID_WIDTH + 1);
  1856.         printw("%02X %-16.16s", j, partition_type[j]);
  1857.         pos++;
  1858.     }
  1859.  
  1860.     sprintf(def, "%02X", new_id);
  1861.     mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Enter filesystem type: ");
  1862.     if ((len = get_string(id, 2, def)) <= 0 && len != GS_DEFAULT)
  1863.     return;
  1864.  
  1865.     if (len != GS_DEFAULT) {
  1866.     if (!isxdigit(id[0]))
  1867.         return;
  1868.     new_id = (isdigit(id[0]) ? id[0] - '0' : tolower(id[0]) - 'a' + 10);
  1869.     if (len == 2)
  1870.         if (isxdigit(id[1]))
  1871.         new_id = new_id*16 +
  1872.             (isdigit(id[1]) ? id[1] - '0' : tolower(id[1]) - 'a' + 10);
  1873.         else
  1874.         return;
  1875.     }
  1876.  
  1877.     if (new_id == 0)
  1878.     print_warning(ID_EMPTY);
  1879.     else if (new_id == EXTENDED)
  1880.     print_warning(ID_EXT);
  1881.     else
  1882.     p_info[i].id = new_id;
  1883. }
  1884.  
  1885. void draw_partition(int i)
  1886. {
  1887.     int size, j;
  1888.     int y = i + DISK_TABLE_START + 2 - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN;
  1889.  
  1890.     if (!arrow_cursor) {
  1891.     move(y, 0);
  1892.     for (j = 0; j < COLS; j++)
  1893.         addch(' ');
  1894.     }
  1895.  
  1896.     if (p_info[i].id > 0) {
  1897.     mvprintw(y, NAME_START,
  1898.          "%s%d", disk_device, p_info[i].num+1);
  1899.     if (p_info[i].flags) {
  1900.         if (p_info[i].flags == ACTIVE_FLAG)
  1901.         mvaddstr(y, FLAGS_START, "Boot");
  1902.         else
  1903.         mvprintw(y, FLAGS_START, "Unk(%02X)", p_info[i].flags);
  1904.         if (p_info[i].first_sector == 0 || IS_LOGICAL(p_info[i].num)) {
  1905.         if (p_info[i].offset != sectors)
  1906.             addstr(", NC");
  1907.         } else {
  1908.         if (p_info[i].offset != 0)
  1909.             addstr(", NC");
  1910.         }
  1911.     } else {
  1912.         if (p_info[i].first_sector == 0 || IS_LOGICAL(p_info[i].num)) {
  1913.         if (p_info[i].offset != sectors)
  1914.             mvaddstr(y, FLAGS_START, "NC");
  1915.         } else {
  1916.         if (p_info[i].offset != 0)
  1917.             mvaddstr(y, FLAGS_START, "NC");
  1918.         }
  1919.     }
  1920.     }
  1921.     mvaddstr(y, PTYPE_START,
  1922.          (p_info[i].id == UNUSABLE ? "" :
  1923.           (IS_LOGICAL(p_info[i].num) ? "Logical" :
  1924.            (p_info[i].num >= 0 ? "Primary" :
  1925.         (p_info[i].num == PRI_OR_LOG ? "Pri/Log" :
  1926.          (p_info[i].num == PRIMARY ? "Primary" : "Logical"))))));
  1927.     if (p_info[i].id == UNUSABLE)
  1928.     mvaddstr(y, FSTYPE_START, "Unusable");
  1929.     else if (p_info[i].id == FREE_SPACE)
  1930.     mvaddstr(y, FSTYPE_START, "Free Space");
  1931.     else if (partition_type[p_info[i].id])
  1932.     mvaddstr(y, FSTYPE_START, partition_type[p_info[i].id]);
  1933.     else
  1934.     mvprintw(y, FSTYPE_START, "Unknown (%02X)", p_info[i].id);
  1935.  
  1936.     size = p_info[i].last_sector - p_info[i].first_sector + 1;
  1937.     if (display_units == SECTORS)
  1938.     mvprintw(y, SIZE_START, "%9d", size);
  1939.     else if (display_units == CYLINDERS)
  1940.     mvprintw(y, SIZE_START, "%9d", size/(sectors*heads));
  1941.     else
  1942.     mvprintw(y, SIZE_START, "%9.2f", ceiling(size/20.48)/100);
  1943.     if (((size/(sectors*heads)) != ceiling(size/(sectors*(float)heads))) ||
  1944.     ((p_info[i].first_sector/(sectors*heads)) !=
  1945.      ceiling(p_info[i].first_sector/(sectors*heads))))
  1946.     mvprintw(y, COLUMNS-1, "*");
  1947. }
  1948.  
  1949. void init_const(void)
  1950. {
  1951.     if (!defined) {
  1952.     NAME_START = (((float)NAME_START)/COLUMNS)*COLS;
  1953.     FLAGS_START = (((float)FLAGS_START)/COLUMNS)*COLS;
  1954.     PTYPE_START = (((float)PTYPE_START)/COLUMNS)*COLS;
  1955.     FSTYPE_START = (((float)FSTYPE_START)/COLUMNS)*COLS;
  1956.     SIZE_START = (((float)SIZE_START)/COLUMNS)*COLS;
  1957.     COMMAND_LINE_X = (((float)COMMAND_LINE_X)/COLUMNS)*COLS;
  1958.  
  1959.     COMMAND_LINE_Y = LINES - 4;
  1960.     WARNING_START = LINES - 2;
  1961.  
  1962.     if ((NUM_ON_SCREEN = COMMAND_LINE_Y - DISK_TABLE_START - 3) <= 0)
  1963.         NUM_ON_SCREEN = 1;
  1964.  
  1965.     COLUMNS = COLS;
  1966.     defined = TRUE;
  1967.     }
  1968. }
  1969.  
  1970. void draw_screen(void)
  1971. {
  1972.     int i;
  1973.     char *line;
  1974.  
  1975.     line = (char *)malloc((COLS+1)*sizeof(char));
  1976.  
  1977.     if (warning_last_time) {
  1978.     for (i = 0; i < COLS; i++) {
  1979.         move(WARNING_START, i);
  1980.         line[i] = inch();
  1981.     }
  1982.     line[COLS] = 0;
  1983.     }
  1984.  
  1985.     erase();
  1986.  
  1987.     if (warning_last_time)
  1988.     mvaddstr(WARNING_START, 0, line);
  1989.  
  1990.  
  1991.     sprintf(line, "cfdisk %s", VERSION);
  1992.     mvaddstr(HEADER_START, (COLS-strlen(line))/2, line);
  1993.     sprintf(line, "Disk Drive: %s", disk_device);
  1994.     mvaddstr(HEADER_START+2, (COLS-strlen(line))/2, line);
  1995.     sprintf(line, "Heads: %d   Sectors per Track: %d   Cylinders: %d",
  1996.         heads, sectors, cylinders);
  1997.     mvaddstr(HEADER_START+3, (COLS-strlen(line))/2, line);
  1998.  
  1999.     mvaddstr(DISK_TABLE_START, NAME_START, "Name");
  2000.     mvaddstr(DISK_TABLE_START, FLAGS_START, "Flags");
  2001.     mvaddstr(DISK_TABLE_START, PTYPE_START, "Part Type");
  2002.     mvaddstr(DISK_TABLE_START, FSTYPE_START, "FS Type");
  2003.     if (display_units == SECTORS)
  2004.     mvaddstr(DISK_TABLE_START, SIZE_START, "  Sectors");
  2005.     else if (display_units == CYLINDERS)
  2006.     mvaddstr(DISK_TABLE_START, SIZE_START, "Cylinders");
  2007.     else
  2008.     mvaddstr(DISK_TABLE_START, SIZE_START, "Size (MB)");
  2009.  
  2010.     move(DISK_TABLE_START+1, 1);
  2011.     for (i = 1; i < COLS-1; i++)
  2012.     addch('-');
  2013.  
  2014.     if (NUM_ON_SCREEN >= num_parts)
  2015.     for (i = 0; i < num_parts; i++)
  2016.         draw_partition(i);
  2017.     else
  2018.     for (i = (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN;
  2019.          i < NUM_ON_SCREEN + (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN &&
  2020.          i < num_parts;
  2021.          i++)
  2022.         draw_partition(i);
  2023.  
  2024.     free(line);
  2025. }
  2026.  
  2027. int draw_cursor(int move)
  2028. {
  2029.     if (move != 0 && (cur_part + move < 0 || cur_part + move >= num_parts))
  2030.     return -1;
  2031.  
  2032.     if (arrow_cursor)
  2033.     mvaddstr(DISK_TABLE_START + cur_part + 2
  2034.          - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN, 0, "   ");
  2035.     else
  2036.     draw_partition(cur_part);
  2037.  
  2038.     cur_part += move;
  2039.  
  2040.     if (((cur_part - move)/NUM_ON_SCREEN)*NUM_ON_SCREEN !=
  2041.     (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN)
  2042.     draw_screen();
  2043.  
  2044.     if (arrow_cursor)
  2045.     mvaddstr(DISK_TABLE_START + cur_part + 2
  2046.          - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN, 0, "-->");
  2047.     else {
  2048.     standout();
  2049.     draw_partition(cur_part);
  2050.     standend();
  2051.     }
  2052.  
  2053.     return 0;
  2054. }
  2055.  
  2056. void die(int dummy)
  2057. {
  2058.     signal(SIGINT, old_SIGINT);
  2059.     signal(SIGTERM, old_SIGTERM);
  2060.     mvcur(0, COLS-1, LINES-1, 0);
  2061.     nl();
  2062.     endwin();
  2063.     fdexit(0);
  2064. }
  2065.  
  2066. void do_curses_fdisk(void)
  2067. {
  2068.     int done = FALSE;
  2069.     char command;
  2070.  
  2071.     static struct MenuItem menuMain[]=
  2072.     {
  2073.         { 'b', "Bootable", "Toggle bootable flag of the current partition" },
  2074.         { 'd', "Delete", "Delete the current partition" },
  2075.         { 'g', "Geometry", "Change disk geometry (experts only)" },
  2076.         { 'h', "Help", "Print help screen" },
  2077.         { 'm', "Maximize", "Maximize disk usage of the current partition (experts only)" },
  2078.         { 'n', "New", "Create new partition from free space" },
  2079.         { 'p', "Print", "Print partition table to the screen or to a file" },
  2080.         { 'q', "Quit", "Quit program without writing partition table" },
  2081.         { 't', "Type", "Change the filesystem type (DOS, Linux, OS/2 and so on)" },
  2082.         { 'u', "Units", "Change units of the partition size display (MB, sect, cyl)" },
  2083.         { 'W', "Write", "Write partition table to disk (this might destroy data)" },
  2084.         { 0, NULL, NULL }
  2085.     };
  2086.  
  2087.     initscr();
  2088.     old_SIGINT = signal(SIGINT, die);
  2089.     old_SIGTERM = signal(SIGTERM, die);
  2090. #ifdef DEBUG
  2091.     signal(SIGINT, old_SIGINT);
  2092.     signal(SIGTERM, old_SIGTERM);
  2093. #endif
  2094.  
  2095.     cbreak();
  2096.     noecho();
  2097.     nonl();
  2098.  
  2099.     init_const();
  2100.  
  2101.     fill_p_info();
  2102.  
  2103.     draw_screen();
  2104.  
  2105.     while (!done) {
  2106.     (void)draw_cursor(0);
  2107.  
  2108.     if (p_info[cur_part].id == FREE_SPACE)
  2109.         command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 8, "hnpquW",
  2110.             MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, 0);
  2111.     else if (p_info[cur_part].id > 0)
  2112.         command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 8, "bdhmpqtuW",
  2113.             MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, 0);
  2114.     else
  2115.         command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 8, "hpquW",
  2116.             MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, 0);
  2117.  
  2118.     switch ( command ) {
  2119.     case 'B':
  2120.     case 'b':
  2121.         if (p_info[cur_part].id > 0)
  2122.         p_info[cur_part].flags ^= 0x80;
  2123.         else
  2124.         print_warning(NO_FLAGS);
  2125.         break;
  2126.     case 'D':
  2127.     case 'd':
  2128.         if (p_info[cur_part].id > 0) {
  2129.         del_part(cur_part);
  2130.         if (cur_part >= num_parts)
  2131.             cur_part = num_parts - 1;
  2132.         draw_screen();
  2133.         } else
  2134.         print_warning(DEL_EMPTY);
  2135.         break;
  2136.     case 'G':
  2137.     case 'g':
  2138.         if (change_geometry())
  2139.         draw_screen();
  2140.         break;
  2141.     case 'M':
  2142.     case 'm':
  2143.         if (p_info[cur_part].id > 0) {
  2144.         if (p_info[cur_part].first_sector == 0 ||
  2145.             IS_LOGICAL(p_info[cur_part].num)) {
  2146.             if (p_info[cur_part].offset == sectors)
  2147.             p_info[cur_part].offset = 1;
  2148.             else
  2149.             p_info[cur_part].offset = sectors;
  2150.             draw_screen();
  2151.         } else if (p_info[cur_part].offset != 0)
  2152.             p_info[cur_part].offset = 0;
  2153.         else
  2154.             print_warning(MAX_UNMAXABLE);
  2155.         } else
  2156.         print_warning(MAX_UNMAXABLE);
  2157.         break;
  2158.     case 'N':
  2159.     case 'n':
  2160.         if (p_info[cur_part].id == FREE_SPACE) {
  2161.         new_part(cur_part);
  2162.         draw_screen();
  2163.         } else if (p_info[cur_part].id == UNUSABLE)
  2164.         print_warning(ADD_UNUSABLE);
  2165.         else
  2166.         print_warning(ADD_EXISTS);
  2167.         break;
  2168.     case 'P':
  2169.     case 'p':
  2170.         print_tables();
  2171.         draw_screen();
  2172.         break;
  2173.     case 'Q':
  2174.     case 'q':
  2175.         done = TRUE;
  2176.         break;
  2177.     case 'T':
  2178.     case 't':
  2179.         if (p_info[cur_part].id > 0) {
  2180.         change_id(cur_part);
  2181.         draw_screen();
  2182.         } else
  2183.         print_warning(TYPE_EMPTY);
  2184.         break;
  2185.     case 'U':
  2186.     case 'u':
  2187.         if (display_units == MEGABYTES)
  2188.         display_units = SECTORS;
  2189.         else if (display_units == SECTORS)
  2190.         display_units = CYLINDERS;
  2191.         else if (display_units == CYLINDERS)
  2192.         display_units = MEGABYTES;
  2193.         draw_screen();
  2194.         break;
  2195.     case 'W':
  2196.         write_part_table();
  2197.         break;
  2198.     case 'H':
  2199.     case 'h':
  2200.     case '?':
  2201.         display_help();
  2202.         draw_screen();
  2203.         break;
  2204.     case MENU_UP : /* Up arrow */
  2205.         if (!draw_cursor(-1))
  2206.         command = 0;
  2207.         else
  2208.         print_warning(NO_MORE_PARTS);
  2209.         break;
  2210.     case MENU_DOWN : /* Down arrow */
  2211.         if (!draw_cursor(1))
  2212.         command = 0;
  2213.         else
  2214.         print_warning(NO_MORE_PARTS);
  2215.         break;
  2216.     case REDRAWKEY:
  2217.         clear();
  2218.         draw_screen();
  2219.         break;
  2220.     default:
  2221.         print_warning(BAD_COMMAND);
  2222.         putchar(BELL); /* CTRL-G */
  2223.     }
  2224.     }
  2225.  
  2226.     signal(SIGINT, old_SIGINT);
  2227.     signal(SIGTERM, old_SIGTERM);
  2228.     mvcur(0, COLS-1, LINES-1, 0);
  2229.     nl();
  2230.     endwin();
  2231.     fdexit(0);
  2232. }
  2233.  
  2234. void copyright(void)
  2235. {
  2236.     fprintf(stderr, "Copyright (C) 1994 Kevin E. Martin\n");
  2237. }
  2238.  
  2239. void usage(char *prog_name)
  2240. {
  2241.     fprintf(stderr,
  2242.         "%s: [-avz] [-c # cylinders] [-h # heads] [-s # sectors/track]\n",
  2243.         prog_name);
  2244.     fprintf(stderr,
  2245.         "[ -P opt ] device\n");
  2246.     copyright();
  2247. }
  2248.  
  2249. void main(int argc, char **argv)
  2250. {
  2251.     char c;
  2252.     int i, len;
  2253.  
  2254.     while ((c = getopt(argc, argv, "ac:h:s:vzP:")) != EOF)
  2255.     switch (c) {
  2256.     case 'a':
  2257.         arrow_cursor = TRUE;
  2258.         break;
  2259.     case 'c':
  2260.         cylinders = atoi(optarg);
  2261.         if (cylinders <= 0 || cylinders > MAX_CYLINDERS) {
  2262.         fprintf(stderr, "%s: %s\n", argv[0], BAD_CYLINDERS);
  2263.         exit(1);
  2264.         }
  2265.         break;
  2266.     case 'h':
  2267.         heads = atoi(optarg);
  2268.         if (heads <= 0 || heads > MAX_HEADS) {
  2269.         fprintf(stderr, "%s: %s\n", argv[0], BAD_HEADS);
  2270.         exit(1);
  2271.         }
  2272.         break;
  2273.     case 's':
  2274.         sectors = atoi(optarg);
  2275.         if (sectors <= 0 || sectors > MAX_SECTORS) {
  2276.         fprintf(stderr, "%s: %s\n", argv[0], BAD_SECTORS);
  2277.         exit(1);
  2278.         }
  2279.         break;
  2280.     case 'v':
  2281.         fprintf(stderr, "cfdisk %s\n", VERSION);
  2282.         copyright();
  2283.         exit(0);
  2284.     case 'z':
  2285.         zero_table = TRUE;
  2286.         break;
  2287.     case 'P':
  2288.         len = strlen(optarg);
  2289.         for (i = 0; i < len; i++) {
  2290.         switch (optarg[i]) {
  2291.         case 'r':
  2292.             print_only |= PRINT_RAW_TABLE;
  2293.             break;
  2294.         case 's':
  2295.             print_only |= PRINT_SECTOR_TABLE;
  2296.             break;
  2297.         case 't':
  2298.             print_only |= PRINT_PARTITION_TABLE;
  2299.             break;
  2300.         default:
  2301.             usage(argv[0]);
  2302.             break;
  2303.         }
  2304.         }
  2305.         break;
  2306.     default:
  2307.         usage(argv[0]);
  2308.         exit(1);
  2309.     }
  2310.  
  2311.     if (argc-optind == 1)
  2312.     disk_device = argv[optind];
  2313.     else if (argc-optind != 0) {
  2314.     usage(argv[0]);
  2315.     exit(1);
  2316.     } else if ((fd = open(DEFAULT_DEVICE, O_RDWR)) < 0)
  2317.     disk_device = ALTERNATE_DEVICE;
  2318.     else close(fd);
  2319.  
  2320.     if (print_only) {
  2321.     fill_p_info();
  2322.     if (print_only & PRINT_RAW_TABLE)
  2323.         print_raw_table();
  2324.     if (print_only & PRINT_SECTOR_TABLE)
  2325.         print_p_info();
  2326.     if (print_only & PRINT_PARTITION_TABLE)
  2327.         print_part_table();
  2328.     } else
  2329.     do_curses_fdisk();
  2330. }
  2331.