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