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
43 * - Make /home automount rather than mount
47 static const char *arg_dest = "/tmp";
49 static int verify_gpt_partition(dev_t dev, sd_id128_t *type, unsigned *nr, char **fstype) {
50 _cleanup_free_ char *t = NULL;
55 r = asprintf(&t, "/dev/block/%u:%u", major(dev), minor(dev));
60 b = blkid_new_probe_from_filename(t);
68 blkid_probe_enable_superblocks(b, 1);
69 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
70 blkid_probe_enable_partitions(b, 1);
71 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
74 r = blkid_do_safeprobe(b);
82 r = errno ? -errno : -EIO;
87 r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL);
89 r = errno ? -errno : -EIO;
93 if (strcmp(v, "gpt") != 0) {
100 r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
102 r = errno ? -errno : -EIO;
106 r = sd_id128_from_string(v, type);
113 r = blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL);
115 r = errno ? -errno : -EIO;
119 r = safe_atou(v, nr);
129 r = blkid_probe_lookup_value(b, "TYPE", &v, NULL);
152 static int add_swap(const char *path, const char *fstype) {
153 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
154 _cleanup_fclose_ FILE *f = NULL;
156 log_debug("Adding swap: %s %s", path, fstype);
158 name = unit_name_from_path(path, ".swap");
162 unit = strjoin(arg_dest, "/", name, NULL);
166 f = fopen(unit, "wxe");
168 log_error("Failed to create unit file %s: %m", unit);
173 "# Automatically generated by systemd-gpt-auto-generator\n\n"
175 "DefaultDependencies=no\n"
176 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
177 "Before=" SPECIAL_UMOUNT_TARGET " " SPECIAL_SWAP_TARGET "\n\n"
184 log_error("Failed to write unit file %s: %m", unit);
188 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
192 mkdir_parents_label(lnk, 0755);
193 if (symlink(unit, lnk) < 0) {
194 log_error("Failed to create symlink %s: %m", lnk);
201 static int add_home(const char *path, const char *fstype) {
202 _cleanup_free_ char *unit = NULL, *lnk = NULL;
203 _cleanup_fclose_ FILE *f = NULL;
205 if (dir_is_empty("/home") <= 0)
208 log_debug("Adding home: %s %s", path, fstype);
210 unit = strappend(arg_dest, "/home.mount");
214 f = fopen(unit, "wxe");
216 log_error("Failed to create unit file %s: %m", unit);
221 "# Automatically generated by systemd-gpt-auto-generator\n\n"
223 "DefaultDependencies=no\n"
224 "After=" SPECIAL_LOCAL_FS_PRE_TARGET "\n"
225 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
226 "Before=" SPECIAL_UMOUNT_TARGET " " SPECIAL_LOCAL_FS_TARGET "\n\n"
236 log_error("Failed to write unit file %s: %m", unit);
240 lnk = strjoin(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".requires/home.mount", NULL);
245 mkdir_parents_label(lnk, 0755);
246 if (symlink(unit, lnk) < 0) {
247 log_error("Failed to create symlink %s: %m", lnk);
254 static int enumerate_partitions(dev_t dev) {
256 struct udev_enumerate *e = NULL;
257 struct udev_device *parent = NULL, *d = NULL;
258 struct udev_list_entry *first, *item;
259 unsigned home_nr = (unsigned) -1;
260 _cleanup_free_ char *home = NULL, *home_fstype = NULL;
267 e = udev_enumerate_new(udev);
273 d = udev_device_new_from_devnum(udev, 'b', dev);
279 parent = udev_device_get_parent(d);
285 r = udev_enumerate_add_match_parent(e, parent);
291 r = udev_enumerate_add_match_subsystem(e, "block");
297 r = udev_enumerate_scan_devices(e);
299 log_error("Failed to enumerate partitions: %s", strerror(-r));
303 first = udev_enumerate_get_list_entry(e);
304 udev_list_entry_foreach(item, first) {
305 _cleanup_free_ char *fstype = NULL;
306 const char *node = NULL;
307 struct udev_device *q;
311 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
317 if (udev_device_get_devnum(q) == udev_device_get_devnum(d))
320 if (udev_device_get_devnum(q) == udev_device_get_devnum(parent))
323 node = udev_device_get_devnode(q);
329 r = verify_gpt_partition(udev_device_get_devnum(q), &type_id, &nr, &fstype);
331 log_error("Failed to verify GPT partition: %s", strerror(-r));
332 udev_device_unref(q);
338 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)))
339 add_swap(node, fstype);
340 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))) {
342 if (!home || nr < home_nr) {
353 home_fstype = fstype;
359 udev_device_unref(q);
362 if (home && home_fstype)
363 add_home(home, home_fstype);
367 udev_device_unref(d);
370 udev_enumerate_unref(e);
378 static int get_btrfs_block_device(const char *path, dev_t *dev) {
379 struct btrfs_ioctl_fs_info_args fsi;
380 _cleanup_close_ int fd = -1;
386 fd = open(path, O_DIRECTORY|O_CLOEXEC);
391 if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
394 /* We won't do this for btrfs RAID */
395 if (fsi.num_devices != 1)
398 for (id = 1; id <= fsi.max_id; id++) {
399 struct btrfs_ioctl_dev_info_args di;
405 if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
412 if (stat((char*) di.path, &st) < 0)
415 if (!S_ISBLK(st.st_mode))
418 if (major(st.st_rdev) == 0)
428 static int get_block_device(const char *path, dev_t *dev) {
438 if (major(st.st_dev) != 0) {
443 if (statfs("/", &sfs) < 0)
446 if (F_TYPE_CMP(sfs.f_type, BTRFS_SUPER_MAGIC))
447 return get_btrfs_block_device(path, dev);
452 int main(int argc, char *argv[]) {
456 if (argc > 1 && argc != 4) {
457 log_error("This program takes three or no arguments.");
464 log_set_target(LOG_TARGET_SAFE);
465 log_parse_environment();
473 r = get_block_device("/", &dev);
475 log_error("Failed to determine block device of root file system: %s", strerror(-r));
479 log_debug("Root file system not on a (single) block device.");
483 log_debug("Root device %u:%u.", major(dev), minor(dev));
485 r = verify_gpt_partition(dev, NULL, NULL, NULL);
487 log_error("Failed to verify GPT partition: %s", strerror(-r));
493 r = enumerate_partitions(dev);
495 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;