blob: 7f046edfb668b5df91ec14c0d721063c11a396f4 [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
Denis Vlasenko6eaf0a92008-06-29 05:10:47 +000023#define DEFAULT_SECTOR_SIZE 512
24#define DEFAULT_SECTOR_SIZE_STR "512"
25#define MAX_SECTOR_SIZE 2048
26#define SECTOR_SIZE 512 /* still used in osf/sgi/sun code */
27#define MAXIMUM_PARTS 60
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000028
Denis Vlasenko6eaf0a92008-06-29 05:10:47 +000029#define ACTIVE_FLAG 0x80
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000030
Denis Vlasenko6eaf0a92008-06-29 05:10:47 +000031#define EXTENDED 0x05
32#define WIN98_EXTENDED 0x0f
33#define LINUX_PARTITION 0x81
34#define LINUX_SWAP 0x82
35#define LINUX_NATIVE 0x83
36#define LINUX_EXTENDED 0x85
37#define LINUX_LVM 0x8e
38#define LINUX_RAID 0xfd
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000039
Denis Vlasenkoc033d512008-04-17 01:52:28 +000040
41enum {
42 OPT_b = 1 << 0,
43 OPT_C = 1 << 1,
44 OPT_H = 1 << 2,
45 OPT_l = 1 << 3,
46 OPT_S = 1 << 4,
47 OPT_u = 1 << 5,
48 OPT_s = (1 << 6) * ENABLE_FEATURE_FDISK_BLKSIZE,
49};
50
51
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +000052/* Used for sector numbers. Today's disk sizes make it necessary */
53typedef unsigned long long ullong;
54
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000055struct hd_geometry {
Rob Landleyb73451d2006-02-24 16:29:00 +000056 unsigned char heads;
57 unsigned char sectors;
58 unsigned short cylinders;
59 unsigned long start;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000060};
61
Denis Vlasenko98ae2162006-10-12 19:30:44 +000062#define HDIO_GETGEO 0x0301 /* get device geometry */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000063
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000064static const char msg_building_new_label[] ALIGN1 =
Denis Vlasenkobd852072007-03-19 14:43:38 +000065"Building a new %s. Changes will remain in memory only,\n"
66"until you decide to write them. After that the previous content\n"
67"won't be recoverable.\n\n";
68
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000069static const char msg_part_already_defined[] ALIGN1 =
Denis Vlasenkobd852072007-03-19 14:43:38 +000070"Partition %d is already defined, delete it before re-adding\n";
71
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000072
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000073struct partition {
74 unsigned char boot_ind; /* 0x80 - active */
75 unsigned char head; /* starting head */
76 unsigned char sector; /* starting sector */
77 unsigned char cyl; /* starting cylinder */
78 unsigned char sys_ind; /* What partition type */
79 unsigned char end_head; /* end head */
80 unsigned char end_sector; /* end sector */
81 unsigned char end_cyl; /* end cylinder */
82 unsigned char start4[4]; /* starting sector counting from 0 */
83 unsigned char size4[4]; /* nr of sectors in partition */
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +000084} ATTRIBUTE_PACKED;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000085
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000086static const char unable_to_open[] ALIGN1 = "cannot open %s";
87static const char unable_to_read[] ALIGN1 = "cannot read from %s";
88static const char unable_to_seek[] ALIGN1 = "cannot seek on %s";
89static const char unable_to_write[] ALIGN1 = "cannot write to %s";
90static const char ioctl_error[] ALIGN1 = "BLKGETSIZE ioctl failed on %s";
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +000091static void fdisk_fatal(const char *why) ATTRIBUTE_NORETURN;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +000092
Denis Vlasenko98ae2162006-10-12 19:30:44 +000093enum label_type {
Denis Vlasenko4437d192008-04-17 00:12:10 +000094 LABEL_DOS, LABEL_SUN, LABEL_SGI, LABEL_AIX, LABEL_OSF
Rob Landley5527b912006-02-25 03:46:10 +000095};
Denis Vlasenkodfce08f2007-03-19 14:45:10 +000096
Denis Vlasenko4437d192008-04-17 00:12:10 +000097#define LABEL_IS_DOS (LABEL_DOS == current_label_type)
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +000098
Denis Vlasenko834410a2006-11-29 12:00:28 +000099#if ENABLE_FEATURE_SUN_LABEL
Denis Vlasenko4437d192008-04-17 00:12:10 +0000100#define LABEL_IS_SUN (LABEL_SUN == current_label_type)
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000101#define STATIC_SUN static
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000102#else
103#define LABEL_IS_SUN 0
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000104#define STATIC_SUN extern
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000105#endif
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000106
Denis Vlasenko834410a2006-11-29 12:00:28 +0000107#if ENABLE_FEATURE_SGI_LABEL
Denis Vlasenko4437d192008-04-17 00:12:10 +0000108#define LABEL_IS_SGI (LABEL_SGI == current_label_type)
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000109#define STATIC_SGI static
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000110#else
111#define LABEL_IS_SGI 0
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000112#define STATIC_SGI extern
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000113#endif
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000114
Denis Vlasenko834410a2006-11-29 12:00:28 +0000115#if ENABLE_FEATURE_AIX_LABEL
Denis Vlasenko4437d192008-04-17 00:12:10 +0000116#define LABEL_IS_AIX (LABEL_AIX == current_label_type)
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000117#define STATIC_AIX static
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000118#else
119#define LABEL_IS_AIX 0
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000120#define STATIC_AIX extern
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000121#endif
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000122
Denis Vlasenko834410a2006-11-29 12:00:28 +0000123#if ENABLE_FEATURE_OSF_LABEL
Denis Vlasenko4437d192008-04-17 00:12:10 +0000124#define LABEL_IS_OSF (LABEL_OSF == current_label_type)
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000125#define STATIC_OSF static
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000126#else
127#define LABEL_IS_OSF 0
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000128#define STATIC_OSF extern
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000129#endif
Rob Landley5527b912006-02-25 03:46:10 +0000130
Denis Vlasenko4437d192008-04-17 00:12:10 +0000131enum action { OPEN_MAIN, TRY_ONLY, CREATE_EMPTY_DOS, CREATE_EMPTY_SUN };
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000132
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000133static void update_units(void);
Denis Vlasenko834410a2006-11-29 12:00:28 +0000134#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000135static void change_units(void);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000136static void reread_partition_table(int leave);
137static void delete_partition(int i);
Rob Landleyb73451d2006-02-24 16:29:00 +0000138static int get_partition(int warn, int max);
Denis Vlasenkobd852072007-03-19 14:43:38 +0000139static void list_types(const char *const *sys);
Denis Vlasenko06c0a712007-01-29 22:51:44 +0000140static unsigned read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, const char *mesg);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000141#endif
142static const char *partition_type(unsigned char type);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000143static void get_geometry(void);
Denis Vlasenko85c24712008-03-17 09:04:04 +0000144#if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000145static int get_boot(enum action what);
Denis Vlasenko85c24712008-03-17 09:04:04 +0000146#else
147static int get_boot(void);
148#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000149
150#define PLURAL 0
151#define SINGULAR 1
152
Denis Vlasenko28703012006-12-19 20:32:02 +0000153static unsigned get_start_sect(const struct partition *p);
154static unsigned get_nr_sects(const struct partition *p);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000155
156/*
157 * per partition table entry data
158 *
159 * The four primary partitions have the same sectorbuffer (MBRbuffer)
160 * and have NULL ext_pointer.
161 * Each logical partition table entry has two pointers, one for the
162 * partition and one link to the next one.
163 */
Denis Vlasenko8e1a0cc2007-03-18 14:42:45 +0000164struct pte {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000165 struct partition *part_table; /* points into sectorbuffer */
166 struct partition *ext_pointer; /* points into sectorbuffer */
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +0000167 ullong offset; /* disk sector number */
Denis Vlasenkodfce08f2007-03-19 14:45:10 +0000168 char *sectorbuffer; /* disk sector contents */
Denis Vlasenko834410a2006-11-29 12:00:28 +0000169#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000170 char changed; /* boolean */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000171#endif
Denis Vlasenko8e1a0cc2007-03-18 14:42:45 +0000172};
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000173
Denis Vlasenkodfce08f2007-03-19 14:45:10 +0000174/* DOS partition types */
175
176static const char *const i386_sys_types[] = {
177 "\x00" "Empty",
178 "\x01" "FAT12",
179 "\x04" "FAT16 <32M",
180 "\x05" "Extended", /* DOS 3.3+ extended partition */
181 "\x06" "FAT16", /* DOS 16-bit >=32M */
182 "\x07" "HPFS/NTFS", /* OS/2 IFS, eg, HPFS or NTFS or QNX */
183 "\x0a" "OS/2 Boot Manager",/* OS/2 Boot Manager */
184 "\x0b" "Win95 FAT32",
185 "\x0c" "Win95 FAT32 (LBA)",/* LBA really is 'Extended Int 13h' */
186 "\x0e" "Win95 FAT16 (LBA)",
187 "\x0f" "Win95 Ext'd (LBA)",
188 "\x11" "Hidden FAT12",
189 "\x12" "Compaq diagnostics",
190 "\x14" "Hidden FAT16 <32M",
191 "\x16" "Hidden FAT16",
192 "\x17" "Hidden HPFS/NTFS",
193 "\x1b" "Hidden Win95 FAT32",
194 "\x1c" "Hidden W95 FAT32 (LBA)",
195 "\x1e" "Hidden W95 FAT16 (LBA)",
196 "\x3c" "Part.Magic recovery",
197 "\x41" "PPC PReP Boot",
198 "\x42" "SFS",
199 "\x63" "GNU HURD or SysV", /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
200 "\x80" "Old Minix", /* Minix 1.4a and earlier */
201 "\x81" "Minix / old Linux",/* Minix 1.4b and later */
202 "\x82" "Linux swap", /* also Solaris */
203 "\x83" "Linux",
204 "\x84" "OS/2 hidden C: drive",
205 "\x85" "Linux extended",
206 "\x86" "NTFS volume set",
207 "\x87" "NTFS volume set",
208 "\x8e" "Linux LVM",
209 "\x9f" "BSD/OS", /* BSDI */
210 "\xa0" "Thinkpad hibernation",
211 "\xa5" "FreeBSD", /* various BSD flavours */
212 "\xa6" "OpenBSD",
213 "\xa8" "Darwin UFS",
214 "\xa9" "NetBSD",
215 "\xab" "Darwin boot",
216 "\xb7" "BSDI fs",
217 "\xb8" "BSDI swap",
218 "\xbe" "Solaris boot",
219 "\xeb" "BeOS fs",
220 "\xee" "EFI GPT", /* Intel EFI GUID Partition Table */
221 "\xef" "EFI (FAT-12/16/32)", /* Intel EFI System Partition */
222 "\xf0" "Linux/PA-RISC boot", /* Linux/PA-RISC boot loader */
223 "\xf2" "DOS secondary", /* DOS 3.3+ secondary */
224 "\xfd" "Linux raid autodetect", /* New (2.2.x) raid partition with
225 autodetect using persistent
226 superblock */
227#if 0 /* ENABLE_WEIRD_PARTITION_TYPES */
228 "\x02" "XENIX root",
229 "\x03" "XENIX usr",
230 "\x08" "AIX", /* AIX boot (AIX -- PS/2 port) or SplitDrive */
231 "\x09" "AIX bootable", /* AIX data or Coherent */
232 "\x10" "OPUS",
233 "\x18" "AST SmartSleep",
234 "\x24" "NEC DOS",
235 "\x39" "Plan 9",
236 "\x40" "Venix 80286",
237 "\x4d" "QNX4.x",
238 "\x4e" "QNX4.x 2nd part",
239 "\x4f" "QNX4.x 3rd part",
240 "\x50" "OnTrack DM",
241 "\x51" "OnTrack DM6 Aux1", /* (or Novell) */
242 "\x52" "CP/M", /* CP/M or Microport SysV/AT */
243 "\x53" "OnTrack DM6 Aux3",
244 "\x54" "OnTrackDM6",
245 "\x55" "EZ-Drive",
246 "\x56" "Golden Bow",
247 "\x5c" "Priam Edisk",
248 "\x61" "SpeedStor",
249 "\x64" "Novell Netware 286",
250 "\x65" "Novell Netware 386",
251 "\x70" "DiskSecure Multi-Boot",
252 "\x75" "PC/IX",
253 "\x93" "Amoeba",
254 "\x94" "Amoeba BBT", /* (bad block table) */
255 "\xa7" "NeXTSTEP",
256 "\xbb" "Boot Wizard hidden",
257 "\xc1" "DRDOS/sec (FAT-12)",
258 "\xc4" "DRDOS/sec (FAT-16 < 32M)",
259 "\xc6" "DRDOS/sec (FAT-16)",
260 "\xc7" "Syrinx",
261 "\xda" "Non-FS data",
262 "\xdb" "CP/M / CTOS / ...",/* CP/M or Concurrent CP/M or
263 Concurrent DOS or CTOS */
264 "\xde" "Dell Utility", /* Dell PowerEdge Server utilities */
265 "\xdf" "BootIt", /* BootIt EMBRM */
266 "\xe1" "DOS access", /* DOS access or SpeedStor 12-bit FAT
267 extended partition */
268 "\xe3" "DOS R/O", /* DOS R/O or SpeedStor */
269 "\xe4" "SpeedStor", /* SpeedStor 16-bit FAT extended
270 partition < 1024 cyl. */
271 "\xf1" "SpeedStor",
272 "\xf4" "SpeedStor", /* SpeedStor large partition */
273 "\xfe" "LANstep", /* SpeedStor >1024 cyl. or LANstep */
274 "\xff" "BBT", /* Xenix Bad Block Table */
275#endif
276 NULL
277};
278
Denis Vlasenko4437d192008-04-17 00:12:10 +0000279enum {
280 dev_fd = 3 /* the disk */
281};
Denis Vlasenkodfce08f2007-03-19 14:45:10 +0000282
283/* Globals */
Denis Vlasenko8e1a0cc2007-03-18 14:42:45 +0000284struct globals {
Denis Vlasenkodfce08f2007-03-19 14:45:10 +0000285 char *line_ptr;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000286
287 const char *disk_device;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000288 int g_partitions; // = 4; /* maximum partition + 1 */
289 unsigned units_per_sector; // = 1;
290 unsigned sector_size; // = DEFAULT_SECTOR_SIZE;
291 unsigned user_set_sector_size;
292 unsigned sector_offset; // = 1;
293 unsigned g_heads, g_sectors, g_cylinders;
Denis Vlasenko6eaf0a92008-06-29 05:10:47 +0000294 smallint /* enum label_type */ current_label_type;
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000295 smallint display_in_cyl_units; // = 1;
296#if ENABLE_FEATURE_OSF_LABEL
297 smallint possibly_osf_label;
298#endif
299
Denis Vlasenko6eaf0a92008-06-29 05:10:47 +0000300 smallint listing; /* no aborts for fdisk -l */
301 smallint dos_compatible_flag; // = 1;
302#if ENABLE_FEATURE_FDISK_WRITABLE
303 //int dos_changed;
304 smallint nowarn; /* no warnings for fdisk -l/-s */
305#endif
306 int ext_index; /* the prime extended partition */
307 unsigned user_cylinders, user_heads, user_sectors;
308 unsigned pt_heads, pt_sectors;
309 unsigned kern_heads, kern_sectors;
310 ullong extended_offset; /* offset of link pointers */
311 ullong total_number_of_sectors;
312
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000313 jmp_buf listingbuf;
Denis Vlasenkodfce08f2007-03-19 14:45:10 +0000314 char line_buffer[80];
315 char partname_buffer[80];
Denis Vlasenko8e1a0cc2007-03-18 14:42:45 +0000316 /* Raw disk label. For DOS-type partition tables the MBR,
317 * with descriptions of the primary partitions. */
318 char MBRbuffer[MAX_SECTOR_SIZE];
319 /* Partition tables */
320 struct pte ptes[MAXIMUM_PARTS];
321};
Denis Vlasenkodfce08f2007-03-19 14:45:10 +0000322#define G (*ptr_to_globals)
Denis Vlasenkodfce08f2007-03-19 14:45:10 +0000323#define line_ptr (G.line_ptr)
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000324#define disk_device (G.disk_device )
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000325#define g_partitions (G.g_partitions )
326#define units_per_sector (G.units_per_sector )
327#define sector_size (G.sector_size )
328#define user_set_sector_size (G.user_set_sector_size)
329#define sector_offset (G.sector_offset )
330#define g_heads (G.g_heads )
331#define g_sectors (G.g_sectors )
332#define g_cylinders (G.g_cylinders )
333#define current_label_type (G.current_label_type )
334#define display_in_cyl_units (G.display_in_cyl_units)
335#define possibly_osf_label (G.possibly_osf_label )
Denis Vlasenko6eaf0a92008-06-29 05:10:47 +0000336#define listing (G.listing )
337#define dos_compatible_flag (G.dos_compatible_flag )
338#define nowarn (G.nowarn )
339#define ext_index (G.ext_index )
340#define user_cylinders (G.user_cylinders )
341#define user_heads (G.user_heads )
342#define user_sectors (G.user_sectors )
343#define pt_heads (G.pt_heads )
344#define pt_sectors (G.pt_sectors )
345#define kern_heads (G.kern_heads )
346#define kern_sectors (G.kern_sectors )
347#define extended_offset (G.extended_offset )
348#define total_number_of_sectors (G.total_number_of_sectors)
Denis Vlasenkodfce08f2007-03-19 14:45:10 +0000349#define listingbuf (G.listingbuf)
350#define line_buffer (G.line_buffer)
351#define partname_buffer (G.partname_buffer)
352#define MBRbuffer (G.MBRbuffer)
353#define ptes (G.ptes)
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000354#define INIT_G() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000355 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000356 sector_size = DEFAULT_SECTOR_SIZE; \
357 sector_offset = 1; \
358 g_partitions = 4; \
359 display_in_cyl_units = 1; \
360 units_per_sector = 1; \
Denis Vlasenko6eaf0a92008-06-29 05:10:47 +0000361 dos_compatible_flag = 1; \
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000362} while (0)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000363
Denis Vlasenkobd852072007-03-19 14:43:38 +0000364
Denis Vlasenkocdf62772008-03-17 08:42:43 +0000365/* TODO: move to libbb? */
Denis Vlasenko4437d192008-04-17 00:12:10 +0000366static ullong bb_BLKGETSIZE_sectors(int fd)
Denis Vlasenkocdf62772008-03-17 08:42:43 +0000367{
368 uint64_t v64;
369 unsigned long longsectors;
370
371 if (ioctl(fd, BLKGETSIZE64, &v64) == 0) {
372 /* got bytes, convert to 512 byte sectors */
373 return (v64 >> 9);
374 }
375 /* Needs temp of type long */
376 if (ioctl(fd, BLKGETSIZE, &longsectors))
377 longsectors = 0;
378 return longsectors;
379}
380
381
Denis Vlasenkodfce08f2007-03-19 14:45:10 +0000382#define IS_EXTENDED(i) \
383 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
384
385#define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
386
387#define scround(x) (((x)+units_per_sector-1)/units_per_sector)
388
389#define pt_offset(b, n) \
390 ((struct partition *)((b) + 0x1be + (n) * sizeof(struct partition)))
391
392#define sector(s) ((s) & 0x3f)
393
394#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
395
396#define hsc2sector(h,s,c) \
397 (sector(s) - 1 + sectors * ((h) + heads * cylinder(s,c)))
398
399#define set_hsc(h,s,c,sector) \
400 do { \
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000401 s = sector % g_sectors + 1; \
402 sector /= g_sectors; \
403 h = sector % g_heads; \
404 sector /= g_heads; \
405 c = sector & 0xff; \
406 s |= (sector >> 2) & 0xc0; \
Denis Vlasenkodfce08f2007-03-19 14:45:10 +0000407 } while (0)
408
Denis Vlasenkoc033d512008-04-17 01:52:28 +0000409static void
410close_dev_fd(void)
411{
412 /* Not really closing, but making sure it is open, and to harmless place */
413 xmove_fd(xopen(bb_dev_null, O_RDONLY), dev_fd);
414}
415
Denis Vlasenko58875ae2007-03-22 22:22:10 +0000416#if ENABLE_FEATURE_FDISK_WRITABLE
Denis Vlasenkodfce08f2007-03-19 14:45:10 +0000417/* read line; return 0 or first printable char */
418static int
419read_line(const char *prompt)
420{
421 int sz;
422
423 sz = read_line_input(prompt, line_buffer, sizeof(line_buffer), NULL);
424 if (sz <= 0)
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +0000425 exit(EXIT_SUCCESS); /* Ctrl-D or Ctrl-C */
Denis Vlasenkodfce08f2007-03-19 14:45:10 +0000426
427 if (line_buffer[sz-1] == '\n')
428 line_buffer[--sz] = '\0';
429
430 line_ptr = line_buffer;
431 while (*line_ptr && !isgraph(*line_ptr))
432 line_ptr++;
433 return *line_ptr;
434}
Denis Vlasenko58875ae2007-03-22 22:22:10 +0000435#endif
Denis Vlasenkodfce08f2007-03-19 14:45:10 +0000436
Denis Vlasenkobd852072007-03-19 14:43:38 +0000437/*
438 * return partition name - uses static storage
439 */
440static const char *
441partname(const char *dev, int pno, int lth)
442{
Denis Vlasenkobd852072007-03-19 14:43:38 +0000443 const char *p;
444 int w, wp;
445 int bufsiz;
446 char *bufp;
447
Denis Vlasenkodfce08f2007-03-19 14:45:10 +0000448 bufp = partname_buffer;
449 bufsiz = sizeof(partname_buffer);
Denis Vlasenkobd852072007-03-19 14:43:38 +0000450
451 w = strlen(dev);
452 p = "";
453
454 if (isdigit(dev[w-1]))
455 p = "p";
456
457 /* devfs kludge - note: fdisk partition names are not supposed
458 to equal kernel names, so there is no reason to do this */
459 if (strcmp(dev + w - 4, "disc") == 0) {
460 w -= 4;
461 p = "part";
462 }
463
464 wp = strlen(p);
465
466 if (lth) {
467 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
468 lth-wp-2, w, dev, p, pno);
469 } else {
470 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
471 }
472 return bufp;
473}
474
Denis Vlasenko834410a2006-11-29 12:00:28 +0000475#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000476static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000477set_all_unchanged(void)
478{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000479 int i;
480
481 for (i = 0; i < MAXIMUM_PARTS; i++)
482 ptes[i].changed = 0;
483}
484
Denis Vlasenko3ad5d0c2007-06-12 20:54:54 +0000485static ALWAYS_INLINE void
Rob Landleyb73451d2006-02-24 16:29:00 +0000486set_changed(int i)
487{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000488 ptes[i].changed = 1;
489}
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000490#endif /* FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000491
Denis Vlasenko3ad5d0c2007-06-12 20:54:54 +0000492static ALWAYS_INLINE struct partition *
Rob Landleyb73451d2006-02-24 16:29:00 +0000493get_part_table(int i)
494{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000495 return ptes[i].part_table;
496}
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000497
498static const char *
Rob Landleyb73451d2006-02-24 16:29:00 +0000499str_units(int n)
500{ /* n==1: use singular */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000501 if (n == 1)
Denis Vlasenkobd852072007-03-19 14:43:38 +0000502 return display_in_cyl_units ? "cylinder" : "sector";
503 return display_in_cyl_units ? "cylinders" : "sectors";
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000504}
505
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000506static int
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000507valid_part_table_flag(const char *mbuffer)
508{
Denis Vlasenko834410a2006-11-29 12:00:28 +0000509 return (mbuffer[510] == 0x55 && (uint8_t)mbuffer[511] == 0xaa);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000510}
511
Denis Vlasenko834410a2006-11-29 12:00:28 +0000512#if ENABLE_FEATURE_FDISK_WRITABLE
Denis Vlasenko3ad5d0c2007-06-12 20:54:54 +0000513static ALWAYS_INLINE void
Denis Vlasenko834410a2006-11-29 12:00:28 +0000514write_part_table_flag(char *b)
515{
516 b[510] = 0x55;
517 b[511] = 0xaa;
518}
519
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000520static char
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000521read_nonempty(const char *mesg)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000522{
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000523 while (!read_line(mesg)) /* repeat */;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000524 return *line_ptr;
525}
526
527static char
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000528read_maybe_empty(const char *mesg)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000529{
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000530 if (!read_line(mesg)) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000531 line_ptr = line_buffer;
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000532 line_ptr[0] = '\n';
533 line_ptr[1] = '\0';
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000534 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000535 return line_ptr[0];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000536}
537
538static int
Denis Vlasenkobd852072007-03-19 14:43:38 +0000539read_hex(const char *const *sys)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000540{
Denis Vlasenkoc6ce8732006-11-29 18:15:52 +0000541 unsigned long v;
Rob Landleyb73451d2006-02-24 16:29:00 +0000542 while (1) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000543 read_nonempty("Hex code (type L to list codes): ");
Denis Vlasenkoc6ce8732006-11-29 18:15:52 +0000544 if (*line_ptr == 'l' || *line_ptr == 'L') {
Rob Landleyb73451d2006-02-24 16:29:00 +0000545 list_types(sys);
Denis Vlasenkoc6ce8732006-11-29 18:15:52 +0000546 continue;
Rob Landleyb73451d2006-02-24 16:29:00 +0000547 }
Denis Vlasenkoc6ce8732006-11-29 18:15:52 +0000548 v = bb_strtoul(line_ptr, NULL, 16);
Denis Vlasenko28703012006-12-19 20:32:02 +0000549 if (v > 0xff)
550 /* Bad input also triggers this */
551 continue;
Denis Vlasenkoc6ce8732006-11-29 18:15:52 +0000552 return v;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000553 }
554}
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000555#endif /* FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000556
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000557#include "fdisk_aix.c"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000558
559typedef struct {
560 unsigned char info[128]; /* Informative text string */
561 unsigned char spare0[14];
562 struct sun_info {
563 unsigned char spare1;
564 unsigned char id;
565 unsigned char spare2;
566 unsigned char flags;
567 } infos[8];
568 unsigned char spare1[246]; /* Boot information etc. */
569 unsigned short rspeed; /* Disk rotational speed */
570 unsigned short pcylcount; /* Physical cylinder count */
571 unsigned short sparecyl; /* extra sects per cylinder */
572 unsigned char spare2[4]; /* More magic... */
573 unsigned short ilfact; /* Interleave factor */
574 unsigned short ncyl; /* Data cylinder count */
575 unsigned short nacyl; /* Alt. cylinder count */
576 unsigned short ntrks; /* Tracks per cylinder */
577 unsigned short nsect; /* Sectors per track */
578 unsigned char spare3[4]; /* Even more magic... */
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000579 struct sun_partinfo {
Eric Andersenacd244a2002-12-11 03:49:33 +0000580 uint32_t start_cylinder;
581 uint32_t num_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000582 } partitions[8];
583 unsigned short magic; /* Magic number */
584 unsigned short csum; /* Label xor'd checksum */
585} sun_partition;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000586#define sunlabel ((sun_partition *)MBRbuffer)
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000587STATIC_OSF void bsd_select(void);
588STATIC_OSF void xbsd_print_disklabel(int);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000589#include "fdisk_osf.c"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000590
Denis Vlasenko28703012006-12-19 20:32:02 +0000591#if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL
Denis Vlasenko10d0d4e2006-11-27 16:48:17 +0000592static uint16_t
Denis Vlasenko28703012006-12-19 20:32:02 +0000593fdisk_swap16(uint16_t x)
Rob Landleyb73451d2006-02-24 16:29:00 +0000594{
Denis Vlasenko10d0d4e2006-11-27 16:48:17 +0000595 return (x << 8) | (x >> 8);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000596}
597
Rob Landley88621d72006-08-29 19:41:06 +0000598static uint32_t
Denis Vlasenko28703012006-12-19 20:32:02 +0000599fdisk_swap32(uint32_t x)
Rob Landleyb73451d2006-02-24 16:29:00 +0000600{
Denis Vlasenko10d0d4e2006-11-27 16:48:17 +0000601 return (x << 24) |
602 ((x & 0xFF00) << 8) |
603 ((x & 0xFF0000) >> 8) |
604 (x >> 24);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000605}
606#endif
607
Denis Vlasenkobd852072007-03-19 14:43:38 +0000608STATIC_SGI const char *const sgi_sys_types[];
Denis Vlasenko834410a2006-11-29 12:00:28 +0000609STATIC_SGI unsigned sgi_get_num_sectors(int i);
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000610STATIC_SGI int sgi_get_sysid(int i);
611STATIC_SGI void sgi_delete_partition(int i);
612STATIC_SGI void sgi_change_sysid(int i, int sys);
613STATIC_SGI void sgi_list_table(int xtra);
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000614#if ENABLE_FEATURE_FDISK_ADVANCED
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000615STATIC_SGI void sgi_set_xcyl(void);
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000616#endif
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000617STATIC_SGI int verify_sgi(int verbose);
618STATIC_SGI void sgi_add_partition(int n, int sys);
619STATIC_SGI void sgi_set_swappartition(int i);
620STATIC_SGI const char *sgi_get_bootfile(void);
621STATIC_SGI void sgi_set_bootfile(const char* aFile);
622STATIC_SGI void create_sgiinfo(void);
623STATIC_SGI void sgi_write_table(void);
624STATIC_SGI void sgi_set_bootpartition(int i);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000625#include "fdisk_sgi.c"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000626
Denis Vlasenkobd852072007-03-19 14:43:38 +0000627STATIC_SUN const char *const sun_sys_types[];
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000628STATIC_SUN void sun_delete_partition(int i);
629STATIC_SUN void sun_change_sysid(int i, int sys);
630STATIC_SUN void sun_list_table(int xtra);
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000631STATIC_SUN void add_sun_partition(int n, int sys);
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000632#if ENABLE_FEATURE_FDISK_ADVANCED
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000633STATIC_SUN void sun_set_alt_cyl(void);
634STATIC_SUN void sun_set_ncyl(int cyl);
635STATIC_SUN void sun_set_xcyl(void);
636STATIC_SUN void sun_set_ilfact(void);
637STATIC_SUN void sun_set_rspeed(void);
638STATIC_SUN void sun_set_pcylcount(void);
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000639#endif
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +0000640STATIC_SUN void toggle_sunflags(int i, unsigned char mask);
641STATIC_SUN void verify_sun(void);
642STATIC_SUN void sun_write_table(void);
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000643#include "fdisk_sun.c"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000644
Denis Vlasenko834410a2006-11-29 12:00:28 +0000645#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000646/* start_sect and nr_sects are stored little endian on all machines */
647/* moreover, they are not aligned correctly */
648static void
Denis Vlasenko834410a2006-11-29 12:00:28 +0000649store4_little_endian(unsigned char *cp, unsigned val)
Rob Landleyb73451d2006-02-24 16:29:00 +0000650{
Denis Vlasenko834410a2006-11-29 12:00:28 +0000651 cp[0] = val;
652 cp[1] = val >> 8;
653 cp[2] = val >> 16;
654 cp[3] = val >> 24;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000655}
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000656#endif /* FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000657
Denis Vlasenko834410a2006-11-29 12:00:28 +0000658static unsigned
Rob Landleyb73451d2006-02-24 16:29:00 +0000659read4_little_endian(const unsigned char *cp)
660{
Denis Vlasenko834410a2006-11-29 12:00:28 +0000661 return cp[0] + (cp[1] << 8) + (cp[2] << 16) + (cp[3] << 24);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000662}
663
Denis Vlasenko834410a2006-11-29 12:00:28 +0000664#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000665static void
Denis Vlasenko834410a2006-11-29 12:00:28 +0000666set_start_sect(struct partition *p, unsigned start_sect)
Rob Landleyb73451d2006-02-24 16:29:00 +0000667{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000668 store4_little_endian(p->start4, start_sect);
669}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000670#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000671
Denis Vlasenko28703012006-12-19 20:32:02 +0000672static unsigned
Rob Landleyb73451d2006-02-24 16:29:00 +0000673get_start_sect(const struct partition *p)
674{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000675 return read4_little_endian(p->start4);
676}
677
Denis Vlasenko834410a2006-11-29 12:00:28 +0000678#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000679static void
Denis Vlasenko28703012006-12-19 20:32:02 +0000680set_nr_sects(struct partition *p, unsigned nr_sects)
Rob Landleyb73451d2006-02-24 16:29:00 +0000681{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000682 store4_little_endian(p->size4, nr_sects);
683}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000684#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000685
Denis Vlasenko28703012006-12-19 20:32:02 +0000686static unsigned
Rob Landleyb73451d2006-02-24 16:29:00 +0000687get_nr_sects(const struct partition *p)
688{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000689 return read4_little_endian(p->size4);
690}
691
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +0000692static void fdisk_fatal(const char *why)
Rob Landleyb73451d2006-02-24 16:29:00 +0000693{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000694 if (listing) {
Denis Vlasenkoc033d512008-04-17 01:52:28 +0000695 close_dev_fd();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000696 longjmp(listingbuf, 1);
697 }
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +0000698 bb_error_msg_and_die(why, disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000699}
700
701static void
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +0000702seek_sector(ullong secno)
Rob Landleyb73451d2006-02-24 16:29:00 +0000703{
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +0000704 secno *= sector_size;
Denis Vlasenko06b3cc22007-09-23 14:05:54 +0000705#if ENABLE_FDISK_SUPPORT_LARGE_DISKS
Denis Vlasenko4437d192008-04-17 00:12:10 +0000706 if (lseek64(dev_fd, (off64_t)secno, SEEK_SET) == (off64_t) -1)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000707 fdisk_fatal(unable_to_seek);
Denis Vlasenko06b3cc22007-09-23 14:05:54 +0000708#else
709 if (secno > MAXINT(off_t)
Denis Vlasenko4437d192008-04-17 00:12:10 +0000710 || lseek(dev_fd, (off_t)secno, SEEK_SET) == (off_t) -1
Denis Vlasenko06b3cc22007-09-23 14:05:54 +0000711 ) {
712 fdisk_fatal(unable_to_seek);
713 }
714#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000715}
716
Denis Vlasenko834410a2006-11-29 12:00:28 +0000717#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000718static void
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +0000719write_sector(ullong secno, char *buf)
Rob Landleyb73451d2006-02-24 16:29:00 +0000720{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000721 seek_sector(secno);
Denis Vlasenko6eaf0a92008-06-29 05:10:47 +0000722 xwrite(dev_fd, buf, sector_size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000723}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000724#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000725
726/* Allocate a buffer and read a partition table sector */
727static void
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +0000728read_pte(struct pte *pe, ullong offset)
Rob Landleyb73451d2006-02-24 16:29:00 +0000729{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000730 pe->offset = offset;
Denis Vlasenko6eaf0a92008-06-29 05:10:47 +0000731 pe->sectorbuffer = xzalloc(sector_size);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000732 seek_sector(offset);
Denis Vlasenko6eaf0a92008-06-29 05:10:47 +0000733 /* xread would make us abort - bad for fdisk -l */
734 if (full_read(dev_fd, pe->sectorbuffer, sector_size) != sector_size)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000735 fdisk_fatal(unable_to_read);
Denis Vlasenko834410a2006-11-29 12:00:28 +0000736#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000737 pe->changed = 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000738#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000739 pe->part_table = pe->ext_pointer = NULL;
740}
741
Denis Vlasenko834410a2006-11-29 12:00:28 +0000742static unsigned
Rob Landleyb73451d2006-02-24 16:29:00 +0000743get_partition_start(const struct pte *pe)
744{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000745 return pe->offset + get_start_sect(pe->part_table);
746}
747
Denis Vlasenko834410a2006-11-29 12:00:28 +0000748#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000749/*
750 * Avoid warning about DOS partitions when no DOS partition was changed.
751 * Here a heuristic "is probably dos partition".
752 * We might also do the opposite and warn in all cases except
753 * for "is probably nondos partition".
754 */
Denis Vlasenko89398812008-01-25 20:18:46 +0000755#ifdef UNUSED
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000756static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000757is_dos_partition(int t)
758{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000759 return (t == 1 || t == 4 || t == 6 ||
760 t == 0x0b || t == 0x0c || t == 0x0e ||
761 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
762 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
763 t == 0xc1 || t == 0xc4 || t == 0xc6);
764}
Denis Vlasenko89398812008-01-25 20:18:46 +0000765#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000766
767static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000768menu(void)
769{
Denis Vlasenkobd852072007-03-19 14:43:38 +0000770 puts("Command Action");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000771 if (LABEL_IS_SUN) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000772 puts("a\ttoggle a read only flag"); /* sun */
773 puts("b\tedit bsd disklabel");
774 puts("c\ttoggle the mountable flag"); /* sun */
775 puts("d\tdelete a partition");
776 puts("l\tlist known partition types");
777 puts("n\tadd a new partition");
778 puts("o\tcreate a new empty DOS partition table");
779 puts("p\tprint the partition table");
780 puts("q\tquit without saving changes");
781 puts("s\tcreate a new empty Sun disklabel"); /* sun */
782 puts("t\tchange a partition's system id");
783 puts("u\tchange display/entry units");
784 puts("v\tverify the partition table");
785 puts("w\twrite table to disk and exit");
Denis Vlasenko834410a2006-11-29 12:00:28 +0000786#if ENABLE_FEATURE_FDISK_ADVANCED
Denis Vlasenkobd852072007-03-19 14:43:38 +0000787 puts("x\textra functionality (experts only)");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000788#endif
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000789 } else if (LABEL_IS_SGI) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000790 puts("a\tselect bootable partition"); /* sgi flavour */
791 puts("b\tedit bootfile entry"); /* sgi */
792 puts("c\tselect sgi swap partition"); /* sgi flavour */
793 puts("d\tdelete a partition");
794 puts("l\tlist known partition types");
795 puts("n\tadd a new partition");
796 puts("o\tcreate a new empty DOS partition table");
797 puts("p\tprint the partition table");
798 puts("q\tquit without saving changes");
799 puts("s\tcreate a new empty Sun disklabel"); /* sun */
800 puts("t\tchange a partition's system id");
801 puts("u\tchange display/entry units");
802 puts("v\tverify the partition table");
803 puts("w\twrite table to disk and exit");
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000804 } else if (LABEL_IS_AIX) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000805 puts("o\tcreate a new empty DOS partition table");
806 puts("q\tquit without saving changes");
807 puts("s\tcreate a new empty Sun disklabel"); /* sun */
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000808 } else {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000809 puts("a\ttoggle a bootable flag");
810 puts("b\tedit bsd disklabel");
811 puts("c\ttoggle the dos compatibility flag");
812 puts("d\tdelete a partition");
813 puts("l\tlist known partition types");
814 puts("n\tadd a new partition");
815 puts("o\tcreate a new empty DOS partition table");
816 puts("p\tprint the partition table");
817 puts("q\tquit without saving changes");
818 puts("s\tcreate a new empty Sun disklabel"); /* sun */
819 puts("t\tchange a partition's system id");
820 puts("u\tchange display/entry units");
821 puts("v\tverify the partition table");
822 puts("w\twrite table to disk and exit");
Denis Vlasenko834410a2006-11-29 12:00:28 +0000823#if ENABLE_FEATURE_FDISK_ADVANCED
Denis Vlasenkobd852072007-03-19 14:43:38 +0000824 puts("x\textra functionality (experts only)");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000825#endif
826 }
827}
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000828#endif /* FEATURE_FDISK_WRITABLE */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000829
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000830
Denis Vlasenko834410a2006-11-29 12:00:28 +0000831#if ENABLE_FEATURE_FDISK_ADVANCED
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000832static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000833xmenu(void)
834{
Denis Vlasenkobd852072007-03-19 14:43:38 +0000835 puts("Command Action");
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000836 if (LABEL_IS_SUN) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000837 puts("a\tchange number of alternate cylinders"); /*sun*/
838 puts("c\tchange number of cylinders");
839 puts("d\tprint the raw data in the partition table");
840 puts("e\tchange number of extra sectors per cylinder");/*sun*/
841 puts("h\tchange number of heads");
842 puts("i\tchange interleave factor"); /*sun*/
843 puts("o\tchange rotation speed (rpm)"); /*sun*/
844 puts("p\tprint the partition table");
845 puts("q\tquit without saving changes");
846 puts("r\treturn to main menu");
847 puts("s\tchange number of sectors/track");
848 puts("v\tverify the partition table");
849 puts("w\twrite table to disk and exit");
850 puts("y\tchange number of physical cylinders"); /*sun*/
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000851 } else if (LABEL_IS_SGI) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000852 puts("b\tmove beginning of data in a partition"); /* !sun */
853 puts("c\tchange number of cylinders");
854 puts("d\tprint the raw data in the partition table");
855 puts("e\tlist extended partitions"); /* !sun */
856 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
857 puts("h\tchange number of heads");
858 puts("p\tprint the partition table");
859 puts("q\tquit without saving changes");
860 puts("r\treturn to main menu");
861 puts("s\tchange number of sectors/track");
862 puts("v\tverify the partition table");
863 puts("w\twrite table to disk and exit");
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000864 } else if (LABEL_IS_AIX) {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000865 puts("b\tmove beginning of data in a partition"); /* !sun */
866 puts("c\tchange number of cylinders");
867 puts("d\tprint the raw data in the partition table");
868 puts("e\tlist extended partitions"); /* !sun */
869 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
870 puts("h\tchange number of heads");
871 puts("p\tprint the partition table");
872 puts("q\tquit without saving changes");
873 puts("r\treturn to main menu");
874 puts("s\tchange number of sectors/track");
875 puts("v\tverify the partition table");
876 puts("w\twrite table to disk and exit");
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000877 } else {
Denis Vlasenkobd852072007-03-19 14:43:38 +0000878 puts("b\tmove beginning of data in a partition"); /* !sun */
879 puts("c\tchange number of cylinders");
880 puts("d\tprint the raw data in the partition table");
881 puts("e\tlist extended partitions"); /* !sun */
882 puts("f\tfix partition order"); /* !sun, !aix, !sgi */
Denis Vlasenko834410a2006-11-29 12:00:28 +0000883#if ENABLE_FEATURE_SGI_LABEL
Denis Vlasenkobd852072007-03-19 14:43:38 +0000884 puts("g\tcreate an IRIX (SGI) partition table");/* sgi */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000885#endif
Denis Vlasenkobd852072007-03-19 14:43:38 +0000886 puts("h\tchange number of heads");
887 puts("p\tprint the partition table");
888 puts("q\tquit without saving changes");
889 puts("r\treturn to main menu");
890 puts("s\tchange number of sectors/track");
891 puts("v\tverify the partition table");
892 puts("w\twrite table to disk and exit");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000893 }
894}
895#endif /* ADVANCED mode */
896
Denis Vlasenko834410a2006-11-29 12:00:28 +0000897#if ENABLE_FEATURE_FDISK_WRITABLE
Denis Vlasenkobd852072007-03-19 14:43:38 +0000898static const char *const *
Rob Landleyb73451d2006-02-24 16:29:00 +0000899get_sys_types(void)
900{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000901 return (
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000902 LABEL_IS_SUN ? sun_sys_types :
903 LABEL_IS_SGI ? sgi_sys_types :
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000904 i386_sys_types);
905}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000906#else
907#define get_sys_types() i386_sys_types
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000908#endif /* FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000909
Denis Vlasenkobd852072007-03-19 14:43:38 +0000910static const char *
911partition_type(unsigned char type)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000912{
913 int i;
Denis Vlasenkobd852072007-03-19 14:43:38 +0000914 const char *const *types = get_sys_types();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000915
Denis Vlasenkobd852072007-03-19 14:43:38 +0000916 for (i = 0; types[i]; i++)
917 if ((unsigned char)types[i][0] == type)
918 return types[i] + 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000919
Denis Vlasenkobd852072007-03-19 14:43:38 +0000920 return "Unknown";
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000921}
922
923
Denis Vlasenko834410a2006-11-29 12:00:28 +0000924#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000925static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000926get_sysid(int i)
927{
Denis Vlasenko98ae2162006-10-12 19:30:44 +0000928 return LABEL_IS_SUN ? sunlabel->infos[i].id :
929 (LABEL_IS_SGI ? sgi_get_sysid(i) :
930 ptes[i].part_table->sys_ind);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000931}
932
Denis Vlasenkobd852072007-03-19 14:43:38 +0000933static void
934list_types(const char *const *sys)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000935{
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000936 enum { COLS = 3 };
937
938 unsigned last[COLS];
939 unsigned done, next, size;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000940 int i;
941
Denis Vlasenkobd852072007-03-19 14:43:38 +0000942 for (size = 0; sys[size]; size++) /* */;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000943
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000944 done = 0;
945 for (i = COLS-1; i >= 0; i--) {
946 done += (size + i - done) / (i + 1);
947 last[COLS-1 - i] = done;
948 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000949
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000950 i = done = next = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000951 do {
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000952 printf("%c%2x %-22.22s", i ? ' ' : '\n',
Denis Vlasenkobd852072007-03-19 14:43:38 +0000953 (unsigned char)sys[next][0],
954 sys[next] + 1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000955 next = last[i++] + done;
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000956 if (i >= COLS || next >= last[i]) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000957 i = 0;
958 next = ++done;
959 }
960 } while (done < last[0]);
Denis Vlasenko4daad902007-09-27 10:20:47 +0000961 bb_putchar('\n');
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000962}
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +0000963#endif /* FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000964
965static int
Rob Landleyb73451d2006-02-24 16:29:00 +0000966is_cleared_partition(const struct partition *p)
967{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000968 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
969 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
970 get_start_sect(p) || get_nr_sects(p));
971}
972
973static void
Rob Landleyb73451d2006-02-24 16:29:00 +0000974clear_partition(struct partition *p)
975{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000976 if (!p)
977 return;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +0000978 memset(p, 0, sizeof(struct partition));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000979}
980
Denis Vlasenko834410a2006-11-29 12:00:28 +0000981#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000982static void
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +0000983set_partition(int i, int doext, ullong start, ullong stop, int sysid)
Rob Landleyb73451d2006-02-24 16:29:00 +0000984{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000985 struct partition *p;
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +0000986 ullong offset;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +0000987
988 if (doext) {
989 p = ptes[i].ext_pointer;
990 offset = extended_offset;
991 } else {
992 p = ptes[i].part_table;
993 offset = ptes[i].offset;
994 }
995 p->boot_ind = 0;
996 p->sys_ind = sysid;
997 set_start_sect(p, start - offset);
998 set_nr_sects(p, stop - start + 1);
Denis Vlasenkof77f3692007-12-16 17:22:33 +0000999 if (dos_compatible_flag && (start / (g_sectors * g_heads) > 1023))
1000 start = g_heads * g_sectors * 1024 - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001001 set_hsc(p->head, p->sector, p->cyl, start);
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001002 if (dos_compatible_flag && (stop / (g_sectors * g_heads) > 1023))
1003 stop = g_heads * g_sectors * 1024 - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001004 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
1005 ptes[i].changed = 1;
1006}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001007#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001008
1009static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001010warn_geometry(void)
1011{
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001012 if (g_heads && g_sectors && g_cylinders)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001013 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001014
Denis Vlasenkobd852072007-03-19 14:43:38 +00001015 printf("Unknown value(s) for:");
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001016 if (!g_heads)
Denis Vlasenkobd852072007-03-19 14:43:38 +00001017 printf(" heads");
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001018 if (!g_sectors)
Denis Vlasenkobd852072007-03-19 14:43:38 +00001019 printf(" sectors");
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001020 if (!g_cylinders)
Denis Vlasenkobd852072007-03-19 14:43:38 +00001021 printf(" cylinders");
1022 printf(
Denis Vlasenko834410a2006-11-29 12:00:28 +00001023#if ENABLE_FEATURE_FDISK_WRITABLE
Denis Vlasenkobd852072007-03-19 14:43:38 +00001024 " (settable in the extra functions menu)"
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001025#endif
Denis Vlasenkobd852072007-03-19 14:43:38 +00001026 "\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001027 return 1;
1028}
1029
Denis Vlasenko8e1a0cc2007-03-18 14:42:45 +00001030static void
1031update_units(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001032{
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001033 int cyl_units = g_heads * g_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001034
1035 if (display_in_cyl_units && cyl_units)
1036 units_per_sector = cyl_units;
1037 else
1038 units_per_sector = 1; /* in sectors */
1039}
1040
Denis Vlasenko834410a2006-11-29 12:00:28 +00001041#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001042static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001043warn_cylinders(void)
1044{
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001045 if (LABEL_IS_DOS && g_cylinders > 1024 && !nowarn)
Denis Vlasenkobd852072007-03-19 14:43:38 +00001046 printf("\n"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001047"The number of cylinders for this disk is set to %d.\n"
1048"There is nothing wrong with that, but this is larger than 1024,\n"
1049"and could in certain setups cause problems with:\n"
1050"1) software that runs at boot time (e.g., old versions of LILO)\n"
1051"2) booting and partitioning software from other OSs\n"
Denis Vlasenkobd852072007-03-19 14:43:38 +00001052" (e.g., DOS FDISK, OS/2 FDISK)\n",
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001053 g_cylinders);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001054}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001055#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001056
1057static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001058read_extended(int ext)
1059{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001060 int i;
1061 struct pte *pex;
1062 struct partition *p, *q;
1063
1064 ext_index = ext;
1065 pex = &ptes[ext];
1066 pex->ext_pointer = pex->part_table;
1067
1068 p = pex->part_table;
1069 if (!get_start_sect(p)) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001070 printf("Bad offset in primary extended partition\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001071 return;
1072 }
1073
Rob Landleyb73451d2006-02-24 16:29:00 +00001074 while (IS_EXTENDED(p->sys_ind)) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001075 struct pte *pe = &ptes[g_partitions];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001076
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001077 if (g_partitions >= MAXIMUM_PARTS) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001078 /* This is not a Linux restriction, but
1079 this program uses arrays of size MAXIMUM_PARTS.
Denis Vlasenko89f0b342006-11-18 22:04:09 +00001080 Do not try to 'improve' this test. */
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001081 struct pte *pre = &ptes[g_partitions - 1];
Denis Vlasenko834410a2006-11-29 12:00:28 +00001082#if ENABLE_FEATURE_FDISK_WRITABLE
Denis Vlasenkobd852072007-03-19 14:43:38 +00001083 printf("Warning: deleting partitions after %d\n",
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001084 g_partitions);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001085 pre->changed = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001086#endif
1087 clear_partition(pre->ext_pointer);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001088 return;
1089 }
1090
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001091 read_pte(pe, extended_offset + get_start_sect(p));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001092
1093 if (!extended_offset)
1094 extended_offset = get_start_sect(p);
1095
1096 q = p = pt_offset(pe->sectorbuffer, 0);
1097 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001098 if (IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001099 if (pe->ext_pointer)
Denis Vlasenkobd852072007-03-19 14:43:38 +00001100 printf("Warning: extra link "
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001101 "pointer in partition table"
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001102 " %d\n", g_partitions + 1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001103 else
1104 pe->ext_pointer = p;
1105 } else if (p->sys_ind) {
1106 if (pe->part_table)
Denis Vlasenkobd852072007-03-19 14:43:38 +00001107 printf("Warning: ignoring extra "
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001108 "data in partition table"
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001109 " %d\n", g_partitions + 1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001110 else
1111 pe->part_table = p;
1112 }
1113 }
1114
1115 /* very strange code here... */
1116 if (!pe->part_table) {
1117 if (q != pe->ext_pointer)
1118 pe->part_table = q;
1119 else
1120 pe->part_table = q + 1;
1121 }
1122 if (!pe->ext_pointer) {
1123 if (q != pe->part_table)
1124 pe->ext_pointer = q;
1125 else
1126 pe->ext_pointer = q + 1;
1127 }
1128
1129 p = pe->ext_pointer;
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001130 g_partitions++;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001131 }
1132
Denis Vlasenko834410a2006-11-29 12:00:28 +00001133#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001134 /* remove empty links */
1135 remove:
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001136 for (i = 4; i < g_partitions; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001137 struct pte *pe = &ptes[i];
1138
Denis Vlasenkobd852072007-03-19 14:43:38 +00001139 if (!get_nr_sects(pe->part_table)
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001140 && (g_partitions > 5 || ptes[4].part_table->sys_ind)
Denis Vlasenkobd852072007-03-19 14:43:38 +00001141 ) {
1142 printf("Omitting empty partition (%d)\n", i+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001143 delete_partition(i);
1144 goto remove; /* numbering changed */
1145 }
1146 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001147#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001148}
1149
Denis Vlasenko834410a2006-11-29 12:00:28 +00001150#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001151static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001152create_doslabel(void)
1153{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001154 int i;
1155
Denis Vlasenkobd852072007-03-19 14:43:38 +00001156 printf(msg_building_new_label, "DOS disklabel");
Rob Landley5527b912006-02-25 03:46:10 +00001157
Denis Vlasenko4437d192008-04-17 00:12:10 +00001158 current_label_type = LABEL_DOS;
Rob Landley5527b912006-02-25 03:46:10 +00001159
Denis Vlasenko834410a2006-11-29 12:00:28 +00001160#if ENABLE_FEATURE_OSF_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001161 possibly_osf_label = 0;
1162#endif
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001163 g_partitions = 4;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001164
1165 for (i = 510-64; i < 510; i++)
1166 MBRbuffer[i] = 0;
1167 write_part_table_flag(MBRbuffer);
1168 extended_offset = 0;
1169 set_all_unchanged();
1170 set_changed(0);
Denis Vlasenko4437d192008-04-17 00:12:10 +00001171 get_boot(CREATE_EMPTY_DOS);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001172}
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +00001173#endif /* FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001174
1175static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001176get_sectorsize(void)
1177{
Rob Landley736e5252006-02-25 03:36:00 +00001178 if (!user_set_sector_size) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001179 int arg;
Denis Vlasenko4437d192008-04-17 00:12:10 +00001180 if (ioctl(dev_fd, BLKSSZGET, &arg) == 0)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001181 sector_size = arg;
1182 if (sector_size != DEFAULT_SECTOR_SIZE)
Denis Vlasenko6eaf0a92008-06-29 05:10:47 +00001183 printf("Note: sector size is %d "
1184 "(not " DEFAULT_SECTOR_SIZE_STR ")\n",
1185 sector_size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001186 }
1187}
1188
Rob Landley88621d72006-08-29 19:41:06 +00001189static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001190get_kernel_geometry(void)
1191{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001192 struct hd_geometry geometry;
1193
Denis Vlasenko4437d192008-04-17 00:12:10 +00001194 if (!ioctl(dev_fd, HDIO_GETGEO, &geometry)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001195 kern_heads = geometry.heads;
1196 kern_sectors = geometry.sectors;
1197 /* never use geometry.cylinders - it is truncated */
1198 }
1199}
1200
1201static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001202get_partition_table_geometry(void)
1203{
"Vladimir N. Oleynik"a972c872005-12-02 10:06:04 +00001204 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001205 struct partition *p;
1206 int i, h, s, hh, ss;
1207 int first = 1;
1208 int bad = 0;
1209
Eric Andersen3496fdc2006-01-30 23:09:20 +00001210 if (!(valid_part_table_flag((char*)bufp)))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001211 return;
1212
1213 hh = ss = 0;
Rob Landleyb73451d2006-02-24 16:29:00 +00001214 for (i = 0; i < 4; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001215 p = pt_offset(bufp, i);
1216 if (p->sys_ind != 0) {
1217 h = p->end_head + 1;
1218 s = (p->end_sector & 077);
1219 if (first) {
1220 hh = h;
1221 ss = s;
1222 first = 0;
1223 } else if (hh != h || ss != s)
1224 bad = 1;
1225 }
1226 }
1227
1228 if (!first && !bad) {
1229 pt_heads = hh;
1230 pt_sectors = ss;
1231 }
1232}
1233
Rob Landleyb73451d2006-02-24 16:29:00 +00001234static void
1235get_geometry(void)
1236{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001237 int sec_fac;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001238
1239 get_sectorsize();
1240 sec_fac = sector_size / 512;
Denis Vlasenko834410a2006-11-29 12:00:28 +00001241#if ENABLE_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001242 guess_device_type();
1243#endif
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001244 g_heads = g_cylinders = g_sectors = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001245 kern_heads = kern_sectors = 0;
1246 pt_heads = pt_sectors = 0;
1247
1248 get_kernel_geometry();
1249 get_partition_table_geometry();
1250
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001251 g_heads = user_heads ? user_heads :
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001252 pt_heads ? pt_heads :
1253 kern_heads ? kern_heads : 255;
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001254 g_sectors = user_sectors ? user_sectors :
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001255 pt_sectors ? pt_sectors :
1256 kern_sectors ? kern_sectors : 63;
Denis Vlasenko4437d192008-04-17 00:12:10 +00001257 total_number_of_sectors = bb_BLKGETSIZE_sectors(dev_fd);
Eric Andersen040f4402003-07-30 08:40:37 +00001258
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001259 sector_offset = 1;
1260 if (dos_compatible_flag)
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001261 sector_offset = g_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001262
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001263 g_cylinders = total_number_of_sectors / (g_heads * g_sectors * sec_fac);
1264 if (!g_cylinders)
1265 g_cylinders = user_cylinders;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001266}
1267
1268/*
Denis Vlasenko4437d192008-04-17 00:12:10 +00001269 * Opens disk_device and optionally reads MBR.
1270 * FIXME: document what each 'what' value will do!
1271 * Returns:
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001272 * -1: no 0xaa55 flag present (possibly entire disk BSD)
1273 * 0: found or created label
1274 * 1: I/O error
1275 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00001276#if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
1277static int get_boot(enum action what)
1278#else
1279static int get_boot(void)
1280#define get_boot(what) get_boot()
1281#endif
Rob Landleyb73451d2006-02-24 16:29:00 +00001282{
Denis Vlasenko4437d192008-04-17 00:12:10 +00001283 int i, fd;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001284
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001285 g_partitions = 4;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001286 for (i = 0; i < 4; i++) {
1287 struct pte *pe = &ptes[i];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001288 pe->part_table = pt_offset(MBRbuffer, i);
1289 pe->ext_pointer = NULL;
1290 pe->offset = 0;
1291 pe->sectorbuffer = MBRbuffer;
Denis Vlasenko834410a2006-11-29 12:00:28 +00001292#if ENABLE_FEATURE_FDISK_WRITABLE
Denis Vlasenko4437d192008-04-17 00:12:10 +00001293 pe->changed = (what == CREATE_EMPTY_DOS);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001294#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001295 }
1296
Denis Vlasenko834410a2006-11-29 12:00:28 +00001297#if ENABLE_FEATURE_FDISK_WRITABLE
Denis Vlasenko4437d192008-04-17 00:12:10 +00001298// ALERT! highly idiotic design!
1299// We end up here when we call get_boot() recursively
1300// via get_boot() [table is bad] -> create_doslabel() -> get_boot(CREATE_EMPTY_DOS).
1301// or get_boot() [table is bad] -> create_sunlabel() -> get_boot(CREATE_EMPTY_SUN).
1302// (just factor out re-init of ptes[0,1,2,3] in a separate fn instead?)
1303// So skip opening device _again_...
1304 if (what == CREATE_EMPTY_DOS USE_FEATURE_SUN_LABEL(|| what == CREATE_EMPTY_SUN))
1305 goto created_table;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001306
Denis Vlasenko4437d192008-04-17 00:12:10 +00001307 fd = open(disk_device, (option_mask32 & OPT_l) ? O_RDONLY : O_RDWR);
1308
Denis Vlasenkobd852072007-03-19 14:43:38 +00001309 if (fd < 0) {
1310 fd = open(disk_device, O_RDONLY);
1311 if (fd < 0) {
Denis Vlasenko4437d192008-04-17 00:12:10 +00001312 if (what == TRY_ONLY)
Rob Landleyb73451d2006-02-24 16:29:00 +00001313 return 1;
1314 fdisk_fatal(unable_to_open);
Denis Vlasenko4437d192008-04-17 00:12:10 +00001315 }
Denis Vlasenko4437d192008-04-17 00:12:10 +00001316 printf("'%s' is opened for read only\n", disk_device);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001317 }
Denis Vlasenkoc033d512008-04-17 01:52:28 +00001318 xmove_fd(fd, dev_fd);
Denis Vlasenko6eaf0a92008-06-29 05:10:47 +00001319 if (512 != full_read(dev_fd, MBRbuffer, 512)) {
Denis Vlasenko4437d192008-04-17 00:12:10 +00001320 if (what == TRY_ONLY) {
Denis Vlasenkoc033d512008-04-17 01:52:28 +00001321 close_dev_fd();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001322 return 1;
Denis Vlasenko4437d192008-04-17 00:12:10 +00001323 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001324 fdisk_fatal(unable_to_read);
1325 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001326#else
Denis Vlasenkobd852072007-03-19 14:43:38 +00001327 fd = open(disk_device, O_RDONLY);
1328 if (fd < 0)
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001329 return 1;
Denis Vlasenko6eaf0a92008-06-29 05:10:47 +00001330 if (512 != full_read(fd, MBRbuffer, 512)) {
Denis Vlasenko4437d192008-04-17 00:12:10 +00001331 close(fd);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001332 return 1;
Denis Vlasenko4437d192008-04-17 00:12:10 +00001333 }
1334 xmove_fd(fd, dev_fd);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001335#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001336
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001337 get_geometry();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001338 update_units();
1339
Denis Vlasenko834410a2006-11-29 12:00:28 +00001340#if ENABLE_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001341 if (check_sun_label())
1342 return 0;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001343#endif
Denis Vlasenko834410a2006-11-29 12:00:28 +00001344#if ENABLE_FEATURE_SGI_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001345 if (check_sgi_label())
1346 return 0;
1347#endif
Denis Vlasenko834410a2006-11-29 12:00:28 +00001348#if ENABLE_FEATURE_AIX_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001349 if (check_aix_label())
1350 return 0;
1351#endif
Denis Vlasenko834410a2006-11-29 12:00:28 +00001352#if ENABLE_FEATURE_OSF_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001353 if (check_osf_label()) {
1354 possibly_osf_label = 1;
1355 if (!valid_part_table_flag(MBRbuffer)) {
Denis Vlasenko4437d192008-04-17 00:12:10 +00001356 current_label_type = LABEL_OSF;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001357 return 0;
1358 }
Denis Vlasenkobd852072007-03-19 14:43:38 +00001359 printf("This disk has both DOS and BSD magic.\n"
1360 "Give the 'b' command to go to BSD mode.\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001361 }
1362#endif
1363
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +00001364#if !ENABLE_FEATURE_FDISK_WRITABLE
Denis Vlasenko4437d192008-04-17 00:12:10 +00001365 if (!valid_part_table_flag(MBRbuffer))
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001366 return -1;
1367#else
Denis Vlasenko4437d192008-04-17 00:12:10 +00001368 if (!valid_part_table_flag(MBRbuffer)) {
1369 if (what == OPEN_MAIN) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001370 printf("Device contains neither a valid DOS "
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001371 "partition table, nor Sun, SGI or OSF "
Denis Vlasenkobd852072007-03-19 14:43:38 +00001372 "disklabel\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001373#ifdef __sparc__
Denis Vlasenko4437d192008-04-17 00:12:10 +00001374 USE_FEATURE_SUN_LABEL(create_sunlabel();)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001375#else
1376 create_doslabel();
1377#endif
1378 return 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001379 }
Denis Vlasenko4437d192008-04-17 00:12:10 +00001380 /* TRY_ONLY: */
1381 return -1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001382 }
Denis Vlasenko4437d192008-04-17 00:12:10 +00001383 created_table:
1384#endif /* FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001385
Denis Vlasenko4437d192008-04-17 00:12:10 +00001386
1387 USE_FEATURE_FDISK_WRITABLE(warn_cylinders();)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001388 warn_geometry();
1389
1390 for (i = 0; i < 4; i++) {
Denis Vlasenko4437d192008-04-17 00:12:10 +00001391 if (IS_EXTENDED(ptes[i].part_table->sys_ind)) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001392 if (g_partitions != 4)
Denis Vlasenkobd852072007-03-19 14:43:38 +00001393 printf("Ignoring extra extended "
1394 "partition %d\n", i + 1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001395 else
1396 read_extended(i);
1397 }
1398 }
1399
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001400 for (i = 3; i < g_partitions; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001401 struct pte *pe = &ptes[i];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001402 if (!valid_part_table_flag(pe->sectorbuffer)) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001403 printf("Warning: invalid flag 0x%02x,0x%02x of partition "
1404 "table %d will be corrected by w(rite)\n",
Denis Vlasenko834410a2006-11-29 12:00:28 +00001405 pe->sectorbuffer[510],
1406 pe->sectorbuffer[511],
1407 i + 1);
Denis Vlasenko4437d192008-04-17 00:12:10 +00001408 USE_FEATURE_FDISK_WRITABLE(pe->changed = 1;)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001409 }
1410 }
1411
1412 return 0;
1413}
1414
Denis Vlasenko834410a2006-11-29 12:00:28 +00001415#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001416/*
1417 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
1418 * If the user hits Enter, DFLT is returned.
1419 * Answers like +10 are interpreted as offsets from BASE.
1420 *
1421 * There is no default if DFLT is not between LOW and HIGH.
1422 */
Denis Vlasenko834410a2006-11-29 12:00:28 +00001423static unsigned
Denis Vlasenko06c0a712007-01-29 22:51:44 +00001424read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, const char *mesg)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001425{
Denis Vlasenko834410a2006-11-29 12:00:28 +00001426 unsigned i;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001427 int default_ok = 1;
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001428 const char *fmt = "%s (%u-%u, default %u): ";
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001429
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001430 if (dflt < low || dflt > high) {
1431 fmt = "%s (%u-%u): ";
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001432 default_ok = 0;
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001433 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001434
1435 while (1) {
1436 int use_default = default_ok;
1437
1438 /* ask question and read answer */
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001439 do {
1440 printf(fmt, mesg, low, high, dflt);
1441 read_maybe_empty("");
1442 } while (*line_ptr != '\n' && !isdigit(*line_ptr)
1443 && *line_ptr != '-' && *line_ptr != '+');
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001444
Eric Andersen84bdea82004-05-19 10:49:17 +00001445 if (*line_ptr == '+' || *line_ptr == '-') {
Rob Landleyb73451d2006-02-24 16:29:00 +00001446 int minus = (*line_ptr == '-');
1447 int absolute = 0;
Eric Andersenc48d49a2003-07-03 10:02:32 +00001448
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001449 i = atoi(line_ptr + 1);
Eric Andersenc48d49a2003-07-03 10:02:32 +00001450
Rob Landleyb73451d2006-02-24 16:29:00 +00001451 while (isdigit(*++line_ptr))
1452 use_default = 0;
Eric Andersen84bdea82004-05-19 10:49:17 +00001453
Rob Landleyb73451d2006-02-24 16:29:00 +00001454 switch (*line_ptr) {
1455 case 'c':
1456 case 'C':
1457 if (!display_in_cyl_units)
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001458 i *= g_heads * g_sectors;
Rob Landleyb73451d2006-02-24 16:29:00 +00001459 break;
1460 case 'K':
1461 absolute = 1024;
1462 break;
1463 case 'k':
1464 absolute = 1000;
1465 break;
1466 case 'm':
1467 case 'M':
1468 absolute = 1000000;
1469 break;
1470 case 'g':
1471 case 'G':
1472 absolute = 1000000000;
1473 break;
1474 default:
1475 break;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001476 }
Rob Landleyb73451d2006-02-24 16:29:00 +00001477 if (absolute) {
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00001478 ullong bytes;
Rob Landleyb73451d2006-02-24 16:29:00 +00001479 unsigned long unit;
1480
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00001481 bytes = (ullong) i * absolute;
Rob Landleyb73451d2006-02-24 16:29:00 +00001482 unit = sector_size * units_per_sector;
1483 bytes += unit/2; /* round */
1484 bytes /= unit;
1485 i = bytes;
1486 }
1487 if (minus)
1488 i = -i;
1489 i += base;
Eric Andersen84bdea82004-05-19 10:49:17 +00001490 } else {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001491 i = atoi(line_ptr);
1492 while (isdigit(*line_ptr)) {
1493 line_ptr++;
1494 use_default = 0;
1495 }
1496 }
Denis Vlasenkobd852072007-03-19 14:43:38 +00001497 if (use_default) {
1498 i = dflt;
1499 printf("Using default value %u\n", i);
1500 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001501 if (i >= low && i <= high)
1502 break;
Denis Vlasenkobd852072007-03-19 14:43:38 +00001503 printf("Value is out of range\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001504 }
1505 return i;
1506}
1507
Rob Landleyb73451d2006-02-24 16:29:00 +00001508static int
1509get_partition(int warn, int max)
1510{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001511 struct pte *pe;
1512 int i;
1513
Denis Vlasenkobd852072007-03-19 14:43:38 +00001514 i = read_int(1, 0, max, 0, "Partition number") - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001515 pe = &ptes[i];
1516
1517 if (warn) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001518 if ((!LABEL_IS_SUN && !LABEL_IS_SGI && !pe->part_table->sys_ind)
1519 || (LABEL_IS_SUN && (!sunlabel->partitions[i].num_sectors || !sunlabel->infos[i].id))
1520 || (LABEL_IS_SGI && !sgi_get_num_sectors(i))
1521 ) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001522 printf("Warning: partition %d has empty type\n", i+1);
Rob Landley5527b912006-02-25 03:46:10 +00001523 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001524 }
1525 return i;
1526}
1527
1528static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001529get_existing_partition(int warn, int max)
1530{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001531 int pno = -1;
1532 int i;
1533
1534 for (i = 0; i < max; i++) {
1535 struct pte *pe = &ptes[i];
1536 struct partition *p = pe->part_table;
1537
1538 if (p && !is_cleared_partition(p)) {
1539 if (pno >= 0)
1540 goto not_unique;
1541 pno = i;
1542 }
1543 }
1544 if (pno >= 0) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001545 printf("Selected partition %d\n", pno+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001546 return pno;
1547 }
Denis Vlasenkobd852072007-03-19 14:43:38 +00001548 printf("No partition is defined yet!\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001549 return -1;
1550
1551 not_unique:
1552 return get_partition(warn, max);
1553}
1554
1555static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001556get_nonexisting_partition(int warn, int max)
1557{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001558 int pno = -1;
1559 int i;
1560
1561 for (i = 0; i < max; i++) {
1562 struct pte *pe = &ptes[i];
1563 struct partition *p = pe->part_table;
1564
1565 if (p && is_cleared_partition(p)) {
1566 if (pno >= 0)
1567 goto not_unique;
1568 pno = i;
1569 }
1570 }
1571 if (pno >= 0) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001572 printf("Selected partition %d\n", pno+1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001573 return pno;
1574 }
Denis Vlasenkobd852072007-03-19 14:43:38 +00001575 printf("All primary partitions have been defined already!\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001576 return -1;
1577
1578 not_unique:
1579 return get_partition(warn, max);
1580}
1581
1582
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001583static void
1584change_units(void)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001585{
1586 display_in_cyl_units = !display_in_cyl_units;
1587 update_units();
Denis Vlasenkobd852072007-03-19 14:43:38 +00001588 printf("Changing display/entry units to %s\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001589 str_units(PLURAL));
1590}
1591
1592static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001593toggle_active(int i)
1594{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001595 struct pte *pe = &ptes[i];
1596 struct partition *p = pe->part_table;
1597
Rob Landleyb73451d2006-02-24 16:29:00 +00001598 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
Denis Vlasenkobd852072007-03-19 14:43:38 +00001599 printf("WARNING: Partition %d is an extended partition\n", i + 1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001600 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
1601 pe->changed = 1;
1602}
1603
1604static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001605toggle_dos_compatibility_flag(void)
1606{
Denis Vlasenkocdf62772008-03-17 08:42:43 +00001607 dos_compatible_flag = 1 - dos_compatible_flag;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001608 if (dos_compatible_flag) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001609 sector_offset = g_sectors;
Denis Vlasenkobd852072007-03-19 14:43:38 +00001610 printf("DOS Compatibility flag is set\n");
1611 } else {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001612 sector_offset = 1;
Denis Vlasenkobd852072007-03-19 14:43:38 +00001613 printf("DOS Compatibility flag is not set\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001614 }
1615}
1616
1617static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001618delete_partition(int i)
1619{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001620 struct pte *pe = &ptes[i];
1621 struct partition *p = pe->part_table;
1622 struct partition *q = pe->ext_pointer;
1623
1624/* Note that for the fifth partition (i == 4) we don't actually
1625 * decrement partitions.
1626 */
1627
1628 if (warn_geometry())
1629 return; /* C/H/S not set */
1630 pe->changed = 1;
1631
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001632 if (LABEL_IS_SUN) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001633 sun_delete_partition(i);
1634 return;
1635 }
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001636 if (LABEL_IS_SGI) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001637 sgi_delete_partition(i);
1638 return;
1639 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001640
1641 if (i < 4) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001642 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001643 g_partitions = 4;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001644 ptes[ext_index].ext_pointer = NULL;
1645 extended_offset = 0;
1646 }
1647 clear_partition(p);
1648 return;
1649 }
1650
1651 if (!q->sys_ind && i > 4) {
1652 /* the last one in the chain - just delete */
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001653 --g_partitions;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001654 --i;
1655 clear_partition(ptes[i].ext_pointer);
1656 ptes[i].changed = 1;
1657 } else {
1658 /* not the last one - further ones will be moved down */
1659 if (i > 4) {
1660 /* delete this link in the chain */
1661 p = ptes[i-1].ext_pointer;
1662 *p = *q;
1663 set_start_sect(p, get_start_sect(q));
1664 set_nr_sects(p, get_nr_sects(q));
1665 ptes[i-1].changed = 1;
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001666 } else if (g_partitions > 5) { /* 5 will be moved to 4 */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001667 /* the first logical in a longer chain */
1668 pe = &ptes[5];
1669
1670 if (pe->part_table) /* prevent SEGFAULT */
1671 set_start_sect(pe->part_table,
Rob Landleyb73451d2006-02-24 16:29:00 +00001672 get_partition_start(pe) -
1673 extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001674 pe->offset = extended_offset;
1675 pe->changed = 1;
1676 }
1677
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001678 if (g_partitions > 5) {
1679 g_partitions--;
1680 while (i < g_partitions) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001681 ptes[i] = ptes[i+1];
1682 i++;
1683 }
1684 } else
1685 /* the only logical: clear only */
1686 clear_partition(ptes[i].part_table);
1687 }
1688}
1689
1690static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001691change_sysid(void)
1692{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001693 int i, sys, origsys;
1694 struct partition *p;
1695
Eric Andersen040f4402003-07-30 08:40:37 +00001696 /* If sgi_label then don't use get_existing_partition,
1697 let the user select a partition, since get_existing_partition()
1698 only works for Linux like partition tables. */
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001699 if (!LABEL_IS_SGI) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001700 i = get_existing_partition(0, g_partitions);
Eric Andersen040f4402003-07-30 08:40:37 +00001701 } else {
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001702 i = get_partition(0, g_partitions);
Eric Andersen040f4402003-07-30 08:40:37 +00001703 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001704 if (i == -1)
1705 return;
1706 p = ptes[i].part_table;
1707 origsys = sys = get_sysid(i);
1708
1709 /* if changing types T to 0 is allowed, then
1710 the reverse change must be allowed, too */
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001711 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN && !get_nr_sects(p)) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001712 printf("Partition %d does not exist yet!\n", i + 1);
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001713 return;
1714 }
1715 while (1) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001716 sys = read_hex(get_sys_types());
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001717
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001718 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001719 printf("Type 0 means free space to many systems\n"
Rob Landleyb73451d2006-02-24 16:29:00 +00001720 "(but not to Linux). Having partitions of\n"
Denis Vlasenkobd852072007-03-19 14:43:38 +00001721 "type 0 is probably unwise.\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001722 /* break; */
1723 }
1724
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001725 if (!LABEL_IS_SUN && !LABEL_IS_SGI) {
Rob Landleyb73451d2006-02-24 16:29:00 +00001726 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001727 printf("You cannot change a partition into"
1728 " an extended one or vice versa\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001729 break;
1730 }
1731 }
1732
1733 if (sys < 256) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001734#if ENABLE_FEATURE_SUN_LABEL
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001735 if (LABEL_IS_SUN && i == 2 && sys != SUN_WHOLE_DISK)
Denis Vlasenkobd852072007-03-19 14:43:38 +00001736 printf("Consider leaving partition 3 "
Rob Landleyb73451d2006-02-24 16:29:00 +00001737 "as Whole disk (5),\n"
1738 "as SunOS/Solaris expects it and "
Denis Vlasenkobd852072007-03-19 14:43:38 +00001739 "even Linux likes it\n\n");
1740#endif
1741#if ENABLE_FEATURE_SGI_LABEL
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001742 if (LABEL_IS_SGI &&
Rob Landley5527b912006-02-25 03:46:10 +00001743 (
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001744 (i == 10 && sys != SGI_ENTIRE_DISK) ||
Rob Landley5527b912006-02-25 03:46:10 +00001745 (i == 8 && sys != 0)
1746 )
Denis Vlasenkobd852072007-03-19 14:43:38 +00001747 ) {
1748 printf("Consider leaving partition 9 "
Rob Landleyb73451d2006-02-24 16:29:00 +00001749 "as volume header (0),\nand "
1750 "partition 11 as entire volume (6)"
Denis Vlasenkobd852072007-03-19 14:43:38 +00001751 "as IRIX expects it\n\n");
Rob Landley5527b912006-02-25 03:46:10 +00001752 }
Denis Vlasenkobd852072007-03-19 14:43:38 +00001753#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001754 if (sys == origsys)
1755 break;
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001756 if (LABEL_IS_SUN) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001757 sun_change_sysid(i, sys);
Denis Vlasenko98ae2162006-10-12 19:30:44 +00001758 } else if (LABEL_IS_SGI) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001759 sgi_change_sysid(i, sys);
1760 } else
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001761 p->sys_ind = sys;
Rob Landley5527b912006-02-25 03:46:10 +00001762
Denis Vlasenkobd852072007-03-19 14:43:38 +00001763 printf("Changed system type of partition %d "
1764 "to %x (%s)\n", i + 1, sys,
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001765 partition_type(sys));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001766 ptes[i].changed = 1;
Denis Vlasenkoa5549c92008-01-24 22:49:15 +00001767 //if (is_dos_partition(origsys) || is_dos_partition(sys))
1768 // dos_changed = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001769 break;
1770 }
1771 }
1772}
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +00001773#endif /* FEATURE_FDISK_WRITABLE */
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00001774
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001775
Denis Vlasenko28703012006-12-19 20:32:02 +00001776/* check_consistency() and linear2chs() added Sat Mar 6 12:28:16 1993,
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001777 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
1778 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
1779 * Lubkin Oct. 1991). */
1780
Rob Landleyb73451d2006-02-24 16:29:00 +00001781static void
Denis Vlasenko28703012006-12-19 20:32:02 +00001782linear2chs(unsigned ls, unsigned *c, unsigned *h, unsigned *s)
Rob Landleyb73451d2006-02-24 16:29:00 +00001783{
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001784 int spc = g_heads * g_sectors;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001785
1786 *c = ls / spc;
1787 ls = ls % spc;
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001788 *h = ls / g_sectors;
1789 *s = ls % g_sectors + 1; /* sectors count from 1 */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001790}
1791
Rob Landleyb73451d2006-02-24 16:29:00 +00001792static void
1793check_consistency(const struct partition *p, int partition)
1794{
Denis Vlasenko834410a2006-11-29 12:00:28 +00001795 unsigned pbc, pbh, pbs; /* physical beginning c, h, s */
1796 unsigned pec, peh, pes; /* physical ending c, h, s */
1797 unsigned lbc, lbh, lbs; /* logical beginning c, h, s */
1798 unsigned lec, leh, les; /* logical ending c, h, s */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001799
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001800 if (!g_heads || !g_sectors || (partition >= 4))
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001801 return; /* do not check extended partitions */
1802
1803/* physical beginning c, h, s */
1804 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
1805 pbh = p->head;
1806 pbs = p->sector & 0x3f;
1807
1808/* physical ending c, h, s */
1809 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
1810 peh = p->end_head;
1811 pes = p->end_sector & 0x3f;
1812
1813/* compute logical beginning (c, h, s) */
Denis Vlasenko28703012006-12-19 20:32:02 +00001814 linear2chs(get_start_sect(p), &lbc, &lbh, &lbs);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001815
1816/* compute logical ending (c, h, s) */
Denis Vlasenko28703012006-12-19 20:32:02 +00001817 linear2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001818
1819/* Same physical / logical beginning? */
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001820 if (g_cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001821 printf("Partition %d has different physical/logical "
1822 "beginnings (non-Linux?):\n", partition + 1);
1823 printf(" phys=(%d, %d, %d) ", pbc, pbh, pbs);
Denis Vlasenkof5d8c902008-06-26 14:32:57 +00001824 printf("logical=(%d, %d, %d)\n", lbc, lbh, lbs);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001825 }
1826
1827/* Same physical / logical ending? */
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001828 if (g_cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001829 printf("Partition %d has different physical/logical "
1830 "endings:\n", partition + 1);
1831 printf(" phys=(%d, %d, %d) ", pec, peh, pes);
1832 printf("logical=(%d, %d, %d)\n", lec, leh, les);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001833 }
1834
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001835/* Ending on cylinder boundary? */
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001836 if (peh != (g_heads - 1) || pes != g_sectors) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001837 printf("Partition %i does not end on cylinder boundary\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001838 partition + 1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001839 }
1840}
1841
1842static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001843list_disk_geometry(void)
1844{
Eric Andersen040f4402003-07-30 08:40:37 +00001845 long long bytes = (total_number_of_sectors << 9);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001846 long megabytes = bytes/1000000;
1847
1848 if (megabytes < 10000)
Denis Vlasenkobd852072007-03-19 14:43:38 +00001849 printf("\nDisk %s: %ld MB, %lld bytes\n",
Rob Landleyb73451d2006-02-24 16:29:00 +00001850 disk_device, megabytes, bytes);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001851 else
Denis Vlasenkobd852072007-03-19 14:43:38 +00001852 printf("\nDisk %s: %ld.%ld GB, %lld bytes\n",
Rob Landleyb73451d2006-02-24 16:29:00 +00001853 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
Denis Vlasenkobd852072007-03-19 14:43:38 +00001854 printf("%d heads, %d sectors/track, %d cylinders",
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001855 g_heads, g_sectors, g_cylinders);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001856 if (units_per_sector == 1)
Denis Vlasenkobd852072007-03-19 14:43:38 +00001857 printf(", total %llu sectors",
Rob Landleyb73451d2006-02-24 16:29:00 +00001858 total_number_of_sectors / (sector_size/512));
Denis Vlasenkobd852072007-03-19 14:43:38 +00001859 printf("\nUnits = %s of %d * %d = %d bytes\n\n",
Rob Landleyb73451d2006-02-24 16:29:00 +00001860 str_units(PLURAL),
1861 units_per_sector, sector_size, units_per_sector * sector_size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001862}
1863
1864/*
1865 * Check whether partition entries are ordered by their starting positions.
1866 * Return 0 if OK. Return i if partition i should have been earlier.
1867 * Two separate checks: primary and logical partitions.
1868 */
1869static int
Rob Landleyb73451d2006-02-24 16:29:00 +00001870wrong_p_order(int *prev)
1871{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001872 const struct pte *pe;
1873 const struct partition *p;
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00001874 ullong last_p_start_pos = 0, p_start_pos;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001875 int i, last_i = 0;
1876
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001877 for (i = 0; i < g_partitions; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001878 if (i == 4) {
1879 last_i = 4;
1880 last_p_start_pos = 0;
1881 }
1882 pe = &ptes[i];
Denis Vlasenko6bef3d12007-11-06 03:05:54 +00001883 p = pe->part_table;
1884 if (p->sys_ind) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001885 p_start_pos = get_partition_start(pe);
1886
1887 if (last_p_start_pos > p_start_pos) {
1888 if (prev)
1889 *prev = last_i;
1890 return i;
1891 }
1892
1893 last_p_start_pos = p_start_pos;
1894 last_i = i;
1895 }
1896 }
1897 return 0;
1898}
1899
Denis Vlasenko834410a2006-11-29 12:00:28 +00001900#if ENABLE_FEATURE_FDISK_ADVANCED
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001901/*
1902 * Fix the chain of logicals.
1903 * extended_offset is unchanged, the set of sectors used is unchanged
1904 * The chain is sorted so that sectors increase, and so that
1905 * starting sectors increase.
1906 *
1907 * After this it may still be that cfdisk doesnt like the table.
1908 * (This is because cfdisk considers expanded parts, from link to
1909 * end of partition, and these may still overlap.)
1910 * Now
1911 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
1912 * may help.
1913 */
1914static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001915fix_chain_of_logicals(void)
1916{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001917 int j, oj, ojj, sj, sjj;
1918 struct partition *pj,*pjj,tmp;
1919
1920 /* Stage 1: sort sectors but leave sector of part 4 */
1921 /* (Its sector is the global extended_offset.) */
1922 stage1:
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001923 for (j = 5; j < g_partitions - 1; j++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001924 oj = ptes[j].offset;
1925 ojj = ptes[j+1].offset;
1926 if (oj > ojj) {
1927 ptes[j].offset = ojj;
1928 ptes[j+1].offset = oj;
1929 pj = ptes[j].part_table;
1930 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
1931 pjj = ptes[j+1].part_table;
1932 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
1933 set_start_sect(ptes[j-1].ext_pointer,
Rob Landleyb73451d2006-02-24 16:29:00 +00001934 ojj-extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001935 set_start_sect(ptes[j].ext_pointer,
Rob Landleyb73451d2006-02-24 16:29:00 +00001936 oj-extended_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001937 goto stage1;
1938 }
1939 }
1940
1941 /* Stage 2: sort starting sectors */
1942 stage2:
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001943 for (j = 4; j < g_partitions - 1; j++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001944 pj = ptes[j].part_table;
1945 pjj = ptes[j+1].part_table;
1946 sj = get_start_sect(pj);
1947 sjj = get_start_sect(pjj);
1948 oj = ptes[j].offset;
1949 ojj = ptes[j+1].offset;
1950 if (oj+sj > ojj+sjj) {
1951 tmp = *pj;
1952 *pj = *pjj;
1953 *pjj = tmp;
1954 set_start_sect(pj, ojj+sjj-oj);
1955 set_start_sect(pjj, oj+sj-ojj);
1956 goto stage2;
1957 }
1958 }
1959
1960 /* Probably something was changed */
Denis Vlasenkof77f3692007-12-16 17:22:33 +00001961 for (j = 4; j < g_partitions; j++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001962 ptes[j].changed = 1;
1963}
1964
1965
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001966static void
Rob Landleyb73451d2006-02-24 16:29:00 +00001967fix_partition_table_order(void)
1968{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001969 struct pte *pei, *pek;
1970 int i,k;
1971
1972 if (!wrong_p_order(NULL)) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00001973 printf("Ordering is already correct\n\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00001974 return;
1975 }
1976
1977 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
1978 /* partition i should have come earlier, move it */
1979 /* We have to move data in the MBR */
1980 struct partition *pi, *pk, *pe, pbuf;
1981 pei = &ptes[i];
1982 pek = &ptes[k];
1983
1984 pe = pei->ext_pointer;
1985 pei->ext_pointer = pek->ext_pointer;
1986 pek->ext_pointer = pe;
1987
1988 pi = pei->part_table;
1989 pk = pek->part_table;
1990
1991 memmove(&pbuf, pi, sizeof(struct partition));
1992 memmove(pi, pk, sizeof(struct partition));
1993 memmove(pk, &pbuf, sizeof(struct partition));
1994
1995 pei->changed = pek->changed = 1;
1996 }
1997
1998 if (i)
1999 fix_chain_of_logicals();
2000
2001 printf("Done.\n");
2002
2003}
2004#endif
2005
2006static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002007list_table(int xtra)
2008{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002009 const struct partition *p;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002010 int i, w;
2011
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002012 if (LABEL_IS_SUN) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002013 sun_list_table(xtra);
2014 return;
2015 }
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002016 if (LABEL_IS_SUN) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002017 sgi_list_table(xtra);
2018 return;
2019 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002020
2021 list_disk_geometry();
2022
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002023 if (LABEL_IS_OSF) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002024 xbsd_print_disklabel(xtra);
2025 return;
2026 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002027
2028 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
2029 but if the device name ends in a digit, say /dev/foo1,
2030 then the partition is called /dev/foo1p3. */
2031 w = strlen(disk_device);
2032 if (w && isdigit(disk_device[w-1]))
2033 w++;
2034 if (w < 5)
2035 w = 5;
2036
Denis Vlasenkobd852072007-03-19 14:43:38 +00002037 // 1 12345678901 12345678901 12345678901 12
2038 printf("%*s Boot Start End Blocks Id System\n",
2039 w+1, "Device");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002040
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002041 for (i = 0; i < g_partitions; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002042 const struct pte *pe = &ptes[i];
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00002043 ullong psects;
2044 ullong pblocks;
Denis Vlasenko834410a2006-11-29 12:00:28 +00002045 unsigned podd;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002046
2047 p = pe->part_table;
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002048 if (!p || is_cleared_partition(p))
2049 continue;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002050
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002051 psects = get_nr_sects(p);
2052 pblocks = psects;
2053 podd = 0;
2054
2055 if (sector_size < 1024) {
2056 pblocks /= (1024 / sector_size);
2057 podd = psects % (1024 / sector_size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002058 }
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002059 if (sector_size > 1024)
2060 pblocks *= (sector_size / 1024);
2061
2062 printf("%s %c %11llu %11llu %11llu%c %2x %s\n",
2063 partname(disk_device, i+1, w+2),
2064 !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG /* boot flag */
2065 ? '*' : '?',
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00002066 (ullong) cround(get_partition_start(pe)), /* start */
2067 (ullong) cround(get_partition_start(pe) + psects /* end */
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002068 - (psects ? 1 : 0)),
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00002069 (ullong) pblocks, podd ? '+' : ' ', /* odd flag on end */
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002070 p->sys_ind, /* type id */
2071 partition_type(p->sys_ind)); /* type name */
2072
2073 check_consistency(p, i);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002074 }
2075
2076 /* Is partition table in disk order? It need not be, but... */
2077 /* partition table entries are not checked for correct order if this
2078 is a sgi, sun or aix labeled disk... */
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002079 if (LABEL_IS_DOS && wrong_p_order(NULL)) {
Rob Landley5527b912006-02-25 03:46:10 +00002080 /* FIXME */
Denis Vlasenkobd852072007-03-19 14:43:38 +00002081 printf("\nPartition table entries are not in disk order\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002082 }
2083}
2084
Denis Vlasenko834410a2006-11-29 12:00:28 +00002085#if ENABLE_FEATURE_FDISK_ADVANCED
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002086static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002087x_list_table(int extend)
2088{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002089 const struct pte *pe;
2090 const struct partition *p;
2091 int i;
2092
Denis Vlasenkobd852072007-03-19 14:43:38 +00002093 printf("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n",
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002094 disk_device, g_heads, g_sectors, g_cylinders);
Denis Vlasenkobd852072007-03-19 14:43:38 +00002095 printf("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n");
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002096 for (i = 0; i < g_partitions; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002097 pe = &ptes[i];
2098 p = (extend ? pe->ext_pointer : pe->part_table);
2099 if (p != NULL) {
Eric Andersen040f4402003-07-30 08:40:37 +00002100 printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002101 i + 1, p->boot_ind, p->head,
2102 sector(p->sector),
2103 cylinder(p->sector, p->cyl), p->end_head,
2104 sector(p->end_sector),
2105 cylinder(p->end_sector, p->end_cyl),
2106 get_start_sect(p), get_nr_sects(p), p->sys_ind);
2107 if (p->sys_ind)
2108 check_consistency(p, i);
2109 }
2110 }
2111}
2112#endif
2113
Denis Vlasenko834410a2006-11-29 12:00:28 +00002114#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002115static void
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00002116fill_bounds(ullong *first, ullong *last)
Rob Landleyb73451d2006-02-24 16:29:00 +00002117{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002118 int i;
2119 const struct pte *pe = &ptes[0];
2120 const struct partition *p;
2121
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002122 for (i = 0; i < g_partitions; pe++,i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002123 p = pe->part_table;
Rob Landleyb73451d2006-02-24 16:29:00 +00002124 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002125 first[i] = 0xffffffff;
2126 last[i] = 0;
2127 } else {
2128 first[i] = get_partition_start(pe);
2129 last[i] = first[i] + get_nr_sects(p) - 1;
2130 }
2131 }
2132}
2133
2134static void
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00002135check(int n, unsigned h, unsigned s, unsigned c, ullong start)
Rob Landleyb73451d2006-02-24 16:29:00 +00002136{
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00002137 ullong total, real_s, real_c;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002138
2139 real_s = sector(s) - 1;
2140 real_c = cylinder(s, c);
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002141 total = (real_c * g_sectors + real_s) * g_heads + h;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002142 if (!total)
Denis Vlasenkobd852072007-03-19 14:43:38 +00002143 printf("Partition %d contains sector 0\n", n);
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002144 if (h >= g_heads)
Denis Vlasenkobd852072007-03-19 14:43:38 +00002145 printf("Partition %d: head %d greater than maximum %d\n",
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002146 n, h + 1, g_heads);
2147 if (real_s >= g_sectors)
Denis Vlasenkobd852072007-03-19 14:43:38 +00002148 printf("Partition %d: sector %d greater than "
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002149 "maximum %d\n", n, s, g_sectors);
2150 if (real_c >= g_cylinders)
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00002151 printf("Partition %d: cylinder %llu greater than "
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002152 "maximum %d\n", n, real_c + 1, g_cylinders);
2153 if (g_cylinders <= 1024 && start != total)
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00002154 printf("Partition %d: previous sectors %llu disagrees with "
2155 "total %llu\n", n, start, total);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002156}
2157
2158static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002159verify(void)
2160{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002161 int i, j;
Denis Vlasenko834410a2006-11-29 12:00:28 +00002162 unsigned total = 1;
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002163 ullong first[g_partitions], last[g_partitions];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002164 struct partition *p;
2165
2166 if (warn_geometry())
2167 return;
2168
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002169 if (LABEL_IS_SUN) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002170 verify_sun();
2171 return;
2172 }
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002173 if (LABEL_IS_SGI) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002174 verify_sgi(1);
2175 return;
2176 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002177
2178 fill_bounds(first, last);
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002179 for (i = 0; i < g_partitions; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002180 struct pte *pe = &ptes[i];
2181
2182 p = pe->part_table;
Rob Landleyb73451d2006-02-24 16:29:00 +00002183 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002184 check_consistency(p, i);
2185 if (get_partition_start(pe) < first[i])
Denis Vlasenkobd852072007-03-19 14:43:38 +00002186 printf("Warning: bad start-of-data in "
2187 "partition %d\n", i + 1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002188 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
2189 last[i]);
2190 total += last[i] + 1 - first[i];
Denis Vlasenkobd852072007-03-19 14:43:38 +00002191 for (j = 0; j < i; j++) {
2192 if ((first[i] >= first[j] && first[i] <= last[j])
2193 || ((last[i] <= last[j] && last[i] >= first[j]))) {
2194 printf("Warning: partition %d overlaps "
2195 "partition %d\n", j + 1, i + 1);
2196 total += first[i] >= first[j] ?
2197 first[i] : first[j];
2198 total -= last[i] <= last[j] ?
2199 last[i] : last[j];
2200 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002201 }
2202 }
2203 }
2204
2205 if (extended_offset) {
2206 struct pte *pex = &ptes[ext_index];
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00002207 ullong e_last = get_start_sect(pex->part_table) +
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002208 get_nr_sects(pex->part_table) - 1;
2209
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002210 for (i = 4; i < g_partitions; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002211 total++;
2212 p = ptes[i].part_table;
2213 if (!p->sys_ind) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002214 if (i != 4 || i + 1 < g_partitions)
Denis Vlasenkobd852072007-03-19 14:43:38 +00002215 printf("Warning: partition %d "
2216 "is empty\n", i + 1);
2217 } else if (first[i] < extended_offset || last[i] > e_last) {
2218 printf("Logical partition %d not entirely in "
2219 "partition %d\n", i + 1, ext_index + 1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002220 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002221 }
2222 }
2223
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002224 if (total > g_heads * g_sectors * g_cylinders)
Denis Vlasenkobd852072007-03-19 14:43:38 +00002225 printf("Total allocated sectors %d greater than the maximum "
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002226 "%d\n", total, g_heads * g_sectors * g_cylinders);
Denis Vlasenkobd852072007-03-19 14:43:38 +00002227 else {
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002228 total = g_heads * g_sectors * g_cylinders - total;
Denis Vlasenkobd852072007-03-19 14:43:38 +00002229 if (total != 0)
2230 printf("%d unallocated sectors\n", total);
2231 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002232}
2233
2234static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002235add_partition(int n, int sys)
2236{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002237 char mesg[256]; /* 48 does not suffice in Japanese */
Mike Frysingerfa6c4842006-05-26 01:48:17 +00002238 int i, num_read = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002239 struct partition *p = ptes[n].part_table;
2240 struct partition *q = ptes[ext_index].part_table;
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00002241 ullong limit, temp;
2242 ullong start, stop = 0;
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002243 ullong first[g_partitions], last[g_partitions];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002244
2245 if (p && p->sys_ind) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00002246 printf(msg_part_already_defined, n + 1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002247 return;
2248 }
2249 fill_bounds(first, last);
2250 if (n < 4) {
2251 start = sector_offset;
Eric Andersen040f4402003-07-30 08:40:37 +00002252 if (display_in_cyl_units || !total_number_of_sectors)
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002253 limit = (ullong) g_heads * g_sectors * g_cylinders - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002254 else
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00002255 limit = total_number_of_sectors - 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002256 if (extended_offset) {
2257 first[ext_index] = extended_offset;
2258 last[ext_index] = get_start_sect(q) +
2259 get_nr_sects(q) - 1;
2260 }
2261 } else {
2262 start = extended_offset + sector_offset;
2263 limit = get_start_sect(q) + get_nr_sects(q) - 1;
2264 }
2265 if (display_in_cyl_units)
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002266 for (i = 0; i < g_partitions; i++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002267 first[i] = (cround(first[i]) - 1) * units_per_sector;
2268
Denis Vlasenkobd852072007-03-19 14:43:38 +00002269 snprintf(mesg, sizeof(mesg), "First %s", str_units(SINGULAR));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002270 do {
2271 temp = start;
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002272 for (i = 0; i < g_partitions; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002273 int lastplusoff;
2274
2275 if (start == ptes[i].offset)
2276 start += sector_offset;
Rob Landleyb73451d2006-02-24 16:29:00 +00002277 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002278 if (start >= first[i] && start <= lastplusoff)
2279 start = lastplusoff + 1;
2280 }
2281 if (start > limit)
2282 break;
Mike Frysingerfa6c4842006-05-26 01:48:17 +00002283 if (start >= temp+units_per_sector && num_read) {
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00002284 printf("Sector %lld is already allocated\n", temp);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002285 temp = start;
Mike Frysingerfa6c4842006-05-26 01:48:17 +00002286 num_read = 0;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002287 }
Mike Frysingerfa6c4842006-05-26 01:48:17 +00002288 if (!num_read && start == temp) {
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00002289 ullong saved_start;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002290
2291 saved_start = start;
2292 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
2293 0, mesg);
2294 if (display_in_cyl_units) {
2295 start = (start - 1) * units_per_sector;
2296 if (start < saved_start) start = saved_start;
2297 }
Mike Frysingerfa6c4842006-05-26 01:48:17 +00002298 num_read = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002299 }
Mike Frysingerfa6c4842006-05-26 01:48:17 +00002300 } while (start != temp || !num_read);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002301 if (n > 4) { /* NOT for fifth partition */
2302 struct pte *pe = &ptes[n];
2303
2304 pe->offset = start - sector_offset;
2305 if (pe->offset == extended_offset) { /* must be corrected */
2306 pe->offset++;
2307 if (sector_offset == 1)
2308 start++;
2309 }
2310 }
2311
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002312 for (i = 0; i < g_partitions; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002313 struct pte *pe = &ptes[i];
2314
2315 if (start < pe->offset && limit >= pe->offset)
2316 limit = pe->offset - 1;
2317 if (start < first[i] && limit >= first[i])
2318 limit = first[i] - 1;
2319 }
2320 if (start > limit) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00002321 printf("No free sectors available\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002322 if (n > 4)
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002323 g_partitions--;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002324 return;
2325 }
2326 if (cround(start) == cround(limit)) {
2327 stop = limit;
2328 } else {
2329 snprintf(mesg, sizeof(mesg),
Denis Vlasenkobd852072007-03-19 14:43:38 +00002330 "Last %s or +size or +sizeM or +sizeK",
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002331 str_units(SINGULAR));
2332 stop = read_int(cround(start), cround(limit), cround(limit),
2333 cround(start), mesg);
2334 if (display_in_cyl_units) {
2335 stop = stop * units_per_sector - 1;
2336 if (stop >limit)
2337 stop = limit;
2338 }
2339 }
2340
2341 set_partition(n, 0, start, stop, sys);
2342 if (n > 4)
2343 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
2344
Rob Landleyb73451d2006-02-24 16:29:00 +00002345 if (IS_EXTENDED(sys)) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002346 struct pte *pe4 = &ptes[4];
2347 struct pte *pen = &ptes[n];
2348
2349 ext_index = n;
2350 pen->ext_pointer = p;
2351 pe4->offset = extended_offset = start;
Rob Landley081e3842006-08-03 20:07:35 +00002352 pe4->sectorbuffer = xzalloc(sector_size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002353 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
2354 pe4->ext_pointer = pe4->part_table + 1;
2355 pe4->changed = 1;
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002356 g_partitions = 5;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002357 }
2358}
2359
2360static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002361add_logical(void)
2362{
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002363 if (g_partitions > 5 || ptes[4].part_table->sys_ind) {
2364 struct pte *pe = &ptes[g_partitions];
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002365
Rob Landley081e3842006-08-03 20:07:35 +00002366 pe->sectorbuffer = xzalloc(sector_size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002367 pe->part_table = pt_offset(pe->sectorbuffer, 0);
2368 pe->ext_pointer = pe->part_table + 1;
2369 pe->offset = 0;
2370 pe->changed = 1;
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002371 g_partitions++;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002372 }
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002373 add_partition(g_partitions - 1, LINUX_NATIVE);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002374}
2375
2376static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002377new_partition(void)
2378{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002379 int i, free_primary = 0;
2380
2381 if (warn_geometry())
2382 return;
2383
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002384 if (LABEL_IS_SUN) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002385 add_sun_partition(get_partition(0, g_partitions), LINUX_NATIVE);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002386 return;
2387 }
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002388 if (LABEL_IS_SGI) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002389 sgi_add_partition(get_partition(0, g_partitions), LINUX_NATIVE);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002390 return;
2391 }
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002392 if (LABEL_IS_AIX) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00002393 printf("Sorry - this fdisk cannot handle AIX disk labels.\n"
2394"If you want to add DOS-type partitions, create a new empty DOS partition\n"
2395"table first (use 'o'). This will destroy the present disk contents.\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002396 return;
2397 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002398
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002399 for (i = 0; i < 4; i++)
2400 free_primary += !ptes[i].part_table->sys_ind;
Eric Andersenc48d49a2003-07-03 10:02:32 +00002401
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002402 if (!free_primary && g_partitions >= MAXIMUM_PARTS) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00002403 printf("The maximum number of partitions has been created\n");
Eric Andersen84bdea82004-05-19 10:49:17 +00002404 return;
Rob Landleyb73451d2006-02-24 16:29:00 +00002405 }
Eric Andersenc48d49a2003-07-03 10:02:32 +00002406
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002407 if (!free_primary) {
2408 if (extended_offset)
2409 add_logical();
2410 else
Denis Vlasenkobd852072007-03-19 14:43:38 +00002411 printf("You must delete some partition and add "
2412 "an extended partition first\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002413 } else {
Denis Vlasenkodfce08f2007-03-19 14:45:10 +00002414 char c, line[80];
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00002415 snprintf(line, sizeof(line),
2416 "Command action\n"
2417 " %s\n"
2418 " p primary partition (1-4)\n",
2419 (extended_offset ?
2420 "l logical (5 or over)" : "e extended"));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002421 while (1) {
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002422 c = read_nonempty(line);
2423 if (c == 'p' || c == 'P') {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002424 i = get_nonexisting_partition(0, 4);
2425 if (i >= 0)
2426 add_partition(i, LINUX_NATIVE);
2427 return;
2428 }
Denis Vlasenkobd852072007-03-19 14:43:38 +00002429 if (c == 'l' && extended_offset) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002430 add_logical();
2431 return;
2432 }
Denis Vlasenkobd852072007-03-19 14:43:38 +00002433 if (c == 'e' && !extended_offset) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002434 i = get_nonexisting_partition(0, 4);
2435 if (i >= 0)
2436 add_partition(i, EXTENDED);
2437 return;
2438 }
Denis Vlasenkobd852072007-03-19 14:43:38 +00002439 printf("Invalid partition number "
2440 "for type '%c'\n", c);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002441 }
2442 }
2443}
2444
2445static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002446write_table(void)
2447{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002448 int i;
2449
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002450 if (LABEL_IS_DOS) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002451 for (i = 0; i < 3; i++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002452 if (ptes[i].changed)
2453 ptes[3].changed = 1;
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002454 for (i = 3; i < g_partitions; i++) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002455 struct pte *pe = &ptes[i];
2456
2457 if (pe->changed) {
2458 write_part_table_flag(pe->sectorbuffer);
2459 write_sector(pe->offset, pe->sectorbuffer);
2460 }
2461 }
2462 }
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002463 else if (LABEL_IS_SGI) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002464 /* no test on change? the printf below might be mistaken */
2465 sgi_write_table();
2466 }
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002467 else if (LABEL_IS_SUN) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002468 int needw = 0;
2469
Rob Landleyb73451d2006-02-24 16:29:00 +00002470 for (i = 0; i < 8; i++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002471 if (ptes[i].changed)
2472 needw = 1;
2473 if (needw)
2474 sun_write_table();
2475 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002476
Denis Vlasenkobd852072007-03-19 14:43:38 +00002477 printf("The partition table has been altered!\n\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002478 reread_partition_table(1);
2479}
2480
Rob Landleyb73451d2006-02-24 16:29:00 +00002481static void
2482reread_partition_table(int leave)
2483{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002484 int i;
2485
Denis Vlasenkobd852072007-03-19 14:43:38 +00002486 printf("Calling ioctl() to re-read partition table\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002487 sync();
Denis Vlasenkobd852072007-03-19 14:43:38 +00002488 /* sleep(2); Huh? */
Denis Vlasenko4437d192008-04-17 00:12:10 +00002489 i = ioctl_or_perror(dev_fd, BLKRRPART, NULL,
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +00002490 "WARNING: rereading partition table "
Denis Vlasenko28703012006-12-19 20:32:02 +00002491 "failed, kernel still uses old table");
Denis Vlasenko28703012006-12-19 20:32:02 +00002492#if 0
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002493 if (dos_changed)
Rob Landleyb73451d2006-02-24 16:29:00 +00002494 printf(
Denis Vlasenkobd852072007-03-19 14:43:38 +00002495 "\nWARNING: If you have created or modified any DOS 6.x\n"
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002496 "partitions, please see the fdisk manual page for additional\n"
Denis Vlasenkobd852072007-03-19 14:43:38 +00002497 "information\n");
Denis Vlasenko28703012006-12-19 20:32:02 +00002498#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002499
2500 if (leave) {
Denis Vlasenko28703012006-12-19 20:32:02 +00002501 if (ENABLE_FEATURE_CLEAN_UP)
Denis Vlasenkoc033d512008-04-17 01:52:28 +00002502 close_dev_fd();
Denis Vlasenko28703012006-12-19 20:32:02 +00002503 exit(i != 0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002504 }
2505}
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +00002506#endif /* FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002507
Denis Vlasenko834410a2006-11-29 12:00:28 +00002508#if ENABLE_FEATURE_FDISK_ADVANCED
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002509#define MAX_PER_LINE 16
2510static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002511print_buffer(char *pbuffer)
2512{
2513 int i,l;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002514
2515 for (i = 0, l = 0; i < sector_size; i++, l++) {
2516 if (l == 0)
2517 printf("0x%03X:", i);
2518 printf(" %02X", (unsigned char) pbuffer[i]);
2519 if (l == MAX_PER_LINE - 1) {
Denis Vlasenko4daad902007-09-27 10:20:47 +00002520 bb_putchar('\n');
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002521 l = -1;
2522 }
2523 }
2524 if (l > 0)
Denis Vlasenko4daad902007-09-27 10:20:47 +00002525 bb_putchar('\n');
2526 bb_putchar('\n');
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002527}
2528
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002529static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002530print_raw(void)
2531{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002532 int i;
2533
Denis Vlasenkobd852072007-03-19 14:43:38 +00002534 printf("Device: %s\n", disk_device);
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002535 if (LABEL_IS_SGI || LABEL_IS_SUN)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002536 print_buffer(MBRbuffer);
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002537 else {
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002538 for (i = 3; i < g_partitions; i++)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002539 print_buffer(ptes[i].sectorbuffer);
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002540 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002541}
2542
2543static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002544move_begin(int i)
2545{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002546 struct pte *pe = &ptes[i];
2547 struct partition *p = pe->part_table;
Denis Vlasenko3f22b7f2007-06-02 12:46:55 +00002548 ullong new, first;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002549
2550 if (warn_geometry())
2551 return;
Rob Landleyb73451d2006-02-24 16:29:00 +00002552 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED(p->sys_ind)) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00002553 printf("Partition %d has no data area\n", i + 1);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002554 return;
2555 }
2556 first = get_partition_start(pe);
2557 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
Denis Vlasenkobd852072007-03-19 14:43:38 +00002558 "New beginning of data") - pe->offset;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002559
2560 if (new != get_nr_sects(p)) {
2561 first = get_nr_sects(p) + get_start_sect(p) - new;
2562 set_nr_sects(p, first);
2563 set_start_sect(p, new);
2564 pe->changed = 1;
2565 }
2566}
2567
2568static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002569xselect(void)
2570{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002571 char c;
2572
Rob Landleyb73451d2006-02-24 16:29:00 +00002573 while (1) {
Denis Vlasenko4daad902007-09-27 10:20:47 +00002574 bb_putchar('\n');
Denis Vlasenkobd852072007-03-19 14:43:38 +00002575 c = tolower(read_nonempty("Expert command (m for help): "));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002576 switch (c) {
2577 case 'a':
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002578 if (LABEL_IS_SUN)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002579 sun_set_alt_cyl();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002580 break;
2581 case 'b':
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002582 if (LABEL_IS_DOS)
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002583 move_begin(get_partition(0, g_partitions));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002584 break;
2585 case 'c':
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002586 user_cylinders = g_cylinders =
2587 read_int(1, g_cylinders, 1048576, 0,
Denis Vlasenkobd852072007-03-19 14:43:38 +00002588 "Number of cylinders");
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002589 if (LABEL_IS_SUN)
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002590 sun_set_ncyl(g_cylinders);
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002591 if (LABEL_IS_DOS)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002592 warn_cylinders();
2593 break;
2594 case 'd':
2595 print_raw();
2596 break;
2597 case 'e':
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002598 if (LABEL_IS_SGI)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002599 sgi_set_xcyl();
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002600 else if (LABEL_IS_SUN)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002601 sun_set_xcyl();
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002602 else if (LABEL_IS_DOS)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002603 x_list_table(1);
2604 break;
2605 case 'f':
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002606 if (LABEL_IS_DOS)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002607 fix_partition_table_order();
2608 break;
2609 case 'g':
Denis Vlasenko834410a2006-11-29 12:00:28 +00002610#if ENABLE_FEATURE_SGI_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002611 create_sgilabel();
2612#endif
2613 break;
2614 case 'h':
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002615 user_heads = g_heads = read_int(1, g_heads, 256, 0,
Denis Vlasenkobd852072007-03-19 14:43:38 +00002616 "Number of heads");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002617 update_units();
2618 break;
2619 case 'i':
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002620 if (LABEL_IS_SUN)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002621 sun_set_ilfact();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002622 break;
2623 case 'o':
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002624 if (LABEL_IS_SUN)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002625 sun_set_rspeed();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002626 break;
2627 case 'p':
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002628 if (LABEL_IS_SUN)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002629 list_table(1);
2630 else
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002631 x_list_table(0);
2632 break;
2633 case 'q':
Denis Vlasenko4437d192008-04-17 00:12:10 +00002634 if (ENABLE_FEATURE_CLEAN_UP)
Denis Vlasenkoc033d512008-04-17 01:52:28 +00002635 close_dev_fd();
Denis Vlasenko4daad902007-09-27 10:20:47 +00002636 bb_putchar('\n');
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00002637 exit(EXIT_SUCCESS);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002638 case 'r':
2639 return;
2640 case 's':
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002641 user_sectors = g_sectors = read_int(1, g_sectors, 63, 0,
Denis Vlasenkobd852072007-03-19 14:43:38 +00002642 "Number of sectors");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002643 if (dos_compatible_flag) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002644 sector_offset = g_sectors;
Denis Vlasenkobd852072007-03-19 14:43:38 +00002645 printf("Warning: setting sector offset for DOS "
2646 "compatiblity\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002647 }
2648 update_units();
2649 break;
2650 case 'v':
2651 verify();
2652 break;
2653 case 'w':
2654 write_table(); /* does not return */
2655 break;
2656 case 'y':
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002657 if (LABEL_IS_SUN)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002658 sun_set_pcylcount();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002659 break;
2660 default:
2661 xmenu();
2662 }
2663 }
2664}
2665#endif /* ADVANCED mode */
2666
2667static int
Rob Landleyb73451d2006-02-24 16:29:00 +00002668is_ide_cdrom_or_tape(const char *device)
2669{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002670 FILE *procf;
2671 char buf[100];
2672 struct stat statbuf;
2673 int is_ide = 0;
2674
2675 /* No device was given explicitly, and we are trying some
2676 likely things. But opening /dev/hdc may produce errors like
2677 "hdc: tray open or drive not ready"
2678 if it happens to be a CD-ROM drive. It even happens that
2679 the process hangs on the attempt to read a music CD.
2680 So try to be careful. This only works since 2.1.73. */
2681
2682 if (strncmp("/dev/hd", device, 7))
2683 return 0;
2684
2685 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
2686 procf = fopen(buf, "r");
2687 if (procf != NULL && fgets(buf, sizeof(buf), procf))
2688 is_ide = (!strncmp(buf, "cdrom", 5) ||
2689 !strncmp(buf, "tape", 4));
2690 else
2691 /* Now when this proc file does not exist, skip the
2692 device when it is read-only. */
2693 if (stat(device, &statbuf) == 0)
2694 is_ide = ((statbuf.st_mode & 0222) == 0);
2695
2696 if (procf)
2697 fclose(procf);
2698 return is_ide;
2699}
2700
Rob Landley5527b912006-02-25 03:46:10 +00002701
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002702static void
Denis Vlasenko4437d192008-04-17 00:12:10 +00002703open_list_and_close(const char *device, int user_specified)
Rob Landleyb73451d2006-02-24 16:29:00 +00002704{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002705 int gb;
2706
2707 disk_device = device;
2708 if (setjmp(listingbuf))
2709 return;
2710 if (!user_specified)
2711 if (is_ide_cdrom_or_tape(device))
2712 return;
Denis Vlasenko4437d192008-04-17 00:12:10 +00002713
2714 /* Open disk_device, save file descriptor to dev_fd */
2715 errno = 0;
2716 gb = get_boot(TRY_ONLY);
2717 if (gb > 0) { /* I/O error */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002718 /* Ignore other errors, since we try IDE
2719 and SCSI hard disks which may not be
2720 installed on the system. */
Denis Vlasenko4437d192008-04-17 00:12:10 +00002721 if (user_specified || errno == EACCES)
2722 bb_perror_msg("can't open '%s'", device);
2723 return;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002724 }
Denis Vlasenko4437d192008-04-17 00:12:10 +00002725
2726 if (gb < 0) { /* no DOS signature */
2727 list_disk_geometry();
2728 if (LABEL_IS_AIX)
2729 goto ret;
2730#if ENABLE_FEATURE_OSF_LABEL
2731 if (bsd_trydev(device) < 0)
2732#endif
2733 printf("Disk %s doesn't contain a valid "
2734 "partition table\n", device);
2735 } else {
2736 list_table(0);
2737#if ENABLE_FEATURE_FDISK_WRITABLE
2738 if (!LABEL_IS_SUN && g_partitions > 4) {
2739 delete_partition(ext_index);
2740 }
2741#endif
2742 }
2743 ret:
Denis Vlasenkoc033d512008-04-17 01:52:28 +00002744 close_dev_fd();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002745}
2746
2747/* for fdisk -l: try all things in /proc/partitions
2748 that look like a partition name (do not end in a digit) */
2749static void
Denis Vlasenko4437d192008-04-17 00:12:10 +00002750list_devs_in_proc_partititons(void)
Rob Landleyb73451d2006-02-24 16:29:00 +00002751{
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002752 FILE *procpt;
2753 char line[100], ptname[100], devname[120], *s;
2754 int ma, mi, sz;
2755
Denis Vlasenkoddec5af2006-10-26 23:25:17 +00002756 procpt = fopen_or_warn("/proc/partitions", "r");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002757
2758 while (fgets(line, sizeof(line), procpt)) {
Rob Landleyb73451d2006-02-24 16:29:00 +00002759 if (sscanf(line, " %d %d %d %[^\n ]",
2760 &ma, &mi, &sz, ptname) != 4)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002761 continue;
Denis Vlasenkocdf62772008-03-17 08:42:43 +00002762 for (s = ptname; *s; s++)
2763 continue;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002764 if (isdigit(s[-1]))
2765 continue;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00002766 sprintf(devname, "/dev/%s", ptname);
Denis Vlasenko4437d192008-04-17 00:12:10 +00002767 open_list_and_close(devname, 0);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002768 }
Denis Vlasenko834410a2006-11-29 12:00:28 +00002769#if ENABLE_FEATURE_CLEAN_UP
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002770 fclose(procpt);
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00002771#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002772}
2773
Denis Vlasenko834410a2006-11-29 12:00:28 +00002774#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002775static void
Rob Landleyb73451d2006-02-24 16:29:00 +00002776unknown_command(int c)
2777{
Denis Vlasenkobd852072007-03-19 14:43:38 +00002778 printf("%c: unknown command\n", c);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002779}
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00002780#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002781
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00002782int fdisk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Rob Landleyb73451d2006-02-24 16:29:00 +00002783int fdisk_main(int argc, char **argv)
2784{
Denis Vlasenko834410a2006-11-29 12:00:28 +00002785 unsigned opt;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002786 /*
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002787 * fdisk -v
2788 * fdisk -l [-b sectorsize] [-u] device ...
2789 * fdisk -s [partition] ...
2790 * fdisk [-b sectorsize] [-u] device
2791 *
2792 * Options -C, -H, -S set the geometry.
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002793 */
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002794 INIT_G();
Denis Vlasenko8e1a0cc2007-03-18 14:42:45 +00002795
Denis Vlasenkoc033d512008-04-17 01:52:28 +00002796 close_dev_fd(); /* needed: fd 3 must not stay closed */
Denis Vlasenko4437d192008-04-17 00:12:10 +00002797
Denis Vlasenko04e11c92008-02-10 19:44:20 +00002798 opt_complementary = "b+:C+:H+:S+"; /* numeric params */
Denis Vlasenkofe7cd642007-08-18 15:32:12 +00002799 opt = getopt32(argv, "b:C:H:lS:u" USE_FEATURE_FDISK_BLKSIZE("s"),
Denis Vlasenko04e11c92008-02-10 19:44:20 +00002800 &sector_size, &user_cylinders, &user_heads, &user_sectors);
Denis Vlasenko834410a2006-11-29 12:00:28 +00002801 argc -= optind;
2802 argv += optind;
2803 if (opt & OPT_b) { // -b
2804 /* Ugly: this sector size is really per device,
2805 so cannot be combined with multiple disks,
2806 and the same goes for the C/H/S options.
2807 */
Denis Vlasenko04e11c92008-02-10 19:44:20 +00002808 if (sector_size != 512 && sector_size != 1024
2809 && sector_size != 2048)
Manuel Novoa III cad53642003-03-19 09:13:01 +00002810 bb_show_usage();
Denis Vlasenko834410a2006-11-29 12:00:28 +00002811 sector_offset = 2;
2812 user_set_sector_size = 1;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002813 }
Denis Vlasenko04e11c92008-02-10 19:44:20 +00002814 if (user_heads <= 0 || user_heads >= 256)
2815 user_heads = 0;
2816 if (user_sectors <= 0 || user_sectors >= 64)
2817 user_sectors = 0;
2818 if (opt & OPT_u)
2819 display_in_cyl_units = 0; // -u
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002820
Denis Vlasenko834410a2006-11-29 12:00:28 +00002821#if ENABLE_FEATURE_FDISK_WRITABLE
2822 if (opt & OPT_l) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002823 nowarn = 1;
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00002824#endif
Denis Vlasenkocdf62772008-03-17 08:42:43 +00002825 if (*argv) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002826 listing = 1;
Denis Vlasenkocdf62772008-03-17 08:42:43 +00002827 do {
Denis Vlasenko4437d192008-04-17 00:12:10 +00002828 open_list_and_close(*argv, 1);
Denis Vlasenkocdf62772008-03-17 08:42:43 +00002829 } while (*++argv);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002830 } else {
Denis Vlasenkocdf62772008-03-17 08:42:43 +00002831 /* we don't have device names, */
2832 /* use /proc/partitions instead */
Denis Vlasenko4437d192008-04-17 00:12:10 +00002833 list_devs_in_proc_partititons();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002834 }
2835 return 0;
Denis Vlasenko834410a2006-11-29 12:00:28 +00002836#if ENABLE_FEATURE_FDISK_WRITABLE
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002837 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00002838#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002839
Denis Vlasenko834410a2006-11-29 12:00:28 +00002840#if ENABLE_FEATURE_FDISK_BLKSIZE
2841 if (opt & OPT_s) {
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00002842 int j;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002843
2844 nowarn = 1;
Denis Vlasenko834410a2006-11-29 12:00:28 +00002845 if (argc <= 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +00002846 bb_show_usage();
Denis Vlasenko834410a2006-11-29 12:00:28 +00002847 for (j = 0; j < argc; j++) {
Denis Vlasenkocdf62772008-03-17 08:42:43 +00002848 unsigned long long size;
2849 fd = xopen(argv[j], O_RDONLY);
Denis Vlasenko4437d192008-04-17 00:12:10 +00002850 size = bb_BLKGETSIZE_sectors(fd) / 2;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002851 close(fd);
Denis Vlasenko834410a2006-11-29 12:00:28 +00002852 if (argc == 1)
Denis Vlasenkocdf62772008-03-17 08:42:43 +00002853 printf("%lld\n", size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002854 else
Denis Vlasenkocdf62772008-03-17 08:42:43 +00002855 printf("%s: %lld\n", argv[j], size);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002856 }
2857 return 0;
2858 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00002859#endif
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002860
Denis Vlasenko834410a2006-11-29 12:00:28 +00002861#if ENABLE_FEATURE_FDISK_WRITABLE
2862 if (argc != 1)
Manuel Novoa III cad53642003-03-19 09:13:01 +00002863 bb_show_usage();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002864
Denis Vlasenko834410a2006-11-29 12:00:28 +00002865 disk_device = argv[0];
Denis Vlasenko4437d192008-04-17 00:12:10 +00002866 get_boot(OPEN_MAIN);
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002867
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002868 if (LABEL_IS_OSF) {
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002869 /* OSF label, and no DOS label */
Denis Vlasenkobd852072007-03-19 14:43:38 +00002870 printf("Detected an OSF/1 disklabel on %s, entering "
2871 "disklabel mode\n", disk_device);
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +00002872 bsd_select();
Rob Landley5527b912006-02-25 03:46:10 +00002873 /*Why do we do this? It seems to be counter-intuitive*/
Denis Vlasenko4437d192008-04-17 00:12:10 +00002874 current_label_type = LABEL_DOS;
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002875 /* If we return we may want to make an empty DOS label? */
2876 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002877
2878 while (1) {
Denis Vlasenko3bba5452006-12-30 17:57:03 +00002879 int c;
Denis Vlasenko4daad902007-09-27 10:20:47 +00002880 bb_putchar('\n');
Denis Vlasenkobd852072007-03-19 14:43:38 +00002881 c = tolower(read_nonempty("Command (m for help): "));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002882 switch (c) {
2883 case 'a':
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002884 if (LABEL_IS_DOS)
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002885 toggle_active(get_partition(1, g_partitions));
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002886 else if (LABEL_IS_SUN)
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002887 toggle_sunflags(get_partition(1, g_partitions),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002888 0x01);
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002889 else if (LABEL_IS_SGI)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002890 sgi_set_bootpartition(
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002891 get_partition(1, g_partitions));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002892 else
2893 unknown_command(c);
2894 break;
2895 case 'b':
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002896 if (LABEL_IS_SGI) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00002897 printf("\nThe current boot file is: %s\n",
Rob Landleyb73451d2006-02-24 16:29:00 +00002898 sgi_get_bootfile());
Denis Vlasenkobd852072007-03-19 14:43:38 +00002899 if (read_maybe_empty("Please enter the name of the "
2900 "new boot file: ") == '\n')
2901 printf("Boot file unchanged\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002902 else
2903 sgi_set_bootfile(line_ptr);
Denis Vlasenko834410a2006-11-29 12:00:28 +00002904 }
2905#if ENABLE_FEATURE_OSF_LABEL
2906 else
Denis Vlasenkoefeed5e2006-10-14 16:16:03 +00002907 bsd_select();
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002908#endif
2909 break;
2910 case 'c':
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002911 if (LABEL_IS_DOS)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002912 toggle_dos_compatibility_flag();
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002913 else if (LABEL_IS_SUN)
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002914 toggle_sunflags(get_partition(1, g_partitions),
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002915 0x10);
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002916 else if (LABEL_IS_SGI)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002917 sgi_set_swappartition(
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002918 get_partition(1, g_partitions));
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002919 else
2920 unknown_command(c);
2921 break;
2922 case 'd':
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00002923 {
Eric Andersen040f4402003-07-30 08:40:37 +00002924 int j;
Eric Andersen040f4402003-07-30 08:40:37 +00002925 /* If sgi_label then don't use get_existing_partition,
2926 let the user select a partition, since
2927 get_existing_partition() only works for Linux-like
2928 partition tables */
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002929 if (!LABEL_IS_SGI) {
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002930 j = get_existing_partition(1, g_partitions);
Eric Andersen040f4402003-07-30 08:40:37 +00002931 } else {
Denis Vlasenkof77f3692007-12-16 17:22:33 +00002932 j = get_partition(1, g_partitions);
Eric Andersen040f4402003-07-30 08:40:37 +00002933 }
Glenn L McGrath4dcc2dd2003-01-04 11:56:06 +00002934 if (j >= 0)
2935 delete_partition(j);
2936 }
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002937 break;
2938 case 'i':
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002939 if (LABEL_IS_SGI)
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002940 create_sgiinfo();
2941 else
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002942 unknown_command(c);
2943 case 'l':
2944 list_types(get_sys_types());
2945 break;
2946 case 'm':
2947 menu();
2948 break;
2949 case 'n':
2950 new_partition();
2951 break;
2952 case 'o':
2953 create_doslabel();
2954 break;
2955 case 'p':
2956 list_table(0);
2957 break;
2958 case 'q':
Denis Vlasenkoc033d512008-04-17 01:52:28 +00002959 if (ENABLE_FEATURE_CLEAN_UP)
2960 close_dev_fd();
Denis Vlasenko4daad902007-09-27 10:20:47 +00002961 bb_putchar('\n');
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002962 return 0;
2963 case 's':
Denis Vlasenko834410a2006-11-29 12:00:28 +00002964#if ENABLE_FEATURE_SUN_LABEL
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002965 create_sunlabel();
2966#endif
2967 break;
2968 case 't':
2969 change_sysid();
2970 break;
2971 case 'u':
2972 change_units();
2973 break;
2974 case 'v':
2975 verify();
2976 break;
2977 case 'w':
2978 write_table(); /* does not return */
2979 break;
Denis Vlasenko834410a2006-11-29 12:00:28 +00002980#if ENABLE_FEATURE_FDISK_ADVANCED
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002981 case 'x':
Denis Vlasenko98ae2162006-10-12 19:30:44 +00002982 if (LABEL_IS_SGI) {
Denis Vlasenkobd852072007-03-19 14:43:38 +00002983 printf("\n\tSorry, no experts menu for SGI "
2984 "partition tables available\n\n");
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002985 } else
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002986 xselect();
2987 break;
2988#endif
2989 default:
2990 unknown_command(c);
2991 menu();
2992 }
2993 }
2994 return 0;
Denis Vlasenko6a5dc5d2006-12-30 18:42:29 +00002995#endif /* FEATURE_FDISK_WRITABLE */
Glenn L McGrath441e7ef2002-11-26 22:00:21 +00002996}