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