s390-tools: add lsstp utility

A small utility to display the STP information present in sysfs
in a more readable way.

Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Sven Schnelle
2020-07-14 08:54:51 +02:00
committed by Jan Höppner
parent 1df4d66387
commit 8b31319ddf
5 changed files with 317 additions and 1 deletions

1
.gitignore vendored
View File

@@ -46,6 +46,7 @@ libutil/util_rec_example
libutil/util_scandir_example
libzds/libzds.a
libvmcp/vmcp_example
lsstp/lsstp
mon_tools/mon_fsstatd
mon_tools/mon_procd
osasnmpd/osasnmpd

View File

@@ -9,7 +9,7 @@ TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \
vmconvert vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \
ziomon iucvterm hyptop cmsfs-fuse qethqoat zfcpdump zdsfs cpumf \
systemd hmcdrvfs cpacfstats zdev dump2tar zkey netboot etc zpcictl \
genprotimg
genprotimg lsstp
SUB_DIRS = $(LIB_DIRS) $(TOOL_DIRS)

18
lsstp/Makefile Normal file
View File

@@ -0,0 +1,18 @@
include ../common.mak
libs = $(rootdir)/libutil/libutil.a
all: lsstp
lsstp: lsstp.o $(libs)
install: all
$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) \
$(DESTDIR)$(MANDIR)/man8
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 lsstp $(DESTDIR)$(BINDIR)
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 lsstp.8 \
$(DESTDIR)$(MANDIR)/man8
clean:
rm -f *.o *~ lsstp core
.PHONY: all install clean

79
lsstp/lsstp.8 Normal file
View File

@@ -0,0 +1,79 @@
.\" Copyright 2020 IBM Corp.
.\" s390-tools is free software; you can redistribute it and/or modify
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH LSSTP 8 "Jul 2020" "s390-tools" "Linux Administrator's Manual"
.SH NAME
.B "lsstp "
\- tool to show STP system information
.SH SYNOPSIS
.BI "lsstp "
.SH DESCRIPTION
.B lsstp
displays information about the currenta Server Time Protocol (STP) configuration
like Coordianted Timing Network (CTN) ID, Timing state and Leap seconds.
.SH OUTPUT
.TP
.B STP online
Whether the STP subsystem is online
.TP
.B CTN ID
The ID of the Coordinated Time Network. If it can be decoded as EBCDIC it will be shown as EBCDIC String, otherwise a hexadecimal representation is shown.
.TP
.B CTN Type
The type of timing network.
.IP
.B No CTN
STP is not configured for attachment to a CTN.
.IP
.B STP-only
STP is configured and attached to a CTN with only STP nodes.
.IP
.B Mixed
STP is configured and attached to a CTN which contains both STP and External Time Reference (ETR) nodes.
.TP
.B Stratum
The Stratum level of the STP clock. This indicates the number of servers in the timing path between the local STP clock and the selected primary time server.
.TP
.B Timing mode
.IP
.B Local
The Time-of-day (TOD) clock is stepped to the local hardware oscillator and is not steered by the STP facility.
.IP
.B ETR
The TOD clock is synchronized with an attached 9037 Sysplex Timer.
.IP
.B STP
The TOD clock is steered by the STP facility to maintain synchronization with a Coordinated Server Time (CST).
.IP
.B Uninitialized
The TOD clock is not initialized. The STP facility is allowed to perform a step adjustment to the TOD clock for synchronization.
.TP
.B Timing state
The synchronization state of the STP facilty. Can be unsynchronzied, synchronized and stopped.
.TP
.B DST offset
The Daylight savings time offset relative to UTC in minutes.
.TP
.B Timezone offset
The offset of the local time relative to UTC in minutes.
.TP
.B Time offset
The total time offset at the server. This field is only valid in mixed CTN configurations.
.TP
.B Active Leap seconds
The number of Leap seconds that are currently in effect at the STP facility.
.TP
.B Leap second <insertion|delation> at
If a Leap second insertion or deletetion is scheduled in the STP facility, this field will show the Day and Time of the scheduled change.
.SH OPTIONS
.TP
.BI "-v|--version"
Print version number.
.TP
.BI "-h|--help"
Print usage text.
.SH AUTHORS
Sven Schnelle <svens@linux.ibm.com>

218
lsstp/lsstp.c Normal file
View File

@@ -0,0 +1,218 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <iconv.h>
#include <inttypes.h>
#include "lib/util_opt.h"
#include "lib/util_file.h"
#include "lib/util_prg.h"
#include "lib/util_path.h"
static const struct util_prg prg = {
.desc = "Display STP system information",
.args = "",
.copyright_vec = {
{
.owner = "IBM Corp.",
.pub_first = 2020,
},
UTIL_PRG_COPYRIGHT_END
}
};
static struct util_opt opt_vec[] = {
UTIL_OPT_HELP,
UTIL_OPT_VERSION,
UTIL_OPT_END
};
struct stp_parms {
uint64_t ctn_id;
unsigned int online;
unsigned int leap_seconds;
int leap_seconds_diff;
unsigned int leap_seconds_utc;
unsigned int stratum;
unsigned int ctn_type;
unsigned int timing_mode;
unsigned int timing_state;
int dst_offset;
int time_offset;
int time_zone_offset;
};
static int convert_ctn_id(char *in, char *out)
{
iconv_t ic;
size_t inlen = sizeof(unsigned long long);
size_t outlen = sizeof(unsigned long long);
ic = iconv_open("ISO-8859-1", "EBCDIC-US");
if (ic == (iconv_t)-1) {
warn("Could not initialize EBCDIC to ISO-8859-1 conversion table");
return -1;
}
if (iconv(ic, &in, &inlen, (char **)&out, &outlen) == (size_t)-1) {
warn("Code page translation EBCDIC to ISO-8859-1 failed");
iconv_close(ic);
return -1;
}
iconv_close(ic);
return 0;
}
static const char *ctn_type_str(int type)
{
switch (type) {
case 0:
return "No CTN defined";
case 1:
return "STP-only";
case 2:
return "mixed";
default:
return "unknown";
}
}
static const char *tmd_to_str(int mode)
{
switch (mode) {
case 0:
return "Local";
case 1:
return "ETR";
case 2:
return "STP";
case 15:
return "Uninitialized";
default:
return "unknown";
}
}
static const char *tst_to_str(int mode)
{
switch (mode) {
case 0:
return "Unsynchronized";
case 1:
return "Synchronized";
case 2:
return "Physical clock stopped";
default:
return "unknown";
}
}
static const char *yesno_str(int val)
{
return val ? "yes" : "no";
}
#define read_sysfs_attr(attr, parm, func, base) \
do { \
path = util_path_sysfs("devices/system/stp/%s", attr); \
ret = func(parm, base, path); \
if (ret) { \
fprintf(stderr, "failed to open %s: %s\n", path, strerror(errno)); \
free(path); \
exit(EXIT_FAILURE); \
} \
free(path); \
} while (0)
int main(int argc, char **argv)
{
struct stp_parms parm = { 0 };
char ctn_id[32] = { 0 };
char *path;
int ret, c;
util_prg_init(&prg);
util_opt_init(opt_vec, NULL);
for (;;) {
c = util_opt_getopt_long(argc, argv);
if (c == -1)
break;
switch (c) {
case 'v':
util_prg_print_version();
exit(EXIT_SUCCESS);
case 'h':
util_prg_print_help();
util_opt_print_help();
exit(EXIT_SUCCESS);
default:
fprintf(stderr, "Try 'lsstp --help' for more information.\n");
exit(EXIT_FAILURE);
}
}
read_sysfs_attr("online", &parm.online, util_file_read_ui, 10);
if (!parm.online) {
printf("STP disabled\n");
goto out;
}
read_sysfs_attr("ctn_id", &parm.ctn_id, util_file_read_ul, 16);
read_sysfs_attr("ctn_type", &parm.ctn_type, util_file_read_ui, 10);
read_sysfs_attr("stratum", &parm.stratum, util_file_read_ui, 10);
read_sysfs_attr("leap_seconds", &parm.leap_seconds, util_file_read_ui, 10);
read_sysfs_attr("timing_mode", &parm.timing_mode, util_file_read_ui, 10);
read_sysfs_attr("timing_state", &parm.timing_state, util_file_read_ui, 10);
read_sysfs_attr("dst_offset", &parm.dst_offset, util_file_read_i, 10);
read_sysfs_attr("time_offset", &parm.time_offset, util_file_read_i, 10);
read_sysfs_attr("time_zone_offset", &parm.time_zone_offset, util_file_read_i, 10);
if (convert_ctn_id((char *)&parm.ctn_id, ctn_id))
snprintf(ctn_id, sizeof(ctn_id)-1, "%016" PRIx64, parm.ctn_id);
printf("STP online: %s\n"
"CTN ID: %s\n"
"CTN type: %s\n"
"Stratum: %d\n"
"Timing mode: %s\n"
"Timing state: %s\n"
"DST offset: %d\n"
"Timezone offset: %d\n"
"Time offset: %d\n"
"Active leap seconds: %d\n",
yesno_str(parm.online),
ctn_id,
ctn_type_str(parm.ctn_type),
parm.stratum,
tmd_to_str(parm.timing_mode),
tst_to_str(parm.timing_state),
parm.dst_offset,
parm.time_zone_offset,
parm.time_offset,
parm.leap_seconds);
printf("Scheduled leap second: ");
path = util_path_sysfs("devices/system/stp/leap_seconds_scheduled");
if (util_file_read_va(path, "%d,%d", &parm.leap_seconds_utc,
&parm.leap_seconds_diff) == 2 &&
parm.leap_seconds_diff && parm.leap_seconds_utc) {
time_t lsoup = parm.leap_seconds_utc;
printf("%s at: %s UTC",
parm.leap_seconds_diff > 0 ? "insertion" : "deletion",
ctime(&lsoup));
} else {
printf("-\n");
}
free(path);
return 0;
out:
return 1;
}