Bug Summary

File:build-scan/../src/portable/portable.c
Warning:line 1124, column 16
Potential leak of memory pointed to by 'marker'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name portable.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -menable-no-infs -menable-no-nans -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.0.0 -include config.h -I systemd-portabled.p -I . -I .. -I src/basic -I ../src/basic -I src/shared -I ../src/shared -I src/systemd -I ../src/systemd -I src/journal -I ../src/journal -I src/journal-remote -I ../src/journal-remote -I src/nspawn -I ../src/nspawn -I src/resolve -I ../src/resolve -I src/timesync -I ../src/timesync -I ../src/time-wait-sync -I src/login -I ../src/login -I src/udev -I ../src/udev -I src/libudev -I ../src/libudev -I src/core -I ../src/core -I ../src/libsystemd/sd-bus -I ../src/libsystemd/sd-device -I ../src/libsystemd/sd-hwdb -I ../src/libsystemd/sd-id128 -I ../src/libsystemd/sd-netlink -I ../src/libsystemd/sd-network -I src/libsystemd-network -I ../src/libsystemd-network -D _FILE_OFFSET_BITS=64 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unused-result -Wno-format-signedness -Wno-error=nonnull -std=gnu99 -fconst-strings -fdebug-compilation-dir /home/mrc0mmand/repos/@redhat-plumbers/systemd-rhel8/build-scan -ferror-limit 19 -fvisibility hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-07-16-221226-1465241-1 -x c ../src/portable/portable.c
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include <stdio_ext.h>
4
5#include "bus-common-errors.h"
6#include "bus-error.h"
7#include "conf-files.h"
8#include "copy.h"
9#include "def.h"
10#include "dirent-util.h"
11#include "dissect-image.h"
12#include "fd-util.h"
13#include "fileio.h"
14#include "fs-util.h"
15#include "io-util.h"
16#include "locale-util.h"
17#include "loop-util.h"
18#include "machine-image.h"
19#include "mkdir.h"
20#include "os-util.h"
21#include "path-lookup.h"
22#include "portable.h"
23#include "process-util.h"
24#include "set.h"
25#include "signal-util.h"
26#include "socket-util.h"
27#include "string-table.h"
28#include "strv.h"
29#include "user-util.h"
30
31static const char profile_dirs[] = CONF_PATHS_NULSTR("systemd/portable/profile")"/etc/" "systemd/portable/profile" "\0" "/run/" "systemd/portable/profile"
"\0" "/usr/local/lib/" "systemd/portable/profile" "\0" "/usr/lib/"
"systemd/portable/profile" "\0"
;
32
33/* Markers used in the first line of our 20-portable.conf unit file drop-in to determine, that a) the unit file was
34 * dropped there by the portable service logic and b) for which image it was dropped there. */
35#define PORTABLE_DROPIN_MARKER_BEGIN"# Drop-in created for image '" "# Drop-in created for image '"
36#define PORTABLE_DROPIN_MARKER_END"', do not edit." "', do not edit."
37
38static bool_Bool prefix_match(const char *unit, const char *prefix) {
39 const char *p;
40
41 p = startswith(unit, prefix);
42 if (!p)
43 return false0;
44
45 /* Only respect prefixes followed by dash or dot or when there's a complete match */
46 return IN_SET(*p, '-', '.', '@', 0)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){'-', '.', '@', 0})/sizeof(int)]; switch(
*p) { case '-': case '.': case '@': case 0: _found = 1; break
; default: break; } _found; })
;
47}
48
49static bool_Bool unit_match(const char *unit, char **matches) {
50 const char *dot;
51 char **i;
52
53 dot = strrchr(unit, '.');
54 if (!dot)
55 return false0;
56
57 if (!STR_IN_SET(dot, ".service", ".socket", ".target", ".timer", ".path")(!!strv_find((((char**) ((const char*[]) { ".service", ".socket"
, ".target", ".timer", ".path", ((void*)0) }))), (dot)))
)
58 return false0;
59
60 /* Empty match expression means: everything */
61 if (strv_isempty(matches))
62 return true1;
63
64 /* Otherwise, at least one needs to match */
65 STRV_FOREACH(i, matches)for ((i) = (matches); (i) && *(i); (i)++)
66 if (prefix_match(unit, *i))
67 return true1;
68
69 return false0;
70}
71
72static PortableMetadata *portable_metadata_new(const char *name, int fd) {
73 PortableMetadata *m;
74
75 m = malloc0(offsetof(PortableMetadata, name) + strlen(name) + 1)(calloc(1, (__builtin_offsetof(PortableMetadata, name) + strlen
(name) + 1)))
;
76 if (!m)
77 return NULL((void*)0);
78
79 strcpy(m->name, name);
80 m->fd = fd;
81
82 return m;
83}
84
85PortableMetadata *portable_metadata_unref(PortableMetadata *i) {
86 if (!i)
87 return NULL((void*)0);
88
89 safe_close(i->fd);
90 free(i->source);
91
92 return mfree(i);
93}
94
95Hashmap *portable_metadata_hashmap_unref(Hashmap *h) {
96
97 for (;;) {
98 PortableMetadata *i;
99
100 i = hashmap_steal_first(h);
101 if (!i)
102 break;
103
104 portable_metadata_unref(i);
105 }
106
107 return hashmap_free(h);
108}
109
110static int compare_metadata(PortableMetadata *const *x, PortableMetadata *const *y) {
111 return strcmp((*x)->name, (*y)->name);
112}
113
114int portable_metadata_hashmap_to_sorted_array(Hashmap *unit_files, PortableMetadata ***ret) {
115
116 _cleanup_free___attribute__((cleanup(freep))) PortableMetadata **sorted = NULL((void*)0);
117 Iterator iterator;
118 PortableMetadata *item;
119 size_t k = 0;
120
121 sorted = new(PortableMetadata*, hashmap_size(unit_files))((PortableMetadata**) malloc_multiply(sizeof(PortableMetadata
*), (hashmap_size(unit_files))))
;
122 if (!sorted)
123 return -ENOMEM12;
124
125 HASHMAP_FOREACH(item, unit_files, iterator)for ((iterator) = ((Iterator) { .idx = ((2147483647 *2U +1U) -
1), .next_key = ((void*)0) }); hashmap_iterate((unit_files),
&(iterator), (void**)&(item), ((void*)0)); )
126 sorted[k++] = item;
127
128 assert(k == hashmap_size(unit_files))do { if ((__builtin_expect(!!(!(k == hashmap_size(unit_files)
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("k == hashmap_size(unit_files)"
), "../src/portable/portable.c", 128, __PRETTY_FUNCTION__); }
while (0)
;
129
130 typesafe_qsort(sorted, k, compare_metadata)({ int (*_func_)(const typeof(sorted[0])*, const typeof(sorted
[0])*) = compare_metadata; qsort_safe((sorted), (k), sizeof((
sorted)[0]), (__compar_fn_t) _func_); })
;
131
132 *ret = TAKE_PTR(sorted)({ typeof(sorted) _ptr_ = (sorted); (sorted) = ((void*)0); _ptr_
; })
;
133 return 0;
134}
135
136static int send_item(
137 int socket_fd,
138 const char *name,
139 int fd) {
140
141 union {
142 struct cmsghdr cmsghdr;
143 uint8_t buf[CMSG_SPACE(sizeof(int))((((sizeof(int)) + sizeof (size_t) - 1) & (size_t) ~(sizeof
(size_t) - 1)) + (((sizeof (struct cmsghdr)) + sizeof (size_t
) - 1) & (size_t) ~(sizeof (size_t) - 1)))
];
144 } control = {};
145 struct iovec iovec;
146 struct msghdr mh = {
147 .msg_control = &control,
148 .msg_controllen = sizeof(control),
149 .msg_iov = &iovec,
150 .msg_iovlen = 1,
151 };
152 struct cmsghdr *cmsg;
153 _cleanup_close___attribute__((cleanup(closep))) int data_fd = -1;
154
155 assert(socket_fd >= 0)do { if ((__builtin_expect(!!(!(socket_fd >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("socket_fd >= 0"), "../src/portable/portable.c"
, 155, __PRETTY_FUNCTION__); } while (0)
;
156 assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name"), "../src/portable/portable.c", 156
, __PRETTY_FUNCTION__); } while (0)
;
157 assert(fd >= 0)do { if ((__builtin_expect(!!(!(fd >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("fd >= 0"), "../src/portable/portable.c"
, 157, __PRETTY_FUNCTION__); } while (0)
;
158
159 data_fd = fd_duplicate_data_fd(fd);
160 if (data_fd < 0)
161 return data_fd;
162
163 cmsg = CMSG_FIRSTHDR(&mh)((size_t) (&mh)->msg_controllen >= sizeof (struct cmsghdr
) ? (struct cmsghdr *) (&mh)->msg_control : (struct cmsghdr
*) 0)
;
164 cmsg->cmsg_level = SOL_SOCKET1;
165 cmsg->cmsg_type = SCM_RIGHTSSCM_RIGHTS;
166 cmsg->cmsg_len = CMSG_LEN(sizeof(int))((((sizeof (struct cmsghdr)) + sizeof (size_t) - 1) & (size_t
) ~(sizeof (size_t) - 1)) + (sizeof(int)))
;
167 memcpy(CMSG_DATA(cmsg)((cmsg)->__cmsg_data), &data_fd, sizeof(int));
168
169 mh.msg_controllen = CMSG_SPACE(sizeof(int))((((sizeof(int)) + sizeof (size_t) - 1) & (size_t) ~(sizeof
(size_t) - 1)) + (((sizeof (struct cmsghdr)) + sizeof (size_t
) - 1) & (size_t) ~(sizeof (size_t) - 1)))
;
170 iovec = IOVEC_MAKE_STRING(name)(struct iovec) { .iov_base = ((char*) name), .iov_len = (strlen
(name)) }
;
171
172 if (sendmsg(socket_fd, &mh, MSG_NOSIGNALMSG_NOSIGNAL) < 0)
173 return -errno(*__errno_location ());
174
175 return 0;
176}
177
178static int recv_item(
179 int socket_fd,
180 char **ret_name,
181 int *ret_fd) {
182
183 union {
184 struct cmsghdr cmsghdr;
185 uint8_t buf[CMSG_SPACE(sizeof(int))((((sizeof(int)) + sizeof (size_t) - 1) & (size_t) ~(sizeof
(size_t) - 1)) + (((sizeof (struct cmsghdr)) + sizeof (size_t
) - 1) & (size_t) ~(sizeof (size_t) - 1)))
];
186 } control = {};
187 char buffer[PATH_MAX4096+2];
188 struct iovec iov = IOVEC_INIT(buffer, sizeof(buffer)-1){ .iov_base = (buffer), .iov_len = (sizeof(buffer)-1) };
189 struct msghdr mh = {
190 .msg_control = &control,
191 .msg_controllen = sizeof(control),
192 .msg_iov = &iov,
193 .msg_iovlen = 1,
194 };
195 struct cmsghdr *cmsg;
196 _cleanup_close___attribute__((cleanup(closep))) int found_fd = -1;
197 char *copy;
198 ssize_t n;
199
200 assert(socket_fd >= 0)do { if ((__builtin_expect(!!(!(socket_fd >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("socket_fd >= 0"), "../src/portable/portable.c"
, 200, __PRETTY_FUNCTION__); } while (0)
;
201 assert(ret_name)do { if ((__builtin_expect(!!(!(ret_name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret_name"), "../src/portable/portable.c"
, 201, __PRETTY_FUNCTION__); } while (0)
;
202 assert(ret_fd)do { if ((__builtin_expect(!!(!(ret_fd)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret_fd"), "../src/portable/portable.c",
202, __PRETTY_FUNCTION__); } while (0)
;
203
204 n = recvmsg(socket_fd, &mh, MSG_CMSG_CLOEXECMSG_CMSG_CLOEXEC);
205 if (n < 0)
206 return -errno(*__errno_location ());
207
208 CMSG_FOREACH(cmsg, &mh)for ((cmsg) = ((size_t) (&mh)->msg_controllen >= sizeof
(struct cmsghdr) ? (struct cmsghdr *) (&mh)->msg_control
: (struct cmsghdr *) 0); (cmsg); (cmsg) = __cmsg_nxthdr ((&
mh), (cmsg)))
{
209 if (cmsg->cmsg_level == SOL_SOCKET1 &&
210 cmsg->cmsg_type == SCM_RIGHTSSCM_RIGHTS) {
211
212 if (cmsg->cmsg_len == CMSG_LEN(sizeof(int))((((sizeof (struct cmsghdr)) + sizeof (size_t) - 1) & (size_t
) ~(sizeof (size_t) - 1)) + (sizeof(int)))
) {
213 assert(found_fd < 0)do { if ((__builtin_expect(!!(!(found_fd < 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("found_fd < 0"), "../src/portable/portable.c"
, 213, __PRETTY_FUNCTION__); } while (0)
;
214 found_fd = *(int*) CMSG_DATA(cmsg)((cmsg)->__cmsg_data);
215 break;
216 }
217
218 cmsg_close_all(&mh);
219 return -EIO5;
220 }
221 }
222
223 buffer[n] = 0;
224
225 copy = strdup(buffer);
226 if (!copy)
227 return -ENOMEM12;
228
229 *ret_name = copy;
230 *ret_fd = TAKE_FD(found_fd)({ int _fd_ = (found_fd); (found_fd) = -1; _fd_; });
231
232 return 0;
233}
234
235static int extract_now(
236 const char *where,
237 char **matches,
238 int socket_fd,
239 PortableMetadata **ret_os_release,
240 Hashmap **ret_unit_files) {
241
242 _cleanup_(portable_metadata_hashmap_unrefp)__attribute__((cleanup(portable_metadata_hashmap_unrefp))) Hashmap *unit_files = NULL((void*)0);
243 _cleanup_(portable_metadata_unrefp)__attribute__((cleanup(portable_metadata_unrefp))) PortableMetadata *os_release = NULL((void*)0);
244 _cleanup_(lookup_paths_free)__attribute__((cleanup(lookup_paths_free))) LookupPaths paths = {};
245 _cleanup_close___attribute__((cleanup(closep))) int os_release_fd = -1;
246 _cleanup_free___attribute__((cleanup(freep))) char *os_release_path = NULL((void*)0);
247 char **i;
248 int r;
249
250 /* Extracts the metadata from a directory tree 'where'. Extracts two kinds of information: the /etc/os-release
251 * data, and all unit files matching the specified expression. Note that this function is called in two very
252 * different but also similar contexts. When the tool gets invoked on a directory tree, we'll process it
253 * directly, and in-process, and thus can return the requested data directly, via 'ret_os_release' and
254 * 'ret_unit_files'. However, if the tool is invoked on a raw disk image — which needs to be mounted first — we
255 * are invoked in a child process with private mounts and then need to send the collected data to our
256 * parent. To handle both cases in one call this function also gets a 'socket_fd' parameter, which when >= 0 is
257 * used to send the data to the parent. */
258
259 assert(where)do { if ((__builtin_expect(!!(!(where)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("where"), "../src/portable/portable.c", 259
, __PRETTY_FUNCTION__); } while (0)
;
260
261 /* First, find /etc/os-release and send it upstream (or just save it). */
262 r = open_os_release(where, &os_release_path, &os_release_fd);
263 if (r < 0)
264 log_debug_errno(r, "Couldn't acquire os-release file, ignoring: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/portable/portable.c", 264, __func__, "Couldn't acquire os-release file, ignoring: %m"
) : -abs(_e); })
;
265 else {
266 if (socket_fd >= 0) {
267 r = send_item(socket_fd, "/etc/os-release", os_release_fd);
268 if (r < 0)
269 return log_debug_errno(r, "Failed to send os-release file: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/portable/portable.c", 269, __func__, "Failed to send os-release file: %m"
) : -abs(_e); })
;
270 }
271
272 if (ret_os_release) {
273 os_release = portable_metadata_new("/etc/os-release", os_release_fd);
274 if (!os_release)
275 return -ENOMEM12;
276
277 os_release_fd = -1;
278 os_release->source = TAKE_PTR(os_release_path)({ typeof(os_release_path) _ptr_ = (os_release_path); (os_release_path
) = ((void*)0); _ptr_; })
;
279 }
280 }
281
282 /* Then, send unit file data to the parent (or/and add it to the hashmap). For that we use our usual unit
283 * discovery logic. Note that we force looking inside of /lib/systemd/system/ for units too, as we mightbe
284 * compiled for a split-usr system but the image might be a legacy-usr one. */
285 r = lookup_paths_init(&paths, UNIT_FILE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, where);
286 if (r < 0)
287 return log_debug_errno(r, "Failed to acquire lookup paths: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/portable/portable.c", 287, __func__, "Failed to acquire lookup paths: %m"
) : -abs(_e); })
;
288
289 unit_files = hashmap_new(&string_hash_ops)internal_hashmap_new(&string_hash_ops );
290 if (!unit_files)
291 return -ENOMEM12;
292
293 STRV_FOREACH(i, paths.search_path)for ((i) = (paths.search_path); (i) && *(i); (i)++) {
294 _cleanup_free___attribute__((cleanup(freep))) char *resolved = NULL((void*)0);
295 _cleanup_closedir___attribute__((cleanup(closedirp))) DIR *d = NULL((void*)0);
296 struct dirent *de;
297
298 r = chase_symlinks_and_opendir(*i, where, 0, &resolved, &d);
299 if (r < 0) {
300 log_debug_errno(r, "Failed to open unit path '%s', ignoring: %m", *i)({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/portable/portable.c", 300, __func__, "Failed to open unit path '%s', ignoring: %m"
, *i) : -abs(_e); })
;
301 continue;
302 }
303
304 FOREACH_DIRENT(de, d, return log_debug_errno(errno, "Failed to read directory: %m"))for ((*__errno_location ()) = 0, de = readdir(d);; (*__errno_location
()) = 0, de = readdir(d)) if (!de) { if ((*__errno_location (
)) > 0) { return ({ int _level = ((7)), _e = (((*__errno_location
()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm
(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((
_realm) << 10 | (_level)), _e, "../src/portable/portable.c"
, 304, __func__, "Failed to read directory: %m") : -abs(_e); }
); } break; } else if (hidden_or_backup_file((de)->d_name)
) continue; else
{
305 _cleanup_(portable_metadata_unrefp)__attribute__((cleanup(portable_metadata_unrefp))) PortableMetadata *m = NULL((void*)0);
306 _cleanup_close___attribute__((cleanup(closep))) int fd = -1;
307
308 if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
309 continue;
310
311 if (!unit_match(de->d_name, matches))
312 continue;
313
314 /* Filter out duplicates */
315 if (hashmap_get(unit_files, de->d_name))
316 continue;
317
318 dirent_ensure_type(d, de);
319 if (!IN_SET(de->d_type, DT_LNK, DT_REG)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){DT_LNK, DT_REG})/sizeof(int)]; switch(de
->d_type) { case DT_LNK: case DT_REG: _found = 1; break; default
: break; } _found; })
)
320 continue;
321
322 fd = openat(dirfd(d), de->d_name, O_CLOEXEC02000000|O_RDONLY00);
323 if (fd < 0) {
324 log_debug_errno(errno, "Failed to open unit file '%s', ignoring: %m", de->d_name)({ int _level = ((7)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/portable/portable.c", 324, __func__
, "Failed to open unit file '%s', ignoring: %m", de->d_name
) : -abs(_e); })
;
325 continue;
326 }
327
328 if (socket_fd >= 0) {
329 r = send_item(socket_fd, de->d_name, fd);
330 if (r < 0)
331 return log_debug_errno(r, "Failed to send unit metadata to parent: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/portable/portable.c", 331, __func__, "Failed to send unit metadata to parent: %m"
) : -abs(_e); })
;
332 }
333
334 m = portable_metadata_new(de->d_name, fd);
335 if (!m)
336 return -ENOMEM12;
337 fd = -1;
338
339 m->source = strjoin(resolved, "/", de->d_name)strjoin_real((resolved), "/", de->d_name, ((void*)0));
340 if (!m->source)
341 return -ENOMEM12;
342
343 r = hashmap_put(unit_files, m->name, m);
344 if (r < 0)
345 return log_debug_errno(r, "Failed to add unit to hashmap: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/portable/portable.c", 345, __func__, "Failed to add unit to hashmap: %m"
) : -abs(_e); })
;
346 m = NULL((void*)0);
347 }
348 }
349
350 if (ret_os_release)
351 *ret_os_release = TAKE_PTR(os_release)({ typeof(os_release) _ptr_ = (os_release); (os_release) = ((
void*)0); _ptr_; })
;
352 if (ret_unit_files)
353 *ret_unit_files = TAKE_PTR(unit_files)({ typeof(unit_files) _ptr_ = (unit_files); (unit_files) = ((
void*)0); _ptr_; })
;
354
355 return 0;
356}
357
358static int portable_extract_by_path(
359 const char *path,
360 char **matches,
361 PortableMetadata **ret_os_release,
362 Hashmap **ret_unit_files,
363 sd_bus_error *error) {
364
365 _cleanup_(portable_metadata_hashmap_unrefp)__attribute__((cleanup(portable_metadata_hashmap_unrefp))) Hashmap *unit_files = NULL((void*)0);
366 _cleanup_(portable_metadata_unrefp)__attribute__((cleanup(portable_metadata_unrefp))) PortableMetadata* os_release = NULL((void*)0);
367 _cleanup_(loop_device_unrefp)__attribute__((cleanup(loop_device_unrefp))) LoopDevice *d = NULL((void*)0);
368 int r;
369
370 assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("path"), "../src/portable/portable.c", 370
, __PRETTY_FUNCTION__); } while (0)
;
371
372 r = loop_device_make_by_path(path, O_RDONLY00, &d);
373 if (r == -EISDIR21) {
374 /* We can't turn this into a loop-back block device, and this returns EISDIR? Then this is a directory
375 * tree and not a raw device. It's easy then. */
376
377 r = extract_now(path, matches, -1, &os_release, &unit_files);
378 if (r < 0)
379 return r;
380
381 } else if (r < 0)
382 return log_debug_errno(r, "Failed to set up loopback device: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/portable/portable.c", 382, __func__, "Failed to set up loopback device: %m"
) : -abs(_e); })
;
383 else {
384 _cleanup_(dissected_image_unrefp)__attribute__((cleanup(dissected_image_unrefp))) DissectedImage *m = NULL((void*)0);
385 _cleanup_(rmdir_and_freep)__attribute__((cleanup(rmdir_and_freep))) char *tmpdir = NULL((void*)0);
386 _cleanup_(close_pairp)__attribute__((cleanup(close_pairp))) int seq[2] = { -1, -1 };
387 _cleanup_(sigkill_waitp)__attribute__((cleanup(sigkill_waitp))) pid_t child = 0;
388
389 /* We now have a loopback block device, let's fork off a child in its own mount namespace, mount it
390 * there, and extract the metadata we need. The metadata is sent from the child back to us. */
391
392 BLOCK_SIGNALS(SIGCHLD)__attribute__((cleanup(block_signals_reset))) __attribute__ (
(unused)) sigset_t _saved_sigset = ({ sigset_t _t; do { if ((
__builtin_expect(!!(!(sigprocmask_many(0, &_t, 17, -1) >=
0)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("sigprocmask_many(SIG_BLOCK, &_t, 17, -1) >= 0"
), "../src/portable/portable.c", 392, __PRETTY_FUNCTION__); }
while (0); _t; })
;
393
394 r = mkdtemp_malloc("/tmp/inspect-XXXXXX", &tmpdir);
395 if (r < 0)
396 return log_debug_errno(r, "Failed to create temporary directory: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/portable/portable.c", 396, __func__, "Failed to create temporary directory: %m"
) : -abs(_e); })
;
397
398 r = dissect_image(d->fd, NULL((void*)0), 0, DISSECT_IMAGE_READ_ONLY|DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP, &m);
399 if (r == -ENOPKG65)
400 sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS"org.freedesktop.DBus.Error.InvalidArgs", "Couldn't identify a suitable partition table or file system in '%s'.", path);
401 else if (r == -EADDRNOTAVAIL99)
402 sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS"org.freedesktop.DBus.Error.InvalidArgs", "No root partition for specified root hash found in '%s'.", path);
403 else if (r == -ENOTUNIQ76)
404 sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS"org.freedesktop.DBus.Error.InvalidArgs", "Multiple suitable root partitions found in image '%s'.", path);
405 else if (r == -ENXIO6)
406 sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS"org.freedesktop.DBus.Error.InvalidArgs", "No suitable root partition found in image '%s'.", path);
407 else if (r == -EPROTONOSUPPORT93)
408 sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS"org.freedesktop.DBus.Error.InvalidArgs", "Device '%s' is loopback block device with partition scanning turned off, please turn it on.", path);
409 if (r < 0)
410 return r;
411
412 if (socketpair(AF_UNIX1, SOCK_SEQPACKETSOCK_SEQPACKET|SOCK_CLOEXECSOCK_CLOEXEC, 0, seq) < 0)
413 return log_debug_errno(errno, "Failed to allocated SOCK_SEQPACKET socket: %m")({ int _level = ((7)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/portable/portable.c", 413, __func__
, "Failed to allocated SOCK_SEQPACKET socket: %m") : -abs(_e)
; })
;
414
415 r = safe_fork("(sd-dissect)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE|FORK_LOG, &child);
416 if (r < 0)
417 return r;
418 if (r == 0) {
419 seq[0] = safe_close(seq[0]);
420
421 r = dissected_image_mount(m, tmpdir, UID_INVALID((uid_t) -1), DISSECT_IMAGE_READ_ONLY|DISSECT_IMAGE_VALIDATE_OS);
422 if (r < 0) {
423 log_debug_errno(r, "Failed to mount dissected image: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/portable/portable.c", 423, __func__, "Failed to mount dissected image: %m"
) : -abs(_e); })
;
424 goto child_finish;
425 }
426
427 r = extract_now(tmpdir, matches, seq[1], NULL((void*)0), NULL((void*)0));
428
429 child_finish:
430 _exit(r < 0 ? EXIT_FAILURE1 : EXIT_SUCCESS0);
431 }
432
433 seq[1] = safe_close(seq[1]);
434
435 unit_files = hashmap_new(&string_hash_ops)internal_hashmap_new(&string_hash_ops );
436 if (!unit_files)
437 return -ENOMEM12;
438
439 for (;;) {
440 _cleanup_(portable_metadata_unrefp)__attribute__((cleanup(portable_metadata_unrefp))) PortableMetadata *add = NULL((void*)0);
441 _cleanup_free___attribute__((cleanup(freep))) char *name = NULL((void*)0);
442 _cleanup_close___attribute__((cleanup(closep))) int fd = -1;
443
444 r = recv_item(seq[0], &name, &fd);
445 if (r < 0)
446 return log_debug_errno(r, "Failed to receive item: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/portable/portable.c", 446, __func__, "Failed to receive item: %m"
) : -abs(_e); })
;
447
448 /* We can't really distuingish a zero-length datagram without any fds from EOF (both are signalled the
449 * same way by recvmsg()). Hence, accept either as end notification. */
450 if (isempty(name) && fd < 0)
451 break;
452
453 if (isempty(name) || fd < 0) {
454 log_debug("Invalid item sent from child.")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/portable/portable.c", 454, __func__, "Invalid item sent from child."
) : -abs(_e); })
;
455 return -EINVAL22;
456 }
457
458 add = portable_metadata_new(name, fd);
459 if (!add)
460 return -ENOMEM12;
461 fd = -1;
462
463 /* Note that we do not initialize 'add->source' here, as the source path is not usable here as
464 * it refers to a path only valid in the short-living namespaced child process we forked
465 * here. */
466
467 if (PORTABLE_METADATA_IS_UNIT(add)(!({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){0, '/'})/sizeof(int)]; switch((add)->
name[0]) { case 0: case '/': _found = 1; break; default: break
; } _found; }))
) {
468 r = hashmap_put(unit_files, add->name, add);
469 if (r < 0)
470 return log_debug_errno(r, "Failed to add item to unit file list: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/portable/portable.c", 470, __func__, "Failed to add item to unit file list: %m"
) : -abs(_e); })
;
471
472 add = NULL((void*)0);
473
474 } else if (PORTABLE_METADATA_IS_OS_RELEASE(add)((strcmp(((add)->name),("/etc/os-release")) == 0))) {
475
476 assert(!os_release)do { if ((__builtin_expect(!!(!(!os_release)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("!os_release"), "../src/portable/portable.c"
, 476, __PRETTY_FUNCTION__); } while (0)
;
477 os_release = TAKE_PTR(add)({ typeof(add) _ptr_ = (add); (add) = ((void*)0); _ptr_; });
478 } else
479 assert_not_reached("Unexpected metadata item from child.")do { log_assert_failed_unreachable_realm(LOG_REALM_SYSTEMD, (
"Unexpected metadata item from child."), "../src/portable/portable.c"
, 479, __PRETTY_FUNCTION__); } while (0)
;
480 }
481
482 r = wait_for_terminate_and_check("(sd-dissect)", child, 0);
483 if (r < 0)
484 return r;
485 child = 0;
486 }
487
488 if (!os_release)
489 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS"org.freedesktop.DBus.Error.InvalidArgs", "Image '%s' lacks os-release data, refusing.", path);
490
491 if (hashmap_isempty(unit_files))
492 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS"org.freedesktop.DBus.Error.InvalidArgs", "Couldn't find any matching unit files in image '%s', refusing.", path);
493
494 if (ret_unit_files)
495 *ret_unit_files = TAKE_PTR(unit_files)({ typeof(unit_files) _ptr_ = (unit_files); (unit_files) = ((
void*)0); _ptr_; })
;
496
497 if (ret_os_release)
498 *ret_os_release = TAKE_PTR(os_release)({ typeof(os_release) _ptr_ = (os_release); (os_release) = ((
void*)0); _ptr_; })
;
499
500 return 0;
501}
502
503int portable_extract(
504 const char *name_or_path,
505 char **matches,
506 PortableMetadata **ret_os_release,
507 Hashmap **ret_unit_files,
508 sd_bus_error *error) {
509
510 _cleanup_(image_unrefp)__attribute__((cleanup(image_unrefp))) Image *image = NULL((void*)0);
511 int r;
512
513 assert(name_or_path)do { if ((__builtin_expect(!!(!(name_or_path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name_or_path"), "../src/portable/portable.c"
, 513, __PRETTY_FUNCTION__); } while (0)
;
514
515 r = image_find_harder(IMAGE_PORTABLE, name_or_path, &image);
516 if (r < 0)
517 return r;
518
519 return portable_extract_by_path(image->path, matches, ret_os_release, ret_unit_files, error);
520}
521
522static int unit_file_is_active(
523 sd_bus *bus,
524 const char *name,
525 sd_bus_error *error) {
526
527 static const char *const active_states[] = {
528 "activating",
529 "active",
530 "reloading",
531 "deactivating",
532 NULL((void*)0),
533 };
534 int r;
535
536 if (!bus)
537 return false0;
538
539 /* If we are looking at a plain or instance things are easy, we can just query the state */
540 if (unit_name_is_valid(name, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) {
541 _cleanup_free___attribute__((cleanup(freep))) char *path = NULL((void*)0), *buf = NULL((void*)0);
542
543 path = unit_dbus_path_from_name(name);
544 if (!path)
545 return -ENOMEM12;
546
547 r = sd_bus_get_property_string(
548 bus,
549 "org.freedesktop.systemd1",
550 path,
551 "org.freedesktop.systemd1.Unit",
552 "ActiveState",
553 error,
554 &buf);
555 if (r < 0)
556 return log_debug_errno(r, "Failed to retrieve unit state: %s", bus_error_message(error, r))({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/portable/portable.c", 556, __func__, "Failed to retrieve unit state: %s"
, bus_error_message(error, r)) : -abs(_e); })
;
557
558 return strv_contains((char**) active_states, buf)(!!strv_find(((char**) active_states), (buf)));
559 }
560
561 /* Otherwise we need to enumerate. But let's build the most restricted query we can */
562 if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE)) {
563 _cleanup_(sd_bus_message_unrefp)__attribute__((cleanup(sd_bus_message_unrefp))) sd_bus_message *m = NULL((void*)0), *reply = NULL((void*)0);
564 const char *at, *prefix, *joined;
565
566 r = sd_bus_message_new_method_call(
567 bus,
568 &m,
569 "org.freedesktop.systemd1",
570 "/org/freedesktop/systemd1",
571 "org.freedesktop.systemd1.Manager",
572 "ListUnitsByPatterns");
573 if (r < 0)
574 return r;
575
576 r = sd_bus_message_append_strv(m, (char**) active_states);
577 if (r < 0)
578 return r;
579
580 at = strchr(name, '@');
581 assert(at)do { if ((__builtin_expect(!!(!(at)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("at"), "../src/portable/portable.c", 581
, __PRETTY_FUNCTION__); } while (0)
;
582
583 prefix = strndupa(name, at + 1 - name)(__extension__ ({ const char *__old = (name); size_t __len = strnlen
(__old, (at + 1 - name)); char *__new = (char *) __builtin_alloca
(__len + 1); __new[__len] = '\0'; (char *) memcpy (__new, __old
, __len); }))
;
584 joined = strjoina(prefix, "*", at + 1)({ const char *_appendees_[] = { prefix, "*", at + 1 }; char *
_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ <
__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
;
585
586 r = sd_bus_message_append_strv(m, STRV_MAKE(joined)((char**) ((const char*[]) { joined, ((void*)0) })));
587 if (r < 0)
588 return r;
589
590 r = sd_bus_call(bus, m, 0, error, &reply);
591 if (r < 0)
592 return log_debug_errno(r, "Failed to list units: %s", bus_error_message(error, r))({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/portable/portable.c", 592, __func__, "Failed to list units: %s"
, bus_error_message(error, r)) : -abs(_e); })
;
593
594 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)");
595 if (r < 0)
596 return r;
597
598 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_STRUCT, "ssssssouso");
599 if (r < 0)
600 return r;
601
602 return r > 0;
603 }
604
605 return -EINVAL22;
606}
607
608static int portable_changes_add(
609 PortableChange **changes,
610 size_t *n_changes,
611 PortableChangeType type,
612 const char *path,
613 const char *source) {
614
615 _cleanup_free___attribute__((cleanup(freep))) char *p = NULL((void*)0), *s = NULL((void*)0);
616 PortableChange *c;
617
618 assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("path"), "../src/portable/portable.c", 618
, __PRETTY_FUNCTION__); } while (0)
;
619 assert(!changes == !n_changes)do { if ((__builtin_expect(!!(!(!changes == !n_changes)),0)))
log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!changes == !n_changes"
), "../src/portable/portable.c", 619, __PRETTY_FUNCTION__); }
while (0)
;
620
621 if (!changes)
622 return 0;
623
624 c = reallocarray(*changes, *n_changes + 1, sizeof(PortableChange));
625 if (!c)
626 return -ENOMEM12;
627 *changes = c;
628
629 p = strdup(path);
630 if (!p)
631 return -ENOMEM12;
632
633 path_simplify(p, false0);
634
635 if (source) {
636 s = strdup(source);
637 if (!s)
638 return -ENOMEM12;
639
640 path_simplify(s, false0);
641 }
642
643 c[(*n_changes)++] = (PortableChange) {
644 .type = type,
645 .path = TAKE_PTR(p)({ typeof(p) _ptr_ = (p); (p) = ((void*)0); _ptr_; }),
646 .source = TAKE_PTR(s)({ typeof(s) _ptr_ = (s); (s) = ((void*)0); _ptr_; }),
647 };
648
649 return 0;
650}
651
652static int portable_changes_add_with_prefix(
653 PortableChange **changes,
654 size_t *n_changes,
655 PortableChangeType type,
656 const char *prefix,
657 const char *path,
658 const char *source) {
659
660 assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("path"), "../src/portable/portable.c", 660
, __PRETTY_FUNCTION__); } while (0)
;
661 assert(!changes == !n_changes)do { if ((__builtin_expect(!!(!(!changes == !n_changes)),0)))
log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!changes == !n_changes"
), "../src/portable/portable.c", 661, __PRETTY_FUNCTION__); }
while (0)
;
662
663 if (!changes)
664 return 0;
665
666 if (prefix) {
667 path = strjoina(prefix, "/", path)({ const char *_appendees_[] = { prefix, "/", path }; char *_d_
, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__
(__builtin_choose_expr( !__builtin_types_compatible_p(typeof
(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
;
668
669 if (source)
670 source = strjoina(prefix, "/", source)({ const char *_appendees_[] = { prefix, "/", source }; char *
_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ <
__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
;
671 }
672
673 return portable_changes_add(changes, n_changes, type, path, source);
674}
675
676void portable_changes_free(PortableChange *changes, size_t n_changes) {
677 size_t i;
678
679 assert(changes || n_changes == 0)do { if ((__builtin_expect(!!(!(changes || n_changes == 0)),0
))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("changes || n_changes == 0"
), "../src/portable/portable.c", 679, __PRETTY_FUNCTION__); }
while (0)
;
680
681 for (i = 0; i < n_changes; i++) {
682 free(changes[i].path);
683 free(changes[i].source);
684 }
685
686 free(changes);
687}
688
689static int install_chroot_dropin(
690 const char *image_path,
691 ImageType type,
692 const PortableMetadata *m,
693 const char *dropin_dir,
694 char **ret_dropin,
695 PortableChange **changes,
696 size_t *n_changes) {
697
698 _cleanup_free___attribute__((cleanup(freep))) char *text = NULL((void*)0), *dropin = NULL((void*)0);
699 int r;
700
701 assert(image_path)do { if ((__builtin_expect(!!(!(image_path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("image_path"), "../src/portable/portable.c"
, 701, __PRETTY_FUNCTION__); } while (0)
;
702 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/portable/portable.c", 702,
__PRETTY_FUNCTION__); } while (0)
;
703 assert(dropin_dir)do { if ((__builtin_expect(!!(!(dropin_dir)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("dropin_dir"), "../src/portable/portable.c"
, 703, __PRETTY_FUNCTION__); } while (0)
;
704
705 dropin = strjoin(dropin_dir, "/20-portable.conf")strjoin_real((dropin_dir), "/20-portable.conf", ((void*)0));
706 if (!dropin)
707 return -ENOMEM12;
708
709 text = strjoin(PORTABLE_DROPIN_MARKER_BEGIN, image_path, PORTABLE_DROPIN_MARKER_END "\n")strjoin_real(("# Drop-in created for image '"), image_path, "', do not edit."
"\n", ((void*)0))
;
710 if (!text)
711 return -ENOMEM12;
712
713 if (endswith(m->name, ".service"))
714 if (!strextend(&text,strextend_with_separator(&text, ((void*)0), "\n" "[Service]\n"
, ({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){IMAGE_DIRECTORY, IMAGE_SUBVOLUME})/sizeof
(int)]; switch(type) { case IMAGE_DIRECTORY: case IMAGE_SUBVOLUME
: _found = 1; break; default: break; } _found; }) ? "RootDirectory="
: "RootImage=", image_path, "\n" "Environment=PORTABLE=", basename
(image_path), "\n" "LogExtraFields=PORTABLE=", basename(image_path
), "\n", ((void*)0))
715 "\n"strextend_with_separator(&text, ((void*)0), "\n" "[Service]\n"
, ({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){IMAGE_DIRECTORY, IMAGE_SUBVOLUME})/sizeof
(int)]; switch(type) { case IMAGE_DIRECTORY: case IMAGE_SUBVOLUME
: _found = 1; break; default: break; } _found; }) ? "RootDirectory="
: "RootImage=", image_path, "\n" "Environment=PORTABLE=", basename
(image_path), "\n" "LogExtraFields=PORTABLE=", basename(image_path
), "\n", ((void*)0))
716 "[Service]\n",strextend_with_separator(&text, ((void*)0), "\n" "[Service]\n"
, ({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){IMAGE_DIRECTORY, IMAGE_SUBVOLUME})/sizeof
(int)]; switch(type) { case IMAGE_DIRECTORY: case IMAGE_SUBVOLUME
: _found = 1; break; default: break; } _found; }) ? "RootDirectory="
: "RootImage=", image_path, "\n" "Environment=PORTABLE=", basename
(image_path), "\n" "LogExtraFields=PORTABLE=", basename(image_path
), "\n", ((void*)0))
717 IN_SET(type, IMAGE_DIRECTORY, IMAGE_SUBVOLUME) ? "RootDirectory=" : "RootImage=", image_path, "\n"strextend_with_separator(&text, ((void*)0), "\n" "[Service]\n"
, ({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){IMAGE_DIRECTORY, IMAGE_SUBVOLUME})/sizeof
(int)]; switch(type) { case IMAGE_DIRECTORY: case IMAGE_SUBVOLUME
: _found = 1; break; default: break; } _found; }) ? "RootDirectory="
: "RootImage=", image_path, "\n" "Environment=PORTABLE=", basename
(image_path), "\n" "LogExtraFields=PORTABLE=", basename(image_path
), "\n", ((void*)0))
718 "Environment=PORTABLE=", basename(image_path), "\n"strextend_with_separator(&text, ((void*)0), "\n" "[Service]\n"
, ({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){IMAGE_DIRECTORY, IMAGE_SUBVOLUME})/sizeof
(int)]; switch(type) { case IMAGE_DIRECTORY: case IMAGE_SUBVOLUME
: _found = 1; break; default: break; } _found; }) ? "RootDirectory="
: "RootImage=", image_path, "\n" "Environment=PORTABLE=", basename
(image_path), "\n" "LogExtraFields=PORTABLE=", basename(image_path
), "\n", ((void*)0))
719 "LogExtraFields=PORTABLE=", basename(image_path), "\n",strextend_with_separator(&text, ((void*)0), "\n" "[Service]\n"
, ({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){IMAGE_DIRECTORY, IMAGE_SUBVOLUME})/sizeof
(int)]; switch(type) { case IMAGE_DIRECTORY: case IMAGE_SUBVOLUME
: _found = 1; break; default: break; } _found; }) ? "RootDirectory="
: "RootImage=", image_path, "\n" "Environment=PORTABLE=", basename
(image_path), "\n" "LogExtraFields=PORTABLE=", basename(image_path
), "\n", ((void*)0))
720 NULL)strextend_with_separator(&text, ((void*)0), "\n" "[Service]\n"
, ({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){IMAGE_DIRECTORY, IMAGE_SUBVOLUME})/sizeof
(int)]; switch(type) { case IMAGE_DIRECTORY: case IMAGE_SUBVOLUME
: _found = 1; break; default: break; } _found; }) ? "RootDirectory="
: "RootImage=", image_path, "\n" "Environment=PORTABLE=", basename
(image_path), "\n" "LogExtraFields=PORTABLE=", basename(image_path
), "\n", ((void*)0))
)
721
722 return -ENOMEM12;
723
724 r = write_string_file(dropin, text, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
725 if (r < 0)
726 return log_debug_errno(r, "Failed to write '%s': %m", dropin)({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/portable/portable.c", 726, __func__, "Failed to write '%s': %m"
, dropin) : -abs(_e); })
;
727
728 (void) portable_changes_add(changes, n_changes, PORTABLE_WRITE, dropin, NULL((void*)0));
729
730 if (ret_dropin)
731 *ret_dropin = TAKE_PTR(dropin)({ typeof(dropin) _ptr_ = (dropin); (dropin) = ((void*)0); _ptr_
; })
;
732
733 return 0;
734}
735
736static int find_profile(const char *name, const char *unit, char **ret) {
737 const char *p, *dot;
738
739 assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name"), "../src/portable/portable.c", 739
, __PRETTY_FUNCTION__); } while (0)
;
740 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/portable/portable.c", 740
, __PRETTY_FUNCTION__); } while (0)
;
741
742 assert_se(dot = strrchr(unit, '.'))do { if ((__builtin_expect(!!(!(dot = strrchr(unit, '.'))),0)
)) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("dot = strrchr(unit, '.')"
), "../src/portable/portable.c", 742, __PRETTY_FUNCTION__); }
while (0)
;
743
744 NULSTR_FOREACH(p, profile_dirs)for ((p) = (profile_dirs); (p) && *(p); (p) = strchr(
(p), 0)+1)
{
745 _cleanup_free___attribute__((cleanup(freep))) char *joined;
746
747 joined = strjoin(p, "/", name, "/", dot + 1, ".conf")strjoin_real((p), "/", name, "/", dot + 1, ".conf", ((void*)0
))
;
748 if (!joined)
749 return -ENOMEM12;
750
751 if (laccess(joined, F_OK)faccessat(-100, (joined), (0), 0x100) >= 0) {
752 *ret = TAKE_PTR(joined)({ typeof(joined) _ptr_ = (joined); (joined) = ((void*)0); _ptr_
; })
;
753 return 0;
754 }
755
756 if (errno(*__errno_location ()) != ENOENT2)
757 return -errno(*__errno_location ());
758 }
759
760 return -ENOENT2;
761}
762
763static int install_profile_dropin(
764 const char *image_path,
765 const PortableMetadata *m,
766 const char *dropin_dir,
767 const char *profile,
768 PortableFlags flags,
769 char **ret_dropin,
770 PortableChange **changes,
771 size_t *n_changes) {
772
773 _cleanup_free___attribute__((cleanup(freep))) char *dropin = NULL((void*)0), *from = NULL((void*)0);
774 int r;
775
776 assert(image_path)do { if ((__builtin_expect(!!(!(image_path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("image_path"), "../src/portable/portable.c"
, 776, __PRETTY_FUNCTION__); } while (0)
;
777 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/portable/portable.c", 777,
__PRETTY_FUNCTION__); } while (0)
;
778 assert(dropin_dir)do { if ((__builtin_expect(!!(!(dropin_dir)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("dropin_dir"), "../src/portable/portable.c"
, 778, __PRETTY_FUNCTION__); } while (0)
;
779
780 if (!profile)
781 return 0;
782
783 r = find_profile(profile, m->name, &from);
784 if (r < 0) {
785 if (r != ENOENT2)
786 return log_debug_errno(errno, "Profile '%s' is not accessible: %m", profile)({ int _level = ((7)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/portable/portable.c", 786, __func__
, "Profile '%s' is not accessible: %m", profile) : -abs(_e); }
)
;
787
788 log_debug_errno(errno, "Skipping link to profile '%s', as it does not exist: %m", profile)({ int _level = ((7)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/portable/portable.c", 788, __func__
, "Skipping link to profile '%s', as it does not exist: %m", profile
) : -abs(_e); })
;
789 return 0;
790 }
791
792 dropin = strjoin(dropin_dir, "/10-profile.conf")strjoin_real((dropin_dir), "/10-profile.conf", ((void*)0));
793 if (!dropin)
794 return -ENOMEM12;
795
796 if (flags & PORTABLE_PREFER_COPY) {
797
798 r = copy_file_atomic(from, dropin, 0644, 0, COPY_REFLINK);
799 if (r < 0)
800 return log_debug_errno(r, "Failed to copy %s %s %s: %m", from, special_glyph(ARROW), dropin)({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/portable/portable.c", 800, __func__, "Failed to copy %s %s %s: %m"
, from, special_glyph(ARROW), dropin) : -abs(_e); })
;
801
802 (void) portable_changes_add(changes, n_changes, PORTABLE_COPY, dropin, from);
803
804 } else {
805
806 if (symlink(from, dropin) < 0)
807 return log_debug_errno(errno, "Failed to link %s %s %s: %m", from, special_glyph(ARROW), dropin)({ int _level = ((7)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/portable/portable.c", 807, __func__
, "Failed to link %s %s %s: %m", from, special_glyph(ARROW), dropin
) : -abs(_e); })
;
808
809 (void) portable_changes_add(changes, n_changes, PORTABLE_SYMLINK, dropin, from);
810 }
811
812 if (ret_dropin)
813 *ret_dropin = TAKE_PTR(dropin)({ typeof(dropin) _ptr_ = (dropin); (dropin) = ((void*)0); _ptr_
; })
;
814
815 return 0;
816}
817
818static const char *config_path(const LookupPaths *paths, PortableFlags flags) {
819 const char *where;
820
821 assert(paths)do { if ((__builtin_expect(!!(!(paths)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("paths"), "../src/portable/portable.c", 821
, __PRETTY_FUNCTION__); } while (0)
;
822
823 if (flags & PORTABLE_RUNTIME)
824 where = paths->runtime_config;
825 else
826 where = paths->persistent_config;
827
828 assert(where)do { if ((__builtin_expect(!!(!(where)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("where"), "../src/portable/portable.c", 828
, __PRETTY_FUNCTION__); } while (0)
;
829 return where;
830}
831
832static int attach_unit_file(
833 const LookupPaths *paths,
834 const char *image_path,
835 ImageType type,
836 const PortableMetadata *m,
837 const char *profile,
838 PortableFlags flags,
839 PortableChange **changes,
840 size_t *n_changes) {
841
842 _cleanup_(unlink_and_freep)__attribute__((cleanup(unlink_and_freep))) char *chroot_dropin = NULL((void*)0), *profile_dropin = NULL((void*)0);
843 _cleanup_(rmdir_and_freep)__attribute__((cleanup(rmdir_and_freep))) char *dropin_dir = NULL((void*)0);
844 const char *where, *path;
845 int r;
846
847 assert(paths)do { if ((__builtin_expect(!!(!(paths)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("paths"), "../src/portable/portable.c", 847
, __PRETTY_FUNCTION__); } while (0)
;
848 assert(image_path)do { if ((__builtin_expect(!!(!(image_path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("image_path"), "../src/portable/portable.c"
, 848, __PRETTY_FUNCTION__); } while (0)
;
849 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/portable/portable.c", 849,
__PRETTY_FUNCTION__); } while (0)
;
850 assert(PORTABLE_METADATA_IS_UNIT(m))do { if ((__builtin_expect(!!(!((!({ _Bool _found = 0; static
__attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){0, '/'})/sizeof(int)]; switch((m)->name
[0]) { case 0: case '/': _found = 1; break; default: break; }
_found; })))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD
, ("PORTABLE_METADATA_IS_UNIT(m)"), "../src/portable/portable.c"
, 850, __PRETTY_FUNCTION__); } while (0)
;
851
852 where = config_path(paths, flags);
853 path = strjoina(where, "/", m->name)({ const char *_appendees_[] = { where, "/", m->name }; char
*_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ <
__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
;
854
855 dropin_dir = strjoin(path, ".d")strjoin_real((path), ".d", ((void*)0));
856 if (!dropin_dir)
857 return -ENOMEM12;
858
859 (void) mkdir_p(dropin_dir, 0755);
860 (void) portable_changes_add(changes, n_changes, PORTABLE_MKDIR, dropin_dir, NULL((void*)0));
861
862 /* We install the drop-ins first, and the actual unit file last to achieve somewhat atomic behaviour if PID 1
863 * is reloaded while we are creating things here: as long as only the drop-ins exist the unit doesn't exist at
864 * all for PID 1. */
865
866 r = install_chroot_dropin(image_path, type, m, dropin_dir, &chroot_dropin, changes, n_changes);
867 if (r < 0)
868 return r;
869
870 r = install_profile_dropin(image_path, m, dropin_dir, profile, flags, &profile_dropin, changes, n_changes);
871 if (r < 0)
872 return r;
873
874 if ((flags & PORTABLE_PREFER_SYMLINK) && m->source) {
875
876 if (symlink(m->source, path) < 0)
877 return log_debug_errno(errno, "Failed to symlink unit file '%s': %m", path)({ int _level = ((7)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/portable/portable.c", 877, __func__
, "Failed to symlink unit file '%s': %m", path) : -abs(_e); }
)
;
878
879 (void) portable_changes_add(changes, n_changes, PORTABLE_SYMLINK, path, m->source);
880
881 } else {
882 _cleanup_(unlink_and_freep)__attribute__((cleanup(unlink_and_freep))) char *tmp = NULL((void*)0);
883 _cleanup_close___attribute__((cleanup(closep))) int fd = -1;
884
885 fd = open_tmpfile_linkable(where, O_WRONLY01|O_CLOEXEC02000000, &tmp);
886 if (fd < 0)
887 return log_debug_errno(fd, "Failed to create unit file '%s': %m", path)({ int _level = ((7)), _e = ((fd)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/portable/portable.c", 887, __func__, "Failed to create unit file '%s': %m"
, path) : -abs(_e); })
;
888
889 r = copy_bytes(m->fd, fd, UINT64_MAX(18446744073709551615UL), COPY_REFLINK);
890 if (r < 0)
891 return log_debug_errno(r, "Failed to copy unit file '%s': %m", path)({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/portable/portable.c", 891, __func__, "Failed to copy unit file '%s': %m"
, path) : -abs(_e); })
;
892
893 if (fchmod(fd, 0644) < 0)
894 return log_debug_errno(errno, "Failed to change unit file access mode for '%s': %m", path)({ int _level = ((7)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/portable/portable.c", 894, __func__
, "Failed to change unit file access mode for '%s': %m", path
) : -abs(_e); })
;
895
896 r = link_tmpfile(fd, tmp, path);
897 if (r < 0)
898 return log_debug_errno(r, "Failed to install unit file '%s': %m", path)({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/portable/portable.c", 898, __func__, "Failed to install unit file '%s': %m"
, path) : -abs(_e); })
;
899
900 tmp = mfree(tmp);
901
902 (void) portable_changes_add(changes, n_changes, PORTABLE_COPY, path, m->source);
903 }
904
905 /* All is established now, now let's disable any rollbacks */
906 chroot_dropin = mfree(chroot_dropin);
907 profile_dropin = mfree(profile_dropin);
908 dropin_dir = mfree(dropin_dir);
909
910 return 0;
911}
912
913static int image_symlink(
914 const char *image_path,
915 PortableFlags flags,
916 char **ret) {
917
918 const char *fn, *where;
919 char *joined = NULL((void*)0);
920
921 assert(image_path)do { if ((__builtin_expect(!!(!(image_path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("image_path"), "../src/portable/portable.c"
, 921, __PRETTY_FUNCTION__); } while (0)
;
922 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/portable/portable.c", 922
, __PRETTY_FUNCTION__); } while (0)
;
923
924 fn = last_path_component(image_path);
925
926 if (flags & PORTABLE_RUNTIME)
927 where = "/run/portables/";
928 else
929 where = "/etc/portables/";
930
931 joined = strjoin(where, fn)strjoin_real((where), fn, ((void*)0));
932 if (!joined)
933 return -ENOMEM12;
934
935 *ret = joined;
936 return 0;
937}
938
939static int install_image_symlink(
940 const char *image_path,
941 PortableFlags flags,
942 PortableChange **changes,
943 size_t *n_changes) {
944
945 _cleanup_free___attribute__((cleanup(freep))) char *sl = NULL((void*)0);
946 int r;
947
948 assert(image_path)do { if ((__builtin_expect(!!(!(image_path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("image_path"), "../src/portable/portable.c"
, 948, __PRETTY_FUNCTION__); } while (0)
;
949
950 /* If the image is outside of the image search also link it into it, so that it can be found with short image
951 * names and is listed among the images. */
952
953 if (image_in_search_path(IMAGE_PORTABLE, image_path))
954 return 0;
955
956 r = image_symlink(image_path, flags, &sl);
957 if (r < 0)
958 return log_debug_errno(r, "Failed to generate image symlink path: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/portable/portable.c", 958, __func__, "Failed to generate image symlink path: %m"
) : -abs(_e); })
;
959
960 (void) mkdir_parents(sl, 0755);
961
962 if (symlink(image_path, sl) < 0)
963 return log_debug_errno(errno, "Failed to link %s %s %s: %m", image_path, special_glyph(ARROW), sl)({ int _level = ((7)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/portable/portable.c", 963, __func__
, "Failed to link %s %s %s: %m", image_path, special_glyph(ARROW
), sl) : -abs(_e); })
;
964
965 (void) portable_changes_add(changes, n_changes, PORTABLE_SYMLINK, sl, image_path);
966 return 0;
967}
968
969int portable_attach(
970 sd_bus *bus,
971 const char *name_or_path,
972 char **matches,
973 const char *profile,
974 PortableFlags flags,
975 PortableChange **changes,
976 size_t *n_changes,
977 sd_bus_error *error) {
978
979 _cleanup_(portable_metadata_hashmap_unrefp)__attribute__((cleanup(portable_metadata_hashmap_unrefp))) Hashmap *unit_files = NULL((void*)0);
980 _cleanup_(lookup_paths_free)__attribute__((cleanup(lookup_paths_free))) LookupPaths paths = {};
981 _cleanup_(image_unrefp)__attribute__((cleanup(image_unrefp))) Image *image = NULL((void*)0);
982 PortableMetadata *item;
983 Iterator iterator;
984 int r;
985
986 assert(name_or_path)do { if ((__builtin_expect(!!(!(name_or_path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name_or_path"), "../src/portable/portable.c"
, 986, __PRETTY_FUNCTION__); } while (0)
;
987
988 r = image_find_harder(IMAGE_PORTABLE, name_or_path, &image);
989 if (r < 0)
990 return r;
991
992 r = portable_extract_by_path(image->path, matches, NULL((void*)0), &unit_files, error);
993 if (r < 0)
994 return r;
995
996 r = lookup_paths_init(&paths, UNIT_FILE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL((void*)0));
997 if (r < 0)
998 return r;
999
1000 HASHMAP_FOREACH(item, unit_files, iterator)for ((iterator) = ((Iterator) { .idx = ((2147483647 *2U +1U) -
1), .next_key = ((void*)0) }); hashmap_iterate((unit_files),
&(iterator), (void**)&(item), ((void*)0)); )
{
1001 r = unit_file_exists(UNIT_FILE_SYSTEM, &paths, item->name);
1002 if (r < 0)
1003 return sd_bus_error_set_errnof(error, r, "Failed to determine whether unit '%s' exists on the host: %m", item->name);
1004 if (r > 0)
1005 return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS"org.freedesktop.systemd1.UnitExists", "Unit file '%s' exists on the host already, refusing.", item->name);
1006
1007 r = unit_file_is_active(bus, item->name, error);
1008 if (r < 0)
1009 return r;
1010 if (r > 0)
1011 return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS"org.freedesktop.systemd1.UnitExists", "Unit file '%s' is active already, refusing.", item->name);
1012 }
1013
1014 HASHMAP_FOREACH(item, unit_files, iterator)for ((iterator) = ((Iterator) { .idx = ((2147483647 *2U +1U) -
1), .next_key = ((void*)0) }); hashmap_iterate((unit_files),
&(iterator), (void**)&(item), ((void*)0)); )
{
1015 r = attach_unit_file(&paths, image->path, image->type, item, profile, flags, changes, n_changes);
1016 if (r < 0)
1017 return r;
1018 }
1019
1020 /* We don't care too much for the image symlink, it's just a convenience thing, it's not necessary for proper
1021 * operation otherwise. */
1022 (void) install_image_symlink(image->path, flags, changes, n_changes);
1023
1024 return 0;
1025}
1026
1027static bool_Bool marker_matches_image(const char *marker, const char *name_or_path) {
1028 const char *a;
1029
1030 assert(marker)do { if ((__builtin_expect(!!(!(marker)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("marker"), "../src/portable/portable.c",
1030, __PRETTY_FUNCTION__); } while (0)
;
1031 assert(name_or_path)do { if ((__builtin_expect(!!(!(name_or_path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name_or_path"), "../src/portable/portable.c"
, 1031, __PRETTY_FUNCTION__); } while (0)
;
1032
1033 a = last_path_component(marker);
1034
1035 if (image_name_is_valid(name_or_path)) {
1036 const char *e;
1037
1038 /* We shall match against an image name. In that case let's compare the last component, and optionally
1039 * allow either a suffix of ".raw" or a series of "/". */
1040
1041 e = startswith(a, name_or_path);
1042 if (!e)
1043 return false0;
1044
1045 return
1046 e[strspn(e, "/")] == 0 ||
1047 streq(e, ".raw")(strcmp((e),(".raw")) == 0);
1048 } else {
1049 const char *b;
1050 size_t l;
1051
1052 /* We shall match against a path. Let's ignore any prefix here though, as often there are many ways to
1053 * reach the same file. However, in this mode, let's validate any file suffix. */
1054
1055 l = strcspn(a, "/");
1056 b = last_path_component(name_or_path);
1057
1058 if (strcspn(b, "/") != l)
1059 return false0;
1060
1061 return memcmp(a, b, l) == 0;
1062 }
1063}
1064
1065static int test_chroot_dropin(
1066 DIR *d,
1067 const char *where,
1068 const char *fname,
1069 const char *name_or_path,
1070 char **ret_marker) {
1071
1072 _cleanup_free___attribute__((cleanup(freep))) char *line = NULL((void*)0), *marker = NULL((void*)0);
1073 _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0);
1074 _cleanup_close___attribute__((cleanup(closep))) int fd = -1;
1075 const char *p, *e, *k;
1076 int r;
1077
1078 assert(d)do { if ((__builtin_expect(!!(!(d)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("d"), "../src/portable/portable.c", 1078
, __PRETTY_FUNCTION__); } while (0)
;
31
Taking false branch
32
Loop condition is false. Exiting loop
1079 assert(where)do { if ((__builtin_expect(!!(!(where)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("where"), "../src/portable/portable.c", 1079
, __PRETTY_FUNCTION__); } while (0)
;
33
Taking false branch
34
Loop condition is false. Exiting loop
1080 assert(fname)do { if ((__builtin_expect(!!(!(fname)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("fname"), "../src/portable/portable.c", 1080
, __PRETTY_FUNCTION__); } while (0)
;
35
Taking false branch
36
Loop condition is false. Exiting loop
1081
1082 /* We recognize unis created from portable images via the drop-in we created for them */
1083
1084 p = strjoina(fname, ".d/20-portable.conf")({ const char *_appendees_[] = { fname, ".d/20-portable.conf"
}; char *_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ =
0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
;
37
Loop condition is true. Entering loop body
38
Loop condition is true. Entering loop body
39
Loop condition is true. Entering loop body
40
Loop condition is true. Entering loop body
1085 fd = openat(dirfd(d), p, O_RDONLY00|O_CLOEXEC02000000);
1086 if (fd < 0) {
41
Assuming 'fd' is >= 0
42
Taking false branch
1087 if (errno(*__errno_location ()) == ENOENT2)
1088 return 0;
1089
1090 return log_debug_errno(errno, "Failed to open %s/%s: %m", where, p)({ int _level = ((7)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/portable/portable.c", 1090, __func__
, "Failed to open %s/%s: %m", where, p) : -abs(_e); })
;
1091 }
1092
1093 f = fdopen(fd, "re");
1094 if (!f)
43
Assuming 'f' is non-null
44
Taking false branch
1095 return log_debug_errno(errno, "Failed to convert file handle: %m")({ int _level = ((7)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/portable/portable.c", 1095, __func__
, "Failed to convert file handle: %m") : -abs(_e); })
;
1096 fd = -1;
1097
1098 (void) __fsetlocking(f, FSETLOCKING_BYCALLERFSETLOCKING_BYCALLER);
1099
1100 r = read_line(f, LONG_LINE_MAX(1U*1024U*1024U), &line);
1101 if (r < 0)
45
Assuming 'r' is >= 0
46
Taking false branch
1102 return log_debug_errno(r, "Failed to read from %s/%s: %m", where, p)({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/portable/portable.c", 1102, __func__, "Failed to read from %s/%s: %m"
, where, p) : -abs(_e); })
;
1103
1104 e = startswith(line, PORTABLE_DROPIN_MARKER_BEGIN"# Drop-in created for image '");
1105 if (!e
46.1
'e' is non-null
)
47
Taking false branch
1106 return 0;
1107
1108 k = endswith(e, PORTABLE_DROPIN_MARKER_END"', do not edit.");
1109 if (!k)
48
Assuming 'k' is non-null
49
Taking false branch
1110 return 0;
1111
1112 marker = strndup(e, k - e);
50
Memory is allocated
1113 if (!marker)
51
Assuming 'marker' is non-null
52
Taking false branch
1114 return -ENOMEM12;
1115
1116 if (!name_or_path
52.1
'name_or_path' is non-null
)
53
Taking false branch
1117 r = true1;
1118 else
1119 r = marker_matches_image(marker, name_or_path);
1120
1121 if (ret_marker
53.1
'ret_marker' is null
)
54
Taking false branch
1122 *ret_marker = TAKE_PTR(marker)({ typeof(marker) _ptr_ = (marker); (marker) = ((void*)0); _ptr_
; })
;
1123
1124 return r;
55
Potential leak of memory pointed to by 'marker'
1125}
1126
1127int portable_detach(
1128 sd_bus *bus,
1129 const char *name_or_path,
1130 PortableFlags flags,
1131 PortableChange **changes,
1132 size_t *n_changes,
1133 sd_bus_error *error) {
1134
1135 _cleanup_(lookup_paths_free)__attribute__((cleanup(lookup_paths_free))) LookupPaths paths = {};
1136 _cleanup_set_free_free___attribute__((cleanup(set_free_freep))) Set *unit_files = NULL((void*)0), *markers = NULL((void*)0);
1137 _cleanup_closedir___attribute__((cleanup(closedirp))) DIR *d = NULL((void*)0);
1138 const char *where, *item;
1139 Iterator iterator;
1140 struct dirent *de;
1141 int ret = 0;
1142 int r;
1143
1144 assert(name_or_path)do { if ((__builtin_expect(!!(!(name_or_path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name_or_path"), "../src/portable/portable.c"
, 1144, __PRETTY_FUNCTION__); } while (0)
;
1145
1146 r = lookup_paths_init(&paths, UNIT_FILE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL((void*)0));
1147 if (r < 0)
1148 return r;
1149
1150 where = config_path(&paths, flags);
1151
1152 d = opendir(where);
1153 if (!d)
1154 return log_debug_errno(errno, "Failed to open '%s' directory: %m", where)({ int _level = ((7)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/portable/portable.c", 1154, __func__
, "Failed to open '%s' directory: %m", where) : -abs(_e); })
;
1155
1156 unit_files = set_new(&string_hash_ops)internal_set_new(&string_hash_ops );
1157 if (!unit_files)
1158 return -ENOMEM12;
1159
1160 markers = set_new(&path_hash_ops)internal_set_new(&path_hash_ops );
1161 if (!markers)
1162 return -ENOMEM12;
1163
1164 FOREACH_DIRENT(de, d, return log_debug_errno(errno, "Failed to enumerate '%s' directory: %m", where))for ((*__errno_location ()) = 0, de = readdir(d);; (*__errno_location
()) = 0, de = readdir(d)) if (!de) { if ((*__errno_location (
)) > 0) { return ({ int _level = ((7)), _e = (((*__errno_location
()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm
(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((
_realm) << 10 | (_level)), _e, "../src/portable/portable.c"
, 1164, __func__, "Failed to enumerate '%s' directory: %m", where
) : -abs(_e); }); } break; } else if (hidden_or_backup_file((
de)->d_name)) continue; else
{
1165 _cleanup_free___attribute__((cleanup(freep))) char *marker = NULL((void*)0);
1166 UnitFileState state;
1167
1168 if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
1169 continue;
1170
1171 /* Filter out duplicates */
1172 if (set_get(unit_files, de->d_name))
1173 continue;
1174
1175 dirent_ensure_type(d, de);
1176 if (!IN_SET(de->d_type, DT_LNK, DT_REG)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){DT_LNK, DT_REG})/sizeof(int)]; switch(de
->d_type) { case DT_LNK: case DT_REG: _found = 1; break; default
: break; } _found; })
)
1177 continue;
1178
1179 r = test_chroot_dropin(d, where, de->d_name, name_or_path, &marker);
1180 if (r < 0)
1181 return r;
1182 if (r == 0)
1183 continue;
1184
1185 r = unit_file_lookup_state(UNIT_FILE_SYSTEM, &paths, de->d_name, &state);
1186 if (r < 0)
1187 return log_debug_errno(r, "Failed to determine unit file state of '%s': %m", de->d_name)({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/portable/portable.c", 1187, __func__, "Failed to determine unit file state of '%s': %m"
, de->d_name) : -abs(_e); })
;
1188 if (!IN_SET(state, UNIT_FILE_STATIC, UNIT_FILE_DISABLED, UNIT_FILE_LINKED, UNIT_FILE_RUNTIME)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){UNIT_FILE_STATIC, UNIT_FILE_DISABLED, UNIT_FILE_LINKED
, UNIT_FILE_RUNTIME})/sizeof(int)]; switch(state) { case UNIT_FILE_STATIC
: case UNIT_FILE_DISABLED: case UNIT_FILE_LINKED: case UNIT_FILE_RUNTIME
: _found = 1; break; default: break; } _found; })
)
1189 return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS"org.freedesktop.systemd1.UnitExists", "Unit file '%s' is in state '%s', can't detach.", de->d_name, unit_file_state_to_string(state));
1190
1191 r = unit_file_is_active(bus, de->d_name, error);
1192 if (r < 0)
1193 return r;
1194 if (r > 0)
1195 return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS"org.freedesktop.systemd1.UnitExists", "Unit file '%s' is active, can't detach.", de->d_name);
1196
1197 r = set_put_strdup(unit_files, de->d_name);
1198 if (r < 0)
1199 return log_debug_errno(r, "Failed to add unit name '%s' to set: %m", de->d_name)({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/portable/portable.c", 1199, __func__, "Failed to add unit name '%s' to set: %m"
, de->d_name) : -abs(_e); })
;
1200
1201 if (path_is_absolute(marker) &&
1202 !image_in_search_path(IMAGE_PORTABLE, marker)) {
1203
1204 r = set_ensure_allocated(&markers, &path_hash_ops)internal_set_ensure_allocated(&markers, &path_hash_ops
)
;
1205 if (r < 0)
1206 return r;
1207
1208 r = set_put(markers, marker);
1209 if (r >= 0)
1210 marker = NULL((void*)0);
1211 else if (r != -EEXIST17)
1212 return r;
1213 }
1214 }
1215
1216 if (set_isempty(unit_files)) {
1217 log_debug("No unit files associated with '%s' found. Image not attached?", name_or_path)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/portable/portable.c", 1217, __func__, "No unit files associated with '%s' found. Image not attached?"
, name_or_path) : -abs(_e); })
;
1218 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT"org.freedesktop.systemd1.NoSuchUnit", "No unit files associated with '%s' found. Image not attached?", name_or_path);
1219 }
1220
1221 SET_FOREACH(item, unit_files, iterator)for ((iterator) = ((Iterator) { .idx = ((2147483647 *2U +1U) -
1), .next_key = ((void*)0) }); set_iterate((unit_files), &
(iterator), (void**)&(item)); )
{
1222 _cleanup_free___attribute__((cleanup(freep))) char *md = NULL((void*)0);
1223 const char *suffix;
1224
1225 if (unlinkat(dirfd(d), item, 0) < 0) {
1226 log_debug_errno(errno, "Can't remove unit file %s/%s: %m", where, item)({ int _level = ((7)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/portable/portable.c", 1226, __func__
, "Can't remove unit file %s/%s: %m", where, item) : -abs(_e)
; })
;
1227
1228 if (errno(*__errno_location ()) != ENOENT2 && ret >= 0)
1229 ret = -errno(*__errno_location ());
1230 } else
1231 portable_changes_add_with_prefix(changes, n_changes, PORTABLE_UNLINK, where, item, NULL((void*)0));
1232
1233 FOREACH_STRING(suffix, ".d/10-profile.conf", ".d/20-portable.conf")for (char **_l = ({ char **_ll = ((char**) ((const char*[]) {
".d/10-profile.conf", ".d/20-portable.conf", ((void*)0) }));
suffix = _ll ? _ll[0] : ((void*)0); _ll; }); _l && *
_l; suffix = ({ _l ++; _l[0]; }))
{
1234 _cleanup_free___attribute__((cleanup(freep))) char *dropin = NULL((void*)0);
1235
1236 dropin = strjoin(item, suffix)strjoin_real((item), suffix, ((void*)0));
1237 if (!dropin)
1238 return -ENOMEM12;
1239
1240 if (unlinkat(dirfd(d), dropin, 0) < 0) {
1241 log_debug_errno(errno, "Can't remove drop-in %s/%s: %m", where, dropin)({ int _level = ((7)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/portable/portable.c", 1241, __func__
, "Can't remove drop-in %s/%s: %m", where, dropin) : -abs(_e)
; })
;
1242
1243 if (errno(*__errno_location ()) != ENOENT2 && ret >= 0)
1244 ret = -errno(*__errno_location ());
1245 } else
1246 portable_changes_add_with_prefix(changes, n_changes, PORTABLE_UNLINK, where, dropin, NULL((void*)0));
1247 }
1248
1249 md = strjoin(item, ".d")strjoin_real((item), ".d", ((void*)0));
1250 if (!md)
1251 return -ENOMEM12;
1252
1253 if (unlinkat(dirfd(d), md, AT_REMOVEDIR0x200) < 0) {
1254 log_debug_errno(errno, "Can't remove drop-in directory %s/%s: %m", where, md)({ int _level = ((7)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/portable/portable.c", 1254, __func__
, "Can't remove drop-in directory %s/%s: %m", where, md) : -abs
(_e); })
;
1255
1256 if (errno(*__errno_location ()) != ENOENT2 && ret >= 0)
1257 ret = -errno(*__errno_location ());
1258 } else
1259 portable_changes_add_with_prefix(changes, n_changes, PORTABLE_UNLINK, where, md, NULL((void*)0));
1260 }
1261
1262 /* Now, also drop any image symlink, for images outside of the sarch path */
1263 SET_FOREACH(item, markers, iterator)for ((iterator) = ((Iterator) { .idx = ((2147483647 *2U +1U) -
1), .next_key = ((void*)0) }); set_iterate((markers), &(
iterator), (void**)&(item)); )
{
1264 _cleanup_free___attribute__((cleanup(freep))) char *sl = NULL((void*)0);
1265 struct stat st;
1266
1267 r = image_symlink(item, flags, &sl);
1268 if (r < 0) {
1269 log_debug_errno(r, "Failed to determine image symlink for '%s', ignoring: %m", item)({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/portable/portable.c", 1269, __func__, "Failed to determine image symlink for '%s', ignoring: %m"
, item) : -abs(_e); })
;
1270 continue;
1271 }
1272
1273 if (lstat(sl, &st) < 0) {
1274 log_debug_errno(errno, "Failed to stat '%s', ignoring: %m", sl)({ int _level = ((7)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/portable/portable.c", 1274, __func__
, "Failed to stat '%s', ignoring: %m", sl) : -abs(_e); })
;
1275 continue;
1276 }
1277
1278 if (!S_ISLNK(st.st_mode)((((st.st_mode)) & 0170000) == (0120000))) {
1279 log_debug("Image '%s' is not a symlink, ignoring.", sl)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/portable/portable.c", 1279, __func__, "Image '%s' is not a symlink, ignoring."
, sl) : -abs(_e); })
;
1280 continue;
1281 }
1282
1283 if (unlink(sl) < 0) {
1284 log_debug_errno(errno, "Can't remove image symlink '%s': %m", sl)({ int _level = ((7)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/portable/portable.c", 1284, __func__
, "Can't remove image symlink '%s': %m", sl) : -abs(_e); })
;
1285
1286 if (errno(*__errno_location ()) != ENOENT2 && ret >= 0)
1287 ret = -errno(*__errno_location ());
1288 } else
1289 portable_changes_add(changes, n_changes, PORTABLE_UNLINK, sl, NULL((void*)0));
1290 }
1291
1292 return ret;
1293}
1294
1295static int portable_get_state_internal(
1296 sd_bus *bus,
1297 const char *name_or_path,
1298 PortableFlags flags,
1299 PortableState *ret,
1300 sd_bus_error *error) {
1301
1302 _cleanup_(lookup_paths_free)__attribute__((cleanup(lookup_paths_free))) LookupPaths paths = {};
1303 bool_Bool found_enabled = false0, found_running = false0;
1304 _cleanup_set_free_free___attribute__((cleanup(set_free_freep))) Set *unit_files = NULL((void*)0);
1305 _cleanup_closedir___attribute__((cleanup(closedirp))) DIR *d = NULL((void*)0);
1306 const char *where;
1307 struct dirent *de;
1308 int r;
1309
1310 assert(name_or_path)do { if ((__builtin_expect(!!(!(name_or_path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name_or_path"), "../src/portable/portable.c"
, 1310, __PRETTY_FUNCTION__); } while (0)
;
8
Taking false branch
9
Loop condition is false. Exiting loop
1311 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/portable/portable.c", 1311
, __PRETTY_FUNCTION__); } while (0)
;
10
Taking false branch
11
Loop condition is false. Exiting loop
1312
1313 r = lookup_paths_init(&paths, UNIT_FILE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL((void*)0));
1314 if (r < 0)
12
Assuming 'r' is >= 0
13
Taking false branch
1315 return r;
1316
1317 where = config_path(&paths, flags);
1318
1319 d = opendir(where);
1320 if (!d)
14
Assuming 'd' is non-null
15
Taking false branch
1321 return log_debug_errno(errno, "Failed to open '%s' directory: %m", where)({ int _level = ((7)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/portable/portable.c", 1321, __func__
, "Failed to open '%s' directory: %m", where) : -abs(_e); })
;
1322
1323 unit_files = set_new(&string_hash_ops)internal_set_new(&string_hash_ops );
1324 if (!unit_files)
16
Assuming 'unit_files' is non-null
17
Taking false branch
1325 return -ENOMEM12;
1326
1327 FOREACH_DIRENT(de, d, return log_debug_errno(errno, "Failed to enumerate '%s' directory: %m", where))for ((*__errno_location ()) = 0, de = readdir(d);; (*__errno_location
()) = 0, de = readdir(d)) if (!de) { if ((*__errno_location (
)) > 0) { return ({ int _level = ((7)), _e = (((*__errno_location
()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm
(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((
_realm) << 10 | (_level)), _e, "../src/portable/portable.c"
, 1327, __func__, "Failed to enumerate '%s' directory: %m", where
) : -abs(_e); }); } break; } else if (hidden_or_backup_file((
de)->d_name)) continue; else
{
18
Loop condition is true. Entering loop body
19
Assuming 'de' is non-null
20
Taking false branch
21
Assuming the condition is false
22
Taking false branch
1328 UnitFileState state;
1329
1330 if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
23
Assuming the condition is false
24
Taking false branch
1331 continue;
1332
1333 /* Filter out duplicates */
1334 if (set_get(unit_files, de->d_name))
25
Assuming the condition is false
26
Taking false branch
1335 continue;
1336
1337 dirent_ensure_type(d, de);
1338 if (!IN_SET(de->d_type, DT_LNK, DT_REG)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){DT_LNK, DT_REG})/sizeof(int)]; switch(de
->d_type) { case DT_LNK: case DT_REG: _found = 1; break; default
: break; } _found; })
)
27
Control jumps to 'case DT_REG:' at line 1338
28
Execution continues on line 1338
29
Taking false branch
1339 continue;
1340
1341 r = test_chroot_dropin(d, where, de->d_name, name_or_path, NULL((void*)0));
30
Calling 'test_chroot_dropin'
1342 if (r < 0)
1343 return r;
1344 if (r == 0)
1345 continue;
1346
1347 r = unit_file_lookup_state(UNIT_FILE_SYSTEM, &paths, de->d_name, &state);
1348 if (r < 0)
1349 return log_debug_errno(r, "Failed to determine unit file state of '%s': %m", de->d_name)({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/portable/portable.c", 1349, __func__, "Failed to determine unit file state of '%s': %m"
, de->d_name) : -abs(_e); })
;
1350 if (!IN_SET(state, UNIT_FILE_STATIC, UNIT_FILE_DISABLED, UNIT_FILE_LINKED, UNIT_FILE_LINKED_RUNTIME)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){UNIT_FILE_STATIC, UNIT_FILE_DISABLED, UNIT_FILE_LINKED
, UNIT_FILE_LINKED_RUNTIME})/sizeof(int)]; switch(state) { case
UNIT_FILE_STATIC: case UNIT_FILE_DISABLED: case UNIT_FILE_LINKED
: case UNIT_FILE_LINKED_RUNTIME: _found = 1; break; default: break
; } _found; })
)
1351 found_enabled = true1;
1352
1353 r = unit_file_is_active(bus, de->d_name, error);
1354 if (r < 0)
1355 return r;
1356 if (r > 0)
1357 found_running = true1;
1358
1359 r = set_put_strdup(unit_files, de->d_name);
1360 if (r < 0)
1361 return log_debug_errno(r, "Failed to add unit name '%s' to set: %m", de->d_name)({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/portable/portable.c", 1361, __func__, "Failed to add unit name '%s' to set: %m"
, de->d_name) : -abs(_e); })
;
1362 }
1363
1364 *ret = found_running ? (!set_isempty(unit_files) && (flags & PORTABLE_RUNTIME) ? PORTABLE_RUNNING_RUNTIME : PORTABLE_RUNNING) :
1365 found_enabled ? (flags & PORTABLE_RUNTIME ? PORTABLE_ENABLED_RUNTIME : PORTABLE_ENABLED) :
1366 !set_isempty(unit_files) ? (flags & PORTABLE_RUNTIME ? PORTABLE_ATTACHED_RUNTIME : PORTABLE_ATTACHED) : PORTABLE_DETACHED;
1367
1368 return 0;
1369}
1370
1371int portable_get_state(
1372 sd_bus *bus,
1373 const char *name_or_path,
1374 PortableFlags flags,
1375 PortableState *ret,
1376 sd_bus_error *error) {
1377
1378 PortableState state;
1379 int r;
1380
1381 assert(name_or_path)do { if ((__builtin_expect(!!(!(name_or_path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name_or_path"), "../src/portable/portable.c"
, 1381, __PRETTY_FUNCTION__); } while (0)
;
1
Assuming 'name_or_path' is non-null
2
Taking false branch
3
Loop condition is false. Exiting loop
1382 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/portable/portable.c", 1382
, __PRETTY_FUNCTION__); } while (0)
;
4
Assuming 'ret' is non-null
5
Taking false branch
6
Loop condition is false. Exiting loop
1383
1384 /* We look for matching units twice: once in the regular directories, and once in the runtime directories — but
1385 * the latter only if we didn't find anything in the former. */
1386
1387 r = portable_get_state_internal(bus, name_or_path, flags & ~PORTABLE_RUNTIME, &state, error);
7
Calling 'portable_get_state_internal'
1388 if (r < 0)
1389 return r;
1390
1391 if (state == PORTABLE_DETACHED) {
1392 r = portable_get_state_internal(bus, name_or_path, flags | PORTABLE_RUNTIME, &state, error);
1393 if (r < 0)
1394 return r;
1395 }
1396
1397 *ret = state;
1398 return 0;
1399}
1400
1401int portable_get_profiles(char ***ret) {
1402 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/portable/portable.c", 1402
, __PRETTY_FUNCTION__); } while (0)
;
1403
1404 return conf_files_list_nulstr(ret, NULL((void*)0), NULL((void*)0), CONF_FILES_DIRECTORY|CONF_FILES_BASENAME|CONF_FILES_FILTER_MASKED, profile_dirs);
1405}
1406
1407static const char* const portable_change_type_table[_PORTABLE_CHANGE_TYPE_MAX] = {
1408 [PORTABLE_COPY] = "copy",
1409 [PORTABLE_MKDIR] = "mkdir",
1410 [PORTABLE_SYMLINK] = "symlink",
1411 [PORTABLE_UNLINK] = "unlink",
1412 [PORTABLE_WRITE] = "write",
1413};
1414
1415DEFINE_STRING_TABLE_LOOKUP(portable_change_type, PortableChangeType)const char *portable_change_type_to_string(PortableChangeType
i) { if (i < 0 || i >= (PortableChangeType) __extension__
(__builtin_choose_expr( !__builtin_types_compatible_p(typeof
(portable_change_type_table), typeof(&*(portable_change_type_table
))), sizeof(portable_change_type_table)/sizeof((portable_change_type_table
)[0]), ((void)0)))) return ((void*)0); return portable_change_type_table
[i]; } PortableChangeType portable_change_type_from_string(const
char *s) { return (PortableChangeType) string_table_lookup(portable_change_type_table
, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(portable_change_type_table), typeof(&*(portable_change_type_table
))), sizeof(portable_change_type_table)/sizeof((portable_change_type_table
)[0]), ((void)0))), s); }
;
1416
1417static const char* const portable_state_table[_PORTABLE_STATE_MAX] = {
1418 [PORTABLE_DETACHED] = "detached",
1419 [PORTABLE_ATTACHED] = "attached",
1420 [PORTABLE_ATTACHED_RUNTIME] = "attached-runtime",
1421 [PORTABLE_ENABLED] = "enabled",
1422 [PORTABLE_ENABLED_RUNTIME] = "enabled-runtime",
1423 [PORTABLE_RUNNING] = "running",
1424 [PORTABLE_RUNNING_RUNTIME] = "running-runtime",
1425};
1426
1427DEFINE_STRING_TABLE_LOOKUP(portable_state, PortableState)const char *portable_state_to_string(PortableState i) { if (i
< 0 || i >= (PortableState) __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(portable_state_table),
typeof(&*(portable_state_table))), sizeof(portable_state_table
)/sizeof((portable_state_table)[0]), ((void)0)))) return ((void
*)0); return portable_state_table[i]; } PortableState portable_state_from_string
(const char *s) { return (PortableState) string_table_lookup(
portable_state_table, __extension__ (__builtin_choose_expr( !
__builtin_types_compatible_p(typeof(portable_state_table), typeof
(&*(portable_state_table))), sizeof(portable_state_table)
/sizeof((portable_state_table)[0]), ((void)0))), s); }
;