Esempio n. 1
0
static struct conf_entry *
parse_source (struct opts *opts, struct conf_entry *conf)
{
  char *host = NULL;
  char *port = NULL;
  char *proxy = NULL;
  /* a source entry:
   * source
   *   host <host>
   *   port <port>
   *   [proxy <proxy>]
   * end
   */
  assert (!strcmp (conf->key, "source"));
  conf = conf->next;
  while (conf && strcmp (conf->key, "end"))
    {
      if (!strcmp (conf->key, "host"))
        host = conf->value;
      else if (!strcmp (conf->key, "port"))
        port = conf->value;
      else if (!strcmp (conf->key, "proxy"))
        proxy = conf->value;
      else
        fatal ("malformed config: '%s' in source stanza", conf->key);
      conf = conf->next;
    }
  if (!conf)
    fatal ("unclosed source stanza");
  if (!host || !port)
    fatal ("incomplete source stanza (needs host, port)");
  add_source_to_conf (opts, host, port, proxy);
  return conf;
}
Esempio n. 2
0
int API
main (int argc, char *argv[], char *envp[])
{
  initalize_syslog ();
  struct state state;
  /* TODO(wad) EVENT_BASE_FLAG_PRECISE_TIMER | EVENT_BASE_FLAG_PRECISE_TIMER */
  struct event_base *base = event_base_new();
  if (!base)
    {
      fatal ("could not allocated new event base");
    }
  /* Add three priority levels:
   * 0 - time saving.  Must be done before any other events are handled.
   * 1 - network synchronization events
   * 2 - any other events (wake, platform, etc)
   */
  event_base_priority_init (base, MAX_EVENT_PRIORITIES);
  memset (&state, 0, sizeof (state));
  set_conf_defaults (&state.opts);
  parse_argv (&state.opts, argc, argv);
  check_conf (&state);
  load_conf (&state.opts);
  check_conf (&state);
  if (!state.opts.sources)
    add_source_to_conf (&state.opts, DEFAULT_HOST, DEFAULT_PORT, DEFAULT_PROXY);
  state.base = base;
  state.envp = envp;
  state.backoff = state.opts.wait_between_tries;
  /* TODO(wad) move this into setup_time_setter */
  /* grab a handle to /dev/rtc for time-setter. */
  if (state.opts.should_sync_hwclock &&
      platform->rtc_open(&state.hwclock))
    {
      pinfo ("can't open hwclock fd");
      state.opts.should_sync_hwclock = 0;
    }
  /* install the SIGCHLD handler for the setter and tlsdate */
  if (setup_sigchld_event (&state, 1))
    {
      error ("Failed to setup SIGCHLD event");
      goto out;
    }
  /* fork off the privileged helper */
  info ("spawning time setting helper . . .");
  if (setup_time_setter (&state))
    {
      error ("could not fork privileged coprocess");
      goto out;
    }
  /* release the hwclock now that the time-setter is running. */
  if (state.opts.should_sync_hwclock)
    {
      platform->rtc_close (&state.hwclock);
    }
  /* drop privileges before touching any untrusted data */
  drop_privs_to (state.opts.user, state.opts.group);
  /* register a signal handler to save time at shutdown */
  if (state.opts.should_save_disk)
    {
      struct event *event = event_new (base, SIGTERM, EV_SIGNAL|EV_PERSIST,
                                       action_sigterm, &state);
      if (!event)
        fatal ("Failed to create SIGTERM event");
      event_priority_set (event, PRI_SAVE);
      event_add (event, NULL);
    }
  if (state.opts.should_dbus && init_dbus (&state))
    {
      error ("Failed to initialize DBus");
      goto out;
    }
  /* Register the tlsdate event before any listeners could show up. */
  state.events[E_TLSDATE] = event_new (base, -1, EV_TIMEOUT,
                                       action_run_tlsdate, &state);
  if (!state.events[E_TLSDATE])
    {
      error ("Failed to create tlsdate event");
      goto out;
    }
  event_priority_set (state.events[E_TLSDATE], PRI_NET);
  /* The timeout and fd will be filled in per-call. */
  if (setup_tlsdate_status (&state))
    {
      error ("Failed to create tlsdate status event");
      goto out;
    }
  /* TODO(wad) Could use a timeout on this to catch setter death? */
  /* EV_READ is for truncation/EPIPE notification */
  state.events[E_SAVE] = event_new (base, state.setter_save_fd,
                                    EV_READ|EV_WRITE, action_sync_and_save,
                                    &state);
  if (!state.events[E_SAVE])
    {
      error ("Failed to create sync & save event");
      goto out;
    }
  event_priority_set (state.events[E_SAVE], PRI_SAVE);
  /* Start by grabbing the system time. */
  state.last_sync_type = SYNC_TYPE_RTC;
  state.last_time = time (NULL);
  /* If possible, grab disk time and check the two. */
  if (state.opts.should_load_disk)
    {
      time_t disk_time = state.last_time;
      if (!load_disk_timestamp (state.timestamp_path, &disk_time))
        {
          info ("disk timestamp available: yes");
          if (!is_sane_time (state.last_time) ||
              state.last_time < disk_time)
            {
              state.last_sync_type = SYNC_TYPE_DISK;
              state.last_time = disk_time;
            }
        }
      else
        {
          info ("disk timestamp available: no");
        }
    }
  if (!is_sane_time (state.last_time))
    {
      state.last_sync_type = SYNC_TYPE_BUILD;
      state.last_time = RECENT_COMPILE_DATE + 1;
    }
  /* Save and announce the initial time source. */
  trigger_event (&state, E_SAVE, -1);
  info ("initial time sync type: %s", sync_type_str (state.last_sync_type));
  /* Initialize platform specific loop behavior */
  if (platform_init_cros (&state))
    {
      error ("Failed to initialize platform code");
      goto out;
    }
  if (setup_event_route_up (&state))
    {
      error ("Failed to setup route up monitoring");
      goto out;
    }
  if (setup_event_timer_sync (&state))
    {
      error ("Failed to setup a timer event");
      goto out;
    }
  if (setup_event_timer_continuity (&state))
    {
      error ("Failed to setup continuity timer");
      goto out;
    }
  /* Add a forced sync event to the event list. */
  action_kickoff_time_sync (-1, EV_TIMEOUT, &state);
  info ("Entering dispatch . . .");
  event_base_dispatch (base);
  info ("tlsdated terminating gracefully");
out:
  return cleanup_main (&state);
}
Esempio n. 3
0
int API
main (int argc, char *argv[], char *envp[])
{
  struct routeup rtc;
  int hwclock_fd = -1;
  time_t last_success = 0;
  struct opts opts;
  int wait_time = 0;

  set_conf_defaults(&opts);
  parse_argv(&opts, argc, argv);
  check_conf(&opts);
  load_conf(&opts);
  check_conf(&opts);
  if (!opts.sources)
    add_source_to_conf(&opts, DEFAULT_HOST, DEFAULT_PORT, DEFAULT_PROXY);

  /* grab a handle to /dev/rtc for sync_hwclock() */
  if (opts.should_sync_hwclock && (hwclock_fd = open (DEFAULT_RTC_DEVICE, O_RDONLY)) < 0)
    {
      pinfo ("can't open hwclock fd");
      opts.should_sync_hwclock = 0;
    }

  /* set up a netlink context if we need one */
  if (opts.should_netlink && routeup_setup (&rtc))
    pfatal ("Can't open netlink socket");

  if (!is_sane_time (time (NULL)))
    {
      struct timeval tv = { 0, 0 };
      /*
       * If the time is before the build timestamp, we're probably on
       * a system with a broken rtc. Try loading the timestamp off
       * disk.
       */
      tv.tv_sec = RECENT_COMPILE_DATE;
      if (opts.should_load_disk &&
    load_disk_timestamp (timestamp_path, &tv.tv_sec))
  pinfo ("can't load disk timestamp");
      if (!opts.dry_run && settimeofday (&tv, NULL))
  pfatal ("settimeofday() failed");
      dbus_announce();
      /*
       * don't save here - we either just loaded this time or used the
       * default time, and neither of those are good to save
       */
      sync_and_save (hwclock_fd, opts.should_sync_hwclock, 0);
    }

  /* register a signal handler to save time at shutdown */
  if (opts.should_save_disk)
    signal (SIGTERM, sigterm_handler);

  /*
   * Try once right away. If we fail, wait for a route to appear, then try
   * for a while; repeat whenever another route appears. Try until we
   * succeed.
   */
  if (!tlsdate (&opts, envp)) {
    last_success = time (NULL);
    sync_and_save (hwclock_fd, opts.should_sync_hwclock, opts.should_save_disk);
    dbus_announce();
  }

  /*
   * Loop until we catch a fatal signal or routeup_once() fails. We run
   * tlsdate at least once a day, but possibly as often as routes come up;
   * this should handle cases like a VPN being brought up and down
   * periodically.
   */
  wait_time = add_jitter(opts.steady_state_interval, opts.jitter);
  while (wait_for_event (&rtc, opts.should_netlink, wait_time) >= 0)
    {
      /*
       * If a route just came up, run tlsdate; if it
       * succeeded, then we're good and can keep time locally
       * from now on.
       */
      int i;
      int backoff = opts.wait_between_tries;
      wait_time = add_jitter(opts.steady_state_interval, opts.jitter);
      if (time (NULL) - last_success < opts.min_steady_state_interval)
        continue;
      for (i = 0; i < opts.max_tries && tlsdate (&opts, envp); ++i) {
        if (backoff < 1)
          fatal ("backoff too small? %d", backoff);
        sleep (backoff);
        if (backoff < MAX_SANE_BACKOFF)
          backoff *= 2;
      }
      if (i != opts.max_tries)
      {
        last_success = time (NULL);
        info ("tlsdate succeeded");
        sync_and_save (hwclock_fd, opts.should_sync_hwclock, opts.should_save_disk);
        dbus_announce();
      }
    }

  return 1;
}