2006-12-06 17:25:32 -06:00
|
|
|
/* fdisk.c -- Partition table manipulator for Linux.
|
|
|
|
*
|
|
|
|
* Copyright (C) 1992 A. V. Le Blanc (LeBlanc@mcc.ac.uk)
|
|
|
|
*
|
|
|
|
* This program is free software. You can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License as
|
|
|
|
* published by the Free Software Foundation: either version 1 or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <setjmp.h>
|
|
|
|
#include <errno.h>
|
2006-12-06 17:25:35 -06:00
|
|
|
#include <getopt.h>
|
|
|
|
#include <sys/stat.h>
|
2008-01-16 12:53:56 -06:00
|
|
|
#include <sys/time.h>
|
2007-07-06 20:32:31 -05:00
|
|
|
#include <time.h>
|
2008-08-19 06:53:28 -05:00
|
|
|
#include <limits.h>
|
2006-12-06 17:25:32 -06:00
|
|
|
|
2011-01-23 15:51:21 -06:00
|
|
|
#include "xalloc.h"
|
2006-12-06 17:25:43 -06:00
|
|
|
#include "nls.h"
|
2011-01-02 15:58:13 -06:00
|
|
|
#include "rpmatch.h"
|
2007-11-07 12:05:31 -06:00
|
|
|
#include "blkdev.h"
|
2006-12-06 17:25:39 -06:00
|
|
|
#include "common.h"
|
2010-03-09 02:21:35 -06:00
|
|
|
#include "mbsalign.h"
|
2006-12-06 17:25:33 -06:00
|
|
|
#include "fdisk.h"
|
2009-03-11 08:00:21 -05:00
|
|
|
#include "wholedisk.h"
|
2010-12-16 18:28:59 -06:00
|
|
|
#include "pathnames.h"
|
|
|
|
#include "canonicalize.h"
|
2011-08-17 06:21:12 -05:00
|
|
|
#include "strutils.h"
|
2006-12-06 17:25:37 -06:00
|
|
|
|
2006-12-06 17:25:35 -06:00
|
|
|
#include "fdisksunlabel.h"
|
2006-12-06 17:25:37 -06:00
|
|
|
#include "fdisksgilabel.h"
|
|
|
|
#include "fdiskaixlabel.h"
|
2007-06-27 16:49:56 -05:00
|
|
|
#include "fdiskmaclabel.h"
|
2006-12-06 17:25:37 -06:00
|
|
|
|
2006-12-06 17:26:54 -06:00
|
|
|
#ifdef HAVE_LINUX_COMPILER_H
|
|
|
|
#include <linux/compiler.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_LINUX_BLKPG_H
|
2006-12-06 17:25:39 -06:00
|
|
|
#include <linux/blkpg.h>
|
|
|
|
#endif
|
2011-03-16 11:45:53 -05:00
|
|
|
#ifdef HAVE_LIBBLKID
|
2009-10-29 05:25:59 -05:00
|
|
|
#include <blkid.h>
|
|
|
|
#endif
|
2006-12-06 17:25:32 -06:00
|
|
|
|
2007-05-31 07:31:51 -05:00
|
|
|
#include "gpt.h"
|
|
|
|
|
2011-12-15 13:02:43 -06:00
|
|
|
static int get_boot(enum action what);
|
2006-12-06 17:25:44 -06:00
|
|
|
static void delete_partition(int i);
|
|
|
|
|
2006-12-06 17:25:32 -06:00
|
|
|
#define hex_val(c) ({ \
|
|
|
|
char _c = (c); \
|
|
|
|
isdigit(_c) ? _c - '0' : \
|
|
|
|
tolower(_c) + 10 - 'a'; \
|
|
|
|
})
|
|
|
|
|
|
|
|
|
2006-12-06 17:25:46 -06:00
|
|
|
#define LINE_LENGTH 800
|
2006-12-06 17:25:43 -06:00
|
|
|
#define pt_offset(b, n) ((struct partition *)((b) + 0x1be + \
|
2006-12-06 17:25:32 -06:00
|
|
|
(n) * sizeof(struct partition)))
|
|
|
|
#define sector(s) ((s) & 0x3f)
|
|
|
|
#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
|
|
|
|
|
2006-12-06 17:25:37 -06:00
|
|
|
#define hsc2sector(h,s,c) (sector(s) - 1 + sectors * \
|
2006-12-06 17:25:32 -06:00
|
|
|
((h) + heads * cylinder(s,c)))
|
|
|
|
#define set_hsc(h,s,c,sector) { \
|
|
|
|
s = sector % sectors + 1; \
|
|
|
|
sector /= sectors; \
|
|
|
|
h = sector % heads; \
|
|
|
|
sector /= heads; \
|
|
|
|
c = sector & 0xff; \
|
|
|
|
s |= (sector >> 2) & 0xc0; \
|
|
|
|
}
|
|
|
|
|
2011-11-09 12:04:12 -06:00
|
|
|
/* menu list description */
|
|
|
|
|
|
|
|
struct menulist_descr {
|
|
|
|
char command; /* command key */
|
|
|
|
char *description; /* command description */
|
|
|
|
enum labeltype label[2]; /* disklabel types associated with main and expert menu */
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct menulist_descr menulist[] = {
|
|
|
|
{'a', N_("toggle a bootable flag"), {DOS_LABEL, 0}},
|
|
|
|
{'a', N_("toggle a read only flag"), {SUN_LABEL, 0}},
|
|
|
|
{'a', N_("select bootable partition"), {SGI_LABEL, 0}},
|
|
|
|
{'a', N_("change number of alternate cylinders"), {0, SUN_LABEL}},
|
|
|
|
{'b', N_("edit bsd disklabel"), {DOS_LABEL, 0}},
|
|
|
|
{'b', N_("edit bootfile entry"), {SGI_LABEL, 0}},
|
|
|
|
{'b', N_("move beginning of data in a partition"), {0, DOS_LABEL}},
|
|
|
|
{'c', N_("toggle the dos compatibility flag"), {DOS_LABEL, 0}},
|
|
|
|
{'c', N_("toggle the mountable flag"), {SUN_LABEL, 0}},
|
|
|
|
{'c', N_("select sgi swap partition"), {SGI_LABEL, 0}},
|
|
|
|
{'c', N_("change number of cylinders"), {0, DOS_LABEL | SUN_LABEL}},
|
|
|
|
{'d', N_("delete a partition"), {DOS_LABEL | SUN_LABEL | SGI_LABEL | OSF_LABEL, 0}},
|
|
|
|
{'d', N_("print the raw data in the partition table"), {0, ANY_LABEL}},
|
|
|
|
{'e', N_("change number of extra sectors per cylinder"), {0, SUN_LABEL}},
|
|
|
|
{'e', N_("list extended partitions"), {0, DOS_LABEL}},
|
|
|
|
{'e', N_("edit drive data"), {OSF_LABEL, 0}},
|
|
|
|
{'f', N_("fix partition order"), {0, DOS_LABEL}},
|
2011-11-11 04:12:11 -06:00
|
|
|
{'g', N_("create an IRIX (SGI) partition table"), {0, ANY_LABEL}},
|
2011-11-09 12:04:12 -06:00
|
|
|
{'h', N_("change number of heads"), {0, DOS_LABEL | SUN_LABEL}},
|
|
|
|
{'i', N_("change interleave factor"), {0, SUN_LABEL}},
|
|
|
|
{'i', N_("change the disk identifier"), {0, DOS_LABEL}},
|
|
|
|
{'i', N_("install bootstrap"), {OSF_LABEL, 0}},
|
|
|
|
{'l', N_("list known partition types"), {DOS_LABEL | SUN_LABEL | SGI_LABEL | OSF_LABEL, 0}},
|
|
|
|
{'m', N_("print this menu"), {ANY_LABEL, ANY_LABEL}},
|
|
|
|
{'n', N_("add a new partition"), {DOS_LABEL | SUN_LABEL | SGI_LABEL | OSF_LABEL, 0}},
|
|
|
|
{'o', N_("create a new empty DOS partition table"), {~OSF_LABEL, 0}},
|
|
|
|
{'o', N_("change rotation speed (rpm)"), {0, SUN_LABEL}},
|
|
|
|
{'p', N_("print the partition table"), {DOS_LABEL | SUN_LABEL | SGI_LABEL | OSF_LABEL, DOS_LABEL | SUN_LABEL}},
|
|
|
|
{'q', N_("quit without saving changes"), {ANY_LABEL, ANY_LABEL}},
|
|
|
|
{'r', N_("return to main menu"), {OSF_LABEL, DOS_LABEL | SUN_LABEL | SGI_LABEL | OSF_LABEL}},
|
|
|
|
{'s', N_("create a new empty Sun disklabel"), {~OSF_LABEL, 0}},
|
|
|
|
{'s', N_("change number of sectors/track"), {0, DOS_LABEL | SUN_LABEL}},
|
|
|
|
{'s', N_("show complete disklabel"), {OSF_LABEL, 0}},
|
|
|
|
{'t', N_("change a partition's system id"), {DOS_LABEL | SUN_LABEL | SGI_LABEL | OSF_LABEL, 0}},
|
|
|
|
{'u', N_("change display/entry units"), {DOS_LABEL | SUN_LABEL | SGI_LABEL | OSF_LABEL, 0}},
|
|
|
|
{'v', N_("verify the partition table"), {DOS_LABEL | SUN_LABEL | SGI_LABEL, DOS_LABEL | SUN_LABEL | SGI_LABEL}},
|
|
|
|
{'w', N_("write table to disk and exit"), {DOS_LABEL | SUN_LABEL | SGI_LABEL, DOS_LABEL | SUN_LABEL | SGI_LABEL}},
|
|
|
|
{'w', N_("write disklabel to disk"), {OSF_LABEL, 0}},
|
2011-11-11 04:12:11 -06:00
|
|
|
{'x', N_("extra functionality (experts only)"), {DOS_LABEL | SUN_LABEL | SGI_LABEL, 0}},
|
2011-11-09 12:04:12 -06:00
|
|
|
#if !defined (__alpha__)
|
|
|
|
{'x', N_("link BSD partition to non-BSD partition"), {OSF_LABEL, 0}},
|
|
|
|
#endif
|
|
|
|
{'y', N_("change number of physical cylinders"), {0, SUN_LABEL}},
|
|
|
|
};
|
|
|
|
|
2006-12-06 17:25:35 -06:00
|
|
|
/* A valid partition table sector ends in 0x55 0xaa */
|
2006-12-06 17:25:43 -06:00
|
|
|
static unsigned int
|
2007-05-30 10:10:43 -05:00
|
|
|
part_table_flag(unsigned char *b) {
|
2006-12-06 17:26:12 -06:00
|
|
|
return ((unsigned int) b[510]) + (((unsigned int) b[511]) << 8);
|
2006-12-06 17:25:35 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
valid_part_table_flag(unsigned char *b) {
|
|
|
|
return (b[510] == 0x55 && b[511] == 0xaa);
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2007-05-30 10:10:43 -05:00
|
|
|
write_part_table_flag(unsigned char *b) {
|
2006-12-06 17:25:35 -06:00
|
|
|
b[510] = 0x55;
|
|
|
|
b[511] = 0xaa;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* start_sect and nr_sects are stored little endian on all machines */
|
|
|
|
/* moreover, they are not aligned correctly */
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2006-12-06 17:25:35 -06:00
|
|
|
store4_little_endian(unsigned char *cp, unsigned int val) {
|
|
|
|
cp[0] = (val & 0xff);
|
|
|
|
cp[1] = ((val >> 8) & 0xff);
|
|
|
|
cp[2] = ((val >> 16) & 0xff);
|
|
|
|
cp[3] = ((val >> 24) & 0xff);
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static unsigned int
|
2007-07-06 20:32:31 -05:00
|
|
|
read4_little_endian(const unsigned char *cp) {
|
2006-12-06 17:26:12 -06:00
|
|
|
return (unsigned int)(cp[0]) + ((unsigned int)(cp[1]) << 8)
|
|
|
|
+ ((unsigned int)(cp[2]) << 16)
|
|
|
|
+ ((unsigned int)(cp[3]) << 24);
|
2006-12-06 17:25:35 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2006-12-06 17:25:35 -06:00
|
|
|
set_start_sect(struct partition *p, unsigned int start_sect) {
|
|
|
|
store4_little_endian(p->start4, start_sect);
|
|
|
|
}
|
|
|
|
|
2007-05-30 10:10:43 -05:00
|
|
|
unsigned long long
|
2006-12-06 17:25:35 -06:00
|
|
|
get_start_sect(struct partition *p) {
|
|
|
|
return read4_little_endian(p->start4);
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2007-05-30 10:10:43 -05:00
|
|
|
set_nr_sects(struct partition *p, unsigned long long nr_sects) {
|
2006-12-06 17:25:35 -06:00
|
|
|
store4_little_endian(p->size4, nr_sects);
|
|
|
|
}
|
|
|
|
|
2007-05-30 10:10:43 -05:00
|
|
|
unsigned long long
|
2006-12-06 17:25:35 -06:00
|
|
|
get_nr_sects(struct partition *p) {
|
|
|
|
return read4_little_endian(p->size4);
|
|
|
|
}
|
|
|
|
|
2007-07-06 20:32:31 -05:00
|
|
|
static ssize_t
|
|
|
|
xread(int fd, void *buf, size_t count) {
|
|
|
|
char *p = buf;
|
|
|
|
ssize_t out = 0;
|
|
|
|
ssize_t rv;
|
|
|
|
|
|
|
|
while (count) {
|
|
|
|
rv = read(fd, p, count);
|
|
|
|
if (rv == -1) {
|
|
|
|
if (errno == EINTR || errno == EAGAIN)
|
|
|
|
continue;
|
|
|
|
return out ? out : -1; /* Error */
|
|
|
|
} else if (rv == 0) {
|
|
|
|
return out; /* EOF */
|
|
|
|
}
|
|
|
|
|
|
|
|
p += rv;
|
|
|
|
out += rv;
|
|
|
|
count -= rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned int
|
|
|
|
get_random_id(void) {
|
|
|
|
int fd;
|
|
|
|
unsigned int v;
|
|
|
|
ssize_t rv = -1;
|
2008-01-16 12:53:56 -06:00
|
|
|
struct timeval tv;
|
2007-07-06 20:32:31 -05:00
|
|
|
|
|
|
|
fd = open("/dev/urandom", O_RDONLY);
|
|
|
|
if (fd >= 0) {
|
|
|
|
rv = xread(fd, &v, sizeof v);
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rv == sizeof v)
|
|
|
|
return v;
|
|
|
|
|
|
|
|
/* Fallback: sucks, but better than nothing */
|
2008-01-16 12:53:56 -06:00
|
|
|
gettimeofday(&tv, NULL);
|
|
|
|
return (unsigned int)(tv.tv_sec + (tv.tv_usec << 12) + getpid());
|
2007-07-06 20:32:31 -05:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
/*
|
|
|
|
* Raw disk label. For DOS-type partition tables the MBR,
|
|
|
|
* with descriptions of the primary partitions.
|
|
|
|
*/
|
2009-10-16 14:49:33 -05:00
|
|
|
unsigned char *MBRbuffer;
|
2006-12-06 17:25:43 -06:00
|
|
|
|
2010-08-09 06:03:02 -05:00
|
|
|
int MBRbuffer_changed;
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
/*
|
|
|
|
* per partition table entry data
|
|
|
|
*
|
|
|
|
* The four primary partitions have the same sectorbuffer (MBRbuffer)
|
|
|
|
* and have NULL ext_pointer.
|
|
|
|
* Each logical partition table entry has two pointers, one for the
|
|
|
|
* partition and one link to the next one.
|
|
|
|
*/
|
|
|
|
struct pte {
|
|
|
|
struct partition *part_table; /* points into sectorbuffer */
|
|
|
|
struct partition *ext_pointer; /* points into sectorbuffer */
|
2006-12-06 17:26:12 -06:00
|
|
|
char changed; /* boolean */
|
2007-05-30 10:10:43 -05:00
|
|
|
unsigned long long offset; /* disk sector number */
|
|
|
|
unsigned char *sectorbuffer; /* disk sector contents */
|
2006-12-06 17:25:43 -06:00
|
|
|
} ptes[MAXIMUM_PARTS];
|
|
|
|
|
2006-12-06 17:25:39 -06:00
|
|
|
char *disk_device, /* must be specified */
|
2006-12-06 17:25:32 -06:00
|
|
|
*line_ptr, /* interactive input */
|
2006-12-06 17:25:43 -06:00
|
|
|
line_buffer[LINE_LENGTH];
|
2006-12-06 17:25:32 -06:00
|
|
|
|
|
|
|
int fd, /* the disk */
|
|
|
|
ext_index, /* the prime extended partition */
|
|
|
|
listing = 0, /* no aborts for fdisk -l */
|
2006-12-06 17:25:35 -06:00
|
|
|
nowarn = 0, /* no warnings for fdisk -l/-s */
|
2010-06-15 06:13:05 -05:00
|
|
|
dos_compatible_flag = 0, /* disabled by default */
|
2006-12-06 17:25:49 -06:00
|
|
|
dos_changed = 0,
|
2006-12-06 17:25:32 -06:00
|
|
|
partitions = 4; /* maximum partition + 1 */
|
|
|
|
|
2006-12-06 17:26:12 -06:00
|
|
|
unsigned int user_cylinders, user_heads, user_sectors;
|
|
|
|
unsigned int pt_heads, pt_sectors;
|
|
|
|
unsigned int kern_heads, kern_sectors;
|
2006-12-06 17:25:43 -06:00
|
|
|
|
2007-05-30 10:10:43 -05:00
|
|
|
unsigned long long sector_offset = 1, extended_offset = 0, sectors;
|
|
|
|
|
2006-12-06 17:26:12 -06:00
|
|
|
unsigned int heads,
|
2006-12-06 17:25:32 -06:00
|
|
|
cylinders,
|
2006-12-06 17:25:37 -06:00
|
|
|
sector_size = DEFAULT_SECTOR_SIZE,
|
2006-12-06 17:25:44 -06:00
|
|
|
user_set_sector_size = 0,
|
2006-12-06 17:25:39 -06:00
|
|
|
units_per_sector = 1,
|
2010-06-15 06:13:05 -05:00
|
|
|
display_in_cyl_units = 0;
|
2006-12-06 17:25:32 -06:00
|
|
|
|
2010-08-23 05:11:26 -05:00
|
|
|
unsigned long long total_number_of_sectors; /* in logical sectors */
|
2010-02-04 06:43:37 -06:00
|
|
|
unsigned long grain = DEFAULT_SECTOR_SIZE,
|
|
|
|
io_size = DEFAULT_SECTOR_SIZE,
|
|
|
|
min_io_size = DEFAULT_SECTOR_SIZE,
|
2010-02-12 14:43:03 -06:00
|
|
|
phy_sector_size = DEFAULT_SECTOR_SIZE,
|
2010-02-04 06:43:37 -06:00
|
|
|
alignment_offset;
|
|
|
|
int has_topology;
|
2006-12-06 17:26:03 -06:00
|
|
|
|
2011-12-15 13:02:47 -06:00
|
|
|
enum labeltype disklabel; /* Current disklabel */
|
2011-07-03 05:01:21 -05:00
|
|
|
|
2006-12-06 17:25:32 -06:00
|
|
|
jmp_buf listingbuf;
|
|
|
|
|
2011-01-23 15:51:20 -06:00
|
|
|
static void __attribute__ ((__noreturn__)) usage(FILE *out)
|
|
|
|
{
|
|
|
|
fprintf(out, _("Usage:\n"
|
|
|
|
" %1$s [options] <disk> change partition table\n"
|
|
|
|
" %1$s [options] -l <disk> list partition table(s)\n"
|
|
|
|
" %1$s -s <partition> give partition size(s) in blocks\n"
|
|
|
|
"\nOptions:\n"
|
|
|
|
" -b <size> sector size (512, 1024, 2048 or 4096)\n"
|
|
|
|
" -c[=<mode>] compatible mode: 'dos' or 'nondos' (default)\n"
|
|
|
|
" -h print this help text\n"
|
|
|
|
" -u[=<unit>] display units: 'cylinders' or 'sectors' (default)\n"
|
|
|
|
" -v print program version\n"
|
|
|
|
" -C <number> specify the number of cylinders\n"
|
|
|
|
" -H <number> specify the number of heads\n"
|
|
|
|
" -S <number> specify the number of sectors per track\n"
|
|
|
|
"\n"), program_invocation_short_name);
|
|
|
|
exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
void fatal(enum failure why) {
|
2006-12-06 17:25:32 -06:00
|
|
|
|
|
|
|
if (listing) {
|
|
|
|
close(fd);
|
|
|
|
longjmp(listingbuf, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (why) {
|
|
|
|
case unable_to_open:
|
2011-01-23 15:58:14 -06:00
|
|
|
err(EXIT_FAILURE, _("unable to open %s"), disk_device);
|
|
|
|
|
2006-12-06 17:25:32 -06:00
|
|
|
case unable_to_read:
|
2011-01-23 15:58:14 -06:00
|
|
|
err(EXIT_FAILURE, _("unable to read %s"), disk_device);
|
|
|
|
|
2006-12-06 17:25:32 -06:00
|
|
|
case unable_to_seek:
|
2011-01-23 15:58:14 -06:00
|
|
|
err(EXIT_FAILURE, _("unable to seek on %s"), disk_device);
|
|
|
|
|
2006-12-06 17:25:32 -06:00
|
|
|
case unable_to_write:
|
2011-01-23 15:58:14 -06:00
|
|
|
err(EXIT_FAILURE, _("unable to write %s"), disk_device);
|
|
|
|
|
2006-12-06 17:25:39 -06:00
|
|
|
case ioctl_error:
|
2011-01-23 15:58:14 -06:00
|
|
|
err(EXIT_FAILURE, _("BLKGETSIZE ioctl failed on %s"), disk_device);
|
|
|
|
|
2006-12-06 17:25:46 -06:00
|
|
|
default:
|
2011-01-23 15:58:14 -06:00
|
|
|
err(EXIT_FAILURE, _("fatal error"));
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2007-05-30 10:10:43 -05:00
|
|
|
seek_sector(int fd, unsigned long long secno) {
|
2006-12-06 17:27:13 -06:00
|
|
|
off_t offset = (off_t) secno * sector_size;
|
|
|
|
if (lseek(fd, offset, SEEK_SET) == (off_t) -1)
|
2006-12-06 17:25:43 -06:00
|
|
|
fatal(unable_to_seek);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2007-05-30 10:10:43 -05:00
|
|
|
read_sector(int fd, unsigned long long secno, unsigned char *buf) {
|
2006-12-06 17:25:43 -06:00
|
|
|
seek_sector(fd, secno);
|
|
|
|
if (read(fd, buf, sector_size) != sector_size)
|
|
|
|
fatal(unable_to_read);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2007-05-30 10:10:43 -05:00
|
|
|
write_sector(int fd, unsigned long long secno, unsigned char *buf) {
|
2006-12-06 17:25:43 -06:00
|
|
|
seek_sector(fd, secno);
|
|
|
|
if (write(fd, buf, sector_size) != sector_size)
|
|
|
|
fatal(unable_to_write);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate a buffer and read a partition table sector */
|
|
|
|
static void
|
2007-05-30 10:10:43 -05:00
|
|
|
read_pte(int fd, int pno, unsigned long long offset) {
|
2006-12-06 17:25:43 -06:00
|
|
|
struct pte *pe = &ptes[pno];
|
|
|
|
|
|
|
|
pe->offset = offset;
|
2011-01-23 15:51:21 -06:00
|
|
|
pe->sectorbuffer = xmalloc(sector_size);
|
2006-12-06 17:25:43 -06:00
|
|
|
read_sector(fd, offset, pe->sectorbuffer);
|
|
|
|
pe->changed = 0;
|
|
|
|
pe->part_table = pe->ext_pointer = NULL;
|
|
|
|
}
|
2006-12-06 17:25:46 -06:00
|
|
|
|
2007-05-30 10:10:43 -05:00
|
|
|
static unsigned long long
|
2006-12-06 17:25:43 -06:00
|
|
|
get_partition_start(struct pte *pe) {
|
|
|
|
return pe->offset + get_start_sect(pe->part_table);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct partition *
|
|
|
|
get_part_table(int i) {
|
|
|
|
return ptes[i].part_table;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
set_all_unchanged(void) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < MAXIMUM_PARTS; i++)
|
|
|
|
ptes[i].changed = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
set_changed(int i) {
|
|
|
|
ptes[i].changed = 1;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:26:24 -06:00
|
|
|
static int
|
|
|
|
is_garbage_table(void) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
struct pte *pe = &ptes[i];
|
|
|
|
struct partition *p = pe->part_table;
|
|
|
|
|
|
|
|
if (p->boot_ind != 0 && p->boot_ind != 0x80)
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:49 -06:00
|
|
|
/*
|
|
|
|
* Avoid warning about DOS partitions when no DOS partition was changed.
|
|
|
|
* Here a heuristic "is probably dos partition".
|
|
|
|
* We might also do the opposite and warn in all cases except
|
|
|
|
* for "is probably nondos partition".
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
is_dos_partition(int t) {
|
|
|
|
return (t == 1 || t == 4 || t == 6 ||
|
|
|
|
t == 0x0b || t == 0x0c || t == 0x0e ||
|
|
|
|
t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
|
|
|
|
t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
|
|
|
|
t == 0xc1 || t == 0xc4 || t == 0xc6);
|
|
|
|
}
|
|
|
|
|
2011-11-09 12:04:12 -06:00
|
|
|
void print_menu(enum menutype menu)
|
|
|
|
{
|
|
|
|
size_t i;
|
2006-12-06 17:25:32 -06:00
|
|
|
|
2011-11-09 12:04:12 -06:00
|
|
|
puts(_("Command action"));
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(menulist); i++)
|
|
|
|
if (menulist[i].label[menu] & disklabel)
|
|
|
|
printf(" %c %s\n", menulist[i].command, menulist[i].description);
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
2006-12-06 17:25:37 -06:00
|
|
|
get_sysid(int i) {
|
|
|
|
return (
|
2011-07-03 05:01:21 -05:00
|
|
|
disklabel == SUN_LABEL ? sun_get_sysid(i) :
|
|
|
|
disklabel == SGI_LABEL ? sgi_get_sysid(i) :
|
2006-12-06 17:25:56 -06:00
|
|
|
ptes[i].part_table->sys_ind);
|
2006-12-06 17:25:37 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static struct systypes *
|
2006-12-06 17:25:37 -06:00
|
|
|
get_sys_types(void) {
|
|
|
|
return (
|
2011-07-03 05:01:21 -05:00
|
|
|
disklabel == SUN_LABEL ? sun_sys_types :
|
|
|
|
disklabel == SGI_LABEL ? sgi_sys_types :
|
2006-12-06 17:25:56 -06:00
|
|
|
i386_sys_types);
|
2006-12-06 17:25:37 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:32 -06:00
|
|
|
char *partition_type(unsigned char type)
|
|
|
|
{
|
2006-12-06 17:25:35 -06:00
|
|
|
int i;
|
2006-12-06 17:25:37 -06:00
|
|
|
struct systypes *types = get_sys_types();
|
2006-12-06 17:25:35 -06:00
|
|
|
|
|
|
|
for (i=0; types[i].name; i++)
|
2006-12-06 17:25:39 -06:00
|
|
|
if (types[i].type == type)
|
|
|
|
return _(types[i].name);
|
2006-12-06 17:25:35 -06:00
|
|
|
|
2006-12-06 17:25:32 -06:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:35 -06:00
|
|
|
void list_types(struct systypes *sys)
|
2006-12-06 17:25:32 -06:00
|
|
|
{
|
2006-12-06 17:26:12 -06:00
|
|
|
unsigned int last[4], done = 0, next = 0, size;
|
2006-12-06 17:25:32 -06:00
|
|
|
int i;
|
|
|
|
|
2006-12-06 17:25:35 -06:00
|
|
|
for (i = 0; sys[i].name; i++);
|
|
|
|
size = i;
|
|
|
|
|
2006-12-06 17:25:32 -06:00
|
|
|
for (i = 3; i >= 0; i--)
|
|
|
|
last[3 - i] = done += (size + i - done) / (i + 1);
|
|
|
|
i = done = 0;
|
|
|
|
|
|
|
|
do {
|
2010-03-09 02:21:35 -06:00
|
|
|
#define NAME_WIDTH 15
|
|
|
|
char name[NAME_WIDTH * MB_LEN_MAX];
|
|
|
|
size_t width = NAME_WIDTH;
|
|
|
|
|
|
|
|
printf("%c%2x ", i ? ' ' : '\n', sys[next].type);
|
|
|
|
size_t ret = mbsalign(_(sys[next].name), name, sizeof(name),
|
|
|
|
&width, MBS_ALIGN_LEFT, 0);
|
|
|
|
if (ret == (size_t)-1 || ret >= sizeof(name))
|
|
|
|
printf("%-15.15s", _(sys[next].name));
|
|
|
|
else
|
|
|
|
fputs(name, stdout);
|
|
|
|
|
|
|
|
next = last[i++] + done;
|
2006-12-06 17:25:32 -06:00
|
|
|
if (i > 3 || next >= last[i]) {
|
|
|
|
i = 0;
|
|
|
|
next = ++done;
|
|
|
|
}
|
|
|
|
} while (done < last[0]);
|
|
|
|
putchar('\n');
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:49 -06:00
|
|
|
static int
|
|
|
|
is_cleared_partition(struct partition *p) {
|
|
|
|
return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
|
|
|
|
p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
|
|
|
|
get_start_sect(p) || get_nr_sects(p));
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
|
|
|
clear_partition(struct partition *p) {
|
|
|
|
if (!p)
|
|
|
|
return;
|
2006-12-06 17:25:32 -06:00
|
|
|
p->boot_ind = 0;
|
|
|
|
p->head = 0;
|
|
|
|
p->sector = 0;
|
|
|
|
p->cyl = 0;
|
|
|
|
p->sys_ind = 0;
|
|
|
|
p->end_head = 0;
|
|
|
|
p->end_sector = 0;
|
|
|
|
p->end_cyl = 0;
|
2006-12-06 17:25:35 -06:00
|
|
|
set_start_sect(p,0);
|
|
|
|
set_nr_sects(p,0);
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2007-05-30 10:10:43 -05:00
|
|
|
set_partition(int i, int doext, unsigned long long start,
|
|
|
|
unsigned long long stop, int sysid) {
|
2006-12-06 17:25:48 -06:00
|
|
|
struct partition *p;
|
2007-05-30 10:10:43 -05:00
|
|
|
unsigned long long offset;
|
2006-12-06 17:25:48 -06:00
|
|
|
|
|
|
|
if (doext) {
|
|
|
|
p = ptes[i].ext_pointer;
|
|
|
|
offset = extended_offset;
|
|
|
|
} else {
|
|
|
|
p = ptes[i].part_table;
|
|
|
|
offset = ptes[i].offset;
|
|
|
|
}
|
2006-12-06 17:25:32 -06:00
|
|
|
p->boot_ind = 0;
|
2006-12-06 17:25:35 -06:00
|
|
|
p->sys_ind = sysid;
|
|
|
|
set_start_sect(p, start - offset);
|
|
|
|
set_nr_sects(p, stop - start + 1);
|
2011-08-17 06:21:12 -05:00
|
|
|
|
|
|
|
if (!doext)
|
|
|
|
print_partition_size(i + 1, start, stop, sysid);
|
|
|
|
|
2006-12-06 17:25:32 -06:00
|
|
|
if (dos_compatible_flag && (start/(sectors*heads) > 1023))
|
|
|
|
start = heads*sectors*1024 - 1;
|
|
|
|
set_hsc(p->head, p->sector, p->cyl, start);
|
|
|
|
if (dos_compatible_flag && (stop/(sectors*heads) > 1023))
|
|
|
|
stop = heads*sectors*1024 - 1;
|
|
|
|
set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
|
2006-12-06 17:25:43 -06:00
|
|
|
ptes[i].changed = 1;
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
|
|
|
test_c(char **m, char *mesg) {
|
2006-12-06 17:25:32 -06:00
|
|
|
int val = 0;
|
|
|
|
if (!*m)
|
2006-12-06 17:25:39 -06:00
|
|
|
fprintf(stderr, _("You must set"));
|
2006-12-06 17:25:32 -06:00
|
|
|
else {
|
|
|
|
fprintf(stderr, " %s", *m);
|
|
|
|
val = 1;
|
|
|
|
}
|
|
|
|
*m = mesg;
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2010-02-04 06:43:37 -06:00
|
|
|
#define alignment_required (grain != sector_size)
|
2009-11-04 09:15:48 -06:00
|
|
|
|
|
|
|
static int
|
|
|
|
lba_is_aligned(unsigned long long lba)
|
|
|
|
{
|
2010-02-12 14:43:03 -06:00
|
|
|
unsigned int granularity = max(phy_sector_size, min_io_size);
|
fdisk: fix alignment check for non-512-byte logical sectors
# modprobe scsi_debug dev_size_mb=1024 sector_size=4096
# fdisk /dev/sdb
Command (m for help): n
Command action
e extended
p primary partition (1-4)
p
Partition number (1-4, default 1):
Using default value 1
First sector (256-262143, default 256): 257
Last sector, +sectors or +size{K,M,G} (257-262143, default 262143): +100M
Command (m for help): p
Disk /dev/sdb: 1073 MB, 1073741824 bytes
32 heads, 32 sectors/track, 256 cylinders, total 262144 sectors
Units = sectors of 1 * 4096 = 4096 bytes
Sector size (logical/physical): 4096 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 262144 bytes
Disk identifier: 0x16db2bb0
Device Boot Start End Blocks Id System
/dev/sdb1 257 25855 102396 83 Linux
Partition 1 does not start on physical sector boundary.
^^^^^^^^
The warning is nonsense. The logical and physical sector size is the
same. It means that every LBA is always aligned to physical sector
boundary.
Note that this bug does not mean that fdisk produces unaligned
partitions. The problem is that fdisk forces to use bigger gaps
between aligned LBAs, for example:
correctly aligned LBA are: 256, 257, 258, ... [N+1]
fdisk assumes: 256, 264, 272, ... [N+(sector_size/512)]
Reported-by: JOB NELSON <job_nelson@hotmail.com>
Signed-off-by: Karel Zak <kzak@redhat.com>
2010-08-23 06:13:36 -05:00
|
|
|
unsigned long long offset = (lba * sector_size) & (granularity - 1);
|
2009-11-04 09:15:48 -06:00
|
|
|
|
2010-02-12 14:43:03 -06:00
|
|
|
return !((granularity + alignment_offset - offset) & (granularity - 1));
|
2009-11-04 09:15:48 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#define ALIGN_UP 1
|
|
|
|
#define ALIGN_DOWN 2
|
|
|
|
#define ALIGN_NEAREST 3
|
|
|
|
|
|
|
|
static unsigned long long
|
|
|
|
align_lba(unsigned long long lba, int direction)
|
|
|
|
{
|
2010-02-12 14:43:03 -06:00
|
|
|
unsigned long long res;
|
2009-11-04 09:15:48 -06:00
|
|
|
|
2010-02-12 14:43:03 -06:00
|
|
|
if (lba_is_aligned(lba))
|
|
|
|
res = lba;
|
|
|
|
else {
|
|
|
|
unsigned long long sects_in_phy = grain / sector_size;
|
2010-02-04 06:43:37 -06:00
|
|
|
|
2010-02-12 14:43:03 -06:00
|
|
|
if (lba < sector_offset)
|
|
|
|
res = sector_offset;
|
2009-11-04 09:15:48 -06:00
|
|
|
|
2010-02-12 14:43:03 -06:00
|
|
|
else if (direction == ALIGN_UP)
|
|
|
|
res = ((lba + sects_in_phy) / sects_in_phy) * sects_in_phy;
|
2009-11-04 09:15:48 -06:00
|
|
|
|
2010-02-12 14:43:03 -06:00
|
|
|
else if (direction == ALIGN_DOWN)
|
|
|
|
res = (lba / sects_in_phy) * sects_in_phy;
|
2009-11-04 09:15:48 -06:00
|
|
|
|
2010-02-12 14:43:03 -06:00
|
|
|
else /* ALIGN_NEAREST */
|
|
|
|
res = ((lba + sects_in_phy / 2) / sects_in_phy) * sects_in_phy;
|
2009-11-04 09:15:48 -06:00
|
|
|
|
2010-02-12 14:43:03 -06:00
|
|
|
if (alignment_offset && !lba_is_aligned(res) &&
|
|
|
|
res > alignment_offset / sector_size) {
|
|
|
|
/*
|
|
|
|
* apply alignment_offset
|
|
|
|
*
|
|
|
|
* On disk with alignment compensation physical blocks starts
|
|
|
|
* at LBA < 0 (usually LBA -1). It means we have to move LBA
|
|
|
|
* according the offset to be on the physical boundary.
|
|
|
|
*/
|
|
|
|
/* fprintf(stderr, "LBA: %llu apply alignment_offset\n", res); */
|
|
|
|
res -= (max(phy_sector_size, min_io_size) -
|
|
|
|
alignment_offset) / sector_size;
|
2010-02-15 07:06:56 -06:00
|
|
|
|
|
|
|
if (direction == ALIGN_UP && res < lba)
|
|
|
|
res += sects_in_phy;
|
2010-02-12 14:43:03 -06:00
|
|
|
}
|
|
|
|
}
|
2010-02-04 06:43:37 -06:00
|
|
|
|
|
|
|
/***
|
2010-02-12 14:43:03 -06:00
|
|
|
fprintf(stderr, "LBA %llu (%s) --align-(%s)--> %llu (%s)\n",
|
2010-02-04 06:43:37 -06:00
|
|
|
lba,
|
2010-02-12 14:43:03 -06:00
|
|
|
lba_is_aligned(lba) ? "OK" : "FALSE",
|
2010-02-04 06:43:37 -06:00
|
|
|
direction == ALIGN_UP ? "UP " :
|
|
|
|
direction == ALIGN_DOWN ? "DOWN " : "NEAREST",
|
|
|
|
res,
|
|
|
|
lba_is_aligned(res) ? "OK" : "FALSE");
|
|
|
|
***/
|
2009-11-04 09:15:48 -06:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned long long
|
|
|
|
align_lba_in_range( unsigned long long lba,
|
|
|
|
unsigned long long start,
|
|
|
|
unsigned long long stop)
|
|
|
|
{
|
|
|
|
start = align_lba(start, ALIGN_UP);
|
|
|
|
stop = align_lba(stop, ALIGN_DOWN);
|
|
|
|
|
|
|
|
lba = align_lba(lba, ALIGN_NEAREST);
|
|
|
|
|
|
|
|
if (lba < start)
|
|
|
|
return start;
|
|
|
|
else if (lba > stop)
|
|
|
|
return stop;
|
|
|
|
return lba;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
|
|
|
warn_geometry(void) {
|
2006-12-06 17:25:32 -06:00
|
|
|
char *m = NULL;
|
|
|
|
int prev = 0;
|
2006-12-06 17:26:30 -06:00
|
|
|
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel == SGI_LABEL) /* cannot set cylinders etc anyway */
|
2006-12-06 17:26:30 -06:00
|
|
|
return 0;
|
2006-12-06 17:25:32 -06:00
|
|
|
if (!heads)
|
2006-12-06 17:25:39 -06:00
|
|
|
prev = test_c(&m, _("heads"));
|
2006-12-06 17:25:32 -06:00
|
|
|
if (!sectors)
|
2006-12-06 17:25:39 -06:00
|
|
|
prev = test_c(&m, _("sectors"));
|
2006-12-06 17:25:32 -06:00
|
|
|
if (!cylinders)
|
2006-12-06 17:25:39 -06:00
|
|
|
prev = test_c(&m, _("cylinders"));
|
2006-12-06 17:25:32 -06:00
|
|
|
if (!m)
|
|
|
|
return 0;
|
|
|
|
fprintf(stderr,
|
2006-12-06 17:25:39 -06:00
|
|
|
_("%s%s.\nYou can do this from the extra functions menu.\n"),
|
|
|
|
prev ? _(" and ") : " ", m);
|
2006-12-06 17:25:32 -06:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void update_units(void)
|
|
|
|
{
|
2006-12-06 17:25:37 -06:00
|
|
|
int cyl_units = heads * sectors;
|
|
|
|
|
2006-12-06 17:25:39 -06:00
|
|
|
if (display_in_cyl_units && cyl_units)
|
|
|
|
units_per_sector = cyl_units;
|
2006-12-06 17:25:37 -06:00
|
|
|
else
|
2010-06-15 06:13:05 -05:00
|
|
|
units_per_sector = 1; /* in sectors */
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
|
2009-11-03 05:00:23 -06:00
|
|
|
static void
|
|
|
|
warn_limits(void) {
|
|
|
|
if (total_number_of_sectors > UINT_MAX && !nowarn) {
|
2010-08-23 05:11:26 -05:00
|
|
|
unsigned long long bytes = total_number_of_sectors * sector_size;
|
|
|
|
int giga = bytes / 1000000000;
|
2008-08-20 16:27:50 -05:00
|
|
|
int hectogiga = (giga + 50) / 100;
|
|
|
|
|
2008-08-19 06:53:28 -05:00
|
|
|
fprintf(stderr, _("\n"
|
|
|
|
"WARNING: The size of this disk is %d.%d TB (%llu bytes).\n"
|
2008-08-20 16:27:50 -05:00
|
|
|
"DOS partition table format can not be used on drives for volumes\n"
|
2009-02-26 03:19:05 -06:00
|
|
|
"larger than (%llu bytes) for %d-byte sectors. Use parted(1) and GUID \n"
|
2008-08-19 06:53:28 -05:00
|
|
|
"partition table format (GPT).\n\n"),
|
2008-08-20 16:27:50 -05:00
|
|
|
hectogiga / 10, hectogiga % 10,
|
2010-08-23 05:11:26 -05:00
|
|
|
bytes,
|
2009-02-26 03:19:05 -06:00
|
|
|
(unsigned long long ) UINT_MAX * sector_size,
|
|
|
|
sector_size);
|
2008-08-19 06:53:28 -05:00
|
|
|
}
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
|
2009-11-03 05:00:23 -06:00
|
|
|
static void
|
|
|
|
warn_alignment(void) {
|
2010-02-04 08:02:16 -06:00
|
|
|
if (nowarn)
|
2009-11-03 05:00:23 -06:00
|
|
|
return;
|
|
|
|
|
2010-02-04 08:02:16 -06:00
|
|
|
if (sector_size != phy_sector_size)
|
|
|
|
fprintf(stderr, _("\n"
|
2009-11-03 05:00:23 -06:00
|
|
|
"The device presents a logical sector size that is smaller than\n"
|
2010-02-04 08:02:16 -06:00
|
|
|
"the physical sector size. Aligning to a physical sector (or optimal\n"
|
|
|
|
"I/O) size boundary is recommended, or performance may be impacted.\n"));
|
2009-11-03 05:00:23 -06:00
|
|
|
|
2010-06-14 13:08:50 -05:00
|
|
|
if (dos_compatible_flag)
|
2010-02-04 08:02:16 -06:00
|
|
|
fprintf(stderr, _("\n"
|
|
|
|
"WARNING: DOS-compatible mode is deprecated. It's strongly recommended to\n"
|
2010-06-14 13:08:50 -05:00
|
|
|
" switch off the mode (with command 'c')."));
|
2009-11-03 05:00:23 -06:00
|
|
|
|
2010-06-14 13:08:50 -05:00
|
|
|
if (display_in_cyl_units)
|
2010-02-15 07:39:30 -06:00
|
|
|
fprintf(stderr, _("\n"
|
|
|
|
"WARNING: cylinders as display units are deprecated. Use command 'u' to\n"
|
|
|
|
" change units to sectors.\n"));
|
|
|
|
|
2009-11-03 05:00:23 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
|
|
|
read_extended(int ext) {
|
2006-12-06 17:25:32 -06:00
|
|
|
int i;
|
2006-12-06 17:25:43 -06:00
|
|
|
struct pte *pex;
|
|
|
|
struct partition *p, *q;
|
|
|
|
|
|
|
|
ext_index = ext;
|
|
|
|
pex = &ptes[ext];
|
|
|
|
pex->ext_pointer = pex->part_table;
|
2006-12-06 17:25:32 -06:00
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
p = pex->part_table;
|
2006-12-06 17:25:44 -06:00
|
|
|
if (!get_start_sect(p)) {
|
|
|
|
fprintf(stderr,
|
|
|
|
_("Bad offset in primary extended partition\n"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (IS_EXTENDED (p->sys_ind)) {
|
2006-12-06 17:25:43 -06:00
|
|
|
struct pte *pe = &ptes[partitions];
|
|
|
|
|
2006-12-06 17:25:32 -06:00
|
|
|
if (partitions >= MAXIMUM_PARTS) {
|
2006-12-06 17:25:39 -06:00
|
|
|
/* This is not a Linux restriction, but
|
|
|
|
this program uses arrays of size MAXIMUM_PARTS.
|
|
|
|
Do not try to `improve' this test. */
|
2006-12-06 17:25:43 -06:00
|
|
|
struct pte *pre = &ptes[partitions-1];
|
|
|
|
|
2006-12-06 17:25:32 -06:00
|
|
|
fprintf(stderr,
|
2006-12-06 17:26:26 -06:00
|
|
|
_("Warning: omitting partitions after #%d.\n"
|
|
|
|
"They will be deleted "
|
|
|
|
"if you save this partition table.\n"),
|
2006-12-06 17:25:32 -06:00
|
|
|
partitions);
|
2006-12-06 17:25:43 -06:00
|
|
|
clear_partition(pre->ext_pointer);
|
|
|
|
pre->changed = 1;
|
2006-12-06 17:25:32 -06:00
|
|
|
return;
|
|
|
|
}
|
2006-12-06 17:25:43 -06:00
|
|
|
|
|
|
|
read_pte(fd, partitions, extended_offset + get_start_sect(p));
|
|
|
|
|
2006-12-06 17:25:32 -06:00
|
|
|
if (!extended_offset)
|
2006-12-06 17:25:35 -06:00
|
|
|
extended_offset = get_start_sect(p);
|
2006-12-06 17:25:43 -06:00
|
|
|
|
|
|
|
q = p = pt_offset(pe->sectorbuffer, 0);
|
2006-12-06 17:25:44 -06:00
|
|
|
for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
|
2006-12-06 17:25:37 -06:00
|
|
|
if (IS_EXTENDED (p->sys_ind)) {
|
2006-12-06 17:25:43 -06:00
|
|
|
if (pe->ext_pointer)
|
2006-12-06 17:25:46 -06:00
|
|
|
fprintf(stderr,
|
|
|
|
_("Warning: extra link "
|
|
|
|
"pointer in partition table"
|
|
|
|
" %d\n"), partitions + 1);
|
2006-12-06 17:25:32 -06:00
|
|
|
else
|
2006-12-06 17:25:43 -06:00
|
|
|
pe->ext_pointer = p;
|
2006-12-06 17:25:37 -06:00
|
|
|
} else if (p->sys_ind) {
|
2006-12-06 17:25:43 -06:00
|
|
|
if (pe->part_table)
|
2006-12-06 17:25:32 -06:00
|
|
|
fprintf(stderr,
|
2006-12-06 17:25:46 -06:00
|
|
|
_("Warning: ignoring extra "
|
|
|
|
"data in partition table"
|
|
|
|
" %d\n"), partitions + 1);
|
2006-12-06 17:25:32 -06:00
|
|
|
else
|
2006-12-06 17:25:43 -06:00
|
|
|
pe->part_table = p;
|
2006-12-06 17:25:37 -06:00
|
|
|
}
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
2006-12-06 17:25:43 -06:00
|
|
|
|
|
|
|
/* very strange code here... */
|
|
|
|
if (!pe->part_table) {
|
|
|
|
if (q != pe->ext_pointer)
|
|
|
|
pe->part_table = q;
|
|
|
|
else
|
|
|
|
pe->part_table = q + 1;
|
2006-12-06 17:25:37 -06:00
|
|
|
}
|
2006-12-06 17:25:43 -06:00
|
|
|
if (!pe->ext_pointer) {
|
|
|
|
if (q != pe->part_table)
|
|
|
|
pe->ext_pointer = q;
|
|
|
|
else
|
|
|
|
pe->ext_pointer = q + 1;
|
2006-12-06 17:25:37 -06:00
|
|
|
}
|
2006-12-06 17:25:43 -06:00
|
|
|
|
|
|
|
p = pe->ext_pointer;
|
|
|
|
partitions++;
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
2006-12-06 17:25:44 -06:00
|
|
|
|
|
|
|
/* remove empty links */
|
|
|
|
remove:
|
|
|
|
for (i = 4; i < partitions; i++) {
|
|
|
|
struct pte *pe = &ptes[i];
|
|
|
|
|
2006-12-06 17:25:46 -06:00
|
|
|
if (!get_nr_sects(pe->part_table) &&
|
|
|
|
(partitions > 5 || ptes[4].part_table->sys_ind)) {
|
2008-10-03 01:52:35 -05:00
|
|
|
printf(_("omitting empty partition (%d)\n"), i+1);
|
2006-12-06 17:25:44 -06:00
|
|
|
delete_partition(i);
|
|
|
|
goto remove; /* numbering changed */
|
|
|
|
}
|
|
|
|
}
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
|
2007-07-06 20:32:31 -05:00
|
|
|
static void
|
|
|
|
dos_write_mbr_id(unsigned char *b, unsigned int id) {
|
|
|
|
store4_little_endian(&b[440], id);
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned int
|
|
|
|
dos_read_mbr_id(const unsigned char *b) {
|
|
|
|
return read4_little_endian(&b[440]);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dos_print_mbr_id(void) {
|
|
|
|
printf(_("Disk identifier: 0x%08x\n"), dos_read_mbr_id(MBRbuffer));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dos_set_mbr_id(void) {
|
|
|
|
unsigned long new_id;
|
|
|
|
char *ep;
|
|
|
|
char ps[64];
|
|
|
|
|
|
|
|
snprintf(ps, sizeof ps, _("New disk identifier (current 0x%08x): "),
|
|
|
|
dos_read_mbr_id(MBRbuffer));
|
|
|
|
|
|
|
|
if (read_chars(ps) == '\n')
|
|
|
|
return;
|
|
|
|
|
|
|
|
new_id = strtoul(line_ptr, &ep, 0);
|
|
|
|
if (*ep != '\n')
|
|
|
|
return;
|
|
|
|
|
|
|
|
dos_write_mbr_id(MBRbuffer, new_id);
|
2010-08-09 06:03:02 -05:00
|
|
|
MBRbuffer_changed = 1;
|
2007-07-06 20:32:31 -05:00
|
|
|
dos_print_mbr_id();
|
|
|
|
}
|
|
|
|
|
2011-12-15 13:02:47 -06:00
|
|
|
static void dos_init(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
disklabel = DOS_LABEL;
|
|
|
|
partitions = 4;
|
|
|
|
ext_index = 0;
|
|
|
|
extended_offset = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
struct pte *pe = &ptes[i];
|
|
|
|
|
|
|
|
pe->part_table = pt_offset(MBRbuffer, i);
|
|
|
|
pe->ext_pointer = NULL;
|
|
|
|
pe->offset = 0;
|
|
|
|
pe->sectorbuffer = MBRbuffer;
|
|
|
|
pe->changed = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
warn_geometry();
|
|
|
|
warn_limits();
|
|
|
|
warn_alignment();
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
|
|
|
create_doslabel(void) {
|
2007-07-06 20:32:31 -05:00
|
|
|
unsigned int id = get_random_id();
|
2006-12-06 17:25:35 -06:00
|
|
|
|
2011-08-16 17:19:04 -05:00
|
|
|
fprintf(stderr, _("Building a new DOS disklabel with disk identifier 0x%08x.\n"), id);
|
2006-12-06 17:25:37 -06:00
|
|
|
sun_nolabel(); /* otherwise always recognised as sun */
|
|
|
|
sgi_nolabel(); /* otherwise always recognised as sgi */
|
|
|
|
|
2011-12-15 13:02:47 -06:00
|
|
|
dos_init();
|
|
|
|
zeroize_mbr_buffer();
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
set_all_unchanged();
|
|
|
|
set_changed(0);
|
2007-07-06 20:32:31 -05:00
|
|
|
|
|
|
|
/* Generate an MBR ID for this disk */
|
|
|
|
dos_write_mbr_id(MBRbuffer, id);
|
|
|
|
|
2011-12-15 13:02:47 -06:00
|
|
|
/* Put MBR signature */
|
2007-07-06 20:32:31 -05:00
|
|
|
write_part_table_flag(MBRbuffer);
|
2006-12-06 17:25:35 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2009-10-29 05:25:59 -05:00
|
|
|
get_topology(int fd) {
|
2007-11-07 12:05:31 -06:00
|
|
|
int arg;
|
2011-03-16 11:45:53 -05:00
|
|
|
#ifdef HAVE_LIBBLKID
|
2009-10-29 05:25:59 -05:00
|
|
|
blkid_probe pr;
|
2007-11-07 12:05:31 -06:00
|
|
|
|
2009-10-29 05:25:59 -05:00
|
|
|
pr = blkid_new_probe();
|
|
|
|
if (pr && blkid_probe_set_device(pr, fd, 0, 0) == 0) {
|
|
|
|
blkid_topology tp = blkid_probe_get_topology(pr);
|
|
|
|
|
|
|
|
if (tp) {
|
2010-02-04 06:43:37 -06:00
|
|
|
min_io_size = blkid_topology_get_minimum_io_size(tp);
|
2010-01-28 12:42:04 -06:00
|
|
|
io_size = blkid_topology_get_optimal_io_size(tp);
|
2010-02-04 06:43:37 -06:00
|
|
|
phy_sector_size = blkid_topology_get_physical_sector_size(tp);
|
2009-10-29 05:25:59 -05:00
|
|
|
alignment_offset = blkid_topology_get_alignment_offset(tp);
|
2010-02-04 06:43:37 -06:00
|
|
|
|
|
|
|
/* We assume that the device provides topology info if
|
|
|
|
* optimal_io_size is set or alignment_offset is set or
|
|
|
|
* minimum_io_size is not power of 2.
|
|
|
|
*
|
|
|
|
* See also update_sector_offset().
|
|
|
|
*/
|
|
|
|
if (io_size || alignment_offset ||
|
|
|
|
(min_io_size & (min_io_size - 1)))
|
|
|
|
has_topology = 1;
|
|
|
|
if (!io_size)
|
|
|
|
/* optimal IO is optional, default to minimum IO */
|
|
|
|
io_size = min_io_size;
|
2009-10-29 05:25:59 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
blkid_free_probe(pr);
|
|
|
|
#endif
|
2007-11-07 12:05:31 -06:00
|
|
|
|
2009-10-29 05:25:59 -05:00
|
|
|
if (user_set_sector_size)
|
2010-03-19 09:56:27 -05:00
|
|
|
/* fdisk since 2.17 differentiate between logical and physical
|
|
|
|
* sectors size. For backward compatibility the
|
|
|
|
* fdisk -b <sectorsize>
|
|
|
|
* changes both, logical and physical sector size.
|
|
|
|
*/
|
|
|
|
phy_sector_size = sector_size;
|
|
|
|
|
|
|
|
else if (blkdev_get_sector_size(fd, &arg) == 0) {
|
2007-11-07 12:05:31 -06:00
|
|
|
sector_size = arg;
|
2009-10-29 05:25:59 -05:00
|
|
|
|
2010-03-19 09:56:27 -05:00
|
|
|
if (!phy_sector_size)
|
|
|
|
phy_sector_size = sector_size;
|
|
|
|
}
|
|
|
|
|
2010-02-15 06:29:04 -06:00
|
|
|
if (!min_io_size)
|
|
|
|
min_io_size = phy_sector_size;
|
2010-01-28 12:42:04 -06:00
|
|
|
if (!io_size)
|
2010-02-15 06:29:04 -06:00
|
|
|
io_size = min_io_size;
|
2009-10-29 05:25:59 -05:00
|
|
|
|
2007-11-07 12:05:31 -06:00
|
|
|
if (sector_size != DEFAULT_SECTOR_SIZE)
|
|
|
|
printf(_("Note: sector size is %d (not %d)\n"),
|
|
|
|
sector_size, DEFAULT_SECTOR_SIZE);
|
2006-12-06 17:25:43 -06:00
|
|
|
}
|
2006-12-06 17:25:39 -06:00
|
|
|
|
2006-12-06 17:25:54 -06:00
|
|
|
static void
|
|
|
|
get_kernel_geometry(int fd) {
|
|
|
|
#ifdef HDIO_GETGEO
|
|
|
|
struct hd_geometry geometry;
|
|
|
|
|
|
|
|
if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
|
|
|
|
kern_heads = geometry.heads;
|
|
|
|
kern_sectors = geometry.sectors;
|
|
|
|
/* never use geometry.cylinders - it is truncated */
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
get_partition_table_geometry(void) {
|
|
|
|
unsigned char *bufp = MBRbuffer;
|
|
|
|
struct partition *p;
|
|
|
|
int i, h, s, hh, ss;
|
|
|
|
int first = 1;
|
|
|
|
int bad = 0;
|
|
|
|
|
|
|
|
if (!(valid_part_table_flag(bufp)))
|
|
|
|
return;
|
|
|
|
|
|
|
|
hh = ss = 0;
|
|
|
|
for (i=0; i<4; i++) {
|
|
|
|
p = pt_offset(bufp, i);
|
|
|
|
if (p->sys_ind != 0) {
|
|
|
|
h = p->end_head + 1;
|
|
|
|
s = (p->end_sector & 077);
|
|
|
|
if (first) {
|
|
|
|
hh = h;
|
|
|
|
ss = s;
|
|
|
|
first = 0;
|
|
|
|
} else if (hh != h || ss != s)
|
|
|
|
bad = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!first && !bad) {
|
|
|
|
pt_heads = hh;
|
|
|
|
pt_sectors = ss;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-03 04:28:55 -06:00
|
|
|
/*
|
|
|
|
* Sets LBA of the first partition
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
update_sector_offset(void)
|
|
|
|
{
|
2010-02-04 06:43:37 -06:00
|
|
|
grain = io_size;
|
|
|
|
|
2010-02-08 10:45:42 -06:00
|
|
|
if (dos_compatible_flag)
|
|
|
|
sector_offset = sectors; /* usually 63 sectors */
|
|
|
|
else {
|
2009-11-03 04:28:55 -06:00
|
|
|
/*
|
2010-02-04 06:43:37 -06:00
|
|
|
* Align the begin of partitions to:
|
|
|
|
*
|
|
|
|
* a) topology
|
|
|
|
* a2) alignment offset
|
|
|
|
* a1) or physical sector (minimal_io_size, aka "grain")
|
|
|
|
*
|
|
|
|
* b) or default to 1MiB (2048 sectrors, Windows Vista default)
|
|
|
|
*
|
2010-02-15 09:46:05 -06:00
|
|
|
* c) or for very small devices use 1 phy.sector
|
2009-11-03 04:28:55 -06:00
|
|
|
*/
|
2010-02-15 08:55:22 -06:00
|
|
|
unsigned long long x = 0;
|
2010-02-04 06:43:37 -06:00
|
|
|
|
2010-02-15 08:55:22 -06:00
|
|
|
if (has_topology) {
|
|
|
|
if (alignment_offset)
|
|
|
|
x = alignment_offset;
|
|
|
|
else if (io_size > 2048 * 512)
|
|
|
|
x = io_size;
|
|
|
|
}
|
|
|
|
/* default to 1MiB */
|
|
|
|
if (!x)
|
|
|
|
x = 2048 * 512;
|
2010-02-04 06:43:37 -06:00
|
|
|
|
|
|
|
sector_offset = x / sector_size;
|
2009-11-03 04:28:55 -06:00
|
|
|
|
2010-02-15 09:46:05 -06:00
|
|
|
/* don't use huge offset on small devices */
|
2010-02-04 06:43:37 -06:00
|
|
|
if (total_number_of_sectors <= sector_offset * 4)
|
|
|
|
sector_offset = phy_sector_size / sector_size;
|
2010-02-15 08:55:22 -06:00
|
|
|
|
|
|
|
/* use 1MiB grain always when possible */
|
|
|
|
if (grain < 2048 * 512)
|
|
|
|
grain = 2048 * 512;
|
2010-02-15 09:46:05 -06:00
|
|
|
|
|
|
|
/* don't use huge grain on small devices */
|
|
|
|
if (total_number_of_sectors <= (grain * 4 / sector_size))
|
|
|
|
grain = phy_sector_size;
|
2009-11-03 04:28:55 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
void
|
|
|
|
get_geometry(int fd, struct geom *g) {
|
2010-08-23 05:11:26 -05:00
|
|
|
unsigned long long llcyls, nsects = 0;
|
2006-12-06 17:25:35 -06:00
|
|
|
|
2009-10-29 05:25:59 -05:00
|
|
|
get_topology(fd);
|
2006-12-06 17:25:43 -06:00
|
|
|
heads = cylinders = sectors = 0;
|
2006-12-06 17:25:54 -06:00
|
|
|
kern_heads = kern_sectors = 0;
|
|
|
|
pt_heads = pt_sectors = 0;
|
|
|
|
|
|
|
|
get_kernel_geometry(fd);
|
|
|
|
get_partition_table_geometry();
|
|
|
|
|
|
|
|
heads = user_heads ? user_heads :
|
|
|
|
pt_heads ? pt_heads :
|
|
|
|
kern_heads ? kern_heads : 255;
|
|
|
|
sectors = user_sectors ? user_sectors :
|
|
|
|
pt_sectors ? pt_sectors :
|
|
|
|
kern_sectors ? kern_sectors : 63;
|
|
|
|
|
2010-08-23 05:11:26 -05:00
|
|
|
/* get number of 512-byte sectors, and convert it the real sectors */
|
|
|
|
if (blkdev_get_sectors(fd, &nsects) == 0)
|
|
|
|
total_number_of_sectors = (nsects / (sector_size >> 9));
|
2006-12-06 17:25:54 -06:00
|
|
|
|
2009-11-03 04:28:55 -06:00
|
|
|
update_sector_offset();
|
2006-12-06 17:25:43 -06:00
|
|
|
|
2010-08-23 05:11:26 -05:00
|
|
|
llcyls = total_number_of_sectors / (heads * sectors);
|
2006-12-06 17:26:18 -06:00
|
|
|
cylinders = llcyls;
|
|
|
|
if (cylinders != llcyls) /* truncated? */
|
|
|
|
cylinders = ~0;
|
2006-12-06 17:25:43 -06:00
|
|
|
if (!cylinders)
|
|
|
|
cylinders = user_cylinders;
|
|
|
|
|
|
|
|
if (g) {
|
|
|
|
g->heads = heads;
|
|
|
|
g->sectors = sectors;
|
|
|
|
g->cylinders = cylinders;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-16 14:49:33 -05:00
|
|
|
/*
|
|
|
|
* Please, always use allocated buffer if you want to cast the buffer to
|
|
|
|
* any struct -- cast non-allocated buffer to any struct is against
|
|
|
|
* strict-aliasing rules. --kzak 16-Oct-2009
|
|
|
|
*/
|
|
|
|
static void init_mbr_buffer(void)
|
|
|
|
{
|
|
|
|
if (MBRbuffer)
|
|
|
|
return;
|
|
|
|
|
2011-01-23 15:51:21 -06:00
|
|
|
MBRbuffer = xcalloc(1, MAX_SECTOR_SIZE);
|
2009-10-16 14:49:33 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void zeroize_mbr_buffer(void)
|
|
|
|
{
|
|
|
|
if (MBRbuffer)
|
|
|
|
memset(MBRbuffer, 0, MAX_SECTOR_SIZE);
|
|
|
|
}
|
|
|
|
|
2011-12-15 13:02:47 -06:00
|
|
|
static int check_dos_label(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!valid_part_table_flag(MBRbuffer))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
dos_init();
|
|
|
|
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
|
|
struct pte *pe = &ptes[i];
|
|
|
|
|
|
|
|
if (IS_EXTENDED (pe->part_table->sys_ind)) {
|
|
|
|
if (partitions != 4)
|
|
|
|
fprintf(stderr, _("Ignoring extra extended "
|
|
|
|
"partition %d\n"), i + 1);
|
|
|
|
else
|
|
|
|
read_extended(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 3; i < partitions; i++) {
|
|
|
|
struct pte *pe = &ptes[i];
|
|
|
|
|
|
|
|
if (!valid_part_table_flag(pe->sectorbuffer)) {
|
|
|
|
fprintf(stderr,
|
|
|
|
_("Warning: invalid flag 0x%04x of partition "
|
|
|
|
"table %d will be corrected by w(rite)\n"),
|
|
|
|
part_table_flag(pe->sectorbuffer), i + 1);
|
|
|
|
pe->changed = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
/*
|
|
|
|
* Read MBR. Returns:
|
|
|
|
* -1: no 0xaa55 flag present (possibly entire disk BSD)
|
|
|
|
* 0: found or created label
|
2006-12-06 17:25:49 -06:00
|
|
|
* 1: I/O error
|
2006-12-06 17:25:43 -06:00
|
|
|
*/
|
2011-12-15 13:02:43 -06:00
|
|
|
static int
|
2006-12-06 17:25:43 -06:00
|
|
|
get_boot(enum action what) {
|
2006-12-06 17:25:58 -06:00
|
|
|
|
2011-12-15 13:02:47 -06:00
|
|
|
disklabel = ANY_LABEL;
|
2006-12-06 17:25:58 -06:00
|
|
|
memset(MBRbuffer, 0, 512);
|
|
|
|
|
2010-09-22 14:11:54 -05:00
|
|
|
if (what != try_only) {
|
2011-12-15 13:02:42 -06:00
|
|
|
if ((fd = open(disk_device, O_RDWR)) < 0) {
|
2010-09-22 14:11:54 -05:00
|
|
|
if ((fd = open(disk_device, O_RDONLY)) < 0)
|
|
|
|
fatal(unable_to_open);
|
|
|
|
else
|
|
|
|
printf(_("You will not be able to write "
|
|
|
|
"the partition table.\n"));
|
|
|
|
}
|
2006-12-06 17:25:43 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:54 -06:00
|
|
|
if (512 != read(fd, MBRbuffer, 512)) {
|
2006-12-06 17:25:49 -06:00
|
|
|
if (what == try_only)
|
|
|
|
return 1;
|
2006-12-06 17:25:43 -06:00
|
|
|
fatal(unable_to_read);
|
2006-12-06 17:25:49 -06:00
|
|
|
}
|
2006-12-06 17:25:43 -06:00
|
|
|
|
2006-12-06 17:25:54 -06:00
|
|
|
get_geometry(fd, NULL);
|
|
|
|
|
|
|
|
update_units();
|
|
|
|
|
2011-12-15 13:02:47 -06:00
|
|
|
if (!check_dos_label())
|
|
|
|
if (check_sun_label() || check_sgi_label() || check_aix_label() || check_mac_label())
|
|
|
|
return 0;
|
2007-06-27 16:49:56 -05:00
|
|
|
|
2006-12-06 17:25:58 -06:00
|
|
|
if (check_osf_label()) {
|
|
|
|
if (!valid_part_table_flag(MBRbuffer)) {
|
2011-07-03 05:01:21 -05:00
|
|
|
disklabel = OSF_LABEL;
|
2006-12-06 17:25:58 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
printf(_("This disk has both DOS and BSD magic.\n"
|
|
|
|
"Give the 'b' command to go to BSD mode.\n"));
|
2011-12-15 13:02:47 -06:00
|
|
|
return 0;
|
2006-12-06 17:25:58 -06:00
|
|
|
}
|
2006-12-06 17:25:43 -06:00
|
|
|
|
2011-12-15 13:02:47 -06:00
|
|
|
if (disklabel == ANY_LABEL) {
|
|
|
|
if (what == try_only)
|
|
|
|
return -1;
|
2006-12-06 17:25:49 -06:00
|
|
|
|
2011-12-15 13:02:47 -06:00
|
|
|
fprintf(stderr,
|
|
|
|
_("Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel\n"));
|
2006-12-06 17:25:35 -06:00
|
|
|
#ifdef __sparc__
|
2011-12-15 13:02:47 -06:00
|
|
|
create_sunlabel();
|
2006-12-06 17:25:35 -06:00
|
|
|
#else
|
2011-12-15 13:02:47 -06:00
|
|
|
create_doslabel();
|
2006-12-06 17:25:35 -06:00
|
|
|
#endif
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
2006-12-06 17:25:35 -06:00
|
|
|
return 0;
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
|
2011-01-02 15:58:12 -06:00
|
|
|
static int is_partition_table_changed(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < partitions; i++)
|
|
|
|
if (ptes[i].changed)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-01-05 09:50:47 -06:00
|
|
|
static void maybe_exit(int rc, int *asked)
|
2011-01-02 15:58:12 -06:00
|
|
|
{
|
|
|
|
char line[LINE_LENGTH];
|
|
|
|
|
|
|
|
putchar('\n');
|
2011-01-05 09:50:47 -06:00
|
|
|
if (asked)
|
|
|
|
*asked = 0;
|
2011-01-02 15:58:12 -06:00
|
|
|
|
|
|
|
if (is_partition_table_changed() || MBRbuffer_changed) {
|
|
|
|
fprintf(stderr, _("Do you really want to quit? "));
|
|
|
|
|
|
|
|
if (!fgets(line, LINE_LENGTH, stdin) || rpmatch(line) == 1)
|
|
|
|
exit(rc);
|
2011-01-05 09:50:47 -06:00
|
|
|
if (asked)
|
|
|
|
*asked = 1;
|
2011-01-02 15:58:12 -06:00
|
|
|
} else
|
|
|
|
exit(rc);
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:37 -06:00
|
|
|
/* read line; return 0 or first char */
|
|
|
|
int
|
2011-01-05 09:50:47 -06:00
|
|
|
read_line(int *asked)
|
2006-12-06 17:25:32 -06:00
|
|
|
{
|
2006-12-06 17:25:37 -06:00
|
|
|
line_ptr = line_buffer;
|
2006-12-06 17:25:39 -06:00
|
|
|
if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
|
2011-01-05 09:50:47 -06:00
|
|
|
maybe_exit(1, asked);
|
2006-12-06 17:25:32 -06:00
|
|
|
return 0;
|
2006-12-06 17:25:39 -06:00
|
|
|
}
|
2011-01-05 09:50:47 -06:00
|
|
|
if (asked)
|
|
|
|
*asked = 0;
|
2006-12-06 17:25:32 -06:00
|
|
|
while (*line_ptr && !isgraph(*line_ptr))
|
|
|
|
line_ptr++;
|
|
|
|
return *line_ptr;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:37 -06:00
|
|
|
char
|
|
|
|
read_char(char *mesg)
|
2006-12-06 17:25:32 -06:00
|
|
|
{
|
2006-12-06 17:25:35 -06:00
|
|
|
do {
|
2006-12-06 17:25:32 -06:00
|
|
|
fputs(mesg, stdout);
|
2006-12-06 17:25:44 -06:00
|
|
|
fflush (stdout); /* requested by niles@scyld.com */
|
2011-01-05 09:50:47 -06:00
|
|
|
} while (!read_line(NULL));
|
2006-12-06 17:25:32 -06:00
|
|
|
return *line_ptr;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:37 -06:00
|
|
|
char
|
|
|
|
read_chars(char *mesg)
|
2006-12-06 17:25:35 -06:00
|
|
|
{
|
2011-01-05 09:50:47 -06:00
|
|
|
int rc, asked = 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
fputs(mesg, stdout);
|
|
|
|
fflush (stdout); /* niles@scyld.com */
|
|
|
|
rc = read_line(&asked);
|
|
|
|
} while (asked);
|
|
|
|
|
|
|
|
if (!rc) {
|
2006-12-06 17:25:35 -06:00
|
|
|
*line_ptr = '\n';
|
2006-12-06 17:25:37 -06:00
|
|
|
line_ptr[1] = 0;
|
|
|
|
}
|
|
|
|
return *line_ptr;
|
2006-12-06 17:25:35 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:37 -06:00
|
|
|
int
|
|
|
|
read_hex(struct systypes *sys)
|
2006-12-06 17:25:32 -06:00
|
|
|
{
|
2006-12-06 17:25:33 -06:00
|
|
|
int hex;
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
2006-12-06 17:25:39 -06:00
|
|
|
read_char(_("Hex code (type L to list codes): "));
|
2006-12-06 17:25:33 -06:00
|
|
|
if (tolower(*line_ptr) == 'l')
|
2006-12-06 17:25:35 -06:00
|
|
|
list_types(sys);
|
2006-12-06 17:25:33 -06:00
|
|
|
else if (isxdigit (*line_ptr))
|
|
|
|
{
|
|
|
|
hex = 0;
|
|
|
|
do
|
|
|
|
hex = hex << 4 | hex_val(*line_ptr++);
|
|
|
|
while (isxdigit(*line_ptr));
|
|
|
|
return hex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-04 07:30:31 -06:00
|
|
|
static unsigned int
|
|
|
|
read_int_sx(unsigned int low, unsigned int dflt, unsigned int high,
|
|
|
|
unsigned int base, char *mesg, int *suffix)
|
2006-12-06 17:25:33 -06:00
|
|
|
{
|
2006-12-06 17:26:12 -06:00
|
|
|
unsigned int i;
|
2006-12-06 17:25:37 -06:00
|
|
|
int default_ok = 1;
|
|
|
|
static char *ms = NULL;
|
2011-08-01 08:19:53 -05:00
|
|
|
static size_t mslen = 0;
|
2006-12-06 17:25:37 -06:00
|
|
|
|
2006-12-06 17:25:46 -06:00
|
|
|
if (!ms || strlen(mesg)+100 > mslen) {
|
|
|
|
mslen = strlen(mesg)+200;
|
2011-01-23 15:51:21 -06:00
|
|
|
ms = xrealloc(ms,mslen);
|
2006-12-06 17:25:33 -06:00
|
|
|
}
|
2006-12-06 17:25:32 -06:00
|
|
|
|
2006-12-06 17:25:37 -06:00
|
|
|
if (dflt < low || dflt > high)
|
|
|
|
default_ok = 0;
|
|
|
|
|
|
|
|
if (default_ok)
|
2006-12-06 17:26:12 -06:00
|
|
|
snprintf(ms, mslen, _("%s (%u-%u, default %u): "),
|
2006-12-06 17:25:46 -06:00
|
|
|
mesg, low, high, dflt);
|
2006-12-06 17:25:37 -06:00
|
|
|
else
|
2006-12-06 17:26:12 -06:00
|
|
|
snprintf(ms, mslen, "%s (%u-%u): ",
|
2006-12-06 17:25:46 -06:00
|
|
|
mesg, low, high);
|
2006-12-06 17:25:37 -06:00
|
|
|
|
2006-12-06 17:25:32 -06:00
|
|
|
while (1) {
|
2006-12-06 17:25:37 -06:00
|
|
|
int use_default = default_ok;
|
|
|
|
|
|
|
|
/* ask question and read answer */
|
|
|
|
while (read_chars(ms) != '\n' && !isdigit(*line_ptr)
|
|
|
|
&& *line_ptr != '-' && *line_ptr != '+')
|
|
|
|
continue;
|
|
|
|
|
2006-12-06 17:25:33 -06:00
|
|
|
if (*line_ptr == '+' || *line_ptr == '-') {
|
2006-12-06 17:26:08 -06:00
|
|
|
int minus = (*line_ptr == '-');
|
|
|
|
int absolute = 0;
|
2007-12-12 18:06:44 -06:00
|
|
|
int suflen;
|
2006-12-06 17:26:08 -06:00
|
|
|
|
2006-12-06 17:25:37 -06:00
|
|
|
i = atoi(line_ptr+1);
|
2006-12-06 17:26:08 -06:00
|
|
|
|
2007-12-12 18:06:44 -06:00
|
|
|
while (isdigit(*++line_ptr))
|
2006-12-06 17:25:33 -06:00
|
|
|
use_default = 0;
|
2006-12-06 17:26:08 -06:00
|
|
|
|
2011-05-09 09:00:36 -05:00
|
|
|
while (isspace(*line_ptr))
|
|
|
|
line_ptr++;
|
|
|
|
|
2007-12-12 18:06:44 -06:00
|
|
|
suflen = strlen(line_ptr) - 1;
|
|
|
|
|
|
|
|
while(isspace(*(line_ptr + suflen)))
|
|
|
|
*(line_ptr + suflen--) = '\0';
|
|
|
|
|
|
|
|
if ((*line_ptr == 'C' || *line_ptr == 'c') &&
|
|
|
|
*(line_ptr + 1) == '\0') {
|
|
|
|
/*
|
|
|
|
* Cylinders
|
|
|
|
*/
|
|
|
|
if (!display_in_cyl_units)
|
|
|
|
i *= heads * sectors;
|
2008-11-13 16:08:34 -06:00
|
|
|
} else if (*line_ptr &&
|
|
|
|
*(line_ptr + 1) == 'B' &&
|
2007-12-12 18:06:44 -06:00
|
|
|
*(line_ptr + 2) == '\0') {
|
|
|
|
/*
|
|
|
|
* 10^N
|
|
|
|
*/
|
|
|
|
if (*line_ptr == 'K')
|
2006-12-06 17:26:08 -06:00
|
|
|
absolute = 1000;
|
2007-12-12 18:06:44 -06:00
|
|
|
else if (*line_ptr == 'M')
|
2006-12-06 17:26:08 -06:00
|
|
|
absolute = 1000000;
|
2007-12-12 18:06:44 -06:00
|
|
|
else if (*line_ptr == 'G')
|
2006-12-06 17:26:08 -06:00
|
|
|
absolute = 1000000000;
|
2007-12-12 18:06:44 -06:00
|
|
|
else
|
|
|
|
absolute = -1;
|
2008-11-13 16:08:34 -06:00
|
|
|
} else if (*line_ptr &&
|
|
|
|
*(line_ptr + 1) == '\0') {
|
2007-12-12 18:06:44 -06:00
|
|
|
/*
|
|
|
|
* 2^N
|
|
|
|
*/
|
|
|
|
if (*line_ptr == 'K')
|
|
|
|
absolute = 1 << 10;
|
|
|
|
else if (*line_ptr == 'M')
|
|
|
|
absolute = 1 << 20;
|
|
|
|
else if (*line_ptr == 'G')
|
|
|
|
absolute = 1 << 30;
|
|
|
|
else
|
|
|
|
absolute = -1;
|
|
|
|
} else if (*line_ptr != '\0')
|
|
|
|
absolute = -1;
|
|
|
|
|
|
|
|
if (absolute == -1) {
|
|
|
|
printf(_("Unsupported suffix: '%s'.\n"), line_ptr);
|
|
|
|
printf(_("Supported: 10^N: KB (KiloByte), MB (MegaByte), GB (GigaByte)\n"
|
|
|
|
" 2^N: K (KibiByte), M (MebiByte), G (GibiByte)\n"));
|
|
|
|
continue;
|
2006-12-06 17:25:33 -06:00
|
|
|
}
|
2007-12-12 18:06:44 -06:00
|
|
|
|
|
|
|
if (absolute && i) {
|
2006-12-06 17:26:08 -06:00
|
|
|
unsigned long long bytes;
|
|
|
|
unsigned long unit;
|
|
|
|
|
|
|
|
bytes = (unsigned long long) i * absolute;
|
|
|
|
unit = sector_size * units_per_sector;
|
|
|
|
bytes += unit/2; /* round */
|
|
|
|
bytes /= unit;
|
|
|
|
i = bytes;
|
2009-11-04 07:30:31 -06:00
|
|
|
if (suffix)
|
|
|
|
*suffix = absolute;
|
2006-12-06 17:26:08 -06:00
|
|
|
}
|
|
|
|
if (minus)
|
|
|
|
i = -i;
|
2006-12-06 17:25:37 -06:00
|
|
|
i += base;
|
|
|
|
} else {
|
2006-12-06 17:25:33 -06:00
|
|
|
i = atoi(line_ptr);
|
2006-12-06 17:25:37 -06:00
|
|
|
while (isdigit(*line_ptr)) {
|
2006-12-06 17:25:33 -06:00
|
|
|
line_ptr++;
|
|
|
|
use_default = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (use_default)
|
2006-12-06 17:26:12 -06:00
|
|
|
printf(_("Using default value %u\n"), i = dflt);
|
2006-12-06 17:25:32 -06:00
|
|
|
if (i >= low && i <= high)
|
|
|
|
break;
|
2006-12-06 17:25:33 -06:00
|
|
|
else
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("Value out of range.\n"));
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2009-11-04 07:30:31 -06:00
|
|
|
/*
|
|
|
|
* Print the message MESG, then read an integer in LOW..HIGH.
|
|
|
|
* If the user hits Enter, DFLT is returned, provided that is in LOW..HIGH.
|
|
|
|
* Answers like +10 are interpreted as offsets from BASE.
|
|
|
|
*
|
|
|
|
* There is no default if DFLT is not between LOW and HIGH.
|
|
|
|
*/
|
|
|
|
unsigned int
|
|
|
|
read_int(unsigned int low, unsigned int dflt, unsigned int high,
|
|
|
|
unsigned int base, char *mesg)
|
|
|
|
{
|
|
|
|
return read_int_sx(low, dflt, high, base, mesg, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
int
|
2010-04-28 03:10:39 -05:00
|
|
|
get_partition_dflt(int warn, int max, int dflt) {
|
2006-12-06 17:25:43 -06:00
|
|
|
struct pte *pe;
|
|
|
|
int i;
|
|
|
|
|
2010-04-28 03:10:39 -05:00
|
|
|
i = read_int(1, dflt, max, 0, _("Partition number")) - 1;
|
2006-12-06 17:25:43 -06:00
|
|
|
pe = &ptes[i];
|
2006-12-06 17:25:32 -06:00
|
|
|
|
2006-12-06 17:26:03 -06:00
|
|
|
if (warn) {
|
2011-07-03 05:01:21 -05:00
|
|
|
if ((disklabel != SUN_LABEL && disklabel != SGI_LABEL && !pe->part_table->sys_ind)
|
|
|
|
|| (disklabel == SUN_LABEL &&
|
2006-12-06 17:26:03 -06:00
|
|
|
(!sunlabel->partitions[i].num_sectors ||
|
fdisk: many significant improvements and fixes to Sun label handling
1) Properly describe the exact layout and fields of the sun disk
label. Several fields were incorrectly mentioned and others
wrongly sized.
2) Properly set the version, sane, and num_partitions fields.
Because we weren't doing this, programs such as Solaris's format
and the Solaris kernel itself refused to recognize our disk labels
as valid.
3) Move SSWAP*() macros into fdisksunlabel.c as there is no reason
for them to be exposed to the rest of fdisk.
4) Kill the sun_predefined_drives array hack and assosciated code.
Instead size the disk and figure out the geometry properly just
like the SGI and MSDOS partition handling do, by means of the
HD_GETGEO ioctl() and disksize().
5) If the disk label read is found to not have the proper values
set in version, sane, or num_partitions, fix them, recompute the
label checksum, dirty the disk label, and let the user know what
we did and that the fixed values will be written out if they 'w'.
This gives users an easy way to fix up disk labels created by
disk labelling programs which had this bug.
6) Create a sun_sys_getid() function so that fdisk.c does not need
to reference the sun disk label details directly, just like the
SGI code does.
Signed-off-by: David S. Miller <davem@davemloft.net>
2007-06-29 17:50:21 -05:00
|
|
|
!sunlabel->part_tags[i].tag))
|
2011-07-03 05:01:21 -05:00
|
|
|
|| (disklabel == SGI_LABEL && (!sgi_get_num_sectors(i)))
|
2006-12-06 17:26:03 -06:00
|
|
|
)
|
|
|
|
fprintf(stderr,
|
|
|
|
_("Warning: partition %d has empty type\n"),
|
|
|
|
i+1);
|
|
|
|
}
|
2006-12-06 17:25:32 -06:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2010-04-28 03:10:39 -05:00
|
|
|
int
|
|
|
|
get_partition(int warn, int max) {
|
|
|
|
return get_partition_dflt(warn, max, 0);
|
|
|
|
}
|
|
|
|
|
2011-12-15 13:02:45 -06:00
|
|
|
/* User partition selection unless one partition only is available */
|
|
|
|
|
2006-12-06 17:26:03 -06:00
|
|
|
static int
|
|
|
|
get_existing_partition(int warn, int max) {
|
|
|
|
int pno = -1;
|
|
|
|
int i;
|
|
|
|
|
2011-12-15 13:02:45 -06:00
|
|
|
if (disklabel != DOS_LABEL)
|
|
|
|
goto not_implemented;
|
|
|
|
|
2006-12-06 17:26:03 -06:00
|
|
|
for (i = 0; i < max; i++) {
|
|
|
|
struct pte *pe = &ptes[i];
|
|
|
|
struct partition *p = pe->part_table;
|
|
|
|
|
|
|
|
if (p && !is_cleared_partition(p)) {
|
|
|
|
if (pno >= 0)
|
|
|
|
goto not_unique;
|
|
|
|
pno = i;
|
|
|
|
}
|
|
|
|
}
|
2011-07-03 05:01:21 -05:00
|
|
|
|
2006-12-06 17:26:03 -06:00
|
|
|
if (pno >= 0) {
|
|
|
|
printf(_("Selected partition %d\n"), pno+1);
|
|
|
|
return pno;
|
|
|
|
}
|
|
|
|
printf(_("No partition is defined yet!\n"));
|
|
|
|
return -1;
|
|
|
|
|
2011-12-15 13:02:45 -06:00
|
|
|
not_implemented:
|
|
|
|
not_unique:
|
2006-12-06 17:26:03 -06:00
|
|
|
return get_partition(warn, max);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
get_nonexisting_partition(int warn, int max) {
|
|
|
|
int pno = -1;
|
|
|
|
int i;
|
2010-04-28 03:10:39 -05:00
|
|
|
int dflt = 0;
|
2006-12-06 17:26:03 -06:00
|
|
|
|
|
|
|
for (i = 0; i < max; i++) {
|
|
|
|
struct pte *pe = &ptes[i];
|
|
|
|
struct partition *p = pe->part_table;
|
|
|
|
|
|
|
|
if (p && is_cleared_partition(p)) {
|
2010-04-28 03:10:39 -05:00
|
|
|
if (pno >= 0) {
|
|
|
|
dflt = pno + 1;
|
2006-12-06 17:26:03 -06:00
|
|
|
goto not_unique;
|
2010-04-28 03:10:39 -05:00
|
|
|
}
|
2006-12-06 17:26:03 -06:00
|
|
|
pno = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (pno >= 0) {
|
|
|
|
printf(_("Selected partition %d\n"), pno+1);
|
|
|
|
return pno;
|
|
|
|
}
|
|
|
|
printf(_("All primary partitions have been defined already!\n"));
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
not_unique:
|
2010-04-28 03:10:39 -05:00
|
|
|
return get_partition_dflt(warn, max, dflt);
|
2006-12-06 17:26:03 -06:00
|
|
|
}
|
|
|
|
|
2007-05-30 10:41:14 -05:00
|
|
|
const char *
|
2011-11-14 07:47:17 -06:00
|
|
|
str_units(int n)
|
|
|
|
{
|
|
|
|
if (display_in_cyl_units)
|
|
|
|
return P_("cylinder", "cylinders", n);
|
|
|
|
return P_("sector", "sectors", n);
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void change_units(void)
|
|
|
|
{
|
2006-12-06 17:25:39 -06:00
|
|
|
display_in_cyl_units = !display_in_cyl_units;
|
2006-12-06 17:25:32 -06:00
|
|
|
update_units();
|
2010-06-16 03:52:20 -05:00
|
|
|
|
|
|
|
if (display_in_cyl_units)
|
|
|
|
printf(_("Changing display/entry units to cylinders (DEPRECATED!)\n"));
|
|
|
|
else
|
|
|
|
printf(_("Changing display/entry units to sectors\n"));
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
|
|
|
toggle_active(int i) {
|
|
|
|
struct pte *pe = &ptes[i];
|
|
|
|
struct partition *p = pe->part_table;
|
2006-12-06 17:25:32 -06:00
|
|
|
|
2006-12-06 17:25:35 -06:00
|
|
|
if (IS_EXTENDED (p->sys_ind) && !p->boot_ind)
|
2006-12-06 17:25:32 -06:00
|
|
|
fprintf(stderr,
|
2006-12-06 17:25:39 -06:00
|
|
|
_("WARNING: Partition %d is an extended partition\n"),
|
2006-12-06 17:25:32 -06:00
|
|
|
i + 1);
|
2006-12-06 17:25:43 -06:00
|
|
|
p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
|
|
|
|
pe->changed = 1;
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
|
|
|
toggle_dos_compatibility_flag(void) {
|
2006-12-06 17:25:32 -06:00
|
|
|
dos_compatible_flag = ~dos_compatible_flag;
|
2009-11-03 04:28:55 -06:00
|
|
|
if (dos_compatible_flag)
|
2010-06-16 03:52:20 -05:00
|
|
|
printf(_("DOS Compatibility flag is set (DEPRECATED!)\n"));
|
2009-11-03 04:28:55 -06:00
|
|
|
else
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("DOS Compatibility flag is not set\n"));
|
2009-11-03 04:28:55 -06:00
|
|
|
|
|
|
|
update_sector_offset();
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
|
2011-11-14 07:47:19 -06:00
|
|
|
static void dos_delete_partition(int i)
|
|
|
|
{
|
2006-12-06 17:25:43 -06:00
|
|
|
struct pte *pe = &ptes[i];
|
|
|
|
struct partition *p = pe->part_table;
|
|
|
|
struct partition *q = pe->ext_pointer;
|
2006-12-06 17:25:32 -06:00
|
|
|
|
2011-11-14 07:47:19 -06:00
|
|
|
/* Note that for the fifth partition (i == 4) we don't actually
|
|
|
|
decrement partitions. */
|
2006-12-06 17:25:37 -06:00
|
|
|
|
2011-11-14 07:47:19 -06:00
|
|
|
if (i < 4) {
|
2006-12-06 17:25:35 -06:00
|
|
|
if (IS_EXTENDED (p->sys_ind) && i == ext_index) {
|
2006-12-06 17:25:43 -06:00
|
|
|
partitions = 4;
|
|
|
|
ptes[ext_index].ext_pointer = NULL;
|
2006-12-06 17:25:32 -06:00
|
|
|
extended_offset = 0;
|
|
|
|
}
|
|
|
|
clear_partition(p);
|
2011-08-16 17:19:03 -05:00
|
|
|
} else if (!q->sys_ind && i > 4) {
|
2006-12-06 17:25:46 -06:00
|
|
|
/* the last one in the chain - just delete */
|
2006-12-06 17:25:43 -06:00
|
|
|
--partitions;
|
|
|
|
--i;
|
|
|
|
clear_partition(ptes[i].ext_pointer);
|
|
|
|
ptes[i].changed = 1;
|
2006-12-06 17:25:44 -06:00
|
|
|
} else {
|
2006-12-06 17:25:46 -06:00
|
|
|
/* not the last one - further ones will be moved down */
|
2006-12-06 17:25:32 -06:00
|
|
|
if (i > 4) {
|
2006-12-06 17:25:46 -06:00
|
|
|
/* delete this link in the chain */
|
2006-12-06 17:25:43 -06:00
|
|
|
p = ptes[i-1].ext_pointer;
|
2006-12-06 17:25:48 -06:00
|
|
|
*p = *q;
|
2006-12-06 17:25:35 -06:00
|
|
|
set_start_sect(p, get_start_sect(q));
|
|
|
|
set_nr_sects(p, get_nr_sects(q));
|
2006-12-06 17:25:43 -06:00
|
|
|
ptes[i-1].changed = 1;
|
2006-12-06 17:25:44 -06:00
|
|
|
} else if (partitions > 5) { /* 5 will be moved to 4 */
|
2006-12-06 17:25:46 -06:00
|
|
|
/* the first logical in a longer chain */
|
2006-12-06 17:25:43 -06:00
|
|
|
struct pte *pe = &ptes[5];
|
|
|
|
|
2006-12-06 17:25:58 -06:00
|
|
|
if (pe->part_table) /* prevent SEGFAULT */
|
2006-12-06 17:25:43 -06:00
|
|
|
set_start_sect(pe->part_table,
|
|
|
|
get_partition_start(pe) -
|
|
|
|
extended_offset);
|
|
|
|
pe->offset = extended_offset;
|
|
|
|
pe->changed = 1;
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
2006-12-06 17:25:44 -06:00
|
|
|
|
2006-12-06 17:25:32 -06:00
|
|
|
if (partitions > 5) {
|
|
|
|
partitions--;
|
|
|
|
while (i < partitions) {
|
2006-12-06 17:25:43 -06:00
|
|
|
ptes[i] = ptes[i+1];
|
2006-12-06 17:25:32 -06:00
|
|
|
i++;
|
|
|
|
}
|
2006-12-06 17:25:43 -06:00
|
|
|
} else
|
2006-12-06 17:25:46 -06:00
|
|
|
/* the only logical: clear only */
|
2006-12-06 17:25:43 -06:00
|
|
|
clear_partition(ptes[i].part_table);
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
2011-11-14 07:47:19 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
delete_partition(int i)
|
|
|
|
{
|
2011-12-15 13:02:46 -06:00
|
|
|
if (i < 0)
|
|
|
|
return;
|
|
|
|
|
2011-11-14 07:47:19 -06:00
|
|
|
if (warn_geometry())
|
|
|
|
return; /* C/H/S not set */
|
|
|
|
|
|
|
|
ptes[i].changed = 1;
|
|
|
|
|
|
|
|
if (disklabel == DOS_LABEL)
|
|
|
|
dos_delete_partition(i);
|
|
|
|
else if (disklabel == SUN_LABEL)
|
|
|
|
sun_delete_partition(i);
|
|
|
|
else if (disklabel == SGI_LABEL)
|
|
|
|
sgi_delete_partition(i);
|
|
|
|
|
2011-08-16 17:19:03 -05:00
|
|
|
printf(_("Partition %d is deleted\n"), i + 1);
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
|
|
|
change_sysid(void) {
|
2006-12-06 17:25:32 -06:00
|
|
|
char *temp;
|
2006-12-06 17:26:03 -06:00
|
|
|
int i, sys, origsys;
|
|
|
|
struct partition *p;
|
2006-12-06 17:25:32 -06:00
|
|
|
|
2011-12-15 13:02:45 -06:00
|
|
|
i = get_existing_partition(0, partitions);
|
2006-12-06 17:26:12 -06:00
|
|
|
|
2006-12-06 17:26:03 -06:00
|
|
|
if (i == -1)
|
|
|
|
return;
|
|
|
|
p = ptes[i].part_table;
|
2006-12-06 17:25:37 -06:00
|
|
|
origsys = sys = get_sysid(i);
|
2006-12-06 17:25:35 -06:00
|
|
|
|
2006-12-06 17:26:02 -06:00
|
|
|
/* if changing types T to 0 is allowed, then
|
|
|
|
the reverse change must be allowed, too */
|
2011-07-03 05:01:21 -05:00
|
|
|
if (!sys && disklabel != SGI_LABEL && disklabel != SUN_LABEL && !get_nr_sects(p))
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("Partition %d does not exist yet!\n"), i + 1);
|
2006-12-06 17:25:35 -06:00
|
|
|
else while (1) {
|
2006-12-06 17:25:37 -06:00
|
|
|
sys = read_hex (get_sys_types());
|
|
|
|
|
2011-07-03 05:01:21 -05:00
|
|
|
if (!sys && disklabel != SGI_LABEL && disklabel != SUN_LABEL) {
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("Type 0 means free space to many systems\n"
|
2006-12-06 17:25:37 -06:00
|
|
|
"(but not to Linux). Having partitions of\n"
|
|
|
|
"type 0 is probably unwise. You can delete\n"
|
2006-12-06 17:25:39 -06:00
|
|
|
"a partition using the `d' command.\n"));
|
2006-12-06 17:25:37 -06:00
|
|
|
/* break; */
|
2006-12-06 17:25:35 -06:00
|
|
|
}
|
|
|
|
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel != SGI_LABEL && disklabel != SUN_LABEL) {
|
2006-12-06 17:25:35 -06:00
|
|
|
if (IS_EXTENDED (sys) != IS_EXTENDED (p->sys_ind)) {
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("You cannot change a partition into"
|
2006-12-06 17:25:35 -06:00
|
|
|
" an extended one or vice versa\n"
|
2006-12-06 17:25:39 -06:00
|
|
|
"Delete it first.\n"));
|
2006-12-06 17:25:32 -06:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2006-12-06 17:25:35 -06:00
|
|
|
|
|
|
|
if (sys < 256) {
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel == SUN_LABEL && i == 2 && sys != SUN_TAG_BACKUP)
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("Consider leaving partition 3 "
|
2006-12-06 17:25:35 -06:00
|
|
|
"as Whole disk (5),\n"
|
|
|
|
"as SunOS/Solaris expects it and "
|
2006-12-06 17:25:39 -06:00
|
|
|
"even Linux likes it.\n\n"));
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel == SGI_LABEL && ((i == 10 && sys != ENTIRE_DISK)
|
2006-12-06 17:25:37 -06:00
|
|
|
|| (i == 8 && sys != 0)))
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("Consider leaving partition 9 "
|
2006-12-06 17:25:37 -06:00
|
|
|
"as volume header (0),\nand "
|
2007-09-29 08:14:42 -05:00
|
|
|
"partition 11 as entire volume (6), "
|
2006-12-06 17:25:39 -06:00
|
|
|
"as IRIX expects it.\n\n"));
|
2006-12-06 17:25:35 -06:00
|
|
|
if (sys == origsys)
|
2006-12-06 17:26:02 -06:00
|
|
|
break;
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel == SUN_LABEL) {
|
2007-07-14 12:32:37 -05:00
|
|
|
ptes[i].changed = sun_change_sysid(i, sys);
|
2006-12-06 17:25:35 -06:00
|
|
|
} else
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel == SGI_LABEL) {
|
2007-07-14 12:32:37 -05:00
|
|
|
ptes[i].changed = sgi_change_sysid(i, sys);
|
|
|
|
} else {
|
2006-12-06 17:25:43 -06:00
|
|
|
p->sys_ind = sys;
|
2007-07-14 12:32:37 -05:00
|
|
|
ptes[i].changed = 1;
|
|
|
|
}
|
|
|
|
temp = partition_type(sys) ? : _("Unknown");
|
|
|
|
if (ptes[i].changed)
|
|
|
|
printf (_("Changed system type of partition %d "
|
|
|
|
"to %x (%s)\n"), i + 1, sys, temp);
|
|
|
|
else
|
2008-04-14 05:16:14 -05:00
|
|
|
printf (_("System type of partition %d is unchanged: "
|
|
|
|
"%x (%s)\n"), i + 1, sys, temp);
|
2006-12-06 17:25:49 -06:00
|
|
|
if (is_dos_partition(origsys) ||
|
|
|
|
is_dos_partition(sys))
|
|
|
|
dos_changed = 1;
|
2006-12-06 17:25:35 -06:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
|
|
|
|
* faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
|
|
|
|
* Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
|
|
|
|
* Lubkin Oct. 1991). */
|
|
|
|
|
2006-12-06 17:26:12 -06:00
|
|
|
static void
|
2010-07-26 04:37:19 -05:00
|
|
|
long2chs(unsigned long ls, unsigned int *c, unsigned int *h, unsigned int *s) {
|
2006-12-06 17:26:12 -06:00
|
|
|
int spc = heads * sectors;
|
2006-12-06 17:25:32 -06:00
|
|
|
|
|
|
|
*c = ls / spc;
|
|
|
|
ls = ls % spc;
|
|
|
|
*h = ls / sectors;
|
|
|
|
*s = ls % sectors + 1; /* sectors count from 1 */
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void check_consistency(struct partition *p, int partition) {
|
2006-12-06 17:26:12 -06:00
|
|
|
unsigned int pbc, pbh, pbs; /* physical beginning c, h, s */
|
|
|
|
unsigned int pec, peh, pes; /* physical ending c, h, s */
|
|
|
|
unsigned int lbc, lbh, lbs; /* logical beginning c, h, s */
|
|
|
|
unsigned int lec, leh, les; /* logical ending c, h, s */
|
2006-12-06 17:25:32 -06:00
|
|
|
|
2010-02-04 08:02:16 -06:00
|
|
|
if (!dos_compatible_flag)
|
|
|
|
return;
|
|
|
|
|
2006-12-06 17:25:32 -06:00
|
|
|
if (!heads || !sectors || (partition >= 4))
|
|
|
|
return; /* do not check extended partitions */
|
|
|
|
|
|
|
|
/* physical beginning c, h, s */
|
2006-12-06 17:25:34 -06:00
|
|
|
pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
|
2006-12-06 17:25:32 -06:00
|
|
|
pbh = p->head;
|
|
|
|
pbs = p->sector & 0x3f;
|
|
|
|
|
|
|
|
/* physical ending c, h, s */
|
2006-12-06 17:25:34 -06:00
|
|
|
pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
|
2006-12-06 17:25:32 -06:00
|
|
|
peh = p->end_head;
|
|
|
|
pes = p->end_sector & 0x3f;
|
|
|
|
|
|
|
|
/* compute logical beginning (c, h, s) */
|
2006-12-06 17:25:35 -06:00
|
|
|
long2chs(get_start_sect(p), &lbc, &lbh, &lbs);
|
2006-12-06 17:25:32 -06:00
|
|
|
|
|
|
|
/* compute logical ending (c, h, s) */
|
2006-12-06 17:25:35 -06:00
|
|
|
long2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
|
2006-12-06 17:25:32 -06:00
|
|
|
|
|
|
|
/* Same physical / logical beginning? */
|
|
|
|
if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("Partition %d has different physical/logical "
|
|
|
|
"beginnings (non-Linux?):\n"), partition + 1);
|
|
|
|
printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
|
|
|
|
printf(_("logical=(%d, %d, %d)\n"),lbc, lbh, lbs);
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Same physical / logical ending? */
|
|
|
|
if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("Partition %d has different physical/logical "
|
|
|
|
"endings:\n"), partition + 1);
|
|
|
|
printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
|
|
|
|
printf(_("logical=(%d, %d, %d)\n"),lec, leh, les);
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:33 -06:00
|
|
|
#if 0
|
2006-12-06 17:25:32 -06:00
|
|
|
/* Beginning on cylinder boundary? */
|
|
|
|
if (pbh != !pbc || pbs != 1) {
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("Partition %i does not start on cylinder "
|
|
|
|
"boundary:\n"), partition + 1);
|
|
|
|
printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
|
|
|
|
printf(_("should be (%d, %d, 1)\n"), pbc, !pbc);
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
2006-12-06 17:25:33 -06:00
|
|
|
#endif
|
2006-12-06 17:25:32 -06:00
|
|
|
|
|
|
|
/* Ending on cylinder boundary? */
|
|
|
|
if (peh != (heads - 1) || pes != sectors) {
|
2006-12-06 17:26:08 -06:00
|
|
|
printf(_("Partition %i does not end on cylinder boundary.\n"),
|
2006-12-06 17:25:32 -06:00
|
|
|
partition + 1);
|
2006-12-06 17:26:03 -06:00
|
|
|
#if 0
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
|
|
|
|
printf(_("should be (%d, %d, %d)\n"),
|
2006-12-06 17:25:32 -06:00
|
|
|
pec, heads - 1, sectors);
|
2006-12-06 17:26:03 -06:00
|
|
|
#endif
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-03 05:09:36 -06:00
|
|
|
static void
|
2010-02-09 03:32:29 -06:00
|
|
|
check_alignment(unsigned long long lba, int partition)
|
2009-11-03 05:09:36 -06:00
|
|
|
{
|
2010-02-09 03:32:29 -06:00
|
|
|
if (!lba_is_aligned(lba))
|
2010-02-04 08:02:16 -06:00
|
|
|
printf(_("Partition %i does not start on physical sector boundary.\n"),
|
2009-11-03 05:09:36 -06:00
|
|
|
partition + 1);
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
|
|
|
list_disk_geometry(void) {
|
2010-08-23 05:11:26 -05:00
|
|
|
unsigned long long bytes = total_number_of_sectors * sector_size;
|
2006-12-06 17:26:03 -06:00
|
|
|
long megabytes = bytes/1000000;
|
|
|
|
|
|
|
|
if (megabytes < 10000)
|
|
|
|
printf(_("\nDisk %s: %ld MB, %lld bytes\n"),
|
|
|
|
disk_device, megabytes, bytes);
|
2008-08-20 16:27:50 -05:00
|
|
|
else {
|
|
|
|
long hectomega = (megabytes + 50) / 100;
|
2010-08-23 05:11:26 -05:00
|
|
|
printf(_("\nDisk %s: %ld.%ld GB, %llu bytes\n"),
|
2008-08-20 16:27:50 -05:00
|
|
|
disk_device, hectomega / 10, hectomega % 10, bytes);
|
|
|
|
}
|
2007-05-30 10:10:43 -05:00
|
|
|
printf(_("%d heads, %llu sectors/track, %d cylinders"),
|
2006-12-06 17:26:03 -06:00
|
|
|
heads, sectors, cylinders);
|
|
|
|
if (units_per_sector == 1)
|
2010-08-23 05:11:26 -05:00
|
|
|
printf(_(", total %llu sectors"), total_number_of_sectors);
|
2006-12-06 17:26:03 -06:00
|
|
|
printf("\n");
|
2007-07-06 20:32:31 -05:00
|
|
|
printf(_("Units = %s of %d * %d = %d bytes\n"),
|
2006-12-06 17:26:03 -06:00
|
|
|
str_units(PLURAL),
|
|
|
|
units_per_sector, sector_size, units_per_sector * sector_size);
|
2009-10-29 05:25:59 -05:00
|
|
|
|
2010-02-12 14:43:03 -06:00
|
|
|
printf(_("Sector size (logical/physical): %u bytes / %lu bytes\n"),
|
2010-02-04 08:02:16 -06:00
|
|
|
sector_size, phy_sector_size);
|
|
|
|
printf(_("I/O size (minimum/optimal): %lu bytes / %lu bytes\n"),
|
|
|
|
min_io_size, io_size);
|
2009-10-29 05:25:59 -05:00
|
|
|
if (alignment_offset)
|
|
|
|
printf(_("Alignment offset: %lu bytes\n"), alignment_offset);
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel == DOS_LABEL)
|
2007-07-06 20:32:31 -05:00
|
|
|
dos_print_mbr_id();
|
|
|
|
printf("\n");
|
2006-12-06 17:25:37 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
/*
|
|
|
|
* Check whether partition entries are ordered by their starting positions.
|
|
|
|
* Return 0 if OK. Return i if partition i should have been earlier.
|
|
|
|
* Two separate checks: primary and logical partitions.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
wrong_p_order(int *prev) {
|
|
|
|
struct pte *pe;
|
|
|
|
struct partition *p;
|
2006-12-06 17:26:12 -06:00
|
|
|
unsigned int last_p_start_pos = 0, p_start_pos;
|
2006-12-06 17:25:43 -06:00
|
|
|
int i, last_i = 0;
|
|
|
|
|
|
|
|
for (i = 0 ; i < partitions; i++) {
|
|
|
|
if (i == 4) {
|
|
|
|
last_i = 4;
|
|
|
|
last_p_start_pos = 0;
|
|
|
|
}
|
|
|
|
pe = &ptes[i];
|
|
|
|
if ((p = pe->part_table)->sys_ind) {
|
|
|
|
p_start_pos = get_partition_start(pe);
|
|
|
|
|
|
|
|
if (last_p_start_pos > p_start_pos) {
|
|
|
|
if (prev)
|
|
|
|
*prev = last_i;
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
last_p_start_pos = p_start_pos;
|
|
|
|
last_i = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:48 -06:00
|
|
|
/*
|
|
|
|
* Fix the chain of logicals.
|
|
|
|
* extended_offset is unchanged, the set of sectors used is unchanged
|
|
|
|
* The chain is sorted so that sectors increase, and so that
|
|
|
|
* starting sectors increase.
|
|
|
|
*
|
|
|
|
* After this it may still be that cfdisk doesnt like the table.
|
|
|
|
* (This is because cfdisk considers expanded parts, from link to
|
|
|
|
* end of partition, and these may still overlap.)
|
|
|
|
* Now
|
|
|
|
* sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
|
|
|
|
* may help.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
fix_chain_of_logicals(void) {
|
|
|
|
int j, oj, ojj, sj, sjj;
|
|
|
|
struct partition *pj,*pjj,tmp;
|
|
|
|
|
|
|
|
/* Stage 1: sort sectors but leave sector of part 4 */
|
|
|
|
/* (Its sector is the global extended_offset.) */
|
|
|
|
stage1:
|
2006-12-06 17:25:58 -06:00
|
|
|
for (j = 5; j < partitions-1; j++) {
|
2006-12-06 17:25:48 -06:00
|
|
|
oj = ptes[j].offset;
|
|
|
|
ojj = ptes[j+1].offset;
|
|
|
|
if (oj > ojj) {
|
|
|
|
ptes[j].offset = ojj;
|
|
|
|
ptes[j+1].offset = oj;
|
|
|
|
pj = ptes[j].part_table;
|
|
|
|
set_start_sect(pj, get_start_sect(pj)+oj-ojj);
|
|
|
|
pjj = ptes[j+1].part_table;
|
|
|
|
set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
|
|
|
|
set_start_sect(ptes[j-1].ext_pointer,
|
|
|
|
ojj-extended_offset);
|
|
|
|
set_start_sect(ptes[j].ext_pointer,
|
|
|
|
oj-extended_offset);
|
|
|
|
goto stage1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Stage 2: sort starting sectors */
|
|
|
|
stage2:
|
2006-12-06 17:25:58 -06:00
|
|
|
for (j = 4; j < partitions-1; j++) {
|
2006-12-06 17:25:48 -06:00
|
|
|
pj = ptes[j].part_table;
|
|
|
|
pjj = ptes[j+1].part_table;
|
|
|
|
sj = get_start_sect(pj);
|
|
|
|
sjj = get_start_sect(pjj);
|
|
|
|
oj = ptes[j].offset;
|
|
|
|
ojj = ptes[j+1].offset;
|
|
|
|
if (oj+sj > ojj+sjj) {
|
|
|
|
tmp = *pj;
|
|
|
|
*pj = *pjj;
|
|
|
|
*pjj = tmp;
|
|
|
|
set_start_sect(pj, ojj+sjj-oj);
|
|
|
|
set_start_sect(pjj, oj+sj-ojj);
|
|
|
|
goto stage2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Probably something was changed */
|
2006-12-06 17:25:58 -06:00
|
|
|
for (j = 4; j < partitions; j++)
|
2006-12-06 17:25:48 -06:00
|
|
|
ptes[j].changed = 1;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
|
|
|
fix_partition_table_order(void) {
|
2006-12-06 17:25:48 -06:00
|
|
|
struct pte *pei, *pek;
|
2006-12-06 17:25:43 -06:00
|
|
|
int i,k;
|
|
|
|
|
2006-12-06 17:25:58 -06:00
|
|
|
if (!wrong_p_order(NULL)) {
|
2006-12-06 17:25:43 -06:00
|
|
|
printf(_("Nothing to do. Ordering is correct already.\n\n"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:48 -06:00
|
|
|
while ((i = wrong_p_order(&k)) != 0 && i < 4) {
|
2006-12-06 17:25:43 -06:00
|
|
|
/* partition i should have come earlier, move it */
|
2006-12-06 17:25:48 -06:00
|
|
|
/* We have to move data in the MBR */
|
|
|
|
struct partition *pi, *pk, *pe, pbuf;
|
2006-12-06 17:25:43 -06:00
|
|
|
pei = &ptes[i];
|
|
|
|
pek = &ptes[k];
|
|
|
|
|
2006-12-06 17:25:48 -06:00
|
|
|
pe = pei->ext_pointer;
|
|
|
|
pei->ext_pointer = pek->ext_pointer;
|
|
|
|
pek->ext_pointer = pe;
|
2006-12-06 17:25:43 -06:00
|
|
|
|
2006-12-06 17:25:48 -06:00
|
|
|
pi = pei->part_table;
|
|
|
|
pk = pek->part_table;
|
2006-12-06 17:25:43 -06:00
|
|
|
|
2006-12-06 17:25:48 -06:00
|
|
|
memmove(&pbuf, pi, sizeof(struct partition));
|
|
|
|
memmove(pi, pk, sizeof(struct partition));
|
|
|
|
memmove(pk, &pbuf, sizeof(struct partition));
|
2006-12-06 17:25:43 -06:00
|
|
|
|
|
|
|
pei->changed = pek->changed = 1;
|
|
|
|
}
|
2006-12-06 17:25:48 -06:00
|
|
|
|
|
|
|
if (i)
|
|
|
|
fix_chain_of_logicals();
|
|
|
|
|
2008-10-03 01:52:35 -05:00
|
|
|
printf(_("Done.\n"));
|
2006-12-06 17:25:48 -06:00
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
list_table(int xtra) {
|
2006-12-06 17:25:32 -06:00
|
|
|
struct partition *p;
|
|
|
|
char *type;
|
2006-12-06 17:25:35 -06:00
|
|
|
int i, w;
|
|
|
|
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel == SUN_LABEL) {
|
2006-12-06 17:25:35 -06:00
|
|
|
sun_list_table(xtra);
|
2006-12-06 17:25:37 -06:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel == SGI_LABEL) {
|
2006-12-06 17:25:37 -06:00
|
|
|
sgi_list_table(xtra);
|
|
|
|
return;
|
|
|
|
}
|
2006-12-06 17:25:35 -06:00
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
list_disk_geometry();
|
|
|
|
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel == OSF_LABEL) {
|
2006-12-06 17:25:43 -06:00
|
|
|
xbsd_print_disklabel(xtra);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:26:24 -06:00
|
|
|
if (is_garbage_table()) {
|
|
|
|
printf(_("This doesn't look like a partition table\n"
|
|
|
|
"Probably you selected the wrong device.\n\n"));
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:37 -06:00
|
|
|
/* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
|
|
|
|
but if the device name ends in a digit, say /dev/foo1,
|
|
|
|
then the partition is called /dev/foo1p3. */
|
2006-12-06 17:25:43 -06:00
|
|
|
w = strlen(disk_device);
|
|
|
|
if (w && isdigit(disk_device[w-1]))
|
|
|
|
w++;
|
2006-12-06 17:25:32 -06:00
|
|
|
if (w < 5)
|
|
|
|
w = 5;
|
2006-12-06 17:25:39 -06:00
|
|
|
|
2006-12-06 17:26:12 -06:00
|
|
|
printf(_("%*s Boot Start End Blocks Id System\n"),
|
2006-12-06 17:25:43 -06:00
|
|
|
w+1, _("Device"));
|
2006-12-06 17:25:35 -06:00
|
|
|
|
2006-12-06 17:26:03 -06:00
|
|
|
for (i = 0; i < partitions; i++) {
|
2006-12-06 17:25:43 -06:00
|
|
|
struct pte *pe = &ptes[i];
|
|
|
|
|
|
|
|
p = pe->part_table;
|
2006-12-06 17:25:49 -06:00
|
|
|
if (p && !is_cleared_partition(p)) {
|
2006-12-06 17:25:35 -06:00
|
|
|
unsigned int psects = get_nr_sects(p);
|
2006-12-06 17:25:37 -06:00
|
|
|
unsigned int pblocks = psects;
|
|
|
|
unsigned int podd = 0;
|
|
|
|
|
|
|
|
if (sector_size < 1024) {
|
|
|
|
pblocks /= (1024 / sector_size);
|
|
|
|
podd = psects % (1024 / sector_size);
|
|
|
|
}
|
|
|
|
if (sector_size > 1024)
|
|
|
|
pblocks *= (sector_size / 1024);
|
2006-12-06 17:25:35 -06:00
|
|
|
printf(
|
2006-12-06 17:26:12 -06:00
|
|
|
"%s %c %11lu %11lu %11lu%c %2x %s\n",
|
2006-12-06 17:25:43 -06:00
|
|
|
partname(disk_device, i+1, w+2),
|
2006-12-06 17:25:33 -06:00
|
|
|
/* boot flag */ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
|
2006-12-06 17:25:32 -06:00
|
|
|
? '*' : '?',
|
2006-12-06 17:26:12 -06:00
|
|
|
/* start */ (unsigned long) cround(get_partition_start(pe)),
|
|
|
|
/* end */ (unsigned long) cround(get_partition_start(pe) + psects
|
2006-12-06 17:25:35 -06:00
|
|
|
- (psects ? 1 : 0)),
|
2006-12-06 17:26:12 -06:00
|
|
|
/* odd flag on end */ (unsigned long) pblocks, podd ? '+' : ' ',
|
2006-12-06 17:25:33 -06:00
|
|
|
/* type id */ p->sys_ind,
|
|
|
|
/* type name */ (type = partition_type(p->sys_ind)) ?
|
2006-12-06 17:25:39 -06:00
|
|
|
type : _("Unknown"));
|
2006-12-06 17:25:32 -06:00
|
|
|
check_consistency(p, i);
|
2010-02-09 03:32:29 -06:00
|
|
|
check_alignment(get_partition_start(pe), i);
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
2006-12-06 17:25:35 -06:00
|
|
|
}
|
2006-12-06 17:25:46 -06:00
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
/* Is partition table in disk order? It need not be, but... */
|
|
|
|
/* partition table entries are not checked for correct order if this
|
|
|
|
is a sgi, sun or aix labeled disk... */
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel == DOS_LABEL && wrong_p_order(NULL)) {
|
2006-12-06 17:25:43 -06:00
|
|
|
printf(_("\nPartition table entries are not in disk order\n"));
|
|
|
|
}
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
|
|
|
x_list_table(int extend) {
|
|
|
|
struct pte *pe;
|
|
|
|
struct partition *p;
|
2006-12-06 17:25:32 -06:00
|
|
|
int i;
|
|
|
|
|
2007-05-30 10:10:43 -05:00
|
|
|
printf(_("\nDisk %s: %d heads, %llu sectors, %d cylinders\n\n"),
|
2006-12-06 17:25:32 -06:00
|
|
|
disk_device, heads, sectors, cylinders);
|
2006-12-06 17:26:12 -06:00
|
|
|
printf(_("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n"));
|
2006-12-06 17:25:43 -06:00
|
|
|
for (i = 0 ; i < partitions; i++) {
|
|
|
|
pe = &ptes[i];
|
|
|
|
p = (extend ? pe->ext_pointer : pe->part_table);
|
|
|
|
if (p != NULL) {
|
2007-05-30 10:10:43 -05:00
|
|
|
printf("%2d %02x%4d%4d%5d%4d%4d%5d%11lu%11lu %02x\n",
|
2006-12-06 17:25:32 -06:00
|
|
|
i + 1, p->boot_ind, p->head,
|
|
|
|
sector(p->sector),
|
|
|
|
cylinder(p->sector, p->cyl), p->end_head,
|
|
|
|
sector(p->end_sector),
|
|
|
|
cylinder(p->end_sector, p->end_cyl),
|
2007-05-30 10:10:43 -05:00
|
|
|
(unsigned long) get_start_sect(p),
|
|
|
|
(unsigned long) get_nr_sects(p), p->sys_ind);
|
2009-11-03 05:09:36 -06:00
|
|
|
if (p->sys_ind) {
|
2006-12-06 17:25:32 -06:00
|
|
|
check_consistency(p, i);
|
2010-02-09 03:32:29 -06:00
|
|
|
check_alignment(get_partition_start(pe), i);
|
2009-11-03 05:09:36 -06:00
|
|
|
}
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
2006-12-06 17:25:43 -06:00
|
|
|
}
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2007-05-30 10:10:43 -05:00
|
|
|
fill_bounds(unsigned long long *first, unsigned long long *last) {
|
2006-12-06 17:25:32 -06:00
|
|
|
int i;
|
2006-12-06 17:25:43 -06:00
|
|
|
struct pte *pe = &ptes[0];
|
|
|
|
struct partition *p;
|
2006-12-06 17:25:32 -06:00
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
for (i = 0; i < partitions; pe++,i++) {
|
|
|
|
p = pe->part_table;
|
2006-12-06 17:25:35 -06:00
|
|
|
if (!p->sys_ind || IS_EXTENDED (p->sys_ind)) {
|
2006-12-06 17:25:37 -06:00
|
|
|
first[i] = 0xffffffff;
|
2006-12-06 17:25:32 -06:00
|
|
|
last[i] = 0;
|
2006-12-06 17:25:35 -06:00
|
|
|
} else {
|
2006-12-06 17:25:43 -06:00
|
|
|
first[i] = get_partition_start(pe);
|
2006-12-06 17:25:37 -06:00
|
|
|
last[i] = first[i] + get_nr_sects(p) - 1;
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
2006-12-06 17:25:35 -06:00
|
|
|
}
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2006-12-06 17:26:12 -06:00
|
|
|
check(int n, unsigned int h, unsigned int s, unsigned int c,
|
|
|
|
unsigned int start) {
|
|
|
|
unsigned int total, real_s, real_c;
|
2006-12-06 17:25:32 -06:00
|
|
|
|
|
|
|
real_s = sector(s) - 1;
|
|
|
|
real_c = cylinder(s, c);
|
|
|
|
total = (real_c * sectors + real_s) * heads + h;
|
|
|
|
if (!total)
|
2006-12-06 17:25:39 -06:00
|
|
|
fprintf(stderr, _("Warning: partition %d contains sector 0\n"), n);
|
2006-12-06 17:25:32 -06:00
|
|
|
if (h >= heads)
|
|
|
|
fprintf(stderr,
|
2006-12-06 17:25:39 -06:00
|
|
|
_("Partition %d: head %d greater than maximum %d\n"),
|
2006-12-06 17:25:32 -06:00
|
|
|
n, h + 1, heads);
|
|
|
|
if (real_s >= sectors)
|
2006-12-06 17:25:39 -06:00
|
|
|
fprintf(stderr, _("Partition %d: sector %d greater than "
|
2007-05-30 10:10:43 -05:00
|
|
|
"maximum %llu\n"), n, s, sectors);
|
2006-12-06 17:25:32 -06:00
|
|
|
if (real_c >= cylinders)
|
2006-12-06 17:25:39 -06:00
|
|
|
fprintf(stderr, _("Partitions %d: cylinder %d greater than "
|
|
|
|
"maximum %d\n"), n, real_c + 1, cylinders);
|
2006-12-06 17:25:33 -06:00
|
|
|
if (cylinders <= 1024 && start != total)
|
2006-12-06 17:25:32 -06:00
|
|
|
fprintf(stderr,
|
2006-12-06 17:25:39 -06:00
|
|
|
_("Partition %d: previous sectors %d disagrees with "
|
|
|
|
"total %d\n"), n, start, total);
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
|
|
|
verify(void) {
|
2006-12-06 17:25:32 -06:00
|
|
|
int i, j;
|
2009-02-26 03:19:05 -06:00
|
|
|
unsigned long long total = 1;
|
2010-08-23 05:11:26 -05:00
|
|
|
unsigned long long n_sectors = total_number_of_sectors;
|
2007-05-30 10:10:43 -05:00
|
|
|
unsigned long long first[partitions], last[partitions];
|
2006-12-06 17:25:46 -06:00
|
|
|
struct partition *p;
|
2006-12-06 17:25:32 -06:00
|
|
|
|
|
|
|
if (warn_geometry())
|
|
|
|
return;
|
|
|
|
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel == SUN_LABEL) {
|
2006-12-06 17:25:35 -06:00
|
|
|
verify_sun();
|
2006-12-06 17:25:37 -06:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel == SGI_LABEL) {
|
2006-12-06 17:25:37 -06:00
|
|
|
verify_sgi(1);
|
|
|
|
return;
|
|
|
|
}
|
2006-12-06 17:25:35 -06:00
|
|
|
|
2006-12-06 17:25:37 -06:00
|
|
|
fill_bounds(first, last);
|
2006-12-06 17:25:43 -06:00
|
|
|
for (i = 0; i < partitions; i++) {
|
|
|
|
struct pte *pe = &ptes[i];
|
|
|
|
|
|
|
|
p = pe->part_table;
|
2006-12-06 17:25:35 -06:00
|
|
|
if (p->sys_ind && !IS_EXTENDED (p->sys_ind)) {
|
2006-12-06 17:25:32 -06:00
|
|
|
check_consistency(p, i);
|
2010-02-09 03:32:29 -06:00
|
|
|
check_alignment(get_partition_start(pe), i);
|
2006-12-06 17:25:43 -06:00
|
|
|
if (get_partition_start(pe) < first[i])
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("Warning: bad start-of-data in "
|
|
|
|
"partition %d\n"), i + 1);
|
2006-12-06 17:25:32 -06:00
|
|
|
check(i + 1, p->end_head, p->end_sector, p->end_cyl,
|
|
|
|
last[i]);
|
|
|
|
total += last[i] + 1 - first[i];
|
|
|
|
for (j = 0; j < i; j++)
|
2006-12-06 17:25:34 -06:00
|
|
|
if ((first[i] >= first[j] && first[i] <= last[j])
|
|
|
|
|| ((last[i] <= last[j] && last[i] >= first[j]))) {
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("Warning: partition %d overlaps "
|
|
|
|
"partition %d.\n"), j + 1, i + 1);
|
2006-12-06 17:25:32 -06:00
|
|
|
total += first[i] >= first[j] ?
|
|
|
|
first[i] : first[j];
|
|
|
|
total -= last[i] <= last[j] ?
|
|
|
|
last[i] : last[j];
|
|
|
|
}
|
|
|
|
}
|
2006-12-06 17:25:43 -06:00
|
|
|
}
|
2006-12-06 17:25:32 -06:00
|
|
|
|
|
|
|
if (extended_offset) {
|
2006-12-06 17:25:43 -06:00
|
|
|
struct pte *pex = &ptes[ext_index];
|
2007-05-30 10:10:43 -05:00
|
|
|
unsigned long long e_last = get_start_sect(pex->part_table) +
|
2006-12-06 17:25:43 -06:00
|
|
|
get_nr_sects(pex->part_table) - 1;
|
2006-12-06 17:25:32 -06:00
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
for (i = 4; i < partitions; i++) {
|
2006-12-06 17:25:32 -06:00
|
|
|
total++;
|
2006-12-06 17:25:43 -06:00
|
|
|
p = ptes[i].part_table;
|
2006-12-06 17:25:32 -06:00
|
|
|
if (!p->sys_ind) {
|
|
|
|
if (i != 4 || i + 1 < partitions)
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("Warning: partition %d "
|
|
|
|
"is empty\n"), i + 1);
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
else if (first[i] < extended_offset ||
|
|
|
|
last[i] > e_last)
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("Logical partition %d not entirely in "
|
|
|
|
"partition %d\n"), i + 1, ext_index + 1);
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-26 03:19:05 -06:00
|
|
|
if (total > n_sectors)
|
|
|
|
printf(_("Total allocated sectors %llu greater than the maximum"
|
|
|
|
" %llu\n"), total, n_sectors);
|
|
|
|
else if (total < n_sectors)
|
2009-12-10 06:04:41 -06:00
|
|
|
printf(_("Remaining %lld unallocated %d-byte sectors\n"),
|
2009-02-26 03:19:05 -06:00
|
|
|
n_sectors - total, sector_size);
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
|
fdisk: offer aligned first sector
Typical "new partition" dialog looks like:
Partition number (1-4): 1
First sector (4-818687, default 4):
^^^^^^^^^
The range (e.g. 4-818687) depends on fdisk mode (DOS/non-DOS), but the
default value should be always aligned.
For example RAID5 device in the DOS mode:
Disk /dev/md0: 419 MB, 419168256 bytes
2 heads, 4 sectors/track, 102336 cylinders, total 818688 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 65536 bytes
Disk identifier: 0x081479c3
....
Command (m for help): n
Command action
e extended
p primary partition (1-4)
p
Partition number (1-4): 1
First sector (4-818687, default 128): <---- !!!
Using default value 128
Last sector, +sectors or +size{K,M,G} (128-818687, default 818687): +10M
Command (m for help): p
....
Device Boot Start End Blocks Id System
/dev/md0p1 128 20607 10240 83 Linux
For non-DOS mode the range will be:
First sector (128-818687, default 128):
Signed-off-by: Karel Zak <kzak@redhat.com>
2009-11-04 08:14:04 -06:00
|
|
|
static unsigned long long
|
|
|
|
get_unused_start(int part_n,
|
|
|
|
unsigned long long start,
|
|
|
|
unsigned long long first[],
|
|
|
|
unsigned long long last[])
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < partitions; i++) {
|
|
|
|
unsigned long long lastplusoff;
|
|
|
|
|
|
|
|
if (start == ptes[i].offset)
|
|
|
|
start += sector_offset;
|
|
|
|
lastplusoff = last[i] + ((part_n < 4) ? 0 : sector_offset);
|
|
|
|
if (start >= first[i] && start <= lastplusoff)
|
|
|
|
start = lastplusoff + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return start;
|
|
|
|
}
|
|
|
|
|
2011-08-17 06:21:12 -05:00
|
|
|
void print_partition_size(int num, unsigned long long start, unsigned long long stop, int sysid)
|
|
|
|
{
|
|
|
|
char *str = size_to_human_string(SIZE_SUFFIX_3LETTER | SIZE_SUFFIX_SPACE,
|
|
|
|
(stop - start + 1) * sector_size);
|
|
|
|
printf(_("Partition %d of type %s and of size %s is set\n"), num, partition_type(sysid), str);
|
|
|
|
free(str);
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
|
|
|
add_partition(int n, int sys) {
|
2006-12-06 17:25:41 -06:00
|
|
|
char mesg[256]; /* 48 does not suffice in Japanese */
|
2006-12-06 17:25:32 -06:00
|
|
|
int i, read = 0;
|
2006-12-06 17:25:43 -06:00
|
|
|
struct partition *p = ptes[n].part_table;
|
|
|
|
struct partition *q = ptes[ext_index].part_table;
|
2007-05-30 10:10:43 -05:00
|
|
|
unsigned long long start, stop = 0, limit, temp,
|
2006-12-06 17:25:32 -06:00
|
|
|
first[partitions], last[partitions];
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
if (p && p->sys_ind) {
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("Partition %d is already defined. Delete "
|
2006-12-06 17:25:48 -06:00
|
|
|
"it before re-adding it.\n"), n + 1);
|
2006-12-06 17:25:32 -06:00
|
|
|
return;
|
|
|
|
}
|
2006-12-06 17:25:37 -06:00
|
|
|
fill_bounds(first, last);
|
2006-12-06 17:25:32 -06:00
|
|
|
if (n < 4) {
|
|
|
|
start = sector_offset;
|
2006-12-06 17:26:12 -06:00
|
|
|
if (display_in_cyl_units || !total_number_of_sectors)
|
2011-08-01 08:19:53 -05:00
|
|
|
limit = heads * sectors * cylinders - 1;
|
2006-12-06 17:26:03 -06:00
|
|
|
else
|
2011-08-01 08:19:53 -05:00
|
|
|
limit = total_number_of_sectors - 1;
|
|
|
|
|
|
|
|
if (limit > UINT_MAX)
|
|
|
|
limit = UINT_MAX;
|
|
|
|
|
2006-12-06 17:25:32 -06:00
|
|
|
if (extended_offset) {
|
|
|
|
first[ext_index] = extended_offset;
|
2006-12-06 17:25:35 -06:00
|
|
|
last[ext_index] = get_start_sect(q) +
|
|
|
|
get_nr_sects(q) - 1;
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
2006-12-06 17:25:35 -06:00
|
|
|
} else {
|
2006-12-06 17:25:32 -06:00
|
|
|
start = extended_offset + sector_offset;
|
2006-12-06 17:25:35 -06:00
|
|
|
limit = get_start_sect(q) + get_nr_sects(q) - 1;
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
2006-12-06 17:25:39 -06:00
|
|
|
if (display_in_cyl_units)
|
2006-12-06 17:25:32 -06:00
|
|
|
for (i = 0; i < partitions; i++)
|
2006-12-06 17:25:39 -06:00
|
|
|
first[i] = (cround(first[i]) - 1) * units_per_sector;
|
2006-12-06 17:25:32 -06:00
|
|
|
|
2006-12-06 17:25:46 -06:00
|
|
|
snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
|
2006-12-06 17:25:32 -06:00
|
|
|
do {
|
2010-02-09 04:06:42 -06:00
|
|
|
unsigned long long dflt, aligned;
|
fdisk: offer aligned first sector
Typical "new partition" dialog looks like:
Partition number (1-4): 1
First sector (4-818687, default 4):
^^^^^^^^^
The range (e.g. 4-818687) depends on fdisk mode (DOS/non-DOS), but the
default value should be always aligned.
For example RAID5 device in the DOS mode:
Disk /dev/md0: 419 MB, 419168256 bytes
2 heads, 4 sectors/track, 102336 cylinders, total 818688 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 65536 bytes
Disk identifier: 0x081479c3
....
Command (m for help): n
Command action
e extended
p primary partition (1-4)
p
Partition number (1-4): 1
First sector (4-818687, default 128): <---- !!!
Using default value 128
Last sector, +sectors or +size{K,M,G} (128-818687, default 818687): +10M
Command (m for help): p
....
Device Boot Start End Blocks Id System
/dev/md0p1 128 20607 10240 83 Linux
For non-DOS mode the range will be:
First sector (128-818687, default 128):
Signed-off-by: Karel Zak <kzak@redhat.com>
2009-11-04 08:14:04 -06:00
|
|
|
|
2006-12-06 17:25:32 -06:00
|
|
|
temp = start;
|
fdisk: offer aligned first sector
Typical "new partition" dialog looks like:
Partition number (1-4): 1
First sector (4-818687, default 4):
^^^^^^^^^
The range (e.g. 4-818687) depends on fdisk mode (DOS/non-DOS), but the
default value should be always aligned.
For example RAID5 device in the DOS mode:
Disk /dev/md0: 419 MB, 419168256 bytes
2 heads, 4 sectors/track, 102336 cylinders, total 818688 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 65536 bytes
Disk identifier: 0x081479c3
....
Command (m for help): n
Command action
e extended
p primary partition (1-4)
p
Partition number (1-4): 1
First sector (4-818687, default 128): <---- !!!
Using default value 128
Last sector, +sectors or +size{K,M,G} (128-818687, default 818687): +10M
Command (m for help): p
....
Device Boot Start End Blocks Id System
/dev/md0p1 128 20607 10240 83 Linux
For non-DOS mode the range will be:
First sector (128-818687, default 128):
Signed-off-by: Karel Zak <kzak@redhat.com>
2009-11-04 08:14:04 -06:00
|
|
|
dflt = start = get_unused_start(n, start, first, last);
|
|
|
|
|
|
|
|
/* the default sector should be aligned and unused */
|
|
|
|
do {
|
2010-02-09 04:06:42 -06:00
|
|
|
aligned = align_lba_in_range(dflt, dflt, limit);
|
|
|
|
dflt = get_unused_start(n, aligned, first, last);
|
|
|
|
} while (dflt != aligned && dflt > aligned && dflt < limit);
|
fdisk: offer aligned first sector
Typical "new partition" dialog looks like:
Partition number (1-4): 1
First sector (4-818687, default 4):
^^^^^^^^^
The range (e.g. 4-818687) depends on fdisk mode (DOS/non-DOS), but the
default value should be always aligned.
For example RAID5 device in the DOS mode:
Disk /dev/md0: 419 MB, 419168256 bytes
2 heads, 4 sectors/track, 102336 cylinders, total 818688 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 65536 bytes
Disk identifier: 0x081479c3
....
Command (m for help): n
Command action
e extended
p primary partition (1-4)
p
Partition number (1-4): 1
First sector (4-818687, default 128): <---- !!!
Using default value 128
Last sector, +sectors or +size{K,M,G} (128-818687, default 818687): +10M
Command (m for help): p
....
Device Boot Start End Blocks Id System
/dev/md0p1 128 20607 10240 83 Linux
For non-DOS mode the range will be:
First sector (128-818687, default 128):
Signed-off-by: Karel Zak <kzak@redhat.com>
2009-11-04 08:14:04 -06:00
|
|
|
|
|
|
|
if (dflt >= limit)
|
|
|
|
dflt = start;
|
2006-12-06 17:25:32 -06:00
|
|
|
if (start > limit)
|
|
|
|
break;
|
2006-12-06 17:25:39 -06:00
|
|
|
if (start >= temp+units_per_sector && read) {
|
2007-05-30 10:10:43 -05:00
|
|
|
printf(_("Sector %llu is already allocated\n"), temp);
|
2006-12-06 17:25:35 -06:00
|
|
|
temp = start;
|
2006-12-06 17:25:32 -06:00
|
|
|
read = 0;
|
|
|
|
}
|
|
|
|
if (!read && start == temp) {
|
2008-11-13 08:37:22 -06:00
|
|
|
unsigned long long i = start;
|
2006-12-06 17:26:12 -06:00
|
|
|
|
fdisk: offer aligned first sector
Typical "new partition" dialog looks like:
Partition number (1-4): 1
First sector (4-818687, default 4):
^^^^^^^^^
The range (e.g. 4-818687) depends on fdisk mode (DOS/non-DOS), but the
default value should be always aligned.
For example RAID5 device in the DOS mode:
Disk /dev/md0: 419 MB, 419168256 bytes
2 heads, 4 sectors/track, 102336 cylinders, total 818688 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 65536 bytes
Disk identifier: 0x081479c3
....
Command (m for help): n
Command action
e extended
p primary partition (1-4)
p
Partition number (1-4): 1
First sector (4-818687, default 128): <---- !!!
Using default value 128
Last sector, +sectors or +size{K,M,G} (128-818687, default 818687): +10M
Command (m for help): p
....
Device Boot Start End Blocks Id System
/dev/md0p1 128 20607 10240 83 Linux
For non-DOS mode the range will be:
First sector (128-818687, default 128):
Signed-off-by: Karel Zak <kzak@redhat.com>
2009-11-04 08:14:04 -06:00
|
|
|
start = read_int(cround(i), cround(dflt), cround(limit),
|
2006-12-06 17:25:37 -06:00
|
|
|
0, mesg);
|
2006-12-06 17:25:39 -06:00
|
|
|
if (display_in_cyl_units) {
|
|
|
|
start = (start - 1) * units_per_sector;
|
2006-12-06 17:25:32 -06:00
|
|
|
if (start < i) start = i;
|
2006-12-06 17:25:35 -06:00
|
|
|
}
|
2006-12-06 17:25:32 -06:00
|
|
|
read = 1;
|
|
|
|
}
|
|
|
|
} while (start != temp || !read);
|
2006-12-06 17:25:39 -06:00
|
|
|
if (n > 4) { /* NOT for fifth partition */
|
2006-12-06 17:25:43 -06:00
|
|
|
struct pte *pe = &ptes[n];
|
|
|
|
|
|
|
|
pe->offset = start - sector_offset;
|
|
|
|
if (pe->offset == extended_offset) { /* must be corrected */
|
2006-12-06 17:25:48 -06:00
|
|
|
pe->offset++;
|
|
|
|
if (sector_offset == 1)
|
|
|
|
start++;
|
2006-12-06 17:25:39 -06:00
|
|
|
}
|
|
|
|
}
|
2006-12-06 17:25:32 -06:00
|
|
|
|
|
|
|
for (i = 0; i < partitions; i++) {
|
2006-12-06 17:25:43 -06:00
|
|
|
struct pte *pe = &ptes[i];
|
|
|
|
|
|
|
|
if (start < pe->offset && limit >= pe->offset)
|
|
|
|
limit = pe->offset - 1;
|
2006-12-06 17:25:32 -06:00
|
|
|
if (start < first[i] && limit >= first[i])
|
|
|
|
limit = first[i] - 1;
|
|
|
|
}
|
|
|
|
if (start > limit) {
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("No free sectors available\n"));
|
2006-12-06 17:25:43 -06:00
|
|
|
if (n > 4)
|
2006-12-06 17:25:32 -06:00
|
|
|
partitions--;
|
|
|
|
return;
|
|
|
|
}
|
2006-12-06 17:25:39 -06:00
|
|
|
if (cround(start) == cround(limit)) {
|
|
|
|
stop = limit;
|
|
|
|
} else {
|
2009-11-04 07:30:31 -06:00
|
|
|
int sx = 0;
|
|
|
|
|
2006-12-06 17:25:46 -06:00
|
|
|
snprintf(mesg, sizeof(mesg),
|
2007-12-12 18:06:44 -06:00
|
|
|
_("Last %1$s, +%2$s or +size{K,M,G}"),
|
|
|
|
str_units(SINGULAR), str_units(PLURAL));
|
|
|
|
|
2009-11-04 07:30:31 -06:00
|
|
|
stop = read_int_sx(cround(start), cround(limit), cround(limit),
|
|
|
|
cround(start), mesg, &sx);
|
2006-12-06 17:25:39 -06:00
|
|
|
if (display_in_cyl_units) {
|
|
|
|
stop = stop * units_per_sector - 1;
|
2006-12-06 17:25:32 -06:00
|
|
|
if (stop >limit)
|
|
|
|
stop = limit;
|
|
|
|
}
|
2009-11-04 07:30:31 -06:00
|
|
|
|
|
|
|
if (sx && alignment_required) {
|
|
|
|
/* the last sector has not been exactly requested (but
|
|
|
|
* defined by +size{K,M,G} convention), so be smart
|
|
|
|
* and align the end of the partition. The next
|
|
|
|
* partition will start at phy.block boundary.
|
|
|
|
*/
|
|
|
|
stop = align_lba_in_range(stop, start, limit) - 1;
|
|
|
|
if (stop > limit)
|
|
|
|
stop = limit;
|
|
|
|
}
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:48 -06:00
|
|
|
set_partition(n, 0, start, stop, sys);
|
|
|
|
if (n > 4)
|
|
|
|
set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
|
2006-12-06 17:25:32 -06:00
|
|
|
|
2006-12-06 17:25:35 -06:00
|
|
|
if (IS_EXTENDED (sys)) {
|
2006-12-06 17:25:43 -06:00
|
|
|
struct pte *pe4 = &ptes[4];
|
|
|
|
struct pte *pen = &ptes[n];
|
|
|
|
|
2006-12-06 17:25:32 -06:00
|
|
|
ext_index = n;
|
2006-12-06 17:25:43 -06:00
|
|
|
pen->ext_pointer = p;
|
|
|
|
pe4->offset = extended_offset = start;
|
2011-01-23 15:51:21 -06:00
|
|
|
pe4->sectorbuffer = xcalloc(1, sector_size);
|
2006-12-06 17:25:43 -06:00
|
|
|
pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
|
|
|
|
pe4->ext_pointer = pe4->part_table + 1;
|
|
|
|
pe4->changed = 1;
|
2006-12-06 17:25:32 -06:00
|
|
|
partitions = 5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
|
|
|
add_logical(void) {
|
|
|
|
if (partitions > 5 || ptes[4].part_table->sys_ind) {
|
|
|
|
struct pte *pe = &ptes[partitions];
|
|
|
|
|
2011-01-23 15:51:21 -06:00
|
|
|
pe->sectorbuffer = xcalloc(1, sector_size);
|
2006-12-06 17:25:43 -06:00
|
|
|
pe->part_table = pt_offset(pe->sectorbuffer, 0);
|
|
|
|
pe->ext_pointer = pe->part_table + 1;
|
|
|
|
pe->offset = 0;
|
|
|
|
pe->changed = 1;
|
2006-12-06 17:25:32 -06:00
|
|
|
partitions++;
|
|
|
|
}
|
2011-05-10 07:13:14 -05:00
|
|
|
printf(_("Adding logical partition %d\n"), partitions);
|
2006-12-06 17:25:32 -06:00
|
|
|
add_partition(partitions - 1, LINUX_NATIVE);
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
|
|
|
new_partition(void) {
|
2006-12-06 17:25:32 -06:00
|
|
|
int i, free_primary = 0;
|
|
|
|
|
|
|
|
if (warn_geometry())
|
|
|
|
return;
|
2006-12-06 17:25:35 -06:00
|
|
|
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel == SUN_LABEL) {
|
2006-12-06 17:25:35 -06:00
|
|
|
add_sun_partition(get_partition(0, partitions), LINUX_NATIVE);
|
2006-12-06 17:25:37 -06:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel == SGI_LABEL) {
|
2006-12-06 17:25:37 -06:00
|
|
|
sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE);
|
|
|
|
return;
|
|
|
|
}
|
2006-12-06 17:25:35 -06:00
|
|
|
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel == AIX_LABEL) {
|
2006-12-06 17:25:49 -06:00
|
|
|
printf(_("\tSorry - this fdisk cannot handle AIX disk labels."
|
|
|
|
"\n\tIf you want to add DOS-type partitions, create"
|
|
|
|
"\n\ta new empty DOS partition table first. (Use o.)"
|
|
|
|
"\n\tWARNING: "
|
|
|
|
"This will destroy the present disk contents.\n"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel == MAC_LABEL) {
|
2007-06-27 16:49:56 -05:00
|
|
|
printf(_("\tSorry - this fdisk cannot handle Mac disk labels."
|
|
|
|
"\n\tIf you want to add DOS-type partitions, create"
|
|
|
|
"\n\ta new empty DOS partition table first. (Use o.)"
|
|
|
|
"\n\tWARNING: "
|
|
|
|
"This will destroy the present disk contents.\n"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:26:05 -06:00
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
free_primary += !ptes[i].part_table->sys_ind;
|
|
|
|
|
|
|
|
if (!free_primary && partitions >= MAXIMUM_PARTS) {
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("The maximum number of partitions has been created\n"));
|
2006-12-06 17:25:32 -06:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:37 -06:00
|
|
|
if (!free_primary) {
|
2011-05-10 07:13:14 -05:00
|
|
|
if (extended_offset) {
|
|
|
|
printf(_("All primary partitions are in use\n"));
|
2006-12-06 17:25:32 -06:00
|
|
|
add_logical();
|
2011-05-10 07:13:14 -05:00
|
|
|
} else
|
2011-04-28 16:39:30 -05:00
|
|
|
printf(_("If you want to create more than four partitions, you must replace a\n"
|
|
|
|
"primary partition with an extended partition first.\n"));
|
2006-12-06 17:26:14 -06:00
|
|
|
} else if (partitions >= MAXIMUM_PARTS) {
|
|
|
|
printf(_("All logical partitions are in use\n"));
|
|
|
|
printf(_("Adding a primary partition\n"));
|
|
|
|
add_partition(get_partition(0, 4), LINUX_NATIVE);
|
2006-12-06 17:25:37 -06:00
|
|
|
} else {
|
2011-05-06 10:23:32 -05:00
|
|
|
char c, dflt, line[LINE_LENGTH];
|
|
|
|
|
2011-05-06 10:23:33 -05:00
|
|
|
dflt = (free_primary == 1 && !extended_offset) ? 'e' : 'p';
|
2006-12-06 17:25:46 -06:00
|
|
|
snprintf(line, sizeof(line),
|
2011-05-06 10:23:31 -05:00
|
|
|
_("Partition type:\n"
|
|
|
|
" p primary (%d primary, %d extended, %d free)\n"
|
|
|
|
"%s\n"
|
2011-05-06 10:23:32 -05:00
|
|
|
"Select (default %c): "),
|
2011-05-06 10:23:31 -05:00
|
|
|
4 - (extended_offset ? 1 : 0) - free_primary, extended_offset ? 1 : 0, free_primary,
|
2011-05-06 10:23:32 -05:00
|
|
|
extended_offset ? _(" l logical (numbered from 5)") : _(" e extended"),
|
|
|
|
dflt);
|
2011-05-06 10:23:31 -05:00
|
|
|
|
2011-05-06 10:23:33 -05:00
|
|
|
c = tolower(read_chars(line));
|
|
|
|
if (c == '\n') {
|
|
|
|
c = dflt;
|
|
|
|
printf(_("Using default response %c\n"), c);
|
2006-12-06 17:25:46 -06:00
|
|
|
}
|
2011-05-06 10:23:33 -05:00
|
|
|
if (c == 'p') {
|
|
|
|
int i = get_nonexisting_partition(0, 4);
|
|
|
|
if (i >= 0)
|
|
|
|
add_partition(i, LINUX_NATIVE);
|
|
|
|
return;
|
|
|
|
} else if (c == 'l' && extended_offset) {
|
|
|
|
add_logical();
|
|
|
|
return;
|
|
|
|
} else if (c == 'e' && !extended_offset) {
|
|
|
|
int i = get_nonexisting_partition(0, 4);
|
|
|
|
if (i >= 0)
|
|
|
|
add_partition(i, EXTENDED);
|
|
|
|
return;
|
|
|
|
} else
|
|
|
|
printf(_("Invalid partition type `%c'\n"), c);
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
|
|
|
write_table(void) {
|
2006-12-06 17:25:41 -06:00
|
|
|
int i;
|
2006-12-06 17:25:32 -06:00
|
|
|
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel == DOS_LABEL) {
|
2010-08-09 06:03:02 -05:00
|
|
|
/* MBR (primary partitions) */
|
|
|
|
if (!MBRbuffer_changed) {
|
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
if (ptes[i].changed)
|
|
|
|
MBRbuffer_changed = 1;
|
|
|
|
}
|
|
|
|
if (MBRbuffer_changed) {
|
|
|
|
write_part_table_flag(MBRbuffer);
|
|
|
|
write_sector(fd, 0, MBRbuffer);
|
|
|
|
}
|
|
|
|
/* EBR (logical partitions) */
|
|
|
|
for (i = 4; i < partitions; i++) {
|
2006-12-06 17:25:43 -06:00
|
|
|
struct pte *pe = &ptes[i];
|
|
|
|
|
|
|
|
if (pe->changed) {
|
|
|
|
write_part_table_flag(pe->sectorbuffer);
|
|
|
|
write_sector(fd, pe->offset, pe->sectorbuffer);
|
|
|
|
}
|
2006-12-06 17:25:35 -06:00
|
|
|
}
|
2006-12-06 17:25:56 -06:00
|
|
|
}
|
2011-07-03 05:01:21 -05:00
|
|
|
else if (disklabel == SGI_LABEL) {
|
2006-12-06 17:25:43 -06:00
|
|
|
/* no test on change? the printf below might be mistaken */
|
|
|
|
sgi_write_table();
|
2011-07-03 05:01:21 -05:00
|
|
|
} else if (disklabel == SUN_LABEL) {
|
2006-12-06 17:25:43 -06:00
|
|
|
int needw = 0;
|
|
|
|
|
|
|
|
for (i=0; i<8; i++)
|
2006-12-06 17:25:58 -06:00
|
|
|
if (ptes[i].changed)
|
2006-12-06 17:25:43 -06:00
|
|
|
needw = 1;
|
|
|
|
if (needw)
|
|
|
|
sun_write_table();
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("The partition table has been altered!\n\n"));
|
2006-12-06 17:25:41 -06:00
|
|
|
reread_partition_table(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
reread_partition_table(int leave) {
|
|
|
|
int i;
|
2007-09-03 17:10:16 -05:00
|
|
|
struct stat statbuf;
|
2006-12-06 17:25:32 -06:00
|
|
|
|
2007-09-03 17:10:16 -05:00
|
|
|
i = fstat(fd, &statbuf);
|
|
|
|
if (i == 0 && S_ISBLK(statbuf.st_mode)) {
|
|
|
|
sync();
|
2008-07-23 17:46:05 -05:00
|
|
|
#ifdef BLKRRPART
|
|
|
|
printf(_("Calling ioctl() to re-read partition table.\n"));
|
2007-09-03 17:10:16 -05:00
|
|
|
i = ioctl(fd, BLKRRPART);
|
2008-07-23 17:46:05 -05:00
|
|
|
#else
|
|
|
|
errno = ENOSYS;
|
|
|
|
i = 1;
|
|
|
|
#endif
|
2006-12-06 17:25:33 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:49 -06:00
|
|
|
if (i) {
|
2011-09-22 05:12:37 -05:00
|
|
|
printf(_("\nWARNING: Re-reading the partition table failed with error %d: %m.\n"
|
2008-09-16 06:08:12 -05:00
|
|
|
"The kernel still uses the old table. The new table will be used at\n"
|
|
|
|
"the next reboot or after you run partprobe(8) or kpartx(8)\n"),
|
2011-09-22 05:12:37 -05:00
|
|
|
errno);
|
2006-12-06 17:25:49 -06:00
|
|
|
}
|
2006-12-06 17:25:32 -06:00
|
|
|
|
2006-12-06 17:25:49 -06:00
|
|
|
if (dos_changed)
|
2006-12-06 17:25:35 -06:00
|
|
|
printf(
|
2006-12-06 17:25:39 -06:00
|
|
|
_("\nWARNING: If you have created or modified any DOS 6.x\n"
|
2006-12-06 17:25:32 -06:00
|
|
|
"partitions, please see the fdisk manual page for additional\n"
|
2006-12-06 17:25:39 -06:00
|
|
|
"information.\n"));
|
2006-12-06 17:25:32 -06:00
|
|
|
|
2006-12-06 17:25:41 -06:00
|
|
|
if (leave) {
|
2006-12-06 17:26:30 -06:00
|
|
|
if (fsync(fd) || close(fd)) {
|
|
|
|
fprintf(stderr, _("\nError closing file\n"));
|
|
|
|
exit(1);
|
|
|
|
}
|
2006-12-06 17:25:41 -06:00
|
|
|
|
|
|
|
printf(_("Syncing disks.\n"));
|
|
|
|
sync();
|
|
|
|
exit(!!i);
|
|
|
|
}
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#define MAX_PER_LINE 16
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2007-05-30 10:10:43 -05:00
|
|
|
print_buffer(unsigned char pbuffer[]) {
|
2011-08-01 08:19:53 -05:00
|
|
|
unsigned int i, l;
|
2006-12-06 17:25:32 -06:00
|
|
|
|
2006-12-06 17:25:37 -06:00
|
|
|
for (i = 0, l = 0; i < sector_size; i++, l++) {
|
2006-12-06 17:25:32 -06:00
|
|
|
if (l == 0)
|
|
|
|
printf("0x%03X:", i);
|
2007-05-30 10:10:43 -05:00
|
|
|
printf(" %02X", pbuffer[i]);
|
2006-12-06 17:25:32 -06:00
|
|
|
if (l == MAX_PER_LINE - 1) {
|
|
|
|
printf("\n");
|
|
|
|
l = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (l > 0)
|
|
|
|
printf("\n");
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
|
|
|
print_raw(void) {
|
2006-12-06 17:25:32 -06:00
|
|
|
int i;
|
|
|
|
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("Device: %s\n"), disk_device);
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel == SUN_LABEL || disklabel == SGI_LABEL)
|
2006-12-06 17:25:43 -06:00
|
|
|
print_buffer(MBRbuffer);
|
2006-12-06 17:25:35 -06:00
|
|
|
else for (i = 3; i < partitions; i++)
|
2006-12-06 17:25:43 -06:00
|
|
|
print_buffer(ptes[i].sectorbuffer);
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
|
|
|
move_begin(int i) {
|
|
|
|
struct pte *pe = &ptes[i];
|
|
|
|
struct partition *p = pe->part_table;
|
2010-04-28 07:40:46 -05:00
|
|
|
unsigned int new, free_start, curr_start, last;
|
|
|
|
int x;
|
2006-12-06 17:25:32 -06:00
|
|
|
|
|
|
|
if (warn_geometry())
|
|
|
|
return;
|
2006-12-06 17:25:35 -06:00
|
|
|
if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED (p->sys_ind)) {
|
2006-12-06 17:25:39 -06:00
|
|
|
printf(_("Partition %d has no data area\n"), i + 1);
|
2006-12-06 17:25:32 -06:00
|
|
|
return;
|
|
|
|
}
|
2010-04-28 07:40:46 -05:00
|
|
|
|
|
|
|
/* the default start is at the second sector of the disk or at the
|
|
|
|
* second sector of the extended partition
|
|
|
|
*/
|
|
|
|
free_start = pe->offset ? pe->offset + 1 : 1;
|
|
|
|
|
|
|
|
curr_start = get_partition_start(pe);
|
|
|
|
|
|
|
|
/* look for a free space before the current start of the partition */
|
|
|
|
for (x = 0; x < partitions; x++) {
|
|
|
|
unsigned int end;
|
|
|
|
struct pte *prev_pe = &ptes[x];
|
|
|
|
struct partition *prev_p = prev_pe->part_table;
|
|
|
|
|
|
|
|
if (!prev_p)
|
|
|
|
continue;
|
|
|
|
end = get_partition_start(prev_pe) + get_nr_sects(prev_p);
|
|
|
|
|
|
|
|
if (!is_cleared_partition(prev_p) &&
|
|
|
|
end > free_start && end <= curr_start)
|
|
|
|
free_start = end;
|
|
|
|
}
|
|
|
|
|
|
|
|
last = get_partition_start(pe) + get_nr_sects(p) - 1;
|
|
|
|
|
|
|
|
new = read_int(free_start, curr_start, last, free_start,
|
2006-12-06 17:25:43 -06:00
|
|
|
_("New beginning of data")) - pe->offset;
|
2006-12-06 17:25:32 -06:00
|
|
|
|
2006-12-06 17:25:35 -06:00
|
|
|
if (new != get_nr_sects(p)) {
|
2010-04-28 07:40:46 -05:00
|
|
|
unsigned int sects = get_nr_sects(p) + get_start_sect(p) - new;
|
|
|
|
set_nr_sects(p, sects);
|
2006-12-06 17:25:35 -06:00
|
|
|
set_start_sect(p, new);
|
2006-12-06 17:25:43 -06:00
|
|
|
pe->changed = 1;
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2011-11-11 04:12:08 -06:00
|
|
|
expert_command_prompt(void)
|
|
|
|
{
|
2006-12-06 17:25:43 -06:00
|
|
|
char c;
|
|
|
|
|
2006-12-06 17:25:32 -06:00
|
|
|
while(1) {
|
|
|
|
putchar('\n');
|
2006-12-06 17:25:43 -06:00
|
|
|
c = tolower(read_char(_("Expert command (m for help): ")));
|
|
|
|
switch (c) {
|
2006-12-06 17:25:35 -06:00
|
|
|
case 'a':
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel == SUN_LABEL)
|
2006-12-06 17:25:35 -06:00
|
|
|
sun_set_alt_cyl();
|
|
|
|
break;
|
|
|
|
case 'b':
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel == DOS_LABEL)
|
2006-12-06 17:25:35 -06:00
|
|
|
move_begin(get_partition(0, partitions));
|
|
|
|
break;
|
|
|
|
case 'c':
|
2006-12-06 17:25:43 -06:00
|
|
|
user_cylinders = cylinders =
|
2006-12-06 17:25:56 -06:00
|
|
|
read_int(1, cylinders, 1048576, 0,
|
2006-12-06 17:25:43 -06:00
|
|
|
_("Number of cylinders"));
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel == SUN_LABEL)
|
2006-12-06 17:25:35 -06:00
|
|
|
sun_set_ncyl(cylinders);
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
print_raw();
|
|
|
|
break;
|
|
|
|
case 'e':
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel == SGI_LABEL)
|
2006-12-06 17:25:37 -06:00
|
|
|
sgi_set_xcyl();
|
2011-07-03 05:01:21 -05:00
|
|
|
else if (disklabel == SUN_LABEL)
|
2006-12-06 17:25:35 -06:00
|
|
|
sun_set_xcyl();
|
2006-12-06 17:25:56 -06:00
|
|
|
else
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel == DOS_LABEL)
|
2006-12-06 17:25:37 -06:00
|
|
|
x_list_table(1);
|
|
|
|
break;
|
2006-12-06 17:25:43 -06:00
|
|
|
case 'f':
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel == DOS_LABEL)
|
2006-12-06 17:25:43 -06:00
|
|
|
fix_partition_table_order();
|
|
|
|
break;
|
2006-12-06 17:25:37 -06:00
|
|
|
case 'g':
|
|
|
|
create_sgilabel();
|
2006-12-06 17:25:35 -06:00
|
|
|
break;
|
|
|
|
case 'h':
|
2006-12-06 17:25:43 -06:00
|
|
|
user_heads = heads = read_int(1, heads, 256, 0,
|
2006-12-06 17:25:39 -06:00
|
|
|
_("Number of heads"));
|
2006-12-06 17:25:35 -06:00
|
|
|
update_units();
|
|
|
|
break;
|
|
|
|
case 'i':
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel == SUN_LABEL)
|
2006-12-06 17:25:35 -06:00
|
|
|
sun_set_ilfact();
|
2011-07-03 05:01:21 -05:00
|
|
|
else if (disklabel == DOS_LABEL)
|
2007-07-06 20:32:31 -05:00
|
|
|
dos_set_mbr_id();
|
2006-12-06 17:25:35 -06:00
|
|
|
break;
|
|
|
|
case 'o':
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel == SUN_LABEL)
|
2006-12-06 17:25:35 -06:00
|
|
|
sun_set_rspeed();
|
|
|
|
break;
|
|
|
|
case 'p':
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel == SUN_LABEL)
|
2006-12-06 17:25:35 -06:00
|
|
|
list_table(1);
|
|
|
|
else
|
|
|
|
x_list_table(0);
|
|
|
|
break;
|
|
|
|
case 'q':
|
|
|
|
close(fd);
|
2006-12-06 17:25:39 -06:00
|
|
|
printf("\n");
|
2006-12-06 17:25:35 -06:00
|
|
|
exit(0);
|
|
|
|
case 'r':
|
|
|
|
return;
|
|
|
|
case 's':
|
2006-12-06 17:25:43 -06:00
|
|
|
user_sectors = sectors = read_int(1, sectors, 63, 0,
|
2006-12-06 17:25:39 -06:00
|
|
|
_("Number of sectors"));
|
2009-11-03 04:28:55 -06:00
|
|
|
if (dos_compatible_flag)
|
2006-12-06 17:25:39 -06:00
|
|
|
fprintf(stderr, _("Warning: setting "
|
2006-12-06 17:25:35 -06:00
|
|
|
"sector offset for DOS "
|
2006-12-06 17:25:39 -06:00
|
|
|
"compatiblity\n"));
|
2009-11-03 04:28:55 -06:00
|
|
|
update_sector_offset();
|
2006-12-06 17:25:35 -06:00
|
|
|
update_units();
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
verify();
|
|
|
|
break;
|
|
|
|
case 'w':
|
|
|
|
write_table(); /* does not return */
|
|
|
|
break;
|
|
|
|
case 'y':
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel == SUN_LABEL)
|
2006-12-06 17:25:35 -06:00
|
|
|
sun_set_pcylcount();
|
|
|
|
break;
|
|
|
|
default:
|
2011-11-09 12:04:12 -06:00
|
|
|
print_menu(EXPERT_MENU);
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static int
|
2006-12-06 17:25:49 -06:00
|
|
|
is_ide_cdrom_or_tape(char *device) {
|
|
|
|
FILE *procf;
|
|
|
|
char buf[100];
|
|
|
|
struct stat statbuf;
|
|
|
|
int is_ide = 0;
|
|
|
|
|
2006-12-06 17:25:35 -06:00
|
|
|
/* No device was given explicitly, and we are trying some
|
2006-12-06 17:25:49 -06:00
|
|
|
likely things. But opening /dev/hdc may produce errors like
|
2006-12-06 17:25:35 -06:00
|
|
|
"hdc: tray open or drive not ready"
|
2006-12-06 17:25:49 -06:00
|
|
|
if it happens to be a CD-ROM drive. It even happens that
|
|
|
|
the process hangs on the attempt to read a music CD.
|
|
|
|
So try to be careful. This only works since 2.1.73. */
|
2006-12-06 17:25:35 -06:00
|
|
|
|
2006-12-06 17:25:49 -06:00
|
|
|
if (strncmp("/dev/hd", device, 7))
|
|
|
|
return 0;
|
2006-12-06 17:25:35 -06:00
|
|
|
|
2006-12-06 17:25:49 -06:00
|
|
|
snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
|
|
|
|
procf = fopen(buf, "r");
|
|
|
|
if (procf != NULL && fgets(buf, sizeof(buf), procf))
|
|
|
|
is_ide = (!strncmp(buf, "cdrom", 5) ||
|
|
|
|
!strncmp(buf, "tape", 4));
|
|
|
|
else
|
|
|
|
/* Now when this proc file does not exist, skip the
|
|
|
|
device when it is read-only. */
|
|
|
|
if (stat(device, &statbuf) == 0)
|
|
|
|
is_ide = ((statbuf.st_mode & 0222) == 0);
|
2006-12-06 17:25:35 -06:00
|
|
|
|
2006-12-06 17:25:49 -06:00
|
|
|
if (procf)
|
|
|
|
fclose(procf);
|
|
|
|
return is_ide;
|
2006-12-06 17:25:35 -06:00
|
|
|
}
|
|
|
|
|
2007-05-31 07:31:51 -05:00
|
|
|
static void
|
|
|
|
gpt_warning(char *dev)
|
|
|
|
{
|
|
|
|
if (dev && gpt_probe_signature_devname(dev))
|
|
|
|
fprintf(stderr, _("\nWARNING: GPT (GUID Partition Table) detected on '%s'! "
|
|
|
|
"The util fdisk doesn't support GPT. Use GNU Parted.\n\n"), dev);
|
|
|
|
}
|
|
|
|
|
2011-12-15 13:02:41 -06:00
|
|
|
/* Print disk geometry and partition table of a specified device (-l option) */
|
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2011-12-15 13:02:41 -06:00
|
|
|
print_partition_table_from_option(char *device)
|
2011-12-15 13:02:40 -06:00
|
|
|
{
|
2006-12-06 17:25:49 -06:00
|
|
|
int gb;
|
|
|
|
|
2006-12-06 17:25:32 -06:00
|
|
|
disk_device = device;
|
2006-12-06 17:25:46 -06:00
|
|
|
if (setjmp(listingbuf))
|
|
|
|
return;
|
2007-05-31 07:31:51 -05:00
|
|
|
gpt_warning(device);
|
2011-12-15 13:02:42 -06:00
|
|
|
if ((fd = open(disk_device, O_RDONLY)) >= 0) {
|
2006-12-06 17:25:49 -06:00
|
|
|
gb = get_boot(try_only);
|
2006-12-06 17:26:16 -06:00
|
|
|
if (gb > 0) { /* I/O error */
|
2006-12-06 17:25:49 -06:00
|
|
|
} else if (gb < 0) { /* no DOS signature */
|
2006-12-06 17:25:46 -06:00
|
|
|
list_disk_geometry();
|
2011-07-03 05:01:21 -05:00
|
|
|
if (disklabel != AIX_LABEL && disklabel != MAC_LABEL && btrydev(device) < 0)
|
2006-12-06 17:25:46 -06:00
|
|
|
fprintf(stderr,
|
|
|
|
_("Disk %s doesn't contain a valid "
|
|
|
|
"partition table\n"), device);
|
2006-12-06 17:25:34 -06:00
|
|
|
} else {
|
2006-12-06 17:25:46 -06:00
|
|
|
list_table(0);
|
|
|
|
}
|
2006-12-06 17:26:16 -06:00
|
|
|
close(fd);
|
2006-12-06 17:25:46 -06:00
|
|
|
} else {
|
|
|
|
/* Ignore other errors, since we try IDE
|
|
|
|
and SCSI hard disks which may not be
|
|
|
|
installed on the system. */
|
2006-12-06 17:25:58 -06:00
|
|
|
if (errno == EACCES) {
|
2006-12-06 17:25:46 -06:00
|
|
|
fprintf(stderr, _("Cannot open %s\n"), device);
|
|
|
|
return;
|
2006-12-06 17:25:34 -06:00
|
|
|
}
|
|
|
|
}
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:26:16 -06:00
|
|
|
/*
|
|
|
|
* for fdisk -l:
|
|
|
|
* try all things in /proc/partitions that look like a full disk
|
|
|
|
*/
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
2011-12-15 13:02:41 -06:00
|
|
|
print_all_partition_table_from_option(void)
|
|
|
|
{
|
2006-12-06 17:25:41 -06:00
|
|
|
FILE *procpt;
|
2009-04-29 07:24:45 -05:00
|
|
|
char line[128], ptname[128], devname[256];
|
2008-11-13 08:37:22 -06:00
|
|
|
int ma, mi;
|
|
|
|
unsigned long long sz;
|
2006-12-06 17:25:41 -06:00
|
|
|
|
2010-12-16 18:28:59 -06:00
|
|
|
procpt = fopen(_PATH_PROC_PARTITIONS, "r");
|
2006-12-06 17:25:41 -06:00
|
|
|
if (procpt == NULL) {
|
2010-12-16 18:28:59 -06:00
|
|
|
fprintf(stderr, _("cannot open %s\n"), _PATH_PROC_PARTITIONS);
|
2006-12-06 17:25:41 -06:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (fgets(line, sizeof(line), procpt)) {
|
2009-04-29 07:24:45 -05:00
|
|
|
if (sscanf (line, " %d %d %llu %128[^\n ]",
|
2006-12-06 17:25:41 -06:00
|
|
|
&ma, &mi, &sz, ptname) != 4)
|
|
|
|
continue;
|
2006-12-06 17:25:46 -06:00
|
|
|
snprintf(devname, sizeof(devname), "/dev/%s", ptname);
|
2010-12-16 18:28:59 -06:00
|
|
|
if (is_whole_disk(devname)) {
|
|
|
|
char *cn = canonicalize_path(devname);
|
|
|
|
if (cn) {
|
2011-12-15 13:02:41 -06:00
|
|
|
print_partition_table_from_option(cn);
|
2010-12-16 18:28:59 -06:00
|
|
|
free(cn);
|
|
|
|
}
|
|
|
|
}
|
2006-12-06 17:25:41 -06:00
|
|
|
}
|
2006-12-06 17:25:49 -06:00
|
|
|
fclose(procpt);
|
2006-12-06 17:25:41 -06:00
|
|
|
}
|
|
|
|
|
2011-08-01 08:19:53 -05:00
|
|
|
static void dummy(int *kk __attribute__ ((__unused__))) {}
|
2006-12-06 17:25:39 -06:00
|
|
|
|
2006-12-06 17:25:43 -06:00
|
|
|
static void
|
|
|
|
unknown_command(int c) {
|
|
|
|
printf(_("%c: unknown command\n"), c);
|
2006-12-06 17:25:39 -06:00
|
|
|
}
|
|
|
|
|
2011-11-11 04:12:09 -06:00
|
|
|
static void command_prompt(void)
|
|
|
|
{
|
2011-12-15 13:02:46 -06:00
|
|
|
int c;
|
2007-05-31 07:31:51 -05:00
|
|
|
|
2011-11-11 04:12:09 -06:00
|
|
|
if (disklabel == OSF_LABEL) {
|
|
|
|
putchar('\n');
|
|
|
|
/* OSF label, and no DOS label */
|
|
|
|
printf(_("Detected an OSF/1 disklabel on %s, entering "
|
|
|
|
"disklabel mode.\n"),
|
|
|
|
disk_device);
|
|
|
|
bsd_command_prompt();
|
|
|
|
/* If we return we may want to make an empty DOS label? */
|
|
|
|
disklabel = DOS_LABEL;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
putchar('\n');
|
|
|
|
c = tolower(read_char(_("Command (m for help): ")));
|
|
|
|
switch (c) {
|
|
|
|
case 'a':
|
|
|
|
if (disklabel == DOS_LABEL)
|
|
|
|
toggle_active(get_partition(1, partitions));
|
|
|
|
else if (disklabel == SUN_LABEL)
|
|
|
|
toggle_sunflags(get_partition(1, partitions),
|
|
|
|
SUN_FLAG_UNMNT);
|
|
|
|
else if (disklabel == SGI_LABEL)
|
|
|
|
sgi_set_bootpartition(
|
|
|
|
get_partition(1, partitions));
|
|
|
|
else
|
|
|
|
unknown_command(c);
|
|
|
|
break;
|
|
|
|
case 'b':
|
2011-12-15 13:02:39 -06:00
|
|
|
if (disklabel == SGI_LABEL)
|
|
|
|
sgi_set_bootfile();
|
|
|
|
else if (disklabel == DOS_LABEL) {
|
2011-11-09 12:04:12 -06:00
|
|
|
disklabel = OSF_LABEL;
|
2011-11-11 04:12:09 -06:00
|
|
|
bsd_command_prompt();
|
2011-11-09 12:04:12 -06:00
|
|
|
disklabel = DOS_LABEL;
|
|
|
|
} else
|
|
|
|
unknown_command(c);
|
2011-11-11 04:12:09 -06:00
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
if (disklabel == DOS_LABEL)
|
|
|
|
toggle_dos_compatibility_flag();
|
|
|
|
else if (disklabel == SUN_LABEL)
|
|
|
|
toggle_sunflags(get_partition(1, partitions),
|
|
|
|
SUN_FLAG_RONLY);
|
|
|
|
else if (disklabel == SGI_LABEL)
|
|
|
|
sgi_set_swappartition(
|
|
|
|
get_partition(1, partitions));
|
|
|
|
else
|
|
|
|
unknown_command(c);
|
|
|
|
break;
|
|
|
|
case 'd':
|
2011-12-15 13:02:46 -06:00
|
|
|
delete_partition(get_existing_partition(1, partitions));
|
2011-11-11 04:12:09 -06:00
|
|
|
break;
|
|
|
|
case 'i':
|
|
|
|
if (disklabel == SGI_LABEL)
|
|
|
|
create_sgiinfo();
|
|
|
|
else
|
|
|
|
unknown_command(c);
|
|
|
|
case 'l':
|
|
|
|
list_types(get_sys_types());
|
|
|
|
break;
|
|
|
|
case 'm':
|
2011-11-09 12:04:12 -06:00
|
|
|
print_menu(MAIN_MENU);
|
2011-11-11 04:12:09 -06:00
|
|
|
break;
|
|
|
|
case 'n':
|
|
|
|
new_partition();
|
|
|
|
break;
|
|
|
|
case 'o':
|
|
|
|
create_doslabel();
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
list_table(0);
|
|
|
|
break;
|
|
|
|
case 'q':
|
|
|
|
close(fd);
|
|
|
|
printf("\n");
|
|
|
|
exit(0);
|
|
|
|
case 's':
|
|
|
|
create_sunlabel();
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
change_sysid();
|
|
|
|
break;
|
|
|
|
case 'u':
|
|
|
|
change_units();
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
verify();
|
|
|
|
break;
|
|
|
|
case 'w':
|
|
|
|
write_table(); /* does not return */
|
|
|
|
break;
|
|
|
|
case 'x':
|
2011-11-11 04:12:11 -06:00
|
|
|
expert_command_prompt();
|
2011-11-11 04:12:09 -06:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
unknown_command(c);
|
2011-11-09 12:04:12 -06:00
|
|
|
print_menu(MAIN_MENU);
|
2011-11-11 04:12:09 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-05-31 07:31:51 -05:00
|
|
|
|
2006-12-06 17:25:37 -06:00
|
|
|
int
|
2006-12-06 17:25:41 -06:00
|
|
|
main(int argc, char **argv) {
|
2006-12-06 17:25:39 -06:00
|
|
|
int j, c;
|
2006-12-06 17:25:35 -06:00
|
|
|
int optl = 0, opts = 0;
|
|
|
|
|
2006-12-06 17:25:39 -06:00
|
|
|
setlocale(LC_ALL, "");
|
|
|
|
bindtextdomain(PACKAGE, LOCALEDIR);
|
|
|
|
textdomain(PACKAGE);
|
2006-12-06 17:25:35 -06:00
|
|
|
|
2010-06-16 03:52:20 -05:00
|
|
|
while ((c = getopt(argc, argv, "b:c::C:hH:lsS:u::vV")) != -1) {
|
2006-12-06 17:25:35 -06:00
|
|
|
switch (c) {
|
|
|
|
case 'b':
|
2006-12-06 17:26:02 -06:00
|
|
|
/* Ugly: this sector size is really per device,
|
|
|
|
so cannot be combined with multiple disks,
|
|
|
|
and te same goes for the C/H/S options.
|
|
|
|
*/
|
2006-12-06 17:25:37 -06:00
|
|
|
sector_size = atoi(optarg);
|
|
|
|
if (sector_size != 512 && sector_size != 1024 &&
|
2009-03-09 03:52:08 -05:00
|
|
|
sector_size != 2048 && sector_size != 4096)
|
2011-01-23 15:51:20 -06:00
|
|
|
usage(stderr);
|
2006-12-06 17:25:37 -06:00
|
|
|
sector_offset = 2;
|
2006-12-06 17:25:39 -06:00
|
|
|
user_set_sector_size = 1;
|
2006-12-06 17:25:35 -06:00
|
|
|
break;
|
2006-12-06 17:26:02 -06:00
|
|
|
case 'C':
|
|
|
|
user_cylinders = atoi(optarg);
|
|
|
|
break;
|
2010-02-15 07:39:30 -06:00
|
|
|
case 'c':
|
2010-06-16 03:52:20 -05:00
|
|
|
dos_compatible_flag = 0; /* default */
|
|
|
|
|
|
|
|
if (optarg && !strcmp(optarg, "=dos"))
|
|
|
|
dos_compatible_flag = ~0;
|
|
|
|
else if (optarg && strcmp(optarg, "=nondos"))
|
2011-01-23 15:51:20 -06:00
|
|
|
usage(stderr);
|
2010-02-15 07:39:30 -06:00
|
|
|
break;
|
2010-02-15 03:08:03 -06:00
|
|
|
case 'h':
|
2011-01-23 15:51:20 -06:00
|
|
|
usage(stdout);
|
2010-02-15 03:08:03 -06:00
|
|
|
break;
|
2006-12-06 17:26:02 -06:00
|
|
|
case 'H':
|
|
|
|
user_heads = atoi(optarg);
|
2009-05-13 09:54:23 -05:00
|
|
|
if (user_heads <= 0 || user_heads > 256)
|
2006-12-06 17:26:02 -06:00
|
|
|
user_heads = 0;
|
|
|
|
break;
|
|
|
|
case 'S':
|
|
|
|
user_sectors = atoi(optarg);
|
|
|
|
if (user_sectors <= 0 || user_sectors >= 64)
|
|
|
|
user_sectors = 0;
|
|
|
|
break;
|
2006-12-06 17:25:35 -06:00
|
|
|
case 'l':
|
|
|
|
optl = 1;
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
opts = 1;
|
|
|
|
break;
|
|
|
|
case 'u':
|
2010-06-16 03:52:20 -05:00
|
|
|
display_in_cyl_units = 0; /* default */
|
|
|
|
if (optarg && strcmp(optarg, "=cylinders") == 0)
|
|
|
|
display_in_cyl_units = !display_in_cyl_units;
|
|
|
|
else if (optarg && strcmp(optarg, "=sectors"))
|
2011-01-23 15:51:20 -06:00
|
|
|
usage(stderr);
|
2006-12-06 17:25:35 -06:00
|
|
|
break;
|
2006-12-06 17:25:43 -06:00
|
|
|
case 'V':
|
2006-12-06 17:25:35 -06:00
|
|
|
case 'v':
|
2006-12-06 17:26:58 -06:00
|
|
|
printf("fdisk (%s)\n", PACKAGE_STRING);
|
2006-12-06 17:25:35 -06:00
|
|
|
exit(0);
|
|
|
|
default:
|
2011-01-23 15:51:20 -06:00
|
|
|
usage(stderr);
|
2006-12-06 17:25:35 -06:00
|
|
|
}
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
2006-12-06 17:25:35 -06:00
|
|
|
|
2006-12-06 17:25:39 -06:00
|
|
|
#if 0
|
2006-12-06 17:25:58 -06:00
|
|
|
printf(_("This kernel finds the sector size itself - "
|
|
|
|
"-b option ignored\n"));
|
2006-12-06 17:25:39 -06:00
|
|
|
#else
|
|
|
|
if (user_set_sector_size && argc-optind != 1)
|
|
|
|
printf(_("Warning: the -b (set sector size) option should"
|
|
|
|
" be used with one specified device\n"));
|
|
|
|
#endif
|
|
|
|
|
2009-10-16 14:49:33 -05:00
|
|
|
init_mbr_buffer();
|
|
|
|
|
2006-12-06 17:25:35 -06:00
|
|
|
if (optl) {
|
|
|
|
nowarn = 1;
|
|
|
|
if (argc > optind) {
|
|
|
|
int k;
|
|
|
|
/* avoid gcc warning:
|
|
|
|
variable `k' might be clobbered by `longjmp' */
|
|
|
|
dummy(&k);
|
2006-12-06 17:25:41 -06:00
|
|
|
listing = 1;
|
2006-12-06 17:26:16 -06:00
|
|
|
for (k = optind; k < argc; k++)
|
2011-12-15 13:02:40 -06:00
|
|
|
if (!is_ide_cdrom_or_tape(argv[k]))
|
2011-12-15 13:02:41 -06:00
|
|
|
print_partition_table_from_option(argv[k]);
|
|
|
|
} else
|
|
|
|
print_all_partition_table_from_option();
|
2006-12-06 17:25:35 -06:00
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opts) {
|
2006-12-06 17:26:18 -06:00
|
|
|
unsigned long long size;
|
2006-12-06 17:25:39 -06:00
|
|
|
|
2006-12-06 17:25:35 -06:00
|
|
|
nowarn = 1;
|
|
|
|
|
|
|
|
opts = argc - optind;
|
|
|
|
if (opts <= 0)
|
2011-01-23 15:51:20 -06:00
|
|
|
usage(stderr);
|
2006-12-06 17:25:35 -06:00
|
|
|
|
|
|
|
for (j = optind; j < argc; j++) {
|
2006-12-06 17:25:39 -06:00
|
|
|
disk_device = argv[j];
|
2011-12-15 13:02:42 -06:00
|
|
|
if ((fd = open(disk_device, O_RDONLY)) < 0)
|
2006-12-06 17:25:35 -06:00
|
|
|
fatal(unable_to_open);
|
2007-11-07 12:05:31 -06:00
|
|
|
if (blkdev_get_sectors(fd, &size) == -1)
|
2006-12-06 17:25:39 -06:00
|
|
|
fatal(ioctl_error);
|
2006-12-06 17:25:35 -06:00
|
|
|
close(fd);
|
|
|
|
if (opts == 1)
|
2006-12-06 17:26:18 -06:00
|
|
|
printf("%llu\n", size/2);
|
2006-12-06 17:25:35 -06:00
|
|
|
else
|
2006-12-06 17:26:18 -06:00
|
|
|
printf("%s: %llu\n", argv[j], size/2);
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
2006-12-06 17:25:35 -06:00
|
|
|
exit(0);
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|
|
|
|
|
2006-12-06 17:25:35 -06:00
|
|
|
if (argc-optind == 1)
|
|
|
|
disk_device = argv[optind];
|
2006-12-06 17:25:39 -06:00
|
|
|
else
|
2011-01-23 15:51:20 -06:00
|
|
|
usage(stderr);
|
2006-12-06 17:25:39 -06:00
|
|
|
|
2011-11-11 04:12:09 -06:00
|
|
|
fprintf(stderr, _("Welcome to fdisk (%s).\n\n"
|
|
|
|
"Changes will remain in memory only, until you decide to write them.\n"
|
|
|
|
"Be careful before using the write command.\n\n"), PACKAGE_STRING);
|
|
|
|
|
2007-05-31 07:31:51 -05:00
|
|
|
gpt_warning(disk_device);
|
2006-12-06 17:25:35 -06:00
|
|
|
get_boot(fdisk);
|
2006-12-06 17:25:32 -06:00
|
|
|
|
2011-11-11 04:12:09 -06:00
|
|
|
command_prompt();
|
2011-08-16 17:19:04 -05:00
|
|
|
|
2006-12-06 17:25:37 -06:00
|
|
|
return 0;
|
2006-12-06 17:25:32 -06:00
|
|
|
}
|