| File: | build-scan/../src/portable/portable.c |
| Warning: | line 126, column 29 Use of zero-allocated memory |
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; | |||
| 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); }; |
| 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
| 2 | #pragma once |
| 3 | |
| 4 | #include <alloca.h> |
| 5 | #include <stddef.h> |
| 6 | #include <stdlib.h> |
| 7 | #include <string.h> |
| 8 | |
| 9 | #include "macro.h" |
| 10 | |
| 11 | #define new(t, n)((t*) malloc_multiply(sizeof(t), (n))) ((t*) malloc_multiply(sizeof(t), (n))) |
| 12 | |
| 13 | #define new0(t, n)((t*) calloc((n), sizeof(t))) ((t*) calloc((n), sizeof(t))) |
| 14 | |
| 15 | #define newa(t, n)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof (t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)" ), "../src/basic/alloc-util.h", 15, __PRETTY_FUNCTION__); } while (0); (t*) __builtin_alloca (sizeof(t)*(n)); }) \ |
| 16 | ({ \ |
| 17 | assert(!size_multiply_overflow(sizeof(t), n))do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof (t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)" ), "../src/basic/alloc-util.h", 17, __PRETTY_FUNCTION__); } while (0); \ |
| 18 | (t*) alloca(sizeof(t)*(n))__builtin_alloca (sizeof(t)*(n)); \ |
| 19 | }) |
| 20 | |
| 21 | #define newa0(t, n)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof (t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)" ), "../src/basic/alloc-util.h", 21, __PRETTY_FUNCTION__); } while (0); (t*) ({ char *_new_; size_t _len_ = sizeof(t)*(n); _new_ = __builtin_alloca (_len_); (void *) memset(_new_, 0, _len_) ; }); }) \ |
| 22 | ({ \ |
| 23 | assert(!size_multiply_overflow(sizeof(t), n))do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof (t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)" ), "../src/basic/alloc-util.h", 23, __PRETTY_FUNCTION__); } while (0); \ |
| 24 | (t*) alloca0(sizeof(t)*(n))({ char *_new_; size_t _len_ = sizeof(t)*(n); _new_ = __builtin_alloca (_len_); (void *) memset(_new_, 0, _len_); }); \ |
| 25 | }) |
| 26 | |
| 27 | #define newdup(t, p, n)((t*) memdup_multiply(p, sizeof(t), (n))) ((t*) memdup_multiply(p, sizeof(t), (n))) |
| 28 | |
| 29 | #define newdup_suffix0(t, p, n)((t*) memdup_suffix0_multiply(p, sizeof(t), (n))) ((t*) memdup_suffix0_multiply(p, sizeof(t), (n))) |
| 30 | |
| 31 | #define malloc0(n)(calloc(1, (n))) (calloc(1, (n))) |
| 32 | |
| 33 | static inline void *mfree(void *memory) { |
| 34 | free(memory); |
| 35 | return NULL((void*)0); |
| 36 | } |
| 37 | |
| 38 | #define free_and_replace(a, b)({ free(a); (a) = (b); (b) = ((void*)0); 0; }) \ |
| 39 | ({ \ |
| 40 | free(a); \ |
| 41 | (a) = (b); \ |
| 42 | (b) = NULL((void*)0); \ |
| 43 | 0; \ |
| 44 | }) |
| 45 | |
| 46 | void* memdup(const void *p, size_t l) _alloc_(2); |
| 47 | void* memdup_suffix0(const void *p, size_t l) _alloc_(2); |
| 48 | |
| 49 | static inline void freep(void *p) { |
| 50 | free(*(void**) p); |
| 51 | } |
| 52 | |
| 53 | #define _cleanup_free___attribute__((cleanup(freep))) _cleanup_(freep)__attribute__((cleanup(freep))) |
| 54 | |
| 55 | static inline bool_Bool size_multiply_overflow(size_t size, size_t need) { |
| 56 | return _unlikely_(need != 0 && size > (SIZE_MAX / need))(__builtin_expect(!!(need != 0 && size > ((18446744073709551615UL ) / need)),0)); |
| 57 | } |
| 58 | |
| 59 | _malloc___attribute__ ((malloc)) _alloc_(1, 2) static inline void *malloc_multiply(size_t size, size_t need) { |
| 60 | if (size_multiply_overflow(size, need)) |
| 61 | return NULL((void*)0); |
| 62 | |
| 63 | return malloc(size * need); |
| 64 | } |
| 65 | |
| 66 | #if !HAVE_REALLOCARRAY1 |
| 67 | _alloc_(2, 3) static inline void *reallocarray(void *p, size_t need, size_t size) { |
| 68 | if (size_multiply_overflow(size, need)) |
| 69 | return NULL((void*)0); |
| 70 | |
| 71 | return realloc(p, size * need); |
| 72 | } |
| 73 | #endif |
| 74 | |
| 75 | _alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, size_t need) { |
| 76 | if (size_multiply_overflow(size, need)) |
| 77 | return NULL((void*)0); |
| 78 | |
| 79 | return memdup(p, size * need); |
| 80 | } |
| 81 | |
| 82 | _alloc_(2, 3) static inline void *memdup_suffix0_multiply(const void *p, size_t size, size_t need) { |
| 83 | if (size_multiply_overflow(size, need)) |
| 84 | return NULL((void*)0); |
| 85 | |
| 86 | return memdup_suffix0(p, size * need); |
| 87 | } |
| 88 | |
| 89 | void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size); |
| 90 | void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size); |
| 91 | |
| 92 | #define GREEDY_REALLOC(array, allocated, need)greedy_realloc((void**) &(array), &(allocated), (need ), sizeof((array)[0])) \ |
| 93 | greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0])) |
| 94 | |
| 95 | #define GREEDY_REALLOC0(array, allocated, need)greedy_realloc0((void**) &(array), &(allocated), (need ), sizeof((array)[0])) \ |
| 96 | greedy_realloc0((void**) &(array), &(allocated), (need), sizeof((array)[0])) |
| 97 | |
| 98 | #define alloca0(n)({ char *_new_; size_t _len_ = n; _new_ = __builtin_alloca (_len_ ); (void *) memset(_new_, 0, _len_); }) \ |
| 99 | ({ \ |
| 100 | char *_new_; \ |
| 101 | size_t _len_ = n; \ |
| 102 | _new_ = alloca(_len_)__builtin_alloca (_len_); \ |
| 103 | (void *) memset(_new_, 0, _len_); \ |
| 104 | }) |
| 105 | |
| 106 | /* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */ |
| 107 | #define alloca_align(size, align)({ void *_ptr_; size_t _mask_ = (align) - 1; _ptr_ = __builtin_alloca ((size) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); }) \ |
| 108 | ({ \ |
| 109 | void *_ptr_; \ |
| 110 | size_t _mask_ = (align) - 1; \ |
| 111 | _ptr_ = alloca((size) + _mask_)__builtin_alloca ((size) + _mask_); \ |
| 112 | (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \ |
| 113 | }) |
| 114 | |
| 115 | #define alloca0_align(size, align)({ void *_new_; size_t _size_ = (size); _new_ = ({ void *_ptr_ ; size_t _mask_ = ((align)) - 1; _ptr_ = __builtin_alloca ((_size_ ) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_ ); }); (void*)memset(_new_, 0, _size_); }) \ |
| 116 | ({ \ |
| 117 | void *_new_; \ |
| 118 | size_t _size_ = (size); \ |
| 119 | _new_ = alloca_align(_size_, (align))({ void *_ptr_; size_t _mask_ = ((align)) - 1; _ptr_ = __builtin_alloca ((_size_) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); }); \ |
| 120 | (void*)memset(_new_, 0, _size_); \ |
| 121 | }) |
| 122 | |
| 123 | /* Takes inspiration from Rusts's Option::take() method: reads and returns a pointer, but at the same time resets it to |
| 124 | * NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */ |
| 125 | #define TAKE_PTR(ptr)({ typeof(ptr) _ptr_ = (ptr); (ptr) = ((void*)0); _ptr_; }) \ |
| 126 | ({ \ |
| 127 | typeof(ptr) _ptr_ = (ptr); \ |
| 128 | (ptr) = NULL((void*)0); \ |
| 129 | _ptr_; \ |
| 130 | }) |