summaryrefslogtreecommitdiffstats
path: root/src/shared
diff options
context:
space:
mode:
authorRichard Phibel <rphibel@googlemail.com>2022-11-07 17:13:15 +0100
committerLennart Poettering <lennart@poettering.net>2023-01-10 15:16:26 +0100
commitcd48e23f6a33c9acb47a06b99d9bdc84ee42cebe (patch)
tree4c241fe4081efeb70aa6b33ff9a7613b2b0b2720 /src/shared
parentci: Remove a bunch of labels when a PR is merged (diff)
downloadsystemd-cd48e23f6a33c9acb47a06b99d9bdc84ee42cebe.tar.xz
systemd-cd48e23f6a33c9acb47a06b99d9bdc84ee42cebe.zip
core: add OpenFile setting
Diffstat (limited to 'src/shared')
-rw-r--r--src/shared/bus-unit-util.c21
-rw-r--r--src/shared/meson.build2
-rw-r--r--src/shared/open-file.c150
-rw-r--r--src/shared/open-file.h36
4 files changed, 209 insertions, 0 deletions
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index 7154c9b4c0..0fa2dea2d4 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -29,6 +29,7 @@
#include "mountpoint-util.h"
#include "nsflags.h"
#include "numa-util.h"
+#include "open-file.h"
#include "parse-helpers.h"
#include "parse-util.h"
#include "path-util.h"
@@ -410,6 +411,23 @@ static int bus_append_exec_command(sd_bus_message *m, const char *field, const c
return 1;
}
+static int bus_append_open_file(sd_bus_message *m, const char *field, const char *eq) {
+ _cleanup_(open_file_freep) OpenFile *of = NULL;
+ int r;
+
+ assert(m);
+
+ r = open_file_parse(eq, &of);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse OpenFile= setting: %m");
+
+ r = sd_bus_message_append(m, "(sv)", field, "a(sst)", (size_t) 1, of->path, of->fdname, of->flags);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 1;
+}
+
static int bus_append_ip_address_access(sd_bus_message *m, int family, const union in_addr_union *prefix, unsigned char prefixlen) {
int r;
@@ -2300,6 +2318,9 @@ static int bus_append_service_property(sd_bus_message *m, const char *field, con
return 1;
}
+ if (streq(field, "OpenFile"))
+ return bus_append_open_file(m, field, eq);
+
return 0;
}
diff --git a/src/shared/meson.build b/src/shared/meson.build
index 0d5e9f2dbb..bc1cfa5b4b 100644
--- a/src/shared/meson.build
+++ b/src/shared/meson.build
@@ -243,6 +243,8 @@ shared_sources = files(
'nsflags.h',
'numa-util.c',
'numa-util.h',
+ 'open-file.c',
+ 'open-file.h',
'openssl-util.c',
'openssl-util.h',
'output-mode.c',
diff --git a/src/shared/open-file.c b/src/shared/open-file.c
new file mode 100644
index 0000000000..dedf067c4c
--- /dev/null
+++ b/src/shared/open-file.c
@@ -0,0 +1,150 @@
+
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <fcntl.h>
+
+#include "escape.h"
+#include "extract-word.h"
+#include "fd-util.h"
+#include "open-file.h"
+#include "path-util.h"
+#include "string-table.h"
+#include "string-util.h"
+
+int open_file_parse(const char *v, OpenFile **ret) {
+ _cleanup_free_ char *options = NULL;
+ _cleanup_(open_file_freep) OpenFile *of = NULL;
+ int r;
+
+ assert(v);
+ assert(ret);
+
+ of = new0(OpenFile, 1);
+ if (!of)
+ return -ENOMEM;
+
+ r = extract_many_words(&v, ":", EXTRACT_DONT_COALESCE_SEPARATORS|EXTRACT_CUNESCAPE, &of->path, &of->fdname, &options, NULL);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -EINVAL;
+
+ /* Enforce that at most 3 colon-separated words are present */
+ if (!isempty(v))
+ return -EINVAL;
+
+ for (const char *p = options;;) {
+ OpenFileFlag flag;
+ _cleanup_free_ char *word = NULL;
+
+ r = extract_first_word(&p, &word, ",", 0);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ flag = open_file_flags_from_string(word);
+ if (flag < 0)
+ return flag;
+
+ if ((flag & of->flags) != 0)
+ return -EINVAL;
+
+ of->flags |= flag;
+ }
+
+ if (isempty(of->fdname)) {
+ free(of->fdname);
+ r = path_extract_filename(of->path, &of->fdname);
+ if (r < 0)
+ return r;
+ }
+
+ r = open_file_validate(of);
+ if (r < 0)
+ return r;
+
+ *ret = TAKE_PTR(of);
+
+ return 0;
+}
+
+int open_file_validate(const OpenFile *of) {
+ assert(of);
+
+ if (!path_is_valid(of->path) || !path_is_absolute(of->path))
+ return -EINVAL;
+
+ if (!fdname_is_valid(of->fdname))
+ return -EINVAL;
+
+ if ((FLAGS_SET(of->flags, OPENFILE_READ_ONLY) + FLAGS_SET(of->flags, OPENFILE_APPEND) +
+ FLAGS_SET(of->flags, OPENFILE_TRUNCATE)) > 1)
+ return -EINVAL;
+
+ if ((of->flags & ~_OPENFILE_MASK_PUBLIC) != 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+int open_file_to_string(const OpenFile *of, char **ret) {
+ _cleanup_free_ char *options = NULL, *fname = NULL, *s = NULL;
+ bool has_fdname = false;
+ int r;
+
+ assert(of);
+ assert(ret);
+
+ s = shell_escape(of->path, ":");
+ if (!s)
+ return -ENOMEM;
+
+ r = path_extract_filename(of->path, &fname);
+ if (r < 0)
+ return r;
+
+ has_fdname = !streq(fname, of->fdname);
+ if (has_fdname)
+ if (!strextend(&s, ":", of->fdname))
+ return -ENOMEM;
+
+ for (OpenFileFlag flag = OPENFILE_READ_ONLY; flag < _OPENFILE_MAX; flag <<= 1)
+ if (FLAGS_SET(of->flags, flag) && !strextend_with_separator(&options, ",", open_file_flags_to_string(flag)))
+ return -ENOMEM;
+
+ if (options)
+ if (!(has_fdname ? strextend(&s, ":", options) : strextend(&s, "::", options)))
+ return -ENOMEM;
+
+ *ret = TAKE_PTR(s);
+
+ return 0;
+}
+
+OpenFile *open_file_free(OpenFile *of) {
+ if (!of)
+ return NULL;
+
+ free(of->path);
+ free(of->fdname);
+ return mfree(of);
+}
+
+void open_file_free_many(OpenFile **head) {
+ OpenFile *of;
+
+ while ((of = *head)) {
+ LIST_REMOVE(open_files, *head, of);
+ of = open_file_free(of);
+ }
+}
+
+static const char * const open_file_flags_table[_OPENFILE_MAX] = {
+ [OPENFILE_READ_ONLY] = "read-only",
+ [OPENFILE_APPEND] = "append",
+ [OPENFILE_TRUNCATE] = "truncate",
+ [OPENFILE_GRACEFUL] = "graceful",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(open_file_flags, OpenFileFlag);
diff --git a/src/shared/open-file.h b/src/shared/open-file.h
new file mode 100644
index 0000000000..bb63ec8f9c
--- /dev/null
+++ b/src/shared/open-file.h
@@ -0,0 +1,36 @@
+
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include "list.h"
+
+typedef enum OpenFileFlag {
+ OPENFILE_READ_ONLY = 1 << 0,
+ OPENFILE_APPEND = 1 << 1,
+ OPENFILE_TRUNCATE = 1 << 2,
+ OPENFILE_GRACEFUL = 1 << 3,
+ _OPENFILE_MAX,
+ _OPENFILE_INVALID = -EINVAL,
+ _OPENFILE_MASK_PUBLIC = OPENFILE_READ_ONLY | OPENFILE_APPEND | OPENFILE_TRUNCATE | OPENFILE_GRACEFUL,
+} OpenFileFlag;
+
+typedef struct OpenFile {
+ char *path;
+ char *fdname;
+ OpenFileFlag flags;
+ LIST_FIELDS(struct OpenFile, open_files);
+} OpenFile;
+
+int open_file_parse(const char *v, OpenFile **ret);
+
+int open_file_validate(const OpenFile *of);
+
+int open_file_to_string(const OpenFile *of, char **ret);
+
+OpenFile *open_file_free(OpenFile *of);
+DEFINE_TRIVIAL_CLEANUP_FUNC(OpenFile*, open_file_free);
+
+void open_file_free_many(OpenFile **head);
+
+const char *open_file_flags_to_string(OpenFileFlag t) _const_;
+OpenFileFlag open_file_flags_from_string(const char *t) _pure_;