gpt-auto-generator.c revision 9a5cb1371b6d8b0a04bd08665bcf9b06cb40c64c
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen/***
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen This file is part of systemd.
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen Copyright 2013 Lennart Poettering
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen systemd is free software; you can redistribute it and/or modify it
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen under the terms of the GNU Lesser General Public License as published by
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen the Free Software Foundation; either version 2.1 of the License, or
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen (at your option) any later version.
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen systemd is distributed in the hope that it will be useful, but
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen Lesser General Public License for more details.
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen You should have received a copy of the GNU Lesser General Public License
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen***/
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen#include <unistd.h>
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen#include <stdlib.h>
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen#include <fcntl.h>
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen#include <sys/ioctl.h>
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen#include <sys/statfs.h>
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen#include <blkid.h>
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen#ifdef HAVE_LINUX_BTRFS_H
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen#include <linux/btrfs.h>
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen#endif
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen#include "path-util.h"
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen#include "util.h"
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen#include "mkdir.h"
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen#include "missing.h"
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen#include "sd-id128.h"
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen#include "libudev.h"
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen#include "special.h"
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen#include "unit-name.h"
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen#include "virt.h"
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen/* TODO:
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen *
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen * - Properly handle cryptsetup partitions
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen * - Define new partition type for encrypted swap
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen * - Make /home automount rather than mount
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen *
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen */
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersenstatic const char *arg_dest = "/tmp";
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersenstatic inline void blkid_free_probep(blkid_probe *b) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (*b)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen blkid_free_probe(*b);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen}
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen#define _cleanup_blkid_freep_probe_ _cleanup_(blkid_free_probep)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersenstatic int verify_gpt_partition(const char *node, sd_id128_t *type, unsigned *nr, char **fstype) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen _cleanup_blkid_freep_probe_ blkid_probe b = NULL;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen const char *v;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen int r;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen errno = 0;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen b = blkid_new_probe_from_filename(node);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (!b)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return errno != 0 ? -errno : -ENOMEM;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen blkid_probe_enable_superblocks(b, 1);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen blkid_probe_enable_partitions(b, 1);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen errno = 0;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen r = blkid_do_safeprobe(b);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (r == -2)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return -ENODEV;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen else if (r == 1)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return -ENODEV;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen else if (r != 0)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return errno ? -errno : -EIO;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen errno = 0;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (r != 0)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen /* return 0 if we're not on GPT */
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return errno ? -errno : 0;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (strcmp(v, "gpt") != 0)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return 0;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (type) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen errno = 0;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (r != 0)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return errno ? -errno : -EIO;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen r = sd_id128_from_string(v, type);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (r < 0)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return r;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen }
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (nr) {
987d561fe202568c0a2880cf047c7833fd365c7aLennart Poettering errno = 0;
987d561fe202568c0a2880cf047c7833fd365c7aLennart Poettering r = blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL);
987d561fe202568c0a2880cf047c7833fd365c7aLennart Poettering if (r != 0)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return errno ? -errno : -EIO;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen r = safe_atou(v, nr);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (r < 0)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return r;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen }
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (fstype) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen char *fst;
c92e531c82a9815ec349aa1bf31236b86b2d5311Lennart Poettering
c92e531c82a9815ec349aa1bf31236b86b2d5311Lennart Poettering errno = 0;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen r = blkid_probe_lookup_value(b, "TYPE", &v, NULL);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (r != 0)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen *fstype = NULL;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen else {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen fst = strdup(v);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (!fst)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return -ENOMEM;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen *fstype = fst;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen }
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen }
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return 1;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen}
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersenstatic int add_swap(const char *path, const char *fstype) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen _cleanup_fclose_ FILE *f = NULL;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen log_debug("Adding swap: %s %s", path, fstype);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen name = unit_name_from_path(path, ".swap");
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (!name)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return log_oom();
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen unit = strjoin(arg_dest, "/", name, NULL);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (!unit)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return log_oom();
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen f = fopen(unit, "wxe");
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (!f) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen log_error("Failed to create unit file %s: %m", unit);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return -errno;
096b6773886bd7a0c8c97aa684b0b67dfae58355Lennart Poettering }
096b6773886bd7a0c8c97aa684b0b67dfae58355Lennart Poettering
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen fprintf(f,
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen "# Automatically generated by systemd-gpt-auto-generator\n\n"
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen "[Unit]\n"
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen "DefaultDependencies=no\n"
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen "Before=" SPECIAL_UMOUNT_TARGET " " SPECIAL_SWAP_TARGET "\n\n"
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen "[Swap]\n"
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen "What=%s\n",
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen path);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen fflush(f);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (ferror(f)) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen log_error("Failed to write unit file %s: %m", unit);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return -errno;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen }
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (!lnk)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return log_oom();
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen mkdir_parents_label(lnk, 0755);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (symlink(unit, lnk) < 0) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen log_error("Failed to create symlink %s: %m", lnk);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return -errno;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen }
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return 0;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen}
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersenstatic int add_home(const char *path, const char *fstype) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen _cleanup_free_ char *unit = NULL, *lnk = NULL;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen _cleanup_fclose_ FILE *f = NULL;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (dir_is_empty("/home") <= 0)
b686acb27ea4de042320fa196cfb14e08f30165bTom Gundersen return 0;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen log_debug("Adding home: %s %s", path, fstype);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen unit = strappend(arg_dest, "/home.mount");
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (!unit)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return log_oom();
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen f = fopen(unit, "wxe");
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (!f) {
b686acb27ea4de042320fa196cfb14e08f30165bTom Gundersen log_error("Failed to create unit file %s: %m", unit);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return -errno;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen }
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen fprintf(f,
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen "# Automatically generated by systemd-gpt-auto-generator\n\n"
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen "[Unit]\n"
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen "DefaultDependencies=no\n"
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen "After=" SPECIAL_LOCAL_FS_PRE_TARGET "\n"
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen "Before=" SPECIAL_UMOUNT_TARGET " " SPECIAL_LOCAL_FS_TARGET "\n\n"
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen "[Mount]\n"
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen "What=%s\n"
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen "Where=/home\n"
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen "Type=%s\n"
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen "FsckPassNo=2\n",
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen path, fstype);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen fflush(f);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (ferror(f)) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen log_error("Failed to write unit file %s: %m", unit);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return -errno;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen }
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen lnk = strjoin(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".requires/home.mount", NULL);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (!lnk)
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return log_oom();
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen mkdir_parents_label(lnk, 0755);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (symlink(unit, lnk) < 0) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen log_error("Failed to create symlink %s: %m", lnk);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return -errno;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen }
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen return 0;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen}
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersenstatic int enumerate_partitions(struct udev *udev, dev_t dev) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen struct udev_enumerate *e = NULL;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen struct udev_device *parent = NULL, *d = NULL;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen struct udev_list_entry *first, *item;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen unsigned home_nr = (unsigned) -1;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen _cleanup_free_ char *home = NULL, *home_fstype = NULL;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen int r;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen e = udev_enumerate_new(udev);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (!e) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen r = log_oom();
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen goto finish;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen }
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen d = udev_device_new_from_devnum(udev, 'b', dev);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (!d) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen r = log_oom();
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen goto finish;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen }
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen parent = udev_device_get_parent(d);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (!parent) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen r = log_oom();
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen goto finish;
b686acb27ea4de042320fa196cfb14e08f30165bTom Gundersen }
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
b686acb27ea4de042320fa196cfb14e08f30165bTom Gundersen r = udev_enumerate_add_match_parent(e, parent);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (r < 0) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen r = log_oom();
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen goto finish;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen }
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen r = udev_enumerate_add_match_subsystem(e, "block");
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (r < 0) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen r = log_oom();
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen goto finish;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen }
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen r = udev_enumerate_scan_devices(e);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (r < 0) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen log_error("Failed to enumerate partitions on /dev/block/%u:%u: %s",
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen major(dev), minor(dev), strerror(-r));
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen goto finish;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen }
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen first = udev_enumerate_get_list_entry(e);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen udev_list_entry_foreach(item, first) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen _cleanup_free_ char *fstype = NULL;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen const char *node = NULL;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen struct udev_device *q;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen sd_id128_t type_id;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen unsigned nr;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (!q) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen r = log_oom();
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen goto finish;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen }
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (udev_device_get_devnum(q) == udev_device_get_devnum(d))
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen goto skip;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (udev_device_get_devnum(q) == udev_device_get_devnum(parent))
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen goto skip;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen node = udev_device_get_devnode(q);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (!node) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen r = log_oom();
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen goto finish;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen }
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen r = verify_gpt_partition(node, &type_id, &nr, &fstype);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (r < 0) {
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen log_error("Failed to verify GPT partition %s: %s",
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen node, strerror(-r));
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen udev_device_unref(q);
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen goto finish;
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen }
091a364c802e34a58f3260c9cb5db9b75c62215cTom Gundersen if (r == 0)
goto skip;
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)))
add_swap(node, fstype);
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))) {
if (!home || nr < home_nr) {
free(home);
home = strdup(node);
if (!home) {
r = log_oom();
goto finish;
}
home_nr = nr;
free(home_fstype);
home_fstype = fstype;
fstype = NULL;
}
}
skip:
udev_device_unref(q);
}
if (home && home_fstype)
add_home(home, home_fstype);
finish:
if (d)
udev_device_unref(d);
if (e)
udev_enumerate_unref(e);
return r;
}
static int get_btrfs_block_device(const char *path, dev_t *dev) {
struct btrfs_ioctl_fs_info_args fsi;
_cleanup_close_ int fd = -1;
uint64_t id;
assert(path);
assert(dev);
fd = open(path, O_DIRECTORY|O_CLOEXEC);
if (fd < 0)
return -errno;
zero(fsi);
if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
return -errno;
/* We won't do this for btrfs RAID */
if (fsi.num_devices != 1)
return 0;
for (id = 1; id <= fsi.max_id; id++) {
struct btrfs_ioctl_dev_info_args di;
struct stat st;
zero(di);
di.devid = id;
if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
if (errno == ENODEV)
continue;
return -errno;
}
if (stat((char*) di.path, &st) < 0)
return -errno;
if (!S_ISBLK(st.st_mode))
return -ENODEV;
if (major(st.st_rdev) == 0)
return -ENODEV;
*dev = st.st_rdev;
return 1;
}
return -ENODEV;
}
static int get_block_device(const char *path, dev_t *dev) {
struct stat st;
struct statfs sfs;
assert(path);
assert(dev);
if (lstat("/", &st))
return -errno;
if (major(st.st_dev) != 0) {
*dev = st.st_dev;
return 1;
}
if (statfs("/", &sfs) < 0)
return -errno;
if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
return get_btrfs_block_device(path, dev);
return 0;
}
static int devno_to_devnode(struct udev *udev, dev_t devno, char **ret) {
struct udev_device *d = NULL;
const char *t;
char *n;
int r;
d = udev_device_new_from_devnum(udev, 'b', devno);
if (!d) {
r = log_oom();
goto finish;
}
t = udev_device_get_devnode(d);
if (!t) {
r = -ENODEV;
goto finish;
}
n = strdup(t);
if (!n) {
r = -ENOMEM;
goto finish;
}
*ret = n;
r = 0;
finish:
if (d)
udev_device_unref(d);
return r;
}
int main(int argc, char *argv[]) {
_cleanup_free_ char *node = NULL;
struct udev *udev = NULL;
dev_t devno;
int r;
if (argc > 1 && argc != 4) {
log_error("This program takes three or no arguments.");
r = -EINVAL;
goto finish;
}
if (argc > 1)
arg_dest = argv[3];
log_set_target(LOG_TARGET_SAFE);
log_parse_environment();
log_open();
umask(0022);
if (in_initrd()) {
log_debug("In initrd, exiting.");
r = 0;
goto finish;
}
if (detect_container(NULL) > 0) {
log_debug("In a container, exiting.");
r = 0;
goto finish;
}
r = get_block_device("/", &devno);
if (r < 0) {
log_error("Failed to determine block device of root file system: %s", strerror(-r));
goto finish;
}
if (r == 0) {
log_debug("Root file system not on a (single) block device.");
goto finish;
}
udev = udev_new();
if (!udev) {
r = log_oom();
goto finish;
}
r = devno_to_devnode(udev, devno, &node);
if (r < 0) {
log_error("Failed to determine block device node from major/minor: %s", strerror(-r));
goto finish;
}
log_debug("Root device %s.", node);
r = verify_gpt_partition(node, NULL, NULL, NULL);
if (r < 0) {
log_error("Failed to verify GPT partition %s: %s", node, strerror(-r));
goto finish;
}
if (r == 0)
goto finish;
r = enumerate_partitions(udev, devno);
finish:
if (udev)
udev_unref(udev);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}