mirror of
https://github.com/systemd/systemd.git
synced 2025-01-27 18:04:05 +03:00
Merge pull request #16676 from poettering/repart-mkfs
repart: add new settings Format=, CopyFiles=, Encrypt= and teach --size= a new value "auto"
This commit is contained in:
commit
3b9d671754
7
TODO
7
TODO
@ -234,9 +234,6 @@ Features:
|
||||
* systemd-repart: allow sizing partitions as factor of available RAM, so that
|
||||
we can reasonably size swap partitions for hibernation.
|
||||
|
||||
* systemd-repart: allow running mkfs before making partitions pop up +
|
||||
encryption via LUKS to allow booting into an empty root with only /usr mounted in
|
||||
|
||||
* systemd-repart: allow managing the gpt read-only partition flag + auto-mount flag
|
||||
|
||||
* systemd-repart: allow boolean option that ensures that if existing partition
|
||||
@ -252,10 +249,6 @@ Features:
|
||||
* systemd-repart: add per-partition option to fail if partition already exist,
|
||||
i.e. is not added new. Similar, add option to fail if partition does not exist yet.
|
||||
|
||||
* systemd-repart: add --size=auto for generating/resizing images of minimal
|
||||
size, i.e. where the image file is sized exactly as large as necessary taking
|
||||
SizeMin= into account, but not a single byte larger.
|
||||
|
||||
* systemd-repart: allow disabling growing of specific partitions, or making
|
||||
them (think ESP: we don't ever want to grow it, since we cannot resize vfat)
|
||||
|
||||
|
@ -55,11 +55,11 @@
|
||||
partition slot greater than the highest slot number currently in use. Any existing partitions that have
|
||||
no matching partition file are left as they are.</para>
|
||||
|
||||
<para>Note that these partition definition files do not describe the contents of the partitions, such as
|
||||
the file system used. Separate mechanisms, such as
|
||||
<citerefentry><refentrytitle>systemd-growfs</refentrytitle><manvolnum>8</manvolnum></citerefentry> and
|
||||
<command>systemd-makefs</command> maybe be used to initialize or grow the file systems inside of these
|
||||
partitions.</para>
|
||||
<para>Note that these definitions may only be used to created and initialize new partitions or grow
|
||||
existing ones. In the latter case it will not grow the contained files systems however; separate
|
||||
mechanisms, such as
|
||||
<citerefentry><refentrytitle>systemd-growfs</refentrytitle><manvolnum>8</manvolnum></citerefentry> may be
|
||||
used to grow the file systems inside of these partitions.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
@ -327,7 +327,72 @@
|
||||
data is never overwritten. Note that the data is copied in before the partition table is updated,
|
||||
i.e. before the partition actually is persistently created. This provides robustness: it is
|
||||
guaranteed that the partition either doesn't exist or exists fully populated; it is not possible that
|
||||
the partition exists but is not or only partially populated.</para></listitem>
|
||||
the partition exists but is not or only partially populated.</para>
|
||||
|
||||
<para>This option cannot be combined with <varname>Format=</varname> or
|
||||
<varname>CopyFiles=</varname>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>Format=</varname></term>
|
||||
|
||||
<listitem><para>Takes a file system name, such as <literal>ext4</literal>, <literal>btrfs</literal>,
|
||||
<literal>xfs</literal> or <literal>vfat</literal>, or the special value <literal>swap</literal>. If
|
||||
specified and the partition is newly created it is formatted with the specified file system (or as
|
||||
swap device). The file system UUID and label are automatically derived from the partition UUID and
|
||||
label. If this option is used, the size allocation algorithm is slightly altered: the partition is
|
||||
created as least as big as required for the minimal file system of the specified type (or 4KiB if the
|
||||
minimal size is not known).</para>
|
||||
|
||||
<para>This option has no effect if the partition already exists.</para>
|
||||
|
||||
<para>Similar to the behaviour of <varname>CopyBlocks=</varname> the file system is formatted before
|
||||
the partition is created, ensuring that the partition only ever exists with a fully initialized
|
||||
file system.</para>
|
||||
|
||||
<para>This option cannot be combined with <varname>CopyBlocks=</varname>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>CopyFiles=</varname></term>
|
||||
|
||||
<listitem><para>Takes a pair of colon separated absolute file system paths. The first path refers to
|
||||
a source file or directory on the host, the second path refers to a target in the file system of the
|
||||
newly created partition and formatted file system. This setting may be used to copy files or
|
||||
directories from the host into the file system that is created due to the <varname>Format=</varname>
|
||||
option. If <varname>CopyFiles=</varname> is used without <varname>Format=</varname> specified
|
||||
explicitly, <literal>Format=</literal> with a suitable default is implied (currently
|
||||
<literal>ext4</literal>, but this may change in the future). This option may be used multiple times
|
||||
to copy multiple files or directories from host into the newly formatted file system. The colon and
|
||||
second path may be omitted in which case the source path is also used as the target path (relative to
|
||||
the root of the newly created file system). If the source path refers to a directory it is copied
|
||||
recursively.</para>
|
||||
|
||||
<para>This option has no effect if the partition already exists: it cannot be used to copy additional
|
||||
files into an existing partition, it may only be used to populate a file system created anew.</para>
|
||||
|
||||
<para>The copy operation is executed before the file system is registered in the partition table,
|
||||
thus ensuring that a file system populated this way only ever exists fully initialized.</para>
|
||||
|
||||
<para>This option cannot be combined with <varname>CopyBlocks=</varname>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>Encrypt=</varname></term>
|
||||
|
||||
<listitem><para>Takes a boolean parameter, defaulting to false. If true the partition will be
|
||||
formatted with a LUKS2 superblock, before the blocks configured with <varname>CopyBlocks=</varname>
|
||||
are copied in or the file system configured with <varname>Format=</varname> is created.</para>
|
||||
|
||||
<para>The LUKS2 UUID is automatically derived from the partition UUID in a stable fashion. A single
|
||||
key is added to the LUKS2 superblock, configurable with the <option>--key-file=</option> switch to
|
||||
<command>systemd-repart</command>.</para>
|
||||
|
||||
<para>When used this slightly alters the size allocation logic as the implicit, minimal size limits
|
||||
of <varname>Format=</varname> and <varname>CopyBlocks=</varname> are increased by the space necessary
|
||||
for the LUKS2 superblock (see above).</para>
|
||||
|
||||
<para>This option has no effect if the partition already exists.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
@ -202,13 +202,26 @@
|
||||
<varlistentry>
|
||||
<term><option>--size=</option></term>
|
||||
|
||||
<listitem><para>Takes a size in bytes, using the usual K, M, G, T suffixes. If used the specified
|
||||
device node path must refer to a regular file, which is then grown to the specified size if smaller,
|
||||
before any change is made to the partition table. This is not supported if the specified node is a
|
||||
block device. This switch has no effect if the file is already as large as the specified size or
|
||||
larger. The specified size is implicitly rounded up to multiples of 4096. When used with
|
||||
<option>--empty=create</option> this specifies the initial size of the loopback file to
|
||||
create.</para></listitem>
|
||||
<listitem><para>Takes a size in bytes, using the usual K, M, G, T suffixes, or the special value
|
||||
<literal>auto</literal>. If used the specified device node path must refer to a regular file, which
|
||||
is then grown to the specified size if smaller, before any change is made to the partition table. If
|
||||
specified as <literal>auto</literal> the minimal size for the disk image is automatically determined
|
||||
(i.e. the minimal sizes of all partitions are summed up, taking space for additional metadata into
|
||||
account). This switch is not supported if the specified node is a block device. This switch has no
|
||||
effect if the file is already as large as the specified size or larger. The specified size is
|
||||
implicitly rounded up to multiples of 4096. When used with <option>--empty=create</option> this
|
||||
specifies the initial size of the loopback file to create.</para>
|
||||
|
||||
<para>The <option>--size=auto</option> option takes the sizes of pre-existing partitions into
|
||||
account. However, it does not accomodate for partition tables that are not tightly packed: the
|
||||
configured partitions might still not fit into the backing device if empty space exists between
|
||||
pre-existing partitions (or before the first partition) that cannot be fully filled by partitions to
|
||||
grow or create.</para>
|
||||
|
||||
<para>Also note that the automatic size determination does not take files or directories specified
|
||||
with <option>CopyFiles=</option> into account: operation might fail if the specified files or
|
||||
directories require more disk space then the configured per-partition minimal size
|
||||
limit.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@ -283,6 +296,18 @@
|
||||
<filename>/run/repart.d/*.conf</filename>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--key-file=</option></term>
|
||||
|
||||
<listitem><para>Takes a file system path. Configures the encryption key to use when setting up LUKS2
|
||||
volumes configured with the <varname>Encrypt=</varname> setting in partition files. Should refer to a
|
||||
regular file containing the key, or an <constant>AF_UNIX</constant> stream socket in the file
|
||||
system. In the latter case a connection is made to it and the key read from it. If this switch is not
|
||||
specified the empty key (i.e. zero length key) is used. This behaviour is useful for setting up encrypted
|
||||
partitions during early first boot that receive their user-supplied password only in a later setup
|
||||
step.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<xi:include href="standard-options.xml" xpointer="help" />
|
||||
<xi:include href="standard-options.xml" xpointer="version" />
|
||||
</variablelist>
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "format-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "macro.h"
|
||||
@ -187,3 +188,54 @@ int mkdir_p(const char *path, mode_t mode) {
|
||||
int mkdir_p_safe(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) {
|
||||
return mkdir_p_internal(prefix, path, mode, uid, gid, flags, mkdir_errno_wrapper);
|
||||
}
|
||||
|
||||
int mkdir_p_root(const char *root, const char *p, uid_t uid, gid_t gid, mode_t m) {
|
||||
_cleanup_free_ char *pp = NULL;
|
||||
_cleanup_close_ int dfd = -1;
|
||||
const char *bn;
|
||||
int r;
|
||||
|
||||
pp = dirname_malloc(p);
|
||||
if (!pp)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Not top-level? */
|
||||
if (!(path_equal(pp, "/") || isempty(pp) || path_equal(pp, "."))) {
|
||||
|
||||
/* Recurse up */
|
||||
r = mkdir_p_root(root, pp, uid, gid, m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
bn = basename(p);
|
||||
if (path_equal(bn, "/") || isempty(bn) || path_equal(bn, "."))
|
||||
return 0;
|
||||
|
||||
if (!filename_is_valid(bn))
|
||||
return -EINVAL;
|
||||
|
||||
dfd = chase_symlinks_and_open(pp, root, CHASE_PREFIX_ROOT, O_RDONLY|O_CLOEXEC|O_DIRECTORY, NULL);
|
||||
if (dfd < 0)
|
||||
return dfd;
|
||||
|
||||
if (mkdirat(dfd, bn, m) < 0) {
|
||||
if (errno == EEXIST)
|
||||
return 0;
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (uid_is_valid(uid) || gid_is_valid(gid)) {
|
||||
_cleanup_close_ int nfd = -1;
|
||||
|
||||
nfd = openat(dfd, bn, O_RDONLY|O_CLOEXEC|O_DIRECTORY);
|
||||
if (nfd < 0)
|
||||
return -errno;
|
||||
|
||||
if (fchown(nfd, uid, gid) < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -26,3 +26,5 @@ typedef int (*mkdir_func_t)(const char *pathname, mode_t mode);
|
||||
int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdir_func_t _mkdir);
|
||||
int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdir_func_t _mkdir);
|
||||
int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdir_func_t _mkdir);
|
||||
|
||||
int mkdir_p_root(const char *root, const char *p, uid_t uid, gid_t gid, mode_t m);
|
||||
|
@ -726,18 +726,6 @@ int fsck_exists(const char *fstype) {
|
||||
return binary_is_good(checker);
|
||||
}
|
||||
|
||||
int mkfs_exists(const char *fstype) {
|
||||
const char *mkfs;
|
||||
|
||||
assert(fstype);
|
||||
|
||||
if (streq(fstype, "auto"))
|
||||
return -EINVAL;
|
||||
|
||||
mkfs = strjoina("mkfs.", fstype);
|
||||
return binary_is_good(mkfs);
|
||||
}
|
||||
|
||||
int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg) {
|
||||
char *p;
|
||||
int r;
|
||||
|
@ -85,7 +85,6 @@ int find_binary(const char *name, char **filename);
|
||||
bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update);
|
||||
|
||||
int fsck_exists(const char *fstype);
|
||||
int mkfs_exists(const char *fstype);
|
||||
|
||||
/* Iterates through the path prefixes of the specified path, going up
|
||||
* the tree, to root. Also returns "" (and not "/"!) for the root
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "memory-util.h"
|
||||
#include "missing_magic.h"
|
||||
#include "mkdir.h"
|
||||
#include "mkfs-util.h"
|
||||
#include "mount-util.h"
|
||||
#include "openssl-util.h"
|
||||
#include "parse-util.h"
|
||||
@ -1371,71 +1372,6 @@ int home_trim_luks(UserRecord *h) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run_mkfs(
|
||||
const char *node,
|
||||
const char *fstype,
|
||||
const char *label,
|
||||
sd_id128_t uuid,
|
||||
bool discard) {
|
||||
|
||||
int r;
|
||||
|
||||
assert(node);
|
||||
assert(fstype);
|
||||
assert(label);
|
||||
|
||||
r = mkfs_exists(fstype);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to check if mkfs for file system %s exists: %m", fstype);
|
||||
if (r == 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EPROTONOSUPPORT), "No mkfs for file system %s installed.", fstype);
|
||||
|
||||
r = safe_fork("(mkfs)", FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG|FORK_LOG|FORK_WAIT|FORK_STDOUT_TO_STDERR, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
const char *mkfs;
|
||||
char suuid[37];
|
||||
|
||||
/* Child */
|
||||
|
||||
mkfs = strjoina("mkfs.", fstype);
|
||||
id128_to_uuid_string(uuid, suuid);
|
||||
|
||||
if (streq(fstype, "ext4"))
|
||||
execlp(mkfs, mkfs,
|
||||
"-L", label,
|
||||
"-U", suuid,
|
||||
"-I", "256",
|
||||
"-O", "has_journal",
|
||||
"-m", "0",
|
||||
"-E", discard ? "lazy_itable_init=1,discard" : "lazy_itable_init=1,nodiscard",
|
||||
node, NULL);
|
||||
else if (streq(fstype, "btrfs")) {
|
||||
if (discard)
|
||||
execlp(mkfs, mkfs, "-L", label, "-U", suuid, node, NULL);
|
||||
else
|
||||
execlp(mkfs, mkfs, "-L", label, "-U", suuid, "--nodiscard", node, NULL);
|
||||
} else if (streq(fstype, "xfs")) {
|
||||
const char *j;
|
||||
|
||||
j = strjoina("uuid=", suuid);
|
||||
if (discard)
|
||||
execlp(mkfs, mkfs, "-L", label, "-m", j, "-m", "reflink=1", node, NULL);
|
||||
else
|
||||
execlp(mkfs, mkfs, "-L", label, "-m", j, "-m", "reflink=1", "-K", node, NULL);
|
||||
} else {
|
||||
log_error("Cannot make file system: %s", fstype);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
log_error_errno(errno, "Failed to execute %s: %m", mkfs);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct crypt_pbkdf_type* build_good_pbkdf(struct crypt_pbkdf_type *buffer, UserRecord *hr) {
|
||||
assert(buffer);
|
||||
assert(hr);
|
||||
@ -2083,7 +2019,7 @@ int home_create_luks(
|
||||
|
||||
log_info("Setting up LUKS device %s completed.", dm_node);
|
||||
|
||||
r = run_mkfs(dm_node, fstype, user_record_user_name_and_realm(h), fs_uuid, user_record_luks_discard(h));
|
||||
r = make_filesystem(dm_node, fstype, user_record_user_name_and_realm(h), fs_uuid, user_record_luks_discard(h));
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
|
@ -11,40 +11,15 @@
|
||||
#include "dissect-image.h"
|
||||
#include "fd-util.h"
|
||||
#include "main-func.h"
|
||||
#include "mkfs-util.h"
|
||||
#include "process-util.h"
|
||||
#include "signal-util.h"
|
||||
#include "string-util.h"
|
||||
|
||||
static int makefs(const char *type, const char *device) {
|
||||
const char *mkfs;
|
||||
pid_t pid;
|
||||
int r;
|
||||
|
||||
if (streq(type, "swap"))
|
||||
mkfs = "/sbin/mkswap";
|
||||
else
|
||||
mkfs = strjoina("/sbin/mkfs.", type);
|
||||
if (access(mkfs, X_OK) != 0)
|
||||
return log_error_errno(errno, "%s is not executable: %m", mkfs);
|
||||
|
||||
r = safe_fork("(mkfs)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
const char *cmdline[3] = { mkfs, device, NULL };
|
||||
|
||||
/* Child */
|
||||
|
||||
execv(cmdline[0], (char**) cmdline);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return wait_for_terminate_and_check(mkfs, pid, WAIT_LOG);
|
||||
}
|
||||
|
||||
static int run(int argc, char *argv[]) {
|
||||
_cleanup_free_ char *device = NULL, *type = NULL, *detected = NULL;
|
||||
_cleanup_free_ char *device = NULL, *fstype = NULL, *detected = NULL;
|
||||
_cleanup_close_ int lock_fd = -1;
|
||||
sd_id128_t uuid;
|
||||
struct stat st;
|
||||
int r;
|
||||
|
||||
@ -55,8 +30,8 @@ static int run(int argc, char *argv[]) {
|
||||
"This program expects two arguments.");
|
||||
|
||||
/* type and device must be copied because makefs calls safe_fork, which clears argv[] */
|
||||
type = strdup(argv[1]);
|
||||
if (!type)
|
||||
fstype = strdup(argv[1]);
|
||||
if (!fstype)
|
||||
return log_oom();
|
||||
|
||||
device = strdup(argv[2]);
|
||||
@ -85,7 +60,11 @@ static int run(int argc, char *argv[]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return makefs(type, device);
|
||||
r = sd_id128_randomize(&uuid);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to generate UUID for file system: %m");
|
||||
|
||||
return make_filesystem(device, fstype, basename(device), uuid, true);
|
||||
}
|
||||
|
||||
DEFINE_MAIN_FUNCTION(run);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -154,6 +154,57 @@ EOF
|
||||
|
||||
cmp --bytes=41943040 --ignore-initial=0:$((512*4194264)) $D/block-copy $D/zzz
|
||||
|
||||
if [ `id -u` == 0 ] && type -P cryptsetup diff losetup > /dev/null ; then
|
||||
echo "### Testing Format=/Encrypt=/CopyFiles="
|
||||
|
||||
# These tests require privileges unfortunately
|
||||
|
||||
cat >$D/definitions/extra3.conf <<EOF
|
||||
[Partition]
|
||||
Type=linux-generic
|
||||
Label=luks-format-copy
|
||||
UUID=7b93d1f2-595d-4ce3-b0b9-837fbd9e63b0
|
||||
Format=ext4
|
||||
Encrypt=yes
|
||||
CopyFiles=$D/definitions:/def
|
||||
SizeMinBytes=48M
|
||||
EOF
|
||||
|
||||
$repart $D/zzz --size=auto --dry-run=no --seed=$SEED --definitions=$D/definitions
|
||||
|
||||
sfdisk -d $D/zzz | grep -v -e 'sector-size' -e '^$' >$D/populated5
|
||||
|
||||
cmp $D/populated5 - <<EOF
|
||||
label: gpt
|
||||
label-id: EF7F7EE2-47B3-4251-B1A1-09EA8BF12D5D
|
||||
device: $D/zzz
|
||||
unit: sectors
|
||||
first-lba: 2048
|
||||
last-lba: 6389726
|
||||
$D/zzz1 : start= 2048, size= 591856, type=933AC7E1-2EB4-4F13-B844-0E14E2AEF915, uuid=A6005774-F558-4330-A8E5-D6D2C01C01D6, name="home-first"
|
||||
$D/zzz2 : start= 593904, size= 591856, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=CE9C76EB-A8F1-40FF-813C-11DCA6C0A55B, name="root-x86-64"
|
||||
$D/zzz3 : start= 1185760, size= 591864, type=4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709, uuid=AC60A837-550C-43BD-B5C4-9CB73B884E79, name="root-x86-64-2"
|
||||
$D/zzz4 : start= 1777624, size= 131072, type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F, uuid=2AA78CDB-59C7-4173-AF11-C7453737A5D1, name="swap"
|
||||
$D/zzz5 : start= 1908696, size= 2285568, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=A0A1A2A3-A4A5-A6A7-A8A9-AAABACADAEAF, name="custom_label"
|
||||
$D/zzz6 : start= 4194264, size= 2097152, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=2A1D97E1-D0A3-46CC-A26E-ADC643926617, name="block-copy"
|
||||
$D/zzz7 : start= 6291416, size= 98304, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=7B93D1F2-595D-4CE3-B0B9-837FBD9E63B0, name="luks-format-copy"
|
||||
EOF
|
||||
|
||||
LOOP=`losetup -P --show --find $D/zzz`
|
||||
VOLUME=test-repart-$RANDOM
|
||||
|
||||
touch $D/empty-password
|
||||
cryptsetup open --type=luks2 --key-file=$D/empty-password ${LOOP}p7 $VOLUME
|
||||
mkdir $D/mount
|
||||
mount -t ext4 /dev/mapper/$VOLUME $D/mount
|
||||
diff -r $D/mount/def $D/definitions > /dev/null
|
||||
umount $D/mount
|
||||
cryptsetup close $VOLUME
|
||||
losetup -d $LOOP
|
||||
else
|
||||
echo "### Skipping Format=/Encrypt=/CopyFiles= test, lacking privileges or missing cryptsetup/diff/losetup"
|
||||
fi
|
||||
|
||||
echo "### Testing json output ###"
|
||||
$repart $D/zzz --size=3G --dry-run=no --seed=$SEED --definitions=$D/definitions --json=help
|
||||
$repart $D/zzz --size=3G --dry-run=no --seed=$SEED --definitions=$D/definitions --json=pretty
|
||||
|
@ -1017,6 +1017,13 @@ static int mount_partition(
|
||||
}
|
||||
|
||||
if (directory) {
|
||||
if (!FLAGS_SET(flags, DISSECT_IMAGE_READ_ONLY)) {
|
||||
/* Automatically create missing mount points, if necessary. */
|
||||
r = mkdir_p_root(where, directory, uid_shift, (gid_t) uid_shift, 0755);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = chase_symlinks(directory, where, CHASE_PREFIX_ROOT, &chased, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -1062,7 +1069,7 @@ static int mount_partition(
|
||||
}
|
||||
|
||||
int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift, DissectImageFlags flags) {
|
||||
int r, boot_mounted;
|
||||
int r, xbootldr_mounted;
|
||||
|
||||
assert(m);
|
||||
assert(where);
|
||||
@ -1116,29 +1123,47 @@ int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift,
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
boot_mounted = mount_partition(m->partitions + PARTITION_XBOOTLDR, where, "/boot", uid_shift, flags);
|
||||
if (boot_mounted < 0)
|
||||
return boot_mounted;
|
||||
xbootldr_mounted = mount_partition(m->partitions + PARTITION_XBOOTLDR, where, "/boot", uid_shift, flags);
|
||||
if (xbootldr_mounted < 0)
|
||||
return xbootldr_mounted;
|
||||
|
||||
if (m->partitions[PARTITION_ESP].found) {
|
||||
int esp_done = false;
|
||||
|
||||
/* Mount the ESP to /efi if it exists. If it doesn't exist, use /boot instead, but only if it
|
||||
* exists and is empty, and we didn't already mount the XBOOTLDR partition into it. */
|
||||
|
||||
r = chase_symlinks("/efi", where, CHASE_PREFIX_ROOT, NULL, NULL);
|
||||
if (r >= 0) {
|
||||
if (r < 0) {
|
||||
if (r != -ENOENT)
|
||||
return r;
|
||||
|
||||
/* /efi doesn't exist. Let's see if /boot is suitable then */
|
||||
|
||||
if (!xbootldr_mounted) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
r = chase_symlinks("/boot", where, CHASE_PREFIX_ROOT, &p, NULL);
|
||||
if (r < 0) {
|
||||
if (r != -ENOENT)
|
||||
return r;
|
||||
} else if (dir_is_empty(p) > 0) {
|
||||
/* It exists and is an empty directory. Let's mount the ESP there. */
|
||||
r = mount_partition(m->partitions + PARTITION_ESP, where, "/boot", uid_shift, flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
esp_done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!esp_done) {
|
||||
/* OK, let's mount the ESP now to /efi (possibly creating the dir if missing) */
|
||||
|
||||
r = mount_partition(m->partitions + PARTITION_ESP, where, "/efi", uid_shift, flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
} else if (boot_mounted <= 0) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
r = chase_symlinks("/boot", where, CHASE_PREFIX_ROOT, &p, NULL);
|
||||
if (r >= 0 && dir_is_empty(p) > 0) {
|
||||
r = mount_partition(m->partitions + PARTITION_ESP, where, "/boot", uid_shift, flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,18 +47,42 @@ static int loop_configure(int fd, const struct loop_config *c) {
|
||||
if (!ERRNO_IS_NOT_SUPPORTED(errno) && errno != EINVAL)
|
||||
return -errno;
|
||||
} else {
|
||||
if (!FLAGS_SET(c->info.lo_flags, LO_FLAGS_PARTSCAN))
|
||||
bool good = true;
|
||||
|
||||
if (c->info.lo_sizelimit != 0) {
|
||||
/* Kernel 5.8 vanilla doesn't properly propagate the size limit into the block
|
||||
* device. If it's used, let's immediately check if it had the desired effect
|
||||
* hence. And if not use classic LOOP_SET_STATUS64. */
|
||||
uint64_t z;
|
||||
|
||||
if (ioctl(fd, BLKGETSIZE64, &z) < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (z != c->info.lo_sizelimit) {
|
||||
log_debug("LOOP_CONFIGURE is broken, doesn't honour .lo_sizelimit. Falling back to LOOP_SET_STATUS64.");
|
||||
good = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (FLAGS_SET(c->info.lo_flags, LO_FLAGS_PARTSCAN)) {
|
||||
/* Kernel 5.8 vanilla doesn't properly propagate the partition scanning flag into the
|
||||
* block device. Let's hence verify if things work correctly here before
|
||||
* returning. */
|
||||
|
||||
r = blockdev_partscan_enabled(fd);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
if (r == 0) {
|
||||
log_debug("LOOP_CONFIGURE is broken, doesn't honour LO_FLAGS_PARTSCAN. Falling back to LOOP_SET_STATUS64.");
|
||||
good = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (good)
|
||||
return 0;
|
||||
|
||||
/* Kernel 5.8 vanilla doesn't properly propagate the partition scanning flag into the
|
||||
* block device. Let's hence verify if things work correctly here before returning. */
|
||||
|
||||
r = blockdev_partscan_enabled(fd);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
if (r > 0)
|
||||
return 0; /* All is good. */
|
||||
|
||||
/* Otherwise, undo the attachment and use the old APIs */
|
||||
(void) ioctl(fd, LOOP_CLR_FD);
|
||||
}
|
||||
@ -472,3 +496,18 @@ int loop_device_flock(LoopDevice *d, int operation) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int loop_device_sync(LoopDevice *d) {
|
||||
assert(d);
|
||||
|
||||
/* We also do this implicitly in loop_device_unref(). Doing this explicitly here has the benefit that
|
||||
* we can check the return value though. */
|
||||
|
||||
if (d->fd < 0)
|
||||
return -EBADF;
|
||||
|
||||
if (fsync(d->fd) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -26,3 +26,4 @@ void loop_device_relinquish(LoopDevice *d);
|
||||
int loop_device_refresh_size(LoopDevice *d, uint64_t offset, uint64_t size);
|
||||
|
||||
int loop_device_flock(LoopDevice *d, int operation);
|
||||
int loop_device_sync(LoopDevice *d);
|
||||
|
@ -166,6 +166,8 @@ shared_sources = files('''
|
||||
macvlan-util.c
|
||||
macvlan-util.h
|
||||
main-func.h
|
||||
mkfs-util.c
|
||||
mkfs-util.h
|
||||
module-util.h
|
||||
mount-util.c
|
||||
mount-util.h
|
||||
|
135
src/shared/mkfs-util.c
Normal file
135
src/shared/mkfs-util.c
Normal file
@ -0,0 +1,135 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
|
||||
#include "id128-util.h"
|
||||
#include "mkfs-util.h"
|
||||
#include "path-util.h"
|
||||
#include "process-util.h"
|
||||
#include "stdio-util.h"
|
||||
#include "string-util.h"
|
||||
|
||||
int mkfs_exists(const char *fstype) {
|
||||
const char *mkfs;
|
||||
int r;
|
||||
|
||||
assert(fstype);
|
||||
|
||||
if (STR_IN_SET(fstype, "auto", "swap")) /* these aren't real file system types, refuse early */
|
||||
return -EINVAL;
|
||||
|
||||
mkfs = strjoina("mkfs.", fstype);
|
||||
if (!filename_is_valid(mkfs)) /* refuse file system types with slashes and similar */
|
||||
return -EINVAL;
|
||||
|
||||
r = find_binary(mkfs, NULL);
|
||||
if (r == -ENOENT)
|
||||
return false;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int make_filesystem(
|
||||
const char *node,
|
||||
const char *fstype,
|
||||
const char *label,
|
||||
sd_id128_t uuid,
|
||||
bool discard) {
|
||||
|
||||
_cleanup_free_ char *mkfs = NULL;
|
||||
int r;
|
||||
|
||||
assert(node);
|
||||
assert(fstype);
|
||||
assert(label);
|
||||
|
||||
if (streq(fstype, "swap")) {
|
||||
r = find_binary("mkswap", &mkfs);
|
||||
if (r == -ENOENT)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EPROTONOSUPPORT), "mkswap binary not available.");
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to determine whether mkswap binary exists: %m");
|
||||
} else {
|
||||
r = mkfs_exists(fstype);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to determine whether mkfs binary for %s exists: %m", fstype);
|
||||
if (r == 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EPROTONOSUPPORT), "mkfs binary for %s is not available.", fstype);
|
||||
|
||||
mkfs = strjoin("mkfs.", fstype);
|
||||
if (!mkfs)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
r = safe_fork("(mkfs)", FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG|FORK_LOG|FORK_WAIT|FORK_STDOUT_TO_STDERR, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
char suuid[ID128_UUID_STRING_MAX];
|
||||
|
||||
/* Child */
|
||||
id128_to_uuid_string(uuid, suuid);
|
||||
|
||||
if (streq(fstype, "ext4"))
|
||||
(void) execlp(mkfs, mkfs,
|
||||
"-L", label,
|
||||
"-U", suuid,
|
||||
"-I", "256",
|
||||
"-O", "has_journal",
|
||||
"-m", "0",
|
||||
"-E", discard ? "lazy_itable_init=1,discard" : "lazy_itable_init=1,nodiscard",
|
||||
node, NULL);
|
||||
|
||||
else if (streq(fstype, "btrfs")) {
|
||||
if (discard)
|
||||
(void) execlp(mkfs, mkfs, "-L", label, "-U", suuid, node, NULL);
|
||||
else
|
||||
(void) execlp(mkfs, mkfs, "-L", label, "-U", suuid, "--nodiscard", node, NULL);
|
||||
|
||||
} else if (streq(fstype, "xfs")) {
|
||||
const char *j;
|
||||
|
||||
j = strjoina("uuid=", suuid);
|
||||
if (discard)
|
||||
(void) execlp(mkfs, mkfs, "-L", label, "-m", j, "-m", "reflink=1", node, NULL);
|
||||
else
|
||||
(void) execlp(mkfs, mkfs, "-L", label, "-m", j, "-m", "reflink=1", "-K", node, NULL);
|
||||
|
||||
} else if (streq(fstype, "vfat")) {
|
||||
char mangled_label[8 + 3 + 1], vol_id[8 + 1];
|
||||
|
||||
/* Classic FAT only allows 11 character uppercase labels */
|
||||
strncpy(mangled_label, label, sizeof(mangled_label)-1);
|
||||
mangled_label[sizeof(mangled_label)-1] = 0;
|
||||
ascii_strupper(mangled_label);
|
||||
|
||||
xsprintf(vol_id, "%08" PRIx32,
|
||||
((uint32_t) uuid.bytes[0] << 24) |
|
||||
((uint32_t) uuid.bytes[1] << 16) |
|
||||
((uint32_t) uuid.bytes[2] << 8) |
|
||||
((uint32_t) uuid.bytes[3])); /* Take first 32 byte of UUID */
|
||||
|
||||
(void) execlp(mkfs, mkfs,
|
||||
"-i", vol_id,
|
||||
"-n", mangled_label,
|
||||
"-F", "32", /* yes, we force FAT32 here */
|
||||
node, NULL);
|
||||
|
||||
} else if (streq(fstype, "swap")) {
|
||||
|
||||
(void) execlp(mkfs, mkfs,
|
||||
"-L", label,
|
||||
"-U", suuid,
|
||||
node, NULL);
|
||||
|
||||
} else
|
||||
/* Generic fallback for all other file systems */
|
||||
(void) execlp(mkfs, mkfs, node, NULL);
|
||||
|
||||
log_error_errno(errno, "Failed to execute %s: %m", mkfs);
|
||||
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
10
src/shared/mkfs-util.h
Normal file
10
src/shared/mkfs-util.h
Normal file
@ -0,0 +1,10 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "sd-id128.h"
|
||||
|
||||
int mkfs_exists(const char *fstype);
|
||||
|
||||
int make_filesystem(const char *node, const char *fstype, const char *label, sd_id128_t uuid, bool discard);
|
Loading…
x
Reference in New Issue
Block a user