blob: 0fba6348985f811a304ac15d049c08f43b9022c0 [file] [log] [blame]
/*
* Copyright (C) 2008 Karel Zak <kzak@redhat.com>
*
* Inspired by libvolume_id by
* Kay Sievers <kay.sievers@vrfy.org>
*
* This file may be redistributed under the terms of the
* GNU Lesser General Public License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdint.h>
#include "superblocks.h"
struct mdp0_super_block {
uint32_t md_magic;
uint32_t major_version;
uint32_t minor_version;
uint32_t patch_version;
uint32_t gvalid_words;
uint32_t set_uuid0;
uint32_t ctime;
uint32_t level;
uint32_t size;
uint32_t nr_disks;
uint32_t raid_disks;
uint32_t md_minor;
uint32_t not_persistent;
uint32_t set_uuid1;
uint32_t set_uuid2;
uint32_t set_uuid3;
};
struct mdp1_super_block {
uint32_t magic;
uint32_t major_version;
uint32_t feature_map;
uint32_t pad0;
uint8_t set_uuid[16];
uint8_t set_name[32];
};
#define MD_RESERVED_BYTES 0x10000
#define MD_SB_MAGIC 0xa92b4efc
static int probe_raid0(blkid_probe pr, off_t off)
{
struct mdp0_super_block *mdp0;
union {
uint32_t ints[4];
uint8_t bytes[16];
} uuid;
if (pr->size < 0x10000)
return -1;
mdp0 = (struct mdp0_super_block *)
blkid_probe_get_buffer(pr,
off,
sizeof(struct mdp0_super_block));
if (!mdp0)
return -1;
memset(uuid.ints, 0, sizeof(uuid.ints));
if (le32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) {
uuid.ints[0] = swab32(mdp0->set_uuid0);
if (le32_to_cpu(mdp0->minor_version >= 90)) {
uuid.ints[1] = swab32(mdp0->set_uuid1);
uuid.ints[2] = swab32(mdp0->set_uuid2);
uuid.ints[3] = swab32(mdp0->set_uuid3);
}
if (blkid_probe_sprintf_version(pr, "%u.%u.%u",
le32_to_cpu(mdp0->major_version),
le32_to_cpu(mdp0->minor_version),
le32_to_cpu(mdp0->patch_version)) != 0)
return -1;
} else if (be32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) {
uuid.ints[0] = mdp0->set_uuid0;
if (be32_to_cpu(mdp0->minor_version >= 90)) {
uuid.ints[1] = mdp0->set_uuid1;
uuid.ints[2] = mdp0->set_uuid2;
uuid.ints[3] = mdp0->set_uuid3;
}
if (blkid_probe_sprintf_version(pr, "%u.%u.%u",
be32_to_cpu(mdp0->major_version),
be32_to_cpu(mdp0->minor_version),
be32_to_cpu(mdp0->patch_version)) != 0)
return -1;
} else
return -1;
if (blkid_probe_set_uuid(pr, (unsigned char *) uuid.bytes) != 0)
return -1;
return 0;
}
static int probe_raid1(blkid_probe pr, off_t off)
{
struct mdp1_super_block *mdp1;
mdp1 = (struct mdp1_super_block *)
blkid_probe_get_buffer(pr,
off,
sizeof(struct mdp1_super_block));
if (!mdp1)
return -1;
if (le32_to_cpu(mdp1->magic) != MD_SB_MAGIC)
return -1;
if (le32_to_cpu(mdp1->major_version) != 1)
return -1;
if (blkid_probe_set_uuid(pr, (unsigned char *) mdp1->set_uuid) != 0)
return -1;
if (blkid_probe_set_label(pr, mdp1->set_name,
sizeof(mdp1->set_name)) != 0)
return -1;
return 0;
}
int probe_raid(blkid_probe pr, const struct blkid_idmag *mag)
{
const char *ver = NULL;
if (pr->size > MD_RESERVED_BYTES) {
/* version 0 at the end of the device */
uint64_t sboff = (pr->size & ~(MD_RESERVED_BYTES - 1))
- MD_RESERVED_BYTES;
if (probe_raid0(pr, sboff) == 0)
return 0;
/* version 1.0 at the end of the device */
sboff = (pr->size & ~(0x1000 - 1)) - 0x2000;
if (probe_raid1(pr, sboff) == 0)
ver = "1.0";
}
if (!ver) {
/* version 1.1 at the start of the device */
if (probe_raid1(pr, 0) == 0)
ver = "1.1";
/* version 1.2 at 4k offset from the start */
else if (probe_raid1(pr, 0x1000) == 0)
ver = "1.2";
}
if (ver) {
blkid_probe_set_version(pr, ver);
return 0;
}
return -1;
}
const struct blkid_idinfo linuxraid_idinfo = {
.name = "linux_raid_member",
.usage = BLKID_USAGE_RAID,
.probefunc = probe_raid,
.magics = BLKID_NONE_MAGIC
};