1 /* ISC license. */
2 
3 #include <unistd.h>
4 #include <errno.h>
5 
6 #include <skalibs/sgetopt.h>
7 #include <skalibs/types.h>
8 #include <skalibs/strerr2.h>
9 #include <skalibs/exec.h>
10 #include <skalibs/djbunix.h>
11 
12 #include <execline/execline.h>
13 
14 #define USAGE "pipeline [ -d ] [ -r | -w ] { command... } command..."
15 #define dieusage() strerr_dieusage(100, USAGE)
16 
main(int argc,char const ** argv,char const * const * envp)17 int main (int argc, char const **argv, char const *const *envp)
18 {
19   int df = 0, w = 0 ;
20   PROG = "pipeline" ;
21   {
22     subgetopt_t l = SUBGETOPT_ZERO ;
23     for (;;)
24     {
25       int opt = subgetopt_r(argc, argv, "drw", &l) ;
26       if (opt == -1) break ;
27       switch (opt)
28       {
29         case 'd' : df = 1 ; break ;
30         case 'r' : w = 0 ; break ;
31         case 'w' : w = 1 ; break ;
32         default : dieusage() ;
33       }
34     }
35     argc -= l.ind ; argv += l.ind ;
36   }
37   {
38     pid_t pid ;
39     int fd ;
40     int argc1 = el_semicolon(argv) ;
41     if (argc1 >= argc) strerr_dief1x(100, "unterminated block") ;
42     if (argc1 + 1 == argc) strerr_dief1x(100, "empty remainder") ;
43     argv[argc1] = 0 ;
44     if (df)
45     {
46       int p[2] ;
47       if (pipe(p) < 0) strerr_diefu1sys(111, "create pipe") ;
48       pid = doublefork() ;
49       switch (pid)
50       {
51         case -1: strerr_diefu1sys(111, "doublefork") ;
52         case 0:
53           PROG = "pipeline (grandchild)" ;
54           fd_close(p[w]) ;
55           if (fd_move(!w, p[!w]) < 0) strerr_diefu1sys(111, "fd_move") ;
56           xexec0_e(argv, envp) ;
57       }
58       fd_close(p[!w]) ;
59       fd = p[w] ;
60     }
61     else
62     {
63       pid = el_spawn1(argv[0], argv, envp, &fd, !w) ;
64       if (!pid) strerr_diefu2sys(111, "spawn ", argv[0]) ;
65     }
66     if (fd_move(w, fd) < 0) strerr_diefu1sys(111, "fd_move") ;
67     if (w == fd) uncoe(fd) ;
68     {
69       char fmt[PID_FMT + 2] = "!=" ;
70       size_t i = 2 ;
71       i += pid_fmt(fmt+i, pid) ; fmt[i++] = 0 ;
72       xmexec_en(argv + argc1 + 1, envp, fmt, i, 1) ;
73     }
74   }
75 }
76