2 This file is part of systemd.
4 Copyright 2013 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 #include <blkid/blkid.h>
22 #include <sys/statfs.h>
28 #include "alloc-util.h"
29 #include "blkid-util.h"
30 #include "btrfs-util.h"
31 #include "dirent-util.h"
32 #include "dissect-image.h"
36 #include "fstab-util.h"
37 #include "generator.h"
41 #include "mount-util.h"
42 #include "parse-util.h"
43 #include "path-util.h"
44 #include "proc-cmdline.h"
46 #include "stat-util.h"
47 #include "string-util.h"
48 #include "udev-util.h"
49 #include "unit-name.h"
53 static const char *arg_dest
= "/tmp";
54 static bool arg_enabled
= true;
55 static bool arg_root_enabled
= true;
56 static bool arg_root_rw
= false;
58 static int add_cryptsetup(const char *id
, const char *what
, bool rw
, bool require
, char **device
) {
59 _cleanup_free_
char *e
= NULL
, *n
= NULL
, *p
= NULL
, *d
= NULL
, *to
= NULL
;
60 _cleanup_fclose_
FILE *f
= NULL
;
67 r
= unit_name_from_path(what
, ".device", &d
);
69 return log_error_errno(r
, "Failed to generate unit name: %m");
71 e
= unit_name_escape(id
);
75 r
= unit_name_build("systemd-cryptsetup", e
, ".service", &n
);
77 return log_error_errno(r
, "Failed to generate unit name: %m");
79 p
= strjoin(arg_dest
, "/", n
);
85 return log_error_errno(errno
, "Failed to create unit file %s: %m", p
);
88 "# Automatically generated by systemd-gpt-auto-generator\n\n"
90 "Description=Cryptography Setup for %%I\n"
91 "Documentation=man:systemd-gpt-auto-generator(8) man:systemd-cryptsetup@.service(8)\n"
92 "DefaultDependencies=no\n"
93 "Conflicts=umount.target\n"
94 "BindsTo=dev-mapper-%%i.device %s\n"
95 "Before=umount.target cryptsetup.target\n"
97 "IgnoreOnIsolate=true\n"
100 "RemainAfterExit=yes\n"
101 "TimeoutSec=0\n" /* the binary handles timeouts anyway */
102 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH
" attach '%s' '%s' '' '%s'\n"
103 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH
" detach '%s'\n",
105 id
, what
, rw
? "" : "read-only",
108 r
= fflush_and_check(f
);
110 return log_error_errno(r
, "Failed to write file %s: %m", p
);
112 from
= strjoina("../", n
);
114 to
= strjoin(arg_dest
, "/", d
, ".wants/", n
);
118 mkdir_parents_label(to
, 0755);
119 if (symlink(from
, to
) < 0)
120 return log_error_errno(errno
, "Failed to create symlink %s: %m", to
);
125 to
= strjoin(arg_dest
, "/cryptsetup.target.requires/", n
);
129 mkdir_parents_label(to
, 0755);
130 if (symlink(from
, to
) < 0)
131 return log_error_errno(errno
, "Failed to create symlink %s: %m", to
);
134 to
= strjoin(arg_dest
, "/dev-mapper-", e
, ".device.requires/", n
);
138 mkdir_parents_label(to
, 0755);
139 if (symlink(from
, to
) < 0)
140 return log_error_errno(errno
, "Failed to create symlink %s: %m", to
);
144 p
= strjoin(arg_dest
, "/dev-mapper-", e
, ".device.d/50-job-timeout-sec-0.conf");
148 mkdir_parents_label(p
, 0755);
149 r
= write_string_file(p
,
150 "# Automatically generated by systemd-gpt-auto-generator\n\n"
153 WRITE_STRING_FILE_CREATE
); /* the binary handles timeouts anyway */
155 return log_error_errno(r
, "Failed to write device drop-in: %m");
157 ret
= strappend("/dev/mapper/", id
);
166 static int add_mount(
173 const char *description
,
176 _cleanup_free_
char *unit
= NULL
, *lnk
= NULL
, *crypto_what
= NULL
, *p
= NULL
;
177 _cleanup_fclose_
FILE *f
= NULL
;
185 log_debug("Adding %s: %s %s", where
, what
, strna(fstype
));
187 if (streq_ptr(fstype
, "crypto_LUKS")) {
189 r
= add_cryptsetup(id
, what
, rw
, true, &crypto_what
);
197 r
= unit_name_from_path(where
, ".mount", &unit
);
199 return log_error_errno(r
, "Failed to generate unit name: %m");
201 p
= strjoin(arg_dest
, "/", unit
);
207 return log_error_errno(errno
, "Failed to create unit file %s: %m", unit
);
210 "# Automatically generated by systemd-gpt-auto-generator\n\n"
213 "Documentation=man:systemd-gpt-auto-generator(8)\n",
217 fprintf(f
, "Before=%s\n", post
);
219 r
= generator_write_fsck_deps(f
, arg_dest
, what
, where
, fstype
);
231 fprintf(f
, "Type=%s\n", fstype
);
234 fprintf(f
, "Options=%s,%s\n", options
, rw
? "rw" : "ro");
236 fprintf(f
, "Options=%s\n", rw
? "rw" : "ro");
238 r
= fflush_and_check(f
);
240 return log_error_errno(r
, "Failed to write unit file %s: %m", p
);
243 lnk
= strjoin(arg_dest
, "/", post
, ".requires/", unit
);
247 mkdir_parents_label(lnk
, 0755);
248 if (symlink(p
, lnk
) < 0)
249 return log_error_errno(errno
, "Failed to create symlink %s: %m", lnk
);
255 static bool path_is_busy(const char *where
) {
258 /* already a mountpoint; generators run during reload */
259 r
= path_is_mount_point(where
, NULL
, AT_SYMLINK_FOLLOW
);
263 /* the directory might not exist on a stateless system */
270 /* not a mountpoint but it contains files */
271 if (dir_is_empty(where
) <= 0)
277 static int add_partition_mount(
278 DissectedPartition
*p
,
281 const char *description
) {
285 if (path_is_busy(where
)) {
286 log_debug("%s already populated, ignoring.", where
);
298 SPECIAL_LOCAL_FS_TARGET
);
301 static int add_swap(const char *path
) {
302 _cleanup_free_
char *name
= NULL
, *unit
= NULL
, *lnk
= NULL
;
303 _cleanup_fclose_
FILE *f
= NULL
;
308 log_debug("Adding swap: %s", path
);
310 r
= unit_name_from_path(path
, ".swap", &name
);
312 return log_error_errno(r
, "Failed to generate unit name: %m");
314 unit
= strjoin(arg_dest
, "/", name
);
318 f
= fopen(unit
, "wxe");
320 return log_error_errno(errno
, "Failed to create unit file %s: %m", unit
);
323 "# Automatically generated by systemd-gpt-auto-generator\n\n"
325 "Description=Swap Partition\n"
326 "Documentation=man:systemd-gpt-auto-generator(8)\n\n"
331 r
= fflush_and_check(f
);
333 return log_error_errno(r
, "Failed to write unit file %s: %m", unit
);
335 lnk
= strjoin(arg_dest
, "/" SPECIAL_SWAP_TARGET
".wants/", name
);
339 mkdir_parents_label(lnk
, 0755);
340 if (symlink(unit
, lnk
) < 0)
341 return log_error_errno(errno
, "Failed to create symlink %s: %m", lnk
);
347 static int add_automount(
354 const char *description
,
357 _cleanup_free_
char *unit
= NULL
, *lnk
= NULL
;
358 _cleanup_free_
char *opt
, *p
= NULL
;
359 _cleanup_fclose_
FILE *f
= NULL
;
367 opt
= strjoin(options
, ",noauto");
369 opt
= strdup("noauto");
384 r
= unit_name_from_path(where
, ".automount", &unit
);
386 return log_error_errno(r
, "Failed to generate unit name: %m");
388 p
= strjoin(arg_dest
, "/", unit
);
394 return log_error_errno(errno
, "Failed to create unit file %s: %m", unit
);
397 "# Automatically generated by systemd-gpt-auto-generator\n\n"
400 "Documentation=man:systemd-gpt-auto-generator(8)\n"
403 "TimeoutIdleSec="USEC_FMT
"\n",
406 timeout
/ USEC_PER_SEC
);
408 r
= fflush_and_check(f
);
410 return log_error_errno(r
, "Failed to write unit file %s: %m", p
);
412 lnk
= strjoin(arg_dest
, "/" SPECIAL_LOCAL_FS_TARGET
".wants/", unit
);
415 mkdir_parents_label(lnk
, 0755);
417 if (symlink(p
, lnk
) < 0)
418 return log_error_errno(errno
, "Failed to create symlink %s: %m", lnk
);
423 static int add_esp(DissectedPartition
*p
) {
430 log_debug("In initrd, ignoring the ESP.");
434 /* If /efi exists we'll use that. Otherwise we'll use /boot, as that's usually the better choice */
435 esp
= access("/efi/", F_OK
) >= 0 ? "/efi" : "/boot";
437 /* We create an .automount which is not overridden by the .mount from the fstab generator. */
438 if (fstab_is_mount_point(esp
)) {
439 log_debug("%s specified in fstab, ignoring.", esp
);
443 if (path_is_busy(esp
)) {
444 log_debug("%s already populated, ignoring.", esp
);
449 sd_id128_t loader_uuid
;
451 /* If this is an EFI boot, be extra careful, and only mount the ESP if it was the ESP used for booting. */
453 r
= efi_loader_get_device_part_uuid(&loader_uuid
);
455 log_debug("EFI loader partition unknown.");
459 return log_error_errno(r
, "Failed to read ESP partition UUID: %m");
461 if (!sd_id128_equal(p
->uuid
, loader_uuid
)) {
462 log_debug("Partition for %s does not appear to be the partition we are booted from.", esp
);
466 log_debug("Not an EFI boot, skipping ESP check.");
468 return add_automount("boot",
474 "EFI System Partition Automount",
478 static int add_esp(const char *what
) {
483 static int open_parent(dev_t devnum
, int *ret
) {
484 _cleanup_udev_device_unref_
struct udev_device
*d
= NULL
;
485 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
486 const char *name
, *devtype
, *node
;
487 struct udev_device
*parent
;
497 d
= udev_device_new_from_devnum(udev
, 'b', devnum
);
501 name
= udev_device_get_devnode(d
);
503 name
= udev_device_get_syspath(d
);
505 log_debug("Device %u:%u does not have a name, ignoring.", major(devnum
), minor(devnum
));
509 parent
= udev_device_get_parent(d
);
511 log_debug("%s: not a partitioned device, ignoring.", name
);
515 /* Does it have a devtype? */
516 devtype
= udev_device_get_devtype(parent
);
518 log_debug("%s: parent doesn't have a device type, ignoring.", name
);
522 /* Is this a disk or a partition? We only care for disks... */
523 if (!streq(devtype
, "disk")) {
524 log_debug("%s: parent isn't a raw disk, ignoring.", name
);
528 /* Does it have a device node? */
529 node
= udev_device_get_devnode(parent
);
531 log_debug("%s: parent device does not have device node, ignoring.", name
);
535 log_debug("%s: root device %s.", name
, node
);
537 pn
= udev_device_get_devnum(parent
);
538 if (major(pn
) == 0) {
539 log_debug("%s: parent device is not a proper block device, ignoring.", name
);
543 fd
= open(node
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
545 return log_error_errno(errno
, "Failed to open %s: %m", node
);
555 static int enumerate_partitions(dev_t devnum
) {
557 _cleanup_close_
int fd
= -1;
558 _cleanup_(dissected_image_unrefp
) DissectedImage
*m
= NULL
;
561 r
= open_parent(devnum
, &fd
);
565 r
= dissect_image(fd
, NULL
, 0, DISSECT_IMAGE_GPT_ONLY
, &m
);
567 log_debug_errno(r
, "No suitable partition table found, ignoring.");
571 return log_error_errno(r
, "Failed to dissect: %m");
573 if (m
->partitions
[PARTITION_SWAP
].found
) {
574 k
= add_swap(m
->partitions
[PARTITION_SWAP
].node
);
579 if (m
->partitions
[PARTITION_ESP
].found
) {
580 k
= add_esp(m
->partitions
+ PARTITION_ESP
);
585 if (m
->partitions
[PARTITION_HOME
].found
) {
586 k
= add_partition_mount(m
->partitions
+ PARTITION_HOME
, "home", "/home", "Home Partition");
591 if (m
->partitions
[PARTITION_SRV
].found
) {
592 k
= add_partition_mount(m
->partitions
+ PARTITION_SRV
, "srv", "/srv", "Server Data Partition");
600 static int get_block_device(const char *path
, dev_t
*dev
) {
607 /* Get's the block device directly backing a file system. If
608 * the block device is encrypted, returns the device mapper
611 if (lstat(path
, &st
))
614 if (major(st
.st_dev
) != 0) {
619 if (statfs(path
, &sfs
) < 0)
622 if (F_TYPE_EQUAL(sfs
.f_type
, BTRFS_SUPER_MAGIC
))
623 return btrfs_get_block_device(path
, dev
);
628 static int get_block_device_harder(const char *path
, dev_t
*dev
) {
629 _cleanup_closedir_
DIR *d
= NULL
;
630 _cleanup_free_
char *p
= NULL
, *t
= NULL
;
631 struct dirent
*de
, *found
= NULL
;
640 /* Gets the backing block device for a file system, and
641 * handles LUKS encrypted file systems, looking for its
642 * immediate parent, if there is one. */
644 r
= get_block_device(path
, &dt
);
648 if (asprintf(&p
, "/sys/dev/block/%u:%u/slaves", major(dt
), minor(dt
)) < 0)
659 FOREACH_DIRENT_ALL(de
, d
, return -errno
) {
661 if (STR_IN_SET(de
->d_name
, ".", ".."))
664 if (!IN_SET(de
->d_type
, DT_LNK
, DT_UNKNOWN
))
668 _cleanup_free_
char *u
= NULL
, *v
= NULL
, *a
= NULL
, *b
= NULL
;
670 /* We found a device backed by multiple other devices. We don't really support automatic
671 * discovery on such setups, with the exception of dm-verity partitions. In this case there are
672 * two backing devices: the data partitoin and the hash partition. We are fine with such
673 * setups, however, only if both partitions are on the same physical device. Hence, let's
676 u
= strjoin(p
, "/", de
->d_name
, "/../dev");
680 v
= strjoin(p
, "/", found
->d_name
, "/../dev");
684 r
= read_one_line_file(u
, &a
);
686 log_debug_errno(r
, "Failed to read %s: %m", u
);
690 r
= read_one_line_file(v
, &b
);
692 log_debug_errno(r
, "Failed to read %s: %m", v
);
696 /* Check if the parent device is the same. If not, then the two backing devices are on
697 * different physical devices, and we don't support that. */
708 q
= strjoina(p
, "/", found
->d_name
, "/dev");
710 r
= read_one_line_file(q
, &t
);
716 if (sscanf(t
, "%u:%u", &maj
, &min
) != 2)
722 *dev
= makedev(maj
, min
);
730 static int parse_proc_cmdline_item(const char *key
, const char *value
, void *data
) {
735 if (STR_IN_SET(key
, "systemd.gpt_auto", "rd.systemd.gpt_auto")) {
737 r
= value
? parse_boolean(value
) : 1;
739 log_warning("Failed to parse gpt-auto switch \"%s\". Ignoring.", value
);
743 } else if (streq(key
, "root")) {
745 if (proc_cmdline_value_missing(key
, value
))
748 /* Disable root disk logic if there's a root= value
749 * specified (unless it happens to be "gpt-auto") */
751 arg_root_enabled
= streq(value
, "gpt-auto");
753 } else if (streq(key
, "roothash")) {
755 if (proc_cmdline_value_missing(key
, value
))
758 /* Disable root disk logic if there's roothash= defined (i.e. verity enabled) */
760 arg_root_enabled
= false;
762 } else if (streq(key
, "rw") && !value
)
764 else if (streq(key
, "ro") && !value
)
771 static int add_root_cryptsetup(void) {
773 /* If a device /dev/gpt-auto-root-luks appears, then make it pull in systemd-cryptsetup-root.service, which
774 * sets it up, and causes /dev/gpt-auto-root to appear which is all we are looking for. */
776 return add_cryptsetup("root", "/dev/gpt-auto-root-luks", true, false, NULL
);
780 static int add_root_mount(void) {
785 if (!is_efi_boot()) {
786 log_debug("Not a EFI boot, not creating root mount.");
790 r
= efi_loader_get_device_part_uuid(NULL
);
792 log_debug("EFI loader partition unknown, exiting.");
795 return log_error_errno(r
, "Failed to read ESP partition UUID: %m");
797 /* OK, we have an ESP partition, this is fantastic, so let's
798 * wait for a root device to show up. A udev rule will create
799 * the link for us under the right name. */
802 r
= generator_write_initrd_root_device_deps(arg_dest
, "/dev/gpt-auto-root");
806 r
= add_root_cryptsetup();
813 "/dev/gpt-auto-root",
814 in_initrd() ? "/sysroot" : "/",
819 in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET
: SPECIAL_LOCAL_FS_TARGET
);
825 static int add_mounts(void) {
829 r
= get_block_device_harder("/", &devno
);
831 return log_error_errno(r
, "Failed to determine block device of root file system: %m");
833 r
= get_block_device_harder("/usr", &devno
);
835 return log_error_errno(r
, "Failed to determine block device of /usr file system: %m");
837 log_debug("Neither root nor /usr file system are on a (single) block device.");
842 return enumerate_partitions(devno
);
845 int main(int argc
, char *argv
[]) {
848 if (argc
> 1 && argc
!= 4) {
849 log_error("This program takes three or no arguments.");
856 log_set_target(LOG_TARGET_SAFE
);
857 log_parse_environment();
862 if (detect_container() > 0) {
863 log_debug("In a container, exiting.");
867 r
= proc_cmdline_parse(parse_proc_cmdline_item
, NULL
, 0);
869 log_warning_errno(r
, "Failed to parse kernel command line, ignoring: %m");
872 log_debug("Disabled, exiting.");
876 if (arg_root_enabled
)
877 r
= add_root_mount();
885 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;