X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lib%2Fblkid%2Fdevname.c;h=3e2efa9d5cb20fc776583dbbb2211273fc363c9a;hb=766c14289119c6ecc362e0e5093ca82a51b5e1ca;hp=df7700185e1c47e42100bee2ff27428ffeb4b4be;hpb=ed78c021c3b111d8ab9a51aef5d5156e3004083f;p=tools%2Fe2fsprogs.git diff --git a/lib/blkid/devname.c b/lib/blkid/devname.c index df77001..3e2efa9 100644 --- a/lib/blkid/devname.c +++ b/lib/blkid/devname.c @@ -11,8 +11,12 @@ * %End-Header% */ +#define _GNU_SOURCE 1 + +#include "config.h" #include #include +#include #if HAVE_UNISTD_H #include #endif @@ -22,6 +26,7 @@ #if HAVE_SYS_TYPES_H #include #endif +#include #if HAVE_SYS_STAT_H #include #endif @@ -44,7 +49,7 @@ blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, int flags) { blkid_dev dev = NULL, tmp; - struct list_head *p; + struct list_head *p, *pnext; if (!cache || !devname) return NULL; @@ -54,57 +59,167 @@ blkid_dev blkid_get_dev(blkid_cache cache, const char *devname, int flags) if (strcmp(tmp->bid_name, devname)) continue; - DBG(DEBUG_DEVNAME, + DBG(DEBUG_DEVNAME, printf("found devname %s in cache\n", tmp->bid_name)); dev = tmp; break; } if (!dev && (flags & BLKID_DEV_CREATE)) { + if (access(devname, F_OK) < 0) + return NULL; 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); cache->bic_flags |= BLKID_BIC_FL_CHANGED; } - if (flags & BLKID_DEV_VERIFY) - dev = blkid_verify_devname(cache, dev); + if (flags & BLKID_DEV_VERIFY) { + dev = blkid_verify(cache, dev); + if (!dev || !(dev->bid_flags & BLKID_BID_FL_VERIFIED)) + return dev; + /* + * If the device is verified, then search the blkid + * cache for any entries that match on the type, uuid, + * and label, and verify them; if a cache entry can + * not be verified, then it's stale and so we remove + * it. + */ + list_for_each_safe(p, pnext, &cache->bic_devs) { + blkid_dev dev2; + dev2 = list_entry(p, struct blkid_struct_dev, bid_devs); + if (dev2->bid_flags & BLKID_BID_FL_VERIFIED) + continue; + if (!dev->bid_type || !dev2->bid_type || + strcmp(dev->bid_type, dev2->bid_type)) + continue; + if (dev->bid_label && dev2->bid_label && + strcmp(dev->bid_label, dev2->bid_label)) + continue; + if (dev->bid_uuid && dev2->bid_uuid && + strcmp(dev->bid_uuid, dev2->bid_uuid)) + continue; + if ((dev->bid_label && !dev2->bid_label) || + (!dev->bid_label && dev2->bid_label) || + (dev->bid_uuid && !dev2->bid_uuid) || + (!dev->bid_uuid && dev2->bid_uuid)) + continue; + dev2 = blkid_verify(cache, dev2); + if (dev2 && !(dev2->bid_flags & BLKID_BID_FL_VERIFIED)) + blkid_free_dev(dev2); + } + } return dev; } +/* Directories where we will try to search for device names */ +static const char *dirlist[] = { "/dev", "/devfs", "/devices", NULL }; + +static int is_dm_leaf(const char *devname) +{ + struct dirent *de, *d_de; + DIR *dir, *d_dir; + char path[256]; + int ret = 1; + + if ((dir = opendir("/sys/block")) == NULL) + return 0; + while ((de = readdir(dir)) != NULL) { + if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..") || + !strcmp(de->d_name, devname) || + strncmp(de->d_name, "dm-", 3) || + strlen(de->d_name) > sizeof(path)-32) + continue; + sprintf(path, "/sys/block/%s/slaves", de->d_name); + if ((d_dir = opendir(path)) == NULL) + continue; + while ((d_de = readdir(d_dir)) != NULL) { + if (!strcmp(d_de->d_name, devname)) { + ret = 0; + break; + } + } + closedir(d_dir); + if (!ret) + break; + } + closedir(dir); + return ret; +} + +/* + * Since 2.6.29 (patch 784aae735d9b0bba3f8b9faef4c8b30df3bf0128) kernel sysfs + * provides the real DM device names in /sys/block//dm/name + */ +static char *get_dm_name(const char *ptname) +{ + FILE *f; + size_t sz; + char path[256], name[256], *res = NULL; + + snprintf(path, sizeof(path), "/sys/block/%s/dm/name", ptname); + if ((f = fopen(path, "r")) == NULL) + return NULL; + + /* read "\n" from sysfs */ + if (fgets(name, sizeof(name), f) && (sz = strlen(name)) > 1) { + name[sz - 1] = '\0'; + snprintf(path, sizeof(path), "/dev/mapper/%s", name); + res = blkid_strdup(path); + } + fclose(f); + return res; +} + /* * 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; + struct list_head *p, *pnext; const char **dir; char *devname = NULL; /* See if we already have this device number in the cache. */ - list_for_each(p, &cache->bic_devs) { + list_for_each_safe(p, pnext, &cache->bic_devs) { blkid_dev tmp = list_entry(p, struct blkid_struct_dev, bid_devs); if (tmp->bid_devno == devno) { - dev = blkid_verify_devname(cache, tmp); - break; + if (only_if_new && !access(tmp->bid_name, F_OK)) + return; + dev = blkid_verify(cache, tmp); + if (dev && (dev->bid_flags & BLKID_BID_FL_VERIFIED)) + break; + dev = 0; } } if (dev && dev->bid_devno == devno) goto set_pri; + /* Try to translate private device-mapper dm- names + * to standard /dev/mapper/. + */ + if (!strncmp(ptname, "dm-", 3) && isdigit(ptname[3])) { + devname = get_dm_name(ptname); + if (!devname) + blkid__scan_dir("/dev/mapper", devno, 0, &devname); + if (devname) + goto get_dev; + } + /* * Take a quick look at /dev/ptname for the device number. We check * all of the likely device directories. If we don't find it, or if * the stat information doesn't check out, use blkid_devno_to_devname() * to find it via an exhaustive search for the device major/minor. */ - for (dir = blkid_devdirs; *dir; dir++) { + for (dir = dirlist; *dir; dir++) { struct stat st; char device[256]; @@ -113,23 +228,36 @@ static void probe_one(blkid_cache cache, const char *ptname, 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; + goto get_dev; } } + /* Do a short-cut scan of /dev/mapper first */ + if (!devname) + devname = get_dm_name(ptname); + if (!devname) + blkid__scan_dir("/dev/mapper", devno, 0, &devname); if (!devname) { devname = blkid_devno_to_devname(devno); if (!devname) return; } +get_dev: dev = blkid_get_dev(cache, devname, BLKID_DEV_NORMAL); free(devname); - set_pri: - if (!pri && !strncmp(ptname, "md", 2)) - pri = BLKID_PRI_MD; - dev->bid_pri = pri; + if (dev) { + if (pri) + dev->bid_pri = pri; + else if (!strncmp(dev->bid_name, "/dev/mapper/", 11)) { + dev->bid_pri = BLKID_PRI_DM; + if (is_dm_leaf(ptname)) + dev->bid_pri += 5; + } else if (!strncmp(ptname, "md", 2)) + dev->bid_pri = BLKID_PRI_MD; + } return; } @@ -143,7 +271,6 @@ set_pri: * safe thing to do?) */ #ifdef VG_DIR -#include static dev_t lvm_get_devno(const char *lvm_device) { FILE *lvf; @@ -169,7 +296,7 @@ static dev_t lvm_get_devno(const char *lvm_device) 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; @@ -220,7 +347,8 @@ static void lvm_probe_all(blkid_cache cache) 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); @@ -233,7 +361,7 @@ exit: #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; @@ -251,7 +379,8 @@ evms_probe_all(blkid_cache cache) 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); @@ -261,7 +390,7 @@ evms_probe_all(blkid_cache cache) /* * 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]; @@ -272,6 +401,7 @@ int blkid_probe_all(blkid_cache cache) unsigned long long sz; int lens[2] = { 0, 0 }; int which = 0, last = 0; + struct list_head *p, *pnext; ptnames[0] = ptname0; ptnames[1] = ptname1; @@ -284,9 +414,9 @@ int blkid_probe_all(blkid_cache cache) return 0; blkid_read_cache(cache); - evms_probe_all(cache); + 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"); @@ -298,17 +428,18 @@ int blkid_probe_all(blkid_cache cache) 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); DBG(DEBUG_DEVNAME, printf("read partition name %s\n", ptname)); - /* Skip whole disk devs unless they have no partitions - * If we don't have a partition on this dev, also + /* Skip whole disk devs unless they have no partitions. + * If base name of device has changed, also * check previous dev to see if it didn't have a partn. - * heuristic: partition name ends in a digit. + * heuristic: partition name ends in a digit, & partition + * names contain whole device name as substring. * * Skip extended partitions. * heuristic: size is 1 @@ -317,37 +448,89 @@ int blkid_probe_all(blkid_cache cache) */ lens[which] = strlen(ptname); + + /* ends in a digit, clearly a partition, so check */ if (isdigit(ptname[lens[which] - 1])) { DBG(DEBUG_DEVNAME, printf("partition dev %s, devno 0x%04X\n", ptname, (unsigned int) devs[which])); if (sz > 1) - probe_one(cache, ptname, devs[which], 0); - lens[which] = 0; + probe_one(cache, ptname, devs[which], 0, + only_if_new); + lens[which] = 0; /* mark as checked */ + } + + /* + * If last was a whole disk and we just found a partition + * on it, remove the whole-disk dev from the cache if + * it exists. + */ + if (lens[last] && !strncmp(ptnames[last], ptname, lens[last])) { + list_for_each_safe(p, pnext, &cache->bic_devs) { + blkid_dev tmp; + + /* find blkid dev for the whole-disk devno */ + tmp = list_entry(p, struct blkid_struct_dev, + bid_devs); + if (tmp->bid_devno == devs[last]) { + DBG(DEBUG_DEVNAME, + printf("freeing %s\n", + tmp->bid_name)); + blkid_free_dev(tmp); + cache->bic_flags |= BLKID_BIC_FL_CHANGED; + break; + } + } lens[last] = 0; - } else if (lens[last] && strncmp(ptnames[last], ptname, - lens[last])) { + } + /* + * If last was not checked because it looked like a whole-disk + * dev, and the device's base name has changed, + * check last as well. + */ + if (lens[last] && strncmp(ptnames[last], ptname, lens[last])) { 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; - blkid_flush_cache(cache); - 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) {