chiark / gitweb /
job: allow job_free() only on already unlinked jobs
[elogind.git] / src / core / manager.c
index 312527aa9c04eb78d0b92cc3d68deb3bbf46203d..aa918f1bd0d0d1cde30c4a69da2358af01564aab 100644 (file)
@@ -6,16 +6,16 @@
   Copyright 2010 Lennart Poettering
 
   systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
   (at your option) any later version.
 
   systemd is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  General Public License for more details.
+  Lesser General Public License for more details.
 
-  You should have received a copy of the GNU General Public License
+  You should have received a copy of the GNU Lesser General Public License
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
@@ -63,6 +63,7 @@
 #include "exit-status.h"
 #include "virt.h"
 #include "watchdog.h"
+#include "cgroup-util.h"
 
 /* As soon as 16 units are in our GC queue, make sure to run a gc sweep */
 #define GC_QUEUE_ENTRIES_MAX 16
@@ -141,13 +142,17 @@ static int enable_special_signals(Manager *m) {
 
         assert(m);
 
-        /* Enable that we get SIGINT on control-alt-del */
-        if (reboot(RB_DISABLE_CAD) < 0)
+        /* Enable that we get SIGINT on control-alt-del. In containers
+         * this will fail with EPERM, so ignore that. */
+        if (reboot(RB_DISABLE_CAD) < 0 && errno != EPERM)
                 log_warning("Failed to enable ctrl-alt-del handling: %m");
 
-        if ((fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC)) < 0)
-                log_warning("Failed to open /dev/tty0: %m");
-        else {
+        fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
+        if (fd < 0) {
+                /* Support systems without virtual console */
+                if (fd != -ENOENT)
+                        log_warning("Failed to open /dev/tty0: %m");
+        } else {
                 /* Enable that we get SIGWINCH on kbrequest */
                 if (ioctl(fd, KDSIGACCEPT, SIGWINCH) < 0)
                         log_warning("Failed to enable kbrequest handling: %s", strerror(errno));
@@ -657,13 +662,15 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
         return r;
 }
 
+static void transaction_unlink_job(Manager *m, Job *j, bool delete_dependencies);
+
 static void transaction_delete_job(Manager *m, Job *j, bool delete_dependencies) {
         assert(m);
         assert(j);
 
         /* Deletes one job from the transaction */
 
-        manager_transaction_unlink_job(m, j, delete_dependencies);
+        transaction_unlink_job(m, j, delete_dependencies);
 
         if (!j->installed)
                 job_free(j);
@@ -705,8 +712,10 @@ static void transaction_abort(Manager *m) {
         while ((j = hashmap_first(m->transaction_jobs)))
                 if (j->installed)
                         transaction_delete_job(m, j, true);
-                else
+                else {
+                        transaction_unlink_job(m, j, true);
                         job_free(j);
+                }
 
         assert(hashmap_isempty(m->transaction_jobs));
 
@@ -753,7 +762,7 @@ static void transaction_merge_and_delete_job(Manager *m, Job *j, Job *other, Job
         assert(j->unit == other->unit);
         assert(!j->installed);
 
-        /* Merges 'other' into 'j' and then deletes j. */
+        /* Merges 'other' into 'j' and then deletes 'other'. */
 
         j->type = t;
         j->state = JOB_WAITING;
@@ -798,6 +807,7 @@ static void transaction_merge_and_delete_job(Manager *m, Job *j, Job *other, Job
         other->object_list = NULL;
         transaction_delete_job(m, other, true);
 }
+
 static bool job_is_conflicted_by(Job *j) {
         JobDependency *l;
 
@@ -1435,6 +1445,7 @@ static Job* transaction_add_one_job(Manager *m, JobType type, Unit *unit, bool o
         LIST_PREPEND(Job, transaction, f, j);
 
         if (hashmap_replace(m->transaction_jobs, unit, f) < 0) {
+                LIST_REMOVE(Job, transaction, f, j);
                 job_free(j);
                 return NULL;
         }
@@ -1447,7 +1458,7 @@ static Job* transaction_add_one_job(Manager *m, JobType type, Unit *unit, bool o
         return j;
 }
 
-void manager_transaction_unlink_job(Manager *m, Job *j, bool delete_dependencies) {
+static void transaction_unlink_job(Manager *m, Job *j, bool delete_dependencies) {
         assert(m);
         assert(j);
 
@@ -2453,7 +2464,6 @@ static int process_event(Manager *m, struct epoll_event *ev) {
 
 int manager_loop(Manager *m) {
         int r;
-        int wait_msec = -1;
 
         RATELIMIT_DEFINE(rl, 1*USEC_PER_SEC, 50000);
 
@@ -2472,18 +2482,12 @@ int manager_loop(Manager *m) {
         if (r < 0)
                 return r;
 
-        /* Sleep for half the watchdog time */
-        if (m->runtime_watchdog > 0 && m->running_as == MANAGER_SYSTEM)  {
-                wait_msec = (int) (m->runtime_watchdog / 2 / USEC_PER_MSEC);
-                if (wait_msec <= 0)
-                        wait_msec = 1;
-        }
-
         while (m->exit_code == MANAGER_RUNNING) {
                 struct epoll_event event;
                 int n;
+                int wait_msec = -1;
 
-                if (wait_msec >= 0)
+                if (m->runtime_watchdog > 0 && m->running_as == MANAGER_SYSTEM)
                         watchdog_ping();
 
                 if (!ratelimit_test(&rl)) {
@@ -2514,6 +2518,14 @@ int manager_loop(Manager *m) {
                 if (swap_dispatch_reload(m) > 0)
                         continue;
 
+                /* Sleep for half the watchdog time */
+                if (m->runtime_watchdog > 0 && m->running_as == MANAGER_SYSTEM) {
+                        wait_msec = (int) (m->runtime_watchdog / 2 / USEC_PER_MSEC);
+                        if (wait_msec <= 0)
+                                wait_msec = 1;
+                } else
+                        wait_msec = -1;
+
                 n = epoll_wait(m->epoll_fd, &event, 1, wait_msec);
                 if (n < 0) {
 
@@ -2607,17 +2619,13 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
         }
 
         if (audit_log_user_comm_message(m->audit_fd, type, "", p, NULL, NULL, NULL, success) < 0) {
-                log_warning("Failed to send audit message: %m");
-
                 if (errno == EPERM) {
                         /* We aren't allowed to send audit messages?
-                         * Then let's not retry again, to avoid
-                         * spamming the user with the same and same
-                         * messages over and over. */
-
+                         * Then let's not retry again. */
                         audit_close(m->audit_fd);
                         m->audit_fd = -1;
-                }
+                } else
+                        log_warning("Failed to send audit message: %m");
         }
 
         free(p);
@@ -3015,7 +3023,7 @@ bool manager_unit_pending_inactive(Manager *m, const char *name) {
 
 void manager_check_finished(Manager *m) {
         char userspace[FORMAT_TIMESPAN_MAX], initrd[FORMAT_TIMESPAN_MAX], kernel[FORMAT_TIMESPAN_MAX], sum[FORMAT_TIMESPAN_MAX];
-        usec_t kernel_usec = 0, initrd_usec = 0, userspace_usec = 0, total_usec = 0;
+        usec_t kernel_usec, initrd_usec, userspace_usec, total_usec;
 
         assert(m);
 
@@ -3164,12 +3172,15 @@ int manager_set_default_controllers(Manager *m, char **controllers) {
 
         assert(m);
 
-        if (!(l = strv_copy(controllers)))
+        l = strv_copy(controllers);
+        if (!l)
                 return -ENOMEM;
 
         strv_free(m->default_controllers);
         m->default_controllers = l;
 
+        cg_shorten_controllers(m->default_controllers);
+
         return 0;
 }