File: | build-scan/../src/portable/portable.c |
Warning: | line 1096, column 9 Value stored to 'fd' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | |
31 | static 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 | |
38 | static 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 | |
49 | static 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 | |
72 | static 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 | |
85 | PortableMetadata *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 | |
95 | Hashmap *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 | |
110 | static int compare_metadata(PortableMetadata *const *x, PortableMetadata *const *y) { |
111 | return strcmp((*x)->name, (*y)->name); |
112 | } |
113 | |
114 | int 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 | |
136 | static 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 | |
178 | static 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 | |
235 | static 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 | |
358 | static 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 | |
503 | int 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 | |
522 | static 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 | |
608 | static 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 | |
652 | static 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 | |
676 | void 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 | |
689 | static 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 | |
736 | static 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 | |
763 | static 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 | |
818 | static 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 | |
832 | static 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 | |
913 | static 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 | |
939 | static 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 | |
969 | int 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 | |
1027 | static 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 | |
1065 | static 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); |
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); |
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); |
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_; }); |
1085 | fd = openat(dirfd(d), p, O_RDONLY00|O_CLOEXEC02000000); |
1086 | if (fd < 0) { |
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) |
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; |
Value stored to 'fd' is never read | |
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) |
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) |
1106 | return 0; |
1107 | |
1108 | k = endswith(e, PORTABLE_DROPIN_MARKER_END"', do not edit."); |
1109 | if (!k) |
1110 | return 0; |
1111 | |
1112 | marker = strndup(e, k - e); |
1113 | if (!marker) |
1114 | return -ENOMEM12; |
1115 | |
1116 | if (!name_or_path) |
1117 | r = true1; |
1118 | else |
1119 | r = marker_matches_image(marker, name_or_path); |
1120 | |
1121 | if (ret_marker) |
1122 | *ret_marker = TAKE_PTR(marker)({ typeof(marker) _ptr_ = (marker); (marker) = ((void*)0); _ptr_ ; }); |
1123 | |
1124 | return r; |
1125 | } |
1126 | |
1127 | int 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 | |
1295 | static 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); |
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); |
1312 | |
1313 | r = lookup_paths_init(&paths, UNIT_FILE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, NULL((void*)0)); |
1314 | if (r < 0) |
1315 | return r; |
1316 | |
1317 | where = config_path(&paths, flags); |
1318 | |
1319 | d = opendir(where); |
1320 | if (!d) |
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) |
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 { |
1328 | UnitFileState state; |
1329 | |
1330 | if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY)) |
1331 | continue; |
1332 | |
1333 | /* Filter out duplicates */ |
1334 | if (set_get(unit_files, de->d_name)) |
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; })) |
1339 | continue; |
1340 | |
1341 | r = test_chroot_dropin(d, where, de->d_name, name_or_path, NULL((void*)0)); |
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 | |
1371 | int 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); |
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); |
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); |
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 | |
1401 | int 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 | |
1407 | static 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 | |
1415 | DEFINE_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 | |
1417 | static 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 | |
1427 | DEFINE_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); }; |