Branch data 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 : 108 : int serialize_item(FILE *f, const char *key, const char *value) {
17 [ - + ]: 108 : assert(f);
18 [ - + ]: 108 : assert(key);
19 : :
20 [ + + ]: 108 : if (!value)
21 : 4 : 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 [ + + ]: 104 : if (strlen(key) + 1 + strlen(value) + 1 > LONG_LINE_MAX) {
26 [ + - ]: 28 : log_warning("Attempted to serialize overly long item '%s', refusing.", key);
27 : 28 : return -EINVAL;
28 : : }
29 : :
30 : 76 : fputs(key, f);
31 : 76 : fputc('=', f);
32 : 76 : fputs(value, f);
33 : 76 : fputc('\n', f);
34 : :
35 : 76 : return 1;
36 : : }
37 : :
38 : 88 : int serialize_item_escaped(FILE *f, const char *key, const char *value) {
39 : 88 : _cleanup_free_ char *c = NULL;
40 : :
41 [ - + ]: 88 : assert(f);
42 [ - + ]: 88 : assert(key);
43 : :
44 [ + + ]: 88 : if (!value)
45 : 4 : return 0;
46 : :
47 : 84 : c = cescape(value);
48 [ - + ]: 84 : if (!c)
49 : 0 : return log_oom();
50 : :
51 : 84 : return serialize_item(f, key, c);
52 : : }
53 : :
54 : 8 : 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 [ - + ]: 8 : assert(f);
60 [ - + ]: 8 : assert(key);
61 [ - + ]: 8 : assert(format);
62 : :
63 : 8 : va_start(ap, format);
64 : 8 : k = vsnprintf(buf, sizeof(buf), format, ap);
65 : 8 : va_end(ap);
66 : :
67 [ + - + - : 8 : 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 : 8 : fputs(key, f);
73 : 8 : fputc('=', f);
74 : 8 : fputs(buf, f);
75 : 8 : fputc('\n', f);
76 : :
77 : 8 : 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 : 12 : int serialize_usec(FILE *f, const char *key, usec_t usec) {
97 [ - + ]: 12 : assert(f);
98 [ - + ]: 12 : assert(key);
99 : :
100 [ + + ]: 12 : if (usec == USEC_INFINITY)
101 : 4 : return 0;
102 : :
103 : 8 : 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 : 20 : int serialize_strv(FILE *f, const char *key, char **l) {
118 : 20 : int ret = 0, r;
119 : : char **i;
120 : :
121 : : /* Returns the first error, or positive if anything was serialized, 0 otherwise. */
122 : :
123 [ + + + + ]: 84 : STRV_FOREACH(i, l) {
124 : 64 : r = serialize_item_escaped(f, key, *i);
125 [ + - + + : 64 : if ((ret >= 0 && r < 0) ||
+ + ]
126 [ + - ]: 8 : (ret == 0 && r > 0))
127 : 12 : ret = r;
128 : : }
129 : :
130 : 20 : return ret;
131 : : }
132 : :
133 : 8 : int deserialize_usec(const char *value, usec_t *ret) {
134 : : int r;
135 : :
136 [ - + ]: 8 : assert(value);
137 : :
138 : 8 : r = safe_atou64(value, ret);
139 [ - + ]: 8 : if (r < 0)
140 [ # # ]: 0 : return log_debug_errno(r, "Failed to parse usec value \"%s\": %m", value);
141 : :
142 : 8 : return 0;
143 : : }
144 : :
145 : 28 : int deserialize_dual_timestamp(const char *value, dual_timestamp *t) {
146 : : uint64_t a, b;
147 : : int r, pos;
148 : :
149 [ - + ]: 28 : assert(value);
150 [ - + ]: 28 : assert(t);
151 : :
152 : 28 : pos = strspn(value, WHITESPACE);
153 [ + + ]: 28 : if (value[pos] == '-')
154 : 4 : return -EINVAL;
155 : 24 : pos += strspn(value + pos, DIGITS);
156 : 24 : pos += strspn(value + pos, WHITESPACE);
157 [ + + ]: 24 : if (value[pos] == '-')
158 : 4 : return -EINVAL;
159 : :
160 : 20 : r = sscanf(value, "%" PRIu64 "%" PRIu64 "%n", &a, &b, &pos);
161 [ + + ]: 20 : if (r != 2)
162 [ - + ]: 4 : return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
163 : : "Failed to parse dual timestamp value \"%s\".",
164 : : value);
165 : :
166 [ + + ]: 16 : if (value[pos] != '\0')
167 : : /* trailing garbage */
168 : 4 : return -EINVAL;
169 : :
170 : 12 : t->realtime = a;
171 : 12 : t->monotonic = b;
172 : :
173 : 12 : return 0;
174 : : }
175 : :
176 : 68 : int deserialize_environment(const char *value, char ***list) {
177 : 68 : _cleanup_free_ char *unescaped = NULL;
178 : : int r;
179 : :
180 [ - + ]: 68 : assert(value);
181 [ - + ]: 68 : assert(list);
182 : :
183 : : /* Changes the *environment strv inline. */
184 : :
185 : 68 : r = cunescape(value, 0, &unescaped);
186 [ + + ]: 68 : if (r < 0)
187 [ + - ]: 8 : return log_error_errno(r, "Failed to unescape: %m");
188 : :
189 : 60 : r = strv_env_replace(list, unescaped);
190 [ - + ]: 60 : if (r < 0)
191 [ # # ]: 0 : return log_error_errno(r, "Failed to append environment variable: %m");
192 : :
193 : 60 : unescaped = NULL; /* now part of 'list' */
194 : 60 : return 0;
195 : : }
196 : :
197 : 88 : int open_serialization_fd(const char *ident) {
198 : : int fd;
199 : :
200 : 88 : fd = memfd_create(ident, MFD_CLOEXEC);
201 [ - + ]: 88 : 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 [ + - ]: 88 : log_debug("Serializing %s to memfd.", ident);
212 : :
213 : 88 : return fd;
214 : : }
|