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"
44 * - Properly handle cryptsetup partitions
45 * - Define new partition type for encrypted swap
46 * - Make /home automount rather than mount
50 static const char *arg_dest = "/tmp";
52 static inline void blkid_free_probep(blkid_probe *b) {
56 #define _cleanup_blkid_freep_probe_ _cleanup_(blkid_free_probep)
58 static int verify_gpt_partition(dev_t dev, sd_id128_t *type, unsigned *nr, char **fstype) {
59 _cleanup_free_ char *t = NULL;
60 _cleanup_blkid_freep_probe_ blkid_probe b = NULL;
64 r = asprintf(&t, "/dev/block/%u:%u", major(dev), minor(dev));
69 b = blkid_new_probe_from_filename(t);
71 return errno != 0 ? -errno : -ENOMEM;
73 blkid_probe_enable_superblocks(b, 1);
74 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
75 blkid_probe_enable_partitions(b, 1);
76 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
79 r = blkid_do_safeprobe(b);
85 return errno ? -errno : -EIO;
88 r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL);
90 /* return 0 if we're not on GPT */
91 return errno ? -errno : 0;
93 if (strcmp(v, "gpt") != 0)
98 r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
100 return errno ? -errno : -EIO;
102 r = sd_id128_from_string(v, type);
109 r = blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL);
111 return errno ? -errno : -EIO;
113 r = safe_atou(v, nr);
123 r = blkid_probe_lookup_value(b, "TYPE", &v, NULL);
138 static int add_swap(const char *path, const char *fstype) {
139 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
140 _cleanup_fclose_ FILE *f = NULL;
142 log_debug("Adding swap: %s %s", path, fstype);
144 name = unit_name_from_path(path, ".swap");
148 unit = strjoin(arg_dest, "/", name, NULL);
152 f = fopen(unit, "wxe");
154 log_error("Failed to create unit file %s: %m", unit);
159 "# Automatically generated by systemd-gpt-auto-generator\n\n"
161 "DefaultDependencies=no\n"
162 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
163 "Before=" SPECIAL_UMOUNT_TARGET " " SPECIAL_SWAP_TARGET "\n\n"
170 log_error("Failed to write unit file %s: %m", unit);
174 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
178 mkdir_parents_label(lnk, 0755);
179 if (symlink(unit, lnk) < 0) {
180 log_error("Failed to create symlink %s: %m", lnk);
187 static int add_home(const char *path, const char *fstype) {
188 _cleanup_free_ char *unit = NULL, *lnk = NULL;
189 _cleanup_fclose_ FILE *f = NULL;
191 if (dir_is_empty("/home") <= 0)
194 log_debug("Adding home: %s %s", path, fstype);
196 unit = strappend(arg_dest, "/home.mount");
200 f = fopen(unit, "wxe");
202 log_error("Failed to create unit file %s: %m", unit);
207 "# Automatically generated by systemd-gpt-auto-generator\n\n"
209 "DefaultDependencies=no\n"
210 "After=" SPECIAL_LOCAL_FS_PRE_TARGET "\n"
211 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
212 "Before=" SPECIAL_UMOUNT_TARGET " " SPECIAL_LOCAL_FS_TARGET "\n\n"
222 log_error("Failed to write unit file %s: %m", unit);
226 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(dev_t dev) {
242 struct udev_enumerate *e = NULL;
243 struct udev_device *parent = NULL, *d = NULL;
244 struct udev_list_entry *first, *item;
245 unsigned home_nr = (unsigned) -1;
246 _cleanup_free_ char *home = NULL, *home_fstype = NULL;
253 e = udev_enumerate_new(udev);
259 d = udev_device_new_from_devnum(udev, 'b', dev);
265 parent = udev_device_get_parent(d);
271 r = udev_enumerate_add_match_parent(e, parent);
277 r = udev_enumerate_add_match_subsystem(e, "block");
283 r = udev_enumerate_scan_devices(e);
285 log_error("Failed to enumerate partitions on /dev/block/%u:%u: %s",
286 major(dev), minor(dev), strerror(-r));
290 first = udev_enumerate_get_list_entry(e);
291 udev_list_entry_foreach(item, first) {
292 _cleanup_free_ char *fstype = NULL;
293 const char *node = NULL;
294 struct udev_device *q;
299 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
305 if (udev_device_get_devnum(q) == udev_device_get_devnum(d))
308 if (udev_device_get_devnum(q) == udev_device_get_devnum(parent))
311 node = udev_device_get_devnode(q);
317 sub = udev_device_get_devnum(q);
319 r = verify_gpt_partition(sub, &type_id, &nr, &fstype);
321 log_error("Failed to verify GPT partition /dev/block/%u:%u: %s",
322 major(sub), minor(sub), strerror(-r));
323 udev_device_unref(q);
329 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)))
330 add_swap(node, fstype);
331 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))) {
333 if (!home || nr < home_nr) {
344 home_fstype = fstype;
350 udev_device_unref(q);
353 if (home && home_fstype)
354 add_home(home, home_fstype);
358 udev_device_unref(d);
361 udev_enumerate_unref(e);
369 static int get_btrfs_block_device(const char *path, dev_t *dev) {
370 struct btrfs_ioctl_fs_info_args fsi;
371 _cleanup_close_ int fd = -1;
377 fd = open(path, O_DIRECTORY|O_CLOEXEC);
382 if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
385 /* We won't do this for btrfs RAID */
386 if (fsi.num_devices != 1)
389 for (id = 1; id <= fsi.max_id; id++) {
390 struct btrfs_ioctl_dev_info_args di;
396 if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
403 if (stat((char*) di.path, &st) < 0)
406 if (!S_ISBLK(st.st_mode))
409 if (major(st.st_rdev) == 0)
419 static int get_block_device(const char *path, dev_t *dev) {
429 if (major(st.st_dev) != 0) {
434 if (statfs("/", &sfs) < 0)
437 if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
438 return get_btrfs_block_device(path, dev);
443 int main(int argc, char *argv[]) {
447 if (argc > 1 && argc != 4) {
448 log_error("This program takes three or no arguments.");
455 log_set_target(LOG_TARGET_SAFE);
456 log_parse_environment();
464 r = get_block_device("/", &dev);
466 log_error("Failed to determine block device of root file system: %s", strerror(-r));
470 log_debug("Root file system not on a (single) block device.");
474 log_debug("Root device /dev/block/%u:%u.", major(dev), minor(dev));
476 r = verify_gpt_partition(dev, NULL, NULL, NULL);
478 log_error("Failed to verify GPT partition /dev/block/%u:%u: %s",
479 major(dev), minor(dev), strerror(-r));
485 r = enumerate_partitions(dev);
487 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;