Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */
2 :
3 : #include <sys/mman.h>
4 :
5 : #include "alloc-util.h"
6 : #include "env-util.h"
7 : #include "escape.h"
8 : #include "fileio.h"
9 : #include "missing.h"
10 : #include "parse-util.h"
11 : #include "process-util.h"
12 : #include "serialize.h"
13 : #include "strv.h"
14 : #include "tmpfile-util.h"
15 :
16 27 : int serialize_item(FILE *f, const char *key, const char *value) {
17 27 : assert(f);
18 27 : assert(key);
19 :
20 27 : if (!value)
21 1 : return 0;
22 :
23 : /* Make sure that anything we serialize we can also read back again with read_line() with a maximum line size
24 : * of LONG_LINE_MAX. This is a safety net only. All code calling us should filter this out earlier anyway. */
25 26 : if (strlen(key) + 1 + strlen(value) + 1 > LONG_LINE_MAX) {
26 7 : log_warning("Attempted to serialize overly long item '%s', refusing.", key);
27 7 : return -EINVAL;
28 : }
29 :
30 19 : fputs(key, f);
31 19 : fputc('=', f);
32 19 : fputs(value, f);
33 19 : fputc('\n', f);
34 :
35 19 : return 1;
36 : }
37 :
38 22 : int serialize_item_escaped(FILE *f, const char *key, const char *value) {
39 22 : _cleanup_free_ char *c = NULL;
40 :
41 22 : assert(f);
42 22 : assert(key);
43 :
44 22 : if (!value)
45 1 : return 0;
46 :
47 21 : c = cescape(value);
48 21 : if (!c)
49 0 : return log_oom();
50 :
51 21 : return serialize_item(f, key, c);
52 : }
53 :
54 2 : int serialize_item_format(FILE *f, const char *key, const char *format, ...) {
55 : char buf[LONG_LINE_MAX];
56 : va_list ap;
57 : int k;
58 :
59 2 : assert(f);
60 2 : assert(key);
61 2 : assert(format);
62 :
63 2 : va_start(ap, format);
64 2 : k = vsnprintf(buf, sizeof(buf), format, ap);
65 2 : va_end(ap);
66 :
67 2 : if (k < 0 || (size_t) k >= sizeof(buf) || strlen(key) + 1 + k + 1 > LONG_LINE_MAX) {
68 0 : log_warning("Attempted to serialize overly long item '%s', refusing.", key);
69 0 : return -EINVAL;
70 : }
71 :
72 2 : fputs(key, f);
73 2 : fputc('=', f);
74 2 : fputs(buf, f);
75 2 : fputc('\n', f);
76 :
77 2 : return 1;
78 : }
79 :
80 0 : int serialize_fd(FILE *f, FDSet *fds, const char *key, int fd) {
81 : int copy;
82 :
83 0 : assert(f);
84 0 : assert(key);
85 :
86 0 : if (fd < 0)
87 0 : return 0;
88 :
89 0 : copy = fdset_put_dup(fds, fd);
90 0 : if (copy < 0)
91 0 : return log_error_errno(copy, "Failed to add file descriptor to serialization set: %m");
92 :
93 0 : return serialize_item_format(f, key, "%i", copy);
94 : }
95 :
96 3 : int serialize_usec(FILE *f, const char *key, usec_t usec) {
97 3 : assert(f);
98 3 : assert(key);
99 :
100 3 : if (usec == USEC_INFINITY)
101 1 : return 0;
102 :
103 2 : return serialize_item_format(f, key, USEC_FMT, usec);
104 : }
105 :
106 0 : int serialize_dual_timestamp(FILE *f, const char *name, const dual_timestamp *t) {
107 0 : assert(f);
108 0 : assert(name);
109 0 : assert(t);
110 :
111 0 : if (!dual_timestamp_is_set(t))
112 0 : return 0;
113 :
114 0 : return serialize_item_format(f, name, USEC_FMT " " USEC_FMT, t->realtime, t->monotonic);
115 : }
116 :
117 5 : int serialize_strv(FILE *f, const char *key, char **l) {
118 5 : int ret = 0, r;
119 : char **i;
120 :
121 : /* Returns the first error, or positive if anything was serialized, 0 otherwise. */
122 :
123 21 : STRV_FOREACH(i, l) {
124 16 : r = serialize_item_escaped(f, key, *i);
125 16 : if ((ret >= 0 && r < 0) ||
126 2 : (ret == 0 && r > 0))
127 3 : ret = r;
128 : }
129 :
130 5 : return ret;
131 : }
132 :
133 2 : int deserialize_usec(const char *value, usec_t *ret) {
134 : int r;
135 :
136 2 : assert(value);
137 :
138 2 : r = safe_atou64(value, ret);
139 2 : if (r < 0)
140 0 : return log_debug_errno(r, "Failed to parse usec value \"%s\": %m", value);
141 :
142 2 : return 0;
143 : }
144 :
145 7 : int deserialize_dual_timestamp(const char *value, dual_timestamp *t) {
146 : uint64_t a, b;
147 : int r, pos;
148 :
149 7 : assert(value);
150 7 : assert(t);
151 :
152 7 : pos = strspn(value, WHITESPACE);
153 7 : if (value[pos] == '-')
154 1 : return -EINVAL;
155 6 : pos += strspn(value + pos, DIGITS);
156 6 : pos += strspn(value + pos, WHITESPACE);
157 6 : if (value[pos] == '-')
158 1 : return -EINVAL;
159 :
160 5 : r = sscanf(value, "%" PRIu64 "%" PRIu64 "%n", &a, &b, &pos);
161 5 : if (r != 2)
162 1 : return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
163 : "Failed to parse dual timestamp value \"%s\".",
164 : value);
165 :
166 4 : if (value[pos] != '\0')
167 : /* trailing garbage */
168 1 : return -EINVAL;
169 :
170 3 : t->realtime = a;
171 3 : t->monotonic = b;
172 :
173 3 : return 0;
174 : }
175 :
176 17 : int deserialize_environment(const char *value, char ***list) {
177 17 : _cleanup_free_ char *unescaped = NULL;
178 : int r;
179 :
180 17 : assert(value);
181 17 : assert(list);
182 :
183 : /* Changes the *environment strv inline. */
184 :
185 17 : r = cunescape(value, 0, &unescaped);
186 17 : if (r < 0)
187 2 : return log_error_errno(r, "Failed to unescape: %m");
188 :
189 15 : r = strv_env_replace(list, unescaped);
190 15 : if (r < 0)
191 0 : return log_error_errno(r, "Failed to append environment variable: %m");
192 :
193 15 : unescaped = NULL; /* now part of 'list' */
194 15 : return 0;
195 : }
196 :
197 22 : int open_serialization_fd(const char *ident) {
198 : int fd;
199 :
200 22 : fd = memfd_create(ident, MFD_CLOEXEC);
201 22 : if (fd < 0) {
202 : const char *path;
203 :
204 0 : path = getpid_cached() == 1 ? "/run/systemd" : "/tmp";
205 0 : fd = open_tmpfile_unlinkable(path, O_RDWR|O_CLOEXEC);
206 0 : if (fd < 0)
207 0 : return fd;
208 :
209 0 : log_debug("Serializing %s to %s.", ident, path);
210 : } else
211 22 : log_debug("Serializing %s to memfd.", ident);
212 :
213 22 : return fd;
214 : }
|