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 mediation approach.
11 * Currently the only argument mediation supported is:
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
17 * Options for setting the operation mode:
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
23 * Options for controlling whether different invocations share a server:
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 ...))
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)
34 ***************************************************************************
36 State during service execution, process parentage and key fds
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
64 && session leader (daemon)
65 & process group leader
67 ***************************************************************************
69 Control flow and causality
77 attempt to connect, and read greeting
80 tidy up stale /run entries *1 (continue from send_fds, below)
83 retry attempt to connect, and read greeting
86 create listening socket release lock
89 | `------------------.
92 make "fake" initial call socketpair (C)
94 fork/exec #########################################################
95 | `-------------. application
98 | # script initialisation
100 | ###########|#############################################
102 | # identify fds from envirnment (Perl)
107 waitpid # fork for initial service
110 | # | SCRIPT [server] &&
112 | # | ** accept / event loop **
113 | # | accepted? \ \ \
114 | # | / \ watch\ \idle
115 | # | fork child \stderr\ \timeout?
116 | # | _________/ | | |
118 | # SCRIPT [monitor] | eof?| |
121 read ,....<.....send greeting | | |
122 greeting # | ___________________
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
138 | # | # kernel closes execterm
139 | # | ,......<....../|
142 | # | | ,......<...../
143 | # waitpid # _______________
145 | ,....<....,..send status #
146 read status # ________________ #
150 ********** Or, if client is killed **********
152 | # | # execute service
153 terminates # wait for read # |
158 _____________ # \|call? # |
160 # kill whole pgrp... # killled
162 # | | ,......<....../
163 # waitpid # _______________
166 # _____SIGPIPE______ #
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
175 ______ process termination (after reaping, if shown)
177 ***************************************************************************
179 Sequence of events and fd pluming.
180 NB INCOMPLETE - does not cover execterm, cleanup
182 client (C wrapper) connects to server
183 (including reading ack byte)
185 === acquires lock ===
186 makes new listening socket
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)
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
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
208 possibly clean env, argv
210 setup (script) runs initialisation parts of the script
211 at prefork establishment point:
212 setup (pm) [1] opens syslog
216 server (pm) [1] [fd0: null],
217 [fd[12]: fd2-from-outer]
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
227 [client (C wrapper)] if client connect succeeds:
228 now fd: call(client-end)
229 sends message with: cmdline, env
232 [server (script)] accepts, forks subseq monitor
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)
239 receives args, env, fds
242 executor sorts out fds:
243 fd0, fd1, fd2: from-outer
244 close fds: call(server-end)
248 runs main part of script
251 [monitor] [fd[012]: null]
252 [fd[12]: init: fd2-from-outer; subseq: null]
253 [errors: init: fd2; subseq: syslog]
255 reports status via socket
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)
262 ***************************************************************************
264 Protocol, and functions of the script
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:
270 2. Env var PREFORK_INTERP contains:
272 v1,SECS.NSECS[,...] LISTEN,CALL,WATCHE,WATCHI[,...][ ???]
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:
280 v1 Protocol version indicator - literal. If something else,
281 fail (means installation is incompatible somehow).
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).
288 The 2nd word's items are file descriptors:
290 LISTEN listening socket nonblocking
291 CALL call socket for initial call blocking
292 WATCHE liveness watcher stderr nonblocking
293 WATCHI liveness sentinel unspecified
295 (any further descriptors should be ignored, not closed)
297 3. Library should do the following:
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.)
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:
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
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
327 4. service (monitor) child does the following:
329 1. close all of LISTEN, WATCHI, WATCHE
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
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
353 10. in the parent, close EXECTERM writing end, and
354 11. select, looking for one of the following:
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
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).
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)).
377 ***************************************************************************
381 #include <arpa/inet.h>
382 #include <sys/utsname.h>
388 const char our_name[] = "prefork-interp";
390 static struct sockaddr_un sockaddr_sun;
391 static FILE *call_sock;
393 #define ACK_BYTE '\n'
395 static const char *const *executor_argv;
397 static const char header_magic[4] = "PFI\n";
399 void fusagemessage(FILE *f) {
400 fprintf(f, "usage: #!/usr/bin/prefork-interp [<options>]\n");
403 #define MODE_NORMAL 0
404 #define MODE_KILL 'k'
405 #define MODE_FRESH 'f'
407 #define MEDIATION_UNSPECIFIED 0
408 #define MEDIATION_UNLAUNDERED 'U'
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
414 static struct stat initial_stab;
416 const struct cmdinfo 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 },
424 static void ident_add_stat(const char *path) {
426 int r = stat(path, &stab);
427 if (r) diee("failed to stat %s", path);
429 IDENT_ADD_OBJ(stab.st_dev);
430 IDENT_ADD_OBJ(stab.st_ino);
433 void ident_addinit(void) {
436 IDENT_ADD_OBJ(magic);
438 struct utsname uts = { };
439 size_t utslen = sizeof(uts);
441 if (r) diee("uname failed!");
442 IDENT_ADD_OBJ(utslen);
449 static void propagate_exit_status(int status, const char *what) {
452 if (WIFEXITED(status)) {
456 if (WIFSIGNALED(status)) {
457 int sig = WTERMSIG(status);
458 const char *signame = strsignal(sig);
459 if (signame == 0) signame = "unknown signal";
461 if (! WCOREDUMP(status) &&
468 sa.sa_handler = SIG_DFL;
469 r = sigaction(sig, &sa, 0);
470 if (r) diee("failed to reset signal handler while propagating %s",
475 sigaddset(&sset, sig);
476 r = sigprocmask(SIG_UNBLOCK, &sset, 0);
477 if (r) diee("failed to reset signal block while propagating %s",
481 die("unexpectedly kept running after raising (to propagate) %s",
485 die("%s failed due to signal %d %s%s", what, sig, signame,
486 WCOREDUMP(status) ? " (core dumped)" : "");
489 die("%s failed with weird wait status %d 0x%x", what, status, status);
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);
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;
510 static time_t preclean_stat_atime(const char *s_path) {
512 int r= lstat(s_path, &stab);
514 if (errno!=ENOENT) diee("pre-cleanup: stat socket (%s)", s_path);
517 return stab.st_atime;
520 static void preclean(void) {
521 DIR *dir = opendir(run_base);
523 if (errno == ENOENT) return;
524 diee("pre-cleanup: open run dir (%s)", run_base);
527 PrecleanEntry *entries=0;
528 size_t avail_entries=0;
529 size_t used_entries=0;
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);
539 if (avail_entries == used_entries) {
540 assert(avail_entries < INT_MAX / 4 / sizeof(PrecleanEntry));
543 entries = realloc(entries, avail_entries * sizeof(PrecleanEntry));
545 entries[used_entries].name_hash = name_hash;
546 entries[used_entries].atime = atime;
549 if (errno) diee("pre-cleanup: read run dir (%s)", run_base);
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))
560 used_entries = q - entries;
562 // Now maybe delete some things
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.
580 int r= unlink(s_path);
581 if (r && errno!=ENOENT) diee("preclean: delete stale (%s)", s_path);
583 if (r) diee("preclean: delete stale lock (%s)", s_path);
584 // NB we don't hold the lock any more now.
592 for (p=entries; p < entries + used_entries; p++)
597 static __attribute((noreturn)) void die_data_overflow(void) {
598 die("cannot handle data with length >2^32");
601 static void prepare_data(size_t *len, char **buf,
602 const void *data, size_t dl) {
604 if (dl >= SIZE_MAX - *len)
609 memcpy(*buf, data, dl);
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));
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);
625 static void prepare_message(size_t *len, char **buf) {
628 const char *const *p = (void*)environ;
631 prepare_string(len, buf, s);
634 prepare_string(len, buf, "");
638 prepare_string(len, buf, s);
641 static void send_fd(int payload_fd) {
642 int via_fd = fileno(call_sock);
645 struct cmsghdr align;
646 char buf[CMSG_SPACE(sizeof(payload_fd))];
656 iov.iov_base = &dummy_byte;
662 msg.msg_control = cmsg_buf.buf;
663 msg.msg_controllen = sizeof(cmsg_buf.buf);
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;
671 msg.msg_controllen = sizeof(cmsg_buf.buf);
674 ssize_t r = sendmsg(via_fd, &msg, 0);
676 if (errno == EINTR) continue;
684 static void send_request(void) {
686 ssize_t sr = fwrite(&ibyte, 1, 1, call_sock);
687 if (sr != 1) diee("write signalling byte");
689 // Sending these before the big message makes it easier for the script to
690 // use buffered IO for the message.
696 prepare_message(&len, 0);
698 size_t tlen = len + 4;
699 char *m = xmalloc(tlen);
701 prepare_length(0, &p, len);
702 prepare_message(0, &p);
703 assert(p == m + tlen);
705 sr = fwrite(m, tlen, 1, call_sock);
706 if (sr != 1) diee("write request (buffer)");
708 if (fflush(call_sock)) diee("write request");
711 static FILE *call_sock_from_fd(int fd) {
714 FILE *call_sock = fdopen(fd, "r+");
715 if (!call_sock) diee("fdopen socket");
717 r = setvbuf(call_sock, 0, _IONBF, 0);
718 if (r) die("setvbuf socket");
723 static bool was_eof(FILE *call_sock) {
724 return feof(call_sock) || errno==ECONNRESET;
728 static int protocol_read_maybe(void *data, size_t sz) {
730 size_t sr = fread(data, sz, 1, call_sock);
732 if (was_eof(call_sock)) return -1;
733 diee("read() on monitor call socket (%zd)", sz);
738 static void protocol_read(void *data, size_t sz) {
739 if (protocol_read_maybe(data, sz) < 0)
740 die("monitor process quit unexpectedly");
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)];
747 if (protocol_read_maybe(&got_magic, sizeof(got_magic)) < 0)
748 return "initial monitor process quit";
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]);
755 protocol_read(&xdata_len, sizeof(xdata_len));
756 void *xdata = xmalloc(xdata_len);
757 protocol_read(xdata, xdata_len);
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) {
768 if (mode != MODE_NORMAL) return 0;
770 fd = socket(AF_UNIX, SOCK_STREAM, 0);
771 if (fd==-1) diee("socket() for client");
773 socklen_t salen = sizeof(sockaddr_sun);
774 r = connect(fd, (const struct sockaddr*)&sockaddr_sun, salen);
776 if (errno==ECONNREFUSED || errno==ENOENT) goto x_garbage;
777 diee("connect() %s", socket_path);
780 call_sock = call_sock_from_fd(fd);
789 if (call_sock) { fclose(call_sock); call_sock=0; }
790 if (fd >= 0) close(fd);
794 static void watcher_cb_stdin(uv_poll_t *handle, int status, int events) {
798 if ((errno = -status)) diee("watcher: poll stdin");
802 if (!(errno==EINTR || errno==EWOULDBLOCK || errno==EAGAIN))
803 diee("watcher: read sentinel stdin");
807 static void watcher_cb_sockpath(uv_fs_event_t *handle, const char *filename,
808 int events, int status) {
810 struct stat now_stab;
812 if ((errno = -status)) diee("watcher: poll stdin");
814 r= stat(socket_path, &now_stab);
816 if (errno==ENOENT) _exit(0);
817 if (errno==EINTR) continue;
818 diee("stat socket: %s", socket_path);
820 if (!stabs_same_inode(&now_stab, &initial_stab))
825 // On entry, stderr is still inherited, but 0 and 1 are the pipes
826 static __attribute__((noreturn))
827 void become_watcher(void) {
829 uv_poll_t uvhandle_stdin;
830 uv_fs_event_t uvhandle_sockpath;
835 errno= -uv_loop_init(&loop);
836 if (errno) diee("watcher: uv_loop_init");
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,
843 if (errno) diee("watcher: uv_poll_start");
845 errno= -uv_fs_event_init(&loop, &uvhandle_sockpath);
846 if (errno) diee("watcher: uv_fs_event_init");
848 errno= -uv_fs_event_start(&uvhandle_sockpath, watcher_cb_sockpath,
850 if (errno) diee("watcher: uv_fs_event_start");
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");
857 pid_t child = fork();
858 if (child == (pid_t)-1) diee("watcher: fork");
861 if (setsid() == (pid_t)-1) diee("watcher: setsid");
863 r= uv_run(&loop, UV_RUN_DEFAULT);
864 die("uv_run returned (%d)", r);
867 static __attribute__((noreturn))
868 void become_setup(int sfd, int lockfd, int fake_pair[2],
869 int watcher_stdin, int watcher_stderr) {
872 int call_fd = fake_pair[1];
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");
877 if (dup2(2, 1) != 1) die("dup2 stderr onto stdout");
881 // Extension could work like this:
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));
893 execvp(executor_argv[0], (char**)executor_argv);
894 diee("execute %s", executor_argv[0]);
897 static void connect_or_spawn(void) {
900 call_sock = connect_existing();
901 if (call_sock) return;
903 // We're going to make a new one, so clean out old ones
906 int lockfd = acquire_lock();
908 if (mode == MODE_KILL) {
909 r= unlink(socket_path);
910 if (r && errno != ENOENT) diee("remove socket %s", socket_path);
912 r= unlink(lock_path);
913 if (r) diee("rmeove lock %s", lock_path);
917 call_sock = connect_existing();
918 if (call_sock) { close(lockfd); return; }
920 // We must start a fresh one, and we hold the lock
922 r = unlink(socket_path);
923 if (r<0 && errno!=ENOENT)
924 diee("failed to remove stale socket %s", socket_path);
926 int sfd = socket(AF_UNIX, SOCK_STREAM, 0);
927 if (sfd<0) diee("socket() for new listener");
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");
933 r= stat(socket_path, &initial_stab);
934 if (r<0) diee("stat() fresh socket");
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");
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");
950 pid_t watcher = fork();
951 if (watcher == (pid_t)-1) diee("fork for watcher");
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]);
965 close(watcher_stdin[0]);
966 close(watcher_stderr[1]);
967 nonblock(watcher_stderr[0]);
972 r = socketpair(AF_UNIX, SOCK_STREAM, 0, fake_pair);
973 if (r<0) diee("socketpair() for fake initial connection");
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]);
982 call_sock = call_sock_from_fd(fake_pair[0]);
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");
991 const char *emsg = read_greeting();
992 if (emsg) die("setup failed: %s", emsg);
998 static void make_executor_argv(const char *const *argv) {
1000 case MEDIATION_UNLAUNDERED: break;
1001 default: die("need -U (specifying unlaundered argument handling)");
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 } \
1013 EACH_NEW_ARG( (void)arg; count++; );
1015 const char **out = calloc(count, sizeof(char*));
1016 executor_argv = (const char* const*)out;
1017 if (!executor_argv) diee("allocate for arguments");
1019 EACH_NEW_ARG( *out++ = arg; );
1023 int main(int argc_unused, const char *const *argv) {
1024 process_opts(&argv);
1027 // - possibly interp
1028 // - possibly script
1030 // which ought to be passed on to the actual executor.
1031 make_executor_argv(argv);
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));
1041 // We're committed now, send the request (or bail out)
1045 protocol_read(&status, sizeof(status));
1047 status = ntohl(status);
1048 if (status > INT_MAX) die("status 0x%lx does not fit in an int",
1049 (unsigned long)status);
1051 propagate_exit_status(status, "invocation");