chiark / gitweb /
mount-setup: consider a few file systems API mounts and ignore them
[elogind.git] / src / install.c
index 2c57c9b607510b9207733188bd579f99e9cc0e3e..bd23a938f36acf21e82ece810894d6dc808c4ac4 100644 (file)
@@ -24,6 +24,7 @@
 #include <getopt.h>
 #include <errno.h>
 #include <unistd.h>
+#include <fcntl.h>
 
 #include "log.h"
 #include "path-lookup.h"
@@ -46,6 +47,7 @@ static enum {
         ACTION_INVALID,
         ACTION_ENABLE,
         ACTION_DISABLE,
+        ACTION_REALIZE,
         ACTION_TEST
 } arg_action = ACTION_INVALID;
 
@@ -81,6 +83,8 @@ static int help(void) {
                "Commands:\n"
                "  enable [NAME...]    Enable one or more units\n"
                "  disable [NAME...]   Disable one or more units\n"
+               "  realize [NAME...]   Test whether any of the specified units are enabled\n"
+               "                      and the start/stop/restart units accordingly\n"
                "  test [NAME...]      Test whether any of the specified units are enabled\n",
                program_invocation_short_name);
 
@@ -108,6 +112,7 @@ static int parse_argv(int argc, char *argv[]) {
         };
 
         int c;
+        bool realize_switch = false;
 
         assert(argc >= 1);
         assert(argv);
@@ -138,6 +143,8 @@ static int parse_argv(int argc, char *argv[]) {
 
                 case ARG_REALIZE:
 
+                        realize_switch = true;
+
                         if (!optarg)
                                 arg_realize = REALIZE_MAYBE;
                         else if (streq(optarg, "no"))
@@ -177,7 +184,12 @@ static int parse_argv(int argc, char *argv[]) {
                 arg_action = ACTION_DISABLE;
         else if (streq(argv[optind], "test"))
                 arg_action = ACTION_TEST;
-        else {
+        else if (streq(argv[optind], "realize")) {
+                arg_action = ACTION_REALIZE;
+
+                if (!realize_switch)
+                        arg_realize = REALIZE_MAYBE;
+        } else {
                 log_error("Unknown verb %s.", argv[optind]);
                 return -EINVAL;
         }
@@ -297,7 +309,7 @@ finish:
         return r;
 }
 
-static int install_info_run(DBusConnection *bus, InstallInfo *i) {
+static int install_info_run(DBusConnection *bus, InstallInfo *i, bool enabled) {
         DBusMessage *m = NULL, *reply = NULL;
         DBusError error;
         int r;
@@ -308,7 +320,8 @@ static int install_info_run(DBusConnection *bus, InstallInfo *i) {
 
         dbus_error_init(&error);
 
-        if (arg_action == ACTION_ENABLE) {
+        if (arg_action == ACTION_ENABLE ||
+            (arg_action == ACTION_REALIZE && enabled)) {
 
                 if (arg_realize == REALIZE_MAYBE) {
                         char **k;
@@ -436,7 +449,8 @@ static int install_info_run(DBusConnection *bus, InstallInfo *i) {
                 }
 
 
-        } else if (arg_action == ACTION_DISABLE) {
+        } else if (arg_action == ACTION_DISABLE ||
+                   (arg_action == ACTION_REALIZE && !enabled)) {
 
                 if (!(m = dbus_message_new_method_call(
                                       "org.freedesktop.systemd1",
@@ -456,10 +470,11 @@ static int install_info_run(DBusConnection *bus, InstallInfo *i) {
                         r = -ENOMEM;
                         goto finish;
                 }
-        }
+        } else
+                assert_not_reached("install_info_run() called but nothing to do?");
 
         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                log_error("Failed to reload configuration: %s", error.message);
+                log_error("Failed to realize unit: %s", error.message);
                 r = -EIO;
                 goto finish;
         }
@@ -591,7 +606,7 @@ static int create_symlink(const char *old_path, const char *new_path) {
                 log_error("Cannot unlink %s: %m", new_path);
                 return -errno;
 
-        } else if (arg_action == ACTION_TEST) {
+        } else if (arg_action == ACTION_TEST || arg_action == ACTION_REALIZE) {
                 char *dest;
 
                 if ((r = readlink_and_make_absolute(new_path, &dest)) < 0) {
@@ -708,22 +723,32 @@ static int install_info_apply(LookupPaths *paths, InstallInfo *i, const char *co
         assert(i);
 
         STRV_FOREACH(p, paths->unit_path) {
+                int fd;
 
                 if (!(filename = path_make_absolute(i->name, *p))) {
                         log_error("Out of memory");
                         return -ENOMEM;
                 }
 
-                if ((f = fopen(filename, "re")))
-                        break;
+                /* Ensure that we don't follow symlinks */
+                if ((fd = open(filename, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NOCTTY)) >= 0)
+                        if ((f = fdopen(fd, "re")))
+                                break;
 
-                free(filename);
-                filename = NULL;
+                if (errno == ELOOP) {
+                        log_error("Refusing to operate on symlinks, please pass unit names or absolute paths to unit files.");
+                        free(filename);
+                        return -errno;
+                }
 
                 if (errno != ENOENT) {
                         log_error("Failed to open %s: %m", filename);
+                        free(filename);
                         return -errno;
                 }
+
+                free(filename);
+                filename = NULL;
         }
 
         if (!f) {
@@ -773,7 +798,7 @@ static char *get_config_path(void) {
         }
 }
 
-static int do_run(void) {
+static int do_realize(bool enabled) {
         DBusConnection *bus = NULL;
         DBusError error;
         int r, q;
@@ -790,13 +815,13 @@ static int do_run(void) {
                 return 0;
         }
 
-        if (arg_action != ACTION_ENABLE && arg_action != ACTION_DISABLE) {
+        if (arg_action == ACTION_TEST) {
                 log_warning("Warning: --realize has no effect with test.");
                 return 0;
         }
 
         if (arg_where == WHERE_SYSTEM && sd_booted() <= 0) {
-                log_info("systemd is not running, --realize has not effect.");
+                log_info("systemd is not running, --realize has no effect.");
                 return 0;
         }
 
@@ -812,13 +837,13 @@ static int do_run(void) {
 
         r = 0;
 
-        if (arg_action == ACTION_ENABLE)
+        if (arg_action == ACTION_ENABLE || arg_action == ACTION_REALIZE)
                 if ((r = daemon_reload(bus)) < 0)
                         goto finish;
 
         if (arg_realize != REALIZE_RELOAD) {
                 HASHMAP_FOREACH(j, have_installed, i)
-                        if ((q = install_info_run(bus, j)) < 0)
+                        if ((q = install_info_run(bus, j, enabled)) < 0)
                                 r = q;
         }
 
@@ -827,8 +852,10 @@ static int do_run(void) {
                         r = q;
 
 finish:
-        if (bus)
+        if (bus) {
+                dbus_connection_close(bus);
                 dbus_connection_unref(bus);
+        }
 
         dbus_error_free(&error);
 
@@ -885,15 +912,13 @@ int main(int argc, char *argv[]) {
 
                         /* In test mode and found something */
                         retval = 0;
-                        goto finish;
+                        break;
                 }
         }
 
-        if (do_run() < 0)
+        if (do_realize(!retval) < 0)
                 goto finish;
 
-        retval = arg_action == ACTION_TEST ? 1 : 0;
-
 finish:
         install_info_hashmap_free(will_install);
         install_info_hashmap_free(have_installed);