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