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"
148 "Description=Swap Partition\n"
149 "Documentation=man:systemd-gpt-auto-generator(8)\n\n"
156 log_error("Failed to write unit file %s: %m", unit);
160 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
164 mkdir_parents_label(lnk, 0755);
165 if (symlink(unit, lnk) < 0) {
166 log_error("Failed to create symlink %s: %m", lnk);
173 static int add_cryptsetup(const char *id, const char *what, char **device) {
174 _cleanup_free_ char *e = NULL, *n = NULL, *p = NULL, *d = NULL, *to = NULL;
175 _cleanup_fclose_ FILE *f = NULL;
183 d = unit_name_from_path(what, ".device");
187 e = unit_name_escape(id);
191 n = unit_name_build("systemd-cryptsetup", e, ".service");
195 p = strjoin(arg_dest, "/", n, NULL);
201 log_error("Failed to create unit file %s: %m", p);
206 "# Automatically generated by systemd-gpt-auto-generator\n\n"
208 "Description=Cryptography Setup for %%I\n"
209 "Documentation=man:systemd-gpt-auto-generator(8) man:systemd-cryptsetup@.service(8)\n"
210 "DefaultDependencies=no\n"
211 "Conflicts=umount.target\n"
212 "BindsTo=dev-mapper-%%i.device %s\n"
213 "Before=umount.target cryptsetup.target\n"
215 "IgnoreOnIsolate=true\n"
216 "After=systemd-readahead-collect.service systemd-readahead-replay.service\n\n"
219 "RemainAfterExit=yes\n"
220 "TimeoutSec=0\n" /* the binary handles timeouts anyway */
221 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s'\n"
222 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
229 log_error("Failed to write file %s: %m", p);
233 from = strappenda("../", n);
235 to = strjoin(arg_dest, "/", d, ".wants/", n, NULL);
239 mkdir_parents_label(to, 0755);
240 if (symlink(from, to) < 0) {
241 log_error("Failed to create symlink %s: %m", to);
246 to = strjoin(arg_dest, "/cryptsetup.target.requires/", n, NULL);
250 mkdir_parents_label(to, 0755);
251 if (symlink(from, to) < 0) {
252 log_error("Failed to create symlink %s: %m", to);
257 to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n, NULL);
261 mkdir_parents_label(to, 0755);
262 if (symlink(from, to) < 0) {
263 log_error("Failed to create symlink %s: %m", to);
268 p = strjoin(arg_dest, "/dev-mapper-", e, ".device.d/50-job-timeout-sec-0.conf", NULL);
272 mkdir_parents_label(p, 0755);
273 r = write_string_file(p,
274 "# Automatically generated by systemd-gpt-auto-generator\n\n"
276 "JobTimeoutSec=0\n"); /* the binary handles timeouts anyway */
278 log_error("Failed to write device drop-in: %s", strerror(-r));
282 ret = strappend("/dev/mapper/", id);
290 static int add_mount(const char *id, const char *what, const char *where, const char *fstype, const char *description) {
291 _cleanup_free_ char *unit = NULL, *lnk = NULL, *crypto_what = NULL, *p = NULL;
292 _cleanup_fclose_ FILE *f = NULL;
301 if (path_is_mount_point(where, true) <= 0 &&
302 dir_is_empty(where) <= 0) {
303 log_debug("%s already populated, ignoring.", where);
307 log_debug("Adding %s: %s %s", where, what, fstype);
309 if (streq(fstype, "crypto_LUKS")) {
311 r = add_cryptsetup(id, what, &crypto_what);
319 unit = unit_name_from_path(where, ".mount");
323 p = strjoin(arg_dest, "/", unit, NULL);
329 log_error("Failed to create unit file %s: %m", unit);
334 "# Automatically generated by systemd-gpt-auto-generator\n\n"
337 "Documentation=man:systemd-gpt-auto-generator(8)\n",
340 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
359 log_error("Failed to write unit file %s: %m", unit);
363 lnk = strjoin(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".requires/", unit, NULL);
367 mkdir_parents_label(lnk, 0755);
368 if (symlink(unit, lnk) < 0) {
369 log_error("Failed to create symlink %s: %m", lnk);
376 static int enumerate_partitions(struct udev *udev, dev_t dev) {
377 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
378 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
379 _cleanup_free_ char *home = NULL, *home_fstype = NULL, *srv = NULL, *srv_fstype = NULL;
380 unsigned home_nr = (unsigned) -1, srv_nr = (unsigned )-1;
381 struct udev_list_entry *first, *item;
382 struct udev_device *parent = NULL;
385 e = udev_enumerate_new(udev);
389 d = udev_device_new_from_devnum(udev, 'b', dev);
393 parent = udev_device_get_parent(d);
397 r = udev_enumerate_add_match_parent(e, parent);
401 r = udev_enumerate_add_match_subsystem(e, "block");
405 r = udev_enumerate_scan_devices(e);
407 log_error("Failed to enumerate partitions on /dev/block/%u:%u: %s", major(dev), minor(dev), strerror(-r));
411 first = udev_enumerate_get_list_entry(e);
412 udev_list_entry_foreach(item, first) {
413 _cleanup_udev_device_unref_ struct udev_device *q;
414 _cleanup_free_ char *fstype = NULL;
415 const char *node = NULL;
419 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
423 if (udev_device_get_devnum(q) == udev_device_get_devnum(d))
426 if (udev_device_get_devnum(q) == udev_device_get_devnum(parent))
429 node = udev_device_get_devnode(q);
433 r = verify_gpt_partition(node, &type_id, &nr, &fstype);
435 /* skip child devices which are not detected properly */
438 log_error("Failed to verify GPT partition %s: %s", node, strerror(-r));
444 if (sd_id128_equal(type_id, GPT_SWAP))
445 add_swap(node, fstype);
447 else if (sd_id128_equal(type_id, GPT_HOME)) {
449 /* We only care for the first /home partition */
450 if (home && nr >= home_nr)
461 home_fstype = fstype;
464 } else if (sd_id128_equal(type_id, GPT_SRV)) {
466 /* We only care for the first /srv partition */
467 if (srv && nr >= srv_nr)
483 if (home && home_fstype)
484 add_mount("home", home, "/home", home_fstype, "Home Partition");
486 if (srv && srv_fstype)
487 add_mount("srv", srv, "/srv", srv_fstype, "Server Data Partition");
492 static int get_btrfs_block_device(const char *path, dev_t *dev) {
493 struct btrfs_ioctl_fs_info_args fsi = {};
494 _cleanup_close_ int fd = -1;
500 fd = open(path, O_DIRECTORY|O_CLOEXEC);
504 if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
507 /* We won't do this for btrfs RAID */
508 if (fsi.num_devices != 1)
511 for (id = 1; id <= fsi.max_id; id++) {
512 struct btrfs_ioctl_dev_info_args di = {
517 if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
524 if (stat((char*) di.path, &st) < 0)
527 if (!S_ISBLK(st.st_mode))
530 if (major(st.st_rdev) == 0)
540 static int get_block_device(const char *path, dev_t *dev) {
547 if (lstat(path, &st))
550 if (major(st.st_dev) != 0) {
555 if (statfs(path, &sfs) < 0)
558 if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
559 return get_btrfs_block_device(path, dev);
564 static int devno_to_devnode(struct udev *udev, dev_t devno, char **ret) {
565 _cleanup_udev_device_unref_ struct udev_device *d;
569 d = udev_device_new_from_devnum(udev, 'b', devno);
573 t = udev_device_get_devnode(d);
585 int main(int argc, char *argv[]) {
586 _cleanup_udev_unref_ struct udev *udev = NULL;
587 _cleanup_free_ char *node = NULL;
591 if (argc > 1 && argc != 4) {
592 log_error("This program takes three or no arguments.");
599 log_set_target(LOG_TARGET_SAFE);
600 log_parse_environment();
606 log_debug("In initrd, exiting.");
610 if (detect_container(NULL) > 0) {
611 log_debug("In a container, exiting.");
615 r = get_block_device("/", &devno);
617 log_error("Failed to determine block device of root file system: %s", strerror(-r));
620 log_debug("Root file system not on a (single) block device.");
630 r = devno_to_devnode(udev, devno, &node);
632 log_error("Failed to determine block device node from major/minor: %s", strerror(-r));
636 log_debug("Root device %s.", node);
638 r = verify_gpt_partition(node, NULL, NULL, NULL);
640 log_error("Failed to verify GPT partition %s: %s", node, strerror(-r));
644 log_debug("Not a GPT disk, exiting.");
648 r = enumerate_partitions(udev, devno);