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)) {
451 _exit(WEXITSTATUS(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) &&
467 sa.sa_handler = SIG_DFL;
468 if (sig != SIGKILL) {
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",
482 die("unexpectedly kept running after raising (to propagate) %s",
486 die("%s failed due to signal %d %s%s", what, sig, signame,
487 WCOREDUMP(status) ? " (core dumped)" : "");
490 die("%s failed with weird wait status %d 0x%x", what, status, status);
498 static int preclean_entry_compar_name(const void *av, const void *bv) {
499 const PrecleanEntry *a = av;
500 const PrecleanEntry *b = bv;
501 return strcmp(a->name_hash, b->name_hash);
504 static int preclean_entry_compar_atime(const void *av, const void *bv) {
505 const PrecleanEntry *ae = av; time_t a = ae->atime;
506 const PrecleanEntry *be = bv; time_t b = be->atime;
511 static time_t preclean_stat_atime(const char *s_path) {
513 int r= lstat(s_path, &stab);
515 if (errno!=ENOENT) diee("pre-cleanup: stat socket (%s)", s_path);
518 return stab.st_atime;
521 static void preclean(void) {
522 DIR *dir = opendir(run_base);
524 if (errno == ENOENT) return;
525 diee("pre-cleanup: open run dir (%s)", run_base);
528 PrecleanEntry *entries=0;
529 size_t avail_entries=0;
530 size_t used_entries=0;
533 while ((errno = 0, de = readdir(dir))) {
534 char c0 = de->d_name[0];
535 if (!(c0 == 'l' || c0 == 's')) continue;
536 char *name_hash = m_asprintf("%s", de->d_name+1);
537 char *s_path = m_asprintf("%s/s%s", run_base, name_hash);
538 time_t atime = preclean_stat_atime(s_path);
540 if (avail_entries == used_entries) {
541 assert(avail_entries < INT_MAX / 4 / sizeof(PrecleanEntry));
544 entries = realloc(entries, avail_entries * sizeof(PrecleanEntry));
546 entries[used_entries].name_hash = name_hash;
547 entries[used_entries].atime = atime;
550 if (errno) diee("pre-cleanup: read run dir (%s)", run_base);
552 // First we dedupe (after sorting by path)
553 qsort(entries, used_entries, sizeof(PrecleanEntry),
554 preclean_entry_compar_name);
555 PrecleanEntry *p, *q;
556 for (p=entries, q=entries; p < entries + used_entries; p++) {
557 if (q > entries && !strcmp(p->name_hash, (q-1)->name_hash))
561 used_entries = q - entries;
563 // Now maybe delete some things
565 // Actually this has an off-by-one error since we are about
566 // to create a socket, so the actual number of sockets is one more.
567 // But, *actually*, since there might be multiple of us running at once,
568 // we might have even more than that. This doesn't really matter.
569 if (used_entries > max_sockets) {
570 qsort(entries, used_entries, sizeof(PrecleanEntry),
571 preclean_entry_compar_atime);
572 for (p=entries; p < entries + max_sockets; p++) {
573 char *l_path = m_asprintf("%s/l%s", run_base, p->name_hash);
574 char *s_path = m_asprintf("%s/s%s", run_base, p->name_hash);
575 int lock_fd = flock_file(l_path);
576 // Recheck atime - we might have raced!
577 time_t atime = preclean_stat_atime(s_path);
578 if (atime != p->atime) {
579 // Raced. This will leave use deleting too few things. Whatever.
581 int r= unlink(s_path);
582 if (r && errno!=ENOENT) diee("preclean: delete stale (%s)", s_path);
584 if (r) diee("preclean: delete stale lock (%s)", s_path);
585 // NB we don't hold the lock any more now.
593 for (p=entries; p < entries + used_entries; p++)
598 static __attribute((noreturn)) void die_data_overflow(void) {
599 die("cannot handle data with length >2^32");
602 static void prepare_data(size_t *len, char **buf,
603 const void *data, size_t dl) {
605 if (dl >= SIZE_MAX - *len)
610 memcpy(*buf, data, dl);
615 static void prepare_length(size_t *len, char **buf, size_t dl_sz) {
616 if (dl_sz > UINT32_MAX) die_data_overflow();
617 uint32_t dl = htonl(dl_sz);
618 prepare_data(len, buf, &dl, sizeof(dl));
621 static void prepare_string(size_t *len, char **buf, const char *s) {
622 size_t sl = strlen(s);
623 prepare_data(len, buf, s, sl+1);
626 static void prepare_message(size_t *len, char **buf) {
629 const char *const *p = (void*)environ;
632 prepare_string(len, buf, s);
635 prepare_string(len, buf, "");
639 prepare_string(len, buf, s);
642 static void send_fd(int payload_fd) {
643 int via_fd = fileno(call_sock);
646 struct cmsghdr align;
647 char buf[CMSG_SPACE(sizeof(payload_fd))];
657 iov.iov_base = &dummy_byte;
663 msg.msg_control = cmsg_buf.buf;
664 msg.msg_controllen = sizeof(cmsg_buf.buf);
666 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
667 cmsg->cmsg_level = SOL_SOCKET;
668 cmsg->cmsg_type = SCM_RIGHTS;
669 cmsg->cmsg_len = CMSG_LEN(sizeof(payload_fd));
670 *(int*)CMSG_DATA(cmsg) = payload_fd;
672 msg.msg_controllen = sizeof(cmsg_buf.buf);
675 ssize_t r = sendmsg(via_fd, &msg, 0);
677 if (errno == EINTR) continue;
685 static void send_request(void) {
687 ssize_t sr = fwrite(&ibyte, 1, 1, call_sock);
688 if (sr != 1) diee("write signalling byte");
690 // Sending these before the big message makes it easier for the script to
691 // use buffered IO for the message.
697 prepare_message(&len, 0);
699 size_t tlen = len + 4;
700 char *m = xmalloc(tlen);
702 prepare_length(0, &p, len);
703 prepare_message(0, &p);
704 assert(p == m + tlen);
706 sr = fwrite(m, tlen, 1, call_sock);
707 if (sr != 1) diee("write request (buffer)");
709 if (fflush(call_sock)) diee("write request");
712 static FILE *call_sock_from_fd(int fd) {
715 FILE *call_sock = fdopen(fd, "r+");
716 if (!call_sock) diee("fdopen socket");
718 r = setvbuf(call_sock, 0, _IONBF, 0);
719 if (r) die("setvbuf socket");
724 static bool was_eof(FILE *call_sock) {
725 return feof(call_sock) || errno==ECONNRESET;
729 static int protocol_read_maybe(void *data, size_t sz) {
731 size_t sr = fread(data, sz, 1, call_sock);
733 if (was_eof(call_sock)) return -1;
734 diee("read() on monitor call socket (%zd)", sz);
739 static void protocol_read(void *data, size_t sz) {
740 if (protocol_read_maybe(data, sz) < 0)
741 die("monitor process quit unexpectedly");
744 // Returns 0 if OK, error msg if peer was garbage.
745 static const char *read_greeting(void) {
746 char got_magic[sizeof(header_magic)];
748 if (protocol_read_maybe(&got_magic, sizeof(got_magic)) < 0)
749 return "initial monitor process quit"
750 " (maybe script didn't call preform_initialisation_complete?)";
752 if (memcmp(got_magic, header_magic, sizeof(header_magic)))
753 die("got unexpected protocol magic 0x%02x%02x%02x%02x",
754 got_magic[0], got_magic[1], got_magic[2], got_magic[3]);
757 protocol_read(&xdata_len, sizeof(xdata_len));
758 void *xdata = xmalloc(xdata_len);
759 protocol_read(xdata, xdata_len);
764 // Returns: call(client-end), or 0 to mean "is garbage"
765 // find_socket_path must have been called
766 static FILE *connect_existing(void) {
770 if (mode != MODE_NORMAL) return 0;
772 fd = socket(AF_UNIX, SOCK_STREAM, 0);
773 if (fd==-1) diee("socket() for client");
775 socklen_t salen = sizeof(sockaddr_sun);
776 r = connect(fd, (const struct sockaddr*)&sockaddr_sun, salen);
778 if (errno==ECONNREFUSED || errno==ENOENT) goto x_garbage;
779 diee("connect() %s", socket_path);
782 call_sock = call_sock_from_fd(fd);
791 if (call_sock) { fclose(call_sock); call_sock=0; }
792 if (fd >= 0) close(fd);
796 static void watcher_cb_stdin(uv_poll_t *handle, int status, int events) {
800 if ((errno = -status)) diee("watcher: poll stdin");
804 if (!(errno==EINTR || errno==EWOULDBLOCK || errno==EAGAIN))
805 diee("watcher: read sentinel stdin");
809 static void watcher_cb_sockpath(uv_fs_event_t *handle, const char *filename,
810 int events, int status) {
812 struct stat now_stab;
814 if ((errno = -status)) diee("watcher: poll stdin");
816 r= stat(socket_path, &now_stab);
818 if (errno==ENOENT) _exit(0);
819 if (errno==EINTR) continue;
820 diee("stat socket: %s", socket_path);
822 if (!stabs_same_inode(&now_stab, &initial_stab))
827 // On entry, stderr is still inherited, but 0 and 1 are the pipes
828 static __attribute__((noreturn))
829 void become_watcher(void) {
831 uv_poll_t uvhandle_stdin;
832 uv_fs_event_t uvhandle_sockpath;
837 errno= -uv_loop_init(&loop);
838 if (errno) diee("watcher: uv_loop_init");
840 errno= -uv_poll_init(&loop, &uvhandle_stdin, 0);
841 if (errno) diee("watcher: uv_poll_init");
842 errno= -uv_poll_start(&uvhandle_stdin,
843 UV_READABLE | UV_WRITABLE | UV_DISCONNECT,
845 if (errno) diee("watcher: uv_poll_start");
847 errno= -uv_fs_event_init(&loop, &uvhandle_sockpath);
848 if (errno) diee("watcher: uv_fs_event_init");
850 errno= -uv_fs_event_start(&uvhandle_sockpath, watcher_cb_sockpath,
852 if (errno) diee("watcher: uv_fs_event_start");
854 // OK everything is set up, let us daemonise
855 if (dup2(1,2) != 2) diee("watcher: set daemonised stderr");
856 r= setvbuf(stderr, 0, _IOLBF, BUFSIZ);
857 if (r) diee("watcher: setvbuf stderr");
859 pid_t child = fork();
860 if (child == (pid_t)-1) diee("watcher: fork");
863 if (setsid() == (pid_t)-1) diee("watcher: setsid");
865 r= uv_run(&loop, UV_RUN_DEFAULT);
866 die("uv_run returned (%d)", r);
869 static __attribute__((noreturn))
870 void become_setup(int sfd, int lockfd, int fake_pair[2],
871 int watcher_stdin, int watcher_stderr) {
874 int call_fd = fake_pair[1];
876 int null_0 = open("/dev/null", O_RDONLY); if (null_0 < 0) diee("open null");
877 if (dup2(null_0, 0)) diee("dup2 /dev/null onto stdin");
879 if (dup2(2, 1) != 1) die("dup2 stderr onto stdout");
883 // Extension could work like this:
885 // We could advertise a new protocol (perhaps one which is nearly entirely
886 // different after the connect) by putting a name for it comma-separated
887 // next to "v1". Simple extension can be done by having the script
888 // side say something about it in the ack xdata, which we currently ignore.
889 // Or we could add other extra data after v1.
890 putenv(m_asprintf("PREFORK_INTERP=v1,%jd.%09ld %d,%d,%d,%d",
891 (intmax_t)initial_stab.st_mtim.tv_sec,
892 (long)initial_stab.st_mtim.tv_nsec,
893 sfd, call_fd, watcher_stdin, watcher_stderr));
895 execvp(executor_argv[0], (char**)executor_argv);
896 diee("execute %s", executor_argv[0]);
899 static void connect_or_spawn(void) {
902 call_sock = connect_existing();
903 if (call_sock) return;
905 // We're going to make a new one, so clean out old ones
908 int lockfd = acquire_lock();
910 if (mode == MODE_KILL) {
911 r= unlink(socket_path);
912 if (r && errno != ENOENT) diee("remove socket %s", socket_path);
914 r= unlink(lock_path);
915 if (r) diee("rmeove lock %s", lock_path);
919 call_sock = connect_existing();
920 if (call_sock) { close(lockfd); return; }
922 // We must start a fresh one, and we hold the lock
924 r = unlink(socket_path);
925 if (r<0 && errno!=ENOENT)
926 diee("failed to remove stale socket %s", socket_path);
928 int sfd = socket(AF_UNIX, SOCK_STREAM, 0);
929 if (sfd<0) diee("socket() for new listener");
931 socklen_t salen = sizeof(sockaddr_sun);
932 r= bind(sfd, (const struct sockaddr*)&sockaddr_sun, salen);
933 if (r<0) diee("bind() on new listener");
935 r= stat(socket_path, &initial_stab);
936 if (r<0) diee("stat() fresh socket");
938 // We never want callers to get ECONNREFUSED. But:
939 // There is a race here: from my RTFM they may get ECONNREFUSED
940 // if they try between our bind() and listen(). But if they do, they'll
941 // acquire the lock (serialising with us) and retry, and then it will work.
942 r = listen(sfd, INT_MAX);
943 if (r<0) diee("listen() for new listener");
947 int watcher_stdin[2];
948 int watcher_stderr[2];
949 if (pipe(watcher_stdin) || pipe(watcher_stderr))
950 diee("pipe() for socket inode watcher");
952 pid_t watcher = fork();
953 if (watcher == (pid_t)-1) diee("fork for watcher");
957 close(watcher_stdin[1]);
958 close(watcher_stderr[0]);
959 if (dup2(watcher_stdin[0], 0) != 0 ||
960 dup2(watcher_stderr[1], 1) != 1)
961 diee("initial dup2() for watcher");
962 close(watcher_stdin[0]);
963 close(watcher_stderr[1]);
967 close(watcher_stdin[0]);
968 close(watcher_stderr[1]);
969 nonblock(watcher_stderr[0]);
974 r = socketpair(AF_UNIX, SOCK_STREAM, 0, fake_pair);
975 if (r<0) diee("socketpair() for fake initial connection");
977 pid_t setup_pid = fork();
978 if (setup_pid == (pid_t)-1) diee("fork for spawn setup");
979 if (!setup_pid) become_setup(sfd, lockfd, fake_pair,
980 watcher_stdin[1], watcher_stderr[0]);
984 call_sock = call_sock_from_fd(fake_pair[0]);
987 pid_t got = waitpid(setup_pid, &status, 0);
988 if (got == (pid_t)-1) diee("waitpid setup [%ld]", (long)setup_pid);
989 if (got != setup_pid) diee("waitpid setup [%ld] gave [%ld]!",
990 (long)setup_pid, (long)got);
991 if (status != 0) propagate_exit_status(status, "setup");
993 const char *emsg = read_greeting();
994 if (emsg) die("setup failed: %s", emsg);
1000 static void make_executor_argv(const char *const *argv) {
1001 switch (mediation) {
1002 case MEDIATION_UNLAUNDERED: break;
1003 default: die("need -U (specifying unlaundered argument handling)");
1007 #define EACH_NEW_ARG(EACH) { \
1008 arg = interp; { EACH } \
1009 if ((arg = script)) { EACH } \
1010 const char *const *walk = argv; \
1011 while ((arg = *walk++)) { EACH } \
1015 EACH_NEW_ARG( (void)arg; count++; );
1017 const char **out = calloc(count, sizeof(char*));
1018 executor_argv = (const char* const*)out;
1019 if (!executor_argv) diee("allocate for arguments");
1021 EACH_NEW_ARG( *out++ = arg; );
1025 int main(int argc_unused, const char *const *argv) {
1026 process_opts(&argv);
1029 // - possibly interp
1030 // - possibly script
1032 // which ought to be passed on to the actual executor.
1033 make_executor_argv(argv);
1036 FILLZERO(sockaddr_sun);
1037 sockaddr_sun.sun_family = AF_UNIX;
1038 assert(strlen(socket_path) <= sizeof(sockaddr_sun.sun_path));
1039 strncpy(sockaddr_sun.sun_path, socket_path, sizeof(sockaddr_sun.sun_path));
1043 // We're committed now, send the request (or bail out)
1047 protocol_read(&status, sizeof(status));
1049 status = ntohl(status);
1050 if (status > INT_MAX) die("status 0x%lx does not fit in an int",
1051 (unsigned long)status);
1053 propagate_exit_status(status, "invocation");