mrrl

Minimal Reliable Reproducible Linux
git clone https://ccx.te2000.cz/git/mrrl
Log | Files | Refs | Submodules | README

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 }