Search code examples
clinuxntp

How do I check whether my system's clock is synchronized to a NTP server?


I have an application on a Linux system (Ubuntu Server) that needs to know whether the current system clock has been synchronized to a NTP server. While I could check timedatectl's output for System clock synchronized: yes, this seems very brittle, especially since timedatectl's human readable output might change in the future.

However, systemd seems to be full of DBus interfaces, so I suspect that there might be a way to check there. Either way, I'm looking for a bool is_ntp_synchronized().

Is there any way to simply check whether the system clock is synchronized without starting another process?


Solution

  • Linux provides adjtimex, which also gets used by systemd. You can check various fields to determine if you're still synchronized. A non-negative return value unequal to TIME_ERROR might be your forte, although you might use the maxerror or other fields to check the clock's quality instead.

    #include <stdio.h>
    #include <sys/timex.h>
    
    int main()
    {
        struct timex timex_info = {};
        timex_info.modes = 0;         /* explicitly don't adjust any time parameters */
    
        int ntp_result = ntp_adjtime(&timex_info);
    
        printf("Max       error: %9ld (us)\n", timex_info.maxerror);
        printf("Estimated error: %9ld (us)\n", timex_info.esterror);
        printf("Clock precision: %9ld (us)\n", timex_info.precision);
        printf("Jitter:          %9ld (%s)\n", timex_info.jitter,
               (timex_info.status & STA_NANO) ? "ns" : "us");
        printf("Synchronized:    %9s\n", 
               (ntp_result >= 0 && ntp_result != TIME_ERROR) ? "yes" : "no");
        return 0;
    }
    

    Note that systemd explicitly ignores the reported result (except for errors) and instead checks that the timex_info.maxerror value hasn't become more than 16 seconds.

    This interface has also been provided since the pre-git times. As such, it's guaranteed to be stable, as it might otherwise break Linux's don't-break-userspace-policy.