==> tests/spawn.c <==1/* Spawning: descriptors land where asked, the environment is extended and
2 * overridden, a process group of its own, statuses described. */
3#include "mesh/check.h"
4#include "mesh/spawn.h"
5
6#include <signal.h>
7#include <stdlib.h>
8#include <string.h>
9#include <sys/wait.h>
10#include <unistd.h>
11
12int main(void) {
13 int out[2];
14 char *err = NULL;
15 CHECK(mesh_pipe_cloexec(out, &err));
16 setenv("MESH_SPAWN_A", "old", 1);
17 char *argv[] = {"sh", "-c", "echo \"$MESH_SPAWN_A $MESH_SPAWN_B $(ps -o pgid= -p $$ | tr -d ' ') $$\" >&5", NULL};
18 char *env[] = {"MESH_SPAWN_A=new", "MESH_SPAWN_B=b", NULL};
19 mesh_spawn_fd fds[] = {{out[1], 5}};
20 pid_t pid;
21 CHECK(mesh_spawn(argv, env, fds, 1, &pid, &err));
22 close(out[1]);
23 char buf[128] = {0};
24 ssize_t n = read(out[0], buf, sizeof buf - 1);
25 int st;
26 waitpid(pid, &st, 0);
27 CHECK(n > 0);
28 char a[16], b[16];
29 long pgid, self;
30 CHECK(sscanf(buf, "%15s %15s %ld %ld", a, b, &pgid, &self) == 4);
31 CHECK_S(a, "new");
32 CHECK_S(b, "b");
33 CHECK_I(pgid, self);
34 CHECK(mesh_status_success(st));
35 char *d = mesh_describe_status(st);
36 CHECK_S(d, "exit 0");
37 free(d);
38 /* Exit codes and signals. */
39 char *e3[] = {"sh", "-c", "exit 3", NULL};
40 CHECK(mesh_spawn(e3, NULL, NULL, 0, &pid, &err));
41 waitpid(pid, &st, 0);
42 d = mesh_describe_status(st);
43 CHECK_S(d, "exit 3");
44 free(d);
45 CHECK_U(mesh_exit_word(st), 3 << 8);
46 char *k9[] = {"sh", "-c", "kill -9 $$", NULL};
47 CHECK(mesh_spawn(k9, NULL, NULL, 0, &pid, &err));
48 waitpid(pid, &st, 0);
49 d = mesh_describe_status(st);
50 CHECK_S(d, "signal 9 (Killed)");
51 free(d);
52 CHECK_U(mesh_exit_word(st), 9);
53 char *nope[] = {"/nonexistent/x", NULL};
54 CHECK(!mesh_spawn(nope, NULL, NULL, 0, &pid, &err));
55 CHECK_S(err, "posix_spawn /nonexistent/x: No such file or directory (os error 2)");
56 free(err);
57 return mesh_check_done();
58}