partx: complete rewrite
Co-Author: Karel Zak <kzak@redhat.com> Signed-off-by: Davidlohr Bueso <dave@gnu.org> Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
parent
4bfa39d5d5
commit
c4ecaf21d5
19 changed files with 970 additions and 2145 deletions
|
@ -26,5 +26,6 @@ static inline void xstrncpy(char *dest, const char *src, size_t n)
|
|||
}
|
||||
|
||||
extern void strmode(mode_t mode, char *str);
|
||||
extern char *size_to_human_string(uint64_t bytes);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,12 +3,15 @@
|
|||
* Copyright (C) 2010 Davidlohr Bueso <dave@gnu.org>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <err.h>
|
||||
#include <sys/stat.h>
|
||||
#include <locale.h>
|
||||
#include <string.h>
|
||||
|
||||
static int do_scale_by_power (uintmax_t *x, int base, int power)
|
||||
{
|
||||
|
@ -224,3 +227,49 @@ void strmode(mode_t mode, char *str)
|
|||
: (mode & S_IXOTH ? 'x' : '-'));
|
||||
str[10] = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* returns exponent (2^x=n) in range KiB..PiB
|
||||
*/
|
||||
static int get_exp(uint64_t n)
|
||||
{
|
||||
int shft;
|
||||
|
||||
for (shft = 10; shft <= 60; shft += 10) {
|
||||
if (n < (1ULL << shft))
|
||||
break;
|
||||
}
|
||||
return shft - 10;
|
||||
}
|
||||
|
||||
char *size_to_human_string(uint64_t bytes)
|
||||
{
|
||||
char buf[32];
|
||||
int dec, frac, exp;
|
||||
const char *letters = "BKMGTP";
|
||||
char c;
|
||||
|
||||
exp = get_exp(bytes);
|
||||
c = *(letters + (exp ? exp / 10 : 0));
|
||||
dec = exp ? bytes / (1ULL << exp) : bytes;
|
||||
frac = exp ? bytes % (1ULL << exp) : 0;
|
||||
|
||||
if (frac) {
|
||||
/* round */
|
||||
frac = (frac / (1ULL << (exp - 10)) + 50) / 100;
|
||||
if (frac == 10)
|
||||
dec++, frac = 0;
|
||||
}
|
||||
|
||||
if (frac) {
|
||||
struct lconv const *l = localeconv();
|
||||
char *dp = l ? l->decimal_point : NULL;
|
||||
|
||||
if (!dp || !*dp)
|
||||
dp = ".";
|
||||
snprintf(buf, sizeof(buf), "%d%s%d%c", dec, dp, frac, c);
|
||||
} else
|
||||
snprintf(buf, sizeof(buf), "%d%c", dec, c);
|
||||
|
||||
return strdup(buf);
|
||||
}
|
||||
|
|
|
@ -235,52 +235,6 @@ static struct dirent *xreaddir(DIR *dp)
|
|||
return d;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns exponent (2^x=n) in range KiB..PiB
|
||||
*/
|
||||
static int get_exp(uint64_t n)
|
||||
{
|
||||
int shft;
|
||||
|
||||
for (shft = 10; shft <= 60; shft += 10) {
|
||||
if (n < (1ULL << shft))
|
||||
break;
|
||||
}
|
||||
return shft - 10;
|
||||
}
|
||||
|
||||
static char *size_to_human_string(uint64_t bytes)
|
||||
{
|
||||
char buf[32];
|
||||
int dec, frac, exp;
|
||||
const char *letters = "BKMGTP";
|
||||
char c;
|
||||
|
||||
exp = get_exp(bytes);
|
||||
c = *(letters + (exp ? exp / 10 : 0));
|
||||
dec = exp ? bytes / (1ULL << exp) : bytes;
|
||||
frac = exp ? bytes % (1ULL << exp) : 0;
|
||||
|
||||
if (frac) {
|
||||
/* round */
|
||||
frac = (frac / (1ULL << (exp - 10)) + 50) / 100;
|
||||
if (frac == 10)
|
||||
dec++, frac = 0;
|
||||
}
|
||||
|
||||
if (frac) {
|
||||
struct lconv const *l = localeconv();
|
||||
char *dp = l ? l->decimal_point : NULL;
|
||||
|
||||
if (!dp || !*dp)
|
||||
dp = ".";
|
||||
snprintf(buf, sizeof(buf), "%d%s%d%c", dec, dp, frac, c);
|
||||
} else
|
||||
snprintf(buf, sizeof(buf), "%d%c", dec, c);
|
||||
|
||||
return xstrdup(buf);
|
||||
}
|
||||
|
||||
|
||||
static int is_partition_dirent(DIR *dir, struct dirent *d, const char *parent_name)
|
||||
{
|
||||
|
|
|
@ -1,15 +1,23 @@
|
|||
include $(top_srcdir)/config/include-Makefile.am
|
||||
|
||||
if BUILD_PARTX
|
||||
usrsbin_exec_PROGRAMS = addpart delpart
|
||||
dist_man_MANS = addpart.8 delpart.8
|
||||
|
||||
usrsbin_exec_PROGRAMS = addpart delpart partx
|
||||
partx_SOURCES = bsd.c dos.c partx.c solaris.c unixware.c sun.c mac.c gpt.c crc32.c \
|
||||
efi.h gpt.h crc32.h partx.h dos.h $(top_srcdir)/lib/blkdev.c
|
||||
if BUILD_PARTX
|
||||
if BUILD_LIBBLKID
|
||||
usrsbin_exec_PROGRAMS += partx
|
||||
partx_SOURCES = partx.c partx.h \
|
||||
$(top_srcdir)/lib/blkdev.c \
|
||||
$(top_srcdir)/lib/tt.c \
|
||||
$(top_srcdir)/lib/strutils.c
|
||||
|
||||
if LINUX
|
||||
partx_SOURCES += $(top_srcdir)/lib/linux_version.c
|
||||
endif
|
||||
|
||||
dist_man_MANS = addpart.8 delpart.8 partx.8
|
||||
|
||||
partx_CFLAGS = -I$(ul_libblkid_incdir)
|
||||
partx_LDADD = $(ul_libblkid_la)
|
||||
dist_man_MANS += partx.8
|
||||
endif
|
||||
endif
|
||||
|
||||
|
|
83
partx/bsd.c
83
partx/bsd.c
|
@ -1,83 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include "partx.h"
|
||||
|
||||
#define BSD_DISKMAGIC (0x82564557UL) /* The disk magic number */
|
||||
#define XBSD_MAXPARTITIONS 16
|
||||
#define BSD_FS_UNUSED 0
|
||||
|
||||
struct bsd_disklabel {
|
||||
unsigned int d_magic; /* the magic number */
|
||||
short int d_type; /* drive type */
|
||||
short int d_subtype; /* controller/d_type specific */
|
||||
char d_typename[16]; /* type name, e.g. "eagle" */
|
||||
char d_packname[16]; /* pack identifier */
|
||||
unsigned int d_secsize; /* # of bytes per sector */
|
||||
unsigned int d_nsectors; /* # of data sectors per track */
|
||||
unsigned int d_ntracks; /* # of tracks per cylinder */
|
||||
unsigned int d_ncylinders; /* # of data cylinders per unit */
|
||||
unsigned int d_secpercyl; /* # of data sectors per cylinder */
|
||||
unsigned int d_secperunit; /* # of data sectors per unit */
|
||||
unsigned short d_sparespertrack;/* # of spare sectors per track */
|
||||
unsigned short d_sparespercyl; /* # of spare sectors per cylinder */
|
||||
unsigned int d_acylinders; /* # of alt. cylinders per unit */
|
||||
unsigned short d_rpm; /* rotational speed */
|
||||
unsigned short d_interleave; /* hardware sector interleave */
|
||||
unsigned short d_trackskew; /* sector 0 skew, per track */
|
||||
unsigned short d_cylskew; /* sector 0 skew, per cylinder */
|
||||
unsigned int d_headswitch; /* head switch time, usec */
|
||||
unsigned int d_trkseek; /* track-to-track seek, usec */
|
||||
unsigned int d_flags; /* generic flags */
|
||||
unsigned int d_drivedata[5]; /* drive-type specific information */
|
||||
unsigned int d_spare[5]; /* reserved for future use */
|
||||
unsigned int d_magic2; /* the magic number (again) */
|
||||
unsigned short d_checksum; /* xor of data incl. partitions */
|
||||
|
||||
/* filesystem and partition information: */
|
||||
unsigned short d_npartitions; /* number of partitions in following */
|
||||
unsigned int d_bbsize; /* size of boot area at sn0, bytes */
|
||||
unsigned int d_sbsize; /* max size of fs superblock, bytes */
|
||||
struct bsd_partition { /* the partition table */
|
||||
unsigned int p_size; /* number of sectors in partition */
|
||||
unsigned int p_offset; /* starting sector */
|
||||
unsigned int p_fsize; /* filesystem basic fragment size */
|
||||
unsigned char p_fstype; /* filesystem type, see below */
|
||||
unsigned char p_frag; /* filesystem fragments per block */
|
||||
unsigned short p_cpg; /* filesystem cylinders per group */
|
||||
} d_partitions[XBSD_MAXPARTITIONS];/* actually may be more */
|
||||
};
|
||||
|
||||
int
|
||||
read_bsd_pt(int fd, struct slice all, struct slice *sp, int ns) {
|
||||
struct bsd_disklabel *l;
|
||||
struct bsd_partition *p;
|
||||
unsigned int offset = all.start;
|
||||
int max_partitions;
|
||||
unsigned char *bp;
|
||||
int n = 0;
|
||||
|
||||
bp = getblock(fd, offset+1); /* 1 sector suffices */
|
||||
if (bp == NULL)
|
||||
return -1;
|
||||
|
||||
l = (struct bsd_disklabel *) bp;
|
||||
if (l->d_magic != BSD_DISKMAGIC)
|
||||
return -1;
|
||||
|
||||
max_partitions = 16;
|
||||
if (l->d_npartitions < max_partitions)
|
||||
max_partitions = l->d_npartitions;
|
||||
for (p = l->d_partitions; p - l->d_partitions < max_partitions; p++) {
|
||||
if (p->p_fstype == BSD_FS_UNUSED)
|
||||
/* nothing */;
|
||||
else if (n < ns) {
|
||||
sp[n].start = p->p_offset;
|
||||
sp[n].size = p->p_size;
|
||||
n++;
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"bsd_partition: too many slices\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
393
partx/crc32.c
393
partx/crc32.c
|
@ -1,393 +0,0 @@
|
|||
/*
|
||||
* crc32.c
|
||||
* This code is in the public domain; copyright abandoned.
|
||||
* Liability for non-performance of this code is limited to the amount
|
||||
* you paid for it. Since it is distributed for free, your refund will
|
||||
* be very very small. If it breaks, you get to keep both pieces.
|
||||
*/
|
||||
|
||||
#include "crc32.h"
|
||||
|
||||
#if __GNUC__ >= 3 /* 2.x has "attribute", but only 3.0 has "pure */
|
||||
#define attribute(x) __attribute__(x)
|
||||
#else
|
||||
#define attribute(x)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* There are multiple 16-bit CRC polynomials in common use, but this is
|
||||
* *the* standard CRC-32 polynomial, first popularized by Ethernet.
|
||||
* x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0
|
||||
*/
|
||||
#define CRCPOLY_LE 0xedb88320
|
||||
#define CRCPOLY_BE 0x04c11db7
|
||||
|
||||
/* How many bits at a time to use. Requires a table of 4<<CRC_xx_BITS bytes. */
|
||||
/* For less performance-sensitive, use 4 */
|
||||
#define CRC_LE_BITS 8
|
||||
#define CRC_BE_BITS 8
|
||||
|
||||
/*
|
||||
* Little-endian CRC computation. Used with serial bit streams sent
|
||||
* lsbit-first. Be sure to use cpu_to_le32() to append the computed CRC.
|
||||
*/
|
||||
#if CRC_LE_BITS > 8 || CRC_LE_BITS < 1 || CRC_LE_BITS & CRC_LE_BITS-1
|
||||
# error CRC_LE_BITS must be a power of 2 between 1 and 8
|
||||
#endif
|
||||
|
||||
#if CRC_LE_BITS == 1
|
||||
/*
|
||||
* In fact, the table-based code will work in this case, but it can be
|
||||
* simplified by inlining the table in ?: form.
|
||||
*/
|
||||
#define crc32init_le()
|
||||
#define crc32cleanup_le()
|
||||
/**
|
||||
* crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
|
||||
* @crc - seed value for computation. ~0 for Ethernet, sometimes 0 for
|
||||
* other uses, or the previous crc32 value if computing incrementally.
|
||||
* @p - pointer to buffer over which CRC is run
|
||||
* @len - length of buffer @p
|
||||
*
|
||||
*/
|
||||
uint32_t attribute((pure)) crc32_le(uint32_t crc, unsigned char const *p, size_t len)
|
||||
{
|
||||
int i;
|
||||
while (len--) {
|
||||
crc ^= *p++;
|
||||
for (i = 0; i < 8; i++)
|
||||
crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
#else /* Table-based approach */
|
||||
|
||||
static uint32_t *crc32table_le;
|
||||
/**
|
||||
* crc32init_le() - allocate and initialize LE table data
|
||||
*
|
||||
* crc is the crc of the byte i; other entries are filled in based on the
|
||||
* fact that crctable[i^j] = crctable[i] ^ crctable[j].
|
||||
*
|
||||
*/
|
||||
static int
|
||||
crc32init_le(void)
|
||||
{
|
||||
unsigned i, j;
|
||||
uint32_t crc = 1;
|
||||
|
||||
crc32table_le =
|
||||
malloc((1 << CRC_LE_BITS) * sizeof(uint32_t));
|
||||
if (!crc32table_le)
|
||||
return 1;
|
||||
crc32table_le[0] = 0;
|
||||
|
||||
for (i = 1 << (CRC_LE_BITS - 1); i; i >>= 1) {
|
||||
crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
|
||||
for (j = 0; j < 1 << CRC_LE_BITS; j += 2 * i)
|
||||
crc32table_le[i + j] = crc ^ crc32table_le[j];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* crc32cleanup_le(): free LE table data
|
||||
*/
|
||||
static void
|
||||
crc32cleanup_le(void)
|
||||
{
|
||||
free(crc32table_le);
|
||||
crc32table_le = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
|
||||
* @crc - seed value for computation. ~0 for Ethernet, sometimes 0 for
|
||||
* other uses, or the previous crc32 value if computing incrementally.
|
||||
* @p - pointer to buffer over which CRC is run
|
||||
* @len - length of buffer @p
|
||||
*
|
||||
*/
|
||||
uint32_t attribute((pure)) crc32_le(uint32_t crc, unsigned char const *p, size_t len)
|
||||
{
|
||||
while (len--) {
|
||||
# if CRC_LE_BITS == 8
|
||||
crc = (crc >> 8) ^ crc32table_le[(crc ^ *p++) & 255];
|
||||
# elif CRC_LE_BITS == 4
|
||||
crc ^= *p++;
|
||||
crc = (crc >> 4) ^ crc32table_le[crc & 15];
|
||||
crc = (crc >> 4) ^ crc32table_le[crc & 15];
|
||||
# elif CRC_LE_BITS == 2
|
||||
crc ^= *p++;
|
||||
crc = (crc >> 2) ^ crc32table_le[crc & 3];
|
||||
crc = (crc >> 2) ^ crc32table_le[crc & 3];
|
||||
crc = (crc >> 2) ^ crc32table_le[crc & 3];
|
||||
crc = (crc >> 2) ^ crc32table_le[crc & 3];
|
||||
# endif
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Big-endian CRC computation. Used with serial bit streams sent
|
||||
* msbit-first. Be sure to use cpu_to_be32() to append the computed CRC.
|
||||
*/
|
||||
#if CRC_BE_BITS > 8 || CRC_BE_BITS < 1 || CRC_BE_BITS & CRC_BE_BITS-1
|
||||
# error CRC_BE_BITS must be a power of 2 between 1 and 8
|
||||
#endif
|
||||
|
||||
#if CRC_BE_BITS == 1
|
||||
/*
|
||||
* In fact, the table-based code will work in this case, but it can be
|
||||
* simplified by inlining the table in ?: form.
|
||||
*/
|
||||
#define crc32init_be()
|
||||
#define crc32cleanup_be()
|
||||
|
||||
/**
|
||||
* crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
|
||||
* @crc - seed value for computation. ~0 for Ethernet, sometimes 0 for
|
||||
* other uses, or the previous crc32 value if computing incrementally.
|
||||
* @p - pointer to buffer over which CRC is run
|
||||
* @len - length of buffer @p
|
||||
*
|
||||
*/
|
||||
uint32_t attribute((pure)) crc32_be(uint32_t crc, unsigned char const *p, size_t len)
|
||||
{
|
||||
int i;
|
||||
while (len--) {
|
||||
crc ^= *p++ << 24;
|
||||
for (i = 0; i < 8; i++)
|
||||
crc =
|
||||
(crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE :
|
||||
0);
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
#else /* Table-based approach */
|
||||
static uint32_t *crc32table_be;
|
||||
|
||||
/**
|
||||
* crc32init_be() - allocate and initialize BE table data
|
||||
*/
|
||||
static int
|
||||
crc32init_be(void)
|
||||
{
|
||||
unsigned i, j;
|
||||
uint32_t crc = 0x80000000;
|
||||
|
||||
crc32table_be =
|
||||
malloc((1 << CRC_BE_BITS) * sizeof(uint32_t));
|
||||
if (!crc32table_be)
|
||||
return 1;
|
||||
crc32table_be[0] = 0;
|
||||
|
||||
for (i = 1; i < 1 << CRC_BE_BITS; i <<= 1) {
|
||||
crc = (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE : 0);
|
||||
for (j = 0; j < i; j++)
|
||||
crc32table_be[i + j] = crc ^ crc32table_be[j];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* crc32cleanup_be(): free BE table data
|
||||
*/
|
||||
static void
|
||||
crc32cleanup_be(void)
|
||||
{
|
||||
free(crc32table_be);
|
||||
crc32table_be = NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
|
||||
* @crc - seed value for computation. ~0 for Ethernet, sometimes 0 for
|
||||
* other uses, or the previous crc32 value if computing incrementally.
|
||||
* @p - pointer to buffer over which CRC is run
|
||||
* @len - length of buffer @p
|
||||
*
|
||||
*/
|
||||
uint32_t attribute((pure)) crc32_be(uint32_t crc, unsigned char const *p, size_t len)
|
||||
{
|
||||
while (len--) {
|
||||
# if CRC_BE_BITS == 8
|
||||
crc = (crc << 8) ^ crc32table_be[(crc >> 24) ^ *p++];
|
||||
# elif CRC_BE_BITS == 4
|
||||
crc ^= *p++ << 24;
|
||||
crc = (crc << 4) ^ crc32table_be[crc >> 28];
|
||||
crc = (crc << 4) ^ crc32table_be[crc >> 28];
|
||||
# elif CRC_BE_BITS == 2
|
||||
crc ^= *p++ << 24;
|
||||
crc = (crc << 2) ^ crc32table_be[crc >> 30];
|
||||
crc = (crc << 2) ^ crc32table_be[crc >> 30];
|
||||
crc = (crc << 2) ^ crc32table_be[crc >> 30];
|
||||
crc = (crc << 2) ^ crc32table_be[crc >> 30];
|
||||
# endif
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* A brief CRC tutorial.
|
||||
*
|
||||
* A CRC is a long-division remainder. You add the CRC to the message,
|
||||
* and the whole thing (message+CRC) is a multiple of the given
|
||||
* CRC polynomial. To check the CRC, you can either check that the
|
||||
* CRC matches the recomputed value, *or* you can check that the
|
||||
* remainder computed on the message+CRC is 0. This latter approach
|
||||
* is used by a lot of hardware implementations, and is why so many
|
||||
* protocols put the end-of-frame flag after the CRC.
|
||||
*
|
||||
* It's actually the same long division you learned in school, except that
|
||||
* - We're working in binary, so the digits are only 0 and 1, and
|
||||
* - When dividing polynomials, there are no carries. Rather than add and
|
||||
* subtract, we just xor. Thus, we tend to get a bit sloppy about
|
||||
* the difference between adding and subtracting.
|
||||
*
|
||||
* A 32-bit CRC polynomial is actually 33 bits long. But since it's
|
||||
* 33 bits long, bit 32 is always going to be set, so usually the CRC
|
||||
* is written in hex with the most significant bit omitted. (If you're
|
||||
* familiar with the IEEE 754 floating-point format, it's the same idea.)
|
||||
*
|
||||
* Note that a CRC is computed over a string of *bits*, so you have
|
||||
* to decide on the endianness of the bits within each byte. To get
|
||||
* the best error-detecting properties, this should correspond to the
|
||||
* order they're actually sent. For example, standard RS-232 serial is
|
||||
* little-endian; the most significant bit (sometimes used for parity)
|
||||
* is sent last. And when appending a CRC word to a message, you should
|
||||
* do it in the right order, matching the endianness.
|
||||
*
|
||||
* Just like with ordinary division, the remainder is always smaller than
|
||||
* the divisor (the CRC polynomial) you're dividing by. Each step of the
|
||||
* division, you take one more digit (bit) of the dividend and append it
|
||||
* to the current remainder. Then you figure out the appropriate multiple
|
||||
* of the divisor to subtract to being the remainder back into range.
|
||||
* In binary, it's easy - it has to be either 0 or 1, and to make the
|
||||
* XOR cancel, it's just a copy of bit 32 of the remainder.
|
||||
*
|
||||
* When computing a CRC, we don't care about the quotient, so we can
|
||||
* throw the quotient bit away, but subtract the appropriate multiple of
|
||||
* the polynomial from the remainder and we're back to where we started,
|
||||
* ready to process the next bit.
|
||||
*
|
||||
* A big-endian CRC written this way would be coded like:
|
||||
* for (i = 0; i < input_bits; i++) {
|
||||
* multiple = remainder & 0x80000000 ? CRCPOLY : 0;
|
||||
* remainder = (remainder << 1 | next_input_bit()) ^ multiple;
|
||||
* }
|
||||
* Notice how, to get at bit 32 of the shifted remainder, we look
|
||||
* at bit 31 of the remainder *before* shifting it.
|
||||
*
|
||||
* But also notice how the next_input_bit() bits we're shifting into
|
||||
* the remainder don't actually affect any decision-making until
|
||||
* 32 bits later. Thus, the first 32 cycles of this are pretty boring.
|
||||
* Also, to add the CRC to a message, we need a 32-bit-long hole for it at
|
||||
* the end, so we have to add 32 extra cycles shifting in zeros at the
|
||||
* end of every message,
|
||||
*
|
||||
* So the standard trick is to rearrage merging in the next_input_bit()
|
||||
* until the moment it's needed. Then the first 32 cycles can be precomputed,
|
||||
* and merging in the final 32 zero bits to make room for the CRC can be
|
||||
* skipped entirely.
|
||||
* This changes the code to:
|
||||
* for (i = 0; i < input_bits; i++) {
|
||||
* remainder ^= next_input_bit() << 31;
|
||||
* multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
|
||||
* remainder = (remainder << 1) ^ multiple;
|
||||
* }
|
||||
* With this optimization, the little-endian code is simpler:
|
||||
* for (i = 0; i < input_bits; i++) {
|
||||
* remainder ^= next_input_bit();
|
||||
* multiple = (remainder & 1) ? CRCPOLY : 0;
|
||||
* remainder = (remainder >> 1) ^ multiple;
|
||||
* }
|
||||
*
|
||||
* Note that the other details of endianness have been hidden in CRCPOLY
|
||||
* (which must be bit-reversed) and next_input_bit().
|
||||
*
|
||||
* However, as long as next_input_bit is returning the bits in a sensible
|
||||
* order, we can actually do the merging 8 or more bits at a time rather
|
||||
* than one bit at a time:
|
||||
* for (i = 0; i < input_bytes; i++) {
|
||||
* remainder ^= next_input_byte() << 24;
|
||||
* for (j = 0; j < 8; j++) {
|
||||
* multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
|
||||
* remainder = (remainder << 1) ^ multiple;
|
||||
* }
|
||||
* }
|
||||
* Or in little-endian:
|
||||
* for (i = 0; i < input_bytes; i++) {
|
||||
* remainder ^= next_input_byte();
|
||||
* for (j = 0; j < 8; j++) {
|
||||
* multiple = (remainder & 1) ? CRCPOLY : 0;
|
||||
* remainder = (remainder << 1) ^ multiple;
|
||||
* }
|
||||
* }
|
||||
* If the input is a multiple of 32 bits, you can even XOR in a 32-bit
|
||||
* word at a time and increase the inner loop count to 32.
|
||||
*
|
||||
* You can also mix and match the two loop styles, for example doing the
|
||||
* bulk of a message byte-at-a-time and adding bit-at-a-time processing
|
||||
* for any fractional bytes at the end.
|
||||
*
|
||||
* The only remaining optimization is to the byte-at-a-time table method.
|
||||
* Here, rather than just shifting one bit of the remainder to decide
|
||||
* in the correct multiple to subtract, we can shift a byte at a time.
|
||||
* This produces a 40-bit (rather than a 33-bit) intermediate remainder,
|
||||
* but again the multiple of the polynomial to subtract depends only on
|
||||
* the high bits, the high 8 bits in this case.
|
||||
*
|
||||
* The multile we need in that case is the low 32 bits of a 40-bit
|
||||
* value whose high 8 bits are given, and which is a multiple of the
|
||||
* generator polynomial. This is simply the CRC-32 of the given
|
||||
* one-byte message.
|
||||
*
|
||||
* Two more details: normally, appending zero bits to a message which
|
||||
* is already a multiple of a polynomial produces a larger multiple of that
|
||||
* polynomial. To enable a CRC to detect this condition, it's common to
|
||||
* invert the CRC before appending it. This makes the remainder of the
|
||||
* message+crc come out not as zero, but some fixed non-zero value.
|
||||
*
|
||||
* The same problem applies to zero bits prepended to the message, and
|
||||
* a similar solution is used. Instead of starting with a remainder of
|
||||
* 0, an initial remainder of all ones is used. As long as you start
|
||||
* the same way on decoding, it doesn't make a difference.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* init_crc32(): generates CRC32 tables
|
||||
*
|
||||
* On successful initialization, use count is increased.
|
||||
* This guarantees that the library functions will stay resident
|
||||
* in memory, and prevents someone from 'rmmod crc32' while
|
||||
* a driver that needs it is still loaded.
|
||||
* This also greatly simplifies drivers, as there's no need
|
||||
* to call an initialization/cleanup function from each driver.
|
||||
* Since crc32.o is a library module, there's no requirement
|
||||
* that the user can unload it.
|
||||
*/
|
||||
int
|
||||
init_crc32(void)
|
||||
{
|
||||
int rc1, rc2, rc;
|
||||
rc1 = crc32init_le();
|
||||
rc2 = crc32init_be();
|
||||
rc = rc1 || rc2;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* cleanup_crc32(): frees crc32 data when no longer needed
|
||||
*/
|
||||
void
|
||||
cleanup_crc32(void)
|
||||
{
|
||||
crc32cleanup_le();
|
||||
crc32cleanup_be();
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
/*
|
||||
* crc32.h
|
||||
*/
|
||||
#ifndef _CRC32_H
|
||||
#define _CRC32_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
extern int init_crc32(void);
|
||||
extern void cleanup_crc32(void);
|
||||
extern uint32_t crc32_le(uint32_t crc, unsigned char const *p, size_t len);
|
||||
extern uint32_t crc32_be(uint32_t crc, unsigned char const *p, size_t len);
|
||||
|
||||
#define crc32(seed, data, length) crc32_le(seed, (unsigned char const *)data, length)
|
||||
#define ether_crc_le(length, data) crc32_le(~0, data, length)
|
||||
#define ether_crc(length, data) crc32_be(~0, data, length)
|
||||
|
||||
#endif /* _CRC32_H */
|
138
partx/dos.c
138
partx/dos.c
|
@ -1,138 +0,0 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include "blkdev.h"
|
||||
|
||||
#include "partx.h"
|
||||
#include "dos.h"
|
||||
|
||||
static int
|
||||
is_extended(int type) {
|
||||
return (type == 5 || type == 0xf || type == 0x85);
|
||||
}
|
||||
|
||||
/* assemble badly aligned little endian integer */
|
||||
static inline unsigned int
|
||||
assemble4le(unsigned char *p) {
|
||||
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
partition_start(struct partition *p) {
|
||||
return assemble4le(&(p->start_sect[0]));
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
partition_size(struct partition *p) {
|
||||
return assemble4le(&(p->nr_sects[0]));
|
||||
}
|
||||
|
||||
static int
|
||||
read_extended_partition(int fd, struct partition *ep,
|
||||
struct slice *sp, int ns, int ssf)
|
||||
{
|
||||
struct partition *p;
|
||||
unsigned long start, here;
|
||||
unsigned char *bp;
|
||||
int loopct = 0;
|
||||
int moretodo = 1;
|
||||
int i, n=0;
|
||||
|
||||
here = start = partition_start(ep);;
|
||||
|
||||
while (moretodo) {
|
||||
moretodo = 0;
|
||||
if (++loopct > 100)
|
||||
return n;
|
||||
|
||||
bp = getblock(fd, here * ssf); /* in 512 blocks */
|
||||
if (bp == NULL)
|
||||
return n;
|
||||
|
||||
if (bp[510] != 0x55 || bp[511] != 0xaa)
|
||||
return n;
|
||||
|
||||
p = (struct partition *) (bp + 0x1be);
|
||||
|
||||
for (i=0; i<2; i++, p++) {
|
||||
if (partition_size(p) == 0 || is_extended(p->sys_type))
|
||||
continue;
|
||||
if (n < ns) {
|
||||
sp[n].start = (here + partition_start(p)) * ssf;
|
||||
sp[n].size = partition_size(p) * ssf;
|
||||
n++;
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"dos_extd_partition: too many slices\n");
|
||||
return n;
|
||||
}
|
||||
loopct = 0;
|
||||
}
|
||||
|
||||
p -= 2;
|
||||
for (i=0; i<2; i++, p++) {
|
||||
if (partition_size(p) != 0 &&
|
||||
is_extended(p->sys_type)) {
|
||||
here = start + partition_start(p);
|
||||
moretodo = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
is_gpt(int type) {
|
||||
return (type == 0xEE);
|
||||
}
|
||||
|
||||
int
|
||||
read_dos_pt(int fd, struct slice all, struct slice *sp, int ns) {
|
||||
struct partition *p;
|
||||
unsigned long offset = all.start;
|
||||
int i, n=0;
|
||||
unsigned char *bp;
|
||||
int ssf;
|
||||
|
||||
bp = getblock(fd, offset);
|
||||
if (bp == NULL)
|
||||
return -1;
|
||||
|
||||
if (bp[510] != 0x55 || bp[511] != 0xaa)
|
||||
return -1;
|
||||
|
||||
/* msdos PT depends sector size... */
|
||||
if (blkdev_get_sector_size(fd, &ssf) != 0)
|
||||
ssf = DEFAULT_SECTOR_SIZE;
|
||||
|
||||
/* ... but partx counts everything in 512-byte sectors */
|
||||
ssf /= 512;
|
||||
|
||||
p = (struct partition *) (bp + 0x1be);
|
||||
for (i=0; i<4; i++) {
|
||||
if (is_gpt(p->sys_type))
|
||||
return 0;
|
||||
p++;
|
||||
}
|
||||
p = (struct partition *) (bp + 0x1be);
|
||||
for (i=0; i<4; i++) {
|
||||
/* always add, even if zero length */
|
||||
if (n < ns) {
|
||||
sp[n].start = partition_start(p) * ssf;
|
||||
sp[n].size = partition_size(p) * ssf;
|
||||
n++;
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"dos_partition: too many slices\n");
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
p = (struct partition *) (bp + 0x1be);
|
||||
for (i=0; i<4; i++) {
|
||||
if (is_extended(p->sys_type))
|
||||
n += read_extended_partition(fd, p, sp+n, ns-n, ssf);
|
||||
p++;
|
||||
}
|
||||
return n;
|
||||
}
|
13
partx/dos.h
13
partx/dos.h
|
@ -1,13 +0,0 @@
|
|||
#ifndef DOS_H_INCLUDED
|
||||
#define DOS_H_INCLUDED
|
||||
|
||||
struct partition {
|
||||
unsigned char boot_ind; /* 0x80 - active */
|
||||
unsigned char bh, bs, bc;
|
||||
unsigned char sys_type;
|
||||
unsigned char eh, es, ec;
|
||||
unsigned char start_sect[4];
|
||||
unsigned char nr_sects[4];
|
||||
};
|
||||
|
||||
#endif /* DOS_H_INCLUDED */
|
57
partx/efi.h
57
partx/efi.h
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
efi.[ch] - Manipulates EFI variables as exported in /proc/efi/vars
|
||||
|
||||
Copyright (C) 2001 Dell Computer Corporation <Matt_Domsch@dell.com>
|
||||
|
||||
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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef EFI_H
|
||||
#define EFI_H
|
||||
|
||||
/*
|
||||
* Extensible Firmware Interface
|
||||
* Based on 'Extensible Firmware Interface Specification'
|
||||
* version 1.02, 12 December, 2000
|
||||
*/
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
uint8_t b[16];
|
||||
} efi_guid_t;
|
||||
|
||||
#define EFI_GUID(a,b,c,d0,d1,d2,d3,d4,d5,d6,d7) \
|
||||
((efi_guid_t) \
|
||||
{{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
|
||||
(b) & 0xff, ((b) >> 8) & 0xff, \
|
||||
(c) & 0xff, ((c) >> 8) & 0xff, \
|
||||
(d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }})
|
||||
|
||||
|
||||
/******************************************************
|
||||
* GUIDs
|
||||
******************************************************/
|
||||
#define NULL_GUID \
|
||||
EFI_GUID( 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)
|
||||
|
||||
static inline int
|
||||
efi_guidcmp(efi_guid_t left, efi_guid_t right)
|
||||
{
|
||||
return memcmp(&left, &right, sizeof (efi_guid_t));
|
||||
}
|
||||
|
||||
typedef uint16_t efi_char16_t; /* UNICODE character */
|
||||
|
||||
#endif /* EFI_H */
|
510
partx/gpt.c
510
partx/gpt.c
|
@ -1,510 +0,0 @@
|
|||
/*
|
||||
gpt.[ch]
|
||||
|
||||
Copyright (C) 2000-2001 Dell Computer Corporation <Matt_Domsch@dell.com>
|
||||
|
||||
EFI GUID Partition Table handling
|
||||
Per Intel EFI Specification v1.02
|
||||
http://developer.intel.com/technology/efi/efi.htm
|
||||
|
||||
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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "blkdev.h"
|
||||
#include "crc32.h"
|
||||
#include "gpt.h"
|
||||
#include "partx.h"
|
||||
#include "bitops.h"
|
||||
|
||||
static inline uint32_t
|
||||
efi_crc32(const void *buf, unsigned long len)
|
||||
{
|
||||
return (crc32(~0L, buf, len) ^ ~0L);
|
||||
}
|
||||
|
||||
/**
|
||||
* is_pmbr_valid(): test Protective MBR for validity
|
||||
* @mbr: pointer to a legacy mbr structure
|
||||
*
|
||||
* Description: Returns 1 if PMBR is valid, 0 otherwise.
|
||||
* Validity depends on two things:
|
||||
* 1) MSDOS signature is in the last two bytes of the MBR
|
||||
* 2) One partition of type 0xEE is found
|
||||
*/
|
||||
static int
|
||||
is_pmbr_valid(legacy_mbr *mbr)
|
||||
{
|
||||
int i, found = 0, signature = 0;
|
||||
if (!mbr)
|
||||
return 0;
|
||||
signature = (le16_to_cpu(mbr->signature) == MSDOS_MBR_SIGNATURE);
|
||||
for (i = 0; signature && i < 4; i++) {
|
||||
if (mbr->partition[i].sys_type ==
|
||||
EFI_PMBR_OSTYPE_EFI_GPT) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (signature && found);
|
||||
}
|
||||
|
||||
static int
|
||||
get_sector_size (int fd)
|
||||
{
|
||||
int sector_size;
|
||||
|
||||
if (blkdev_get_sector_size(fd, §or_size) == -1)
|
||||
return DEFAULT_SECTOR_SIZE;
|
||||
return sector_size;
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
get_num_sectors(int fd)
|
||||
{
|
||||
unsigned long long bytes=0;
|
||||
|
||||
if (blkdev_get_size(fd, &bytes) == -1)
|
||||
return 0;
|
||||
return bytes / get_sector_size(fd);
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
last_lba(int filedes)
|
||||
{
|
||||
int rc;
|
||||
uint64_t sectors = 0;
|
||||
struct stat s;
|
||||
memset(&s, 0, sizeof (s));
|
||||
rc = fstat(filedes, &s);
|
||||
if (rc == -1) {
|
||||
fprintf(stderr, "last_lba() could not stat: %s\n",
|
||||
strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (S_ISBLK(s.st_mode)) {
|
||||
sectors = get_num_sectors(filedes);
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"last_lba(): I don't know how to handle files with mode %x\n",
|
||||
s.st_mode);
|
||||
sectors = 1;
|
||||
}
|
||||
|
||||
return sectors - 1;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
read_lba(int fd, uint64_t lba, void *buffer, size_t bytes)
|
||||
{
|
||||
int sector_size = get_sector_size(fd);
|
||||
off_t offset = lba * sector_size;
|
||||
|
||||
lseek(fd, offset, SEEK_SET);
|
||||
return read(fd, buffer, bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* alloc_read_gpt_entries(): reads partition entries from disk
|
||||
* @fd is an open file descriptor to the whole disk
|
||||
* @gpt is a buffer into which the GPT will be put
|
||||
* Description: Returns ptes on success, NULL on error.
|
||||
* Allocates space for PTEs based on information found in @gpt.
|
||||
* Notes: remember to free pte when you're done!
|
||||
*/
|
||||
static gpt_entry *
|
||||
alloc_read_gpt_entries(int fd, gpt_header * gpt)
|
||||
{
|
||||
gpt_entry *pte;
|
||||
size_t count = le32_to_cpu(gpt->num_partition_entries) *
|
||||
le32_to_cpu(gpt->sizeof_partition_entry);
|
||||
|
||||
if (!count) return NULL;
|
||||
|
||||
pte = (gpt_entry *)malloc(count);
|
||||
if (!pte)
|
||||
return NULL;
|
||||
memset(pte, 0, count);
|
||||
|
||||
if (!read_lba(fd, le64_to_cpu(gpt->partition_entry_lba), pte,
|
||||
count)) {
|
||||
free(pte);
|
||||
return NULL;
|
||||
}
|
||||
return pte;
|
||||
}
|
||||
|
||||
/**
|
||||
* alloc_read_gpt_header(): Allocates GPT header, reads into it from disk
|
||||
* @fd is an open file descriptor to the whole disk
|
||||
* @lba is the Logical Block Address of the partition table
|
||||
*
|
||||
* Description: returns GPT header on success, NULL on error. Allocates
|
||||
* and fills a GPT header starting at @ from @bdev.
|
||||
* Note: remember to free gpt when finished with it.
|
||||
*/
|
||||
static gpt_header *
|
||||
alloc_read_gpt_header(int fd, uint64_t lba)
|
||||
{
|
||||
gpt_header *gpt;
|
||||
gpt = (gpt_header *)
|
||||
malloc(sizeof (gpt_header));
|
||||
if (!gpt)
|
||||
return NULL;
|
||||
memset(gpt, 0, sizeof (*gpt));
|
||||
if (!read_lba(fd, lba, gpt, sizeof (gpt_header))) {
|
||||
free(gpt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return gpt;
|
||||
}
|
||||
|
||||
/**
|
||||
* is_gpt_valid() - tests one GPT header and PTEs for validity
|
||||
* @fd is an open file descriptor to the whole disk
|
||||
* @lba is the logical block address of the GPT header to test
|
||||
* @gpt is a GPT header ptr, filled on return.
|
||||
* @ptes is a PTEs ptr, filled on return.
|
||||
*
|
||||
* Description: returns 1 if valid, 0 on error.
|
||||
* If valid, returns pointers to newly allocated GPT header and PTEs.
|
||||
*/
|
||||
static int
|
||||
is_gpt_valid(int fd, uint64_t lba,
|
||||
gpt_header ** gpt, gpt_entry ** ptes)
|
||||
{
|
||||
int rc = 0; /* default to not valid */
|
||||
uint32_t crc, origcrc;
|
||||
|
||||
if (!gpt || !ptes)
|
||||
return 0;
|
||||
if (!(*gpt = alloc_read_gpt_header(fd, lba)))
|
||||
return 0;
|
||||
|
||||
/* Check the GUID Partition Table signature */
|
||||
if (le64_to_cpu((*gpt)->signature) != GPT_HEADER_SIGNATURE) {
|
||||
/*
|
||||
printf("GUID Partition Table Header signature is wrong: %" PRIx64" != %" PRIx64 "\n",
|
||||
le64_to_cpu((*gpt)->signature), GUID_PT_HEADER_SIGNATURE);
|
||||
*/
|
||||
free(*gpt);
|
||||
*gpt = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Check the GUID Partition Table Header CRC */
|
||||
origcrc = le32_to_cpu((*gpt)->header_crc32);
|
||||
(*gpt)->header_crc32 = 0;
|
||||
crc = efi_crc32(*gpt, le32_to_cpu((*gpt)->header_size));
|
||||
if (crc != origcrc) {
|
||||
/* printf( "GPTH CRC check failed, %x != %x.\n", origcrc, crc); */
|
||||
(*gpt)->header_crc32 = cpu_to_le32(origcrc);
|
||||
free(*gpt);
|
||||
*gpt = NULL;
|
||||
return 0;
|
||||
}
|
||||
(*gpt)->header_crc32 = cpu_to_le32(origcrc);
|
||||
|
||||
/* Check that the my_lba entry points to the LBA
|
||||
* that contains the GPT we read */
|
||||
if (le64_to_cpu((*gpt)->my_lba) != lba) {
|
||||
/* printf( "my_lba % PRIx64 "x != lba %"PRIx64 "x.\n", le64_to_cpu((*gpt)->my_lba), lba); */
|
||||
free(*gpt);
|
||||
*gpt = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(*ptes = alloc_read_gpt_entries(fd, *gpt))) {
|
||||
free(*gpt);
|
||||
*gpt = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check the GUID Partition Entry Array CRC */
|
||||
crc = efi_crc32(*ptes,
|
||||
le32_to_cpu((*gpt)->num_partition_entries) *
|
||||
le32_to_cpu((*gpt)->sizeof_partition_entry));
|
||||
if (crc != le32_to_cpu((*gpt)->partition_entry_array_crc32)) {
|
||||
/* printf("GUID Partitition Entry Array CRC check failed.\n"); */
|
||||
free(*gpt);
|
||||
*gpt = NULL;
|
||||
free(*ptes);
|
||||
*ptes = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We're done, all's well */
|
||||
return 1;
|
||||
}
|
||||
/**
|
||||
* compare_gpts() - Search disk for valid GPT headers and PTEs
|
||||
* @pgpt is the primary GPT header
|
||||
* @agpt is the alternate GPT header
|
||||
* @lastlba is the last LBA number
|
||||
* Description: Returns nothing. Sanity checks pgpt and agpt fields
|
||||
* and prints warnings on discrepancies.
|
||||
*
|
||||
*/
|
||||
static void
|
||||
compare_gpts(gpt_header *pgpt, gpt_header *agpt, uint64_t lastlba)
|
||||
{
|
||||
int error_found = 0;
|
||||
if (!pgpt || !agpt)
|
||||
return;
|
||||
if (le64_to_cpu(pgpt->my_lba) != le64_to_cpu(agpt->alternate_lba)) {
|
||||
fprintf(stderr,
|
||||
"GPT:Primary header LBA != Alt. header alternate_lba\n");
|
||||
fprintf(stderr, "GPT:%" PRIx64 "x != %" PRIx64 "x\n",
|
||||
le64_to_cpu(pgpt->my_lba),
|
||||
le64_to_cpu(agpt->alternate_lba));
|
||||
error_found++;
|
||||
}
|
||||
if (le64_to_cpu(pgpt->alternate_lba) != le64_to_cpu(agpt->my_lba)) {
|
||||
fprintf(stderr,
|
||||
"GPT:Primary header alternate_lba != Alt. header my_lba\n");
|
||||
fprintf(stderr, "GPT:%" PRIx64 " != %" PRIx64 "\n",
|
||||
le64_to_cpu(pgpt->alternate_lba),
|
||||
le64_to_cpu(agpt->my_lba));
|
||||
error_found++;
|
||||
}
|
||||
if (le64_to_cpu(pgpt->first_usable_lba) !=
|
||||
le64_to_cpu(agpt->first_usable_lba)) {
|
||||
fprintf(stderr, "GPT:first_usable_lbas don't match.\n");
|
||||
fprintf(stderr, "GPT:%" PRIx64 " != %" PRIx64 "\n",
|
||||
le64_to_cpu(pgpt->first_usable_lba),
|
||||
le64_to_cpu(agpt->first_usable_lba));
|
||||
error_found++;
|
||||
}
|
||||
if (le64_to_cpu(pgpt->last_usable_lba) !=
|
||||
le64_to_cpu(agpt->last_usable_lba)) {
|
||||
fprintf(stderr, "GPT:last_usable_lbas don't match.\n");
|
||||
fprintf(stderr, "GPT:%" PRIx64 " != %" PRIx64 "\n",
|
||||
le64_to_cpu(pgpt->last_usable_lba),
|
||||
le64_to_cpu(agpt->last_usable_lba));
|
||||
error_found++;
|
||||
}
|
||||
if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid)) {
|
||||
fprintf(stderr, "GPT:disk_guids don't match.\n");
|
||||
error_found++;
|
||||
}
|
||||
if (le32_to_cpu(pgpt->num_partition_entries) !=
|
||||
le32_to_cpu(agpt->num_partition_entries)) {
|
||||
fprintf(stderr, "GPT:num_partition_entries don't match: "
|
||||
"0x%x != 0x%x\n",
|
||||
le32_to_cpu(pgpt->num_partition_entries),
|
||||
le32_to_cpu(agpt->num_partition_entries));
|
||||
error_found++;
|
||||
}
|
||||
if (le32_to_cpu(pgpt->sizeof_partition_entry) !=
|
||||
le32_to_cpu(agpt->sizeof_partition_entry)) {
|
||||
fprintf(stderr,
|
||||
"GPT:sizeof_partition_entry values don't match: "
|
||||
"0x%x != 0x%x\n",
|
||||
le32_to_cpu(pgpt->sizeof_partition_entry),
|
||||
le32_to_cpu(agpt->sizeof_partition_entry));
|
||||
error_found++;
|
||||
}
|
||||
if (le32_to_cpu(pgpt->partition_entry_array_crc32) !=
|
||||
le32_to_cpu(agpt->partition_entry_array_crc32)) {
|
||||
fprintf(stderr,
|
||||
"GPT:partition_entry_array_crc32 values don't match: "
|
||||
"0x%x != 0x%x\n",
|
||||
le32_to_cpu(pgpt->partition_entry_array_crc32),
|
||||
le32_to_cpu(agpt->partition_entry_array_crc32));
|
||||
error_found++;
|
||||
}
|
||||
if (le64_to_cpu(pgpt->alternate_lba) != lastlba) {
|
||||
fprintf(stderr,
|
||||
"GPT:Primary header thinks Alt. header is not at the end of the disk.\n");
|
||||
fprintf(stderr, "GPT:%" PRIx64 " != %" PRIx64 "\n",
|
||||
le64_to_cpu(pgpt->alternate_lba), lastlba);
|
||||
error_found++;
|
||||
}
|
||||
|
||||
if (le64_to_cpu(agpt->my_lba) != lastlba) {
|
||||
fprintf(stderr,
|
||||
"GPT:Alternate GPT header not at the end of the disk.\n");
|
||||
fprintf(stderr, "GPT:%" PRIx64 " != %" PRIx64 "\n",
|
||||
le64_to_cpu(agpt->my_lba), lastlba);
|
||||
error_found++;
|
||||
}
|
||||
|
||||
if (error_found)
|
||||
fprintf(stderr,
|
||||
"GPT: Use GNU Parted to correct GPT errors.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* find_valid_gpt() - Search disk for valid GPT headers and PTEs
|
||||
* @fd is an open file descriptor to the whole disk
|
||||
* @gpt is a GPT header ptr, filled on return.
|
||||
* @ptes is a PTEs ptr, filled on return.
|
||||
* Description: Returns 1 if valid, 0 on error.
|
||||
* If valid, returns pointers to newly allocated GPT header and PTEs.
|
||||
* Validity depends on finding either the Primary GPT header and PTEs valid,
|
||||
* or the Alternate GPT header and PTEs valid, and the PMBR valid.
|
||||
*/
|
||||
static int
|
||||
find_valid_gpt(int fd, gpt_header ** gpt, gpt_entry ** ptes)
|
||||
{
|
||||
extern int force_gpt;
|
||||
int good_pgpt = 0, good_agpt = 0, good_pmbr = 0;
|
||||
gpt_header *pgpt = NULL, *agpt = NULL;
|
||||
gpt_entry *pptes = NULL, *aptes = NULL;
|
||||
legacy_mbr *legacymbr = NULL;
|
||||
uint64_t lastlba;
|
||||
if (!gpt || !ptes)
|
||||
return 0;
|
||||
|
||||
lastlba = last_lba(fd);
|
||||
good_pgpt = is_gpt_valid(fd, GPT_PRIMARY_PARTITION_TABLE_LBA,
|
||||
&pgpt, &pptes);
|
||||
if (good_pgpt) {
|
||||
good_agpt = is_gpt_valid(fd,
|
||||
le64_to_cpu(pgpt->alternate_lba),
|
||||
&agpt, &aptes);
|
||||
if (!good_agpt) {
|
||||
good_agpt = is_gpt_valid(fd, lastlba,
|
||||
&agpt, &aptes);
|
||||
}
|
||||
}
|
||||
else {
|
||||
good_agpt = is_gpt_valid(fd, lastlba,
|
||||
&agpt, &aptes);
|
||||
}
|
||||
|
||||
/* The obviously unsuccessful case */
|
||||
if (!good_pgpt && !good_agpt) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* This will be added to the EFI Spec. per Intel after v1.02. */
|
||||
legacymbr = malloc(sizeof (*legacymbr));
|
||||
if (legacymbr) {
|
||||
memset(legacymbr, 0, sizeof (*legacymbr));
|
||||
read_lba(fd, 0, (uint8_t *) legacymbr,
|
||||
sizeof (*legacymbr));
|
||||
good_pmbr = is_pmbr_valid(legacymbr);
|
||||
free(legacymbr);
|
||||
legacymbr=NULL;
|
||||
}
|
||||
|
||||
/* Failure due to bad PMBR */
|
||||
if ((good_pgpt || good_agpt) && !good_pmbr && !force_gpt) {
|
||||
fprintf(stderr,
|
||||
" Warning: Disk has a valid GPT signature "
|
||||
"but invalid PMBR.\n"
|
||||
" Assuming this disk is *not* a GPT disk anymore.\n"
|
||||
" Use gpt kernel option to override. "
|
||||
"Use GNU Parted to correct disk.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Would fail due to bad PMBR, but force GPT anyhow */
|
||||
if ((good_pgpt || good_agpt) && !good_pmbr && force_gpt) {
|
||||
fprintf(stderr,
|
||||
" Warning: Disk has a valid GPT signature but "
|
||||
"invalid PMBR.\n"
|
||||
" Use GNU Parted to correct disk.\n"
|
||||
" gpt option taken, disk treated as GPT.\n");
|
||||
}
|
||||
|
||||
compare_gpts(pgpt, agpt, lastlba);
|
||||
|
||||
/* The good cases */
|
||||
if (good_pgpt && (good_pmbr || force_gpt)) {
|
||||
*gpt = pgpt;
|
||||
*ptes = pptes;
|
||||
if (agpt) { free(agpt); agpt = NULL; }
|
||||
if (aptes) { free(aptes); aptes = NULL; }
|
||||
if (!good_agpt) {
|
||||
fprintf(stderr,
|
||||
"Alternate GPT is invalid, "
|
||||
"using primary GPT.\n");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else if (good_agpt && (good_pmbr || force_gpt)) {
|
||||
*gpt = agpt;
|
||||
*ptes = aptes;
|
||||
if (pgpt) { free(pgpt); pgpt = NULL; }
|
||||
if (pptes) { free(pptes); pptes = NULL; }
|
||||
fprintf(stderr,
|
||||
"Primary GPT is invalid, using alternate GPT.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fail:
|
||||
if (pgpt) { free(pgpt); pgpt=NULL; }
|
||||
if (agpt) { free(agpt); agpt=NULL; }
|
||||
if (pptes) { free(pptes); pptes=NULL; }
|
||||
if (aptes) { free(aptes); aptes=NULL; }
|
||||
*gpt = NULL;
|
||||
*ptes = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* read_gpt_pt()
|
||||
* @fd
|
||||
* @all - slice with start/size of whole disk
|
||||
*
|
||||
* 0 if this isn't our partition table
|
||||
* number of partitions if successful
|
||||
*
|
||||
*/
|
||||
int
|
||||
read_gpt_pt (int fd, struct slice all, struct slice *sp, int ns)
|
||||
{
|
||||
gpt_header *gpt = NULL;
|
||||
gpt_entry *ptes = NULL;
|
||||
uint32_t i;
|
||||
int n = 0;
|
||||
int last_used_index=-1;
|
||||
|
||||
if (!find_valid_gpt (fd, &gpt, &ptes) || !gpt || !ptes) {
|
||||
free (gpt);
|
||||
free (ptes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < ns; i++) {
|
||||
if (!efi_guidcmp (NULL_GUID, ptes[i].partition_type_guid)) {
|
||||
sp[n].start = 0;
|
||||
sp[n].size = 0;
|
||||
n++;
|
||||
} else {
|
||||
sp[n].start = le64_to_cpu(ptes[i].starting_lba);
|
||||
sp[n].size = le64_to_cpu(ptes[i].ending_lba) -
|
||||
le64_to_cpu(ptes[i].starting_lba) + 1;
|
||||
last_used_index=n;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
free (ptes);
|
||||
free (gpt);
|
||||
return last_used_index+1;
|
||||
}
|
131
partx/gpt.h
131
partx/gpt.h
|
@ -1,131 +0,0 @@
|
|||
/*
|
||||
gpt.[ch]
|
||||
|
||||
Copyright (C) 2000-2001 Dell Computer Corporation <Matt_Domsch@dell.com>
|
||||
|
||||
EFI GUID Partition Table handling
|
||||
Per Intel EFI Specification v1.02
|
||||
http://developer.intel.com/technology/efi/efi.htm
|
||||
|
||||
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 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _GPT_H
|
||||
#define _GPT_H
|
||||
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "partx.h"
|
||||
#include "dos.h"
|
||||
#include "efi.h"
|
||||
|
||||
#define EFI_PMBR_OSTYPE_EFI 0xEF
|
||||
#define EFI_PMBR_OSTYPE_EFI_GPT 0xEE
|
||||
#define MSDOS_MBR_SIGNATURE 0xaa55
|
||||
#define GPT_BLOCK_SIZE 512
|
||||
|
||||
#define GPT_HEADER_SIGNATURE 0x5452415020494645ULL
|
||||
#define GPT_HEADER_REVISION_V1_02 0x00010200
|
||||
#define GPT_HEADER_REVISION_V1_00 0x00010000
|
||||
#define GPT_HEADER_REVISION_V0_99 0x00009900
|
||||
#define GPT_PRIMARY_PARTITION_TABLE_LBA 1
|
||||
|
||||
typedef struct _gpt_header {
|
||||
uint64_t signature;
|
||||
uint32_t revision;
|
||||
uint32_t header_size;
|
||||
uint32_t header_crc32;
|
||||
uint32_t reserved1;
|
||||
uint64_t my_lba;
|
||||
uint64_t alternate_lba;
|
||||
uint64_t first_usable_lba;
|
||||
uint64_t last_usable_lba;
|
||||
efi_guid_t disk_guid;
|
||||
uint64_t partition_entry_lba;
|
||||
uint32_t num_partition_entries;
|
||||
uint32_t sizeof_partition_entry;
|
||||
uint32_t partition_entry_array_crc32;
|
||||
uint8_t reserved2[GPT_BLOCK_SIZE - 92];
|
||||
} __attribute__ ((packed)) gpt_header;
|
||||
|
||||
typedef struct _gpt_entry_attributes {
|
||||
uint64_t required_to_function:1;
|
||||
uint64_t reserved:47;
|
||||
uint64_t type_guid_specific:16;
|
||||
} __attribute__ ((packed)) gpt_entry_attributes;
|
||||
|
||||
typedef struct _gpt_entry {
|
||||
efi_guid_t partition_type_guid;
|
||||
efi_guid_t unique_partition_guid;
|
||||
uint64_t starting_lba;
|
||||
uint64_t ending_lba;
|
||||
gpt_entry_attributes attributes;
|
||||
efi_char16_t partition_name[72 / sizeof(efi_char16_t)];
|
||||
} __attribute__ ((packed)) gpt_entry;
|
||||
|
||||
|
||||
/*
|
||||
These values are only defaults. The actual on-disk structures
|
||||
may define different sizes, so use those unless creating a new GPT disk!
|
||||
*/
|
||||
|
||||
#define GPT_DEFAULT_RESERVED_PARTITION_ENTRY_ARRAY_SIZE 16384
|
||||
/*
|
||||
Number of actual partition entries should be calculated
|
||||
as:
|
||||
*/
|
||||
#define GPT_DEFAULT_RESERVED_PARTITION_ENTRIES \
|
||||
(GPT_DEFAULT_RESERVED_PARTITION_ENTRY_ARRAY_SIZE / \
|
||||
sizeof(gpt_entry))
|
||||
|
||||
|
||||
/* Protected Master Boot Record & Legacy MBR share same structure */
|
||||
/* Needs to be packed because the u16s force misalignment. */
|
||||
|
||||
typedef struct _legacy_mbr {
|
||||
uint8_t bootcode[440];
|
||||
uint32_t unique_mbr_signature;
|
||||
uint16_t unknown;
|
||||
struct partition partition[4];
|
||||
uint16_t signature;
|
||||
} __attribute__ ((packed)) legacy_mbr;
|
||||
|
||||
|
||||
#define EFI_GPT_PRIMARY_PARTITION_TABLE_LBA 1
|
||||
|
||||
/* Functions */
|
||||
int read_gpt_pt (int fd, struct slice all, struct slice *sp, int ns);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-indent-level: 4
|
||||
* c-brace-imaginary-offset: 0
|
||||
* c-brace-offset: -4
|
||||
* c-argdecl-indent: 4
|
||||
* c-label-offset: -4
|
||||
* c-continued-statement-offset: 4
|
||||
* c-continued-brace-offset: 0
|
||||
* indent-tabs-mode: nil
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
74
partx/mac.c
74
partx/mac.c
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
* Lifted from kpartx's mac.c
|
||||
*
|
||||
* Integrated to partx
|
||||
* Davidlohr Bueso <dave@gnu.org>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "bitops.h"
|
||||
#include "partx.h"
|
||||
|
||||
#define MAC_PARTITION_MAGIC 0x504d
|
||||
#define MAC_DRIVER_MAGIC 0x4552
|
||||
|
||||
struct mac_partition {
|
||||
uint16_t signature; /* expected to be MAC_PARTITION_MAGIC */
|
||||
uint16_t res1;
|
||||
uint32_t map_count; /* # blocks in partition map */
|
||||
uint32_t start_block; /* absolute starting block # of partition */
|
||||
uint32_t block_count; /* number of blocks in partition */
|
||||
/* there is more stuff after this that we don't need */
|
||||
};
|
||||
|
||||
/* Driver descriptor structure, in block 0 */
|
||||
struct mac_driver_desc {
|
||||
uint16_t signature; /* expected to be MAC_DRIVER_MAGIC */
|
||||
uint16_t block_size;
|
||||
uint32_t block_count;
|
||||
};
|
||||
|
||||
int
|
||||
read_mac_pt(int fd, struct slice all, struct slice *sp, int ns) {
|
||||
struct mac_driver_desc *md;
|
||||
struct mac_partition *part;
|
||||
unsigned secsize;
|
||||
unsigned char *data;
|
||||
int blk, blocks_in_map;
|
||||
int n = 0;
|
||||
|
||||
md = (struct mac_driver_desc *) getblock(fd, 0);
|
||||
if (md == NULL)
|
||||
return -1;
|
||||
|
||||
if (be16_to_cpu(md->signature) != MAC_DRIVER_MAGIC)
|
||||
return -1;
|
||||
|
||||
secsize = be16_to_cpu(md->block_size);
|
||||
data = getblock(fd, secsize/512);
|
||||
if (!data)
|
||||
return -1;
|
||||
part = (struct mac_partition *) (data + secsize%512);
|
||||
|
||||
if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
|
||||
return -1;
|
||||
|
||||
blocks_in_map = be32_to_cpu(part->map_count);
|
||||
for (blk = 1; blk <= blocks_in_map && blk <= ns; ++blk, ++n) {
|
||||
int pos = blk * secsize;
|
||||
data = getblock(fd, pos/512);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
part = (struct mac_partition *) (data + pos%512);
|
||||
if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
|
||||
break;
|
||||
|
||||
sp[n].start = be32_to_cpu(part->start_block) * (secsize/512);
|
||||
sp[n].size = be32_to_cpu(part->block_count) * (secsize/512);
|
||||
}
|
||||
return n;
|
||||
}
|
117
partx/partx.8
117
partx/partx.8
|
@ -1,48 +1,112 @@
|
|||
.\" partx.8 --
|
||||
.\" Copyright 2007 Karel Zak <kzak@redhat.com>
|
||||
.\" Copyright 2007 Red Hat, Inc.
|
||||
.\" Copyright 2010 Davidlohr Bueso <dave@gnu.org>
|
||||
.\" May be distributed under the GNU General Public License
|
||||
.TH PARTX 8 "11 Jan 2007"
|
||||
.TH PARTX 8 "28 Oct 2010"
|
||||
.SH NAME
|
||||
partx \-
|
||||
telling the kernel about presence and numbering of on-disk partitions.
|
||||
tell the linux kernel about presence and numbering of on-disk partitions.
|
||||
.SH SYNOPSIS
|
||||
.B partx
|
||||
.RB [ \-a | \-d | \-l ]
|
||||
.RB [ \-\-type
|
||||
.RB [ \-a | \-d | \-s ]
|
||||
.RB [ \-t
|
||||
.IR TYPE ]
|
||||
.RB [ \-\-nr
|
||||
.IR M-N ]
|
||||
.RI [ partition ]
|
||||
.RB [ \-n
|
||||
.IR M:N ]
|
||||
.RI [ \- ]
|
||||
.I disk
|
||||
|
||||
.B partx
|
||||
.RB [ \-a | \-d | \-s ]
|
||||
.RB [ \-t
|
||||
.IR TYPE ]
|
||||
.I partition
|
||||
.RI [ disk ]
|
||||
|
||||
.SH DESCRIPTION
|
||||
Given a block device (
|
||||
.B disk
|
||||
) and a partition table
|
||||
.B type
|
||||
, try to parse the partition table, and list the
|
||||
Given a device or disk-image, try to parse the partition table, and list the
|
||||
contents. Optionally add or remove partitions.
|
||||
|
||||
This is not an fdisk - adding and removing partitions
|
||||
The
|
||||
.I disk
|
||||
argument is optional when a
|
||||
.I partition
|
||||
argument is provided. It's possible to force scannig on partition (for example
|
||||
to list nested subpartitions), then the string "-" has to be used, for example:
|
||||
|
||||
.RS
|
||||
.br
|
||||
.B partx \-\-show \- /dev/sda3
|
||||
.RE
|
||||
|
||||
This will use sda3 as a whole-disk rather than a partition.
|
||||
|
||||
.B This is not an fdisk
|
||||
\- adding and removing partitions
|
||||
is not a change of the disk, but just telling the kernel
|
||||
about presence and numbering of on-disk partitions.
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-a
|
||||
.IP "\fB\-a, \-\-add\fP"
|
||||
add specified partitions or read disk and add all partitions
|
||||
.TP
|
||||
.B \-d
|
||||
.IP "\fB\-b, \-\-bytes\fP"
|
||||
Print the SIZE column in bytes rather than in human readable format.
|
||||
.IP "\fB\-d, \-\-delete\fP"
|
||||
delete specified or all partitions
|
||||
.IP "\fB\-l, \-\-list\fP"
|
||||
list partitions. Note that the all numbers are in 512-byte sectors. This output
|
||||
format is DEPRECATED in favour of \fB\-\-show\fP. Don't use it in newly written
|
||||
scripts.
|
||||
.IP "\fB\-g, \-\-noheadings\fP"
|
||||
Do not print a header line.
|
||||
.IP "\fB\-o, \-\-output \fIlist\fP"
|
||||
Define output columns for \fB\-\-show\fP and \fB\-\-raw\fP output. If output format is
|
||||
not specified then \fB\-\-show\fP is enable by default. Use \fB\-\-help\fP to
|
||||
get list of all supported columns.
|
||||
.IP "\fB\-r, \-\-raw\fP"
|
||||
Use raw output format.
|
||||
.IP "\fB\-s, \-\-show\fP"
|
||||
list partitions. All numbers (except SIZE) are in 512-byte sectors. The output
|
||||
columns could be (re)defined by \fB\-\-output\fP option.
|
||||
.IP "\fB\-t, \-\-type \fItype\fP"
|
||||
Specify the partition table type -- dos, bsd, solaris, unixware or gpt.
|
||||
.IP "\fB\-n, \-\-nr \fIM:N\fP"
|
||||
Specify the range of partitions. For backward compatibility is also supported
|
||||
range definition in <M-N> format. The range could be specified by negative
|
||||
numbers, for example "--nr :-1" means last partition, and "--nr -2:-1" means
|
||||
last two partition. Supported range specifications:
|
||||
.RS
|
||||
.TP
|
||||
.B \-l
|
||||
list partitions. Note that the all numbers are in 512-byte sectors.
|
||||
.B <M>
|
||||
Specify only one partition (e.g. --nr 3).
|
||||
.TP
|
||||
.BI --type " TYPE"
|
||||
Specify the partition type -- dos, bsd, solaris, unixware or gpt.
|
||||
.B <M:>
|
||||
Specify lower limit only (e.g. --nr 2:).
|
||||
.TP
|
||||
.BI --nr " M-N"
|
||||
Specify the range of partitions (e.g --nr 2-4).
|
||||
.B <:N>
|
||||
Specify upper limit only (e.g. --nr :4).
|
||||
.TP
|
||||
.B <M:N>
|
||||
or
|
||||
.B <M-N>
|
||||
Specify lower and upper limits (e.g. --nr 2:4).
|
||||
.RE
|
||||
.SH EXAMPLES
|
||||
.IP "\fBpartx \-\-show /dev/sdb3\fP"
|
||||
.IP "\fBpartx \-\-show --nr 3 /dev/sdb\fP"
|
||||
.IP "\fBpartx \-\-show /dev/sdb3 /dev/sdb\fP"
|
||||
List partition 3 of /dev/sdb.
|
||||
.IP "\fBpartx \-\-show \- /dev/sdb3\fP"
|
||||
List all subpartitions on /dev/sdb3 (the device is used as whole-disk).
|
||||
.IP "\fBpartx \-o START -g --nr 3 /dev/sdb\fP"
|
||||
Print the start sector of partition 5 on /dev/sda without header.
|
||||
.IP "\fBpartx \-o SECTORS,SIZE /dev/sda5 /dev/sda\fP"
|
||||
List the length in sectors and human readable size of partition 5 on /dev/sda.
|
||||
.IP "\fBpartx \-\-add --nr 3:5 /dev/sdd\fP"
|
||||
Add all available partitions from 3 to 5 (inclusive) on /dev/sdd.
|
||||
.IP "\fBpartx \-d --nr :-1 /dev/sdd\fP"
|
||||
Removes last partition on /dev/sdd.
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR addpart (8),
|
||||
|
@ -51,6 +115,13 @@ Specify the range of partitions (e.g --nr 2-4).
|
|||
.BR parted (8),
|
||||
.BR partprobe (8)
|
||||
|
||||
.SH SEE ALSO
|
||||
.nf
|
||||
Davidlohr Bueso <dave@gnu.org>
|
||||
Karel Zak <kzak@redhat.com>
|
||||
.fi
|
||||
|
||||
The original version was written by Andries E. Brouwer <aeb@cwi.nl>.
|
||||
.SH AVAILABILITY
|
||||
The partx command is part of the util-linux package and is available from
|
||||
ftp://ftp.kernel.org/pub/linux/utils/util-linux/.
|
||||
|
|
1118
partx/partx.c
1118
partx/partx.c
File diff suppressed because it is too large
Load diff
|
@ -1,32 +1,44 @@
|
|||
#ifndef PARTX_H_INCLUDED
|
||||
#define PARTX_H_INCLUDED
|
||||
#ifndef UTIL_LINUX_PARTX_H
|
||||
#define UTIL_LINUX_PARTX_H
|
||||
|
||||
/*
|
||||
* For each partition type there is a routine that takes
|
||||
* a block device and a range, and returns the list of
|
||||
* slices found there in the supplied array SP that can
|
||||
* hold NS entries. The return value is the number of
|
||||
* entries stored, or -1 if the appropriate type is not
|
||||
* present.
|
||||
*/
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/blkpg.h>
|
||||
|
||||
static inline int partx_del_partition(int fd, int partno)
|
||||
{
|
||||
struct blkpg_ioctl_arg a;
|
||||
struct blkpg_partition p;
|
||||
|
||||
/* units: 512 byte sectors */
|
||||
struct slice {
|
||||
unsigned int start;
|
||||
unsigned int size;
|
||||
};
|
||||
p.pno = partno;
|
||||
p.start = 0;
|
||||
p.length = 0;
|
||||
p.devname[0] = 0;
|
||||
p.volname[0] = 0;
|
||||
a.op = BLKPG_DEL_PARTITION;
|
||||
a.flags = 0;
|
||||
a.datalen = sizeof(p);
|
||||
a.data = &p;
|
||||
|
||||
typedef int (ptreader)(int fd, struct slice all, struct slice *sp, int ns);
|
||||
|
||||
extern ptreader read_dos_pt, read_bsd_pt, read_solaris_pt, read_unixware_pt, read_gpt_pt;
|
||||
extern ptreader read_sun_pt, read_mac_pt;
|
||||
|
||||
unsigned char *getblock(int fd, unsigned int secnr);
|
||||
|
||||
static inline int
|
||||
four2int(unsigned char *p) {
|
||||
return p[0] + (p[1]<<8) + (p[2]<<16) + (p[3]<<24);
|
||||
return ioctl(fd, BLKPG, &a);
|
||||
}
|
||||
|
||||
#endif /* PARTX_H_INCLUDED */
|
||||
static inline int partx_add_partition(int fd, int partno,
|
||||
unsigned long start, unsigned long size)
|
||||
{
|
||||
struct blkpg_ioctl_arg a;
|
||||
struct blkpg_partition p;
|
||||
|
||||
p.pno = partno;
|
||||
p.start = start << 9;
|
||||
p.length = size << 9;
|
||||
p.devname[0] = 0;
|
||||
p.volname[0] = 0;
|
||||
a.op = BLKPG_ADD_PARTITION;
|
||||
a.flags = 0;
|
||||
a.datalen = sizeof(p);
|
||||
a.data = &p;
|
||||
|
||||
return ioctl(fd, BLKPG, &a);
|
||||
}
|
||||
|
||||
#endif /* UTIL_LINUX_PARTX_H */
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <time.h> /* time_t */
|
||||
#include <sys/types.h>
|
||||
#include "partx.h"
|
||||
|
||||
#define SOLARIS_X86_NUMSLICE 8
|
||||
#define SOLARIS_X86_VTOC_SANE (0x600DDEEEUL)
|
||||
|
||||
struct solaris_x86_slice {
|
||||
unsigned short s_tag; /* ID tag of partition */
|
||||
unsigned short s_flag; /* permision flags */
|
||||
daddr_t s_start; /* start sector no of partition */
|
||||
long s_size; /* # of blocks in partition */
|
||||
};
|
||||
|
||||
struct solaris_x86_vtoc {
|
||||
unsigned long v_bootinfo[3]; /* info for mboot */
|
||||
unsigned long v_sanity; /* to verify vtoc sanity */
|
||||
unsigned long v_version; /* layout version */
|
||||
char v_volume[8]; /* volume name */
|
||||
unsigned short v_sectorsz; /* sector size in bytes */
|
||||
unsigned short v_nparts; /* number of partitions */
|
||||
unsigned long v_reserved[10]; /* free space */
|
||||
struct solaris_x86_slice
|
||||
v_slice[SOLARIS_X86_NUMSLICE]; /* slice headers */
|
||||
time_t timestamp[SOLARIS_X86_NUMSLICE]; /* timestamp */
|
||||
char v_asciilabel[128]; /* for compatibility */
|
||||
};
|
||||
|
||||
int
|
||||
read_solaris_pt(int fd, struct slice all, struct slice *sp, int ns) {
|
||||
struct solaris_x86_vtoc *v;
|
||||
struct solaris_x86_slice *s;
|
||||
unsigned int offset = all.start;
|
||||
int i, n;
|
||||
unsigned char *bp;
|
||||
|
||||
bp = getblock(fd, offset+1); /* 1 sector suffices */
|
||||
if (bp == NULL)
|
||||
return -1;
|
||||
|
||||
v = (struct solaris_x86_vtoc *) bp;
|
||||
if(v->v_sanity != SOLARIS_X86_VTOC_SANE)
|
||||
return -1;
|
||||
|
||||
if(v->v_version != 1) {
|
||||
fprintf(stderr, "Cannot handle solaris version %ld vtoc\n",
|
||||
v->v_version);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(i=0, n=0; i<SOLARIS_X86_NUMSLICE; i++) {
|
||||
s = &v->v_slice[i];
|
||||
|
||||
if (s->s_size == 0)
|
||||
continue;
|
||||
if (n < ns) {
|
||||
sp[n].start = offset + s->s_start;
|
||||
sp[n].size = s->s_size;
|
||||
n++;
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"solaris_x86_partition: too many slices\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
130
partx/sun.c
130
partx/sun.c
|
@ -1,130 +0,0 @@
|
|||
/*
|
||||
* Lifted from kpartx's sun.c
|
||||
*
|
||||
* Copyrights of the original file apply
|
||||
* Copyright (c) 2007 Hannes Reinecke
|
||||
*
|
||||
* Integrated to partx
|
||||
* Davidlohr Bueso <dave@gnu.org>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "bitops.h"
|
||||
#include "partx.h"
|
||||
|
||||
#define SUN_DISK_MAGIC 0xDABE /* Disk magic number */
|
||||
#define SUN_DISK_MAXPARTITIONS 8
|
||||
|
||||
struct __attribute__ ((packed)) sun_raw_part {
|
||||
u_int32_t start_cylinder; /* where the part starts... */
|
||||
u_int32_t num_sectors; /* ...and it's length */
|
||||
};
|
||||
|
||||
struct __attribute__ ((packed)) sun_part_info {
|
||||
u_int8_t spare1;
|
||||
u_int8_t id; /* Partition type */
|
||||
u_int8_t spare2;
|
||||
u_int8_t flags; /* Partition flags */
|
||||
};
|
||||
|
||||
struct __attribute__ ((packed)) sun_disk_label {
|
||||
char info[128]; /* Informative text string */
|
||||
u_int8_t spare0[14];
|
||||
struct sun_part_info infos[SUN_DISK_MAXPARTITIONS];
|
||||
u_int8_t spare1[246]; /* Boot information etc. */
|
||||
u_int16_t rspeed; /* Disk rotational speed */
|
||||
u_int16_t pcylcount; /* Physical cylinder count */
|
||||
u_int16_t sparecyl; /* extra sects per cylinder */
|
||||
u_int8_t spare2[4]; /* More magic... */
|
||||
u_int16_t ilfact; /* Interleave factor */
|
||||
u_int16_t ncyl; /* Data cylinder count */
|
||||
u_int16_t nacyl; /* Alt. cylinder count */
|
||||
u_int16_t ntrks; /* Tracks per cylinder */
|
||||
u_int16_t nsect; /* Sectors per track */
|
||||
u_int8_t spare3[4]; /* Even more magic... */
|
||||
struct sun_raw_part partitions[SUN_DISK_MAXPARTITIONS];
|
||||
u_int16_t magic; /* Magic number */
|
||||
u_int16_t csum; /* Label xor'd checksum */
|
||||
};
|
||||
|
||||
/* Checksum Verification */
|
||||
static int
|
||||
sun_verify_checksum (struct sun_disk_label *label)
|
||||
{
|
||||
u_int16_t *ush = ((u_int16_t *)(label + 1)) - 1;
|
||||
u_int16_t csum = 0;
|
||||
|
||||
while (ush >= (u_int16_t *)label)
|
||||
csum ^= *ush--;
|
||||
|
||||
return !csum;
|
||||
}
|
||||
|
||||
int
|
||||
read_sun_pt(int fd, struct slice all, struct slice *sp, int ns) {
|
||||
struct sun_disk_label *l;
|
||||
struct sun_raw_part *s;
|
||||
unsigned int offset = all.start, end;
|
||||
int i, j, n;
|
||||
unsigned char *bp;
|
||||
|
||||
bp = getblock(fd, offset);
|
||||
if (bp == NULL)
|
||||
return -1;
|
||||
|
||||
l = (struct sun_disk_label *) bp;
|
||||
if(be16_to_cpu(l->magic) != SUN_DISK_MAGIC)
|
||||
return -1;
|
||||
|
||||
if (!sun_verify_checksum(l)) {
|
||||
fprintf(stderr, "Corrupted Sun disk label\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(i=0, n=0; i<SUN_DISK_MAXPARTITIONS; i++) {
|
||||
s = &l->partitions[i];
|
||||
|
||||
if (s->num_sectors == 0)
|
||||
continue;
|
||||
if (n < ns) {
|
||||
sp[n].start = offset +
|
||||
be32_to_cpu(s->start_cylinder) * be16_to_cpu(l->nsect) * be16_to_cpu(l->ntrks);
|
||||
sp[n].size = be32_to_cpu(s->num_sectors);
|
||||
n++;
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"sun_disklabel: too many slices\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Convention has it that the SUN disklabel will always have
|
||||
* the 'c' partition spanning the entire disk.
|
||||
* So we have to check for contained slices.
|
||||
*/
|
||||
for(i = 0; i < SUN_DISK_MAXPARTITIONS; i++) {
|
||||
if (sp[i].size == 0)
|
||||
continue;
|
||||
|
||||
end = sp[i].start + sp[i].size;
|
||||
for(j = 0; j < SUN_DISK_MAXPARTITIONS; j ++) {
|
||||
if ( i == j )
|
||||
continue;
|
||||
if (sp[j].size == 0)
|
||||
continue;
|
||||
|
||||
if (sp[i].start < sp[j].start) {
|
||||
if (end > sp[j].start &&
|
||||
end < sp[j].start + sp[j].size) {
|
||||
/* Invalid slice */
|
||||
fprintf(stderr,
|
||||
"sun_disklabel: slice %d overlaps with %d\n", i , j);
|
||||
sp[i].size = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include "partx.h"
|
||||
|
||||
#define UNIXWARE_FS_UNUSED 0
|
||||
#define UNIXWARE_NUMSLICE 16
|
||||
#define UNIXWARE_DISKMAGIC (0xCA5E600D)
|
||||
#define UNIXWARE_DISKMAGIC2 (0x600DDEEE)
|
||||
|
||||
struct unixware_slice {
|
||||
unsigned short s_label; /* label */
|
||||
unsigned short s_flags; /* permission flags */
|
||||
unsigned int start_sect; /* starting sector */
|
||||
unsigned int nr_sects; /* number of sectors in slice */
|
||||
};
|
||||
|
||||
struct unixware_disklabel {
|
||||
unsigned int d_type; /* drive type */
|
||||
unsigned char d_magic[4]; /* the magic number */
|
||||
unsigned int d_version; /* version number */
|
||||
char d_serial[12]; /* serial number of the device */
|
||||
unsigned int d_ncylinders; /* # of data cylinders per device */
|
||||
unsigned int d_ntracks; /* # of tracks per cylinder */
|
||||
unsigned int d_nsectors; /* # of data sectors per track */
|
||||
unsigned int d_secsize; /* # of bytes per sector */
|
||||
unsigned int d_part_start; /* # of first sector of this partition */
|
||||
unsigned int d_unknown1[12]; /* ? */
|
||||
unsigned int d_alt_tbl; /* byte offset of alternate table */
|
||||
unsigned int d_alt_len; /* byte length of alternate table */
|
||||
unsigned int d_phys_cyl; /* # of physical cylinders per device */
|
||||
unsigned int d_phys_trk; /* # of physical tracks per cylinder */
|
||||
unsigned int d_phys_sec; /* # of physical sectors per track */
|
||||
unsigned int d_phys_bytes; /* # of physical bytes per sector */
|
||||
unsigned int d_unknown2; /* ? */
|
||||
unsigned int d_unknown3; /* ? */
|
||||
unsigned int d_pad[8]; /* pad */
|
||||
|
||||
struct unixware_vtoc {
|
||||
unsigned char v_magic[4]; /* the magic number */
|
||||
unsigned int v_version; /* version number */
|
||||
char v_name[8]; /* volume name */
|
||||
unsigned short v_nslices; /* # of slices */
|
||||
unsigned short v_unknown1; /* ? */
|
||||
unsigned int v_reserved[10]; /* reserved */
|
||||
struct unixware_slice
|
||||
v_slice[UNIXWARE_NUMSLICE]; /* slice headers */
|
||||
} vtoc;
|
||||
|
||||
}; /* 408 */
|
||||
|
||||
int
|
||||
read_unixware_pt(int fd, struct slice all, struct slice *sp, int ns) {
|
||||
struct unixware_disklabel *l;
|
||||
struct unixware_slice *p;
|
||||
unsigned int offset = all.start;
|
||||
unsigned char *bp;
|
||||
int n = 0;
|
||||
|
||||
bp = getblock(fd, offset+29); /* 1 sector suffices */
|
||||
if (bp == NULL)
|
||||
return -1;
|
||||
|
||||
l = (struct unixware_disklabel *) bp;
|
||||
if (four2int(l->d_magic) != UNIXWARE_DISKMAGIC ||
|
||||
four2int(l->vtoc.v_magic) != UNIXWARE_DISKMAGIC2)
|
||||
return -1;
|
||||
|
||||
p = &l->vtoc.v_slice[1]; /* slice 0 is the whole disk. */
|
||||
while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) {
|
||||
if (p->s_label == UNIXWARE_FS_UNUSED)
|
||||
/* nothing */;
|
||||
else if (n < ns) {
|
||||
sp[n].start = p->start_sect;
|
||||
sp[n].size = p->nr_sects;
|
||||
n++;
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"unixware_partition: too many slices\n");
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
return n;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue