pidns_run.c (2390B)
1 #include <errno.h> 2 #include <sched.h> /* Definition of CLONE_* constants & unshare */ 3 #include <unistd.h> /* fork(), getpid() */ 4 #include <sys/wait.h> 5 #include <sys/select.h> 6 #include <assert.h> 7 #include <stdlib.h> /* exit() */ 8 9 #include <skalibs/exec.h> 10 #include <skalibs/djbunix.h> 11 #include <skalibs/strerr.h> 12 13 #define PROG "pidns_run" 14 15 int main(const int argc, const char **argv) { 16 int piperw[2]; 17 #define parent_rfd piperw[0] 18 #define parent_wfd piperw[1] 19 /* Create pipe with (O_NONBLOCK | FD_CLOEXEC) */ 20 if(pipenbcoe(piperw) != 0) { 21 strerr_dief1sys(111, "pipe()"); 22 } 23 if(unshare(CLONE_NEWPID) != 0) { 24 strerr_dief1sys(111, "unshare()"); 25 } 26 int fork1_pid = fork(); 27 if(fork1_pid < 0) { 28 strerr_dief1sys(111, "first fork()"); 29 } 30 if(fork1_pid == 0) { 31 /* child */ 32 assert(getpid() == 1); 33 if(close(parent_wfd) != 0) { 34 strerr_dief1sys(111, "close(parent_wfd)"); 35 } 36 int fork2_pid = fork(); 37 if(fork2_pid < 0) { 38 strerr_dief1sys(111, "second fork()"); 39 } 40 if(fork2_pid == 0) { 41 /* child */ 42 exec(&argv[1]); 43 } else { 44 /* parent */ 45 fd_set rfds; 46 struct timeval tv = {1, 0}; 47 int retval, wstatus; 48 pid_t pid; 49 FD_ZERO(&rfds); 50 FD_SET(parent_rfd, &rfds); 51 while(1) { 52 pid = waitpid(0, &wstatus, WNOHANG); 53 if(pid == fork2_pid) { 54 exit(wait_estatus(wstatus)); 55 } 56 retval = select(1, &rfds, NULL, NULL, &tv); 57 if (retval == -1 && errno != EINTR) { 58 strerr_dief1sys(111, "select()"); 59 } 60 if(retval > 0) { 61 const char term_msg[] = "pidns_run: parent died, terminating\n"; 62 write(2, "pidns_run: parent died, terminating\n", sizeof(term_msg)); 63 exit(111); 64 } 65 tv.tv_sec = 1; 66 tv.tv_usec = 0; 67 } 68 } 69 } else { 70 /* parent */ 71 if(close(parent_rfd) != 0) { 72 strerr_dief1sys(111, "close(parent_rfd)"); 73 } 74 int wstatus; 75 pid_t pid = waitpid(fork1_pid, &wstatus, 0); 76 exit(wait_estatus(wstatus)); 77 } 78 }