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>
33 #include "path-util.h"
39 #include "udev-util.h"
41 #include "unit-name.h"
46 * - Properly handle cryptsetup partitions
47 * - Define new partition type for encrypted swap
48 * - Make /home automount rather than mount
52 #define GPT_SWAP SD_ID128_MAKE(06,57,fd,6d,a4,ab,43,c4,84,e5,09,33,c8,4b,4f,4f)
53 #define GPT_HOME SD_ID128_MAKE(93,3a,c7,e1,2e,b4,4f,13,b8,44,0e,14,e2,ae,f9,15)
55 static const char *arg_dest = "/tmp";
57 DEFINE_TRIVIAL_CLEANUP_FUNC(blkid_probe, blkid_free_probe);
58 #define _cleanup_blkid_freep_probe_ _cleanup_(blkid_free_probep)
60 static int verify_gpt_partition(const char *node, sd_id128_t *type, unsigned *nr, char **fstype) {
61 _cleanup_blkid_freep_probe_ blkid_probe b = NULL;
66 b = blkid_new_probe_from_filename(node);
68 return errno != 0 ? -errno : -ENOMEM;
70 blkid_probe_enable_superblocks(b, 1);
71 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
72 blkid_probe_enable_partitions(b, 1);
73 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
76 r = blkid_do_safeprobe(b);
82 return errno ? -errno : -EIO;
85 r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL);
87 /* return 0 if we're not on GPT */
88 return errno ? -errno : 0;
90 if (strcmp(v, "gpt") != 0)
95 r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
97 return errno ? -errno : -EIO;
99 r = sd_id128_from_string(v, type);
106 r = blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL);
108 return errno ? -errno : -EIO;
110 r = safe_atou(v, nr);
118 r = blkid_probe_lookup_value(b, "TYPE", &v, NULL);
135 static int add_swap(const char *path, const char *fstype) {
136 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
137 _cleanup_fclose_ FILE *f = NULL;
139 log_debug("Adding swap: %s %s", path, fstype);
141 name = unit_name_from_path(path, ".swap");
145 unit = strjoin(arg_dest, "/", name, NULL);
149 f = fopen(unit, "wxe");
151 log_error("Failed to create unit file %s: %m", unit);
156 "# Automatically generated by systemd-gpt-auto-generator\n\n"
158 "DefaultDependencies=no\n"
159 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
160 "Before=" SPECIAL_UMOUNT_TARGET " " SPECIAL_SWAP_TARGET "\n\n"
167 log_error("Failed to write unit file %s: %m", unit);
171 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
175 mkdir_parents_label(lnk, 0755);
176 if (symlink(unit, lnk) < 0) {
177 log_error("Failed to create symlink %s: %m", lnk);
184 static int add_home(const char *path, const char *fstype) {
185 _cleanup_free_ char *unit = NULL, *lnk = NULL, *fsck = NULL;
186 _cleanup_fclose_ FILE *f = NULL;
188 if (dir_is_empty("/home") <= 0)
191 log_debug("Adding home: %s %s", path, fstype);
193 unit = strappend(arg_dest, "/home.mount");
197 f = fopen(unit, "wxe");
199 log_error("Failed to create unit file %s: %m", unit);
203 fsck = unit_name_from_path_instance("systemd-fsck", path, ".service");
208 "# Automatically generated by systemd-gpt-auto-generator\n\n"
210 "DefaultDependencies=no\n"
212 "After=" SPECIAL_LOCAL_FS_PRE_TARGET " %s\n"
213 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
214 "Before=" SPECIAL_UMOUNT_TARGET " " SPECIAL_LOCAL_FS_TARGET "\n\n"
219 fsck, fsck, path, fstype);
223 log_error("Failed to write unit file %s: %m", unit);
227 lnk = strjoin(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".requires/home.mount", NULL);
231 mkdir_parents_label(lnk, 0755);
232 if (symlink(unit, lnk) < 0) {
233 log_error("Failed to create symlink %s: %m", lnk);
240 static int enumerate_partitions(struct udev *udev, dev_t dev) {
241 struct udev_device *parent = NULL;
242 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
243 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
244 struct udev_list_entry *first, *item;
245 unsigned home_nr = (unsigned) -1;
246 _cleanup_free_ char *home = NULL, *home_fstype = NULL;
249 e = udev_enumerate_new(udev);
253 d = udev_device_new_from_devnum(udev, 'b', dev);
257 parent = udev_device_get_parent(d);
261 r = udev_enumerate_add_match_parent(e, parent);
265 r = udev_enumerate_add_match_subsystem(e, "block");
269 r = udev_enumerate_scan_devices(e);
271 log_error("Failed to enumerate partitions on /dev/block/%u:%u: %s",
272 major(dev), minor(dev), strerror(-r));
276 first = udev_enumerate_get_list_entry(e);
277 udev_list_entry_foreach(item, first) {
278 _cleanup_free_ char *fstype = NULL;
279 const char *node = NULL;
280 _cleanup_udev_device_unref_ struct udev_device *q;
284 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
288 if (udev_device_get_devnum(q) == udev_device_get_devnum(d))
291 if (udev_device_get_devnum(q) == udev_device_get_devnum(parent))
294 node = udev_device_get_devnode(q);
298 r = verify_gpt_partition(node, &type_id, &nr, &fstype);
300 /* skip child devices which are not detected properly */
303 log_error("Failed to verify GPT partition %s: %s",
310 if (sd_id128_equal(type_id, GPT_SWAP))
311 add_swap(node, fstype);
312 else if (sd_id128_equal(type_id, GPT_HOME)) {
313 if (!home || nr < home_nr) {
322 home_fstype = fstype;
328 if (home && home_fstype)
329 add_home(home, home_fstype);
334 static int get_btrfs_block_device(const char *path, dev_t *dev) {
335 struct btrfs_ioctl_fs_info_args fsi = {};
336 _cleanup_close_ int fd = -1;
342 fd = open(path, O_DIRECTORY|O_CLOEXEC);
346 if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
349 /* We won't do this for btrfs RAID */
350 if (fsi.num_devices != 1)
353 for (id = 1; id <= fsi.max_id; id++) {
354 struct btrfs_ioctl_dev_info_args di = {
359 if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
366 if (stat((char*) di.path, &st) < 0)
369 if (!S_ISBLK(st.st_mode))
372 if (major(st.st_rdev) == 0)
382 static int get_block_device(const char *path, dev_t *dev) {
392 if (major(st.st_dev) != 0) {
397 if (statfs("/", &sfs) < 0)
400 if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
401 return get_btrfs_block_device(path, dev);
406 static int devno_to_devnode(struct udev *udev, dev_t devno, char **ret) {
407 _cleanup_udev_device_unref_ struct udev_device *d;
411 d = udev_device_new_from_devnum(udev, 'b', devno);
415 t = udev_device_get_devnode(d);
427 int main(int argc, char *argv[]) {
428 _cleanup_free_ char *node = NULL;
429 _cleanup_udev_unref_ struct udev *udev = NULL;
433 if (argc > 1 && argc != 4) {
434 log_error("This program takes three or no arguments.");
442 log_set_target(LOG_TARGET_SAFE);
443 log_parse_environment();
449 log_debug("In initrd, exiting.");
453 if (detect_container(NULL) > 0) {
454 log_debug("In a container, exiting.");
458 r = get_block_device("/", &devno);
460 log_error("Failed to determine block device of root file system: %s", strerror(-r));
464 log_debug("Root file system not on a (single) block device.");
474 r = devno_to_devnode(udev, devno, &node);
476 log_error("Failed to determine block device node from major/minor: %s", strerror(-r));
480 log_debug("Root device %s.", node);
482 r = verify_gpt_partition(node, NULL, NULL, NULL);
484 log_error("Failed to verify GPT partition %s: %s", node, strerror(-r));
490 r = enumerate_partitions(udev, devno);
493 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;