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