]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/serialize.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
5 #include "alloc-util.h"
10 #include "hexdecoct.h"
11 #include "memfd-util.h"
12 #include "missing_mman.h"
13 #include "missing_syscall.h"
14 #include "parse-util.h"
15 #include "process-util.h"
16 #include "serialize.h"
18 #include "tmpfile-util.h"
20 int serialize_item(FILE *f
, const char *key
, const char *value
) {
27 /* Make sure that anything we serialize we can also read back again with read_line() with a maximum line size
28 * of LONG_LINE_MAX. This is a safety net only. All code calling us should filter this out earlier anyway. */
29 if (strlen(key
) + 1 + strlen(value
) + 1 > LONG_LINE_MAX
)
30 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
), "Attempted to serialize overly long item '%s', refusing.", key
);
40 int serialize_item_escaped(FILE *f
, const char *key
, const char *value
) {
41 _cleanup_free_
char *c
= NULL
;
49 c
= xescape(value
, " ");
53 return serialize_item(f
, key
, c
);
56 int serialize_item_format(FILE *f
, const char *key
, const char *format
, ...) {
57 _cleanup_free_
char *allocated
= NULL
;
58 char buf
[256]; /* Something reasonably short that fits nicely on any stack (i.e. is considerably less
59 * than LONG_LINE_MAX (1MiB!) */
68 /* First, let's try to format this into a stack buffer */
70 k
= vsnprintf(buf
, sizeof(buf
), format
, ap
);
74 return log_warning_errno(errno
, "Failed to serialize item '%s', ignoring: %m", key
);
75 if (strlen(key
) + 1 + k
+ 1 > LONG_LINE_MAX
) /* See above */
76 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
), "Attempted to serialize overly long item '%s', refusing.", key
);
78 if ((size_t) k
< sizeof(buf
))
79 b
= buf
; /* Yay, it fit! */
81 /* So the string didn't fit in the short buffer above, but was not above our total limit,
82 * hence let's format it via dynamic memory */
85 k
= vasprintf(&allocated
, format
, ap
);
89 return log_warning_errno(errno
, "Failed to serialize item '%s', ignoring: %m", key
);
102 int serialize_fd(FILE *f
, FDSet
*fds
, const char *key
, int fd
) {
112 copy
= fdset_put_dup(fds
, fd
);
114 return log_error_errno(copy
, "Failed to add file descriptor to serialization set: %m");
116 return serialize_item_format(f
, key
, "%i", copy
);
119 int serialize_fd_many(FILE *f
, FDSet
*fds
, const char *key
, const int fd_array
[], size_t n_fd_array
) {
120 _cleanup_free_
char *t
= NULL
;
129 for (size_t i
= 0; i
< n_fd_array
; i
++) {
135 copy
= fdset_put_dup(fds
, fd_array
[i
]);
137 return log_error_errno(copy
, "Failed to add file descriptor to serialization set: %m");
139 if (strextendf_with_separator(&t
, " ", "%i", copy
) < 0)
143 return serialize_item(f
, key
, t
);
146 int serialize_usec(FILE *f
, const char *key
, usec_t usec
) {
150 if (usec
== USEC_INFINITY
)
153 return serialize_item_format(f
, key
, USEC_FMT
, usec
);
156 int serialize_dual_timestamp(FILE *f
, const char *name
, const dual_timestamp
*t
) {
161 if (!dual_timestamp_is_set(t
))
164 return serialize_item_format(f
, name
, USEC_FMT
" " USEC_FMT
, t
->realtime
, t
->monotonic
);
167 int serialize_strv(FILE *f
, const char *key
, char **l
) {
170 /* Returns the first error, or positive if anything was serialized, 0 otherwise. */
173 r
= serialize_item_escaped(f
, key
, *i
);
174 if ((ret
>= 0 && r
< 0) ||
182 int serialize_pidref(FILE *f
, FDSet
*fds
, const char *key
, PidRef
*pidref
) {
188 if (!pidref_is_set(pidref
))
191 /* If we have a pidfd we serialize the fd and encode the fd number prefixed by "@" in the
192 * serialization. Otherwise we serialize the numeric PID as it is. */
195 return serialize_item_format(f
, key
, PID_FMT
, pidref
->pid
);
197 copy
= fdset_put_dup(fds
, pidref
->fd
);
199 return log_error_errno(copy
, "Failed to add file descriptor to serialization set: %m");
201 return serialize_item_format(f
, key
, "@%i", copy
);
204 int serialize_ratelimit(FILE *f
, const char *key
, const RateLimit
*rl
) {
207 return serialize_item_format(f
, key
,
208 USEC_FMT
" " USEC_FMT
" %u %u",
215 int serialize_item_hexmem(FILE *f
, const char *key
, const void *p
, size_t l
) {
216 _cleanup_free_
char *encoded
= NULL
;
228 encoded
= hexmem(p
, l
);
230 return log_oom_debug();
232 r
= serialize_item(f
, key
, encoded
);
239 int serialize_item_base64mem(FILE *f
, const char *key
, const void *p
, size_t l
) {
240 _cleanup_free_
char *encoded
= NULL
;
253 len
= base64mem(p
, l
, &encoded
);
255 return log_oom_debug();
257 r
= serialize_item(f
, key
, encoded
);
264 int serialize_string_set(FILE *f
, const char *key
, Set
*s
) {
274 /* Serialize as individual items, as each element might contain separators and escapes */
277 r
= serialize_item(f
, key
, e
);
285 int serialize_image_policy(FILE *f
, const char *key
, const ImagePolicy
*p
) {
286 _cleanup_free_
char *policy
= NULL
;
295 r
= image_policy_to_string(p
, /* simplify= */ false, &policy
);
299 r
= serialize_item(f
, key
, policy
);
306 int deserialize_read_line(FILE *f
, char **ret
) {
307 _cleanup_free_
char *line
= NULL
;
313 r
= read_stripped_line(f
, LONG_LINE_MAX
, &line
);
315 return log_error_errno(r
, "Failed to read serialization line: %m");
316 if (r
== 0) { /* eof */
321 if (isempty(line
)) { /* End marker */
326 *ret
= TAKE_PTR(line
);
330 int deserialize_fd(FDSet
*fds
, const char *value
) {
331 _cleanup_close_
int our_fd
= -EBADF
;
336 parsed_fd
= parse_fd(value
);
338 return log_debug_errno(parsed_fd
, "Failed to parse file descriptor serialization: %s", value
);
340 our_fd
= fdset_remove(fds
, parsed_fd
); /* Take possession of the fd */
342 return log_debug_errno(our_fd
, "Failed to acquire fd from serialization fds: %m");
344 return TAKE_FD(our_fd
);
347 int deserialize_fd_many(FDSet
*fds
, const char *value
, size_t n
, int *ret
) {
348 int r
, *fd_array
= NULL
;
353 fd_array
= new(int, n
);
357 CLEANUP_ARRAY(fd_array
, m
, close_many_and_free
);
360 _cleanup_free_
char *w
= NULL
;
363 r
= extract_first_word(&value
, &w
, NULL
, 0);
367 if (m
< n
) /* Too few */
373 if (m
>= n
) /* Too many */
376 fd
= deserialize_fd(fds
, w
);
383 memcpy(ret
, fd_array
, m
* sizeof(int));
384 fd_array
= mfree(fd_array
);
389 int deserialize_strv(const char *value
, char ***l
) {
390 ssize_t unescaped_len
;
396 unescaped_len
= cunescape(value
, 0, &unescaped
);
397 if (unescaped_len
< 0)
398 return unescaped_len
;
400 return strv_consume(l
, unescaped
);
403 int deserialize_usec(const char *value
, usec_t
*ret
) {
409 r
= safe_atou64(value
, ret
);
411 return log_debug_errno(r
, "Failed to parse usec value \"%s\": %m", value
);
416 int deserialize_dual_timestamp(const char *value
, dual_timestamp
*ret
) {
423 pos
= strspn(value
, WHITESPACE
);
424 if (value
[pos
] == '-')
426 pos
+= strspn(value
+ pos
, DIGITS
);
427 pos
+= strspn(value
+ pos
, WHITESPACE
);
428 if (value
[pos
] == '-')
431 r
= sscanf(value
, "%" PRIu64
"%" PRIu64
"%n", &a
, &b
, &pos
);
433 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
),
434 "Failed to parse dual timestamp value \"%s\".",
437 if (value
[pos
] != '\0')
438 /* trailing garbage */
441 *ret
= (dual_timestamp
) {
449 int deserialize_environment(const char *value
, char ***list
) {
450 _cleanup_free_
char *unescaped
= NULL
;
457 /* Changes the *environment strv inline. */
459 l
= cunescape(value
, 0, &unescaped
);
461 return log_error_errno(l
, "Failed to unescape: %m");
463 r
= strv_env_replace_consume(list
, TAKE_PTR(unescaped
));
465 return log_error_errno(r
, "Failed to append environment variable: %m");
470 int deserialize_pidref(FDSet
*fds
, const char *value
, PidRef
*ret
) {
477 e
= startswith(value
, "@");
479 int fd
= deserialize_fd(fds
, e
);
484 r
= pidref_set_pidfd_consume(ret
, fd
);
488 r
= parse_pid(value
, &pid
);
490 return log_debug_errno(r
, "Failed to parse PID: %s", value
);
492 r
= pidref_set_pid(ret
, pid
);
495 return log_debug_errno(r
, "Failed to initialize pidref: %m");
500 void deserialize_ratelimit(RateLimit
*rl
, const char *name
, const char *value
) {
501 usec_t begin
, interval
;
508 if (sscanf(value
, USEC_FMT
" " USEC_FMT
" %u %u", &begin
, &interval
, &num
, &burst
) != 4)
509 return log_notice("Failed to parse %s, ignoring: %s", name
, value
);
511 /* Preserve the counter only if the configuration didn't change. */
512 rl
->num
= (interval
== rl
->interval
&& burst
== rl
->burst
) ? num
: 0;
516 int open_serialization_fd(const char *ident
) {
519 fd
= memfd_create_wrapper(ident
, MFD_CLOEXEC
| MFD_NOEXEC_SEAL
);
523 path
= getpid_cached() == 1 ? "/run/systemd" : "/tmp";
524 fd
= open_tmpfile_unlinkable(path
, O_RDWR
|O_CLOEXEC
);
528 log_debug("Serializing %s to %s.", ident
, path
);
530 log_debug("Serializing %s to memfd.", ident
);
535 int open_serialization_file(const char *ident
, FILE **ret
) {
536 _cleanup_fclose_
FILE *f
= NULL
;
537 _cleanup_close_
int fd
;
541 fd
= open_serialization_fd(ident
);
545 f
= take_fdopen(&fd
, "w+");