summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Faylor <cgf@redhat.com>2004-01-20 19:57:29 +0000
committerChristopher Faylor <cgf@redhat.com>2004-01-20 19:57:29 +0000
commitc78dc94cc5c939c6a5a6c4dd43e822d54a5f1526 (patch)
treed180fc923ee81166ebdc33735109cbf645d46d5c
parent69a7b5f79888513741e65a54216d7756474b76c2 (diff)
downloadgdb-c78dc94cc5c939c6a5a6c4dd43e822d54a5f1526.tar.gz
merge from trunk.
-rw-r--r--winsup/cygwin/Makefile.in451
-rw-r--r--winsup/cygwin/dcrt0.cc1180
-rw-r--r--winsup/cygwin/sec_acl.cc1042
-rw-r--r--winsup/cygwin/sigproc.cc1276
-rw-r--r--winsup/cygwin/wincap.h121
5 files changed, 4070 insertions, 0 deletions
diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in
new file mode 100644
index 00000000000..5cbe318a1b2
--- /dev/null
+++ b/winsup/cygwin/Makefile.in
@@ -0,0 +1,451 @@
+# Makefile.in for Cygwin.
+# Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
+#
+# This file is part of Cygwin.
+#
+# This software is a copyrighted work licensed under the terms of the
+# Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+# details.
+
+# This makefile requires GNU make.
+
+SHELL:=@SHELL@
+srcdir:=@srcdir@
+objdir:=.
+
+CONFIG_DIR:=$(srcdir)/config/@CONFIG_DIR@
+VPATH:=$(srcdir):$(CONFIG_DIR):$(srcdir)/regex:$(srcdir)/regexp:$(srcdir)/lib
+
+target_alias:=@target_alias@
+build_alias:=@build_alias@
+host_alias:=@host_alias@
+prefix:=@prefix@
+
+program_transform_name:=@program_transform_name@
+exec_prefix:=@exec_prefix@
+bindir:=@bindir@
+libdir:=@libdir@
+mandir:=@mandir@
+ifeq ($(target_alias),$(host_alias))
+ifeq ($(build_alias),$(host_alias))
+tooldir:=$(exec_prefix)
+else
+tooldir:=$(exec_prefix)/$(target_alias)
+endif
+else
+tooldir:=$(exec_prefix)/$(target_alias)
+endif
+datadir:=@datadir@
+infodir:=@infodir@
+includedir:=@includedir@
+
+override INSTALL:=@INSTALL@
+override INSTALL_PROGRAM:=@INSTALL_PROGRAM@
+override INSTALL_DATA:=@INSTALL_DATA@
+
+#
+# --enable options from configure
+#
+MT_SAFE:=@MT_SAFE@
+DEFS:=@DEFS@
+
+CC:=@CC@
+# FIXME: Which is it, CC or CC_FOR_TARGET?
+CC_FOR_TARGET:=$(CC)
+CFLAGS=@CFLAGS@
+override CFLAGS+=-MMD ${$(*F)_CFLAGS} -fmerge-constants -ftracer
+CXX=@CXX@
+CXXFLAGS=@CXXFLAGS@
+
+AR:=@AR@
+AR_FLAGS:=qv
+RANLIB:=@RANLIB@
+LD:=@LD@
+DLLTOOL:=@DLLTOOL@
+WINDRES:=@WINDRES@
+AS:=@AS@
+NM:=@NM@
+LDSCRIPT:=cygwin.sc
+
+#
+# Include common definitions for winsup directory
+#
+include $(srcdir)/../Makefile.common
+
+@SET_MAKE@
+
+# Setup the testing framework, if you have one
+EXPECT = `if [ -f $${rootme}/../../expect/expect$(EXEEXT) ] ; then \
+ echo $${rootme}/../../expect/expect$(EXEEXT) ; \
+ else echo expect ; fi`
+
+RUNTEST = `if [ -f $${srcdir}/../dejagnu/runtest ] ; then \
+ echo $${srcdir}/../dejagnu/runtest ; \
+ else echo runtest; fi`
+RUNTESTFLAGS =
+
+# Parameters used in building the cygwin.dll.
+# We build as cygwin0.dll and rename at install time to overcome
+# native rebuilding issues (we don't want the build tools to see a partially
+# built cygwin.dll and attempt to use it instead of the old one).
+
+DLL_NAME:=cygwin1.dll
+TEST_DLL_NAME:=cygwin0.dll
+TEST_LIB_NAME:=libcygwin0.a
+DEF_FILE:=cygwin.def
+DLL_ENTRY:=@DLL_ENTRY@
+
+LIBGMON_A:=libgmon.a
+CYGWIN_START:=crt0.o
+GMON_START:=gcrt0.o
+
+# Some things want these from libc, but they have their own static
+# data which apps can get to, which is a pain in the dll, so we
+# include them directly into the library.
+
+LIBCOS:=${sort ${addsuffix .o,${basename ${notdir ${wildcard $(srcdir)/lib/*.c}}}} \
+ ${addsuffix .o,${basename ${notdir ${wildcard $(srcdir)/lib/*.cc}}}}}
+
+# Build all source files in the config directory
+
+EXTRA_DLL_OFILES:=${addsuffix .o,${basename ${notdir ${wildcard $(CONFIG_DIR)/*.c}}}}
+
+EXTRA_OFILES=$(bupdir1)/libiberty/random.o $(bupdir1)/libiberty/strsignal.o
+
+MALLOC_OFILES=@MALLOC_OFILES@
+
+DLL_IMPORTS:=$(w32api_lib)/libkernel32.a $(w32api_lib)/libadvapi32.a
+
+MT_SAFE_OBJECTS:=
+# Please maintain this list in sorted order, with maximum files per 80 col line
+#
+DLL_OFILES:=assert.o autoload.o bsdlib.o cxx.o cygheap.o cygthread.o cygtls.o \
+ dcrt0.o debug.o delqueue.o devices.o dir.o dlfcn.o dll_init.o dtable.o \
+ environ.o errno.o exceptions.o exec.o external.o fcntl.o fhandler.o \
+ fhandler_clipboard.o fhandler_console.o fhandler_disk_file.o \
+ fhandler_dsp.o fhandler_fifo.o fhandler_floppy.o fhandler_mem.o \
+ fhandler_nodevice.o fhandler_proc.o fhandler_process.o \
+ fhandler_random.o fhandler_raw.o fhandler_registry.o fhandler_serial.o \
+ fhandler_socket.o fhandler_tape.o fhandler_termios.o \
+ fhandler_tty.o fhandler_virtual.o fhandler_windows.o \
+ fhandler_zero.o flock.o fnmatch.o fork.o getopt.o glob.o grp.o heap.o \
+ init.o ioctl.o ipc.o iruserok.o localtime.o malloc_wrapper.o miscfuncs.o \
+ mmap.o msg.o net.o netdb.o ntea.o passwd.o path.o pinfo.o pipe.o \
+ poll.o pthread.o regcomp.o regerror.o regexec.o regfree.o registry.o \
+ resource.o scandir.o sched.o sec_acl.o sec_helper.o security.o \
+ select.o sem.o shared.o shm.o sigfe.o signal.o sigproc.o smallprint.o \
+ spawn.o strace.o strsep.o sync.o syscalls.o sysconf.o syslog.o \
+ termios.o thread.o times.o tty.o uinfo.o uname.o v8_regexp.o \
+ v8_regerror.o v8_regsub.o wait.o wincap.o window.o \
+ $(EXTRA_DLL_OFILES) $(EXTRA_OFILES) $(MALLOC_OFILES) $(MT_SAFE_OBJECTS)
+
+GMON_OFILES:=gmon.o mcount.o profil.o
+
+OBSOLETE_FUNCTIONS:=regcomp regerror regexec regfree regsub \
+ open acl aclcheck aclfrommode aclfrompbits \
+ aclfromtext aclsort acltomode acltopbits \
+ acltotext chown facl fchown fcntl fdopen fgetpos fopen \
+ freopen fseeko fsetpos fstat ftello ftruncate \
+ getegid geteuid getgid getgrent getgrgid getgrnam \
+ getgroups getpwuid getpwuid_r getuid initgroups \
+ lchown lseek lstat mknod mmap seekdir setegid seteuid \
+ setgid setgroups setregid setreuid setuid stat \
+ telldir tmpfile truncate
+
+NEW_FUNCTIONS:=regcomp posix_regcomp \
+ regerror posix_regerror \
+ regexec posix_regexec \
+ regfree posix_regfree \
+ open _open64 \
+ acl _acl32 \
+ aclcheck _aclcheck32 \
+ aclfrommode _aclfrommode32 \
+ aclfrompbits _aclfrompbits32 \
+ aclfromtext _aclfromtext32 \
+ aclsort _aclsort32 \
+ acltomode _acltomode32 \
+ acltopbits _acltopbits32 \
+ acltotext _acltotext32 \
+ chown _chown32 \
+ facl _facl32 \
+ fchown _fchown32 \
+ fcntl _fcntl64 \
+ fdopen _fdopen64 \
+ fgetpos _fgetpos64 \
+ fopen _fopen64 \
+ freopen _freopen64 \
+ fseeko _fseeko64 \
+ fsetpos _fsetpos64 \
+ fstat _fstat64 \
+ ftello _ftello64 \
+ ftruncate _ftruncate64 \
+ getegid _getegid32 \
+ geteuid _geteuid32 \
+ getgid _getgid32 \
+ getgrent _getgrent32 \
+ getgrgid _getgrgid32 \
+ getgrnam _getgrnam32 \
+ getgroups _getgroups32 \
+ getpwuid _getpwuid32 \
+ getpwuid_r _getpwuid_r32 \
+ getuid _getuid32 \
+ initgroups _initgroups32 \
+ lchown _lchown32 \
+ lseek _lseek64 \
+ lstat _lstat64 \
+ mknod _mknod32 \
+ mmap _mmap64 \
+ seekdir _seekdir64 \
+ setegid _setegid32 \
+ seteuid _seteuid32 \
+ setgid _setgid32 \
+ setgroups _setgroups32 \
+ setregid _setregid32 \
+ setreuid _setreuid32 \
+ setuid _setuid32 \
+ stat _stat64 \
+ telldir _telldir64 \
+ tmpfile _tmpfile64 \
+ truncate _truncate64
+
+API_VER:=$(srcdir)/include/cygwin/version.h
+
+PWD:=${shell pwd}
+LIB_NAME:=$(PWD)/libcygwin.a
+LIBSERVER:=@LIBSERVER@
+SUBLIBS:=$(PWD)/libpthread.a $(PWD)/libm.a $(PWD)/libc.a
+EXTRALIBS:=libautomode.a libbinmode.a libtextmode.a
+INSTOBJS:=automode.o binmode.o textmode.o
+TARGET_LIBS:=$(LIB_NAME) $(CYGWIN_START) $(GMON_START) $(LIBGMON_A) $(SUBLIBS) $(INSTOBJS) $(EXTRALIBS)
+
+ifneq "${filter -O%,$(CFLAGS)}" ""
+cygheap_CFLAGS:=-fomit-frame-pointer
+cygthread_CFLAGS:=-fomit-frame-pointer
+cygtls_CFLAGS:=-fomit-frame-pointer
+devices_CFLAGS:=-fomit-frame-pointer -Os
+dir_CFLAGS:=-fomit-frame-pointer
+fcntl_CFLAGS:=-fomit-frame-pointer
+fhandler_CFLAGS:=-fomit-frame-pointer
+fhandler_clipboard_CFLAGS:=-fomit-frame-pointer
+fhandler_console_CFLAGS:=-fomit-frame-pointer
+fhandler_disk_file_CFLAGS:=-fomit-frame-pointer
+fhandler_dsp_CFLAGS:=-fomit-frame-pointer
+fhandler_floppy_CFLAGS:=-fomit-frame-pointer
+fhandler_mem_CFLAGS:=-fomit-frame-pointer
+fhandler_proc_CFLAGS:=-fomit-frame-pointer
+fhandler_process_CFLAGS:=-fomit-frame-pointer
+fhandler_random_CFLAGS:=-fomit-frame-pointer
+fhandler_raw_CFLAGS:=-fomit-frame-pointer
+fhandler_registry_CFLAGS:=-fomit-frame-pointer
+fhandler_serial_CFLAGS:=-fomit-frame-pointer
+fhandler_socket_CFLAGS:=-fomit-frame-pointer
+fhandler_syslog_CFLAGS:=-fomit-frame-pointer
+fhandler_tape_CFLAGS:=-fomit-frame-pointer
+fhandler_termios_CFLAGS:=-fomit-frame-pointer
+fhandler_tty_CFLAGS:=-fomit-frame-pointer
+fhandler_virtual_CFLAGS:=-fomit-frame-pointer
+fhandler_windows_CFLAGS:=-fomit-frame-pointer
+fhandler_zero_CFLAGS:=-fomit-frame-pointer
+malloc_CFLAGS:=-fomit-frame-pointer
+malloc_wrapper_CFLAGS:=-fomit-frame-pointer
+miscfuncs_CFLAGS:=-fomit-frame-pointer
+regcomp_CFLAGS=-fomit-frame-pointer
+regerror_CFLAGS=-fomit-frame-pointer
+regexec_CFLAGS=-fomit-frame-pointer
+regfree_CFLAGS=-fomit-frame-pointer
+shared_CFLAGS:=-fomit-frame-pointer
+smallprint_CFLAGS:=-fomit-frame-pointer
+sysconf_CFLAGS:=-fomit-frame-pointer
+uinfo_CFLAGS:=-fomit-frame-pointer
+endif
+
+.PHONY: all force dll_ofiles install all_target install_target all_host install_host \
+ install install-libs install-headers -lgcc
+
+.SUFFIXES:
+.SUFFIXES: .c .cc .def .a .o .d .s
+
+all_host=@all_host@
+install_host=@install_host@
+
+all: all_target $(all_host)
+
+all_target: $(TARGET_LIBS)
+
+all_host: $(TEST_LIB_NAME)
+
+force:
+
+install: install-libs install-headers install-man install_target \
+ $(install_host) $(install_target)
+
+uninstall: uninstall-libs uninstall-headers uninstall-man
+
+install-libs: $(TARGET_LIBS)
+ $(INSTALL_PROGRAM) $(TEST_DLL_NAME) $(bindir)/$(DLL_NAME); \
+ for i in $^; do \
+ $(INSTALL_DATA) $$i $(tooldir)/lib/`basename $$i` ; \
+ done
+
+install-headers:
+ cd $(srcdir); \
+ for sub in `find include -name '[a-z]*' -type d -print | sort`; do \
+ for i in $$sub/*.h ; do \
+ $(INSTALL_DATA) $$i $(tooldir)/$$sub/`basename $$i` ; \
+ done ; \
+ done ; \
+ $(INSTALL_DATA) regex/regex.h $(tooldir)/include/regex.h
+
+install-man:
+ cd $(srcdir); \
+ for i in `find . -type f -name '*.2'`; do \
+ $(INSTALL_DATA) $$i $(mandir)/man2/`basename $$i` ; \
+ done; \
+ for i in `find . -type f -name '*.3'`; do \
+ $(INSTALL_DATA) $$i $(mandir)/man3/`basename $$i` ; \
+ done; \
+ for i in `find . -type f -name '*.5'`; do \
+ $(INSTALL_DATA) $$i $(mandir)/man5/`basename $$i` ; \
+ done; \
+ for i in `find . -type f -name '*.7'`; do \
+ $(INSTALL_DATA) $$i $(mandir)/man7/`basename $$i` ; \
+ done
+
+install_target:
+
+install_host:
+
+uninstall-libs: $(TARGET_LIBS)
+ rm -f $(bindir)/$(DLL_NAME); \
+ for i in $^; do \
+ rm -f $(tooldir)/lib/$$i ; \
+ done
+
+uninstall-headers:
+ cd $(srcdir); \
+ for sub in `find include -name '[a-z]*' -type d -print | sort`; do \
+ for i in $$sub/*.h ; do \
+ rm -f $(tooldir)/$$sub/`basename $$i` ; \
+ done ; \
+ done ; \
+ rm -f $(tooldir)/include/regex.h
+
+uninstall-man:
+ cd $(srcdir); \
+ for i in `find . -type f -name '*.2'`; do \
+ rm -f $(tooldir)/man/man2/`basename $$i` ; \
+ done; \
+ for i in `find . -type f -name '*.3'`; do \
+ rm -f $(tooldir)/man/man3/`basename $$i` ; \
+ done; \
+ for i in `find . -type f -name '*.5'`; do \
+ rm -f $(tooldir)/man/man5/`basename $$i` ; \
+ done; \
+ for i in `find . -type f -name '*.7'`; do \
+ rm -f $(tooldir)/man/man7/`basename $$i` ; \
+ done
+
+clean:
+ -rm -f *.o *.dll *.a *.exp junk *.base version.cc regexp/*.o winver_stamp *.exe *.d *stamp* *_magic.h
+
+maintainer-clean realclean: clean
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+ -rm -fr configure
+
+
+# Rule to build cygwin.dll
+$(TEST_DLL_NAME): $(LDSCRIPT) $(DLL_OFILES) $(DLL_IMPORTS) $(LIBSERVER) $(LIBC) $(LIBM) $(API_VER) Makefile winver_stamp
+ $(CXX) $(CXXFLAGS) $(nostdlib) -Wl,-T$(firstword $^) -Wl,--out-implib,cygdll.a -shared -o $@ \
+ -e $(DLL_ENTRY) $(DEF_FILE) $(DLL_OFILES) version.o winver.o \
+ $(MALLOC_OBJ) $(LIBSERVER) $(LIBM) $(LIBC) \
+ -lgcc $(DLL_IMPORTS)
+ @ln -f $@ new-$(DLL_NAME)
+
+# Rule to build libcygwin.a
+$(LIB_NAME): rmsym newsym $(TEST_DLL_NAME) $(LIBCOS)
+ /bin/sh ${word 1,$^} ./cygdll.a "$(NM)" "$(AR)" $(OBSOLETE_FUNCTIONS) || exit 0
+ /bin/sh ${word 2,$^} ./cygdll.a "$(AS)" "$(AR)" $(NEW_FUNCTIONS) || exit 0
+ (echo create $(LIB_NAME); echo addmod $(LIBCOS); echo addlib cygdll.a; echo save) | $(AR) -M
+ $(RANLIB) $@
+
+# Rule to make stub library used by testsuite
+# dependency set to $(LIB_NAME) to accommodate make -j2.
+# Otherwise dlltool gets confused. cgf (11-16-2000)
+$(TEST_LIB_NAME): $(LIB_NAME)
+ perl -p -e 'BEGIN{binmode(STDIN); binmode(STDOUT);}; s/cygwin1/cygwin0/g' < $? > $@
+
+$(LIBSERVER): $(bupdir)/cygserver/Makefile
+ $(MAKE) -C $(bupdir)/cygserver libcygserver.a
+
+dll_ofiles: $(DLL_OFILES)
+
+$(LIBGMON_A): $(GMON_OFILES) $(GMON_START)
+ $(AR) rcv $(LIBGMON_A) $(GMON_OFILES)
+
+$(API_VER): $(srcdir)/cygwin.din
+ @echo Error: Version info is older than DLL API!;\
+ false
+
+version.cc winver.o: winver_stamp
+ @ :
+
+shared_info_magic.h: cygmagic shared_info.h
+ /bin/sh ${word 1,$^} $@ "$(CC) -x c" ${word 2,$^} USER_MAGIC 'class user_info' SHARED_MAGIC 'class shared_info'
+
+child_info_magic.h: cygmagic child_info.h
+ /bin/sh ${word 1,$^} $@ "$(CC) -x c" ${word 2,$^} CHILD_INFO_MAGIC 'class child_info'
+
+dcrt0.o sigproc.o: child_info_magic.h
+
+shared.o: shared_info_magic.h
+
+$(srcdir)/qevices.cc: cygwin-gperf devices.gperf devices.h
+ $^ > $@
+
+$(srcdir)/devices.cc: gendevices devices.in devices.h
+ ${wordlist 1,2,$^} $@
+
+$(PWD)/libpthread.a: speclib $(LIB_NAME) pthread.o thread.o
+ /bin/sh ${word 1, $^} $@ "${NM}" "$(AR)" ${wordlist 2, 99, $^}
+
+$(PWD)/libm.a: speclib $(LIB_NAME) $(LIBM)
+ /bin/sh ${word 1, $^} $@ "${NM}" "$(AR)" ${wordlist 2, 99, $^}
+
+$(PWD)/libc.a: speclib $(LIB_NAME) $(PWD)/libm.a libpthread.a
+ /bin/sh ${word 1, $^} -v $@ "${NM}" "$(AR)" ${wordlist 2, 99, $^}
+
+lib%.a: %.o
+ $(AR) cru $@ $?
+
+winver_stamp: mkvers.sh include/cygwin/version.h winver.rc $(DLL_OFILES)
+ @echo "Making version.o and winver.o";\
+ $(SHELL) ${word 1,$^} ${word 2,$^} ${word 3,$^} $(WINDRES) && \
+ $(COMPILE_CXX) -o version.o version.cc && \
+ touch $@
+
+-lgcc:
+ :
+
+#
+
+Makefile: cygwin.din
+
+$(DEF_FILE): gendef cygwin.din $(srcdir)/tlsoffsets.h
+ $^ $@ sigfe.s
+
+$(srcdir)/tlsoffsets.h: gentls_offsets cygtls.h
+ $^ $@ $(COMPILE_CXX)
+
+sigfe.s: $(DEF_FILE)
+ @touch $@
+
+sigfe.o: sigfe.s
+ $(CC) -c -o $@ $?
+
+winsup.h: config.h
+
+deps:=${wildcard *.d}
+ifneq (,$(deps))
+include $(deps)
+endif
diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc
new file mode 100644
index 00000000000..71ae1847c01
--- /dev/null
+++ b/winsup/cygwin/dcrt0.cc
@@ -0,0 +1,1180 @@
+/* dcrt0.cc -- essentially the main() for the Cygwin dll
+
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "glob.h"
+#include "exceptions.h"
+#include <ctype.h>
+#include <limits.h>
+#include <wingdi.h>
+#include <winuser.h>
+#include "sigproc.h"
+#include "pinfo.h"
+#include "cygerrno.h"
+#define NEED_VFORK
+#include "perprocess.h"
+#include "security.h"
+#include "path.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "cygheap.h"
+#include "child_info_magic.h"
+#include "perthread.h"
+#include "shared_info.h"
+#include "cygwin_version.h"
+#include "dll_init.h"
+#include "cygthread.h"
+#include "sync.h"
+#include "heap.h"
+
+#define MAX_AT_FILE_LEVEL 10
+
+#define PREMAIN_LEN (sizeof (user_data->premain) / sizeof (user_data->premain[0]))
+
+HANDLE NO_COPY hMainProc = (HANDLE) -1;
+HANDLE NO_COPY hMainThread;
+
+per_thread_waitq NO_COPY waitq_storage;
+per_thread_vfork NO_COPY vfork_storage;
+
+per_thread NO_COPY *threadstuff[] = {&waitq_storage,
+ &vfork_storage,
+ NULL};
+
+bool display_title;
+bool strip_title_path;
+bool allow_glob = true;
+codepage_type current_codepage = ansi_cp;
+
+int __argc_safe;
+int _declspec(dllexport) __argc;
+char _declspec(dllexport) **__argv;
+vfork_save NO_COPY *main_vfork;
+
+static int NO_COPY envc;
+char NO_COPY **envp;
+
+extern "C" void __sinit (_reent *);
+
+_threadinfo NO_COPY *_main_tls;
+
+int cygwin_finished_initializing;
+
+/* Used in SIGTOMASK for generating a bit for insertion into a sigset_t.
+ This is subtracted from the signal number prior to shifting the bit.
+ In older versions of cygwin, the signal was used as-is to shift the
+ bit for masking. So, we'll temporarily detect this and set it to zero
+ for programs that are linked using older cygwins. This is just a stopgap
+ measure to allow an orderly transfer to the new, correct sigmask method. */
+unsigned NO_COPY int signal_shift_subtract = 1;
+
+ResourceLocks _reslock NO_COPY;
+MTinterface _mtinterf;
+
+bool NO_COPY _cygwin_testing;
+
+char NO_COPY almost_null[1];
+
+extern "C"
+{
+ /* This is an exported copy of environ which can be used by DLLs
+ which use cygwin.dll. */
+ char **__cygwin_environ;
+ char ***main_environ;
+ /* __progname used in getopt error message */
+ char *__progname;
+ static struct _reent reent_data;
+ struct per_process __cygwin_user_data =
+ {/* initial_sp */ 0, /* magic_biscuit */ 0,
+ /* dll_major */ CYGWIN_VERSION_DLL_MAJOR,
+ /* dll_major */ CYGWIN_VERSION_DLL_MINOR,
+ /* impure_ptr_ptr */ NULL, /* envptr */ NULL,
+ /* malloc */ malloc, /* free */ free,
+ /* realloc */ realloc,
+ /* fmode_ptr */ NULL, /* main */ NULL, /* ctors */ NULL,
+ /* dtors */ NULL, /* data_start */ NULL, /* data_end */ NULL,
+ /* bss_start */ NULL, /* bss_end */ NULL,
+ /* calloc */ calloc,
+ /* premain */ {NULL, NULL, NULL, NULL},
+ /* run_ctors_p */ 0,
+ /* unused */ {0, 0, 0, 0, 0, 0, 0},
+ /* forkee */ 0,
+ /* hmodule */ NULL,
+ /* api_major */ CYGWIN_VERSION_API_MAJOR,
+ /* api_minor */ CYGWIN_VERSION_API_MINOR,
+ /* unused2 */ {0, 0, 0, 0, 0},
+ /* resourcelocks */ &_reslock, /* threadinterface */ &_mtinterf,
+ /* impure_ptr */ &reent_data,
+ };
+ bool ignore_case_with_glob;
+ int __declspec (dllexport) _check_for_executable = true;
+#ifdef DEBUGGING
+ int pinger;
+#endif
+};
+
+char *old_title;
+char title_buf[TITLESIZE + 1];
+
+static void
+do_global_dtors (void)
+{
+ if (user_data->dtors)
+ {
+ void (**pfunc)() = user_data->dtors;
+ while (*++pfunc)
+ (*pfunc) ();
+ }
+}
+
+static void __stdcall
+do_global_ctors (void (**in_pfunc)(), int force)
+{
+ if (!force && user_data->forkee)
+ return; // inherit constructed stuff from parent pid
+
+ /* Run ctors backwards, so skip the first entry and find how many
+ there are, then run them. */
+
+ void (**pfunc) () = in_pfunc;
+
+ while (*++pfunc)
+ ;
+ while (--pfunc > in_pfunc)
+ (*pfunc) ();
+}
+
+/*
+ * Replaces @file in the command line with the contents of the file.
+ * There may be multiple @file's in a single command line
+ * A \@file is replaced with @file so that echo \@foo would print
+ * @foo and not the contents of foo.
+ */
+static bool __stdcall
+insert_file (char *name, char *&cmd)
+{
+ HANDLE f;
+ DWORD size;
+
+ f = CreateFile (name + 1,
+ GENERIC_READ, /* open for reading */
+ FILE_SHARE_READ, /* share for reading */
+ &sec_none_nih, /* no security */
+ OPEN_EXISTING, /* existing file only */
+ FILE_ATTRIBUTE_NORMAL, /* normal file */
+ NULL); /* no attr. template */
+
+ if (f == INVALID_HANDLE_VALUE)
+ {
+ debug_printf ("couldn't open file '%s', %E", name);
+ return false;
+ }
+
+ /* This only supports files up to about 4 billion bytes in
+ size. I am making the bold assumption that this is big
+ enough for this feature */
+ size = GetFileSize (f, NULL);
+ if (size == 0xFFFFFFFF)
+ {
+ debug_printf ("couldn't get file size for '%s', %E", name);
+ return false;
+ }
+
+ int new_size = strlen (cmd) + size + 2;
+ char *tmp = (char *) malloc (new_size);
+ if (!tmp)
+ {
+ debug_printf ("malloc failed, %E");
+ return false;
+ }
+
+ /* realloc passed as it should */
+ DWORD rf_read;
+ BOOL rf_result;
+ rf_result = ReadFile (f, tmp, size, &rf_read, NULL);
+ CloseHandle (f);
+ if (!rf_result || (rf_read != size))
+ {
+ debug_printf ("ReadFile failed, %E");
+ return false;
+ }
+
+ tmp[size++] = ' ';
+ strcpy (tmp + size, cmd);
+ cmd = tmp;
+ return true;
+}
+
+static inline int
+isquote (char c)
+{
+ char ch = c;
+ return ch == '"' || ch == '\'';
+}
+
+/* Step over a run of characters delimited by quotes */
+static /*__inline*/ char *
+quoted (char *cmd, int winshell)
+{
+ char *p;
+ char quote = *cmd;
+
+ if (!winshell)
+ {
+ char *p;
+ strcpy (cmd, cmd + 1);
+ if (*(p = strechr (cmd, quote)))
+ strcpy (p, p + 1);
+ return p;
+ }
+
+ const char *s = quote == '\'' ? "'" : "\\\"";
+ /* This must have been run from a Windows shell, so preserve
+ quotes for globify to play with later. */
+ while (*cmd && *++cmd)
+ if ((p = strpbrk (cmd, s)) == NULL)
+ {
+ cmd = strchr (cmd, '\0'); // no closing quote
+ break;
+ }
+ else if (*p == '\\')
+ cmd = ++p;
+ else if (quote == '"' && p[1] == '"')
+ {
+ *p = '\\';
+ cmd = ++p; // a quoted quote
+ }
+ else
+ {
+ cmd = p + 1; // point to after end
+ break;
+ }
+ return cmd;
+}
+
+/* Perform a glob on word if it contains wildcard characters.
+ Also quote every character between quotes to force glob to
+ treat the characters literally. */
+static int __stdcall
+globify (char *word, char **&argv, int &argc, int &argvlen)
+{
+ if (*word != '~' && strpbrk (word, "?*[\"\'(){}") == NULL)
+ return 0;
+
+ int n = 0;
+ char *p, *s;
+ int dos_spec = isdrive (word);
+ if (!dos_spec && isquote (*word) && word[1] && word[2])
+ dos_spec = isdrive (word + 1);
+
+ /* We'll need more space if there are quoting characters in
+ word. If that is the case, doubling the size of the
+ string should provide more than enough space. */
+ if (strpbrk (word, "'\""))
+ n = strlen (word);
+ char pattern[strlen (word) + ((dos_spec + 1) * n) + 1];
+
+ /* Fill pattern with characters from word, quoting any
+ characters found within quotes. */
+ for (p = pattern, s = word; *s != '\000'; s++, p++)
+ if (!isquote (*s))
+ {
+ if (dos_spec && *s == '\\')
+ *p++ = '\\';
+ *p = *s;
+ }
+ else
+ {
+ char quote = *s;
+ while (*++s && *s != quote)
+ {
+ if (dos_spec || *s != '\\')
+ /* nothing */;
+ else if (s[1] == quote || s[1] == '\\')
+ s++;
+ *p++ = '\\';
+ *p++ = *s;
+ }
+ if (*s == quote)
+ p--;
+ if (*s == '\0')
+ break;
+ }
+
+ *p = '\0';
+
+ glob_t gl;
+ gl.gl_offs = 0;
+
+ /* Attempt to match the argument. Return just word (minus quoting) if no match. */
+ if (glob (pattern, GLOB_TILDE | GLOB_NOCHECK | GLOB_BRACE | GLOB_QUOTE, NULL, &gl) || !gl.gl_pathc)
+ return 0;
+
+ /* Allocate enough space in argv for the matched filenames. */
+ n = argc;
+ if ((argc += gl.gl_pathc) > argvlen)
+ {
+ argvlen = argc + 10;
+ argv = (char **) realloc (argv, (1 + argvlen) * sizeof (argv[0]));
+ }
+
+ /* Copy the matched filenames to argv. */
+ char **gv = gl.gl_pathv;
+ char **av = argv + n;
+ while (*gv)
+ {
+ debug_printf ("argv[%d] = '%s'", n++, *gv);
+ *av++ = *gv++;
+ }
+
+ /* Clean up after glob. */
+ free (gl.gl_pathv);
+ return 1;
+}
+
+/* Build argv, argc from string passed from Windows. */
+
+static void __stdcall
+build_argv (char *cmd, char **&argv, int &argc, int winshell)
+{
+ int argvlen = 0;
+ int nesting = 0; // monitor "nesting" from insert_file
+
+ argc = 0;
+ argvlen = 0;
+ argv = NULL;
+
+ /* Scan command line until there is nothing left. */
+ while (*cmd)
+ {
+ /* Ignore spaces */
+ if (issep (*cmd))
+ {
+ cmd++;
+ continue;
+ }
+
+ /* Found the beginning of an argument. */
+ char *word = cmd;
+ char *sawquote = NULL;
+ while (*cmd)
+ {
+ if (*cmd != '"' && (!winshell || *cmd != '\''))
+ cmd++; // Skip over this character
+ else
+ /* Skip over characters until the closing quote */
+ {
+ sawquote = cmd;
+ cmd = quoted (cmd, winshell && argc > 0);
+ }
+ if (issep (*cmd)) // End of argument if space
+ break;
+ }
+ if (*cmd)
+ *cmd++ = '\0'; // Terminate `word'
+
+ /* Possibly look for @file construction assuming that this isn't
+ the very first argument and the @ wasn't quoted */
+ if (argc && sawquote != word && *word == '@')
+ {
+ if (++nesting > MAX_AT_FILE_LEVEL)
+ api_fatal ("Too many levels of nesting for %s", word);
+ if (insert_file (word, cmd))
+ continue; // There's new stuff in cmd now
+ }
+
+ /* See if we need to allocate more space for argv */
+ if (argc >= argvlen)
+ {
+ argvlen = argc + 10;
+ argv = (char **) realloc (argv, (1 + argvlen) * sizeof (argv[0]));
+ }
+
+ /* Add word to argv file after (optional) wildcard expansion. */
+ if (!winshell || !argc || !globify (word, argv, argc, argvlen))
+ {
+ debug_printf ("argv[%d] = '%s'", argc, word);
+ argv[argc++] = word;
+ }
+ }
+
+ argv[argc] = NULL;
+
+ debug_printf ("argc %d", argc);
+}
+
+/* sanity and sync check */
+void __stdcall
+check_sanity_and_sync (per_process *p)
+{
+ /* Sanity check to make sure developers didn't change the per_process */
+ /* struct without updating SIZEOF_PER_PROCESS [it makes them think twice */
+ /* about changing it]. */
+ if (sizeof (per_process) != SIZEOF_PER_PROCESS)
+ {
+ api_fatal ("per_process sanity check failed");
+ }
+
+ /* Make sure that the app and the dll are in sync. */
+
+ /* Complain if older than last incompatible change */
+ if (p->dll_major < CYGWIN_VERSION_DLL_EPOCH)
+ api_fatal ("cygwin DLL and APP are out of sync -- DLL version mismatch %d < %d",
+ p->dll_major, CYGWIN_VERSION_DLL_EPOCH);
+
+ /* magic_biscuit != 0 if using the old style version numbering scheme. */
+ if (p->magic_biscuit != SIZEOF_PER_PROCESS)
+ api_fatal ("Incompatible cygwin .dll -- incompatible per_process info %d != %d",
+ p->magic_biscuit, SIZEOF_PER_PROCESS);
+
+ /* Complain if incompatible API changes made */
+ if (p->api_major > cygwin_version.api_major)
+ api_fatal ("cygwin DLL and APP are out of sync -- API version mismatch %d > %d",
+ p->api_major, cygwin_version.api_major);
+
+ if (CYGWIN_VERSION_DLL_MAKE_COMBINED (p->dll_major, p->dll_minor) <=
+ CYGWIN_VERSION_DLL_BAD_SIGNAL_MASK)
+ signal_shift_subtract = 0;
+}
+
+child_info NO_COPY *child_proc_info = NULL;
+static MEMORY_BASIC_INFORMATION NO_COPY sm;
+
+#define CYGWIN_GUARD ((wincap.has_page_guard ()) ? \
+ PAGE_EXECUTE_READWRITE|PAGE_GUARD : PAGE_NOACCESS)
+
+// __inline__ void
+extern void
+alloc_stack_hard_way (child_info_fork *ci, volatile char *b)
+{
+ void *new_stack_pointer;
+ MEMORY_BASIC_INFORMATION m;
+ void *newbase;
+ int newlen;
+ LPBYTE curbot = (LPBYTE) sm.BaseAddress + sm.RegionSize;
+ bool noguard;
+
+ if (ci->stacktop > (LPBYTE) sm.AllocationBase && ci->stacktop < curbot)
+ {
+ newbase = curbot;
+ newlen = (LPBYTE) ci->stackbottom - (LPBYTE) curbot;
+ noguard = 1;
+ }
+ else
+ {
+ newbase = ci->stacktop;
+ newlen = (DWORD) ci->stackbottom - (DWORD) ci->stacktop;
+ noguard = 0;
+ }
+ if (!VirtualAlloc (newbase, newlen, MEM_RESERVE, PAGE_NOACCESS))
+ api_fatal ("fork: can't reserve memory for stack %p - %p, %E",
+ ci->stacktop, ci->stackbottom);
+
+ new_stack_pointer = (void *) ((LPBYTE) ci->stackbottom - ci->stacksize);
+
+ if (!VirtualAlloc (new_stack_pointer, ci->stacksize, MEM_COMMIT,
+ PAGE_EXECUTE_READWRITE))
+ api_fatal ("fork: can't commit memory for stack %p(%d), %E",
+ new_stack_pointer, ci->stacksize);
+ if (!VirtualQuery ((LPCVOID) new_stack_pointer, &m, sizeof m))
+ api_fatal ("fork: couldn't get new stack info, %E");
+ if (!noguard)
+ {
+ m.BaseAddress = (LPVOID)((DWORD)m.BaseAddress - 1);
+ if (!VirtualAlloc ((LPVOID) m.BaseAddress, 1, MEM_COMMIT,
+ CYGWIN_GUARD))
+ api_fatal ("fork: couldn't allocate new stack guard page %p, %E",
+ m.BaseAddress);
+ }
+ if (!VirtualQuery ((LPCVOID) m.BaseAddress, &m, sizeof m))
+ api_fatal ("fork: couldn't get new stack info, %E");
+ ci->stacktop = m.BaseAddress;
+ *b = 0;
+}
+
+/* extend the stack prior to fork longjmp */
+
+static void
+alloc_stack (child_info_fork *ci)
+{
+ /* FIXME: adding 16384 seems to avoid a stack copy problem during
+ fork on Win95, but I don't know exactly why yet. DJ */
+ volatile char b[ci->stacksize + 16384];
+
+ if (!VirtualQuery ((LPCVOID) &b, &sm, sizeof sm))
+ api_fatal ("fork: couldn't get stack info, %E");
+
+ if (sm.AllocationBase == ci->stacktop)
+ ci->stacksize = 0;
+ else
+ alloc_stack_hard_way (ci, b + sizeof (b) - 1);
+
+ return;
+}
+
+#ifdef DEBUGGING
+void
+break_here ()
+{
+ debug_printf ("break here");
+}
+#endif
+
+static void
+initial_env (bool first)
+{
+ char buf[CYG_MAX_PATH + 1];
+ if (!first)
+ /* nothing */;
+ else if (GetEnvironmentVariable ("CYGWIN_TESTING", buf, sizeof (buf) - 1))
+ _cygwin_testing = 1;
+#ifdef DEBUGGING
+ DWORD len;
+ static bool NO_COPY did_debugging_stuff;
+ if (did_debugging_stuff || (first && wincap.cant_debug_dll_entry ()))
+ return;
+
+ did_debugging_stuff = true;
+ if (GetEnvironmentVariable ("CYGWIN_SLEEP", buf, sizeof (buf) - 1))
+ {
+ DWORD ms = atoi (buf);
+ buf[0] = '\0';
+ len = GetModuleFileName (NULL, buf, CYG_MAX_PATH);
+ console_printf ("Sleeping %d, pid %u %s\n", ms, GetCurrentProcessId (), buf);
+ while (ms--)
+ Sleep (1);
+ }
+ if (GetEnvironmentVariable ("CYGWIN_DEBUG", buf, sizeof (buf) - 1))
+ {
+ char buf1[CYG_MAX_PATH + 1];
+ len = GetModuleFileName (NULL, buf1, CYG_MAX_PATH);
+ strlwr (buf1);
+ strlwr (buf);
+ char *p = strchr (buf, ':');
+ if (!p)
+ p = (char *) "gdb.exe -nw";
+ else
+ *p++ = '\0';
+ if (strstr (buf1, buf))
+ {
+ error_start_init (p);
+ try_to_debug ();
+ break_here ();
+ }
+ }
+#endif
+}
+
+void __stdcall
+dll_crt0_0 ()
+{
+ wincap.init ();
+ initial_env (true);
+
+ char zeros[sizeof (child_proc_info->zero)] = {0};
+
+ init_console_handler ();
+ init_global_security ();
+ if (!DuplicateHandle (GetCurrentProcess (), GetCurrentProcess (),
+ GetCurrentProcess (), &hMainProc, 0, FALSE,
+ DUPLICATE_SAME_ACCESS))
+ hMainProc = GetCurrentProcess ();
+
+ DuplicateHandle (hMainProc, GetCurrentThread (), hMainProc,
+ &hMainThread, 0, false, DUPLICATE_SAME_ACCESS);
+
+ (void) SetErrorMode (SEM_FAILCRITICALERRORS);
+
+ STARTUPINFO si;
+ GetStartupInfo (&si);
+ child_proc_info = (child_info *) si.lpReserved2;
+
+ int mypid = 0;
+ if (si.cbReserved2 < EXEC_MAGIC_SIZE || !child_proc_info
+ || memcmp (child_proc_info->zero, zeros,
+ sizeof (child_proc_info->zero)) != 0)
+ child_proc_info = NULL;
+ else
+ {
+ if ((child_proc_info->intro & OPROC_MAGIC_MASK) == OPROC_MAGIC_GENERIC)
+ multiple_cygwin_problem ("proc", child_proc_info->intro, 0);
+ else if (child_proc_info->intro == PROC_MAGIC_GENERIC
+ && child_proc_info->magic != CHILD_INFO_MAGIC)
+ multiple_cygwin_problem ("proc", child_proc_info->magic,
+ CHILD_INFO_MAGIC);
+ else if (child_proc_info->cygheap != (void *) &_cygheap_start)
+ multiple_cygwin_problem ("cygheap", (DWORD) child_proc_info->cygheap,
+ (DWORD) &_cygheap_start);
+ unsigned should_be_cb = 0;
+ switch (child_proc_info->type)
+ {
+ case _PROC_FORK:
+ user_data->forkee = child_proc_info->cygpid;
+ should_be_cb = sizeof (child_info_fork);
+ /* fall through */;
+ case _PROC_SPAWN:
+ case _PROC_EXEC:
+ if (!should_be_cb)
+ should_be_cb = sizeof (child_info);
+ if (should_be_cb != child_proc_info->cb)
+ multiple_cygwin_problem ("proc size", child_proc_info->cb, should_be_cb);
+ else if (sizeof (fhandler_union) != child_proc_info->fhandler_union_cb)
+ multiple_cygwin_problem ("fhandler size", child_proc_info->fhandler_union_cb, sizeof (fhandler_union));
+ else
+ {
+ cygwin_user_h = child_proc_info->user_h;
+ mypid = child_proc_info->cygpid;
+ break;
+ }
+ default:
+ system_printf ("unknown exec type %d", child_proc_info->type);
+ /* intentionally fall through */
+ case _PROC_WHOOPS:
+ child_proc_info = NULL;
+ break;
+ }
+ }
+
+ device::init ();
+ winpids::init ();
+ do_global_ctors (&__CTOR_LIST__, 1);
+ cygthread::init ();
+
+ if (!child_proc_info)
+ memory_init ();
+ else
+ {
+ bool close_ppid_handle = false;
+ bool close_hexec_proc = false;
+ switch (child_proc_info->type)
+ {
+ case _PROC_FORK:
+ alloc_stack (fork_info);
+ cygheap_fixup_in_child (0);
+ memory_init ();
+ set_myself (mypid);
+ close_ppid_handle = !!child_proc_info->pppid_handle;
+ break;
+ case _PROC_SPAWN:
+ /* Have to delay closes until after cygheap is setup */
+ close_hexec_proc = !!spawn_info->hexec_proc;
+ close_ppid_handle = !!child_proc_info->pppid_handle;
+ goto around;
+ case _PROC_EXEC:
+ hexec_proc = spawn_info->hexec_proc;
+ around:
+ HANDLE h;
+ cygheap_fixup_in_child (1);
+ memory_init ();
+ if (!spawn_info->moreinfo->myself_pinfo ||
+ !DuplicateHandle (hMainProc, spawn_info->moreinfo->myself_pinfo,
+ hMainProc, &h, 0, 0,
+ DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
+ h = NULL;
+ set_myself (mypid, h);
+ __argc = spawn_info->moreinfo->argc;
+ __argv = spawn_info->moreinfo->argv;
+ envp = spawn_info->moreinfo->envp;
+ envc = spawn_info->moreinfo->envc;
+ envp = spawn_info->moreinfo->envp;
+ cygheap->fdtab.fixup_after_exec (spawn_info->parent);
+ signal_fixup_after_exec ();
+ CloseHandle (spawn_info->parent);
+ if (spawn_info->moreinfo->old_title)
+ {
+ old_title = strcpy (title_buf, spawn_info->moreinfo->old_title);
+ cfree (spawn_info->moreinfo->old_title);
+ }
+ break;
+ }
+ if (close_hexec_proc)
+ CloseHandle (spawn_info->hexec_proc);
+ if (close_ppid_handle)
+ CloseHandle (child_proc_info->pppid_handle);
+ }
+
+ _threadinfo::init ();
+
+ /* Initialize events */
+ events_init ();
+
+ /* Init global well known SID objects */
+ cygsid::init ();
+ cygheap->cwd.init ();
+}
+
+/* Take over from libc's crt0.o and start the application. Note the
+ various special cases when Cygwin DLL is being runtime loaded (as
+ opposed to being link-time loaded by Cygwin apps) from a non
+ cygwin app via LoadLibrary. */
+static void
+dll_crt0_1 (char *)
+{
+ /* According to onno@stack.urc.tue.nl, the exception handler record must
+ be on the stack. */
+ /* FIXME: Verify forked children get their exception handler set up ok. */
+ exception_list cygwin_except_entry;
+
+ initial_env (false);
+ check_sanity_and_sync (user_data);
+ malloc_init ();
+
+ /* Initialize SIGSEGV handling, etc. */
+ init_exceptions (&cygwin_except_entry);
+
+ /* Nasty static stuff needed by newlib -- point to a local copy of
+ the reent stuff.
+ Note: this MUST be done here (before the forkee code) as the
+ fork copy code doesn't copy the data in libccrt0.cc (that's why we
+ pass in the per_process struct into the .dll from libccrt0). */
+
+ user_data->resourcelocks->Init ();
+ user_data->threadinterface->Init ();
+ ProtectHandle (hMainProc);
+ ProtectHandle (hMainThread);
+
+ /* Initialize pthread mainthread when not forked and it is safe to call new,
+ otherwise it is reinitalized in fixup_after_fork */
+ if (!user_data->forkee)
+ {
+ __sinit (_impure_ptr);
+ pthread::init_mainthread ();
+ }
+
+#ifdef DEBUGGING
+ strace.microseconds ();
+#endif
+
+ /* Initialize debug muto, if DLL is built with --enable-debugging.
+ Need to do this before any helper threads start. */
+ debug_init ();
+
+ cygheap->fdtab.vfork_child_fixup ();
+
+ main_vfork = vfork_storage.create ();
+
+ cygbench ("pre-forkee");
+ if (user_data->forkee)
+ {
+ /* If we've played with the stack, stacksize != 0. That means that
+ fork() was invoked from other than the main thread. Make sure that
+ frame pointer is referencing the new stack so that the OS knows what
+ to do when it needs to increase the size of the stack.
+
+ NOTE: Don't do anything that involves the stack until you've completed
+ this step. */
+ if (fork_info->stacksize)
+ {
+ _tlsbase = (char *) fork_info->stackbottom;
+ _tlstop = (char *) fork_info->stacktop;
+ }
+
+ longjmp (fork_info->jmp, fork_info->cygpid);
+ }
+
+#ifdef DEBUGGING
+ {
+ extern void fork_init ();
+ fork_init ();
+ }
+#endif
+
+ /* Initialize our process table entry. */
+ pinfo_init (envp, envc);
+
+ if (!old_title && GetConsoleTitle (title_buf, TITLESIZE))
+ old_title = title_buf;
+
+ /* Allocate cygheap->fdtab */
+ dtable_init ();
+
+ /* Initialize user info. */
+ uinfo_init ();
+
+ /* Initialize signal/subprocess handling. */
+ sigproc_init ();
+
+ /* Connect to tty. */
+ tty_init ();
+
+ if (!__argc)
+ {
+ char *line = GetCommandLineA ();
+ line = strcpy ((char *) alloca (strlen (line) + 1), line);
+
+ if (current_codepage == oem_cp)
+ CharToOemA (line, line);
+
+ /* Scan the command line and build argv. Expand wildcards if not
+ called from another cygwin process. */
+ build_argv (line, __argv, __argc,
+ NOTSTATE (myself, PID_CYGPARENT) && allow_glob);
+
+ /* Convert argv[0] to posix rules if it's currently blatantly
+ win32 style. */
+ if ((strchr (__argv[0], ':')) || (strchr (__argv[0], '\\')))
+ {
+ char *new_argv0 = (char *) malloc (CYG_MAX_PATH);
+ cygwin_conv_to_posix_path (__argv[0], new_argv0);
+ __argv[0] = (char *) realloc (new_argv0, strlen (new_argv0) + 1);
+ }
+ }
+
+ __argc_safe = __argc;
+ if (user_data->premain[0])
+ for (unsigned int i = 0; i < PREMAIN_LEN / 2; i++)
+ user_data->premain[i] (__argc, __argv, user_data);
+
+ /* Set up standard fds in file descriptor table. */
+ cygheap->fdtab.stdio_init ();
+
+ /* Set up __progname for getopt error call. */
+ if (__argv[0] && (__progname = strrchr (__argv[0], '/')))
+ ++__progname;
+ else
+ __progname = __argv[0];
+ if (__progname)
+ {
+ char *cp = strchr (__progname, '\0') - 4;
+ if (cp > __progname && strcasematch (cp, ".exe"))
+ *cp = '\0';
+ }
+
+ /* Set new console title if appropriate. */
+
+ if (display_title && !dynamically_loaded)
+ {
+ char *cp = __progname;
+ if (strip_title_path)
+ for (char *ptr = cp; *ptr && *ptr != ' '; ptr++)
+ if (isdirsep (*ptr))
+ cp = ptr + 1;
+ set_console_title (cp);
+ }
+
+ cygwin_finished_initializing = 1;
+ /* Call init of loaded dlls. */
+ dlls.init ();
+
+ /* Execute any specified "premain" functions */
+ if (user_data->premain[PREMAIN_LEN / 2])
+ for (unsigned int i = PREMAIN_LEN / 2; i < PREMAIN_LEN; i++)
+ user_data->premain[i] (__argc, __argv, user_data);
+
+ debug_printf ("user_data->main %p", user_data->main);
+
+ if (dynamically_loaded)
+ {
+ set_errno (0);
+ return;
+ }
+
+ /* Disable case-insensitive globbing */
+ ignore_case_with_glob = false;
+
+
+ set_errno (0);
+
+ MALLOC_CHECK;
+ cygbench (__progname);
+
+ /* Flush signals and ensure that signal thread is up and running. Can't
+ do this for noncygwin case since the signal thread is blocked due to
+ LoadLibrary serialization. */
+ wait_for_sigthread ();
+ if (user_data->main)
+ exit (user_data->main (__argc, __argv, *user_data->envptr));
+}
+
+struct _reent *
+initialize_main_tls (char *padding)
+{
+ if (!_main_tls)
+ {
+ _main_tls = &_my_tls;
+ _main_tls->init_thread (padding, NULL);
+ }
+ return &_main_tls->local_clib;
+}
+
+/* Wrap the real one, otherwise gdb gets confused about
+ two symbols with the same name, but different addresses.
+
+ UPTR is a pointer to global data that lives on the libc side of the
+ line [if one distinguishes the application from the dll]. */
+
+extern "C" void __stdcall
+_dll_crt0 ()
+{
+ extern HANDLE sync_startup;
+ if (sync_startup)
+ {
+ (void) WaitForSingleObject (sync_startup, INFINITE);
+ CloseHandle (sync_startup);
+ }
+
+ main_environ = user_data->envptr;
+ *main_environ = NULL;
+
+ if (child_proc_info && child_proc_info->type == _PROC_FORK)
+ user_data->forkee = child_proc_info->cygpid;
+
+ char padding[CYGTLS_PADSIZE];
+ _impure_ptr = &reent_data;
+ _impure_ptr->_stdin = &_impure_ptr->__sf[0];
+ _impure_ptr->_stdout = &_impure_ptr->__sf[1];
+ _impure_ptr->_stderr = &_impure_ptr->__sf[2];
+ _impure_ptr->_current_locale = "C";
+ initialize_main_tls (padding);
+ dll_crt0_1 (padding);
+}
+
+void
+dll_crt0 (per_process *uptr)
+{
+ /* Set the local copy of the pointer into the user space. */
+ if (uptr && uptr != user_data)
+ {
+ memcpy (user_data, uptr, per_process_overwrite);
+ *(user_data->impure_ptr_ptr) = &reent_data;
+ }
+ _dll_crt0 ();
+}
+
+/* This must be called by anyone who uses LoadLibrary to load cygwin1.dll */
+extern "C" void
+cygwin_dll_init ()
+{
+ static char **envp;
+ static int _fmode;
+
+ if (!DuplicateHandle (GetCurrentProcess (), GetCurrentProcess (),
+ GetCurrentProcess (), &hMainProc, 0, FALSE,
+ DUPLICATE_SAME_ACCESS))
+ hMainProc = GetCurrentProcess ();
+
+ DuplicateHandle (hMainProc, GetCurrentThread (), hMainProc,
+ &hMainThread, 0, FALSE, DUPLICATE_SAME_ACCESS);
+ user_data->magic_biscuit = sizeof (per_process);
+
+ user_data->envptr = &envp;
+ user_data->fmode_ptr = &_fmode;
+
+ dll_crt0_1 (NULL);
+}
+
+extern "C" void
+__main (void)
+{
+ do_global_ctors (user_data->ctors, false);
+ atexit (do_global_dtors);
+}
+
+exit_states NO_COPY exit_state;
+extern CRITICAL_SECTION exit_lock;
+
+void __stdcall
+do_exit (int status)
+{
+ syscall_printf ("do_exit (%d), exit_state %d", status, exit_state);
+
+ vfork_save *vf = vfork_storage.val ();
+ if (vf != NULL && vf->pid < 0)
+ {
+ exit_state = ES_NOT_EXITING;
+ vf->restore_exit (status);
+ }
+
+ EnterCriticalSection (&exit_lock);
+ muto::set_exiting_thread ();
+ if (exit_state < ES_EVENTS_TERMINATE)
+ {
+ exit_state = ES_EVENTS_TERMINATE;
+ events_terminate ();
+ }
+
+ UINT n = (UINT) status;
+ if (exit_state < ES_THREADTERM)
+ {
+ exit_state = ES_THREADTERM;
+ cygthread::terminate ();
+ }
+
+ if (exit_state < ES_SIGNAL)
+ {
+ exit_state = ES_SIGNAL;
+ if (!(n & EXIT_REPARENTING))
+ {
+ signal (SIGCHLD, SIG_IGN);
+ signal (SIGHUP, SIG_IGN);
+ signal (SIGINT, SIG_IGN);
+ signal (SIGQUIT, SIG_IGN);
+ }
+ }
+
+ if (exit_state < ES_CLOSEALL)
+ {
+ exit_state = ES_CLOSEALL;
+ close_all_files ();
+ }
+
+ if (exit_state < ES_SIGPROCTERMINATE)
+ {
+ exit_state = ES_SIGPROCTERMINATE;
+ sigproc_terminate ();
+ }
+
+ myself->stopsig = 0;
+ if (exit_state < ES_TITLE)
+ {
+ exit_state = ES_TITLE;
+ /* restore console title */
+ if (old_title && display_title)
+ set_console_title (old_title);
+ }
+
+ if (exit_state < ES_HUP_PGRP)
+ {
+ exit_state = ES_HUP_PGRP;
+ /* Kill orphaned children on group leader exit */
+ if (myself->has_pgid_children && myself->pid == myself->pgid)
+ {
+ sigproc_printf ("%d == pgrp %d, send SIG{HUP,CONT} to stopped children",
+ myself->pid, myself->pgid);
+ kill_pgrp (myself->pgid, -SIGHUP);
+ }
+ }
+
+ if (exit_state < ES_HUP_SID)
+ {
+ exit_state = ES_HUP_SID;
+ /* Kill the foreground process group on session leader exit */
+ if (getpgrp () > 0 && myself->pid == myself->sid && real_tty_attached (myself))
+ {
+ tty *tp = cygwin_shared->tty[myself->ctty];
+ sigproc_printf ("%d == sid %d, send SIGHUP to children",
+ myself->pid, myself->sid);
+
+ /* CGF FIXME: This can't be right. */
+ if (tp->getsid () == myself->sid)
+ tp->kill_pgrp (SIGHUP);
+ }
+
+ }
+
+ if (exit_state < ES_TTY_TERMINATE)
+ {
+ exit_state = ES_TTY_TERMINATE;
+ tty_terminate ();
+ }
+
+ minimal_printf ("winpid %d, exit %d", GetCurrentProcessId (), n);
+ myself->exit (n);
+}
+
+static muto *atexit_lock;
+
+extern "C" int
+cygwin_atexit (void (*function)(void))
+{
+ int res;
+ if (!atexit_lock)
+ new_muto (atexit_lock);
+ atexit_lock->acquire ();
+ res = atexit (function);
+ atexit_lock->release ();
+ return res;
+}
+
+extern "C" void
+cygwin_exit (int n)
+{
+ if (atexit_lock)
+ atexit_lock->acquire ();
+ exit (n);
+}
+
+extern "C" void
+_exit (int n)
+{
+ do_exit ((DWORD) n & 0xffff);
+}
+
+extern "C" void
+__api_fatal (const char *fmt, ...)
+{
+ char buf[4096];
+ va_list ap;
+
+ va_start (ap, fmt);
+ int n = __small_sprintf (buf, "%P (%u): *** ", cygwin_pid (GetCurrentProcessId ()));
+ __small_vsprintf (buf + n, fmt, ap);
+ va_end (ap);
+ strcat (buf, "\n");
+ int len = strlen (buf);
+ DWORD done;
+ (void) WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, len, &done, 0);
+
+ /* Make sure that the message shows up on the screen, too, since this is
+ a serious error. */
+ if (GetFileType (GetStdHandle (STD_ERROR_HANDLE)) != FILE_TYPE_CHAR)
+ {
+ HANDLE h = CreateFile ("CONOUT$", GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_WRITE | FILE_SHARE_WRITE,
+ &sec_none, OPEN_EXISTING, 0, 0);
+ if (h != INVALID_HANDLE_VALUE)
+ (void) WriteFile (h, buf, len, &done, 0);
+ }
+
+ /* We are going down without mercy. Make sure we reset
+ our process_state. */
+ sigproc_terminate ();
+#ifdef DEBUGGING
+ (void) try_to_debug ();
+#endif
+ myself->exit (1);
+}
+
+void
+multiple_cygwin_problem (const char *what, unsigned magic_version, unsigned version)
+{
+ if (_cygwin_testing && (strstr (what, "proc") || strstr (what, "cygheap")))
+ {
+ child_proc_info->type = _PROC_WHOOPS;
+ return;
+ }
+
+ char buf[1024];
+ if (GetEnvironmentVariable ("CYGWIN_MISMATCH_OK", buf, sizeof (buf)))
+ return;
+
+ if (CYGWIN_VERSION_MAGIC_VERSION (magic_version) == version)
+ system_printf ("%s magic number mismatch detected - %p/%p", what, magic_version, version);
+ else
+ api_fatal ("%s version mismatch detected - %p/%p.\n\
+You have multiple copies of cygwin1.dll on your system.\n\
+Search for cygwin1.dll using the Windows Start->Find/Search facility\n\
+and delete all but the most recent version. The most recent version *should*\n\
+reside in x:\\cygwin\\bin, where 'x' is the drive on which you have\n\
+installed the cygwin distribution.", what, magic_version, version);
+}
+
+#ifdef DEBUGGING
+void __stdcall
+cygbench (const char *s)
+{
+ char buf[1024];
+ if (GetEnvironmentVariable ("CYGWIN_BENCH", buf, sizeof (buf)))
+ small_printf ("%05d ***** %s : %10d\n", GetCurrentProcessId (), s, strace.microseconds ());
+}
+#endif
diff --git a/winsup/cygwin/sec_acl.cc b/winsup/cygwin/sec_acl.cc
new file mode 100644
index 00000000000..472c20329e8
--- /dev/null
+++ b/winsup/cygwin/sec_acl.cc
@@ -0,0 +1,1042 @@
+/* sec_acl.cc: Sun compatible ACL functions.
+
+ Copyright 2000, 2001, 2002, 2003 Red Hat, Inc.
+
+ Written by Corinna Vinschen <corinna@vinschen.de>
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include <grp.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/acl.h>
+#include <ctype.h>
+#include <wingdi.h>
+#include <winuser.h>
+#include "cygerrno.h"
+#include "security.h"
+#include "path.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "pinfo.h"
+#include "cygheap.h"
+#include "pwdgrp.h"
+
+extern "C" int aclsort32 (int nentries, int, __aclent32_t *aclbufp);
+extern "C" int acl32 (const char *path, int cmd, int nentries, __aclent32_t *aclbufp);
+
+static int
+searchace (__aclent32_t *aclp, int nentries, int type, __uid32_t id = ILLEGAL_UID)
+{
+ int i;
+
+ for (i = 0; i < nentries; ++i)
+ if ((aclp[i].a_type == type && (id == ILLEGAL_UID || aclp[i].a_id == id))
+ || !aclp[i].a_type)
+ return i;
+ return -1;
+}
+
+static int
+setacl (const char *file, int nentries, __aclent32_t *aclbufp)
+{
+ security_descriptor sd_ret;
+
+ if (read_sd (file, sd_ret) <= 0)
+ {
+ debug_printf ("read_sd %E");
+ return -1;
+ }
+
+ BOOL dummy;
+
+ /* Get owner SID. */
+ PSID owner_sid;
+ if (!GetSecurityDescriptorOwner (sd_ret, &owner_sid, &dummy))
+ {
+ __seterrno ();
+ return -1;
+ }
+ cygsid owner (owner_sid);
+
+ /* Get group SID. */
+ PSID group_sid;
+ if (!GetSecurityDescriptorGroup (sd_ret, &group_sid, &dummy))
+ {
+ __seterrno ();
+ return -1;
+ }
+ cygsid group (group_sid);
+
+ /* Initialize local security descriptor. */
+ SECURITY_DESCRIPTOR sd;
+ if (!InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION))
+ {
+ __seterrno ();
+ return -1;
+ }
+ if (!SetSecurityDescriptorOwner (&sd, owner, FALSE))
+ {
+ __seterrno ();
+ return -1;
+ }
+ if (!SetSecurityDescriptorGroup (&sd, group, FALSE))
+ {
+ __seterrno ();
+ return -1;
+ }
+
+ /* Fill access control list. */
+ char acl_buf[3072];
+ PACL acl = (PACL) acl_buf;
+ size_t acl_len = sizeof (ACL);
+ int ace_off = 0;
+
+ cygsid sid;
+ struct passwd *pw;
+ struct __group32 *gr;
+ int pos;
+
+ if (!InitializeAcl (acl, 3072, ACL_REVISION))
+ {
+ __seterrno ();
+ return -1;
+ }
+ for (int i = 0; i < nentries; ++i)
+ {
+ DWORD allow;
+ /* Owner has more standard rights set. */
+ if ((aclbufp[i].a_type & ~ACL_DEFAULT) == USER_OBJ)
+ allow = STANDARD_RIGHTS_ALL | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA;
+ else
+ allow = STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES | FILE_READ_EA;
+ if (aclbufp[i].a_perm & S_IROTH)
+ allow |= FILE_GENERIC_READ;
+ if (aclbufp[i].a_perm & S_IWOTH)
+ allow |= STANDARD_RIGHTS_WRITE | FILE_GENERIC_WRITE;
+ if (aclbufp[i].a_perm & S_IXOTH)
+ allow |= FILE_GENERIC_EXECUTE;
+ if ((aclbufp[i].a_perm & (S_IWOTH | S_IXOTH)) == (S_IWOTH | S_IXOTH))
+ allow |= FILE_DELETE_CHILD;
+ /* Set inherit property. */
+ DWORD inheritance = (aclbufp[i].a_type & ACL_DEFAULT)
+ ? (SUB_CONTAINERS_AND_OBJECTS_INHERIT | INHERIT_ONLY)
+ : NO_INHERITANCE;
+ /*
+ * If a specific acl contains a corresponding default entry with
+ * identical permissions, only one Windows ACE with proper
+ * inheritance bits is created.
+ */
+ if (!(aclbufp[i].a_type & ACL_DEFAULT)
+ && aclbufp[i].a_type & (USER|GROUP|OTHER_OBJ)
+ && (pos = searchace (aclbufp + i + 1, nentries - i - 1,
+ aclbufp[i].a_type | ACL_DEFAULT,
+ (aclbufp[i].a_type & (USER|GROUP))
+ ? aclbufp[i].a_id : ILLEGAL_UID)) >= 0
+ && aclbufp[i].a_perm == aclbufp[pos].a_perm)
+ {
+ inheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
+ /* This invalidates the corresponding default entry. */
+ aclbufp[pos].a_type = USER|GROUP|ACL_DEFAULT;
+ }
+ switch (aclbufp[i].a_type)
+ {
+ case USER_OBJ:
+ if (!add_access_allowed_ace (acl, ace_off++, allow,
+ owner, acl_len, inheritance))
+ return -1;
+ break;
+ case DEF_USER_OBJ:
+ if (!add_access_allowed_ace (acl, ace_off++, allow,
+ well_known_creator_owner_sid, acl_len, inheritance))
+ return -1;
+ break;
+ case USER:
+ case DEF_USER:
+ if (!(pw = internal_getpwuid (aclbufp[i].a_id))
+ || !sid.getfrompw (pw)
+ || !add_access_allowed_ace (acl, ace_off++, allow,
+ sid, acl_len, inheritance))
+ return -1;
+ break;
+ case GROUP_OBJ:
+ if (!add_access_allowed_ace (acl, ace_off++, allow,
+ group, acl_len, inheritance))
+ return -1;
+ break;
+ case DEF_GROUP_OBJ:
+ if (!add_access_allowed_ace (acl, ace_off++, allow,
+ well_known_creator_group_sid, acl_len, inheritance))
+ return -1;
+ break;
+ case GROUP:
+ case DEF_GROUP:
+ if (!(gr = internal_getgrgid (aclbufp[i].a_id))
+ || !sid.getfromgr (gr)
+ || !add_access_allowed_ace (acl, ace_off++, allow,
+ sid, acl_len, inheritance))
+ return -1;
+ break;
+ case OTHER_OBJ:
+ case DEF_OTHER_OBJ:
+ if (!add_access_allowed_ace (acl, ace_off++, allow,
+ well_known_world_sid,
+ acl_len, inheritance))
+ return -1;
+ break;
+ }
+ }
+ /* Set AclSize to computed value. */
+ acl->AclSize = acl_len;
+ debug_printf ("ACL-Size: %d", acl_len);
+ /* Create DACL for local security descriptor. */
+ if (!SetSecurityDescriptorDacl (&sd, TRUE, acl, FALSE))
+ {
+ __seterrno ();
+ return -1;
+ }
+ /* Make self relative security descriptor in sd_ret. */
+ DWORD sd_size = 0;
+ MakeSelfRelativeSD (&sd, sd_ret, &sd_size);
+ if (sd_size <= 0)
+ {
+ __seterrno ();
+ return -1;
+ }
+ if (!sd_ret.realloc (sd_size))
+ {
+ set_errno (ENOMEM);
+ return -1;
+ }
+ if (!MakeSelfRelativeSD (&sd, sd_ret, &sd_size))
+ {
+ __seterrno ();
+ return -1;
+ }
+ debug_printf ("Created SD-Size: %d", sd_ret.size ());
+ return write_sd (file, sd_ret);
+}
+
+/* Temporary access denied bits */
+#define DENY_R 040000
+#define DENY_W 020000
+#define DENY_X 010000
+
+static void
+getace (__aclent32_t &acl, int type, int id, DWORD win_ace_mask,
+ DWORD win_ace_type)
+{
+ acl.a_type = type;
+ acl.a_id = id;
+
+ if ((win_ace_mask & FILE_READ_BITS) && !(acl.a_perm & (S_IROTH | DENY_R)))
+ if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE)
+ acl.a_perm |= S_IROTH;
+ else if (win_ace_type == ACCESS_DENIED_ACE_TYPE)
+ acl.a_perm |= DENY_R;
+
+ if ((win_ace_mask & FILE_WRITE_BITS) && !(acl.a_perm & (S_IWOTH | DENY_W)))
+ if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE)
+ acl.a_perm |= S_IWOTH;
+ else if (win_ace_type == ACCESS_DENIED_ACE_TYPE)
+ acl.a_perm |= DENY_W;
+
+ if ((win_ace_mask & FILE_EXEC_BITS) && !(acl.a_perm & (S_IXOTH | DENY_X)))
+ if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE)
+ acl.a_perm |= S_IXOTH;
+ else if (win_ace_type == ACCESS_DENIED_ACE_TYPE)
+ acl.a_perm |= DENY_X;
+}
+
+static int
+getacl (const char *file, DWORD attr, int nentries, __aclent32_t *aclbufp)
+{
+ security_descriptor sd;
+
+ int ret;
+ if ((ret = read_sd (file, sd)) <= 0)
+ {
+ debug_printf ("read_sd %E");
+ return ret;
+ }
+
+ cygpsid owner_sid;
+ cygpsid group_sid;
+ BOOL dummy;
+ __uid32_t uid;
+ __gid32_t gid;
+
+ if (!GetSecurityDescriptorOwner (sd, (PSID *) &owner_sid, &dummy))
+ {
+ debug_printf ("GetSecurityDescriptorOwner %E");
+ __seterrno ();
+ return -1;
+ }
+ uid = owner_sid.get_uid ();
+
+ if (!GetSecurityDescriptorGroup (sd, (PSID *) &group_sid, &dummy))
+ {
+ debug_printf ("GetSecurityDescriptorGroup %E");
+ __seterrno ();
+ return -1;
+ }
+ gid = group_sid.get_gid ();
+
+ __aclent32_t lacl[MAX_ACL_ENTRIES];
+ memset (&lacl, 0, MAX_ACL_ENTRIES * sizeof (__aclent32_t));
+ lacl[0].a_type = USER_OBJ;
+ lacl[0].a_id = uid;
+ lacl[1].a_type = GROUP_OBJ;
+ lacl[1].a_id = gid;
+ lacl[2].a_type = OTHER_OBJ;
+ lacl[2].a_id = ILLEGAL_GID;
+ lacl[3].a_type = CLASS_OBJ;
+ lacl[3].a_id = ILLEGAL_GID;
+ lacl[3].a_perm = S_IROTH | S_IWOTH | S_IXOTH;
+
+ PACL acl;
+ BOOL acl_exists;
+
+ if (!GetSecurityDescriptorDacl (sd, &acl_exists, &acl, &dummy))
+ {
+ __seterrno ();
+ debug_printf ("GetSecurityDescriptorDacl %E");
+ return -1;
+ }
+
+ int pos, i, types_def = 0;
+
+ if (!acl_exists || !acl)
+ for (pos = 0; pos < 3; ++pos) /* Don't change CLASS_OBJ entry */
+ lacl[pos].a_perm = S_IROTH | S_IWOTH | S_IXOTH;
+ else
+ {
+ for (i = 0; i < acl->AceCount; ++i)
+ {
+ ACCESS_ALLOWED_ACE *ace;
+
+ if (!GetAce (acl, i, (PVOID *) &ace))
+ continue;
+
+ cygpsid ace_sid ((PSID) &ace->SidStart);
+ int id;
+ int type = 0;
+
+ if (ace_sid == well_known_world_sid)
+ {
+ type = OTHER_OBJ;
+ id = ILLEGAL_GID;
+ }
+ else if (ace_sid == group_sid)
+ {
+ type = GROUP_OBJ;
+ id = gid;
+ }
+ else if (ace_sid == owner_sid)
+ {
+ type = USER_OBJ;
+ id = uid;
+ }
+ else if (ace_sid == well_known_creator_group_sid)
+ {
+ type = GROUP_OBJ | ACL_DEFAULT;
+ id = ILLEGAL_GID;
+ }
+ else if (ace_sid == well_known_creator_owner_sid)
+ {
+ type = USER_OBJ | ACL_DEFAULT;
+ id = ILLEGAL_GID;
+ }
+ else
+ id = ace_sid.get_id (true, &type);
+
+ if (!type)
+ continue;
+ if (!(ace->Header.AceFlags & INHERIT_ONLY || type & ACL_DEFAULT))
+ {
+ if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, id)) >= 0)
+ getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType);
+ }
+ if ((ace->Header.AceFlags & SUB_CONTAINERS_AND_OBJECTS_INHERIT)
+ && (attr & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ if (type == USER_OBJ)
+ type = USER;
+ else if (type == GROUP_OBJ)
+ type = GROUP;
+ type |= ACL_DEFAULT;
+ types_def |= type;
+ if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, id)) >= 0)
+ getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType);
+ }
+ }
+ /* Include DEF_CLASS_OBJ if any default ace exists */
+ if ((types_def & (USER|GROUP))
+ && ((pos = searchace (lacl, MAX_ACL_ENTRIES, DEF_CLASS_OBJ)) >= 0))
+ {
+ lacl[pos].a_type = DEF_CLASS_OBJ;
+ lacl[pos].a_id = ILLEGAL_GID;
+ lacl[pos].a_perm = S_IRWXU | S_IRWXG | S_IRWXO;
+ }
+ }
+ if ((pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) < 0)
+ pos = MAX_ACL_ENTRIES;
+ if (aclbufp) {
+ if (owner_sid == group_sid)
+ lacl[0].a_perm = lacl[1].a_perm;
+ if (pos > nentries)
+ {
+ set_errno (ENOSPC);
+ return -1;
+ }
+ memcpy (aclbufp, lacl, pos * sizeof (__aclent32_t));
+ for (i = 0; i < pos; ++i)
+ aclbufp[i].a_perm &= ~(DENY_R | DENY_W | DENY_X);
+ aclsort32 (pos, 0, aclbufp);
+ }
+ syscall_printf ("%d = getacl (%s)", pos, file);
+ return pos;
+}
+
+static int
+acl_worker (const char *path, int cmd, int nentries, __aclent32_t *aclbufp,
+ int nofollow)
+{
+ extern suffix_info stat_suffixes[];
+ path_conv real_path (path, (nofollow ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW) | PC_FULL, stat_suffixes);
+ if (real_path.error)
+ {
+ set_errno (real_path.error);
+ syscall_printf ("-1 = acl (%s)", path);
+ return -1;
+ }
+ if (!real_path.has_acls () || !allow_ntsec)
+ {
+ struct __stat64 st;
+ int ret = -1;
+
+ switch (cmd)
+ {
+ case SETACL:
+ set_errno (ENOSYS);
+ break;
+ case GETACL:
+ if (!aclbufp)
+ set_errno(EFAULT);
+ else if (nentries < MIN_ACL_ENTRIES)
+ set_errno (ENOSPC);
+ else if ((nofollow && !lstat64 (path, &st))
+ || (!nofollow && !stat64 (path, &st)))
+ {
+ aclbufp[0].a_type = USER_OBJ;
+ aclbufp[0].a_id = st.st_uid;
+ aclbufp[0].a_perm = (st.st_mode & S_IRWXU) >> 6;
+ aclbufp[1].a_type = GROUP_OBJ;
+ aclbufp[1].a_id = st.st_gid;
+ aclbufp[1].a_perm = (st.st_mode & S_IRWXG) >> 3;
+ aclbufp[2].a_type = OTHER_OBJ;
+ aclbufp[2].a_id = ILLEGAL_GID;
+ aclbufp[2].a_perm = st.st_mode & S_IRWXO;
+ aclbufp[3].a_type = CLASS_OBJ;
+ aclbufp[3].a_id = ILLEGAL_GID;
+ aclbufp[3].a_perm = S_IRWXU | S_IRWXG | S_IRWXO;
+ ret = MIN_ACL_ENTRIES;
+ }
+ break;
+ case GETACLCNT:
+ ret = MIN_ACL_ENTRIES;
+ break;
+ }
+ syscall_printf ("%d = acl (%s)", ret, path);
+ return ret;
+ }
+ switch (cmd)
+ {
+ case SETACL:
+ if (!aclsort32 (nentries, 0, aclbufp))
+ return setacl (real_path.get_win32 (),
+ nentries, aclbufp);
+ break;
+ case GETACL:
+ if (!aclbufp)
+ set_errno(EFAULT);
+ else
+ return getacl (real_path.get_win32 (),
+ real_path.file_attributes (),
+ nentries, aclbufp);
+ break;
+ case GETACLCNT:
+ return getacl (real_path.get_win32 (),
+ real_path.file_attributes (),
+ 0, NULL);
+ default:
+ set_errno (EINVAL);
+ break;
+ }
+ syscall_printf ("-1 = acl (%s)", path);
+ return -1;
+}
+
+extern "C" int
+acl32 (const char *path, int cmd, int nentries, __aclent32_t *aclbufp)
+{
+ return acl_worker (path, cmd, nentries, aclbufp, 0);
+}
+
+extern "C" int
+lacl32 (const char *path, int cmd, int nentries, __aclent32_t *aclbufp)
+{
+ return acl_worker (path, cmd, nentries, aclbufp, 1);
+}
+
+extern "C" int
+facl32 (int fd, int cmd, int nentries, __aclent32_t *aclbufp)
+{
+ cygheap_fdget cfd (fd);
+ if (cfd < 0)
+ {
+ syscall_printf ("-1 = facl (%d)", fd);
+ return -1;
+ }
+ const char *path = cfd->get_name ();
+ if (path == NULL)
+ {
+ syscall_printf ("-1 = facl (%d) (no name)", fd);
+ set_errno (ENOSYS);
+ return -1;
+ }
+ syscall_printf ("facl (%d): calling acl (%s)", fd, path);
+ return acl_worker (path, cmd, nentries, aclbufp, 0);
+}
+
+extern "C" int
+aclcheck32 (__aclent32_t *aclbufp, int nentries, int *which)
+{
+ bool has_user_obj = false;
+ bool has_group_obj = false;
+ bool has_other_obj = false;
+ bool has_class_obj = false;
+ bool has_ug_objs = false;
+ bool has_def_user_obj = false;
+ bool has_def_group_obj = false;
+ bool has_def_other_obj = false;
+ bool has_def_class_obj = false;
+ bool has_def_ug_objs = false;
+ int pos2;
+
+ for (int pos = 0; pos < nentries; ++pos)
+ switch (aclbufp[pos].a_type)
+ {
+ case USER_OBJ:
+ if (has_user_obj)
+ {
+ if (which)
+ *which = pos;
+ return USER_ERROR;
+ }
+ has_user_obj = true;
+ break;
+ case GROUP_OBJ:
+ if (has_group_obj)
+ {
+ if (which)
+ *which = pos;
+ return GRP_ERROR;
+ }
+ has_group_obj = true;
+ break;
+ case OTHER_OBJ:
+ if (has_other_obj)
+ {
+ if (which)
+ *which = pos;
+ return OTHER_ERROR;
+ }
+ has_other_obj = true;
+ break;
+ case CLASS_OBJ:
+ if (has_class_obj)
+ {
+ if (which)
+ *which = pos;
+ return CLASS_ERROR;
+ }
+ has_class_obj = true;
+ break;
+ case USER:
+ case GROUP:
+ if ((pos2 = searchace (aclbufp + pos + 1, nentries - pos - 1,
+ aclbufp[pos].a_type, aclbufp[pos].a_id)) >= 0)
+ {
+ if (which)
+ *which = pos2;
+ return DUPLICATE_ERROR;
+ }
+ has_ug_objs = true;
+ break;
+ case DEF_USER_OBJ:
+ if (has_def_user_obj)
+ {
+ if (which)
+ *which = pos;
+ return USER_ERROR;
+ }
+ has_def_user_obj = true;
+ break;
+ case DEF_GROUP_OBJ:
+ if (has_def_group_obj)
+ {
+ if (which)
+ *which = pos;
+ return GRP_ERROR;
+ }
+ has_def_group_obj = true;
+ break;
+ case DEF_OTHER_OBJ:
+ if (has_def_other_obj)
+ {
+ if (which)
+ *which = pos;
+ return OTHER_ERROR;
+ }
+ has_def_other_obj = true;
+ break;
+ case DEF_CLASS_OBJ:
+ if (has_def_class_obj)
+ {
+ if (which)
+ *which = pos;
+ return CLASS_ERROR;
+ }
+ has_def_class_obj = true;
+ break;
+ case DEF_USER:
+ case DEF_GROUP:
+ if ((pos2 = searchace (aclbufp + pos + 1, nentries - pos - 1,
+ aclbufp[pos].a_type, aclbufp[pos].a_id)) >= 0)
+ {
+ if (which)
+ *which = pos2;
+ return DUPLICATE_ERROR;
+ }
+ has_def_ug_objs = true;
+ break;
+ default:
+ return ENTRY_ERROR;
+ }
+ if (!has_user_obj
+ || !has_group_obj
+ || !has_other_obj
+#if 0
+ /* These checks are not ok yet since CLASS_OBJ isn't fully implemented. */
+ || (has_ug_objs && !has_class_obj)
+ || (has_def_ug_objs && !has_def_class_obj)
+#endif
+ )
+ {
+ if (which)
+ *which = -1;
+ return MISS_ERROR;
+ }
+ return 0;
+}
+
+static int
+acecmp (const void *a1, const void *a2)
+{
+#define ace(i) ((const __aclent32_t *) a##i)
+ int ret = ace (1)->a_type - ace (2)->a_type;
+ if (!ret)
+ ret = ace (1)->a_id - ace (2)->a_id;
+ return ret;
+#undef ace
+}
+
+extern "C" int
+aclsort32 (int nentries, int, __aclent32_t *aclbufp)
+{
+ if (aclcheck32 (aclbufp, nentries, NULL))
+ return -1;
+ if (!aclbufp || nentries < 1)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ qsort ((void *) aclbufp, nentries, sizeof (__aclent32_t), acecmp);
+ return 0;
+}
+
+extern "C" int
+acltomode32 (__aclent32_t *aclbufp, int nentries, mode_t *modep)
+{
+ int pos;
+
+ if (!aclbufp || nentries < 1 || !modep)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ *modep = 0;
+ if ((pos = searchace (aclbufp, nentries, USER_OBJ)) < 0
+ || !aclbufp[pos].a_type)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ *modep |= (aclbufp[pos].a_perm & S_IRWXO) << 6;
+ if ((pos = searchace (aclbufp, nentries, GROUP_OBJ)) < 0
+ || !aclbufp[pos].a_type)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ *modep |= (aclbufp[pos].a_perm & S_IRWXO) << 3;
+ int cpos;
+ if ((cpos = searchace (aclbufp, nentries, CLASS_OBJ)) >= 0
+ && aclbufp[cpos].a_type == CLASS_OBJ)
+ *modep |= ((aclbufp[pos].a_perm & S_IRWXO) & aclbufp[cpos].a_perm) << 3;
+ if ((pos = searchace (aclbufp, nentries, OTHER_OBJ)) < 0
+ || !aclbufp[pos].a_type)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ *modep |= aclbufp[pos].a_perm & S_IRWXO;
+ return 0;
+}
+
+extern "C" int
+aclfrommode32 (__aclent32_t *aclbufp, int nentries, mode_t *modep)
+{
+ int pos;
+
+ if (!aclbufp || nentries < 1 || !modep)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ if ((pos = searchace (aclbufp, nentries, USER_OBJ)) < 0
+ || !aclbufp[pos].a_type)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ aclbufp[pos].a_perm = (*modep & S_IRWXU) >> 6;
+ if ((pos = searchace (aclbufp, nentries, GROUP_OBJ)) < 0
+ || !aclbufp[pos].a_type)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ aclbufp[pos].a_perm = (*modep & S_IRWXG) >> 3;
+ if ((pos = searchace (aclbufp, nentries, CLASS_OBJ)) >= 0
+ && aclbufp[pos].a_type == CLASS_OBJ)
+ aclbufp[pos].a_perm = (*modep & S_IRWXG) >> 3;
+ if ((pos = searchace (aclbufp, nentries, OTHER_OBJ)) < 0
+ || !aclbufp[pos].a_type)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ aclbufp[pos].a_perm = (*modep & S_IRWXO);
+ return 0;
+}
+
+extern "C" int
+acltopbits32 (__aclent32_t *aclbufp, int nentries, mode_t *pbitsp)
+{
+ return acltomode32 (aclbufp, nentries, pbitsp);
+}
+
+extern "C" int
+aclfrompbits32 (__aclent32_t *aclbufp, int nentries, mode_t *pbitsp)
+{
+ return aclfrommode32 (aclbufp, nentries, pbitsp);
+}
+
+static char *
+permtostr (mode_t perm)
+{
+ static char pbuf[4];
+
+ pbuf[0] = (perm & S_IROTH) ? 'r' : '-';
+ pbuf[1] = (perm & S_IWOTH) ? 'w' : '-';
+ pbuf[2] = (perm & S_IXOTH) ? 'x' : '-';
+ pbuf[3] = '\0';
+ return pbuf;
+}
+
+extern "C" char *
+acltotext32 (__aclent32_t *aclbufp, int aclcnt)
+{
+ if (!aclbufp || aclcnt < 1 || aclcnt > MAX_ACL_ENTRIES
+ || aclcheck32 (aclbufp, aclcnt, NULL))
+ {
+ set_errno (EINVAL);
+ return NULL;
+ }
+ char buf[32000];
+ buf[0] = '\0';
+ bool first = true;
+
+ for (int pos = 0; pos < aclcnt; ++pos)
+ {
+ if (!first)
+ strcat (buf, ",");
+ first = false;
+ if (aclbufp[pos].a_type & ACL_DEFAULT)
+ strcat (buf, "default");
+ switch (aclbufp[pos].a_type)
+ {
+ case USER_OBJ:
+ __small_sprintf (buf + strlen (buf), "user::%s",
+ permtostr (aclbufp[pos].a_perm));
+ break;
+ case USER:
+ __small_sprintf (buf + strlen (buf), "user:%d:%s",
+ aclbufp[pos].a_id, permtostr (aclbufp[pos].a_perm));
+ break;
+ case GROUP_OBJ:
+ __small_sprintf (buf + strlen (buf), "group::%s",
+ permtostr (aclbufp[pos].a_perm));
+ break;
+ case GROUP:
+ __small_sprintf (buf + strlen (buf), "group:%d:%s",
+ aclbufp[pos].a_id, permtostr (aclbufp[pos].a_perm));
+ break;
+ case CLASS_OBJ:
+ __small_sprintf (buf + strlen (buf), "mask::%s",
+ permtostr (aclbufp[pos].a_perm));
+ break;
+ case OTHER_OBJ:
+ __small_sprintf (buf + strlen (buf), "other::%s",
+ permtostr (aclbufp[pos].a_perm));
+ break;
+ default:
+ set_errno (EINVAL);
+ return NULL;
+ }
+ }
+ return strdup (buf);
+}
+
+static mode_t
+permfromstr (char *perm)
+{
+ mode_t mode = 0;
+
+ if (strlen (perm) != 3)
+ return 01000;
+ if (perm[0] == 'r')
+ mode |= S_IROTH;
+ else if (perm[0] != '-')
+ return 01000;
+ if (perm[1] == 'w')
+ mode |= S_IWOTH;
+ else if (perm[1] != '-')
+ return 01000;
+ if (perm[2] == 'x')
+ mode |= S_IXOTH;
+ else if (perm[2] != '-')
+ return 01000;
+ return mode;
+}
+
+extern "C" __aclent32_t *
+aclfromtext32 (char *acltextp, int *)
+{
+ if (!acltextp)
+ {
+ set_errno (EINVAL);
+ return NULL;
+ }
+ char buf[strlen (acltextp) + 1];
+ __aclent32_t lacl[MAX_ACL_ENTRIES];
+ memset (lacl, 0, sizeof lacl);
+ int pos = 0;
+ strcpy (buf, acltextp);
+ char *lasts;
+ for (char *c = strtok_r (buf, ",", &lasts);
+ c;
+ c = strtok_r (NULL, ",", &lasts))
+ {
+ if (!strncmp (c, "default", 7))
+ {
+ lacl[pos].a_type |= ACL_DEFAULT;
+ c += 7;
+ }
+ if (!strncmp (c, "user:", 5))
+ {
+ if (c[5] == ':')
+ lacl[pos].a_type |= USER_OBJ;
+ else
+ {
+ lacl[pos].a_type |= USER;
+ c += 5;
+ if (isalpha (*c))
+ {
+ struct passwd *pw = internal_getpwnam (c);
+ if (!pw)
+ {
+ set_errno (EINVAL);
+ return NULL;
+ }
+ lacl[pos].a_id = pw->pw_uid;
+ c = strechr (c, ':');
+ }
+ else if (isdigit (*c))
+ lacl[pos].a_id = strtol (c, &c, 10);
+ if (*c != ':')
+ {
+ set_errno (EINVAL);
+ return NULL;
+ }
+ }
+ }
+ else if (!strncmp (c, "group:", 6))
+ {
+ if (c[5] == ':')
+ lacl[pos].a_type |= GROUP_OBJ;
+ else
+ {
+ lacl[pos].a_type |= GROUP;
+ c += 5;
+ if (isalpha (*c))
+ {
+ struct __group32 *gr = internal_getgrnam (c);
+ if (!gr)
+ {
+ set_errno (EINVAL);
+ return NULL;
+ }
+ lacl[pos].a_id = gr->gr_gid;
+ c = strechr (c, ':');
+ }
+ else if (isdigit (*c))
+ lacl[pos].a_id = strtol (c, &c, 10);
+ if (*c != ':')
+ {
+ set_errno (EINVAL);
+ return NULL;
+ }
+ }
+ }
+ else if (!strncmp (c, "mask:", 5))
+ {
+ if (c[5] == ':')
+ lacl[pos].a_type |= CLASS_OBJ;
+ else
+ {
+ set_errno (EINVAL);
+ return NULL;
+ }
+ }
+ else if (!strncmp (c, "other:", 6))
+ {
+ if (c[5] == ':')
+ lacl[pos].a_type |= OTHER_OBJ;
+ else
+ {
+ set_errno (EINVAL);
+ return NULL;
+ }
+ }
+ if ((lacl[pos].a_perm = permfromstr (c)) == 01000)
+ {
+ set_errno (EINVAL);
+ return NULL;
+ }
+ ++pos;
+ }
+ __aclent32_t *aclp = (__aclent32_t *) malloc (pos * sizeof (__aclent32_t));
+ if (aclp)
+ memcpy (aclp, lacl, pos * sizeof (__aclent32_t));
+ return aclp;
+}
+
+/* __aclent16_t and __aclent32_t have same size and same member offsets */
+static __aclent32_t *
+acl16to32 (__aclent16_t *aclbufp, int nentries)
+{
+ __aclent32_t *aclbufp32 = (__aclent32_t *) aclbufp;
+ if (aclbufp32)
+ for (int i = 0; i < nentries; i++)
+ aclbufp32[i].a_id &= USHRT_MAX;
+ return aclbufp32;
+}
+
+extern "C" int
+acl (const char *path, int cmd, int nentries, __aclent16_t *aclbufp)
+{
+ return acl32 (path, cmd, nentries, acl16to32 (aclbufp, nentries));
+}
+
+extern "C" int
+facl (int fd, int cmd, int nentries, __aclent16_t *aclbufp)
+{
+ return facl32 (fd, cmd, nentries, acl16to32 (aclbufp, nentries));
+}
+
+extern "C" int
+lacl (const char *path, int cmd, int nentries, __aclent16_t *aclbufp)
+{
+ return lacl32 (path, cmd, nentries, acl16to32 (aclbufp, nentries));
+}
+
+extern "C" int
+aclcheck (__aclent16_t *aclbufp, int nentries, int *which)
+{
+ return aclcheck32 (acl16to32 (aclbufp, nentries), nentries, which);
+}
+
+extern "C" int
+aclsort (int nentries, int i, __aclent16_t *aclbufp)
+{
+ return aclsort32 (nentries, i, acl16to32 (aclbufp, nentries));
+}
+
+
+extern "C" int
+acltomode (__aclent16_t *aclbufp, int nentries, mode_t *modep)
+{
+ return acltomode32 (acl16to32 (aclbufp, nentries), nentries, modep);
+}
+
+extern "C" int
+aclfrommode (__aclent16_t *aclbufp, int nentries, mode_t *modep)
+{
+ return aclfrommode32 ((__aclent32_t *)aclbufp, nentries, modep);
+}
+
+extern "C" int
+acltopbits (__aclent16_t *aclbufp, int nentries, mode_t *pbitsp)
+{
+ return acltopbits32 (acl16to32 (aclbufp, nentries), nentries, pbitsp);
+}
+
+extern "C" int
+aclfrompbits (__aclent16_t *aclbufp, int nentries, mode_t *pbitsp)
+{
+ return aclfrompbits32 ((__aclent32_t *)aclbufp, nentries, pbitsp);
+}
+
+extern "C" char *
+acltotext (__aclent16_t *aclbufp, int aclcnt)
+{
+ return acltotext32 (acl16to32 (aclbufp, aclcnt), aclcnt);
+}
+
+extern "C" __aclent16_t *
+aclfromtext (char *acltextp, int * aclcnt)
+{
+ return (__aclent16_t *) aclfromtext32 (acltextp, aclcnt);
+}
diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc
new file mode 100644
index 00000000000..b53aa5f58bf
--- /dev/null
+++ b/winsup/cygwin/sigproc.cc
@@ -0,0 +1,1276 @@
+/* sigproc.cc: inter/intra signal and sub process handler
+
+ Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
+
+ Written by Christopher Faylor
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include <stdlib.h>
+#include <time.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <sys/cygwin.h>
+#include <assert.h>
+#include <sys/signal.h>
+#include "cygerrno.h"
+#include "sync.h"
+#include "pinfo.h"
+#include "security.h"
+#include "path.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "cygheap.h"
+#include "child_info_magic.h"
+#include "shared_info.h"
+#include "cygthread.h"
+#include "cygtls.h"
+#include "sigproc.h"
+#include "perthread.h"
+#include "exceptions.h"
+
+/*
+ * Convenience defines
+ */
+#define WSSC 60000 // Wait for signal completion
+#define WPSP 40000 // Wait for proc_subproc mutex
+
+#define PSIZE 63 // Number of processes
+
+#define wake_wait_subproc() SetEvent (events[0])
+
+#define no_signals_available() (!hwait_sig || (myself->sendsig == INVALID_HANDLE_VALUE) || exit_state)
+
+#define NZOMBIES 256
+
+struct sigelem
+{
+ int sig;
+ int pid;
+ _threadinfo *tls;
+ class sigelem *next;
+ friend class pending_signals;
+ friend int __stdcall sig_dispatch_pending ();
+};
+
+class pending_signals
+{
+ sigelem sigs[NSIG + 1];
+ sigelem start;
+ sigelem *end;
+ sigelem *prev;
+ sigelem *curr;
+ int empty;
+public:
+ void reset () {curr = &start; prev = &start;}
+ void add (int sig, int pid, _threadinfo *tls);
+ void del ();
+ sigelem *next ();
+ friend int __stdcall sig_dispatch_pending ();
+};
+
+struct sigpacket
+{
+ int sig;
+ pid_t pid;
+ HANDLE wakeup;
+ sigset_t *mask;
+ _threadinfo *tls;
+};
+
+static pending_signals sigqueue;
+
+struct sigaction *global_sigs;
+
+void __stdcall
+sigalloc ()
+{
+ cygheap->sigs = global_sigs =
+ (struct sigaction *) ccalloc (HEAP_SIGS, NSIG, sizeof (struct sigaction));
+}
+
+void __stdcall
+signal_fixup_after_exec ()
+{
+ global_sigs = cygheap->sigs;
+ /* Set up child's signal handlers */
+ for (int i = 0; i < NSIG; i++)
+ {
+ global_sigs[i].sa_mask = 0;
+ if (global_sigs[i].sa_handler != SIG_IGN)
+ global_sigs[i].sa_handler = SIG_DFL;
+ }
+}
+
+/*
+ * Global variables
+ */
+const char *__sp_fn ;
+int __sp_ln;
+
+char NO_COPY myself_nowait_dummy[1] = {'0'};// Flag to sig_send that signal goes to
+ // current process but no wait is required
+HANDLE NO_COPY signal_arrived; // Event signaled when a signal has
+ // resulted in a user-specified
+ // function call
+/*
+ * Common variables
+ */
+
+
+/* How long to wait for message/signals. Normally this is infinite.
+ * On termination, however, these are set to zero as a flag to exit.
+ */
+
+#define Static static NO_COPY
+
+Static DWORD proc_loop_wait = 1000; // Wait for subprocesses to exit
+
+Static HANDLE sigcomplete_main; // Event signaled when a signal has
+ // finished processing for the main
+ // thread
+HANDLE NO_COPY sigCONT; // Used to "STOP" a process
+Static cygthread *hwait_sig; // Handle of wait_sig thread
+Static cygthread *hwait_subproc; // Handle of sig_subproc thread
+
+Static HANDLE wait_sig_inited; // Control synchronization of
+ // message queue startup
+
+/* Used by WaitForMultipleObjects. These are handles to child processes.
+ */
+Static HANDLE events[PSIZE + 1]; // All my children's handles++
+#define hchildren (events + 1) // Where the children handles begin
+Static char cpchildren[PSIZE * sizeof (pinfo)]; // All my children info
+Static int nchildren; // Number of active children
+Static char czombies[(NZOMBIES + 1) * sizeof (pinfo)]; // All my deceased children info
+Static int nzombies; // Number of deceased children
+
+#define pchildren ((pinfo *) cpchildren)
+#define zombies ((pinfo *) czombies)
+
+Static waitq waitq_head = {0, 0, 0, 0, 0, 0, 0};// Start of queue for wait'ing threads
+Static waitq waitq_main; // Storage for main thread
+
+muto NO_COPY *sync_proc_subproc = NULL; // Control access to subproc stuff
+
+DWORD NO_COPY sigtid = 0; // ID of the signal thread
+
+/* Functions
+ */
+static int __stdcall checkstate (waitq *) __attribute__ ((regparm (1)));
+static __inline__ bool get_proc_lock (DWORD, DWORD);
+static void __stdcall remove_zombie (int);
+static DWORD WINAPI wait_sig (VOID *arg);
+static int __stdcall stopped_or_terminated (waitq *, _pinfo *);
+static DWORD WINAPI wait_subproc (VOID *);
+
+/* Determine if the parent process is alive.
+ */
+
+bool __stdcall
+my_parent_is_alive ()
+{
+ bool res;
+ if (!myself->ppid_handle)
+ {
+ debug_printf ("No myself->ppid_handle");
+ res = false;
+ }
+ else
+ for (int i = 0; i < 2; i++)
+ switch (res = WaitForSingleObject (myself->ppid_handle, 0))
+ {
+ case WAIT_OBJECT_0:
+ debug_printf ("parent dead.");
+ res = false;
+ goto out;
+ case WAIT_TIMEOUT:
+ debug_printf ("parent still alive");
+ res = true;
+ goto out;
+ case WAIT_FAILED:
+ DWORD werr = GetLastError ();
+ if (werr == ERROR_INVALID_HANDLE && i == 0)
+ continue;
+ system_printf ("WFSO for myself->ppid_handle(%p) failed, error %d",
+ myself->ppid_handle, werr);
+ res = false;
+ goto out;
+ }
+out:
+ return res;
+}
+
+void __stdcall
+wait_for_sigthread ()
+{
+ sigproc_printf ("wait_sig_inited %p", wait_sig_inited);
+ HANDLE hsig_inited = wait_sig_inited;
+ (void) WaitForSingleObject (hsig_inited, INFINITE);
+ wait_sig_inited = NULL;
+ (void) ForceCloseHandle1 (hsig_inited, wait_sig_inited);
+}
+
+/* Get the sync_proc_subproc muto to control access to
+ * children, zombie arrays.
+ * Attempt to handle case where process is exiting as we try to grab
+ * the mutex.
+ */
+static bool
+get_proc_lock (DWORD what, DWORD val)
+{
+ Static int lastwhat = -1;
+ if (!sync_proc_subproc)
+ {
+ sigproc_printf ("sync_proc_subproc is NULL (1)");
+ return false;
+ }
+ if (sync_proc_subproc->acquire (WPSP))
+ {
+ lastwhat = what;
+ return true;
+ }
+ if (!sync_proc_subproc)
+ {
+ sigproc_printf ("sync_proc_subproc is NULL (2)");
+ return false;
+ }
+ system_printf ("Couldn't aquire sync_proc_subproc for(%d,%d), %E, last %d",
+ what, val, lastwhat);
+ return true;
+}
+
+static bool __stdcall
+proc_can_be_signalled (_pinfo *p)
+{
+ if (p->sendsig == INVALID_HANDLE_VALUE)
+ {
+ set_errno (EPERM);
+ return false;
+ }
+
+ if (p == myself_nowait || p == myself)
+ return hwait_sig;
+
+ if (ISSTATE (p, PID_INITIALIZING) ||
+ (((p)->process_state & (PID_ACTIVE | PID_IN_USE)) ==
+ (PID_ACTIVE | PID_IN_USE)))
+ return true;
+
+ set_errno (ESRCH);
+ return false;
+}
+
+bool __stdcall
+pid_exists (pid_t pid)
+{
+ pinfo p (pid);
+ return proc_exists (p);
+}
+
+/* Test to determine if a process really exists and is processing signals.
+ */
+bool __stdcall
+proc_exists (_pinfo *p)
+{
+ return p && !(p->process_state & (PID_EXITED | PID_ZOMBIE));
+}
+
+/* Return 1 if this is one of our children, zero otherwise.
+ FIXME: This really should be integrated with the rest of the proc_subproc
+ testing. Scanning these lists twice is inefficient. */
+int __stdcall
+mychild (int pid)
+{
+ for (int i = 0; i < nchildren; i++)
+ if (pchildren[i]->pid == pid)
+ return 1;
+ for (int i = 0; i < nzombies; i++)
+ if (zombies[i]->pid == pid)
+ return 1;
+ return 0;
+}
+
+/* Handle all subprocess requests
+ */
+#define vchild (*((pinfo *) val))
+int __stdcall
+proc_subproc (DWORD what, DWORD val)
+{
+ int rc = 1;
+ int potential_match;
+ _pinfo *child;
+ int clearing;
+ waitq *w;
+ int thiszombie;
+
+#define wval ((waitq *) val)
+
+ sigproc_printf ("args: %x, %d", what, val);
+
+ if (!get_proc_lock (what, val)) // Serialize access to this function
+ {
+ system_printf ("couldn't get proc lock. what %d, val %d", what, val);
+ goto out1;
+ }
+
+ switch (what)
+ {
+ /* Add a new subprocess to the children arrays.
+ * (usually called from the main thread)
+ */
+ case PROC_ADDCHILD:
+ if (nchildren >= PSIZE - 1)
+ {
+ rc = 0;
+ break;
+ }
+ pchildren[nchildren] = vchild;
+ hchildren[nchildren] = vchild->hProcess;
+ if (!DuplicateHandle (hMainProc, vchild->hProcess, hMainProc, &vchild->pid_handle,
+ 0, 0, DUPLICATE_SAME_ACCESS))
+ system_printf ("Couldn't duplicate child handle for pid %d, %E", vchild->pid);
+ ProtectHandle1 (vchild->pid_handle, pid_handle);
+
+ if (!DuplicateHandle (hMainProc, hMainProc, vchild->hProcess, &vchild->ppid_handle,
+ SYNCHRONIZE | PROCESS_DUP_HANDLE, TRUE, 0))
+ system_printf ("Couldn't duplicate my handle<%p> for pid %d, %E", hMainProc, vchild->pid);
+ vchild->ppid = myself->pid;
+ vchild->uid = myself->uid;
+ vchild->gid = myself->gid;
+ vchild->pgid = myself->pgid;
+ vchild->sid = myself->sid;
+ vchild->ctty = myself->ctty;
+ vchild->process_state |= PID_INITIALIZING | (myself->process_state & PID_USETTY);
+
+ sigproc_printf ("added pid %d to wait list, slot %d, winpid %p, handle %p",
+ vchild->pid, nchildren, vchild->dwProcessId,
+ vchild->hProcess);
+ nchildren++;
+
+ wake_wait_subproc ();
+ break;
+
+ /* A child process had terminated.
+ Possibly this is just due to an exec(). Cygwin implements an exec()
+ as a "handoff" from one windows process to another. If child->hProcess
+ is different from what is recorded in hchildren, then this is an exec().
+ Otherwise this is a normal child termination event.
+ (called from wait_subproc thread) */
+ case PROC_CHILDTERMINATED:
+ if (hchildren[val] != pchildren[val]->hProcess)
+ {
+ sigproc_printf ("pid %d[%d], reparented old hProcess %p, new %p",
+ pchildren[val]->pid, val, hchildren[val], pchildren[val]->hProcess);
+ HANDLE h = hchildren[val];
+ hchildren[val] = pchildren[val]->hProcess; /* Filled out by child */
+ sync_proc_subproc->release (); // Release the lock ASAP
+ ForceCloseHandle1 (h, childhProc);
+ ProtectHandle1 (pchildren[val]->hProcess, childhProc);
+ rc = 0;
+ goto out; // This was an exec()
+ }
+
+ sigproc_printf ("pid %d[%d] terminated, handle %p, nchildren %d, nzombies %d",
+ pchildren[val]->pid, val, hchildren[val], nchildren, nzombies);
+
+ thiszombie = nzombies;
+ zombies[nzombies] = pchildren[val]; // Add to zombie array
+ zombies[nzombies++]->process_state = PID_ZOMBIE;// Walking dead
+
+ sigproc_printf ("zombifying [%d], pid %d, handle %p, nchildren %d",
+ val, pchildren[val]->pid, hchildren[val], nchildren);
+ if ((int) val < --nchildren)
+ {
+ hchildren[val] = hchildren[nchildren];
+ pchildren[val] = pchildren[nchildren];
+ }
+
+ /* See if we should care about the this terminated process. If we've
+ filled up our table or if we're ignoring SIGCHLD, then we immediately
+ remove the process and move on. Otherwise, this process becomes a zombie
+ which must be reaped by a wait() call. FIXME: This is a very inelegant
+ way to deal with this and could lead to process hangs. */
+ if (nzombies >= NZOMBIES)
+ {
+ sigproc_printf ("zombie table overflow %d", thiszombie);
+ remove_zombie (thiszombie);
+ }
+
+ /* Don't scan the wait queue yet. Caller will send SIGCHLD to this process.
+ This will cause an eventual scan of waiters. */
+ break;
+
+ /* Handle a wait4() operation. Allocates an event for the calling
+ * thread which is signaled when the appropriate pid exits or stops.
+ * (usually called from the main thread)
+ */
+ case PROC_WAIT:
+ wval->ev = NULL; // Don't know event flag yet
+
+ if (wval->pid <= 0)
+ child = NULL; // Not looking for a specific pid
+ else if (!mychild (wval->pid))
+ goto out; // invalid pid. flag no such child
+
+ wval->status = 0; // Don't know status yet
+ sigproc_printf ("wval->pid %d, wval->options %d", wval->pid, wval->options);
+
+ /* If the first time for this thread, create a new event, otherwise
+ * reset the event.
+ */
+ if ((wval->ev = wval->thread_ev) == NULL)
+ {
+ wval->ev = wval->thread_ev = CreateEvent (&sec_none_nih, TRUE,
+ FALSE, NULL);
+ ProtectHandle (wval->ev);
+ }
+
+ ResetEvent (wval->ev);
+ w = waitq_head.next;
+ waitq_head.next = wval; /* Add at the beginning. */
+ wval->next = w; /* Link in rest of the list. */
+ clearing = 0;
+ goto scan_wait;
+
+ /* Clear all waiting threads. Called from exceptions.cc prior to
+ the main thread's dispatch to a signal handler function.
+ (called from wait_sig thread) */
+ case PROC_CLEARWAIT:
+ /* Clear all "wait"ing threads. */
+ if (val)
+ sigproc_printf ("clear waiting threads");
+ else
+ sigproc_printf ("looking for processes to reap");
+ clearing = val;
+
+ scan_wait:
+ /* Scan the linked list of wait()ing threads. If a wait's parameters
+ * match this pid, then activate it.
+ */
+ for (w = &waitq_head; w->next != NULL; w = w->next)
+ {
+ if ((potential_match = checkstate (w)) > 0)
+ sigproc_printf ("released waiting thread");
+ else if (!clearing && !(w->next->options & WNOHANG) && potential_match < 0)
+ sigproc_printf ("only found non-terminated children");
+ else if (potential_match <= 0) // nothing matched
+ {
+ sigproc_printf ("waiting thread found no children");
+ HANDLE oldw = w->next->ev;
+ w->next->pid = 0;
+ if (clearing)
+ w->next->status = -1; /* flag that a signal was received */
+ else if (!potential_match || !(w->next->options & WNOHANG))
+ w->next->ev = NULL;
+ if (!SetEvent (oldw))
+ system_printf ("couldn't wake up wait event %p, %E", oldw);
+ w->next = w->next->next;
+ }
+ if (w->next == NULL)
+ break;
+ }
+
+ if (!clearing)
+ sigproc_printf ("finished processing terminated/stopped child");
+ else
+ {
+ waitq_head.next = NULL;
+ sigproc_printf ("finished clearing");
+ }
+
+ if (global_sigs[SIGCHLD].sa_handler == (void *) SIG_IGN)
+ while (nzombies)
+ remove_zombie (0);
+ break;
+ }
+
+out:
+ sync_proc_subproc->release (); // Release the lock
+out1:
+ sigproc_printf ("returning %d", rc);
+ return rc;
+}
+
+/* Terminate the wait_subproc thread.
+ * Called on process exit.
+ * Also called by spawn_guts to disassociate any subprocesses from this
+ * process. Subprocesses will then know to clean up after themselves and
+ * will not become zombies.
+ */
+void __stdcall
+proc_terminate (void)
+{
+ sigproc_printf ("nchildren %d, nzombies %d", nchildren, nzombies);
+ /* Signal processing is assumed to be blocked in this routine. */
+ if (hwait_subproc)
+ {
+ proc_loop_wait = 0; // Tell wait_subproc thread to exit
+ sync_proc_subproc->acquire (WPSP);
+ wake_wait_subproc (); // Wake wait_subproc loop
+ hwait_subproc = NULL;
+
+ (void) proc_subproc (PROC_CLEARWAIT, 1);
+
+ /* Clean out zombie processes from the pid list. */
+ int i;
+ for (i = 0; i < nzombies; i++)
+ {
+ if (zombies[i]->hProcess)
+ {
+ ForceCloseHandle1 (zombies[i]->hProcess, childhProc);
+ ForceCloseHandle1 (zombies[i]->pid_handle, pid_handle);
+ }
+ zombies[i]->ppid = 1;
+ zombies[i]->process_state = PID_EXITED; /* CGF FIXME - still needed? */
+ zombies[i].release (); // FIXME: this breaks older gccs for some reason
+ }
+
+ /* Disassociate my subprocesses */
+ for (i = 0; i < nchildren; i++)
+ {
+ if (!pchildren[i]->hProcess)
+ sigproc_printf ("%d(%d) hProcess cleared already?", pchildren[i]->pid,
+ pchildren[i]->dwProcessId);
+ else
+ {
+ ForceCloseHandle1 (pchildren[i]->hProcess, childhProc);
+ sigproc_printf ("%d(%d) closed child handle", pchildren[i]->pid,
+ pchildren[i]->dwProcessId);
+ pchildren[i]->ppid = 1;
+ if (pchildren[i]->pgid == myself->pid)
+ pchildren[i]->process_state |= PID_ORPHANED;
+ }
+ pchildren[i].release ();
+ }
+ nchildren = nzombies = 0;
+ sync_proc_subproc = NULL;
+ }
+ sigproc_printf ("leaving");
+}
+
+/* Clear pending signal */
+void __stdcall
+sig_clear (int target_sig)
+{
+ if (GetCurrentThreadId () != sigtid)
+ sig_send (myself, -target_sig);
+ else
+ {
+ sigqueue.reset ();
+ sigelem *q;
+ while ((q = sigqueue.next ()))
+ if (q->sig == target_sig)
+ {
+ sigqueue.del ();
+ break;
+ }
+ }
+ return;
+}
+
+extern "C" int
+sigpending (sigset_t *mask)
+{
+ sigset_t outset = (sigset_t) sig_send (myself, __SIGPENDING);
+ if (outset == SIG_BAD_MASK)
+ return -1;
+ *mask = outset;
+ return 0;
+}
+
+/* Force the wait_sig thread to wake up and scan for pending signals */
+int __stdcall
+sig_dispatch_pending ()
+{
+ if (exit_state || GetCurrentThreadId () == sigtid || !sigqueue.start.next)
+ {
+#ifdef DEBUGGING
+ sigproc_printf ("exit_state %d, GetCurrentThreadId () %p, sigtid %p, sigqueue.start.next %p",
+ exit_state, GetCurrentThreadId (), sigtid, sigqueue.start.next);
+#endif
+ return 0;
+ }
+
+#ifdef DEBUGGING
+ sigproc_printf ("flushing");
+#endif
+ (void) sig_send (myself, __SIGFLUSH);
+ return call_signal_handler_now ();
+}
+
+/* Message initialization. Called from dll_crt0_1
+ *
+ * This routine starts the signal handling thread. The wait_sig_inited
+ * event is used to signal that the thread is ready to handle signals.
+ * We don't wait for this during initialization but instead detect it
+ * in sig_send to gain a little concurrency.
+ */
+void __stdcall
+sigproc_init ()
+{
+ wait_sig_inited = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
+ ProtectHandle (wait_sig_inited);
+
+ /* sync_proc_subproc is used by proc_subproc. It serialises
+ * access to the children and zombie arrays.
+ */
+ new_muto (sync_proc_subproc);
+
+ /* local event signaled when main thread has been dispatched
+ to a signal handler function. */
+ signal_arrived = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
+ ProtectHandle (signal_arrived);
+
+ hwait_sig = new cygthread (wait_sig, cygself, "sig");
+ hwait_sig->zap_h ();
+
+ /* Initialize waitq structure for main thread. A waitq structure is
+ * allocated for each thread that executes a wait to allow multiple threads
+ * to perform waits. Pre-allocate a waitq structure for the main thread.
+ */
+ waitq *w;
+ if ((w = (waitq *)waitq_storage.get ()) == NULL)
+ {
+ w = &waitq_main;
+ waitq_storage.set (w);
+ }
+ memset (w, 0, sizeof *w); // Just to be safe
+
+ global_sigs[SIGSTOP].sa_flags = SA_RESTART | SA_NODEFER;
+ sigproc_printf ("process/signal handling enabled(%x)", myself->process_state);
+ return;
+}
+
+/* Called on process termination to terminate signal and process threads.
+ */
+void __stdcall
+sigproc_terminate (void)
+{
+ extern HANDLE hExeced;
+ hwait_sig = NULL;
+
+ if (myself->sendsig == INVALID_HANDLE_VALUE)
+ sigproc_printf ("sigproc handling not active");
+ else
+ {
+ sigproc_printf ("entering");
+ // finished with anything it is doing
+ ForceCloseHandle (sigcomplete_main);
+ if (!hExeced)
+ {
+ HANDLE sendsig = myself->sendsig;
+ myself->sendsig = INVALID_HANDLE_VALUE;
+ CloseHandle (sendsig);
+ }
+ }
+ proc_terminate (); // Terminate process handling thread
+
+ return;
+}
+
+/* Send a signal to another process by raising its signal semaphore.
+ * If pinfo *p == NULL, send to the current process.
+ * If sending to this process, wait for notification that a signal has
+ * completed before returning.
+ */
+int __stdcall
+sig_send (_pinfo *p, int sig, void *tls)
+{
+ int rc = 1;
+ bool its_me;
+ HANDLE sendsig;
+ sigpacket pack;
+
+ bool wait_for_completion;
+ // FIXMENOW: Avoid using main thread's completion event!
+ if (!(its_me = (p == NULL || p == myself || p == myself_nowait)))
+ wait_for_completion = false;
+ else
+ {
+ if (no_signals_available ())
+ {
+ sigproc_printf ("hwait_sig %p, myself->sendsig %p, exit_state %d",
+ hwait_sig, myself->sendsig, exit_state);
+ goto out; // Either exiting or not yet initializing
+ }
+ if (wait_sig_inited)
+ wait_for_sigthread ();
+ wait_for_completion = p != myself_nowait && _my_tls.isinitialized ();
+ p = myself;
+ }
+
+ /* It is possible that the process is not yet ready to receive messages
+ * or that it has exited. Detect this.
+ */
+ if (!proc_can_be_signalled (p)) /* Is the process accepting messages? */
+ {
+ sigproc_printf ("invalid pid %d(%x), signal %d",
+ p->pid, p->process_state, sig);
+ goto out;
+ }
+
+ if (its_me)
+ {
+ sendsig = myself->sendsig;
+ if (wait_for_completion)
+ pack.wakeup = sigcomplete_main;
+ }
+ else
+ {
+ HANDLE hp = OpenProcess (PROCESS_DUP_HANDLE, false, p->dwProcessId);
+ if (!hp)
+ {
+ sigproc_printf ("OpenProcess failed, %E");
+ __seterrno ();
+ goto out;
+ }
+ for (int i = 0; !p->sendsig && i < 10000; i++)
+ low_priority_sleep (0);
+ if (!DuplicateHandle (hp, p->sendsig, hMainProc, &sendsig, false, 0,
+ DUPLICATE_SAME_ACCESS) || !sendsig)
+ {
+ sigproc_printf ("DuplicateHandle failed, %E");
+ __seterrno ();
+ goto out;
+ }
+ CloseHandle (hp);
+ pack.wakeup = NULL;
+ }
+
+ sigproc_printf ("sendsig %p, pid %d, signal %d, its_me %d", sendsig, p->pid,
+ sig, its_me);
+
+ sigset_t pending;
+ if (!its_me)
+ pack.mask = NULL;
+ else if (sig == __SIGPENDING)
+ pack.mask = &pending;
+ else if (sig == __SIGFLUSH || sig > 0)
+ pack.mask = &myself->getsigmask ();
+ else
+ pack.mask = NULL;
+
+ pack.sig = sig;
+ pack.pid = myself->pid;
+ pack.tls = (_threadinfo *) tls;
+ DWORD nb;
+ if (!WriteFile (sendsig, &pack, sizeof (pack), &nb, NULL) || nb != sizeof (pack))
+ {
+ /* Couldn't send to the pipe. This probably means that the
+ process is exiting. */
+ if (!its_me)
+ {
+ sigproc_printf ("WriteFile for pipe %p failed, %E", sendsig);
+ __seterrno ();
+ ForceCloseHandle (sendsig);
+ }
+ else
+ {
+ if (no_signals_available ())
+ sigproc_printf ("I'm going away now");
+ else
+ system_printf ("error sending signal %d to pid %d, pipe handle %p, %E",
+ sig, p->pid, sendsig);
+ }
+ goto out;
+ }
+
+
+ /* No need to wait for signal completion unless this was a signal to
+ this process.
+
+ If it was a signal to this process, wait for a dispatched signal.
+ Otherwise just wait for the wait_sig to signal that it has finished
+ processing the signal. */
+ if (wait_for_completion)
+ {
+ sigproc_printf ("Waiting for pack.wakeup %p", pack.wakeup);
+ rc = WaitForSingleObject (pack.wakeup, WSSC);
+ }
+ else
+ {
+ rc = WAIT_OBJECT_0;
+ sigproc_printf ("Not waiting for sigcomplete. its_me %d signal %d", its_me, sig);
+ if (!its_me)
+ ForceCloseHandle (sendsig);
+ }
+
+ if (rc == WAIT_OBJECT_0)
+ rc = 0; // Successful exit
+ else
+ {
+ if (!no_signals_available ())
+ system_printf ("wait for sig_complete event failed, signal %d, rc %d, %E",
+ sig, rc);
+ set_errno (ENOSYS);
+ rc = -1;
+ }
+
+ if (wait_for_completion)
+ call_signal_handler_now ();
+
+out:
+ if (sig != __SIGPENDING)
+ /* nothing */;
+ else if (!rc)
+ rc = (int) pending;
+ else
+ rc = SIG_BAD_MASK;
+ sigproc_printf ("returning %p from sending signal %d", rc, sig);
+ return rc;
+}
+
+/* Initialize the wait_subproc thread.
+ * Called from fork() or spawn() to initialize the handling of subprocesses.
+ */
+void __stdcall
+subproc_init (void)
+{
+ if (hwait_subproc)
+ return;
+
+ /* A "wakeup" handle which can be toggled to make wait_subproc reexamine
+ * the hchildren array.
+ */
+ events[0] = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL);
+ hwait_subproc = new cygthread (wait_subproc, NULL, "proc");
+ hwait_subproc->zap_h ();
+ ProtectHandle (events[0]);
+ sigproc_printf ("started wait_subproc thread");
+}
+
+/* Initialize some of the memory block passed to child processes
+ by fork/spawn/exec. */
+
+void __stdcall
+init_child_info (DWORD chtype, child_info *ch, pid_t pid, HANDLE subproc_ready)
+{
+ memset (ch, 0, sizeof *ch);
+ ch->cb = chtype == PROC_FORK ? sizeof (child_info_fork) : sizeof (child_info);
+ ch->intro = PROC_MAGIC_GENERIC;
+ ch->magic = CHILD_INFO_MAGIC;
+ ch->type = chtype;
+ ch->cygpid = pid;
+ ch->subproc_ready = subproc_ready;
+ ch->pppid_handle = myself->ppid_handle;
+ ch->fhandler_union_cb = sizeof (fhandler_union);
+ ch->user_h = cygwin_user_h;
+}
+
+/* Check the state of all of our children to see if any are stopped or
+ * terminated.
+ */
+static int __stdcall
+checkstate (waitq *parent_w)
+{
+ int potential_match = 0;
+
+ sigproc_printf ("nchildren %d, nzombies %d", nchildren, nzombies);
+
+ /* Check already dead processes first to see if they match the criteria
+ * given in w->next.
+ */
+ for (int i = 0; i < nzombies; i++)
+ switch (stopped_or_terminated (parent_w, zombies[i]))
+ {
+ case -1:
+ potential_match = -1;
+ break;
+ case 1:
+ remove_zombie (i);
+ potential_match = 1;
+ goto out;
+ }
+
+ sigproc_printf ("checking alive children");
+
+ /* No dead terminated children matched. Check for stopped children. */
+ for (int i = 0; i < nchildren; i++)
+ switch (stopped_or_terminated (parent_w, pchildren[i]))
+ {
+ case -1:
+ potential_match = -1;
+ break;
+ case 1:
+ potential_match = 1;
+ goto out;
+ }
+
+out:
+ sigproc_printf ("returning %d", potential_match);
+ return potential_match;
+}
+
+/* Remove a zombie from zombies by swapping it with the last child in the list.
+ */
+static void __stdcall
+remove_zombie (int ci)
+{
+ sigproc_printf ("removing %d, pid %d, nzombies %d", ci, zombies[ci]->pid,
+ nzombies);
+
+ if (zombies[ci])
+ {
+ ForceCloseHandle1 (zombies[ci]->hProcess, childhProc);
+ ForceCloseHandle1 (zombies[ci]->pid_handle, pid_handle);
+ zombies[ci].release ();
+ }
+
+ if (ci < --nzombies)
+ zombies[ci] = zombies[nzombies];
+
+ return;
+}
+
+/* Check status of child process vs. waitq member.
+ *
+ * parent_w is the pointer to the parent of the waitq member in question.
+ * child is the subprocess being considered.
+ *
+ * Returns
+ * 1 if stopped or terminated child matches parent_w->next criteria
+ * -1 if a non-stopped/terminated child matches parent_w->next criteria
+ * 0 if child does not match parent_w->next criteria
+ */
+static int __stdcall
+stopped_or_terminated (waitq *parent_w, _pinfo *child)
+{
+ int potential_match;
+ waitq *w = parent_w->next;
+
+ sigproc_printf ("considering pid %d", child->pid);
+ if (w->pid == -1)
+ potential_match = 1;
+ else if (w->pid == 0)
+ potential_match = child->pgid == myself->pgid;
+ else if (w->pid < 0)
+ potential_match = child->pgid == -w->pid;
+ else
+ potential_match = (w->pid == child->pid);
+
+ if (!potential_match)
+ return 0;
+
+ bool terminated;
+
+ if ((terminated = child->process_state == PID_ZOMBIE) ||
+ ((w->options & WUNTRACED) && child->stopsig))
+ {
+ parent_w->next = w->next; /* successful wait. remove from wait queue */
+ w->pid = child->pid;
+
+ if (!terminated)
+ {
+ sigproc_printf ("stopped child");
+ w->status = (child->stopsig << 8) | 0x7f;
+ child->stopsig = 0;
+ }
+ else /* Should only get here when child has been moved to the zombies array */
+ {
+ DWORD status;
+ if (!GetExitCodeProcess (child->hProcess, &status))
+ status = 0xffff;
+ if (status & EXIT_SIGNAL)
+ w->status = (status >> 8) & 0xff; /* exited due to signal */
+ else
+ w->status = (status & 0xff) << 8; /* exited via "exit ()" */
+
+ add_rusage (&myself->rusage_children, &child->rusage_children);
+ add_rusage (&myself->rusage_children, &child->rusage_self);
+
+ if (w->rusage)
+ {
+ add_rusage ((struct rusage *) w->rusage, &child->rusage_children);
+ add_rusage ((struct rusage *) w->rusage, &child->rusage_self);
+ }
+ }
+
+ if (!SetEvent (w->ev)) /* wake up wait4 () immediately */
+ system_printf ("couldn't wake up wait event %p, %E", w->ev);
+ return 1;
+ }
+
+ return -potential_match;
+}
+
+static void
+talktome ()
+{
+ winpids pids ((DWORD) PID_MAP_RW);
+ for (unsigned i = 0; i < pids.npids; i++)
+ if (pids[i]->hello_pid == myself->pid)
+ if (!IsBadWritePtr (pids[i], sizeof (_pinfo)))
+ pids[i]->commune_recv ();
+}
+
+/* Process signals by waiting for a semaphore to become signaled.
+ Then scan an in-memory array representing queued signals.
+ Executes in a separate thread.
+
+ Signals sent from this process are sent a completion signal so
+ that returns from kill/raise do not occur until the signal has
+ has been handled, as per POSIX. */
+
+void
+pending_signals::add (int sig, int pid, _threadinfo *tls)
+{
+ sigelem *se;
+ for (se = start.next; se; se = se->next)
+ if (se->sig == sig)
+ return;
+ while (sigs[empty].sig)
+ if (++empty == NSIG)
+ empty = 0;
+ se = sigs + empty;
+ se->sig = sig;
+ se->next = NULL;
+ se->tls = tls;
+ se->pid = pid;
+ if (end)
+ end->next = se;
+ end = se;
+ if (!start.next)
+ start.next = se;
+ empty++;
+}
+
+void
+pending_signals::del ()
+{
+ sigelem *next = curr->next;
+ prev->next = next;
+ curr->sig = 0;
+#ifdef DEBUGGING
+ curr->next = NULL;
+#endif
+ if (end == curr)
+ end = prev;
+ empty = curr - sigs;
+ curr = next;
+}
+
+sigelem *
+pending_signals::next ()
+{
+ sigelem *res;
+ prev = curr;
+ if (!curr || !(curr = curr->next))
+ res = NULL;
+ else
+ res = curr;
+ return res;
+}
+
+/* Process signals by waiting for signal data to arrive in a pipe.
+ Set a completion event if one was specified. */
+static DWORD WINAPI
+wait_sig (VOID *self)
+{
+ HANDLE readsig;
+ char sa_buf[1024];
+
+ /* Initialization */
+ (void) SetThreadPriority (GetCurrentThread (), WAIT_SIG_PRIORITY);
+
+ /* sigcomplete_main - event used to signal main thread on signal
+ completion */
+ if (!CreatePipe (&readsig, &myself->sendsig, sec_user_nih (sa_buf), 0))
+ api_fatal ("couldn't create signal pipe, %E");
+ sigcomplete_main = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL);
+ sigproc_printf ("sigcomplete_main %p", sigcomplete_main);
+ sigCONT = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL);
+
+ /* Setting dwProcessId flags that this process is now capable of receiving
+ signals. Prior to this, dwProcessId was set to the windows pid of
+ of the original windows process which spawned us unless this was a
+ "toplevel" process. */
+ myself->dwProcessId = GetCurrentProcessId ();
+ myself->process_state |= PID_ACTIVE;
+ myself->process_state &= ~PID_INITIALIZING;
+
+ ProtectHandle (sigcomplete_main);
+
+ /* If we've been execed, then there is still a stub left in the previous
+ windows process waiting to see if it's started a cygwin process or not.
+ Signalling subproc_ready indicates that we are a cygwin process. */
+ if (child_proc_info && child_proc_info->type == PROC_EXEC)
+ {
+ debug_printf ("subproc_ready %p", child_proc_info->subproc_ready);
+ if (!SetEvent (child_proc_info->subproc_ready))
+ system_printf ("SetEvent (subproc_ready) failed, %E");
+ ForceCloseHandle1 (child_proc_info->subproc_ready, subproc_ready);
+ /* Initialize an "indirect" pid block so that if someone looks up this
+ process via its Windows PID it will be redirected to the appropriate
+ Cygwin PID shared memory block. */
+ static pinfo NO_COPY myself_identity;
+ myself_identity.init (cygwin_pid (myself->dwProcessId), PID_EXECED);
+ }
+
+ SetEvent (wait_sig_inited);
+ sigtid = GetCurrentThreadId ();
+
+ exception_list el;
+ _my_tls.init_threadlist_exceptions (&el);
+ debug_printf ("entering ReadFile loop, readsig %p, myself->sendsig %p",
+ readsig, myself->sendsig);
+
+ for (;;)
+ {
+ DWORD nb;
+ sigpacket pack;
+ if (!ReadFile (readsig, &pack, sizeof (pack), &nb, NULL))
+ break;
+ if (myself->sendsig == INVALID_HANDLE_VALUE)
+ break;
+
+ if (nb != sizeof (pack))
+ {
+ system_printf ("short read from signal pipe: %d != %d", nb,
+ sizeof (pack));
+ continue;
+ }
+
+ if (!pack.sig)
+ {
+#ifdef DEBUGGING
+ system_printf ("zero signal?");
+#endif
+ continue;
+ }
+
+ sigset_t dummy_mask;
+ if (!pack.mask)
+ {
+ dummy_mask = myself->getsigmask ();
+ pack.mask = &dummy_mask;
+ }
+
+ sigelem *q;
+ switch (pack.sig)
+ {
+ case __SIGCOMMUNE:
+ talktome ();
+ break;
+ case __SIGSTRACE:
+ strace.hello ();
+ break;
+ case __SIGPENDING:
+ *pack.mask = 0;
+ unsigned bit;
+ sigqueue.reset ();
+ while ((q = sigqueue.next ()))
+ if (myself->getsigmask () & (bit = SIGTOMASK (q->sig)))
+ *pack.mask |= bit;
+ break;
+ case __SIGFLUSH:
+ sigqueue.reset ();
+ while ((q = sigqueue.next ()))
+ if (sig_handle (q->sig, *pack.mask, q->pid, q->tls) > 0)
+ sigqueue.del ();
+ break;
+ default:
+ if (pack.sig < 0)
+ sig_clear (-pack.sig);
+ else
+ {
+ int sigres = sig_handle (pack.sig, *pack.mask, pack.pid, pack.tls);
+ if (sigres <= 0)
+ {
+#ifdef DEBUGGING2
+ if (!sigres)
+ system_printf ("Failed to arm signal %d from pid %d", pack.sig, pack.pid);
+#endif
+ sigqueue.add (pack.sig, pack.pid, pack.tls);// FIXME: Shouldn't add this in !sh condition
+ }
+ if (pack.sig == SIGCHLD)
+ proc_subproc (PROC_CLEARWAIT, 0);
+ }
+ break;
+ }
+ if (pack.wakeup)
+ SetEvent (pack.wakeup);
+ }
+
+ sigproc_printf ("done");
+ ExitThread (0);
+}
+
+/* Wait for subprocesses to terminate. Executes in a separate thread. */
+static DWORD WINAPI
+wait_subproc (VOID *)
+{
+ sigproc_printf ("starting");
+ int errloop = 0;
+
+ for (;;)
+ {
+ DWORD rc = WaitForMultipleObjects (nchildren + 1, events, FALSE,
+ proc_loop_wait);
+ if (rc == WAIT_TIMEOUT)
+ if (!proc_loop_wait)
+ break; // Exiting
+ else
+ continue;
+
+ if (rc == WAIT_FAILED)
+ {
+ if (!proc_loop_wait)
+ break;
+
+ /* It's ok to get an ERROR_INVALID_HANDLE since another thread may have
+ closed a handle in the children[] array. So, we try looping a couple
+ of times to stabilize. FIXME - this is not foolproof. Probably, this
+ thread should be responsible for closing the children. */
+ if (!errloop++)
+ proc_subproc (PROC_NOTHING, 0); // Just synchronize and continue
+ if (errloop < 10)
+ continue;
+
+ system_printf ("wait failed. nchildren %d, wait %d, %E",
+ nchildren, proc_loop_wait);
+
+ for (int i = 0; i <= nchildren; i++)
+ if ((rc = WaitForSingleObject (events[i], 0)) == WAIT_OBJECT_0 ||
+ rc == WAIT_TIMEOUT)
+ continue;
+ else if (i == 0)
+ system_printf ("nchildren %d, event[%d] %p, %E", nchildren, i, events[i]);
+ else
+ {
+ system_printf ("nchildren %d, event[%d] %p, pchildren[%d] %p, events[0] %p, %E",
+ nchildren, i, events[i], i - 1, (_pinfo *) pchildren[i - 1], events[0]);
+ system_printf ("pid %d, dwProcessId %u, hProcess %p, progname '%s'",
+ pchildren[i - 1]->pid, pchildren[i - 1]->dwProcessId,
+ pchildren[i - 1]->hProcess, pchildren[i - 1]->progname);
+ }
+ break;
+ }
+
+ errloop = 0;
+ rc -= WAIT_OBJECT_0;
+ if (rc-- != 0)
+ {
+ rc = proc_subproc (PROC_CHILDTERMINATED, rc);
+ if (!proc_loop_wait) // Don't bother if wait_subproc is
+ break; // exiting
+
+ /* Send a SIGCHLD to myself. We do this here, rather than in proc_subproc
+ to avoid the proc_subproc lock since the signal thread will eventually
+ be calling proc_subproc and could unnecessarily block. */
+ if (rc)
+ sig_send (myself_nowait, SIGCHLD);
+ }
+ sigproc_printf ("looping");
+ }
+
+ ForceCloseHandle (events[0]);
+ events[0] = NULL;
+ sigproc_printf ("done");
+ ExitThread (0);
+}
diff --git a/winsup/cygwin/wincap.h b/winsup/cygwin/wincap.h
new file mode 100644
index 00000000000..66ab87e2759
--- /dev/null
+++ b/winsup/cygwin/wincap.h
@@ -0,0 +1,121 @@
+/* wincap.h: Header for OS capability class.
+
+ Copyright 2001, 2002 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#ifndef _WINCAP_H
+#define _WINCAP_H
+
+struct wincaps
+{
+ DWORD lock_file_highword;
+ DWORD chunksize;
+ int shared;
+ unsigned is_winnt : 1;
+ unsigned is_server : 1;
+ unsigned access_denied_on_delete : 1;
+ unsigned has_delete_on_close : 1;
+ unsigned has_page_guard : 1;
+ unsigned has_security : 1;
+ unsigned has_security_descriptor_control : 1;
+ unsigned has_get_process_times : 1;
+ unsigned has_lseek_bug : 1;
+ unsigned has_lock_file_ex : 1;
+ unsigned has_signal_object_and_wait : 1;
+ unsigned has_eventlog : 1;
+ unsigned has_ip_helper_lib : 1;
+ unsigned has_set_handle_information : 1;
+ unsigned has_set_handle_information_on_console_handles: 1;
+ unsigned supports_smp : 1;
+ unsigned map_view_of_file_ex_sucks : 1;
+ unsigned altgr_is_ctrl_alt : 1;
+ unsigned has_physical_mem_access : 1;
+ unsigned has_working_copy_on_write : 1;
+ unsigned share_mmaps_only_by_name : 1;
+ unsigned virtual_protect_works_on_shared_pages : 1;
+ unsigned has_hard_links : 1;
+ unsigned can_open_directories : 1;
+ unsigned has_move_file_ex : 1;
+ unsigned has_negative_pids : 1;
+ unsigned has_unreliable_pipes : 1;
+ unsigned has_try_enter_critical_section : 1;
+ unsigned has_raw_devices : 1;
+ unsigned has_valid_processorlevel : 1;
+ unsigned has_64bit_file_access : 1;
+ unsigned has_process_io_counters : 1;
+ unsigned supports_reading_modem_output_lines : 1;
+ unsigned needs_memory_protection : 1;
+ unsigned pty_needs_alloc_console : 1;
+ unsigned has_terminal_services : 1;
+ unsigned has_switch_to_thread : 1;
+ unsigned cant_debug_dll_entry : 1;
+};
+
+class wincapc
+{
+ OSVERSIONINFOEX version;
+ char osnam[40];
+ void *caps;
+
+public:
+ void init ();
+
+ void set_chunksize (DWORD nchunksize);
+
+ const char *osname () const { return osnam; }
+
+#define IMPLEMENT(cap) cap() const { return ((wincaps *) this->caps)->cap; }
+
+ DWORD IMPLEMENT (lock_file_highword)
+ DWORD IMPLEMENT (chunksize)
+ int IMPLEMENT (shared)
+ bool IMPLEMENT (is_winnt)
+ bool IMPLEMENT (is_server)
+ bool IMPLEMENT (access_denied_on_delete)
+ bool IMPLEMENT (has_delete_on_close)
+ bool IMPLEMENT (has_page_guard)
+ bool IMPLEMENT (has_security)
+ bool IMPLEMENT (has_security_descriptor_control)
+ bool IMPLEMENT (has_get_process_times)
+ bool IMPLEMENT (has_lseek_bug)
+ bool IMPLEMENT (has_lock_file_ex)
+ bool IMPLEMENT (has_signal_object_and_wait)
+ bool IMPLEMENT (has_eventlog)
+ bool IMPLEMENT (has_ip_helper_lib)
+ bool IMPLEMENT (has_set_handle_information)
+ bool IMPLEMENT (has_set_handle_information_on_console_handles)
+ bool IMPLEMENT (supports_smp)
+ bool IMPLEMENT (map_view_of_file_ex_sucks)
+ bool IMPLEMENT (altgr_is_ctrl_alt)
+ bool IMPLEMENT (has_physical_mem_access)
+ bool IMPLEMENT (has_working_copy_on_write)
+ bool IMPLEMENT (share_mmaps_only_by_name)
+ bool IMPLEMENT (virtual_protect_works_on_shared_pages)
+ bool IMPLEMENT (has_hard_links)
+ bool IMPLEMENT (can_open_directories)
+ bool IMPLEMENT (has_move_file_ex)
+ bool IMPLEMENT (has_negative_pids)
+ bool IMPLEMENT (has_unreliable_pipes)
+ bool IMPLEMENT (has_try_enter_critical_section)
+ bool IMPLEMENT (has_raw_devices)
+ bool IMPLEMENT (has_valid_processorlevel)
+ bool IMPLEMENT (has_64bit_file_access)
+ bool IMPLEMENT (has_process_io_counters)
+ bool IMPLEMENT (supports_reading_modem_output_lines)
+ bool IMPLEMENT (needs_memory_protection)
+ bool IMPLEMENT (pty_needs_alloc_console)
+ bool IMPLEMENT (has_terminal_services)
+ bool IMPLEMENT (has_switch_to_thread)
+ bool IMPLEMENT (cant_debug_dll_entry)
+
+#undef IMPLEMENT
+};
+
+extern wincapc wincap;
+
+#endif /* _WINCAP_H */