From 681f01dee6f7cae68dd32a58e0266346db11554d Mon Sep 17 00:00:00 2001 From: Jim Garlick Date: Tue, 24 Oct 2017 15:16:45 -0700 Subject: [PATCH] cmd/flux-kvs: handle non-JSON values in "dir" cmd Problem: the KVS allows non-JSON values to be stored, but flux kvs dir -R exits with an error if it encounters one. For each value, if it decodes as JSON, format it like before. But if it doesn't print it directly instead of exiting. Truncate output at 79 colummns, or at first newline if value contains them. Indicate truncated values by appending "...". Fixes #1158 --- src/cmd/flux-kvs.c | 93 +++++++++++++++++++++++++++++++++------------- 1 file changed, 68 insertions(+), 25 deletions(-) diff --git a/src/cmd/flux-kvs.c b/src/cmd/flux-kvs.c index 040ff0157819..829018eaf374 100644 --- a/src/cmd/flux-kvs.c +++ b/src/cmd/flux-kvs.c @@ -304,37 +304,73 @@ int main (int argc, char *argv[]) return (exitval); } -static void output_key_json_object (const char *key, json_t *o) +static void kv_printf (const char *key, int maxcol, const char *fmt, ...) +{ + va_list ap; + int rc; + char *val, *kv, *p; + bool overflow = false; + + assert (maxcol == 0 || maxcol > 3); + + va_start (ap, fmt); + rc = vasprintf (&val, fmt, ap); + va_end (ap); + + if (rc < 0) + log_err_exit ("%s", __FUNCTION__); + + if (asprintf (&kv, "%s%s%s", key ? key : "", + key ? " = " : "", + val) < 0) + log_err_exit ("%s", __FUNCTION__); + + if (maxcol != 0) { // perform truncation + if ((p = strchr (kv, '\n'))) { + *p = '\0'; + overflow = true; + } + if (strlen (kv) > maxcol - 3) { + kv[maxcol - 3] = '\0'; + overflow = true; + } + } + printf ("%s%s\n", kv, + overflow ? "..." : ""); + + free (val); + free (kv); +} + +static void output_key_json_object (const char *key, json_t *o, int maxcol) { char *s; - if (key) - printf ("%s = ", key); switch (json_typeof (o)) { case JSON_NULL: - printf ("nil\n"); + kv_printf (key, maxcol, "nil"); break; case JSON_TRUE: - printf ("true\n"); + kv_printf (key, maxcol, "true"); break; case JSON_FALSE: - printf ("false\n"); + kv_printf (key, maxcol, "false"); break; case JSON_REAL: - printf ("%f\n", json_real_value (o)); + kv_printf (key, maxcol, "%f", json_real_value (o)); break; case JSON_INTEGER: - printf ("%lld\n", (long long)json_integer_value (o)); + kv_printf (key, maxcol, "%lld", (long long)json_integer_value (o)); break; case JSON_STRING: - printf ("%s\n", json_string_value (o)); + kv_printf (key, maxcol, "%s", json_string_value (o)); break; case JSON_ARRAY: case JSON_OBJECT: default: if (!(s = json_dumps (o, JSON_SORT_KEYS))) log_msg_exit ("json_dumps failed"); - printf ("%s\n", s); + kv_printf (key, maxcol, "%s", s); free (s); break; } @@ -352,7 +388,7 @@ static void output_key_json_str (const char *key, if (!(o = json_loads (json_str, JSON_DECODE_ANY, &error))) log_msg_exit ("%s: %s (line %d column %d)", arg, error.text, error.line, error.column); - output_key_json_object (key, o); + output_key_json_object (key, o, 0); json_decref (o); } @@ -802,20 +838,20 @@ int cmd_dropcache (optparse_t *p, int argc, char **argv) return (0); } -static void dump_kvs_val (const char *key, const char *json_str) +static void dump_kvs_val (const char *key, int maxcol, const char *value) { json_t *o; - json_error_t error; - if (!json_str) - json_str = "null"; - if (!(o = json_loads (json_str, JSON_DECODE_ANY, &error))) { - printf ("%s: %s (line %d column %d)\n", - key, error.text, error.line, error.column); - return; + if (!value) { + kv_printf (key, maxcol, "NULL"); + } + else if ((o = json_loads (value, JSON_DECODE_ANY, NULL))) { + output_key_json_object (key, o, maxcol); + json_decref (o); + } + else { + kv_printf (key, maxcol, value); } - output_key_json_object (key, o); - json_decref (o); } static void dump_kvs_dir (const flux_kvsdir_t *dir, bool Ropt, bool dopt) @@ -826,6 +862,7 @@ static void dump_kvs_dir (const flux_kvsdir_t *dir, bool Ropt, bool dopt) flux_kvsitr_t *itr; const char *name; char *key; + const int maxcol = 79; itr = flux_kvsitr_create (dir); while ((name = flux_kvsitr_next (itr))) { @@ -850,11 +887,17 @@ static void dump_kvs_dir (const flux_kvsdir_t *dir, bool Ropt, bool dopt) printf ("%s.\n", key); } else { if (!dopt) { - const char *json_str; - if (!(f = flux_kvs_lookupat (h, 0, key, rootref)) - || flux_kvs_lookup_get (f, &json_str) < 0) + const char *value; + const void *buf; + int len; + if (!(f = flux_kvs_lookupat (h, 0, key, rootref))) + log_err_exit ("%s", key); + if (flux_kvs_lookup_get (f, &value) == 0) // null terminated + dump_kvs_val (key, maxcol, value); + else if (flux_kvs_lookup_get_raw (f, &buf, &len) == 0) + kv_printf (key, maxcol, "%.*s", len, buf); + else log_err_exit ("%s", key); - dump_kvs_val (key, json_str); flux_future_destroy (f); } else