From edba74df1d20c8b99bb79670f4baf90b9e1e1328 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Thomas=20Wei=C3=9Fschuh?= Date: Tue, 11 Jul 2023 21:01:05 +0200 Subject: [PATCH] lsclocks: add support for RTC MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Weißschuh --- bash-completion/lsclocks | 6 ++ misc-utils/lsclocks.1.adoc | 7 ++ misc-utils/lsclocks.c | 162 +++++++++++++++++++++++++------ tests/expected/misc/lsclocks-rtc | 1 + tests/ts/misc/lsclocks | 16 ++- 5 files changed, 160 insertions(+), 32 deletions(-) create mode 100644 tests/expected/misc/lsclocks-rtc diff --git a/bash-completion/lsclocks b/bash-completion/lsclocks index 30cf9c545a..7158701ea7 100644 --- a/bash-completion/lsclocks +++ b/bash-completion/lsclocks @@ -31,6 +31,11 @@ _lsclocks_module() COMPREPLY=( $(compgen -o filenames -W "$clocks" -- "$cur") ) return 0 ;; + '-x'|'--rtc') + clocks="$(echo /dev/rtc*)" + COMPREPLY=( $(compgen -o filenames -W "$clocks" -- "$cur") ) + return 0 + ;; '-c'|'--cpu-clock') _pids return 0 @@ -48,6 +53,7 @@ _lsclocks_module() --raw --time --dynamic-clock + --rtc --cpu-clock --help --version" diff --git a/misc-utils/lsclocks.1.adoc b/misc-utils/lsclocks.1.adoc index 32de275f60..bb0e1db8bc 100644 --- a/misc-utils/lsclocks.1.adoc +++ b/misc-utils/lsclocks.1.adoc @@ -49,6 +49,13 @@ Do not try to discover dynamic clocks. Also display specified dynamic clock. Can be specified multiple times. +*--no-discover-rtc* +Do not try to discover RTCs. + +*-x*, *--rtc* _path_ +Also display specified RTC. +Can be specified multiple times. + *-c*, *--cpu-clock* _pid_ Also display CPU clock of specified process. Can be specified multiple times. diff --git a/misc-utils/lsclocks.c b/misc-utils/lsclocks.c index 1e81a42815..a8531510a5 100644 --- a/misc-utils/lsclocks.c +++ b/misc-utils/lsclocks.c @@ -24,9 +24,12 @@ #include #include #include +#include #include +#include + #include "c.h" #include "nls.h" #include "strutils.h" @@ -94,6 +97,7 @@ enum CLOCK_TYPE { CT_SYS, CT_PTP, CT_CPU, + CT_RTC, }; static const char *clock_type_name(enum CLOCK_TYPE type) @@ -105,6 +109,8 @@ static const char *clock_type_name(enum CLOCK_TYPE type) return "ptp"; case CT_CPU: return "cpu"; + case CT_RTC: + return "rtc"; } errx(EXIT_FAILURE, _("Unknown clock type %d"), type); } @@ -115,6 +121,7 @@ struct clockinfo { const char * const id_name; const char * const name; const char * const ns_offset_name; + bool no_id; }; static const struct clockinfo clocks[] = { @@ -291,9 +298,9 @@ static int64_t get_namespace_offset(const char *name) } static void add_clock_line(struct libscols_table *tb, const int *columns, - size_t ncolumns, const struct clockinfo *clockinfo) + size_t ncolumns, const struct clockinfo *clockinfo, + const struct timespec *now, const struct timespec *resolution) { - struct timespec resolution, now; char buf[FORMAT_TIMESTAMP_MAX]; struct libscols_line *ln; size_t i; @@ -303,22 +310,13 @@ static void add_clock_line(struct libscols_table *tb, const int *columns, 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; - - rc = clock_getres(clockinfo->id, &resolution); - if (rc) - resolution.tv_nsec = -1; - for (i = 0; i < ncolumns; i++) { switch (columns[i]) { case COL_TYPE: scols_line_set_data(ln, i, clock_type_name(clockinfo->type)); break; case COL_ID: - if (CLOCKID_IS_DYNAMIC(clockinfo->id)) + if (!clockinfo->no_id) scols_line_asprintf(ln, i, "%ju", (uintmax_t) clockinfo->id); break; case COL_CLOCK: @@ -328,16 +326,16 @@ static void add_clock_line(struct libscols_table *tb, const int *columns, scols_line_set_data(ln, i, clockinfo->name); break; case COL_TIME: - if (now.tv_nsec == -1) + if (now->tv_nsec == -1) break; - scols_line_format_timespec(ln, i, &now); + scols_line_format_timespec(ln, i, now); break; case COL_ISO_TIME: - if (now.tv_nsec == -1) + if (now->tv_nsec == -1) break; - rc = strtimespec_iso(&now, + rc = strtimespec_iso(now, ISO_GMTIME | ISO_DATE | ISO_TIME | ISO_T | ISO_DOTNSEC | ISO_TIMEZONE, buf, sizeof(buf)); if (rc) @@ -345,23 +343,23 @@ static void add_clock_line(struct libscols_table *tb, const int *columns, scols_line_set_data(ln, i, buf); break; case COL_RESOL: - if (resolution.tv_nsec == -1) + if (resolution->tv_nsec == -1) break; - rc = strtimespec_relative(&resolution, buf, sizeof(buf)); + rc = strtimespec_relative(resolution, buf, sizeof(buf)); if (rc) errx(EXIT_FAILURE, _("failed to format relative time")); scols_line_set_data(ln, i, buf); break; case COL_RESOL_RAW: - if (resolution.tv_nsec == -1) + if (resolution->tv_nsec == -1) break; - scols_line_format_timespec(ln, i, &resolution); + scols_line_format_timespec(ln, i, resolution); break; case COL_REL_TIME: - if (now.tv_nsec == -1) + if (now->tv_nsec == -1) break; - rc = strtimespec_relative(&now, buf, sizeof(buf)); + rc = strtimespec_relative(now, buf, sizeof(buf)); if (rc) errx(EXIT_FAILURE, _("failed to format relative time")); scols_line_set_data(ln, i, buf); @@ -375,6 +373,23 @@ static void add_clock_line(struct libscols_table *tb, const int *columns, } } +static void add_posix_clock_line(struct libscols_table *tb, const int *columns, + size_t ncolumns, const struct clockinfo *clockinfo) +{ + struct timespec resolution, now; + int rc; + + rc = clock_gettime(clockinfo->id, &now); + if (rc) + now.tv_nsec = -1; + + rc = clock_getres(clockinfo->id, &resolution); + if (rc) + resolution.tv_nsec = -1; + + add_clock_line(tb, columns, ncolumns, clockinfo, &now, &resolution); +} + struct path_clock { struct list_head head; const char * path; @@ -394,11 +409,11 @@ static void add_dynamic_clock_from_path(struct libscols_table *tb, struct clockinfo clockinfo = { .type = CT_PTP, - .id = FD_TO_CLOCKID(fd), + .no_id = true, .id_name = path, .name = path, }; - add_clock_line(tb, columns, ncolumns, &clockinfo); + add_posix_clock_line(tb, columns, ncolumns, &clockinfo); close(fd); } @@ -422,6 +437,70 @@ static void add_dynamic_clocks_from_discovery(struct libscols_table *tb, globfree(&state); } +static void add_rtc_clock_from_path(struct libscols_table *tb, + const int *columns, size_t ncolumns, + const char *path, bool explicit) +{ + int fd, rc; + struct rtc_time rtc_time; + struct tm tm = { 0 }; + struct timespec now = { 0 }, resolution = { .tv_nsec = -1 }; + + fd = open(path, O_RDONLY); + if (fd == -1) { + if (explicit) + err(EXIT_FAILURE, _("Could not open %s"), path); + else + return; + } + + rc = ioctl(fd, RTC_RD_TIME, &rtc_time); + if (rc) + err(EXIT_FAILURE, + _("ioctl(RTC_RD_NAME) to %s to read the time failed"), path); + + tm.tm_sec = rtc_time.tm_sec; + tm.tm_min = rtc_time.tm_min; + tm.tm_hour = rtc_time.tm_hour; + tm.tm_mday = rtc_time.tm_mday; + tm.tm_mon = rtc_time.tm_mon; + tm.tm_year = rtc_time.tm_year; + tm.tm_wday = rtc_time.tm_wday; + tm.tm_yday = rtc_time.tm_yday; + + now.tv_sec = mktime(&tm); + + struct clockinfo clockinfo = { + .type = CT_RTC, + .no_id = true, + .id_name = path, + .name = path, + }; + add_clock_line(tb, columns, ncolumns, &clockinfo, &now, &resolution); + + close(fd); +} + +static void add_rtc_clocks_from_discovery(struct libscols_table *tb, + const int *columns, size_t ncolumns) +{ + int rc; + size_t i; + glob_t state; + + rc = glob("/dev/rtc*", 0, NULL, &state); + if (rc == GLOB_NOMATCH) + return; + if (rc) + errx(EXIT_FAILURE, _("Could not glob: %d"), rc); + + for (i = 0; i < state.gl_pathc; i++) + add_rtc_clock_from_path(tb, columns, ncolumns, + state.gl_pathv[i], false); + + globfree(&state); +} + struct cpu_clock { struct list_head head; pid_t pid; @@ -443,9 +522,9 @@ static void add_cpu_clock(struct libscols_table *tb, struct clockinfo clockinfo = { .type = CT_CPU, .name = name, - .id = clockid, + .no_id = true, }; - add_clock_line(tb, columns, ncolumns, &clockinfo); + add_posix_clock_line(tb, columns, ncolumns, &clockinfo); } @@ -458,7 +537,8 @@ int main(int argc, char **argv) struct libscols_table *tb; struct libscols_column *col; - bool noheadings = false, raw = false, json = false, disc_dynamic = true; + bool noheadings = false, raw = false, json = false, + disc_dynamic = true, disc_rtc = true; const char *outarg = NULL; int columns[ARRAY_SIZE(infos) * 2]; size_t ncolumns = 0; @@ -466,13 +546,14 @@ int main(int argc, char **argv) struct path_clock *path_clock; struct cpu_clock *cpu_clock; struct list_head *current_path_clock, *current_cpu_clock; - struct list_head dynamic_clocks, cpu_clocks; + struct list_head dynamic_clocks, cpu_clocks, rtc_clocks; struct timespec now; enum { OPT_OUTPUT_ALL = CHAR_MAX + 1, OPT_NO_DISC_DYN, + OPT_NO_DISC_RTC, }; static const struct option longopts[] = { { "noheadings", no_argument, NULL, 'n' }, @@ -486,6 +567,8 @@ int main(int argc, char **argv) { "no-discover-dynamic", no_argument, NULL, OPT_NO_DISC_DYN }, { "dynamic-clock", required_argument, NULL, 'd' }, { "cpu-clock", required_argument, NULL, 'c' }, + { "no-discover-rtc", no_argument, NULL, OPT_NO_DISC_RTC }, + { "rtc", required_argument, NULL, 'x' }, { 0 } }; @@ -496,8 +579,9 @@ int main(int argc, char **argv) INIT_LIST_HEAD(&dynamic_clocks); INIT_LIST_HEAD(&cpu_clocks); + INIT_LIST_HEAD(&rtc_clocks); - while ((c = getopt_long(argc, argv, "no:Jrt:d:c:Vh", longopts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "no:Jrt:d:c:x:Vh", longopts, NULL)) != -1) { switch (c) { case 'n': noheadings = true; @@ -533,6 +617,14 @@ int main(int argc, char **argv) "%jd", (intmax_t) cpu_clock->pid); list_add(&cpu_clock->head, &cpu_clocks); break; + case 'x': + path_clock = xmalloc(sizeof(*path_clock)); + path_clock->path = optarg; + list_add(&path_clock->head, &rtc_clocks); + break; + case OPT_NO_DISC_RTC: + disc_rtc = false; + break; case 'V': print_version(EXIT_SUCCESS); case 'h': @@ -584,7 +676,7 @@ int main(int argc, char **argv) } for (i = 0; i < ARRAY_SIZE(clocks); i++) - add_clock_line(tb, columns, ncolumns, &clocks[i]); + add_posix_clock_line(tb, columns, ncolumns, &clocks[i]); if (disc_dynamic) add_dynamic_clocks_from_discovery(tb, columns, ncolumns); @@ -596,6 +688,16 @@ int main(int argc, char **argv) list_free(&dynamic_clocks, struct path_clock, head, free); + if (disc_rtc) + add_rtc_clocks_from_discovery(tb, columns, ncolumns); + + list_for_each(current_path_clock, &rtc_clocks) { + path_clock = list_entry(current_path_clock, struct path_clock, head); + add_rtc_clock_from_path(tb, columns, ncolumns, path_clock->path, true); + } + + list_free(&rtc_clocks, struct path_clock, head, free); + list_for_each(current_cpu_clock, &cpu_clocks) { cpu_clock = list_entry(current_cpu_clock, struct cpu_clock, head); add_cpu_clock(tb, columns, ncolumns, cpu_clock->pid, cpu_clock->name); diff --git a/tests/expected/misc/lsclocks-rtc b/tests/expected/misc/lsclocks-rtc new file mode 100644 index 0000000000..85615b147f --- /dev/null +++ b/tests/expected/misc/lsclocks-rtc @@ -0,0 +1 @@ +rtc /dev/rtc0 /dev/rtc0 diff --git a/tests/ts/misc/lsclocks b/tests/ts/misc/lsclocks index f1e403c5bd..71fefaa52b 100755 --- a/tests/ts/misc/lsclocks +++ b/tests/ts/misc/lsclocks @@ -27,9 +27,11 @@ mask_timestamps() { sed 's/[0-9]\+\.[0-9]\+/X.X/g' } +NO_DISCOVER="--no-discover-dynamic --no-discover-rtc" + ts_init_subtest basic -"$TS_CMD_LSCLOCKS" --no-discover-dynamic -o TYPE,ID,CLOCK,NAME > "$TS_OUTPUT" 2>> "$TS_ERRLOG" +"$TS_CMD_LSCLOCKS" $NO_DISCOVER -o TYPE,ID,CLOCK,NAME > "$TS_OUTPUT" 2>> "$TS_ERRLOG" ts_finalize_subtest @@ -42,13 +44,23 @@ ts_finalize_subtest ts_init_subtest dynamic if [ -c /dev/ptp0 ] && [ -r /dev/ptp0 ]; then - "$TS_CMD_LSCLOCKS" --no-discover-dynamic --dynamic-clock /dev/ptp0 --output TYPE,ID,CLOCK,NAME \ + "$TS_CMD_LSCLOCKS" $NO_DISCOVER --dynamic-clock /dev/ptp0 --output TYPE,ID,CLOCK,NAME \ | tail -1 > "$TS_OUTPUT" 2>> "$TS_ERRLOG" ts_finalize_subtest else ts_skip_subtest "/dev/ptp0 not usable" fi +ts_init_subtest rtc + +if [ -c /dev/rtc0 ] && [ -r /dev/rtc0 ]; then + "$TS_CMD_LSCLOCKS" $NO_DISCOVER --rtc /dev/rtc0 --output TYPE,ID,CLOCK,NAME \ + | tail -1 > "$TS_OUTPUT" 2>> "$TS_ERRLOG" + ts_finalize_subtest +else + ts_skip_subtest "/dev/rtc0 not usable" +fi + ts_init_subtest cpu "$TS_CMD_LSCLOCKS" --cpu 1 --output TYPE,ID,NAME | tail -1 > "$TS_OUTPUT" 2>> "$TS_ERRLOG" -- 2.47.2