Update to upstream util-linux 2.20.1
[framework/base/util-linux-ng.git] / libblkid / src / devname.c
similarity index 76%
rename from shlibs/blkid/src/devname.c
rename to libblkid/src/devname.c
index ef686f4..e1fc2c8 100644 (file)
@@ -20,8 +20,8 @@
 #include <unistd.h>
 #endif
 #include <stdlib.h>
-#include <string.h>
 #include <ctype.h>
+#include <fcntl.h>
 #if HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
 #if HAVE_ERRNO_H
 #include <errno.h>
 #endif
-#if HAVE_SYS_MKDEV_H
-#include <sys/mkdev.h>
-#endif
 #include <time.h>
 
 #include "blkidP.h"
 
+#include "canonicalize.h"              /* $(top_srcdir)/include */
+#include "pathnames.h"
+#include "sysfs.h"
+#include "at.h"
+
 /*
  * Find a dev struct in the cache by device name, if available.
  *
@@ -153,34 +155,10 @@ static int is_dm_leaf(const char *devname)
 }
 
 /*
- * Since 2.6.29 (patch 784aae735d9b0bba3f8b9faef4c8b30df3bf0128) kernel sysfs
- * provides the real DM device names in /sys/block/<ptname>/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 "<name>\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, int only_if_new)
+                     dev_t devno, int pri, int only_if_new, int removable)
 {
        blkid_dev dev = NULL;
        struct list_head *p, *pnext;
@@ -207,7 +185,7 @@ static void probe_one(blkid_cache cache, const char *ptname,
         * to standard /dev/mapper/<name>.
         */
        if (!strncmp(ptname, "dm-", 3) && isdigit(ptname[3])) {
-               devname = get_dm_name(ptname);
+               devname = canonicalize_dm_name(ptname);
                if (!devname)
                        blkid__scan_dir("/dev/mapper", devno, 0, &devname);
                if (devname)
@@ -229,7 +207,9 @@ static void probe_one(blkid_cache cache, const char *ptname,
                    dev->bid_devno == devno)
                        goto set_pri;
 
-               if (stat(device, &st) == 0 && S_ISBLK(st.st_mode) &&
+               if (stat(device, &st) == 0 &&
+                   (S_ISBLK(st.st_mode) ||
+                    (S_ISCHR(st.st_mode) && !strncmp(ptname, "ubi", 3))) &&
                    st.st_rdev == devno) {
                        devname = blkid_strdup(device);
                        goto get_dev;
@@ -258,6 +238,8 @@ set_pri:
                                dev->bid_pri += 5;
                } else if (!strncmp(ptname, "md", 2))
                        dev->bid_pri = BLKID_PRI_MD;
+               if (removable)
+                       dev->bid_flags |= BLKID_BID_FL_REMOVABLE;
        }
        return;
 }
@@ -349,7 +331,7 @@ static void lvm_probe_all(blkid_cache cache, int only_if_new)
                                                  lvm_device,
                                                  (unsigned int) dev));
                        probe_one(cache, lvm_device, dev, BLKID_PRI_LVM,
-                                 only_if_new);
+                                 only_if_new, 0);
                        free(lvm_device);
                }
                closedir(lv_list);
@@ -381,13 +363,60 @@ evms_probe_all(blkid_cache cache, int only_if_new)
                                          device, ma, mi));
 
                probe_one(cache, device, makedev(ma, mi), BLKID_PRI_EVMS,
-                         only_if_new);
+                         only_if_new, 0);
                num++;
        }
        fclose(procpt);
        return num;
 }
 
+static void
+ubi_probe_all(blkid_cache cache, int only_if_new)
+{
+       const char **dirname;
+
+       for (dirname = dirlist; *dirname; dirname++) {
+               DBG(DEBUG_DEVNAME, printf("probing UBI volumes under %s\n",
+                                         *dirname));
+
+               DIR             *dir;
+               struct dirent   *iter;
+
+               dir = opendir(*dirname);
+               if (dir == NULL)
+                       continue ;
+
+               while ((iter = readdir(dir)) != NULL) {
+                       char            *name;
+                       struct stat     st;
+                       dev_t           dev;
+
+                       name = iter->d_name;
+#ifdef _DIRENT_HAVE_D_TYPE
+                       if (iter->d_type != DT_UNKNOWN &&
+                           iter->d_type != DT_CHR && iter->d_type != DT_LNK)
+                               continue;
+#endif
+                       if (!strcmp(name, ".") || !strcmp(name, "..") ||
+                           !strstr(name, "ubi"))
+                               continue;
+                       if (!strcmp(name, "ubi_ctrl"))
+                               continue;
+                       if (fstat_at(dirfd(dir), *dirname, name, &st, 0))
+                               continue;
+
+                       dev = st.st_rdev;
+
+                       if (!S_ISCHR(st.st_mode) || !minor(dev))
+                               continue;
+                       DBG(DEBUG_DEVNAME, printf("UBI vol %s/%s: devno 0x%04X\n",
+                                 *dirname, name, (int) dev));
+                       probe_one(cache, name, dev, BLKID_PRI_UBI, only_if_new, 0);
+               }
+               closedir(dir);
+       }
+}
+
 /*
  * Read the device data for all available block devices in the system.
  */
@@ -419,6 +448,7 @@ static int probe_all(blkid_cache cache, int only_if_new)
 #ifdef VG_DIR
        lvm_probe_all(cache, only_if_new);
 #endif
+       ubi_probe_all(cache, only_if_new);
 
        proc = fopen(PROC_PARTITIONS, "r");
        if (!proc)
@@ -458,7 +488,7 @@ static int probe_all(blkid_cache cache, int only_if_new)
 
                        if (sz > 1)
                                probe_one(cache, ptname, devs[which], 0,
-                                         only_if_new);
+                                         only_if_new, 0);
                        lens[which] = 0;        /* mark as checked */
                }
 
@@ -495,20 +525,74 @@ static int probe_all(blkid_cache cache, int only_if_new)
                            printf("whole dev %s, devno 0x%04X\n",
                                   ptnames[last], (unsigned int) devs[last]));
                        probe_one(cache, ptnames[last], devs[last], 0,
-                                 only_if_new);
+                                 only_if_new, 0);
                        lens[last] = 0;
                }
        }
 
        /* Handle the last device if it wasn't partitioned */
        if (lens[which])
-               probe_one(cache, ptname, devs[which], 0, only_if_new);
+               probe_one(cache, ptname, devs[which], 0, only_if_new, 0);
 
        fclose(proc);
        blkid_flush_cache(cache);
        return 0;
 }
 
+/* Don't use it by default -- it's pretty slow (because cdroms, floppy, ...)
+ */
+static int probe_all_removable(blkid_cache cache)
+{
+       DIR *dir;
+       struct dirent *d;
+
+       if (!cache)
+               return -BLKID_ERR_PARAM;
+
+       dir = opendir(_PATH_SYS_BLOCK);
+       if (!dir)
+               return -BLKID_ERR_PROC;
+
+       while((d = readdir(dir))) {
+               struct sysfs_cxt sysfs;
+               int removable = 0;
+               dev_t devno;
+
+#ifdef _DIRENT_HAVE_D_TYPE
+               if (d->d_type != DT_UNKNOWN && d->d_type != DT_LNK)
+                       continue;
+#endif
+               if (d->d_name[0] == '.' &&
+                   ((d->d_name[1] == 0) ||
+                    ((d->d_name[1] == '.') && (d->d_name[2] == 0))))
+                       continue;
+
+               devno = sysfs_devname_to_devno(d->d_name, NULL);
+               if (!devno)
+                       continue;
+
+               if (sysfs_init(&sysfs, devno, NULL) == 0) {
+                       sysfs_read_int(&sysfs, "removable", &removable);
+                       sysfs_deinit(&sysfs);
+               }
+
+               if (removable)
+                       probe_one(cache, d->d_name, devno, 0, 0, 1);
+       }
+
+       closedir(dir);
+       return 0;
+}
+
+
+/**
+ * blkid_probe_all:
+ * @cache: cache handler
+ *
+ * Probes all block devices.
+ *
+ * Returns: 0 on success, or number less than zero in case of error.
+ */
 int blkid_probe_all(blkid_cache cache)
 {
        int ret;
@@ -521,6 +605,14 @@ int blkid_probe_all(blkid_cache cache)
        return ret;
 }
 
+/**
+ * blkid_probe_all_new:
+ * @cache: cache handler
+ *
+ * Probes all new block devices.
+ *
+ * Returns: 0 on success, or number less than zero in case of error.
+ */
 int blkid_probe_all_new(blkid_cache cache)
 {
        int ret;
@@ -531,6 +623,33 @@ int blkid_probe_all_new(blkid_cache cache)
        return ret;
 }
 
+/**
+ * blkid_probe_all_removable:
+ * @cache: cache handler
+ *
+ * The libblkid probing is based on devices from /proc/partitions by default.
+ * This file usually does not contain removable devices (e.g. CDROMs) and this kind
+ * of devices are invisible for libblkid.
+ *
+ * This function adds removable block devices to @cache (probing is based on
+ * information from the /sys directory). Don't forget that removable devices
+ * (floppies, CDROMs, ...) could be pretty slow. It's very bad idea to call
+ * this function by default.
+ *
+ * Note that devices which were detected by this function won't be written to
+ * blkid.tab cache file.
+ *
+ * Returns: 0 on success, or number less than zero in case of error.
+ */
+int blkid_probe_all_removable(blkid_cache cache)
+{
+       int ret;
+
+       DBG(DEBUG_PROBE, printf("Begin blkid_probe_all_removable()\n"));
+       ret = probe_all_removable(cache);
+       DBG(DEBUG_PROBE, printf("End blkid_probe_all_removable()\n"));
+       return ret;
+}
 
 #ifdef TEST_PROGRAM
 int main(int argc, char **argv)
@@ -552,6 +671,9 @@ int main(int argc, char **argv)
        if (blkid_probe_all(cache) < 0)
                printf("%s: error probing devices\n", argv[0]);
 
+       if (blkid_probe_all_removable(cache) < 0)
+               printf("%s: error probing removable devices\n", argv[0]);
+
        blkid_put_cache(cache);
        return (0);
 }