int main(const int argc,char* argv[]) { //test_fork_return_twice(); test_fork(); //test_vfork(); return 0; }
int main(int argc, char **argv) { int rv, i; int counter = 0; test_init(argc, argv); if (scale > MAX_SCALE) { err("Too many children specified\n"); exit(-1); } if (signal(SIGUSR2, do_stop) == SIG_ERR) { err("Can't setup handler\n"); exit(-1); } for (i = 0; i < scale; i++) { rv = test_fork(); if (rv == -1) { err("Can't fork\n"); killall(); exit(-1); } if (rv == 0) chew_some_file(i); pids[i] = rv; } test_daemon(); test_waitsig(); killall(); for (i = 0; i < scale; i++) { if (waitpid(pids[i], &rv, 0) == -1) { fail("Can't wipe up the kid\n"); counter++; continue; } if (!WIFEXITED(rv)) { fail("Kid was killed\n"); counter++; } else { rv = WEXITSTATUS(rv); if (rv < MAX_EXIT_CODE_VAL && rv > SUCCESS) { fail("Kid failed: %s (%d)\n", kids_fail_reasons[rv], rv); counter++; } else if (rv != SUCCESS) { fail("Unknow exitcode from kid: %d\n", rv); counter++; } } } if (counter == 0) pass(); return 0; }
int main(int argc, char *argv[]){ int number_of_cycles[] = {50000,100000,150000,200000}; int i = 0; // for(i = 0; i<1;i++){ // printf("\n counter after fork %d, real_time %ld ", counter, test_fork(number_of_cycles[i])); // counter = 0; // printf("\n counter after vfork %d, real_time %ld ", counter, test_vfork(number_of_cycles[i])); // counter = 0; // printf("\n counter after clone_fork %d, real_time %ld ", counter, test_clone_fork(number_of_cycles[i])); // counter = 0; // printf("\n counter after clone_vfork %d, real_time %ld ", counter, test_clone_vfork(number_of_cycles[i])); // } FILE *parent_handle; if( (parent_handle = fopen("data/parent","w")) < 0) perror("fopen failed"); FILE *child_handle; if( (child_handle = fopen("data/child","w")) < 0) perror("fopen failed"); FILE *sum_handle; if( (sum_handle = fopen("data/sum","w")) < 0) perror("fopen failed"); fprintf(parent_handle,"%10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s","N","sys_f","usr_f","syusr_f","real_f","syst_f","usr_vf","syusr_vf","real_vf","sys_cf","usr_cf","syusr_cf","real_cf","sys_cvf","usr_cvf","syusr_cvf","real_cvf"); fprintf(child_handle,"%10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s","N","sys_f","usr_f","syusr_f","real_f","syst_f","usr_vf","syusr_vf","real_vf","sys_cf","usr_cf","syusr_cf","real_cf","sys_cvf","usr_cvf","syusr_cvf","real_cvf"); fprintf(sum_handle,"%10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s","N","sys_f","usr_f","syusr_f","real_f","syst_f","usr_vf","syusr_vf","real_vf","sys_cf","usr_cf","syusr_cf","real_cf","sys_cvf","usr_cvf","syusr_cvf","real_cvf"); for(i = 0; i<4; i++){ struct tms *t = malloc(sizeof(struct tms)); fprintf(parent_handle,"\n%10d ", number_of_cycles[i]); fprintf(child_handle,"\n%10d ", number_of_cycles[i]); fprintf(sum_handle,"\n%10d ", number_of_cycles[i]); counter = 0; clock_t p_real_time = times(t); suseconds_t c_real_time = test_fork(number_of_cycles[i]); time_checker(t, c_real_time, p_real_time, parent_handle, child_handle, sum_handle); p_real_time = times(t); counter = 0; c_real_time = test_vfork(number_of_cycles[i]); time_checker(t, c_real_time, p_real_time, parent_handle, child_handle, sum_handle); p_real_time = times(t); counter = 0; c_real_time = test_clone_fork(number_of_cycles[i]); time_checker(t, c_real_time, p_real_time, parent_handle, child_handle, sum_handle); p_real_time = times(t); counter = 0; c_real_time = test_clone_vfork(number_of_cycles[i]); time_checker(t, c_real_time, p_real_time, parent_handle, child_handle, sum_handle); } return 0; }
int main(int argc, char **argv) { test_file(); test_fork(); test_time(); test_socket(); // test_clone(); test_signal(); test_shm(); return 0; }
int main(void) { int ret; ret = test_init(); if (ret != 0) { fprintf(stderr, "test_init failed\n"); return 1; } ret = test_fork(); if (ret != 0) { fprintf(stderr, "test_fork failed\n"); return 1; } ret = test_jobs(10, 10000); if (ret != 0) { fprintf(stderr, "test_jobs failed\n"); return 1; } ret = test_busydestroy(); if (ret != 0) { fprintf(stderr, "test_busydestroy failed\n"); return 1; } /* * Test 10 threads adding jobs on a single pool */ ret = test_threaded_addjob(1, 10, 5, 5000); if (ret != 0) { fprintf(stderr, "test_jobs failed\n"); return 1; } /* * Test 10 threads on 3 pools to verify our fork handling * works right. */ ret = test_threaded_addjob(3, 10, 5, 5000); if (ret != 0) { fprintf(stderr, "test_jobs failed\n"); return 1; } printf("success\n"); return 0; }
int main(int argc, char **argv) { int ret = 0; int readfd, writefd; mode_t mode = S_IFIFO | 0644; char path[PROCS_DEF][BUF_SIZE]; pid_t pid; int i; uint8_t buf[0x100000]; char *file_path; test_init(argc, argv); for (i = 0; i < PROCS_DEF; i++) { file_path = path[i]; if (snprintf(file_path, BUF_SIZE, "%s-%02d", filename, i) >= BUF_SIZE) { err("filename %s is too long\n", filename); exit(1); } if (mkfifo(file_path, mode)) { err("can't make fifo \"%s\": %m\n", file_path); exit(1); } } if (signal(SIGCHLD, inc_num_exited) == SIG_ERR) { err("can't set SIGCHLD handler: %m\n"); exit(1); } for (i = 1; i < num_procs; i++) { /* i = 0 - parent */ pid = test_fork(); if (pid < 0) { err("Can't fork: %m\n"); kill(0, SIGKILL); exit(1); } if (pid == 0) { file_path = path[i - 1]; readfd = open(file_path, O_RDONLY); if (readfd < 0) { err("open(%s, O_RDONLY) Failed: %m\n", file_path); ret = errno; return ret; } file_path = path[i]; writefd = open(file_path, O_WRONLY); if (writefd < 0) { err("open(%s, O_WRONLY) Failed: %m\n", file_path); ret = errno; return ret; } signal(SIGPIPE, SIG_IGN); if (pipe_in2out(readfd, writefd, buf, sizeof(buf)) < 0) /* pass errno as exit code to the parent */ if (test_go() /* signal NOT delivered */ || (errno != EINTR && errno != EPIPE)) ret = errno; close(readfd); close(writefd); exit(ret); } pids[i] = pid; } file_path = path[0]; writefd = open(file_path, O_WRONLY); if (writefd < 0) { err("open(%s, O_WRONLY) Failed: %m\n", file_path); kill(0, SIGKILL); exit(1); } file_path = path[i - 1]; readfd = open(file_path, O_RDONLY); if (readfd < 0) { err("open(%s, O_RDONLY) Failed: %m\n", file_path); kill(0, SIGKILL); exit(1); } if (num_exited) { err("Some children died unexpectedly\n"); kill(0, SIGKILL); exit(1); } test_daemon(); while (test_go()) { int len, rlen = 0, wlen; uint8_t rbuf[sizeof(buf)], *p; datagen(buf, sizeof(buf), NULL); wlen = write(writefd, buf, sizeof(buf)); if (wlen < 0) { if (errno == EINTR) continue; else { fail("write failed: %m\n"); ret = 1; break; } } for (p = rbuf, len = wlen; len > 0; p += rlen, len -= rlen) { rlen = read(readfd, p, len); if (rlen <= 0) break; } if (rlen < 0 && errno == EINTR) continue; if (len > 0) { fail("read failed: %m\n"); ret = 1; break; } if (memcmp(buf, rbuf, wlen)) { fail("data mismatch\n"); ret = 1; break; } } close(writefd); test_waitsig(); /* even if failed, wait for migration to complete */ if (kill(0, SIGTERM)) { fail("failed to send SIGTERM to my process group: %m\n"); return 1; /* shouldn't wait() in this case */ } close(readfd); for (i = 1; i < num_procs; i++) { /* i = 0 - parent */ int chret; if (waitpid(pids[i], &chret, 0) < 0) { fail("waitpid error: %m\n"); ret = 1; continue; } chret = WEXITSTATUS(chret); if (chret) { fail("child %d exited with non-zero code %d (%s)\n", i, chret, strerror(chret)); ret = 1; continue; } } if (!ret) pass(); for (i = 0; i < PROCS_DEF; i++) unlink(path[i]); return 0; }
int main(int argc, char **argv) { char buf[BUF_SIZE]; int fd, fd_s; struct aiocb aiocb; int status; pid_t pid; int ret, res; const struct aiocb *aioary[1]; task_waiter_t child_waiter; test_init(argc, argv); task_waiter_init(&child_waiter); if ((fd_s = tcp_init_server(AF_INET, &port)) < 0) { pr_err("initializing server failed\n"); return 1; } pid = test_fork(); if (pid < 0) { pr_perror("fork failed"); return 1; } if (pid == 0) { /* * Chiled is client of TCP connection */ close(fd_s); fd = tcp_init_client(AF_INET, "127.0.0.1", port); if (fd < 0) return 1; memset(&aiocb, 0, sizeof(struct aiocb)); aiocb.aio_fildes = fd; aiocb.aio_buf = buf; aiocb.aio_nbytes = BUF_SIZE; ret = aio_read(&aiocb); if (ret < 0) { pr_perror("aio_read failed"); return 1; } task_waiter_complete_current(&child_waiter); /* Wait for request completion */ aioary[0] = &aiocb; ret = aio_error(&aiocb); #ifdef DEBUG test_msg("."); #endif res = 0; again: if (aio_suspend(aioary, 1, NULL) < 0 && errno != EINTR) { pr_perror("aio_suspend failed"); res = 1; } ret = aio_error(&aiocb); if (!res && ret == EINPROGRESS) { #ifdef DEBUG test_msg("restart aio_suspend\n"); #endif goto again; } if (ret != 0) { pr_err("Error at aio_error(): %s\n", strerror(ret)); res = 1; } if (aio_return(&aiocb) != BUF_SIZE) { pr_perror("Error at aio_return()"); res = 1; } close(fd); return res; } /* * parent is server of TCP connection */ fd = tcp_accept_server(fd_s); close(fd_s); if (fd < 0) { pr_err("can't accept client connection\n"); goto error; } task_waiter_wait4(&child_waiter, pid); test_daemon(); test_waitsig(); if (write(fd, buf, BUF_SIZE) < BUF_SIZE) { pr_perror("can't write"); goto error; } close(fd); if (wait(&status) < 0) { pr_perror("wait failed"); goto error; } if (WIFEXITED(status) && WEXITSTATUS(status) != 0) { pr_err("child failed with exit code %d\n", WEXITSTATUS(status)); return 1; } pass(); return 0; error: kill(pid, SIGKILL); wait(&status); return -1; }
int main(int argc, char **argv) { int fd, fd1; struct stat st; mode_t mode = S_IFIFO | 0600; int pid; int chret; test_init(argc, argv); if (mknod(filename, mode, 0)) { pr_perror("can't make fifo \"%s\"", filename); exit(1); } pid = test_fork(); if (pid < 0) { pr_perror("Can't fork"); exit(1); } if (pid == 0) { char rbuf[BUF_SIZE]; int res; fd1 = open(filename, O_RDONLY); if (fd1 < 0) { pr_perror("open(%s, O_RDONLY) Failed", filename); chret = errno; return chret; } res = read(fd1, rbuf, 7); if (res < 0) { pr_perror("read error %s", filename); chret = errno; return chret; } else if (res == 0) { pr_perror("read(%d, rbuf, 7) return 0", fd1); return 1; } if (close(fd1) < 0) { fail("can't close %d, %s: %m", fd1, filename); chret = errno; return chret; } } else { fd = open(filename, O_WRONLY); if (fd < 0) { pr_perror("open(%s, O_WRONLY) Failed", filename); kill(pid, SIGKILL); wait(NULL); return 1; } test_daemon(); test_waitsig(); if (write(fd, "string", 7) == -1) { pr_perror("write(%d, 'string', 7) Failed", fd); return 1; } wait(&chret); chret = WEXITSTATUS(chret); if (chret) { fail("child exited with non-zero code %d (%s)\n", chret, strerror(chret)); return 1; } if (close(fd) < 0) { fail("can't close %d, %s: %m", fd, filename); return 1; } if (stat(filename, &st) < 0) { fail("can't stat %s: %m", filename); return 1; } if (st.st_mode != mode) { fail("%s is no longer the fifo we had", filename); return 1; } if (unlink(filename) < 0) { fail("can't unlink %s: %m", filename); return 1; } } pass(); return 0; }
int main(int argc, char ** argv) { int pipe1[2]; int pipe2[2]; int ret; pid_t pid; char buf[sizeof(TEST_STRING)]; test_init(argc, argv); ret = pipe(pipe1); if (ret) return 1; ret = pipe(pipe2); if (ret) return 1; pid = test_fork(); if (pid < 0) { err("Can't fork"); exit(1); } else if (pid == 0) { if (dup2(pipe1[1], 11) == -1 || dup2(pipe2[0], 12) == -1) { err("dup2 failed"); return 1; } } else { if (dup2(pipe1[0], 12) == -1 || dup2(pipe2[1], 11) == -1) { err("dup2 failed"); goto err; } } close(pipe2[0]); close(pipe2[1]); close(pipe1[0]); close(pipe1[1]); if (pid > 0) { int status; test_daemon(); while (test_go()) ; ret = read(12, buf, sizeof(TEST_STRING)); if (ret != sizeof(TEST_STRING)) { err("read failed: %d", ret); goto err; } ret = write(11, TEST_STRING, sizeof(TEST_STRING)); if (ret != sizeof(TEST_STRING)) { err("write failed: %d", ret); goto err; } close(11); ret = read(12, buf, sizeof(TEST_STRING)); if (ret != sizeof(TEST_STRING)) { err("read failed: %d", ret); goto err; } if (strcmp(TEST_STRING, buf)) { err("data curruption"); goto err; } ret = wait(&status); if (ret == -1 || !WIFEXITED(status) || WEXITSTATUS(status)) { kill(pid, SIGKILL); goto err; } pass(); } else { ret = write(11, TEST_STRING, sizeof(TEST_STRING)); if (ret != sizeof(TEST_STRING)) { err("write failed: %d", ret); return 1; } ret = read(12, buf, sizeof(TEST_STRING)); if (ret != sizeof(TEST_STRING)) { err("read failed: %d", ret); return 1; } ret = write(11, TEST_STRING, sizeof(TEST_STRING)); if (ret != sizeof(TEST_STRING)) { err("write failed: %d", ret); return 1; } close(11); if (strcmp(TEST_STRING, buf)) { err("data curruption"); return 1; } } return 0; err: err("FAIL"); return 1; }
int main(int argc, char ** argv) { int fdm, fds, status; task_waiter_t t; char *slavename; pid_t pid; test_init(argc, argv); task_waiter_init(&t); fdm = open("/dev/ptmx", O_RDWR); if (fdm == -1) { pr_perror("Can't open a master pseudoterminal"); return 1; } grantpt(fdm); unlockpt(fdm); slavename = ptsname(fdm); pid = test_fork(); if (pid < 0) { pr_perror("fork() failed"); return 1; } if (pid == 0) { close(fdm); signal(SIGHUP, sighup_handler); if (setsid() == -1) return 1; /* set up a controlling terminal */ fds = open(slavename, O_RDWR); if (fds == -1) { pr_perror("Can't open a slave pseudoterminal %s", slavename); return 1; } if (ioctl(fdm, TIOCSCTTY, 1) < 0) { pr_perror("Can't setup a controlling terminal"); return 1; } close(fds); task_waiter_complete_current(&t); test_waitsig(); if (sighup) return 0; return 1; } task_waiter_wait4(&t, pid); test_daemon(); test_waitsig(); close(fdm); if (kill(pid, SIGTERM) == -1) { pr_perror("kill failed"); return 1; } pid = waitpid(pid, &status, 0); if (pid < 0) return 1; if (WIFEXITED(status)) { if (WEXITSTATUS(status)) { fail("The child returned %d", WEXITSTATUS(status)); return 1; } } else { test_msg("The child has been killed by %d\n", WTERMSIG(status)); return 1; } pass(); return 0; }
int main(int argc, char *argv[]) { struct sigaction saio = { }; struct params obtained = { }; uid_t ruid, euid, suid; int status, pipes[2]; pid_t pid; test_init(argc, argv); shared = (void *)mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); if ((void *)shared == MAP_FAILED) { fail("mmap failed"); exit(1); } if (getresuid(&ruid, &euid, &suid)) { fail("getresuid failed\n"); exit(1); } if (pipe(pipes)) { err("Can't create pipe: %m\n"); exit(1); } saio.sa_handler = (sig_t)signal_handler_io; saio.sa_flags = SA_RESTART; if (sigaction(SIGIO, &saio, 0)) { fail("sigaction failed\n"); exit(1); } if (setresuid(-1, 1, -1)) { fail("setresuid failed\n"); exit(1); } if (fcntl(pipes[0], F_SETOWN, getpid()) || fcntl(pipes[1], F_SETOWN, getpid()) || fcntl(pipes[0], F_SETSIG, SIGIO) || fcntl(pipes[1], F_SETSIG, SIGIO) || fcntl(pipes[0], F_SETFL, fcntl(pipes[0], F_GETFL) | O_ASYNC) || fcntl(pipes[1], F_SETFL, fcntl(pipes[1], F_GETFL) | O_ASYNC)) { fail("fcntl failed\n"); exit(1); } asm volatile ("" :::); fill_pipe_params(shared, pipes); if (setresuid(-1, euid, -1)) { fail("setresuid failed\n"); exit(1); } pid = test_fork(); if (pid < 0) { err("can't fork %m"); exit(1); } if (pid == 0) { struct params p = { }; test_waitsig(); fcntl(pipes[1], F_SETOWN, getpid()); fill_pipe_params(&p, pipes); if (write(pipes[1], &p, sizeof(p)) != sizeof(p)) { fail("write failed\n"); exit(1); } exit(0); } test_daemon(); test_waitsig(); kill(pid, SIGTERM); if (waitpid(pid, &status, P_ALL) == -1) { fail("waitpid failed\n"); exit(1); } if (read(pipes[0], &obtained, sizeof(obtained)) != sizeof(obtained)) { fail("read failed\n"); exit(1); } if (shared->sigio < 1) { fail("shared->sigio = %d (> 0 expected)\n", shared->sigio); exit(1); } shared->pipe_pid[1] = pid; if (cmp_pipe_params(shared, &obtained)) { fail("params comparison failed\n"); exit(1); } pass(); return 0; }
int main(int argc, char **argv) { int ret = 0; int readfd, writefd; mode_t mode = S_IFIFO | 0600; char path[PROCS_DEF][BUF_SIZE]; pid_t pid; int i; uint8_t buf[0x100000]; int chret; char *file_path; test_init(argc, argv); for (i = 0; i < PROCS_DEF; i++) { file_path = path[i]; if (snprintf(file_path, BUF_SIZE, "%s-%02d", filename, i) >= BUF_SIZE) { pr_perror("filename %s is too long", filename); exit(1); } if (mkfifo(file_path, mode)) { pr_perror("can't make fifo \"%s\"", file_path); exit(1); } } pid = test_fork(); if (pid < 0) { pr_perror("Can't fork"); kill(0, SIGKILL); exit(1); } if (pid == 0) { file_path = path[0]; readfd = open(file_path, O_RDONLY); if (readfd < 0) { pr_perror("open(%s, O_RDONLY) Failed", file_path); ret = errno; return ret; } file_path = path[1]; writefd = open(file_path, O_WRONLY); if (writefd < 0) { pr_perror("open(%s, O_WRONLY) Failed", file_path); ret = errno; return ret; } if (pipe_in2out(readfd, writefd, buf, sizeof(buf)) < 0) /* pass errno as exit code to the parent */ if (test_go() /* signal NOT delivered */ || (errno != EINTR && errno != EPIPE)) ret = errno; close(readfd); close(writefd); exit(ret); } file_path = path[0]; writefd = open(file_path, O_WRONLY); if (writefd < 0) { pr_perror("open(%s, O_WRONLY) Failed", file_path); kill(pid, SIGKILL); return 1; } file_path = path[1]; readfd = open(file_path, O_RDONLY); if (readfd < 0) { pr_perror("open(%s, O_RDONLY) Failed", file_path); kill(pid, SIGKILL); return 1; } test_daemon(); while (test_go()) { int len, rlen = 0, wlen; uint8_t rbuf[sizeof(buf)], *p; datagen(buf, sizeof(buf), NULL); wlen = write(writefd, buf, sizeof(buf)); if (wlen < 0) { if (errno == EINTR) continue; else { fail("write failed: %m\n"); ret = 1; break; } } for (p = rbuf, len = wlen; len > 0; p += rlen, len -= rlen) { rlen = read(readfd, p, len); if (rlen <= 0) break; } if (rlen < 0 && errno == EINTR) continue; if (len > 0) { fail("read failed: %m\n"); ret = 1; break; } if (memcmp(buf, rbuf, wlen)) { fail("data mismatch\n"); ret = 1; break; } } close(writefd); test_waitsig(); wait(&chret); chret = WEXITSTATUS(chret); if (chret) { fail("child exited with non-zero code %d (%s)\n", chret, strerror(chret)); return 1; } if (!ret) pass(); close(readfd); for (i = 0; i < PROCS_DEF; i++) unlink(path[i]); return 0; }
static int test_fn(int argc, char **argv) { key_t key; int sem, shm, pid1, pid2; int fail_count = 0; uint8_t *mem; uint32_t crc; int ret; key = ftok(argv[0], 822155650); if (key == -1) { pr_perror("Can't make key"); goto out; } sem = semget(key, 1, 0777 | IPC_CREAT | IPC_EXCL); if (sem == -1) { pr_perror("Can't get sem"); goto out; } if (semctl(sem, 0, SETVAL, 1) == -1) { pr_perror("Can't init sem"); fail_count++; goto out_sem; } shm = shmget(key, shmem_size, 0777 | IPC_CREAT | IPC_EXCL); if (shm == -1) { pr_perror("Can't get shm"); fail_count++; goto out_sem; } mem = shmat(shm, NULL, 0); if (mem == (void *)-1) { pr_perror("Can't attach shm"); fail_count++; goto out_shm; } poison_area((int *)mem); pid1 = test_fork(); if (pid1 == -1) { pr_perror("Can't fork 1st time"); goto out_shdt; } else if (pid1 == 0) exit(child(key)); pid2 = test_fork(); if (pid2 == -1) { pr_perror("Can't fork 2nd time"); fail_count++; goto out_child; } else if (pid2 == 0) exit(child(key)); test_daemon(); while (test_go()) { ret = semop(sem, &lock, 1); if (ret) { if (errno == EINTR) continue; fail_count++; fail("Error in semop lock"); break; } if (mem[0] != POISON) { crc = INIT_CRC; if (datachk(mem, shmem_size, &crc)) { fail_count++; fail("Semaphore protection is broken or " "shmem pages are messed"); semop(sem, &unlock, 1); break; } poison_area((int *)mem); } while ((ret = semop(sem, &unlock, 1)) && (errno == EINTR)); if (ret) { fail_count++; fail("Error in semop unlock"); break; } } test_waitsig(); kill(pid2, SIGTERM); waitpid(pid2, &ret, 0); if (!WIFEXITED(ret)) { fail_count++; pr_perror("Child 2 was killed"); } else if (WEXITSTATUS(ret)) { fail_count++; pr_perror("Child 2 couldn't inititalise"); } out_child: kill(pid1, SIGTERM); waitpid(pid1, &ret, 0); if (!WIFEXITED(ret)) { fail_count++; pr_perror("Child 1 was killed"); } else if (WEXITSTATUS(ret)) { fail_count++; pr_perror("Child 1 couldn't inititalise"); } out_shdt: shmdt(mem); out_shm: shmctl(shm, IPC_RMID, NULL); out_sem: semctl(sem, 1, IPC_RMID); if (fail_count == 0) pass(); out: return 0; }
int main(int argc, char **argv) { int pid, pipe_prep[2], pipe_goon[2], pipe_res[2]; char res; int fd, fd2; test_init(argc, argv); filepath = malloc(strlen(filename) + 1); sprintf(filepath, "/%s", filename); pipe(pipe_prep); pipe(pipe_goon); pipe(pipe_res); pid = test_fork(); if (pid != 0) { close(pipe_prep[1]); close(pipe_goon[0]); close(pipe_res[1]); res = ERR_PIPES; read(pipe_prep[0], &res, 1); read(pipe_prep[0], &res, 1); /* wait when pipe_prep[] will be closed */ if (res != SUCCESS) { if (res == ERR_PIPES) pr_perror("broken pipes"); else { if (res & ERR_IN_FILE) pr_perror("inside-root file fail"); if (res & ERR_ROOT) pr_perror("chroot fail"); if (res & ERR_DIR) pr_perror("mkdir fail"); } return 0; } test_daemon(); test_waitsig(); close(pipe_goon[1]); res = ERR_PIPES; read(pipe_res[0], &res, 1); if (res == SUCCESS) pass(); else if (res == ERR_PIPES) fail("broken pipes"); else { if (res & ERR_IN_FILE) fail("opened file broken"); if (res & ERR_OPEN) fail("open in chroot fail"); if (res & ERR_FILE2) fail("wrong file opened"); } wait(NULL); return 0; } close(pipe_prep[0]); close(pipe_goon[1]); close(pipe_res[0]); if (mkdir(dirname, 0700)) { res = ERR_DIR; goto err_nodir; } if (chroot(dirname)) { res = ERR_ROOT; goto err_noroot; } fd = make_file(filepath); if (fd < 0) { res = ERR_IN_FILE; goto err_nofile2; } res = SUCCESS; write(pipe_prep[1], &res, 1); close(pipe_prep[1]); read(pipe_goon[0], &res, 1); res = SUCCESS; if (check_file(fd)) res |= ERR_IN_FILE; fd2 = open(filepath, O_RDWR); if (fd2 < 0) res |= ERR_OPEN; else if (check_file(fd2)) res |= ERR_FILE2; write(pipe_res[1], &res, 1); exit(0); err_nofile2: err_noroot: err_nodir: write(pipe_prep[1], &res, 1); exit(0); }
int main(int argc, char ** argv) { int sock, acc_sock, ret; pid_t pid; uint32_t crc; uint8_t buf[1000]; test_init(argc, argv); sock = setup_srv_sock(); if (sock < 0) exit(1); pid = test_fork(); if (pid < 0) { pr_perror("can't fork"); exit(1); } if (pid == 0) { /* child writes to the unlinked socket and returns */ close(sock); sock = setup_clnt_sock(); if (sock < 0) _exit(1); test_waitsig(); crc = ~0; datagen(buf, sizeof(buf), &crc); if (write(sock, buf, sizeof(buf)) != sizeof(buf)) { pr_perror("can't write to socket"); exit(errno); } close(sock); exit(0); } acc_sock = accept(sock, NULL, NULL); if (acc_sock < 0) { pr_perror("can't accept() the connection on \"%s\"", filename); goto out_kill; } close(sock); sock = acc_sock; if (unlink(filename)) { pr_perror("can't unlink %s", filename); goto out_kill; } test_daemon(); test_waitsig(); if (kill(pid, SIGTERM)) { fail("terminating the child failed: %m\n"); goto out; } if (wait(&ret) != pid) { fail("wait() returned wrong pid %d: %m\n", pid); goto out; } if (WIFEXITED(ret)) { ret = WEXITSTATUS(ret); if (ret) { fail("child exited with nonzero code %d (%s)\n", ret, strerror(ret)); goto out; } } if (WIFSIGNALED(ret)) { fail("child exited on unexpected signal %d\n", WTERMSIG(ret)); goto out; } if (read(sock, buf, sizeof(buf)) != sizeof(buf)) { fail("can't read %s: %m\n", filename); goto out; } crc = ~0; if (datachk(buf, sizeof(buf), &crc)) { fail("CRC mismatch\n"); goto out; } if (close(sock)) { fail("close failed: %m\n"); goto out; } if (unlink(filename) != -1 || errno != ENOENT) { fail("file %s should have been deleted before migration: unlink: %m\n", filename); goto out; } pass(); out_kill: kill(pid, SIGTERM); out: close(sock); return 0; }
int main(int argc, char ** argv) { void *m, *m2; char path[PATH_MAX]; uint32_t crc; pid_t pid = -1; int status, fd; test_init(argc, argv); m = mmap(NULL, MEM_SIZE, PROT_WRITE | PROT_READ, MAP_SHARED | MAP_ANONYMOUS, -1, 0); if (m == MAP_FAILED) goto err; pid = test_fork(); if (pid < 0) { goto err; } else if (pid == 0) { crc = ~0; datagen(m + MEM_OFFSET, PAGE_SIZE, &crc); crc = ~0; datagen(m + MEM_OFFSET2, PAGE_SIZE, &crc); test_waitsig(); crc = ~0; status = datachk(m + MEM_OFFSET, PAGE_SIZE, &crc); if (status) return 1; crc = ~0; status = datachk(m + MEM_OFFSET2, PAGE_SIZE, &crc); if (status) return 1; crc = ~0; status = datachk(m + PAGE_SIZE, PAGE_SIZE, &crc); if (status) return 1; return 0; } snprintf(path, PATH_MAX, "/proc/self/map_files/%lx-%lx", (unsigned long) m, (unsigned long) m + MEM_SIZE); fd = open(path, O_RDWR); if (fd == -1) { err("Can't open file %s: %m", path); goto err; } m2 = mmap(NULL, PAGE_SIZE, PROT_WRITE | PROT_READ, MAP_SHARED, fd, MEM_OFFSET3); if (m2 == MAP_FAILED) { err("Can't map file %s", path); goto err; } close(fd); munmap(m, PAGE_SIZE); munmap(m + PAGE_SIZE * 10, PAGE_SIZE); munmap(m + MEM_OFFSET2, PAGE_SIZE); crc = ~0; datagen(m + PAGE_SIZE, PAGE_SIZE, &crc); crc = ~0; datagen(m2, PAGE_SIZE, &crc); test_daemon(); test_waitsig(); kill(pid, SIGTERM); wait(&status); if (WIFEXITED(status)) { if (WEXITSTATUS(status)) goto err; } else goto err; crc = ~0; if (datachk(m + MEM_OFFSET, PAGE_SIZE, &crc)) goto err; crc = ~0; if (datachk(m2, PAGE_SIZE, &crc)) goto err; pass(); return 0; err: if (waitpid(-1, NULL, WNOHANG) == 0) { kill(pid, SIGTERM); wait(NULL); } return 1; }
static int fork_child(int i) { int p[2]; int status, ret; pid_t pid, sid; ret = pipe(p); if (ret) { pr_perror("pipe() failed"); return 1; } pid = test_fork(); if (pid < 0) { pr_perror("Can't fork"); return 1; } if (pid == 0) { if (testcases[i].flags & NEWSID) { sid = setsid(); if (sid == -1) { pr_perror("setsid failed"); write(p[1], &sid, sizeof(sid)); exit(1); } } if (testcases[i].flags & (DETACH | CHANGESID)) { pid = test_fork(); if (pid < 0) { write(p[1], &pid, sizeof(pid)); exit(1); } } if (pid != 0) { if (!(testcases[i].flags & CHANGESID)) exit(0); sid = setsid(); if (sid == -1) { pr_perror("setsid failed"); write(p[1], &sid, sizeof(sid)); exit(1); } close(p[1]); wait(NULL); if (getsid(getpid()) != sid) { fail("The process %d (%x) has SID=%d (expected %d)", pid, testcases[i].flags, sid, testcases[i].sid); exit(1); } exit(0); } if (testcases[i].flags & DOUBLE_CHANGESID) { pid = fork(); if (pid < 0) { write(p[1], &pid, sizeof(pid)); exit(1); } if (pid == 0) goto child; sid = setsid(); if (sid == -1) { pr_perror("setsid failed"); write(p[1], &sid, sizeof(sid)); exit(1); } close(p[1]); wait(NULL); if (getsid(getpid()) != sid) { fail("The process %d (%x) has SID=%d (expected %d)", pid, testcases[i].flags, sid, testcases[i].sid); exit(1); } exit(0); } child: pid = getpid(); write(p[1], &pid, sizeof(pid)); close(p[1]); test_waitsig(); pass(); exit(0); } close(p[1]); if (testcases[i].flags & DETACH) { pid_t ret; ret = wait(&status); if (ret != pid) { pr_perror("wait return %d instead of %d", ret, pid); kill(pid, SIGKILL); return 1; } } ret = read(p[0], &testcases[i].pid, sizeof(pid)); if (ret != sizeof(ret)) { pr_perror("read failed"); return 1; } /* wait when a child closes fd */ ret = read(p[0], &testcases[i].pid, sizeof(pid)); if (ret != 0) { pr_perror("read failed"); return 1; } close(p[0]); if (testcases[i].pid < 0) { pr_perror("child failed"); return 1; } testcases[i].sid = getsid(testcases[i].pid); return 0; }
int main(int argc, char **argv) { unsigned char buf[BUF_SIZE]; int fd, fd_s; int status; pid_t pid; int res; uint32_t crc; struct sigaction sa = { .sa_handler = sig_hand, /* don't set SA_RESTART */ }; test_init(argc, argv); if ((fd_s = tcp_init_server(ZDTM_FAMILY, &port)) < 0) { err("initializing server failed"); return 1; } test_daemon(); test_waitsig(); sigemptyset(&sa.sa_mask); if (sigaction(SIGCHLD, &sa, NULL)) fprintf(stderr, "Can't set SIGTERM handler: %m\n"); pid = test_fork(); if (pid < 0) { err("fork failed. Return %d %m", pid); return 1; } if (pid == 0) { /* * Chiled is client of TCP connection */ close(fd_s); fd = tcp_init_client(ZDTM_FAMILY, "localhost", port); if (fd < 0) return 1; res = read(fd, buf, BUF_SIZE); close(fd); if (res != BUF_SIZE) { err("read less then have to: %d instead of %d", res, BUF_SIZE); return -1; } if (datachk(buf, BUF_SIZE, &crc)) return -2; return 0; } /* * parent is server of TCP connection */ fd = tcp_accept_server(fd_s); close(fd_s); if (fd < 0) { err("can't accept client connection %m"); goto error; } datagen(buf, BUF_SIZE, &crc); if (write(fd, buf, BUF_SIZE) < BUF_SIZE) { err("can't write"); goto error; } close(fd); if (wait(&status) < 0) { err("wait failed %m"); goto error; } if (WIFEXITED(status) && WEXITSTATUS(status) != 0) { err("chiled failed. Return %d", WEXITSTATUS(status)); return 1; } pass(); return 0; error: kill(pid, SIGKILL); wait(&status); return -1; }
int main(int argc, char **argv) { int ret = 0; pid_t pid; int i; uint8_t buf[PIPE_BUF * 100]; int pipes[2]; test_init(argc, argv); if (num_procs > PROCS_MAX) { pr_err("%d processes is too many: max = %d\n", num_procs, PROCS_MAX); exit(1); } if (pipe(pipes)) { pr_perror("Can't create pipes"); exit(1); } if (signal(SIGCHLD, inc_num_exited) == SIG_ERR) { pr_perror("can't set SIGCHLD handler"); exit(1); } for (i = 1; i < num_procs; i++) { /* i = 0 - parent */ pid = test_fork(); if (pid < 0) { pr_perror("can't fork"); kill(0, SIGKILL); exit(1); } if (pid == 0) { close(pipes[1]); while (test_go()) { int rlen = read(pipes[0], buf, sizeof(buf)); if (rlen == 0) break; else if (rlen < 0) { ret = errno; /* pass errno as exit code to the parent */ break; } for (i = 0; i < rlen && buf[i] == SND_CHR; i++) ; if (i < rlen) { ret = EILSEQ; break; } } test_waitsig(); /* even if failed, wait for migration to complete */ close(pipes[0]); exit(ret); } } close(pipes[0]); if (num_exited) { pr_err("Some children died unexpectedly\n"); kill(0, SIGKILL); exit(1); } test_daemon(); memset(buf, SND_CHR, sizeof(buf)); while(test_go()) if (write(pipes[1], buf, sizeof(buf)) < 0 && (errno != EINTR || test_go())) { /* only SIGTERM may stop us */ fail("write failed: %m\n"); ret = 1; break; } close(pipes[1]); test_waitsig(); /* even if failed, wait for migration to complete */ if (kill(0, SIGTERM)) { fail("failed to send SIGTERM to my process group: %m\n"); goto out; /* shouldn't wait() in this case */ } for (i = 1; i < num_procs; i++) { /* i = 0 - parent */ int chret; if (wait(&chret) < 0) { fail("can't wait for a child: %m\n"); ret = 1; continue; } chret = WEXITSTATUS(chret); if (chret) { fail("child exited with non-zero code %d (%s)\n", chret, strerror(chret)); ret = 1; continue; } } if (!ret) pass(); out: return 0; }
int main(int argc, char **argv) { key_t key; int msg, pid; struct msg1 msgbuf; int chret; test_init(argc, argv); key = ftok(argv[0], 822155650); if (key == -1) { pr_perror("Can't make key"); exit(1); } pid = test_fork(); if (pid < 0) { pr_perror("Can't fork"); exit(1); } msg = msgget(key, IPC_CREAT | IPC_EXCL | 0666); if (msg == -1) { msg = msgget(key, 0666); if (msg == -1) { pr_perror("Can't get queue"); goto err_kill; } } if (pid == 0) { test_waitsig(); if (msgrcv(msg, &msgbuf, sizeof(TEST_STRING), MSG_TYPE, IPC_NOWAIT) == -1) { fail("Child: msgrcv failed (%m)"); return -errno; } if (strncmp(TEST_STRING, msgbuf.mtext, sizeof(TEST_STRING))) { fail("Child: the source and received strings aren't equal"); return -errno; } test_msg("Child: received %s\n", msgbuf.mtext); msgbuf.mtype = ANOTHER_MSG_TYPE; memcpy(msgbuf.mtext, ANOTHER_TEST_STRING, sizeof(ANOTHER_TEST_STRING)); if (msgsnd(msg, &msgbuf, sizeof(ANOTHER_TEST_STRING), IPC_NOWAIT) != 0) { fail("Child: msgsnd failed (%m)"); return -errno; }; pass(); return 0; } else { msgbuf.mtype = MSG_TYPE; memcpy(msgbuf.mtext, TEST_STRING, sizeof(TEST_STRING)); if (msgsnd(msg, &msgbuf, sizeof(TEST_STRING), IPC_NOWAIT) != 0) { fail("Parent: msgsnd failed (%m)"); goto err_kill; }; msgbuf.mtype = ANOTHER_MSG_TYPE; memcpy(msgbuf.mtext, ANOTHER_TEST_STRING, sizeof(ANOTHER_TEST_STRING)); if (msgsnd(msg, &msgbuf, sizeof(ANOTHER_TEST_STRING), IPC_NOWAIT) != 0) { fail("child: msgsnd (2) failed (%m)"); return -errno; }; test_daemon(); test_waitsig(); kill(pid, SIGTERM); wait(&chret); chret = WEXITSTATUS(chret); if (chret) { fail("Parent: child exited with non-zero code %d (%s)\n", chret, strerror(chret)); goto out; } if (msgrcv(msg, &msgbuf, sizeof(ANOTHER_TEST_STRING), ANOTHER_MSG_TYPE, IPC_NOWAIT) == -1) { fail("Parent: msgrcv failed (%m)"); goto err; } if (strncmp(ANOTHER_TEST_STRING, msgbuf.mtext, sizeof(ANOTHER_TEST_STRING))) { fail("Parent: the source and received strings aren't equal"); goto err; } test_msg("Parent: received %s\n", msgbuf.mtext); pass(); } out: if (msgctl(msg, IPC_RMID, 0)) { fail("Failed to destroy message queue: %d\n", -errno); return -errno; } return chret; err_kill: kill(pid, SIGKILL); wait(NULL); err: chret = -errno; goto out; }
int main(int argc, char **argv) { pid_t pid; int p[2], ret, status; test_init(argc, argv); if (pipe(p)) { err("Unable to create pipe"); return 1; } pid = test_fork(); if (pid < 0) return -1; else if (pid == 0) { char c; close(p[1]); ret = read(p[0], &c, 1); if (ret != 1) { err("Unable to read: %d", ret); return 1; } return 0; } close(p[0]); kill(pid, SIGSTOP); write(p[1], "0", 1); close(p[1]); test_daemon(); test_waitsig(); // Return immediately if child run or stopped(by SIGSTOP) if (waitpid(pid, &status, WUNTRACED | WCONTINUED) == -1) { err("Unable to wait child"); goto out; } if (WIFSTOPPED(status)) test_msg("The procces stopped\n"); else{ fail("The process doesn't stopped"); goto out; } kill(pid, SIGCONT); if (waitpid(pid, &status, 0) == -1) { err("Unable to wait child"); goto out; } if (WIFEXITED(status)) pass(); else fail("The process doesn't continue"); out: return 0; }
int main(int argc, char **argv) { int ret = 0; pid_t pid; int i; uint8_t buf[0x100000]; int pipes[PROCS_MAX * 2]; int in, out; test_init(argc, argv); if (num_procs > PROCS_MAX) { err("%d processes is too many: max = %d\n", num_procs, PROCS_MAX); exit(1); } for (i = 0; i < num_procs; i++) if (pipe(pipes + i * 2)) { err("Can't create pipes: %m\n"); exit(1); } if (signal(SIGCHLD, inc_num_exited) == SIG_ERR) { err("can't set SIGCHLD handler: %m\n"); exit(1); } for (i = 1; i < num_procs; i++) { /* i = 0 - parent */ pid = test_fork(); if (pid < 0) { err("Can't fork: %m\n"); kill(0, SIGKILL); exit(1); } if (pid == 0) { int j; in = i * 2; out = in - 1; for (j = 0; j < num_procs * 2; j++) if (j != in && j != out) close(pipes[j]); signal(SIGPIPE, SIG_IGN); if (pipe_in2out(pipes[in], pipes[out], buf, sizeof(buf)) < 0) /* pass errno as exit code to the parent */ if (test_go() /* signal NOT delivered */ || (errno != EINTR && errno != EPIPE)) ret = errno; test_waitsig(); /* even if failed, wait for migration to complete */ close(pipes[in]); close(pipes[out]); exit(ret); } } for (i = 1; i < num_procs * 2 - 1; i++) close(pipes[i]); in = pipes[0]; out = pipes[num_procs * 2 - 1]; /* don't block on writing, _do_ block on reading */ if (set_nonblock(out,1) < 0) { err("setting O_NONBLOCK failed: %m"); exit(1); } if (num_exited) { err("Some children died unexpectedly\n"); kill(0, SIGKILL); exit(1); } test_daemon(); while (test_go()) { int len, rlen = 0, wlen; uint8_t rbuf[sizeof(buf)], *p; datagen(buf, sizeof(buf), NULL); wlen = write(out, buf, sizeof(buf)); if (wlen < 0) { if (errno == EINTR) continue; else { fail("write failed: %m\n", i); ret = 1; break; } } for (p = rbuf, len = wlen; len > 0; p += rlen, len -= rlen) { rlen = read(in, p, len); if (rlen <= 0) break; } if (rlen < 0 && errno == EINTR) continue; if (len > 0) { fail("read failed: %m\n"); ret = 1; break; } if (memcmp(buf, rbuf, wlen)) { fail("data mismatch\n"); ret = 1; break; } } close(out); test_waitsig(); /* even if failed, wait for migration to complete */ if (kill(0, SIGTERM)) { fail("failed to send SIGTERM to my process group: %m\n"); goto out; /* shouldn't wait() in this case */ } for (i = 1; i < num_procs; i++) { /* i = 0 - parent */ int chret; if (wait(&chret) < 0) { fail("can't wait for a child: %m\n"); ret = 1; continue; } chret = WEXITSTATUS(chret); if (chret) { fail("child %d exited with non-zero code %d (%s)\n", i, chret, strerror(chret)); ret = 1; continue; } } if (!ret) pass(); out: close(in); return 0; }
int main(int argc, char *argv[]) { char buf[sizeof(teststr)]; int master, slave, ret; char *slavename; task_waiter_t t; pid_t pid; test_init(argc, argv); master = open("/dev/ptmx", O_RDWR); if (master == -1) { err("open(%s) failed", "/dev/ptmx"); return 1; } grantpt(master); unlockpt(master); slavename = ptsname(master); slave = open(slavename, O_RDWR); if (slave == -1) { err("open(%s) failed", slavename); return 1; } task_waiter_init(&t); pid = test_fork(); if (pid == 0) { int new_master, ret; new_master = dup(master); if (new_master < 0) { err("can't dup master\n"); exit_shot_parent(1); } task_waiter_complete_current(&t); ret = write(new_master, teststr, sizeof(teststr) - 1); if (ret != sizeof(teststr) - 1) { err("write(new_master) failed"); exit_shot_parent(1); } task_waiter_wait4(&t, 1); close(new_master); exit(0); } else if (pid < 0) { err("test_fork failed: %m\n"); exit(1); } task_waiter_wait4(&t, pid); close(master); test_daemon(); test_waitsig(); signal(SIGHUP, SIG_IGN); task_waiter_complete(&t, 1); ret = read(slave, buf, sizeof(teststr) - 1); if (ret != sizeof(teststr) - 1) { err("read(slave) failed"); return 1; } if (strncmp(teststr, buf, sizeof(teststr) - 1)) { fail("data mismatch"); return 1; } close(slave); pass(); return 0; }
int main(int argc, char **argv) { int ret = 0; pid_t pid; int i; uint8_t buf[0x100000]; int socks[PROCS_MAX * 2]; int in, out; test_init(argc, argv); if (num_procs > PROCS_MAX) { err("%d processes is too many: max = %d\n", num_procs, PROCS_MAX); exit(1); } for (i = 0; i < num_procs; i++) if (socketpair(AF_LOCAL, SOCK_STREAM, 0, socks + i * 2)) { err("Can't create socks: %m\n"); exit(1); } if (signal(SIGCHLD, inc_num_exited) == SIG_ERR) { err("can't set SIGCHLD handler: %m\n"); exit(1); } for (i = 1; i < num_procs; i++) { /* i = 0 - parent */ pid = test_fork(); if (pid < 0) { err("Can't fork: %m\n"); kill(0, SIGKILL); exit(1); } if (pid == 0) { int j; in = i * 2; out = in - 1; for (j = 0; j < num_procs * 2; j++) if (j != in && j != out) close(socks[j]); signal(SIGPIPE, SIG_IGN); if (pipe_in2out(socks[in], socks[out], buf, sizeof(buf)) < 0) /* pass errno as exit code to the parent */ if (test_go() /* signal NOT delivered */ || (errno != EINTR && errno != EPIPE && errno != ECONNRESET)) ret = errno; test_waitsig(); /* even if failed, wait for migration to complete */ close(socks[in]); close(socks[out]); exit(ret); } } for (i = 1; i < num_procs * 2 - 1; i++) close(socks[i]); in = socks[0]; out = socks[num_procs * 2 - 1]; /* don't block on writing, _do_ block on reading */ if (set_nonblock(out,1) < 0) { err("setting O_NONBLOCK failed: %m"); exit(1); } if (num_exited) { err("Some children died unexpectedly\n"); kill(0, SIGKILL); exit(1); } test_daemon(); while (test_go()) { int len, rlen = 0, wlen; uint8_t rbuf[sizeof(buf)], *p; datagen(buf, sizeof(buf), NULL); wlen = write(out, buf, sizeof(buf)); if (wlen < 0) { if (errno == EINTR) continue; else { fail("write failed: %m\n", i); ret = 1; break; } } for (p = rbuf, len = wlen; len > 0; p += rlen, len -= rlen) { rlen = read(in, p, len); if (rlen <= 0) break; } if (rlen < 0 && errno == EINTR) continue; if (len > 0) { fail("read failed: %m\n"); ret = 1; break; } if (memcmp(buf, rbuf, wlen)) { fail("data mismatch\n"); ret = 1; break; } } test_waitsig(); /* even if failed, wait for migration to complete */ /* We expect that write(2) in child may return error only after signal * has been received. Thus, send signal before closing parent fds. */ if (kill(0, SIGTERM)) { fail("failed to send SIGTERM to my process group: %m\n"); goto out; /* shouldn't wait() in this case */ } if (close(out)) fail("Failed to close parent fd 'out': %m\n"); /* If last child in the chain (from whom we read data) receives signal * after parent has finished reading but before calling write(2), this * child can block forever. To avoid this, close 'in' fd. */ if (close(in)) fail("failed to close parent fd 'in': %m\n"); for (i = 1; i < num_procs; i++) { /* i = 0 - parent */ int chret; if (wait(&chret) < 0) { fail("can't wait for a child: %m\n"); ret = 1; continue; } chret = WEXITSTATUS(chret); if (chret) { fail("child %d exited with non-zero code %d (%s)\n", i, chret, strerror(chret)); ret = 1; continue; } } if (!ret) pass(); out: return 0; }