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"
48 * - Properly handle cryptsetup partitions
49 * - Define new partition type for encrypted swap
50 * - Make /home automount rather than mount
54 static const char *arg_dest = "/tmp";
56 DEFINE_TRIVIAL_CLEANUP_FUNC(blkid_probe, blkid_free_probe);
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);
76 if (r == -2 || r == 1) /* no result or uncertain */
79 return errno ? -errno : -EIO;
82 r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL);
84 /* return 0 if we're not on GPT */
85 return errno ? -errno : 0;
87 if (strcmp(v, "gpt") != 0)
92 r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
94 return errno ? -errno : -EIO;
96 r = sd_id128_from_string(v, type);
103 r = blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL);
105 return errno ? -errno : -EIO;
107 r = safe_atou(v, nr);
115 r = blkid_probe_lookup_value(b, "TYPE", &v, NULL);
132 static int add_swap(const char *path, const char *fstype) {
133 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
134 _cleanup_fclose_ FILE *f = NULL;
136 log_debug("Adding swap: %s %s", path, fstype);
138 name = unit_name_from_path(path, ".swap");
142 unit = strjoin(arg_dest, "/", name, NULL);
146 f = fopen(unit, "wxe");
148 log_error("Failed to create unit file %s: %m", unit);
153 "# Automatically generated by systemd-gpt-auto-generator\n\n"
160 log_error("Failed to write unit file %s: %m", unit);
164 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
168 mkdir_parents_label(lnk, 0755);
169 if (symlink(unit, lnk) < 0) {
170 log_error("Failed to create symlink %s: %m", lnk);
177 static int add_mount(const char *what, const char *where, const char *fstype, const char *description) {
178 _cleanup_free_ char *unit = NULL, *lnk = NULL, *p = NULL;
179 _cleanup_fclose_ FILE *f = NULL;
182 if (dir_is_empty(where) <= 0) {
183 log_debug("%s already populated, ignoring.", where);
187 log_debug("Adding %s: %s %s", where, what, fstype);
189 unit = unit_name_from_path(where, ".mount");
193 p = strjoin(arg_dest, "/", unit, NULL);
199 log_error("Failed to create unit file %s: %m", unit);
204 "# Automatically generated by systemd-gpt-auto-generator\n\n"
209 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
219 what, where, fstype);
223 log_error("Failed to write unit file %s: %m", unit);
227 lnk = strjoin(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".requires/", unit, 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(struct udev *udev, dev_t dev) {
241 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
242 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
243 _cleanup_free_ char *home = NULL, *home_fstype = NULL, *srv = NULL, *srv_fstype = NULL;
244 unsigned home_nr = (unsigned) -1, srv_nr = (unsigned )-1;
245 struct udev_list_entry *first, *item;
246 struct udev_device *parent = NULL;
249 e = udev_enumerate_new(udev);
253 d = udev_device_new_from_devnum(udev, 'b', dev);
257 parent = udev_device_get_parent(d);
261 r = udev_enumerate_add_match_parent(e, parent);
265 r = udev_enumerate_add_match_subsystem(e, "block");
269 r = udev_enumerate_scan_devices(e);
271 log_error("Failed to enumerate partitions on /dev/block/%u:%u: %s", major(dev), minor(dev), strerror(-r));
275 first = udev_enumerate_get_list_entry(e);
276 udev_list_entry_foreach(item, first) {
277 _cleanup_udev_device_unref_ struct udev_device *q;
278 _cleanup_free_ char *fstype = NULL;
279 const char *node = NULL;
283 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
287 if (udev_device_get_devnum(q) == udev_device_get_devnum(d))
290 if (udev_device_get_devnum(q) == udev_device_get_devnum(parent))
293 node = udev_device_get_devnode(q);
297 r = verify_gpt_partition(node, &type_id, &nr, &fstype);
299 /* skip child devices which are not detected properly */
302 log_error("Failed to verify GPT partition %s: %s", node, strerror(-r));
308 if (sd_id128_equal(type_id, GPT_SWAP))
309 add_swap(node, fstype);
311 else if (sd_id128_equal(type_id, GPT_HOME)) {
313 /* We only care for the first /home partition */
314 if (home && nr >= home_nr)
325 home_fstype = fstype;
328 } else if (sd_id128_equal(type_id, GPT_SRV)) {
330 /* We only care for the first /srv partition */
331 if (srv && nr >= srv_nr)
347 if (home && home_fstype)
348 add_mount(home, "/home", home_fstype, "Home Partition");
350 if (srv && srv_fstype)
351 add_mount(srv, "/srv", srv_fstype, "Server Data Partition");
356 static int get_btrfs_block_device(const char *path, dev_t *dev) {
357 struct btrfs_ioctl_fs_info_args fsi = {};
358 _cleanup_close_ int fd = -1;
364 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 = {
381 if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
388 if (stat((char*) di.path, &st) < 0)
391 if (!S_ISBLK(st.st_mode))
394 if (major(st.st_rdev) == 0)
404 static int get_block_device(const char *path, dev_t *dev) {
411 if (lstat(path, &st))
414 if (major(st.st_dev) != 0) {
419 if (statfs(path, &sfs) < 0)
422 if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
423 return get_btrfs_block_device(path, dev);
428 static int devno_to_devnode(struct udev *udev, dev_t devno, char **ret) {
429 _cleanup_udev_device_unref_ struct udev_device *d;
433 d = udev_device_new_from_devnum(udev, 'b', devno);
437 t = udev_device_get_devnode(d);
449 int main(int argc, char *argv[]) {
450 _cleanup_udev_unref_ struct udev *udev = NULL;
451 _cleanup_free_ char *node = NULL;
455 if (argc > 1 && argc != 4) {
456 log_error("This program takes three or no arguments.");
463 log_set_target(LOG_TARGET_SAFE);
464 log_parse_environment();
470 log_debug("In initrd, exiting.");
474 if (detect_container(NULL) > 0) {
475 log_debug("In a container, exiting.");
479 r = get_block_device("/", &devno);
481 log_error("Failed to determine block device of root file system: %s", strerror(-r));
484 log_debug("Root file system not on a (single) block device.");
494 r = devno_to_devnode(udev, devno, &node);
496 log_error("Failed to determine block device node from major/minor: %s", strerror(-r));
500 log_debug("Root device %s.", node);
502 r = verify_gpt_partition(node, NULL, NULL, NULL);
504 log_error("Failed to verify GPT partition %s: %s", node, strerror(-r));
508 log_debug("Not a GPT disk, exiting.");
512 r = enumerate_partitions(udev, devno);