chiark / gitweb /
prefork-interp: formalise mediation etc.
[chiark-utils.git] / cprogs / prefork-interp.c
1 /*
2  * "Interpreter" that you can put in #! like this
3  *   #!/usr/bin/prefork-interp [<options>] <interpreter>
4  *
5  * Usages:
6  *   prefork-interp  [<option> ..] <interpreter>  [<script> [<args> ...]]
7  *   prefork-interp  [<option>,..],<interpreter>   <script> [<args> ...]
8  *   prefork-interp '[<option> ..] <interpreter>'  <script> [<args> ...]
9  *
10  * Options must specify argument laundering mode.
11  * Currently the only mode supported is:
12  *   -U    unlaundered: setup and executor both get all arguments and env vars
13  *         ident covers only env vars specified  with -E
14  *         ident covers only arguments interpreter and (if present) script
15  */
16
17 /*
18 ***************************************************************************
19 \f
20   State during service execution, process parentage and key fds
21
22       CALLER
23         ||
24         ||
25         ||                               listen     watch-err/in
26         ||       call                 (accept) \     ,------2
27         || ,-----------------------------.     SERVER -----0 WATCHER(C)
28       CLIENT 2--=fdpassed>=---------.     \      || &&          |      &&
29        (C)  1--=fdpassed>=---------. \     \     ||           inotify
30            0--=fdpassed>=---------. \ \     \    ||           sockpath
31                                    \ \ \     \   ||
32                                    | | |\     |  ||
33                                    | | | \    |  ||
34                                    | \ |  \   \  ||
35                                     \ \ \  \   MONITOR &
36                                      \ \ \  `12  ||  |
37                                       \ \ \      ||  |
38                                        \ \ \     ||  |execterm
39                                         \ \ \    ||  |
40                                          \ \ \   ||  |
41                                           \ \ 2  ||  |
42                                            \ 1 EXECUTOR
43                                             0
44     ----      pipes, sockets
45     012       descriptors
46     -==-      fds shared
47     ||        process parentage
48     &&        session leader (daemon)
49     &         process group leader
50
51 ***************************************************************************
52 \f
53  Control flow and causality
54
55       CALLER
56          |
57          |fork/exec
58          |
59       CLIENT
60          |
61       attempt to connect, and read greeting
62          |failure?                \success?
63          |                         \
64       tidy up stale /run entries    *1 (continue from send_fds, below)
65       acquire lock
66          |
67       retry attempt to connect, and read greeting
68          |failure?                \success?
69          |                         \
70       create listening socket     release lock
71          |                           \
72       fork/daemonise                  *1
73          |    `------------------.
74          |                      WATCHER(C) &&
75          |
76        make "fake" initial call socketpair                               (C)
77          |                                                    prefork-interp
78        fork/exec   #########################################################
79          |      `-------------.                                  application
80          |         #        SCRIPT (setup)
81          |         #          |
82          |         #       script initialisation
83          |         #          |                                  application
84          |         #  ########|#############################################
85          |         #          |                               prefork-interp
86          |         #       identify fds from envirnment               (Perl)
87          |         #       open syslog
88          |         #          |
89          |         #       dzemonize
90          |   ,.....<....../   |
91       waitpid      #        fork for initial service
92          |         #          |child?       |parent?
93          |         #          |             |
94          |         #          |         SCRIPT [server] &&
95          |         #          |             |
96          |         #          |         ** accept / event loop **
97          |         #          |        accepted?    \      \ \
98          |         #          |            /         \ watch\ \idle
99          |         #          |        fork child     \stderr\ \timeout?
100          |         #          | _________/            |       | |
101          |         #          |/                      |read?  | |
102          |         #     SCRIPT [monitor]             |   eof?| |
103          |         #       setpgrpt &                 |       | |
104          |         #          |                     log msg   | |
105        read   ,....<.....send greeting                |       | |
106       greeting     #          |                    ___________________
107          |         #          |
108       release      #          |
109       lock    *1   #          |
110          |   /     #          |
111       send fds.....>....      |
112          |         #    \receive fds
113          |         #             |
114          |         #         fork for executor                        (Perl)
115          |         #          |parent?        \child?         prefork-interp
116          |         #          |          ######\############################
117          |         #          |          #  SCRIPT (executor)    application
118          |         #          |          #  execute service
119          |         #    wait for read    #       |
120          |         #      (select)       #   terminates
121          |         #        |   |        #       |
122          |         #            |        #    kernel closes execterm
123          |         #            | ,......<....../|
124          |         #      execterm?      #       |
125          |         #            |        #     zombie
126          |         #        |   | ,......<...../
127          |         #       waitpid       #  _______________
128          |         #          |          #
129          |    ,....<....,..send status   #
130     read status    #  ________________   #
131    _____________   #
132
133
134   ********** Or, if client is killed **********
135
136          |         #          |          #  execute service
137      terminates    #    wait for read    #       |
138          |         #      (select)       #       |
139       kernel       #        |   |        #       |
140      closes call   #        |            #       |
141                 \..>......_ |            #       |
142    _____________   #       \|call?       #       |
143                    #        |            #       |
144                    #  kill whole pgrp... #    killled
145                    #        |            #     zombie
146                    #        |   | ,......<....../
147                    #       waitpid       #  _______________
148                    #          |          #
149                    #   send exit status  #
150                    #  _____SIGPIPE______ #
151
152     | - \ /    process control flow
153     ... < >    causes mediated by fds or other IPC etc.
154     &&         session leader (daemon)
155     &          process group leader
156     #          language/implementation boundary
157     *1         line continued elsewhere
158     event?     condition
159     ______     process termination (after reaping, if shown)
160
161 ***************************************************************************
162 \f
163   Sequence of events and fd pluming.
164   NB INCOMPLETE - does not cover execterm, cleanup
165  
166    client (C wrapper)        connects to server
167                                (including reading ack byte)
168                              if fails or garbage
169                              === acquires lock ===
170                              makes new listening socket
171                              makes watcher pipes
172                              forks watcher and awaits
173                              makes first-instance socketpair
174                              forks setup (script, sock fds indicated in env)
175                              fd0, fd1, fd2: from-outer
176                              other fd: call(client-end)(fake)
177                              reaps setup (and reports error)
178                              (implicitly releases lock)
179  
180       watcher                fd[012]: watcher pipes
181                              starts watch on socket path
182                              sets stderr to line buffered
183                              sets stdin to nonblocking
184                              daemonises (one fork, becomes session leader)
185                              when socket stat changes, quit
186  
187       setup (pre-exec)       fd0: null,
188                              fd[12]: fd2-from-outer
189                              env fds: listener, call(server-end)(fake),
190                                        watcher read, watcher write
191                              close fd: lockfile
192                              possibly clean env, argv
193  
194       setup (script)         runs initialisation parts of the script
195                              at prefork establishment point:
196       setup (pm) [1]         opens syslog
197                              forks for server
198                  [2]         exits
199  
200          server (pm) [1]     [fd0: null],
201                              [fd[12]: fd2-from-outer]
202                              setsid
203                              right away, forks init monitor
204                      [2]     closes outer caller fds and call(fake)
205          [server (pm)]       fd[012]: null
206                              other fds: listener, syslog
207                              runs in loop accepting and forking,
208                              reaping and limiting children (incl init monitor)
209                              reports failures of monitors to syslog
210  
211    [client (C wrapper)]      if client connect succeeds:
212                              now fd: call(client-end)
213                                 sends message with: cmdline, env
214                                 sends fds
215  
216          [server (script)]   accepts, forks subseq monitor
217  
218            monitor [1]       [fd0: null]
219             (init            [fd[12]: init: fd2-from-outer; subseq: null]
220               or             errors: init: fd2; subseq: syslog
221              subseq)         other fds: syslog, call(server-end)
222                              sends ack byte
223                              receives args, env, fds
224                              forks executor
225  
226              executor        sorts out fds:
227                              fd0, fd1, fd2: from-outer
228                              close fds: call(server-end)
229                              retained fds: syslog
230  
231                              sets cmdline, env
232                              runs main part of script
233                              exits normally
234  
235            [monitor]         [fd[012]: null]
236                              [fd[12]: init: fd2-from-outer; subseq: null]
237                              [errors: init: fd2; subseq: syslog]
238                              reaps executor
239                              reports status via socket
240  
241      [client (C wrapper)]    [fd0, fd1, fd2: from-outer]
242                              [other fd: call(client-end)]
243                              receives status, exits appropriately
244                              (if was bad signal, reports to stderr, exits 127)
245
246 ***************************************************************************
247 \f
248 */
249
250 #include <arpa/inet.h>
251
252 #include <uv.h>
253
254 #include "prefork.h"
255
256 const char our_name[] = "prefork-interp";
257
258 static struct sockaddr_un sockaddr_sun;
259 static FILE *call_sock;
260
261 #define ACK_BYTE '\n'
262
263 static const char *const *executor_argv;
264
265 static const char header_magic[4] = "PFI\n";
266
267 void fusagemessage(FILE *f) {
268   fprintf(f, "usage: #!/usr/bin/prefork-interp [<options>]\n");
269 }
270
271 #define MODE_NORMAL 0
272 #define MODE_KILL   'k'
273 #define MODE_FRESH  'f'
274
275 #define MEDIATION_UNSPECIFIED 0
276 #define MEDIATION_UNLAUNDERED 'U'
277
278 static int mediation = MEDIATION_UNSPECIFIED;
279 static int mode = MODE_NORMAL;
280 static int max_sockets = 100; // maximum entries in the run dir is 2x this
281
282 static struct stat initial_stab;
283
284 const struct cmdinfo cmdinfos[]= {
285   PREFORK_CMDINFOS
286   { 0,         'U',   0, .iassignto= &mediation, .arg= MEDIATION_UNLAUNDERED },
287   { "kill",     0,    0, .iassignto= &mode,      .arg= MODE_KILL   },
288   { 0,         'f',   0, .iassignto= &mode,      .arg= MODE_FRESH  },
289   { 0 }
290 };
291
292 void ident_addinit(void) {
293   char ident_magic[1] = { 0 };
294   sha256_update(&identsc, sizeof(ident_magic), ident_magic);
295 }
296
297 static void propagate_exit_status(int status, const char *what) {
298   int r;
299
300   if (WIFEXITED(status)) {
301     _exit(status);
302   }
303
304   if (WIFSIGNALED(status)) {
305     int sig = WTERMSIG(status);
306     const char *signame = strsignal(sig);
307     if (signame == 0) signame = "unknown signal";
308
309     if (! WCOREDUMP(status) &&
310         (sig == SIGINT ||
311          sig == SIGHUP ||
312          sig == SIGPIPE ||
313          sig == SIGKILL)) {
314       struct sigaction sa;
315       FILLZERO(sa);
316       sa.sa_handler = SIG_DFL;
317       r = sigaction(sig, &sa, 0);
318       if (r) diee("failed to reset signal handler while propagating %s",
319                   signame);
320
321       sigset_t sset;
322       sigemptyset(&sset);
323       sigaddset(&sset, sig);
324       r = sigprocmask(SIG_UNBLOCK, &sset, 0);
325       if (r) diee("failed to reset signal block while propagating %s",
326                   signame);
327
328       raise(sig);
329       die("unexpectedly kept running after raising (to propagate) %s",
330           signame);
331     }
332
333     die("%s failed due to signal %d %s%s", what, sig, signame,
334         WCOREDUMP(status) ? " (core dumped)" : "");
335   }
336
337   die("%s failed with weird wait status %d 0x%x", what, status, status);
338 }
339
340 typedef struct {
341   char *name_hash;
342   time_t atime;
343 } PrecleanEntry;
344
345 static int preclean_entry_compar_name(const void *av, const void *bv) {
346   const PrecleanEntry *a = av;
347   const PrecleanEntry *b = bv;
348   return strcmp(a->name_hash, b->name_hash);
349 }
350
351 static int preclean_entry_compar_atime(const void *av, const void *bv) {
352   const PrecleanEntry *ae = av;  time_t a = ae->atime;
353   const PrecleanEntry *be = bv;  time_t b = be->atime;
354   return (a > b ? +1 :
355           a < b ? -1 : 0);
356 }
357
358 static time_t preclean_stat_atime(const char *s_path) {
359   struct stat stab;
360   int r= lstat(s_path, &stab);
361   if (r) {
362     if (errno!=ENOENT) diee("pre-cleanup: stat socket (%s)", s_path);
363     return 0;
364   }
365   return stab.st_atime;
366 }
367
368 static void preclean(void) {
369   DIR *dir = opendir(run_base);
370   if (!dir) {
371     if (errno == ENOENT) return;
372     diee("pre-cleanup: open run dir (%s)", run_base);
373   }
374
375   PrecleanEntry *entries=0;
376   size_t avail_entries=0;
377   size_t used_entries=0;
378
379   struct dirent *de;
380   while ((errno = 0, de = readdir(dir))) {
381     char c0 = de->d_name[0];
382     if (!(c0 == 'l' || c0 == 's')) continue;
383     char *name_hash = m_asprintf("%s", de->d_name+1);
384     char *s_path = m_asprintf("%s/s%s", run_base, name_hash);
385     time_t atime = preclean_stat_atime(s_path);
386
387     if (avail_entries == used_entries) {
388       assert(avail_entries < INT_MAX / 4 / sizeof(PrecleanEntry));
389       avail_entries <<= 1;
390       avail_entries += 10;
391       entries = realloc(entries, avail_entries * sizeof(PrecleanEntry));
392     }
393     entries[used_entries].name_hash = name_hash;
394     entries[used_entries].atime = atime;
395     used_entries++;
396   }
397   if (errno) diee("pre-cleanup: read run dir (%s)", run_base);
398
399   // First we dedupe (after sorting by path)
400   qsort(entries, used_entries, sizeof(PrecleanEntry),
401         preclean_entry_compar_name);
402   PrecleanEntry *p, *q;
403   for (p=entries, q=entries; p < entries + used_entries; p++) {
404     if (q > entries && !strcmp(p->name_hash, (q-1)->name_hash))
405       continue;
406     *q++ = *p;
407   }
408   used_entries = q - entries;
409
410   // Now maybe delete some things
411   //
412   // Actually this has an off-by-one error since we are about
413   // to create a socket, so the actual number of sockets is one more.
414   // But, *actually*, since there might be multiple of us running at once,
415   // we might have even more than that.  This doesn't really matter.
416   if (used_entries > max_sockets) {
417     qsort(entries, used_entries, sizeof(PrecleanEntry),
418           preclean_entry_compar_atime);
419     for (p=entries; p < entries + max_sockets; p++) {
420       char *l_path = m_asprintf("%s/l%s", run_base, p->name_hash);
421       char *s_path = m_asprintf("%s/s%s", run_base, p->name_hash);
422       int lock_fd = flock_file(l_path);
423       // Recheck atime - we might have raced!
424       time_t atime = preclean_stat_atime(s_path);
425       if (atime != p->atime) {
426         // Raced.  This will leave use deleting too few things.  Whatever.
427       } else {
428         int r= unlink(s_path);
429         if (r && errno!=ENOENT) diee("preclean: delete stale (%s)", s_path);
430         r= unlink(l_path);
431         if (r) diee("preclean: delete stale lock (%s)", s_path);
432         // NB we don't hold the lock any more now.
433       }
434       close(lock_fd);
435       free(l_path);
436       free(s_path);
437     }
438   }
439
440   for (p=entries; p < entries + used_entries; p++)
441     free(p->name_hash);
442   free(entries);
443 }
444
445 static __attribute((noreturn)) void die_data_overflow(void) {
446   die("cannot handle data with length >2^32");
447 }
448
449 static void prepare_data(size_t *len, char **buf,
450                          const void *data, size_t dl) {
451   if (len) {
452     if (dl >= SIZE_MAX - *len)
453       die_data_overflow();
454     *len += dl;
455   }
456   if (buf) {
457     memcpy(*buf, data, dl);
458     *buf += dl;
459   }
460 }
461
462 static void prepare_length(size_t *len, char **buf, size_t dl_sz) {
463   if (dl_sz > UINT32_MAX) die_data_overflow();
464   uint32_t dl = htonl(dl_sz);
465   prepare_data(len, buf, &dl, sizeof(dl));
466 }
467
468 static void prepare_string(size_t *len, char **buf, const char *s) {
469   size_t sl = strlen(s);
470   prepare_data(len, buf, s, sl+1);
471 }
472
473 static void prepare_message(size_t *len, char **buf) {
474   const char *s;
475
476   const char *const *p = (void*)environ;
477   while ((s = *p++)) {
478     if (strchr(s, '='))
479       prepare_string(len, buf, s);
480   }
481
482   prepare_string(len, buf, "");
483
484   p = executor_argv;
485   while ((s = *p++))
486     prepare_string(len, buf, s);
487 }
488
489 static void send_fd(int payload_fd) {
490   int via_fd = fileno(call_sock);
491
492   union {
493     struct cmsghdr align;
494     char buf[CMSG_SPACE(sizeof(payload_fd))];
495   } cmsg_buf;
496
497   struct msghdr msg;
498   FILLZERO(msg);
499   FILLZERO(cmsg_buf);
500
501   char dummy_byte = 0;
502   struct iovec iov;
503   FILLZERO(iov);
504   iov.iov_base = &dummy_byte;
505   iov.iov_len = 1;
506
507   msg.msg_name = 0;
508   msg.msg_iov = &iov;
509   msg.msg_iovlen = 1;
510   msg.msg_control = cmsg_buf.buf;
511   msg.msg_controllen = sizeof(cmsg_buf.buf);
512
513   struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
514   cmsg->cmsg_level = SOL_SOCKET;
515   cmsg->cmsg_type = SCM_RIGHTS;
516   cmsg->cmsg_len = CMSG_LEN(sizeof(payload_fd));
517   *(int*)CMSG_DATA(cmsg) = payload_fd;
518
519   msg.msg_controllen = sizeof(cmsg_buf.buf);
520
521   for (;;) {
522     ssize_t r = sendmsg(via_fd, &msg, 0);
523     if (r == -1) {
524       if (errno == EINTR) continue;
525       diee("send fd");
526     }
527     assert(r == 1);
528     break;
529   }
530 }
531
532 static void send_request(void) {
533   // Sending these first makes it easier for the script to
534   // use buffered IO for the message.
535   send_fd(0);
536   send_fd(1);
537   send_fd(2);
538
539   size_t len = 0;
540   prepare_message(&len, 0);
541
542   size_t tlen = len + 4;
543   char *m = xmalloc(tlen);
544   char *p = m;
545   prepare_length(0, &p, len);
546   prepare_message(0, &p);
547   assert(p == m + tlen);
548
549   ssize_t sr = fwrite(m, tlen, 1, call_sock);
550   if (sr != 1) diee("write request (buffer)");
551
552   if (fflush(call_sock)) diee("write request");
553 }
554
555 static FILE *call_sock_from_fd(int fd) {
556   int r;
557
558   FILE *call_sock = fdopen(fd, "r+");
559   if (!call_sock) diee("fdopen socket");
560
561   r = setvbuf(call_sock, 0, _IONBF, 0);
562   if (r) die("setvbuf socket");
563
564   return call_sock;
565 }
566
567 static bool was_eof(FILE *call_sock) {
568   return feof(call_sock) || errno==ECONNRESET;
569 }
570
571 // Returns -1 on EOF
572 static int protocol_read_maybe(void *data, size_t sz) {
573   if (!sz) return 0;
574   size_t sr = fread(data, sz, 1, call_sock);
575   if (sr != 1) {
576     if (was_eof(call_sock)) return -1;
577     diee("read() on monitor call socket (%zd)", sz);
578   }
579   return 0;
580 }
581
582 static void protocol_read(void *data, size_t sz) {
583   if (protocol_read_maybe(data, sz) < 0)
584     die("monitor process quit unexpectedly");
585 }
586
587 // Returns 0 if OK, error msg if peer was garbage.
588 static const char *read_greeting(void) {
589   char got_magic[sizeof(header_magic)];
590
591   if (protocol_read_maybe(&got_magic, sizeof(got_magic)) < 0)
592     return "initial monitor process quit";
593
594   if (memcmp(got_magic, header_magic, sizeof(header_magic)))
595     die("got unexpected protocol magic 0x%02x%02x%02x%02x",
596         got_magic[0], got_magic[1], got_magic[2], got_magic[3]);
597
598   uint32_t xdata_len;
599   protocol_read(&xdata_len, sizeof(xdata_len));
600   void *xdata = xmalloc(xdata_len);
601   protocol_read(xdata, xdata_len);
602
603   return 0;
604 }
605
606 // Returns: call(client-end), or 0 to mean "is garbage"
607 // find_socket_path must have been called
608 static FILE *connect_existing(void) {
609   int r;
610   int fd = -1;
611
612   if (mode != MODE_NORMAL) return 0;
613
614   fd = socket(AF_UNIX, SOCK_STREAM, 0);
615   if (fd==-1) diee("socket() for client");
616
617   socklen_t salen = sizeof(sockaddr_sun);
618   r = connect(fd, (const struct sockaddr*)&sockaddr_sun, salen);
619   if (r==-1) {
620     if (errno==ECONNREFUSED || errno==ENOENT) goto x_garbage;
621     diee("connect() %s", socket_path);
622   }
623
624   call_sock = call_sock_from_fd(fd);
625   fd = -1;
626
627   if (read_greeting())
628     goto x_garbage;
629
630   return call_sock;
631
632  x_garbage:
633   if (call_sock) { fclose(call_sock); call_sock=0; }
634   if (fd >= 0) close(fd);
635   return 0;
636 }
637
638 static void watcher_cb_stdin(uv_poll_t *handle, int status, int events) {
639   char c;
640   int r;
641
642   if ((errno = -status)) diee("watcher: poll stdin");
643   for (;;) {
644     r= read(0, &c, 1);
645     if (r!=-1) _exit(0);
646     if (!(errno==EINTR || errno==EWOULDBLOCK || errno==EAGAIN))
647       diee("watcher: read sentinel stdin");
648   }
649 }
650
651 static void watcher_cb_sockpath(uv_fs_event_t *handle, const char *filename,
652                                 int events, int status) {
653   int r;
654   struct stat now_stab;
655
656   if ((errno = -status)) diee("watcher: poll stdin");
657   for (;;) {
658     r= stat(socket_path, &now_stab);
659     if (r==-1) {
660       if (errno==ENOENT) _exit(0);
661       if (errno==EINTR) continue;
662       diee("stat socket: %s", socket_path);
663     }
664     if (!stabs_same_inode(&now_stab, &initial_stab))
665       _exit(0);
666   }
667 }
668
669 // On entry, stderr is still inherited, but 0 and 1 are the pipes
670 static __attribute__((noreturn))
671 void become_watcher(void) {
672   uv_loop_t loop;
673   uv_poll_t uvhandle_stdin;
674   uv_fs_event_t uvhandle_sockpath;
675   int r;
676
677   nonblock(0);
678
679   errno= -uv_loop_init(&loop);
680   if (errno) diee("watcher: uv_loop_init");
681
682   errno= -uv_poll_init(&loop, &uvhandle_stdin, 0);
683   if (errno) diee("watcher: uv_poll_init");
684   errno= -uv_poll_start(&uvhandle_stdin,
685                         UV_READABLE | UV_WRITABLE | UV_DISCONNECT,
686                         watcher_cb_stdin);
687   if (errno) diee("watcher: uv_poll_start");
688
689   errno= -uv_fs_event_init(&loop, &uvhandle_sockpath);
690   if (errno) diee("watcher: uv_fs_event_init");
691
692   errno= -uv_fs_event_start(&uvhandle_sockpath, watcher_cb_sockpath,
693                             socket_path, 0);
694   if (errno) diee("watcher: uv_fs_event_start");
695
696   // OK everything is set up, let us daemonise
697   if (dup2(1,2) != 2) diee("watcher: set daemonised stderr");
698   r= setvbuf(stderr, 0, _IOLBF, BUFSIZ);
699   if (r) diee("watcher: setvbuf stderr");
700
701   pid_t child = fork();
702   if (child == (pid_t)-1) diee("watcher: fork");
703   if (child) _exit(0);
704
705   if (setsid() == (pid_t)-1) diee("watcher: setsid");
706
707   r= uv_run(&loop, UV_RUN_DEFAULT);
708   die("uv_run returned (%d)", r);
709 }
710
711 static __attribute__((noreturn))
712 void become_setup(int sfd, int lockfd, int fake_pair[2],
713                   int watcher_stdin, int watcher_stderr) {
714   close(lockfd);
715   close(fake_pair[0]);
716   int call_fd = fake_pair[1];
717
718   int null_0 = open("/dev/null", O_RDONLY);  if (null_0 < 0) diee("open null");
719   if (dup2(null_0, 0)) diee("dup2 /dev/null onto stdin");
720   close(null_0);
721   if (dup2(2, 1) != 1) die("dup2 stderr onto stdout");
722
723   nonblock(sfd);
724
725   // Extension could work like this:
726   //
727   // We advertise a new protocol (perhaps one which is nearly entirely
728   // different after the connect) by putting a name for it comma-separated
729   // next to "v1".  Simple extension can be done by having the script
730   // side say something about it in the ack xdata, which we currently ignore.
731   putenv(m_asprintf("PREFORK_INTERP=v1 %d,%d,%d,%d",
732                     sfd, call_fd, watcher_stdin, watcher_stderr));
733
734   execvp(executor_argv[0], (char**)executor_argv);
735   diee("execute %s", executor_argv[0]);
736 }
737
738 static void connect_or_spawn(void) {
739   int r;
740
741   call_sock = connect_existing();
742   if (call_sock) return;
743
744   // We're going to make a new one, so clean out old ones
745   preclean();
746
747   int lockfd = acquire_lock();
748
749   if (mode == MODE_KILL) {
750     r= unlink(socket_path);
751     if (r && errno != ENOENT) diee("remove socket %s", socket_path);
752
753     r= unlink(lock_path);
754     if (r) diee("rmeove lock %s", lock_path);
755     _exit(0);
756   }
757
758   call_sock = connect_existing();
759   if (call_sock) { close(lockfd); return; }
760
761   // We must start a fresh one, and we hold the lock
762
763   r = unlink(socket_path);
764   if (r<0 && errno!=ENOENT)
765     diee("failed to remove stale socket %s", socket_path);
766
767   int sfd = socket(AF_UNIX, SOCK_STREAM, 0);
768   if (sfd<0) diee("socket() for new listener");
769
770   socklen_t salen = sizeof(sockaddr_sun);
771   r= bind(sfd, (const struct sockaddr*)&sockaddr_sun, salen);
772   if (r<0) diee("bind() on new listener");
773
774   r= stat(socket_path, &initial_stab);
775   if (r<0) diee("stat() fresh socket");
776
777   // We never want callers to get ECONNREFUSED.  But:
778   // There is a race here: from my RTFM they may get ECONNREFUSED
779   // if they try between our bind() and listen().  But if they do, they'll
780   // acquire the lock (serialising with us) and retry, and then it will work.
781   r = listen(sfd, INT_MAX);
782   if (r<0) diee("listen() for new listener");
783
784   // Fork watcher
785
786   int watcher_stdin[2];
787   int watcher_stderr[2];
788   if (pipe(watcher_stdin) || pipe(watcher_stderr))
789     diee("pipe() for socket inode watcher");
790
791   pid_t watcher = fork();
792   if (watcher == (pid_t)-1) diee("fork for watcher");
793   if (!watcher) {
794     close(sfd);
795     close(lockfd);
796     close(watcher_stdin[1]);
797     close(watcher_stderr[0]);
798     if (dup2(watcher_stdin[0], 0) != 0 ||
799         dup2(watcher_stderr[1], 1) != 1)
800       diee("initial dup2() for watcher");
801     close(watcher_stdin[0]);
802     close(watcher_stderr[1]);
803     become_watcher();
804   }
805
806   close(watcher_stdin[0]);
807   close(watcher_stderr[1]);
808   nonblock(watcher_stderr[0]);
809
810   // Fork setup
811
812   int fake_pair[2];
813   r = socketpair(AF_UNIX, SOCK_STREAM, 0, fake_pair);
814   if (r<0) diee("socketpair() for fake initial connection");
815
816   pid_t setup_pid = fork();
817   if (setup_pid == (pid_t)-1) diee("fork for spawn setup");
818   if (!setup_pid) become_setup(sfd, lockfd, fake_pair,
819                                watcher_stdin[1], watcher_stderr[0]);
820   close(fake_pair[1]);
821   close(sfd);
822
823   call_sock = call_sock_from_fd(fake_pair[0]);
824
825   int status;
826   pid_t got = waitpid(setup_pid, &status, 0);
827   if (got == (pid_t)-1) diee("waitpid setup [%ld]", (long)setup_pid);
828   if (got != setup_pid) diee("waitpid setup [%ld] gave [%ld]!",
829                              (long)setup_pid, (long)got);
830   if (status != 0) propagate_exit_status(status, "setup");
831
832   const char *emsg = read_greeting();
833   if (emsg) die("setup failed: %s", emsg);
834
835   close(lockfd);
836   return;
837 }
838
839 static void make_executor_argv(const char *const *argv) {
840   switch (mediation) {
841   case MEDIATION_UNLAUNDERED: break;
842   default: die("need -U (specifying unlaundered argument handling)");
843   }
844
845   const char *arg;
846   #define EACH_NEW_ARG(EACH) {                  \
847     arg = interp; { EACH }                      \
848     if ((arg = script)) { EACH }                \
849     const char *const *walk = argv;             \
850     while ((arg = *walk++)) { EACH }            \
851   }
852
853   size_t count = 1;
854   EACH_NEW_ARG( (void)arg; count++; );
855
856   const char **out = calloc(count, sizeof(char*));
857   executor_argv = (const char* const*)out;
858   if (!executor_argv) diee("allocate for arguments");
859
860   EACH_NEW_ARG( *out++ = arg; );
861   *out++ = 0;
862 }
863
864 int main(int argc_unused, const char *const *argv) {
865   process_opts(&argv);
866
867   // Now we have
868   //  - possibly interp
869   //  - possibly script
870   //  - remaining args
871   // which ought to be passed on to the actual executor.
872   make_executor_argv(argv);
873
874   find_socket_path();
875   FILLZERO(sockaddr_sun);
876   sockaddr_sun.sun_family = AF_UNIX;
877   assert(strlen(socket_path) <= sizeof(sockaddr_sun.sun_path));
878   strncpy(sockaddr_sun.sun_path, socket_path, sizeof(sockaddr_sun.sun_path));
879
880   connect_or_spawn();
881
882   // We're committed now, send the request (or bail out)
883   send_request();
884
885   uint32_t status;
886   protocol_read(&status, sizeof(status));
887
888   status = ntohl(status);
889   if (status > INT_MAX) die("status 0x%lx does not fit in an int",
890                             (unsigned long)status);
891
892   propagate_exit_status(status, "invocation");
893 }