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/>.
25 #include <sys/ioctl.h>
26 #include <sys/statfs.h>
27 #include <blkid/blkid.h>
29 #ifdef HAVE_LINUX_BTRFS_H
30 #include <linux/btrfs.h>
35 #include "path-util.h"
39 #include "udev-util.h"
41 #include "unit-name.h"
43 #include "generator.h"
47 static const char *arg_dest = "/tmp";
49 DEFINE_TRIVIAL_CLEANUP_FUNC(blkid_probe, blkid_free_probe);
50 #define _cleanup_blkid_freep_probe_ _cleanup_(blkid_free_probep)
52 static int verify_gpt_partition(const char *node, sd_id128_t *type, unsigned *nr, char **fstype) {
53 _cleanup_blkid_freep_probe_ blkid_probe b = NULL;
58 b = blkid_new_probe_from_filename(node);
60 return errno != 0 ? -errno : -ENOMEM;
62 blkid_probe_enable_superblocks(b, 1);
63 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
64 blkid_probe_enable_partitions(b, 1);
65 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
68 r = blkid_do_safeprobe(b);
69 if (r == -2 || r == 1) /* no result or uncertain */
72 return errno ? -errno : -EIO;
75 r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL);
77 /* return 0 if we're not on GPT */
78 return errno ? -errno : 0;
80 if (strcmp(v, "gpt") != 0)
85 r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
87 return errno ? -errno : -EIO;
89 r = sd_id128_from_string(v, type);
96 r = blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL);
98 return errno ? -errno : -EIO;
100 r = safe_atou(v, nr);
108 r = blkid_probe_lookup_value(b, "TYPE", &v, NULL);
125 static int add_swap(const char *path, const char *fstype) {
126 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
127 _cleanup_fclose_ FILE *f = NULL;
129 log_debug("Adding swap: %s %s", path, fstype);
131 name = unit_name_from_path(path, ".swap");
135 unit = strjoin(arg_dest, "/", name, NULL);
139 f = fopen(unit, "wxe");
141 log_error("Failed to create unit file %s: %m", unit);
146 "# Automatically generated by systemd-gpt-auto-generator\n\n"
153 log_error("Failed to write unit file %s: %m", unit);
157 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
161 mkdir_parents_label(lnk, 0755);
162 if (symlink(unit, lnk) < 0) {
163 log_error("Failed to create symlink %s: %m", lnk);
170 static int add_cryptsetup(const char *id, const char *what, char **device) {
171 _cleanup_free_ char *e = NULL, *n = NULL, *p = NULL, *d = NULL, *to = NULL;
172 _cleanup_fclose_ FILE *f = NULL;
180 d = unit_name_from_path(what, ".device");
184 e = unit_name_escape(id);
188 n = unit_name_build("systemd-cryptsetup", e, ".service");
192 p = strjoin(arg_dest, "/", n, NULL);
198 log_error("Failed to create unit file %s: %m", p);
203 "# Automatically generated by systemd-gpt-auto-generator\n\n"
205 "Description=Cryptography Setup for %%I\n"
206 "Documentation=man:systemd-cryptsetup@.service(8)\n"
207 "DefaultDependencies=no\n"
208 "Conflicts=umount.target\n"
209 "BindsTo=dev-mapper-%%i.device %s\n"
210 "Before=umount.target cryptsetup.target\n"
212 "IgnoreOnIsolate=true\n"
213 "After=systemd-readahead-collect.service systemd-readahead-replay.service\n\n"
216 "RemainAfterExit=yes\n"
217 "TimeoutSec=0\n" /* the binary handles timeouts anyway */
218 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s'\n"
219 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
226 log_error("Failed to write file %s: %m", p);
230 from = strappenda("../", n);
232 to = strjoin(arg_dest, "/", d, ".wants/", n, NULL);
236 mkdir_parents_label(to, 0755);
237 if (symlink(from, to) < 0) {
238 log_error("Failed to create symlink %s: %m", to);
243 to = strjoin(arg_dest, "/cryptsetup.target.requires/", n, NULL);
247 mkdir_parents_label(to, 0755);
248 if (symlink(from, to) < 0) {
249 log_error("Failed to create symlink %s: %m", to);
254 to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n, NULL);
258 mkdir_parents_label(to, 0755);
259 if (symlink(from, to) < 0) {
260 log_error("Failed to create symlink %s: %m", to);
265 p = strjoin(arg_dest, "/dev-mapper-", e, ".device.d/50-job-timeout-sec-0.conf", NULL);
269 mkdir_parents_label(p, 0755);
270 r = write_string_file(p,
271 "# Automatically generated by systemd-gpt-auto-generator\n\n"
273 "JobTimeoutSec=0\n"); /* the binary handles timeouts anyway */
275 log_error("Failed to write device drop-in: %s", strerror(-r));
279 ret = strappend("/dev/mapper/", id);
287 static int add_mount(const char *id, const char *what, const char *where, const char *fstype, const char *description) {
288 _cleanup_free_ char *unit = NULL, *lnk = NULL, *crypto_what = NULL, *p = NULL;
289 _cleanup_fclose_ FILE *f = NULL;
298 if (dir_is_empty(where) <= 0) {
299 log_debug("%s already populated, ignoring.", where);
303 log_debug("Adding %s: %s %s", where, what, fstype);
305 if (streq(fstype, "crypto_LUKS")) {
307 r = add_cryptsetup(id, what, &crypto_what);
315 unit = unit_name_from_path(where, ".mount");
319 p = strjoin(arg_dest, "/", unit, NULL);
325 log_error("Failed to create unit file %s: %m", unit);
330 "# Automatically generated by systemd-gpt-auto-generator\n\n"
335 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
354 log_error("Failed to write unit file %s: %m", unit);
358 lnk = strjoin(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".requires/", unit, NULL);
362 mkdir_parents_label(lnk, 0755);
363 if (symlink(unit, lnk) < 0) {
364 log_error("Failed to create symlink %s: %m", lnk);
371 static int enumerate_partitions(struct udev *udev, dev_t dev) {
372 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
373 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
374 _cleanup_free_ char *home = NULL, *home_fstype = NULL, *srv = NULL, *srv_fstype = NULL;
375 unsigned home_nr = (unsigned) -1, srv_nr = (unsigned )-1;
376 struct udev_list_entry *first, *item;
377 struct udev_device *parent = NULL;
380 e = udev_enumerate_new(udev);
384 d = udev_device_new_from_devnum(udev, 'b', dev);
388 parent = udev_device_get_parent(d);
392 r = udev_enumerate_add_match_parent(e, parent);
396 r = udev_enumerate_add_match_subsystem(e, "block");
400 r = udev_enumerate_scan_devices(e);
402 log_error("Failed to enumerate partitions on /dev/block/%u:%u: %s", major(dev), minor(dev), strerror(-r));
406 first = udev_enumerate_get_list_entry(e);
407 udev_list_entry_foreach(item, first) {
408 _cleanup_udev_device_unref_ struct udev_device *q;
409 _cleanup_free_ char *fstype = NULL;
410 const char *node = NULL;
414 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
418 if (udev_device_get_devnum(q) == udev_device_get_devnum(d))
421 if (udev_device_get_devnum(q) == udev_device_get_devnum(parent))
424 node = udev_device_get_devnode(q);
428 r = verify_gpt_partition(node, &type_id, &nr, &fstype);
430 /* skip child devices which are not detected properly */
433 log_error("Failed to verify GPT partition %s: %s", node, strerror(-r));
439 if (sd_id128_equal(type_id, GPT_SWAP))
440 add_swap(node, fstype);
442 else if (sd_id128_equal(type_id, GPT_HOME)) {
444 /* We only care for the first /home partition */
445 if (home && nr >= home_nr)
456 home_fstype = fstype;
459 } else if (sd_id128_equal(type_id, GPT_SRV)) {
461 /* We only care for the first /srv partition */
462 if (srv && nr >= srv_nr)
478 if (home && home_fstype)
479 add_mount("home", home, "/home", home_fstype, "Home Partition");
481 if (srv && srv_fstype)
482 add_mount("srv", srv, "/srv", srv_fstype, "Server Data Partition");
487 static int get_btrfs_block_device(const char *path, dev_t *dev) {
488 struct btrfs_ioctl_fs_info_args fsi = {};
489 _cleanup_close_ int fd = -1;
495 fd = open(path, O_DIRECTORY|O_CLOEXEC);
499 if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
502 /* We won't do this for btrfs RAID */
503 if (fsi.num_devices != 1)
506 for (id = 1; id <= fsi.max_id; id++) {
507 struct btrfs_ioctl_dev_info_args di = {
512 if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
519 if (stat((char*) di.path, &st) < 0)
522 if (!S_ISBLK(st.st_mode))
525 if (major(st.st_rdev) == 0)
535 static int get_block_device(const char *path, dev_t *dev) {
542 if (lstat(path, &st))
545 if (major(st.st_dev) != 0) {
550 if (statfs(path, &sfs) < 0)
553 if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
554 return get_btrfs_block_device(path, dev);
559 static int devno_to_devnode(struct udev *udev, dev_t devno, char **ret) {
560 _cleanup_udev_device_unref_ struct udev_device *d;
564 d = udev_device_new_from_devnum(udev, 'b', devno);
568 t = udev_device_get_devnode(d);
580 int main(int argc, char *argv[]) {
581 _cleanup_udev_unref_ struct udev *udev = NULL;
582 _cleanup_free_ char *node = NULL;
586 if (argc > 1 && argc != 4) {
587 log_error("This program takes three or no arguments.");
594 log_set_target(LOG_TARGET_SAFE);
595 log_parse_environment();
601 log_debug("In initrd, exiting.");
605 if (detect_container(NULL) > 0) {
606 log_debug("In a container, exiting.");
610 r = get_block_device("/", &devno);
612 log_error("Failed to determine block device of root file system: %s", strerror(-r));
615 log_debug("Root file system not on a (single) block device.");
625 r = devno_to_devnode(udev, devno, &node);
627 log_error("Failed to determine block device node from major/minor: %s", strerror(-r));
631 log_debug("Root device %s.", node);
633 r = verify_gpt_partition(node, NULL, NULL, NULL);
635 log_error("Failed to verify GPT partition %s: %s", node, strerror(-r));
639 log_debug("Not a GPT disk, exiting.");
643 r = enumerate_partitions(udev, devno);