[LTP] [PATCH v1 1/2] lib: Add support option for .needs_cmds

Wei Gao wegao@suse.com
Fri Sep 26 10:50:11 CEST 2025


NOTE:This patchset is draft for review not final one.
Since not include update .needs_cmds for all related testcases.

Suggested-by: Cyril Hrubis <chrubis@suse.cz>
Signed-off-by: Wei Gao <wegao@suse.com>
---
 include/tst_cmd.h     | 15 +++++++
 include/tst_private.h |  2 +
 include/tst_test.h    |  2 +-
 lib/tst_cmd.c         | 98 +++++++++++++++++++++++++++++++++++++++++++
 lib/tst_test.c        |  9 ++--
 5 files changed, 121 insertions(+), 5 deletions(-)

diff --git a/include/tst_cmd.h b/include/tst_cmd.h
index 939825646..c7e7e56c1 100644
--- a/include/tst_cmd.h
+++ b/include/tst_cmd.h
@@ -5,6 +5,8 @@
 #ifndef TST_CMD_H__
 #define TST_CMD_H__
 
+#include <stdbool.h>
+
 enum tst_cmd_flags {
 	/*
 	 * return the program exit code, otherwise it will call cleanup_fn() if the
@@ -16,6 +18,19 @@ enum tst_cmd_flags {
 	TST_CMD_TCONF_ON_MISSING = 2,
 };
 
+struct tst_cmd {
+	const char *cmd;
+	unsigned int required:1;
+	unsigned int support:1;
+};
+
+
+/*
+ * tst_cmd_present would loop over the tst_cmd array and return the supported flag
+ * value.
+ */
+bool tst_cmd_present(struct tst_cmd *pcmd, const char *cmd);
+
 /*
  * vfork() + execvp() specified program.
  *
diff --git a/include/tst_private.h b/include/tst_private.h
index 4c6479f4b..d549cf968 100644
--- a/include/tst_private.h
+++ b/include/tst_private.h
@@ -47,4 +47,6 @@ char tst_kconfig_get(const char *confname);
  */
 int tst_check_cmd(const char *cmd, const int brk_nosupp);
 
+int tst_check_needs_cmds(struct tst_cmd *cmd, const int brk_nosupp);
+
 #endif
diff --git a/include/tst_test.h b/include/tst_test.h
index 9c21c1728..8fb7cd86c 100644
--- a/include/tst_test.h
+++ b/include/tst_test.h
@@ -617,7 +617,7 @@ struct tst_fs {
 
 	const struct tst_tag *tags;
 
-	const char *const *needs_cmds;
+	struct tst_cmd *needs_cmds;
 
 	const enum tst_cg_ver needs_cgroup_ver;
 
diff --git a/lib/tst_cmd.c b/lib/tst_cmd.c
index 82d60497a..7457d17c4 100644
--- a/lib/tst_cmd.c
+++ b/lib/tst_cmd.c
@@ -330,3 +330,101 @@ error:
 
 	return 1;
 }
+
+int tst_check_needs_cmds(struct tst_cmd *cmd, const int brk_nosupp)
+{
+	struct version_parser *p;
+	char *cmd_token, *op_token, *version_token, *next, *str;
+	char path[PATH_MAX];
+	char parser_cmd[100];
+	int ver_parser, ver_get;
+
+	strcpy(parser_cmd, cmd->cmd);
+
+	cmd_token = strtok_r(parser_cmd, " ", &next);
+	op_token = strtok_r(NULL, " ", &next);
+	version_token = strtok_r(NULL, " ", &next);
+	str = strtok_r(NULL, " ", &next);
+
+	if (tst_get_path(cmd_token, path, sizeof(path)))
+		if (brk_nosupp)
+			tst_brkm(TCONF, NULL, "Couldn't find '%s' in $PATH", cmd_token);
+		else
+			goto error;
+
+	if (!op_token)
+		goto pass;
+
+	if (!version_token || str) {
+		tst_brkm(TCONF, NULL,
+			"Illegal format(%s), should use format like mkfs.ext4 >= 1.43.0",
+			cmd->cmd);
+	}
+
+	for (p = &version_parsers[0]; p->cmd; p++) {
+		if (!strcmp(p->cmd, cmd_token)) {
+			tst_resm(TINFO, "Parsing %s version", p->cmd);
+			break;
+		}
+	}
+
+	if (!p->cmd) {
+		tst_brkm(TBROK, NULL, "No version parser for %s implemented!",
+			cmd_token);
+	}
+
+	ver_parser = p->parser();
+	if (ver_parser < 0)
+		tst_brkm(TBROK, NULL, "Failed to parse %s version", p->cmd);
+
+	ver_get = p->table_get(version_token);
+	if (ver_get < 0)
+		tst_brkm(TBROK, NULL, "Failed to get %s version", p->cmd);
+
+	if (!strcmp(op_token, ">=")) {
+		if (ver_parser < ver_get)
+			goto error;
+	} else if (!strcmp(op_token, ">")) {
+		if (ver_parser <= ver_get)
+			goto error;
+	} else if (!strcmp(op_token, "<=")) {
+		if (ver_parser > ver_get)
+			goto error;
+	} else if (!strcmp(op_token, "<")) {
+		if (ver_parser >= ver_get)
+			goto error;
+	} else if (!strcmp(op_token, "==")) {
+		if (ver_parser != ver_get)
+			goto error;
+	} else if (!strcmp(op_token, "!=")) {
+		if (ver_parser == ver_get)
+			goto error;
+	} else {
+		tst_brkm(TCONF, NULL, "Invalid op(%s)", op_token);
+	}
+pass:
+	cmd->support = 1;
+	return 0;
+error:
+	cmd->support = 0;
+	if (brk_nosupp) {
+		tst_brkm(TCONF, NULL, "%s requires %s %d, but got %d",
+			cmd, op_token, ver_get, ver_parser);
+	} else {
+		tst_resm(TCONF, "%s requires %s %d, but got %d",
+			cmd, op_token, ver_get, ver_parser);
+	}
+
+	return 1;
+}
+
+bool tst_cmd_present(struct tst_cmd *pcmd, const char *cmd)
+{
+	while (pcmd->cmd) {
+		if (!strcmp(pcmd->cmd, cmd))
+			return pcmd->support;
+
+		pcmd++;
+	}
+	return false;
+}
diff --git a/lib/tst_test.c b/lib/tst_test.c
index b8894f782..41519d4e1 100644
--- a/lib/tst_test.c
+++ b/lib/tst_test.c
@@ -1422,11 +1422,12 @@ static void do_setup(int argc, char *argv[])
 		tst_brk(TCONF, "%dbit ABI is not supported", tst_test->needs_abi_bits);
 
 	if (tst_test->needs_cmds) {
-		const char *cmd;
-		int i;
+		struct tst_cmd *cmd = tst_test->needs_cmds;
 
-		for (i = 0; (cmd = tst_test->needs_cmds[i]); ++i)
-			tst_check_cmd(cmd, 1);
+		while (cmd->cmd) {
+			tst_check_needs_cmds(cmd,cmd->required);
+			cmd++;
+		}
 	}
 
 	if (tst_test->needs_drivers) {
-- 
2.51.0



More information about the ltp mailing list