* %End-Header%
*/
+#define _GNU_SOURCE 1
+
#include <stdio.h>
#include <string.h>
+#include <limits.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "blkidP.h"
+#ifdef HAVE_DEVMAPPER
+#include <libdevmapper.h>
+#endif
+
/*
* Find a dev struct in the cache by device name, if available.
*
dev = blkid_new_dev();
if (!dev)
return NULL;
+ dev->bid_time = INT_MIN;
dev->bid_name = blkid_strdup(devname);
dev->bid_cache = cache;
list_add_tail(&dev->bid_devs, &cache->bic_devs);
}
if (flags & BLKID_DEV_VERIFY)
- dev = blkid_verify_devname(cache, dev);
+ dev = blkid_verify(cache, dev);
return dev;
}
+#ifdef HAVE_DEVMAPPER
+static int dm_device_is_leaf(const dev_t dev);
+#endif
+
/*
* Probe a single block device to add to the device cache.
*/
static void probe_one(blkid_cache cache, const char *ptname,
- dev_t devno, int pri)
+ dev_t devno, int pri, int only_if_new)
{
blkid_dev dev = NULL;
struct list_head *p;
list_for_each(p, &cache->bic_devs) {
blkid_dev tmp = list_entry(p, struct blkid_struct_dev,
bid_devs);
+#ifdef HAVE_DEVMAPPER
+ if (!dm_device_is_leaf(devno))
+ continue;
+#endif
if (tmp->bid_devno == devno) {
- dev = blkid_verify_devname(cache, tmp);
+ if (only_if_new)
+ return;
+ dev = blkid_verify(cache, tmp);
break;
}
}
dev->bid_devno == devno)
goto set_pri;
- if (stat(device, &st) == 0 && st.st_rdev == devno) {
+ if (stat(device, &st) == 0 && S_ISBLK(st.st_mode) &&
+ st.st_rdev == devno) {
devname = blkid_strdup(device);
break;
}
set_pri:
if (!pri && !strncmp(ptname, "md", 2))
pri = BLKID_PRI_MD;
- dev->bid_pri = pri;
+ if (dev)
+ dev->bid_pri = pri;
+ return;
+}
+
+#ifdef HAVE_DEVMAPPER
+static void dm_quiet_log(int level __BLKID_ATTR((unused)),
+ const char *file __BLKID_ATTR((unused)),
+ int line __BLKID_ATTR((unused)),
+ const char *f __BLKID_ATTR((unused)), ...)
+{
return;
}
+/*
+ * device-mapper support
+ */
+static int dm_device_has_dep(const dev_t dev, const char *name)
+{
+ struct dm_task *task;
+ struct dm_deps *deps;
+ struct dm_info info;
+ unsigned int i;
+
+ task = dm_task_create(DM_DEVICE_DEPS);
+ if (!task)
+ return 0;
+
+ dm_task_set_name(task, name);
+ dm_task_run(task);
+ dm_task_get_info(task, &info);
+
+ if (!info.exists) {
+ dm_task_destroy(task);
+ return 0;
+ }
+
+ deps = dm_task_get_deps(task);
+ if (!deps || deps->count == 0) {
+ dm_task_destroy(task);
+ return 0;
+ }
+
+ for (i = 0; i < deps->count; i++) {
+ dev_t dep_dev = deps->device[i];
+
+ if (dev == dep_dev) {
+ dm_task_destroy(task);
+ return 1;
+ }
+ }
+
+ dm_task_destroy(task);
+ return 0;
+}
+
+static int dm_device_is_leaf(const dev_t dev)
+{
+ struct dm_task *task;
+ struct dm_names *names;
+ unsigned int next = 0;
+ int n, ret = 1;
+
+ dm_log_init(dm_quiet_log);
+ task = dm_task_create(DM_DEVICE_LIST);
+ if (!task)
+ return 1;
+ dm_log_init(0);
+
+ dm_task_run(task);
+ names = dm_task_get_names(task);
+ if (!names || !names->dev) {
+ dm_task_destroy(task);
+ return 1;
+ }
+
+ n = 0;
+ do {
+ names = (struct dm_names *) ((char *)names + next);
+
+ if (dm_device_has_dep(dev, names->name))
+ ret = 0;
+
+ next = names->next;
+ } while (next);
+
+ dm_task_destroy(task);
+
+ return ret;
+}
+
+static dev_t dm_get_devno(const char *name)
+{
+ struct dm_task *task;
+ struct dm_info info;
+ dev_t ret = 0;
+
+ task = dm_task_create(DM_DEVICE_INFO);
+ if (!task)
+ return ret;
+
+ dm_task_set_name(task, name);
+ dm_task_run(task);
+ dm_task_get_info(task, &info);
+
+ if (!info.exists) {
+ dm_task_destroy(task);
+ return ret;
+ }
+
+ ret = makedev(info.major, info.minor);
+
+ dm_task_destroy(task);
+
+ return ret;
+}
+
+static void dm_probe_all(blkid_cache cache, int only_if_new)
+{
+ struct dm_task *task;
+ struct dm_names *names;
+ unsigned int next = 0;
+ int n;
+
+ dm_log_init(dm_quiet_log);
+ task = dm_task_create(DM_DEVICE_LIST);
+ if (!task)
+ return;
+ dm_log_init(0);
+
+ dm_task_run(task);
+ names = dm_task_get_names(task);
+ if (!names || !names->dev) {
+ dm_task_destroy(task);
+ return;
+ }
+
+ n = 0;
+ do {
+ int rc;
+ char *device = NULL;
+ dev_t dev = 0;
+
+ names = (struct dm_names *) ((char *)names + next);
+
+ rc = asprintf(&device, "mapper/%s", names->name);
+ if (rc < 0)
+ goto try_next;
+
+ dev = dm_get_devno(names->name);
+ if (dev == 0)
+ goto try_next;
+
+ if (!dm_device_is_leaf(dev))
+ goto try_next;
+
+ probe_one(cache, device, dev, BLKID_PRI_DM, only_if_new);
+
+try_next:
+ free(device);
+ next = names->next;
+ } while (next);
+
+ dm_task_destroy(task);
+}
+#endif /* HAVE_DEVMAPPER */
+
#define PROC_PARTITIONS "/proc/partitions"
#define VG_DIR "/proc/lvm/VGs"
return ret;
}
-static void lvm_probe_all(blkid_cache cache)
+static void lvm_probe_all(blkid_cache cache, int only_if_new)
{
DIR *vg_list;
struct dirent *vg_iter;
DBG(DEBUG_DEVNAME, printf("LVM dev %s: devno 0x%04X\n",
lvm_device,
(unsigned int) dev));
- probe_one(cache, lvm_device, dev, BLKID_PRI_LVM);
+ probe_one(cache, lvm_device, dev, BLKID_PRI_LVM,
+ only_if_new);
free(lvm_device);
}
closedir(lv_list);
#define PROC_EVMS_VOLUMES "/proc/evms/volumes"
static int
-evms_probe_all(blkid_cache cache)
+evms_probe_all(blkid_cache cache, int only_if_new)
{
char line[100];
int ma, mi, sz, num = 0;
DBG(DEBUG_DEVNAME, printf("Checking partition %s (%d, %d)\n",
device, ma, mi));
- probe_one(cache, device, makedev(ma, mi), BLKID_PRI_EVMS);
+ probe_one(cache, device, makedev(ma, mi), BLKID_PRI_EVMS,
+ only_if_new);
num++;
}
fclose(procpt);
/*
* Read the device data for all available block devices in the system.
*/
-int blkid_probe_all(blkid_cache cache)
+static int probe_all(blkid_cache cache, int only_if_new)
{
FILE *proc;
char line[1024];
char ptname0[128], ptname1[128], *ptname = 0;
- char *ptnames[2] = { ptname0, ptname1 };
+ char *ptnames[2];
dev_t devs[2];
int ma, mi;
unsigned long long sz;
int lens[2] = { 0, 0 };
int which = 0, last = 0;
+ ptnames[0] = ptname0;
+ ptnames[1] = ptname1;
+
if (!cache)
return -BLKID_ERR_PARAM;
time(0) - cache->bic_time < BLKID_PROBE_INTERVAL)
return 0;
- evms_probe_all(cache);
+ blkid_read_cache(cache);
+#ifdef HAVE_DEVMAPPER
+ dm_probe_all(cache, only_if_new);
+#endif
+ evms_probe_all(cache, only_if_new);
#ifdef VG_DIR
- lvm_probe_all(cache);
+ lvm_probe_all(cache, only_if_new);
#endif
proc = fopen(PROC_PARTITIONS, "r");
which ^= 1;
ptname = ptnames[which];
- if (sscanf(line, " %d %d %lld %128[^\n ]",
+ if (sscanf(line, " %d %d %llu %128[^\n ]",
&ma, &mi, &sz, ptname) != 4)
continue;
devs[which] = makedev(ma, mi);
ptname, (unsigned int) devs[which]));
if (sz > 1)
- probe_one(cache, ptname, devs[which], 0);
+ probe_one(cache, ptname, devs[which], 0,
+ only_if_new);
lens[which] = 0;
lens[last] = 0;
} else if (lens[last] && strncmp(ptnames[last], ptname,
DBG(DEBUG_DEVNAME,
printf("whole dev %s, devno 0x%04X\n",
ptnames[last], (unsigned int) devs[last]));
- probe_one(cache, ptnames[last], devs[last], 0);
+ probe_one(cache, ptnames[last], devs[last], 0,
+ only_if_new);
lens[last] = 0;
}
}
/* Handle the last device if it wasn't partitioned */
if (lens[which])
- probe_one(cache, ptname, devs[which], 0);
+ probe_one(cache, ptname, devs[which], 0, only_if_new);
fclose(proc);
+ blkid_flush_cache(cache);
+ return 0;
+}
+
+int blkid_probe_all(blkid_cache cache)
+{
+ int ret;
+ DBG(DEBUG_PROBE, printf("Begin blkid_probe_all()\n"));
+ ret = probe_all(cache, 0);
cache->bic_time = time(0);
cache->bic_flags |= BLKID_BIC_FL_PROBED;
- return 0;
+ DBG(DEBUG_PROBE, printf("End blkid_probe_all()\n"));
+ return ret;
+}
+
+int blkid_probe_all_new(blkid_cache cache)
+{
+ int ret;
+
+ DBG(DEBUG_PROBE, printf("Begin blkid_probe_all_new()\n"));
+ ret = probe_all(cache, 1);
+ DBG(DEBUG_PROBE, printf("End blkid_probe_all_new()\n"));
+ return ret;
}
+
#ifdef TEST_PROGRAM
int main(int argc, char **argv)
{
blkid_cache cache = NULL;
+ int ret;
blkid_debug_mask = DEBUG_ALL;
if (argc != 1) {
"Probe all devices and exit\n", argv[0]);
exit(1);
}
- if ((cache = blkid_new_cache()) == NULL) {
- fprintf(stderr, "%s: error creating cache\n", argv[0]);
+ if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) {
+ fprintf(stderr, "%s: error creating cache (%d)\n",
+ argv[0], ret);
exit(1);
}
if (blkid_probe_all(cache) < 0)