* the selected (see blkid_probe_set_device()) device.
*
* The probing routines are grouped together into separate chains. Currently,
- * the librray provides superblocks, partitions and topology chains.
+ * the library provides superblocks, partitions and topology chains.
*
* The probing routines is possible to filter (enable/disable) by type (e.g.
* fstype "vfat" or partype "gpt") or by usage flags (e.g. BLKID_USAGE_RAID).
* 2. The binary interfaces. These interfaces return data in the native formats.
* The interface is always specific to the probing chain.
*
+ * Note that the previous probing result (binary or NAME=value) is always
+ * zeroized when a chain probing function is called. For example
+ *
+ * <informalexample>
+ * <programlisting>
+ * blkid_probe_enable_partitions(pr, TRUE);
+ * blkid_probe_enable_superblocks(pr, FALSE);
+ *
+ * blkid_do_safeprobe(pr);
+ * </programlisting>
+ * </informalexample>
+ *
+ * overwrites the previous probing result for the partitions chain, the superblocks
+ * result is not modified.
*/
/**
#include <fcntl.h>
#include <ctype.h>
#include <sys/types.h>
+#ifdef HAVE_LINUX_CDROM_H
+#include <linux/cdrom.h>
+#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
-#ifdef HAVE_SYS_MKDEV_H
-#include <sys/mkdev.h>
-#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
+#include <inttypes.h>
#include <stdint.h>
#include <stdarg.h>
#ifdef HAVE_LIBUUID
-# ifdef HAVE_UUID_UUID_H
-# include <uuid/uuid.h>
-# else
-# include <uuid.h>
-# endif
+# include <uuid.h>
#endif
-#include "blkdev.h"
#include "blkidP.h"
/* chains */
void *blkid_probe_get_binary_data(blkid_probe pr, struct blkid_chain *chn)
{
- int rc;
+ int rc, org_prob_flags;
+ struct blkid_chain *org_chn;
- if (!pr && !chn)
+ if (!pr || !chn)
return NULL;
+ /* save the current setting -- the binary API has to be completely
+ * independent on the current probing status
+ */
+ org_chn = pr->cur_chain;
+ org_prob_flags = pr->prob_flags;
+
pr->cur_chain = chn;
+ pr->prob_flags = 0;
chn->binary = TRUE;
blkid_probe_chain_reset_position(chn);
rc = chn->driver->probe(pr, chn);
chn->binary = FALSE;
- pr->cur_chain = NULL;
blkid_probe_chain_reset_position(chn);
+ /* restore the original setting
+ */
+ pr->cur_chain = org_chn;
+ pr->prob_flags = org_prob_flags;
+
if (rc != 0)
return NULL;
{
int i;
struct blkid_chain *chn;
- unsigned long *fltr;
-
- fltr = blkid_probe_get_filter(pr, chain, FALSE);
- if (!fltr)
- return -1;
chn = &pr->chains[chain];
+ if (!chn->driver->has_fltr || !chn->fltr)
+ return -1;
+
for (i = 0; i < blkid_bmp_nwords(chn->driver->nidinfos); i++)
- fltr[i] = ~fltr[i];
+ chn->fltr[i] = ~chn->fltr[i];
DBG(DEBUG_LOWPROBE, printf("probing filter inverted\n"));
/* blkid_probe_dump_filter(pr, chain); */
struct list_head *p;
struct blkid_bufinfo *bf = NULL;
+ if (pr->size <= 0)
+ return NULL;
+
list_for_each(p, &pr->buffers) {
struct blkid_bufinfo *x =
list_entry(p, struct blkid_bufinfo, bufs);
static void blkid_probe_reset_buffer(blkid_probe pr)
{
- ssize_t read_ct = 0, len_ct = 0;
+ uint64_t read_ct = 0, len_ct = 0;
if (!pr || list_empty(&pr->buffers))
return;
}
DBG(DEBUG_LOWPROBE,
- printf("buffers summary: %jd bytes by %jd read() call(s)\n",
+ printf("buffers summary: %"PRIu64" bytes "
+ "by %"PRIu64" read() call(s)\n",
len_ct, read_ct));
INIT_LIST_HEAD(&pr->buffers);
return pr && (pr->flags & BLKID_TINY_DEV);
}
+/*
+ * CDROMs may fail when probed for RAID (last sector problem)
+ */
+int blkid_probe_is_cdrom(blkid_probe pr)
+{
+ return pr && (pr->flags & BLKID_CDROM_DEV);
+}
+
/**
* blkid_probe_set_device:
* @pr: probe
int blkid_probe_set_device(blkid_probe pr, int fd,
blkid_loff_t off, blkid_loff_t size)
{
+ struct stat sb;
+
if (!pr)
return -1;
close(pr->fd);
pr->flags &= ~BLKID_PRIVATE_FD;
+ pr->flags &= ~BLKID_TINY_DEV;
+ pr->flags &= ~BLKID_CDROM_DEV;
pr->fd = fd;
pr->off = off;
pr->size = 0;
/* Disable read-ahead */
posix_fadvise(fd, 0, 0, POSIX_FADV_RANDOM);
#endif
- if (size)
- pr->size = size;
- else {
- struct stat sb;
+ if (fstat(fd, &sb))
+ goto err;
- if (fstat(fd, &sb))
- goto err;
+ if (!S_ISBLK(sb.st_mode) && !S_ISCHR(sb.st_mode) && !S_ISREG(sb.st_mode))
+ goto err;
- pr->mode = sb.st_mode;
+ pr->mode = sb.st_mode;
+ if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode))
+ pr->devno = sb.st_rdev;
- if (S_ISBLK(sb.st_mode))
- blkdev_get_size(fd, (unsigned long long *) &pr->size);
- else if (S_ISCHR(sb.st_mode))
+ if (size)
+ pr->size = size;
+ else {
+ if (S_ISBLK(sb.st_mode)) {
+ if (blkdev_get_size(fd, (unsigned long long *) &pr->size)) {
+ DBG(DEBUG_LOWPROBE, printf(
+ "failed to get device size\n"));
+ goto err;
+ }
+ } else if (S_ISCHR(sb.st_mode))
pr->size = 1; /* UBI devices are char... */
else if (S_ISREG(sb.st_mode))
pr->size = sb.st_size; /* regular file */
- if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode))
- pr->devno = sb.st_rdev;
-
if (pr->off > pr->size)
goto err;
pr->size -= pr->off;
}
- if (!pr->size)
- goto err;
- DBG(DEBUG_LOWPROBE, printf("ready for low-probing, offset=%zd, size=%zd\n",
- pr->off, pr->size));
-
- if (pr->size <= 1440 * 1024 && !S_ISCHR(pr->mode))
+ if (pr->size <= 1440 * 1024 && !S_ISCHR(sb.st_mode))
pr->flags |= BLKID_TINY_DEV;
+#ifdef CDROM_GET_CAPABILITY
+ if (S_ISBLK(sb.st_mode) && ioctl(fd, CDROM_GET_CAPABILITY, NULL) >= 0)
+ pr->flags |= BLKID_CDROM_DEV;
+#endif
+
+ DBG(DEBUG_LOWPROBE, printf("ready for low-probing, offset=%jd, size=%jd\n",
+ pr->off, pr->size));
+ DBG(DEBUG_LOWPROBE, printf("whole-disk: %s, regfile: %s\n",
+ blkid_probe_is_wholedisk(pr) ?"YES" : "NO",
+ S_ISREG(pr->mode) ? "YES" : "NO"));
+
return 0;
err:
DBG(DEBUG_LOWPROBE,
pr->off = off;
pr->size = size;
+ pr->flags &= ~BLKID_TINY_DEV;
+
+ if (pr->size <= 1440 * 1024 && !S_ISCHR(pr->mode))
+ pr->flags |= BLKID_TINY_DEV;
blkid_probe_reset_buffer(pr);
return 0;
}
+int blkid_probe_get_idmag(blkid_probe pr, const struct blkid_idinfo *id,
+ blkid_loff_t *offset, const struct blkid_idmag **res)
+{
+ const struct blkid_idmag *mag = NULL;
+ blkid_loff_t off = 0;
+
+ if (id)
+ mag = id->magics ? &id->magics[0] : NULL;
+ if (res)
+ *res = NULL;
+
+ /* try to detect by magic string */
+ while(mag && mag->magic) {
+ unsigned char *buf;
+
+ off = (mag->kboff + (mag->sboff >> 10)) << 10;
+ buf = blkid_probe_get_buffer(pr, off, 1024);
+
+ if (buf && !memcmp(mag->magic,
+ buf + (mag->sboff & 0x3ff), mag->len)) {
+ DBG(DEBUG_LOWPROBE, printf(
+ "\tmagic sboff=%u, kboff=%ld\n",
+ mag->sboff, mag->kboff));
+ if (offset)
+ *offset = off + (mag->sboff & 0x3ff);
+ if (res)
+ *res = mag;
+ return 0;
+ }
+ mag++;
+ }
+
+ if (id->magics && id->magics[0].magic)
+ /* magic string(s) defined, but not found */
+ return 1;
+
+ return 0;
+}
+
+static inline void blkid_probe_start(blkid_probe pr)
+{
+ if (pr) {
+ pr->cur_chain = NULL;
+ pr->prob_flags = 0;
+ blkid_probe_set_wiper(pr, 0, 0);
+ }
+}
+
+static inline void blkid_probe_end(blkid_probe pr)
+{
+ if (pr) {
+ pr->cur_chain = NULL;
+ pr->prob_flags = 0;
+ blkid_probe_set_wiper(pr, 0, 0);
+ }
+}
+
/**
* blkid_do_probe:
* @pr: prober
do {
struct blkid_chain *chn = pr->cur_chain;
- if (!chn)
+ if (!chn) {
+ blkid_probe_start(pr);
chn = pr->cur_chain = &pr->chains[0];
-
+ }
/* we go to the next chain only when the previous probing
* result was nothing (rc == 1) and when the current chain is
* disabled or we are at end of the current chain (chain->idx +
- * 1 == sizeof chain)
+ * 1 == sizeof chain) or the current chain bailed out right at
+ * the start (chain->idx == -1)
*/
else if (rc == 1 && (chn->enabled == FALSE ||
- chn->idx + 1 == chn->driver->nidinfos)) {
+ chn->idx + 1 == chn->driver->nidinfos ||
+ chn->idx == -1)) {
int idx = chn->driver->id + 1;
if (idx < BLKID_NCHAINS)
chn = pr->cur_chain = &pr->chains[idx];
- else
+ else {
+ blkid_probe_end(pr);
return 1; /* all chains already probed */
+ }
}
chn->binary = FALSE; /* for sure... */
*
* Note about suberblocks chain -- 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.
+ * collision between RAIDs. The first detected RAID is returned. The function
+ * checks for collision between partition table and RAID signature -- it's
+ * recommended to enable partitions chain together with superblocks chain.
*
* Returns: 0 on success, 1 if nothing is detected, -2 if ambivalen result is
* detected and -1 on case of error.
if (!pr)
return -1;
+ blkid_probe_start(pr);
+
for (i = 0; i < BLKID_NCHAINS; i++) {
struct blkid_chain *chn;
}
done:
- pr->cur_chain = NULL;
+ blkid_probe_end(pr);
if (rc < 0)
return rc;
return count ? 0 : 1;
if (!pr)
return -1;
+ blkid_probe_start(pr);
+
for (i = 0; i < BLKID_NCHAINS; i++) {
int rc;
struct blkid_chain *chn;
}
done:
- pr->cur_chain = NULL;
+ blkid_probe_end(pr);
if (rc < 0)
return rc;
return count ? 0 : 1;
*/
dev_t blkid_probe_get_devno(blkid_probe pr)
{
- if (!pr->devno) {
- struct stat sb;
+ return pr->devno;
+}
+
+/**
+ * blkid_probe_get_wholedisk_devno:
+ * @pr: probe
+ *
+ * Returns: device number of the wholedisk, or 0 for regilar files.
+ */
+dev_t blkid_probe_get_wholedisk_devno(blkid_probe pr)
+{
+ if (!pr->disk_devno) {
+ dev_t devno, disk_devno = 0;
+
+ devno = blkid_probe_get_devno(pr);
+ if (!devno)
+ return 0;
- if (fstat(pr->fd, &sb) == 0 &&
- (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)))
- pr->devno = sb.st_rdev;
+ if (blkid_devno_to_wholedisk(devno, NULL, 0, &disk_devno) == 0)
+ pr->disk_devno = disk_devno;
}
- return pr->devno;
+ return pr->disk_devno;
+}
+
+/**
+ * blkid_probe_is_wholedisk:
+ * @pr: probe
+ *
+ * Returns: 1 if the device is whole-disk or 0.
+ */
+int blkid_probe_is_wholedisk(blkid_probe pr)
+{
+ dev_t devno, disk_devno;
+
+ devno = blkid_probe_get_devno(pr);
+ if (!devno)
+ return 0;
+
+ disk_devno = blkid_probe_get_wholedisk_devno(pr);
+ if (!disk_devno)
+ return 0;
+
+ return devno == disk_devno;
}
/**
* blkid_probe_get_size:
* @pr: probe
*
- * Returns: block device (or file) size in bytes or -1 in case of error.
+ * This function returns size of probing area as defined by blkid_probe_set_device().
+ * If the size of the probing area is unrestricted then this function returns
+ * the real size of device. See also blkid_get_dev_size().
+ *
+ * Returns: size in bytes or -1 in case of error.
*/
blkid_loff_t blkid_probe_get_size(blkid_probe pr)
{
}
/**
- * blkid_probe_get_sectorsize:
+ * blkid_probe_get_offset:
+ * @pr: probe
+ *
+ * This function returns offset of probing area as defined by blkid_probe_set_device().
+ *
+ * Returns: offset in bytes or -1 in case of error.
+ */
+blkid_loff_t blkid_probe_get_offset(blkid_probe pr)
+{
+ return pr ? pr->off : -1;
+}
+
+/**
+ * blkid_probe_get_fd:
* @pr: probe
*
+ * Returns: file descriptor for assigned device/file.
+ */
+int blkid_probe_get_fd(blkid_probe pr)
+{
+ return pr ? pr->fd : -1;
+}
+
+/**
+ * blkid_probe_get_sectorsize:
+ * @pr: probe or NULL (for NULL returns 512)
+ *
* Returns: block device logical sector size (BLKSSZGET ioctl, default 512).
*/
unsigned int blkid_probe_get_sectorsize(blkid_probe pr)
{
if (!pr)
return DEFAULT_SECTOR_SIZE; /*... and good luck! */
+
if (pr->blkssz)
return pr->blkssz;
- if (!pr->mode) {
- struct stat st;
-
- if (fstat(pr->fd, &st))
- goto fallback;
- pr->mode = st.st_mode;
- }
- if (S_ISBLK(pr->mode)) {
- if (blkdev_get_sector_size(pr->fd, (int *) &pr->blkssz))
- goto fallback;
- return pr->blkssz;
- }
+ if (S_ISBLK(pr->mode) &&
+ blkdev_get_sector_size(pr->fd, (int *) &pr->blkssz) == 0)
+ return pr->blkssz;
-fallback:
pr->blkssz = DEFAULT_SECTOR_SIZE;
return pr->blkssz;
}
+/**
+ * blkid_probe_get_sectors:
+ * @pr: probe
+ *
+ * Returns: 512-byte sector count or -1 in case of error.
+ */
+blkid_loff_t blkid_probe_get_sectors(blkid_probe pr)
+{
+ return pr ? pr->size >> 9 : -1;
+}
+
/**
* blkid_probe_numof_values:
* @pr: probe
return i;
}
+/*
+ * Some mkfs-like utils wipe some parts (usually begin) of the device.
+ * For example LVM (pvcreate) or mkswap(8). This information could be used
+ * for later resolution to conflicts between superblocks.
+ *
+ * For example we found valid LVM superblock, LVM wipes 8KiB at the begin of
+ * the device. If we found another signature (for example MBR) this wiped area
+ * then the signature has been added later and LVM superblock should be ignore.
+ *
+ * Note that this heuristic is not 100% reliable, for example "pvcreate --zero
+ * n" allows to keep the begin of the device unmodified. It's probably better
+ * to use this heuristic for conflicts between superblocks and partition tables
+ * than for conflicts between filesystem superblocks -- existence of unwanted
+ * partition table is very unusual, because PT is pretty visible (parsed and
+ * interpreted by kernel).
+ */
+void blkid_probe_set_wiper(blkid_probe pr, blkid_loff_t off, blkid_loff_t size)
+{
+ struct blkid_chain *chn;
+
+ if (!pr)
+ return;
+
+ if (!size) {
+ DBG(DEBUG_LOWPROBE, printf("zeroize wiper\n"));
+ pr->wipe_size = pr->wipe_off = 0;
+ pr->wipe_chain = NULL;
+ return;
+ }
+
+ chn = pr->cur_chain;
+
+ if (!chn || !chn->driver ||
+ chn->idx < 0 || chn->idx >= chn->driver->nidinfos)
+ return;
+
+ pr->wipe_size = size;
+ pr->wipe_off = off;
+ pr->wipe_chain = chn;
+
+ DBG(DEBUG_LOWPROBE,
+ printf("wiper set to %s::%s off=%jd size=%jd\n",
+ chn->driver->name,
+ chn->driver->idinfos[chn->idx]->name,
+ pr->wipe_off, pr->wipe_size));
+ return;
+}
+
+/*
+ * Returns 1 if the <@off,@size> area was wiped
+ */
+int blkid_probe_is_wiped(blkid_probe pr, struct blkid_chain **chn,
+ blkid_loff_t off, blkid_loff_t size)
+{
+ if (!pr || !size)
+ return 0;
+
+ if (pr->wipe_off <= off && off + size <= pr->wipe_off + pr->wipe_size) {
+ if (chn)
+ *chn = pr->wipe_chain;
+ return 1;
+ }
+ return 0;
+}
+
+void blkid_probe_use_wiper(blkid_probe pr, blkid_loff_t off, blkid_loff_t size)
+{
+ struct blkid_chain *chn = NULL;
+
+ if (blkid_probe_is_wiped(pr, &chn, off, size) && chn) {
+ DBG(DEBUG_LOWPROBE, printf("wiped area detected -- ignore previous results\n"));
+ blkid_probe_set_wiper(pr, 0, 0);
+ blkid_probe_chain_reset_vals(pr, chn);
+ }
+}
+