X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fcore%2Fdbus-manager.c;h=747bcfcb9167d617d10c10b5785e2f84e47faa84;hp=859fa1a90699bc348881eb2c25dd567eff0307df;hb=05d3a176239c1dd67863c70a5b79d9bc14144ef6;hpb=bc2708414babc5c99bb8000e63c84e87606cc15d diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 859fa1a90..747bcfcb9 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -36,6 +36,7 @@ #include "path-util.h" #include "dbus-unit.h" #include "virt.h" +#include "env-util.h" #define BUS_MANAGER_INTERFACE_BEGIN \ " \n" @@ -106,6 +107,9 @@ " \n" \ " \n" \ " \n" \ + " \n" \ + " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ @@ -124,6 +128,9 @@ " \n" \ " \n" \ " \n" \ + " \n" \ + " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ @@ -145,8 +152,8 @@ " \n" \ " \n" \ " \n" \ - " \n" \ - " \n" \ + " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ @@ -194,6 +201,25 @@ " \n" \ " \n" \ " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ " \n" #define BUS_MANAGER_INTERFACE_SIGNALS \ @@ -224,7 +250,10 @@ " \n" \ " \n" \ " " \ - " \n" + " \n" \ + " \n" \ + " \n" \ + " " #define BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \ " \n" \ @@ -242,6 +271,18 @@ " \n" \ " \n" \ " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ " \n" \ " \n" \ " \n" \ @@ -253,12 +294,10 @@ " \n" \ " \n" \ " \n" \ - " \n" \ - " \n" \ " \n" \ " \n" \ - " \n" \ - " \n" \ + " \n" \ + " \n" \ " \n" #define BUS_MANAGER_INTERFACE_END \ @@ -286,7 +325,7 @@ BUS_GENERIC_INTERFACES_LIST \ "org.freedesktop.systemd1.Manager\0" -const char bus_manager_interface[] _introspect_("Manager") = BUS_MANAGER_INTERFACE; +const char bus_manager_interface[] = BUS_MANAGER_INTERFACE; static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_exec_output, exec_output, ExecOutput); @@ -351,7 +390,7 @@ static int bus_manager_set_log_target(DBusMessageIter *i, const char *property, } static int bus_manager_append_log_level(DBusMessageIter *i, const char *property, void *data) { - char *t; + _cleanup_free_ char *t = NULL; int r; assert(i); @@ -364,7 +403,6 @@ static int bus_manager_append_log_level(DBusMessageIter *i, const char *property if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t)) r = -ENOMEM; - free(t); return r; } @@ -432,7 +470,7 @@ static int bus_manager_append_progress(DBusMessageIter *i, const char *property, static int bus_manager_append_virt(DBusMessageIter *i, const char *property, void *data) { Manager *m = data; - const char *id = ""; + const char *id = NULL; assert(i); assert(property); @@ -440,6 +478,8 @@ static int bus_manager_append_virt(DBusMessageIter *i, const char *property, voi detect_virtualization(&id); + if (!id) + id = ""; if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &id)) return -ENOMEM; @@ -547,6 +587,18 @@ static const BusProperty bus_manager_properties[] = { { "UserspaceTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.monotonic) }, { "FinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.realtime) }, { "FinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.monotonic) }, + { "SecurityStartTimestamp", bus_property_append_uint64, "t", offsetof(Manager, security_start_timestamp.realtime) }, + { "SecurityStartTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, security_start_timestamp.monotonic) }, + { "SecurityFinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, security_finish_timestamp.realtime) }, + { "SecurityFinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, security_finish_timestamp.monotonic) }, + { "GeneratorsStartTimestamp", bus_property_append_uint64, "t", offsetof(Manager, generators_start_timestamp.realtime) }, + { "GeneratorsStartTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, generators_start_timestamp.monotonic) }, + { "GeneratorsFinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, generators_finish_timestamp.realtime) }, + { "GeneratorsFinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, generators_finish_timestamp.monotonic) }, + { "UnitsLoadStartTimestamp", bus_property_append_uint64, "t", offsetof(Manager, unitsload_start_timestamp.realtime) }, + { "UnitsLoadStartTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, unitsload_start_timestamp.monotonic) }, + { "UnitsLoadFinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, unitsload_finish_timestamp.realtime) }, + { "UnitsLoadFinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, unitsload_finish_timestamp.monotonic) }, { "LogLevel", bus_manager_append_log_level, "s", 0, false, bus_manager_set_log_level }, { "LogTarget", bus_manager_append_log_target, "s", 0, false, bus_manager_set_log_target }, { "NNames", bus_manager_append_n_names, "u", 0 }, @@ -558,8 +610,6 @@ static const BusProperty bus_manager_properties[] = { { "ConfirmSpawn", bus_property_append_bool, "b", offsetof(Manager, confirm_spawn) }, { "ShowStatus", bus_property_append_bool, "b", offsetof(Manager, show_status) }, { "UnitPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.unit_path), true }, - { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_hierarchy), true }, - { "DefaultControllers", bus_property_append_strv, "as", offsetof(Manager, default_controllers), true }, { "DefaultStandardOutput", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_output) }, { "DefaultStandardError", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_error) }, { "RuntimeWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, runtime_watchdog), false, bus_manager_set_runtime_watchdog_usec }, @@ -629,7 +679,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBUS_TYPE_INVALID)) return bus_send_error_reply(connection, message, &error, -EINVAL); - u = cgroup_unit_by_pid(m, (pid_t) pid); + u = manager_get_unit_by_pid(m, (pid_t) pid); if (!u) { dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid); return bus_send_error_reply(connection, message, &error, -ENOENT); @@ -774,10 +824,33 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBUS_TYPE_INVALID)) goto oom; + } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CancelJob")) { + uint32_t id; + Job *j; + + if (!dbus_message_get_args( + message, + &error, + DBUS_TYPE_UINT32, &id, + DBUS_TYPE_INVALID)) + return bus_send_error_reply(connection, message, &error, -EINVAL); + + j = manager_get_job(m, id); + if (!j) { + dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id); + return bus_send_error_reply(connection, message, &error, -ENOENT); + } + + SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "stop"); + job_finish_and_invalidate(j, JOB_CANCELED, true); + + reply = dbus_message_new_method_return(message); + if (!reply) + goto oom; + } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) { SELINUX_ACCESS_CHECK(connection, message, "reboot"); - manager_clear_jobs(m); reply = dbus_message_new_method_return(message); @@ -969,27 +1042,17 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, SELINUX_ACCESS_CHECK(connection, message, "status"); - s = BUS_CONNECTION_SUBSCRIBED(m, connection); - if (!s) { - s = set_new(string_hash_func, string_compare_func); - if (!s) - goto oom; - - if (!dbus_connection_set_data(connection, m->subscribed_data_slot, s, NULL)) { - set_free(s); - goto oom; - } - } + s = bus_acquire_subscribed(m, connection); + if (!s) + goto oom; client = strdup(bus_message_get_sender_with_fallback(message)); if (!client) goto oom; - r = set_put(s, client); - if (r < 0) { - free(client); + r = set_consume(s, client); + if (r < 0) return bus_send_error_reply(connection, message, NULL, r); - } reply = dbus_message_new_method_return(message); if (!reply) @@ -1080,8 +1143,37 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBUS_TYPE_INVALID)) goto oom; + } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RemoveSnapshot")) { + const char *name; + Unit *u; + + if (!dbus_message_get_args( + message, + &error, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_INVALID)) + return bus_send_error_reply(connection, message, &error, -EINVAL); + + u = manager_get_unit(m, name); + if (!u) { + dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s does not exist.", name); + return bus_send_error_reply(connection, message, &error, -ENOENT); + } + + if (u->type != UNIT_SNAPSHOT) { + dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not a snapshot.", name); + return bus_send_error_reply(connection, message, &error, -ENOENT); + } + + SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop"); + snapshot_remove(SNAPSHOT(u)); + + reply = dbus_message_new_method_return(message); + if (!reply) + goto oom; + } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) { - char *introspection = NULL; + _cleanup_free_ char *introspection = NULL; FILE *f; Iterator i; Unit *u; @@ -1107,7 +1199,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, fputs(INTROSPECTION_BEGIN, f); HASHMAP_FOREACH_KEY(u, k, m->units, i) { - char *p; + _cleanup_free_ char *p = NULL; if (k != u->id) continue; @@ -1115,12 +1207,10 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, p = bus_path_escape(k); if (!p) { fclose(f); - free(introspection); goto oom; } fprintf(f, "", p); - free(p); } HASHMAP_FOREACH(j, m->jobs, i) @@ -1130,7 +1220,6 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, if (ferror(f)) { fclose(f); - free(introspection); goto oom; } @@ -1140,12 +1229,8 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, goto oom; if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) { - free(introspection); goto oom; } - - free(introspection); - } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) { SELINUX_ACCESS_CHECK(connection, message, "reload"); @@ -1251,7 +1336,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SwitchRoot")) { const char *switch_root, *switch_root_init; char *u, *v; - int k; + bool good; SELINUX_ACCESS_CHECK(connection, message, "reboot"); @@ -1275,20 +1360,24 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, } /* Safety check */ - if (isempty(switch_root_init)) - k = access(switch_root, F_OK); + if (isempty(switch_root_init)) { + good = path_is_os_tree(switch_root); + if (!good) + log_error("Not switching root: %s does not seem to be an OS tree. /etc/os-release is missing.", switch_root); + } else { - char *p; + _cleanup_free_ char *p = NULL; p = strjoin(switch_root, "/", switch_root_init, NULL); if (!p) goto oom; - k = access(p, X_OK); - free(p); + good = access(p, X_OK) >= 0; + if (!good) + log_error("Not switching root: cannot execute new init %s", p); } - if (k < 0) - return bus_send_error_reply(connection, message, NULL, -errno); + if (!good) + return bus_send_error_reply(connection, message, NULL, -EINVAL); u = strdup(switch_root); if (!u) @@ -1315,18 +1404,20 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, m->exit_code = MANAGER_SWITCH_ROOT; } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) { - char **l = NULL, **e = NULL; + _cleanup_strv_free_ char **l = NULL; + char **e = NULL; - SELINUX_ACCESS_CHECK(connection, message, "reboot"); + SELINUX_ACCESS_CHECK(connection, message, "reload"); r = bus_parse_strv(message, &l); if (r == -ENOMEM) goto oom; if (r < 0) return bus_send_error_reply(connection, message, NULL, r); + if (!strv_env_is_valid(l)) + return bus_send_error_reply(connection, message, NULL, -EINVAL); e = strv_env_merge(2, m->environment, l); - strv_free(l); if (!e) goto oom; @@ -1340,19 +1431,20 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, m->environment = e; } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) { - char **l = NULL, **e = NULL; + _cleanup_strv_free_ char **l = NULL; + char **e = NULL; - SELINUX_ACCESS_CHECK(connection, message, "reboot"); + SELINUX_ACCESS_CHECK(connection, message, "reload"); r = bus_parse_strv(message, &l); if (r == -ENOMEM) goto oom; if (r < 0) return bus_send_error_reply(connection, message, NULL, r); + if (!strv_env_name_or_assignment_is_valid(l)) + return bus_send_error_reply(connection, message, NULL, -EINVAL); e = strv_env_delete(m->environment, 1, l); - strv_free(l); - if (!e) goto oom; @@ -1366,10 +1458,11 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, m->environment = e; } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) { - char **l_set = NULL, **l_unset = NULL, **e = NULL, **f = NULL; + _cleanup_strv_free_ char **l_set = NULL, **l_unset = NULL, **e = NULL; + char **f = NULL; DBusMessageIter iter; - SELINUX_ACCESS_CHECK(connection, message, "reboot"); + SELINUX_ACCESS_CHECK(connection, message, "reload"); if (!dbus_message_iter_init(message, &iter)) goto oom; @@ -1379,33 +1472,25 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, goto oom; if (r < 0) return bus_send_error_reply(connection, message, NULL, r); + if (!strv_env_name_or_assignment_is_valid(l_unset)) + return bus_send_error_reply(connection, message, NULL, -EINVAL); - if (!dbus_message_iter_next(&iter)) { - strv_free(l_unset); + if (!dbus_message_iter_next(&iter)) return bus_send_error_reply(connection, message, NULL, -EINVAL); - } r = bus_parse_strv_iter(&iter, &l_set); - if (r < 0) { - strv_free(l_unset); - if (r == -ENOMEM) - goto oom; - + if (r == -ENOMEM) + goto oom; + if (r < 0) return bus_send_error_reply(connection, message, NULL, r); - } + if (!strv_env_is_valid(l_set)) + return bus_send_error_reply(connection, message, NULL, -EINVAL); e = strv_env_delete(m->environment, 1, l_unset); - strv_free(l_unset); - - if (!e) { - strv_free(l_set); + if (!e) goto oom; - } f = strv_env_merge(2, e, l_set); - strv_free(l_set); - strv_free(e); - if (!f) goto oom; @@ -1500,7 +1585,8 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") || dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") || dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") || - dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles")) { + dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles") || + dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetDefaultTarget")) { char **l = NULL; DBusMessageIter iter; @@ -1543,6 +1629,8 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, carries_install_info = r; } else if (streq(member, "MaskUnitFiles")) r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes); + else if (streq(member, "SetDefaultTarget")) + r = unit_file_set_default(scope, NULL, l[0], &changes, &n_changes); else assert_not_reached("Uh? Wrong method"); @@ -1610,6 +1698,111 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, if (!reply) goto oom; + } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetDefaultTarget")) { + UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; + _cleanup_free_ char *default_target = NULL; + + reply = dbus_message_new_method_return(message); + if (!reply) + goto oom; + + r = unit_file_get_default(scope, NULL, &default_target); + if (r < 0) + return bus_send_error_reply(connection, message, NULL, r); + + if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &default_target, DBUS_TYPE_INVALID)) { + goto oom; + } + + } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetUnitProperties")) { + DBusMessageIter iter; + dbus_bool_t runtime; + const char *name; + Unit *u; + + if (!dbus_message_iter_init(message, &iter)) + goto oom; + + if (bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true) < 0 || + bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0) + return bus_send_error_reply(connection, message, NULL, -EINVAL); + + u = manager_get_unit(m, name); + if (!u) { + dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name); + return bus_send_error_reply(connection, message, &error, -ENOENT); + } + + SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start"); + + r = bus_unit_set_properties(u, &iter, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, &error); + if (r < 0) + return bus_send_error_reply(connection, message, &error, r); + + reply = dbus_message_new_method_return(message); + if (!reply) + goto oom; + + } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartTransientUnit")) { + const char *name, *smode; + DBusMessageIter iter; + JobMode mode; + UnitType t; + Unit *u; + + if (!dbus_message_iter_init(message, &iter)) + goto oom; + + if (bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true) < 0 || + bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &smode, true) < 0) + return bus_send_error_reply(connection, message, NULL, -EINVAL); + + t = unit_name_to_type(name); + if (t < 0) + return bus_send_error_reply(connection, message, NULL, -EINVAL); + if (!unit_vtable[t]->can_transient) { + dbus_set_error(&error, DBUS_ERROR_INVALID_ARGS, "Unit type %s does not support transient units.", unit_type_to_string(t)); + return bus_send_error_reply(connection, message, &error, -EINVAL); + } + + mode = job_mode_from_string(smode); + if (mode < 0) { + dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode); + return bus_send_error_reply(connection, message, &error, -EINVAL); + } + + r = manager_load_unit(m, name, NULL, NULL, &u); + if (r < 0) + return bus_send_error_reply(connection, message, &error, r); + + SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start"); + + if (u->load_state != UNIT_NOT_FOUND || set_size(u->dependencies[UNIT_REFERENCED_BY]) > 0) { + dbus_set_error(&error, BUS_ERROR_UNIT_EXISTS, "Unit %s already exists.", name); + return bus_send_error_reply(connection, message, &error, -EEXIST); + } + + /* OK, the unit failed to load and is unreferenced, + * now let's fill in the transient data instead */ + r = unit_make_transient(u); + if (r < 0) + return bus_send_error_reply(connection, message, &error, r); + + /* Set our properties */ + r = bus_unit_set_properties(u, &iter, UNIT_RUNTIME, false, &error); + if (r < 0) + return bus_send_error_reply(connection, message, &error, r); + + /* And load this stub fully */ + r = unit_load(u); + if (r < 0) + return bus_send_error_reply(connection, message, &error, r); + + manager_dispatch_load_queue(m); + + /* Finally, start it */ + return bus_unit_queue_job(connection, message, u, JOB_START, mode, false); + } else { const BusBoundProperties bps[] = { { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string }, @@ -1668,7 +1861,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, } if (reply) - if (!dbus_connection_send(connection, reply, NULL)) + if (!bus_maybe_send_reply(connection, message, reply)) goto oom; return DBUS_HANDLER_RESULT_HANDLED;