@@ -19,6 +19,19 @@ enum tst_cmd_flags {
TST_CMD_TCONF_ON_MISSING = 2,
};
+/**
+ * struct tst_cmd - Provides details about a command struct needed by LTP test.
+ * @cmd: The name of the command.
+ * @optional: A flag indicating if the command is optional.
+ * @present: A flag indicating if the command was found at runtime. This is an output
+ * parameter, set by the LTP library during the test setup.
+ */
+struct tst_cmd {
+ const char *cmd;
+ unsigned int optional:1;
+ unsigned int present:1;
+};
+
/*
* vfork() + execvp() specified program.
*
@@ -526,7 +526,7 @@ struct tst_fs {
*
* @tags: A {} terminated array of test tags. See struct tst_tag for details.
*
- * @needs_cmds: A NULL terminated array of commands required for the test to run.
+ * @needs_cmds: A NULL terminated array of :ref:`struct tst_cmd` required for the test to run.
*
* @needs_cgroup_ver: If set the test will run only if the specified cgroup
* version is present on the system.
@@ -619,7 +619,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;
@@ -12,13 +12,13 @@ static void do_test(void)
static struct tst_test test = {
.test_all = do_test,
- .needs_cmds = (const char *[]) {
- "mkfs.ext4",
- "mkfs.ext4 >= 1.0.0",
- "mkfs.ext4 <= 2.0.0",
- "mkfs.ext4 != 2.0.0",
- "mkfs.ext4 > 1.0.0",
- "mkfs.ext4 < 2.0.0",
- NULL
+ .needs_cmds = (struct tst_cmd[]) {
+ {.cmd = "mkfs.ext4", .optional = 1},
+ {.cmd = "mkfs.ext4 >= 1.0.0", .optional = 0},
+ {.cmd = "mkfs.ext4 <= 2.0.0"},
+ {.cmd = "mkfs.ext4 != 2.0.0"},
+ {.cmd = "mkfs.ext4 > 1.0.0"},
+ {.cmd = "mkfs.ext4 < 2.0.0"},
+ {}
}
};
@@ -16,8 +16,8 @@ static void do_test(void)
static struct tst_test test = {
.test_all = do_test,
- .needs_cmds = (const char *[]) {
- "mkfs.ext45 >= 1.43.0",
- NULL
+ .needs_cmds = (struct tst_cmd[]) {
+ {.cmd = "mkfs.ext45 >= 1.43.0"},
+ {}
}
};
@@ -16,8 +16,8 @@ static void do_test(void)
static struct tst_test test = {
.test_all = do_test,
- .needs_cmds = (const char *[]) {
- "mkfs.ext4 ! 1.43.0",
- NULL
+ .needs_cmds = (struct tst_cmd[]) {
+ {.cmd = "mkfs.ext4 ! 1.43.0"},
+ {}
}
};
@@ -16,8 +16,8 @@ static void do_test(void)
static struct tst_test test = {
.test_all = do_test,
- .needs_cmds = (const char *[]) {
- "mkfs.ext4 > 1.43",
- NULL
+ .needs_cmds = (struct tst_cmd[]) {
+ {.cmd = "mkfs.ext4 > 1.43"},
+ {}
}
};
@@ -16,8 +16,8 @@ static void do_test(void)
static struct tst_test test = {
.test_all = do_test,
- .needs_cmds = (const char *[]) {
- "mkfs.ext4 > 1.43.0-1",
- NULL
+ .needs_cmds = (struct tst_cmd[]) {
+ {.cmd = "mkfs.ext4 > 1.43.0-1"},
+ {}
}
};
@@ -16,8 +16,8 @@ static void do_test(void)
static struct tst_test test = {
.test_all = do_test,
- .needs_cmds = (const char *[]) {
- "mkfs.ext4 > 1.43.0 2",
- NULL
+ .needs_cmds = (struct tst_cmd[]) {
+ {.cmd = "mkfs.ext4 > 1.43.0 2"},
+ {}
}
};
@@ -16,8 +16,8 @@ static void do_test(void)
static struct tst_test test = {
.test_all = do_test,
- .needs_cmds = (const char *[]) {
- "mkfs.ext45",
- NULL
+ .needs_cmds = (struct tst_cmd[]) {
+ {.cmd = "mkfs.ext45"},
+ {}
}
};
@@ -18,9 +18,9 @@ static void do_test(void)
static struct tst_test test = {
.test_all = do_test,
- .needs_cmds = (const char *[]) {
- "mkfs.xfs",
- "mkfs.xfs >= 4.20.0",
- NULL
+ .needs_cmds = (struct tst_cmd[]) {
+ {.cmd = "mkfs.xfs"},
+ {.cmd = "mkfs.xfs >= 4.20.0"},
+ {}
}
};
@@ -1449,11 +1449,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 *pcmd = tst_test->needs_cmds;
- for (i = 0; (cmd = tst_test->needs_cmds[i]); ++i)
- tst_check_cmd(cmd, 1);
+ while (pcmd->cmd) {
+ pcmd->present = tst_check_cmd(pcmd->cmd, !pcmd->optional) ? 1 : 0;
+ pcmd++;
+ }
}
if (tst_test->needs_drivers) {
@@ -240,9 +240,9 @@ static struct tst_test test = {
"zram",
NULL
},
- .needs_cmds = (const char *[]) {
- "modprobe",
- "rmmod",
- NULL
+ .needs_cmds = (struct tst_cmd[]) {
+ {.cmd = "modprobe"},
+ {.cmd = "rmmod"},
+ {}
}
};
@@ -102,9 +102,9 @@ static struct tst_test test = {
.needs_root = 1,
.needs_device = 1,
.dev_min_size = 1,
- .needs_cmds = (const char *const []) {
- "mksquashfs",
- NULL
+ .needs_cmds = (struct tst_cmd[]) {
+ {.cmd = "mksquashfs"},
+ {}
},
.needs_drivers = (const char *const []) {
"squashfs",
@@ -277,8 +277,8 @@ static struct tst_test test = {
"CONFIG_HAVE_ARCH_MMAP_RND_BITS=y",
NULL
},
- .needs_cmds = (const char *[]) {
- "ldd",
- NULL
+ .needs_cmds = (struct tst_cmd[]) {
+ {.cmd = "ldd"},
+ {}
},
};
@@ -231,11 +231,11 @@ static struct tst_test test = {
{&user_buf, .size = 64},
{}
},
- .needs_cmds = (const char *const []) {
- "useradd",
- "userdel",
- "groupdel",
- NULL
+ .needs_cmds = (struct tst_cmd[]) {
+ {.cmd = "useradd"},
+ {.cmd = "userdel"},
+ {.cmd = "groupdel"},
+ {}
},
.tags = (const struct tst_tag[]) {
{"linux-git", "a08bf91ce28"},
@@ -327,9 +327,9 @@ static struct tst_test test = {
{"linux-git", "76486b104168"},
{}
},
- .needs_cmds = (const char *[]) {
- "debugfs",
- NULL
+ .needs_cmds = (struct tst_cmd[]) {
+ {.cmd = "debugfs"},
+ {}
}
};
@@ -108,9 +108,9 @@ static struct tst_test test = {
"loop",
NULL
},
- .needs_cmds = (const char *const []) {
- "parted",
- NULL
+ .needs_cmds = (struct tst_cmd[]) {
+ {.cmd = "parted"},
+ {}
},
.needs_tmpdir = 1,
};
@@ -421,10 +421,10 @@ static struct tst_test test = {
HW_MODULE,
NULL
},
- .needs_cmds = (const char *[]) {
- "modprobe",
- "rmmod",
- NULL
+ .needs_cmds = (struct tst_cmd[]) {
+ {.cmd = "modprobe"},
+ {.cmd = "rmmod"},
+ {}
},
.needs_kconfigs = (const char *[]) {
"CONFIG_MEMORY_FAILURE=y",
@@ -223,9 +223,9 @@ static struct tst_test test = {
{}
},
.mntpoint = MNTPOINT,
- .needs_cmds = (const char *const []) {
- "quotacheck",
- NULL
+ .needs_cmds = (struct tst_cmd[]) {
+ {.cmd = "quotacheck"},
+ {}
},
.setup = setup,
.cleanup = cleanup,
@@ -165,8 +165,8 @@ static struct tst_test test = {
},
.mntpoint = MNTPOINT,
.test_variants = QUOTACTL_SYSCALL_VARIANTS,
- .needs_cmds = (const char *[]) {
- "mkfs.ext4 >= 1.43.0",
- NULL
+ .needs_cmds = (struct tst_cmd[]) {
+ {.cmd = "mkfs.ext4 >= 1.43.0"},
+ {}
}
};
@@ -226,9 +226,9 @@ static struct tst_test test = {
},
.mntpoint = MNTPOINT,
.mount_device = 1,
- .needs_cmds = (const char *const []) {
- "quotacheck",
- NULL
+ .needs_cmds = (struct tst_cmd[]) {
+ {.cmd = "quotacheck"},
+ {}
},
.needs_root = 1,
.test_variants = QUOTACTL_FMT_VARIANTS,
@@ -220,8 +220,8 @@ static struct tst_test test = {
.setup = setup,
.cleanup = cleanup,
.test_variants = QUOTACTL_SYSCALL_VARIANTS,
- .needs_cmds = (const char *[]) {
- "mkfs.ext4 >= 1.43.0",
- NULL
+ .needs_cmds = (struct tst_cmd[]) {
+ {.cmd = "mkfs.ext4 >= 1.43.0"},
+ {}
}
};
@@ -185,8 +185,8 @@ static struct tst_test test = {
.mount_device = 1,
.needs_root = 1,
.test_variants = QUOTACTL_SYSCALL_VARIANTS,
- .needs_cmds = (const char *[]) {
- "mkfs.ext4 >= 1.43.0",
- NULL
+ .needs_cmds = (struct tst_cmd[]) {
+ {.cmd = "mkfs.ext4 >= 1.43.0"},
+ {}
}
};
@@ -123,9 +123,9 @@ static struct tst_test test = {
{.type = "ext4"},
{}
},
- .needs_cmds = (const char *[]) {
- "mkfs.ext4 >= 1.43.0",
- "e4crypt",
- NULL
+ .needs_cmds = (struct tst_cmd[]) {
+ {.cmd = "mkfs.ext4 >= 1.43.0"},
+ {.cmd = "e4crypt"},
+ {}
}
};
@@ -171,8 +171,8 @@ static struct tst_test test = {
{}
},
.needs_root = 1,
- .needs_cmds = (const char *[]) {
- "exportfs",
- NULL
+ .needs_cmds = (struct tst_cmd[]) {
+ {.cmd = "exportfs"},
+ {}
}
};
@@ -162,8 +162,8 @@ static struct tst_test test = {
"CONFIG_FS_VERITY",
NULL
},
- .needs_cmds = (const char *[]) {
- "mkfs.ext4 >= 1.45.2",
- NULL
+ .needs_cmds = (struct tst_cmd[]) {
+ {.cmd = "mkfs.ext4 >= 1.45.2"},
+ {}
}
};
@@ -179,6 +179,21 @@ static ujson_obj fs_obj = {
.attr_cnt = UJSON_ARRAY_SIZE(fs_attrs),
};
+enum cmd_ids {
+ CMD,
+ OPTIONAL,
+};
+
+static ujson_obj_attr cmd_attrs[] = {
+ UJSON_OBJ_ATTR_IDX(CMD, "cmd", UJSON_STR),
+ UJSON_OBJ_ATTR_IDX(OPTIONAL, "optional", UJSON_INT),
+};
+
+static ujson_obj cmd_obj = {
+ .attrs = cmd_attrs,
+ .attr_cnt = UJSON_ARRAY_SIZE(cmd_attrs),
+};
+
static int parse_mnt_flags(ujson_reader *reader, ujson_val *val)
{
int ret = 0;
@@ -256,6 +271,45 @@ static struct tst_fs *parse_filesystems(ujson_reader *reader, ujson_val *val)
return ret;
}
+static struct tst_cmd *parse_cmds(ujson_reader *reader, ujson_val *val)
+{
+ unsigned int i = 0, cnt = 0;
+ struct tst_cmd *ret;
+
+ ujson_reader_state state = ujson_reader_state_save(reader);
+
+ UJSON_ARR_FOREACH(reader, val) {
+ if (val->type != UJSON_OBJ) {
+ ujson_err(reader, "Expected object!");
+ return NULL;
+ }
+ ujson_obj_skip(reader);
+ cnt++;
+ }
+
+ ujson_reader_state_load(reader, state);
+
+ ret = SAFE_MALLOC(sizeof(struct tst_cmd) * (cnt + 1));
+ memset(&ret[cnt], 0, sizeof(ret[cnt]));
+
+ UJSON_ARR_FOREACH(reader, val) {
+ UJSON_OBJ_FOREACH_FILTER(reader, val, &cmd_obj, ujson_empty_obj) {
+ switch ((enum cmd_ids)val->idx) {
+ case CMD:
+ ret[i].cmd = strdup(val->val_str);
+ break;
+ case OPTIONAL:
+ ret[i].optional = val->val_int;
+ break;
+ }
+ }
+
+ i++;
+ }
+
+ return ret;
+}
+
static struct tst_tag *parse_tags(ujson_reader *reader, ujson_val *val)
{
unsigned int i = 0, cnt = 0;
@@ -450,7 +504,7 @@ static void parse_metadata(void)
ujson_err(&reader, "ABI bits must be 32 or 64");
break;
case NEEDS_CMDS:
- test.needs_cmds = parse_strarr(&reader, &val);
+ test.needs_cmds = parse_cmds(&reader, &val);
break;
case NEEDS_DEVFS:
test.needs_devfs = val.val_bool;