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 (dir_is_empty(where) <= 0) {
302 log_debug("%s already populated, ignoring.", where);
306 log_debug("Adding %s: %s %s", where, what, fstype);
308 if (streq(fstype, "crypto_LUKS")) {
310 r = add_cryptsetup(id, what, &crypto_what);
318 unit = unit_name_from_path(where, ".mount");
322 p = strjoin(arg_dest, "/", unit, NULL);
328 log_error("Failed to create unit file %s: %m", unit);
333 "# Automatically generated by systemd-gpt-auto-generator\n\n"
336 "Documentation=man:systemd-gpt-auto-generator(8)\n",
339 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
358 log_error("Failed to write unit file %s: %m", unit);
362 lnk = strjoin(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".requires/", unit, NULL);
366 mkdir_parents_label(lnk, 0755);
367 if (symlink(unit, lnk) < 0) {
368 log_error("Failed to create symlink %s: %m", lnk);
375 static int enumerate_partitions(struct udev *udev, dev_t dev) {
376 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
377 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
378 _cleanup_free_ char *home = NULL, *home_fstype = NULL, *srv = NULL, *srv_fstype = NULL;
379 unsigned home_nr = (unsigned) -1, srv_nr = (unsigned )-1;
380 struct udev_list_entry *first, *item;
381 struct udev_device *parent = NULL;
384 e = udev_enumerate_new(udev);
388 d = udev_device_new_from_devnum(udev, 'b', dev);
392 parent = udev_device_get_parent(d);
396 r = udev_enumerate_add_match_parent(e, parent);
400 r = udev_enumerate_add_match_subsystem(e, "block");
404 r = udev_enumerate_scan_devices(e);
406 log_error("Failed to enumerate partitions on /dev/block/%u:%u: %s", major(dev), minor(dev), strerror(-r));
410 first = udev_enumerate_get_list_entry(e);
411 udev_list_entry_foreach(item, first) {
412 _cleanup_udev_device_unref_ struct udev_device *q;
413 _cleanup_free_ char *fstype = NULL;
414 const char *node = NULL;
418 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
422 if (udev_device_get_devnum(q) == udev_device_get_devnum(d))
425 if (udev_device_get_devnum(q) == udev_device_get_devnum(parent))
428 node = udev_device_get_devnode(q);
432 r = verify_gpt_partition(node, &type_id, &nr, &fstype);
434 /* skip child devices which are not detected properly */
437 log_error("Failed to verify GPT partition %s: %s", node, strerror(-r));
443 if (sd_id128_equal(type_id, GPT_SWAP))
444 add_swap(node, fstype);
446 else if (sd_id128_equal(type_id, GPT_HOME)) {
448 /* We only care for the first /home partition */
449 if (home && nr >= home_nr)
460 home_fstype = fstype;
463 } else if (sd_id128_equal(type_id, GPT_SRV)) {
465 /* We only care for the first /srv partition */
466 if (srv && nr >= srv_nr)
482 if (home && home_fstype)
483 add_mount("home", home, "/home", home_fstype, "Home Partition");
485 if (srv && srv_fstype)
486 add_mount("srv", srv, "/srv", srv_fstype, "Server Data Partition");
491 static int get_btrfs_block_device(const char *path, dev_t *dev) {
492 struct btrfs_ioctl_fs_info_args fsi = {};
493 _cleanup_close_ int fd = -1;
499 fd = open(path, O_DIRECTORY|O_CLOEXEC);
503 if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
506 /* We won't do this for btrfs RAID */
507 if (fsi.num_devices != 1)
510 for (id = 1; id <= fsi.max_id; id++) {
511 struct btrfs_ioctl_dev_info_args di = {
516 if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
523 if (stat((char*) di.path, &st) < 0)
526 if (!S_ISBLK(st.st_mode))
529 if (major(st.st_rdev) == 0)
539 static int get_block_device(const char *path, dev_t *dev) {
546 if (lstat(path, &st))
549 if (major(st.st_dev) != 0) {
554 if (statfs(path, &sfs) < 0)
557 if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
558 return get_btrfs_block_device(path, dev);
563 static int devno_to_devnode(struct udev *udev, dev_t devno, char **ret) {
564 _cleanup_udev_device_unref_ struct udev_device *d;
568 d = udev_device_new_from_devnum(udev, 'b', devno);
572 t = udev_device_get_devnode(d);
584 int main(int argc, char *argv[]) {
585 _cleanup_udev_unref_ struct udev *udev = NULL;
586 _cleanup_free_ char *node = NULL;
590 if (argc > 1 && argc != 4) {
591 log_error("This program takes three or no arguments.");
598 log_set_target(LOG_TARGET_SAFE);
599 log_parse_environment();
605 log_debug("In initrd, exiting.");
609 if (detect_container(NULL) > 0) {
610 log_debug("In a container, exiting.");
614 r = get_block_device("/", &devno);
616 log_error("Failed to determine block device of root file system: %s", strerror(-r));
619 log_debug("Root file system not on a (single) block device.");
629 r = devno_to_devnode(udev, devno, &node);
631 log_error("Failed to determine block device node from major/minor: %s", strerror(-r));
635 log_debug("Root device %s.", node);
637 r = verify_gpt_partition(node, NULL, NULL, NULL);
639 log_error("Failed to verify GPT partition %s: %s", node, strerror(-r));
643 log_debug("Not a GPT disk, exiting.");
647 r = enumerate_partitions(udev, devno);