chiark / gitweb /
core: add catalog entry and MESSAGE_ID for overmounting
[elogind.git] / src / core / mount.c
index 69cb6e24e4b23861b07ea8664de3c7befb889afa..f263d9b9d15461539b164d892ab7f5b97df16e48 100644 (file)
@@ -30,6 +30,7 @@
 #include "load-fragment.h"
 #include "load-dropin.h"
 #include "log.h"
+#include "sd-messages.h"
 #include "strv.h"
 #include "mkdir.h"
 #include "path-util.h"
@@ -79,6 +80,8 @@ static void mount_init(Unit *u) {
                 m->exec_context.std_error = u->manager->default_std_error;
         }
 
+        kill_context_init(&m->kill_context);
+
         /* We need to make sure that /bin/mount is always called in
          * the same process group as us, so that the autofs kernel
          * side doesn't send us another mount request while we are
@@ -350,17 +353,21 @@ static int mount_add_device_links(Mount *m) {
         if (!p->what)
                 return 0;
 
-        if (!mount_is_bind(p) &&
-            !path_equal(m->where, "/")) {
-                r = unit_add_node_link(UNIT(m), p->what, false);
-                if (r < 0)
-                        return r;
-        }
+        if (mount_is_bind(p))
+                return 0;
+
+        if (!is_device_path(p->what))
+                return 0;
+
+        if (path_equal(m->where, "/"))
+                return 0;
+
+        r = unit_add_node_link(UNIT(m), p->what, false);
+        if (r < 0)
+                return r;
 
         if (p->passno > 0 &&
-            !mount_is_bind(p) &&
-            !path_equal(m->where, "/") &&
-            UNIT(m)->manager->running_as == MANAGER_SYSTEM) {
+            UNIT(m)->manager->running_as == SYSTEMD_SYSTEM) {
                 char *name;
                 Unit *fsck;
                 /* Let's add in the fsck service */
@@ -394,7 +401,7 @@ static int mount_add_quota_links(Mount *m) {
 
         assert(m);
 
-        if (UNIT(m)->manager->running_as != MANAGER_SYSTEM)
+        if (UNIT(m)->manager->running_as != SYSTEMD_SYSTEM)
                 return 0;
 
         p = get_mount_parameters_fragment(m);
@@ -422,7 +429,7 @@ static int mount_add_default_dependencies(Mount *m) {
 
         assert(m);
 
-        if (UNIT(m)->manager->running_as != MANAGER_SYSTEM)
+        if (UNIT(m)->manager->running_as != SYSTEMD_SYSTEM)
                 return 0;
 
         p = get_mount_parameters_fragment(m);
@@ -529,7 +536,7 @@ static int mount_verify(Mount *m) {
                 return -EBADMSG;
         }
 
-        if (m->exec_context.pam_name && m->exec_context.kill_mode != KILL_CONTROL_GROUP) {
+        if (m->exec_context.pam_name && m->kill_context.kill_mode != KILL_CONTROL_GROUP) {
                 log_error("%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", UNIT(m)->id);
                 return -EINVAL;
         }
@@ -541,10 +548,6 @@ static int mount_add_extras(Mount *m) {
         Unit *u = UNIT(m);
         int r;
 
-        r = unit_add_exec_dependencies(u, &m->exec_context);
-        if (r < 0)
-                return r;
-
         if (UNIT(m)->fragment_path)
                 m->from_fragment = true;
 
@@ -556,6 +559,10 @@ static int mount_add_extras(Mount *m) {
 
         path_kill_slashes(m->where);
 
+        r = unit_add_exec_dependencies(u, &m->exec_context);
+        if (r < 0)
+                return r;
+
         if (!UNIT(m)->description) {
                 r = unit_set_description(u, m->where);
                 if (r < 0)
@@ -631,6 +638,10 @@ static int mount_load(Unit *u) {
                 r = mount_add_extras(m);
                 if (r < 0)
                         return r;
+
+                r = unit_exec_context_defaults(u, &m->exec_context);
+                if (r < 0)
+                        return r;
         }
 
         return mount_verify(m);
@@ -687,8 +698,10 @@ static void mount_set_state(Mount *m, MountState state) {
                  state == MOUNT_REMOUNTING_SIGKILL ||
                  state == MOUNT_UNMOUNTING_SIGTERM ||
                  state == MOUNT_UNMOUNTING_SIGKILL ||
-                 state == MOUNT_FAILED)
-                mount_notify_automount(m, -ENODEV);
+                 state == MOUNT_FAILED) {
+               if (state != old_state)
+                       mount_notify_automount(m, -ENODEV);
+       }
 
         if (state != old_state)
                 log_debug("%s changed %s -> %s",
@@ -729,10 +742,12 @@ static int mount_coldplug(Unit *u) {
                         if (m->control_pid <= 0)
                                 return -EBADMSG;
 
-                        if ((r = unit_watch_pid(UNIT(m), m->control_pid)) < 0)
+                        r = unit_watch_pid(UNIT(m), m->control_pid);
+                        if (r < 0)
                                 return r;
 
-                        if ((r = unit_watch_timer(UNIT(m), m->timeout_usec, &m->timer_watch)) < 0)
+                        r = unit_watch_timer(UNIT(m), CLOCK_MONOTONIC, true, m->timeout_usec, &m->timer_watch);
+                        if (r < 0)
                                 return r;
                 }
 
@@ -777,6 +792,7 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) {
                         prefix, (unsigned long) m->control_pid);
 
         exec_context_dump(&m->exec_context, f, prefix);
+        kill_context_dump(&m->kill_context, f, prefix);
 }
 
 static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
@@ -787,7 +803,8 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
         assert(c);
         assert(_pid);
 
-        if ((r = unit_watch_timer(UNIT(m), m->timeout_usec, &m->timer_watch)) < 0)
+        r = unit_watch_timer(UNIT(m), CLOCK_MONOTONIC, true, m->timeout_usec, &m->timer_watch);
+        if (r < 0)
                 goto fail;
 
         if ((r = exec_spawn(c,
@@ -849,10 +866,10 @@ static void mount_enter_signal(Mount *m, MountState state, MountResult f) {
         if (f != MOUNT_SUCCESS)
                 m->result = f;
 
-        if (m->exec_context.kill_mode != KILL_NONE) {
+        if (m->kill_context.kill_mode != KILL_NONE) {
                 int sig = (state == MOUNT_MOUNTING_SIGTERM ||
                            state == MOUNT_UNMOUNTING_SIGTERM ||
-                           state == MOUNT_REMOUNTING_SIGTERM) ? m->exec_context.kill_signal : SIGKILL;
+                           state == MOUNT_REMOUNTING_SIGTERM) ? m->kill_context.kill_signal : SIGKILL;
 
                 if (m->control_pid > 0) {
                         if (kill_and_sigcont(m->control_pid, sig) < 0 && errno != ESRCH)
@@ -862,7 +879,7 @@ static void mount_enter_signal(Mount *m, MountState state, MountResult f) {
                                 wait_for_exit = true;
                 }
 
-                if (m->exec_context.kill_mode == KILL_CONTROL_GROUP) {
+                if (m->kill_context.kill_mode == KILL_CONTROL_GROUP) {
 
                         if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) {
                                 r = -ENOMEM;
@@ -887,7 +904,8 @@ static void mount_enter_signal(Mount *m, MountState state, MountResult f) {
         }
 
         if (wait_for_exit) {
-                if ((r = unit_watch_timer(UNIT(m), m->timeout_usec, &m->timer_watch)) < 0)
+                r = unit_watch_timer(UNIT(m), CLOCK_MONOTONIC, true, m->timeout_usec, &m->timer_watch);
+                if (r < 0)
                         goto fail;
 
                 mount_set_state(m, state);
@@ -910,6 +928,18 @@ fail:
                 set_free(pid_set);
 }
 
+void warn_if_dir_nonempty(const char *unit, const char* where) {
+        if (dir_is_empty(where) > 0)
+                return;
+        log_struct(LOG_NOTICE,
+                   "MESSAGE=%s: Directory %s to mount over is not empty, mounting anyway.",
+                   unit, where,
+                   "WHERE=%s", where,
+                   "_SYSTEMD_UNIT=%s", unit,
+                   MESSAGE_ID(SD_MESSAGE_OVERMOUNTING),
+                   NULL);
+}
+
 static void mount_enter_unmounting(Mount *m) {
         int r;
 
@@ -950,6 +980,8 @@ static void mount_enter_mounting(Mount *m) {
 
         mkdir_p_label(m->where, m->directory_mode);
 
+        warn_if_dir_nonempty(m->meta.id, m->where);
+
         /* Create the source directory for bind-mounts if needed */
         p = get_mount_parameters_fragment(m);
         if (p && mount_is_bind(p))
@@ -972,7 +1004,8 @@ static void mount_enter_mounting(Mount *m) {
 
         mount_unwatch_control_pid(m);
 
-        if ((r = mount_spawn(m, m->control_command, &m->control_pid)) < 0)
+        r = mount_spawn(m, m->control_command, &m->control_pid);
+        if (r < 0)
                 goto fail;
 
         mount_set_state(m, MOUNT_MOUNTING);
@@ -1216,7 +1249,7 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
 
         m->control_pid = 0;
 
-        if (is_clean_exit(code, status))
+        if (is_clean_exit(code, status, NULL))
                 f = MOUNT_SUCCESS;
         else if (code == CLD_EXITED)
                 f = MOUNT_FAILURE_EXIT_CODE;
@@ -1321,7 +1354,7 @@ static void mount_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
                 break;
 
         case MOUNT_MOUNTING_SIGTERM:
-                if (m->exec_context.send_sigkill) {
+                if (m->kill_context.send_sigkill) {
                         log_warning("%s mounting timed out. Killing.", u->id);
                         mount_enter_signal(m, MOUNT_MOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
                 } else {
@@ -1335,7 +1368,7 @@ static void mount_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
                 break;
 
         case MOUNT_REMOUNTING_SIGTERM:
-                if (m->exec_context.send_sigkill) {
+                if (m->kill_context.send_sigkill) {
                         log_warning("%s remounting timed out. Killing.", u->id);
                         mount_enter_signal(m, MOUNT_REMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
                 } else {
@@ -1349,7 +1382,7 @@ static void mount_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
                 break;
 
         case MOUNT_UNMOUNTING_SIGTERM:
-                if (m->exec_context.send_sigkill) {
+                if (m->kill_context.send_sigkill) {
                         log_warning("%s unmounting timed out. Killing.", u->id);
                         mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
                 } else {
@@ -1391,6 +1424,7 @@ static int mount_add_one(
         bool delete;
         char *e, *w = NULL, *o = NULL, *f = NULL;
         MountParameters *p;
+        bool load_extras = false;
 
         assert(m);
         assert(what);
@@ -1441,12 +1475,21 @@ static int mount_add_one(
                 delete = false;
                 free(e);
 
+                if (!MOUNT(u)->where) {
+                        MOUNT(u)->where = strdup(where);
+                        if (!MOUNT(u)->where) {
+                                r = -ENOMEM;
+                                goto fail;
+                        }
+                }
+
                 if (u->load_state == UNIT_ERROR) {
                         u->load_state = UNIT_LOADED;
                         u->load_error = 0;
-                        r = mount_add_extras(MOUNT(u));
-                        if (r < 0)
-                                goto fail;
+
+                        /* Load in the extras later on, after we
+                         * finished initialization of the unit */
+                        load_extras = true;
                 }
         }
 
@@ -1477,6 +1520,12 @@ static int mount_add_one(
 
         p->passno = passno;
 
+        if (load_extras) {
+                r = mount_add_extras(MOUNT(u));
+                if (r < 0)
+                        goto fail;
+        }
+
         unit_add_to_dbus_queue(u);
 
         return 0;
@@ -1532,7 +1581,7 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
                         goto clean_up;
                 }
 
-                o = join(options, ",", options2, NULL);
+                o = strjoin(options, ",", options2, NULL);
                 if (!o) {
                         r = -ENOMEM;
                         goto finish;
@@ -1699,7 +1748,7 @@ static void mount_reset_failed(Unit *u) {
         m->reload_result = MOUNT_SUCCESS;
 }
 
-static int mount_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError *error) {
+static int mount_kill(Unit *u, KillWho who, int signo, DBusError *error) {
         Mount *m = MOUNT(u);
         int r = 0;
         Set *pid_set = NULL;
@@ -1721,23 +1770,25 @@ static int mount_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError
                         if (kill(m->control_pid, signo) < 0)
                                 r = -errno;
 
-        if (who == KILL_ALL && mode == KILL_CONTROL_GROUP) {
+        if (who == KILL_ALL) {
                 int q;
 
-                if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func)))
+                pid_set = set_new(trivial_hash_func, trivial_compare_func);
+                if (!pid_set)
                         return -ENOMEM;
 
                 /* Exclude the control pid from being killed via the cgroup */
-                if (m->control_pid > 0)
-                        if ((q = set_put(pid_set, LONG_TO_PTR(m->control_pid))) < 0) {
+                if (m->control_pid > 0) {
+                        q = set_put(pid_set, LONG_TO_PTR(m->control_pid));
+                        if (q < 0) {
                                 r = q;
                                 goto finish;
                         }
+                }
 
                 q = cgroup_bonding_kill_list(UNIT(m)->cgroup_bondings, signo, false, false, pid_set, NULL);
-                if (q < 0)
-                        if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
-                                r = q;
+                if (q < 0 && q != -EAGAIN && q != -ESRCH && q != -ENOENT)
+                        r = q;
         }
 
 finish:
@@ -1786,6 +1837,8 @@ DEFINE_STRING_TABLE_LOOKUP(mount_result, MountResult);
 
 const UnitVTable mount_vtable = {
         .object_size = sizeof(Mount),
+        .exec_context_offset = offsetof(Mount, exec_context),
+
         .sections =
                 "Unit\0"
                 "Mount\0"