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