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(path[0], stab.st_dev);
430 IDENT_ADD_OBJ('i', stab.st_ino);
433 void ident_addinit(void) {
434 ident_add_key_byte(1);
436 struct utsname uts = { };
437 size_t utslen = sizeof(uts);
439 if (r) diee("uname failed!");
440 IDENT_ADD_OBJ('u', utslen);
441 IDENT_ADD_OBJ('u', uts);
447 static void propagate_exit_status(int status, const char *what) {
450 if (WIFEXITED(status)) {
454 if (WIFSIGNALED(status)) {
455 int sig = WTERMSIG(status);
456 const char *signame = strsignal(sig);
457 if (signame == 0) signame = "unknown signal";
459 if (! WCOREDUMP(status) &&
466 sa.sa_handler = SIG_DFL;
467 r = sigaction(sig, &sa, 0);
468 if (r) diee("failed to reset signal handler while propagating %s",
473 sigaddset(&sset, sig);
474 r = sigprocmask(SIG_UNBLOCK, &sset, 0);
475 if (r) diee("failed to reset signal block while propagating %s",
479 die("unexpectedly kept running after raising (to propagate) %s",
483 die("%s failed due to signal %d %s%s", what, sig, signame,
484 WCOREDUMP(status) ? " (core dumped)" : "");
487 die("%s failed with weird wait status %d 0x%x", what, status, status);
495 static int preclean_entry_compar_name(const void *av, const void *bv) {
496 const PrecleanEntry *a = av;
497 const PrecleanEntry *b = bv;
498 return strcmp(a->name_hash, b->name_hash);
501 static int preclean_entry_compar_atime(const void *av, const void *bv) {
502 const PrecleanEntry *ae = av; time_t a = ae->atime;
503 const PrecleanEntry *be = bv; time_t b = be->atime;
508 static time_t preclean_stat_atime(const char *s_path) {
510 int r= lstat(s_path, &stab);
512 if (errno!=ENOENT) diee("pre-cleanup: stat socket (%s)", s_path);
515 return stab.st_atime;
518 static void preclean(void) {
519 DIR *dir = opendir(run_base);
521 if (errno == ENOENT) return;
522 diee("pre-cleanup: open run dir (%s)", run_base);
525 PrecleanEntry *entries=0;
526 size_t avail_entries=0;
527 size_t used_entries=0;
530 while ((errno = 0, de = readdir(dir))) {
531 char c0 = de->d_name[0];
532 if (!(c0 == 'l' || c0 == 's')) continue;
533 char *name_hash = m_asprintf("%s", de->d_name+1);
534 char *s_path = m_asprintf("%s/s%s", run_base, name_hash);
535 time_t atime = preclean_stat_atime(s_path);
537 if (avail_entries == used_entries) {
538 assert(avail_entries < INT_MAX / 4 / sizeof(PrecleanEntry));
541 entries = realloc(entries, avail_entries * sizeof(PrecleanEntry));
543 entries[used_entries].name_hash = name_hash;
544 entries[used_entries].atime = atime;
547 if (errno) diee("pre-cleanup: read run dir (%s)", run_base);
549 // First we dedupe (after sorting by path)
550 qsort(entries, used_entries, sizeof(PrecleanEntry),
551 preclean_entry_compar_name);
552 PrecleanEntry *p, *q;
553 for (p=entries, q=entries; p < entries + used_entries; p++) {
554 if (q > entries && !strcmp(p->name_hash, (q-1)->name_hash))
558 used_entries = q - entries;
560 // Now maybe delete some things
562 // Actually this has an off-by-one error since we are about
563 // to create a socket, so the actual number of sockets is one more.
564 // But, *actually*, since there might be multiple of us running at once,
565 // we might have even more than that. This doesn't really matter.
566 if (used_entries > max_sockets) {
567 qsort(entries, used_entries, sizeof(PrecleanEntry),
568 preclean_entry_compar_atime);
569 for (p=entries; p < entries + max_sockets; p++) {
570 char *l_path = m_asprintf("%s/l%s", run_base, p->name_hash);
571 char *s_path = m_asprintf("%s/s%s", run_base, p->name_hash);
572 int lock_fd = flock_file(l_path);
573 // Recheck atime - we might have raced!
574 time_t atime = preclean_stat_atime(s_path);
575 if (atime != p->atime) {
576 // Raced. This will leave use deleting too few things. Whatever.
578 int r= unlink(s_path);
579 if (r && errno!=ENOENT) diee("preclean: delete stale (%s)", s_path);
581 if (r) diee("preclean: delete stale lock (%s)", s_path);
582 // NB we don't hold the lock any more now.
590 for (p=entries; p < entries + used_entries; p++)
595 static __attribute((noreturn)) void die_data_overflow(void) {
596 die("cannot handle data with length >2^32");
599 static void prepare_data(size_t *len, char **buf,
600 const void *data, size_t dl) {
602 if (dl >= SIZE_MAX - *len)
607 memcpy(*buf, data, dl);
612 static void prepare_length(size_t *len, char **buf, size_t dl_sz) {
613 if (dl_sz > UINT32_MAX) die_data_overflow();
614 uint32_t dl = htonl(dl_sz);
615 prepare_data(len, buf, &dl, sizeof(dl));
618 static void prepare_string(size_t *len, char **buf, const char *s) {
619 size_t sl = strlen(s);
620 prepare_data(len, buf, s, sl+1);
623 static void prepare_message(size_t *len, char **buf) {
626 const char *const *p = (void*)environ;
629 prepare_string(len, buf, s);
632 prepare_string(len, buf, "");
636 prepare_string(len, buf, s);
639 static void send_fd(int payload_fd) {
640 int via_fd = fileno(call_sock);
643 struct cmsghdr align;
644 char buf[CMSG_SPACE(sizeof(payload_fd))];
654 iov.iov_base = &dummy_byte;
660 msg.msg_control = cmsg_buf.buf;
661 msg.msg_controllen = sizeof(cmsg_buf.buf);
663 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
664 cmsg->cmsg_level = SOL_SOCKET;
665 cmsg->cmsg_type = SCM_RIGHTS;
666 cmsg->cmsg_len = CMSG_LEN(sizeof(payload_fd));
667 *(int*)CMSG_DATA(cmsg) = payload_fd;
669 msg.msg_controllen = sizeof(cmsg_buf.buf);
672 ssize_t r = sendmsg(via_fd, &msg, 0);
674 if (errno == EINTR) continue;
682 static void send_request(void) {
684 ssize_t sr = fwrite(&ibyte, 1, 1, call_sock);
685 if (sr != 1) diee("write signalling byte");
687 // Sending these before the big message makes it easier for the script to
688 // use buffered IO for the message.
694 prepare_message(&len, 0);
696 size_t tlen = len + 4;
697 char *m = xmalloc(tlen);
699 prepare_length(0, &p, len);
700 prepare_message(0, &p);
701 assert(p == m + tlen);
703 sr = fwrite(m, tlen, 1, call_sock);
704 if (sr != 1) diee("write request (buffer)");
706 if (fflush(call_sock)) diee("write request");
709 static FILE *call_sock_from_fd(int fd) {
712 FILE *call_sock = fdopen(fd, "r+");
713 if (!call_sock) diee("fdopen socket");
715 r = setvbuf(call_sock, 0, _IONBF, 0);
716 if (r) die("setvbuf socket");
721 static bool was_eof(FILE *call_sock) {
722 return feof(call_sock) || errno==ECONNRESET;
726 static int protocol_read_maybe(void *data, size_t sz) {
728 size_t sr = fread(data, sz, 1, call_sock);
730 if (was_eof(call_sock)) return -1;
731 diee("read() on monitor call socket (%zd)", sz);
736 static void protocol_read(void *data, size_t sz) {
737 if (protocol_read_maybe(data, sz) < 0)
738 die("monitor process quit unexpectedly");
741 // Returns 0 if OK, error msg if peer was garbage.
742 static const char *read_greeting(void) {
743 char got_magic[sizeof(header_magic)];
745 if (protocol_read_maybe(&got_magic, sizeof(got_magic)) < 0)
746 return "initial monitor process quit";
748 if (memcmp(got_magic, header_magic, sizeof(header_magic)))
749 die("got unexpected protocol magic 0x%02x%02x%02x%02x",
750 got_magic[0], got_magic[1], got_magic[2], got_magic[3]);
753 protocol_read(&xdata_len, sizeof(xdata_len));
754 void *xdata = xmalloc(xdata_len);
755 protocol_read(xdata, xdata_len);
760 // Returns: call(client-end), or 0 to mean "is garbage"
761 // find_socket_path must have been called
762 static FILE *connect_existing(void) {
766 if (mode != MODE_NORMAL) return 0;
768 fd = socket(AF_UNIX, SOCK_STREAM, 0);
769 if (fd==-1) diee("socket() for client");
771 socklen_t salen = sizeof(sockaddr_sun);
772 r = connect(fd, (const struct sockaddr*)&sockaddr_sun, salen);
774 if (errno==ECONNREFUSED || errno==ENOENT) goto x_garbage;
775 diee("connect() %s", socket_path);
778 call_sock = call_sock_from_fd(fd);
787 if (call_sock) { fclose(call_sock); call_sock=0; }
788 if (fd >= 0) close(fd);
792 static void watcher_cb_stdin(uv_poll_t *handle, int status, int events) {
796 if ((errno = -status)) diee("watcher: poll stdin");
800 if (!(errno==EINTR || errno==EWOULDBLOCK || errno==EAGAIN))
801 diee("watcher: read sentinel stdin");
805 static void watcher_cb_sockpath(uv_fs_event_t *handle, const char *filename,
806 int events, int status) {
808 struct stat now_stab;
810 if ((errno = -status)) diee("watcher: poll stdin");
812 r= stat(socket_path, &now_stab);
814 if (errno==ENOENT) _exit(0);
815 if (errno==EINTR) continue;
816 diee("stat socket: %s", socket_path);
818 if (!stabs_same_inode(&now_stab, &initial_stab))
823 // On entry, stderr is still inherited, but 0 and 1 are the pipes
824 static __attribute__((noreturn))
825 void become_watcher(void) {
827 uv_poll_t uvhandle_stdin;
828 uv_fs_event_t uvhandle_sockpath;
833 errno= -uv_loop_init(&loop);
834 if (errno) diee("watcher: uv_loop_init");
836 errno= -uv_poll_init(&loop, &uvhandle_stdin, 0);
837 if (errno) diee("watcher: uv_poll_init");
838 errno= -uv_poll_start(&uvhandle_stdin,
839 UV_READABLE | UV_WRITABLE | UV_DISCONNECT,
841 if (errno) diee("watcher: uv_poll_start");
843 errno= -uv_fs_event_init(&loop, &uvhandle_sockpath);
844 if (errno) diee("watcher: uv_fs_event_init");
846 errno= -uv_fs_event_start(&uvhandle_sockpath, watcher_cb_sockpath,
848 if (errno) diee("watcher: uv_fs_event_start");
850 // OK everything is set up, let us daemonise
851 if (dup2(1,2) != 2) diee("watcher: set daemonised stderr");
852 r= setvbuf(stderr, 0, _IOLBF, BUFSIZ);
853 if (r) diee("watcher: setvbuf stderr");
855 pid_t child = fork();
856 if (child == (pid_t)-1) diee("watcher: fork");
859 if (setsid() == (pid_t)-1) diee("watcher: setsid");
861 r= uv_run(&loop, UV_RUN_DEFAULT);
862 die("uv_run returned (%d)", r);
865 static __attribute__((noreturn))
866 void become_setup(int sfd, int lockfd, int fake_pair[2],
867 int watcher_stdin, int watcher_stderr) {
870 int call_fd = fake_pair[1];
872 int null_0 = open("/dev/null", O_RDONLY); if (null_0 < 0) diee("open null");
873 if (dup2(null_0, 0)) diee("dup2 /dev/null onto stdin");
875 if (dup2(2, 1) != 1) die("dup2 stderr onto stdout");
879 // Extension could work like this:
881 // We could advertise a new protocol (perhaps one which is nearly entirely
882 // different after the connect) by putting a name for it comma-separated
883 // next to "v1". Simple extension can be done by having the script
884 // side say something about it in the ack xdata, which we currently ignore.
885 // Or we could add other extra data after v1.
886 putenv(m_asprintf("PREFORK_INTERP=v1,%jd.%09ld %d,%d,%d,%d",
887 (intmax_t)initial_stab.st_mtim.tv_sec,
888 (long)initial_stab.st_mtim.tv_nsec,
889 sfd, call_fd, watcher_stdin, watcher_stderr));
891 execvp(executor_argv[0], (char**)executor_argv);
892 diee("execute %s", executor_argv[0]);
895 static void connect_or_spawn(void) {
898 call_sock = connect_existing();
899 if (call_sock) return;
901 // We're going to make a new one, so clean out old ones
904 int lockfd = acquire_lock();
906 if (mode == MODE_KILL) {
907 r= unlink(socket_path);
908 if (r && errno != ENOENT) diee("remove socket %s", socket_path);
910 r= unlink(lock_path);
911 if (r) diee("rmeove lock %s", lock_path);
915 call_sock = connect_existing();
916 if (call_sock) { close(lockfd); return; }
918 // We must start a fresh one, and we hold the lock
920 r = unlink(socket_path);
921 if (r<0 && errno!=ENOENT)
922 diee("failed to remove stale socket %s", socket_path);
924 int sfd = socket(AF_UNIX, SOCK_STREAM, 0);
925 if (sfd<0) diee("socket() for new listener");
927 socklen_t salen = sizeof(sockaddr_sun);
928 r= bind(sfd, (const struct sockaddr*)&sockaddr_sun, salen);
929 if (r<0) diee("bind() on new listener");
931 r= stat(socket_path, &initial_stab);
932 if (r<0) diee("stat() fresh socket");
934 // We never want callers to get ECONNREFUSED. But:
935 // There is a race here: from my RTFM they may get ECONNREFUSED
936 // if they try between our bind() and listen(). But if they do, they'll
937 // acquire the lock (serialising with us) and retry, and then it will work.
938 r = listen(sfd, INT_MAX);
939 if (r<0) diee("listen() for new listener");
943 int watcher_stdin[2];
944 int watcher_stderr[2];
945 if (pipe(watcher_stdin) || pipe(watcher_stderr))
946 diee("pipe() for socket inode watcher");
948 pid_t watcher = fork();
949 if (watcher == (pid_t)-1) diee("fork for watcher");
953 close(watcher_stdin[1]);
954 close(watcher_stderr[0]);
955 if (dup2(watcher_stdin[0], 0) != 0 ||
956 dup2(watcher_stderr[1], 1) != 1)
957 diee("initial dup2() for watcher");
958 close(watcher_stdin[0]);
959 close(watcher_stderr[1]);
963 close(watcher_stdin[0]);
964 close(watcher_stderr[1]);
965 nonblock(watcher_stderr[0]);
970 r = socketpair(AF_UNIX, SOCK_STREAM, 0, fake_pair);
971 if (r<0) diee("socketpair() for fake initial connection");
973 pid_t setup_pid = fork();
974 if (setup_pid == (pid_t)-1) diee("fork for spawn setup");
975 if (!setup_pid) become_setup(sfd, lockfd, fake_pair,
976 watcher_stdin[1], watcher_stderr[0]);
980 call_sock = call_sock_from_fd(fake_pair[0]);
983 pid_t got = waitpid(setup_pid, &status, 0);
984 if (got == (pid_t)-1) diee("waitpid setup [%ld]", (long)setup_pid);
985 if (got != setup_pid) diee("waitpid setup [%ld] gave [%ld]!",
986 (long)setup_pid, (long)got);
987 if (status != 0) propagate_exit_status(status, "setup");
989 const char *emsg = read_greeting();
990 if (emsg) die("setup failed: %s", emsg);
996 static void make_executor_argv(const char *const *argv) {
998 case MEDIATION_UNLAUNDERED: break;
999 default: die("need -U (specifying unlaundered argument handling)");
1003 #define EACH_NEW_ARG(EACH) { \
1004 arg = interp; { EACH } \
1005 if ((arg = script)) { EACH } \
1006 const char *const *walk = argv; \
1007 while ((arg = *walk++)) { EACH } \
1011 EACH_NEW_ARG( (void)arg; count++; );
1013 const char **out = calloc(count, sizeof(char*));
1014 executor_argv = (const char* const*)out;
1015 if (!executor_argv) diee("allocate for arguments");
1017 EACH_NEW_ARG( *out++ = arg; );
1021 int main(int argc_unused, const char *const *argv) {
1022 process_opts(&argv);
1025 // - possibly interp
1026 // - possibly script
1028 // which ought to be passed on to the actual executor.
1029 make_executor_argv(argv);
1032 FILLZERO(sockaddr_sun);
1033 sockaddr_sun.sun_family = AF_UNIX;
1034 assert(strlen(socket_path) <= sizeof(sockaddr_sun.sun_path));
1035 strncpy(sockaddr_sun.sun_path, socket_path, sizeof(sockaddr_sun.sun_path));
1039 // We're committed now, send the request (or bail out)
1043 protocol_read(&status, sizeof(status));
1045 status = ntohl(status);
1046 if (status > INT_MAX) die("status 0x%lx does not fit in an int",
1047 (unsigned long)status);
1049 propagate_exit_status(status, "invocation");