diff options
author | Richard Phibel <rphibel@googlemail.com> | 2022-11-07 17:13:15 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2023-01-10 15:16:26 +0100 |
commit | cd48e23f6a33c9acb47a06b99d9bdc84ee42cebe (patch) | |
tree | 4c241fe4081efeb70aa6b33ff9a7613b2b0b2720 /src/shared | |
parent | ci: Remove a bunch of labels when a PR is merged (diff) | |
download | systemd-cd48e23f6a33c9acb47a06b99d9bdc84ee42cebe.tar.xz systemd-cd48e23f6a33c9acb47a06b99d9bdc84ee42cebe.zip |
core: add OpenFile setting
Diffstat (limited to 'src/shared')
-rw-r--r-- | src/shared/bus-unit-util.c | 21 | ||||
-rw-r--r-- | src/shared/meson.build | 2 | ||||
-rw-r--r-- | src/shared/open-file.c | 150 | ||||
-rw-r--r-- | src/shared/open-file.h | 36 |
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_; |