summaryrefslogtreecommitdiffstats
path: root/libblkid/src/partitions
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 14:30:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 14:30:35 +0000
commit378c18e5f024ac5a8aef4cb40d7c9aa9633d144c (patch)
tree44dfb6ca500d32cabd450649b322a42e70a30683 /libblkid/src/partitions
parentInitial commit. (diff)
downloadutil-linux-upstream.tar.xz
util-linux-upstream.zip
Adding upstream version 2.38.1.upstream/2.38.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'libblkid/src/partitions')
-rw-r--r--libblkid/src/partitions/aix.c57
-rw-r--r--libblkid/src/partitions/aix.h7
-rw-r--r--libblkid/src/partitions/atari.c312
-rw-r--r--libblkid/src/partitions/bsd.c188
-rw-r--r--libblkid/src/partitions/dos.c373
-rw-r--r--libblkid/src/partitions/gpt.c473
-rw-r--r--libblkid/src/partitions/mac.c200
-rw-r--r--libblkid/src/partitions/minix.c102
-rw-r--r--libblkid/src/partitions/partitions.c1526
-rw-r--r--libblkid/src/partitions/partitions.h74
-rw-r--r--libblkid/src/partitions/sgi.c87
-rw-r--r--libblkid/src/partitions/solaris_x86.c154
-rw-r--r--libblkid/src/partitions/sun.c125
-rw-r--r--libblkid/src/partitions/ultrix.c99
-rw-r--r--libblkid/src/partitions/unixware.c197
15 files changed, 3974 insertions, 0 deletions
diff --git a/libblkid/src/partitions/aix.c b/libblkid/src/partitions/aix.c
new file mode 100644
index 0000000..03a311a
--- /dev/null
+++ b/libblkid/src/partitions/aix.c
@@ -0,0 +1,57 @@
+/*
+ * aix partitions
+ *
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "partitions.h"
+#include "aix.h"
+
+static int probe_aix_pt(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ blkid_partlist ls;
+ blkid_parttable tab;
+
+ if (blkid_partitions_need_typeonly(pr))
+ /* caller does not ask for details about partitions */
+ return BLKID_PROBE_OK;
+
+ ls = blkid_probe_get_partlist(pr);
+ if (!ls)
+ return BLKID_PROBE_NONE;
+
+ tab = blkid_partlist_new_parttable(ls, "aix", 0);
+ if (!tab)
+ return -ENOMEM;
+
+ return BLKID_PROBE_OK;
+}
+
+/*
+ * We know nothing about AIX on-disk structures. Everything what we know is the
+ * magic number at begin of the disk.
+ *
+ * Note, Linux kernel is trying to be smart and AIX signature is ignored when
+ * there is a valid DOS partitions table. We don't support such behavior. All
+ * fdisk-like programs has to properly wipe the fist sector. Everything other
+ * is a bug.
+ */
+const struct blkid_idinfo aix_pt_idinfo =
+{
+ .name = "aix",
+ .probefunc = probe_aix_pt,
+ .magics =
+ {
+ { .magic = BLKID_AIX_MAGIC_STRING, .len = BLKID_AIX_MAGIC_STRLEN },
+ { NULL }
+ }
+};
+
diff --git a/libblkid/src/partitions/aix.h b/libblkid/src/partitions/aix.h
new file mode 100644
index 0000000..f767c5a
--- /dev/null
+++ b/libblkid/src/partitions/aix.h
@@ -0,0 +1,7 @@
+#ifndef BLKID_PARTITIONS_AIX_H
+#define BLKID_PARTITIONS_AIX_H
+
+#define BLKID_AIX_MAGIC_STRING "\xC9\xC2\xD4\xC1"
+#define BLKID_AIX_MAGIC_STRLEN (sizeof(BLKID_AIX_MAGIC_STRING) - 1)
+
+#endif
diff --git a/libblkid/src/partitions/atari.c b/libblkid/src/partitions/atari.c
new file mode 100644
index 0000000..314f047
--- /dev/null
+++ b/libblkid/src/partitions/atari.c
@@ -0,0 +1,312 @@
+/*
+ * atari partitions parsing code
+ *
+ * Copyright (C) 2018 Vaclav Dolezal <vdolezal@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ * Based on Linux kernel implementation and atari-fdisk
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "partitions.h"
+
+struct atari_part_def {
+ /*
+ * flags:
+ * 0 (LSB): active
+ * 1-6: (reserved)
+ * 7 (MSB): bootable
+ */
+ unsigned char flags;
+ char id[3];
+ uint32_t start;
+ uint32_t size;
+} __attribute__((packed));
+
+struct atari_rootsector {
+ char unused0[0x156]; /* boot code */
+ struct atari_part_def icd_part[8]; /* ICD partition entries */
+ char unused1[0xc];
+ uint32_t hd_size;
+ struct atari_part_def part[4]; /* primary partition entries */
+ uint32_t bsl_start; /* bad sector list start */
+ uint32_t bsl_len; /* bad sector list length */
+ uint16_t checksum;
+} __attribute__((packed));
+
+
+/*
+ * Generated using linux kernel ctype.{c,h}
+ *
+ * Since kernel uses isalnum() to detect whether it is Atari PT, we need same
+ * definition of alnum character to be consistent with kernel.
+ */
+static const unsigned char _linux_isalnum[] = {
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,
+0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,
+0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1
+};
+
+static int linux_isalnum(unsigned char c) {
+ return _linux_isalnum[c];
+}
+
+#define isalnum linux_isalnum
+
+#define IS_ACTIVE(partdef) ((partdef).flags & 1)
+
+static int is_valid_dimension(uint32_t start, uint32_t size, uint32_t maxoff)
+{
+ uint64_t end = start + size;
+
+ return end >= start
+ && 0 < start && start <= maxoff
+ && 0 < size && size <= maxoff
+ && 0 < end && end <= maxoff;
+}
+
+static int is_valid_partition(struct atari_part_def *part, uint32_t maxoff)
+{
+ uint32_t start = be32_to_cpu(part->start),
+ size = be32_to_cpu(part->size);
+
+ return (part->flags & 1)
+ && isalnum(part->id[0])
+ && isalnum(part->id[1])
+ && isalnum(part->id[2])
+ && is_valid_dimension(start, size, maxoff);
+}
+
+static int is_id_common(char *id)
+{
+ const char *ids[] = {"GEM", "BGM", "LNX", "SWP", "RAW", };
+ unsigned i;
+
+ for (i = 0; i < ARRAY_SIZE(ids); i++) {
+ if (!memcmp(ids[i], id, 3))
+ return 1;
+ }
+ return 0;
+}
+
+static int parse_partition(blkid_partlist ls, blkid_parttable tab,
+ struct atari_part_def *part, uint32_t offset)
+{
+ blkid_partition par;
+ uint32_t start;
+ uint32_t size;
+
+ start = be32_to_cpu(part->start) + offset;
+ size = be32_to_cpu(part->size);
+
+ if (blkid_partlist_get_partition_by_start(ls, start)) {
+ /* Don't increment partno for extended parts */
+ if (!offset)
+ blkid_partlist_increment_partno(ls);
+ return 0;
+ }
+
+ par = blkid_partlist_add_partition(ls, tab, start, size);
+ if (!par)
+ return -ENOMEM;
+
+ blkid_partition_set_type_string(par, (unsigned char *) part->id,
+ sizeof(part->id));
+ return 1;
+}
+
+/*
+ * \return 1: OK, 0: bad format or -errno
+ */
+static int parse_extended(blkid_probe pr, blkid_partlist ls,
+ blkid_parttable tab, struct atari_part_def *part)
+{
+ uint32_t x0start, xstart;
+ unsigned ct = 0, i = 0;
+ int rc;
+
+ x0start = xstart = be32_to_cpu(part->start);
+ while (1) {
+ struct atari_rootsector *xrs;
+
+ if (++ct > 100)
+ break;
+
+ xrs = (struct atari_rootsector *) blkid_probe_get_sector(pr, xstart);
+ if (!xrs) {
+ if (errno)
+ return -errno;
+ return 0;
+ }
+
+ /*
+ * There must be data partition followed by reference to next
+ * XGM or inactive entry.
+ */
+ for (i=0; ; i++) {
+ if (i >= ARRAY_SIZE(xrs->part) - 1)
+ return 0;
+ if (IS_ACTIVE(xrs->part[i]))
+ break;
+ }
+
+ if (!memcmp(xrs->part[i].id, "XGM", 3))
+ return 0;
+
+ rc = parse_partition(ls, tab, &xrs->part[i], xstart);
+ if (rc <= 0)
+ return rc;
+
+ if (!IS_ACTIVE(xrs->part[i+1]))
+ break;
+
+ if (memcmp(xrs->part[i+1].id, "XGM", 3) != 0)
+ return 0;
+
+ xstart = x0start + be32_to_cpu(xrs->part[i+1].start);
+ }
+
+ return 1;
+}
+
+static int probe_atari_pt(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ struct atari_rootsector *rs;
+
+ blkid_parttable tab = NULL;
+ blkid_partlist ls;
+
+ unsigned i;
+ int has_xgm = 0;
+ int rc = 0;
+ uint32_t rssize; /* size in sectors from root sector */
+ uint64_t size; /* size in sectors from system */
+
+ /* Atari partition is not defined for other sector sizes */
+ if (blkid_probe_get_sectorsize(pr) != 512)
+ goto nothing;
+
+ size = blkid_probe_get_size(pr) / 512;
+
+ /* Atari is not well defined to support large disks */
+ if (size > INT32_MAX)
+ goto nothing;
+
+ /* read root sector */
+ rs = (struct atari_rootsector *) blkid_probe_get_sector(pr, 0);
+ if (!rs) {
+ if (errno)
+ return -errno;
+ goto nothing;
+ }
+
+ rssize = be32_to_cpu(rs->hd_size);
+
+ /* check number of sectors stored in the root sector */
+ if (rssize < 2 || rssize > size)
+ goto nothing;
+
+ /* check list of bad blocks */
+ if ((rs->bsl_start || rs->bsl_len)
+ && !is_valid_dimension(be32_to_cpu(rs->bsl_start),
+ be32_to_cpu(rs->bsl_len),
+ rssize))
+ goto nothing;
+
+ /*
+ * At least one valid partition required
+ */
+ for (i = 0; i < 4; i++) {
+ if (is_valid_partition(&rs->part[i], rssize)) {
+ if (blkid_probe_set_magic(pr,
+ offsetof(struct atari_rootsector, part[i]),
+ sizeof(rs->part[i].flags) + sizeof(rs->part[i].id),
+ (unsigned char *) &rs->part[i]))
+ goto err;
+ break;
+ }
+ }
+
+ if (i == 4)
+ goto nothing;
+
+ if (blkid_partitions_need_typeonly(pr))
+ /* caller does not ask for details about partitions */
+ return BLKID_PROBE_OK;
+
+ ls = blkid_probe_get_partlist(pr);
+ if (!ls)
+ goto nothing;
+
+ tab = blkid_partlist_new_parttable(ls, "atari", 0);
+ if (!tab)
+ goto err;
+
+ for (i = 0; i < ARRAY_SIZE(rs->part); i++) {
+ struct atari_part_def *p = &rs->part[i];
+
+ if (!IS_ACTIVE(*p)) {
+ blkid_partlist_increment_partno(ls);
+ continue;
+ }
+ if (!memcmp(p->id, "XGM", 3)) {
+ has_xgm = 1;
+ rc = parse_extended(pr, ls, tab, p);
+ } else {
+ rc = parse_partition(ls, tab, p, 0);
+ }
+ if (rc < 0)
+ return rc;
+ }
+
+ /* if there are no XGM partitions, we can try ICD format */
+ /* if first ICD partition ID is not valid, assume no ICD format */
+ if (!has_xgm && is_id_common(rs->icd_part[0].id)) {
+ for (i = 0; i < ARRAY_SIZE(rs->icd_part); i++) {
+ struct atari_part_def *p = &rs->icd_part[i];
+
+ if (!IS_ACTIVE(*p) || !is_id_common(p->id)) {
+ blkid_partlist_increment_partno(ls);
+ continue;
+ }
+
+ rc = parse_partition(ls, tab, p, 0);
+ if (rc < 0)
+ return rc;
+ }
+ }
+
+ return BLKID_PROBE_OK;
+
+nothing:
+ return BLKID_PROBE_NONE;
+err:
+ return -ENOMEM;
+}
+
+const struct blkid_idinfo atari_pt_idinfo =
+{
+ .name = "atari",
+ .probefunc = probe_atari_pt,
+ .magics = BLKID_NONE_MAGIC
+};
diff --git a/libblkid/src/partitions/bsd.c b/libblkid/src/partitions/bsd.c
new file mode 100644
index 0000000..7a0b231
--- /dev/null
+++ b/libblkid/src/partitions/bsd.c
@@ -0,0 +1,188 @@
+/*
+ * BSD/OSF partition parsing code
+ *
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ * Inspired by fdisk, partx, Linux kernel, libparted and openbsd header files.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "partitions.h"
+#include "pt-bsd.h"
+
+/* Returns 'blkid_idmag' in 512-sectors */
+#define BLKID_MAG_SECTOR(_mag) (((_mag)->kboff / 2) + ((_mag)->sboff >> 9))
+
+/* Returns 'blkid_idmag' in bytes */
+#define BLKID_MAG_OFFSET(_mag) ((_mag)->kboff << 10) + ((_mag)->sboff)
+
+/* Returns 'blkid_idmag' offset in bytes within the last sector */
+#define BLKID_MAG_LASTOFFSET(_mag) \
+ (BLKID_MAG_OFFSET(_mag) - (BLKID_MAG_SECTOR(_mag) << 9))
+
+static int probe_bsd_pt(blkid_probe pr, const struct blkid_idmag *mag)
+{
+ struct bsd_disklabel *l;
+ struct bsd_partition *p;
+ const char *name = "bsd" ;
+ blkid_parttable tab = NULL;
+ blkid_partition parent;
+ blkid_partlist ls;
+ int i, nparts = BSD_MAXPARTITIONS;
+ unsigned char *data;
+ int rc = BLKID_PROBE_NONE;
+ uint32_t abs_offset = 0;
+
+ if (blkid_partitions_need_typeonly(pr))
+ /* caller does not ask for details about partitions */
+ return rc;
+
+ data = blkid_probe_get_sector(pr, BLKID_MAG_SECTOR(mag));
+ if (!data) {
+ if (errno)
+ rc = -errno;
+ goto nothing;
+ }
+
+ l = (struct bsd_disklabel *) (data + BLKID_MAG_LASTOFFSET(mag));
+
+ ls = blkid_probe_get_partlist(pr);
+ if (!ls)
+ goto nothing;
+
+ /* try to determine the real type of BSD system according to
+ * (parental) primary partition */
+ parent = blkid_partlist_get_parent(ls);
+ if (parent) {
+ switch(blkid_partition_get_type(parent)) {
+ case MBR_FREEBSD_PARTITION:
+ name = "freebsd";
+ abs_offset = blkid_partition_get_start(parent);
+ break;
+ case MBR_NETBSD_PARTITION:
+ name = "netbsd";
+ break;
+ case MBR_OPENBSD_PARTITION:
+ name = "openbsd";
+ break;
+ default:
+ DBG(LOWPROBE, ul_debug(
+ "WARNING: BSD label detected on unknown (0x%x) "
+ "primary partition",
+ blkid_partition_get_type(parent)));
+ break;
+ }
+ }
+
+ tab = blkid_partlist_new_parttable(ls, name, BLKID_MAG_OFFSET(mag));
+ if (!tab) {
+ rc = -ENOMEM;
+ goto nothing;
+ }
+
+ if (le16_to_cpu(l->d_npartitions) < BSD_MAXPARTITIONS)
+ nparts = le16_to_cpu(l->d_npartitions);
+
+ else if (le16_to_cpu(l->d_npartitions) > BSD_MAXPARTITIONS)
+ DBG(LOWPROBE, ul_debug(
+ "WARNING: ignore %d more BSD partitions",
+ le16_to_cpu(l->d_npartitions) - BSD_MAXPARTITIONS));
+
+ for (i = 0, p = l->d_partitions; i < nparts; i++, p++) {
+ blkid_partition par;
+ uint32_t start, size;
+
+ if (p->p_fstype == BSD_FS_UNUSED)
+ continue;
+
+ start = le32_to_cpu(p->p_offset);
+ size = le32_to_cpu(p->p_size);
+
+ /* FreeBSD since version 10 uses relative offsets. We can use
+ * 3rd partition (special wholedisk partition) to detect this
+ * situation.
+ */
+ if (abs_offset && nparts >= 3
+ && le32_to_cpu(l->d_partitions[2].p_offset) == 0)
+ start += abs_offset;
+
+ if (parent && blkid_partition_get_start(parent) == start
+ && blkid_partition_get_size(parent) == size) {
+ DBG(LOWPROBE, ul_debug(
+ "WARNING: BSD partition (%d) same like parent, "
+ "ignore", i));
+ continue;
+ }
+ if (parent && !blkid_is_nested_dimension(parent, start, size)) {
+ DBG(LOWPROBE, ul_debug(
+ "WARNING: BSD partition (%d) overflow "
+ "detected, ignore", i));
+ continue;
+ }
+
+ par = blkid_partlist_add_partition(ls, tab, start, size);
+ if (!par) {
+ rc = -ENOMEM;
+ goto nothing;
+ }
+
+ blkid_partition_set_type(par, p->p_fstype);
+ }
+
+ return BLKID_PROBE_OK;
+
+nothing:
+ return rc;
+}
+
+
+/*
+ * All BSD variants use the same magic string (little-endian),
+ * and the same disklabel.
+ *
+ * The difference between {Free,Open,...}BSD is in the (parental)
+ * primary partition type.
+ *
+ * See also: http://en.wikipedia.org/wiki/BSD_disklabel
+ *
+ * The location of BSD disk label is architecture specific and in defined by
+ * LABELSECTOR and LABELOFFSET macros in the disklabel.h file. The location
+ * also depends on BSD variant, FreeBSD uses only one location, NetBSD and
+ * OpenBSD are more creative...
+ *
+ * The basic overview:
+ *
+ * arch | LABELSECTOR | LABELOFFSET
+ * ------------------------+-------------+------------
+ * amd64 arm hppa hppa64 | |
+ * i386, macppc, mvmeppc | 1 | 0
+ * sgi, aviion, sh, socppc | |
+ * ------------------------+-------------+------------
+ * alpha luna88k mac68k | 0 | 64
+ * sparc(OpenBSD) vax | |
+ * ------------------------+-------------+------------
+ * sparc64 sparc(NetBSD) | 0 | 128
+ * ------------------------+-------------+------------
+ *
+ * ...and more (see http://fxr.watson.org/fxr/ident?v=NETBSD;i=LABELSECTOR)
+ *
+ */
+const struct blkid_idinfo bsd_pt_idinfo =
+{
+ .name = "bsd",
+ .probefunc = probe_bsd_pt,
+ .magics =
+ {
+ { .magic = "\x57\x45\x56\x82", .len = 4, .sboff = 512 },
+ { .magic = "\x57\x45\x56\x82", .len = 4, .sboff = 64 },
+ { .magic = "\x57\x45\x56\x82", .len = 4, .sboff = 128 },
+ { NULL }
+ }
+};
+
diff --git a/libblkid/src/partitions/dos.c b/libblkid/src/partitions/dos.c
new file mode 100644
index 0000000..6e758ec
--- /dev/null
+++ b/libblkid/src/partitions/dos.c
@@ -0,0 +1,373 @@
+/*
+ * MS-DOS partition parsing code
+ *
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ * Inspired by fdisk, partx, Linux kernel and libparted.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "partitions.h"
+#include "superblocks/superblocks.h"
+#include "aix.h"
+
+/* see superblocks/vfat.c */
+extern int blkid_probe_is_vfat(blkid_probe pr);
+
+static const struct dos_subtypes {
+ unsigned char type;
+ const struct blkid_idinfo *id;
+} dos_nested[] = {
+ { MBR_FREEBSD_PARTITION, &bsd_pt_idinfo },
+ { MBR_NETBSD_PARTITION, &bsd_pt_idinfo },
+ { MBR_OPENBSD_PARTITION, &bsd_pt_idinfo },
+ { MBR_UNIXWARE_PARTITION, &unixware_pt_idinfo },
+ { MBR_SOLARIS_X86_PARTITION, &solaris_x86_pt_idinfo },
+ { MBR_MINIX_PARTITION, &minix_pt_idinfo }
+};
+
+static inline int is_extended(struct dos_partition *p)
+{
+ return (p->sys_ind == MBR_DOS_EXTENDED_PARTITION ||
+ p->sys_ind == MBR_W95_EXTENDED_PARTITION ||
+ p->sys_ind == MBR_LINUX_EXTENDED_PARTITION);
+}
+
+static int parse_dos_extended(blkid_probe pr, blkid_parttable tab,
+ uint32_t ex_start, uint32_t ex_size, int ssf)
+{
+ blkid_partlist ls = blkid_probe_get_partlist(pr);
+ uint32_t cur_start = ex_start, cur_size = ex_size;
+ unsigned char *data;
+ int ct_nodata = 0; /* count ext.partitions without data partitions */
+ int i;
+
+ DBG(LOWPROBE, ul_debug("parse EBR [start=%d, size=%d]", ex_start/ssf, ex_size/ssf));
+ if (ex_start == 0) {
+ DBG(LOWPROBE, ul_debug("Bad offset in primary extended partition -- ignore"));
+ return 0;
+ }
+
+ while (1) {
+ struct dos_partition *p, *p0;
+ uint32_t start = 0, size;
+
+ if (++ct_nodata > 100)
+ return BLKID_PROBE_OK;
+ data = blkid_probe_get_sector(pr, cur_start);
+ if (!data) {
+ if (errno)
+ return -errno;
+ goto leave; /* malformed partition? */
+ }
+
+ if (!mbr_is_valid_magic(data))
+ goto leave;
+
+ p0 = mbr_get_partition(data, 0);
+
+ /* 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.
+ * -- Linux kernel fs/partitions/dos.c
+ *
+ * See also http://en.wikipedia.org/wiki/Extended_boot_record
+ */
+
+ /* Parse data partition */
+ for (p = p0, i = 0; i < 4; i++, p++) {
+ uint32_t abs_start;
+ blkid_partition par;
+
+ /* the start is relative to the parental ext.partition */
+ start = dos_partition_get_start(p) * ssf;
+ size = dos_partition_get_size(p) * ssf;
+ abs_start = cur_start + start; /* absolute start */
+
+ if (!size || is_extended(p))
+ continue;
+ if (i >= 2) {
+ /* extra checks to detect real data on
+ * 3rd and 4th entries */
+ if (start + size > cur_size)
+ continue;
+ if (abs_start < ex_start)
+ continue;
+ if (abs_start + size > ex_start + ex_size)
+ continue;
+ }
+
+ /* Avoid recursive non-empty links, see ct_nodata counter */
+ if (blkid_partlist_get_partition_by_start(ls, abs_start)) {
+ DBG(LOWPROBE, ul_debug("#%d: EBR duplicate data partition [abs start=%u] -- ignore",
+ i + 1, abs_start));
+ continue;
+ }
+
+ par = blkid_partlist_add_partition(ls, tab, abs_start, size);
+ if (!par)
+ return -ENOMEM;
+
+ blkid_partition_set_type(par, p->sys_ind);
+ blkid_partition_set_flags(par, p->boot_ind);
+ blkid_partition_gen_uuid(par);
+ ct_nodata = 0;
+ }
+ /* The first nested ext.partition should be a link to the next
+ * logical partition. Everything other (recursive ext.partitions)
+ * is junk.
+ */
+ for (p = p0, i = 0; i < 4; i++, p++) {
+ start = dos_partition_get_start(p) * ssf;
+ size = dos_partition_get_size(p) * ssf;
+
+ if (size && is_extended(p)) {
+ if (start == 0)
+ DBG(LOWPROBE, ul_debug("#%d: EBR link offset is zero -- ignore", i + 1));
+ else
+ break;
+ }
+ }
+ if (i == 4)
+ goto leave;
+
+ cur_start = ex_start + start;
+ cur_size = size;
+ }
+leave:
+ return BLKID_PROBE_OK;
+}
+
+static inline int is_lvm(blkid_probe pr)
+{
+ struct blkid_prval *v = __blkid_probe_lookup_value(pr, "TYPE");
+
+ return (v && v->data && strcmp((char *) v->data, "LVM2_member") == 0);
+}
+
+static inline int is_empty_mbr(unsigned char *mbr)
+{
+ struct dos_partition *p = mbr_get_partition(mbr, 0);
+ int i, nparts = 0;
+
+ for (i = 0; i < 4; i++) {
+ if (dos_partition_get_size(p) > 0)
+ nparts++;
+ p++;
+ }
+
+ return nparts == 0;
+}
+
+static int probe_dos_pt(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ int i;
+ int ssf;
+ blkid_parttable tab = NULL;
+ blkid_partlist ls;
+ struct dos_partition *p0, *p;
+ unsigned char *data;
+ uint32_t start, size, id;
+ char idstr[UUID_STR_LEN];
+
+
+ data = blkid_probe_get_sector(pr, 0);
+ if (!data) {
+ if (errno)
+ return -errno;
+ goto nothing;
+ }
+
+ /* ignore disks with AIX magic number -- for more details see aix.c */
+ if (memcmp(data, BLKID_AIX_MAGIC_STRING, BLKID_AIX_MAGIC_STRLEN) == 0)
+ goto nothing;
+
+ p0 = mbr_get_partition(data, 0);
+
+ /*
+ * Reject PT where boot indicator is not 0 or 0x80.
+ */
+ for (p = p0, i = 0; i < 4; i++, p++)
+ if (p->boot_ind != 0 && p->boot_ind != 0x80) {
+ DBG(LOWPROBE, ul_debug("missing boot indicator -- ignore"));
+ goto nothing;
+ }
+
+ /*
+ * GPT uses valid MBR
+ */
+ for (p = p0, i = 0; i < 4; i++, p++) {
+ if (p->sys_ind == MBR_GPT_PARTITION) {
+ DBG(LOWPROBE, ul_debug("probably GPT -- ignore"));
+ goto nothing;
+ }
+ }
+
+ /*
+ * Now that the 55aa signature is present, this is probably
+ * either the boot sector of a FAT filesystem or a DOS-type
+ * partition table.
+ */
+ if (blkid_probe_is_vfat(pr) == 1) {
+ DBG(LOWPROBE, ul_debug("probably FAT -- ignore"));
+ goto nothing;
+ }
+
+ /* Another false positive is NTFS */
+ if (blkid_probe_is_ntfs(pr) == 1) {
+ DBG(LOWPROBE, ul_debug("probably NTFS -- ignore"));
+ goto nothing;
+ }
+
+ /*
+ * Ugly exception, if the device contains a valid LVM physical volume
+ * and empty MBR (=no partition defined) then it's LVM and MBR should
+ * be ignored. Crazy people use it to boot from LVM devices.
+ */
+ if (is_lvm(pr) && is_empty_mbr(data)) {
+ DBG(LOWPROBE, ul_debug("empty MBR on LVM device -- ignore"));
+ goto nothing;
+ }
+
+ blkid_probe_use_wiper(pr, MBR_PT_OFFSET, 512 - MBR_PT_OFFSET);
+
+ id = mbr_get_id(data);
+ if (id)
+ snprintf(idstr, sizeof(idstr), "%08x", id);
+
+ /*
+ * Well, all checks pass, it's MS-DOS partition table
+ */
+ if (blkid_partitions_need_typeonly(pr)) {
+ /* Non-binary interface -- caller does not ask for details
+ * about partitions, just set generic variables only. */
+ if (id)
+ blkid_partitions_strcpy_ptuuid(pr, idstr);
+ return 0;
+ }
+
+ ls = blkid_probe_get_partlist(pr);
+ if (!ls)
+ goto nothing;
+
+ /* sector size factor (the start and size are in the real sectors, but
+ * we need to convert all sizes to 512 logical sectors
+ */
+ ssf = blkid_probe_get_sectorsize(pr) / 512;
+
+ /* allocate a new partition table */
+ tab = blkid_partlist_new_parttable(ls, "dos", MBR_PT_OFFSET);
+ if (!tab)
+ return -ENOMEM;
+
+ if (id)
+ blkid_parttable_set_id(tab, (unsigned char *) idstr);
+
+ /* Parse primary partitions */
+ for (p = p0, i = 0; i < 4; i++, p++) {
+ blkid_partition par;
+
+ start = dos_partition_get_start(p) * ssf;
+ size = dos_partition_get_size(p) * ssf;
+
+ if (!size) {
+ /* Linux kernel ignores empty partitions, but partno for
+ * the empty primary partitions is not reused */
+ blkid_partlist_increment_partno(ls);
+ continue;
+ }
+ par = blkid_partlist_add_partition(ls, tab, start, size);
+ if (!par)
+ return -ENOMEM;
+
+ blkid_partition_set_type(par, p->sys_ind);
+ blkid_partition_set_flags(par, p->boot_ind);
+ blkid_partition_gen_uuid(par);
+ }
+
+ /* Linux uses partition numbers greater than 4
+ * for all logical partition and all nested partition tables (bsd, ..)
+ */
+ blkid_partlist_set_partno(ls, 5);
+
+ /* Parse logical partitions */
+ for (p = p0, i = 0; i < 4; i++, p++) {
+ start = dos_partition_get_start(p) * ssf;
+ size = dos_partition_get_size(p) * ssf;
+
+ if (!size)
+ continue;
+ if (is_extended(p) &&
+ parse_dos_extended(pr, tab, start, size, ssf) == -1)
+ goto nothing;
+ }
+
+ /* Parse subtypes (nested partitions) on large disks */
+ if (!blkid_probe_is_tiny(pr)) {
+ int nparts = blkid_partlist_numof_partitions(ls);
+
+ DBG(LOWPROBE, ul_debug("checking for subtypes"));
+
+ for (i = 0; i < nparts; i++) {
+ size_t n;
+ int type;
+ blkid_partition pa = blkid_partlist_get_partition(ls, i);
+
+ if (pa == NULL
+ || blkid_partition_get_size(pa) == 0
+ || blkid_partition_is_extended(pa)
+ || blkid_partition_is_logical(pa))
+ continue;
+
+ type = blkid_partition_get_type(pa);
+
+ for (n = 0; n < ARRAY_SIZE(dos_nested); n++) {
+ int rc;
+
+ if (dos_nested[n].type != type)
+ continue;
+
+ rc = blkid_partitions_do_subprobe(pr, pa,
+ dos_nested[n].id);
+ if (rc < 0)
+ return rc;
+ break;
+ }
+ }
+ }
+ return BLKID_PROBE_OK;
+
+nothing:
+ return BLKID_PROBE_NONE;
+}
+
+
+const struct blkid_idinfo dos_pt_idinfo =
+{
+ .name = "dos",
+ .probefunc = probe_dos_pt,
+ .magics =
+ {
+ /* DOS master boot sector:
+ *
+ * 0 | Code Area
+ * 440 | Optional Disk signature
+ * 446 | Partition table
+ * 510 | 0x55
+ * 511 | 0xAA
+ */
+ { .magic = "\x55\xAA", .len = 2, .sboff = 510 },
+ { NULL }
+ }
+};
+
diff --git a/libblkid/src/partitions/gpt.c b/libblkid/src/partitions/gpt.c
new file mode 100644
index 0000000..af6257a
--- /dev/null
+++ b/libblkid/src/partitions/gpt.c
@@ -0,0 +1,473 @@
+/*
+ * EFI GPT partition parsing code
+ *
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ * This code is not copy & past from any other implementation.
+ *
+ * For more information about GPT start your study at:
+ * http://en.wikipedia.org/wiki/GUID_Partition_Table
+ * http://technet.microsoft.com/en-us/library/cc739412(WS.10).aspx
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <limits.h>
+#include <inttypes.h>
+
+#include "partitions.h"
+#include "crc32.h"
+
+#define GPT_PRIMARY_LBA 1
+
+/* Signature - “EFI PART” */
+#define GPT_HEADER_SIGNATURE 0x5452415020494645ULL
+#define GPT_HEADER_SIGNATURE_STR "EFI PART"
+
+/* basic types */
+typedef uint16_t efi_char16_t;
+
+/* UUID */
+typedef struct {
+ uint32_t time_low;
+ uint16_t time_mid;
+ uint16_t time_hi_and_version;
+ uint8_t clock_seq_hi;
+ uint8_t clock_seq_low;
+ uint8_t node[6];
+} efi_guid_t;
+
+
+#define GPT_UNUSED_ENTRY_GUID \
+ ((efi_guid_t) { 0x00000000, 0x0000, 0x0000, 0x00, 0x00, \
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }})
+struct gpt_header {
+ uint64_t signature; /* "EFI PART" */
+ uint32_t revision;
+ uint32_t header_size; /* usually 92 bytes */
+ uint32_t header_crc32; /* checksum of header with this
+ * field zeroed during calculation */
+ uint32_t reserved1;
+
+ uint64_t my_lba; /* location of this header copy */
+ uint64_t alternate_lba; /* location of the other header copy */
+ uint64_t first_usable_lba; /* first usable LBA for partitions */
+ uint64_t last_usable_lba; /* last usable LBA for partitions */
+
+ efi_guid_t disk_guid; /* disk UUID */
+
+ uint64_t partition_entries_lba; /* always 2 in primary header copy */
+ uint32_t num_partition_entries;
+ uint32_t sizeof_partition_entry;
+ uint32_t partition_entry_array_crc32;
+
+ /*
+ * The rest of the block is reserved by UEFI and must be zero. EFI
+ * standard handles this by:
+ *
+ * uint8_t reserved2[ BLKSSZGET - 92 ];
+ *
+ * This definition is useless in practice. It is necessary to read
+ * whole block from the device rather than sizeof(struct gpt_header)
+ * only.
+ */
+} __attribute__ ((packed));
+
+/*** not used
+struct gpt_entry_attributes {
+ uint64_t required_to_function:1;
+ uint64_t reserved:47;
+ uint64_t type_guid_specific:16;
+} __attribute__ ((packed));
+***/
+
+struct gpt_entry {
+ efi_guid_t partition_type_guid; /* type UUID */
+ efi_guid_t unique_partition_guid; /* partition UUID */
+ uint64_t starting_lba;
+ uint64_t ending_lba;
+
+ /*struct gpt_entry_attributes attributes;*/
+
+ uint64_t attributes;
+
+ efi_char16_t partition_name[72 / sizeof(efi_char16_t)]; /* UTF-16LE string*/
+} __attribute__ ((packed));
+
+
+/*
+ * EFI uses crc32 with ~0 seed and xor's with ~0 at the end.
+ */
+static inline uint32_t count_crc32(const unsigned char *buf, size_t len,
+ size_t exclude_off, size_t exclude_len)
+{
+ return (ul_crc32_exclude_offset(~0L, buf, len, exclude_off, exclude_len) ^ ~0L);
+}
+
+static inline unsigned char *get_lba_buffer(blkid_probe pr,
+ uint64_t lba, size_t bytes)
+{
+ return blkid_probe_get_buffer(pr,
+ blkid_probe_get_sectorsize(pr) * lba, bytes);
+}
+
+static inline int guidcmp(efi_guid_t left, efi_guid_t right)
+{
+ return memcmp(&left, &right, sizeof (efi_guid_t));
+}
+
+/*
+ * UUID is traditionally 16 byte big-endian array, except Intel EFI
+ * specification where the UUID is a structure of little-endian fields.
+ */
+static void swap_efi_guid(efi_guid_t *uid)
+{
+ uid->time_low = swab32(uid->time_low);
+ uid->time_mid = swab16(uid->time_mid);
+ uid->time_hi_and_version = swab16(uid->time_hi_and_version);
+}
+
+static int last_lba(blkid_probe pr, uint64_t *lba)
+{
+ uint64_t sz = blkid_probe_get_size(pr);
+ unsigned int ssz = blkid_probe_get_sectorsize(pr);
+
+ if (sz < ssz)
+ return -1;
+
+ *lba = (sz / ssz) - 1ULL;
+ return 0;
+}
+
+/*
+ * Protective (legacy) MBR.
+ *
+ * This MBR contains standard DOS partition table with a single partition, type
+ * of 0xEE. The partition usually encompassing the entire GPT drive - or 2TiB
+ * for large disks.
+ *
+ * Note that Apple uses GPT/MBR hybrid disks, where the DOS partition table is
+ * synchronized with GPT. This synchronization has many restriction of course
+ * (due DOS PT limitations).
+ *
+ * Note that the PMBR detection is optional (enabled by default) and could be
+ * disabled by BLKID_PARTS_FOPCE_GPT flag (see also blkid_partitions_set_flags()).
+ */
+static int is_pmbr_valid(blkid_probe pr, int *has)
+{
+ int flags = blkid_partitions_get_flags(pr);
+ unsigned char *data;
+ struct dos_partition *p;
+ int i;
+
+ if (has)
+ *has = 0;
+ else if (flags & BLKID_PARTS_FORCE_GPT)
+ return 1; /* skip PMBR check */
+
+ data = blkid_probe_get_sector(pr, 0);
+ if (!data) {
+ if (errno)
+ return -errno;
+ goto failed;
+ }
+
+ if (!mbr_is_valid_magic(data))
+ goto failed;
+
+ for (i = 0, p = mbr_get_partition(data, 0); i < 4; i++, p++) {
+ if (p->sys_ind == MBR_GPT_PARTITION) {
+ DBG(LOWPROBE, ul_debug(" #%d valid PMBR partition", i + 1));
+ goto ok;
+ }
+ }
+failed:
+ return 0;
+ok:
+ if (has)
+ *has = 1;
+ return 1;
+}
+
+/*
+ * Reads GPT header to @hdr and returns a pointer to @hdr or NULL in case of
+ * error. The function also returns GPT entries in @ents.
+ *
+ * Note, this function does not allocate any memory. The GPT header has fixed
+ * size so we use stack, and @ents returns memory from libblkid buffer (so the
+ * next blkid_probe_get_buffer() will overwrite this buffer).
+ *
+ * This function checks validity of header and entries array. A corrupted
+ * header is not returned.
+ */
+static struct gpt_header *get_gpt_header(
+ blkid_probe pr, struct gpt_header *hdr,
+ struct gpt_entry **ents, uint64_t lba,
+ uint64_t lastlba)
+{
+ struct gpt_header *h;
+ uint32_t crc;
+ uint64_t lu, fu;
+ uint64_t esz;
+ uint32_t hsz, ssz;
+
+ ssz = blkid_probe_get_sectorsize(pr);
+
+ DBG(LOWPROBE, ul_debug(" checking for GPT header at %"PRIu64, lba));
+
+ /* whole sector is allocated for GPT header */
+ h = (struct gpt_header *) get_lba_buffer(pr, lba, ssz);
+ if (!h)
+ return NULL;
+
+ if (le64_to_cpu(h->signature) != GPT_HEADER_SIGNATURE)
+ return NULL;
+
+ hsz = le32_to_cpu(h->header_size);
+
+ /* EFI: The HeaderSize must be greater than 92 and must be less
+ * than or equal to the logical block size.
+ */
+ if (hsz > ssz || hsz < sizeof(*h))
+ return NULL;
+
+ /* Header has to be verified when header_crc32 is zero */
+ crc = count_crc32((unsigned char *) h, hsz,
+ offsetof(struct gpt_header, header_crc32),
+ sizeof(h->header_crc32));
+
+ if (crc != le32_to_cpu(h->header_crc32)) {
+ DBG(LOWPROBE, ul_debug("GPT header corrupted"));
+ return NULL;
+ }
+
+ /* Valid header has to be at MyLBA */
+ if (le64_to_cpu(h->my_lba) != lba) {
+ DBG(LOWPROBE, ul_debug(
+ "GPT->MyLBA mismatch with real position"));
+ return NULL;
+ }
+
+ fu = le64_to_cpu(h->first_usable_lba);
+ lu = le64_to_cpu(h->last_usable_lba);
+
+ /* Check if First and Last usable LBA makes sense */
+ if (lu < fu || fu > lastlba || lu > lastlba) {
+ DBG(LOWPROBE, ul_debug(
+ "GPT->{First,Last}UsableLBA out of range"));
+ return NULL;
+ }
+
+ /* The header has to be outside usable range */
+ if (fu < lba && lba < lu) {
+ DBG(LOWPROBE, ul_debug("GPT header is inside usable area"));
+ return NULL;
+ }
+
+ /* Size of blocks with GPT entries */
+ esz = (uint64_t)le32_to_cpu(h->num_partition_entries) *
+ le32_to_cpu(h->sizeof_partition_entry);
+
+ if (esz == 0 || esz >= UINT32_MAX ||
+ le32_to_cpu(h->sizeof_partition_entry) != sizeof(struct gpt_entry)) {
+ DBG(LOWPROBE, ul_debug("GPT entries undefined"));
+ return NULL;
+ }
+
+ /* The header seems valid, save it
+ * (we don't care about zeros in hdr->reserved2 area) */
+ memcpy(hdr, h, sizeof(*h));
+ h = hdr;
+
+ /* Read GPT entries */
+ *ents = (struct gpt_entry *) get_lba_buffer(pr,
+ le64_to_cpu(h->partition_entries_lba), esz);
+ if (!*ents) {
+ DBG(LOWPROBE, ul_debug("GPT entries unreadable"));
+ return NULL;
+ }
+
+ /* Validate entries */
+ crc = count_crc32((unsigned char *) *ents, esz, 0, 0);
+ if (crc != le32_to_cpu(h->partition_entry_array_crc32)) {
+ DBG(LOWPROBE, ul_debug("GPT entries corrupted"));
+ return NULL;
+ }
+
+ return h;
+}
+
+static int probe_gpt_pt(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ uint64_t lastlba = 0, lba;
+ struct gpt_header hdr, *h;
+ struct gpt_entry *e;
+ blkid_parttable tab = NULL;
+ blkid_partlist ls;
+ uint64_t fu, lu;
+ uint32_t ssf, i;
+ efi_guid_t guid;
+ int ret;
+
+ if (last_lba(pr, &lastlba))
+ goto nothing;
+
+ ret = is_pmbr_valid(pr, NULL);
+ if (ret < 0)
+ return ret;
+ if (ret == 0)
+ goto nothing;
+
+ errno = 0;
+ h = get_gpt_header(pr, &hdr, &e, (lba = GPT_PRIMARY_LBA), lastlba);
+ if (!h && !errno)
+ h = get_gpt_header(pr, &hdr, &e, (lba = lastlba), lastlba);
+
+ if (!h) {
+ if (errno)
+ return -errno;
+ goto nothing;
+ }
+
+ blkid_probe_use_wiper(pr, lba * blkid_probe_get_size(pr), 8);
+
+ if (blkid_probe_set_magic(pr, blkid_probe_get_sectorsize(pr) * lba,
+ sizeof(GPT_HEADER_SIGNATURE_STR) - 1,
+ (unsigned char *) GPT_HEADER_SIGNATURE_STR))
+ goto err;
+
+ guid = h->disk_guid;
+ swap_efi_guid(&guid);
+
+ if (blkid_partitions_need_typeonly(pr)) {
+ /* Non-binary interface -- caller does not ask for details
+ * about partitions, just set generic variables only. */
+ blkid_partitions_set_ptuuid(pr, (unsigned char *) &guid);
+ return BLKID_PROBE_OK;
+ }
+
+ ls = blkid_probe_get_partlist(pr);
+ if (!ls)
+ goto nothing;
+
+ tab = blkid_partlist_new_parttable(ls, "gpt",
+ blkid_probe_get_sectorsize(pr) * lba);
+ if (!tab)
+ goto err;
+
+ blkid_parttable_set_uuid(tab, (const unsigned char *) &guid);
+
+ ssf = blkid_probe_get_sectorsize(pr) / 512;
+
+ fu = le64_to_cpu(h->first_usable_lba);
+ lu = le64_to_cpu(h->last_usable_lba);
+
+ for (i = 0; i < le32_to_cpu(h->num_partition_entries); i++, e++) {
+
+ blkid_partition par;
+ uint64_t start = le64_to_cpu(e->starting_lba);
+ uint64_t size = le64_to_cpu(e->ending_lba) -
+ le64_to_cpu(e->starting_lba) + 1ULL;
+
+ /* 00000000-0000-0000-0000-000000000000 entry */
+ if (!guidcmp(e->partition_type_guid, GPT_UNUSED_ENTRY_GUID)) {
+ blkid_partlist_increment_partno(ls);
+ continue;
+ }
+ /* the partition has to inside usable range */
+ if (start < fu || start + size - 1 > lu) {
+ DBG(LOWPROBE, ul_debug(
+ "GPT entry[%d] overflows usable area - ignore",
+ i));
+ blkid_partlist_increment_partno(ls);
+ continue;
+ }
+
+ par = blkid_partlist_add_partition(ls, tab,
+ start * ssf, size * ssf);
+ if (!par)
+ goto err;
+
+ blkid_partition_set_utf8name(par,
+ (unsigned char *) e->partition_name,
+ sizeof(e->partition_name), UL_ENCODE_UTF16LE);
+
+ guid = e->unique_partition_guid;
+ swap_efi_guid(&guid);
+ blkid_partition_set_uuid(par, (const unsigned char *) &guid);
+
+ guid = e->partition_type_guid;
+ swap_efi_guid(&guid);
+ blkid_partition_set_type_uuid(par, (const unsigned char *) &guid);
+
+ blkid_partition_set_flags(par, le64_to_cpu(e->attributes));
+ }
+
+ return BLKID_PROBE_OK;
+
+nothing:
+ return BLKID_PROBE_NONE;
+
+err:
+ return -ENOMEM;
+}
+
+
+const struct blkid_idinfo gpt_pt_idinfo =
+{
+ .name = "gpt",
+ .probefunc = probe_gpt_pt,
+
+ /*
+ * It would be possible to check for DOS signature (0xAA55), but
+ * unfortunately almost all EFI GPT implementations allow to optionally
+ * skip the legacy MBR. We follows this behavior and MBR is optional.
+ * See is_valid_pmbr().
+ *
+ * It means we have to always call probe_gpt_pt().
+ */
+ .magics = BLKID_NONE_MAGIC
+};
+
+
+
+/* probe for *alone* protective MBR */
+static int probe_pmbr_pt(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ int has = 0;
+ struct gpt_entry *e;
+ uint64_t lastlba = 0;
+ struct gpt_header hdr;
+
+ if (last_lba(pr, &lastlba))
+ goto nothing;
+
+ is_pmbr_valid(pr, &has);
+ if (!has)
+ goto nothing;
+
+ if (!get_gpt_header(pr, &hdr, &e, GPT_PRIMARY_LBA, lastlba) &&
+ !get_gpt_header(pr, &hdr, &e, lastlba, lastlba))
+ return 0;
+nothing:
+ return 1;
+}
+
+const struct blkid_idinfo pmbr_pt_idinfo =
+{
+ .name = "PMBR",
+ .probefunc = probe_pmbr_pt,
+ .magics =
+ {
+ { .magic = "\x55\xAA", .len = 2, .sboff = 510 },
+ { NULL }
+ }
+};
+
diff --git a/libblkid/src/partitions/mac.c b/libblkid/src/partitions/mac.c
new file mode 100644
index 0000000..75a558b
--- /dev/null
+++ b/libblkid/src/partitions/mac.c
@@ -0,0 +1,200 @@
+/*
+ * mac partitions parsing code
+ *
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "partitions.h"
+
+#define MAC_PARTITION_MAGIC 0x504d
+#define MAC_PARTITION_MAGIC_OLD 0x5453
+
+/*
+ * Mac partition entry
+ * http://developer.apple.com/legacy/mac/library/documentation/mac/Devices/Devices-126.html
+ */
+struct mac_partition {
+ uint16_t signature; /* expected to be MAC_PARTITION_MAGIC */
+ uint16_t reserved; /* reserved */
+ uint32_t map_count; /* # blocks in partition map */
+ uint32_t start_block; /* absolute starting block # of partition */
+ uint32_t block_count; /* number of blocks in partition */
+ char name[32]; /* partition name */
+ char type[32]; /* string type description */
+ uint32_t data_start; /* rel block # of first data block */
+ uint32_t data_count; /* number of data blocks */
+ uint32_t status; /* partition status bits */
+ uint32_t boot_start; /* first logical block of boot code */
+ uint32_t boot_size; /* size of boot code, in bytes */
+ uint32_t boot_load; /* boot code load address */
+ uint32_t boot_load2; /* reserved */
+ uint32_t boot_entry; /* boot code entry point */
+ uint32_t boot_entry2; /* reserved */
+ uint32_t boot_cksum; /* boot code checksum */
+ char processor[16]; /* identifies ISA of boot */
+
+ /* there is more stuff after this that we don't need */
+} __attribute__((packed));
+
+/*
+ * Driver descriptor structure, in block 0
+ * http://developer.apple.com/legacy/mac/library/documentation/mac/Devices/Devices-121.html
+ */
+struct mac_driver_desc {
+ uint16_t signature; /* expected to be MAC_DRIVER_MAGIC */
+ uint16_t block_size; /* block size of the device */
+ uint32_t block_count; /* number of blocks on the device */
+
+ /* there is more stuff after this that we don't need */
+} __attribute__((packed));
+
+static inline unsigned char *get_mac_block(
+ blkid_probe pr,
+ uint16_t block_size,
+ uint32_t num)
+{
+ return blkid_probe_get_buffer(pr, (uint64_t) num * block_size, block_size);
+}
+
+static inline int has_part_signature(struct mac_partition *p)
+{
+ return be16_to_cpu(p->signature) == MAC_PARTITION_MAGIC ||
+ be16_to_cpu(p->signature) == MAC_PARTITION_MAGIC_OLD;
+}
+
+static int probe_mac_pt(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ struct mac_driver_desc *md;
+ struct mac_partition *p;
+ blkid_parttable tab = NULL;
+ blkid_partlist ls;
+ uint16_t block_size;
+ uint16_t ssf; /* sector size fragment */
+ uint32_t nblks, nprts, i;
+
+
+ /* The driver descriptor record is always located at physical block 0,
+ * the first block on the disk.
+ */
+ md = (struct mac_driver_desc *) blkid_probe_get_sector(pr, 0);
+ if (!md) {
+ if (errno)
+ return -errno;
+ goto nothing;
+ }
+
+ block_size = be16_to_cpu(md->block_size);
+ if (block_size < sizeof(struct mac_partition))
+ goto nothing;
+
+ /* The partition map always begins at physical block 1,
+ * the second block on the disk.
+ */
+ p = (struct mac_partition *) get_mac_block(pr, block_size, 1);
+ if (!p) {
+ if (errno)
+ return -errno;
+ goto nothing;
+ }
+
+ /* check the first partition signature */
+ if (!has_part_signature(p))
+ goto nothing;
+
+ if (blkid_partitions_need_typeonly(pr))
+ /* caller does not ask for details about partitions */
+ return 0;
+
+ ls = blkid_probe_get_partlist(pr);
+ if (!ls)
+ goto nothing;
+
+ tab = blkid_partlist_new_parttable(ls, "mac", 0);
+ if (!tab)
+ goto err;
+
+ ssf = block_size / 512;
+ nblks = be32_to_cpu(p->map_count);
+ if (nblks > 256) {
+ nprts = 256;
+ DBG(LOWPROBE, ul_debug(
+ "mac: map_count too large, entry[0]: %u, "
+ "enforcing limit of %u", nblks, nprts));
+ } else
+ nprts = nblks;
+
+ for (i = 0; i < nprts; ++i) {
+ blkid_partition par;
+ uint32_t start;
+ uint32_t size;
+
+ p = (struct mac_partition *) get_mac_block(pr, block_size, i + 1);
+ if (!p) {
+ if (errno)
+ return -errno;
+ goto nothing;
+ }
+ if (!has_part_signature(p))
+ goto nothing;
+
+ if (be32_to_cpu(p->map_count) != nblks) {
+ DBG(LOWPROBE, ul_debug(
+ "mac: inconsistent map_count in partition map, "
+ "entry[0]: %u, entry[%u]: %u",
+ nblks, i,
+ be32_to_cpu(p->map_count)));
+ }
+
+ /*
+ * note that libparted ignores some mac partitions according to
+ * the partition name (e.g. "Apple_Free" or "Apple_Void"). We
+ * follows Linux kernel and all partitions are visible
+ */
+
+ start = be32_to_cpu(p->start_block) * ssf;
+ size = be32_to_cpu(p->block_count) * ssf;
+
+ par = blkid_partlist_add_partition(ls, tab, start, size);
+ if (!par)
+ goto err;
+
+ blkid_partition_set_name(par, (unsigned char *) p->name,
+ sizeof(p->name));
+
+ blkid_partition_set_type_string(par, (unsigned char *) p->type,
+ sizeof(p->type));
+ }
+
+ return BLKID_PROBE_OK;
+
+nothing:
+ return BLKID_PROBE_NONE;
+err:
+ return -ENOMEM;
+}
+
+/*
+ * Mac disk always begin with "Driver Descriptor Record"
+ * (struct mac_driver_desc) and magic 0x4552.
+ */
+const struct blkid_idinfo mac_pt_idinfo =
+{
+ .name = "mac",
+ .probefunc = probe_mac_pt,
+ .magics =
+ {
+ /* big-endian magic string */
+ { .magic = "\x45\x52", .len = 2 },
+ { NULL }
+ }
+};
+
diff --git a/libblkid/src/partitions/minix.c b/libblkid/src/partitions/minix.c
new file mode 100644
index 0000000..43c9d9a
--- /dev/null
+++ b/libblkid/src/partitions/minix.c
@@ -0,0 +1,102 @@
+/*
+ * Minix partition parsing code
+ *
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "partitions.h"
+#include "minix.h"
+
+static int probe_minix_pt(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ struct dos_partition *p;
+ blkid_parttable tab = NULL;
+ blkid_partition parent;
+ blkid_partlist ls;
+ unsigned char *data;
+ int i;
+
+ data = blkid_probe_get_sector(pr, 0);
+ if (!data) {
+ if (errno)
+ return -errno;
+ goto nothing;
+ }
+
+ ls = blkid_probe_get_partlist(pr);
+ if (!ls)
+ goto nothing;
+
+ /* Parent is required, because Minix uses the same PT as DOS and
+ * difference is only in primary partition (parent) type.
+ */
+ parent = blkid_partlist_get_parent(ls);
+ if (!parent)
+ goto nothing;
+
+ if (blkid_partition_get_type(parent) != MBR_MINIX_PARTITION)
+ goto nothing;
+
+ if (blkid_partitions_need_typeonly(pr))
+ /* caller does not ask for details about partitions */
+ return BLKID_PROBE_OK;
+
+ tab = blkid_partlist_new_parttable(ls, "minix", MBR_PT_OFFSET);
+ if (!tab)
+ goto err;
+
+ for (i = 0, p = mbr_get_partition(data, 0);
+ i < MINIX_MAXPARTITIONS; i++, p++) {
+
+ uint32_t start, size;
+ blkid_partition par;
+
+ if (p->sys_ind != MBR_MINIX_PARTITION)
+ continue;
+
+ start = dos_partition_get_start(p);
+ size = dos_partition_get_size(p);
+
+ if (parent && !blkid_is_nested_dimension(parent, start, size)) {
+ DBG(LOWPROBE, ul_debug(
+ "WARNING: minix partition (%d) overflow "
+ "detected, ignore", i));
+ continue;
+ }
+
+ par = blkid_partlist_add_partition(ls, tab, start, size);
+ if (!par)
+ goto err;
+
+ blkid_partition_set_type(par, p->sys_ind);
+ blkid_partition_set_flags(par, p->boot_ind);
+ }
+
+ return BLKID_PROBE_OK;
+
+nothing:
+ return BLKID_PROBE_NONE;
+err:
+ return -ENOMEM;
+}
+
+/* same as DOS */
+const struct blkid_idinfo minix_pt_idinfo =
+{
+ .name = "minix",
+ .probefunc = probe_minix_pt,
+ .magics =
+ {
+ { .magic = "\x55\xAA", .len = 2, .sboff = 510 },
+ { NULL }
+ }
+};
+
diff --git a/libblkid/src/partitions/partitions.c b/libblkid/src/partitions/partitions.c
new file mode 100644
index 0000000..a34a446
--- /dev/null
+++ b/libblkid/src/partitions/partitions.c
@@ -0,0 +1,1526 @@
+/*
+ * partitions - partition tables parsing
+ *
+ * Copyright (C) 2008-2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdarg.h>
+
+#include "partitions.h"
+#include "sysfs.h"
+#include "strutils.h"
+
+/**
+ * SECTION: partitions
+ * @title: Partitions probing
+ * @short_description: partitions tables detection and parsing
+ *
+ * This chain supports binary and NAME=value interfaces, but complete PT
+ * description is provided by binary interface only. The libblkid prober is
+ * compatible with kernel partition tables parser. The parser does not return
+ * empty (size=0) partitions or special hidden partitions.
+ *
+ * NAME=value interface, supported tags:
+ *
+ * @PTTYPE: partition table type (dos, gpt, etc.).
+ *
+ * @PTUUID: partition table id (uuid for gpt, hex for dos).
+
+ * @PART_ENTRY_SCHEME: partition table type
+ *
+ * @PART_ENTRY_NAME: partition name (gpt and mac only)
+ *
+ * @PART_ENTRY_UUID: partition UUID (gpt, or pseudo IDs for MBR)
+ *
+ * @PART_ENTRY_TYPE: partition type, 0xNN (e.g. 0x82) or type UUID (gpt only) or type string (mac)
+ *
+ * @PART_ENTRY_FLAGS: partition flags (e.g. boot_ind) or attributes (e.g. gpt attributes)
+ *
+ * @PART_ENTRY_NUMBER: partition number
+ *
+ * @PART_ENTRY_OFFSET: the begin of the partition
+ *
+ * @PART_ENTRY_SIZE: size of the partition
+ *
+ * @PART_ENTRY_DISK: whole-disk maj:min
+ *
+ * Example:
+ *
+ * <informalexample>
+ * <programlisting>
+ * blkid_probe pr;
+ * const char *ptname;
+ *
+ * pr = blkid_new_probe_from_filename(devname);
+ * if (!pr)
+ * err("%s: failed to open device", devname);
+ *
+ * blkid_probe_enable_partitions(pr, TRUE);
+ * blkid_do_fullprobe(pr);
+ *
+ * blkid_probe_lookup_value(pr, "PTTYPE", &ptname, NULL);
+ * printf("%s partition type detected\n", pttype);
+ *
+ * blkid_free_probe(pr);
+ *
+ * // don't forget to check return codes in your code!
+ * </programlisting>
+ * </informalexample>
+ *
+ * Binary interface:
+ *
+ * <informalexample>
+ * <programlisting>
+ * blkid_probe pr;
+ * blkid_partlist ls;
+ * int nparts, i;
+ *
+ * pr = blkid_new_probe_from_filename(devname);
+ * if (!pr)
+ * err("%s: failed to open device", devname);
+ *
+ * ls = blkid_probe_get_partitions(pr);
+ * nparts = blkid_partlist_numof_partitions(ls);
+ *
+ * for (i = 0; i < nparts; i++) {
+ * blkid_partition par = blkid_partlist_get_partition(ls, i);
+ * printf("#%d: %llu %llu 0x%x",
+ * blkid_partition_get_partno(par),
+ * blkid_partition_get_start(par),
+ * blkid_partition_get_size(par),
+ * blkid_partition_get_type(par));
+ * }
+ *
+ * blkid_free_probe(pr);
+ *
+ * // don't forget to check return codes in your code!
+ * </programlisting>
+ * </informalexample>
+ */
+
+/*
+ * Chain driver function
+ */
+static int partitions_probe(blkid_probe pr, struct blkid_chain *chn);
+static void partitions_free_data(blkid_probe pr, void *data);
+
+/*
+ * Partitions chain probing functions
+ */
+static const struct blkid_idinfo *idinfos[] =
+{
+ &aix_pt_idinfo,
+ &sgi_pt_idinfo,
+ &sun_pt_idinfo,
+ &dos_pt_idinfo,
+ &gpt_pt_idinfo,
+ &pmbr_pt_idinfo, /* always after GPT */
+ &mac_pt_idinfo,
+ &ultrix_pt_idinfo,
+ &bsd_pt_idinfo,
+ &unixware_pt_idinfo,
+ &solaris_x86_pt_idinfo,
+ &minix_pt_idinfo,
+ &atari_pt_idinfo
+};
+
+/*
+ * Driver definition
+ */
+const struct blkid_chaindrv partitions_drv = {
+ .id = BLKID_CHAIN_PARTS,
+ .name = "partitions",
+ .dflt_enabled = FALSE,
+ .idinfos = idinfos,
+ .nidinfos = ARRAY_SIZE(idinfos),
+ .has_fltr = TRUE,
+ .probe = partitions_probe,
+ .safeprobe = partitions_probe,
+ .free_data = partitions_free_data
+};
+
+
+/*
+ * For compatibility with the rest of libblkid API (with the old high-level
+ * API) we use completely opaque typedefs for all structs. Don't forget that
+ * the final blkid_* types are pointers! See blkid.h.
+ *
+ * [Just for the record, I hate typedef for pointers --kzak]
+ */
+
+/* exported as opaque type "blkid_parttable" */
+struct blkid_struct_parttable {
+ const char *type; /* partition table type */
+ uint64_t offset; /* begin of the partition table (in bytes) */
+ int nparts; /* number of partitions */
+ blkid_partition parent; /* parent of nested partition table */
+ char id[UUID_STR_LEN]; /* PT identifier (e.g. UUID for GPT) */
+
+ struct list_head t_tabs; /* all tables */
+};
+
+/* exported as opaque type "blkid_partition" */
+struct blkid_struct_partition {
+ uint64_t start; /* begin of the partition (512-bytes sectors) */
+ uint64_t size; /* size of the partitions (512-bytes sectors) */
+
+ int type; /* partition type */
+ char typestr[UUID_STR_LEN]; /* partition type string (GPT and Mac) */
+
+ unsigned long long flags; /* partition flags / attributes */
+
+ int partno; /* partition number */
+ char uuid[UUID_STR_LEN]; /* UUID (when supported by PT), e.g. GPT */
+ unsigned char name[128]; /* Partition in UTF8 name (when supported by PT), e.g. Mac */
+
+ blkid_parttable tab; /* partition table */
+};
+
+/* exported as opaque type "blkid_partlist" */
+struct blkid_struct_partlist {
+ int next_partno; /* next partition number */
+ blkid_partition next_parent; /* next parent if parsing nested PT */
+
+ int nparts; /* number of partitions */
+ int nparts_max; /* max.number of partitions */
+ blkid_partition parts; /* array of partitions */
+
+ struct list_head l_tabs; /* list of partition tables */
+};
+
+static int blkid_partitions_probe_partition(blkid_probe pr);
+
+/**
+ * blkid_probe_enable_partitions:
+ * @pr: probe
+ * @enable: TRUE/FALSE
+ *
+ * Enables/disables the partitions probing for non-binary interface.
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ */
+int blkid_probe_enable_partitions(blkid_probe pr, int enable)
+{
+ pr->chains[BLKID_CHAIN_PARTS].enabled = enable;
+ return 0;
+}
+
+/**
+ * blkid_probe_set_partitions_flags:
+ * @pr: prober
+ * @flags: BLKID_PARTS_* flags
+ *
+ * Sets probing flags to the partitions prober. This function is optional.
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ */
+int blkid_probe_set_partitions_flags(blkid_probe pr, int flags)
+{
+ pr->chains[BLKID_CHAIN_PARTS].flags = flags;
+ return 0;
+}
+
+/**
+ * blkid_probe_reset_partitions_filter:
+ * @pr: prober
+ *
+ * Resets partitions probing filter
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ */
+int blkid_probe_reset_partitions_filter(blkid_probe pr)
+{
+ return __blkid_probe_reset_filter(pr, BLKID_CHAIN_PARTS);
+}
+
+/**
+ * blkid_probe_invert_partitions_filter:
+ * @pr: prober
+ *
+ * Inverts partitions probing filter
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ */
+int blkid_probe_invert_partitions_filter(blkid_probe pr)
+{
+ return __blkid_probe_invert_filter(pr, BLKID_CHAIN_PARTS);
+}
+
+/**
+ * blkid_probe_filter_partitions_type:
+ * @pr: prober
+ * @flag: filter BLKID_FLTR_{NOTIN,ONLYIN} flag
+ * @names: NULL terminated array of probing function names (e.g. "vfat").
+ *
+ * %BLKID_FLTR_NOTIN - probe for all items which are NOT IN @names
+ *
+ * %BLKID_FLTR_ONLYIN - probe for items which are IN @names
+ *
+ * Returns: 0 on success, or -1 in case of error.
+ */
+int blkid_probe_filter_partitions_type(blkid_probe pr, int flag, char *names[])
+{
+ return __blkid_probe_filter_types(pr, BLKID_CHAIN_PARTS, flag, names);
+}
+
+/**
+ * blkid_probe_get_partitions:
+ * @pr: probe
+ *
+ * This is a binary interface for partitions. See also blkid_partlist_*
+ * functions.
+ *
+ * This function is independent on blkid_do_[safe,full]probe() and
+ * blkid_probe_enable_partitions() calls.
+ *
+ * WARNING: the returned object will be overwritten by the next
+ * blkid_probe_get_partitions() call for the same @pr. If you want to
+ * use more blkid_partlist objects in the same time you have to create
+ * more blkid_probe handlers (see blkid_new_probe()).
+ *
+ * Returns: list of partitions, or NULL in case of error.
+ */
+blkid_partlist blkid_probe_get_partitions(blkid_probe pr)
+{
+ return (blkid_partlist) blkid_probe_get_binary_data(pr,
+ &pr->chains[BLKID_CHAIN_PARTS]);
+}
+
+/* for internal usage only */
+blkid_partlist blkid_probe_get_partlist(blkid_probe pr)
+{
+ return (blkid_partlist) pr->chains[BLKID_CHAIN_PARTS].data;
+}
+
+static void blkid_probe_set_partlist(blkid_probe pr, blkid_partlist ls)
+{
+ pr->chains[BLKID_CHAIN_PARTS].data = ls;
+}
+
+static void ref_parttable(blkid_parttable tab)
+{
+ if (tab)
+ tab->nparts++;
+}
+
+static void unref_parttable(blkid_parttable tab)
+{
+ if (!tab)
+ return;
+
+ tab->nparts--;
+ if (tab->nparts <= 0) {
+ list_del(&tab->t_tabs);
+ free(tab);
+ }
+}
+
+/* free all allocated parttables */
+static void free_parttables(blkid_partlist ls)
+{
+ if (!ls || !ls->l_tabs.next)
+ return;
+
+ /* remove unassigned partition tables */
+ while (!list_empty(&ls->l_tabs)) {
+ blkid_parttable tab = list_entry(ls->l_tabs.next,
+ struct blkid_struct_parttable, t_tabs);
+ unref_parttable(tab);
+ }
+}
+
+static void reset_partlist(blkid_partlist ls)
+{
+ if (!ls)
+ return;
+
+ free_parttables(ls);
+
+ if (ls->next_partno) {
+ /* already initialized - reset */
+ int tmp_nparts = ls->nparts_max;
+ blkid_partition tmp_parts = ls->parts;
+
+ memset(ls, 0, sizeof(struct blkid_struct_partlist));
+
+ ls->nparts_max = tmp_nparts;
+ ls->parts = tmp_parts;
+ }
+
+ ls->nparts = 0;
+ ls->next_partno = 1;
+ INIT_LIST_HEAD(&ls->l_tabs);
+
+ DBG(LOWPROBE, ul_debug("partlist reset"));
+}
+
+static blkid_partlist partitions_init_data(struct blkid_chain *chn)
+{
+ blkid_partlist ls;
+
+ if (chn->data)
+ ls = (blkid_partlist) chn->data;
+ else {
+ /* allocate the new list of partitions */
+ ls = calloc(1, sizeof(struct blkid_struct_partlist));
+ if (!ls)
+ return NULL;
+ chn->data = (void *) ls;
+ }
+
+ reset_partlist(ls);
+
+ DBG(LOWPROBE, ul_debug("parts: initialized partitions list (size=%d)", ls->nparts_max));
+ return ls;
+}
+
+static void partitions_free_data(blkid_probe pr __attribute__((__unused__)),
+ void *data)
+{
+ blkid_partlist ls = (blkid_partlist) data;
+
+ if (!ls)
+ return;
+
+ free_parttables(ls);
+
+ /* deallocate partitions and partlist */
+ free(ls->parts);
+ free(ls);
+}
+
+blkid_parttable blkid_partlist_new_parttable(blkid_partlist ls,
+ const char *type, uint64_t offset)
+{
+ blkid_parttable tab;
+
+ tab = calloc(1, sizeof(struct blkid_struct_parttable));
+ if (!tab)
+ return NULL;
+ tab->type = type;
+ tab->offset = offset;
+ tab->parent = ls->next_parent;
+
+ INIT_LIST_HEAD(&tab->t_tabs);
+ list_add_tail(&tab->t_tabs, &ls->l_tabs);
+
+ DBG(LOWPROBE, ul_debug("parts: create a new partition table "
+ "(type=%s, offset=%"PRId64")", type, offset));
+ return tab;
+}
+
+static blkid_partition new_partition(blkid_partlist ls, blkid_parttable tab)
+{
+ blkid_partition par;
+
+ if (ls->nparts + 1 > ls->nparts_max) {
+ /* Linux kernel has DISK_MAX_PARTS=256, but it's too much for
+ * generic Linux machine -- let start with 32 partitions.
+ */
+ void *tmp = realloc(ls->parts, (ls->nparts_max + 32) *
+ sizeof(struct blkid_struct_partition));
+ if (!tmp)
+ return NULL;
+ ls->parts = tmp;
+ ls->nparts_max += 32;
+ }
+
+ par = &ls->parts[ls->nparts++];
+ memset(par, 0, sizeof(struct blkid_struct_partition));
+
+ ref_parttable(tab);
+ par->tab = tab;
+ par->partno = blkid_partlist_increment_partno(ls);
+
+ return par;
+}
+
+blkid_partition blkid_partlist_add_partition(blkid_partlist ls,
+ blkid_parttable tab, uint64_t start, uint64_t size)
+{
+ blkid_partition par = new_partition(ls, tab);
+
+ if (!par)
+ return NULL;
+
+ par->start = start;
+ par->size = size;
+
+ DBG(LOWPROBE, ul_debug("parts: add partition (start=%"
+ PRIu64 ", size=%" PRIu64 ")",
+ par->start, par->size));
+ return par;
+}
+
+/* can be used to modify used partitions numbers (for example for logical partitions) */
+int blkid_partlist_set_partno(blkid_partlist ls, int partno)
+{
+ if (!ls)
+ return -1;
+ ls->next_partno = partno;
+ return 0;
+}
+
+int blkid_partlist_increment_partno(blkid_partlist ls)
+{
+ return ls ? ls->next_partno++ : -1;
+}
+
+/* can be used to set "parent" for the next nested partition */
+static int blkid_partlist_set_parent(blkid_partlist ls, blkid_partition par)
+{
+ if (!ls)
+ return -1;
+ ls->next_parent = par;
+ return 0;
+}
+
+blkid_partition blkid_partlist_get_parent(blkid_partlist ls)
+{
+ if (!ls)
+ return NULL;
+ return ls->next_parent;
+}
+
+int blkid_partitions_need_typeonly(blkid_probe pr)
+{
+ struct blkid_chain *chn = blkid_probe_get_chain(pr);
+
+ return chn && chn->data && chn->binary ? FALSE : TRUE;
+}
+
+/* get private chain flags */
+int blkid_partitions_get_flags(blkid_probe pr)
+{
+ struct blkid_chain *chn = blkid_probe_get_chain(pr);
+
+ return chn ? chn->flags : 0;
+}
+
+/* check if @start and @size are within @par partition */
+int blkid_is_nested_dimension(blkid_partition par,
+ uint64_t start, uint64_t size)
+{
+ uint64_t pstart;
+ uint64_t psize;
+
+ if (!par)
+ return 0;
+
+ pstart = blkid_partition_get_start(par);
+ psize = blkid_partition_get_size(par);
+
+ if (start < pstart || start + size > pstart + psize)
+ return 0;
+
+ return 1;
+}
+
+static int idinfo_probe(blkid_probe pr, const struct blkid_idinfo *id,
+ struct blkid_chain *chn)
+{
+ const struct blkid_idmag *mag = NULL;
+ uint64_t off;
+ int rc = BLKID_PROBE_NONE; /* default is nothing */
+
+ if (pr->size <= 0 || (id->minsz && (unsigned)id->minsz > pr->size))
+ goto nothing; /* the device is too small */
+ if (pr->flags & BLKID_FL_NOSCAN_DEV)
+ goto nothing;
+
+ rc = blkid_probe_get_idmag(pr, id, &off, &mag);
+ if (rc != BLKID_PROBE_OK)
+ goto nothing;
+
+ /* final check by probing function */
+ if (id->probefunc) {
+ DBG(LOWPROBE, ul_debug(
+ "%s: ---> call probefunc()", id->name));
+ rc = id->probefunc(pr, mag);
+ if (rc < 0) {
+ /* reset after error */
+ reset_partlist(blkid_probe_get_partlist(pr));
+ if (chn && !chn->binary)
+ blkid_probe_chain_reset_values(pr, chn);
+ DBG(LOWPROBE, ul_debug("%s probefunc failed, rc %d",
+ id->name, rc));
+ }
+ if (rc == BLKID_PROBE_OK && mag && chn && !chn->binary)
+ rc = blkid_probe_set_magic(pr, off, mag->len,
+ (const unsigned char *) mag->magic);
+
+ DBG(LOWPROBE, ul_debug("%s: <--- (rc = %d)", id->name, rc));
+ }
+
+ return rc;
+
+nothing:
+ return BLKID_PROBE_NONE;
+}
+
+/*
+ * The blkid_do_probe() backend.
+ */
+static int partitions_probe(blkid_probe pr, struct blkid_chain *chn)
+{
+ int rc = BLKID_PROBE_NONE;
+ size_t i;
+
+ if (!pr || chn->idx < -1)
+ return -EINVAL;
+
+ blkid_probe_chain_reset_values(pr, chn);
+
+ if (pr->flags & BLKID_FL_NOSCAN_DEV)
+ return BLKID_PROBE_NONE;
+
+ if (chn->binary)
+ partitions_init_data(chn);
+
+ if (!pr->wipe_size && (pr->prob_flags & BLKID_PROBE_FL_IGNORE_PT))
+ goto details_only;
+
+ DBG(LOWPROBE, ul_debug("--> starting probing loop [PARTS idx=%d]",
+ chn->idx));
+
+ i = chn->idx < 0 ? 0 : chn->idx + 1U;
+
+ for ( ; i < ARRAY_SIZE(idinfos); i++) {
+ const char *name;
+
+ chn->idx = i;
+
+ /* apply filter */
+ if (chn->fltr && blkid_bmp_get_item(chn->fltr, i))
+ continue;
+
+ /* apply checks from idinfo */
+ rc = idinfo_probe(pr, idinfos[i], chn);
+ if (rc < 0)
+ break;
+ if (rc != BLKID_PROBE_OK)
+ continue;
+
+ name = idinfos[i]->name;
+
+ if (!chn->binary)
+ /*
+ * Non-binary interface, set generic variables. Note
+ * that the another variables could be set in prober
+ * functions.
+ */
+ blkid_probe_set_value(pr, "PTTYPE",
+ (const unsigned char *) name,
+ strlen(name) + 1);
+
+ DBG(LOWPROBE, ul_debug("<-- leaving probing loop (type=%s) [PARTS idx=%d]",
+ name, chn->idx));
+ rc = BLKID_PROBE_OK;
+ break;
+ }
+
+ if (rc != BLKID_PROBE_OK) {
+ DBG(LOWPROBE, ul_debug("<-- leaving probing loop (failed=%d) [PARTS idx=%d]",
+ rc, chn->idx));
+ }
+
+details_only:
+ /*
+ * Gather PART_ENTRY_* values if the current device is a partition.
+ */
+ if ((rc == BLKID_PROBE_OK || rc == BLKID_PROBE_NONE) && !chn->binary &&
+ (blkid_partitions_get_flags(pr) & BLKID_PARTS_ENTRY_DETAILS)) {
+
+ int xrc = blkid_partitions_probe_partition(pr);
+
+ /* partition entry probing is optional, and "not-found" from
+ * this sub-probing must not to overwrite previous success. */
+ if (xrc < 0)
+ rc = xrc; /* always propagate errors */
+ else if (rc == BLKID_PROBE_NONE)
+ rc = xrc;
+ }
+
+ DBG(LOWPROBE, ul_debug("partitions probe done [rc=%d]", rc));
+ return rc;
+}
+
+/* Probe for nested partition table within the parental partition */
+int blkid_partitions_do_subprobe(blkid_probe pr, blkid_partition parent,
+ const struct blkid_idinfo *id)
+{
+ blkid_probe prc;
+ int rc;
+ blkid_partlist ls;
+ uint64_t sz, off;
+
+ DBG(LOWPROBE, ul_debug(
+ "parts: ----> %s subprobe requested)",
+ id->name));
+
+ if (!pr || !parent || !parent->size)
+ return -EINVAL;
+ if (pr->flags & BLKID_FL_NOSCAN_DEV)
+ return BLKID_PROBE_NONE;
+
+ /* range defined by parent */
+ sz = parent->size << 9;
+ off = parent->start << 9;
+
+ if (off < pr->off || pr->off + pr->size < off + sz) {
+ DBG(LOWPROBE, ul_debug(
+ "ERROR: parts: <---- '%s' subprobe: overflow detected.",
+ id->name));
+ return -ENOSPC;
+ }
+
+ /* create private prober */
+ prc = blkid_clone_probe(pr);
+ if (!prc)
+ return -ENOMEM;
+
+ blkid_probe_set_dimension(prc, off, sz);
+
+ /* clone is always with reset chain, fix it */
+ prc->cur_chain = blkid_probe_get_chain(pr);
+
+ /*
+ * Set 'parent' to the current list of the partitions and use the list
+ * in cloned prober (so the cloned prober will extend the current list
+ * of partitions rather than create a new).
+ */
+ ls = blkid_probe_get_partlist(pr);
+ blkid_partlist_set_parent(ls, parent);
+
+ blkid_probe_set_partlist(prc, ls);
+
+ rc = idinfo_probe(prc, id, blkid_probe_get_chain(pr));
+
+ blkid_probe_set_partlist(prc, NULL);
+ blkid_partlist_set_parent(ls, NULL);
+
+ blkid_free_probe(prc); /* free cloned prober */
+
+ DBG(LOWPROBE, ul_debug(
+ "parts: <---- %s subprobe done (rc=%d)",
+ id->name, rc));
+
+ return rc;
+}
+
+static int blkid_partitions_probe_partition(blkid_probe pr)
+{
+ blkid_probe disk_pr = NULL;
+ blkid_partlist ls;
+ blkid_partition par;
+ dev_t devno;
+
+ DBG(LOWPROBE, ul_debug("parts: start probing for partition entry"));
+
+ if (pr->flags & BLKID_FL_NOSCAN_DEV)
+ goto nothing;
+
+ devno = blkid_probe_get_devno(pr);
+ if (!devno)
+ goto nothing;
+
+ disk_pr = blkid_probe_get_wholedisk_probe(pr);
+ if (!disk_pr)
+ goto nothing;
+
+ /* parse PT */
+ ls = blkid_probe_get_partitions(disk_pr);
+ if (!ls)
+ goto nothing;
+
+ par = blkid_partlist_devno_to_partition(ls, devno);
+ if (!par)
+ goto nothing;
+ else {
+ const char *v;
+ blkid_parttable tab = blkid_partition_get_table(par);
+ dev_t disk = blkid_probe_get_devno(disk_pr);
+
+ if (tab) {
+ v = blkid_parttable_get_type(tab);
+ if (v)
+ blkid_probe_set_value(pr, "PART_ENTRY_SCHEME",
+ (const unsigned char *) v, strlen(v) + 1);
+ }
+
+ v = blkid_partition_get_name(par);
+ if (v)
+ blkid_probe_set_value(pr, "PART_ENTRY_NAME",
+ (const unsigned char *) v, strlen(v) + 1);
+
+ v = blkid_partition_get_uuid(par);
+ if (v)
+ blkid_probe_set_value(pr, "PART_ENTRY_UUID",
+ (const unsigned char *) v, strlen(v) + 1);
+
+ /* type */
+ v = blkid_partition_get_type_string(par);
+ if (v)
+ blkid_probe_set_value(pr, "PART_ENTRY_TYPE",
+ (const unsigned char *) v, strlen(v) + 1);
+ else
+ blkid_probe_sprintf_value(pr, "PART_ENTRY_TYPE",
+ "0x%x", blkid_partition_get_type(par));
+
+ if (blkid_partition_get_flags(par))
+ blkid_probe_sprintf_value(pr, "PART_ENTRY_FLAGS",
+ "0x%llx", blkid_partition_get_flags(par));
+
+ blkid_probe_sprintf_value(pr, "PART_ENTRY_NUMBER",
+ "%d", blkid_partition_get_partno(par));
+
+ blkid_probe_sprintf_value(pr, "PART_ENTRY_OFFSET", "%jd",
+ (intmax_t)blkid_partition_get_start(par));
+ blkid_probe_sprintf_value(pr, "PART_ENTRY_SIZE", "%jd",
+ (intmax_t)blkid_partition_get_size(par));
+
+ blkid_probe_sprintf_value(pr, "PART_ENTRY_DISK", "%u:%u",
+ major(disk), minor(disk));
+ }
+
+ DBG(LOWPROBE, ul_debug("parts: end probing for partition entry [success]"));
+ return BLKID_PROBE_OK;
+
+nothing:
+ DBG(LOWPROBE, ul_debug("parts: end probing for partition entry [nothing]"));
+ return BLKID_PROBE_NONE;
+
+
+}
+
+/*
+ * Returns 1 if the device is whole-disk and the area specified by @offset and
+ * @size is covered by any partition.
+ */
+int blkid_probe_is_covered_by_pt(blkid_probe pr,
+ uint64_t offset, uint64_t size)
+{
+ blkid_probe prc = NULL;
+ blkid_partlist ls = NULL;
+ uint64_t start, end;
+ int nparts, i, rc = 0;
+
+ DBG(LOWPROBE, ul_debug(
+ "=> checking if off=%"PRIu64" size=%"PRIu64" covered by PT",
+ offset, size));
+
+ if (pr->flags & BLKID_FL_NOSCAN_DEV)
+ goto done;
+
+ prc = blkid_clone_probe(pr);
+ if (!prc)
+ goto done;
+
+ ls = blkid_probe_get_partitions(prc);
+ if (!ls)
+ goto done;
+
+ nparts = blkid_partlist_numof_partitions(ls);
+ if (!nparts)
+ goto done;
+
+ end = (offset + size) >> 9;
+ start = offset >> 9;
+
+ /* check if the partition table fits into the device */
+ for (i = 0; i < nparts; i++) {
+ blkid_partition par = &ls->parts[i];
+
+ if (par->start + par->size > (pr->size >> 9)) {
+ DBG(LOWPROBE, ul_debug("partition #%d overflows "
+ "device (off=%" PRId64 " size=%" PRId64 ")",
+ par->partno, par->start, par->size));
+ goto done;
+ }
+ }
+
+ /* check if the requested area is covered by PT */
+ for (i = 0; i < nparts; i++) {
+ blkid_partition par = &ls->parts[i];
+
+ if (start >= par->start && end <= par->start + par->size) {
+ rc = 1;
+ break;
+ }
+ }
+done:
+ blkid_free_probe(prc);
+
+ DBG(LOWPROBE, ul_debug("<= %s covered by PT", rc ? "IS" : "NOT"));
+ return rc;
+}
+
+/**
+ * blkid_known_pttype:
+ * @pttype: partition name
+ *
+ * Returns: 1 for known or 0 for unknown partition type.
+ */
+int blkid_known_pttype(const char *pttype)
+{
+ size_t i;
+
+ if (!pttype)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(idinfos); i++) {
+ const struct blkid_idinfo *id = idinfos[i];
+ if (strcmp(id->name, pttype) == 0)
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * blkid_partitions_get_name:
+ * @idx: number >= 0
+ * @name: returns name of a supported partition
+ *
+ * Since: 2.30
+ *
+ * Returns: -1 if @idx is out of range, or 0 on success.
+ */
+int blkid_partitions_get_name(const size_t idx, const char **name)
+{
+ if (idx < ARRAY_SIZE(idinfos)) {
+ *name = idinfos[idx]->name;
+ return 0;
+ }
+ return -1;
+}
+
+/**
+ * blkid_partlist_numof_partitions:
+ * @ls: partitions list
+ *
+ * Returns: number of partitions in the list or -1 in case of error.
+ */
+int blkid_partlist_numof_partitions(blkid_partlist ls)
+{
+ return ls->nparts;
+}
+
+/**
+ * blkid_partlist_get_table:
+ * @ls: partitions list
+ *
+ * Returns: top-level partition table or NULL if there is not a partition table
+ * on the device.
+ */
+blkid_parttable blkid_partlist_get_table(blkid_partlist ls)
+{
+ if (list_empty(&ls->l_tabs))
+ return NULL;
+
+ return list_entry(ls->l_tabs.next,
+ struct blkid_struct_parttable, t_tabs);
+}
+
+
+/**
+ * blkid_partlist_get_partition:
+ * @ls: partitions list
+ * @n: partition number in range 0..N, where 'N' is blkid_partlist_numof_partitions().
+ *
+ * It's possible that the list of partitions is *empty*, but there is a valid
+ * partition table on the disk. This happen when on-disk details about
+ * partitions are unknown or the partition table is empty.
+ *
+ * See also blkid_partlist_get_table().
+ *
+ * Returns: partition object or NULL in case or error.
+ */
+blkid_partition blkid_partlist_get_partition(blkid_partlist ls, int n)
+{
+ if (n < 0 || n >= ls->nparts)
+ return NULL;
+
+ return &ls->parts[n];
+}
+
+blkid_partition blkid_partlist_get_partition_by_start(blkid_partlist ls, uint64_t start)
+{
+ int i, nparts;
+ blkid_partition par;
+
+ nparts = blkid_partlist_numof_partitions(ls);
+ for (i = 0; i < nparts; i++) {
+ par = blkid_partlist_get_partition(ls, i);
+ if ((uint64_t) blkid_partition_get_start(par) == start)
+ return par;
+ }
+ return NULL;
+}
+
+/**
+ * blkid_partlist_get_partition_by_partno
+ * @ls: partitions list
+ * @n: the partition number (e.g. 'N' from sda'N')
+ *
+ * This does not assume any order of the input blkid_partlist. And correctly
+ * handles "out of order" partition tables. partition N is located after
+ * partition N+1 on the disk.
+ *
+ * Returns: partition object or NULL in case or error.
+ */
+blkid_partition blkid_partlist_get_partition_by_partno(blkid_partlist ls, int n)
+{
+ int i, nparts;
+ blkid_partition par;
+
+ nparts = blkid_partlist_numof_partitions(ls);
+ for (i = 0; i < nparts; i++) {
+ par = blkid_partlist_get_partition(ls, i);
+ if (n == blkid_partition_get_partno(par))
+ return par;
+ }
+ return NULL;
+}
+
+
+/**
+ * blkid_partlist_devno_to_partition:
+ * @ls: partitions list
+ * @devno: requested partition
+ *
+ * This function tries to get start and size for @devno from sysfs and
+ * returns a partition from @ls which matches with the values from sysfs.
+ *
+ * This function is necessary when you want to make a relation between an entry
+ * in the partition table (@ls) and block devices in your system.
+ *
+ * Returns: partition object or NULL in case or error.
+ */
+blkid_partition blkid_partlist_devno_to_partition(blkid_partlist ls, dev_t devno)
+{
+ struct path_cxt *pc;
+ uint64_t start = 0, size;
+ int i, rc, partno = 0;
+
+ DBG(LOWPROBE, ul_debug("trying to convert devno 0x%llx to partition",
+ (long long) devno));
+
+
+ pc = ul_new_sysfs_path(devno, NULL, NULL);
+ if (!pc) {
+ DBG(LOWPROBE, ul_debug("failed t init sysfs context"));
+ return NULL;
+ }
+ rc = ul_path_read_u64(pc, &size, "size");
+ if (!rc) {
+ rc = ul_path_read_u64(pc, &start, "start");
+ if (rc) {
+ /* try to get partition number from DM uuid.
+ */
+ char *uuid = NULL, *tmp, *prefix;
+
+ ul_path_read_string(pc, &uuid, "dm/uuid");
+ tmp = uuid;
+ prefix = uuid ? strsep(&tmp, "-") : NULL;
+
+ if (prefix && strncasecmp(prefix, "part", 4) == 0) {
+ char *end = NULL;
+
+ errno = 0;
+ partno = strtol(prefix + 4, &end, 10);
+ if (errno || prefix == end || (end && *end))
+ partno = 0;
+ else
+ rc = 0; /* success */
+ }
+ free(uuid);
+ }
+ }
+
+ ul_unref_path(pc);
+
+ if (rc)
+ return NULL;
+
+ if (partno) {
+ DBG(LOWPROBE, ul_debug("mapped by DM, using partno %d", partno));
+
+ /*
+ * Partition mapped by kpartx does not provide "start" offset
+ * in /sys, but if we know partno and size of the partition
+ * that we can probably make the relation between the device
+ * and an entry in partition table.
+ */
+ for (i = 0; i < ls->nparts; i++) {
+ blkid_partition par = &ls->parts[i];
+
+ if (partno != blkid_partition_get_partno(par))
+ continue;
+
+ if (size == (uint64_t)blkid_partition_get_size(par) ||
+ (blkid_partition_is_extended(par) && size <= 1024ULL))
+ return par;
+
+ }
+ return NULL;
+ }
+
+ DBG(LOWPROBE, ul_debug("searching by offset/size"));
+
+ for (i = 0; i < ls->nparts; i++) {
+ blkid_partition par = &ls->parts[i];
+
+ if ((uint64_t)blkid_partition_get_start(par) == start &&
+ (uint64_t)blkid_partition_get_size(par) == size)
+ return par;
+
+ /* exception for extended dos partitions */
+ if ((uint64_t)blkid_partition_get_start(par) == start &&
+ blkid_partition_is_extended(par) && size <= 1024ULL)
+ return par;
+
+ }
+
+ DBG(LOWPROBE, ul_debug("not found partition for device"));
+ return NULL;
+}
+
+
+int blkid_parttable_set_uuid(blkid_parttable tab, const unsigned char *id)
+{
+ if (!tab)
+ return -1;
+
+ blkid_unparse_uuid(id, tab->id, sizeof(tab->id));
+ return 0;
+}
+
+int blkid_parttable_set_id(blkid_parttable tab, const unsigned char *id)
+{
+ if (!tab)
+ return -1;
+
+ xstrncpy(tab->id, (const char *) id, sizeof(tab->id));
+ return 0;
+}
+
+/* set PTUUID variable for non-binary API */
+int blkid_partitions_set_ptuuid(blkid_probe pr, unsigned char *uuid)
+{
+ struct blkid_chain *chn = blkid_probe_get_chain(pr);
+ struct blkid_prval *v;
+
+ if (chn->binary || blkid_uuid_is_empty(uuid, 16))
+ return 0;
+
+ v = blkid_probe_assign_value(pr, "PTUUID");
+ if (!v)
+ return -ENOMEM;
+
+ v->len = UUID_STR_LEN;
+ v->data = calloc(1, v->len);
+ if (v->data) {
+ blkid_unparse_uuid(uuid, (char *) v->data, v->len);
+ return 0;
+ }
+
+ blkid_probe_free_value(v);
+ return -ENOMEM;
+}
+
+/* set PTUUID variable for non-binary API for tables where
+ * the ID is just a string */
+int blkid_partitions_strcpy_ptuuid(blkid_probe pr, char *str)
+{
+ struct blkid_chain *chn = blkid_probe_get_chain(pr);
+
+ if (chn->binary || !str || !*str)
+ return 0;
+
+ if (!blkid_probe_set_value(pr, "PTUUID", (unsigned char *) str, strlen(str) + 1))
+ return -ENOMEM;
+
+ return 0;
+}
+
+/**
+ * blkid_parttable_get_id:
+ * @tab: partition table
+ *
+ * The ID is GPT disk UUID or DOS disk ID (in hex format).
+ *
+ * Returns: partition table ID (for example GPT disk UUID) or NULL
+ */
+const char *blkid_parttable_get_id(blkid_parttable tab)
+{
+ return *tab->id ? tab->id : NULL;
+}
+
+
+int blkid_partition_set_type(blkid_partition par, int type)
+{
+ par->type = type;
+ return 0;
+}
+
+/**
+ * blkid_parttable_get_type:
+ * @tab: partition table
+ *
+ * Returns: partition table type (type name, e.g. "dos", "gpt", ...)
+ */
+const char *blkid_parttable_get_type(blkid_parttable tab)
+{
+ return tab->type;
+}
+
+/**
+ * blkid_parttable_get_parent:
+ * @tab: partition table
+ *
+ * Returns: parent for nested partition tables or NULL.
+ */
+blkid_partition blkid_parttable_get_parent(blkid_parttable tab)
+{
+ return tab->parent;
+}
+
+/**
+ * blkid_parttable_get_offset:
+ * @tab: partition table
+ *
+ * Note the position is relative to begin of the device as defined by
+ * blkid_probe_set_device() for primary partition table, and relative
+ * to parental partition for nested partition tables.
+ *
+ * <informalexample>
+ * <programlisting>
+ * off_t offset;
+ * blkid_partition parent = blkid_parttable_get_parent(tab);
+ *
+ * offset = blkid_parttable_get_offset(tab);
+ *
+ * if (parent)
+ * / * 'tab' is nested partition table * /
+ * offset += blkid_partition_get_start(parent);
+ * </programlisting>
+ * </informalexample>
+
+ * Returns: position (in bytes) of the partition table or -1 in case of error.
+ *
+ */
+blkid_loff_t blkid_parttable_get_offset(blkid_parttable tab)
+{
+ return (blkid_loff_t)tab->offset;
+}
+
+/**
+ * blkid_partition_get_table:
+ * @par: partition
+ *
+ * The "parttable" describes partition table. The table is usually the same for
+ * all partitions -- except nested partition tables.
+ *
+ * For example bsd, solaris, etc. use a nested partition table within
+ * standard primary dos partition:
+ *
+ * <informalexample>
+ * <programlisting>
+ *
+ * -- dos partition table
+ * 0: sda1 dos primary partition
+ * 1: sda2 dos primary partition
+ * -- bsd partition table (with in sda2)
+ * 2: sda5 bds partition
+ * 3: sda6 bds partition
+ *
+ * </programlisting>
+ * </informalexample>
+ *
+ * The library does not to use a separate partition table object for dos logical
+ * partitions (partitions within extended partition). It's possible to
+ * differentiate between logical, extended and primary partitions by
+ *
+ * blkid_partition_is_{extended,primary,logical}().
+ *
+ * Returns: partition table object or NULL in case of error.
+ */
+blkid_parttable blkid_partition_get_table(blkid_partition par)
+{
+ return par->tab;
+}
+
+static int partition_get_logical_type(blkid_partition par)
+{
+ blkid_parttable tab;
+
+ if (!par)
+ return -1;
+
+ tab = blkid_partition_get_table(par);
+ if (!tab || !tab->type)
+ return -1;
+
+ if (tab->parent)
+ return 'L'; /* report nested partitions as logical */
+
+ if (!strcmp(tab->type, "dos")) {
+ if (par->partno > 4)
+ return 'L'; /* logical */
+
+ if(par->type == MBR_DOS_EXTENDED_PARTITION ||
+ par->type == MBR_W95_EXTENDED_PARTITION ||
+ par->type == MBR_LINUX_EXTENDED_PARTITION)
+ return 'E';
+ }
+ return 'P';
+}
+
+/**
+ * blkid_partition_is_primary:
+ * @par: partition
+ *
+ * Note, this function returns FALSE for DOS extended partitions and
+ * all partitions in nested partition tables.
+ *
+ * Returns: 1 if the partitions is primary partition or 0 if not.
+ */
+int blkid_partition_is_primary(blkid_partition par)
+{
+ return partition_get_logical_type(par) == 'P' ? TRUE : FALSE;
+}
+
+/**
+ * blkid_partition_is_extended:
+ * @par: partition
+ *
+ * Returns: 1 if the partitions is extended (dos, windows or linux)
+ * partition or 0 if not.
+ */
+int blkid_partition_is_extended(blkid_partition par)
+{
+ return partition_get_logical_type(par) == 'E' ? TRUE : FALSE;
+}
+
+/**
+ * blkid_partition_is_logical:
+ * @par: partition
+ *
+ * Note that this function returns TRUE for all partitions in all
+ * nested partition tables (e.g. BSD labels).
+ *
+ * Returns: 1 if the partitions is logical partition or 0 if not.
+ */
+int blkid_partition_is_logical(blkid_partition par)
+{
+ return partition_get_logical_type(par) == 'L' ? TRUE : FALSE;
+}
+
+static void set_string(unsigned char *item, size_t max,
+ const unsigned char *data, size_t len)
+{
+ if (len >= max)
+ len = max - 1;
+
+ memcpy(item, data, len);
+ item[len] = '\0';
+
+ blkid_rtrim_whitespace(item);
+}
+
+int blkid_partition_set_name(blkid_partition par,
+ const unsigned char *name, size_t len)
+{
+ if (!par)
+ return -1;
+
+ set_string(par->name, sizeof(par->name), name, len);
+ return 0;
+}
+
+int blkid_partition_set_utf8name(blkid_partition par, const unsigned char *name,
+ size_t len, int enc)
+{
+ if (!par)
+ return -1;
+
+ ul_encode_to_utf8(enc, par->name, sizeof(par->name), name, len);
+ blkid_rtrim_whitespace(par->name);
+ return 0;
+}
+
+int blkid_partition_set_uuid(blkid_partition par, const unsigned char *uuid)
+{
+ if (!par)
+ return -1;
+
+ blkid_unparse_uuid(uuid, par->uuid, sizeof(par->uuid));
+ return 0;
+}
+
+int blkid_partition_gen_uuid(blkid_partition par)
+{
+ if (!par || !par->tab || !*par->tab->id)
+ return -1;
+
+ snprintf(par->uuid, sizeof(par->uuid), "%.33s-%02x",
+ par->tab->id, par->partno);
+ return 0;
+}
+
+/**
+ * blkid_partition_get_name:
+ * @par: partition
+ *
+ * Returns: partition name string if supported by PT (e.g. Mac) or NULL.
+ */
+const char *blkid_partition_get_name(blkid_partition par)
+{
+ return *par->name ? (char *) par->name : NULL;
+}
+
+/**
+ * blkid_partition_get_uuid:
+ * @par: partition
+ *
+ * Returns: partition UUID string if supported by PT (e.g. GPT) or NULL.
+ */
+const char *blkid_partition_get_uuid(blkid_partition par)
+{
+ return *par->uuid ? par->uuid : NULL;
+}
+
+/**
+ * blkid_partition_get_partno:
+ * @par: partition
+ *
+ * Returns: proposed partition number (e.g. 'N' from sda'N') or -1 in case of
+ * error. Note that the number is generated by library independently of your OS.
+ */
+int blkid_partition_get_partno(blkid_partition par)
+{
+ return par->partno;
+}
+
+/**
+ * blkid_partition_get_start:
+ * @par: partition
+ *
+ * Be careful if you _not_ probe whole disk:
+ *
+ * 1) the offset is usually relative to begin of the disk -- but if you probe a
+ * fragment of the disk only -- then the offset could be still relative to
+ * the begin of the disk rather that relative to the fragment.
+ *
+ * 2) the offset for nested partitions could be relative to parent (e.g. Solaris)
+ * _or_ relative to the begin of the whole disk (e.g. bsd).
+ *
+ * You don't have to care about such details if you probe whole disk. In such
+ * a case libblkid always returns the offset relative to the begin of the disk.
+ *
+ * Returns: start of the partition (in 512-sectors).
+ */
+blkid_loff_t blkid_partition_get_start(blkid_partition par)
+{
+ return (blkid_loff_t)par->start;
+}
+
+/**
+ * blkid_partition_get_size:
+ * @par: partition
+ *
+ * WARNING: be very careful when you work with MS-DOS extended partitions. The
+ * library always returns full size of the partition. If you want to
+ * add the partition to the Linux system (BLKPG_ADD_PARTITION ioctl)
+ * you need to reduce the size of the partition to 1 or 2 blocks. The
+ * rest of the partition has to be inaccessible for mkfs or mkswap
+ * programs, we need a small space for boot loaders only.
+ *
+ * For some unknown reason this (safe) practice is not to used for
+ * nested BSD, Solaris, ..., partition tables in Linux kernel.
+ *
+ * Returns: size of the partition (in 512-sectors).
+ */
+blkid_loff_t blkid_partition_get_size(blkid_partition par)
+{
+ return (blkid_loff_t)par->size;
+}
+
+/**
+ * blkid_partition_get_type:
+ * @par: partition
+ *
+ * Returns: partition type.
+ */
+int blkid_partition_get_type(blkid_partition par)
+{
+ return par->type;
+}
+
+/* Sets partition 'type' for PT where the type is defined by string rather
+ * than by number
+ */
+int blkid_partition_set_type_string(blkid_partition par,
+ const unsigned char *type, size_t len)
+{
+ set_string((unsigned char *) par->typestr,
+ sizeof(par->typestr), type, len);
+ return 0;
+}
+
+/* Sets partition 'type' for PT where the type is defined by UUID rather
+ * than by number
+ */
+int blkid_partition_set_type_uuid(blkid_partition par, const unsigned char *uuid)
+{
+ blkid_unparse_uuid(uuid, par->typestr, sizeof(par->typestr));
+ return 0;
+}
+
+/**
+ * blkid_partition_get_type_string:
+ * @par: partition
+ *
+ * The type string is supported by a small subset of partition tables (e.g. Mac
+ * and EFI GPT). Note that GPT uses type UUID and this function returns this
+ * UUID as string.
+ *
+ * Returns: partition type string or NULL.
+ */
+const char *blkid_partition_get_type_string(blkid_partition par)
+{
+ return *par->typestr ? par->typestr : NULL;
+}
+
+
+int blkid_partition_set_flags(blkid_partition par, unsigned long long flags)
+{
+ par->flags = flags;
+ return 0;
+}
+
+/**
+ * blkid_partition_get_flags
+ * @par: partition
+ *
+ * Returns: partition flags (or attributes for gpt).
+ */
+unsigned long long blkid_partition_get_flags(blkid_partition par)
+{
+ return par->flags;
+}
+
diff --git a/libblkid/src/partitions/partitions.h b/libblkid/src/partitions/partitions.h
new file mode 100644
index 0000000..4a718f4
--- /dev/null
+++ b/libblkid/src/partitions/partitions.h
@@ -0,0 +1,74 @@
+#ifndef BLKID_PARTITIONS_H
+#define BLKID_PARTITIONS_H
+
+#include "blkidP.h"
+#include "pt-mbr.h"
+
+extern int blkid_partitions_get_flags(blkid_probe pr);
+
+extern blkid_parttable blkid_partlist_new_parttable(blkid_partlist ls,
+ const char *type, uint64_t offset);
+
+extern int blkid_parttable_set_uuid(blkid_parttable tab, const unsigned char *id);
+extern int blkid_parttable_set_id(blkid_parttable tab, const unsigned char *id);
+
+extern blkid_partition blkid_partlist_add_partition(blkid_partlist ls,
+ blkid_parttable tab,
+ uint64_t start, uint64_t size);
+
+extern int blkid_partlist_set_partno(blkid_partlist ls, int partno);
+extern int blkid_partlist_increment_partno(blkid_partlist ls);
+
+extern blkid_partition blkid_partlist_get_parent(blkid_partlist ls);
+
+extern blkid_partition blkid_partlist_get_partition_by_start(blkid_partlist ls, uint64_t start);
+
+extern int blkid_partitions_do_subprobe(blkid_probe pr,
+ blkid_partition parent, const struct blkid_idinfo *id);
+
+extern int blkid_partitions_need_typeonly(blkid_probe pr);
+extern int blkid_partitions_set_ptuuid(blkid_probe pr, unsigned char *uuid);
+extern int blkid_partitions_strcpy_ptuuid(blkid_probe pr, char *str);
+
+
+extern int blkid_is_nested_dimension(blkid_partition par,
+ uint64_t start, uint64_t size);
+
+extern int blkid_partition_set_name(blkid_partition par,
+ const unsigned char *name, size_t len);
+
+extern int blkid_partition_set_utf8name(blkid_partition par,
+ const unsigned char *name, size_t len, int enc);
+
+extern int blkid_partition_set_uuid(blkid_partition par,
+ const unsigned char *uuid);
+extern int blkid_partition_gen_uuid(blkid_partition par);
+
+extern int blkid_partition_set_type(blkid_partition par, int type);
+
+extern int blkid_partition_set_type_string(blkid_partition par,
+ const unsigned char *type, size_t len);
+
+extern int blkid_partition_set_type_uuid(blkid_partition par,
+ const unsigned char *uuid);
+
+extern int blkid_partition_set_flags(blkid_partition par, unsigned long long flags);
+
+/*
+ * partition probers
+ */
+extern const struct blkid_idinfo aix_pt_idinfo;
+extern const struct blkid_idinfo bsd_pt_idinfo;
+extern const struct blkid_idinfo unixware_pt_idinfo;
+extern const struct blkid_idinfo solaris_x86_pt_idinfo;
+extern const struct blkid_idinfo sun_pt_idinfo;
+extern const struct blkid_idinfo sgi_pt_idinfo;
+extern const struct blkid_idinfo mac_pt_idinfo;
+extern const struct blkid_idinfo dos_pt_idinfo;
+extern const struct blkid_idinfo minix_pt_idinfo;
+extern const struct blkid_idinfo gpt_pt_idinfo;
+extern const struct blkid_idinfo pmbr_pt_idinfo;
+extern const struct blkid_idinfo ultrix_pt_idinfo;
+extern const struct blkid_idinfo atari_pt_idinfo;
+
+#endif /* BLKID_PARTITIONS_H */
diff --git a/libblkid/src/partitions/sgi.c b/libblkid/src/partitions/sgi.c
new file mode 100644
index 0000000..99c0bf1
--- /dev/null
+++ b/libblkid/src/partitions/sgi.c
@@ -0,0 +1,87 @@
+/*
+ * sgi partition parsing code
+ *
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "partitions.h"
+#include "pt-sgi.h"
+
+static int probe_sgi_pt(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ struct sgi_disklabel *l;
+ struct sgi_partition *p;
+ blkid_parttable tab = NULL;
+ blkid_partlist ls;
+ int i;
+
+ l = (struct sgi_disklabel *) blkid_probe_get_sector(pr, 0);
+ if (!l) {
+ if (errno)
+ return -errno;
+ goto nothing;
+ }
+
+ if (sgi_pt_checksum(l)) {
+ DBG(LOWPROBE, ul_debug(
+ "detected corrupted sgi disk label -- ignore"));
+ goto nothing;
+ }
+
+ if (blkid_partitions_need_typeonly(pr))
+ /* caller does not ask for details about partitions */
+ return BLKID_PROBE_OK;
+
+ ls = blkid_probe_get_partlist(pr);
+ if (!ls)
+ goto nothing;
+
+ tab = blkid_partlist_new_parttable(ls, "sgi", 0);
+ if (!tab)
+ goto err;
+
+ for(i = 0, p = &l->partitions[0]; i < SGI_MAXPARTITIONS; i++, p++) {
+ uint32_t size = be32_to_cpu(p->num_blocks);
+ uint32_t start = be32_to_cpu(p->first_block);
+ uint32_t type = be32_to_cpu(p->type);
+ blkid_partition par;
+
+ if (!size) {
+ blkid_partlist_increment_partno(ls);
+ continue;
+ }
+ par = blkid_partlist_add_partition(ls, tab, start, size);
+ if (!par)
+ goto err;
+
+ blkid_partition_set_type(par, type);
+ }
+
+ return BLKID_PROBE_OK;
+
+nothing:
+ return BLKID_PROBE_NONE;
+err:
+ return -ENOMEM;
+}
+
+const struct blkid_idinfo sgi_pt_idinfo =
+{
+ .name = "sgi",
+ .probefunc = probe_sgi_pt,
+ .magics =
+ {
+ { .magic = "\x0B\xE5\xA9\x41", .len = 4 },
+ { NULL }
+ }
+};
+
diff --git a/libblkid/src/partitions/solaris_x86.c b/libblkid/src/partitions/solaris_x86.c
new file mode 100644
index 0000000..df1def5
--- /dev/null
+++ b/libblkid/src/partitions/solaris_x86.c
@@ -0,0 +1,154 @@
+/*
+ * Solaris x86 partition parsing code
+ *
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "partitions.h"
+
+/*
+ * Solaris-x86 is always within primary dos partition (nested PT table). The
+ * solaris-x86 vtoc can be used to split the entire partition to "slices". The
+ * offset (start) of the slice is always relatively to the primary dos
+ * partition.
+ *
+ * Note that Solaris-SPARC uses entire disk with a different partitioning
+ * scheme.
+ */
+
+/* some other implementation than Linux kernel assume 8 partitions only */
+#define SOLARIS_MAXPARTITIONS 16
+
+/* disklabel (vtoc) location */
+#define SOLARIS_SECTOR 1 /* in 512-sectors */
+#define SOLARIS_OFFSET (SOLARIS_SECTOR << 9) /* in bytes */
+#define SOLARIS_MAGICOFFSET (SOLARIS_OFFSET + 12) /* v_sanity offset in bytes */
+
+/* slice tags */
+#define SOLARIS_TAG_WHOLEDISK 5
+
+struct solaris_slice {
+ uint16_t s_tag; /* ID tag of partition */
+ uint16_t s_flag; /* permission flags */
+ uint32_t s_start; /* start sector no of partition */
+ uint32_t s_size; /* # of blocks in partition */
+} __attribute__((packed));
+
+struct solaris_vtoc {
+ unsigned int v_bootinfo[3]; /* info needed by mboot (unsupported) */
+
+ uint32_t v_sanity; /* to verify vtoc sanity */
+ uint32_t v_version; /* layout version */
+ char v_volume[8]; /* volume name */
+ uint16_t v_sectorsz; /* sector size in bytes */
+ uint16_t v_nparts; /* number of partitions */
+ unsigned int v_reserved[10]; /* free space */
+
+ struct solaris_slice v_slice[SOLARIS_MAXPARTITIONS]; /* slices */
+
+ unsigned int timestamp[SOLARIS_MAXPARTITIONS]; /* timestamp (unsupported) */
+ char v_asciilabel[128]; /* for compatibility */
+} __attribute__((packed));
+
+static int probe_solaris_pt(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ struct solaris_vtoc *l; /* disk label */
+ struct solaris_slice *p; /* partition */
+ blkid_parttable tab = NULL;
+ blkid_partition parent;
+ blkid_partlist ls;
+ int i;
+ uint16_t nparts;
+
+ l = (struct solaris_vtoc *) blkid_probe_get_sector(pr, SOLARIS_SECTOR);
+ if (!l) {
+ if (errno)
+ return -errno;
+ goto nothing;
+ }
+
+ if (le32_to_cpu(l->v_version) != 1) {
+ DBG(LOWPROBE, ul_debug(
+ "WARNING: unsupported solaris x86 version %d, ignore",
+ le32_to_cpu(l->v_version)));
+ goto nothing;
+ }
+
+ if (blkid_partitions_need_typeonly(pr))
+ /* caller does not ask for details about partitions */
+ return BLKID_PROBE_OK;
+
+ ls = blkid_probe_get_partlist(pr);
+ if (!ls)
+ goto nothing;
+
+ parent = blkid_partlist_get_parent(ls);
+
+ tab = blkid_partlist_new_parttable(ls, "solaris", SOLARIS_OFFSET);
+ if (!tab)
+ goto err;
+
+ nparts = le16_to_cpu(l->v_nparts);
+ if (nparts > SOLARIS_MAXPARTITIONS)
+ nparts = SOLARIS_MAXPARTITIONS;
+
+ for (i = 1, p = &l->v_slice[0]; i < nparts; i++, p++) {
+
+ uint32_t start = le32_to_cpu(p->s_start);
+ uint32_t size = le32_to_cpu(p->s_size);
+ blkid_partition par;
+
+ if (size == 0 || le16_to_cpu(p->s_tag) == SOLARIS_TAG_WHOLEDISK)
+ continue;
+
+ if (parent)
+ /* Solaris slices are relative to the parent (primary
+ * DOS partition) */
+ start += blkid_partition_get_start(parent);
+
+ if (parent && !blkid_is_nested_dimension(parent, start, size)) {
+ DBG(LOWPROBE, ul_debug(
+ "WARNING: solaris partition (%d) overflow "
+ "detected, ignore", i));
+ continue;
+ }
+
+ par = blkid_partlist_add_partition(ls, tab, start, size);
+ if (!par)
+ goto err;
+
+ blkid_partition_set_type(par, le16_to_cpu(p->s_tag));
+ blkid_partition_set_flags(par, le16_to_cpu(p->s_flag));
+ }
+
+ return BLKID_PROBE_OK;
+
+nothing:
+ return BLKID_PROBE_NONE;
+err:
+ return -ENOMEM;
+}
+
+const struct blkid_idinfo solaris_x86_pt_idinfo =
+{
+ .name = "solaris",
+ .probefunc = probe_solaris_pt,
+ .magics =
+ {
+ {
+ .magic = "\xEE\xDE\x0D\x60", /* little-endian magic string */
+ .len = 4, /* v_sanity size in bytes */
+ .sboff = SOLARIS_MAGICOFFSET /* offset of v_sanity */
+ },
+ { NULL }
+ }
+};
+
diff --git a/libblkid/src/partitions/sun.c b/libblkid/src/partitions/sun.c
new file mode 100644
index 0000000..058a663
--- /dev/null
+++ b/libblkid/src/partitions/sun.c
@@ -0,0 +1,125 @@
+/*
+ * sun (solaris-sparc) partition parsing code
+ *
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stddef.h>
+
+#include "pt-sun.h"
+#include "partitions.h"
+
+static int probe_sun_pt(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ struct sun_disklabel *l;
+ struct sun_partition *p;
+ blkid_parttable tab = NULL;
+ blkid_partlist ls;
+ uint16_t nparts;
+ uint64_t spc;
+ int i, use_vtoc;
+
+ l = (struct sun_disklabel *) blkid_probe_get_sector(pr, 0);
+ if (!l) {
+ if (errno)
+ return -errno;
+ goto nothing;
+ }
+
+ if (sun_pt_checksum(l)) {
+ DBG(LOWPROBE, ul_debug(
+ "detected corrupted sun disk label -- ignore"));
+ goto nothing;
+ }
+
+ if (blkid_partitions_need_typeonly(pr))
+ /* caller does not ask for details about partitions */
+ return BLKID_PROBE_OK;
+
+ ls = blkid_probe_get_partlist(pr);
+ if (!ls)
+ goto nothing;
+
+ tab = blkid_partlist_new_parttable(ls, "sun", 0);
+ if (!tab)
+ goto err;
+
+ /* sectors per cylinder (partition offset is in cylinders...) */
+ spc = (uint64_t) be16_to_cpu(l->nhead) * be16_to_cpu(l->nsect);
+
+ DBG(LOWPROBE, ul_debug("Sun VTOC sanity=%u version=%u nparts=%u",
+ be32_to_cpu(l->vtoc.sanity),
+ be32_to_cpu(l->vtoc.version),
+ be16_to_cpu(l->vtoc.nparts)));
+
+ /* Check to see if we can use the VTOC table */
+ use_vtoc = ((be32_to_cpu(l->vtoc.sanity) == SUN_VTOC_SANITY) &&
+ (be32_to_cpu(l->vtoc.version) == SUN_VTOC_VERSION) &&
+ (be16_to_cpu(l->vtoc.nparts) <= SUN_MAXPARTITIONS));
+
+ /* Use 8 partition entries if not specified in validated VTOC */
+ nparts = use_vtoc ? be16_to_cpu(l->vtoc.nparts) : SUN_MAXPARTITIONS;
+
+ /*
+ * So that old Linux-Sun partitions continue to work,
+ * allow the VTOC to be used under the additional condition ...
+ */
+ use_vtoc = use_vtoc || !(l->vtoc.sanity || l->vtoc.version || l->vtoc.nparts);
+
+ for (i = 0, p = l->partitions; i < nparts; i++, p++) {
+
+ uint64_t start, size;
+ uint16_t type = 0, flags = 0;
+ blkid_partition par;
+
+ start = be32_to_cpu(p->start_cylinder) * spc;
+ size = be32_to_cpu(p->num_sectors);
+ if (use_vtoc) {
+ type = be16_to_cpu(l->vtoc.infos[i].id);
+ flags = be16_to_cpu(l->vtoc.infos[i].flags);
+ }
+
+ if (type == SUN_TAG_WHOLEDISK || !size) {
+ blkid_partlist_increment_partno(ls);
+ continue;
+ }
+ par = blkid_partlist_add_partition(ls, tab, start, size);
+ if (!par)
+ goto err;
+
+ if (type)
+ blkid_partition_set_type(par, type);
+ if (flags)
+ blkid_partition_set_flags(par, flags);
+ }
+ return BLKID_PROBE_OK;
+
+nothing:
+ return BLKID_PROBE_NONE;
+err:
+ return -ENOMEM;
+}
+
+
+const struct blkid_idinfo sun_pt_idinfo =
+{
+ .name = "sun",
+ .probefunc = probe_sun_pt,
+ .magics =
+ {
+ {
+ .magic = "\xDA\xBE", /* big-endian magic string */
+ .len = 2,
+ .sboff = offsetof(struct sun_disklabel, magic)
+ },
+ { NULL }
+ }
+};
+
diff --git a/libblkid/src/partitions/ultrix.c b/libblkid/src/partitions/ultrix.c
new file mode 100644
index 0000000..9c060be
--- /dev/null
+++ b/libblkid/src/partitions/ultrix.c
@@ -0,0 +1,99 @@
+/*
+ * uktrix partition parsing code
+ *
+ * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "partitions.h"
+
+#define ULTRIX_MAXPARTITIONS 8
+
+#define ULTRIX_MAGIC 0x032957
+#define ULTRIX_MAGIC_STR "\x02\x29\x57"
+
+/* sector with partition table */
+#define ULTRIX_SECTOR ((16384 - sizeof(struct ultrix_disklabel)) >> 9)
+/* position of partition table within ULTRIX_SECTOR */
+#define ULTRIX_OFFSET (512 - sizeof(struct ultrix_disklabel))
+
+struct ultrix_disklabel {
+ int32_t pt_magic; /* magic no. indicating part. info exits */
+ int32_t pt_valid; /* set by driver if pt is current */
+ struct pt_info {
+ int32_t pi_nblocks; /* no. of sectors */
+ uint32_t pi_blkoff; /* block offset for start */
+ } pt_part[ULTRIX_MAXPARTITIONS];
+} __attribute__((packed));
+
+
+static int probe_ultrix_pt(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ unsigned char *data;
+ struct ultrix_disklabel *l;
+ blkid_parttable tab = NULL;
+ blkid_partlist ls;
+ int i;
+
+ data = blkid_probe_get_sector(pr, ULTRIX_SECTOR);
+ if (!data) {
+ if (errno)
+ return -errno;
+ goto nothing;
+ }
+
+ l = (struct ultrix_disklabel *) (data + ULTRIX_OFFSET);
+
+ if (l->pt_magic != ULTRIX_MAGIC || l->pt_valid != 1)
+ goto nothing;
+
+ if (blkid_probe_set_magic(pr, (ULTRIX_SECTOR << 9) + ULTRIX_OFFSET,
+ sizeof(ULTRIX_MAGIC_STR) - 1,
+ (unsigned char *) ULTRIX_MAGIC_STR))
+ goto err;
+
+ if (blkid_partitions_need_typeonly(pr))
+ /* caller does not ask for details about partitions */
+ return BLKID_PROBE_OK;
+
+ ls = blkid_probe_get_partlist(pr);
+ if (!ls)
+ goto nothing;
+
+ tab = blkid_partlist_new_parttable(ls, "ultrix", 0);
+ if (!tab)
+ goto err;
+
+ for (i = 0; i < ULTRIX_MAXPARTITIONS; i++) {
+ if (!l->pt_part[i].pi_nblocks)
+ blkid_partlist_increment_partno(ls);
+ else {
+ if (!blkid_partlist_add_partition(ls, tab,
+ l->pt_part[i].pi_blkoff,
+ l->pt_part[i].pi_nblocks))
+ goto err;
+ }
+ }
+
+ return BLKID_PROBE_OK;
+nothing:
+ return BLKID_PROBE_NONE;
+err:
+ return -ENOMEM;
+}
+
+const struct blkid_idinfo ultrix_pt_idinfo =
+{
+ .name = "ultrix",
+ .probefunc = probe_ultrix_pt,
+ .magics = BLKID_NONE_MAGIC
+};
+
diff --git a/libblkid/src/partitions/unixware.c b/libblkid/src/partitions/unixware.c
new file mode 100644
index 0000000..845924e
--- /dev/null
+++ b/libblkid/src/partitions/unixware.c
@@ -0,0 +1,197 @@
+/*
+ * unixware partition parsing code
+ *
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ *
+ * The interesting information about unixware PT:
+ * - Linux kernel / partx
+ * - vtoc(7) SCO UNIX command man page
+ * - evms source code (http://evms.sourceforge.net/)
+ * - vxtools source code (http://martin.hinner.info/fs/vxfs/)
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "partitions.h"
+
+/* disklabel location */
+#define UNIXWARE_SECTOR 29
+#define UNIXWARE_OFFSET (UNIXWARE_SECTOR << 9) /* offset in bytes */
+#define UNIXWARE_KBOFFSET (UNIXWARE_OFFSET >> 10) /* offset in 1024-blocks */
+
+/* disklabel->d_magic offset within the last 1024 block */
+#define UNIXWARE_MAGICOFFSET (UNIXWARE_OFFSET - UNIXWARE_KBOFFSET + 4)
+
+#define UNIXWARE_VTOCMAGIC 0x600DDEEEUL
+#define UNIXWARE_MAXPARTITIONS 16
+
+/* unixware_partition->s_label flags */
+#define UNIXWARE_TAG_UNUSED 0x0000 /* unused partition */
+#define UNIXWARE_TAG_BOOT 0x0001 /* boot fs */
+#define UNIXWARE_TAG_ROOT 0x0002 /* root fs */
+#define UNIXWARE_TAG_SWAP 0x0003 /* swap fs */
+#define UNIXWARE_TAG_USER 0x0004 /* user fs */
+#define UNIXWARE_TAG_ENTIRE_DISK 0x0005 /* whole disk */
+#define UNIXWARE_TAG_ALT_S 0x0006 /* alternate sector space */
+#define UNIXWARE_TAG_OTHER 0x0007 /* non unix */
+#define UNIXWARE_TAG_ALT_T 0x0008 /* alternate track space */
+#define UNIXWARE_TAG_STAND 0x0009 /* stand partition */
+#define UNIXWARE_TAG_VAR 0x000a /* var partition */
+#define UNIXWARE_TAG_HOME 0x000b /* home partition */
+#define UNIXWARE_TAG_DUMP 0x000c /* dump partition */
+#define UNIXWARE_TAG_ALT_ST 0x000d /* alternate sector track */
+#define UNIXWARE_TAG_VM_PUBLIC 0x000e /* volume mgt public partition */
+#define UNIXWARE_TAG_VM_PRIVATE 0x000f /* volume mgt private partition */
+
+
+/* unixware_partition->s_flags flags */
+#define UNIXWARE_FLAG_VALID 0x0200
+
+struct unixware_partition {
+ uint16_t s_label; /* partition label (tag) */
+ uint16_t s_flags; /* permission flags */
+ uint32_t start_sect; /* starting sector */
+ uint32_t nr_sects; /* number of sectors */
+} __attribute__((packed));
+
+struct unixware_disklabel {
+ uint32_t d_type; /* drive type */
+ uint32_t d_magic; /* the magic number */
+ uint32_t d_version; /* version number */
+ char d_serial[12]; /* serial number of the device */
+ uint32_t d_ncylinders; /* # of data cylinders per device */
+ uint32_t d_ntracks; /* # of tracks per cylinder */
+ uint32_t d_nsectors; /* # of data sectors per track */
+ uint32_t d_secsize; /* # of bytes per sector */
+ uint32_t d_part_start; /* # of first sector of this partition */
+ uint32_t d_unknown1[12]; /* ? */
+ uint32_t d_alt_tbl; /* byte offset of alternate table */
+ uint32_t d_alt_len; /* byte length of alternate table */
+ uint32_t d_phys_cyl; /* # of physical cylinders per device */
+ uint32_t d_phys_trk; /* # of physical tracks per cylinder */
+ uint32_t d_phys_sec; /* # of physical sectors per track */
+ uint32_t d_phys_bytes; /* # of physical bytes per sector */
+ uint32_t d_unknown2; /* ? */
+ uint32_t d_unknown3; /* ? */
+ uint32_t d_pad[8]; /* pad */
+
+ struct unixware_vtoc {
+ uint32_t v_magic; /* the magic number */
+ uint32_t v_version; /* version number */
+ char v_name[8]; /* volume name */
+ uint16_t v_nslices; /* # of partitions */
+ uint16_t v_unknown1; /* ? */
+ uint32_t v_reserved[10]; /* reserved */
+
+ struct unixware_partition
+ v_slice[UNIXWARE_MAXPARTITIONS]; /* partition */
+ } __attribute__((packed)) vtoc;
+};
+
+static int probe_unixware_pt(blkid_probe pr,
+ const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+ struct unixware_disklabel *l;
+ struct unixware_partition *p;
+ blkid_parttable tab = NULL;
+ blkid_partition parent;
+ blkid_partlist ls;
+ int i;
+
+ l = (struct unixware_disklabel *)
+ blkid_probe_get_sector(pr, UNIXWARE_SECTOR);
+ if (!l) {
+ if (errno)
+ return -errno;
+ goto nothing;
+ }
+
+ if (le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_VTOCMAGIC)
+ goto nothing;
+
+ if (blkid_partitions_need_typeonly(pr))
+ /* caller does not ask for details about partitions */
+ return BLKID_PROBE_OK;
+
+ ls = blkid_probe_get_partlist(pr);
+ if (!ls)
+ goto nothing;
+
+ parent = blkid_partlist_get_parent(ls);
+
+ tab = blkid_partlist_new_parttable(ls, "unixware", UNIXWARE_OFFSET);
+ if (!tab)
+ goto err;
+
+ /* Skip the first partition that describe whole disk
+ */
+ for (i = 1, p = &l->vtoc.v_slice[1];
+ i < UNIXWARE_MAXPARTITIONS; i++, p++) {
+
+ uint32_t start, size;
+ uint16_t tag, flg;
+ blkid_partition par;
+
+ tag = le16_to_cpu(p->s_label);
+ flg = le16_to_cpu(p->s_flags);
+
+ if (tag == UNIXWARE_TAG_UNUSED ||
+ tag == UNIXWARE_TAG_ENTIRE_DISK ||
+ flg != UNIXWARE_FLAG_VALID)
+ continue;
+
+ start = le32_to_cpu(p->start_sect);
+ size = le32_to_cpu(p->nr_sects);
+
+ if (parent && !blkid_is_nested_dimension(parent, start, size)) {
+ DBG(LOWPROBE, ul_debug(
+ "WARNING: unixware partition (%d) overflow "
+ "detected, ignore", i));
+ continue;
+ }
+
+ par = blkid_partlist_add_partition(ls, tab, start, size);
+ if (!par)
+ goto err;
+
+ blkid_partition_set_type(par, tag);
+ blkid_partition_set_flags(par, flg);
+ }
+
+ return BLKID_PROBE_OK;
+
+nothing:
+ return BLKID_PROBE_NONE;
+err:
+ return -ENOMEM;
+}
+
+
+/*
+ * The unixware partition table is within primary DOS partition. The PT is
+ * located on 29 sector, PT magic string is d_magic member of 'struct
+ * unixware_disklabel'.
+ */
+const struct blkid_idinfo unixware_pt_idinfo =
+{
+ .name = "unixware",
+ .probefunc = probe_unixware_pt,
+ .minsz = 1024 * 1440 + 1, /* ignore floppies */
+ .magics =
+ {
+ {
+ .magic = "\x0D\x60\xE5\xCA", /* little-endian magic string */
+ .len = 4, /* d_magic size in bytes */
+ .kboff = UNIXWARE_KBOFFSET,
+ .sboff = UNIXWARE_MAGICOFFSET
+ },
+ { NULL }
+ }
+};
+