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 (!path_is_absolute(what)) { log_debug("Skipping entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype)); return 0; } 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, 1, false, false, false, SPECIAL_INITRD_ROOT_FS_TARGET, "/proc/cmdline"); }
static int add_usr_mount(void) { _cleanup_free_ char *what = NULL; const char *opts; if (!arg_usr_what && !arg_usr_fstype && !arg_usr_options) return 0; if (arg_root_what && !arg_usr_what) { arg_usr_what = strdup(arg_root_what); if (!arg_usr_what) return log_oom(); } if (arg_root_fstype && !arg_usr_fstype) { arg_usr_fstype = strdup(arg_root_fstype); if (!arg_usr_fstype) return log_oom(); } if (arg_root_options && !arg_usr_options) { arg_usr_options = strdup(arg_root_options); if (!arg_usr_options) return log_oom(); } if (!arg_usr_what) return 0; what = fstab_node_to_udev_node(arg_usr_what); if (!path_is_absolute(what)) { log_debug("Skipping entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype)); return -1; } if (!arg_usr_options) opts = arg_root_rw > 0 ? "rw" : "ro"; else if (!fstab_test_option(arg_usr_options, "ro\0" "rw\0")) opts = strjoina(arg_usr_options, ",", arg_root_rw > 0 ? "rw" : "ro"); else opts = arg_usr_options; log_debug("Found entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype)); return add_mount(what, "/sysroot/usr", arg_usr_fstype, opts, 1, false, false, false, SPECIAL_INITRD_ROOT_FS_TARGET, "/proc/cmdline"); }
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); }
static bool mount_in_initrd(struct mntent *me) { assert(me); return fstab_test_option(me->mnt_opts, "x-initrd.mount\0") || streq(me->mnt_dir, "/usr"); }
static bool mount_is_network(struct mntent *me) { assert(me); return fstab_test_option(me->mnt_opts, "_netdev\0") || fstype_is_network(me->mnt_type); }
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; }
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; }
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, *e = NULL, *filtered = NULL, *u_escaped = NULL, *password_escaped = NULL, *filtered_escaped = NULL, *name_escaped = NULL; _cleanup_fclose_ FILE *f = NULL; const char *dmname; bool noauto, nofail, tmp, swap, netdev; 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"); netdev = fstab_test_option(options, "_netdev\0"); if (tmp && swap) { log_error("Device '%s' cannot be both 'tmp' and 'swap'. Ignoring.", name); return -EINVAL; } name_escaped = specifier_escape(name); if (!name_escaped) return log_oom(); 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); if (!p) return log_oom(); u = fstab_node_to_udev_node(device); if (!u) return log_oom(); u_escaped = specifier_escape(u); if (!u_escaped) 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"); password_escaped = specifier_escape(password); if (!password_escaped) return log_oom(); f = fopen(p, "wxe"); if (!f) return log_error_errno(errno, "Failed to create unit file %s: %m", p); fprintf(f, "# 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" "IgnoreOnIsolate=true\n" "After=%s\n", netdev ? "remote-fs-pre.target" : "cryptsetup-pre.target"); if (!nofail) fprintf(f, "Before=%s\n", netdev ? "remote-cryptsetup.target" : "cryptsetup.target"); if (password) { if (STR_IN_SET(password, "/dev/urandom", "/dev/random", "/dev/hw_random")) fputs_unlocked("After=systemd-random-seed.service\n", f); else if (!STR_IN_SET(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 (path_startswith(uu, "/dev/")) { _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_escaped); } } } if (path_startswith(u, "/dev/")) { fprintf(f, "BindsTo=%s\n" "After=%s\n" "Before=umount.target\n", d, d); if (swap) fputs_unlocked("Before=dev-mapper-%i.swap\n", f); } else fprintf(f, "RequiresMountsFor=%s\n", u_escaped); r = generator_write_timeouts(arg_dest, device, name, options, &filtered); if (r < 0) return r; filtered_escaped = specifier_escape(filtered); if (!filtered_escaped) return log_oom(); fprintf(f, "\n[Service]\n" "Type=oneshot\n" "RemainAfterExit=yes\n" "TimeoutSec=0\n" /* the binary handles timeouts anyway */ "KeyringMode=shared\n" /* make sure we can share cached keys among instances */ "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '%s' '%s'\n" "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n", name_escaped, u_escaped, strempty(password_escaped), strempty(filtered_escaped), name_escaped); if (tmp) fprintf(f, "ExecStartPost=/sbin/mke2fs '/dev/mapper/%s'\n", name_escaped); if (swap) fprintf(f, "ExecStartPost=/sbin/mkswap '/dev/mapper/%s'\n", name_escaped); r = fflush_and_check(f); if (r < 0) return log_error_errno(r, "Failed to write file %s: %m", p); if (!noauto) { r = generator_add_symlink(arg_dest, d, "wants", n); if (r < 0) return r; r = generator_add_symlink(arg_dest, netdev ? "remote-cryptsetup.target" : "cryptsetup.target", nofail ? "wants" : "requires", n); if (r < 0) return r; } dmname = strjoina("dev-mapper-", e, ".device"); r = generator_add_symlink(arg_dest, dmname, "requires", n); if (r < 0) return r; if (!noauto && !nofail) { 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; }