Magellan Linux

Annotation of /trunk/mkinitrd-magellan/busybox/util-linux/fdisk.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 816 - (hide annotations) (download)
Fri Apr 24 18:33:46 2009 UTC (15 years, 1 month ago) by niro
File MIME type: text/plain
File size: 74546 byte(s)
-updated to busybox-1.13.4
1 niro 532 /* vi: set sw=4 ts=4: */
2     /* fdisk.c -- Partition table manipulator for Linux.
3     *
4     * Copyright (C) 1992 A. V. Le Blanc (LeBlanc@mcc.ac.uk)
5     * Copyright (C) 2001,2002 Vladimir Oleynik <dzo@simtreas.ru> (initial bb port)
6     *
7     * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
8     */
9    
10 niro 816 #ifndef _LARGEFILE64_SOURCE
11     /* For lseek64 */
12     #define _LARGEFILE64_SOURCE
13     #endif
14 niro 532 #include <assert.h> /* assert */
15 niro 816 #include "libbb.h"
16 niro 532
17     /* Looks like someone forgot to add this to config system */
18     #ifndef ENABLE_FEATURE_FDISK_BLKSIZE
19     # define ENABLE_FEATURE_FDISK_BLKSIZE 0
20     # define USE_FEATURE_FDISK_BLKSIZE(a)
21     #endif
22    
23 niro 816 #define DEFAULT_SECTOR_SIZE 512
24     #define DEFAULT_SECTOR_SIZE_STR "512"
25     #define MAX_SECTOR_SIZE 2048
26     #define SECTOR_SIZE 512 /* still used in osf/sgi/sun code */
27     #define MAXIMUM_PARTS 60
28 niro 532
29 niro 816 #define ACTIVE_FLAG 0x80
30 niro 532
31 niro 816 #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 niro 532
40    
41 niro 816 enum {
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 niro 532
51    
52 niro 816 /* Used for sector numbers. Today's disk sizes make it necessary */
53     typedef unsigned long long ullong;
54    
55 niro 532 struct 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 /* get device geometry */
63    
64 niro 816 static 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 niro 532
69 niro 816 static const char msg_part_already_defined[] ALIGN1 =
70     "Partition %d is already defined, delete it before re-adding\n";
71 niro 532
72    
73     struct partition {
74     unsigned char boot_ind; /* 0x80 - active */
75     unsigned char head; /* starting head */
76     unsigned char sector; /* starting sector */
77     unsigned char cyl; /* starting cylinder */
78 niro 816 unsigned char sys_ind; /* what partition type */
79 niro 532 unsigned char end_head; /* end head */
80     unsigned char end_sector; /* end sector */
81     unsigned char end_cyl; /* end cylinder */
82     unsigned char start4[4]; /* starting sector counting from 0 */
83     unsigned char size4[4]; /* nr of sectors in partition */
84 niro 816 } PACKED;
85 niro 532
86 niro 816 static const char unable_to_open[] ALIGN1 = "can't open %s";
87     static const char unable_to_read[] ALIGN1 = "can't read from %s";
88     static const char unable_to_seek[] ALIGN1 = "can't seek on %s";
89 niro 532
90     enum label_type {
91 niro 816 LABEL_DOS, LABEL_SUN, LABEL_SGI, LABEL_AIX, LABEL_OSF
92 niro 532 };
93    
94 niro 816 #define LABEL_IS_DOS (LABEL_DOS == current_label_type)
95    
96 niro 532 #if ENABLE_FEATURE_SUN_LABEL
97 niro 816 #define LABEL_IS_SUN (LABEL_SUN == current_label_type)
98 niro 532 #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 niro 816 #define LABEL_IS_SGI (LABEL_SGI == current_label_type)
106 niro 532 #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 niro 816 #define LABEL_IS_AIX (LABEL_AIX == current_label_type)
114 niro 532 #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 niro 816 #define LABEL_IS_OSF (LABEL_OSF == current_label_type)
122 niro 532 #define STATIC_OSF static
123     #else
124     #define LABEL_IS_OSF 0
125     #define STATIC_OSF extern
126     #endif
127    
128 niro 816 enum action { OPEN_MAIN, TRY_ONLY, CREATE_EMPTY_DOS, CREATE_EMPTY_SUN };
129 niro 532
130 niro 816 static void update_units(void);
131 niro 532 #if ENABLE_FEATURE_FDISK_WRITABLE
132     static void change_units(void);
133     static void reread_partition_table(int leave);
134     static void delete_partition(int i);
135     static int get_partition(int warn, int max);
136 niro 816 static void list_types(const char *const *sys);
137     static unsigned read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, const char *mesg);
138 niro 532 #endif
139     static const char *partition_type(unsigned char type);
140     static void get_geometry(void);
141 niro 816 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
142 niro 532 static int get_boot(enum action what);
143 niro 816 #else
144     static int get_boot(void);
145     #endif
146 niro 532
147     #define PLURAL 0
148     #define SINGULAR 1
149    
150     static unsigned get_start_sect(const struct partition *p);
151     static unsigned get_nr_sects(const struct partition *p);
152    
153     /*
154     * per partition table entry data
155     *
156     * The four primary partitions have the same sectorbuffer (MBRbuffer)
157     * and have NULL ext_pointer.
158     * Each logical partition table entry has two pointers, one for the
159     * partition and one link to the next one.
160     */
161 niro 816 struct pte {
162 niro 532 struct partition *part_table; /* points into sectorbuffer */
163     struct partition *ext_pointer; /* points into sectorbuffer */
164 niro 816 ullong offset; /* disk sector number */
165     char *sectorbuffer; /* disk sector contents */
166 niro 532 #if ENABLE_FEATURE_FDISK_WRITABLE
167     char changed; /* boolean */
168     #endif
169 niro 816 };
170 niro 532
171 niro 816 /* DOS partition types */
172 niro 532
173 niro 816 static const char *const i386_sys_types[] = {
174     "\x00" "Empty",
175     "\x01" "FAT12",
176     "\x04" "FAT16 <32M",
177     "\x05" "Extended", /* DOS 3.3+ extended partition */
178     "\x06" "FAT16", /* DOS 16-bit >=32M */
179     "\x07" "HPFS/NTFS", /* OS/2 IFS, eg, HPFS or NTFS or QNX */
180     "\x0a" "OS/2 Boot Manager",/* OS/2 Boot Manager */
181     "\x0b" "Win95 FAT32",
182     "\x0c" "Win95 FAT32 (LBA)",/* LBA really is 'Extended Int 13h' */
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", /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
197     "\x80" "Old Minix", /* Minix 1.4a and earlier */
198     "\x81" "Minix / old Linux",/* Minix 1.4b and later */
199     "\x82" "Linux swap", /* also Solaris */
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", /* BSDI */
207     "\xa0" "Thinkpad hibernation",
208     "\xa5" "FreeBSD", /* various BSD flavours */
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", /* Intel EFI GUID Partition Table */
218     "\xef" "EFI (FAT-12/16/32)", /* Intel EFI System Partition */
219     "\xf0" "Linux/PA-RISC boot", /* Linux/PA-RISC boot loader */
220     "\xf2" "DOS secondary", /* DOS 3.3+ secondary */
221     "\xfd" "Linux raid autodetect", /* New (2.2.x) raid partition with
222     autodetect using persistent
223     superblock */
224     #if 0 /* ENABLE_WEIRD_PARTITION_TYPES */
225     "\x02" "XENIX root",
226     "\x03" "XENIX usr",
227     "\x08" "AIX", /* AIX boot (AIX -- PS/2 port) or SplitDrive */
228     "\x09" "AIX bootable", /* AIX data or Coherent */
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", /* (or Novell) */
239     "\x52" "CP/M", /* CP/M or Microport SysV/AT */
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", /* (bad block table) */
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 / ...",/* CP/M or Concurrent CP/M or
260     Concurrent DOS or CTOS */
261     "\xde" "Dell Utility", /* Dell PowerEdge Server utilities */
262     "\xdf" "BootIt", /* BootIt EMBRM */
263     "\xe1" "DOS access", /* DOS access or SpeedStor 12-bit FAT
264     extended partition */
265     "\xe3" "DOS R/O", /* DOS R/O or SpeedStor */
266     "\xe4" "SpeedStor", /* SpeedStor 16-bit FAT extended
267     partition < 1024 cyl. */
268     "\xf1" "SpeedStor",
269     "\xf4" "SpeedStor", /* SpeedStor large partition */
270     "\xfe" "LANstep", /* SpeedStor >1024 cyl. or LANstep */
271     "\xff" "BBT", /* Xenix Bad Block Table */
272     #endif
273     NULL
274     };
275    
276     enum {
277     dev_fd = 3 /* the disk */
278     };
279    
280     /* Globals */
281     struct globals {
282     char *line_ptr;
283    
284     const char *disk_device;
285     int g_partitions; // = 4; /* maximum partition + 1 */
286     unsigned units_per_sector; // = 1;
287     unsigned sector_size; // = DEFAULT_SECTOR_SIZE;
288     unsigned user_set_sector_size;
289     unsigned sector_offset; // = 1;
290     unsigned g_heads, g_sectors, g_cylinders;
291     smallint /* enum label_type */ current_label_type;
292     smallint display_in_cyl_units; // = 1;
293     #if ENABLE_FEATURE_OSF_LABEL
294     smallint possibly_osf_label;
295     #endif
296    
297     smallint listing; /* no aborts for fdisk -l */
298     smallint dos_compatible_flag; // = 1;
299 niro 532 #if ENABLE_FEATURE_FDISK_WRITABLE
300 niro 816 //int dos_changed;
301     smallint nowarn; /* no warnings for fdisk -l/-s */
302     #endif
303     int ext_index; /* the prime extended partition */
304     unsigned user_cylinders, user_heads, user_sectors;
305     unsigned pt_heads, pt_sectors;
306     unsigned kern_heads, kern_sectors;
307     ullong extended_offset; /* offset of link pointers */
308     ullong total_number_of_sectors;
309    
310     jmp_buf listingbuf;
311     char line_buffer[80];
312     char partname_buffer[80];
313     /* Raw disk label. For DOS-type partition tables the MBR,
314     * with descriptions of the primary partitions. */
315     char MBRbuffer[MAX_SECTOR_SIZE];
316     /* Partition tables */
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     /* TODO: move to libbb? */
363     static ullong bb_BLKGETSIZE_sectors(int fd)
364     {
365     uint64_t v64;
366     unsigned long longsectors;
367    
368     if (ioctl(fd, BLKGETSIZE64, &v64) == 0) {
369     /* Got bytes, convert to 512 byte sectors */
370     return (v64 >> 9);
371     }
372     /* Needs temp of type long */
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    
406 niro 532 static void
407 niro 816 close_dev_fd(void)
408     {
409     /* Not really closing, but making sure it is open, and to harmless place */
410     xmove_fd(xopen(bb_dev_null, O_RDONLY), dev_fd);
411     }
412    
413     #if ENABLE_FEATURE_FDISK_WRITABLE
414     /* Read line; return 0 or first printable char */
415     static int
416     read_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); /* Ctrl-D or Ctrl-C */
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     * Return partition name - uses static storage
436     */
437     static const char *
438     partname(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     /* devfs kludge - note: fdisk partition names are not supposed
455     to equal kernel names, so there is no reason to do this */
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
473     static void
474 niro 532 set_all_unchanged(void)
475     {
476     int i;
477    
478     for (i = 0; i < MAXIMUM_PARTS; i++)
479     ptes[i].changed = 0;
480     }
481    
482 niro 816 static ALWAYS_INLINE void
483 niro 532 set_changed(int i)
484     {
485     ptes[i].changed = 1;
486     }
487     #endif /* FEATURE_FDISK_WRITABLE */
488    
489 niro 816 static ALWAYS_INLINE struct partition *
490 niro 532 get_part_table(int i)
491     {
492     return ptes[i].part_table;
493     }
494    
495     static const char *
496     str_units(int n)
497     { /* n==1: use singular */
498     if (n == 1)
499 niro 816 return display_in_cyl_units ? "cylinder" : "sector";
500     return display_in_cyl_units ? "cylinders" : "sectors";
501 niro 532 }
502    
503     static int
504     valid_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
510 niro 816 static ALWAYS_INLINE void
511 niro 532 write_part_table_flag(char *b)
512     {
513     b[510] = 0x55;
514     b[511] = 0xaa;
515     }
516    
517     static char
518     read_nonempty(const char *mesg)
519     {
520 niro 816 while (!read_line(mesg))
521     continue;
522 niro 532 return *line_ptr;
523     }
524    
525     static char
526     read_maybe_empty(const char *mesg)
527     {
528 niro 816 if (!read_line(mesg)) {
529 niro 532 line_ptr = line_buffer;
530 niro 816 line_ptr[0] = '\n';
531     line_ptr[1] = '\0';
532 niro 532 }
533 niro 816 return line_ptr[0];
534 niro 532 }
535    
536     static int
537 niro 816 read_hex(const char *const *sys)
538 niro 532 {
539     unsigned long v;
540     while (1) {
541 niro 816 read_nonempty("Hex code (type L to list codes): ");
542 niro 532 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     /* Bad input also triggers this */
549     continue;
550     return v;
551     }
552     }
553     #endif /* FEATURE_FDISK_WRITABLE */
554    
555 niro 816 static 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    
564     static void
565     seek_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
581     static void
582     write_sector(ullong secno, const void *buf)
583     {
584     seek_sector(secno);
585     xwrite(dev_fd, buf, sector_size);
586     }
587     #endif
588    
589    
590 niro 532 #include "fdisk_aix.c"
591    
592     typedef struct {
593     unsigned char info[128]; /* Informative text string */
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]; /* Boot information etc. */
602     unsigned short rspeed; /* Disk rotational speed */
603     unsigned short pcylcount; /* Physical cylinder count */
604     unsigned short sparecyl; /* extra sects per cylinder */
605     unsigned char spare2[4]; /* More magic... */
606     unsigned short ilfact; /* Interleave factor */
607     unsigned short ncyl; /* Data cylinder count */
608     unsigned short nacyl; /* Alt. cylinder count */
609     unsigned short ntrks; /* Tracks per cylinder */
610     unsigned short nsect; /* Sectors per track */
611     unsigned char spare3[4]; /* Even more magic... */
612     struct sun_partinfo {
613     uint32_t start_cylinder;
614     uint32_t num_sectors;
615     } partitions[8];
616     unsigned short magic; /* Magic number */
617     unsigned short csum; /* Label xor'd checksum */
618     } sun_partition;
619     #define sunlabel ((sun_partition *)MBRbuffer)
620     STATIC_OSF void bsd_select(void);
621     STATIC_OSF void xbsd_print_disklabel(int);
622     #include "fdisk_osf.c"
623    
624     #if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL
625     static uint16_t
626     fdisk_swap16(uint16_t x)
627     {
628     return (x << 8) | (x >> 8);
629     }
630    
631     static uint32_t
632     fdisk_swap32(uint32_t x)
633     {
634     return (x << 24) |
635     ((x & 0xFF00) << 8) |
636     ((x & 0xFF0000) >> 8) |
637     (x >> 24);
638     }
639     #endif
640    
641 niro 816 STATIC_SGI const char *const sgi_sys_types[];
642 niro 532 STATIC_SGI unsigned sgi_get_num_sectors(int i);
643     STATIC_SGI int sgi_get_sysid(int i);
644     STATIC_SGI void sgi_delete_partition(int i);
645     STATIC_SGI void sgi_change_sysid(int i, int sys);
646     STATIC_SGI void sgi_list_table(int xtra);
647     #if ENABLE_FEATURE_FDISK_ADVANCED
648     STATIC_SGI void sgi_set_xcyl(void);
649     #endif
650     STATIC_SGI int verify_sgi(int verbose);
651     STATIC_SGI void sgi_add_partition(int n, int sys);
652     STATIC_SGI void sgi_set_swappartition(int i);
653     STATIC_SGI const char *sgi_get_bootfile(void);
654     STATIC_SGI void sgi_set_bootfile(const char* aFile);
655     STATIC_SGI void create_sgiinfo(void);
656     STATIC_SGI void sgi_write_table(void);
657     STATIC_SGI void sgi_set_bootpartition(int i);
658     #include "fdisk_sgi.c"
659    
660 niro 816 STATIC_SUN const char *const sun_sys_types[];
661 niro 532 STATIC_SUN void sun_delete_partition(int i);
662     STATIC_SUN void sun_change_sysid(int i, int sys);
663     STATIC_SUN void sun_list_table(int xtra);
664     STATIC_SUN void add_sun_partition(int n, int sys);
665     #if ENABLE_FEATURE_FDISK_ADVANCED
666     STATIC_SUN void sun_set_alt_cyl(void);
667     STATIC_SUN void sun_set_ncyl(int cyl);
668     STATIC_SUN void sun_set_xcyl(void);
669     STATIC_SUN void sun_set_ilfact(void);
670     STATIC_SUN void sun_set_rspeed(void);
671     STATIC_SUN void sun_set_pcylcount(void);
672     #endif
673     STATIC_SUN void toggle_sunflags(int i, unsigned char mask);
674     STATIC_SUN void verify_sun(void);
675     STATIC_SUN void sun_write_table(void);
676     #include "fdisk_sun.c"
677    
678    
679     #if ENABLE_FEATURE_FDISK_WRITABLE
680     /* start_sect and nr_sects are stored little endian on all machines */
681     /* moreover, they are not aligned correctly */
682     static void
683     store4_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 /* FEATURE_FDISK_WRITABLE */
691    
692     static unsigned
693     read4_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
699     static void
700     set_start_sect(struct partition *p, unsigned start_sect)
701     {
702     store4_little_endian(p->start4, start_sect);
703     }
704     #endif
705    
706     static unsigned
707     get_start_sect(const struct partition *p)
708     {
709     return read4_little_endian(p->start4);
710     }
711    
712     #if ENABLE_FEATURE_FDISK_WRITABLE
713     static void
714     set_nr_sects(struct partition *p, unsigned nr_sects)
715     {
716     store4_little_endian(p->size4, nr_sects);
717     }
718     #endif
719    
720     static unsigned
721     get_nr_sects(const struct partition *p)
722     {
723     return read4_little_endian(p->size4);
724     }
725    
726     /* Allocate a buffer and read a partition table sector */
727     static void
728 niro 816 read_pte(struct pte *pe, ullong offset)
729 niro 532 {
730     pe->offset = offset;
731 niro 816 pe->sectorbuffer = xzalloc(sector_size);
732 niro 532 seek_sector(offset);
733 niro 816 /* xread would make us abort - bad for fdisk -l */
734     if (full_read(dev_fd, pe->sectorbuffer, sector_size) != sector_size)
735 niro 532 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    
742     static unsigned
743     get_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     * Avoid warning about DOS partitions when no DOS partition was changed.
751     * Here a heuristic "is probably dos partition".
752     * We might also do the opposite and warn in all cases except
753     * for "is probably nondos partition".
754     */
755 niro 816 #ifdef UNUSED
756 niro 532 static int
757     is_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 niro 816 #endif
766 niro 532
767     static void
768     menu(void)
769     {
770 niro 816 puts("Command Action");
771 niro 532 if (LABEL_IS_SUN) {
772 niro 816 puts("a\ttoggle a read only flag"); /* sun */
773     puts("b\tedit bsd disklabel");
774     puts("c\ttoggle the mountable flag"); /* sun */
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"); /* sun */
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 niro 532 #if ENABLE_FEATURE_FDISK_ADVANCED
787 niro 816 puts("x\textra functionality (experts only)");
788 niro 532 #endif
789 niro 816 } else if (LABEL_IS_SGI) {
790     puts("a\tselect bootable partition"); /* sgi flavour */
791     puts("b\tedit bootfile entry"); /* sgi */
792     puts("c\tselect sgi swap partition"); /* sgi flavour */
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"); /* sun */
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"); /* sun */
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"); /* sun */
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 niro 532 #if ENABLE_FEATURE_FDISK_ADVANCED
824 niro 816 puts("x\textra functionality (experts only)");
825 niro 532 #endif
826     }
827     }
828     #endif /* FEATURE_FDISK_WRITABLE */
829    
830    
831     #if ENABLE_FEATURE_FDISK_ADVANCED
832     static void
833     xmenu(void)
834     {
835 niro 816 puts("Command Action");
836 niro 532 if (LABEL_IS_SUN) {
837 niro 816 puts("a\tchange number of alternate cylinders"); /*sun*/
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");/*sun*/
841     puts("h\tchange number of heads");
842     puts("i\tchange interleave factor"); /*sun*/
843     puts("o\tchange rotation speed (rpm)"); /*sun*/
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"); /*sun*/
851     } else if (LABEL_IS_SGI) {
852     puts("b\tmove beginning of data in a partition"); /* !sun */
853     puts("c\tchange number of cylinders");
854     puts("d\tprint the raw data in the partition table");
855     puts("e\tlist extended partitions"); /* !sun */
856     puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
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"); /* !sun */
866     puts("c\tchange number of cylinders");
867     puts("d\tprint the raw data in the partition table");
868     puts("e\tlist extended partitions"); /* !sun */
869     puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
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"); /* !sun */
879     puts("c\tchange number of cylinders");
880     puts("d\tprint the raw data in the partition table");
881     puts("e\tlist extended partitions"); /* !sun */
882     puts("f\tfix partition order"); /* !sun, !aix, !sgi */
883 niro 532 #if ENABLE_FEATURE_SGI_LABEL
884 niro 816 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
885 niro 532 #endif
886 niro 816 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 niro 532 }
894     }
895     #endif /* ADVANCED mode */
896    
897     #if ENABLE_FEATURE_FDISK_WRITABLE
898 niro 816 static const char *const *
899 niro 532 get_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 /* FEATURE_FDISK_WRITABLE */
909    
910 niro 816 static const char *
911     partition_type(unsigned char type)
912 niro 532 {
913     int i;
914 niro 816 const char *const *types = get_sys_types();
915 niro 532
916 niro 816 for (i = 0; types[i]; i++)
917     if ((unsigned char)types[i][0] == type)
918     return types[i] + 1;
919 niro 532
920 niro 816 return "Unknown";
921 niro 532 }
922    
923    
924     #if ENABLE_FEATURE_FDISK_WRITABLE
925     static int
926     get_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    
933 niro 816 static void
934     list_types(const char *const *sys)
935 niro 532 {
936 niro 816 enum { COLS = 3 };
937    
938     unsigned last[COLS];
939     unsigned done, next, size;
940 niro 532 int i;
941    
942 niro 816 for (size = 0; sys[size]; size++)
943     continue;
944 niro 532
945 niro 816 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 niro 532
951 niro 816 i = done = next = 0;
952 niro 532 do {
953 niro 816 printf("%c%2x %-22.22s", i ? ' ' : '\n',
954     (unsigned char)sys[next][0],
955     sys[next] + 1);
956 niro 532 next = last[i++] + done;
957 niro 816 if (i >= COLS || next >= last[i]) {
958 niro 532 i = 0;
959     next = ++done;
960     }
961     } while (done < last[0]);
962 niro 816 bb_putchar('\n');
963 niro 532 }
964     #endif /* FEATURE_FDISK_WRITABLE */
965    
966     static int
967     is_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    
974     static void
975     clear_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
983     static void
984 niro 816 set_partition(int i, int doext, ullong start, ullong stop, int sysid)
985 niro 532 {
986     struct partition *p;
987 niro 816 ullong offset;
988 niro 532
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 niro 816 if (dos_compatible_flag && (start / (g_sectors * g_heads) > 1023))
1001     start = g_heads * g_sectors * 1024 - 1;
1002 niro 532 set_hsc(p->head, p->sector, p->cyl, start);
1003 niro 816 if (dos_compatible_flag && (stop / (g_sectors * g_heads) > 1023))
1004     stop = g_heads * g_sectors * 1024 - 1;
1005 niro 532 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
1006     ptes[i].changed = 1;
1007     }
1008     #endif
1009    
1010     static int
1011     warn_geometry(void)
1012     {
1013 niro 816 if (g_heads && g_sectors && g_cylinders)
1014 niro 532 return 0;
1015    
1016 niro 816 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 niro 532 #if ENABLE_FEATURE_FDISK_WRITABLE
1025 niro 816 " (settable in the extra functions menu)"
1026 niro 532 #endif
1027 niro 816 "\n");
1028 niro 532 return 1;
1029     }
1030    
1031 niro 816 static void
1032     update_units(void)
1033 niro 532 {
1034 niro 816 int cyl_units = g_heads * g_sectors;
1035 niro 532
1036     if (display_in_cyl_units && cyl_units)
1037     units_per_sector = cyl_units;
1038     else
1039     units_per_sector = 1; /* in sectors */
1040     }
1041    
1042     #if ENABLE_FEATURE_FDISK_WRITABLE
1043     static void
1044     warn_cylinders(void)
1045     {
1046 niro 816 if (LABEL_IS_DOS && g_cylinders > 1024 && !nowarn)
1047     printf("\n"
1048 niro 532 "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 niro 816 " (e.g., DOS FDISK, OS/2 FDISK)\n",
1054     g_cylinders);
1055 niro 532 }
1056     #endif
1057    
1058     static void
1059     read_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 niro 816 printf("Bad offset in primary extended partition\n");
1072 niro 532 return;
1073     }
1074    
1075     while (IS_EXTENDED(p->sys_ind)) {
1076 niro 816 struct pte *pe = &ptes[g_partitions];
1077 niro 532
1078 niro 816 if (g_partitions >= MAXIMUM_PARTS) {
1079 niro 532 /* This is not a Linux restriction, but
1080     this program uses arrays of size MAXIMUM_PARTS.
1081     Do not try to 'improve' this test. */
1082 niro 816 struct pte *pre = &ptes[g_partitions - 1];
1083 niro 532 #if ENABLE_FEATURE_FDISK_WRITABLE
1084 niro 816 printf("Warning: deleting partitions after %d\n",
1085     g_partitions);
1086 niro 532 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 niro 816 printf("Warning: extra link "
1102 niro 532 "pointer in partition table"
1103 niro 816 " %d\n", g_partitions + 1);
1104 niro 532 else
1105     pe->ext_pointer = p;
1106     } else if (p->sys_ind) {
1107     if (pe->part_table)
1108 niro 816 printf("Warning: ignoring extra "
1109 niro 532 "data in partition table"
1110 niro 816 " %d\n", g_partitions + 1);
1111 niro 532 else
1112     pe->part_table = p;
1113     }
1114     }
1115    
1116     /* very strange code here... */
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 niro 816 g_partitions++;
1132 niro 532 }
1133    
1134     #if ENABLE_FEATURE_FDISK_WRITABLE
1135     /* remove empty links */
1136     remove:
1137 niro 816 for (i = 4; i < g_partitions; i++) {
1138 niro 532 struct pte *pe = &ptes[i];
1139    
1140 niro 816 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 niro 532 delete_partition(i);
1145     goto remove; /* numbering changed */
1146     }
1147     }
1148     #endif
1149     }
1150    
1151     #if ENABLE_FEATURE_FDISK_WRITABLE
1152     static void
1153     create_doslabel(void)
1154     {
1155     int i;
1156    
1157 niro 816 printf(msg_building_new_label, "DOS disklabel");
1158 niro 532
1159 niro 816 current_label_type = LABEL_DOS;
1160 niro 532
1161     #if ENABLE_FEATURE_OSF_LABEL
1162     possibly_osf_label = 0;
1163     #endif
1164 niro 816 g_partitions = 4;
1165 niro 532
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 niro 816 get_boot(CREATE_EMPTY_DOS);
1173 niro 532 }
1174     #endif /* FEATURE_FDISK_WRITABLE */
1175    
1176     static void
1177     get_sectorsize(void)
1178     {
1179     if (!user_set_sector_size) {
1180     int arg;
1181 niro 816 if (ioctl(dev_fd, BLKSSZGET, &arg) == 0)
1182 niro 532 sector_size = arg;
1183     if (sector_size != DEFAULT_SECTOR_SIZE)
1184 niro 816 printf("Note: sector size is %d "
1185     "(not " DEFAULT_SECTOR_SIZE_STR ")\n",
1186     sector_size);
1187 niro 532 }
1188     }
1189    
1190     static void
1191     get_kernel_geometry(void)
1192     {
1193     struct hd_geometry geometry;
1194    
1195 niro 816 if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) {
1196 niro 532 kern_heads = geometry.heads;
1197     kern_sectors = geometry.sectors;
1198     /* never use geometry.cylinders - it is truncated */
1199     }
1200     }
1201    
1202     static void
1203     get_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    
1235     static void
1236     get_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 niro 816 g_heads = g_cylinders = g_sectors = 0;
1246 niro 532 kern_heads = kern_sectors = 0;
1247     pt_heads = pt_sectors = 0;
1248    
1249     get_kernel_geometry();
1250     get_partition_table_geometry();
1251    
1252 niro 816 g_heads = user_heads ? user_heads :
1253 niro 532 pt_heads ? pt_heads :
1254     kern_heads ? kern_heads : 255;
1255 niro 816 g_sectors = user_sectors ? user_sectors :
1256 niro 532 pt_sectors ? pt_sectors :
1257     kern_sectors ? kern_sectors : 63;
1258 niro 816 total_number_of_sectors = bb_BLKGETSIZE_sectors(dev_fd);
1259 niro 532
1260     sector_offset = 1;
1261     if (dos_compatible_flag)
1262 niro 816 sector_offset = g_sectors;
1263 niro 532
1264 niro 816 g_cylinders = total_number_of_sectors / (g_heads * g_sectors * sec_fac);
1265     if (!g_cylinders)
1266     g_cylinders = user_cylinders;
1267 niro 532 }
1268    
1269     /*
1270 niro 816 * Opens disk_device and optionally reads MBR.
1271     * FIXME: document what each 'what' value will do!
1272     * Returns:
1273 niro 532 * -1: no 0xaa55 flag present (possibly entire disk BSD)
1274     * 0: found or created label
1275     * 1: I/O error
1276     */
1277 niro 816 #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
1278     static int get_boot(enum action what)
1279     #else
1280     static int get_boot(void)
1281     #define get_boot(what) get_boot()
1282     #endif
1283 niro 532 {
1284 niro 816 int i, fd;
1285 niro 532
1286 niro 816 g_partitions = 4;
1287 niro 532 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 niro 816 pe->changed = (what == CREATE_EMPTY_DOS);
1295 niro 532 #endif
1296     }
1297    
1298 niro 816 #if ENABLE_FEATURE_FDISK_WRITABLE
1299     // ALERT! highly idiotic design!
1300     // We end up here when we call get_boot() recursively
1301     // via get_boot() [table is bad] -> create_doslabel() -> get_boot(CREATE_EMPTY_DOS).
1302     // or get_boot() [table is bad] -> create_sunlabel() -> get_boot(CREATE_EMPTY_SUN).
1303     // (just factor out re-init of ptes[0,1,2,3] in a separate fn instead?)
1304     // So skip opening device _again_...
1305     if (what == CREATE_EMPTY_DOS USE_FEATURE_SUN_LABEL(|| what == CREATE_EMPTY_SUN))
1306     goto created_table;
1307 niro 532
1308 niro 816 fd = open(disk_device, (option_mask32 & OPT_l) ? O_RDONLY : O_RDWR);
1309 niro 532
1310 niro 816 if (fd < 0) {
1311     fd = open(disk_device, O_RDONLY);
1312     if (fd < 0) {
1313     if (what == TRY_ONLY)
1314 niro 532 return 1;
1315     fdisk_fatal(unable_to_open);
1316 niro 816 }
1317     printf("'%s' is opened for read only\n", disk_device);
1318 niro 532 }
1319 niro 816 xmove_fd(fd, dev_fd);
1320     if (512 != full_read(dev_fd, MBRbuffer, 512)) {
1321     if (what == TRY_ONLY) {
1322     close_dev_fd();
1323 niro 532 return 1;
1324 niro 816 }
1325 niro 532 fdisk_fatal(unable_to_read);
1326     }
1327     #else
1328 niro 816 fd = open(disk_device, O_RDONLY);
1329     if (fd < 0)
1330 niro 532 return 1;
1331 niro 816 if (512 != full_read(fd, MBRbuffer, 512)) {
1332     close(fd);
1333 niro 532 return 1;
1334 niro 816 }
1335     xmove_fd(fd, dev_fd);
1336 niro 532 #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 niro 816 current_label_type = LABEL_OSF;
1358 niro 532 return 0;
1359     }
1360 niro 816 printf("This disk has both DOS and BSD magic.\n"
1361     "Give the 'b' command to go to BSD mode.\n");
1362 niro 532 }
1363     #endif
1364    
1365     #if !ENABLE_FEATURE_FDISK_WRITABLE
1366 niro 816 if (!valid_part_table_flag(MBRbuffer))
1367 niro 532 return -1;
1368     #else
1369 niro 816 if (!valid_part_table_flag(MBRbuffer)) {
1370     if (what == OPEN_MAIN) {
1371     printf("Device contains neither a valid DOS "
1372 niro 532 "partition table, nor Sun, SGI or OSF "
1373 niro 816 "disklabel\n");
1374 niro 532 #ifdef __sparc__
1375 niro 816 USE_FEATURE_SUN_LABEL(create_sunlabel();)
1376 niro 532 #else
1377     create_doslabel();
1378     #endif
1379     return 0;
1380     }
1381 niro 816 /* TRY_ONLY: */
1382     return -1;
1383     }
1384     created_table:
1385 niro 532 #endif /* FEATURE_FDISK_WRITABLE */
1386    
1387 niro 816
1388     USE_FEATURE_FDISK_WRITABLE(warn_cylinders();)
1389 niro 532 warn_geometry();
1390    
1391     for (i = 0; i < 4; i++) {
1392 niro 816 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 niro 532 else
1397     read_extended(i);
1398     }
1399     }
1400    
1401 niro 816 for (i = 3; i < g_partitions; i++) {
1402 niro 532 struct pte *pe = &ptes[i];
1403     if (!valid_part_table_flag(pe->sectorbuffer)) {
1404 niro 816 printf("Warning: invalid flag 0x%02x,0x%02x of partition "
1405     "table %d will be corrected by w(rite)\n",
1406 niro 532 pe->sectorbuffer[510],
1407     pe->sectorbuffer[511],
1408     i + 1);
1409 niro 816 USE_FEATURE_FDISK_WRITABLE(pe->changed = 1;)
1410 niro 532 }
1411     }
1412    
1413     return 0;
1414     }
1415    
1416     #if ENABLE_FEATURE_FDISK_WRITABLE
1417     /*
1418     * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
1419     * If the user hits Enter, DFLT is returned.
1420     * Answers like +10 are interpreted as offsets from BASE.
1421     *
1422     * There is no default if DFLT is not between LOW and HIGH.
1423     */
1424     static unsigned
1425 niro 816 read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, const char *mesg)
1426 niro 532 {
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     /* ask question and read answer */
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 niro 816 i *= g_heads * g_sectors;
1460 niro 532 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 niro 816 ullong bytes;
1480 niro 532 unsigned long unit;
1481    
1482 niro 816 bytes = (ullong) i * absolute;
1483 niro 532 unit = sector_size * units_per_sector;
1484     bytes += unit/2; /* round */
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 niro 816 if (use_default) {
1499     i = dflt;
1500     printf("Using default value %u\n", i);
1501     }
1502 niro 532 if (i >= low && i <= high)
1503     break;
1504 niro 816 printf("Value is out of range\n");
1505 niro 532 }
1506     return i;
1507     }
1508    
1509     static int
1510     get_partition(int warn, int max)
1511     {
1512     struct pte *pe;
1513     int i;
1514    
1515 niro 816 i = read_int(1, 0, max, 0, "Partition number") - 1;
1516 niro 532 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 niro 816 printf("Warning: partition %d has empty type\n", i+1);
1524 niro 532 }
1525     }
1526     return i;
1527     }
1528    
1529     static int
1530     get_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 niro 816 printf("Selected partition %d\n", pno+1);
1547 niro 532 return pno;
1548     }
1549 niro 816 printf("No partition is defined yet!\n");
1550 niro 532 return -1;
1551    
1552     not_unique:
1553     return get_partition(warn, max);
1554     }
1555    
1556     static int
1557     get_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 niro 816 printf("Selected partition %d\n", pno+1);
1574 niro 532 return pno;
1575     }
1576 niro 816 printf("All primary partitions have been defined already!\n");
1577 niro 532 return -1;
1578    
1579     not_unique:
1580     return get_partition(warn, max);
1581     }
1582    
1583    
1584     static void
1585     change_units(void)
1586     {
1587     display_in_cyl_units = !display_in_cyl_units;
1588     update_units();
1589 niro 816 printf("Changing display/entry units to %s\n",
1590 niro 532 str_units(PLURAL));
1591     }
1592    
1593     static void
1594     toggle_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 niro 816 printf("WARNING: Partition %d is an extended partition\n", i + 1);
1601 niro 532 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
1602     pe->changed = 1;
1603     }
1604    
1605     static void
1606     toggle_dos_compatibility_flag(void)
1607     {
1608 niro 816 dos_compatible_flag = 1 - dos_compatible_flag;
1609 niro 532 if (dos_compatible_flag) {
1610 niro 816 sector_offset = g_sectors;
1611     printf("DOS Compatibility flag is set\n");
1612     } else {
1613 niro 532 sector_offset = 1;
1614 niro 816 printf("DOS Compatibility flag is not set\n");
1615 niro 532 }
1616     }
1617    
1618     static void
1619     delete_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     /* Note that for the fifth partition (i == 4) we don't actually
1626     * decrement partitions.
1627     */
1628    
1629     if (warn_geometry())
1630     return; /* C/H/S not set */
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 niro 816 g_partitions = 4;
1645 niro 532 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     /* the last one in the chain - just delete */
1654 niro 816 --g_partitions;
1655 niro 532 --i;
1656     clear_partition(ptes[i].ext_pointer);
1657     ptes[i].changed = 1;
1658     } else {
1659     /* not the last one - further ones will be moved down */
1660     if (i > 4) {
1661     /* delete this link in the chain */
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 niro 816 } else if (g_partitions > 5) { /* 5 will be moved to 4 */
1668 niro 532 /* the first logical in a longer chain */
1669     pe = &ptes[5];
1670    
1671     if (pe->part_table) /* prevent SEGFAULT */
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 niro 816 if (g_partitions > 5) {
1680     g_partitions--;
1681     while (i < g_partitions) {
1682 niro 532 ptes[i] = ptes[i+1];
1683     i++;
1684     }
1685     } else
1686     /* the only logical: clear only */
1687     clear_partition(ptes[i].part_table);
1688     }
1689     }
1690    
1691     static void
1692     change_sysid(void)
1693     {
1694     int i, sys, origsys;
1695     struct partition *p;
1696    
1697     /* If sgi_label then don't use get_existing_partition,
1698     let the user select a partition, since get_existing_partition()
1699     only works for Linux like partition tables. */
1700     if (!LABEL_IS_SGI) {
1701 niro 816 i = get_existing_partition(0, g_partitions);
1702 niro 532 } else {
1703 niro 816 i = get_partition(0, g_partitions);
1704 niro 532 }
1705     if (i == -1)
1706     return;
1707     p = ptes[i].part_table;
1708     origsys = sys = get_sysid(i);
1709    
1710     /* if changing types T to 0 is allowed, then
1711     the reverse change must be allowed, too */
1712     if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN && !get_nr_sects(p)) {
1713 niro 816 printf("Partition %d does not exist yet!\n", i + 1);
1714 niro 532 return;
1715     }
1716     while (1) {
1717 niro 816 sys = read_hex(get_sys_types());
1718 niro 532
1719     if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN) {
1720 niro 816 printf("Type 0 means free space to many systems\n"
1721 niro 532 "(but not to Linux). Having partitions of\n"
1722 niro 816 "type 0 is probably unwise.\n");
1723 niro 532 /* break; */
1724     }
1725    
1726     if (!LABEL_IS_SUN && !LABEL_IS_SGI) {
1727     if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
1728 niro 816 printf("You cannot change a partition into"
1729     " an extended one or vice versa\n");
1730 niro 532 break;
1731     }
1732     }
1733    
1734     if (sys < 256) {
1735 niro 816 #if ENABLE_FEATURE_SUN_LABEL
1736 niro 532 if (LABEL_IS_SUN && i == 2 && sys != SUN_WHOLE_DISK)
1737 niro 816 printf("Consider leaving partition 3 "
1738 niro 532 "as Whole disk (5),\n"
1739     "as SunOS/Solaris expects it and "
1740 niro 816 "even Linux likes it\n\n");
1741     #endif
1742     #if ENABLE_FEATURE_SGI_LABEL
1743 niro 532 if (LABEL_IS_SGI &&
1744     (
1745     (i == 10 && sys != SGI_ENTIRE_DISK) ||
1746     (i == 8 && sys != 0)
1747     )
1748 niro 816 ) {
1749     printf("Consider leaving partition 9 "
1750 niro 532 "as volume header (0),\nand "
1751     "partition 11 as entire volume (6)"
1752 niro 816 "as IRIX expects it\n\n");
1753 niro 532 }
1754 niro 816 #endif
1755 niro 532 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 niro 816 printf("Changed system type of partition %d "
1765     "to %x (%s)\n", i + 1, sys,
1766 niro 532 partition_type(sys));
1767     ptes[i].changed = 1;
1768 niro 816 //if (is_dos_partition(origsys) || is_dos_partition(sys))
1769     // dos_changed = 1;
1770 niro 532 break;
1771     }
1772     }
1773     }
1774     #endif /* FEATURE_FDISK_WRITABLE */
1775    
1776    
1777     /* check_consistency() and linear2chs() added Sat Mar 6 12:28:16 1993,
1778     * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
1779     * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
1780     * Lubkin Oct. 1991). */
1781    
1782     static void
1783     linear2chs(unsigned ls, unsigned *c, unsigned *h, unsigned *s)
1784     {
1785 niro 816 int spc = g_heads * g_sectors;
1786 niro 532
1787     *c = ls / spc;
1788     ls = ls % spc;
1789 niro 816 *h = ls / g_sectors;
1790     *s = ls % g_sectors + 1; /* sectors count from 1 */
1791 niro 532 }
1792    
1793     static void
1794     check_consistency(const struct partition *p, int partition)
1795     {
1796     unsigned pbc, pbh, pbs; /* physical beginning c, h, s */
1797     unsigned pec, peh, pes; /* physical ending c, h, s */
1798     unsigned lbc, lbh, lbs; /* logical beginning c, h, s */
1799     unsigned lec, leh, les; /* logical ending c, h, s */
1800    
1801 niro 816 if (!g_heads || !g_sectors || (partition >= 4))
1802 niro 532 return; /* do not check extended partitions */
1803    
1804     /* physical beginning c, h, s */
1805     pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
1806     pbh = p->head;
1807     pbs = p->sector & 0x3f;
1808    
1809     /* physical ending c, h, s */
1810     pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
1811     peh = p->end_head;
1812     pes = p->end_sector & 0x3f;
1813    
1814     /* compute logical beginning (c, h, s) */
1815     linear2chs(get_start_sect(p), &lbc, &lbh, &lbs);
1816    
1817     /* compute logical ending (c, h, s) */
1818     linear2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
1819    
1820     /* Same physical / logical beginning? */
1821 niro 816 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 niro 532 }
1827    
1828     /* Same physical / logical ending? */
1829 niro 816 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 niro 532 }
1835    
1836     /* Ending on cylinder boundary? */
1837 niro 816 if (peh != (g_heads - 1) || pes != g_sectors) {
1838     printf("Partition %i does not end on cylinder boundary\n",
1839 niro 532 partition + 1);
1840     }
1841     }
1842    
1843     static void
1844     list_disk_geometry(void)
1845     {
1846     long long bytes = (total_number_of_sectors << 9);
1847     long megabytes = bytes/1000000;
1848    
1849     if (megabytes < 10000)
1850 niro 816 printf("\nDisk %s: %ld MB, %lld bytes\n",
1851 niro 532 disk_device, megabytes, bytes);
1852     else
1853 niro 816 printf("\nDisk %s: %ld.%ld GB, %lld bytes\n",
1854 niro 532 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
1855 niro 816 printf("%d heads, %d sectors/track, %d cylinders",
1856     g_heads, g_sectors, g_cylinders);
1857 niro 532 if (units_per_sector == 1)
1858 niro 816 printf(", total %llu sectors",
1859 niro 532 total_number_of_sectors / (sector_size/512));
1860 niro 816 printf("\nUnits = %s of %d * %d = %d bytes\n\n",
1861 niro 532 str_units(PLURAL),
1862     units_per_sector, sector_size, units_per_sector * sector_size);
1863     }
1864    
1865     /*
1866     * Check whether partition entries are ordered by their starting positions.
1867     * Return 0 if OK. Return i if partition i should have been earlier.
1868     * Two separate checks: primary and logical partitions.
1869     */
1870     static int
1871     wrong_p_order(int *prev)
1872     {
1873     const struct pte *pe;
1874     const struct partition *p;
1875 niro 816 ullong last_p_start_pos = 0, p_start_pos;
1876 niro 532 int i, last_i = 0;
1877    
1878 niro 816 for (i = 0; i < g_partitions; i++) {
1879 niro 532 if (i == 4) {
1880     last_i = 4;
1881     last_p_start_pos = 0;
1882     }
1883     pe = &ptes[i];
1884 niro 816 p = pe->part_table;
1885     if (p->sys_ind) {
1886 niro 532 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     * Fix the chain of logicals.
1904     * extended_offset is unchanged, the set of sectors used is unchanged
1905     * The chain is sorted so that sectors increase, and so that
1906     * starting sectors increase.
1907     *
1908     * After this it may still be that cfdisk doesnt like the table.
1909     * (This is because cfdisk considers expanded parts, from link to
1910     * end of partition, and these may still overlap.)
1911     * Now
1912     * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
1913     * may help.
1914     */
1915     static void
1916     fix_chain_of_logicals(void)
1917     {
1918     int j, oj, ojj, sj, sjj;
1919     struct partition *pj,*pjj,tmp;
1920    
1921     /* Stage 1: sort sectors but leave sector of part 4 */
1922     /* (Its sector is the global extended_offset.) */
1923     stage1:
1924 niro 816 for (j = 5; j < g_partitions - 1; j++) {
1925 niro 532 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     /* Stage 2: sort starting sectors */
1943     stage2:
1944 niro 816 for (j = 4; j < g_partitions - 1; j++) {
1945 niro 532 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     /* Probably something was changed */
1962 niro 816 for (j = 4; j < g_partitions; j++)
1963 niro 532 ptes[j].changed = 1;
1964     }
1965    
1966    
1967     static void
1968     fix_partition_table_order(void)
1969     {
1970     struct pte *pei, *pek;
1971     int i,k;
1972    
1973     if (!wrong_p_order(NULL)) {
1974 niro 816 printf("Ordering is already correct\n\n");
1975 niro 532 return;
1976     }
1977    
1978     while ((i = wrong_p_order(&k)) != 0 && i < 4) {
1979     /* partition i should have come earlier, move it */
1980     /* We have to move data in the MBR */
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    
2007     static void
2008     list_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     /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
2030     but if the device name ends in a digit, say /dev/foo1,
2031     then the partition is called /dev/foo1p3. */
2032     w = strlen(disk_device);
2033     if (w && isdigit(disk_device[w-1]))
2034     w++;
2035     if (w < 5)
2036     w = 5;
2037    
2038 niro 816 // 1 12345678901 12345678901 12345678901 12
2039     printf("%*s Boot Start End Blocks Id System\n",
2040     w+1, "Device");
2041 niro 532
2042 niro 816 for (i = 0; i < g_partitions; i++) {
2043 niro 532 const struct pte *pe = &ptes[i];
2044 niro 816 ullong psects;
2045     ullong pblocks;
2046 niro 532 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 /* boot flag */
2066     ? '*' : '?',
2067 niro 816 (ullong) cround(get_partition_start(pe)), /* start */
2068     (ullong) cround(get_partition_start(pe) + psects /* end */
2069 niro 532 - (psects ? 1 : 0)),
2070 niro 816 (ullong) pblocks, podd ? '+' : ' ', /* odd flag on end */
2071 niro 532 p->sys_ind, /* type id */
2072     partition_type(p->sys_ind)); /* type name */
2073    
2074     check_consistency(p, i);
2075     }
2076    
2077     /* Is partition table in disk order? It need not be, but... */
2078     /* partition table entries are not checked for correct order if this
2079     is a sgi, sun or aix labeled disk... */
2080     if (LABEL_IS_DOS && wrong_p_order(NULL)) {
2081     /* FIXME */
2082 niro 816 printf("\nPartition table entries are not in disk order\n");
2083 niro 532 }
2084     }
2085    
2086     #if ENABLE_FEATURE_FDISK_ADVANCED
2087     static void
2088     x_list_table(int extend)
2089     {
2090     const struct pte *pe;
2091     const struct partition *p;
2092     int i;
2093    
2094 niro 816 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 niro 532 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
2116     static void
2117 niro 816 fill_bounds(ullong *first, ullong *last)
2118 niro 532 {
2119     int i;
2120     const struct pte *pe = &ptes[0];
2121     const struct partition *p;
2122    
2123 niro 816 for (i = 0; i < g_partitions; pe++,i++) {
2124 niro 532 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    
2135     static void
2136 niro 816 check(int n, unsigned h, unsigned s, unsigned c, ullong start)
2137 niro 532 {
2138 niro 816 ullong total, real_s, real_c;
2139 niro 532
2140     real_s = sector(s) - 1;
2141     real_c = cylinder(s, c);
2142 niro 816 total = (real_c * g_sectors + real_s) * g_heads + h;
2143 niro 532 if (!total)
2144 niro 816 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 niro 532 }
2158    
2159     static void
2160     verify(void)
2161     {
2162     int i, j;
2163     unsigned total = 1;
2164 niro 816 ullong first[g_partitions], last[g_partitions];
2165 niro 532 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 niro 816 for (i = 0; i < g_partitions; i++) {
2181 niro 532 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 niro 816 printf("Warning: bad start-of-data in "
2188     "partition %d\n", i + 1);
2189 niro 532 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
2190     last[i]);
2191     total += last[i] + 1 - first[i];
2192 niro 816 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 niro 532 }
2203     }
2204     }
2205    
2206     if (extended_offset) {
2207     struct pte *pex = &ptes[ext_index];
2208 niro 816 ullong e_last = get_start_sect(pex->part_table) +
2209 niro 532 get_nr_sects(pex->part_table) - 1;
2210    
2211 niro 816 for (i = 4; i < g_partitions; i++) {
2212 niro 532 total++;
2213     p = ptes[i].part_table;
2214     if (!p->sys_ind) {
2215 niro 816 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 niro 532 }
2222     }
2223     }
2224    
2225 niro 816 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 niro 532 }
2234    
2235     static void
2236     add_partition(int n, int sys)
2237     {
2238     char mesg[256]; /* 48 does not suffice in Japanese */
2239     int i, num_read = 0;
2240     struct partition *p = ptes[n].part_table;
2241     struct partition *q = ptes[ext_index].part_table;
2242 niro 816 ullong limit, temp;
2243     ullong start, stop = 0;
2244     ullong first[g_partitions], last[g_partitions];
2245 niro 532
2246     if (p && p->sys_ind) {
2247 niro 816 printf(msg_part_already_defined, n + 1);
2248 niro 532 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 niro 816 limit = (ullong) g_heads * g_sectors * g_cylinders - 1;
2255 niro 532 else
2256 niro 816 limit = total_number_of_sectors - 1;
2257 niro 532 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 niro 816 for (i = 0; i < g_partitions; i++)
2268 niro 532 first[i] = (cround(first[i]) - 1) * units_per_sector;
2269    
2270 niro 816 snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
2271 niro 532 do {
2272     temp = start;
2273 niro 816 for (i = 0; i < g_partitions; i++) {
2274 niro 532 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 niro 816 printf("Sector %lld is already allocated\n", temp);
2286 niro 532 temp = start;
2287     num_read = 0;
2288     }
2289     if (!num_read && start == temp) {
2290 niro 816 ullong saved_start;
2291 niro 532
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) { /* NOT for fifth partition */
2303     struct pte *pe = &ptes[n];
2304    
2305     pe->offset = start - sector_offset;
2306     if (pe->offset == extended_offset) { /* must be corrected */
2307     pe->offset++;
2308     if (sector_offset == 1)
2309     start++;
2310     }
2311     }
2312    
2313 niro 816 for (i = 0; i < g_partitions; i++) {
2314 niro 532 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 niro 816 printf("No free sectors available\n");
2323 niro 532 if (n > 4)
2324 niro 816 g_partitions--;
2325 niro 532 return;
2326     }
2327     if (cround(start) == cround(limit)) {
2328     stop = limit;
2329     } else {
2330     snprintf(mesg, sizeof(mesg),
2331 niro 816 "Last %s or +size or +sizeM or +sizeK",
2332 niro 532 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 niro 816 g_partitions = 5;
2358 niro 532 }
2359     }
2360    
2361     static void
2362     add_logical(void)
2363     {
2364 niro 816 if (g_partitions > 5 || ptes[4].part_table->sys_ind) {
2365     struct pte *pe = &ptes[g_partitions];
2366 niro 532
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 niro 816 g_partitions++;
2373 niro 532 }
2374 niro 816 add_partition(g_partitions - 1, LINUX_NATIVE);
2375 niro 532 }
2376    
2377     static void
2378     new_partition(void)
2379     {
2380     int i, free_primary = 0;
2381    
2382     if (warn_geometry())
2383     return;
2384    
2385     if (LABEL_IS_SUN) {
2386 niro 816 add_sun_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2387 niro 532 return;
2388     }
2389     if (LABEL_IS_SGI) {
2390 niro 816 sgi_add_partition(get_partition(0, g_partitions), LINUX_NATIVE);
2391 niro 532 return;
2392     }
2393     if (LABEL_IS_AIX) {
2394 niro 816 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 niro 532 return;
2398     }
2399    
2400     for (i = 0; i < 4; i++)
2401     free_primary += !ptes[i].part_table->sys_ind;
2402    
2403 niro 816 if (!free_primary && g_partitions >= MAXIMUM_PARTS) {
2404     printf("The maximum number of partitions has been created\n");
2405 niro 532 return;
2406     }
2407    
2408     if (!free_primary) {
2409     if (extended_offset)
2410     add_logical();
2411     else
2412 niro 816 printf("You must delete some partition and add "
2413     "an extended partition first\n");
2414 niro 532 } else {
2415 niro 816 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 niro 532 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 niro 816 if (c == 'l' && extended_offset) {
2431 niro 532 add_logical();
2432     return;
2433     }
2434 niro 816 if (c == 'e' && !extended_offset) {
2435 niro 532 i = get_nonexisting_partition(0, 4);
2436     if (i >= 0)
2437     add_partition(i, EXTENDED);
2438     return;
2439     }
2440 niro 816 printf("Invalid partition number "
2441     "for type '%c'\n", c);
2442 niro 532 }
2443     }
2444     }
2445    
2446     static void
2447     write_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 niro 816 for (i = 3; i < g_partitions; i++) {
2456 niro 532 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     /* no test on change? the printf below might be mistaken */
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 niro 816 printf("The partition table has been altered!\n\n");
2479 niro 532 reread_partition_table(1);
2480     }
2481    
2482     static void
2483     reread_partition_table(int leave)
2484     {
2485     int i;
2486    
2487 niro 816 printf("Calling ioctl() to re-read partition table\n");
2488 niro 532 sync();
2489 niro 816 /* sleep(2); Huh? */
2490     i = ioctl_or_perror(dev_fd, BLKRRPART, NULL,
2491     "WARNING: rereading partition table "
2492 niro 532 "failed, kernel still uses old table");
2493     #if 0
2494     if (dos_changed)
2495     printf(
2496 niro 816 "\nWARNING: If you have created or modified any DOS 6.x\n"
2497 niro 532 "partitions, please see the fdisk manual page for additional\n"
2498 niro 816 "information\n");
2499 niro 532 #endif
2500    
2501     if (leave) {
2502     if (ENABLE_FEATURE_CLEAN_UP)
2503 niro 816 close_dev_fd();
2504 niro 532 exit(i != 0);
2505     }
2506     }
2507     #endif /* FEATURE_FDISK_WRITABLE */
2508    
2509     #if ENABLE_FEATURE_FDISK_ADVANCED
2510     #define MAX_PER_LINE 16
2511     static void
2512     print_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 niro 816 bb_putchar('\n');
2522 niro 532 l = -1;
2523     }
2524     }
2525     if (l > 0)
2526 niro 816 bb_putchar('\n');
2527     bb_putchar('\n');
2528 niro 532 }
2529    
2530     static void
2531     print_raw(void)
2532     {
2533     int i;
2534    
2535 niro 816 printf("Device: %s\n", disk_device);
2536 niro 532 if (LABEL_IS_SGI || LABEL_IS_SUN)
2537     print_buffer(MBRbuffer);
2538     else {
2539 niro 816 for (i = 3; i < g_partitions; i++)
2540 niro 532 print_buffer(ptes[i].sectorbuffer);
2541     }
2542     }
2543    
2544     static void
2545     move_begin(int i)
2546     {
2547     struct pte *pe = &ptes[i];
2548     struct partition *p = pe->part_table;
2549 niro 816 ullong new, first;
2550 niro 532
2551     if (warn_geometry())
2552     return;
2553     if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED(p->sys_ind)) {
2554 niro 816 printf("Partition %d has no data area\n", i + 1);
2555 niro 532 return;
2556     }
2557     first = get_partition_start(pe);
2558     new = read_int(first, first, first + get_nr_sects(p) - 1, first,
2559 niro 816 "New beginning of data") - pe->offset;
2560 niro 532
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    
2569     static void
2570     xselect(void)
2571     {
2572     char c;
2573    
2574     while (1) {
2575 niro 816 bb_putchar('\n');
2576     c = tolower(read_nonempty("Expert command (m for help): "));
2577 niro 532 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 niro 816 move_begin(get_partition(0, g_partitions));
2585 niro 532 break;
2586     case 'c':
2587 niro 816 user_cylinders = g_cylinders =
2588     read_int(1, g_cylinders, 1048576, 0,
2589     "Number of cylinders");
2590 niro 532 if (LABEL_IS_SUN)
2591 niro 816 sun_set_ncyl(g_cylinders);
2592 niro 532 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 niro 816 user_heads = g_heads = read_int(1, g_heads, 256, 0,
2617     "Number of heads");
2618 niro 532 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 niro 816 if (ENABLE_FEATURE_CLEAN_UP)
2636     close_dev_fd();
2637     bb_putchar('\n');
2638     exit(EXIT_SUCCESS);
2639 niro 532 case 'r':
2640     return;
2641     case 's':
2642 niro 816 user_sectors = g_sectors = read_int(1, g_sectors, 63, 0,
2643     "Number of sectors");
2644 niro 532 if (dos_compatible_flag) {
2645 niro 816 sector_offset = g_sectors;
2646     printf("Warning: setting sector offset for DOS "
2647     "compatiblity\n");
2648 niro 532 }
2649     update_units();
2650     break;
2651     case 'v':
2652     verify();
2653     break;
2654     case 'w':
2655     write_table(); /* does not return */
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 /* ADVANCED mode */
2667    
2668     static int
2669     is_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     /* No device was given explicitly, and we are trying some
2677     likely things. But opening /dev/hdc may produce errors like
2678     "hdc: tray open or drive not ready"
2679     if it happens to be a CD-ROM drive. It even happens that
2680     the process hangs on the attempt to read a music CD.
2681     So try to be careful. This only works since 2.1.73. */
2682    
2683     if (strncmp("/dev/hd", device, 7))
2684     return 0;
2685    
2686     snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
2687 niro 816 procf = fopen_for_read(buf);
2688 niro 532 if (procf != NULL && fgets(buf, sizeof(buf), procf))
2689     is_ide = (!strncmp(buf, "cdrom", 5) ||
2690     !strncmp(buf, "tape", 4));
2691     else
2692     /* Now when this proc file does not exist, skip the
2693     device when it is read-only. */
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    
2703     static void
2704 niro 816 open_list_and_close(const char *device, int user_specified)
2705 niro 532 {
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 niro 816
2715     /* Open disk_device, save file descriptor to dev_fd */
2716     errno = 0;
2717     gb = get_boot(TRY_ONLY);
2718     if (gb > 0) { /* I/O error */
2719     /* Ignore other errors, since we try IDE
2720     and SCSI hard disks which may not be
2721     installed on the system. */
2722     if (user_specified || errno == EACCES)
2723     bb_perror_msg("can't open '%s'", device);
2724     return;
2725     }
2726    
2727     if (gb < 0) { /* no DOS signature */
2728     list_disk_geometry();
2729     if (LABEL_IS_AIX)
2730     goto ret;
2731 niro 532 #if ENABLE_FEATURE_OSF_LABEL
2732 niro 816 if (bsd_trydev(device) < 0)
2733 niro 532 #endif
2734 niro 816 printf("Disk %s doesn't contain a valid "
2735     "partition table\n", device);
2736     } else {
2737     list_table(0);
2738 niro 532 #if ENABLE_FEATURE_FDISK_WRITABLE
2739 niro 816 if (!LABEL_IS_SUN && g_partitions > 4) {
2740     delete_partition(ext_index);
2741     }
2742 niro 532 #endif
2743     }
2744 niro 816 ret:
2745     close_dev_fd();
2746 niro 532 }
2747    
2748     /* for fdisk -l: try all things in /proc/partitions
2749     that look like a partition name (do not end in a digit) */
2750     static void
2751 niro 816 list_devs_in_proc_partititons(void)
2752 niro 532 {
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 niro 816 for (s = ptname; *s; s++)
2764     continue;
2765 niro 532 if (isdigit(s[-1]))
2766     continue;
2767     sprintf(devname, "/dev/%s", ptname);
2768 niro 816 open_list_and_close(devname, 0);
2769 niro 532 }
2770     #if ENABLE_FEATURE_CLEAN_UP
2771     fclose(procpt);
2772     #endif
2773     }
2774    
2775     #if ENABLE_FEATURE_FDISK_WRITABLE
2776     static void
2777     unknown_command(int c)
2778     {
2779 niro 816 printf("%c: unknown command\n", c);
2780 niro 532 }
2781     #endif
2782    
2783 niro 816 int fdisk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
2784 niro 532 int fdisk_main(int argc, char **argv)
2785     {
2786     unsigned opt;
2787     /*
2788     * fdisk -v
2789     * fdisk -l [-b sectorsize] [-u] device ...
2790     * fdisk -s [partition] ...
2791     * fdisk [-b sectorsize] [-u] device
2792     *
2793     * Options -C, -H, -S set the geometry.
2794     */
2795 niro 816 INIT_G();
2796    
2797     close_dev_fd(); /* needed: fd 3 must not stay closed */
2798    
2799     opt_complementary = "b+:C+:H+:S+"; /* numeric params */
2800     opt = getopt32(argv, "b:C:H:lS:u" USE_FEATURE_FDISK_BLKSIZE("s"),
2801     &sector_size, &user_cylinders, &user_heads, &user_sectors);
2802 niro 532 argc -= optind;
2803     argv += optind;
2804     if (opt & OPT_b) { // -b
2805     /* Ugly: this sector size is really per device,
2806     so cannot be combined with multiple disks,
2807     and the same goes for the C/H/S options.
2808     */
2809 niro 816 if (sector_size != 512 && sector_size != 1024
2810     && sector_size != 2048)
2811 niro 532 bb_show_usage();
2812     sector_offset = 2;
2813     user_set_sector_size = 1;
2814     }
2815 niro 816 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; // -u
2821 niro 532
2822     #if ENABLE_FEATURE_FDISK_WRITABLE
2823     if (opt & OPT_l) {
2824     nowarn = 1;
2825     #endif
2826 niro 816 if (*argv) {
2827 niro 532 listing = 1;
2828 niro 816 do {
2829     open_list_and_close(*argv, 1);
2830     } while (*++argv);
2831 niro 532 } else {
2832 niro 816 /* we don't have device names, */
2833     /* use /proc/partitions instead */
2834     list_devs_in_proc_partititons();
2835 niro 532 }
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 niro 816 unsigned long long size;
2850     fd = xopen(argv[j], O_RDONLY);
2851     size = bb_BLKGETSIZE_sectors(fd) / 2;
2852 niro 532 close(fd);
2853     if (argc == 1)
2854 niro 816 printf("%lld\n", size);
2855 niro 532 else
2856 niro 816 printf("%s: %lld\n", argv[j], size);
2857 niro 532 }
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 niro 816 get_boot(OPEN_MAIN);
2868 niro 532
2869     if (LABEL_IS_OSF) {
2870     /* OSF label, and no DOS label */
2871 niro 816 printf("Detected an OSF/1 disklabel on %s, entering "
2872     "disklabel mode\n", disk_device);
2873 niro 532 bsd_select();
2874     /*Why do we do this? It seems to be counter-intuitive*/
2875 niro 816 current_label_type = LABEL_DOS;
2876 niro 532 /* If we return we may want to make an empty DOS label? */
2877     }
2878    
2879     while (1) {
2880     int c;
2881 niro 816 bb_putchar('\n');
2882     c = tolower(read_nonempty("Command (m for help): "));
2883 niro 532 switch (c) {
2884     case 'a':
2885     if (LABEL_IS_DOS)
2886 niro 816 toggle_active(get_partition(1, g_partitions));
2887 niro 532 else if (LABEL_IS_SUN)
2888 niro 816 toggle_sunflags(get_partition(1, g_partitions),
2889 niro 532 0x01);
2890     else if (LABEL_IS_SGI)
2891     sgi_set_bootpartition(
2892 niro 816 get_partition(1, g_partitions));
2893 niro 532 else
2894     unknown_command(c);
2895     break;
2896     case 'b':
2897     if (LABEL_IS_SGI) {
2898 niro 816 printf("\nThe current boot file is: %s\n",
2899 niro 532 sgi_get_bootfile());
2900 niro 816 if (read_maybe_empty("Please enter the name of the "
2901     "new boot file: ") == '\n')
2902     printf("Boot file unchanged\n");
2903 niro 532 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 niro 816 toggle_sunflags(get_partition(1, g_partitions),
2916 niro 532 0x10);
2917     else if (LABEL_IS_SGI)
2918     sgi_set_swappartition(
2919 niro 816 get_partition(1, g_partitions));
2920 niro 532 else
2921     unknown_command(c);
2922     break;
2923     case 'd':
2924     {
2925     int j;
2926     /* If sgi_label then don't use get_existing_partition,
2927     let the user select a partition, since
2928     get_existing_partition() only works for Linux-like
2929     partition tables */
2930     if (!LABEL_IS_SGI) {
2931 niro 816 j = get_existing_partition(1, g_partitions);
2932 niro 532 } else {
2933 niro 816 j = get_partition(1, g_partitions);
2934 niro 532 }
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 niro 816 if (ENABLE_FEATURE_CLEAN_UP)
2961     close_dev_fd();
2962     bb_putchar('\n');
2963 niro 532 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(); /* does not return */
2980     break;
2981     #if ENABLE_FEATURE_FDISK_ADVANCED
2982     case 'x':
2983     if (LABEL_IS_SGI) {
2984 niro 816 printf("\n\tSorry, no experts menu for SGI "
2985     "partition tables available\n\n");
2986 niro 532 } else
2987     xselect();
2988     break;
2989     #endif
2990     default:
2991     unknown_command(c);
2992     menu();
2993     }
2994     }
2995     return 0;
2996     #endif /* FEATURE_FDISK_WRITABLE */
2997     }