1/*	$NetBSD: h_forkcli.c,v 1.1 2011/01/05 17:19:09 pooka Exp $	*/
2
3#include <sys/types.h>
4#include <sys/wait.h>
5
6#include <err.h>
7#include <errno.h>
8#include <fcntl.h>
9#include <stdlib.h>
10#include <stdio.h>
11#include <string.h>
12#include <unistd.h>
13
14#include <rump/rump_syscalls.h>
15#include <rump/rumpclient.h>
16
17static void
18simple(void)
19{
20	struct rumpclient_fork *rf;
21	pid_t pid1, pid2;
22	int fd, status;
23
24	if ((pid1 = rump_sys_getpid()) < 2)
25		errx(1, "unexpected pid %d", pid1);
26
27	fd = rump_sys_open("/dev/null", O_CREAT | O_RDWR);
28	if (rump_sys_write(fd, &fd, sizeof(fd)) != sizeof(fd))
29		errx(1, "write newlyopened /dev/null");
30
31	if ((rf = rumpclient_prefork()) == NULL)
32		err(1, "prefork");
33
34	switch (fork()) {
35	case -1:
36		err(1, "fork");
37		break;
38	case 0:
39		if (rumpclient_fork_init(rf) == -1)
40			err(1, "postfork init failed");
41
42		if ((pid2 = rump_sys_getpid()) < 2)
43			errx(1, "unexpected pid %d", pid2);
44		if (pid1 == pid2)
45			errx(1, "child and parent pids are equal");
46
47		/* check that we can access the fd, the close it and exit */
48		if (rump_sys_write(fd, &fd, sizeof(fd)) != sizeof(fd))
49			errx(1, "write child /dev/null");
50		rump_sys_close(fd);
51		break;
52	default:
53		/*
54		 * check that we can access the fd, wait for the child, and
55		 * check we can still access the fd
56		 */
57		if (rump_sys_write(fd, &fd, sizeof(fd)) != sizeof(fd))
58			errx(1, "write parent /dev/null");
59		if (wait(&status) == -1)
60			err(1, "wait failed");
61		if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
62			errx(1, "child exited with status %d", status);
63		if (rump_sys_write(fd, &fd, sizeof(fd)) != sizeof(fd))
64			errx(1, "write parent /dev/null");
65		break;
66	}
67}
68
69static void
70cancel(void)
71{
72
73	/* XXX: not implemented in client / server !!! */
74}
75
76#define TESTSTR "i am your fatherrrrrrr"
77#define TESTSLEN (sizeof(TESTSTR)-1)
78static void
79pipecomm(void)
80{
81	struct rumpclient_fork *rf;
82	char buf[TESTSLEN+1];
83	int pipetti[2];
84	int status;
85
86	if (rump_sys_pipe(pipetti) == -1)
87		errx(1, "pipe");
88
89	if ((rf = rumpclient_prefork()) == NULL)
90		err(1, "prefork");
91
92	switch (fork()) {
93	case -1:
94		err(1, "fork");
95		break;
96	case 0:
97		if (rumpclient_fork_init(rf) == -1)
98			err(1, "postfork init failed");
99
100		memset(buf, 0, sizeof(buf));
101		if (rump_sys_read(pipetti[0], buf, TESTSLEN) != TESTSLEN)
102			err(1, "pipe read");
103		if (strcmp(TESTSTR, buf) != 0)
104			errx(1, "teststring doesn't match, got %s", buf);
105		break;
106	default:
107		if (rump_sys_write(pipetti[1], TESTSTR, TESTSLEN) != TESTSLEN)
108			err(1, "pipe write");
109		if (wait(&status) == -1)
110			err(1, "wait failed");
111		if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
112			errx(1, "child exited with status %d", status);
113		break;
114	}
115}
116
117static void
118fakeauth(void)
119{
120	struct rumpclient_fork *rf;
121	uint32_t *auth;
122	int rv;
123
124	if ((rf = rumpclient_prefork()) == NULL)
125		err(1, "prefork");
126
127	/* XXX: we know the internal structure of rf */
128	auth = (void *)rf;
129	*(auth+3) = *(auth+3) ^ 0x1;
130
131	rv = rumpclient_fork_init(rf);
132	if (!(rv == -1 && errno == ESRCH))
133		exit(1);
134}
135
136struct parsa {
137	const char *arg;		/* sp arg, el		*/
138	void (*spring)(void);		/* spring into action	*/
139} paragus[] = {
140	{ "simple", simple },
141	{ "cancel", cancel },
142	{ "pipecomm", pipecomm },
143	{ "fakeauth", fakeauth },
144};
145
146int
147main(int argc, char *argv[])
148{
149	unsigned i;
150
151	if (argc != 2)
152		errx(1, "invalid usage");
153
154	if (rumpclient_init() == -1)
155		err(1, "rumpclient init");
156
157	for (i = 0; i < __arraycount(paragus); i++) {
158		if (strcmp(argv[1], paragus[i].arg) == 0) {
159			paragus[i].spring();
160			break;
161		}
162	}
163	if (i == __arraycount(paragus)) {
164		printf("invalid test %s\n", argv[1]);
165		exit(1);
166	}
167
168	exit(0);
169}
170