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 <linux/btrfs.h>
26 #include <sys/ioctl.h>
27 #include <sys/statfs.h>
30 #include "path-util.h"
37 #include "unit-name.h"
41 * - Properly handle cryptsetup partitions
42 * - Define new partition type for encrypted swap
46 static const char *arg_dest = "/tmp";
48 static int verify_gpt_partition(dev_t dev, sd_id128_t *type, unsigned *nr, char **fstype) {
49 _cleanup_free_ char *t = NULL;
54 r = asprintf(&t, "/dev/block/%u:%u", major(dev), minor(dev));
59 b = blkid_new_probe_from_filename(t);
67 blkid_probe_enable_superblocks(b, 1);
68 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
69 blkid_probe_enable_partitions(b, 1);
70 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
73 r = blkid_do_safeprobe(b);
81 r = errno ? -errno : -EIO;
86 r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL);
88 r = errno ? -errno : -EIO;
92 if (strcmp(v, "gpt") != 0) {
99 r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
101 r = errno ? -errno : -EIO;
105 r = sd_id128_from_string(v, type);
112 r = blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL);
114 r = errno ? -errno : -EIO;
118 r = safe_atou(v, nr);
128 r = blkid_probe_lookup_value(b, "TYPE", &v, NULL);
151 static int add_swap(const char *path, const char *fstype) {
152 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
153 _cleanup_fclose_ FILE *f = NULL;
155 log_debug("Adding swap: %s %s", path, fstype);
157 name = unit_name_from_path(path, ".swap");
161 unit = strjoin(arg_dest, "/", name, NULL);
165 f = fopen(unit, "wxe");
167 log_error("Failed to create unit file %s: %m", unit);
172 "# Automatically generated by systemd-gpt-auto-generator\n\n"
174 "DefaultDependencies=no\n"
175 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
176 "Before=" SPECIAL_UMOUNT_TARGET " " SPECIAL_SWAP_TARGET "\n\n"
183 log_error("Failed to write unit file %s: %m", unit);
187 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
191 mkdir_parents_label(lnk, 0755);
192 if (symlink(unit, lnk) < 0) {
193 log_error("Failed to create symlink %s: %m", lnk);
200 static int add_home(const char *path, const char *fstype) {
201 _cleanup_free_ char *unit = NULL, *lnk = NULL;
202 _cleanup_fclose_ FILE *f = NULL;
204 log_debug("Adding home: %s %s", path, fstype);
206 unit = strappend(arg_dest, "/home.mount");
210 f = fopen(unit, "wxe");
212 log_error("Failed to create unit file %s: %m", unit);
217 "# Automatically generated by systemd-gpt-auto-generator\n\n"
219 "DefaultDependencies=no\n"
220 "After=" SPECIAL_LOCAL_FS_PRE_TARGET "\n"
221 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
222 "Before=" SPECIAL_UMOUNT_TARGET " " SPECIAL_LOCAL_FS_TARGET "\n\n"
232 log_error("Failed to write unit file %s: %m", unit);
236 lnk = strjoin(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".requires/home.mount", NULL);
241 mkdir_parents_label(lnk, 0755);
242 if (symlink(unit, lnk) < 0) {
243 log_error("Failed to create symlink %s: %m", lnk);
250 static int enumerate_partitions(dev_t dev) {
252 struct udev_enumerate *e = NULL;
253 struct udev_device *parent = NULL, *d = NULL;
254 struct udev_list_entry *first, *item;
255 unsigned home_nr = (unsigned) -1;
256 _cleanup_free_ char *home = NULL, *home_fstype = NULL;
263 e = udev_enumerate_new(udev);
269 d = udev_device_new_from_devnum(udev, 'b', dev);
275 parent = udev_device_get_parent(d);
281 r = udev_enumerate_add_match_parent(e, parent);
287 r = udev_enumerate_add_match_subsystem(e, "block");
293 r = udev_enumerate_scan_devices(e);
295 log_error("Failed to enumerate partitions: %s", strerror(-r));
299 first = udev_enumerate_get_list_entry(e);
300 udev_list_entry_foreach(item, first) {
301 _cleanup_free_ char *fstype = NULL;
302 const char *node = NULL;
303 struct udev_device *q;
307 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
313 if (udev_device_get_devnum(q) == udev_device_get_devnum(d))
316 if (udev_device_get_devnum(q) == udev_device_get_devnum(parent))
319 node = udev_device_get_devnode(q);
325 r = verify_gpt_partition(udev_device_get_devnum(q), &type_id, &nr, &fstype);
327 log_error("Failed to verify GPT partition: %s", strerror(-r));
328 udev_device_unref(q);
334 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)))
335 add_swap(node, fstype);
336 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))) {
338 if (!home || nr < home_nr) {
349 home_fstype = fstype;
355 udev_device_unref(q);
358 if (home && home_fstype)
359 add_home(home, home_fstype);
363 udev_device_unref(d);
366 udev_enumerate_unref(e);
374 static int get_btrfs_block_device(const char *path, dev_t *dev) {
375 struct btrfs_ioctl_fs_info_args fsi;
376 _cleanup_close_ int fd = -1;
382 fd = open(path, O_DIRECTORY|O_CLOEXEC);
387 if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
390 /* We won't do this for btrfs RAID */
391 if (fsi.num_devices != 1)
394 for (id = 1; id <= fsi.max_id; id++) {
395 struct btrfs_ioctl_dev_info_args di;
401 if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
408 if (stat((char*) di.path, &st) < 0)
411 if (!S_ISBLK(st.st_mode))
414 if (major(st.st_rdev) == 0)
424 static int get_block_device(const char *path, dev_t *dev) {
434 if (major(st.st_dev) != 0) {
439 if (statfs("/", &sfs) < 0)
442 if (F_TYPE_CMP(sfs.f_type, BTRFS_SUPER_MAGIC))
443 return get_btrfs_block_device(path, dev);
448 int main(int argc, char *argv[]) {
452 if (argc > 1 && argc != 4) {
453 log_error("This program takes three or no arguments.");
460 log_set_target(LOG_TARGET_SAFE);
461 log_parse_environment();
469 r = get_block_device("/", &dev);
471 log_error("Failed to determine block device of root file system: %s", strerror(-r));
475 log_debug("Root file system not on a (single) block device.");
479 log_debug("Root device %u:%u.", major(dev), minor(dev));
481 r = verify_gpt_partition(dev, NULL, NULL, NULL);
483 log_error("Failed to verify GPT partition: %s", strerror(-r));
489 r = enumerate_partitions(dev);
491 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;