[PATCH 1/9] util: Add conf.d support for connmand and vpnd
Jussi Laakkonen <[email protected]> Wed, 20 May 2026 16:47:05 +0300
| Newsgroups | dev.linux.lists.connman |
|---|---|
| Message-ID | <[email protected]> |
Add support for reading and processing of additional configuration
files. Util is best suited for both daemons to avoid adding more
internal dependencies to vpnd.
The files are saved into the list with the full path if it is given as a
parameter. Callback can be omitted for only getting the list of
configuration files with the desired suffix in the given directory.
Callback gets the full path of the config file for convenience.
Add a Glib file error converter to utils. Map the errors in G_FILE_ERROR
domain to matching errnos. Return -EBADMSG if error is NULL and -ENOTSUP
when domain is not G_FILE_ERROR.
---
src/shared/util.c | 179 ++++++++++++++++++++++++++++++++++++++++++++++
src/shared/util.h | 7 ++
2 files changed, 186 insertions(+)
diff --git a/src/shared/util.c b/src/shared/util.c
index bda2d2b3..fa42e1c9 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -3,6 +3,7 @@
* Connection Manager
*
* Copyright (C) 2012 Intel Corporation. All rights reserved.
+ * Copyright (C) 2025 Jolla Mobile Ltd. All right reserved.
*
*
* This library is free software; you can redistribute it and/or
@@ -29,6 +30,11 @@
#include <ctype.h>
#include <stdarg.h>
#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdbool.h>
+
+#include <connman/log.h>
#include "src/shared/util.h"
@@ -128,3 +134,176 @@ char *util_timeval_to_iso8601(struct timeval *time)
return g_strdup(buf);
}
+
+static bool is_file_symlink(const char *filename)
+{
+ int fd;
+
+ fd = open(filename, O_WRONLY | O_NOFOLLOW | O_CLOEXEC);
+ if (fd == -1 && errno == ELOOP)
+ return true;
+
+ if (fd >= 0)
+ close(fd);
+
+ return false;
+}
+
+int util_g_file_error_to_errno(GError *error)
+{
+ if (!error)
+ return -EBADMSG;
+
+ if (error->domain != G_FILE_ERROR)
+ return -ENOTSUP;
+
+ switch (error->code) {
+ case G_FILE_ERROR_EXIST:
+ return -EEXIST;
+ case G_FILE_ERROR_ISDIR:
+ return -EISDIR;
+ case G_FILE_ERROR_ACCES:
+ return -EACCES;
+ case G_FILE_ERROR_NAMETOOLONG:
+ return -ENAMETOOLONG;
+ case G_FILE_ERROR_NOENT:
+ return -ENOENT;
+ case G_FILE_ERROR_NOTDIR:
+ return -ENOTDIR;
+ case G_FILE_ERROR_NXIO:
+ return -ENXIO;
+ case G_FILE_ERROR_NODEV:
+ return -ENODEV;
+ case G_FILE_ERROR_ROFS:
+ return -EROFS;
+ case G_FILE_ERROR_TXTBSY:
+ return -ETXTBSY;
+ case G_FILE_ERROR_FAULT:
+ return -EFAULT;
+ case G_FILE_ERROR_LOOP:
+ return -ELOOP;
+ case G_FILE_ERROR_NOSPC:
+ return -ENOSPC;
+ case G_FILE_ERROR_NOMEM:
+ return -ENOMEM;
+ case G_FILE_ERROR_MFILE:
+ return -EMFILE;
+ case G_FILE_ERROR_NFILE:
+ return -ENFILE;
+ case G_FILE_ERROR_BADF:
+ return EBADF;
+ case G_FILE_ERROR_INVAL:
+ return -EINVAL;
+ case G_FILE_ERROR_PIPE:
+ return -EPIPE;
+ case G_FILE_ERROR_AGAIN:
+ return -EAGAIN;
+ case G_FILE_ERROR_INTR:
+ return -EINTR;
+ case G_FILE_ERROR_IO:
+ return -EIO;
+ case G_FILE_ERROR_PERM:
+ return -EPERM;
+ case G_FILE_ERROR_NOSYS:
+ return -ENOSYS;
+ case G_FILE_ERROR_FAILED:
+ return -EINVAL;
+ }
+
+ return -EINVAL;
+}
+
+int util_read_config_files_from(const char *path, const char *suffix,
+ GList **conffiles, config_callback cb)
+{
+ GList *files = NULL;
+ GList *iter;
+ GError *error = NULL;
+ GDir *dir;
+ const char *filename = NULL;
+ int err = 0;
+
+ if (!path || !suffix)
+ return -EINVAL;
+
+ if (!g_file_test(path, G_FILE_TEST_IS_DIR))
+ return -ENOTDIR;
+
+ dir = g_dir_open(path, 0, &error);
+ if (!dir) {
+ if (error) {
+ connman_warn("cannot open dir %s, error: %s", path,
+ error->message);
+ err = util_g_file_error_to_errno(error);
+ } else {
+ err = -ENOMEM;
+ }
+ }
+
+ g_clear_error(&error);
+
+ if (err)
+ return err;
+
+ /*
+ * Ordering of files is not guaranteed with g_dir_open(). Read
+ * the filenames into list to be sorted after.
+ */
+ while ((filename = g_dir_read_name(dir))) {
+ char *filepath;
+
+ /* Read configs that have the requested conf suffix */
+ if (!g_str_has_suffix(filename, suffix)) {
+ connman_warn("suffix mismatch in %s required: %s",
+ filename, suffix);
+ continue;
+ }
+
+ filepath = g_build_filename(path, filename, NULL);
+
+ /* Allow only regular files */
+ if (!g_file_test(filepath, G_FILE_TEST_IS_REGULAR)) {
+ connman_warn("invalid non-regular file %s", filepath);
+ g_free(filepath);
+ continue;
+ }
+
+ /* Do not allow symlinks */
+ if (is_file_symlink(filepath)) {
+ connman_warn("config %s is a symlink, ignore",
+ filepath);
+ g_free(filepath);
+ continue;
+ }
+
+ /*
+ * Prepend read files into list of configuration
+ * files to be used in checks when new configurations
+ * are added to avoid unnecessary reads of already read
+ * configurations. Sort list after all are added.
+ */
+ files = g_list_prepend(files, filepath);
+ }
+
+ g_dir_close(dir);
+
+ files = g_list_sort(files, (GCompareFunc)g_strcmp0);
+
+ if (cb) {
+ for (iter = files; iter; iter = iter->next) {
+ filename = iter->data;
+
+ err = cb(filename);
+ if (err)
+ connman_warn("cannot process config %s: %d",
+ filename, err);
+ }
+ }
+
+ if (conffiles)
+ *conffiles = files;
+ else
+ g_list_free_full(files, g_free);
+
+ return 0;
+}
diff --git a/src/shared/util.h b/src/shared/util.h
index 430b821f..39fcdeb7 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -3,6 +3,7 @@
* Connection Manager
*
* Copyright (C) 2012 Intel Corporation. All rights reserved.
+ * Copyright (C) 2025 Jolla Mobile Ltd. All right reserved.
*
*
* This library is free software; you can redistribute it and/or
@@ -53,3 +54,9 @@ static inline struct cb_data *cb_data_new(void *cb, void *user_data)
void util_iso8601_to_timeval(char *str, struct timeval *time);
char *util_timeval_to_iso8601(struct timeval *time);
+
+typedef int (*config_callback) (const char *filepath);
+/* Returns -ENOTSUP for non G_FILE_ERROR in error */
+int util_g_file_error_to_errno(GError *error);
+int util_read_config_files_from(const char *path, const char *suffix,
+ GList **conffiles, config_callback cb);
--
2.47.3