summaryrefslogtreecommitdiff
path: root/vere/pkg/vere/platform/windows/daemon.c
diff options
context:
space:
mode:
Diffstat (limited to 'vere/pkg/vere/platform/windows/daemon.c')
-rw-r--r--vere/pkg/vere/platform/windows/daemon.c116
1 files changed, 116 insertions, 0 deletions
diff --git a/vere/pkg/vere/platform/windows/daemon.c b/vere/pkg/vere/platform/windows/daemon.c
new file mode 100644
index 0000000..e08b945
--- /dev/null
+++ b/vere/pkg/vere/platform/windows/daemon.c
@@ -0,0 +1,116 @@
+#include "noun.h"
+#include "vere.h"
+
+/* _dup_std_handle(): creates an inheritable duplicate of a standard handle.
+*/
+static BOOL
+_dup_std_handle(HANDLE* new_u, DWORD typ_u)
+{
+ DWORD dum_u;
+ HANDLE han_u = GetStdHandle(typ_u);
+ BOOL con_u = GetConsoleMode(han_u, &dum_u);
+ if ( con_u ) {
+ han_u = (HANDLE)_get_osfhandle(c3_open(c3_dev_null, O_RDWR, 0));
+ }
+
+ if ( !DuplicateHandle(GetCurrentProcess(), han_u, GetCurrentProcess(), new_u, 0, TRUE, DUPLICATE_SAME_ACCESS) ) {
+ fprintf(stderr, "vere: DuplicateHandle(%lu): %lu\r\n", typ_u, GetLastError());
+ exit(1);
+ }
+
+ return con_u;
+}
+
+/* _on_boot_completed_cb: invoked when the ship has finished booting.
+*/
+static void _on_boot_completed_cb() {
+ HANDLE hin_u = GetStdHandle(STD_INPUT_HANDLE);
+ SetEvent(hin_u);
+ CloseHandle(hin_u);
+}
+
+/* u3_daemon_init(): platform-specific daemon mode initialization.
+*/
+void
+u3_daemon_init()
+{
+ // detect if this process is the child daemon process
+ //
+ if ( ResetEvent(GetStdHandle(STD_INPUT_HANDLE)) ) {
+ u3_Host.bot_f = _on_boot_completed_cb;
+ return;
+ }
+
+ STARTUPINFOW psi_u;
+ ZeroMemory(&psi_u, sizeof(psi_u));
+ psi_u.cb = sizeof(psi_u);
+ psi_u.dwFlags = STARTF_USESTDHANDLES;
+
+ // duplicate standard output and error handles for the child process,
+ // replacing any raw console handles with handles to /dev/null
+ // print a warning if raw console output detected
+ //
+ // On Windows, console handles become invalid once the console is
+ // detached. This will cause urbit terminal output to fail. libuv
+ // provides no way of changing the handle of an open uv_pipe_handle,
+ // and Windows has no equivalent of dup2() for handles, so I cannot
+ // substitute a /dev/null handle once the terminal is initialized.
+ // It is possible to create an anonymous pipe and have the child
+ // process take over its drain end after it signals that the ship
+ // has booted, but -d is intended for background operation anyway
+ // and does not seem to warrant the added complexity.
+ //
+ if ( _dup_std_handle(&psi_u.hStdOutput, STD_OUTPUT_HANDLE) |
+ _dup_std_handle(&psi_u.hStdError, STD_ERROR_HANDLE) )
+ {
+ fprintf(stderr, "vere: -d used from a Windows console without redirection\r\n"
+ " no output from the daemon process will be visible\r\n");
+ fflush(stderr);
+ }
+
+ // create an event for the child process to signal
+ // the parent that the ship has finished booting
+ // pass the handle as "stdin" (otherwise unused with -d)
+ //
+ SECURITY_ATTRIBUTES sa_u = {sizeof (SECURITY_ATTRIBUTES), NULL, TRUE};
+ if ( !(psi_u.hStdInput = CreateEvent(&sa_u, TRUE, FALSE, NULL)) ) {
+ fprintf(stderr, "vere: CreateEvent: %lu\r\n", GetLastError());
+ exit(1);
+ }
+
+ // create the child process with the same command line as parent
+ // it will start, re-parse the command line, and call u3_daemon_init
+ //
+ PROCESS_INFORMATION ppi_u;
+ if ( !CreateProcessW(NULL, _wcsdup(GetCommandLineW()), NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &psi_u, &ppi_u) ) {
+ fprintf(stderr, "vere: CreateProcess: %lu\r\n", GetLastError());
+ exit(1);
+ }
+
+ CloseHandle(ppi_u.hThread);
+
+ // wait for the child process to exit or to signal the event
+ //
+ DWORD exi_u;
+ HANDLE han_u[2] = {ppi_u.hProcess, psi_u.hStdInput};
+ switch ( WaitForMultipleObjects(2, han_u, FALSE, INFINITE) ) {
+ case WAIT_OBJECT_0:
+ // the child process exited prematurely, propagate its exit code
+ //
+ if ( GetExitCodeProcess(ppi_u.hProcess, &exi_u) ) {
+ exit(exi_u);
+ }
+
+ fprintf(stderr, "vere: GetExitCodeProcess: %lu\r\n", GetLastError());
+ exit(1);
+
+ case WAIT_OBJECT_0 + 1:
+ // the child process has finished booting, exit normally
+ //
+ exit(0);
+
+ default:
+ fprintf(stderr, "vere: WaitForMultipleObjects: %lu\r\n", GetLastError());
+ exit(1);
+ }
+}