ccx-utils

Miscellaneous utilities written in C
git clone https://ccx.te2000.cz/git/ccx-utils
Log | Files | Refs

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 }