blob: 57d4d653e7e28c96f5811bb1c04d83b1a11fb3e5 [file] [log] [blame]
"Robert P. J. Day"63fc1a92006-07-02 19:47:05 +00001/* vi: set sw=4 ts=4: */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002/* fdisk.c -- Partition table manipulator for Linux.
3 *
4 * Copyright (C) 1992 A. V. Le Blanc (LeBlanc@mcc.ac.uk)
Mike Frysinger983e0ca2006-02-25 07:42:02 +00005 * Copyright (C) 2001,2002 Vladimir Oleynik <dzo@simtreas.ru> (initial bb port)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00006 *
Rob Landleyb73451d2006-02-24 16:29:00 +00007 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00008 */
9
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +000010#ifndef _LARGEFILE64_SOURCE
11/* For lseek64 */
12#define _LARGEFILE64_SOURCE
13#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000014#include <assert.h> /* assert */
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000015#include "libbb.h"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000016
Denis Vlasenko834410a2006-11-29 12:00:28 +000017/* Looks like someone forgot to add this to config system */
18#ifndef ENABLE_FEATURE_FDISK_BLKSIZE
19# define ENABLE_FEATURE_FDISK_BLKSIZE 0
20# define USE_FEATURE_FDISK_BLKSIZE(a)
21#endif
22
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000023#define DEFAULT_SECTOR_SIZE 512
24#define MAX_SECTOR_SIZE 2048
Denis Vlasenko98ae2162006-10-12 19:30:44 +000025#define SECTOR_SIZE 512 /* still used in osf/sgi/sun code */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000026#define MAXIMUM_PARTS 60
27
28#define ACTIVE_FLAG 0x80
29
30#define EXTENDED 0x05
31#define WIN98_EXTENDED 0x0f
32#define LINUX_PARTITION 0x81
33#define LINUX_SWAP 0x82
34#define LINUX_NATIVE 0x83
35#define LINUX_EXTENDED 0x85
36#define LINUX_LVM 0x8e
37#define LINUX_RAID 0xfd
38
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +000039/* Used for sector numbers. Today's disk sizes make it necessary */
40typedef unsigned long long ullong;
41
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000042struct hd_geometry {
Rob Landleyb73451d2006-02-24 16:29:00 +000043 unsigned char heads;
44 unsigned char sectors;
45 unsigned short cylinders;
46 unsigned long start;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000047};
48
Denis Vlasenko98ae2162006-10-12 19:30:44 +000049#define HDIO_GETGEO 0x0301 /* get device geometry */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000050
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000051static const char msg_building_new_label[] ALIGN1 =
Denis Vlasenkobd852072007-03-19 14:43:38 +000052"Building a new %s. Changes will remain in memory only,\n"
53"until you decide to write them. After that the previous content\n"
54"won't be recoverable.\n\n";
55
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000056static const char msg_part_already_defined[] ALIGN1 =
Denis Vlasenkobd852072007-03-19 14:43:38 +000057"Partition %d is already defined, delete it before re-adding\n";
58
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000059
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000060struct partition {
61 unsigned char boot_ind; /* 0x80 - active */
62 unsigned char head; /* starting head */
63 unsigned char sector; /* starting sector */
64 unsigned char cyl; /* starting cylinder */
65 unsigned char sys_ind; /* What partition type */
66 unsigned char end_head; /* end head */
67 unsigned char end_sector; /* end sector */
68 unsigned char end_cyl; /* end cylinder */
69 unsigned char start4[4]; /* starting sector counting from 0 */
70 unsigned char size4[4]; /* nr of sectors in partition */
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +000071} ATTRIBUTE_PACKED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000072
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000073static const char unable_to_open[] ALIGN1 = "cannot open %s";
74static const char unable_to_read[] ALIGN1 = "cannot read from %s";
75static const char unable_to_seek[] ALIGN1 = "cannot seek on %s";
76static const char unable_to_write[] ALIGN1 = "cannot write to %s";
77static const char ioctl_error[] ALIGN1 = "BLKGETSIZE ioctl failed on %s";
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +000078static void fdisk_fatal(const char *why) ATTRIBUTE_NORETURN;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000079
Denis Vlasenko98ae2162006-10-12 19:30:44 +000080enum label_type {
Denis Vlasenko4437d192008-04-17 00:12:10 +000081 LABEL_DOS, LABEL_SUN, LABEL_SGI, LABEL_AIX, LABEL_OSF
Rob Landley5527b912006-02-25 03:46:10 +000082};
Denis Vlasenkodfce08f2007-03-19 14:45:10 +000083
Denis Vlasenko4437d192008-04-17 00:12:10 +000084#define LABEL_IS_DOS (LABEL_DOS == current_label_type)
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +000085
Denis Vlasenko834410a2006-11-29 12:00:28 +000086#if ENABLE_FEATURE_SUN_LABEL
Denis Vlasenko4437d192008-04-17 00:12:10 +000087#define LABEL_IS_SUN (LABEL_SUN == current_label_type)
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +000088#define STATIC_SUN static
Denis Vlasenko98ae2162006-10-12 19:30:44 +000089#else
90#define LABEL_IS_SUN 0
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +000091#define STATIC_SUN extern
Denis Vlasenko98ae2162006-10-12 19:30:44 +000092#endif
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +000093
Denis Vlasenko834410a2006-11-29 12:00:28 +000094#if ENABLE_FEATURE_SGI_LABEL
Denis Vlasenko4437d192008-04-17 00:12:10 +000095#define LABEL_IS_SGI (LABEL_SGI == current_label_type)
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +000096#define STATIC_SGI static
Denis Vlasenko98ae2162006-10-12 19:30:44 +000097#else
98#define LABEL_IS_SGI 0
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +000099#define STATIC_SGI extern
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000100#endif
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000101
Denis Vlasenko834410a2006-11-29 12:00:28 +0000102#if ENABLE_FEATURE_AIX_LABEL
Denis Vlasenko4437d192008-04-17 00:12:10 +0000103#define LABEL_IS_AIX (LABEL_AIX == current_label_type)
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000104#define STATIC_AIX static
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000105#else
106#define LABEL_IS_AIX 0
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000107#define STATIC_AIX extern
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000108#endif
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000109
Denis Vlasenko834410a2006-11-29 12:00:28 +0000110#if ENABLE_FEATURE_OSF_LABEL
Denis Vlasenko4437d192008-04-17 00:12:10 +0000111#define LABEL_IS_OSF (LABEL_OSF == current_label_type)
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000112#define STATIC_OSF static
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000113#else
114#define LABEL_IS_OSF 0
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000115#define STATIC_OSF extern
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000116#endif
Rob Landley5527b912006-02-25 03:46:10 +0000117
Denis Vlasenko4437d192008-04-17 00:12:10 +0000118enum action { OPEN_MAIN, TRY_ONLY, CREATE_EMPTY_DOS, CREATE_EMPTY_SUN };
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000119
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000120static void update_units(void);
Denis Vlasenko834410a2006-11-29 12:00:28 +0000121#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000122static void change_units(void);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000123static void reread_partition_table(int leave);
124static void delete_partition(int i);
Rob Landleyb73451d2006-02-24 16:29:00 +0000125static int get_partition(int warn, int max);
Denis Vlasenkobd852072007-03-19 14:43:38 +0000126static void list_types(const char *const *sys);
Denis Vlasenko06c0a712007-01-29 22:51:44 +0000127static unsigned read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, const char *mesg);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000128#endif
129static const char *partition_type(unsigned char type);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000130static void get_geometry(void);
Denis Vlasenko85c24712008-03-17 09:04:04 +0000131#if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000132static int get_boot(enum action what);
Denis Vlasenko85c24712008-03-17 09:04:04 +0000133#else
134static int get_boot(void);
135#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000136
137#define PLURAL 0
138#define SINGULAR 1
139
Denis Vlasenko28703012006-12-19 20:32:02 +0000140static unsigned get_start_sect(const struct partition *p);
141static unsigned get_nr_sects(const struct partition *p);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000142
143/*
144 * per partition table entry data
145 *
146 * The four primary partitions have the same sectorbuffer (MBRbuffer)
147 * and have NULL ext_pointer.
148 * Each logical partition table entry has two pointers, one for the
149 * partition and one link to the next one.
150 */
Denis Vlasenko8e1a0cc2007-03-18 14:42:45 +0000151struct pte {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000152 struct partition *part_table; /* points into sectorbuffer */
153 struct partition *ext_pointer; /* points into sectorbuffer */
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +0000154 ullong offset; /* disk sector number */
Denis Vlasenkodfce08f2007-03-19 14:45:10 +0000155 char *sectorbuffer; /* disk sector contents */
Denis Vlasenko834410a2006-11-29 12:00:28 +0000156#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000157 char changed; /* boolean */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000158#endif
Denis Vlasenko8e1a0cc2007-03-18 14:42:45 +0000159};
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000160
Denis Vlasenkodfce08f2007-03-19 14:45:10 +0000161/* DOS partition types */
162
163static const char *const i386_sys_types[] = {
164 "\x00" "Empty",
165 "\x01" "FAT12",
166 "\x04" "FAT16 <32M",
167 "\x05" "Extended", /* DOS 3.3+ extended partition */
168 "\x06" "FAT16", /* DOS 16-bit >=32M */
169 "\x07" "HPFS/NTFS", /* OS/2 IFS, eg, HPFS or NTFS or QNX */
170 "\x0a" "OS/2 Boot Manager",/* OS/2 Boot Manager */
171 "\x0b" "Win95 FAT32",
172 "\x0c" "Win95 FAT32 (LBA)",/* LBA really is 'Extended Int 13h' */
173 "\x0e" "Win95 FAT16 (LBA)",
174 "\x0f" "Win95 Ext'd (LBA)",
175 "\x11" "Hidden FAT12",
176 "\x12" "Compaq diagnostics",
177 "\x14" "Hidden FAT16 <32M",
178 "\x16" "Hidden FAT16",
179 "\x17" "Hidden HPFS/NTFS",
180 "\x1b" "Hidden Win95 FAT32",
181 "\x1c" "Hidden W95 FAT32 (LBA)",
182 "\x1e" "Hidden W95 FAT16 (LBA)",
183 "\x3c" "Part.Magic recovery",
184 "\x41" "PPC PReP Boot",
185 "\x42" "SFS",
186 "\x63" "GNU HURD or SysV", /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
187 "\x80" "Old Minix", /* Minix 1.4a and earlier */
188 "\x81" "Minix / old Linux",/* Minix 1.4b and later */
189 "\x82" "Linux swap", /* also Solaris */
190 "\x83" "Linux",
191 "\x84" "OS/2 hidden C: drive",
192 "\x85" "Linux extended",
193 "\x86" "NTFS volume set",
194 "\x87" "NTFS volume set",
195 "\x8e" "Linux LVM",
196 "\x9f" "BSD/OS", /* BSDI */
197 "\xa0" "Thinkpad hibernation",
198 "\xa5" "FreeBSD", /* various BSD flavours */
199 "\xa6" "OpenBSD",
200 "\xa8" "Darwin UFS",
201 "\xa9" "NetBSD",
202 "\xab" "Darwin boot",
203 "\xb7" "BSDI fs",
204 "\xb8" "BSDI swap",
205 "\xbe" "Solaris boot",
206 "\xeb" "BeOS fs",
207 "\xee" "EFI GPT", /* Intel EFI GUID Partition Table */
208 "\xef" "EFI (FAT-12/16/32)", /* Intel EFI System Partition */
209 "\xf0" "Linux/PA-RISC boot", /* Linux/PA-RISC boot loader */
210 "\xf2" "DOS secondary", /* DOS 3.3+ secondary */
211 "\xfd" "Linux raid autodetect", /* New (2.2.x) raid partition with
212 autodetect using persistent
213 superblock */
214#if 0 /* ENABLE_WEIRD_PARTITION_TYPES */
215 "\x02" "XENIX root",
216 "\x03" "XENIX usr",
217 "\x08" "AIX", /* AIX boot (AIX -- PS/2 port) or SplitDrive */
218 "\x09" "AIX bootable", /* AIX data or Coherent */
219 "\x10" "OPUS",
220 "\x18" "AST SmartSleep",
221 "\x24" "NEC DOS",
222 "\x39" "Plan 9",
223 "\x40" "Venix 80286",
224 "\x4d" "QNX4.x",
225 "\x4e" "QNX4.x 2nd part",
226 "\x4f" "QNX4.x 3rd part",
227 "\x50" "OnTrack DM",
228 "\x51" "OnTrack DM6 Aux1", /* (or Novell) */
229 "\x52" "CP/M", /* CP/M or Microport SysV/AT */
230 "\x53" "OnTrack DM6 Aux3",
231 "\x54" "OnTrackDM6",
232 "\x55" "EZ-Drive",
233 "\x56" "Golden Bow",
234 "\x5c" "Priam Edisk",
235 "\x61" "SpeedStor",
236 "\x64" "Novell Netware 286",
237 "\x65" "Novell Netware 386",
238 "\x70" "DiskSecure Multi-Boot",
239 "\x75" "PC/IX",
240 "\x93" "Amoeba",
241 "\x94" "Amoeba BBT", /* (bad block table) */
242 "\xa7" "NeXTSTEP",
243 "\xbb" "Boot Wizard hidden",
244 "\xc1" "DRDOS/sec (FAT-12)",
245 "\xc4" "DRDOS/sec (FAT-16 < 32M)",
246 "\xc6" "DRDOS/sec (FAT-16)",
247 "\xc7" "Syrinx",
248 "\xda" "Non-FS data",
249 "\xdb" "CP/M / CTOS / ...",/* CP/M or Concurrent CP/M or
250 Concurrent DOS or CTOS */
251 "\xde" "Dell Utility", /* Dell PowerEdge Server utilities */
252 "\xdf" "BootIt", /* BootIt EMBRM */
253 "\xe1" "DOS access", /* DOS access or SpeedStor 12-bit FAT
254 extended partition */
255 "\xe3" "DOS R/O", /* DOS R/O or SpeedStor */
256 "\xe4" "SpeedStor", /* SpeedStor 16-bit FAT extended
257 partition < 1024 cyl. */
258 "\xf1" "SpeedStor",
259 "\xf4" "SpeedStor", /* SpeedStor large partition */
260 "\xfe" "LANstep", /* SpeedStor >1024 cyl. or LANstep */
261 "\xff" "BBT", /* Xenix Bad Block Table */
262#endif
263 NULL
264};
265
Denis Vlasenko4437d192008-04-17 00:12:10 +0000266enum {
267 dev_fd = 3 /* the disk */
268};
Denis Vlasenkodfce08f2007-03-19 14:45:10 +0000269
270/* Globals */
Denis Vlasenko8e1a0cc2007-03-18 14:42:45 +0000271struct globals {
Denis Vlasenkodfce08f2007-03-19 14:45:10 +0000272 char *line_ptr;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000273
274 const char *disk_device;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000275 int g_partitions; // = 4; /* maximum partition + 1 */
276 unsigned units_per_sector; // = 1;
277 unsigned sector_size; // = DEFAULT_SECTOR_SIZE;
278 unsigned user_set_sector_size;
279 unsigned sector_offset; // = 1;
280 unsigned g_heads, g_sectors, g_cylinders;
281 enum label_type current_label_type;
282 smallint display_in_cyl_units; // = 1;
283#if ENABLE_FEATURE_OSF_LABEL
284 smallint possibly_osf_label;
285#endif
286
287 jmp_buf listingbuf;
Denis Vlasenkodfce08f2007-03-19 14:45:10 +0000288 char line_buffer[80];
289 char partname_buffer[80];
Denis Vlasenko8e1a0cc2007-03-18 14:42:45 +0000290 /* Raw disk label. For DOS-type partition tables the MBR,
291 * with descriptions of the primary partitions. */
292 char MBRbuffer[MAX_SECTOR_SIZE];
293 /* Partition tables */
294 struct pte ptes[MAXIMUM_PARTS];
295};
Denis Vlasenkodfce08f2007-03-19 14:45:10 +0000296#define G (*ptr_to_globals)
Denis Vlasenkodfce08f2007-03-19 14:45:10 +0000297#define line_ptr (G.line_ptr)
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000298#define disk_device (G.disk_device )
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000299#define g_partitions (G.g_partitions )
300#define units_per_sector (G.units_per_sector )
301#define sector_size (G.sector_size )
302#define user_set_sector_size (G.user_set_sector_size)
303#define sector_offset (G.sector_offset )
304#define g_heads (G.g_heads )
305#define g_sectors (G.g_sectors )
306#define g_cylinders (G.g_cylinders )
307#define current_label_type (G.current_label_type )
308#define display_in_cyl_units (G.display_in_cyl_units)
309#define possibly_osf_label (G.possibly_osf_label )
Denis Vlasenkodfce08f2007-03-19 14:45:10 +0000310#define listingbuf (G.listingbuf)
311#define line_buffer (G.line_buffer)
312#define partname_buffer (G.partname_buffer)
313#define MBRbuffer (G.MBRbuffer)
314#define ptes (G.ptes)
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000315#define INIT_G() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000316 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000317 sector_size = DEFAULT_SECTOR_SIZE; \
318 sector_offset = 1; \
319 g_partitions = 4; \
320 display_in_cyl_units = 1; \
321 units_per_sector = 1; \
322} while (0)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000323
Denis Vlasenkobd852072007-03-19 14:43:38 +0000324
Denis Vlasenkocdf62772008-03-17 08:42:43 +0000325/* TODO: move to libbb? */
Denis Vlasenko4437d192008-04-17 00:12:10 +0000326static ullong bb_BLKGETSIZE_sectors(int fd)
Denis Vlasenkocdf62772008-03-17 08:42:43 +0000327{
328 uint64_t v64;
329 unsigned long longsectors;
330
331 if (ioctl(fd, BLKGETSIZE64, &v64) == 0) {
332 /* got bytes, convert to 512 byte sectors */
333 return (v64 >> 9);
334 }
335 /* Needs temp of type long */
336 if (ioctl(fd, BLKGETSIZE, &longsectors))
337 longsectors = 0;
338 return longsectors;
339}
340
341
Denis Vlasenkodfce08f2007-03-19 14:45:10 +0000342#define IS_EXTENDED(i) \
343 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
344
345#define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
346
347#define scround(x) (((x)+units_per_sector-1)/units_per_sector)
348
349#define pt_offset(b, n) \
350 ((struct partition *)((b) + 0x1be + (n) * sizeof(struct partition)))
351
352#define sector(s) ((s) & 0x3f)
353
354#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
355
356#define hsc2sector(h,s,c) \
357 (sector(s) - 1 + sectors * ((h) + heads * cylinder(s,c)))
358
359#define set_hsc(h,s,c,sector) \
360 do { \
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000361 s = sector % g_sectors + 1; \
362 sector /= g_sectors; \
363 h = sector % g_heads; \
364 sector /= g_heads; \
365 c = sector & 0xff; \
366 s |= (sector >> 2) & 0xc0; \
Denis Vlasenkodfce08f2007-03-19 14:45:10 +0000367 } while (0)
368
Denis Vlasenko58875ae2007-03-22 22:22:10 +0000369#if ENABLE_FEATURE_FDISK_WRITABLE
Denis Vlasenkodfce08f2007-03-19 14:45:10 +0000370/* read line; return 0 or first printable char */
371static int
372read_line(const char *prompt)
373{
374 int sz;
375
376 sz = read_line_input(prompt, line_buffer, sizeof(line_buffer), NULL);
377 if (sz <= 0)
378 exit(0); /* Ctrl-D or Ctrl-C */
379
380 if (line_buffer[sz-1] == '\n')
381 line_buffer[--sz] = '\0';
382
383 line_ptr = line_buffer;
384 while (*line_ptr && !isgraph(*line_ptr))
385 line_ptr++;
386 return *line_ptr;
387}
Denis Vlasenko58875ae2007-03-22 22:22:10 +0000388#endif
Denis Vlasenkodfce08f2007-03-19 14:45:10 +0000389
Denis Vlasenkobd852072007-03-19 14:43:38 +0000390/*
391 * return partition name - uses static storage
392 */
393static const char *
394partname(const char *dev, int pno, int lth)
395{
Denis Vlasenkobd852072007-03-19 14:43:38 +0000396 const char *p;
397 int w, wp;
398 int bufsiz;
399 char *bufp;
400
Denis Vlasenkodfce08f2007-03-19 14:45:10 +0000401 bufp = partname_buffer;
402 bufsiz = sizeof(partname_buffer);
Denis Vlasenkobd852072007-03-19 14:43:38 +0000403
404 w = strlen(dev);
405 p = "";
406
407 if (isdigit(dev[w-1]))
408 p = "p";
409
410 /* devfs kludge - note: fdisk partition names are not supposed
411 to equal kernel names, so there is no reason to do this */
412 if (strcmp(dev + w - 4, "disc") == 0) {
413 w -= 4;
414 p = "part";
415 }
416
417 wp = strlen(p);
418
419 if (lth) {
420 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
421 lth-wp-2, w, dev, p, pno);
422 } else {
423 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
424 }
425 return bufp;
426}
427
Denis Vlasenko834410a2006-11-29 12:00:28 +0000428#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000429static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000430set_all_unchanged(void)
431{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000432 int i;
433
434 for (i = 0; i < MAXIMUM_PARTS; i++)
435 ptes[i].changed = 0;
436}
437
Denis Vlasenko3ad5d0c2007-06-12 20:54:54 +0000438static ALWAYS_INLINE void
Rob Landleyb73451d2006-02-24 16:29:00 +0000439set_changed(int i)
440{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000441 ptes[i].changed = 1;
442}
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000443#endif /* FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000444
Denis Vlasenko3ad5d0c2007-06-12 20:54:54 +0000445static ALWAYS_INLINE struct partition *
Rob Landleyb73451d2006-02-24 16:29:00 +0000446get_part_table(int i)
447{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000448 return ptes[i].part_table;
449}
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000450
451static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +0000452str_units(int n)
453{ /* n==1: use singular */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000454 if (n == 1)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000455 return display_in_cyl_units ? "cylinder" : "sector";
456 return display_in_cyl_units ? "cylinders" : "sectors";
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000457}
458
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000459static int
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000460valid_part_table_flag(const char *mbuffer)
461{
Denis Vlasenko834410a2006-11-29 12:00:28 +0000462 return (mbuffer[510] == 0x55 && (uint8_t)mbuffer[511] == 0xaa);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000463}
464
Denis Vlasenko834410a2006-11-29 12:00:28 +0000465#if ENABLE_FEATURE_FDISK_WRITABLE
Denis Vlasenko3ad5d0c2007-06-12 20:54:54 +0000466static ALWAYS_INLINE void
Denis Vlasenko834410a2006-11-29 12:00:28 +0000467write_part_table_flag(char *b)
468{
469 b[510] = 0x55;
470 b[511] = 0xaa;
471}
472
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000473static char
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000474read_nonempty(const char *mesg)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000475{
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000476 while (!read_line(mesg)) /* repeat */;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000477 return *line_ptr;
478}
479
480static char
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000481read_maybe_empty(const char *mesg)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000482{
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000483 if (!read_line(mesg)) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000484 line_ptr = line_buffer;
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000485 line_ptr[0] = '\n';
486 line_ptr[1] = '\0';
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000487 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000488 return line_ptr[0];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000489}
490
491static int
Denis Vlasenkobd852072007-03-19 14:43:38 +0000492read_hex(const char *const *sys)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000493{
Denis Vlasenkoc6ce8732006-11-29 18:15:52 +0000494 unsigned long v;
Rob Landleyb73451d2006-02-24 16:29:00 +0000495 while (1) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000496 read_nonempty("Hex code (type L to list codes): ");
Denis Vlasenkoc6ce8732006-11-29 18:15:52 +0000497 if (*line_ptr == 'l' || *line_ptr == 'L') {
Rob Landleyb73451d2006-02-24 16:29:00 +0000498 list_types(sys);
Denis Vlasenkoc6ce8732006-11-29 18:15:52 +0000499 continue;
Rob Landleyb73451d2006-02-24 16:29:00 +0000500 }
Denis Vlasenkoc6ce8732006-11-29 18:15:52 +0000501 v = bb_strtoul(line_ptr, NULL, 16);
Denis Vlasenko28703012006-12-19 20:32:02 +0000502 if (v > 0xff)
503 /* Bad input also triggers this */
504 continue;
Denis Vlasenkoc6ce8732006-11-29 18:15:52 +0000505 return v;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000506 }
507}
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000508#endif /* FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000509
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000510#include "fdisk_aix.c"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000511
512typedef struct {
513 unsigned char info[128]; /* Informative text string */
514 unsigned char spare0[14];
515 struct sun_info {
516 unsigned char spare1;
517 unsigned char id;
518 unsigned char spare2;
519 unsigned char flags;
520 } infos[8];
521 unsigned char spare1[246]; /* Boot information etc. */
522 unsigned short rspeed; /* Disk rotational speed */
523 unsigned short pcylcount; /* Physical cylinder count */
524 unsigned short sparecyl; /* extra sects per cylinder */
525 unsigned char spare2[4]; /* More magic... */
526 unsigned short ilfact; /* Interleave factor */
527 unsigned short ncyl; /* Data cylinder count */
528 unsigned short nacyl; /* Alt. cylinder count */
529 unsigned short ntrks; /* Tracks per cylinder */
530 unsigned short nsect; /* Sectors per track */
531 unsigned char spare3[4]; /* Even more magic... */
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000532 struct sun_partinfo {
Eric Andersenacd244a2002-12-11 03:49:33 +0000533 uint32_t start_cylinder;
534 uint32_t num_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000535 } partitions[8];
536 unsigned short magic; /* Magic number */
537 unsigned short csum; /* Label xor'd checksum */
538} sun_partition;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000539#define sunlabel ((sun_partition *)MBRbuffer)
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000540STATIC_OSF void bsd_select(void);
541STATIC_OSF void xbsd_print_disklabel(int);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000542#include "fdisk_osf.c"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000543
Denis Vlasenko28703012006-12-19 20:32:02 +0000544#if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL
Denis Vlasenko10d0d4e2006-11-27 16:48:17 +0000545static uint16_t
Denis Vlasenko28703012006-12-19 20:32:02 +0000546fdisk_swap16(uint16_t x)
Rob Landleyb73451d2006-02-24 16:29:00 +0000547{
Denis Vlasenko10d0d4e2006-11-27 16:48:17 +0000548 return (x << 8) | (x >> 8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000549}
550
Rob Landley88621d72006-08-29 19:41:06 +0000551static uint32_t
Denis Vlasenko28703012006-12-19 20:32:02 +0000552fdisk_swap32(uint32_t x)
Rob Landleyb73451d2006-02-24 16:29:00 +0000553{
Denis Vlasenko10d0d4e2006-11-27 16:48:17 +0000554 return (x << 24) |
555 ((x & 0xFF00) << 8) |
556 ((x & 0xFF0000) >> 8) |
557 (x >> 24);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000558}
559#endif
560
Denis Vlasenkobd852072007-03-19 14:43:38 +0000561STATIC_SGI const char *const sgi_sys_types[];
Denis Vlasenko834410a2006-11-29 12:00:28 +0000562STATIC_SGI unsigned sgi_get_num_sectors(int i);
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000563STATIC_SGI int sgi_get_sysid(int i);
564STATIC_SGI void sgi_delete_partition(int i);
565STATIC_SGI void sgi_change_sysid(int i, int sys);
566STATIC_SGI void sgi_list_table(int xtra);
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000567#if ENABLE_FEATURE_FDISK_ADVANCED
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000568STATIC_SGI void sgi_set_xcyl(void);
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000569#endif
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000570STATIC_SGI int verify_sgi(int verbose);
571STATIC_SGI void sgi_add_partition(int n, int sys);
572STATIC_SGI void sgi_set_swappartition(int i);
573STATIC_SGI const char *sgi_get_bootfile(void);
574STATIC_SGI void sgi_set_bootfile(const char* aFile);
575STATIC_SGI void create_sgiinfo(void);
576STATIC_SGI void sgi_write_table(void);
577STATIC_SGI void sgi_set_bootpartition(int i);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000578#include "fdisk_sgi.c"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000579
Denis Vlasenkobd852072007-03-19 14:43:38 +0000580STATIC_SUN const char *const sun_sys_types[];
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000581STATIC_SUN void sun_delete_partition(int i);
582STATIC_SUN void sun_change_sysid(int i, int sys);
583STATIC_SUN void sun_list_table(int xtra);
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000584STATIC_SUN void add_sun_partition(int n, int sys);
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000585#if ENABLE_FEATURE_FDISK_ADVANCED
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000586STATIC_SUN void sun_set_alt_cyl(void);
587STATIC_SUN void sun_set_ncyl(int cyl);
588STATIC_SUN void sun_set_xcyl(void);
589STATIC_SUN void sun_set_ilfact(void);
590STATIC_SUN void sun_set_rspeed(void);
591STATIC_SUN void sun_set_pcylcount(void);
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000592#endif
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000593STATIC_SUN void toggle_sunflags(int i, unsigned char mask);
594STATIC_SUN void verify_sun(void);
595STATIC_SUN void sun_write_table(void);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000596#include "fdisk_sun.c"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000597
Denis Vlasenko834410a2006-11-29 12:00:28 +0000598#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000599/* start_sect and nr_sects are stored little endian on all machines */
600/* moreover, they are not aligned correctly */
601static void
Denis Vlasenko834410a2006-11-29 12:00:28 +0000602store4_little_endian(unsigned char *cp, unsigned val)
Rob Landleyb73451d2006-02-24 16:29:00 +0000603{
Denis Vlasenko834410a2006-11-29 12:00:28 +0000604 cp[0] = val;
605 cp[1] = val >> 8;
606 cp[2] = val >> 16;
607 cp[3] = val >> 24;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000608}
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000609#endif /* FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000610
Denis Vlasenko834410a2006-11-29 12:00:28 +0000611static unsigned
Rob Landleyb73451d2006-02-24 16:29:00 +0000612read4_little_endian(const unsigned char *cp)
613{
Denis Vlasenko834410a2006-11-29 12:00:28 +0000614 return cp[0] + (cp[1] << 8) + (cp[2] << 16) + (cp[3] << 24);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000615}
616
Denis Vlasenko834410a2006-11-29 12:00:28 +0000617#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000618static void
Denis Vlasenko834410a2006-11-29 12:00:28 +0000619set_start_sect(struct partition *p, unsigned start_sect)
Rob Landleyb73451d2006-02-24 16:29:00 +0000620{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000621 store4_little_endian(p->start4, start_sect);
622}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000623#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000624
Denis Vlasenko28703012006-12-19 20:32:02 +0000625static unsigned
Rob Landleyb73451d2006-02-24 16:29:00 +0000626get_start_sect(const struct partition *p)
627{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000628 return read4_little_endian(p->start4);
629}
630
Denis Vlasenko834410a2006-11-29 12:00:28 +0000631#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000632static void
Denis Vlasenko28703012006-12-19 20:32:02 +0000633set_nr_sects(struct partition *p, unsigned nr_sects)
Rob Landleyb73451d2006-02-24 16:29:00 +0000634{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000635 store4_little_endian(p->size4, nr_sects);
636}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000637#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000638
Denis Vlasenko28703012006-12-19 20:32:02 +0000639static unsigned
Rob Landleyb73451d2006-02-24 16:29:00 +0000640get_nr_sects(const struct partition *p)
641{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000642 return read4_little_endian(p->size4);
643}
644
Denis Vlasenkocdf62772008-03-17 08:42:43 +0000645static int ext_index; /* the prime extended partition */
646static smallint listing; /* no aborts for fdisk -l */
647static smallint dos_compatible_flag = 1;
Denis Vlasenko834410a2006-11-29 12:00:28 +0000648#if ENABLE_FEATURE_FDISK_WRITABLE
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000649//static int dos_changed;
Denis Vlasenkocdf62772008-03-17 08:42:43 +0000650static smallint nowarn; /* no warnings for fdisk -l/-s */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000651#endif
652
Denis Vlasenko834410a2006-11-29 12:00:28 +0000653static unsigned user_cylinders, user_heads, user_sectors;
654static unsigned pt_heads, pt_sectors;
655static unsigned kern_heads, kern_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000656
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +0000657static ullong extended_offset; /* offset of link pointers */
658static ullong total_number_of_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000659
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +0000660static void fdisk_fatal(const char *why)
Rob Landleyb73451d2006-02-24 16:29:00 +0000661{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000662 if (listing) {
Denis Vlasenko4437d192008-04-17 00:12:10 +0000663 close(dev_fd);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000664 longjmp(listingbuf, 1);
665 }
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +0000666 bb_error_msg_and_die(why, disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000667}
668
669static void
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +0000670seek_sector(ullong secno)
Rob Landleyb73451d2006-02-24 16:29:00 +0000671{
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +0000672 secno *= sector_size;
Denis Vlasenko06b3cc22007-09-23 14:05:54 +0000673#if ENABLE_FDISK_SUPPORT_LARGE_DISKS
Denis Vlasenko4437d192008-04-17 00:12:10 +0000674 if (lseek64(dev_fd, (off64_t)secno, SEEK_SET) == (off64_t) -1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000675 fdisk_fatal(unable_to_seek);
Denis Vlasenko06b3cc22007-09-23 14:05:54 +0000676#else
677 if (secno > MAXINT(off_t)
Denis Vlasenko4437d192008-04-17 00:12:10 +0000678 || lseek(dev_fd, (off_t)secno, SEEK_SET) == (off_t) -1
Denis Vlasenko06b3cc22007-09-23 14:05:54 +0000679 ) {
680 fdisk_fatal(unable_to_seek);
681 }
682#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000683}
684
Denis Vlasenko834410a2006-11-29 12:00:28 +0000685#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000686static void
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +0000687write_sector(ullong secno, char *buf)
Rob Landleyb73451d2006-02-24 16:29:00 +0000688{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000689 seek_sector(secno);
Denis Vlasenko4437d192008-04-17 00:12:10 +0000690 if (write(dev_fd, buf, sector_size) != sector_size)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000691 fdisk_fatal(unable_to_write);
692}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000693#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000694
695/* Allocate a buffer and read a partition table sector */
696static void
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +0000697read_pte(struct pte *pe, ullong offset)
Rob Landleyb73451d2006-02-24 16:29:00 +0000698{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000699 pe->offset = offset;
Denis Vlasenkob95636c2006-12-19 23:36:04 +0000700 pe->sectorbuffer = xmalloc(sector_size);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000701 seek_sector(offset);
Denis Vlasenko4437d192008-04-17 00:12:10 +0000702 if (read(dev_fd, pe->sectorbuffer, sector_size) != sector_size)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000703 fdisk_fatal(unable_to_read);
Denis Vlasenko834410a2006-11-29 12:00:28 +0000704#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000705 pe->changed = 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000706#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000707 pe->part_table = pe->ext_pointer = NULL;
708}
709
Denis Vlasenko834410a2006-11-29 12:00:28 +0000710static unsigned
Rob Landleyb73451d2006-02-24 16:29:00 +0000711get_partition_start(const struct pte *pe)
712{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000713 return pe->offset + get_start_sect(pe->part_table);
714}
715
Denis Vlasenko834410a2006-11-29 12:00:28 +0000716#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000717/*
718 * Avoid warning about DOS partitions when no DOS partition was changed.
719 * Here a heuristic "is probably dos partition".
720 * We might also do the opposite and warn in all cases except
721 * for "is probably nondos partition".
722 */
Denis Vlasenko89398812008-01-25 20:18:46 +0000723#ifdef UNUSED
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000724static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000725is_dos_partition(int t)
726{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000727 return (t == 1 || t == 4 || t == 6 ||
728 t == 0x0b || t == 0x0c || t == 0x0e ||
729 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
730 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
731 t == 0xc1 || t == 0xc4 || t == 0xc6);
732}
Denis Vlasenko89398812008-01-25 20:18:46 +0000733#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000734
735static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000736menu(void)
737{
Denis Vlasenkobd852072007-03-19 14:43:38 +0000738 puts("Command Action");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000739 if (LABEL_IS_SUN) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000740 puts("a\ttoggle a read only flag"); /* sun */
741 puts("b\tedit bsd disklabel");
742 puts("c\ttoggle the mountable flag"); /* sun */
743 puts("d\tdelete a partition");
744 puts("l\tlist known partition types");
745 puts("n\tadd a new partition");
746 puts("o\tcreate a new empty DOS partition table");
747 puts("p\tprint the partition table");
748 puts("q\tquit without saving changes");
749 puts("s\tcreate a new empty Sun disklabel"); /* sun */
750 puts("t\tchange a partition's system id");
751 puts("u\tchange display/entry units");
752 puts("v\tverify the partition table");
753 puts("w\twrite table to disk and exit");
Denis Vlasenko834410a2006-11-29 12:00:28 +0000754#if ENABLE_FEATURE_FDISK_ADVANCED
Denis Vlasenkobd852072007-03-19 14:43:38 +0000755 puts("x\textra functionality (experts only)");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000756#endif
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000757 } else if (LABEL_IS_SGI) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000758 puts("a\tselect bootable partition"); /* sgi flavour */
759 puts("b\tedit bootfile entry"); /* sgi */
760 puts("c\tselect sgi swap partition"); /* sgi flavour */
761 puts("d\tdelete a partition");
762 puts("l\tlist known partition types");
763 puts("n\tadd a new partition");
764 puts("o\tcreate a new empty DOS partition table");
765 puts("p\tprint the partition table");
766 puts("q\tquit without saving changes");
767 puts("s\tcreate a new empty Sun disklabel"); /* sun */
768 puts("t\tchange a partition's system id");
769 puts("u\tchange display/entry units");
770 puts("v\tverify the partition table");
771 puts("w\twrite table to disk and exit");
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000772 } else if (LABEL_IS_AIX) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000773 puts("o\tcreate a new empty DOS partition table");
774 puts("q\tquit without saving changes");
775 puts("s\tcreate a new empty Sun disklabel"); /* sun */
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000776 } else {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000777 puts("a\ttoggle a bootable flag");
778 puts("b\tedit bsd disklabel");
779 puts("c\ttoggle the dos compatibility flag");
780 puts("d\tdelete a partition");
781 puts("l\tlist known partition types");
782 puts("n\tadd a new partition");
783 puts("o\tcreate a new empty DOS partition table");
784 puts("p\tprint the partition table");
785 puts("q\tquit without saving changes");
786 puts("s\tcreate a new empty Sun disklabel"); /* sun */
787 puts("t\tchange a partition's system id");
788 puts("u\tchange display/entry units");
789 puts("v\tverify the partition table");
790 puts("w\twrite table to disk and exit");
Denis Vlasenko834410a2006-11-29 12:00:28 +0000791#if ENABLE_FEATURE_FDISK_ADVANCED
Denis Vlasenkobd852072007-03-19 14:43:38 +0000792 puts("x\textra functionality (experts only)");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000793#endif
794 }
795}
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000796#endif /* FEATURE_FDISK_WRITABLE */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000797
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000798
Denis Vlasenko834410a2006-11-29 12:00:28 +0000799#if ENABLE_FEATURE_FDISK_ADVANCED
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000800static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000801xmenu(void)
802{
Denis Vlasenkobd852072007-03-19 14:43:38 +0000803 puts("Command Action");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000804 if (LABEL_IS_SUN) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000805 puts("a\tchange number of alternate cylinders"); /*sun*/
806 puts("c\tchange number of cylinders");
807 puts("d\tprint the raw data in the partition table");
808 puts("e\tchange number of extra sectors per cylinder");/*sun*/
809 puts("h\tchange number of heads");
810 puts("i\tchange interleave factor"); /*sun*/
811 puts("o\tchange rotation speed (rpm)"); /*sun*/
812 puts("p\tprint the partition table");
813 puts("q\tquit without saving changes");
814 puts("r\treturn to main menu");
815 puts("s\tchange number of sectors/track");
816 puts("v\tverify the partition table");
817 puts("w\twrite table to disk and exit");
818 puts("y\tchange number of physical cylinders"); /*sun*/
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000819 } else if (LABEL_IS_SGI) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000820 puts("b\tmove beginning of data in a partition"); /* !sun */
821 puts("c\tchange number of cylinders");
822 puts("d\tprint the raw data in the partition table");
823 puts("e\tlist extended partitions"); /* !sun */
824 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
825 puts("h\tchange number of heads");
826 puts("p\tprint the partition table");
827 puts("q\tquit without saving changes");
828 puts("r\treturn to main menu");
829 puts("s\tchange number of sectors/track");
830 puts("v\tverify the partition table");
831 puts("w\twrite table to disk and exit");
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000832 } else if (LABEL_IS_AIX) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000833 puts("b\tmove beginning of data in a partition"); /* !sun */
834 puts("c\tchange number of cylinders");
835 puts("d\tprint the raw data in the partition table");
836 puts("e\tlist extended partitions"); /* !sun */
837 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
838 puts("h\tchange number of heads");
839 puts("p\tprint the partition table");
840 puts("q\tquit without saving changes");
841 puts("r\treturn to main menu");
842 puts("s\tchange number of sectors/track");
843 puts("v\tverify the partition table");
844 puts("w\twrite table to disk and exit");
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000845 } else {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000846 puts("b\tmove beginning of data in a partition"); /* !sun */
847 puts("c\tchange number of cylinders");
848 puts("d\tprint the raw data in the partition table");
849 puts("e\tlist extended partitions"); /* !sun */
850 puts("f\tfix partition order"); /* !sun, !aix, !sgi */
Denis Vlasenko834410a2006-11-29 12:00:28 +0000851#if ENABLE_FEATURE_SGI_LABEL
Denis Vlasenkobd852072007-03-19 14:43:38 +0000852 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000853#endif
Denis Vlasenkobd852072007-03-19 14:43:38 +0000854 puts("h\tchange number of heads");
855 puts("p\tprint the partition table");
856 puts("q\tquit without saving changes");
857 puts("r\treturn to main menu");
858 puts("s\tchange number of sectors/track");
859 puts("v\tverify the partition table");
860 puts("w\twrite table to disk and exit");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000861 }
862}
863#endif /* ADVANCED mode */
864
Denis Vlasenko834410a2006-11-29 12:00:28 +0000865#if ENABLE_FEATURE_FDISK_WRITABLE
Denis Vlasenkobd852072007-03-19 14:43:38 +0000866static const char *const *
Rob Landleyb73451d2006-02-24 16:29:00 +0000867get_sys_types(void)
868{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000869 return (
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000870 LABEL_IS_SUN ? sun_sys_types :
871 LABEL_IS_SGI ? sgi_sys_types :
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000872 i386_sys_types);
873}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000874#else
875#define get_sys_types() i386_sys_types
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000876#endif /* FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000877
Denis Vlasenkobd852072007-03-19 14:43:38 +0000878static const char *
879partition_type(unsigned char type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000880{
881 int i;
Denis Vlasenkobd852072007-03-19 14:43:38 +0000882 const char *const *types = get_sys_types();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000883
Denis Vlasenkobd852072007-03-19 14:43:38 +0000884 for (i = 0; types[i]; i++)
885 if ((unsigned char)types[i][0] == type)
886 return types[i] + 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000887
Denis Vlasenkobd852072007-03-19 14:43:38 +0000888 return "Unknown";
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000889}
890
891
Denis Vlasenko834410a2006-11-29 12:00:28 +0000892#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000893static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000894get_sysid(int i)
895{
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000896 return LABEL_IS_SUN ? sunlabel->infos[i].id :
897 (LABEL_IS_SGI ? sgi_get_sysid(i) :
898 ptes[i].part_table->sys_ind);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000899}
900
Denis Vlasenkobd852072007-03-19 14:43:38 +0000901static void
902list_types(const char *const *sys)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000903{
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000904 enum { COLS = 3 };
905
906 unsigned last[COLS];
907 unsigned done, next, size;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000908 int i;
909
Denis Vlasenkobd852072007-03-19 14:43:38 +0000910 for (size = 0; sys[size]; size++) /* */;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000911
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000912 done = 0;
913 for (i = COLS-1; i >= 0; i--) {
914 done += (size + i - done) / (i + 1);
915 last[COLS-1 - i] = done;
916 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000917
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000918 i = done = next = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000919 do {
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000920 printf("%c%2x %-22.22s", i ? ' ' : '\n',
Denis Vlasenkobd852072007-03-19 14:43:38 +0000921 (unsigned char)sys[next][0],
922 sys[next] + 1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000923 next = last[i++] + done;
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000924 if (i >= COLS || next >= last[i]) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000925 i = 0;
926 next = ++done;
927 }
928 } while (done < last[0]);
Denis Vlasenko4daad902007-09-27 10:20:47 +0000929 bb_putchar('\n');
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000930}
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000931#endif /* FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000932
933static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000934is_cleared_partition(const struct partition *p)
935{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000936 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
937 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
938 get_start_sect(p) || get_nr_sects(p));
939}
940
941static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000942clear_partition(struct partition *p)
943{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000944 if (!p)
945 return;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000946 memset(p, 0, sizeof(struct partition));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000947}
948
Denis Vlasenko834410a2006-11-29 12:00:28 +0000949#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000950static void
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +0000951set_partition(int i, int doext, ullong start, ullong stop, int sysid)
Rob Landleyb73451d2006-02-24 16:29:00 +0000952{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000953 struct partition *p;
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +0000954 ullong offset;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000955
956 if (doext) {
957 p = ptes[i].ext_pointer;
958 offset = extended_offset;
959 } else {
960 p = ptes[i].part_table;
961 offset = ptes[i].offset;
962 }
963 p->boot_ind = 0;
964 p->sys_ind = sysid;
965 set_start_sect(p, start - offset);
966 set_nr_sects(p, stop - start + 1);
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000967 if (dos_compatible_flag && (start / (g_sectors * g_heads) > 1023))
968 start = g_heads * g_sectors * 1024 - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000969 set_hsc(p->head, p->sector, p->cyl, start);
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000970 if (dos_compatible_flag && (stop / (g_sectors * g_heads) > 1023))
971 stop = g_heads * g_sectors * 1024 - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000972 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
973 ptes[i].changed = 1;
974}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000975#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000976
977static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000978warn_geometry(void)
979{
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000980 if (g_heads && g_sectors && g_cylinders)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000981 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000982
Denis Vlasenkobd852072007-03-19 14:43:38 +0000983 printf("Unknown value(s) for:");
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000984 if (!g_heads)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000985 printf(" heads");
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000986 if (!g_sectors)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000987 printf(" sectors");
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000988 if (!g_cylinders)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000989 printf(" cylinders");
990 printf(
Denis Vlasenko834410a2006-11-29 12:00:28 +0000991#if ENABLE_FEATURE_FDISK_WRITABLE
Denis Vlasenkobd852072007-03-19 14:43:38 +0000992 " (settable in the extra functions menu)"
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000993#endif
Denis Vlasenkobd852072007-03-19 14:43:38 +0000994 "\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000995 return 1;
996}
997
Denis Vlasenko8e1a0cc2007-03-18 14:42:45 +0000998static void
999update_units(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001000{
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001001 int cyl_units = g_heads * g_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001002
1003 if (display_in_cyl_units && cyl_units)
1004 units_per_sector = cyl_units;
1005 else
1006 units_per_sector = 1; /* in sectors */
1007}
1008
Denis Vlasenko834410a2006-11-29 12:00:28 +00001009#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001010static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001011warn_cylinders(void)
1012{
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001013 if (LABEL_IS_DOS && g_cylinders > 1024 && !nowarn)
Denis Vlasenkobd852072007-03-19 14:43:38 +00001014 printf("\n"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001015"The number of cylinders for this disk is set to %d.\n"
1016"There is nothing wrong with that, but this is larger than 1024,\n"
1017"and could in certain setups cause problems with:\n"
1018"1) software that runs at boot time (e.g., old versions of LILO)\n"
1019"2) booting and partitioning software from other OSs\n"
Denis Vlasenkobd852072007-03-19 14:43:38 +00001020" (e.g., DOS FDISK, OS/2 FDISK)\n",
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001021 g_cylinders);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001022}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001023#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001024
1025static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001026read_extended(int ext)
1027{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001028 int i;
1029 struct pte *pex;
1030 struct partition *p, *q;
1031
1032 ext_index = ext;
1033 pex = &ptes[ext];
1034 pex->ext_pointer = pex->part_table;
1035
1036 p = pex->part_table;
1037 if (!get_start_sect(p)) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001038 printf("Bad offset in primary extended partition\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001039 return;
1040 }
1041
Rob Landleyb73451d2006-02-24 16:29:00 +00001042 while (IS_EXTENDED(p->sys_ind)) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001043 struct pte *pe = &ptes[g_partitions];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001044
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001045 if (g_partitions >= MAXIMUM_PARTS) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001046 /* This is not a Linux restriction, but
1047 this program uses arrays of size MAXIMUM_PARTS.
Denis Vlasenko89f0b342006-11-18 22:04:09 +00001048 Do not try to 'improve' this test. */
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001049 struct pte *pre = &ptes[g_partitions - 1];
Denis Vlasenko834410a2006-11-29 12:00:28 +00001050#if ENABLE_FEATURE_FDISK_WRITABLE
Denis Vlasenkobd852072007-03-19 14:43:38 +00001051 printf("Warning: deleting partitions after %d\n",
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001052 g_partitions);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001053 pre->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001054#endif
1055 clear_partition(pre->ext_pointer);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001056 return;
1057 }
1058
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001059 read_pte(pe, extended_offset + get_start_sect(p));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001060
1061 if (!extended_offset)
1062 extended_offset = get_start_sect(p);
1063
1064 q = p = pt_offset(pe->sectorbuffer, 0);
1065 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001066 if (IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001067 if (pe->ext_pointer)
Denis Vlasenkobd852072007-03-19 14:43:38 +00001068 printf("Warning: extra link "
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001069 "pointer in partition table"
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001070 " %d\n", g_partitions + 1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001071 else
1072 pe->ext_pointer = p;
1073 } else if (p->sys_ind) {
1074 if (pe->part_table)
Denis Vlasenkobd852072007-03-19 14:43:38 +00001075 printf("Warning: ignoring extra "
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001076 "data in partition table"
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001077 " %d\n", g_partitions + 1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001078 else
1079 pe->part_table = p;
1080 }
1081 }
1082
1083 /* very strange code here... */
1084 if (!pe->part_table) {
1085 if (q != pe->ext_pointer)
1086 pe->part_table = q;
1087 else
1088 pe->part_table = q + 1;
1089 }
1090 if (!pe->ext_pointer) {
1091 if (q != pe->part_table)
1092 pe->ext_pointer = q;
1093 else
1094 pe->ext_pointer = q + 1;
1095 }
1096
1097 p = pe->ext_pointer;
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001098 g_partitions++;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001099 }
1100
Denis Vlasenko834410a2006-11-29 12:00:28 +00001101#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001102 /* remove empty links */
1103 remove:
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001104 for (i = 4; i < g_partitions; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001105 struct pte *pe = &ptes[i];
1106
Denis Vlasenkobd852072007-03-19 14:43:38 +00001107 if (!get_nr_sects(pe->part_table)
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001108 && (g_partitions > 5 || ptes[4].part_table->sys_ind)
Denis Vlasenkobd852072007-03-19 14:43:38 +00001109 ) {
1110 printf("Omitting empty partition (%d)\n", i+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001111 delete_partition(i);
1112 goto remove; /* numbering changed */
1113 }
1114 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001115#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001116}
1117
Denis Vlasenko834410a2006-11-29 12:00:28 +00001118#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001119static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001120create_doslabel(void)
1121{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001122 int i;
1123
Denis Vlasenkobd852072007-03-19 14:43:38 +00001124 printf(msg_building_new_label, "DOS disklabel");
Rob Landley5527b912006-02-25 03:46:10 +00001125
Denis Vlasenko4437d192008-04-17 00:12:10 +00001126 current_label_type = LABEL_DOS;
Rob Landley5527b912006-02-25 03:46:10 +00001127
Denis Vlasenko834410a2006-11-29 12:00:28 +00001128#if ENABLE_FEATURE_OSF_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001129 possibly_osf_label = 0;
1130#endif
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001131 g_partitions = 4;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001132
1133 for (i = 510-64; i < 510; i++)
1134 MBRbuffer[i] = 0;
1135 write_part_table_flag(MBRbuffer);
1136 extended_offset = 0;
1137 set_all_unchanged();
1138 set_changed(0);
Denis Vlasenko4437d192008-04-17 00:12:10 +00001139 get_boot(CREATE_EMPTY_DOS);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001140}
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +00001141#endif /* FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001142
1143static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001144get_sectorsize(void)
1145{
Rob Landley736e5252006-02-25 03:36:00 +00001146 if (!user_set_sector_size) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001147 int arg;
Denis Vlasenko4437d192008-04-17 00:12:10 +00001148 if (ioctl(dev_fd, BLKSSZGET, &arg) == 0)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001149 sector_size = arg;
1150 if (sector_size != DEFAULT_SECTOR_SIZE)
Denis Vlasenkobd852072007-03-19 14:43:38 +00001151 printf("Note: sector size is %d (not %d)\n",
Rob Landleyb73451d2006-02-24 16:29:00 +00001152 sector_size, DEFAULT_SECTOR_SIZE);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001153 }
1154}
1155
Rob Landley88621d72006-08-29 19:41:06 +00001156static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001157get_kernel_geometry(void)
1158{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001159 struct hd_geometry geometry;
1160
Denis Vlasenko4437d192008-04-17 00:12:10 +00001161 if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001162 kern_heads = geometry.heads;
1163 kern_sectors = geometry.sectors;
1164 /* never use geometry.cylinders - it is truncated */
1165 }
1166}
1167
1168static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001169get_partition_table_geometry(void)
1170{
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00001171 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001172 struct partition *p;
1173 int i, h, s, hh, ss;
1174 int first = 1;
1175 int bad = 0;
1176
Eric Andersen3496fdc2006-01-30 23:09:20 +00001177 if (!(valid_part_table_flag((char*)bufp)))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001178 return;
1179
1180 hh = ss = 0;
Rob Landleyb73451d2006-02-24 16:29:00 +00001181 for (i = 0; i < 4; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001182 p = pt_offset(bufp, i);
1183 if (p->sys_ind != 0) {
1184 h = p->end_head + 1;
1185 s = (p->end_sector & 077);
1186 if (first) {
1187 hh = h;
1188 ss = s;
1189 first = 0;
1190 } else if (hh != h || ss != s)
1191 bad = 1;
1192 }
1193 }
1194
1195 if (!first && !bad) {
1196 pt_heads = hh;
1197 pt_sectors = ss;
1198 }
1199}
1200
Rob Landleyb73451d2006-02-24 16:29:00 +00001201static void
1202get_geometry(void)
1203{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001204 int sec_fac;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001205
1206 get_sectorsize();
1207 sec_fac = sector_size / 512;
Denis Vlasenko834410a2006-11-29 12:00:28 +00001208#if ENABLE_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001209 guess_device_type();
1210#endif
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001211 g_heads = g_cylinders = g_sectors = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001212 kern_heads = kern_sectors = 0;
1213 pt_heads = pt_sectors = 0;
1214
1215 get_kernel_geometry();
1216 get_partition_table_geometry();
1217
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001218 g_heads = user_heads ? user_heads :
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001219 pt_heads ? pt_heads :
1220 kern_heads ? kern_heads : 255;
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001221 g_sectors = user_sectors ? user_sectors :
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001222 pt_sectors ? pt_sectors :
1223 kern_sectors ? kern_sectors : 63;
Denis Vlasenko4437d192008-04-17 00:12:10 +00001224 total_number_of_sectors = bb_BLKGETSIZE_sectors(dev_fd);
Eric Andersen040f4402003-07-30 08:40:37 +00001225
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001226 sector_offset = 1;
1227 if (dos_compatible_flag)
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001228 sector_offset = g_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001229
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001230 g_cylinders = total_number_of_sectors / (g_heads * g_sectors * sec_fac);
1231 if (!g_cylinders)
1232 g_cylinders = user_cylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001233}
1234
1235/*
Denis Vlasenko4437d192008-04-17 00:12:10 +00001236 * Opens disk_device and optionally reads MBR.
1237 * FIXME: document what each 'what' value will do!
1238 * Returns:
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001239 * -1: no 0xaa55 flag present (possibly entire disk BSD)
1240 * 0: found or created label
1241 * 1: I/O error
1242 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00001243#if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
1244static int get_boot(enum action what)
1245#else
1246static int get_boot(void)
1247#define get_boot(what) get_boot()
1248#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001249{
Denis Vlasenko4437d192008-04-17 00:12:10 +00001250 int i, fd;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001251
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001252 g_partitions = 4;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001253 for (i = 0; i < 4; i++) {
1254 struct pte *pe = &ptes[i];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001255 pe->part_table = pt_offset(MBRbuffer, i);
1256 pe->ext_pointer = NULL;
1257 pe->offset = 0;
1258 pe->sectorbuffer = MBRbuffer;
Denis Vlasenko834410a2006-11-29 12:00:28 +00001259#if ENABLE_FEATURE_FDISK_WRITABLE
Denis Vlasenko4437d192008-04-17 00:12:10 +00001260 pe->changed = (what == CREATE_EMPTY_DOS);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001261#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001262 }
1263
Denis Vlasenko834410a2006-11-29 12:00:28 +00001264#if ENABLE_FEATURE_FDISK_WRITABLE
Denis Vlasenko4437d192008-04-17 00:12:10 +00001265// ALERT! highly idiotic design!
1266// We end up here when we call get_boot() recursively
1267// via get_boot() [table is bad] -> create_doslabel() -> get_boot(CREATE_EMPTY_DOS).
1268// or get_boot() [table is bad] -> create_sunlabel() -> get_boot(CREATE_EMPTY_SUN).
1269// (just factor out re-init of ptes[0,1,2,3] in a separate fn instead?)
1270// So skip opening device _again_...
1271 if (what == CREATE_EMPTY_DOS USE_FEATURE_SUN_LABEL(|| what == CREATE_EMPTY_SUN))
1272 goto created_table;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001273
Denis Vlasenko4437d192008-04-17 00:12:10 +00001274 fd = open(disk_device, (option_mask32 & OPT_l) ? O_RDONLY : O_RDWR);
1275
Denis Vlasenkobd852072007-03-19 14:43:38 +00001276 if (fd < 0) {
1277 fd = open(disk_device, O_RDONLY);
1278 if (fd < 0) {
Denis Vlasenko4437d192008-04-17 00:12:10 +00001279 if (what == TRY_ONLY)
Rob Landleyb73451d2006-02-24 16:29:00 +00001280 return 1;
1281 fdisk_fatal(unable_to_open);
Denis Vlasenko4437d192008-04-17 00:12:10 +00001282 }
1283 xmove_fd(fd, dev_fd);
1284 printf("'%s' is opened for read only\n", disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001285 }
Denis Vlasenko4437d192008-04-17 00:12:10 +00001286 if (512 != read(dev_fd, MBRbuffer, 512)) {
1287 if (what == TRY_ONLY) {
1288 close(dev_fd);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001289 return 1;
Denis Vlasenko4437d192008-04-17 00:12:10 +00001290 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001291 fdisk_fatal(unable_to_read);
1292 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001293#else
Denis Vlasenkobd852072007-03-19 14:43:38 +00001294 fd = open(disk_device, O_RDONLY);
1295 if (fd < 0)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001296 return 1;
Denis Vlasenko4437d192008-04-17 00:12:10 +00001297 if (512 != read(fd, MBRbuffer, 512)) {
1298 close(fd);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001299 return 1;
Denis Vlasenko4437d192008-04-17 00:12:10 +00001300 }
1301 xmove_fd(fd, dev_fd);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001302#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001303
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001304 get_geometry();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001305 update_units();
1306
Denis Vlasenko834410a2006-11-29 12:00:28 +00001307#if ENABLE_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001308 if (check_sun_label())
1309 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001310#endif
Denis Vlasenko834410a2006-11-29 12:00:28 +00001311#if ENABLE_FEATURE_SGI_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001312 if (check_sgi_label())
1313 return 0;
1314#endif
Denis Vlasenko834410a2006-11-29 12:00:28 +00001315#if ENABLE_FEATURE_AIX_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001316 if (check_aix_label())
1317 return 0;
1318#endif
Denis Vlasenko834410a2006-11-29 12:00:28 +00001319#if ENABLE_FEATURE_OSF_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001320 if (check_osf_label()) {
1321 possibly_osf_label = 1;
1322 if (!valid_part_table_flag(MBRbuffer)) {
Denis Vlasenko4437d192008-04-17 00:12:10 +00001323 current_label_type = LABEL_OSF;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001324 return 0;
1325 }
Denis Vlasenkobd852072007-03-19 14:43:38 +00001326 printf("This disk has both DOS and BSD magic.\n"
1327 "Give the 'b' command to go to BSD mode.\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001328 }
1329#endif
1330
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +00001331#if !ENABLE_FEATURE_FDISK_WRITABLE
Denis Vlasenko4437d192008-04-17 00:12:10 +00001332 if (!valid_part_table_flag(MBRbuffer))
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001333 return -1;
1334#else
Denis Vlasenko4437d192008-04-17 00:12:10 +00001335 if (!valid_part_table_flag(MBRbuffer)) {
1336 if (what == OPEN_MAIN) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001337 printf("Device contains neither a valid DOS "
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001338 "partition table, nor Sun, SGI or OSF "
Denis Vlasenkobd852072007-03-19 14:43:38 +00001339 "disklabel\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001340#ifdef __sparc__
Denis Vlasenko4437d192008-04-17 00:12:10 +00001341 USE_FEATURE_SUN_LABEL(create_sunlabel();)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001342#else
1343 create_doslabel();
1344#endif
1345 return 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001346 }
Denis Vlasenko4437d192008-04-17 00:12:10 +00001347 /* TRY_ONLY: */
1348 return -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001349 }
Denis Vlasenko4437d192008-04-17 00:12:10 +00001350 created_table:
1351#endif /* FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001352
Denis Vlasenko4437d192008-04-17 00:12:10 +00001353
1354 USE_FEATURE_FDISK_WRITABLE(warn_cylinders();)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001355 warn_geometry();
1356
1357 for (i = 0; i < 4; i++) {
Denis Vlasenko4437d192008-04-17 00:12:10 +00001358 if (IS_EXTENDED(ptes[i].part_table->sys_ind)) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001359 if (g_partitions != 4)
Denis Vlasenkobd852072007-03-19 14:43:38 +00001360 printf("Ignoring extra extended "
1361 "partition %d\n", i + 1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001362 else
1363 read_extended(i);
1364 }
1365 }
1366
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001367 for (i = 3; i < g_partitions; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001368 struct pte *pe = &ptes[i];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001369 if (!valid_part_table_flag(pe->sectorbuffer)) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001370 printf("Warning: invalid flag 0x%02x,0x%02x of partition "
1371 "table %d will be corrected by w(rite)\n",
Denis Vlasenko834410a2006-11-29 12:00:28 +00001372 pe->sectorbuffer[510],
1373 pe->sectorbuffer[511],
1374 i + 1);
Denis Vlasenko4437d192008-04-17 00:12:10 +00001375 USE_FEATURE_FDISK_WRITABLE(pe->changed = 1;)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001376 }
1377 }
1378
1379 return 0;
1380}
1381
Denis Vlasenko834410a2006-11-29 12:00:28 +00001382#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001383/*
1384 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
1385 * If the user hits Enter, DFLT is returned.
1386 * Answers like +10 are interpreted as offsets from BASE.
1387 *
1388 * There is no default if DFLT is not between LOW and HIGH.
1389 */
Denis Vlasenko834410a2006-11-29 12:00:28 +00001390static unsigned
Denis Vlasenko06c0a712007-01-29 22:51:44 +00001391read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, const char *mesg)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001392{
Denis Vlasenko834410a2006-11-29 12:00:28 +00001393 unsigned i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001394 int default_ok = 1;
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001395 const char *fmt = "%s (%u-%u, default %u): ";
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001396
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001397 if (dflt < low || dflt > high) {
1398 fmt = "%s (%u-%u): ";
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001399 default_ok = 0;
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001400 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001401
1402 while (1) {
1403 int use_default = default_ok;
1404
1405 /* ask question and read answer */
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001406 do {
1407 printf(fmt, mesg, low, high, dflt);
1408 read_maybe_empty("");
1409 } while (*line_ptr != '\n' && !isdigit(*line_ptr)
1410 && *line_ptr != '-' && *line_ptr != '+');
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001411
Eric Andersen84bdea82004-05-19 10:49:17 +00001412 if (*line_ptr == '+' || *line_ptr == '-') {
Rob Landleyb73451d2006-02-24 16:29:00 +00001413 int minus = (*line_ptr == '-');
1414 int absolute = 0;
Eric Andersenc48d49a2003-07-03 10:02:32 +00001415
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001416 i = atoi(line_ptr + 1);
Eric Andersenc48d49a2003-07-03 10:02:32 +00001417
Rob Landleyb73451d2006-02-24 16:29:00 +00001418 while (isdigit(*++line_ptr))
1419 use_default = 0;
Eric Andersen84bdea82004-05-19 10:49:17 +00001420
Rob Landleyb73451d2006-02-24 16:29:00 +00001421 switch (*line_ptr) {
1422 case 'c':
1423 case 'C':
1424 if (!display_in_cyl_units)
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001425 i *= g_heads * g_sectors;
Rob Landleyb73451d2006-02-24 16:29:00 +00001426 break;
1427 case 'K':
1428 absolute = 1024;
1429 break;
1430 case 'k':
1431 absolute = 1000;
1432 break;
1433 case 'm':
1434 case 'M':
1435 absolute = 1000000;
1436 break;
1437 case 'g':
1438 case 'G':
1439 absolute = 1000000000;
1440 break;
1441 default:
1442 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001443 }
Rob Landleyb73451d2006-02-24 16:29:00 +00001444 if (absolute) {
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00001445 ullong bytes;
Rob Landleyb73451d2006-02-24 16:29:00 +00001446 unsigned long unit;
1447
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00001448 bytes = (ullong) i * absolute;
Rob Landleyb73451d2006-02-24 16:29:00 +00001449 unit = sector_size * units_per_sector;
1450 bytes += unit/2; /* round */
1451 bytes /= unit;
1452 i = bytes;
1453 }
1454 if (minus)
1455 i = -i;
1456 i += base;
Eric Andersen84bdea82004-05-19 10:49:17 +00001457 } else {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001458 i = atoi(line_ptr);
1459 while (isdigit(*line_ptr)) {
1460 line_ptr++;
1461 use_default = 0;
1462 }
1463 }
Denis Vlasenkobd852072007-03-19 14:43:38 +00001464 if (use_default) {
1465 i = dflt;
1466 printf("Using default value %u\n", i);
1467 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001468 if (i >= low && i <= high)
1469 break;
Denis Vlasenkobd852072007-03-19 14:43:38 +00001470 printf("Value is out of range\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001471 }
1472 return i;
1473}
1474
Rob Landleyb73451d2006-02-24 16:29:00 +00001475static int
1476get_partition(int warn, int max)
1477{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001478 struct pte *pe;
1479 int i;
1480
Denis Vlasenkobd852072007-03-19 14:43:38 +00001481 i = read_int(1, 0, max, 0, "Partition number") - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001482 pe = &ptes[i];
1483
1484 if (warn) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001485 if ((!LABEL_IS_SUN && !LABEL_IS_SGI && !pe->part_table->sys_ind)
1486 || (LABEL_IS_SUN && (!sunlabel->partitions[i].num_sectors || !sunlabel->infos[i].id))
1487 || (LABEL_IS_SGI && !sgi_get_num_sectors(i))
1488 ) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001489 printf("Warning: partition %d has empty type\n", i+1);
Rob Landley5527b912006-02-25 03:46:10 +00001490 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001491 }
1492 return i;
1493}
1494
1495static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001496get_existing_partition(int warn, int max)
1497{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001498 int pno = -1;
1499 int i;
1500
1501 for (i = 0; i < max; i++) {
1502 struct pte *pe = &ptes[i];
1503 struct partition *p = pe->part_table;
1504
1505 if (p && !is_cleared_partition(p)) {
1506 if (pno >= 0)
1507 goto not_unique;
1508 pno = i;
1509 }
1510 }
1511 if (pno >= 0) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001512 printf("Selected partition %d\n", pno+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001513 return pno;
1514 }
Denis Vlasenkobd852072007-03-19 14:43:38 +00001515 printf("No partition is defined yet!\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001516 return -1;
1517
1518 not_unique:
1519 return get_partition(warn, max);
1520}
1521
1522static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001523get_nonexisting_partition(int warn, int max)
1524{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001525 int pno = -1;
1526 int i;
1527
1528 for (i = 0; i < max; i++) {
1529 struct pte *pe = &ptes[i];
1530 struct partition *p = pe->part_table;
1531
1532 if (p && is_cleared_partition(p)) {
1533 if (pno >= 0)
1534 goto not_unique;
1535 pno = i;
1536 }
1537 }
1538 if (pno >= 0) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001539 printf("Selected partition %d\n", pno+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001540 return pno;
1541 }
Denis Vlasenkobd852072007-03-19 14:43:38 +00001542 printf("All primary partitions have been defined already!\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001543 return -1;
1544
1545 not_unique:
1546 return get_partition(warn, max);
1547}
1548
1549
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001550static void
1551change_units(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001552{
1553 display_in_cyl_units = !display_in_cyl_units;
1554 update_units();
Denis Vlasenkobd852072007-03-19 14:43:38 +00001555 printf("Changing display/entry units to %s\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001556 str_units(PLURAL));
1557}
1558
1559static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001560toggle_active(int i)
1561{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001562 struct pte *pe = &ptes[i];
1563 struct partition *p = pe->part_table;
1564
Rob Landleyb73451d2006-02-24 16:29:00 +00001565 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
Denis Vlasenkobd852072007-03-19 14:43:38 +00001566 printf("WARNING: Partition %d is an extended partition\n", i + 1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001567 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
1568 pe->changed = 1;
1569}
1570
1571static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001572toggle_dos_compatibility_flag(void)
1573{
Denis Vlasenkocdf62772008-03-17 08:42:43 +00001574 dos_compatible_flag = 1 - dos_compatible_flag;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001575 if (dos_compatible_flag) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001576 sector_offset = g_sectors;
Denis Vlasenkobd852072007-03-19 14:43:38 +00001577 printf("DOS Compatibility flag is set\n");
1578 } else {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001579 sector_offset = 1;
Denis Vlasenkobd852072007-03-19 14:43:38 +00001580 printf("DOS Compatibility flag is not set\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001581 }
1582}
1583
1584static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001585delete_partition(int i)
1586{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001587 struct pte *pe = &ptes[i];
1588 struct partition *p = pe->part_table;
1589 struct partition *q = pe->ext_pointer;
1590
1591/* Note that for the fifth partition (i == 4) we don't actually
1592 * decrement partitions.
1593 */
1594
1595 if (warn_geometry())
1596 return; /* C/H/S not set */
1597 pe->changed = 1;
1598
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001599 if (LABEL_IS_SUN) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001600 sun_delete_partition(i);
1601 return;
1602 }
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001603 if (LABEL_IS_SGI) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001604 sgi_delete_partition(i);
1605 return;
1606 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001607
1608 if (i < 4) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001609 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001610 g_partitions = 4;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001611 ptes[ext_index].ext_pointer = NULL;
1612 extended_offset = 0;
1613 }
1614 clear_partition(p);
1615 return;
1616 }
1617
1618 if (!q->sys_ind && i > 4) {
1619 /* the last one in the chain - just delete */
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001620 --g_partitions;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001621 --i;
1622 clear_partition(ptes[i].ext_pointer);
1623 ptes[i].changed = 1;
1624 } else {
1625 /* not the last one - further ones will be moved down */
1626 if (i > 4) {
1627 /* delete this link in the chain */
1628 p = ptes[i-1].ext_pointer;
1629 *p = *q;
1630 set_start_sect(p, get_start_sect(q));
1631 set_nr_sects(p, get_nr_sects(q));
1632 ptes[i-1].changed = 1;
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001633 } else if (g_partitions > 5) { /* 5 will be moved to 4 */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001634 /* the first logical in a longer chain */
1635 pe = &ptes[5];
1636
1637 if (pe->part_table) /* prevent SEGFAULT */
1638 set_start_sect(pe->part_table,
Rob Landleyb73451d2006-02-24 16:29:00 +00001639 get_partition_start(pe) -
1640 extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001641 pe->offset = extended_offset;
1642 pe->changed = 1;
1643 }
1644
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001645 if (g_partitions > 5) {
1646 g_partitions--;
1647 while (i < g_partitions) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001648 ptes[i] = ptes[i+1];
1649 i++;
1650 }
1651 } else
1652 /* the only logical: clear only */
1653 clear_partition(ptes[i].part_table);
1654 }
1655}
1656
1657static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001658change_sysid(void)
1659{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001660 int i, sys, origsys;
1661 struct partition *p;
1662
Eric Andersen040f4402003-07-30 08:40:37 +00001663 /* If sgi_label then don't use get_existing_partition,
1664 let the user select a partition, since get_existing_partition()
1665 only works for Linux like partition tables. */
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001666 if (!LABEL_IS_SGI) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001667 i = get_existing_partition(0, g_partitions);
Eric Andersen040f4402003-07-30 08:40:37 +00001668 } else {
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001669 i = get_partition(0, g_partitions);
Eric Andersen040f4402003-07-30 08:40:37 +00001670 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001671 if (i == -1)
1672 return;
1673 p = ptes[i].part_table;
1674 origsys = sys = get_sysid(i);
1675
1676 /* if changing types T to 0 is allowed, then
1677 the reverse change must be allowed, too */
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001678 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN && !get_nr_sects(p)) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001679 printf("Partition %d does not exist yet!\n", i + 1);
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001680 return;
1681 }
1682 while (1) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001683 sys = read_hex(get_sys_types());
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001684
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001685 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001686 printf("Type 0 means free space to many systems\n"
Rob Landleyb73451d2006-02-24 16:29:00 +00001687 "(but not to Linux). Having partitions of\n"
Denis Vlasenkobd852072007-03-19 14:43:38 +00001688 "type 0 is probably unwise.\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001689 /* break; */
1690 }
1691
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001692 if (!LABEL_IS_SUN && !LABEL_IS_SGI) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001693 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001694 printf("You cannot change a partition into"
1695 " an extended one or vice versa\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001696 break;
1697 }
1698 }
1699
1700 if (sys < 256) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001701#if ENABLE_FEATURE_SUN_LABEL
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001702 if (LABEL_IS_SUN && i == 2 && sys != SUN_WHOLE_DISK)
Denis Vlasenkobd852072007-03-19 14:43:38 +00001703 printf("Consider leaving partition 3 "
Rob Landleyb73451d2006-02-24 16:29:00 +00001704 "as Whole disk (5),\n"
1705 "as SunOS/Solaris expects it and "
Denis Vlasenkobd852072007-03-19 14:43:38 +00001706 "even Linux likes it\n\n");
1707#endif
1708#if ENABLE_FEATURE_SGI_LABEL
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001709 if (LABEL_IS_SGI &&
Rob Landley5527b912006-02-25 03:46:10 +00001710 (
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001711 (i == 10 && sys != SGI_ENTIRE_DISK) ||
Rob Landley5527b912006-02-25 03:46:10 +00001712 (i == 8 && sys != 0)
1713 )
Denis Vlasenkobd852072007-03-19 14:43:38 +00001714 ) {
1715 printf("Consider leaving partition 9 "
Rob Landleyb73451d2006-02-24 16:29:00 +00001716 "as volume header (0),\nand "
1717 "partition 11 as entire volume (6)"
Denis Vlasenkobd852072007-03-19 14:43:38 +00001718 "as IRIX expects it\n\n");
Rob Landley5527b912006-02-25 03:46:10 +00001719 }
Denis Vlasenkobd852072007-03-19 14:43:38 +00001720#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001721 if (sys == origsys)
1722 break;
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001723 if (LABEL_IS_SUN) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001724 sun_change_sysid(i, sys);
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001725 } else if (LABEL_IS_SGI) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001726 sgi_change_sysid(i, sys);
1727 } else
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001728 p->sys_ind = sys;
Rob Landley5527b912006-02-25 03:46:10 +00001729
Denis Vlasenkobd852072007-03-19 14:43:38 +00001730 printf("Changed system type of partition %d "
1731 "to %x (%s)\n", i + 1, sys,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001732 partition_type(sys));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001733 ptes[i].changed = 1;
Denis Vlasenkoa5549c92008-01-24 22:49:15 +00001734 //if (is_dos_partition(origsys) || is_dos_partition(sys))
1735 // dos_changed = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001736 break;
1737 }
1738 }
1739}
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +00001740#endif /* FEATURE_FDISK_WRITABLE */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001741
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001742
Denis Vlasenko28703012006-12-19 20:32:02 +00001743/* check_consistency() and linear2chs() added Sat Mar 6 12:28:16 1993,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001744 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
1745 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
1746 * Lubkin Oct. 1991). */
1747
Rob Landleyb73451d2006-02-24 16:29:00 +00001748static void
Denis Vlasenko28703012006-12-19 20:32:02 +00001749linear2chs(unsigned ls, unsigned *c, unsigned *h, unsigned *s)
Rob Landleyb73451d2006-02-24 16:29:00 +00001750{
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001751 int spc = g_heads * g_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001752
1753 *c = ls / spc;
1754 ls = ls % spc;
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001755 *h = ls / g_sectors;
1756 *s = ls % g_sectors + 1; /* sectors count from 1 */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001757}
1758
Rob Landleyb73451d2006-02-24 16:29:00 +00001759static void
1760check_consistency(const struct partition *p, int partition)
1761{
Denis Vlasenko834410a2006-11-29 12:00:28 +00001762 unsigned pbc, pbh, pbs; /* physical beginning c, h, s */
1763 unsigned pec, peh, pes; /* physical ending c, h, s */
1764 unsigned lbc, lbh, lbs; /* logical beginning c, h, s */
1765 unsigned lec, leh, les; /* logical ending c, h, s */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001766
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001767 if (!g_heads || !g_sectors || (partition >= 4))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001768 return; /* do not check extended partitions */
1769
1770/* physical beginning c, h, s */
1771 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
1772 pbh = p->head;
1773 pbs = p->sector & 0x3f;
1774
1775/* physical ending c, h, s */
1776 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
1777 peh = p->end_head;
1778 pes = p->end_sector & 0x3f;
1779
1780/* compute logical beginning (c, h, s) */
Denis Vlasenko28703012006-12-19 20:32:02 +00001781 linear2chs(get_start_sect(p), &lbc, &lbh, &lbs);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001782
1783/* compute logical ending (c, h, s) */
Denis Vlasenko28703012006-12-19 20:32:02 +00001784 linear2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001785
1786/* Same physical / logical beginning? */
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001787 if (g_cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001788 printf("Partition %d has different physical/logical "
1789 "beginnings (non-Linux?):\n", partition + 1);
1790 printf(" phys=(%d, %d, %d) ", pbc, pbh, pbs);
1791 printf("logical=(%d, %d, %d)\n",lbc, lbh, lbs);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001792 }
1793
1794/* Same physical / logical ending? */
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001795 if (g_cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001796 printf("Partition %d has different physical/logical "
1797 "endings:\n", partition + 1);
1798 printf(" phys=(%d, %d, %d) ", pec, peh, pes);
1799 printf("logical=(%d, %d, %d)\n", lec, leh, les);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001800 }
1801
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001802/* Ending on cylinder boundary? */
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001803 if (peh != (g_heads - 1) || pes != g_sectors) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001804 printf("Partition %i does not end on cylinder boundary\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001805 partition + 1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001806 }
1807}
1808
1809static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001810list_disk_geometry(void)
1811{
Eric Andersen040f4402003-07-30 08:40:37 +00001812 long long bytes = (total_number_of_sectors << 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001813 long megabytes = bytes/1000000;
1814
1815 if (megabytes < 10000)
Denis Vlasenkobd852072007-03-19 14:43:38 +00001816 printf("\nDisk %s: %ld MB, %lld bytes\n",
Rob Landleyb73451d2006-02-24 16:29:00 +00001817 disk_device, megabytes, bytes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001818 else
Denis Vlasenkobd852072007-03-19 14:43:38 +00001819 printf("\nDisk %s: %ld.%ld GB, %lld bytes\n",
Rob Landleyb73451d2006-02-24 16:29:00 +00001820 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
Denis Vlasenkobd852072007-03-19 14:43:38 +00001821 printf("%d heads, %d sectors/track, %d cylinders",
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001822 g_heads, g_sectors, g_cylinders);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001823 if (units_per_sector == 1)
Denis Vlasenkobd852072007-03-19 14:43:38 +00001824 printf(", total %llu sectors",
Rob Landleyb73451d2006-02-24 16:29:00 +00001825 total_number_of_sectors / (sector_size/512));
Denis Vlasenkobd852072007-03-19 14:43:38 +00001826 printf("\nUnits = %s of %d * %d = %d bytes\n\n",
Rob Landleyb73451d2006-02-24 16:29:00 +00001827 str_units(PLURAL),
1828 units_per_sector, sector_size, units_per_sector * sector_size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001829}
1830
1831/*
1832 * Check whether partition entries are ordered by their starting positions.
1833 * Return 0 if OK. Return i if partition i should have been earlier.
1834 * Two separate checks: primary and logical partitions.
1835 */
1836static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001837wrong_p_order(int *prev)
1838{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001839 const struct pte *pe;
1840 const struct partition *p;
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00001841 ullong last_p_start_pos = 0, p_start_pos;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001842 int i, last_i = 0;
1843
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001844 for (i = 0; i < g_partitions; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001845 if (i == 4) {
1846 last_i = 4;
1847 last_p_start_pos = 0;
1848 }
1849 pe = &ptes[i];
Denis Vlasenko6bef3d12007-11-06 03:05:54 +00001850 p = pe->part_table;
1851 if (p->sys_ind) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001852 p_start_pos = get_partition_start(pe);
1853
1854 if (last_p_start_pos > p_start_pos) {
1855 if (prev)
1856 *prev = last_i;
1857 return i;
1858 }
1859
1860 last_p_start_pos = p_start_pos;
1861 last_i = i;
1862 }
1863 }
1864 return 0;
1865}
1866
Denis Vlasenko834410a2006-11-29 12:00:28 +00001867#if ENABLE_FEATURE_FDISK_ADVANCED
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001868/*
1869 * Fix the chain of logicals.
1870 * extended_offset is unchanged, the set of sectors used is unchanged
1871 * The chain is sorted so that sectors increase, and so that
1872 * starting sectors increase.
1873 *
1874 * After this it may still be that cfdisk doesnt like the table.
1875 * (This is because cfdisk considers expanded parts, from link to
1876 * end of partition, and these may still overlap.)
1877 * Now
1878 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
1879 * may help.
1880 */
1881static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001882fix_chain_of_logicals(void)
1883{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001884 int j, oj, ojj, sj, sjj;
1885 struct partition *pj,*pjj,tmp;
1886
1887 /* Stage 1: sort sectors but leave sector of part 4 */
1888 /* (Its sector is the global extended_offset.) */
1889 stage1:
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001890 for (j = 5; j < g_partitions - 1; j++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001891 oj = ptes[j].offset;
1892 ojj = ptes[j+1].offset;
1893 if (oj > ojj) {
1894 ptes[j].offset = ojj;
1895 ptes[j+1].offset = oj;
1896 pj = ptes[j].part_table;
1897 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
1898 pjj = ptes[j+1].part_table;
1899 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
1900 set_start_sect(ptes[j-1].ext_pointer,
Rob Landleyb73451d2006-02-24 16:29:00 +00001901 ojj-extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001902 set_start_sect(ptes[j].ext_pointer,
Rob Landleyb73451d2006-02-24 16:29:00 +00001903 oj-extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001904 goto stage1;
1905 }
1906 }
1907
1908 /* Stage 2: sort starting sectors */
1909 stage2:
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001910 for (j = 4; j < g_partitions - 1; j++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001911 pj = ptes[j].part_table;
1912 pjj = ptes[j+1].part_table;
1913 sj = get_start_sect(pj);
1914 sjj = get_start_sect(pjj);
1915 oj = ptes[j].offset;
1916 ojj = ptes[j+1].offset;
1917 if (oj+sj > ojj+sjj) {
1918 tmp = *pj;
1919 *pj = *pjj;
1920 *pjj = tmp;
1921 set_start_sect(pj, ojj+sjj-oj);
1922 set_start_sect(pjj, oj+sj-ojj);
1923 goto stage2;
1924 }
1925 }
1926
1927 /* Probably something was changed */
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001928 for (j = 4; j < g_partitions; j++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001929 ptes[j].changed = 1;
1930}
1931
1932
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001933static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001934fix_partition_table_order(void)
1935{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001936 struct pte *pei, *pek;
1937 int i,k;
1938
1939 if (!wrong_p_order(NULL)) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001940 printf("Ordering is already correct\n\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001941 return;
1942 }
1943
1944 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
1945 /* partition i should have come earlier, move it */
1946 /* We have to move data in the MBR */
1947 struct partition *pi, *pk, *pe, pbuf;
1948 pei = &ptes[i];
1949 pek = &ptes[k];
1950
1951 pe = pei->ext_pointer;
1952 pei->ext_pointer = pek->ext_pointer;
1953 pek->ext_pointer = pe;
1954
1955 pi = pei->part_table;
1956 pk = pek->part_table;
1957
1958 memmove(&pbuf, pi, sizeof(struct partition));
1959 memmove(pi, pk, sizeof(struct partition));
1960 memmove(pk, &pbuf, sizeof(struct partition));
1961
1962 pei->changed = pek->changed = 1;
1963 }
1964
1965 if (i)
1966 fix_chain_of_logicals();
1967
1968 printf("Done.\n");
1969
1970}
1971#endif
1972
1973static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001974list_table(int xtra)
1975{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001976 const struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001977 int i, w;
1978
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001979 if (LABEL_IS_SUN) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001980 sun_list_table(xtra);
1981 return;
1982 }
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001983 if (LABEL_IS_SUN) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001984 sgi_list_table(xtra);
1985 return;
1986 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001987
1988 list_disk_geometry();
1989
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001990 if (LABEL_IS_OSF) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001991 xbsd_print_disklabel(xtra);
1992 return;
1993 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001994
1995 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
1996 but if the device name ends in a digit, say /dev/foo1,
1997 then the partition is called /dev/foo1p3. */
1998 w = strlen(disk_device);
1999 if (w && isdigit(disk_device[w-1]))
2000 w++;
2001 if (w < 5)
2002 w = 5;
2003
Denis Vlasenkobd852072007-03-19 14:43:38 +00002004 // 1 12345678901 12345678901 12345678901 12
2005 printf("%*s Boot Start End Blocks Id System\n",
2006 w+1, "Device");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002007
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002008 for (i = 0; i < g_partitions; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002009 const struct pte *pe = &ptes[i];
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00002010 ullong psects;
2011 ullong pblocks;
Denis Vlasenko834410a2006-11-29 12:00:28 +00002012 unsigned podd;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002013
2014 p = pe->part_table;
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002015 if (!p || is_cleared_partition(p))
2016 continue;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002017
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002018 psects = get_nr_sects(p);
2019 pblocks = psects;
2020 podd = 0;
2021
2022 if (sector_size < 1024) {
2023 pblocks /= (1024 / sector_size);
2024 podd = psects % (1024 / sector_size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002025 }
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002026 if (sector_size > 1024)
2027 pblocks *= (sector_size / 1024);
2028
2029 printf("%s %c %11llu %11llu %11llu%c %2x %s\n",
2030 partname(disk_device, i+1, w+2),
2031 !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG /* boot flag */
2032 ? '*' : '?',
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00002033 (ullong) cround(get_partition_start(pe)), /* start */
2034 (ullong) cround(get_partition_start(pe) + psects /* end */
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002035 - (psects ? 1 : 0)),
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00002036 (ullong) pblocks, podd ? '+' : ' ', /* odd flag on end */
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002037 p->sys_ind, /* type id */
2038 partition_type(p->sys_ind)); /* type name */
2039
2040 check_consistency(p, i);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002041 }
2042
2043 /* Is partition table in disk order? It need not be, but... */
2044 /* partition table entries are not checked for correct order if this
2045 is a sgi, sun or aix labeled disk... */
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002046 if (LABEL_IS_DOS && wrong_p_order(NULL)) {
Rob Landley5527b912006-02-25 03:46:10 +00002047 /* FIXME */
Denis Vlasenkobd852072007-03-19 14:43:38 +00002048 printf("\nPartition table entries are not in disk order\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002049 }
2050}
2051
Denis Vlasenko834410a2006-11-29 12:00:28 +00002052#if ENABLE_FEATURE_FDISK_ADVANCED
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002053static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002054x_list_table(int extend)
2055{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002056 const struct pte *pe;
2057 const struct partition *p;
2058 int i;
2059
Denis Vlasenkobd852072007-03-19 14:43:38 +00002060 printf("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n",
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002061 disk_device, g_heads, g_sectors, g_cylinders);
Denis Vlasenkobd852072007-03-19 14:43:38 +00002062 printf("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n");
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002063 for (i = 0; i < g_partitions; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002064 pe = &ptes[i];
2065 p = (extend ? pe->ext_pointer : pe->part_table);
2066 if (p != NULL) {
Eric Andersen040f4402003-07-30 08:40:37 +00002067 printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002068 i + 1, p->boot_ind, p->head,
2069 sector(p->sector),
2070 cylinder(p->sector, p->cyl), p->end_head,
2071 sector(p->end_sector),
2072 cylinder(p->end_sector, p->end_cyl),
2073 get_start_sect(p), get_nr_sects(p), p->sys_ind);
2074 if (p->sys_ind)
2075 check_consistency(p, i);
2076 }
2077 }
2078}
2079#endif
2080
Denis Vlasenko834410a2006-11-29 12:00:28 +00002081#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002082static void
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00002083fill_bounds(ullong *first, ullong *last)
Rob Landleyb73451d2006-02-24 16:29:00 +00002084{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002085 int i;
2086 const struct pte *pe = &ptes[0];
2087 const struct partition *p;
2088
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002089 for (i = 0; i < g_partitions; pe++,i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002090 p = pe->part_table;
Rob Landleyb73451d2006-02-24 16:29:00 +00002091 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002092 first[i] = 0xffffffff;
2093 last[i] = 0;
2094 } else {
2095 first[i] = get_partition_start(pe);
2096 last[i] = first[i] + get_nr_sects(p) - 1;
2097 }
2098 }
2099}
2100
2101static void
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00002102check(int n, unsigned h, unsigned s, unsigned c, ullong start)
Rob Landleyb73451d2006-02-24 16:29:00 +00002103{
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00002104 ullong total, real_s, real_c;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002105
2106 real_s = sector(s) - 1;
2107 real_c = cylinder(s, c);
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002108 total = (real_c * g_sectors + real_s) * g_heads + h;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002109 if (!total)
Denis Vlasenkobd852072007-03-19 14:43:38 +00002110 printf("Partition %d contains sector 0\n", n);
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002111 if (h >= g_heads)
Denis Vlasenkobd852072007-03-19 14:43:38 +00002112 printf("Partition %d: head %d greater than maximum %d\n",
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002113 n, h + 1, g_heads);
2114 if (real_s >= g_sectors)
Denis Vlasenkobd852072007-03-19 14:43:38 +00002115 printf("Partition %d: sector %d greater than "
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002116 "maximum %d\n", n, s, g_sectors);
2117 if (real_c >= g_cylinders)
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00002118 printf("Partition %d: cylinder %llu greater than "
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002119 "maximum %d\n", n, real_c + 1, g_cylinders);
2120 if (g_cylinders <= 1024 && start != total)
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00002121 printf("Partition %d: previous sectors %llu disagrees with "
2122 "total %llu\n", n, start, total);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002123}
2124
2125static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002126verify(void)
2127{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002128 int i, j;
Denis Vlasenko834410a2006-11-29 12:00:28 +00002129 unsigned total = 1;
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002130 ullong first[g_partitions], last[g_partitions];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002131 struct partition *p;
2132
2133 if (warn_geometry())
2134 return;
2135
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002136 if (LABEL_IS_SUN) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002137 verify_sun();
2138 return;
2139 }
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002140 if (LABEL_IS_SGI) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002141 verify_sgi(1);
2142 return;
2143 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002144
2145 fill_bounds(first, last);
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002146 for (i = 0; i < g_partitions; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002147 struct pte *pe = &ptes[i];
2148
2149 p = pe->part_table;
Rob Landleyb73451d2006-02-24 16:29:00 +00002150 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002151 check_consistency(p, i);
2152 if (get_partition_start(pe) < first[i])
Denis Vlasenkobd852072007-03-19 14:43:38 +00002153 printf("Warning: bad start-of-data in "
2154 "partition %d\n", i + 1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002155 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
2156 last[i]);
2157 total += last[i] + 1 - first[i];
Denis Vlasenkobd852072007-03-19 14:43:38 +00002158 for (j = 0; j < i; j++) {
2159 if ((first[i] >= first[j] && first[i] <= last[j])
2160 || ((last[i] <= last[j] && last[i] >= first[j]))) {
2161 printf("Warning: partition %d overlaps "
2162 "partition %d\n", j + 1, i + 1);
2163 total += first[i] >= first[j] ?
2164 first[i] : first[j];
2165 total -= last[i] <= last[j] ?
2166 last[i] : last[j];
2167 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002168 }
2169 }
2170 }
2171
2172 if (extended_offset) {
2173 struct pte *pex = &ptes[ext_index];
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00002174 ullong e_last = get_start_sect(pex->part_table) +
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002175 get_nr_sects(pex->part_table) - 1;
2176
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002177 for (i = 4; i < g_partitions; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002178 total++;
2179 p = ptes[i].part_table;
2180 if (!p->sys_ind) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002181 if (i != 4 || i + 1 < g_partitions)
Denis Vlasenkobd852072007-03-19 14:43:38 +00002182 printf("Warning: partition %d "
2183 "is empty\n", i + 1);
2184 } else if (first[i] < extended_offset || last[i] > e_last) {
2185 printf("Logical partition %d not entirely in "
2186 "partition %d\n", i + 1, ext_index + 1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002187 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002188 }
2189 }
2190
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002191 if (total > g_heads * g_sectors * g_cylinders)
Denis Vlasenkobd852072007-03-19 14:43:38 +00002192 printf("Total allocated sectors %d greater than the maximum "
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002193 "%d\n", total, g_heads * g_sectors * g_cylinders);
Denis Vlasenkobd852072007-03-19 14:43:38 +00002194 else {
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002195 total = g_heads * g_sectors * g_cylinders - total;
Denis Vlasenkobd852072007-03-19 14:43:38 +00002196 if (total != 0)
2197 printf("%d unallocated sectors\n", total);
2198 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002199}
2200
2201static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002202add_partition(int n, int sys)
2203{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002204 char mesg[256]; /* 48 does not suffice in Japanese */
Mike Frysingerfa6c4842006-05-26 01:48:17 +00002205 int i, num_read = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002206 struct partition *p = ptes[n].part_table;
2207 struct partition *q = ptes[ext_index].part_table;
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00002208 ullong limit, temp;
2209 ullong start, stop = 0;
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002210 ullong first[g_partitions], last[g_partitions];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002211
2212 if (p && p->sys_ind) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00002213 printf(msg_part_already_defined, n + 1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002214 return;
2215 }
2216 fill_bounds(first, last);
2217 if (n < 4) {
2218 start = sector_offset;
Eric Andersen040f4402003-07-30 08:40:37 +00002219 if (display_in_cyl_units || !total_number_of_sectors)
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002220 limit = (ullong) g_heads * g_sectors * g_cylinders - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002221 else
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00002222 limit = total_number_of_sectors - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002223 if (extended_offset) {
2224 first[ext_index] = extended_offset;
2225 last[ext_index] = get_start_sect(q) +
2226 get_nr_sects(q) - 1;
2227 }
2228 } else {
2229 start = extended_offset + sector_offset;
2230 limit = get_start_sect(q) + get_nr_sects(q) - 1;
2231 }
2232 if (display_in_cyl_units)
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002233 for (i = 0; i < g_partitions; i++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002234 first[i] = (cround(first[i]) - 1) * units_per_sector;
2235
Denis Vlasenkobd852072007-03-19 14:43:38 +00002236 snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002237 do {
2238 temp = start;
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002239 for (i = 0; i < g_partitions; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002240 int lastplusoff;
2241
2242 if (start == ptes[i].offset)
2243 start += sector_offset;
Rob Landleyb73451d2006-02-24 16:29:00 +00002244 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002245 if (start >= first[i] && start <= lastplusoff)
2246 start = lastplusoff + 1;
2247 }
2248 if (start > limit)
2249 break;
Mike Frysingerfa6c4842006-05-26 01:48:17 +00002250 if (start >= temp+units_per_sector && num_read) {
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00002251 printf("Sector %lld is already allocated\n", temp);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002252 temp = start;
Mike Frysingerfa6c4842006-05-26 01:48:17 +00002253 num_read = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002254 }
Mike Frysingerfa6c4842006-05-26 01:48:17 +00002255 if (!num_read && start == temp) {
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00002256 ullong saved_start;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002257
2258 saved_start = start;
2259 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
2260 0, mesg);
2261 if (display_in_cyl_units) {
2262 start = (start - 1) * units_per_sector;
2263 if (start < saved_start) start = saved_start;
2264 }
Mike Frysingerfa6c4842006-05-26 01:48:17 +00002265 num_read = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002266 }
Mike Frysingerfa6c4842006-05-26 01:48:17 +00002267 } while (start != temp || !num_read);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002268 if (n > 4) { /* NOT for fifth partition */
2269 struct pte *pe = &ptes[n];
2270
2271 pe->offset = start - sector_offset;
2272 if (pe->offset == extended_offset) { /* must be corrected */
2273 pe->offset++;
2274 if (sector_offset == 1)
2275 start++;
2276 }
2277 }
2278
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002279 for (i = 0; i < g_partitions; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002280 struct pte *pe = &ptes[i];
2281
2282 if (start < pe->offset && limit >= pe->offset)
2283 limit = pe->offset - 1;
2284 if (start < first[i] && limit >= first[i])
2285 limit = first[i] - 1;
2286 }
2287 if (start > limit) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00002288 printf("No free sectors available\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002289 if (n > 4)
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002290 g_partitions--;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002291 return;
2292 }
2293 if (cround(start) == cround(limit)) {
2294 stop = limit;
2295 } else {
2296 snprintf(mesg, sizeof(mesg),
Denis Vlasenkobd852072007-03-19 14:43:38 +00002297 "Last %s or +size or +sizeM or +sizeK",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002298 str_units(SINGULAR));
2299 stop = read_int(cround(start), cround(limit), cround(limit),
2300 cround(start), mesg);
2301 if (display_in_cyl_units) {
2302 stop = stop * units_per_sector - 1;
2303 if (stop >limit)
2304 stop = limit;
2305 }
2306 }
2307
2308 set_partition(n, 0, start, stop, sys);
2309 if (n > 4)
2310 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
2311
Rob Landleyb73451d2006-02-24 16:29:00 +00002312 if (IS_EXTENDED(sys)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002313 struct pte *pe4 = &ptes[4];
2314 struct pte *pen = &ptes[n];
2315
2316 ext_index = n;
2317 pen->ext_pointer = p;
2318 pe4->offset = extended_offset = start;
Rob Landley081e3842006-08-03 20:07:35 +00002319 pe4->sectorbuffer = xzalloc(sector_size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002320 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
2321 pe4->ext_pointer = pe4->part_table + 1;
2322 pe4->changed = 1;
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002323 g_partitions = 5;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002324 }
2325}
2326
2327static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002328add_logical(void)
2329{
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002330 if (g_partitions > 5 || ptes[4].part_table->sys_ind) {
2331 struct pte *pe = &ptes[g_partitions];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002332
Rob Landley081e3842006-08-03 20:07:35 +00002333 pe->sectorbuffer = xzalloc(sector_size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002334 pe->part_table = pt_offset(pe->sectorbuffer, 0);
2335 pe->ext_pointer = pe->part_table + 1;
2336 pe->offset = 0;
2337 pe->changed = 1;
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002338 g_partitions++;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002339 }
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002340 add_partition(g_partitions - 1, LINUX_NATIVE);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002341}
2342
2343static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002344new_partition(void)
2345{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002346 int i, free_primary = 0;
2347
2348 if (warn_geometry())
2349 return;
2350
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002351 if (LABEL_IS_SUN) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002352 add_sun_partition(get_partition(0, g_partitions), LINUX_NATIVE);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002353 return;
2354 }
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002355 if (LABEL_IS_SGI) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002356 sgi_add_partition(get_partition(0, g_partitions), LINUX_NATIVE);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002357 return;
2358 }
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002359 if (LABEL_IS_AIX) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00002360 printf("Sorry - this fdisk cannot handle AIX disk labels.\n"
2361"If you want to add DOS-type partitions, create a new empty DOS partition\n"
2362"table first (use 'o'). This will destroy the present disk contents.\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002363 return;
2364 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002365
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002366 for (i = 0; i < 4; i++)
2367 free_primary += !ptes[i].part_table->sys_ind;
Eric Andersenc48d49a2003-07-03 10:02:32 +00002368
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002369 if (!free_primary && g_partitions >= MAXIMUM_PARTS) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00002370 printf("The maximum number of partitions has been created\n");
Eric Andersen84bdea82004-05-19 10:49:17 +00002371 return;
Rob Landleyb73451d2006-02-24 16:29:00 +00002372 }
Eric Andersenc48d49a2003-07-03 10:02:32 +00002373
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002374 if (!free_primary) {
2375 if (extended_offset)
2376 add_logical();
2377 else
Denis Vlasenkobd852072007-03-19 14:43:38 +00002378 printf("You must delete some partition and add "
2379 "an extended partition first\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002380 } else {
Denis Vlasenkodfce08f2007-03-19 14:45:10 +00002381 char c, line[80];
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00002382 snprintf(line, sizeof(line),
2383 "Command action\n"
2384 " %s\n"
2385 " p primary partition (1-4)\n",
2386 (extended_offset ?
2387 "l logical (5 or over)" : "e extended"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002388 while (1) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002389 c = read_nonempty(line);
2390 if (c == 'p' || c == 'P') {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002391 i = get_nonexisting_partition(0, 4);
2392 if (i >= 0)
2393 add_partition(i, LINUX_NATIVE);
2394 return;
2395 }
Denis Vlasenkobd852072007-03-19 14:43:38 +00002396 if (c == 'l' && extended_offset) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002397 add_logical();
2398 return;
2399 }
Denis Vlasenkobd852072007-03-19 14:43:38 +00002400 if (c == 'e' && !extended_offset) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002401 i = get_nonexisting_partition(0, 4);
2402 if (i >= 0)
2403 add_partition(i, EXTENDED);
2404 return;
2405 }
Denis Vlasenkobd852072007-03-19 14:43:38 +00002406 printf("Invalid partition number "
2407 "for type '%c'\n", c);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002408 }
2409 }
2410}
2411
2412static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002413write_table(void)
2414{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002415 int i;
2416
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002417 if (LABEL_IS_DOS) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002418 for (i = 0; i < 3; i++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002419 if (ptes[i].changed)
2420 ptes[3].changed = 1;
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002421 for (i = 3; i < g_partitions; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002422 struct pte *pe = &ptes[i];
2423
2424 if (pe->changed) {
2425 write_part_table_flag(pe->sectorbuffer);
2426 write_sector(pe->offset, pe->sectorbuffer);
2427 }
2428 }
2429 }
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002430 else if (LABEL_IS_SGI) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002431 /* no test on change? the printf below might be mistaken */
2432 sgi_write_table();
2433 }
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002434 else if (LABEL_IS_SUN) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002435 int needw = 0;
2436
Rob Landleyb73451d2006-02-24 16:29:00 +00002437 for (i = 0; i < 8; i++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002438 if (ptes[i].changed)
2439 needw = 1;
2440 if (needw)
2441 sun_write_table();
2442 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002443
Denis Vlasenkobd852072007-03-19 14:43:38 +00002444 printf("The partition table has been altered!\n\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002445 reread_partition_table(1);
2446}
2447
Rob Landleyb73451d2006-02-24 16:29:00 +00002448static void
2449reread_partition_table(int leave)
2450{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002451 int i;
2452
Denis Vlasenkobd852072007-03-19 14:43:38 +00002453 printf("Calling ioctl() to re-read partition table\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002454 sync();
Denis Vlasenkobd852072007-03-19 14:43:38 +00002455 /* sleep(2); Huh? */
Denis Vlasenko4437d192008-04-17 00:12:10 +00002456 i = ioctl_or_perror(dev_fd, BLKRRPART, NULL,
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00002457 "WARNING: rereading partition table "
Denis Vlasenko28703012006-12-19 20:32:02 +00002458 "failed, kernel still uses old table");
Denis Vlasenko28703012006-12-19 20:32:02 +00002459#if 0
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002460 if (dos_changed)
Rob Landleyb73451d2006-02-24 16:29:00 +00002461 printf(
Denis Vlasenkobd852072007-03-19 14:43:38 +00002462 "\nWARNING: If you have created or modified any DOS 6.x\n"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002463 "partitions, please see the fdisk manual page for additional\n"
Denis Vlasenkobd852072007-03-19 14:43:38 +00002464 "information\n");
Denis Vlasenko28703012006-12-19 20:32:02 +00002465#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002466
2467 if (leave) {
Denis Vlasenko28703012006-12-19 20:32:02 +00002468 if (ENABLE_FEATURE_CLEAN_UP)
Denis Vlasenko4437d192008-04-17 00:12:10 +00002469 close(dev_fd);
Denis Vlasenko28703012006-12-19 20:32:02 +00002470 exit(i != 0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002471 }
2472}
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +00002473#endif /* FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002474
Denis Vlasenko834410a2006-11-29 12:00:28 +00002475#if ENABLE_FEATURE_FDISK_ADVANCED
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002476#define MAX_PER_LINE 16
2477static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002478print_buffer(char *pbuffer)
2479{
2480 int i,l;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002481
2482 for (i = 0, l = 0; i < sector_size; i++, l++) {
2483 if (l == 0)
2484 printf("0x%03X:", i);
2485 printf(" %02X", (unsigned char) pbuffer[i]);
2486 if (l == MAX_PER_LINE - 1) {
Denis Vlasenko4daad902007-09-27 10:20:47 +00002487 bb_putchar('\n');
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002488 l = -1;
2489 }
2490 }
2491 if (l > 0)
Denis Vlasenko4daad902007-09-27 10:20:47 +00002492 bb_putchar('\n');
2493 bb_putchar('\n');
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002494}
2495
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002496static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002497print_raw(void)
2498{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002499 int i;
2500
Denis Vlasenkobd852072007-03-19 14:43:38 +00002501 printf("Device: %s\n", disk_device);
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002502 if (LABEL_IS_SGI || LABEL_IS_SUN)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002503 print_buffer(MBRbuffer);
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002504 else {
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002505 for (i = 3; i < g_partitions; i++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002506 print_buffer(ptes[i].sectorbuffer);
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002507 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002508}
2509
2510static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002511move_begin(int i)
2512{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002513 struct pte *pe = &ptes[i];
2514 struct partition *p = pe->part_table;
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00002515 ullong new, first;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002516
2517 if (warn_geometry())
2518 return;
Rob Landleyb73451d2006-02-24 16:29:00 +00002519 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED(p->sys_ind)) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00002520 printf("Partition %d has no data area\n", i + 1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002521 return;
2522 }
2523 first = get_partition_start(pe);
2524 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
Denis Vlasenkobd852072007-03-19 14:43:38 +00002525 "New beginning of data") - pe->offset;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002526
2527 if (new != get_nr_sects(p)) {
2528 first = get_nr_sects(p) + get_start_sect(p) - new;
2529 set_nr_sects(p, first);
2530 set_start_sect(p, new);
2531 pe->changed = 1;
2532 }
2533}
2534
2535static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002536xselect(void)
2537{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002538 char c;
2539
Rob Landleyb73451d2006-02-24 16:29:00 +00002540 while (1) {
Denis Vlasenko4daad902007-09-27 10:20:47 +00002541 bb_putchar('\n');
Denis Vlasenkobd852072007-03-19 14:43:38 +00002542 c = tolower(read_nonempty("Expert command (m for help): "));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002543 switch (c) {
2544 case 'a':
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002545 if (LABEL_IS_SUN)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002546 sun_set_alt_cyl();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002547 break;
2548 case 'b':
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002549 if (LABEL_IS_DOS)
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002550 move_begin(get_partition(0, g_partitions));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002551 break;
2552 case 'c':
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002553 user_cylinders = g_cylinders =
2554 read_int(1, g_cylinders, 1048576, 0,
Denis Vlasenkobd852072007-03-19 14:43:38 +00002555 "Number of cylinders");
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002556 if (LABEL_IS_SUN)
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002557 sun_set_ncyl(g_cylinders);
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002558 if (LABEL_IS_DOS)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002559 warn_cylinders();
2560 break;
2561 case 'd':
2562 print_raw();
2563 break;
2564 case 'e':
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002565 if (LABEL_IS_SGI)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002566 sgi_set_xcyl();
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002567 else if (LABEL_IS_SUN)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002568 sun_set_xcyl();
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002569 else if (LABEL_IS_DOS)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002570 x_list_table(1);
2571 break;
2572 case 'f':
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002573 if (LABEL_IS_DOS)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002574 fix_partition_table_order();
2575 break;
2576 case 'g':
Denis Vlasenko834410a2006-11-29 12:00:28 +00002577#if ENABLE_FEATURE_SGI_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002578 create_sgilabel();
2579#endif
2580 break;
2581 case 'h':
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002582 user_heads = g_heads = read_int(1, g_heads, 256, 0,
Denis Vlasenkobd852072007-03-19 14:43:38 +00002583 "Number of heads");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002584 update_units();
2585 break;
2586 case 'i':
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002587 if (LABEL_IS_SUN)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002588 sun_set_ilfact();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002589 break;
2590 case 'o':
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002591 if (LABEL_IS_SUN)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002592 sun_set_rspeed();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002593 break;
2594 case 'p':
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002595 if (LABEL_IS_SUN)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002596 list_table(1);
2597 else
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002598 x_list_table(0);
2599 break;
2600 case 'q':
Denis Vlasenko4437d192008-04-17 00:12:10 +00002601 if (ENABLE_FEATURE_CLEAN_UP)
2602 close(dev_fd);
Denis Vlasenko4daad902007-09-27 10:20:47 +00002603 bb_putchar('\n');
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002604 exit(0);
2605 case 'r':
2606 return;
2607 case 's':
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002608 user_sectors = g_sectors = read_int(1, g_sectors, 63, 0,
Denis Vlasenkobd852072007-03-19 14:43:38 +00002609 "Number of sectors");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002610 if (dos_compatible_flag) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002611 sector_offset = g_sectors;
Denis Vlasenkobd852072007-03-19 14:43:38 +00002612 printf("Warning: setting sector offset for DOS "
2613 "compatiblity\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002614 }
2615 update_units();
2616 break;
2617 case 'v':
2618 verify();
2619 break;
2620 case 'w':
2621 write_table(); /* does not return */
2622 break;
2623 case 'y':
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002624 if (LABEL_IS_SUN)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002625 sun_set_pcylcount();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002626 break;
2627 default:
2628 xmenu();
2629 }
2630 }
2631}
2632#endif /* ADVANCED mode */
2633
2634static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002635is_ide_cdrom_or_tape(const char *device)
2636{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002637 FILE *procf;
2638 char buf[100];
2639 struct stat statbuf;
2640 int is_ide = 0;
2641
2642 /* No device was given explicitly, and we are trying some
2643 likely things. But opening /dev/hdc may produce errors like
2644 "hdc: tray open or drive not ready"
2645 if it happens to be a CD-ROM drive. It even happens that
2646 the process hangs on the attempt to read a music CD.
2647 So try to be careful. This only works since 2.1.73. */
2648
2649 if (strncmp("/dev/hd", device, 7))
2650 return 0;
2651
2652 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
2653 procf = fopen(buf, "r");
2654 if (procf != NULL && fgets(buf, sizeof(buf), procf))
2655 is_ide = (!strncmp(buf, "cdrom", 5) ||
2656 !strncmp(buf, "tape", 4));
2657 else
2658 /* Now when this proc file does not exist, skip the
2659 device when it is read-only. */
2660 if (stat(device, &statbuf) == 0)
2661 is_ide = ((statbuf.st_mode & 0222) == 0);
2662
2663 if (procf)
2664 fclose(procf);
2665 return is_ide;
2666}
2667
Rob Landley5527b912006-02-25 03:46:10 +00002668
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002669static void
Denis Vlasenko4437d192008-04-17 00:12:10 +00002670open_list_and_close(const char *device, int user_specified)
Rob Landleyb73451d2006-02-24 16:29:00 +00002671{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002672 int gb;
2673
2674 disk_device = device;
2675 if (setjmp(listingbuf))
2676 return;
2677 if (!user_specified)
2678 if (is_ide_cdrom_or_tape(device))
2679 return;
Denis Vlasenko4437d192008-04-17 00:12:10 +00002680
2681 /* Open disk_device, save file descriptor to dev_fd */
2682 errno = 0;
2683 gb = get_boot(TRY_ONLY);
2684 if (gb > 0) { /* I/O error */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002685 /* Ignore other errors, since we try IDE
2686 and SCSI hard disks which may not be
2687 installed on the system. */
Denis Vlasenko4437d192008-04-17 00:12:10 +00002688 if (user_specified || errno == EACCES)
2689 bb_perror_msg("can't open '%s'", device);
2690 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002691 }
Denis Vlasenko4437d192008-04-17 00:12:10 +00002692
2693 if (gb < 0) { /* no DOS signature */
2694 list_disk_geometry();
2695 if (LABEL_IS_AIX)
2696 goto ret;
2697#if ENABLE_FEATURE_OSF_LABEL
2698 if (bsd_trydev(device) < 0)
2699#endif
2700 printf("Disk %s doesn't contain a valid "
2701 "partition table\n", device);
2702 } else {
2703 list_table(0);
2704#if ENABLE_FEATURE_FDISK_WRITABLE
2705 if (!LABEL_IS_SUN && g_partitions > 4) {
2706 delete_partition(ext_index);
2707 }
2708#endif
2709 }
2710 ret:
2711 close(dev_fd);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002712}
2713
2714/* for fdisk -l: try all things in /proc/partitions
2715 that look like a partition name (do not end in a digit) */
2716static void
Denis Vlasenko4437d192008-04-17 00:12:10 +00002717list_devs_in_proc_partititons(void)
Rob Landleyb73451d2006-02-24 16:29:00 +00002718{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002719 FILE *procpt;
2720 char line[100], ptname[100], devname[120], *s;
2721 int ma, mi, sz;
2722
Denis Vlasenkoddec5af2006-10-26 23:25:17 +00002723 procpt = fopen_or_warn("/proc/partitions", "r");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002724
2725 while (fgets(line, sizeof(line), procpt)) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002726 if (sscanf(line, " %d %d %d %[^\n ]",
2727 &ma, &mi, &sz, ptname) != 4)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002728 continue;
Denis Vlasenkocdf62772008-03-17 08:42:43 +00002729 for (s = ptname; *s; s++)
2730 continue;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002731 if (isdigit(s[-1]))
2732 continue;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00002733 sprintf(devname, "/dev/%s", ptname);
Denis Vlasenko4437d192008-04-17 00:12:10 +00002734 open_list_and_close(devname, 0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002735 }
Denis Vlasenko834410a2006-11-29 12:00:28 +00002736#if ENABLE_FEATURE_CLEAN_UP
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002737 fclose(procpt);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00002738#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002739}
2740
Denis Vlasenko834410a2006-11-29 12:00:28 +00002741#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002742static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002743unknown_command(int c)
2744{
Denis Vlasenkobd852072007-03-19 14:43:38 +00002745 printf("%c: unknown command\n", c);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002746}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00002747#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002748
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00002749int fdisk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Rob Landleyb73451d2006-02-24 16:29:00 +00002750int fdisk_main(int argc, char **argv)
2751{
Denis Vlasenko834410a2006-11-29 12:00:28 +00002752 unsigned opt;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002753 /*
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002754 * fdisk -v
2755 * fdisk -l [-b sectorsize] [-u] device ...
2756 * fdisk -s [partition] ...
2757 * fdisk [-b sectorsize] [-u] device
2758 *
2759 * Options -C, -H, -S set the geometry.
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002760 */
Denis Vlasenko834410a2006-11-29 12:00:28 +00002761 enum {
2762 OPT_b = 1 << 0,
2763 OPT_C = 1 << 1,
2764 OPT_H = 1 << 2,
2765 OPT_l = 1 << 3,
2766 OPT_S = 1 << 4,
2767 OPT_u = 1 << 5,
2768 OPT_s = (1 << 6) * ENABLE_FEATURE_FDISK_BLKSIZE,
2769 };
Denis Vlasenko8e1a0cc2007-03-18 14:42:45 +00002770
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002771 INIT_G();
Denis Vlasenko8e1a0cc2007-03-18 14:42:45 +00002772
Denis Vlasenko4437d192008-04-17 00:12:10 +00002773 close(dev_fd); /* just in case */
2774
Denis Vlasenko04e11c92008-02-10 19:44:20 +00002775 opt_complementary = "b+:C+:H+:S+"; /* numeric params */
Denis Vlasenkofe7cd642007-08-18 15:32:12 +00002776 opt = getopt32(argv, "b:C:H:lS:u" USE_FEATURE_FDISK_BLKSIZE("s"),
Denis Vlasenko04e11c92008-02-10 19:44:20 +00002777 &sector_size, &user_cylinders, &user_heads, &user_sectors);
Denis Vlasenko834410a2006-11-29 12:00:28 +00002778 argc -= optind;
2779 argv += optind;
2780 if (opt & OPT_b) { // -b
2781 /* Ugly: this sector size is really per device,
2782 so cannot be combined with multiple disks,
2783 and the same goes for the C/H/S options.
2784 */
Denis Vlasenko04e11c92008-02-10 19:44:20 +00002785 if (sector_size != 512 && sector_size != 1024
2786 && sector_size != 2048)
Manuel Novoa III cad53642003-03-19 09:13:01 +00002787 bb_show_usage();
Denis Vlasenko834410a2006-11-29 12:00:28 +00002788 sector_offset = 2;
2789 user_set_sector_size = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002790 }
Denis Vlasenko04e11c92008-02-10 19:44:20 +00002791 if (user_heads <= 0 || user_heads >= 256)
2792 user_heads = 0;
2793 if (user_sectors <= 0 || user_sectors >= 64)
2794 user_sectors = 0;
2795 if (opt & OPT_u)
2796 display_in_cyl_units = 0; // -u
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002797
Denis Vlasenko834410a2006-11-29 12:00:28 +00002798#if ENABLE_FEATURE_FDISK_WRITABLE
2799 if (opt & OPT_l) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002800 nowarn = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00002801#endif
Denis Vlasenkocdf62772008-03-17 08:42:43 +00002802 if (*argv) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002803 listing = 1;
Denis Vlasenkocdf62772008-03-17 08:42:43 +00002804 do {
Denis Vlasenko4437d192008-04-17 00:12:10 +00002805 open_list_and_close(*argv, 1);
Denis Vlasenkocdf62772008-03-17 08:42:43 +00002806 } while (*++argv);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002807 } else {
Denis Vlasenkocdf62772008-03-17 08:42:43 +00002808 /* we don't have device names, */
2809 /* use /proc/partitions instead */
Denis Vlasenko4437d192008-04-17 00:12:10 +00002810 list_devs_in_proc_partititons();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002811 }
2812 return 0;
Denis Vlasenko834410a2006-11-29 12:00:28 +00002813#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002814 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00002815#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002816
Denis Vlasenko834410a2006-11-29 12:00:28 +00002817#if ENABLE_FEATURE_FDISK_BLKSIZE
2818 if (opt & OPT_s) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00002819 int j;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002820
2821 nowarn = 1;
Denis Vlasenko834410a2006-11-29 12:00:28 +00002822 if (argc <= 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +00002823 bb_show_usage();
Denis Vlasenko834410a2006-11-29 12:00:28 +00002824 for (j = 0; j < argc; j++) {
Denis Vlasenkocdf62772008-03-17 08:42:43 +00002825 unsigned long long size;
2826 fd = xopen(argv[j], O_RDONLY);
Denis Vlasenko4437d192008-04-17 00:12:10 +00002827 size = bb_BLKGETSIZE_sectors(fd) / 2;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002828 close(fd);
Denis Vlasenko834410a2006-11-29 12:00:28 +00002829 if (argc == 1)
Denis Vlasenkocdf62772008-03-17 08:42:43 +00002830 printf("%lld\n", size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002831 else
Denis Vlasenkocdf62772008-03-17 08:42:43 +00002832 printf("%s: %lld\n", argv[j], size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002833 }
2834 return 0;
2835 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00002836#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002837
Denis Vlasenko834410a2006-11-29 12:00:28 +00002838#if ENABLE_FEATURE_FDISK_WRITABLE
2839 if (argc != 1)
Manuel Novoa III cad53642003-03-19 09:13:01 +00002840 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002841
Denis Vlasenko834410a2006-11-29 12:00:28 +00002842 disk_device = argv[0];
Denis Vlasenko4437d192008-04-17 00:12:10 +00002843 get_boot(OPEN_MAIN);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002844
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002845 if (LABEL_IS_OSF) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002846 /* OSF label, and no DOS label */
Denis Vlasenkobd852072007-03-19 14:43:38 +00002847 printf("Detected an OSF/1 disklabel on %s, entering "
2848 "disklabel mode\n", disk_device);
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +00002849 bsd_select();
Rob Landley5527b912006-02-25 03:46:10 +00002850 /*Why do we do this? It seems to be counter-intuitive*/
Denis Vlasenko4437d192008-04-17 00:12:10 +00002851 current_label_type = LABEL_DOS;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002852 /* If we return we may want to make an empty DOS label? */
2853 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002854
2855 while (1) {
Denis Vlasenko3bba5452006-12-30 17:57:03 +00002856 int c;
Denis Vlasenko4daad902007-09-27 10:20:47 +00002857 bb_putchar('\n');
Denis Vlasenkobd852072007-03-19 14:43:38 +00002858 c = tolower(read_nonempty("Command (m for help): "));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002859 switch (c) {
2860 case 'a':
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002861 if (LABEL_IS_DOS)
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002862 toggle_active(get_partition(1, g_partitions));
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002863 else if (LABEL_IS_SUN)
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002864 toggle_sunflags(get_partition(1, g_partitions),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002865 0x01);
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002866 else if (LABEL_IS_SGI)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002867 sgi_set_bootpartition(
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002868 get_partition(1, g_partitions));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002869 else
2870 unknown_command(c);
2871 break;
2872 case 'b':
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002873 if (LABEL_IS_SGI) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00002874 printf("\nThe current boot file is: %s\n",
Rob Landleyb73451d2006-02-24 16:29:00 +00002875 sgi_get_bootfile());
Denis Vlasenkobd852072007-03-19 14:43:38 +00002876 if (read_maybe_empty("Please enter the name of the "
2877 "new boot file: ") == '\n')
2878 printf("Boot file unchanged\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002879 else
2880 sgi_set_bootfile(line_ptr);
Denis Vlasenko834410a2006-11-29 12:00:28 +00002881 }
2882#if ENABLE_FEATURE_OSF_LABEL
2883 else
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +00002884 bsd_select();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002885#endif
2886 break;
2887 case 'c':
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002888 if (LABEL_IS_DOS)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002889 toggle_dos_compatibility_flag();
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002890 else if (LABEL_IS_SUN)
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002891 toggle_sunflags(get_partition(1, g_partitions),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002892 0x10);
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002893 else if (LABEL_IS_SGI)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002894 sgi_set_swappartition(
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002895 get_partition(1, g_partitions));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002896 else
2897 unknown_command(c);
2898 break;
2899 case 'd':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00002900 {
Eric Andersen040f4402003-07-30 08:40:37 +00002901 int j;
Eric Andersen040f4402003-07-30 08:40:37 +00002902 /* If sgi_label then don't use get_existing_partition,
2903 let the user select a partition, since
2904 get_existing_partition() only works for Linux-like
2905 partition tables */
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002906 if (!LABEL_IS_SGI) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002907 j = get_existing_partition(1, g_partitions);
Eric Andersen040f4402003-07-30 08:40:37 +00002908 } else {
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002909 j = get_partition(1, g_partitions);
Eric Andersen040f4402003-07-30 08:40:37 +00002910 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00002911 if (j >= 0)
2912 delete_partition(j);
2913 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002914 break;
2915 case 'i':
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002916 if (LABEL_IS_SGI)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002917 create_sgiinfo();
2918 else
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002919 unknown_command(c);
2920 case 'l':
2921 list_types(get_sys_types());
2922 break;
2923 case 'm':
2924 menu();
2925 break;
2926 case 'n':
2927 new_partition();
2928 break;
2929 case 'o':
2930 create_doslabel();
2931 break;
2932 case 'p':
2933 list_table(0);
2934 break;
2935 case 'q':
Denis Vlasenko4437d192008-04-17 00:12:10 +00002936 close(dev_fd);
Denis Vlasenko4daad902007-09-27 10:20:47 +00002937 bb_putchar('\n');
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002938 return 0;
2939 case 's':
Denis Vlasenko834410a2006-11-29 12:00:28 +00002940#if ENABLE_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002941 create_sunlabel();
2942#endif
2943 break;
2944 case 't':
2945 change_sysid();
2946 break;
2947 case 'u':
2948 change_units();
2949 break;
2950 case 'v':
2951 verify();
2952 break;
2953 case 'w':
2954 write_table(); /* does not return */
2955 break;
Denis Vlasenko834410a2006-11-29 12:00:28 +00002956#if ENABLE_FEATURE_FDISK_ADVANCED
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002957 case 'x':
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002958 if (LABEL_IS_SGI) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00002959 printf("\n\tSorry, no experts menu for SGI "
2960 "partition tables available\n\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002961 } else
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002962 xselect();
2963 break;
2964#endif
2965 default:
2966 unknown_command(c);
2967 menu();
2968 }
2969 }
2970 return 0;
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +00002971#endif /* FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002972}