From 953c674fa9b9ae6f20e2cbdd8ed17cadd17922c9 Mon Sep 17 00:00:00 2001 From: Andreas Dilger Date: Fri, 10 Jan 2020 14:18:53 -0700 Subject: [PATCH] LU-11407 tgt: cleanup job_stats output printing Escape non-printable and other special characters in the JobID name, which may be passed from the client environment, to avoid breaking YAML format parsing. Signed-off-by: Andreas Dilger Change-Id: If6a0bc4276fae03305f94e8c85d8f109913ebbe5 --- lustre/obdclass/lprocfs_jobstats.c | 42 +++++++++++++++++++++++++------------- lustre/tests/sanity.sh | 32 +++++++++++++++++++++-------- 2 files changed, 51 insertions(+), 23 deletions(-) diff --git a/lustre/obdclass/lprocfs_jobstats.c b/lustre/obdclass/lprocfs_jobstats.c index 5fc89a0..aba9ee4 100644 --- a/lustre/obdclass/lprocfs_jobstats.c +++ b/lustre/obdclass/lprocfs_jobstats.c @@ -420,28 +420,41 @@ static int inline width(const char *str, int len) static int lprocfs_jobstats_seq_show(struct seq_file *p, void *v) { - struct job_stat *job = v; - struct lprocfs_stats *s; - struct lprocfs_counter ret; - struct lprocfs_counter_header *cntr_header; - int i; + struct job_stat *job = v; + struct lprocfs_stats *s; + struct lprocfs_counter ret; + struct lprocfs_counter_header *cntr_header; + char escaped[LUSTRE_JOBID_SIZE * 4] = ""; + char *quote = "", *c, *end; + int i, joblen = 0; if (v == SEQ_START_TOKEN) { seq_printf(p, "job_stats:\n"); return 0; } - /* Replace the non-printable character in jobid with '?', so - * that the output of jobid will be confined in single line. */ - seq_printf(p, "- %-16s ", "job_id:"); - for (i = 0; i < strlen(job->js_jobid); i++) { - if (isprint(job->js_jobid[i]) != 0) - seq_putc(p, job->js_jobid[i]); - else - seq_putc(p, '?'); + /* Quote and escape jobid characters to escape hex codes "\xHH" if + * it contains any non-standard characters (space, newline, etc), + * so it will be confined to single line and not break parsing. + * We can't use "%*pEhps" or similar printk() format, since that does + * not escape quotes or other characters that break the parsing. + */ + for (c = job->js_jobid, end = job->js_jobid + sizeof(job->js_jobid); + c < end && *c != '\0'; + c++, joblen++) { + if (!isalnum(*c) && + *c != '.' && *c != '@' && *c != '-' && *c != '_') { + quote = "\""; + snprintf(escaped + joblen, sizeof(escaped), "\\x%02X", + (unsigned char)*c); + joblen += 3; + } else { + escaped[joblen] = *c; + } } - seq_putc(p, '\n'); + seq_printf(p, "- %-16s %s%*s%s\n", + "job_id:", quote, joblen, escaped, quote); seq_printf(p, " %-16s %lld\n", "snapshot_time:", job->js_timestamp); s = job->js_stats; @@ -470,6 +483,7 @@ static int lprocfs_jobstats_seq_show(struct seq_file *p, void *v) seq_printf(p, " }\n"); } + return 0; } diff --git a/lustre/tests/sanity.sh b/lustre/tests/sanity.sh index a847d88..21e6c47 100755 --- a/lustre/tests/sanity.sh +++ b/lustre/tests/sanity.sh @@ -18278,18 +18278,32 @@ test_205b() { (( $MDS1_VERSION >= $(version_code 2.13.54.91) )) || skip "Need MDS version at least 2.13.54.91" - job_stats="mdt.*.job_stats" - $LCTL set_param $job_stats=clear + local job_stats="mdt.*.job_stats" + local old_jobid=$(do_facet mds1 $LCTL get_param jobid_var) + + do_facet mds1 $LCTL set_param $job_stats=clear + # Setting jobid_var to USER might not be supported + [[ -n "$old_jobid" ]] && stack_trap "$LCTL set_param $old_jobid" $LCTL set_param jobid_var=USER || true - $LCTL set_param jobid_name="%e.%u" + stack_trap "$LCTL set_param $($LCTL get_param jobid_name)" + $LCTL set_param jobid_name="%j.%e.%u" + env -i USERTESTJOBSTATS=foolish touch $DIR/$tfile.1 - do_facet $SINGLEMDS $LCTL get_param $job_stats | - grep "job_id:.*foolish" && - error "Unexpected jobid found" - do_facet $SINGLEMDS $LCTL get_param $job_stats | - grep "open:.*min.*max.*sum" || - error "wrong job_stats format found" + do_facet mds1 $LCTL get_param $job_stats | grep "job_id:.*foolish" && + { do_facet mds1 $LCTL get_param $job_stats; + error "Unexpected jobid found"; } + do_facet mds1 $LCTL get_param $job_stats | grep "open:.*min.*max.*sum"|| + { do_facet mds1 $LCTL get_param $job_stats; + error "wrong job_stats format found"; } + + (( $MDS1_VERSION < $(version_code 2.14.0.17) )) && + echo "MDS does not yet escape jobid" && return 0 + $LCTL set_param jobid_var=TEST205b + env -i TEST205b="has sp" touch $DIR/$tfile.2 + do_facet mds1 $LCTL get_param $job_stats | grep "has.*x20sp" || + { do_facet mds1 $LCTL get_param $job_stats; + error "jobid not escaped"; } } run_test 205b "Verify job stats jobid and output format" -- 1.8.3.1