chiark / gitweb /
Bump version to 7.0.2~
[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  * to amortise the startup time of a script.
5  *
6  * Usages:
7  *   prefork-interp  [<option> ..] <interpreter>  [<script> [<args> ...]]
8  *   prefork-interp  [<option>,..],<interpreter>   <script> [<args> ...]
9  *   prefork-interp '[<option> ..] <interpreter>'  <script> [<args> ...]
10  *
11  * The script must load a corresponding library (eg Proc::Prefork::Interp
12  * for Perl) and call its preform_initialisation_complete routine.
13  *
14  * Options must specify argument/environment mediation approach.
15  * Currently the only args/env mediation supported is:
16  *
17  *   -U    unlaundered: setup and executor both get all arguments and env vars
18  *         ident covers only env vars specified with -E
19  *         ident covers only two arguments: interpreter and (if present) script
20  *
21  * Options for setting the operation mode:
22  *
23  *   (none)     Default: start new server if needed, then run service
24  *   -f         Force a fresh service (old one is terminated)
25  *   --kill     Kill any existing service; do not actually run anything
26  *
27  * Options for controlling whether different invocations share a server:
28  *
29  *   -E VAR      ident includes env var VAR (or its absence)
30  *   -G STRING   ident includes string STRING
31  *   -g IDENT    use IDENT rather than hex(SHA256(... identity things ...))
32  *
33  * (Ordering of -E and -G options is relevant; invocations with different
34  * -E -G options are different even if the env var settings are the same)
35  */
36
37 /*
38 ***************************************************************************
39 \f
40   State during service execution, process parentage and key fds
41
42       CALLER
43         ||
44         ||
45         ||                               listen     watch-err/in
46         ||       call                 (accept) \     ,------2
47         || ,-----------------------------.     SERVER -----0 WATCHER(C)
48       CLIENT 2--=fdpassed>=---------.     \      || &&          |      &&
49        (C)  1--=fdpassed>=---------. \     \     ||           inotify
50            0--=fdpassed>=---------. \ \     \    ||           sockpath
51                                    \ \ \     \   ||
52                                    | | |\     |  ||
53                                    | | | \    |  ||
54                                    | \ |  \   \  ||
55                                     \ \ \  \   MONITOR &
56                                      \ \ \  `12  ||  |
57                                       \ \ \      ||  |
58                                        \ \ \     ||  |execterm
59                                         \ \ \    ||  |
60                                          \ \ \   ||  |
61                                           \ \ 2  ||  |
62                                            \ 1 EXECUTOR
63                                             0
64     ----      pipes, sockets
65     012       descriptors
66     -==-      fds shared
67     ||        process parentage
68     &&        session leader (daemon)
69     &         process group leader
70
71 ***************************************************************************
72 \f
73  Control flow and causality
74
75       CALLER
76          |
77          |fork/exec
78          |
79       CLIENT
80          |
81       attempt to connect, and read greeting
82          |failure?                \success?
83          |                         \
84       tidy up stale /run entries    *1 (continue from send_fds, below)
85       acquire lock
86          |
87       retry attempt to connect, and read greeting
88          |failure?                \success?
89          |                         \
90       create listening socket     release lock
91          |                           \
92       fork/daemonise                  *1
93          |    `------------------.
94          |                      WATCHER(C) &&
95          |
96        make "fake" initial call socketpair                               (C)
97          |                                                    prefork-interp
98        fork/exec   #########################################################
99          |      `-------------.                                  application
100          |         #        SCRIPT (setup)
101          |         #          |
102          |         #       script initialisation
103          |         #          |                                  application
104          |         ###########|#############################################
105          |         #          |                               prefork-interp
106          |         #       identify fds from envirnment               (Perl)
107          |         #       open syslog
108          |         #          |
109          |         #       dzemonize
110          |   ,.....<....../   |
111       waitpid      #        fork for initial service
112          |         #          |child?       |parent?
113          |         #          |             |
114          |         #          |         SCRIPT [server] &&
115          |         #          |             |
116          |         #          |         ** accept / event loop **
117          |         #          |        accepted?    \      \ \
118          |         #          |            /         \ watch\ \idle
119          |         #          |        fork child     \stderr\ \timeout?
120          |         #          | _________/            |       | |
121          |         #          |/                      |read?  | |
122          |         #     SCRIPT [monitor]             |   eof?| |
123          |         #       setpgrpt &                 |       | |
124          |         #          |                     log msg   | |
125        read   ,....<.....send greeting                |       | |
126       greeting     #          |                    ___________________
127          |         #          |
128       release      #          |
129       lock    *1   #          |
130          |   /     #          |
131       send fds.....>....      |
132          |         #    \receive fds
133          |         #             |
134          |         #         fork for executor                        (Perl)
135          |         #          |parent?        \child?         prefork-interp
136          |         #          |          ######\############################
137          |         #          |          #  SCRIPT (executor)    application
138          |         #          |          #  execute service
139          |         #    wait for read    #       |
140          |         #      (select)       #   terminates
141          |         #        |   |        #       |
142          |         #            |        #    kernel closes execterm
143          |         #            | ,......<....../|
144          |         #      execterm?      #       |
145          |         #            |        #     zombie
146          |         #        |   | ,......<...../
147          |         #       waitpid       #  _______________
148          |         #          |          #
149          |    ,....<....,..send status   #
150     read status    #  ________________   #
151    _____________   #
152
153
154   ********** Or, if client is killed **********
155
156          |         #          |          #  execute service
157      terminates    #    wait for read    #       |
158          |         #      (select)       #       |
159       kernel       #        |   |        #       |
160      closes call   #        |            #       |
161                 \..>......_ |            #       |
162    _____________   #       \|call?       #       |
163                    #        |            #       |
164                    #  kill whole pgrp... #    killled
165                    #        |            #     zombie
166                    #        |   | ,......<....../
167                    #       waitpid       #  _______________
168                    #          |          #
169                    #   send exit status  #
170                    #  _____SIGPIPE______ #
171
172     | - \ /    process control flow
173     ... < >    causes mediated by fds or other IPC etc.
174     &&         session leader (daemon)
175     &          process group leader
176     #          language/implementation boundary
177     *1         line continued elsewhere
178     event?     condition
179     ______     process termination (after reaping, if shown)
180
181 ***************************************************************************
182 \f
183   Sequence of events and fd pluming.
184   NB INCOMPLETE - does not cover execterm, cleanup
185  
186    client (C wrapper)        connects to server
187                                (including reading ack byte)
188                              if fails or garbage
189                              === acquires lock ===
190                              makes new listening socket
191                              makes watcher pipes
192                              forks watcher and awaits
193                              makes first-instance socketpair
194                              forks setup (script, sock fds indicated in env)
195                              fd0, fd1, fd2: from-outer
196                              other fd: call(client-end)(fake)
197                              reaps setup (and reports error)
198                              (implicitly releases lock)
199  
200       watcher                fd[012]: watcher pipes
201                              starts watch on socket path
202                              sets stderr to line buffered
203                              sets stdin to nonblocking
204                              daemonises (one fork, becomes session leader)
205                              when socket stat changes, quit
206  
207       setup (pre-exec)       fd0: null,
208                              fd[12]: fd2-from-outer
209                              env fds: listener, call(server-end)(fake),
210                                        watcher read, watcher write
211                              close fd: lockfile
212                              possibly clean env, argv
213  
214       setup (script)         runs initialisation parts of the script
215                              at prefork establishment point:
216       setup (pm) [1]         opens syslog
217                              forks for server
218                  [2]         exits
219  
220          server (pm) [1]     [fd0: null],
221                              [fd[12]: fd2-from-outer]
222                              setsid
223                              right away, forks init monitor
224                      [2]     closes outer caller fds and call(fake)
225          [server (pm)]       fd[012]: null
226                              other fds: listener, syslog
227                              runs in loop accepting and forking,
228                              reaping and limiting children (incl init monitor)
229                              reports failures of monitors to syslog
230  
231    [client (C wrapper)]      if client connect succeeds:
232                              now fd: call(client-end)
233                                 sends message with: cmdline, env
234                                 sends fds
235  
236          [server (script)]   accepts, forks subseq monitor
237  
238            monitor [1]       [fd0: null]
239             (init            [fd[12]: init: fd2-from-outer; subseq: null]
240               or             errors: init: fd2; subseq: syslog
241              subseq)         other fds: syslog, call(server-end)
242                              sends ack byte
243                              receives args, env, fds
244                              forks executor
245  
246              executor        sorts out fds:
247                              fd0, fd1, fd2: from-outer
248                              close fds: call(server-end)
249                              retained fds: syslog
250  
251                              sets cmdline, env
252                              runs main part of script
253                              exits normally
254  
255            [monitor]         [fd[012]: null]
256                              [fd[12]: init: fd2-from-outer; subseq: null]
257                              [errors: init: fd2; subseq: syslog]
258                              reaps executor
259                              reports status via socket
260  
261      [client (C wrapper)]    [fd0, fd1, fd2: from-outer]
262                              [other fd: call(client-end)]
263                              receives status, exits appropriately
264                              (if was bad signal, reports to stderr, exits 127)
265
266 ***************************************************************************
267 \f
268   Protocol, and functions of the script
269
270   1. Script interpreter will be spawned apparently as normal;
271      should run synchronously in the normal way until
272      "initialisation complete" point.  At initialisation complete:
273
274   2. Env var PREFORK_INTERP contains:
275
276          v1,SECS.NSECS[,...] LISTEN,CALL,WATCHE,WATCHI[,...][ ???]
277
278      To parse it: treat as bytes and split on ASCII space, taking
279      the first two words.  (There may or may not be
280      further "words"; and if there are they might be binary data.)
281      Then split each of the first two words (which will contain only
282      ASCII printing characters) on comma.  Take the first two items:
283
284         v1    Protocol version indicator - literal.  If something else,
285               fail (means installation is incompatible somehow).
286
287         SECS.NSECS
288               timestamp just before script started running, as a
289               decimal time_t.  NSECS is exactly 9 digits.
290               To be used for auto reloading (see below).
291
292      The 2nd word's items are file descriptors:
293
294         LISTEN   listening socket                 nonblocking
295         CALL     call socket for initial call     blocking
296         WATCHE   liveness watcher stderr          nonblocking
297         WATCHI   liveness sentinel                unspecified
298
299         (any further descriptors should be ignored, not closed)
300
301   3. Library should do the following:
302
303      1. Read and understand the PREFORK_INTERP env var.
304         If it is not set, initialisation complete should simply return.
305         (This allows simple synchronous operation.)
306
307      2. Open syslog
308      3. fork/exit (fork and have parent exit) (to make server)
309      4. setsid (to become session leader)
310      5. fork initial service (monitor) child, using CALL (see below)
311      6. Replace stdin/stdout/stderr with /dev/null,
312         and make a note to send all error messages to syslog
313      7. Enter select loop, looking for the following:
314
315         A. accept on LISTEN:
316             i. see if we need to reload: is any file forming part
317                of the program newer than the SECS.NSECS ?
318                If so, log at LOG_INFO, and exit immediately
319                (dropping CALL, LISTEN, WATCHI, etc.)
320             ii. see if we can reap any children, possibly waiting
321                for children if we are at our concurrency limit
322                (limit should be configured through library, default 4)
323                Report child exit status if not zero or SIGPIPE.
324             iii. fork service (monitor) child, using accepted fd
325
326         B. WATCHE is readable:
327             * EOF: log at LOG_INFO, and exit
328             * data to read: read what is available immediately;
329               it will be an error message: log it at LOG_ERR, and exit
330
331   4. service (monitor) child does the following:
332
333       1. close all of LISTEN, WATCHI, WATCHE
334       2. setpgrp
335       3. send a greeting (on CALL) "PFI\n\0\0\0\0" (8 bytes)
336       4. read a single byte, fail if it's not zero
337       5. three times, receive a single byte with a file descriptor
338          attached as ancillary data.  (These descriptors will be
339          service stdin, stdout, stderr.)
340       6. read a 4-byte big-endian length
341       7. read that many bytes, the initial service request message,
342          which contains the following nul-terminated strings:
343             * environment variable settings in the format NAME=value
344             * an empty string
345             * arguments NOT INCLUDING argv[0] or script filename
346          (not that this means the service request must end in a nul)
347       8. make a new pipe EXECTERM
348       9. fork for the service executor; in the child
349             i. redirect stdin/stdout/stderr to the recevied fds
350             ii. replace environment and arguments with those received,
351             iii. close descriptors: close the original received descriptors;
352                  close CALL; keep only the writing end of EXECTERM
353             iv. if the script programming language does things with SIGINT,
354                 set it set back to default handling (immediate termination).
355             v. return back to script, now in the grandchild
356
357       10. in the parent, close EXECTERM writing end, and
358       11. select, looking for one of the following:
359            * CALL is readable
360            * EXECTERM reading end is readable
361           No need to actually read, since these shouldn't produce
362           spurious wakeups (but do loop on EINTR).
363       12. set SIGINT to ignored
364       13. send SIGINT to the entire process group
365       14. wait, blocking, for the executor child
366       15. write the wait status, in 32-bit big-endian, to CAL
367       16. exit 0
368
369      Errors detected in the service monitor should be sent to
370      syslog, or stderr, depending on whether this is the initial
371      service monitor (from part 3 step 5) or an accepted socket
372      service monitor (from part 4 step 9); this can be achieved
373      easily by having a global flag (set at part 3 step 6),
374      or perhaps using logger(8) and redirecting stderr (but
375      then be careful to ensure everyone gets only the necessary fds).
376
377      EOF on CALL, or EPIPE/SIGPIPE writing to it, are not errors.
378      In this case, exit zero or die with SIGPIPE, so parent
379      won't report error either (part 3 step 7(A)(ii)).
380
381 ***************************************************************************
382 \f
383 */
384
385 #include <arpa/inet.h>
386 #include <sys/utsname.h>
387
388 #include <uv.h>
389
390 #include "prefork.h"
391
392 const char our_name[] = "prefork-interp";
393
394 static struct sockaddr_un sockaddr_sun;
395 static FILE *call_sock;
396
397 #define ACK_BYTE '\n'
398
399 static const char *const *executor_argv;
400
401 static const char header_magic[4] = "PFI\n";
402
403 void fusagemessage(FILE *f) {
404   fprintf(f, "usage: #!/usr/bin/prefork-interp [<options>]\n");
405 }
406
407 #define MODE_NORMAL 0
408 #define MODE_KILL   'k'
409 #define MODE_FRESH  'f'
410
411 #define MEDIATION_UNSPECIFIED 0
412 #define MEDIATION_UNLAUNDERED 'U'
413
414 static int mediation = MEDIATION_UNSPECIFIED;
415 static int mode = MODE_NORMAL;
416 static int max_sockets = 100; // maximum entries in the run dir is 2x this
417
418 static struct stat initial_stab;
419
420 const struct cmdinfo cmdinfos[]= {
421   PREFORK_CMDINFOS
422   { 0,         'U',   0, .iassignto= &mediation, .arg= MEDIATION_UNLAUNDERED },
423   { "kill",     0,    0, .iassignto= &mode,      .arg= MODE_KILL   },
424   { 0,         'f',   0, .iassignto= &mode,      .arg= MODE_FRESH  },
425   { 0 }
426 };
427
428 static void ident_add_stat(const char *path) {
429   struct stat stab;
430   int r = stat(path, &stab);
431   if (r) diee("failed to stat %s", path);
432
433   IDENT_ADD_OBJ(path[0], stab.st_dev);
434   IDENT_ADD_OBJ('i',     stab.st_ino);
435 }
436
437 void ident_addinit(void) {
438   ident_add_key_byte(1);
439
440   struct utsname uts = { };
441   size_t utslen = sizeof(uts);
442   int r = uname(&uts);
443   if (r) diee("uname failed!");
444   IDENT_ADD_OBJ('u', utslen);
445   IDENT_ADD_OBJ('u', uts);
446
447   ident_add_stat(".");
448   ident_add_stat("/");
449 }
450
451 static void propagate_exit_status(int status, const char *what) {
452   int r;
453
454   if (WIFEXITED(status)) {
455     _exit(WEXITSTATUS(status));
456   }
457
458   if (WIFSIGNALED(status)) {
459     int sig = WTERMSIG(status);
460     const char *signame = strsignal(sig);
461     if (signame == 0) signame = "unknown signal";
462
463     if (! WCOREDUMP(status) &&
464         (sig == SIGINT ||
465          sig == SIGTERM ||
466          sig == SIGHUP ||
467          sig == SIGPIPE ||
468          sig == SIGKILL)) {
469       struct sigaction sa;
470       FILLZERO(sa);
471       sa.sa_handler = SIG_DFL;
472       if (sig != SIGKILL) {
473         r = sigaction(sig, &sa, 0);
474         if (r) diee("failed to reset signal handler while propagating %s",
475                     signame);
476
477         sigset_t sset;
478         sigemptyset(&sset);
479         sigaddset(&sset, sig);
480         r = sigprocmask(SIG_UNBLOCK, &sset, 0);
481         if (r) diee("failed to reset signal block while propagating %s",
482                     signame);
483       }
484
485       raise(sig);
486       die("unexpectedly kept running after raising (to propagate) %s",
487           signame);
488     }
489
490     die("%s failed due to signal %d %s%s", what, sig, signame,
491         WCOREDUMP(status) ? " (core dumped)" : "");
492   }
493
494   die("%s failed with weird wait status %d 0x%x", what, status, status);
495 }
496
497 typedef struct {
498   char *name_hash;
499   time_t atime;
500 } PrecleanEntry;
501
502 static int preclean_entry_compar_name(const void *av, const void *bv) {
503   const PrecleanEntry *a = av;
504   const PrecleanEntry *b = bv;
505   return strcmp(a->name_hash, b->name_hash);
506 }
507
508 static int preclean_entry_compar_atime(const void *av, const void *bv) {
509   const PrecleanEntry *ae = av;  time_t a = ae->atime;
510   const PrecleanEntry *be = bv;  time_t b = be->atime;
511   return (a > b ? +1 :
512           a < b ? -1 : 0);
513 }
514
515 static time_t preclean_stat_atime(const char *s_path) {
516   struct stat stab;
517   int r= lstat(s_path, &stab);
518   if (r) {
519     if (errno!=ENOENT) diee("pre-cleanup: stat socket (%s)", s_path);
520     return 0;
521   }
522   return stab.st_atime;
523 }
524
525 static void preclean(void) {
526   DIR *dir = opendir(run_base);
527   if (!dir) {
528     if (errno == ENOENT) return;
529     diee("pre-cleanup: open run dir (%s)", run_base);
530   }
531
532   PrecleanEntry *entries=0;
533   size_t avail_entries=0;
534   size_t used_entries=0;
535
536   struct dirent *de;
537   while ((errno = 0, de = readdir(dir))) {
538     char c0 = de->d_name[0];
539     if (!(c0 == 'l' || c0 == 's')) continue;
540     char *name_hash = m_asprintf("%s", de->d_name+1);
541     char *s_path = m_asprintf("%s/s%s", run_base, name_hash);
542     time_t atime = preclean_stat_atime(s_path);
543
544     if (avail_entries == used_entries) {
545       assert(avail_entries < INT_MAX / 4 / sizeof(PrecleanEntry));
546       avail_entries <<= 1;
547       avail_entries += 10;
548       entries = realloc(entries, avail_entries * sizeof(PrecleanEntry));
549     }
550     entries[used_entries].name_hash = name_hash;
551     entries[used_entries].atime = atime;
552     used_entries++;
553   }
554   if (errno) diee("pre-cleanup: read run dir (%s)", run_base);
555
556   // First we dedupe (after sorting by path)
557   qsort(entries, used_entries, sizeof(PrecleanEntry),
558         preclean_entry_compar_name);
559   PrecleanEntry *p, *q;
560   for (p=entries, q=entries; p < entries + used_entries; p++) {
561     if (q > entries && !strcmp(p->name_hash, (q-1)->name_hash))
562       continue;
563     *q++ = *p;
564   }
565   used_entries = q - entries;
566
567   // Now maybe delete some things
568   //
569   // Actually this has an off-by-one error since we are about
570   // to create a socket, so the actual number of sockets is one more.
571   // But, *actually*, since there might be multiple of us running at once,
572   // we might have even more than that.  This doesn't really matter.
573   if (used_entries > max_sockets) {
574     qsort(entries, used_entries, sizeof(PrecleanEntry),
575           preclean_entry_compar_atime);
576     for (p=entries; p < entries + max_sockets; p++) {
577       char *l_path = m_asprintf("%s/l%s", run_base, p->name_hash);
578       char *s_path = m_asprintf("%s/s%s", run_base, p->name_hash);
579       int lock_fd = flock_file(l_path);
580       // Recheck atime - we might have raced!
581       time_t atime = preclean_stat_atime(s_path);
582       if (atime != p->atime) {
583         // Raced.  This will leave use deleting too few things.  Whatever.
584       } else {
585         int r= unlink(s_path);
586         if (r && errno!=ENOENT) diee("preclean: delete stale (%s)", s_path);
587         r= unlink(l_path);
588         if (r) diee("preclean: delete stale lock (%s)", s_path);
589         // NB we don't hold the lock any more now.
590       }
591       close(lock_fd);
592       free(l_path);
593       free(s_path);
594     }
595   }
596
597   for (p=entries; p < entries + used_entries; p++)
598     free(p->name_hash);
599   free(entries);
600 }
601
602 static __attribute((noreturn)) void die_data_overflow(void) {
603   die("cannot handle data with length >2^32");
604 }
605
606 static void prepare_data(size_t *len, char **buf,
607                          const void *data, size_t dl) {
608   if (len) {
609     if (dl >= SIZE_MAX - *len)
610       die_data_overflow();
611     *len += dl;
612   }
613   if (buf) {
614     memcpy(*buf, data, dl);
615     *buf += dl;
616   }
617 }
618
619 static void prepare_length(size_t *len, char **buf, size_t dl_sz) {
620   if (dl_sz > UINT32_MAX) die_data_overflow();
621   uint32_t dl = htonl(dl_sz);
622   prepare_data(len, buf, &dl, sizeof(dl));
623 }
624
625 static void prepare_string(size_t *len, char **buf, const char *s) {
626   size_t sl = strlen(s);
627   prepare_data(len, buf, s, sl+1);
628 }
629
630 static void prepare_message(size_t *len, char **buf) {
631   const char *s;
632
633   const char *const *p = (void*)environ;
634   while ((s = *p++)) {
635     if (strchr(s, '='))
636       prepare_string(len, buf, s);
637   }
638
639   prepare_string(len, buf, "");
640
641   p = executor_argv;
642   while ((s = *p++))
643     prepare_string(len, buf, s);
644 }
645
646 static void send_fd(int payload_fd) {
647   int via_fd = fileno(call_sock);
648
649   union {
650     struct cmsghdr align;
651     char buf[CMSG_SPACE(sizeof(payload_fd))];
652   } cmsg_buf;
653
654   struct msghdr msg;
655   FILLZERO(msg);
656   FILLZERO(cmsg_buf);
657
658   char dummy_byte = 0;
659   struct iovec iov;
660   FILLZERO(iov);
661   iov.iov_base = &dummy_byte;
662   iov.iov_len = 1;
663
664   msg.msg_name = 0;
665   msg.msg_iov = &iov;
666   msg.msg_iovlen = 1;
667   msg.msg_control = cmsg_buf.buf;
668   msg.msg_controllen = sizeof(cmsg_buf.buf);
669
670   struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
671   cmsg->cmsg_level = SOL_SOCKET;
672   cmsg->cmsg_type = SCM_RIGHTS;
673   cmsg->cmsg_len = CMSG_LEN(sizeof(payload_fd));
674   *(int*)CMSG_DATA(cmsg) = payload_fd;
675
676   msg.msg_controllen = sizeof(cmsg_buf.buf);
677
678   for (;;) {
679     ssize_t r = sendmsg(via_fd, &msg, 0);
680     if (r == -1) {
681       if (errno == EINTR) continue;
682       diee("send fd");
683     }
684     assert(r == 1);
685     break;
686   }
687 }
688
689 static void send_request(void) {
690   char ibyte= 0;
691   ssize_t sr = fwrite(&ibyte, 1, 1, call_sock);
692   if (sr != 1) diee("write signalling byte");
693
694   // Sending these before the big message makes it easier for the script to
695   // use buffered IO for the message.
696   send_fd(0);
697   send_fd(1);
698   send_fd(2);
699
700   size_t len = 0;
701   prepare_message(&len, 0);
702
703   size_t tlen = len + 4;
704   char *m = xmalloc(tlen);
705   char *p = m;
706   prepare_length(0, &p, len);
707   prepare_message(0, &p);
708   assert(p == m + tlen);
709
710   sr = fwrite(m, tlen, 1, call_sock);
711   if (sr != 1) diee("write request (buffer)");
712
713   if (fflush(call_sock)) diee("write request");
714 }
715
716 static FILE *call_sock_from_fd(int fd) {
717   int r;
718
719   FILE *call_sock = fdopen(fd, "r+");
720   if (!call_sock) diee("fdopen socket");
721
722   r = setvbuf(call_sock, 0, _IONBF, 0);
723   if (r) die("setvbuf socket");
724
725   return call_sock;
726 }
727
728 static bool was_eof(FILE *call_sock) {
729   return feof(call_sock) || errno==ECONNRESET;
730 }
731
732 // Returns -1 on EOF
733 static int protocol_read_maybe(void *data, size_t sz) {
734   if (!sz) return 0;
735   size_t sr = fread(data, sz, 1, call_sock);
736   if (sr != 1) {
737     if (was_eof(call_sock)) return -1;
738     diee("read() on monitor call socket (%zd)", sz);
739   }
740   return 0;
741 }
742
743 static void protocol_read(void *data, size_t sz) {
744   if (protocol_read_maybe(data, sz) < 0)
745     die("monitor process quit unexpectedly");
746 }
747
748 // Returns 0 if OK, error msg if peer was garbage.
749 static const char *read_greeting(void) {
750   char got_magic[sizeof(header_magic)];
751
752   if (protocol_read_maybe(&got_magic, sizeof(got_magic)) < 0)
753     return "initial monitor process quit"
754       " (maybe script didn't call preform_initialisation_complete?)";
755
756   if (memcmp(got_magic, header_magic, sizeof(header_magic)))
757     die("got unexpected protocol magic 0x%02x%02x%02x%02x",
758         got_magic[0], got_magic[1], got_magic[2], got_magic[3]);
759
760   uint32_t xdata_len;
761   protocol_read(&xdata_len, sizeof(xdata_len));
762   void *xdata = xmalloc(xdata_len);
763   protocol_read(xdata, xdata_len);
764
765   return 0;
766 }
767
768 // Returns: call(client-end), or 0 to mean "is garbage"
769 // find_socket_path must have been called
770 static FILE *connect_existing(void) {
771   int r;
772   int fd = -1;
773
774   if (mode != MODE_NORMAL) return 0;
775
776   fd = socket(AF_UNIX, SOCK_STREAM, 0);
777   if (fd==-1) diee("socket() for client");
778
779   socklen_t salen = sizeof(sockaddr_sun);
780   r = connect(fd, (const struct sockaddr*)&sockaddr_sun, salen);
781   if (r==-1) {
782     if (errno==ECONNREFUSED || errno==ENOENT) goto x_garbage;
783     diee("connect() %s", socket_path);
784   }
785
786   call_sock = call_sock_from_fd(fd);
787   fd = -1;
788
789   if (read_greeting())
790     goto x_garbage;
791
792   return call_sock;
793
794  x_garbage:
795   if (call_sock) { fclose(call_sock); call_sock=0; }
796   if (fd >= 0) close(fd);
797   return 0;
798 }
799
800 static void watcher_cb_stdin(uv_poll_t *handle, int status, int events) {
801   char c;
802   int r;
803
804   if ((errno = -status)) diee("watcher: poll stdin");
805   for (;;) {
806     r= read(0, &c, 1);
807     if (r!=-1) _exit(0);
808     if (!(errno==EINTR || errno==EWOULDBLOCK || errno==EAGAIN))
809       diee("watcher: read sentinel stdin");
810   }
811 }
812
813 static void watcher_cb_sockpath(uv_fs_event_t *handle, const char *filename,
814                                 int events, int status) {
815   int r;
816   struct stat now_stab;
817
818   if ((errno = -status)) diee("watcher: poll stdin");
819   for (;;) {
820     r= stat(socket_path, &now_stab);
821     if (r==-1) {
822       if (errno==ENOENT) _exit(0);
823       if (errno==EINTR) continue;
824       diee("stat socket: %s", socket_path);
825     }
826     if (!stabs_same_inode(&now_stab, &initial_stab))
827       _exit(0);
828   }
829 }
830
831 // On entry, stderr is still inherited, but 0 and 1 are the pipes
832 static __attribute__((noreturn))
833 void become_watcher(void) {
834   uv_loop_t loop;
835   uv_poll_t uvhandle_stdin;
836   uv_fs_event_t uvhandle_sockpath;
837   int r;
838
839   nonblock(0);
840
841   errno= -uv_loop_init(&loop);
842   if (errno) diee("watcher: uv_loop_init");
843
844   errno= -uv_poll_init(&loop, &uvhandle_stdin, 0);
845   if (errno) diee("watcher: uv_poll_init");
846   errno= -uv_poll_start(&uvhandle_stdin,
847                         UV_READABLE | UV_WRITABLE | UV_DISCONNECT,
848                         watcher_cb_stdin);
849   if (errno) diee("watcher: uv_poll_start");
850
851   errno= -uv_fs_event_init(&loop, &uvhandle_sockpath);
852   if (errno) diee("watcher: uv_fs_event_init");
853
854   errno= -uv_fs_event_start(&uvhandle_sockpath, watcher_cb_sockpath,
855                             socket_path, 0);
856   if (errno) diee("watcher: uv_fs_event_start");
857
858   // OK everything is set up, let us daemonise
859   if (dup2(1,2) != 2) diee("watcher: set daemonised stderr");
860   r= setvbuf(stderr, 0, _IOLBF, BUFSIZ);
861   if (r) diee("watcher: setvbuf stderr");
862
863   pid_t child = fork();
864   if (child == (pid_t)-1) diee("watcher: fork");
865   if (child) _exit(0);
866
867   if (setsid() == (pid_t)-1) diee("watcher: setsid");
868
869   r= uv_run(&loop, UV_RUN_DEFAULT);
870   die("uv_run returned (%d)", r);
871 }
872
873 static __attribute__((noreturn))
874 void become_setup(int sfd, int lockfd, int fake_pair[2],
875                   int watcher_stdin, int watcher_stderr) {
876   close(lockfd);
877   close(fake_pair[0]);
878   int call_fd = fake_pair[1];
879
880   int null_0 = open("/dev/null", O_RDONLY);  if (null_0 < 0) diee("open null");
881   if (dup2(null_0, 0)) diee("dup2 /dev/null onto stdin");
882   close(null_0);
883   if (dup2(2, 1) != 1) die("dup2 stderr onto stdout");
884
885   nonblock(sfd);
886
887   // Extension could work like this:
888   //
889   // We could advertise a new protocol (perhaps one which is nearly entirely
890   // different after the connect) by putting a name for it comma-separated
891   // next to "v1".  Simple extension can be done by having the script
892   // side say something about it in the ack xdata, which we currently ignore.
893   // Or we could add other extra data after v1.
894   putenv(m_asprintf("PREFORK_INTERP=v1,%jd.%09ld %d,%d,%d,%d",
895                     (intmax_t)initial_stab.st_mtim.tv_sec,
896                     (long)initial_stab.st_mtim.tv_nsec,
897                     sfd, call_fd, watcher_stdin, watcher_stderr));
898
899   execvp(executor_argv[0], (char**)executor_argv);
900   diee("execute %s", executor_argv[0]);
901 }
902
903 static void connect_or_spawn(void) {
904   int r;
905
906   call_sock = connect_existing();
907   if (call_sock) return;
908
909   // We're going to make a new one, so clean out old ones
910   preclean();
911
912   int lockfd = acquire_lock();
913
914   if (mode == MODE_KILL) {
915     r= unlink(socket_path);
916     if (r && errno != ENOENT) diee("remove socket %s", socket_path);
917
918     r= unlink(lock_path);
919     if (r) diee("rmeove lock %s", lock_path);
920     _exit(0);
921   }
922
923   call_sock = connect_existing();
924   if (call_sock) { close(lockfd); return; }
925
926   // We must start a fresh one, and we hold the lock
927
928   r = unlink(socket_path);
929   if (r<0 && errno!=ENOENT)
930     diee("failed to remove stale socket %s", socket_path);
931
932   int sfd = socket(AF_UNIX, SOCK_STREAM, 0);
933   if (sfd<0) diee("socket() for new listener");
934
935   socklen_t salen = sizeof(sockaddr_sun);
936   r= bind(sfd, (const struct sockaddr*)&sockaddr_sun, salen);
937   if (r<0) diee("bind() on new listener");
938
939   r= stat(socket_path, &initial_stab);
940   if (r<0) diee("stat() fresh socket");
941
942   // We never want callers to get ECONNREFUSED.  But:
943   // There is a race here: from my RTFM they may get ECONNREFUSED
944   // if they try between our bind() and listen().  But if they do, they'll
945   // acquire the lock (serialising with us) and retry, and then it will work.
946   r = listen(sfd, INT_MAX);
947   if (r<0) diee("listen() for new listener");
948
949   // Fork watcher
950
951   int watcher_stdin[2];
952   int watcher_stderr[2];
953   if (pipe(watcher_stdin) || pipe(watcher_stderr))
954     diee("pipe() for socket inode watcher");
955
956   pid_t watcher = fork();
957   if (watcher == (pid_t)-1) diee("fork for watcher");
958   if (!watcher) {
959     close(sfd);
960     close(lockfd);
961     close(watcher_stdin[1]);
962     close(watcher_stderr[0]);
963     if (dup2(watcher_stdin[0], 0) != 0 ||
964         dup2(watcher_stderr[1], 1) != 1)
965       diee("initial dup2() for watcher");
966     close(watcher_stdin[0]);
967     close(watcher_stderr[1]);
968     become_watcher();
969   }
970
971   close(watcher_stdin[0]);
972   close(watcher_stderr[1]);
973   nonblock(watcher_stderr[0]);
974
975   // Fork setup
976
977   int fake_pair[2];
978   r = socketpair(AF_UNIX, SOCK_STREAM, 0, fake_pair);
979   if (r<0) diee("socketpair() for fake initial connection");
980
981   pid_t setup_pid = fork();
982   if (setup_pid == (pid_t)-1) diee("fork for spawn setup");
983   if (!setup_pid) become_setup(sfd, lockfd, fake_pair,
984                                watcher_stdin[1], watcher_stderr[0]);
985   close(fake_pair[1]);
986   close(sfd);
987
988   call_sock = call_sock_from_fd(fake_pair[0]);
989
990   int status;
991   pid_t got = waitpid(setup_pid, &status, 0);
992   if (got == (pid_t)-1) diee("waitpid setup [%ld]", (long)setup_pid);
993   if (got != setup_pid) diee("waitpid setup [%ld] gave [%ld]!",
994                              (long)setup_pid, (long)got);
995   if (status != 0) propagate_exit_status(status, "setup");
996
997   const char *emsg = read_greeting();
998   if (emsg) die("setup failed: %s", emsg);
999
1000   close(lockfd);
1001   return;
1002 }
1003
1004 static void make_executor_argv(const char *const *argv) {
1005   switch (mediation) {
1006   case MEDIATION_UNLAUNDERED: break;
1007   default: die("need -U (specifying unlaundered argument handling)");
1008   }
1009
1010   const char *arg;
1011   #define EACH_NEW_ARG(EACH) {                  \
1012     arg = interp; { EACH }                      \
1013     if ((arg = script)) { EACH }                \
1014     const char *const *walk = argv;             \
1015     while ((arg = *walk++)) { EACH }            \
1016   }
1017
1018   size_t count = 1;
1019   EACH_NEW_ARG( (void)arg; count++; );
1020
1021   const char **out = calloc(count, sizeof(char*));
1022   executor_argv = (const char* const*)out;
1023   if (!executor_argv) diee("allocate for arguments");
1024
1025   EACH_NEW_ARG( *out++ = arg; );
1026   *out++ = 0;
1027 }
1028
1029 int main(int argc_unused, const char *const *argv) {
1030   process_opts(&argv);
1031
1032   // Now we have
1033   //  - possibly interp
1034   //  - possibly script
1035   //  - remaining args
1036   // which ought to be passed on to the actual executor.
1037   make_executor_argv(argv);
1038
1039   find_socket_path();
1040   FILLZERO(sockaddr_sun);
1041   sockaddr_sun.sun_family = AF_UNIX;
1042   assert(strlen(socket_path) <= sizeof(sockaddr_sun.sun_path));
1043   strncpy(sockaddr_sun.sun_path, socket_path, sizeof(sockaddr_sun.sun_path));
1044
1045   connect_or_spawn();
1046
1047   // We're committed now, send the request (or bail out)
1048   send_request();
1049
1050   uint32_t status;
1051   protocol_read(&status, sizeof(status));
1052
1053   status = ntohl(status);
1054   if (status > INT_MAX) die("status 0x%lx does not fit in an int",
1055                             (unsigned long)status);
1056
1057   propagate_exit_status(status, "invocation");
1058 }