2 * "Interpreter" that you can put in #! like this
3 * #!/usr/bin/prefork-interp [<options>] <interpreter>
6 * prefork-interp [<option> ..] <interpreter> [<script> [<args> ...]]
7 * prefork-interp [<option>,..],<interpreter> <script> [<args> ...]
8 * prefork-interp '[<option> ..] <interpreter>' <script> [<args> ...]
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
18 ***************************************************************************
20 State during service execution, process parentage and key fds
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
48 && session leader (daemon)
49 & process group leader
51 ***************************************************************************
53 Control flow and causality
61 attempt to connect, and read greeting
64 tidy up stale /run entries *1 (continue from send_fds, below)
67 retry attempt to connect, and read greeting
70 create listening socket release lock
73 | `------------------.
76 make "fake" initial call socketpair (C)
78 fork/exec #########################################################
79 | `-------------. application
82 | # script initialisation
84 | ###########|#############################################
86 | # identify fds from envirnment (Perl)
91 waitpid # fork for initial service
94 | # | SCRIPT [server] &&
96 | # | ** accept / event loop **
98 | # | / \ watch\ \idle
99 | # | fork child \stderr\ \timeout?
100 | # | _________/ | | |
102 | # SCRIPT [monitor] | eof?| |
105 read ,....<.....send greeting | | |
106 greeting # | ___________________
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
122 | # | # kernel closes execterm
123 | # | ,......<....../|
126 | # | | ,......<...../
127 | # waitpid # _______________
129 | ,....<....,..send status #
130 read status # ________________ #
134 ********** Or, if client is killed **********
136 | # | # execute service
137 terminates # wait for read # |
142 _____________ # \|call? # |
144 # kill whole pgrp... # killled
146 # | | ,......<....../
147 # waitpid # _______________
150 # _____SIGPIPE______ #
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
159 ______ process termination (after reaping, if shown)
161 ***************************************************************************
163 Sequence of events and fd pluming.
164 NB INCOMPLETE - does not cover execterm, cleanup
166 client (C wrapper) connects to server
167 (including reading ack byte)
169 === acquires lock ===
170 makes new listening socket
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)
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
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
192 possibly clean env, argv
194 setup (script) runs initialisation parts of the script
195 at prefork establishment point:
196 setup (pm) [1] opens syslog
200 server (pm) [1] [fd0: null],
201 [fd[12]: fd2-from-outer]
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
211 [client (C wrapper)] if client connect succeeds:
212 now fd: call(client-end)
213 sends message with: cmdline, env
216 [server (script)] accepts, forks subseq monitor
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)
223 receives args, env, fds
226 executor sorts out fds:
227 fd0, fd1, fd2: from-outer
228 close fds: call(server-end)
232 runs main part of script
235 [monitor] [fd[012]: null]
236 [fd[12]: init: fd2-from-outer; subseq: null]
237 [errors: init: fd2; subseq: syslog]
239 reports status via socket
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)
246 ***************************************************************************
248 Protocol, and functions of the script
250 1. Script interpreter will be spawned apparently as normal;
251 should run synchronously in the normal way until
252 "initialisation complete" point. At initialisation complete:
254 2. Env var PREFORK_INTERP contains:
256 v1,SECS.NSECS[,...] LISTEN,CALL,WATCHE,WATCHI[,...][ ???]
258 To parse it: treat as bytes and split on ASCII space, taking
259 the first two words. (There may or may not be
260 further "words"; and if there are they might be binary data.)
261 Then split each of the first two words (which will contain only
262 ASCII printing characters) on comma. Take the first two items:
264 v1 Protocol version indicator - literal. If something else,
265 fail (means installation is incompatible somehow).
268 timestamp just before script started running, as a
269 decimal time_t. NSECS is exactly 9 digits.
270 To be used for auto reloading (see below).
272 The 2nd word's items are file descriptors:
274 LISTEN listening socket nonblocking
275 CALL call socket for initial call blocking
276 WATCHE liveness watcher stderr nonblocking
277 WATCHI liveness sentinel unspecified
279 (any further descriptors should be ignored, not closed)
281 3. Library should do the following:
283 1. Read and understand the PREFORK_INTERP env var.
284 If it is not set, initialisation complete should simply return.
285 (This allows simple synchronous operation.)
288 3. fork/exit (fork and have parent exit) (to make server)
289 4. setsid (to become session leader)
290 5. fork initial service (monitor) child, using CALL (see below)
291 6. Replace stdin/stdout/stderr with /dev/null,
292 and make a note to send all error messages to syslog
293 7. Enter select loop, looking for the following:
296 i. see if we need to reload: is any file forming part
297 of the program newer than the SECS.NSECS ?
298 If so, log at LOG_INFO, and exit immediately
299 (dropping CALL, LISTEN, WATCHI, etc.)
300 ii. see if we can reap any children, possibly waiting
301 for children if we are at our concurrency limit
302 (limit should be configured through library, default 4)
303 Report child exit status if not zero or SIGPIPE.
304 iii. fork service (monitor) child, using accepted fd
306 B. WATCHE is readable:
307 * EOF: log at LOG_INFO, and exit
308 * data to read: read what is available immediately;
309 it will be an error message: log it at LOG_ERR, and exit
311 4. service (monitor) child does the following:
313 1. close all of LISTEN, WATCHI, WATCHE
315 3. send a greeting (on CALL) "PFI\n\0\0\0\0" (8 bytes)
316 4. read a single byte, fail if it's not zero
317 5. three times, receive a single byte with a file descriptor
318 attached as ancillary data. (These descriptors will be
319 service stdin, stdout, stderr.)
320 6. read a 4-byte big-endian length
321 7. read that many bytes, the initial service request message,
322 which contains the following nul-terminated strings:
323 * environment variable settings in the format NAME=value
325 * arguments NOT INCLUDING argv[0] or script filename
326 (not that this means the service request must end in a nul)
327 8. make a new pipe EXECTERM
328 9. fork for the service executor; in the child
329 i. redirect stdin/stdout/stderr to the recevied fds
330 ii. replace environment and arguments with those received,
331 iii. close descriptors: close the original received descriptors;
332 close CALL; keep only the writing end of EXECTERM
333 iv. if the script programming language does things with SIGINT,
334 set it set back to default handling (immediate termination).
335 v. return back to script, now in the grandchild
337 10. in the parent, close EXECTERM writing end, and
338 11. select, looking for one of the following:
340 * EXECTERM reading end is readable
341 No need to actually read, since these shouldn't produce
342 spurious wakeups (but do loop on EINTR).
343 12. set SIGINT to ignored
344 13. send SIGINT to the entire process group
345 14. wait, blocking, for the executor child
346 15. write the wait status, in 32-bit big-endian, to CAL
349 Errors detected in the service monitor should be sent to
350 syslog, or stderr, depending on whether this is the initial
351 service monitor (from part 3 step 5) or an accepted socket
352 service monitor (from part 4 step 9); this can be achieved
353 easily by having a global flag (set at part 3 step 6),
354 or perhaps using logger(8) and redirecting stderr (but
355 then be careful to ensure everyone gets only the necessary fds).
357 EOF on CALL, or EPIPE/SIGPIPE writing to it, are not errors.
358 In this case, exit zero or die with SIGPIPE, so parent
359 won't report error either (part 3 step 7(A)(ii)).
361 ***************************************************************************
365 #include <arpa/inet.h>
371 const char our_name[] = "prefork-interp";
373 static struct sockaddr_un sockaddr_sun;
374 static FILE *call_sock;
376 #define ACK_BYTE '\n'
378 static const char *const *executor_argv;
380 static const char header_magic[4] = "PFI\n";
382 void fusagemessage(FILE *f) {
383 fprintf(f, "usage: #!/usr/bin/prefork-interp [<options>]\n");
386 #define MODE_NORMAL 0
387 #define MODE_KILL 'k'
388 #define MODE_FRESH 'f'
390 #define MEDIATION_UNSPECIFIED 0
391 #define MEDIATION_UNLAUNDERED 'U'
393 static int mediation = MEDIATION_UNSPECIFIED;
394 static int mode = MODE_NORMAL;
395 static int max_sockets = 100; // maximum entries in the run dir is 2x this
397 static struct stat initial_stab;
399 const struct cmdinfo cmdinfos[]= {
401 { 0, 'U', 0, .iassignto= &mediation, .arg= MEDIATION_UNLAUNDERED },
402 { "kill", 0, 0, .iassignto= &mode, .arg= MODE_KILL },
403 { 0, 'f', 0, .iassignto= &mode, .arg= MODE_FRESH },
407 void ident_addinit(void) {
408 char ident_magic[1] = { 0 };
409 sha256_update(&identsc, sizeof(ident_magic), ident_magic);
412 static void propagate_exit_status(int status, const char *what) {
415 if (WIFEXITED(status)) {
419 if (WIFSIGNALED(status)) {
420 int sig = WTERMSIG(status);
421 const char *signame = strsignal(sig);
422 if (signame == 0) signame = "unknown signal";
424 if (! WCOREDUMP(status) &&
431 sa.sa_handler = SIG_DFL;
432 r = sigaction(sig, &sa, 0);
433 if (r) diee("failed to reset signal handler while propagating %s",
438 sigaddset(&sset, sig);
439 r = sigprocmask(SIG_UNBLOCK, &sset, 0);
440 if (r) diee("failed to reset signal block while propagating %s",
444 die("unexpectedly kept running after raising (to propagate) %s",
448 die("%s failed due to signal %d %s%s", what, sig, signame,
449 WCOREDUMP(status) ? " (core dumped)" : "");
452 die("%s failed with weird wait status %d 0x%x", what, status, status);
460 static int preclean_entry_compar_name(const void *av, const void *bv) {
461 const PrecleanEntry *a = av;
462 const PrecleanEntry *b = bv;
463 return strcmp(a->name_hash, b->name_hash);
466 static int preclean_entry_compar_atime(const void *av, const void *bv) {
467 const PrecleanEntry *ae = av; time_t a = ae->atime;
468 const PrecleanEntry *be = bv; time_t b = be->atime;
473 static time_t preclean_stat_atime(const char *s_path) {
475 int r= lstat(s_path, &stab);
477 if (errno!=ENOENT) diee("pre-cleanup: stat socket (%s)", s_path);
480 return stab.st_atime;
483 static void preclean(void) {
484 DIR *dir = opendir(run_base);
486 if (errno == ENOENT) return;
487 diee("pre-cleanup: open run dir (%s)", run_base);
490 PrecleanEntry *entries=0;
491 size_t avail_entries=0;
492 size_t used_entries=0;
495 while ((errno = 0, de = readdir(dir))) {
496 char c0 = de->d_name[0];
497 if (!(c0 == 'l' || c0 == 's')) continue;
498 char *name_hash = m_asprintf("%s", de->d_name+1);
499 char *s_path = m_asprintf("%s/s%s", run_base, name_hash);
500 time_t atime = preclean_stat_atime(s_path);
502 if (avail_entries == used_entries) {
503 assert(avail_entries < INT_MAX / 4 / sizeof(PrecleanEntry));
506 entries = realloc(entries, avail_entries * sizeof(PrecleanEntry));
508 entries[used_entries].name_hash = name_hash;
509 entries[used_entries].atime = atime;
512 if (errno) diee("pre-cleanup: read run dir (%s)", run_base);
514 // First we dedupe (after sorting by path)
515 qsort(entries, used_entries, sizeof(PrecleanEntry),
516 preclean_entry_compar_name);
517 PrecleanEntry *p, *q;
518 for (p=entries, q=entries; p < entries + used_entries; p++) {
519 if (q > entries && !strcmp(p->name_hash, (q-1)->name_hash))
523 used_entries = q - entries;
525 // Now maybe delete some things
527 // Actually this has an off-by-one error since we are about
528 // to create a socket, so the actual number of sockets is one more.
529 // But, *actually*, since there might be multiple of us running at once,
530 // we might have even more than that. This doesn't really matter.
531 if (used_entries > max_sockets) {
532 qsort(entries, used_entries, sizeof(PrecleanEntry),
533 preclean_entry_compar_atime);
534 for (p=entries; p < entries + max_sockets; p++) {
535 char *l_path = m_asprintf("%s/l%s", run_base, p->name_hash);
536 char *s_path = m_asprintf("%s/s%s", run_base, p->name_hash);
537 int lock_fd = flock_file(l_path);
538 // Recheck atime - we might have raced!
539 time_t atime = preclean_stat_atime(s_path);
540 if (atime != p->atime) {
541 // Raced. This will leave use deleting too few things. Whatever.
543 int r= unlink(s_path);
544 if (r && errno!=ENOENT) diee("preclean: delete stale (%s)", s_path);
546 if (r) diee("preclean: delete stale lock (%s)", s_path);
547 // NB we don't hold the lock any more now.
555 for (p=entries; p < entries + used_entries; p++)
560 static __attribute((noreturn)) void die_data_overflow(void) {
561 die("cannot handle data with length >2^32");
564 static void prepare_data(size_t *len, char **buf,
565 const void *data, size_t dl) {
567 if (dl >= SIZE_MAX - *len)
572 memcpy(*buf, data, dl);
577 static void prepare_length(size_t *len, char **buf, size_t dl_sz) {
578 if (dl_sz > UINT32_MAX) die_data_overflow();
579 uint32_t dl = htonl(dl_sz);
580 prepare_data(len, buf, &dl, sizeof(dl));
583 static void prepare_string(size_t *len, char **buf, const char *s) {
584 size_t sl = strlen(s);
585 prepare_data(len, buf, s, sl+1);
588 static void prepare_message(size_t *len, char **buf) {
591 const char *const *p = (void*)environ;
594 prepare_string(len, buf, s);
597 prepare_string(len, buf, "");
601 prepare_string(len, buf, s);
604 static void send_fd(int payload_fd) {
605 int via_fd = fileno(call_sock);
608 struct cmsghdr align;
609 char buf[CMSG_SPACE(sizeof(payload_fd))];
619 iov.iov_base = &dummy_byte;
625 msg.msg_control = cmsg_buf.buf;
626 msg.msg_controllen = sizeof(cmsg_buf.buf);
628 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
629 cmsg->cmsg_level = SOL_SOCKET;
630 cmsg->cmsg_type = SCM_RIGHTS;
631 cmsg->cmsg_len = CMSG_LEN(sizeof(payload_fd));
632 *(int*)CMSG_DATA(cmsg) = payload_fd;
634 msg.msg_controllen = sizeof(cmsg_buf.buf);
637 ssize_t r = sendmsg(via_fd, &msg, 0);
639 if (errno == EINTR) continue;
647 static void send_request(void) {
649 ssize_t sr = fwrite(&ibyte, 1, 1, call_sock);
650 if (sr != 1) diee("write signalling byte");
652 // Sending these before the big message makes it easier for the script to
653 // use buffered IO for the message.
659 prepare_message(&len, 0);
661 size_t tlen = len + 4;
662 char *m = xmalloc(tlen);
664 prepare_length(0, &p, len);
665 prepare_message(0, &p);
666 assert(p == m + tlen);
668 sr = fwrite(m, tlen, 1, call_sock);
669 if (sr != 1) diee("write request (buffer)");
671 if (fflush(call_sock)) diee("write request");
674 static FILE *call_sock_from_fd(int fd) {
677 FILE *call_sock = fdopen(fd, "r+");
678 if (!call_sock) diee("fdopen socket");
680 r = setvbuf(call_sock, 0, _IONBF, 0);
681 if (r) die("setvbuf socket");
686 static bool was_eof(FILE *call_sock) {
687 return feof(call_sock) || errno==ECONNRESET;
691 static int protocol_read_maybe(void *data, size_t sz) {
693 size_t sr = fread(data, sz, 1, call_sock);
695 if (was_eof(call_sock)) return -1;
696 diee("read() on monitor call socket (%zd)", sz);
701 static void protocol_read(void *data, size_t sz) {
702 if (protocol_read_maybe(data, sz) < 0)
703 die("monitor process quit unexpectedly");
706 // Returns 0 if OK, error msg if peer was garbage.
707 static const char *read_greeting(void) {
708 char got_magic[sizeof(header_magic)];
710 if (protocol_read_maybe(&got_magic, sizeof(got_magic)) < 0)
711 return "initial monitor process quit";
713 if (memcmp(got_magic, header_magic, sizeof(header_magic)))
714 die("got unexpected protocol magic 0x%02x%02x%02x%02x",
715 got_magic[0], got_magic[1], got_magic[2], got_magic[3]);
718 protocol_read(&xdata_len, sizeof(xdata_len));
719 void *xdata = xmalloc(xdata_len);
720 protocol_read(xdata, xdata_len);
725 // Returns: call(client-end), or 0 to mean "is garbage"
726 // find_socket_path must have been called
727 static FILE *connect_existing(void) {
731 if (mode != MODE_NORMAL) return 0;
733 fd = socket(AF_UNIX, SOCK_STREAM, 0);
734 if (fd==-1) diee("socket() for client");
736 socklen_t salen = sizeof(sockaddr_sun);
737 r = connect(fd, (const struct sockaddr*)&sockaddr_sun, salen);
739 if (errno==ECONNREFUSED || errno==ENOENT) goto x_garbage;
740 diee("connect() %s", socket_path);
743 call_sock = call_sock_from_fd(fd);
752 if (call_sock) { fclose(call_sock); call_sock=0; }
753 if (fd >= 0) close(fd);
757 static void watcher_cb_stdin(uv_poll_t *handle, int status, int events) {
761 if ((errno = -status)) diee("watcher: poll stdin");
765 if (!(errno==EINTR || errno==EWOULDBLOCK || errno==EAGAIN))
766 diee("watcher: read sentinel stdin");
770 static void watcher_cb_sockpath(uv_fs_event_t *handle, const char *filename,
771 int events, int status) {
773 struct stat now_stab;
775 if ((errno = -status)) diee("watcher: poll stdin");
777 r= stat(socket_path, &now_stab);
779 if (errno==ENOENT) _exit(0);
780 if (errno==EINTR) continue;
781 diee("stat socket: %s", socket_path);
783 if (!stabs_same_inode(&now_stab, &initial_stab))
788 // On entry, stderr is still inherited, but 0 and 1 are the pipes
789 static __attribute__((noreturn))
790 void become_watcher(void) {
792 uv_poll_t uvhandle_stdin;
793 uv_fs_event_t uvhandle_sockpath;
798 errno= -uv_loop_init(&loop);
799 if (errno) diee("watcher: uv_loop_init");
801 errno= -uv_poll_init(&loop, &uvhandle_stdin, 0);
802 if (errno) diee("watcher: uv_poll_init");
803 errno= -uv_poll_start(&uvhandle_stdin,
804 UV_READABLE | UV_WRITABLE | UV_DISCONNECT,
806 if (errno) diee("watcher: uv_poll_start");
808 errno= -uv_fs_event_init(&loop, &uvhandle_sockpath);
809 if (errno) diee("watcher: uv_fs_event_init");
811 errno= -uv_fs_event_start(&uvhandle_sockpath, watcher_cb_sockpath,
813 if (errno) diee("watcher: uv_fs_event_start");
815 // OK everything is set up, let us daemonise
816 if (dup2(1,2) != 2) diee("watcher: set daemonised stderr");
817 r= setvbuf(stderr, 0, _IOLBF, BUFSIZ);
818 if (r) diee("watcher: setvbuf stderr");
820 pid_t child = fork();
821 if (child == (pid_t)-1) diee("watcher: fork");
824 if (setsid() == (pid_t)-1) diee("watcher: setsid");
826 r= uv_run(&loop, UV_RUN_DEFAULT);
827 die("uv_run returned (%d)", r);
830 static __attribute__((noreturn))
831 void become_setup(int sfd, int lockfd, int fake_pair[2],
832 int watcher_stdin, int watcher_stderr) {
835 int call_fd = fake_pair[1];
837 int null_0 = open("/dev/null", O_RDONLY); if (null_0 < 0) diee("open null");
838 if (dup2(null_0, 0)) diee("dup2 /dev/null onto stdin");
840 if (dup2(2, 1) != 1) die("dup2 stderr onto stdout");
844 // Extension could work like this:
846 // We could advertise a new protocol (perhaps one which is nearly entirely
847 // different after the connect) by putting a name for it comma-separated
848 // next to "v1". Simple extension can be done by having the script
849 // side say something about it in the ack xdata, which we currently ignore.
850 // Or we could add other extra data after v1.
851 putenv(m_asprintf("PREFORK_INTERP=v1,%jd.%09ld %d,%d,%d,%d",
852 (intmax_t)initial_stab.st_mtim.tv_sec,
853 (long)initial_stab.st_mtim.tv_nsec,
854 sfd, call_fd, watcher_stdin, watcher_stderr));
856 execvp(executor_argv[0], (char**)executor_argv);
857 diee("execute %s", executor_argv[0]);
860 static void connect_or_spawn(void) {
863 call_sock = connect_existing();
864 if (call_sock) return;
866 // We're going to make a new one, so clean out old ones
869 int lockfd = acquire_lock();
871 if (mode == MODE_KILL) {
872 r= unlink(socket_path);
873 if (r && errno != ENOENT) diee("remove socket %s", socket_path);
875 r= unlink(lock_path);
876 if (r) diee("rmeove lock %s", lock_path);
880 call_sock = connect_existing();
881 if (call_sock) { close(lockfd); return; }
883 // We must start a fresh one, and we hold the lock
885 r = unlink(socket_path);
886 if (r<0 && errno!=ENOENT)
887 diee("failed to remove stale socket %s", socket_path);
889 int sfd = socket(AF_UNIX, SOCK_STREAM, 0);
890 if (sfd<0) diee("socket() for new listener");
892 socklen_t salen = sizeof(sockaddr_sun);
893 r= bind(sfd, (const struct sockaddr*)&sockaddr_sun, salen);
894 if (r<0) diee("bind() on new listener");
896 r= stat(socket_path, &initial_stab);
897 if (r<0) diee("stat() fresh socket");
899 // We never want callers to get ECONNREFUSED. But:
900 // There is a race here: from my RTFM they may get ECONNREFUSED
901 // if they try between our bind() and listen(). But if they do, they'll
902 // acquire the lock (serialising with us) and retry, and then it will work.
903 r = listen(sfd, INT_MAX);
904 if (r<0) diee("listen() for new listener");
908 int watcher_stdin[2];
909 int watcher_stderr[2];
910 if (pipe(watcher_stdin) || pipe(watcher_stderr))
911 diee("pipe() for socket inode watcher");
913 pid_t watcher = fork();
914 if (watcher == (pid_t)-1) diee("fork for watcher");
918 close(watcher_stdin[1]);
919 close(watcher_stderr[0]);
920 if (dup2(watcher_stdin[0], 0) != 0 ||
921 dup2(watcher_stderr[1], 1) != 1)
922 diee("initial dup2() for watcher");
923 close(watcher_stdin[0]);
924 close(watcher_stderr[1]);
928 close(watcher_stdin[0]);
929 close(watcher_stderr[1]);
930 nonblock(watcher_stderr[0]);
935 r = socketpair(AF_UNIX, SOCK_STREAM, 0, fake_pair);
936 if (r<0) diee("socketpair() for fake initial connection");
938 pid_t setup_pid = fork();
939 if (setup_pid == (pid_t)-1) diee("fork for spawn setup");
940 if (!setup_pid) become_setup(sfd, lockfd, fake_pair,
941 watcher_stdin[1], watcher_stderr[0]);
945 call_sock = call_sock_from_fd(fake_pair[0]);
948 pid_t got = waitpid(setup_pid, &status, 0);
949 if (got == (pid_t)-1) diee("waitpid setup [%ld]", (long)setup_pid);
950 if (got != setup_pid) diee("waitpid setup [%ld] gave [%ld]!",
951 (long)setup_pid, (long)got);
952 if (status != 0) propagate_exit_status(status, "setup");
954 const char *emsg = read_greeting();
955 if (emsg) die("setup failed: %s", emsg);
961 static void make_executor_argv(const char *const *argv) {
963 case MEDIATION_UNLAUNDERED: break;
964 default: die("need -U (specifying unlaundered argument handling)");
968 #define EACH_NEW_ARG(EACH) { \
969 arg = interp; { EACH } \
970 if ((arg = script)) { EACH } \
971 const char *const *walk = argv; \
972 while ((arg = *walk++)) { EACH } \
976 EACH_NEW_ARG( (void)arg; count++; );
978 const char **out = calloc(count, sizeof(char*));
979 executor_argv = (const char* const*)out;
980 if (!executor_argv) diee("allocate for arguments");
982 EACH_NEW_ARG( *out++ = arg; );
986 int main(int argc_unused, const char *const *argv) {
993 // which ought to be passed on to the actual executor.
994 make_executor_argv(argv);
997 FILLZERO(sockaddr_sun);
998 sockaddr_sun.sun_family = AF_UNIX;
999 assert(strlen(socket_path) <= sizeof(sockaddr_sun.sun_path));
1000 strncpy(sockaddr_sun.sun_path, socket_path, sizeof(sockaddr_sun.sun_path));
1004 // We're committed now, send the request (or bail out)
1008 protocol_read(&status, sizeof(status));
1010 status = ntohl(status);
1011 if (status > INT_MAX) die("status 0x%lx does not fit in an int",
1012 (unsigned long)status);
1014 propagate_exit_status(status, "invocation");