action: implement exec() test option
Exec() adds the ability to run a command, with the
result of the test being the exit status of the command;
if the command returns a valid exit status (0), exec() returns
TRUE, otherwise on a bad exit status exec() returns FALSE.
Three environment variables hold:
- NAME: name of file
- PATHNAME: pathname of file relative to squashfs root
- SOURCE_PATHNAME: the pathname of the file in the source
directory
Currently only a single argument (without spaces) can be entered
as a command, this is because the actions parser currently lacks the
ability to have arguments with spaces in them (either argument quoted
with '"', or spaces blackslashed with '\')!
Signed-off-by: Phillip Lougher <phillip@squashfs.org.uk>
diff --git a/squashfs-tools/action.c b/squashfs-tools/action.c
index 08ac64c..25860ca 100644
--- a/squashfs-tools/action.c
+++ b/squashfs-tools/action.c
@@ -22,6 +22,7 @@
* action.c
*/
+#include <fcntl.h>
#include <dirent.h>
#include <stddef.h>
#include <stdlib.h>
@@ -2139,6 +2140,73 @@
}
+/*
+ * Exec test specific code
+ */
+static int exec_fn(struct atom *atom, struct action_data *action_data)
+{
+ int child, i, res, status;
+
+ child = fork();
+ if (child == -1)
+ BAD_ERROR("exec_fn fork_failed\n");
+
+ if (child == 0) {
+ /*
+ * Child process
+ * redirect stdin, stdout & stderr to /dev/null and
+ * execute atom->argv[0]
+ */
+ int fd = open("/dev/null", O_RDWR);
+ if(fd == -1)
+ exit(EXIT_FAILURE);
+
+ close(STDIN_FILENO);
+ close(STDOUT_FILENO);
+ close(STDERR_FILENO);
+ for(i = 0; i < 3; i++) {
+ res = dup(fd);
+ if (res == -1)
+ exit(EXIT_FAILURE);
+ }
+ close(fd);
+
+ /*
+ * Create environment variables
+ * NAME: name of file
+ * PATHNAME: pathname of file relative to squashfs root
+ * SOURCE_PATHNAME: the pathname of the file in the source
+ * directory
+ */
+ res = setenv("NAME", action_data->name, 1);
+ if(res == -1)
+ exit(EXIT_FAILURE);
+
+ res = setenv("PATHNAME", action_data->subpath, 1);
+ if(res == -1)
+ exit(EXIT_FAILURE);
+
+ res = setenv("SOURCE_PATHNAME", action_data->pathname, 1);
+ if(res == -1)
+ exit(EXIT_FAILURE);
+
+ execl("/bin/sh", "sh", "-c", atom->argv[0], (char *) NULL);
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * Parent process.
+ */
+
+ res = waitpid(child, &status, 0);
+
+ if (res == -1)
+ BAD_ERROR("exec_fn waitpid failed\n");
+
+ return WIFEXITED(status) ? WEXITSTATUS(status) == 0 : 0;
+}
+
+
static struct test_entry test_table[] = {
{ "name", 1, name_fn},
{ "pathname", 1, pathname_fn, check_pathname},
@@ -2169,6 +2237,7 @@
{ "true", 0, true_fn, NULL},
{ "false", 0, false_fn, NULL},
{ "file", 1, file_fn, parse_file_arg},
+ { "exec", 1, exec_fn, NULL},
{ "", -1 }
};