minix/test/test5.c

401 lines
7.2 KiB
C

/* test 5 */
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#define ITERATIONS 2
#define MAX_ERROR 4
int errct;
int subtest;
int zero[1024];
int sigmap[5] = {9, 10, 11};
_PROTOTYPE(int main, (int argc, char *argv[]));
_PROTOTYPE(void test5a, (void));
_PROTOTYPE(void parent, (int childpid));
_PROTOTYPE(void child, (int parpid));
_PROTOTYPE(void func1, (int s));
_PROTOTYPE(void func8, (int s));
_PROTOTYPE(void func10, (int s));
_PROTOTYPE(void func11, (int s));
_PROTOTYPE(void test5b, (void));
_PROTOTYPE(void test5c, (void));
_PROTOTYPE(void test5d, (void));
_PROTOTYPE(void test5e, (void));
_PROTOTYPE(void test5f, (void));
_PROTOTYPE(void test5g, (void));
_PROTOTYPE(void funcalrm, (int s));
_PROTOTYPE(void test5h, (void));
_PROTOTYPE(void test5i, (void));
_PROTOTYPE(void ex, (void));
_PROTOTYPE(void e, (int n));
_PROTOTYPE(void quit, (void));
#ifdef _ANSI
void (*Signal(int _sig, void (*_func)(int)))(int);
#define SIG_ZERO ((void (*)(int))0) /* default signal handling */
#else
sighandler_t Signal();
/* void (*Signal()) (); */
#define SIG_ZERO ((void (*)())0) /* default signal handling */
#endif
_VOLATILE int childsigs, parsigs, alarms;
int main(argc, argv)
int argc;
char *argv[];
{
int i, m = 0x7777;
printf("Test 5 ");
fflush(stdout); /* have to flush for child's benefit */
system("rm -rf DIR_05; mkdir DIR_05");
chdir("DIR_05");
for (i = 0; i < ITERATIONS; i++) {
if (m & 0001) test5a();
if (m & 0002) test5b();
if (m & 0004) test5c();
if (m & 0010) test5d();
if (m & 0020) test5e();
if (m & 0040) test5f();
if (m & 0100) test5g();
if (m & 0200) test5h();
if (m & 0400) test5i();
}
quit();
return(-1); /* impossible */
}
void test5a()
{
int parpid, childpid, flag, *zp;
subtest = 0;
flag = 0;
for (zp = &zero[0]; zp < &zero[1024]; zp++)
if (*zp != 0) flag = 1;
if (flag) e(0); /* check if bss is cleared to 0 */
if (Signal(1, func1) == SIG_ERR) e(1);
if (Signal(10, func10) < SIG_ZERO) e(2);
parpid = getpid();
if (childpid = fork()) {
if (childpid < 0) ex();
parent(childpid);
} else {
child(parpid);
}
if (Signal(1, SIG_DFL) < SIG_ZERO) e(4);
if (Signal(10, SIG_DFL) < SIG_ZERO) e(5);
}
void parent(childpid)
int childpid;
{
int i, pid;
for (i = 0; i < 3; i++) {
if (kill(childpid, 1) < 0) e(6);
while (parsigs == 0);
parsigs--;
}
if ( (pid = wait(&i)) < 0) e(7);
if (i != 256 * 6) e(8);
}
void child(parpid)
int parpid;
{
int i;
for (i = 0; i < 3; i++) {
while (childsigs == 0);
childsigs--;
if (kill(parpid, 10) < 0) e(9);
}
exit(6);
}
void func1(s)
int s; /* for ANSI */
{
if (Signal(1, func1) < SIG_ZERO) e(10);
childsigs++;
}
void func8(s)
int s;
{
}
void func10(s)
int s; /* for ANSI */
{
if (Signal(10, func10) < SIG_ZERO) e(11);
parsigs++;
}
void func11(s)
int s; /* for ANSI */
{
e(38);
}
void test5b()
{
int cpid, n, pid;
subtest = 1;
if ((pid = fork())) {
if (pid < 0) ex();
if ((pid = fork())) {
if (pid < 0) ex();
if (cpid = fork()) {
if (cpid < 0) ex();
if (kill(cpid, 9) < 0) e(12);
if (wait(&n) < 0) e(13);
if (wait(&n) < 0) e(14);
if (wait(&n) < 0) e(15);
} else {
pause();
while (1);
}
} else {
exit(0);
}
} else {
exit(0);
}
}
void test5c()
{
int n, i, pid, wpid;
/* Test exit status codes for processes killed by signals. */
subtest = 3;
for (i = 0; i < 2; i++) {
if (pid = fork()) {
if (pid < 0) ex();
sleep(2); /* wait for child to pause */
if (kill(pid, sigmap[i]) < 0) {
e(20);
exit(1);
}
if ((wpid = wait(&n)) < 0) e(21);
if ((n & 077) != sigmap[i]) e(22);
if (pid != wpid) e(23);
} else {
pause();
exit(0);
}
}
}
void test5d()
{
/* Test alarm */
int i;
subtest = 4;
alarms = 0;
for (i = 0; i < 8; i++) {
Signal(SIGALRM, funcalrm);
alarm(1);
pause();
if (alarms != i + 1) e(24);
}
}
void test5e()
{
/* When a signal knocks a processes out of WAIT or PAUSE, it is supposed to
* get EINTR as error status. Check that.
*/
int n, j;
subtest = 5;
if (Signal(8, func8) < SIG_ZERO) e(25);
if (n = fork()) {
/* Parent must delay to give child a chance to pause. */
if (n < 0) ex();
sleep(1);
if (kill(n, 8) < 0) e(26);
if (wait(&n) < 0) e(27);
if (Signal(8, SIG_DFL) < SIG_ZERO) e(28);
} else {
j = pause();
if (errno != EINTR && -errno != EINTR) e(29);
exit(0);
}
}
void test5f()
{
int i, j, k, n;
subtest = 6;
if (getuid() != 0) return;
n = fork();
if (n < 0) ex();
if (n) {
wait(&i);
i = (i >> 8) & 0377;
if (i != (n & 0377)) e(30);
} else {
i = getgid();
j = getegid();
k = (i + j + 7) & 0377;
if (setgid(k) < 0) e(31);
if (getgid() != k) e(32);
if (getegid() != k) e(33);
i = getuid();
j = geteuid();
k = (i + j + 1) & 0377;
if (setuid(k) < 0) e(34);
if (getuid() != k) e(35);
if (geteuid() != k) e(36);
i = getpid() & 0377;
if (wait(&j) != -1) e(37);
exit(i);
}
}
void test5g()
{
int n;
subtest = 7;
Signal(11, func11);
Signal(11, SIG_IGN);
n = getpid();
if (kill(n, 11) != 0) e(1);
Signal(11, SIG_DFL);
}
void funcalrm(s)
int s; /* for ANSI */
{
alarms++;
}
void test5h()
{
/* When a signal knocks a processes out of PIPE, it is supposed to
* get EINTR as error status. Check that.
*/
int n, j, fd[2];
subtest = 8;
unlink("XXX.test5");
if (Signal(8, func8) < SIG_ZERO) e(1);
pipe(fd);
if (n = fork()) {
/* Parent must delay to give child a chance to pause. */
if (n < 0) ex();
while (access("XXX.test5", 0) != 0) /* just wait */ ;
sleep(1);
unlink("XXX.test5");
if (kill(n, 8) < 0) e(2);
if (wait(&n) < 0) e(3);
if (Signal(8, SIG_DFL) < SIG_ZERO) e(4);
if (close(fd[0]) != 0) e(5);
if (close(fd[1]) != 0) e(6);
} else {
if (creat("XXX.test5", 0777) < 0) e(7);
j = read(fd[0], (char *) &n, 1);
if (errno != EINTR) e(8);
exit(0);
}
}
void test5i()
{
int fd[2], pid, buf[10], n;
subtest = 9;
pipe(fd);
unlink("XXXxxxXXX");
if ( (pid = fork())) {
/* Parent */
/* Wait until child has started and has created the XXXxxxXXX file. */
while (access("XXXxxxXXX", 0) != 0) /* loop */ ;
sleep(1);
if (kill(pid, SIGKILL) != 0) e(1);
if (wait(&n) < 0) e(2);
if (close(fd[0]) != 0) e(3);
if (close(fd[1]) != 0) e(4);
} else {
if (creat("XXXxxxXXX", 0777) < 0) e(5);
read(fd[0], (char *) buf, 1);
e(5); /* should be killed by signal and not get here */
}
unlink("XXXxxxXXX");
}
void ex()
{
int e = errno;
printf("Fork failed: %s (%d)\n", strerror(e), e);
exit(1);
}
void e(n)
int n;
{
int err_num = errno; /* save errno in case printf clobbers it */
printf("Subtest %d, error %d errno=%d ", subtest, n, errno);
errno = err_num; /* restore errno, just in case */
perror("");
if (errct++ > MAX_ERROR) {
printf("Too many errors; test aborted\n");
chdir("..");
system("rm -rf DIR*");
exit(1);
}
}
#ifdef _ANSI
void (*Signal(int a, void (*b)(int)))(int)
#else
sighandler_t Signal(a, b)
int a;
void (*b)();
#endif
{
if (signal(a, (void (*) ()) b) == (void (*)()) -1)
return(SIG_ERR);
else
return(SIG_ZERO);
}
void quit()
{
chdir("..");
system("rm -rf DIR*");
if (errct == 0) {
printf("ok\n");
exit(0);
} else {
printf("%d errors\n", errct);
exit(1);
}
}