From 61c7294e59c8f92f81f5f082425a82dbc386d541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B8=CC=86=20=D0=9F?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=BE=D0=B2?= Date: Sun, 14 Apr 2019 20:40:45 +0300 Subject: [PATCH 01/50] Add MSYS2 triplet --- compile | 4 ++-- config.guess | 3 +++ config.rpath | 8 +++---- config/dfp.m4 | 3 ++- config/elf.m4 | 2 +- config/lthostflags.m4 | 2 +- config/mmap.m4 | 4 ++-- config/picflag.m4 | 2 ++ config/tcl.m4 | 4 ++-- configure | 22 +++++++++--------- configure.ac | 20 ++++++++--------- libtool.m4 | 36 +++++++++++++++++------------- ltmain.sh | 52 +++++++++++++++++++++---------------------- ltoptions.m4 | 2 +- newlib/configure | 2 +- newlib/configure.host | 8 +++---- 16 files changed, 93 insertions(+), 81 deletions(-) diff --git a/compile b/compile index a85b723c7e..a4ecdb2519 100755 --- a/compile +++ b/compile @@ -53,7 +53,7 @@ func_file_conv () MINGW*) file_conv=mingw ;; - CYGWIN*) + CYGWIN*|MSYS*) file_conv=cygwin ;; *) @@ -67,7 +67,7 @@ func_file_conv () mingw/*) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; - cygwin/*) + cygwin/*|msys/*) file=`cygpath -m "$file" || echo "$file"` ;; wine/*) diff --git a/config.guess b/config.guess index 1972fda8eb..a922fa3881 100755 --- a/config.guess +++ b/config.guess @@ -914,6 +914,9 @@ EOF amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-pc-cygwin exit ;; + amd64:MSYS*:*:* | x86_64:MSYS*:*:*) + echo x86_64-unknown-msys + exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2"$(echo "$UNAME_RELEASE"|sed -e 's/[^.]*//')" exit ;; diff --git a/config.rpath b/config.rpath index 4dea75957c..4f12c27e02 100755 --- a/config.rpath +++ b/config.rpath @@ -109,7 +109,7 @@ hardcode_direct=no hardcode_minus_L=no case "$host_os" in - cygwin* | mingw* | pw32*) + cygwin* | msys* | mingw* | pw32*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. @@ -149,7 +149,7 @@ if test "$with_gnu_ld" = yes; then ld_shlibs=no fi ;; - cygwin* | mingw* | pw32*) + cygwin* | msys* | mingw* | pw32*) # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' @@ -268,7 +268,7 @@ else ;; bsdi4*) ;; - cygwin* | mingw* | pw32*) + cygwin* | msys* | mingw* | pw32*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is @@ -437,7 +437,7 @@ case "$host_os" in ;; bsdi4*) ;; - cygwin* | mingw* | pw32*) + cygwin* | msys* | mingw* | pw32*) shrext=.dll ;; darwin* | rhapsody*) diff --git a/config/dfp.m4 b/config/dfp.m4 index 5b29089cec..b03bcf0ccb 100644 --- a/config/dfp.m4 +++ b/config/dfp.m4 @@ -23,7 +23,8 @@ Valid choices are 'yes', 'bid', 'dpd', and 'no'.]) ;; powerpc*-*-linux* | i?86*-*-linux* | x86_64*-*-linux* | s390*-*-linux* | \ i?86*-*-elfiamcu | i?86*-*-gnu* | \ i?86*-*-mingw* | x86_64*-*-mingw* | \ - i?86*-*-cygwin* | x86_64*-*-cygwin*) + i?86*-*-cygwin* | x86_64*-*-cygwin* | \ + i?86*-*-msys* | x86_64*-*-msys*) enable_decimal_float=yes ;; *) diff --git a/config/elf.m4 b/config/elf.m4 index 5f5cd88da0..b8491de764 100644 --- a/config/elf.m4 +++ b/config/elf.m4 @@ -15,7 +15,7 @@ AC_REQUIRE([AC_CANONICAL_TARGET]) target_elf=no case $target in - *-darwin* | *-aix* | *-cygwin* | *-mingw* | *-aout* | *-*coff* | \ + *-darwin* | *-aix* | *-cygwin* | *-msys* | *-mingw* | *-aout* | *-*coff* | \ *-msdosdjgpp* | *-vms* | *-wince* | *-*-pe* | \ alpha*-dec-osf* | hppa[[12]]*-*-hpux* | \ nvptx-*-none) diff --git a/config/lthostflags.m4 b/config/lthostflags.m4 index bc0f59ee79..ad977d43dc 100644 --- a/config/lthostflags.m4 +++ b/config/lthostflags.m4 @@ -13,7 +13,7 @@ AC_DEFUN([ACX_LT_HOST_FLAGS], [ AC_REQUIRE([AC_CANONICAL_SYSTEM]) case $host in - *-cygwin* | *-mingw*) + *-cygwin* | *-msys* | *-mingw*) # 'host' will be top-level target in the case of a target lib, # we must compare to with_cross_host to decide if this is a native # or cross-compiler and select where to install dlls appropriately. diff --git a/config/mmap.m4 b/config/mmap.m4 index fba0d9d365..df2c778524 100644 --- a/config/mmap.m4 +++ b/config/mmap.m4 @@ -42,7 +42,7 @@ else # Systems known to be in this category are Windows (all variants), # VMS, and Darwin. case "$host_os" in - *vms* | cygwin* | pe | mingw* | darwin* | ultrix* | hpux10* | hpux11.00) + *vms* | cygwin* | msys* | pe | mingw* | darwin* | ultrix* | hpux10* | hpux11.00) gcc_cv_func_mmap_dev_zero=no ;; *) gcc_cv_func_mmap_dev_zero=yes;; @@ -74,7 +74,7 @@ else # above for use of /dev/zero. # Systems known to be in this category are Windows, VMS, and SCO Unix. case "$host_os" in - *vms* | cygwin* | pe | mingw* | sco* | udk* ) + *vms* | cygwin* | msys* | pe | mingw* | sco* | udk* ) gcc_cv_func_mmap_anon=no ;; *) gcc_cv_func_mmap_anon=yes;; diff --git a/config/picflag.m4 b/config/picflag.m4 index 614421d2a9..9d507ba3f8 100644 --- a/config/picflag.m4 +++ b/config/picflag.m4 @@ -25,6 +25,8 @@ case "${$2}" in ;; i[[34567]]86-*-cygwin* | x86_64-*-cygwin*) ;; + i[[34567]]86-*-msys* | x86_64-*-msys*) + ;; i[[34567]]86-*-mingw* | x86_64-*-mingw*) ;; i[[34567]]86-*-nto-qnx*) diff --git a/config/tcl.m4 b/config/tcl.m4 index 4542a4b23d..209bd8d9b8 100644 --- a/config/tcl.m4 +++ b/config/tcl.m4 @@ -33,7 +33,7 @@ AC_DEFUN([SC_PATH_TCLCONFIG], [ # First check to see if --with-tcl was specified. case "${host}" in - *-*-cygwin*) platDir="win" ;; + *-*-cygwin* | *-*-msys*) platDir="win" ;; *) platDir="unix" ;; esac if test x"${with_tclconfig}" != x ; then @@ -165,7 +165,7 @@ AC_DEFUN([SC_PATH_TKCONFIG], [ # then check for a private Tk library case "${host}" in - *-*-cygwin*) platDir="win" ;; + *-*-cygwin* | *-*-msys*) platDir="win" ;; *) platDir="unix" ;; esac if test x"${ac_cv_c_tkconfig}" = x ; then diff --git a/configure b/configure index 9477153056..1474838bd6 100755 --- a/configure +++ b/configure @@ -3088,7 +3088,7 @@ fi # Configure extra directories which are host specific case "${host}" in - *-cygwin*) + *-cygwin* | *-msys*) configdirs="$configdirs libtermcap" ;; esac @@ -3609,7 +3609,7 @@ esac # Disable the go frontend on systems where it is known to not work. Please keep # this in sync with contrib/config-list.mk. case "${target}" in -*-*-darwin* | *-*-cygwin* | *-*-mingw* | *-*-aix*) +*-*-darwin* | *-*-cygwin* | *-*-msys* | *-*-mingw* | *-*-aix*) unsupported_languages="$unsupported_languages go" ;; esac @@ -3622,7 +3622,7 @@ if test x$enable_libgo = x; then # PR 46986 noconfigdirs="$noconfigdirs target-libgo" ;; - *-*-cygwin* | *-*-mingw*) + *-*-cygwin* | *-*-msys* | *-*-mingw*) noconfigdirs="$noconfigdirs target-libgo" ;; *-*-aix*) @@ -3894,7 +3894,7 @@ case "${target}" in i[3456789]86-*-mingw*) target_configdirs="$target_configdirs target-winsup" ;; - *-*-cygwin*) + *-*-cygwin* | *-*-msys*) target_configdirs="$target_configdirs target-libtermcap target-winsup" noconfigdirs="$noconfigdirs target-libgloss" # always build newlib if winsup directory is present. @@ -4038,7 +4038,7 @@ case "${host}" in i[3456789]86-*-msdosdjgpp*) host_makefile_frag="config/mh-djgpp" ;; - *-cygwin*) + *-cygwin* | *-msys*) { $as_echo "$as_me:${as_lineno-$LINENO}: checking to see if cat works as expected" >&5 $as_echo_n "checking to see if cat works as expected... " >&6; } @@ -6206,7 +6206,7 @@ fi target_elf=no case $target in - *-darwin* | *-aix* | *-cygwin* | *-mingw* | *-aout* | *-*coff* | \ + *-darwin* | *-aix* | *-cygwin* | *-msys* | *-mingw* | *-aout* | *-*coff* | \ *-msdosdjgpp* | *-vms* | *-wince* | *-*-pe* | \ alpha*-dec-osf* | hppa[12]*-*-hpux* | \ nvptx-*-none) @@ -6224,7 +6224,7 @@ if test $target_elf = yes; then : else if test x"$default_enable_lto" = x"yes" ; then case $target in - *-apple-darwin9* | *-cygwin* | *-mingw* | *djgpp*) ;; + *-apple-darwin9* | *-cygwin* | *-msys* | *-mingw* | *djgpp*) ;; # On other non-ELF platforms, LTO has yet to be validated. *) enable_lto=no ;; esac @@ -6235,7 +6235,7 @@ else # warn during gcc/ subconfigure; unless you're bootstrapping with # -flto it won't be needed until after installation anyway. case $target in - *-cygwin* | *-mingw* | *-apple-darwin* | *djgpp*) ;; + *-cygwin* | *-msys* | *-mingw* | *-apple-darwin* | *djgpp*) ;; *) if test x"$enable_lto" = x"yes"; then as_fn_error $? "LTO support is not enabled for this target." "$LINENO" 5 fi @@ -6245,7 +6245,7 @@ else # Among non-ELF, only Windows platforms support the lto-plugin so far. # Build it unless LTO was explicitly disabled. case $target in - *-cygwin* | *-mingw*) build_lto_plugin=$enable_lto ;; + *-cygwin* | *-msys* | *-mingw*) build_lto_plugin=$enable_lto ;; *) ;; esac @@ -7130,7 +7130,7 @@ rm -f conftest* case "${host}" in *-*-hpux*) RPATH_ENVVAR=SHLIB_PATH ;; *-*-darwin*) RPATH_ENVVAR=DYLD_LIBRARY_PATH ;; - *-*-mingw* | *-*-cygwin ) RPATH_ENVVAR=PATH ;; + *-*-mingw* | *-*-cygwin | *-msys ) RPATH_ENVVAR=PATH ;; *) RPATH_ENVVAR=LD_LIBRARY_PATH ;; esac @@ -7648,7 +7648,7 @@ case " $target_configdirs " in case " $target_configargs " in *" --with-newlib "*) case "$target" in - *-cygwin*) + *-cygwin* | *-msys*) FLAGS_FOR_TARGET=$FLAGS_FOR_TARGET' -L$$r/$(TARGET_SUBDIR)/winsup/cygwin -isystem $$s/winsup/cygwin/include' ;; esac diff --git a/configure.ac b/configure.ac index 05ddf69870..3ed8a1b888 100644 --- a/configure.ac +++ b/configure.ac @@ -409,7 +409,7 @@ AC_ARG_ENABLE(compressed_debug_sections, # Configure extra directories which are host specific case "${host}" in - *-cygwin*) + *-cygwin* | *-msys*) configdirs="$configdirs libtermcap" ;; esac @@ -893,7 +893,7 @@ esac # Disable the go frontend on systems where it is known to not work. Please keep # this in sync with contrib/config-list.mk. case "${target}" in -*-*-darwin* | *-*-cygwin* | *-*-mingw* | *-*-aix*) +*-*-darwin* | *-*-cygwin* | *-*-msys* | *-*-mingw* | *-*-aix*) unsupported_languages="$unsupported_languages go" ;; esac @@ -906,7 +906,7 @@ if test x$enable_libgo = x; then # PR 46986 noconfigdirs="$noconfigdirs target-libgo" ;; - *-*-cygwin* | *-*-mingw*) + *-*-cygwin* | *-*-msys* | *-*-mingw*) noconfigdirs="$noconfigdirs target-libgo" ;; *-*-aix*) @@ -1178,7 +1178,7 @@ case "${target}" in i[[3456789]]86-*-mingw*) target_configdirs="$target_configdirs target-winsup" ;; - *-*-cygwin*) + *-*-cygwin* | *-*-msys*) target_configdirs="$target_configdirs target-libtermcap target-winsup" noconfigdirs="$noconfigdirs target-libgloss" # always build newlib if winsup directory is present. @@ -1322,7 +1322,7 @@ case "${host}" in i[[3456789]]86-*-msdosdjgpp*) host_makefile_frag="config/mh-djgpp" ;; - *-cygwin*) + *-cygwin* | *-msys*) ACX_CHECK_CYGWIN_CAT_WORKS host_makefile_frag="config/mh-cygwin" ;; @@ -1809,7 +1809,7 @@ ACX_ELF_TARGET_IFELSE([# ELF platforms build the lto-plugin always. build_lto_plugin=yes ],[if test x"$default_enable_lto" = x"yes" ; then case $target in - *-apple-darwin9* | *-cygwin* | *-mingw* | *djgpp*) ;; + *-apple-darwin9* | *-cygwin* | *-msys* | *-mingw* | *djgpp*) ;; # On other non-ELF platforms, LTO has yet to be validated. *) enable_lto=no ;; esac @@ -1820,7 +1820,7 @@ ACX_ELF_TARGET_IFELSE([# ELF platforms build the lto-plugin always. # warn during gcc/ subconfigure; unless you're bootstrapping with # -flto it won't be needed until after installation anyway. case $target in - *-cygwin* | *-mingw* | *-apple-darwin* | *djgpp*) ;; + *-cygwin* | *-msys*| *-mingw* | *-apple-darwin* | *djgpp*) ;; *) if test x"$enable_lto" = x"yes"; then AC_MSG_ERROR([LTO support is not enabled for this target.]) fi @@ -1830,7 +1830,7 @@ ACX_ELF_TARGET_IFELSE([# ELF platforms build the lto-plugin always. # Among non-ELF, only Windows platforms support the lto-plugin so far. # Build it unless LTO was explicitly disabled. case $target in - *-cygwin* | *-mingw*) build_lto_plugin=$enable_lto ;; + *-cygwin* | *-msys* | *-mingw*) build_lto_plugin=$enable_lto ;; *) ;; esac ]) @@ -2652,7 +2652,7 @@ rm -f conftest* case "${host}" in *-*-hpux*) RPATH_ENVVAR=SHLIB_PATH ;; *-*-darwin*) RPATH_ENVVAR=DYLD_LIBRARY_PATH ;; - *-*-mingw* | *-*-cygwin ) RPATH_ENVVAR=PATH ;; + *-*-mingw* | *-*-cygwin | *-*-msys ) RPATH_ENVVAR=PATH ;; *) RPATH_ENVVAR=LD_LIBRARY_PATH ;; esac @@ -3165,7 +3165,7 @@ case " $target_configdirs " in case " $target_configargs " in *" --with-newlib "*) case "$target" in - *-cygwin*) + *-cygwin* | *-msys*) FLAGS_FOR_TARGET=$FLAGS_FOR_TARGET' -L$$r/$(TARGET_SUBDIR)/winsup/cygwin -isystem $$s/winsup/cygwin/include' ;; esac diff --git a/libtool.m4 b/libtool.m4 index a216bb14e9..0d6d17a668 100644 --- a/libtool.m4 +++ b/libtool.m4 @@ -1521,7 +1521,7 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl lt_cv_sys_max_cmd_len=-1; ;; - cygwin* | mingw* | cegcc*) + cygwin* | msys* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, @@ -1763,7 +1763,7 @@ else lt_cv_dlopen_libs= ;; - cygwin*) + cygwin* | msys*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; @@ -2234,14 +2234,14 @@ bsdi[[45]]*) # libtool to hard-code these into programs ;; -cygwin* | mingw* | pw32* | cegcc*) +cygwin* | msys* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$host_os in - yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) + yes,cygwin* | yes,msys* | yes,mingw* | yes,pw32* | yes,cegcc*) library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ @@ -2262,6 +2262,12 @@ cygwin* | mingw* | pw32* | cegcc*) cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) + ;; + msys*) + # Msys DLLs use 'msys-' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/msys-/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) ;; @@ -3021,7 +3027,7 @@ bsdi[[45]]*) lt_cv_file_magic_test_file=/shlib/libc.so ;; -cygwin*) +cygwin* | msys*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' @@ -3307,7 +3313,7 @@ AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in -*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) +*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-msys* | *-*-haiku* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) @@ -3382,7 +3388,7 @@ case $host_os in aix*) symcode='[[BCDT]]' ;; -cygwin* | mingw* | pw32* | cegcc*) +cygwin* | msys* | mingw* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) @@ -3629,7 +3635,7 @@ m4_if([$1], [CXX], [ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; - mingw* | cygwin* | os2* | pw32* | cegcc*) + mingw* | cygwin* | msys* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style @@ -3942,7 +3948,7 @@ m4_if([$1], [CXX], [ # PIC is the default for these OSes. ;; - mingw* | cygwin* | pw32* | os2* | cegcc*) + mingw* | cygwin* | msys* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style @@ -4025,7 +4031,7 @@ m4_if([$1], [CXX], [ fi ;; - mingw* | cygwin* | pw32* | os2* | cegcc*) + mingw* | cygwin* | msys* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], @@ -4258,7 +4264,7 @@ m4_if([$1], [CXX], [ pw32*) _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" ;; - cygwin* | mingw* | cegcc*) + cygwin* | msys* | mingw* | cegcc*) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' ;; *) @@ -4310,7 +4316,7 @@ dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | msys* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. @@ -4425,7 +4431,7 @@ _LT_EOF fi ;; - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | msys* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' @@ -4798,7 +4804,7 @@ _LT_EOF _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | msys* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is @@ -5742,7 +5748,7 @@ if test "$_lt_caught_CXX_error" != yes; then esac ;; - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | msys* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' diff --git a/ltmain.sh b/ltmain.sh index 9503ec85d7..307a33979e 100644 --- a/ltmain.sh +++ b/ltmain.sh @@ -976,7 +976,7 @@ func_enable_tag () case $host in - *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* ) + *cygwin* | *msys* | *mingw* | *pw32* | *cegcc* | *solaris2* ) # don't eliminate duplications in $postdeps and $predeps opt_duplicate_compiler_generated_deps=: ;; @@ -1453,7 +1453,7 @@ func_mode_compile () # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in - cygwin* | mingw* | pw32* | os2* | cegcc*) + cygwin* | msys* | mingw* | pw32* | os2* | cegcc*) pic_mode=default ;; esac @@ -2279,7 +2279,7 @@ func_mode_install () 'exit $?' tstripme="$stripme" case $host_os in - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | msys* | mingw* | pw32* | cegcc*) case $realname in *.dll.a) tstripme="" @@ -2385,7 +2385,7 @@ func_mode_install () # Do a test to see if this is really a libtool program. case $host in - *cygwin* | *mingw*) + *cygwin* | *msys* | *mingw*) if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" wrapper=$func_ltwrapper_scriptname_result @@ -2460,7 +2460,7 @@ func_mode_install () # remove .exe since cygwin /usr/bin/install will append another # one anyway case $install_prog,$host in - */usr/bin/install*,*cygwin*) + */usr/bin/install*,*cygwin*|*/usr/bin/install*,*msys*) case $file:$destfile in *.exe:*.exe) # this is ok @@ -2595,7 +2595,7 @@ extern \"C\" { $RM $export_symbols ${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' < "$nlist" > "$export_symbols" case $host in - *cygwin* | *mingw* | *cegcc* ) + *cygwin* | *msys* | *mingw* | *cegcc* ) echo EXPORTS > "$output_objdir/$outputname.def" cat "$export_symbols" >> "$output_objdir/$outputname.def" ;; @@ -2607,7 +2607,7 @@ extern \"C\" { $GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T $MV "$nlist"T "$nlist" case $host in - *cygwin* | *mingw* | *cegcc* ) + *cygwin* | *msys* | *mingw* | *cegcc* ) echo EXPORTS > "$output_objdir/$outputname.def" cat "$nlist" >> "$output_objdir/$outputname.def" ;; @@ -2663,7 +2663,7 @@ typedef struct { } lt_dlsymlist; " case $host in - *cygwin* | *mingw* | *cegcc* ) + *cygwin* | *msys* | *mingw* | *cegcc* ) echo >> "$output_objdir/$my_dlsyms" "\ /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation @@ -2749,7 +2749,7 @@ static const void *lt_preloaded_setup() { # Transform the symbol file into the correct name. symfileobj="$output_objdir/${my_outputname}S.$objext" case $host in - *cygwin* | *mingw* | *cegcc* ) + *cygwin* | *msys* | *mingw* | *cegcc* ) if test -f "$output_objdir/$my_outputname.def"; then compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` @@ -3192,7 +3192,7 @@ func_to_host_path () func_to_host_path_result=`( cmd //c echo "$1" ) 2>/dev/null | $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` ;; - *cygwin* ) + *cygwin* | *msys* ) func_to_host_path_result=`cygpath -w "$1" | $SED -e "$lt_sed_naive_backslashify"` ;; @@ -3265,7 +3265,7 @@ func_to_host_pathlist () ( cmd //c echo "$func_to_host_pathlist_tmp1" ) 2>/dev/null | $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` ;; - *cygwin* ) + *cygwin* | *msys* ) func_to_host_pathlist_result=`cygpath -w -p "$func_to_host_pathlist_tmp1" | $SED -e "$lt_sed_naive_backslashify"` ;; @@ -3571,7 +3571,7 @@ main (int argc, char *argv[]) { EOF case "$host" in - *mingw* | *cygwin* ) + *mingw* | *cygwin* | *msys* ) # make stdout use "unix" line endings echo " setmode(1,_O_BINARY);" ;; @@ -4233,7 +4233,7 @@ func_mode_link () { $opt_debug case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + *-*-cygwin* | *-*-msys* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # which system we are compiling for in order to pass an extra @@ -4713,7 +4713,7 @@ func_mode_link () ;; esac case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + *-*-cygwin* | *-*-msys* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` case :$dllsearchpath: in *":$dir:"*) ;; @@ -4733,7 +4733,7 @@ func_mode_link () -l*) if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) + *-*-cygwin* | *-*-msys* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) # These systems don't actually have a C or math library (as such) continue ;; @@ -4813,7 +4813,7 @@ func_mode_link () -no-install) case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) + *-*-cygwin* | *-*-msys* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) # The PATH hackery in wrapper scripts is required on Windows # and Darwin in order for the loader to find any dlls it needs. func_warning "\`-no-install' is ignored for $host" @@ -5772,7 +5772,7 @@ func_mode_link () if test -n "$library_names" && { test "$use_static_libs" = no || test -z "$old_library"; }; then case $host in - *cygwin* | *mingw* | *cegcc*) + *cygwin* | *msys* | *mingw* | *cegcc*) # No point in relinking DLLs because paths are not encoded notinst_deplibs="$notinst_deplibs $lib" need_relink=no @@ -5842,7 +5842,7 @@ func_mode_link () elif test -n "$soname_spec"; then # bleh windows case $host in - *cygwin* | mingw* | *cegcc*) + *cygwin* | msys* | mingw* | *cegcc*) func_arith $current - $age major=$func_arith_result versuffix="-$major" @@ -6693,7 +6693,7 @@ func_mode_link () if test "$build_libtool_libs" = yes; then if test -n "$rpath"; then case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) + *-*-cygwin* | *-*-msys* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) @@ -7194,7 +7194,7 @@ EOF orig_export_symbols= case $host_os in - cygwin* | mingw* | cegcc*) + cygwin* | msys* | mingw* | cegcc*) if test -n "$export_symbols" && test -z "$export_symbols_regex"; then # exporting using user supplied symfile if test "x`$SED 1q $export_symbols`" != xEXPORTS; then @@ -7710,7 +7710,7 @@ EOF prog) case $host in - *cygwin*) func_stripname '' '.exe' "$output" + *cygwin* | *msys*) func_stripname '' '.exe' "$output" output=$func_stripname_result.exe;; esac test -n "$vinfo" && \ @@ -7823,7 +7823,7 @@ EOF esac fi case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + *-*-cygwin* | *-*-msys* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$libdir:"*) ;; @@ -7901,7 +7901,7 @@ EOF # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. wrappers_required=no ;; - *cygwin* | *mingw* ) + *cygwin* | *msys* | *mingw* ) if test "$build_libtool_libs" != yes; then wrappers_required=no fi @@ -8029,14 +8029,14 @@ EOF esac # test for cygwin because mv fails w/o .exe extensions case $host in - *cygwin*) + *cygwin* | *msys*) exeext=.exe func_stripname '' '.exe' "$outputname" outputname=$func_stripname_result ;; *) exeext= ;; esac case $host in - *cygwin* | *mingw* ) + *cygwin* | *msys* | *mingw* ) func_dirname_and_basename "$output" "" "." output_name=$func_basename_result output_path=$func_dirname_result @@ -8343,7 +8343,7 @@ EOF # tests/bindir.at for full details. tdlname=$dlname case $host,$output,$installed,$module,$dlname in - *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) + *cygwin*,*lai,yes,no,*.dll | *msys*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) # If a -bindir argument was supplied, place the dll there. if test "x$bindir" != x ; then diff --git a/ltoptions.m4 b/ltoptions.m4 index 5ef12ced2a..5e7bc34702 100644 --- a/ltoptions.m4 +++ b/ltoptions.m4 @@ -126,7 +126,7 @@ LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in -*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) +*-*-cygwin* | *-*-msys* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) diff --git a/newlib/configure b/newlib/configure index 6a542bb884..00de6b93a2 100755 --- a/newlib/configure +++ b/newlib/configure @@ -4283,7 +4283,7 @@ else fi -ac_ext=c +:cn ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' diff --git a/newlib/configure.host b/newlib/configure.host index 3861834663..2023e58f57 100644 --- a/newlib/configure.host +++ b/newlib/configure.host @@ -195,7 +195,7 @@ case "${host_cpu}" in shared_machine_dir=shared_x86 # Don't use for these since they provide their own setjmp. case ${host} in - *-*-sco* | *-*-cygwin*) + *-*-sco* | *-*-cygwin* | *-*-msys*) ;; *) mach_add_setjmp=true @@ -407,7 +407,7 @@ fi if [ "x${newlib_mb}" = "x" ]; then case "${host}" in - *-*-cygwin*) + *-*-cygwin*|*-*-msys*) newlib_mb=yes ;; esac @@ -426,7 +426,7 @@ fi # THIS TABLE IS ALPHA SORTED. KEEP IT THAT WAY. case "${host}" in - *-*-cygwin*) + *-*-cygwin* | *-*-msys*) posix_dir=posix xdr_dir=xdr ;; @@ -589,7 +589,7 @@ esac # THIS TABLE IS ALPHA SORTED. KEEP IT THAT WAY. case "${host}" in - *-*-cygwin*) + *-*-cygwin* | *-*-msys*) test -z "$cygwin_srcdir" && cygwin_srcdir="${abs_newlib_basedir}/../winsup/cygwin" export cygwin_srcdir default_newlib_io_c99_formats="yes" From e6895db114ffaa2c877b38c22e7d7eede8b79de5 Mon Sep 17 00:00:00 2001 From: Kaleb Barrett Date: Sun, 14 Mar 2021 18:58:55 -0500 Subject: [PATCH 02/50] Fix msys library name in import libraries Cygwin's speclib doesn't handle dashes or dots. However, we are about to rename the output file name from `cygwin1.dll` to `msys-2.0.dll`. Let's preemptively fix up all the import libraries that would link against `msys_2_0.dll` to correctly link against `msys-2.0.dll` instead. --- winsup/cygwin/scripts/speclib | 1 + 1 file changed, 1 insertion(+) diff --git a/winsup/cygwin/scripts/speclib b/winsup/cygwin/scripts/speclib index 41a3a8e139..42a02c511b 100755 --- a/winsup/cygwin/scripts/speclib +++ b/winsup/cygwin/scripts/speclib @@ -38,6 +38,7 @@ while (<$nm_fd>) { study; if (/ I _?(.*)_dll_iname/o) { $dllname = $1; + $dllname =~ s/_2_0/-2.0/; } else { my ($file, $member, $symbol) = m%^([^:]*):([^:]*(?=:))?.* T (.*)%o; next if !defined($symbol) || $symbol =~ $exclude_regex; From e501600b6d38a8698be4e6b6d68f6caa9632d822 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B8=CC=86=20=D0=9F?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=BE=D0=B2?= Date: Sun, 14 Apr 2019 21:09:17 +0300 Subject: [PATCH 03/50] Rename dll from cygwin to msys --- winsup/cygserver/transport_pipes.h | 4 +++ winsup/cygwin/Makefile.am | 27 ++++++++++--------- winsup/cygwin/crt0.c | 8 ++++++ winsup/cygwin/cygwin.din | 6 ++--- winsup/cygwin/cygwin.sc.in | 4 +++ winsup/cygwin/dcrt0.cc | 4 +++ winsup/cygwin/dlfcn.cc | 5 ++++ winsup/cygwin/dll_init.cc | 4 +++ winsup/cygwin/dtable.cc | 6 +++++ winsup/cygwin/exceptions.cc | 4 +-- winsup/cygwin/fhandler/pipe.cc | 4 +++ winsup/cygwin/fhandler/pty.cc | 20 ++++++++++++++ winsup/cygwin/hookapi.cc | 4 +++ winsup/cygwin/include/cygwin/cygwin_dll.h | 10 +++---- winsup/cygwin/include/cygwin/version.h | 8 ++++++ winsup/cygwin/lib/_cygwin_crt0_common.cc | 4 +++ winsup/cygwin/lib/crt0.h | 4 +++ winsup/cygwin/lib/cygwin_attach_dll.c | 8 ++++++ winsup/cygwin/lib/cygwin_crt0.c | 8 ++++++ .../cygwin/local_includes/cygserver_setpwd.h | 4 +++ winsup/cygwin/scripts/mkvers.sh | 6 ++--- winsup/cygwin/sec/auth.cc | 8 +++--- winsup/cygwin/syscalls.cc | 4 +-- winsup/cygwin/syslog.cc | 4 +++ winsup/cygwin/winver.rc | 2 +- winsup/testsuite/winsup.api/cygload.cc | 10 +++---- winsup/testsuite/winsup.api/cygload.h | 2 +- winsup/utils/ldd.cc | 2 +- winsup/utils/loadlib.h | 6 ++--- winsup/utils/mingw/cygcheck.cc | 27 +++++++++---------- winsup/utils/mingw/strace.cc | 9 +++---- winsup/utils/path.cc | 12 ++++----- winsup/utils/ssp.c | 8 +++--- 33 files changed, 174 insertions(+), 72 deletions(-) diff --git a/winsup/cygserver/transport_pipes.h b/winsup/cygserver/transport_pipes.h index e101623d24..66272bc86c 100644 --- a/winsup/cygserver/transport_pipes.h +++ b/winsup/cygserver/transport_pipes.h @@ -11,7 +11,11 @@ details. */ #ifndef _TRANSPORT_PIPES_H #define _TRANSPORT_PIPES_H +#ifdef __MSYS__ +#define PIPE_NAME_PREFIX L"\\\\.\\pipe\\msys-" +#else #define PIPE_NAME_PREFIX L"\\\\.\\pipe\\cygwin-" +#endif #define PIPE_NAME_SUFFIX L"-lpc" /* Named pipes based transport, for security on NT */ diff --git a/winsup/cygwin/Makefile.am b/winsup/cygwin/Makefile.am index 376c79fc3c..e65e675bcd 100644 --- a/winsup/cygwin/Makefile.am +++ b/winsup/cygwin/Makefile.am @@ -37,12 +37,12 @@ newlib_build=$(target_builddir)/newlib toollibdir=$(tooldir)/lib toolincludedir=$(tooldir)/include -# Parameters used in building the cygwin.dll. +# Parameters used in building the msys-2.0.dll. -DLL_NAME=cygwin1.dll -NEW_DLL_NAME=new-cygwin1.dll -DEF_FILE=cygwin.def -LIB_NAME=libcygwin.a +DLL_NAME=msys-2.0.dll +NEW_DLL_NAME=new-msys-2.0.dll +DEF_FILE=msys.def +LIB_NAME=libmsys-2.0.a # # sources @@ -584,16 +584,16 @@ LIBSERVER = $(cygserver_blddir)/libcygserver.a $(LIBSERVER): $(MAKE) -C $(cygserver_blddir) libcygserver.a -# We build as new-cygwin1.dll and rename at install time to overcome native +# We build as new-msys-2.0.dll and rename at install time to overcome native # rebuilding issues (we don't want the build tools to see a partially built -# cygwin1.dll and attempt to use it instead of the old one). +# msys-2.0.dll and attempt to use it instead of the old one). # linker script LDSCRIPT=cygwin.sc $(LDSCRIPT): $(LDSCRIPT).in $(AM_V_GEN)$(CC) -E - -P < $^ -o $@ -# cygwin dll +# msys-2.0 dll # Set PE and export table header timestamps to zero for reproducible builds. $(NEW_DLL_NAME): $(LDSCRIPT) libdll.a $(VERSION_OFILES) $(LIBSERVER)\ $(newlib_build)/libm.a $(newlib_build)/libc.a @@ -602,18 +602,18 @@ $(NEW_DLL_NAME): $(LDSCRIPT) libdll.a $(VERSION_OFILES) $(LIBSERVER)\ -Wl,--gc-sections -nostdlib -Wl,-T$(LDSCRIPT) \ -Wl,--dynamicbase -static \ $${SOURCE_DATE_EPOCH:+-Wl,--no-insert-timestamp} \ - -Wl,--heap=0 -Wl,--out-implib,cygdll.a -shared -o $@ \ + -Wl,--heap=0 -Wl,--out-implib,msysdll.a -shared -o $@ \ -e @DLL_ENTRY@ $(DEF_FILE) \ -Wl,-whole-archive libdll.a -Wl,-no-whole-archive \ $(VERSION_OFILES) \ $(LIBSERVER) \ $(newlib_build)/libm.a \ $(newlib_build)/libc.a \ - -lgcc -lkernel32 -lntdll -Wl,-Map,cygwin.map + -lgcc -lkernel32 -lntdll -Wl,-Map,msys.map @$(MKDIR_P) ${target_builddir}/winsup/testsuite/testinst/bin/ $(AM_V_at)$(INSTALL_PROGRAM) $(NEW_DLL_NAME) ${target_builddir}/winsup/testsuite/testinst/bin/$(DLL_NAME) -# cygwin import library +# msys-2.0 import library toolopts=--cpu=@target_cpu@ --ar=@AR@ --as=@AS@ --nm=@NM@ --objcopy=@OBJCOPY@ $(DEF_FILE): scripts/gendef cygwin.din @@ -626,13 +626,14 @@ sigfe.s: $(DEF_FILE) tlsoffsets LIBCOS=$(addsuffix .o,$(basename $(LIB_FILES))) $(LIB_NAME): $(DEF_FILE) $(LIBCOS) | $(NEW_DLL_NAME) - $(AM_V_GEN)$(srcdir)/scripts/mkimport $(toolopts) $(NEW_FUNCTIONS) $@ cygdll.a $(wordlist 2,99,$^) + $(AM_V_GEN)$(srcdir)/scripts/mkimport $(toolopts) $(NEW_FUNCTIONS) $@ msysdll.a $(wordlist 2,99,$^) # sublibs # import libraries for some subset of symbols indicated by given objects speclib=\ $(srcdir)/scripts/speclib $(toolopts) \ --exclude='cygwin' \ + --exclude='msys' \ --exclude='(?i:dll)' \ --exclude='reloc' \ --exclude='^main$$' \ @@ -679,7 +680,7 @@ all-local: $(LIB_NAME) $(SUBLIBS) clean-local: -rm -f $(BUILT_SOURCES) -rm -f $(DEF_FILE) sigfe.s - -rm -f cygwin.sc cygdll.a cygwin.map + -rm -f cygwin.sc msysdll.a msys.map -rm -f $(NEW_DLL_NAME) -rm -f $(LIB_NAME) $(SUBLIBS) -rm -f version.cc diff --git a/winsup/cygwin/crt0.c b/winsup/cygwin/crt0.c index 1096e58970..3160df4491 100644 --- a/winsup/cygwin/crt0.c +++ b/winsup/cygwin/crt0.c @@ -9,12 +9,20 @@ details. */ extern int main (int argc, char **argv); +#ifdef __MSYS__ +void msys_crt0 (int (*main) (int, char **)); +#else void cygwin_crt0 (int (*main) (int, char **)); +#endif void mainCRTStartup () { +#ifdef __MSYS__ + msys_crt0 (main); +#else cygwin_crt0 (main); +#endif /* These are never actually called. They are just here to force the inclusion of things like -lbinmode. */ diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din index 9e354acc61..76e88df2fc 100644 --- a/winsup/cygwin/cygwin.din +++ b/winsup/cygwin/cygwin.din @@ -1,4 +1,4 @@ -LIBRARY "cygwin1.dll" BASE=0x180040000 +LIBRARY "msys-2.0.dll" BASE=0x180040000 EXPORTS # Exported variables @@ -404,8 +404,8 @@ cygwin_attach_handle_to_fd SIGFE cygwin_conv_path SIGFE cygwin_conv_path_list SIGFE cygwin_create_path SIGFE -cygwin_detach_dll SIGFE_MAYBE -cygwin_dll_init NOSIGFE +msys_detach_dll SIGFE_MAYBE +msys_dll_init NOSIGFE cygwin_internal NOSIGFE cygwin_logon_user SIGFE cygwin_posix_path_list_p NOSIGFE diff --git a/winsup/cygwin/cygwin.sc.in b/winsup/cygwin/cygwin.sc.in index 69526f5d8a..4dc5daed8d 100644 --- a/winsup/cygwin/cygwin.sc.in +++ b/winsup/cygwin/cygwin.sc.in @@ -1,6 +1,10 @@ #ifdef __x86_64__ OUTPUT_FORMAT(pei-x86-64) +# ifdef __MSYS__ +SEARCH_DIR("/usr/x86_64-pc-msys/lib/w32api"); SEARCH_DIR("=/usr/lib/w32api"); +# else SEARCH_DIR("/usr/x86_64-pc-cygwin/lib/w32api"); SEARCH_DIR("=/usr/lib/w32api"); +# endif #else #error unimplemented for this target #endif diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index ff7e6ec50f..16b624eab5 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -1077,7 +1077,11 @@ dll_crt0 (per_process *uptr) See winsup/testsuite/cygload for an example of how to use cygwin1.dll from MSVC and non-cygwin MinGW applications. */ extern "C" void +#ifdef __MSYS__ +msys_dll_init () +#else cygwin_dll_init () +#endif { static int _fmode; diff --git a/winsup/cygwin/dlfcn.cc b/winsup/cygwin/dlfcn.cc index fb70524735..7367d29713 100644 --- a/winsup/cygwin/dlfcn.cc +++ b/winsup/cygwin/dlfcn.cc @@ -147,8 +147,13 @@ collect_basenames (pathfinder::basenamelist & basenames, /* If the basename starts with "lib", ... */ if (!strncmp (basename, "lib", 3)) { +#ifdef __MSYS__ + /* ... replace "lib" with "msys-", before ... */ + basenames.appendv ("msys-", 5, basename+3, baselen-3, ext, extlen, NULL); +#else /* ... replace "lib" with "cyg", before ... */ basenames.appendv ("cyg", 3, basename+3, baselen-3, ext, extlen, NULL); +#endif } /* ... using original basename with new suffix. */ basenames.appendv (basename, baselen, ext, extlen, NULL); diff --git a/winsup/cygwin/dll_init.cc b/winsup/cygwin/dll_init.cc index 1a047511f8..7c5f8cc9fd 100644 --- a/winsup/cygwin/dll_init.cc +++ b/winsup/cygwin/dll_init.cc @@ -874,7 +874,11 @@ dll_dllcrt0_1 (VOID *x) } extern "C" void +#ifdef __MSYS__ +msys_detach_dll (dll *) +#else cygwin_detach_dll (dll *) +#endif { HANDLE retaddr; if (_my_tls.isinitialized ()) diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc index 9508f3e0bb..3c40e0fa3d 100644 --- a/winsup/cygwin/dtable.cc +++ b/winsup/cygwin/dtable.cc @@ -998,9 +998,15 @@ handle_to_fn (HANDLE h, char *posix_fn) if (wcsncasecmp (w32, DEV_NAMED_PIPE, DEV_NAMED_PIPE_LEN) == 0) { w32 += DEV_NAMED_PIPE_LEN; +#ifdef __MSYS__ + if (wcsncmp (w32, L"msys-", WCLEN (L"msys-")) != 0) + return false; + w32 += WCLEN (L"msys-"); +#else if (wcsncmp (w32, L"cygwin-", WCLEN (L"cygwin-")) != 0) return false; w32 += WCLEN (L"cygwin-"); +#endif /* Check for installation key and trailing dash. */ w32len = cygheap->installation_key.Length / sizeof (WCHAR); if (w32len diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index 9accf3c94f..c734a4df43 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -526,14 +526,14 @@ int exec_prepared_command (PWCHAR command) PWCHAR rawenv = GetEnvironmentStringsW () ; for (PWCHAR p = rawenv; *p != L'\0'; p = wcschr (p, L'\0') + 1) { - if (wcsncmp (p, L"CYGWIN=", wcslen (L"CYGWIN=")) == 0) + if (wcsncmp (p, L"MSYS=", wcslen (L"MSYS=")) == 0) { PWCHAR q = wcsstr (p, L"error_start") ; /* replace 'error_start=...' with '_rror_start=...' */ if (q) { *q = L'_' ; - SetEnvironmentVariableW (L"CYGWIN", p + wcslen (L"CYGWIN=")) ; + SetEnvironmentVariableW (L"MSYS", p + wcslen (L"MSYS=")) ; } break; } diff --git a/winsup/cygwin/fhandler/pipe.cc b/winsup/cygwin/fhandler/pipe.cc index 6a1ef03b69..7244fa4cd5 100644 --- a/winsup/cygwin/fhandler/pipe.cc +++ b/winsup/cygwin/fhandler/pipe.cc @@ -751,7 +751,11 @@ fhandler_pipe::close () return ret; } +#ifdef __MSYS__ +#define PIPE_INTRO "\\\\.\\pipe\\msys-" +#else #define PIPE_INTRO "\\\\.\\pipe\\cygwin-" +#endif /* Create a pipe, and return handles to the read and write ends, just like CreatePipe, but ensure that the write end permits diff --git a/winsup/cygwin/fhandler/pty.cc b/winsup/cygwin/fhandler/pty.cc index 4f0f718127..eb51c6d392 100644 --- a/winsup/cygwin/fhandler/pty.cc +++ b/winsup/cygwin/fhandler/pty.cc @@ -875,7 +875,11 @@ fhandler_pty_slave::open (int flags, mode_t) pipe_reply repl; DWORD len; +#ifdef __MSYS__ + __small_sprintf (buf, "\\\\.\\pipe\\msys-%S-pty%d-master-ctl", +#else __small_sprintf (buf, "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl", +#endif &cygheap->installation_key, get_minor ()); termios_printf ("dup handles via master control pipe %s", buf); if (!CallNamedPipe (buf, &req, sizeof req, &repl, sizeof repl, @@ -1137,7 +1141,11 @@ fhandler_pty_slave::reset_switch_to_nat_pipe (void) { char pipe[MAX_PATH]; __small_sprintf (pipe, +#ifdef __MSYS__ + "\\\\.\\pipe\\msys-%S-pty%d-master-ctl", +#else "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl", +#endif &cygheap->installation_key, get_minor ()); pipe_request req = { GetCurrentProcessId () }; pipe_reply repl; @@ -2021,7 +2029,11 @@ fhandler_pty_master::close () pipe_reply repl; DWORD len; +#ifdef __MSYS__ + __small_sprintf (buf, "\\\\.\\pipe\\msys-%S-pty%d-master-ctl", +#else __small_sprintf (buf, "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl", +#endif &cygheap->installation_key, get_minor ()); acquire_output_mutex (mutex_timeout); if (master_ctl) @@ -2927,7 +2939,11 @@ fhandler_pty_master::setup () /* Create master control pipe which allows the master to duplicate the pty pipe handles to processes which deserve it. */ +#ifdef __MSYS__ + __small_sprintf (buf, "\\\\.\\pipe\\msys-%S-pty%d-master-ctl", +#else __small_sprintf (buf, "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl", +#endif &cygheap->installation_key, unit); master_ctl = CreateNamedPipe (buf, PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE, @@ -3816,7 +3832,11 @@ fhandler_pty_slave::transfer_input (tty::xfer_dir dir, HANDLE from, tty *ttyp, { char pipe[MAX_PATH]; __small_sprintf (pipe, +#ifdef __MSYS__ + "\\\\.\\pipe\\msys-%S-pty%d-master-ctl", +#else "\\\\.\\pipe\\cygwin-%S-pty%d-master-ctl", +#endif &cygheap->installation_key, ttyp->get_minor ()); pipe_request req = { GetCurrentProcessId () }; pipe_reply repl; diff --git a/winsup/cygwin/hookapi.cc b/winsup/cygwin/hookapi.cc index ee2edbafee..9f31a716c4 100644 --- a/winsup/cygwin/hookapi.cc +++ b/winsup/cygwin/hookapi.cc @@ -379,7 +379,11 @@ hook_or_detect_cygwin (const char *name, const void *fn, WORD& subsys, HANDLE h) for (PIMAGE_IMPORT_DESCRIPTOR pd = pdfirst; pd->FirstThunk; pd++) { if (!ascii_strcasematch (rva (PSTR, map ?: (char *) hm, pd->Name - delta), +#ifdef __MSYS__ + "msys-2.0.dll")) +#else "cygwin1.dll")) +#endif continue; if (!fn) { diff --git a/winsup/cygwin/include/cygwin/cygwin_dll.h b/winsup/cygwin/include/cygwin/cygwin_dll.h index 1e4cf98ba5..b77598bb63 100644 --- a/winsup/cygwin/include/cygwin/cygwin_dll.h +++ b/winsup/cygwin/include/cygwin/cygwin_dll.h @@ -24,8 +24,8 @@ details. */ CDECL_BEGIN \ int Entry (HINSTANCE h, DWORD reason, void *ptr); \ typedef int (*mainfunc) (int, char **, char **); \ - extern PVOID cygwin_attach_dll (HMODULE, mainfunc); \ - extern void cygwin_detach_dll (PVOID); \ + extern PVOID msys_attach_dll (HMODULE, mainfunc); \ + extern void msys_detach_dll (PVOID); \ CDECL_END \ \ static HINSTANCE storedHandle; \ @@ -42,7 +42,7 @@ static int __dllMain (int a __attribute__ ((__unused__)), \ \ static PVOID dll_index; \ \ -int _cygwin_dll_entry (HINSTANCE h, DWORD reason, void *ptr) \ +int _msys_dll_entry (HINSTANCE h, DWORD reason, void *ptr) \ { \ int ret; \ ret = 1; \ @@ -55,7 +55,7 @@ int _cygwin_dll_entry (HINSTANCE h, DWORD reason, void *ptr) \ storedReason = reason; \ storedPtr = ptr; \ __dynamically_loaded = (ptr == NULL); \ - dll_index = cygwin_attach_dll (h, &__dllMain); \ + dll_index = msys_attach_dll (h, &__dllMain); \ if (dll_index == (PVOID) -1) \ ret = 0; \ } \ @@ -66,7 +66,7 @@ int _cygwin_dll_entry (HINSTANCE h, DWORD reason, void *ptr) \ ret = Entry (h, reason, ptr); \ if (ret) \ { \ - cygwin_detach_dll (dll_index); \ + msys_detach_dll (dll_index); \ dll_index = (PVOID) -1; \ } \ } \ diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h index 0d1b17b2e9..97878699ca 100644 --- a/winsup/cygwin/include/cygwin/version.h +++ b/winsup/cygwin/include/cygwin/version.h @@ -502,7 +502,11 @@ details. */ names include the CYGWIN_VERSION_SHARED_DATA version as well as this identifier. */ +#ifdef __MSYS__ +#define CYGWIN_VERSION_DLL_IDENTIFIER "msys-2.0" +#else #define CYGWIN_VERSION_DLL_IDENTIFIER "cygwin1" +#endif /* The Cygwin mount table interface in the Win32 registry also has a version number associated with it in case that is changed in a non-backwards @@ -518,7 +522,11 @@ details. */ /* Identifiers used in the Win32 registry. */ +#ifdef __MSYS__ +#define CYGWIN_INFO_CYGWIN_REGISTRY_NAME "MSYS" +#else #define CYGWIN_INFO_CYGWIN_REGISTRY_NAME "Cygwin" +#endif #define CYGWIN_INFO_INSTALLATIONS_NAME "Installations" /* The default cygdrive prefix. */ diff --git a/winsup/cygwin/lib/_cygwin_crt0_common.cc b/winsup/cygwin/lib/_cygwin_crt0_common.cc index d356a50fba..801b6f91ca 100644 --- a/winsup/cygwin/lib/_cygwin_crt0_common.cc +++ b/winsup/cygwin/lib/_cygwin_crt0_common.cc @@ -73,7 +73,11 @@ struct per_process_cxx_malloc __cygwin_cxx_malloc = and then jump to the dll. */ int +#ifdef __MSYS__ +_msys_crt0_common (MainFunc f, per_process *u) +#else _cygwin_crt0_common (MainFunc f, per_process *u) +#endif { per_process *newu = (per_process *) cygwin_internal (CW_USER_DATA); bool uwasnull; diff --git a/winsup/cygwin/lib/crt0.h b/winsup/cygwin/lib/crt0.h index e599b44934..e81750032b 100644 --- a/winsup/cygwin/lib/crt0.h +++ b/winsup/cygwin/lib/crt0.h @@ -13,7 +13,11 @@ extern "C" { #include "winlean.h" struct per_process; typedef int (*MainFunc) (int argc, char *argv[], char **env); +#ifdef __MSYS__ +int _msys_crt0_common (MainFunc, struct per_process *); +#else int _cygwin_crt0_common (MainFunc, struct per_process *); +#endif PVOID dll_dllcrt0 (HMODULE, struct per_process *); #ifdef __cplusplus diff --git a/winsup/cygwin/lib/cygwin_attach_dll.c b/winsup/cygwin/lib/cygwin_attach_dll.c index 866bfd80fa..82679c4a97 100644 --- a/winsup/cygwin/lib/cygwin_attach_dll.c +++ b/winsup/cygwin/lib/cygwin_attach_dll.c @@ -15,10 +15,18 @@ details. */ /* for a loaded dll */ PVOID +#ifdef __MSYS__ +msys_attach_dll (HMODULE h, MainFunc f) +#else cygwin_attach_dll (HMODULE h, MainFunc f) +#endif { static struct per_process u; +#ifdef __MSYS__ + (void) _msys_crt0_common (f, &u); +#else (void) _cygwin_crt0_common (f, &u); +#endif /* jump into the dll. */ return dll_dllcrt0 (h, &u); diff --git a/winsup/cygwin/lib/cygwin_crt0.c b/winsup/cygwin/lib/cygwin_crt0.c index 7020a639dd..396447e52e 100644 --- a/winsup/cygwin/lib/cygwin_crt0.c +++ b/winsup/cygwin/lib/cygwin_crt0.c @@ -14,8 +14,16 @@ extern void _dll_crt0 () /* for main module */ void +#ifdef __MSYS__ +msys_crt0 (MainFunc f) +#else cygwin_crt0 (MainFunc f) +#endif { +#ifdef __MSYS__ + _msys_crt0_common (f, NULL); +#else _cygwin_crt0_common (f, NULL); +#endif _dll_crt0 (); /* Jump into the dll, never to return */ } diff --git a/winsup/cygwin/local_includes/cygserver_setpwd.h b/winsup/cygwin/local_includes/cygserver_setpwd.h index fc1576b059..b2975111cf 100644 --- a/winsup/cygwin/local_includes/cygserver_setpwd.h +++ b/winsup/cygwin/local_includes/cygserver_setpwd.h @@ -12,7 +12,11 @@ details. */ #include #include "cygserver.h" +#ifdef __MSYS__ +#define CYGWIN_LSA_KEY_PREFIX L"L$MSYS_" +#else #define CYGWIN_LSA_KEY_PREFIX L"L$CYGWIN_" +#endif #ifndef __INSIDE_CYGWIN__ class transport_layer_base; diff --git a/winsup/cygwin/scripts/mkvers.sh b/winsup/cygwin/scripts/mkvers.sh index 38f439cd0d..a3d45c5db0 100755 --- a/winsup/cygwin/scripts/mkvers.sh +++ b/winsup/cygwin/scripts/mkvers.sh @@ -123,7 +123,7 @@ dir=$(echo $dir | sed -e 's%/include/cygwin.*$%%' -e 's%include/cygwin.*$%.%') ) | while read var; do read val cat <&9 @@ -135,9 +135,9 @@ trap "rm -f /tmp/mkvers.$$" 0 1 2 15 # cat <&9 #ifdef DEBUGGING - "%%% Cygwin shared id: " CYGWIN_VERSION_DLL_IDENTIFIER "S" shared_data_version "-$builddate\n" + "%%% MSYS shared id: " CYGWIN_VERSION_DLL_IDENTIFIER "S" shared_data_version "-$builddate\n" #else - "%%% Cygwin shared id: " CYGWIN_VERSION_DLL_IDENTIFIER "S" shared_data_version "\n" + "%%% MSYS shared id: " CYGWIN_VERSION_DLL_IDENTIFIER "S" shared_data_version "\n" #endif "END_CYGWIN_VERSION_INFO\n\0"; cygwin_version_info cygwin_version = diff --git a/winsup/cygwin/sec/auth.cc b/winsup/cygwin/sec/auth.cc index 43b5803893..db1d5c8977 100644 --- a/winsup/cygwin/sec/auth.cc +++ b/winsup/cygwin/sec/auth.cc @@ -462,7 +462,7 @@ verify_token (HANDLE token, cygsid &usersid, user_groups &groups, bool *pintern) if (!NT_SUCCESS (status)) debug_printf ("NtQueryInformationToken(), %y", status); else - *pintern = intern = !memcmp (ts.SourceName, "Cygwin.1", 8); + *pintern = intern = !memcmp (ts.SourceName, "MSYS.2", 6); } /* Verify usersid */ cygsid tok_usersid (NO_SID); @@ -747,7 +747,7 @@ s4uauth (bool logon, PCWSTR domain, PCWSTR user, NTSTATUS &ret_status) { /* Register as logon process. */ debug_printf ("Impersonation requested"); - RtlInitAnsiString (&name, "Cygwin"); + RtlInitAnsiString (&name, "MSYS"); status = LsaRegisterLogonProcess (&name, &lsa_hdl, &sec_mode); } else @@ -786,11 +786,11 @@ s4uauth (bool logon, PCWSTR domain, PCWSTR user, NTSTATUS &ret_status) } /* Create origin. */ - stpcpy (origin.buf, "Cygwin"); + stpcpy (origin.buf, "MSYS"); RtlInitAnsiString (&origin.str, origin.buf); /* Create token source. */ - memcpy (ts.SourceName, "Cygwin.1", 8); + memcpy (ts.SourceName, "MSYS.2", 6); ts.SourceIdentifier.HighPart = 0; ts.SourceIdentifier.LowPart = kerberos_auth ? 0x0105 : 0x0106; diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 83318d6057..808e661792 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -339,7 +339,7 @@ try_to_bin (path_conv &pc, HANDLE &fh, ACCESS_MASK access, ULONG flags) } else { - /* Create unique filename. Start with a dot, followed by "cyg" + /* Create unique filename. Start with a dot, followed by "msys" transposed to the Unicode private use area in the U+f700 area on file systems supporting Unicode (except Samba), followed by the inode number in hex, followed by a path hash in hex. The @@ -347,7 +347,7 @@ try_to_bin (path_conv &pc, HANDLE &fh, ACCESS_MASK access, ULONG flags) RtlAppendUnicodeToString (&recycler, (pc.fs_flags () & FILE_UNICODE_ON_DISK && !pc.fs_is_samba ()) - ? L".\xf763\xf779\xf767" : L".cyg"); + ? L".\xf76d\xf773\xf779\xf773" : L".msys"); pfii = (PFILE_INTERNAL_INFORMATION) infobuf; status = NtQueryInformationFile (fh, &io, pfii, sizeof *pfii, FileInternalInformation); diff --git a/winsup/cygwin/syslog.cc b/winsup/cygwin/syslog.cc index 6a295501f1..431f9d2396 100644 --- a/winsup/cygwin/syslog.cc +++ b/winsup/cygwin/syslog.cc @@ -26,7 +26,11 @@ details. */ #include "cygtls.h" #include "tls_pbuf.h" +#ifdef __MSYS__ +#define CYGWIN_LOG_NAME L"MSYS" +#else #define CYGWIN_LOG_NAME L"Cygwin" +#endif static struct { diff --git a/winsup/cygwin/winver.rc b/winsup/cygwin/winver.rc index 980d51204c..58878d41bd 100644 --- a/winsup/cygwin/winver.rc +++ b/winsup/cygwin/winver.rc @@ -35,7 +35,7 @@ BEGIN VALUE "InternalName", CYGWIN_DLL_NAME VALUE "LegalCopyright", "Copyright \251 Cygwin Authors 1996-" STRINGIFY(CYGWIN_BUILD_YEAR) VALUE "OriginalFilename", CYGWIN_DLL_NAME - VALUE "ProductName", "Cygwin" + VALUE "ProductName", "MSYS2" VALUE "ProductVersion", STRINGIFY(CYGWIN_VERSION) VALUE "APIVersion", CYGWIN_API_VERSION VALUE "SharedMemoryVersion", STRINGIFY(CYGWIN_VERSION_SHARED_DATA) diff --git a/winsup/testsuite/winsup.api/cygload.cc b/winsup/testsuite/winsup.api/cygload.cc index afd3ee90fc..1b2f79dc05 100644 --- a/winsup/testsuite/winsup.api/cygload.cc +++ b/winsup/testsuite/winsup.api/cygload.cc @@ -25,7 +25,7 @@ save for errors. -testinterrupts Pauses the program for 30 seconds so you can demonstrate that it handles ^C properly. - -cygwin Name of DLL to load. Defaults to "cygwin1.dll". */ + -cygwin Name of DLL to load. Defaults to "msys-2.0.dll". */ #include "cygload.h" #include @@ -154,13 +154,13 @@ cygwin::connector::connector (const char *dll) *out << "Initializing cygwin..." << endl; - // This calls dcrt0.cc:cygwin_dll_init(), which calls dll_crt0_1(), + // This calls dcrt0.cc:msys_dll_init(), which calls dll_crt0_1(), // which will, among other things: // * spawn the cygwin signal handling thread from sigproc_init() // * initialize the thread-local storage for this thread and overwrite // the first 4K of the stack void (*cyginit) (); - get_symbol ("cygwin_dll_init", cyginit); + get_symbol ("msys_dll_init", cyginit); (*cyginit) (); *out << "Loading symbols..." << endl; @@ -224,7 +224,7 @@ cygwin::connector::~connector () // This should call init.cc:dll_entry() with DLL_PROCESS_DETACH. if (!FreeLibrary (_library)) - throw windows_error ("FreeLibrary", "cygwin1.dll"); + throw windows_error ("FreeLibrary", "msys-2.0.dll"); } catch (std::exception &x) { @@ -490,7 +490,7 @@ main (int argc, char *argv[]) std::ostringstream output; bool verbose = false, testinterrupts = false; - const char *dll = "cygwin1.dll"; + const char *dll = "msys-2.0.dll"; out = &output; diff --git a/winsup/testsuite/winsup.api/cygload.h b/winsup/testsuite/winsup.api/cygload.h index 30154048b0..0f2aacda9a 100644 --- a/winsup/testsuite/winsup.api/cygload.h +++ b/winsup/testsuite/winsup.api/cygload.h @@ -76,7 +76,7 @@ namespace cygwin // spawns a thread to let you receive signals from cygwin. class connector { public: - connector (const char *dll = "cygwin1.dll"); + connector (const char *dll = "msys-2.0.dll"); ~connector (); // A wrapper around GetProcAddress() for fetching symbols from the diff --git a/winsup/utils/ldd.cc b/winsup/utils/ldd.cc index 0d073c2989..a31c4c6e44 100644 --- a/winsup/utils/ldd.cc +++ b/winsup/utils/ldd.cc @@ -249,7 +249,7 @@ tocyg (wchar_t *win_fn) return fn; } -#define CYGWIN_DLL_LEN (wcslen (L"\\cygwin1.dll")) +#define CYGWIN_DLL_LEN (wcslen (L"\\msys-2.0.dll")) static int print_dlls (dlls *dll, const wchar_t *dllfn, const wchar_t *process_fn) { diff --git a/winsup/utils/loadlib.h b/winsup/utils/loadlib.h index c83b76478f..42ffbfdc03 100644 --- a/winsup/utils/loadlib.h +++ b/winsup/utils/loadlib.h @@ -13,7 +13,7 @@ #include /* Load all system libs from the windows system directory by prepending the - full path. This doesn't work for loadling cygwin1.dll. For this case, + full path. This doesn't work for loadling msys-2.0.dll. For this case, instead of prepending the path, make sure that the CWD is removed from the DLL search path, if possible (XP SP1++, Vista++). */ static HMODULE _load_sys_library (const wchar_t *dll) __attribute__ ((used)); @@ -45,8 +45,8 @@ _load_sys_library (const wchar_t *dll) set_dll_directory (L""); } - if (wcscmp (dll, L"cygwin1.dll") == 0) - return LoadLibraryExW (L"cygwin1.dll", NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + if (wcscmp (dll, L"msys-2.0.dll") == 0) + return LoadLibraryExW (L"msys-2.0.dll", NULL, LOAD_WITH_ALTERED_SEARCH_PATH); wcscpy (dllpath, sysdir); wcscpy (dllpath + sysdir_len, dll); diff --git a/winsup/utils/mingw/cygcheck.cc b/winsup/utils/mingw/cygcheck.cc index 1dde2ecbab..7718ab9dc9 100644 --- a/winsup/utils/mingw/cygcheck.cc +++ b/winsup/utils/mingw/cygcheck.cc @@ -95,8 +95,7 @@ static const char *known_env_vars[] = { "c_include_path", "compiler_path", "cxx_include_path", - "cygwin", - "cygwin32", + "msys", "dejagnu", "expect", "gcc_default_options", @@ -554,7 +553,7 @@ struct ImpDirectory static bool track_down (const char *file, const char *suffix, int lvl); -#define CYGPREFIX (sizeof ("%%% Cygwin ") - 1) +#define CYGPREFIX (sizeof ("%%% Msys ") - 1) static void cygwin_info (HANDLE h) { @@ -586,7 +585,7 @@ cygwin_info (HANDLE h) while (buf < bufend) if ((buf = (char *) memchr (buf, '%', bufend - buf)) == NULL) break; - else if (strncmp ("%%% Cygwin ", buf, CYGPREFIX) != 0) + else if (strncmp ("%%% Msys ", buf, CYGPREFIX) != 0) buf++; else { @@ -780,7 +779,7 @@ dll_info (const char *path, HANDLE fh, int lvl, int recurse) } } } - if (strstr (path, "\\cygwin1.dll")) + if (strstr (path, "\\msys-2.0.dll")) cygwin_info (fh); } @@ -1027,7 +1026,7 @@ scan_registry (RegInfo * prev, HKEY hKey, char *name, int cygwin, bool wow64) char *cp; for (cp = name; *cp; cp++) - if (strncasecmp (cp, "Cygwin", 6) == 0) + if (strncasecmp (cp, "Msys", 4) == 0) cygwin = 1; DWORD num_subkeys, max_subkey_len, num_values; @@ -1309,7 +1308,7 @@ handle_reg_installation (handle_reg_t what) printf ("Cygwin installations found in the registry:\n"); for (int i = 0; i < 2; ++i) if (RegOpenKeyEx (i ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, - "SOFTWARE\\Cygwin\\Installations", 0, + "SOFTWARE\\Msys\\Installations", 0, what == DELETE_KEY ? KEY_READ | KEY_WRITE : KEY_READ, &key) == ERROR_SUCCESS) @@ -1331,7 +1330,7 @@ handle_reg_installation (handle_reg_t what) if (what == PRINT_KEY) printf (" %s Key: %s Path: %s", i ? "User: " : "System:", name, path); - strcat (path, "\\bin\\cygwin1.dll"); + strcat (path, "\\bin\\msys-2.0.dll"); if (what == PRINT_KEY) printf ("%s\n", access (path, F_OK) ? " (ORPHANED)" : ""); else if (access (path, F_OK)) @@ -1783,7 +1782,7 @@ dump_sysinfo () if (registry) { if (givehelp) - printf ("Scanning registry for keys with 'Cygwin' in them...\n"); + printf ("Scanning registry for keys with 'Msys' in them...\n"); scan_registry (0, HKEY_CURRENT_USER, (char *) "HKEY_CURRENT_USER", 0, false); scan_registry (0, HKEY_LOCAL_MACHINE, @@ -1978,10 +1977,10 @@ dump_sysinfo () wcstombs (f, ffinfo.cFileName, sizeof f); if (strcasecmp (f + strlen (f) - 4, ".dll") == 0) { - if (strncasecmp (f, "cyg", 3) == 0) + if (strncasecmp (f, "msys-", 5) == 0) { sprintf (tmp, "%s%s", pth->dir, f); - if (strcasecmp (f, "cygwin1.dll") == 0) + if (strcasecmp (f, "msys-2.0.dll") == 0) { if (!cygwin_dll_count) strcpy (cygdll_path, pth->dir); @@ -2005,9 +2004,9 @@ dump_sysinfo () FindClose (ff); } if (cygwin_dll_count > 1) - puts ("Warning: There are multiple cygwin1.dlls on your path"); + puts ("Warning: There are multiple msys-2.0.dlls on your path"); if (!cygwin_dll_count) - puts ("Warning: cygwin1.dll not found on your path"); + puts ("Warning: msys-2.0.dll not found on your path"); dump_dodgy_apps (verbose); @@ -3021,7 +3020,7 @@ load_cygwin (int& argc, char **&argv) { HMODULE h; - if (!(h = LoadLibrary ("cygwin1.dll"))) + if (!(h = LoadLibrary ("msys-2.0.dll"))) return; GetModuleFileNameW (h, cygwin_dll_path, 32768); if ((cygwin_internal = (uintptr_t (*) (cygwin_getinfo_types, ...)) diff --git a/winsup/utils/mingw/strace.cc b/winsup/utils/mingw/strace.cc index c220643b33..29db640239 100644 --- a/winsup/utils/mingw/strace.cc +++ b/winsup/utils/mingw/strace.cc @@ -284,7 +284,7 @@ load_cygwin () if (h) return 0; - if (!(h = LoadLibrary ("cygwin1.dll"))) + if (!(h = LoadLibrary ("msys-2.0.dll"))) { errno = ENOENT; return 0; @@ -354,17 +354,16 @@ create_child (char **argv) make_command_line (one_line, argv); SetConsoleCtrlHandler (NULL, 0); - - const char *cygwin_env = getenv ("CYGWIN"); + const char *cygwin_env = getenv ("MSYS"); const char *space; if (cygwin_env && strlen (cygwin_env) <= 256) /* sanity check */ space = " "; else space = cygwin_env = ""; - char *newenv = (char *) malloc (sizeof ("CYGWIN=noglob") + char *newenv = (char *) malloc (sizeof ("MSYS=noglob") + strlen (space) + strlen (cygwin_env)); - sprintf (newenv, "CYGWIN=noglob%s%s", space, cygwin_env); + sprintf (newenv, "MSYS=noglob%s%s", space, cygwin_env); _putenv (newenv); ret = CreateProcess (0, one_line.buf, /* command line */ NULL, /* Security */ diff --git a/winsup/utils/path.cc b/winsup/utils/path.cc index fe55a646d9..323e4c784b 100644 --- a/winsup/utils/path.cc +++ b/winsup/utils/path.cc @@ -585,14 +585,14 @@ read_mounts () } max_mount_entry = 0; - /* First fetch the cygwin1.dll path from the LoadLibrary call in load_cygwin. - This utilizes the DLL search order to find a matching cygwin1.dll and to + /* First fetch the msys-2.0.dll path from the LoadLibrary call in load_cygwin. + This utilizes the DLL search order to find a matching msys-2.0.dll and to compute the installation path from that DLL's path. */ if (cygwin_dll_path[0]) wcscpy (path, cygwin_dll_path); - /* If we can't load cygwin1.dll, check where cygcheck is living itself and - try to fetch installation path from here. Does cygwin1.dll exist in the - same path? This should only kick in if the cygwin1.dll in the same path + /* If we can't load msys-2.0.dll, check where cygcheck is living itself and + try to fetch installation path from here. Does msys-2.0.dll exist in the + same path? This should only kick in if the msys-2.0.dll in the same path has been made non-executable for the current user accidentally. */ else if (!GetModuleFileNameW (NULL, path, 32768)) return; @@ -601,7 +601,7 @@ read_mounts () { if (!cygwin_dll_path[0]) { - wcscpy (path_end, L"\\cygwin1.dll"); + wcscpy (path_end, L"\\msys-2.0.dll"); DWORD attr = GetFileAttributesW (path); if (attr == (DWORD) -1 || (attr & (FILE_ATTRIBUTE_DIRECTORY diff --git a/winsup/utils/ssp.c b/winsup/utils/ssp.c index 96a90a1d98..95045e1e8b 100644 --- a/winsup/utils/ssp.c +++ b/winsup/utils/ssp.c @@ -710,15 +710,15 @@ usage (FILE * stream) "You must specify the range of memory addresses to keep track of\n" "manually, but it's not hard to figure out what to specify. Use the\n" "\"objdump\" program to determine the bounds of the target's \".text\"\n" - "section. Let's say we're profiling cygwin1.dll. Make sure you've\n" + "section. Let's say we're profiling msys-2.0.dll. Make sure you've\n" "built it with debug symbols (else gprof won't run) and run objdump\n" "like this:\n" "\n" - " objdump -h cygwin1.dll\n" + " objdump -h msys-2.0.dll\n" "\n" "It will print a report like this:\n" "\n" - "cygwin1.dll: file format pei-i386\n" + "msys-2.0.dll: file format pei-i386\n" "\n" "Sections:\n" "Idx Name Size VMA LMA File off Algn\n" @@ -749,7 +749,7 @@ usage (FILE * stream) "\"gmon.out\". You can turn this data file into a readable report with\n" "gprof:\n" "\n" - " gprof -b cygwin1.dll\n" + " gprof -b msys-2.0.dll\n" "\n" "The \"-b\" means 'skip the help pages'. You can omit this until you're\n" "familiar with the report layout. The gprof documentation explains\n" From 70cdcbadb9512f5e636173fc96fee9aeb8687c25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B8=CC=86=20=D0=9F?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=BE=D0=B2?= Date: Sun, 14 Apr 2019 21:17:46 +0300 Subject: [PATCH 04/50] Add functionality for converting UNIX paths in arguments and environment variables to Windows form for native Win32 applications. --- winsup/cygwin/Makefile.am | 1 + winsup/cygwin/environ.cc | 24 +- winsup/cygwin/external.cc | 2 +- winsup/cygwin/include/sys/cygwin.h | 6 + winsup/cygwin/local_includes/environ.h | 2 +- winsup/cygwin/local_includes/winf.h | 4 + winsup/cygwin/msys2_path_conv.cc | 699 +++++++++++++++++++++++++ winsup/cygwin/msys2_path_conv.h | 147 ++++++ winsup/cygwin/path.cc | 69 +++ winsup/cygwin/spawn.cc | 38 +- 10 files changed, 988 insertions(+), 4 deletions(-) create mode 100644 winsup/cygwin/msys2_path_conv.cc create mode 100644 winsup/cygwin/msys2_path_conv.h diff --git a/winsup/cygwin/Makefile.am b/winsup/cygwin/Makefile.am index e65e675bcd..b1b0df708e 100644 --- a/winsup/cygwin/Makefile.am +++ b/winsup/cygwin/Makefile.am @@ -312,6 +312,7 @@ DLL_FILES= \ miscfuncs.cc \ mktemp.cc \ msg.cc \ + msys2_path_conv.cc \ mount.cc \ net.cc \ netdb.cc \ diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index d4cedcbdfe..639e69393b 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -1046,7 +1046,7 @@ env_compare (const void *key, const void *memb) to the child. */ char ** build_env (const char * const *envp, PWCHAR &envblock, int &envc, - bool no_envblock, HANDLE new_token) + bool no_envblock, HANDLE new_token, bool keep_posix) { PWCHAR cwinenv = NULL; size_t winnum = 0; @@ -1139,6 +1139,19 @@ build_env (const char * const *envp, PWCHAR &envblock, int &envc, for (srcp = envp, dstp = newenv, pass_dstp = pass_env; *srcp; srcp++) { bool calc_tl = !no_envblock; +#ifdef __MSYS__ + /* Don't pass timezone environment to non-msys applications */ + if (!keep_posix && ascii_strncasematch(*srcp, "TZ=", 3)) + { + const char *v = *srcp + 3; + if (*v == ':') + goto next1; + for (; *v; v++) + if (!isalpha(*v) && !isdigit(*v) && + *v != '-' && *v != '+' && *v != ':') + goto next1; + } +#endif /* Look for entries that require special attention */ for (unsigned i = 0; i < SPENVS_SIZE; i++) if (!saw_spenv[i] && (*dstp = spenvs[i].retrieve (no_envblock, *srcp))) @@ -1259,6 +1272,15 @@ build_env (const char * const *envp, PWCHAR &envblock, int &envc, saw_PATH = true; } } +#ifdef __MSYS__ + else if (!keep_posix) { + char *win_arg = arg_heuristic(*srcp); + debug_printf("WIN32_PATH is %s", win_arg); + p = cstrdup1(win_arg); + if (win_arg != *srcp) + free (win_arg); + } +#endif else p = *srcp; /* Don't worry about it */ diff --git a/winsup/cygwin/external.cc b/winsup/cygwin/external.cc index 97e4528741..33863d8001 100644 --- a/winsup/cygwin/external.cc +++ b/winsup/cygwin/external.cc @@ -141,7 +141,7 @@ create_winenv (const char * const *env) int unused_envc; PWCHAR envblock = NULL; char **envp = build_env (env ?: environ, envblock, unused_envc, false, - NULL); + NULL, true); PWCHAR p = envblock; if (envp) diff --git a/winsup/cygwin/include/sys/cygwin.h b/winsup/cygwin/include/sys/cygwin.h index 2c5997b5e2..6383646cc7 100644 --- a/winsup/cygwin/include/sys/cygwin.h +++ b/winsup/cygwin/include/sys/cygwin.h @@ -60,6 +60,12 @@ extern ssize_t cygwin_conv_path_list (cygwin_conv_path_t what, const void *from, to one of the above values, or to ENOMEM if malloc fails. */ extern void *cygwin_create_path (cygwin_conv_path_t what, const void *from); +extern char * arg_heuristic_with_exclusions (char const * const arg, + char const * exclusions, + size_t exclusions_count); + +extern char * arg_heuristic (char const * const); + extern pid_t cygwin_winpid_to_pid (int); extern int cygwin_posix_path_list_p (const char *); extern void cygwin_split_path (const char *, char *, char *); diff --git a/winsup/cygwin/local_includes/environ.h b/winsup/cygwin/local_includes/environ.h index 86e64a72f9..0dd45359cc 100644 --- a/winsup/cygwin/local_includes/environ.h +++ b/winsup/cygwin/local_includes/environ.h @@ -34,7 +34,7 @@ win_env *getwinenv (const char *name, const char *posix = NULL, win_env * = NULL char *getwinenveq (const char *name, size_t len, int); char **build_env (const char * const *envp, PWCHAR &envblock, - int &envc, bool need_envblock, HANDLE new_token); + int &envc, bool need_envblock, HANDLE new_token, bool keep_posix); char **win32env_to_cygenv (PWCHAR rawenv, bool posify); diff --git a/winsup/cygwin/local_includes/winf.h b/winsup/cygwin/local_includes/winf.h index b586934410..bc53cd1aa3 100644 --- a/winsup/cygwin/local_includes/winf.h +++ b/winsup/cygwin/local_includes/winf.h @@ -56,6 +56,10 @@ class av calloced = 1; } } + void replace (int i, const char *arg) + { + argv[i] = cstrdup1 (arg); + } void dup_all () { for (int i = calloced; i < argc; i++) diff --git a/winsup/cygwin/msys2_path_conv.cc b/winsup/cygwin/msys2_path_conv.cc new file mode 100644 index 0000000000..c52728759e --- /dev/null +++ b/winsup/cygwin/msys2_path_conv.cc @@ -0,0 +1,699 @@ +/* + The MSYS2 Path conversion source code is licensed under: + + CC0 1.0 Universal + + Official translations of this legal tool are available + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + + Statement of Purpose + + The laws of most jurisdictions throughout the world automatically + confer exclusive Copyright and Related Rights (defined below) upon the + creator and subsequent owner(s) (each and all, an "owner") of an + original work of authorship and/or a database (each, a "Work"). + + Certain owners wish to permanently relinquish those rights to a Work + for the purpose of contributing to a commons of creative, cultural and + scientific works ("Commons") that the public can reliably and without + fear of later claims of infringement build upon, modify, incorporate + in other works, reuse and redistribute as freely as possible in any + form whatsoever and for any purposes, including without limitation + commercial purposes. These owners may contribute to the Commons to + promote the ideal of a free culture and the further production of + creative, cultural and scientific works, or to gain reputation or + greater distribution for their Work in part through the use and + efforts of others. + + For these and/or other purposes and motivations, and without any + expectation of additional consideration or compensation, the person + associating CC0 with a Work (the "Affirmer"), to the extent that he or + she is an owner of Copyright and Related Rights in the Work, + voluntarily elects to apply CC0 to the Work and publicly distribute + the Work under its terms, with knowledge of his or her Copyright and + Related Rights in the Work and the meaning and intended legal effect + of CC0 on those rights. + + 1. Copyright and Related Rights. A Work made available under CC0 may + be protected by copyright and related or neighboring rights + ("Copyright and Related Rights"). Copyright and Related Rights + include, but are not limited to, the following: + + the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + moral rights retained by the original author(s) and/or performer(s); + publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + rights protecting the extraction, dissemination, use and reuse of data + in a Work; + database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and + other similar, equivalent or corresponding rights throughout the world + based on applicable law or treaty, and any national implementations + thereof. + + 2. Waiver. To the greatest extent permitted by, but not in + contravention of, applicable law, Affirmer hereby overtly, fully, + permanently, irrevocably and unconditionally waives, abandons, and + surrenders all of Affirmer's Copyright and Related Rights and + associated claims and causes of action, whether now known or unknown + (including existing as well as future claims and causes of action), in + the Work (i) in all territories worldwide, (ii) for the maximum + duration provided by applicable law or treaty (including future time + extensions), (iii) in any current or future medium and for any number + of copies, and (iv) for any purpose whatsoever, including without + limitation commercial, advertising or promotional purposes (the + "Waiver"). Affirmer makes the Waiver for the benefit of each member of + the public at large and to the detriment of Affirmer's heirs and + successors, fully intending that such Waiver shall not be subject to + revocation, rescission, cancellation, termination, or any other legal + or equitable action to disrupt the quiet enjoyment of the Work by the + public as contemplated by Affirmer's express Statement of Purpose. + + 3. Public License Fallback. Should any part of the Waiver for any + reason be judged legally invalid or ineffective under applicable law, + then the Waiver shall be preserved to the maximum extent permitted + taking into account Affirmer's express Statement of Purpose. In + addition, to the extent the Waiver is so judged Affirmer hereby grants + to each affected person a royalty-free, non transferable, non + sublicensable, non exclusive, irrevocable and unconditional license to + exercise Affirmer's Copyright and Related Rights in the Work (i) in + all territories worldwide, (ii) for the maximum duration provided by + applicable law or treaty (including future time extensions), (iii) in + any current or future medium and for any number of copies, and (iv) + for any purpose whatsoever, including without limitation commercial, + advertising or promotional purposes (the "License"). The License shall + be deemed effective as of the date CC0 was applied by Affirmer to the + Work. Should any part of the License for any reason be judged legally + invalid or ineffective under applicable law, such partial invalidity + or ineffectiveness shall not invalidate the remainder of the License, + and in such case Affirmer hereby affirms that he or she will not (i) + exercise any of his or her remaining Copyright and Related Rights in + the Work or (ii) assert any associated claims and causes of action + with respect to the Work, in either case contrary to Affirmer's + express Statement of Purpose. + + 4. Limitations and Disclaimers. + + No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. + + Contributions thanks to: + niXman + Ely Arzhannikov + Alexey Pavlov + Ray Donnelly + Johannes Schindelin + +*/ + +#include "winsup.h" +#include "miscfuncs.h" +#include +#include +#include +#include +#include +#include "cygerrno.h" +#include "security.h" +#include "path.h" +#include "fhandler.h" +#include "dtable.h" +#include "cygheap.h" +#include "shared_info.h" +#include "cygtls.h" +#include "tls_pbuf.h" +#include "environ.h" +#include +#include +#include +#include + +#include "msys2_path_conv.h" + +typedef enum PATH_TYPE_E { + NONE = 0, + SIMPLE_WINDOWS_PATH, + ESCAPE_WINDOWS_PATH, + WINDOWS_PATH_LIST, + UNC, + ESCAPED_PATH, + ROOTED_PATH, + POSIX_PATH_LIST, + RELATIVE_PATH, + URL +} path_type; + +int is_special_posix_path(const char* from, const char* to, char** dst, const char* dstend); +void posix_to_win32_path(const char* from, const char* to, char** dst, const char* dstend); + + +path_type find_path_start_and_type(const char** src, int recurse, const char* end); +void copy_to_dst(const char* from, const char* to, char** dst, const char* dstend); +void convert_path(const char** from, const char* to, path_type type, char** dst, const char* dstend); + +//Transformations +//SIMPLE_WINDOWS_PATH converter. Copy as is. Hold C:\Something\like\this +void swp_convert(const char** from, const char* to, char** dst, const char* dstend); +//ESCAPE_WINDOWS_PATH converter. Turn backslashes to slashes and skip first /. Hold /C:\Somethind\like\this +void ewp_convert(const char** from, const char* to, char** dst, const char* dstend); +//WINDOWS_PATH_LIST converter. Copy as is. Hold /something/like/this; +void wpl_convert(const char** from, const char* to, char** dst, const char* dstend); +//UNC convert converter. Copy as is. Hold //somethig/like/this +void unc_convert(const char** from, const char* to, char** dst, const char* dstend); +//ESCAPED_PATH converter. Turn backslashes to slashes and skip first /. Hold //something\like\this +void ep_convert(const char** from, const char* to, char** dst, const char* dstend); +//ROOTED_PATH converter. Prepend root dir to front. Hold /something/like/this +void rp_convert(const char** from, const char* to, char** dst, const char* dstend); +//URL converter. Copy as is. +void url_convert(const char** from, const char* to, char** dst, const char* dstend); +//POSIX_PATH_LIST. Hold x::x/y:z +void ppl_convert(const char** from, const char* to, char** dst, const char* dstend); + + +void find_end_of_posix_list(const char** to, int* in_string) { + for (; **to != '\0' && (!in_string || **to != *in_string); ++*to) { + } + + if (**to == *in_string) { + *in_string = 0; + } +} + +void find_end_of_rooted_path(const char** from, const char** to, int* in_string) { + for (const char* it = *from; *it != '\0' && it != *to; ++it) + if (*it == '.' && *(it + 1) == '.' && *(it - 1) == '/') { + *to = it - 1; + return; + } + + for (; **to != '\0'; ++*to) { + if (*in_string == 0 && **to == ' ') { + return; + } + + if (**to == *in_string) { + *in_string = 0; + return; + } + + if (**to == '/') { + if (*(*to - 1) == ' ') { + *to -= 1; + return; + } + } + } +} + +void sub_convert(const char** from, const char** to, char** dst, const char* dstend, int* in_string) { + const char* copy_from = *from; + path_type type = find_path_start_and_type(from, false, *to); + debug_printf("found type %d for path %s", type, copy_from); + + if (type == POSIX_PATH_LIST) { + find_end_of_posix_list(to, in_string); + } + + if (type == ROOTED_PATH) { + find_end_of_rooted_path(from, to, in_string); + } + + copy_to_dst(copy_from, *from, dst, dstend); + + if (type != NONE) { + convert_path(from, *to, type, dst, dstend); + } + + if (*dst != dstend) { + **dst = **to; + *dst += 1; + } +} + +const char* convert(char *dst, size_t dstlen, const char *src) { + if (dst == NULL || dstlen == 0 || src == NULL) { + return dst; + } + + int need_convert = false; + for (const char* it = src; *it != '\0'; ++it) { + if (*it == '\\' || *it == '/') { + need_convert = true; + break; + } + if (isspace(*it)) { + need_convert = false; + break; + } + } + + char* dstit = dst; + char* dstend = dst + dstlen; + if (!need_convert) { + copy_to_dst(src, NULL, &dstit, dstend); + *dstit = '\0'; + return dst; + } + *dstend = '\0'; + + const char* srcit = src; + const char* srcbeg = src; + + int in_string = false; + + for (; *srcit != '\0'; ++srcit) { + if (*srcit == '\'' || *srcit == '"') { + if (in_string == *srcit) { + if (*(srcit + 1) != in_string) { + in_string = 0; + } + } else { + in_string = *srcit; + } + continue; + } + } + + sub_convert(&srcbeg, &srcit, &dstit, dstend, &in_string); + if (!*srcit) { + *dstit = '\0'; + return dst; + } + srcbeg = srcit + 1; + for (; *srcit != '\0'; ++srcit) { + continue; + } + copy_to_dst(srcbeg, srcit, &dstit, dstend); + *dstit = '\0'; + + /*if (dstit - dst < 2) { + dstit = dst; + copy_to_dst(src, NULL, &dstit, dstend); + *dstit = '\0'; + }*/ + + return dst; +} + +void copy_to_dst(const char* from, const char* to, char** dst, const char* dstend) { + for (; (*from != '\0') && (from != to) && (*dst != dstend); ++from, ++(*dst)) { + **dst = *from; + } +} + +const char** move(const char** p, int count) { + *p += count; + return p; +} + +path_type find_path_start_and_type(const char** src, int recurse, const char* end) { + const char* it = *src; + + if (*it == '\0' || it == end) return NONE; + + /* Let's not convert ~/.file to ~C:\msys64\.file */ + if (*it == '~') { +skip_p2w: + *src = end; + return NONE; + } + + /* + * Prevent Git's :file.txt and :/message syntax from beeing modified. + */ + if (*it == ':') + goto skip_p2w; + + while (it != end && *it) { + switch (*it) { + case '`': + case '\'': + case '*': + case '?': + case '[': + case ']': + goto skip_p2w; + case '/': + if (it + 1 < end && it[1] == '~') + goto skip_p2w; + break; + case ':': + // Avoid mangling IPv6 addresses + if (it + 1 < end && it[1] == ':') + goto skip_p2w; + + // Leave Git's :./name syntax alone + if (it + 1 < end && it[1] == '.') { + if (it + 2 < end && it[2] == '/') + goto skip_p2w; + if (it + 3 < end && it[2] == '.' && it[3] == '/') + goto skip_p2w; + } + break; + case '@': + // Paths do not contain '@@' + if (it + 1 < end && it[1] == '@') + goto skip_p2w; + } + ++it; + } + it = *src; + + while (!isalnum(*it) && *it != '/' && *it != '\\' && *it != ':' && *it != '-' && *it != '.') { + recurse = true; + it = ++*src; + if (it == end || *it == '\0') return NONE; + } + + path_type result = NONE; + + if (it + 1 == end) { + switch (*it) { + case '/': return ROOTED_PATH ; + default: return SIMPLE_WINDOWS_PATH; + } + } + + if (isalpha(*it) && *(it + 1) == ':') { + if (*(it + 2) == '\\') { + return SIMPLE_WINDOWS_PATH; + } + + if (*(it + 2) == '/' && memchr(it + 2, ':', end - (it + 2)) == NULL) { + return SIMPLE_WINDOWS_PATH; + } + + if (*(it + 2) == '/' && memchr(it + 2, ';', end - (it + 2))) { + return WINDOWS_PATH_LIST; + } + } + + if (*it == '.' && (*(it + 1) == '.' || *(it + 1) == '/') && memchr(it + 2, ':', end - (it + 2)) == NULL) { + return RELATIVE_PATH; + } + + if (*it == '/') { + it += 1; + + if (isalpha(*it) && *(it + 1) == ':') { + return ESCAPE_WINDOWS_PATH; + } + + if (*it == '.' && *(it + 1) == '.') { + return SIMPLE_WINDOWS_PATH; + } + + if (*it == '/') { + it += 1; + switch(*it) { + case ':': return URL; + case '/': return ESCAPED_PATH; + } + if (memchr(it, '/', end - it)) + return UNC; + else + return ESCAPED_PATH; + } + + for (; *it != '\0' && it != end; ++it) { + switch(*it) { + case ':': {char ch = *(it + 1); if (ch == '/' || ch == ':' || ch == '.') return POSIX_PATH_LIST;} return WINDOWS_PATH_LIST; + case ';': return WINDOWS_PATH_LIST; + } + } + + if (result != NONE) { + return result; + } + + return ROOTED_PATH; + } + + int starts_with_minus = 0; + int starts_with_minus_alpha = 0; + int only_dots = *it == '.'; + int has_slashes = 0; + if (*it == '-') { + starts_with_minus = 1; + it += 1; + if (isalpha(*it)) { + it += 1; + starts_with_minus_alpha = 1; + if (memchr(it, ';', end - it)) { + return WINDOWS_PATH_LIST; + } + } + } + + for (const char* it2 = it; *it2 != '\0' && it2 != end; ++it2) { + char ch = *it2; + if (starts_with_minus_alpha) { + if (isalpha(ch) && (*(it2+1) == ':') && (*(it2+2) == '/')) { + return SIMPLE_WINDOWS_PATH; + } + if (ch == '/'&& memchr(it2, ',', end - it2) == NULL) { + *src = it2; + return find_path_start_and_type(src, true, end); + } + starts_with_minus_alpha = 0; + } + if (ch == '\'' || ch == '"') + starts_with_minus = false; + if ((ch == '=') || (ch == ':' && starts_with_minus) || ((ch == '\'' || ch == '"') && result == NONE)) { + *src = it2 + 1; + return find_path_start_and_type(src, true, end); + } + + if (ch == ',' && starts_with_minus) { + *src = it2 + 1; + return find_path_start_and_type(src, true, end); + } + + if (ch == ':' && it2 + 1 != end) { + it2 += 1; + ch = *it2; + if (ch == '/' || ch == ':' || ch == '.') { + if (ch == '/' && *(it2 + 1) == '/') { + return URL; + } else { + if (!only_dots && !has_slashes) + goto skip_p2w; + return POSIX_PATH_LIST; + } + } else if (memchr(it2, '=', end - it2) == NULL) { + return SIMPLE_WINDOWS_PATH; + } + } else if (ch != '.') { + only_dots = 0; + if (ch == '/' || ch == '\\') + has_slashes = 1; + } + } + + if (result != NONE) { + *src = it; + return result; + } + + return SIMPLE_WINDOWS_PATH; +} + +void convert_path(const char** from, const char* to, path_type type, char** dst, const char* dstend) { + switch(type) { + case SIMPLE_WINDOWS_PATH: swp_convert(from, to, dst, dstend); break; + case ESCAPE_WINDOWS_PATH: ewp_convert(from, to, dst, dstend); break; + case WINDOWS_PATH_LIST: wpl_convert(from, to, dst, dstend); break; + case RELATIVE_PATH: swp_convert(from, to, dst, dstend); break; + case UNC: unc_convert(from, to, dst, dstend); break; + case ESCAPED_PATH: ep_convert(from, to, dst, dstend); break; + case ROOTED_PATH: rp_convert(from, to, dst, dstend); break; + case URL: url_convert(from, to, dst, dstend); break; + case POSIX_PATH_LIST: ppl_convert(from, to, dst, dstend); break; + case NONE: // prevent warnings; + default: + return; + } +} + +void swp_convert(const char** from, const char* to, char** dst, const char* dstend) { + copy_to_dst(*from, to, dst, dstend); +} + +void ewp_convert(const char** from, const char* to, char** dst, const char* dstend) { + *from += 1; + unc_convert(from, to, dst, dstend); +} + +void wpl_convert(const char** from, const char* to, char** dst, const char* dstend) { + swp_convert(from, to, dst, dstend); +} + +void unc_convert(const char** from, const char* to, char** dst, const char* dstend) { + const char* it = *from; + for (; (*it != '\0' && it != to) && (*dst != dstend); ++it, ++(*dst)) { + if (*it == '\\') { + **dst = '/'; + } else { + **dst = *it; + } + } +} + +void ep_convert(const char** from, const char* to, char** dst, const char* dstend) { + ewp_convert(from, to, dst, dstend); +} + +void rp_convert(const char** from, const char* to, char** dst, const char* dstend) { + const char* it = *from; + const char* real_to = to; + + if (*real_to == '\0') { + real_to -= 1; + if (*real_to != '\'' && *real_to != '"') { + real_to += 1; + } + } + + if (!is_special_posix_path(*from, real_to, dst, dstend)) { + posix_to_win32_path(it, real_to, dst, dstend); + } + + if (*dst != dstend && real_to != to) { + **dst = *real_to; + *dst += 1; + } +} + +void url_convert(const char** from, const char* to, char** dst, const char* dstend) { + unc_convert(from, to, dst, dstend); +} + +void subp_convert(const char** from, const char* end, int is_url, char** dst, const char* dstend) { + const char* begin = *from; + path_type type = is_url ? URL : find_path_start_and_type(from, 0, end); + copy_to_dst(begin, *from, dst, dstend); + + if (type == NONE) { + return; + } + + char* start = *dst; + convert_path(from, end, type, dst, dstend); + + if (!is_url) { + for (; start != *dst; ++start) { + if (*start == '/') { + *start = '\\'; + } + } + } +} + +void ppl_convert(const char** from, const char* to, char** dst, const char* dstend) { + const char *orig_dst = *dst; + const char* it = *from; + const char* beg = it; + int prev_was_simc = 0; + int is_url = 0; + for (; (*it != '\0' && it != to) && (*dst != dstend); ++it) { + if (*it == ':') { + if (prev_was_simc) { + continue; + } + if (*(it + 1) == '/' && *(it + 2) == '/' && isalpha(*beg)) { + is_url = 1; + /* double-check: protocol must be alnum (or +) */ + for (const char *p = beg; p != it; ++p) + if (!isalnum(*p) && *p != '+') { + is_url = 0; + break; + } + if (is_url) + continue; + } + prev_was_simc = 1; + subp_convert(&beg, it, is_url, dst, dstend); + is_url = 0; + + if (*dst == dstend) { + system_printf("Path cut off during conversion: %s\n", orig_dst); + break; + } + + **dst = ';'; + *dst += 1; + } + + if (*it != ':' && prev_was_simc) { + prev_was_simc = 0; + beg = it; + } + } + + if (!prev_was_simc) { + subp_convert(&beg, it, is_url, dst, dstend); + } +} + +int is_special_posix_path(const char* from, const char* to, char** dst, const char* dstend) { + const char dev_null[] = "/dev/null"; + + if ((to - from) == (sizeof(dev_null) - 1) && strncmp(from, "/dev/null", to - from) == 0) { + copy_to_dst("nul", NULL, dst, dstend); + return true; + } + return false; +} + +void posix_to_win32_path(const char* from, const char* to, char** dst, const char* dstend) { + if ( from != to ) { + tmp_pathbuf tp; + char *one_path = tp.c_get(); + strncpy(one_path, from, to-from); + one_path[to-from] = '\0'; + + path_conv conv (one_path, 0); + if (conv.error) + { + set_errno(conv.error); + copy_to_dst(one_path, NULL, dst, dstend); + } else { + char* win32_path = tp.c_get(); + stpcpy (win32_path, conv.get_win32 ()); + for (; (*win32_path != '\0') && (*dst != dstend); ++win32_path, ++(*dst)) { + **dst = (*win32_path == '\\') ? '/' : *win32_path; + } + } + } +} + diff --git a/winsup/cygwin/msys2_path_conv.h b/winsup/cygwin/msys2_path_conv.h new file mode 100644 index 0000000000..67d85ecb64 --- /dev/null +++ b/winsup/cygwin/msys2_path_conv.h @@ -0,0 +1,147 @@ +/* + The MSYS2 Path conversion source code is licensed under: + + CC0 1.0 Universal + + Official translations of this legal tool are available + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + + Statement of Purpose + + The laws of most jurisdictions throughout the world automatically + confer exclusive Copyright and Related Rights (defined below) upon the + creator and subsequent owner(s) (each and all, an "owner") of an + original work of authorship and/or a database (each, a "Work"). + + Certain owners wish to permanently relinquish those rights to a Work + for the purpose of contributing to a commons of creative, cultural and + scientific works ("Commons") that the public can reliably and without + fear of later claims of infringement build upon, modify, incorporate + in other works, reuse and redistribute as freely as possible in any + form whatsoever and for any purposes, including without limitation + commercial purposes. These owners may contribute to the Commons to + promote the ideal of a free culture and the further production of + creative, cultural and scientific works, or to gain reputation or + greater distribution for their Work in part through the use and + efforts of others. + + For these and/or other purposes and motivations, and without any + expectation of additional consideration or compensation, the person + associating CC0 with a Work (the "Affirmer"), to the extent that he or + she is an owner of Copyright and Related Rights in the Work, + voluntarily elects to apply CC0 to the Work and publicly distribute + the Work under its terms, with knowledge of his or her Copyright and + Related Rights in the Work and the meaning and intended legal effect + of CC0 on those rights. + + 1. Copyright and Related Rights. A Work made available under CC0 may + be protected by copyright and related or neighboring rights + ("Copyright and Related Rights"). Copyright and Related Rights + include, but are not limited to, the following: + + the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + moral rights retained by the original author(s) and/or performer(s); + publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + rights protecting the extraction, dissemination, use and reuse of data + in a Work; + database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and + other similar, equivalent or corresponding rights throughout the world + based on applicable law or treaty, and any national implementations + thereof. + + 2. Waiver. To the greatest extent permitted by, but not in + contravention of, applicable law, Affirmer hereby overtly, fully, + permanently, irrevocably and unconditionally waives, abandons, and + surrenders all of Affirmer's Copyright and Related Rights and + associated claims and causes of action, whether now known or unknown + (including existing as well as future claims and causes of action), in + the Work (i) in all territories worldwide, (ii) for the maximum + duration provided by applicable law or treaty (including future time + extensions), (iii) in any current or future medium and for any number + of copies, and (iv) for any purpose whatsoever, including without + limitation commercial, advertising or promotional purposes (the + "Waiver"). Affirmer makes the Waiver for the benefit of each member of + the public at large and to the detriment of Affirmer's heirs and + successors, fully intending that such Waiver shall not be subject to + revocation, rescission, cancellation, termination, or any other legal + or equitable action to disrupt the quiet enjoyment of the Work by the + public as contemplated by Affirmer's express Statement of Purpose. + + 3. Public License Fallback. Should any part of the Waiver for any + reason be judged legally invalid or ineffective under applicable law, + then the Waiver shall be preserved to the maximum extent permitted + taking into account Affirmer's express Statement of Purpose. In + addition, to the extent the Waiver is so judged Affirmer hereby grants + to each affected person a royalty-free, non transferable, non + sublicensable, non exclusive, irrevocable and unconditional license to + exercise Affirmer's Copyright and Related Rights in the Work (i) in + all territories worldwide, (ii) for the maximum duration provided by + applicable law or treaty (including future time extensions), (iii) in + any current or future medium and for any number of copies, and (iv) + for any purpose whatsoever, including without limitation commercial, + advertising or promotional purposes (the "License"). The License shall + be deemed effective as of the date CC0 was applied by Affirmer to the + Work. Should any part of the License for any reason be judged legally + invalid or ineffective under applicable law, such partial invalidity + or ineffectiveness shall not invalidate the remainder of the License, + and in such case Affirmer hereby affirms that he or she will not (i) + exercise any of his or her remaining Copyright and Related Rights in + the Work or (ii) assert any associated claims and causes of action + with respect to the Work, in either case contrary to Affirmer's + express Statement of Purpose. + + 4. Limitations and Disclaimers. + + No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. + + Contributions thanks to: + niXman + Ely Arzhannikov + Alexey Pavlov + Ray Donnelly + Johannes Schindelin + +*/ + +#ifndef PATH_CONV_H_DB4IQBH3 +#define PATH_CONV_H_DB4IQBH3 + +#include + +const char* convert(char *dst, size_t dstlen, const char *src); + +#endif /* end of include guard: PATH_CONV_H_DB4IQBH3 */ + diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index e6f4c3e3de..d2bdf7d1ac 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -66,6 +66,7 @@ #include "shared_info.h" #include "tls_pbuf.h" #include "environ.h" +#include "msys2_path_conv.h" #undef basename suffix_info stat_suffixes[] = @@ -3872,6 +3873,74 @@ fchdir (int fd) return res; } +// +// Important: If returned pointer == arg, then this function +// did not malloc that pointer; otherwise free it. +// +extern "C" char * +arg_heuristic_with_exclusions (char const * const arg, char const * exclusions, size_t exclusions_count) +{ + char *arg_result; + + // Must return something .. + size_t arglen = (arg ? strlen (arg): 0); + + if (arglen == 0 || !arg) + { + arg_result = (char *)malloc (sizeof (char)); + arg_result[0] = '\0'; + return arg_result; + } + + debug_printf("Input value: (%s)", arg); + for (size_t excl = 0; excl < exclusions_count; ++excl) + { + /* Since we've got regex linked we should maybe switch to that, but + running regexes for every argument could be too slow. */ + if ( strcmp (exclusions, "*") == 0 || (strlen (exclusions) && strstr (arg, exclusions) == arg) ) + return (char*)arg; + exclusions += strlen (exclusions) + 1; + } + + // Leave enough room for at least 16 path elements; we might be converting + // a path list. + size_t stack_len = arglen + 16 * MAX_PATH; + char * stack_path = (char *)malloc (stack_len); + if (!stack_path) + { + debug_printf ("out of stack space?"); + return (char *)arg; + } + memset (stack_path, 0, MAX_PATH); + convert (stack_path, stack_len - 1, arg); + debug_printf ("convert()'ed: %s (length %d)\n.....->: %s", arg, arglen, stack_path); + // Don't allocate memory if no conversion happened. + if (!strcmp (arg, stack_path)) + { + if (arg != stack_path) + { + free (stack_path); + } + return ((char *)arg); + } + arg_result = (char *)realloc (stack_path, strlen (stack_path)+1); + // Windows doesn't like empty entries in PATH env. variables (;;) + char* semisemi = strstr(arg_result, ";;"); + while (semisemi) + { + memmove(semisemi, semisemi+1, strlen(semisemi)); + semisemi = strstr(semisemi, ";;"); + } + return arg_result; +} + +extern "C" char * +arg_heuristic (char const * const arg) +{ + return arg_heuristic_with_exclusions (arg, NULL, 0); +} + + /******************** Exported Path Routines *********************/ /* Cover functions to the path conversion routines. diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index f5a4b91d76..902cef8ae2 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -292,6 +292,27 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv, bool rc; int res = -1; + /* Environment variable MSYS2_ARG_CONV_EXCL contains a list + of ';' separated argument prefixes to pass un-modified.. + It isn't applied to env. variables; only spawn arguments. + A value of * means don't convert any arguments. */ + char* msys2_arg_conv_excl_env = getenv("MSYS2_ARG_CONV_EXCL"); + char* msys2_arg_conv_excl = NULL; + size_t msys2_arg_conv_excl_count = 0; + if (msys2_arg_conv_excl_env) + { + msys2_arg_conv_excl = (char*)alloca (strlen(msys2_arg_conv_excl_env)+1); + strcpy (msys2_arg_conv_excl, msys2_arg_conv_excl_env); + msys2_arg_conv_excl_count = 1; + msys2_arg_conv_excl_env = strchr ( msys2_arg_conv_excl, ';' ); + while (msys2_arg_conv_excl_env) + { + *msys2_arg_conv_excl_env = '\0'; + ++msys2_arg_conv_excl_count; + msys2_arg_conv_excl_env = strchr ( msys2_arg_conv_excl_env + 1, ';' ); + } + } + /* Check if we have been called from exec{lv}p or spawn{lv}p and mask mode to keep only the spawn mode. */ bool p_type_exec = !!(mode & _P_PATH_TYPE_EXEC); @@ -383,6 +404,20 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv, moreinfo->argc = newargv.argc; moreinfo->argv = newargv; } + else + { + for (int i = 0; i < newargv.argc; i++) + { + //convert argv to win32 + int newargvlen = strlen (newargv[i]); + char *tmpbuf = (char *)malloc (newargvlen + 1); + memcpy (tmpbuf, newargv[i], newargvlen + 1); + tmpbuf = arg_heuristic_with_exclusions(tmpbuf, msys2_arg_conv_excl, msys2_arg_conv_excl_count); + debug_printf("newargv[%d] = %s", i, newargv[i]); + newargv.replace (i, tmpbuf); + free (tmpbuf); + } + } if ((wincmdln || !real_path.iscygexec ()) && !cmd.fromargv (newargv, real_path.get_win32 (), real_path.iscygexec ())) @@ -513,7 +548,8 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv, moreinfo->envp = build_env (envp, envblock, moreinfo->envc, real_path.iscygexec (), switch_user ? ::cygheap->user.primary_token () - : NULL); + : NULL, + real_path.iscygexec ()); if (!moreinfo->envp || !envblock) { set_errno (E2BIG); From d6cd58e21e1b8157e4b715af7a654a63f615b062 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B8=CC=86=20=D0=9F?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=BE=D0=B2?= Date: Sun, 14 Apr 2019 21:29:01 +0300 Subject: [PATCH 05/50] Add functionality for changing OS name via MSYSTEM environment variables. --- winsup/cygserver/cygserver-config | 4 ++-- winsup/cygwin/environ.cc | 34 ++++++++++++++++++++++++++--- winsup/cygwin/include/sys/utsname.h | 2 +- winsup/cygwin/uname.cc | 17 +++++++++++++-- 4 files changed, 49 insertions(+), 8 deletions(-) diff --git a/winsup/cygserver/cygserver-config b/winsup/cygserver/cygserver-config index 373bfd24dd..c902857ea7 100755 --- a/winsup/cygserver/cygserver-config +++ b/winsup/cygserver/cygserver-config @@ -86,7 +86,7 @@ done # Check if running on NT _sys="`uname`" -_nt=`expr "${_sys}" : "CYGWIN_NT"` +_nt=`expr "${_sys}" : "MSYS_NT"` # Check for running cygserver processes first. if ps -ef | grep -v grep | grep -q ${service_name} @@ -178,7 +178,7 @@ then echo "Do you want to install cygserver as service?" if request "(Say \"no\" if it's already installed as service)" then - if ! cygrunsrv -I ${service_name} -d "CYGWIN cygserver" -p /usr/sbin/cygserver + if ! cygrunsrv -I ${service_name} -d "MSYS cygserver" -p /usr/sbin/cygserver then echo echo "Installation of cygserver as service failed. Please check the" diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index 639e69393b..b9f7e05452 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -192,7 +192,11 @@ parse_options (const char *inbuf) if (export_settings) { debug_printf ("%s", newbuf + 1); +#ifdef __MSYS__ + setenv ("MSYS", newbuf + 1, 1); +#else setenv ("CYGWIN", newbuf + 1, 1); +#endif } return; } @@ -651,7 +655,7 @@ _addenv (const char *name, const char *value, int overwrite) win_env *spenv; if ((spenv = getwinenv (envhere))) spenv->add_cache (value); - if (strcmp (name, "CYGWIN") == 0) + if (strcmp (name, "MSYS") == 0) parse_options (value); return 0; @@ -754,6 +758,9 @@ static struct renv { } renv_arr[] = { { NL("COMMONPROGRAMFILES=") }, // 0 { NL("COMSPEC=") }, +#ifdef __MSYS__ + { NL("MSYSTEM=") }, // 2 +#endif /* __MSYS__ */ { NL("PATH=") }, // 2 { NL("PROGRAMFILES=") }, { NL("SYSTEMDRIVE=") }, // 4 @@ -765,10 +772,21 @@ static struct renv { #define RENV_SIZE (sizeof (renv_arr) / sizeof (renv_arr[0])) /* Set of first characters of the above list of variables. */ -static const char idx_arr[] = "CPSTW"; +static const char idx_arr[] = +#ifdef __MSYS__ + "CMPSTW"; +#else + "CPSTW"; +#endif /* Index into renv_arr at which the variables with this specific character starts. */ -static const int start_at[] = { 0, 2, 4, 6, 8 }; +static const int start_at[] = { +#ifdef __MSYS__ + 0, 2, 3, 5, 7, 9 +#else + 0, 2, 4, 6, 8 +#endif + }; /* Turn environment variable part of a=b string into uppercase - for some environment variables only. */ @@ -836,7 +854,11 @@ environ_init (char **envp, int envc) dumper_init (); if (envp_passed_in) { +#ifdef __MSYS__ + p = getenv ("MSYS"); +#else p = getenv ("CYGWIN"); +#endif if (p) parse_options (p); } @@ -883,8 +905,13 @@ win32env_to_cygenv (PWCHAR rawenv, bool posify) ucenv (newp, eq); /* uppercase env vars which need it */ if (*newp == 'T' && strncmp (newp, "TERM=", 5) == 0) sawTERM = 1; +#ifdef __MSYS__ + else if (*newp == 'M' && strncmp (newp, "MSYS=", 5) == 0) + parse_options (newp + 5); +#else else if (*newp == 'C' && strncmp (newp, "CYGWIN=", 7) == 0) parse_options (newp + 7); +#endif if (*eq && posify) posify_maybe (envp + i, *++eq ? eq : --eq, tmpbuf); debug_printf ("%p: %s", envp[i], envp[i]); @@ -959,6 +986,7 @@ static NO_COPY spenv spenvs[] = {NL ("HOMEPATH="), false, false, &cygheap_user::env_homepath}, {NL ("LOGONSERVER="), false, false, &cygheap_user::env_logsrv}, {NL ("PATH="), false, true, NULL}, + {NL ("MSYSTEM="), true, true, NULL}, {NL ("SYSTEMDRIVE="), false, true, NULL}, {NL ("SYSTEMROOT="), true, true, &cygheap_user::env_systemroot}, {NL ("USERDOMAIN="), false, false, &cygheap_user::env_domain}, diff --git a/winsup/cygwin/include/sys/utsname.h b/winsup/cygwin/include/sys/utsname.h index d6b3be96f7..730cb731a5 100644 --- a/winsup/cygwin/include/sys/utsname.h +++ b/winsup/cygwin/include/sys/utsname.h @@ -17,7 +17,7 @@ extern "C" { struct utsname { - char sysname[_UTSNAME_LENGTH]; + char sysname[_UTSNAME_LENGTH + 1]; char nodename[_UTSNAME_LENGTH]; char release[_UTSNAME_LENGTH]; char version[_UTSNAME_LENGTH]; diff --git a/winsup/cygwin/uname.cc b/winsup/cygwin/uname.cc index dd4160189c..0d0c5aa52a 100644 --- a/winsup/cygwin/uname.cc +++ b/winsup/cygwin/uname.cc @@ -36,7 +36,12 @@ uname_x (struct utsname *name) memset (name, 0, sizeof (*name)); /* sysname */ - __small_sprintf (name->sysname, "CYGWIN_%s-%u", + char* msystem = getenv("MSYSTEM"); + const char* msystem_sysname = "MSYS"; + if (msystem != NULL && *msystem && strcmp(msystem, "MSYS") != 0) + msystem_sysname = (strstr(msystem, "32") != NULL) ? "MINGW32" : "MINGW64";; + __small_sprintf (name->sysname, "%s_%s-%u", + msystem_sysname, wincap.osname (), wincap.build_number ()); /* nodename */ memset (buf, 0, sizeof buf); @@ -88,7 +93,7 @@ uname_x (struct utsname *name) /* Old entrypoint for applications up to API 334 */ struct old_utsname { - char sysname[20]; + char sysname[21]; char nodename[20]; char release[20]; char version[20]; @@ -102,7 +107,15 @@ uname (struct utsname *in_name) __try { memset (name, 0, sizeof (*name)); +#ifdef __MSYS__ + char* msystem = getenv("MSYSTEM"); + const char* msystem_sysname = "MSYS"; + if (msystem != NULL && *msystem && strcmp(msystem, "MSYS") != 0) + msystem_sysname = (strstr(msystem, "32") != NULL) ? "MINGW32" : "MINGW64"; + __small_sprintf (name->sysname, "%s_%s", msystem_sysname, wincap.osname ()); +#else __small_sprintf (name->sysname, "CYGWIN_%s", wincap.osname ()); +#endif /* Computer name */ cygwin_gethostname (name->nodename, sizeof (name->nodename) - 1); From e7d3c8f96ea04770599cca058bc1c622d7aa2df0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B8=CC=86=20=D0=9F?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=BE=D0=B2?= Date: Sun, 14 Apr 2019 21:45:06 +0300 Subject: [PATCH 06/50] - Move root to /usr. - Change sorting mount points. - By default mount without ACLs. - Can read /etc/fstab with short mount point format. --- winsup/cygwin/local_includes/mount.h | 3 +- winsup/cygwin/mm/cygheap.cc | 12 +- winsup/cygwin/mount.cc | 185 +++++++++++++++++++++++---- winsup/cygwin/uinfo.cc | 2 +- 4 files changed, 174 insertions(+), 28 deletions(-) diff --git a/winsup/cygwin/local_includes/mount.h b/winsup/cygwin/local_includes/mount.h index b2acdf08b4..1fc5c39b76 100644 --- a/winsup/cygwin/local_includes/mount.h +++ b/winsup/cygwin/local_includes/mount.h @@ -172,7 +172,6 @@ class mount_info mount_item mount[MAX_MOUNTS]; static bool got_usr_bin; - static bool got_usr_lib; static int root_idx; /* cygdrive_prefix is used as the root of the path automatically @@ -184,6 +183,8 @@ class mount_info private: int posix_sorted[MAX_MOUNTS]; int native_sorted[MAX_MOUNTS]; + int longest_posix_sorted[MAX_MOUNTS]; + int shortest_native_sorted[MAX_MOUNTS]; public: void init (bool); diff --git a/winsup/cygwin/mm/cygheap.cc b/winsup/cygwin/mm/cygheap.cc index 3dc0c011fa..bf4d82f07c 100644 --- a/winsup/cygwin/mm/cygheap.cc +++ b/winsup/cygwin/mm/cygheap.cc @@ -220,14 +220,22 @@ init_cygheap::init_installation_root () /* Strip off last path component ("\\cygwin1.dll") */ PWCHAR w = wcsrchr (installation_root_buf, L'\\'); +#ifdef __MSYS__ + /* Back two folders to get root as we have all stuff in usr subfolder */ + for (int i=1; i >=0; --i) + { +#endif if (w) { *w = L'\0'; w = wcsrchr (installation_root_buf, L'\\'); } if (!w) - api_fatal ("Can't initialize Cygwin installation root dir.\n" + api_fatal ("Can't initialize MSYS2 installation root dir.\n" "Invalid DLL path"); +#ifdef __MSYS__ + } +#endif /* Copy result into installation_dir before stripping off "bin" dir and revert to Win32 path. This path is added to the Windows environment @@ -252,6 +260,7 @@ init_cygheap::init_installation_root () RtlInitUnicodeString (&installation_root, installation_root_buf); RtlInitUnicodeString (&installation_dir, installation_dir_buf); +#ifndef __MSYS__ for (int i = 1; i >= 0; --i) { reg_key r (i, KEY_WRITE, _WIDE (CYGWIN_INFO_INSTALLATIONS_NAME), @@ -260,6 +269,7 @@ init_cygheap::init_installation_root () installation_root_buf))) break; } +#endif } /* Initialize bucket_val. The value is the max size of a block diff --git a/winsup/cygwin/mount.cc b/winsup/cygwin/mount.cc index bf26c4af3e..eff9803241 100644 --- a/winsup/cygwin/mount.cc +++ b/winsup/cygwin/mount.cc @@ -42,7 +42,6 @@ details. */ (path_prefix_p (proc, (path), proc_len, false)) bool NO_COPY mount_info::got_usr_bin; -bool NO_COPY mount_info::got_usr_lib; int NO_COPY mount_info::root_idx = -1; /* is_native_path: Return non-zero if PATH starts with \??\[a-zA-Z] or @@ -395,7 +394,6 @@ fs_info::update (PUNICODE_STRING upath, HANDLE in_vol) #define MINIMAL_WIN_NTFS_FLAGS (FILE_CASE_SENSITIVE_SEARCH \ | FILE_CASE_PRESERVED_NAMES \ | FILE_UNICODE_ON_DISK \ - | FILE_PERSISTENT_ACLS \ | FILE_FILE_COMPRESSION \ | FILE_VOLUME_QUOTAS \ | FILE_SUPPORTS_SPARSE_FILES \ @@ -552,13 +550,13 @@ mount_info::create_root_entry (const PWCHAR root) sys_wcstombs (native_root, PATH_MAX, root); assert (*native_root != '\0'); if (add_item (native_root, "/", - MOUNT_SYSTEM | MOUNT_IMMUTABLE | MOUNT_AUTOMATIC) + MOUNT_SYSTEM | MOUNT_IMMUTABLE | MOUNT_AUTOMATIC | MOUNT_NOACL) < 0) api_fatal ("add_item (\"%s\", \"/\", ...) failed, errno %d", native_root, errno); /* Create a default cygdrive entry. Note that this is a user entry. This allows to override it with mount, unless the sysadmin created a cygdrive entry in /etc/fstab. */ - cygdrive_flags = MOUNT_NOPOSIX | MOUNT_CYGDRIVE; + cygdrive_flags = MOUNT_NOPOSIX | MOUNT_CYGDRIVE | MOUNT_NOACL; strcpy (cygdrive, CYGWIN_INFO_CYGDRIVE_DEFAULT_PREFIX "/"); cygdrive_len = strlen (cygdrive); } @@ -578,22 +576,14 @@ mount_info::init (bool user_init) pathend = wcpcpy (pathend, L"\\etc\\fstab"); from_fstab (user_init, path, pathend); - if (!user_init && (!got_usr_bin || !got_usr_lib)) + if (!user_init && !got_usr_bin) { char native[PATH_MAX]; if (root_idx < 0) - api_fatal ("root_idx %d, user_shared magic %y, nmounts %d", root_idx, user_shared->version, nmounts); + api_fatal ("root_idx %d, user_shared magic %y, nmounts %d", root_idx, user_shared->version, nmounts); char *p = stpcpy (native, mount[root_idx].native_path); - if (!got_usr_bin) - { - stpcpy (p, "\\bin"); - add_item (native, "/usr/bin", MOUNT_SYSTEM | MOUNT_AUTOMATIC); - } - if (!got_usr_lib) - { - stpcpy (p, "\\lib"); - add_item (native, "/usr/lib", MOUNT_SYSTEM | MOUNT_AUTOMATIC); - } + stpcpy (p, "\\usr\\bin"); + add_item (native, "/bin", MOUNT_SYSTEM | MOUNT_AUTOMATIC | MOUNT_NOACL); } } @@ -674,6 +664,7 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev, /* See if this is a cygwin "device" */ if (win32_device_name (src_path, dst, dev)) { + debug_printf ("win32_device_name (%s)", src_path); *flags = 0; rc = 0; goto out_no_chroot_check; @@ -711,6 +702,7 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev, } if (isproc (src_path)) { + debug_printf ("isproc (%s)", src_path); dev = *proc_dev; dev = fhandler_proc::get_proc_fhandler (src_path); if (dev == FH_NADA) @@ -732,6 +724,7 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev, off the prefix and transform it into an MS-DOS path. */ else if (iscygdrive (src_path)) { + debug_printf ("iscygdrive (%s) mount_table->cygdrive %s", src_path, mount_table->cygdrive); int n = mount_table->cygdrive_len - 1; int unit; @@ -743,11 +736,15 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev, } else if (cygdrive_win32_path (src_path, dst, unit)) { + debug_printf ("cygdrive_win32_path (%s)", src_path); *flags = cygdrive_flags; goto out; } else if (mount_table->cygdrive_len > 1) - return ENOENT; + { + debug_printf ("mount_table->cygdrive_len > 1 (%s)", src_path); + return ENOENT; + } } int chroot_pathlen; @@ -758,7 +755,9 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev, const char *path; int len; - mi = mount + posix_sorted[i]; + mi = mount + shortest_native_sorted[i]; + debug_printf (" mount[%d] .. checking %s -> %s ", i, mi->posix_path, mi->native_path); + if (!cygheap->root.exists () || (mi->posix_pathlen == 1 && mi->posix_path[0] == '/')) { @@ -998,7 +997,8 @@ mount_info::conv_to_posix_path (const char *src_path, char *posix_path, int pathbuflen = tail - pathbuf; for (int i = 0; i < nmounts; ++i) { - mount_item &mi = mount[native_sorted[i]]; + mount_item &mi = mount[longest_posix_sorted[i]]; + debug_printf (" mount[%d] .. checking %s -> %s ", i, mi.posix_path, mi.native_path); if (!path_prefix_p (mi.native_path, pathbuf, mi.native_pathlen, mi.flags & MOUNT_NOPOSIX)) continue; @@ -1211,8 +1211,17 @@ mount_info::from_fstab_line (char *line, bool user) if (!*c) return true; cend = find_ws (c); - *cend = '\0'; posix_path = conv_fstab_spaces (c); + if (!*cend) + { + unsigned mount_flags = MOUNT_SYSTEM | MOUNT_NOPOSIX | MOUNT_NOACL; + + int res = mount_table->add_item (native_path, posix_path, mount_flags); + if (res && get_errno () == EMFILE) + return false; + return true; + } + *cend = '\0'; /* Third field: FS type. */ c = skip_ws (cend + 1); if (!*c) @@ -1441,16 +1450,145 @@ sort_by_native_name (const void *a, const void *b) return res; } +/* sort_by_longest_posix_name: qsort callback to sort the mount entries. + Sort user mounts ahead of system mounts to the same POSIX path. */ +/* FIXME: should the user should be able to choose whether to + prefer user or system mounts??? */ +static int +sort_by_longest_posix_name (const void *a, const void *b) +{ + mount_item *ap = mounts_for_sort + (*((int*) a)); + mount_item *bp = mounts_for_sort + (*((int*) b)); + + /* Base weighting on the conversion that would give the longest + posix path. */ + ssize_t alen = (ssize_t) strlen (ap->posix_path) - (ssize_t) strlen (ap->native_path); + ssize_t blen = (ssize_t) strlen (bp->posix_path) - (ssize_t) strlen (bp->native_path); + + int res = blen - alen; + + if (res) + return res; /* Path lengths differed */ + + /* The two paths were the same length, so just determine normal + lexical sorted order. */ + res = strcmp (ap->posix_path, bp->posix_path); + + if (res == 0) + { + /* need to select between user and system mount to same POSIX path */ + if (!(bp->flags & MOUNT_SYSTEM)) /* user mount */ + return 1; + else + return -1; + } + + return res; +} + +/* sort_by_shortest_native_name: qsort callback to sort the mount entries. + Sort user mounts ahead of system mounts to the same POSIX path. */ +/* FIXME: should the user should be able to choose whether to + prefer user or system mounts??? */ +static int +sort_by_shortest_native_name (const void *a, const void *b) +{ + mount_item *ap = mounts_for_sort + (*((int*) a)); + mount_item *bp = mounts_for_sort + (*((int*) b)); + + /* Base weighting on the conversion that would give the shortest + native path. */ + ssize_t alen = (ssize_t) strlen (ap->native_path); + ssize_t blen = (ssize_t) strlen (bp->native_path); + + int res = alen - blen; + + if (res) + return res; /* Path lengths differed */ + + /* The two paths were the same length, so just determine normal + lexical sorted order. */ + res = strcmp (ap->native_path, bp->native_path); + + if (res == 0) + { + /* need to select between user and system mount to same POSIX path */ + if (!(bp->flags & MOUNT_SYSTEM)) /* user mount */ + return 1; + else + return -1; + } + + return res; +} + +static int +sort_posix_subdirs_before_parents (const void *a, const void *b) +{ + mount_item *ap = mounts_for_sort + (*((int*) a)); + mount_item *bp = mounts_for_sort + (*((int*) b)); + + if (ap->posix_pathlen > bp->posix_pathlen) + { + if (!memcmp (bp->posix_path, ap->posix_path, bp->posix_pathlen)) + { + // bp is a subdir of ap (bp must be moved in-front) + return -1; + } + } + else if (ap->posix_pathlen < bp->posix_pathlen) + { + if (!memcmp (ap->posix_path, bp->posix_path, ap->posix_pathlen)) + { + // ap is a subdir of bp (good as we are) + return 1; + } + } + return 0; +} + +#define DISABLE_NEW_STUFF 0 +#define ONLY_USE_NEW_STUFF 1 + void mount_info::sort () { for (int i = 0; i < nmounts; i++) - native_sorted[i] = posix_sorted[i] = i; + native_sorted[i] = posix_sorted[i] = shortest_native_sorted[i] = longest_posix_sorted[i] = i; /* Sort them into reverse length order, otherwise we won't be able to look for /foo in /. */ mounts_for_sort = mount; /* ouch. */ qsort (posix_sorted, nmounts, sizeof (posix_sorted[0]), sort_by_posix_name); qsort (native_sorted, nmounts, sizeof (native_sorted[0]), sort_by_native_name); + qsort (longest_posix_sorted, nmounts, sizeof (longest_posix_sorted[0]), sort_by_longest_posix_name); + qsort (shortest_native_sorted, nmounts, sizeof (shortest_native_sorted[0]), sort_by_shortest_native_name); + qsort (shortest_native_sorted, nmounts, sizeof (shortest_native_sorted[0]), sort_posix_subdirs_before_parents); + /* Disabling my new crap. */ + #if DISABLE_NEW_STUFF + for (int i = 0; i < nmounts; i++) + { + longest_posix_sorted[i] = native_sorted[i]; + shortest_native_sorted[i] = posix_sorted[i]; + } + #else + #if ONLY_USE_NEW_STUFF + for (int i = 0; i < nmounts; i++) + { + native_sorted[i] = longest_posix_sorted[i]; + posix_sorted[i] = shortest_native_sorted[i]; + } + #endif + #endif + for (int i = 0; i < nmounts; i++) + { + mount_item *mi = mount + shortest_native_sorted[i]; + debug_printf ("shortest_native_sorted (subdirs before parents)[%d] %12s %12s", i, mi->native_path, mi->posix_path); + } + for (int i = 0; i < nmounts; i++) + { + mount_item *mi = mount + longest_posix_sorted[i]; + debug_printf ("longest_posix_sorted[%d] %12s %12s", i, mi->native_path, mi->posix_path); + } } /* Add an entry to the mount table. @@ -1541,12 +1679,9 @@ mount_info::add_item (const char *native, const char *posix, if (i == nmounts) nmounts++; - if (strcmp (posixtmp, "/usr/bin") == 0) + if (strcmp (posixtmp, "/bin") == 0) got_usr_bin = true; - if (strcmp (posixtmp, "/usr/lib") == 0) - got_usr_lib = true; - if (posixtmp[0] == '/' && posixtmp[1] == '\0' && !(mountflags & MOUNT_CYGDRIVE)) root_idx = i; diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc index acbc945e41..81d9529824 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -2827,7 +2827,7 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap) dom, name, sid.string ((char *) sidstr), home ?: "/home/", home ? L"" : name, - shell ?: "/bin/bash"); + shell ?: "/usr/bin/bash"); if (gecos) free (gecos); if (home) From 8c5cc2861a2b7e42fe4cf862b56bbc7424e5b1ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B8=CC=86=20=D0=9F?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=BE=D0=B2?= Date: Sun, 14 Apr 2019 21:47:21 +0300 Subject: [PATCH 07/50] Instead of creating Cygwin symlinks, use deep copy by default The new `winsymlinks` mode `deepcopy` (which is made the default) lets calls to `symlink()` create (deep) copies of the source file/directory. This is necessary because unlike Cygwin, MSYS2 does not try to be its own little ecosystem that lives its life separate from regular Win32 programs: the latter have _no idea_ about Cygwin-emulated symbolic links (i.e. system files whose contents start with `!\xff\xfe` and the remainder consists of the NUL-terminated, UTF-16LE-encoded symlink target). To support Cygwin-style symlinks, the new mode `sysfile` is introduced. Co-authored-by: Johannes Schindelin --- winsup/cygwin/environ.cc | 4 + winsup/cygwin/globals.cc | 3 +- winsup/cygwin/path.cc | 154 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 160 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index b9f7e05452..5fb3f53ef5 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -88,6 +88,10 @@ set_winsymlinks (const char *buf) else if (ascii_strncasematch (buf, "native", 6)) allow_winsymlinks = ascii_strcasematch (buf + 6, "strict") ? WSYM_nativestrict : WSYM_native; + else if (ascii_strncasematch (buf, "deepcopy", 8)) + allow_winsymlinks = WSYM_deepcopy; + else + allow_winsymlinks = WSYM_sysfile; } /* The structure below is used to set up an array which is used to diff --git a/winsup/cygwin/globals.cc b/winsup/cygwin/globals.cc index d14ea593f6..0c21fa624e 100644 --- a/winsup/cygwin/globals.cc +++ b/winsup/cygwin/globals.cc @@ -57,6 +57,7 @@ enum winsym_t WSYM_nativestrict, WSYM_nfs, WSYM_sysfile, + WSYM_deepcopy }; exit_states NO_COPY exit_state; @@ -70,7 +71,7 @@ bool ignore_case_with_glob; bool pipe_byte = true; /* Default to byte mode so that C# programs work. */ bool reset_com; bool wincmdln; -winsym_t allow_winsymlinks = WSYM_default; +winsym_t allow_winsymlinks = WSYM_deepcopy; bool disable_pcon; bool winjitdebug = false; diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index d2bdf7d1ac..6ec06fb3e1 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -1685,6 +1685,89 @@ conv_path_list (const char *src, char *dst, size_t size, /********************** Symbolic Link Support **************************/ +/* + Create a deep copy of src as dst, while avoiding descending in origpath. +*/ +static int +recursiveCopy (char * src, char * dst, const char * origpath) +{ + WIN32_FIND_DATA dHfile; + HANDLE dH = INVALID_HANDLE_VALUE; + BOOL findfiles; + int srcpos = strlen (src); + int dstpos = strlen (dst); + int res = -1; + + debug_printf("recursiveCopy (%s, %s)", src, dst); + + /* Create the destination directory */ + if (!CreateDirectoryEx (src, dst, NULL)) + { + debug_printf("CreateDirectoryEx(%s, %s, 0) failed", src, dst); + __seterrno (); + goto done; + } + /* Descend into the source directory */ + if (srcpos + 2 >= MAX_PATH || dstpos + 1 >= MAX_PATH) + { + set_errno (ENAMETOOLONG); + goto done; + } + strcat (src, "\\*"); + strcat (dst, "\\"); + dH = FindFirstFile (src, &dHfile); + debug_printf("dHfile(1): %s", dHfile.cFileName); + findfiles = FindNextFile (dH, &dHfile); + debug_printf("dHfile(2): %s", dHfile.cFileName); + findfiles = FindNextFile (dH, &dHfile); + while (findfiles) + { + /* Append the directory item filename to both source and destination */ + int filelen = strlen (dHfile.cFileName); + debug_printf("dHfile(3): %s", dHfile.cFileName); + if (srcpos + 1 + filelen >= MAX_PATH || + dstpos + 1 + filelen >= MAX_PATH) + { + set_errno (ENAMETOOLONG); + goto done; + } + strcpy (&src[srcpos+1], dHfile.cFileName); + strcpy (&dst[dstpos+1], dHfile.cFileName); + debug_printf("%s -> %s", src, dst); + if (dHfile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + /* Recurse into the child directory */ + debug_printf("%s <-> %s", src, origpath); + if (strcmp (src, origpath)) // avoids endless recursion + if (recursiveCopy (src, dst, origpath)) + goto done; + } + else + { + /* Just copy the file */ + if (!CopyFile (src, dst, FALSE)) + { + __seterrno (); + goto done; + } + } + findfiles = FindNextFile (dH, &dHfile); + } + if (GetLastError() != ERROR_NO_MORE_FILES) + { + __seterrno (); + goto done; + } + res = 0; + +done: + + if (dH != INVALID_HANDLE_VALUE) + FindClose (dH); + + return res; +} + /* Create a symlink from FROMPATH to TOPATH. */ extern "C" int @@ -2221,6 +2304,77 @@ symlink_worker (const char *oldpath, path_conv &win32_newpath, bool isdevice) } else /* wsym_type == WSYM_sysfile */ { + if (wsym_type == WSYM_deepcopy) + { + path_conv src_path; + src_path.check (oldpath, PC_SYM_NOFOLLOW, stat_suffixes); + if (src_path.error) + { + set_errno (src_path.error); + __leave; + } + if (!src_path.isdevice () && !src_path.is_fs_special ()) + { + /* MSYS copy file instead make symlink */ + + char * real_oldpath; + if (isabspath (oldpath)) + strcpy (real_oldpath = tp.c_get (), oldpath); + else + /* Find the real source path, relative + to the directory of the destination */ + { + /* Determine the character position of the last path component */ + const char *newpath = win32_newpath.get_posix(); + int pos = strlen (newpath); + while (--pos >= 0) + if (isdirsep (newpath[pos])) + break; + /* Append the source path to the directory + component of the destination */ + if (pos+1+strlen(oldpath) >= MAX_PATH) + { + set_errno(ENAMETOOLONG); + __leave; + } + strcpy (real_oldpath = tp.c_get (), newpath); + strcpy (&real_oldpath[pos+1], oldpath); + } + + /* As a MSYS limitation, the source path must exist. */ + path_conv win32_oldpath; + win32_oldpath.check (real_oldpath, PC_SYM_NOFOLLOW, stat_suffixes); + if (!win32_oldpath.exists ()) + { + set_errno (ENOENT); + __leave; + } + + char *w_newpath; + char *w_oldpath; + stpcpy (w_newpath = tp.c_get (), win32_newpath.get_win32()); + stpcpy (w_oldpath = tp.c_get (), win32_oldpath.get_win32()); + if (win32_oldpath.isdir()) + { + char *origpath; + strcpy (origpath = tp.c_get (), w_oldpath); + res = recursiveCopy (w_oldpath, w_newpath, origpath); + } + else + { + if (!CopyFile (w_oldpath, w_newpath, FALSE)) + { + __seterrno (); + } + else + { + res = 0; + } + } + __leave; + } + } + /* Default technique creating a symlink. */ buf = tp.t_get (); cp = stpcpy (buf, SYMLINK_COOKIE); From e9074291e7ecf75a70db8ab612da18b0da0953b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B8=CC=86=20=D0=9F?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=BE=D0=B2?= Date: Sun, 14 Apr 2019 21:48:54 +0300 Subject: [PATCH 08/50] Automatically rewrite TERM=msys to TERM=cygwin With MSys1, it was necessary to set the TERM variable to "msys". To allow for a smooth transition from MSys1 to MSys2, let's simply handle TERM=msys as if the user had not specified TERM at all and wanted us to use our preferred TERM value. --- winsup/cygwin/environ.cc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index 5fb3f53ef5..117531367e 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -908,7 +908,16 @@ win32env_to_cygenv (PWCHAR rawenv, bool posify) char *eq = strchrnul (newp, '='); ucenv (newp, eq); /* uppercase env vars which need it */ if (*newp == 'T' && strncmp (newp, "TERM=", 5) == 0) - sawTERM = 1; + { + /* backwards compatibility: override TERM=msys by TERM=cygwin */ + if (strcmp (newp + 5, "msys") == 0) + { + free(newp); + i--; + continue; + } + sawTERM = 1; + } #ifdef __MSYS__ else if (*newp == 'M' && strncmp (newp, "MSYS=", 5) == 0) parse_options (newp + 5); From 8102cded4c93aae879027be150ec36fd04c37545 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B8=CC=86=20=D0=9F?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=BE=D0=B2?= Date: Sun, 14 Apr 2019 21:50:55 +0300 Subject: [PATCH 09/50] Do not convert environment for strace Strace is a Windows program so MSYS2 will convert all arguments and environment vars and that makes debugging msys2 software with strace very tricky. --- winsup/cygwin/spawn.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index 902cef8ae2..d7affaac88 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -545,11 +545,13 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv, bool switch_user = ::cygheap->user.issetuid () && (::cygheap->user.saved_uid != ::cygheap->user.real_uid); + bool keep_posix = (iscmd (argv[0], "strace.exe") + || iscmd (argv[0], "strace")) ? true : real_path.iscygexec (); moreinfo->envp = build_env (envp, envblock, moreinfo->envc, real_path.iscygexec (), switch_user ? ::cygheap->user.primary_token () : NULL, - real_path.iscygexec ()); + keep_posix); if (!moreinfo->envp || !envblock) { set_errno (E2BIG); From c68f8fd84b0d5da778866a85f0b6c86b798359d3 Mon Sep 17 00:00:00 2001 From: Ray Donnelly Date: Sun, 23 Aug 2015 20:47:30 +0100 Subject: [PATCH 10/50] strace.cc: Don't set MSYS=noglob Commit message for this code was: * strace.cc (create_child): Set CYGWIN=noglob when starting new process so that Cygwin will leave already-parsed the command line alonw." I can see no reason for it and it badly breaks the ability to use strace.exe to investigate calling a Cygwin program from a Windows program, for example: strace mingw32-make.exe .. where mingw32-make.exe finds sh.exe and uses it as the shell. The reason it badly breaks this use-case is because dcrt0.cc depends on globbing to happen to parse commandlines from Windows programs; irrespective of whether they contain any glob patterns or not. See quoted () comment: "This must have been run from a Windows shell, so preserve quotes for globify to play with later." --- winsup/utils/mingw/strace.cc | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/winsup/utils/mingw/strace.cc b/winsup/utils/mingw/strace.cc index 29db640239..25adf4e8dd 100644 --- a/winsup/utils/mingw/strace.cc +++ b/winsup/utils/mingw/strace.cc @@ -354,10 +354,28 @@ create_child (char **argv) make_command_line (one_line, argv); SetConsoleCtrlHandler (NULL, 0); +/* Commit message for this code was: +"* strace.cc (create_child): Set CYGWIN=noglob when starting new process so that + + Cygwin will leave already-parsed the command line alonw." + + I can see no reason for it and it badly breaks the ability to use + strace.exe to investigate calling a Cygwin program from a Windows + program, for example: + strace mingw32-make.exe + .. where mingw32-make.exe finds sh.exe and uses it as the shell. + The reason it badly breaks this use-case is because dcrt0.cc depends + on globbing to happen to parse commandlines from Windows programs; + irrespective of whether they contain any glob patterns or not. + + See quoted () comment: + "This must have been run from a Windows shell, so preserve + quotes for globify to play with later." + const char *cygwin_env = getenv ("MSYS"); const char *space; - if (cygwin_env && strlen (cygwin_env) <= 256) /* sanity check */ + if (cygwin_env && strlen (cygwin_env) <= 256) // sanity check space = " "; else space = cygwin_env = ""; @@ -365,6 +383,7 @@ create_child (char **argv) + strlen (space) + strlen (cygwin_env)); sprintf (newenv, "MSYS=noglob%s%s", space, cygwin_env); _putenv (newenv); +*/ ret = CreateProcess (0, one_line.buf, /* command line */ NULL, /* Security */ NULL, /* thread */ From e6cc70d89e9410573b3fad0c16e69c7cc02277dc Mon Sep 17 00:00:00 2001 From: Ray Donnelly Date: Fri, 21 Aug 2015 09:52:47 +0100 Subject: [PATCH 11/50] Add debugging for strace make_command_line --- winsup/utils/mingw/strace.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/winsup/utils/mingw/strace.cc b/winsup/utils/mingw/strace.cc index 25adf4e8dd..d346abc4e7 100644 --- a/winsup/utils/mingw/strace.cc +++ b/winsup/utils/mingw/strace.cc @@ -352,6 +352,7 @@ create_child (char **argv) flags |= CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP; make_command_line (one_line, argv); + printf ("create_child: %s\n", one_line.buf); SetConsoleCtrlHandler (NULL, 0); /* Commit message for this code was: From e25ab8660e6040a9526ca985edec430625b47b5c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 17 May 2017 18:13:32 +0200 Subject: [PATCH 12/50] strace --quiet: be *really* quiet The biggest problem with strace spitting out `create_child: ...` despite being asked to be real quiet is that its output can very well interfere with scripts' operations. For example, when running any of Git for Windows' shell scripts with `GIT_STRACE_COMMANDS=/path/to/logfile` (which is sadly an often needed debugging technique while trying to address the many MSYS2 issues Git for Windows faces), any time the output of any command is redirected into a variable, it will include that `create_child: ...` line, wreaking havoc with Git's expectations. So let's just really be quiet when we're asked to be quiet. Signed-off-by: Johannes Schindelin --- winsup/utils/mingw/strace.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/winsup/utils/mingw/strace.cc b/winsup/utils/mingw/strace.cc index d346abc4e7..a6b2e5d548 100644 --- a/winsup/utils/mingw/strace.cc +++ b/winsup/utils/mingw/strace.cc @@ -352,7 +352,8 @@ create_child (char **argv) flags |= CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP; make_command_line (one_line, argv); - printf ("create_child: %s\n", one_line.buf); + if (!quiet) + printf ("create_child: %s\n", one_line.buf); SetConsoleCtrlHandler (NULL, 0); /* Commit message for this code was: From 8e182331c4c06b839da9f0e71aa5098df7d564ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B8=CC=86=20=D0=9F?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=BE=D0=B2?= Date: Sun, 14 Apr 2019 22:13:51 +0300 Subject: [PATCH 13/50] path_conv: special-case root directory to have trailing slash When converting `/c/` to `C:\`, the trailing slash is actually really necessary, as `C:` is not an absolute path. We must be very careful to do this only for root directories, though. If we kept the trailing slash also for, say, `/y/directory/`, we would run into the following issue: On FAT file systems, the normalized path is used to fake inode numbers. As a result, `Y:\directory\` and `Y:\directory` have different inode numbers!!! This would result in very non-obvious symptoms. Back when we were too careless about keeping the trailing slash, it was reported to the Git for Windows project that the `find` and `rm` commands can error out on FAT file systems with very confusing "No such file or directory" errors, for no good reason. During the original investigation, Vasil Minkov pointed out in https://github.com/git-for-windows/git/issues/1497#issuecomment-372665870, that this bug had been fixed in Cygwin as early as 1997... and the bug was unfortunately reintroduced into early MSYS2 versions. Signed-off-by: Johannes Schindelin --- winsup/cygwin/path.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 6ec06fb3e1..5412101f40 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -709,6 +709,12 @@ path_conv::check (const char *src, unsigned opt, need_directory = 1; *--tail = '\0'; } + /* Special case for "/" must set need_directory, without removing + trailing slash */ + else if (tail == path_copy + 1 && isslash (tail[-1])) + { + need_directory = 1; + } path_end = tail; /* Scan path_copy from right to left looking either for a symlink @@ -1251,6 +1257,7 @@ path_conv::check (const char *src, unsigned opt, cfree (wide_path); wide_path = NULL; } + if (need_directory) { size_t n = strlen (this->path); From 0c102ea21bf0ad8ac591e46eddf29b02d3ef2fd3 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 8 Nov 2022 16:24:20 +0100 Subject: [PATCH 14/50] When converting to a Unix path, avoid double trailing slashes When calling `cygpath -u C:/msys64/` in an MSYS2 setup that was installed into `C:/msys64/`, the result should be `/`, not `//`. Let's ensure that we do not append another trailing slash if the converted path already ends in a slash. This fixes https://github.com/msys2/msys2-runtime/issues/112 Signed-off-by: Johannes Schindelin --- winsup/cygwin/mount.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/winsup/cygwin/mount.cc b/winsup/cygwin/mount.cc index eff9803241..bd6ec2a7a1 100644 --- a/winsup/cygwin/mount.cc +++ b/winsup/cygwin/mount.cc @@ -1018,6 +1018,9 @@ mount_info::conv_to_posix_path (const char *src_path, char *posix_path, nextchar = 1; int addslash = nextchar > 0 ? 1 : 0; + /* avoid appending a slash if the result already has a trailing slash */ + if (append_slash && mi.posix_pathlen && mi.posix_path[mi.posix_pathlen-1] == '/') + append_slash = addslash = 0; if ((mi.posix_pathlen + (pathbuflen - mi.native_pathlen) + addslash) >= NT_MAX_PATH) return ENAMETOOLONG; strcpy (posix_path, mi.posix_path); From 8ed6549f805a813ca3f89c950f65899be4fc8510 Mon Sep 17 00:00:00 2001 From: Christoph Reiter Date: Sun, 20 Nov 2022 13:57:36 +0100 Subject: [PATCH 15/50] msys2_path_conv: pass PC_NOFULL to path_conv In theory this doesn't make a difference because posix_to_win32_path() is only called with rooted/absolute paths, but as pointed out in https://github.com/msys2/msys2-runtime/pull/103 PC_NOFULL will preserve the trailing slash of unix paths (for some reason). See "cygpath -m /bin/" (preserved) vs "cygpath -am /bin/" (dropped) One use case where we need to trailing slashes to be preserved is the GCC build system: https://github.com/gcc-mirror/gcc/blob/6d82e0fea5f988e829912a/gcc/Makefile.in#L2314 The Makefile appends a slash to the prefixes and the C code doing relocation will treat the path as a directory if there is a trailing slash. See https://github.com/msys2/MINGW-packages/issues/14173 for details. With this change all our MSYS2 path_conv tests pass again. --- winsup/cygwin/msys2_path_conv.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winsup/cygwin/msys2_path_conv.cc b/winsup/cygwin/msys2_path_conv.cc index c52728759e..d584800c00 100644 --- a/winsup/cygwin/msys2_path_conv.cc +++ b/winsup/cygwin/msys2_path_conv.cc @@ -682,7 +682,7 @@ void posix_to_win32_path(const char* from, const char* to, char** dst, const cha strncpy(one_path, from, to-from); one_path[to-from] = '\0'; - path_conv conv (one_path, 0); + path_conv conv (one_path, PC_NOFULL); if (conv.error) { set_errno(conv.error); From 853cc5411c9c3562e23d4fccae7ef12d70d7a4ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A7=88=EB=88=84=EC=97=98?= Date: Wed, 17 Jun 2015 09:30:41 +0200 Subject: [PATCH 16/50] path-conversion: Introduce ability to switch off conversion. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When calling windows native apps from MSYS2, the runtime tries to convert commandline arguments by a specific set of rules. This idea was inherited from the MSys/MinGW project (which is now seemingly stale, yet must be credited with championing this useful feature, see MinGW wiki https://web.archive.org/web/20201112005258/http://www.mingw.org/wiki/Posix_path_conversion). If the user does not want that behavior on a big scale, e.g. inside a Bash script, with the changes introduced in this commit, the user can now set the the environment variable `MSYS_NO_PATHCONV` when calling native windows commands. This is a feature that has been introduced in Git for Windows via https://github.com/git-for-windows/msys2-runtime/pull/11 and it predates support for the `MSYS2_ENV_CONV_EXCL` and `MSYS2_ARG_CONV_EXCL` environment variables in the MSYS2 runtime; Many users find the simplicity of `MSYS_NO_PATHCONV` appealing. So let's teach MSYS2 proper this simple trick that still allows using the sophisticated `MSYS2_*_CONV_EXCL` facilities but also offers a convenient catch-all "just don't convert anything" knob. Signed-off-by: 마누엘 Signed-off-by: Johannes Schindelin --- winsup/cygwin/msys2_path_conv.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/winsup/cygwin/msys2_path_conv.cc b/winsup/cygwin/msys2_path_conv.cc index d584800c00..4c0cc82cf2 100644 --- a/winsup/cygwin/msys2_path_conv.cc +++ b/winsup/cygwin/msys2_path_conv.cc @@ -341,6 +341,16 @@ path_type find_path_start_and_type(const char** src, int recurse, const char* en if (*it == '\0' || it == end) return NONE; + /* + * Skip path mangling when environment indicates it. + */ + const char *no_pathconv = getenv ("MSYS_NO_PATHCONV"); + + if (no_pathconv) { + *src = end; + return NONE; + } + /* Let's not convert ~/.file to ~C:\msys64\.file */ if (*it == '~') { skip_p2w: From 5d54a247cde553b9558c6fab449591e296c6e563 Mon Sep 17 00:00:00 2001 From: Ray Donnelly Date: Fri, 21 Aug 2015 12:52:09 +0100 Subject: [PATCH 17/50] dcrt0.cc: Untangle allow_glob from winshell Otherwise if globbing is allowed and we get called from a Windows program, build_argv thinks we've been called from a Cygwin program. --- winsup/cygwin/dcrt0.cc | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index 16b624eab5..3536e80730 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -154,12 +154,12 @@ isquote (char c) /* Step over a run of characters delimited by quotes */ static /*__inline*/ char * -quoted (char *cmd, int winshell) +quoted (char *cmd, int winshell, int glob) { char *p; char quote = *cmd; - if (!winshell) + if (!winshell || !glob) { char *p; strcpy (cmd, cmd + 1); @@ -169,8 +169,8 @@ quoted (char *cmd, int winshell) } const char *s = quote == '\'' ? "'" : "\\\""; - /* This must have been run from a Windows shell, so preserve - quotes for globify to play with later. */ + /* This must have been run from a Windows shell and globbing is enabled, + so preserve quotes for globify to play with later. */ while (*cmd && *++cmd) if ((p = strpbrk (cmd, s)) == NULL) { @@ -292,7 +292,7 @@ globify (char *word, char **&argv, int &argc, int &argvlen) /* Build argv, argc from string passed from Windows. */ static void -build_argv (char *cmd, char **&argv, int &argc, int winshell) +build_argv (char *cmd, char **&argv, int &argc, int winshell, int glob) { int argvlen = 0; int nesting = 0; // monitor "nesting" from insert_file @@ -326,7 +326,7 @@ build_argv (char *cmd, char **&argv, int &argc, int winshell) a Cygwin process, or if the word starts with a '@'. In this case, the insert_file function needs an unquoted DOS filename and globbing isn't performed anyway. */ - cmd = quoted (cmd, winshell && argc > 0 && *word != '@'); + cmd = quoted (cmd, winshell && argc > 0 && *word != '@', glob); } if (issep (*cmd)) // End of argument if space break; @@ -352,7 +352,7 @@ build_argv (char *cmd, char **&argv, int &argc, int winshell) } /* Add word to argv file after (optional) wildcard expansion. */ - if (!winshell || !argc || !globify (word, argv, argc, argvlen)) + if (!glob || !argc || !globify (word, argv, argc, argvlen)) { debug_printf ("argv[%d] = '%s'", argc, word); argv[argc++] = word; @@ -907,6 +907,7 @@ dll_crt0_1 (void *) /* Scan the command line and build argv. Expand wildcards if not called from another cygwin process. */ build_argv (line, __argv, __argc, + NOTSTATE (myself, PID_CYGPARENT), NOTSTATE (myself, PID_CYGPARENT) && allow_glob); /* Convert argv[0] to posix rules if it's currently blatantly From d85da3a918acc954b267cd39d0e94bb732f2a102 Mon Sep 17 00:00:00 2001 From: Ray Donnelly Date: Mon, 24 Aug 2015 00:48:06 +0100 Subject: [PATCH 18/50] dcrt0.cc (globify): Don't quote literal strings differently when dos_spec Reverts 25ba8f306f3099caf8397859019e936b90510e8d. I can't figure out what the intention was. I'm sure I'll find out soon enough when everything breaks. This change means that input of: '"C:/test.exe SOME_VAR=\"literal quotes\""' becomes: 'C:/test.exe SOME_VAR="literal quotes"' instead of: 'C:/test.exe SOME_VAR=\literal quotes\' .. which is at least consistent with the result for: '"no_drive_or_colon SOME_VAR=\"literal quotes\""' The old result of course resulted in the quoted string being split into two arguments at the space which is clearly not intended. I *guess* backslashes in dos paths may have been the issue here? If so I don't care since we should not use them, ever, esp. not at the expense of sensible forward-slash-containing input. --- winsup/cygwin/dcrt0.cc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index 3536e80730..81031cae8a 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -237,10 +237,20 @@ globify (char *word, char **&argv, int &argc, int &argvlen) while (*++s && *s != quote) { mbstate_t mbs = { 0 }; + /* This used to be: if (dos_spec || *s != '\\') - /* nothing */; + // nothing else if (s[1] == quote || s[1] == '\\') s++; + With commit message: + dcrt0.cc (globify): Don't use \ quoting when apparently quoting a DOS path + spec, even within a quoted string. + But that breaks the "literal quotes" part of '"C:/test.exe SOME_VAR=\"literal quotes\""' + giving: 'C:/test.exe SOME_VAR=\literal quotes\' (with \'s between each character) + instead of 'C:/test.exe SOME_VAR="literal quotes"' (with \'s between each character) + */ + if (*s == '\\' && (s[1] == quote || s[1] == '\\')) + s++; *p++ = '\\'; size_t cnt = isascii (*s) ? 1 : mbrtowi (NULL, s, MB_CUR_MAX, &mbs); if (cnt <= 1 || cnt == (size_t)-1) From a3e7629f84a2cc2831007ee308c148f60b101fe9 Mon Sep 17 00:00:00 2001 From: Ray Donnelly Date: Fri, 21 Aug 2015 12:18:52 +0100 Subject: [PATCH 19/50] Add debugging for build_argv --- winsup/cygwin/dcrt0.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index 81031cae8a..0a5c817b3c 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -311,6 +311,8 @@ build_argv (char *cmd, char **&argv, int &argc, int winshell, int glob) argvlen = 0; argv = NULL; + debug_printf ("cmd = '%s', winshell = %d, glob = %d", cmd, winshell, glob); + /* Scan command line until there is nothing left. */ while (*cmd) { From ca226ec37bb466a1b15674b0dcb441b08232458f Mon Sep 17 00:00:00 2001 From: Ray Donnelly Date: Sun, 10 Apr 2016 21:47:41 +0100 Subject: [PATCH 20/50] environ.cc: New facility/environment variable MSYS2_ENV_CONV_EXCL Works very much like MSYS2_ARG_CONV_EXCL. In fact it uses the same function, arg_heuristic_with_exclusions (). Also refactors parsing the env. variables to use new function, string_split_delimited (). The env. that is searched through is the merged (POSIX + Windows) one. It remains to be seen if this should be made an option or not. This feature was prompted because the R language (Windows exe) calls bash to run configure.win, which then calls back into R to read its config variables (LOCAL_SOFT) and when this happens, msys2-runtime converts R_ARCH from "/x64" to an absolute Windows path and appends it to another absolute path, R_HOME, forming an invalid path. --- winsup/cygwin/environ.cc | 34 +++++++++++++++++------- winsup/cygwin/local_includes/miscfuncs.h | 2 ++ winsup/cygwin/miscfuncs.cc | 20 ++++++++++++++ winsup/cygwin/path.cc | 1 - winsup/cygwin/spawn.cc | 12 ++------- 5 files changed, 48 insertions(+), 21 deletions(-) diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index 117531367e..a9cce9645a 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -1173,6 +1173,10 @@ build_env (const char * const *envp, PWCHAR &envblock, int &envc, int tl = 0; char **pass_dstp; +#ifdef __MSYS__ + char *msys2_env_conv_excl_env = NULL; + size_t msys2_env_conv_excl_count = 0; +#endif char **pass_env = (char **) alloca (sizeof (char *) * (n + winnum + SPENVS_SIZE + 1)); /* Iterate over input list, generating a new environment list and refreshing @@ -1181,16 +1185,25 @@ build_env (const char * const *envp, PWCHAR &envblock, int &envc, { bool calc_tl = !no_envblock; #ifdef __MSYS__ - /* Don't pass timezone environment to non-msys applications */ - if (!keep_posix && ascii_strncasematch(*srcp, "TZ=", 3)) + if (!keep_posix) { - const char *v = *srcp + 3; - if (*v == ':') - goto next1; - for (; *v; v++) - if (!isalpha(*v) && !isdigit(*v) && - *v != '-' && *v != '+' && *v != ':') - goto next1; + /* Don't pass timezone environment to non-msys applications */ + if (ascii_strncasematch(*srcp, "TZ=", 3)) + { + const char *v = *srcp + 3; + if (*v == ':') + goto next1; + for (; *v; v++) + if (!isalpha(*v) && !isdigit(*v) && + *v != '-' && *v != '+' && *v != ':') + goto next1; + } + else if (ascii_strncasematch(*srcp, "MSYS2_ENV_CONV_EXCL=", 20)) + { + msys2_env_conv_excl_env = (char*)alloca (strlen(&(*srcp)[20])+1); + strcpy (msys2_env_conv_excl_env, &(*srcp)[20]); + msys2_env_conv_excl_count = string_split_delimited (msys2_env_conv_excl_env, ';'); + } } #endif /* Look for entries that require special attention */ @@ -1315,7 +1328,8 @@ build_env (const char * const *envp, PWCHAR &envblock, int &envc, } #ifdef __MSYS__ else if (!keep_posix) { - char *win_arg = arg_heuristic(*srcp); + char *win_arg = arg_heuristic_with_exclusions + (*srcp, msys2_env_conv_excl_env, msys2_env_conv_excl_count); debug_printf("WIN32_PATH is %s", win_arg); p = cstrdup1(win_arg); if (win_arg != *srcp) diff --git a/winsup/cygwin/local_includes/miscfuncs.h b/winsup/cygwin/local_includes/miscfuncs.h index d52debad1a..c4dbe0235b 100644 --- a/winsup/cygwin/local_includes/miscfuncs.h +++ b/winsup/cygwin/local_includes/miscfuncs.h @@ -81,6 +81,8 @@ void backslashify (const char *, char *, bool); void slashify (const char *, char *, bool); #define isslash(c) ((c) == '/') +size_t string_split_delimited (char * string, char delimiter); + extern void transform_chars (PWCHAR, PWCHAR); extern inline void transform_chars (PUNICODE_STRING upath, USHORT start_idx) diff --git a/winsup/cygwin/miscfuncs.cc b/winsup/cygwin/miscfuncs.cc index 4220f62757..5446654389 100644 --- a/winsup/cygwin/miscfuncs.cc +++ b/winsup/cygwin/miscfuncs.cc @@ -311,6 +311,26 @@ NT_readline::gets () } } +/* Searches through string for delimiter replacing each instance with '\0' + and returning the number of such delimited substrings. This function + Will return 0 for the NULL string and at least 1 otherwise. */ + +size_t +string_split_delimited (char * string, char delimiter) +{ + if ( string == NULL ) + return 0; + size_t count = 1; + string = strchr ( string, delimiter ); + while (string) + { + *string = '\0'; + ++count; + string = strchr ( string + 1, delimiter ); + } + return count; +} + /* Signal the thread name to any attached debugger (See "How to: Set a Thread Name in Native Code" diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 5412101f40..1b9050064c 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -4053,7 +4053,6 @@ arg_heuristic_with_exclusions (char const * const arg, char const * exclusions, return arg_result; } - debug_printf("Input value: (%s)", arg); for (size_t excl = 0; excl < exclusions_count; ++excl) { /* Since we've got regex linked we should maybe switch to that, but diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index d7affaac88..5b3cbeb90f 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -293,8 +293,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv, int res = -1; /* Environment variable MSYS2_ARG_CONV_EXCL contains a list - of ';' separated argument prefixes to pass un-modified.. - It isn't applied to env. variables; only spawn arguments. + of ';' separated argument prefixes to pass un-modified. A value of * means don't convert any arguments. */ char* msys2_arg_conv_excl_env = getenv("MSYS2_ARG_CONV_EXCL"); char* msys2_arg_conv_excl = NULL; @@ -303,14 +302,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv, { msys2_arg_conv_excl = (char*)alloca (strlen(msys2_arg_conv_excl_env)+1); strcpy (msys2_arg_conv_excl, msys2_arg_conv_excl_env); - msys2_arg_conv_excl_count = 1; - msys2_arg_conv_excl_env = strchr ( msys2_arg_conv_excl, ';' ); - while (msys2_arg_conv_excl_env) - { - *msys2_arg_conv_excl_env = '\0'; - ++msys2_arg_conv_excl_count; - msys2_arg_conv_excl_env = strchr ( msys2_arg_conv_excl_env + 1, ';' ); - } + msys2_arg_conv_excl_count = string_split_delimited (msys2_arg_conv_excl, ';'); } /* Check if we have been called from exec{lv}p or spawn{lv}p and mask From 89f8cacab1b0a9870859aeeaa438e805438e0509 Mon Sep 17 00:00:00 2001 From: SquallATF Date: Mon, 10 Sep 2018 11:32:18 +0300 Subject: [PATCH 21/50] Fix native symbolic link spawn passing wrong arg0 --- winsup/cygwin/spawn.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index 5b3cbeb90f..b97c6da3ed 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -50,7 +50,7 @@ perhaps_suffix (const char *prog, path_conv& buf, int& err, unsigned opt) err = 0; debug_printf ("prog '%s'", prog); - buf.check (prog, PC_SYM_FOLLOW | PC_NULLEMPTY | PC_POSIX, + buf.check (prog, PC_SYM_FOLLOW | PC_SYM_NOFOLLOW_REP | PC_NULLEMPTY | PC_POSIX, (opt & FE_DLL) ? stat_suffixes : exe_suffixes); if (buf.isdir ()) From a46c7539a1826461434525905688b95334fb1fdf Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 19 May 2020 13:49:37 +0200 Subject: [PATCH 22/50] Introduce the `enable_pcon` value for `MSYS` It is simply the negation of `disable_pcon`, i.e. `MSYS=enable_pcon` is equivalent to `MSYS=nodisable_pcon` (the former is slightly more intuitive than the latter) and likewise `MSYS=noenable_pcon` is equivalent to `MSYS=disable_pcon` (here, the latter is definitely more intuitive than the former). This is needed because we just demoted the pseudo console feature to be opt-in instead of opt-out, and it would be awkward to recommend to users to use "nodisable_pcon"... "nodisable" is not even a verb. Signed-off-by: Johannes Schindelin --- winsup/cygwin/environ.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index a9cce9645a..b9600ef9a8 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -42,6 +42,7 @@ enum settings isfunc, setdword, setbool, + setnegbool, setbit }; @@ -118,6 +119,7 @@ static struct parse_thing } known[] NO_COPY = { {"disable_pcon", {&disable_pcon}, setbool, NULL, {{false}, {true}}}, + {"enable_pcon", {&disable_pcon}, setnegbool, NULL, {{true}, {false}}}, {"error_start", {func: error_start_init}, isfunc, NULL, {{0}, {0}}}, {"export", {&export_settings}, setbool, NULL, {{false}, {true}}}, {"glob", {func: glob_init}, isfunc, NULL, {{0}, {s: "normal"}}}, @@ -244,6 +246,13 @@ parse_options (const char *inbuf) *k->setting.b = !!strtol (eq, NULL, 0); debug_printf ("%s%s", *k->setting.b ? "" : "no", k->name); break; + case setnegbool: + if (!istrue || !eq) + *k->setting.b = k->values[istrue].i; + else + *k->setting.b = !strtol (eq, NULL, 0); + debug_printf ("%s%s", !*k->setting.b ? "" : "no", k->name); + break; case setbit: *k->setting.x &= ~k->values[istrue].i; if (istrue || (eq && strtol (eq, NULL, 0))) From 5f0df244ed792a0aa09e6ff2accb018579ba5f8c Mon Sep 17 00:00:00 2001 From: Christoph Reiter Date: Fri, 5 Jun 2020 20:09:11 +0200 Subject: [PATCH 23/50] popen: call /usr/bin/sh instead of /bin/sh We mount /usr/bin to /bin, but in a chroot this is broken and we have no /bin, so try to use the real path. chroot is used by pacman to run install scripts when called with --root and this broke programs in install scripts calling popen() (install-info from texinfo for example) There are more paths hardcoded to /bin in cygwin which might also be broken in this scenario, so this maybe should be extended to all of them. --- winsup/cygwin/syscalls.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 808e661792..7e8f356854 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -4423,7 +4423,7 @@ popen (const char *command, const char *in_type) fcntl (stdchild, F_SETFD, stdchild_state | FD_CLOEXEC); /* Start a shell process to run the given command without forking. */ - pid_t pid = ch_spawn.worker ("/bin/sh", argv, environ, _P_NOWAIT, + pid_t pid = ch_spawn.worker ("/usr/bin/sh", argv, environ, _P_NOWAIT, __std[0], __std[1]); /* Reinstate the close-on-exec state */ From c1a941081dfbdc062897dbc898d6caf6d63dbf0a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 17 Mar 2021 17:41:02 +0100 Subject: [PATCH 24/50] Disable the 'cygwin' GitHub workflow It does not work at all. For example, `rpm -E %fedora` says that there should be version 33 of rpmsphere at https://github.com/rpmsphere/noarch/tree/master/r, but there is only version 32. Another thing that is broken: Cygwin now assumes that a recent mingw-w64-headers version is available, but Fedora apparently only offers v7.0.0, which is definitely too old to accommodate for the expectation of https://github.com/cygwin/cygwin/commit/c1f7c4d1b6d7. Signed-off-by: Johannes Schindelin --- .github/workflows/cygwin.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/cygwin.yml b/.github/workflows/cygwin.yml index 803462a017..5caa3d11b8 100644 --- a/.github/workflows/cygwin.yml +++ b/.github/workflows/cygwin.yml @@ -1,12 +1,6 @@ name: cygwin -on: - push: - # since master is a symbolic reference to main, don't run for both - branches-ignore: - - 'master' - tags: - - '*' +on: workflow_dispatch jobs: fedora-build: From 93544235a4449a463f2a28115c0ea57070226600 Mon Sep 17 00:00:00 2001 From: Christoph Reiter Date: Sun, 9 Aug 2020 14:02:51 +0200 Subject: [PATCH 25/50] CI: add a GHA for doing a basic build test Build with --disable-dependency-tracking because we only build once and this saves 3-4 minutes in CI. --- .github/workflows/build.yaml | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/workflows/build.yaml diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000000..ae6b2c8950 --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,36 @@ +name: build + +on: [push, pull_request] + +jobs: + build: + runs-on: windows-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: setup-msys2 + uses: msys2/setup-msys2@v2 + with: + msystem: MSYS + update: true + install: msys2-devel base-devel autotools cocom diffutils gcc gettext-devel libiconv-devel make mingw-w64-cross-crt mingw-w64-cross-gcc mingw-w64-cross-zlib perl zlib-devel xmlto docbook-xsl + + - name: Build + shell: msys2 {0} + run: | + (cd winsup && ./autogen.sh) + ./configure --disable-dependency-tracking --with-msys2-runtime-commit="$GITHUB_SHA" + make -j8 + + - name: Install + shell: msys2 {0} + run: | + make DESTDIR="$(pwd)"/_dest install + + - name: Upload + uses: actions/upload-artifact@v4 + with: + name: install + path: _dest/ From 3edbe0194634bbb114024e4eb33ef61170c2fa6f Mon Sep 17 00:00:00 2001 From: Christoph Reiter Date: Fri, 10 Nov 2023 15:31:10 +0100 Subject: [PATCH 26/50] CI: fix the build with gcc 13 --- .github/workflows/build.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index ae6b2c8950..4b3fa42ec9 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -20,6 +20,9 @@ jobs: - name: Build shell: msys2 {0} run: | + # XXX: cygwin still uses gcc v11 so we get new warnings with v13, + # resulting in errors due to -Werror. Disable them for now. + export CXXFLAGS="-Wno-error=stringop-truncation -Wno-error=array-bounds -Wno-error=overloaded-virtual -Wno-narrowing -Wno-use-after-free" (cd winsup && ./autogen.sh) ./configure --disable-dependency-tracking --with-msys2-runtime-commit="$GITHUB_SHA" make -j8 From d49861d9ab610b101176dcd430643c049ace9bcf Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 22 Nov 2019 11:20:22 +0100 Subject: [PATCH 27/50] Set up a GitHub Action to keep in sync with Cygwin This will help us by automating an otherwise tedious task. Signed-off-by: Johannes Schindelin --- .github/workflows/sync-with-cygwin.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/sync-with-cygwin.yml diff --git a/.github/workflows/sync-with-cygwin.yml b/.github/workflows/sync-with-cygwin.yml new file mode 100644 index 0000000000..57bd30e5da --- /dev/null +++ b/.github/workflows/sync-with-cygwin.yml @@ -0,0 +1,24 @@ +name: sync-with-cygwin + +# File: .github/workflows/repo-sync.yml + +on: + workflow_dispatch: + schedule: + - cron: "42 * * * *" +jobs: + repo-sync: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Fetch Cygwin's latest master and tags + run: | + git init --bare + # Potentially use git://sourceware.org/git/newlib-cygwin.git directly, but GitHub seems more reliable + git fetch https://github.com/cygwin/cygwin master:refs/heads/cygwin/master 'refs/tags/*:refs/tags/*' + - name: Push to our fork + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git push https://$GITHUB_ACTOR:$GITHUB_TOKEN@github.com/$GITHUB_REPOSITORY refs/heads/cygwin/master 'refs/tags/*:refs/tags/*' From 6d0c6370ed5c45de01fb6041813e00005d1a2c11 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 12 Aug 2020 12:22:38 +0200 Subject: [PATCH 28/50] Expose full command-lines to other Win32 processes by default In the Cygwin project, it was decided that the command-line of Cygwin processes, as shown in the output of `wmic process list`, would suffer from being truncated to 32k (and is transmitted to the child process via a different mechanism, anyway), and therefore only the absolute path of the executable is shown by default. Users who would like to see the full command-line (even if it is truncated) are expected to set `CYGWIN=wincmdln` (or, in MSYS2's case, `MSYS=wincmdln`). Seeing as MSYS2 tries to integrate much better with the surrounding Win32 ecosystem than Cygwin, it makes sense to turn this on by default. Users who wish to suppress it can still set `MSYS=nowincmdln`. Signed-off-by: Johannes Schindelin --- winsup/cygwin/globals.cc | 2 +- winsup/doc/cygwinenv.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/winsup/cygwin/globals.cc b/winsup/cygwin/globals.cc index 0c21fa624e..b3b77de405 100644 --- a/winsup/cygwin/globals.cc +++ b/winsup/cygwin/globals.cc @@ -70,7 +70,7 @@ bool allow_glob = true; bool ignore_case_with_glob; bool pipe_byte = true; /* Default to byte mode so that C# programs work. */ bool reset_com; -bool wincmdln; +bool wincmdln = true; winsym_t allow_winsymlinks = WSYM_deepcopy; bool disable_pcon; bool winjitdebug = false; diff --git a/winsup/doc/cygwinenv.xml b/winsup/doc/cygwinenv.xml index fcb6e22485..4ea63b407a 100644 --- a/winsup/doc/cygwinenv.xml +++ b/winsup/doc/cygwinenv.xml @@ -90,7 +90,7 @@ time and when handles are inherited. Defaults to set. (no)wincmdln - if set, the windows complete command line (truncated to ~32K) will be passed on any processes that it creates -in addition to the normal UNIX argv list. Defaults to not set. +in addition to the normal UNIX argv list. Defaults to set. From 0e5a7de4fcc8c207b1dd2180c7d16a2888f25a8c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 16 Apr 2018 14:59:39 +0200 Subject: [PATCH 29/50] Add a helper to obtain a function's address in kernel32.dll In particular, we are interested in the address of the CtrlRoutine and the ExitProcess functions. Since kernel32.dll is loaded first thing, the addresses will be the same for all processes (matching the CPU architecture, of course). This will help us with emulating SIGINT properly (by not sending signals to *all* processes attached to the same Console, as GenerateConsoleCtrlEvent() would do). Co-authored-by: Naveen M K Signed-off-by: Johannes Schindelin --- winsup/configure.ac | 5 + winsup/utils/mingw/Makefile.am | 15 ++ winsup/utils/mingw/getprocaddr.c | 310 +++++++++++++++++++++++++++++++ 3 files changed, 330 insertions(+) create mode 100644 winsup/utils/mingw/getprocaddr.c diff --git a/winsup/configure.ac b/winsup/configure.ac index 9b9b59dbcb..b9e3977fcf 100644 --- a/winsup/configure.ac +++ b/winsup/configure.ac @@ -106,6 +106,11 @@ if test "x$with_cross_bootstrap" != "xyes"; then test -n "$MINGW_CXX" || AC_MSG_ERROR([no acceptable MinGW g++ found in \$PATH]) AC_CHECK_PROGS(MINGW_CC, ${target_cpu}-w64-mingw32-gcc) test -n "$MINGW_CC" || AC_MSG_ERROR([no acceptable MinGW gcc found in \$PATH]) + + AC_CHECK_PROGS(MINGW32_CC, i686-w64-mingw32-gcc) + test -n "$MINGW32_CC" || AC_MSG_ERROR([no acceptable mingw32 gcc found in \$PATH]) + AC_CHECK_PROGS(MINGW64_CC, x86_64-w64-mingw32-gcc) + test -n "$MINGW64_CC" || AC_MSG_ERROR([no acceptable mingw64 gcc found in \$PATH]) fi AM_CONDITIONAL(CROSS_BOOTSTRAP, [test "x$with_cross_bootstrap" != "xyes"]) diff --git a/winsup/utils/mingw/Makefile.am b/winsup/utils/mingw/Makefile.am index 7f7317ae15..07b9f928d4 100644 --- a/winsup/utils/mingw/Makefile.am +++ b/winsup/utils/mingw/Makefile.am @@ -26,6 +26,21 @@ bin_PROGRAMS = \ ldh \ strace +libexec_PROGRAMS = getprocaddr32 getprocaddr64 + +# Must *not* use -O2 here, as it screws up the stack backtrace +getprocaddr32.o: %32.o: %.c + $(MINGW32_CC) -c -o $@ $< + +getprocaddr32.exe: %.exe: %.o + $(MINGW32_CC) -o $@ $^ -static -ldbghelp + +getprocaddr64.o: %64.o: %.c + $(MINGW64_CC) -c -o $@ $< + +getprocaddr64.exe: %.exe: %.o + $(MINGW64_CC) -o $@ $^ -static -ldbghelp + cygcheck_SOURCES = \ bloda.cc \ cygcheck.cc \ diff --git a/winsup/utils/mingw/getprocaddr.c b/winsup/utils/mingw/getprocaddr.c new file mode 100644 index 0000000000..25814c7bdd --- /dev/null +++ b/winsup/utils/mingw/getprocaddr.c @@ -0,0 +1,310 @@ +/* getprocaddr.c + +This program is a helper for getting the pointers for the +functions in kernel32 module, and optionally injects a remote +thread that runs those functions given a pid and exit code. + +We use dbghelp.dll to get the pointer to kernel32!CtrlRoutine +because it isn't exported. For that, we try to generate console +event (Ctrl+Break) ourselves, to find the pointer, and it is +printed if asked to, or a remote thread is injected to run the +given function. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include + +/* Include dbghelp.h after windows.h */ +#include + +static DWORD pid; +static uintptr_t exit_code; +static HANDLE CtrlEvent; + +static int +inject_remote_thread_into_process (HANDLE process, + LPTHREAD_START_ROUTINE address, + uintptr_t exit_code, + DWORD *thread_return) +{ + int res = -1; + + if (!address) + return res; + DWORD thread_id; + HANDLE thread = CreateRemoteThread (process, NULL, 1024 * 1024, address, + (PVOID)exit_code, 0, &thread_id); + if (thread) + { + /* + * Wait up to 10 seconds (arbitrary constant) for the thread to finish; + * Maybe we should wait forever? I have seen Cmd does so, but well... + */ + if (WaitForSingleObject (thread, 10000) == WAIT_OBJECT_0) + res = 0; + /* + According to the docs at MSDN for GetExitCodeThread, it will + get the return value from the function, here CtrlRoutine. So, this + checks if the Ctrl Event is handled correctly by the process. + + By some testing I could see CtrlRoutine returns 0 in case where + CtrlEvent set by SetConsoleCtrlHandler is handled correctly, in all + other cases it returns something non-zero(not sure what it that). + */ + if (thread_return != NULL) + GetExitCodeThread (thread, thread_return); + + CloseHandle (thread); + } + + return res; +} + +/* Here, we send a CtrlEvent to the current process for the + * sole purpose of capturing the address of the CtrlRoutine + * function, by looking the stack trace. + * + * This hack is needed because we cannot use GetProcAddress() + * as we do for ExitProcess(), because CtrlRoutine is not + * exported (although the .pdb files ensure that we can see + * it in a debugger). + */ +static WINAPI BOOL +ctrl_handler (DWORD ctrl_type) +{ + unsigned short count; + void *address; + HANDLE process; + PSYMBOL_INFOW info; + DWORD64 displacement; + DWORD thread_return = 0; + + count = CaptureStackBackTrace (1l /* skip this function */, + 1l /* return only one trace item */, &address, + NULL); + if (count != 1) + { + fprintf (stderr, "Could not capture backtrace\n"); + return FALSE; + } + + process = GetCurrentProcess (); + if (!SymInitialize (process, NULL, TRUE)) + { + fprintf (stderr, "Could not initialize symbols\n"); + return FALSE; + } + + info = (PSYMBOL_INFOW)malloc (sizeof (*info) + + MAX_SYM_NAME * sizeof (wchar_t)); + if (!info) + { + fprintf (stderr, "Could not allocate symbol info structure\n"); + return FALSE; + } + info->SizeOfStruct = sizeof (*info); + info->MaxNameLen = MAX_SYM_NAME; + + if (!SymFromAddrW (process, (DWORD64) (intptr_t)address, &displacement, + info)) + { + fprintf (stderr, "Could not get symbol info\n"); + SymCleanup (process); + return FALSE; + } + + if (pid == 0) + { + printf ("%p\n", (void *)(intptr_t)info->Address); + } + else + { + LPTHREAD_START_ROUTINE address = + (LPTHREAD_START_ROUTINE) (intptr_t)info->Address; + HANDLE h = OpenProcess (PROCESS_CREATE_THREAD | + PROCESS_QUERY_INFORMATION | + PROCESS_VM_OPERATION | + PROCESS_VM_WRITE | + PROCESS_VM_READ, FALSE, pid); + if (h == NULL) + { + fprintf (stderr, "OpenProcess failed: %ld\n", GetLastError ()); + return 1; + } + /* Inject the remote thread only when asked to */ + if (inject_remote_thread_into_process (h, address, exit_code, + &thread_return) < 0) + { + fprintf (stderr, + "Error while injecting remote thread for pid(%lu)\n", pid); + exit (1); /*We should exit immediately or else there will a 10s hang + waiting for the event to happen.*/ + } + if (thread_return) + fprintf (stderr, + "Injected remote thread for pid(%lu) returned %lu\n", pid, + thread_return); + } + SymCleanup (process); + if (!SetEvent (CtrlEvent)) + { + fprintf (stderr, "SetEvent failed (%ld)\n", GetLastError ()); + return 1; + } + exit (thread_return != 0); +} + +/* The easy route for finding the address of CtrlRoutine + * would be use GetProcAddress() but this isn't viable + * here because that symbol isn't exported. + */ +static int +find_ctrl_routine_the_hard_way () +{ + /* + * Avoid terminating all processes attached to the current console; + * This would happen if we used the same console as the caller, though, + * because we are sending a CtrlEvent on purpose (which _is_ sent to + * all processes connected to the same console, and the other processes + * are most likely unprepared for that CTRL_BREAK_EVENT and would be + * terminated as a consequence, _including the caller_). + * + * In case we get only one result from GetConsoleProcessList(), we don't + * need to create and allocate a new console, and it could avoid a console + * window popping up. + */ + DWORD proc_lists; + if (GetConsoleProcessList (&proc_lists, 5) > 1) + { + if (!FreeConsole () && GetLastError () != ERROR_INVALID_PARAMETER) + { + fprintf (stderr, "Could not detach from current Console: %ld\n", + GetLastError ()); + return 1; + } + if (!AllocConsole ()) + { + fprintf (stderr, "Could not allocate a new Console\n"); + return 1; + } + } + + CtrlEvent = CreateEvent (NULL, // default security attributes + TRUE, // manual-reset event + FALSE, // initial state is nonsignaled + NULL // object name + ); + + if (CtrlEvent == NULL) + { + fprintf (stderr, "CreateEvent failed (%ld)\n", GetLastError ()); + return 1; + } + + + if (!SetConsoleCtrlHandler (ctrl_handler, TRUE)) + { + fprintf (stderr, "Could not register Ctrl handler\n"); + return 1; + } + + if (!GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, 0)) + { + fprintf (stderr, "Could not simulate Ctrl+Break\n"); + return 1; + } + + if (WaitForSingleObject (CtrlEvent, 10000 /* 10 seconds*/) != WAIT_OBJECT_0) + { + fprintf (stderr, "WaitForSingleObject failed (%ld)\n", GetLastError ()); + return 1; + } + return 0; +} + +static void * +get_proc_addr (const char * module_name, const char * function_name) +{ + HMODULE module = GetModuleHandle (module_name); + if (!module) + return NULL; + return (void *)GetProcAddress (module, function_name); +} + +int +main (int argc, char **argv) +{ + char *end; + void *address; + BOOL is_ctrl_routine; + DWORD thread_return = 0; + + if (argc == 4) + { + exit_code = atoi (argv[2]); + pid = strtoul (argv[3], NULL, 0); + } + else if (argc == 2) + { + pid = 0; + } + else + { + fprintf (stderr, "Need a function name, exit code and pid\n" + "Or needs a function name.\n"); + return 1; + } + + is_ctrl_routine = strcmp (argv[1], "CtrlRoutine") == 0; + address = get_proc_addr ("kernel32", argv[1]); + if (is_ctrl_routine && !address) + { + /* CtrlRoutine is undocumented, and has been seen in both + * kernel32 and kernelbase + */ + address = get_proc_addr ("kernelbase", argv[1]); + if (!address) + return find_ctrl_routine_the_hard_way (); + } + + if (!address) + { + fprintf (stderr, "Could not get proc address\n"); + return 1; + } + + if (pid == 0) + { + printf ("%p\n", address); + fflush (stdout); + return 0; + } + HANDLE h = OpenProcess (PROCESS_CREATE_THREAD | + PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | + PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, pid); + if (h == NULL) + { + fprintf (stderr, "OpenProcess failed: %ld\n", GetLastError ()); + return 1; + } + /* Inject the remote thread */ + if (inject_remote_thread_into_process (h, (LPTHREAD_START_ROUTINE)address, + exit_code, &thread_return) < 0) + { + fprintf (stderr, "Could not inject thread into process %lu\n", pid); + return 1; + } + + if (is_ctrl_routine && thread_return) + { + fprintf (stderr, + "Injected remote thread for pid %lu returned %lu\n", pid, + thread_return); + return 1; + } + + return 0; +} From 98632e154dbb564454ffbe97f223ce9ab21e876d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 20 Mar 2015 09:56:28 +0000 Subject: [PATCH 30/50] Emulate GenerateConsoleCtrlEvent() upon Ctrl+C This patch is heavily inspired by the Git for Windows' strategy in handling Ctrl+C. When a process is terminated via TerminateProcess(), it has no chance to do anything in the way of cleaning up. This is particularly noticeable when a lengthy Git for Windows process tries to update Git's index file and leaves behind an index.lock file. Git's idea is to remove the stale index.lock file in that case, using the signal and atexit handlers available in Linux. But those signal handlers never run. Note: this is not an issue for MSYS2 processes because MSYS2 emulates Unix' signal system accurately, both for the process sending the kill signal and the process receiving it. Win32 processes do not have such a signal handler, though, instead MSYS2 shuts them down via `TerminateProcess()`. For a while, Git for Windows tried to use a gentler method, described in the Dr Dobb's article "A Safer Alternative to TerminateProcess()" by Andrew Tucker (July 1, 1999), http://www.drdobbs.com/a-safer-alternative-to-terminateprocess/184416547 Essentially, we injected a new thread into the running process that does nothing else than running the ExitProcess() function. However, this was still not in line with the way CMD handles Ctrl+C: it gives processes a chance to do something upon Ctrl+C by calling SetConsoleCtrlHandler(), and ExitProcess() simply never calls that handler. So for a while we tried to handle SIGINT/SIGTERM by attaching to the console of the command to interrupt, and generating the very same event as CMD does via GenerateConsoleCtrlEvent(). This method *still* was not correct, though, as it would interrupt *every* process attached to that Console, not just the process (and its children) that we wanted to signal. A symptom was that hitting Ctrl+C while `git log` was shown in the pager would interrupt *the pager*. The method we settled on is to emulate what GenerateConsoleCtrlEvent() does, but on a process by process basis: inject a remote thread and call the (private) function kernel32!CtrlRoutine. To obtain said function's address, we use the dbghelp API to generate a stack trace from a handler configured via SetConsoleCtrlHandler() and triggered via GenerateConsoleCtrlEvent(). To avoid killing each and all processes attached to the same Console as the MSYS2 runtime, we modify the cygwin-console-helper to optionally print the address of kernel32!CtrlRoutine to stdout, and then spawn it with a new Console. Note that this also opens the door to handling 32-bit process from a 64-bit MSYS2 runtime and vice versa, by letting the MSYS2 runtime look for the cygwin-console-helper.exe of the "other architecture" in a specific place (we choose /usr/libexec/, as it seems to be the convention for helper .exe files that are not intended for public consumption). The 32-bit helper implicitly links to libgcc_s_dw2.dll and libwinpthread-1.dll, so to avoid cluttering /usr/libexec/, we look for the helped of the "other" architecture in the corresponding mingw32/ or mingw64/ subdirectory. Among other bugs, this strategy to handle Ctrl+C fixes the MSYS2 side of the bug where interrupting `git clone https://...` would send the spawned-off `git remote-https` process into the background instead of interrupting it, i.e. the clone would continue and its progress would be reported mercilessly to the console window without the user being able to do anything about it (short of firing up the task manager and killing the appropriate task manually). Note that this special-handling is only necessary when *MSYS2* handles the Ctrl+C event, e.g. when interrupting a process started from within MinTTY or any other non-cmd-based terminal emulator. If the process was started from within `cmd.exe`'s terminal window, child processes are already killed appropriately upon Ctrl+C, by `cmd.exe` itself. Also, we can't trust the processes to end it's subprocesses upon receiving Ctrl+C. For example, `pip.exe` from `python-pip` doesn't kill the python it lauches (it tries to but fails), and I noticed that in cmd it kills python also correctly, which mean we should kill all the process using `exit_process_tree`. Co-authored-by: Naveen M K Signed-off-by: Johannes Schindelin --- winsup/cygwin/exceptions.cc | 24 +- winsup/cygwin/include/cygwin/exit_process.h | 364 ++++++++++++++++++++ 2 files changed, 384 insertions(+), 4 deletions(-) create mode 100644 winsup/cygwin/include/cygwin/exit_process.h diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index c734a4df43..1cce7c8498 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -29,6 +29,7 @@ details. */ #include "exception.h" #include "posix_timer.h" #include "gcc_seh.h" +#include "cygwin/exit_process.h" /* Define macros for CPU-agnostic register access. The _CX_foo macros are for access into CONTEXT, the _MC_foo ones for access into @@ -1595,10 +1596,25 @@ sigpacket::process () dosig: if (have_execed) { - sigproc_printf ("terminating captive process"); - if (::cygheap->ctty) - ::cygheap->ctty->cleanup_before_exit (); - TerminateProcess (ch_spawn, sigExeced = si.si_signo); + switch (si.si_signo) + { + case SIGUSR1: + case SIGUSR2: + case SIGCONT: + case SIGSTOP: + case SIGTSTP: + case SIGTTIN: + case SIGTTOU: + system_printf ("Suppressing signal %d to win32 process (pid %u)", + (int)si.si_signo, (unsigned int)GetProcessId(ch_spawn)); + goto done; + default: + sigproc_printf ("terminating captive process"); + if (::cygheap->ctty) + ::cygheap->ctty->cleanup_before_exit (); + rc = exit_process_tree (ch_spawn, 128 + (sigExeced = si.si_signo)); + goto done; + } } /* Dispatch to the appropriate function. */ sigproc_printf ("signal %d, signal handler %p", si.si_signo, handler); diff --git a/winsup/cygwin/include/cygwin/exit_process.h b/winsup/cygwin/include/cygwin/exit_process.h new file mode 100644 index 0000000000..0486a0c74a --- /dev/null +++ b/winsup/cygwin/include/cygwin/exit_process.h @@ -0,0 +1,364 @@ +#ifndef EXIT_PROCESS_H +#define EXIT_PROCESS_H + +/* + * This file contains functions to terminate a Win32 process, as gently as + * possible. + * + * If appropriate, we will attempt to emulate a console Ctrl event for the + * process. Otherwise we will fall back to terminating the process. + * + * As we do not want to export this function in the MSYS2 runtime, these + * functions are marked as file-local. + * + * The idea is to inject a thread into the given process that runs either + * kernel32!CtrlRoutine() (i.e. the work horse of GenerateConsoleCtrlEvent()) + * for SIGINT (Ctrl+C) and SIGQUIT (Ctrl+Break), or ExitProcess() for SIGTERM. + * This is handled through the console helpers. + * + * For SIGKILL, we run TerminateProcess() without injecting anything, and this + * is also the fall-back when the previous methods are unavailable. + * + * Note: as kernel32.dll is loaded before any process, the other process and + * this process will have ExitProcess() at the same address. The same holds + * true for kernel32!CtrlRoutine(), of course, but it is an internal API + * function, so we cannot look it up directly. Instead, we launch + * getprocaddr.exe to find out and inject the remote thread. + * + * This function expects the process handle to have the access rights for + * CreateRemoteThread(): PROCESS_CREATE_THREAD, PROCESS_QUERY_INFORMATION, + * PROCESS_VM_OPERATION, PROCESS_VM_WRITE, and PROCESS_VM_READ. + * + * The idea for the injected remote thread comes from the Dr Dobb's article "A + * Safer Alternative to TerminateProcess()" by Andrew Tucker (July 1, 1999), + * http://www.drdobbs.com/a-safer-alternative-to-terminateprocess/184416547. + * + * The idea to use kernel32!CtrlRoutine for the other signals comes from + * SendSignal (https://github.com/AutoSQA/SendSignal/ and + * http://stanislavs.org/stopping-command-line-applications-programatically-with-ctrl-c-events-from-net/). + */ + +#include +#include + +#ifndef __INSIDE_CYGWIN__ +/* To help debugging via kill.exe */ +#define small_printf(...) fprintf (stderr, __VA_ARGS__) +#endif + +static BOOL get_wow (HANDLE process, BOOL &is_wow, USHORT &process_arch); +static int exit_process_tree (HANDLE main_process, int exit_code); + +static BOOL +kill_via_console_helper (HANDLE process, wchar_t *function_name, int exit_code, + DWORD pid) +{ + BOOL is_wow; + USHORT process_arch; + if (!get_wow (process, is_wow, process_arch)) + { + return FALSE; + } + + const char *name; + switch (process_arch) + { + case IMAGE_FILE_MACHINE_I386: + name = "/usr/libexec/getprocaddr32.exe"; + break; + case IMAGE_FILE_MACHINE_AMD64: + name = "/usr/libexec/getprocaddr64.exe"; + break; + /* TODO: provide exes for these */ + case IMAGE_FILE_MACHINE_ARMNT: + name = "/usr/libexec/getprocaddrarm32.exe"; + break; + case IMAGE_FILE_MACHINE_ARM64: + name = "/usr/libexec/getprocaddrarm64.exe"; + break; + default: + return FALSE; /* what?!? */ + } + wchar_t wbuf[PATH_MAX]; + + if (cygwin_conv_path (CCP_POSIX_TO_WIN_W, name, wbuf, PATH_MAX) + || GetFileAttributesW (wbuf) == INVALID_FILE_ATTRIBUTES) + return FALSE; + + STARTUPINFOW si = {}; + PROCESS_INFORMATION pi; + size_t len = wcslen (wbuf) + 1 /* space */ + wcslen (function_name) + + 1 /* space */ + 3 /* exit code */ + 1 /* space */ + + 10 /* process ID, i.e. DWORD */ + 1 /* NUL */; + WCHAR cmd[len + 1]; + WCHAR title[] = L"cygwin-console-helper"; + DWORD process_exit; + + swprintf (cmd, len + 1, L"%S %S %d %u", wbuf, function_name, exit_code, + pid); + + si.cb = sizeof (si); + si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; + si.wShowWindow = SW_HIDE; + si.lpTitle = title; + si.hStdInput = si.hStdError = si.hStdOutput = INVALID_HANDLE_VALUE; + + /* Create a new hidden process. */ + if (!CreateProcessW (NULL, cmd, NULL, NULL, TRUE, + CREATE_NO_WINDOW | CREATE_NEW_PROCESS_GROUP, NULL, NULL, + &si, &pi)) + { + return FALSE; + } + else + { + /* Wait for the process to complete for 10 seconds */ + WaitForSingleObject (pi.hProcess, 10000); + } + + if (!GetExitCodeProcess (pi.hProcess, &process_exit)) + process_exit = -1; + + CloseHandle (pi.hThread); + CloseHandle (pi.hProcess); + + return process_exit == 0 ? TRUE : FALSE; +} + +static int current_is_wow = -1; +static int is_32_bit_os = -1; + +typedef BOOL (WINAPI * IsWow64Process2_t) (HANDLE, USHORT *, USHORT *); +static bool wow64process2initialized = false; +static IsWow64Process2_t pIsWow64Process2 /* = NULL */; + +typedef BOOL (WINAPI * GetProcessInformation_t) (HANDLE, + PROCESS_INFORMATION_CLASS, + LPVOID, DWORD); +static bool getprocessinfoinitialized = false; +static GetProcessInformation_t pGetProcessInformation /* = NULL */; + +static BOOL +get_wow (HANDLE process, BOOL &is_wow, USHORT &process_arch) +{ + USHORT native_arch = IMAGE_FILE_MACHINE_UNKNOWN; + if (!wow64process2initialized) + { + pIsWow64Process2 = (IsWow64Process2_t) + GetProcAddress (GetModuleHandle ("KERNEL32"), + "IsWow64Process2"); + MemoryBarrier (); + wow64process2initialized = true; + } + if (!pIsWow64Process2) + { + if (is_32_bit_os == -1) + { + SYSTEM_INFO info; + + GetNativeSystemInfo (&info); + if (info.wProcessorArchitecture == 0) + is_32_bit_os = 1; + else if (info.wProcessorArchitecture == 9) + is_32_bit_os = 0; + else + is_32_bit_os = -2; + } + + if (current_is_wow == -1 + && !IsWow64Process (GetCurrentProcess (), ¤t_is_wow)) + current_is_wow = -2; + + if (is_32_bit_os == -2 || current_is_wow == -2) + return FALSE; + + if (!IsWow64Process (process, &is_wow)) + return FALSE; + + process_arch = is_32_bit_os || is_wow ? IMAGE_FILE_MACHINE_I386 : + IMAGE_FILE_MACHINE_AMD64; + return TRUE; + } + + if (!pIsWow64Process2 (process, &process_arch, &native_arch)) + return FALSE; + + /* The value will be IMAGE_FILE_MACHINE_UNKNOWN if the target process + * is not a WOW64 process + */ + if (process_arch == IMAGE_FILE_MACHINE_UNKNOWN) + { + struct /* _PROCESS_MACHINE_INFORMATION */ + { + /* 0x0000 */ USHORT ProcessMachine; + /* 0x0002 */ USHORT Res0; + /* 0x0004 */ DWORD MachineAttributes; + } /* size: 0x0008 */ process_machine_info; + + is_wow = FALSE; + /* However, x86_64 on ARM64 claims not to be WOW64, so we have to + * dig harder... */ + if (!getprocessinfoinitialized) + { + pGetProcessInformation = (GetProcessInformation_t) + GetProcAddress (GetModuleHandle ("KERNEL32"), + "GetProcessInformation"); + MemoryBarrier (); + getprocessinfoinitialized = true; + } + /*#define ProcessMachineTypeInfo 9*/ + if (pGetProcessInformation && + pGetProcessInformation (process, (PROCESS_INFORMATION_CLASS)9, + &process_machine_info, sizeof (process_machine_info))) + process_arch = process_machine_info.ProcessMachine; + else + process_arch = native_arch; + } + else + { + is_wow = TRUE; + } + return TRUE; +} + +/** + * Terminates the process corresponding to the process ID + * + * This way of terminating the processes is not gentle: the process gets + * no chance of cleaning up after itself (closing file handles, removing + * .lock files, terminating spawned processes (if any), etc). + */ +static int +exit_process (HANDLE process, int exit_code) +{ + LPTHREAD_START_ROUTINE address = NULL; + DWORD pid = GetProcessId (process), code; + int signo = exit_code & 0x7f; + switch (signo) + { + case SIGINT: + case SIGQUIT: + /* We are not going to kill them but simply say that Ctrl+C + is pressed. If the processes want they can exit or else + just wait.*/ + if (kill_via_console_helper ( + process, L"CtrlRoutine", + signo == SIGINT ? CTRL_C_EVENT : CTRL_BREAK_EVENT, pid)) + return 0; + /* fall-through */ + case SIGTERM: + if (kill_via_console_helper (process, L"ExitProcess", exit_code, pid)) + return 0; + break; + default: + break; + } + + return int (TerminateProcess (process, exit_code)); +} + +#include +#include + +/** + * Terminates the process corresponding to the process ID and all of its + * directly and indirectly spawned subprocesses using the + * TerminateProcess() function. + */ +static int +exit_process_tree (HANDLE main_process, int exit_code) +{ + HANDLE snapshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); + PROCESSENTRY32 entry; + DWORD pids[16384]; + int max_len = sizeof (pids) / sizeof (*pids), i, len, ret = 0; + DWORD pid = GetProcessId (main_process); + int signo = exit_code & 0x7f; + + pids[0] = pid; + len = 1; + + /* + * Even if Process32First()/Process32Next() seem to traverse the + * processes in topological order (i.e. parent processes before + * child processes), there is nothing in the Win32 API documentation + * suggesting that this is guaranteed. + * + * Therefore, run through them at least twice and stop when no more + * process IDs were added to the list. + */ + for (;;) + { + memset (&entry, 0, sizeof (entry)); + entry.dwSize = sizeof (entry); + + if (!Process32First (snapshot, &entry)) + break; + + int orig_len = len; + do + { + /** + * Look for the parent process ID in the list of pids to kill, and if + * found, add it to the list. + */ + for (i = len - 1; i >= 0; i--) + { + if (pids[i] == entry.th32ProcessID) + break; + if (pids[i] != entry.th32ParentProcessID) + continue; + + /* We found a process to kill; is it an MSYS2 process? */ + pid_t cyg_pid = cygwin_winpid_to_pid (entry.th32ProcessID); + if (cyg_pid > -1) + { + if (cyg_pid == getpgid (cyg_pid)) + kill (cyg_pid, signo); + break; + } + pids[len++] = entry.th32ProcessID; + break; + } + } + while (len < max_len && Process32Next (snapshot, &entry)); + + if (orig_len == len || len >= max_len) + break; + } + + CloseHandle (snapshot); + + for (i = len - 1; i >= 0; i--) + { + HANDLE process; + + if (!i) + process = main_process; + else + { + process = OpenProcess ( + PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION + | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, + FALSE, pids[i]); + if (!process) + process = OpenProcess ( + PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_TERMINATE, + FALSE, pids[i]); + } + DWORD code; + + if (process + && (!GetExitCodeProcess (process, &code) || code == STILL_ACTIVE)) + { + if (!exit_process (process, exit_code)) + ret = -1; + } + if (process && process != main_process) + CloseHandle (process); + } + + return ret; +} + +#endif From c890b0cc1613c1343c35beb005c59f2ef3120a82 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 20 Mar 2015 10:01:50 +0000 Subject: [PATCH 31/50] kill: kill Win32 processes more gently This change is the equivalent to the change to the Ctrl+C handling we just made. Co-authored-by: Naveen M K Signed-off-by: Johannes Schindelin --- winsup/utils/kill.cc | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/winsup/utils/kill.cc b/winsup/utils/kill.cc index bcabcd47c9..31ad57a137 100644 --- a/winsup/utils/kill.cc +++ b/winsup/utils/kill.cc @@ -17,6 +17,7 @@ details. */ #include #include #include +#include static char *prog_name; @@ -300,10 +301,20 @@ forcekill (pid_t pid, DWORD winpid, int sig, int wait) return; } if (!wait || WaitForSingleObject (h, 200) != WAIT_OBJECT_0) - if (sig && !TerminateProcess (h, sig << 8) - && WaitForSingleObject (h, 200) != WAIT_OBJECT_0) - fprintf (stderr, "%s: couldn't kill pid %u, %u\n", - prog_name, (unsigned int) dwpid, (unsigned int) GetLastError ()); + { + HANDLE cur = GetCurrentProcess (), h2; + /* duplicate handle with access rights required for exit_process_tree() */ + if (DuplicateHandle (cur, h, cur, &h2, PROCESS_CREATE_THREAD | + PROCESS_QUERY_INFORMATION | + PROCESS_VM_OPERATION | + PROCESS_VM_WRITE | PROCESS_VM_READ | + PROCESS_TERMINATE, FALSE, 0)) + { + CloseHandle(h); + h = h2; + } + exit_process_tree (h, 128 + sig); + } CloseHandle (h); } From 5ab3720b4f5c47411643a1c4cb5b408c18bd288f Mon Sep 17 00:00:00 2001 From: Jeremy Drake Date: Thu, 22 Jul 2021 11:59:16 -0700 Subject: [PATCH 32/50] Cygwin: make option for native inner link handling. This code has been causing issues with SUBST and mapped network drives, so add an option (defaulted to on) which can be used to disable it where needed. MSYS=nonativeinnerlinks --- winsup/cygwin/environ.cc | 1 + winsup/cygwin/globals.cc | 1 + winsup/cygwin/path.cc | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index b9600ef9a8..06b1111f51 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -123,6 +123,7 @@ static struct parse_thing {"error_start", {func: error_start_init}, isfunc, NULL, {{0}, {0}}}, {"export", {&export_settings}, setbool, NULL, {{false}, {true}}}, {"glob", {func: glob_init}, isfunc, NULL, {{0}, {s: "normal"}}}, + {"nativeinnerlinks", {&nativeinnerlinks}, setbool, NULL, {{false}, {true}}}, {"pipe_byte", {&pipe_byte}, setbool, NULL, {{false}, {true}}}, {"proc_retry", {func: set_proc_retry}, isfunc, NULL, {{0}, {5}}}, {"reset_com", {&reset_com}, setbool, NULL, {{false}, {true}}}, diff --git a/winsup/cygwin/globals.cc b/winsup/cygwin/globals.cc index b3b77de405..ab2c205609 100644 --- a/winsup/cygwin/globals.cc +++ b/winsup/cygwin/globals.cc @@ -74,6 +74,7 @@ bool wincmdln = true; winsym_t allow_winsymlinks = WSYM_deepcopy; bool disable_pcon; bool winjitdebug = false; +bool nativeinnerlinks = true; /* Taken from BSD libc: This variable is zero until a process has created a pthread. It is used diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 1b9050064c..d0c97ad4c3 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -3724,7 +3724,8 @@ symlink_info::check (char *path, const suffix_info *suffixes, fs_info &fs, differ, return the final path as symlink content and set symlen to a negative value. This forces path_conv::check to restart symlink evaluation with the new path. */ - if ((pc_flags & (PC_SYM_FOLLOW | PC_SYM_NOFOLLOW_REP)) == PC_SYM_FOLLOW) + if (nativeinnerlinks + && (pc_flags & (PC_SYM_FOLLOW | PC_SYM_NOFOLLOW_REP)) == PC_SYM_FOLLOW) { PWCHAR fpbuf = tp.w_get (); DWORD ret; From 1fcaaa3ff2d03311fa5aa04585280421a7b39543 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 8 Nov 2021 14:20:07 +0100 Subject: [PATCH 33/50] docs: skip building texinfo and PDF files The MSYS2 packages lack the infrastructure to build those. Signed-off-by: Johannes Schindelin --- winsup/configure.ac | 7 +++---- winsup/doc/Makefile.am | 9 +++------ 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/winsup/configure.ac b/winsup/configure.ac index b9e3977fcf..b88f3ade29 100644 --- a/winsup/configure.ac +++ b/winsup/configure.ac @@ -84,11 +84,10 @@ AM_CONDITIONAL(BUILD_DOC, [test $enable_doc != "no"]) AC_CHECK_PROGS([DOCBOOK2XTEXI], [docbook2x-texi db2x_docbook2texi]) if test -z "$DOCBOOK2XTEXI" ; then if test "x$enable_doc" != "xno"; then - AC_MSG_ERROR([docbook2texi is required to build documentation]) - else - unset DOCBOOK2XTEXI - AM_MISSING_PROG([DOCBOOK2XTEXI], [docbook2texi]) + AC_MSG_WARN([docbook2texi is required to build documentation]) fi + unset DOCBOOK2XTEXI + AM_MISSING_PROG([DOCBOOK2XTEXI], [docbook2texi]) fi AC_CHECK_PROGS([XMLTO], [xmlto]) diff --git a/winsup/doc/Makefile.am b/winsup/doc/Makefile.am index 650e0c9247..55e9b95e78 100644 --- a/winsup/doc/Makefile.am +++ b/winsup/doc/Makefile.am @@ -10,9 +10,7 @@ man1_MANS = man3_MANS = man5_MANS = -doc_DATA = \ - cygwin-ug-net/cygwin-ug-net.pdf \ - cygwin-api/cygwin-api.pdf +doc_DATA = htmldir = $(datarootdir)/doc @@ -35,8 +33,7 @@ all-local: Makefile.dep \ cygwin-ug-net/cygwin-ug-net.html \ faq/faq.html faq/faq.body \ cygwin-ug-net/cygwin-ug-net-nochunks.html.gz \ - api2man.stamp intro2man.stamp utils2man.stamp \ - cygwin-api.info cygwin-ug-net.info + api2man.stamp intro2man.stamp utils2man.stamp clean-local: rm -f Makefile.dep @@ -76,7 +73,7 @@ install-etc: @$(MKDIR_P) $(DESTDIR)$(sysconfdir)/preremove $(INSTALL_SCRIPT) $(srcdir)/etc.preremove.cygwin-doc.sh $(DESTDIR)$(sysconfdir)/preremove/cygwin-doc.sh -install-data-hook: install-extra-man install-html-local install-info-local install-etc +install-data-hook: install-extra-man install-html-local install-etc uninstall-extra-man: for i in *.1 ; do \ From bbd5897e690ce050ca41ff48f2738db8bd8a55eb Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 8 Nov 2021 16:22:57 +0100 Subject: [PATCH 34/50] install-libs: depend on the "toollibs" Before symlinking libg.a, we need the symlink source `libmsys-2.0.a`: in MSYS2, we copy by default (if we were creating Unix-style symlinks, the target would not have to exist before symlinking, but when copying we do need the source _right away_). Signed-off-by: Johannes Schindelin --- winsup/cygwin/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winsup/cygwin/Makefile.am b/winsup/cygwin/Makefile.am index b1b0df708e..1064b416b7 100644 --- a/winsup/cygwin/Makefile.am +++ b/winsup/cygwin/Makefile.am @@ -699,7 +699,7 @@ man_MANS = regex/regex.3 regex/regex.7 install-exec-hook: install-libs install-data-local: install-headers install-ldif -install-libs: +install-libs: install-toollibDATA @$(MKDIR_P) $(DESTDIR)$(bindir) $(INSTALL_PROGRAM) $(NEW_DLL_NAME) $(DESTDIR)$(bindir)/$(DLL_NAME) @$(MKDIR_P) $(DESTDIR)$(toollibdir) From 7e40bdfb022b6a7e8ae6df7e2267e9163d23b7ca Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 23 Nov 2015 20:03:11 +0100 Subject: [PATCH 35/50] POSIX-ify the SHELL variable When calling a non-MSys2 binary, all of the environment is converted from POSIX to Win32, including the SHELL environment variable. In Git for Windows, for example, `SHELL=/usr/bin/bash` is converted to `SHELL=C:\Program Files\Git\usr\bin\bash.exe` when calling the `git.exe` binary. This is appropriate because non-MSys2 binaries would not handle POSIX paths correctly. Under certain circumstances, however, `git.exe` calls an *MSys2* binary in turn, such as `git config --edit` calling `vim.exe` unless Git is configured to use another editor specifically. Now, when this "improved vi" calls shell commands, it uses that $SHELL variable *without quoting*, resulting in a nasty error: C:\Program: No such file or directory Many other programs behave in the same manner, assuming that $SHELL does not contain spaces and hence needs no quoting, unfortunately including some of Git's own scripts. Therefore let's make sure that $SHELL gets "posified" again when entering MSys2 programs. Earlier attempts by Git for Windows contributors claimed that adding `SHELL` to the `conv_envvars` array does not have the intended effect. These reports just missed that the `conv_start_chars` array (which makes the code more performant) needs to be adjusted, too. Note that we set the `immediate` flag to `true` so that the environment variable is set immediately by the MSys2 runtime, i.e. not only spawned processes will see the POSIX-ified `SHELL` variable, but the MSys2 runtime *itself*, too. This fixes https://github.com/git-for-windows/git/issues/542, https://github.com/git-for-windows/git/issues/498, and https://github.com/git-for-windows/git/issues/468. Signed-off-by: Johannes Schindelin --- winsup/cygwin/environ.cc | 8 +++++++- winsup/cygwin/local_includes/environ.h | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index 06b1111f51..e21c8fddb9 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -323,6 +323,7 @@ static win_env conv_envvars[] = {NL ("HOME="), NULL, NULL, env_path_to_posix, env_path_to_win32, false}, {NL ("LD_LIBRARY_PATH="), NULL, NULL, env_plist_to_posix, env_plist_to_win32, true}, + {NL ("SHELL="), NULL, NULL, env_path_to_posix, env_path_to_win32, true, true}, {NL ("TMPDIR="), NULL, NULL, env_path_to_posix, env_path_to_win32, false}, {NL ("TMP="), NULL, NULL, env_path_to_posix, env_path_to_win32, false}, {NL ("TEMP="), NULL, NULL, env_path_to_posix, env_path_to_win32, false}, @@ -351,7 +352,7 @@ static const unsigned char conv_start_chars[256] = WC, 0, 0, 0, WC, 0, 0, 0, /* 80 */ /* P Q R S T U V W */ - WC, 0, 0, 0, WC, 0, 0, 0, + WC, 0, 0, WC, WC, 0, 0, 0, /* 88 */ /* x Y Z */ 0, 0, 0, 0, 0, 0, 0, 0, @@ -380,6 +381,7 @@ win_env::operator = (struct win_env& x) toposix = x.toposix; towin32 = x.towin32; immediate = false; + skip_if_empty = x.skip_if_empty; return *this; } @@ -401,6 +403,8 @@ win_env::add_cache (const char *in_posix, const char *in_native) native = (char *) realloc (native, namelen + 1 + strlen (in_native)); stpcpy (stpcpy (native, name), in_native); } + else if (skip_if_empty && !*in_posix) + native = (char *) calloc(1, 1); else { tmp_pathbuf tp; @@ -466,6 +470,8 @@ posify_maybe (char **here, const char *value, char *outenv) return; int len = strcspn (src, "=") + 1; + if (conv->skip_if_empty && !src[len]) + return; /* Turn all the items from c:; into their mounted equivalents - if there is one. */ diff --git a/winsup/cygwin/local_includes/environ.h b/winsup/cygwin/local_includes/environ.h index 0dd45359cc..fd6ca466e8 100644 --- a/winsup/cygwin/local_includes/environ.h +++ b/winsup/cygwin/local_includes/environ.h @@ -21,7 +21,7 @@ struct win_env char *native; ssize_t (*toposix) (const void *, void *, size_t); ssize_t (*towin32) (const void *, void *, size_t); - bool immediate; + bool immediate, skip_if_empty; void add_cache (const char *in_posix, const char *in_native = NULL); const char * get_native () const {return native ? native + namelen : NULL;} const char * get_posix () const {return posix ? posix : NULL;} From 4c80b59ea393c6248a6e17e37a2c00628c4aaf70 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 21 Mar 2017 13:18:38 +0100 Subject: [PATCH 36/50] Handle ORIGINAL_PATH just like PATH MSYS2 recently introduced that hack where the ORIGINAL_PATH variable is set to the original PATH value in /etc/profile, unless previously set. In Git for Windows' default mode, that ORIGINAL_PATH value is the used to define the PATH variable explicitly. So far so good. The problem: when calling from inside an MSYS2 process (such as Bash) a MINGW executable (such as git.exe) that then calls another MSYS2 executable (such as bash.exe), that latter call will try to re-convert ORIGINAL_PATH after the previous call converted ORIGINAL_PATH from POSIX to Windows paths. And this conversion may very well fail, e.g. when the path list contains mixed semicolons and colons. So let's just *force* the MSYS2 runtime to handle ORIGINAL_PATH in the same way as the PATH variable (which conversion works, as we know). Signed-off-by: Johannes Schindelin --- winsup/cygwin/environ.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index e21c8fddb9..031db039ea 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -323,6 +323,7 @@ static win_env conv_envvars[] = {NL ("HOME="), NULL, NULL, env_path_to_posix, env_path_to_win32, false}, {NL ("LD_LIBRARY_PATH="), NULL, NULL, env_plist_to_posix, env_plist_to_win32, true}, + {NL ("ORIGINAL_PATH="), NULL, NULL, env_PATH_to_posix, env_plist_to_win32, true}, {NL ("SHELL="), NULL, NULL, env_path_to_posix, env_path_to_win32, true, true}, {NL ("TMPDIR="), NULL, NULL, env_path_to_posix, env_path_to_win32, false}, {NL ("TMP="), NULL, NULL, env_path_to_posix, env_path_to_win32, false}, @@ -349,7 +350,7 @@ static const unsigned char conv_start_chars[256] = 0, 0, 0, 0, 0, 0, 0, 0, /* 72 */ /* H I J K L M N O */ - WC, 0, 0, 0, WC, 0, 0, 0, + WC, 0, 0, 0, WC, 0, 0, WC, /* 80 */ /* P Q R S T U V W */ WC, 0, 0, WC, WC, 0, 0, 0, From 0c124b9088fd6e3a00517b3b5b65f689dee825c2 Mon Sep 17 00:00:00 2001 From: Christoph Reiter Date: Sun, 3 Jul 2022 22:39:32 +0200 Subject: [PATCH 37/50] uname: allow setting the system name to CYGWIN We are currently trying to move our cygwin build environment closer to cygwin and some autotools/bash based build systems call "uname -s" to figure out the OS and in many cases only handle the cygwin case, so we have to patch them. With this instead of patching we can set MSYSTEM=CYGWIN and change uname output that way. The next step would be to always output CYGWIN in an msys env by default, but for now this allows us to get rid of all the patches without affecting users. --- winsup/cygwin/uname.cc | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/winsup/cygwin/uname.cc b/winsup/cygwin/uname.cc index 0d0c5aa52a..a4ac0e304d 100644 --- a/winsup/cygwin/uname.cc +++ b/winsup/cygwin/uname.cc @@ -24,6 +24,24 @@ extern "C" int getdomainname (char *__name, size_t __len); #define ATTRIBUTE_NONSTRING #endif +static const char* +get_sysname() +{ +#ifdef __MSYS__ + char* msystem = getenv("MSYSTEM"); + if (!msystem || strcmp(msystem, "MSYS") == 0) + return "MSYS"; + else if (strcmp(msystem, "CYGWIN") == 0) + return "CYGWIN"; + else if (strstr(msystem, "32") != NULL) + return "MINGW32"; + else + return "MINGW64"; +#else + return "CYGWIN"; +#endif +} + /* uname: POSIX 4.4.1.1 */ /* New entrypoint for applications since API 335 */ @@ -36,12 +54,9 @@ uname_x (struct utsname *name) memset (name, 0, sizeof (*name)); /* sysname */ - char* msystem = getenv("MSYSTEM"); - const char* msystem_sysname = "MSYS"; - if (msystem != NULL && *msystem && strcmp(msystem, "MSYS") != 0) - msystem_sysname = (strstr(msystem, "32") != NULL) ? "MINGW32" : "MINGW64";; + const char* sysname = get_sysname(); __small_sprintf (name->sysname, "%s_%s-%u", - msystem_sysname, + sysname, wincap.osname (), wincap.build_number ()); /* nodename */ memset (buf, 0, sizeof buf); @@ -107,15 +122,8 @@ uname (struct utsname *in_name) __try { memset (name, 0, sizeof (*name)); -#ifdef __MSYS__ - char* msystem = getenv("MSYSTEM"); - const char* msystem_sysname = "MSYS"; - if (msystem != NULL && *msystem && strcmp(msystem, "MSYS") != 0) - msystem_sysname = (strstr(msystem, "32") != NULL) ? "MINGW32" : "MINGW64"; - __small_sprintf (name->sysname, "%s_%s", msystem_sysname, wincap.osname ()); -#else - __small_sprintf (name->sysname, "CYGWIN_%s", wincap.osname ()); -#endif + const char* sysname = get_sysname(); + __small_sprintf (name->sysname, "%s_%s", sysname, wincap.osname ()); /* Computer name */ cygwin_gethostname (name->nodename, sizeof (name->nodename) - 1); From 54d1ac996bca6999cee71cc0f4d9a35e821792ac Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 18 Feb 2015 12:32:17 +0000 Subject: [PATCH 38/50] Pass environment variables with empty values There is a difference between an empty value and an unset environment variable. We should not confuse both; If the user wants to unset an environment variable, they can certainly do so (unsetenv(3), or in the shell: 'unset ABC'). This fixes Git's t3301-notes.sh, which overrides environment variables with empty values. Signed-off-by: Johannes Schindelin --- winsup/cygwin/environ.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index 031db039ea..6b385cd03d 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -1326,11 +1326,11 @@ build_env (const char * const *envp, PWCHAR &envblock, int &envc, Note that this doesn't stop invalid strings without '=' in it etc., but we're opting for speed here for now. Adding complete checking would be pretty expensive. */ - if (len == 1 || !*rest) + if (len == 1) continue; /* See if this entry requires posix->win32 conversion. */ - conv = getwinenv (*srcp, rest, &temp); + conv = !*rest ? NULL : getwinenv (*srcp, rest, &temp); if (conv) { p = conv->native; /* Use win32 path */ @@ -1344,7 +1344,7 @@ build_env (const char * const *envp, PWCHAR &envblock, int &envc, } } #ifdef __MSYS__ - else if (!keep_posix) { + else if (!keep_posix && *rest) { char *win_arg = arg_heuristic_with_exclusions (*srcp, msys2_env_conv_excl_env, msys2_env_conv_excl_count); debug_printf("WIN32_PATH is %s", win_arg); From 6fe00e22de4a5ee84bb519dfa70e35990fc2e00e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 6 Sep 2022 10:40:58 +0200 Subject: [PATCH 39/50] Optionally disallow empty environment values again We just disabled the code that skips environment variables whose values are empty. However, this code was introduced a long time ago into Cygwin in d6b1ac7faa (* environ.cc (build_env): Don't put an empty environment variable into the environment. Optimize use of "len". * errno.cc (ERROR_MORE_DATA): Translate to EMSGSIZE rather than EAGAIN., 2006-09-07), seemingly without any complaints. Meaning: There might very well be use cases out there where it makes sense to skip empty-valued environment variables. Therefore, it seems like a good idea to have a "knob" to turn it back on. With this commit, we introduce such a knob: by setting `noemptyenvvalues` the `MSYS` variable (or appending it if that variable is already set), users can tell the MSYS2 runtime to behave just like in the olden times. Signed-off-by: Johannes Schindelin --- winsup/cygwin/environ.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index 6b385cd03d..12b4d57563 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -36,6 +36,7 @@ static char **lastenviron; /* Parse CYGWIN options */ static NO_COPY bool export_settings = false; +static bool emptyenvvalues = true; enum settings { @@ -119,6 +120,7 @@ static struct parse_thing } known[] NO_COPY = { {"disable_pcon", {&disable_pcon}, setbool, NULL, {{false}, {true}}}, + {"emptyenvvalues", {&emptyenvvalues}, setbool, NULL, {{false}, {true}}}, {"enable_pcon", {&disable_pcon}, setnegbool, NULL, {{true}, {false}}}, {"error_start", {func: error_start_init}, isfunc, NULL, {{0}, {0}}}, {"export", {&export_settings}, setbool, NULL, {{false}, {true}}}, @@ -1326,7 +1328,7 @@ build_env (const char * const *envp, PWCHAR &envblock, int &envc, Note that this doesn't stop invalid strings without '=' in it etc., but we're opting for speed here for now. Adding complete checking would be pretty expensive. */ - if (len == 1) + if (len == 1 || (!emptyenvvalues && !*rest)) continue; /* See if this entry requires posix->win32 conversion. */ From 82d1e3b556949c920997adbdb73bc19ec0874d19 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 6 Sep 2022 12:18:18 +0200 Subject: [PATCH 40/50] build_env(): respect the `MSYS` environment variable With this commit, you can call MSYS=noemptyenvvalues my-command and it does what is expected: to pass no empty-valued environment variables to `my-command`. Signed-off-by: Johannes Schindelin --- winsup/cygwin/environ.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index 12b4d57563..4e049211e9 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -1204,7 +1204,11 @@ build_env (const char * const *envp, PWCHAR &envblock, int &envc, { bool calc_tl = !no_envblock; #ifdef __MSYS__ - if (!keep_posix) + if (ascii_strncasematch(*srcp, "MSYS=", 5)) + { + parse_options (*srcp + 5); + } + else if (!keep_posix) { /* Don't pass timezone environment to non-msys applications */ if (ascii_strncasematch(*srcp, "TZ=", 3)) From 855f33f4b940bb73cf749bdde31c81a157b7e6ae Mon Sep 17 00:00:00 2001 From: Christoph Reiter Date: Sat, 17 Dec 2022 20:14:49 +0100 Subject: [PATCH 41/50] Revert "Cygwin: Enable dynamicbase on the Cygwin DLL by default" This reverts commit 943433b00cacdde0cb9507d0178770a2fb67bd71. This seems to fix fork errors under Docker, see https://cygwin.com/pipermail/cygwin/2022-December/252711.html --- winsup/cygwin/Makefile.am | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/winsup/cygwin/Makefile.am b/winsup/cygwin/Makefile.am index 1064b416b7..76b54eba4f 100644 --- a/winsup/cygwin/Makefile.am +++ b/winsup/cygwin/Makefile.am @@ -600,8 +600,7 @@ $(NEW_DLL_NAME): $(LDSCRIPT) libdll.a $(VERSION_OFILES) $(LIBSERVER)\ $(newlib_build)/libm.a $(newlib_build)/libc.a $(AM_V_CXXLD)$(CXX) $(CXXFLAGS) \ -mno-use-libstdc-wrappers \ - -Wl,--gc-sections -nostdlib -Wl,-T$(LDSCRIPT) \ - -Wl,--dynamicbase -static \ + -Wl,--gc-sections -nostdlib -Wl,-T$(LDSCRIPT) -static \ $${SOURCE_DATE_EPOCH:+-Wl,--no-insert-timestamp} \ -Wl,--heap=0 -Wl,--out-implib,msysdll.a -shared -o $@ \ -e @DLL_ENTRY@ $(DEF_FILE) \ From c8c911a222f9a3442b72901a60bfa4f2105b6125 Mon Sep 17 00:00:00 2001 From: Christoph Reiter Date: Fri, 17 May 2024 19:37:45 +0200 Subject: [PATCH 42/50] CI: set -Wno-error=maybe-uninitialized After the update of msys2-w32api from v11.0.1 to current master (and soon to be v12) we get: winsup/cygwin/exceptions.cc:1736:33: error: '' may be used uninitialized [-Werror=maybe-uninitialized] Ignore it like the rest. Fixes #214 --- .github/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 4b3fa42ec9..80dc67e5b6 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -22,7 +22,7 @@ jobs: run: | # XXX: cygwin still uses gcc v11 so we get new warnings with v13, # resulting in errors due to -Werror. Disable them for now. - export CXXFLAGS="-Wno-error=stringop-truncation -Wno-error=array-bounds -Wno-error=overloaded-virtual -Wno-narrowing -Wno-use-after-free" + export CXXFLAGS="-Wno-error=stringop-truncation -Wno-error=array-bounds -Wno-error=overloaded-virtual -Wno-narrowing -Wno-use-after-free -Wno-error=maybe-uninitialized" (cd winsup && ./autogen.sh) ./configure --disable-dependency-tracking --with-msys2-runtime-commit="$GITHUB_SHA" make -j8 From f840e12ed789d12122691d6de8a08c0971cd1992 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 30 Jan 2023 23:22:22 +0100 Subject: [PATCH 43/50] Avoid sharing cygheaps across Cygwin versions It frequently leads to problems when trying, say, to call from MSYS2's Bash into Cygwin's or Git for Windows', merely because sharing that data is pretty finicky. For example, using the MSYS2' Bash using the MSYS2 runtime version that is current at time of writing, trying to call Cygwin's programs fails in manners like this: $ /c/cygwin64/bin/uname -r 0 [main] uname (9540) child_copy: cygheap read copy failed, 0x800000000..0x800010BE0, done 0, windows pid 9540, Win32 error 6 680 [main] uname 880 C:\cygwin64\bin\uname.exe: *** fatal error - couldn't create signal pipe, Win32 error 5 with the rather misleading exit code 127 (a code which is reserved to indicate that a command was not found). Let's just treat the MSYS2 runtime and the Cygwin runtime as completely incompatible with one another, by virtue of using a different magic constant than merely `CHILD_INFO_MAGIC`. By using the msys2-runtime commit to modify that magic constant, we can even spawn programs using a different MSYS2 runtime (such as Git for Windows') because the commit serves as the tell-tale whether two MSYS2 runtime versions are compatible with each other. To support building in the MSYS2-packages repository (where we do not check out the `msys2-runtime` but instead check out Cygwin and apply patches on top), let's accept a hard-coded commit hash as `./configure` option. One consequence is that spawned MSYS processes using a different MSYS2 runtime will not be visible as such to the parent process, i.e. they cannot share any resources such as pseudo terminals. But that's okay, they are simply treated as if they were regular Win32 programs. Note: We have to use a very rare form of encoding the brackets in the `expr` calls: quadrigraphs (for a thorough explanation, see https://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.70/html_node/Quadrigraphs.html#Quadrigraphs). This is necessary because it is apparently impossible to encode brackets in `configure.ac` files otherwise. Signed-off-by: Johannes Schindelin --- winsup/configure.ac | 28 ++++++++++++++++++++++++++++ winsup/cygwin/Makefile.am | 3 +++ winsup/cygwin/dcrt0.cc | 2 +- winsup/cygwin/sigproc.cc | 2 +- 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/winsup/configure.ac b/winsup/configure.ac index b88f3ade29..3aa2b16bf8 100644 --- a/winsup/configure.ac +++ b/winsup/configure.ac @@ -57,6 +57,34 @@ AC_CHECK_TOOL(RANLIB, ranlib, ranlib) AC_CHECK_TOOL(STRIP, strip, strip) AC_CHECK_TOOL(WINDRES, windres, windres) +# Record msys2-runtime commit +AC_ARG_WITH([msys2-runtime-commit], + [AS_HELP_STRING([--with-msys2-runtime-commit=COMMIT], + [indicate the msys2-runtime commit corresponding to this build])], + [MSYS2_RUNTIME_COMMIT=$withval], [MSYS2_RUNTIME_COMMIT=yes]) +case "$MSYS2_RUNTIME_COMMIT" in +no) + MSYS2_RUNTIME_COMMIT= + MSYS2_RUNTIME_COMMIT_HEX=0 + ;; +yes|auto) + if MSYS2_RUNTIME_COMMIT="$(git --git-dir="$srcdir/../.git" rev-parse HEAD)" + then + MSYS2_RUNTIME_COMMIT_HEX="0x$(expr "$MSYS2_RUNTIME_COMMIT" : '\(.\{,8\}\)')ull" + else + AC_MSG_WARN([Could not determine msys2-runtime commit]) + MSYS2_RUNTIME_COMMIT= + MSYS2_RUNTIME_COMMIT_HEX=0 + fi + ;; +*) + expr "$MSYS2_RUNTIME_COMMIT" : '@<:@0-9a-f@:>@\{6,64\}$' || + AC_MSG_ERROR([Invalid commit name: "$MSYS2_RUNTIME_COMMIT"]) + MSYS2_RUNTIME_COMMIT_HEX="0x$(expr "$MSYS2_RUNTIME_COMMIT" : '\(.\{,8\}\)')ull" + ;; +esac +AC_SUBST(MSYS2_RUNTIME_COMMIT_HEX) + AC_ARG_ENABLE(debugging, [AS_HELP_STRING([--enable-debugging],[Build a cygwin DLL which has more consistency checking for debugging])], [case "${enableval}" in diff --git a/winsup/cygwin/Makefile.am b/winsup/cygwin/Makefile.am index 76b54eba4f..774e562f51 100644 --- a/winsup/cygwin/Makefile.am +++ b/winsup/cygwin/Makefile.am @@ -17,6 +17,9 @@ if TARGET_X86_64 COMMON_CFLAGS+=-mcmodel=small endif +VERSION_CFLAGS = -DMSYS2_RUNTIME_COMMIT_HEX="@MSYS2_RUNTIME_COMMIT_HEX@" +COMMON_CFLAGS += $(VERSION_CFLAGS) + AM_CFLAGS=$(cflags_common) $(COMMON_CFLAGS) AM_CXXFLAGS=$(cxxflags_common) $(COMMON_CFLAGS) -fno-threadsafe-statics diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index 0a5c817b3c..351d32d8e3 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -531,7 +531,7 @@ get_cygwin_startup_info () child_info *res = (child_info *) si.lpReserved2; if (si.cbReserved2 < EXEC_MAGIC_SIZE || !res - || res->intro != PROC_MAGIC_GENERIC || res->magic != CHILD_INFO_MAGIC) + || res->intro != PROC_MAGIC_GENERIC || res->magic != (CHILD_INFO_MAGIC ^ MSYS2_RUNTIME_COMMIT_HEX)) { strace.activate (false); res = NULL; diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index 2759d16244..858a7fd12d 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -835,7 +835,7 @@ int child_info::retry_count = 0; child_info::child_info (unsigned in_cb, child_info_types chtype, bool need_subproc_ready): msv_count (0), cb (in_cb), intro (PROC_MAGIC_GENERIC), - magic (CHILD_INFO_MAGIC), type (chtype), cygheap (::cygheap), + magic (CHILD_INFO_MAGIC ^ MSYS2_RUNTIME_COMMIT_HEX), type (chtype), cygheap (::cygheap), cygheap_max (::cygheap_max), flag (0), retry (child_info::retry_count), rd_proc_pipe (NULL), wr_proc_pipe (NULL), sigmask (_my_tls.sigmask) { From 905cab18b56559691f5648b5bdfe26320a9f2d5e Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 21 Feb 2023 16:36:36 +0100 Subject: [PATCH 44/50] uname: report msys2-runtime commit hash, too Having just Cygwin's version in the output of `uname` is not helpful, as both MSYS2 as well as Git for Windows release intermediate versions of the MSYS2 runtime much more often than Cygwin runtime versions are released. Signed-off-by: Johannes Schindelin --- winsup/configure.ac | 10 ++++++++-- winsup/cygwin/Makefile.am | 6 ++++-- winsup/cygwin/scripts/mkvers.sh | 8 ++++++++ winsup/cygwin/uname.cc | 16 +++++++++------- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/winsup/configure.ac b/winsup/configure.ac index 3aa2b16bf8..4dd5ccb9f9 100644 --- a/winsup/configure.ac +++ b/winsup/configure.ac @@ -65,24 +65,30 @@ AC_ARG_WITH([msys2-runtime-commit], case "$MSYS2_RUNTIME_COMMIT" in no) MSYS2_RUNTIME_COMMIT= + MSYS2_RUNTIME_COMMIT_SHORT= MSYS2_RUNTIME_COMMIT_HEX=0 ;; yes|auto) if MSYS2_RUNTIME_COMMIT="$(git --git-dir="$srcdir/../.git" rev-parse HEAD)" then - MSYS2_RUNTIME_COMMIT_HEX="0x$(expr "$MSYS2_RUNTIME_COMMIT" : '\(.\{,8\}\)')ull" + MSYS2_RUNTIME_COMMIT_SHORT="$(expr "$MSYS2_RUNTIME_COMMIT" : '\(.\{,8\}\)')" + MSYS2_RUNTIME_COMMIT_HEX="0x${MSYS2_RUNTIME_COMMIT_SHORT}ul" else AC_MSG_WARN([Could not determine msys2-runtime commit]) MSYS2_RUNTIME_COMMIT= + MSYS2_RUNTIME_COMMIT_SHORT= MSYS2_RUNTIME_COMMIT_HEX=0 fi ;; *) expr "$MSYS2_RUNTIME_COMMIT" : '@<:@0-9a-f@:>@\{6,64\}$' || AC_MSG_ERROR([Invalid commit name: "$MSYS2_RUNTIME_COMMIT"]) - MSYS2_RUNTIME_COMMIT_HEX="0x$(expr "$MSYS2_RUNTIME_COMMIT" : '\(.\{,8\}\)')ull" + MSYS2_RUNTIME_COMMIT_SHORT="$(expr "$MSYS2_RUNTIME_COMMIT" : '\(.\{,8\}\)')" + MSYS2_RUNTIME_COMMIT_HEX="0x${MSYS2_RUNTIME_COMMIT_SHORT}ul" ;; esac +AC_SUBST(MSYS2_RUNTIME_COMMIT) +AC_SUBST(MSYS2_RUNTIME_COMMIT_SHORT) AC_SUBST(MSYS2_RUNTIME_COMMIT_HEX) AC_ARG_ENABLE(debugging, diff --git a/winsup/cygwin/Makefile.am b/winsup/cygwin/Makefile.am index 774e562f51..abcb32360d 100644 --- a/winsup/cygwin/Makefile.am +++ b/winsup/cygwin/Makefile.am @@ -17,7 +17,9 @@ if TARGET_X86_64 COMMON_CFLAGS+=-mcmodel=small endif -VERSION_CFLAGS = -DMSYS2_RUNTIME_COMMIT_HEX="@MSYS2_RUNTIME_COMMIT_HEX@" +VERSION_CFLAGS = -DMSYS2_RUNTIME_COMMIT="\"@MSYS2_RUNTIME_COMMIT@\"" +VERSION_CFLAGS += -DMSYS2_RUNTIME_COMMIT_SHORT="\"@MSYS2_RUNTIME_COMMIT_SHORT@\"" +VERSION_CFLAGS += -DMSYS2_RUNTIME_COMMIT_HEX="@MSYS2_RUNTIME_COMMIT_HEX@" COMMON_CFLAGS += $(VERSION_CFLAGS) AM_CFLAGS=$(cflags_common) $(COMMON_CFLAGS) @@ -452,7 +454,7 @@ uname_version.c: .FORCE version.cc: scripts/mkvers.sh include/cygwin/version.h winver.rc $(src_files) @echo "Making version.cc and winver.o";\ export CC="$(CC)";\ - /bin/sh $(word 1,$^) $(word 2,$^) $(word 3,$^) $(WINDRES) $(CFLAGS) + /bin/sh $(word 1,$^) $(word 2,$^) $(word 3,$^) $(WINDRES) $(CFLAGS) $(VERSION_CFLAGS) winver.o: version.cc diff --git a/winsup/cygwin/scripts/mkvers.sh b/winsup/cygwin/scripts/mkvers.sh index a3d45c5db0..34d8d6dce1 100755 --- a/winsup/cygwin/scripts/mkvers.sh +++ b/winsup/cygwin/scripts/mkvers.sh @@ -16,6 +16,7 @@ incfile="$1"; shift rcfile="$1"; shift windres="$1"; shift iflags= +msys2_runtime_commit= # Find header file locations while [ -n "$*" ]; do case "$1" in @@ -26,6 +27,9 @@ while [ -n "$*" ]; do shift iflags="$iflags -I$1" ;; + -DMSYS2_RUNTIME_COMMIT=*) + msys2_runtime_commit="${1#*=}" + ;; esac shift done @@ -168,6 +172,10 @@ then cvs_tag="$(echo $wv_cvs_tag | sed -e 's/-branch.*//')" cygwin_ver="$cygwin_ver-$cvs_tag" fi +if [ -n "$msys2_runtime_commit" ] +then + cygwin_ver="$cygwin_ver-$msys2_runtime_commit" +fi echo "Version $cygwin_ver" set -$- $builddate diff --git a/winsup/cygwin/uname.cc b/winsup/cygwin/uname.cc index a4ac0e304d..a978363f1c 100644 --- a/winsup/cygwin/uname.cc +++ b/winsup/cygwin/uname.cc @@ -76,18 +76,19 @@ uname_x (struct utsname *name) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat-truncation=" #ifdef CYGPORT_RELEASE_INFO - snprintf (name->release, _UTSNAME_LENGTH, "%s.%s", - __XSTRING (CYGPORT_RELEASE_INFO), name->machine); + snprintf (name->release, _UTSNAME_LENGTH, "%s-%s.%s", + __XSTRING (CYGPORT_RELEASE_INFO), MSYS2_RUNTIME_COMMIT_SHORT, name->machine); #else extern const char *uname_dev_version; if (uname_dev_version && uname_dev_version[0]) - snprintf (name->release, _UTSNAME_LENGTH, "%s.%s", - uname_dev_version, name->machine); + snprintf (name->release, _UTSNAME_LENGTH, "%s-%s.%s", + uname_dev_version, MSYS2_RUNTIME_COMMIT_SHORT, name->machine); else - __small_sprintf (name->release, "%d.%d.%d-api-%d.%s", + __small_sprintf (name->release, "%d.%d.%d-%s-api-%d.%s", cygwin_version.dll_major / 1000, cygwin_version.dll_major % 1000, cygwin_version.dll_minor, + MSYS2_RUNTIME_COMMIT_SHORT, cygwin_version.api_minor, name->machine); #endif @@ -129,14 +130,15 @@ uname (struct utsname *in_name) cygwin_gethostname (name->nodename, sizeof (name->nodename) - 1); /* Cygwin dll release */ - __small_sprintf (name->release, "%d.%d.%d(%d.%d/%d/%d)", + __small_sprintf (name->release, "%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_version.mount_registry); + cygwin_version.mount_registry, + MSYS2_RUNTIME_COMMIT_SHORT); /* Cygwin "version" aka build date */ strcpy (name->version, cygwin_version.dll_build_date); From 856e9498336066f8a96fef1dadeb0d9fe0c700b4 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Tue, 13 Feb 2024 16:47:51 +0100 Subject: [PATCH 45/50] Cygwin: find_fast_cwd: don't run assembler checking code on ARM64 https://cygwin.com/pipermail/cygwin/2024-February/255397.html reports a crash on ARM64 probably related to checking x86_64 code on the x86_64 emulator on AArch64. At least for testing, pull the code checking the host HW up to be called before trying to evaluate assembler code. This fixes https://github.com/git-for-windows/git/issues/4808 Backported from 4e77fa9b8b (Cygwin: find_fast_cwd: don't run assembler checking code on ARM64, 2024-02-13). Signed-off-by: Corinna Vinschen Signed-off-by: Johannes Schindelin --- winsup/cygwin/path.cc | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index d0c97ad4c3..1021005d7f 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -4828,29 +4828,27 @@ find_fast_cwd_pointer () static fcwd_access_t ** find_fast_cwd () { + USHORT emulated, hosted; + fcwd_access_t **f_cwd_ptr; + + /* First check if we're running in WOW64 on ARM64 emulating AMD64. Skip + fetching FAST_CWD pointer as long as there's no solution for finding + it on that system. */ + if (IsWow64Process2 (GetCurrentProcess (), &emulated, &hosted) + && hosted == IMAGE_FILE_MACHINE_ARM64) + return NULL; + /* Fetch the pointer but don't set the global fast_cwd_ptr yet. First we have to make sure we know the version of the FAST_CWD structure used on the system. */ - fcwd_access_t **f_cwd_ptr = find_fast_cwd_pointer (); + f_cwd_ptr = find_fast_cwd_pointer (); if (!f_cwd_ptr) - { - bool warn = 1; - USHORT emulated, hosted; - - /* Check if we're running in WOW64 on ARM64 emulating AMD64. Skip - warning as long as there's no solution for finding the FAST_CWD - pointer on that system. */ - if (IsWow64Process2 (GetCurrentProcess (), &emulated, &hosted) - && hosted == IMAGE_FILE_MACHINE_ARM64) - warn = 0; - - if (warn) - small_printf ("Cygwin WARNING:\n" + small_printf ("Cygwin WARNING:\n" " Couldn't compute FAST_CWD pointer. This typically occurs if you're using\n" " an older Cygwin version on a newer Windows. Please update to the latest\n" " available Cygwin version from https://cygwin.com/. If the problem persists,\n" " please see https://cygwin.com/problems.html\n\n"); - } + /* Eventually, after we set the version as well, set fast_cwd_ptr. */ return f_cwd_ptr; } From c94b46ba0328dcba25f6a541f1c60ab53c06754e Mon Sep 17 00:00:00 2001 From: Jeremy Drake Date: Mon, 11 Nov 2024 20:09:49 -0800 Subject: [PATCH 46/50] cygthread: suspend thread before terminating. This addresses an extremely difficult to debug deadlock when running under emulation on ARM64. A relatively easy way to trigger this bug is to call `fork()`, then within the child process immediately call another `fork()` and then `exit()` the intermediate process. It would seem that there is a "code emulation" lock on the wait thread at this stage, and if the thread is terminated too early, that lock still exists albeit without a thread, and nothing moves forward. It seems that a `SuspendThread()` combined with a `GetThreadContext()` (to force the thread to _actually_ be suspended, for more details see https://devblogs.microsoft.com/oldnewthing/20150205-00/?p=44743) makes sure the thread is "booted" from emulation before it is suspended. Hopefully this means it won't be holding any locks or otherwise leave emulation in a bad state when the thread is terminated. Also, attempt to use `CancelSynchonousIo()` (as seen in `flock.cc`) to avoid the need for `TerminateThread()` altogether. This doesn't always work, however, so was not a complete fix for the deadlock issue. Addresses: https://cygwin.com/pipermail/cygwin-developers/2024-May/012694.html Signed-off-by: Jeremy Drake --- winsup/cygwin/cygthread.cc | 14 ++++++++++++++ winsup/cygwin/pinfo.cc | 10 +++++++--- winsup/cygwin/sigproc.cc | 12 ++++++++++-- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/winsup/cygwin/cygthread.cc b/winsup/cygwin/cygthread.cc index 54918e7677..4f16097531 100644 --- a/winsup/cygwin/cygthread.cc +++ b/winsup/cygwin/cygthread.cc @@ -302,6 +302,20 @@ cygthread::terminate_thread () if (!inuse) goto force_notterminated; + if (_my_tls._ctinfo != this) + { + CONTEXT context; + context.ContextFlags = CONTEXT_CONTROL; + /* SuspendThread makes sure a thread is "booted" from emulation before + it is suspended. As such, the emulator hopefully won't be in a bad + state (aka, holding any locks) when the thread is terminated. */ + SuspendThread (h); + /* We need to call GetThreadContext, even though we don't care about the + context, because SuspendThread is asynchronous and GetThreadContext + will make sure the thread is *really* suspended before returning */ + GetThreadContext (h, &context); + } + TerminateThread (h, 0); WaitForSingleObject (h, INFINITE); CloseHandle (h); diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc index a5f5d6eb22..4bb19464b4 100644 --- a/winsup/cygwin/pinfo.cc +++ b/winsup/cygwin/pinfo.cc @@ -1262,13 +1262,17 @@ proc_waiter (void *arg) for (;;) { - DWORD nb; + DWORD nb, err; char buf = '\0'; if (!ReadFile (vchild.rd_proc_pipe, &buf, 1, &nb, NULL) - && GetLastError () != ERROR_BROKEN_PIPE) + && (err = GetLastError ()) != ERROR_BROKEN_PIPE) { - system_printf ("error on read of child wait pipe %p, %E", vchild.rd_proc_pipe); + /* ERROR_OPERATION_ABORTED is expected due to the possibility that + CancelSynchronousIo interruped the ReadFile call, so don't output + that error */ + if (err != ERROR_OPERATION_ABORTED) + system_printf ("error on read of child wait pipe %p, %E", vchild.rd_proc_pipe); break; } diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index 858a7fd12d..a6d06a8149 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -413,7 +413,11 @@ proc_terminate () to 1 iff it is a Cygwin process. */ if (!have_execed || !have_execed_cygwin) chld_procs[i]->ppid = 1; - if (chld_procs[i].wait_thread) + /* Attempt to exit the wait_thread cleanly via CancelSynchronousIo + before falling back to the (explicitly dangerous) cross-thread + termination */ + if (chld_procs[i].wait_thread + && !CancelSynchronousIo (chld_procs[i].wait_thread->thread_handle ())) chld_procs[i].wait_thread->terminate_thread (); /* Release memory associated with this process unless it is 'myself'. 'myself' is only in the chld_procs table when we've execed. We @@ -1198,7 +1202,11 @@ remove_proc (int ci) { if (have_execed) { - if (_my_tls._ctinfo != chld_procs[ci].wait_thread) + /* Attempt to exit the wait_thread cleanly via CancelSynchronousIo + before falling back to the (explicitly dangerous) cross-thread + termination */ + if (_my_tls._ctinfo != chld_procs[ci].wait_thread + && !CancelSynchronousIo (chld_procs[ci].wait_thread->thread_handle ())) chld_procs[ci].wait_thread->terminate_thread (); } else if (chld_procs[ci] && chld_procs[ci]->exists ()) From 62f6088206fcf4c9cbd74b23a869b7547f640c65 Mon Sep 17 00:00:00 2001 From: Jeremy Drake Date: Thu, 21 Nov 2024 22:13:42 -0800 Subject: [PATCH 47/50] Cygwin: revert use of CancelSyncronousIo on wait_thread. It appears this is causing hangs on native x86_64 in similar scenarios as the hangs on ARM64, because `CancelSynchronousIo` is returning `TRUE` but not canceling the `ReadFile` call as expected. Addresses: https://github.com/msys2/MSYS2-packages/issues/4340#issuecomment-2491401847 Fixes: b091b47b9e56 ("cygthread: suspend thread before terminating.") Signed-off-by: Jeremy Drake --- winsup/cygwin/pinfo.cc | 10 +++------- winsup/cygwin/sigproc.cc | 12 ++---------- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc index 4bb19464b4..a5f5d6eb22 100644 --- a/winsup/cygwin/pinfo.cc +++ b/winsup/cygwin/pinfo.cc @@ -1262,17 +1262,13 @@ proc_waiter (void *arg) for (;;) { - DWORD nb, err; + DWORD nb; char buf = '\0'; if (!ReadFile (vchild.rd_proc_pipe, &buf, 1, &nb, NULL) - && (err = GetLastError ()) != ERROR_BROKEN_PIPE) + && GetLastError () != ERROR_BROKEN_PIPE) { - /* ERROR_OPERATION_ABORTED is expected due to the possibility that - CancelSynchronousIo interruped the ReadFile call, so don't output - that error */ - if (err != ERROR_OPERATION_ABORTED) - system_printf ("error on read of child wait pipe %p, %E", vchild.rd_proc_pipe); + system_printf ("error on read of child wait pipe %p, %E", vchild.rd_proc_pipe); break; } diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index a6d06a8149..858a7fd12d 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -413,11 +413,7 @@ proc_terminate () to 1 iff it is a Cygwin process. */ if (!have_execed || !have_execed_cygwin) chld_procs[i]->ppid = 1; - /* Attempt to exit the wait_thread cleanly via CancelSynchronousIo - before falling back to the (explicitly dangerous) cross-thread - termination */ - if (chld_procs[i].wait_thread - && !CancelSynchronousIo (chld_procs[i].wait_thread->thread_handle ())) + if (chld_procs[i].wait_thread) chld_procs[i].wait_thread->terminate_thread (); /* Release memory associated with this process unless it is 'myself'. 'myself' is only in the chld_procs table when we've execed. We @@ -1202,11 +1198,7 @@ remove_proc (int ci) { if (have_execed) { - /* Attempt to exit the wait_thread cleanly via CancelSynchronousIo - before falling back to the (explicitly dangerous) cross-thread - termination */ - if (_my_tls._ctinfo != chld_procs[ci].wait_thread - && !CancelSynchronousIo (chld_procs[ci].wait_thread->thread_handle ())) + if (_my_tls._ctinfo != chld_procs[ci].wait_thread) chld_procs[ci].wait_thread->terminate_thread (); } else if (chld_procs[ci] && chld_procs[ci]->exists ()) From 7f3ae80791561c7dbed811e6e316d40ee9af3406 Mon Sep 17 00:00:00 2001 From: Jeremy Drake Date: Wed, 27 Nov 2024 11:22:49 -0800 Subject: [PATCH 48/50] Cygwin: cache IsWow64Process2 host arch in wincap. This was already used in the FAST_CWD check, and could be used in a couple other places. I found the "emulated"/process value returned from the function largely useless, so I did not cache it. It is useless because, as the docs say, it is set to IMAGE_FILE_MACHINE_UNKNOWN (0) if the process is not running under WOW64, but Microsoft also doesn't consider x64-on-ARM64 to be WOW64, so it is set to 0 regardless if the process is ARM64 or x64. You can tell the difference via GetProcessInformation(ProcessMachineTypeInfo), but for the current process even that's overkill: what we really want to know is the IMAGE_FILE_MACHINE_* constant for the Cygwin dll itself, which is conveniently located in memory already, so cache that in wincap also for easy comparisons. Signed-off-by: Jeremy Drake (cherry picked from commit 46f7bcc1e575826f6d3e4a5770ae61423d9be5a9) --- winsup/cygwin/local_includes/wincap.h | 4 ++++ winsup/cygwin/path.cc | 6 ++---- winsup/cygwin/wincap.cc | 19 +++++++++++++++++++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/winsup/cygwin/local_includes/wincap.h b/winsup/cygwin/local_includes/wincap.h index c14872787c..250866f061 100644 --- a/winsup/cygwin/local_includes/wincap.h +++ b/winsup/cygwin/local_includes/wincap.h @@ -42,6 +42,8 @@ class wincapc RTL_OSVERSIONINFOEXW version; char osnam[40]; const void *caps; + USHORT host_mach; + USHORT cygwin_mach; bool _is_server; public: @@ -61,6 +63,8 @@ class wincapc { return (size_t) system_info.dwAllocationGranularity; } const char *osname () const { return osnam; } const DWORD build_number () const { return version.dwBuildNumber; } + const USHORT host_machine () const { return host_mach; } + const USHORT cygwin_machine () const { return cygwin_mach; } #define IMPLEMENT(cap) cap() const { return ((wincaps *) this->caps)->cap; } diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 1021005d7f..b634c40b15 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -4828,14 +4828,12 @@ find_fast_cwd_pointer () static fcwd_access_t ** find_fast_cwd () { - USHORT emulated, hosted; fcwd_access_t **f_cwd_ptr; - /* First check if we're running in WOW64 on ARM64 emulating AMD64. Skip + /* First check if we're running on an ARM64 system. Skip fetching FAST_CWD pointer as long as there's no solution for finding it on that system. */ - if (IsWow64Process2 (GetCurrentProcess (), &emulated, &hosted) - && hosted == IMAGE_FILE_MACHINE_ARM64) + if (wincap.host_machine () == IMAGE_FILE_MACHINE_ARM64) return NULL; /* Fetch the pointer but don't set the global fast_cwd_ptr yet. First diff --git a/winsup/cygwin/wincap.cc b/winsup/cygwin/wincap.cc index 30d9c14e8d..deecf8ba51 100644 --- a/winsup/cygwin/wincap.cc +++ b/winsup/cygwin/wincap.cc @@ -235,9 +235,15 @@ static const wincaps wincap_11 = { wincapc wincap __attribute__((section (".cygwin_dll_common"), shared)); +extern IMAGE_DOS_HEADER +__image_base__; + void wincapc::init () { + PIMAGE_NT_HEADERS ntheader; + USHORT emul_mach; + if (caps) return; // already initialized @@ -282,4 +288,17 @@ wincapc::init () __small_sprintf (osnam, "NT-%d.%d", version.dwMajorVersion, version.dwMinorVersion); + + if (!IsWow64Process2 (GetCurrentProcess (), &emul_mach, &host_mach)) + { + /* If IsWow64Process2 succeeded, it filled in host_mach. Assume the only + way it fails for the current process is that we're running on an OS + version where it's not implemented yet. As such, the only realistic + option for host_mach is AMD64 */ + host_mach = IMAGE_FILE_MACHINE_AMD64; + } + + ntheader = (PIMAGE_NT_HEADERS)((LPBYTE) &__image_base__ + + __image_base__.e_lfanew); + cygwin_mach = ntheader->FileHeader.Machine; } From 7da06fd0ea09d64f1c15adc18c0e6274a22cf41b Mon Sep 17 00:00:00 2001 From: Jeremy Drake Date: Wed, 27 Nov 2024 11:26:50 -0800 Subject: [PATCH 49/50] Cygwin: uname: add host machine tag to sysname. If the Cygwin dll's architecture is different from the host system's architecture, append an additional tag that indicates the host system architecture (the Cygwin dll's architecture is already indicated in machine). Signed-off-by: Jeremy Drake (cherry picked from commit 7923059bff6c120c6fb74b63c7553ea345c0a8f3) --- winsup/cygwin/uname.cc | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/winsup/cygwin/uname.cc b/winsup/cygwin/uname.cc index a978363f1c..ba73edda43 100644 --- a/winsup/cygwin/uname.cc +++ b/winsup/cygwin/uname.cc @@ -51,13 +51,27 @@ uname_x (struct utsname *name) __try { char buf[NI_MAXHOST + 1] ATTRIBUTE_NONSTRING; + int n; memset (name, 0, sizeof (*name)); /* sysname */ const char* sysname = get_sysname(); - __small_sprintf (name->sysname, "%s_%s-%u", - sysname, - wincap.osname (), wincap.build_number ()); + n = __small_sprintf (name->sysname, "%s_%s-%u", + sysname, + wincap.osname (), wincap.build_number ()); + if (wincap.host_machine () != wincap.cygwin_machine ()) + { + switch (wincap.host_machine ()) + { + case IMAGE_FILE_MACHINE_ARM64: + n = stpcpy (name->sysname + n, "-ARM64") - name->sysname; + break; + default: + n += __small_sprintf (name->sysname + n, "-%04y", + (int) wincap.host_machine ()); + break; + } + } /* nodename */ memset (buf, 0, sizeof buf); cygwin_gethostname (buf, sizeof buf - 1); From 2c0e426da70f161af3776ffaa3559498b81c9df4 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 27 Jan 2025 20:49:14 +0100 Subject: [PATCH 50/50] fixup! Instead of creating Cygwin symlinks, use deep copy by default In Cygwin v3.5.6, the `isdevice()` method was dropped, and the commit message of 002aad0410 (Cygwin: path_conv: simplify, rearrange, rename combined device checks, 2025-01-21), which is the commit that dropped it, explains: Drop the isdevice() check in favor of a new isondisk() check. On the face of it, the message is clear: we should use `isondisk()` instead of `isdevice()`. As it turns out, MSYS2's code that pretends to create a symbolic link upon `ln -s` but instead makes a deep copy used to call `isdevice()`: if (!src_path.isdevice () && !src_path.is_fs_special ()) // do a deep copy and return // otherwise fall back to creating a sysfile link A deep dive into the issue reveals that in this instance, the condition is actually equivalent to: if (!src_path.isspecial() || (src_path.isfifo() && !src_path.isondisk())) Further study (by trying it out) reveals that replacing this condition with `src_path.isondisk()` fails to produce the expected result. Here is the expected result, which we receive whether we use MSYS2 runtime v3.5.5 or the version with `src_path.isspecial()`: $ mknod foo c 1 3 $ ln -s foo foolnk $ ls -l foo* crw-rw-rw- 1 x None 1, 3 Jan 27 10:43 foo lrwxrwxrwx 1 x None 3 Jan 27 10:43 foolnk -> foo and with `isondisk()`, this happens instead: $ mknod foo c 1 3 $ ln -s foo foolnk $ ls -l foo* crw-rw-rw- 1 x None 1, 3 Jan 27 10:41 foo -r--r--r-- 1 x None 126 Jan 27 10:41 foolnk Further experimentation reveals that FIFOs are handled without bothering with the `isfifo() && !isondisk()` condition, merely testing `!isspecial()` is enough (and recapitulates the behavior of v3.5.5): $ mkfifo fifo $ ln -s fifo fifolnk $ ls -l fifo fifolnk prw-rw-rw- 1 None 0 Jan 27 20:44 fifo lrwxrwxrwx 1 None 4 Jan 27 20:44 fifolnk -> fifo Therefore, let's just go with the sweet-and-simple `!isspecial()`. This commit will live un-autosquashed in the `msys2-3.5.6` branch to allow for all of the above to be documented in the commit history. Helped-by: Jeremy Drake Signed-off-by: Johannes Schindelin --- winsup/cygwin/path.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index b634c40b15..c49025a73e 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -2320,7 +2320,7 @@ symlink_worker (const char *oldpath, path_conv &win32_newpath, bool isdevice) set_errno (src_path.error); __leave; } - if (!src_path.isdevice () && !src_path.is_fs_special ()) + if (!src_path.isspecial ()) { /* MSYS copy file instead make symlink */