libfstools: skip JFFS2 padding when BLOCKSIZE was given
[project/fstools.git] / libfstools / partname.c
index 5d4fde5c8cb85c7cb0c21b14c3b82bcf7c058ca1..9f2347a02acec9bd7b1af4d421c7891b864e8ee0 100644 (file)
@@ -4,8 +4,6 @@
 
 #define BUFLEN 64
 
-const char *const block_dir_name = "/sys/class/block";
-
 struct devpath {
        char prefix[5];
        char device[11];
@@ -61,11 +59,14 @@ static int partname_volume_init(struct volume *v)
        return block_volume_format(v, 0, p->parent_dev.devpathstr);
 }
 
-/* from procd/utils.c -> should go to libubox */
-static char* get_cmdline_val(const char* name, char* out, int len)
+/* adapted from procd/utils.c -> should go to libubox */
+static char* get_var_from_file(const char* filename, const char* name, char* out, int len)
 {
        char line[1024], *c, *sptr;
-       int fd = open("/proc/cmdline", O_RDONLY);
+       int fd = open(filename, O_RDONLY);
+       if (fd == -1)
+               return NULL;
+
        ssize_t r = read(fd, line, sizeof(line) - 1);
        close(fd);
 
@@ -112,31 +113,52 @@ static char *rootdevname(char *devpath) {
 static struct volume *partname_volume_find(char *name)
 {
        struct partname_volume *p;
-       char volnamegstr[BUFLEN];
+       char ueventgstr[BUFLEN];
        char namebuf[BUFLEN];
        char rootparam[BUFLEN];
        char *rootdev = NULL, *devname, *tmp;
        int j;
        bool found = false;
+       bool allow_fallback = false;
+       bool has_root = false;
        glob_t gl;
 
-       if (get_cmdline_val("fstools_ignore_partname", rootparam, sizeof(rootparam))) {
+       if (get_var_from_file("/proc/cmdline", "fstools_ignore_partname", rootparam, sizeof(rootparam))) {
                if (!strcmp("1", rootparam))
                        return NULL;
        }
 
-       if (get_cmdline_val("root", rootparam, sizeof(rootparam))) {
+       /*
+        * Some device may contains a GPT partition named rootfs_data that may not be suitable.
+        * To save from regression with old implementation that doesn't use fstools_ignore_partname to
+        * explicitly say that that partname scan should be ignored, make explicit that scanning each
+        * partition should be done by providing fstools_partname_fallback_scan=1 and skip partname scan
+        * in every other case.
+        */
+       if (get_var_from_file("/proc/cmdline", "fstools_partname_fallback_scan", rootparam, sizeof(rootparam))) {
+               if (!strcmp("1", rootparam))
+                       allow_fallback = true;
+       }
+
+       if (get_var_from_file("/proc/cmdline", "root", rootparam, sizeof(rootparam)))
+               has_root = true;
+
+       if (has_root && rootparam[0] == '/') {
                rootdev = rootdevname(rootparam);
                /* find partition on same device as rootfs */
-               snprintf(volnamegstr, sizeof(volnamegstr), "%s/%s/*/name", block_dir_name, rootdev);
+               snprintf(ueventgstr, sizeof(ueventgstr), "%s/%s/*/uevent", block_dir_name, rootdev);
        } else {
-               /* no 'root=' kernel cmdline parameter, find on any block device */
-               snprintf(volnamegstr, sizeof(volnamegstr), "%s/*/name", block_dir_name);
+               /* For compatibility, devices with root= params must explicitly opt into this fallback. */
+               if (has_root && !allow_fallback)
+                       return NULL;
+
+               /* no useful 'root=' kernel cmdline parameter, find on any block device */
+               snprintf(ueventgstr, sizeof(ueventgstr), "%s/*/uevent", block_dir_name);
        }
 
-       if (!glob(volnamegstr, GLOB_NOESCAPE, NULL, &gl))
+       if (!glob(ueventgstr, GLOB_NOESCAPE, NULL, &gl))
                for (j = 0; j < gl.gl_pathc; j++) {
-                       if (!read_string_from_file("", gl.gl_pathv[j], namebuf, sizeof(namebuf)))
+                       if (!get_var_from_file(gl.gl_pathv[j], "PARTNAME", namebuf, sizeof(namebuf)))
                                continue;
                        if (!strncmp(namebuf, name, sizeof(namebuf))) {
                                found = 1;
@@ -149,6 +171,9 @@ static struct volume *partname_volume_find(char *name)
 
        devname = gl.gl_pathv[j];
        tmp = strrchr(devname, '/');
+       if (!tmp)
+               return NULL;
+
        *tmp = '\0';
        devname = strrchr(devname, '/') + 1;
 
@@ -174,6 +199,7 @@ static struct volume *partname_volume_find(char *name)
 
 static struct driver partname_driver = {
        .name = "partname",
+       .priority = 25,
        .find = partname_volume_find,
        .init = partname_volume_init,
        .identify = partname_volume_identify,