libblkid: add superblocks chain

Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
Karel Zak 2009-09-15 21:38:46 +02:00
parent 5657c25a51
commit 0e89abac8b
2 changed files with 302 additions and 0 deletions

View File

@ -5,6 +5,7 @@ AM_CPPFLAGS += -I$(ul_libblkid_srcdir)
noinst_LTLIBRARIES = libblkid_superblocks.la
libblkid_superblocks_la_SOURCES = \
superblocks.h \
superblocks.c \
cramfs.c \
swap.c \
adaptec_raid.c \

View File

@ -0,0 +1,301 @@
/*
* superblocks.c - reads information from filesystem and raid superblocks
*
* 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 <stdarg.h>
#include "blkdev.h"
#include "blkidP.h"
#include "superblocks.h"
/**
* SECTION:superblocks
* @title: Superblocks probing
* @short_description: filesystems and raids superblocks probing.
*
* The library API has been originaly designed for superblocks probing only.
* This is reason why some *deprecated* superblock specific functions don't use
* '_superblocks_' namespace in the function name. Please, don't use these
* functions in new code.
*
* The 'superblocks' probers support NAME=value (tags) interface only. The
* superblocks probing is enabled by default (and controled by
* blkid_probe_enable_superblocks()).
*
* Currently supported tags:
*
* @TYPE: filesystem type
*
* @SEC_TYPE: secondary filesystem type
*
* @LABEL: filesystem label
*
* @LABEL_RAW: raw label from FS superblock
*
* @UUID: filesystem UUID (lower case)
*
* @UUID_RAW: raw UUID from FS superblock
*
* @EXT_JOURNAL: external journal UUID
*
* @USAGE: usage string: "raid", "filesystem", ...
*
* @VERSION: filesystem version
*
* @MOUNT: cluster mount name (?) -- ocfs only
*
* @SBMAGIC: super block magic string [not-implemented yet]
*
* @SBOFFSET: offset of superblock [not-implemented yet]
*
* @FSSIZE: size of filessystem [not-implemented yet]
*/
static int superblocks_probe(blkid_probe pr, struct blkid_chain *chn);
static int superblocks_safeprobe(blkid_probe pr, struct blkid_chain *chn);
static int blkid_probe_set_usage(blkid_probe pr, int usage);
/*
* Superblocks chains probing functions
*/
static const struct blkid_idinfo *idinfos[] =
{
/* RAIDs */
&linuxraid_idinfo,
&ddfraid_idinfo,
&iswraid_idinfo,
&lsiraid_idinfo,
&viaraid_idinfo,
&silraid_idinfo,
&nvraid_idinfo,
&pdcraid_idinfo,
&highpoint45x_idinfo,
&highpoint37x_idinfo,
&adraid_idinfo,
&jmraid_idinfo,
&lvm2_idinfo,
&lvm1_idinfo,
&snapcow_idinfo,
&luks_idinfo,
/* Filesystems */
&vfat_idinfo,
&swsuspend_idinfo,
&swap_idinfo,
&xfs_idinfo,
&ext4dev_idinfo,
&ext4_idinfo,
&ext3_idinfo,
&ext2_idinfo,
&jbd_idinfo,
&reiser_idinfo,
&reiser4_idinfo,
&jfs_idinfo,
&udf_idinfo,
&iso9660_idinfo,
&zfs_idinfo,
&hfsplus_idinfo,
&hfs_idinfo,
&ufs_idinfo,
&hpfs_idinfo,
&sysv_idinfo,
&xenix_idinfo,
&ntfs_idinfo,
&cramfs_idinfo,
&romfs_idinfo,
&minix_idinfo,
&gfs_idinfo,
&gfs2_idinfo,
&ocfs_idinfo,
&ocfs2_idinfo,
&oracleasm_idinfo,
&vxfs_idinfo,
&squashfs_idinfo,
&netware_idinfo,
&btrfs_idinfo
};
/*
* Driver definition
*/
const struct blkid_chaindrv superblocks_drv = {
.id = BLKID_CHAIN_SUBLKS,
.name = "superblocks",
.dflt_enabled = TRUE,
.dflt_flags = BLKID_SUBLKS_DEFAULT,
.idinfos = idinfos,
.nidinfos = ARRAY_SIZE(idinfos),
.has_fltr = TRUE,
.probe = superblocks_probe,
.safeprobe = superblocks_safeprobe
};
/*
* The blkid_do_probe() backend.
*/
static int superblocks_probe(blkid_probe pr, struct blkid_chain *chn)
{
int i = 0;
if (!pr || chn->idx < -1)
return -1;
if (chn->idx < -1)
return -1;
blkid_probe_chain_reset_vals(pr, chn);
DBG(DEBUG_LOWPROBE,
printf("--> starting probing loop [SUBLKS idx=%d]\n",
chn->idx));
i = chn->idx + 1;
for ( ; i < ARRAY_SIZE(idinfos); i++) {
const struct blkid_idinfo *id;
const struct blkid_idmag *mag;
int hasmag = 0;
chn->idx = i;
if (chn->fltr && blkid_bmp_get_item(chn->fltr, i))
continue;
id = idinfos[i];
mag = id->magics ? &id->magics[0] : NULL;
/* try to detect by magic string */
while(mag && mag->magic) {
blkid_loff_t off;
unsigned char *buf;
off = mag->kboff + ((blkid_loff_t) mag->sboff >> 10);
buf = blkid_probe_get_buffer(pr, off << 10, 1024);
if (buf && !memcmp(mag->magic,
buf + (mag->sboff & 0x3ff), mag->len)) {
DBG(DEBUG_LOWPROBE, printf(
"%s: magic sboff=%u, kboff=%ld\n",
id->name, mag->sboff, mag->kboff));
hasmag = 1;
break;
}
mag++;
}
if (hasmag == 0 && id->magics && id->magics[0].magic)
/* magic string(s) defined, but not found */
continue;
/* final check by probing function */
if (id->probefunc) {
DBG(DEBUG_LOWPROBE, printf(
"%s: call probefunc()\n", id->name));
if (id->probefunc(pr, mag) != 0)
continue;
}
/* all cheks passed */
if (chn->flags & BLKID_SUBLKS_TYPE)
blkid_probe_set_value(pr, "TYPE",
(unsigned char *) id->name,
strlen(id->name) + 1);
if (chn->flags & BLKID_SUBLKS_USAGE)
blkid_probe_set_usage(pr, id->usage);
DBG(DEBUG_LOWPROBE,
printf("<-- leaving probing loop (type=%s) [SUBLKS idx=%d]\n",
id->name, chn->idx));
return 0;
}
DBG(DEBUG_LOWPROBE,
printf("<-- leaving probing loop (failed) [SUBLKS idx=%d]\n",
chn->idx));
return 1;
}
/*
* This is the same function as blkid_do_probe(), but returns only one result
* (cannot be used in while()) and checks for ambivalen results (more
* filesystems on the device) -- in such case returns -2.
*
* The function does not check for filesystems when a RAID signature is
* detected. The function also does not check for collision between RAIDs. The
* first detected RAID is returned.
*/
static int superblocks_safeprobe(blkid_probe pr, struct blkid_chain *chn)
{
struct blkid_prval vals[BLKID_NVALS_SUBLKS];
int nvals = BLKID_NVALS_SUBLKS;
int idx = -1;
int count = 0;
int intol = 0;
int rc;
while ((rc = superblocks_probe(pr, chn)) == 0) {
if (!count) {
/* save the first result */
nvals = blkid_probe_chain_copy_vals(pr, chn, vals, nvals);
idx = chn->idx;
}
count++;
if (idinfos[chn->idx]->usage & BLKID_USAGE_RAID)
break;
if (!(idinfos[chn->idx]->flags & BLKID_IDINFO_TOLERANT))
intol++;
}
if (rc < 0)
return rc; /* error */
if (count > 1 && intol) {
DBG(DEBUG_LOWPROBE,
printf("ERROR: superblocks chain: "
"ambivalent result detected (%d filesystems)!\n",
count));
return -2; /* error, ambivalent result (more FS) */
}
if (!count)
return 1; /* nothing detected */
/* restore the first result */
blkid_probe_chain_reset_vals(pr, chn);
blkid_probe_append_vals(pr, vals, nvals);
chn->idx = idx;
return 0;
}
static int blkid_probe_set_usage(blkid_probe pr, int usage)
{
char *u = NULL;
if (usage & BLKID_USAGE_FILESYSTEM)
u = "filesystem";
else if (usage & BLKID_USAGE_RAID)
u = "raid";
else if (usage & BLKID_USAGE_CRYPTO)
u = "crypto";
else if (usage & BLKID_USAGE_OTHER)
u = "other";
else
u = "unknown";
return blkid_probe_set_value(pr, "USAGE", (unsigned char *) u, strlen(u) + 1);
}