mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-07 00:38:05 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
269
block/partitions/Kconfig
Normal file
269
block/partitions/Kconfig
Normal file
|
@ -0,0 +1,269 @@
|
|||
#
|
||||
# Partition configuration
|
||||
#
|
||||
config PARTITION_ADVANCED
|
||||
bool "Advanced partition selection"
|
||||
help
|
||||
Say Y here if you would like to use hard disks under Linux which
|
||||
were partitioned under an operating system running on a different
|
||||
architecture than your Linux system.
|
||||
|
||||
Note that the answer to this question won't directly affect the
|
||||
kernel: saying N will just cause the configurator to skip all
|
||||
the questions about foreign partitioning schemes.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config ACORN_PARTITION
|
||||
bool "Acorn partition support" if PARTITION_ADVANCED
|
||||
default y if ARCH_ACORN
|
||||
help
|
||||
Support hard disks partitioned under Acorn operating systems.
|
||||
|
||||
config ACORN_PARTITION_CUMANA
|
||||
bool "Cumana partition support" if PARTITION_ADVANCED
|
||||
default y if ARCH_ACORN
|
||||
depends on ACORN_PARTITION
|
||||
help
|
||||
Say Y here if you would like to use hard disks under Linux which
|
||||
were partitioned using the Cumana interface on Acorn machines.
|
||||
|
||||
config ACORN_PARTITION_EESOX
|
||||
bool "EESOX partition support" if PARTITION_ADVANCED
|
||||
default y if ARCH_ACORN
|
||||
depends on ACORN_PARTITION
|
||||
|
||||
config ACORN_PARTITION_ICS
|
||||
bool "ICS partition support" if PARTITION_ADVANCED
|
||||
default y if ARCH_ACORN
|
||||
depends on ACORN_PARTITION
|
||||
help
|
||||
Say Y here if you would like to use hard disks under Linux which
|
||||
were partitioned using the ICS interface on Acorn machines.
|
||||
|
||||
config ACORN_PARTITION_ADFS
|
||||
bool "Native filecore partition support" if PARTITION_ADVANCED
|
||||
default y if ARCH_ACORN
|
||||
depends on ACORN_PARTITION
|
||||
help
|
||||
The Acorn Disc Filing System is the standard file system of the
|
||||
RiscOS operating system which runs on Acorn's ARM-based Risc PC
|
||||
systems and the Acorn Archimedes range of machines. If you say
|
||||
`Y' here, Linux will support disk partitions created under ADFS.
|
||||
|
||||
config ACORN_PARTITION_POWERTEC
|
||||
bool "PowerTec partition support" if PARTITION_ADVANCED
|
||||
default y if ARCH_ACORN
|
||||
depends on ACORN_PARTITION
|
||||
help
|
||||
Support reading partition tables created on Acorn machines using
|
||||
the PowerTec SCSI drive.
|
||||
|
||||
config ACORN_PARTITION_RISCIX
|
||||
bool "RISCiX partition support" if PARTITION_ADVANCED
|
||||
default y if ARCH_ACORN
|
||||
depends on ACORN_PARTITION
|
||||
help
|
||||
Once upon a time, there was a native Unix port for the Acorn series
|
||||
of machines called RISCiX. If you say 'Y' here, Linux will be able
|
||||
to read disks partitioned under RISCiX.
|
||||
|
||||
config AIX_PARTITION
|
||||
bool "AIX basic partition table support" if PARTITION_ADVANCED
|
||||
help
|
||||
Say Y here if you would like to be able to read the hard disk
|
||||
partition table format used by IBM or Motorola PowerPC machines
|
||||
running AIX. AIX actually uses a Logical Volume Manager, where
|
||||
"logical volumes" can be spread across one or multiple disks,
|
||||
but this driver works only for the simple case of partitions which
|
||||
are contiguous.
|
||||
Otherwise, say N.
|
||||
|
||||
config OSF_PARTITION
|
||||
bool "Alpha OSF partition support" if PARTITION_ADVANCED
|
||||
default y if ALPHA
|
||||
help
|
||||
Say Y here if you would like to use hard disks under Linux which
|
||||
were partitioned on an Alpha machine.
|
||||
|
||||
config AMIGA_PARTITION
|
||||
bool "Amiga partition table support" if PARTITION_ADVANCED
|
||||
default y if (AMIGA || AFFS_FS=y)
|
||||
help
|
||||
Say Y here if you would like to use hard disks under Linux which
|
||||
were partitioned under AmigaOS.
|
||||
|
||||
config ATARI_PARTITION
|
||||
bool "Atari partition table support" if PARTITION_ADVANCED
|
||||
default y if ATARI
|
||||
help
|
||||
Say Y here if you would like to use hard disks under Linux which
|
||||
were partitioned under the Atari OS.
|
||||
|
||||
config IBM_PARTITION
|
||||
bool "IBM disk label and partition support"
|
||||
depends on PARTITION_ADVANCED && S390
|
||||
help
|
||||
Say Y here if you would like to be able to read the hard disk
|
||||
partition table format used by IBM DASD disks operating under CMS.
|
||||
Otherwise, say N.
|
||||
|
||||
config MAC_PARTITION
|
||||
bool "Macintosh partition map support" if PARTITION_ADVANCED
|
||||
default y if (MAC || PPC_PMAC)
|
||||
help
|
||||
Say Y here if you would like to use hard disks under Linux which
|
||||
were partitioned on a Macintosh.
|
||||
|
||||
config MSDOS_PARTITION
|
||||
bool "PC BIOS (MSDOS partition tables) support" if PARTITION_ADVANCED
|
||||
default y
|
||||
help
|
||||
Say Y here.
|
||||
|
||||
config BSD_DISKLABEL
|
||||
bool "BSD disklabel (FreeBSD partition tables) support"
|
||||
depends on PARTITION_ADVANCED && MSDOS_PARTITION
|
||||
help
|
||||
FreeBSD uses its own hard disk partition scheme on your PC. It
|
||||
requires only one entry in the primary partition table of your disk
|
||||
and manages it similarly to DOS extended partitions, putting in its
|
||||
first sector a new partition table in BSD disklabel format. Saying Y
|
||||
here allows you to read these disklabels and further mount FreeBSD
|
||||
partitions from within Linux if you have also said Y to "UFS
|
||||
file system support", above. If you don't know what all this is
|
||||
about, say N.
|
||||
|
||||
config MINIX_SUBPARTITION
|
||||
bool "Minix subpartition support"
|
||||
depends on PARTITION_ADVANCED && MSDOS_PARTITION
|
||||
help
|
||||
Minix 2.0.0/2.0.2 subpartition table support for Linux.
|
||||
Say Y here if you want to mount and use Minix 2.0.0/2.0.2
|
||||
subpartitions.
|
||||
|
||||
config SOLARIS_X86_PARTITION
|
||||
bool "Solaris (x86) partition table support"
|
||||
depends on PARTITION_ADVANCED && MSDOS_PARTITION
|
||||
help
|
||||
Like most systems, Solaris x86 uses its own hard disk partition
|
||||
table format, incompatible with all others. Saying Y here allows you
|
||||
to read these partition tables and further mount Solaris x86
|
||||
partitions from within Linux if you have also said Y to "UFS
|
||||
file system support", above.
|
||||
|
||||
config UNIXWARE_DISKLABEL
|
||||
bool "Unixware slices support"
|
||||
depends on PARTITION_ADVANCED && MSDOS_PARTITION
|
||||
---help---
|
||||
Like some systems, UnixWare uses its own slice table inside a
|
||||
partition (VTOC - Virtual Table of Contents). Its format is
|
||||
incompatible with all other OSes. Saying Y here allows you to read
|
||||
VTOC and further mount UnixWare partitions read-only from within
|
||||
Linux if you have also said Y to "UFS file system support" or
|
||||
"System V and Coherent file system support", above.
|
||||
|
||||
This is mainly used to carry data from a UnixWare box to your
|
||||
Linux box via a removable medium like magneto-optical, ZIP or
|
||||
removable IDE drives. Note, however, that a good portable way to
|
||||
transport files and directories between unixes (and even other
|
||||
operating systems) is given by the tar program ("man tar" or
|
||||
preferably "info tar").
|
||||
|
||||
If you don't know what all this is about, say N.
|
||||
|
||||
config LDM_PARTITION
|
||||
bool "Windows Logical Disk Manager (Dynamic Disk) support"
|
||||
depends on PARTITION_ADVANCED
|
||||
---help---
|
||||
Say Y here if you would like to use hard disks under Linux which
|
||||
were partitioned using Windows 2000's/XP's or Vista's Logical Disk
|
||||
Manager. They are also known as "Dynamic Disks".
|
||||
|
||||
Note this driver only supports Dynamic Disks with a protective MBR
|
||||
label, i.e. DOS partition table. It does not support GPT labelled
|
||||
Dynamic Disks yet as can be created with Vista.
|
||||
|
||||
Windows 2000 introduced the concept of Dynamic Disks to get around
|
||||
the limitations of the PC's partitioning scheme. The Logical Disk
|
||||
Manager allows the user to repartition a disk and create spanned,
|
||||
mirrored, striped or RAID volumes, all without the need for
|
||||
rebooting.
|
||||
|
||||
Normal partitions are now called Basic Disks under Windows 2000, XP,
|
||||
and Vista.
|
||||
|
||||
For a fuller description read <file:Documentation/ldm.txt>.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config LDM_DEBUG
|
||||
bool "Windows LDM extra logging"
|
||||
depends on LDM_PARTITION
|
||||
help
|
||||
Say Y here if you would like LDM to log verbosely. This could be
|
||||
helpful if the driver doesn't work as expected and you'd like to
|
||||
report a bug.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config SGI_PARTITION
|
||||
bool "SGI partition support" if PARTITION_ADVANCED
|
||||
default y if DEFAULT_SGI_PARTITION
|
||||
help
|
||||
Say Y here if you would like to be able to read the hard disk
|
||||
partition table format used by SGI machines.
|
||||
|
||||
config ULTRIX_PARTITION
|
||||
bool "Ultrix partition table support" if PARTITION_ADVANCED
|
||||
default y if MACH_DECSTATION
|
||||
help
|
||||
Say Y here if you would like to be able to read the hard disk
|
||||
partition table format used by DEC (now Compaq) Ultrix machines.
|
||||
Otherwise, say N.
|
||||
|
||||
config SUN_PARTITION
|
||||
bool "Sun partition tables support" if PARTITION_ADVANCED
|
||||
default y if (SPARC || SUN3 || SUN3X)
|
||||
---help---
|
||||
Like most systems, SunOS uses its own hard disk partition table
|
||||
format, incompatible with all others. Saying Y here allows you to
|
||||
read these partition tables and further mount SunOS partitions from
|
||||
within Linux if you have also said Y to "UFS file system support",
|
||||
above. This is mainly used to carry data from a SPARC under SunOS to
|
||||
your Linux box via a removable medium like magneto-optical or ZIP
|
||||
drives; note however that a good portable way to transport files and
|
||||
directories between unixes (and even other operating systems) is
|
||||
given by the tar program ("man tar" or preferably "info tar"). If
|
||||
you don't know what all this is about, say N.
|
||||
|
||||
config KARMA_PARTITION
|
||||
bool "Karma Partition support"
|
||||
depends on PARTITION_ADVANCED
|
||||
help
|
||||
Say Y here if you would like to mount the Rio Karma MP3 player, as it
|
||||
uses a proprietary partition table.
|
||||
|
||||
config EFI_PARTITION
|
||||
bool "EFI GUID Partition support" if PARTITION_ADVANCED
|
||||
default y
|
||||
select CRC32
|
||||
help
|
||||
Say Y here if you would like to use hard disks under Linux which
|
||||
were partitioned using EFI GPT.
|
||||
|
||||
config SYSV68_PARTITION
|
||||
bool "SYSV68 partition table support" if PARTITION_ADVANCED
|
||||
default y if VME
|
||||
help
|
||||
Say Y here if you would like to be able to read the hard disk
|
||||
partition table format used by Motorola Delta machines (using
|
||||
sysv68).
|
||||
Otherwise, say N.
|
||||
|
||||
config CMDLINE_PARTITION
|
||||
bool "Command line partition support" if PARTITION_ADVANCED
|
||||
select BLK_CMDLINE_PARSER
|
||||
help
|
||||
Say Y here if you want to read the partition table from bootargs.
|
||||
The format for the command line is just like mtdparts.
|
22
block/partitions/Makefile
Normal file
22
block/partitions/Makefile
Normal file
|
@ -0,0 +1,22 @@
|
|||
#
|
||||
# Makefile for the linux kernel.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_BLOCK) := check.o
|
||||
|
||||
obj-$(CONFIG_ACORN_PARTITION) += acorn.o
|
||||
obj-$(CONFIG_AMIGA_PARTITION) += amiga.o
|
||||
obj-$(CONFIG_ATARI_PARTITION) += atari.o
|
||||
obj-$(CONFIG_AIX_PARTITION) += aix.o
|
||||
obj-$(CONFIG_CMDLINE_PARTITION) += cmdline.o
|
||||
obj-$(CONFIG_MAC_PARTITION) += mac.o
|
||||
obj-$(CONFIG_LDM_PARTITION) += ldm.o
|
||||
obj-$(CONFIG_MSDOS_PARTITION) += msdos.o
|
||||
obj-$(CONFIG_OSF_PARTITION) += osf.o
|
||||
obj-$(CONFIG_SGI_PARTITION) += sgi.o
|
||||
obj-$(CONFIG_SUN_PARTITION) += sun.o
|
||||
obj-$(CONFIG_ULTRIX_PARTITION) += ultrix.o
|
||||
obj-$(CONFIG_IBM_PARTITION) += ibm.o
|
||||
obj-$(CONFIG_EFI_PARTITION) += efi.o
|
||||
obj-$(CONFIG_KARMA_PARTITION) += karma.o
|
||||
obj-$(CONFIG_SYSV68_PARTITION) += sysv68.o
|
556
block/partitions/acorn.c
Normal file
556
block/partitions/acorn.c
Normal file
|
@ -0,0 +1,556 @@
|
|||
/*
|
||||
* linux/fs/partitions/acorn.c
|
||||
*
|
||||
* Copyright (c) 1996-2000 Russell King.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Scan ADFS partitions on hard disk drives. Unfortunately, there
|
||||
* isn't a standard for partitioning drives on Acorn machines, so
|
||||
* every single manufacturer of SCSI and IDE cards created their own
|
||||
* method.
|
||||
*/
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/adfs_fs.h>
|
||||
|
||||
#include "check.h"
|
||||
#include "acorn.h"
|
||||
|
||||
/*
|
||||
* Partition types. (Oh for reusability)
|
||||
*/
|
||||
#define PARTITION_RISCIX_MFM 1
|
||||
#define PARTITION_RISCIX_SCSI 2
|
||||
#define PARTITION_LINUX 9
|
||||
|
||||
#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \
|
||||
defined(CONFIG_ACORN_PARTITION_ADFS)
|
||||
static struct adfs_discrecord *
|
||||
adfs_partition(struct parsed_partitions *state, char *name, char *data,
|
||||
unsigned long first_sector, int slot)
|
||||
{
|
||||
struct adfs_discrecord *dr;
|
||||
unsigned int nr_sects;
|
||||
|
||||
if (adfs_checkbblk(data))
|
||||
return NULL;
|
||||
|
||||
dr = (struct adfs_discrecord *)(data + 0x1c0);
|
||||
|
||||
if (dr->disc_size == 0 && dr->disc_size_high == 0)
|
||||
return NULL;
|
||||
|
||||
nr_sects = (le32_to_cpu(dr->disc_size_high) << 23) |
|
||||
(le32_to_cpu(dr->disc_size) >> 9);
|
||||
|
||||
if (name) {
|
||||
strlcat(state->pp_buf, " [", PAGE_SIZE);
|
||||
strlcat(state->pp_buf, name, PAGE_SIZE);
|
||||
strlcat(state->pp_buf, "]", PAGE_SIZE);
|
||||
}
|
||||
put_partition(state, slot, first_sector, nr_sects);
|
||||
return dr;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACORN_PARTITION_RISCIX
|
||||
|
||||
struct riscix_part {
|
||||
__le32 start;
|
||||
__le32 length;
|
||||
__le32 one;
|
||||
char name[16];
|
||||
};
|
||||
|
||||
struct riscix_record {
|
||||
__le32 magic;
|
||||
#define RISCIX_MAGIC cpu_to_le32(0x4a657320)
|
||||
__le32 date;
|
||||
struct riscix_part part[8];
|
||||
};
|
||||
|
||||
#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \
|
||||
defined(CONFIG_ACORN_PARTITION_ADFS)
|
||||
static int riscix_partition(struct parsed_partitions *state,
|
||||
unsigned long first_sect, int slot,
|
||||
unsigned long nr_sects)
|
||||
{
|
||||
Sector sect;
|
||||
struct riscix_record *rr;
|
||||
|
||||
rr = read_part_sector(state, first_sect, §);
|
||||
if (!rr)
|
||||
return -1;
|
||||
|
||||
strlcat(state->pp_buf, " [RISCiX]", PAGE_SIZE);
|
||||
|
||||
|
||||
if (rr->magic == RISCIX_MAGIC) {
|
||||
unsigned long size = nr_sects > 2 ? 2 : nr_sects;
|
||||
int part;
|
||||
|
||||
strlcat(state->pp_buf, " <", PAGE_SIZE);
|
||||
|
||||
put_partition(state, slot++, first_sect, size);
|
||||
for (part = 0; part < 8; part++) {
|
||||
if (rr->part[part].one &&
|
||||
memcmp(rr->part[part].name, "All\0", 4)) {
|
||||
put_partition(state, slot++,
|
||||
le32_to_cpu(rr->part[part].start),
|
||||
le32_to_cpu(rr->part[part].length));
|
||||
strlcat(state->pp_buf, "(", PAGE_SIZE);
|
||||
strlcat(state->pp_buf, rr->part[part].name, PAGE_SIZE);
|
||||
strlcat(state->pp_buf, ")", PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
strlcat(state->pp_buf, " >\n", PAGE_SIZE);
|
||||
} else {
|
||||
put_partition(state, slot++, first_sect, nr_sects);
|
||||
}
|
||||
|
||||
put_dev_sector(sect);
|
||||
return slot;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define LINUX_NATIVE_MAGIC 0xdeafa1de
|
||||
#define LINUX_SWAP_MAGIC 0xdeafab1e
|
||||
|
||||
struct linux_part {
|
||||
__le32 magic;
|
||||
__le32 start_sect;
|
||||
__le32 nr_sects;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \
|
||||
defined(CONFIG_ACORN_PARTITION_ADFS)
|
||||
static int linux_partition(struct parsed_partitions *state,
|
||||
unsigned long first_sect, int slot,
|
||||
unsigned long nr_sects)
|
||||
{
|
||||
Sector sect;
|
||||
struct linux_part *linuxp;
|
||||
unsigned long size = nr_sects > 2 ? 2 : nr_sects;
|
||||
|
||||
strlcat(state->pp_buf, " [Linux]", PAGE_SIZE);
|
||||
|
||||
put_partition(state, slot++, first_sect, size);
|
||||
|
||||
linuxp = read_part_sector(state, first_sect, §);
|
||||
if (!linuxp)
|
||||
return -1;
|
||||
|
||||
strlcat(state->pp_buf, " <", PAGE_SIZE);
|
||||
while (linuxp->magic == cpu_to_le32(LINUX_NATIVE_MAGIC) ||
|
||||
linuxp->magic == cpu_to_le32(LINUX_SWAP_MAGIC)) {
|
||||
if (slot == state->limit)
|
||||
break;
|
||||
put_partition(state, slot++, first_sect +
|
||||
le32_to_cpu(linuxp->start_sect),
|
||||
le32_to_cpu(linuxp->nr_sects));
|
||||
linuxp ++;
|
||||
}
|
||||
strlcat(state->pp_buf, " >", PAGE_SIZE);
|
||||
|
||||
put_dev_sector(sect);
|
||||
return slot;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACORN_PARTITION_CUMANA
|
||||
int adfspart_check_CUMANA(struct parsed_partitions *state)
|
||||
{
|
||||
unsigned long first_sector = 0;
|
||||
unsigned int start_blk = 0;
|
||||
Sector sect;
|
||||
unsigned char *data;
|
||||
char *name = "CUMANA/ADFS";
|
||||
int first = 1;
|
||||
int slot = 1;
|
||||
|
||||
/*
|
||||
* Try Cumana style partitions - sector 6 contains ADFS boot block
|
||||
* with pointer to next 'drive'.
|
||||
*
|
||||
* There are unknowns in this code - is the 'cylinder number' of the
|
||||
* next partition relative to the start of this one - I'm assuming
|
||||
* it is.
|
||||
*
|
||||
* Also, which ID did Cumana use?
|
||||
*
|
||||
* This is totally unfinished, and will require more work to get it
|
||||
* going. Hence it is totally untested.
|
||||
*/
|
||||
do {
|
||||
struct adfs_discrecord *dr;
|
||||
unsigned int nr_sects;
|
||||
|
||||
data = read_part_sector(state, start_blk * 2 + 6, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
if (slot == state->limit)
|
||||
break;
|
||||
|
||||
dr = adfs_partition(state, name, data, first_sector, slot++);
|
||||
if (!dr)
|
||||
break;
|
||||
|
||||
name = NULL;
|
||||
|
||||
nr_sects = (data[0x1fd] + (data[0x1fe] << 8)) *
|
||||
(dr->heads + (dr->lowsector & 0x40 ? 1 : 0)) *
|
||||
dr->secspertrack;
|
||||
|
||||
if (!nr_sects)
|
||||
break;
|
||||
|
||||
first = 0;
|
||||
first_sector += nr_sects;
|
||||
start_blk += nr_sects >> (BLOCK_SIZE_BITS - 9);
|
||||
nr_sects = 0; /* hmm - should be partition size */
|
||||
|
||||
switch (data[0x1fc] & 15) {
|
||||
case 0: /* No partition / ADFS? */
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_ACORN_PARTITION_RISCIX
|
||||
case PARTITION_RISCIX_SCSI:
|
||||
/* RISCiX - we don't know how to find the next one. */
|
||||
slot = riscix_partition(state, first_sector, slot,
|
||||
nr_sects);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case PARTITION_LINUX:
|
||||
slot = linux_partition(state, first_sector, slot,
|
||||
nr_sects);
|
||||
break;
|
||||
}
|
||||
put_dev_sector(sect);
|
||||
if (slot == -1)
|
||||
return -1;
|
||||
} while (1);
|
||||
put_dev_sector(sect);
|
||||
return first ? 0 : 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACORN_PARTITION_ADFS
|
||||
/*
|
||||
* Purpose: allocate ADFS partitions.
|
||||
*
|
||||
* Params : hd - pointer to gendisk structure to store partition info.
|
||||
* dev - device number to access.
|
||||
*
|
||||
* Returns: -1 on error, 0 for no ADFS boot sector, 1 for ok.
|
||||
*
|
||||
* Alloc : hda = whole drive
|
||||
* hda1 = ADFS partition on first drive.
|
||||
* hda2 = non-ADFS partition.
|
||||
*/
|
||||
int adfspart_check_ADFS(struct parsed_partitions *state)
|
||||
{
|
||||
unsigned long start_sect, nr_sects, sectscyl, heads;
|
||||
Sector sect;
|
||||
unsigned char *data;
|
||||
struct adfs_discrecord *dr;
|
||||
unsigned char id;
|
||||
int slot = 1;
|
||||
|
||||
data = read_part_sector(state, 6, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
dr = adfs_partition(state, "ADFS", data, 0, slot++);
|
||||
if (!dr) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
|
||||
heads = dr->heads + ((dr->lowsector >> 6) & 1);
|
||||
sectscyl = dr->secspertrack * heads;
|
||||
start_sect = ((data[0x1fe] << 8) + data[0x1fd]) * sectscyl;
|
||||
id = data[0x1fc] & 15;
|
||||
put_dev_sector(sect);
|
||||
|
||||
/*
|
||||
* Work out start of non-adfs partition.
|
||||
*/
|
||||
nr_sects = (state->bdev->bd_inode->i_size >> 9) - start_sect;
|
||||
|
||||
if (start_sect) {
|
||||
switch (id) {
|
||||
#ifdef CONFIG_ACORN_PARTITION_RISCIX
|
||||
case PARTITION_RISCIX_SCSI:
|
||||
case PARTITION_RISCIX_MFM:
|
||||
slot = riscix_partition(state, start_sect, slot,
|
||||
nr_sects);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case PARTITION_LINUX:
|
||||
slot = linux_partition(state, start_sect, slot,
|
||||
nr_sects);
|
||||
break;
|
||||
}
|
||||
}
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACORN_PARTITION_ICS
|
||||
|
||||
struct ics_part {
|
||||
__le32 start;
|
||||
__le32 size;
|
||||
};
|
||||
|
||||
static int adfspart_check_ICSLinux(struct parsed_partitions *state,
|
||||
unsigned long block)
|
||||
{
|
||||
Sector sect;
|
||||
unsigned char *data = read_part_sector(state, block, §);
|
||||
int result = 0;
|
||||
|
||||
if (data) {
|
||||
if (memcmp(data, "LinuxPart", 9) == 0)
|
||||
result = 1;
|
||||
put_dev_sector(sect);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for a valid ICS partition using the checksum.
|
||||
*/
|
||||
static inline int valid_ics_sector(const unsigned char *data)
|
||||
{
|
||||
unsigned long sum;
|
||||
int i;
|
||||
|
||||
for (i = 0, sum = 0x50617274; i < 508; i++)
|
||||
sum += data[i];
|
||||
|
||||
sum -= le32_to_cpu(*(__le32 *)(&data[508]));
|
||||
|
||||
return sum == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Purpose: allocate ICS partitions.
|
||||
* Params : hd - pointer to gendisk structure to store partition info.
|
||||
* dev - device number to access.
|
||||
* Returns: -1 on error, 0 for no ICS table, 1 for partitions ok.
|
||||
* Alloc : hda = whole drive
|
||||
* hda1 = ADFS partition 0 on first drive.
|
||||
* hda2 = ADFS partition 1 on first drive.
|
||||
* ..etc..
|
||||
*/
|
||||
int adfspart_check_ICS(struct parsed_partitions *state)
|
||||
{
|
||||
const unsigned char *data;
|
||||
const struct ics_part *p;
|
||||
int slot;
|
||||
Sector sect;
|
||||
|
||||
/*
|
||||
* Try ICS style partitions - sector 0 contains partition info.
|
||||
*/
|
||||
data = read_part_sector(state, 0, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
if (!valid_ics_sector(data)) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
|
||||
strlcat(state->pp_buf, " [ICS]", PAGE_SIZE);
|
||||
|
||||
for (slot = 1, p = (const struct ics_part *)data; p->size; p++) {
|
||||
u32 start = le32_to_cpu(p->start);
|
||||
s32 size = le32_to_cpu(p->size); /* yes, it's signed. */
|
||||
|
||||
if (slot == state->limit)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Negative sizes tell the RISC OS ICS driver to ignore
|
||||
* this partition - in effect it says that this does not
|
||||
* contain an ADFS filesystem.
|
||||
*/
|
||||
if (size < 0) {
|
||||
size = -size;
|
||||
|
||||
/*
|
||||
* Our own extension - We use the first sector
|
||||
* of the partition to identify what type this
|
||||
* partition is. We must not make this visible
|
||||
* to the filesystem.
|
||||
*/
|
||||
if (size > 1 && adfspart_check_ICSLinux(state, start)) {
|
||||
start += 1;
|
||||
size -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (size)
|
||||
put_partition(state, slot++, start, size);
|
||||
}
|
||||
|
||||
put_dev_sector(sect);
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACORN_PARTITION_POWERTEC
|
||||
struct ptec_part {
|
||||
__le32 unused1;
|
||||
__le32 unused2;
|
||||
__le32 start;
|
||||
__le32 size;
|
||||
__le32 unused5;
|
||||
char type[8];
|
||||
};
|
||||
|
||||
static inline int valid_ptec_sector(const unsigned char *data)
|
||||
{
|
||||
unsigned char checksum = 0x2a;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* If it looks like a PC/BIOS partition, then it
|
||||
* probably isn't PowerTec.
|
||||
*/
|
||||
if (data[510] == 0x55 && data[511] == 0xaa)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < 511; i++)
|
||||
checksum += data[i];
|
||||
|
||||
return checksum == data[511];
|
||||
}
|
||||
|
||||
/*
|
||||
* Purpose: allocate ICS partitions.
|
||||
* Params : hd - pointer to gendisk structure to store partition info.
|
||||
* dev - device number to access.
|
||||
* Returns: -1 on error, 0 for no ICS table, 1 for partitions ok.
|
||||
* Alloc : hda = whole drive
|
||||
* hda1 = ADFS partition 0 on first drive.
|
||||
* hda2 = ADFS partition 1 on first drive.
|
||||
* ..etc..
|
||||
*/
|
||||
int adfspart_check_POWERTEC(struct parsed_partitions *state)
|
||||
{
|
||||
Sector sect;
|
||||
const unsigned char *data;
|
||||
const struct ptec_part *p;
|
||||
int slot = 1;
|
||||
int i;
|
||||
|
||||
data = read_part_sector(state, 0, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
if (!valid_ptec_sector(data)) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
|
||||
strlcat(state->pp_buf, " [POWERTEC]", PAGE_SIZE);
|
||||
|
||||
for (i = 0, p = (const struct ptec_part *)data; i < 12; i++, p++) {
|
||||
u32 start = le32_to_cpu(p->start);
|
||||
u32 size = le32_to_cpu(p->size);
|
||||
|
||||
if (size)
|
||||
put_partition(state, slot++, start, size);
|
||||
}
|
||||
|
||||
put_dev_sector(sect);
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACORN_PARTITION_EESOX
|
||||
struct eesox_part {
|
||||
char magic[6];
|
||||
char name[10];
|
||||
__le32 start;
|
||||
__le32 unused6;
|
||||
__le32 unused7;
|
||||
__le32 unused8;
|
||||
};
|
||||
|
||||
/*
|
||||
* Guess who created this format?
|
||||
*/
|
||||
static const char eesox_name[] = {
|
||||
'N', 'e', 'i', 'l', ' ',
|
||||
'C', 'r', 'i', 't', 'c', 'h', 'e', 'l', 'l', ' ', ' '
|
||||
};
|
||||
|
||||
/*
|
||||
* EESOX SCSI partition format.
|
||||
*
|
||||
* This is a goddamned awful partition format. We don't seem to store
|
||||
* the size of the partition in this table, only the start addresses.
|
||||
*
|
||||
* There are two possibilities where the size comes from:
|
||||
* 1. The individual ADFS boot block entries that are placed on the disk.
|
||||
* 2. The start address of the next entry.
|
||||
*/
|
||||
int adfspart_check_EESOX(struct parsed_partitions *state)
|
||||
{
|
||||
Sector sect;
|
||||
const unsigned char *data;
|
||||
unsigned char buffer[256];
|
||||
struct eesox_part *p;
|
||||
sector_t start = 0;
|
||||
int i, slot = 1;
|
||||
|
||||
data = read_part_sector(state, 7, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* "Decrypt" the partition table. God knows why...
|
||||
*/
|
||||
for (i = 0; i < 256; i++)
|
||||
buffer[i] = data[i] ^ eesox_name[i & 15];
|
||||
|
||||
put_dev_sector(sect);
|
||||
|
||||
for (i = 0, p = (struct eesox_part *)buffer; i < 8; i++, p++) {
|
||||
sector_t next;
|
||||
|
||||
if (memcmp(p->magic, "Eesox", 6))
|
||||
break;
|
||||
|
||||
next = le32_to_cpu(p->start);
|
||||
if (i)
|
||||
put_partition(state, slot++, start, next - start);
|
||||
start = next;
|
||||
}
|
||||
|
||||
if (i != 0) {
|
||||
sector_t size;
|
||||
|
||||
size = get_capacity(state->bdev->bd_disk);
|
||||
put_partition(state, slot++, start, size - start);
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
}
|
||||
|
||||
return i ? 1 : 0;
|
||||
}
|
||||
#endif
|
14
block/partitions/acorn.h
Normal file
14
block/partitions/acorn.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* linux/fs/partitions/acorn.h
|
||||
*
|
||||
* Copyright (C) 1996-2001 Russell King.
|
||||
*
|
||||
* I _hate_ this partitioning mess - why can't we have one defined
|
||||
* format, and everyone stick to it?
|
||||
*/
|
||||
|
||||
int adfspart_check_CUMANA(struct parsed_partitions *state);
|
||||
int adfspart_check_ADFS(struct parsed_partitions *state);
|
||||
int adfspart_check_ICS(struct parsed_partitions *state);
|
||||
int adfspart_check_POWERTEC(struct parsed_partitions *state);
|
||||
int adfspart_check_EESOX(struct parsed_partitions *state);
|
293
block/partitions/aix.c
Normal file
293
block/partitions/aix.c
Normal file
|
@ -0,0 +1,293 @@
|
|||
/*
|
||||
* fs/partitions/aix.c
|
||||
*
|
||||
* Copyright (C) 2012-2013 Philippe De Muyter <phdm@macqel.be>
|
||||
*/
|
||||
|
||||
#include "check.h"
|
||||
#include "aix.h"
|
||||
|
||||
struct lvm_rec {
|
||||
char lvm_id[4]; /* "_LVM" */
|
||||
char reserved4[16];
|
||||
__be32 lvmarea_len;
|
||||
__be32 vgda_len;
|
||||
__be32 vgda_psn[2];
|
||||
char reserved36[10];
|
||||
__be16 pp_size; /* log2(pp_size) */
|
||||
char reserved46[12];
|
||||
__be16 version;
|
||||
};
|
||||
|
||||
struct vgda {
|
||||
__be32 secs;
|
||||
__be32 usec;
|
||||
char reserved8[16];
|
||||
__be16 numlvs;
|
||||
__be16 maxlvs;
|
||||
__be16 pp_size;
|
||||
__be16 numpvs;
|
||||
__be16 total_vgdas;
|
||||
__be16 vgda_size;
|
||||
};
|
||||
|
||||
struct lvd {
|
||||
__be16 lv_ix;
|
||||
__be16 res2;
|
||||
__be16 res4;
|
||||
__be16 maxsize;
|
||||
__be16 lv_state;
|
||||
__be16 mirror;
|
||||
__be16 mirror_policy;
|
||||
__be16 num_lps;
|
||||
__be16 res10[8];
|
||||
};
|
||||
|
||||
struct lvname {
|
||||
char name[64];
|
||||
};
|
||||
|
||||
struct ppe {
|
||||
__be16 lv_ix;
|
||||
unsigned short res2;
|
||||
unsigned short res4;
|
||||
__be16 lp_ix;
|
||||
unsigned short res8[12];
|
||||
};
|
||||
|
||||
struct pvd {
|
||||
char reserved0[16];
|
||||
__be16 pp_count;
|
||||
char reserved18[2];
|
||||
__be32 psn_part1;
|
||||
char reserved24[8];
|
||||
struct ppe ppe[1016];
|
||||
};
|
||||
|
||||
#define LVM_MAXLVS 256
|
||||
|
||||
/**
|
||||
* last_lba(): return number of last logical block of device
|
||||
* @bdev: block device
|
||||
*
|
||||
* Description: Returns last LBA value on success, 0 on error.
|
||||
* This is stored (by sd and ide-geometry) in
|
||||
* the part[0] entry for this disk, and is the number of
|
||||
* physical sectors available on the disk.
|
||||
*/
|
||||
static u64 last_lba(struct block_device *bdev)
|
||||
{
|
||||
if (!bdev || !bdev->bd_inode)
|
||||
return 0;
|
||||
return (bdev->bd_inode->i_size >> 9) - 1ULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* read_lba(): Read bytes from disk, starting at given LBA
|
||||
* @state
|
||||
* @lba
|
||||
* @buffer
|
||||
* @count
|
||||
*
|
||||
* Description: Reads @count bytes from @state->bdev into @buffer.
|
||||
* Returns number of bytes read on success, 0 on error.
|
||||
*/
|
||||
static size_t read_lba(struct parsed_partitions *state, u64 lba, u8 *buffer,
|
||||
size_t count)
|
||||
{
|
||||
size_t totalreadcount = 0;
|
||||
|
||||
if (!buffer || lba + count / 512 > last_lba(state->bdev))
|
||||
return 0;
|
||||
|
||||
while (count) {
|
||||
int copied = 512;
|
||||
Sector sect;
|
||||
unsigned char *data = read_part_sector(state, lba++, §);
|
||||
if (!data)
|
||||
break;
|
||||
if (copied > count)
|
||||
copied = count;
|
||||
memcpy(buffer, data, copied);
|
||||
put_dev_sector(sect);
|
||||
buffer += copied;
|
||||
totalreadcount += copied;
|
||||
count -= copied;
|
||||
}
|
||||
return totalreadcount;
|
||||
}
|
||||
|
||||
/**
|
||||
* alloc_pvd(): reads physical volume descriptor
|
||||
* @state
|
||||
* @lba
|
||||
*
|
||||
* Description: Returns pvd on success, NULL on error.
|
||||
* Allocates space for pvd and fill it with disk blocks at @lba
|
||||
* Notes: remember to free pvd when you're done!
|
||||
*/
|
||||
static struct pvd *alloc_pvd(struct parsed_partitions *state, u32 lba)
|
||||
{
|
||||
size_t count = sizeof(struct pvd);
|
||||
struct pvd *p;
|
||||
|
||||
p = kmalloc(count, GFP_KERNEL);
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
if (read_lba(state, lba, (u8 *) p, count) < count) {
|
||||
kfree(p);
|
||||
return NULL;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* alloc_lvn(): reads logical volume names
|
||||
* @state
|
||||
* @lba
|
||||
*
|
||||
* Description: Returns lvn on success, NULL on error.
|
||||
* Allocates space for lvn and fill it with disk blocks at @lba
|
||||
* Notes: remember to free lvn when you're done!
|
||||
*/
|
||||
static struct lvname *alloc_lvn(struct parsed_partitions *state, u32 lba)
|
||||
{
|
||||
size_t count = sizeof(struct lvname) * LVM_MAXLVS;
|
||||
struct lvname *p;
|
||||
|
||||
p = kmalloc(count, GFP_KERNEL);
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
if (read_lba(state, lba, (u8 *) p, count) < count) {
|
||||
kfree(p);
|
||||
return NULL;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
int aix_partition(struct parsed_partitions *state)
|
||||
{
|
||||
int ret = 0;
|
||||
Sector sect;
|
||||
unsigned char *d;
|
||||
u32 pp_bytes_size;
|
||||
u32 pp_blocks_size = 0;
|
||||
u32 vgda_sector = 0;
|
||||
u32 vgda_len = 0;
|
||||
int numlvs = 0;
|
||||
struct pvd *pvd;
|
||||
struct lv_info {
|
||||
unsigned short pps_per_lv;
|
||||
unsigned short pps_found;
|
||||
unsigned char lv_is_contiguous;
|
||||
} *lvip;
|
||||
struct lvname *n = NULL;
|
||||
|
||||
d = read_part_sector(state, 7, §);
|
||||
if (d) {
|
||||
struct lvm_rec *p = (struct lvm_rec *)d;
|
||||
u16 lvm_version = be16_to_cpu(p->version);
|
||||
char tmp[64];
|
||||
|
||||
if (lvm_version == 1) {
|
||||
int pp_size_log2 = be16_to_cpu(p->pp_size);
|
||||
|
||||
pp_bytes_size = 1 << pp_size_log2;
|
||||
pp_blocks_size = pp_bytes_size / 512;
|
||||
snprintf(tmp, sizeof(tmp),
|
||||
" AIX LVM header version %u found\n",
|
||||
lvm_version);
|
||||
vgda_len = be32_to_cpu(p->vgda_len);
|
||||
vgda_sector = be32_to_cpu(p->vgda_psn[0]);
|
||||
} else {
|
||||
snprintf(tmp, sizeof(tmp),
|
||||
" unsupported AIX LVM version %d found\n",
|
||||
lvm_version);
|
||||
}
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
put_dev_sector(sect);
|
||||
}
|
||||
if (vgda_sector && (d = read_part_sector(state, vgda_sector, §))) {
|
||||
struct vgda *p = (struct vgda *)d;
|
||||
|
||||
numlvs = be16_to_cpu(p->numlvs);
|
||||
put_dev_sector(sect);
|
||||
}
|
||||
lvip = kcalloc(state->limit, sizeof(struct lv_info), GFP_KERNEL);
|
||||
if (!lvip)
|
||||
return 0;
|
||||
if (numlvs && (d = read_part_sector(state, vgda_sector + 1, §))) {
|
||||
struct lvd *p = (struct lvd *)d;
|
||||
int i;
|
||||
|
||||
n = alloc_lvn(state, vgda_sector + vgda_len - 33);
|
||||
if (n) {
|
||||
int foundlvs = 0;
|
||||
|
||||
for (i = 0; foundlvs < numlvs && i < state->limit; i += 1) {
|
||||
lvip[i].pps_per_lv = be16_to_cpu(p[i].num_lps);
|
||||
if (lvip[i].pps_per_lv)
|
||||
foundlvs += 1;
|
||||
}
|
||||
}
|
||||
put_dev_sector(sect);
|
||||
}
|
||||
pvd = alloc_pvd(state, vgda_sector + 17);
|
||||
if (pvd) {
|
||||
int numpps = be16_to_cpu(pvd->pp_count);
|
||||
int psn_part1 = be32_to_cpu(pvd->psn_part1);
|
||||
int i;
|
||||
int cur_lv_ix = -1;
|
||||
int next_lp_ix = 1;
|
||||
int lp_ix;
|
||||
|
||||
for (i = 0; i < numpps; i += 1) {
|
||||
struct ppe *p = pvd->ppe + i;
|
||||
unsigned int lv_ix;
|
||||
|
||||
lp_ix = be16_to_cpu(p->lp_ix);
|
||||
if (!lp_ix) {
|
||||
next_lp_ix = 1;
|
||||
continue;
|
||||
}
|
||||
lv_ix = be16_to_cpu(p->lv_ix) - 1;
|
||||
if (lv_ix >= state->limit) {
|
||||
cur_lv_ix = -1;
|
||||
continue;
|
||||
}
|
||||
lvip[lv_ix].pps_found += 1;
|
||||
if (lp_ix == 1) {
|
||||
cur_lv_ix = lv_ix;
|
||||
next_lp_ix = 1;
|
||||
} else if (lv_ix != cur_lv_ix || lp_ix != next_lp_ix) {
|
||||
next_lp_ix = 1;
|
||||
continue;
|
||||
}
|
||||
if (lp_ix == lvip[lv_ix].pps_per_lv) {
|
||||
char tmp[70];
|
||||
|
||||
put_partition(state, lv_ix + 1,
|
||||
(i + 1 - lp_ix) * pp_blocks_size + psn_part1,
|
||||
lvip[lv_ix].pps_per_lv * pp_blocks_size);
|
||||
snprintf(tmp, sizeof(tmp), " <%s>\n",
|
||||
n[lv_ix].name);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
lvip[lv_ix].lv_is_contiguous = 1;
|
||||
ret = 1;
|
||||
next_lp_ix = 1;
|
||||
} else
|
||||
next_lp_ix += 1;
|
||||
}
|
||||
for (i = 0; i < state->limit; i += 1)
|
||||
if (lvip[i].pps_found && !lvip[i].lv_is_contiguous)
|
||||
pr_warn("partition %s (%u pp's found) is "
|
||||
"not contiguous\n",
|
||||
n[i].name, lvip[i].pps_found);
|
||||
kfree(pvd);
|
||||
}
|
||||
kfree(n);
|
||||
kfree(lvip);
|
||||
return ret;
|
||||
}
|
1
block/partitions/aix.h
Normal file
1
block/partitions/aix.h
Normal file
|
@ -0,0 +1 @@
|
|||
extern int aix_partition(struct parsed_partitions *state);
|
141
block/partitions/amiga.c
Normal file
141
block/partitions/amiga.c
Normal file
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* fs/partitions/amiga.c
|
||||
*
|
||||
* Code extracted from drivers/block/genhd.c
|
||||
*
|
||||
* Copyright (C) 1991-1998 Linus Torvalds
|
||||
* Re-organised Feb 1998 Russell King
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) fmt
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/affs_hardblocks.h>
|
||||
|
||||
#include "check.h"
|
||||
#include "amiga.h"
|
||||
|
||||
static __inline__ u32
|
||||
checksum_block(__be32 *m, int size)
|
||||
{
|
||||
u32 sum = 0;
|
||||
|
||||
while (size--)
|
||||
sum += be32_to_cpu(*m++);
|
||||
return sum;
|
||||
}
|
||||
|
||||
int amiga_partition(struct parsed_partitions *state)
|
||||
{
|
||||
Sector sect;
|
||||
unsigned char *data;
|
||||
struct RigidDiskBlock *rdb;
|
||||
struct PartitionBlock *pb;
|
||||
int start_sect, nr_sects, blk, part, res = 0;
|
||||
int blksize = 1; /* Multiplier for disk block size */
|
||||
int slot = 1;
|
||||
char b[BDEVNAME_SIZE];
|
||||
|
||||
for (blk = 0; ; blk++, put_dev_sector(sect)) {
|
||||
if (blk == RDB_ALLOCATION_LIMIT)
|
||||
goto rdb_done;
|
||||
data = read_part_sector(state, blk, §);
|
||||
if (!data) {
|
||||
if (warn_no_part)
|
||||
pr_err("Dev %s: unable to read RDB block %d\n",
|
||||
bdevname(state->bdev, b), blk);
|
||||
res = -1;
|
||||
goto rdb_done;
|
||||
}
|
||||
if (*(__be32 *)data != cpu_to_be32(IDNAME_RIGIDDISK))
|
||||
continue;
|
||||
|
||||
rdb = (struct RigidDiskBlock *)data;
|
||||
if (checksum_block((__be32 *)data, be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F) == 0)
|
||||
break;
|
||||
/* Try again with 0xdc..0xdf zeroed, Windows might have
|
||||
* trashed it.
|
||||
*/
|
||||
*(__be32 *)(data+0xdc) = 0;
|
||||
if (checksum_block((__be32 *)data,
|
||||
be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F)==0) {
|
||||
pr_err("Trashed word at 0xd0 in block %d ignored in checksum calculation\n",
|
||||
blk);
|
||||
break;
|
||||
}
|
||||
|
||||
pr_err("Dev %s: RDB in block %d has bad checksum\n",
|
||||
bdevname(state->bdev, b), blk);
|
||||
}
|
||||
|
||||
/* blksize is blocks per 512 byte standard block */
|
||||
blksize = be32_to_cpu( rdb->rdb_BlockBytes ) / 512;
|
||||
|
||||
{
|
||||
char tmp[7 + 10 + 1 + 1];
|
||||
|
||||
/* Be more informative */
|
||||
snprintf(tmp, sizeof(tmp), " RDSK (%d)", blksize * 512);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
}
|
||||
blk = be32_to_cpu(rdb->rdb_PartitionList);
|
||||
put_dev_sector(sect);
|
||||
for (part = 1; blk>0 && part<=16; part++, put_dev_sector(sect)) {
|
||||
blk *= blksize; /* Read in terms partition table understands */
|
||||
data = read_part_sector(state, blk, §);
|
||||
if (!data) {
|
||||
if (warn_no_part)
|
||||
pr_err("Dev %s: unable to read partition block %d\n",
|
||||
bdevname(state->bdev, b), blk);
|
||||
res = -1;
|
||||
goto rdb_done;
|
||||
}
|
||||
pb = (struct PartitionBlock *)data;
|
||||
blk = be32_to_cpu(pb->pb_Next);
|
||||
if (pb->pb_ID != cpu_to_be32(IDNAME_PARTITION))
|
||||
continue;
|
||||
if (checksum_block((__be32 *)pb, be32_to_cpu(pb->pb_SummedLongs) & 0x7F) != 0 )
|
||||
continue;
|
||||
|
||||
/* Tell Kernel about it */
|
||||
|
||||
nr_sects = (be32_to_cpu(pb->pb_Environment[10]) + 1 -
|
||||
be32_to_cpu(pb->pb_Environment[9])) *
|
||||
be32_to_cpu(pb->pb_Environment[3]) *
|
||||
be32_to_cpu(pb->pb_Environment[5]) *
|
||||
blksize;
|
||||
if (!nr_sects)
|
||||
continue;
|
||||
start_sect = be32_to_cpu(pb->pb_Environment[9]) *
|
||||
be32_to_cpu(pb->pb_Environment[3]) *
|
||||
be32_to_cpu(pb->pb_Environment[5]) *
|
||||
blksize;
|
||||
put_partition(state,slot++,start_sect,nr_sects);
|
||||
{
|
||||
/* Be even more informative to aid mounting */
|
||||
char dostype[4];
|
||||
char tmp[42];
|
||||
|
||||
__be32 *dt = (__be32 *)dostype;
|
||||
*dt = pb->pb_Environment[16];
|
||||
if (dostype[3] < ' ')
|
||||
snprintf(tmp, sizeof(tmp), " (%c%c%c^%c)",
|
||||
dostype[0], dostype[1],
|
||||
dostype[2], dostype[3] + '@' );
|
||||
else
|
||||
snprintf(tmp, sizeof(tmp), " (%c%c%c%c)",
|
||||
dostype[0], dostype[1],
|
||||
dostype[2], dostype[3]);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
snprintf(tmp, sizeof(tmp), "(res %d spb %d)",
|
||||
be32_to_cpu(pb->pb_Environment[6]),
|
||||
be32_to_cpu(pb->pb_Environment[4]));
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
}
|
||||
res = 1;
|
||||
}
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
|
||||
rdb_done:
|
||||
return res;
|
||||
}
|
6
block/partitions/amiga.h
Normal file
6
block/partitions/amiga.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
/*
|
||||
* fs/partitions/amiga.h
|
||||
*/
|
||||
|
||||
int amiga_partition(struct parsed_partitions *state);
|
||||
|
149
block/partitions/atari.c
Normal file
149
block/partitions/atari.c
Normal file
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* fs/partitions/atari.c
|
||||
*
|
||||
* Code extracted from drivers/block/genhd.c
|
||||
*
|
||||
* Copyright (C) 1991-1998 Linus Torvalds
|
||||
* Re-organised Feb 1998 Russell King
|
||||
*/
|
||||
|
||||
#include <linux/ctype.h>
|
||||
#include "check.h"
|
||||
#include "atari.h"
|
||||
|
||||
/* ++guenther: this should be settable by the user ("make config")?.
|
||||
*/
|
||||
#define ICD_PARTS
|
||||
|
||||
/* check if a partition entry looks valid -- Atari format is assumed if at
|
||||
least one of the primary entries is ok this way */
|
||||
#define VALID_PARTITION(pi,hdsiz) \
|
||||
(((pi)->flg & 1) && \
|
||||
isalnum((pi)->id[0]) && isalnum((pi)->id[1]) && isalnum((pi)->id[2]) && \
|
||||
be32_to_cpu((pi)->st) <= (hdsiz) && \
|
||||
be32_to_cpu((pi)->st) + be32_to_cpu((pi)->siz) <= (hdsiz))
|
||||
|
||||
static inline int OK_id(char *s)
|
||||
{
|
||||
return memcmp (s, "GEM", 3) == 0 || memcmp (s, "BGM", 3) == 0 ||
|
||||
memcmp (s, "LNX", 3) == 0 || memcmp (s, "SWP", 3) == 0 ||
|
||||
memcmp (s, "RAW", 3) == 0 ;
|
||||
}
|
||||
|
||||
int atari_partition(struct parsed_partitions *state)
|
||||
{
|
||||
Sector sect;
|
||||
struct rootsector *rs;
|
||||
struct partition_info *pi;
|
||||
u32 extensect;
|
||||
u32 hd_size;
|
||||
int slot;
|
||||
#ifdef ICD_PARTS
|
||||
int part_fmt = 0; /* 0:unknown, 1:AHDI, 2:ICD/Supra */
|
||||
#endif
|
||||
|
||||
rs = read_part_sector(state, 0, §);
|
||||
if (!rs)
|
||||
return -1;
|
||||
|
||||
/* Verify this is an Atari rootsector: */
|
||||
hd_size = state->bdev->bd_inode->i_size >> 9;
|
||||
if (!VALID_PARTITION(&rs->part[0], hd_size) &&
|
||||
!VALID_PARTITION(&rs->part[1], hd_size) &&
|
||||
!VALID_PARTITION(&rs->part[2], hd_size) &&
|
||||
!VALID_PARTITION(&rs->part[3], hd_size)) {
|
||||
/*
|
||||
* if there's no valid primary partition, assume that no Atari
|
||||
* format partition table (there's no reliable magic or the like
|
||||
* :-()
|
||||
*/
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pi = &rs->part[0];
|
||||
strlcat(state->pp_buf, " AHDI", PAGE_SIZE);
|
||||
for (slot = 1; pi < &rs->part[4] && slot < state->limit; slot++, pi++) {
|
||||
struct rootsector *xrs;
|
||||
Sector sect2;
|
||||
ulong partsect;
|
||||
|
||||
if ( !(pi->flg & 1) )
|
||||
continue;
|
||||
/* active partition */
|
||||
if (memcmp (pi->id, "XGM", 3) != 0) {
|
||||
/* we don't care about other id's */
|
||||
put_partition (state, slot, be32_to_cpu(pi->st),
|
||||
be32_to_cpu(pi->siz));
|
||||
continue;
|
||||
}
|
||||
/* extension partition */
|
||||
#ifdef ICD_PARTS
|
||||
part_fmt = 1;
|
||||
#endif
|
||||
strlcat(state->pp_buf, " XGM<", PAGE_SIZE);
|
||||
partsect = extensect = be32_to_cpu(pi->st);
|
||||
while (1) {
|
||||
xrs = read_part_sector(state, partsect, §2);
|
||||
if (!xrs) {
|
||||
printk (" block %ld read failed\n", partsect);
|
||||
put_dev_sector(sect);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ++roman: sanity check: bit 0 of flg field must be set */
|
||||
if (!(xrs->part[0].flg & 1)) {
|
||||
printk( "\nFirst sub-partition in extended partition is not valid!\n" );
|
||||
put_dev_sector(sect2);
|
||||
break;
|
||||
}
|
||||
|
||||
put_partition(state, slot,
|
||||
partsect + be32_to_cpu(xrs->part[0].st),
|
||||
be32_to_cpu(xrs->part[0].siz));
|
||||
|
||||
if (!(xrs->part[1].flg & 1)) {
|
||||
/* end of linked partition list */
|
||||
put_dev_sector(sect2);
|
||||
break;
|
||||
}
|
||||
if (memcmp( xrs->part[1].id, "XGM", 3 ) != 0) {
|
||||
printk("\nID of extended partition is not XGM!\n");
|
||||
put_dev_sector(sect2);
|
||||
break;
|
||||
}
|
||||
|
||||
partsect = be32_to_cpu(xrs->part[1].st) + extensect;
|
||||
put_dev_sector(sect2);
|
||||
if (++slot == state->limit) {
|
||||
printk( "\nMaximum number of partitions reached!\n" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
strlcat(state->pp_buf, " >", PAGE_SIZE);
|
||||
}
|
||||
#ifdef ICD_PARTS
|
||||
if ( part_fmt!=1 ) { /* no extended partitions -> test ICD-format */
|
||||
pi = &rs->icdpart[0];
|
||||
/* sanity check: no ICD format if first partition invalid */
|
||||
if (OK_id(pi->id)) {
|
||||
strlcat(state->pp_buf, " ICD<", PAGE_SIZE);
|
||||
for (; pi < &rs->icdpart[8] && slot < state->limit; slot++, pi++) {
|
||||
/* accept only GEM,BGM,RAW,LNX,SWP partitions */
|
||||
if (!((pi->flg & 1) && OK_id(pi->id)))
|
||||
continue;
|
||||
part_fmt = 2;
|
||||
put_partition (state, slot,
|
||||
be32_to_cpu(pi->st),
|
||||
be32_to_cpu(pi->siz));
|
||||
}
|
||||
strlcat(state->pp_buf, " >", PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
put_dev_sector(sect);
|
||||
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
|
||||
return 1;
|
||||
}
|
36
block/partitions/atari.h
Normal file
36
block/partitions/atari.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* fs/partitions/atari.h
|
||||
* Moved by Russell King from:
|
||||
*
|
||||
* linux/include/linux/atari_rootsec.h
|
||||
* definitions for Atari Rootsector layout
|
||||
* by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de)
|
||||
*
|
||||
* modified for ICD/Supra partitioning scheme restricted to at most 12
|
||||
* partitions
|
||||
* by Guenther Kelleter (guenther@pool.informatik.rwth-aachen.de)
|
||||
*/
|
||||
|
||||
#include <linux/compiler.h>
|
||||
|
||||
struct partition_info
|
||||
{
|
||||
u8 flg; /* bit 0: active; bit 7: bootable */
|
||||
char id[3]; /* "GEM", "BGM", "XGM", or other */
|
||||
__be32 st; /* start of partition */
|
||||
__be32 siz; /* length of partition */
|
||||
};
|
||||
|
||||
struct rootsector
|
||||
{
|
||||
char unused[0x156]; /* room for boot code */
|
||||
struct partition_info icdpart[8]; /* info for ICD-partitions 5..12 */
|
||||
char unused2[0xc];
|
||||
u32 hd_siz; /* size of disk in blocks */
|
||||
struct partition_info part[4];
|
||||
u32 bsl_st; /* start of bad sector list */
|
||||
u32 bsl_cnt; /* length of bad sector list */
|
||||
u16 checksum; /* checksum for bootable disks */
|
||||
} __packed;
|
||||
|
||||
int atari_partition(struct parsed_partitions *state);
|
197
block/partitions/check.c
Normal file
197
block/partitions/check.c
Normal file
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* fs/partitions/check.c
|
||||
*
|
||||
* Code extracted from drivers/block/genhd.c
|
||||
* Copyright (C) 1991-1998 Linus Torvalds
|
||||
* Re-organised Feb 1998 Russell King
|
||||
*
|
||||
* We now have independent partition support from the
|
||||
* block drivers, which allows all the partition code to
|
||||
* be grouped in one location, and it to be mostly self
|
||||
* contained.
|
||||
*
|
||||
* Added needed MAJORS for new pairs, {hdi,hdj}, {hdk,hdl}
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/genhd.h>
|
||||
|
||||
#include "check.h"
|
||||
|
||||
#include "acorn.h"
|
||||
#include "amiga.h"
|
||||
#include "atari.h"
|
||||
#include "ldm.h"
|
||||
#include "mac.h"
|
||||
#include "msdos.h"
|
||||
#include "osf.h"
|
||||
#include "sgi.h"
|
||||
#include "sun.h"
|
||||
#include "ibm.h"
|
||||
#include "ultrix.h"
|
||||
#include "efi.h"
|
||||
#include "karma.h"
|
||||
#include "sysv68.h"
|
||||
#include "cmdline.h"
|
||||
|
||||
int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/
|
||||
|
||||
static int (*check_part[])(struct parsed_partitions *) = {
|
||||
/*
|
||||
* Probe partition formats with tables at disk address 0
|
||||
* that also have an ADFS boot block at 0xdc0.
|
||||
*/
|
||||
#ifdef CONFIG_ACORN_PARTITION_ICS
|
||||
adfspart_check_ICS,
|
||||
#endif
|
||||
#ifdef CONFIG_ACORN_PARTITION_POWERTEC
|
||||
adfspart_check_POWERTEC,
|
||||
#endif
|
||||
#ifdef CONFIG_ACORN_PARTITION_EESOX
|
||||
adfspart_check_EESOX,
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Now move on to formats that only have partition info at
|
||||
* disk address 0xdc0. Since these may also have stale
|
||||
* PC/BIOS partition tables, they need to come before
|
||||
* the msdos entry.
|
||||
*/
|
||||
#ifdef CONFIG_ACORN_PARTITION_CUMANA
|
||||
adfspart_check_CUMANA,
|
||||
#endif
|
||||
#ifdef CONFIG_ACORN_PARTITION_ADFS
|
||||
adfspart_check_ADFS,
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CMDLINE_PARTITION
|
||||
cmdline_partition,
|
||||
#endif
|
||||
#ifdef CONFIG_EFI_PARTITION
|
||||
efi_partition, /* this must come before msdos */
|
||||
#endif
|
||||
#ifdef CONFIG_SGI_PARTITION
|
||||
sgi_partition,
|
||||
#endif
|
||||
#ifdef CONFIG_LDM_PARTITION
|
||||
ldm_partition, /* this must come before msdos */
|
||||
#endif
|
||||
#ifdef CONFIG_MSDOS_PARTITION
|
||||
msdos_partition,
|
||||
#endif
|
||||
#ifdef CONFIG_OSF_PARTITION
|
||||
osf_partition,
|
||||
#endif
|
||||
#ifdef CONFIG_SUN_PARTITION
|
||||
sun_partition,
|
||||
#endif
|
||||
#ifdef CONFIG_AMIGA_PARTITION
|
||||
amiga_partition,
|
||||
#endif
|
||||
#ifdef CONFIG_ATARI_PARTITION
|
||||
atari_partition,
|
||||
#endif
|
||||
#ifdef CONFIG_MAC_PARTITION
|
||||
mac_partition,
|
||||
#endif
|
||||
#ifdef CONFIG_ULTRIX_PARTITION
|
||||
ultrix_partition,
|
||||
#endif
|
||||
#ifdef CONFIG_IBM_PARTITION
|
||||
ibm_partition,
|
||||
#endif
|
||||
#ifdef CONFIG_KARMA_PARTITION
|
||||
karma_partition,
|
||||
#endif
|
||||
#ifdef CONFIG_SYSV68_PARTITION
|
||||
sysv68_partition,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct parsed_partitions *allocate_partitions(struct gendisk *hd)
|
||||
{
|
||||
struct parsed_partitions *state;
|
||||
int nr;
|
||||
|
||||
state = kzalloc(sizeof(*state), GFP_KERNEL);
|
||||
if (!state)
|
||||
return NULL;
|
||||
|
||||
nr = disk_max_parts(hd);
|
||||
state->parts = vzalloc(nr * sizeof(state->parts[0]));
|
||||
if (!state->parts) {
|
||||
kfree(state);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
state->limit = nr;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
void free_partitions(struct parsed_partitions *state)
|
||||
{
|
||||
vfree(state->parts);
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
struct parsed_partitions *
|
||||
check_partition(struct gendisk *hd, struct block_device *bdev)
|
||||
{
|
||||
struct parsed_partitions *state;
|
||||
int i, res, err;
|
||||
|
||||
state = allocate_partitions(hd);
|
||||
if (!state)
|
||||
return NULL;
|
||||
state->pp_buf = (char *)__get_free_page(GFP_KERNEL);
|
||||
if (!state->pp_buf) {
|
||||
free_partitions(state);
|
||||
return NULL;
|
||||
}
|
||||
state->pp_buf[0] = '\0';
|
||||
|
||||
state->bdev = bdev;
|
||||
disk_name(hd, 0, state->name);
|
||||
snprintf(state->pp_buf, PAGE_SIZE, " %s:", state->name);
|
||||
if (isdigit(state->name[strlen(state->name)-1]))
|
||||
sprintf(state->name, "p");
|
||||
|
||||
i = res = err = 0;
|
||||
while (!res && check_part[i]) {
|
||||
memset(state->parts, 0, state->limit * sizeof(state->parts[0]));
|
||||
res = check_part[i++](state);
|
||||
if (res < 0) {
|
||||
/* We have hit an I/O error which we don't report now.
|
||||
* But record it, and let the others do their job.
|
||||
*/
|
||||
err = res;
|
||||
res = 0;
|
||||
}
|
||||
|
||||
}
|
||||
if (res > 0) {
|
||||
printk(KERN_INFO "%s", state->pp_buf);
|
||||
|
||||
free_page((unsigned long)state->pp_buf);
|
||||
return state;
|
||||
}
|
||||
if (state->access_beyond_eod)
|
||||
err = -ENOSPC;
|
||||
if (err)
|
||||
/* The partition is unrecognized. So report I/O errors if there were any */
|
||||
res = err;
|
||||
if (!res)
|
||||
strlcat(state->pp_buf, " unknown partition table\n", PAGE_SIZE);
|
||||
else if (warn_no_part)
|
||||
strlcat(state->pp_buf, " unable to read partition table\n", PAGE_SIZE);
|
||||
|
||||
printk(KERN_INFO "%s", state->pp_buf);
|
||||
|
||||
free_page((unsigned long)state->pp_buf);
|
||||
free_partitions(state);
|
||||
return ERR_PTR(res);
|
||||
}
|
54
block/partitions/check.h
Normal file
54
block/partitions/check.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
#include <linux/pagemap.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/genhd.h>
|
||||
|
||||
/*
|
||||
* add_gd_partition adds a partitions details to the devices partition
|
||||
* description.
|
||||
*/
|
||||
struct parsed_partitions {
|
||||
struct block_device *bdev;
|
||||
char name[BDEVNAME_SIZE];
|
||||
struct {
|
||||
sector_t from;
|
||||
sector_t size;
|
||||
int flags;
|
||||
bool has_info;
|
||||
struct partition_meta_info info;
|
||||
} *parts;
|
||||
int next;
|
||||
int limit;
|
||||
bool access_beyond_eod;
|
||||
char *pp_buf;
|
||||
};
|
||||
|
||||
void free_partitions(struct parsed_partitions *state);
|
||||
|
||||
struct parsed_partitions *
|
||||
check_partition(struct gendisk *, struct block_device *);
|
||||
|
||||
static inline void *read_part_sector(struct parsed_partitions *state,
|
||||
sector_t n, Sector *p)
|
||||
{
|
||||
if (n >= get_capacity(state->bdev->bd_disk)) {
|
||||
state->access_beyond_eod = true;
|
||||
return NULL;
|
||||
}
|
||||
return read_dev_sector(state->bdev, n, p);
|
||||
}
|
||||
|
||||
static inline void
|
||||
put_partition(struct parsed_partitions *p, int n, sector_t from, sector_t size)
|
||||
{
|
||||
if (n < p->limit) {
|
||||
char tmp[1 + BDEVNAME_SIZE + 10 + 1];
|
||||
|
||||
p->parts[n].from = from;
|
||||
p->parts[n].size = size;
|
||||
snprintf(tmp, sizeof(tmp), " %s%d", p->name, n);
|
||||
strlcat(p->pp_buf, tmp, PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
extern int warn_no_part;
|
||||
|
99
block/partitions/cmdline.c
Normal file
99
block/partitions/cmdline.c
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright (C) 2013 HUAWEI
|
||||
* Author: Cai Zhiyong <caizhiyong@huawei.com>
|
||||
*
|
||||
* Read block device partition table from the command line.
|
||||
* Typically used for fixed block (eMMC) embedded devices.
|
||||
* It has no MBR, so saves storage space. Bootloader can be easily accessed
|
||||
* by absolute address of data on the block device.
|
||||
* Users can easily change the partition.
|
||||
*
|
||||
* The format for the command line is just like mtdparts.
|
||||
*
|
||||
* For further information, see "Documentation/block/cmdline-partition.txt"
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/cmdline-parser.h>
|
||||
|
||||
#include "check.h"
|
||||
#include "cmdline.h"
|
||||
|
||||
static char *cmdline;
|
||||
static struct cmdline_parts *bdev_parts;
|
||||
|
||||
static int add_part(int slot, struct cmdline_subpart *subpart, void *param)
|
||||
{
|
||||
int label_min;
|
||||
struct partition_meta_info *info;
|
||||
char tmp[sizeof(info->volname) + 4];
|
||||
struct parsed_partitions *state = (struct parsed_partitions *)param;
|
||||
|
||||
if (slot >= state->limit)
|
||||
return 1;
|
||||
|
||||
put_partition(state, slot, subpart->from >> 9,
|
||||
subpart->size >> 9);
|
||||
|
||||
info = &state->parts[slot].info;
|
||||
|
||||
label_min = min_t(int, sizeof(info->volname) - 1,
|
||||
sizeof(subpart->name));
|
||||
strncpy(info->volname, subpart->name, label_min);
|
||||
info->volname[label_min] = '\0';
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "(%s)", info->volname);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
|
||||
state->parts[slot].has_info = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init cmdline_parts_setup(char *s)
|
||||
{
|
||||
cmdline = s;
|
||||
return 1;
|
||||
}
|
||||
__setup("blkdevparts=", cmdline_parts_setup);
|
||||
|
||||
/*
|
||||
* Purpose: allocate cmdline partitions.
|
||||
* Returns:
|
||||
* -1 if unable to read the partition table
|
||||
* 0 if this isn't our partition table
|
||||
* 1 if successful
|
||||
*/
|
||||
int cmdline_partition(struct parsed_partitions *state)
|
||||
{
|
||||
sector_t disk_size;
|
||||
char bdev[BDEVNAME_SIZE];
|
||||
struct cmdline_parts *parts;
|
||||
|
||||
if (cmdline) {
|
||||
if (bdev_parts)
|
||||
cmdline_parts_free(&bdev_parts);
|
||||
|
||||
if (cmdline_parts_parse(&bdev_parts, cmdline)) {
|
||||
cmdline = NULL;
|
||||
return -1;
|
||||
}
|
||||
cmdline = NULL;
|
||||
}
|
||||
|
||||
if (!bdev_parts)
|
||||
return 0;
|
||||
|
||||
bdevname(state->bdev, bdev);
|
||||
parts = cmdline_parts_find(bdev_parts, bdev);
|
||||
if (!parts)
|
||||
return 0;
|
||||
|
||||
disk_size = get_capacity(state->bdev->bd_disk) << 9;
|
||||
|
||||
cmdline_parts_set(parts, disk_size, 1, add_part, (void *)state);
|
||||
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
|
||||
return 1;
|
||||
}
|
2
block/partitions/cmdline.h
Normal file
2
block/partitions/cmdline.h
Normal file
|
@ -0,0 +1,2 @@
|
|||
|
||||
int cmdline_partition(struct parsed_partitions *state);
|
737
block/partitions/efi.c
Normal file
737
block/partitions/efi.c
Normal file
|
@ -0,0 +1,737 @@
|
|||
/************************************************************
|
||||
* EFI GUID Partition Table handling
|
||||
*
|
||||
* http://www.uefi.org/specs/
|
||||
* http://www.intel.com/technology/efi/
|
||||
*
|
||||
* efi.[ch] by Matt Domsch <Matt_Domsch@dell.com>
|
||||
* Copyright 2000,2001,2002,2004 Dell Inc.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*
|
||||
* TODO:
|
||||
*
|
||||
* Changelog:
|
||||
* Mon August 5th, 2013 Davidlohr Bueso <davidlohr@hp.com>
|
||||
* - detect hybrid MBRs, tighter pMBR checking & cleanups.
|
||||
*
|
||||
* Mon Nov 09 2004 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* - test for valid PMBR and valid PGPT before ever reading
|
||||
* AGPT, allow override with 'gpt' kernel command line option.
|
||||
* - check for first/last_usable_lba outside of size of disk
|
||||
*
|
||||
* Tue Mar 26 2002 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* - Ported to 2.5.7-pre1 and 2.5.7-dj2
|
||||
* - Applied patch to avoid fault in alternate header handling
|
||||
* - cleaned up find_valid_gpt
|
||||
* - On-disk structure and copy in memory is *always* LE now -
|
||||
* swab fields as needed
|
||||
* - remove print_gpt_header()
|
||||
* - only use first max_p partition entries, to keep the kernel minor number
|
||||
* and partition numbers tied.
|
||||
*
|
||||
* Mon Feb 04 2002 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* - Removed __PRIPTR_PREFIX - not being used
|
||||
*
|
||||
* Mon Jan 14 2002 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* - Ported to 2.5.2-pre11 + library crc32 patch Linus applied
|
||||
*
|
||||
* Thu Dec 6 2001 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* - Added compare_gpts().
|
||||
* - moved le_efi_guid_to_cpus() back into this file. GPT is the only
|
||||
* thing that keeps EFI GUIDs on disk.
|
||||
* - Changed gpt structure names and members to be simpler and more Linux-like.
|
||||
*
|
||||
* Wed Oct 17 2001 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* - Removed CONFIG_DEVFS_VOLUMES_UUID code entirely per Martin Wilck
|
||||
*
|
||||
* Wed Oct 10 2001 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* - Changed function comments to DocBook style per Andreas Dilger suggestion.
|
||||
*
|
||||
* Mon Oct 08 2001 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* - Change read_lba() to use the page cache per Al Viro's work.
|
||||
* - print u64s properly on all architectures
|
||||
* - fixed debug_printk(), now Dprintk()
|
||||
*
|
||||
* Mon Oct 01 2001 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* - Style cleanups
|
||||
* - made most functions static
|
||||
* - Endianness addition
|
||||
* - remove test for second alternate header, as it's not per spec,
|
||||
* and is unnecessary. There's now a method to read/write the last
|
||||
* sector of an odd-sized disk from user space. No tools have ever
|
||||
* been released which used this code, so it's effectively dead.
|
||||
* - Per Asit Mallick of Intel, added a test for a valid PMBR.
|
||||
* - Added kernel command line option 'gpt' to override valid PMBR test.
|
||||
*
|
||||
* Wed Jun 6 2001 Martin Wilck <Martin.Wilck@Fujitsu-Siemens.com>
|
||||
* - added devfs volume UUID support (/dev/volumes/uuids) for
|
||||
* mounting file systems by the partition GUID.
|
||||
*
|
||||
* Tue Dec 5 2000 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* - Moved crc32() to linux/lib, added efi_crc32().
|
||||
*
|
||||
* Thu Nov 30 2000 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* - Replaced Intel's CRC32 function with an equivalent
|
||||
* non-license-restricted version.
|
||||
*
|
||||
* Wed Oct 25 2000 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* - Fixed the last_lba() call to return the proper last block
|
||||
*
|
||||
* Thu Oct 12 2000 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* - Thanks to Andries Brouwer for his debugging assistance.
|
||||
* - Code works, detects all the partitions.
|
||||
*
|
||||
************************************************************/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/slab.h>
|
||||
#include "check.h"
|
||||
#include "efi.h"
|
||||
|
||||
/* This allows a kernel command line option 'gpt' to override
|
||||
* the test for invalid PMBR. Not __initdata because reloading
|
||||
* the partition tables happens after init too.
|
||||
*/
|
||||
static int force_gpt;
|
||||
static int __init
|
||||
force_gpt_fn(char *str)
|
||||
{
|
||||
force_gpt = 1;
|
||||
return 1;
|
||||
}
|
||||
__setup("gpt", force_gpt_fn);
|
||||
|
||||
|
||||
/**
|
||||
* efi_crc32() - EFI version of crc32 function
|
||||
* @buf: buffer to calculate crc32 of
|
||||
* @len: length of buf
|
||||
*
|
||||
* Description: Returns EFI-style CRC32 value for @buf
|
||||
*
|
||||
* This function uses the little endian Ethernet polynomial
|
||||
* but seeds the function with ~0, and xor's with ~0 at the end.
|
||||
* Note, the EFI Specification, v1.02, has a reference to
|
||||
* Dr. Dobbs Journal, May 1994 (actually it's in May 1992).
|
||||
*/
|
||||
static inline u32
|
||||
efi_crc32(const void *buf, unsigned long len)
|
||||
{
|
||||
return (crc32(~0L, buf, len) ^ ~0L);
|
||||
}
|
||||
|
||||
/**
|
||||
* last_lba(): return number of last logical block of device
|
||||
* @bdev: block device
|
||||
*
|
||||
* Description: Returns last LBA value on success, 0 on error.
|
||||
* This is stored (by sd and ide-geometry) in
|
||||
* the part[0] entry for this disk, and is the number of
|
||||
* physical sectors available on the disk.
|
||||
*/
|
||||
static u64 last_lba(struct block_device *bdev)
|
||||
{
|
||||
if (!bdev || !bdev->bd_inode)
|
||||
return 0;
|
||||
return div_u64(bdev->bd_inode->i_size,
|
||||
bdev_logical_block_size(bdev)) - 1ULL;
|
||||
}
|
||||
|
||||
static inline int pmbr_part_valid(gpt_mbr_record *part)
|
||||
{
|
||||
if (part->os_type != EFI_PMBR_OSTYPE_EFI_GPT)
|
||||
goto invalid;
|
||||
|
||||
/* set to 0x00000001 (i.e., the LBA of the GPT Partition Header) */
|
||||
if (le32_to_cpu(part->starting_lba) != GPT_PRIMARY_PARTITION_TABLE_LBA)
|
||||
goto invalid;
|
||||
|
||||
return GPT_MBR_PROTECTIVE;
|
||||
invalid:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* is_pmbr_valid(): test Protective MBR for validity
|
||||
* @mbr: pointer to a legacy mbr structure
|
||||
* @total_sectors: amount of sectors in the device
|
||||
*
|
||||
* Description: Checks for a valid protective or hybrid
|
||||
* master boot record (MBR). The validity of a pMBR depends
|
||||
* on all of the following properties:
|
||||
* 1) MSDOS signature is in the last two bytes of the MBR
|
||||
* 2) One partition of type 0xEE is found
|
||||
*
|
||||
* In addition, a hybrid MBR will have up to three additional
|
||||
* primary partitions, which point to the same space that's
|
||||
* marked out by up to three GPT partitions.
|
||||
*
|
||||
* Returns 0 upon invalid MBR, or GPT_MBR_PROTECTIVE or
|
||||
* GPT_MBR_HYBRID depending on the device layout.
|
||||
*/
|
||||
static int is_pmbr_valid(legacy_mbr *mbr, sector_t total_sectors)
|
||||
{
|
||||
uint32_t sz = 0;
|
||||
int i, part = 0, ret = 0; /* invalid by default */
|
||||
|
||||
if (!mbr || le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE)
|
||||
goto done;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
ret = pmbr_part_valid(&mbr->partition_record[i]);
|
||||
if (ret == GPT_MBR_PROTECTIVE) {
|
||||
part = i;
|
||||
/*
|
||||
* Ok, we at least know that there's a protective MBR,
|
||||
* now check if there are other partition types for
|
||||
* hybrid MBR.
|
||||
*/
|
||||
goto check_hybrid;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret != GPT_MBR_PROTECTIVE)
|
||||
goto done;
|
||||
check_hybrid:
|
||||
for (i = 0; i < 4; i++)
|
||||
if ((mbr->partition_record[i].os_type !=
|
||||
EFI_PMBR_OSTYPE_EFI_GPT) &&
|
||||
(mbr->partition_record[i].os_type != 0x00))
|
||||
ret = GPT_MBR_HYBRID;
|
||||
|
||||
/*
|
||||
* Protective MBRs take up the lesser of the whole disk
|
||||
* or 2 TiB (32bit LBA), ignoring the rest of the disk.
|
||||
* Some partitioning programs, nonetheless, choose to set
|
||||
* the size to the maximum 32-bit limitation, disregarding
|
||||
* the disk size.
|
||||
*
|
||||
* Hybrid MBRs do not necessarily comply with this.
|
||||
*
|
||||
* Consider a bad value here to be a warning to support dd'ing
|
||||
* an image from a smaller disk to a larger disk.
|
||||
*/
|
||||
if (ret == GPT_MBR_PROTECTIVE) {
|
||||
sz = le32_to_cpu(mbr->partition_record[part].size_in_lba);
|
||||
if (sz != (uint32_t) total_sectors - 1 && sz != 0xFFFFFFFF)
|
||||
pr_debug("GPT: mbr size in lba (%u) different than whole disk (%u).\n",
|
||||
sz, min_t(uint32_t,
|
||||
total_sectors - 1, 0xFFFFFFFF));
|
||||
}
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* read_lba(): Read bytes from disk, starting at given LBA
|
||||
* @state: disk parsed partitions
|
||||
* @lba: the Logical Block Address of the partition table
|
||||
* @buffer: destination buffer
|
||||
* @count: bytes to read
|
||||
*
|
||||
* Description: Reads @count bytes from @state->bdev into @buffer.
|
||||
* Returns number of bytes read on success, 0 on error.
|
||||
*/
|
||||
static size_t read_lba(struct parsed_partitions *state,
|
||||
u64 lba, u8 *buffer, size_t count)
|
||||
{
|
||||
size_t totalreadcount = 0;
|
||||
struct block_device *bdev = state->bdev;
|
||||
sector_t n = lba * (bdev_logical_block_size(bdev) / 512);
|
||||
|
||||
if (!buffer || lba > last_lba(bdev))
|
||||
return 0;
|
||||
|
||||
while (count) {
|
||||
int copied = 512;
|
||||
Sector sect;
|
||||
unsigned char *data = read_part_sector(state, n++, §);
|
||||
if (!data)
|
||||
break;
|
||||
if (copied > count)
|
||||
copied = count;
|
||||
memcpy(buffer, data, copied);
|
||||
put_dev_sector(sect);
|
||||
buffer += copied;
|
||||
totalreadcount +=copied;
|
||||
count -= copied;
|
||||
}
|
||||
return totalreadcount;
|
||||
}
|
||||
|
||||
/**
|
||||
* alloc_read_gpt_entries(): reads partition entries from disk
|
||||
* @state: disk parsed partitions
|
||||
* @gpt: GPT header
|
||||
*
|
||||
* 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(struct parsed_partitions *state,
|
||||
gpt_header *gpt)
|
||||
{
|
||||
size_t count;
|
||||
gpt_entry *pte;
|
||||
|
||||
if (!gpt)
|
||||
return NULL;
|
||||
|
||||
count = le32_to_cpu(gpt->num_partition_entries) *
|
||||
le32_to_cpu(gpt->sizeof_partition_entry);
|
||||
if (!count)
|
||||
return NULL;
|
||||
pte = kmalloc(count, GFP_KERNEL);
|
||||
if (!pte)
|
||||
return NULL;
|
||||
|
||||
if (read_lba(state, le64_to_cpu(gpt->partition_entry_lba),
|
||||
(u8 *) pte, count) < count) {
|
||||
kfree(pte);
|
||||
pte=NULL;
|
||||
return NULL;
|
||||
}
|
||||
return pte;
|
||||
}
|
||||
|
||||
/**
|
||||
* alloc_read_gpt_header(): Allocates GPT header, reads into it from disk
|
||||
* @state: disk parsed partitions
|
||||
* @lba: 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 @state->bdev.
|
||||
* Note: remember to free gpt when finished with it.
|
||||
*/
|
||||
static gpt_header *alloc_read_gpt_header(struct parsed_partitions *state,
|
||||
u64 lba)
|
||||
{
|
||||
gpt_header *gpt;
|
||||
unsigned ssz = bdev_logical_block_size(state->bdev);
|
||||
|
||||
gpt = kmalloc(ssz, GFP_KERNEL);
|
||||
if (!gpt)
|
||||
return NULL;
|
||||
|
||||
if (read_lba(state, lba, (u8 *) gpt, ssz) < ssz) {
|
||||
kfree(gpt);
|
||||
gpt=NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return gpt;
|
||||
}
|
||||
|
||||
/**
|
||||
* is_gpt_valid() - tests one GPT header and PTEs for validity
|
||||
* @state: disk parsed partitions
|
||||
* @lba: logical block address of the GPT header to test
|
||||
* @gpt: GPT header ptr, filled on return.
|
||||
* @ptes: 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(struct parsed_partitions *state, u64 lba,
|
||||
gpt_header **gpt, gpt_entry **ptes)
|
||||
{
|
||||
u32 crc, origcrc;
|
||||
u64 lastlba;
|
||||
|
||||
if (!ptes)
|
||||
return 0;
|
||||
if (!(*gpt = alloc_read_gpt_header(state, lba)))
|
||||
return 0;
|
||||
|
||||
/* Check the GUID Partition Table signature */
|
||||
if (le64_to_cpu((*gpt)->signature) != GPT_HEADER_SIGNATURE) {
|
||||
pr_debug("GUID Partition Table Header signature is wrong:"
|
||||
"%lld != %lld\n",
|
||||
(unsigned long long)le64_to_cpu((*gpt)->signature),
|
||||
(unsigned long long)GPT_HEADER_SIGNATURE);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Check the GUID Partition Table header size is too big */
|
||||
if (le32_to_cpu((*gpt)->header_size) >
|
||||
bdev_logical_block_size(state->bdev)) {
|
||||
pr_debug("GUID Partition Table Header size is too large: %u > %u\n",
|
||||
le32_to_cpu((*gpt)->header_size),
|
||||
bdev_logical_block_size(state->bdev));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Check the GUID Partition Table header size is too small */
|
||||
if (le32_to_cpu((*gpt)->header_size) < sizeof(gpt_header)) {
|
||||
pr_debug("GUID Partition Table Header size is too small: %u < %zu\n",
|
||||
le32_to_cpu((*gpt)->header_size),
|
||||
sizeof(gpt_header));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Check the GUID Partition Table CRC */
|
||||
origcrc = le32_to_cpu((*gpt)->header_crc32);
|
||||
(*gpt)->header_crc32 = 0;
|
||||
crc = efi_crc32((const unsigned char *) (*gpt), le32_to_cpu((*gpt)->header_size));
|
||||
|
||||
if (crc != origcrc) {
|
||||
pr_debug("GUID Partition Table Header CRC is wrong: %x != %x\n",
|
||||
crc, origcrc);
|
||||
goto fail;
|
||||
}
|
||||
(*gpt)->header_crc32 = cpu_to_le32(origcrc);
|
||||
|
||||
/* Check that the my_lba entry points to the LBA that contains
|
||||
* the GUID Partition Table */
|
||||
if (le64_to_cpu((*gpt)->my_lba) != lba) {
|
||||
pr_debug("GPT my_lba incorrect: %lld != %lld\n",
|
||||
(unsigned long long)le64_to_cpu((*gpt)->my_lba),
|
||||
(unsigned long long)lba);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Check the first_usable_lba and last_usable_lba are
|
||||
* within the disk.
|
||||
*/
|
||||
lastlba = last_lba(state->bdev);
|
||||
if (le64_to_cpu((*gpt)->first_usable_lba) > lastlba) {
|
||||
pr_debug("GPT: first_usable_lba incorrect: %lld > %lld\n",
|
||||
(unsigned long long)le64_to_cpu((*gpt)->first_usable_lba),
|
||||
(unsigned long long)lastlba);
|
||||
goto fail;
|
||||
}
|
||||
if (le64_to_cpu((*gpt)->last_usable_lba) > lastlba) {
|
||||
pr_debug("GPT: last_usable_lba incorrect: %lld > %lld\n",
|
||||
(unsigned long long)le64_to_cpu((*gpt)->last_usable_lba),
|
||||
(unsigned long long)lastlba);
|
||||
goto fail;
|
||||
}
|
||||
if (le64_to_cpu((*gpt)->last_usable_lba) < le64_to_cpu((*gpt)->first_usable_lba)) {
|
||||
pr_debug("GPT: last_usable_lba incorrect: %lld > %lld\n",
|
||||
(unsigned long long)le64_to_cpu((*gpt)->last_usable_lba),
|
||||
(unsigned long long)le64_to_cpu((*gpt)->first_usable_lba));
|
||||
goto fail;
|
||||
}
|
||||
/* Check that sizeof_partition_entry has the correct value */
|
||||
if (le32_to_cpu((*gpt)->sizeof_partition_entry) != sizeof(gpt_entry)) {
|
||||
pr_debug("GUID Partitition Entry Size check failed.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(*ptes = alloc_read_gpt_entries(state, *gpt)))
|
||||
goto fail;
|
||||
|
||||
/* Check the GUID Partition Entry Array CRC */
|
||||
crc = efi_crc32((const unsigned char *) (*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)) {
|
||||
pr_debug("GUID Partitition Entry Array CRC check failed.\n");
|
||||
goto fail_ptes;
|
||||
}
|
||||
|
||||
/* We're done, all's well */
|
||||
return 1;
|
||||
|
||||
fail_ptes:
|
||||
kfree(*ptes);
|
||||
*ptes = NULL;
|
||||
fail:
|
||||
kfree(*gpt);
|
||||
*gpt = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* is_pte_valid() - tests one PTE for validity
|
||||
* @pte:pte to check
|
||||
* @lastlba: last lba of the disk
|
||||
*
|
||||
* Description: returns 1 if valid, 0 on error.
|
||||
*/
|
||||
static inline int
|
||||
is_pte_valid(const gpt_entry *pte, const u64 lastlba)
|
||||
{
|
||||
if ((!efi_guidcmp(pte->partition_type_guid, NULL_GUID)) ||
|
||||
le64_to_cpu(pte->starting_lba) > lastlba ||
|
||||
le64_to_cpu(pte->ending_lba) > lastlba)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* compare_gpts() - Search disk for valid GPT headers and PTEs
|
||||
* @pgpt: primary GPT header
|
||||
* @agpt: alternate GPT header
|
||||
* @lastlba: 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, u64 lastlba)
|
||||
{
|
||||
int error_found = 0;
|
||||
if (!pgpt || !agpt)
|
||||
return;
|
||||
if (le64_to_cpu(pgpt->my_lba) != le64_to_cpu(agpt->alternate_lba)) {
|
||||
pr_warn("GPT:Primary header LBA != Alt. header alternate_lba\n");
|
||||
pr_warn("GPT:%lld != %lld\n",
|
||||
(unsigned long long)le64_to_cpu(pgpt->my_lba),
|
||||
(unsigned long long)le64_to_cpu(agpt->alternate_lba));
|
||||
error_found++;
|
||||
}
|
||||
if (le64_to_cpu(pgpt->alternate_lba) != le64_to_cpu(agpt->my_lba)) {
|
||||
pr_warn("GPT:Primary header alternate_lba != Alt. header my_lba\n");
|
||||
pr_warn("GPT:%lld != %lld\n",
|
||||
(unsigned long long)le64_to_cpu(pgpt->alternate_lba),
|
||||
(unsigned long long)le64_to_cpu(agpt->my_lba));
|
||||
error_found++;
|
||||
}
|
||||
if (le64_to_cpu(pgpt->first_usable_lba) !=
|
||||
le64_to_cpu(agpt->first_usable_lba)) {
|
||||
pr_warn("GPT:first_usable_lbas don't match.\n");
|
||||
pr_warn("GPT:%lld != %lld\n",
|
||||
(unsigned long long)le64_to_cpu(pgpt->first_usable_lba),
|
||||
(unsigned long long)le64_to_cpu(agpt->first_usable_lba));
|
||||
error_found++;
|
||||
}
|
||||
if (le64_to_cpu(pgpt->last_usable_lba) !=
|
||||
le64_to_cpu(agpt->last_usable_lba)) {
|
||||
pr_warn("GPT:last_usable_lbas don't match.\n");
|
||||
pr_warn("GPT:%lld != %lld\n",
|
||||
(unsigned long long)le64_to_cpu(pgpt->last_usable_lba),
|
||||
(unsigned long long)le64_to_cpu(agpt->last_usable_lba));
|
||||
error_found++;
|
||||
}
|
||||
if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid)) {
|
||||
pr_warn("GPT:disk_guids don't match.\n");
|
||||
error_found++;
|
||||
}
|
||||
if (le32_to_cpu(pgpt->num_partition_entries) !=
|
||||
le32_to_cpu(agpt->num_partition_entries)) {
|
||||
pr_warn("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)) {
|
||||
pr_warn("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)) {
|
||||
pr_warn("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) {
|
||||
pr_warn("GPT:Primary header thinks Alt. header is not at the end of the disk.\n");
|
||||
pr_warn("GPT:%lld != %lld\n",
|
||||
(unsigned long long)le64_to_cpu(pgpt->alternate_lba),
|
||||
(unsigned long long)lastlba);
|
||||
error_found++;
|
||||
}
|
||||
|
||||
if (le64_to_cpu(agpt->my_lba) != lastlba) {
|
||||
pr_warn("GPT:Alternate GPT header not at the end of the disk.\n");
|
||||
pr_warn("GPT:%lld != %lld\n",
|
||||
(unsigned long long)le64_to_cpu(agpt->my_lba),
|
||||
(unsigned long long)lastlba);
|
||||
error_found++;
|
||||
}
|
||||
|
||||
if (error_found)
|
||||
pr_warn("GPT: Use GNU Parted to correct GPT errors.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* find_valid_gpt() - Search disk for valid GPT headers and PTEs
|
||||
* @state: disk parsed partitions
|
||||
* @gpt: GPT header ptr, filled on return.
|
||||
* @ptes: 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 PMBR being valid (or being overridden by the
|
||||
* 'gpt' kernel command line option) and finding either the Primary
|
||||
* GPT header and PTEs valid, or the Alternate GPT header and PTEs
|
||||
* valid. If the Primary GPT header is not valid, the Alternate GPT header
|
||||
* is not checked unless the 'gpt' kernel command line option is passed.
|
||||
* This protects against devices which misreport their size, and forces
|
||||
* the user to decide to use the Alternate GPT.
|
||||
*/
|
||||
static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt,
|
||||
gpt_entry **ptes)
|
||||
{
|
||||
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;
|
||||
sector_t total_sectors = i_size_read(state->bdev->bd_inode) >> 9;
|
||||
u64 lastlba;
|
||||
|
||||
if (!ptes)
|
||||
return 0;
|
||||
|
||||
lastlba = last_lba(state->bdev);
|
||||
if (!force_gpt) {
|
||||
/* This will be added to the EFI Spec. per Intel after v1.02. */
|
||||
legacymbr = kzalloc(sizeof(*legacymbr), GFP_KERNEL);
|
||||
if (!legacymbr)
|
||||
goto fail;
|
||||
|
||||
read_lba(state, 0, (u8 *)legacymbr, sizeof(*legacymbr));
|
||||
good_pmbr = is_pmbr_valid(legacymbr, total_sectors);
|
||||
kfree(legacymbr);
|
||||
|
||||
if (!good_pmbr)
|
||||
goto fail;
|
||||
|
||||
pr_debug("Device has a %s MBR\n",
|
||||
good_pmbr == GPT_MBR_PROTECTIVE ?
|
||||
"protective" : "hybrid");
|
||||
}
|
||||
|
||||
good_pgpt = is_gpt_valid(state, GPT_PRIMARY_PARTITION_TABLE_LBA,
|
||||
&pgpt, &pptes);
|
||||
if (good_pgpt)
|
||||
good_agpt = is_gpt_valid(state,
|
||||
le64_to_cpu(pgpt->alternate_lba),
|
||||
&agpt, &aptes);
|
||||
if (!good_agpt && force_gpt)
|
||||
good_agpt = is_gpt_valid(state, lastlba, &agpt, &aptes);
|
||||
|
||||
/* The obviously unsuccessful case */
|
||||
if (!good_pgpt && !good_agpt)
|
||||
goto fail;
|
||||
|
||||
compare_gpts(pgpt, agpt, lastlba);
|
||||
|
||||
/* The good cases */
|
||||
if (good_pgpt) {
|
||||
*gpt = pgpt;
|
||||
*ptes = pptes;
|
||||
kfree(agpt);
|
||||
kfree(aptes);
|
||||
if (!good_agpt)
|
||||
pr_warn("Alternate GPT is invalid, using primary GPT.\n");
|
||||
return 1;
|
||||
}
|
||||
else if (good_agpt) {
|
||||
*gpt = agpt;
|
||||
*ptes = aptes;
|
||||
kfree(pgpt);
|
||||
kfree(pptes);
|
||||
pr_warn("Primary GPT is invalid, using alternate GPT.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fail:
|
||||
kfree(pgpt);
|
||||
kfree(agpt);
|
||||
kfree(pptes);
|
||||
kfree(aptes);
|
||||
*gpt = NULL;
|
||||
*ptes = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_partition(struct parsed_partitions *state)
|
||||
* @state: disk parsed partitions
|
||||
*
|
||||
* Description: called from check.c, if the disk contains GPT
|
||||
* partitions, sets up partition entries in the kernel.
|
||||
*
|
||||
* If the first block on the disk is a legacy MBR,
|
||||
* it will get handled by msdos_partition().
|
||||
* If it's a Protective MBR, we'll handle it here.
|
||||
*
|
||||
* We do not create a Linux partition for GPT, but
|
||||
* only for the actual data partitions.
|
||||
* Returns:
|
||||
* -1 if unable to read the partition table
|
||||
* 0 if this isn't our partition table
|
||||
* 1 if successful
|
||||
*
|
||||
*/
|
||||
int efi_partition(struct parsed_partitions *state)
|
||||
{
|
||||
gpt_header *gpt = NULL;
|
||||
gpt_entry *ptes = NULL;
|
||||
u32 i;
|
||||
unsigned ssz = bdev_logical_block_size(state->bdev) / 512;
|
||||
|
||||
if (!find_valid_gpt(state, &gpt, &ptes) || !gpt || !ptes) {
|
||||
kfree(gpt);
|
||||
kfree(ptes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pr_debug("GUID Partition Table is valid! Yea!\n");
|
||||
|
||||
for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < state->limit-1; i++) {
|
||||
struct partition_meta_info *info;
|
||||
unsigned label_count = 0;
|
||||
unsigned label_max;
|
||||
u64 start = le64_to_cpu(ptes[i].starting_lba);
|
||||
u64 size = le64_to_cpu(ptes[i].ending_lba) -
|
||||
le64_to_cpu(ptes[i].starting_lba) + 1ULL;
|
||||
|
||||
if (!is_pte_valid(&ptes[i], last_lba(state->bdev)))
|
||||
continue;
|
||||
|
||||
put_partition(state, i+1, start * ssz, size * ssz);
|
||||
|
||||
/* If this is a RAID volume, tell md */
|
||||
if (!efi_guidcmp(ptes[i].partition_type_guid, PARTITION_LINUX_RAID_GUID))
|
||||
state->parts[i + 1].flags = ADDPART_FLAG_RAID;
|
||||
|
||||
info = &state->parts[i + 1].info;
|
||||
efi_guid_unparse(&ptes[i].unique_partition_guid, info->uuid);
|
||||
|
||||
/* Naively convert UTF16-LE to 7 bits. */
|
||||
label_max = min(ARRAY_SIZE(info->volname) - 1,
|
||||
ARRAY_SIZE(ptes[i].partition_name));
|
||||
info->volname[label_max] = 0;
|
||||
while (label_count < label_max) {
|
||||
u8 c = ptes[i].partition_name[label_count] & 0xff;
|
||||
if (c && !isprint(c))
|
||||
c = '!';
|
||||
info->volname[label_count] = c;
|
||||
label_count++;
|
||||
}
|
||||
state->parts[i + 1].has_info = true;
|
||||
}
|
||||
kfree(ptes);
|
||||
kfree(gpt);
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
return 1;
|
||||
}
|
133
block/partitions/efi.h
Normal file
133
block/partitions/efi.h
Normal file
|
@ -0,0 +1,133 @@
|
|||
/************************************************************
|
||||
* EFI GUID Partition Table
|
||||
* Per Intel EFI Specification v1.02
|
||||
* http://developer.intel.com/technology/efi/efi.htm
|
||||
*
|
||||
* By Matt Domsch <Matt_Domsch@dell.com> Fri Sep 22 22:15:56 CDT 2000
|
||||
* Copyright 2000,2001 Dell Inc.
|
||||
*
|
||||
* 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 FS_PART_EFI_H_INCLUDED
|
||||
#define FS_PART_EFI_H_INCLUDED
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/genhd.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/efi.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
#define MSDOS_MBR_SIGNATURE 0xaa55
|
||||
#define EFI_PMBR_OSTYPE_EFI 0xEF
|
||||
#define EFI_PMBR_OSTYPE_EFI_GPT 0xEE
|
||||
|
||||
#define GPT_MBR_PROTECTIVE 1
|
||||
#define GPT_MBR_HYBRID 2
|
||||
|
||||
#define GPT_HEADER_SIGNATURE 0x5452415020494645ULL
|
||||
#define GPT_HEADER_REVISION_V1 0x00010000
|
||||
#define GPT_PRIMARY_PARTITION_TABLE_LBA 1
|
||||
|
||||
#define PARTITION_SYSTEM_GUID \
|
||||
EFI_GUID( 0xC12A7328, 0xF81F, 0x11d2, \
|
||||
0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B)
|
||||
#define LEGACY_MBR_PARTITION_GUID \
|
||||
EFI_GUID( 0x024DEE41, 0x33E7, 0x11d3, \
|
||||
0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F)
|
||||
#define PARTITION_MSFT_RESERVED_GUID \
|
||||
EFI_GUID( 0xE3C9E316, 0x0B5C, 0x4DB8, \
|
||||
0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE)
|
||||
#define PARTITION_BASIC_DATA_GUID \
|
||||
EFI_GUID( 0xEBD0A0A2, 0xB9E5, 0x4433, \
|
||||
0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7)
|
||||
#define PARTITION_LINUX_RAID_GUID \
|
||||
EFI_GUID( 0xa19d880f, 0x05fc, 0x4d3b, \
|
||||
0xa0, 0x06, 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e)
|
||||
#define PARTITION_LINUX_SWAP_GUID \
|
||||
EFI_GUID( 0x0657fd6d, 0xa4ab, 0x43c4, \
|
||||
0x84, 0xe5, 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f)
|
||||
#define PARTITION_LINUX_LVM_GUID \
|
||||
EFI_GUID( 0xe6d6d379, 0xf507, 0x44c2, \
|
||||
0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28)
|
||||
|
||||
typedef struct _gpt_header {
|
||||
__le64 signature;
|
||||
__le32 revision;
|
||||
__le32 header_size;
|
||||
__le32 header_crc32;
|
||||
__le32 reserved1;
|
||||
__le64 my_lba;
|
||||
__le64 alternate_lba;
|
||||
__le64 first_usable_lba;
|
||||
__le64 last_usable_lba;
|
||||
efi_guid_t disk_guid;
|
||||
__le64 partition_entry_lba;
|
||||
__le32 num_partition_entries;
|
||||
__le32 sizeof_partition_entry;
|
||||
__le32 partition_entry_array_crc32;
|
||||
|
||||
/* The rest of the logical block is reserved by UEFI and must be zero.
|
||||
* EFI standard handles this by:
|
||||
*
|
||||
* uint8_t reserved2[ BlockSize - 92 ];
|
||||
*/
|
||||
} __packed gpt_header;
|
||||
|
||||
typedef struct _gpt_entry_attributes {
|
||||
u64 required_to_function:1;
|
||||
u64 reserved:47;
|
||||
u64 type_guid_specific:16;
|
||||
} __packed gpt_entry_attributes;
|
||||
|
||||
typedef struct _gpt_entry {
|
||||
efi_guid_t partition_type_guid;
|
||||
efi_guid_t unique_partition_guid;
|
||||
__le64 starting_lba;
|
||||
__le64 ending_lba;
|
||||
gpt_entry_attributes attributes;
|
||||
efi_char16_t partition_name[72 / sizeof (efi_char16_t)];
|
||||
} __packed gpt_entry;
|
||||
|
||||
typedef struct _gpt_mbr_record {
|
||||
u8 boot_indicator; /* unused by EFI, set to 0x80 for bootable */
|
||||
u8 start_head; /* unused by EFI, pt start in CHS */
|
||||
u8 start_sector; /* unused by EFI, pt start in CHS */
|
||||
u8 start_track;
|
||||
u8 os_type; /* EFI and legacy non-EFI OS types */
|
||||
u8 end_head; /* unused by EFI, pt end in CHS */
|
||||
u8 end_sector; /* unused by EFI, pt end in CHS */
|
||||
u8 end_track; /* unused by EFI, pt end in CHS */
|
||||
__le32 starting_lba; /* used by EFI - start addr of the on disk pt */
|
||||
__le32 size_in_lba; /* used by EFI - size of pt in LBA */
|
||||
} __packed gpt_mbr_record;
|
||||
|
||||
|
||||
typedef struct _legacy_mbr {
|
||||
u8 boot_code[440];
|
||||
__le32 unique_mbr_signature;
|
||||
__le16 unknown;
|
||||
gpt_mbr_record partition_record[4];
|
||||
__le16 signature;
|
||||
} __packed legacy_mbr;
|
||||
|
||||
/* Functions */
|
||||
extern int efi_partition(struct parsed_partitions *state);
|
||||
|
||||
#endif
|
364
block/partitions/ibm.c
Normal file
364
block/partitions/ibm.c
Normal file
|
@ -0,0 +1,364 @@
|
|||
/*
|
||||
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
|
||||
* Volker Sameske <sameske@de.ibm.com>
|
||||
* Bugreports.to..: <Linux390@de.ibm.com>
|
||||
* Copyright IBM Corp. 1999, 2012
|
||||
*/
|
||||
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/hdreg.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/dasd.h>
|
||||
#include <asm/ebcdic.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/vtoc.h>
|
||||
|
||||
#include "check.h"
|
||||
#include "ibm.h"
|
||||
|
||||
|
||||
union label_t {
|
||||
struct vtoc_volume_label_cdl vol;
|
||||
struct vtoc_volume_label_ldl lnx;
|
||||
struct vtoc_cms_label cms;
|
||||
};
|
||||
|
||||
/*
|
||||
* compute the block number from a
|
||||
* cyl-cyl-head-head structure
|
||||
*/
|
||||
static sector_t cchh2blk(struct vtoc_cchh *ptr, struct hd_geometry *geo)
|
||||
{
|
||||
sector_t cyl;
|
||||
__u16 head;
|
||||
|
||||
/* decode cylinder and heads for large volumes */
|
||||
cyl = ptr->hh & 0xFFF0;
|
||||
cyl <<= 12;
|
||||
cyl |= ptr->cc;
|
||||
head = ptr->hh & 0x000F;
|
||||
return cyl * geo->heads * geo->sectors +
|
||||
head * geo->sectors;
|
||||
}
|
||||
|
||||
/*
|
||||
* compute the block number from a
|
||||
* cyl-cyl-head-head-block structure
|
||||
*/
|
||||
static sector_t cchhb2blk(struct vtoc_cchhb *ptr, struct hd_geometry *geo)
|
||||
{
|
||||
sector_t cyl;
|
||||
__u16 head;
|
||||
|
||||
/* decode cylinder and heads for large volumes */
|
||||
cyl = ptr->hh & 0xFFF0;
|
||||
cyl <<= 12;
|
||||
cyl |= ptr->cc;
|
||||
head = ptr->hh & 0x000F;
|
||||
return cyl * geo->heads * geo->sectors +
|
||||
head * geo->sectors +
|
||||
ptr->b;
|
||||
}
|
||||
|
||||
static int find_label(struct parsed_partitions *state,
|
||||
dasd_information2_t *info,
|
||||
struct hd_geometry *geo,
|
||||
int blocksize,
|
||||
sector_t *labelsect,
|
||||
char name[],
|
||||
char type[],
|
||||
union label_t *label)
|
||||
{
|
||||
Sector sect;
|
||||
unsigned char *data;
|
||||
sector_t testsect[3];
|
||||
unsigned char temp[5];
|
||||
int found = 0;
|
||||
int i, testcount;
|
||||
|
||||
/* There a three places where we may find a valid label:
|
||||
* - on an ECKD disk it's block 2
|
||||
* - on an FBA disk it's block 1
|
||||
* - on an CMS formatted FBA disk it is sector 1, even if the block size
|
||||
* is larger than 512 bytes (possible if the DIAG discipline is used)
|
||||
* If we have a valid info structure, then we know exactly which case we
|
||||
* have, otherwise we just search through all possebilities.
|
||||
*/
|
||||
if (info) {
|
||||
if ((info->cu_type == 0x6310 && info->dev_type == 0x9336) ||
|
||||
(info->cu_type == 0x3880 && info->dev_type == 0x3370))
|
||||
testsect[0] = info->label_block;
|
||||
else
|
||||
testsect[0] = info->label_block * (blocksize >> 9);
|
||||
testcount = 1;
|
||||
} else {
|
||||
testsect[0] = 1;
|
||||
testsect[1] = (blocksize >> 9);
|
||||
testsect[2] = 2 * (blocksize >> 9);
|
||||
testcount = 3;
|
||||
}
|
||||
for (i = 0; i < testcount; ++i) {
|
||||
data = read_part_sector(state, testsect[i], §);
|
||||
if (data == NULL)
|
||||
continue;
|
||||
memcpy(label, data, sizeof(*label));
|
||||
memcpy(temp, data, 4);
|
||||
temp[4] = 0;
|
||||
EBCASC(temp, 4);
|
||||
put_dev_sector(sect);
|
||||
if (!strcmp(temp, "VOL1") ||
|
||||
!strcmp(temp, "LNX1") ||
|
||||
!strcmp(temp, "CMS1")) {
|
||||
if (!strcmp(temp, "VOL1")) {
|
||||
strncpy(type, label->vol.vollbl, 4);
|
||||
strncpy(name, label->vol.volid, 6);
|
||||
} else {
|
||||
strncpy(type, label->lnx.vollbl, 4);
|
||||
strncpy(name, label->lnx.volid, 6);
|
||||
}
|
||||
EBCASC(type, 4);
|
||||
EBCASC(name, 6);
|
||||
*labelsect = testsect[i];
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
memset(label, 0, sizeof(*label));
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static int find_vol1_partitions(struct parsed_partitions *state,
|
||||
struct hd_geometry *geo,
|
||||
int blocksize,
|
||||
char name[],
|
||||
union label_t *label)
|
||||
{
|
||||
sector_t blk;
|
||||
int counter;
|
||||
char tmp[64];
|
||||
Sector sect;
|
||||
unsigned char *data;
|
||||
loff_t offset, size;
|
||||
struct vtoc_format1_label f1;
|
||||
int secperblk;
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "VOL1/%8s:", name);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
/*
|
||||
* get start of VTOC from the disk label and then search for format1
|
||||
* and format8 labels
|
||||
*/
|
||||
secperblk = blocksize >> 9;
|
||||
blk = cchhb2blk(&label->vol.vtoc, geo) + 1;
|
||||
counter = 0;
|
||||
data = read_part_sector(state, blk * secperblk, §);
|
||||
while (data != NULL) {
|
||||
memcpy(&f1, data, sizeof(struct vtoc_format1_label));
|
||||
put_dev_sector(sect);
|
||||
/* skip FMT4 / FMT5 / FMT7 labels */
|
||||
if (f1.DS1FMTID == _ascebc['4']
|
||||
|| f1.DS1FMTID == _ascebc['5']
|
||||
|| f1.DS1FMTID == _ascebc['7']
|
||||
|| f1.DS1FMTID == _ascebc['9']) {
|
||||
blk++;
|
||||
data = read_part_sector(state, blk * secperblk, §);
|
||||
continue;
|
||||
}
|
||||
/* only FMT1 and 8 labels valid at this point */
|
||||
if (f1.DS1FMTID != _ascebc['1'] &&
|
||||
f1.DS1FMTID != _ascebc['8'])
|
||||
break;
|
||||
/* OK, we got valid partition data */
|
||||
offset = cchh2blk(&f1.DS1EXT1.llimit, geo);
|
||||
size = cchh2blk(&f1.DS1EXT1.ulimit, geo) -
|
||||
offset + geo->sectors;
|
||||
offset *= secperblk;
|
||||
size *= secperblk;
|
||||
if (counter >= state->limit)
|
||||
break;
|
||||
put_partition(state, counter + 1, offset, size);
|
||||
counter++;
|
||||
blk++;
|
||||
data = read_part_sector(state, blk * secperblk, §);
|
||||
}
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int find_lnx1_partitions(struct parsed_partitions *state,
|
||||
struct hd_geometry *geo,
|
||||
int blocksize,
|
||||
char name[],
|
||||
union label_t *label,
|
||||
sector_t labelsect,
|
||||
loff_t i_size,
|
||||
dasd_information2_t *info)
|
||||
{
|
||||
loff_t offset, geo_size, size;
|
||||
char tmp[64];
|
||||
int secperblk;
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "LNX1/%8s:", name);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
secperblk = blocksize >> 9;
|
||||
if (label->lnx.ldl_version == 0xf2) {
|
||||
size = label->lnx.formatted_blocks * secperblk;
|
||||
} else {
|
||||
/*
|
||||
* Formated w/o large volume support. If the sanity check
|
||||
* 'size based on geo == size based on i_size' is true, then
|
||||
* we can safely assume that we know the formatted size of
|
||||
* the disk, otherwise we need additional information
|
||||
* that we can only get from a real DASD device.
|
||||
*/
|
||||
geo_size = geo->cylinders * geo->heads
|
||||
* geo->sectors * secperblk;
|
||||
size = i_size >> 9;
|
||||
if (size != geo_size) {
|
||||
if (!info) {
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
return 1;
|
||||
}
|
||||
if (!strcmp(info->type, "ECKD"))
|
||||
if (geo_size < size)
|
||||
size = geo_size;
|
||||
/* else keep size based on i_size */
|
||||
}
|
||||
}
|
||||
/* first and only partition starts in the first block after the label */
|
||||
offset = labelsect + secperblk;
|
||||
put_partition(state, 1, offset, size - offset);
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int find_cms1_partitions(struct parsed_partitions *state,
|
||||
struct hd_geometry *geo,
|
||||
int blocksize,
|
||||
char name[],
|
||||
union label_t *label,
|
||||
sector_t labelsect)
|
||||
{
|
||||
loff_t offset, size;
|
||||
char tmp[64];
|
||||
int secperblk;
|
||||
|
||||
/*
|
||||
* VM style CMS1 labeled disk
|
||||
*/
|
||||
blocksize = label->cms.block_size;
|
||||
secperblk = blocksize >> 9;
|
||||
if (label->cms.disk_offset != 0) {
|
||||
snprintf(tmp, sizeof(tmp), "CMS1/%8s(MDSK):", name);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
/* disk is reserved minidisk */
|
||||
offset = label->cms.disk_offset * secperblk;
|
||||
size = (label->cms.block_count - 1) * secperblk;
|
||||
} else {
|
||||
snprintf(tmp, sizeof(tmp), "CMS1/%8s:", name);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
/*
|
||||
* Special case for FBA devices:
|
||||
* If an FBA device is CMS formatted with blocksize > 512 byte
|
||||
* and the DIAG discipline is used, then the CMS label is found
|
||||
* in sector 1 instead of block 1. However, the partition is
|
||||
* still supposed to start in block 2.
|
||||
*/
|
||||
if (labelsect == 1)
|
||||
offset = 2 * secperblk;
|
||||
else
|
||||
offset = labelsect + secperblk;
|
||||
size = label->cms.block_count * secperblk;
|
||||
}
|
||||
|
||||
put_partition(state, 1, offset, size-offset);
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This is the main function, called by check.c
|
||||
*/
|
||||
int ibm_partition(struct parsed_partitions *state)
|
||||
{
|
||||
struct block_device *bdev = state->bdev;
|
||||
int blocksize, res;
|
||||
loff_t i_size, offset, size;
|
||||
dasd_information2_t *info;
|
||||
struct hd_geometry *geo;
|
||||
char type[5] = {0,};
|
||||
char name[7] = {0,};
|
||||
sector_t labelsect;
|
||||
union label_t *label;
|
||||
|
||||
res = 0;
|
||||
blocksize = bdev_logical_block_size(bdev);
|
||||
if (blocksize <= 0)
|
||||
goto out_exit;
|
||||
i_size = i_size_read(bdev->bd_inode);
|
||||
if (i_size == 0)
|
||||
goto out_exit;
|
||||
info = kmalloc(sizeof(dasd_information2_t), GFP_KERNEL);
|
||||
if (info == NULL)
|
||||
goto out_exit;
|
||||
geo = kmalloc(sizeof(struct hd_geometry), GFP_KERNEL);
|
||||
if (geo == NULL)
|
||||
goto out_nogeo;
|
||||
label = kmalloc(sizeof(union label_t), GFP_KERNEL);
|
||||
if (label == NULL)
|
||||
goto out_nolab;
|
||||
if (ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo) != 0)
|
||||
goto out_freeall;
|
||||
if (ioctl_by_bdev(bdev, BIODASDINFO2, (unsigned long)info) != 0) {
|
||||
kfree(info);
|
||||
info = NULL;
|
||||
}
|
||||
|
||||
if (find_label(state, info, geo, blocksize, &labelsect, name, type,
|
||||
label)) {
|
||||
if (!strncmp(type, "VOL1", 4)) {
|
||||
res = find_vol1_partitions(state, geo, blocksize, name,
|
||||
label);
|
||||
} else if (!strncmp(type, "LNX1", 4)) {
|
||||
res = find_lnx1_partitions(state, geo, blocksize, name,
|
||||
label, labelsect, i_size,
|
||||
info);
|
||||
} else if (!strncmp(type, "CMS1", 4)) {
|
||||
res = find_cms1_partitions(state, geo, blocksize, name,
|
||||
label, labelsect);
|
||||
}
|
||||
} else if (info) {
|
||||
/*
|
||||
* ugly but needed for backward compatibility:
|
||||
* If the block device is a DASD (i.e. BIODASDINFO2 works),
|
||||
* then we claim it in any case, even though it has no valid
|
||||
* label. If it has the LDL format, then we simply define a
|
||||
* partition as if it had an LNX1 label.
|
||||
*/
|
||||
res = 1;
|
||||
if (info->format == DASD_FORMAT_LDL) {
|
||||
strlcat(state->pp_buf, "(nonl)", PAGE_SIZE);
|
||||
size = i_size >> 9;
|
||||
offset = (info->label_block + 1) * (blocksize >> 9);
|
||||
put_partition(state, 1, offset, size-offset);
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
}
|
||||
} else
|
||||
res = 0;
|
||||
|
||||
out_freeall:
|
||||
kfree(label);
|
||||
out_nolab:
|
||||
kfree(geo);
|
||||
out_nogeo:
|
||||
kfree(info);
|
||||
out_exit:
|
||||
return res;
|
||||
}
|
1
block/partitions/ibm.h
Normal file
1
block/partitions/ibm.h
Normal file
|
@ -0,0 +1 @@
|
|||
int ibm_partition(struct parsed_partitions *);
|
58
block/partitions/karma.c
Normal file
58
block/partitions/karma.c
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* fs/partitions/karma.c
|
||||
* Rio Karma partition info.
|
||||
*
|
||||
* Copyright (C) 2006 Bob Copeland (me@bobcopeland.com)
|
||||
* based on osf.c
|
||||
*/
|
||||
|
||||
#include "check.h"
|
||||
#include "karma.h"
|
||||
#include <linux/compiler.h>
|
||||
|
||||
int karma_partition(struct parsed_partitions *state)
|
||||
{
|
||||
int i;
|
||||
int slot = 1;
|
||||
Sector sect;
|
||||
unsigned char *data;
|
||||
struct disklabel {
|
||||
u8 d_reserved[270];
|
||||
struct d_partition {
|
||||
__le32 p_res;
|
||||
u8 p_fstype;
|
||||
u8 p_res2[3];
|
||||
__le32 p_offset;
|
||||
__le32 p_size;
|
||||
} d_partitions[2];
|
||||
u8 d_blank[208];
|
||||
__le16 d_magic;
|
||||
} __packed *label;
|
||||
struct d_partition *p;
|
||||
|
||||
data = read_part_sector(state, 0, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
label = (struct disklabel *)data;
|
||||
if (le16_to_cpu(label->d_magic) != KARMA_LABEL_MAGIC) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
|
||||
p = label->d_partitions;
|
||||
for (i = 0 ; i < 2; i++, p++) {
|
||||
if (slot == state->limit)
|
||||
break;
|
||||
|
||||
if (p->p_fstype == 0x4d && le32_to_cpu(p->p_size)) {
|
||||
put_partition(state, slot, le32_to_cpu(p->p_offset),
|
||||
le32_to_cpu(p->p_size));
|
||||
}
|
||||
slot++;
|
||||
}
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
put_dev_sector(sect);
|
||||
return 1;
|
||||
}
|
||||
|
8
block/partitions/karma.h
Normal file
8
block/partitions/karma.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* fs/partitions/karma.h
|
||||
*/
|
||||
|
||||
#define KARMA_LABEL_MAGIC 0xAB56
|
||||
|
||||
int karma_partition(struct parsed_partitions *state);
|
||||
|
1567
block/partitions/ldm.c
Normal file
1567
block/partitions/ldm.c
Normal file
File diff suppressed because it is too large
Load diff
215
block/partitions/ldm.h
Normal file
215
block/partitions/ldm.h
Normal file
|
@ -0,0 +1,215 @@
|
|||
/**
|
||||
* ldm - Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (C) 2001,2002 Richard Russon <ldm@flatcap.org>
|
||||
* Copyright (c) 2001-2007 Anton Altaparmakov
|
||||
* Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>
|
||||
*
|
||||
* Documentation is available at http://www.linux-ntfs.org/doku.php?id=downloads
|
||||
*
|
||||
* 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 (in the main directory of the Linux-NTFS source
|
||||
* in the file COPYING); if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _FS_PT_LDM_H_
|
||||
#define _FS_PT_LDM_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/genhd.h>
|
||||
#include <linux/fs.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
struct parsed_partitions;
|
||||
|
||||
/* Magic numbers in CPU format. */
|
||||
#define MAGIC_VMDB 0x564D4442 /* VMDB */
|
||||
#define MAGIC_VBLK 0x56424C4B /* VBLK */
|
||||
#define MAGIC_PRIVHEAD 0x5052495648454144ULL /* PRIVHEAD */
|
||||
#define MAGIC_TOCBLOCK 0x544F43424C4F434BULL /* TOCBLOCK */
|
||||
|
||||
/* The defined vblk types. */
|
||||
#define VBLK_VOL5 0x51 /* Volume, version 5 */
|
||||
#define VBLK_CMP3 0x32 /* Component, version 3 */
|
||||
#define VBLK_PRT3 0x33 /* Partition, version 3 */
|
||||
#define VBLK_DSK3 0x34 /* Disk, version 3 */
|
||||
#define VBLK_DSK4 0x44 /* Disk, version 4 */
|
||||
#define VBLK_DGR3 0x35 /* Disk Group, version 3 */
|
||||
#define VBLK_DGR4 0x45 /* Disk Group, version 4 */
|
||||
|
||||
/* vblk flags indicating extra information will be present */
|
||||
#define VBLK_FLAG_COMP_STRIPE 0x10
|
||||
#define VBLK_FLAG_PART_INDEX 0x08
|
||||
#define VBLK_FLAG_DGR3_IDS 0x08
|
||||
#define VBLK_FLAG_DGR4_IDS 0x08
|
||||
#define VBLK_FLAG_VOLU_ID1 0x08
|
||||
#define VBLK_FLAG_VOLU_ID2 0x20
|
||||
#define VBLK_FLAG_VOLU_SIZE 0x80
|
||||
#define VBLK_FLAG_VOLU_DRIVE 0x02
|
||||
|
||||
/* size of a vblk's static parts */
|
||||
#define VBLK_SIZE_HEAD 16
|
||||
#define VBLK_SIZE_CMP3 22 /* Name and version */
|
||||
#define VBLK_SIZE_DGR3 12
|
||||
#define VBLK_SIZE_DGR4 44
|
||||
#define VBLK_SIZE_DSK3 12
|
||||
#define VBLK_SIZE_DSK4 45
|
||||
#define VBLK_SIZE_PRT3 28
|
||||
#define VBLK_SIZE_VOL5 58
|
||||
|
||||
/* component types */
|
||||
#define COMP_STRIPE 0x01 /* Stripe-set */
|
||||
#define COMP_BASIC 0x02 /* Basic disk */
|
||||
#define COMP_RAID 0x03 /* Raid-set */
|
||||
|
||||
/* Other constants. */
|
||||
#define LDM_DB_SIZE 2048 /* Size in sectors (= 1MiB). */
|
||||
|
||||
#define OFF_PRIV1 6 /* Offset of the first privhead
|
||||
relative to the start of the
|
||||
device in sectors */
|
||||
|
||||
/* Offsets to structures within the LDM Database in sectors. */
|
||||
#define OFF_PRIV2 1856 /* Backup private headers. */
|
||||
#define OFF_PRIV3 2047
|
||||
|
||||
#define OFF_TOCB1 1 /* Tables of contents. */
|
||||
#define OFF_TOCB2 2
|
||||
#define OFF_TOCB3 2045
|
||||
#define OFF_TOCB4 2046
|
||||
|
||||
#define OFF_VMDB 17 /* List of partitions. */
|
||||
|
||||
#define LDM_PARTITION 0x42 /* Formerly SFS (Landis). */
|
||||
|
||||
#define TOC_BITMAP1 "config" /* Names of the two defined */
|
||||
#define TOC_BITMAP2 "log" /* bitmaps in the TOCBLOCK. */
|
||||
|
||||
/* Borrowed from msdos.c */
|
||||
#define SYS_IND(p) (get_unaligned(&(p)->sys_ind))
|
||||
|
||||
struct frag { /* VBLK Fragment handling */
|
||||
struct list_head list;
|
||||
u32 group;
|
||||
u8 num; /* Total number of records */
|
||||
u8 rec; /* This is record number n */
|
||||
u8 map; /* Which portions are in use */
|
||||
u8 data[0];
|
||||
};
|
||||
|
||||
/* In memory LDM database structures. */
|
||||
|
||||
#define GUID_SIZE 16
|
||||
|
||||
struct privhead { /* Offsets and sizes are in sectors. */
|
||||
u16 ver_major;
|
||||
u16 ver_minor;
|
||||
u64 logical_disk_start;
|
||||
u64 logical_disk_size;
|
||||
u64 config_start;
|
||||
u64 config_size;
|
||||
u8 disk_id[GUID_SIZE];
|
||||
};
|
||||
|
||||
struct tocblock { /* We have exactly two bitmaps. */
|
||||
u8 bitmap1_name[16];
|
||||
u64 bitmap1_start;
|
||||
u64 bitmap1_size;
|
||||
u8 bitmap2_name[16];
|
||||
u64 bitmap2_start;
|
||||
u64 bitmap2_size;
|
||||
};
|
||||
|
||||
struct vmdb { /* VMDB: The database header */
|
||||
u16 ver_major;
|
||||
u16 ver_minor;
|
||||
u32 vblk_size;
|
||||
u32 vblk_offset;
|
||||
u32 last_vblk_seq;
|
||||
};
|
||||
|
||||
struct vblk_comp { /* VBLK Component */
|
||||
u8 state[16];
|
||||
u64 parent_id;
|
||||
u8 type;
|
||||
u8 children;
|
||||
u16 chunksize;
|
||||
};
|
||||
|
||||
struct vblk_dgrp { /* VBLK Disk Group */
|
||||
u8 disk_id[64];
|
||||
};
|
||||
|
||||
struct vblk_disk { /* VBLK Disk */
|
||||
u8 disk_id[GUID_SIZE];
|
||||
u8 alt_name[128];
|
||||
};
|
||||
|
||||
struct vblk_part { /* VBLK Partition */
|
||||
u64 start;
|
||||
u64 size; /* start, size and vol_off in sectors */
|
||||
u64 volume_offset;
|
||||
u64 parent_id;
|
||||
u64 disk_id;
|
||||
u8 partnum;
|
||||
};
|
||||
|
||||
struct vblk_volu { /* VBLK Volume */
|
||||
u8 volume_type[16];
|
||||
u8 volume_state[16];
|
||||
u8 guid[16];
|
||||
u8 drive_hint[4];
|
||||
u64 size;
|
||||
u8 partition_type;
|
||||
};
|
||||
|
||||
struct vblk_head { /* VBLK standard header */
|
||||
u32 group;
|
||||
u16 rec;
|
||||
u16 nrec;
|
||||
};
|
||||
|
||||
struct vblk { /* Generalised VBLK */
|
||||
u8 name[64];
|
||||
u64 obj_id;
|
||||
u32 sequence;
|
||||
u8 flags;
|
||||
u8 type;
|
||||
union {
|
||||
struct vblk_comp comp;
|
||||
struct vblk_dgrp dgrp;
|
||||
struct vblk_disk disk;
|
||||
struct vblk_part part;
|
||||
struct vblk_volu volu;
|
||||
} vblk;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct ldmdb { /* Cache of the database */
|
||||
struct privhead ph;
|
||||
struct tocblock toc;
|
||||
struct vmdb vm;
|
||||
struct list_head v_dgrp;
|
||||
struct list_head v_disk;
|
||||
struct list_head v_volu;
|
||||
struct list_head v_comp;
|
||||
struct list_head v_part;
|
||||
};
|
||||
|
||||
int ldm_partition(struct parsed_partitions *state);
|
||||
|
||||
#endif /* _FS_PT_LDM_H_ */
|
||||
|
138
block/partitions/mac.c
Normal file
138
block/partitions/mac.c
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* fs/partitions/mac.c
|
||||
*
|
||||
* Code extracted from drivers/block/genhd.c
|
||||
* Copyright (C) 1991-1998 Linus Torvalds
|
||||
* Re-organised Feb 1998 Russell King
|
||||
*/
|
||||
|
||||
#include <linux/ctype.h>
|
||||
#include "check.h"
|
||||
#include "mac.h"
|
||||
|
||||
#ifdef CONFIG_PPC_PMAC
|
||||
#include <asm/machdep.h>
|
||||
extern void note_bootable_part(dev_t dev, int part, int goodness);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Code to understand MacOS partition tables.
|
||||
*/
|
||||
|
||||
static inline void mac_fix_string(char *stg, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = len - 1; i >= 0 && stg[i] == ' '; i--)
|
||||
stg[i] = 0;
|
||||
}
|
||||
|
||||
int mac_partition(struct parsed_partitions *state)
|
||||
{
|
||||
Sector sect;
|
||||
unsigned char *data;
|
||||
int slot, blocks_in_map;
|
||||
unsigned secsize;
|
||||
#ifdef CONFIG_PPC_PMAC
|
||||
int found_root = 0;
|
||||
int found_root_goodness = 0;
|
||||
#endif
|
||||
struct mac_partition *part;
|
||||
struct mac_driver_desc *md;
|
||||
|
||||
/* Get 0th block and look at the first partition map entry. */
|
||||
md = read_part_sector(state, 0, §);
|
||||
if (!md)
|
||||
return -1;
|
||||
if (be16_to_cpu(md->signature) != MAC_DRIVER_MAGIC) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
secsize = be16_to_cpu(md->block_size);
|
||||
put_dev_sector(sect);
|
||||
data = read_part_sector(state, secsize/512, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
part = (struct mac_partition *) (data + secsize%512);
|
||||
if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC) {
|
||||
put_dev_sector(sect);
|
||||
return 0; /* not a MacOS disk */
|
||||
}
|
||||
blocks_in_map = be32_to_cpu(part->map_count);
|
||||
if (blocks_in_map < 0 || blocks_in_map >= DISK_MAX_PARTS) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (blocks_in_map >= state->limit)
|
||||
blocks_in_map = state->limit - 1;
|
||||
|
||||
strlcat(state->pp_buf, " [mac]", PAGE_SIZE);
|
||||
for (slot = 1; slot <= blocks_in_map; ++slot) {
|
||||
int pos = slot * secsize;
|
||||
put_dev_sector(sect);
|
||||
data = read_part_sector(state, pos/512, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
part = (struct mac_partition *) (data + pos%512);
|
||||
if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
|
||||
break;
|
||||
put_partition(state, slot,
|
||||
be32_to_cpu(part->start_block) * (secsize/512),
|
||||
be32_to_cpu(part->block_count) * (secsize/512));
|
||||
|
||||
if (!strncasecmp(part->type, "Linux_RAID", 10))
|
||||
state->parts[slot].flags = ADDPART_FLAG_RAID;
|
||||
#ifdef CONFIG_PPC_PMAC
|
||||
/*
|
||||
* If this is the first bootable partition, tell the
|
||||
* setup code, in case it wants to make this the root.
|
||||
*/
|
||||
if (machine_is(powermac)) {
|
||||
int goodness = 0;
|
||||
|
||||
mac_fix_string(part->processor, 16);
|
||||
mac_fix_string(part->name, 32);
|
||||
mac_fix_string(part->type, 32);
|
||||
|
||||
if ((be32_to_cpu(part->status) & MAC_STATUS_BOOTABLE)
|
||||
&& strcasecmp(part->processor, "powerpc") == 0)
|
||||
goodness++;
|
||||
|
||||
if (strcasecmp(part->type, "Apple_UNIX_SVR2") == 0
|
||||
|| (strncasecmp(part->type, "Linux", 5) == 0
|
||||
&& strcasecmp(part->type, "Linux_swap") != 0)) {
|
||||
int i, l;
|
||||
|
||||
goodness++;
|
||||
l = strlen(part->name);
|
||||
if (strcmp(part->name, "/") == 0)
|
||||
goodness++;
|
||||
for (i = 0; i <= l - 4; ++i) {
|
||||
if (strncasecmp(part->name + i, "root",
|
||||
4) == 0) {
|
||||
goodness += 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (strncasecmp(part->name, "swap", 4) == 0)
|
||||
goodness--;
|
||||
}
|
||||
|
||||
if (goodness > found_root_goodness) {
|
||||
found_root = slot;
|
||||
found_root_goodness = goodness;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_PPC_PMAC */
|
||||
}
|
||||
#ifdef CONFIG_PPC_PMAC
|
||||
if (found_root_goodness)
|
||||
note_bootable_part(state->bdev->bd_dev, found_root,
|
||||
found_root_goodness);
|
||||
#endif
|
||||
|
||||
put_dev_sector(sect);
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
return 1;
|
||||
}
|
44
block/partitions/mac.h
Normal file
44
block/partitions/mac.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* fs/partitions/mac.h
|
||||
*/
|
||||
|
||||
#define MAC_PARTITION_MAGIC 0x504d
|
||||
|
||||
/* type field value for A/UX or other Unix partitions */
|
||||
#define APPLE_AUX_TYPE "Apple_UNIX_SVR2"
|
||||
|
||||
struct mac_partition {
|
||||
__be16 signature; /* expected to be MAC_PARTITION_MAGIC */
|
||||
__be16 res1;
|
||||
__be32 map_count; /* # blocks in partition map */
|
||||
__be32 start_block; /* absolute starting block # of partition */
|
||||
__be32 block_count; /* number of blocks in partition */
|
||||
char name[32]; /* partition name */
|
||||
char type[32]; /* string type description */
|
||||
__be32 data_start; /* rel block # of first data block */
|
||||
__be32 data_count; /* number of data blocks */
|
||||
__be32 status; /* partition status bits */
|
||||
__be32 boot_start;
|
||||
__be32 boot_size;
|
||||
__be32 boot_load;
|
||||
__be32 boot_load2;
|
||||
__be32 boot_entry;
|
||||
__be32 boot_entry2;
|
||||
__be32 boot_cksum;
|
||||
char processor[16]; /* identifies ISA of boot */
|
||||
/* there is more stuff after this that we don't need */
|
||||
};
|
||||
|
||||
#define MAC_STATUS_BOOTABLE 8 /* partition is bootable */
|
||||
|
||||
#define MAC_DRIVER_MAGIC 0x4552
|
||||
|
||||
/* Driver descriptor structure, in block 0 */
|
||||
struct mac_driver_desc {
|
||||
__be16 signature; /* expected to be MAC_DRIVER_MAGIC */
|
||||
__be16 block_size;
|
||||
__be32 block_count;
|
||||
/* ... more stuff */
|
||||
};
|
||||
|
||||
int mac_partition(struct parsed_partitions *state);
|
582
block/partitions/msdos.c
Normal file
582
block/partitions/msdos.c
Normal file
|
@ -0,0 +1,582 @@
|
|||
/*
|
||||
* fs/partitions/msdos.c
|
||||
*
|
||||
* Code extracted from drivers/block/genhd.c
|
||||
* Copyright (C) 1991-1998 Linus Torvalds
|
||||
*
|
||||
* Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
|
||||
* in the early extended-partition checks and added DM partitions
|
||||
*
|
||||
* Support for DiskManager v6.0x added by Mark Lord,
|
||||
* with information provided by OnTrack. This now works for linux fdisk
|
||||
* and LILO, as well as loadlin and bootln. Note that disks other than
|
||||
* /dev/hda *must* have a "DOS" type 0x51 partition in the first slot (hda1).
|
||||
*
|
||||
* More flexible handling of extended partitions - aeb, 950831
|
||||
*
|
||||
* Check partition table on IDE disks for common CHS translations
|
||||
*
|
||||
* Re-organised Feb 1998 Russell King
|
||||
*/
|
||||
#include <linux/msdos_fs.h>
|
||||
|
||||
#include "check.h"
|
||||
#include "msdos.h"
|
||||
#include "efi.h"
|
||||
#include "aix.h"
|
||||
|
||||
/*
|
||||
* Many architectures don't like unaligned accesses, while
|
||||
* the nr_sects and start_sect partition table entries are
|
||||
* at a 2 (mod 4) address.
|
||||
*/
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#define SYS_IND(p) get_unaligned(&p->sys_ind)
|
||||
|
||||
static inline sector_t nr_sects(struct partition *p)
|
||||
{
|
||||
return (sector_t)get_unaligned_le32(&p->nr_sects);
|
||||
}
|
||||
|
||||
static inline sector_t start_sect(struct partition *p)
|
||||
{
|
||||
return (sector_t)get_unaligned_le32(&p->start_sect);
|
||||
}
|
||||
|
||||
static inline int is_extended_partition(struct partition *p)
|
||||
{
|
||||
return (SYS_IND(p) == DOS_EXTENDED_PARTITION ||
|
||||
SYS_IND(p) == WIN98_EXTENDED_PARTITION ||
|
||||
SYS_IND(p) == LINUX_EXTENDED_PARTITION);
|
||||
}
|
||||
|
||||
#define MSDOS_LABEL_MAGIC1 0x55
|
||||
#define MSDOS_LABEL_MAGIC2 0xAA
|
||||
|
||||
static inline int
|
||||
msdos_magic_present(unsigned char *p)
|
||||
{
|
||||
return (p[0] == MSDOS_LABEL_MAGIC1 && p[1] == MSDOS_LABEL_MAGIC2);
|
||||
}
|
||||
|
||||
/* Value is EBCDIC 'IBMA' */
|
||||
#define AIX_LABEL_MAGIC1 0xC9
|
||||
#define AIX_LABEL_MAGIC2 0xC2
|
||||
#define AIX_LABEL_MAGIC3 0xD4
|
||||
#define AIX_LABEL_MAGIC4 0xC1
|
||||
static int aix_magic_present(struct parsed_partitions *state, unsigned char *p)
|
||||
{
|
||||
struct partition *pt = (struct partition *) (p + 0x1be);
|
||||
Sector sect;
|
||||
unsigned char *d;
|
||||
int slot, ret = 0;
|
||||
|
||||
if (!(p[0] == AIX_LABEL_MAGIC1 &&
|
||||
p[1] == AIX_LABEL_MAGIC2 &&
|
||||
p[2] == AIX_LABEL_MAGIC3 &&
|
||||
p[3] == AIX_LABEL_MAGIC4))
|
||||
return 0;
|
||||
/* Assume the partition table is valid if Linux partitions exists */
|
||||
for (slot = 1; slot <= 4; slot++, pt++) {
|
||||
if (pt->sys_ind == LINUX_SWAP_PARTITION ||
|
||||
pt->sys_ind == LINUX_RAID_PARTITION ||
|
||||
pt->sys_ind == LINUX_DATA_PARTITION ||
|
||||
pt->sys_ind == LINUX_LVM_PARTITION ||
|
||||
is_extended_partition(pt))
|
||||
return 0;
|
||||
}
|
||||
d = read_part_sector(state, 7, §);
|
||||
if (d) {
|
||||
if (d[0] == '_' && d[1] == 'L' && d[2] == 'V' && d[3] == 'M')
|
||||
ret = 1;
|
||||
put_dev_sector(sect);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void set_info(struct parsed_partitions *state, int slot,
|
||||
u32 disksig)
|
||||
{
|
||||
struct partition_meta_info *info = &state->parts[slot].info;
|
||||
|
||||
snprintf(info->uuid, sizeof(info->uuid), "%08x-%02x", disksig,
|
||||
slot);
|
||||
info->volname[0] = 0;
|
||||
state->parts[slot].has_info = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create devices for each logical partition in an extended partition.
|
||||
* The logical partitions form a linked list, with each entry being
|
||||
* a partition table with two entries. The first entry
|
||||
* is the real data partition (with a start relative to the partition
|
||||
* table start). The second is a pointer to the next logical partition
|
||||
* (with a start relative to the entire extended partition).
|
||||
* We do not create a Linux partition for the partition tables, but
|
||||
* only for the actual data partitions.
|
||||
*/
|
||||
|
||||
static void parse_extended(struct parsed_partitions *state,
|
||||
sector_t first_sector, sector_t first_size,
|
||||
u32 disksig)
|
||||
{
|
||||
struct partition *p;
|
||||
Sector sect;
|
||||
unsigned char *data;
|
||||
sector_t this_sector, this_size;
|
||||
sector_t sector_size = bdev_logical_block_size(state->bdev) / 512;
|
||||
int loopct = 0; /* number of links followed
|
||||
without finding a data partition */
|
||||
int i;
|
||||
|
||||
this_sector = first_sector;
|
||||
this_size = first_size;
|
||||
|
||||
while (1) {
|
||||
if (++loopct > 100)
|
||||
return;
|
||||
if (state->next == state->limit)
|
||||
return;
|
||||
data = read_part_sector(state, this_sector, §);
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
if (!msdos_magic_present(data + 510))
|
||||
goto done;
|
||||
|
||||
p = (struct partition *) (data + 0x1be);
|
||||
|
||||
/*
|
||||
* Usually, the first entry is the real data partition,
|
||||
* the 2nd entry is the next extended partition, or empty,
|
||||
* and the 3rd and 4th entries are unused.
|
||||
* However, DRDOS sometimes has the extended partition as
|
||||
* the first entry (when the data partition is empty),
|
||||
* and OS/2 seems to use all four entries.
|
||||
*/
|
||||
|
||||
/*
|
||||
* First process the data partition(s)
|
||||
*/
|
||||
for (i = 0; i < 4; i++, p++) {
|
||||
sector_t offs, size, next;
|
||||
|
||||
if (!nr_sects(p) || is_extended_partition(p))
|
||||
continue;
|
||||
|
||||
/* Check the 3rd and 4th entries -
|
||||
these sometimes contain random garbage */
|
||||
offs = start_sect(p)*sector_size;
|
||||
size = nr_sects(p)*sector_size;
|
||||
next = this_sector + offs;
|
||||
if (i >= 2) {
|
||||
if (offs + size > this_size)
|
||||
continue;
|
||||
if (next < first_sector)
|
||||
continue;
|
||||
if (next + size > first_sector + first_size)
|
||||
continue;
|
||||
}
|
||||
|
||||
put_partition(state, state->next, next, size);
|
||||
set_info(state, state->next, disksig);
|
||||
if (SYS_IND(p) == LINUX_RAID_PARTITION)
|
||||
state->parts[state->next].flags = ADDPART_FLAG_RAID;
|
||||
loopct = 0;
|
||||
if (++state->next == state->limit)
|
||||
goto done;
|
||||
}
|
||||
/*
|
||||
* Next, process the (first) extended partition, if present.
|
||||
* (So far, there seems to be no reason to make
|
||||
* parse_extended() recursive and allow a tree
|
||||
* of extended partitions.)
|
||||
* It should be a link to the next logical partition.
|
||||
*/
|
||||
p -= 4;
|
||||
for (i = 0; i < 4; i++, p++)
|
||||
if (nr_sects(p) && is_extended_partition(p))
|
||||
break;
|
||||
if (i == 4)
|
||||
goto done; /* nothing left to do */
|
||||
|
||||
this_sector = first_sector + start_sect(p) * sector_size;
|
||||
this_size = nr_sects(p) * sector_size;
|
||||
put_dev_sector(sect);
|
||||
}
|
||||
done:
|
||||
put_dev_sector(sect);
|
||||
}
|
||||
|
||||
/* james@bpgc.com: Solaris has a nasty indicator: 0x82 which also
|
||||
indicates linux swap. Be careful before believing this is Solaris. */
|
||||
|
||||
static void parse_solaris_x86(struct parsed_partitions *state,
|
||||
sector_t offset, sector_t size, int origin)
|
||||
{
|
||||
#ifdef CONFIG_SOLARIS_X86_PARTITION
|
||||
Sector sect;
|
||||
struct solaris_x86_vtoc *v;
|
||||
int i;
|
||||
short max_nparts;
|
||||
|
||||
v = read_part_sector(state, offset + 1, §);
|
||||
if (!v)
|
||||
return;
|
||||
if (le32_to_cpu(v->v_sanity) != SOLARIS_X86_VTOC_SANE) {
|
||||
put_dev_sector(sect);
|
||||
return;
|
||||
}
|
||||
{
|
||||
char tmp[1 + BDEVNAME_SIZE + 10 + 11 + 1];
|
||||
|
||||
snprintf(tmp, sizeof(tmp), " %s%d: <solaris:", state->name, origin);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
}
|
||||
if (le32_to_cpu(v->v_version) != 1) {
|
||||
char tmp[64];
|
||||
|
||||
snprintf(tmp, sizeof(tmp), " cannot handle version %d vtoc>\n",
|
||||
le32_to_cpu(v->v_version));
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
put_dev_sector(sect);
|
||||
return;
|
||||
}
|
||||
/* Ensure we can handle previous case of VTOC with 8 entries gracefully */
|
||||
max_nparts = le16_to_cpu(v->v_nparts) > 8 ? SOLARIS_X86_NUMSLICE : 8;
|
||||
for (i = 0; i < max_nparts && state->next < state->limit; i++) {
|
||||
struct solaris_x86_slice *s = &v->v_slice[i];
|
||||
char tmp[3 + 10 + 1 + 1];
|
||||
|
||||
if (s->s_size == 0)
|
||||
continue;
|
||||
snprintf(tmp, sizeof(tmp), " [s%d]", i);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
/* solaris partitions are relative to current MS-DOS
|
||||
* one; must add the offset of the current partition */
|
||||
put_partition(state, state->next++,
|
||||
le32_to_cpu(s->s_start)+offset,
|
||||
le32_to_cpu(s->s_size));
|
||||
}
|
||||
put_dev_sector(sect);
|
||||
strlcat(state->pp_buf, " >\n", PAGE_SIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BSD_DISKLABEL)
|
||||
/*
|
||||
* Create devices for BSD partitions listed in a disklabel, under a
|
||||
* dos-like partition. See parse_extended() for more information.
|
||||
*/
|
||||
static void parse_bsd(struct parsed_partitions *state,
|
||||
sector_t offset, sector_t size, int origin, char *flavour,
|
||||
int max_partitions)
|
||||
{
|
||||
Sector sect;
|
||||
struct bsd_disklabel *l;
|
||||
struct bsd_partition *p;
|
||||
char tmp[64];
|
||||
|
||||
l = read_part_sector(state, offset + 1, §);
|
||||
if (!l)
|
||||
return;
|
||||
if (le32_to_cpu(l->d_magic) != BSD_DISKMAGIC) {
|
||||
put_dev_sector(sect);
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(tmp, sizeof(tmp), " %s%d: <%s:", state->name, origin, flavour);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
|
||||
if (le16_to_cpu(l->d_npartitions) < max_partitions)
|
||||
max_partitions = le16_to_cpu(l->d_npartitions);
|
||||
for (p = l->d_partitions; p - l->d_partitions < max_partitions; p++) {
|
||||
sector_t bsd_start, bsd_size;
|
||||
|
||||
if (state->next == state->limit)
|
||||
break;
|
||||
if (p->p_fstype == BSD_FS_UNUSED)
|
||||
continue;
|
||||
bsd_start = le32_to_cpu(p->p_offset);
|
||||
bsd_size = le32_to_cpu(p->p_size);
|
||||
if (offset == bsd_start && size == bsd_size)
|
||||
/* full parent partition, we have it already */
|
||||
continue;
|
||||
if (offset > bsd_start || offset+size < bsd_start+bsd_size) {
|
||||
strlcat(state->pp_buf, "bad subpartition - ignored\n", PAGE_SIZE);
|
||||
continue;
|
||||
}
|
||||
put_partition(state, state->next++, bsd_start, bsd_size);
|
||||
}
|
||||
put_dev_sector(sect);
|
||||
if (le16_to_cpu(l->d_npartitions) > max_partitions) {
|
||||
snprintf(tmp, sizeof(tmp), " (ignored %d more)",
|
||||
le16_to_cpu(l->d_npartitions) - max_partitions);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
}
|
||||
strlcat(state->pp_buf, " >\n", PAGE_SIZE);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void parse_freebsd(struct parsed_partitions *state,
|
||||
sector_t offset, sector_t size, int origin)
|
||||
{
|
||||
#ifdef CONFIG_BSD_DISKLABEL
|
||||
parse_bsd(state, offset, size, origin, "bsd", BSD_MAXPARTITIONS);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void parse_netbsd(struct parsed_partitions *state,
|
||||
sector_t offset, sector_t size, int origin)
|
||||
{
|
||||
#ifdef CONFIG_BSD_DISKLABEL
|
||||
parse_bsd(state, offset, size, origin, "netbsd", BSD_MAXPARTITIONS);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void parse_openbsd(struct parsed_partitions *state,
|
||||
sector_t offset, sector_t size, int origin)
|
||||
{
|
||||
#ifdef CONFIG_BSD_DISKLABEL
|
||||
parse_bsd(state, offset, size, origin, "openbsd",
|
||||
OPENBSD_MAXPARTITIONS);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Create devices for Unixware partitions listed in a disklabel, under a
|
||||
* dos-like partition. See parse_extended() for more information.
|
||||
*/
|
||||
static void parse_unixware(struct parsed_partitions *state,
|
||||
sector_t offset, sector_t size, int origin)
|
||||
{
|
||||
#ifdef CONFIG_UNIXWARE_DISKLABEL
|
||||
Sector sect;
|
||||
struct unixware_disklabel *l;
|
||||
struct unixware_slice *p;
|
||||
|
||||
l = read_part_sector(state, offset + 29, §);
|
||||
if (!l)
|
||||
return;
|
||||
if (le32_to_cpu(l->d_magic) != UNIXWARE_DISKMAGIC ||
|
||||
le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_DISKMAGIC2) {
|
||||
put_dev_sector(sect);
|
||||
return;
|
||||
}
|
||||
{
|
||||
char tmp[1 + BDEVNAME_SIZE + 10 + 12 + 1];
|
||||
|
||||
snprintf(tmp, sizeof(tmp), " %s%d: <unixware:", state->name, origin);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
}
|
||||
p = &l->vtoc.v_slice[1];
|
||||
/* I omit the 0th slice as it is the same as whole disk. */
|
||||
while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) {
|
||||
if (state->next == state->limit)
|
||||
break;
|
||||
|
||||
if (p->s_label != UNIXWARE_FS_UNUSED)
|
||||
put_partition(state, state->next++,
|
||||
le32_to_cpu(p->start_sect),
|
||||
le32_to_cpu(p->nr_sects));
|
||||
p++;
|
||||
}
|
||||
put_dev_sector(sect);
|
||||
strlcat(state->pp_buf, " >\n", PAGE_SIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Minix 2.0.0/2.0.2 subpartition support.
|
||||
* Anand Krishnamurthy <anandk@wiproge.med.ge.com>
|
||||
* Rajeev V. Pillai <rajeevvp@yahoo.com>
|
||||
*/
|
||||
static void parse_minix(struct parsed_partitions *state,
|
||||
sector_t offset, sector_t size, int origin)
|
||||
{
|
||||
#ifdef CONFIG_MINIX_SUBPARTITION
|
||||
Sector sect;
|
||||
unsigned char *data;
|
||||
struct partition *p;
|
||||
int i;
|
||||
|
||||
data = read_part_sector(state, offset, §);
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
p = (struct partition *)(data + 0x1be);
|
||||
|
||||
/* The first sector of a Minix partition can have either
|
||||
* a secondary MBR describing its subpartitions, or
|
||||
* the normal boot sector. */
|
||||
if (msdos_magic_present(data + 510) &&
|
||||
SYS_IND(p) == MINIX_PARTITION) { /* subpartition table present */
|
||||
char tmp[1 + BDEVNAME_SIZE + 10 + 9 + 1];
|
||||
|
||||
snprintf(tmp, sizeof(tmp), " %s%d: <minix:", state->name, origin);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
for (i = 0; i < MINIX_NR_SUBPARTITIONS; i++, p++) {
|
||||
if (state->next == state->limit)
|
||||
break;
|
||||
/* add each partition in use */
|
||||
if (SYS_IND(p) == MINIX_PARTITION)
|
||||
put_partition(state, state->next++,
|
||||
start_sect(p), nr_sects(p));
|
||||
}
|
||||
strlcat(state->pp_buf, " >\n", PAGE_SIZE);
|
||||
}
|
||||
put_dev_sector(sect);
|
||||
#endif /* CONFIG_MINIX_SUBPARTITION */
|
||||
}
|
||||
|
||||
static struct {
|
||||
unsigned char id;
|
||||
void (*parse)(struct parsed_partitions *, sector_t, sector_t, int);
|
||||
} subtypes[] = {
|
||||
{FREEBSD_PARTITION, parse_freebsd},
|
||||
{NETBSD_PARTITION, parse_netbsd},
|
||||
{OPENBSD_PARTITION, parse_openbsd},
|
||||
{MINIX_PARTITION, parse_minix},
|
||||
{UNIXWARE_PARTITION, parse_unixware},
|
||||
{SOLARIS_X86_PARTITION, parse_solaris_x86},
|
||||
{NEW_SOLARIS_X86_PARTITION, parse_solaris_x86},
|
||||
{0, NULL},
|
||||
};
|
||||
|
||||
int msdos_partition(struct parsed_partitions *state)
|
||||
{
|
||||
sector_t sector_size = bdev_logical_block_size(state->bdev) / 512;
|
||||
Sector sect;
|
||||
unsigned char *data;
|
||||
struct partition *p;
|
||||
struct fat_boot_sector *fb;
|
||||
int slot;
|
||||
u32 disksig;
|
||||
|
||||
data = read_part_sector(state, 0, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Note order! (some AIX disks, e.g. unbootable kind,
|
||||
* have no MSDOS 55aa)
|
||||
*/
|
||||
if (aix_magic_present(state, data)) {
|
||||
put_dev_sector(sect);
|
||||
#ifdef CONFIG_AIX_PARTITION
|
||||
return aix_partition(state);
|
||||
#else
|
||||
strlcat(state->pp_buf, " [AIX]", PAGE_SIZE);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!msdos_magic_present(data + 510)) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now that the 55aa signature is present, this is probably
|
||||
* either the boot sector of a FAT filesystem or a DOS-type
|
||||
* partition table. Reject this in case the boot indicator
|
||||
* is not 0 or 0x80.
|
||||
*/
|
||||
p = (struct partition *) (data + 0x1be);
|
||||
for (slot = 1; slot <= 4; slot++, p++) {
|
||||
if (p->boot_ind != 0 && p->boot_ind != 0x80) {
|
||||
/*
|
||||
* Even without a valid boot inidicator value
|
||||
* its still possible this is valid FAT filesystem
|
||||
* without a partition table.
|
||||
*/
|
||||
fb = (struct fat_boot_sector *) data;
|
||||
if (slot == 1 && fb->reserved && fb->fats
|
||||
&& fat_valid_media(fb->media)) {
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
put_dev_sector(sect);
|
||||
return 1;
|
||||
} else {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EFI_PARTITION
|
||||
p = (struct partition *) (data + 0x1be);
|
||||
for (slot = 1 ; slot <= 4 ; slot++, p++) {
|
||||
/* If this is an EFI GPT disk, msdos should ignore it. */
|
||||
if (SYS_IND(p) == EFI_PMBR_OSTYPE_EFI_GPT) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
p = (struct partition *) (data + 0x1be);
|
||||
|
||||
disksig = le32_to_cpup((__le32 *)(data + 0x1b8));
|
||||
|
||||
/*
|
||||
* Look for partitions in two passes:
|
||||
* First find the primary and DOS-type extended partitions.
|
||||
* On the second pass look inside *BSD, Unixware and Solaris partitions.
|
||||
*/
|
||||
|
||||
state->next = 5;
|
||||
for (slot = 1 ; slot <= 4 ; slot++, p++) {
|
||||
sector_t start = start_sect(p)*sector_size;
|
||||
sector_t size = nr_sects(p)*sector_size;
|
||||
|
||||
if (!size)
|
||||
continue;
|
||||
if (is_extended_partition(p)) {
|
||||
/*
|
||||
* prevent someone doing mkfs or mkswap on an
|
||||
* extended partition, but leave room for LILO
|
||||
* FIXME: this uses one logical sector for > 512b
|
||||
* sector, although it may not be enough/proper.
|
||||
*/
|
||||
sector_t n = 2;
|
||||
|
||||
n = min(size, max(sector_size, n));
|
||||
put_partition(state, slot, start, n);
|
||||
|
||||
strlcat(state->pp_buf, " <", PAGE_SIZE);
|
||||
parse_extended(state, start, size, disksig);
|
||||
strlcat(state->pp_buf, " >", PAGE_SIZE);
|
||||
continue;
|
||||
}
|
||||
put_partition(state, slot, start, size);
|
||||
set_info(state, slot, disksig);
|
||||
if (SYS_IND(p) == LINUX_RAID_PARTITION)
|
||||
state->parts[slot].flags = ADDPART_FLAG_RAID;
|
||||
if (SYS_IND(p) == DM6_PARTITION)
|
||||
strlcat(state->pp_buf, "[DM]", PAGE_SIZE);
|
||||
if (SYS_IND(p) == EZD_PARTITION)
|
||||
strlcat(state->pp_buf, "[EZD]", PAGE_SIZE);
|
||||
}
|
||||
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
|
||||
/* second pass - output for each on a separate line */
|
||||
p = (struct partition *) (0x1be + data);
|
||||
for (slot = 1 ; slot <= 4 ; slot++, p++) {
|
||||
unsigned char id = SYS_IND(p);
|
||||
int n;
|
||||
|
||||
if (!nr_sects(p))
|
||||
continue;
|
||||
|
||||
for (n = 0; subtypes[n].parse && id != subtypes[n].id; n++)
|
||||
;
|
||||
|
||||
if (!subtypes[n].parse)
|
||||
continue;
|
||||
subtypes[n].parse(state, start_sect(p) * sector_size,
|
||||
nr_sects(p) * sector_size, slot);
|
||||
}
|
||||
put_dev_sector(sect);
|
||||
return 1;
|
||||
}
|
8
block/partitions/msdos.h
Normal file
8
block/partitions/msdos.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* fs/partitions/msdos.h
|
||||
*/
|
||||
|
||||
#define MSDOS_LABEL_MAGIC 0xAA55
|
||||
|
||||
int msdos_partition(struct parsed_partitions *state);
|
||||
|
86
block/partitions/osf.c
Normal file
86
block/partitions/osf.c
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* fs/partitions/osf.c
|
||||
*
|
||||
* Code extracted from drivers/block/genhd.c
|
||||
*
|
||||
* Copyright (C) 1991-1998 Linus Torvalds
|
||||
* Re-organised Feb 1998 Russell King
|
||||
*/
|
||||
|
||||
#include "check.h"
|
||||
#include "osf.h"
|
||||
|
||||
#define MAX_OSF_PARTITIONS 18
|
||||
|
||||
int osf_partition(struct parsed_partitions *state)
|
||||
{
|
||||
int i;
|
||||
int slot = 1;
|
||||
unsigned int npartitions;
|
||||
Sector sect;
|
||||
unsigned char *data;
|
||||
struct disklabel {
|
||||
__le32 d_magic;
|
||||
__le16 d_type,d_subtype;
|
||||
u8 d_typename[16];
|
||||
u8 d_packname[16];
|
||||
__le32 d_secsize;
|
||||
__le32 d_nsectors;
|
||||
__le32 d_ntracks;
|
||||
__le32 d_ncylinders;
|
||||
__le32 d_secpercyl;
|
||||
__le32 d_secprtunit;
|
||||
__le16 d_sparespertrack;
|
||||
__le16 d_sparespercyl;
|
||||
__le32 d_acylinders;
|
||||
__le16 d_rpm, d_interleave, d_trackskew, d_cylskew;
|
||||
__le32 d_headswitch, d_trkseek, d_flags;
|
||||
__le32 d_drivedata[5];
|
||||
__le32 d_spare[5];
|
||||
__le32 d_magic2;
|
||||
__le16 d_checksum;
|
||||
__le16 d_npartitions;
|
||||
__le32 d_bbsize, d_sbsize;
|
||||
struct d_partition {
|
||||
__le32 p_size;
|
||||
__le32 p_offset;
|
||||
__le32 p_fsize;
|
||||
u8 p_fstype;
|
||||
u8 p_frag;
|
||||
__le16 p_cpg;
|
||||
} d_partitions[MAX_OSF_PARTITIONS];
|
||||
} * label;
|
||||
struct d_partition * partition;
|
||||
|
||||
data = read_part_sector(state, 0, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
label = (struct disklabel *) (data+64);
|
||||
partition = label->d_partitions;
|
||||
if (le32_to_cpu(label->d_magic) != DISKLABELMAGIC) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
if (le32_to_cpu(label->d_magic2) != DISKLABELMAGIC) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
npartitions = le16_to_cpu(label->d_npartitions);
|
||||
if (npartitions > MAX_OSF_PARTITIONS) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
for (i = 0 ; i < npartitions; i++, partition++) {
|
||||
if (slot == state->limit)
|
||||
break;
|
||||
if (le32_to_cpu(partition->p_size))
|
||||
put_partition(state, slot,
|
||||
le32_to_cpu(partition->p_offset),
|
||||
le32_to_cpu(partition->p_size));
|
||||
slot++;
|
||||
}
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
put_dev_sector(sect);
|
||||
return 1;
|
||||
}
|
7
block/partitions/osf.h
Normal file
7
block/partitions/osf.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* fs/partitions/osf.h
|
||||
*/
|
||||
|
||||
#define DISKLABELMAGIC (0x82564557UL)
|
||||
|
||||
int osf_partition(struct parsed_partitions *state);
|
82
block/partitions/sgi.c
Normal file
82
block/partitions/sgi.c
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* fs/partitions/sgi.c
|
||||
*
|
||||
* Code extracted from drivers/block/genhd.c
|
||||
*/
|
||||
|
||||
#include "check.h"
|
||||
#include "sgi.h"
|
||||
|
||||
struct sgi_disklabel {
|
||||
__be32 magic_mushroom; /* Big fat spliff... */
|
||||
__be16 root_part_num; /* Root partition number */
|
||||
__be16 swap_part_num; /* Swap partition number */
|
||||
s8 boot_file[16]; /* Name of boot file for ARCS */
|
||||
u8 _unused0[48]; /* Device parameter useless crapola.. */
|
||||
struct sgi_volume {
|
||||
s8 name[8]; /* Name of volume */
|
||||
__be32 block_num; /* Logical block number */
|
||||
__be32 num_bytes; /* How big, in bytes */
|
||||
} volume[15];
|
||||
struct sgi_partition {
|
||||
__be32 num_blocks; /* Size in logical blocks */
|
||||
__be32 first_block; /* First logical block */
|
||||
__be32 type; /* Type of this partition */
|
||||
} partitions[16];
|
||||
__be32 csum; /* Disk label checksum */
|
||||
__be32 _unused1; /* Padding */
|
||||
};
|
||||
|
||||
int sgi_partition(struct parsed_partitions *state)
|
||||
{
|
||||
int i, csum;
|
||||
__be32 magic;
|
||||
int slot = 1;
|
||||
unsigned int start, blocks;
|
||||
__be32 *ui, cs;
|
||||
Sector sect;
|
||||
struct sgi_disklabel *label;
|
||||
struct sgi_partition *p;
|
||||
char b[BDEVNAME_SIZE];
|
||||
|
||||
label = read_part_sector(state, 0, §);
|
||||
if (!label)
|
||||
return -1;
|
||||
p = &label->partitions[0];
|
||||
magic = label->magic_mushroom;
|
||||
if(be32_to_cpu(magic) != SGI_LABEL_MAGIC) {
|
||||
/*printk("Dev %s SGI disklabel: bad magic %08x\n",
|
||||
bdevname(bdev, b), be32_to_cpu(magic));*/
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
ui = ((__be32 *) (label + 1)) - 1;
|
||||
for(csum = 0; ui >= ((__be32 *) label);) {
|
||||
cs = *ui--;
|
||||
csum += be32_to_cpu(cs);
|
||||
}
|
||||
if(csum) {
|
||||
printk(KERN_WARNING "Dev %s SGI disklabel: csum bad, label corrupted\n",
|
||||
bdevname(state->bdev, b));
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
/* All SGI disk labels have 16 partitions, disks under Linux only
|
||||
* have 15 minor's. Luckily there are always a few zero length
|
||||
* partitions which we don't care about so we never overflow the
|
||||
* current_minor.
|
||||
*/
|
||||
for(i = 0; i < 16; i++, p++) {
|
||||
blocks = be32_to_cpu(p->num_blocks);
|
||||
start = be32_to_cpu(p->first_block);
|
||||
if (blocks) {
|
||||
put_partition(state, slot, start, blocks);
|
||||
if (be32_to_cpu(p->type) == LINUX_RAID_PARTITION)
|
||||
state->parts[slot].flags = ADDPART_FLAG_RAID;
|
||||
}
|
||||
slot++;
|
||||
}
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
put_dev_sector(sect);
|
||||
return 1;
|
||||
}
|
8
block/partitions/sgi.h
Normal file
8
block/partitions/sgi.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* fs/partitions/sgi.h
|
||||
*/
|
||||
|
||||
extern int sgi_partition(struct parsed_partitions *state);
|
||||
|
||||
#define SGI_LABEL_MAGIC 0x0be5a941
|
||||
|
122
block/partitions/sun.c
Normal file
122
block/partitions/sun.c
Normal file
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* fs/partitions/sun.c
|
||||
*
|
||||
* Code extracted from drivers/block/genhd.c
|
||||
*
|
||||
* Copyright (C) 1991-1998 Linus Torvalds
|
||||
* Re-organised Feb 1998 Russell King
|
||||
*/
|
||||
|
||||
#include "check.h"
|
||||
#include "sun.h"
|
||||
|
||||
int sun_partition(struct parsed_partitions *state)
|
||||
{
|
||||
int i;
|
||||
__be16 csum;
|
||||
int slot = 1;
|
||||
__be16 *ush;
|
||||
Sector sect;
|
||||
struct sun_disklabel {
|
||||
unsigned char info[128]; /* Informative text string */
|
||||
struct sun_vtoc {
|
||||
__be32 version; /* Layout version */
|
||||
char volume[8]; /* Volume name */
|
||||
__be16 nparts; /* Number of partitions */
|
||||
struct sun_info { /* Partition hdrs, sec 2 */
|
||||
__be16 id;
|
||||
__be16 flags;
|
||||
} infos[8];
|
||||
__be16 padding; /* Alignment padding */
|
||||
__be32 bootinfo[3]; /* Info needed by mboot */
|
||||
__be32 sanity; /* To verify vtoc sanity */
|
||||
__be32 reserved[10]; /* Free space */
|
||||
__be32 timestamp[8]; /* Partition timestamp */
|
||||
} vtoc;
|
||||
__be32 write_reinstruct; /* sectors to skip, writes */
|
||||
__be32 read_reinstruct; /* sectors to skip, reads */
|
||||
unsigned char spare[148]; /* Padding */
|
||||
__be16 rspeed; /* Disk rotational speed */
|
||||
__be16 pcylcount; /* Physical cylinder count */
|
||||
__be16 sparecyl; /* extra sects per cylinder */
|
||||
__be16 obs1; /* gap1 */
|
||||
__be16 obs2; /* gap2 */
|
||||
__be16 ilfact; /* Interleave factor */
|
||||
__be16 ncyl; /* Data cylinder count */
|
||||
__be16 nacyl; /* Alt. cylinder count */
|
||||
__be16 ntrks; /* Tracks per cylinder */
|
||||
__be16 nsect; /* Sectors per track */
|
||||
__be16 obs3; /* bhead - Label head offset */
|
||||
__be16 obs4; /* ppart - Physical Partition */
|
||||
struct sun_partition {
|
||||
__be32 start_cylinder;
|
||||
__be32 num_sectors;
|
||||
} partitions[8];
|
||||
__be16 magic; /* Magic number */
|
||||
__be16 csum; /* Label xor'd checksum */
|
||||
} * label;
|
||||
struct sun_partition *p;
|
||||
unsigned long spc;
|
||||
char b[BDEVNAME_SIZE];
|
||||
int use_vtoc;
|
||||
int nparts;
|
||||
|
||||
label = read_part_sector(state, 0, §);
|
||||
if (!label)
|
||||
return -1;
|
||||
|
||||
p = label->partitions;
|
||||
if (be16_to_cpu(label->magic) != SUN_LABEL_MAGIC) {
|
||||
/* printk(KERN_INFO "Dev %s Sun disklabel: bad magic %04x\n",
|
||||
bdevname(bdev, b), be16_to_cpu(label->magic)); */
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
/* Look at the checksum */
|
||||
ush = ((__be16 *) (label+1)) - 1;
|
||||
for (csum = 0; ush >= ((__be16 *) label);)
|
||||
csum ^= *ush--;
|
||||
if (csum) {
|
||||
printk("Dev %s Sun disklabel: Csum bad, label corrupted\n",
|
||||
bdevname(state->bdev, b));
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check to see if we can use the VTOC table */
|
||||
use_vtoc = ((be32_to_cpu(label->vtoc.sanity) == SUN_VTOC_SANITY) &&
|
||||
(be32_to_cpu(label->vtoc.version) == 1) &&
|
||||
(be16_to_cpu(label->vtoc.nparts) <= 8));
|
||||
|
||||
/* Use 8 partition entries if not specified in validated VTOC */
|
||||
nparts = (use_vtoc) ? be16_to_cpu(label->vtoc.nparts) : 8;
|
||||
|
||||
/*
|
||||
* So that old Linux-Sun partitions continue to work,
|
||||
* alow the VTOC to be used under the additional condition ...
|
||||
*/
|
||||
use_vtoc = use_vtoc || !(label->vtoc.sanity ||
|
||||
label->vtoc.version || label->vtoc.nparts);
|
||||
spc = be16_to_cpu(label->ntrks) * be16_to_cpu(label->nsect);
|
||||
for (i = 0; i < nparts; i++, p++) {
|
||||
unsigned long st_sector;
|
||||
unsigned int num_sectors;
|
||||
|
||||
st_sector = be32_to_cpu(p->start_cylinder) * spc;
|
||||
num_sectors = be32_to_cpu(p->num_sectors);
|
||||
if (num_sectors) {
|
||||
put_partition(state, slot, st_sector, num_sectors);
|
||||
state->parts[slot].flags = 0;
|
||||
if (use_vtoc) {
|
||||
if (be16_to_cpu(label->vtoc.infos[i].id) == LINUX_RAID_PARTITION)
|
||||
state->parts[slot].flags |= ADDPART_FLAG_RAID;
|
||||
else if (be16_to_cpu(label->vtoc.infos[i].id) == SUN_WHOLE_DISK)
|
||||
state->parts[slot].flags |= ADDPART_FLAG_WHOLEDISK;
|
||||
}
|
||||
}
|
||||
slot++;
|
||||
}
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
put_dev_sector(sect);
|
||||
return 1;
|
||||
}
|
8
block/partitions/sun.h
Normal file
8
block/partitions/sun.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* fs/partitions/sun.h
|
||||
*/
|
||||
|
||||
#define SUN_LABEL_MAGIC 0xDABE
|
||||
#define SUN_VTOC_SANITY 0x600DDEEE
|
||||
|
||||
int sun_partition(struct parsed_partitions *state);
|
95
block/partitions/sysv68.c
Normal file
95
block/partitions/sysv68.c
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* fs/partitions/sysv68.c
|
||||
*
|
||||
* Copyright (C) 2007 Philippe De Muyter <phdm@macqel.be>
|
||||
*/
|
||||
|
||||
#include "check.h"
|
||||
#include "sysv68.h"
|
||||
|
||||
/*
|
||||
* Volume ID structure: on first 256-bytes sector of disk
|
||||
*/
|
||||
|
||||
struct volumeid {
|
||||
u8 vid_unused[248];
|
||||
u8 vid_mac[8]; /* ASCII string "MOTOROLA" */
|
||||
};
|
||||
|
||||
/*
|
||||
* config block: second 256-bytes sector on disk
|
||||
*/
|
||||
|
||||
struct dkconfig {
|
||||
u8 ios_unused0[128];
|
||||
__be32 ios_slcblk; /* Slice table block number */
|
||||
__be16 ios_slccnt; /* Number of entries in slice table */
|
||||
u8 ios_unused1[122];
|
||||
};
|
||||
|
||||
/*
|
||||
* combined volumeid and dkconfig block
|
||||
*/
|
||||
|
||||
struct dkblk0 {
|
||||
struct volumeid dk_vid;
|
||||
struct dkconfig dk_ios;
|
||||
};
|
||||
|
||||
/*
|
||||
* Slice Table Structure
|
||||
*/
|
||||
|
||||
struct slice {
|
||||
__be32 nblocks; /* slice size (in blocks) */
|
||||
__be32 blkoff; /* block offset of slice */
|
||||
};
|
||||
|
||||
|
||||
int sysv68_partition(struct parsed_partitions *state)
|
||||
{
|
||||
int i, slices;
|
||||
int slot = 1;
|
||||
Sector sect;
|
||||
unsigned char *data;
|
||||
struct dkblk0 *b;
|
||||
struct slice *slice;
|
||||
char tmp[64];
|
||||
|
||||
data = read_part_sector(state, 0, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
b = (struct dkblk0 *)data;
|
||||
if (memcmp(b->dk_vid.vid_mac, "MOTOROLA", sizeof(b->dk_vid.vid_mac))) {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
slices = be16_to_cpu(b->dk_ios.ios_slccnt);
|
||||
i = be32_to_cpu(b->dk_ios.ios_slcblk);
|
||||
put_dev_sector(sect);
|
||||
|
||||
data = read_part_sector(state, i, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
slices -= 1; /* last slice is the whole disk */
|
||||
snprintf(tmp, sizeof(tmp), "sysV68: %s(s%u)", state->name, slices);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
slice = (struct slice *)data;
|
||||
for (i = 0; i < slices; i++, slice++) {
|
||||
if (slot == state->limit)
|
||||
break;
|
||||
if (be32_to_cpu(slice->nblocks)) {
|
||||
put_partition(state, slot,
|
||||
be32_to_cpu(slice->blkoff),
|
||||
be32_to_cpu(slice->nblocks));
|
||||
snprintf(tmp, sizeof(tmp), "(s%u)", i);
|
||||
strlcat(state->pp_buf, tmp, PAGE_SIZE);
|
||||
}
|
||||
slot++;
|
||||
}
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
put_dev_sector(sect);
|
||||
return 1;
|
||||
}
|
1
block/partitions/sysv68.h
Normal file
1
block/partitions/sysv68.h
Normal file
|
@ -0,0 +1 @@
|
|||
extern int sysv68_partition(struct parsed_partitions *state);
|
48
block/partitions/ultrix.c
Normal file
48
block/partitions/ultrix.c
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* fs/partitions/ultrix.c
|
||||
*
|
||||
* Code extracted from drivers/block/genhd.c
|
||||
*
|
||||
* Re-organised Jul 1999 Russell King
|
||||
*/
|
||||
|
||||
#include "check.h"
|
||||
#include "ultrix.h"
|
||||
|
||||
int ultrix_partition(struct parsed_partitions *state)
|
||||
{
|
||||
int i;
|
||||
Sector sect;
|
||||
unsigned char *data;
|
||||
struct ultrix_disklabel {
|
||||
s32 pt_magic; /* magic no. indicating part. info exits */
|
||||
s32 pt_valid; /* set by driver if pt is current */
|
||||
struct pt_info {
|
||||
s32 pi_nblocks; /* no. of sectors */
|
||||
u32 pi_blkoff; /* block offset for start */
|
||||
} pt_part[8];
|
||||
} *label;
|
||||
|
||||
#define PT_MAGIC 0x032957 /* Partition magic number */
|
||||
#define PT_VALID 1 /* Indicates if struct is valid */
|
||||
|
||||
data = read_part_sector(state, (16384 - sizeof(*label))/512, §);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
label = (struct ultrix_disklabel *)(data + 512 - sizeof(*label));
|
||||
|
||||
if (label->pt_magic == PT_MAGIC && label->pt_valid == PT_VALID) {
|
||||
for (i=0; i<8; i++)
|
||||
if (label->pt_part[i].pi_nblocks)
|
||||
put_partition(state, i+1,
|
||||
label->pt_part[i].pi_blkoff,
|
||||
label->pt_part[i].pi_nblocks);
|
||||
put_dev_sector(sect);
|
||||
strlcat(state->pp_buf, "\n", PAGE_SIZE);
|
||||
return 1;
|
||||
} else {
|
||||
put_dev_sector(sect);
|
||||
return 0;
|
||||
}
|
||||
}
|
5
block/partitions/ultrix.h
Normal file
5
block/partitions/ultrix.h
Normal file
|
@ -0,0 +1,5 @@
|
|||
/*
|
||||
* fs/partitions/ultrix.h
|
||||
*/
|
||||
|
||||
int ultrix_partition(struct parsed_partitions *state);
|
Loading…
Add table
Add a link
Reference in a new issue