LCOV - code coverage report
Current view: top level - timedate - timedatectl.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 25 415 6.0 %
Date: 2019-08-22 15:41:25 Functions: 4 27 14.8 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <getopt.h>
       4             : #include <locale.h>
       5             : #include <math.h>
       6             : #include <stdbool.h>
       7             : #include <stdlib.h>
       8             : 
       9             : #include "sd-bus.h"
      10             : 
      11             : #include "bus-error.h"
      12             : #include "bus-util.h"
      13             : #include "in-addr-util.h"
      14             : #include "main-func.h"
      15             : #include "pager.h"
      16             : #include "parse-util.h"
      17             : #include "pretty-print.h"
      18             : #include "spawn-polkit-agent.h"
      19             : #include "sparse-endian.h"
      20             : #include "string-table.h"
      21             : #include "strv.h"
      22             : #include "terminal-util.h"
      23             : #include "util.h"
      24             : #include "verbs.h"
      25             : 
      26             : static PagerFlags arg_pager_flags = 0;
      27             : static bool arg_ask_password = true;
      28             : static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
      29             : static char *arg_host = NULL;
      30             : static bool arg_adjust_system_clock = false;
      31             : static bool arg_monitor = false;
      32             : static char **arg_property = NULL;
      33             : static bool arg_value = false;
      34             : static bool arg_all = false;
      35             : 
      36             : typedef struct StatusInfo {
      37             :         usec_t time;
      38             :         const char *timezone;
      39             : 
      40             :         usec_t rtc_time;
      41             :         bool rtc_local;
      42             : 
      43             :         bool ntp_capable;
      44             :         bool ntp_active;
      45             :         bool ntp_synced;
      46             : } StatusInfo;
      47             : 
      48           0 : static void print_status_info(const StatusInfo *i) {
      49           0 :         const char *old_tz = NULL, *tz;
      50           0 :         bool have_time = false;
      51             :         char a[LINE_MAX];
      52             :         struct tm tm;
      53             :         time_t sec;
      54             :         size_t n;
      55             :         int r;
      56             : 
      57           0 :         assert(i);
      58             : 
      59             :         /* Save the old $TZ */
      60           0 :         tz = getenv("TZ");
      61           0 :         if (tz)
      62           0 :                 old_tz = strdupa(tz);
      63             : 
      64             :         /* Set the new $TZ */
      65           0 :         if (setenv("TZ", isempty(i->timezone) ? "UTC" : i->timezone, true) < 0)
      66           0 :                 log_warning_errno(errno, "Failed to set TZ environment variable, ignoring: %m");
      67             :         else
      68           0 :                 tzset();
      69             : 
      70           0 :         if (i->time != 0) {
      71           0 :                 sec = (time_t) (i->time / USEC_PER_SEC);
      72           0 :                 have_time = true;
      73           0 :         } else if (IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_MACHINE)) {
      74           0 :                 sec = time(NULL);
      75           0 :                 have_time = true;
      76             :         } else
      77           0 :                 log_warning("Could not get time from timedated and not operating locally, ignoring.");
      78             : 
      79           0 :         if (have_time) {
      80           0 :                 n = strftime(a, sizeof a, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&sec, &tm));
      81           0 :                 printf("               Local time: %s\n", n > 0 ? a : "n/a");
      82             : 
      83           0 :                 n = strftime(a, sizeof a, "%a %Y-%m-%d %H:%M:%S UTC", gmtime_r(&sec, &tm));
      84           0 :                 printf("           Universal time: %s\n", n > 0 ? a : "n/a");
      85             :         } else {
      86           0 :                 printf("               Local time: %s\n", "n/a");
      87           0 :                 printf("           Universal time: %s\n", "n/a");
      88             :         }
      89             : 
      90           0 :         if (i->rtc_time > 0) {
      91             :                 time_t rtc_sec;
      92             : 
      93           0 :                 rtc_sec = (time_t) (i->rtc_time / USEC_PER_SEC);
      94           0 :                 n = strftime(a, sizeof a, "%a %Y-%m-%d %H:%M:%S", gmtime_r(&rtc_sec, &tm));
      95           0 :                 printf("                 RTC time: %s\n", n > 0 ? a : "n/a");
      96             :         } else
      97           0 :                 printf("                 RTC time: %s\n", "n/a");
      98             : 
      99           0 :         if (have_time)
     100           0 :                 n = strftime(a, sizeof a, "%Z, %z", localtime_r(&sec, &tm));
     101             : 
     102             :         /* Restore the $TZ */
     103           0 :         if (old_tz)
     104           0 :                 r = setenv("TZ", old_tz, true);
     105             :         else
     106           0 :                 r = unsetenv("TZ");
     107           0 :         if (r < 0)
     108           0 :                 log_warning_errno(errno, "Failed to set TZ environment variable, ignoring: %m");
     109             :         else
     110           0 :                 tzset();
     111             : 
     112           0 :         printf("                Time zone: %s (%s)\n"
     113             :                "System clock synchronized: %s\n"
     114             :                "              NTP service: %s\n"
     115             :                "          RTC in local TZ: %s\n",
     116           0 :                strna(i->timezone), have_time && n > 0 ? a : "n/a",
     117           0 :                yes_no(i->ntp_synced),
     118           0 :                i->ntp_capable ? (i->ntp_active ? "active" : "inactive") : "n/a",
     119           0 :                yes_no(i->rtc_local));
     120             : 
     121           0 :         if (i->rtc_local)
     122           0 :                 printf("\n%s"
     123             :                        "Warning: The system is configured to read the RTC time in the local time zone.\n"
     124             :                        "         This mode cannot be fully supported. It will create various problems\n"
     125             :                        "         with time zone changes and daylight saving time adjustments. The RTC\n"
     126             :                        "         time is never updated, it relies on external facilities to maintain it.\n"
     127             :                        "         If at all possible, use RTC in UTC by calling\n"
     128             :                        "         'timedatectl set-local-rtc 0'.%s\n", ansi_highlight(), ansi_normal());
     129           0 : }
     130             : 
     131           0 : static int show_status(int argc, char **argv, void *userdata) {
     132           0 :         StatusInfo info = {};
     133             :         static const struct bus_properties_map map[]  = {
     134             :                 { "Timezone",        "s", NULL, offsetof(StatusInfo, timezone)    },
     135             :                 { "LocalRTC",        "b", NULL, offsetof(StatusInfo, rtc_local)   },
     136             :                 { "NTP",             "b", NULL, offsetof(StatusInfo, ntp_active)  },
     137             :                 { "CanNTP",          "b", NULL, offsetof(StatusInfo, ntp_capable) },
     138             :                 { "NTPSynchronized", "b", NULL, offsetof(StatusInfo, ntp_synced)  },
     139             :                 { "TimeUSec",        "t", NULL, offsetof(StatusInfo, time)        },
     140             :                 { "RTCTimeUSec",     "t", NULL, offsetof(StatusInfo, rtc_time)    },
     141             :                 {}
     142             :         };
     143             : 
     144           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     145           0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
     146           0 :         sd_bus *bus = userdata;
     147             :         int r;
     148             : 
     149           0 :         assert(bus);
     150             : 
     151           0 :         r = bus_map_all_properties(bus,
     152             :                                    "org.freedesktop.timedate1",
     153             :                                    "/org/freedesktop/timedate1",
     154             :                                    map,
     155             :                                    BUS_MAP_BOOLEAN_AS_BOOL,
     156             :                                    &error,
     157             :                                    &m,
     158             :                                    &info);
     159           0 :         if (r < 0)
     160           0 :                 return log_error_errno(r, "Failed to query server: %s", bus_error_message(&error, r));
     161             : 
     162           0 :         print_status_info(&info);
     163             : 
     164           0 :         return r;
     165             : }
     166             : 
     167           0 : static int show_properties(int argc, char **argv, void *userdata) {
     168           0 :         sd_bus *bus = userdata;
     169             :         int r;
     170             : 
     171           0 :         assert(bus);
     172             : 
     173           0 :         r = bus_print_all_properties(bus,
     174             :                                      "org.freedesktop.timedate1",
     175             :                                      "/org/freedesktop/timedate1",
     176             :                                      NULL,
     177             :                                      arg_property,
     178             :                                      arg_value,
     179             :                                      arg_all,
     180             :                                      NULL);
     181           0 :         if (r < 0)
     182           0 :                 return bus_log_parse_error(r);
     183             : 
     184           0 :         return 0;
     185             : }
     186             : 
     187           0 : static int set_time(int argc, char **argv, void *userdata) {
     188           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     189           0 :         bool relative = false, interactive = arg_ask_password;
     190           0 :         sd_bus *bus = userdata;
     191             :         usec_t t;
     192             :         int r;
     193             : 
     194           0 :         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
     195             : 
     196           0 :         r = parse_timestamp(argv[1], &t);
     197           0 :         if (r < 0)
     198           0 :                 return log_error_errno(r, "Failed to parse time specification '%s': %m", argv[1]);
     199             : 
     200           0 :         r = sd_bus_call_method(bus,
     201             :                                "org.freedesktop.timedate1",
     202             :                                "/org/freedesktop/timedate1",
     203             :                                "org.freedesktop.timedate1",
     204             :                                "SetTime",
     205             :                                &error,
     206             :                                NULL,
     207             :                                "xbb", (int64_t) t, relative, interactive);
     208           0 :         if (r < 0)
     209           0 :                 return log_error_errno(r, "Failed to set time: %s", bus_error_message(&error, r));
     210             : 
     211           0 :         return 0;
     212             : }
     213             : 
     214           0 : static int set_timezone(int argc, char **argv, void *userdata) {
     215           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     216           0 :         sd_bus *bus = userdata;
     217             :         int r;
     218             : 
     219           0 :         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
     220             : 
     221           0 :         r = sd_bus_call_method(bus,
     222             :                                "org.freedesktop.timedate1",
     223             :                                "/org/freedesktop/timedate1",
     224             :                                "org.freedesktop.timedate1",
     225             :                                "SetTimezone",
     226             :                                &error,
     227             :                                NULL,
     228           0 :                                "sb", argv[1], arg_ask_password);
     229           0 :         if (r < 0)
     230           0 :                 return log_error_errno(r, "Failed to set time zone: %s", bus_error_message(&error, r));
     231             : 
     232           0 :         return 0;
     233             : }
     234             : 
     235           0 : static int set_local_rtc(int argc, char **argv, void *userdata) {
     236           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     237           0 :         sd_bus *bus = userdata;
     238             :         int r, b;
     239             : 
     240           0 :         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
     241             : 
     242           0 :         b = parse_boolean(argv[1]);
     243           0 :         if (b < 0)
     244           0 :                 return log_error_errno(b, "Failed to parse local RTC setting '%s': %m", argv[1]);
     245             : 
     246           0 :         r = sd_bus_call_method(bus,
     247             :                                "org.freedesktop.timedate1",
     248             :                                "/org/freedesktop/timedate1",
     249             :                                "org.freedesktop.timedate1",
     250             :                                "SetLocalRTC",
     251             :                                &error,
     252             :                                NULL,
     253             :                                "bbb", b, arg_adjust_system_clock, arg_ask_password);
     254           0 :         if (r < 0)
     255           0 :                 return log_error_errno(r, "Failed to set local RTC: %s", bus_error_message(&error, r));
     256             : 
     257           0 :         return 0;
     258             : }
     259             : 
     260           0 : static int set_ntp(int argc, char **argv, void *userdata) {
     261           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     262           0 :         sd_bus *bus = userdata;
     263             :         int b, r;
     264             : 
     265           0 :         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
     266             : 
     267           0 :         b = parse_boolean(argv[1]);
     268           0 :         if (b < 0)
     269           0 :                 return log_error_errno(b, "Failed to parse NTP setting '%s': %m", argv[1]);
     270             : 
     271           0 :         r = sd_bus_call_method(bus,
     272             :                                "org.freedesktop.timedate1",
     273             :                                "/org/freedesktop/timedate1",
     274             :                                "org.freedesktop.timedate1",
     275             :                                "SetNTP",
     276             :                                &error,
     277             :                                NULL,
     278             :                                "bb", b, arg_ask_password);
     279           0 :         if (r < 0)
     280           0 :                 return log_error_errno(r, "Failed to set ntp: %s", bus_error_message(&error, r));
     281             : 
     282           0 :         return 0;
     283             : }
     284             : 
     285           0 : static int list_timezones(int argc, char **argv, void *userdata) {
     286           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     287           0 :         sd_bus *bus = userdata;
     288           0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
     289             :         int r;
     290             :         char** zones;
     291             : 
     292           0 :         r = sd_bus_call_method(bus,
     293             :                                "org.freedesktop.timedate1",
     294             :                                "/org/freedesktop/timedate1",
     295             :                                "org.freedesktop.timedate1",
     296             :                                "ListTimezones",
     297             :                                &error,
     298             :                                &reply,
     299             :                                NULL);
     300           0 :         if (r < 0)
     301           0 :                 return log_error_errno(r, "Failed to request list of time zones: %s",
     302             :                                        bus_error_message(&error, r));
     303             : 
     304           0 :         r = sd_bus_message_read_strv(reply, &zones);
     305           0 :         if (r < 0)
     306           0 :                 return bus_log_parse_error(r);
     307             : 
     308           0 :         (void) pager_open(arg_pager_flags);
     309           0 :         strv_print(zones);
     310             : 
     311           0 :         return 0;
     312             : }
     313             : 
     314             : typedef struct NTPStatusInfo {
     315             :         const char *server_name;
     316             :         char *server_address;
     317             :         usec_t poll_interval, poll_max, poll_min;
     318             :         usec_t root_distance_max;
     319             : 
     320             :         uint32_t leap, version, mode, stratum;
     321             :         int32_t precision;
     322             :         usec_t root_delay, root_dispersion;
     323             :         union {
     324             :                 char str[5];
     325             :                 uint32_t val;
     326             :         } reference;
     327             :         usec_t origin, recv, trans, dest;
     328             : 
     329             :         bool spike;
     330             :         uint64_t packet_count;
     331             :         usec_t jitter;
     332             : 
     333             :         int64_t freq;
     334             : } NTPStatusInfo;
     335             : 
     336           0 : static void ntp_status_info_clear(NTPStatusInfo *p) {
     337           0 :         p->server_address = mfree(p->server_address);
     338           0 : }
     339             : 
     340             : static const char * const ntp_leap_table[4] = {
     341             :         [0] = "normal",
     342             :         [1] = "last minute of the day has 61 seconds",
     343             :         [2] = "last minute of the day has 59 seconds",
     344             :         [3] = "not synchronized",
     345             : };
     346             : 
     347             : #pragma GCC diagnostic push
     348             : #pragma GCC diagnostic ignored "-Wtype-limits"
     349           0 : DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(ntp_leap, uint32_t);
     350             : #pragma GCC diagnostic pop
     351             : 
     352           0 : static void print_ntp_status_info(NTPStatusInfo *i) {
     353             :         char ts[FORMAT_TIMESPAN_MAX], tmin[FORMAT_TIMESPAN_MAX], tmax[FORMAT_TIMESPAN_MAX];
     354             :         usec_t delay, t14, t23, offset, root_distance;
     355             :         bool offset_sign;
     356             : 
     357           0 :         assert(i);
     358             : 
     359             :         /*
     360             :          * "Timestamp Name          ID   When Generated
     361             :          *  ------------------------------------------------------------
     362             :          *  Originate Timestamp     T1   time request sent by client
     363             :          *  Receive Timestamp       T2   time request received by server
     364             :          *  Transmit Timestamp      T3   time reply sent by server
     365             :          *  Destination Timestamp   T4   time reply received by client
     366             :          *
     367             :          *  The round-trip delay, d, and system clock offset, t, are defined as:
     368             :          *  d = (T4 - T1) - (T3 - T2)     t = ((T2 - T1) + (T3 - T4)) / 2"
     369             :          */
     370             : 
     371           0 :         printf("       Server: %s (%s)\n",
     372             :                i->server_address, i->server_name);
     373           0 :         printf("Poll interval: %s (min: %s; max %s)\n",
     374             :                format_timespan(ts, sizeof(ts), i->poll_interval, 0),
     375             :                format_timespan(tmin, sizeof(tmin), i->poll_min, 0),
     376             :                format_timespan(tmax, sizeof(tmax), i->poll_max, 0));
     377             : 
     378           0 :         if (i->packet_count == 0) {
     379           0 :                 printf(" Packet count: 0\n");
     380           0 :                 return;
     381             :         }
     382             : 
     383           0 :         if (i->dest < i->origin || i->trans < i->recv || i->dest - i->origin < i->trans - i->recv) {
     384           0 :                 log_error("Invalid NTP response");
     385           0 :                 return;
     386             :         }
     387             : 
     388           0 :         delay = (i->dest - i->origin) - (i->trans - i->recv);
     389             : 
     390           0 :         t14 = i->origin + i->dest;
     391           0 :         t23 = i->recv + i->trans;
     392           0 :         offset_sign = t14 < t23;
     393           0 :         offset = (offset_sign ? t23 - t14 : t14 - t23) / 2;
     394             : 
     395           0 :         root_distance = i->root_delay / 2 + i->root_dispersion;
     396             : 
     397           0 :         printf("         Leap: %s\n"
     398             :                "      Version: %" PRIu32 "\n"
     399             :                "      Stratum: %" PRIu32 "\n",
     400             :                ntp_leap_to_string(i->leap),
     401             :                i->version,
     402             :                i->stratum);
     403           0 :         if (i->stratum <= 1)
     404           0 :                 printf("    Reference: %s\n", i->reference.str);
     405             :         else
     406           0 :                 printf("    Reference: %" PRIX32 "\n", be32toh(i->reference.val));
     407           0 :         printf("    Precision: %s (%" PRIi32 ")\n",
     408           0 :                format_timespan(ts, sizeof(ts), DIV_ROUND_UP((nsec_t) (exp2(i->precision) * NSEC_PER_SEC), NSEC_PER_USEC), 0),
     409             :                i->precision);
     410           0 :         printf("Root distance: %s (max: %s)\n",
     411             :                format_timespan(ts, sizeof(ts), root_distance, 0),
     412             :                format_timespan(tmax, sizeof(tmax), i->root_distance_max, 0));
     413           0 :         printf("       Offset: %s%s\n",
     414             :                offset_sign ? "+" : "-",
     415             :                format_timespan(ts, sizeof(ts), offset, 0));
     416           0 :         printf("        Delay: %s\n",
     417             :                format_timespan(ts, sizeof(ts), delay, 0));
     418           0 :         printf("       Jitter: %s\n",
     419             :                format_timespan(ts, sizeof(ts), i->jitter, 0));
     420           0 :         printf(" Packet count: %" PRIu64 "\n", i->packet_count);
     421             : 
     422           0 :         if (!i->spike)
     423           0 :                 printf("    Frequency: %+.3fppm\n",
     424           0 :                        (double) i->freq / 0x10000);
     425             : }
     426             : 
     427           0 : static int map_server_address(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
     428           0 :         char **p = (char **) userdata;
     429             :         const void *d;
     430             :         int family, r;
     431             :         size_t sz;
     432             : 
     433           0 :         assert(p);
     434             : 
     435           0 :         r = sd_bus_message_enter_container(m, 'r', "iay");
     436           0 :         if (r < 0)
     437           0 :                 return r;
     438             : 
     439           0 :         r = sd_bus_message_read(m, "i", &family);
     440           0 :         if (r < 0)
     441           0 :                 return r;
     442             : 
     443           0 :         r = sd_bus_message_read_array(m, 'y', &d, &sz);
     444           0 :         if (r < 0)
     445           0 :                 return r;
     446             : 
     447           0 :         r = sd_bus_message_exit_container(m);
     448           0 :         if (r < 0)
     449           0 :                 return r;
     450             : 
     451           0 :         if (sz == 0 && family == AF_UNSPEC) {
     452           0 :                 *p = mfree(*p);
     453           0 :                 return 0;
     454             :         }
     455             : 
     456           0 :         if (!IN_SET(family, AF_INET, AF_INET6))
     457           0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     458             :                                        "Unknown address family %i", family);
     459             : 
     460           0 :         if (sz != FAMILY_ADDRESS_SIZE(family))
     461           0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     462             :                                        "Invalid address size");
     463             : 
     464           0 :         r = in_addr_to_string(family, d, p);
     465           0 :         if (r < 0)
     466           0 :                 return r;
     467             : 
     468           0 :         return 0;
     469             : }
     470             : 
     471           0 : static int map_ntp_message(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
     472           0 :         NTPStatusInfo *p = userdata;
     473             :         const void *d;
     474             :         size_t sz;
     475             :         int32_t b;
     476             :         int r;
     477             : 
     478           0 :         assert(p);
     479             : 
     480           0 :         r = sd_bus_message_enter_container(m, 'r', "uuuuittayttttbtt");
     481           0 :         if (r < 0)
     482           0 :                 return r;
     483             : 
     484           0 :         r = sd_bus_message_read(m, "uuuuitt",
     485             :                                 &p->leap, &p->version, &p->mode, &p->stratum, &p->precision,
     486             :                                 &p->root_delay, &p->root_dispersion);
     487           0 :         if (r < 0)
     488           0 :                 return r;
     489             : 
     490           0 :         r = sd_bus_message_read_array(m, 'y', &d, &sz);
     491           0 :         if (r < 0)
     492           0 :                 return r;
     493             : 
     494           0 :         r = sd_bus_message_read(m, "ttttbtt",
     495             :                                 &p->origin, &p->recv, &p->trans, &p->dest,
     496             :                                 &b, &p->packet_count, &p->jitter);
     497           0 :         if (r < 0)
     498           0 :                 return r;
     499             : 
     500           0 :         r = sd_bus_message_exit_container(m);
     501           0 :         if (r < 0)
     502           0 :                 return r;
     503             : 
     504           0 :         if (sz != 4)
     505           0 :                 return -EINVAL;
     506             : 
     507           0 :         memcpy(p->reference.str, d, sz);
     508             : 
     509           0 :         p->spike = b;
     510             : 
     511           0 :         return 0;
     512             : }
     513             : 
     514           0 : static int show_timesync_status_once(sd_bus *bus) {
     515             :         static const struct bus_properties_map map_timesync[]  = {
     516             :                 { "ServerName",           "s",                  NULL,               offsetof(NTPStatusInfo, server_name)       },
     517             :                 { "ServerAddress",        "(iay)",              map_server_address, offsetof(NTPStatusInfo, server_address)    },
     518             :                 { "PollIntervalUSec",     "t",                  NULL,               offsetof(NTPStatusInfo, poll_interval)     },
     519             :                 { "PollIntervalMinUSec",  "t",                  NULL,               offsetof(NTPStatusInfo, poll_min)          },
     520             :                 { "PollIntervalMaxUSec",  "t",                  NULL,               offsetof(NTPStatusInfo, poll_max)          },
     521             :                 { "RootDistanceMaxUSec",  "t",                  NULL,               offsetof(NTPStatusInfo, root_distance_max) },
     522             :                 { "NTPMessage",           "(uuuuittayttttbtt)", map_ntp_message,    0                                          },
     523             :                 { "Frequency",            "x",                  NULL,               offsetof(NTPStatusInfo, freq)              },
     524             :                 {}
     525             :         };
     526           0 :         _cleanup_(ntp_status_info_clear) NTPStatusInfo info = {};
     527           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     528           0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
     529             :         int r;
     530             : 
     531           0 :         assert(bus);
     532             : 
     533           0 :         r = bus_map_all_properties(bus,
     534             :                                    "org.freedesktop.timesync1",
     535             :                                    "/org/freedesktop/timesync1",
     536             :                                    map_timesync,
     537             :                                    BUS_MAP_BOOLEAN_AS_BOOL,
     538             :                                    &error,
     539             :                                    &m,
     540             :                                    &info);
     541           0 :         if (r < 0)
     542           0 :                 return log_error_errno(r, "Failed to query server: %s", bus_error_message(&error, r));
     543             : 
     544           0 :         if (arg_monitor && !terminal_is_dumb())
     545           0 :                 fputs(ANSI_HOME_CLEAR, stdout);
     546             : 
     547           0 :         print_ntp_status_info(&info);
     548             : 
     549           0 :         return 0;
     550             : }
     551             : 
     552           0 : static int on_properties_changed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
     553             :         const char *name;
     554             :         int r;
     555             : 
     556           0 :         assert(m);
     557             : 
     558           0 :         r = sd_bus_message_read(m, "s", &name);
     559           0 :         if (r < 0)
     560           0 :                 return log_error_errno(r, "Failed to read interface name: %m");
     561             : 
     562           0 :         if (!streq_ptr(name, "org.freedesktop.timesync1.Manager"))
     563           0 :                 return 0;
     564             : 
     565           0 :         return show_timesync_status_once(sd_bus_message_get_bus(m));
     566             : }
     567             : 
     568           0 : static int show_timesync_status(int argc, char **argv, void *userdata) {
     569           0 :         _cleanup_(sd_event_unrefp) sd_event *event = NULL;
     570           0 :         sd_bus *bus = userdata;
     571             :         int r;
     572             : 
     573           0 :         assert(bus);
     574             : 
     575           0 :         r = show_timesync_status_once(bus);
     576           0 :         if (r < 0)
     577           0 :                 return r;
     578             : 
     579           0 :         if (!arg_monitor)
     580           0 :                 return 0;
     581             : 
     582           0 :         r = sd_event_default(&event);
     583           0 :         if (r < 0)
     584           0 :                 return log_error_errno(r, "Failed to get event loop: %m");
     585             : 
     586           0 :         r = sd_bus_match_signal(bus,
     587             :                                 NULL,
     588             :                                 "org.freedesktop.timesync1",
     589             :                                 "/org/freedesktop/timesync1",
     590             :                                 "org.freedesktop.DBus.Properties",
     591             :                                 "PropertiesChanged",
     592             :                                 on_properties_changed, NULL);
     593           0 :         if (r < 0)
     594           0 :                 return log_error_errno(r, "Failed to request match for PropertiesChanged signal: %m");
     595             : 
     596           0 :         r = sd_bus_attach_event(bus, event, SD_EVENT_PRIORITY_NORMAL);
     597           0 :         if (r < 0)
     598           0 :                 return log_error_errno(r, "Failed to attach bus to event loop: %m");
     599             : 
     600           0 :         r = sd_event_loop(event);
     601           0 :         if (r < 0)
     602           0 :                 return log_error_errno(r, "Failed to run event loop: %m");
     603             : 
     604           0 :         return 0;
     605             : }
     606             : 
     607           0 : static int print_timesync_property(const char *name, const char *expected_value, sd_bus_message *m, bool value, bool all) {
     608             :         char type;
     609             :         const char *contents;
     610             :         int r;
     611             : 
     612           0 :         assert(name);
     613           0 :         assert(m);
     614             : 
     615           0 :         r = sd_bus_message_peek_type(m, &type, &contents);
     616           0 :         if (r < 0)
     617           0 :                 return r;
     618             : 
     619           0 :         switch (type) {
     620             : 
     621           0 :         case SD_BUS_TYPE_STRUCT:
     622           0 :                 if (streq(name, "NTPMessage")) {
     623           0 :                         _cleanup_(ntp_status_info_clear) NTPStatusInfo i = {};
     624             :                         char ts[FORMAT_TIMESPAN_MAX], stamp[FORMAT_TIMESTAMP_MAX];
     625             : 
     626           0 :                         r = map_ntp_message(NULL, NULL, m, NULL, &i);
     627           0 :                         if (r < 0)
     628           0 :                                 return r;
     629             : 
     630           0 :                         if (i.packet_count == 0)
     631           0 :                                 return 1;
     632             : 
     633           0 :                         if (!value) {
     634           0 :                                 fputs(name, stdout);
     635           0 :                                 fputc('=', stdout);
     636             :                         }
     637             : 
     638           0 :                         printf("{ Leap=%u, Version=%u, Mode=%u, Stratum=%u, Precision=%i,",
     639             :                                i.leap, i.version, i.mode, i.stratum, i.precision);
     640           0 :                         printf(" RootDelay=%s,",
     641             :                                format_timespan(ts, sizeof(ts), i.root_delay, 0));
     642           0 :                         printf(" RootDispersion=%s,",
     643             :                                format_timespan(ts, sizeof(ts), i.root_dispersion, 0));
     644             : 
     645           0 :                         if (i.stratum == 1)
     646           0 :                                 printf(" Reference=%s,", i.reference.str);
     647             :                         else
     648           0 :                                 printf(" Reference=%" PRIX32 ",", be32toh(i.reference.val));
     649             : 
     650           0 :                         printf(" OriginateTimestamp=%s,",
     651             :                                format_timestamp(stamp, sizeof(stamp), i.origin));
     652           0 :                         printf(" ReceiveTimestamp=%s,",
     653             :                                format_timestamp(stamp, sizeof(stamp), i.recv));
     654           0 :                         printf(" TransmitTimestamp=%s,",
     655             :                                format_timestamp(stamp, sizeof(stamp), i.trans));
     656           0 :                         printf(" DestinationTimestamp=%s,",
     657             :                                format_timestamp(stamp, sizeof(stamp), i.dest));
     658           0 :                         printf(" Ignored=%s PacketCount=%" PRIu64 ",",
     659           0 :                                yes_no(i.spike), i.packet_count);
     660           0 :                         printf(" Jitter=%s }\n",
     661             :                                format_timespan(ts, sizeof(ts), i.jitter, 0));
     662             : 
     663           0 :                         return 1;
     664             : 
     665           0 :                 } else if (streq(name, "ServerAddress")) {
     666           0 :                         _cleanup_free_ char *str = NULL;
     667             : 
     668           0 :                         r = map_server_address(NULL, NULL, m, NULL, &str);
     669           0 :                         if (r < 0)
     670           0 :                                 return r;
     671             : 
     672           0 :                         if (arg_all || !isempty(str))
     673           0 :                                 bus_print_property_value(name, expected_value, value, str);
     674             : 
     675           0 :                         return 1;
     676             :                 }
     677           0 :                 break;
     678             :         }
     679             : 
     680           0 :         return 0;
     681             : }
     682             : 
     683           0 : static int show_timesync(int argc, char **argv, void *userdata) {
     684           0 :         sd_bus *bus = userdata;
     685             :         int r;
     686             : 
     687           0 :         assert(bus);
     688             : 
     689           0 :         r = bus_print_all_properties(bus,
     690             :                                      "org.freedesktop.timesync1",
     691             :                                      "/org/freedesktop/timesync1",
     692             :                                      print_timesync_property,
     693             :                                      arg_property,
     694             :                                      arg_value,
     695             :                                      arg_all,
     696             :                                      NULL);
     697           0 :         if (r < 0)
     698           0 :                 return bus_log_parse_error(r);
     699             : 
     700           0 :         return 0;
     701             : }
     702             : 
     703           0 : static int parse_ifindex_bus(sd_bus *bus, const char *str, int *ret) {
     704           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     705           0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
     706             :         int32_t i;
     707             :         int r;
     708             : 
     709           0 :         assert(bus);
     710           0 :         assert(str);
     711           0 :         assert(ret);
     712             : 
     713           0 :         r = parse_ifindex(str, ret);
     714           0 :         if (r >= 0)
     715           0 :                 return 0;
     716             : 
     717           0 :         r = sd_bus_call_method(
     718             :                         bus,
     719             :                         "org.freedesktop.network1",
     720             :                         "/org/freedesktop/network1",
     721             :                         "org.freedesktop.network1.Manager",
     722             :                         "GetLinkByName",
     723             :                         &error,
     724             :                         &reply,
     725             :                         "s", str);
     726           0 :         if (r < 0)
     727           0 :                 return log_error_errno(r, "Failed to get ifindex of interfaces %s: %s", str, bus_error_message(&error, r));
     728             : 
     729           0 :         r = sd_bus_message_read(reply, "io", &i, NULL);
     730           0 :         if (r < 0)
     731           0 :                 return bus_log_create_error(r);
     732             : 
     733           0 :         *ret = i;
     734           0 :         return 0;
     735             : }
     736             : 
     737           0 : static int verb_ntp_servers(int argc, char **argv, void *userdata) {
     738           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     739           0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL;
     740           0 :         sd_bus *bus = userdata;
     741             :         int ifindex, r;
     742             : 
     743           0 :         assert(bus);
     744             : 
     745           0 :         r = parse_ifindex_bus(bus, argv[1], &ifindex);
     746           0 :         if (r < 0)
     747           0 :                 return r;
     748             : 
     749           0 :         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
     750             : 
     751           0 :         r = sd_bus_message_new_method_call(
     752             :                         bus,
     753             :                         &req,
     754             :                         "org.freedesktop.network1",
     755             :                         "/org/freedesktop/network1",
     756             :                         "org.freedesktop.network1.Manager",
     757             :                         "SetLinkNTP");
     758           0 :         if (r < 0)
     759           0 :                 return bus_log_create_error(r);
     760             : 
     761           0 :         r = sd_bus_message_append(req, "i", ifindex);
     762           0 :         if (r < 0)
     763           0 :                 return bus_log_create_error(r);
     764             : 
     765           0 :         r = sd_bus_message_append_strv(req, argv + 2);
     766           0 :         if (r < 0)
     767           0 :                 return bus_log_create_error(r);
     768             : 
     769           0 :         r = sd_bus_call(bus, req, 0, &error, NULL);
     770           0 :         if (r < 0)
     771           0 :                 return log_error_errno(r, "Failed to set NTP servers: %s", bus_error_message(&error, r));
     772             : 
     773           0 :         return 0;
     774             : }
     775             : 
     776           0 : static int verb_revert(int argc, char **argv, void *userdata) {
     777           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     778           0 :         sd_bus *bus = userdata;
     779             :         int ifindex, r;
     780             : 
     781           0 :         assert(bus);
     782             : 
     783           0 :         r = parse_ifindex_bus(bus, argv[1], &ifindex);
     784           0 :         if (r < 0)
     785           0 :                 return r;
     786             : 
     787           0 :         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
     788             : 
     789           0 :         r = sd_bus_call_method(
     790             :                         bus,
     791             :                         "org.freedesktop.network1",
     792             :                         "/org/freedesktop/network1",
     793             :                         "org.freedesktop.network1.Manager",
     794             :                         "RevertLinkNTP",
     795             :                         &error,
     796             :                         NULL,
     797             :                         "i", ifindex);
     798           0 :         if (r < 0)
     799           0 :                 return log_error_errno(r, "Failed to revert interface configuration: %s", bus_error_message(&error, r));
     800             : 
     801           0 :         return 0;
     802             : }
     803             : 
     804           3 : static int help(void) {
     805           3 :         _cleanup_free_ char *link = NULL;
     806             :         int r;
     807             : 
     808           3 :         r = terminal_urlify_man("timedatectl", "1", &link);
     809           3 :         if (r < 0)
     810           0 :                 return log_oom();
     811             : 
     812           3 :         printf("%s [OPTIONS...] COMMAND ...\n\n"
     813             :                "Query or change system time and date settings.\n\n"
     814             :                "  -h --help                Show this help message\n"
     815             :                "     --version             Show package version\n"
     816             :                "     --no-pager            Do not pipe output into a pager\n"
     817             :                "     --no-ask-password     Do not prompt for password\n"
     818             :                "  -H --host=[USER@]HOST    Operate on remote host\n"
     819             :                "  -M --machine=CONTAINER   Operate on local container\n"
     820             :                "     --adjust-system-clock Adjust system clock when changing local RTC mode\n"
     821             :                "     --monitor             Monitor status of systemd-timesyncd\n"
     822             :                "  -p --property=NAME       Show only properties by this name\n"
     823             :                "  -a --all                 Show all properties, including empty ones\n"
     824             :                "     --value               When showing properties, only print the value\n"
     825             :                "\n"
     826             :                "Commands:\n"
     827             :                "  status                   Show current time settings\n"
     828             :                "  show                     Show properties of systemd-timedated\n"
     829             :                "  set-time TIME            Set system time\n"
     830             :                "  set-timezone ZONE        Set system time zone\n"
     831             :                "  list-timezones           Show known time zones\n"
     832             :                "  set-local-rtc BOOL       Control whether RTC is in local time\n"
     833             :                "  set-ntp BOOL             Enable or disable network time synchronization\n"
     834             :                "\n"
     835             :                "systemd-timesyncd Commands:\n"
     836             :                "  timesync-status          Show status of systemd-timesyncd\n"
     837             :                "  show-timesync            Show properties of systemd-timesyncd\n"
     838             :                "\nSee the %s for details.\n"
     839             :                , program_invocation_short_name
     840             :                , link
     841             :         );
     842             : 
     843           3 :         return 0;
     844             : }
     845             : 
     846           0 : static int verb_help(int argc, char **argv, void *userdata) {
     847           0 :         return help();
     848             : }
     849             : 
     850           4 : static int parse_argv(int argc, char *argv[]) {
     851             : 
     852             :         enum {
     853             :                 ARG_VERSION = 0x100,
     854             :                 ARG_NO_PAGER,
     855             :                 ARG_ADJUST_SYSTEM_CLOCK,
     856             :                 ARG_NO_ASK_PASSWORD,
     857             :                 ARG_MONITOR,
     858             :                 ARG_VALUE,
     859             :         };
     860             : 
     861             :         static const struct option options[] = {
     862             :                 { "help",                no_argument,       NULL, 'h'                     },
     863             :                 { "version",             no_argument,       NULL, ARG_VERSION             },
     864             :                 { "no-pager",            no_argument,       NULL, ARG_NO_PAGER            },
     865             :                 { "host",                required_argument, NULL, 'H'                     },
     866             :                 { "machine",             required_argument, NULL, 'M'                     },
     867             :                 { "no-ask-password",     no_argument,       NULL, ARG_NO_ASK_PASSWORD     },
     868             :                 { "adjust-system-clock", no_argument,       NULL, ARG_ADJUST_SYSTEM_CLOCK },
     869             :                 { "monitor",             no_argument,       NULL, ARG_MONITOR             },
     870             :                 { "property",            required_argument, NULL, 'p'                     },
     871             :                 { "all",                 no_argument,       NULL, 'a'                     },
     872             :                 { "value",               no_argument,       NULL, ARG_VALUE               },
     873             :                 {}
     874             :         };
     875             : 
     876             :         int c, r;
     877             : 
     878           4 :         assert(argc >= 0);
     879           4 :         assert(argv);
     880             : 
     881           4 :         while ((c = getopt_long(argc, argv, "hH:M:p:a", options, NULL)) >= 0)
     882             : 
     883           4 :                 switch (c) {
     884             : 
     885           3 :                 case 'h':
     886           3 :                         return help();
     887             : 
     888           0 :                 case ARG_VERSION:
     889           0 :                         return version();
     890             : 
     891           0 :                 case 'H':
     892           0 :                         arg_transport = BUS_TRANSPORT_REMOTE;
     893           0 :                         arg_host = optarg;
     894           0 :                         break;
     895             : 
     896           0 :                 case 'M':
     897           0 :                         arg_transport = BUS_TRANSPORT_MACHINE;
     898           0 :                         arg_host = optarg;
     899           0 :                         break;
     900             : 
     901           0 :                 case ARG_NO_ASK_PASSWORD:
     902           0 :                         arg_ask_password = false;
     903           0 :                         break;
     904             : 
     905           0 :                 case ARG_ADJUST_SYSTEM_CLOCK:
     906           0 :                         arg_adjust_system_clock = true;
     907           0 :                         break;
     908             : 
     909           0 :                 case ARG_NO_PAGER:
     910           0 :                         arg_pager_flags |= PAGER_DISABLE;
     911           0 :                         break;
     912             : 
     913           0 :                 case ARG_MONITOR:
     914           0 :                         arg_monitor = true;
     915           0 :                         break;
     916             : 
     917           0 :                 case 'p': {
     918           0 :                         r = strv_extend(&arg_property, optarg);
     919           0 :                         if (r < 0)
     920           0 :                                 return log_oom();
     921             : 
     922             :                         /* If the user asked for a particular
     923             :                          * property, show it to him, even if it is
     924             :                          * empty. */
     925           0 :                         arg_all = true;
     926           0 :                         break;
     927             :                 }
     928             : 
     929           0 :                 case 'a':
     930           0 :                         arg_all = true;
     931           0 :                         break;
     932             : 
     933           0 :                 case ARG_VALUE:
     934           0 :                         arg_value = true;
     935           0 :                         break;
     936             : 
     937           1 :                 case '?':
     938           1 :                         return -EINVAL;
     939             : 
     940           0 :                 default:
     941           0 :                         assert_not_reached("Unhandled option");
     942             :                 }
     943             : 
     944           0 :         return 1;
     945             : }
     946             : 
     947           0 : static int timedatectl_main(sd_bus *bus, int argc, char *argv[]) {
     948             :         static const Verb verbs[] = {
     949             :                 { "status",          VERB_ANY, 1,        VERB_DEFAULT, show_status          },
     950             :                 { "show",            VERB_ANY, 1,        0,            show_properties      },
     951             :                 { "set-time",        2,        2,        0,            set_time             },
     952             :                 { "set-timezone",    2,        2,        0,            set_timezone         },
     953             :                 { "list-timezones",  VERB_ANY, 1,        0,            list_timezones       },
     954             :                 { "set-local-rtc",   2,        2,        0,            set_local_rtc        },
     955             :                 { "set-ntp",         2,        2,        0,            set_ntp              },
     956             :                 { "timesync-status", VERB_ANY, 1,        0,            show_timesync_status },
     957             :                 { "show-timesync",   VERB_ANY, 1,        0,            show_timesync        },
     958             :                 { "ntp-servers",     3,        VERB_ANY, 0,            verb_ntp_servers     },
     959             :                 { "revert",          2,        2,        0,            verb_revert          },
     960             :                 { "help",            VERB_ANY, VERB_ANY, 0,            verb_help            }, /* Not documented, but supported since it is created. */
     961             :                 {}
     962             :         };
     963             : 
     964           0 :         return dispatch_verb(argc, argv, verbs, bus);
     965             : }
     966             : 
     967           4 : static int run(int argc, char *argv[]) {
     968           4 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
     969             :         int r;
     970             : 
     971           4 :         setlocale(LC_ALL, "");
     972           4 :         log_show_color(true);
     973           4 :         log_parse_environment();
     974           4 :         log_open();
     975             : 
     976           4 :         r = parse_argv(argc, argv);
     977           4 :         if (r <= 0)
     978           4 :                 return r;
     979             : 
     980           0 :         r = bus_connect_transport(arg_transport, arg_host, false, &bus);
     981           0 :         if (r < 0)
     982           0 :                 return log_error_errno(r, "Failed to create bus connection: %m");
     983             : 
     984           0 :         return timedatectl_main(bus, argc, argv);
     985             : }
     986             : 
     987           4 : DEFINE_MAIN_FUNCTION(run);

Generated by: LCOV version 1.14