1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2024-12-22 13:33:56 +03:00

Merge pull request #7237 from keszybz/growfs

Create and grow filesystems
This commit is contained in:
Lennart Poettering 2017-12-01 17:58:58 +01:00 committed by GitHub
commit 1a2d4d7084
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 1339 additions and 341 deletions

View File

@ -569,6 +569,13 @@ manpages = [
['systemd-machine-id-commit.service', '8', [], ''],
['systemd-machine-id-setup', '1', [], ''],
['systemd-machined.service', '8', ['systemd-machined'], 'ENABLE_MACHINED'],
['systemd-makefs@.service',
'8',
['systemd-growfs',
'systemd-growfs@.service',
'systemd-makefs',
'systemd-makeswap@.service'],
''],
['systemd-modules-load.service', '8', ['systemd-modules-load'], 'HAVE_KMOD'],
['systemd-mount', '1', ['systemd-umount'], ''],
['systemd-networkd-wait-online.service',

View File

@ -0,0 +1,120 @@
<?xml version="1.0"?>
<!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<!--
SPDX-License-Identifier: LGPL-2.1+
This file is part of systemd.
Copyright 2017 Zbigniew Jędrzejewski-Szmek
systemd is free software; you can redistribute it and/or modify it
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/>.
-->
<refentry id="systemd-makefs@.service">
<refentryinfo>
<title>systemd-makefs@.service</title>
<productname>systemd</productname>
<authorgroup>
<author>
<contrib>Developer</contrib>
<firstname>Zbigniew</firstname>
<surname>Jędrzejewski-Szmek</surname>
<email>zbyszek@in.waw.pl</email>
</author>
</authorgroup>
</refentryinfo>
<refmeta>
<refentrytitle>systemd-makefs@.service</refentrytitle>
<manvolnum>8</manvolnum>
</refmeta>
<refnamediv>
<refname>systemd-makefs@.service</refname>
<refname>systemd-makeswap@.service</refname>
<refname>systemd-growfs@.service</refname>
<refname>systemd-makefs</refname>
<refname>systemd-growfs</refname>
<refpurpose>Creating and growing file systems on demand</refpurpose>
</refnamediv>
<refsynopsisdiv>
<para><filename>systemd-makefs@<replaceable>device</replaceable>.service</filename></para>
<para><filename>systemd-makeswap@<replaceable>device</replaceable>.service</filename></para>
<para><filename>systemd-growfs@<replaceable>mountpoint</replaceable>.service</filename></para>
<para><filename>/usr/lib/systemd/systemd-makefs</filename></para>
<para><filename>/usr/lib/systemd/systemd-growfs</filename></para>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para><filename>systemd-makefs@.service</filename>,
<filename>systemd-makeswap@.service</filename>, and
<filename>systemd-growfs@.service</filename> are used to implement the
<option>x-systemd.makefs</option> and <option>x-systemd.growfs</option> options
in <citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
see <citerefentry><refentrytitle>systemd.mount</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
They are instantiated for each device for which the file system or swap structure
needs to be initalized, and for each mount point where the file system needs to
be grown.</para>
<para>These services are started at boot, either right before or right after the
mount point or swap device are used.</para>
<para><filename>systemd-makefs</filename> knows very little about specific file
systems and swap devices, and after checking that the block device does not already
contain a file system or other content, it will execute binaries specific to
each filesystem type (<filename>/sbin/mkfs.*</filename>).</para>
<para><filename>systemd-growfs</filename> knows very little about specific file
systems and swap devices, and will instruct the kernel to grow the mounted
filesystem to full size of the underlying block device. Nevertheless, it needs
to know the
<citerefentry project='man-pages'><refentrytitle>ioctl</refentrytitle><manvolnum>2</manvolnum></citerefentry>
number specific to each file system, so only certain types are supported.
Currently:
<citerefentry project='man-pages'><refentrytitle>ext4</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
btrfs (see
<citerefentry project='man-pages'><refentrytitle>btrfs-man5</refentrytitle><manvolnum>5</manvolnum></citerefentry>),
<!-- yes, that's what the man page is called. -->
and dm-crypt partitions (see
<citerefentry project='die-net'><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>).
</para>
<para>If the creation of a file system or swap device fails, the mount point or
swap is failed too. If the growing of a file system fails, a warning is emitted.
</para>
</refsect1>
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>mkfs.btrfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>mkfs.cramfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>mkfs.ext4</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>mkfs.fat</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>mkfs.hfsplus</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>mkfs.minix</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>mkfs.ntfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry project='man-pages'><refentrytitle>mkfs.xfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>

View File

@ -318,6 +318,44 @@
</listitem>
</varlistentry>
<varlistentry>
<term><option>x-systemd.makefs</option></term>
<listitem><para>The file system or swap structure will be intialized
on the device. If the device is not "empty", i.e. it contains any signature,
the operation will be skipped. It is hence expected that this option
remains set even after the device has been initalized.</para>
<para>Note that this option can only be used in
<filename>/etc/fstab</filename>, and will be ignored when part of the
<varname>Options=</varname> setting in a unit file.</para>
<para>See
<citerefentry><refentrytitle>systemd-makefs@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
</para>
<para><citerefentry project='man-pages'><refentrytitle>wipefs</refentrytitle><manvolnum>8</manvolnum></citerefentry>
may be used to remove any signatures from a block device to force
<option>x-systemd.makefs</option> to reinitialize the device.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>x-systemd.growfs</option></term>
<listitem><para>The file system will be grown to occupy the full block
device. If the file system is already at maximum size, no action will
be performed. It is hence expected that this option remains set even after
the file system has been grown. Only certain file system types are supported,
see
<citerefentry><refentrytitle>systemd-makefs@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
for details.</para>
<para>Note that this option can only be used in
<filename>/etc/fstab</filename>, and will be ignored when part of the
<varname>Options=</varname> setting in a unit file.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>_netdev</option></term>

View File

@ -182,6 +182,8 @@ conf.set_quoted('CATALOG_DATABASE', join_paths(catalog
conf.set_quoted('SYSTEMD_CGROUP_AGENT_PATH', join_paths(rootlibexecdir, 'systemd-cgroups-agent'))
conf.set_quoted('SYSTEMD_BINARY_PATH', join_paths(rootlibexecdir, 'systemd'))
conf.set_quoted('SYSTEMD_FSCK_PATH', join_paths(rootlibexecdir, 'systemd-fsck'))
conf.set_quoted('SYSTEMD_MAKEFS_PATH', join_paths(rootlibexecdir, 'systemd-makefs'))
conf.set_quoted('SYSTEMD_GROWFS_PATH', join_paths(rootlibexecdir, 'systemd-growfs'))
conf.set_quoted('SYSTEMD_SHUTDOWN_BINARY_PATH', join_paths(rootlibexecdir, 'systemd-shutdown'))
conf.set_quoted('SYSTEMD_SLEEP_BINARY_PATH', join_paths(rootlibexecdir, 'systemd-sleep'))
conf.set_quoted('SYSTEMCTL_BINARY_PATH', join_paths(rootbindir, 'systemctl'))
@ -1936,6 +1938,23 @@ executable('systemd-fsck',
install : true,
install_dir : rootlibexecdir)
executable('systemd-growfs',
'src/partition/growfs.c',
include_directories : includes,
link_with : [libshared],
dependencies : [libcryptsetup],
install_rpath : rootlibexecdir,
install : true,
install_dir : rootlibexecdir)
executable('systemd-makefs',
'src/partition/makefs.c',
include_directories : includes,
link_with : [libshared],
install_rpath : rootlibexecdir,
install : true,
install_dir : rootlibexecdir)
executable('systemd-sleep',
'src/sleep/sleep.c',
include_directories : includes,

View File

@ -42,6 +42,7 @@
#include "btrfs-util.h"
#include "chattr-util.h"
#include "copy.h"
#include "device-nodes.h"
#include "fd-util.h"
#include "fileio.h"
#include "io-util.h"
@ -910,7 +911,8 @@ int btrfs_subvol_set_subtree_quota_limit(const char *path, uint64_t subvol_id, u
int btrfs_resize_loopback_fd(int fd, uint64_t new_size, bool grow_only) {
struct btrfs_ioctl_vol_args args = {};
_cleanup_free_ char *p = NULL, *loop = NULL, *backing = NULL;
char p[SYS_BLOCK_PATH_MAX("/loop/backing_file")];
_cleanup_free_ char *backing = NULL;
_cleanup_close_ int loop_fd = -1, backing_fd = -1;
struct stat st;
dev_t dev = 0;
@ -930,8 +932,7 @@ int btrfs_resize_loopback_fd(int fd, uint64_t new_size, bool grow_only) {
if (r == 0)
return -ENODEV;
if (asprintf(&p, "/sys/dev/block/%u:%u/loop/backing_file", major(dev), minor(dev)) < 0)
return -ENOMEM;
xsprintf_sys_block_path(p, "/loop/backing_file", dev);
r = read_one_line_file(p, &backing);
if (r == -ENOENT)
return -ENODEV;
@ -955,9 +956,8 @@ int btrfs_resize_loopback_fd(int fd, uint64_t new_size, bool grow_only) {
if (grow_only && new_size < (uint64_t) st.st_size)
return -EINVAL;
if (asprintf(&loop, "/dev/block/%u:%u", major(dev), minor(dev)) < 0)
return -ENOMEM;
loop_fd = open(loop, O_RDWR|O_CLOEXEC|O_NOCTTY);
xsprintf_sys_block_path(p, NULL, dev);
loop_fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY);
if (loop_fd < 0)
return -errno;

27
src/basic/crypt-util.c Normal file
View File

@ -0,0 +1,27 @@
/***
This file is part of systemd.
Copyright 2017 Zbigniew Jędrzejewski-Szmek
systemd is free software; you can redistribute it and/or modify it
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/>.
***/
#if HAVE_LIBCRYPTSETUP
#include "crypt-util.h"
#include "log.h"
void cryptsetup_log_glue(int level, const char *msg, void *usrptr) {
log_debug("%s", msg);
}
#endif

34
src/basic/crypt-util.h Normal file
View File

@ -0,0 +1,34 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
Copyright 2017 Zbigniew Jędrzejewski-Szmek
systemd is free software; you can redistribute it and/or modify it
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/>.
***/
#if HAVE_LIBCRYPTSETUP
#include <libcryptsetup.h>
#include "macro.h"
/* libcryptsetup define for any LUKS version, compatible with libcryptsetup 1.x */
#ifndef CRYPT_LUKS
#define CRYPT_LUKS NULL
#endif
DEFINE_TRIVIAL_CLEANUP_FUNC(struct crypt_device *, crypt_free);
void cryptsetup_log_glue(int level, const char *msg, void *usrptr);
#endif

View File

@ -23,5 +23,18 @@
#include <stddef.h>
#include <sys/types.h>
#include "macro.h"
#include "stdio-util.h"
int encode_devnode_name(const char *str, char *str_enc, size_t len);
int whitelisted_char_for_devnode(char c, const char *additional);
#define SYS_BLOCK_PATH_MAX(suffix) \
(strlen("/sys/dev/block/") + DECIMAL_STR_MAX(dev_t) + 1 + DECIMAL_STR_MAX(dev_t) + strlen_ptr(suffix))
#define xsprintf_sys_block_path(buf, suffix, devno) \
xsprintf(buf, "/sys/dev/block/%u:%u%s", major(devno), minor(devno), strempty(suffix))
#define DEV_NUM_PATH_MAX \
(strlen("/dev/block/") + DECIMAL_STR_MAX(dev_t) + 1 + DECIMAL_STR_MAX(dev_t))
#define xsprintf_dev_num_path(buf, type, devno) \
xsprintf(buf, "/dev/%s/%u:%u", type, major(devno), minor(devno))

View File

@ -661,10 +661,19 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
todo += m;
/* Just a single slash? Then we reached the end. */
if (isempty(first) || path_equal(first, "/"))
/* Empty? Then we reached the end. */
if (isempty(first))
break;
/* Just a single slash? Then we reached the end. */
if (path_equal(first, "/")) {
/* Preserve the trailing slash */
if (!strextend(&done, "/", NULL))
return -ENOMEM;
break;
}
/* Just a dot? Then let's eat this up. */
if (path_equal(first, "/."))
continue;
@ -726,7 +735,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
if (fstat(child, &st) < 0)
return -errno;
if ((flags & CHASE_NO_AUTOFS) &&
fd_check_fstype(child, AUTOFS_SUPER_MAGIC) > 0)
fd_is_fs_type(child, AUTOFS_SUPER_MAGIC) > 0)
return -EREMOTE;
if (S_ISLNK(st.st_mode)) {

View File

@ -61,6 +61,8 @@ basic_sources_plain = files('''
copy.h
cpu-set-util.c
cpu-set-util.h
crypt-util.c
crypt-util.h
def.h
device-nodes.c
device-nodes.h

View File

@ -1271,4 +1271,8 @@ struct fib_rule_uid_range {
#define AF_VSOCK 40
#endif
#ifndef EXT4_IOC_RESIZE_FS
# define EXT4_IOC_RESIZE_FS _IOW('f', 16, __u64)
#endif
#include "missing_syscall.h"

View File

@ -278,6 +278,7 @@ int path_is_mount_point(const char *t, const char *root, int flags) {
int r;
assert(t);
assert((flags & ~AT_SYMLINK_FOLLOW) == 0);
if (path_equal(t, "/"))
return 1;
@ -302,7 +303,7 @@ int path_is_mount_point(const char *t, const char *root, int flags) {
if (fd < 0)
return -errno;
return fd_is_mount_point(fd, basename(t), flags);
return fd_is_mount_point(fd, last_path_component(t), flags);
}
int path_get_mnt_id(const char *path, int *ret) {

View File

@ -703,6 +703,37 @@ char* dirname_malloc(const char *path) {
return dir2;
}
const char *last_path_component(const char *path) {
/* Finds the last component of the path, preserving the
* optional trailing slash that signifies a directory.
* a/b/c c
* a/b/c/ c/
* / /
* // → /
* /foo/a a
* /foo/a/ a/
* This is different than basename, which returns "" when
* a trailing slash is present.
*/
unsigned l, k;
l = k = strlen(path);
if (l == 0) /* special case — an empty string */
return path;
while (k > 0 && path[k-1] == '/')
k--;
if (k == 0) /* the root directory */
return path + l - 1;
while (k > 0 && path[k-1] != '/')
k--;
return path + k;
}
bool filename_is_valid(const char *p) {
const char *e;

View File

@ -130,6 +130,7 @@ char *prefix_root(const char *root, const char *path);
int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg);
char* dirname_malloc(const char *path);
const char *last_path_component(const char *path);
bool filename_is_valid(const char *p) _pure_;
bool path_is_normalized(const char *p) _pure_;

View File

@ -193,7 +193,7 @@ bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
return F_TYPE_EQUAL(s->f_type, magic_value);
}
int fd_check_fstype(int fd, statfs_f_type_t magic_value) {
int fd_is_fs_type(int fd, statfs_f_type_t magic_value) {
struct statfs s;
if (fstatfs(fd, &s) < 0)
@ -202,14 +202,14 @@ int fd_check_fstype(int fd, statfs_f_type_t magic_value) {
return is_fs_type(&s, magic_value);
}
int path_check_fstype(const char *path, statfs_f_type_t magic_value) {
int path_is_fs_type(const char *path, statfs_f_type_t magic_value) {
_cleanup_close_ int fd = -1;
fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
if (fd < 0)
return -errno;
return fd_check_fstype(fd, magic_value);
return fd_is_fs_type(fd, magic_value);
}
bool is_temporary_fs(const struct statfs *s) {

View File

@ -57,8 +57,8 @@ int files_same(const char *filea, const char *fileb, int flags);
typedef typeof(((struct statfs*)NULL)->f_type) statfs_f_type_t;
bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) _pure_;
int fd_check_fstype(int fd, statfs_f_type_t magic_value);
int path_check_fstype(const char *path, statfs_f_type_t magic_value);
int fd_is_fs_type(int fd, statfs_f_type_t magic_value);
int path_is_fs_type(const char *path, statfs_f_type_t magic_value);
bool is_temporary_fs(const struct statfs *s) _pure_;
int fd_is_temporary_fs(int fd);

View File

@ -39,6 +39,7 @@
#include "build.h"
#include "cgroup-util.h"
#include "def.h"
#include "device-nodes.h"
#include "dirent-util.h"
#include "fd-util.h"
#include "fileio.h"
@ -118,63 +119,42 @@ int socket_from_display(const char *display, char **path) {
}
int block_get_whole_disk(dev_t d, dev_t *ret) {
char *p, *s;
char p[SYS_BLOCK_PATH_MAX("/partition")];
_cleanup_free_ char *s = NULL;
int r;
unsigned n, m;
assert(ret);
/* If it has a queue this is good enough for us */
if (asprintf(&p, "/sys/dev/block/%u:%u/queue", major(d), minor(d)) < 0)
return -ENOMEM;
r = access(p, F_OK);
free(p);
if (r >= 0) {
xsprintf_sys_block_path(p, "/queue", d);
if (access(p, F_OK) >= 0) {
*ret = d;
return 0;
}
/* If it is a partition find the originating device */
if (asprintf(&p, "/sys/dev/block/%u:%u/partition", major(d), minor(d)) < 0)
return -ENOMEM;
r = access(p, F_OK);
free(p);
if (r < 0)
xsprintf_sys_block_path(p, "/partition", d);
if (access(p, F_OK) < 0)
return -ENOENT;
/* Get parent dev_t */
if (asprintf(&p, "/sys/dev/block/%u:%u/../dev", major(d), minor(d)) < 0)
return -ENOMEM;
xsprintf_sys_block_path(p, "/../dev", d);
r = read_one_line_file(p, &s);
free(p);
if (r < 0)
return r;
r = sscanf(s, "%u:%u", &m, &n);
free(s);
if (r != 2)
return -EINVAL;
/* Only return this if it is really good enough for us. */
if (asprintf(&p, "/sys/dev/block/%u:%u/queue", m, n) < 0)
return -ENOMEM;
xsprintf_sys_block_path(p, "/queue", makedev(m, n));
if (access(p, F_OK) < 0)
return -ENOENT;
r = access(p, F_OK);
free(p);
if (r >= 0) {
*ret = makedev(m, n);
return 0;
}
return -ENOENT;
*ret = makedev(m, n);
return 0;
}
bool kexec_loaded(void) {
@ -749,7 +729,8 @@ int get_block_device(const char *path, dev_t *dev) {
int get_block_device_harder(const char *path, dev_t *dev) {
_cleanup_closedir_ DIR *d = NULL;
_cleanup_free_ char *p = NULL, *t = NULL;
_cleanup_free_ char *t = NULL;
char p[SYS_BLOCK_PATH_MAX("/slaves")];
struct dirent *de, *found = NULL;
const char *q;
unsigned maj, min;
@ -767,9 +748,7 @@ int get_block_device_harder(const char *path, dev_t *dev) {
if (r <= 0)
return r;
if (asprintf(&p, "/sys/dev/block/%u:%u/slaves", major(dt), minor(dt)) < 0)
return -ENOMEM;
xsprintf_sys_block_path(p, "/slaves", dt);
d = opendir(p);
if (!d) {
if (errno == ENOENT)

View File

@ -19,7 +19,6 @@
***/
#include <errno.h>
#include <libcryptsetup.h>
#include <mntent.h>
#include <string.h>
#include <sys/mman.h>
@ -28,6 +27,7 @@
#include "alloc-util.h"
#include "ask-password-api.h"
#include "crypt-util.h"
#include "device-util.h"
#include "escape.h"
#include "fileio.h"
@ -39,11 +39,6 @@
#include "strv.h"
#include "util.h"
/* libcryptsetup define for any LUKS version, compatible with libcryptsetup 1.x */
#ifndef CRYPT_LUKS
#define CRYPT_LUKS NULL
#endif
/* internal helper */
#define ANY_LUKS "LUKS"
@ -254,10 +249,6 @@ static int parse_options(const char *options) {
return 0;
}
static void log_glue(int level, const char *msg, void *usrptr) {
log_debug("%s", msg);
}
static int disk_major_minor(const char *path, char **ret) {
struct stat st;
@ -604,7 +595,7 @@ static int help(void) {
}
int main(int argc, char *argv[]) {
struct crypt_device *cd = NULL;
_cleanup_(crypt_freep) struct crypt_device *cd = NULL;
int r = -EINVAL;
if (argc <= 1) {
@ -666,7 +657,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
crypt_set_log_callback(cd, log_glue, NULL);
crypt_set_log_callback(cd, cryptsetup_log_glue, NULL);
status = crypt_status(cd, argv[2]);
if (IN_SET(status, CRYPT_ACTIVE, CRYPT_BUSY)) {
@ -750,7 +741,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
crypt_set_log_callback(cd, log_glue, NULL);
crypt_set_log_callback(cd, cryptsetup_log_glue, NULL);
r = crypt_deactivate(cd, argv[2]);
if (r < 0) {
@ -766,9 +757,6 @@ int main(int argc, char *argv[]) {
r = 0;
finish:
if (cd)
crypt_free(cd);
free(arg_cipher);
free(arg_hash);
free(arg_header);

View File

@ -47,6 +47,14 @@
#include "virt.h"
#include "volatile-util.h"
typedef enum MountpointFlags {
NOAUTO = 1 << 0,
NOFAIL = 1 << 1,
AUTOMOUNT = 1 << 2,
MAKEFS = 1 << 3,
GROWFS = 1 << 4,
} MountpointFlags;
static const char *arg_dest = "/tmp";
static const char *arg_dest_late = "/tmp";
static bool arg_fstab_enabled = true;
@ -91,8 +99,7 @@ static int write_what(FILE *f, const char *what) {
static int add_swap(
const char *what,
struct mntent *me,
bool noauto,
bool nofail) {
MountpointFlags flags) {
_cleanup_free_ char *name = NULL, *unit = NULL;
_cleanup_fclose_ FILE *f = NULL;
@ -150,9 +157,19 @@ static int add_swap(
if (r < 0)
return r;
if (!noauto) {
if (flags & MAKEFS) {
r = generator_hook_up_mkswap(arg_dest, what);
if (r < 0)
return r;
}
if (flags & GROWFS)
/* TODO: swap devices must be wiped and recreated */
log_warning("%s: growing swap devices is currently unsupported.", what);
if (!(flags & NOAUTO)) {
r = generator_add_symlink(arg_dest, SPECIAL_SWAP_TARGET,
nofail ? "wants" : "requires", name);
(flags & NOFAIL) ? "wants" : "requires", name);
if (r < 0)
return r;
}
@ -297,17 +314,16 @@ static int add_mount(
const char *fstype,
const char *opts,
int passno,
bool noauto,
bool nofail,
bool automount,
MountpointFlags flags,
const char *post,
const char *source) {
_cleanup_free_ char
*name = NULL, *unit = NULL,
*name = NULL,
*automount_name = NULL, *automount_unit = NULL,
*filtered = NULL,
*where_escaped = NULL;
const char *unit;
_cleanup_fclose_ FILE *f = NULL;
int r;
@ -330,23 +346,21 @@ static int add_mount(
return 0;
if (path_equal(where, "/")) {
if (noauto)
if (flags & NOAUTO)
log_warning("Ignoring \"noauto\" for root device");
if (nofail)
if (flags & NOFAIL)
log_warning("Ignoring \"nofail\" for root device");
if (automount)
if (flags & AUTOMOUNT)
log_warning("Ignoring automount option for root device");
noauto = nofail = automount = false;
SET_FLAG(flags, NOAUTO | NOFAIL | AUTOMOUNT, false);
}
r = unit_name_from_path(where, ".mount", &name);
if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m");
unit = strjoin(dest, "/", name);
if (!unit)
return log_oom();
unit = strjoina(dest, "/", name);
f = fopen(unit, "wxe");
if (!f)
@ -363,7 +377,7 @@ static int add_mount(
"Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
source);
if (STRPTR_IN_SET(fstype, "nfs", "nfs4") && !automount &&
if (STRPTR_IN_SET(fstype, "nfs", "nfs4") && !(flags & AUTOMOUNT) &&
fstab_test_yes_no_option(opts, "bg\0" "fg\0")) {
/* The default retry timeout that mount.nfs uses for 'bg' mounts
* is 10000 minutes, where as it uses 2 minutes for 'fg' mounts.
@ -374,13 +388,13 @@ static int add_mount(
* By placing these options first, they can be over-ridden by
* settings in /etc/fstab. */
opts = strjoina("x-systemd.mount-timeout=infinity,retry=10000,", opts, ",fg");
nofail = true;
SET_FLAG(flags, NOFAIL, true);
}
if (!nofail && !automount)
if (!(flags & NOFAIL) && !(flags & AUTOMOUNT))
fprintf(f, "Before=%s\n", post);
if (!automount && opts) {
if (!(flags & AUTOMOUNT) && opts) {
r = write_after(f, opts);
if (r < 0)
return r;
@ -444,14 +458,26 @@ static int add_mount(
if (r < 0)
return log_error_errno(r, "Failed to write unit file %s: %m", unit);
if (!noauto && !automount) {
r = generator_add_symlink(dest, post,
nofail ? "wants" : "requires", name);
if (flags & MAKEFS) {
r = generator_hook_up_mkfs(dest, what, where, fstype);
if (r < 0)
return r;
}
if (automount) {
if (flags & GROWFS) {
r = generator_hook_up_growfs(dest, where, post);
if (r < 0)
return r;
}
if (!(flags & NOAUTO) && !(flags & AUTOMOUNT)) {
r = generator_add_symlink(dest, post,
(flags & NOFAIL) ? "wants" : "requires", name);
if (r < 0)
return r;
}
if (flags & AUTOMOUNT) {
r = unit_name_from_path(where, ".automount", &automount_name);
if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m");
@ -504,7 +530,7 @@ static int add_mount(
return log_error_errno(r, "Failed to write unit file %s: %m", automount_unit);
r = generator_add_symlink(dest, post,
nofail ? "wants" : "requires", automount_name);
(flags & NOFAIL) ? "wants" : "requires", automount_name);
if (r < 0)
return r;
}
@ -529,7 +555,7 @@ static int parse_fstab(bool initrd) {
while ((me = getmntent(f))) {
_cleanup_free_ char *where = NULL, *what = NULL, *canonical_where = NULL;
bool noauto, nofail;
bool makefs, growfs, noauto, nofail;
int k;
if (initrd && !mount_in_initrd(me))
@ -571,14 +597,18 @@ static int parse_fstab(bool initrd) {
}
}
makefs = fstab_test_option(me->mnt_opts, "x-systemd.makefs\0");
growfs = fstab_test_option(me->mnt_opts, "x-systemd.growfs\0");
noauto = fstab_test_yes_no_option(me->mnt_opts, "noauto\0" "auto\0");
nofail = fstab_test_yes_no_option(me->mnt_opts, "nofail\0" "fail\0");
log_debug("Found entry what=%s where=%s type=%s nofail=%s noauto=%s",
log_debug("Found entry what=%s where=%s type=%s makefs=%s nofail=%s noauto=%s",
what, where, me->mnt_type,
yes_no(makefs),
yes_no(noauto), yes_no(nofail));
if (streq(me->mnt_type, "swap"))
k = add_swap(what, me, noauto, nofail);
k = add_swap(what, me,
makefs*MAKEFS | growfs*GROWFS | noauto*NOAUTO | nofail*NOFAIL);
else {
bool automount;
const char *post;
@ -600,14 +630,12 @@ static int parse_fstab(bool initrd) {
me->mnt_type,
me->mnt_opts,
me->mnt_passno,
noauto,
nofail,
automount,
makefs*MAKEFS | growfs*GROWFS | noauto*NOAUTO | nofail*NOFAIL | automount*AUTOMOUNT,
post,
fstab_path);
}
if (k < 0)
if (r >= 0 && k < 0)
r = k;
}
@ -663,9 +691,7 @@ static int add_sysroot_mount(void) {
arg_root_fstype,
opts,
is_device_path(what) ? 1 : 0, /* passno */
false, /* noauto off */
false, /* nofail off */
false, /* automount off */
0, /* makefs off, growfs off, noauto off, nofail off, automount off */
SPECIAL_INITRD_ROOT_FS_TARGET,
"/proc/cmdline");
}
@ -718,9 +744,7 @@ static int add_sysroot_usr_mount(void) {
arg_usr_fstype,
opts,
is_device_path(what) ? 1 : 0, /* passno */
false, /* noauto off */
false, /* nofail off */
false, /* automount off */
0,
SPECIAL_INITRD_FS_TARGET,
"/proc/cmdline");
}
@ -759,9 +783,7 @@ static int add_volatile_var(void) {
"tmpfs",
"mode=0755",
0,
false,
false,
false,
0,
SPECIAL_LOCAL_FS_TARGET,
"/proc/cmdline");
}

View File

@ -405,7 +405,7 @@ int mount_sysfs(const char *dest, MountSettingsMask mount_settings) {
unsigned long extra_flags = 0;
top = prefix_roota(dest, "/sys");
r = path_check_fstype(top, SYSFS_MAGIC);
r = path_is_fs_type(top, SYSFS_MAGIC);
if (r < 0)
return log_error_errno(r, "Failed to determine filesystem type of %s: %m", top);
/* /sys might already be mounted as sysfs by the outer child in the

317
src/partition/growfs.c Normal file
View File

@ -0,0 +1,317 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
Copyright 2017 Zbigniew Jędrzejewski-Szmek
systemd is free software; you can redistribute it and/or modify it
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 <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <linux/magic.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/vfs.h>
#include "crypt-util.h"
#include "device-nodes.h"
#include "dissect-image.h"
#include "escape.h"
#include "fd-util.h"
#include "format-util.h"
#include "log.h"
#include "missing.h"
#include "mount-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "strv.h"
const char *arg_target = NULL;
bool arg_dry_run = false;
static int resize_ext4(const char *path, int mountfd, int devfd, uint64_t numblocks, uint64_t blocksize) {
assert((uint64_t) (int) blocksize == blocksize);
if (arg_dry_run)
return 0;
if (ioctl(mountfd, EXT4_IOC_RESIZE_FS, &numblocks) != 0)
return log_error_errno(errno, "Failed to resize \"%s\" to %"PRIu64" blocks (ext4): %m",
path, numblocks);
return 0;
}
static int resize_btrfs(const char *path, int mountfd, int devfd, uint64_t numblocks, uint64_t blocksize) {
struct btrfs_ioctl_vol_args args = {};
int r;
assert((uint64_t) (int) blocksize == blocksize);
/* https://bugzilla.kernel.org/show_bug.cgi?id=118111 */
if (numblocks * blocksize < 256*1024*1024) {
log_warning("%s: resizing of btrfs volumes smaller than 256M is not supported", path);
return -EOPNOTSUPP;
}
r = snprintf(args.name, sizeof(args.name), "%"PRIu64, numblocks * blocksize);
/* The buffer is large enough for any number to fit... */
assert((size_t) r < sizeof(args.name));
if (arg_dry_run)
return 0;
if (ioctl(mountfd, BTRFS_IOC_RESIZE, &args) != 0)
return log_error_errno(errno, "Failed to resize \"%s\" to %"PRIu64" blocks (btrfs): %m",
path, numblocks);
return 0;
}
static int resize_crypt_luks_device(dev_t devno, const char *fstype, dev_t main_devno) {
char devpath[DEV_NUM_PATH_MAX], main_devpath[DEV_NUM_PATH_MAX];
_cleanup_close_ int main_devfd = -1;
_cleanup_(crypt_freep) struct crypt_device *cd = NULL;
uint64_t size;
int r;
xsprintf_dev_num_path(main_devpath, "block", main_devno);
main_devfd = open(main_devpath, O_RDONLY|O_CLOEXEC);
if (main_devfd < 0)
return log_error_errno(errno, "Failed to open \"%s\": %m", main_devpath);
if (ioctl(main_devfd, BLKGETSIZE64, &size) != 0)
return log_error_errno(errno, "Failed to query size of \"%s\" (before resize): %m",
main_devpath);
log_debug("%s is %"PRIu64" bytes", main_devpath, size);
xsprintf_dev_num_path(devpath, "block", devno);
r = crypt_init(&cd, devpath);
if (r < 0)
return log_error_errno(r, "crypt_init(\"%s\") failed: %m", devpath);
crypt_set_log_callback(cd, cryptsetup_log_glue, NULL);
r = crypt_load(cd, CRYPT_LUKS, NULL);
if (r < 0)
return log_debug_errno(r, "Failed to load LUKS metadata for %s: %m", devpath);
if (arg_dry_run)
return 0;
r = crypt_resize(cd, main_devpath, 0);
if (r < 0)
return log_error_errno(r, "crypt_resize() of %s failed: %m", devpath);
if (ioctl(main_devfd, BLKGETSIZE64, &size) != 0)
log_warning_errno(errno, "Failed to query size of \"%s\" (after resize): %m",
devpath);
else
log_debug("%s is now %"PRIu64" bytes", main_devpath, size);
return 1;
}
static int maybe_resize_slave_device(const char *mountpath, dev_t main_devno) {
dev_t devno;
char devpath[DEV_NUM_PATH_MAX];
_cleanup_free_ char *fstype = NULL;
int r;
crypt_set_log_callback(NULL, cryptsetup_log_glue, NULL);
crypt_set_debug_level(1);
r = get_block_device_harder(mountpath, &devno);
if (r < 0)
return log_error_errno(r, "Failed to determine underlying block device of \"%s\": %m",
mountpath);
log_debug("Underlying device %d:%d, main dev %d:%d, %s",
major(devno), minor(devno),
major(main_devno), minor(main_devno),
devno == main_devno ? "same" : "different");
if (devno == main_devno)
return 0;
xsprintf_dev_num_path(devpath, "block", devno);
r = probe_filesystem(devpath, &fstype);
if (r == -EUCLEAN)
return log_warning_errno(r, "Cannot reliably determine probe \"%s\", refusing to proceed.", devpath);
if (r < 0)
return log_warning_errno(r, "Failed to probe \"%s\": %m", devpath);
if (streq_ptr(fstype, "crypto_LUKS"))
return resize_crypt_luks_device(devno, fstype, main_devno);
log_debug("Don't know how to resize %s of type %s, ignoring", devpath, strnull(fstype));
return 0;
}
static void help(void) {
printf("%s [OPTIONS...] /path/to/mountpoint\n\n"
"Grow filesystem or encrypted payload to device size.\n\n"
"Options:\n"
" -h --help Show this help and exit\n"
" --version Print version string and exit\n"
" -n --dry-run Just print what would be done\n"
, program_invocation_short_name);
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
};
int c;
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version" , no_argument, NULL, ARG_VERSION },
{ "dry-run", no_argument, NULL, 'n' },
{}
};
assert(argc >= 0);
assert(argv);
while ((c = getopt_long(argc, argv, "hn", options, NULL)) >= 0)
switch(c) {
case 'h':
help();
return 0;
case ARG_VERSION:
version();
return 0;
case 'n':
arg_dry_run = true;
break;
case '?':
return -EINVAL;
default:
assert_not_reached("Unhandled option");
}
if (optind + 1 != argc) {
log_error("%s excepts exactly one argument (the mount point).",
program_invocation_short_name);
return -EINVAL;
}
arg_target = argv[optind];
return 1;
}
int main(int argc, char *argv[]) {
dev_t devno;
_cleanup_close_ int mountfd = -1, devfd = -1;
int blocksize;
uint64_t size, numblocks;
char devpath[DEV_NUM_PATH_MAX], fb[FORMAT_BYTES_MAX];
struct statfs sfs;
int r;
log_set_target(LOG_TARGET_AUTO);
log_parse_environment();
log_open();
r = parse_argv(argc, argv);
if (r < 0)
return EXIT_FAILURE;
if (r == 0)
return EXIT_SUCCESS;
r = path_is_mount_point(arg_target, NULL, 0);
if (r < 0) {
log_error_errno(r, "Failed to check if \"%s\" is a mount point: %m", arg_target);
return EXIT_FAILURE;
}
if (r == 0) {
log_error_errno(r, "\"%s\" is not a mount point: %m", arg_target);
return EXIT_FAILURE;
}
r = get_block_device(arg_target, &devno);
if (r < 0) {
log_error_errno(r, "Failed to determine block device of \"%s\": %m", arg_target);
return EXIT_FAILURE;
}
r = maybe_resize_slave_device(arg_target, devno);
if (r < 0)
return EXIT_FAILURE;
mountfd = open(arg_target, O_RDONLY|O_CLOEXEC);
if (mountfd < 0) {
log_error_errno(errno, "Failed to open \"%s\": %m", arg_target);
return EXIT_FAILURE;
}
xsprintf_dev_num_path(devpath, "block", devno);
devfd = open(devpath, O_RDONLY|O_CLOEXEC);
if (devfd < 0) {
log_error_errno(errno, "Failed to open \"%s\": %m", devpath);
return EXIT_FAILURE;
}
if (ioctl(devfd, BLKBSZGET, &blocksize) != 0) {
log_error_errno(errno, "Failed to query block size of \"%s\": %m", devpath);
return EXIT_FAILURE;
}
if (ioctl(devfd, BLKGETSIZE64, &size) != 0) {
log_error_errno(errno, "Failed to query size of \"%s\": %m", devpath);
return EXIT_FAILURE;
}
if (size % blocksize != 0)
log_notice("Partition size %"PRIu64" is not a multiple of the blocksize %d,"
" ignoring %"PRIu64" bytes", size, blocksize, size % blocksize);
numblocks = size / blocksize;
if (fstatfs(mountfd, &sfs) < 0) {
log_error_errno(errno, "Failed to stat file system \"%s\": %m", arg_target);
return EXIT_FAILURE;
}
switch(sfs.f_type) {
case EXT4_SUPER_MAGIC:
r = resize_ext4(arg_target, mountfd, devfd, numblocks, blocksize);
break;
case BTRFS_SUPER_MAGIC:
r = resize_btrfs(arg_target, mountfd, devfd, numblocks, blocksize);
break;
default:
log_error("Don't know how to resize fs %llx on \"%s\"",
(long long unsigned) sfs.f_type, arg_target);
return EXIT_FAILURE;
}
if (r < 0)
return EXIT_FAILURE;
log_info("Successfully resized \"%s\" to %s bytes (%"PRIu64" blocks of %d bytes).",
arg_target, format_bytes(fb, sizeof fb, size), numblocks, blocksize);
return EXIT_SUCCESS;
}

110
src/partition/makefs.c Normal file
View File

@ -0,0 +1,110 @@
/***
SPDX-License-Identifier: LGPL-2.1+
This file is part of systemd.
Copyright 2017 Zbigniew Jędrzejewski-Szmek
systemd is free software; you can redistribute it and/or modify it
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 <fcntl.h>
#include <signal.h>
#include <sys/prctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "alloc-util.h"
#include "dissect-image.h"
#include "signal-util.h"
#include "string-util.h"
static int makefs(const char *type, const char *device) {
const char *mkfs;
pid_t pid;
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);
pid = fork();
if (pid < 0)
return log_error_errno(errno, "fork(): %m");
if (pid == 0) {
const char *cmdline[3] = { mkfs, device, NULL };
/* Child */
(void) reset_all_signal_handlers();
(void) reset_signal_mask();
assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
execv(cmdline[0], (char**) cmdline);
_exit(EXIT_FAILURE);
}
return wait_for_terminate_and_warn(mkfs, pid, true);
}
int main(int argc, char *argv[]) {
const char *device, *type;
_cleanup_free_ char *detected = NULL;
struct stat st;
int r;
log_set_target(LOG_TARGET_AUTO);
log_parse_environment();
log_open();
if (argc != 3) {
log_error("This program expects two arguments.");
return EXIT_FAILURE;
}
type = argv[1];
device = argv[2];
if (stat(device, &st) < 0) {
r = log_error_errno(errno, "Failed to stat \"%s\": %m", device);
goto finish;
}
if (!S_ISBLK(st.st_mode))
log_info("%s is not a block device.", device);
r = probe_filesystem(device, &detected);
if (r < 0) {
log_warning_errno(r,
r == -EUCLEAN ?
"Cannot reliably determine probe \"%s\", refusing to proceed." :
"Failed to probe \"%s\": %m",
device);
goto finish;
}
if (detected) {
log_info("%s is not empty (type %s), exiting", device, detected);
goto finish;
}
r = makefs(type, device);
finish:
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}

View File

@ -25,6 +25,7 @@
#include "bootspec.h"
#include "conf-files.h"
#include "def.h"
#include "device-nodes.h"
#include "efivars.h"
#include "fd-util.h"
#include "fileio.h"
@ -420,7 +421,7 @@ static int verify_esp(
sd_id128_t *ret_uuid) {
_cleanup_blkid_free_probe_ blkid_probe b = NULL;
_cleanup_free_ char *t = NULL;
char t[DEV_NUM_PATH_MAX];
uint64_t pstart = 0, psize = 0;
struct stat st, st2;
const char *v, *t2;
@ -478,10 +479,7 @@ static int verify_esp(
if (detect_container() > 0 || geteuid() != 0)
goto finish;
r = asprintf(&t, "/dev/block/%u:%u", major(st.st_dev), minor(st.st_dev));
if (r < 0)
return log_oom();
xsprintf_dev_num_path(t, "block", st.st_dev);
errno = 0;
b = blkid_new_probe_from_filename(t);
if (!b)

View File

@ -18,12 +18,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#if HAVE_LIBCRYPTSETUP
#include <libcryptsetup.h>
#ifndef CRYPT_LUKS
#define CRYPT_LUKS NULL
#endif
#endif
#include <sys/mount.h>
#include <sys/prctl.h>
#include <sys/wait.h>
@ -32,7 +26,9 @@
#include "ask-password-api.h"
#include "blkid-util.h"
#include "copy.h"
#include "crypt-util.h"
#include "def.h"
#include "device-nodes.h"
#include "dissect-image.h"
#include "fd-util.h"
#include "fileio.h"
@ -55,25 +51,34 @@
#include "udev-util.h"
#include "xattr-util.h"
_unused_ static int probe_filesystem(const char *node, char **ret_fstype) {
int probe_filesystem(const char *node, char **ret_fstype) {
/* Try to find device content type and return it in *ret_fstype. If nothing is found,
* 0/NULL will be returned. -EUCLEAN will be returned for ambigous results, and an
* different error otherwise. */
#if HAVE_BLKID
_cleanup_blkid_free_probe_ blkid_probe b = NULL;
const char *fstype;
int r;
errno = 0;
b = blkid_new_probe_from_filename(node);
if (!b)
return -ENOMEM;
return -errno ?: -ENOMEM;
blkid_probe_enable_superblocks(b, 1);
blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
errno = 0;
r = blkid_do_safeprobe(b);
if (IN_SET(r, -2, 1)) {
log_debug("Failed to identify any partition type on partition %s", node);
if (r == 1) {
log_debug("No type detected on partition %s", node);
goto not_found;
}
if (r == -2) {
log_debug("Results ambiguous for partition %s", node);
return -EUCLEAN;
}
if (r != 0)
return -errno ?: -EIO;
@ -611,7 +616,7 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectI
if (!p->fstype && p->node) {
r = probe_filesystem(p->node, &p->fstype);
if (r < 0)
if (r < 0 && r != -EUCLEAN)
return r;
}
@ -652,7 +657,7 @@ DissectedImage* dissected_image_unref(DissectedImage *m) {
}
static int is_loop_device(const char *path) {
char s[strlen("/sys/dev/block/") + DECIMAL_STR_MAX(dev_t) + 1 + DECIMAL_STR_MAX(dev_t) + strlen("/../loop/")];
char s[SYS_BLOCK_PATH_MAX("/../loop/")];
struct stat st;
assert(path);
@ -663,13 +668,13 @@ static int is_loop_device(const char *path) {
if (!S_ISBLK(st.st_mode))
return -ENOTBLK;
xsprintf(s, "/sys/dev/block/%u:%u/loop/", major(st.st_rdev), minor(st.st_rdev));
xsprintf_sys_block_path(s, "/loop/", st.st_dev);
if (access(s, F_OK) < 0) {
if (errno != ENOENT)
return -errno;
/* The device itself isn't a loop device, but maybe it's a partition and its parent is? */
xsprintf(s, "/sys/dev/block/%u:%u/../loop/", major(st.st_rdev), minor(st.st_rdev));
xsprintf_sys_block_path(s, "/../loop/", st.st_dev);
if (access(s, F_OK) < 0)
return errno == ENOENT ? false : -errno;
}
@ -849,7 +854,7 @@ static int decrypt_partition(
DecryptedImage *d) {
_cleanup_free_ char *node = NULL, *name = NULL;
struct crypt_device *cd;
_cleanup_(crypt_freep) struct crypt_device *cd = NULL;
int r;
assert(m);
@ -876,37 +881,28 @@ static int decrypt_partition(
return log_debug_errno(r, "Failed to initialize dm-crypt: %m");
r = crypt_load(cd, CRYPT_LUKS, NULL);
if (r < 0) {
log_debug_errno(r, "Failed to load LUKS metadata: %m");
goto fail;
}
if (r < 0)
return log_debug_errno(r, "Failed to load LUKS metadata: %m");
r = crypt_activate_by_passphrase(cd, name, CRYPT_ANY_SLOT, passphrase, strlen(passphrase),
((flags & DISSECT_IMAGE_READ_ONLY) ? CRYPT_ACTIVATE_READONLY : 0) |
((flags & DISSECT_IMAGE_DISCARD_ON_CRYPTO) ? CRYPT_ACTIVATE_ALLOW_DISCARDS : 0));
if (r < 0)
if (r < 0) {
log_debug_errno(r, "Failed to activate LUKS device: %m");
if (r == -EPERM) {
r = -EKEYREJECTED;
goto fail;
return r == -EPERM ? -EKEYREJECTED : r;
}
if (r < 0)
goto fail;
d->decrypted[d->n_decrypted].name = name;
name = NULL;
d->decrypted[d->n_decrypted].device = cd;
cd = NULL;
d->n_decrypted++;
m->decrypted_node = node;
node = NULL;
return 0;
fail:
crypt_free(cd);
return r;
}
static int verity_partition(
@ -918,7 +914,7 @@ static int verity_partition(
DecryptedImage *d) {
_cleanup_free_ char *node = NULL, *name = NULL;
struct crypt_device *cd;
_cleanup_(crypt_freep) struct crypt_device *cd = NULL;
int r;
assert(m);
@ -948,30 +944,27 @@ static int verity_partition(
r = crypt_load(cd, CRYPT_VERITY, NULL);
if (r < 0)
goto fail;
return r;
r = crypt_set_data_device(cd, m->node);
if (r < 0)
goto fail;
return r;
r = crypt_activate_by_volume_key(cd, name, root_hash, root_hash_size, CRYPT_ACTIVATE_READONLY);
if (r < 0)
goto fail;
return r;
d->decrypted[d->n_decrypted].name = name;
name = NULL;
d->decrypted[d->n_decrypted].device = cd;
cd = NULL;
d->n_decrypted++;
m->decrypted_node = node;
node = NULL;
return 0;
fail:
crypt_free(cd);
return r;
}
#endif
@ -1033,7 +1026,7 @@ int dissected_image_decrypt(
if (!p->decrypted_fstype && p->decrypted_node) {
r = probe_filesystem(p->decrypted_node, &p->decrypted_fstype);
if (r < 0)
if (r < 0 && r != -EUCLEAN)
return r;
}
}

View File

@ -86,6 +86,7 @@ struct DissectedImage {
char **os_release;
};
int probe_filesystem(const char *node, char **ret_fstype);
int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectImageFlags flags, DissectedImage **ret);
DissectedImage* dissected_image_unref(DissectedImage *m);

View File

@ -83,8 +83,8 @@ static int write_fsck_sysroot_service(const char *dir, const char *what) {
fprintf(f,
"# Automatically generated by %1$s\n\n"
"[Unit]\n"
"Documentation=man:systemd-fsck-root.service(8)\n"
"Description=File System Check on %2$s\n"
"Documentation=man:systemd-fsck-root.service(8)\n"
"DefaultDependencies=no\n"
"BindsTo=%3$s\n"
"After=initrd-root-device.target local-fs-pre.target %3$s\n"
@ -248,7 +248,8 @@ int generator_write_device_deps(
r = unit_name_from_path(node, ".device", &unit);
if (r < 0)
return log_error_errno(r, "Failed to make unit name from path: %m");
return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
node);
/* See mount_add_default_dependencies for explanation why we create such
* dependencies. */
@ -266,7 +267,8 @@ int generator_write_initrd_root_device_deps(const char *dir, const char *what) {
r = unit_name_from_path(what, ".device", &unit);
if (r < 0)
return log_error_errno(r, "Failed to make unit name from path: %m");
return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
what);
return write_drop_in_format(dir, SPECIAL_INITRD_ROOT_DEVICE_TARGET, 50, "root-device",
"# Automatically generated by %s\n\n"
@ -277,3 +279,206 @@ int generator_write_initrd_root_device_deps(const char *dir, const char *what) {
unit,
unit);
}
int generator_hook_up_mkswap(
const char *dir,
const char *what) {
_cleanup_free_ char *node = NULL, *unit = NULL, *escaped = NULL, *where_unit = NULL;
_cleanup_fclose_ FILE *f = NULL;
const char *unit_file;
int r;
node = fstab_node_to_udev_node(what);
if (!node)
return log_oom();
/* Nothing to work on. */
if (!is_device_path(node)) {
log_error("Cannot format something that is not a device node: %s", node);
return -EINVAL;
}
r = unit_name_from_path_instance("systemd-mkswap", node, ".service", &unit);
if (r < 0)
return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m",
node);
unit_file = strjoina(dir, "/", unit);
log_debug("Creating %s", unit_file);
escaped = cescape(node);
if (!escaped)
return log_oom();
r = unit_name_from_path(what, ".swap", &where_unit);
if (r < 0)
return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
what);
f = fopen(unit_file, "wxe");
if (!f)
return log_error_errno(errno, "Failed to create unit file %s: %m",
unit_file);
fprintf(f,
"# Automatically generated by %s\n\n"
"[Unit]\n"
"Description=Make Swap on %%f\n"
"Documentation=man:systemd-mkswap@.service(8)\n"
"DefaultDependencies=no\n"
"BindsTo=%%i.device\n"
"After=%%i.device\n"
"Before=%s\n"
"Before=shutdown.target\n"
"\n"
"[Service]\n"
"Type=oneshot\n"
"RemainAfterExit=yes\n"
"ExecStart="SYSTEMD_MAKEFS_PATH " swap %s\n"
"TimeoutSec=0\n",
program_invocation_short_name,
where_unit,
escaped);
r = fflush_and_check(f);
if (r < 0)
return log_error_errno(r, "Failed to write unit file %s: %m", unit_file);
return generator_add_symlink(dir, where_unit, "requires", unit);
}
int generator_hook_up_mkfs(
const char *dir,
const char *what,
const char *where,
const char *type) {
_cleanup_free_ char *node = NULL, *unit = NULL, *escaped = NULL, *where_unit = NULL;
_cleanup_fclose_ FILE *f = NULL;
const char *unit_file;
int r;
node = fstab_node_to_udev_node(what);
if (!node)
return log_oom();
/* Nothing to work on. */
if (!is_device_path(node)) {
log_error("Cannot format something that is not a device node: %s", node);
return -EINVAL;
}
if (!type || streq(type, "auto")) {
log_error("Cannot format partition %s, filesystem type is not specified", node);
return -EINVAL;
}
r = unit_name_from_path_instance("systemd-mkfs", node, ".service", &unit);
if (r < 0)
return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m",
node);
unit_file = strjoina(dir, "/", unit);
log_debug("Creating %s", unit_file);
escaped = cescape(node);
if (!escaped)
return log_oom();
r = unit_name_from_path(where, ".mount", &where_unit);
if (r < 0)
return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
where);
f = fopen(unit_file, "wxe");
if (!f)
return log_error_errno(errno, "Failed to create unit file %s: %m",
unit_file);
fprintf(f,
"# Automatically generated by %s\n\n"
"[Unit]\n"
"Description=Make File System on %%f\n"
"Documentation=man:systemd-mkfs@.service(8)\n"
"DefaultDependencies=no\n"
"BindsTo=%%i.device\n"
"After=%%i.device\n"
/* fsck might or might not be used, so let's be safe and order
* ourselves before both systemd-fsck@.service and the mount unit. */
"Before=systemd-fsck@%%i.service\n"
"Before=%s\n"
"Before=shutdown.target\n"
"\n"
"[Service]\n"
"Type=oneshot\n"
"RemainAfterExit=yes\n"
"ExecStart="SYSTEMD_MAKEFS_PATH " %s %s\n"
"TimeoutSec=0\n",
program_invocation_short_name,
where_unit,
type,
escaped);
// XXX: what about local-fs-pre.target?
r = fflush_and_check(f);
if (r < 0)
return log_error_errno(r, "Failed to write unit file %s: %m", unit_file);
return generator_add_symlink(dir, where_unit, "requires", unit);
}
int generator_hook_up_growfs(
const char *dir,
const char *where,
const char *target) {
_cleanup_free_ char *unit = NULL, *escaped = NULL, *where_unit = NULL;
_cleanup_fclose_ FILE *f = NULL;
const char *unit_file;
int r;
escaped = cescape(where);
if (!escaped)
return log_oom();
r = unit_name_from_path_instance("systemd-growfs", where, ".service", &unit);
if (r < 0)
return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m",
where);
r = unit_name_from_path(where, ".mount", &where_unit);
if (r < 0)
return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
where);
unit_file = strjoina(dir, "/", unit);
log_debug("Creating %s", unit_file);
f = fopen(unit_file, "wxe");
if (!f)
return log_error_errno(errno, "Failed to create unit file %s: %m",
unit_file);
fprintf(f,
"# Automatically generated by %s\n\n"
"[Unit]\n"
"Description=Grow File System on %%f\n"
"Documentation=man:systemd-growfs@.service(8)\n"
"DefaultDependencies=no\n"
"BindsTo=%%i.mount\n"
"After=%%i.mount\n"
"Before=shutdown.target\n"
"Before=%s\n"
"\n"
"[Service]\n"
"Type=oneshot\n"
"RemainAfterExit=yes\n"
"ExecStart="SYSTEMD_GROWFS_PATH " %s\n"
"TimeoutSec=0\n",
program_invocation_short_name,
target,
escaped);
return generator_add_symlink(dir, where_unit, "wants", unit);
}

View File

@ -39,11 +39,24 @@ int generator_write_timeouts(
char **filtered);
int generator_write_device_deps(
const char *dir,
const char *what,
const char *where,
const char *opts);
const char *dir,
const char *what,
const char *where,
const char *opts);
int generator_write_initrd_root_device_deps(
const char *dir,
const char *what);
int generator_hook_up_mkswap(
const char *dir,
const char *what);
int generator_hook_up_mkfs(
const char *dir,
const char *what,
const char *where,
const char *type);
int generator_hook_up_growfs(
const char *dir,
const char *where,
const char *target);

View File

@ -35,7 +35,7 @@
static void test_chase_symlinks(void) {
_cleanup_free_ char *result = NULL;
char temp[] = "/tmp/test-chase.XXXXXX";
const char *top, *p, *q;
const char *top, *p, *pslash, *q, *qslash;
int r;
assert_se(mkdtemp(temp));
@ -66,93 +66,114 @@ static void test_chase_symlinks(void) {
r = chase_symlinks(p, NULL, 0, &result);
assert_se(r > 0);
assert_se(path_equal(result, "/usr"));
result = mfree(result);
pslash = strjoina(p, "/");
r = chase_symlinks(pslash, NULL, 0, &result);
assert_se(r > 0);
assert_se(path_equal(result, "/usr/"));
result = mfree(result);
r = chase_symlinks(p, temp, 0, &result);
assert_se(r == -ENOENT);
r = chase_symlinks(pslash, temp, 0, &result);
assert_se(r == -ENOENT);
q = strjoina(temp, "/usr");
r = chase_symlinks(p, temp, CHASE_NONEXISTENT, &result);
assert_se(r == 0);
assert_se(path_equal(result, q));
result = mfree(result);
qslash = strjoina(q, "/");
r = chase_symlinks(pslash, temp, CHASE_NONEXISTENT, &result);
assert_se(r == 0);
assert_se(path_equal(result, qslash));
result = mfree(result);
assert_se(mkdir(q, 0700) >= 0);
result = mfree(result);
r = chase_symlinks(p, temp, 0, &result);
assert_se(r > 0);
assert_se(path_equal(result, q));
result = mfree(result);
r = chase_symlinks(pslash, temp, 0, &result);
assert_se(r > 0);
assert_se(path_equal(result, qslash));
result = mfree(result);
p = strjoina(temp, "/slash");
assert_se(symlink("/", p) >= 0);
result = mfree(result);
r = chase_symlinks(p, NULL, 0, &result);
assert_se(r > 0);
assert_se(path_equal(result, "/"));
result = mfree(result);
r = chase_symlinks(p, temp, 0, &result);
assert_se(r > 0);
assert_se(path_equal(result, temp));
result = mfree(result);
/* Paths that would "escape" outside of the "root" */
p = strjoina(temp, "/6dots");
assert_se(symlink("../../..", p) >= 0);
result = mfree(result);
r = chase_symlinks(p, temp, 0, &result);
assert_se(r > 0 && path_equal(result, temp));
result = mfree(result);
p = strjoina(temp, "/6dotsusr");
assert_se(symlink("../../../usr", p) >= 0);
result = mfree(result);
r = chase_symlinks(p, temp, 0, &result);
assert_se(r > 0 && path_equal(result, q));
result = mfree(result);
p = strjoina(temp, "/top/8dotsusr");
assert_se(symlink("../../../../usr", p) >= 0);
result = mfree(result);
r = chase_symlinks(p, temp, 0, &result);
assert_se(r > 0 && path_equal(result, q));
result = mfree(result);
/* Paths that contain repeated slashes */
p = strjoina(temp, "/slashslash");
assert_se(symlink("///usr///", p) >= 0);
result = mfree(result);
r = chase_symlinks(p, NULL, 0, &result);
assert_se(r > 0);
assert_se(path_equal(result, "/usr"));
result = mfree(result);
r = chase_symlinks(p, temp, 0, &result);
assert_se(r > 0);
assert_se(path_equal(result, q));
result = mfree(result);
/* Paths using . */
result = mfree(result);
r = chase_symlinks("/etc/./.././", NULL, 0, &result);
assert_se(r > 0);
assert_se(path_equal(result, "/"));
result = mfree(result);
r = chase_symlinks("/etc/./.././", "/etc", 0, &result);
assert_se(r > 0 && path_equal(result, "/etc"));
result = mfree(result);
r = chase_symlinks("/etc/machine-id/foo", NULL, 0, &result);
assert_se(r == -ENOTDIR);
result = mfree(result);
/* Path that loops back to self */
result = mfree(result);
p = strjoina(temp, "/recursive-symlink");
assert_se(symlink("recursive-symlink", p) >= 0);
r = chase_symlinks(p, NULL, 0, &result);

View File

@ -26,8 +26,10 @@
#include "fileio.h"
#include "hashmap.h"
#include "log.h"
#include "log.h"
#include "mount-util.h"
#include "path-util.h"
#include "rm-rf.h"
#include "string-util.h"
static void test_mount_propagation_flags(const char *name, int ret, unsigned long expected) {
@ -100,6 +102,165 @@ static void test_mnt_id(void) {
hashmap_free_free(h);
}
static void test_path_is_mount_point(void) {
int fd;
char tmp_dir[] = "/tmp/test-path-is-mount-point-XXXXXX";
_cleanup_free_ char *file1 = NULL, *file2 = NULL, *link1 = NULL, *link2 = NULL;
_cleanup_free_ char *dir1 = NULL, *dir1file = NULL, *dirlink1 = NULL, *dirlink1file = NULL;
_cleanup_free_ char *dir2 = NULL, *dir2file = NULL;
assert_se(path_is_mount_point("/", NULL, AT_SYMLINK_FOLLOW) > 0);
assert_se(path_is_mount_point("/", NULL, 0) > 0);
assert_se(path_is_mount_point("//", NULL, AT_SYMLINK_FOLLOW) > 0);
assert_se(path_is_mount_point("//", NULL, 0) > 0);
assert_se(path_is_mount_point("/proc", NULL, AT_SYMLINK_FOLLOW) > 0);
assert_se(path_is_mount_point("/proc", NULL, 0) > 0);
assert_se(path_is_mount_point("/proc/", NULL, AT_SYMLINK_FOLLOW) > 0);
assert_se(path_is_mount_point("/proc/", NULL, 0) > 0);
assert_se(path_is_mount_point("/proc/1", NULL, AT_SYMLINK_FOLLOW) == 0);
assert_se(path_is_mount_point("/proc/1", NULL, 0) == 0);
assert_se(path_is_mount_point("/proc/1/", NULL, AT_SYMLINK_FOLLOW) == 0);
assert_se(path_is_mount_point("/proc/1/", NULL, 0) == 0);
assert_se(path_is_mount_point("/sys", NULL, AT_SYMLINK_FOLLOW) > 0);
assert_se(path_is_mount_point("/sys", NULL, 0) > 0);
assert_se(path_is_mount_point("/sys/", NULL, AT_SYMLINK_FOLLOW) > 0);
assert_se(path_is_mount_point("/sys/", NULL, 0) > 0);
/* we'll create a hierarchy of different kinds of dir/file/link
* layouts:
*
* <tmp>/file1, <tmp>/file2
* <tmp>/link1 -> file1, <tmp>/link2 -> file2
* <tmp>/dir1/
* <tmp>/dir1/file
* <tmp>/dirlink1 -> dir1
* <tmp>/dirlink1file -> dirlink1/file
* <tmp>/dir2/
* <tmp>/dir2/file
*/
/* file mountpoints */
assert_se(mkdtemp(tmp_dir) != NULL);
file1 = path_join(NULL, tmp_dir, "file1");
assert_se(file1);
file2 = path_join(NULL, tmp_dir, "file2");
assert_se(file2);
fd = open(file1, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
assert_se(fd > 0);
close(fd);
fd = open(file2, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
assert_se(fd > 0);
close(fd);
link1 = path_join(NULL, tmp_dir, "link1");
assert_se(link1);
assert_se(symlink("file1", link1) == 0);
link2 = path_join(NULL, tmp_dir, "link2");
assert_se(link1);
assert_se(symlink("file2", link2) == 0);
assert_se(path_is_mount_point(file1, NULL, AT_SYMLINK_FOLLOW) == 0);
assert_se(path_is_mount_point(file1, NULL, 0) == 0);
assert_se(path_is_mount_point(link1, NULL, AT_SYMLINK_FOLLOW) == 0);
assert_se(path_is_mount_point(link1, NULL, 0) == 0);
/* directory mountpoints */
dir1 = path_join(NULL, tmp_dir, "dir1");
assert_se(dir1);
assert_se(mkdir(dir1, 0755) == 0);
dirlink1 = path_join(NULL, tmp_dir, "dirlink1");
assert_se(dirlink1);
assert_se(symlink("dir1", dirlink1) == 0);
dirlink1file = path_join(NULL, tmp_dir, "dirlink1file");
assert_se(dirlink1file);
assert_se(symlink("dirlink1/file", dirlink1file) == 0);
dir2 = path_join(NULL, tmp_dir, "dir2");
assert_se(dir2);
assert_se(mkdir(dir2, 0755) == 0);
assert_se(path_is_mount_point(dir1, NULL, AT_SYMLINK_FOLLOW) == 0);
assert_se(path_is_mount_point(dir1, NULL, 0) == 0);
assert_se(path_is_mount_point(dirlink1, NULL, AT_SYMLINK_FOLLOW) == 0);
assert_se(path_is_mount_point(dirlink1, NULL, 0) == 0);
/* file in subdirectory mountpoints */
dir1file = path_join(NULL, dir1, "file");
assert_se(dir1file);
fd = open(dir1file, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
assert_se(fd > 0);
close(fd);
assert_se(path_is_mount_point(dir1file, NULL, AT_SYMLINK_FOLLOW) == 0);
assert_se(path_is_mount_point(dir1file, NULL, 0) == 0);
assert_se(path_is_mount_point(dirlink1file, NULL, AT_SYMLINK_FOLLOW) == 0);
assert_se(path_is_mount_point(dirlink1file, NULL, 0) == 0);
/* these tests will only work as root */
if (mount(file1, file2, NULL, MS_BIND, NULL) >= 0) {
int rf, rt, rdf, rdt, rlf, rlt, rl1f, rl1t;
const char *file2d;
/* files */
/* capture results in vars, to avoid dangling mounts on failure */
log_info("%s: %s", __func__, file2);
rf = path_is_mount_point(file2, NULL, 0);
rt = path_is_mount_point(file2, NULL, AT_SYMLINK_FOLLOW);
file2d = strjoina(file2, "/");
log_info("%s: %s", __func__, file2d);
rdf = path_is_mount_point(file2d, NULL, 0);
rdt = path_is_mount_point(file2d, NULL, AT_SYMLINK_FOLLOW);
log_info("%s: %s", __func__, link2);
rlf = path_is_mount_point(link2, NULL, 0);
rlt = path_is_mount_point(link2, NULL, AT_SYMLINK_FOLLOW);
assert_se(umount(file2) == 0);
assert_se(rf == 1);
assert_se(rt == 1);
assert_se(rdf == -ENOTDIR);
assert_se(rdt == -ENOTDIR);
assert_se(rlf == 0);
assert_se(rlt == 1);
/* dirs */
dir2file = path_join(NULL, dir2, "file");
assert_se(dir2file);
fd = open(dir2file, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
assert_se(fd > 0);
close(fd);
assert_se(mount(dir2, dir1, NULL, MS_BIND, NULL) >= 0);
log_info("%s: %s", __func__, dir1);
rf = path_is_mount_point(dir1, NULL, 0);
rt = path_is_mount_point(dir1, NULL, AT_SYMLINK_FOLLOW);
log_info("%s: %s", __func__, dirlink1);
rlf = path_is_mount_point(dirlink1, NULL, 0);
rlt = path_is_mount_point(dirlink1, NULL, AT_SYMLINK_FOLLOW);
log_info("%s: %s", __func__, dirlink1file);
/* its parent is a mount point, but not /file itself */
rl1f = path_is_mount_point(dirlink1file, NULL, 0);
rl1t = path_is_mount_point(dirlink1file, NULL, AT_SYMLINK_FOLLOW);
assert_se(umount(dir1) == 0);
assert_se(rf == 1);
assert_se(rt == 1);
assert_se(rlf == 0);
assert_se(rlt == 1);
assert_se(rl1f == 0);
assert_se(rl1t == 0);
} else
printf("Skipping bind mount file test: %m\n");
assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
}
int main(int argc, char *argv[]) {
log_set_max_level(LOG_DEBUG);
@ -113,6 +274,7 @@ int main(int argc, char *argv[]) {
test_mount_propagation_flags(" ", -EINVAL, 0);
test_mnt_id();
test_path_is_mount_point();
return 0;
}

View File

@ -19,7 +19,6 @@
***/
#include <stdio.h>
#include <sys/mount.h>
#include <unistd.h>
#include "alloc-util.h"
@ -376,143 +375,6 @@ static void test_prefix_root(void) {
test_prefix_root_one("/foo///", "//bar", "/foo/bar");
}
static void test_path_is_mount_point(void) {
int fd;
char tmp_dir[] = "/tmp/test-path-is-mount-point-XXXXXX";
_cleanup_free_ char *file1 = NULL, *file2 = NULL, *link1 = NULL, *link2 = NULL;
_cleanup_free_ char *dir1 = NULL, *dir1file = NULL, *dirlink1 = NULL, *dirlink1file = NULL;
_cleanup_free_ char *dir2 = NULL, *dir2file = NULL;
assert_se(path_is_mount_point("/", NULL, AT_SYMLINK_FOLLOW) > 0);
assert_se(path_is_mount_point("/", NULL, 0) > 0);
assert_se(path_is_mount_point("/proc", NULL, AT_SYMLINK_FOLLOW) > 0);
assert_se(path_is_mount_point("/proc", NULL, 0) > 0);
assert_se(path_is_mount_point("/proc/1", NULL, AT_SYMLINK_FOLLOW) == 0);
assert_se(path_is_mount_point("/proc/1", NULL, 0) == 0);
assert_se(path_is_mount_point("/sys", NULL, AT_SYMLINK_FOLLOW) > 0);
assert_se(path_is_mount_point("/sys", NULL, 0) > 0);
/* we'll create a hierarchy of different kinds of dir/file/link
* layouts:
*
* <tmp>/file1, <tmp>/file2
* <tmp>/link1 -> file1, <tmp>/link2 -> file2
* <tmp>/dir1/
* <tmp>/dir1/file
* <tmp>/dirlink1 -> dir1
* <tmp>/dirlink1file -> dirlink1/file
* <tmp>/dir2/
* <tmp>/dir2/file
*/
/* file mountpoints */
assert_se(mkdtemp(tmp_dir) != NULL);
file1 = path_join(NULL, tmp_dir, "file1");
assert_se(file1);
file2 = path_join(NULL, tmp_dir, "file2");
assert_se(file2);
fd = open(file1, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
assert_se(fd > 0);
close(fd);
fd = open(file2, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
assert_se(fd > 0);
close(fd);
link1 = path_join(NULL, tmp_dir, "link1");
assert_se(link1);
assert_se(symlink("file1", link1) == 0);
link2 = path_join(NULL, tmp_dir, "link2");
assert_se(link1);
assert_se(symlink("file2", link2) == 0);
assert_se(path_is_mount_point(file1, NULL, AT_SYMLINK_FOLLOW) == 0);
assert_se(path_is_mount_point(file1, NULL, 0) == 0);
assert_se(path_is_mount_point(link1, NULL, AT_SYMLINK_FOLLOW) == 0);
assert_se(path_is_mount_point(link1, NULL, 0) == 0);
/* directory mountpoints */
dir1 = path_join(NULL, tmp_dir, "dir1");
assert_se(dir1);
assert_se(mkdir(dir1, 0755) == 0);
dirlink1 = path_join(NULL, tmp_dir, "dirlink1");
assert_se(dirlink1);
assert_se(symlink("dir1", dirlink1) == 0);
dirlink1file = path_join(NULL, tmp_dir, "dirlink1file");
assert_se(dirlink1file);
assert_se(symlink("dirlink1/file", dirlink1file) == 0);
dir2 = path_join(NULL, tmp_dir, "dir2");
assert_se(dir2);
assert_se(mkdir(dir2, 0755) == 0);
assert_se(path_is_mount_point(dir1, NULL, AT_SYMLINK_FOLLOW) == 0);
assert_se(path_is_mount_point(dir1, NULL, 0) == 0);
assert_se(path_is_mount_point(dirlink1, NULL, AT_SYMLINK_FOLLOW) == 0);
assert_se(path_is_mount_point(dirlink1, NULL, 0) == 0);
/* file in subdirectory mountpoints */
dir1file = path_join(NULL, dir1, "file");
assert_se(dir1file);
fd = open(dir1file, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
assert_se(fd > 0);
close(fd);
assert_se(path_is_mount_point(dir1file, NULL, AT_SYMLINK_FOLLOW) == 0);
assert_se(path_is_mount_point(dir1file, NULL, 0) == 0);
assert_se(path_is_mount_point(dirlink1file, NULL, AT_SYMLINK_FOLLOW) == 0);
assert_se(path_is_mount_point(dirlink1file, NULL, 0) == 0);
/* these tests will only work as root */
if (mount(file1, file2, NULL, MS_BIND, NULL) >= 0) {
int rt, rf, rlt, rlf, rl1t, rl1f;
/* files */
/* capture results in vars, to avoid dangling mounts on failure */
rf = path_is_mount_point(file2, NULL, 0);
rt = path_is_mount_point(file2, NULL, AT_SYMLINK_FOLLOW);
rlf = path_is_mount_point(link2, NULL, 0);
rlt = path_is_mount_point(link2, NULL, AT_SYMLINK_FOLLOW);
assert_se(umount(file2) == 0);
assert_se(rf == 1);
assert_se(rt == 1);
assert_se(rlf == 0);
assert_se(rlt == 1);
/* dirs */
dir2file = path_join(NULL, dir2, "file");
assert_se(dir2file);
fd = open(dir2file, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
assert_se(fd > 0);
close(fd);
assert_se(mount(dir2, dir1, NULL, MS_BIND, NULL) >= 0);
rf = path_is_mount_point(dir1, NULL, 0);
rt = path_is_mount_point(dir1, NULL, AT_SYMLINK_FOLLOW);
rlf = path_is_mount_point(dirlink1, NULL, 0);
rlt = path_is_mount_point(dirlink1, NULL, AT_SYMLINK_FOLLOW);
/* its parent is a mount point, but not /file itself */
rl1f = path_is_mount_point(dirlink1file, NULL, 0);
rl1t = path_is_mount_point(dirlink1file, NULL, AT_SYMLINK_FOLLOW);
assert_se(umount(dir1) == 0);
assert_se(rf == 1);
assert_se(rt == 1);
assert_se(rlf == 0);
assert_se(rlt == 1);
assert_se(rl1f == 0);
assert_se(rl1t == 0);
} else
printf("Skipping bind mount file test: %m\n");
assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
}
static void test_file_in_same_dir(void) {
char *t;
@ -537,6 +399,21 @@ static void test_file_in_same_dir(void) {
free(t);
}
static void test_last_path_component(void) {
assert_se(streq(last_path_component("a/b/c"), "c"));
assert_se(streq(last_path_component("a/b/c/"), "c/"));
assert_se(streq(last_path_component("/"), "/"));
assert_se(streq(last_path_component("//"), "/"));
assert_se(streq(last_path_component("///"), "/"));
assert_se(streq(last_path_component("."), "."));
assert_se(streq(last_path_component("./."), "."));
assert_se(streq(last_path_component("././"), "./"));
assert_se(streq(last_path_component("././/"), ".//"));
assert_se(streq(last_path_component("/foo/a"), "a"));
assert_se(streq(last_path_component("/foo/a/"), "a/"));
assert_se(streq(last_path_component(""), ""));
}
static void test_filename_is_valid(void) {
char foo[FILENAME_MAX+2];
int i;
@ -621,8 +498,8 @@ int main(int argc, char **argv) {
test_strv_resolve();
test_path_startswith();
test_prefix_root();
test_path_is_mount_point();
test_file_in_same_dir();
test_last_path_component();
test_filename_is_valid();
test_hidden_or_backup_file();
test_skip_dev_prefix();

View File

@ -72,16 +72,16 @@ static void test_path_is_os_tree(void) {
assert_se(path_is_os_tree("/idontexist") == -ENOENT);
}
static void test_path_check_fstype(void) {
static void test_path_is_fs_type(void) {
/* run might not be a mount point in build chroots */
if (path_is_mount_point("/run", NULL, AT_SYMLINK_FOLLOW) > 0) {
assert_se(path_check_fstype("/run", TMPFS_MAGIC) > 0);
assert_se(path_check_fstype("/run", BTRFS_SUPER_MAGIC) == 0);
assert_se(path_is_fs_type("/run", TMPFS_MAGIC) > 0);
assert_se(path_is_fs_type("/run", BTRFS_SUPER_MAGIC) == 0);
}
assert_se(path_check_fstype("/proc", PROC_SUPER_MAGIC) > 0);
assert_se(path_check_fstype("/proc", BTRFS_SUPER_MAGIC) == 0);
assert_se(path_check_fstype("/proc", BTRFS_SUPER_MAGIC) == 0);
assert_se(path_check_fstype("/i-dont-exist", BTRFS_SUPER_MAGIC) == -ENOENT);
assert_se(path_is_fs_type("/proc", PROC_SUPER_MAGIC) > 0);
assert_se(path_is_fs_type("/proc", BTRFS_SUPER_MAGIC) == 0);
assert_se(path_is_fs_type("/proc", BTRFS_SUPER_MAGIC) == 0);
assert_se(path_is_fs_type("/i-dont-exist", BTRFS_SUPER_MAGIC) == -ENOENT);
}
static void test_path_is_temporary_fs(void) {
@ -96,7 +96,7 @@ int main(int argc, char *argv[]) {
test_files_same();
test_is_symlink();
test_path_is_os_tree();
test_path_check_fstype();
test_path_is_fs_type();
test_path_is_temporary_fs();
return 0;

View File

@ -320,6 +320,19 @@ static void test_delete_trailing_chars(void) {
assert_se(s == input3);
}
static void test_delete_trailing_slashes(void) {
char s1[] = "foobar//",
s2[] = "foobar/",
s3[] = "foobar",
s4[] = "";
assert_se(streq(delete_trailing_chars(s1, "_"), "foobar//"));
assert_se(streq(delete_trailing_chars(s1, "/"), "foobar"));
assert_se(streq(delete_trailing_chars(s2, "/"), "foobar"));
assert_se(streq(delete_trailing_chars(s3, "/"), "foobar"));
assert_se(streq(delete_trailing_chars(s4, "/"), ""));
}
static void test_skip_leading_chars(void) {
char input1[] = " \n \r k \n \r ",
input2[] = "kkkkthiskkkiskkkaktestkkk",
@ -399,6 +412,7 @@ int main(int argc, char *argv[]) {
test_endswith_no_case();
test_delete_chars();
test_delete_trailing_chars();
test_delete_trailing_slashes();
test_skip_leading_chars();
test_in_charset();
test_split_pair();

View File

@ -25,6 +25,7 @@
#include <sys/stat.h>
#include <unistd.h>
#include "device-nodes.h"
#include "dirent-util.h"
#include "format-util.h"
#include "fs-util.h"
@ -337,7 +338,7 @@ out:
void udev_node_add(struct udev_device *dev, bool apply,
mode_t mode, uid_t uid, gid_t gid,
struct udev_list *seclabel_list) {
char filename[sizeof("/dev/block/:") + 2*DECIMAL_STR_MAX(unsigned)];
char filename[DEV_NUM_PATH_MAX];
struct udev_list_entry *list_entry;
log_debug("handling device node '%s', devnum=%s, mode=%#o, uid="UID_FMT", gid="GID_FMT,
@ -347,10 +348,9 @@ void udev_node_add(struct udev_device *dev, bool apply,
return;
/* always add /dev/{block,char}/$major:$minor */
xsprintf(filename, "/dev/%s/%u:%u",
streq(udev_device_get_subsystem(dev), "block") ? "block" : "char",
major(udev_device_get_devnum(dev)),
minor(udev_device_get_devnum(dev)));
xsprintf_dev_num_path(filename,
streq(udev_device_get_subsystem(dev), "block") ? "block" : "char",
udev_device_get_devnum(dev));
node_symlink(dev, udev_device_get_devnode(dev), filename);
/* create/update symlinks, add symlinks to name index */
@ -360,16 +360,15 @@ void udev_node_add(struct udev_device *dev, bool apply,
void udev_node_remove(struct udev_device *dev) {
struct udev_list_entry *list_entry;
char filename[sizeof("/dev/block/:") + 2*DECIMAL_STR_MAX(unsigned)];
char filename[DEV_NUM_PATH_MAX];
/* remove/update symlinks, remove symlinks from name index */
udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev))
link_update(dev, udev_list_entry_get_name(list_entry), false);
/* remove /dev/{block,char}/$major:$minor */
xsprintf(filename, "/dev/%s/%u:%u",
streq(udev_device_get_subsystem(dev), "block") ? "block" : "char",
major(udev_device_get_devnum(dev)),
minor(udev_device_get_devnum(dev)));
xsprintf_dev_num_path(filename,
streq(udev_device_get_subsystem(dev), "block") ? "block" : "char",
udev_device_get_devnum(dev));
unlink(filename);
}

View File

@ -18,10 +18,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <libcryptsetup.h>
#include <stdio.h>
#include <sys/stat.h>
#include "crypt-util.h"
#include "log.h"
#include "hexdecoct.h"
#include "string-util.h"
@ -41,12 +41,8 @@ static int help(void) {
return 0;
}
static void log_glue(int level, const char *msg, void *usrptr) {
log_debug("%s", msg);
}
int main(int argc, char *argv[]) {
struct crypt_device *cd = NULL;
_cleanup_(crypt_freep) struct crypt_device *cd = NULL;
int r;
if (argc <= 1) {
@ -89,7 +85,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
crypt_set_log_callback(cd, log_glue, NULL);
crypt_set_log_callback(cd, cryptsetup_log_glue, NULL);
status = crypt_status(cd, argv[2]);
if (IN_SET(status, CRYPT_ACTIVE, CRYPT_BUSY)) {
@ -127,7 +123,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
crypt_set_log_callback(cd, log_glue, NULL);
crypt_set_log_callback(cd, cryptsetup_log_glue, NULL);
r = crypt_deactivate(cd, argv[2]);
if (r < 0) {
@ -144,9 +140,6 @@ int main(int argc, char *argv[]) {
r = 0;
finish:
if (cd)
crypt_free(cd);
free(arg_root_hash);
free(arg_data_what);
free(arg_hash_what);