dissect: add --make-archive option to convert DDI to tarball

This commit is contained in:
Lennart Poettering 2024-01-24 12:28:41 +01:00
parent 6811774510
commit b68f4cade4
18 changed files with 374 additions and 5 deletions

View file

@ -41,6 +41,9 @@ actions:
- 'sed -i "/^CONFIGURE_OPTS=(/a--werror" .packit_rpm/systemd.spec' - 'sed -i "/^CONFIGURE_OPTS=(/a--werror" .packit_rpm/systemd.spec'
# Ignore unpackaged standalone binaries # Ignore unpackaged standalone binaries
- "sed -i 's/assert False,.*/pass/' .packit_rpm/split-files.py" - "sed -i 's/assert False,.*/pass/' .packit_rpm/split-files.py"
# Temporarily add libarchive-devel build dep until the change propagates to
# Rawhide's specfile
- "sed -ri '0,/^BuildRequires: .+$/s//&\\nBuildRequires: libarchive-devel/' .packit_rpm/systemd.spec"
jobs: jobs:
- job: copr_build - job: copr_build

View file

@ -53,6 +53,9 @@
<cmdsynopsis> <cmdsynopsis>
<command>systemd-dissect</command> <arg choice="opt" rep="repeat">OPTIONS</arg> <arg>--copy-to</arg> <arg choice="plain"><replaceable>IMAGE</replaceable></arg> <arg choice="opt"><replaceable>SOURCE</replaceable></arg> <arg choice="plain"><replaceable>PATH</replaceable></arg> <command>systemd-dissect</command> <arg choice="opt" rep="repeat">OPTIONS</arg> <arg>--copy-to</arg> <arg choice="plain"><replaceable>IMAGE</replaceable></arg> <arg choice="opt"><replaceable>SOURCE</replaceable></arg> <arg choice="plain"><replaceable>PATH</replaceable></arg>
</cmdsynopsis> </cmdsynopsis>
<cmdsynopsis>
<command>systemd-dissect</command> <arg choice="opt" rep="repeat">OPTIONS</arg> <arg>--make-archive</arg> <arg choice="plain"><replaceable>IMAGE</replaceable></arg> <arg choice="opt"><replaceable>TARGET</replaceable></arg>
</cmdsynopsis>
<cmdsynopsis> <cmdsynopsis>
<command>systemd-dissect</command> <arg choice="opt" rep="repeat">OPTIONS</arg> <arg>--discover</arg> <command>systemd-dissect</command> <arg choice="opt" rep="repeat">OPTIONS</arg> <arg>--discover</arg>
</cmdsynopsis> </cmdsynopsis>
@ -305,6 +308,21 @@
<xi:include href="version-info.xml" xpointer="v247"/></listitem> <xi:include href="version-info.xml" xpointer="v247"/></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><option>--make-archive</option></term>
<listitem><para>Generates an archive file from the specified disk image. Expects two arguments: the
path to the disk image and optionally the output archive file path. If the latter is omitted the
archive is written to standard output. The archive file format is determined automatically from the
specified output archive file name, e.g. any path suffixed with <literal>.tar.xz</literal> will
result in an xz compressed UNIX tarball (if the path is omitted an uncompressed UNIX tarball is
created). See
<citerefentry><refentrytitle>libarchive</refentrytitle><manvolnum>3</manvolnum></citerefentry> for a
list of supported archive formats and compression schemes.</para>
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><option>--discover</option></term> <term><option>--discover</option></term>
@ -535,10 +553,18 @@
<title>Examples</title> <title>Examples</title>
<example> <example>
<title>Generate a tarball from an OS disk image</title> <title>Generate a tarball from an OS disk image (<option>--with</option>)</title>
<programlisting># systemd-dissect --with foo.raw tar cz . >foo.tar.gz</programlisting> <programlisting># systemd-dissect --with foo.raw tar cz . >foo.tar.gz</programlisting>
</example> </example>
<para>or alternatively just:</para>
<example>
<title>Generate a tarball from an OS disk image (<option>--make-archive</option>)</title>
<programlisting># systemd-dissect --make-archive foo.raw foo.tar.gz</programlisting>
</example>
</refsect1> </refsect1>
<refsect1> <refsect1>

View file

@ -1413,6 +1413,11 @@ elif compression == 'xz' and not libxz.found()
endif endif
conf.set('DEFAULT_COMPRESSION', 'COMPRESSION_@0@'.format(compression.to_upper())) conf.set('DEFAULT_COMPRESSION', 'COMPRESSION_@0@'.format(compression.to_upper()))
libarchive = dependency('libarchive',
version : '>= 3.0',
required : get_option('libarchive'))
conf.set10('HAVE_LIBARCHIVE', libarchive.found())
libxkbcommon = dependency('xkbcommon', libxkbcommon = dependency('xkbcommon',
version : '>= 0.3.0', version : '>= 0.3.0',
required : get_option('xkbcommon')) required : get_option('xkbcommon'))

View file

@ -451,6 +451,8 @@ option('glib', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'd
description : 'libglib support (for tests only)') description : 'libglib support (for tests only)')
option('dbus', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' }, option('dbus', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' },
description : 'libdbus support (for tests only)') description : 'libdbus support (for tests only)')
option('libarchive', type : 'feature',
description : 'libarchive support')
option('bootloader', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' }, option('bootloader', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' },
description : 'sd-boot/stub and userspace tools') description : 'sd-boot/stub and userspace tools')

View file

@ -153,6 +153,7 @@ if [ ! -f "$BUILDDIR"/build.ninja ]; then
-D initrd=true -D initrd=true
-D fexecve=true -D fexecve=true
-D default-keymap="$DEFAULT_KEYMAP" -D default-keymap="$DEFAULT_KEYMAP"
-D libarchive=enabled
) )
# On debian-like systems the library directory is not /usr/lib64 but /usr/lib/<arch-triplet>/. # On debian-like systems the library directory is not /usr/lib64 but /usr/lib/<arch-triplet>/.

View file

@ -8,6 +8,7 @@ Packages=
cryptsetup cryptsetup
dbus dbus
gnutls gnutls
libarchive
libbpf libbpf
libfido2 libfido2
libmicrohttpd libmicrohttpd

View file

@ -9,6 +9,7 @@ Packages=
audit-libs audit-libs
cryptsetup-libs cryptsetup-libs
gnutls gnutls
libarchive
libasan libasan
libbpf libbpf
libfido2 libfido2
@ -39,6 +40,7 @@ BuildPackages=
pkgconfig(glib-2.0) pkgconfig(glib-2.0)
pkgconfig(gnutls) pkgconfig(gnutls)
pkgconfig(libacl) pkgconfig(libacl)
pkgconfig(libarchive)
pkgconfig(libbpf) pkgconfig(libbpf)
pkgconfig(libcap) pkgconfig(libcap)
pkgconfig(libcryptsetup) pkgconfig(libcryptsetup)

View file

@ -8,6 +8,7 @@ Distribution=|ubuntu
Packages= Packages=
dmsetup dmsetup
libapparmor1 libapparmor1
libarchive13
libfdisk1 libfdisk1
libfido2-1 libfido2-1
libglib2.0-0 libglib2.0-0
@ -30,6 +31,7 @@ BuildPackages=
g++ g++
libacl1-dev libacl1-dev
libapparmor-dev libapparmor-dev
libarchive-dev
libaudit-dev libaudit-dev
libblkid-dev libblkid-dev
libbpf-dev libbpf-dev

View file

@ -14,6 +14,7 @@ Packages=
grep grep
gzip gzip
libbpf1 libbpf1
libarchive13
libcrypt1 libcrypt1
libcryptsetup12 libcryptsetup12
libdw1 libdw1
@ -53,6 +54,7 @@ BuildPackages=
intltool intltool
libacl-devel libacl-devel
libapparmor-devel libapparmor-devel
libarchive-devel
libblkid-devel libblkid-devel
libbpf-devel libbpf-devel
libcap-devel libcap-devel

View file

@ -238,6 +238,12 @@ const char* const systemd_features =
" -SYSVINIT" " -SYSVINIT"
#endif #endif
#if HAVE_LIBARCHIVE
" +LIBARCHIVE"
#else
" -LIBARCHIVE"
#endif
" default-hierarchy=" DEFAULT_HIERARCHY_NAME " default-hierarchy=" DEFAULT_HIERARCHY_NAME
; ;

View file

@ -27,6 +27,7 @@
#include "format-util.h" #include "format-util.h"
#include "fs-util.h" #include "fs-util.h"
#include "hexdecoct.h" #include "hexdecoct.h"
#include "libarchive-util.h"
#include "log.h" #include "log.h"
#include "loop-util.h" #include "loop-util.h"
#include "main-func.h" #include "main-func.h"
@ -63,6 +64,7 @@ static enum {
ACTION_COPY_TO, ACTION_COPY_TO,
ACTION_DISCOVER, ACTION_DISCOVER,
ACTION_VALIDATE, ACTION_VALIDATE,
ACTION_MAKE_ARCHIVE,
} arg_action = ACTION_DISSECT; } arg_action = ACTION_DISSECT;
static char *arg_image = NULL; static char *arg_image = NULL;
static char *arg_root = NULL; static char *arg_root = NULL;
@ -116,6 +118,7 @@ static int help(void) {
"%1$s [OPTIONS...] --with IMAGE [COMMAND…]\n" "%1$s [OPTIONS...] --with IMAGE [COMMAND…]\n"
"%1$s [OPTIONS...] --copy-from IMAGE PATH [TARGET]\n" "%1$s [OPTIONS...] --copy-from IMAGE PATH [TARGET]\n"
"%1$s [OPTIONS...] --copy-to IMAGE [SOURCE] PATH\n" "%1$s [OPTIONS...] --copy-to IMAGE [SOURCE] PATH\n"
"%1$s [OPTIONS...] --make-archive IMAGE [TARGET]\n"
"%1$s [OPTIONS...] --discover\n" "%1$s [OPTIONS...] --discover\n"
"%1$s [OPTIONS...] --validate IMAGE\n" "%1$s [OPTIONS...] --validate IMAGE\n"
"\n%5$sDissect a Discoverable Disk Image (DDI).%6$s\n\n" "\n%5$sDissect a Discoverable Disk Image (DDI).%6$s\n\n"
@ -157,6 +160,7 @@ static int help(void) {
" --with Mount, run command, unmount\n" " --with Mount, run command, unmount\n"
" -x --copy-from Copy files from image to host\n" " -x --copy-from Copy files from image to host\n"
" -a --copy-to Copy files from host to image\n" " -a --copy-to Copy files from host to image\n"
" --make-archive Convert the DDI to an archive file\n"
" --discover Discover DDIs in well known directories\n" " --discover Discover DDIs in well known directories\n"
" --validate Validate image and image policy\n" " --validate Validate image and image policy\n"
"\nSee the %2$s for details.\n", "\nSee the %2$s for details.\n",
@ -263,6 +267,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_IMAGE_POLICY, ARG_IMAGE_POLICY,
ARG_VALIDATE, ARG_VALIDATE,
ARG_MTREE_HASH, ARG_MTREE_HASH,
ARG_MAKE_ARCHIVE,
}; };
static const struct option options[] = { static const struct option options[] = {
@ -295,6 +300,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "image-policy", required_argument, NULL, ARG_IMAGE_POLICY }, { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY },
{ "validate", no_argument, NULL, ARG_VALIDATE }, { "validate", no_argument, NULL, ARG_VALIDATE },
{ "mtree-hash", required_argument, NULL, ARG_MTREE_HASH }, { "mtree-hash", required_argument, NULL, ARG_MTREE_HASH },
{ "make-archive", no_argument, NULL, ARG_MAKE_ARCHIVE },
{} {}
}; };
@ -518,6 +524,15 @@ static int parse_argv(int argc, char *argv[]) {
return r; return r;
break; break;
case ARG_MAKE_ARCHIVE:
r = dlopen_libarchive();
if (r < 0)
return log_error_errno(r, "Archive support not available (compiled without libarchive, or libarchive not installed?).");
arg_action = ACTION_MAKE_ARCHIVE;
break;
case '?': case '?':
return -EINVAL; return -EINVAL;
@ -600,6 +615,19 @@ static int parse_argv(int argc, char *argv[]) {
arg_flags |= DISSECT_IMAGE_READ_ONLY | DISSECT_IMAGE_REQUIRE_ROOT; arg_flags |= DISSECT_IMAGE_READ_ONLY | DISSECT_IMAGE_REQUIRE_ROOT;
break; break;
case ACTION_MAKE_ARCHIVE:
if (argc < optind + 1 || argc > optind + 2)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Expected an image file, and an optional target path as only arguments.");
r = parse_image_path_argument(argv[optind], &arg_root, &arg_image);
if (r < 0)
return r;
arg_target = argc > optind + 1 ? empty_or_dash_to_null(argv[optind + 1]) : NULL;
arg_flags |= DISSECT_IMAGE_READ_ONLY | DISSECT_IMAGE_REQUIRE_ROOT;
break;
case ACTION_COPY_FROM: case ACTION_COPY_FROM:
if (argc < optind + 2 || argc > optind + 3) if (argc < optind + 2 || argc > optind + 3)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
@ -1274,13 +1302,116 @@ static int mtree_print_item(
return RECURSE_DIR_CONTINUE; return RECURSE_DIR_CONTINUE;
} }
static int action_list_or_mtree_or_copy(DissectedImage *m, LoopDevice *d) { #if HAVE_LIBARCHIVE
static int archive_item(
RecurseDirEvent event,
const char *path,
int dir_fd,
int inode_fd,
const struct dirent *de,
const struct statx *sx,
void *userdata) {
struct archive *a = ASSERT_PTR(userdata);
int r;
assert(path);
if (!IN_SET(event, RECURSE_DIR_ENTER, RECURSE_DIR_ENTRY))
return RECURSE_DIR_CONTINUE;
assert(inode_fd >= 0);
assert(sx);
log_debug("Archiving %s\n", path);
_cleanup_(sym_archive_entry_freep) struct archive_entry *entry = NULL;
entry = sym_archive_entry_new();
if (!entry)
return log_oom();
assert(FLAGS_SET(sx->stx_mask, STATX_TYPE|STATX_MODE));
sym_archive_entry_set_pathname(entry, path);
sym_archive_entry_set_filetype(entry, sx->stx_mode);
if (!S_ISLNK(sx->stx_mode))
sym_archive_entry_set_perm(entry, sx->stx_mode);
if (FLAGS_SET(sx->stx_mask, STATX_UID))
sym_archive_entry_set_uid(entry, sx->stx_uid);
if (FLAGS_SET(sx->stx_mask, STATX_GID))
sym_archive_entry_set_gid(entry, sx->stx_gid);
if (S_ISREG(sx->stx_mode)) {
if (!FLAGS_SET(sx->stx_mask, STATX_SIZE))
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Unable to determine file size of '%s'.", path);
sym_archive_entry_set_size(entry, sx->stx_size);
}
if (S_ISCHR(sx->stx_mode) || S_ISBLK(sx->stx_mode)) {
sym_archive_entry_set_rdevmajor(entry, sx->stx_rdev_major);
sym_archive_entry_set_rdevminor(entry, sx->stx_rdev_minor);
}
/* We care about a modicum of reproducibility here, hence we don't save atime/btime here */
if (FLAGS_SET(sx->stx_mask, STATX_MTIME))
sym_archive_entry_set_mtime(entry, sx->stx_mtime.tv_sec, sx->stx_mtime.tv_nsec);
if (FLAGS_SET(sx->stx_mask, STATX_CTIME))
sym_archive_entry_set_ctime(entry, sx->stx_ctime.tv_sec, sx->stx_ctime.tv_nsec);
if (S_ISLNK(sx->stx_mode)) {
_cleanup_free_ char *s = NULL;
assert(dir_fd >= 0);
assert(de);
r = readlinkat_malloc(dir_fd, de->d_name, &s);
if (r < 0)
return log_error_errno(r, "Failed to read symlink target of '%s': %m", path);
sym_archive_entry_set_symlink(entry, s);
}
if (sym_archive_write_header(a, entry) != ARCHIVE_OK)
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to write archive entry header: %s", sym_archive_error_string(a));
if (S_ISREG(sx->stx_mode)) {
_cleanup_close_ int data_fd = -EBADF;
/* Convert the O_PATH fd in a proper fd */
data_fd = fd_reopen(inode_fd, O_RDONLY|O_CLOEXEC);
if (data_fd < 0)
return log_error_errno(data_fd, "Failed to open '%s': %m", path);
for (;;) {
char buffer[64*1024];
ssize_t l;
l = read(data_fd, buffer, sizeof(buffer));
if (l < 0)
return log_error_errno(errno, "Failed to read '%s': %m", path);
if (l == 0)
break;
la_ssize_t k;
k = sym_archive_write_data(a, buffer, l);
if (k < 0)
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to write archive data: %s", sym_archive_error_string(a));
}
}
return RECURSE_DIR_CONTINUE;
}
#endif
static int action_list_or_mtree_or_copy_or_make_archive(DissectedImage *m, LoopDevice *d) {
_cleanup_(umount_and_rmdir_and_freep) char *mounted_dir = NULL; _cleanup_(umount_and_rmdir_and_freep) char *mounted_dir = NULL;
_cleanup_free_ char *t = NULL; _cleanup_free_ char *t = NULL;
const char *root; const char *root;
int r; int r;
assert(IN_SET(arg_action, ACTION_LIST, ACTION_MTREE, ACTION_COPY_FROM, ACTION_COPY_TO)); assert(IN_SET(arg_action, ACTION_LIST, ACTION_MTREE, ACTION_COPY_FROM, ACTION_COPY_TO, ACTION_MAKE_ARCHIVE));
if (arg_image) { if (arg_image) {
assert(m); assert(m);
@ -1466,6 +1597,68 @@ static int action_list_or_mtree_or_copy(DissectedImage *m, LoopDevice *d) {
return 0; return 0;
} }
case ACTION_MAKE_ARCHIVE: {
#if HAVE_LIBARCHIVE
_cleanup_(unlink_and_freep) char *tar = NULL;
_cleanup_close_ int dfd = -EBADF;
_cleanup_fclose_ FILE *f = NULL;
dfd = open(root, O_DIRECTORY|O_CLOEXEC|O_RDONLY);
if (dfd < 0)
return log_error_errno(errno, "Failed to open mount directory: %m");
_cleanup_(sym_archive_write_freep) struct archive *a = sym_archive_write_new();
if (!a)
return log_oom();
if (arg_target)
r = sym_archive_write_set_format_filter_by_ext(a, arg_target);
else
r = sym_archive_write_set_format_gnutar(a);
if (r != ARCHIVE_OK)
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to set libarchive output format: %s", sym_archive_error_string(a));
if (arg_target) {
r = fopen_tmpfile_linkable(arg_target, O_WRONLY|O_CLOEXEC, &tar, &f);
if (r < 0)
return log_error_errno(r, "Failed to create target file '%s': %m", arg_target);
r = sym_archive_write_open_FILE(a, f);
} else {
if (isatty(STDOUT_FILENO))
return log_error_errno(SYNTHETIC_ERRNO(EBADF), "Refusing to write archive to TTY.");
r = sym_archive_write_open_fd(a, STDOUT_FILENO);
}
if (r != ARCHIVE_OK)
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to set libarchive output file: %s", sym_archive_error_string(a));
r = recurse_dir(dfd,
".",
STATX_TYPE|STATX_MODE|STATX_UID|STATX_GID|STATX_SIZE|STATX_ATIME|STATX_CTIME,
UINT_MAX,
RECURSE_DIR_SORT|RECURSE_DIR_INODE_FD|RECURSE_DIR_TOPLEVEL,
archive_item,
a);
if (r < 0)
return log_error_errno(r, "Failed to make archive: %m");
r = sym_archive_write_close(a);
if (r != ARCHIVE_OK)
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Unable to finish writing archive: %s", sym_archive_error_string(a));
if (arg_target) {
r = flink_tmpfile(f, tar, arg_target, LINK_TMPFILE_REPLACE);
if (r < 0)
return log_error_errno(r, "Failed to move archive file into place: %m");
}
return 0;
#else
assert_not_reached();
#endif
}
default: default:
assert_not_reached(); assert_not_reached();
} }
@ -1914,7 +2107,8 @@ static int run(int argc, char *argv[]) {
case ACTION_MTREE: case ACTION_MTREE:
case ACTION_COPY_FROM: case ACTION_COPY_FROM:
case ACTION_COPY_TO: case ACTION_COPY_TO:
return action_list_or_mtree_or_copy(m, d); case ACTION_MAKE_ARCHIVE:
return action_list_or_mtree_or_copy_or_make_archive(m, d);
case ACTION_WITH: case ACTION_WITH:
return action_with(m, d); return action_with(m, d);

View file

@ -0,0 +1,62 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "libarchive-util.h"
#if HAVE_LIBARCHIVE
static void *libarchive_dl = NULL;
DLSYM_FUNCTION(archive_entry_free);
DLSYM_FUNCTION(archive_entry_new);
DLSYM_FUNCTION(archive_entry_set_ctime);
DLSYM_FUNCTION(archive_entry_set_filetype);
DLSYM_FUNCTION(archive_entry_set_gid);
DLSYM_FUNCTION(archive_entry_set_mtime);
DLSYM_FUNCTION(archive_entry_set_pathname);
DLSYM_FUNCTION(archive_entry_set_perm);
DLSYM_FUNCTION(archive_entry_set_rdevmajor);
DLSYM_FUNCTION(archive_entry_set_rdevminor);
DLSYM_FUNCTION(archive_entry_set_symlink);
DLSYM_FUNCTION(archive_entry_set_size);
DLSYM_FUNCTION(archive_entry_set_uid);
DLSYM_FUNCTION(archive_error_string);
DLSYM_FUNCTION(archive_write_close);
DLSYM_FUNCTION(archive_write_data);
DLSYM_FUNCTION(archive_write_free);
DLSYM_FUNCTION(archive_write_header);
DLSYM_FUNCTION(archive_write_new);
DLSYM_FUNCTION(archive_write_open_FILE);
DLSYM_FUNCTION(archive_write_open_fd);
DLSYM_FUNCTION(archive_write_set_format_filter_by_ext);
DLSYM_FUNCTION(archive_write_set_format_gnutar);
int dlopen_libarchive(void) {
return dlopen_many_sym_or_warn(
&libarchive_dl,
"libarchive.so.13",
LOG_DEBUG,
DLSYM_ARG(archive_entry_free),
DLSYM_ARG(archive_entry_new),
DLSYM_ARG(archive_entry_set_ctime),
DLSYM_ARG(archive_entry_set_filetype),
DLSYM_ARG(archive_entry_set_gid),
DLSYM_ARG(archive_entry_set_mtime),
DLSYM_ARG(archive_entry_set_pathname),
DLSYM_ARG(archive_entry_set_perm),
DLSYM_ARG(archive_entry_set_rdevmajor),
DLSYM_ARG(archive_entry_set_rdevminor),
DLSYM_ARG(archive_entry_set_size),
DLSYM_ARG(archive_entry_set_symlink),
DLSYM_ARG(archive_entry_set_uid),
DLSYM_ARG(archive_error_string),
DLSYM_ARG(archive_write_close),
DLSYM_ARG(archive_write_data),
DLSYM_ARG(archive_write_free),
DLSYM_ARG(archive_write_header),
DLSYM_ARG(archive_write_new),
DLSYM_ARG(archive_write_open_FILE),
DLSYM_ARG(archive_write_open_fd),
DLSYM_ARG(archive_write_set_format_filter_by_ext),
DLSYM_ARG(archive_write_set_format_gnutar));
}
#endif

View file

@ -0,0 +1,45 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "dlfcn-util.h"
#if HAVE_LIBARCHIVE
#include <archive.h>
#include <archive_entry.h>
DLSYM_PROTOTYPE(archive_entry_free);
DLSYM_PROTOTYPE(archive_entry_new);
DLSYM_PROTOTYPE(archive_entry_set_ctime);
DLSYM_PROTOTYPE(archive_entry_set_filetype);
DLSYM_PROTOTYPE(archive_entry_set_gid);
DLSYM_PROTOTYPE(archive_entry_set_mtime);
DLSYM_PROTOTYPE(archive_entry_set_pathname);
DLSYM_PROTOTYPE(archive_entry_set_perm);
DLSYM_PROTOTYPE(archive_entry_set_rdevmajor);
DLSYM_PROTOTYPE(archive_entry_set_rdevminor);
DLSYM_PROTOTYPE(archive_entry_set_symlink);
DLSYM_PROTOTYPE(archive_entry_set_size);
DLSYM_PROTOTYPE(archive_entry_set_uid);
DLSYM_PROTOTYPE(archive_error_string);
DLSYM_PROTOTYPE(archive_write_close);
DLSYM_PROTOTYPE(archive_write_data);
DLSYM_PROTOTYPE(archive_write_free);
DLSYM_PROTOTYPE(archive_write_header);
DLSYM_PROTOTYPE(archive_write_new);
DLSYM_PROTOTYPE(archive_write_open_FILE);
DLSYM_PROTOTYPE(archive_write_open_fd);
DLSYM_PROTOTYPE(archive_write_set_format_filter_by_ext);
DLSYM_PROTOTYPE(archive_write_set_format_gnutar);
int dlopen_libarchive(void);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct archive_entry*, sym_archive_entry_free, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct archive*, sym_archive_write_free, NULL);
#else
static inline int dlopen_libarchive(void) {
return -EOPNOTSUPP;
}
#endif

View file

@ -103,6 +103,7 @@ shared_sources = files(
'keyring-util.c', 'keyring-util.c',
'killall.c', 'killall.c',
'label-util.c', 'label-util.c',
'libarchive-util.c',
'libcrypt-util.c', 'libcrypt-util.c',
'libfido2-util.c', 'libfido2-util.c',
'libmount-util.c', 'libmount-util.c',

View file

@ -7,6 +7,7 @@
#include "cryptsetup-util.h" #include "cryptsetup-util.h"
#include "elf-util.h" #include "elf-util.h"
#include "idn-util.h" #include "idn-util.h"
#include "libarchive-util.h"
#include "libfido2-util.h" #include "libfido2-util.h"
#include "macro.h" #include "macro.h"
#include "main-func.h" #include "main-func.h"
@ -70,6 +71,10 @@ static int run(int argc, char **argv) {
assert_se(dlopen_p11kit() >= 0); assert_se(dlopen_p11kit() >= 0);
#endif #endif
#if HAVE_LIBARCHIVE
assert_se(dlopen_libarchive() >= 0);
#endif
return 0; return 0;
} }

View file

@ -21,6 +21,7 @@ test_append_files() {
generate_module_dependencies generate_module_dependencies
inst_binary wc inst_binary wc
inst_binary sha256sum inst_binary sha256sum
inst_binary tar
if command -v openssl >/dev/null 2>&1; then if command -v openssl >/dev/null 2>&1; then
inst_binary openssl inst_binary openssl
fi fi

View file

@ -1551,7 +1551,7 @@ install_missing_libraries() {
local lib path local lib path
# A number of dependencies is now optional via dlopen, so the install # A number of dependencies is now optional via dlopen, so the install
# script will not pick them up, since it looks at linkage. # script will not pick them up, since it looks at linkage.
for lib in libcryptsetup libidn libidn2 pwquality libqrencode tss2-esys tss2-rc tss2-mu tss2-tcti-device libfido2 libbpf libelf libdw xkbcommon p11-kit-1; do for lib in libcryptsetup libidn libidn2 pwquality libqrencode tss2-esys tss2-rc tss2-mu tss2-tcti-device libfido2 libbpf libelf libdw xkbcommon p11-kit-1 libarchive; do
ddebug "Searching for $lib via pkg-config" ddebug "Searching for $lib via pkg-config"
if pkg-config --exists "$lib"; then if pkg-config --exists "$lib"; then
path="$(pkg-config --variable=libdir "$lib")" path="$(pkg-config --variable=libdir "$lib")"

View file

@ -54,6 +54,17 @@ read -r SHA256SUM2 _ < <(systemd-dissect --read-only --with "${image}.raw" sha25
test "$SHA256SUM2" != "" test "$SHA256SUM2" != ""
test "$SHA256SUM1" = "$SHA256SUM2" test "$SHA256SUM1" = "$SHA256SUM2"
if systemctl --version | grep -qF -- "+LIBARCHIVE" ; then
# Make sure tarballs are reproducible
read -r SHA256SUM1 _ < <(systemd-dissect --make-archive "${image}.raw" | sha256sum)
test "$SHA256SUM1" != ""
read -r SHA256SUM2 _ < <(systemd-dissect --make-archive "${image}.raw" | sha256sum)
test "$SHA256SUM2" != ""
test "$SHA256SUM1" = "$SHA256SUM2"
# Also check that a file we expect to be there is there
systemd-dissect --make-archive "${image}.raw" | tar t | grep etc/os-release
fi
mv "${image}.verity" "${image}.fooverity" mv "${image}.verity" "${image}.fooverity"
mv "${image}.roothash" "${image}.foohash" mv "${image}.roothash" "${image}.foohash"
systemd-dissect --json=short "${image}.raw" --root-hash="${roothash}" --verity-data="${image}.fooverity" | grep -q -F '{"rw":"ro","designator":"root","partition_uuid":null,"partition_label":null,"fstype":"squashfs","architecture":null,"verity":"external"' systemd-dissect --json=short "${image}.raw" --root-hash="${roothash}" --verity-data="${image}.fooverity" | grep -q -F '{"rw":"ro","designator":"root","partition_uuid":null,"partition_label":null,"fstype":"squashfs","architecture":null,"verity":"external"'