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