| File: | build-scan/../src/portable/portablectl.c |
| Warning: | line 406, column 24 Potential leak of memory pointed to by 'image' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | |||
| 2 | ||||
| 3 | #include <errno(*__errno_location ()).h> | |||
| 4 | #include <getopt.h> | |||
| 5 | ||||
| 6 | #include "sd-bus.h" | |||
| 7 | ||||
| 8 | #include "alloc-util.h" | |||
| 9 | #include "bus-error.h" | |||
| 10 | #include "bus-util.h" | |||
| 11 | #include "def.h" | |||
| 12 | #include "dirent-util.h" | |||
| 13 | #include "fd-util.h" | |||
| 14 | #include "fileio.h" | |||
| 15 | #include "format-table.h" | |||
| 16 | #include "fs-util.h" | |||
| 17 | #include "locale-util.h" | |||
| 18 | #include "machine-image.h" | |||
| 19 | #include "pager.h" | |||
| 20 | #include "parse-util.h" | |||
| 21 | #include "path-util.h" | |||
| 22 | #include "spawn-polkit-agent.h" | |||
| 23 | #include "string-util.h" | |||
| 24 | #include "strv.h" | |||
| 25 | #include "terminal-util.h" | |||
| 26 | #include "verbs.h" | |||
| 27 | ||||
| 28 | static bool_Bool arg_no_pager = false0; | |||
| 29 | static bool_Bool arg_legend = true1; | |||
| 30 | static bool_Bool arg_ask_password = true1; | |||
| 31 | static bool_Bool arg_quiet = false0; | |||
| 32 | static const char *arg_profile = "default"; | |||
| 33 | static const char* arg_copy_mode = NULL((void*)0); | |||
| 34 | static bool_Bool arg_runtime = false0; | |||
| 35 | static bool_Bool arg_reload = true1; | |||
| 36 | static bool_Bool arg_cat = false0; | |||
| 37 | static BusTransport arg_transport = BUS_TRANSPORT_LOCAL; | |||
| 38 | static char *arg_host = NULL((void*)0); | |||
| 39 | ||||
| 40 | static int determine_image(const char *image, bool_Bool permit_non_existing, char **ret) { | |||
| 41 | int r; | |||
| 42 | ||||
| 43 | /* If the specified name is a valid image name, we pass it as-is to portabled, which will search for it in the | |||
| 44 | * usual search directories. Otherwise we presume it's a path, and will normalize it on the client's side | |||
| 45 | * (among other things, to make the path independent of the client's working directory) before passing it | |||
| 46 | * over. */ | |||
| 47 | ||||
| 48 | if (image_name_is_valid(image)) { | |||
| 49 | char *c; | |||
| 50 | ||||
| 51 | if (!arg_quiet && laccess(image, F_OK)faccessat(-100, (image), (0), 0x100) >= 0) | |||
| 52 | log_warning("Ambiguous invocation: current working directory contains file matching non-path argument '%s', ignoring. "({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 53, __func__, "Ambiguous invocation: current working directory contains file matching non-path argument '%s', ignoring. " "Prefix argument with './' to force reference to file in current working directory." , image) : -abs(_e); }) | |||
| 53 | "Prefix argument with './' to force reference to file in current working directory.", image)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 53, __func__, "Ambiguous invocation: current working directory contains file matching non-path argument '%s', ignoring. " "Prefix argument with './' to force reference to file in current working directory." , image) : -abs(_e); }); | |||
| 54 | ||||
| 55 | c = strdup(image); | |||
| 56 | if (!c) | |||
| 57 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/portable/portablectl.c" , 57, __func__); | |||
| 58 | ||||
| 59 | *ret = c; | |||
| 60 | return 0; | |||
| 61 | } | |||
| 62 | ||||
| 63 | if (arg_transport != BUS_TRANSPORT_LOCAL) { | |||
| 64 | log_error("Operations on images by path not supported when connecting to remote systems.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 64, __func__, "Operations on images by path not supported when connecting to remote systems." ) : -abs(_e); }); | |||
| 65 | return -EOPNOTSUPP95; | |||
| 66 | } | |||
| 67 | ||||
| 68 | r = chase_symlinks(image, NULL((void*)0), CHASE_TRAIL_SLASH | (permit_non_existing ? CHASE_NONEXISTENT : 0), ret); | |||
| 69 | if (r < 0) | |||
| 70 | return log_error_errno(r, "Cannot normalize specified image path '%s': %m", image)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 70, __func__, "Cannot normalize specified image path '%s': %m" , image) : -abs(_e); }); | |||
| 71 | ||||
| 72 | return 0; | |||
| 73 | } | |||
| 74 | ||||
| 75 | static int extract_prefix(const char *path, char **ret) { | |||
| 76 | _cleanup_free___attribute__((cleanup(freep))) char *name = NULL((void*)0); | |||
| 77 | const char *bn, *underscore; | |||
| 78 | size_t m; | |||
| 79 | ||||
| 80 | bn = basename(path); | |||
| 81 | ||||
| 82 | underscore = strchr(bn, '_'); | |||
| 83 | if (underscore) | |||
| 84 | m = underscore - bn; | |||
| 85 | else { | |||
| 86 | const char *e; | |||
| 87 | ||||
| 88 | e = endswith(bn, ".raw"); | |||
| 89 | if (!e) | |||
| 90 | e = strchr(bn, 0); | |||
| 91 | ||||
| 92 | m = e - bn; | |||
| 93 | } | |||
| 94 | ||||
| 95 | name = strndup(bn, m); | |||
| 96 | if (!name) | |||
| 97 | return -ENOMEM12; | |||
| 98 | ||||
| 99 | /* A slightly reduced version of what's permitted in unit names. With ':' and '\' are removed, as well as '_' | |||
| 100 | * which we use as delimiter for the second part of the image string, which we ignore for now. */ | |||
| 101 | if (!in_charset(name, DIGITS"0123456789" LETTERS"abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "-.")) | |||
| 102 | return -EINVAL22; | |||
| 103 | ||||
| 104 | if (!filename_is_valid(name)) | |||
| 105 | return -EINVAL22; | |||
| 106 | ||||
| 107 | *ret = TAKE_PTR(name)({ typeof(name) _ptr_ = (name); (name) = ((void*)0); _ptr_; } ); | |||
| 108 | ||||
| 109 | return 0; | |||
| 110 | } | |||
| 111 | ||||
| 112 | static int determine_matches(const char *image, char **l, bool_Bool allow_any, char ***ret) { | |||
| 113 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **k = NULL((void*)0); | |||
| 114 | int r; | |||
| 115 | ||||
| 116 | /* Determine the matches to apply. If the list is empty we derive the match from the image name. If the list | |||
| 117 | * contains exactly the "-" we return a wildcard list (which is the empty list), but only if this is expressly | |||
| 118 | * permitted. */ | |||
| 119 | ||||
| 120 | if (strv_isempty(l)) { | |||
| 121 | char *prefix; | |||
| 122 | ||||
| 123 | r = extract_prefix(image, &prefix); | |||
| 124 | if (r < 0) | |||
| 125 | return log_error_errno(r, "Failed to extract prefix of image name '%s': %m", image)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 125, __func__, "Failed to extract prefix of image name '%s': %m" , image) : -abs(_e); }); | |||
| 126 | ||||
| 127 | if (!arg_quiet) | |||
| 128 | log_info("(Matching unit files with prefix '%s'.)", prefix)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 128, __func__, "(Matching unit files with prefix '%s'.)" , prefix) : -abs(_e); }); | |||
| 129 | ||||
| 130 | r = strv_consume(&k, prefix); | |||
| 131 | if (r < 0) | |||
| 132 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/portable/portablectl.c" , 132, __func__); | |||
| 133 | ||||
| 134 | } else if (strv_equal(l, STRV_MAKE("-")((char**) ((const char*[]) { "-", ((void*)0) })))) { | |||
| 135 | ||||
| 136 | if (!allow_any) { | |||
| 137 | log_error("Refusing all unit file match.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 137, __func__, "Refusing all unit file match." ) : -abs(_e); }); | |||
| 138 | return -EINVAL22; | |||
| 139 | } | |||
| 140 | ||||
| 141 | if (!arg_quiet) | |||
| 142 | log_info("(Matching all unit files.)")({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 142, __func__, "(Matching all unit files.)" ) : -abs(_e); }); | |||
| 143 | } else { | |||
| 144 | ||||
| 145 | k = strv_copy(l); | |||
| 146 | if (!k) | |||
| 147 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/portable/portablectl.c" , 147, __func__); | |||
| 148 | ||||
| 149 | if (!arg_quiet) { | |||
| 150 | _cleanup_free___attribute__((cleanup(freep))) char *joined = NULL((void*)0); | |||
| 151 | ||||
| 152 | joined = strv_join(k, "', '"); | |||
| 153 | if (!joined) | |||
| 154 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/portable/portablectl.c" , 154, __func__); | |||
| 155 | ||||
| 156 | log_info("(Matching unit files with prefixes '%s'.)", joined)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 156, __func__, "(Matching unit files with prefixes '%s'.)" , joined) : -abs(_e); }); | |||
| 157 | } | |||
| 158 | } | |||
| 159 | ||||
| 160 | *ret = TAKE_PTR(k)({ typeof(k) _ptr_ = (k); (k) = ((void*)0); _ptr_; }); | |||
| 161 | ||||
| 162 | return 0; | |||
| 163 | } | |||
| 164 | ||||
| 165 | static int acquire_bus(sd_bus **bus) { | |||
| 166 | int r; | |||
| 167 | ||||
| 168 | assert(bus)do { if ((__builtin_expect(!!(!(bus)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("bus"), "../src/portable/portablectl.c", 168, __PRETTY_FUNCTION__); } while (0); | |||
| 169 | ||||
| 170 | if (*bus) | |||
| 171 | return 0; | |||
| 172 | ||||
| 173 | r = bus_connect_transport(arg_transport, arg_host, false0, bus); | |||
| 174 | if (r < 0) | |||
| 175 | return log_error_errno(r, "Failed to connect to bus: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 175, __func__, "Failed to connect to bus: %m" ) : -abs(_e); }); | |||
| 176 | ||||
| 177 | (void) sd_bus_set_allow_interactive_authorization(*bus, arg_ask_password); | |||
| 178 | ||||
| 179 | return 0; | |||
| 180 | } | |||
| 181 | ||||
| 182 | static int maybe_reload(sd_bus **bus) { | |||
| 183 | _cleanup_(sd_bus_error_free)__attribute__((cleanup(sd_bus_error_free))) sd_bus_error error = SD_BUS_ERROR_NULL((const sd_bus_error) {(((void*)0)), (((void*)0)), 0}); | |||
| 184 | _cleanup_(sd_bus_message_unrefp)__attribute__((cleanup(sd_bus_message_unrefp))) sd_bus_message *m = NULL((void*)0); | |||
| 185 | int r; | |||
| 186 | ||||
| 187 | if (!arg_reload) | |||
| 188 | return 0; | |||
| 189 | ||||
| 190 | r = acquire_bus(bus); | |||
| 191 | if (r < 0) | |||
| 192 | return r; | |||
| 193 | ||||
| 194 | r = sd_bus_message_new_method_call( | |||
| 195 | *bus, | |||
| 196 | &m, | |||
| 197 | "org.freedesktop.systemd1", | |||
| 198 | "/org/freedesktop/systemd1", | |||
| 199 | "org.freedesktop.systemd1.Manager", | |||
| 200 | "Reload"); | |||
| 201 | if (r < 0) | |||
| 202 | return bus_log_create_error(r); | |||
| 203 | ||||
| 204 | /* Reloading the daemon may take long, hence set a longer timeout here */ | |||
| 205 | r = sd_bus_call(*bus, m, DEFAULT_TIMEOUT_USEC(90*((usec_t) 1000000ULL)) * 2, &error, NULL((void*)0)); | |||
| 206 | if (r < 0) | |||
| 207 | return log_error_errno(r, "Failed to reload daemon: %s", bus_error_message(&error, r))({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 207, __func__, "Failed to reload daemon: %s" , bus_error_message(&error, r)) : -abs(_e); }); | |||
| 208 | ||||
| 209 | return 0; | |||
| 210 | } | |||
| 211 | ||||
| 212 | static int inspect_image(int argc, char *argv[], void *userdata) { | |||
| 213 | _cleanup_(sd_bus_message_unrefp)__attribute__((cleanup(sd_bus_message_unrefp))) sd_bus_message *m = NULL((void*)0), *reply = NULL((void*)0); | |||
| 214 | _cleanup_(sd_bus_error_free)__attribute__((cleanup(sd_bus_error_free))) sd_bus_error error = SD_BUS_ERROR_NULL((const sd_bus_error) {(((void*)0)), (((void*)0)), 0}); | |||
| 215 | _cleanup_(sd_bus_flush_close_unrefp)__attribute__((cleanup(sd_bus_flush_close_unrefp))) sd_bus *bus = NULL((void*)0); | |||
| 216 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **matches = NULL((void*)0); | |||
| 217 | _cleanup_free___attribute__((cleanup(freep))) char *image = NULL((void*)0); | |||
| 218 | bool_Bool nl = false0, header = false0; | |||
| 219 | const void *data; | |||
| 220 | const char *path; | |||
| 221 | size_t sz; | |||
| 222 | int r; | |||
| 223 | ||||
| 224 | r = determine_image(argv[1], false0, &image); | |||
| 225 | if (r < 0) | |||
| 226 | return r; | |||
| 227 | ||||
| 228 | r = determine_matches(argv[1], argv + 2, true1, &matches); | |||
| 229 | if (r < 0) | |||
| 230 | return r; | |||
| 231 | ||||
| 232 | r = acquire_bus(&bus); | |||
| 233 | if (r < 0) | |||
| 234 | return r; | |||
| 235 | ||||
| 236 | r = sd_bus_message_new_method_call( | |||
| 237 | bus, | |||
| 238 | &m, | |||
| 239 | "org.freedesktop.portable1", | |||
| 240 | "/org/freedesktop/portable1", | |||
| 241 | "org.freedesktop.portable1.Manager", | |||
| 242 | "GetImageMetadata"); | |||
| 243 | if (r < 0) | |||
| 244 | return bus_log_create_error(r); | |||
| 245 | ||||
| 246 | r = sd_bus_message_append(m, "s", image); | |||
| 247 | if (r < 0) | |||
| 248 | return bus_log_create_error(r); | |||
| 249 | ||||
| 250 | r = sd_bus_message_append_strv(m, matches); | |||
| 251 | if (r < 0) | |||
| 252 | return bus_log_create_error(r); | |||
| 253 | ||||
| 254 | r = sd_bus_call(bus, m, 0, &error, &reply); | |||
| 255 | if (r < 0) | |||
| 256 | return log_error_errno(r, "Failed to inspect image metadata: %s", bus_error_message(&error, r))({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 256, __func__, "Failed to inspect image metadata: %s" , bus_error_message(&error, r)) : -abs(_e); }); | |||
| 257 | ||||
| 258 | r = sd_bus_message_read(reply, "s", &path); | |||
| 259 | if (r < 0) | |||
| 260 | return bus_log_parse_error(r); | |||
| 261 | ||||
| 262 | r = sd_bus_message_read_array(reply, 'y', &data, &sz); | |||
| 263 | if (r < 0) | |||
| 264 | return bus_log_parse_error(r); | |||
| 265 | ||||
| 266 | (void) pager_open(arg_no_pager, false0); | |||
| 267 | ||||
| 268 | if (arg_cat) { | |||
| 269 | printf("%s-- OS Release: --%s\n", ansi_highlight(), ansi_normal()); | |||
| 270 | fwrite(data, sz, 1, stdoutstdout); | |||
| 271 | fflush(stdoutstdout); | |||
| 272 | nl = true1; | |||
| 273 | } else { | |||
| 274 | _cleanup_free___attribute__((cleanup(freep))) char *pretty_portable = NULL((void*)0), *pretty_os = NULL((void*)0); | |||
| 275 | ||||
| 276 | _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f; | |||
| 277 | ||||
| 278 | f = fmemopen((void*) data, sz, "re"); | |||
| 279 | if (!f) | |||
| 280 | return log_error_errno(errno, "Failed to open /etc/os-release buffer: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/portable/portablectl.c", 280, __func__ , "Failed to open /etc/os-release buffer: %m") : -abs(_e); }); | |||
| 281 | ||||
| 282 | r = parse_env_file(f, "/etc/os-release", NEWLINE"\n\r", | |||
| 283 | "PORTABLE_PRETTY_NAME", &pretty_portable, | |||
| 284 | "PRETTY_NAME", &pretty_os, | |||
| 285 | NULL((void*)0)); | |||
| 286 | if (r < 0) | |||
| 287 | return log_error_errno(r, "Failed to parse /etc/os-release: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 287, __func__, "Failed to parse /etc/os-release: %m" ) : -abs(_e); }); | |||
| 288 | ||||
| 289 | printf("Image:\n\t%s\n" | |||
| 290 | "Portable Service:\n\t%s\n" | |||
| 291 | "Operating System:\n\t%s\n", | |||
| 292 | path, | |||
| 293 | strna(pretty_portable), | |||
| 294 | strna(pretty_os)); | |||
| 295 | } | |||
| 296 | ||||
| 297 | r = sd_bus_message_enter_container(reply, 'a', "{say}"); | |||
| 298 | if (r < 0) | |||
| 299 | return bus_log_parse_error(r); | |||
| 300 | ||||
| 301 | for (;;) { | |||
| 302 | const char *name; | |||
| 303 | ||||
| 304 | r = sd_bus_message_enter_container(reply, 'e', "say"); | |||
| 305 | if (r < 0) | |||
| 306 | return bus_log_parse_error(r); | |||
| 307 | if (r == 0) | |||
| 308 | break; | |||
| 309 | ||||
| 310 | r = sd_bus_message_read(reply, "s", &name); | |||
| 311 | if (r < 0) | |||
| 312 | return bus_log_parse_error(r); | |||
| 313 | ||||
| 314 | r = sd_bus_message_read_array(reply, 'y', &data, &sz); | |||
| 315 | if (r < 0) | |||
| 316 | return bus_log_parse_error(r); | |||
| 317 | ||||
| 318 | if (arg_cat) { | |||
| 319 | if (nl) | |||
| 320 | fputc('\n', stdoutstdout); | |||
| 321 | ||||
| 322 | printf("%s-- Unit file: %s --%s\n", ansi_highlight(), name, ansi_normal()); | |||
| 323 | fwrite(data, sz, 1, stdoutstdout); | |||
| 324 | fflush(stdoutstdout); | |||
| 325 | nl = true1; | |||
| 326 | } else { | |||
| 327 | if (!header) { | |||
| 328 | fputs("Unit files:\n", stdoutstdout); | |||
| 329 | header = true1; | |||
| 330 | } | |||
| 331 | ||||
| 332 | fputc('\t', stdoutstdout); | |||
| 333 | fputs(name, stdoutstdout); | |||
| 334 | fputc('\n', stdoutstdout); | |||
| 335 | } | |||
| 336 | ||||
| 337 | r = sd_bus_message_exit_container(reply); | |||
| 338 | if (r < 0) | |||
| 339 | return bus_log_parse_error(r); | |||
| 340 | } | |||
| 341 | ||||
| 342 | r = sd_bus_message_exit_container(reply); | |||
| 343 | if (r < 0) | |||
| 344 | return bus_log_parse_error(r); | |||
| 345 | ||||
| 346 | return 0; | |||
| 347 | } | |||
| 348 | ||||
| 349 | static int print_changes(sd_bus_message *m) { | |||
| 350 | int r; | |||
| 351 | ||||
| 352 | if (arg_quiet) | |||
| 353 | return 0; | |||
| 354 | ||||
| 355 | r = sd_bus_message_enter_container(m, 'a', "(sss)"); | |||
| 356 | if (r < 0) | |||
| 357 | return bus_log_parse_error(r); | |||
| 358 | ||||
| 359 | for (;;) { | |||
| 360 | const char *type, *path, *source; | |||
| 361 | ||||
| 362 | r = sd_bus_message_read(m, "(sss)", &type, &path, &source); | |||
| 363 | if (r < 0) | |||
| 364 | return bus_log_parse_error(r); | |||
| 365 | if (r == 0) | |||
| 366 | break; | |||
| 367 | ||||
| 368 | if (streq(type, "symlink")(strcmp((type),("symlink")) == 0)) | |||
| 369 | log_info("Created symlink %s %s %s.", path, special_glyph(ARROW), source)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 369, __func__, "Created symlink %s %s %s." , path, special_glyph(ARROW), source) : -abs(_e); }); | |||
| 370 | else if (streq(type, "copy")(strcmp((type),("copy")) == 0)) { | |||
| 371 | if (isempty(source)) | |||
| 372 | log_info("Copied %s.", path)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 372, __func__, "Copied %s." , path) : -abs(_e); }); | |||
| 373 | else | |||
| 374 | log_info("Copied %s %s %s.", source, special_glyph(ARROW), path)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 374, __func__, "Copied %s %s %s." , source, special_glyph(ARROW), path) : -abs(_e); }); | |||
| 375 | } else if (streq(type, "unlink")(strcmp((type),("unlink")) == 0)) | |||
| 376 | log_info("Removed %s.", path)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 376, __func__, "Removed %s." , path) : -abs(_e); }); | |||
| 377 | else if (streq(type, "write")(strcmp((type),("write")) == 0)) | |||
| 378 | log_info("Written %s.", path)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 378, __func__, "Written %s." , path) : -abs(_e); }); | |||
| 379 | else if (streq(type, "mkdir")(strcmp((type),("mkdir")) == 0)) | |||
| 380 | log_info("Created directory %s.", path)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 380, __func__, "Created directory %s." , path) : -abs(_e); }); | |||
| 381 | else | |||
| 382 | log_error("Unexpected change: %s/%s/%s", type, path, source)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 382, __func__, "Unexpected change: %s/%s/%s" , type, path, source) : -abs(_e); }); | |||
| 383 | } | |||
| 384 | ||||
| 385 | r = sd_bus_message_exit_container(m); | |||
| 386 | if (r < 0) | |||
| 387 | return r; | |||
| 388 | ||||
| 389 | return 0; | |||
| 390 | } | |||
| 391 | ||||
| 392 | static int attach_image(int argc, char *argv[], void *userdata) { | |||
| 393 | _cleanup_(sd_bus_message_unrefp)__attribute__((cleanup(sd_bus_message_unrefp))) sd_bus_message *m = NULL((void*)0), *reply = NULL((void*)0); | |||
| 394 | _cleanup_(sd_bus_error_free)__attribute__((cleanup(sd_bus_error_free))) sd_bus_error error = SD_BUS_ERROR_NULL((const sd_bus_error) {(((void*)0)), (((void*)0)), 0}); | |||
| 395 | _cleanup_(sd_bus_flush_close_unrefp)__attribute__((cleanup(sd_bus_flush_close_unrefp))) sd_bus *bus = NULL((void*)0); | |||
| 396 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **matches = NULL((void*)0); | |||
| 397 | _cleanup_free___attribute__((cleanup(freep))) char *image = NULL((void*)0); | |||
| 398 | int r; | |||
| 399 | ||||
| 400 | r = determine_image(argv[1], false0, &image); | |||
| ||||
| 401 | if (r
| |||
| 402 | return r; | |||
| 403 | ||||
| 404 | r = determine_matches(argv[1], argv + 2, false0, &matches); | |||
| 405 | if (r < 0) | |||
| 406 | return r; | |||
| ||||
| 407 | ||||
| 408 | r = acquire_bus(&bus); | |||
| 409 | if (r < 0) | |||
| 410 | return r; | |||
| 411 | ||||
| 412 | (void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password); | |||
| 413 | ||||
| 414 | r = sd_bus_message_new_method_call( | |||
| 415 | bus, | |||
| 416 | &m, | |||
| 417 | "org.freedesktop.portable1", | |||
| 418 | "/org/freedesktop/portable1", | |||
| 419 | "org.freedesktop.portable1.Manager", | |||
| 420 | "AttachImage"); | |||
| 421 | if (r < 0) | |||
| 422 | return bus_log_create_error(r); | |||
| 423 | ||||
| 424 | r = sd_bus_message_append(m, "s", image); | |||
| 425 | if (r < 0) | |||
| 426 | return bus_log_create_error(r); | |||
| 427 | ||||
| 428 | r = sd_bus_message_append_strv(m, matches); | |||
| 429 | if (r < 0) | |||
| 430 | return bus_log_create_error(r); | |||
| 431 | ||||
| 432 | r = sd_bus_message_append(m, "sbs", arg_profile, arg_runtime, arg_copy_mode); | |||
| 433 | if (r < 0) | |||
| 434 | return bus_log_create_error(r); | |||
| 435 | ||||
| 436 | r = sd_bus_call(bus, m, 0, &error, &reply); | |||
| 437 | if (r < 0) | |||
| 438 | return log_error_errno(r, "Failed to attach image: %s", bus_error_message(&error, r))({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 438, __func__, "Failed to attach image: %s" , bus_error_message(&error, r)) : -abs(_e); }); | |||
| 439 | ||||
| 440 | (void) maybe_reload(&bus); | |||
| 441 | ||||
| 442 | print_changes(reply); | |||
| 443 | return 0; | |||
| 444 | } | |||
| 445 | ||||
| 446 | static int detach_image(int argc, char *argv[], void *userdata) { | |||
| 447 | _cleanup_(sd_bus_message_unrefp)__attribute__((cleanup(sd_bus_message_unrefp))) sd_bus_message *reply = NULL((void*)0); | |||
| 448 | _cleanup_(sd_bus_error_free)__attribute__((cleanup(sd_bus_error_free))) sd_bus_error error = SD_BUS_ERROR_NULL((const sd_bus_error) {(((void*)0)), (((void*)0)), 0}); | |||
| 449 | _cleanup_(sd_bus_flush_close_unrefp)__attribute__((cleanup(sd_bus_flush_close_unrefp))) sd_bus *bus = NULL((void*)0); | |||
| 450 | _cleanup_free___attribute__((cleanup(freep))) char *image = NULL((void*)0); | |||
| 451 | int r; | |||
| 452 | ||||
| 453 | r = determine_image(argv[1], true1, &image); | |||
| 454 | if (r < 0) | |||
| 455 | return r; | |||
| 456 | ||||
| 457 | r = acquire_bus(&bus); | |||
| 458 | if (r < 0) | |||
| 459 | return r; | |||
| 460 | ||||
| 461 | (void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password); | |||
| 462 | ||||
| 463 | r = sd_bus_call_method( | |||
| 464 | bus, | |||
| 465 | "org.freedesktop.portable1", | |||
| 466 | "/org/freedesktop/portable1", | |||
| 467 | "org.freedesktop.portable1.Manager", | |||
| 468 | "DetachImage", | |||
| 469 | &error, | |||
| 470 | &reply, | |||
| 471 | "sb", image, arg_runtime); | |||
| 472 | if (r < 0) | |||
| 473 | return log_error_errno(r, "Failed to detach image: %s", bus_error_message(&error, r))({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 473, __func__, "Failed to detach image: %s" , bus_error_message(&error, r)) : -abs(_e); }); | |||
| 474 | ||||
| 475 | (void) maybe_reload(&bus); | |||
| 476 | ||||
| 477 | print_changes(reply); | |||
| 478 | return 0; | |||
| 479 | } | |||
| 480 | ||||
| 481 | static int list_images(int argc, char *argv[], void *userdata) { | |||
| 482 | _cleanup_(sd_bus_error_free)__attribute__((cleanup(sd_bus_error_free))) sd_bus_error error = SD_BUS_ERROR_NULL((const sd_bus_error) {(((void*)0)), (((void*)0)), 0}); | |||
| 483 | _cleanup_(sd_bus_message_unrefp)__attribute__((cleanup(sd_bus_message_unrefp))) sd_bus_message *reply = NULL((void*)0); | |||
| 484 | _cleanup_(sd_bus_flush_close_unrefp)__attribute__((cleanup(sd_bus_flush_close_unrefp))) sd_bus *bus = NULL((void*)0); | |||
| 485 | _cleanup_(table_unrefp)__attribute__((cleanup(table_unrefp))) Table *table = NULL((void*)0); | |||
| 486 | int r; | |||
| 487 | ||||
| 488 | r = acquire_bus(&bus); | |||
| 489 | if (r < 0) | |||
| 490 | return r; | |||
| 491 | ||||
| 492 | r = sd_bus_call_method( | |||
| 493 | bus, | |||
| 494 | "org.freedesktop.portable1", | |||
| 495 | "/org/freedesktop/portable1", | |||
| 496 | "org.freedesktop.portable1.Manager", | |||
| 497 | "ListImages", | |||
| 498 | &error, | |||
| 499 | &reply, | |||
| 500 | NULL((void*)0)); | |||
| 501 | if (r < 0) | |||
| 502 | return log_error_errno(r, "Failed to list images: %s", bus_error_message(&error, r))({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 502, __func__, "Failed to list images: %s" , bus_error_message(&error, r)) : -abs(_e); }); | |||
| 503 | ||||
| 504 | table = table_new("NAME", "TYPE", "RO", "CRTIME", "MTIME", "USAGE", "STATE")table_new_internal("NAME", "TYPE", "RO", "CRTIME", "MTIME", "USAGE" , "STATE", ((void*)0)); | |||
| 505 | if (!table) | |||
| 506 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/portable/portablectl.c" , 506, __func__); | |||
| 507 | ||||
| 508 | r = sd_bus_message_enter_container(reply, 'a', "(ssbtttso)"); | |||
| 509 | if (r < 0) | |||
| 510 | return bus_log_parse_error(r); | |||
| 511 | ||||
| 512 | for (;;) { | |||
| 513 | const char *name, *type, *state; | |||
| 514 | uint64_t crtime, mtime, usage; | |||
| 515 | TableCell *cell; | |||
| 516 | bool_Bool ro_bool; | |||
| 517 | int ro_int; | |||
| 518 | ||||
| 519 | r = sd_bus_message_read(reply, "(ssbtttso)", &name, &type, &ro_int, &crtime, &mtime, &usage, &state, NULL((void*)0)); | |||
| 520 | if (r < 0) | |||
| 521 | return bus_log_parse_error(r); | |||
| 522 | if (r == 0) | |||
| 523 | break; | |||
| 524 | ||||
| 525 | r = table_add_many(table,table_add_many_internal(table, TABLE_STRING, name, TABLE_STRING , type, _TABLE_DATA_TYPE_MAX) | |||
| 526 | TABLE_STRING, name,table_add_many_internal(table, TABLE_STRING, name, TABLE_STRING , type, _TABLE_DATA_TYPE_MAX) | |||
| 527 | TABLE_STRING, type)table_add_many_internal(table, TABLE_STRING, name, TABLE_STRING , type, _TABLE_DATA_TYPE_MAX); | |||
| 528 | if (r < 0) | |||
| 529 | return log_error_errno(r, "Failed to add row to table: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 529, __func__, "Failed to add row to table: %m" ) : -abs(_e); }); | |||
| 530 | ||||
| 531 | ro_bool = ro_int; | |||
| 532 | r = table_add_cell(table, &cell, TABLE_BOOLEAN, &ro_bool); | |||
| 533 | if (r < 0) | |||
| 534 | return log_error_errno(r, "Failed to add row to table: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 534, __func__, "Failed to add row to table: %m" ) : -abs(_e); }); | |||
| 535 | ||||
| 536 | if (ro_bool) { | |||
| 537 | r = table_set_color(table, cell, ansi_highlight_red()); | |||
| 538 | if (r < 0) | |||
| 539 | return log_error_errno(r, "Failed to set table cell color: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 539, __func__, "Failed to set table cell color: %m" ) : -abs(_e); }); | |||
| 540 | } | |||
| 541 | ||||
| 542 | r = table_add_many(table,table_add_many_internal(table, TABLE_TIMESTAMP, crtime, TABLE_TIMESTAMP , mtime, TABLE_SIZE, usage, _TABLE_DATA_TYPE_MAX) | |||
| 543 | TABLE_TIMESTAMP, crtime,table_add_many_internal(table, TABLE_TIMESTAMP, crtime, TABLE_TIMESTAMP , mtime, TABLE_SIZE, usage, _TABLE_DATA_TYPE_MAX) | |||
| 544 | TABLE_TIMESTAMP, mtime,table_add_many_internal(table, TABLE_TIMESTAMP, crtime, TABLE_TIMESTAMP , mtime, TABLE_SIZE, usage, _TABLE_DATA_TYPE_MAX) | |||
| 545 | TABLE_SIZE, usage)table_add_many_internal(table, TABLE_TIMESTAMP, crtime, TABLE_TIMESTAMP , mtime, TABLE_SIZE, usage, _TABLE_DATA_TYPE_MAX); | |||
| 546 | if (r < 0) | |||
| 547 | return log_error_errno(r, "Failed to add row to table: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 547, __func__, "Failed to add row to table: %m" ) : -abs(_e); }); | |||
| 548 | ||||
| 549 | r = table_add_cell(table, &cell, TABLE_STRING, state); | |||
| 550 | if (r < 0) | |||
| 551 | return log_error_errno(r, "Failed to add row to table: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 551, __func__, "Failed to add row to table: %m" ) : -abs(_e); }); | |||
| 552 | ||||
| 553 | if (!streq(state, "detached")(strcmp((state),("detached")) == 0)) { | |||
| 554 | r = table_set_color(table, cell, ansi_highlight_green()); | |||
| 555 | if (r < 0) | |||
| 556 | return log_error_errno(r, "Failed to set table cell color: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 556, __func__, "Failed to set table cell color: %m" ) : -abs(_e); }); | |||
| 557 | } | |||
| 558 | } | |||
| 559 | ||||
| 560 | r = sd_bus_message_exit_container(reply); | |||
| 561 | if (r < 0) | |||
| 562 | return bus_log_parse_error(r); | |||
| 563 | ||||
| 564 | if (table_get_rows(table) > 1) { | |||
| 565 | r = table_set_sort(table, (size_t) 0, (size_t) -1); | |||
| 566 | if (r < 0) | |||
| 567 | return log_error_errno(r, "Failed to sort table: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 567, __func__, "Failed to sort table: %m" ) : -abs(_e); }); | |||
| 568 | ||||
| 569 | table_set_header(table, arg_legend); | |||
| 570 | ||||
| 571 | r = table_print(table, NULL((void*)0)); | |||
| 572 | if (r < 0) | |||
| 573 | return log_error_errno(r, "Failed to show table: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 573, __func__, "Failed to show table: %m" ) : -abs(_e); }); | |||
| 574 | } | |||
| 575 | ||||
| 576 | if (arg_legend) { | |||
| 577 | if (table_get_rows(table) > 1) | |||
| 578 | printf("\n%zu images listed.\n", table_get_rows(table) - 1); | |||
| 579 | else | |||
| 580 | printf("No images.\n"); | |||
| 581 | } | |||
| 582 | ||||
| 583 | return 0; | |||
| 584 | } | |||
| 585 | ||||
| 586 | static int remove_image(int argc, char *argv[], void *userdata) { | |||
| 587 | _cleanup_(sd_bus_flush_close_unrefp)__attribute__((cleanup(sd_bus_flush_close_unrefp))) sd_bus *bus = NULL((void*)0); | |||
| 588 | int r, i; | |||
| 589 | ||||
| 590 | r = acquire_bus(&bus); | |||
| 591 | if (r < 0) | |||
| 592 | return r; | |||
| 593 | ||||
| 594 | (void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password); | |||
| 595 | ||||
| 596 | for (i = 1; i < argc; i++) { | |||
| 597 | _cleanup_(sd_bus_error_free)__attribute__((cleanup(sd_bus_error_free))) sd_bus_error error = SD_BUS_ERROR_NULL((const sd_bus_error) {(((void*)0)), (((void*)0)), 0}); | |||
| 598 | _cleanup_(sd_bus_message_unrefp)__attribute__((cleanup(sd_bus_message_unrefp))) sd_bus_message *m = NULL((void*)0); | |||
| 599 | ||||
| 600 | r = sd_bus_message_new_method_call( | |||
| 601 | bus, | |||
| 602 | &m, | |||
| 603 | "org.freedesktop.portable1", | |||
| 604 | "/org/freedesktop/portable1", | |||
| 605 | "org.freedesktop.portable1.Manager", | |||
| 606 | "RemoveImage"); | |||
| 607 | if (r < 0) | |||
| 608 | return bus_log_create_error(r); | |||
| 609 | ||||
| 610 | r = sd_bus_message_append(m, "s", argv[i]); | |||
| 611 | if (r < 0) | |||
| 612 | return bus_log_create_error(r); | |||
| 613 | ||||
| 614 | /* This is a slow operation, hence turn off any method call timeouts */ | |||
| 615 | r = sd_bus_call(bus, m, USEC_INFINITY((usec_t) -1), &error, NULL((void*)0)); | |||
| 616 | if (r < 0) | |||
| 617 | return log_error_errno(r, "Could not remove image: %s", bus_error_message(&error, r))({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 617, __func__, "Could not remove image: %s" , bus_error_message(&error, r)) : -abs(_e); }); | |||
| 618 | } | |||
| 619 | ||||
| 620 | return 0; | |||
| 621 | } | |||
| 622 | ||||
| 623 | static int read_only_image(int argc, char *argv[], void *userdata) { | |||
| 624 | _cleanup_(sd_bus_error_free)__attribute__((cleanup(sd_bus_error_free))) sd_bus_error error = SD_BUS_ERROR_NULL((const sd_bus_error) {(((void*)0)), (((void*)0)), 0}); | |||
| 625 | _cleanup_(sd_bus_flush_close_unrefp)__attribute__((cleanup(sd_bus_flush_close_unrefp))) sd_bus *bus = NULL((void*)0); | |||
| 626 | int b = true1, r; | |||
| 627 | ||||
| 628 | if (argc > 2) { | |||
| 629 | b = parse_boolean(argv[2]); | |||
| 630 | if (b < 0) | |||
| 631 | return log_error_errno(b, "Failed to parse boolean argument: %s", argv[2])({ int _level = ((3)), _e = ((b)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 631, __func__, "Failed to parse boolean argument: %s" , argv[2]) : -abs(_e); }); | |||
| 632 | } | |||
| 633 | ||||
| 634 | r = acquire_bus(&bus); | |||
| 635 | if (r < 0) | |||
| 636 | return r; | |||
| 637 | ||||
| 638 | (void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password); | |||
| 639 | ||||
| 640 | r = sd_bus_call_method( | |||
| 641 | bus, | |||
| 642 | "org.freedesktop.portable1", | |||
| 643 | "/org/freedesktop/portable1", | |||
| 644 | "org.freedesktop.portable1.Manager", | |||
| 645 | "MarkImageReadOnly", | |||
| 646 | &error, | |||
| 647 | NULL((void*)0), | |||
| 648 | "sb", argv[1], b); | |||
| 649 | if (r < 0) | |||
| 650 | return log_error_errno(r, "Could not mark image read-only: %s", bus_error_message(&error, r))({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 650, __func__, "Could not mark image read-only: %s" , bus_error_message(&error, r)) : -abs(_e); }); | |||
| 651 | ||||
| 652 | return 0; | |||
| 653 | } | |||
| 654 | ||||
| 655 | static int set_limit(int argc, char *argv[], void *userdata) { | |||
| 656 | _cleanup_(sd_bus_error_free)__attribute__((cleanup(sd_bus_error_free))) sd_bus_error error = SD_BUS_ERROR_NULL((const sd_bus_error) {(((void*)0)), (((void*)0)), 0}); | |||
| 657 | _cleanup_(sd_bus_flush_close_unrefp)__attribute__((cleanup(sd_bus_flush_close_unrefp))) sd_bus *bus = NULL((void*)0); | |||
| 658 | uint64_t limit; | |||
| 659 | int r; | |||
| 660 | ||||
| 661 | r = acquire_bus(&bus); | |||
| 662 | if (r < 0) | |||
| 663 | return r; | |||
| 664 | ||||
| 665 | (void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password); | |||
| 666 | ||||
| 667 | if (STR_IN_SET(argv[argc-1], "-", "none", "infinity")(!!strv_find((((char**) ((const char*[]) { "-", "none", "infinity" , ((void*)0) }))), (argv[argc-1])))) | |||
| 668 | limit = (uint64_t) -1; | |||
| 669 | else { | |||
| 670 | r = parse_size(argv[argc-1], 1024, &limit); | |||
| 671 | if (r < 0) | |||
| 672 | return log_error_errno(r, "Failed to parse size: %s", argv[argc-1])({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 672, __func__, "Failed to parse size: %s" , argv[argc-1]) : -abs(_e); }); | |||
| 673 | } | |||
| 674 | ||||
| 675 | if (argc > 2) | |||
| 676 | /* With two arguments changes the quota limit of the specified image */ | |||
| 677 | r = sd_bus_call_method( | |||
| 678 | bus, | |||
| 679 | "org.freedesktop.portable1", | |||
| 680 | "/org/freedesktop/portable1", | |||
| 681 | "org.freedesktop.portable1.Manager", | |||
| 682 | "SetImageLimit", | |||
| 683 | &error, | |||
| 684 | NULL((void*)0), | |||
| 685 | "st", argv[1], limit); | |||
| 686 | else | |||
| 687 | /* With one argument changes the pool quota limit */ | |||
| 688 | r = sd_bus_call_method( | |||
| 689 | bus, | |||
| 690 | "org.freedesktop.portable1", | |||
| 691 | "/org/freedesktop/portable1", | |||
| 692 | "org.freedesktop.portable1.Manager", | |||
| 693 | "SetPoolLimit", | |||
| 694 | &error, | |||
| 695 | NULL((void*)0), | |||
| 696 | "t", limit); | |||
| 697 | ||||
| 698 | if (r < 0) | |||
| 699 | return log_error_errno(r, "Could not set limit: %s", bus_error_message(&error, r))({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 699, __func__, "Could not set limit: %s" , bus_error_message(&error, r)) : -abs(_e); }); | |||
| 700 | ||||
| 701 | return 0; | |||
| 702 | } | |||
| 703 | ||||
| 704 | static int is_image_attached(int argc, char *argv[], void *userdata) { | |||
| 705 | _cleanup_(sd_bus_message_unrefp)__attribute__((cleanup(sd_bus_message_unrefp))) sd_bus_message *reply = NULL((void*)0); | |||
| 706 | _cleanup_(sd_bus_error_free)__attribute__((cleanup(sd_bus_error_free))) sd_bus_error error = SD_BUS_ERROR_NULL((const sd_bus_error) {(((void*)0)), (((void*)0)), 0}); | |||
| 707 | _cleanup_(sd_bus_flush_close_unrefp)__attribute__((cleanup(sd_bus_flush_close_unrefp))) sd_bus *bus = NULL((void*)0); | |||
| 708 | _cleanup_free___attribute__((cleanup(freep))) char *image = NULL((void*)0); | |||
| 709 | const char *state; | |||
| 710 | int r; | |||
| 711 | ||||
| 712 | r = determine_image(argv[1], true1, &image); | |||
| 713 | if (r < 0) | |||
| 714 | return r; | |||
| 715 | ||||
| 716 | r = acquire_bus(&bus); | |||
| 717 | if (r < 0) | |||
| 718 | return r; | |||
| 719 | ||||
| 720 | r = sd_bus_call_method( | |||
| 721 | bus, | |||
| 722 | "org.freedesktop.portable1", | |||
| 723 | "/org/freedesktop/portable1", | |||
| 724 | "org.freedesktop.portable1.Manager", | |||
| 725 | "GetImageState", | |||
| 726 | &error, | |||
| 727 | &reply, | |||
| 728 | "s", image); | |||
| 729 | if (r < 0) | |||
| 730 | return log_error_errno(r, "Failed to get image state: %s", bus_error_message(&error, r))({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 730, __func__, "Failed to get image state: %s" , bus_error_message(&error, r)) : -abs(_e); }); | |||
| 731 | ||||
| 732 | r = sd_bus_message_read(reply, "s", &state); | |||
| 733 | if (r < 0) | |||
| 734 | return r; | |||
| 735 | ||||
| 736 | if (!arg_quiet) | |||
| 737 | puts(state); | |||
| 738 | ||||
| 739 | return streq(state, "detached")(strcmp((state),("detached")) == 0); | |||
| 740 | } | |||
| 741 | ||||
| 742 | static int dump_profiles(void) { | |||
| 743 | _cleanup_(sd_bus_error_free)__attribute__((cleanup(sd_bus_error_free))) sd_bus_error error = SD_BUS_ERROR_NULL((const sd_bus_error) {(((void*)0)), (((void*)0)), 0}); | |||
| 744 | _cleanup_(sd_bus_flush_close_unrefp)__attribute__((cleanup(sd_bus_flush_close_unrefp))) sd_bus *bus = NULL((void*)0); | |||
| 745 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **l = NULL((void*)0); | |||
| 746 | char **i; | |||
| 747 | int r; | |||
| 748 | ||||
| 749 | r = acquire_bus(&bus); | |||
| 750 | if (r < 0) | |||
| 751 | return r; | |||
| 752 | ||||
| 753 | r = sd_bus_get_property_strv( | |||
| 754 | bus, | |||
| 755 | "org.freedesktop.portable1", | |||
| 756 | "/org/freedesktop/portable1", | |||
| 757 | "org.freedesktop.portable1.Manager", | |||
| 758 | "Profiles", | |||
| 759 | &error, | |||
| 760 | &l); | |||
| 761 | if (r < 0) | |||
| 762 | return log_error_errno(r, "Failed to acquire list of profiles: %s", bus_error_message(&error, r))({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 762, __func__, "Failed to acquire list of profiles: %s" , bus_error_message(&error, r)) : -abs(_e); }); | |||
| 763 | ||||
| 764 | if (arg_legend) | |||
| 765 | log_info("Available unit profiles:")({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 765, __func__, "Available unit profiles:" ) : -abs(_e); }); | |||
| 766 | ||||
| 767 | STRV_FOREACH(i, l)for ((i) = (l); (i) && *(i); (i)++) { | |||
| 768 | fputs(*i, stdoutstdout); | |||
| 769 | fputc('\n', stdoutstdout); | |||
| 770 | } | |||
| 771 | ||||
| 772 | return 0; | |||
| 773 | } | |||
| 774 | ||||
| 775 | static int help(int argc, char *argv[], void *userdata) { | |||
| 776 | ||||
| 777 | (void) pager_open(arg_no_pager, false0); | |||
| 778 | ||||
| 779 | printf("%s [OPTIONS...] {COMMAND} ...\n\n" | |||
| 780 | "Attach or detach portable services from the local system.\n\n" | |||
| 781 | " -h --help Show this help\n" | |||
| 782 | " --version Show package version\n" | |||
| 783 | " --no-pager Do not pipe output into a pager\n" | |||
| 784 | " --no-legend Do not show the headers and footers\n" | |||
| 785 | " --no-ask-password Do not ask for system passwords\n" | |||
| 786 | " -H --host=[USER@]HOST Operate on remote host\n" | |||
| 787 | " -M --machine=CONTAINER Operate on local container\n" | |||
| 788 | " -q --quiet Suppress informational messages\n" | |||
| 789 | " -p --profile=PROFILE Pick security profile for portable service\n" | |||
| 790 | " --copy=copy|auto|symlink Prefer copying or symlinks if possible\n" | |||
| 791 | " --runtime Attach portable service until next reboot only\n" | |||
| 792 | " --no-reload Don't reload the system and service manager\n" | |||
| 793 | " --cat When inspecting include unit and os-release file\n" | |||
| 794 | " contents\n\n" | |||
| 795 | "Commands:\n" | |||
| 796 | " list List available portable service images\n" | |||
| 797 | " attach NAME|PATH [PREFIX...]\n" | |||
| 798 | " Attach the specified portable service image\n" | |||
| 799 | " detach NAME|PATH Detach the specified portable service image\n" | |||
| 800 | " inspect NAME|PATH [PREFIX...]\n" | |||
| 801 | " Show details of specified portable service image\n" | |||
| 802 | " is-attached NAME|PATH Query if portable service image is attached\n" | |||
| 803 | " read-only NAME|PATH [BOOL] Mark or unmark portable service image read-only\n" | |||
| 804 | " remove NAME|PATH... Remove a portable service image\n" | |||
| 805 | " set-limit [NAME|PATH] Set image or pool size limit (disk quota)\n" | |||
| 806 | , program_invocation_short_name); | |||
| 807 | ||||
| 808 | return 0; | |||
| 809 | } | |||
| 810 | ||||
| 811 | static int parse_argv(int argc, char *argv[]) { | |||
| 812 | ||||
| 813 | enum { | |||
| 814 | ARG_VERSION = 0x100, | |||
| 815 | ARG_NO_PAGER, | |||
| 816 | ARG_NO_LEGEND, | |||
| 817 | ARG_NO_ASK_PASSWORD, | |||
| 818 | ARG_COPY, | |||
| 819 | ARG_RUNTIME, | |||
| 820 | ARG_NO_RELOAD, | |||
| 821 | ARG_CAT, | |||
| 822 | }; | |||
| 823 | ||||
| 824 | static const struct option options[] = { | |||
| 825 | { "help", no_argument0, NULL((void*)0), 'h' }, | |||
| 826 | { "version", no_argument0, NULL((void*)0), ARG_VERSION }, | |||
| 827 | { "no-pager", no_argument0, NULL((void*)0), ARG_NO_PAGER }, | |||
| 828 | { "no-legend", no_argument0, NULL((void*)0), ARG_NO_LEGEND }, | |||
| 829 | { "no-ask-password", no_argument0, NULL((void*)0), ARG_NO_ASK_PASSWORD }, | |||
| 830 | { "host", required_argument1, NULL((void*)0), 'H' }, | |||
| 831 | { "machine", required_argument1, NULL((void*)0), 'M' }, | |||
| 832 | { "quiet", no_argument0, NULL((void*)0), 'q' }, | |||
| 833 | { "profile", required_argument1, NULL((void*)0), 'p' }, | |||
| 834 | { "copy", required_argument1, NULL((void*)0), ARG_COPY }, | |||
| 835 | { "runtime", no_argument0, NULL((void*)0), ARG_RUNTIME }, | |||
| 836 | { "no-reload", no_argument0, NULL((void*)0), ARG_NO_RELOAD }, | |||
| 837 | { "cat", no_argument0, NULL((void*)0), ARG_CAT }, | |||
| 838 | {} | |||
| 839 | }; | |||
| 840 | ||||
| 841 | assert(argc >= 0)do { if ((__builtin_expect(!!(!(argc >= 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("argc >= 0"), "../src/portable/portablectl.c" , 841, __PRETTY_FUNCTION__); } while (0); | |||
| 842 | assert(argv)do { if ((__builtin_expect(!!(!(argv)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("argv"), "../src/portable/portablectl.c" , 842, __PRETTY_FUNCTION__); } while (0); | |||
| 843 | ||||
| 844 | for (;;) { | |||
| 845 | int c; | |||
| 846 | ||||
| 847 | c = getopt_long(argc, argv, "hH:M:qp:", options, NULL((void*)0)); | |||
| 848 | if (c < 0) | |||
| 849 | break; | |||
| 850 | ||||
| 851 | switch (c) { | |||
| 852 | ||||
| 853 | case 'h': | |||
| 854 | help(0, NULL((void*)0), NULL((void*)0)); | |||
| 855 | return 0; | |||
| 856 | ||||
| 857 | case ARG_VERSION: | |||
| 858 | return version(); | |||
| 859 | ||||
| 860 | case ARG_NO_PAGER: | |||
| 861 | arg_no_pager = true1; | |||
| 862 | break; | |||
| 863 | ||||
| 864 | case ARG_NO_LEGEND: | |||
| 865 | arg_legend = false0; | |||
| 866 | break; | |||
| 867 | ||||
| 868 | case ARG_NO_ASK_PASSWORD: | |||
| 869 | arg_ask_password = false0; | |||
| 870 | break; | |||
| 871 | ||||
| 872 | case 'H': | |||
| 873 | arg_transport = BUS_TRANSPORT_REMOTE; | |||
| 874 | arg_host = optarg; | |||
| 875 | break; | |||
| 876 | ||||
| 877 | case 'M': | |||
| 878 | arg_transport = BUS_TRANSPORT_MACHINE; | |||
| 879 | arg_host = optarg; | |||
| 880 | break; | |||
| 881 | ||||
| 882 | case 'q': | |||
| 883 | arg_quiet = true1; | |||
| 884 | break; | |||
| 885 | ||||
| 886 | case 'p': | |||
| 887 | if (streq(optarg, "help")(strcmp((optarg),("help")) == 0)) | |||
| 888 | return dump_profiles(); | |||
| 889 | ||||
| 890 | if (!filename_is_valid(optarg)) { | |||
| 891 | log_error("Unit profile name not valid: %s", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 891, __func__, "Unit profile name not valid: %s" , optarg) : -abs(_e); }); | |||
| 892 | return -EINVAL22; | |||
| 893 | } | |||
| 894 | ||||
| 895 | arg_profile = optarg; | |||
| 896 | break; | |||
| 897 | ||||
| 898 | case ARG_COPY: | |||
| 899 | if (streq(optarg, "auto")(strcmp((optarg),("auto")) == 0)) | |||
| 900 | arg_copy_mode = NULL((void*)0); | |||
| 901 | else if (STR_IN_SET(optarg, "copy", "symlink")(!!strv_find((((char**) ((const char*[]) { "copy", "symlink", ((void*)0) }))), (optarg)))) | |||
| 902 | arg_copy_mode = optarg; | |||
| 903 | else if (streq(optarg, "help")(strcmp((optarg),("help")) == 0)) { | |||
| 904 | puts("auto\n" | |||
| 905 | "copy\n" | |||
| 906 | "symlink"); | |||
| 907 | return 0; | |||
| 908 | } else { | |||
| 909 | log_error("Failed to parse --copy= argument: %s", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/portable/portablectl.c", 909, __func__, "Failed to parse --copy= argument: %s" , optarg) : -abs(_e); }); | |||
| 910 | return -EINVAL22; | |||
| 911 | } | |||
| 912 | ||||
| 913 | break; | |||
| 914 | ||||
| 915 | case ARG_RUNTIME: | |||
| 916 | arg_runtime = true1; | |||
| 917 | break; | |||
| 918 | ||||
| 919 | case ARG_NO_RELOAD: | |||
| 920 | arg_reload = false0; | |||
| 921 | break; | |||
| 922 | ||||
| 923 | case ARG_CAT: | |||
| 924 | arg_cat = true1; | |||
| 925 | break; | |||
| 926 | ||||
| 927 | case '?': | |||
| 928 | return -EINVAL22; | |||
| 929 | ||||
| 930 | default: | |||
| 931 | assert_not_reached("Unhandled option")do { log_assert_failed_unreachable_realm(LOG_REALM_SYSTEMD, ( "Unhandled option"), "../src/portable/portablectl.c", 931, __PRETTY_FUNCTION__ ); } while (0); | |||
| 932 | } | |||
| 933 | } | |||
| 934 | ||||
| 935 | return 1; | |||
| 936 | } | |||
| 937 | ||||
| 938 | int main(int argc, char *argv[]) { | |||
| 939 | ||||
| 940 | static const Verb verbs[] = { | |||
| 941 | { "help", VERB_ANY((unsigned) -1), VERB_ANY((unsigned) -1), 0, help }, | |||
| 942 | { "list", VERB_ANY((unsigned) -1), 1, VERB_DEFAULT, list_images }, | |||
| 943 | { "attach", 2, VERB_ANY((unsigned) -1), 0, attach_image }, | |||
| 944 | { "detach", 2, 2, 0, detach_image }, | |||
| 945 | { "inspect", 2, VERB_ANY((unsigned) -1), 0, inspect_image }, | |||
| 946 | { "is-attached", 2, 2, 0, is_image_attached }, | |||
| 947 | { "read-only", 2, 3, 0, read_only_image }, | |||
| 948 | { "remove", 2, VERB_ANY((unsigned) -1), 0, remove_image }, | |||
| 949 | { "set-limit", 3, 3, 0, set_limit }, | |||
| 950 | {} | |||
| 951 | }; | |||
| 952 | ||||
| 953 | int r; | |||
| 954 | ||||
| 955 | log_parse_environment()log_parse_environment_realm(LOG_REALM_SYSTEMD); | |||
| 956 | log_open(); | |||
| 957 | ||||
| 958 | r = parse_argv(argc, argv); | |||
| 959 | if (r <= 0) | |||
| 960 | goto finish; | |||
| 961 | ||||
| 962 | r = dispatch_verb(argc, argv, verbs, NULL((void*)0)); | |||
| 963 | ||||
| 964 | finish: | |||
| 965 | pager_close(); | |||
| 966 | ||||
| 967 | return r < 0 ? EXIT_FAILURE1 : EXIT_SUCCESS0; | |||
| 968 | } |