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