Exemplo n.º 1
0
static int add_root_mount(void) {
        _cleanup_free_ char *what = NULL;
        const char *opts;

        if (isempty(arg_root_what)) {
                log_debug("Could not find a root= entry on the kernel command line.");
                return 0;
        }

        what = fstab_node_to_udev_node(arg_root_what);
        if (!what)
                return log_oom();

        if (!arg_root_options)
                opts = arg_root_rw > 0 ? "rw" : "ro";
        else if (arg_root_rw >= 0 ||
                 !fstab_test_option(arg_root_options, "ro\0" "rw\0"))
                opts = strjoina(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro");
        else
                opts = arg_root_options;

        log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
        return add_mount(what,
                         "/sysroot",
                         arg_root_fstype,
                         opts,
                         is_device_path(what) ? 1 : 0,
                         false,
                         false,
                         false,
                         SPECIAL_INITRD_ROOT_FS_TARGET,
                         "/proc/cmdline");
}
Exemplo n.º 2
0
static int device_name(const char *path, char **unit) {
        char *p;

        assert(path);

        if (!is_device_path(path))
                return 0;

        p = unit_name_from_path(path, ".device");
        if (!p)
                return log_oom();

        *unit = p;
        return 1;
}
Exemplo n.º 3
0
int generator_write_timeouts(
                const char *dir,
                const char *what,
                const char *where,
                const char *opts,
                char **filtered) {

        /* Allow configuration how long we wait for a device that
         * backs a mount point to show up. This is useful to support
         * endless device timeouts for devices that show up only after
         * user input, like crypto devices. */

        _cleanup_free_ char *node = NULL, *unit = NULL, *timeout = NULL;
        usec_t u;
        int r;

        r = fstab_filter_options(opts, "comment=systemd.device-timeout\0"
                                       "x-systemd.device-timeout\0",
                                 NULL, &timeout, filtered);
        if (r <= 0)
                return r;

        r = parse_sec_fix_0(timeout, &u);
        if (r < 0) {
                log_warning("Failed to parse timeout for %s, ignoring: %s", where, timeout);
                return 0;
        }

        node = fstab_node_to_udev_node(what);
        if (!node)
                return log_oom();
        if (!is_device_path(node)) {
                log_warning("x-systemd.device-timeout ignored for %s", what);
                return 0;
        }

        r = unit_name_from_path(node, ".device", &unit);
        if (r < 0)
                return log_error_errno(r, "Failed to make unit name from path: %m");

        return write_drop_in_format(dir, unit, 50, "device-timeout",
                                    "# Automatically generated by %s\n\n"
                                    "[Unit]\n"
                                    "JobRunningTimeoutSec=%s",
                                    program_invocation_short_name,
                                    timeout);
}
Exemplo n.º 4
0
int generator_write_device_deps(
                const char *dir,
                const char *what,
                const char *where,
                const char *opts) {

        /* fstab records that specify _netdev option should apply the network
         * ordering on the actual device depending on network connection. If we
         * are not mounting real device (NFS, CIFS), we rely on _netdev effect
         * on the mount unit itself. */

        _cleanup_free_ char *node = NULL, *unit = NULL;
        int r;

        if (!fstab_test_option(opts, "_netdev\0"))
                return 0;

        node = fstab_node_to_udev_node(what);
        if (!node)
                return log_oom();

        /* Nothing to apply dependencies to. */
        if (!is_device_path(node))
                return 0;

        r = unit_name_from_path(node, ".device", &unit);
        if (r < 0)
                return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
                                       node);

        /* See mount_add_default_dependencies for explanation why we create such
         * dependencies. */
        return write_drop_in_format(dir, unit, 50, "netdev-dependencies",
                                    "# Automatically generated by %s\n\n"
                                    "[Unit]\n"
                                    "After=" SPECIAL_NETWORK_ONLINE_TARGET " " SPECIAL_NETWORK_TARGET "\n"
                                    "Wants=" SPECIAL_NETWORK_ONLINE_TARGET "\n",
                                    program_invocation_short_name);
}
Exemplo n.º 5
0
int generator_hook_up_mkfs(
                const char *dir,
                const char *what,
                const char *where,
                const char *type) {

        _cleanup_free_ char *node = NULL, *unit = NULL, *escaped = NULL, *where_unit = NULL;
        _cleanup_fclose_ FILE *f = NULL;
        const char *unit_file;
        int r;

        node = fstab_node_to_udev_node(what);
        if (!node)
                return log_oom();

        /* Nothing to work on. */
        if (!is_device_path(node)) {
                log_error("Cannot format something that is not a device node: %s", node);
                return -EINVAL;
        }

        if (!type || streq(type, "auto")) {
                log_error("Cannot format partition %s, filesystem type is not specified", node);
                return -EINVAL;
        }

        r = unit_name_from_path_instance("systemd-mkfs", node, ".service", &unit);
        if (r < 0)
                return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m",
                                       node);

        unit_file = strjoina(dir, "/", unit);
        log_debug("Creating %s", unit_file);

        escaped = cescape(node);
        if (!escaped)
                return log_oom();

        r = unit_name_from_path(where, ".mount", &where_unit);
        if (r < 0)
                return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
                                       where);

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

        fprintf(f,
                "# Automatically generated by %s\n\n"
                "[Unit]\n"
                "Description=Make File System on %%f\n"
                "Documentation=man:[email protected](8)\n"
                "DefaultDependencies=no\n"
                "BindsTo=%%i.device\n"
                "After=%%i.device\n"
                /* fsck might or might not be used, so let's be safe and order
                 * ourselves before both [email protected] and the mount unit. */
                "Before=systemd-fsck@%%i.service\n"
                "Before=%s\n"
                "Before=shutdown.target\n"
                "\n"
                "[Service]\n"
                "Type=oneshot\n"
                "RemainAfterExit=yes\n"
                "ExecStart="SYSTEMD_MAKEFS_PATH " %s %s\n"
                "TimeoutSec=0\n",
                program_invocation_short_name,
                where_unit,
                type,
                escaped);
        // XXX: what about local-fs-pre.target?

        r = fflush_and_check(f);
        if (r < 0)
                return log_error_errno(r, "Failed to write unit file %s: %m", unit_file);

        return generator_add_symlink(dir, where_unit, "requires", unit);
}
Exemplo n.º 6
0
int generator_hook_up_mkswap(
                const char *dir,
                const char *what) {

        _cleanup_free_ char *node = NULL, *unit = NULL, *escaped = NULL, *where_unit = NULL;
        _cleanup_fclose_ FILE *f = NULL;
        const char *unit_file;
        int r;

        node = fstab_node_to_udev_node(what);
        if (!node)
                return log_oom();

        /* Nothing to work on. */
        if (!is_device_path(node)) {
                log_error("Cannot format something that is not a device node: %s", node);
                return -EINVAL;
        }

        r = unit_name_from_path_instance("systemd-mkswap", node, ".service", &unit);
        if (r < 0)
                return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m",
                                       node);

        unit_file = strjoina(dir, "/", unit);
        log_debug("Creating %s", unit_file);

        escaped = cescape(node);
        if (!escaped)
                return log_oom();

        r = unit_name_from_path(what, ".swap", &where_unit);
        if (r < 0)
                return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
                                       what);

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

        fprintf(f,
                "# Automatically generated by %s\n\n"
                "[Unit]\n"
                "Description=Make Swap on %%f\n"
                "Documentation=man:[email protected](8)\n"
                "DefaultDependencies=no\n"
                "BindsTo=%%i.device\n"
                "After=%%i.device\n"
                "Before=%s\n"
                "Before=shutdown.target\n"
                "\n"
                "[Service]\n"
                "Type=oneshot\n"
                "RemainAfterExit=yes\n"
                "ExecStart="SYSTEMD_MAKEFS_PATH " swap %s\n"
                "TimeoutSec=0\n",
                program_invocation_short_name,
                where_unit,
                escaped);

        r = fflush_and_check(f);
        if (r < 0)
                return log_error_errno(r, "Failed to write unit file %s: %m", unit_file);

        return generator_add_symlink(dir, where_unit, "requires", unit);
}
Exemplo n.º 7
0
int generator_write_fsck_deps(
                FILE *f,
                const char *dir,
                const char *what,
                const char *where,
                const char *fstype) {

        int r;

        assert(f);
        assert(dir);
        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 (!isempty(fstype) && !streq(fstype, "auto")) {
                r = fsck_exists(fstype);
                if (r < 0)
                        log_warning_errno(r, "Checking was requested for %s, but couldn't detect if fsck.%s may be used, proceeding: %m", what, fstype);
                else if (r == 0) {
                        /* treat missing check as essentially OK */
                        log_debug("Checking was requested for %s, but fsck.%s does not exist.", what, fstype);
                        return 0;
                }
        }

        if (path_equal(where, "/")) {
                const char *lnk;

                lnk = strjoina(dir, "/" SPECIAL_LOCAL_FS_TARGET ".wants/systemd-fsck-root.service");

                mkdir_parents(lnk, 0755);
                if (symlink(SYSTEM_DATA_UNIT_PATH "/systemd-fsck-root.service", lnk) < 0)
                        return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);

        } else {
                _cleanup_free_ char *_fsck = NULL;
                const char *fsck;

                if (in_initrd() && path_equal(where, "/sysroot")) {
                        r = write_fsck_sysroot_service(dir, what);
                        if (r < 0)
                                return r;

                        fsck = "systemd-fsck-root.service";
                } else {
                        r = unit_name_from_path_instance("systemd-fsck", what, ".service", &_fsck);
                        if (r < 0)
                                return log_error_errno(r, "Failed to create fsck service name: %m");

                        fsck = _fsck;
                }

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

        return 0;
}
Exemplo n.º 8
0
static int parse_fstab(bool initrd) {
        _cleanup_endmntent_ FILE *f = NULL;
        const char *fstab_path;
        struct mntent *me;
        int r = 0;

        fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
        f = setmntent(fstab_path, "re");
        if (!f) {
                if (errno == ENOENT)
                        return 0;

                log_error_errno(errno, "Failed to open %s: %m", fstab_path);
                return -errno;
        }

        while ((me = getmntent(f))) {
                _cleanup_free_ char *where = NULL, *what = NULL;
                bool noauto, nofail;
                int k;

                if (initrd && !mount_in_initrd(me))
                        continue;

                what = fstab_node_to_udev_node(me->mnt_fsname);
                if (!what)
                        return log_oom();

                if (is_device_path(what) && path_is_read_only_fs("sys") > 0) {
                        log_info("Running in a container, ignoring fstab device entry for %s.", what);
                        continue;
                }

                where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
                if (!where)
                        return log_oom();

                if (is_path(where))
                        path_kill_slashes(where);

                noauto = fstab_test_yes_no_option(me->mnt_opts, "noauto\0" "auto\0");
                nofail = fstab_test_yes_no_option(me->mnt_opts, "nofail\0" "fail\0");
                log_debug("Found entry what=%s where=%s type=%s nofail=%s noauto=%s",
                          what, where, me->mnt_type,
                          yes_no(noauto), yes_no(nofail));

                if (streq(me->mnt_type, "swap"))
                        k = add_swap(what, me, noauto, nofail);
                else {
                        bool automount;
                        const char *post;

                        automount = fstab_test_option(me->mnt_opts,
                                                      "comment=systemd.automount\0"
                                                      "x-systemd.automount\0");
                        if (initrd)
                                post = SPECIAL_INITRD_FS_TARGET;
                        else if (mount_in_initrd(me))
                                post = SPECIAL_INITRD_ROOT_FS_TARGET;
                        else if (mount_is_network(me))
                                post = SPECIAL_REMOTE_FS_TARGET;
                        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);
                }

                if (k < 0)
                        r = k;
        }

        return r;
}
Exemplo n.º 9
0
static int create_disk(
                const char *name,
                const char *device,
                const char *password,
                const char *options) {

        _cleanup_free_ char *p = NULL, *n = NULL, *d = NULL, *u = NULL, *to = NULL, *e = NULL,
                *filtered = NULL;
        _cleanup_fclose_ FILE *f = NULL;
        bool noauto, nofail, tmp, swap;
        char *from;
        int r;

        assert(name);
        assert(device);

        noauto = fstab_test_yes_no_option(options, "noauto\0" "auto\0");
        nofail = fstab_test_yes_no_option(options, "nofail\0" "fail\0");
        tmp = fstab_test_option(options, "tmp\0");
        swap = fstab_test_option(options, "swap\0");

        if (tmp && swap) {
                log_error("Device '%s' cannot be both 'tmp' and 'swap'. Ignoring.", name);
                return -EINVAL;
        }

        e = unit_name_escape(name);
        if (!e)
                return log_oom();

        r = unit_name_build("systemd-cryptsetup", e, ".service", &n);
        if (r < 0)
                return log_error_errno(r, "Failed to generate unit name: %m");

        p = strjoin(arg_dest, "/", n, NULL);
        if (!p)
                return log_oom();

        u = fstab_node_to_udev_node(device);
        if (!u)
                return log_oom();

        r = unit_name_from_path(u, ".device", &d);
        if (r < 0)
                return log_error_errno(r, "Failed to generate unit name: %m");

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

        fputs(
                "# Automatically generated by systemd-cryptsetup-generator\n\n"
                "[Unit]\n"
                "Description=Cryptography Setup for %I\n"
                "Documentation=man:crypttab(5) man:systemd-cryptsetup-generator(8) man:[email protected](8)\n"
                "SourcePath=/etc/crypttab\n"
                "DefaultDependencies=no\n"
                "Conflicts=umount.target\n"
                "BindsTo=dev-mapper-%i.device\n"
                "IgnoreOnIsolate=true\n"
                "After=cryptsetup-pre.target\n",
                f);

        if (!nofail)
                fprintf(f,
                        "Before=cryptsetup.target\n");

        if (password) {
                if (STR_IN_SET(password, "/dev/urandom", "/dev/random", "/dev/hw_random"))
                        fputs("After=systemd-random-seed.service\n", f);
                else if (!streq(password, "-") && !streq(password, "none")) {
                        _cleanup_free_ char *uu;

                        uu = fstab_node_to_udev_node(password);
                        if (!uu)
                                return log_oom();

                        if (!path_equal(uu, "/dev/null")) {

                                if (is_device_path(uu)) {
                                        _cleanup_free_ char *dd = NULL;

                                        r = unit_name_from_path(uu, ".device", &dd);
                                        if (r < 0)
                                                return log_error_errno(r, "Failed to generate unit name: %m");

                                        fprintf(f, "After=%1$s\nRequires=%1$s\n", dd);
                                } else
                                        fprintf(f, "RequiresMountsFor=%s\n", password);
                        }
                }
        }

        if (is_device_path(u))
                fprintf(f,
                        "BindsTo=%s\n"
                        "After=%s\n"
                        "Before=umount.target\n",
                        d, d);
        else
                fprintf(f,
                        "RequiresMountsFor=%s\n",
                        u);

        r = generator_write_timeouts(arg_dest, device, name, options, &filtered);
        if (r < 0)
                return r;

        fprintf(f,
                "\n[Service]\n"
                "Type=oneshot\n"
                "RemainAfterExit=yes\n"
                "TimeoutSec=0\n" /* the binary handles timeouts anyway */
                "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '%s' '%s'\n"
                "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
                name, u, strempty(password), strempty(filtered),
                name);

        if (tmp)
                fprintf(f,
                        "ExecStartPost=/sbin/mke2fs '/dev/mapper/%s'\n",
                        name);

        if (swap)
                fprintf(f,
                        "ExecStartPost=/sbin/mkswap '/dev/mapper/%s'\n",
                        name);

        r = fflush_and_check(f);
        if (r < 0)
                return log_error_errno(r, "Failed to write file %s: %m", p);

        from = strjoina("../", n);

        if (!noauto) {

                to = strjoin(arg_dest, "/", d, ".wants/", n, NULL);
                if (!to)
                        return log_oom();

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

                free(to);
                if (!nofail)
                        to = strjoin(arg_dest, "/cryptsetup.target.requires/", n, NULL);
                else
                        to = strjoin(arg_dest, "/cryptsetup.target.wants/", n, NULL);
                if (!to)
                        return log_oom();

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

        free(to);
        to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n, NULL);
        if (!to)
                return log_oom();

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

        if (!noauto && !nofail) {
                _cleanup_free_ char *dmname;
                dmname = strjoin("dev-mapper-", e, ".device", NULL);
                if (!dmname)
                        return log_oom();

                r = write_drop_in(arg_dest, dmname, 90, "device-timeout",
                                  "# Automatically generated by systemd-cryptsetup-generator \n\n"
                                  "[Unit]\nJobTimeoutSec=0");
                if (r < 0)
                        return log_error_errno(r, "Failed to write device drop-in: %m");
        }

        return 0;
}
Exemplo n.º 10
0
static int create_disk(
                const char *name,
                const char *device,
                const char *password,
                const char *options) {

        _cleanup_free_ char *p = NULL, *n = NULL, *d = NULL, *u = NULL, *from = NULL, *to = NULL, *e = NULL;
        _cleanup_fclose_ FILE *f = NULL;
        bool noauto, nofail, tmp, swap;

        assert(name);
        assert(device);

        noauto = has_option(options, "noauto");
        nofail = has_option(options, "nofail");
        tmp = has_option(options, "tmp");
        swap = has_option(options, "swap");

        if (tmp && swap) {
                log_error("Device '%s' cannot be both 'tmp' and 'swap'. Ignoring.", name);
                return -EINVAL;
        }

        n = unit_name_from_path_instance("systemd-cryptsetup", name, ".service");
        if (!n)
                return log_oom();

        p = strjoin(arg_dest, "/", n, NULL);
        if (!p)
                return log_oom();

        u = fstab_node_to_udev_node(device);
        if (!u)
                return log_oom();

        d = unit_name_from_path(u, ".device");
        if (!d)
                return log_oom();

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

        fputs(
                "# Automatically generated by systemd-cryptsetup-generator\n\n"
                "[Unit]\n"
                "Description=Cryptography Setup for %I\n"
                "Documentation=man:[email protected](8) man:crypttab(5)\n"
                "SourcePath=/etc/crypttab\n"
                "Conflicts=umount.target\n"
                "DefaultDependencies=no\n"
                "BindsTo=dev-mapper-%i.device\n"
                "IgnoreOnIsolate=true\n"
                "After=systemd-readahead-collect.service systemd-readahead-replay.service\n",
                f);

        if (!nofail)
                fprintf(f,
                        "Before=cryptsetup.target\n");

        if (password) {
                if (streq(password, "/dev/urandom") ||
                    streq(password, "/dev/random") ||
                    streq(password, "/dev/hw_random"))
                        fputs("After=systemd-random-seed.service\n", f);
                else if (!streq(password, "-") &&
                         !streq(password, "none"))
                        fprintf(f,
                                "RequiresMountsFor=%s\n",
                                password);
        }

        if (is_device_path(u))
                fprintf(f,
                        "BindsTo=%s\n"
                        "After=%s\n"
                        "Before=umount.target\n",
                        d, d);
        else
                fprintf(f,
                        "RequiresMountsFor=%s\n",
                        u);

        fprintf(f,
                "\n[Service]\n"
                "Type=oneshot\n"
                "RemainAfterExit=yes\n"
                "TimeoutSec=0\n" /* the binary handles timeouts anyway */
                "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '%s' '%s'\n"
                "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
                name, u, strempty(password), strempty(options),
                name);

        if (tmp)
                fprintf(f,
                        "ExecStartPost=/sbin/mke2fs '/dev/mapper/%s'\n",
                        name);

        if (swap)
                fprintf(f,
                        "ExecStartPost=/sbin/mkswap '/dev/mapper/%s'\n",
                        name);

        fflush(f);

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

        if (asprintf(&from, "../%s", n) < 0)
                return log_oom();

        if (!noauto) {

                to = strjoin(arg_dest, "/", d, ".wants/", n, NULL);
                if (!to)
                        return log_oom();

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

                free(to);
                if (!nofail)
                        to = strjoin(arg_dest, "/cryptsetup.target.requires/", n, NULL);
                else
                        to = strjoin(arg_dest, "/cryptsetup.target.wants/", n, NULL);
                if (!to)
                        return log_oom();

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

        e = unit_name_escape(name);
        if (!e)
                return log_oom();

        free(to);
        to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n, NULL);
        if (!to)
                return log_oom();

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

        if (!noauto && !nofail) {
                int r;
                free(p);
                p = strjoin(arg_dest, "/dev-mapper-", e, ".device.d/50-job-timeout-sec-0.conf", NULL);
                if (!p)
                        return log_oom();

                mkdir_parents_label(p, 0755);

                r = write_string_file(p,
                                "# Automatically generated by systemd-cryptsetup-generator\n\n"
                                "[Unit]\n"
                                "JobTimeoutSec=0\n"); /* the binary handles timeouts anyway */
                if (r)
                        return r;
        }

        return 0;
}