chiark / gitweb /
manager: fix build on 32bit systems
[elogind.git] / src / core / manager.c
index 6fecbc3f7111aafe1464ceb718de3e8d808b4988..1ddd8bae62497407e555bbe4cfa47a03f507754e 100644 (file)
@@ -36,6 +36,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <dirent.h>
+#include <sys/timerfd.h>
 
 #ifdef HAVE_AUDIT
 #include <libaudit.h>
@@ -120,19 +121,66 @@ static int manager_setup_notify(Manager *m) {
         ev.events = EPOLLIN;
         ev.data.ptr = &m->notify_watch;
 
-        if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->notify_watch.fd, &ev) < 0)
+        if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->notify_watch.fd, &ev) < 0) {
+                log_error("Failed to add timer change fd to epoll: %m");
                 return -errno;
+        }
 
         sa.un.sun_path[0] = '@';
         m->notify_socket = strdup(sa.un.sun_path);
         if (!m->notify_socket)
-                return -ENOMEM;
+                return log_oom();
 
         log_debug("Using notification socket %s", m->notify_socket);
 
         return 0;
 }
 
+static int manager_setup_time_change(Manager *m) {
+        struct epoll_event ev;
+        struct itimerspec its;
+
+        assert(m);
+        assert(m->time_change_watch.type == WATCH_INVALID);
+
+        /* Uses TFD_TIMER_CANCEL_ON_SET to get notifications whenever
+         * CLOCK_REALTIME makes a jump relative to CLOCK_MONOTONIC */
+
+        m->time_change_watch.type = WATCH_TIME_CHANGE;
+        m->time_change_watch.fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
+        if (m->time_change_watch.fd < 0) {
+                log_error("Failed to create timerfd: %m");
+                return -errno;
+        }
+
+        zero(its);
+
+        /* We only care for the cancellation event, hence we set the
+         * timeout to the latest possible value. */
+        assert_cc(sizeof(time_t) == sizeof(long));
+        its.it_value.tv_sec = LONG_MAX;
+
+        if (timerfd_settime(m->time_change_watch.fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0) {
+                log_debug("Failed to set up TFD_TIMER_CANCEL_ON_SET, ignoring: %m");
+                close_nointr_nofail(m->time_change_watch.fd);
+                watch_init(&m->time_change_watch);
+                return 0;
+        }
+
+        zero(ev);
+        ev.events = EPOLLIN;
+        ev.data.ptr = &m->time_change_watch;
+
+        if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->time_change_watch.fd, &ev) < 0) {
+                log_error("Failed to add timer change fd to epoll: %m");
+                return -errno;
+        }
+
+        log_debug("Set up TFD_TIMER_CANCEL_ON_SET timerfd.");
+
+        return 0;
+}
+
 static int enable_special_signals(Manager *m) {
         int fd;
 
@@ -199,6 +247,7 @@ static int manager_setup_signals(Manager *m) {
                         SIGRTMIN+21, /* systemd: disable status messages */
                         SIGRTMIN+22, /* systemd: set log level to LOG_DEBUG */
                         SIGRTMIN+23, /* systemd: set log level to LOG_INFO */
+                        SIGRTMIN+24, /* systemd: Immediate exit (--user only) */
                         SIGRTMIN+26, /* systemd: set log target to journal-or-kmsg */
                         SIGRTMIN+27, /* systemd: set log target to console */
                         SIGRTMIN+28, /* systemd: set log target to kmsg */
@@ -207,7 +256,8 @@ static int manager_setup_signals(Manager *m) {
         assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
 
         m->signal_watch.type = WATCH_SIGNAL;
-        if ((m->signal_watch.fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0)
+        m->signal_watch.fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
+        if (m->signal_watch.fd < 0)
                 return -errno;
 
         zero(ev);
@@ -258,7 +308,13 @@ int manager_new(SystemdRunningAs running_as, Manager **_m) {
         m->pin_cgroupfs_fd = -1;
         m->idle_pipe[0] = m->idle_pipe[1] = -1;
 
-        m->signal_watch.fd = m->mount_watch.fd = m->udev_watch.fd = m->epoll_fd = m->dev_autofs_fd = m->swap_watch.fd = -1;
+        watch_init(&m->signal_watch);
+        watch_init(&m->mount_watch);
+        watch_init(&m->swap_watch);
+        watch_init(&m->udev_watch);
+        watch_init(&m->time_change_watch);
+
+        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 */
 
         m->environment = strv_copy(environ);
@@ -288,20 +344,29 @@ int manager_new(SystemdRunningAs running_as, Manager **_m) {
         if (!(m->watch_bus = hashmap_new(string_hash_func, string_compare_func)))
                 goto fail;
 
-        if ((m->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0)
+        m->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+        if (m->epoll_fd < 0)
+                goto fail;
+
+        r = manager_setup_signals(m);
+        if (r < 0)
                 goto fail;
 
-        if ((r = manager_setup_signals(m)) < 0)
+        r = manager_setup_cgroup(m);
+        if (r < 0)
                 goto fail;
 
-        if ((r = manager_setup_cgroup(m)) < 0)
+        r = manager_setup_notify(m);
+        if (r < 0)
                 goto fail;
 
-        if ((r = manager_setup_notify(m)) < 0)
+        r = manager_setup_time_change(m);
+        if (r < 0)
                 goto fail;
 
         /* Try to connect to the busses, if possible. */
-        if ((r = bus_init(m, running_as != SYSTEMD_SYSTEM)) < 0)
+        r = bus_init(m, running_as != SYSTEMD_SYSTEM);
+        if (r < 0)
                 goto fail;
 
         m->taint_usr = dir_is_empty("/usr") > 0;
@@ -486,6 +551,8 @@ void manager_free(Manager *m) {
                 close_nointr_nofail(m->signal_watch.fd);
         if (m->notify_watch.fd >= 0)
                 close_nointr_nofail(m->notify_watch.fd);
+        if (m->time_change_watch.fd >= 0)
+                close_nointr_nofail(m->time_change_watch.fd);
 
         free(m->notify_socket);
 
@@ -1272,6 +1339,15 @@ static int manager_process_signal_fd(Manager *m) {
                                 log_notice("Setting log level to info.");
                                 break;
 
+                        case 24:
+                                if (m->running_as == SYSTEMD_USER) {
+                                        m->exit_code = MANAGER_EXIT;
+                                        return 0;
+                                }
+
+                                /* This is a nop on init */
+                                break;
+
                         case 26:
                                 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
                                 log_notice("Setting log target to journal-or-kmsg.");
@@ -1353,11 +1429,13 @@ static int process_event(Manager *m, struct epoll_event *ev) {
                 ssize_t k;
 
                 /* Some timer event, to be dispatched to the units */
-                if ((k = read(w->fd, &v, sizeof(v))) != sizeof(v)) {
+                k = read(w->fd, &v, sizeof(v));
+                if (k != sizeof(v)) {
 
                         if (k < 0 && (errno == EINTR || errno == EAGAIN))
                                 break;
 
+                        log_error("Failed to read timer event counter: %s", k < 0 ? strerror(-k) : "Short read");
                         return k < 0 ? -errno : -EIO;
                 }
 
@@ -1391,6 +1469,28 @@ static int process_event(Manager *m, struct epoll_event *ev) {
                 bus_timeout_event(m, w, ev->events);
                 break;
 
+        case WATCH_TIME_CHANGE: {
+                Unit *u;
+                Iterator i;
+
+                log_struct(LOG_INFO,
+                           MESSAGE_ID(SD_MESSAGE_TIME_CHANGE),
+                           "MESSAGE=Time has been changed",
+                           NULL);
+
+                /* Restart the watch */
+                close_nointr_nofail(m->time_change_watch.fd);
+                watch_init(&m->time_change_watch);
+                manager_setup_time_change(m);
+
+                HASHMAP_FOREACH(u, m->units, i) {
+                        if (UNIT_VTABLE(u)->time_change)
+                                UNIT_VTABLE(u)->time_change(u);
+                }
+
+                break;
+        }
+
         default:
                 log_error("event type=%i", w->type);
                 assert_not_reached("Unknown epoll event type.");
@@ -1522,10 +1622,12 @@ int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j) {
         if (!startswith(s, "/org/freedesktop/systemd1/job/"))
                 return -EINVAL;
 
-        if ((r = safe_atou(s + 30, &id)) < 0)
+        r = safe_atou(s + 30, &id);
+        if (r < 0)
                 return r;
 
-        if (!(j = manager_get_job(m, id)))
+        j = manager_get_job(m, id);
+        if (!j)
                 return -ENOENT;
 
         *_j = j;
@@ -2039,7 +2141,7 @@ void manager_check_finished(Manager *m) {
 
                         if (!log_on_console())
                                 log_struct(LOG_INFO,
-                                           "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(SD_MESSAGE_STARTUP_FINISHED),
+                                           MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED),
                                            "KERNEL_USEC=%llu", (unsigned long long) kernel_usec,
                                            "INITRD_USEC=%llu", (unsigned long long) initrd_usec,
                                            "USERSPACE_USEC=%llu", (unsigned long long) userspace_usec,
@@ -2055,7 +2157,7 @@ void manager_check_finished(Manager *m) {
 
                         if (!log_on_console())
                                 log_struct(LOG_INFO,
-                                           "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(SD_MESSAGE_STARTUP_FINISHED),
+                                           MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED),
                                            "KERNEL_USEC=%llu", (unsigned long long) kernel_usec,
                                            "USERSPACE_USEC=%llu", (unsigned long long) userspace_usec,
                                            "MESSAGE=Startup finished in %s (kernel) + %s (userspace) = %s.",
@@ -2070,7 +2172,7 @@ void manager_check_finished(Manager *m) {
 
                 if (!log_on_console())
                         log_struct(LOG_INFO,
-                                   "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(SD_MESSAGE_STARTUP_FINISHED),
+                                   MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED),
                                    "USERSPACE_USEC=%llu", (unsigned long long) userspace_usec,
                                    "MESSAGE=Startup finished in %s.",
                                    format_timespan(sum, sizeof(sum), total_usec),
@@ -2297,3 +2399,10 @@ bool manager_get_show_status(Manager *m) {
 
         return plymouth_running();
 }
+
+void watch_init(Watch *w) {
+        assert(w);
+
+        w->type = WATCH_INVALID;
+        w->fd = -1;
+}