aboutsummaryrefslogtreecommitdiff
path: root/src/events/time_set.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/events/time_set.c')
-rw-r--r--src/events/time_set.c174
1 files changed, 174 insertions, 0 deletions
diff --git a/src/events/time_set.c b/src/events/time_set.c
new file mode 100644
index 0000000..edc30c9
--- /dev/null
+++ b/src/events/time_set.c
@@ -0,0 +1,174 @@
+/*
+ * time_set.c - time setting functions
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <event2/event.h>
+
+#include "src/conf.h"
+#include "src/dbus.h"
+#include "src/tlsdate.h"
+#include "src/util.h"
+
+void
+handle_time_setter (struct state *state, int status)
+{
+ switch (status)
+ {
+ case SETTER_BAD_TIME:
+ info ("[event:%s] time setter received bad time", __func__);
+ /* This is the leaf node. Failure means that our source
+ * tried to walk back in time.
+ */
+ state->last_sync_type = SYNC_TYPE_RTC;
+ state->last_time = time (NULL);
+ break;
+ case SETTER_TIME_SET:
+ info ("[event:%s] time set from the %s (%ld)",
+ __func__, sync_type_str (state->last_sync_type), state->last_time);
+ if (state->last_sync_type == SYNC_TYPE_NET)
+ {
+ /* Update the delta so it doesn't fire again immediately. */
+ state->clock_delta = 0;
+ check_continuity (&state->clock_delta);
+ /* Reset the sources list! */
+ state->opts.cur_source = NULL;
+ }
+ /* Share our success. */
+ if (state->opts.should_dbus)
+ dbus_announce (state);
+ break;
+ case SETTER_NO_SBOX:
+ error ("[event:%s] time setter failed to sandbox", __func__);
+ break;
+ case SETTER_EXIT:
+ error ("[event:%s] time setter exited gracefully", __func__);
+ break;
+ case SETTER_SET_ERR:
+ error ("[event:%s] time setter could not settimeofday()", __func__);
+ break;
+ case SETTER_NO_RTC:
+ error ("[event:%s] time setter could sync rtc", __func__);
+ break;
+ case SETTER_NO_SAVE:
+ error ("[event:%s] time setter could not open save file", __func__);
+ break;
+ case SETTER_READ_ERR:
+ error ("[event:%s] time setter could not read time", __func__);
+ break;
+ default:
+ error ("[event:%s] received bogus status from time setter: %d",
+ __func__, status);
+ exit (status);
+ }
+}
+
+void
+action_time_set (evutil_socket_t fd, short what, void *arg)
+{
+ struct state *state = arg;
+ int status = -1;
+ ssize_t bytes = 0;
+ verb_debug ("[event:%s] fired", __func__);
+ bytes = IGNORE_EINTR (read (fd, &status, sizeof (status)));
+ if (bytes == -1 && errno == EAGAIN)
+ return; /* Catch next wake up */
+ /* Catch the rest of the errnos and any truncation. */
+ if (bytes != sizeof (status))
+ {
+ /* Truncation of an int over a pipe shouldn't happen except in
+ * terminal cases.
+ */
+ perror ("[event:%s] time setter pipe truncated! (%d)", __func__,
+ bytes);
+ /* Let SIGCHLD do the teardown. */
+ close (fd);
+ return;
+ }
+ handle_time_setter (state, status);
+}
+
+int
+setup_time_setter (struct state *state)
+{
+ struct event *event;
+ int to_fds[2];
+ int from_fds[2];
+ if (pipe (to_fds) < 0)
+ {
+ perror ("pipe failed");
+ return 1;
+ }
+ if (pipe (from_fds) < 0)
+ {
+ perror ("pipe failed");
+ close (to_fds[0]);
+ close (to_fds[1]);
+ return 1;
+ }
+ /* The fd that tlsdated will write to */
+ state->setter_save_fd = to_fds[1];
+ state->setter_notify_fd = from_fds[0];
+ /* Make the notifications fd non-blocking. */
+ if (fcntl (from_fds[0], F_SETFL, O_NONBLOCK) < 0)
+ {
+ perror ("notifier_fd fcntl(O_NONBLOCK) failed");
+ goto close_and_fail;
+ }
+ /* Make writes non-blocking */
+ if (fcntl (to_fds[1], F_SETFL, O_NONBLOCK) < 0)
+ {
+ perror ("save_fd fcntl(O_NONBLOCK) failed");
+ goto close_and_fail;
+ }
+ event = event_new (state->base, from_fds[0], EV_READ|EV_PERSIST,
+ action_time_set, state);
+ if (!event)
+ {
+ error ("Failed to allocate tlsdate setter event");
+ goto close_and_fail;
+ }
+ event_priority_set (event, PRI_NET);
+ event_add (event, NULL);
+ /* fork */
+ state->setter_pid = fork();
+ if (state->setter_pid < 0)
+ {
+ perror ("fork()ing the time setter failed");
+ goto close_and_fail;
+ }
+ if (state->setter_pid == 0)
+ {
+ close (to_fds[1]);
+ close (from_fds[0]);
+ time_setter_coprocess (to_fds[0], from_fds[1], state);
+ _exit (1);
+ }
+ close (from_fds[1]);
+ close (to_fds[0]);
+ return 0;
+
+close_and_fail:
+ close (to_fds[0]);
+ close (to_fds[1]);
+ close (from_fds[0]);
+ close (from_fds[1]);
+ return 1;
+}