Beispiel #1
0
int main(int argc, char *argv[]) {
    int ret = EXIT_FAILURE;
    _cleanup_endmntent_ FILE *f = NULL;
    struct mntent* me;
    Hashmap *pids = NULL;

    if (argc > 1) {
        log_error("This program takes no argument.");
        return EXIT_FAILURE;
    }

    log_set_target(LOG_TARGET_AUTO);
    log_parse_environment();
    log_open();

    umask(0022);

    f = setmntent("/etc/fstab", "r");
    if (!f) {
        if (errno == ENOENT)
            return EXIT_SUCCESS;

        log_error("Failed to open /etc/fstab: %m");
        return EXIT_FAILURE;
    }

    pids = hashmap_new(trivial_hash_func, trivial_compare_func);
    if (!pids) {
        log_error("Failed to allocate set");
        goto finish;
    }

    ret = EXIT_SUCCESS;

    while ((me = getmntent(f))) {
        pid_t pid;
        int k;
        char *s;

        /* Remount the root fs, /usr and all API VFS */
        if (!mount_point_is_api(me->mnt_dir) &&
                !path_equal(me->mnt_dir, "/") &&
                !path_equal(me->mnt_dir, "/usr"))
            continue;

        log_debug("Remounting %s", me->mnt_dir);

        pid = fork();
        if (pid < 0) {
            log_error("Failed to fork: %m");
            ret = EXIT_FAILURE;
            continue;
        }

        if (pid == 0) {
            const char *arguments[5];
            /* Child */

            arguments[0] = "/bin/mount";
            arguments[1] = me->mnt_dir;
            arguments[2] = "-o";
            arguments[3] = "remount";
            arguments[4] = NULL;

            execv("/bin/mount", (char **) arguments);

            log_error("Failed to execute /bin/mount: %m");
            _exit(EXIT_FAILURE);
        }

        /* Parent */

        s = strdup(me->mnt_dir);
        if (!s) {
            log_oom();
            ret = EXIT_FAILURE;
            continue;
        }


        k = hashmap_put(pids, UINT_TO_PTR(pid), s);
        if (k < 0) {
            log_error("Failed to add PID to set: %s", strerror(-k));
            ret = EXIT_FAILURE;
            continue;
        }
    }

    while (!hashmap_isempty(pids)) {
        siginfo_t si = {};
        char *s;

        if (waitid(P_ALL, 0, &si, WEXITED) < 0) {

            if (errno == EINTR)
                continue;

            log_error("waitid() failed: %m");
            ret = EXIT_FAILURE;
            break;
        }

        s = hashmap_remove(pids, UINT_TO_PTR(si.si_pid));
        if (s) {
            if (!is_clean_exit(si.si_code, si.si_status, NULL)) {
                if (si.si_code == CLD_EXITED)
                    log_error("/bin/mount for %s exited with exit status %i.", s, si.si_status);
                else
                    log_error("/bin/mount for %s terminated by signal %s.", s, signal_to_string(si.si_status));

                ret = EXIT_FAILURE;
            }

            free(s);
        }
    }

finish:

    if (pids)
        hashmap_free_free(pids);

    return ret;
}
static int add_mount(
                const char *what,
                const char *where,
                const char *type,
                const char *opts,
                int passno,
                bool noauto,
                bool nofail,
                bool automount,
                bool isbind,
                const char *pre,
                const char *pre2,
                const char *online,
                const char *post,
                const char *source) {
        _cleanup_free_ char
                *name = NULL, *unit = NULL, *lnk = NULL, *device = NULL,
                *automount_name = NULL, *automount_unit = NULL;
        _cleanup_fclose_ FILE *f = NULL;
        int r;

        assert(what);
        assert(where);
        assert(type);
        assert(opts);
        assert(source);

        if (streq(type, "autofs"))
                return 0;

        if (!is_path(where)) {
                log_warning("Mount point %s is not a valid path, ignoring.", where);
                return 0;
        }

        if (mount_point_is_api(where) ||
            mount_point_ignore(where))
                return 0;

        name = unit_name_from_path(where, ".mount");
        if (!name)
                return log_oom();

        unit = strjoin(arg_dest, "/", name, NULL);
        if (!unit)
                return log_oom();

        f = fopen(unit, "wxe");
        if (!f) {
                if (errno == EEXIST)
                        log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
                else
                        log_error("Failed to create unit file %s: %m", unit);
                return -errno;
        }

        fprintf(f,
              "# Automatically generated by systemd-fstab-generator\n\n"
              "[Unit]\n"
              "SourcePath=%s\n"
              "DefaultDependencies=no\n",
              source);

        if (!path_equal(where, "/")) {
                if (pre)
                        fprintf(f,
                                "After=%s\n",
                                pre);

                if (pre2)
                        fprintf(f,
                                "After=%s\n",
                                pre2);

                if (online)
                        fprintf(f,
                                "After=%s\n"
                                "Wants=%s\n",
                                online,
                                online);

                fprintf(f,
                        "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
                        "Before=" SPECIAL_UMOUNT_TARGET "\n");
        }

        if (post && !noauto && !nofail && !automount)
                fprintf(f,
                        "Before=%s\n",
                        post);

        fprintf(f,
                "\n"
                "[Mount]\n"
                "What=%s\n"
                "Where=%s\n"
                "Type=%s\n"
                "FsckPassNo=%i\n",
                what,
                where,
                type,
                passno);

        if (!isempty(opts) &&
            !streq(opts, "defaults"))
                fprintf(f,
                        "Options=%s\n",
                        opts);

        fflush(f);
        if (ferror(f)) {
                log_error("Failed to write unit file %s: %m", unit);
                return -errno;
        }

        if (!noauto) {
                /* don't start network mounts automatically, we do that via ifupdown hooks for now */
                if (post && !streq(post, SPECIAL_REMOTE_FS_TARGET)) {
                        lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
                        if (!lnk)
                                return log_oom();

                        mkdir_parents_label(lnk, 0755);
                        if (symlink(unit, lnk) < 0) {
                                log_error("Failed to create symlink %s: %m", lnk);
                                return -errno;
                        }
                }

                if (!isbind &&
                    !path_equal(where, "/")) {

                        r = device_name(what, &device);
                        if (r < 0)
                                return r;

                        if (r > 0) {
                                free(lnk);
                                lnk = strjoin(arg_dest, "/", device, ".wants/", name, NULL);
                                if (!lnk)
                                        return log_oom();

                                mkdir_parents_label(lnk, 0755);
                                if (symlink(unit, lnk) < 0) {
                                        log_error("Failed to create symlink %s: %m", lnk);
                                        return -errno;
                                }
                        }
                }
        }

        if (automount && !path_equal(where, "/")) {
                automount_name = unit_name_from_path(where, ".automount");
                if (!name)
                        return log_oom();

                automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
                if (!automount_unit)
                        return log_oom();

                fclose(f);
                f = fopen(automount_unit, "wxe");
                if (!f) {
                        log_error("Failed to create unit file %s: %m", automount_unit);
                        return -errno;
                }

                fprintf(f,
                        "# Automatically generated by systemd-fstab-generator\n\n"
                        "[Unit]\n"
                        "SourcePath=%s\n"
                        "DefaultDependencies=no\n"
                        "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
                        "Before=" SPECIAL_UMOUNT_TARGET "\n",
                        source);

                if (post)
                        fprintf(f,
                                "Before= %s\n",
                                post);

                fprintf(f,
                        "[Automount]\n"
                        "Where=%s\n",
                        where);

                fflush(f);
                if (ferror(f)) {
                        log_error("Failed to write unit file %s: %m", automount_unit);
                        return -errno;
                }

                free(lnk);
                lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
                if (!lnk)
                        return log_oom();

                mkdir_parents_label(lnk, 0755);
                if (symlink(automount_unit, lnk) < 0) {
                        log_error("Failed to create symlink %s: %m", lnk);
                        return -errno;
                }
        }

        return 0;
}
static int add_mount(
                const char *what,
                const char *where,
                const char *fstype,
                const char *opts,
                int passno,
                bool noauto,
                bool nofail,
                bool automount,
                const char *post,
                const char *source) {

        _cleanup_free_ char
                *name = NULL, *unit = NULL, *lnk = NULL,
                *automount_name = NULL, *automount_unit = NULL,
                *filtered = NULL;
        _cleanup_fclose_ FILE *f = NULL;
        int r;

        assert(what);
        assert(where);
        assert(opts);
        assert(source);

        if (streq_ptr(fstype, "autofs"))
                return 0;

        if (!is_path(where)) {
                log_warning("Mount point %s is not a valid path, ignoring.", where);
                return 0;
        }

        if (mount_point_is_api(where) ||
            mount_point_ignore(where))
                return 0;

        if (path_equal(where, "/")) {
                /* The root disk is not an option */
                automount = false;
                noauto = false;
                nofail = false;
        }

        name = unit_name_from_path(where, ".mount");
        if (!name)
                return log_oom();

        unit = strjoin(arg_dest, "/", name, NULL);
        if (!unit)
                return log_oom();

        f = fopen(unit, "wxe");
        if (!f) {
                if (errno == EEXIST)
                        log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
                else
                        log_error_errno(errno, "Failed to create unit file %s: %m", unit);
                return -errno;
        }

        fprintf(f,
                "# Automatically generated by systemd-fstab-generator\n\n"
                "[Unit]\n"
                "SourcePath=%s\n"
                "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
                source);

        if (post && !noauto && !nofail && !automount)
                fprintf(f, "Before=%s\n", post);

        if (passno != 0) {
                r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
                if (r < 0)
                        return r;
        }

        fprintf(f,
                "\n"
                "[Mount]\n"
                "What=%s\n"
                "Where=%s\n",
                what,
                where);

        if (!isempty(fstype) && !streq(fstype, "auto"))
                fprintf(f, "Type=%s\n", fstype);

        r = generator_write_timeouts(arg_dest, what, where, opts, &filtered);
        if (r < 0)
                return r;

        if (!isempty(filtered) && !streq(filtered, "defaults"))
                fprintf(f, "Options=%s\n", filtered);

        fflush(f);
        if (ferror(f))
                return log_error_errno(errno, "Failed to write unit file %s: %m", unit);

        if (!noauto && post) {
                lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
                if (!lnk)
                        return log_oom();

                mkdir_parents_label(lnk, 0755);
                if (symlink(unit, lnk) < 0)
                        return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
        }

        if (automount) {
                automount_name = unit_name_from_path(where, ".automount");
                if (!automount_name)
                        return log_oom();

                automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
                if (!automount_unit)
                        return log_oom();

                fclose(f);
                f = fopen(automount_unit, "wxe");
                if (!f)
                        return log_error_errno(errno, "Failed to create unit file %s: %m", automount_unit);

                fprintf(f,
                        "# Automatically generated by systemd-fstab-generator\n\n"
                        "[Unit]\n"
                        "SourcePath=%s\n"
                        "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
                        source);

                if (post)
                        fprintf(f,
                                "Before=%s\n",
                                post);

                fprintf(f,
                        "[Automount]\n"
                        "Where=%s\n",
                        where);

                fflush(f);
                if (ferror(f))
                        return log_error_errno(errno, "Failed to write unit file %s: %m", automount_unit);

                free(lnk);
                lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
                if (!lnk)
                        return log_oom();

                mkdir_parents_label(lnk, 0755);
                if (symlink(automount_unit, lnk) < 0)
                        return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
        }

        return 0;
}
Beispiel #4
0
static int add_mount(
                const char *what,
                const char *where,
                const char *type,
                const char *opts,
                int passno,
                bool noauto,
                bool nofail,
                bool automount,
                const char *post,
                const char *source) {
        _cleanup_free_ char
                *name = NULL, *unit = NULL, *lnk = NULL,
                *automount_name = NULL, *automount_unit = NULL;
        _cleanup_fclose_ FILE *f = NULL;

        assert(what);
        assert(where);
        assert(type);
        assert(opts);
        assert(source);

        if (streq(type, "autofs"))
                return 0;

        if (!is_path(where)) {
                log_warning("Mount point %s is not a valid path, ignoring.", where);
                return 0;
        }

        if (mount_point_is_api(where) ||
            mount_point_ignore(where))
                return 0;

        name = unit_name_from_path(where, ".mount");
        if (!name)
                return log_oom();

        unit = strjoin(arg_dest, "/", name, NULL);
        if (!unit)
                return log_oom();

        f = fopen(unit, "wxe");
        if (!f) {
                if (errno == EEXIST)
                        log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
                else
                        log_error("Failed to create unit file %s: %m", unit);
                return -errno;
        }

        fprintf(f,
              "# Automatically generated by systemd-fstab-generator\n\n"
              "[Unit]\n"
              "SourcePath=%s\n",
              source);

        if (post && !noauto && !nofail && !automount)
                fprintf(f,
                        "Before=%s\n",
                        post);

        if (passno > 0) {
                if (streq(where, "/")) {
                        lnk = strjoin(arg_dest, "/", SPECIAL_LOCAL_FS_TARGET, ".wants/", "systemd-fsck-root.service", NULL);
                        if (!lnk)
                                return log_oom();

                        mkdir_parents_label(lnk, 0755);
                        if (symlink("systemd-fsck-root.service", lnk) < 0) {
                                log_error("Failed to create symlink %s: %m", lnk);
                                return -errno;
                        }
                } else {
                        _cleanup_free_ char *fsck = NULL;

                        fsck = unit_name_from_path_instance("systemd-fsck", what, ".service");
                        if (!fsck)
                                return log_oom();

                        fprintf(f,
                                "Requires=%s\n"
                                "After=%s\n",
                                fsck,
                                fsck);
                }
        }


        fprintf(f,
                "\n"
                "[Mount]\n"
                "What=%s\n"
                "Where=%s\n"
                "Type=%s\n",
                what,
                where,
                type);

        if (!isempty(opts) &&
            !streq(opts, "defaults"))
                fprintf(f,
                        "Options=%s\n",
                        opts);

        fflush(f);
        if (ferror(f)) {
                log_error("Failed to write unit file %s: %m", unit);
                return -errno;
        }

        if (!noauto) {
                if (post) {
                        free(lnk);
                        lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
                        if (!lnk)
                                return log_oom();

                        mkdir_parents_label(lnk, 0755);
                        if (symlink(unit, lnk) < 0) {
                                log_error("Failed to create symlink %s: %m", lnk);
                                return -errno;
                        }
                }
        }

        if (automount && !path_equal(where, "/")) {
                automount_name = unit_name_from_path(where, ".automount");
                if (!automount_name)
                        return log_oom();

                automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
                if (!automount_unit)
                        return log_oom();

                fclose(f);
                f = fopen(automount_unit, "wxe");
                if (!f) {
                        log_error("Failed to create unit file %s: %m", automount_unit);
                        return -errno;
                }

                fprintf(f,
                        "# Automatically generated by systemd-fstab-generator\n\n"
                        "[Unit]\n"
                        "SourcePath=%s\n",
                        source);

                if (post)
                        fprintf(f,
                                "Before= %s\n",
                                post);

                fprintf(f,
                        "[Automount]\n"
                        "Where=%s\n",
                        where);

                fflush(f);
                if (ferror(f)) {
                        log_error("Failed to write unit file %s: %m", automount_unit);
                        return -errno;
                }

                free(lnk);
                lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
                if (!lnk)
                        return log_oom();

                mkdir_parents_label(lnk, 0755);
                if (symlink(automount_unit, lnk) < 0) {
                        log_error("Failed to create symlink %s: %m", lnk);
                        return -errno;
                }
        }

        return 0;
}
Beispiel #5
0
static int add_mount(const char *what, const char *where, struct mntent *me) {
        char *name = NULL, *unit = NULL, *lnk = NULL, *device = NULL, *automount_name = NULL, *automount_unit = NULL;
        FILE *f = NULL;
        bool noauto, nofail, automount, isbind, isnetwork;
        int r;
        const char *post, *pre;

        assert(what);
        assert(where);
        assert(me);

        if (streq(me->mnt_type, "autofs"))
                return 0;

        if (!is_path(where)) {
                log_warning("Mount point %s is not a valid path, ignoring.", where);
                return 0;
        }

        if (mount_point_is_api(where) ||
            mount_point_ignore(where))
                return 0;

        isnetwork = mount_is_network(me);
        isbind = mount_is_bind(me);

        noauto = !!hasmntopt(me, "noauto");
        nofail = !!hasmntopt(me, "nofail");
        automount =
                hasmntopt(me, "comment=systemd.automount") ||
                hasmntopt(me, "x-systemd.automount");

        if (isnetwork) {
                post = SPECIAL_REMOTE_FS_TARGET;
                pre = SPECIAL_REMOTE_FS_PRE_TARGET;
        } else {
                post = SPECIAL_LOCAL_FS_TARGET;
                pre = SPECIAL_LOCAL_FS_PRE_TARGET;
        }

        name = unit_name_from_path(where, ".mount");
        if (!name) {
                r = log_oom();
                goto finish;
        }

        unit = strjoin(arg_dest, "/", name, NULL);
        if (!unit) {
                r = log_oom();
                goto finish;
        }

        f = fopen(unit, "wxe");
        if (!f) {
                r = -errno;
                log_error("Failed to create unit file: %m");
                goto finish;
        }

        fputs("# Automatically generated by systemd-fstab-generator\n\n"
              "[Unit]\n"
              "SourcePath=/etc/fstab\n"
              "DefaultDependencies=no\n", f);

        if (!path_equal(where, "/"))
                fprintf(f,
                        "After=%s\n"
                        "Wants=%s\n"
                        "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
                        "Before=" SPECIAL_UMOUNT_TARGET "\n",
                        pre,
                        pre);


        if (!noauto && !nofail && !automount)
                fprintf(f,
                        "Before=%s\n",
                        post);

        fprintf(f,
                "\n"
                "[Mount]\n"
                "What=%s\n"
                "Where=%s\n"
                "Type=%s\n"
                "FsckPassNo=%i\n",
                what,
                where,
                me->mnt_type,
                me->mnt_passno);

        if (!isempty(me->mnt_opts) &&
            !streq(me->mnt_opts, "defaults"))
                fprintf(f,
                        "Options=%s\n",
                        me->mnt_opts);

        fflush(f);
        if (ferror(f)) {
                log_error("Failed to write unit file: %m");
                r = -errno;
                goto finish;
        }

        if (!noauto) {
                lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
                if (!lnk) {
                        r = log_oom();
                        goto finish;
                }

                mkdir_parents_label(lnk, 0755);
                if (symlink(unit, lnk) < 0) {
                        log_error("Failed to create symlink: %m");
                        r = -errno;
                        goto finish;
                }

                if (!isbind &&
                    !path_equal(where, "/")) {

                        r = device_name(what, &device);
                        if (r < 0)
                                goto finish;

                        if (r > 0) {
                                free(lnk);
                                lnk = strjoin(arg_dest, "/", device, ".wants/", name, NULL);
                                if (!lnk) {
                                        r = log_oom();
                                        goto finish;
                                }

                                mkdir_parents_label(lnk, 0755);
                                if (symlink(unit, lnk) < 0) {
                                        log_error("Failed to create symlink: %m");
                                        r = -errno;
                                        goto finish;
                                }
                        }
                }
        }

        if (automount && !path_equal(where, "/")) {
                automount_name = unit_name_from_path(where, ".automount");
                if (!name) {
                        r = log_oom();
                        goto finish;
                }

                automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
                if (!automount_unit) {
                        r = log_oom();
                        goto finish;
                }

                fclose(f);
                f = fopen(automount_unit, "wxe");
                if (!f) {
                        r = -errno;
                        log_error("Failed to create unit file: %m");
                        goto finish;
                }

                fprintf(f,
                        "# Automatically generated by systemd-fstab-generator\n\n"
                        "[Unit]\n"
                        "SourcePath=/etc/fstab\n"
                        "DefaultDependencies=no\n"
                        "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
                        "Before=" SPECIAL_UMOUNT_TARGET " %s\n"
                        "\n"
                        "[Automount]\n"
                        "Where=%s\n",
                        post,
                        where);

                fflush(f);
                if (ferror(f)) {
                        log_error("Failed to write unit file: %m");
                        r = -errno;
                        goto finish;
                }

                free(lnk);
                lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
                if (!lnk) {
                        r = log_oom();
                        goto finish;
                }

                mkdir_parents_label(lnk, 0755);
                if (symlink(automount_unit, lnk) < 0) {
                        log_error("Failed to create symlink: %m");
                        r = -errno;
                        goto finish;
                }
        }

        r = 0;
finish:
        if (f)
                fclose(f);

        free(unit);
        free(lnk);
        free(name);
        free(device);
        free(automount_name);
        free(automount_unit);

        return r;
}
Beispiel #6
0
static int mount_points_list_get(MountPoint **head) {
        _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
        unsigned int i;
        int r;

        assert(head);

        proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
        if (!proc_self_mountinfo)
                return -errno;

        for (i = 1;; i++) {
                _cleanup_free_ char *path = NULL;
                char *p = NULL;
                MountPoint *m;
                int k;

                k = fscanf(proc_self_mountinfo,
                           "%*s "       /* (1) mount id */
                           "%*s "       /* (2) parent id */
                           "%*s "       /* (3) major:minor */
                           "%*s "       /* (4) root */
                           "%ms "       /* (5) mount point */
                           "%*s"        /* (6) mount options */
                           "%*[^-]"     /* (7) optional fields */
                           "- "         /* (8) separator */
                           "%*s "       /* (9) file system type */
                           "%*s"        /* (10) mount source */
                           "%*s"        /* (11) mount options 2 */
                           "%*[^\n]",   /* some rubbish at the end */
                           &path);
                if (k != 1) {
                        if (k == EOF)
                                break;

                        log_warning("Failed to parse /proc/self/mountinfo:%u.", i);
                        continue;
                }

                r = cunescape(path, UNESCAPE_RELAX, &p);
                if (r < 0)
                        return r;

                /* Ignore mount points we can't unmount because they
                 * are API or because we are keeping them open (like
                 * /dev/console). Also, ignore all mounts below API
                 * file systems, since they are likely virtual too,
                 * and hence not worth spending time on. Also, in
                 * unprivileged containers we might lack the rights to
                 * unmount these things, hence don't bother. */
                if (mount_point_is_api(p) ||
                    mount_point_ignore(p) ||
                    path_startswith(p, "/dev") ||
                    path_startswith(p, "/sys") ||
                    path_startswith(p, "/proc")) {
                        free(p);
                        continue;
                }

                m = new0(MountPoint, 1);
                if (!m) {
                        free(p);
                        return -ENOMEM;
                }

                m->path = p;
                LIST_PREPEND(mount_point, *head, m);
        }

        return 0;
}
int main(int argc, char *argv[]) {
        _cleanup_hashmap_free_free_ Hashmap *pids = NULL;
        _cleanup_endmntent_ FILE *f = NULL;
        struct mntent* me;
        int r;

        if (argc > 1) {
                log_error("This program takes no argument.");
                return EXIT_FAILURE;
        }

        log_set_target(LOG_TARGET_AUTO);
        log_parse_environment();
        log_open();

        umask(0022);

        f = setmntent("/etc/fstab", "r");
        if (!f) {
                if (errno == ENOENT) {
                        r = 0;
                        goto finish;
                }

                r = log_error_errno(errno, "Failed to open /etc/fstab: %m");
                goto finish;
        }

        pids = hashmap_new(NULL);
        if (!pids) {
                r = log_oom();
                goto finish;
        }

        while ((me = getmntent(f))) {
                pid_t pid;
                int k;
                char *s;

                /* Remount the root fs, /usr and all API VFS */
                if (!mount_point_is_api(me->mnt_dir) &&
                    !path_equal(me->mnt_dir, "/") &&
                    !path_equal(me->mnt_dir, "/usr"))
                        continue;

                log_debug("Remounting %s", me->mnt_dir);

                pid = fork();
                if (pid < 0) {
                        r = log_error_errno(errno, "Failed to fork: %m");
                        goto finish;
                }

                if (pid == 0) {
                        /* Child */

                        (void) reset_all_signal_handlers();
                        (void) reset_signal_mask();
                        (void) prctl(PR_SET_PDEATHSIG, SIGTERM);

                        execv(MOUNT_PATH, STRV_MAKE(MOUNT_PATH, me->mnt_dir, "-o", "remount"));

                        log_error_errno(errno, "Failed to execute " MOUNT_PATH ": %m");
                        _exit(EXIT_FAILURE);
                }

                /* Parent */

                s = strdup(me->mnt_dir);
                if (!s) {
                        r = log_oom();
                        goto finish;
                }

                k = hashmap_put(pids, PID_TO_PTR(pid), s);
                if (k < 0) {
                        free(s);
                        r = log_oom();
                        goto finish;
                }
        }

        r = 0;
        while (!hashmap_isempty(pids)) {
                siginfo_t si = {};
                char *s;

                if (waitid(P_ALL, 0, &si, WEXITED) < 0) {

                        if (errno == EINTR)
                                continue;

                        r = log_error_errno(errno, "waitid() failed: %m");
                        goto finish;
                }

                s = hashmap_remove(pids, PID_TO_PTR(si.si_pid));
                if (s) {
                        if (!is_clean_exit(si.si_code, si.si_status, EXIT_CLEAN_COMMAND, NULL)) {
                                if (si.si_code == CLD_EXITED)
                                        log_error(MOUNT_PATH " for %s exited with exit status %i.", s, si.si_status);
                                else
                                        log_error(MOUNT_PATH " for %s terminated by signal %s.", s, signal_to_string(si.si_status));

                                r = -ENOEXEC;
                        }

                        free(s);
                }
        }

finish:
        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}