diff options
Diffstat (limited to 'src/couchdb')
-rw-r--r-- | src/couchdb/Makefile.am | 50 | ||||
-rwxr-xr-x | src/couchdb/priv/couchspawnkillable.sh (renamed from src/couchdb/priv/couchspawnkillable) | 0 | ||||
-rw-r--r-- | src/couchdb/priv/couchspawnkillable_win.c | 139 |
3 files changed, 180 insertions, 9 deletions
diff --git a/src/couchdb/Makefile.am b/src/couchdb/Makefile.am index 7d7b1720..89a0c7f2 100644 --- a/src/couchdb/Makefile.am +++ b/src/couchdb/Makefile.am @@ -13,6 +13,11 @@ SUBDIRS = priv ICU_LOCAL_FLAGS = $(ICU_LOCAL_CFLAGS) $(ICU_LOCAL_LDFLAGS) +if WINDOWS +ICU_LOCAL_LIBS=-licuuc -licudt -licuin +else +ICU_LOCAL_LIBS=-licuuc -licudata -licui18n +endif # devdocdir = $(localdocdir)/developer/couchdb couchlibdir = $(localerlanglibdir)/couch-$(version) @@ -25,19 +30,28 @@ couchprivlib_LTLIBRARIES = couch_erl_driver.la couch_erl_driver_la_SOURCES = couch_erl_driver.c couch_erl_driver_la_LDFLAGS = -module -avoid-version $(ICU_LOCAL_FLAGS) couch_erl_driver_la_CFLAGS = $(ICU_LOCAL_FLAGS) -couch_erl_driver_la_LIBADD = -licuuc -licudata -licui18n +couch_erl_driver_la_LIBADD = $(ICU_LOCAL_LIBS) locallibbin_PROGRAMS = couchjs couchjs_SOURCES = couch_js.c curlhelper.c curlhelper.h -couchjs_LDLAGS = $(CURL_LDLAGS) +couchjs_LDFLAGS = $(CURL_LDFLAGS) couchjs_CFLAGS = $(CURL_CFLAGS) -couchjs_LDADD = -lcurl +couchjs_LDADD = $(CURL_LDFLAGS) + +if WINDOWS +priv_couchspawnkillable_win_SOURCES = priv/couchspawnkillable_win.c +couchpriv_PROGRAMS = priv/couchspawnkillable_win +couch_erl_driver_la_LDFLAGS += -no-undefined + +# copy ICU dlls for the erlang driver +dist_couch_erl_driver_la_DATA=$(ICU_LOCAL_BIN)/icuuc42.dll $(ICU_LOCAL_BIN)/icudt42.dll $(ICU_LOCAL_BIN)/icuin42.dll +couch_erl_driver_ladir=$(bindir) +endif couchinclude_DATA = couch_db.hrl couchebin_DATA = $(compiled_files) -couchpriv_SCRIPTS = priv/couchspawnkillable # dist_devdoc_DATA = $(doc_base) $(doc_modules) @@ -98,6 +112,7 @@ source_files = \ EXTRA_DIST = $(source_files) couch_db.hrl couch_stats.hrl compiled_files = \ + priv/couchspawnkillable \ couch.app \ couch_btree.beam \ couch_batch_save.beam \ @@ -191,14 +206,31 @@ couch.app: couch.app.tpl %.beam: %.erl couch_db.hrl $(ERLC) $(ERLC_FLAGS) ${TEST} $<; +if WINDOWS +priv/couchspawnkillable: priv/couchspawnkillable_win + cp $< $@ +else +priv/couchspawnkillable: priv/couchspawnkillable.sh + cp $< $@ +endif + install-data-hook: - if test -f "$(DESTDIR)/$(couchprivlibdir)/couch_erl_driver"; then \ - rm -f "$(DESTDIR)/$(couchprivlibdir)/couch_erl_driver.so"; \ - cd "$(DESTDIR)/$(couchprivlibdir)" && \ + if test -f "$(DESTDIR)$(couchprivlibdir)/couch_erl_driver"; then \ + rm -f "$(DESTDIR)$(couchprivlibdir)/couch_erl_driver.so"; \ + cd "$(DESTDIR)$(couchprivlibdir)" && \ $(LN_S) couch_erl_driver couch_erl_driver.so; \ fi +if WINDOWS +# libtool and automake have defeated markh. For each of our executables +# we end up with 2 copies - one directly in the 'target' folder (eg, 'priv') +# and another - the correct one - in .libs. The former doesn't work but is +# what gets installed for 'couchspawnkillable' - but the correct one for +# couchjs.exe *does* get copied. *shrug* So just clobber it with the +# correct one here... See bug COUCHDB-439 + $(INSTALL) priv/.libs/couchspawnkillable_win.exe "$(DESTDIR)$(couchprivdir)/couchspawnkillable.exe" +endif uninstall-local: - if test -f "$(DESTDIR)/$(couchprivlibdir)/couch_erl_driver"; then \ - rm -f "$(DESTDIR)/$(couchprivlibdir)/couch_erl_driver.so"; \ + if test -f "$(DESTDIR)$(couchprivlibdir)/couch_erl_driver"; then \ + rm -f "$(DESTDIR)$(couchprivlibdir)/couch_erl_driver.so"; \ fi diff --git a/src/couchdb/priv/couchspawnkillable b/src/couchdb/priv/couchspawnkillable.sh index f8d042e3..f8d042e3 100755 --- a/src/couchdb/priv/couchspawnkillable +++ b/src/couchdb/priv/couchspawnkillable.sh diff --git a/src/couchdb/priv/couchspawnkillable_win.c b/src/couchdb/priv/couchspawnkillable_win.c new file mode 100644 index 00000000..f812711e --- /dev/null +++ b/src/couchdb/priv/couchspawnkillable_win.c @@ -0,0 +1,139 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +// Do what 2 lines of shell script in couchspawnkillable does... +// * Create a new suspended process with the same (duplicated) standard +// handles as us. +// * Write a line to stdout, consisting of the path to ourselves, plus +// '--kill {pid}' where {pid} is the PID of the newly created process. +// * Un-suspend the new process. +// * Terminate + +// Later, couch will call us with --kill and the PID, so we dutifully +// terminate the specified PID. + +#include <stdlib.h> +#include "windows.h" + +char *get_child_cmdline(int argc, char **argv) +{ + // make a new command-line, but skipping me. + // XXX - todo - spaces etc in args??? + int i; + char *p, *cmdline; + int nchars = 0; + int nthis = 1; + for (i=1;i<argc;i++) + nchars += strlen(argv[i])+1; + cmdline = p = malloc(nchars+1); + if (!cmdline) + return NULL; + for (i=1;i<argc;i++) { + nthis = strlen(argv[i]); + strncpy(p, argv[i], nthis); + p[nthis] = ' '; + p += nthis+1; + } + // Replace the last space we added above with a '\0' + cmdline[nchars-1] = '\0'; + return cmdline; +} + +// create the child process, returning 0, or the exit-code we will +// terminate with. +int create_child(int argc, char **argv, PROCESS_INFORMATION *pi) +{ + char buf[1024]; + DWORD dwcreate; + STARTUPINFO si; + char *cmdline; + if (argc < 2) + return 1; + cmdline = get_child_cmdline(argc, argv); + if (!cmdline) + return 2; + + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + // depending on how *our* parent is started, we may or may not have + // a valid stderr stream - so although we try and duplicate it, only + // failing to duplicate stdin and stdout are considered fatal. + if (!DuplicateHandle(GetCurrentProcess(), + GetStdHandle(STD_INPUT_HANDLE), + GetCurrentProcess(), + &si.hStdInput, + 0, + TRUE, // inheritable + DUPLICATE_SAME_ACCESS) || + !DuplicateHandle(GetCurrentProcess(), + GetStdHandle(STD_OUTPUT_HANDLE), + GetCurrentProcess(), + &si.hStdOutput, + 0, + TRUE, // inheritable + DUPLICATE_SAME_ACCESS)) { + return 3; + } + DuplicateHandle(GetCurrentProcess(), + GetStdHandle(STD_ERROR_HANDLE), + GetCurrentProcess(), + &si.hStdError, + 0, + TRUE, // inheritable + DUPLICATE_SAME_ACCESS); + + si.dwFlags = STARTF_USESTDHANDLES; + dwcreate = CREATE_SUSPENDED; + if (!CreateProcess( NULL, cmdline, + NULL, + NULL, + TRUE, // inherit handles + dwcreate, + NULL, // environ + NULL, // cwd + &si, + pi)) + return 4; + return 0; +} + +// and here we go... +int main(int argc, char **argv) +{ + char out_buf[1024]; + int rc; + DWORD cbwritten; + PROCESS_INFORMATION pi; + if (argc==3 && strcmp(argv[1], "--kill")==0) { + HANDLE h = OpenProcess(PROCESS_TERMINATE, 0, atoi(argv[2])); + if (!h) + return 1; + if (!TerminateProcess(h, 0)) + return 2; + CloseHandle(h); + return 0; + } + // spawn the new suspended process + rc = create_child(argc, argv, &pi); + if (rc) + return rc; + // Write the 'terminate' command, which includes this PID, back to couch. + // *sob* - what about spaces etc? + sprintf_s(out_buf, sizeof(out_buf), "%s --kill %d\n", + argv[0], pi.dwProcessId); + WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), out_buf, strlen(out_buf), + &cbwritten, NULL); + // Let the child process go... + ResumeThread(pi.hThread); + // and that is all - we can die... + return 0; +} |