Just some refactoring.
The code is slightly updated, for example it now uses string_is_safe().
But mostly this just splits out code from one large file to a smaller
one.
'objects' : ['systemd-sysupdate'],
'conditions' : ['ENABLE_SYSUPDATED'],
},
+ test_template + {
+ 'sources' : files('test-sysupdate-util.c'),
+ 'objects' : ['systemd-sysupdate'],
+ 'conditions' : ['ENABLE_SYSUPDATE'],
+ },
]
if conf.get('ENABLE_SYSUPDATED') == 1
#include "bus-error.h"
#include "bus-locator.h"
+#include "conf-files.h"
+#include "constants.h"
#include "log.h"
#include "login-util.h"
+#include "path-util.h"
+#include "set.h"
+#include "string-util.h"
+#include "strv.h"
#include "sysupdate-util.h"
int reboot_now(void) {
return 0;
}
+
+bool component_name_valid(const char *c) {
+ /* See if the specified string enclosed in the directory prefix+suffix would be a valid file name */
+
+ if (!string_is_safe(c, STRING_FILENAME_PART))
+ return false;
+
+ /* Stack allocation is safe, since STRING_FILENAME_PART includes a length check */
+ const char *j = strjoina("sysupdate.", c, ".d");
+
+ return filename_is_valid(j);
+}
+
+int get_component_list(const char *root, char ***ret) {
+ int r;
+
+ assert(ret);
+
+ ConfFile **directories = NULL;
+ size_t n_directories = 0;
+ CLEANUP_ARRAY(directories, n_directories, conf_file_free_array);
+
+ r = conf_files_list_strv_full(
+ ".d",
+ root,
+ CONF_FILES_DIRECTORY|CONF_FILES_WARN,
+ (const char * const *) CONF_PATHS_STRV(""),
+ &directories,
+ &n_directories);
+ if (r < 0)
+ return r;
+
+ _cleanup_set_free_ Set *names = NULL;
+
+ FOREACH_ARRAY(i, directories, n_directories) {
+ ConfFile *e = *i;
+
+ const char *s = startswith(e->filename, "sysupdate.");
+ if (!s)
+ continue;
+
+ const char *a = endswith(s, ".d");
+ if (!a)
+ continue;
+
+ if (a == s)
+ continue;
+
+ _cleanup_free_ char *n = strndup(s, a - s);
+ if (!n)
+ return log_oom();
+
+ if (!component_name_valid(n))
+ continue;
+
+ r = set_ensure_consume(&names, &string_hash_ops_free, TAKE_PTR(n));
+ if (r < 0 && r != -EEXIST)
+ return r;
+ }
+
+ _cleanup_strv_free_ char **z = set_to_strv(&names);
+ if (!z)
+ return -ENOMEM;
+
+ strv_sort(z);
+
+ *ret = TAKE_PTR(z);
+ return 0;
+}
/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
#pragma once
+#include <stdbool.h>
+
int reboot_now(void);
-#define SD_SYSUPDATE_OFFLINE (UINT64_C(1) << 0)
+#define SD_SYSUPDATE_OFFLINE (UINT64_C(1) << 0)
#define SD_SYSUPDATE_FLAGS_ALL (SD_SYSUPDATE_OFFLINE)
+
+bool component_name_valid(const char *c);
+int get_component_list(const char *root, char ***ret);
return EXIT_SUCCESS;
}
-static int component_name_valid(const char *c) {
- _cleanup_free_ char *j = NULL;
-
- /* See if the specified string enclosed in the directory prefix+suffix would be a valid file name */
-
- if (isempty(c))
- return false;
-
- if (string_has_cc(c, NULL))
- return false;
-
- if (!utf8_is_valid(c))
- return false;
-
- j = strjoin("sysupdate.", c, ".d");
- if (!j)
- return -ENOMEM;
-
- return filename_is_valid(j);
-}
-
VERB_NOARG(verb_components, "components",
"Show list of components");
static int verb_components(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_(context_freep) Context* context = NULL;
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
_cleanup_(umount_and_rmdir_and_freep) char *mounted_dir = NULL;
- _cleanup_set_free_ Set *names = NULL;
bool has_default_component = false;
int r;
if (r < 0)
return r;
- ConfFile **directories = NULL;
- size_t n_directories = 0;
-
- CLEANUP_ARRAY(directories, n_directories, conf_file_free_array);
-
- r = conf_files_list_strv_full(".d", arg_root, CONF_FILES_DIRECTORY|CONF_FILES_WARN,
- (const char * const *) CONF_PATHS_STRV(""), &directories, &n_directories);
+ _cleanup_strv_free_ char **z = NULL;
+ r = get_component_list(arg_root, &z);
if (r < 0)
- return log_error_errno(r, "Failed to enumerate directories: %m");
-
- FOREACH_ARRAY(i, directories, n_directories) {
- ConfFile *e = *i;
-
- if (streq(e->filename, "sysupdate.d")) {
- continue;
- }
-
- const char *s = startswith(e->filename, "sysupdate.");
- if (!s)
- continue;
-
- const char *a = endswith(s, ".d");
- if (!a)
- continue;
-
- _cleanup_free_ char *n = strndup(s, a - s);
- if (!n)
- return log_oom();
-
- r = component_name_valid(n);
- if (r < 0)
- return log_error_errno(r, "Unable to validate component name '%s': %m", n);
- if (r == 0)
- continue;
-
- r = set_ensure_put(&names, &string_hash_ops_free, n);
- if (r < 0 && r != -EEXIST)
- return log_error_errno(r, "Failed to add component '%s' to set: %m", n);
- TAKE_PTR(n);
- }
+ 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 */
!arg_image &&
context->n_transfers > 0);
- /* We use simple free() rather than strv_free() here, since set_free() will free the strings for us */
- _cleanup_free_ char **z = set_get_strv(names);
- if (!z)
- return log_oom();
-
- strv_sort(z);
-
if (!sd_json_format_enabled(arg_json_format_flags)) {
- if (!has_default_component && set_isempty(names)) {
+ if (!has_default_component && strv_isempty(z)) {
log_info("No components defined.");
return 0;
}
break;
}
- r = component_name_valid(opts.arg);
- if (r < 0)
- return log_error_errno(r, "Failed to determine if component name is valid: %m");
- if (r == 0)
+ if (!component_name_valid(opts.arg))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Component name invalid: %s", opts.arg);
r = free_and_strdup_warn(&arg_component, opts.arg);
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "sysupdate-util.h"
+#include "tests.h"
+
+TEST(component_name_valid) {
+ /* Valid component names: anything that turns "sysupdate.<name>.d" into a valid filename. */
+ ASSERT_TRUE(component_name_valid("foo"));
+ ASSERT_TRUE(component_name_valid("foo-bar"));
+ ASSERT_TRUE(component_name_valid("foo.bar"));
+ ASSERT_TRUE(component_name_valid("foo_bar_baz"));
+ ASSERT_TRUE(component_name_valid("0815"));
+ ASSERT_TRUE(component_name_valid("über")); /* valid UTF-8 is fine */
+
+ /* Invalid: empty, slashes, control characters, invalid UTF-8. */
+ ASSERT_FALSE(component_name_valid(""));
+ ASSERT_FALSE(component_name_valid("foo/bar"));
+ ASSERT_FALSE(component_name_valid("/foo"));
+ ASSERT_FALSE(component_name_valid("foo/"));
+ ASSERT_FALSE(component_name_valid("foo\tbar"));
+ ASSERT_FALSE(component_name_valid("foo\nbar"));
+ ASSERT_FALSE(component_name_valid("foo\x7f"));
+ ASSERT_FALSE(component_name_valid("\xff")); /* not valid UTF-8 */
+}
+
+DEFINE_TEST_MAIN(LOG_INFO);