]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
chronyc: add wider output option
authorThomas Kupper <tom@kupper.org>
Sat, 14 Feb 2026 11:24:32 +0000 (12:24 +0100)
committerMiroslav Lichvar <mlichvar@redhat.com>
Thu, 26 Feb 2026 14:31:21 +0000 (15:31 +0100)
Add option '-w' which set the output width from 80 to 94. This allows
for all table-outputting operations to display IPv4 and IPv6 addresses
aligned with the headers.

Extend test/simulation/110-chronyc to test for the five commands which
support wide mode.

To set wide display, call `chronyc` with option `-w`.

Example of a `clients` list before and after:

chronyc -n clients -p 5
Hostname                      NTP   Drop Int IntL Last     Cmd   Drop Int  Last
===============================================================================
2001:db8:1234:5678:90ab:cdef:1234:5678     952      0   7   -    75       0      0   -     -
192.168.1.1                     0      0   -   -     -       0      0   -     -

chronyc -n -w clients -p 5
Hostname                                    NTP   Drop Int IntL Last     Cmd   Drop Int  Last
=============================================================================================
2001:db8:1234:5678:90ab:cdef:1234:5678      952      0   7   -    75       0      0   -     -
192.168.1.1                                   0      0   -   -     -       0      0   -     -

client.c
doc/chronyc.adoc
test/simulation/110-chronyc

index a3c2ab35c20516c504fe898a4337407978622873..71db5677493f85e9ee43143fe4f0de830c2d9308 100644 (file)
--- a/client.c
+++ b/client.c
@@ -78,6 +78,8 @@ static int csv_mode = 0;
 
 static int end_dot = 0;
 
+static int wide = 0;
+
 /* ================================================== */
 /* Log a message. This is a minimalistic replacement of the logging.c
    implementation to avoid linking with it and other modules. */
@@ -1768,7 +1770,7 @@ print_report(const char *format, ...)
 {
   char buf[256];
   va_list ap;
-  int i, field, sign, width, prec, spec;
+  int i, field, sign, width, prec, spec, varwidth;
   const char *string;
   unsigned int uinteger;
   uint64_t uinteger64;
@@ -1802,10 +1804,14 @@ print_report(const char *format, ...)
     sign = 0;
     width = 0;
     prec = 5;
+    varwidth = 0;
 
     if (*format == '+' || *format == '-') {
       sign = 1;
       format++;
+    } else if (*format == '*') {
+      varwidth = 1;
+      format++;
     }
 
     if (isdigit((unsigned char)*format)) {
@@ -1993,6 +1999,14 @@ print_report(const char *format, ...)
         printf("%*o", width, uinteger);
         break;
       case 's': /* string */
+        if (varwidth) {
+          if (csv_mode) {
+            integer = va_arg(ap, int);
+            width = 0;
+          } else {
+            width = va_arg(ap, int);
+          }
+        }
         string = va_arg(ap, const char *);
         if (sign)
           printf("%-*s", width, string);
@@ -2143,14 +2157,17 @@ process_cmd_sources(char *line)
     printf("  .-- Source mode  '^' = server, '=' = peer, '#' = local clock.\n");
     printf(" / .- Source state '*' = current best, '+' = combined, '-' = not combined,\n");
     printf("| /             'x' = may be in error, '~' = too variable, '?' = unusable.\n");
-    printf("||                                                 .- xxxx [ yyyy ] +/- zzzz\n");
-    printf("||      Reachability register (octal) -.           |  xxxx = adjusted offset,\n");
-    printf("||      Log2(Polling interval) --.      |          |  yyyy = measured offset,\n");
-    printf("||                                \\     |          |  zzzz = estimated error.\n");
-    printf("||                                 |    |           \\\n");
+    printf("||  %*s                                               .- xxxx [ yyyy ] +/- zzzz\n", wide, "");
+    printf("||  %*s    Reachability register (octal) -.           |  xxxx = adjusted offset,\n", wide, "");
+    printf("||  %*s    Log2(Polling interval) --.      |          |  yyyy = measured offset,\n", wide, "");
+    printf("||  %*s                              \\     |          |  zzzz = estimated error.\n", wide, "");
+    printf("||  %*s                               |    |           \\\n", wide, "");
   }
 
-  print_header("MS Name/IP address         Stratum Poll Reach LastRx Last sample               ");
+  if (wide)
+    print_header("MS Name/IP address                       Stratum Poll Reach LastRx Last sample               ");
+  else
+    print_header("MS Name/IP address         Stratum Poll Reach LastRx Last sample               ");
 
   /*           "MS NNNNNNNNNNNNNNNNNNNNNNNNNNN  SS  PP   RRR  RRRR  SSSSSSS[SSSSSSS] +/- SSSSSS" */
 
@@ -2166,7 +2183,7 @@ process_cmd_sources(char *line)
       continue;
 
     ref = mode == RPY_SD_MD_REF && ip_addr.family == IPADDR_INET4;
-    format_name(name, sizeof (name), 25, ref, ref ? ip_addr.addr.in4 : 0, 1, &ip_addr);
+    format_name(name, sizeof (name), 25 + wide, ref, ref ? ip_addr.addr.in4 : 0, 1, &ip_addr);
 
     switch (mode) {
       case RPY_SD_MD_CLIENT:
@@ -2210,8 +2227,8 @@ process_cmd_sources(char *line)
         break;
     }
 
-    print_report("%c%c %-27s  %2d  %2d   %3o  %I  %+S[%+S] +/- %S\n",
-                 mode_ch, state_ch, name,
+    print_report("%c%c %*s  %2d  %2d   %3o  %I  %+S[%+S] +/- %S\n",
+                 mode_ch, state_ch, -27 - wide, name,
                  ntohs(reply.data.source_data.stratum),
                  (int16_t)ntohs(reply.data.source_data.poll),
                  ntohs(reply.data.source_data.reachability),
@@ -2246,18 +2263,21 @@ process_cmd_sourcestats(char *line)
   n_sources = ntohl(reply.data.n_sources.n_sources);
 
   if (verbose) {
-    printf("                             .- Number of sample points in measurement set.\n");
-    printf("                            /    .- Number of residual runs with same sign.\n");
-    printf("                           |    /    .- Length of measurement set (time).\n");
-    printf("                           |   |    /      .- Est. clock freq error (ppm).\n");
-    printf("                           |   |   |      /           .- Est. error in freq.\n");
-    printf("                           |   |   |     |           /         .- Est. offset.\n");
-    printf("                           |   |   |     |          |          |   On the -.\n");
-    printf("                           |   |   |     |          |          |   samples. \\\n");
-    printf("                           |   |   |     |          |          |             |\n");
-  }
-
-  print_header("Name/IP Address            NP  NR  Span  Frequency  Freq Skew  Offset  Std Dev");
+    printf("%*s                             .- Number of sample points in measurement set.\n", wide, "");
+    printf("%*s                            /    .- Number of residual runs with same sign.\n", wide, "");
+    printf("%*s                           |    /    .- Length of measurement set (time).\n", wide, "");
+    printf("%*s                           |   |    /      .- Est. clock freq error (ppm).\n", wide, "");
+    printf("%*s                           |   |   |      /           .- Est. error in freq.\n", wide, "");
+    printf("%*s                           |   |   |     |           /         .- Est. offset.\n", wide, "");
+    printf("%*s                           |   |   |     |          |          |   On the -.\n", wide, "");
+    printf("%*s                           |   |   |     |          |          |   samples. \\\n", wide, "");
+    printf("%*s                           |   |   |     |          |          |             |\n", wide, "");
+  }
+
+  if (wide)
+    print_header("Name/IP Address                          NP  NR  Span  Frequency  Freq Skew  Offset  Std Dev");
+  else
+    print_header("Name/IP Address            NP  NR  Span  Frequency  Freq Skew  Offset  Std Dev");
 
   /*           "NNNNNNNNNNNNNNNNNNNNNNNNN  NP  NR  SSSS FFFFFFFFFF SSSSSSSSSS  SSSSSSS  SSSSSS" */
 
@@ -2271,11 +2291,11 @@ process_cmd_sourcestats(char *line)
     if (!all && ip_addr.family == IPADDR_ID)
       continue;
 
-    format_name(name, sizeof (name), 25, ip_addr.family == IPADDR_UNSPEC,
+    format_name(name, sizeof (name), 25 + wide, ip_addr.family == IPADDR_UNSPEC,
                 ntohl(reply.data.sourcestats.ref_id), 1, &ip_addr);
 
-    print_report("%-25s %3U %3U  %I %+P %P  %+S  %S\n",
-                 name,
+    print_report("%*s %3U %3U  %I %+P %P  %+S  %S\n",
+                 -25 - wide, name,
                  ntohl(reply.data.sourcestats.n_samples),
                  ntohl(reply.data.sourcestats.n_runs),
                  ntohl(reply.data.sourcestats.span_seconds),
@@ -2365,14 +2385,17 @@ process_cmd_authdata(char *line)
   n_sources = ntohl(reply.data.n_sources.n_sources);
 
   if (verbose) {
-    printf(    "                             .- Auth. mechanism (NTS, SK - symmetric key)\n");
-    printf(    "                            |   Key length -.  Cookie length (bytes) -.\n");
-    printf(    "                            |       (bits)  |  Num. of cookies --.    |\n");
-    printf(    "                            |               |  Key est. attempts  |   |\n");
-    printf(    "                            |               |           |         |   |\n");
+    printf(    "%*s                             .- Auth. mechanism (NTS, SK - symmetric key)\n", wide, "");
+    printf(    "%*s                            |   Key length -.  Cookie length (bytes) -.\n", wide, "");
+    printf(    "%*s                            |       (bits)  |  Num. of cookies --.    |\n", wide, "");
+    printf(    "%*s                            |               |  Key est. attempts  |   |\n", wide, "");
+    printf(    "%*s                            |               |           |         |   |\n", wide, "");
   }
 
-  print_header("Name/IP address             Mode KeyID Type KLen Last Atmp  NAK Cook CLen");
+  if (wide)
+    print_header("Name/IP address                           Mode KeyID Type KLen Last Atmp  NAK Cook CLen");
+  else
+    print_header("Name/IP address             Mode KeyID Type KLen Last Atmp  NAK Cook CLen");
 
   /*           "NNNNNNNNNNNNNNNNNNNNNNNNNNN MMMM KKKKK AAAA LLLL LLLL AAAA NNNN CCCC LLLL" */
 
@@ -2395,7 +2418,7 @@ process_cmd_authdata(char *line)
     if (!request_reply(&request, &reply, RPY_AUTH_DATA, 0))
       return 0;
 
-    format_name(name, sizeof (name), 25, 0, 0, 1, &ip_addr);
+    format_name(name, sizeof (name), 25 + wide, 0, 0, 1, &ip_addr);
 
     switch (ntohs(reply.data.auth_data.mode)) {
       case RPY_AD_MD_NONE:
@@ -2412,8 +2435,8 @@ process_cmd_authdata(char *line)
         break;
     }
 
-    print_report("%-27s %4s %5U %4d %4d %I %4d %4d %4d %4d\n",
-                 name, mode_str,
+    print_report("%*s %4s %5U %4d %4d %I %4d %4d %4d %4d\n",
+                 -27 - wide, name, mode_str,
                  ntohl(reply.data.auth_data.key_id),
                  ntohs(reply.data.auth_data.key_type),
                  ntohs(reply.data.auth_data.key_length),
@@ -2578,13 +2601,16 @@ process_cmd_selectdata(char *line)
     printf(    " /         d/D - large distance, ~ - jittery, w/W - waits for others,\n");
     printf(    "|          S - stale, O - orphan, T - not trusted, P - not preferred,\n");
     printf(    "|          U - waits for update, x - falseticker, + - combined, * - best.\n");
-    printf(    "|   Effective options   ---------.  (N - noselect, P - prefer\n");
-    printf(    "|   Configured options  ----.     \\  T - trust, R - require)\n");
-    printf(    "|   Auth. enabled (Y/N) -.   \\     \\     Offset interval --.\n");
-    printf(    "|                        |    |     |                       |\n");
+    printf(    "|%*s   Effective options   ---------.  (N - noselect, P - prefer\n", wide, "");
+    printf(    "|%*s   Configured options  ----.     \\  T - trust, R - require)\n", wide, "");
+    printf(    "|%*s   Auth. enabled (Y/N) -.   \\     \\     Offset interval --.\n", wide, "");
+    printf(    "|%*s                        |    |     |                       |\n", wide, "");
   }
 
-  print_header("S Name/IP Address        Auth COpts EOpts Last Score     Interval  Leap");
+  if (wide)
+    print_header("S Name/IP Address                      Auth COpts EOpts Last Score     Interval  Leap");
+  else
+    print_header("S Name/IP Address        Auth COpts EOpts Last Score     Interval  Leap");
 
   /*           "S NNNNNNNNNNNNNNNNNNNNNNNNN A OOOO- OOOO- LLLL SSSSS IIIIIII IIIIIII  L" */
 
@@ -2598,15 +2624,15 @@ process_cmd_selectdata(char *line)
     if (!all && ip_addr.family == IPADDR_ID)
       continue;
 
-    format_name(name, sizeof (name), 25, ip_addr.family == IPADDR_UNSPEC,
+    format_name(name, sizeof (name), 25 + wide, ip_addr.family == IPADDR_UNSPEC,
                 ntohl(reply.data.select_data.ref_id), 1, &ip_addr);
 
     conf_options = ntohs(reply.data.select_data.conf_options);
     eff_options = ntohs(reply.data.select_data.eff_options);
 
-    print_report("%c %-25s %c %c%c%c%c%c %c%c%c%c%c %I %5.1f %+S %+S  %1L\n",
+    print_report("%c %*s %c %c%c%c%c%c %c%c%c%c%c %I %5.1f %+S %+S  %1L\n",
                  reply.data.select_data.state_char,
-                 name,
+                 -25 - wide, name,
                  reply.data.select_data.authentication ? 'Y' : 'N',
                  conf_options & RPY_SD_OPTION_NOSELECT ? 'N' : '-',
                  conf_options & RPY_SD_OPTION_PREFER ? 'P' : '-',
@@ -2774,7 +2800,7 @@ process_cmd_clients(char *line)
   IPAddr ip;
   uint32_t i, n_clients, next_index, n_indices, min_hits, reset;
   RPY_ClientAccesses_Client *client;
-  char header[80], name[50], *opt, *arg;
+  char header[94], name[50], *opt, *arg;
   int nke;
 
   next_index = 0;
@@ -2800,8 +2826,8 @@ process_cmd_clients(char *line)
   }
 
   snprintf(header, sizeof (header),
-           "Hostname                      NTP   Drop Int IntL Last  %6s   Drop Int  Last",
-           nke ? "NTS-KE" : "Cmd");
+           "Hostname %*s NTP   Drop Int IntL Last  %6s   Drop Int  Last",
+            20 + wide, "", nke ? "NTS-KE" : "Cmd");
   print_header(header);
 
   while (1) {
@@ -2827,10 +2853,10 @@ process_cmd_clients(char *line)
       if (ip.family == IPADDR_UNSPEC)
         continue;
 
-      format_name(name, sizeof (name), 25, 0, 0, 0, &ip);
+      format_name(name, sizeof (name), 25 + wide, 0, 0, 0, &ip);
 
-      print_report("%-25s  %6U  %5U  %C  %C  %I  %6U  %5U  %C  %I\n",
-                   name,
+      print_report("%*s  %6U  %5U  %C  %C  %I  %6U  %5U  %C  %I\n",
+                   -25 - wide, name,
                    ntohl(client->ntp_hits),
                    ntohl(client->ntp_drops),
                    client->ntp_interval,
@@ -3589,6 +3615,7 @@ print_help(const char *progname)
              "  -h HOST\tSpecify server (%s)\n"
              "  -p PORT\tSpecify UDP port (%d)\n"
              "  -u USER\tSpecify user (%s)\n"
+             "  -w\t\tWide output\n"
              "  -v, --version\tPrint version and exit\n"
              "      --help\tPrint usage and exit\n",
              progname, DEFAULT_COMMAND_SOCKET",127.0.0.1,::1",
@@ -3629,7 +3656,7 @@ main(int argc, char **argv)
   optind = 1;
 
   /* Parse short command-line options */
-  while ((opt = getopt(argc, argv, "+46acdef:h:mnNp:u:v")) != -1) {
+  while ((opt = getopt(argc, argv, "+46acdef:h:mnNp:u:v:w")) != -1) {
     switch (opt) {
       case '4':
       case '6':
@@ -3671,6 +3698,9 @@ main(int argc, char **argv)
       case 'v':
         print_version();
         return 0;
+      case 'w':
+        wide = 14;
+        break;
       default:
         print_help(progname);
         return 1;
index b7f30c656be3d5a1ccfb2e7444e395df95ec4466..ee1918546507242d3ba5b047994ae32af1242eb8 100644 (file)
@@ -134,6 +134,10 @@ This option is ignored and is provided only for compatibility.
 *-a*::
 This option is ignored and is provided only for compatibility.
 
+*-w*::
+This option sets the output width to 94 columns, from the standard 80, for the
+commands *authdata*, *clients*, *selectdata*, *sources*, and *sourcestats*.
+
 *-v*, *--version*::
 With this option *chronyc* displays its version number on the terminal and
 exits.
index 6488d97c29de0a4c9f2bc5d1a170406ce81e06c6..fa9196e8a741a4a50773cd77a8e5f8d43d688ec8 100755 (executable)
@@ -103,6 +103,49 @@ check_chronyc_output "^#,.,SHM0.*
 \.$" \
        || test_fail
 
+client_conf=""
+client_server_conf="
+server node1.net1.clk
+server ntp.notresolved.com
+server 2001:db8:c001:cafe:1234:1234:1234:1234"
+server_conf="server 192.168.123.1"
+server_strata=1
+cmdmon_unix=1
+dns=0
+
+chronyc_options="-w"
+chronyc_conf="authdata -a
+selectdata -a
+sources -a
+sourcestats -a
+clients -k"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+
+check_chronyc_output "^Name/IP address                           Mode KeyID Type KLen Last Atmp  NAK Cook CLen
+=======================================================================================
+192\.168\.123\.1                                -     0    0    0    -    0    0    0    0
+ID#0000000002                                -     0    0    0    -    0    0    0    0
+(2001:db8:c001:cafe:1234:1234:1234:1234|ID#0000000003)       [- ]+     0    0    0    -    0    0    0    0
+S Name/IP Address                      Auth COpts EOpts Last Score     Interval  Leap
+=====================================================================================
+\* 192\.168\.123\.1                           N ----- -----    [0-9]+   1\.0  [0-9 +-]+[un]s  [0-9 +-]+[un]s  N
+M ID#0000000002                           N ----- -----    0   1\.0    \+0ns    \+0ns  \?
+M (2001:db8:c001:cafe:1234:1234:1234:1234|ID#0000000003)  [N ]+ ----- -----    0   1\.0    \+0ns    \+0ns  \?
+MS Name/IP address                       Stratum Poll Reach LastRx Last sample               
+=============================================================================================
+\^\* 192\.168\.123\.1                               1   [67]   377    [0-9]+ [0-9 +-]+[un]s\[[0-9 +-]+[un]s\] \+/-[ 0-9]+[un]s
+\^\? ID#0000000002                               0   [0-9]+     0     -     \+0ns\[   \+0ns\] \+/-    0ns
+\^\? (2001:db8:c001:cafe:1234:1234:1234:1234|ID#0000000003)      [0 ]+   [0-9]+     0     -     \+0ns\[   \+0ns\] \+/-    0ns
+Name/IP Address                          NP  NR  Span  Frequency  Freq Skew  Offset  Std Dev
+============================================================================================
+192\.168\.123\.1                            [0-9 ]+ [0-9 ]+ [0-9 ]+ [ +-][01]\.... [0-9 ]+\....  [0-9 +-]+[un]s [0-9 ]+[un]s
+ID#0000000002                             0   0     0     \+0\.000   2000\.000     \+0ns  4000ms
+(2001:db8:c001:cafe:1234:1234:1234:1234|ID#0000000003)    [0 ]+   0     0     \+0\.000   2000\.000     \+0ns  4000ms
+Hostname                                    NTP   Drop Int IntL Last  NTS-KE   Drop Int  Last
+=============================================================================================$" || test_fail
+
 chronyc_options=""
 server_strata=0
 chronyc_start=0.5
@@ -110,6 +153,8 @@ client_server_conf=""
 client_conf=""
 server_conf="server 192.168.123.1"
 limit=1
+dns=1
+cmdmon_unix=0
 
 for chronyc_conf in \
        "accheck 1.2.3.4" \