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"
43 #include "generator.h"
46 static const char *arg_dest = "/tmp";
48 DEFINE_TRIVIAL_CLEANUP_FUNC(blkid_probe, blkid_free_probe);
49 #define _cleanup_blkid_freep_probe_ _cleanup_(blkid_free_probep)
51 static int verify_gpt_partition(const char *node, sd_id128_t *type, unsigned *nr, char **fstype) {
52 _cleanup_blkid_freep_probe_ blkid_probe b = NULL;
57 b = blkid_new_probe_from_filename(node);
59 return errno != 0 ? -errno : -ENOMEM;
61 blkid_probe_enable_superblocks(b, 1);
62 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
63 blkid_probe_enable_partitions(b, 1);
64 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
67 r = blkid_do_safeprobe(b);
68 if (r == -2 || r == 1) /* no result or uncertain */
71 return errno ? -errno : -EIO;
74 r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL);
76 /* return 0 if we're not on GPT */
77 return errno ? -errno : 0;
79 if (strcmp(v, "gpt") != 0)
84 r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
86 return errno ? -errno : -EIO;
88 r = sd_id128_from_string(v, type);
95 r = blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL);
97 return errno ? -errno : -EIO;
107 r = blkid_probe_lookup_value(b, "TYPE", &v, NULL);
124 static int add_swap(const char *path, const char *fstype) {
125 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
126 _cleanup_fclose_ FILE *f = NULL;
128 log_debug("Adding swap: %s %s", path, fstype);
130 name = unit_name_from_path(path, ".swap");
134 unit = strjoin(arg_dest, "/", name, NULL);
138 f = fopen(unit, "wxe");
140 log_error("Failed to create unit file %s: %m", unit);
145 "# Automatically generated by systemd-gpt-auto-generator\n\n"
152 log_error("Failed to write unit file %s: %m", unit);
156 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
160 mkdir_parents_label(lnk, 0755);
161 if (symlink(unit, lnk) < 0) {
162 log_error("Failed to create symlink %s: %m", lnk);
169 static int add_mount(const char *what, const char *where, const char *fstype, const char *description) {
170 _cleanup_free_ char *unit = NULL, *lnk = NULL, *p = NULL;
171 _cleanup_fclose_ FILE *f = NULL;
174 if (dir_is_empty(where) <= 0) {
175 log_debug("%s already populated, ignoring.", where);
179 log_debug("Adding %s: %s %s", where, what, fstype);
181 unit = unit_name_from_path(where, ".mount");
185 p = strjoin(arg_dest, "/", unit, NULL);
191 log_error("Failed to create unit file %s: %m", unit);
196 "# Automatically generated by systemd-gpt-auto-generator\n\n"
201 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
211 what, where, fstype);
215 log_error("Failed to write unit file %s: %m", unit);
219 lnk = strjoin(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".requires/", unit, NULL);
223 mkdir_parents_label(lnk, 0755);
224 if (symlink(unit, lnk) < 0) {
225 log_error("Failed to create symlink %s: %m", lnk);
232 static int enumerate_partitions(struct udev *udev, dev_t dev) {
233 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
234 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
235 _cleanup_free_ char *home = NULL, *home_fstype = NULL, *srv = NULL, *srv_fstype = NULL;
236 unsigned home_nr = (unsigned) -1, srv_nr = (unsigned )-1;
237 struct udev_list_entry *first, *item;
238 struct udev_device *parent = NULL;
241 e = udev_enumerate_new(udev);
245 d = udev_device_new_from_devnum(udev, 'b', dev);
249 parent = udev_device_get_parent(d);
253 r = udev_enumerate_add_match_parent(e, parent);
257 r = udev_enumerate_add_match_subsystem(e, "block");
261 r = udev_enumerate_scan_devices(e);
263 log_error("Failed to enumerate partitions on /dev/block/%u:%u: %s", major(dev), minor(dev), strerror(-r));
267 first = udev_enumerate_get_list_entry(e);
268 udev_list_entry_foreach(item, first) {
269 _cleanup_udev_device_unref_ struct udev_device *q;
270 _cleanup_free_ char *fstype = NULL;
271 const char *node = NULL;
275 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
279 if (udev_device_get_devnum(q) == udev_device_get_devnum(d))
282 if (udev_device_get_devnum(q) == udev_device_get_devnum(parent))
285 node = udev_device_get_devnode(q);
289 r = verify_gpt_partition(node, &type_id, &nr, &fstype);
291 /* skip child devices which are not detected properly */
294 log_error("Failed to verify GPT partition %s: %s", node, strerror(-r));
300 if (sd_id128_equal(type_id, GPT_SWAP))
301 add_swap(node, fstype);
303 else if (sd_id128_equal(type_id, GPT_HOME)) {
305 /* We only care for the first /home partition */
306 if (home && nr >= home_nr)
317 home_fstype = fstype;
320 } else if (sd_id128_equal(type_id, GPT_SRV)) {
322 /* We only care for the first /srv partition */
323 if (srv && nr >= srv_nr)
339 if (home && home_fstype)
340 add_mount(home, "/home", home_fstype, "Home Partition");
342 if (srv && srv_fstype)
343 add_mount(srv, "/srv", srv_fstype, "Server Data Partition");
348 static int get_btrfs_block_device(const char *path, dev_t *dev) {
349 struct btrfs_ioctl_fs_info_args fsi = {};
350 _cleanup_close_ int fd = -1;
356 fd = open(path, O_DIRECTORY|O_CLOEXEC);
360 if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
363 /* We won't do this for btrfs RAID */
364 if (fsi.num_devices != 1)
367 for (id = 1; id <= fsi.max_id; id++) {
368 struct btrfs_ioctl_dev_info_args di = {
373 if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
380 if (stat((char*) di.path, &st) < 0)
383 if (!S_ISBLK(st.st_mode))
386 if (major(st.st_rdev) == 0)
396 static int get_block_device(const char *path, dev_t *dev) {
403 if (lstat(path, &st))
406 if (major(st.st_dev) != 0) {
411 if (statfs(path, &sfs) < 0)
414 if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
415 return get_btrfs_block_device(path, dev);
420 static int devno_to_devnode(struct udev *udev, dev_t devno, char **ret) {
421 _cleanup_udev_device_unref_ struct udev_device *d;
425 d = udev_device_new_from_devnum(udev, 'b', devno);
429 t = udev_device_get_devnode(d);
441 int main(int argc, char *argv[]) {
442 _cleanup_udev_unref_ struct udev *udev = NULL;
443 _cleanup_free_ char *node = NULL;
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();
462 log_debug("In initrd, exiting.");
466 if (detect_container(NULL) > 0) {
467 log_debug("In a container, exiting.");
471 r = get_block_device("/", &devno);
473 log_error("Failed to determine block device of root file system: %s", strerror(-r));
476 log_debug("Root file system not on a (single) block device.");
486 r = devno_to_devnode(udev, devno, &node);
488 log_error("Failed to determine block device node from major/minor: %s", strerror(-r));
492 log_debug("Root device %s.", node);
494 r = verify_gpt_partition(node, NULL, NULL, NULL);
496 log_error("Failed to verify GPT partition %s: %s", node, strerror(-r));
500 log_debug("Not a GPT disk, exiting.");
504 r = enumerate_partitions(udev, devno);