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