chiark / gitweb /
util: properly detect ttyname_r() failing
[elogind.git] / src / manager.c
index ddb253ae4eb0a240721297d79adb76528374ea25..c8fdbb5dee33993e60c0853bdc0cfb100482952b 100644 (file)
@@ -1,4 +1,4 @@
-/*-*- Mode: C; c-basic-offset: 8 -*-*/
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
 
 /***
   This file is part of systemd.
@@ -27,7 +27,6 @@
 #include <sys/signalfd.h>
 #include <sys/wait.h>
 #include <unistd.h>
-#include <utmpx.h>
 #include <sys/poll.h>
 #include <sys/reboot.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <dirent.h>
 
+#ifdef HAVE_AUDIT
+#include <libaudit.h>
+#endif
+
 #include "manager.h"
 #include "hashmap.h"
 #include "macro.h"
@@ -47,7 +50,6 @@
 #include "ratelimit.h"
 #include "cgroup.h"
 #include "mount-setup.h"
-#include "utmp-wtmp.h"
 #include "unit-name.h"
 #include "dbus-unit.h"
 #include "dbus-job.h"
@@ -202,6 +204,10 @@ int manager_new(ManagerRunningAs running_as, Manager **_m) {
         m->exit_code = _MANAGER_EXIT_CODE_INVALID;
         m->pin_cgroupfs_fd = -1;
 
+#ifdef HAVE_AUDIT
+        m->audit_fd = -1;
+#endif
+
         m->signal_watch.fd = m->mount_watch.fd = m->udev_watch.fd = m->epoll_fd = m->dev_autofs_fd = -1;
         m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
 
@@ -245,6 +251,11 @@ int manager_new(ManagerRunningAs running_as, Manager **_m) {
         if ((r = bus_init(m)) < 0)
                 goto fail;
 
+#ifdef HAVE_AUDIT
+        if ((m->audit_fd = audit_open()) < 0)
+                log_error("Failed to connect to audit log: %m");
+#endif
+
         *_m = m;
         return 0;
 
@@ -429,6 +440,11 @@ void manager_free(Manager *m) {
         if (m->notify_watch.fd >= 0)
                 close_nointr_nofail(m->notify_watch.fd);
 
+#ifdef HAVE_AUDIT
+        if (m->audit_fd >= 0)
+                audit_close(m->audit_fd);
+#endif
+
         free(m->notify_socket);
 
         lookup_paths_free(&m->lookup_paths);
@@ -567,10 +583,6 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
                 m->n_deserializing --;
         }
 
-        /* Now that the initial devices are available, let's see if we
-         * can write the utmp file */
-        manager_write_utmp_reboot(m);
-
         return r;
 }
 
@@ -779,7 +791,8 @@ static int delete_one_unmergeable_job(Manager *m, Job *j) {
                                                 d = j;
                                         else
                                                 d = k;
-                                }
+                                } else
+                                        d = j;
 
                         } else if (!j->matters_to_anchor)
                                 d = j;
@@ -812,7 +825,7 @@ static int transaction_merge_jobs(Manager *m, DBusError *e) {
 
                 t = j->type;
                 LIST_FOREACH(transaction, k, j->transaction_next) {
-                        if ((r = job_type_merge(&t, k->type)) >= 0)
+                        if (job_type_merge(&t, k->type) >= 0)
                                 continue;
 
                         /* OK, we could not merge all jobs for this
@@ -1281,7 +1294,6 @@ rollback:
 
 static Job* transaction_add_one_job(Manager *m, JobType type, Unit *unit, bool override, bool *is_new) {
         Job *j, *f;
-        int r;
 
         assert(m);
         assert(unit);
@@ -1314,7 +1326,7 @@ static Job* transaction_add_one_job(Manager *m, JobType type, Unit *unit, bool o
 
         LIST_PREPEND(Job, transaction, f, j);
 
-        if ((r = hashmap_replace(m->transaction_jobs, unit, f)) < 0) {
+        if (hashmap_replace(m->transaction_jobs, unit, f) < 0) {
                 job_free(j);
                 return NULL;
         }
@@ -1380,9 +1392,15 @@ static int transaction_add_job_and_dependencies(
         assert(type < _JOB_TYPE_MAX);
         assert(unit);
 
-        if (type != JOB_STOP &&
-            unit->meta.load_state != UNIT_LOADED) {
-                dbus_set_error(e, BUS_ERROR_LOAD_FAILED, "Unit %s failed to load. See logs for details.", unit->meta.id);
+        if (unit->meta.load_state != UNIT_LOADED && unit->meta.load_state != UNIT_FAILED) {
+                dbus_set_error(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->meta.id);
+                return -EINVAL;
+        }
+
+        if (type != JOB_STOP && unit->meta.load_state == UNIT_FAILED) {
+                dbus_set_error(e, BUS_ERROR_LOAD_FAILED, "Unit %s failed to load: %s. You might find more information in the logs.",
+                               unit->meta.id,
+                               strerror(-unit->meta.load_error));
                 return -EINVAL;
         }
 
@@ -1768,7 +1786,7 @@ static int manager_process_notify_fd(Manager *m) {
                         if (n >= 0)
                                 return -EIO;
 
-                        if (errno == EAGAIN)
+                        if (errno == EAGAIN || errno == EINTR)
                                 break;
 
                         return -errno;
@@ -2234,70 +2252,30 @@ int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j) {
         return 0;
 }
 
-static bool manager_utmp_good(Manager *m) {
-        int r;
-
-        assert(m);
-
-        if ((r = mount_path_is_mounted(m, _PATH_UTMPX)) <= 0) {
+void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
 
-                if (r < 0)
-                        log_warning("Failed to determine whether " _PATH_UTMPX " is mounted: %s", strerror(-r));
+#ifdef HAVE_AUDIT
+        char *p;
 
-                return false;
-        }
-
-        return true;
-}
-
-void manager_write_utmp_reboot(Manager *m) {
-        int r;
-
-        assert(m);
-
-        if (m->utmp_reboot_written)
+        if (m->audit_fd < 0)
                 return;
 
-        if (m->running_as != MANAGER_SYSTEM)
+        /* Don't generate audit events if the service was already
+         * started and we're just deserializing */
+        if (m->n_deserializing > 0)
                 return;
 
-        if (!manager_utmp_good(m))
-                return;
-
-        if ((r = utmp_put_reboot(m->startup_timestamp.realtime)) < 0) {
-
-                if (r != -ENOENT && r != -EROFS)
-                        log_warning("Failed to write utmp/wtmp: %s", strerror(-r));
-
+        if (!(p = unit_name_to_prefix_and_instance(u->meta.id))) {
+                log_error("Failed to allocate unit name for audit message: %s", strerror(ENOMEM));
                 return;
         }
 
-        m->utmp_reboot_written = true;
-}
-
-void manager_write_utmp_runlevel(Manager *m, Unit *u) {
-        int runlevel, r;
-
-        assert(m);
-        assert(u);
-
-        if (u->meta.type != UNIT_TARGET)
-                return;
-
-        if (m->running_as != MANAGER_SYSTEM)
-                return;
-
-        if (!manager_utmp_good(m))
-                return;
-
-        if ((runlevel = target_get_runlevel(TARGET(u))) <= 0)
-                return;
+        if (audit_log_user_comm_message(m->audit_fd, type, "", p, NULL, NULL, NULL, success) < 0)
+                log_error("Failed to send audit message: %m");
 
-        if ((r = utmp_put_runlevel(0, runlevel, 0)) < 0) {
+        free(p);
+#endif
 
-                if (r != -ENOENT && r != -EROFS)
-                        log_warning("Failed to write utmp/wtmp: %s", strerror(-r));
-        }
 }
 
 void manager_dispatch_bus_name_owner_changed(
@@ -2384,6 +2362,10 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds) {
         assert(f);
         assert(fds);
 
+        fprintf(f, "startup-timestamp=%llu %llu\n\n",
+                (unsigned long long) m->startup_timestamp.realtime,
+                (unsigned long long) m->startup_timestamp.monotonic);
+
         HASHMAP_FOREACH_KEY(u, t, m->units, i) {
                 if (u->meta.id != t)
                         continue;
@@ -2415,6 +2397,37 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
 
         m->n_deserializing ++;
 
+        for (;;) {
+                char line[1024], *l;
+
+                if (!fgets(line, sizeof(line), f)) {
+                        if (feof(f))
+                                r = 0;
+                        else
+                                r = -errno;
+
+                        goto finish;
+                }
+
+                char_array_0(line);
+                l = strstrip(line);
+
+                if (l[0] == 0)
+                        break;
+
+                if (startswith(l, "startup-timestamp=")) {
+                        unsigned long long a, b;
+
+                        if (sscanf(l+18, "%lli %llu", &a, &b) != 2)
+                                log_debug("Failed to parse startup timestamp value %s", l+18);
+                        else {
+                                m->startup_timestamp.realtime = a;
+                                m->startup_timestamp.monotonic = b;
+                        }
+                } else
+                        log_debug("Unknown serialization item '%s'", l);
+        }
+
         for (;;) {
                 Unit *u;
                 char name[UNIT_NAME_MAX+2];
@@ -2422,9 +2435,10 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
                 /* Start marker */
                 if (!fgets(name, sizeof(name), f)) {
                         if (feof(f))
-                                break;
+                                r = 0;
+                        else
+                                r = -errno;
 
-                        r = -errno;
                         goto finish;
                 }
 
@@ -2437,14 +2451,12 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
                         goto finish;
         }
 
+finish:
         if (ferror(f)) {
                 r = -EIO;
                 goto finish;
         }
 
-        r = 0;
-
-finish:
         assert(m->n_deserializing > 0);
         m->n_deserializing --;