1 /****************************************************************************
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.
9 * cfdisk was inspired by the fdisk program, by A. V. Le Blanc
10 * (LeBlanc@mcc.ac.uk).
12 * Copyright (C) 1994 Kevin E. Martin (martin@cs.unc.edu)
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.
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.
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.
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-p: aeb@cwi.nl
33 * Rebaptised 2.9p, following util-linux versioning.
35 * Recognition of NTFS / HPFS difference inspired by patches
36 * from Marty Leisner <leisner@sdsp.mc.xerox.com>
37 * Exit codes by Enrique Zanardi <ezanardi@ull.es>:
39 * 1: command line error, out of memory
40 * 2: hardware problems [Cannot open/seek/read/write disk drive].
41 * 3: ioctl(fd, HDIO_GETGEO,...) failed. (Probably it is not a disk.)
42 * 4: bad partition table on disk. [Bad primary/logical partition].
44 * Sat, 23 Jan 1999 19:34:45 +0100 <Vincent.Renardias@ldsol.com>
45 * Internationalized + provided initial French translation.
46 * Sat Mar 20 09:26:34 EST 1999 <acme@conectiva.com.br>
48 * Sun Jul 18 03:19:42 MEST 1999 <aeb@cwi.nl>
49 * Terabyte-sized disks.
50 * Sat Jun 30 05:23:19 EST 2001 <nathans@sgi.com>
51 * XFS label recognition.
52 * Thu Nov 22 15:42:56 CET 2001 <flavio.stanchina@tin.it>
53 * ext3 and ReiserFS recognition.
54 * Sun Oct 12 17:43:43 CEST 2003 <flavio.stanchina@tin.it>
55 * JFS recognition; ReiserFS label recognition.
57 ****************************************************************************/
67 #ifdef HAVE_SLCURSES_H
69 #elif defined(HAVE_SLANG_SLCURSES_H)
70 #include <slang/slcurses.h>
71 #elif defined(HAVE_NCURSES_H)
73 #elif defined(HAVE_NCURSES_NCURSES_H)
74 #include <ncurses/ncurses.h>
80 #include <sys/ioctl.h>
89 #define DEFAULT_DEVICE "/dev/hd0"
90 #define ALTERNATE_DEVICE "/dev/sd0"
91 #elif defined(__FreeBSD__)
92 #define DEFAULT_DEVICE "/dev/ad0"
93 #define ALTERNATE_DEVICE "/dev/da0"
95 #define DEFAULT_DEVICE "/dev/hda"
96 #define ALTERNATE_DEVICE "/dev/sda"
99 /* With K=1024 we have `binary' megabytes, gigabytes, etc.
100 Some misguided hackers like that.
101 With K=1000 we have MB and GB that follow the standards
102 [SI, ATA, IEEE etc] and the disk manufacturers and the law. */
105 #define LINE_LENGTH 80
106 #define MAXIMUM_PARTS 60
108 #define SECTOR_SIZE 512
110 #define MAX_HEADS 256
111 #define MAX_SECTORS 63
113 #define ACTIVE_FLAG 0x80
114 #define PART_TABLE_FLAG0 0x55
115 #define PART_TABLE_FLAG1 0xAA
118 #define FREE_SPACE 0x00
119 #define DOS_EXTENDED 0x05
120 #define OS2_OR_NTFS 0x07
121 #define WIN98_EXTENDED 0x0f
122 #define LINUX_EXTENDED 0x85
123 #define LINUX_MINIX 0x81
124 #define LINUX_SWAP 0x82
127 #define PRI_OR_LOG -1
131 #define COL_ID_WIDTH 25
138 #define REDRAWKEY '\014' /* ^L */
139 #define UPKEY '\020' /* ^P */
140 #define DOWNKEY '\016' /* ^N */
148 #define GS_DEFAULT -1
151 #define PRINT_RAW_TABLE 1
152 #define PRINT_SECTOR_TABLE 2
153 #define PRINT_PARTITION_TABLE 4
155 #define IS_PRIMARY(p) ((p) >= 0 && (p) < 4)
156 #define IS_LOGICAL(p) ((p) > 3)
158 #define round_int(d) ((double)((int)(d+0.5)))
159 #define ceiling(d) ((double)(((d) != (int)(d)) ? (int)(d+1.0) : (int)(d)))
162 unsigned char boot_ind; /* 0x80 - active */
163 unsigned char head; /* starting head */
164 unsigned char sector; /* starting sector */
165 unsigned char cyl; /* starting cylinder */
166 unsigned char sys_ind; /* What partition type */
167 unsigned char end_head; /* end head */
168 unsigned char end_sector; /* end sector */
169 unsigned char end_cyl; /* end cylinder */
170 unsigned char start4[4]; /* starting sector counting from 0 */
171 unsigned char size4[4]; /* nr of sectors in partition */
176 long long cylinders = 0;
177 int cylinder_size = 0; /* heads * sectors */
178 long long total_size = 0; /* actual_size rounded down */
179 long long actual_size = 0; /* (in 512-byte sectors) - set using ioctl */
180 /* explicitly given user values */
181 int user_heads = 0, user_sectors = 0;
182 long long user_cylinders = 0;
183 /* kernel values; ignore the cylinders */
184 int kern_heads = 0, kern_sectors = 0;
185 /* partition-table derived values */
186 int pt_heads = 0, pt_sectors = 0;
190 set_hsc0(unsigned char *h, unsigned char *s, int *c, long long sector) {
191 *s = sector % sectors + 1;
199 set_hsc(unsigned char *h, unsigned char *s, unsigned char *c,
203 if (sector >= 1024*cylinder_size)
204 sector = 1024*cylinder_size - 1;
205 set_hsc0(h, s, &cc, sector);
207 *s |= (cc >> 2) & 0xC0;
211 set_hsc_begin(struct partition *p, long long sector) {
212 set_hsc(& p->head, & p->sector, & p->cyl, sector);
216 set_hsc_end(struct partition *p, long long sector) {
217 set_hsc(& p->end_head, & p->end_sector, & p->end_cyl, sector);
220 #define is_extended(x) ((x) == DOS_EXTENDED || (x) == WIN98_EXTENDED || \
221 (x) == LINUX_EXTENDED)
223 #define is_dos_partition(x) ((x) == 1 || (x) == 4 || (x) == 6)
224 #define may_have_dos_label(x) (is_dos_partition(x) \
225 || (x) == 7 || (x) == 0xb || (x) == 0xc || (x) == 0xe \
226 || (x) == 0x11 || (x) == 0x14 || (x) == 0x16 || (x) == 0x17)
228 /* start_sect and nr_sects are stored little endian on all machines */
229 /* moreover, they are not aligned correctly */
231 store4_little_endian(unsigned char *cp, unsigned int val) {
232 cp[0] = (val & 0xff);
233 cp[1] = ((val >> 8) & 0xff);
234 cp[2] = ((val >> 16) & 0xff);
235 cp[3] = ((val >> 24) & 0xff);
239 read4_little_endian(unsigned char *cp) {
240 return (unsigned int)(cp[0]) + ((unsigned int)(cp[1]) << 8)
241 + ((unsigned int)(cp[2]) << 16)
242 + ((unsigned int)(cp[3]) << 24);
246 set_start_sect(struct partition *p, unsigned int start_sect) {
247 store4_little_endian(p->start4, start_sect);
251 get_start_sect(struct partition *p) {
252 return read4_little_endian(p->start4);
256 set_nr_sects(struct partition *p, unsigned int nr_sects) {
257 store4_little_endian(p->size4, nr_sects);
261 get_nr_sects(struct partition *p) {
262 return read4_little_endian(p->size4);
268 unsigned char align[ALIGNMENT];
269 unsigned char b[SECTOR_SIZE];
272 unsigned char align[ALIGNMENT];
273 unsigned char buffer[0x1BE];
274 struct partition part[4];
275 unsigned char magicflag[2];
280 long long first_sector; /* first sector in partition */
281 long long last_sector; /* last sector in partition */
282 long offset; /* offset from first sector to start of data */
283 int flags; /* active == 0x80 */
284 int id; /* filesystem type */
285 int num; /* number of partition -- primary vs. logical */
287 char volume_label[LABELSZ+1];
289 char ostype[OSTYPESZ+1];
291 char fstype[FSTYPESZ+1];
294 char *disk_device = DEFAULT_DEVICE;
299 int curses_started = 0;
301 partition_info p_info[MAXIMUM_PARTS];
302 partition_info ext_info;
306 long long logical_sectors[MAXIMUM_PARTS];
308 __sighandler_t old_SIGINT, old_SIGTERM;
310 int arrow_cursor = FALSE;
311 int display_units = MEGABYTES;
312 int zero_table = FALSE;
313 int use_partition_table_geometry = FALSE;
316 /* Curses screen information */
318 int warning_last_time = FALSE;
321 int NUM_ON_SCREEN = 1;
324 int HEADER_START = 0;
325 int DISK_TABLE_START = 6;
326 int WARNING_START = 23;
327 int COMMAND_LINE_Y = 21;
331 int FLAGS_START = 16;
332 int PTYPE_START = 28;
333 int FSTYPE_START = 38;
334 int LABEL_START = 54;
336 int COMMAND_LINE_X = 5;
338 static void die_x(int ret);
339 static void draw_screen(void);
341 /* Guaranteed alloc */
343 xmalloc (size_t size) {
351 fprintf (stderr, _("%s: Out of memory!\n"), "cfdisk");
357 /* Some libc's have their own basename() */
359 my_basename(char *devname) {
360 char *s = strrchr(devname, '/');
361 return s ? s+1 : devname;
365 partition_type_name(unsigned char type) {
366 struct systypes *s = i386_sys_types;
368 while(s->name && s->type != type)
374 partition_type_text(int i) {
375 if (p_info[i].id == UNUSABLE)
376 return _("Unusable");
377 else if (p_info[i].id == FREE_SPACE)
378 return _("Free Space");
379 else if (p_info[i].id == LINUX) {
380 if (!strcmp(p_info[i].fstype, "ext2"))
381 return _("Linux ext2");
382 else if (!strcmp(p_info[i].fstype, "ext3"))
383 return _("Linux ext3");
384 else if (!strcmp(p_info[i].fstype, "xfs"))
385 return _("Linux XFS");
386 else if (!strcmp(p_info[i].fstype, "jfs"))
387 return _("Linux JFS");
388 else if (!strcmp(p_info[i].fstype, "reiserfs"))
389 return _("Linux ReiserFS");
392 } else if (p_info[i].id == OS2_OR_NTFS) {
393 if (!strncmp(p_info[i].fstype, "HPFS", 4))
394 return _("OS/2 HPFS");
395 else if (!strncmp(p_info[i].ostype, "OS2", 3))
396 return _("OS/2 IFS");
397 else if (!p_info[i].ostype)
398 return p_info[i].ostype;
402 return _(partition_type_name(p_info[i].id));
411 fprintf(stderr, _("Disk has been changed.\n"));
413 fprintf(stderr, _("Reboot the system to ensure the partition "
414 "table is correctly updated.\n"));
417 fprintf( stderr, _("\nWARNING: If you have created or modified any\n"
418 "DOS 6.x partitions, please see the cfdisk manual\n"
419 "page for additional information.\n") );
426 get_string(char *str, int len, char *def) {
444 while ((c = getch()) != '\n' && c != CR) {
455 mvaddch(y, x+i, ' ');
457 } else if (use_def) {
464 if (i < len && isprint(c)) {
485 clear_warning(void) {
488 if (!curses_started || !warning_last_time)
491 move(WARNING_START,0);
492 for (i = 0; i < COLS; i++)
495 warning_last_time = FALSE;
499 print_warning(char *s) {
500 if (!curses_started) {
501 fprintf(stderr, "%s\n", s);
503 mvaddstr(WARNING_START, (COLS-strlen(s))/2, s);
504 putchar(BELL); /* CTRL-G */
506 warning_last_time = TRUE;
511 fatal(char *s, int ret) {
512 char *err1 = _("FATAL ERROR");
513 char *err2 = _("Press any key to exit cfdisk");
515 if (curses_started) {
516 char *str = xmalloc(strlen(s) + strlen(err1) + strlen(err2) + 10);
518 sprintf(str, "%s: %s", err1, s);
519 if (strlen(str) > COLS)
521 mvaddstr(WARNING_START, (COLS-strlen(str))/2, str);
522 sprintf(str, "%s", err2);
523 if (strlen(str) > COLS)
525 mvaddstr(WARNING_START+1, (COLS-strlen(str))/2, str);
526 putchar(BELL); /* CTRL-G */
531 fprintf(stderr, "%s: %s\n", err1, s);
543 signal(SIGINT, old_SIGINT);
544 signal(SIGTERM, old_SIGTERM);
545 #if defined(HAVE_SLCURSES_H) || defined(HAVE_SLANG_SLCURSES_H)
546 SLsmg_gotorc(LINES-1, 0);
549 mvcur(0, COLS-1, LINES-1, 0);
558 read_sector(unsigned char *buffer, long long sect_num) {
559 if (lseek(fd, sect_num*SECTOR_SIZE, SEEK_SET) < 0)
560 fatal(_("Cannot seek on disk drive"), 2);
561 if (read(fd, buffer, SECTOR_SIZE) != SECTOR_SIZE)
562 fatal(_("Cannot read disk drive"), 2);
566 write_sector(unsigned char *buffer, long long sect_num) {
567 if (lseek(fd, sect_num*SECTOR_SIZE, SEEK_SET) < 0)
568 fatal(_("Cannot seek on disk drive"), 2);
569 if (write(fd, buffer, SECTOR_SIZE) != SECTOR_SIZE)
570 fatal(_("Cannot write disk drive"), 2);
574 dos_copy_to_info(char *to, int tosz, char *from, int fromsz) {
577 for(i=0; i<tosz && i<fromsz && isascii(from[i]); i++)
583 get_dos_label(int i) {
585 #define DOS_OSTYPE_OFFSET 3
586 #define DOS_LABEL_OFFSET 43
587 #define DOS_FSTYPE_OFFSET 54
588 #define DOS_OSTYPE_SZ 8
589 #define DOS_LABEL_SZ 11
590 #define DOS_FSTYPE_SZ 8
593 offset = (p_info[i].first_sector + p_info[i].offset) * SECTOR_SIZE;
594 if (lseek(fd, offset, SEEK_SET) == offset
595 && read(fd, §or, sizeof(sector)) == sizeof(sector)) {
596 dos_copy_to_info(p_info[i].ostype, OSTYPESZ,
597 sector+DOS_OSTYPE_OFFSET, DOS_OSTYPE_SZ);
598 dos_copy_to_info(p_info[i].volume_label, LABELSZ,
599 sector+DOS_LABEL_OFFSET, DOS_LABEL_SZ);
600 dos_copy_to_info(p_info[i].fstype, FSTYPESZ,
601 sector+DOS_FSTYPE_OFFSET, DOS_FSTYPE_SZ);
605 #define REISERFS_SUPER_MAGIC_STRING "ReIsErFs"
606 #define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs"
607 struct reiserfs_super_block {
613 #define REISERFSLABELSZ sizeof(reiserfsb.s_label)
616 has_reiserfs_magic_string(const struct reiserfs_super_block *rs, int *is_3_6) {
617 if (!strncmp(rs->s_magic, REISERFS_SUPER_MAGIC_STRING,
618 strlen(REISERFS_SUPER_MAGIC_STRING))) {
622 if (!strncmp(rs->s_magic, REISER2FS_SUPER_MAGIC_STRING,
623 strlen(REISER2FS_SUPER_MAGIC_STRING))) {
631 get_linux_label(int i) {
633 #define EXT2LABELSZ 16
634 #define EXT2_SUPER_MAGIC 0xEF53
635 #define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
636 struct ext2_super_block {
638 unsigned char s_magic[2];
640 unsigned char s_feature_compat[4];
642 char s_volume_name[EXT2LABELSZ];
643 char s_last_mounted[64];
647 #define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024)
648 struct reiserfs_super_block reiserfsb;
651 #define JFS_SUPER1_OFF 0x8000
652 #define JFS_MAGIC "JFS1"
653 #define JFSLABELSZ 16
654 struct jfs_super_block {
661 char s_label[JFSLABELSZ];
664 #define XFS_SUPER_MAGIC "XFSB"
665 #define XFSLABELSZ 12
666 struct xfs_super_block {
667 unsigned char s_magic[4];
668 unsigned char s_dummy0[104];
669 unsigned char s_fname[XFSLABELSZ];
670 unsigned char s_dummy1[904];
677 offset = (p_info[i].first_sector + p_info[i].offset) * SECTOR_SIZE
679 if (lseek(fd, offset, SEEK_SET) == offset
680 && read(fd, &e2fsb, sizeof(e2fsb)) == sizeof(e2fsb)
681 && e2fsb.s_magic[0] + (e2fsb.s_magic[1]<<8) == EXT2_SUPER_MAGIC) {
682 label = e2fsb.s_volume_name;
683 for(j=0; j<EXT2LABELSZ && j<LABELSZ && isprint(label[j]); j++)
684 p_info[i].volume_label[j] = label[j];
685 p_info[i].volume_label[j] = 0;
687 if (e2fsb.s_feature_compat[0]&EXT3_FEATURE_COMPAT_HAS_JOURNAL)
688 strncpy(p_info[i].fstype, "ext3", FSTYPESZ);
690 strncpy(p_info[i].fstype, "ext2", FSTYPESZ);
694 offset = (p_info[i].first_sector + p_info[i].offset) * SECTOR_SIZE + 0;
695 if (lseek(fd, offset, SEEK_SET) == offset
696 && read(fd, &xfsb, sizeof(xfsb)) == sizeof(xfsb)
697 && !strncmp((char *) xfsb.s_magic, XFS_SUPER_MAGIC, 4)) {
698 label = (char *) xfsb.s_fname;
699 for(j=0; j<XFSLABELSZ && j<LABELSZ && isprint(label[j]); j++)
700 p_info[i].volume_label[j] = label[j];
701 p_info[i].volume_label[j] = 0;
702 strncpy(p_info[i].fstype, "xfs", FSTYPESZ);
707 offset = (p_info[i].first_sector + p_info[i].offset) * SECTOR_SIZE
709 if (lseek(fd, offset, SEEK_SET) == offset
710 && read(fd, &jfsb, sizeof(jfsb)) == sizeof(jfsb)
711 && !strncmp(jfsb.s_magic, JFS_MAGIC, strlen(JFS_MAGIC))) {
712 label = jfsb.s_label;
713 for(j=0; j<JFSLABELSZ && j<LABELSZ && isprint(label[j]); j++)
714 p_info[i].volume_label[j] = label[j];
715 p_info[i].volume_label[j] = 0;
716 strncpy(p_info[i].fstype, "jfs", FSTYPESZ);
721 offset = (p_info[i].first_sector + p_info[i].offset) * SECTOR_SIZE
722 + REISERFS_DISK_OFFSET_IN_BYTES;
723 if (lseek(fd, offset, SEEK_SET) == offset
724 && read(fd, &reiserfsb, sizeof(reiserfsb)) == sizeof(reiserfsb)
725 && has_reiserfs_magic_string(&reiserfsb, &reiserfs_is_3_6)) {
726 if (reiserfs_is_3_6) {
727 /* label only on version 3.6 onward */
728 label = (char *) reiserfsb.s_label;
729 for(j=0; j<REISERFSLABELSZ && j<LABELSZ &&
730 isprint(label[j]); j++)
731 p_info[i].volume_label[j] = label[j];
732 p_info[i].volume_label[j] = 0;
734 strncpy(p_info[i].fstype, "reiserfs", FSTYPESZ);
740 check_part_info(void) {
741 int i, pri = 0, log = 0;
743 for (i = 0; i < num_parts; i++)
744 if (p_info[i].id > 0 && IS_PRIMARY(p_info[i].num))
746 else if (p_info[i].id > 0 && IS_LOGICAL(p_info[i].num))
748 if (is_extended(ext_info.id)) {
752 ext_info.first_sector = 0;
753 ext_info.last_sector = 0;
756 ext_info.id = FREE_SPACE;
757 ext_info.num = PRIMARY;
762 for (i = 0; i < num_parts; i++)
763 if (p_info[i].id == FREE_SPACE || p_info[i].id == UNUSABLE) {
764 if (is_extended(ext_info.id)) {
765 if (p_info[i].first_sector >= ext_info.first_sector &&
766 p_info[i].last_sector <= ext_info.last_sector) {
767 p_info[i].id = FREE_SPACE;
768 p_info[i].num = LOGICAL;
770 p_info[i-1].first_sector >=
771 ext_info.first_sector &&
772 p_info[i-1].last_sector <=
773 ext_info.last_sector) {
774 p_info[i].id = FREE_SPACE;
775 p_info[i].num = LOGICAL;
776 } else if (i < num_parts-1 &&
777 p_info[i+1].first_sector >=
778 ext_info.first_sector &&
779 p_info[i+1].last_sector <=
780 ext_info.last_sector) {
781 p_info[i].id = FREE_SPACE;
782 p_info[i].num = LOGICAL;
784 p_info[i].id = UNUSABLE;
785 } else /* if (!is_extended(ext_info.id)) */
786 p_info[i].id = UNUSABLE;
787 } else /* if (p_info[i].id > 0) */
788 while (0); /* Leave these alone */
789 } else { /* if (pri < 4) */
790 for (i = 0; i < num_parts; i++) {
791 if (p_info[i].id == UNUSABLE)
792 p_info[i].id = FREE_SPACE;
793 if (p_info[i].id == FREE_SPACE) {
794 if (is_extended(ext_info.id)) {
795 if (p_info[i].first_sector >= ext_info.first_sector &&
796 p_info[i].last_sector <= ext_info.last_sector)
797 p_info[i].num = LOGICAL;
799 p_info[i-1].first_sector >=
800 ext_info.first_sector &&
801 p_info[i-1].last_sector <=
802 ext_info.last_sector)
803 p_info[i].num = PRI_OR_LOG;
804 else if (i < num_parts-1 &&
805 p_info[i+1].first_sector >=
806 ext_info.first_sector &&
807 p_info[i+1].last_sector <=
808 ext_info.last_sector)
809 p_info[i].num = PRI_OR_LOG;
811 p_info[i].num = PRIMARY;
812 } else /* if (!is_extended(ext_info.id)) */
813 p_info[i].num = PRI_OR_LOG;
814 } else /* if (p_info[i].id > 0) */
815 while (0); /* Leave these alone */
824 for (p = i; p < num_parts; p++)
825 p_info[p] = p_info[p+1];
828 if (cur_part == num_parts)
833 insert_empty_part(int i, long long first, long long last) {
836 for (p = num_parts; p > i; p--)
837 p_info[p] = p_info[p-1];
839 p_info[i].first_sector = first;
840 p_info[i].last_sector = last;
841 p_info[i].offset = 0;
843 p_info[i].id = FREE_SPACE;
844 p_info[i].num = PRI_OR_LOG;
845 p_info[i].volume_label[0] = 0;
846 p_info[i].fstype[0] = 0;
847 p_info[i].ostype[0] = 0;
854 int num = p_info[i].num;
856 if (i > 0 && (p_info[i-1].id == FREE_SPACE ||
857 p_info[i-1].id == UNUSABLE)) {
858 /* Merge with previous partition */
859 p_info[i-1].last_sector = p_info[i].last_sector;
863 if (i < num_parts - 1 && (p_info[i+1].id == FREE_SPACE ||
864 p_info[i+1].id == UNUSABLE)) {
865 /* Merge with next partition */
866 p_info[i+1].first_sector = p_info[i].first_sector;
871 p_info[i].first_sector = p_info[i-1].last_sector + 1;
873 p_info[i].first_sector = 0;
875 if (i < num_parts - 1)
876 p_info[i].last_sector = p_info[i+1].first_sector - 1;
878 p_info[i].last_sector = total_size - 1;
880 p_info[i].offset = 0;
882 p_info[i].id = FREE_SPACE;
883 p_info[i].num = PRI_OR_LOG;
885 if (IS_LOGICAL(num)) {
886 /* We have a logical partition --> shrink the extended partition
887 * if (1) this is the first logical drive, or (2) this is the
888 * last logical drive; and if there are any other logical drives
889 * then renumber the ones after "num".
891 if (i == 0 || (i > 0 && IS_PRIMARY(p_info[i-1].num))) {
892 ext_info.first_sector = p_info[i].last_sector + 1;
895 if (i == num_parts-1 ||
896 (i < num_parts-1 && IS_PRIMARY(p_info[i+1].num)))
897 ext_info.last_sector = p_info[i].first_sector - 1;
898 for (i = 0; i < num_parts; i++)
899 if (p_info[i].num > num)
903 /* Clean up the rest of the partitions */
908 add_part(int num, int id, int flags, long long first, long long last,
909 long long offset, int want_label, char **errmsg) {
910 int i, pri = 0, log = 0;
912 if (num_parts == MAXIMUM_PARTS) {
913 *errmsg = _("Too many partitions");
918 *errmsg = _("Partition begins before sector 0");
923 *errmsg = _("Partition ends before sector 0");
927 if (first >= total_size) {
928 *errmsg = _("Partition begins after end-of-disk");
932 if (last >= actual_size) {
933 *errmsg = _("Partition ends after end-of-disk");
937 if (last >= total_size) {
938 *errmsg = _("Partition ends in the final partial cylinder");
942 for (i = 0; i < num_parts; i++) {
943 if (p_info[i].id > 0 && IS_PRIMARY(p_info[i].num))
945 else if (p_info[i].id > 0 && IS_LOGICAL(p_info[i].num))
948 if (is_extended(ext_info.id) && log > 0)
951 if (IS_PRIMARY(num)) {
953 return -1; /* no room for more */
958 for (i = 0; i < num_parts && p_info[i].last_sector < first; i++);
960 if (i < num_parts && p_info[i].id != FREE_SPACE) {
961 if (last < p_info[i].first_sector)
962 *errmsg = _("logical partitions not in disk order");
963 else if (first + offset <= p_info[i].last_sector &&
964 p_info[i].first_sector + p_info[i].offset <= last)
965 *errmsg = _("logical partitions overlap");
967 /* the enlarged logical partition starts at the
968 partition table sector that defines it */
969 *errmsg = _("enlarged logical partitions overlap");
973 if (i == num_parts || last > p_info[i].last_sector) {
977 if (is_extended(id)) {
978 if (ext_info.id != FREE_SPACE) {
979 return -1; /* second extended */
981 else if (IS_PRIMARY(num)) {
982 ext_info.first_sector = first;
983 ext_info.last_sector = last;
984 ext_info.offset = offset;
985 ext_info.flags = flags;
988 ext_info.volume_label[0] = 0;
989 ext_info.fstype[0] = 0;
990 ext_info.ostype[0] = 0;
993 return -1; /* explicit extended logical */
997 if (IS_LOGICAL(num)) {
998 if (!is_extended(ext_info.id)) {
999 print_warning(_("!!!! Internal error creating logical "
1000 "drive with no extended partition !!!!"));
1002 /* We might have a logical partition outside of the extended
1003 * partition's range --> we have to extend the extended
1004 * partition's range to encompass this new partition, but we
1005 * must make sure that there are no primary partitions between
1006 * it and the closest logical drive in extended partition.
1008 if (first < ext_info.first_sector) {
1009 if (i < num_parts-1 && IS_PRIMARY(p_info[i+1].num)) {
1010 print_warning(_("Cannot create logical drive here -- would create two extended partitions"));
1014 ext_info.first_sector = 0;
1015 ext_info.offset = first = offset;
1017 ext_info.first_sector = first;
1020 } else if (last > ext_info.last_sector) {
1021 if (i > 0 && IS_PRIMARY(p_info[i-1].num)) {
1022 print_warning(_("Cannot create logical drive here -- would create two extended partitions"));
1025 ext_info.last_sector = last;
1031 if (first != p_info[i].first_sector &&
1032 !(IS_LOGICAL(num) && first == offset)) {
1033 insert_empty_part(i, p_info[i].first_sector, first-1);
1037 if (last != p_info[i].last_sector)
1038 insert_empty_part(i+1, last+1, p_info[i].last_sector);
1040 p_info[i].first_sector = first;
1041 p_info[i].last_sector = last;
1042 p_info[i].offset = offset;
1043 p_info[i].flags = flags;
1045 p_info[i].num = num;
1046 p_info[i].volume_label[0] = 0;
1047 p_info[i].fstype[0] = 0;
1048 p_info[i].ostype[0] = 0;
1050 if (may_have_dos_label(id))
1052 else if (id == LINUX)
1062 find_primary(void) {
1063 int num = 0, cur = 0;
1065 while (cur < num_parts && IS_PRIMARY(num))
1066 if ((p_info[cur].id > 0 && p_info[cur].num == num) ||
1067 (is_extended(ext_info.id) && ext_info.num == num)) {
1073 if (!IS_PRIMARY(num))
1080 find_logical(int i) {
1084 for (j = i; j < num_parts && num == -1; j++)
1085 if (p_info[j].id > 0 && IS_LOGICAL(p_info[j].num))
1086 num = p_info[j].num;
1090 for (j = 0; j < num_parts; j++)
1091 if (p_info[j].id > 0 && p_info[j].num == num)
1099 * Command menu support by Janne Kukonlehto <jtklehto@phoenix.oulu.fi>
1103 /* Constants for menuType parameter of menuSelect function */
1104 #define MENU_HORIZ 1
1106 #define MENU_ACCEPT_OTHERS 4
1107 #define MENU_BUTTON 8
1108 /* Miscellenous constants */
1109 #define MENU_SPACING 2
1110 #define MENU_MAX_ITEMS 256 /* for simpleMenu function */
1113 #define MENU_RIGHT 3
1118 int key; /* Keyboard shortcut; if zero, then there is no more items in the menu item table */
1119 char *name; /* Item name, should be eight characters with current implementation */
1120 char *desc; /* Item description to be printed when item is selected */
1124 * Actual function which prints the button bar and highlights the active button
1125 * Should not be called directly. Call function menuSelect instead.
1129 menuUpdate( int y, int x, struct MenuItem *menuItems, int itemLength,
1130 char *available, int menuType, int current ) {
1131 int i, lmargin = x, ymargin = y;
1134 /* Print available buttons */
1135 move( y, x ); clrtoeol();
1137 for( i = 0; menuItems[i].key; i++ ) {
1142 /* Search next available button */
1143 while( menuItems[i].key && !strchr(available, menuItems[i].key) )
1146 if( !menuItems[i].key ) break; /* No more menu items */
1148 /* If selected item is not available and we have bypassed it,
1149 make current item selected */
1150 if( current < i && menuItems[current].key < 0 ) current = i;
1152 /* If current item is selected, highlight it */
1153 if( current == i ) /*attron( A_REVERSE )*/ standout ();
1156 /* Because of a bug in gettext() we must not translate empty strings */
1157 if (menuItems[i].name[0])
1158 mi = _(menuItems[i].name);
1161 lenName = strlen( mi );
1163 if(lenName > itemLength || lenName >= sizeof(buff))
1164 print_warning(_("Menu item too long. Menu may look odd."));
1166 if (lenName >= sizeof(buff)) { /* truncate ridiculously long string */
1167 xstrncpy(buff, mi, sizeof(buff));
1168 } else if (lenName >= itemLength) {
1169 snprintf(buff, sizeof(buff),
1170 (menuType & MENU_BUTTON) ? "[%s]" : "%s", mi);
1172 snprintf(buff, sizeof(buff),
1173 (menuType & MENU_BUTTON) ? "[%*s%-*s]" : "%*s%-*s",
1174 (itemLength - lenName) / 2, "",
1175 (itemLength - lenName + 1) / 2 + lenName, mi);
1177 mvaddstr( y, x, buff );
1179 /* Lowlight after selected item */
1180 if( current == i ) /*attroff( A_REVERSE )*/ standend ();
1182 /* Calculate position for the next item */
1183 if( menuType & MENU_VERT )
1186 if( y >= WARNING_START )
1189 x += itemLength + MENU_SPACING;
1190 if( menuType & MENU_BUTTON ) x += 2;
1195 x += itemLength + MENU_SPACING;
1196 if( menuType & MENU_BUTTON ) x += 2;
1197 if( x > COLUMNS - lmargin - 12 )
1205 /* Print the description of selected item */
1206 mcd = _(menuItems[current].desc);
1207 mvaddstr( WARNING_START + 1, (COLUMNS - strlen( mcd )) / 2, mcd );
1211 /* This function takes a list of menu items, lets the user choose one *
1212 * and returns the keyboard shortcut value of the selected menu item */
1215 menuSelect( int y, int x, struct MenuItem *menuItems, int itemLength,
1216 char *available, int menuType, int menuDefault ) {
1217 int i, ylast = y, key = 0, current = menuDefault;
1219 if( !( menuType & ( MENU_HORIZ | MENU_VERT ) ) ) {
1220 print_warning(_("Menu without direction. Defaulting to horizontal."));
1221 menuType |= MENU_HORIZ;
1224 /* Make sure that the current is one of the available items */
1225 while( !strchr(available, menuItems[current].key) ) {
1227 if( !menuItems[current].key ) current = 0;
1230 /* Repeat until allowable choice has been made */
1232 /* Display the menu and read a command */
1233 ylast = menuUpdate( y, x, menuItems, itemLength, available,
1234 menuType, current );
1238 /* Clear out all prompts and such */
1240 for (i = y; i < ylast; i++) {
1244 move( WARNING_START + 1, 0 );
1247 /* Cursor keys - possibly split by slow connection */
1249 /* Check whether this is a real ESC or one of extended keys */
1250 /*nodelay(stdscr, TRUE);*/
1252 /*nodelay(stdscr, FALSE);*/
1254 if( key == /*ERR*/ ESC ) {
1255 /* This is a real ESC */
1258 if(key == '[' || key == 'O') {
1259 /* This is one extended keys */
1263 case 'A': /* Up arrow */
1266 case 'B': /* Down arrow */
1269 case 'C': /* Right arrow */
1272 case 'D': /* Left arrow */
1281 /* Enter equals the keyboard shortcut of current menu item */
1283 key = menuItems[current].key;
1285 /* Give alternatives for arrow keys in case the window manager
1289 if (key == UPKEY) /* ^P */
1291 if (key == DOWNKEY) /* ^N */
1294 if (key == MENU_UP) {
1295 if( menuType & MENU_VERT ) {
1299 while( menuItems[current+1].key )
1301 } while( !strchr( available, menuItems[current].key ));
1306 if (key == MENU_DOWN) {
1307 if( menuType & MENU_VERT ) {
1310 if( !menuItems[current].key ) current = 0 ;
1311 } while( !strchr( available, menuItems[current].key ));
1316 if (key == MENU_RIGHT) {
1317 if( menuType & MENU_HORIZ ) {
1320 if( !menuItems[current].key )
1322 } while( !strchr( available, menuItems[current].key ));
1327 if (key == MENU_LEFT) {
1328 if( menuType & MENU_HORIZ ) {
1332 while( menuItems[current + 1].key )
1335 } while( !strchr( available, menuItems[current].key ));
1340 /* Should all keys to be accepted? */
1341 if( key && (menuType & MENU_ACCEPT_OTHERS) ) break;
1343 /* Is pressed key among acceptable ones? */
1344 if( key && (strchr(available, tolower(key)) || strchr(available, key)))
1347 /* The key has not been accepted so far -> let's reject it */
1351 print_warning(_("Illegal key"));
1355 /* Clear out prompts and such */
1357 for( i = y; i <= ylast; i ++ ) {
1361 move( WARNING_START + 1, 0 );
1366 /* A function which displays "Press a key to continue" *
1367 * and waits for a keypress. *
1368 * Perhaps calling function menuSelect is a bit overkill but who cares? */
1371 menuContinue(void) {
1372 static struct MenuItem menuContinueBtn[]=
1374 { 'c', "", N_("Press a key to continue") },
1378 menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X,
1379 menuContinueBtn, 0, "c", MENU_HORIZ | MENU_ACCEPT_OTHERS, 0 );
1382 /* Function menuSelect takes way too many parameters *
1383 * Luckily, most of time we can do with this function */
1386 menuSimple(struct MenuItem *menuItems, int menuDefault) {
1387 int i, j, itemLength = 0;
1388 char available[MENU_MAX_ITEMS];
1390 for(i = 0; menuItems[i].key; i++)
1392 j = strlen( _(menuItems[i].name) );
1393 if( j > itemLength ) itemLength = j;
1394 available[i] = menuItems[i].key;
1397 return menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuItems, itemLength,
1398 available, MENU_HORIZ | MENU_BUTTON, menuDefault);
1401 /* End of command menu support code */
1405 char response[LINE_LENGTH], def[LINE_LENGTH];
1407 long long first = p_info[i].first_sector;
1408 long long last = p_info[i].last_sector;
1409 long long offset = 0;
1413 long long num_sects = last - first + 1;
1416 double sectors_per_MB = K*K / 512.0;
1418 if (p_info[i].num == PRI_OR_LOG) {
1419 static struct MenuItem menuPartType[]=
1421 { 'p', N_("Primary"), N_("Create a new primary partition") },
1422 { 'l', N_("Logical"), N_("Create a new logical partition") },
1423 { ESC, N_("Cancel"), N_("Don't create a partition") },
1427 c = menuSimple( menuPartType, 0 );
1428 if (toupper(c) == 'P')
1429 num = find_primary();
1430 else if (toupper(c) == 'L')
1431 num = find_logical(i);
1434 } else if (p_info[i].num == PRIMARY)
1435 num = find_primary();
1436 else if (p_info[i].num == LOGICAL)
1437 num = find_logical(i);
1439 print_warning(_("!!! Internal error !!!"));
1441 snprintf(def, sizeof(def), "%.2f", num_sects/sectors_per_MB);
1442 mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, _("Size (in MB): "));
1443 if ((len = get_string(response, LINE_LENGTH, def)) <= 0 &&
1447 #define num_cyls(bytes) (round_int(bytes/SECTOR_SIZE/cylinder_size))
1449 j < len-1 && (isdigit(response[j]) || response[j] == '.');
1451 if (toupper(response[j]) == 'K') {
1452 num_sects = num_cyls(atof(response)*K)*cylinder_size;
1453 } else if (toupper(response[j]) == 'M') {
1454 num_sects = num_cyls(atof(response)*K*K)*cylinder_size;
1455 } else if (toupper(response[j]) == 'G') {
1456 num_sects = num_cyls(atof(response)*K*K*K)*cylinder_size;
1457 } else if (toupper(response[j]) == 'C') {
1458 num_sects = round_int(atof(response))*cylinder_size;
1459 } else if (toupper(response[j]) == 'S') {
1460 num_sects = round_int(atof(response));
1462 num_sects = num_cyls(atof(response)*K*K)*cylinder_size;
1466 if (num_sects <= 0 ||
1467 num_sects > p_info[i].last_sector - p_info[i].first_sector + 1)
1470 move( COMMAND_LINE_Y, COMMAND_LINE_X ); clrtoeol();
1471 if (num_sects < p_info[i].last_sector - p_info[i].first_sector + 1) {
1472 /* Determine where inside free space to put partition.
1474 static struct MenuItem menuPlace[]=
1476 { 'b', N_("Beginning"), N_("Add partition at beginning of free space") },
1477 { 'e', N_("End"), N_("Add partition at end of free space") },
1478 { ESC, N_("Cancel"), N_("Don't create a partition") },
1481 c = menuSimple( menuPlace, 0 );
1482 if (toupper(c) == 'B')
1483 last = first + num_sects - 1;
1484 else if (toupper(c) == 'E')
1485 first = last - num_sects + 1;
1490 if (IS_LOGICAL(num) && !is_extended(ext_info.id)) {
1491 /* We want to add a logical partition, but need to create an
1492 * extended partition first.
1494 if ((ext = find_primary()) < 0) {
1495 print_warning(_("No room to create the extended partition"));
1499 if (add_part(ext, DOS_EXTENDED, 0, first, last,
1500 (first == 0 ? sectors : 0), 0, &errmsg) && errmsg)
1501 print_warning(errmsg);
1502 first = ext_info.first_sector + ext_info.offset;
1505 /* increment number of all partitions past this one */
1506 if (IS_LOGICAL(num)) {
1508 /* original text - ok, but fails when partitions not in disk order */
1509 for (j = i; j < num_parts; j++)
1510 if (p_info[j].id > 0 && IS_LOGICAL(p_info[j].num))
1514 for (j = 0; j < num_parts; j++)
1515 if (p_info[j].id > 0 && p_info[j].num >= num)
1520 /* Now we have a complete partition to ourselves */
1521 if (first == 0 || IS_LOGICAL(num))
1525 if (add_part(num, id, flags, first, last, offset, 0, &errmsg) && errmsg)
1526 print_warning(errmsg);
1530 get_kernel_geometry(void) {
1532 struct hd_geometry geometry;
1534 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
1535 kern_heads = geometry.heads;
1536 kern_sectors = geometry.sectors;
1542 said_yes(char answer) {
1549 yn = rpmatch(reply); /* 1: yes, 0: no, -1: ? */
1553 return (answer == 'y' || answer == 'Y');
1557 get_partition_table_geometry(partition_table *bufp) {
1558 struct partition *p;
1563 for (i=0; i<66; i++)
1564 if (bufp->c.b[446+i])
1568 if (!curses_started) {
1569 fatal(_("No partition table.\n"), 3);
1572 mvaddstr(WARNING_START, 0,
1573 _("No partition table. Starting with zero table."));
1580 if (bufp->p.magicflag[0] != PART_TABLE_FLAG0 ||
1581 bufp->p.magicflag[1] != PART_TABLE_FLAG1) {
1582 if (!curses_started)
1583 fatal(_("Bad signature on partition table"), 3);
1585 /* Matthew Wilcox */
1586 mvaddstr(WARNING_START, 0,
1587 _("Unknown partition table type"));
1588 mvaddstr(WARNING_START+1, 0,
1589 _("Do you wish to start with a zero table [y/N] ?"));
1594 if (cont == EOF || !said_yes(cont))
1602 for (i=0; i<4; i++) {
1603 p = &(bufp->p.part[i]);
1604 if (p->sys_ind != 0) {
1605 h = p->end_head + 1;
1606 s = (p->end_sector & 077);
1611 } else if (hh != h || ss != s)
1616 if (!first && !bad) {
1623 decide_on_geometry(void) {
1624 heads = (user_heads ? user_heads :
1625 pt_heads ? pt_heads :
1626 kern_heads ? kern_heads : 255);
1627 sectors = (user_sectors ? user_sectors :
1628 pt_sectors ? pt_sectors :
1629 kern_sectors ? kern_sectors : 63);
1630 cylinder_size = heads*sectors;
1631 cylinders = actual_size/cylinder_size;
1632 if (user_cylinders > 0)
1633 cylinders = user_cylinders;
1635 total_size = cylinder_size*cylinders;
1636 if (total_size > actual_size)
1637 print_warning(_("You specified more cylinders than fit on disk"));
1641 clear_p_info(void) {
1643 p_info[0].first_sector = 0;
1644 p_info[0].last_sector = total_size - 1;
1645 p_info[0].offset = 0;
1646 p_info[0].flags = 0;
1647 p_info[0].id = FREE_SPACE;
1648 p_info[0].num = PRI_OR_LOG;
1650 ext_info.first_sector = 0;
1651 ext_info.last_sector = 0;
1652 ext_info.offset = 0;
1654 ext_info.id = FREE_SPACE;
1655 ext_info.num = PRIMARY;
1662 unsigned long long llsectors;
1663 struct partition *p;
1664 partition_table buffer;
1665 partition_info tmp_ext = { 0, 0, 0, 0, FREE_SPACE, PRIMARY };
1667 if ((fd = open(disk_device, O_RDWR)) < 0) {
1668 if ((fd = open(disk_device, O_RDONLY)) < 0)
1669 fatal(_("Cannot open disk drive"), 2);
1670 opentype = O_RDONLY;
1671 print_warning(_("Opened disk read-only - you have no permission to write"));
1672 if (curses_started) {
1681 if (gpt_probe_signature_fd(fd)) {
1682 print_warning(_("Warning!! Unsupported GPT (GUID Partition Table) detected. Use GNU Parted."));
1689 /* Blocks are visible in more than one way:
1690 e.g. as block on /dev/hda and as block on /dev/hda3
1691 By a bug in the Linux buffer cache, we will see the old
1692 contents of /dev/hda when the change was made to /dev/hda3.
1693 In order to avoid this, discard all blocks on /dev/hda.
1694 Note that partition table blocks do not live in /dev/hdaN,
1695 so this only plays a role if we want to show volume labels. */
1696 ioctl(fd, BLKFLSBUF); /* ignore errors */
1697 /* e.g. Permission Denied */
1700 if (blkdev_get_sectors(fd, &llsectors) == -1)
1701 fatal(_("Cannot get disk size"), 3);
1702 actual_size = llsectors;
1704 read_sector(buffer.c.b, 0);
1706 get_kernel_geometry();
1708 if (!zero_table || use_partition_table_geometry)
1709 get_partition_table_geometry(& buffer);
1711 decide_on_geometry();
1718 for (i = 0; i < 4; i++) {
1719 p = & buffer.p.part[i];
1720 bs = get_start_sect(p);
1721 bsz = get_nr_sects(p);
1723 if (p->sys_ind > 0 &&
1724 add_part(i, p->sys_ind, p->boot_ind,
1725 ((bs <= sectors) ? 0 : bs), bs + bsz - 1,
1726 ((bs <= sectors) ? bs : 0), 1, &errmsg)) {
1727 char *bad = _("Bad primary partition");
1728 char *msg = (char *) xmalloc(strlen(bad) + strlen(errmsg) + 30);
1729 sprintf(msg, "%s %d: %s", bad, i, errmsg);
1732 if (is_extended(buffer.p.part[i].sys_ind))
1736 if (is_extended(tmp_ext.id)) {
1738 logical_sectors[logical] =
1739 ext_info.first_sector + ext_info.offset;
1740 read_sector(buffer.c.b, logical_sectors[logical++]);
1744 pn < 4 && (!buffer.p.part[pn].sys_ind ||
1745 is_extended(buffer.p.part[pn].sys_ind));
1749 p = & buffer.p.part[pn];
1750 bs = get_start_sect(p);
1751 bsz = get_nr_sects(p);
1753 if (add_part(i++, p->sys_ind, p->boot_ind,
1754 logical_sectors[logical-1],
1755 logical_sectors[logical-1] + bs + bsz - 1,
1757 char *bad = _("Bad logical partition");
1758 char *msg = (char *) xmalloc(strlen(bad) + strlen(errmsg) + 30);
1759 sprintf(msg, "%s %d: %s", bad, i, errmsg);
1765 pn < 4 && !is_extended(buffer.p.part[pn].sys_ind);
1768 p = & buffer.p.part[pn];
1769 bs = get_start_sect(p);
1770 logical_sectors[logical] = ext_info.first_sector
1771 + ext_info.offset + bs;
1772 read_sector(buffer.c.b, logical_sectors[logical++]);
1774 } while (pn < 4 && logical < MAXIMUM_PARTS-4);
1780 fill_part_table(struct partition *p, partition_info *pi) {
1783 p->boot_ind = pi->flags;
1784 p->sys_ind = pi->id;
1785 begin = pi->first_sector + pi->offset;
1786 if (IS_LOGICAL(pi->num))
1787 set_start_sect(p,pi->offset);
1789 set_start_sect(p,begin);
1790 set_nr_sects(p, pi->last_sector - begin + 1);
1791 set_hsc_begin(p, begin);
1792 set_hsc_end(p, pi->last_sector);
1796 fill_primary_table(partition_table *buffer) {
1799 /* Zero out existing table */
1800 for (i = 0x1BE; i < SECTOR_SIZE; i++)
1803 for (i = 0; i < num_parts; i++)
1804 if (IS_PRIMARY(p_info[i].num))
1805 fill_part_table(&(buffer->p.part[p_info[i].num]), &(p_info[i]));
1807 if (is_extended(ext_info.id))
1808 fill_part_table(&(buffer->p.part[ext_info.num]), &ext_info);
1810 buffer->p.magicflag[0] = PART_TABLE_FLAG0;
1811 buffer->p.magicflag[1] = PART_TABLE_FLAG1;
1815 fill_logical_table(partition_table *buffer, partition_info *pi) {
1816 struct partition *p;
1819 for (i = 0; i < logical && pi->first_sector != logical_sectors[i]; i++);
1820 if (i == logical || buffer->p.magicflag[0] != PART_TABLE_FLAG0
1821 || buffer->p.magicflag[1] != PART_TABLE_FLAG1)
1822 for (i = 0; i < SECTOR_SIZE; i++)
1825 /* Zero out existing table */
1826 for (i = 0x1BE; i < SECTOR_SIZE; i++)
1829 fill_part_table(&(buffer->p.part[0]), pi);
1832 i < num_parts && pi->num != p_info[i].num - 1;
1835 if (i < num_parts) {
1836 p = &(buffer->p.part[1]);
1840 p->sys_ind = DOS_EXTENDED;
1841 set_start_sect(p, pi->first_sector - ext_info.first_sector - ext_info.offset);
1842 set_nr_sects(p, pi->last_sector - pi->first_sector + 1);
1843 set_hsc_begin(p, pi->first_sector);
1844 set_hsc_end(p, pi->last_sector);
1847 buffer->p.magicflag[0] = PART_TABLE_FLAG0;
1848 buffer->p.magicflag[1] = PART_TABLE_FLAG1;
1852 write_part_table(void) {
1853 int i, ct, done = FALSE, len;
1854 partition_table buffer;
1857 char response[LINE_LENGTH];
1859 if (opentype == O_RDONLY) {
1860 print_warning(_("Opened disk read-only - you have no permission to write"));
1868 if(fstat(fd, &s) == 0 && S_ISBLK(s.st_mode))
1872 print_warning(_("Warning!! This may destroy data on your disk!"));
1875 mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X,
1876 _("Are you sure you want to write the partition table "
1877 "to disk? (yes or no): "));
1878 len = get_string(response, LINE_LENGTH, NULL);
1880 if (len == GS_ESCAPE)
1882 else if (strcasecmp(response, _("no")) == 0 ||
1883 strcasecmp(response, "no") == 0) {
1884 print_warning(_("Did not write partition table to disk"));
1886 } else if (strcasecmp(response, _("yes")) == 0 ||
1887 strcasecmp(response, "yes") == 0)
1890 print_warning(_("Please enter `yes' or `no'"));
1894 print_warning(_("Writing partition table to disk..."));
1898 read_sector(buffer.c.b, 0);
1899 fill_primary_table(&buffer);
1900 write_sector(buffer.c.b, 0);
1902 for (i = 0; i < num_parts; i++)
1903 if (IS_LOGICAL(p_info[i].num)) {
1904 read_sector(buffer.c.b, p_info[i].first_sector);
1905 fill_logical_table(&buffer, &(p_info[i]));
1906 write_sector(buffer.c.b, p_info[i].first_sector);
1913 if (!ioctl(fd,BLKRRPART))
1921 print_warning(_("Wrote partition table to disk"));
1923 print_warning(_("Wrote partition table, but re-read table failed. Run partprobe(8), kpartx(8) or reboot to update table."));
1925 print_warning(_("Wrote partition table to disk"));
1927 /* Check: unique bootable primary partition? */
1929 for (i = 0; i < num_parts; i++)
1930 if (IS_PRIMARY(i) && p_info[i].flags == ACTIVE_FLAG)
1933 print_warning(_("No primary partitions are marked bootable. DOS MBR cannot boot this."));
1935 print_warning(_("More than one primary partition is marked bootable. DOS MBR cannot boot this."));
1939 fp_printf(FILE *fp, char *format, ...) {
1944 va_start(args, format);
1945 vsnprintf(buf, sizeof(buf), format, args);
1949 /* The following works best if the string to be printed has at
1950 most only one newline. */
1952 getyx(stdscr, y, x);
1953 if (y >= COMMAND_LINE_Y-2) {
1959 fprintf(fp, "%s", buf);
1962 #define MAX_PER_LINE 16
1964 print_file_buffer(FILE *fp, unsigned char *buffer) {
1967 for (i = 0, l = 0; i < SECTOR_SIZE; i++, l++) {
1969 fp_printf(fp, "0x%03X:", i);
1970 fp_printf(fp, " %02X", buffer[i]);
1971 if (l == MAX_PER_LINE - 1) {
1972 fp_printf(fp, "\n");
1977 fp_printf(fp, "\n");
1978 fp_printf(fp, "\n");
1982 print_raw_table(void) {
1984 partition_table buffer;
1985 char fname[LINE_LENGTH];
1992 mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X,
1993 _("Enter filename or press RETURN to display on screen: "));
1995 if ((to_file = get_string(fname, LINE_LENGTH, NULL)) < 0)
1999 if ((fp = fopen(fname, "w")) == NULL) {
2000 char errstr[LINE_LENGTH];
2001 snprintf(errstr, sizeof(errstr),
2002 _("Cannot open file '%s'"), fname);
2003 print_warning(errstr);
2013 fp_printf(fp, _("Disk Drive: %s\n"), disk_device);
2015 fp_printf(fp, _("Sector 0:\n"));
2016 read_sector(buffer.c.b, 0);
2017 fill_primary_table(&buffer);
2018 print_file_buffer(fp, buffer.c.b);
2020 for (i = 0; i < num_parts; i++)
2021 if (IS_LOGICAL(p_info[i].num)) {
2022 fp_printf(fp, _("Sector %d:\n"), p_info[i].first_sector);
2023 read_sector(buffer.c.b, p_info[i].first_sector);
2024 fill_logical_table(&buffer, &(p_info[i]));
2025 print_file_buffer(fp, buffer.c.b);
2037 print_p_info_entry(FILE *fp, partition_info *p) {
2041 if (p->id == UNUSABLE)
2042 fp_printf(fp, _(" None "));
2043 else if (p->id == FREE_SPACE && p->num == PRI_OR_LOG)
2044 fp_printf(fp, _(" Pri/Log"));
2045 else if (p->id == FREE_SPACE && p->num == PRIMARY)
2046 fp_printf(fp, _(" Primary"));
2047 else if (p->id == FREE_SPACE && p->num == LOGICAL)
2048 fp_printf(fp, _(" Logical"));
2050 fp_printf(fp, "%2d %-7.7s", p->num+1,
2051 IS_LOGICAL(p->num) ? _("Logical") : _("Primary"));
2055 fp_printf(fp, "%11lld%c", p->first_sector,
2056 ((p->first_sector/cylinder_size) !=
2057 ((float)p->first_sector/cylinder_size) ?
2060 fp_printf(fp, "%11lld%c", p->last_sector,
2061 (((p->last_sector+1)/cylinder_size) !=
2062 ((float)(p->last_sector+1)/cylinder_size) ?
2065 fp_printf(fp, "%6ld%c", p->offset,
2066 ((((p->first_sector == 0 || IS_LOGICAL(p->num)) &&
2067 (p->offset != sectors)) ||
2068 (p->first_sector != 0 && IS_PRIMARY(p->num) &&
2072 size = p->last_sector - p->first_sector + 1;
2073 fp_printf(fp, "%11lld%c", size,
2074 ((size/cylinder_size) != ((float)size/cylinder_size) ?
2077 /* fp_printf(fp, " "); */
2079 if (p->id == UNUSABLE)
2080 sprintf(part_str, "%.15s", _("Unusable"));
2081 else if (p->id == FREE_SPACE)
2082 sprintf(part_str, "%.15s", _("Free Space"));
2083 else if (partition_type_name(p->id))
2084 sprintf(part_str, "%.15s (%02X)", _(partition_type_name(p->id)), p->id);
2086 sprintf(part_str, "%.15s (%02X)", _("Unknown"), p->id);
2087 fp_printf(fp, "%-20.20s", part_str);
2091 if (p->flags == ACTIVE_FLAG)
2092 fp_printf(fp, _("Boot"), p->flags);
2093 else if (p->flags != 0)
2094 fp_printf(fp, _("(%02X)"), p->flags);
2096 fp_printf(fp, _("None"), p->flags);
2098 fp_printf(fp, "\n");
2102 print_p_info(void) {
2103 char fname[LINE_LENGTH];
2105 int i, to_file, pext = is_extended(ext_info.id);
2111 mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X,
2112 _("Enter filename or press RETURN to display on screen: "));
2114 if ((to_file = get_string(fname, LINE_LENGTH, NULL)) < 0)
2118 if ((fp = fopen(fname, "w")) == NULL) {
2119 char errstr[LINE_LENGTH];
2120 snprintf(errstr, LINE_LENGTH, _("Cannot open file '%s'"), fname);
2121 print_warning(errstr);
2131 fp_printf(fp, _("Partition Table for %s\n"), disk_device);
2132 fp_printf(fp, "\n");
2133 fp_printf(fp, _(" First Last\n"));
2134 fp_printf(fp, _(" # Type Sector Sector Offset Length Filesystem Type (ID) Flag\n"));
2135 fp_printf(fp, _("-- ------- ----------- ----------- ------ ----------- -------------------- ----\n"));
2137 for (i = 0; i < num_parts; i++) {
2138 if (pext && (p_info[i].first_sector >= ext_info.first_sector)) {
2139 print_p_info_entry(fp,&ext_info);
2142 print_p_info_entry(fp, &(p_info[i]));
2154 print_part_entry(FILE *fp, int num, partition_info *pi) {
2155 long long first = 0, start = 0, end = 0, size = 0;
2156 unsigned char ss, es, sh, eh;
2158 int flags = 0, id = 0;
2160 ss = sh = es = eh = 0;
2167 if (IS_LOGICAL(num))
2170 first = pi->first_sector + pi->offset;
2172 start = pi->first_sector + pi->offset;
2173 end = pi->last_sector;
2174 size = end - start + 1;
2176 set_hsc0(&sh, &ss, &sc, start);
2177 set_hsc0(&eh, &es, &ec, end);
2180 fp_printf(fp, "%2d 0x%02X %4d %4d %5d 0x%02X %4d %4d %5d %11lld %11lld\n",
2181 num+1, flags, sh, ss, sc, id, eh, es, ec, first, size);
2186 print_part_table(void) {
2188 char fname[LINE_LENGTH];
2195 mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X,
2196 _("Enter filename or press RETURN to display on screen: "));
2198 if ((to_file = get_string(fname, LINE_LENGTH, NULL)) < 0)
2202 if ((fp = fopen(fname, "w")) == NULL) {
2203 char errstr[LINE_LENGTH];
2204 snprintf(errstr, LINE_LENGTH, _("Cannot open file '%s'"), fname);
2205 print_warning(errstr);
2215 fp_printf(fp, _("Partition Table for %s\n"), disk_device);
2216 fp_printf(fp, "\n");
2217 /* Three-line heading. Read "Start Sector" etc vertically. */
2218 fp_printf(fp, _(" ---Starting---- ----Ending----- Start Number of\n"));
2219 fp_printf(fp, _(" # Flags Head Sect Cyl ID Head Sect Cyl Sector Sectors\n"));
2220 fp_printf(fp, _("-- ----- ---- ---- ----- ---- ---- ---- ----- ----------- -----------\n"));
2222 for (i = 0; i < 4; i++) {
2224 j < num_parts && (p_info[j].id <= 0 || p_info[j].num != i);
2226 if (j < num_parts) {
2227 print_part_entry(fp, i, &(p_info[j]));
2228 } else if (is_extended(ext_info.id) && ext_info.num == i) {
2229 print_part_entry(fp, i, &ext_info);
2231 print_part_entry(fp, i, NULL);
2235 for (i = 0; i < num_parts; i++)
2236 if (IS_LOGICAL(p_info[i].num))
2237 print_part_entry(fp, p_info[i].num, &(p_info[i]));
2248 print_tables(void) {
2251 static struct MenuItem menuFormat[]=
2253 { 'r', N_("Raw"), N_("Print the table using raw data format") },
2254 { 's', N_("Sectors"), N_("Print the table ordered by sectors") },
2255 { 't', N_("Table"), N_("Just print the partition table") },
2256 { ESC, N_("Cancel"), N_("Don't print the table") },
2261 switch ( toupper(menuSimple( menuFormat, 2)) ) {
2280 #define END_OF_HELP "EOHS!"
2282 display_help(void) {
2283 char *help_text[] = {
2284 N_("Help Screen for cfdisk"),
2286 N_("This is cfdisk, a curses based disk partitioning program, which"),
2287 N_("allows you to create, delete and modify partitions on your hard"),
2290 N_("Copyright (C) 1994-1999 Kevin E. Martin & aeb"),
2292 N_("Command Meaning"),
2293 N_("------- -------"),
2294 N_(" b Toggle bootable flag of the current partition"),
2295 N_(" d Delete the current partition"),
2296 N_(" g Change cylinders, heads, sectors-per-track parameters"),
2297 N_(" WARNING: This option should only be used by people who"),
2298 N_(" know what they are doing."),
2299 N_(" h Print this screen"),
2300 N_(" m Maximize disk usage of the current partition"),
2301 N_(" Note: This may make the partition incompatible with"),
2302 N_(" DOS, OS/2, ..."),
2303 N_(" n Create new partition from free space"),
2304 N_(" p Print partition table to the screen or to a file"),
2305 N_(" There are several different formats for the partition"),
2306 N_(" that you can choose from:"),
2307 N_(" r - Raw data (exactly what would be written to disk)"),
2308 N_(" s - Table ordered by sectors"),
2309 N_(" t - Table in raw format"),
2310 N_(" q Quit program without writing partition table"),
2311 N_(" t Change the filesystem type"),
2312 N_(" u Change units of the partition size display"),
2313 N_(" Rotates through MB, sectors and cylinders"),
2314 N_(" W Write partition table to disk (must enter upper case W)"),
2315 N_(" Since this might destroy data on the disk, you must"),
2316 N_(" either confirm or deny the write by entering `yes' or"),
2318 N_("Up Arrow Move cursor to the previous partition"),
2319 N_("Down Arrow Move cursor to the next partition"),
2320 N_("CTRL-L Redraws the screen"),
2321 N_(" ? Print this screen"),
2323 N_("Note: All of the commands can be entered with either upper or lower"),
2324 N_("case letters (except for Writes)."),
2333 while (strcmp(help_text[cur_line], END_OF_HELP)) {
2334 if (help_text[cur_line][0])
2335 fp_printf(fp, "%s\n", _(help_text[cur_line]));
2337 fp_printf(fp, "\n");
2344 change_geometry(void) {
2345 int ret_val = FALSE;
2347 char def[LINE_LENGTH];
2348 char response[LINE_LENGTH];
2353 static struct MenuItem menuGeometry[]=
2355 { 'c', N_("Cylinders"), N_("Change cylinder geometry") },
2356 { 'h', N_("Heads"), N_("Change head geometry") },
2357 { 's', N_("Sectors"), N_("Change sector geometry") },
2358 { 'd', N_("Done"), N_("Done with changing geometry") },
2361 move(COMMAND_LINE_Y, COMMAND_LINE_X);
2367 switch (toupper( menuSimple(menuGeometry, 3) )) {
2369 sprintf(def, "%llu", actual_size/cylinder_size);
2370 mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X,
2371 _("Enter the number of cylinders: "));
2372 i = get_string(response, LINE_LENGTH, def);
2373 if (i == GS_DEFAULT) {
2374 user_cylinders = actual_size/cylinder_size;
2377 tmp_val = atoll(response);
2379 user_cylinders = tmp_val;
2382 print_warning(_("Illegal cylinders value"));
2386 sprintf(def, "%d", heads);
2387 mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X,
2388 _("Enter the number of heads: "));
2389 if (get_string(response, LINE_LENGTH, def) > 0) {
2390 tmp_val = atoll(response);
2391 if (tmp_val > 0 && tmp_val <= MAX_HEADS) {
2392 user_heads = tmp_val;
2395 print_warning(_("Illegal heads value"));
2399 sprintf(def, "%d", sectors);
2400 mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X,
2401 _("Enter the number of sectors per track: "));
2402 if (get_string(response, LINE_LENGTH, def) > 0) {
2403 tmp_val = atoll(response);
2404 if (tmp_val > 0 && tmp_val <= MAX_SECTORS) {
2405 user_sectors = tmp_val;
2408 print_warning(_("Illegal sectors value"));
2421 decide_on_geometry();
2429 disk_end = total_size-1;
2431 if (p_info[num_parts-1].last_sector > disk_end) {
2432 while (p_info[num_parts-1].first_sector > disk_end) {
2433 if (p_info[num_parts-1].id == FREE_SPACE ||
2434 p_info[num_parts-1].id == UNUSABLE)
2435 remove_part(num_parts-1);
2437 del_part(num_parts-1);
2440 p_info[num_parts-1].last_sector = disk_end;
2442 if (ext_info.last_sector > disk_end)
2443 ext_info.last_sector = disk_end;
2444 } else if (p_info[num_parts-1].last_sector < disk_end) {
2445 if (p_info[num_parts-1].id == FREE_SPACE ||
2446 p_info[num_parts-1].id == UNUSABLE) {
2447 p_info[num_parts-1].last_sector = disk_end;
2449 insert_empty_part(num_parts,
2450 p_info[num_parts-1].last_sector+1,
2455 /* Make sure the partitions are correct */
2464 char id[LINE_LENGTH], def[LINE_LENGTH];
2466 int num_across, num_down;
2467 int len, new_id = ((p_info[i].id == LINUX) ? LINUX_SWAP : LINUX);
2468 int y_start, y_end, row, row_min, row_max, row_offset, j, needmore;
2470 for (j = 1; i386_sys_types[j].name; j++) ;
2471 num_types = j-1; /* do not count the Empty type */
2473 num_across = COLS/COL_ID_WIDTH;
2474 num_down = (((float)num_types)/num_across + 1);
2475 y_start = COMMAND_LINE_Y - 1 - num_down;
2478 y_end = COMMAND_LINE_Y - 2;
2480 if (y_start > DISK_TABLE_START+cur_part+4)
2481 y_start = DISK_TABLE_START+cur_part+4;
2482 y_end = y_start + num_down - 1;
2486 row_max = COMMAND_LINE_Y - 2;
2489 for (j = y_start - 1; j <= y_end + 1; j++) {
2494 for (j = 1; i386_sys_types[j].name; j++) {
2495 row = y_start + (j-1) % num_down - row_offset;
2496 if (row >= row_min && row <= row_max) {
2497 move(row, ((j-1)/num_down)*COL_ID_WIDTH + 1);
2498 printw("%02X %-20.20s",
2499 i386_sys_types[j].type,
2500 _(i386_sys_types[j].name));
2507 row_offset += (row_max - row_min + 1);
2510 sprintf(def, "%02X", new_id);
2511 mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, _("Enter filesystem type: "));
2512 if ((len = get_string(id, 2, def)) <= 0 && len != GS_DEFAULT)
2515 if (len != GS_DEFAULT) {
2516 if (!isxdigit(id[0]))
2518 new_id = (isdigit(id[0]) ? id[0] - '0' : tolower(id[0]) - 'a' + 10);
2520 if (isxdigit(id[1]))
2521 new_id = new_id*16 +
2522 (isdigit(id[1]) ? id[1] - '0' : tolower(id[1]) - 'a' + 10);
2529 print_warning(_("Cannot change FS Type to empty"));
2530 else if (is_extended(new_id))
2531 print_warning(_("Cannot change FS Type to extended"));
2533 p_info[i].id = new_id;
2537 draw_partition(int i) {
2539 int y = i + DISK_TABLE_START + 2 - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN;
2544 if (!arrow_cursor) {
2546 for (j = 0; j < COLS; j++)
2550 if (p_info[i].id > 0) {
2551 char *dbn = my_basename(disk_device);
2552 int l = strlen(dbn);
2553 int digit_last = isdigit(dbn[l-1]);
2555 mvprintw(y, NAME_START,
2556 "%s%s%d", dbn, (digit_last ? "p" : ""),
2558 if (p_info[i].flags) {
2559 if (p_info[i].flags == ACTIVE_FLAG)
2560 mvaddstr(y, FLAGS_START, _("Boot"));
2562 mvprintw(y, FLAGS_START, _("Unk(%02X)"), p_info[i].flags);
2563 if (p_info[i].first_sector == 0 || IS_LOGICAL(p_info[i].num)) {
2564 if (p_info[i].offset != sectors)
2567 if (p_info[i].offset != 0)
2571 if (p_info[i].first_sector == 0 || IS_LOGICAL(p_info[i].num)) {
2572 if (p_info[i].offset != sectors)
2573 mvaddstr(y, FLAGS_START, _("NC"));
2575 if (p_info[i].offset != 0)
2576 mvaddstr(y, FLAGS_START, _("NC"));
2580 mvaddstr(y, PTYPE_START,
2581 (p_info[i].id == UNUSABLE ? "" :
2582 (IS_LOGICAL(p_info[i].num) ? _("Logical") :
2583 (p_info[i].num >= 0 ? _("Primary") :
2584 (p_info[i].num == PRI_OR_LOG ? _("Pri/Log") :
2585 (p_info[i].num == PRIMARY ? _("Primary") : _("Logical")))))));
2587 t = partition_type_text(i);
2589 mvaddstr(y, FSTYPE_START, t);
2591 mvprintw(y, FSTYPE_START, _("Unknown (%02X)"), p_info[i].id);
2593 if (p_info[i].volume_label[0]) {
2594 int l = strlen(p_info[i].volume_label);
2595 int s = SIZE_START-5-l;
2596 mvprintw(y, (s > LABEL_START) ? LABEL_START : s,
2597 " [%s] ", p_info[i].volume_label);
2600 size = p_info[i].last_sector - p_info[i].first_sector + 1;
2601 fsize = (double) size * SECTOR_SIZE;
2602 if (display_units == SECTORS)
2603 mvprintw(y, SIZE_START, "%11lld", size);
2604 else if (display_units == CYLINDERS)
2605 mvprintw(y, SIZE_START, "%11lld", size/cylinder_size);
2606 else if (display_units == MEGABYTES)
2607 mvprintw(y, SIZE_START, "%11.2f", ceiling((100*fsize)/(K*K))/100);
2608 else if (display_units == GIGABYTES)
2609 mvprintw(y, SIZE_START, "%11.2f", ceiling((100*fsize)/(K*K*K))/100);
2610 if (size % cylinder_size != 0 ||
2611 p_info[i].first_sector % cylinder_size != 0)
2612 mvprintw(y, COLUMNS-1, "*");
2618 NAME_START = (((float)NAME_START)/COLUMNS)*COLS;
2619 FLAGS_START = (((float)FLAGS_START)/COLUMNS)*COLS;
2620 PTYPE_START = (((float)PTYPE_START)/COLUMNS)*COLS;
2621 FSTYPE_START = (((float)FSTYPE_START)/COLUMNS)*COLS;
2622 LABEL_START = (((float)LABEL_START)/COLUMNS)*COLS;
2623 SIZE_START = (((float)SIZE_START)/COLUMNS)*COLS;
2624 COMMAND_LINE_X = (((float)COMMAND_LINE_X)/COLUMNS)*COLS;
2626 COMMAND_LINE_Y = LINES - 4;
2627 WARNING_START = LINES - 2;
2629 if ((NUM_ON_SCREEN = COMMAND_LINE_Y - DISK_TABLE_START - 3) <= 0)
2642 line = (char *) xmalloc((COLS+1)*sizeof(char));
2644 if (warning_last_time) {
2645 for (i = 0; i < COLS; i++) {
2646 move(WARNING_START, i);
2654 if (warning_last_time)
2655 mvaddstr(WARNING_START, 0, line);
2658 snprintf(line, COLS+1, "cfdisk (%s)", PACKAGE_STRING);
2659 mvaddstr(HEADER_START, (COLS-strlen(line))/2, line);
2660 snprintf(line, COLS+1, _("Disk Drive: %s"), disk_device);
2661 mvaddstr(HEADER_START+2, (COLS-strlen(line))/2, line);
2663 long long bytes = actual_size*(long long) SECTOR_SIZE;
2664 long long megabytes = bytes/(K*K);
2666 if (megabytes < 10000)
2667 sprintf(line, _("Size: %lld bytes, %lld MB"),
2670 sprintf(line, _("Size: %lld bytes, %lld.%lld GB"),
2671 bytes, megabytes/K, (10*megabytes/K)%10);
2673 mvaddstr(HEADER_START+3, (COLS-strlen(line))/2, line);
2674 snprintf(line, COLS+1, _("Heads: %d Sectors per Track: %d Cylinders: %lld"),
2675 heads, sectors, cylinders);
2676 mvaddstr(HEADER_START+4, (COLS-strlen(line))/2, line);
2678 mvaddstr(DISK_TABLE_START, NAME_START, _("Name"));
2679 mvaddstr(DISK_TABLE_START, FLAGS_START, _("Flags"));
2680 mvaddstr(DISK_TABLE_START, PTYPE_START-1, _("Part Type"));
2681 mvaddstr(DISK_TABLE_START, FSTYPE_START, _("FS Type"));
2682 mvaddstr(DISK_TABLE_START, LABEL_START+1, _("[Label]"));
2683 if (display_units == SECTORS)
2684 mvaddstr(DISK_TABLE_START, SIZE_START, _(" Sectors"));
2685 else if (display_units == CYLINDERS)
2686 mvaddstr(DISK_TABLE_START, SIZE_START, _(" Cylinders"));
2687 else if (display_units == MEGABYTES)
2688 mvaddstr(DISK_TABLE_START, SIZE_START, _(" Size (MB)"));
2689 else if (display_units == GIGABYTES)
2690 mvaddstr(DISK_TABLE_START, SIZE_START, _(" Size (GB)"));
2692 move(DISK_TABLE_START+1, 1);
2693 for (i = 1; i < COLS-1; i++)
2696 if (NUM_ON_SCREEN >= num_parts)
2697 for (i = 0; i < num_parts; i++)
2700 for (i = (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN;
2701 i < NUM_ON_SCREEN + (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN &&
2710 draw_cursor(int move) {
2711 if (move != 0 && (cur_part + move < 0 || cur_part + move >= num_parts))
2715 mvaddstr(DISK_TABLE_START + cur_part + 2
2716 - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN, 0, " ");
2718 draw_partition(cur_part);
2722 if (((cur_part - move)/NUM_ON_SCREEN)*NUM_ON_SCREEN !=
2723 (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN)
2727 mvaddstr(DISK_TABLE_START + cur_part + 2
2728 - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN, 0, "-->");
2731 draw_partition(cur_part);
2739 do_curses_fdisk(void) {
2743 static struct MenuItem menuMain[] = {
2744 { 'b', N_("Bootable"), N_("Toggle bootable flag of the current partition") },
2745 { 'd', N_("Delete"), N_("Delete the current partition") },
2746 { 'g', N_("Geometry"), N_("Change disk geometry (experts only)") },
2747 { 'h', N_("Help"), N_("Print help screen") },
2748 { 'm', N_("Maximize"), N_("Maximize disk usage of the current partition (experts only)") },
2749 { 'n', N_("New"), N_("Create new partition from free space") },
2750 { 'p', N_("Print"), N_("Print partition table to the screen or to a file") },
2751 { 'q', N_("Quit"), N_("Quit program without writing partition table") },
2752 { 't', N_("Type"), N_("Change the filesystem type (DOS, Linux, OS/2 and so on)") },
2753 { 'u', N_("Units"), N_("Change units of the partition size display (MB, sect, cyl)") },
2754 { 'W', N_("Write"), N_("Write partition table to disk (this might destroy data)") },
2761 old_SIGINT = signal(SIGINT, die);
2762 old_SIGTERM = signal(SIGTERM, die);
2764 signal(SIGINT, old_SIGINT);
2765 signal(SIGTERM, old_SIGTERM);
2779 (void)draw_cursor(0);
2781 if (p_info[cur_part].id == FREE_SPACE) {
2782 s = ((opentype == O_RDWR) ? "hnpquW" : "hnpqu");
2783 command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 10,
2784 s, MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, 0);
2785 } else if (p_info[cur_part].id > 0) {
2786 s = ((opentype == O_RDWR) ? "bdhmpqtuW" : "bdhmpqtu");
2787 command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 10,
2788 s, MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, 0);
2790 s = ((opentype == O_RDWR) ? "hpquW" : "hpqu");
2791 command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 10,
2792 s, MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, 0);
2794 switch ( command ) {
2797 if (p_info[cur_part].id > 0)
2798 p_info[cur_part].flags ^= 0x80;
2800 print_warning(_("Cannot make this partition bootable"));
2804 if (p_info[cur_part].id > 0) {
2806 if (cur_part >= num_parts)
2807 cur_part = num_parts - 1;
2810 print_warning(_("Cannot delete an empty partition"));
2814 if (change_geometry())
2819 if (p_info[cur_part].id > 0) {
2820 if (p_info[cur_part].first_sector == 0 ||
2821 IS_LOGICAL(p_info[cur_part].num)) {
2822 if (p_info[cur_part].offset == sectors)
2823 p_info[cur_part].offset = 1;
2825 p_info[cur_part].offset = sectors;
2827 } else if (p_info[cur_part].offset != 0)
2828 p_info[cur_part].offset = 0;
2830 print_warning(_("Cannot maximize this partition"));
2832 print_warning(_("Cannot maximize this partition"));
2836 if (p_info[cur_part].id == FREE_SPACE) {
2839 } else if (p_info[cur_part].id == UNUSABLE)
2840 print_warning(_("This partition is unusable"));
2842 print_warning(_("This partition is already in use"));
2855 if (p_info[cur_part].id > 0) {
2856 change_id(cur_part);
2859 print_warning(_("Cannot change the type of an empty partition"));
2863 if (display_units == GIGABYTES)
2864 display_units = MEGABYTES;
2865 else if (display_units == MEGABYTES)
2866 display_units = SECTORS;
2867 else if (display_units == SECTORS)
2868 display_units = CYLINDERS;
2869 else if (display_units == CYLINDERS)
2870 display_units = MEGABYTES; /* not yet GIGA */
2882 case MENU_UP : /* Up arrow */
2883 if (!draw_cursor(-1))
2886 print_warning(_("No more partitions"));
2888 case MENU_DOWN : /* Down arrow */
2889 if (!draw_cursor(1))
2892 print_warning(_("No more partitions"));
2899 print_warning(_("Illegal command"));
2900 putchar(BELL); /* CTRL-G */
2909 fprintf(stderr, _("Copyright (C) 1994-2002 Kevin E. Martin & aeb\n"));
2913 usage(char *prog_name) {
2914 /* Unfortunately, xgettext does not handle multi-line strings */
2915 /* so, let's use explicit \n's instead */
2916 fprintf(stderr, _("\n"
2920 "Print partition table:\n"
2921 " %s -P {r|s|t} [options] device\n"
2922 "Interactive use:\n"
2923 " %s [options] device\n"
2926 "-a: Use arrow instead of highlighting;\n"
2927 "-z: Start with a zero partition table, instead of reading the pt from disk;\n"
2928 "-c C -h H -s S: Override the kernel's idea of the number of cylinders,\n"
2929 " the number of heads and the number of sectors/track.\n\n"),
2930 prog_name, prog_name, prog_name);
2936 main(int argc, char **argv)
2941 setlocale(LC_ALL, "");
2942 bindtextdomain(PACKAGE, LOCALEDIR);
2943 textdomain(PACKAGE);
2945 while ((c = getopt(argc, argv, "ac:gh:s:vzP:")) != -1)
2948 arrow_cursor = TRUE;
2951 user_cylinders = cylinders = atoll(optarg);
2952 if (cylinders <= 0) {
2953 fprintf(stderr, "%s: %s\n", argv[0], _("Illegal cylinders value"));
2958 use_partition_table_geometry = TRUE;
2961 user_heads = heads = atoi(optarg);
2962 if (heads <= 0 || heads > MAX_HEADS) {
2963 fprintf(stderr, "%s: %s\n", argv[0], _("Illegal heads value"));
2968 user_sectors = sectors = atoi(optarg);
2969 if (sectors <= 0 || sectors > MAX_SECTORS) {
2970 fprintf(stderr, "%s: %s\n", argv[0], _("Illegal sectors value"));
2975 fprintf(stderr, "cfdisk (%s)\n", PACKAGE_STRING);
2982 len = strlen(optarg);
2983 for (i = 0; i < len; i++) {
2984 switch (optarg[i]) {
2986 print_only |= PRINT_RAW_TABLE;
2989 print_only |= PRINT_SECTOR_TABLE;
2992 print_only |= PRINT_PARTITION_TABLE;
3005 if (argc-optind == 1)
3006 disk_device = argv[optind];
3007 else if (argc-optind != 0) {
3010 } else if ((fd = open(DEFAULT_DEVICE, O_RDONLY)) < 0)
3011 disk_device = ALTERNATE_DEVICE;
3016 if (print_only & PRINT_RAW_TABLE)
3018 if (print_only & PRINT_SECTOR_TABLE)
3020 if (print_only & PRINT_PARTITION_TABLE)