chiark / gitweb /
fstab-generator: merge /proc/cmdline parsing loops into one
authorLennart Poettering <lennart@poettering.net>
Thu, 6 Mar 2014 20:14:26 +0000 (21:14 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 7 Mar 2014 01:40:24 +0000 (02:40 +0100)
src/core/mount.c
src/fstab-generator/fstab-generator.c
src/shared/generator.c
src/shared/util.c
src/shared/util.h

index 60067d4d75c2b65e777cad13c8e2d261fa431bde..b4b6080ea8f70a650ad0adfbfb98a8bd71abdedf 100644 (file)
@@ -62,20 +62,6 @@ static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = {
 static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
 static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
 
-static char* mount_test_option(const char *haystack, const char *needle) {
-        struct mntent me = { .mnt_opts = (char*) haystack };
-
-        assert(needle);
-
-        /* Like glibc's hasmntopt(), but works on a string, not a
-         * struct mntent */
-
-        if (!haystack)
-                return NULL;
-
-        return hasmntopt(&me, needle);
-}
-
 static bool mount_is_network(MountParameters *p) {
         assert(p);
 
index 248a4ceb90d4d8af4aeace4f31cb1f88c18583a1..57d0a53f2847051759f3cd4c999ed84c64b86023 100644 (file)
 
 static const char *arg_dest = "/tmp";
 static bool arg_fstab_enabled = true;
+static char *arg_root_what = NULL;
+static char *arg_root_fstype = NULL;
+static char *arg_root_options = NULL;
+static int arg_root_rw = -1;
 
 static int mount_find_pri(struct mntent *me, int *ret) {
         char *end, *pri;
@@ -152,7 +156,7 @@ static bool mount_in_initrd(struct mntent *me) {
 static int add_mount(
                 const char *what,
                 const char *where,
-                const char *type,
+                const char *fstype,
                 const char *opts,
                 int passno,
                 bool noauto,
@@ -169,11 +173,10 @@ static int add_mount(
 
         assert(what);
         assert(where);
-        assert(type);
         assert(opts);
         assert(source);
 
-        if (streq(type, "autofs"))
+        if (streq_ptr(fstype, "autofs"))
                 return 0;
 
         if (!is_path(where)) {
@@ -221,7 +224,7 @@ static int add_mount(
                         post);
 
         if (passno != 0) {
-                r = generator_write_fsck_deps(f, arg_dest, what, where, type);
+                r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
                 if (r < 0)
                         return r;
         }
@@ -230,16 +233,15 @@ static int add_mount(
                 "\n"
                 "[Mount]\n"
                 "What=%s\n"
-                "Where=%s\n"
-                "Type=%s\n",
+                "Where=%s\n",
                 what,
-                where,
-                type);
+                where);
+
+        if (!isempty(fstype) && !streq(fstype, "auto"))
+                fprintf(f, "Type=%s\n", fstype);
 
         if (!isempty(opts) && !streq(opts, "defaults"))
-                fprintf(f,
-                        "Options=%s\n",
-                        opts);
+                fprintf(f, "Options=%s\n", opts);
 
         fflush(f);
         if (ferror(f)) {
@@ -316,7 +318,7 @@ static int add_mount(
 }
 
 static int parse_fstab(bool initrd) {
-        _cleanup_endmntent_ FILE *f;
+        _cleanup_endmntent_ FILE *f = NULL;
         const char *fstab_path;
         struct mntent *me;
         int r = 0;
@@ -372,9 +374,16 @@ static int parse_fstab(bool initrd) {
                         else
                                 post = SPECIAL_LOCAL_FS_TARGET;
 
-                        k = add_mount(what, where, me->mnt_type, me->mnt_opts,
-                                      me->mnt_passno, noauto, nofail, automount,
-                                      post, fstab_path);
+                        k = add_mount(what,
+                                      where,
+                                      me->mnt_type,
+                                      me->mnt_opts,
+                                      me->mnt_passno,
+                                      noauto,
+                                      nofail,
+                                      automount,
+                                      post,
+                                      fstab_path);
                 }
 
                 if (k < 0)
@@ -384,90 +393,56 @@ static int parse_fstab(bool initrd) {
         return r;
 }
 
-static int parse_new_root_from_proc_cmdline(void) {
-        _cleanup_free_ char *what = NULL, *type = NULL, *opts = NULL, *line = NULL;
+static int add_root_mount(void) {
+        _cleanup_free_ char *o = NULL, *what = NULL;
         bool noauto, nofail;
-        char *w, *state;
-        size_t l;
-        int r;
-
-        r = proc_cmdline(&line);
-        if (r < 0)
-                log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
-        if (r <= 0)
-                return 0;
-
-        opts = strdup("ro");
-        type = strdup("auto");
-        if (!opts || !type)
-                return log_oom();
-
-        /* root= and roofstype= may occur more than once, the last instance should take precedence.
-         * In the case of multiple rootflags= the arguments should be concatenated */
-        FOREACH_WORD_QUOTED(w, l, line, state) {
-                _cleanup_free_ char *word;
-
-                word = strndup(w, l);
-                if (!word)
-                        return log_oom();
 
-                else if (startswith(word, "root=")) {
-                        free(what);
-                        what = fstab_node_to_udev_node(word+5);
-                        if (!what)
-                                return log_oom();
-
-                } else if (startswith(word, "rootfstype=")) {
-                        free(type);
-                        type = strdup(word + 11);
-                        if (!type)
-                                return log_oom();
-
-                } else if (startswith(word, "rootflags=")) {
-                        char *o;
-
-                        o = strjoin(opts, ",", word + 10, NULL);
-                        if (!o)
-                                return log_oom();
-
-                        free(opts);
-                        opts = o;
-
-                } else if (streq(word, "ro") || streq(word, "rw")) {
-                        char *o;
-
-                        o = strjoin(opts, ",", word, NULL);
-                        if (!o)
-                                return log_oom();
-
-                        free(opts);
-                        opts = o;
-                }
-        }
-
-        noauto = !!strstr(opts, "noauto");
-        nofail = !!strstr(opts, "nofail");
-
-        if (!what) {
+        if (isempty(arg_root_what)) {
                 log_debug("Could not find a root= entry on the kernel commandline.");
                 return 0;
         }
 
-        if (what[0] != '/') {
-                log_debug("Skipping entry what=%s where=/sysroot type=%s", what, type);
+        what = fstab_node_to_udev_node(arg_root_what);
+        if (!path_is_absolute(what)) {
+                log_debug("Skipping entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
                 return 0;
         }
 
-        log_debug("Found entry what=%s where=/sysroot type=%s", what, type);
-        r = add_mount(what, "/sysroot", type, opts, 1, noauto, nofail, false,
-                      SPECIAL_INITRD_ROOT_FS_TARGET, "/proc/cmdline");
+        if (!arg_root_options)
+                o = strdup(arg_root_rw > 0 ? "rw" : "ro");
+        else {
+                if (arg_root_rw >= 0 ||
+                    (!mount_test_option(arg_root_options, "ro") &&
+                     !mount_test_option(arg_root_options, "rw")))
+                        o = strjoin(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro", NULL);
+                else
+                        o = strdup(arg_root_options);
+        }
+        if (!o)
+                return log_oom();
 
-        return (r < 0) ? r : 0;
+        noauto = mount_test_option(arg_root_options, "noauto");
+        nofail = mount_test_option(arg_root_options, "nofail");
+
+        log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
+        return add_mount(what,
+                         "/sysroot",
+                         arg_root_fstype,
+                         o,
+                         1,
+                         noauto, nofail,
+                         false,
+                         SPECIAL_INITRD_ROOT_FS_TARGET,
+                         "/proc/cmdline");
 }
 
 static int parse_proc_cmdline_item(const char *key, const char *value) {
         int r;
 
+        /* root= and roofstype= may occur more than once, the last
+         * instance should take precedence.  In the case of multiple
+         * rootflags= the arguments should be concatenated */
+
         if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
 
                 r = parse_boolean(value);
@@ -476,7 +451,37 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
                 else
                         arg_fstab_enabled = r;
 
-        } else if (startswith(key, "fstab.") || startswith(key, "rd.fstab."))
+        } else if (streq(key, "root") && value) {
+
+                free(arg_root_what);
+                arg_root_what = strdup(value);
+                if (!arg_root_what)
+                        return log_oom();
+
+        } else if (streq(key, "rootfstype") && value) {
+
+                free(arg_root_fstype);
+                arg_root_fstype = strdup(value);
+                if (!arg_root_fstype)
+                        return log_oom();
+
+        } else if (streq(key, "rootflags") && value) {
+                char *o;
+
+                o = arg_root_options ?
+                        strjoin(arg_root_options, ",", value, NULL) :
+                        strdup(value);
+                if (!o)
+                        return log_oom();
+
+                free(arg_root_options);
+                arg_root_options = o;
+
+        } else if (streq(key, "rw") && !value)
+                arg_root_rw = true;
+        else if (streq(key, "ro") && !value)
+                arg_root_rw = false;
+        else if (startswith(key, "fstab.") || startswith(key, "rd.fstab."))
                 log_warning("Unknown kernel switch %s. Ignoring.", key);
 
         return 0;
@@ -504,7 +509,7 @@ int main(int argc, char *argv[]) {
 
         /* Always honour root= in the kernel command line if we are in an initrd */
         if (in_initrd())
-                r = parse_new_root_from_proc_cmdline();
+                r = add_root_mount();
 
         /* Honour /etc/fstab only when that's enabled */
         if (arg_fstab_enabled) {
index 49647c1ab6b55857ff687ae350fb1dd27ad14cbc..61103031db23b31df7a5d7c79dc98d11608a3d4a 100644 (file)
@@ -32,20 +32,23 @@ int generator_write_fsck_deps(
                 const char *dest,
                 const char *what,
                 const char *where,
-                const char *type) {
+                const char *fstype) {
 
         assert(f);
+        assert(dest);
+        assert(what);
+        assert(where);
 
         if (!is_device_path(what)) {
                 log_warning("Checking was requested for \"%s\", but it is not a device.", what);
                 return 0;
         }
 
-        if (type && !streq(type, "auto")) {
+        if (!isempty(fstype) && !streq(fstype, "auto")) {
                 const char *checker;
                 int r;
 
-                checker = strappenda("/sbin/fsck.", type);
+                checker = strappenda("/sbin/fsck.", fstype);
                 r = access(checker, X_OK);
                 if (r < 0) {
                         log_warning("Checking was requested for %s, but %s cannot be used: %m", what, checker);
index cffa1abb3061c507e2c239626f238379bd4e4160..d28caae6c2ebc0fd034acebf2d06fa77bd1c96cb 100644 (file)
@@ -3519,25 +3519,21 @@ int signal_from_string_try_harder(const char *s) {
 
 static char *tag_to_udev_node(const char *tagvalue, const char *by) {
         _cleanup_free_ char *t = NULL, *u = NULL;
-        char *dn;
         size_t enc_len;
 
         u = unquote(tagvalue, "\"\'");
-        if (u == NULL)
+        if (!u)
                 return NULL;
 
         enc_len = strlen(u) * 4 + 1;
         t = new(char, enc_len);
-        if (t == NULL)
+        if (!t)
                 return NULL;
 
         if (encode_devnode_name(u, t, enc_len) < 0)
                 return NULL;
 
-        if (asprintf(&dn, "/dev/disk/by-%s/%s", by, t) < 0)
-                return NULL;
-
-        return dn;
+        return strjoin("/dev/disk/by-", by, "/", t, NULL);
 }
 
 char *fstab_node_to_udev_node(const char *p) {
@@ -6339,3 +6335,20 @@ uint64_t physical_memory(void) {
 
         return (uint64_t) mem * (uint64_t) page_size();
 }
+
+char* mount_test_option(const char *haystack, const char *needle) {
+
+        struct mntent me = {
+                .mnt_opts = (char*) haystack
+        };
+
+        assert(needle);
+
+        /* Like glibc's hasmntopt(), but works on a string, not a
+         * struct mntent */
+
+        if (!haystack)
+                return NULL;
+
+        return hasmntopt(&me, needle);
+}
index cd166f663710a72f73b6f6d8fe2c1535fca35353..c2bc9771b9f424c4bc5f6d5eb3725cfd184975aa 100644 (file)
@@ -893,3 +893,5 @@ unsigned long personality_from_string(const char *p);
 const char *personality_to_string(unsigned long);
 
 uint64_t physical_memory(void);
+
+char* mount_test_option(const char *haystack, const char *needle);