1
2
3
4
5
6
7
8
9
10#ifndef _LARGEFILE64_SOURCE
11
12#define _LARGEFILE64_SOURCE
13#endif
14#include <assert.h>
15#include "libbb.h"
16
17
18#ifndef ENABLE_FEATURE_FDISK_BLKSIZE
19# define ENABLE_FEATURE_FDISK_BLKSIZE 0
20# define USE_FEATURE_FDISK_BLKSIZE(a)
21#endif
22
23#define DEFAULT_SECTOR_SIZE 512
24#define DEFAULT_SECTOR_SIZE_STR "512"
25#define MAX_SECTOR_SIZE 2048
26#define SECTOR_SIZE 512
27#define MAXIMUM_PARTS 60
28
29#define ACTIVE_FLAG 0x80
30
31#define EXTENDED 0x05
32#define WIN98_EXTENDED 0x0f
33#define LINUX_PARTITION 0x81
34#define LINUX_SWAP 0x82
35#define LINUX_NATIVE 0x83
36#define LINUX_EXTENDED 0x85
37#define LINUX_LVM 0x8e
38#define LINUX_RAID 0xfd
39
40
41enum {
42 OPT_b = 1 << 0,
43 OPT_C = 1 << 1,
44 OPT_H = 1 << 2,
45 OPT_l = 1 << 3,
46 OPT_S = 1 << 4,
47 OPT_u = 1 << 5,
48 OPT_s = (1 << 6) * ENABLE_FEATURE_FDISK_BLKSIZE,
49};
50
51
52
53typedef unsigned long long ullong;
54
55struct hd_geometry {
56 unsigned char heads;
57 unsigned char sectors;
58 unsigned short cylinders;
59 unsigned long start;
60};
61
62#define HDIO_GETGEO 0x0301
63
64static const char msg_building_new_label[] ALIGN1 =
65"Building a new %s. Changes will remain in memory only,\n"
66"until you decide to write them. After that the previous content\n"
67"won't be recoverable.\n\n";
68
69static const char msg_part_already_defined[] ALIGN1 =
70"Partition %d is already defined, delete it before re-adding\n";
71
72
73struct partition {
74 unsigned char boot_ind;
75 unsigned char head;
76 unsigned char sector;
77 unsigned char cyl;
78 unsigned char sys_ind;
79 unsigned char end_head;
80 unsigned char end_sector;
81 unsigned char end_cyl;
82 unsigned char start4[4];
83 unsigned char size4[4];
84} PACKED;
85
86static const char unable_to_open[] ALIGN1 = "can't open '%s'";
87static const char unable_to_read[] ALIGN1 = "can't read from %s";
88static const char unable_to_seek[] ALIGN1 = "can't seek on %s";
89
90enum label_type {
91 LABEL_DOS, LABEL_SUN, LABEL_SGI, LABEL_AIX, LABEL_OSF
92};
93
94#define LABEL_IS_DOS (LABEL_DOS == current_label_type)
95
96#if ENABLE_FEATURE_SUN_LABEL
97#define LABEL_IS_SUN (LABEL_SUN == current_label_type)
98#define STATIC_SUN static
99#else
100#define LABEL_IS_SUN 0
101#define STATIC_SUN extern
102#endif
103
104#if ENABLE_FEATURE_SGI_LABEL
105#define LABEL_IS_SGI (LABEL_SGI == current_label_type)
106#define STATIC_SGI static
107#else
108#define LABEL_IS_SGI 0
109#define STATIC_SGI extern
110#endif
111
112#if ENABLE_FEATURE_AIX_LABEL
113#define LABEL_IS_AIX (LABEL_AIX == current_label_type)
114#define STATIC_AIX static
115#else
116#define LABEL_IS_AIX 0
117#define STATIC_AIX extern
118#endif
119
120#if ENABLE_FEATURE_OSF_LABEL
121#define LABEL_IS_OSF (LABEL_OSF == current_label_type)
122#define STATIC_OSF static
123#else
124#define LABEL_IS_OSF 0
125#define STATIC_OSF extern
126#endif
127
128enum action { OPEN_MAIN, TRY_ONLY, CREATE_EMPTY_DOS, CREATE_EMPTY_SUN };
129
130static void update_units(void);
131#if ENABLE_FEATURE_FDISK_WRITABLE
132static void change_units(void);
133static void reread_partition_table(int leave);
134static void delete_partition(int i);
135static int get_partition(int warn, int max);
136static void list_types(const char *const *sys);
137static unsigned read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, const char *mesg);
138#endif
139static const char *partition_type(unsigned char type);
140static void get_geometry(void);
141#if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
142static int get_boot(enum action what);
143#else
144static int get_boot(void);
145#endif
146
147#define PLURAL 0
148#define SINGULAR 1
149
150static unsigned get_start_sect(const struct partition *p);
151static unsigned get_nr_sects(const struct partition *p);
152
153
154
155
156
157
158
159
160
161struct pte {
162 struct partition *part_table;
163 struct partition *ext_pointer;
164 ullong offset;
165 char *sectorbuffer;
166#if ENABLE_FEATURE_FDISK_WRITABLE
167 char changed;
168#endif
169};
170
171
172
173static const char *const i386_sys_types[] = {
174 "\x00" "Empty",
175 "\x01" "FAT12",
176 "\x04" "FAT16 <32M",
177 "\x05" "Extended",
178 "\x06" "FAT16",
179 "\x07" "HPFS/NTFS",
180 "\x0a" "OS/2 Boot Manager",
181 "\x0b" "Win95 FAT32",
182 "\x0c" "Win95 FAT32 (LBA)",
183 "\x0e" "Win95 FAT16 (LBA)",
184 "\x0f" "Win95 Ext'd (LBA)",
185 "\x11" "Hidden FAT12",
186 "\x12" "Compaq diagnostics",
187 "\x14" "Hidden FAT16 <32M",
188 "\x16" "Hidden FAT16",
189 "\x17" "Hidden HPFS/NTFS",
190 "\x1b" "Hidden Win95 FAT32",
191 "\x1c" "Hidden W95 FAT32 (LBA)",
192 "\x1e" "Hidden W95 FAT16 (LBA)",
193 "\x3c" "Part.Magic recovery",
194 "\x41" "PPC PReP Boot",
195 "\x42" "SFS",
196 "\x63" "GNU HURD or SysV",
197 "\x80" "Old Minix",
198 "\x81" "Minix / old Linux",
199 "\x82" "Linux swap",
200 "\x83" "Linux",
201 "\x84" "OS/2 hidden C: drive",
202 "\x85" "Linux extended",
203 "\x86" "NTFS volume set",
204 "\x87" "NTFS volume set",
205 "\x8e" "Linux LVM",
206 "\x9f" "BSD/OS",
207 "\xa0" "Thinkpad hibernation",
208 "\xa5" "FreeBSD",
209 "\xa6" "OpenBSD",
210 "\xa8" "Darwin UFS",
211 "\xa9" "NetBSD",
212 "\xab" "Darwin boot",
213 "\xb7" "BSDI fs",
214 "\xb8" "BSDI swap",
215 "\xbe" "Solaris boot",
216 "\xeb" "BeOS fs",
217 "\xee" "EFI GPT",
218 "\xef" "EFI (FAT-12/16/32)",
219 "\xf0" "Linux/PA-RISC boot",
220 "\xf2" "DOS secondary",
221 "\xfd" "Linux raid autodetect",
222
223
224#if 0
225 "\x02" "XENIX root",
226 "\x03" "XENIX usr",
227 "\x08" "AIX",
228 "\x09" "AIX bootable",
229 "\x10" "OPUS",
230 "\x18" "AST SmartSleep",
231 "\x24" "NEC DOS",
232 "\x39" "Plan 9",
233 "\x40" "Venix 80286",
234 "\x4d" "QNX4.x",
235 "\x4e" "QNX4.x 2nd part",
236 "\x4f" "QNX4.x 3rd part",
237 "\x50" "OnTrack DM",
238 "\x51" "OnTrack DM6 Aux1",
239 "\x52" "CP/M",
240 "\x53" "OnTrack DM6 Aux3",
241 "\x54" "OnTrackDM6",
242 "\x55" "EZ-Drive",
243 "\x56" "Golden Bow",
244 "\x5c" "Priam Edisk",
245 "\x61" "SpeedStor",
246 "\x64" "Novell Netware 286",
247 "\x65" "Novell Netware 386",
248 "\x70" "DiskSecure Multi-Boot",
249 "\x75" "PC/IX",
250 "\x93" "Amoeba",
251 "\x94" "Amoeba BBT",
252 "\xa7" "NeXTSTEP",
253 "\xbb" "Boot Wizard hidden",
254 "\xc1" "DRDOS/sec (FAT-12)",
255 "\xc4" "DRDOS/sec (FAT-16 < 32M)",
256 "\xc6" "DRDOS/sec (FAT-16)",
257 "\xc7" "Syrinx",
258 "\xda" "Non-FS data",
259 "\xdb" "CP/M / CTOS / ...",
260
261 "\xde" "Dell Utility",
262 "\xdf" "BootIt",
263 "\xe1" "DOS access",
264
265 "\xe3" "DOS R/O",
266 "\xe4" "SpeedStor",
267
268 "\xf1" "SpeedStor",
269 "\xf4" "SpeedStor",
270 "\xfe" "LANstep",
271 "\xff" "BBT",
272#endif
273 NULL
274};
275
276enum {
277 dev_fd = 3
278};
279
280
281struct globals {
282 char *line_ptr;
283
284 const char *disk_device;
285 int g_partitions;
286 unsigned units_per_sector;
287 unsigned sector_size;
288 unsigned user_set_sector_size;
289 unsigned sector_offset;
290 unsigned g_heads, g_sectors, g_cylinders;
291 smallint current_label_type;
292 smallint display_in_cyl_units;
293#if ENABLE_FEATURE_OSF_LABEL
294 smallint possibly_osf_label;
295#endif
296
297 smallint listing;
298 smallint dos_compatible_flag;
299#if ENABLE_FEATURE_FDISK_WRITABLE
300
301 smallint nowarn;
302#endif
303 int ext_index;
304 unsigned user_cylinders, user_heads, user_sectors;
305 unsigned pt_heads, pt_sectors;
306 unsigned kern_heads, kern_sectors;
307 ullong extended_offset;
308 ullong total_number_of_sectors;
309
310 jmp_buf listingbuf;
311 char line_buffer[80];
312 char partname_buffer[80];
313
314
315 char MBRbuffer[MAX_SECTOR_SIZE];
316
317 struct pte ptes[MAXIMUM_PARTS];
318};
319#define G (*ptr_to_globals)
320#define line_ptr (G.line_ptr )
321#define disk_device (G.disk_device )
322#define g_partitions (G.g_partitions )
323#define units_per_sector (G.units_per_sector )
324#define sector_size (G.sector_size )
325#define user_set_sector_size (G.user_set_sector_size)
326#define sector_offset (G.sector_offset )
327#define g_heads (G.g_heads )
328#define g_sectors (G.g_sectors )
329#define g_cylinders (G.g_cylinders )
330#define current_label_type (G.current_label_type )
331#define display_in_cyl_units (G.display_in_cyl_units)
332#define possibly_osf_label (G.possibly_osf_label )
333#define listing (G.listing )
334#define dos_compatible_flag (G.dos_compatible_flag )
335#define nowarn (G.nowarn )
336#define ext_index (G.ext_index )
337#define user_cylinders (G.user_cylinders )
338#define user_heads (G.user_heads )
339#define user_sectors (G.user_sectors )
340#define pt_heads (G.pt_heads )
341#define pt_sectors (G.pt_sectors )
342#define kern_heads (G.kern_heads )
343#define kern_sectors (G.kern_sectors )
344#define extended_offset (G.extended_offset )
345#define total_number_of_sectors (G.total_number_of_sectors)
346#define listingbuf (G.listingbuf )
347#define line_buffer (G.line_buffer )
348#define partname_buffer (G.partname_buffer)
349#define MBRbuffer (G.MBRbuffer )
350#define ptes (G.ptes )
351#define INIT_G() do { \
352 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
353 sector_size = DEFAULT_SECTOR_SIZE; \
354 sector_offset = 1; \
355 g_partitions = 4; \
356 display_in_cyl_units = 1; \
357 units_per_sector = 1; \
358 dos_compatible_flag = 1; \
359} while (0)
360
361
362
363static ullong bb_BLKGETSIZE_sectors(int fd)
364{
365 uint64_t v64;
366 unsigned long longsectors;
367
368 if (ioctl(fd, BLKGETSIZE64, &v64) == 0) {
369
370 return (v64 >> 9);
371 }
372
373 if (ioctl(fd, BLKGETSIZE, &longsectors))
374 longsectors = 0;
375 return longsectors;
376}
377
378
379#define IS_EXTENDED(i) \
380 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
381
382#define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
383
384#define scround(x) (((x)+units_per_sector-1)/units_per_sector)
385
386#define pt_offset(b, n) \
387 ((struct partition *)((b) + 0x1be + (n) * sizeof(struct partition)))
388
389#define sector(s) ((s) & 0x3f)
390
391#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
392
393#define hsc2sector(h,s,c) \
394 (sector(s) - 1 + sectors * ((h) + heads * cylinder(s,c)))
395
396#define set_hsc(h,s,c,sector) \
397 do { \
398 s = sector % g_sectors + 1; \
399 sector /= g_sectors; \
400 h = sector % g_heads; \
401 sector /= g_heads; \
402 c = sector & 0xff; \
403 s |= (sector >> 2) & 0xc0; \
404 } while (0)
405
406static void
407close_dev_fd(void)
408{
409
410 xmove_fd(xopen(bb_dev_null, O_RDONLY), dev_fd);
411}
412
413#if ENABLE_FEATURE_FDISK_WRITABLE
414
415static int
416read_line(const char *prompt)
417{
418 int sz;
419
420 sz = read_line_input(prompt, line_buffer, sizeof(line_buffer), NULL);
421 if (sz <= 0)
422 exit(EXIT_SUCCESS);
423
424 if (line_buffer[sz-1] == '\n')
425 line_buffer[--sz] = '\0';
426
427 line_ptr = line_buffer;
428 while (*line_ptr && !isgraph(*line_ptr))
429 line_ptr++;
430 return *line_ptr;
431}
432#endif
433
434
435
436
437static const char *
438partname(const char *dev, int pno, int lth)
439{
440 const char *p;
441 int w, wp;
442 int bufsiz;
443 char *bufp;
444
445 bufp = partname_buffer;
446 bufsiz = sizeof(partname_buffer);
447
448 w = strlen(dev);
449 p = "";
450
451 if (isdigit(dev[w-1]))
452 p = "p";
453
454
455
456 if (strcmp(dev + w - 4, "disc") == 0) {
457 w -= 4;
458 p = "part";
459 }
460
461 wp = strlen(p);
462
463 if (lth) {
464 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
465 lth-wp-2, w, dev, p, pno);
466 } else {
467 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
468 }
469 return bufp;
470}
471
472#if ENABLE_FEATURE_FDISK_WRITABLE
473static void
474set_all_unchanged(void)
475{
476 int i;
477
478 for (i = 0; i < MAXIMUM_PARTS; i++)
479 ptes[i].changed = 0;
480}
481
482static ALWAYS_INLINE void
483set_changed(int i)
484{
485 ptes[i].changed = 1;
486}
487#endif
488
489static ALWAYS_INLINE struct partition *
490get_part_table(int i)
491{
492 return ptes[i].part_table;
493}
494
495static const char *
496str_units(int n)
497{
498 if (n == 1)
499 return display_in_cyl_units ? "cylinder" : "sector";
500 return display_in_cyl_units ? "cylinders" : "sectors";
501}
502
503static int
504valid_part_table_flag(const char *mbuffer)
505{
506 return (mbuffer[510] == 0x55 && (uint8_t)mbuffer[511] == 0xaa);
507}
508
509#if ENABLE_FEATURE_FDISK_WRITABLE
510static ALWAYS_INLINE void
511write_part_table_flag(char *b)
512{
513 b[510] = 0x55;
514 b[511] = 0xaa;
515}
516
517static char
518read_nonempty(const char *mesg)
519{
520 while (!read_line(mesg))
521 continue;
522 return *line_ptr;
523}
524
525static char
526read_maybe_empty(const char *mesg)
527{
528 if (!read_line(mesg)) {
529 line_ptr = line_buffer;
530 line_ptr[0] = '\n';
531 line_ptr[1] = '\0';
532 }
533 return line_ptr[0];
534}
535
536static int
537read_hex(const char *const *sys)
538{
539 unsigned long v;
540 while (1) {
541 read_nonempty("Hex code (type L to list codes): ");
542 if (*line_ptr == 'l' || *line_ptr == 'L') {
543 list_types(sys);
544 continue;
545 }
546 v = bb_strtoul(line_ptr, NULL, 16);
547 if (v > 0xff)
548
549 continue;
550 return v;
551 }
552}
553#endif
554
555static void fdisk_fatal(const char *why)
556{
557 if (listing) {
558 close_dev_fd();
559 longjmp(listingbuf, 1);
560 }
561 bb_error_msg_and_die(why, disk_device);
562}
563
564static void
565seek_sector(ullong secno)
566{
567 secno *= sector_size;
568#if ENABLE_FDISK_SUPPORT_LARGE_DISKS
569 if (lseek64(dev_fd, (off64_t)secno, SEEK_SET) == (off64_t) -1)
570 fdisk_fatal(unable_to_seek);
571#else
572 if (secno > MAXINT(off_t)
573 || lseek(dev_fd, (off_t)secno, SEEK_SET) == (off_t) -1
574 ) {
575 fdisk_fatal(unable_to_seek);
576 }
577#endif
578}
579
580#if ENABLE_FEATURE_FDISK_WRITABLE
581static void
582write_sector(ullong secno, const void *buf)
583{
584 seek_sector(secno);
585 xwrite(dev_fd, buf, sector_size);
586}
587#endif
588
589
590#include "fdisk_aix.c"
591
592typedef struct {
593 unsigned char info[128];
594 unsigned char spare0[14];
595 struct sun_info {
596 unsigned char spare1;
597 unsigned char id;
598 unsigned char spare2;
599 unsigned char flags;
600 } infos[8];
601 unsigned char spare1[246];
602 unsigned short rspeed;
603 unsigned short pcylcount;
604 unsigned short sparecyl;
605 unsigned char spare2[4];
606 unsigned short ilfact;
607 unsigned short ncyl;
608 unsigned short nacyl;
609 unsigned short ntrks;
610 unsigned short nsect;
611 unsigned char spare3[4];
612 struct sun_partinfo {
613 uint32_t start_cylinder;
614 uint32_t num_sectors;
615 } partitions[8];
616 unsigned short magic;
617 unsigned short csum;
618} sun_partition;
619#define sunlabel ((sun_partition *)MBRbuffer)
620STATIC_OSF void bsd_select(void);
621STATIC_OSF void xbsd_print_disklabel(int);
622#include "fdisk_osf.c"
623
624#if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL
625static uint16_t
626fdisk_swap16(uint16_t x)
627{
628 return (x << 8) | (x >> 8);
629}
630
631static uint32_t
632fdisk_swap32(uint32_t x)
633{
634 return (x << 24) |
635 ((x & 0xFF00) << 8) |
636 ((x & 0xFF0000) >> 8) |
637 (x >> 24);
638}
639#endif
640
641STATIC_SGI const char *const sgi_sys_types[];
642STATIC_SGI unsigned sgi_get_num_sectors(int i);
643STATIC_SGI int sgi_get_sysid(int i);
644STATIC_SGI void sgi_delete_partition(int i);
645STATIC_SGI void sgi_change_sysid(int i, int sys);
646STATIC_SGI void sgi_list_table(int xtra);
647#if ENABLE_FEATURE_FDISK_ADVANCED
648STATIC_SGI void sgi_set_xcyl(void);
649#endif
650STATIC_SGI int verify_sgi(int verbose);
651STATIC_SGI void sgi_add_partition(int n, int sys);
652STATIC_SGI void sgi_set_swappartition(int i);
653STATIC_SGI const char *sgi_get_bootfile(void);
654STATIC_SGI void sgi_set_bootfile(const char* aFile);
655STATIC_SGI void create_sgiinfo(void);
656STATIC_SGI void sgi_write_table(void);
657STATIC_SGI void sgi_set_bootpartition(int i);
658#include "fdisk_sgi.c"
659
660STATIC_SUN const char *const sun_sys_types[];
661STATIC_SUN void sun_delete_partition(int i);
662STATIC_SUN void sun_change_sysid(int i, int sys);
663STATIC_SUN void sun_list_table(int xtra);
664STATIC_SUN void add_sun_partition(int n, int sys);
665#if ENABLE_FEATURE_FDISK_ADVANCED
666STATIC_SUN void sun_set_alt_cyl(void);
667STATIC_SUN void sun_set_ncyl(int cyl);
668STATIC_SUN void sun_set_xcyl(void);
669STATIC_SUN void sun_set_ilfact(void);
670STATIC_SUN void sun_set_rspeed(void);
671STATIC_SUN void sun_set_pcylcount(void);
672#endif
673STATIC_SUN void toggle_sunflags(int i, unsigned char mask);
674STATIC_SUN void verify_sun(void);
675STATIC_SUN void sun_write_table(void);
676#include "fdisk_sun.c"
677
678
679#if ENABLE_FEATURE_FDISK_WRITABLE
680
681
682static void
683store4_little_endian(unsigned char *cp, unsigned val)
684{
685 cp[0] = val;
686 cp[1] = val >> 8;
687 cp[2] = val >> 16;
688 cp[3] = val >> 24;
689}
690#endif
691
692static unsigned
693read4_little_endian(const unsigned char *cp)
694{
695 return cp[0] + (cp[1] << 8) + (cp[2] << 16) + (cp[3] << 24);
696}
697
698#if ENABLE_FEATURE_FDISK_WRITABLE
699static void
700set_start_sect(struct partition *p, unsigned start_sect)
701{
702 store4_little_endian(p->start4, start_sect);
703}
704#endif
705
706static unsigned
707get_start_sect(const struct partition *p)
708{
709 return read4_little_endian(p->start4);
710}
711
712#if ENABLE_FEATURE_FDISK_WRITABLE
713static void
714set_nr_sects(struct partition *p, unsigned nr_sects)
715{
716 store4_little_endian(p->size4, nr_sects);
717}
718#endif
719
720static unsigned
721get_nr_sects(const struct partition *p)
722{
723 return read4_little_endian(p->size4);
724}
725
726
727static void
728read_pte(struct pte *pe, ullong offset)
729{
730 pe->offset = offset;
731 pe->sectorbuffer = xzalloc(sector_size);
732 seek_sector(offset);
733
734 if (full_read(dev_fd, pe->sectorbuffer, sector_size) != sector_size)
735 fdisk_fatal(unable_to_read);
736#if ENABLE_FEATURE_FDISK_WRITABLE
737 pe->changed = 0;
738#endif
739 pe->part_table = pe->ext_pointer = NULL;
740}
741
742static unsigned
743get_partition_start(const struct pte *pe)
744{
745 return pe->offset + get_start_sect(pe->part_table);
746}
747
748#if ENABLE_FEATURE_FDISK_WRITABLE
749
750
751
752
753
754
755#ifdef UNUSED
756static int
757is_dos_partition(int t)
758{
759 return (t == 1 || t == 4 || t == 6 ||
760 t == 0x0b || t == 0x0c || t == 0x0e ||
761 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
762 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
763 t == 0xc1 || t == 0xc4 || t == 0xc6);
764}
765#endif
766
767static void
768menu(void)
769{
770 puts("Command Action");
771 if (LABEL_IS_SUN) {
772 puts("a\ttoggle a read only flag");
773 puts("b\tedit bsd disklabel");
774 puts("c\ttoggle the mountable flag");
775 puts("d\tdelete a partition");
776 puts("l\tlist known partition types");
777 puts("n\tadd a new partition");
778 puts("o\tcreate a new empty DOS partition table");
779 puts("p\tprint the partition table");
780 puts("q\tquit without saving changes");
781 puts("s\tcreate a new empty Sun disklabel");
782 puts("t\tchange a partition's system id");
783 puts("u\tchange display/entry units");
784 puts("v\tverify the partition table");
785 puts("w\twrite table to disk and exit");
786#if ENABLE_FEATURE_FDISK_ADVANCED
787 puts("x\textra functionality (experts only)");
788#endif
789 } else if (LABEL_IS_SGI) {
790 puts("a\tselect bootable partition");
791 puts("b\tedit bootfile entry");
792 puts("c\tselect sgi swap partition");
793 puts("d\tdelete a partition");
794 puts("l\tlist known partition types");
795 puts("n\tadd a new partition");
796 puts("o\tcreate a new empty DOS partition table");
797 puts("p\tprint the partition table");
798 puts("q\tquit without saving changes");
799 puts("s\tcreate a new empty Sun disklabel");
800 puts("t\tchange a partition's system id");
801 puts("u\tchange display/entry units");
802 puts("v\tverify the partition table");
803 puts("w\twrite table to disk and exit");
804 } else if (LABEL_IS_AIX) {
805 puts("o\tcreate a new empty DOS partition table");
806 puts("q\tquit without saving changes");
807 puts("s\tcreate a new empty Sun disklabel");
808 } else {
809 puts("a\ttoggle a bootable flag");
810 puts("b\tedit bsd disklabel");
811 puts("c\ttoggle the dos compatibility flag");
812 puts("d\tdelete a partition");
813 puts("l\tlist known partition types");
814 puts("n\tadd a new partition");
815 puts("o\tcreate a new empty DOS partition table");
816 puts("p\tprint the partition table");
817 puts("q\tquit without saving changes");
818 puts("s\tcreate a new empty Sun disklabel");
819 puts("t\tchange a partition's system id");
820 puts("u\tchange display/entry units");
821 puts("v\tverify the partition table");
822 puts("w\twrite table to disk and exit");
823#if ENABLE_FEATURE_FDISK_ADVANCED
824 puts("x\textra functionality (experts only)");
825#endif
826 }
827}
828#endif
829
830
831#if ENABLE_FEATURE_FDISK_ADVANCED
832static void
833xmenu(void)
834{
835 puts("Command Action");
836 if (LABEL_IS_SUN) {
837 puts("a\tchange number of alternate cylinders");
838 puts("c\tchange number of cylinders");
839 puts("d\tprint the raw data in the partition table");
840 puts("e\tchange number of extra sectors per cylinder");
841 puts("h\tchange number of heads");
842 puts("i\tchange interleave factor");
843 puts("o\tchange rotation speed (rpm)");
844 puts("p\tprint the partition table");
845 puts("q\tquit without saving changes");
846 puts("r\treturn to main menu");
847 puts("s\tchange number of sectors/track");
848 puts("v\tverify the partition table");
849 puts("w\twrite table to disk and exit");
850 puts("y\tchange number of physical cylinders");
851 } else if (LABEL_IS_SGI) {
852 puts("b\tmove beginning of data in a partition");
853 puts("c\tchange number of cylinders");
854 puts("d\tprint the raw data in the partition table");
855 puts("e\tlist extended partitions");
856 puts("g\tcreate an IRIX (SGI) partition table");
857 puts("h\tchange number of heads");
858 puts("p\tprint the partition table");
859 puts("q\tquit without saving changes");
860 puts("r\treturn to main menu");
861 puts("s\tchange number of sectors/track");
862 puts("v\tverify the partition table");
863 puts("w\twrite table to disk and exit");
864 } else if (LABEL_IS_AIX) {
865 puts("b\tmove beginning of data in a partition");
866 puts("c\tchange number of cylinders");
867 puts("d\tprint the raw data in the partition table");
868 puts("e\tlist extended partitions");
869 puts("g\tcreate an IRIX (SGI) partition table");
870 puts("h\tchange number of heads");
871 puts("p\tprint the partition table");
872 puts("q\tquit without saving changes");
873 puts("r\treturn to main menu");
874 puts("s\tchange number of sectors/track");
875 puts("v\tverify the partition table");
876 puts("w\twrite table to disk and exit");
877 } else {
878 puts("b\tmove beginning of data in a partition");
879 puts("c\tchange number of cylinders");
880 puts("d\tprint the raw data in the partition table");
881 puts("e\tlist extended partitions");
882 puts("f\tfix partition order");
883#if ENABLE_FEATURE_SGI_LABEL
884 puts("g\tcreate an IRIX (SGI) partition table");
885#endif
886 puts("h\tchange number of heads");
887 puts("p\tprint the partition table");
888 puts("q\tquit without saving changes");
889 puts("r\treturn to main menu");
890 puts("s\tchange number of sectors/track");
891 puts("v\tverify the partition table");
892 puts("w\twrite table to disk and exit");
893 }
894}
895#endif
896
897#if ENABLE_FEATURE_FDISK_WRITABLE
898static const char *const *
899get_sys_types(void)
900{
901 return (
902 LABEL_IS_SUN ? sun_sys_types :
903 LABEL_IS_SGI ? sgi_sys_types :
904 i386_sys_types);
905}
906#else
907#define get_sys_types() i386_sys_types
908#endif
909
910static const char *
911partition_type(unsigned char type)
912{
913 int i;
914 const char *const *types = get_sys_types();
915
916 for (i = 0; types[i]; i++)
917 if ((unsigned char)types[i][0] == type)
918 return types[i] + 1;
919
920 return "Unknown";
921}
922
923
924#if ENABLE_FEATURE_FDISK_WRITABLE
925static int
926get_sysid(int i)
927{
928 return LABEL_IS_SUN ? sunlabel->infos[i].id :
929 (LABEL_IS_SGI ? sgi_get_sysid(i) :
930 ptes[i].part_table->sys_ind);
931}
932
933static void
934list_types(const char *const *sys)
935{
936 enum { COLS = 3 };
937
938 unsigned last[COLS];
939 unsigned done, next, size;
940 int i;
941
942 for (size = 0; sys[size]; size++)
943 continue;
944
945 done = 0;
946 for (i = COLS-1; i >= 0; i--) {
947 done += (size + i - done) / (i + 1);
948 last[COLS-1 - i] = done;
949 }
950
951 i = done = next = 0;
952 do {
953 printf("%c%2x %-22.22s", i ? ' ' : '\n',
954 (unsigned char)sys[next][0],
955 sys[next] + 1);
956 next = last[i++] + done;
957 if (i >= COLS || next >= last[i]) {
958 i = 0;
959 next = ++done;
960 }
961 } while (done < last[0]);
962 bb_putchar('\n');
963}
964#endif
965
966static int
967is_cleared_partition(const struct partition *p)
968{
969 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
970 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
971 get_start_sect(p) || get_nr_sects(p));
972}
973
974static void
975clear_partition(struct partition *p)
976{
977 if (!p)
978 return;
979 memset(p, 0, sizeof(struct partition));
980}
981
982#if ENABLE_FEATURE_FDISK_WRITABLE
983static void
984set_partition(int i, int doext, ullong start, ullong stop, int sysid)
985{
986 struct partition *p;
987 ullong offset;
988
989 if (doext) {
990 p = ptes[i].ext_pointer;
991 offset = extended_offset;
992 } else {
993 p = ptes[i].part_table;
994 offset = ptes[i].offset;
995 }
996 p->boot_ind = 0;
997 p->sys_ind = sysid;
998 set_start_sect(p, start - offset);
999 set_nr_sects(p, stop - start + 1);
1000 if (dos_compatible_flag && (start / (g_sectors * g_heads) > 1023))
1001 start = g_heads * g_sectors * 1024 - 1;
1002 set_hsc(p->head, p->sector, p->cyl, start);
1003 if (dos_compatible_flag && (stop / (g_sectors * g_heads) > 1023))
1004 stop = g_heads * g_sectors * 1024 - 1;
1005 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
1006 ptes[i].changed = 1;
1007}
1008#endif
1009
1010static int
1011warn_geometry(void)
1012{
1013 if (g_heads && g_sectors && g_cylinders)
1014 return 0;
1015
1016 printf("Unknown value(s) for:");
1017 if (!g_heads)
1018 printf(" heads");
1019 if (!g_sectors)
1020 printf(" sectors");
1021 if (!g_cylinders)
1022 printf(" cylinders");
1023 printf(
1024#if ENABLE_FEATURE_FDISK_WRITABLE
1025 " (settable in the extra functions menu)"
1026#endif
1027 "\n");
1028 return 1;
1029}
1030
1031static void
1032update_units(void)
1033{
1034 int cyl_units = g_heads * g_sectors;
1035
1036 if (display_in_cyl_units && cyl_units)
1037 units_per_sector = cyl_units;
1038 else
1039 units_per_sector = 1;
1040}
1041
1042#if ENABLE_FEATURE_FDISK_WRITABLE
1043static void
1044warn_cylinders(void)
1045{
1046 if (LABEL_IS_DOS && g_cylinders > 1024 && !nowarn)
1047 printf("\n"
1048"The number of cylinders for this disk is set to %d.\n"
1049"There is nothing wrong with that, but this is larger than 1024,\n"
1050"and could in certain setups cause problems with:\n"
1051"1) software that runs at boot time (e.g., old versions of LILO)\n"
1052"2) booting and partitioning software from other OSs\n"
1053" (e.g., DOS FDISK, OS/2 FDISK)\n",
1054 g_cylinders);
1055}
1056#endif
1057
1058static void
1059read_extended(int ext)
1060{
1061 int i;
1062 struct pte *pex;
1063 struct partition *p, *q;
1064
1065 ext_index = ext;
1066 pex = &ptes[ext];
1067 pex->ext_pointer = pex->part_table;
1068
1069 p = pex->part_table;
1070 if (!get_start_sect(p)) {
1071 printf("Bad offset in primary extended partition\n");
1072 return;
1073 }
1074
1075 while (IS_EXTENDED(p->sys_ind)) {
1076 struct pte *pe = &ptes[g_partitions];
1077
1078 if (g_partitions >= MAXIMUM_PARTS) {
1079
1080
1081
1082 struct pte *pre = &ptes[g_partitions - 1];
1083#if ENABLE_FEATURE_FDISK_WRITABLE
1084 printf("Warning: deleting partitions after %d\n",
1085 g_partitions);
1086 pre->changed = 1;
1087#endif
1088 clear_partition(pre->ext_pointer);
1089 return;
1090 }
1091
1092 read_pte(pe, extended_offset + get_start_sect(p));
1093
1094 if (!extended_offset)
1095 extended_offset = get_start_sect(p);
1096
1097 q = p = pt_offset(pe->sectorbuffer, 0);
1098 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
1099 if (IS_EXTENDED(p->sys_ind)) {
1100 if (pe->ext_pointer)
1101 printf("Warning: extra link "
1102 "pointer in partition table"
1103 " %d\n", g_partitions + 1);
1104 else
1105 pe->ext_pointer = p;
1106 } else if (p->sys_ind) {
1107 if (pe->part_table)
1108 printf("Warning: ignoring extra "
1109 "data in partition table"
1110 " %d\n", g_partitions + 1);
1111 else
1112 pe->part_table = p;
1113 }
1114 }
1115
1116
1117 if (!pe->part_table) {
1118 if (q != pe->ext_pointer)
1119 pe->part_table = q;
1120 else
1121 pe->part_table = q + 1;
1122 }
1123 if (!pe->ext_pointer) {
1124 if (q != pe->part_table)
1125 pe->ext_pointer = q;
1126 else
1127 pe->ext_pointer = q + 1;
1128 }
1129
1130 p = pe->ext_pointer;
1131 g_partitions++;
1132 }
1133
1134#if ENABLE_FEATURE_FDISK_WRITABLE
1135
1136 remove:
1137 for (i = 4; i < g_partitions; i++) {
1138 struct pte *pe = &ptes[i];
1139
1140 if (!get_nr_sects(pe->part_table)
1141 && (g_partitions > 5 || ptes[4].part_table->sys_ind)
1142 ) {
1143 printf("Omitting empty partition (%d)\n", i+1);
1144 delete_partition(i);
1145 goto remove;
1146 }
1147 }
1148#endif
1149}
1150
1151#if ENABLE_FEATURE_FDISK_WRITABLE
1152static void
1153create_doslabel(void)
1154{
1155 int i;
1156
1157 printf(msg_building_new_label, "DOS disklabel");
1158
1159 current_label_type = LABEL_DOS;
1160
1161#if ENABLE_FEATURE_OSF_LABEL
1162 possibly_osf_label = 0;
1163#endif
1164 g_partitions = 4;
1165
1166 for (i = 510-64; i < 510; i++)
1167 MBRbuffer[i] = 0;
1168 write_part_table_flag(MBRbuffer);
1169 extended_offset = 0;
1170 set_all_unchanged();
1171 set_changed(0);
1172 get_boot(CREATE_EMPTY_DOS);
1173}
1174#endif
1175
1176static void
1177get_sectorsize(void)
1178{
1179 if (!user_set_sector_size) {
1180 int arg;
1181 if (ioctl(dev_fd, BLKSSZGET, &arg) == 0)
1182 sector_size = arg;
1183 if (sector_size != DEFAULT_SECTOR_SIZE)
1184 printf("Note: sector size is %d "
1185 "(not " DEFAULT_SECTOR_SIZE_STR ")\n",
1186 sector_size);
1187 }
1188}
1189
1190static void
1191get_kernel_geometry(void)
1192{
1193 struct hd_geometry geometry;
1194
1195 if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) {
1196 kern_heads = geometry.heads;
1197 kern_sectors = geometry.sectors;
1198
1199 }
1200}
1201
1202static void
1203get_partition_table_geometry(void)
1204{
1205 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
1206 struct partition *p;
1207 int i, h, s, hh, ss;
1208 int first = 1;
1209 int bad = 0;
1210
1211 if (!(valid_part_table_flag((char*)bufp)))
1212 return;
1213
1214 hh = ss = 0;
1215 for (i = 0; i < 4; i++) {
1216 p = pt_offset(bufp, i);
1217 if (p->sys_ind != 0) {
1218 h = p->end_head + 1;
1219 s = (p->end_sector & 077);
1220 if (first) {
1221 hh = h;
1222 ss = s;
1223 first = 0;
1224 } else if (hh != h || ss != s)
1225 bad = 1;
1226 }
1227 }
1228
1229 if (!first && !bad) {
1230 pt_heads = hh;
1231 pt_sectors = ss;
1232 }
1233}
1234
1235static void
1236get_geometry(void)
1237{
1238 int sec_fac;
1239
1240 get_sectorsize();
1241 sec_fac = sector_size / 512;
1242#if ENABLE_FEATURE_SUN_LABEL
1243 guess_device_type();
1244#endif
1245 g_heads = g_cylinders = g_sectors = 0;
1246 kern_heads = kern_sectors = 0;
1247 pt_heads = pt_sectors = 0;
1248
1249 get_kernel_geometry();
1250 get_partition_table_geometry();
1251
1252 g_heads = user_heads ? user_heads :
1253 pt_heads ? pt_heads :
1254 kern_heads ? kern_heads : 255;
1255 g_sectors = user_sectors ? user_sectors :
1256 pt_sectors ? pt_sectors :
1257 kern_sectors ? kern_sectors : 63;
1258 total_number_of_sectors = bb_BLKGETSIZE_sectors(dev_fd);
1259
1260 sector_offset = 1;
1261 if (dos_compatible_flag)
1262 sector_offset = g_sectors;
1263
1264 g_cylinders = total_number_of_sectors / (g_heads * g_sectors * sec_fac);
1265 if (!g_cylinders)
1266 g_cylinders = user_cylinders;
1267}
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277#if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
1278static int get_boot(enum action what)
1279#else
1280static int get_boot(void)
1281#define get_boot(what) get_boot()
1282#endif
1283{
1284 int i, fd;
1285
1286 g_partitions = 4;
1287 for (i = 0; i < 4; i++) {
1288 struct pte *pe = &ptes[i];
1289 pe->part_table = pt_offset(MBRbuffer, i);
1290 pe->ext_pointer = NULL;
1291 pe->offset = 0;
1292 pe->sectorbuffer = MBRbuffer;
1293#if ENABLE_FEATURE_FDISK_WRITABLE
1294 pe->changed = (what == CREATE_EMPTY_DOS);
1295#endif
1296 }
1297
1298#if ENABLE_FEATURE_FDISK_WRITABLE
1299
1300
1301
1302
1303
1304
1305 if (what == CREATE_EMPTY_DOS USE_FEATURE_SUN_LABEL(|| what == CREATE_EMPTY_SUN))
1306 goto created_table;
1307
1308 fd = open(disk_device, (option_mask32 & OPT_l) ? O_RDONLY : O_RDWR);
1309
1310 if (fd < 0) {
1311 fd = open(disk_device, O_RDONLY);
1312 if (fd < 0) {
1313 if (what == TRY_ONLY)
1314 return 1;
1315 fdisk_fatal(unable_to_open);
1316 }
1317 printf("'%s' is opened for read only\n", disk_device);
1318 }
1319 xmove_fd(fd, dev_fd);
1320 if (512 != full_read(dev_fd, MBRbuffer, 512)) {
1321 if (what == TRY_ONLY) {
1322 close_dev_fd();
1323 return 1;
1324 }
1325 fdisk_fatal(unable_to_read);
1326 }
1327#else
1328 fd = open(disk_device, O_RDONLY);
1329 if (fd < 0)
1330 return 1;
1331 if (512 != full_read(fd, MBRbuffer, 512)) {
1332 close(fd);
1333 return 1;
1334 }
1335 xmove_fd(fd, dev_fd);
1336#endif
1337
1338 get_geometry();
1339 update_units();
1340
1341#if ENABLE_FEATURE_SUN_LABEL
1342 if (check_sun_label())
1343 return 0;
1344#endif
1345#if ENABLE_FEATURE_SGI_LABEL
1346 if (check_sgi_label())
1347 return 0;
1348#endif
1349#if ENABLE_FEATURE_AIX_LABEL
1350 if (check_aix_label())
1351 return 0;
1352#endif
1353#if ENABLE_FEATURE_OSF_LABEL
1354 if (check_osf_label()) {
1355 possibly_osf_label = 1;
1356 if (!valid_part_table_flag(MBRbuffer)) {
1357 current_label_type = LABEL_OSF;
1358 return 0;
1359 }
1360 printf("This disk has both DOS and BSD magic.\n"
1361 "Give the 'b' command to go to BSD mode.\n");
1362 }
1363#endif
1364
1365#if !ENABLE_FEATURE_FDISK_WRITABLE
1366 if (!valid_part_table_flag(MBRbuffer))
1367 return -1;
1368#else
1369 if (!valid_part_table_flag(MBRbuffer)) {
1370 if (what == OPEN_MAIN) {
1371 printf("Device contains neither a valid DOS "
1372 "partition table, nor Sun, SGI or OSF "
1373 "disklabel\n");
1374#ifdef __sparc__
1375 USE_FEATURE_SUN_LABEL(create_sunlabel();)
1376#else
1377 create_doslabel();
1378#endif
1379 return 0;
1380 }
1381
1382 return -1;
1383 }
1384 created_table:
1385#endif
1386
1387
1388 USE_FEATURE_FDISK_WRITABLE(warn_cylinders();)
1389 warn_geometry();
1390
1391 for (i = 0; i < 4; i++) {
1392 if (IS_EXTENDED(ptes[i].part_table->sys_ind)) {
1393 if (g_partitions != 4)
1394 printf("Ignoring extra extended "
1395 "partition %d\n", i + 1);
1396 else
1397 read_extended(i);
1398 }
1399 }
1400
1401 for (i = 3; i < g_partitions; i++) {
1402 struct pte *pe = &ptes[i];
1403 if (!valid_part_table_flag(pe->sectorbuffer)) {
1404 printf("Warning: invalid flag 0x%02x,0x%02x of partition "
1405 "table %d will be corrected by w(rite)\n",
1406 pe->sectorbuffer[510],
1407 pe->sectorbuffer[511],
1408 i + 1);
1409 USE_FEATURE_FDISK_WRITABLE(pe->changed = 1;)
1410 }
1411 }
1412
1413 return 0;
1414}
1415
1416#if ENABLE_FEATURE_FDISK_WRITABLE
1417
1418
1419
1420
1421
1422
1423
1424static unsigned
1425read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, const char *mesg)
1426{
1427 unsigned i;
1428 int default_ok = 1;
1429 const char *fmt = "%s (%u-%u, default %u): ";
1430
1431 if (dflt < low || dflt > high) {
1432 fmt = "%s (%u-%u): ";
1433 default_ok = 0;
1434 }
1435
1436 while (1) {
1437 int use_default = default_ok;
1438
1439
1440 do {
1441 printf(fmt, mesg, low, high, dflt);
1442 read_maybe_empty("");
1443 } while (*line_ptr != '\n' && !isdigit(*line_ptr)
1444 && *line_ptr != '-' && *line_ptr != '+');
1445
1446 if (*line_ptr == '+' || *line_ptr == '-') {
1447 int minus = (*line_ptr == '-');
1448 int absolute = 0;
1449
1450 i = atoi(line_ptr + 1);
1451
1452 while (isdigit(*++line_ptr))
1453 use_default = 0;
1454
1455 switch (*line_ptr) {
1456 case 'c':
1457 case 'C':
1458 if (!display_in_cyl_units)
1459 i *= g_heads * g_sectors;
1460 break;
1461 case 'K':
1462 absolute = 1024;
1463 break;
1464 case 'k':
1465 absolute = 1000;
1466 break;
1467 case 'm':
1468 case 'M':
1469 absolute = 1000000;
1470 break;
1471 case 'g':
1472 case 'G':
1473 absolute = 1000000000;
1474 break;
1475 default:
1476 break;
1477 }
1478 if (absolute) {
1479 ullong bytes;
1480 unsigned long unit;
1481
1482 bytes = (ullong) i * absolute;
1483 unit = sector_size * units_per_sector;
1484 bytes += unit/2;
1485 bytes /= unit;
1486 i = bytes;
1487 }
1488 if (minus)
1489 i = -i;
1490 i += base;
1491 } else {
1492 i = atoi(line_ptr);
1493 while (isdigit(*line_ptr)) {
1494 line_ptr++;
1495 use_default = 0;
1496 }
1497 }
1498 if (use_default) {
1499 i = dflt;
1500 printf("Using default value %u\n", i);
1501 }
1502 if (i >= low && i <= high)
1503 break;
1504 printf("Value is out of range\n");
1505 }
1506 return i;
1507}
1508
1509static int
1510get_partition(int warn, int max)
1511{
1512 struct pte *pe;
1513 int i;
1514
1515 i = read_int(1, 0, max, 0, "Partition number") - 1;
1516 pe = &ptes[i];
1517
1518 if (warn) {
1519 if ((!LABEL_IS_SUN && !LABEL_IS_SGI && !pe->part_table->sys_ind)
1520 || (LABEL_IS_SUN && (!sunlabel->partitions[i].num_sectors || !sunlabel->infos[i].id))
1521 || (LABEL_IS_SGI && !sgi_get_num_sectors(i))
1522 ) {
1523 printf("Warning: partition %d has empty type\n", i+1);
1524 }
1525 }
1526 return i;
1527}
1528
1529static int
1530get_existing_partition(int warn, int max)
1531{
1532 int pno = -1;
1533 int i;
1534
1535 for (i = 0; i < max; i++) {
1536 struct pte *pe = &ptes[i];
1537 struct partition *p = pe->part_table;
1538
1539 if (p && !is_cleared_partition(p)) {
1540 if (pno >= 0)
1541 goto not_unique;
1542 pno = i;
1543 }
1544 }
1545 if (pno >= 0) {
1546 printf("Selected partition %d\n", pno+1);
1547 return pno;
1548 }
1549 printf("No partition is defined yet!\n");
1550 return -1;
1551
1552 not_unique:
1553 return get_partition(warn, max);
1554}
1555
1556static int
1557get_nonexisting_partition(int warn, int max)
1558{
1559 int pno = -1;
1560 int i;
1561
1562 for (i = 0; i < max; i++) {
1563 struct pte *pe = &ptes[i];
1564 struct partition *p = pe->part_table;
1565
1566 if (p && is_cleared_partition(p)) {
1567 if (pno >= 0)
1568 goto not_unique;
1569 pno = i;
1570 }
1571 }
1572 if (pno >= 0) {
1573 printf("Selected partition %d\n", pno+1);
1574 return pno;
1575 }
1576 printf("All primary partitions have been defined already!\n");
1577 return -1;
1578
1579 not_unique:
1580 return get_partition(warn, max);
1581}
1582
1583
1584static void
1585change_units(void)
1586{
1587 display_in_cyl_units = !display_in_cyl_units;
1588 update_units();
1589 printf("Changing display/entry units to %s\n",
1590 str_units(PLURAL));
1591}
1592
1593static void
1594toggle_active(int i)
1595{
1596 struct pte *pe = &ptes[i];
1597 struct partition *p = pe->part_table;
1598
1599 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
1600 printf("WARNING: Partition %d is an extended partition\n", i + 1);
1601 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
1602 pe->changed = 1;
1603}
1604
1605static void
1606toggle_dos_compatibility_flag(void)
1607{
1608 dos_compatible_flag = 1 - dos_compatible_flag;
1609 if (dos_compatible_flag) {
1610 sector_offset = g_sectors;
1611 printf("DOS Compatibility flag is set\n");
1612 } else {
1613 sector_offset = 1;
1614 printf("DOS Compatibility flag is not set\n");
1615 }
1616}
1617
1618static void
1619delete_partition(int i)
1620{
1621 struct pte *pe = &ptes[i];
1622 struct partition *p = pe->part_table;
1623 struct partition *q = pe->ext_pointer;
1624
1625
1626
1627
1628
1629 if (warn_geometry())
1630 return;
1631 pe->changed = 1;
1632
1633 if (LABEL_IS_SUN) {
1634 sun_delete_partition(i);
1635 return;
1636 }
1637 if (LABEL_IS_SGI) {
1638 sgi_delete_partition(i);
1639 return;
1640 }
1641
1642 if (i < 4) {
1643 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
1644 g_partitions = 4;
1645 ptes[ext_index].ext_pointer = NULL;
1646 extended_offset = 0;
1647 }
1648 clear_partition(p);
1649 return;
1650 }
1651
1652 if (!q->sys_ind && i > 4) {
1653
1654 --g_partitions;
1655 --i;
1656 clear_partition(ptes[i].ext_pointer);
1657 ptes[i].changed = 1;
1658 } else {
1659
1660 if (i > 4) {
1661
1662 p = ptes[i-1].ext_pointer;
1663 *p = *q;
1664 set_start_sect(p, get_start_sect(q));
1665 set_nr_sects(p, get_nr_sects(q));
1666 ptes[i-1].changed = 1;
1667 } else if (g_partitions > 5) {
1668
1669 pe = &ptes[5];
1670
1671 if (pe->part_table)
1672 set_start_sect(pe->part_table,
1673 get_partition_start(pe) -
1674 extended_offset);
1675 pe->offset = extended_offset;
1676 pe->changed = 1;
1677 }
1678
1679 if (g_partitions > 5) {
1680 g_partitions--;
1681 while (i < g_partitions) {
1682 ptes[i] = ptes[i+1];
1683 i++;
1684 }
1685 } else
1686
1687 clear_partition(ptes[i].part_table);
1688 }
1689}
1690
1691static void
1692change_sysid(void)
1693{
1694 int i, sys, origsys;
1695 struct partition *p;
1696
1697
1698
1699
1700 if (!LABEL_IS_SGI) {
1701 i = get_existing_partition(0, g_partitions);
1702 } else {
1703 i = get_partition(0, g_partitions);
1704 }
1705 if (i == -1)
1706 return;
1707 p = ptes[i].part_table;
1708 origsys = sys = get_sysid(i);
1709
1710
1711
1712 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN && !get_nr_sects(p)) {
1713 printf("Partition %d does not exist yet!\n", i + 1);
1714 return;
1715 }
1716 while (1) {
1717 sys = read_hex(get_sys_types());
1718
1719 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN) {
1720 printf("Type 0 means free space to many systems\n"
1721 "(but not to Linux). Having partitions of\n"
1722 "type 0 is probably unwise.\n");
1723
1724 }
1725
1726 if (!LABEL_IS_SUN && !LABEL_IS_SGI) {
1727 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
1728 printf("You cannot change a partition into"
1729 " an extended one or vice versa\n");
1730 break;
1731 }
1732 }
1733
1734 if (sys < 256) {
1735#if ENABLE_FEATURE_SUN_LABEL
1736 if (LABEL_IS_SUN && i == 2 && sys != SUN_WHOLE_DISK)
1737 printf("Consider leaving partition 3 "
1738 "as Whole disk (5),\n"
1739 "as SunOS/Solaris expects it and "
1740 "even Linux likes it\n\n");
1741#endif
1742#if ENABLE_FEATURE_SGI_LABEL
1743 if (LABEL_IS_SGI &&
1744 (
1745 (i == 10 && sys != SGI_ENTIRE_DISK) ||
1746 (i == 8 && sys != 0)
1747 )
1748 ) {
1749 printf("Consider leaving partition 9 "
1750 "as volume header (0),\nand "
1751 "partition 11 as entire volume (6)"
1752 "as IRIX expects it\n\n");
1753 }
1754#endif
1755 if (sys == origsys)
1756 break;
1757 if (LABEL_IS_SUN) {
1758 sun_change_sysid(i, sys);
1759 } else if (LABEL_IS_SGI) {
1760 sgi_change_sysid(i, sys);
1761 } else
1762 p->sys_ind = sys;
1763
1764 printf("Changed system type of partition %d "
1765 "to %x (%s)\n", i + 1, sys,
1766 partition_type(sys));
1767 ptes[i].changed = 1;
1768
1769
1770 break;
1771 }
1772 }
1773}
1774#endif
1775
1776
1777
1778
1779
1780
1781
1782static void
1783linear2chs(unsigned ls, unsigned *c, unsigned *h, unsigned *s)
1784{
1785 int spc = g_heads * g_sectors;
1786
1787 *c = ls / spc;
1788 ls = ls % spc;
1789 *h = ls / g_sectors;
1790 *s = ls % g_sectors + 1;
1791}
1792
1793static void
1794check_consistency(const struct partition *p, int partition)
1795{
1796 unsigned pbc, pbh, pbs;
1797 unsigned pec, peh, pes;
1798 unsigned lbc, lbh, lbs;
1799 unsigned lec, leh, les;
1800
1801 if (!g_heads || !g_sectors || (partition >= 4))
1802 return;
1803
1804
1805 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
1806 pbh = p->head;
1807 pbs = p->sector & 0x3f;
1808
1809
1810 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
1811 peh = p->end_head;
1812 pes = p->end_sector & 0x3f;
1813
1814
1815 linear2chs(get_start_sect(p), &lbc, &lbh, &lbs);
1816
1817
1818 linear2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
1819
1820
1821 if (g_cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
1822 printf("Partition %d has different physical/logical "
1823 "beginnings (non-Linux?):\n", partition + 1);
1824 printf(" phys=(%d, %d, %d) ", pbc, pbh, pbs);
1825 printf("logical=(%d, %d, %d)\n", lbc, lbh, lbs);
1826 }
1827
1828
1829 if (g_cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
1830 printf("Partition %d has different physical/logical "
1831 "endings:\n", partition + 1);
1832 printf(" phys=(%d, %d, %d) ", pec, peh, pes);
1833 printf("logical=(%d, %d, %d)\n", lec, leh, les);
1834 }
1835
1836
1837 if (peh != (g_heads - 1) || pes != g_sectors) {
1838 printf("Partition %i does not end on cylinder boundary\n",
1839 partition + 1);
1840 }
1841}
1842
1843static void
1844list_disk_geometry(void)
1845{
1846 long long bytes = (total_number_of_sectors << 9);
1847 long megabytes = bytes/1000000;
1848
1849 if (megabytes < 10000)
1850 printf("\nDisk %s: %ld MB, %lld bytes\n",
1851 disk_device, megabytes, bytes);
1852 else
1853 printf("\nDisk %s: %ld.%ld GB, %lld bytes\n",
1854 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
1855 printf("%d heads, %d sectors/track, %d cylinders",
1856 g_heads, g_sectors, g_cylinders);
1857 if (units_per_sector == 1)
1858 printf(", total %llu sectors",
1859 total_number_of_sectors / (sector_size/512));
1860 printf("\nUnits = %s of %d * %d = %d bytes\n\n",
1861 str_units(PLURAL),
1862 units_per_sector, sector_size, units_per_sector * sector_size);
1863}
1864
1865
1866
1867
1868
1869
1870static int
1871wrong_p_order(int *prev)
1872{
1873 const struct pte *pe;
1874 const struct partition *p;
1875 ullong last_p_start_pos = 0, p_start_pos;
1876 int i, last_i = 0;
1877
1878 for (i = 0; i < g_partitions; i++) {
1879 if (i == 4) {
1880 last_i = 4;
1881 last_p_start_pos = 0;
1882 }
1883 pe = &ptes[i];
1884 p = pe->part_table;
1885 if (p->sys_ind) {
1886 p_start_pos = get_partition_start(pe);
1887
1888 if (last_p_start_pos > p_start_pos) {
1889 if (prev)
1890 *prev = last_i;
1891 return i;
1892 }
1893
1894 last_p_start_pos = p_start_pos;
1895 last_i = i;
1896 }
1897 }
1898 return 0;
1899}
1900
1901#if ENABLE_FEATURE_FDISK_ADVANCED
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915static void
1916fix_chain_of_logicals(void)
1917{
1918 int j, oj, ojj, sj, sjj;
1919 struct partition *pj,*pjj,tmp;
1920
1921
1922
1923 stage1:
1924 for (j = 5; j < g_partitions - 1; j++) {
1925 oj = ptes[j].offset;
1926 ojj = ptes[j+1].offset;
1927 if (oj > ojj) {
1928 ptes[j].offset = ojj;
1929 ptes[j+1].offset = oj;
1930 pj = ptes[j].part_table;
1931 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
1932 pjj = ptes[j+1].part_table;
1933 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
1934 set_start_sect(ptes[j-1].ext_pointer,
1935 ojj-extended_offset);
1936 set_start_sect(ptes[j].ext_pointer,
1937 oj-extended_offset);
1938 goto stage1;
1939 }
1940 }
1941
1942
1943 stage2:
1944 for (j = 4; j < g_partitions - 1; j++) {
1945 pj = ptes[j].part_table;
1946 pjj = ptes[j+1].part_table;
1947 sj = get_start_sect(pj);
1948 sjj = get_start_sect(pjj);
1949 oj = ptes[j].offset;
1950 ojj = ptes[j+1].offset;
1951 if (oj+sj > ojj+sjj) {
1952 tmp = *pj;
1953 *pj = *pjj;
1954 *pjj = tmp;
1955 set_start_sect(pj, ojj+sjj-oj);
1956 set_start_sect(pjj, oj+sj-ojj);
1957 goto stage2;
1958 }
1959 }
1960
1961
1962 for (j = 4; j < g_partitions; j++)
1963 ptes[j].changed = 1;
1964}
1965
1966
1967static void
1968fix_partition_table_order(void)
1969{
1970 struct pte *pei, *pek;
1971 int i,k;
1972
1973 if (!wrong_p_order(NULL)) {
1974 printf("Ordering is already correct\n\n");
1975 return;
1976 }
1977
1978 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
1979
1980
1981 struct partition *pi, *pk, *pe, pbuf;
1982 pei = &ptes[i];
1983 pek = &ptes[k];
1984
1985 pe = pei->ext_pointer;
1986 pei->ext_pointer = pek->ext_pointer;
1987 pek->ext_pointer = pe;
1988
1989 pi = pei->part_table;
1990 pk = pek->part_table;
1991
1992 memmove(&pbuf, pi, sizeof(struct partition));
1993 memmove(pi, pk, sizeof(struct partition));
1994 memmove(pk, &pbuf, sizeof(struct partition));
1995
1996 pei->changed = pek->changed = 1;
1997 }
1998
1999 if (i)
2000 fix_chain_of_logicals();
2001
2002 printf("Done.\n");
2003
2004}
2005#endif
2006
2007static void
2008list_table(int xtra)
2009{
2010 const struct partition *p;
2011 int i, w;
2012
2013 if (LABEL_IS_SUN) {
2014 sun_list_table(xtra);
2015 return;
2016 }
2017 if (LABEL_IS_SUN) {
2018 sgi_list_table(xtra);
2019 return;
2020 }
2021
2022 list_disk_geometry();
2023
2024 if (LABEL_IS_OSF) {
2025 xbsd_print_disklabel(xtra);
2026 return;
2027 }
2028
2029
2030
2031
2032 w = strlen(disk_device);
2033 if (w && isdigit(disk_device[w-1]))
2034 w++;
2035 if (w < 5)
2036 w = 5;
2037
2038
2039 printf("%*s Boot Start End Blocks Id System\n",
2040 w+1, "Device");
2041
2042 for (i = 0; i < g_partitions; i++) {
2043 const struct pte *pe = &ptes[i];
2044 ullong psects;
2045 ullong pblocks;
2046 unsigned podd;
2047
2048 p = pe->part_table;
2049 if (!p || is_cleared_partition(p))
2050 continue;
2051
2052 psects = get_nr_sects(p);
2053 pblocks = psects;
2054 podd = 0;
2055
2056 if (sector_size < 1024) {
2057 pblocks /= (1024 / sector_size);
2058 podd = psects % (1024 / sector_size);
2059 }
2060 if (sector_size > 1024)
2061 pblocks *= (sector_size / 1024);
2062
2063 printf("%s %c %11llu %11llu %11llu%c %2x %s\n",
2064 partname(disk_device, i+1, w+2),
2065 !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
2066 ? '*' : '?',
2067 (ullong) cround(get_partition_start(pe)),
2068 (ullong) cround(get_partition_start(pe) + psects
2069 - (psects ? 1 : 0)),
2070 (ullong) pblocks, podd ? '+' : ' ',
2071 p->sys_ind,
2072 partition_type(p->sys_ind));
2073
2074 check_consistency(p, i);
2075 }
2076
2077
2078
2079
2080 if (LABEL_IS_DOS && wrong_p_order(NULL)) {
2081
2082 printf("\nPartition table entries are not in disk order\n");
2083 }
2084}
2085
2086#if ENABLE_FEATURE_FDISK_ADVANCED
2087static void
2088x_list_table(int extend)
2089{
2090 const struct pte *pe;
2091 const struct partition *p;
2092 int i;
2093
2094 printf("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n",
2095 disk_device, g_heads, g_sectors, g_cylinders);
2096 printf("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n");
2097 for (i = 0; i < g_partitions; i++) {
2098 pe = &ptes[i];
2099 p = (extend ? pe->ext_pointer : pe->part_table);
2100 if (p != NULL) {
2101 printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
2102 i + 1, p->boot_ind, p->head,
2103 sector(p->sector),
2104 cylinder(p->sector, p->cyl), p->end_head,
2105 sector(p->end_sector),
2106 cylinder(p->end_sector, p->end_cyl),
2107 get_start_sect(p), get_nr_sects(p), p->sys_ind);
2108 if (p->sys_ind)
2109 check_consistency(p, i);
2110 }
2111 }
2112}
2113#endif
2114
2115#if ENABLE_FEATURE_FDISK_WRITABLE
2116static void
2117fill_bounds(ullong *first, ullong *last)
2118{
2119 int i;
2120 const struct pte *pe = &ptes[0];
2121 const struct partition *p;
2122
2123 for (i = 0; i < g_partitions; pe++,i++) {
2124 p = pe->part_table;
2125 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
2126 first[i] = 0xffffffff;
2127 last[i] = 0;
2128 } else {
2129 first[i] = get_partition_start(pe);
2130 last[i] = first[i] + get_nr_sects(p) - 1;
2131 }
2132 }
2133}
2134
2135static void
2136check(int n, unsigned h, unsigned s, unsigned c, ullong start)
2137{
2138 ullong total, real_s, real_c;
2139
2140 real_s = sector(s) - 1;
2141 real_c = cylinder(s, c);
2142 total = (real_c * g_sectors + real_s) * g_heads + h;
2143 if (!total)
2144 printf("Partition %d contains sector 0\n", n);
2145 if (h >= g_heads)
2146 printf("Partition %d: head %d greater than maximum %d\n",
2147 n, h + 1, g_heads);
2148 if (real_s >= g_sectors)
2149 printf("Partition %d: sector %d greater than "
2150 "maximum %d\n", n, s, g_sectors);
2151 if (real_c >= g_cylinders)
2152 printf("Partition %d: cylinder %llu greater than "
2153 "maximum %d\n", n, real_c + 1, g_cylinders);
2154 if (g_cylinders <= 1024 && start != total)
2155 printf("Partition %d: previous sectors %llu disagrees with "
2156 "total %llu\n", n, start, total);
2157}
2158
2159static void
2160verify(void)
2161{
2162 int i, j;
2163 unsigned total = 1;
2164 ullong first[g_partitions], last[g_partitions];
2165 struct partition *p;
2166
2167 if (warn_geometry())
2168 return;
2169
2170 if (LABEL_IS_SUN) {
2171 verify_sun();
2172 return;
2173 }
2174 if (LABEL_IS_SGI) {
2175 verify_sgi(1);
2176 return;
2177 }
2178
2179 fill_bounds(first, last);
2180 for (i = 0; i < g_partitions; i++) {
2181 struct pte *pe = &ptes[i];
2182
2183 p = pe->part_table;
2184 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
2185 check_consistency(p, i);
2186 if (get_partition_start(pe) < first[i])
2187 printf("Warning: bad start-of-data in "
2188 "partition %d\n", i + 1);
2189 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
2190 last[i]);
2191 total += last[i] + 1 - first[i];
2192 for (j = 0; j < i; j++) {
2193 if ((first[i] >= first[j] && first[i] <= last[j])
2194 || ((last[i] <= last[j] && last[i] >= first[j]))) {
2195 printf("Warning: partition %d overlaps "
2196 "partition %d\n", j + 1, i + 1);
2197 total += first[i] >= first[j] ?
2198 first[i] : first[j];
2199 total -= last[i] <= last[j] ?
2200 last[i] : last[j];
2201 }
2202 }
2203 }
2204 }
2205
2206 if (extended_offset) {
2207 struct pte *pex = &ptes[ext_index];
2208 ullong e_last = get_start_sect(pex->part_table) +
2209 get_nr_sects(pex->part_table) - 1;
2210
2211 for (i = 4; i < g_partitions; i++) {
2212 total++;
2213 p = ptes[i].part_table;
2214 if (!p->sys_ind) {
2215 if (i != 4 || i + 1 < g_partitions)
2216 printf("Warning: partition %d "
2217 "is empty\n", i + 1);
2218 } else if (first[i] < extended_offset || last[i] > e_last) {
2219 printf("Logical partition %d not entirely in "
2220 "partition %d\n", i + 1, ext_index + 1);
2221 }
2222 }
2223 }
2224
2225 if (total > g_heads * g_sectors * g_cylinders)
2226 printf("Total allocated sectors %d greater than the maximum "
2227 "%d\n", total, g_heads * g_sectors * g_cylinders);
2228 else {
2229 total = g_heads * g_sectors * g_cylinders - total;
2230 if (total != 0)
2231 printf("%d unallocated sectors\n", total);
2232 }
2233}
2234
2235static void
2236add_partition(int n, int sys)
2237{
2238 char mesg[256];
2239 int i, num_read = 0;
2240 struct partition *p = ptes[n].part_table;
2241 struct partition *q = ptes[ext_index].part_table;
2242 ullong limit, temp;
2243 ullong start, stop = 0;
2244 ullong first[g_partitions], last[g_partitions];
2245
2246 if (p && p->sys_ind) {
2247 printf(msg_part_already_defined, n + 1);
2248 return;
2249 }
2250 fill_bounds(first, last);
2251 if (n < 4) {
2252 start = sector_offset;
2253 if (display_in_cyl_units || !total_number_of_sectors)
2254 limit = (ullong) g_heads * g_sectors * g_cylinders - 1;
2255 else
2256 limit = total_number_of_sectors - 1;
2257 if (extended_offset) {
2258 first[ext_index] = extended_offset;
2259 last[ext_index] = get_start_sect(q) +
2260 get_nr_sects(q) - 1;
2261 }
2262 } else {
2263 start = extended_offset + sector_offset;
2264 limit = get_start_sect(q) + get_nr_sects(q) - 1;
2265 }
2266 if (display_in_cyl_units)
2267 for (i = 0; i < g_partitions; i++)
2268 first[i] = (cround(first[i]) - 1) * units_per_sector;
2269
2270 snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
2271 do {
2272 temp = start;
2273 for (i = 0; i < g_partitions; i++) {
2274 int lastplusoff;
2275
2276 if (start == ptes[i].offset)
2277 start += sector_offset;
2278 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
2279 if (start >= first[i] && start <= lastplusoff)
2280 start = lastplusoff + 1;
2281 }
2282 if (start > limit)
2283 break;
2284 if (start >= temp+units_per_sector && num_read) {
2285 printf("Sector %lld is already allocated\n", temp);
2286 temp = start;
2287 num_read = 0;
2288 }
2289 if (!num_read && start == temp) {
2290 ullong saved_start;
2291
2292 saved_start = start;
2293 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
2294 0, mesg);
2295 if (display_in_cyl_units) {
2296 start = (start - 1) * units_per_sector;
2297 if (start < saved_start) start = saved_start;
2298 }
2299 num_read = 1;
2300 }
2301 } while (start != temp || !num_read);
2302 if (n > 4) {
2303 struct pte *pe = &ptes[n];
2304
2305 pe->offset = start - sector_offset;
2306 if (pe->offset == extended_offset) {
2307 pe->offset++;
2308 if (sector_offset == 1)
2309 start++;
2310 }
2311 }
2312
2313 for (i = 0; i < g_partitions; i++) {
2314 struct pte *pe = &ptes[i];
2315
2316 if (start < pe->offset && limit >= pe->offset)
2317 limit = pe->offset - 1;
2318 if (start < first[i] && limit >= first[i])
2319 limit = first[i] - 1;
2320 }
2321 if (start > limit) {
2322 printf("No free sectors available\n");
2323 if (n > 4)
2324 g_partitions--;
2325 return;
2326 }
2327 if (cround(start) == cround(limit)) {
2328 stop = limit;
2329 } else {
2330 snprintf(mesg, sizeof(mesg),
2331 "Last %s or +size or +sizeM or +sizeK",
2332 str_units(SINGULAR));
2333 stop = read_int(cround(start), cround(limit), cround(limit),
2334 cround(start), mesg);
2335 if (display_in_cyl_units) {
2336 stop = stop * units_per_sector - 1;
2337 if (stop >limit)
2338 stop = limit;
2339 }
2340 }
2341
2342 set_partition(n, 0, start, stop, sys);
2343 if (n > 4)
2344 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
2345
2346 if (IS_EXTENDED(sys)) {
2347 struct pte *pe4 = &ptes[4];
2348 struct pte *pen = &ptes[n];
2349
2350 ext_index = n;
2351 pen->ext_pointer = p;
2352 pe4->offset = extended_offset = start;
2353 pe4->sectorbuffer = xzalloc(sector_size);
2354 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
2355 pe4->ext_pointer = pe4->part_table + 1;
2356 pe4->changed = 1;
2357 g_partitions = 5;
2358 }
2359}
2360
2361static void
2362add_logical(void)
2363{
2364 if (g_partitions > 5 || ptes[4].part_table->sys_ind) {
2365 struct pte *pe = &ptes[g_partitions];
2366
2367 pe->sectorbuffer = xzalloc(sector_size);
2368 pe->part_table = pt_offset(pe->sectorbuffer, 0);
2369 pe->ext_pointer = pe->part_table + 1;
2370 pe->offset = 0;
2371 pe->changed = 1;
2372 g_partitions++;
2373 }
2374 add_partition(g_partitions - 1, LINUX_NATIVE);
2375}
2376
2377static void
2378new_partition(void)
2379{
2380 int i, free_primary = 0;
2381
2382 if (warn_geometry())
2383 return;
2384
2385 if (LABEL_IS_SUN) {
2386 add_sun_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2387 return;
2388 }
2389 if (LABEL_IS_SGI) {
2390 sgi_add_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2391 return;
2392 }
2393 if (LABEL_IS_AIX) {
2394 printf("Sorry - this fdisk cannot handle AIX disk labels.\n"
2395"If you want to add DOS-type partitions, create a new empty DOS partition\n"
2396"table first (use 'o'). This will destroy the present disk contents.\n");
2397 return;
2398 }
2399
2400 for (i = 0; i < 4; i++)
2401 free_primary += !ptes[i].part_table->sys_ind;
2402
2403 if (!free_primary && g_partitions >= MAXIMUM_PARTS) {
2404 printf("The maximum number of partitions has been created\n");
2405 return;
2406 }
2407
2408 if (!free_primary) {
2409 if (extended_offset)
2410 add_logical();
2411 else
2412 printf("You must delete some partition and add "
2413 "an extended partition first\n");
2414 } else {
2415 char c, line[80];
2416 snprintf(line, sizeof(line),
2417 "Command action\n"
2418 " %s\n"
2419 " p primary partition (1-4)\n",
2420 (extended_offset ?
2421 "l logical (5 or over)" : "e extended"));
2422 while (1) {
2423 c = read_nonempty(line);
2424 if (c == 'p' || c == 'P') {
2425 i = get_nonexisting_partition(0, 4);
2426 if (i >= 0)
2427 add_partition(i, LINUX_NATIVE);
2428 return;
2429 }
2430 if (c == 'l' && extended_offset) {
2431 add_logical();
2432 return;
2433 }
2434 if (c == 'e' && !extended_offset) {
2435 i = get_nonexisting_partition(0, 4);
2436 if (i >= 0)
2437 add_partition(i, EXTENDED);
2438 return;
2439 }
2440 printf("Invalid partition number "
2441 "for type '%c'\n", c);
2442 }
2443 }
2444}
2445
2446static void
2447write_table(void)
2448{
2449 int i;
2450
2451 if (LABEL_IS_DOS) {
2452 for (i = 0; i < 3; i++)
2453 if (ptes[i].changed)
2454 ptes[3].changed = 1;
2455 for (i = 3; i < g_partitions; i++) {
2456 struct pte *pe = &ptes[i];
2457
2458 if (pe->changed) {
2459 write_part_table_flag(pe->sectorbuffer);
2460 write_sector(pe->offset, pe->sectorbuffer);
2461 }
2462 }
2463 }
2464 else if (LABEL_IS_SGI) {
2465
2466 sgi_write_table();
2467 }
2468 else if (LABEL_IS_SUN) {
2469 int needw = 0;
2470
2471 for (i = 0; i < 8; i++)
2472 if (ptes[i].changed)
2473 needw = 1;
2474 if (needw)
2475 sun_write_table();
2476 }
2477
2478 printf("The partition table has been altered!\n\n");
2479 reread_partition_table(1);
2480}
2481
2482static void
2483reread_partition_table(int leave)
2484{
2485 int i;
2486
2487 printf("Calling ioctl() to re-read partition table\n");
2488 sync();
2489
2490 i = ioctl_or_perror(dev_fd, BLKRRPART, NULL,
2491 "WARNING: rereading partition table "
2492 "failed, kernel still uses old table");
2493#if 0
2494 if (dos_changed)
2495 printf(
2496 "\nWARNING: If you have created or modified any DOS 6.x\n"
2497 "partitions, please see the fdisk manual page for additional\n"
2498 "information\n");
2499#endif
2500
2501 if (leave) {
2502 if (ENABLE_FEATURE_CLEAN_UP)
2503 close_dev_fd();
2504 exit(i != 0);
2505 }
2506}
2507#endif
2508
2509#if ENABLE_FEATURE_FDISK_ADVANCED
2510#define MAX_PER_LINE 16
2511static void
2512print_buffer(char *pbuffer)
2513{
2514 int i,l;
2515
2516 for (i = 0, l = 0; i < sector_size; i++, l++) {
2517 if (l == 0)
2518 printf("0x%03X:", i);
2519 printf(" %02X", (unsigned char) pbuffer[i]);
2520 if (l == MAX_PER_LINE - 1) {
2521 bb_putchar('\n');
2522 l = -1;
2523 }
2524 }
2525 if (l > 0)
2526 bb_putchar('\n');
2527 bb_putchar('\n');
2528}
2529
2530static void
2531print_raw(void)
2532{
2533 int i;
2534
2535 printf("Device: %s\n", disk_device);
2536 if (LABEL_IS_SGI || LABEL_IS_SUN)
2537 print_buffer(MBRbuffer);
2538 else {
2539 for (i = 3; i < g_partitions; i++)
2540 print_buffer(ptes[i].sectorbuffer);
2541 }
2542}
2543
2544static void
2545move_begin(int i)
2546{
2547 struct pte *pe = &ptes[i];
2548 struct partition *p = pe->part_table;
2549 ullong new, first;
2550
2551 if (warn_geometry())
2552 return;
2553 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED(p->sys_ind)) {
2554 printf("Partition %d has no data area\n", i + 1);
2555 return;
2556 }
2557 first = get_partition_start(pe);
2558 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
2559 "New beginning of data") - pe->offset;
2560
2561 if (new != get_nr_sects(p)) {
2562 first = get_nr_sects(p) + get_start_sect(p) - new;
2563 set_nr_sects(p, first);
2564 set_start_sect(p, new);
2565 pe->changed = 1;
2566 }
2567}
2568
2569static void
2570xselect(void)
2571{
2572 char c;
2573
2574 while (1) {
2575 bb_putchar('\n');
2576 c = tolower(read_nonempty("Expert command (m for help): "));
2577 switch (c) {
2578 case 'a':
2579 if (LABEL_IS_SUN)
2580 sun_set_alt_cyl();
2581 break;
2582 case 'b':
2583 if (LABEL_IS_DOS)
2584 move_begin(get_partition(0, g_partitions));
2585 break;
2586 case 'c':
2587 user_cylinders = g_cylinders =
2588 read_int(1, g_cylinders, 1048576, 0,
2589 "Number of cylinders");
2590 if (LABEL_IS_SUN)
2591 sun_set_ncyl(g_cylinders);
2592 if (LABEL_IS_DOS)
2593 warn_cylinders();
2594 break;
2595 case 'd':
2596 print_raw();
2597 break;
2598 case 'e':
2599 if (LABEL_IS_SGI)
2600 sgi_set_xcyl();
2601 else if (LABEL_IS_SUN)
2602 sun_set_xcyl();
2603 else if (LABEL_IS_DOS)
2604 x_list_table(1);
2605 break;
2606 case 'f':
2607 if (LABEL_IS_DOS)
2608 fix_partition_table_order();
2609 break;
2610 case 'g':
2611#if ENABLE_FEATURE_SGI_LABEL
2612 create_sgilabel();
2613#endif
2614 break;
2615 case 'h':
2616 user_heads = g_heads = read_int(1, g_heads, 256, 0,
2617 "Number of heads");
2618 update_units();
2619 break;
2620 case 'i':
2621 if (LABEL_IS_SUN)
2622 sun_set_ilfact();
2623 break;
2624 case 'o':
2625 if (LABEL_IS_SUN)
2626 sun_set_rspeed();
2627 break;
2628 case 'p':
2629 if (LABEL_IS_SUN)
2630 list_table(1);
2631 else
2632 x_list_table(0);
2633 break;
2634 case 'q':
2635 if (ENABLE_FEATURE_CLEAN_UP)
2636 close_dev_fd();
2637 bb_putchar('\n');
2638 exit(EXIT_SUCCESS);
2639 case 'r':
2640 return;
2641 case 's':
2642 user_sectors = g_sectors = read_int(1, g_sectors, 63, 0,
2643 "Number of sectors");
2644 if (dos_compatible_flag) {
2645 sector_offset = g_sectors;
2646 printf("Warning: setting sector offset for DOS "
2647 "compatiblity\n");
2648 }
2649 update_units();
2650 break;
2651 case 'v':
2652 verify();
2653 break;
2654 case 'w':
2655 write_table();
2656 break;
2657 case 'y':
2658 if (LABEL_IS_SUN)
2659 sun_set_pcylcount();
2660 break;
2661 default:
2662 xmenu();
2663 }
2664 }
2665}
2666#endif
2667
2668static int
2669is_ide_cdrom_or_tape(const char *device)
2670{
2671 FILE *procf;
2672 char buf[100];
2673 struct stat statbuf;
2674 int is_ide = 0;
2675
2676
2677
2678
2679
2680
2681
2682
2683 if (strncmp("/dev/hd", device, 7))
2684 return 0;
2685
2686 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
2687 procf = fopen_for_read(buf);
2688 if (procf != NULL && fgets(buf, sizeof(buf), procf))
2689 is_ide = (!strncmp(buf, "cdrom", 5) ||
2690 !strncmp(buf, "tape", 4));
2691 else
2692
2693
2694 if (stat(device, &statbuf) == 0)
2695 is_ide = ((statbuf.st_mode & 0222) == 0);
2696
2697 if (procf)
2698 fclose(procf);
2699 return is_ide;
2700}
2701
2702
2703static void
2704open_list_and_close(const char *device, int user_specified)
2705{
2706 int gb;
2707
2708 disk_device = device;
2709 if (setjmp(listingbuf))
2710 return;
2711 if (!user_specified)
2712 if (is_ide_cdrom_or_tape(device))
2713 return;
2714
2715
2716 errno = 0;
2717 gb = get_boot(TRY_ONLY);
2718 if (gb > 0) {
2719
2720
2721
2722 if (user_specified || errno == EACCES)
2723 bb_perror_msg("can't open '%s'", device);
2724 return;
2725 }
2726
2727 if (gb < 0) {
2728 list_disk_geometry();
2729 if (LABEL_IS_AIX)
2730 goto ret;
2731#if ENABLE_FEATURE_OSF_LABEL
2732 if (bsd_trydev(device) < 0)
2733#endif
2734 printf("Disk %s doesn't contain a valid "
2735 "partition table\n", device);
2736 } else {
2737 list_table(0);
2738#if ENABLE_FEATURE_FDISK_WRITABLE
2739 if (!LABEL_IS_SUN && g_partitions > 4) {
2740 delete_partition(ext_index);
2741 }
2742#endif
2743 }
2744 ret:
2745 close_dev_fd();
2746}
2747
2748
2749
2750static void
2751list_devs_in_proc_partititons(void)
2752{
2753 FILE *procpt;
2754 char line[100], ptname[100], devname[120], *s;
2755 int ma, mi, sz;
2756
2757 procpt = fopen_or_warn("/proc/partitions", "r");
2758
2759 while (fgets(line, sizeof(line), procpt)) {
2760 if (sscanf(line, " %d %d %d %[^\n ]",
2761 &ma, &mi, &sz, ptname) != 4)
2762 continue;
2763 for (s = ptname; *s; s++)
2764 continue;
2765 if (isdigit(s[-1]))
2766 continue;
2767 sprintf(devname, "/dev/%s", ptname);
2768 open_list_and_close(devname, 0);
2769 }
2770#if ENABLE_FEATURE_CLEAN_UP
2771 fclose(procpt);
2772#endif
2773}
2774
2775#if ENABLE_FEATURE_FDISK_WRITABLE
2776static void
2777unknown_command(int c)
2778{
2779 printf("%c: unknown command\n", c);
2780}
2781#endif
2782
2783int fdisk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
2784int fdisk_main(int argc, char **argv)
2785{
2786 unsigned opt;
2787
2788
2789
2790
2791
2792
2793
2794
2795 INIT_G();
2796
2797 close_dev_fd();
2798
2799 opt_complementary = "b+:C+:H+:S+";
2800 opt = getopt32(argv, "b:C:H:lS:u" USE_FEATURE_FDISK_BLKSIZE("s"),
2801 §or_size, &user_cylinders, &user_heads, &user_sectors);
2802 argc -= optind;
2803 argv += optind;
2804 if (opt & OPT_b) {
2805
2806
2807
2808
2809 if (sector_size != 512 && sector_size != 1024
2810 && sector_size != 2048)
2811 bb_show_usage();
2812 sector_offset = 2;
2813 user_set_sector_size = 1;
2814 }
2815 if (user_heads <= 0 || user_heads >= 256)
2816 user_heads = 0;
2817 if (user_sectors <= 0 || user_sectors >= 64)
2818 user_sectors = 0;
2819 if (opt & OPT_u)
2820 display_in_cyl_units = 0;
2821
2822#if ENABLE_FEATURE_FDISK_WRITABLE
2823 if (opt & OPT_l) {
2824 nowarn = 1;
2825#endif
2826 if (*argv) {
2827 listing = 1;
2828 do {
2829 open_list_and_close(*argv, 1);
2830 } while (*++argv);
2831 } else {
2832
2833
2834 list_devs_in_proc_partititons();
2835 }
2836 return 0;
2837#if ENABLE_FEATURE_FDISK_WRITABLE
2838 }
2839#endif
2840
2841#if ENABLE_FEATURE_FDISK_BLKSIZE
2842 if (opt & OPT_s) {
2843 int j;
2844
2845 nowarn = 1;
2846 if (argc <= 0)
2847 bb_show_usage();
2848 for (j = 0; j < argc; j++) {
2849 unsigned long long size;
2850 fd = xopen(argv[j], O_RDONLY);
2851 size = bb_BLKGETSIZE_sectors(fd) / 2;
2852 close(fd);
2853 if (argc == 1)
2854 printf("%lld\n", size);
2855 else
2856 printf("%s: %lld\n", argv[j], size);
2857 }
2858 return 0;
2859 }
2860#endif
2861
2862#if ENABLE_FEATURE_FDISK_WRITABLE
2863 if (argc != 1)
2864 bb_show_usage();
2865
2866 disk_device = argv[0];
2867 get_boot(OPEN_MAIN);
2868
2869 if (LABEL_IS_OSF) {
2870
2871 printf("Detected an OSF/1 disklabel on %s, entering "
2872 "disklabel mode\n", disk_device);
2873 bsd_select();
2874
2875 current_label_type = LABEL_DOS;
2876
2877 }
2878
2879 while (1) {
2880 int c;
2881 bb_putchar('\n');
2882 c = tolower(read_nonempty("Command (m for help): "));
2883 switch (c) {
2884 case 'a':
2885 if (LABEL_IS_DOS)
2886 toggle_active(get_partition(1, g_partitions));
2887 else if (LABEL_IS_SUN)
2888 toggle_sunflags(get_partition(1, g_partitions),
2889 0x01);
2890 else if (LABEL_IS_SGI)
2891 sgi_set_bootpartition(
2892 get_partition(1, g_partitions));
2893 else
2894 unknown_command(c);
2895 break;
2896 case 'b':
2897 if (LABEL_IS_SGI) {
2898 printf("\nThe current boot file is: %s\n",
2899 sgi_get_bootfile());
2900 if (read_maybe_empty("Please enter the name of the "
2901 "new boot file: ") == '\n')
2902 printf("Boot file unchanged\n");
2903 else
2904 sgi_set_bootfile(line_ptr);
2905 }
2906#if ENABLE_FEATURE_OSF_LABEL
2907 else
2908 bsd_select();
2909#endif
2910 break;
2911 case 'c':
2912 if (LABEL_IS_DOS)
2913 toggle_dos_compatibility_flag();
2914 else if (LABEL_IS_SUN)
2915 toggle_sunflags(get_partition(1, g_partitions),
2916 0x10);
2917 else if (LABEL_IS_SGI)
2918 sgi_set_swappartition(
2919 get_partition(1, g_partitions));
2920 else
2921 unknown_command(c);
2922 break;
2923 case 'd':
2924 {
2925 int j;
2926
2927
2928
2929
2930 if (!LABEL_IS_SGI) {
2931 j = get_existing_partition(1, g_partitions);
2932 } else {
2933 j = get_partition(1, g_partitions);
2934 }
2935 if (j >= 0)
2936 delete_partition(j);
2937 }
2938 break;
2939 case 'i':
2940 if (LABEL_IS_SGI)
2941 create_sgiinfo();
2942 else
2943 unknown_command(c);
2944 case 'l':
2945 list_types(get_sys_types());
2946 break;
2947 case 'm':
2948 menu();
2949 break;
2950 case 'n':
2951 new_partition();
2952 break;
2953 case 'o':
2954 create_doslabel();
2955 break;
2956 case 'p':
2957 list_table(0);
2958 break;
2959 case 'q':
2960 if (ENABLE_FEATURE_CLEAN_UP)
2961 close_dev_fd();
2962 bb_putchar('\n');
2963 return 0;
2964 case 's':
2965#if ENABLE_FEATURE_SUN_LABEL
2966 create_sunlabel();
2967#endif
2968 break;
2969 case 't':
2970 change_sysid();
2971 break;
2972 case 'u':
2973 change_units();
2974 break;
2975 case 'v':
2976 verify();
2977 break;
2978 case 'w':
2979 write_table();
2980 break;
2981#if ENABLE_FEATURE_FDISK_ADVANCED
2982 case 'x':
2983 if (LABEL_IS_SGI) {
2984 printf("\n\tSorry, no experts menu for SGI "
2985 "partition tables available\n\n");
2986 } else
2987 xselect();
2988 break;
2989#endif
2990 default:
2991 unknown_command(c);
2992 menu();
2993 }
2994 }
2995 return 0;
2996#endif
2997}
2998