static int set_locale(int argc, char **argv, void *userdata) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus = userdata; int r; assert(bus); polkit_agent_open_if_enabled(arg_transport, arg_ask_password); r = sd_bus_message_new_method_call( bus, &m, "org.freedesktop.locale1", "/org/freedesktop/locale1", "org.freedesktop.locale1", "SetLocale"); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_append_strv(m, argv + 1); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_append(m, "b", arg_ask_password); if (r < 0) return bus_log_create_error(r); r = sd_bus_call(bus, m, 0, &error, NULL); if (r < 0) return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, -r)); return 0; }
static int set_locale(sd_bus *bus, char **args, unsigned n) { _cleanup_bus_message_unref_ sd_bus_message *m = NULL; _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(bus); assert(args); polkit_agent_open_if_enabled(); r = sd_bus_message_new_method_call(bus, "org.freedesktop.locale1", "/org/freedesktop/locale1", "org.freedesktop.locale1", "SetLocale", &m); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_append_strv(m, args + 1); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_append(m, "b", arg_ask_password); if (r < 0) return bus_log_create_error(r); r = sd_bus_call(bus, m, 0, &error, NULL); if (r < 0) { log_error("Failed to issue method call: %s", bus_error_message(&error, -r)); return r; } return 0; }
static int attach_image(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_strv_free_ char **matches = NULL; _cleanup_free_ char *image = NULL; int r; r = determine_image(argv[1], false, &image); if (r < 0) return r; r = determine_matches(argv[1], argv + 2, false, &matches); if (r < 0) return r; r = acquire_bus(&bus); if (r < 0) return r; (void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password); r = sd_bus_message_new_method_call( bus, &m, "org.freedesktop.portable1", "/org/freedesktop/portable1", "org.freedesktop.portable1.Manager", "AttachImage"); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_append(m, "s", image); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_append_strv(m, matches); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_append(m, "sbs", arg_profile, arg_runtime, arg_copy_mode); if (r < 0) return bus_log_create_error(r); r = sd_bus_call(bus, m, 0, &error, &reply); if (r < 0) return log_error_errno(r, "Failed to attach image: %s", bus_error_message(&error, r)); (void) maybe_reload(&bus); print_changes(reply); return 0; }
static int maybe_reload(sd_bus **bus) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; int r; if (!arg_reload) return 0; r = acquire_bus(bus); if (r < 0) return r; r = sd_bus_message_new_method_call( *bus, &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "Reload"); if (r < 0) return bus_log_create_error(r); /* Reloading the daemon may take long, hence set a longer timeout here */ r = sd_bus_call(*bus, m, DEFAULT_TIMEOUT_USEC * 2, &error, NULL); if (r < 0) return log_error_errno(r, "Failed to reload daemon: %s", bus_error_message(&error, r)); return 0; }
static int reload_manager(sd_bus *bus) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; int r; log_info("Reloading system manager configuration"); r = sd_bus_message_new_method_call( bus, &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "Reload"); if (r < 0) return bus_log_create_error(r); /* Note we use an extra-long timeout here. This is because a reload or reexec means generators are rerun which * are timed out after DEFAULT_TIMEOUT_USEC. Let's use twice that time here, so that the generators can have * their timeout, and for everything else there's the same time budget in place. */ r = sd_bus_call(bus, m, DEFAULT_TIMEOUT_USEC * 2, &error, NULL); if (r < 0) return log_error_errno(r, "Failed to reload daemon: %s", bus_error_message(&error, r)); return 0; }
static int remove_image(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; int r, i; r = acquire_bus(&bus); if (r < 0) return r; (void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password); for (i = 1; i < argc; i++) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; r = sd_bus_message_new_method_call( bus, &m, "org.freedesktop.portable1", "/org/freedesktop/portable1", "org.freedesktop.portable1.Manager", "RemoveImage"); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_append(m, "s", argv[i]); if (r < 0) return bus_log_create_error(r); /* This is a slow operation, hence turn off any method call timeouts */ r = sd_bus_call(bus, m, USEC_INFINITY, &error, NULL); if (r < 0) return log_error_errno(r, "Could not remove image: %s", bus_error_message(&error, r)); } return 0; }
static int append_controller_property(sd_bus *bus, sd_bus_message *m) { const char *unique; int r; assert(bus); assert(m); r = sd_bus_get_unique_name(bus, &unique); if (r < 0) return log_error_errno(r, "Failed to get unique name: %m"); r = sd_bus_message_append(m, "(sv)", "Controller", "s", unique); if (r < 0) return bus_log_create_error(r); return 0; }
static int append_machine_properties( sd_bus_message *m, CustomMount *mounts, unsigned n_mounts, int kill_signal, char **properties) { unsigned j; int r; assert(m); r = sd_bus_message_append(m, "(sv)", "DevicePolicy", "s", "closed"); if (r < 0) return bus_log_create_error(r); /* If you make changes here, also make sure to update [email protected], to keep the device policies in * sync regardless if we are run with or without the --keep-unit switch. */ r = sd_bus_message_append(m, "(sv)", "DeviceAllow", "a(ss)", 2, /* Allow the container to * access and create the API * device nodes, so that * PrivateDevices= in the * container can work * fine */ "/dev/net/tun", "rwm", /* Allow the container * access to ptys. However, * do not permit the * container to ever create * these device nodes. */ "char-pts", "rw"); if (r < 0) return bus_log_create_error(r); for (j = 0; j < n_mounts; j++) { CustomMount *cm = mounts + j; if (cm->type != CUSTOM_MOUNT_BIND) continue; r = is_device_node(cm->source); if (r == -ENOENT) { /* The bind source might only appear as the image is put together, hence don't complain */ log_debug_errno(r, "Bind mount source %s not found, ignoring: %m", cm->source); continue; } if (r < 0) return log_error_errno(r, "Failed to stat %s: %m", cm->source); if (r) { r = sd_bus_message_append(m, "(sv)", "DeviceAllow", "a(ss)", 1, cm->source, cm->read_only ? "r" : "rw"); if (r < 0) return log_error_errno(r, "Failed to append message arguments: %m"); } } if (kill_signal != 0) { r = sd_bus_message_append(m, "(sv)", "KillSignal", "i", kill_signal); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_append(m, "(sv)", "KillMode", "s", "mixed"); if (r < 0) return bus_log_create_error(r); } return 0; }
int allocate_scope( sd_bus *bus, const char *machine_name, pid_t pid, const char *slice, CustomMount *mounts, unsigned n_mounts, int kill_signal, char **properties) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL; _cleanup_free_ char *scope = NULL; const char *description, *object; int r; assert(bus); r = bus_wait_for_jobs_new(bus, &w); if (r < 0) return log_error_errno(r, "Could not watch job: %m"); r = unit_name_mangle_with_suffix(machine_name, UNIT_NAME_NOGLOB, ".scope", &scope); if (r < 0) return log_error_errno(r, "Failed to mangle scope name: %m"); r = sd_bus_message_new_method_call( bus, &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartTransientUnit"); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_append(m, "ss", scope, "fail"); if (r < 0) return bus_log_create_error(r); /* Properties */ r = sd_bus_message_open_container(m, 'a', "(sv)"); if (r < 0) return bus_log_create_error(r); description = strjoina("Container ", machine_name); r = sd_bus_message_append(m, "(sv)(sv)(sv)(sv)", "PIDs", "au", 1, pid, "Description", "s", description, "Delegate", "b", 1, "Slice", "s", isempty(slice) ? "machine.slice" : slice); if (r < 0) return bus_log_create_error(r); r = append_controller_property(bus, m); if (r < 0) return r; r = append_machine_properties( m, mounts, n_mounts, kill_signal, properties); if (r < 0) return r; r = bus_append_unit_property_assignment_many(m, UNIT_SCOPE, properties); if (r < 0) return r; r = sd_bus_message_close_container(m); if (r < 0) return bus_log_create_error(r); /* No auxiliary units */ r = sd_bus_message_append( m, "a(sa(sv))", 0); if (r < 0) return bus_log_create_error(r); r = sd_bus_call(bus, m, 0, &error, &reply); if (r < 0) { log_error("Failed to allocate scope: %s", bus_error_message(&error, r)); return r; } r = sd_bus_message_read(reply, "o", &object); if (r < 0) return bus_log_parse_error(r); r = bus_wait_for_jobs_one(w, object, false); if (r < 0) return r; return 0; }
int register_machine( sd_bus *bus, const char *machine_name, pid_t pid, const char *directory, sd_id128_t uuid, int local_ifindex, const char *slice, CustomMount *mounts, unsigned n_mounts, int kill_signal, char **properties, bool keep_unit, const char *service) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(bus); if (keep_unit) { r = sd_bus_call_method( bus, "org.freedesktop.machine1", "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", "RegisterMachineWithNetwork", &error, NULL, "sayssusai", machine_name, SD_BUS_MESSAGE_APPEND_ID128(uuid), service, "container", (uint32_t) pid, strempty(directory), local_ifindex > 0 ? 1 : 0, local_ifindex); } else { _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; r = sd_bus_message_new_method_call( bus, &m, "org.freedesktop.machine1", "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", "CreateMachineWithNetwork"); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_append( m, "sayssusai", machine_name, SD_BUS_MESSAGE_APPEND_ID128(uuid), service, "container", (uint32_t) pid, strempty(directory), local_ifindex > 0 ? 1 : 0, local_ifindex); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_open_container(m, 'a', "(sv)"); if (r < 0) return bus_log_create_error(r); if (!isempty(slice)) { r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice); if (r < 0) return bus_log_create_error(r); } r = append_controller_property(bus, m); if (r < 0) return r; r = append_machine_properties( m, mounts, n_mounts, kill_signal, properties); if (r < 0) return r; r = bus_append_unit_property_assignment_many(m, UNIT_SERVICE, properties); if (r < 0) return r; r = sd_bus_message_close_container(m); if (r < 0) return bus_log_create_error(r); r = sd_bus_call(bus, m, 0, &error, NULL); } if (r < 0) { log_error("Failed to register machine: %s", bus_error_message(&error, r)); return r; } return 0; }
static int locale_update_system_manager(Context *c, sd_bus *bus) { _cleanup_free_ char **l_unset = NULL; _cleanup_strv_free_ char **l_set = NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; sd_bus_error error = SD_BUS_ERROR_NULL; size_t c_set, c_unset; LocaleVariable p; int r; assert(bus); l_unset = new0(char*, _VARIABLE_LC_MAX); if (!l_unset) return log_oom(); l_set = new0(char*, _VARIABLE_LC_MAX); if (!l_set) return log_oom(); for (p = 0, c_set = 0, c_unset = 0; p < _VARIABLE_LC_MAX; p++) { const char *name; name = locale_variable_to_string(p); assert(name); if (isempty(c->locale[p])) l_unset[c_set++] = (char*) name; else { char *s; s = strjoin(name, "=", c->locale[p]); if (!s) return log_oom(); l_set[c_unset++] = s; } } assert(c_set + c_unset == _VARIABLE_LC_MAX); r = sd_bus_message_new_method_call(bus, &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment"); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_append_strv(m, l_unset); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_append_strv(m, l_set); if (r < 0) return bus_log_create_error(r); r = sd_bus_call(bus, m, 0, &error, NULL); if (r < 0) return log_error_errno(r, "Failed to update the manager environment: %s", bus_error_message(&error, r)); return 0; }
int register_machine( const char *machine_name, pid_t pid, const char *directory, sd_id128_t uuid, int local_ifindex, const char *slice, CustomMount *mounts, unsigned n_mounts, int kill_signal, char **properties, bool keep_unit) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; int r; r = sd_bus_default_system(&bus); if (r < 0) return log_error_errno(r, "Failed to open system bus: %m"); if (keep_unit) { r = sd_bus_call_method( bus, "org.freedesktop.machine1", "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", "RegisterMachineWithNetwork", &error, NULL, "sayssusai", machine_name, SD_BUS_MESSAGE_APPEND_ID128(uuid), "nspawn", "container", (uint32_t) pid, strempty(directory), local_ifindex > 0 ? 1 : 0, local_ifindex); } else { _cleanup_bus_message_unref_ sd_bus_message *m = NULL; char **i; unsigned j; r = sd_bus_message_new_method_call( bus, &m, "org.freedesktop.machine1", "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", "CreateMachineWithNetwork"); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_append( m, "sayssusai", machine_name, SD_BUS_MESSAGE_APPEND_ID128(uuid), "nspawn", "container", (uint32_t) pid, strempty(directory), local_ifindex > 0 ? 1 : 0, local_ifindex); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_open_container(m, 'a', "(sv)"); if (r < 0) return bus_log_create_error(r); if (!isempty(slice)) { r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice); if (r < 0) return bus_log_create_error(r); } r = sd_bus_message_append(m, "(sv)", "DevicePolicy", "s", "strict"); if (r < 0) return bus_log_create_error(r); /* If you make changes here, also make sure to update * [email protected], to keep the device * policies in sync regardless if we are run with or * without the --keep-unit switch. */ r = sd_bus_message_append(m, "(sv)", "DeviceAllow", "a(ss)", 9, /* Allow the container to * access and create the API * device nodes, so that * PrivateDevices= in the * container can work * fine */ "/dev/null", "rwm", "/dev/zero", "rwm", "/dev/full", "rwm", "/dev/random", "rwm", "/dev/urandom", "rwm", "/dev/tty", "rwm", "/dev/net/tun", "rwm", /* Allow the container * access to ptys. However, * do not permit the * container to ever create * these device nodes. */ "/dev/pts/ptmx", "rw", "char-pts", "rw"); if (r < 0) return bus_log_create_error(r); for (j = 0; j < n_mounts; j++) { CustomMount *cm = mounts + j; if (cm->type != CUSTOM_MOUNT_BIND) continue; r = is_device_node(cm->source); if (r < 0) return log_error_errno(r, "Failed to stat %s: %m", cm->source); if (r) { r = sd_bus_message_append(m, "(sv)", "DeviceAllow", "a(ss)", 1, cm->source, cm->read_only ? "r" : "rw"); if (r < 0) return log_error_errno(r, "Failed to append message arguments: %m"); } } if (kill_signal != 0) { r = sd_bus_message_append(m, "(sv)", "KillSignal", "i", kill_signal); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_append(m, "(sv)", "KillMode", "s", "mixed"); if (r < 0) return bus_log_create_error(r); } STRV_FOREACH(i, properties) { r = sd_bus_message_open_container(m, 'r', "sv"); if (r < 0) return bus_log_create_error(r); r = bus_append_unit_property_assignment(m, *i); if (r < 0) return r; r = sd_bus_message_close_container(m); if (r < 0) return bus_log_create_error(r); } r = sd_bus_message_close_container(m); if (r < 0) return bus_log_create_error(r); r = sd_bus_call(bus, m, 0, &error, NULL); }
static int resolve_host(sd_bus *bus, const char *name) { _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL; _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; const char *canonical = NULL; unsigned c = 0; int r, ifindex; uint64_t flags; assert(name); log_debug("Resolving %s (family %s, ifindex %i).", name, af_to_name(arg_family) ?: "*", arg_ifindex); r = sd_bus_message_new_method_call( bus, &req, "org.freedesktop.resolve1", "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager", "ResolveHostname"); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_set_auto_start(req, false); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_append(req, "isit", arg_ifindex, name, arg_family, arg_flags); if (r < 0) return bus_log_create_error(r); r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply); if (r < 0) { log_error("%s: resolve call failed: %s", name, bus_error_message(&error, r)); return r; } r = sd_bus_message_read(reply, "i", &ifindex); if (r < 0) return bus_log_parse_error(r); r = sd_bus_message_enter_container(reply, 'a', "(iay)"); if (r < 0) return bus_log_parse_error(r); while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) { const void *a; int family; size_t sz; _cleanup_free_ char *pretty = NULL; char ifname[IF_NAMESIZE] = ""; r = sd_bus_message_read(reply, "i", &family); if (r < 0) return bus_log_parse_error(r); r = sd_bus_message_read_array(reply, 'y', &a, &sz); if (r < 0) return bus_log_parse_error(r); r = sd_bus_message_exit_container(reply); if (r < 0) return bus_log_parse_error(r); if (!IN_SET(family, AF_INET, AF_INET6)) { log_debug("%s: skipping entry with family %d (%s)", name, family, af_to_name(family) ?: "unknown"); continue; } if (sz != FAMILY_ADDRESS_SIZE(family)) { log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown"); continue; }
static int start_transient_timer( sd_bus *bus, char **argv) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL; _cleanup_free_ char *timer = NULL, *service = NULL; const char *object = NULL; int r; assert(bus); assert(argv); r = bus_wait_for_jobs_new(bus, &w); if (r < 0) return log_oom(); if (arg_unit) { switch (unit_name_to_type(arg_unit)) { case UNIT_SERVICE: service = strdup(arg_unit); if (!service) return log_oom(); r = unit_name_change_suffix(service, ".timer", &timer); if (r < 0) return log_error_errno(r, "Failed to change unit suffix: %m"); break; case UNIT_TIMER: timer = strdup(arg_unit); if (!timer) return log_oom(); r = unit_name_change_suffix(timer, ".service", &service); if (r < 0) return log_error_errno(r, "Failed to change unit suffix: %m"); break; default: r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".service", &service); if (r < 0) return log_error_errno(r, "Failed to mangle unit name: %m"); r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".timer", &timer); if (r < 0) return log_error_errno(r, "Failed to mangle unit name: %m"); break; } } else { r = make_unit_name(bus, UNIT_SERVICE, &service); if (r < 0) return r; r = unit_name_change_suffix(service, ".timer", &timer); if (r < 0) return log_error_errno(r, "Failed to change unit suffix: %m"); } r = sd_bus_message_new_method_call( bus, &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartTransientUnit"); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password); if (r < 0) return bus_log_create_error(r); /* Name and Mode */ r = sd_bus_message_append(m, "ss", timer, "fail"); if (r < 0) return bus_log_create_error(r); /* Properties */ r = sd_bus_message_open_container(m, 'a', "(sv)"); if (r < 0) return bus_log_create_error(r); r = transient_timer_set_properties(m); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_close_container(m); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_open_container(m, 'a', "(sa(sv))"); if (r < 0) return bus_log_create_error(r); if (!strv_isempty(argv)) { r = sd_bus_message_open_container(m, 'r', "sa(sv)"); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_append(m, "s", service); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_open_container(m, 'a', "(sv)"); if (r < 0) return bus_log_create_error(r); r = transient_service_set_properties(m, argv, NULL); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_close_container(m); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_close_container(m); if (r < 0) return bus_log_create_error(r); } r = sd_bus_message_close_container(m); if (r < 0) return bus_log_create_error(r); polkit_agent_open_if_enabled(); r = sd_bus_call(bus, m, 0, &error, &reply); if (r < 0) { log_error("Failed to start transient timer unit: %s", bus_error_message(&error, -r)); return r; } r = sd_bus_message_read(reply, "o", &object); if (r < 0) return bus_log_parse_error(r); r = bus_wait_for_jobs_one(w, object, arg_quiet); if (r < 0) return r; if (!arg_quiet) { log_info("Running timer as unit: %s", timer); if (argv[0]) log_info("Will run service as unit: %s", service); } return 0; }
int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) { const char *eq, *field; int r; assert(m); assert(assignment); eq = strchr(assignment, '='); if (!eq) { log_error("Not an assignment: %s", assignment); return -EINVAL; } field = strndupa(assignment, eq - assignment); eq ++; if (streq(field, "CPUQuota")) { if (isempty(eq)) { r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec"); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_append(m, "v", "t", USEC_INFINITY); } else if (endswith(eq, "%")) { double percent; if (sscanf(eq, "%lf%%", &percent) != 1 || percent <= 0) { log_error("CPU quota '%s' invalid.", eq); return -EINVAL; } r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec"); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_append(m, "v", "t", (usec_t) percent * USEC_PER_SEC / 100); } else { log_error("CPU quota needs to be in percent."); return -EINVAL; } if (r < 0) return bus_log_create_error(r); return 0; } r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); if (r < 0) return bus_log_create_error(r); if (STR_IN_SET(field, "CPUAccounting", "MemoryAccounting", "BlockIOAccounting", "SendSIGHUP", "SendSIGKILL")) { r = parse_boolean(eq); if (r < 0) { log_error("Failed to parse boolean assignment %s.", assignment); return -EINVAL; } r = sd_bus_message_append(m, "v", "b", r); } else if (streq(field, "MemoryLimit")) { off_t bytes; r = parse_size(eq, 1024, &bytes); if (r < 0) { log_error("Failed to parse bytes specification %s", assignment); return -EINVAL; } r = sd_bus_message_append(m, "v", "t", (uint64_t) bytes); } else if (STR_IN_SET(field, "CPUShares", "BlockIOWeight")) { uint64_t u; r = safe_atou64(eq, &u); if (r < 0) { log_error("Failed to parse %s value %s.", field, eq); return -EINVAL; } r = sd_bus_message_append(m, "v", "t", u); } else if (STR_IN_SET(field, "User", "Group", "DevicePolicy", "KillMode")) r = sd_bus_message_append(m, "v", "s", eq); else if (streq(field, "DeviceAllow")) { if (isempty(eq)) r = sd_bus_message_append(m, "v", "a(ss)", 0); else { const char *path, *rwm, *e; e = strchr(eq, ' '); if (e) { path = strndupa(eq, e - eq); rwm = e+1; } else { path = eq; rwm = ""; } if (!path_startswith(path, "/dev")) { log_error("%s is not a device file in /dev.", path); return -EINVAL; } r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm); } } else if (STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) { if (isempty(eq)) r = sd_bus_message_append(m, "v", "a(st)", 0); else { const char *path, *bandwidth, *e; off_t bytes; e = strchr(eq, ' '); if (e) { path = strndupa(eq, e - eq); bandwidth = e+1; } else { log_error("Failed to parse %s value %s.", field, eq); return -EINVAL; } if (!path_startswith(path, "/dev")) { log_error("%s is not a device file in /dev.", path); return -EINVAL; } r = parse_size(bandwidth, 1000, &bytes); if (r < 0) { log_error("Failed to parse byte value %s.", bandwidth); return -EINVAL; } r = sd_bus_message_append(m, "v", "a(st)", 1, path, (uint64_t) bytes); } } else if (streq(field, "BlockIODeviceWeight")) { if (isempty(eq)) r = sd_bus_message_append(m, "v", "a(st)", 0); else { const char *path, *weight, *e; uint64_t u; e = strchr(eq, ' '); if (e) { path = strndupa(eq, e - eq); weight = e+1; } else { log_error("Failed to parse %s value %s.", field, eq); return -EINVAL; } if (!path_startswith(path, "/dev")) { log_error("%s is not a device file in /dev.", path); return -EINVAL; } r = safe_atou64(weight, &u); if (r < 0) { log_error("Failed to parse %s value %s.", field, weight); return -EINVAL; } r = sd_bus_message_append(m, "v", "a(st)", path, u); } } else if (rlimit_from_string(field) >= 0) { uint64_t rl; if (streq(eq, "infinity")) rl = (uint64_t) -1; else { r = safe_atou64(eq, &rl); if (r < 0) { log_error("Invalid resource limit: %s", eq); return -EINVAL; } } r = sd_bus_message_append(m, "v", "t", rl); } else if (streq(field, "Nice")) { int32_t i; r = safe_atoi32(eq, &i); if (r < 0) { log_error("Failed to parse %s value %s.", field, eq); return -EINVAL; } r = sd_bus_message_append(m, "v", "i", i); } else if (streq(field, "Environment")) { r = sd_bus_message_append(m, "v", "as", 1, eq); } else if (streq(field, "KillSignal")) { int sig; sig = signal_from_string_try_harder(eq); if (sig < 0) { log_error("Failed to parse %s value %s.", field, eq); return -EINVAL; } r = sd_bus_message_append(m, "v", "i", sig); } else { log_error("Unknown assignment %s.", assignment); return -EINVAL; } if (r < 0) return bus_log_create_error(r); return 0; }
static int inspect_image(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_strv_free_ char **matches = NULL; _cleanup_free_ char *image = NULL; bool nl = false, header = false; const void *data; const char *path; size_t sz; int r; r = determine_image(argv[1], false, &image); if (r < 0) return r; r = determine_matches(argv[1], argv + 2, true, &matches); if (r < 0) return r; r = acquire_bus(&bus); if (r < 0) return r; r = sd_bus_message_new_method_call( bus, &m, "org.freedesktop.portable1", "/org/freedesktop/portable1", "org.freedesktop.portable1.Manager", "GetImageMetadata"); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_append(m, "s", image); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_append_strv(m, matches); if (r < 0) return bus_log_create_error(r); r = sd_bus_call(bus, m, 0, &error, &reply); if (r < 0) return log_error_errno(r, "Failed to inspect image metadata: %s", bus_error_message(&error, r)); r = sd_bus_message_read(reply, "s", &path); if (r < 0) return bus_log_parse_error(r); r = sd_bus_message_read_array(reply, 'y', &data, &sz); if (r < 0) return bus_log_parse_error(r); (void) pager_open(arg_pager_flags); if (arg_cat) { printf("%s-- OS Release: --%s\n", ansi_highlight(), ansi_normal()); fwrite(data, sz, 1, stdout); fflush(stdout); nl = true; } else { _cleanup_free_ char *pretty_portable = NULL, *pretty_os = NULL; _cleanup_fclose_ FILE *f; f = fmemopen_unlocked((void*) data, sz, "re"); if (!f) return log_error_errno(errno, "Failed to open /etc/os-release buffer: %m"); r = parse_env_file(f, "/etc/os-release", "PORTABLE_PRETTY_NAME", &pretty_portable, "PRETTY_NAME", &pretty_os); if (r < 0) return log_error_errno(r, "Failed to parse /etc/os-release: %m"); printf("Image:\n\t%s\n" "Portable Service:\n\t%s\n" "Operating System:\n\t%s\n", path, strna(pretty_portable), strna(pretty_os)); } r = sd_bus_message_enter_container(reply, 'a', "{say}"); if (r < 0) return bus_log_parse_error(r); for (;;) { const char *name; r = sd_bus_message_enter_container(reply, 'e', "say"); if (r < 0) return bus_log_parse_error(r); if (r == 0) break; r = sd_bus_message_read(reply, "s", &name); if (r < 0) return bus_log_parse_error(r); r = sd_bus_message_read_array(reply, 'y', &data, &sz); if (r < 0) return bus_log_parse_error(r); if (arg_cat) { if (nl) fputc('\n', stdout); printf("%s-- Unit file: %s --%s\n", ansi_highlight(), name, ansi_normal()); fwrite(data, sz, 1, stdout); fflush(stdout); nl = true; } else { if (!header) { fputs("Unit files:\n", stdout); header = true; } fputc('\t', stdout); fputs(name, stdout); fputc('\n', stdout); } r = sd_bus_message_exit_container(reply); if (r < 0) return bus_log_parse_error(r); } r = sd_bus_message_exit_container(reply); if (r < 0) return bus_log_parse_error(r); return 0; }
static int start_transient_service( sd_bus *bus, char **argv, int *retval) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL; _cleanup_free_ char *service = NULL, *pty_path = NULL; _cleanup_close_ int master = -1; int r; assert(bus); assert(argv); assert(retval); if (arg_pty) { if (arg_transport == BUS_TRANSPORT_LOCAL) { master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NDELAY); if (master < 0) return log_error_errno(errno, "Failed to acquire pseudo tty: %m"); r = ptsname_malloc(master, &pty_path); if (r < 0) return log_error_errno(r, "Failed to determine tty name: %m"); if (unlockpt(master) < 0) return log_error_errno(errno, "Failed to unlock tty: %m"); } else if (arg_transport == BUS_TRANSPORT_MACHINE) { _cleanup_(sd_bus_unrefp) sd_bus *system_bus = NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *pty_reply = NULL; const char *s; r = sd_bus_default_system(&system_bus); if (r < 0) return log_error_errno(r, "Failed to connect to system bus: %m"); r = sd_bus_call_method(system_bus, "org.freedesktop.machine1", "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", "OpenMachinePTY", &error, &pty_reply, "s", arg_host); if (r < 0) { log_error("Failed to get machine PTY: %s", bus_error_message(&error, -r)); return r; } r = sd_bus_message_read(pty_reply, "hs", &master, &s); if (r < 0) return bus_log_parse_error(r); master = fcntl(master, F_DUPFD_CLOEXEC, 3); if (master < 0) return log_error_errno(errno, "Failed to duplicate master fd: %m"); pty_path = strdup(s); if (!pty_path) return log_oom(); } else assert_not_reached("Can't allocate tty via ssh"); } if (!arg_no_block) { r = bus_wait_for_jobs_new(bus, &w); if (r < 0) return log_error_errno(r, "Could not watch jobs: %m"); } if (arg_unit) { r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".service", &service); if (r < 0) return log_error_errno(r, "Failed to mangle unit name: %m"); } else { r = make_unit_name(bus, UNIT_SERVICE, &service); if (r < 0) return r; } r = sd_bus_message_new_method_call( bus, &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartTransientUnit"); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password); if (r < 0) return bus_log_create_error(r); /* Name and mode */ r = sd_bus_message_append(m, "ss", service, "fail"); if (r < 0) return bus_log_create_error(r); /* Properties */ r = sd_bus_message_open_container(m, 'a', "(sv)"); if (r < 0) return bus_log_create_error(r); r = transient_service_set_properties(m, argv, pty_path); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_close_container(m); if (r < 0) return bus_log_create_error(r); /* Auxiliary units */ r = sd_bus_message_append(m, "a(sa(sv))", 0); if (r < 0) return bus_log_create_error(r); polkit_agent_open_if_enabled(); r = sd_bus_call(bus, m, 0, &error, &reply); if (r < 0) return log_error_errno(r, "Failed to start transient service unit: %s", bus_error_message(&error, r)); if (w) { const char *object; r = sd_bus_message_read(reply, "o", &object); if (r < 0) return bus_log_parse_error(r); r = bus_wait_for_jobs_one(w, object, arg_quiet); if (r < 0) return r; } if (!arg_quiet) log_info("Running as unit: %s", service); if (arg_wait || master >= 0) { _cleanup_(run_context_free) RunContext c = {}; c.bus = sd_bus_ref(bus); r = sd_event_default(&c.event); if (r < 0) return log_error_errno(r, "Failed to get event loop: %m"); if (master >= 0) { assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGWINCH, SIGTERM, SIGINT, -1) >= 0); (void) sd_event_add_signal(c.event, NULL, SIGINT, NULL, NULL); (void) sd_event_add_signal(c.event, NULL, SIGTERM, NULL, NULL); if (!arg_quiet) log_info("Press ^] three times within 1s to disconnect TTY."); r = pty_forward_new(c.event, master, PTY_FORWARD_IGNORE_INITIAL_VHANGUP, &c.forward); if (r < 0) return log_error_errno(r, "Failed to create PTY forwarder: %m"); pty_forward_set_handler(c.forward, pty_forward_handler, &c); } if (arg_wait) { _cleanup_free_ char *path = NULL; const char *mt; path = unit_dbus_path_from_name(service); if (!path) return log_oom(); mt = strjoina("type='signal'," "sender='org.freedesktop.systemd1'," "path='", path, "'," "interface='org.freedesktop.DBus.Properties'," "member='PropertiesChanged'"); r = sd_bus_add_match(bus, &c.match, mt, on_properties_changed, &c); if (r < 0) return log_error_errno(r, "Failed to add properties changed signal."); r = sd_bus_attach_event(bus, c.event, 0); if (r < 0) return log_error_errno(r, "Failed to attach bus to event loop."); } r = sd_event_loop(c.event); if (r < 0) return log_error_errno(r, "Failed to run event loop: %m"); if (c.forward) { char last_char = 0; r = pty_forward_get_last_char(c.forward, &last_char); if (r >= 0 && !arg_quiet && last_char != '\n') fputc('\n', stdout); } if (!arg_quiet) { if (!isempty(c.result)) log_info("Finished with result: %s", strna(c.result)); if (c.exit_code == CLD_EXITED) log_info("Main processes terminated with: code=%s/status=%i", sigchld_code_to_string(c.exit_code), c.exit_status); else if (c.exit_code > 0) log_info("Main processes terminated with: code=%s/status=%s", sigchld_code_to_string(c.exit_code), signal_to_string(c.exit_status)); if (c.inactive_enter_usec > 0 && c.inactive_enter_usec != USEC_INFINITY && c.inactive_exit_usec > 0 && c.inactive_exit_usec != USEC_INFINITY && c.inactive_enter_usec > c.inactive_exit_usec) { char ts[FORMAT_TIMESPAN_MAX]; log_info("Service runtime: %s", format_timespan(ts, sizeof(ts), c.inactive_enter_usec - c.inactive_exit_usec, USEC_PER_MSEC)); } if (c.cpu_usage_nsec > 0 && c.cpu_usage_nsec != NSEC_INFINITY) { char ts[FORMAT_TIMESPAN_MAX]; log_info("CPU time consumed: %s", format_timespan(ts, sizeof(ts), (c.cpu_usage_nsec + NSEC_PER_USEC - 1) / NSEC_PER_USEC, USEC_PER_MSEC)); } } /* Try to propagate the service's return value */ if (c.result && STR_IN_SET(c.result, "success", "exit-code") && c.exit_code == CLD_EXITED) *retval = c.exit_status; else *retval = EXIT_FAILURE; } return 0; }
static int resolve_host(sd_bus *bus, const char *name) { _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL; _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; const char *canonical = NULL; char ifname[IF_NAMESIZE] = ""; unsigned c = 0; int r; uint64_t flags; usec_t ts; assert(name); if (arg_ifindex > 0 && !if_indextoname(arg_ifindex, ifname)) return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", arg_ifindex); log_debug("Resolving %s (family %s, interface %s).", name, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname); r = sd_bus_message_new_method_call( bus, &req, "org.freedesktop.resolve1", "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager", "ResolveHostname"); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_append(req, "isit", arg_ifindex, name, arg_family, arg_flags); if (r < 0) return bus_log_create_error(r); ts = now(CLOCK_MONOTONIC); r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply); if (r < 0) { log_error("%s: resolve call failed: %s", name, bus_error_message(&error, r)); return r; } ts = now(CLOCK_MONOTONIC) - ts; r = sd_bus_message_enter_container(reply, 'a', "(iiay)"); if (r < 0) return bus_log_parse_error(r); while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) { const void *a; size_t sz; _cleanup_free_ char *pretty = NULL; int ifindex, family; assert_cc(sizeof(int) == sizeof(int32_t)); r = sd_bus_message_read(reply, "ii", &ifindex, &family); if (r < 0) return bus_log_parse_error(r); r = sd_bus_message_read_array(reply, 'y', &a, &sz); if (r < 0) return bus_log_parse_error(r); r = sd_bus_message_exit_container(reply); if (r < 0) return bus_log_parse_error(r); if (!IN_SET(family, AF_INET, AF_INET6)) { log_debug("%s: skipping entry with family %d (%s)", name, family, af_to_name(family) ?: "unknown"); continue; } if (sz != FAMILY_ADDRESS_SIZE(family)) { log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown"); continue; }
static int start_transient_scope( sd_bus *bus, char **argv) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL; _cleanup_strv_free_ char **env = NULL, **user_env = NULL; _cleanup_free_ char *scope = NULL; const char *object = NULL; int r; assert(bus); assert(argv); r = bus_wait_for_jobs_new(bus, &w); if (r < 0) return log_oom(); if (arg_unit) { r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".scope", &scope); if (r < 0) return log_error_errno(r, "Failed to mangle scope name: %m"); } else { r = make_unit_name(bus, UNIT_SCOPE, &scope); if (r < 0) return r; } r = sd_bus_message_new_method_call( bus, &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartTransientUnit"); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password); if (r < 0) return bus_log_create_error(r); /* Name and Mode */ r = sd_bus_message_append(m, "ss", scope, "fail"); if (r < 0) return bus_log_create_error(r); /* Properties */ r = sd_bus_message_open_container(m, 'a', "(sv)"); if (r < 0) return bus_log_create_error(r); r = transient_scope_set_properties(m); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_close_container(m); if (r < 0) return bus_log_create_error(r); /* Auxiliary units */ r = sd_bus_message_append(m, "a(sa(sv))", 0); if (r < 0) return bus_log_create_error(r); polkit_agent_open_if_enabled(); r = sd_bus_call(bus, m, 0, &error, &reply); if (r < 0) { log_error("Failed to start transient scope unit: %s", bus_error_message(&error, -r)); return r; } if (arg_nice_set) { if (setpriority(PRIO_PROCESS, 0, arg_nice) < 0) return log_error_errno(errno, "Failed to set nice level: %m"); } if (arg_exec_group) { gid_t gid; r = get_group_creds(&arg_exec_group, &gid); if (r < 0) return log_error_errno(r, "Failed to resolve group %s: %m", arg_exec_group); if (setresgid(gid, gid, gid) < 0) return log_error_errno(errno, "Failed to change GID to " GID_FMT ": %m", gid); } if (arg_exec_user) { const char *home, *shell; uid_t uid; gid_t gid; r = get_user_creds(&arg_exec_user, &uid, &gid, &home, &shell); if (r < 0) return log_error_errno(r, "Failed to resolve user %s: %m", arg_exec_user); r = strv_extendf(&user_env, "HOME=%s", home); if (r < 0) return log_oom(); r = strv_extendf(&user_env, "SHELL=%s", shell); if (r < 0) return log_oom(); r = strv_extendf(&user_env, "USER=%s", arg_exec_user); if (r < 0) return log_oom(); r = strv_extendf(&user_env, "LOGNAME=%s", arg_exec_user); if (r < 0) return log_oom(); if (!arg_exec_group) { if (setresgid(gid, gid, gid) < 0) return log_error_errno(errno, "Failed to change GID to " GID_FMT ": %m", gid); } if (setresuid(uid, uid, uid) < 0) return log_error_errno(errno, "Failed to change UID to " UID_FMT ": %m", uid); } env = strv_env_merge(3, environ, user_env, arg_environment); if (!env) return log_oom(); r = sd_bus_message_read(reply, "o", &object); if (r < 0) return bus_log_parse_error(r); r = bus_wait_for_jobs_one(w, object, arg_quiet); if (r < 0) return r; if (!arg_quiet) log_info("Running scope as unit: %s", scope); execvpe(argv[0], argv, env); return log_error_errno(errno, "Failed to execute: %m"); }