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