diff options
author | Christopher Faylor <cgf@redhat.com> | 2003-07-06 05:10:42 +0000 |
---|---|---|
committer | Christopher Faylor <cgf@redhat.com> | 2003-07-06 05:10:42 +0000 |
commit | 61845845988c077545effa69e36fefe40c2f5a18 (patch) | |
tree | d728c7cf589c5dad057c817f6f945b0106617867 /winsup | |
parent | 09edab1c1dcc6c47daef3d4ac3f277116cf88912 (diff) | |
download | gdb-61845845988c077545effa69e36fefe40c2f5a18.tar.gz |
merge from trunk
Diffstat (limited to 'winsup')
92 files changed, 4033 insertions, 496 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index a4182314605..352df7b9dd6 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,18 +1,32 @@ +2003-07-04 Corinna Vinschen <corinna@vinschen.de> + + * mmap.cc (fhandler_disk_file::mmap): Fix address test. + +2003-07-03 Christopher Faylor <cgf@redhat.com> + + * path.cc (fillout_mntent): Change "posix" to "managed". + 2003-07-02 Christopher Faylor <cgf@redhat.com> * fhandler.h (FH_ENC): New enum. (fhandler_base::get_encoded): New function. (fhandler_base::set_encoded): Ditto. - * fhandler_disk_file.cc (fhandler_disk_file::readdir): Unmunge filename - as appropriate based on new encoding flag. - * path.cc (normalize_posix_path): Change drive check short-circuit. + * fhandler_disk_file.cc (fhandler_disk_file::opendir): Set encoded flag + in fhandler, as appropriate. + (fhandler_disk_file::readdir): Unmunge filename as appropriate based on + new encoding flag. + * path.cc (normalize_posix_path): Don't punt on files with colons. (special_char): New function. (mount_item::fnmunge): Ditto. (fnunmunge): Ditto. (special_name): Ditto. + (mount_item::build_win32): Avoid drive considerations when file is + encoded. (mount_info::conv_to_win32_path): Handle encoded filenames. + (mount_info::conv_to_posix_path): Ditto. (fillout_mntent): Add posix string when directory is encoded. * path.h (fnunmunge): Declare. + (path_conv::is_encoded): Declare. 2003-07-03 Christopher Faylor <cgf@redhat.com> @@ -386,7 +400,7 @@ 2003-05-27 Bill C. Riemers <cygwin@docbill.net> * fhandler_disk_file.cc (fhandler_disk_file::fstat_helper): Filter - permissions throug umask on FAT or if ntsec is off. + permissions through umask on FAT or if ntsec is off. 2003-05-26 Pierre Humblet <pierre.humblet@ieee.org> diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in index b892b37c7c2..53422ac9bcd 100644 --- a/winsup/cygwin/Makefile.in +++ b/winsup/cygwin/Makefile.in @@ -146,9 +146,7 @@ DLL_IMPORTS:=$(w32api_lib)/libkernel32.a MT_SAFE_OBJECTS:= # Please maintain this list in sorted order, with maximum files per 80 col line -DLL_OFILES:=assert.o autoload.o cxx.o cygheap.o cygserver_client.o \ - cygserver_transport.o cygserver_transport_pipes.o \ - cygserver_transport_sockets.o cygthread.o dcrt0.o debug.o \ +DLL_OFILES:=assert.o autoload.o cxx.o cygheap.o cygthread.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 \ @@ -252,7 +250,7 @@ install_host=@install_host@ all: all_target $(all_host) -all_target: $(TARGET_LIBS) cygserver.exe +all_target: $(TARGET_LIBS) all_host: $(TEST_LIB_NAME) @@ -264,7 +262,7 @@ install: install-libs install-headers install-man install_target \ uninstall: uninstall-libs uninstall-headers uninstall-man install-libs: $(TARGET_LIBS) - $(INSTALL_DATA) $(TEST_DLL_NAME) $(bindir)/$(DLL_NAME); \ + $(INSTALL_PROGRAM) $(TEST_DLL_NAME) $(bindir)/$(DLL_NAME); \ for i in $^; do \ $(INSTALL_DATA) $$i $(tooldir)/lib/`basename $$i` ; \ done @@ -293,8 +291,7 @@ install-man: $(INSTALL_DATA) $$i $(tooldir)/man/man7/`basename $$i` ; \ done -install_target: cygserver.exe - $(INSTALL_PROGRAM) cygserver.exe $(bindir)/cygserver.exe +install_target: install_host: @@ -399,32 +396,6 @@ winver_stamp: mkvers.sh include/cygwin/version.h winver.rc $(DLL_OFILES) $(COMPILE_CXX) -o version.o version.cc && \ touch $@ -cygserver_transport_outside.o: cygserver_transport.cc - $(COMPILE_CXX) -D__OUTSIDE_CYGWIN__ -o $@ $< - -cygserver_transport_pipes_outside.o: cygserver_transport_pipes.cc - $(COMPILE_CXX) -D__OUTSIDE_CYGWIN__ -o $@ $< - -cygserver_transport_sockets_outside.o: cygserver_transport_sockets.cc - $(COMPILE_CXX) -D__OUTSIDE_CYGWIN__ -o $@ $< - -cygserver_client_outside.o: cygserver_client.cc - $(COMPILE_CXX) -D__OUTSIDE_CYGWIN__ -o $@ $< - -# gperf -c --key-positions='1-126' -r -t -C -E -L 'ANSI-C' -Hdevhash -N'device::lookup' -Z devstring -7 $? |\ - -$(srcdir)/devices.cc: cygwin-gperf devices.gperf devices.h - perl $^ > $@ - -cygserver.exe: cygserver.o cygserver_shm.o cygserver_transport_outside.o cygserver_transport_pipes_outside.o cygserver_transport_sockets_outside.o cygserver_client_outside.o cygserver_process.o threaded_queue.o wincap.o version.o smallprint.o - $(CXX) -o $@ $^ -lstdc++ -#ifdef VERBOSE -# $(CXX) $(MINGW_CXXFLAGS) -o $@ ${wordlist 1,3,$^} -B$(mingw_build)/ $(MINGW_LDFLAGS) -#else -# @echo $(CXX) -o $@ ${wordlist 1,3,$^} ${filter-out -B%, $(MINGW_CXXFLAGS) $(MINGW_LDFLAGS)};\ -# $(CXX) $(MINGW_CXXFLAGS) -o $@ ${wordlist 1,3,$^} -B$(mingw_build)/ $(MINGW_LDFLAGS) -#endif - -lgcc: : diff --git a/winsup/cygwin/acconfig.h b/winsup/cygwin/acconfig.h new file mode 100644 index 00000000000..79e2651d38d --- /dev/null +++ b/winsup/cygwin/acconfig.h @@ -0,0 +1,20 @@ +/* Define if DEBUGGING support is requested. */ +#undef DEBUGGING + +/* Define if building "extra" thread-safe Cygwin DLL. */ +#undef _CYG_THREAD_FAILSAFE + +/* Define if GCC supports builtin memset. */ +#undef HAVE_BUILTIN_MEMSET + +/* Define if MALLOC_DEBUGGING support is requested. */ +#undef MALLOC_DEBUG + +/* Define if building thread-safe Cygwin DLL. */ +#undef _MT_SAFE + +/* Define if using new vfork functionality. */ +#undef NEWVFORK + +/* Define if using cygserver */ +#undef USE_CYGSERVER diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc index 71e7f9ead90..f5cc250fa0e 100644 --- a/winsup/cygwin/autoload.cc +++ b/winsup/cygwin/autoload.cc @@ -492,6 +492,7 @@ LoadDLLfuncEx (WSAEnumNetworkEvents, 12, ws2_32, 1) LoadDLLfuncEx (GetIfTable, 12, iphlpapi, 1) LoadDLLfuncEx (GetIfEntry, 4, iphlpapi, 1) LoadDLLfuncEx (GetIpAddrTable, 12, iphlpapi, 1) +LoadDLLfuncEx (GetNetworkParams, 8, iphlpapi, 1) LoadDLLfunc (CoInitialize, 4, ole32) LoadDLLfunc (CoUninitialize, 0, ole32) diff --git a/winsup/cygwin/config.h.in b/winsup/cygwin/config.h.in new file mode 100644 index 00000000000..d4f6269e0d6 --- /dev/null +++ b/winsup/cygwin/config.h.in @@ -0,0 +1,41 @@ +/* config.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define if using alloca.c. */ +#undef C_ALLOCA + +/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems. + This function is required for alloca.c support on those systems. */ +#undef CRAY_STACKSEG_END + +/* Define if you have alloca, as a function or macro. */ +#undef HAVE_ALLOCA + +/* Define if you have <alloca.h> and it should be used (not on Ultrix). */ +#undef HAVE_ALLOCA_H + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown + */ +#undef STACK_DIRECTION + +/* Define if DEBUGGING support is requested. */ +#undef DEBUGGING + +/* Define if building "extra" thread-safe Cygwin DLL. */ +#undef _CYG_THREAD_FAILSAFE + +/* Define if GCC supports builtin memset. */ +#undef HAVE_BUILTIN_MEMSET + +/* Define if MALLOC_DEBUGGING support is requested. */ +#undef MALLOC_DEBUG + +/* Define if using new vfork functionality. */ +#undef NEWVFORK + +/* Define if using cygserver */ +#undef USE_CYGSERVER diff --git a/winsup/cygwin/configure b/winsup/cygwin/configure index f5c8a7d4be6..af5f3cab0fe 100755 --- a/winsup/cygwin/configure +++ b/winsup/cygwin/configure @@ -12,12 +12,12 @@ ac_help= ac_default_prefix=/usr/local # Any additions from configure.in: ac_help="$ac_help - --enable-threadsafe=[runtime] Build a cygwin DLL which is thread safe" -ac_help="$ac_help --enable-extra-threadsafe-checking Build a cygwin DLL which is thread safe with extra consistency checking" ac_help="$ac_help --enable-debugging Build a cygwin DLL which has more consistency checking for debugging" ac_help="$ac_help + --enable-server Build a cygwin DLL which can communicate with cygserver" +ac_help="$ac_help --enable-malloc-debugging Build a cygwin DLL with heap sanity checking (this is very slow, use only if you have heap corruption problems)" ac_help="$ac_help --enable-vfork Build a cygwin DLL which uses experimental vfork code" @@ -1865,28 +1865,6 @@ ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$a cross_compiling=$ac_cv_prog_cc_cross -mt_safe_val=1 -MT_SAFE=yes - -# Check whether --enable-threadsafe or --disable-threadsafe was given. -if test "${enable_threadsafe+set}" = set; then - enableval="$enable_threadsafe" - case "${enableval}" in -yes) - ;; -runtime) - mt_safe_val=2 - MT_SAFE=yes - ;; -no) - mt_safe_val=0 - MT_SAFE=no - ;; -esac - -fi - - # Check whether --enable-extra-threadsafe-checking or --disable-extra-threadsafe-checking was given. if test "${enable_extra_threadsafe_checking+set}" = set; then enableval="$enable_extra_threadsafe_checking" @@ -1906,21 +1884,26 @@ esac fi -if test "$MT_SAFE" = "yes"; then - cat >> confdefs.h <<EOF -#define _MT_SAFE $mt_safe_val +# Check whether --enable-debugging or --disable-debugging was given. +if test "${enable_debugging+set}" = set; then + enableval="$enable_debugging" + case "${enableval}" in +yes) cat >> confdefs.h <<\EOF +#define DEBUGGING 1 EOF + ;; +no) ;; +esac fi - -# Check whether --enable-debugging or --disable-debugging was given. -if test "${enable_debugging+set}" = set; then - enableval="$enable_debugging" +# Check whether --enable-server or --disable-server was given. +if test "${enable_server+set}" = set; then + enableval="$enable_server" case "${enableval}" in yes) cat >> confdefs.h <<\EOF -#define DEBUGGING 1 +#define USE_CYGSERVER 1 EOF ;; no) ;; @@ -2146,7 +2129,6 @@ s%@WINDRES@%$WINDRES%g s%@CPP@%$CPP%g s%@ALLOCA@%$ALLOCA%g s%@SET_MAKE@%$SET_MAKE%g -s%@MT_SAFE@%$MT_SAFE%g s%@MALLOC_OFILES@%$MALLOC_OFILES%g s%@DLL_ENTRY@%$DLL_ENTRY%g s%@DEF_DLL_ENTRY@%$DEF_DLL_ENTRY%g diff --git a/winsup/cygwin/configure.in b/winsup/cygwin/configure.in index 48ffe7dbb48..c192221ab99 100644 --- a/winsup/cygwin/configure.in +++ b/winsup/cygwin/configure.in @@ -1,5 +1,5 @@ dnl Autoconf configure script for Cygwin. -dnl Copyright 1996, 1997, 1998, 2000, 2001 Red Hat, Inc. +dnl Copyright 1996, 1997, 1998, 2000, 2001, 2002, 2003 Red Hat, Inc. dnl dnl This file is part of Cygwin. dnl @@ -111,27 +111,6 @@ if test $use_builtin_memset = "yes"; then fi AC_LANG_RESTORE -dnl set default mt safeness and then process the options. -mt_safe_val=1 -MT_SAFE=yes - -AC_ARG_ENABLE(threadsafe, -[ --enable-threadsafe=[runtime] Build a cygwin DLL which is thread safe], -[case "${enableval}" in -yes) - dnl default. - ;; -runtime) - mt_safe_val=2 - MT_SAFE=yes - ;; -no) - mt_safe_val=0 - MT_SAFE=no - ;; -esac -]) - AC_ARG_ENABLE(extra-threadsafe-checking, [ --enable-extra-threadsafe-checking Build a cygwin DLL which is thread safe with extra consistency checking], [case "${enableval}" in @@ -146,13 +125,6 @@ no) esac ]) -if test "$MT_SAFE" = "yes"; then - AC_DEFINE_UNQUOTED(_MT_SAFE,$mt_safe_val) -fi - -dnl Makefile uses MT_SAFE, so we subst as well as defining it. -AC_SUBST(MT_SAFE) - AC_ARG_ENABLE(debugging, [ --enable-debugging Build a cygwin DLL which has more consistency checking for debugging], [case "${enableval}" in @@ -161,6 +133,14 @@ no) ;; esac ]) +AC_ARG_ENABLE(server, +[ --enable-server Build a cygwin DLL which can communicate with cygserver], +[case "${enableval}" in +yes) AC_DEFINE(USE_CYGSERVER) ;; +no) ;; +esac +]) + MALLOC_OFILES= AC_ARG_ENABLE(malloc-debugging, [ --enable-malloc-debugging Build a cygwin DLL with heap sanity checking (this is very slow, use only if you have heap corruption problems)], diff --git a/winsup/cygwin/cygerrno.h b/winsup/cygwin/cygerrno.h new file mode 100644 index 00000000000..fb00f3f1d2a --- /dev/null +++ b/winsup/cygwin/cygerrno.h @@ -0,0 +1,41 @@ +/* cygerrno.h: main Cygwin header file. + + Copyright 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. */ + +#include <errno.h> + +void __stdcall seterrno_from_win_error (const char *file, int line, DWORD code) __attribute__ ((regparm(3))); +void __stdcall seterrno (const char *, int line) __attribute__ ((regparm(2))); +int __stdcall geterrno_from_win_error (DWORD code, int deferrno) __attribute__ ((regparm(2))); + +#define __seterrno() seterrno (__FILE__, __LINE__) +#define __seterrno_from_win_error(val) seterrno_from_win_error (__FILE__, __LINE__, val) + +#ifndef DEBUGGING +#define set_errno(val) (errno = (val)) +#else +int __stdcall __set_errno (const char *ln, int ln, int val) __attribute ((regparm(3))); +#define set_errno(val) __set_errno (__PRETTY_FUNCTION__, __LINE__, (val)) +#endif +#define get_errno() (errno) +extern "C" void __stdcall set_sig_errno (int e); + +class save_errno + { + int saved; + public: + save_errno () {saved = get_errno ();} + save_errno (int what) {saved = get_errno (); set_errno (what); } + void set (int what) {set_errno (what); saved = what;} + void reset () {saved = get_errno ();} + ~save_errno () {set_errno (saved);} + }; + +extern const char *__sp_fn; +extern int __sp_ln; diff --git a/winsup/cygwin/cygheap.cc b/winsup/cygwin/cygheap.cc index 1d3e4fb84c6..1ee1f2d7192 100644 --- a/winsup/cygwin/cygheap.cc +++ b/winsup/cygwin/cygheap.cc @@ -10,7 +10,6 @@ #include "winsup.h" #include <string.h> -#include <errno.h> #include <assert.h> #include <stdlib.h> #include "security.h" diff --git a/winsup/cygwin/cygheap.h b/winsup/cygwin/cygheap.h index 281f9b4b7eb..215d202b51b 100644 --- a/winsup/cygwin/cygheap.h +++ b/winsup/cygwin/cygheap.h @@ -92,7 +92,13 @@ enum homebodies CH_HOME }; -struct passwd; +enum impersonation +{ + IMP_BAD = -1, + IMP_NONE = 0, + IMP_EXTERNAL, + IMP_INTERNAL +}; class cygheap_user { @@ -117,8 +123,9 @@ public: /* token is needed if set(e)uid should be called. It can be set by a call to `set_impersonation_token()'. */ - HANDLE token; - BOOL impersonated; + HANDLE external_token; + HANDLE internal_token; + enum impersonation impersonation_state; /* CGF 2002-06-27. I removed the initializaton from this constructor since this class is always allocated statically. That means that everything @@ -165,7 +172,40 @@ public: const char *ontherange (homebodies what, struct passwd * = NULL); bool issetuid () const { - return impersonated && token != INVALID_HANDLE_VALUE; + return impersonation_state > IMP_NONE; + } + HANDLE token () + { + if (impersonation_state == IMP_EXTERNAL) + return external_token; + if (impersonation_state == IMP_INTERNAL) + return internal_token; + return INVALID_HANDLE_VALUE; + } + void deimpersonate () + { + if (impersonation_state > IMP_NONE) + RevertToSelf (); + } + void reimpersonate () + { + if (impersonation_state > IMP_NONE + && !ImpersonateLoggedOnUser (token ())) + system_printf ("ImpersonateLoggedOnUser: %E"); + } + bool has_impersonation_tokens () { return external_token || internal_token; } + void close_impersonation_tokens () + { + if (external_token) + { + CloseHandle (external_token); + external_token = 0; + } + if (internal_token) + { + CloseHandle (internal_token); + internal_token = 0; + } } const char *cygheap_user::test_uid (char *&, const char *, size_t) __attribute__ ((regparm (3))); diff --git a/winsup/cygwin/cygserver.cc b/winsup/cygwin/cygserver.cc new file mode 100755 index 00000000000..137730f9ef7 --- /dev/null +++ b/winsup/cygwin/cygserver.cc @@ -0,0 +1,773 @@ +/* cygserver.cc + + Copyright 2001, 2002 Red Hat Inc. + + Written by Egor Duda <deo@logos-m.ru> + +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 "woutsup.h" + +#include <sys/types.h> + +#include <assert.h> +#include <ctype.h> +#include <getopt.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "cygerrno.h" +#include "cygwin_version.h" + +#include "cygwin/cygserver.h" +#include "cygwin/cygserver_process.h" +#include "cygwin/cygserver_transport.h" + +// Version string. +static const char version[] = "$Revision$"; + +/* + * Support function for the XXX_printf () macros in "woutsup.h". + * Copied verbatim from "strace.cc". + */ +static int +getfunc (char *in_dst, const char *func) +{ + const char *p; + const char *pe; + char *dst = in_dst; + for (p = func; (pe = strchr (p, '(')); p = pe + 1) + if (isalnum ((int)pe[-1]) || pe[-1] == '_') + break; + else if (isspace ((int)pe[-1])) + { + pe--; + break; + } + if (!pe) + pe = strchr (func, '\0'); + for (p = pe; p > func; p--) + if (p != pe && *p == ' ') + { + p++; + break; + } + if (*p == '*') + p++; + while (p < pe) + *dst++ = *p++; + + *dst++ = ':'; + *dst++ = ' '; + *dst = '\0'; + + return dst - in_dst; +} + +/* + * Support function for the XXX_printf () macros in "woutsup.h". + */ +extern "C" void +__cygserver__printf (const char *const function, const char *const fmt, ...) +{ + const DWORD lasterror = GetLastError (); + const int lasterrno = errno; + + va_list ap; + + char *const buf = (char *) alloca (BUFSIZ); + + assert (buf); + + int len = 0; + + if (function) + len += getfunc (buf, function); + + va_start (ap, fmt); + len += vsnprintf (buf + len, BUFSIZ - len, fmt, ap); + va_end (ap); + + len += snprintf (buf + len, BUFSIZ - len, "\n"); + + const int actual = (len > BUFSIZ ? BUFSIZ : len); + + write (2, buf, actual); + + errno = lasterrno; + SetLastError (lasterror); + + return; +} + +#ifdef DEBUGGING + +int __stdcall +__set_errno (const char *func, int ln, int val) +{ + debug_printf ("%s:%d val %d", func, ln, val); + return _impure_ptr->_errno = val; +} + +#endif /* DEBUGGING */ + +GENERIC_MAPPING access_mapping; + +static BOOL +setup_privileges () +{ + BOOL rc, ret_val; + HANDLE hToken = NULL; + TOKEN_PRIVILEGES sPrivileges; + + rc = OpenProcessToken (GetCurrentProcess () , TOKEN_ALL_ACCESS , &hToken) ; + if (!rc) + { + system_printf ("error opening process token (%lu)", GetLastError ()); + ret_val = FALSE; + goto out; + } + rc = LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &sPrivileges.Privileges[0].Luid); + if (!rc) + { + system_printf ("error getting privilege luid (%lu)", GetLastError ()); + ret_val = FALSE; + goto out; + } + sPrivileges.PrivilegeCount = 1 ; + sPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED ; + rc = AdjustTokenPrivileges (hToken, FALSE, &sPrivileges, 0, NULL, NULL) ; + if (!rc) + { + system_printf ("error adjusting privilege level. (%lu)", + GetLastError ()); + ret_val = FALSE; + goto out; + } + + access_mapping.GenericRead = FILE_READ_DATA; + access_mapping.GenericWrite = FILE_WRITE_DATA; + access_mapping.GenericExecute = 0; + access_mapping.GenericAll = FILE_READ_DATA | FILE_WRITE_DATA; + + ret_val = TRUE; + +out: + CloseHandle (hToken); + return ret_val; +} + +int +check_and_dup_handle (HANDLE from_process, HANDLE to_process, + HANDLE from_process_token, + DWORD access, + HANDLE from_handle, + HANDLE *to_handle_ptr, BOOL bInheritHandle = FALSE) +{ + HANDLE local_handle = NULL; + int ret_val = EACCES; + + if (from_process != GetCurrentProcess ()) + { + if (!DuplicateHandle (from_process, from_handle, + GetCurrentProcess (), &local_handle, + 0, bInheritHandle, + DUPLICATE_SAME_ACCESS)) + { + system_printf ("error getting handle(%u) to server (%lu)", + (unsigned int)from_handle, GetLastError ()); + goto out; + } + } else + local_handle = from_handle; + + if (!wincap.has_security ()) + assert (!from_process_token); + else + { + char sd_buf [1024]; + PSECURITY_DESCRIPTOR sd = (PSECURITY_DESCRIPTOR) &sd_buf; + DWORD bytes_needed; + PRIVILEGE_SET ps; + DWORD ps_len = sizeof (ps); + BOOL status; + + if (!GetKernelObjectSecurity (local_handle, + (OWNER_SECURITY_INFORMATION + | GROUP_SECURITY_INFORMATION + | DACL_SECURITY_INFORMATION), + sd, sizeof (sd_buf), &bytes_needed)) + { + system_printf ("error getting handle SD (%lu)", GetLastError ()); + goto out; + } + + MapGenericMask (&access, &access_mapping); + + if (!AccessCheck (sd, from_process_token, access, &access_mapping, + &ps, &ps_len, &access, &status)) + { + system_printf ("error checking access rights (%lu)", + GetLastError ()); + goto out; + } + + if (!status) + { + system_printf ("access to object denied"); + goto out; + } + } + + if (!DuplicateHandle (from_process, from_handle, + to_process, to_handle_ptr, + access, bInheritHandle, 0)) + { + system_printf ("error getting handle to client (%lu)", GetLastError ()); + goto out; + } + + // verbose: debug_printf ("Duplicated %p to %p", from_handle, *to_handle_ptr); + + ret_val = 0; + + out: + if (local_handle && from_process != GetCurrentProcess ()) + CloseHandle (local_handle); + + return (ret_val); +} + +/* + * client_request_attach_tty::serve () + */ + +void +client_request_attach_tty::serve (transport_layer_base *const conn, + process_cache *) +{ + assert (conn); + + assert (!error_code ()); + + if (!wincap.has_security ()) + { + syscall_printf ("operation only supported on systems with security"); + error_code (EINVAL); + msglen (0); + return; + } + + if (msglen () != sizeof (req)) + { + syscall_printf ("bad request body length: expecting %lu bytes, got %lu", + sizeof (req), msglen ()); + error_code (EINVAL); + msglen (0); + return; + } + + msglen (0); // Until we fill in some fields. + + // verbose: debug_printf ("pid %ld:(%p,%p) -> pid %ld", + // req.master_pid, req.from_master, req.to_master, + // req.pid); + + // verbose: debug_printf ("opening process %ld", req.master_pid); + + const HANDLE from_process_handle = + OpenProcess (PROCESS_DUP_HANDLE, FALSE, req.master_pid); + + if (!from_process_handle) + { + system_printf ("error opening `from' process, error = %lu", + GetLastError ()); + error_code (EACCES); + return; + } + + // verbose: debug_printf ("opening process %ld", req.pid); + + const HANDLE to_process_handle = + OpenProcess (PROCESS_DUP_HANDLE, FALSE, req.pid); + + if (!to_process_handle) + { + system_printf ("error opening `to' process, error = %lu", + GetLastError ()); + CloseHandle (from_process_handle); + error_code (EACCES); + return; + } + + // verbose: debug_printf ("Impersonating client"); + conn->impersonate_client (); + + HANDLE token_handle = NULL; + + // verbose: debug_printf ("about to open thread token"); + const DWORD rc = OpenThreadToken (GetCurrentThread (), + TOKEN_QUERY, + TRUE, + &token_handle); + + // verbose: debug_printf ("opened thread token, rc=%lu", rc); + conn->revert_to_self (); + + if (!rc) + { + system_printf ("error opening thread token, error = %lu", + GetLastError ()); + CloseHandle (from_process_handle); + CloseHandle (to_process_handle); + error_code (EACCES); + return; + } + + // From this point on, a reply body is returned to the client. + + const HANDLE from_master = req.from_master; + const HANDLE to_master = req.to_master; + + req.from_master = NULL; + req.to_master = NULL; + + msglen (sizeof (req)); + + if (from_master) + if (check_and_dup_handle (from_process_handle, to_process_handle, + token_handle, + GENERIC_READ, + from_master, + &req.from_master, TRUE) != 0) + { + system_printf ("error duplicating from_master handle, error = %lu", + GetLastError ()); + error_code (EACCES); + } + + if (to_master) + if (check_and_dup_handle (from_process_handle, to_process_handle, + token_handle, + GENERIC_WRITE, + to_master, + &req.to_master, TRUE) != 0) + { + system_printf ("error duplicating to_master handle, error = %lu", + GetLastError ()); + error_code (EACCES); + } + + CloseHandle (from_process_handle); + CloseHandle (to_process_handle); + CloseHandle (token_handle); + + debug_printf ("%lu(%lu, %lu) -> %lu(%lu,%lu)", + req.master_pid, from_master, to_master, + req.pid, req.from_master, req.to_master); + + return; +} + +void +client_request_get_version::serve (transport_layer_base *, process_cache *) +{ + assert (!error_code ()); + + if (msglen ()) + syscall_printf ("unexpected request body ignored: %lu bytes", msglen ()); + + msglen (sizeof (version)); + + version.major = CYGWIN_SERVER_VERSION_MAJOR; + version.api = CYGWIN_SERVER_VERSION_API; + version.minor = CYGWIN_SERVER_VERSION_MINOR; + version.patch = CYGWIN_SERVER_VERSION_PATCH; +} + +class server_request : public queue_request +{ +public: + server_request (transport_layer_base *const conn, process_cache *const cache) + : _conn (conn), _cache (cache) + {} + + virtual ~server_request () + { + safe_delete (_conn); + } + + virtual void process () + { + client_request::handle_request (_conn, _cache); + } + +private: + transport_layer_base *const _conn; + process_cache *const _cache; +}; + +class server_submission_loop : public queue_submission_loop +{ +public: + server_submission_loop (threaded_queue *const queue, + transport_layer_base *const transport, + process_cache *const cache) + : queue_submission_loop (queue, false), + _transport (transport), + _cache (cache) + { + assert (_transport); + assert (_cache); + } + +private: + transport_layer_base *const _transport; + process_cache *const _cache; + + virtual void request_loop (); +}; + +/* FIXME: this is a little ugly. What we really want is to wait on + * two objects: one for the pipe/socket, and one for being told to + * shutdown. Otherwise this will stay a problem (we won't actually + * shutdown until the request _AFTER_ the shutdown request. And + * sending ourselves a request is ugly + */ +void +server_submission_loop::request_loop () +{ + /* I'd like the accepting thread's priority to be above any "normal" + * thread in the system to avoid overflowing the listen queue (for + * sockets; similar issues exist for named pipes); but, for example, + * a normal priority thread in a foregrounded process is boosted to + * THREAD_PRIORITY_HIGHEST (AFAICT). Thus try to set the current + * thread's priority to a level one above that. This fails on + * win9x/ME so assume any failure in that call is due to that and + * simply call again at one priority level lower. + */ + if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST + 1)) + if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST)) + debug_printf ("failed to raise accept thread priority, error = %lu", + GetLastError ()); + + while (_running) + { + bool recoverable = false; + transport_layer_base *const conn = _transport->accept (&recoverable); + if (!conn && !recoverable) + { + system_printf ("fatal error on IPC transport: closing down"); + return; + } + // EINTR probably implies a shutdown request; so back off for a + // moment to let the main thread take control, otherwise the + // server spins here receiving EINTR repeatedly since the signal + // handler in the main thread doesn't get a chance to be called. + if (!conn && errno == EINTR) + { + if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_NORMAL)) + debug_printf ("failed to reset thread priority, error = %lu", + GetLastError ()); + + Sleep (0); + if (!SetThreadPriority (GetCurrentThread (), + THREAD_PRIORITY_HIGHEST + 1)) + if (!SetThreadPriority (GetCurrentThread (), + THREAD_PRIORITY_HIGHEST)) + debug_printf ("failed to raise thread priority, error = %lu", + GetLastError ()); + } + if (conn) + _queue->add (safe_new (server_request, conn, _cache)); + } +} + +client_request_shutdown::client_request_shutdown () + : client_request (CYGSERVER_REQUEST_SHUTDOWN) +{ + // verbose: syscall_printf ("created"); +} + +void +client_request_shutdown::serve (transport_layer_base *, process_cache *) +{ + assert (!error_code ()); + + if (msglen ()) + syscall_printf ("unexpected request body ignored: %lu bytes", msglen ()); + + /* FIXME: link upwards, and then this becomes a trivial method call to + * only shutdown _this queue_ + */ + + kill (getpid (), SIGINT); + + msglen (0); +} + +static sig_atomic_t shutdown_server = false; + +static void +handle_signal (const int signum) +{ + /* any signal makes us die :} */ + + shutdown_server = true; +} + +/* + * print_usage () + */ + +static void +print_usage (const char *const pgm) +{ + printf ("Usage: %s [OPTIONS]\n", pgm); + printf (" -c, --cleanup-threads number of cleanup threads to use\n"); + printf (" -h, --help output usage information and exit\n"); + printf (" -r, --request-threads number of request threads to use\n"); + printf (" -s, --shutdown shutdown the daemon\n"); + printf (" -v, --version output version information and exit\n"); +} + +/* + * print_version () + */ + +static void +print_version (const char *const pgm) +{ + char *vn = NULL; + + const char *const colon = strchr (version, ':'); + + if (!colon) + { + vn = strdup ("?"); + } + else + { + vn = strdup (colon + 2); // Skip ": " + + char *const spc = strchr (vn, ' '); + + if (spc) + *spc = '\0'; + } + + char buf[200]; + snprintf (buf, sizeof (buf), "%d.%d.%d(%d.%d/%d/%d)-(%d.%d.%d.%d) %s", + cygwin_version.dll_major / 1000, + cygwin_version.dll_major % 1000, + cygwin_version.dll_minor, + cygwin_version.api_major, + cygwin_version.api_minor, + cygwin_version.shared_data, + CYGWIN_SERVER_VERSION_MAJOR, + CYGWIN_SERVER_VERSION_API, + CYGWIN_SERVER_VERSION_MINOR, + CYGWIN_SERVER_VERSION_PATCH, + cygwin_version.mount_registry, + cygwin_version.dll_build_date); + + printf ("%s (cygwin) %s\n", pgm, vn); + printf ("API version %s\n", buf); + printf ("Copyright 2001, 2002 Red Hat, Inc.\n"); + printf ("Compiled on %s\n", __DATE__); + + free (vn); +} + +/* + * main () + */ + +int +main (const int argc, char *argv[]) +{ + const struct option longopts[] = { + {"cleanup-threads", required_argument, NULL, 'c'}, + {"help", no_argument, NULL, 'h'}, + {"request-threads", required_argument, NULL, 'r'}, + {"shutdown", no_argument, NULL, 's'}, + {"version", no_argument, NULL, 'v'}, + {0, no_argument, NULL, 0} + }; + + const char opts[] = "c:hr:sv"; + + int cleanup_threads = 2; + int request_threads = 10; + bool shutdown = false; + + const char *pgm = NULL; + + if (!(pgm = strrchr (*argv, '\\')) && !(pgm = strrchr (*argv, '/'))) + pgm = *argv; + else + pgm++; + + wincap.init (); + if (wincap.has_security ()) + setup_privileges (); + + int opt; + + while ((opt = getopt_long (argc, argv, opts, longopts, NULL)) != EOF) + switch (opt) + { + case 'c': + cleanup_threads = atoi (optarg); + if (cleanup_threads <= 0) + { + fprintf (stderr, + "%s: number of cleanup threads must be positive\n", + pgm); + exit (1); + } + break; + + case 'h': + print_usage (pgm); + return 0; + + case 'r': + request_threads = atoi (optarg); + if (request_threads <= 0) + { + fprintf (stderr, + "%s: number of request threads must be positive\n", + pgm); + exit (1); + } + break; + + case 's': + shutdown = true; + break; + + case 'v': + print_version (pgm); + return 0; + + case '?': + fprintf (stderr, "Try `%s --help' for more information.\n", pgm); + exit (1); + } + + if (optind != argc) + { + fprintf (stderr, "%s: too many arguments\n", pgm); + exit (1); + } + + if (shutdown) + { + /* Setting `cygserver_running' stops the request code making a + * version request, which is not much to the point. + */ + cygserver_running = CYGSERVER_OK; + + client_request_shutdown req; + + if (req.make_request () == -1 || req.error_code ()) + { + fprintf (stderr, "%s: shutdown request failed: %s\n", + pgm, strerror (req.error_code ())); + exit (1); + } + + // FIXME: It would be nice to wait here for the daemon to exit. + + return 0; + } + +#define SIGHANDLE(SIG) \ + do \ + { \ + struct sigaction act; \ + \ + act.sa_handler = &handle_signal; \ + act.sa_mask = 0; \ + act.sa_flags = 0; \ + \ + if (sigaction (SIG, &act, NULL) == -1) \ + { \ + system_printf ("failed to install handler for " #SIG ": %s", \ + strerror (errno)); \ + exit (1); \ + } \ + } while (false) + + SIGHANDLE (SIGHUP); + SIGHANDLE (SIGINT); + SIGHANDLE (SIGTERM); + + print_version (pgm); + setbuf (stdout, NULL); + printf ("daemon starting up"); + + threaded_queue request_queue (request_threads); + printf ("."); + + transport_layer_base *const transport = create_server_transport (); + assert (transport); + printf ("."); + + process_cache cache (cleanup_threads); + printf ("."); + + server_submission_loop submission_loop (&request_queue, transport, &cache); + printf ("."); + + request_queue.add_submission_loop (&submission_loop); + printf ("."); + + if (transport->listen () == -1) + { + exit (1); + } + printf ("."); + + cache.start (); + printf ("."); + + request_queue.start (); + printf ("."); + + printf ("complete\n"); + + /* TODO: wait on multiple objects - the thread handle for each + * request loop + all the process handles. This should be done by + * querying the request_queue and the process cache for all their + * handles, and then waiting for (say) 30 seconds. after that we + * recreate the list of handles to wait on, and wait again. the + * point of all this abstraction is that we can trivially server + * both sockets and pipes simply by making a new transport, and then + * calling request_queue.process_requests (transport2); + */ + /* WaitForMultipleObjects abort && request_queue && process_queue && signal + -- if signal event then retrigger it + */ + while (!shutdown_server && request_queue.running () && cache.running ()) + pause (); + + printf ("\nShutdown request received - new requests will be denied\n"); + request_queue.stop (); + printf ("All pending requests processed\n"); + safe_delete (transport); + printf ("No longer accepting requests - cygwin will operate in daemonless mode\n"); + cache.stop (); + printf ("All outstanding process-cache activities completed\n"); + printf ("daemon shutdown\n"); + + return 0; +} diff --git a/winsup/cygwin/cygserver_client.cc b/winsup/cygwin/cygserver_client.cc new file mode 100755 index 00000000000..f6683182d72 --- /dev/null +++ b/winsup/cygwin/cygserver_client.cc @@ -0,0 +1,528 @@ +/* cygserver_client.cc + + Copyright 2001, 2002 Red Hat Inc. + + Written by Egor Duda <deo@logos-m.ru> + +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. */ + +/* to allow this to link into cygwin and the .dll, a little magic is needed. */ +#ifdef __OUTSIDE_CYGWIN__ +#include "woutsup.h" +#else +#include "winsup.h" +#endif + +#include <assert.h> +#include <stdio.h> +#include <unistd.h> + +#include "cygerrno.h" +#include "cygserver_shm.h" +#include "safe_memory.h" + +#include "cygwin/cygserver.h" +#include "cygwin/cygserver_transport.h" + +int cygserver_running = CYGSERVER_UNKNOWN; // Nb: inherited by children. + +/* On by default during development. For release, we probably want off + * by default. + */ +bool allow_daemon = true; // Nb: inherited by children. + +client_request_get_version::client_request_get_version () + : client_request (CYGSERVER_REQUEST_GET_VERSION, &version, sizeof (version)) +{ + msglen (0); // No parameters for request. + + // verbose: syscall_printf ("created"); +} + +/* + * client_request_get_version::check_version () + * + * The major version and API version numbers must match exactly. An + * older than expected minor version number is accepted (as long as + * the first numbers match, that is). + */ + +bool +client_request_get_version::check_version () const +{ + const bool ok = (version.major == CYGWIN_SERVER_VERSION_MAJOR + && version.api == CYGWIN_SERVER_VERSION_API + && version.minor <= CYGWIN_SERVER_VERSION_MINOR); + + if (!ok) + syscall_printf (("incompatible version of cygwin server: " + "client version %d.%d.%d.%d, " + "server version %ld.%ld.%ld.%ld"), + CYGWIN_SERVER_VERSION_MAJOR, + CYGWIN_SERVER_VERSION_API, + CYGWIN_SERVER_VERSION_MINOR, + CYGWIN_SERVER_VERSION_PATCH, + version.major, + version.api, + version.minor, + version.patch); + + return ok; +} + +#ifdef __INSIDE_CYGWIN__ + +client_request_attach_tty::client_request_attach_tty (DWORD nmaster_pid, + HANDLE nfrom_master, + HANDLE nto_master) + : client_request (CYGSERVER_REQUEST_ATTACH_TTY, &req, sizeof (req)) +{ + req.pid = GetCurrentProcessId (); + req.master_pid = nmaster_pid; + req.from_master = nfrom_master; + req.to_master = nto_master; + + syscall_printf (("created: pid = %lu, master_pid = %lu, " + "from_master = %lu, to_master = %lu"), + req.pid, req.master_pid, req.from_master, req.to_master); +} + +#else /* !__INSIDE_CYGWIN__ */ + +client_request_attach_tty::client_request_attach_tty () + : client_request (CYGSERVER_REQUEST_ATTACH_TTY, &req, sizeof (req)) +{ + // verbose: syscall_printf ("created"); +} + +#endif /* __INSIDE_CYGWIN__ */ + +/* + * client_request_attach_tty::send () + * + * Wraps the base method to provide error handling support. If the + * reply contains a body but is flagged as an error, close any handles + * that have been returned by cygserver and then discard the message + * body, i.e. the client either sees a successful result with handles + * or an unsuccessful result with no handles. + */ + +void +client_request_attach_tty::send (transport_layer_base * const conn) +{ + client_request::send (conn); + + if (msglen () && error_code ()) + { + if (from_master ()) + CloseHandle (from_master ()); + if (to_master ()) + CloseHandle (to_master ()); + msglen (0); + } +} + +client_request::header_t::header_t (const request_code_t request_code, + const size_t msglen) + : msglen (msglen), + request_code (request_code) +{ + assert (request_code >= 0 && request_code < CYGSERVER_REQUEST_LAST); +} + +// FIXME: also check write and read result for -1. + +void +client_request::send (transport_layer_base * const conn) +{ + assert (conn); + assert (!(msglen () && !_buf)); // i.e., msglen () implies _buf + assert (msglen () <= _buflen); + + { + const ssize_t count = conn->write (&_header, sizeof (_header)); + + if (count != sizeof (_header)) + { + assert (errno); + error_code (errno); + syscall_printf (("request header write failure: " + "only %ld bytes sent of %ld, " + "error = %d(%lu)"), + count, sizeof (_header), + errno, GetLastError ()); + return; + } + } + + if (msglen ()) + { + const ssize_t count = conn->write (_buf, msglen ()); + + if (count == -1 || (size_t) count != msglen ()) + { + assert (errno); + error_code (errno); + syscall_printf (("request body write failure: " + "only %ld bytes sent of %ld, " + "error = %d(%lu)"), + count, msglen (), + errno, GetLastError ()); + return; + } + } + + // verbose: syscall_printf ("request sent (%ld + %ld bytes)", + // sizeof (_header), msglen ()); + + { + const ssize_t count = conn->read (&_header, sizeof (_header)); + + if (count != sizeof (_header)) + { + assert (errno); + error_code (errno); + syscall_printf (("reply header read failure: " + "only %ld bytes received of %ld, " + "error = %d(%lu)"), + count, sizeof (_header), + errno, GetLastError ()); + return; + } + } + + if (msglen () && !_buf) + { + system_printf ("no client buffer for reply body: %ld bytes needed", + msglen ()); + error_code (EINVAL); + return; + } + + if (msglen () > _buflen) + { + system_printf (("client buffer too small for reply body: " + "have %ld bytes and need %ld"), + _buflen, msglen ()); + error_code (EINVAL); + return; + } + + if (msglen ()) + { + const ssize_t count = conn->read (_buf, msglen ()); + + if (count == -1 || (size_t) count != msglen ()) + { + assert (errno); + error_code (errno); + syscall_printf (("reply body read failure: " + "only %ld bytes received of %ld, " + "error = %d(%lu)"), + count, msglen (), + errno, GetLastError ()); + return; + } + } + + // verbose: syscall_printf ("reply received (%ld + %ld bytes)", + // sizeof (_header), msglen ()); +} + +#ifndef __INSIDE_CYGWIN__ + +/* + * client_request::handle_request () + * + * A server-side method. + * + * This is a factory method for the client_request subclasses. It + * reads the incoming request header and, based on its request code, + * creates an instance of the appropriate class. + * + * FIXME: If the incoming packet is malformed, the server drops it on + * the floor. Should it try and generate some sort of reply for the + * client? As it is, the client will simply get a broken connection. + * + * FIXME: also check write and read result for -1. + */ + +/* static */ void +client_request::handle_request (transport_layer_base *const conn, + process_cache *const cache) +{ + // verbose: debug_printf ("about to read"); + + header_t header; + + { + const ssize_t count = conn->read (&header, sizeof (header)); + + if (count != sizeof (header)) + { + syscall_printf (("request header read failure: " + "only %ld bytes received of %ld, " + "error = %d(%lu)"), + count, sizeof (header), + errno, GetLastError ()); + return; + } + + // verbose: debug_printf ("got header (%ld)", count); + } + + client_request *req = NULL; + + switch (header.request_code) + { + case CYGSERVER_REQUEST_GET_VERSION: + req = safe_new0 (client_request_get_version); + break; + case CYGSERVER_REQUEST_SHUTDOWN: + req = safe_new0 (client_request_shutdown); + break; + case CYGSERVER_REQUEST_ATTACH_TTY: + req = safe_new0 (client_request_attach_tty); + break; + case CYGSERVER_REQUEST_SHM: + req = safe_new0 (client_request_shm); + break; + default: + syscall_printf ("unknown request code %d received: request ignored", + header.request_code); + return; + } + + assert (req); + + req->msglen (header.msglen); + req->handle (conn, cache); + + safe_delete (req); + +#ifndef DEBUGGING + printf ("."); // A little noise when we're being quiet. +#endif +} + +#endif /* !__INSIDE_CYGWIN__ */ + +client_request::client_request (request_code_t const id, + void * const buf, + size_t const buflen) + : _header (id, buflen), + _buf (buf), + _buflen (buflen) +{ + assert ((!_buf && !_buflen) || (_buf && _buflen)); +} + +client_request::~client_request () +{} + +int +client_request::make_request () +{ + assert (cygserver_running == CYGSERVER_UNKNOWN \ + || cygserver_running == CYGSERVER_OK \ + || cygserver_running == CYGSERVER_UNAVAIL); + + if (cygserver_running == CYGSERVER_UNKNOWN) + cygserver_init (); + + assert (cygserver_running == CYGSERVER_OK \ + || cygserver_running == CYGSERVER_UNAVAIL); + + /* Don't retry every request if the server's not there */ + if (cygserver_running == CYGSERVER_UNAVAIL) + { + syscall_printf ("cygserver un-available"); + error_code (ENOSYS); + return -1; + } + + transport_layer_base *const transport = create_server_transport (); + + assert (transport); + + if (transport->connect () == -1) + { + if (errno) + error_code (errno); + else + error_code (ENOSYS); + safe_delete (transport); + return -1; + } + + // verbose: debug_printf ("connected to server %p", transport); + + send (transport); + + safe_delete (transport); + + return 0; +} + +#ifndef __INSIDE_CYGWIN__ + +/* + * client_request::handle () + * + * A server-side method. + * + * At this point, the header of an incoming request has been read and + * an appropriate client_request object constructed. This method has + * to read the request body into its buffer, if there is such a body, + * then perform the request and send back the results to the client. + * + * FIXME: If the incoming packet is malformed, the server drops it on + * the floor. Should it try and generate some sort of reply for the + * client? As it is, the client will simply get a broken connection. + * + * FIXME: also check write and read result for -1. + */ + +void +client_request::handle (transport_layer_base *const conn, + process_cache *const cache) +{ + if (msglen () && !_buf) + { + system_printf ("no buffer for request body: %ld bytes needed", + msglen ()); + error_code (EINVAL); + return; + } + + if (msglen () > _buflen) + { + system_printf (("buffer too small for request body: " + "have %ld bytes and need %ld"), + _buflen, msglen ()); + error_code (EINVAL); + return; + } + + if (msglen ()) + { + const ssize_t count = conn->read (_buf, msglen ()); + + if (count == -1 || (size_t) count != msglen ()) + { + assert (errno); + error_code (errno); + syscall_printf (("request body read failure: " + "only %ld bytes received of %ld, " + "error = %d(%lu)"), + count, msglen (), + errno, GetLastError ()); + return; + } + } + + // verbose: syscall_printf ("request received (%ld + %ld bytes)", + // sizeof (_header), msglen ()); + + error_code (0); // Overwrites the _header.request_code field. + + /* + * This is not allowed to fail. We must return ENOSYS at a minimum + * to the client. + */ + serve (conn, cache); + + { + const ssize_t count = conn->write (&_header, sizeof (_header)); + + if (count != sizeof (_header)) + { + assert (errno); + error_code (errno); + syscall_printf (("reply header write failure: " + "only %ld bytes sent of %ld, " + "error = %d(%lu)"), + count, sizeof (_header), + errno, GetLastError ()); + return; + } + } + + if (msglen ()) + { + const ssize_t count = conn->write (_buf, msglen ()); + + if (count == -1 || (size_t) count != msglen ()) + { + assert (errno); + error_code (errno); + syscall_printf (("reply body write failure: " + "only %ld bytes sent of %ld, " + "error = %d(%lu)"), + count, msglen (), + errno, GetLastError ()); + return; + } + } + + // verbose: syscall_printf ("reply sent (%ld + %ld bytes)", + // sizeof (_header), msglen ()); +} + +#endif /* !__INSIDE_CYGWIN__ */ + +bool +check_cygserver_available () +{ + assert (cygserver_running == CYGSERVER_UNKNOWN \ + || cygserver_running == CYGSERVER_UNAVAIL); + + cygserver_running = CYGSERVER_OK; // For make_request (). + + client_request_get_version req; + + /* This indicates that we failed to connect to cygserver at all but + * that's fine as cygwin doesn't need it to be running. + */ + if (req.make_request () == -1) + return false; + + /* We connected to the server but something went wrong after that + * (in sending the message, in cygserver itself, or in receiving the + * reply). + */ + if (req.error_code ()) + { + syscall_printf ("failure in cygserver version request: %d", + req.error_code ()); + syscall_printf ("process will continue without cygserver support"); + return false; + } + + return req.check_version (); +} + +void +cygserver_init () +{ + if (!allow_daemon) + { + syscall_printf ("cygserver use disabled in client"); + cygserver_running = CYGSERVER_UNAVAIL; + return; + } + + assert (cygserver_running == CYGSERVER_UNKNOWN \ + || cygserver_running == CYGSERVER_OK \ + || cygserver_running == CYGSERVER_UNAVAIL); + + if (cygserver_running == CYGSERVER_OK) + return; + + if (!check_cygserver_available ()) + cygserver_running = CYGSERVER_UNAVAIL; +} diff --git a/winsup/cygwin/cygserver_process.cc b/winsup/cygwin/cygserver_process.cc new file mode 100755 index 00000000000..2cc7be19c92 --- /dev/null +++ b/winsup/cygwin/cygserver_process.cc @@ -0,0 +1,431 @@ +/* cygserver_process.cc + + Copyright 2001, 2002 Red Hat Inc. + + Written by Robert Collins <rbtcollins@hotmail.com> + +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 "woutsup.h" + +#include <sys/types.h> + +#include <assert.h> +#include <stdlib.h> + +#include "cygerrno.h" + +#include "cygwin/cygserver_process.h" + +/*****************************************************************************/ + +#define elements(ARRAY) (sizeof (ARRAY) / sizeof (*ARRAY)) + +/*****************************************************************************/ + +process_cleanup::~process_cleanup () +{ + safe_delete (_process); +} + +void +process_cleanup::process () +{ + _process->cleanup (); +} + +/*****************************************************************************/ + +/* cleanup_routine */ +cleanup_routine::~cleanup_routine () +{ +} + +/*****************************************************************************/ + +process::process (const pid_t cygpid, const DWORD winpid) + : _cygpid (cygpid), + _winpid (winpid), + _hProcess (NULL), + _cleaning_up (false), + _exit_status (STILL_ACTIVE), + _routines_head (NULL), + _next (NULL) +{ + _hProcess = OpenProcess (PROCESS_ALL_ACCESS, FALSE, winpid); + if (!_hProcess) + { + system_printf ("unable to obtain handle for new cache process %d(%lu)", + _cygpid, _winpid); + _hProcess = INVALID_HANDLE_VALUE; + _exit_status = 0; + } + else + debug_printf ("got handle %p for new cache process %d(%lu)", + _hProcess, _cygpid, _winpid); + InitializeCriticalSection (&_access); +} + +process::~process () +{ + DeleteCriticalSection (&_access); + (void) CloseHandle (_hProcess); +} + +/* No need to be thread-safe as this is only ever called by + * process_cache::remove_process (). If it has to be made thread-safe + * later on, it should not use the `access' critical section as that + * is held by the client request handlers for an arbitrary length of + * time, i.e. while they do whatever processing is required for a + * client request. + */ +DWORD +process::check_exit_code () +{ + if (_hProcess && _hProcess != INVALID_HANDLE_VALUE + && _exit_status == STILL_ACTIVE + && !GetExitCodeProcess (_hProcess, &_exit_status)) + { + system_printf ("failed to retrieve exit code for %d(%lu), error = %lu", + _cygpid, _winpid, GetLastError ()); + _hProcess = INVALID_HANDLE_VALUE; + } + return _exit_status; +} + +bool +process::add (cleanup_routine *const entry) +{ + assert (entry); + + bool res = false; + EnterCriticalSection (&_access); + + if (!_cleaning_up) + { + entry->_next = _routines_head; + _routines_head = entry; + res = true; + } + + LeaveCriticalSection (&_access); + return res; +} + +bool +process::remove (const cleanup_routine *const entry) +{ + assert (entry); + + bool res = false; + EnterCriticalSection (&_access); + + if (!_cleaning_up) + { + cleanup_routine *previous = NULL; + + for (cleanup_routine *ptr = _routines_head; + ptr; + previous = ptr, ptr = ptr->_next) + { + if (*ptr == *entry) + { + if (previous) + previous->_next = ptr->_next; + else + _routines_head = ptr->_next; + + safe_delete (ptr); + res = true; + break; + } + } + } + + LeaveCriticalSection (&_access); + return res; +} + +/* This is single threaded. It's called after the process is removed + * from the cache, but inserts may be attemped by worker threads that + * have a pointer to it. + */ +void +process::cleanup () +{ + EnterCriticalSection (&_access); + assert (!is_active ()); + assert (!_cleaning_up); + InterlockedExchange (&_cleaning_up, true); + cleanup_routine *entry = _routines_head; + _routines_head = NULL; + LeaveCriticalSection (&_access); + + while (entry) + { + cleanup_routine *const ptr = entry; + entry = entry->_next; + ptr->cleanup (this); + safe_delete (ptr); + } +} + +/*****************************************************************************/ + +void +process_cache::submission_loop::request_loop () +{ + assert (this); + assert (_cache); + assert (_interrupt_event); + + while (_running) + _cache->wait_for_processes (_interrupt_event); +} + +/*****************************************************************************/ + +process_cache::process_cache (const unsigned int initial_workers) + : _queue (initial_workers), + _submitter (this, &_queue), // true == interruptible + _processes_count (0), + _processes_head (NULL), + _cache_add_trigger (NULL) +{ + /* there can only be one */ + InitializeCriticalSection (&_cache_write_access); + + _cache_add_trigger = CreateEvent (NULL, // SECURITY_ATTRIBUTES + FALSE, // Auto-reset + FALSE, // Initially non-signalled + NULL); // Anonymous + + if (!_cache_add_trigger) + { + system_printf ("failed to create cache add trigger, error = %lu", + GetLastError ()); + abort (); + } + + _queue.add_submission_loop (&_submitter); +} + +process_cache::~process_cache () +{ + (void) CloseHandle (_cache_add_trigger); + DeleteCriticalSection (&_cache_write_access); +} + +/* This returns the process object to the caller already locked, that + * is, with the object's `access' critical region entered. Thus the + * caller must unlock the object when it's finished with it (via + * process::release ()). It must then not try to access the object + * afterwards, except by going through this routine again, as it may + * have been deleted once it has been unlocked. + */ +class process * +process_cache::process (const pid_t cygpid, const DWORD winpid) +{ + /* TODO: make this more granular, so a search doesn't involve the + * write lock. + */ + EnterCriticalSection (&_cache_write_access); + class process *previous = NULL; + class process *entry = find (winpid, &previous); + + if (!entry) + { + if (_processes_count + SPECIALS_COUNT >= MAXIMUM_WAIT_OBJECTS) + { + LeaveCriticalSection (&_cache_write_access); + system_printf (("process limit (%d processes) reached; " + "new connection refused for %d(%lu)"), + MAXIMUM_WAIT_OBJECTS - SPECIALS_COUNT, + cygpid, winpid); + set_errno (EAGAIN); + return NULL; + } + + entry = safe_new (class process, cygpid, winpid); + if (!entry->is_active ()) + { + LeaveCriticalSection (&_cache_write_access); + safe_delete (entry); + set_errno (ESRCH); + return NULL; + } + + if (previous) + { + entry->_next = previous->_next; + previous->_next = entry; + } + else + { + entry->_next = _processes_head; + _processes_head = entry; + } + + _processes_count += 1; + SetEvent (_cache_add_trigger); + } + + EnterCriticalSection (&entry->_access); // To be released by the caller. + LeaveCriticalSection (&_cache_write_access); + assert (entry); + assert (entry->_winpid == winpid); + return entry; +} + +void +process_cache::wait_for_processes (const HANDLE interrupt_event) +{ + // Update `_wait_array' with handles of all current processes. + const size_t count = sync_wait_array (interrupt_event); + + debug_printf ("waiting on %u objects in total (%u processes)", + count, _processes_count); + + const DWORD rc = WaitForMultipleObjects (count, _wait_array, + FALSE, INFINITE); + + if (rc == WAIT_FAILED) + { + system_printf ("could not wait on the process handles, error = %lu", + GetLastError ()); + abort (); + } + + const size_t start = rc - WAIT_OBJECT_0; + + if (rc < WAIT_OBJECT_0 || start > count) + { + system_printf (("unexpected return code %rc " + "from WaitForMultipleObjects: " + "expected [%u .. %u)"), + rc, WAIT_OBJECT_0, WAIT_OBJECT_0 + count); + abort (); + } + + // Tell all the processes, from the signalled point up, the bad news. + for (size_t index = start; index != count; index++) + if (_process_array[index]) + check_and_remove_process (index); +} + +/* + * process_cache::sync_wait_array () + * + * Fill-in the wait array with the handles that the cache needs to wait on. + * These handles are: + * - the process_process_param's interrupt event + * - the process_cache's cache_add_trigger event + * - the handle for each live process in the cache. + * + * Return value: the number of live handles in the array. + */ + +size_t +process_cache::sync_wait_array (const HANDLE interrupt_event) +{ + assert (this); + assert (_cache_add_trigger && _cache_add_trigger != INVALID_HANDLE_VALUE); + assert (interrupt_event && interrupt_event != INVALID_HANDLE_VALUE); + + EnterCriticalSection (&_cache_write_access); + + assert (_processes_count + SPECIALS_COUNT <= elements (_wait_array)); + + size_t index = 0; + + for (class process *ptr = _processes_head; ptr; ptr = ptr->_next) + { + assert (ptr->_hProcess && ptr->_hProcess != INVALID_HANDLE_VALUE); + assert (ptr->is_active ()); + + _wait_array[index] = ptr->handle (); + _process_array[index++] = ptr; + + assert (index <= elements (_wait_array)); + } + + /* Sorry for shouting, but THESE MUST BE ADDED AT THE END! */ + /* Well, not strictly `must', but it's more efficient if they are :-) */ + + _wait_array[index] = interrupt_event; + _process_array[index++] = NULL; + + _wait_array[index] = _cache_add_trigger; + _process_array[index++] = NULL; + + /* Phew, back to normal volume now. */ + + assert (index <= elements (_wait_array)); + + LeaveCriticalSection (&_cache_write_access); + + return index; +} + +void +process_cache::check_and_remove_process (const size_t index) +{ + assert (this); + assert (index < elements (_wait_array) - SPECIALS_COUNT); + + class process *const process = _process_array[index]; + + assert (process); + assert (process->handle () == _wait_array[index]); + + if (process->check_exit_code () == STILL_ACTIVE) + return; + + debug_printf ("process %d(%lu) has left the building ($? = %lu)", + process->_cygpid, process->_winpid, process->_exit_status); + + /* Unlink the process object from the process list. */ + + EnterCriticalSection (&_cache_write_access); + + class process *previous = NULL; + + const class process *const tmp = find (process->_winpid, &previous); + + assert (tmp == process); + assert (previous ? previous->_next == process : _processes_head == process); + + if (previous) + previous->_next = process->_next; + else + _processes_head = process->_next; + + _processes_count -= 1; + LeaveCriticalSection (&_cache_write_access); + + /* Schedule any cleanup tasks for this process. */ + _queue.add (safe_new (process_cleanup, process)); +} + +class process * +process_cache::find (const DWORD winpid, class process **previous) +{ + if (previous) + *previous = NULL; + + for (class process *ptr = _processes_head; ptr; ptr = ptr->_next) + if (ptr->_winpid == winpid) + return ptr; + else if (ptr->_winpid > winpid) // The list is sorted by winpid. + return NULL; + else if (previous) + *previous = ptr; + + return NULL; +} + +/*****************************************************************************/ diff --git a/winsup/cygwin/cygserver_transport_pipes.cc b/winsup/cygwin/cygserver_transport_pipes.cc new file mode 100755 index 00000000000..6d80defd4ed --- /dev/null +++ b/winsup/cygwin/cygserver_transport_pipes.cc @@ -0,0 +1,362 @@ +/* cygserver_transport_pipes.cc + + Copyright 2001, 2002 Red Hat Inc. + + Written by Robert Collins <rbtcollins@hotmail.com> + +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. */ + +/* to allow this to link into cygwin and the .dll, a little magic is needed. */ +#ifdef __OUTSIDE_CYGWIN__ +#include "woutsup.h" +#else +#include "winsup.h" +#endif + +#include <sys/types.h> + +#include <assert.h> +#include <netdb.h> +#include <pthread.h> +#include <unistd.h> + +#include "cygerrno.h" +#include "cygwin/cygserver_transport.h" +#include "cygwin/cygserver_transport_pipes.h" + +#ifndef __INSIDE_CYGWIN__ +#include "cygwin/cygserver.h" +#endif + +enum + { + MAX_WAIT_NAMED_PIPE_RETRY = 64, + WAIT_NAMED_PIPE_TIMEOUT = 10 // milliseconds + }; + +#ifndef __INSIDE_CYGWIN__ + +static pthread_once_t pipe_instance_lock_once = PTHREAD_ONCE_INIT; +static CRITICAL_SECTION pipe_instance_lock; +static long pipe_instance = 0; + +static void +initialise_pipe_instance_lock () +{ + assert (pipe_instance == 0); + InitializeCriticalSection (&pipe_instance_lock); +} + +#endif /* !__INSIDE_CYGWIN__ */ + +#ifndef __INSIDE_CYGWIN__ + +transport_layer_pipes::transport_layer_pipes (const HANDLE hPipe) + : _pipe_name (""), + _hPipe (hPipe), + _is_accepted_endpoint (true), + _is_listening_endpoint (false) +{ + assert (_hPipe); + assert (_hPipe != INVALID_HANDLE_VALUE); + + init_security (); +} + +#endif /* !__INSIDE_CYGWIN__ */ + +transport_layer_pipes::transport_layer_pipes () + : _pipe_name ("\\\\.\\pipe\\cygwin_lpc"), + _hPipe (NULL), + _is_accepted_endpoint (false), + _is_listening_endpoint (false) +{ + init_security (); +} + +void +transport_layer_pipes::init_security () +{ + assert (wincap.has_security ()); + + /* FIXME: pthread_once or equivalent needed */ + + InitializeSecurityDescriptor (&_sd, SECURITY_DESCRIPTOR_REVISION); + SetSecurityDescriptorDacl (&_sd, TRUE, NULL, FALSE); + + _sec_all_nih.nLength = sizeof (SECURITY_ATTRIBUTES); + _sec_all_nih.lpSecurityDescriptor = &_sd; + _sec_all_nih.bInheritHandle = FALSE; +} + +transport_layer_pipes::~transport_layer_pipes () +{ + close (); +} + +#ifndef __INSIDE_CYGWIN__ + +int +transport_layer_pipes::listen () +{ + assert (!_hPipe); + assert (!_is_accepted_endpoint); + assert (!_is_listening_endpoint); + + _is_listening_endpoint = true; + + /* no-op */ + return 0; +} + +class transport_layer_pipes * +transport_layer_pipes::accept (bool *const recoverable) +{ + assert (!_hPipe); + assert (!_is_accepted_endpoint); + assert (_is_listening_endpoint); + + pthread_once (&pipe_instance_lock_once, &initialise_pipe_instance_lock); + + EnterCriticalSection (&pipe_instance_lock); + + // Read: http://www.securityinternals.com/research/papers/namedpipe.php + // See also the Microsoft security bulletins MS00-053 and MS01-031. + + // FIXME: Remove FILE_CREATE_PIPE_INSTANCE. + + const bool first_instance = (pipe_instance == 0); + + const HANDLE accept_pipe = + CreateNamedPipe (_pipe_name, + (PIPE_ACCESS_DUPLEX + | (first_instance ? FILE_FLAG_FIRST_PIPE_INSTANCE : 0)), + (PIPE_TYPE_BYTE | PIPE_WAIT), + PIPE_UNLIMITED_INSTANCES, + 0, 0, 1000, + &_sec_all_nih); + + const bool duplicate = (accept_pipe == INVALID_HANDLE_VALUE + && pipe_instance == 0 + && GetLastError () == ERROR_ACCESS_DENIED); + + if (accept_pipe != INVALID_HANDLE_VALUE) + InterlockedIncrement (&pipe_instance); + + LeaveCriticalSection (&pipe_instance_lock); + + if (duplicate) + { + *recoverable = false; + system_printf ("failed to create named pipe: " + "is the daemon already running?"); + return NULL; + } + + if (accept_pipe == INVALID_HANDLE_VALUE) + { + debug_printf ("error creating pipe (%lu).", GetLastError ()); + *recoverable = true; // FIXME: case analysis? + return NULL; + } + + assert (accept_pipe); + + if (!ConnectNamedPipe (accept_pipe, NULL) + && GetLastError () != ERROR_PIPE_CONNECTED) + { + debug_printf ("error connecting to pipe (%lu)", GetLastError ()); + (void) CloseHandle (accept_pipe); + *recoverable = true; // FIXME: case analysis? + return NULL; + } + + return safe_new (transport_layer_pipes, accept_pipe); +} + +#endif /* !__INSIDE_CYGWIN__ */ + +void +transport_layer_pipes::close () +{ + // verbose: debug_printf ("closing pipe %p", _hPipe); + + if (_hPipe) + { + assert (_hPipe != INVALID_HANDLE_VALUE); + +#ifndef __INSIDE_CYGWIN__ + + if (_is_accepted_endpoint) + { + (void) FlushFileBuffers (_hPipe); // Blocks until client reads. + (void) DisconnectNamedPipe (_hPipe); + EnterCriticalSection (&pipe_instance_lock); + (void) CloseHandle (_hPipe); + assert (pipe_instance > 0); + InterlockedDecrement (&pipe_instance); + LeaveCriticalSection (&pipe_instance_lock); + } + else + (void) CloseHandle (_hPipe); + +#else /* __INSIDE_CYGWIN__ */ + + assert (!_is_accepted_endpoint); + (void) ForceCloseHandle (_hPipe); + +#endif /* __INSIDE_CYGWIN__ */ + + _hPipe = NULL; + } +} + +ssize_t +transport_layer_pipes::read (void *const buf, const size_t len) +{ + // verbose: debug_printf ("reading from pipe %p", _hPipe); + + assert (_hPipe); + assert (_hPipe != INVALID_HANDLE_VALUE); + assert (!_is_listening_endpoint); + + DWORD count; + if (!ReadFile (_hPipe, buf, len, &count, NULL)) + { + debug_printf ("error reading from pipe (%lu)", GetLastError ()); + set_errno (EINVAL); // FIXME? + return -1; + } + + return count; +} + +ssize_t +transport_layer_pipes::write (void *const buf, const size_t len) +{ + // verbose: debug_printf ("writing to pipe %p", _hPipe); + + assert (_hPipe); + assert (_hPipe != INVALID_HANDLE_VALUE); + assert (!_is_listening_endpoint); + + DWORD count; + if (!WriteFile (_hPipe, buf, len, &count, NULL)) + { + debug_printf ("error writing to pipe, error = %lu", GetLastError ()); + set_errno (EINVAL); // FIXME? + return -1; + } + + return count; +} + +/* + * This routine holds a static variable, assume_cygserver, that is set + * if the transport has good reason to think that cygserver is + * running, i.e. if if successfully connected to it with the previous + * attempt. If this is set, the code tries a lot harder to get a + * connection, making the assumption that any failures are just + * congestion and overloading problems. + */ + +int +transport_layer_pipes::connect () +{ + assert (!_hPipe); + assert (!_is_accepted_endpoint); + assert (!_is_listening_endpoint); + + static bool assume_cygserver = false; + + BOOL rc = TRUE; + int retries = 0; + + while (rc) + { + _hPipe = CreateFile (_pipe_name, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + &_sec_all_nih, + OPEN_EXISTING, + SECURITY_IMPERSONATION, + NULL); + + if (_hPipe != INVALID_HANDLE_VALUE) + { + assert (_hPipe); +#ifdef __INSIDE_CYGWIN__ + ProtectHandle (_hPipe); +#endif + assume_cygserver = true; + return 0; + } + + _hPipe = NULL; + + if (!assume_cygserver && GetLastError () != ERROR_PIPE_BUSY) + { + debug_printf ("Error opening the pipe (%lu)", GetLastError ()); + return -1; + } + + /* Note: `If no instances of the specified named pipe exist, the + * WaitNamedPipe function returns immediately, regardless of the + * time-out value.' Thus the explicit Sleep if the call fails + * with ERROR_FILE_NOT_FOUND. + */ + while (retries != MAX_WAIT_NAMED_PIPE_RETRY + && !(rc = WaitNamedPipe (_pipe_name, WAIT_NAMED_PIPE_TIMEOUT))) + { + if (GetLastError () == ERROR_FILE_NOT_FOUND) + Sleep (0); // Give the server a chance. + + retries += 1; + } + } + + assert (retries == MAX_WAIT_NAMED_PIPE_RETRY); + + system_printf ("lost connection to cygserver, error = %lu", + GetLastError ()); + + assume_cygserver = false; + + return -1; +} + +#ifndef __INSIDE_CYGWIN__ + +void +transport_layer_pipes::impersonate_client () +{ + assert (_hPipe); + assert (_hPipe != INVALID_HANDLE_VALUE); + assert (_is_accepted_endpoint); + + // verbose: debug_printf ("impersonating pipe %p", _hPipe); + if (_hPipe) + { + assert (_hPipe != INVALID_HANDLE_VALUE); + + if (!ImpersonateNamedPipeClient (_hPipe)) + debug_printf ("Failed to Impersonate the client, (%lu)", + GetLastError ()); + } + // verbose: debug_printf ("I am who you are"); +} + +void +transport_layer_pipes::revert_to_self () +{ + assert (_is_accepted_endpoint); + + RevertToSelf (); + // verbose: debug_printf ("I am who I yam"); +} + +#endif /* !__INSIDE_CYGWIN__ */ diff --git a/winsup/cygwin/cygthread.cc b/winsup/cygwin/cygthread.cc index 2d45f2917f5..c4c871cf754 100644 --- a/winsup/cygwin/cygthread.cc +++ b/winsup/cygwin/cygthread.cc @@ -9,7 +9,6 @@ details. */ #include "winsup.h" #include <windows.h> #include <stdlib.h> -#include <errno.h> #include "exceptions.h" #include "security.h" #include "cygthread.h" diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din index 5dda7eadcb4..107dc00f3e2 100644 --- a/winsup/cygwin/cygwin.din +++ b/winsup/cygwin/cygwin.din @@ -26,6 +26,7 @@ __eprintf __errno __fpclassifyd __fpclassifyf +__getreent __infinity __main __signbitd @@ -1299,6 +1300,7 @@ sysconf _sysconf = sysconf syslog _syslog = syslog +vsyslog system _system = system tan diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index 09fbf58ee0f..04449b2f6ff 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -17,7 +17,6 @@ details. */ #include <limits.h> #include <wingdi.h> #include <winuser.h> -#include <errno.h> #include "sigproc.h" #include "pinfo.h" #include "cygerrno.h" @@ -54,9 +53,9 @@ per_thread NO_COPY *threadstuff[] = {&waitq_storage, &signal_dispatch_storage, NULL}; -BOOL display_title; -BOOL strip_title_path; -BOOL allow_glob = TRUE; +bool display_title; +bool strip_title_path; +bool allow_glob = TRUE; codepage_type current_codepage = ansi_cp; int cygwin_finished_initializing; diff --git a/winsup/cygwin/debug.cc b/winsup/cygwin/debug.cc index e85717bcac9..2f0471a1a6d 100644 --- a/winsup/cygwin/debug.cc +++ b/winsup/cygwin/debug.cc @@ -15,7 +15,6 @@ details. */ #include "security.h" #include "cygerrno.h" #ifdef DEBUGGING -#include <errno.h> #include "path.h" #include "fhandler.h" #include "dtable.h" @@ -222,6 +221,6 @@ int __stdcall __set_errno (const char *func, int ln, int val) { debug_printf ("%s:%d val %d", func, ln, val); - return _impure_ptr->_errno = val; + return errno = val; } #endif /*DEBUGGING*/ diff --git a/winsup/cygwin/dir.cc b/winsup/cygwin/dir.cc index 4ed076e2f35..88a1689e6fd 100644 --- a/winsup/cygwin/dir.cc +++ b/winsup/cygwin/dir.cc @@ -12,7 +12,6 @@ details. */ #include <unistd.h> #include <stdlib.h> #include <sys/stat.h> -#include <errno.h> #define _COMPILING_NEWLIB #include <dirent.h> diff --git a/winsup/cygwin/dll_init.cc b/winsup/cygwin/dll_init.cc index 4e5491947d2..38af9aa4cea 100644 --- a/winsup/cygwin/dll_init.cc +++ b/winsup/cygwin/dll_init.cc @@ -8,7 +8,6 @@ details. */ #include "winsup.h" #include <stdlib.h> -#include <errno.h> #include "cygerrno.h" #include "perprocess.h" #include "dll_init.h" diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc index 40c37caacea..6ff8121c72a 100644 --- a/winsup/cygwin/dtable.cc +++ b/winsup/cygwin/dtable.cc @@ -11,7 +11,6 @@ details. */ #define __INSIDE_CYGWIN_NET__ #include "winsup.h" -#include <errno.h> #include <sys/socket.h> #include <stdlib.h> #include <stdio.h> @@ -676,8 +675,7 @@ dtable::vfork_child_dup () int res = 1; /* Remove impersonation */ - if (cygheap->user.issetuid ()) - RevertToSelf (); + cygheap->user.deimpersonate (); for (size_t i = 0; i < size; i++) if (not_open (i)) @@ -696,8 +694,7 @@ dtable::vfork_child_dup () out: /* Restore impersonation */ - if (cygheap->user.issetuid ()) - ImpersonateLoggedOnUser (cygheap->user.token); + cygheap->user.reimpersonate (); ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "dup"); return 1; diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index 6a112518ee7..6c75f987dac 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -1,14 +1,13 @@ /* environ.cc: Cygwin-adopted functions from newlib to manipulate process's environment. - Copyright 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. + Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc. 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 <errno.h> #include <stdlib.h> #include <stddef.h> #include <ctype.h> @@ -27,17 +26,17 @@ details. */ #include "environ.h" #include "child_info.h" -extern BOOL allow_daemon; -extern BOOL allow_glob; +extern bool allow_glob; extern bool ignore_case_with_glob; -extern BOOL allow_ntea; -extern BOOL allow_smbntsec; -extern BOOL allow_winsymlinks; -extern BOOL strip_title_path; +extern bool allow_ntea; +extern bool allow_smbntsec; +extern bool allow_winsymlinks; +extern bool strip_title_path; extern int pcheck_case; extern int subauth_id; -BOOL reset_com = FALSE; -static BOOL envcache = TRUE; +bool reset_com = false; +bool allow_daemon = false; +static bool envcache = true; static char **lastenviron; @@ -366,7 +365,7 @@ ucenv (char *p, char *eq) /* Parse CYGWIN options */ -static NO_COPY BOOL export_settings = false; +static NO_COPY bool export_settings = false; enum settings { @@ -385,18 +384,18 @@ glob_init (const char *buf) { if (!buf || !*buf) { - allow_glob = FALSE; - ignore_case_with_glob = FALSE; + allow_glob = false; + ignore_case_with_glob = false; } else if (strncasematch (buf, "ignorecase", 10)) { - allow_glob = TRUE; - ignore_case_with_glob = TRUE; + allow_glob = true; + ignore_case_with_glob = true; } else { - allow_glob = TRUE; - ignore_case_with_glob = FALSE; + allow_glob = true; + ignore_case_with_glob = false; } } @@ -489,7 +488,7 @@ static struct parse_thing const char *name; union parse_setting { - BOOL *b; + bool *b; DWORD *x; int *i; void (*func)(const char *); @@ -507,21 +506,21 @@ static struct parse_thing {"binmode", {x: &binmode}, justset, NULL, {{O_TEXT}, {O_BINARY}}}, {"check_case", {func: &check_case_init}, isfunc, NULL, {{0}, {0}}}, {"codepage", {func: &codepage_init}, isfunc, NULL, {{0}, {0}}}, - {"daemon", {&allow_daemon}, justset, NULL, {{FALSE}, {TRUE}}}, - {"envcache", {&envcache}, justset, NULL, {{TRUE}, {FALSE}}}, + {"daemon", {&allow_daemon}, justset, NULL, {{false}, {true}}}, + {"envcache", {&envcache}, justset, NULL, {{true}, {false}}}, {"error_start", {func: &error_start_init}, isfunc, NULL, {{0}, {0}}}, - {"export", {&export_settings}, justset, NULL, {{FALSE}, {TRUE}}}, + {"export", {&export_settings}, justset, NULL, {{false}, {true}}}, {"forkchunk", {func: set_chunksize}, isfunc, NULL, {{0}, {0}}}, {"glob", {func: &glob_init}, isfunc, NULL, {{0}, {s: "normal"}}}, - {"ntea", {&allow_ntea}, justset, NULL, {{FALSE}, {TRUE}}}, - {"ntsec", {&allow_ntsec}, justset, NULL, {{FALSE}, {TRUE}}}, - {"smbntsec", {&allow_smbntsec}, justset, NULL, {{FALSE}, {TRUE}}}, - {"reset_com", {&reset_com}, justset, NULL, {{FALSE}, {TRUE}}}, - {"strip_title", {&strip_title_path}, justset, NULL, {{FALSE}, {TRUE}}}, + {"ntea", {&allow_ntea}, justset, NULL, {{false}, {true}}}, + {"ntsec", {&allow_ntsec}, justset, NULL, {{false}, {true}}}, + {"smbntsec", {&allow_smbntsec}, justset, NULL, {{false}, {true}}}, + {"reset_com", {&reset_com}, justset, NULL, {{false}, {true}}}, + {"strip_title", {&strip_title_path}, justset, NULL, {{false}, {true}}}, {"subauth_id", {func: &subauth_id_init}, isfunc, NULL, {{0}, {0}}}, - {"title", {&display_title}, justset, NULL, {{FALSE}, {TRUE}}}, + {"title", {&display_title}, justset, NULL, {{false}, {true}}}, {"tty", {NULL}, set_process_state, NULL, {{0}, {PID_USETTY}}}, - {"winsymlinks", {&allow_winsymlinks}, justset, NULL, {{FALSE}, {TRUE}}}, + {"winsymlinks", {&allow_winsymlinks}, justset, NULL, {{false}, {true}}}, {NULL, {0}, justset, 0, {{0}, {0}}} }; @@ -677,7 +676,7 @@ environ_init (char **envp, int envc) /* Set ntsec explicit as default, if NT is running */ if (wincap.has_security ()) - allow_ntsec = TRUE; + allow_ntsec = true; if (!envp) envp_passed_in = 0; diff --git a/winsup/cygwin/errno.cc b/winsup/cygwin/errno.cc index a922d5280dd..127eff9d353 100644 --- a/winsup/cygwin/errno.cc +++ b/winsup/cygwin/errno.cc @@ -10,14 +10,14 @@ details. */ #define _sys_nerr FOO_sys_nerr #define sys_nerr FOOsys_nerr +#define _sys_errlist FOO_sys_errlist #include "winsup.h" -#define _REENT_ONLY #include <stdio.h> -#include <errno.h> #include "cygerrno.h" #include "thread.h" #undef _sys_nerr #undef sys_nerr +#undef _sys_errlist /* Table to map Windows error codes to Errno values. */ /* FIXME: Doing things this way is a little slow. It's trivial to change @@ -25,13 +25,12 @@ details. */ #define X(w, e) {ERROR_##w, #w, e} -static const NO_COPY struct - { - DWORD w; /* windows version of error */ - const char *s; /* text of windows version */ - int e; /* errno version of error */ - } -errmap[] = +static NO_COPY struct +{ + DWORD w; /* windows version of error */ + const char *s; /* text of windows version */ + int e; /* errno version of error */ +} errmap[] = { /* FIXME: Some of these choices are arbitrary! */ X (INVALID_FUNCTION, EBADRQC), @@ -116,42 +115,8 @@ errmap[] = { 0, NULL, 0} }; -int __stdcall -geterrno_from_win_error (DWORD code, int deferrno) -{ - for (int i = 0; errmap[i].w != 0; ++i) - if (code == errmap[i].w) - { - syscall_printf ("windows error %u == errno %d", code, errmap[i].e); - return errmap[i].e; - } - - syscall_printf ("unknown windows error %u, setting errno to %d", code, - deferrno); - return deferrno; /* FIXME: what's so special about EACCESS? */ -} - -/* seterrno_from_win_error: Given a Windows error code, set errno - as appropriate. */ -void __stdcall -seterrno_from_win_error (const char *file, int line, DWORD code) -{ - syscall_printf ("%s:%d windows error %d", file, line, code); - set_errno (geterrno_from_win_error (code, EACCES)); - return; -} - -/* seterrno: Set `errno' based on GetLastError (). */ -void __stdcall -seterrno (const char *file, int line) -{ - seterrno_from_win_error (file, line, GetLastError ()); -} - -extern char *_user_strerror _PARAMS ((int)); - extern "C" { -const NO_COPY char __declspec(dllexport) * const _sys_errlist[]= +const char __declspec(dllexport) * _sys_errlist[] NO_COPY_INIT = { /* NOERROR 0 */ "No error", /* EPERM 1 */ "Operation not permitted", @@ -295,9 +260,43 @@ const NO_COPY char __declspec(dllexport) * const _sys_errlist[]= /* EOVERFLOW 139 */ "Value too large for defined data type" }; -extern const int NO_COPY __declspec(dllexport) _sys_nerr = sizeof (_sys_errlist) / sizeof (_sys_errlist[0]); +int NO_COPY_INIT _sys_nerr = sizeof (_sys_errlist) / sizeof (_sys_errlist[0]); }; +int __stdcall +geterrno_from_win_error (DWORD code, int deferrno) +{ + for (int i = 0; errmap[i].w != 0; ++i) + if (code == errmap[i].w) + { + syscall_printf ("windows error %u == errno %d", code, errmap[i].e); + return errmap[i].e; + } + + syscall_printf ("unknown windows error %u, setting errno to %d", code, + deferrno); + return deferrno; /* FIXME: what's so special about EACCESS? */ +} + +/* seterrno_from_win_error: Given a Windows error code, set errno + as appropriate. */ +void __stdcall +seterrno_from_win_error (const char *file, int line, DWORD code) +{ + syscall_printf ("%s:%d windows error %d", file, line, code); + set_errno (geterrno_from_win_error (code, EACCES)); + return; +} + +/* seterrno: Set `errno' based on GetLastError (). */ +void __stdcall +seterrno (const char *file, int line) +{ + seterrno_from_win_error (file, line, GetLastError ()); +} + +extern char *_user_strerror _PARAMS ((int)); + /* FIXME: Why is strerror() a long switch and not just: return sys_errlist[errnum]; (or moral equivalent). @@ -681,7 +680,11 @@ strerror (int errnum) error = "Value too large for defined data type"; break; default: +#ifdef _MT_SAFE char *buf= _reent_winsup ()->_strerror_buf; +#else + static NO_COPY char buf[20]; +#endif __small_sprintf (buf, "error %d", errnum); error = buf; break; diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index 4a38a8e4c3a..3c8bf39c99f 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -10,7 +10,6 @@ details. */ #include "winsup.h" #include <imagehlp.h> -#include <errno.h> #include <stdlib.h> #include "exceptions.h" @@ -154,7 +153,7 @@ error_start_init (const char *buf) for (char *p = strchr (pgm, '\\'); p; p = strchr (p, '\\')) *p = '/'; - __small_sprintf (debugger_command, "%s %s", buf, pgm); + __small_sprintf (debugger_command, "%s \"%s\"", buf, pgm); } static void @@ -932,7 +931,13 @@ ctrl_c_handler (DWORD type) is shut down or console window is closed. */ if (type == CTRL_SHUTDOWN_EVENT) { +#if 0 + /* Don't send a signal. Only NT service applications and their child + processes will receive this event and the services typically already + handle the shutdown action when getting the SERVICE_CONTROL_SHUTDOWN + control message. */ sig_send (NULL, SIGTERM); +#endif return FALSE; } if (type == CTRL_CLOSE_EVENT) diff --git a/winsup/cygwin/exec.cc b/winsup/cygwin/exec.cc index af345be99fe..d7c2ee1c271 100644 --- a/winsup/cygwin/exec.cc +++ b/winsup/cygwin/exec.cc @@ -12,7 +12,6 @@ details. */ #include "winsup.h" #include <unistd.h> #include <stdlib.h> -#include <errno.h> #include <process.h> #include "perprocess.h" #include "security.h" diff --git a/winsup/cygwin/external.cc b/winsup/cygwin/external.cc index c1a829adcc3..49e430518b6 100644 --- a/winsup/cygwin/external.cc +++ b/winsup/cygwin/external.cc @@ -11,7 +11,6 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #include "winsup.h" -#include <errno.h> #include "security.h" #include "sigproc.h" #include "pinfo.h" diff --git a/winsup/cygwin/fcntl.cc b/winsup/cygwin/fcntl.cc index f99dd2d2b7c..b1afb57d38e 100644 --- a/winsup/cygwin/fcntl.cc +++ b/winsup/cygwin/fcntl.cc @@ -10,7 +10,6 @@ details. */ #include "winsup.h" #include <stdarg.h> -#include <errno.h> #include <unistd.h> #include "security.h" #include "path.h" diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc index ab5e4b8f62e..253fca6fc47 100644 --- a/winsup/cygwin/fhandler.cc +++ b/winsup/cygwin/fhandler.cc @@ -9,7 +9,6 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #include "winsup.h" -#include <errno.h> #include <unistd.h> #include <stdlib.h> #include <sys/cygwin.h> @@ -600,7 +599,7 @@ fhandler_base::write (const void *ptr, size_t len) if (current_position > actual_length) { if ((get_fs_flags (FILE_SUPPORTS_SPARSE_FILES)) - && current_position >= actual_length + (64 * 1024)) + && current_position >= actual_length + (128 * 1024)) { /* If the file systemn supports sparse files and the application is writing after a long seek beyond EOF, convert the file to diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index d3b0f5dec61..2ee82fcf95a 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -20,8 +20,7 @@ enum FH_WBINSET = 0x00010000, /* binary write mode has been explicitly set */ FH_APPEND = 0x00020000, /* always append */ FH_ASYNC = 0x00040000, /* async I/O */ - FH_SIGCLOSE = 0x00080000, /* signal handler should close fd on interrupt */ - + FH_ENC = 0x00080000, /* native path is encoded */ FH_SYMLINK = 0x00100000, /* is a symlink */ FH_EXECABL = 0x00200000, /* file looked like it would run: * ends in .exe or .bat or begins with #! */ @@ -200,6 +199,9 @@ class fhandler_base bool get_need_fork_fixup () { return FHISSETF (FFIXUP); } void set_need_fork_fixup () { FHSETF (FFIXUP); } + bool get_encoded () { return FHISSETF (ENC);} + void set_encoded () { FHSETF (ENC);} + virtual void set_close_on_exec (int val); virtual void fixup_before_fork_exec (DWORD) {} @@ -387,6 +389,7 @@ class fhandler_socket: public fhandler_base bool is_connect_pending () const {return had_connect_or_listen == CONNECT_PENDING;} bool is_connected () const {return had_connect_or_listen == CONNECTED;} void set_connect_state (int newstate) { had_connect_or_listen = newstate; } + int get_connect_state () const { return had_connect_or_listen; } int bind (const struct sockaddr *name, int namelen); int connect (const struct sockaddr *name, int namelen); diff --git a/winsup/cygwin/fhandler_clipboard.cc b/winsup/cygwin/fhandler_clipboard.cc index 3f72703b32c..3f24094024e 100644 --- a/winsup/cygwin/fhandler_clipboard.cc +++ b/winsup/cygwin/fhandler_clipboard.cc @@ -13,7 +13,6 @@ details. */ #include "winsup.h" #include <stdio.h> #include <stdlib.h> -#include <errno.h> #include <unistd.h> #include <windows.h> #include <wingdi.h> diff --git a/winsup/cygwin/fhandler_console.cc b/winsup/cygwin/fhandler_console.cc index a76cfb0cdc5..9409cddd4ee 100644 --- a/winsup/cygwin/fhandler_console.cc +++ b/winsup/cygwin/fhandler_console.cc @@ -12,7 +12,6 @@ details. */ #include <sys/termios.h> #include <stdio.h> #include <stdlib.h> -#include <errno.h> #include <unistd.h> #include <wingdi.h> #include <winuser.h> diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc index 7e6d033757f..d97b5dc63eb 100644 --- a/winsup/cygwin/fhandler_disk_file.cc +++ b/winsup/cygwin/fhandler_disk_file.cc @@ -9,7 +9,6 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #include "winsup.h" -#include <errno.h> #include <unistd.h> #include <stdlib.h> #include <sys/cygwin.h> @@ -627,6 +626,8 @@ fhandler_disk_file::opendir () res = dir; } + if (real_name.isencoded ()) + set_encoded (); } syscall_printf ("%p = opendir (%s)", res, get_name ()); @@ -653,9 +654,7 @@ fhandler_disk_file::readdir (DIR *dir) } } else if (dir->__d_u.__d_data.__handle == INVALID_HANDLE_VALUE) - { - return res; - } + return res; else if (!FindNextFileA (dir->__d_u.__d_data.__handle, &buf)) { DWORD lasterr = GetLastError (); @@ -670,7 +669,10 @@ fhandler_disk_file::readdir (DIR *dir) } /* We get here if `buf' contains valid data. */ - strcpy (dir->__d_dirent->d_name, buf.cFileName); + if (get_encoded ()) + (void) fnunmunge (dir->__d_dirent->d_name, buf.cFileName); + else + strcpy (dir->__d_dirent->d_name, buf.cFileName); /* Check for Windows shortcut. If it's a Cygwin or U/WIN symlink, drop the .lnk suffix. */ diff --git a/winsup/cygwin/fhandler_dsp.cc b/winsup/cygwin/fhandler_dsp.cc index f961ec99bdf..3c577a89e34 100644 --- a/winsup/cygwin/fhandler_dsp.cc +++ b/winsup/cygwin/fhandler_dsp.cc @@ -12,7 +12,6 @@ details. */ #include "winsup.h" #include <stdio.h> -#include <errno.h> #include <windows.h> #include <sys/soundcard.h> #include <mmsystem.h> diff --git a/winsup/cygwin/fhandler_floppy.cc b/winsup/cygwin/fhandler_floppy.cc index dbf603c9f2d..1b8cccf7e9a 100644 --- a/winsup/cygwin/fhandler_floppy.cc +++ b/winsup/cygwin/fhandler_floppy.cc @@ -11,7 +11,6 @@ details. */ #include "winsup.h" #include <sys/termios.h> -#include <errno.h> #include <unistd.h> #include <winioctl.h> #include <asm/socket.h> diff --git a/winsup/cygwin/fhandler_mem.cc b/winsup/cygwin/fhandler_mem.cc index 243986e4be7..883412f2f7f 100644 --- a/winsup/cygwin/fhandler_mem.cc +++ b/winsup/cygwin/fhandler_mem.cc @@ -9,7 +9,6 @@ details. */ #include "winsup.h" -#include <errno.h> #include <unistd.h> #include <sys/mman.h> #include <ntdef.h> diff --git a/winsup/cygwin/fhandler_proc.cc b/winsup/cygwin/fhandler_proc.cc index 2ab9fad26bc..081fcf53771 100644 --- a/winsup/cygwin/fhandler_proc.cc +++ b/winsup/cygwin/fhandler_proc.cc @@ -11,7 +11,6 @@ details. */ #define _WIN32_WINNT 0x0501 #include "winsup.h" -#include <errno.h> #include <unistd.h> #include <stdlib.h> #include <sys/cygwin.h> diff --git a/winsup/cygwin/fhandler_process.cc b/winsup/cygwin/fhandler_process.cc index 1c46f6f49db..ca48352cd5c 100644 --- a/winsup/cygwin/fhandler_process.cc +++ b/winsup/cygwin/fhandler_process.cc @@ -9,7 +9,6 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #include "winsup.h" -#include <errno.h> #include <unistd.h> #include <stdlib.h> #include <sys/cygwin.h> diff --git a/winsup/cygwin/fhandler_random.cc b/winsup/cygwin/fhandler_random.cc index 257228a9513..55953348f6e 100644 --- a/winsup/cygwin/fhandler_random.cc +++ b/winsup/cygwin/fhandler_random.cc @@ -11,7 +11,6 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #include "winsup.h" -#include <errno.h> #include <limits.h> #include "cygerrno.h" #include "security.h" diff --git a/winsup/cygwin/fhandler_raw.cc b/winsup/cygwin/fhandler_raw.cc index 302af884717..9266290a668 100644 --- a/winsup/cygwin/fhandler_raw.cc +++ b/winsup/cygwin/fhandler_raw.cc @@ -10,7 +10,6 @@ #include "winsup.h" #include <sys/termios.h> -#include <errno.h> #include <unistd.h> #include <cygwin/rdevio.h> diff --git a/winsup/cygwin/fhandler_registry.cc b/winsup/cygwin/fhandler_registry.cc index ea193b836e0..91370147670 100644 --- a/winsup/cygwin/fhandler_registry.cc +++ b/winsup/cygwin/fhandler_registry.cc @@ -11,7 +11,6 @@ details. */ /* FIXME: Access permissions are ignored at the moment. */ #include "winsup.h" -#include <errno.h> #include <unistd.h> #include <stdlib.h> #include <sys/cygwin.h> diff --git a/winsup/cygwin/fhandler_serial.cc b/winsup/cygwin/fhandler_serial.cc index eec4735e1ec..45c3cc1bff3 100644 --- a/winsup/cygwin/fhandler_serial.cc +++ b/winsup/cygwin/fhandler_serial.cc @@ -9,7 +9,6 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #include "winsup.h" -#include <errno.h> #include <unistd.h> #include <stdlib.h> #include "cygerrno.h" diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc index 6a163b6644c..3dc16902598 100644 --- a/winsup/cygwin/fhandler_socket.cc +++ b/winsup/cygwin/fhandler_socket.cc @@ -13,7 +13,6 @@ #define __INSIDE_CYGWIN_NET__ #include "winsup.h" -#include <errno.h> #include <sys/socket.h> #include <sys/un.h> #include <sys/uio.h> @@ -328,6 +327,7 @@ fhandler_socket::dup (fhandler_base *child) if (get_addr_family () == AF_LOCAL) fhs->set_sun_path (get_sun_path ()); fhs->set_socket_type (get_socket_type ()); + fhs->set_connect_state (get_connect_state ()); if (winsock2_active) { @@ -338,12 +338,10 @@ fhandler_socket::dup (fhandler_base *child) If WSADuplicateSocket() still fails for some reason, we fall back to DuplicateHandle(). */ WSASetLastError (0); - if (cygheap->user.issetuid ()) - RevertToSelf (); + cygheap->user.deimpersonate (); fhs->set_io_handle (get_io_handle ()); fhs->fixup_before_fork_exec (GetCurrentProcessId ()); - if (cygheap->user.issetuid ()) - ImpersonateLoggedOnUser (cygheap->user.token); + cygheap->user.reimpersonate (); if (!WSAGetLastError ()) { fhs->fixup_after_fork (hMainProc); @@ -492,6 +490,7 @@ fhandler_socket::connect (const struct sockaddr *name, int namelen) BOOL in_progress = FALSE; sockaddr_in sin; int secret [4]; + DWORD err; if (!get_inet_addr (name, namelen, &sin, &namelen, secret)) return -1; @@ -504,12 +503,12 @@ fhandler_socket::connect (const struct sockaddr *name, int namelen) when called on a non-blocking socket. */ if (is_nonblocking () || is_connect_pending ()) { - DWORD err = WSAGetLastError (); + err = WSAGetLastError (); if (err == WSAEWOULDBLOCK || err == WSAEALREADY) - { - WSASetLastError (WSAEINPROGRESS); - in_progress = TRUE; - } + in_progress = TRUE; + + if (err == WSAEWOULDBLOCK) + WSASetLastError (WSAEINPROGRESS); else if (err == WSAEINVAL) WSASetLastError (WSAEISCONN); } @@ -546,7 +545,8 @@ fhandler_socket::connect (const struct sockaddr *name, int namelen) } } - if (WSAGetLastError () == WSAEINPROGRESS) + err = WSAGetLastError (); + if (err == WSAEINPROGRESS || err == WSAEALREADY) set_connect_state (CONNECT_PENDING); else set_connect_state (CONNECTED); diff --git a/winsup/cygwin/fhandler_tape.cc b/winsup/cygwin/fhandler_tape.cc index 4cbf868c2c9..e3efcd1f9f5 100644 --- a/winsup/cygwin/fhandler_tape.cc +++ b/winsup/cygwin/fhandler_tape.cc @@ -11,7 +11,6 @@ details. */ #include "winsup.h" #include <sys/termios.h> -#include <errno.h> #include <unistd.h> #include <sys/mtio.h> #include "cygerrno.h" diff --git a/winsup/cygwin/fhandler_termios.cc b/winsup/cygwin/fhandler_termios.cc index cd4fafff0e7..89d883c681c 100644 --- a/winsup/cygwin/fhandler_termios.cc +++ b/winsup/cygwin/fhandler_termios.cc @@ -12,7 +12,6 @@ details. */ #include <sys/termios.h> #include <stdlib.h> #include <unistd.h> -#include <errno.h> #include <ctype.h> #include "cygerrno.h" #include "security.h" diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc index 322b80a256b..3c88fcc97b5 100644 --- a/winsup/cygwin/fhandler_tty.cc +++ b/winsup/cygwin/fhandler_tty.cc @@ -14,7 +14,6 @@ details. */ #include <stdio.h> #include <unistd.h> #include <stdlib.h> -#include <errno.h> #include <ctype.h> #include <limits.h> #include "cygerrno.h" @@ -508,9 +507,11 @@ fhandler_tty_slave::open (int flags, mode_t) HANDLE from_master_local, to_master_local; - if (!wincap.has_security () || - cygserver_running == CYGSERVER_UNAVAIL || - !cygserver_attach_tty (&from_master_local, &to_master_local)) +#ifdef USE_CYGSERVER + if (!wincap.has_security () + || cygserver_running == CYGSERVER_UNAVAIL + || !cygserver_attach_tty (&from_master_local, &to_master_local)) +#endif { termios_printf ("cannot dup handles via server. using old method."); @@ -583,7 +584,8 @@ fhandler_tty_slave::close () { if (!output_done_event) { - fhandler_console::open_fhs--; + if (!--fhandler_console::open_fhs && myself->ctty == -1) + FreeConsole (); termios_printf ("decremented open_fhs %d", fhandler_console::open_fhs); } return fhandler_tty_common::close (); @@ -593,6 +595,9 @@ int fhandler_tty_slave::cygserver_attach_tty (LPHANDLE from_master_ptr, LPHANDLE to_master_ptr) { +#ifndef USE_CYGSERVER + return 0; +#else if (!from_master_ptr || !to_master_ptr) return 0; @@ -605,7 +610,9 @@ fhandler_tty_slave::cygserver_attach_tty (LPHANDLE from_master_ptr, *from_master_ptr = req.from_master (); *to_master_ptr = req.to_master (); + return 1; +#endif } void diff --git a/winsup/cygwin/fhandler_virtual.cc b/winsup/cygwin/fhandler_virtual.cc index baf8e79989a..aedaf018726 100644 --- a/winsup/cygwin/fhandler_virtual.cc +++ b/winsup/cygwin/fhandler_virtual.cc @@ -9,7 +9,6 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #include "winsup.h" -#include <errno.h> #include <unistd.h> #include <stdlib.h> #include <sys/cygwin.h> diff --git a/winsup/cygwin/fhandler_windows.cc b/winsup/cygwin/fhandler_windows.cc index 81972bf132b..4affbc6faf4 100644 --- a/winsup/cygwin/fhandler_windows.cc +++ b/winsup/cygwin/fhandler_windows.cc @@ -12,7 +12,6 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #include "winsup.h" -#include <errno.h> #include <wingdi.h> #include <winuser.h> #include "cygerrno.h" diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc index ac1708a6ea6..859bb64e342 100644 --- a/winsup/cygwin/fork.cc +++ b/winsup/cygwin/fork.cc @@ -13,7 +13,6 @@ details. */ #include <unistd.h> #include <stdlib.h> #include <stdarg.h> -#include <errno.h> #include "security.h" #include "path.h" #include "fhandler.h" @@ -237,14 +236,7 @@ fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls) /* Restore the inheritance state as in parent Don't call setuid here! The flags are already set. */ - if (cygheap->user.impersonated) - { - debug_printf ("Impersonation of child, token: %d", cygheap->user.token); - if (cygheap->user.token == INVALID_HANDLE_VALUE) - RevertToSelf (); // probably not needed - else if (!ImpersonateLoggedOnUser (cygheap->user.token)) - system_printf ("Impersonate for forked child failed: %E"); - } + cygheap->user.reimpersonate (); sync_with_parent ("after longjmp.", TRUE); sigproc_printf ("hParent %p, child 1 first_dll %p, load_dlls %d", hParent, @@ -306,8 +298,10 @@ fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls) (void) ForceCloseHandle1 (fork_info->subproc_ready, subproc_ready); (void) ForceCloseHandle1 (fork_info->forker_finished, forker_finished); +#ifdef USE_CYGSERVER if (fixup_shms_after_fork ()) api_fatal ("recreate_shm areas after fork failed"); +#endif pinfo_fixup_after_fork (); signal_fixup_after_fork (); @@ -437,8 +431,7 @@ fork_parent (HANDLE& hParent, dll *&first_dll, si.cbReserved2 = sizeof (ch); /* Remove impersonation */ - if (cygheap->user.issetuid ()) - RevertToSelf (); + cygheap->user.deimpersonate (); ch.parent = hParent; #ifdef DEBUGGING @@ -486,8 +479,7 @@ fork_parent (HANDLE& hParent, dll *&first_dll, ForceCloseHandle (subproc_ready); ForceCloseHandle (forker_finished); /* Restore impersonation */ - if (cygheap->user.issetuid ()) - ImpersonateLoggedOnUser (cygheap->user.token); + cygheap->user.reimpersonate (); cygheap_setup_for_child_cleanup (newheap, &ch, 0); return -1; } @@ -514,8 +506,7 @@ fork_parent (HANDLE& hParent, dll *&first_dll, strcpy (forked->progname, myself->progname); /* Restore impersonation */ - if (cygheap->user.issetuid ()) - ImpersonateLoggedOnUser (cygheap->user.token); + cygheap->user.reimpersonate (); ProtectHandle (pi.hThread); /* Protect the handle but name it similarly to the way it will diff --git a/winsup/cygwin/grp.cc b/winsup/cygwin/grp.cc index f4df7580d73..6e34a3a19bf 100644 --- a/winsup/cygwin/grp.cc +++ b/winsup/cygwin/grp.cc @@ -16,7 +16,6 @@ details. */ #include <wininet.h> #include <stdio.h> #include <stdlib.h> -#include <errno.h> #include "pinfo.h" #include "security.h" #include "path.h" @@ -262,7 +261,7 @@ internal_getgroups (int gidsetsize, __gid32_t *grouplist, cygpsid * srchsid) { /* If impersonated, use impersonation token. */ if (cygheap->user.issetuid ()) - hToken = cygheap->user.token; + hToken = cygheap->user.token (); else if (!OpenProcessToken (hMainProc, TOKEN_QUERY, &hToken)) hToken = NULL; } @@ -296,7 +295,7 @@ internal_getgroups (int gidsetsize, __gid32_t *grouplist, cygpsid * srchsid) ++cnt; if (gidsetsize && cnt > gidsetsize) { - if (hToken != cygheap->user.token) + if (!cygheap->user.issetuid ()) CloseHandle (hToken); goto error; } @@ -306,7 +305,7 @@ internal_getgroups (int gidsetsize, __gid32_t *grouplist, cygpsid * srchsid) } else debug_printf ("%d = GetTokenInformation(NULL) %E", size); - if (hToken != cygheap->user.token) + if (!cygheap->user.issetuid ()) CloseHandle (hToken); return cnt; } diff --git a/winsup/cygwin/heap.cc b/winsup/cygwin/heap.cc index ae8a9d0a7b2..d6f0452e2c6 100644 --- a/winsup/cygwin/heap.cc +++ b/winsup/cygwin/heap.cc @@ -9,7 +9,6 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #include "winsup.h" -#include <errno.h> #include "cygerrno.h" #include "sigproc.h" #include "pinfo.h" diff --git a/winsup/cygwin/include/cygwin/config.h b/winsup/cygwin/include/cygwin/config.h index 77815a071ff..e3e09f051ae 100644 --- a/winsup/cygwin/include/cygwin/config.h +++ b/winsup/cygwin/include/cygwin/config.h @@ -19,6 +19,7 @@ extern "C" { #endif #define _CYGWIN_CONFIG_H +#define __DYNAMIC_REENT__ #define __FILENAME_MAX__ (260 - 1 /* NUL */) #define _READ_WRITE_RETURN_TYPE _ssize_t #define __LARGE64_FILES 1 diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h index cd49fa58952..13657a078f3 100644 --- a/winsup/cygwin/include/cygwin/version.h +++ b/winsup/cygwin/include/cygwin/version.h @@ -205,12 +205,15 @@ details. */ underscore. No problems with backward compatibility since no official release has been made so far. This change removes exported symbols like fopen64, which might confuse configure. + 86: Export ftok + 87: Export vsyslog + 88: Export _getreent */ /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */ #define CYGWIN_VERSION_API_MAJOR 0 -#define CYGWIN_VERSION_API_MINOR 85 +#define CYGWIN_VERSION_API_MINOR 88 /* There is also a compatibity version number associated with the shared memory regions. It is incremented when incompatible diff --git a/winsup/cygwin/include/sys/syslog.h b/winsup/cygwin/include/sys/syslog.h new file mode 100644 index 00000000000..a37b042d722 --- /dev/null +++ b/winsup/cygwin/include/sys/syslog.h @@ -0,0 +1,86 @@ +/* sys/syslog.h + + Copyright 1996, 1998, 2001 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 _SYS_LOG_H +#define _SYS_LOG_H + +#include <sys/cdefs.h> +#include <stdarg.h> + +#define LOG_EMERG 0 +#define LOG_ALERT 1 +#define LOG_CRIT 2 +#define LOG_ERR 3 +#define LOG_WARNING 4 +#define LOG_NOTICE 5 +#define LOG_INFO 6 +#define LOG_DEBUG 7 + +#define LOG_PRIMASK 0x07 + +#define LOG_PRI(p) ((p) & LOG_PRIMASK) +#define LOG_MAKEPRI(fac, pri) (((fac) << 3) | (pri)) + +#define LOG_KERN (0<<3) +#define LOG_USER (1<<3) +#define LOG_MAIL (2<<3) +#define LOG_DAEMON (3<<3) +#define LOG_AUTH (4<<3) +#define LOG_SYSLOG (5<<3) +#define LOG_LPR (6<<3) +#define LOG_NEWS (7<<3) +#define LOG_UUCP (8<<3) +#define LOG_CRON (9<<3) +#define LOG_AUTHPRIV (10<<3) +#define LOG_FTP (11<<3) + +/* Codes through 15 are reserved for system use */ +#define LOG_LOCAL0 (16<<3) +#define LOG_LOCAL1 (17<<3) +#define LOG_LOCAL2 (18<<3) +#define LOG_LOCAL3 (19<<3) +#define LOG_LOCAL4 (20<<3) +#define LOG_LOCAL5 (21<<3) +#define LOG_LOCAL6 (22<<3) +#define LOG_LOCAL7 (23<<3) + +#define LOG_NFACILITIES 24 +#define LOG_FACMASK 0x03f8 +#define LOG_FAC(p) (((p) & LOG_FACMASK) >> 3) + +#define LOG_MASK(pri) (1 << (pri)) +#define LOG_UPTO(pri) ((1 << ((pri)+1)) - 1) + +/* + * Option flags for openlog. + * + * LOG_ODELAY no longer does anything. + * LOG_NDELAY is the inverse of what it used to be. + */ +#define LOG_PID 0x01 /* log the pid with each message */ +#define LOG_CONS 0x02 /* log on the console if errors in sending */ +#define LOG_ODELAY 0x04 /* delay open until first syslog() (default) */ +#define LOG_NDELAY 0x08 /* don't delay open */ +#define LOG_NOWAIT 0x10 /* don't wait for console forks: DEPRECATED */ +#define LOG_PERROR 0x20 /* log to stderr as well */ + +__BEGIN_DECLS + + +void closelog (void); +void openlog (const char *, int, int); +int setlogmask (int); +void syslog (int, const char *, ...); +void vsyslog (int, const char *, va_list ap); + +__END_DECLS + + +#endif /* _SYS_LOG_H */ diff --git a/winsup/cygwin/ioctl.cc b/winsup/cygwin/ioctl.cc index 5d9ec87d0cb..39917902d83 100644 --- a/winsup/cygwin/ioctl.cc +++ b/winsup/cygwin/ioctl.cc @@ -13,7 +13,6 @@ details. */ #include "winsup.h" #include <sys/ioctl.h> -#include <errno.h> #include "cygerrno.h" #include "security.h" #include "path.h" diff --git a/winsup/cygwin/malloc_wrapper.cc b/winsup/cygwin/malloc_wrapper.cc index 9841cd528b6..5798cf41742 100644 --- a/winsup/cygwin/malloc_wrapper.cc +++ b/winsup/cygwin/malloc_wrapper.cc @@ -18,7 +18,6 @@ details. */ #include "path.h" #include "fhandler.h" #include "dtable.h" -#include <errno.h> #include "cygerrno.h" #include "cygheap.h" #include "heap.h" diff --git a/winsup/cygwin/mmap.cc b/winsup/cygwin/mmap.cc index 6cf8cc7df8f..08f89c84f4c 100644 --- a/winsup/cygwin/mmap.cc +++ b/winsup/cygwin/mmap.cc @@ -13,7 +13,6 @@ details. */ #include <stdlib.h> #include <stddef.h> #include <sys/mman.h> -#include <errno.h> #include "security.h" #include "path.h" #include "fhandler.h" @@ -272,7 +271,8 @@ public: void erase (int i); void erase (); mmap_record *match (_off64_t off, DWORD len); - long match (caddr_t addr, DWORD len, long start); + long match (caddr_t addr, DWORD len, caddr_t &m_addr, DWORD &m_len, + long start); }; list::list () @@ -325,13 +325,24 @@ list::match (_off64_t off, DWORD len) /* Used in munmap() */ long -list::match (caddr_t addr, DWORD len, _off_t start) +list::match (caddr_t addr, DWORD len, caddr_t &m_addr, DWORD &m_len, + _off_t start) { + caddr_t low, high; + for (int i = start + 1; i < nrecs; ++i) - if (addr >= recs[i].get_address () - && addr + len <= recs[i].get_address () - + (PAGE_CNT (recs[i].get_size ()) * getpagesize ())) - return i; + { + low = (addr >= recs[i].get_address ()) ? addr : recs[i].get_address (); + high = recs[i].get_address () + + (PAGE_CNT (recs[i].get_size ()) * getpagesize ()); + high = (addr + len < high) ? addr + len : high; + if (low < high) + { + m_addr = low; + m_len = high - low; + return i; + } + } return -1; } @@ -440,7 +451,7 @@ mmap64 (caddr_t addr, size_t len, int prot, int flags, int fd, _off64_t off) if (off % getpagesize () || (!(flags & MAP_SHARED) && !(flags & MAP_PRIVATE)) || ((flags & MAP_SHARED) && (flags & MAP_PRIVATE)) - || ((flags & MAP_FIXED) && ((DWORD)addr % granularity)) + || ((flags & MAP_FIXED) && ((DWORD)addr % getpagesize ())) || !len) { set_errno (EINVAL); @@ -471,8 +482,6 @@ mmap64 (caddr_t addr, size_t len, int prot, int flags, int fd, _off64_t off) DWORD gran_len = howmany (off + len, granularity) * granularity - gran_off; fhandler_base *fh; - caddr_t base = addr; - HANDLE h; if (fd != -1) { @@ -490,6 +499,16 @@ mmap64 (caddr_t addr, size_t len, int prot, int flags, int fd, _off64_t off) DWORD high; DWORD low = GetFileSize (fh->get_handle (), &high); _off64_t fsiz = ((_off64_t)high << 32) + low; + /* Don't allow mappings beginning beyond EOF since Windows can't + handle that POSIX like. FIXME: Still looking for a good idea + to allow that nevertheless. */ + if (gran_off >= fsiz) + { + set_errno (ENXIO); + ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, + "mmap"); + return MAP_FAILED; + } fsiz -= gran_off; if (gran_len > fsiz) gran_len = fsiz; @@ -542,7 +561,13 @@ mmap64 (caddr_t addr, size_t len, int prot, int flags, int fd, _off64_t off) && (wincap.has_working_copy_on_write () || fd != -1)) access = FILE_MAP_COPY; - h = fh->mmap (&base, gran_len, access, flags, gran_off); + caddr_t base = addr; + /* This shifts the base address to the next lower 64K boundary. + The offset is re-added when evaluating the return value. */ + if (base) + base -= off - gran_off; + + HANDLE h = fh->mmap (&base, gran_len, access, flags, gran_off); if (h == INVALID_HANDLE_VALUE) { @@ -589,16 +614,16 @@ mmap (caddr_t addr, size_t len, int prot, int flags, int fd, _off_t off) return mmap64 (addr, len, prot, flags, fd, (_off64_t)off); } -/* munmap () removes an mmapped area. It insists that base area - requested is the same as that mmapped, error if not. */ +/* munmap () removes all mmapped pages between addr and addr+len. */ extern "C" int munmap (caddr_t addr, size_t len) { syscall_printf ("munmap (addr %x, len %d)", addr, len); - /* Error conditions according to SUSv2 */ - if (((DWORD)addr % getpagesize ()) || !len) + /* Error conditions according to SUSv3 */ + if (!addr || ((DWORD)addr % getpagesize ()) || !len + || IsBadReadPtr (addr, len)) { set_errno (EINVAL); syscall_printf ("-1 = munmap(): Invalid parameters"); @@ -606,17 +631,15 @@ munmap (caddr_t addr, size_t len) } SetResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "munmap"); - /* Check if a mmap'ed area was ever created */ if (mmapped_areas == NULL) { syscall_printf ("-1 = munmap(): mmapped_areas == NULL"); - set_errno (EINVAL); ReleaseResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "munmap"); - return -1; + return 0; } - /* Iterate through the map, looking for the mmapped area. - Error if not found. */ + /* Iterate through the map, unmap pages between addr and addr+len + in all maps. */ for (int it = 0; it < mmapped_areas->nlists; ++it) { @@ -624,10 +647,13 @@ munmap (caddr_t addr, size_t len) if (map_list) { long li = -1; - if ((li = map_list->match(addr, len, li)) >= 0) + caddr_t u_addr; + DWORD u_len; + + while ((li = map_list->match(addr, len, u_addr, u_len, li)) >= 0) { mmap_record *rec = map_list->recs + li; - if (rec->unmap_map (addr, len)) + if (rec->unmap_map (u_addr, u_len)) { fhandler_base *fh = rec->alloc_fh (); fh->munmap (rec->get_handle (), addr, len); @@ -636,18 +662,13 @@ munmap (caddr_t addr, size_t len) /* Delete the entry. */ map_list->erase (li); } - syscall_printf ("0 = munmap(): %x", addr); - ReleaseResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "munmap"); - return 0; } } } - set_errno (EINVAL); - syscall_printf ("-1 = munmap(): EINVAL"); - ReleaseResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, "munmap"); - return -1; + syscall_printf ("0 = munmap(): %x", addr); + return 0; } /* Sync file with memory. Ignore flags for now. */ @@ -815,9 +836,15 @@ fhandler_disk_file::mmap (caddr_t *addr, size_t len, DWORD access, } DWORD high = off >> 32, low = off & 0xffffffff; - void *base = MapViewOfFileEx (h, access, high, low, len, - (flags & MAP_FIXED) ? *addr : NULL); - debug_printf ("%x = MapViewOfFileEx (h:%x, access:%x, 0, off:%D, len:%d, addr:%x)", base, h, access, off, len, (flags & MAP_FIXED) ? *addr : NULL); + void *base = NULL; + /* If a non-zero address is given, try mapping using the given address first. + If it fails and flags is not MAP_FIXED, try again with NULL address. */ + if (*addr) + base = MapViewOfFileEx (h, access, high, low, len, *addr); + if (!base && !(flags & MAP_FIXED)) + base = MapViewOfFileEx (h, access, high, low, len, NULL); + debug_printf ("%x = MapViewOfFileEx (h:%x, access:%x, 0, off:%D, " + "len:%d, addr:%x)", base, h, access, off, len, *addr); if (!base || ((flags & MAP_FIXED) && base != *addr)) { if (!base) diff --git a/winsup/cygwin/msg.cc b/winsup/cygwin/msg.cc new file mode 100644 index 00000000000..fecaa068a62 --- /dev/null +++ b/winsup/cygwin/msg.cc @@ -0,0 +1,47 @@ +/* msg.cc: Single unix specification IPC interface for Cygwin. + + Copyright 2002 Red Hat, Inc. + + Written by Conrad Scott <conrad.scott@dsl.pipex.com>. + +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 <sys/types.h> +#include <cygwin/msg.h> + + +#include "cygerrno.h" + +extern "C" int +msgctl (int msqid, int cmd, struct msqid_ds *buf) +{ + set_errno (ENOSYS); + return -1; +} + +extern "C" int +msgget (key_t key, int msgflg) +{ + set_errno (ENOSYS); + return -1; +} + +extern "C" ssize_t +msgrcv (int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg) +{ + set_errno (ENOSYS); + return -1; +} + +extern "C" int +msgsnd (int msqid, const void *msgp, size_t msgsz, int msgflg) +{ + set_errno (ENOSYS); + return -1; +} diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc index fc4f5482c66..1d1abab7659 100644 --- a/winsup/cygwin/net.cc +++ b/winsup/cygwin/net.cc @@ -13,7 +13,6 @@ details. */ #define __INSIDE_CYGWIN_NET__ #include "winsup.h" -#include <errno.h> #include <ctype.h> #include <sys/socket.h> #include <sys/un.h> @@ -1288,20 +1287,39 @@ getdomainname (char *domain, size_t len) if (__check_null_invalid_struct_errno (domain, len)) return -1; + PFIXED_INFO info = NULL; + ULONG size = 0; + + if (GetNetworkParams(info, &size) == ERROR_BUFFER_OVERFLOW + && (info = (PFIXED_INFO) alloca(size)) + && GetNetworkParams(info, &size) == ERROR_SUCCESS) + { + strncpy(domain, info->DomainName, len); + return 0; + } + + /* This is only used by Win95 and NT <= 4.0. + The registry names are language independent. + FIXME: Handle DHCP on Win95. The DhcpDomain(s) may be available + in ..VxD\DHCP\DhcpInfoXX\OptionInfo, RFC 1533 format */ + reg_key r (HKEY_LOCAL_MACHINE, KEY_READ, (!wincap.is_winnt ()) ? "System" : "SYSTEM", "CurrentControlSet", "Services", (!wincap.is_winnt ()) ? "VxD" : "Tcpip", (!wincap.is_winnt ()) ? "MSTCP" : "Parameters", NULL); - /* FIXME: Are registry keys case sensitive? */ - if (r.error () || r.get_string ("Domain", domain, len, "") != ERROR_SUCCESS) + if (!r.error ()) { - __seterrno (); - return -1; + int res1, res2 = 0; /* Suppress compiler warning */ + res1 = r.get_string ("Domain", domain, len, ""); + if (res1 != ERROR_SUCCESS || !domain[0]) + res2 = r.get_string ("DhcpDomain", domain, len, ""); + if (res1 == ERROR_SUCCESS || res2 == ERROR_SUCCESS) + return 0; } - - return 0; + __seterrno (); + return -1; } /* Fill out an ifconf struct. */ @@ -1972,7 +1990,10 @@ cygwin_rcmd (char **ahost, unsigned short inport, char *locuser, cygheap_fdnew res_fd; if (res_fd >= 0 && fdsock (res_fd, tcp_dev, res)) - res = res_fd; + { + ((fhandler_socket *) res_fd)->set_connect_state (CONNECTED); + res = res_fd; + } else { closesocket (res); @@ -1985,7 +2006,10 @@ cygwin_rcmd (char **ahost, unsigned short inport, char *locuser, cygheap_fdget fd (*fd2p); if (newfd >= 0 && fdsock (newfd, tcp_dev, fd2s)) - *fd2p = newfd; + { + *fd2p = newfd; + ((fhandler_socket *) fd2p)->set_connect_state (CONNECTED); + } else { closesocket (res); @@ -2048,7 +2072,10 @@ cygwin_rexec (char **ahost, unsigned short inport, char *locuser, cygheap_fdnew res_fd; if (res_fd >= 0 && fdsock (res_fd, tcp_dev, res)) - res = res_fd; + { + ((fhandler_socket *) res_fd)->set_connect_state (CONNECTED); + res = res_fd; + } else { closesocket (res); @@ -2061,7 +2088,10 @@ cygwin_rexec (char **ahost, unsigned short inport, char *locuser, cygheap_fdget fd (*fd2p); if (newfd >= 0 && fdsock (newfd, tcp_dev, fd2s)) - *fd2p = newfd; + { + ((fhandler_socket *) fd2p)->set_connect_state (CONNECTED); + *fd2p = newfd; + } else { closesocket (res); @@ -2234,6 +2264,7 @@ socketpair (int family, int type, int protocol, int *sb) ((fhandler_socket *) sb0)->set_sun_path (""); ((fhandler_socket *) sb0)->set_addr_family (family); ((fhandler_socket *) sb0)->set_socket_type (type); + ((fhandler_socket *) sb0)->set_connect_state (CONNECTED); cygheap_fdnew sb1 (sb0, false); @@ -2242,6 +2273,7 @@ socketpair (int family, int type, int protocol, int *sb) ((fhandler_socket *) sb1)->set_sun_path (""); ((fhandler_socket *) sb1)->set_addr_family (family); ((fhandler_socket *) sb1)->set_socket_type (type); + ((fhandler_socket *) sb1)->set_connect_state (CONNECTED); sb[0] = sb0; sb[1] = sb1; diff --git a/winsup/cygwin/ntea.cc b/winsup/cygwin/ntea.cc index 7ddff77707c..4841a4c9345 100644 --- a/winsup/cygwin/ntea.cc +++ b/winsup/cygwin/ntea.cc @@ -16,7 +16,7 @@ details. */ #include "security.h" /* Default to not using NTEA information */ -BOOL allow_ntea; +bool allow_ntea; /* From Windows NT DDK: diff --git a/winsup/cygwin/passwd.cc b/winsup/cygwin/passwd.cc index 38876d21710..01e9a6ba163 100644 --- a/winsup/cygwin/passwd.cc +++ b/winsup/cygwin/passwd.cc @@ -12,7 +12,6 @@ details. */ #include <stdlib.h> #include <pwd.h> #include <stdio.h> -#include <errno.h> #include "cygerrno.h" #include "security.h" #include "path.h" diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 60856f2e110..8947be723f1 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -53,7 +53,6 @@ details. */ #include <sys/mount.h> #include <mntent.h> #include <unistd.h> -#include <errno.h> #include <ctype.h> #include <winioctl.h> #include <wingdi.h> @@ -208,7 +207,7 @@ normalize_posix_path (const char *src, char *dst) syscall_printf ("src %s", src); - if (isdrive (src) || strpbrk (src, "\\:")) + if (isdrive (src)) { int err = normalize_win32_path (src, dst); if (!err && isdrive (dst)) @@ -513,7 +512,7 @@ path_conv::check (const char *src, unsigned opt, /* Scan path_copy from right to left looking either for a symlink or an actual existing file. If an existing file is found, just - return. If a symlink is found exit the for loop. + return. If a symlink is found, exit the for loop. Also: be careful to preserve the errno returned from symlink.check as the caller may need it. */ /* FIXME: Do we have to worry about multiple \'s here? */ @@ -1151,10 +1150,99 @@ set_flags (unsigned *flags, unsigned val) } } +char special_chars[] = + "\001" "\002" "\003" "\004" "\005" "\006" "\007" "\010" + "\011" "\012" "\013" "\014" "\015" "\016" "\017" "\020" + "\021" "\022" "\023" "\024" "\025" "\026" "\027" "\030" + "\031" "\032" "\033" "\034" "\035" "\036" "\037" + ":" "\\" "*" "?" "%" + "A" "B" "C" "D" "E" "F" "G" "H" + "I" "J" "K" "L" "M" "N" "O" "P" + "Q" "R" "S" "T" "U" "V" "W" "X" + "Y" "Z"; + +static inline char +special_char (const char *s) +{ + char *p = strechr (special_chars, *s); + if (*p == '%' && strlen (p) >= 3) + { + char hex[] = {s[1], s[2], '\0'}; + unsigned char c = strtoul (hex, &p, 16); + p = strechr (special_chars, c); + } + return *p; +} + +bool +fnunmunge (char *dst, const char *src) +{ + bool converted = false; + char c; + + while (*src) + if (*src != '%' || !(c = special_char (src))) + *dst++ = *src++; + else + { + converted = true; + *dst++ = c; + src += 3; + } + + *dst = *src; + return converted; +} + +/* Determines if name is "special". Assumes that name is empty or "absolute" */ +static int +special_name (const char *s) +{ + if (!*s) + return false; + + if (strpbrk (++s, special_chars)) + return !strncasematch (s, "%2f", 3); + + if (strcasematch (s, "nul") + || strcasematch (s, "aux") + || strcasematch (s, "prn")) + return -1; + if (!strncasematch (s, "com", 3) + && !strncasematch (s, "lpt", 3)) + return false; + char *p; + (void) strtol (s, &p, 10); + return -(*p == '\0'); +} + void mount_item::fnmunge (char *dst, const char *src) { - strcpy (dst, src); + int name_type; + if (!(flags & MOUNT_ENC) || !(name_type = special_name (src))) + strcpy (dst, src); + else + { + char *d = dst; + *d++ = *src++; + if (name_type < 0) + { + __small_sprintf (d, "%%%02x", (unsigned char) *src++); + d += 3; + } + + while (*src) + if (!special_char (src)) + *d++ = *src++; + else + { + __small_sprintf (d, "%%%02x", (unsigned char) *src++); + d += 3; + } + *d = *src; + } + backslashify (dst, dst, 0); } @@ -1181,7 +1269,7 @@ mount_item::build_win32 (char *dst, const char *src, unsigned *outflags, unsigne const char *p = src + real_posix_pathlen; if (*p == '/') /* nothing */; - else if ((isdrive (dst) && !dst[2]) || *p) + else if ((!(flags & MOUNT_ENC) && isdrive (dst) && !dst[2]) || *p) dst[n++] = '\\'; fnmunge (dst + n, p); } @@ -1234,22 +1322,6 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev, if (dst == NULL) goto out; /* Sanity check. */ - /* An MS-DOS spec has either a : or a \. If this is found, short - circuit most of the rest of this function. */ - if (strpbrk (src_path, ":\\") != NULL || slash_unc_prefix_p (src_path)) - { - debug_printf ("%s already win32", src_path); - rc = normalize_win32_path (src_path, dst); - if (rc) - { - debug_printf ("normalize_win32_path failed, rc %d", rc); - return rc; - } - - set_flags (flags, (unsigned) set_flags_from_win32_path (dst)); - goto out; - } - /* Normalize the path, taking out ../../ stuff, we need to do this so that we can move from one mounted directory to another with relative stuff. @@ -1349,16 +1421,21 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev, break; } - if (i >= nmounts) + if (i < nmounts) { - backslashify (pathbuf, dst, 0); /* just convert */ - set_flags (flags, PATH_BINARY); - chroot_ok = !cygheap->root.exists (); + mi->build_win32 (dst, pathbuf, flags, chroot_pathlen); + chroot_ok = true; } else { - mi->build_win32 (dst, pathbuf, flags, chroot_pathlen); - chroot_ok = true; + if (strpbrk (src_path, ":\\") != NULL || slash_unc_prefix_p (src_path)) + rc = normalize_win32_path (src_path, dst); + else + { + backslashify (pathbuf, dst, 0); /* just convert */ + set_flags (flags, PATH_BINARY); + } + chroot_ok = !cygheap->root.exists (); } if (!isvirtual_dev (dev.devn)) @@ -1522,6 +1599,12 @@ mount_info::conv_to_posix_path (const char *src_path, char *posix_path, const char *p = cygheap->root.unchroot (posix_path); memmove (posix_path, p, strlen (p) + 1); } + if (mi.flags & MOUNT_ENC) + { + char tmpbuf[MAX_PATH + 1]; + if (fnunmunge (tmpbuf, posix_path)) + strcpy (posix_path, tmpbuf); + } goto out; } @@ -1656,10 +1739,16 @@ mount_info::from_registry () /* FIXME: Need a mutex to avoid collisions with other tasks. */ int -mount_info::add_reg_mount (const char * native_path, const char * posix_path, unsigned mountflags) +mount_info::add_reg_mount (const char *native_path, const char *posix_path, unsigned mountflags) { int res = 0; + if (strchr (posix_path, '\\')) + { + set_errno (EINVAL); + goto err1; + } + /* Add the mount to the right registry location, depending on whether MOUNT_SYSTEM is set in the mount flags. */ if (!(mountflags & MOUNT_SYSTEM)) /* current_user mount */ @@ -1710,6 +1799,7 @@ mount_info::add_reg_mount (const char * native_path, const char * posix_path, un return 0; /* Success */ err: __seterrno_from_win_error (res); + err1: return -1; } @@ -2175,6 +2265,8 @@ fillout_mntent (const char *native_path, const char *posix_path, unsigned flags) strcat (_reent_winsup ()->mnt_opts, (char *) ",exec"); else if (flags & MOUNT_NOTEXEC) strcat (_reent_winsup ()->mnt_opts, (char *) ",noexec"); + if (flags & MOUNT_ENC) + strcat (_reent_winsup ()->mnt_opts, ",managed"); if ((flags & MOUNT_CYGDRIVE)) /* cygdrive */ strcat (_reent_winsup ()->mnt_opts, (char *) ",noumount"); @@ -2259,7 +2351,9 @@ mount (const char *win32_path, const char *posix_path, unsigned flags) { int res = -1; - if (flags & MOUNT_CYGDRIVE) /* normal mount */ + if (strpbrk (posix_path, "\\:")) + set_errno (EINVAL); + else if (flags & MOUNT_CYGDRIVE) /* normal mount */ { /* When flags include MOUNT_CYGDRIVE, take this to mean that we actually want to change the cygdrive prefix and flags @@ -3162,7 +3256,7 @@ chdir (const char *in_dir) return -1; } - const char *native_dir = path.get_win32 (); + const char *native_dir = path; /* Check to see if path translates to something like C:. If it does, append a \ to the native directory specification to diff --git a/winsup/cygwin/path.h b/winsup/cygwin/path.h index 9275bef066f..3f4fe34a949 100644 --- a/winsup/cygwin/path.h +++ b/winsup/cygwin/path.h @@ -59,6 +59,7 @@ enum path_types PATH_EXEC = MOUNT_EXEC, PATH_NOTEXEC = MOUNT_NOTEXEC, PATH_CYGWIN_EXEC = MOUNT_CYGWIN_EXEC, + PATH_ENC = MOUNT_ENC, PATH_ALL_EXEC = (PATH_CYGWIN_EXEC | PATH_EXEC), PATH_LNK = 0x01000000, PATH_TEXT = 0x02000000, @@ -108,6 +109,7 @@ class path_conv int has_symlinks () const {return path_flags & PATH_HAS_SYMLINKS;} int hasgood_inode () const {return path_flags & PATH_HASACLS;} // Not strictly correct int has_buggy_open () const {return path_flags & PATH_HASBUGGYOPEN;} + bool isencoded () {return path_flags & PATH_ENC;} int binmode () const { if (path_flags & PATH_BINARY) @@ -242,6 +244,8 @@ has_exec_chars (const char *buf, int len) int pathmatch (const char *path1, const char *path2) __attribute__ ((regparm (2))); int pathnmatch (const char *path1, const char *path2, int len) __attribute__ ((regparm (2))); +bool fnunmunge (char *, const char *) __attribute__ ((regparm (2))); + int path_prefix_p (const char *path1, const char *path2, int len1) __attribute__ ((regparm (3))); /* FIXME: Move to own include file eventually */ diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc index bd07e48a65e..e7eeb43c9fb 100644 --- a/winsup/cygwin/pinfo.cc +++ b/winsup/cygwin/pinfo.cc @@ -11,7 +11,6 @@ details. */ #include "winsup.h" #include <stdlib.h> #include <time.h> -#include <errno.h> #include <limits.h> #include <stdarg.h> #include "security.h" @@ -361,7 +360,7 @@ _pinfo::commune_send (DWORD code, ...) res.s = NULL; res.n = 0; - if (!pid || !this) + if (!pid || !this || (dwProcessId != (DWORD) pid && !pinfo (myself->dwProcessId))) { set_errno (ESRCH); goto err; diff --git a/winsup/cygwin/pipe.cc b/winsup/cygwin/pipe.cc index 50f5a4dcb48..a1e99b27e25 100644 --- a/winsup/cygwin/pipe.cc +++ b/winsup/cygwin/pipe.cc @@ -12,7 +12,6 @@ details. */ #include "winsup.h" #include <unistd.h> -#include <errno.h> #include <sys/socket.h> #include "cygerrno.h" #include "security.h" diff --git a/winsup/cygwin/poll.cc b/winsup/cygwin/poll.cc index 35d02a83da0..da650ff61cb 100644 --- a/winsup/cygwin/poll.cc +++ b/winsup/cygwin/poll.cc @@ -10,11 +10,11 @@ #define __INSIDE_CYGWIN_NET__ +#define FD_SETSIZE 16384 // lots of fds #include "winsup.h" #include <sys/time.h> #include <sys/poll.h> #include <sys/socket.h> -#include <errno.h> #include <stdlib.h> #define USE_SYS_TYPES_FD_SET #include <winsock2.h> diff --git a/winsup/cygwin/resource.cc b/winsup/cygwin/resource.cc new file mode 100644 index 00000000000..e87702babfa --- /dev/null +++ b/winsup/cygwin/resource.cc @@ -0,0 +1,188 @@ +/* resource.cc: getrusage () and friends. + + Copyright 1996, 1997, 1998, 2000, 2001, 2002 Red Hat, Inc. + + Written by Steve Chamberlain (sac@cygnus.com), Doug Evans (dje@cygnus.com), + Geoffrey Noer (noer@cygnus.com) of Cygnus Support. + Rewritten by Sergey S. Okhapkin (sos@prospect.com.ru) + +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 <limits.h> +#include "cygerrno.h" +#include "pinfo.h" +#include "psapi.h" + +/* add timeval values */ +static void +add_timeval (struct timeval *tv1, struct timeval *tv2) +{ + tv1->tv_sec += tv2->tv_sec; + tv1->tv_usec += tv2->tv_usec; + if (tv1->tv_usec >= 1000000) + { + tv1->tv_usec -= 1000000; + tv1->tv_sec++; + } +} + +/* add rusage values of r2 to r1 */ +void __stdcall +add_rusage (struct rusage *r1, struct rusage *r2) +{ + add_timeval (&r1->ru_utime, &r2->ru_utime); + add_timeval (&r1->ru_stime, &r2->ru_stime); + r1->ru_maxrss += r2->ru_maxrss; + r1->ru_ixrss += r2->ru_ixrss; + r1->ru_idrss += r2->ru_idrss; + r1->ru_isrss += r2->ru_isrss; + r1->ru_minflt += r2->ru_minflt; + r1->ru_majflt += r2->ru_majflt; + r1->ru_nswap += r2->ru_nswap; + r1->ru_inblock += r2->ru_inblock; + r1->ru_oublock += r2->ru_oublock; + r1->ru_msgsnd += r2->ru_msgsnd; + r1->ru_msgrcv += r2->ru_msgrcv; + r1->ru_nsignals += r2->ru_nsignals; + r1->ru_nvcsw += r2->ru_nvcsw; + r1->ru_nivcsw += r2->ru_nivcsw; +} + +/* FIXME: what about other fields? */ +void __stdcall +fill_rusage (struct rusage *r, HANDLE h) +{ + FILETIME creation_time = {0,0}; + FILETIME exit_time = {0,0}; + FILETIME kernel_time = {0,0}; + FILETIME user_time = {0,0}; + + struct timeval tv; + + memset (r, 0, sizeof (*r)); + GetProcessTimes (h, &creation_time, &exit_time, &kernel_time, &user_time); + totimeval (&tv, &kernel_time, 0, 0); + add_timeval (&r->ru_stime, &tv); + totimeval (&tv, &user_time, 0, 0); + add_timeval (&r->ru_utime, &tv); + + PROCESS_MEMORY_COUNTERS pmc; + + memset (&pmc, 0, sizeof (pmc)); + if (GetProcessMemoryInfo (h, &pmc, sizeof (pmc))) + { + r->ru_maxrss += (long) (pmc.WorkingSetSize /1024); + r->ru_majflt += pmc.PageFaultCount; + } +} + +extern "C" int +getrusage (int intwho, struct rusage *rusage_in) +{ + int res = 0; + struct rusage r; + + if (intwho == RUSAGE_SELF) + { + memset (&r, 0, sizeof (r)); + fill_rusage (&r, hMainProc); + *rusage_in = r; + } + else if (intwho == RUSAGE_CHILDREN) + *rusage_in = myself->rusage_children; + else + { + set_errno (EINVAL); + res = -1; + } + + syscall_printf ("%d = getrusage (%d, %p)", res, intwho, rusage_in); + return res; +} + +unsigned long rlim_core = RLIM_INFINITY; + +extern "C" int +getrlimit (int resource, struct rlimit *rlp) +{ + MEMORY_BASIC_INFORMATION m; + + if (check_null_invalid_struct_errno (rlp)) + return -1; + + rlp->rlim_cur = RLIM_INFINITY; + rlp->rlim_max = RLIM_INFINITY; + + switch (resource) + { + case RLIMIT_CPU: + case RLIMIT_FSIZE: + case RLIMIT_DATA: + break; + case RLIMIT_STACK: + if (!VirtualQuery ((LPCVOID) &m, &m, sizeof m)) + debug_printf ("couldn't get stack info, returning def.values. %E"); + else + { + rlp->rlim_cur = (DWORD) &m - (DWORD) m.AllocationBase; + rlp->rlim_max = (DWORD) m.BaseAddress + m.RegionSize + - (DWORD) m.AllocationBase; + } + break; + case RLIMIT_NOFILE: + rlp->rlim_cur = getdtablesize (); + break; + case RLIMIT_CORE: + rlp->rlim_cur = rlim_core; + break; + case RLIMIT_AS: + rlp->rlim_cur = 0x80000000UL; + rlp->rlim_max = 0x80000000UL; + break; + default: + set_errno (EINVAL); + return -1; + } + return 0; +} + +extern "C" int +setrlimit (int resource, const struct rlimit *rlp) +{ + if (__check_invalid_read_ptr_errno (rlp, sizeof (*rlp))) + return -1; + + struct rlimit oldlimits; + + // Check if the request is to actually change the resource settings. + // If it does not result in a change, take no action and do not + // fail. + if (getrlimit (resource, &oldlimits) < 0) + return -1; + + if (oldlimits.rlim_cur == rlp->rlim_cur && + oldlimits.rlim_max == rlp->rlim_max) + // No change in resource requirements, succeed immediately + return 0; + + switch (resource) + { + case RLIMIT_CORE: + rlim_core = rlp->rlim_cur; + break; + case RLIMIT_NOFILE: + if (rlp->rlim_cur != RLIM_INFINITY) + return setdtablesize (rlp->rlim_cur); + break; + default: + set_errno (EINVAL); + return -1; + } + return 0; +} diff --git a/winsup/cygwin/scandir.cc b/winsup/cygwin/scandir.cc new file mode 100644 index 00000000000..a2f682a50c5 --- /dev/null +++ b/winsup/cygwin/scandir.cc @@ -0,0 +1,99 @@ +/* scandir.cc + + Copyright 1998, 1999, 2000, 2001 Red Hat, Inc. + + Written by Corinna Vinschen <corinna.vinschen@cityweb.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 <dirent.h> +#include <stdlib.h> +#include "cygerrno.h" + +extern "C" int +alphasort (const struct dirent **a, const struct dirent **b) +{ + return strcoll ((*a)->d_name, (*b)->d_name); +} + +extern "C" int +scandir (const char *dir, + struct dirent ***namelist, + int (*select) (const struct dirent *), + int (*compar) (const struct dirent **, const struct dirent **)) +{ + DIR *dirp; + struct dirent *ent, *etmp, **nl = NULL, **ntmp; + int count = 0; + int allocated = 0; + + if (!(dirp = opendir (dir))) + return -1; + + int prior_errno = get_errno (); + set_errno (0); + if (!compar) + compar = alphasort; + + while ((ent = readdir (dirp))) + { + if (!select || select (ent)) + { + + /* Ignore error from readdir/select. See POSIX specs. */ + set_errno (0); + + if (count == allocated) + { + + if (allocated == 0) + allocated = 10; + else + allocated *= 2; + + ntmp = (struct dirent **) realloc (nl, allocated * sizeof *nl); + if (!ntmp) + { + set_errno (ENOMEM); + break; + } + nl = ntmp; + } + + if (!(etmp = (struct dirent *) malloc (sizeof *ent))) + { + set_errno (ENOMEM); + break; + } + *etmp = *ent; + nl[count++] = etmp; + } + } + + if ((prior_errno = get_errno ()) != 0) + { + closedir (dirp); + if (nl) + { + while (count > 0) + free (nl[--count]); + free (nl); + } + /* Ignore errors from closedir() and what not else. */ + set_errno (prior_errno); + return -1; + } + + closedir (dirp); + set_errno (prior_errno); + + qsort (nl, count, sizeof *nl, (int (*)(const void *, const void *)) compar); + if (namelist) + *namelist = nl; + return count; +} diff --git a/winsup/cygwin/sched.cc b/winsup/cygwin/sched.cc new file mode 100644 index 00000000000..b29d7a49e4e --- /dev/null +++ b/winsup/cygwin/sched.cc @@ -0,0 +1,443 @@ +/* sched.cc: scheduler interface for Cygwin + + Copyright 2001, 2002 Red Hat, Inc. + + Written by Robert Collins <rbtcollins@hotmail.com> + + 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. */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "winsup.h" +#include <limits.h> +#include "cygerrno.h" +#include <assert.h> +#include <stdlib.h> +#include <syslog.h> +#include <sched.h> +#include "pinfo.h" +/* for getpid */ +#include <unistd.h> + +/* Win32 priority to UNIX priority Mapping. + For now, I'm just following the spec: any range of priorities is ok. + There are probably many many issues with this... + + We don't want process's going realtime. Well, they probably could, but the issues + with avoiding the priority values 17-22 and 27-30 (not supported before win2k) + make that inefficient. + However to complicate things most unixes use lower is better priorities. + + So we map -14 to 15, and 15 to 1 via (16- ((n+16) >> 1)) + we then map 1 to 15 to various process class and thread priority combinations + + Then we need to look at the threads vi process priority. As win95 98 and NT 4 + Don't support opening threads cross-process (unless a thread HANDLE is passed around) + for now, we'll just use the priority class. + + The code and logic are present to calculate the priority for thread + , if a thread handle can be obtained. Alternatively, if the symbols wouldn't be + resolved until they are used + we could support this on windows 2000 and ME now, and just fall back to the + class only on pre win2000 machines. + + Lastly, because we can't assume that the pid we're given are Windows pids, we can't + alter non-cygwin started programs. +*/ + +extern "C" +{ + +/* max priority for policy */ +int +sched_get_priority_max (int policy) +{ + if (policy < 1 || policy > 3) + { + set_errno (EINVAL); + return -1; + } + return -14; +} + +/* min priority for policy */ +int +sched_get_priority_min (int policy) +{ + if (policy < 1 || policy > 3) + { + set_errno (EINVAL); + return -1; + } + return 15; +} + +/* Check a scheduler parameter struct for valid settings */ +int +valid_sched_parameters (const struct sched_param *param) +{ + if (param->sched_priority < -14 || param->sched_priority > 15) + { + return 0; + } + return -1; + +} + +/* get sched params for process + + Note, I'm never returning EPERM, + Always ESRCH. This is by design (If cygwin ever looks at paranoid security + Walking the pid values is a known hole in some os's) +*/ +int +sched_getparam (pid_t pid, struct sched_param *param) +{ + pid_t localpid; + int winpri; + if (!param || pid < 0) + { + set_errno (EINVAL); + return -1; + } + + localpid = pid ? pid : getpid (); + + DWORD Class; + int ThreadPriority; + HANDLE process; + pinfo p (localpid); + + /* get the class */ + + if (!p) + { + set_errno (ESRCH); + return -1; + } + process = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, p->dwProcessId); + if (!process) + { + set_errno (ESRCH); + return -1; + } + Class = GetPriorityClass (process); + CloseHandle (process); + if (!Class) + { + set_errno (ESRCH); + return -1; + } + ThreadPriority = THREAD_PRIORITY_NORMAL; + + /* calculate the unix priority. + + FIXME: windows 2000 supports ABOVE_NORMAL and BELOW_NORMAL class's + So this logic just defaults those class factors to NORMAL in the calculations */ + + switch (Class) + { + case IDLE_PRIORITY_CLASS: + switch (ThreadPriority) + { + case THREAD_PRIORITY_IDLE: + winpri = 1; + break; + case THREAD_PRIORITY_LOWEST: + winpri = 2; + break; + case THREAD_PRIORITY_BELOW_NORMAL: + winpri = 3; + break; + case THREAD_PRIORITY_NORMAL: + winpri = 4; + break; + case THREAD_PRIORITY_ABOVE_NORMAL: + winpri = 5; + break; + case THREAD_PRIORITY_HIGHEST: + default: + winpri = 6; + break; + } + break; + case HIGH_PRIORITY_CLASS: + switch (ThreadPriority) + { + case THREAD_PRIORITY_IDLE: + winpri = 1; + break; + case THREAD_PRIORITY_LOWEST: + winpri = 11; + break; + case THREAD_PRIORITY_BELOW_NORMAL: + winpri = 12; + break; + case THREAD_PRIORITY_NORMAL: + winpri = 13; + break; + case THREAD_PRIORITY_ABOVE_NORMAL: + winpri = 14; + break; + case THREAD_PRIORITY_HIGHEST: + default: + winpri = 15; + break; + } + break; + case NORMAL_PRIORITY_CLASS: + default: + switch (ThreadPriority) + { + case THREAD_PRIORITY_IDLE: + winpri = 1; + break; + case THREAD_PRIORITY_LOWEST: + winpri = 7; + break; + case THREAD_PRIORITY_BELOW_NORMAL: + winpri = 8; + break; + case THREAD_PRIORITY_NORMAL: + winpri = 9; + break; + case THREAD_PRIORITY_ABOVE_NORMAL: + winpri = 10; + break; + case THREAD_PRIORITY_HIGHEST: + default: + winpri = 11; + break; + } + break; + } + + /* reverse out winpri = (16- ((unixpri+16) >> 1)) */ + /* + winpri-16 = - (unixpri +16 ) >> 1 + + -(winpri-16) = unixpri +16 >> 1 + (-(winpri-16)) << 1 = unixpri+16 + ((-(winpri - 16)) << 1) - 16 = unixpri + */ + + param->sched_priority = ((-(winpri - 16)) << 1) - 16; + + return 0; +} + +/* get the scheduler for pid + + All process's on WIN32 run with SCHED_FIFO. + So we just give an answer. + (WIN32 uses a multi queue FIFO). +*/ +int +sched_getscheduler (pid_t pid) +{ + if (pid < 0) + return ESRCH; + else + return SCHED_FIFO; +} + +/* get the time quantum for pid + + We can't return -11, errno ENOSYS, because that implies that + sched_get_priority_max & min are also not supported (according to the spec) + so some spec-driven autoconf tests will likely assume they aren't present either + + returning ESRCH might confuse some applications (if they assumed that when + rr_get_interval is called on pid 0 it always works). + + If someone knows the time quanta for the various win32 platforms, then a + simple check for the os we're running on will finish this function +*/ +int +sched_rr_get_interval (pid_t pid, struct timespec *interval) +{ + set_errno (ESRCH); + return -1; +} + +/* set the scheduling parameters */ +int +sched_setparam (pid_t pid, const struct sched_param *param) +{ + pid_t localpid; + int winpri; + DWORD Class; + int ThreadPriority; + HANDLE process; + + if (!param || pid < 0) + { + set_errno (EINVAL); + return -1; + } + + if (!valid_sched_parameters (param)) + { + set_errno (EINVAL); + return -1; + } + + /* winpri = (16- ((unixpri+16) >> 1)) */ + winpri = 16 - ((param->sched_priority + 16) >> 1); + + /* calculate our desired priority class and thread priority */ + + if (winpri < 7) + Class = IDLE_PRIORITY_CLASS; + else if (winpri > 10) + Class = HIGH_PRIORITY_CLASS; + else + Class = NORMAL_PRIORITY_CLASS; + + switch (Class) + { + case IDLE_PRIORITY_CLASS: + switch (winpri) + { + case 1: + ThreadPriority = THREAD_PRIORITY_IDLE; + break; + case 2: + ThreadPriority = THREAD_PRIORITY_LOWEST; + break; + case 3: + ThreadPriority = THREAD_PRIORITY_BELOW_NORMAL; + break; + case 4: + ThreadPriority = THREAD_PRIORITY_NORMAL; + break; + case 5: + ThreadPriority = THREAD_PRIORITY_ABOVE_NORMAL; + break; + case 6: + ThreadPriority = THREAD_PRIORITY_HIGHEST; + break; + } + break; + case NORMAL_PRIORITY_CLASS: + switch (winpri) + { + case 7: + ThreadPriority = THREAD_PRIORITY_LOWEST; + break; + case 8: + ThreadPriority = THREAD_PRIORITY_BELOW_NORMAL; + break; + case 9: + ThreadPriority = THREAD_PRIORITY_NORMAL; + break; + case 10: + ThreadPriority = THREAD_PRIORITY_ABOVE_NORMAL; + break; + case 11: + ThreadPriority = THREAD_PRIORITY_HIGHEST; + break; + } + break; + case HIGH_PRIORITY_CLASS: + switch (winpri) + { + case 12: + ThreadPriority = THREAD_PRIORITY_BELOW_NORMAL; + break; + case 13: + ThreadPriority = THREAD_PRIORITY_NORMAL; + break; + case 14: + ThreadPriority = THREAD_PRIORITY_ABOVE_NORMAL; + break; + case 15: + ThreadPriority = THREAD_PRIORITY_HIGHEST; + break; + } + break; + } + + localpid = pid ? pid : getpid (); + + pinfo p (localpid); + + /* set the class */ + + if (!p) + { + set_errno (1); //ESRCH); + return -1; + } + process = + OpenProcess (PROCESS_SET_INFORMATION, FALSE, (DWORD) p->dwProcessId); + if (!process) + { + set_errno (2); //ESRCH); + return -1; + } + if (!SetPriorityClass (process, Class)) + { + CloseHandle (process); + set_errno (EPERM); + return -1; + } + CloseHandle (process); + + return 0; +} + +/* we map -14 to 15, and 15 to 1 via (16- ((n+16) >> 1)). This lines up with the allowed + * valueswe return elsewhere in the sched* functions. We then map in groups of three to + * allowed thread priority's. The reason for dropping accuracy while still returning + * a wide range of values is to allow more flexible code in the future. + */ +int +sched_set_thread_priority (HANDLE thread, int priority) +{ + int real_pri; + real_pri = 16 - ((priority + 16) >> 1); + if (real_pri <1 || real_pri > 15) + return EINVAL; + + if (real_pri < 4) + real_pri = THREAD_PRIORITY_LOWEST; + else if (real_pri < 7) + real_pri = THREAD_PRIORITY_BELOW_NORMAL; + else if (real_pri < 10) + real_pri = THREAD_PRIORITY_NORMAL; + else if (real_pri < 13) + real_pri = THREAD_PRIORITY_ABOVE_NORMAL; + else + real_pri = THREAD_PRIORITY_HIGHEST; + + if (!SetThreadPriority (thread, real_pri)) + /* invalid handle, no access are the only expected errors. */ + return EPERM; + return 0; +} + +/* set the scheduler */ +int +sched_setscheduler (pid_t pid, int policy, + const struct sched_param *param) +{ + /* on win32, you can't change the scheduler. Doh! */ + set_errno (ENOSYS); + return -1; +} + +/* yield the cpu */ +int +sched_yield (void) +{ + low_priority_sleep (0); + return 0; +} +} diff --git a/winsup/cygwin/sec_acl.cc b/winsup/cygwin/sec_acl.cc index f71236152c5..c35891016ac 100644 --- a/winsup/cygwin/sec_acl.cc +++ b/winsup/cygwin/sec_acl.cc @@ -15,7 +15,6 @@ details. */ #include <pwd.h> #include <unistd.h> #include <stdlib.h> -#include <errno.h> #include <limits.h> #include <sys/types.h> #include <sys/stat.h> diff --git a/winsup/cygwin/sec_helper.cc b/winsup/cygwin/sec_helper.cc index b50a4c8c51a..3869a60da44 100644 --- a/winsup/cygwin/sec_helper.cc +++ b/winsup/cygwin/sec_helper.cc @@ -15,7 +15,6 @@ details. */ #include <pwd.h> #include <unistd.h> #include <stdlib.h> -#include <errno.h> #include <limits.h> #include <sys/types.h> #include <sys/stat.h> diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc index 98cb37666b1..47f7c335469 100644 --- a/winsup/cygwin/security.cc +++ b/winsup/cygwin/security.cc @@ -16,7 +16,6 @@ details. */ #include <pwd.h> #include <unistd.h> #include <stdlib.h> -#include <errno.h> #include <limits.h> #include <sys/types.h> #include <sys/stat.h> @@ -41,12 +40,11 @@ details. */ #include "lm.h" #include "pwdgrp.h" -extern BOOL allow_ntea; -BOOL allow_ntsec; +bool allow_ntsec; /* allow_smbntsec is handled exclusively in path.cc (path_conv::check). It's defined here because of it's strong relationship to allow_ntsec. The default is TRUE to reflect the old behaviour. */ -BOOL allow_smbntsec; +bool allow_smbntsec; cygsid * cygsidlist::alloc_sids (int n) @@ -71,10 +69,16 @@ extern "C" void cygwin_set_impersonation_token (const HANDLE hToken) { debug_printf ("set_impersonation_token (%d)", hToken); - if (cygheap->user.token != hToken) + if (cygheap->user.impersonation_state == IMP_EXTERNAL + && cygheap->user.external_token != hToken) { - cygheap->user.token = hToken; - cygheap->user.impersonated = FALSE; + set_errno (EPERM); + return; + } + else + { + cygheap->user.external_token = hToken; + return; } } @@ -718,7 +722,7 @@ verify_token (HANDLE token, cygsid &usersid, user_groups &groups, BOOL *pintern) if (pintern) { TOKEN_SOURCE ts; - if (!GetTokenInformation (cygheap->user.token, TokenSource, + if (!GetTokenInformation (token, TokenSource, &ts, sizeof ts, &size)) debug_printf ("GetTokenInformation(): %E"); else @@ -1907,7 +1911,7 @@ check_file_access (const char *fn, int flags) goto done; if (cygheap->user.issetuid ()) - hToken = cygheap->user.token; + hToken = cygheap->user.token (); else if (!OpenProcessToken (hMainProc, TOKEN_DUPLICATE, &hToken)) { __seterrno (); @@ -1915,7 +1919,7 @@ check_file_access (const char *fn, int flags) } if (!(status = DuplicateToken (hToken, SecurityIdentification, &hIToken))) __seterrno (); - if (hToken != cygheap->user.token) + if (!cygheap->user.issetuid ()) CloseHandle (hToken); if (!status) goto done; diff --git a/winsup/cygwin/security.h b/winsup/cygwin/security.h index 2965b1dec59..71ffe4cecaa 100644 --- a/winsup/cygwin/security.h +++ b/winsup/cygwin/security.h @@ -209,9 +209,9 @@ legal_sid_type (SID_NAME_USE type) || type == SidTypeAlias || type == SidTypeWellKnownGroup; } -extern BOOL allow_ntea; -extern BOOL allow_ntsec; -extern BOOL allow_smbntsec; +extern bool allow_ntea; +extern bool allow_ntsec; +extern bool allow_smbntsec; /* File manipulation */ int __stdcall set_process_privileges (); diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc index 6c8a5b4a75a..48cb56c9674 100644 --- a/winsup/cygwin/select.cc +++ b/winsup/cygwin/select.cc @@ -20,7 +20,6 @@ details. */ #define __INSIDE_CYGWIN_NET__ #include "winsup.h" -#include <errno.h> #include <sys/socket.h> #include <stdlib.h> #include <sys/time.h> diff --git a/winsup/cygwin/sem.cc b/winsup/cygwin/sem.cc new file mode 100644 index 00000000000..97d91a3546d --- /dev/null +++ b/winsup/cygwin/sem.cc @@ -0,0 +1,40 @@ +/* sem.cc: Single unix specification IPC interface for Cygwin. + + Copyright 2002 Red Hat, Inc. + + Written by Conrad Scott <conrad.scott@dsl.pipex.com>. + +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 <sys/types.h> +#include <cygwin/sem.h> + + +#include "cygerrno.h" + +extern "C" int +semctl (int semid, int semnum, int cmd, ...) +{ + set_errno (ENOSYS); + return -1; +} + +extern "C" int +semget (key_t key, int nsems, int semflg) +{ + set_errno (ENOSYS); + return -1; +} + +extern "C" int +semop (int semid, struct sembuf *sops, size_t nsops) +{ + set_errno (ENOSYS); + return -1; +} diff --git a/winsup/cygwin/shared.cc b/winsup/cygwin/shared.cc index c91e380b6eb..1f1145840fa 100644 --- a/winsup/cygwin/shared.cc +++ b/winsup/cygwin/shared.cc @@ -14,7 +14,6 @@ details. */ #include <stdlib.h> #include <grp.h> #include <pwd.h> -#include <errno.h> #include "pinfo.h" #include "security.h" #include "path.h" diff --git a/winsup/cygwin/shm.cc b/winsup/cygwin/shm.cc index 618cac1823f..1221298d2b5 100644 --- a/winsup/cygwin/shm.cc +++ b/winsup/cygwin/shm.cc @@ -12,11 +12,10 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #include "winsup.h" - +#ifdef USE_CYGSERVER #include <sys/types.h> #include <assert.h> -#include <errno.h> #include <stdio.h> #include <unistd.h> @@ -691,3 +690,4 @@ client_request_shm::client_request_shm (const key_t key, msglen (sizeof (_parameters.in)); } +#endif /* USE_CYGSERVER */ diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc index 547a1285d0c..0530fcf476b 100644 --- a/winsup/cygwin/signal.cc +++ b/winsup/cygwin/signal.cc @@ -12,7 +12,6 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #include "winsup.h" -#include <errno.h> #include <stdlib.h> #include "cygerrno.h" #include <sys/cygwin.h> @@ -297,8 +296,8 @@ abort (void) be flushed. However this is the way FreeBSD does it, and it is much easier to do things this way, so... */ - if (_reent_clib ()->__cleanup) - _reent_clib ()->__cleanup (_reent_clib ()); + if (_REENT->__cleanup) + _REENT->__cleanup (_REENT); /* Ensure that SIGABRT can be caught regardless of blockage. */ sigset_t sig_mask; diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index dafaad84faf..3237accba5d 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -14,7 +14,6 @@ details. */ #include <stdlib.h> #include <time.h> #include <sys/wait.h> -#include <errno.h> #include <stdlib.h> #include <sys/cygwin.h> #include <assert.h> diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index 850536c9de7..fe4efbad0e5 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -14,7 +14,6 @@ details. */ #include <unistd.h> #include <process.h> #include <sys/wait.h> -#include <errno.h> #include <limits.h> #include <wingdi.h> #include <winuser.h> @@ -622,7 +621,16 @@ spawn_guts (const char * prog_arg, const char *const *argv, cygbench ("spawn-guts"); cygheap->fdtab.set_file_pointers_for_exec (); - if (!cygheap->user.issetuid ()) + cygheap->user.deimpersonate (); + /* When ruid != euid we create the new process under the current original + account and impersonate in child, this way maintaining the different + effective vs. real ids. + FIXME: If ruid != euid and ruid != orig_uid we currently give + up on ruid. The new process will have ruid == euid. */ + if (!cygheap->user.issetuid () + || (cygheap->user.orig_uid == cygheap->user.real_uid + && cygheap->user.orig_gid == cygheap->user.real_gid + && !cygheap->user.groups.issetgroups ())) { PSECURITY_ATTRIBUTES sec_attribs = sec_user_nih (sa_buf); ciresrv.moreinfo->envp = build_env (envp, envblock, ciresrv.moreinfo->envc, @@ -646,8 +654,6 @@ spawn_guts (const char * prog_arg, const char *const *argv, /* Set security attributes with sid */ PSECURITY_ATTRIBUTES sec_attribs = sec_user_nih (sa_buf, sid); - RevertToSelf (); - /* Load users registry hive. */ load_registry_hive (sid); @@ -671,7 +677,7 @@ spawn_guts (const char * prog_arg, const char *const *argv, ciresrv.moreinfo->envp = build_env (envp, envblock, ciresrv.moreinfo->envc, real_path.iscygexec ()); newheap = cygheap_setup_for_child (&ciresrv, cygheap->fdtab.need_fixup_before ()); - rc = CreateProcessAsUser (cygheap->user.token, + rc = CreateProcessAsUser (cygheap->user.token (), runpath, /* image name - with full path */ one_line.buf, /* what was passed to exec */ sec_attribs, /* process security attrs */ @@ -682,11 +688,11 @@ spawn_guts (const char * prog_arg, const char *const *argv, 0, /* use current drive/directory */ &si, &pi); - /* Restore impersonation. In case of _P_OVERLAY this isn't - allowed since it would overwrite child data. */ - if (mode != _P_OVERLAY) - ImpersonateLoggedOnUser (cygheap->user.token); } + /* Restore impersonation. In case of _P_OVERLAY this isn't + allowed since it would overwrite child data. */ + if (mode != _P_OVERLAY) + cygheap->user.reimpersonate (); MALLOC_CHECK; if (envblock) diff --git a/winsup/cygwin/strace.cc b/winsup/cygwin/strace.cc index 283f019141f..57ad3ba0668 100644 --- a/winsup/cygwin/strace.cc +++ b/winsup/cygwin/strace.cc @@ -14,7 +14,6 @@ details. */ #include <wingdi.h> #include <winuser.h> #include <ctype.h> -#include <errno.h> #include "pinfo.h" #include "perprocess.h" #include "cygwin_version.h" diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 5625f1a1eb8..91b533f19c4 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -29,7 +29,6 @@ details. */ #include <process.h> #include <utmp.h> #include <sys/uio.h> -#include <errno.h> #include <limits.h> #include <unistd.h> #include <setjmp.h> @@ -1539,8 +1538,6 @@ getpagesize () static int check_posix_perm (const char *fname, int v) { - extern int allow_ntea, allow_ntsec, allow_smbntsec; - /* Windows 95/98/ME don't support file system security at all. */ if (!wincap.has_security ()) return 0; @@ -2123,66 +2120,52 @@ seteuid32 (__uid32_t uid) sigframe thisframe (mainthread); cygsid usersid; user_groups &groups = cygheap->user.groups; - HANDLE ptok, sav_token; - BOOL sav_impersonated, sav_token_is_internal_token; - BOOL process_ok, explicitly_created_token = FALSE; + HANDLE ptok, new_token = INVALID_HANDLE_VALUE; struct passwd * pw_new; PSID origpsid, psid2 = NO_SID; + enum impersonation new_state = IMP_BAD; + BOOL token_is_internal; pw_new = internal_getpwuid (uid); if (!wincap.has_security () && pw_new) - goto success; + goto success_9x; if (!usersid.getfrompw (pw_new)) { set_errno (EINVAL); return -1; } - /* Save current information */ - sav_token = cygheap->user.token; - sav_impersonated = cygheap->user.impersonated; RevertToSelf (); if (!OpenProcessToken (hMainProc, TOKEN_QUERY | TOKEN_ADJUST_DEFAULT, &ptok)) { __seterrno (); - goto failed; + goto failed_ptok;; } - /* Verify if the process token is suitable. - Currently we do not try to differentiate between - internal tokens and others */ - process_ok = verify_token (ptok, usersid, groups); - debug_printf ("Process token %sverified", process_ok ? "" : "not "); - if (process_ok) + + /* Verify if the process token is suitable. */ + if (verify_token (ptok, usersid, groups)) + new_state = IMP_NONE; + /* Verify if a current token is suitable */ + else if (cygheap->user.external_token + && verify_token (cygheap->user.external_token, usersid, groups)) { - if (cygheap->user.issetuid ()) - cygheap->user.impersonated = FALSE; - else - { - CloseHandle (ptok); - goto success; /* No change */ - } + new_token = cygheap->user.external_token; + new_state = IMP_EXTERNAL; + } + else if (cygheap->user.internal_token + && verify_token (cygheap->user.internal_token, usersid, groups, + &token_is_internal)) + { + new_token = cygheap->user.internal_token; + new_state = IMP_INTERNAL; } - if (!process_ok && cygheap->user.token != INVALID_HANDLE_VALUE) + debug_printf ("New token %d, state %d", new_token, new_state); + /* Return if current token is valid */ + if (cygheap->user.impersonation_state == new_state) { - /* Verify if the current tokem is suitable */ - BOOL token_ok = verify_token (cygheap->user.token, usersid, groups, - &sav_token_is_internal_token); - debug_printf ("Thread token %d %sverified", - cygheap->user.token, token_ok?"":"not "); - if (!token_ok) - cygheap->user.token = INVALID_HANDLE_VALUE; - else - { - /* Return if current token is valid */ - if (cygheap->user.impersonated) - { - CloseHandle (ptok); - if (!ImpersonateLoggedOnUser (cygheap->user.token)) - system_printf ("Impersonating in seteuid failed: %E"); - goto success; /* No change */ - } - } + cygheap->user.reimpersonate (); + goto success; /* No change */ } /* Set process def dacl to allow access to impersonated token */ @@ -2198,72 +2181,72 @@ seteuid32 (__uid32_t uid) debug_printf ("SetTokenInformation" "(TokenDefaultDacl): %E"); } - CloseHandle (ptok); - if (!process_ok && cygheap->user.token == INVALID_HANDLE_VALUE) + if (new_state == IMP_BAD) { /* If no impersonation token is available, try to authenticate using NtCreateToken () or subauthentication. */ - cygheap->user.token = create_token (usersid, groups, pw_new); - if (cygheap->user.token != INVALID_HANDLE_VALUE) - explicitly_created_token = TRUE; - else + new_token = create_token (usersid, groups, pw_new); + if (new_token == INVALID_HANDLE_VALUE) { /* create_token failed. Try subauthentication. */ debug_printf ("create token failed, try subauthentication."); - cygheap->user.token = subauth (pw_new); - if (cygheap->user.token == INVALID_HANDLE_VALUE) + new_token = subauth (pw_new); + if (new_token == INVALID_HANDLE_VALUE) goto failed; } + new_state = IMP_INTERNAL; } /* If using the token, set info and impersonate */ - if (!process_ok) + if (new_state != IMP_NONE) { /* If the token was explicitly created, all information has already been set correctly. */ - if (!explicitly_created_token) + if (new_state == IMP_EXTERNAL) { /* Try setting owner to same value as user. */ - if (!SetTokenInformation (cygheap->user.token, TokenOwner, + if (!SetTokenInformation (new_token, TokenOwner, &usersid, sizeof usersid)) debug_printf ("SetTokenInformation(user.token, " "TokenOwner): %E"); /* Try setting primary group in token to current group */ - if (!SetTokenInformation (cygheap->user.token, + if (!SetTokenInformation (new_token, TokenPrimaryGroup, &groups.pgsid, sizeof (cygsid))) debug_printf ("SetTokenInformation(user.token, " "TokenPrimaryGroup): %E"); } - /* Now try to impersonate. */ - if (!ImpersonateLoggedOnUser (cygheap->user.token)) + /* Try to impersonate. */ + if (!ImpersonateLoggedOnUser (new_token)) { debug_printf ("ImpersonateLoggedOnUser %E"); __seterrno (); goto failed; } - cygheap->user.impersonated = TRUE; + /* Keep at most one internal token */ + if (new_state == IMP_INTERNAL) + { + if (cygheap->user.internal_token) + CloseHandle (cygheap->user.internal_token); + cygheap->user.internal_token = new_token; + } } - - /* If sav_token was internally created and is replaced, destroy it. */ - if (sav_token != INVALID_HANDLE_VALUE && - sav_token != cygheap->user.token && - sav_token_is_internal_token) - CloseHandle (sav_token); cygheap->user.set_sid (usersid); + success: + CloseHandle (ptok); + cygheap->user.impersonation_state = new_state; +success_9x: cygheap->user.set_name (pw_new->pw_name); myself->uid = uid; groups.ischanged = FALSE; return 0; failed: - cygheap->user.token = sav_token; - cygheap->user.impersonated = sav_impersonated; - if (cygheap->user.issetuid () - && !ImpersonateLoggedOnUser (cygheap->user.token)) - system_printf ("Impersonating in seteuid failed: %E"); + CloseHandle (ptok); +failed_ptok: + cygheap->user.reimpersonate (); return -1; } @@ -2344,7 +2327,7 @@ setegid32 (__gid32_t gid) /* If impersonated, update primary group and revert */ if (cygheap->user.issetuid ()) { - if (!SetTokenInformation (cygheap->user.token, + if (!SetTokenInformation (cygheap->user.token (), TokenPrimaryGroup, &gsid, sizeof gsid)) debug_printf ("SetTokenInformation(thread, " @@ -2362,7 +2345,7 @@ setegid32 (__gid32_t gid) CloseHandle (ptok); } if (cygheap->user.issetuid () - && !ImpersonateLoggedOnUser (cygheap->user.token)) + && !ImpersonateLoggedOnUser (cygheap->user.token ())) system_printf ("Impersonating in setegid failed: %E"); return 0; } diff --git a/winsup/cygwin/sysconf.cc b/winsup/cygwin/sysconf.cc index 608f1877671..55eaa8cee93 100644 --- a/winsup/cygwin/sysconf.cc +++ b/winsup/cygwin/sysconf.cc @@ -10,7 +10,6 @@ details. */ #include "winsup.h" #include <unistd.h> -#include <errno.h> #include <time.h> #include <limits.h> #include <ntdef.h> diff --git a/winsup/cygwin/syslog.cc b/winsup/cygwin/syslog.cc index cf3931ffe76..f8b17149c8d 100644 --- a/winsup/cygwin/syslog.cc +++ b/winsup/cygwin/syslog.cc @@ -14,7 +14,6 @@ details. */ #include <syslog.h> #include <stdarg.h> #include <unistd.h> -#include <errno.h> #include "security.h" #include "path.h" #include "fhandler.h" @@ -208,7 +207,7 @@ pass_handler::print_va (const char *fmt, va_list list) */ extern "C" void -syslog (int priority, const char *message, ...) +vsyslog (int priority, const char *message, va_list ap) { debug_printf ("%x %s", priority, message); /* If the priority fails the current mask, reject */ @@ -281,8 +280,6 @@ syslog (int priority, const char *message, ...) output, then do it again to a malloc'ed string. This is ugly, slow, but prevents core dumps :-). */ - va_list ap; - pass_handler pass; for (int pass_number = 0; pass_number < 2; ++pass_number) { @@ -341,10 +338,8 @@ syslog (int priority, const char *message, ...) } /* Print out the variable part */ - va_start (ap, message); if (pass.print_va (message, ap) == -1) return; - va_end (ap); } const char *msg_strings[1]; @@ -409,6 +404,15 @@ syslog (int priority, const char *message, ...) } extern "C" void +syslog (int priority, const char *message, ...) +{ + va_list ap; + va_start (ap, message); + vsyslog (priority, message, ap); + va_end (ap); +} + +extern "C" void closelog (void) { ; diff --git a/winsup/cygwin/termios.cc b/winsup/cygwin/termios.cc index 99019b84b75..ebc06573f01 100644 --- a/winsup/cygwin/termios.cc +++ b/winsup/cygwin/termios.cc @@ -12,7 +12,6 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #include "winsup.h" -#include <errno.h> #include <signal.h> #include <stdlib.h> #include "cygerrno.h" diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc index 0321ea47b9d..b42bb140bdc 100644 --- a/winsup/cygwin/thread.cc +++ b/winsup/cygwin/thread.cc @@ -29,7 +29,6 @@ details. */ # include "config.h" #endif -#ifdef _MT_SAFE #include "winsup.h" #include <limits.h> #include "cygerrno.h" @@ -45,16 +44,21 @@ details. */ extern int threadsafe; -struct _reent * -_reent_clib () +extern "C" struct _reent * +__getreent () { struct __reent_t *_r = (struct __reent_t *) MT_INTERFACE->reent_key.get (); -#ifdef _CYG_THREAD_FAILSAFE if (_r == 0) - system_printf ("local thread storage not inited"); + { +#ifdef _CYG_THREAD_FAILSAFE + system_printf ("local thread storage not inited"); #endif + /* Return _impure_ptr as long as MTinterface is not initialized */ + return _impure_ptr; + } + return _r->_clib; } @@ -64,10 +68,14 @@ _reent_winsup () struct __reent_t *_r = (struct __reent_t *) MT_INTERFACE->reent_key.get (); -#ifdef _CYG_THREAD_FAILSAFE if (_r == 0) - system_printf ("local thread storage not inited"); + { +#ifdef _CYG_THREAD_FAILSAFE + system_printf ("local thread storage not inited"); #endif + return NULL; + } + return _r->_winsup; } @@ -212,9 +220,24 @@ MTinterface::fixup_after_fork (void) { pthread_key::fixup_after_fork (); +#ifndef __SIGNALS_ARE_MULTITHREADED__ + /* As long as the signal handling not multithreaded + switch reents storage back to _impure_ptr for the mainthread + to support fork from threads other than the mainthread */ + struct _reent *reent_old = __getreent (); + + if (reent_old && _impure_ptr != reent_old) + *_impure_ptr = *reent_old; + reents._clib = _impure_ptr; + reents._winsup = &winsup_reent; + winsup_reent._process_logmask = LOG_UPTO (LOG_DEBUG); + reent_key.set (&reents); +#endif + threadcount = 1; pthread::init_mainthread (); + pthread::fixup_after_fork (); pthread_mutex::fixup_after_fork (); pthread_cond::fixup_after_fork (); pthread_rwlock::fixup_after_fork (); @@ -261,11 +284,16 @@ pthread::get_tls_self_pointer () +List<pthread> pthread::threads; + /* member methods */ pthread::pthread ():verifyable_object (PTHREAD_MAGIC), win32_obj_id (0), + running (false), suspended (false), cancelstate (0), canceltype (0), cancel_event (0), - joiner (NULL), cleanup_stack (NULL) + joiner (NULL), next (NULL), cleanup_stack (NULL) { + if (this != pthread_null::get_null_pthread ()) + threads.insert (this); } pthread::~pthread () @@ -274,6 +302,9 @@ pthread::~pthread () CloseHandle (win32_obj_id); if (cancel_event) CloseHandle (cancel_event); + + if (this != pthread_null::get_null_pthread ()) + threads.remove (this); } void @@ -347,13 +378,15 @@ pthread::create (void *(*func) (void *), pthread_attr *newattr, void pthread::postcreate () { - InterlockedIncrement (&MT_INTERFACE->threadcount); - /* FIXME: set the priority appropriately for system contention scope */ - if (attr.inheritsched == PTHREAD_EXPLICIT_SCHED) - { - /* FIXME: set the scheduling settings for the new thread */ - /* sched_thread_setparam (win32_obj_id, attr.schedparam); */ - } + running = true; + + InterlockedIncrement (&MT_INTERFACE->threadcount); + /* FIXME: set the priority appropriately for system contention scope */ + if (attr.inheritsched == PTHREAD_EXPLICIT_SCHED) + { + /* FIXME: set the scheduling settings for the new thread */ + /* sched_thread_setparam (win32_obj_id, attr.schedparam); */ + } } void @@ -372,6 +405,7 @@ pthread::exit (void *value_ptr) delete this; else { + running = false; return_ptr = value_ptr; mutex.unlock (); } @@ -390,6 +424,12 @@ pthread::cancel (void) mutex.lock (); + if (!running) + { + mutex.unlock (); + return 0; + } + if (canceltype == PTHREAD_CANCEL_DEFERRED || cancelstate == PTHREAD_CANCEL_DISABLE) { @@ -739,6 +779,19 @@ pthread::init_current_thread () set_tls_self_pointer (this); } +void +pthread::_fixup_after_fork () +{ + /* set thread to not running if it is not the forking thread */ + if (this != pthread::self ()) + { + magic = 0; + running = false; + win32_obj_id = NULL; + cancel_event = NULL; + } +} + /* static members */ bool pthread_attr::is_good_object (pthread_attr_t const *attr) @@ -1964,14 +2017,15 @@ pthread::atfork (void (*prepare)(void), void (*parent)(void), void (*child)(void extern "C" int pthread_attr_init (pthread_attr_t *attr) { - if (check_valid_pointer (attr)) - return EINVAL; + if (pthread_attr::is_good_object (attr)) + return EBUSY; + *attr = new pthread_attr; if (!pthread_attr::is_good_object (attr)) { delete (*attr); *attr = NULL; - return EAGAIN; + return ENOMEM; } return 0; } @@ -2187,7 +2241,7 @@ pthread::detach (pthread_t *thread) } // check if thread is still alive - if (WaitForSingleObject ((*thread)->win32_obj_id, 0) == WAIT_TIMEOUT) + if ((*thread)->running && WaitForSingleObject ((*thread)->win32_obj_id, 0) == WAIT_TIMEOUT) { // force cleanup on exit (*thread)->joiner = *thread; @@ -2488,14 +2542,15 @@ pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) extern "C" int pthread_condattr_init (pthread_condattr_t *condattr) { - if (check_valid_pointer (condattr)) - return EINVAL; + if (pthread_condattr::is_good_object (condattr)) + return EBUSY; + *condattr = new pthread_condattr; if (!pthread_condattr::is_good_object (condattr)) { delete (*condattr); *condattr = NULL; - return EAGAIN; + return ENOMEM; } return 0; } @@ -2673,14 +2728,15 @@ pthread_rwlock_unlock (pthread_rwlock_t *rwlock) extern "C" int pthread_rwlockattr_init (pthread_rwlockattr_t *rwlockattr) { - if (check_valid_pointer (rwlockattr)) - return EINVAL; + if (pthread_rwlockattr::is_good_object (rwlockattr)) + return EBUSY; + *rwlockattr = new pthread_rwlockattr; if (!pthread_rwlockattr::is_good_object (rwlockattr)) { delete (*rwlockattr); *rwlockattr = NULL; - return EAGAIN; + return ENOMEM; } return 0; } @@ -3172,5 +3228,3 @@ pthread_null::getsequence_np () } pthread_null pthread_null::_instance; - -#endif // MT_SAFE diff --git a/winsup/cygwin/thread.h b/winsup/cygwin/thread.h index 55d94157b0f..ea1f13f44a2 100644 --- a/winsup/cygwin/thread.h +++ b/winsup/cygwin/thread.h @@ -110,7 +110,6 @@ struct __reent_t struct _winsup_t *_winsup; }; -_reent *_reent_clib (); _winsup_t *_reent_winsup (); void SetResourceLock (int, int, const char *) __attribute__ ((regparm (3))); void ReleaseResourceLock (int, int, const char *) @@ -386,11 +385,11 @@ public: void *(*function) (void *); void *arg; void *return_ptr; + bool running; bool suspended; int cancelstate, canceltype; HANDLE cancel_event; pthread_t joiner; - // int joinable; /* signal handling */ struct sigaction *sigs; @@ -443,11 +442,21 @@ public: return t1 == t2; } + /* List support calls */ + class pthread *next; + static void fixup_after_fork () + { + threads.for_each (&pthread::_fixup_after_fork); + } + private: + static List<pthread> threads; DWORD thread_id; __pthread_cleanup_handler *cleanup_stack; pthread_mutex mutex; + void _fixup_after_fork (); + void pop_all_cleanup_handlers (void); void precreate (pthread_attr *); void postcreate (); diff --git a/winsup/cygwin/times.cc b/winsup/cygwin/times.cc index 87b8c858981..44a08831a9a 100644 --- a/winsup/cygwin/times.cc +++ b/winsup/cygwin/times.cc @@ -15,7 +15,6 @@ details. */ #include <utime.h> #include <stdio.h> #include <stdlib.h> -#include <errno.h> #include "cygerrno.h" #include "security.h" #include "path.h" diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc index 01d3f5250ec..f13a96f29cd 100644 --- a/winsup/cygwin/tty.cc +++ b/winsup/cygwin/tty.cc @@ -9,7 +9,6 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #include "winsup.h" -#include <errno.h> #include <unistd.h> #include <utmp.h> #include <wingdi.h> @@ -409,11 +408,16 @@ tty::common_init (fhandler_pty_master *ptym) */ if (wincap.has_security ()) { +#ifdef USE_CYGSERVER if (cygserver_running == CYGSERVER_UNKNOWN) cygserver_init (); +#endif - if (cygserver_running != CYGSERVER_OK - && !SetKernelObjectSecurity (hMainProc, + if ( +#ifdef USE_CYGSERVER + cygserver_running != CYGSERVER_OK && +#endif + !SetKernelObjectSecurity (hMainProc, DACL_SECURITY_INFORMATION, get_null_sd ())) system_printf ("Can't set process security, %E"); diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc index b74cd165b2c..8c16ac64952 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -17,7 +17,6 @@ details. */ #include <limits.h> #include <stdlib.h> #include <lm.h> -#include <errno.h> #include <sys/cygwin.h> #include "pinfo.h" #include "security.h" @@ -103,18 +102,28 @@ internal_getlogin (cygheap_user &user) void uinfo_init () { - if (!child_proc_info || cygheap->user.token != INVALID_HANDLE_VALUE) + if (child_proc_info && !cygheap->user.has_impersonation_tokens ()) + return; + + if (!child_proc_info) + internal_getlogin (cygheap->user); /* Set the cygheap->user. */ + /* Conditions must match those in spawn to allow starting child + processes with ruid != euid and rgid != egid. */ + else if (cygheap->user.issetuid () + && cygheap->user.orig_uid == cygheap->user.real_uid + && cygheap->user.orig_gid == cygheap->user.real_gid + && !cygheap->user.groups.issetgroups ()) { - if (!child_proc_info) - internal_getlogin (cygheap->user); /* Set the cygheap->user. */ - else - CloseHandle (cygheap->user.token); - cygheap->user.set_orig_sid (); /* Update the original sid */ - cygheap->user.token = INVALID_HANDLE_VALUE; /* No token present */ + cygheap->user.reimpersonate (); + return; } - /* Real and effective uid/gid are identical on process start up. */ + else + cygheap->user.close_impersonation_tokens (); + cygheap->user.orig_uid = cygheap->user.real_uid = myself->uid; cygheap->user.orig_gid = cygheap->user.real_gid = myself->gid; + cygheap->user.impersonation_state = IMP_NONE; + cygheap->user.set_orig_sid (); /* Update the original sid */ } extern "C" char * diff --git a/winsup/cygwin/wait.cc b/winsup/cygwin/wait.cc index 3b6427ad927..fd782783e33 100644 --- a/winsup/cygwin/wait.cc +++ b/winsup/cygwin/wait.cc @@ -11,7 +11,6 @@ details. */ #include "winsup.h" #include <sys/wait.h> #include <stdlib.h> -#include <errno.h> #include "cygerrno.h" #include "sigproc.h" #include "perthread.h" diff --git a/winsup/cygwin/window.cc b/winsup/cygwin/window.cc new file mode 100644 index 00000000000..ea9ed6e04bb --- /dev/null +++ b/winsup/cygwin/window.cc @@ -0,0 +1,249 @@ +/* window.cc: hidden windows for signals/itimer support + + Copyright 1997, 1998, 2000, 2001, 2002, 2003 Red Hat, Inc. + + Written by Sergey Okhapkin <sos@prospect.com.ru> + +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 <sys/time.h> +#include <stdlib.h> +#include <signal.h> +#include <limits.h> +#include <wingdi.h> +#include <winuser.h> +#define USE_SYS_TYPES_FD_SET +#include <winsock2.h> +#include <unistd.h> +#include "cygerrno.h" +#include "perprocess.h" +#include "security.h" +#include "cygthread.h" + +static NO_COPY UINT timer_active = 0; +static NO_COPY struct itimerval itv; +static NO_COPY DWORD start_time; +static NO_COPY HWND ourhwnd = NULL; + +static LRESULT CALLBACK +WndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ +#ifndef NOSTRACE + strace.wm (uMsg, wParam, lParam); +#endif + switch (uMsg) + { + case WM_PAINT: + return 0; + case WM_DESTROY: + PostQuitMessage (0); + return 0; + case WM_TIMER: + if (wParam == timer_active) + { + UINT elapse = itv.it_interval.tv_sec * 1000 + + itv.it_interval.tv_usec / 1000; + KillTimer (hwnd, timer_active); + if (!elapse) + { + timer_active = 0; + } + else + { + timer_active = SetTimer (hwnd, 1, elapse, NULL); + start_time = GetTickCount (); + itv.it_value = itv.it_interval; + } + raise (SIGALRM); + } + return 0; + case WM_ASYNCIO: + if (WSAGETSELECTEVENT (lParam) == FD_OOB) + raise (SIGURG); + else + raise (SIGIO); + return 0; + default: + return DefWindowProc (hwnd, uMsg, wParam, lParam); + } +} + +static HANDLE window_started; + +static DWORD WINAPI +Winmain (VOID *) +{ + MSG msg; + WNDCLASS wc; + static NO_COPY char classname[] = "CygwinWndClass"; + + /* Register the window class for the main window. */ + + wc.style = 0; + wc.lpfnWndProc = (WNDPROC) WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = user_data->hmodule; + wc.hIcon = NULL; + wc.hCursor = NULL; + wc.hbrBackground = NULL; + wc.lpszMenuName = NULL; + wc.lpszClassName = classname; + + if (!RegisterClass (&wc)) + { + system_printf ("Cannot register window class"); + return FALSE; + } + + /* Create hidden window. */ + ourhwnd = CreateWindow (classname, classname, WS_POPUP, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + (HWND) NULL, (HMENU) NULL, user_data->hmodule, + (LPVOID) NULL); + + SetEvent (window_started); + + if (!ourhwnd) + { + system_printf ("Cannot create window"); + return FALSE; + } + + /* Start the message loop. */ + + while (GetMessage (&msg, ourhwnd, 0, 0) == TRUE) + DispatchMessage (&msg); + + ExitThread (0); +} + +HWND __stdcall +gethwnd () +{ + if (ourhwnd != NULL) + return ourhwnd; + + cygthread *h; + + window_started = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL); + h = new cygthread (Winmain, NULL, "win"); + h->SetThreadPriority (THREAD_PRIORITY_HIGHEST); + WaitForSingleObject (window_started, INFINITE); + CloseHandle (window_started); + h->zap_h (); + return ourhwnd; +} + +extern "C" int +setitimer (int which, const struct itimerval *value, struct itimerval *oldvalue) +{ + UINT elapse; + + if (which != ITIMER_REAL) + { + set_errno (ENOSYS); + return -1; + } + /* Check if we will wrap */ + if (itv.it_value.tv_sec >= (long) (UINT_MAX / 1000)) + { + set_errno (EINVAL); + return -1; + } + if (timer_active) + { + KillTimer (gethwnd (), timer_active); + timer_active = 0; + } + if (oldvalue) + *oldvalue = itv; + if (value == NULL) + { + set_errno (EFAULT); + return -1; + } + itv = *value; + elapse = itv.it_value.tv_sec * 1000 + itv.it_value.tv_usec / 1000; + if (elapse == 0) + if (itv.it_value.tv_usec) + elapse = 1; + else + return 0; + if (!(timer_active = SetTimer (gethwnd (), 1, elapse, NULL))) + { + __seterrno (); + return -1; + } + start_time = GetTickCount (); + return 0; +} + +extern "C" int +getitimer (int which, struct itimerval *value) +{ + UINT elapse, val; + + if (which != ITIMER_REAL) + { + set_errno (EINVAL); + return -1; + } + if (value == NULL) + { + set_errno (EFAULT); + return -1; + } + *value = itv; + if (!timer_active) + { + value->it_value.tv_sec = 0; + value->it_value.tv_usec = 0; + return 0; + } + elapse = GetTickCount () - start_time; + val = itv.it_value.tv_sec * 1000 + itv.it_value.tv_usec / 1000; + val -= elapse; + value->it_value.tv_sec = val / 1000; + value->it_value.tv_usec = val % 1000; + return 0; +} + +extern "C" unsigned int +alarm (unsigned int seconds) +{ + int ret; + struct itimerval newt, oldt; + + newt.it_value.tv_sec = seconds; + newt.it_value.tv_usec = 0; + newt.it_interval.tv_sec = 0; + newt.it_interval.tv_usec = 0; + setitimer (ITIMER_REAL, &newt, &oldt); + ret = oldt.it_value.tv_sec; + if (ret == 0 && oldt.it_value.tv_usec) + ret = 1; + return ret; +} + +extern "C" useconds_t +ualarm (useconds_t value, useconds_t interval) +{ + struct itimerval timer, otimer; + + timer.it_value.tv_sec = 0; + timer.it_value.tv_usec = value; + timer.it_interval.tv_sec = 0; + timer.it_interval.tv_usec = interval; + + if (setitimer (ITIMER_REAL, &timer, &otimer) < 0) + return (u_int)-1; + + return (otimer.it_value.tv_sec * 1000000) + otimer.it_value.tv_usec; +} + diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h index 092f502fc9b..fc9de77a25c 100644 --- a/winsup/cygwin/winsup.h +++ b/winsup/cygwin/winsup.h @@ -98,6 +98,8 @@ extern int dynamically_loaded; extern int cygserver_running; +#define _MT_SAFE // DELTEME someday + #define TITLESIZE 1024 /* status bit manipulation */ @@ -197,7 +199,6 @@ extern int cygwin_finished_initializing; void __stdcall set_std_handle (int); int __stdcall writable_directory (const char *file); int __stdcall stat_dev (DWORD, int, unsigned long, struct __stat64 *); -extern BOOL allow_ntsec; __ino64_t __stdcall hash_path_name (__ino64_t hash, const char *name) __attribute__ ((regparm(2))); void __stdcall nofinalslash (const char *src, char *dst) __attribute__ ((regparm(2))); @@ -292,7 +293,7 @@ extern SYSTEM_INFO system_info; /* The title on program start. */ extern char *old_title; -extern BOOL display_title; +extern bool display_title; extern HANDLE hMainThread; extern HANDLE hMainProc; |