/***
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 <stdlib.h>
#include <unistd.h>
#include "libudev.h"
#include "sd-id128.h"
#include "alloc-util.h"
#include "blkid-util.h"
#include "btrfs-util.h"
#include "dirent-util.h"
#include "efivars.h"
#include "fd-util.h"
#include "fileio.h"
#include "fstab-util.h"
#include "generator.h"
#include "gpt.h"
#include "missing.h"
#include "mkdir.h"
#include "mount-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "proc-cmdline.h"
#include "special.h"
#include "stat-util.h"
#include "string-util.h"
#include "udev-util.h"
#include "unit-name.h"
#include "util.h"
#include "virt.h"
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");
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);
r = fflush_and_check(f);
if (r < 0)
return log_error_errno(r, "Failed to write file %s: %m", p);
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",
WRITE_STRING_FILE_CREATE); /* 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 *options,
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)
if (options)
else
r = fflush_and_check(f);
if (r < 0)
return log_error_errno(r, "Failed to write unit file %s: %m", p);
if (post) {
if (!lnk)
return log_oom();
}
return 0;
}
int r;
/* already a mountpoint; generators run during reload */
if (r > 0)
return false;
/* the directory might not exist on a stateless system */
if (r == -ENOENT)
return false;
if (r < 0)
return true;
/* not a mountpoint but it contains files */
if (dir_is_empty(where) <= 0)
return true;
return false;
}
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_busy(where)) {
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();
}
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,
NULL,
post);
}
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);
r = fflush_and_check(f);
if (r < 0)
if (!lnk)
return log_oom();
return 0;
}
#ifdef ENABLE_EFI
static int add_automount(
const char *id,
const char *what,
const char *where,
const char *fstype,
bool rw,
const char *options,
const char *description,
int r;
if (options)
else
if (!opt)
return log_oom();
what,
rw,
opt,
NULL);
if (r < 0)
return r;
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"
"[Automount]\n"
"Where=%s\n"
"TimeoutIdleSec=%lld\n",
(unsigned long long)timeout / USEC_PER_SEC);
r = fflush_and_check(f);
if (r < 0)
return log_error_errno(r, "Failed to write unit file %s: %m", p);
if (!lnk)
return log_oom();
return 0;
}
int r;
if (!is_efi_boot()) {
log_debug("Not an EFI boot, ignoring /boot.");
return 0;
}
if (in_initrd()) {
log_debug("In initrd, ignoring /boot.");
return 0;
}
if (detect_container() > 0) {
log_debug("In a container, ignoring /boot.");
return 0;
}
/* We create an .automount which is not overridden by the .mount from the fstab generator. */
if (fstab_is_mount_point("/boot")) {
log_debug("/boot specified in fstab, ignoring.");
return 0;
}
if (path_is_busy("/boot")) {
log_debug("/boot already populated, ignoring.");
return 0;
}
if (r == -ENOENT) {
log_debug("EFI loader partition unknown.");
return 0;
}
if (r < 0) {
log_error_errno(r, "Failed to read ESP partition UUID: %m");
return r;
}
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)
log_debug("Partition for /boot is not a FAT filesystem, ignoring.");
return 0;
}
errno = 0;
if (r != 0) {
return 0;
}
log_debug("Partition for /boot does not have a valid UUID, ignoring.");
return 0;
}
log_debug("Partition for /boot does not appear to be the partition we are booted from.");
return 0;
}
r = add_automount("boot",
what,
"/boot",
"vfat",
true,
"umask=0077",
"EFI System Partition Automount",
120 * USEC_PER_SEC);
return r;
}
#else
return 0;
}
#endif
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 == 1)
return 0; /* no results */
else if (r == -2) {
return 0;
} else if (r != 0)
errno = 0;
if (r != 0) {
if (errno == 0)
return 0; /* No partition table found. */
}
/* 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;
unsigned long long flags;
int nr;
if (!q)
continue;
qn = udev_device_get_devnum(q);
continue;
continue;
continue;
if (!subnode)
continue;
if (!pp)
continue;
if (nr < 0)
continue;
if (!stype)
continue;
continue;
if (flags & GPT_FLAG_NO_AUTO)
continue;
if (flags & GPT_FLAG_READ_ONLY) {
continue;
}
if (k < 0)
r = k;
/* We only care for the first /boot partition */
continue;
/* Note that we do not honour the "no-auto"
* flag for the ESP, as it is often unset, to
* hide it from Windows. */
if (r < 0)
return log_oom();
if (flags & GPT_FLAG_NO_AUTO)
continue;
/* We only care for the first /home partition */
continue;
if (r < 0)
return log_oom();
if (flags & GPT_FLAG_NO_AUTO)
continue;
/* We only care for the first /srv partition */
continue;
if (r < 0)
return log_oom();
}
}
if (boot) {
if (k < 0)
r = k;
}
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;
}
/* Get's the block device directly backing a file system. If
* the block device is encrypted, returns the device mapper
* block device. */
return -errno;
return 1;
}
return -errno;
return 0;
}
const char *q;
int r;
/* Gets the backing block device for a file system, and
* handles LUKS encrypted file systems, looking for its
* immediate parent, if there is one. */
if (r <= 0)
return r;
return -ENOMEM;
d = opendir(p);
if (!d) {
goto fallback;
return -errno;
}
continue;
continue;
if (found) /* Don't try to support multiple backing block devices */
goto fallback;
}
if (!found)
goto fallback;
r = read_one_line_file(q, &t);
if (r == -ENOENT)
goto fallback;
if (r < 0)
return r;
return -EINVAL;
if (maj == 0)
goto fallback;
return 1;
return 1;
}
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,
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() > 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;
}