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>
29 #ifdef HAVE_LINUX_BTRFS_H
30 #include <linux/btrfs.h>
33 #include "path-util.h"
40 #include "unit-name.h"
45 * - Properly handle cryptsetup partitions
46 * - Define new partition type for encrypted swap
47 * - Make /home automount rather than mount
51 static const char *arg_dest = "/tmp";
53 static inline void blkid_free_probep(blkid_probe *b) {
57 #define _cleanup_blkid_freep_probe_ _cleanup_(blkid_free_probep)
59 static int verify_gpt_partition(const char *node, sd_id128_t *type, unsigned *nr, char **fstype) {
60 _cleanup_blkid_freep_probe_ blkid_probe b = NULL;
65 b = blkid_new_probe_from_filename(node);
67 return errno != 0 ? -errno : -ENOMEM;
69 blkid_probe_enable_superblocks(b, 1);
70 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
71 blkid_probe_enable_partitions(b, 1);
72 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
75 r = blkid_do_safeprobe(b);
81 return errno ? -errno : -EIO;
84 r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL);
86 /* return 0 if we're not on GPT */
87 return errno ? -errno : 0;
89 if (strcmp(v, "gpt") != 0)
94 r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
96 return errno ? -errno : -EIO;
98 r = sd_id128_from_string(v, type);
105 r = blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL);
107 return errno ? -errno : -EIO;
109 r = safe_atou(v, nr);
119 r = blkid_probe_lookup_value(b, "TYPE", &v, NULL);
134 static int add_swap(const char *path, const char *fstype) {
135 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
136 _cleanup_fclose_ FILE *f = NULL;
138 log_debug("Adding swap: %s %s", path, fstype);
140 name = unit_name_from_path(path, ".swap");
144 unit = strjoin(arg_dest, "/", name, NULL);
148 f = fopen(unit, "wxe");
150 log_error("Failed to create unit file %s: %m", unit);
155 "# Automatically generated by systemd-gpt-auto-generator\n\n"
157 "DefaultDependencies=no\n"
158 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
159 "Before=" SPECIAL_UMOUNT_TARGET " " SPECIAL_SWAP_TARGET "\n\n"
166 log_error("Failed to write unit file %s: %m", unit);
170 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
174 mkdir_parents_label(lnk, 0755);
175 if (symlink(unit, lnk) < 0) {
176 log_error("Failed to create symlink %s: %m", lnk);
183 static int add_home(const char *path, const char *fstype) {
184 _cleanup_free_ char *unit = NULL, *lnk = NULL;
185 _cleanup_fclose_ FILE *f = NULL;
187 if (dir_is_empty("/home") <= 0)
190 log_debug("Adding home: %s %s", path, fstype);
192 unit = strappend(arg_dest, "/home.mount");
196 f = fopen(unit, "wxe");
198 log_error("Failed to create unit file %s: %m", unit);
203 "# Automatically generated by systemd-gpt-auto-generator\n\n"
205 "DefaultDependencies=no\n"
206 "After=" SPECIAL_LOCAL_FS_PRE_TARGET "\n"
207 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
208 "Before=" SPECIAL_UMOUNT_TARGET " " SPECIAL_LOCAL_FS_TARGET "\n\n"
218 log_error("Failed to write unit file %s: %m", unit);
222 lnk = strjoin(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".requires/home.mount", NULL);
227 mkdir_parents_label(lnk, 0755);
228 if (symlink(unit, lnk) < 0) {
229 log_error("Failed to create symlink %s: %m", lnk);
236 static int enumerate_partitions(struct udev *udev, dev_t dev) {
237 struct udev_enumerate *e = NULL;
238 struct udev_device *parent = NULL, *d = NULL;
239 struct udev_list_entry *first, *item;
240 unsigned home_nr = (unsigned) -1;
241 _cleanup_free_ char *home = NULL, *home_fstype = NULL;
244 e = udev_enumerate_new(udev);
250 d = udev_device_new_from_devnum(udev, 'b', dev);
256 parent = udev_device_get_parent(d);
262 r = udev_enumerate_add_match_parent(e, parent);
268 r = udev_enumerate_add_match_subsystem(e, "block");
274 r = udev_enumerate_scan_devices(e);
276 log_error("Failed to enumerate partitions on /dev/block/%u:%u: %s",
277 major(dev), minor(dev), strerror(-r));
281 first = udev_enumerate_get_list_entry(e);
282 udev_list_entry_foreach(item, first) {
283 _cleanup_free_ char *fstype = NULL;
284 const char *node = NULL;
285 struct udev_device *q;
289 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
295 if (udev_device_get_devnum(q) == udev_device_get_devnum(d))
298 if (udev_device_get_devnum(q) == udev_device_get_devnum(parent))
301 node = udev_device_get_devnode(q);
307 r = verify_gpt_partition(node, &type_id, &nr, &fstype);
309 log_error("Failed to verify GPT partition %s: %s",
311 udev_device_unref(q);
317 if (sd_id128_equal(type_id, SD_ID128_MAKE(06,57,fd,6d,a4,ab,43,c4,84,e5,09,33,c8,4b,4f,4f)))
318 add_swap(node, fstype);
319 else if (sd_id128_equal(type_id, SD_ID128_MAKE(93,3a,c7,e1,2e,b4,4f,13,b8,44,0e,14,e2,ae,f9,15))) {
321 if (!home || nr < home_nr) {
332 home_fstype = fstype;
338 udev_device_unref(q);
341 if (home && home_fstype)
342 add_home(home, home_fstype);
346 udev_device_unref(d);
349 udev_enumerate_unref(e);
355 static int get_btrfs_block_device(const char *path, dev_t *dev) {
356 struct btrfs_ioctl_fs_info_args fsi;
357 _cleanup_close_ int fd = -1;
363 fd = open(path, O_DIRECTORY|O_CLOEXEC);
368 if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
371 /* We won't do this for btrfs RAID */
372 if (fsi.num_devices != 1)
375 for (id = 1; id <= fsi.max_id; id++) {
376 struct btrfs_ioctl_dev_info_args di;
382 if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
389 if (stat((char*) di.path, &st) < 0)
392 if (!S_ISBLK(st.st_mode))
395 if (major(st.st_rdev) == 0)
405 static int get_block_device(const char *path, dev_t *dev) {
415 if (major(st.st_dev) != 0) {
420 if (statfs("/", &sfs) < 0)
423 if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
424 return get_btrfs_block_device(path, dev);
429 static int devno_to_devnode(struct udev *udev, dev_t devno, char **ret) {
430 struct udev_device *d = NULL;
435 d = udev_device_new_from_devnum(udev, 'b', devno);
441 t = udev_device_get_devnode(d);
458 udev_device_unref(d);
463 int main(int argc, char *argv[]) {
464 _cleanup_free_ char *node = NULL;
465 struct udev *udev = NULL;
469 if (argc > 1 && argc != 4) {
470 log_error("This program takes three or no arguments.");
478 log_set_target(LOG_TARGET_SAFE);
479 log_parse_environment();
485 log_debug("In initrd, exiting.");
490 if (detect_container(NULL) > 0) {
491 log_debug("In a container, exiting.");
496 r = get_block_device("/", &devno);
498 log_error("Failed to determine block device of root file system: %s", strerror(-r));
502 log_debug("Root file system not on a (single) block device.");
512 r = devno_to_devnode(udev, devno, &node);
514 log_error("Failed to determine block device node from major/minor: %s", strerror(-r));
518 log_debug("Root device %s.", node);
520 r = verify_gpt_partition(node, NULL, NULL, NULL);
522 log_error("Failed to verify GPT partition %s: %s", node, strerror(-r));
528 r = enumerate_partitions(udev, devno);
534 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;