1272343Sngie/*	$NetBSD: h_forkcli.c,v 1.1 2011/01/05 17:19:09 pooka Exp $	*/
2272343Sngie
3272343Sngie#include <sys/types.h>
4272343Sngie#include <sys/wait.h>
5272343Sngie
6272343Sngie#include <err.h>
7272343Sngie#include <errno.h>
8272343Sngie#include <fcntl.h>
9272343Sngie#include <stdlib.h>
10272343Sngie#include <stdio.h>
11272343Sngie#include <string.h>
12272343Sngie#include <unistd.h>
13272343Sngie
14272343Sngie#include <rump/rump_syscalls.h>
15272343Sngie#include <rump/rumpclient.h>
16272343Sngie
17272343Sngiestatic void
18272343Sngiesimple(void)
19272343Sngie{
20272343Sngie	struct rumpclient_fork *rf;
21272343Sngie	pid_t pid1, pid2;
22272343Sngie	int fd, status;
23272343Sngie
24272343Sngie	if ((pid1 = rump_sys_getpid()) < 2)
25272343Sngie		errx(1, "unexpected pid %d", pid1);
26272343Sngie
27272343Sngie	fd = rump_sys_open("/dev/null", O_CREAT | O_RDWR);
28272343Sngie	if (rump_sys_write(fd, &fd, sizeof(fd)) != sizeof(fd))
29272343Sngie		errx(1, "write newlyopened /dev/null");
30272343Sngie
31272343Sngie	if ((rf = rumpclient_prefork()) == NULL)
32272343Sngie		err(1, "prefork");
33272343Sngie
34272343Sngie	switch (fork()) {
35272343Sngie	case -1:
36272343Sngie		err(1, "fork");
37272343Sngie		break;
38272343Sngie	case 0:
39272343Sngie		if (rumpclient_fork_init(rf) == -1)
40272343Sngie			err(1, "postfork init failed");
41272343Sngie
42272343Sngie		if ((pid2 = rump_sys_getpid()) < 2)
43272343Sngie			errx(1, "unexpected pid %d", pid2);
44272343Sngie		if (pid1 == pid2)
45272343Sngie			errx(1, "child and parent pids are equal");
46272343Sngie
47272343Sngie		/* check that we can access the fd, the close it and exit */
48272343Sngie		if (rump_sys_write(fd, &fd, sizeof(fd)) != sizeof(fd))
49272343Sngie			errx(1, "write child /dev/null");
50272343Sngie		rump_sys_close(fd);
51272343Sngie		break;
52272343Sngie	default:
53272343Sngie		/*
54272343Sngie		 * check that we can access the fd, wait for the child, and
55272343Sngie		 * check we can still access the fd
56272343Sngie		 */
57272343Sngie		if (rump_sys_write(fd, &fd, sizeof(fd)) != sizeof(fd))
58272343Sngie			errx(1, "write parent /dev/null");
59272343Sngie		if (wait(&status) == -1)
60272343Sngie			err(1, "wait failed");
61272343Sngie		if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
62272343Sngie			errx(1, "child exited with status %d", status);
63272343Sngie		if (rump_sys_write(fd, &fd, sizeof(fd)) != sizeof(fd))
64272343Sngie			errx(1, "write parent /dev/null");
65272343Sngie		break;
66272343Sngie	}
67272343Sngie}
68272343Sngie
69272343Sngiestatic void
70272343Sngiecancel(void)
71272343Sngie{
72272343Sngie
73272343Sngie	/* XXX: not implemented in client / server !!! */
74272343Sngie}
75272343Sngie
76272343Sngie#define TESTSTR "i am your fatherrrrrrr"
77272343Sngie#define TESTSLEN (sizeof(TESTSTR)-1)
78272343Sngiestatic void
79272343Sngiepipecomm(void)
80272343Sngie{
81272343Sngie	struct rumpclient_fork *rf;
82272343Sngie	char buf[TESTSLEN+1];
83272343Sngie	int pipetti[2];
84272343Sngie	int status;
85272343Sngie
86272343Sngie	if (rump_sys_pipe(pipetti) == -1)
87272343Sngie		errx(1, "pipe");
88272343Sngie
89272343Sngie	if ((rf = rumpclient_prefork()) == NULL)
90272343Sngie		err(1, "prefork");
91272343Sngie
92272343Sngie	switch (fork()) {
93272343Sngie	case -1:
94272343Sngie		err(1, "fork");
95272343Sngie		break;
96272343Sngie	case 0:
97272343Sngie		if (rumpclient_fork_init(rf) == -1)
98272343Sngie			err(1, "postfork init failed");
99272343Sngie
100272343Sngie		memset(buf, 0, sizeof(buf));
101272343Sngie		if (rump_sys_read(pipetti[0], buf, TESTSLEN) != TESTSLEN)
102272343Sngie			err(1, "pipe read");
103272343Sngie		if (strcmp(TESTSTR, buf) != 0)
104272343Sngie			errx(1, "teststring doesn't match, got %s", buf);
105272343Sngie		break;
106272343Sngie	default:
107272343Sngie		if (rump_sys_write(pipetti[1], TESTSTR, TESTSLEN) != TESTSLEN)
108272343Sngie			err(1, "pipe write");
109272343Sngie		if (wait(&status) == -1)
110272343Sngie			err(1, "wait failed");
111272343Sngie		if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
112272343Sngie			errx(1, "child exited with status %d", status);
113272343Sngie		break;
114272343Sngie	}
115272343Sngie}
116272343Sngie
117272343Sngiestatic void
118272343Sngiefakeauth(void)
119272343Sngie{
120272343Sngie	struct rumpclient_fork *rf;
121272343Sngie	uint32_t *auth;
122272343Sngie	int rv;
123272343Sngie
124272343Sngie	if ((rf = rumpclient_prefork()) == NULL)
125272343Sngie		err(1, "prefork");
126272343Sngie
127272343Sngie	/* XXX: we know the internal structure of rf */
128272343Sngie	auth = (void *)rf;
129272343Sngie	*(auth+3) = *(auth+3) ^ 0x1;
130272343Sngie
131272343Sngie	rv = rumpclient_fork_init(rf);
132272343Sngie	if (!(rv == -1 && errno == ESRCH))
133272343Sngie		exit(1);
134272343Sngie}
135272343Sngie
136272343Sngiestruct parsa {
137272343Sngie	const char *arg;		/* sp arg, el		*/
138272343Sngie	void (*spring)(void);		/* spring into action	*/
139272343Sngie} paragus[] = {
140272343Sngie	{ "simple", simple },
141272343Sngie	{ "cancel", cancel },
142272343Sngie	{ "pipecomm", pipecomm },
143272343Sngie	{ "fakeauth", fakeauth },
144272343Sngie};
145272343Sngie
146272343Sngieint
147272343Sngiemain(int argc, char *argv[])
148272343Sngie{
149272343Sngie	unsigned i;
150272343Sngie
151272343Sngie	if (argc != 2)
152272343Sngie		errx(1, "invalid usage");
153272343Sngie
154272343Sngie	if (rumpclient_init() == -1)
155272343Sngie		err(1, "rumpclient init");
156272343Sngie
157272343Sngie	for (i = 0; i < __arraycount(paragus); i++) {
158272343Sngie		if (strcmp(argv[1], paragus[i].arg) == 0) {
159272343Sngie			paragus[i].spring();
160272343Sngie			break;
161272343Sngie		}
162272343Sngie	}
163272343Sngie	if (i == __arraycount(paragus)) {
164272343Sngie		printf("invalid test %s\n", argv[1]);
165272343Sngie		exit(1);
166272343Sngie	}
167272343Sngie
168272343Sngie	exit(0);
169272343Sngie}
170