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