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 
17 static void
18 simple(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 
69 static void
70 cancel(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)
78 static void
79 pipecomm(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 
117 static void
118 fakeauth(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 
136 struct 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 
146 int
147 main(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