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