137Srgrimes/*	$NetBSD: h_forkcli.c,v 1.1 2011/01/05 17:19:09 pooka Exp $	*/
237Srgrimes
337Srgrimes#include <sys/types.h>
437Srgrimes#include <sys/wait.h>
537Srgrimes
637Srgrimes#include <err.h>
737Srgrimes#include <errno.h>
837Srgrimes#include <fcntl.h>
937Srgrimes#include <stdlib.h>
1037Srgrimes#include <stdio.h>
1137Srgrimes#include <string.h>
1237Srgrimes#include <unistd.h>
1337Srgrimes
1437Srgrimes#include <rump/rump_syscalls.h>
1537Srgrimes#include <rump/rumpclient.h>
1637Srgrimes
1737Srgrimesstatic void
1837Srgrimessimple(void)
1937Srgrimes{
2037Srgrimes	struct rumpclient_fork *rf;
2137Srgrimes	pid_t pid1, pid2;
2237Srgrimes	int fd, status;
2337Srgrimes
2437Srgrimes	if ((pid1 = rump_sys_getpid()) < 2)
2537Srgrimes		errx(1, "unexpected pid %d", pid1);
2637Srgrimes
2737Srgrimes	fd = rump_sys_open("/dev/null", O_CREAT | O_RDWR);
2837Srgrimes	if (rump_sys_write(fd, &fd, sizeof(fd)) != sizeof(fd))
2937Srgrimes		errx(1, "write newlyopened /dev/null");
3037Srgrimes
3137Srgrimes	if ((rf = rumpclient_prefork()) == NULL)
3237Srgrimes		err(1, "prefork");
3337Srgrimes
3437Srgrimes	switch (fork()) {
3537Srgrimes	case -1:
3637Srgrimes		err(1, "fork");
3737Srgrimes		break;
3837Srgrimes	case 0:
3937Srgrimes		if (rumpclient_fork_init(rf) == -1)
4037Srgrimes			err(1, "postfork init failed");
4137Srgrimes
4237Srgrimes		if ((pid2 = rump_sys_getpid()) < 2)
4337Srgrimes			errx(1, "unexpected pid %d", pid2);
4437Srgrimes		if (pid1 == pid2)
4537Srgrimes			errx(1, "child and parent pids are equal");
4637Srgrimes
4737Srgrimes		/* check that we can access the fd, the close it and exit */
4837Srgrimes		if (rump_sys_write(fd, &fd, sizeof(fd)) != sizeof(fd))
4937Srgrimes			errx(1, "write child /dev/null");
5037Srgrimes		rump_sys_close(fd);
5137Srgrimes		break;
5237Srgrimes	default:
5337Srgrimes		/*
5437Srgrimes		 * check that we can access the fd, wait for the child, and
5537Srgrimes		 * check we can still access the fd
5637Srgrimes		 */
5737Srgrimes		if (rump_sys_write(fd, &fd, sizeof(fd)) != sizeof(fd))
5837Srgrimes			errx(1, "write parent /dev/null");
5937Srgrimes		if (wait(&status) == -1)
6037Srgrimes			err(1, "wait failed");
6137Srgrimes		if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
6237Srgrimes			errx(1, "child exited with status %d", status);
6337Srgrimes		if (rump_sys_write(fd, &fd, sizeof(fd)) != sizeof(fd))
6437Srgrimes			errx(1, "write parent /dev/null");
6537Srgrimes		break;
6637Srgrimes	}
6737Srgrimes}
6837Srgrimes
6937Srgrimesstatic void
7037Srgrimescancel(void)
7137Srgrimes{
7237Srgrimes
7337Srgrimes	/* XXX: not implemented in client / server !!! */
7437Srgrimes}
7537Srgrimes
7637Srgrimes#define TESTSTR "i am your fatherrrrrrr"
7737Srgrimes#define TESTSLEN (sizeof(TESTSTR)-1)
7837Srgrimesstatic void
7937Srgrimespipecomm(void)
8037Srgrimes{
8137Srgrimes	struct rumpclient_fork *rf;
8237Srgrimes	char buf[TESTSLEN+1];
8337Srgrimes	int pipetti[2];
8437Srgrimes	int status;
8537Srgrimes
8637Srgrimes	if (rump_sys_pipe(pipetti) == -1)
8737Srgrimes		errx(1, "pipe");
8837Srgrimes
8937Srgrimes	if ((rf = rumpclient_prefork()) == NULL)
9037Srgrimes		err(1, "prefork");
9137Srgrimes
9237Srgrimes	switch (fork()) {
9337Srgrimes	case -1:
9437Srgrimes		err(1, "fork");
9537Srgrimes		break;
9637Srgrimes	case 0:
9737Srgrimes		if (rumpclient_fork_init(rf) == -1)
9837Srgrimes			err(1, "postfork init failed");
9937Srgrimes
10037Srgrimes		memset(buf, 0, sizeof(buf));
10137Srgrimes		if (rump_sys_read(pipetti[0], buf, TESTSLEN) != TESTSLEN)
10237Srgrimes			err(1, "pipe read");
10337Srgrimes		if (strcmp(TESTSTR, buf) != 0)
10437Srgrimes			errx(1, "teststring doesn't match, got %s", buf);
10537Srgrimes		break;
10637Srgrimes	default:
10737Srgrimes		if (rump_sys_write(pipetti[1], TESTSTR, TESTSLEN) != TESTSLEN)
10837Srgrimes			err(1, "pipe write");
10937Srgrimes		if (wait(&status) == -1)
11037Srgrimes			err(1, "wait failed");
11137Srgrimes		if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
11237Srgrimes			errx(1, "child exited with status %d", status);
11337Srgrimes		break;
11437Srgrimes	}
11537Srgrimes}
11637Srgrimes
11737Srgrimesstatic void
11837Srgrimesfakeauth(void)
11937Srgrimes{
12037Srgrimes	struct rumpclient_fork *rf;
12137Srgrimes	uint32_t *auth;
12237Srgrimes	int rv;
12337Srgrimes
12437Srgrimes	if ((rf = rumpclient_prefork()) == NULL)
12537Srgrimes		err(1, "prefork");
12637Srgrimes
12737Srgrimes	/* XXX: we know the internal structure of rf */
12837Srgrimes	auth = (void *)rf;
12937Srgrimes	*(auth+3) = *(auth+3) ^ 0x1;
13037Srgrimes
13137Srgrimes	rv = rumpclient_fork_init(rf);
13237Srgrimes	if (!(rv == -1 && errno == ESRCH))
13337Srgrimes		exit(1);
13437Srgrimes}
13537Srgrimes
13637Srgrimesstruct parsa {
13737Srgrimes	const char *arg;		/* sp arg, el		*/
13837Srgrimes	void (*spring)(void);		/* spring into action	*/
13937Srgrimes} paragus[] = {
14037Srgrimes	{ "simple", simple },
14137Srgrimes	{ "cancel", cancel },
14237Srgrimes	{ "pipecomm", pipecomm },
14337Srgrimes	{ "fakeauth", fakeauth },
14437Srgrimes};
14537Srgrimes
14637Srgrimesint
14737Srgrimesmain(int argc, char *argv[])
14837Srgrimes{
14937Srgrimes	unsigned i;
15037Srgrimes
15137Srgrimes	if (argc != 2)
15237Srgrimes		errx(1, "invalid usage");
15337Srgrimes
15437Srgrimes	if (rumpclient_init() == -1)
15537Srgrimes		err(1, "rumpclient init");
15637Srgrimes
15737Srgrimes	for (i = 0; i < __arraycount(paragus); i++) {
15837Srgrimes		if (strcmp(argv[1], paragus[i].arg) == 0) {
15937Srgrimes			paragus[i].spring();
16037Srgrimes			break;
16137Srgrimes		}
16237Srgrimes	}
16337Srgrimes	if (i == __arraycount(paragus)) {
16437Srgrimes		printf("invalid test %s\n", argv[1]);
16537Srgrimes		exit(1);
16637Srgrimes	}
16737Srgrimes
16837Srgrimes	exit(0);
16937Srgrimes}
17037Srgrimes