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