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
|
.B lschp
|
||||||
.RB [ \-h|\-\-help ]
|
.RB [ \-h|\-\-help ]
|
||||||
.RB [ \-v|\-\-version ]
|
.RB [ \-v|\-\-version ]
|
||||||
|
.RB [ \-\-format
|
||||||
|
.IR FORMAT ]
|
||||||
.RB [
|
.RB [
|
||||||
.I CHPID
|
.I CHPID
|
||||||
]
|
]
|
||||||
@@ -108,6 +110,77 @@ Print a short help text, then exit.
|
|||||||
Print version number, then exit.
|
Print version number, then exit.
|
||||||
.RE
|
.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
|
.SH SEE ALSO
|
||||||
.BR chchp (8)
|
.BR chchp (8)
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include "lib/util_base.h"
|
#include "lib/util_base.h"
|
||||||
#include "lib/util_file.h"
|
#include "lib/util_file.h"
|
||||||
|
#include "lib/util_fmt.h"
|
||||||
#include "lib/util_opt.h"
|
#include "lib/util_opt.h"
|
||||||
#include "lib/util_path.h"
|
#include "lib/util_path.h"
|
||||||
#include "lib/util_prg.h"
|
#include "lib/util_prg.h"
|
||||||
@@ -31,6 +32,11 @@
|
|||||||
#define CHP_CMG "cmg"
|
#define CHP_CMG "cmg"
|
||||||
#define CHP_ID "chpid"
|
#define CHP_ID "chpid"
|
||||||
|
|
||||||
|
static enum util_fmt_t fmt;
|
||||||
|
static bool fmt_specified;
|
||||||
|
|
||||||
|
#define OPT_FORMAT 262 /* --format */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Program configuration
|
* Program configuration
|
||||||
*/
|
*/
|
||||||
@@ -52,9 +58,85 @@ static const struct util_prg prg = {
|
|||||||
static struct util_opt opt_vec[] = {
|
static struct util_opt opt_vec[] = {
|
||||||
UTIL_OPT_HELP,
|
UTIL_OPT_HELP,
|
||||||
UTIL_OPT_VERSION,
|
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
|
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
|
* Read all attributes of a desired directory
|
||||||
*
|
*
|
||||||
@@ -133,8 +215,12 @@ static void print_chpid(const char *chp_dir, unsigned int css_id,
|
|||||||
} else {
|
} else {
|
||||||
util_rec_set(rec, CHP_PCHID, "%s", "-");
|
util_rec_set(rec, CHP_PCHID, "%s", "-");
|
||||||
}
|
}
|
||||||
if (!strlen(chp) || strcmp(util_rec_get(rec, CHP_ID), chp) == 0)
|
if (!strlen(chp) || strcmp(util_rec_get(rec, CHP_ID), chp) == 0) {
|
||||||
util_rec_print(rec);
|
if (fmt_specified)
|
||||||
|
fmt_rec_print_formatted(rec);
|
||||||
|
else
|
||||||
|
util_rec_print(rec);
|
||||||
|
}
|
||||||
free(path);
|
free(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,6 +282,7 @@ static void cmd_lschp(char *chp)
|
|||||||
int i, count;
|
int i, count;
|
||||||
char *path;
|
char *path;
|
||||||
|
|
||||||
|
fmt_init();
|
||||||
rec = util_rec_new_wide("=");
|
rec = util_rec_new_wide("=");
|
||||||
util_rec_def(rec, CHP_ID, UTIL_REC_ALIGN_LEFT, 6, "CHPID");
|
util_rec_def(rec, CHP_ID, UTIL_REC_ALIGN_LEFT, 6, "CHPID");
|
||||||
util_rec_def(rec, CHP_STATE, UTIL_REC_ALIGN_LEFT, 5, "Vary");
|
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_SHARED, UTIL_REC_ALIGN_LEFT, 6, "Shared");
|
||||||
util_rec_def(rec, CHP_PCHID, UTIL_REC_ALIGN_LEFT, 6, " PCHID");
|
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.*"
|
* Iterate over each "/sys/devices/css.*"
|
||||||
*/
|
*/
|
||||||
path = util_path_sysfs("devices");
|
path = util_path_sysfs("devices");
|
||||||
count = util_scandir(&de_vec, alphasort, path, "^css[[:xdigit:]]{1,2}$");
|
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++)
|
for (i = 0; i < count; i++)
|
||||||
print_css(de_vec[i]->d_name, rec, chp);
|
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);
|
util_ptr_vec_free((void **) de_vec, count);
|
||||||
free(path);
|
free(path);
|
||||||
util_rec_free(rec);
|
util_rec_free(rec);
|
||||||
|
fmt_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CHP_LEN 4
|
#define CHP_LEN 4
|
||||||
@@ -242,6 +335,10 @@ int main(int argc, char *argv[])
|
|||||||
case 'v':
|
case 'v':
|
||||||
util_prg_print_version();
|
util_prg_print_version();
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
case OPT_FORMAT:
|
||||||
|
fmt_specified = true;
|
||||||
|
fmt_set(argv[optind - 1]);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
util_opt_print_parse_error(c, argv);
|
util_opt_print_parse_error(c, argv);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
|||||||
Reference in New Issue
Block a user