gpt-auto-generator.c revision 7410616cd9dbbec97cf98d75324da5cda2b2f7a2
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2013 Lennart Poettering
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <unistd.h>
#include <stdlib.h>
#include "sd-id128.h"
#include "libudev.h"
#include "path-util.h"
#include "util.h"
#include "mkdir.h"
#include "missing.h"
#include "udev-util.h"
#include "special.h"
#include "unit-name.h"
#include "virt.h"
#include "generator.h"
#include "gpt.h"
#include "fileio.h"
#include "efivars.h"
#include "blkid-util.h"
#include "btrfs-util.h"
static const char *arg_dest = "/tmp";
static bool arg_enabled = true;
static bool arg_root_enabled = true;
static bool arg_root_rw = false;
int r;
if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m");
if (!unit)
return log_oom();
if (!f)
fprintf(f,
"# Automatically generated by systemd-gpt-auto-generator\n\n"
"[Unit]\n"
"Description=Swap Partition\n"
"Documentation=man:systemd-gpt-auto-generator(8)\n\n"
"[Swap]\n"
"What=%s\n",
path);
fflush(f);
if (ferror(f))
if (!lnk)
return log_oom();
return 0;
}
int r;
if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m");
e = unit_name_escape(id);
if (!e)
return log_oom();
if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m");
if (!p)
return log_oom();
f = fopen(p, "wxe");
if (!f)
fprintf(f,
"# Automatically generated by systemd-gpt-auto-generator\n\n"
"[Unit]\n"
"Description=Cryptography Setup for %%I\n"
"Documentation=man:systemd-gpt-auto-generator(8) man:systemd-cryptsetup@.service(8)\n"
"DefaultDependencies=no\n"
"Conflicts=umount.target\n"
"BindsTo=dev-mapper-%%i.device %s\n"
"Before=umount.target cryptsetup.target\n"
"After=%s\n"
"IgnoreOnIsolate=true\n"
"[Service]\n"
"Type=oneshot\n"
"RemainAfterExit=yes\n"
"TimeoutSec=0\n" /* the binary handles timeouts anyway */
d, d,
id);
fflush(f);
if (ferror(f))
if (!to)
return log_oom();
if (!to)
return log_oom();
if (!to)
return log_oom();
free(p);
if (!p)
return log_oom();
mkdir_parents_label(p, 0755);
r = write_string_file(p,
"# Automatically generated by systemd-gpt-auto-generator\n\n"
"[Unit]\n"
"JobTimeoutSec=0\n"); /* the binary handles timeouts anyway */
if (r < 0)
return log_error_errno(r, "Failed to write device drop-in: %m");
if (!ret)
return log_oom();
return 0;
}
static int add_mount(
const char *id,
const char *what,
const char *where,
const char *fstype,
bool rw,
const char *description,
const char *post) {
int r;
if (r < 0)
return r;
what = crypto_what;
}
if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m");
if (!p)
return log_oom();
f = fopen(p, "wxe");
if (!f)
fprintf(f,
"# Automatically generated by systemd-gpt-auto-generator\n\n"
"[Unit]\n"
"Description=%s\n"
"Documentation=man:systemd-gpt-auto-generator(8)\n",
if (post)
if (r < 0)
return r;
fprintf(f,
"\n"
"[Mount]\n"
"What=%s\n"
"Where=%s\n",
if (fstype)
fflush(f);
if (ferror(f))
if (post) {
if (!lnk)
return log_oom();
}
return 0;
}
static int probe_and_add_mount(
const char *id,
const char *what,
const char *where,
bool rw,
const char *description,
const char *post) {
int r;
if (path_is_mount_point(where, true) <= 0 &&
dir_is_empty(where) <= 0) {
return 0;
}
/* Let's check the partition type here, so that we know
* whether to do LUKS magic. */
errno = 0;
if (!b) {
if (errno == 0)
return log_oom();
return -errno;
}
errno = 0;
r = blkid_do_safeprobe(b);
if (r == -2 || r == 1) /* no result or uncertain */
return 0;
else if (r != 0)
/* add_mount is OK with fstype being NULL. */
return add_mount(
id,
what,
rw,
post);
}
int r, k;
if (!udev)
return log_oom();
if (!d)
return log_oom();
name = udev_device_get_devnode(d);
if (!name)
name = udev_device_get_syspath(d);
if (!name) {
log_debug("Device %u:%u does not have a name, ignoring.",
return 0;
}
parent = udev_device_get_parent(d);
if (!parent) {
return 0;
}
/* Does it have a devtype? */
if (!devtype) {
return 0;
}
/* Is this a disk or a partition? We only care for disks... */
return 0;
}
/* Does it have a device node? */
if (!node) {
return 0;
}
return 0;
errno = 0;
if (!b) {
if (errno == 0)
return log_oom();
}
errno = 0;
r = blkid_do_safeprobe(b);
if (r == -2 || r == 1) /* no result or uncertain */
return 0;
else if (r != 0)
errno = 0;
if (r != 0)
"%s: failed to determine partition table type: %m", node);
/* We only do this all for GPT... */
return 0;
}
errno = 0;
pl = blkid_probe_get_partitions(b);
if (!pl) {
if (errno == 0)
return log_oom();
}
e = udev_enumerate_new(udev);
if (!e)
return log_oom();
r = udev_enumerate_add_match_parent(e, parent);
if (r < 0)
return log_oom();
r = udev_enumerate_add_match_subsystem(e, "block");
if (r < 0)
return log_oom();
r = udev_enumerate_scan_devices(e);
if (r < 0)
_cleanup_udev_device_unref_ struct udev_device *q;
int nr;
unsigned long long flags;
if (!q)
continue;
qn = udev_device_get_devnum(q);
continue;
continue;
continue;
if (!subnode)
continue;
if (!pp)
continue;
/* Ignore partitions that are not marked for automatic
* mounting on discovery */
if (flags & GPT_FLAG_NO_AUTO)
continue;
if (nr < 0)
continue;
if (!stype)
continue;
continue;
if (flags & GPT_FLAG_READ_ONLY) {
continue;
}
if (k < 0)
r = k;
/* We only care for the first /home partition */
continue;
if (!home)
return log_oom();
/* We only care for the first /srv partition */
continue;
if (!srv)
return log_oom();
}
}
if (home) {
if (k < 0)
r = k;
}
if (srv) {
k = probe_and_add_mount("srv", srv, "/srv", srv_rw, "Server Data Partition", SPECIAL_LOCAL_FS_TARGET);
if (k < 0)
r = k;
}
return r;
}
return -errno;
return 1;
}
return -errno;
return 0;
}
int r;
r = parse_boolean(value);
if (r < 0)
else
arg_enabled = r;
/* Disable root disk logic if there's a root= value
* specified (unless it happens to be "gpt-auto") */
arg_root_rw = true;
arg_root_rw = false;
return 0;
}
static int add_root_mount(void) {
#ifdef ENABLE_EFI
int r;
if (!is_efi_boot()) {
log_debug("Not a EFI boot, not creating root mount.");
return 0;
}
if (r == -ENOENT) {
log_debug("EFI loader partition unknown, exiting.");
return 0;
} else if (r < 0)
return log_error_errno(r, "Failed to read ESP partition UUID: %m");
/* OK, we have an ESP partition, this is fantastic, so let's
* wait for a root device to show up. A udev rule will create
* the link for us under the right name. */
return add_mount(
"root",
"/dev/gpt-auto-root",
NULL,
"Root Partition",
#else
return 0;
#endif
}
static int add_mounts(void) {
int r;
if (r < 0)
return log_error_errno(r, "Failed to determine block device of root file system: %m");
else if (r == 0) {
if (r < 0)
return log_error_errno(r, "Failed to determine block device of /usr file system: %m");
else if (r == 0) {
log_debug("Neither root nor /usr file system are on a (single) block device.");
return 0;
}
}
return enumerate_partitions(devno);
}
int r = 0;
log_error("This program takes three or no arguments.");
return EXIT_FAILURE;
}
if (argc > 1)
log_open();
umask(0022);
if (detect_container(NULL) > 0) {
log_debug("In a container, exiting.");
return EXIT_SUCCESS;
}
if (r < 0)
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
if (!arg_enabled) {
log_debug("Disabled, exiting.");
return EXIT_SUCCESS;
}
if (arg_root_enabled)
r = add_root_mount();
if (!in_initrd()) {
int k;
k = add_mounts();
if (k < 0)
r = k;
}
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}