+static int sntp_clock_watch(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
+ SNTPContext *sntp = userdata;
+
+ assert(sntp);
+ assert(sntp->event_receive);
+
+ /* rearm timer */
+ sntp_clock_watch_setup(sntp);
+
+ /* skip our own jumps */
+ if (sntp->jumped) {
+ sntp->jumped = false;
+ return 0;
+ }
+
+ /* resync */
+ log_info("System time changed, resyncing.");
+ sntp->poll_resync = true;
+ sntp_send_request(sntp);
+
+ return 0;
+}
+
+/* wake up when the system time changes underneath us */
+static int sntp_clock_watch_setup(SNTPContext *sntp) {
+ struct itimerspec its = { .it_value.tv_sec = TIME_T_MAX };
+ _cleanup_close_ int fd = -1;
+ sd_event *e;
+ sd_event_source *source;
+ int r;
+
+ assert(sntp);
+ assert(sntp->event_receive);
+
+ fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
+ if (fd < 0) {
+ log_error("Failed to create timerfd: %m");
+ return -errno;
+ }
+
+ if (timerfd_settime(fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0) {
+ log_error("Failed to set up timerfd: %m");
+ return -errno;
+ }
+
+ e = sd_event_source_get_event(sntp->event_receive);
+ r = sd_event_add_io(e, &source, fd, EPOLLIN, sntp_clock_watch, sntp);
+ if (r < 0) {
+ log_error("Failed to create clock watch event source: %s", strerror(-r));
+ return r;
+ }
+
+ sd_event_source_unref(sntp->event_clock_watch);
+ sntp->event_clock_watch = source;
+
+ if (sntp->clock_watch_fd >= 0)
+ close(sntp->clock_watch_fd);
+ sntp->clock_watch_fd = fd;
+ fd = -1;
+
+ return 0;
+}
+