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