Home | History | Annotate | Download | only in events
      1 /*
      2  * time_set.c - time setting functions
      3  * Copyright (c) 2013 The Chromium Authors. All rights reserved.
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "config.h"
      9 
     10 #include <assert.h>
     11 #include <errno.h>
     12 #include <fcntl.h>
     13 #include <signal.h>
     14 #include <stdarg.h>
     15 #include <stdint.h>
     16 #include <stdlib.h>
     17 #include <string.h>
     18 #include <sys/wait.h>
     19 #include <sys/types.h>
     20 #include <time.h>
     21 #include <unistd.h>
     22 
     23 #include <event2/event.h>
     24 
     25 #include "src/conf.h"
     26 #include "src/dbus.h"
     27 #include "src/tlsdate.h"
     28 #include "src/util.h"
     29 
     30 void
     31 handle_time_setter (struct state *state, int status)
     32 {
     33   switch (status)
     34     {
     35     case SETTER_BAD_TIME:
     36       info ("[event:%s] time setter received bad time", __func__);
     37       /* This is the leaf node. Failure means that our source
     38        * tried to walk back in time.
     39        */
     40       state->last_sync_type = SYNC_TYPE_RTC;
     41       state->last_time = time (NULL);
     42       break;
     43     case SETTER_TIME_SET:
     44       info ("[event:%s] time set from the %s (%ld)",
     45             __func__, sync_type_str (state->last_sync_type), state->last_time);
     46       if (state->last_sync_type == SYNC_TYPE_NET)
     47         {
     48           /* Update the delta so it doesn't fire again immediately. */
     49           state->clock_delta = 0;
     50           check_continuity (&state->clock_delta);
     51           /* Reset the sources list! */
     52           state->opts.cur_source = NULL;
     53         }
     54       /* Share our success. */
     55       if (state->opts.should_dbus)
     56         dbus_announce (state);
     57       break;
     58     case SETTER_NO_SBOX:
     59       error ("[event:%s] time setter failed to sandbox", __func__);
     60       break;
     61     case SETTER_EXIT:
     62       error ("[event:%s] time setter exited gracefully", __func__);
     63       break;
     64     case SETTER_SET_ERR:
     65       error ("[event:%s] time setter could not settimeofday()", __func__);
     66       break;
     67     case SETTER_NO_RTC:
     68       error ("[event:%s] time setter could sync rtc", __func__);
     69       break;
     70     case SETTER_NO_SAVE:
     71       error ("[event:%s] time setter could not open save file", __func__);
     72       break;
     73     case SETTER_READ_ERR:
     74       error ("[event:%s] time setter could not read time", __func__);
     75       break;
     76     default:
     77       error ("[event:%s] received bogus status from time setter: %d",
     78              __func__, status);
     79       exit (status);
     80     }
     81 }
     82 
     83 void
     84 action_time_set (evutil_socket_t fd, short what, void *arg)
     85 {
     86   struct state *state = arg;
     87   int status = -1;
     88   ssize_t bytes = 0;
     89   verb_debug ("[event:%s] fired", __func__);
     90   bytes = IGNORE_EINTR (read (fd, &status, sizeof (status)));
     91   if (bytes == -1 && errno == EAGAIN)
     92     return;  /* Catch next wake up */
     93   /* Catch the rest of the errnos and any truncation. */
     94   if (bytes != sizeof (status))
     95     {
     96       /* Truncation of an int over a pipe shouldn't happen except in
     97        * terminal cases.
     98        */
     99       perror ("[event:%s] time setter pipe truncated! (%d)", __func__,
    100               bytes);
    101       /* Let SIGCHLD do the teardown. */
    102       close (fd);
    103       return;
    104     }
    105   handle_time_setter (state, status);
    106 }
    107 
    108 int
    109 setup_time_setter (struct state *state)
    110 {
    111   struct event *event;
    112   int to_fds[2];
    113   int from_fds[2];
    114   if (pipe (to_fds) < 0)
    115     {
    116       perror ("pipe failed");
    117       return 1;
    118     }
    119   if (pipe (from_fds) < 0)
    120     {
    121       perror ("pipe failed");
    122       close (to_fds[0]);
    123       close (to_fds[1]);
    124       return 1;
    125     }
    126   /* The fd that tlsdated will write to */
    127   state->setter_save_fd = to_fds[1];
    128   state->setter_notify_fd = from_fds[0];
    129   /* Make the notifications fd non-blocking. */
    130   if (fcntl (from_fds[0], F_SETFL, O_NONBLOCK) < 0)
    131     {
    132       perror ("notifier_fd fcntl(O_NONBLOCK) failed");
    133       goto close_and_fail;
    134     }
    135   /* Make writes non-blocking */
    136   if (fcntl (to_fds[1], F_SETFL, O_NONBLOCK) < 0)
    137     {
    138       perror ("save_fd fcntl(O_NONBLOCK) failed");
    139       goto close_and_fail;
    140     }
    141   event = event_new (state->base, from_fds[0], EV_READ|EV_PERSIST,
    142                      action_time_set, state);
    143   if (!event)
    144     {
    145       error ("Failed to allocate tlsdate setter event");
    146       goto close_and_fail;
    147     }
    148   event_priority_set (event, PRI_NET);
    149   event_add (event, NULL);
    150   /* fork */
    151   state->setter_pid = fork();
    152   if (state->setter_pid < 0)
    153     {
    154       perror ("fork()ing the time setter failed");
    155       goto close_and_fail;
    156     }
    157   if (state->setter_pid == 0)
    158     {
    159       close (to_fds[1]);
    160       close (from_fds[0]);
    161       time_setter_coprocess (to_fds[0], from_fds[1], state);
    162       _exit (1);
    163     }
    164   close (from_fds[1]);
    165   close (to_fds[0]);
    166   return 0;
    167 
    168 close_and_fail:
    169   close (to_fds[0]);
    170   close (to_fds[1]);
    171   close (from_fds[0]);
    172   close (from_fds[1]);
    173   return 1;
    174 }
    175