mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
lschp: Support for structured output
Introduce a new command line flag ("--format") to specify the output
format. Valid options are "pairs" for shell-compatible key
value pairs, "csv" for CSV, "json" for a formatted JSON document, and
"json-seq" for a stream of JSON text sequences as per RFC7464[1].
[1]: https://datatracker.ietf.org/doc/html/rfc7464
Signed-off-by: Volkan Unal <vunal@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
@@ -11,6 +11,8 @@ lschp \- list information about available channel\-paths.
|
||||
.B lschp
|
||||
.RB [ \-h|\-\-help ]
|
||||
.RB [ \-v|\-\-version ]
|
||||
.RB [ \-\-format
|
||||
.IR FORMAT ]
|
||||
.RB [
|
||||
.I CHPID
|
||||
]
|
||||
@@ -108,6 +110,77 @@ Print a short help text, then exit.
|
||||
Print version number, then exit.
|
||||
.RE
|
||||
|
||||
.br
|
||||
.B \-\-format \fIFORMAT\fR
|
||||
.RS
|
||||
Specify the output format. Supported formats include
|
||||
\fIjson\fR, \fIjson-seq\fR, \fIpairs\fR and \fIcsv\fR.
|
||||
See section "OUTPUT FORMAT" for more details.
|
||||
.RE
|
||||
|
||||
|
||||
.SH "OUTPUT FORMAT"
|
||||
This section contains additional information for json output format.
|
||||
|
||||
.SS json
|
||||
|
||||
JSON output consists of a top-level object with the following properties
|
||||
(key-value pairs):
|
||||
|
||||
.IP \(bu 3
|
||||
.BR meta :
|
||||
Tool meta-data including API level, version, host name, and time of invocation
|
||||
.PP
|
||||
.IP \(bu 3
|
||||
.BR channel-paths :
|
||||
Information about available Channel\-path
|
||||
.PP
|
||||
|
||||
Example JSON output for channel-path with all properties:
|
||||
|
||||
.nf
|
||||
{
|
||||
"meta": {
|
||||
"api_level": 1,
|
||||
"version": "2.39.0-build-20260119",
|
||||
"host": "localhost",
|
||||
"time_epoch": 1769092556,
|
||||
"time": "2026-01-22 15:35:56+0100"
|
||||
},
|
||||
"channel_paths": [
|
||||
{
|
||||
"chpid": "0.32",
|
||||
"vary": 1,
|
||||
"cfg": 1,
|
||||
"type": 27,
|
||||
"cmg": 2,
|
||||
"shared": 1,
|
||||
"chid": 576,
|
||||
"chid_external": true
|
||||
},
|
||||
{
|
||||
"chpid": "0.34",
|
||||
"vary": 1,
|
||||
"cfg": 0,
|
||||
"type": 27,
|
||||
"cmg": null,
|
||||
"shared": null,
|
||||
"chid": 608,
|
||||
"chid_external": true
|
||||
},
|
||||
{
|
||||
"chpid": "0.f8",
|
||||
"vary": 1,
|
||||
"cfg": 1,
|
||||
"type": 36,
|
||||
"cmg": 3,
|
||||
"shared": 1,
|
||||
"chid": 2040,
|
||||
"chid_external": false
|
||||
}
|
||||
]
|
||||
}
|
||||
.fi
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR chchp (8)
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "lib/util_base.h"
|
||||
#include "lib/util_file.h"
|
||||
#include "lib/util_fmt.h"
|
||||
#include "lib/util_opt.h"
|
||||
#include "lib/util_path.h"
|
||||
#include "lib/util_prg.h"
|
||||
@@ -31,6 +32,11 @@
|
||||
#define CHP_CMG "cmg"
|
||||
#define CHP_ID "chpid"
|
||||
|
||||
static enum util_fmt_t fmt;
|
||||
static bool fmt_specified;
|
||||
|
||||
#define OPT_FORMAT 262 /* --format */
|
||||
|
||||
/*
|
||||
* Program configuration
|
||||
*/
|
||||
@@ -52,9 +58,85 @@ static const struct util_prg prg = {
|
||||
static struct util_opt opt_vec[] = {
|
||||
UTIL_OPT_HELP,
|
||||
UTIL_OPT_VERSION,
|
||||
{
|
||||
.option = { "format", required_argument, NULL, OPT_FORMAT},
|
||||
.argument = "FORMAT",
|
||||
.desc = "Output format (" FMT_TYPE_NAMES ")",
|
||||
.flags = UTIL_OPT_FLAG_NOSHORT,
|
||||
},
|
||||
UTIL_OPT_END
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the "--format" option
|
||||
*
|
||||
* @param[in] str Format for structured output
|
||||
*/
|
||||
static void fmt_set(const char *str)
|
||||
{
|
||||
if (!util_fmt_name_to_type(str, &fmt)) {
|
||||
errx(EXIT_FAILURE, "Unknown format '%s', supported formats: %s\n", str,
|
||||
FMT_TYPE_NAMES);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print buffer structure as formatted
|
||||
*
|
||||
* @param[in] rec The buffer structure, where results are written to
|
||||
*/
|
||||
static void fmt_rec_print_formatted(struct util_rec *rec)
|
||||
{
|
||||
const char *str_val, *key;
|
||||
struct util_rec_fld *fld;
|
||||
bool is_chid_external;
|
||||
int ival = -1;
|
||||
|
||||
util_fmt_obj_start(FMT_ROW, "entry");
|
||||
util_list_iterate(__util_rec_get_list(rec), fld) {
|
||||
key = util_rec_fld_get_key(fld);
|
||||
str_val = util_rec_get(rec, key);
|
||||
if (!strcmp(str_val, "-")) {
|
||||
util_fmt_pair(FMT_QUOTE | FMT_INVAL, key, "");
|
||||
} else if (!strcmp(key, CHP_PCHID)) {
|
||||
is_chid_external = (str_val[0] != '(');
|
||||
sscanf(str_val, is_chid_external ? "%x" : "(%x)", &ival);
|
||||
util_fmt_pair(FMT_DEFAULT, "chid", "%d", ival);
|
||||
util_fmt_pair(FMT_DEFAULT, "chid_external", "%s", is_chid_external ?
|
||||
"true" : "false");
|
||||
} else if (!strcmp(key, CHP_ID)) {
|
||||
util_fmt_pair(FMT_DEFAULT | FMT_QUOTE, key, "%s", str_val);
|
||||
} else if (!strcmp(key, CHP_TYPE)) {
|
||||
sscanf(str_val, "%x", &ival);
|
||||
util_fmt_pair(FMT_DEFAULT, key, "%d", ival);
|
||||
} else {
|
||||
ival = atoi(str_val);
|
||||
util_fmt_pair(FMT_DEFAULT, key, "%d", ival);
|
||||
}
|
||||
}
|
||||
util_fmt_obj_end(); /* entry */
|
||||
}
|
||||
|
||||
static void fmt_init(void)
|
||||
{
|
||||
unsigned int flags = FMT_HANDLEINT | FMT_KEEPINVAL;
|
||||
|
||||
if (!fmt_specified)
|
||||
return;
|
||||
if (fmt == FMT_CSV)
|
||||
flags |= FMT_NOMETA | FMT_QUOTEALL;
|
||||
else
|
||||
flags |= FMT_DEFAULT;
|
||||
util_fmt_init(stdout, fmt, flags, 1);
|
||||
}
|
||||
|
||||
static void fmt_end(void)
|
||||
{
|
||||
if (!fmt_specified)
|
||||
return;
|
||||
util_fmt_exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read all attributes of a desired directory
|
||||
*
|
||||
@@ -133,8 +215,12 @@ static void print_chpid(const char *chp_dir, unsigned int css_id,
|
||||
} else {
|
||||
util_rec_set(rec, CHP_PCHID, "%s", "-");
|
||||
}
|
||||
if (!strlen(chp) || strcmp(util_rec_get(rec, CHP_ID), chp) == 0)
|
||||
util_rec_print(rec);
|
||||
if (!strlen(chp) || strcmp(util_rec_get(rec, CHP_ID), chp) == 0) {
|
||||
if (fmt_specified)
|
||||
fmt_rec_print_formatted(rec);
|
||||
else
|
||||
util_rec_print(rec);
|
||||
}
|
||||
free(path);
|
||||
}
|
||||
|
||||
@@ -196,6 +282,7 @@ static void cmd_lschp(char *chp)
|
||||
int i, count;
|
||||
char *path;
|
||||
|
||||
fmt_init();
|
||||
rec = util_rec_new_wide("=");
|
||||
util_rec_def(rec, CHP_ID, UTIL_REC_ALIGN_LEFT, 6, "CHPID");
|
||||
util_rec_def(rec, CHP_STATE, UTIL_REC_ALIGN_LEFT, 5, "Vary");
|
||||
@@ -205,17 +292,23 @@ static void cmd_lschp(char *chp)
|
||||
util_rec_def(rec, CHP_SHARED, UTIL_REC_ALIGN_LEFT, 6, "Shared");
|
||||
util_rec_def(rec, CHP_PCHID, UTIL_REC_ALIGN_LEFT, 6, " PCHID");
|
||||
|
||||
util_rec_print_hdr(rec);
|
||||
if (!fmt_specified)
|
||||
util_rec_print_hdr(rec);
|
||||
/*
|
||||
* Iterate over each "/sys/devices/css.*"
|
||||
*/
|
||||
path = util_path_sysfs("devices");
|
||||
count = util_scandir(&de_vec, alphasort, path, "^css[[:xdigit:]]{1,2}$");
|
||||
if (fmt_specified)
|
||||
util_fmt_obj_start(FMT_LIST, "channel_paths");
|
||||
for (i = 0; i < count; i++)
|
||||
print_css(de_vec[i]->d_name, rec, chp);
|
||||
if (fmt_specified)
|
||||
util_fmt_obj_end(); /* channel_paths */
|
||||
util_ptr_vec_free((void **) de_vec, count);
|
||||
free(path);
|
||||
util_rec_free(rec);
|
||||
fmt_end();
|
||||
}
|
||||
|
||||
#define CHP_LEN 4
|
||||
@@ -242,6 +335,10 @@ int main(int argc, char *argv[])
|
||||
case 'v':
|
||||
util_prg_print_version();
|
||||
return EXIT_SUCCESS;
|
||||
case OPT_FORMAT:
|
||||
fmt_specified = true;
|
||||
fmt_set(argv[optind - 1]);
|
||||
break;
|
||||
default:
|
||||
util_opt_print_parse_error(c, argv);
|
||||
return EXIT_FAILURE;
|
||||
|
||||
Reference in New Issue
Block a user