blkid: add blkid_do_safeprobe()

The function blkid_do_probe() is able to detect more filesystems on
the device

	while(blkid_do_probe(pr) == 0)
		...

but in many cases we need only one exact answer, and we also need to
be sure that there is not any other FS on the device.

For example it's possible to create valid LUKS (or vfat, ...) header
and valid linux swap header on the same device -- in such case the
device can be interpreted (by mount/swapon) in two completely
different ways. An ambivalent result is always error -- the library
never returns such result.

Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
Karel Zak 2009-01-27 17:25:06 +01:00
parent ba837d3f0a
commit a2f01a1c0b
8 changed files with 66 additions and 7 deletions

View File

@ -319,6 +319,7 @@ static int lowprobe_device(blkid_probe pr, const char *devname, int output,
int nvals, n;
size_t len;
int fd;
int rc = 0;
fd = open(devname, O_RDONLY);
if (fd < 0) {
@ -328,7 +329,8 @@ static int lowprobe_device(blkid_probe pr, const char *devname, int output,
if (blkid_probe_set_device(pr, fd, offset, size))
goto error;
if (blkid_do_probe(pr))
rc = blkid_do_safeprobe(pr);
if (rc)
goto error;
nvals = blkid_probe_numof_values(pr);
@ -341,8 +343,13 @@ static int lowprobe_device(blkid_probe pr, const char *devname, int output,
print_value(output, n + 1, NULL, (char *) data, name, len);
}
close(fd);
return 0;
error:
if (rc == -2)
fprintf(stderr, "%s: ambivalent result "
"(probably more filesystems on the device)\n",
devname);
close(fd);
return -1;
}

View File

@ -150,6 +150,8 @@ extern int blkid_probe_invert_filter(blkid_probe pr);
extern int blkid_probe_reset_filter(blkid_probe pr);
extern int blkid_do_probe(blkid_probe pr);
extern int blkid_do_safeprobe(blkid_probe pr);
extern int blkid_probe_numof_values(blkid_probe pr);
extern int blkid_probe_get_value(blkid_probe pr, int num, const char **name,
unsigned char **data, size_t *len);

View File

@ -7,6 +7,7 @@
blkid_devno_to_devname;
blkid_dev_set_search;
blkid_do_probe;
blkid_do_safeprobe;
blkid_encode_string;
blkid_find_dev_with_tag;
blkid_free_probe;

View File

@ -134,10 +134,11 @@ struct blkid_idmag
*/
struct blkid_idinfo
{
const char *name; /* FS/RAID name */
int usage; /* BLKID_USAGE_* flag */
const char *name; /* FS/RAID name */
int usage; /* BLKID_USAGE_* flag */
int flags; /* BLKID_IDINFO_* flags */
/* probe function */
/* probe function */
int (*probefunc)(blkid_probe pr, const struct blkid_idmag *mag);
struct blkid_idmag magics[]; /* NULL or array with magic strings */
@ -145,6 +146,13 @@ struct blkid_idinfo
#define BLKID_NONE_MAGIC {{ NULL }}
/*
* tolerant FS - can share the same device with more filesystems (e.g. typical
* on CD-ROMs). We need this flag to detect ambivalent results (e.g. valid fat
* and valid linux swap on the same device).
*/
#define BLKID_IDINFO_TOLERANT (1 << 1)
/*
* Minimum number of seconds between device probes, even when reading
* from the cache. This is to avoid re-probing all devices which were

View File

@ -169,6 +169,7 @@ void blkid_reset_probe(blkid_probe pr)
memset(pr->buf, 0, pr->buf_max);
pr->buf_off = 0;
pr->buf_len = 0;
pr->idx = 0;
if (pr->sbbuf)
memset(pr->sbbuf, 0, BLKID_SB_BUFSIZ);
pr->sbbuf_len = 0;
@ -448,7 +449,7 @@ int blkid_do_probe(blkid_probe pr)
DBG(DEBUG_LOWPROBE, printf("*** starting probing loop\n"));
for (i = 0; i < ARRAY_SIZE(idinfos); i++) {
for ( ; i < ARRAY_SIZE(idinfos); i++) {
const struct blkid_idinfo *id;
const struct blkid_idmag *mag;
int hasmag = 0;
@ -510,6 +511,44 @@ int blkid_do_probe(blkid_probe pr)
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.
*/
int blkid_do_safeprobe(blkid_probe pr)
{
struct blkid_struct_probe first;
int count = 0;
int intol = 0;
int rc;
while ((rc = blkid_do_probe(pr)) == 0) {
if (!count) {
/* store the fist result */
memcpy(first.vals, pr->vals, sizeof(first.vals));
first.nvals = pr->nvals;
first.idx = pr->idx;
}
if (!(idinfos[pr->idx]->flags & BLKID_IDINFO_TOLERANT))
intol++;
count++;
}
if (rc < 0)
return rc; /* error */
if (count > 1 && intol)
return -2; /* error, ambivalent result (more FS) */
if (!count)
return 1; /* nothing detected */
/* restore the first result */
memcpy(pr->vals, first.vals, sizeof(first.vals));
pr->nvals = first.nvals;
pr->idx = first.idx;
return 0;
}
int blkid_probe_numof_values(blkid_probe pr)
{
if (!pr)

View File

@ -122,6 +122,7 @@ const struct blkid_idinfo iso9660_idinfo =
.name = "iso9660",
.usage = BLKID_USAGE_FILESYSTEM,
.probefunc = probe_iso9660,
.flags = BLKID_IDINFO_TOLERANT,
.magics =
{
{ .magic = "CD001", .len = 5, .kboff = 32, .sboff = 1 },

View File

@ -144,6 +144,7 @@ const struct blkid_idinfo udf_idinfo =
.name = "udf",
.usage = BLKID_USAGE_FILESYSTEM,
.probefunc = probe_udf,
.flags = BLKID_IDINFO_TOLERANT,
.magics =
{
{ .magic = "BEA01", .len = 5, .kboff = 32, .sboff = 1 },

View File

@ -141,8 +141,8 @@ blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev)
/*
* Probe for all types.
*/
if (blkid_do_probe(cache->probe)) {
/* found nothing */
if (blkid_do_safeprobe(cache->probe)) {
/* found nothing or error */
blkid_free_dev(dev);
dev = NULL;
}