* 'clock' of https://github.com/t-8ch/util-linux:
  lsclocks: new util to interact with system clocks
  lib/timeutils: implement timespec formatting
  lib/timeutils: implement nanosecond formatting
  lib/timeutils: constify some arguments
  utmpdump: validate subsecond granularity
This commit is contained in:
Karel Zak 2023-07-03 12:47:08 +02:00
commit 6462dbe2ef
16 changed files with 625 additions and 17 deletions

View file

@ -347,5 +347,8 @@ endif
if BUILD_ENOSYS
dist_bashcompletion_DATA += bash-completion/enosys
endif
if BUILD_LSCLOCKS
dist_bashcompletion_DATA += bash-completion/lsclocks
endif
endif # BUILD_BASH_COMPLETION

48
bash-completion/lsclocks Normal file
View file

@ -0,0 +1,48 @@
_lsclocks_module()
{
local cur prev OPTS
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
case $prev in
'-J'|'--json')
return 0
;;
'-n'|'--noheadings')
return 0
;;
'-o'|'--output')
return 0
;;
'-r'|'--raw')
return 0
;;
'-t'|'--time')
clocks="$(command "$1" --noheadings --raw --output NAME)"
COMPREPLY=( $(compgen -W "$clocks" -- "$cur") )
return 0
;;
'-h'|'--help'|'-V'|'--version')
return 0
;;
esac
case $cur in
-*)
OPTS="--json
--noheadings
--output
--raw
--time
--help
--version"
COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) )
return 0
;;
*)
return 0
;;
esac
return 0
}
complete -F _lsclocks_module lsclocks

View file

@ -1894,6 +1894,9 @@ AS_IF([test "x$build_enosys" = xyes], [
])
AM_CONDITIONAL([BUILD_ENOSYS], [test "x$build_enosys" = xyes])
UL_BUILD_INIT([lsclocks], [yes])
AM_CONDITIONAL([BUILD_LSCLOCKS], [test "x$build_lsclocks" = xyes])
UL_BUILD_INIT([getopt], [yes])
AM_CONDITIONAL([BUILD_GETOPT], [test "x$build_getopt" = xyes])

View file

@ -57,8 +57,10 @@ enum {
ISO_TIMEZONE = (1 << 2),
ISO_DOTUSEC = (1 << 3),
ISO_COMMAUSEC = (1 << 4),
ISO_T = (1 << 5),
ISO_GMTIME = (1 << 6),
ISO_DOTNSEC = (1 << 5),
ISO_COMMANSEC = (1 << 6),
ISO_T = (1 << 7),
ISO_GMTIME = (1 << 8),
ISO_TIMESTAMP = ISO_DATE | ISO_TIME | ISO_TIMEZONE,
ISO_TIMESTAMP_T = ISO_TIMESTAMP | ISO_T,
ISO_TIMESTAMP_DOT = ISO_TIMESTAMP | ISO_DOTUSEC,
@ -72,9 +74,10 @@ enum {
#define CTIME_BUFSIZ 26
#define ISO_BUFSIZ 42
int strtimeval_iso(struct timeval *tv, int flags, char *buf, size_t bufsz);
int strtm_iso(struct tm *tm, int flags, char *buf, size_t bufsz);
int strtimeval_iso(const struct timeval *tv, int flags, char *buf, size_t bufsz);
int strtm_iso(const struct tm *tm, int flags, char *buf, size_t bufsz);
int strtime_iso(const time_t *t, int flags, char *buf, size_t bufsz);
int strtimespec_iso(const struct timespec *t, int flags, char *buf, size_t bufsz);
#define UL_SHORTTIME_THISYEAR_HHMM (1 << 1)

View file

@ -448,8 +448,9 @@ int get_gmtoff(const struct tm *tp)
#endif
}
static int format_iso_time(struct tm *tm, suseconds_t usec, int flags, char *buf, size_t bufsz)
static int format_iso_time(const struct tm *tm, uint32_t nsec, int flags, char *buf, size_t bufsz)
{
uint32_t usec = nsec / NSEC_PER_USEC;
char *p = buf;
int len;
@ -479,15 +480,28 @@ static int format_iso_time(struct tm *tm, suseconds_t usec, int flags, char *buf
p += len;
}
if (flags & ISO_DOTUSEC) {
len = snprintf(p, bufsz, ".%06"PRId64, (int64_t) usec);
if (flags & ISO_DOTNSEC) {
len = snprintf(p, bufsz, ".%09"PRIu32, nsec);
if (len < 0 || (size_t) len > bufsz)
goto err;
bufsz -= len;
p += len;
} else if (flags & ISO_COMMANSEC) {
len = snprintf(p, bufsz, ",%09"PRIu32, nsec);
if (len < 0 || (size_t) len > bufsz)
goto err;
bufsz -= len;
p += len;
} else if (flags & ISO_DOTUSEC) {
len = snprintf(p, bufsz, ".%06"PRIu32, usec);
if (len < 0 || (size_t) len > bufsz)
goto err;
bufsz -= len;
p += len;
} else if (flags & ISO_COMMAUSEC) {
len = snprintf(p, bufsz, ",%06"PRId64, (int64_t) usec);
len = snprintf(p, bufsz, ",%06"PRIu32, usec);
if (len < 0 || (size_t) len > bufsz)
goto err;
bufsz -= len;
@ -508,26 +522,37 @@ static int format_iso_time(struct tm *tm, suseconds_t usec, int flags, char *buf
return -1;
}
/* timeval to ISO 8601 */
int strtimeval_iso(struct timeval *tv, int flags, char *buf, size_t bufsz)
/* timespec to ISO 8601 */
int strtimespec_iso(const struct timespec *ts, int flags, char *buf, size_t bufsz)
{
struct tm tm;
struct tm *rc;
if (flags & ISO_GMTIME)
rc = gmtime_r(&tv->tv_sec, &tm);
rc = gmtime_r(&ts->tv_sec, &tm);
else
rc = localtime_r(&tv->tv_sec, &tm);
rc = localtime_r(&ts->tv_sec, &tm);
if (rc)
return format_iso_time(&tm, tv->tv_usec, flags, buf, bufsz);
return format_iso_time(&tm, ts->tv_nsec, flags, buf, bufsz);
warnx(_("time %"PRId64" is out of range."), (int64_t)(tv->tv_sec));
warnx(_("time %"PRId64" is out of range."), (int64_t)(ts->tv_sec));
return -1;
}
/* timeval to ISO 8601 */
int strtimeval_iso(const struct timeval *tv, int flags, char *buf, size_t bufsz)
{
struct timespec ts = {
.tv_sec = tv->tv_sec,
.tv_nsec = tv->tv_usec * NSEC_PER_USEC,
};
return strtimespec_iso(&ts, flags, buf, bufsz);
}
/* struct tm to ISO 8601 */
int strtm_iso(struct tm *tm, int flags, char *buf, size_t bufsz)
int strtm_iso(const struct tm *tm, int flags, char *buf, size_t bufsz)
{
return format_iso_time(tm, 0, flags, buf, bufsz);
}

View file

@ -108,7 +108,7 @@ static void print_utline(struct utmpx *ut, FILE *out)
addr_string = inet_ntop(AF_INET, &(ut->ut_addr_v6), buffer, sizeof(buffer));
tv.tv_sec = ut->ut_tv.tv_sec;
tv.tv_usec = ut->ut_tv.tv_usec;
tv.tv_usec = ut->ut_tv.tv_usec < (int32_t) USEC_PER_SEC ? ut->ut_tv.tv_usec : 0;
if (strtimeval_iso(&tv, ISO_TIMESTAMP_COMMA_GT, time_string,
sizeof(time_string)) != 0)

View file

@ -2908,6 +2908,19 @@ if cc.compiles(fs.read('include/audit-arch.h'), name : 'has AUDIT_ARCH_NATIVE')
endif
endif
exe = executable(
'lsclocks',
lsclocks_sources,
include_directories : includes,
link_with : [lib_common, lib_smartcols],
install_dir : usrbin_exec_dir,
install : true)
if not is_disabler(exe)
exes += exe
manadocs += ['misc-utils/lsclocks.1.adoc']
bashcompletions += ['lsclocks']
endif
############################################################
opt = not get_option('build-schedutils').disabled()

View file

@ -316,3 +316,11 @@ enosys_SOURCES = misc-utils/enosys.c
enosys_LDADD = $(LDADD) libcommon.la
enosys_CFLAGS = $(AM_CFLAGS)
endif
if BUILD_LSCLOCKS
usrbin_exec_PROGRAMS += lsclocks
MANPAGES += misc-utils/lsclocks.1
lsclocks_SOURCES = misc-utils/lsclocks.c
lsclocks_LDADD = $(LDADD) libcommon.la libsmartcols.la
lsclocks_CFLAGS = $(AM_CFLAGS) -I$(ul_libsmartcols_incdir)
endif

View file

@ -0,0 +1,81 @@
//po4a: entry man manual
= lsclocks(1)
:doctype: manpage
:man manual: User Commands
:man source: util-linux {release-version}
:page-layout: base
:command: lsclocks
== NAME
lsclocks - display system clocks
== SYNOPSIS
*lsclocks* [option]
== DESCRIPTION
*lsclocks* is a simple command to display system clocks.
It allows to display information like current time and resolutionof clocks like
CLOCK_MONOTONIC, CLOCK_REALTIME and CLOCK_BOOTTIME.
== OPTIONS
*-J*, *--json*::
Use JSON output format.
*-n*, *--noheadings*::
Don't print headings.
*-o*, *--output* _list_::
Specify which output columns to print. See the *OUTPUT COLUMNS*
section for details of available columns.
*-r*, *--raw*::
Use raw output format.
*-r*, *--time* _clock_
Show current time of one specific clocks.
include::man-common/help-version.adoc[]
== OUTPUT COLUMNS
Each column has a type. Types are surround by < and >.
ID <``number``>::
Numeric clock ID.
CLOCK <``string``>::
Name in the form *CLOCK_*
NAME <``string``>::
Shorter, easier to read name.
TIME <``number``>::
Current clock timestamp as returned by *clock_gettime()*.
ISO_TIME <``string``>::
ISO8601 formatted version of *TIME*.
RESOLUTION <``number``>::
Clock resolution as returned by *clock_getres()*.
== AUTHORS
mailto:thomas@t-8ch.de[Thomas Weißschuh]
== SEE ALSO
*clock_getres*(2) *clock_gettime*(2)
include::man-common/bugreports.adoc[]
include::man-common/footer.adoc[]
ifdef::translation[]
include::man-common/translation.adoc[]
endif::[]

366
misc-utils/lsclocks.c Normal file
View file

@ -0,0 +1,366 @@
/*
* lsclocks(1) - display system clocks
*
* Copyright (C) 2023 Thomas Weißschuh <thomas@t-8ch.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it would be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <stdio.h>
#include <stdbool.h>
#include <time.h>
#include <inttypes.h>
#include <getopt.h>
#include <libsmartcols.h>
#include "c.h"
#include "nls.h"
#include "strutils.h"
#include "timeutils.h"
#include "closestream.h"
#include "xalloc.h"
#define CLOCKFD 3
#define FD_TO_CLOCKID(fd) ((~(clockid_t) (fd) << 3) | CLOCKFD)
#ifndef CLOCK_REALTIME
#define CLOCK_REALTIME 0
#endif
#ifndef CLOCK_MONOTONIC
#define CLOCK_MONOTONIC 1
#endif
#ifndef CLOCK_MONOTONIC_RAW
#define CLOCK_MONOTONIC_RAW 4
#endif
#ifndef CLOCK_REALTIME_COARSE
#define CLOCK_REALTIME_COARSE 5
#endif
#ifndef CLOCK_MONOTONIC_COARSE
#define CLOCK_MONOTONIC_COARSE 6
#endif
#ifndef CLOCK_BOOTTIME
#define CLOCK_BOOTTIME 7
#endif
#ifndef CLOCK_REALTIME_ALARM
#define CLOCK_REALTIME_ALARM 8
#endif
#ifndef CLOCK_BOOTTIME_ALARM
#define CLOCK_BOOTTIME_ALARM 9
#endif
#ifndef CLOCK_TAI
#define CLOCK_TAI 11
#endif
struct clockinfo {
clockid_t id;
const char * const id_name;
const char * const name;
};
static const struct clockinfo clocks[] = {
{ CLOCK_REALTIME, "CLOCK_REALTIME", "realtime" },
{ CLOCK_MONOTONIC, "CLOCK_MONOTONIC", "monotonic" },
{ CLOCK_MONOTONIC_RAW, "CLOCK_MONOTONIC_RAW", "monotonic-raw" },
{ CLOCK_REALTIME_COARSE, "CLOCK_REALTIME_COARSE", "realtime-coarse" },
{ CLOCK_MONOTONIC_COARSE, "CLOCK_MONOTONIC_COARSE", "monotonic-coarse" },
{ CLOCK_BOOTTIME, "CLOCK_BOOTTIME", "boottime" },
{ CLOCK_REALTIME_ALARM, "CLOCK_REALTIME_ALARM", "realtime-alarm" },
{ CLOCK_BOOTTIME_ALARM, "CLOCK_BOOTTIME_ALARM", "boottime-alarm" },
{ CLOCK_TAI, "CLOCK_TAI", "tai" },
};
/* column IDs */
enum {
COL_ID,
COL_CLOCK,
COL_NAME,
COL_TIME,
COL_ISO_TIME,
COL_RESOLUTION,
};
/* column names */
struct colinfo {
const char * const name; /* header */
double whint; /* width hint (N < 1 is in percent of termwidth) */
int flags; /* SCOLS_FL_* */
int json_type; /* SCOLS_JSON_* */
const char * const help;
};
/* columns descriptions */
static const struct colinfo infos[] = {
[COL_ID] = { "ID", 1, SCOLS_FL_RIGHT, SCOLS_JSON_NUMBER, N_("numeric id") },
[COL_CLOCK] = { "CLOCK", 1, 0, SCOLS_JSON_STRING, N_("symbolic name") },
[COL_NAME] = { "NAME", 1, 0, SCOLS_JSON_STRING, N_("readable name") },
[COL_TIME] = { "TIME", 1, SCOLS_FL_RIGHT, SCOLS_JSON_NUMBER, N_("numeric time") },
[COL_ISO_TIME] = { "ISO_TIME", 1, SCOLS_FL_RIGHT, SCOLS_JSON_STRING, N_("human readable ISO time") },
[COL_RESOLUTION] = { "RESOLUTION", 1, SCOLS_FL_RIGHT, SCOLS_JSON_NUMBER, N_("resolution") },
};
static int column_name_to_id(const char *name, size_t namesz)
{
size_t i;
for (i = 0; i < ARRAY_SIZE(infos); i++) {
const char *cn = infos[i].name;
if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
return i;
}
warnx(_("unknown column: %s"), name);
return -1;
}
static void __attribute__((__noreturn__)) usage(void)
{
FILE *out = stdout;
size_t i;
fputs(USAGE_HEADER, out);
fprintf(out, _(" %s [options]\n"), program_invocation_short_name);
fputs(USAGE_OPTIONS, out);
fputs(_(" -J, --json use JSON output format\n"), out);
fputs(_(" -n, --noheadings don't print headings\n"), out);
fputs(_(" -o, --output <list> output columns\n"), out);
fputs(_(" -r, --raw use raw output format\n"), out);
fputs(_(" -t, --time <clock> show current time of single clock\n"), out);
fputs(USAGE_SEPARATOR, out);
printf(USAGE_HELP_OPTIONS(25));
fprintf(out, USAGE_COLUMNS);
for (i = 0; i < ARRAY_SIZE(infos); i++)
fprintf(out, " %16s %-10s%s\n", infos[i].name,
infos[i].json_type == SCOLS_JSON_STRING? "<string>":
infos[i].json_type == SCOLS_JSON_ARRAY_STRING? "<string>":
infos[i].json_type == SCOLS_JSON_ARRAY_NUMBER? "<string>":
infos[i].json_type == SCOLS_JSON_NUMBER? "<number>":
"<boolean>",
_(infos[i].help));
printf(USAGE_MAN_TAIL("lslocks(1)"));
exit(EXIT_SUCCESS);
}
__attribute__ ((__format__ (__printf__, 3, 4)))
static void scols_line_asprintf(struct libscols_line *ln, size_t n, const char *format, ...)
{
char *data;
va_list args;
va_start(args, format);
xvasprintf(&data, format, args);
va_end(args);
scols_line_refer_data(ln, n, data);
}
static void scols_line_format_timespec(struct libscols_line *ln, size_t n, const struct timespec *ts)
{
scols_line_asprintf(ln, n, "%ju.%09" PRId32, (uintmax_t) ts->tv_sec, (uint32_t) ts->tv_nsec);
}
static clockid_t parse_clock(const char *name)
{
size_t i;
uint32_t id = -1;
int rc;
rc = ul_strtou32(name, &id, 10);
for (i = 0; i < ARRAY_SIZE(clocks); i++) {
if (!strcmp(name, clocks[i].id_name)
|| !strcmp(name, clocks[i].name))
return clocks[i].id;
if (rc == 0 && (clockid_t) id == clocks[i].id)
return id;
}
errx(EXIT_FAILURE, _("Unknown clock: %s"), name);
}
int main(int argc, char **argv)
{
size_t i, j;
char c;
int rc;
const struct colinfo *colinfo;
const struct clockinfo *clockinfo;
struct libscols_table *tb;
struct libscols_line *ln;
struct libscols_column *col;
bool noheadings = false, raw = false, json = false;
const char *outarg = NULL;
int columns[ARRAY_SIZE(infos) * 2];
size_t ncolumns = 0;
clockid_t clock = -1;
struct timespec resolution, now;
char buf[FORMAT_TIMESTAMP_MAX];
static const struct option longopts[] = {
{ "noheadings", no_argument, NULL, 'n' },
{ "output", required_argument, NULL, 'o' },
{ "version", no_argument, NULL, 'V' },
{ "help", no_argument, NULL, 'h' },
{ "json", no_argument, NULL, 'J' },
{ "raw", no_argument, NULL, 'r' },
{ "time", required_argument, NULL, 't' },
{ 0 }
};
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
close_stdout_atexit();
while ((c = getopt_long(argc, argv, "no:Jrt:Vh", longopts, NULL)) != -1) {
switch (c) {
case 'n':
noheadings = true;
break;
case 'o':
outarg = optarg;
break;
case 'J':
json = true;
break;
case 'r':
raw = true;
break;
case 't':
clock = parse_clock(optarg);
break;
case 'V':
print_version(EXIT_SUCCESS);
case 'h':
usage();
default:
errtryhelp(EXIT_FAILURE);
}
}
if (argv[optind])
errtryhelp(EXIT_FAILURE);
if (clock != -1) {
rc = clock_gettime(clock, &now);
if (rc)
err(EXIT_FAILURE, _("failed to get time"));
printf("%ju.%09"PRId32"\n", (uintmax_t) now.tv_sec, (uint32_t) now.tv_nsec);
return EXIT_SUCCESS;
}
if (!ncolumns) {
columns[ncolumns++] = COL_ID;
columns[ncolumns++] = COL_CLOCK;
columns[ncolumns++] = COL_NAME;
columns[ncolumns++] = COL_TIME;
columns[ncolumns++] = COL_ISO_TIME;
columns[ncolumns++] = COL_RESOLUTION;
}
if (outarg && string_add_to_idarray(outarg, columns, ARRAY_SIZE(columns),
&ncolumns, column_name_to_id) < 0)
return EXIT_FAILURE;
scols_init_debug(0);
tb = scols_new_table();
if (!tb)
errx(EXIT_FAILURE, _("failed to allocate output table"));
scols_table_set_name(tb, "clocks");
for (i = 0; i < ncolumns; i++) {
colinfo = &infos[columns[i]];
col = scols_table_new_column(tb, colinfo->name, colinfo->whint, colinfo->flags);
if (!col)
errx(EXIT_FAILURE, _("failed to allocate output column"));
scols_column_set_json_type(col, colinfo->json_type);
}
for (i = 0; i < ARRAY_SIZE(clocks); i++) {
clockinfo = &clocks[i];
ln = scols_table_new_line(tb, NULL);
if (!ln)
errx(EXIT_FAILURE, _("failed to allocate output line"));
/* outside the loop to guarantee consistency between COL_TIME and COL_ISO_TIME */
rc = clock_gettime(clockinfo->id, &now);
if (rc)
now.tv_nsec = -1;
for (j = 0; j < ncolumns; j++) {
switch (columns[j]) {
case COL_ID:
scols_line_asprintf(ln, j, "%ju", (uintmax_t) clockinfo->id);
break;
case COL_CLOCK:
scols_line_set_data(ln, j, clockinfo->id_name);
break;
case COL_NAME:
scols_line_set_data(ln, j, clockinfo->name);
break;
case COL_TIME:
if (now.tv_nsec == -1)
break;
scols_line_format_timespec(ln, j, &now);
break;
case COL_ISO_TIME:
if (now.tv_nsec == -1)
break;
rc = strtimespec_iso(&now,
ISO_GMTIME | ISO_DATE | ISO_TIME | ISO_T | ISO_DOTNSEC | ISO_TIMEZONE,
buf, sizeof(buf));
if (rc)
errx(EXIT_FAILURE, _("failed to format iso time"));
scols_line_set_data(ln, j, buf);
break;
case COL_RESOLUTION:
rc = clock_getres(clockinfo->id, &resolution);
if (!rc)
scols_line_format_timespec(ln, j, &resolution);
break;
}
}
}
scols_table_enable_json(tb, json);
scols_table_enable_raw(tb, raw);
scols_table_enable_noheadings(tb, noheadings);
scols_print_table(tb);
scols_unref_table(tb);
}

View file

@ -165,3 +165,7 @@ fadvise_sources = files(
waitpid_sources = files(
'waitpid.c',
)
lsclocks_sources = files(
'lsclocks.c',
)

View file

@ -87,6 +87,7 @@ TS_CMD_LINE=${TS_CMD_LINE-"${ts_commandsdir}line"}
TS_CMD_LOOK=${TS_CMD_LOOK-"${ts_commandsdir}look"}
TS_CMD_LOSETUP=${TS_CMD_LOSETUP:-"${ts_commandsdir}losetup"}
TS_CMD_LSBLK=${TS_CMD_LSBLK-"${ts_commandsdir}lsblk"}
TS_CMD_LSCLOCKS=${TS_CMD_LSCPU-"${ts_commandsdir}lsclocks"}
TS_CMD_LSCPU=${TS_CMD_LSCPU-"${ts_commandsdir}lscpu"}
TS_CMD_LSFD=${TS_CMD_LSFD-"${ts_commandsdir}lsfd"}
TS_CMD_LSMEM=${TS_CMD_LSMEM-"${ts_commandsdir}lsmem"}

View file

@ -0,0 +1,10 @@
ID CLOCK NAME
0 CLOCK_REALTIME realtime
1 CLOCK_MONOTONIC monotonic
4 CLOCK_MONOTONIC_RAW monotonic-raw
5 CLOCK_REALTIME_COARSE realtime-coarse
6 CLOCK_MONOTONIC_COARSE monotonic-coarse
7 CLOCK_BOOTTIME boottime
8 CLOCK_REALTIME_ALARM realtime-alarm
9 CLOCK_BOOTTIME_ALARM boottime-alarm
11 CLOCK_TAI tai

View file

@ -0,0 +1 @@
X.X

View file

@ -1,4 +1,4 @@
last 9 is expected to disappear in conversion
[7] [00010] [ipv6] [IPv6 ] [root ] [dns-server ] [2001:503:ba3e::2:30] [2013-08-28T20:30:40,123456+00:00]
[8] [00011] [ipv6] [IPv6 ] [root ] [dns-server ] [2001:503:ba3e::2:30] [2013-08-28T20:40:50,999999+00:00]
[0] [00000] [ts/0] [nonvalid] [foo ] [zero ] [0.0.0.0 ] [2013-08-28T12:00:00,12345678+00:00]
[0] [00000] [ts/0] [nonvalid] [foo ] [zero ] [0.0.0.0 ] [2013-08-28T12:00:00,000000+00:00]

42
tests/ts/misc/lsclocks Executable file
View file

@ -0,0 +1,42 @@
#!/bin/bash
# Copyright (C) 2023 Thomas Weißschuh <thomas@t-8ch.de>
#
# This file is part of util-linux.
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This file is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
TS_TOPDIR="${0%/*}/../.."
TS_DESC="lsclocks"
. "$TS_TOPDIR"/functions.sh
ts_init "$*"
ts_check_test_command "$TS_CMD_LSCLOCKS"
ts_check_prog sed
mask_timestamps() {
sed 's/[0-9]\+\.[0-9]\+/X.X/g'
}
ts_init_subtest basic
"$TS_CMD_LSCLOCKS" -o ID,CLOCK,NAME > "$TS_OUTPUT" 2>> "$TS_ERRLOG"
ts_finalize_subtest
ts_init_subtest time
"$TS_CMD_LSCLOCKS" --time monotonic | mask_timestamps > "$TS_OUTPUT" 2>> "$TS_ERRLOG"
ts_finalize_subtest
ts_finalize