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