2 * Copyright 2010, Sine Nomine Associates and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include <afs/param.h>
13 #include <afs/afsutil.h>
14 #include <tap/basic.h>
17 #include <sys/types.h>
25 #define FAILSTR "exec test failure\n"
26 #define ARGSTRING "teststring"
28 static struct exec_test {
29 const char *prefix; /* program prefix to run */
30 const char *suffix; /* program suffix to run */
31 const char *result; /* expected output from stdout from the child program,
32 or NULL if we should fail to run anything */
34 { "exec-test1.", NULL, "exec test 1\n" },
35 { NULL, ".exec-test2", "exec test 2\n" },
36 { "exec-test3.", ".suffix", "exec test 3\n" },
38 { "nonexistent", NULL, NULL },
42 create_child_script(const char *argv0, struct exec_test *test)
45 char *dirc, *basec, *bname, *dname;
46 const char *prefix, *suffix;
55 basec = strdup(argv0);
56 script = malloc(PATH_MAX);
58 if (!dirc || !basec || !script) {
62 dname = dirname(dirc);
63 bname = basename(basec);
65 prefix = test->prefix;
69 suffix = test->suffix;
74 sprintf(script, "%s/%s%s%s", dname, prefix, bname, suffix);
79 fd = open(script, O_WRONLY | O_CREAT | O_EXCL, 0770);
81 sysbail("open(%s)", script);
89 fprintf(fh, "#!/bin/sh\n"
90 "if test x\"$1\" = x%s ; then\n"
94 "fi\n", ARGSTRING, test->result);
102 main(int argc, char **argv)
110 unsigned long nTests = sizeof(tests) / sizeof(tests[0]);
113 /* in case afs_exec_alt tries to run us again */
117 child_argv[0] = argv[0];
118 child_argv[1] = ARGSTRING;
119 child_argv[2] = NULL;
124 * Testing afs_exec_alt is a little interesting, since a successful run
125 * means that we exec() someone else. Our general strategy is to fork and
126 * run some generated shell scripts that just output a (known) string and
127 * exit successfully. We have each of those scripts output something
128 * different so we can make sure we're executing the right one.
130 * This isn't 100% foolproof, since afs_exec_alt could bug out and exec
131 * some entirely different program, which happens to have the exact same
132 * behavior as our shell scripts. But we've tried to make that unlikely.
134 * The shell scripts are passed exactly one argument: 'teststring'. All
135 * they should do is see if that were given that argument, and if so,
136 * they should print out the expected 'result' string to stdout, and
137 * should exit with successful status.
140 for (i = 0; i < nTests; i++) {
150 child_script = create_child_script(argv[0], t);
161 printf("child: close(%d) failed: %s", fds[0], strerror(errno));
165 if (dup2(fds[1], 1) < 0) {
166 printf("dup2: %s", strerror(errno));
170 prog = afs_exec_alt(child_argc, child_argv, t->prefix, t->suffix);
171 if (t->result == NULL) {
172 printf("%s", FAILSTR);
175 printf("afs_exec_alt failed to exec %s: %s", prog, strerror(errno));
181 ssize_t result_len, nBytes;
186 sysdiag("parent: close(%d) failed", fds[1]);
194 result_len = strlen(result);
196 nBytes = read(fds[0], buf, sizeof(buf)-1);
197 is_int(result_len, nBytes,
198 "child output size for prefix=%s, suffix=%s",
199 t->prefix, t->suffix);
202 skip("read() failed; cannot test read buffer");
204 /* just so is_string doesn't go running off into memory... */
207 is_string(result, buf,
208 "child output for prefix=%s, suffix=%s",
209 t->prefix, t->suffix);
213 sysdiag("parent: close(%d) failed", fds[0]);
216 if (waitpid(pid, &status, 0) <= 0) {
221 if (unlink(child_script)) {
222 sysdiag("unlink(%s)", child_script);
227 ok(WIFEXITED(status), "child exited for prefix=%s, suffix=%s",
228 t->prefix, t->suffix);
230 if (WIFEXITED(status)) {
231 is_int(0, WEXITSTATUS(status),
232 "child exit code for prefix=%s, suffix=%s",
233 t->prefix, t->suffix);
235 skip("!WIFEXITED(status) (status=%d), cannot check exit code",
237 if (WIFSIGNALED(status)) {
238 diag("terminated with signal %d", WTERMSIG(status));