1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include <sys/statfs.h>
25 #include <blkid/blkid.h>
29 #include "path-util.h"
33 #include "udev-util.h"
35 #include "unit-name.h"
37 #include "generator.h"
41 #include "blkid-util.h"
42 #include "btrfs-util.h"
44 static const char *arg_dest
= "/tmp";
45 static bool arg_enabled
= true;
46 static bool arg_root_enabled
= true;
47 static bool arg_root_rw
= false;
49 static int add_swap(const char *path
) {
50 _cleanup_free_
char *name
= NULL
, *unit
= NULL
, *lnk
= NULL
;
51 _cleanup_fclose_
FILE *f
= NULL
;
56 log_debug("Adding swap: %s", path
);
58 r
= unit_name_from_path(path
, ".swap", &name
);
60 return log_error_errno(r
, "Failed to generate unit name: %m");
62 unit
= strjoin(arg_dest
, "/", name
, NULL
);
66 f
= fopen(unit
, "wxe");
68 return log_error_errno(errno
, "Failed to create unit file %s: %m", unit
);
71 "# Automatically generated by systemd-gpt-auto-generator\n\n"
73 "Description=Swap Partition\n"
74 "Documentation=man:systemd-gpt-auto-generator(8)\n\n"
81 return log_error_errno(errno
, "Failed to write unit file %s: %m", unit
);
83 lnk
= strjoin(arg_dest
, "/" SPECIAL_SWAP_TARGET
".wants/", name
, NULL
);
87 mkdir_parents_label(lnk
, 0755);
88 if (symlink(unit
, lnk
) < 0)
89 return log_error_errno(errno
, "Failed to create symlink %s: %m", lnk
);
94 static int add_cryptsetup(const char *id
, const char *what
, bool rw
, char **device
) {
95 _cleanup_free_
char *e
= NULL
, *n
= NULL
, *p
= NULL
, *d
= NULL
, *to
= NULL
;
96 _cleanup_fclose_
FILE *f
= NULL
;
104 r
= unit_name_from_path(what
, ".device", &d
);
106 return log_error_errno(r
, "Failed to generate unit name: %m");
108 e
= unit_name_escape(id
);
112 r
= unit_name_build("systemd-cryptsetup", e
, ".service", &n
);
114 return log_error_errno(r
, "Failed to generate unit name: %m");
116 p
= strjoin(arg_dest
, "/", n
, NULL
);
122 return log_error_errno(errno
, "Failed to create unit file %s: %m", p
);
125 "# Automatically generated by systemd-gpt-auto-generator\n\n"
127 "Description=Cryptography Setup for %%I\n"
128 "Documentation=man:systemd-gpt-auto-generator(8) man:systemd-cryptsetup@.service(8)\n"
129 "DefaultDependencies=no\n"
130 "Conflicts=umount.target\n"
131 "BindsTo=dev-mapper-%%i.device %s\n"
132 "Before=umount.target cryptsetup.target\n"
134 "IgnoreOnIsolate=true\n"
137 "RemainAfterExit=yes\n"
138 "TimeoutSec=0\n" /* the binary handles timeouts anyway */
139 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH
" attach '%s' '%s' '' '%s'\n"
140 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH
" detach '%s'\n",
142 id
, what
, rw
? "" : "read-only",
147 return log_error_errno(errno
, "Failed to write file %s: %m", p
);
149 from
= strjoina("../", n
);
151 to
= strjoin(arg_dest
, "/", d
, ".wants/", n
, NULL
);
155 mkdir_parents_label(to
, 0755);
156 if (symlink(from
, to
) < 0)
157 return log_error_errno(errno
, "Failed to create symlink %s: %m", to
);
160 to
= strjoin(arg_dest
, "/cryptsetup.target.requires/", n
, NULL
);
164 mkdir_parents_label(to
, 0755);
165 if (symlink(from
, to
) < 0)
166 return log_error_errno(errno
, "Failed to create symlink %s: %m", to
);
169 to
= strjoin(arg_dest
, "/dev-mapper-", e
, ".device.requires/", n
, NULL
);
173 mkdir_parents_label(to
, 0755);
174 if (symlink(from
, to
) < 0)
175 return log_error_errno(errno
, "Failed to create symlink %s: %m", to
);
178 p
= strjoin(arg_dest
, "/dev-mapper-", e
, ".device.d/50-job-timeout-sec-0.conf", NULL
);
182 mkdir_parents_label(p
, 0755);
183 r
= write_string_file(p
,
184 "# Automatically generated by systemd-gpt-auto-generator\n\n"
187 WRITE_STRING_FILE_CREATE
); /* the binary handles timeouts anyway */
189 return log_error_errno(r
, "Failed to write device drop-in: %m");
191 ret
= strappend("/dev/mapper/", id
);
199 static int add_mount(
205 const char *description
,
208 _cleanup_free_
char *unit
= NULL
, *lnk
= NULL
, *crypto_what
= NULL
, *p
= NULL
;
209 _cleanup_fclose_
FILE *f
= NULL
;
217 log_debug("Adding %s: %s %s", where
, what
, strna(fstype
));
219 if (streq_ptr(fstype
, "crypto_LUKS")) {
221 r
= add_cryptsetup(id
, what
, rw
, &crypto_what
);
229 r
= unit_name_from_path(where
, ".mount", &unit
);
231 return log_error_errno(r
, "Failed to generate unit name: %m");
233 p
= strjoin(arg_dest
, "/", unit
, NULL
);
239 return log_error_errno(errno
, "Failed to create unit file %s: %m", unit
);
242 "# Automatically generated by systemd-gpt-auto-generator\n\n"
245 "Documentation=man:systemd-gpt-auto-generator(8)\n",
249 fprintf(f
, "Before=%s\n", post
);
251 r
= generator_write_fsck_deps(f
, arg_dest
, what
, where
, fstype
);
263 fprintf(f
, "Type=%s\n", fstype
);
265 fprintf(f
, "Options=%s\n", rw
? "rw" : "ro");
269 return log_error_errno(errno
, "Failed to write unit file %s: %m", p
);
272 lnk
= strjoin(arg_dest
, "/", post
, ".requires/", unit
, NULL
);
276 mkdir_parents_label(lnk
, 0755);
277 if (symlink(p
, lnk
) < 0)
278 return log_error_errno(errno
, "Failed to create symlink %s: %m", lnk
);
284 static int probe_and_add_mount(
289 const char *description
,
292 _cleanup_blkid_free_probe_ blkid_probe b
= NULL
;
293 const char *fstype
= NULL
;
301 if (path_is_mount_point(where
, AT_SYMLINK_FOLLOW
) <= 0 &&
302 dir_is_empty(where
) <= 0) {
303 log_debug("%s already populated, ignoring.", where
);
307 /* Let's check the partition type here, so that we know
308 * whether to do LUKS magic. */
311 b
= blkid_new_probe_from_filename(what
);
315 log_error_errno(errno
, "Failed to allocate prober: %m");
319 blkid_probe_enable_superblocks(b
, 1);
320 blkid_probe_set_superblocks_flags(b
, BLKID_SUBLKS_TYPE
);
323 r
= blkid_do_safeprobe(b
);
324 if (r
== -2 || r
== 1) /* no result or uncertain */
327 return log_error_errno(errno
?: EIO
, "Failed to probe %s: %m", what
);
329 /* add_mount is OK with fstype being NULL. */
330 (void) blkid_probe_lookup_value(b
, "TYPE", &fstype
, NULL
);
342 static int enumerate_partitions(dev_t devnum
) {
344 _cleanup_udev_enumerate_unref_
struct udev_enumerate
*e
= NULL
;
345 _cleanup_udev_device_unref_
struct udev_device
*d
= NULL
;
346 _cleanup_blkid_free_probe_ blkid_probe b
= NULL
;
347 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
348 _cleanup_free_
char *home
= NULL
, *srv
= NULL
;
349 struct udev_list_entry
*first
, *item
;
350 struct udev_device
*parent
= NULL
;
351 const char *name
, *node
, *pttype
, *devtype
;
352 int home_nr
= -1, srv_nr
= -1;
353 bool home_rw
= true, srv_rw
= true;
362 d
= udev_device_new_from_devnum(udev
, 'b', devnum
);
366 name
= udev_device_get_devnode(d
);
368 name
= udev_device_get_syspath(d
);
370 log_debug("Device %u:%u does not have a name, ignoring.",
371 major(devnum
), minor(devnum
));
375 parent
= udev_device_get_parent(d
);
377 log_debug("%s: not a partitioned device, ignoring.", name
);
381 /* Does it have a devtype? */
382 devtype
= udev_device_get_devtype(parent
);
384 log_debug("%s: parent doesn't have a device type, ignoring.", name
);
388 /* Is this a disk or a partition? We only care for disks... */
389 if (!streq(devtype
, "disk")) {
390 log_debug("%s: parent isn't a raw disk, ignoring.", name
);
394 /* Does it have a device node? */
395 node
= udev_device_get_devnode(parent
);
397 log_debug("%s: parent device does not have device node, ignoring.", name
);
401 log_debug("%s: root device %s.", name
, node
);
403 pn
= udev_device_get_devnum(parent
);
408 b
= blkid_new_probe_from_filename(node
);
413 return log_error_errno(errno
, "%s: failed to allocate prober: %m", node
);
416 blkid_probe_enable_partitions(b
, 1);
417 blkid_probe_set_partitions_flags(b
, BLKID_PARTS_ENTRY_DETAILS
);
420 r
= blkid_do_safeprobe(b
);
421 if (r
== -2 || r
== 1) /* no result or uncertain */
424 return log_error_errno(errno
?: EIO
, "%s: failed to probe: %m", node
);
427 r
= blkid_probe_lookup_value(b
, "PTTYPE", &pttype
, NULL
);
429 return log_error_errno(errno
?: EIO
,
430 "%s: failed to determine partition table type: %m", node
);
432 /* We only do this all for GPT... */
433 if (!streq_ptr(pttype
, "gpt")) {
434 log_debug("%s: not a GPT partition table, ignoring.", node
);
439 pl
= blkid_probe_get_partitions(b
);
444 return log_error_errno(errno
, "%s: failed to list partitions: %m", node
);
447 e
= udev_enumerate_new(udev
);
451 r
= udev_enumerate_add_match_parent(e
, parent
);
455 r
= udev_enumerate_add_match_subsystem(e
, "block");
459 r
= udev_enumerate_scan_devices(e
);
461 return log_error_errno(r
, "%s: failed to enumerate partitions: %m", node
);
463 first
= udev_enumerate_get_list_entry(e
);
464 udev_list_entry_foreach(item
, first
) {
465 _cleanup_udev_device_unref_
struct udev_device
*q
;
466 const char *stype
, *subnode
;
471 unsigned long long flags
;
473 q
= udev_device_new_from_syspath(udev
, udev_list_entry_get_name(item
));
477 qn
= udev_device_get_devnum(q
);
487 subnode
= udev_device_get_devnode(q
);
491 pp
= blkid_partlist_devno_to_partition(pl
, qn
);
495 flags
= blkid_partition_get_flags(pp
);
497 /* Ignore partitions that are not marked for automatic
498 * mounting on discovery */
499 if (flags
& GPT_FLAG_NO_AUTO
)
502 nr
= blkid_partition_get_partno(pp
);
506 stype
= blkid_partition_get_type_string(pp
);
510 if (sd_id128_from_string(stype
, &type_id
) < 0)
513 if (sd_id128_equal(type_id
, GPT_SWAP
)) {
515 if (flags
& GPT_FLAG_READ_ONLY
) {
516 log_debug("%s marked as read-only swap partition, which is bogus. Ignoring.", subnode
);
520 k
= add_swap(subnode
);
524 } else if (sd_id128_equal(type_id
, GPT_HOME
)) {
526 /* We only care for the first /home partition */
527 if (home
&& nr
>= home_nr
)
531 home_rw
= !(flags
& GPT_FLAG_READ_ONLY
),
534 home
= strdup(subnode
);
538 } else if (sd_id128_equal(type_id
, GPT_SRV
)) {
540 /* We only care for the first /srv partition */
541 if (srv
&& nr
>= srv_nr
)
545 srv_rw
= !(flags
& GPT_FLAG_READ_ONLY
),
548 srv
= strdup(subnode
);
555 k
= probe_and_add_mount("home", home
, "/home", home_rw
, "Home Partition", SPECIAL_LOCAL_FS_TARGET
);
561 k
= probe_and_add_mount("srv", srv
, "/srv", srv_rw
, "Server Data Partition", SPECIAL_LOCAL_FS_TARGET
);
569 static int get_block_device(const char *path
, dev_t
*dev
) {
576 if (lstat(path
, &st
))
579 if (major(st
.st_dev
) != 0) {
584 if (statfs(path
, &sfs
) < 0)
587 if (F_TYPE_EQUAL(sfs
.f_type
, BTRFS_SUPER_MAGIC
))
588 return btrfs_get_block_device(path
, dev
);
593 static int parse_proc_cmdline_item(const char *key
, const char *value
) {
598 if (STR_IN_SET(key
, "systemd.gpt_auto", "rd.systemd.gpt_auto") && value
) {
600 r
= parse_boolean(value
);
602 log_warning("Failed to parse gpt-auto switch \"%s\". Ignoring.", value
);
606 } else if (streq(key
, "root") && value
) {
608 /* Disable root disk logic if there's a root= value
609 * specified (unless it happens to be "gpt-auto") */
611 arg_root_enabled
= streq(value
, "gpt-auto");
613 } else if (streq(key
, "rw") && !value
)
615 else if (streq(key
, "ro") && !value
)
621 static int add_root_mount(void) {
626 if (!is_efi_boot()) {
627 log_debug("Not a EFI boot, not creating root mount.");
631 r
= efi_loader_get_device_part_uuid(NULL
);
633 log_debug("EFI loader partition unknown, exiting.");
636 return log_error_errno(r
, "Failed to read ESP partition UUID: %m");
638 /* OK, we have an ESP partition, this is fantastic, so let's
639 * wait for a root device to show up. A udev rule will create
640 * the link for us under the right name. */
644 "/dev/gpt-auto-root",
645 in_initrd() ? "/sysroot" : "/",
649 in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET
: SPECIAL_LOCAL_FS_TARGET
);
655 static int add_mounts(void) {
659 r
= get_block_device("/", &devno
);
661 return log_error_errno(r
, "Failed to determine block device of root file system: %m");
663 r
= get_block_device("/usr", &devno
);
665 return log_error_errno(r
, "Failed to determine block device of /usr file system: %m");
667 log_debug("Neither root nor /usr file system are on a (single) block device.");
672 return enumerate_partitions(devno
);
675 int main(int argc
, char *argv
[]) {
678 if (argc
> 1 && argc
!= 4) {
679 log_error("This program takes three or no arguments.");
686 log_set_target(LOG_TARGET_SAFE
);
687 log_parse_environment();
692 if (detect_container(NULL
) > 0) {
693 log_debug("In a container, exiting.");
697 r
= parse_proc_cmdline(parse_proc_cmdline_item
);
699 log_warning_errno(r
, "Failed to parse kernel command line, ignoring: %m");
702 log_debug("Disabled, exiting.");
706 if (arg_root_enabled
)
707 r
= add_root_mount();
717 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;