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(const char *node, sd_id128_t *type, unsigned *nr, char **fstype) {
59 _cleanup_blkid_freep_probe_ blkid_probe b = NULL;
64 b = blkid_new_probe_from_filename(node);
66 return errno != 0 ? -errno : -ENOMEM;
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);
80 return errno ? -errno : -EIO;
83 r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL);
85 /* return 0 if we're not on GPT */
86 return errno ? -errno : 0;
88 if (strcmp(v, "gpt") != 0)
93 r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
95 return errno ? -errno : -EIO;
97 r = sd_id128_from_string(v, type);
104 r = blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL);
106 return errno ? -errno : -EIO;
108 r = safe_atou(v, nr);
118 r = blkid_probe_lookup_value(b, "TYPE", &v, NULL);
133 static int add_swap(const char *path, const char *fstype) {
134 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
135 _cleanup_fclose_ FILE *f = NULL;
137 log_debug("Adding swap: %s %s", path, fstype);
139 name = unit_name_from_path(path, ".swap");
143 unit = strjoin(arg_dest, "/", name, NULL);
147 f = fopen(unit, "wxe");
149 log_error("Failed to create unit file %s: %m", unit);
154 "# Automatically generated by systemd-gpt-auto-generator\n\n"
156 "DefaultDependencies=no\n"
157 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
158 "Before=" SPECIAL_UMOUNT_TARGET " " SPECIAL_SWAP_TARGET "\n\n"
165 log_error("Failed to write unit file %s: %m", unit);
169 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
173 mkdir_parents_label(lnk, 0755);
174 if (symlink(unit, lnk) < 0) {
175 log_error("Failed to create symlink %s: %m", lnk);
182 static int add_home(const char *path, const char *fstype) {
183 _cleanup_free_ char *unit = NULL, *lnk = NULL;
184 _cleanup_fclose_ FILE *f = NULL;
186 if (dir_is_empty("/home") <= 0)
189 log_debug("Adding home: %s %s", path, fstype);
191 unit = strappend(arg_dest, "/home.mount");
195 f = fopen(unit, "wxe");
197 log_error("Failed to create unit file %s: %m", unit);
202 "# Automatically generated by systemd-gpt-auto-generator\n\n"
204 "DefaultDependencies=no\n"
205 "After=" SPECIAL_LOCAL_FS_PRE_TARGET "\n"
206 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
207 "Before=" SPECIAL_UMOUNT_TARGET " " SPECIAL_LOCAL_FS_TARGET "\n\n"
217 log_error("Failed to write unit file %s: %m", unit);
221 lnk = strjoin(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".requires/home.mount", NULL);
226 mkdir_parents_label(lnk, 0755);
227 if (symlink(unit, lnk) < 0) {
228 log_error("Failed to create symlink %s: %m", lnk);
235 static int enumerate_partitions(struct udev *udev, dev_t dev) {
236 struct udev_enumerate *e = NULL;
237 struct udev_device *parent = NULL, *d = NULL;
238 struct udev_list_entry *first, *item;
239 unsigned home_nr = (unsigned) -1;
240 _cleanup_free_ char *home = NULL, *home_fstype = NULL;
243 e = udev_enumerate_new(udev);
249 d = udev_device_new_from_devnum(udev, 'b', dev);
255 parent = udev_device_get_parent(d);
261 r = udev_enumerate_add_match_parent(e, parent);
267 r = udev_enumerate_add_match_subsystem(e, "block");
273 r = udev_enumerate_scan_devices(e);
275 log_error("Failed to enumerate partitions on /dev/block/%u:%u: %s",
276 major(dev), minor(dev), strerror(-r));
280 first = udev_enumerate_get_list_entry(e);
281 udev_list_entry_foreach(item, first) {
282 _cleanup_free_ char *fstype = NULL;
283 const char *node = NULL;
284 struct udev_device *q;
288 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
294 if (udev_device_get_devnum(q) == udev_device_get_devnum(d))
297 if (udev_device_get_devnum(q) == udev_device_get_devnum(parent))
300 node = udev_device_get_devnode(q);
306 r = verify_gpt_partition(node, &type_id, &nr, &fstype);
308 log_error("Failed to verify GPT partition %s: %s",
310 udev_device_unref(q);
316 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)))
317 add_swap(node, fstype);
318 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))) {
320 if (!home || nr < home_nr) {
331 home_fstype = fstype;
337 udev_device_unref(q);
340 if (home && home_fstype)
341 add_home(home, home_fstype);
345 udev_device_unref(d);
348 udev_enumerate_unref(e);
354 static int get_btrfs_block_device(const char *path, dev_t *dev) {
355 struct btrfs_ioctl_fs_info_args fsi;
356 _cleanup_close_ int fd = -1;
362 fd = open(path, O_DIRECTORY|O_CLOEXEC);
367 if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
370 /* We won't do this for btrfs RAID */
371 if (fsi.num_devices != 1)
374 for (id = 1; id <= fsi.max_id; id++) {
375 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) {
414 if (major(st.st_dev) != 0) {
419 if (statfs("/", &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 struct udev_device *d = NULL;
434 d = udev_device_new_from_devnum(udev, 'b', devno);
440 t = udev_device_get_devnode(d);
457 udev_device_unref(d);
462 int main(int argc, char *argv[]) {
463 _cleanup_free_ char *node = NULL;
464 struct udev *udev = NULL;
468 if (argc > 1 && argc != 4) {
469 log_error("This program takes three or no arguments.");
477 log_set_target(LOG_TARGET_SAFE);
478 log_parse_environment();
488 r = get_block_device("/", &devno);
490 log_error("Failed to determine block device of root file system: %s", strerror(-r));
494 log_debug("Root file system not on a (single) block device.");
504 r = devno_to_devnode(udev, devno, &node);
506 log_error("Failed to determine block device node from major/minor: %s", strerror(-r));
510 log_debug("Root device %s.", node);
512 r = verify_gpt_partition(node, NULL, NULL, NULL);
514 log_error("Failed to verify GPT partition %s: %s", node, strerror(-r));
520 r = enumerate_partitions(udev, devno);
526 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;