_cleanup_free_ char *resolved = NULL;
char ***protected_versions = ASSERT_PTR(data);
+ Transfer *t = ASSERT_PTR(userdata);
int r;
assert(rvalue);
- r = specifier_printf(rvalue, NAME_MAX, specifier_table, arg_root, NULL, &resolved);
+ r = specifier_printf(rvalue, NAME_MAX, specifier_table, t->context->root, NULL, &resolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to expand specifiers in ProtectVersion=, ignoring: %s", rvalue);
_cleanup_free_ char *resolved = NULL;
char **version = ASSERT_PTR(data);
+ Transfer *t = ASSERT_PTR(userdata);
int r;
assert(rvalue);
- r = specifier_printf(rvalue, NAME_MAX, specifier_table, arg_root, NULL, &resolved);
+ r = specifier_printf(rvalue, NAME_MAX, specifier_table, t->context->root, NULL, &resolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to expand specifiers in MinVersion=, ignoring: %s", rvalue);
void *data,
void *userdata) {
char ***s = ASSERT_PTR(data);
+ Transfer *t = ASSERT_PTR(userdata);
_cleanup_free_ char *resolved = NULL;
int r;
return 0;
}
- r = specifier_printf(rvalue, NAME_MAX, specifier_table, arg_root, NULL, &resolved);
+ r = specifier_printf(rvalue, NAME_MAX, specifier_table, t->context->root, NULL, &resolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to expand specifiers in %s=, ignoring: %s", lvalue, rvalue);
_cleanup_free_ char *resolved = NULL;
char **current_symlink = ASSERT_PTR(data);
+ Transfer *t = ASSERT_PTR(userdata);
int r;
assert(rvalue);
- r = specifier_printf(rvalue, NAME_MAX, specifier_table, arg_root, NULL, &resolved);
+ r = specifier_printf(rvalue, NAME_MAX, specifier_table, t->context->root, NULL, &resolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to expand specifiers in CurrentSymlink=, ignoring: %s", rvalue);
void *userdata) {
char ***patterns = ASSERT_PTR(data);
+ Transfer *t = ASSERT_PTR(userdata);
int r;
assert(rvalue);
if (r == 0)
break;
- r = specifier_printf(word, NAME_MAX, specifier_table, arg_root, NULL, &resolved);
+ r = specifier_printf(word, NAME_MAX, specifier_table, t->context->root, NULL, &resolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to expand specifiers in MatchPattern=, ignoring: %s", rvalue);
void *userdata) {
_cleanup_free_ char *resolved = NULL;
Resource *rr = ASSERT_PTR(data);
+ Transfer *t = ASSERT_PTR(userdata);
int r;
assert(rvalue);
return 0;
}
- r = specifier_printf(rvalue, PATH_MAX-1, specifier_table, arg_root, NULL, &resolved);
+ r = specifier_printf(rvalue, PATH_MAX-1, specifier_table, t->context->root, NULL, &resolved);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to expand specifiers in Path=, ignoring: %s", rvalue);
STRV_MAKE_CONST(path),
dirs,
strjoina(filename, ".d"),
- arg_root,
+ t->context->root,
/* root_fd= */ -EBADF,
"Transfer\0"
"Source\0"
"Target\0",
config_item_table_lookup, table,
CONFIG_PARSE_WARN,
- /* userdata= */ NULL,
+ t,
/* stats_by_path= */ NULL,
/* drop_in_files= */ NULL);
if (r < 0)
return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
"Source specification lacks Path=.");
- if (t->source.path_relative_to == PATH_RELATIVE_TO_EXPLICIT && !arg_transfer_source)
+ if (t->source.path_relative_to == PATH_RELATIVE_TO_EXPLICIT && !t->context->transfer_source)
return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL),
"PathRelativeTo=explicit requires --transfer-source= to be specified.");
assert(t);
- r = resource_resolve_path(&t->source, root, arg_transfer_source, node);
+ r = resource_resolve_path(&t->source, root, t->context->transfer_source, node);
if (r < 0)
return r;
/* Second, calculate how many instances to keep, based on the instance limit — but keep at least one */
- instances_max = arg_instances_max != UINT64_MAX ? arg_instances_max : t->instances_max;
+ instances_max = t->context->instances_max != UINT64_MAX ? t->context->instances_max : t->instances_max;
assert(instances_max >= 1);
if (instances_max == UINT64_MAX) /* Keep infinite instances? */
limit = UINT64_MAX;
SYSTEMD_IMPORT_PATH,
"raw",
"--direct", /* just copy/unpack the specified file, don't do anything else */
- arg_sync ? "--sync=yes" : "--sync=no",
+ t->context->sync ? "--sync=yes" : "--sync=no",
i->path,
t->temporary_partial_path),
t, i, cb, userdata);
"--direct", /* just copy/unpack the specified file, don't do anything else */
"--offset", offset,
"--size-max", max_size,
- arg_sync ? "--sync=yes" : "--sync=no",
+ t->context->sync ? "--sync=yes" : "--sync=no",
i->path,
t->target.path),
t, i, cb, userdata);
SYSTEMD_IMPORT_FS_PATH,
"run",
"--direct", /* just untar the specified file, don't do anything else */
- arg_sync ? "--sync=yes" : "--sync=no",
+ t->context->sync ? "--sync=yes" : "--sync=no",
t->target.type == RESOURCE_SUBVOLUME ? "--btrfs-subvol=yes" : "--btrfs-subvol=no",
i->path,
t->temporary_partial_path),
SYSTEMD_IMPORT_PATH,
"tar",
"--direct", /* just untar the specified file, don't do anything else */
- arg_sync ? "--sync=yes" : "--sync=no",
+ t->context->sync ? "--sync=yes" : "--sync=no",
t->target.type == RESOURCE_SUBVOLUME ? "--btrfs-subvol=yes" : "--btrfs-subvol=no",
i->path,
t->temporary_partial_path),
"raw",
"--direct", /* just download the specified URL, don't download anything else */
"--verify", digest, /* validate by explicit SHA256 sum */
- arg_sync ? "--sync=yes" : "--sync=no",
+ t->context->sync ? "--sync=yes" : "--sync=no",
i->path,
t->temporary_partial_path),
t, i, cb, userdata);
"--verify", digest, /* validate by explicit SHA256 sum */
"--offset", offset,
"--size-max", max_size,
- arg_sync ? "--sync=yes" : "--sync=no",
+ t->context->sync ? "--sync=yes" : "--sync=no",
i->path,
t->target.path),
t, i, cb, userdata);
"--direct", /* just download the specified URL, don't download anything else */
"--verify", digest, /* validate by explicit SHA256 sum */
t->target.type == RESOURCE_SUBVOLUME ? "--btrfs-subvol=yes" : "--btrfs-subvol=no",
- arg_sync ? "--sync=yes" : "--sync=no",
+ t->context->sync ? "--sync=yes" : "--sync=no",
i->path,
t->temporary_partial_path),
t, i, cb, userdata);
}
/* Synchronize */
- if (arg_sync && need_sync) {
+ if (t->context->sync && need_sync) {
if (t->target.type == RESOURCE_REGULAR_FILE)
r = fsync_path_and_parent_at(AT_FDCWD, t->temporary_partial_path);
else {
#include "verbs.h"
static char *arg_definitions = NULL;
-bool arg_sync = true;
-uint64_t arg_instances_max = UINT64_MAX;
+static bool arg_sync = true;
+static uint64_t arg_instances_max = UINT64_MAX;
static sd_json_format_flags_t arg_json_format_flags = SD_JSON_FORMAT_OFF;
static PagerFlags arg_pager_flags = 0;
static bool arg_legend = true;
-char *arg_root = NULL;
+static char *arg_root = NULL;
static char *arg_image = NULL;
static bool arg_reboot = false;
static int arg_cleanup = -1;
static int arg_verify = -1;
static ImagePolicy *arg_image_policy = NULL;
static bool arg_offline = false;
-char *arg_transfer_source = NULL;
+static char *arg_transfer_source = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_definitions, freep);
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
#define CONTEXT_NULL \
(Context) { \
+ .sync = true, \
+ .instances_max = UINT64_MAX, \
+ .verify = -1, \
+ .cleanup = -1, \
.installdb_fd = -EBADF, \
}
void context_done(Context *c) {
assert(c);
- c->component = mfree(c->component);
-
c->mounted_dir = umount_and_rmdir_and_free(c->mounted_dir);
c->loop_device = loop_device_unref(c->loop_device);
c->web_cache = hashmap_free(c->web_cache);
c->installdb_fd = safe_close(c->installdb_fd);
+
+ c->definitions = mfree(c->definitions);
+ c->root = mfree(c->root);
+ c->image = mfree(c->image);
+ c->component = mfree(c->component);
+ c->image_policy = image_policy_free(c->image_policy);
+ c->transfer_source = mfree(c->transfer_source);
+}
+
+static int context_from_cmdline(Context *ret) {
+ assert(ret);
+
+ _cleanup_(context_done) Context context = CONTEXT_NULL;
+
+ context.instances_max = arg_instances_max;
+ context.sync = arg_sync;
+ context.reboot = arg_reboot;
+ context.verify = arg_verify;
+ context.offline = arg_offline;
+ context.cleanup = arg_cleanup;
+ context.component_all = arg_component_all;
+
+ if (strdup_to(&context.definitions, arg_definitions) < 0)
+ return log_oom();
+
+ if (strdup_to(&context.root, arg_root) < 0)
+ return log_oom();
+
+ if (strdup_to(&context.image, arg_image) < 0)
+ return log_oom();
+
+ if (strdup_to(&context.component, arg_component) < 0)
+ return log_oom();
+
+ if (strdup_to(&context.transfer_source, arg_transfer_source) < 0)
+ return log_oom();
+
+ if (arg_image_policy) {
+ context.image_policy = image_policy_copy(arg_image_policy);
+ if (!context.image_policy)
+ return log_oom();
+ }
+
+ *ret = TAKE_GENERIC(context, Context, CONTEXT_NULL);
+ return 0;
}
static DEFINE_POINTER_ARRAY_FREE_FUNC(Transfer*, transfer_free);
assert(dirs);
assert(suffix);
- r = conf_files_list_strv_full(suffix, arg_root,
+ r = conf_files_list_strv_full(suffix, c->root,
CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED|CONF_FILES_WARN,
dirs, &files, &n_files);
if (r < 0)
if (r < 0)
return r;
- r = transfer_resolve_paths(t, arg_root, node);
+ r = transfer_resolve_paths(t, c->root, node);
if (r < 0)
return r;
assert(c);
- if (arg_definitions)
- dirs = strv_new(arg_definitions);
+ if (c->definitions)
+ dirs = strv_new(c->definitions);
else if (c->component) {
char **l = CONF_PATHS_STRV("");
size_t i = 0;
CLEANUP_ARRAY(files, n_files, conf_file_free_array);
- r = conf_files_list_strv_full(".feature", arg_root,
+ r = conf_files_list_strv_full(".feature", c->root,
CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED|CONF_FILES_WARN,
(const char**) dirs, &files, &n_files);
if (r < 0)
if (!f)
return log_oom();
- r = feature_read_definition(f, e->result, (const char**) dirs);
+ r = feature_read_definition(f, c->root, e->result, (const char**) dirs);
if (r < 0)
return r;
r = resource_load_instances(
&t->target,
- arg_verify >= 0 ? arg_verify : t->verify,
+ c->verify >= 0 ? c->verify : t->verify,
&c->web_cache);
if (r < 0)
return r;
r = resource_load_instances(
&t->target,
- arg_verify >= 0 ? arg_verify : t->verify,
+ c->verify >= 0 ? c->verify : t->verify,
&c->web_cache);
if (r < 0)
return r;
r = resource_load_instances(
&t->source,
- arg_verify >= 0 ? arg_verify : t->verify,
+ c->verify >= 0 ? c->verify : t->verify,
&c->web_cache);
if (r < 0)
return r;
if (r < 0)
return r;
- if (!arg_offline) {
+ if (!c->offline) {
log_info("Determining available update sets%s", glyph(GLYPH_ELLIPSIS));
r = context_discover_update_sets_by_flag(c, UPDATE_AVAILABLE);
assert(c);
- if (!arg_image)
+ if (!c->image)
return 0;
- assert(!arg_root);
+ assert(!c->root);
assert(!c->mounted_dir);
assert(!c->loop_device);
r = mount_image_privately_interactively(
- arg_image,
- arg_image_policy,
+ c->image,
+ c->image_policy,
(FLAGS_SET(flags, PROCESS_IMAGE_READ_ONLY) ? DISSECT_IMAGE_READ_ONLY : 0) |
DISSECT_IMAGE_FSCK |
DISSECT_IMAGE_MKDIR |
if (r < 0)
return r;
- arg_root = strdup(mounted_dir);
- if (!arg_root)
+ c->root = strdup(mounted_dir);
+ if (!c->root)
return log_oom();
c->mounted_dir = TAKE_PTR(mounted_dir);
static int context_load_offline(
Context *context,
- const char *component,
ProcessImageFlags process_image_flags,
ReadDefinitionsFlags read_definitions_flags) {
int r;
/* Sets up a context object and initializes everything we can initialize offline, i.e. without
* checking on the update source (i.e. the Internet) what versions are available */
- r = free_and_strdup_warn(&context->component, component);
- if (r < 0)
- return r;
-
r = process_image(context, process_image_flags);
if (r < 0)
return r;
static int context_load_online(
Context *context,
- const char *component,
ProcessImageFlags process_image_flags) {
int r;
r = context_load_offline(
context,
- component,
process_image_flags,
READ_DEFINITIONS_REQUIRES_ENABLED_TRANSFERS|READ_DEFINITIONS_REQUIRES_ANY_TRANSFERS);
if (r < 0)
return r;
- if (!arg_offline) {
+ if (!context->offline) {
r = context_load_available_instances(context);
if (r < 0)
return r;
if (r < 0)
return r;
- if (arg_sync)
+ if (c->sync)
sync();
(void) sd_notifyf(/* unset_environment= */ false,
return r;
}
- if (arg_sync)
+ if (c->sync)
sync();
return 1;
_cleanup_(sd_json_variant_unrefp) sd_json_variant *params = NULL;
r = sd_json_buildo(
¶ms,
- SD_JSON_BUILD_PAIR_CONDITION(!!arg_component, "component", SD_JSON_BUILD_STRING(arg_component)),
+ SD_JSON_BUILD_PAIR_CONDITION(!!c->component, "component", SD_JSON_BUILD_STRING(c->component)),
SD_JSON_BUILD_PAIR_CONDITION(!!us, "version", SD_JSON_BUILD_STRING(us ? us->version : NULL)),
SD_JSON_BUILD_PAIR_CONDITION(!!resources, "resources", SD_JSON_BUILD_VARIANT(resources)));
if (r < 0)
!inst->is_pending)
continue;
- r = transfer_install_instance(t, inst, arg_root);
+ r = transfer_install_instance(t, inst, c->root);
if (r < 0)
return r;
}
log_info("%s Successfully installed update '%s'.", glyph(GLYPH_SPARKLES), us->version);
- if (!arg_root)
+ if (!c->root)
(void) context_notify_subscribers(c, us);
(void) sd_notifyf(/* unset_environment= */ false,
assert(argc <= 2);
version = argc >= 2 ? argv[1] : NULL;
- if (arg_component_all)
+ r = context_from_cmdline(&context);
+ if (r < 0)
+ return r;
+
+ if (context.component_all)
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "--component-all currently not supported for '%s'.", argv[0]);
- r = context_load_online(
- &context,
- arg_component,
- PROCESS_IMAGE_READ_ONLY);
+ r = context_load_online(&context, PROCESS_IMAGE_READ_ONLY);
if (r < 0)
return r;
assert(argc <= 2);
feature_id = argc >= 2 ? argv[1] : NULL;
- if (arg_component_all)
+ r = context_from_cmdline(&context);
+ if (r < 0)
+ return r;
+
+ if (context.component_all)
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "--component-all currently not supported for '%s'.", argv[0]);
r = context_load_offline(
&context,
- arg_component,
PROCESS_IMAGE_READ_ONLY,
READ_DEFINITIONS_REQUIRES_ANY_TRANSFERS);
if (r < 0)
assert(argc <= 1);
- if (arg_component_all)
+ r = context_from_cmdline(&context);
+ if (r < 0)
+ return r;
+
+ if (context.component_all)
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "--component-all currently not supported for '%s'.", argv[0]);
r = context_load_online(
&context,
- arg_component,
PROCESS_IMAGE_READ_ONLY);
if (r < 0)
return r;
assert(argc <= 2);
version = argc >= 2 ? argv[1] : NULL;
- if (arg_component_all)
+ r = context_from_cmdline(&context);
+ if (r < 0)
+ return r;
+
+ if (context.component_all)
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "--component-all currently not supported for '%s'.", argv[0]);
- if (arg_instances_max < 2)
+ if (context.instances_max < 2)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"The --instances-max argument must be >= 2 while updating");
- if (arg_reboot) {
+ if (context.reboot) {
/* If automatic reboot on completion is requested, let's first determine the currently booted image */
- r = parse_os_release(arg_root, "IMAGE_VERSION", &booted_version);
+ r = parse_os_release(context.root, "IMAGE_VERSION", &booted_version);
if (r < 0)
return log_error_errno(r, "Failed to parse /etc/os-release: %m");
if (!booted_version)
r = context_load_online(
&context,
- arg_component,
/* process_image_flags= */ 0);
if (r < 0) {
if (r != -ENOENT)
}
}
- if (arg_cleanup > 0)
+ if (context.cleanup > 0)
RET_GATHER(ret, installdb_cleanup_component(&context));
if (installed) {
/* We installed something, yay */
- if (arg_reboot) {
+ if (context.reboot) {
assert(applied);
assert(booted_version);
assert(argc <= 1);
- if (arg_component_all)
+ r = context_from_cmdline(&context);
+ if (r < 0)
+ return r;
+
+ if (context.component_all)
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "--component-all currently not supported for '%s'.", argv[0]);
- if (arg_instances_max < 1)
+ if (context.instances_max < 1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"The --instances-max argument must be >= 1 while vacuuming");
r = context_load_offline(
&context,
- arg_component,
/* process_image_flags= */ 0,
READ_DEFINITIONS_REQUIRES_ANY_TRANSFERS);
if (r < 0)
assert(argc == 1);
- if (arg_image || arg_root)
+ r = context_from_cmdline(&context);
+ if (r < 0)
+ return r;
+
+ if (context.image || context.root)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"The --root=/--image= switches may not be combined with the '%s' operation.", argv[0]);
- if (arg_component || arg_component_all)
+ if (context.component || context.component_all)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"The --component= and --component-all switches may not be combined with the '%s' operation, which only applies to the booted OS version.", argv[0]);
r = context_load_offline(
&context,
- arg_component,
/* process_image_flags= */ 0,
READ_DEFINITIONS_REQUIRES_ENABLED_TRANSFERS|READ_DEFINITIONS_REQUIRES_ANY_TRANSFERS);
if (r < 0)
if (!context.newest_installed)
return log_error_errno(SYNTHETIC_ERRNO(ENODATA), "Couldn't find any suitable installed versions.");
- r = parse_os_release(arg_root, "IMAGE_VERSION", &booted_version);
- if (r < 0) /* yes, arg_root is NULL here, but we have to pass something, and it's a lot more readable
+ r = parse_os_release(context.root, "IMAGE_VERSION", &booted_version);
+ if (r < 0) /* yes, context.root is NULL here, but we have to pass something, and it's a lot more readable
* if we see what the first argument is about */
return log_error_errno(r, "Failed to parse /etc/os-release: %m");
if (!booted_version)
assert(argc <= 1);
- if (arg_component_all)
+ r = context_from_cmdline(&context);
+ if (r < 0)
+ return r;
+
+ if (context.component_all)
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "--component-all currently not supported for '%s'.", argv[0]);
r = context_load_offline(
&context,
- arg_component,
/* process_image_flags= */ 0,
/* read_definitions_flags= */ 0);
if (r < 0)
return r;
_cleanup_strv_free_ char **z = NULL;
- r = get_component_list(arg_root, &z);
+ r = get_component_list(context.root, &z);
if (r < 0)
return log_error_errno(r, "Failed to enumerate components: %m");
/* Does the system have at least one transfer file in /etc/sysupdate.d, which can be considered a
* TARGET_HOST? See target_get_argument() in sysupdated.c */
- has_default_component = (!arg_definitions &&
+ has_default_component = (!context.definitions &&
!context.component &&
- !arg_root &&
- !arg_image &&
+ !context.root &&
+ !context.image &&
context.n_transfers > 0);
if (!sd_json_format_enabled(arg_json_format_flags)) {
assert(argc <= 1);
- if (arg_cleanup == 0)
+ r = context_from_cmdline(&context);
+ if (r < 0)
+ return r;
+
+ if (context.cleanup == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invocation of 'cleanup' with --cleanup=no is contradictory, refusing.");
r = context_load_offline(
&context,
- arg_component,
/* process_image_flags= */ 0,
/* read_definitions_flags= */ 0);
if (r < 0)
int ret = 0;
RET_GATHER(ret, installdb_cleanup_component(&context));
- if (arg_component_all) {
+ if (context.component_all) {
_cleanup_strv_free_ char **z = NULL;
- r = installdb_list_components(&z);
+ r = installdb_list_components(&context, &z);
if (r < 0)
return log_error_errno(r, "Failed to enumerate components: %m");
STRV_FOREACH(i, z) {
_cleanup_(context_done) Context component_context = CONTEXT_NULL;
+ r = context_from_cmdline(&component_context);
+ if (r < 0)
+ return r;
+
+ /* Override the component with our iter. This needs to be done in a fresh Context
+ * as the installdb_fd and other state are specific to the component. */
+ r = free_and_strdup_warn(&component_context.component, *i);
+ if (r < 0)
+ return r;
+
r = context_load_offline(
&component_context,
- *i,
/* process_image_flags= */ 0,
/* read_definitions_flags= */ 0);
if (r < 0)