Sync usage with man page.
[netbsd-mini2440.git] / regress / lib / libc / clone / clonetest.c
blob3daa64e26876dc2f402750c292d42c118b7cc17e
1 /* $NetBSD: clonetest.c,v 1.9 2004/07/19 06:34:10 chs Exp $ */
3 /*
4 * This file placed in the public domain.
5 * Jason R. Thorpe, July 16, 2001.
6 */
8 #include <sys/types.h>
9 #include <sys/mman.h>
10 #include <sys/wait.h>
11 #include <sys/resource.h>
12 #include <err.h>
13 #include <sched.h>
14 #include <signal.h>
15 #include <stdio.h>
16 #include <unistd.h>
17 #include <stdlib.h>
18 #include <errno.h>
20 static int newclone(void *);
21 static int stackdir(void *);
22 static void test1(void);
23 static void test2(void);
24 static void test3(void);
26 int main(int, char *[]);
29 #define STACKSIZE (8 * 1024)
31 #define FROBVAL 41973
32 #define CHILDEXIT 0xa5
34 int
35 main(int argc, char *argv[])
37 test1();
38 test2();
39 test3();
40 return 0;
43 static void
44 test1()
46 sigset_t mask;
47 void *allocstack, *stack;
48 pid_t pid;
49 volatile long frobme[2];
50 int stat;
52 allocstack = mmap(NULL, STACKSIZE, PROT_READ|PROT_WRITE|PROT_EXEC,
53 MAP_PRIVATE|MAP_ANON, -1, (off_t) 0);
55 if (allocstack == MAP_FAILED)
56 err(1, "mmap stack");
58 stack = (caddr_t) allocstack + STACKSIZE * stackdir(&stat);
60 printf("parent: stack = %p, frobme = %p\n", stack, frobme);
61 fflush(stdout);
63 frobme[0] = (long)getpid();
64 frobme[1] = (long)stack;
66 sigemptyset(&mask);
67 sigaddset(&mask, SIGUSR1);
69 if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
70 err(1, "sigprocmask (SIGUSR1)");
72 switch (pid = __clone(newclone, stack,
73 CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGUSR1,
74 (void *)frobme)) {
75 case 0:
76 errx(1, "clone returned 0");
77 /*NOTREACHED*/
78 case -1:
79 err(1, "clone");
80 /*NOTREACHED*/
81 default:
82 while (waitpid(pid, &stat, __WCLONE) != pid)
83 continue;
86 if (WIFEXITED(stat) == 0)
87 errx(1, "child didn't exit");
89 printf("parent: childexit = 0x%x, frobme = %ld\n",
90 WEXITSTATUS(stat), frobme[1]);
92 if (WEXITSTATUS(stat) != CHILDEXIT || frobme[1] != FROBVAL)
93 exit(1);
95 if (munmap(allocstack, STACKSIZE) == -1)
96 err(1, "munmap stack");
98 printf("test1: PASS\n");
101 static void
102 test2()
104 void *allocstack, *stack;
105 int rv, stat;
107 allocstack = mmap(NULL, STACKSIZE, PROT_READ|PROT_WRITE|PROT_EXEC,
108 MAP_PRIVATE|MAP_ANON, -1, (off_t) 0);
110 if (allocstack == MAP_FAILED)
111 err(1, "mmap stack");
113 stack = (caddr_t) allocstack + STACKSIZE * stackdir(&stat);
115 errno = 0;
116 rv = __clone(0, stack,
117 CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGCHLD, NULL);
118 if (rv != -1 || errno != EINVAL)
119 errx(1, "clone did not return EINVAL on NULL function pointer: "
120 "rv %d errno %d", rv, errno);
121 rv = __clone(newclone, NULL,
122 CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGCHLD,
123 NULL);
124 if (rv != -1 || errno != EINVAL)
125 errx(1, "clone did not return EINVAL on NULL stack pointer: "
126 "rv %d errno %d", rv, errno);
128 if (munmap(allocstack, STACKSIZE) == -1)
129 err(1, "munmap stack");
131 printf("test2: PASS\n");
134 static void
135 test3()
137 struct rlimit rl;
139 /* Can't enforce resource limit on root */
140 if (geteuid() == 0)
141 return;
143 if (getrlimit(RLIMIT_NPROC, &rl) == -1)
144 err(1, "getrlimit");
145 rl.rlim_cur = 0;
146 rl.rlim_max = 0;
147 if (setrlimit(RLIMIT_NPROC, &rl) == -1)
148 err(1, "setrlimit");
149 if (__clone(newclone, malloc(10240),
150 CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGCHLD,
151 (void *)&rl) != -1 || errno != EAGAIN)
152 errx(1, "clone did not return EAGAIN running out of procs");
154 printf("test3: PASS\n");
157 static int
158 newclone(void *arg)
160 long *frobp = arg, diff;
162 printf("child: stack ~= %p, frobme = %p\n", &frobp, frobp);
163 fflush(stdout);
165 if (frobp[0] != getppid())
166 errx(1, "argument does not contain parent's pid");
168 if (frobp[0] == getpid())
169 errx(1, "called in parent's pid");
171 if (frobp[1] > (long)&frobp)
172 diff = frobp[1] - (long)&frobp;
173 else
174 diff = (long)&frobp - frobp[1];
176 if (diff > 1024)
177 errx(1, "called with bad stack");
179 frobp[1] = FROBVAL;
181 return (CHILDEXIT);
185 * return 1 if the stack grows down, 0 if it grows up.
187 static int
188 stackdir(void *p)
190 int val;
191 void *q = &val;
193 return p < q ? 0 : 1;