[systemd-devel] [PATCH] systemctl: add command default-target

Vaclav Pavlin vpavlin at redhat.com
Fri May 17 06:14:15 PDT 2013


From: Václav Pavlín <vpavlin at redhat.com>

systemctl default-target NAME will set the default target.
If the NAME is not specified, the default target is printed out.
---
 man/systemctl.xml               | 11 ++++++
 shell-completion/bash/systemctl |  4 ++
 src/core/dbus-manager.c         | 15 +++++++-
 src/shared/install.c            | 82 +++++++++++++++++++++++++++++++++++++++++
 src/shared/install.h            |  2 +
 src/systemctl/systemctl.c       | 39 +++++++++++++++-----
 6 files changed, 142 insertions(+), 11 deletions(-)

diff --git a/man/systemctl.xml b/man/systemctl.xml
index 0afb0cc..459444b 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -998,6 +998,17 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
       </varlistentry>
 
       <varlistentry>
+        <term><command>default-target [<replaceable>NAME</replaceable>]</command></term>
+
+        <listitem>
+          <para>Set/get the default target to boot into. If
+           the name is specified the default.target is linked
+           to the unit file. If the command is used without the name,
+           current default.target is printed.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
         <term><command>load <replaceable>NAME</replaceable>...</command></term>
 
         <listitem>
diff --git a/shell-completion/bash/systemctl b/shell-completion/bash/systemctl
index 191b8d1..ff59dbc 100644
--- a/shell-completion/bash/systemctl
+++ b/shell-completion/bash/systemctl
@@ -137,6 +137,7 @@ _systemctl () {
                              show-environment suspend'
                      [NAME]='snapshot load'
                      [FILE]='link'
+                  [TARGETS]='default-target'
         )
 
         for ((i=0; $i <= $COMP_CWORD; i++)); do
@@ -210,6 +211,9 @@ _systemctl () {
         elif __contains_word "$verb" ${VERBS[FILE]}; then
                 comps=$( compgen -A file -- "$cur" )
                 compopt -o filenames
+        elif __contains_word "$verb" ${VERBS[TARGETS]}; then
+                comps=$( __systemctl $mode list-unit-files --type target --full --all \
+                        | { while read -r a b; do echo " $a"; done; } )
         fi
 
         COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index 56b02a1..22449c5 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -227,6 +227,13 @@
         "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
         "   <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n"      \
         "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
+        "  </method>\n"                                                 \
+        "  <method name=\"SetDefaultTarget\">\n"                         \
+        "   <arg name=\"files\" type=\"as\" direction=\"in\"/>\n"       \
+        "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
+        "  </method>\n"                                                 \
+        "  <method name=\"GetDefaultTarget\">\n"                         \
+        "   <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
         "  </method>\n"
 
 #define BUS_MANAGER_INTERFACE_SIGNALS                                   \
@@ -1728,7 +1735,9 @@ 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") ||
+                   dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetDefaultTarget")) {
 
                 char **l = NULL;
                 DBusMessageIter iter;
@@ -1771,6 +1780,10 @@ 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 if (streq(member, "GetDefaultTarget"))
+                        r = unit_file_get_default(scope, NULL, &changes, &n_changes);
                 else
                         assert_not_reached("Uh? Wrong method");
 
diff --git a/src/shared/install.c b/src/shared/install.c
index edf4d2a..a411e62 100644
--- a/src/shared/install.c
+++ b/src/shared/install.c
@@ -1570,6 +1570,88 @@ int unit_file_reenable(
         return r;
 }
 
+int unit_file_set_default(
+                UnitFileScope scope,
+                const char *root_dir,
+                char *file,
+                UnitFileChange **changes,
+                unsigned *n_changes) {
+
+        _cleanup_lookup_paths_free_ LookupPaths paths = {};
+        _cleanup_install_context_done_ InstallContext c = {};
+        _cleanup_free_ char *config_path = NULL;
+        _cleanup_free_ char *path = NULL;
+        int r;
+        const char *e = NULL;
+        InstallInfo *i = NULL;
+
+        assert(scope >= 0);
+        assert(scope < _UNIT_FILE_SCOPE_MAX);
+
+
+        e = strrchr(file, '.');
+        if (unit_type_from_string(e + 1) != UNIT_TARGET)
+                return -EINVAL;
+
+        r = lookup_paths_init_from_scope(&paths, scope);
+        if (r < 0)
+                return r;
+
+        r = get_config_path(scope, false, root_dir, &config_path);
+        if (r < 0)
+                return r;
+
+        r = install_info_add_auto(&c, file);
+        if (r < 0)
+                return r;
+
+        i = (InstallInfo*)hashmap_first(c.will_install);
+
+        r = unit_file_search(&c, i, &paths, root_dir, false);
+        if (r < 0)
+                return r;
+
+        if (asprintf(&path, "%s/%s", config_path, "default.target") < 0)
+                return -ENOMEM;
+
+        r = create_symlink(i->path, path, true, changes, n_changes);
+        if (r < 0)
+                return r;
+
+        return 0;
+
+
+}
+
+int unit_file_get_default(
+                UnitFileScope scope,
+                const char *root_dir,
+                UnitFileChange **changes,
+                unsigned *n_changes) {
+
+        _cleanup_free_ char *path;
+        _cleanup_free_ char *config_path;
+        _cleanup_free_ char *dest;
+        int r;
+
+        r = get_config_path(scope, false, root_dir, &config_path);
+        if (r < 0)
+                return r;
+
+        if (asprintf(&path, "%s/%s", config_path, "default.target") < 0)
+                return -ENOMEM;
+
+        r = readlink_and_make_absolute(path, &dest);
+        if (r < 0)
+                return r;
+
+        r = add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, dest, NULL);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
 UnitFileState unit_file_get_state(
                 UnitFileScope scope,
                 const char *root_dir,
diff --git a/src/shared/install.h b/src/shared/install.h
index 94516c9..1789482 100644
--- a/src/shared/install.h
+++ b/src/shared/install.h
@@ -80,6 +80,8 @@ int unit_file_link(UnitFileScope scope, bool runtime, const char *root_dir, char
 int unit_file_preset(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes);
 int unit_file_mask(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes);
 int unit_file_unmask(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes);
+int unit_file_set_default(UnitFileScope scope, const char *root_dir, char *file, UnitFileChange **changes, unsigned *n_changes);
+int unit_file_get_default(UnitFileScope scope, const char *root_dir, UnitFileChange **changes, unsigned *n_changes);
 
 UnitFileState unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename);
 
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 3cca861..8aadf85 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -4214,7 +4214,7 @@ static int enable_unit(DBusConnection *bus, char **args) {
         if (r < 0)
                 return r;
 
-        if (!args[1])
+        if (!args[1] && !streq(verb, "default-target"))
                 return 0;
 
         if (!bus || avoid_bus()) {
@@ -4235,7 +4235,15 @@ static int enable_unit(DBusConnection *bus, char **args) {
                         r = unit_file_mask(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
                 else if (streq(verb, "unmask"))
                         r = unit_file_unmask(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
-                else
+                else if (streq(verb, "default-target")) {
+                        if(args[1])
+                                r = unit_file_set_default(arg_scope, arg_root, args[1], &changes, &n_changes);
+                        else
+                                r = unit_file_get_default(arg_scope, arg_root, &changes, &n_changes);
+
+                        if (!args[1] && n_changes > 0)
+                                log_info("%s\n", changes[n_changes-1].path);
+                } else
                         assert_not_reached("Unknown verb");
 
                 if (r < 0) {
@@ -4243,7 +4251,7 @@ static int enable_unit(DBusConnection *bus, char **args) {
                         goto finish;
                 }
 
-                if (!arg_quiet) {
+                if (!arg_quiet && args[1]) {
                         for (i = 0; i < n_changes; i++) {
                                 if (changes[i].type == UNIT_FILE_SYMLINK)
                                         log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path);
@@ -4278,6 +4286,11 @@ static int enable_unit(DBusConnection *bus, char **args) {
                 else if (streq(verb, "unmask")) {
                         method = "UnmaskUnitFiles";
                         send_force = false;
+                } else if (streq(verb, "default-target")) {
+                        if (args[1])
+                                method = "SetDefaultTarget";
+                        else
+                                method = "GetDefaultTarget";
                 } else
                         assert_not_reached("Unknown verb");
 
@@ -4294,7 +4307,7 @@ static int enable_unit(DBusConnection *bus, char **args) {
                 dbus_message_iter_init_append(m, &iter);
 
                 r = mangle_names(args+1, &mangled_names);
-                if(r < 0)
+                if (r < 0)
                         goto finish;
 
                 r = bus_append_strv_iter(&iter, mangled_names);
@@ -4369,11 +4382,15 @@ static int enable_unit(DBusConnection *bus, char **args) {
                                 goto finish;
                         }
 
-                        if (!arg_quiet) {
-                                if (streq(type, "symlink"))
-                                        log_info("ln -s '%s' '%s'", source, path);
-                                else
-                                        log_info("rm '%s'", path);
+                        if (streq(method, "GetDefaultTarget"))
+                                log_info("%s", path);
+                        else {
+                                if (!arg_quiet) {
+                                        if (streq(type, "symlink"))
+                                                log_info("ln -s '%s' '%s'", source, path);
+                                        else
+                                                log_info("rm '%s'", path);
+                                }
                         }
 
                         dbus_message_iter_next(&sub);
@@ -5642,6 +5659,7 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
                 { "link",                  MORE,  2, enable_unit       },
                 { "switch-root",           MORE,  2, switch_root       },
                 { "list-dependencies",     LESS,  2, list_dependencies },
+                { "default-target",        LESS,  2, enable_unit       },
         };
 
         int left;
@@ -5713,7 +5731,8 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
             !streq(verbs[i].verb, "preset") &&
             !streq(verbs[i].verb, "mask") &&
             !streq(verbs[i].verb, "unmask") &&
-            !streq(verbs[i].verb, "link")) {
+            !streq(verbs[i].verb, "link") &&
+            !streq(verbs[i].verb, "default-target")) {
 
                 if (running_in_chroot() > 0) {
                         log_info("Running in chroot, ignoring request.");
-- 
1.8.1.4



More information about the systemd-devel mailing list