From 1fd5e000ace55b323124c7e556a7a864b972a5c4 Mon Sep 17 00:00:00 2001 From: Christopher Faylor Date: Thu, 17 Feb 2000 19:38:33 +0000 Subject: import winsup-2000-02-17 snapshot --- winsup/cygwin/CYGWIN_LICENSE | 46 + winsup/cygwin/ChangeLog | 229 ++ winsup/cygwin/ChangeLog-1995 | 177 ++ winsup/cygwin/ChangeLog-1996 | 2031 +++++++++++++ winsup/cygwin/ChangeLog-1997 | 2800 ++++++++++++++++++ winsup/cygwin/ChangeLog-1998 | 4490 +++++++++++++++++++++++++++++ winsup/cygwin/ChangeLog-1999 | 3552 +++++++++++++++++++++++ winsup/cygwin/Makefile.in | 341 +++ winsup/cygwin/ROADMAP | 129 + winsup/cygwin/acconfig.h | 15 + winsup/cygwin/ansi.sgml | 59 + winsup/cygwin/assert.cc | 50 + winsup/cygwin/config.h.in | 38 + winsup/cygwin/config/i386/longjmp.c | 51 + winsup/cygwin/config/i386/makefrag | 17 + winsup/cygwin/config/i386/profile.h | 58 + winsup/cygwin/config/i386/setjmp.c | 48 + winsup/cygwin/configure | 2335 +++++++++++++++ winsup/cygwin/configure.in | 229 ++ winsup/cygwin/cygwin.din | 1051 +++++++ winsup/cygwin/dcrt0.cc | 1063 +++++++ winsup/cygwin/debug.cc | 326 +++ winsup/cygwin/debug.h | 69 + winsup/cygwin/delqueue.cc | 99 + winsup/cygwin/dir.cc | 340 +++ winsup/cygwin/dlfcn.cc | 236 ++ winsup/cygwin/dll_init.cc | 499 ++++ winsup/cygwin/dll_init.h | 102 + winsup/cygwin/dll_init.sgml | 11 + winsup/cygwin/dtable.cc | 603 ++++ winsup/cygwin/dtable.sgml | 20 + winsup/cygwin/environ.cc | 567 ++++ winsup/cygwin/errno.cc | 669 +++++ winsup/cygwin/exceptions.cc | 1066 +++++++ winsup/cygwin/exec.cc | 204 ++ winsup/cygwin/external.cc | 107 + winsup/cygwin/external.sgml | 16 + winsup/cygwin/fcntl.cc | 106 + winsup/cygwin/fhandler.cc | 1501 ++++++++++ winsup/cygwin/fhandler.h | 804 ++++++ winsup/cygwin/fhandler_console.cc | 1387 +++++++++ winsup/cygwin/fhandler_floppy.cc | 90 + winsup/cygwin/fhandler_raw.cc | 495 ++++ winsup/cygwin/fhandler_serial.cc | 883 ++++++ winsup/cygwin/fhandler_tape.cc | 829 ++++++ winsup/cygwin/fhandler_termios.cc | 293 ++ winsup/cygwin/fhandler_tty.cc | 1070 +++++++ winsup/cygwin/fhandler_windows.cc | 145 + winsup/cygwin/fhandler_zero.cc | 58 + winsup/cygwin/fork.cc | 625 ++++ winsup/cygwin/gcrt0.c | 41 + winsup/cygwin/glob.c | 871 ++++++ winsup/cygwin/gmon.c | 277 ++ winsup/cygwin/gmon.h | 166 ++ winsup/cygwin/grp.cc | 283 ++ winsup/cygwin/heap.cc | 140 + winsup/cygwin/include/a.out.h | 421 +++ winsup/cygwin/include/arpa/ftp.h | 109 + winsup/cygwin/include/arpa/inet.h | 25 + winsup/cygwin/include/arpa/telnet.h | 322 +++ winsup/cygwin/include/asm/byteorder.h | 93 + winsup/cygwin/include/asm/socket.h | 58 + winsup/cygwin/include/asm/types.h | 13 + winsup/cygwin/include/cygwin/acl.h | 81 + winsup/cygwin/include/cygwin/cygwin_dll.h | 96 + winsup/cygwin/include/cygwin/icmp.h | 1 + winsup/cygwin/include/cygwin/if.h | 74 + winsup/cygwin/include/cygwin/in.h | 188 ++ winsup/cygwin/include/cygwin/mtio.h | 190 ++ winsup/cygwin/include/cygwin/rdevio.h | 30 + winsup/cygwin/include/cygwin/socket.h | 152 + winsup/cygwin/include/cygwin/sockios.h | 1 + winsup/cygwin/include/cygwin/types.h | 1 + winsup/cygwin/include/cygwin/uio.h | 1 + winsup/cygwin/include/cygwin/version.h | 159 + winsup/cygwin/include/dlfcn.h | 41 + winsup/cygwin/include/exceptions.h | 120 + winsup/cygwin/include/fcntl.h | 7 + winsup/cygwin/include/features.h | 1 + winsup/cygwin/include/getopt.h | 66 + winsup/cygwin/include/glob.h | 111 + winsup/cygwin/include/icmp.h | 1 + winsup/cygwin/include/io.h | 28 + winsup/cygwin/include/lastlog.h | 12 + winsup/cygwin/include/limits.h | 144 + winsup/cygwin/include/mapi.h | 102 + winsup/cygwin/include/memory.h | 7 + winsup/cygwin/include/mntent.h | 35 + winsup/cygwin/include/net/if.h | 6 + winsup/cygwin/include/netdb.h | 167 ++ winsup/cygwin/include/netinet/in.h | 6 + winsup/cygwin/include/netinet/ip.h | 6 + winsup/cygwin/include/netinet/ip_icmp.h | 6 + winsup/cygwin/include/paths.h | 9 + winsup/cygwin/include/pthread.h | 92 + winsup/cygwin/include/strings.h | 6 + winsup/cygwin/include/sys/acl.h | 17 + winsup/cygwin/include/sys/cdefs.h | 12 + winsup/cygwin/include/sys/copying.dj | 41 + winsup/cygwin/include/sys/cygwin.h | 44 + winsup/cygwin/include/sys/file.h | 31 + winsup/cygwin/include/sys/ioctl.h | 20 + winsup/cygwin/include/sys/mman.h | 40 + winsup/cygwin/include/sys/mount.h | 25 + winsup/cygwin/include/sys/mtio.h | 11 + winsup/cygwin/include/sys/resource.h | 40 + winsup/cygwin/include/sys/select.h | 35 + winsup/cygwin/include/sys/smallprint.h | 17 + winsup/cygwin/include/sys/socket.h | 38 + winsup/cygwin/include/sys/strace.h | 96 + winsup/cygwin/include/sys/syslog.h | 73 + winsup/cygwin/include/sys/sysmacros.h | 8 + winsup/cygwin/include/sys/termio.h | 2 + winsup/cygwin/include/sys/termios.h | 295 ++ winsup/cygwin/include/sys/ttychars.h | 1 + winsup/cygwin/include/sys/uio.h | 25 + winsup/cygwin/include/sys/un.h | 16 + winsup/cygwin/include/sys/utsname.h | 23 + winsup/cygwin/include/sys/vfs.h | 28 + winsup/cygwin/include/sys/wait.h | 63 + winsup/cygwin/include/syslog.h | 6 + winsup/cygwin/include/termio.h | 6 + winsup/cygwin/include/tzfile.h | 10 + winsup/cygwin/init.cc | 58 + winsup/cygwin/ioctl.cc | 44 + winsup/cygwin/malloc_wrapper.cc | 221 ++ winsup/cygwin/mcount.c | 174 ++ winsup/cygwin/misc-std.sgml | 73 + winsup/cygwin/mkvers.sh | 165 ++ winsup/cygwin/mmap.cc | 474 +++ winsup/cygwin/net.cc | 1827 ++++++++++++ winsup/cygwin/ntea.cc | 335 +++ winsup/cygwin/passwd.cc | 275 ++ winsup/cygwin/path.cc | 2836 ++++++++++++++++++ winsup/cygwin/path.h | 98 + winsup/cygwin/path.sgml | 205 ++ winsup/cygwin/pinfo.cc | 413 +++ winsup/cygwin/pipe.cc | 93 + winsup/cygwin/posix.sgml | 88 + winsup/cygwin/profil.c | 173 ++ winsup/cygwin/profil.h | 44 + winsup/cygwin/pthread.cc | 203 ++ winsup/cygwin/regexp/COPYRIGHT | 22 + winsup/cygwin/regexp/README | 84 + winsup/cygwin/regexp/regexp.h | 24 + winsup/cygwin/regexp/regmagic.h | 7 + winsup/cygwin/registry.cc | 176 ++ winsup/cygwin/resource.cc | 94 + winsup/cygwin/scandir.cc | 101 + winsup/cygwin/security.cc | 2084 +++++++++++++ winsup/cygwin/select.cc | 1380 +++++++++ winsup/cygwin/select.h | 56 + winsup/cygwin/shared.cc | 287 ++ winsup/cygwin/shared.sgml | 17 + winsup/cygwin/signal.cc | 367 +++ winsup/cygwin/sigproc.cc | 1345 +++++++++ winsup/cygwin/sigproc.h | 66 + winsup/cygwin/smallprint.c | 229 ++ winsup/cygwin/spawn.cc | 980 +++++++ winsup/cygwin/strace.cc | 409 +++ winsup/cygwin/strsep.cc | 65 + winsup/cygwin/sync.cc | 112 + winsup/cygwin/sync.h | 48 + winsup/cygwin/syscalls.cc | 1939 +++++++++++++ winsup/cygwin/sysconf.cc | 62 + winsup/cygwin/syslog.cc | 395 +++ winsup/cygwin/termios.cc | 274 ++ winsup/cygwin/thread.cc | 1001 +++++++ winsup/cygwin/thread.h | 312 ++ winsup/cygwin/times.cc | 540 ++++ winsup/cygwin/tty.cc | 417 +++ winsup/cygwin/tz_posixrules.h | 48 + winsup/cygwin/uinfo.cc | 200 ++ winsup/cygwin/uname.cc | 110 + winsup/cygwin/wait.cc | 113 + winsup/cygwin/window.cc | 231 ++ winsup/cygwin/winsup.h | 595 ++++ winsup/cygwin/winver.rc | 53 + 178 files changed, 59860 insertions(+) create mode 100644 winsup/cygwin/CYGWIN_LICENSE create mode 100644 winsup/cygwin/ChangeLog create mode 100644 winsup/cygwin/ChangeLog-1995 create mode 100644 winsup/cygwin/ChangeLog-1996 create mode 100644 winsup/cygwin/ChangeLog-1997 create mode 100644 winsup/cygwin/ChangeLog-1998 create mode 100644 winsup/cygwin/ChangeLog-1999 create mode 100644 winsup/cygwin/Makefile.in create mode 100644 winsup/cygwin/ROADMAP create mode 100644 winsup/cygwin/acconfig.h create mode 100644 winsup/cygwin/ansi.sgml create mode 100644 winsup/cygwin/assert.cc create mode 100644 winsup/cygwin/config.h.in create mode 100644 winsup/cygwin/config/i386/longjmp.c create mode 100644 winsup/cygwin/config/i386/makefrag create mode 100644 winsup/cygwin/config/i386/profile.h create mode 100644 winsup/cygwin/config/i386/setjmp.c create mode 100755 winsup/cygwin/configure create mode 100644 winsup/cygwin/configure.in create mode 100644 winsup/cygwin/cygwin.din create mode 100644 winsup/cygwin/dcrt0.cc create mode 100644 winsup/cygwin/debug.cc create mode 100644 winsup/cygwin/debug.h create mode 100644 winsup/cygwin/delqueue.cc create mode 100644 winsup/cygwin/dir.cc create mode 100644 winsup/cygwin/dlfcn.cc create mode 100644 winsup/cygwin/dll_init.cc create mode 100644 winsup/cygwin/dll_init.h create mode 100644 winsup/cygwin/dll_init.sgml create mode 100644 winsup/cygwin/dtable.cc create mode 100644 winsup/cygwin/dtable.sgml create mode 100644 winsup/cygwin/environ.cc create mode 100644 winsup/cygwin/errno.cc create mode 100644 winsup/cygwin/exceptions.cc create mode 100644 winsup/cygwin/exec.cc create mode 100644 winsup/cygwin/external.cc create mode 100644 winsup/cygwin/external.sgml create mode 100644 winsup/cygwin/fcntl.cc create mode 100644 winsup/cygwin/fhandler.cc create mode 100644 winsup/cygwin/fhandler.h create mode 100644 winsup/cygwin/fhandler_console.cc create mode 100644 winsup/cygwin/fhandler_floppy.cc create mode 100644 winsup/cygwin/fhandler_raw.cc create mode 100644 winsup/cygwin/fhandler_serial.cc create mode 100644 winsup/cygwin/fhandler_tape.cc create mode 100644 winsup/cygwin/fhandler_termios.cc create mode 100644 winsup/cygwin/fhandler_tty.cc create mode 100644 winsup/cygwin/fhandler_windows.cc create mode 100644 winsup/cygwin/fhandler_zero.cc create mode 100644 winsup/cygwin/fork.cc create mode 100644 winsup/cygwin/gcrt0.c create mode 100644 winsup/cygwin/glob.c create mode 100644 winsup/cygwin/gmon.c create mode 100644 winsup/cygwin/gmon.h create mode 100644 winsup/cygwin/grp.cc create mode 100644 winsup/cygwin/heap.cc create mode 100644 winsup/cygwin/include/a.out.h create mode 100644 winsup/cygwin/include/arpa/ftp.h create mode 100644 winsup/cygwin/include/arpa/inet.h create mode 100644 winsup/cygwin/include/arpa/telnet.h create mode 100644 winsup/cygwin/include/asm/byteorder.h create mode 100644 winsup/cygwin/include/asm/socket.h create mode 100644 winsup/cygwin/include/asm/types.h create mode 100644 winsup/cygwin/include/cygwin/acl.h create mode 100644 winsup/cygwin/include/cygwin/cygwin_dll.h create mode 100644 winsup/cygwin/include/cygwin/icmp.h create mode 100644 winsup/cygwin/include/cygwin/if.h create mode 100644 winsup/cygwin/include/cygwin/in.h create mode 100644 winsup/cygwin/include/cygwin/mtio.h create mode 100644 winsup/cygwin/include/cygwin/rdevio.h create mode 100644 winsup/cygwin/include/cygwin/socket.h create mode 100644 winsup/cygwin/include/cygwin/sockios.h create mode 100644 winsup/cygwin/include/cygwin/types.h create mode 100644 winsup/cygwin/include/cygwin/uio.h create mode 100644 winsup/cygwin/include/cygwin/version.h create mode 100644 winsup/cygwin/include/dlfcn.h create mode 100644 winsup/cygwin/include/exceptions.h create mode 100644 winsup/cygwin/include/fcntl.h create mode 100644 winsup/cygwin/include/features.h create mode 100644 winsup/cygwin/include/getopt.h create mode 100644 winsup/cygwin/include/glob.h create mode 100644 winsup/cygwin/include/icmp.h create mode 100644 winsup/cygwin/include/io.h create mode 100644 winsup/cygwin/include/lastlog.h create mode 100644 winsup/cygwin/include/limits.h create mode 100644 winsup/cygwin/include/mapi.h create mode 100644 winsup/cygwin/include/memory.h create mode 100644 winsup/cygwin/include/mntent.h create mode 100644 winsup/cygwin/include/net/if.h create mode 100644 winsup/cygwin/include/netdb.h create mode 100644 winsup/cygwin/include/netinet/in.h create mode 100644 winsup/cygwin/include/netinet/ip.h create mode 100644 winsup/cygwin/include/netinet/ip_icmp.h create mode 100644 winsup/cygwin/include/paths.h create mode 100644 winsup/cygwin/include/pthread.h create mode 100644 winsup/cygwin/include/strings.h create mode 100644 winsup/cygwin/include/sys/acl.h create mode 100644 winsup/cygwin/include/sys/cdefs.h create mode 100644 winsup/cygwin/include/sys/copying.dj create mode 100644 winsup/cygwin/include/sys/cygwin.h create mode 100644 winsup/cygwin/include/sys/file.h create mode 100644 winsup/cygwin/include/sys/ioctl.h create mode 100644 winsup/cygwin/include/sys/mman.h create mode 100644 winsup/cygwin/include/sys/mount.h create mode 100644 winsup/cygwin/include/sys/mtio.h create mode 100644 winsup/cygwin/include/sys/resource.h create mode 100644 winsup/cygwin/include/sys/select.h create mode 100644 winsup/cygwin/include/sys/smallprint.h create mode 100644 winsup/cygwin/include/sys/socket.h create mode 100644 winsup/cygwin/include/sys/strace.h create mode 100644 winsup/cygwin/include/sys/syslog.h create mode 100644 winsup/cygwin/include/sys/sysmacros.h create mode 100644 winsup/cygwin/include/sys/termio.h create mode 100644 winsup/cygwin/include/sys/termios.h create mode 100644 winsup/cygwin/include/sys/ttychars.h create mode 100644 winsup/cygwin/include/sys/uio.h create mode 100644 winsup/cygwin/include/sys/un.h create mode 100644 winsup/cygwin/include/sys/utsname.h create mode 100644 winsup/cygwin/include/sys/vfs.h create mode 100644 winsup/cygwin/include/sys/wait.h create mode 100644 winsup/cygwin/include/syslog.h create mode 100644 winsup/cygwin/include/termio.h create mode 100644 winsup/cygwin/include/tzfile.h create mode 100644 winsup/cygwin/init.cc create mode 100644 winsup/cygwin/ioctl.cc create mode 100644 winsup/cygwin/malloc_wrapper.cc create mode 100644 winsup/cygwin/mcount.c create mode 100644 winsup/cygwin/misc-std.sgml create mode 100755 winsup/cygwin/mkvers.sh create mode 100644 winsup/cygwin/mmap.cc create mode 100644 winsup/cygwin/net.cc create mode 100644 winsup/cygwin/ntea.cc create mode 100644 winsup/cygwin/passwd.cc create mode 100644 winsup/cygwin/path.cc create mode 100644 winsup/cygwin/path.h create mode 100644 winsup/cygwin/path.sgml create mode 100644 winsup/cygwin/pinfo.cc create mode 100644 winsup/cygwin/pipe.cc create mode 100644 winsup/cygwin/posix.sgml create mode 100644 winsup/cygwin/profil.c create mode 100644 winsup/cygwin/profil.h create mode 100644 winsup/cygwin/pthread.cc create mode 100644 winsup/cygwin/regexp/COPYRIGHT create mode 100644 winsup/cygwin/regexp/README create mode 100644 winsup/cygwin/regexp/regexp.h create mode 100644 winsup/cygwin/regexp/regmagic.h create mode 100644 winsup/cygwin/registry.cc create mode 100644 winsup/cygwin/resource.cc create mode 100644 winsup/cygwin/scandir.cc create mode 100644 winsup/cygwin/security.cc create mode 100644 winsup/cygwin/select.cc create mode 100644 winsup/cygwin/select.h create mode 100644 winsup/cygwin/shared.cc create mode 100644 winsup/cygwin/shared.sgml create mode 100644 winsup/cygwin/signal.cc create mode 100644 winsup/cygwin/sigproc.cc create mode 100644 winsup/cygwin/sigproc.h create mode 100644 winsup/cygwin/smallprint.c create mode 100644 winsup/cygwin/spawn.cc create mode 100644 winsup/cygwin/strace.cc create mode 100644 winsup/cygwin/strsep.cc create mode 100644 winsup/cygwin/sync.cc create mode 100644 winsup/cygwin/sync.h create mode 100644 winsup/cygwin/syscalls.cc create mode 100644 winsup/cygwin/sysconf.cc create mode 100644 winsup/cygwin/syslog.cc create mode 100644 winsup/cygwin/termios.cc create mode 100644 winsup/cygwin/thread.cc create mode 100644 winsup/cygwin/thread.h create mode 100644 winsup/cygwin/times.cc create mode 100644 winsup/cygwin/tty.cc create mode 100644 winsup/cygwin/tz_posixrules.h create mode 100644 winsup/cygwin/uinfo.cc create mode 100644 winsup/cygwin/uname.cc create mode 100644 winsup/cygwin/wait.cc create mode 100644 winsup/cygwin/window.cc create mode 100644 winsup/cygwin/winsup.h create mode 100644 winsup/cygwin/winver.rc (limited to 'winsup/cygwin') diff --git a/winsup/cygwin/CYGWIN_LICENSE b/winsup/cygwin/CYGWIN_LICENSE new file mode 100644 index 000000000..f10b01f56 --- /dev/null +++ b/winsup/cygwin/CYGWIN_LICENSE @@ -0,0 +1,46 @@ +-------------------------------------------------------------------------- +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License (GPL) as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +-------------------------------------------------------------------------- + + *** NOTE *** + +In accordance with section 10 of the GPL, Cygnus permits programs whose +sources are distributed under a license that complies with the Open +Source definition to be linked with libcygwin.a without libcygwin.a +itself causing the resulting program to be covered by the GNU GPL. + +This means that you can port an Open Source(tm) application to cygwin, +and distribute that executable as if it didn't include a copy of +libcygwin.a linked into it. Note that this does not apply to the cygwin +DLL itself. If you distribute a (possibly modified) version of the DLL +you must adhere to the terms of the GPL, i.e., you must provide sources +for the cygwin DLL. + +See http://www.opensource.org/osd.html for the precise Open Source +Definition referenced above. + +If you have questions about any of the above or would like to arrange +for other licensing terms, please contact Cygnus using the information +given below: + + Cygnus Solutions + 1325 Chesapeake Terrace + Sunnyvale, CA 94089 + USA + + +1 408 542 9600 + hotline: +1 408 542 9601 + email: info@cygnus.com + fax: +1 408 542 9699 diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog new file mode 100644 index 000000000..70651d065 --- /dev/null +++ b/winsup/cygwin/ChangeLog @@ -0,0 +1,229 @@ +Mon Feb 7 16:50:44 2000 Christopher Faylor + + * Makefile.in: cygrun needs libshell32.a. + +Sun Feb 6 22:17:58 2000 Christopher Faylor + + * sigproc.cc (proc_subproc): Simplify case for when a child process is + stopped since new signal handler ensures the desired behavior. + +Sun Feb 6 21:52:33 2000 Christopher Faylor + + * Makefile.in: Fix install target so that directories will be created + when necessary. + +Sun Feb 6 18:12:17 2000 Christopher Faylor + + * Makefile.in: exceptions.cc should depend on autoload.h. + * exceptions.cc: Undef DECLSPEC_IMPORT prior to including imagehlp.h to + avoid defining StackWalk as "import". + (call_handler): Minor optimizations. + (sig_handle_tty_stop): Fix typo in previous checkin. + * sigproc.cc (sigproc_init): Ditto, for signal_arrived initialization. + +Sat Feb 5 15:37:37 2000 Christopher Faylor + + * dcrt0.cc (isquote): Convert to inline function. + +Sat Feb 5 00:26:01 2000 Christopher Faylor + + Throughout, rename global_signal_arrived to signal_arrived. + Throughout, eliminate use of arm_signals and __signal_arrived. + Throughout, revert to use of simple call to WaitForSingleObject or + WaitForMultipleObjects. + * debug.h: Eliminate obsolete function declaration. + * exceptions.cc (sigWaitForSingleObject): Eliminate obsolete function + definition. + * fhandler.h: Reflect change to select_stuff wait method. + * fhandler_tape.cc (get_ll): Accomodate new w32api LARGE_INTEGER + definition. + * ntea.c (NTReadEARaw): Ditto. + (NTWriteEA): Ditto. + * security.cc (ReadSD): Ditto. + (WriteSD): Ditto. + * syscalls.cc (_link): Ditto. + * uname.cc (uname): Eliminate PPC switch. + +2000-02-01 Salvador Eduardo Tropea + + * include/io.h: add return type to setmode() + +2000-01-27 DJ Delorie + + * include/netdb.h (h_errno): change __imp_ to dllimport + * cygwin.din (reent_data): add DATA + +Thu Jan 27 01:07:14 2000 Christopher Faylor + + * exceptions.cc (call_handler): Add debugging output. + * select.cc (MAKEready): Arm signals earlier. + * sigproc.cc (__signal_arrived:arm): Move debugging version of this + method here. + (__signal_arrived::release): Ditto. + * sigproc.h: Recognize debugging versions of above two methods. + (arm_signals::WaitForMultipleObjects): Don't release signal lock unless + signal arrived. + (arm_signals::WaitForMultipleSingleObject): Ditto. + (arm_signals::MsgWaitForMultipleObjects): Ditto. + +Thu Jan 27 00:19:26 2000 Christopher Faylor + + * sync.h (new_muto): Workaround change in gcc behavior. + +Wed Jan 26 12:57:13 2000 Christopher Faylor + + * Makefile.in: Ensure that all required libraries are built prior + to linking cygrun.exe. + +Tue Jan 25 21:26:57 2000 Christopher Faylor + + * exceptions.cc (sig_handle): Crudely work around potential problem + when main thread has a lock but is killed by a fatal signal. + * fhandler_tty.cc (fhandler_pty_master::write): Don't perform line + editing on the pty master (so why do we need the second argument to + line_edit, then?) + * thread.cc: Reformat to GNU standards. + +2000-01-11 DJ Delorie + + * ROADMAP: new + +2000-01-11 DJ Delorie + + * fhandler_zero.cc: new, emulate /dev/zero + * testsuite/winsup.api/devzero.c: new, test /dev/zero + * Makefile.in: build fhandler_zero.o + * fhandler.h: add support for /dev/zero + * hinfo.cc: ditto + * path.cc: ditto + +2000-01-11 DJ Delorie + + * mmap.cc (mmap): MSDN says *one* of FILE_MAP_*, fix flags for + MAP_PRIVATE. + +Mon Jan 10 01:11:00 2000 Corinna Vinschen + + * security.cc (acl_access): New function. + * syscalls.cc (access): Call acl_access if ntsec is on. + +Mon Jan 10 01:11:00 2000 Corinna Vinschen + + * fhandler.cc (get_file_owner): Use of ReadSD() instead of + GetFileSecurity(). + (get_file_group): Ditto. + +Sun Jan 9 15:43:07 2000 Christopher Faylor + + * debug.cc (struct thread_start): Add a flag to determine whether a + field is in use. Eliminate thread_start_ix since it was not + thread-safe. + (thread_stub): Use notavail flag to control whether the entry in + start_buf can be reused. + (makethread): Ditto. + +Sun Jan 9 20:18:00 2000 Corinna Vinschen + + * security.cc (alloc_sd): Rearrange order of ACE creation. + (setacl): Optimize creation of ACEs related to inheritance. Code + cleanup. + (aclcheck): Disable check for existance of DEF_)CLASS_OBJ. + +Sat Jan 8 18:42:32 2000 Christopher Faylor + + * mkvers.h: Reorg fix. + +Sat Jan 8 20:00:00 2000 Corinna Vinschen + + * cygwin.din: Add new acl API calls. + * grp.cc (getgroups): Change to work for any username. + * security.cc (get_id_from_sid): Change to work with acl API. + (is_grp_member): New function. + (get_nt_attribute): Rewritten. + (add_access_allowed_ace): New function. + (add_access_denied_ace): Ditto. + (alloc_sd): Rewritten. + (setacl): New function. + (getace): Ditto. + (searchace): Ditto. + (getacl): Ditto. + (acl): Ditto. + (facl): Ditto. + (aclcheck): Ditto. + (acecmp): Ditto. + (aclsort): Ditto. + (acltomode): Ditto. + (aclfrommode): Ditto. + (acltopbits): Ditto. + (aclfrompbits): Ditto. + (permtostr): Ditto. + (acltotext): Ditto. + (permfromstr): Ditto. + (aclfromtext): Ditto. + * syscalls.cc (access): Set errno again when needed. + * include/cygwin/acl.h: New file. + * include/sys/acl.h: Ditto. + +Sat Jan 8 14:46:19 2000 Christopher Faylor + + * Makefile.in: Add cygwin DLL specific CFLAGS define. + +Fri Jan 7 21:01:57 2000 Christopher Faylor + + * exceptions.cc (interrupt_on_return): Properly coerce assignment of + sigsave.func. + +2000-01-07 Mumit Khan + + * acconfig.h: New file. + * configure.in Add check for memset builtin. + (AC_CONFIG_HEADER): Use. + (STRACE_HHMMSS): Define instead of substituting. + (_MT_SAFE): Likewise. + (_CYG_THREAD_FAILSAFE): Likewise. + (DEBUGGING): Likewise. + (MT_SAFE): Substitute as a yes/no variable. + * Makefile.in: Remove DEBUGGING, STRACE_HHMMSS, and THREAD_FAILSAFE + variables and add DEFS. Update usage of MT_SAFE to reflect yes/no + values. Add config.h to winsup.h dependency. + (CFLAGS_CONFIG): Update. + (INCLUDES): Prepend `-I.'. + * utils/Makefile.in (INCLUDES): Likewise. + * winsup.h: Conditionally include config.h. + * thread.cc: Likewise. + * config.h.in: Generate new file. + * configure: Regenerate. + + +Fri Jan 7 16:21:01 2000 Christopher Faylor + + * dcrt0.cc (dll_crt0): Allow signal handling for dynamically loaded + case. + +Thu Jan 6 00:30:12 2000 Corinna Vinschen + + * path.cc (symlink_check_one): Initialize local variable `unixattr' + before calling `get_file_attribute'. + * syscalls.cc (chown): Ditto. + * security.cc (get_nt_attribute): Eliminate attribute copying from + world to user/group in case of missing ACEs. + (alloc_sd): Set special rights for administrators group only if it's + neither owner nor group. + * utils/mkpasswd.c: Create entry for local group administrators (SID + 544). + +Thu Jan 6 00:21:31 2000 Christopher Faylor + + Change function calls to __stdcall throughout. + * exceptions.cc (handle_exceptions): Probe stack for return address to + use with new signal method. Fill out sigsave.cx with this information. + (call_handler): Use sigsave.cx if it is available, rather than trying + to find the context of the main thread. + (interrupt_on_return): Use address of context rather than + pass-by-reference. + (interrupt_now): Ditto. + +Thu Jan 6 00:21:31 2000 Corinna Vinschen + + * grp.cc (getgroups): Return supplementary groups now. + * include/limits.h: Define NGROUP_MAX as 16 now. diff --git a/winsup/cygwin/ChangeLog-1995 b/winsup/cygwin/ChangeLog-1995 new file mode 100644 index 000000000..462a61336 --- /dev/null +++ b/winsup/cygwin/ChangeLog-1995 @@ -0,0 +1,177 @@ +Mon Dec 18 16:44:38 1995 Jason Molenda (crash@phydeaux.cygnus.com) + + * configure.in (target_cpu): specify valid Intel x86 architectures + explicitly. + +Mon Dec 18 15:04:29 1995 Jason Molenda (crash@phydeaux.cygnus.com) + + * sysdef/*.def: moved to sysdef/i386/. + +Mon Dec 18 15:00:56 1995 Jason Molenda (crash@phydeaux.cygnus.com) + + * configure.in: Set DLL_ENTRY and SYSDEF_DIR for i386 and powerpc. + * configure: Regenerated with autoconf 2.7. + + * Makefile.in: Use DLL_ENTRY and SYSDEF_DIR. + +Sat Dec 16 18:36:44 1995 steve chamberlain + + Changed the way that file handles are inherited. Now + all files are opened with the inheriting turned on, and they're + closed when necessary. + + Changed the way that children are waited for. Now + you can exec a non-gnuwin32 program and wait for its + result. + + * Makefile.in: Turn off frame-pointer. + * dcrt0.cc (environ_init): Lint. + * dirsearch.cc (opendir): Use new path_conv mechanism. + * exceptions.cc (ctrl_c_handler): Exit with correct status + * exec.cc (file_exists): Moved to paths.cc + (_execve): Moved most of the work into spawn.cc. + * fhandler.cc (*): Much. + * libccrt0.c (foo): Deleted. + (cygwin_crt0): Lint. + * path.cc (readlink): Initialize the SECURITY_ATTRIBUTES struct. + * pipe.cc (pipe, dup*): Reorganized. + * registry.cc (read_in): Create the key in CURRENT_USER. + * wait.cc, spawn.cc (*): Much. + * sysconf.cc (sysconf): Understand SC_PAGESIZE. + * times.cc (utime): New function. + * uname.cc (uname): Dig out more info. + +Wed Dec 13 05:54:55 1995 Michael Meissner + + * dcrt0.cc (environ_init): Cast alloca return to appropriate type. + * spawn.cc (spawn_guts): Ditto. + + * strace.cc (__small_{v,}sprintf): Add appropriate prototypes. + + * exceptions.cc (_except_list): Only use segments for 386 systems. + (__stack_trace): Add PowerPC support, and do nothing for systems + that are not supported except print stack tracing is not yet + support. + + * sdata.cc (import_term): Only use __attribute__((section)) on 386 + systems. + + * shared.cc (shared_init): Use MARK macro instead of calling mark + directly with incorrect type arguments. + + * fhandler.cc (fhandler_dev_null::{read,write}): Use size_t in + prototype, not unsigned int. + + * fork.cc (find_exec): Fix type errors. + * path.cc (path_to_real_path_keep_rel): Ditto. + * syscalls.h (PATH_TO_REAL_PATH): Ditto. + + * {longjmp,setjmp}.c: #ifdef i386 code. + + * include/wintypes.h (ExitProcess): Add + __attribute__((__noreturn__)) so exit compiles without warnings. + +Tue Dec 12 18:25:05 1995 Jason Molenda (crash@phydeaux.cygnus.com) + + * include/wintypes.h (WINAPI): Only define WINAPI for x86 systems. + +Tue Dec 5 16:00:05 1995 Jason Molenda (crash@phydeaux.cygnus.com) + + * Makefile.in (all): Only build documentation for info target. + Expect texi2html to not be found most of the time. + +Tue Dec 5 08:08:08 1995 steve chamberlain + + Release-B10 + + * cygwin.dll (__assert, wait, spawnv, spawnvp): Deleted. + * dcrt0.c: Quoting rewritten. + * exec.cc (file_exists): Use new path_conv mechanism. + (_execve): Close open child process handles. + * fhandler.cc (fhandler_normal::open): Follow symlinks. + (fhandler_normal::read): Keep track of logical file posision. + (fhandler_normal::lseek): Seek in text files correctly. + (fhandler_normal::fstat): Set IFLNK bit if its a symlink. + (fhandler_normal::init): Maintain is_pipe. + (fhandler_dev_null::fstat): New. + (fhandler_dev_null::get_handle): Return INVALID_HANDLE. + * fork.cc: Use new event mechanism. + * libccrt0.cc: Keep track of _fmode variable. + * misc.c (readlink): Delete. + * path.cc (__path_to_real_path_1): Allow /d mechanism. + (path_to_real_path_keep_rel): New + (link_cookie:*): Support for symbolic links. + * spawn.cc (spawn_guts): Quoting rewritten. + * times.cc: New. + * syscalls.cc (_stat_worker): New. + (_stat, _lstat): Use _stat_worker. + * sysconf.cc (sysconf): Support _SC_CLK_TCK. + +Tue Nov 28 15:29:38 1995 steve chamberlain + + * loads of stuff. When I make < 100k of diffs in a day, + the ChangeLog will be usefull. + +Tue Nov 21 18:01:39 1995 steve chamberlain + + * Makefile.in: Build the doc. + * exceptions.cc: lint. + * fork.cc: lint. + * shared.cc (shared_init): If MapViewOfFileEx fails, then try + again, but get the OS to select the address (for win95) + * strace.cc (__sysprintf): Print pid and state in hex. + * syscalls.cc (_unlink): Translate path to realpath. + +Wed Nov 15 23:47:43 1995 Jason Molenda (crash@phydeaux.cygnus.com) + + * spawn.cc (_exit): set return value's lower byte to 0 by default. + + Tue Oct 3 10:23:14 1995 Anders Blomdell (anders.blomdell@control.lth.se) + + * spawn.cc (spawn_guts): quote doublequotes correctly + +Tue Nov 14 15:05:33 1995 Jason Molenda (crash@phydeaux.cygnus.com) + + * configure.in: comment out call to cfg-ml-com.in. + +Tue Oct 31 11:19:18 1995 steve chamberlain + + * libcerr.cc: New file. + * dcrt0.cc (environ_init): Initialize PATH and friends nicely. + * exceptions.cc (ctrl_c_handler): Default case is to exit. + * fork.cc (__suffixy, find_exec): translate between paths and + real_paths. + * shared.cc (shared_init): Hard wire shared memory at 0xa0000000. + * syscalls.c (__path_to_real_path, real_path_to_path): Always + translate '/' <> '\' + +Mon Oct 30 17:36:10 1995 steve chamberlain + + * syscalls.cc (_rename): Fix for win95. + +Fri Oct 27 20:53:47 1995 steve chamberlain + + * Everything changed. + +Thu Oct 19 10:47:52 1995 steve chamberlain + + * registry.cc, uinfo.cc: New files. + * crt0.c (*uinfo*, *_exe_suffix*): Delete. + (dll_crt0): Call shared_init. + * getlogin.c: deleted. + * shared.cc: Fill in. + * spawn.c (_spawn): Use __exe_suffix function. + * syscalls.c (getuid, getgid): Moved into uinfo.cc + * syscalls.h (*uinfo, __exe_suffix): Deleted + * Makefile.in: Cope with target configury. + * termios.c: Fix stub prototypes. + * win.h: Deleted. + * include/winadvapi.h: Fill in some REG prototypes. + +Thu Oct 19 10:47:52 1995 steve chamberlain + + * Makefile.in: Cope with target configury. + +Wed Oct 18 15:34:49 1995 steve chamberlain + + * Moved from newlib. diff --git a/winsup/cygwin/ChangeLog-1996 b/winsup/cygwin/ChangeLog-1996 new file mode 100644 index 000000000..b0c88d97b --- /dev/null +++ b/winsup/cygwin/ChangeLog-1996 @@ -0,0 +1,2031 @@ +Mon Dec 23 13:35:27 1996 Jeremy Allison + + * Makefile.in: Added $(srcdir)/../libstdc++/stl -I$(srcdir)/../libio + to the include path. As mmap uses STL then this is needed + to build the cross compiler. Also added mmap.o file. + * cygwin.din: Added mmap, mprotect, msync, munmap. + * dcrt0.cc: Added code to get the module pathname from + a previously unused field in the u area so fork() calls + don't have to search the path. Forwards compatible with + earlier releases as they set this field to zero. + * fork.cc: Added call to recreate_mmaps_after_fork() in + child code. Ensures child has same view of mmap'ed areas + as parent. + * libccrt0.cc: (See dcrt0.cc change). Setup the module + handle so fork can get the path name. + * mmap.cc: New file. Implements mmap, mprotect, msync, munmap, + recreate_mmaps_after_fork. Uses STL. + * select.cc: Added code to set errno to EINVAL if select done + on handles and sockets. Must fix this soon. + * spawn.cc: Set new variable hmodule in u area to zero for child. + * syscalls.cc: Added fsync functionality. No longer a dummy call. + * winsup.h: Decremented internal_reserved array by one to add + hmodule in u area. Added prototype for recreate_mmaps_after_fork(). + * include/sys/mman.h: Fixed include file for mmap calls. + +Tue Dec 17 16:20:52 1996 Geoffrey Noer + + * syscalls.cc (_rename): fix code so we really do + return -1 if _rename fails. + +Tue Dec 17 12:12:29 1996 Jeremy Allison + + * fhandler.cc: Added Sergeys patch for FakeReadFile. + * cygwin.din: Re-ordered network calls. + +Mon Dec 16 16:47:26 1996 Geoffrey Noer + + * configure.in: remove AC_C_CROSS (now part of AC_PROG_CC) + * utils/configure.in: ditto + * configure: regenerate + * utils/configure: regenerate + +Mon Dec 16 14:50:46 1996 Geoffrey Noer + + * cygwin.din: export cygwin32_getsockopt + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * spawn.cc: don't assume all scripts should be run in + bash -- run the shell specified after the #! + +Fri Dec 13 16:18:22 1996 Jeremy Allison + + * path.cc: Added support for UNC paths. + +Fri Dec 13 10:56:21 1996 Jeremy Allison + + * cygwin.din: Added h_errno, seteuid, _seteuid. + * exceptions.cc: Made init_exceptions extern "C". + * exceptions.h: Added cplusplus wrappers to enable this to + be used from C. + * net.cc: Added error numbers, fixed gethostbyaddr, added h_errno + fixes. + * stubs.cc: Added seteuid. + * include/mywinsock.h: Added HOST error entries for DNS lookups. + +Tue Dec 10 15:38:46 1996 Geoffrey Noer + + * version.h: bump CYGWIN_DLL_VERSION_MINOR to 4 + + patch from Marcus Daniels : + * fhandler.cc: add fhandler_dev_null::dup (fhandler_base *child) + * fhandler.h: add matching header + + gnu-win32 beta 17.1 release made + +Thu Dec 5 14:03:08 1996 Geoffrey Noer + + * select.cc: add missing end comment at about line 933. + gnu-win32 beta 17 release made + +Wed Dec 4 15:53:11 1996 Geoffrey Noer + + * version.h: increment minor dll number in conjunction + with gnu-win32 beta 17 release + +Tue Dec 3 15:05:57 1996 Geoffrey Noer + + * strsep.cc: new file containing Berkeley-copyrighted strsep + code previously in misc.cc. + * misc.cc: strsep moved to strsep.cc, stop including + unistd.h, strings.h, sys/types.h, stddef.h, and stdarg.h + * Makefile.in: appropriate adjustments to add strsep.cc + +Tue Dec 3 13:50:59 1996 Geoffrey Noer + + * include/sys/copying.dj: new file whose presence is + required by include/sys/file.h + +Tue Dec 3 13:37:27 1996 Geoffrey Noer + + Throughout all Cygnus-developped source files: put all + code under GPL + +Tue Dec 3 10:54:01 1996 Jeremy Allison + + * fork.cc: Changed code to delete [] saved child_hinfo + after allocate_pid called. Needed as child changes this + value in the shared area when it de-linearizes fd array. + Needed to stop race condition with earlier fix. + * winsup.h: Changed definition of item in hinfo to be + a char array rather than fhandler_console. Stops + destructor being called when fork delete [] of + hinfo array called. + * hinfo.cc: Changes (casts) to support winsup.h changes. + +Mon Dec 2 17:22:13 1996 Geoffrey Noer + + * include/utime.h: add ifdef _UTIME_U wrapper around header + +Mon Dec 2 15:45:46 1996 Jeremy Allison + + * fork.cc: Fixed file descriptor resource leak in parent. + * registry.cc: Removed fatal error if registry key cannot + be opened. Causes errors in service code. + +Wed Nov 27 15:40:15 1996 Geoffrey Noer + + * cygwin.din: for MS compatibility, also export functions + as _funcname = funcname + * include/netdb: + * include/sys/socket.h: + Do the equivalent thing for functions exported as cygwin32_funcname + +Wed Nov 27 15:14:30 1996 Geoffrey Noer + + * cygwin.din: remove exported helper functions that shouldn't + need to be exported (_read et al) + * glob/Makefile.in: add SHELL definition + * utils/Makefile.in: add SHELL definition + +Mon Nov 25 14:24:52 1996 Geoffrey Noer + + * include/commdlg.h, ddeml.h, winadvapi.h, winbase.h, wincon.h, + windef.h, windowsx.h, winerror.h, wingdi.h, winkernel.h, winnt.h, + wintypes.h, winuser.h, winversion.h: + Add MS-style header files back, each of which now includes our + windows.h. This should allow compilation of Windows code + that expects normal MS-named headers as long as the information + is in our windows.h somewhere. The appropriate wrappers have + been added to each file so windows.h isn't included more than + once. + * include/windows.h: add paranoia wrapper so it can be included + more than once. + +Mon Nov 18 22:19:40 1996 Geoffrey Noer + + * Makefile.in: change rules around so new-cygwin.dll is + only rebuilt when necessary + * spawn.cc: include + +Mon Nov 18 21:08:15 1996 Geoffrey Noer + + * net.cc: remove extern "C"s that shouldn't be there + (get_win95_ifconf, get_winnt_ifconf, get_if_flags) + * syscalls.cc: remove extern "C"s from num_entries, _stat_worker + * winsup.h: add extern "C"s for syscalls protos + +Mon Nov 18 20:35:39 1996 Geoffrey Noer + + * winsup.h: include version.h + * Makefile.in: remove dependencies involving version.h, but add + version.h to winsup.h dependency line and also add others that + should also be there. + * dcrt0.cc: + * libccrt0.cc: + * registry.cc: + * shared.cc: delete includes of version.h + +Mon Nov 18 20:16:37 1996 Geoffrey Noer + + * stubs.c -> stubs.cc, add extern "C"s + * uname.c -> uname.cc, add extern "C"s + * console.cc: add extern "C"s, remove include windows.h + since its already included in winsup.h + * dirsearch.cc: add extern "C"s + * fcntl.cc: add extern "C"s + * winsup.h: remove LEAN_AND_MEAN define since that's no longer + relevant with new windows headers, include version.h + * malloc.cc: fix typos + +Mon Nov 18 18:02:31 1996 Geoffrey Noer + + * grp.c renamed to grp.cc, add extern "C"s + * misc.c renamed to misc.cc, add extern "C"s + +Mon Nov 18 16:08:26 1996 Geoffrey Noer + + * syscalls.cc: extern "C"'d function calls + * net.cc: extern "C"'d function calls, some respacing + * hinfo.cc: extern "C"'d function calls, some respacing + * syscalls.h: removed defines for MIN, errno, alloca(x), + DEFAULT_GID/UID, NOT_OPEN_FD(fd), STD_RBITS et al, + O_NOSYMLINK + * winsup.h: added what was just deleted from syscalls.h + +Mon Nov 18 15:56:22 1996 Jeremy Allison + + * cygwin.din: Added readv + * syscalls.cc: Added readv code. + * syscalls.h: Added readv prototype. + +Wed Nov 13 15:55:14 1996 Geoffrey Noer + + * cygwin.din: added C++-related exports for stuff in + libgcc.a (from new.o, tinfo.o, tinfo2.o, exception.o). + +Mon Nov 11 15:50:26 1996 Geoffrey Noer + + * dcrt0.cc + * dirsearch.cc + * malloc.cc + * passwd.cc + * path.cc, + * pinfo.cc + * syslog.cc + * utils/kill.cc + * utils/cygwin.cc: + need to #include which used to be included + automatically in windows.h included by winsup.h. + * shared.cc: UnmapViewOfFile takes a void *, not a + const void * + * malloc.cc: formatting fixes + +Fri Nov 8 17:31:55 1996 Jeremy Allison + + * select.cc: Added fix for HANDLE select sent by + Sergey Okhapkin. + * fhandler.h: Changed dup to return int. Can now + return error to dup2. + * fhandler.cc: Changed dup to return error code. + Corrected fhandler_console::close to return + error code. + * hinfo.cc (dup2): Check return code from + fhandler->dup. + * times.cc: Changed DST calculation as tm struct + month starts at zero, NT wMonth starts at 1. + * TODO: Added the things i'd like to do. + +Wed Nov 6 17:42:31 1996 Geoffrey Noer + + * Makefile.in: Changed name of base file for cygwin.dll from + base to cygwin.base. Changed name of exp file for cygwin.dll + from win.exp to cygwin.exp. Updated dependency list, removing + recently removed files like libcfork.cc, added missing files, + and added all missing header dependencies. Small formatting + fixes. + +Fri Nov 1 16:38:48 1996 Geoffrey Noer + + * TODO: deleted old stuff from a long time ago, added some + new stuff + + * added public domain disclaimers to all files missing them, + reformatting of non-imported code to conform to GNU standards. + Changes to: + delqueue.h, exceptions.h, fcntl.cc, fhandler.h, grp.c, + init.cc, ioctl.cc, key.cc, libcctype.c, libcerr.cc, libcmain.cc, + misc.c, path.h, pold.c, resource.cc, smallprint.c, strerror.cc, + syslog.cc, termios.cc, test.c, version.h, wait.cc + +Fri Nov 1 14:44:29 1996 Jeremy Allison + + * fhandler.h: Added is_console() method needed by + new select code. + * fhandler.cc (fhandler_console::init): Added c_oflag setting + dependent on bin parameter. + * select.cc: Added code to implement select from console + handles. Ignores keyup events and still blocks. + +Wed Oct 30 16:35:41 1996 Jeremy Allison + + * fhandler.h: Removed fhandler_console_in, fhandler_console_out + and integrated them both into fhandler_console. Added output_handle_ + so fhandler console has two handles. + * fhandler.cc: Updated to support changes in fhandler.h. It is now + possible to open("/dev/tty") and read/write to the same fd. + * hinfo.cc(build_fhandler): Removed references to obsolete classes. + * spawn.cc: Changed to get correct reference to output_handle_ for + fhandler_console class. + * console.cc: Changed to get output handle rather than input handle. + * winsup.h: Changed definition of prototypes for functions changed + in console.cc + +Wed Oct 30 13:05:33 1996 Geoffrey Noer + + * include/custcntl.h + * include/features.h + * include/icmp.h + * include/wchar.h + * include/cygwin32/icmp.h + * include/cygwin32/ip.h + * include/cygwin32/sockios.h + * include/cygwin32/types.h + * include/cygwin32/uio.h + * include/sys/ttychars.h + Added comment with name of header to each so that these are no + longer empty files (some unzip programs won't create + zero-length files which is a problem for headers) + +Sun Oct 27 17:30:03 1996 Geoffrey Noer + + * cygwin.din: also export "_execl = execl" and the same + for _execle and _execlp + +Thu Oct 24 01:43:29 1996 Geoffrey Noer + + * include/windows.h: rewritten to include headers from + the include/Windows32 subdirectory + * winsup.h: no longer define MAX_PATH here since it's defined + in header files dragged in by windows.h + * dirsearch.cc (readdir): change WIN32_FIND_DATAA to WIN32_FIND_DATA + * libccrt0.cc: #include + * syscalls.cc (_unlink): chmod file to be unlinked to be + writable and try to delete it again if first delete failed + with permission denied error (rm will now work on read-only files) + (num_entries): change WIN32_FIND_DATAA to WIN32_FIND_DATA + * include/commdlg.h: delete + * include/ddeml.h: delete + * include/winadvapi.h: delete + * include/winbase.h: delete + * include/wincon.h: delete + * include/windef.h: delete + * include/windowsx.h: delete + * include/winerror.h: delete + * include/wingdi.h: delete + * include/winkernel.h: delete + * include/winnt.h: delete + * include/wintypes.h: delete + * include/winuser.h: delete + * include/winversion.h: delete + +Wed Oct 23 10:43:05 1996 Jeremy Allison + + * dcrt0.cc (api_fatal): Changed locking clear of + process table to unlocking clear. Needed as lock code calls + api_fatal. + * exceptions.cc: Added debug_printfs to follow exceptions in + strace mode. + * pinfo.cc: Added code to ensure fd table is cleared when new + pid entry allocated. Fixed bug when process is terminated + violently by TerminateProcess and leaves fd table non-zero. + * termios.cc: Changed stubbed out syscalls to syscall_printf + rather than small_printf. Stops annoying tcdrain message. + * winsup.h: Made get_empty_pinfo call private to pinfo_list. + Should never be called external to this class. + +Tue Oct 22 16:14:23 1996 Jeremy Allison + + * hinfo.cc: Removed previous change. This is not the + correct place to flush input events. + +Tue Oct 22 09:25:32 1996 Jeremy Allison + + * dcrt0.cc: Fixed up exit code to clean up pinfo array. + * exceptions.cc: Fixed up exit code to clean up pinfo array. + * fork.cc: Tidied up access to inuse_p entry. Added flags + to allow different states to be represented. + * hinfo.cc: Added code to flush pending events if + stdin is a console. + * pinfo.cc (pinfo::record_death): Added code to clean + the pinfo array if we are an exiting parent. + * spawn.cc: Removed erroneous code to clean childs + pinfo entry. + * wait.cc: Changed WAIT_ERROR_RC to Win32 WAIT_FAILED. + Tidied up access to pinfo array. + * winsup.h: Added record_death_nolock to pinfo class. + Added PID_XXX types for inuse_p. + +Tue Oct 22 01:26:52 1996 Geoffrey Noer + + * include/Windows32/Base.h: + * include/Windows32/Functions.h: + * include/Windows32/Structures.h: + * include/Windows32/UnicodeFunctions.h: + Fixes to just commited changes + +Mon Oct 21 19:58:50 1996 Geoffrey Noer + + * include/Windows32/ASCIIFunctions.h: + * include/Windows32/Base.h: + * include/Windows32/Defines.h: + * include/Windows32/Functions.h: + * include/Windows32/Structures.h: + * include/Windows32/UnicodeFunctions.h: + + Add back items in old include files (commdlg.h, ddeml.h, + shellapi.h, winadvapi.h, winbase.h, wincon.h, windef.h, + windowsx.h, winerror.h, wingdi.h, winkernel.h, winnt.h, + wintypes.h, winuser.h, winversion.h) which should now be able + to be erased and windows.h modified to point to the new headers + without anything nasty happening. + + * include/WINREADME: deleted + * include/mywinsock.h: removed many blank lines + +Mon Oct 21 09:48:00 1996 Jeremy Allison + + * select.cc: Re-written from scratch. Take account of + the following cases. (1). All sockets [written&works] + (2). Handles, sockets and always readies [written,not tested] + (3). All handles [written,not tested]. (4). Handles & sockets + with timeout [not yet written,returns -1]. Correctly blocks + and doesn't spin cpu. + * pinfo.cc: Changed to add global lock around pinfo array. + * fork.cc: Changed to use global pinfo lock. + * shared.cc: Fixed bug with fork()->exec()->exec() code. + * net.cc: Removed select_init() call (no longer used). + * spawn.cc: Implemented suggestion that spawn creates + process suspended, then sets up it's dwProcessId entry + in the shared pinfo array. + * wait.cc: Changed to use global pinfo lock. + * winsup.h: Added missing windows_95() call. + * fhandler.h: Changed ifdefs to select new always_ready + methods. + * fhandler.cc (fhandler_console::write): Fixed bug + where return of write_normal was being ignored. + * dcrt0.cc: Added code to use global pinfo lock. + Ensure that process records it's own death. + * exceptions.cc: Added code to clear our entry in pinfo + array when we are exiting. Should reduce dead processes in + pinfo array. + * include/winbase.h: Added MAXIMUM_WAIT_OBJECTS define. + +Mon Oct 21 00:52:17 1996 Geoffrey Noer + + * Makefile.in: install headers from new Windows32 dir + +Sat Oct 19 00:47:58 1996 Geoffrey Noer + + * include/Windows32/Base.h: change DWORD to unsigned int from + unsigned long, change __WIN32__ checks to _WIN32, change + // comments to /* */ + +Fri Oct 18 17:33:07 1996 Geoffrey Noer + + * include/Windows32/Defines.h: change INFINITE to 0xFFFFFFFF, + add back definitions present in old winsup headers missing from + this file (STATUS_WAIT_0 et al, CONTEXT stuff, FAR, PACKED, + ASCIICHAR) + * include/Windows32/Functions.h: change // comments to /* */ + * include/Windows32/Messages.h: add definitions for WM_NULL, + WM_PENWINFIRST, WM_PENWINLAST + * include/Windows32/Sockets.h: change __WIN32__ checks to _WIN32 + * include/Windows32/Structures.h: add ppc case for CONTEXT + structure, change // comments to /* */ + +Fri Oct 18 17:25:09 1996 Geoffrey Noer + + * include/Windows32: new directory for Windows headers + * include/Windows32/ASCIIFunctions.h: + * include/Windows32/Base.h: + * include/Windows32/Defines.h: + * include/Windows32/Errors.h: + * include/Windows32/Functions.h: + * include/Windows32/Messages.h: + * include/Windows32/Sockets.h: + * include/Windows32/Structures.h: + * include/Windows32/UnicodeFunctions.h: + New Win32 headers from Scott Christley's windows32api-0.1.2 package + with no local modifications. + +Wed Oct 16 17:16:33 1996 Geoffrey Noer + + * key.cc: remove extra blank lines, change ASCIICHAR to AsciiChar + * registry.cc: remove #include since it's already + included in windows.h + +Tue Oct 15 09:51:48 1996 Jeremy Allison + + * fhandler.h: Many changes to support moving fhandler array out of + shared area into locally allocated memory. Removed fhandler class, + fhandler_base is now root of class tree. Re-arranged class definitions + to make it clear what functions are virtual and can be overridden. + Inlined may accessor functions. + * fhandler.cc: Many changes to support moving fhandler array out of + shared area into locally allocated memory. unix_path_name_ is now + always set (all fhandler_base classes have a name). + * hinfo.cc: Many changes to support moving fhandler array out of + shared area into locally allocated memory. Added linearization and + de-linearization functions. + * net.cc(socket): Added code to keep name for fhandler_socket. + * pinfo.cc : Changed allocation of fhandler_base array to be in local + memory rather than in shared area. (modified functions are pinfo_init, + pinfo_list::get_empty_pinfo, pinfo_list::allocate_pid, + pinfo::record_death). + * shared.cc: Added functions to copy fd area for spawned process. + Changed name of shared area to include master version number of + Cygwin32. + * spawn.cc (spawn_guts): Added code to initialize new shared area + for fds. + * syscalls.cc: Changed all code depending on NOFILE to use + getdtablesize(). Added internal setdtablesize() call for exec'ed + processes. + * syscalls.h: Added getdtablesize(). + * sysconf.cc (sysconf): Changed SC_OPEN_MAX to return getdtablesize(). + * winsup.h: Moved fhandler array out of shared area. Changed from + fhandler to fhandler_base (new root of class tree). + * include/mywinsock.h: Updated #endif to make end of + __INSIDE_CYGWIN32__ clear. + * include/winkernel.h: Added UnmapViewOfFile call. + +Mon Oct 14 14:59:16 1996 Geoffrey Noer + + * sysdef/i386: replace all files with ones from Scott + Christley's windows32api-0.1.2 package. Still need to + integrate new headers. + +Mon Oct 14 13:41:14 1996 Geoffrey Noer + + * syscalls.cc (_unlink): need to fchmod file to writable + before attempting to delete. This change still needs more + work (fchmod isn't written yet). + * (fchmod): change comment + +Fri Oct 11 22:27:17 1996 Geoffrey Noer + + * fhandler.cc, fhandler.h: minor fixes to console + support functions (remove missed reference to gotarg2, + definition in fhandler.h) + +Wed Oct 9 17:55:00 1996 Geoffrey Noer + + * delqueue.cc: added copyright notice, reformatted file + + from sos@prospect.com.ru (Sergey Okhapkin): + * fhandler.cc, fhandler.h: add/fix ansi/vt100 console support, + and fix a tab bug + (modified functions are fhandler_console_out::clear_screen, + fhandler_console_out::clear_to_eol, + fhandler_console_out::char_command, + fhandler_console_out::write, + FakeReadFile) + +Wed Oct 9 17:32:17 1996 Jeremy Allison + + * times.cc: Swapped gmtime and localtime (they were + incorrectly reversed). + Added is_dst determination to them both. + * misc.c: Added swab, ffs. + * fcntl.cc(fcntl): Added capability for lock calls. + * fhandler.h: Added lock method into fhandler class. + * fhandler.cc: Added NT/Win95 semantics locks into ::lock + made them pretend they are POSIX locks. + * syscalls.cc (writev): Fixed return value bug. + * net.cc: Added WSAEOPNOTSUPP error. + * cygwin.din: Added ffs and swab. + * include/strings.h: Added file (just include string.h). + * include/winbase.h: Added defines LOCKFILE_FAIL_IMMEDIATELY + and LOCKFILE_EXCLUSIVE_LOCK. + * include/winerror.h: Added define ERROR_LOCK_FAILED. + +Thu Oct 3 16:19:23 1996 Jeremy Allison + + * fhandler.h: Many changes - removed all public variables + from classes, replaced with accessor functions. Renamed all + class variables to add a trailing '_'. This makes reading + and understanding which variables are class variables much simpler. + Changed name member to unix_path_name_ and made dynamic rather + than a fixed 31 byte buffer per entry. + * fhandler.cc: Updated varable access for above. + * fcntl.cc: Updated varable access for above. + * hinfo.cc: Updated varable access for above. + * spawn.cc: Updated varable access for above. + * syscalls.cc: Added fsync (null call) and fchmod(null + call at present). + * net.cc: Added ioctls for SIOCGIFCONF and SIOCGIFFLAGS. + Added ntohs, ntohl, static functions get_winnt_ifconf, + get_win95_ifconf and get_if_flags. + * include/cygwin32/if.h: Added structs for new ioctls. + * include/cygwin32/socket.h: Added iovec include. + * include/asm/socket.h: Added defines for above ioctls. + * cygwin.din: Added ntohs, ntohl, fsync, fchmod. + +Wed Oct 2 17:34:21 1996 Geoffrey Noer + + * utils/configure.in: add call to AC_CANONICAL_SYSTEM + * utils/configure: regenerate + * Makefile.in: build cygwin.dll as new-cygwin.dll and install as + cygwin.dll to prevent confusion when building winsup natively + +Tue Oct 1 17:27:34 1996 Jeremy Allison (jra@cygnus.com) + + * include/regex.h: Added. + * net.cc: Added WSAECONNRESET, WSAEPFNOSUPPORT to + errmap array. + +Tue Oct 1 15:40:39 1996 Jeremy Allison (jra@cygnus.com) + + * fork.cc (cygwin_fork_helper1): Fixed resource leak of process + handles, added cleanup code. Also fixed timout problem when child + cannot be initialized. + * dirsearch.cc (readdir): Changed comparison to explicitly check for + INVALID_HANDLE_VALUE. Test < 0 fails with void *. + * syscalls.cc (num_entries): Changed comparison to explicitly check for + INVALID_HANDLE_VALUE. Test < 0 fails with void *. + * cygwin.din: Added regcomp, regexec, regerror, regfree. + * Makefile.in: Added EXTRA_OFILES containing ../librx/rx.o. Added + comment to explain makefrag. Added ../newlib/libc/include to include + path. + +Mon Sep 30 16:10:56 1996 Stu Grossman (grossman@critters.cygnus.com) + + * cygwin.din: Remove getopt and friends. + +Fri Sep 27 18:31:28 1996 Jeremy Allison + + * dcrt0.cc (dll_crt_1): Moved initialization of _reent to correct + position. + +Fri Sep 27 14:24:05 1996 Jeremy Allison + + * dcrt0.cc (dll_crt_1): Fixed fork bug with _impure_ptr not being + initialized correctly in a forked child. This should fix + the bash echo in a sub-shell bug. + * include/sys/uio.h: Created file. Contains definitions for writev + * include/limits.h: Added IOV_MAX and SSIZE_MAX. + * syscalls.cc: Added writev, changed read and write to return ssize_t. + * syscalls.h: Added writev, changed read and write to return ssize_t. + * cygwin.din: Added writev call. + +Wed Sep 20 13:09:00 1996 Jeremy Allison + + * include/mntent.h: Added MOUNTED definition, needed by + some code. + * dcrt0.cc : Added __progname for getopt code. + * misc.c: Added getw code. + * cygwin.din: Added getopt, optarg, opterr, optind + optopt, putw, getw calls. + +Fri Sep 20 03:03:17 1996 Geoffrey Noer + + * select.cc: change long millisec to unsigned int, + respaced file + + patch from Sergey Okhapkin : + * select.cc (polled): fix for select to get keyboard input + working properly (check EventType != KEY_EVENT instead + of checking for KeyEvent.AsciiChar == 0) + * select.cc (cygwin32_select): make int i unsigned int so NULL is + a valid timeout argument for loop + +Fri Sep 13 18:21:52 1996 Jeremy Allison + + * fhandler.cc (fhandler_base::read): rewrite text mode read + +Fri Sep 13 14:58:17 1996 Geoffrey Noer + + * exceptions.cc (call_handler): fix control-C not working + problem by setting rethere variable before the old value is + clobbered. + +Thu Sep 12 16:27:00 1996 Jeremy Allison + + * syslog.cc (pass_handler) : Removed duplicate code + in pass_handler::print(). Added get_win95_event_log_path() + to facilitate moving to registry configuration. + +Thu Sep 12 12:56:00 1996 Jeremy Allison + + * syslog.cc : Added real openlog, syslog, logmask, closelog + calls. syslog logs to event log on NT, file on Win95. + * include/winnt.h : added EVENTLOG_xx_TYPE definitions. + * include/winadvapi.h : added ReportEventA, RegisterEventSourceA + DeregisterEventSourceA declarations. + * include/winkernel.h : added LockFile, UnlockFile, LockFileEx, + UnlockFileEx declarations. + * include/wintypes.h : added PSID typedef. + * include/sys/syslog.h : added options flag definitions for openlog. + +Wed Sep 11 15:34:09 1996 Geoffrey Noer + + * fhandler.cc (popen): delete stub in favor of newlib's + (pclose): delete stub in favor of newlib's + +Tue Sep 10 17:20:56 1996 Geoffrey Noer + + * configure.in: don't transform names (the only time this might + be a good idea is for unix x cygwin32) + * configure: regenerated with autoconf + +Tue Sep 10 17:20:56 1996 Geoffrey Noer + + patch from Sergey Okhapkin : + * fhandler.cc (FakeReadFile): support arrow keys, stop treating + bringing window to front as a key down (resulting in random + characters being printed in bash). + +Mon Sep 9 19:09:36 1996 Geoffrey Noer + + * syscalls.cc (system): fix system call + +Fri Sep 6 09:33:13 1996 Doug Evans + + * fhandler.h (fhandler_base): Make execable_p public char, not + private signed char. Delete get_execable. + * fhandler.cc (fhandler_base::get_execable): Renamed to + check_execable_p. + (fhandler_base::open): Restore symlink support. + Set execable_p, symlink_p. + (fhandler_base::fstat): Replace call to get_execable with reference + to execable_p. + (fhandler_base::fhandler_base): Set execable_p to 0. + * path.h (symlink_check): Declare it. + * path.cc (symlink_check): New function. + (readlink): Call it. + (symlink_follow): Likewise. New arg EXEC, callers updated. + * syscalls.cc (_stat_worker): New arg CALLER, callers updated. + + * syscalls.cc: Delete all occurences of in/out and MARK. + +Thu Sep 5 18:51:01 1996 Doug Evans + + * fork.cc: Don't include . Delete find_exec and support. + * spawn.cc: Include . Move find_exec and support here. + (perhaps_suffix): New argument report_failure_p, callers updated. + (find_exec_1): Use perhaps_suffix when scanning PATH. + (spawn_guts): Replace code to translate posix to win32 path lists + with calls to utility fns that do the job. + +Wed Sep 4 13:30:57 1996 Doug Evans + + * path.cc (readlink): Make more bulletproof. + +Wed Aug 28 16:44:24 1996 Geoffrey Noer + + * syscalls.cc (system): use execlp + * public release beta 16 made + +Tue Aug 27 09:58:14 1996 Doug Evans + + * version.h (CYGWIN_DLL_VERSION_MINOR): Bump up to 2. + +Mon Aug 26 15:12:44 1996 Geoffrey Noer + + * syscalls.cc (system): added basic system() call. + +Mon Aug 26 13:46:30 1996 Doug Evans + + * cygwin.din (cygwin_fork_helper__FPvN30): Delete. + (vfork,select): Add. + * fork.cc (prepare_child): Delete, contents moved into + cygwin_fork_helper1. + (cygwin_fork_helper): Delete, contents moved into __fork. + * winsup.h (cygwin_fork_helper): Delete. + + * path.cc: #include . + (symlink,readlink): Reenable, rewrite. + (symlink_follow): New function. + * path.h (symlink): Delete. + (SYMLINK_COOKIE, MAX_LINK_DEPTH): Define. + (symlink_follow): Declare. + * spawn.cc (spawn_guts): Rewrite symlink support. + + * syscalls.cc (_unlink): Make arg a const char *. + * winsup.h (_unlink): Likewise. + + * spawn.cc (spawn_guts): Fix allocation of stack space for sh.exe path. + + * include/sys/errno.h: Deleted. Use newlib's. + +Fri Aug 23 16:00:00 1996 Jeremy Allison + + * net.cc (getdomainname): Changed win95 code to open + "System" key rather than "SYSTEM". I think the registry + is case-sensitive. + +Thu Aug 22 17:04:09 1996 Geoffrey Noer + + move fork into the dll: + * libcfork.cc: deleted + * fork.cc (vfork): used to be in libcfork.cc + * (__fork): used to be in libcfork.cc + * (fork): used to be in libcfork.cc + * Makefile.in: don't build libcfork.cc any more + * libccrt0.cc: set data_start, etc. from dll structure + * winsup.h: add data_start, etc. to public vars in dll + * cygwin.din: list fork + +Thu Aug 22 01:36:53 1996 Geoffrey Noer + + * registry.cc: fix new registry code + * syscalls.cc: make Windows95 check function extern "C" + +Wed Aug 21 16:15:47 1996 Geoffrey Noer + + * cygwin.din: list vfork + * dirsearch.cc: fix errno setting in readdir that caused + diff to not function on directories + * pipe.cc: reformatted + +Wed Aug 21 15:12:47 1996 Jeremy Allison + + * net.cc (domainname): Changed getdomainname to get the + information from the registry. + * registry.h: Modified interface to reg_key. + * registry.cc: Added open(),close() calls, made + get/set string values return error indication, added trailing + underscore to hkey member so it can be seen to + be a class member. + * include/winadvapi.h: Added KEY_READ and KEY write + defines for registry access. + +Mon Aug 19 09:22:35 1996 Doug Evans + + * path.cc (split_path): New function. + * path.h (split_path): Declare it. + * cygwin.din (cygwin32_split_path): Export it. + + * include/winkernel.h (FILE_SHARE_DELETE): Define. + + * syscalls.cc (__do_global_[cd]tors], __main): Move from here. + * dcrt0.cc: To here. + + * dcrt0.cc (recur): Restore (now that we know WHY it was needed). + (dll_crt0_1): Probe forked child's stack out. + + * fork.cc (FORK_WAIT_TIMEOUT): Bump up to two minutes. + + * fork.cc (dump_jmp_buf): New function. + (cygwin_fork_helper1): Call it. + * dcrt0.cc (dll_crt0:1): Call it. + * winsup.h (dump_jmp_buf): Declare it. + + * fork.cc (cygwin_fork_helper1): Reenable child suspend before + stack copy code. + +Sat Aug 17 04:06:36 1996 Geoffrey Noer + + * dirsearch.cc: reformatted, removed a couple of gotos + +Thu Aug 15 17:56:08 1996 Geoffrey Noer + + * cygwin.din: added __eprintf, a newlib function needed by assert. + * times.cc: swap gmtime and localtime (gmtime really was localtime + and vice versa). + +Tue Aug 13 03:46:22 1996 Geoffrey Noer + + * signal.cc: renamed all signal variables "sig", + fixed signal range error checking in all relevant functions, + (sigaddset): new + (sigismember): new + (sigfillset): new + (sigemptyset): new + * cygwin.din: added corresponding entries for new signal functions. + * cygwin.h: added protos for them + * fhandler.cc, fhandler.h: major reformat of code + * net.cc (cygwin32_socket): call checkinit() at start to + initialize WinSock in case it isn't already. + * syscalls.cc (access): set errno appropriately when no + write access + * fcntl.cc: reformatting + +Sat Aug 10 16:30:14 1996 Geoffrey Noer + + * signal.cc (_raise): rewrite to shorten code, corrected + return values. + * fcntl.cc, net.cc, signal.cc, stubs.c: reformatted, added + public domain notice at the tops if they were missing. + +Fri Aug 9 18:19:12 1996 Geoffrey Noer + + * syscalls.cc (_rename): return -1 if file to be renamed + doesn't exist. Reformatted whole file. + * fork.cc: increase timeout value to 60 sec from 30 sec + +Thu Aug 8 17:44:39 1996 Jim Wilson + + * config/i386/longjmp.c: Increment %eax if it is zero. + +Wed Aug 7 15:51:04 1996 Geoffrey Noer + + * include/sys/mman.h: fixed defines for PROT_READ et al to + match what's more normally there in unix + * sysdef/i386/*: removed the extra underscores present in most + of these files that shouldn't have been there + * net.cc: cleaned up whitespace, formatting + +Tue Jul 16 12:43:16 1996 Doug Evans + + * libccrt0.cc (__version): Deleted, unused. + + * uname.c (uname): Print CYGWIN_DLL_VERSION is version field. + +Mon Jul 15 16:48:29 1996 Doug Evans + + * version.h (CYGWIN_DLL_VERSION_MINOR): Bump up to 1. + + Path handling clean up, pass 2 (use //, not /..). + * path.cc (SLASH_DRIVE_PREFIX_LEN): Delete. + (slash_drive_to_win32_path): New function. + (mount_info::posix_path_p): Delete support for $CYGWIN, + always return 1. + (path_conv::path_conv): Call slash_drive_to_win32_path. + (mount_info::conv_to_win32_path): Renamed from + posix_path_to_win32_path. All callers updated. + (mount_info::conv_to_posix_path): Renamed from + win32_path_to_posix_path. All callers updated. + (normalize_posix_path): Keep two leading /'s (or \'s). + (normalize_win32_path): Likewise. + (conv_to_{win32,posix}_path): Renamed from + {posix,win32}_path_to_{win32,posix}_path_keep_rel. + (conv_to_full_{win32,posix}_path): Renamed from + {posix,win32}_path_to_full_{win32,posix}_path. + (posix_path_list_p): New function. + (cygwin32_{unix,dos}_path_to_{dos,unix}_path_keep_rel): Delete. + ({unix,dos}_path_to_{dos,unix}_path): Delete. + ({win32,posix}_to_{posix,win32}_path_list_buf_size): Renamed from + cygwin32_{win32,posix}_to_{posix,win32}_path_list_buf_size. + ({win32,posix}_to_{posix,win32}_path_list): Renamed from + cygwin32_{win32,posix}_to_{posix,win32}_path_list. + (slash_drive_prefix_p): Recognize //, not /.. + (build_slash_drive_prefix): Update. + * path.h: Update. + * cygwin.din ({dos,unix}_path_to_{unix,dos}_path): Delete. + (cygwin32_{dos,unix}_path_to_{unix,dos}_path_keep_rel): Delete. + (cygwin32_conv_to_{posix,win32}_path): Renamed from + (cygwin32_{win32,posix}_path_to_{posix,win32}_path_keep_rel. + (cygwin32_conv_to_full_{posix,win32}): New exports. + (cygwin32_posix_path_list_p): New export. + * dcrt0.cc (path_len): Delete. + (PATH_ENV_BUF_SIZE): Delete. + (conv_path_names): Delete all but PATH. + (dll_crt0_1): Rewrite environment variable conversion code. + * fork.cc (find_exec_1): Delete _SC_PATH_RULES support. Determine + path delimiter by calling posix_path_list_p. + * shared.cc (shared_info::initialize): Delete `path_rules'. + * sysconf.cc (sysconf): Delete _SC_PATH_RULES. + * winsup.h (shared_info): Delete `path_rules'. + + * fork.cc (cygwin_fork_helper1): Reset u->forkee after child has + started. + + * pinfo.cc (pinfo::init_from_fork): Delete. Empty function. + * fork.cc (cygwin_fork_helper1): Delete call to it. + + * utils/kill.cc (usage): New function. + (main): Allow multiple pids to be passed. Call usage. + +Mon Jul 15 13:07:23 1996 Michael Meissner + + * Makefile.in (install): If cross compiling, install the + cygwin.dll file as $target_alias-cygwin.dll in the bin directory, + instead of plain cygin.dll. + Install the cygwin.dll file in the library directory as well. + + * configure.in: Test for cross compiling, and if cross compiling, + transform name of cygwin.dll file in the binary directory. + + * configure: Regenerate. + + * utils/Makefile.in (Makefile): Rebuild Makefile if configure.in + changes. + (install): Use the toplevel install.sh to install the utilities, + and transform the name if cross compiling. + + * utils/configure.in: Test for cross compiling, and if cross + compiling, tranform mount, umount, ps, etc. Do not call + AC_PROG_INSTALL anymore. + + * utils/configure: Regenerate. + +Fri Jul 12 16:25:09 1996 Geoffrey Noer + + * Makefile.in: also make install in utils subdir so "mount" + et al gets installed. + +Thu Jul 11 17:53:31 1996 Geoffrey Noer + + * include/sys/param.h: fixed value of HZ (now 1000 instead of 100). + caused bug that showed up as "time sleep 5" returning 50. + +Thu Jul 11 14:08:09 1996 Geoffrey Noer + + * fhandler.cc: correct typo in comment + * exceptions.cc: remove definition of sig_func_ptr, replace + occurances with newlib-defined _sig_func_ptr. + +Wed Jul 10 19:12:18 1996 Doug Evans + + * version.h (CYGWIN_DLL_VERSION_{MAJOR,MINOR}): Bump up to 17.0. + * winsup.h (class per_process): New members {public,internal}_reserved. + (SIZEOF_PER_PROCESS): Define. + * dcrt0.cc (dll_crt0_1): Add sanity check of per_process size. + Don't call checkout for forkee. + * libccrt0.cc (cygwin_crt0): Set magic_biscuit to sizeof per_process + again. + + * utils/ps.cc (main): Print uid. + + * hinfo.h: Deleted. Contents moved to winsup.h. + * Makefile.in (WINSUP_H): Update. + + * dcrt0.cc (u, environ): Moved here. + * shared.cc: From here. + + * pinfo.cc (pinfo_init): Renamed from pinfo_init_per_process. + All callers updated. + * hinfo.cc (hmap_init): Renamed from hmap_init_per_process. + All callers updated. + * winsup.h (cygwin_parent_p): Renamed from invoked_by_cygwin_p. + All uses updated. + + * fork.cc (prepare_child): Add debug message. + + * uinfo.cc (uinfo_init): Renamed from uinfo::init. + All callers updated. Call getlogin instead of GetUserName. + (getlogin): Call GetUserName. + * winsup.h (class uinfo): Delete. Members uid,gid moved ... + (class pinfo): To here. All uses updated. + (class shared_info): Delete member `u'. + * fork.cc (cygwin_fork_helper1): Set child's uid,gid. + + * pinfo.cc (pinfo::clearout): Reset strace_mask_ptr. + + * shared.cc (open_shared_file_map): Add debugging message. + +Fri Jul 5 15:36:48 1996 Doug Evans + + * exceptions.cc (sig_func_ptr): New typedef. + (__stack_trace): Make i386 and ppc formats the same. + (sigfunc): Use sig_func_ptr. + (call_handler): Likewise. All callers updated. + (__cygwin_exception_handler): Handle exceptions before dll has + fully initialized. Only call dump_status once, like __stack_trace. + (really_exit): Call _exit, not exit. + + * hinfo.cc: Add copyright. + * uinfo.cc: Likewise. + + * passwd.c: Whitespace cleanup. + (search_for): Make static. + + * pinfo.cc (pinfo_list::init): Delete call to clearout vec[0]. + (pinfo::clearout): Reset more fields. + (pinfo_list::get_empty_pinfo): Delete printing of error messages + if table is full. + + * shared.cc (open_shared_file_map): Mark shared map as not inherited. + + * signal.cc (signal): Delete (void *) coersion of result. + (usleep): Convert microseconds to milliseconds. Delete second copy. + (_raise): Use _sig_func_ptr. + + * syscalls.h: Delete #include mntent.h, sys/types.h, string.h, + stdio.h, setjmp.h, stdlib.h, signal.h, sys/strace.h, unistd.h, + ctype.h, fcntl.h. + * winsup.h: #include sys/types.h, sys/strace.h, setjmp.h, signal.h, + string.h, windows.h. + * All necessary files updated. + + * winsup.h (class pinfo): Delete member localtime_buf. + * times.cc (corelocaltime): Use static local for localtime_buf. + + * winsup.h (class pinfo): Rename the_pid to pid. All uses updated. + Delete handle_valid_p, unused. Rename __sig_mask to sig_mask. + +Thu Jul 4 14:36:01 1996 Doug Evans + + * shared.h: Deleted. All files updated. + * winsup.h: shared.h contents moved here. + * Makefile.in (WINSUP_H): Update. + + * heap.cc: Renamed from pproc.cc. + (heap_init): Renamed from per_process::init. + In forkee initialization, ensure memory being reserved is at same + address as parent's. Commit forkee memory in one chunk. + (_sbrk): Moved here, + * syscalls.cc (_sbrk): From here. + * Makefile.in (DLL_OFILES): Update. + * dcrt0.cc (dll_crt0_1): Call heap_init instead of u->init. + * winsup.h (class per_process): Delete member `init'. + + * dcrt0.cc (recur): Delete. + (dos_argv_to_unix_argv): Delete. + + * delqueue.cc: Delete #include of delqueue.h, winerror.h + * winsup.h: #include delqueue.h. + + * exceptions.cc (ctrl_c_handler): Only require 13 ^c's to quit task. + + * fork.cc (fork_mutex,forkee_stopped,forker_stopped): New static + globals, were in class_shared info. + (fork_init,fork_terminate): New functions. + (prepare_child,cygwin_fork_helper1): Update. + (cygwin_fork_helper1): If fork disabled, return EAGAIN. + Delete unnecessary resetting of forkee_stopped event. + * winsup.h (fork_init,fork_terminate): Declare them. + * dcrt0.cc (dll_crt0_1): Call fork_init. + (_exit): Call fork_terminate. + * shared.c (shared_info::initialize): Delete init of fork stuff. + + * shared.c (h): New static global, was in class shared_info. + (shared_info::terminate): Delete, move contents into shared_terminate. + + * strace.cc (flush_p): New static global. + (strace_init): Don't clobber u->strace_mask if _STRACE_INHERIT set. + (__sys_printf): Only flush buffers if _STRACE_FLUSH. + * include/sys/strace.h (_STRACE_FLUSH,_STRACE_INHERIT): Define. + Reorganize bitmasks. + + * utils/ps.cc (main): Make output prettier. + +Wed Jul 3 12:30:24 1996 Doug Evans + + * utils/Makefile.in (mount,umount,ps,kill): Rewrite rules. + (PROGS): Add cygwin. + (cygwin): New target. + (install): Install all of $(PROGS). + * utils/cygwin.cc: New file. + + * pinfo.cc (pinfo_init_per_process): PID environment variable handling + moved here. Delete setting of u->parent. Set strace_mask_ptr. + Set invoked_by_cygwin_p appropriately. + (vfork_init): Delete, unused. + (pinfo::init_self): Delete setting of root_p. + (pinfo::terminate): root_p renamed to invoked_by_cygwin_p. + * winsup.h (class per_process): Delete initial_pid, no longer used. + (class pinfo): Add strace_mask_ptr. + * fork.cc (cygwin_fork_helper1): Update. + + * winsup.h (class per_process): Delete trace_file, trace_mutex. + Rename estrace to strace_mask. + (system_printf): Declare. + * strace.cc (strace_init): Renamed from per_process::strace_init. + Don't open trace file unless strace environment variable set. + Open trace file with FILE_SHARE_READ so others can read trace file + while tracing in progress. Print error if $strace too big. + (strace_file, strace_mutex): New static globals. + (__sys_printf): Don't do anything if strace file not opened. + (system_printf): New function. + * pproc.cc (per_process::init): Delete call to strace_init. + * dcrt0 (dll_crt0_1): Call strace_init as soon as possible. + + * dcrt0 (dll_crt0_1): Delete local can_glob, use + u->self->invoked_by_cygwin_p instead. + Move PID environment variable handling into pinfo_init_per_process. + Delete setting of u->self->in_bash. + Delete watching for bash. + * winsup.h (class pinfo): Delete in_bash. + + * exceptions.cc (*): Call system_printf, not __sys_printf. + + * shared.h (class shared_info): Delete pp, unused. + + * syscalls.cc (isatty): Replace ttyname with is_tty. + + * winsup.h (registry_init_once_only): Delete, unused. + (stdout_handle,file_handle_from_fd): Likewise. + (CHILD_P,child_p,ALL_FS,loadup_dll,cygwin_s): Likewise. + (unmixedcaseify): Prototype moved to path.h. + * path.h (unmixedcaseify): Declare. + + * fork.cc (FORK_WAIT_TIMEOUT, WAIT_ERROR_RC): Define. + (find_exec_1): Don't search PATH if directory present (not only if + absolute path). Search "." before searching PATH. + (copy): Return boolean indicating success. All callers updated. + (prepare_child): Simplify. Check return code of WaitForSingleObject. + Don't wait an infinite amount of time. + (cygwin_fork_helper1): Simplify. + Check return code of WaitForSingleObject. + Don't wait an infinite amount of time. + Check return code of copy. + Disable code to Suspend/Resume child thread a second time. + + * winsup.h (class per_process): Make initial_sp a char *. + * libccrt0.cc (cygwin_crt0): Update. + + * path.cc (path_conv): If name too long, set path to bogus value. + + * include/winkernel.h (WriteProcessMemory): Fix prototype. + + * include/sys/strace.h: Add extern "C" ifdef __cplusplus. + (_STRACE): Delete. + * dirsearch.cc (rewinddir): Use syscall_printf. + +Tue Jul 2 14:44:18 1996 Doug Evans + + * wait.cc (WAIT_ERROR_RC): Use it instead of ALL_FS. + (wait_found): New argument `options'. If GetExitCodeProcess fails, + ensure `result' contains something reasonable. + (wait_for_single): Check whether `c' is NULL before dereferencing it. + (wait_for_any): Add some comments. Delete unnecessary gotos. + (waitpid): Print message if called with intpid == 0. + +Sat Jun 29 10:49:28 1996 Doug Evans + + * dirsearch.cc (readdir): Clean up syscall tracing. + Mixed case handling temporarily disabled. + +Wed Jun 26 11:54:27 1996 Jason Molenda (crash@godzilla.cygnus.co.jp) + + * Makefile.in (bindir, libdir, datadir, infodir, includedir): + Use autoconf-set values. + (docdir): Removed. + (install-info): Add. + * configure.in (AC_PREREQ): autoconf 2.5 or higher. + * configure: Rebuilt. + * glob/configure.in (AC_PREREQ): autoconf 2.5 or higher. + * glob/configure: Rebuilt. + * utils/Makefile.in (bindir, exec_prefix): Use autoconf-set values. + * utils/configure.in (AC_PREREQ): autoconf 2.5 or higher. + * utils/configure: Rebuilt. + +Tue Jun 25 17:48:56 1996 Doug Evans + + * include/sys/param.h (PATH_MAX,MAXPATHLEN): Change from 1024 to 259. + (BIG_ENDIAN,LITTLE_ENDIAN,BYTE_ORDER): Define. + +Mon Jun 24 16:35:48 1996 Mark Eichin + + * fhandler.cc (read): Replace the old broken igncr code (which has + been disabled for a while anyway) with code that checks for + ENABLE_LINE_INPUT and replace only \r\n with \n. + +Mon Jun 24 00:12:22 1996 Doug Evans + + * dcrt0.cc (dll_crt0_1): Convert argv[0] to posix style if necessary. + +Sun Jun 23 17:21:41 1996 Doug Evans + + * version.h (CYGWIN_DLL_VERSION_MINOR): Bump up to 2. + + * fork.cc (perhaps_suffix): Simplify. + (find_exec_1): Likewise. Always try appending .exe first. + (cygwin_fork_helper1): Clean up (lots more needed still). + Test for split heap before calling CreateProcess. + No longer call find_exec, now done at start up. + * dcrt0.cc (dll_crt0_1): Call find_exec to expand argv[0]. + + * path.cc (conv_path_list_buf_size): New function. + (cygwin32_{win32,posix}_to_{posix,win32}_path_list_buf_size): Ditto. + (conv_path_list): Ditto. + (cygwin32_{win32,posix}_to_{posix,win32}_path_list): Ditto. + * cygwin.din: Export them. + + * misc.c (small_printf): Delete. + (vhangup): Set errno. + + * syscalls.cc (isatty): Print syscall trace message even if error. + + * console.cc (*): Check return codes of win32 api calls. + + * syscalls.cc (chmod): Set errno of SetFileAttributes fails. + Fix call to syscall_printf. + +Thu Jun 20 00:43:52 1996 Doug Evans + + * dcrt0.cc (dll_crt0_1): Save full program name. + * fork.cc (cygwin_fork_helper1): Always call find_exec. + + * path.cc (normalize_{posix,win32}_path): Fix edge case handling. + (path_conv::path_conv): Ensure path is \-ified if win32 path rules. + + * spawn.cc (spawn_guts): Set errno if CreateProcess fails. + +Wed Jun 19 00:18:03 1996 Doug Evans + + * path.h (PATH_RULES macros): Delete. Use ones in unistd.h. + (enum path_rules_enum): Deleted. All uses updated. + (path_conv): Rename member get_native to get_win32. All uses updated. + (*win32_path*): Renamed from *native_path*. + * path.cc (*win32_path*): Renamed from *native_path*. + (mount_info::posix_path_p): Prepend '_' to PATH_RULES. + Fix returning of cached value. + (slash_drive_prefix_p, build_slash_drive_prefix): New functions. + (mount_info::posix_path_to_win32_path): /.. is a drive spec. + (path_conv::path_conv): Likewise. + (mount_info::win32_path_to_posix_path): Convert unknown drives to + /.. Normalize win32_path. + (normalize_win32_path): New functions. + (getcwd_inner): New arg `posix_p'. All callers updated. + * shared.cc (shared_info::initialize): Prepend '_' to PATH_RULES. + _PATH_RULES_NATIVE -> _PATH_RULES_WIN32. + * spawn.cc (*win32_path*): Renamed from *native_path*. + * dcrt0.cc: Likewise. + * cygwin.din: Likewise. + + * Makefile.in (WINSUP_H): Add shared.h + + * smallprint.c (rn): Make static. + + * sysconf.cc: Renamed from sysconf.c. + (sysconf): Support _SC_PATH_RULES. + + * screen.c: Deleted. + * Makefile.in (DLL_OFILES): Delete screen.o. + + * fork.cc (cygwin_fork_helper): Don't pass 0 from longjmp to setjmp. + + * path.h (class mount_info): Update posix_path_to_native_path member. + * path.cc (path_prefix_p): Rewrite. + New arg `len'. All callers updated. + (mount_info::binary_native_path_p): Call path_prefix_p. + (path_conv::path_conv): Pass full_path to binary_native_path_p. + (mount_info::posix_path_to_native_path): Delete arg keep_rel_p. + New arg full_native_path. All callers updated. Don't call + getcwd_inner if unnecessary. Rewrite relative path handling. + (mount_info::native_path_to_posix_path): Call path_prefix_p. + Call slashify on `pathbuf', not original argument. + + * syscalls.cc (chdir): Fix lifetime of converted path. + +Tue Jun 18 11:48:51 1996 Doug Evans + + * configure.in (EXE_LDFLAGS): Explicitly link with newlib if necessary. + * configure: Regenerated. + * Makefile.in (EXE_LDFLAGS): Define. + (FLAGS_TO_PASS): Add EXE_LDFLAGS. + (config.status): New target. + (utils-all): Depend on $(LIBNAME). + * utils/Makefile.in (EXE_LDFLAGS): Define. + (mount,umount,ps,kill): Link with $(EXE_LDFLAGS). + + * version.h (CYGWIN_DLL_VERSION_MINOR): Bump up to 1. + +Mon Jun 17 18:29:54 1996 Doug Evans + + Improve pathname handling, first pass. + * path.h (symlink): Renamed from link_cookie. + (class path_conv): New member error. + (path_conv::get_native): Renamed from get_dos, all uses updated. + (path_conv::get_binary): Delete. + (mount_info::{mangle,reverse_mangle}): Delete. + (mount_item::posix_path_to_native_path): Renamed from mangle. + (mount_info::native_path_to_posix_path): Renamed from reverse_mangle. + (path_rules_enum): Define. + * path.cc: Temporarily disable mixed-case and symlink handling. + (mount_info::posix_path_p): New function. + (mount_info::binary_native_path_p): Renamed from binary_dos_path_p. + (path_conv::path_conv): Handle native path rules. + (mount_item::{mangle,reverse_mangle}): Delete. + (mount_info::posix_path_to_native_path): Renamed from mangle. + (mount_info::native_path_to_posix_path): Renamed from reverse_mangle. + (mount_info::from_registry): Set nmounts. Use MAX_PATH. + (mount_info::{add,del}_item): Rewrite. + (slashify): Renamed from flip_slash. + (getcwd_inner): Make static. Don't convert to posix path if using + native path rules. + (file_exists): Delete. + (addmntent,hasmntopt): Delete. + (mount): Only update registry if mount succeeded. + (umount): Only update registry if umount succeeded. + (normalize_posix_path): Renamed from normalize_path. Pass in cwd. + (cygwin32_{posix,native}_path_to_{native,posix}_path_keep_rel): Renamed + from ...{unix/dos}.... + * dcrt0.cc (dos_argv_to_unix_argv): #ifdef out. + (dll_crt0_1): Don't call it. + * fhandler.cc (fhandler_base::open): Temporarily disable symlinks. + * shared.cc (open_shared_file_map): New function. + (shared_init): Call it. + (shared_info::initialize): Fetch `path_rules' from registry. + * shared.h (inited): Make private. + (path_rules): New member. + * spawn.cc: #include "shared.h". + (spawn_guts, env var translation): Don't translate path names if + using native path rules. + * syscalls.cc (symlink): Delete (moved to path.cc). + * cygwin.din (dump__5pinfo): Delete. + (cygwin32_{posix,native}_path_to_{native,posix}_path_keep_rel): Renamed + from ...{unix/dos}.... + + * smallout.cc: Delete. + * sdata.cc: Delete. + * shared.cc (u,s,environ): Define here. + * Makefile.in (glob/libglob.a): Depend on glob/glob.c, glob/fnmatch.c. + (utils-all): New target. + (DLL_OFILES): Delete smallout.o, sdata.o. + (Makefile): Depend on cygwin.din. + (WINSUP_H): Depend on syscalls.h. + + * configure.in (AC_CONFIG_SUBDIRS): Add bin. + (AC_PROG_INSTALL): Call. + * configure: Regenerated. + * utils/{Makefile.in,configure.in,configure}: New files. + * utils/{kill.cc,mount.cc,ps.cc,umount.cc,termcap}: New files. + * Makefile.in (UTILS_ALL): Define. + (all): Depend on $(UTILS_ALL). + (utils-all): New target. + + * dcrt0.cc (recur): Make no-op to see what happens. + (globify): Don't call glob if unnecessary. + Check return code from glob. + (api_fatal): New function. + * fhandler.cc (fhandler_base::read): Dump first few chars read. + (fhandler_base::get_execable): New function. + (fhandler_base::fstat): Use it. + (fhandler_base::fhandler_base): Init execable_p. + (fhandler_disk_file::fhandler_disk_file): Delete execable_p. + (fhandler::{get,set}_execable_bit): Delete. + (fhandler_disk_file::{get,set}_execable_bit): Delete. + * fhandler.h (class fhandler): Delete {get,set}_execable_bit. + (class fhandler_base): New member execable_p. + New member fn get_execable. + * fork.cc: Simplify/cleanup. + (cygwin_fork_helper1): Use MAX_PATH, not MAXPATHLEN. + * pinfo.cc (pinfo::dump): Delete. + * pproc.cc (per_process::set_envname): Delete. + * strace.cc (smallout::do_pline): Delete. + * syscalls.h (readlink): Third arg is an int. + * winsup.h (class pinfo, member progname): Use MAX_PATH. + (class pinfo, member dump): Delete. + (class smallout): Delete. + (smallout): Delete. + (class per_process, member set_envname): Delete. + (file_exists): Delete. + (api_fatal): Declare. + * Makefile.in (LIB{C,CXX}FLAGS_FOR_TARGET): Delete, use {C,CXX}FLAGS. + (FLAGS_TO_PASS): Define. + (glob/libglob.a): Delete duplicate entry. + + * syscalls.cc (_sbrk): Update u->size when heap is grown. + + * hinfo.cc (hmap_init_per_process): Ensure stdout's handle != stderr's. + +Fri Jun 14 06:32:13 1996 Doug Evans + + * register.h, registry.cc: Whitespace cleanup. + +Thu Jun 13 20:57:28 1996 Doug Evans + + * Makefile.in (install): Install cygwin.dll in $(bindir). + +Tue Jun 11 13:46:17 1996 Geoffrey Noer + + * fhandler.cc: lseek is now only binary mode, interpret control + z characters as EOF when reading from a file. Reformatted some + of the code (cleaned up line spacing, etc.) + +Tue Jun 11 09:50:09 1996 Jason Molenda (crash@kyriath.cygnus.com) + + * path.cc (nofinalslash): move it so it is next to its friends + flip_slash and backslashify. + +Mon Jun 10 18:57:03 1996 Jason Molenda (crash@kyriath.cygnus.com) + + * path.cc (*): Pretty printing. + (unix_path_to_dos_path_with_rel): use "dosnamein" and "unixnameout" + instead of "path" & "real_path". + (dos_path_to_unix_path_keep_rel): delete obsolete code. + (mount_item::mangle): use "unixnamein" and "dosnameout" instead of + "unixname" and "dosname". + (mount_info::mangle): use "unixnamein" and "dosnameout". Remove + obsolete code. + * path.h (mount_item): Update prototypes, add comment. + (mount_info): Update prototypes. + +Mon Jun 10 17:05:23 1996 Jason Molenda (crash@kyriath.cygnus.com) + + * path.cc (mount_item::reverse_mangle): Pretty printing, + add a bit to the comment. + (getcwd_inner): use MAX_PATH not MAXPATHLEN. + (normalize_path): use MAX_PATH not MAXPATHLEN. + (link_cookie::follow): use MAX_PATH not MAXPATHLEN. + +Mon Jun 10 15:36:32 1996 Geoffrey Noer + + * Makefile.in: changed $(DOC) so it doesn't include html + files; made a new info-html target that does the html + versions of the docs. Since most customers don't have texi2html + installed, the make shouldn't fail because of this. + * configure: regenerated with autoconf 2.8 + +Sun Jun 9 17:10:37 1996 Doug Evans + + * version.c: Deleted. + * version.h: New file. + * winsup.h (VERSION): Deleted. + (class per_process): Add version_major, version_minor. Delete version. + * registry.cc: #include "version.h". + (reg_session::reg_session): Update. + * libccrt0.cc: #include "version.h" + (cygwin_crt0): Delete setting of version, set magic_biscuit to 0. + Set version_major, version_minor. + * dcrt0.cc: #include "version.h". + (cygwin_dll_version_{major,minor}): New static locals. + (dll_crt0_1): Rewrite app/dll compatibility test. + * Makefile.in (LIBCOS): Delete version.o. + (DLL_OFILES): Delete version.o. + (dcrt0.o,libccrt0.o,registry.o): Depend on version.h. + + * exceptions.h: New file. + * exceptions.cc: Massive cleanups (still lots more to go). + #include "exceptions.h". + (init_exceptions): Renamed from __init_exceptions. New argument of + pointer to exception handler list entry. + (init_exception_handler): Renamed from init_thread_exceptions. + Rewrite based on info from Onno Hovers . + (ppc descriptor_to_{function,gotattr}): Make static. + (i386 __stack_trace): Fix test for top of stack. + * dcrt0.cc: #include "exceptions.h". + (dll_crt0_1): Exception handler list entry must live on stack. + * winsup.h (class pinfo): Delete member myp. + * syscalls.h (struct exception_list): Delete. + (__really_exit, __init_exceptions): Delete. + * Makefile.in (dcrt0.o,exceptions.o): Depend on exceptions.h. + +Fri Jun 7 17:49:28 1996 Jason Molenda (crash@phydeaux.cygnus.com) + + * dcrt0.cc (conv_path_names): Add GCC_EXEC_PREFIX. + +Fri Jun 7 14:38:05 1996 Doug Evans + + * Makefile.in (CC_FOR_TARGET,LD,DLLTOOL): Define. + (AR,RANLIB): Set via configure. + * configure.in (AR,LD,DLLTOOL): Set. + (AC_PROG_RANLIB): Call. + * configure: Regenerated. + +Thu Jun 6 12:11:23 1996 Kim Knuttila + + * dcrt0.cc (dll_crt0_1): Removed reference to reent_data._next. + +Tue Jun 4 15:52:29 1996 Geoffrey Noer + + * include/winkernel.h: fixed typo + +Tue May 28 13:08:25 1996 Doug Evans + + * syscalls.cc (_sbrk): Fix test of return value from VirtualAlloc. + Delete lincr, make incr signed, and use only it. Misc. minor cleanup. + +Thu May 23 17:31:57 1996 Geoffrey Noer + + sac diffs applied: + * path.h: change MAXMOUNTS to 30 instead of 20 + * sysdef/i386/rpcndr.def: add "none" to end of file + * fhandler.cc: fix memset call to say sizeof (*buf) instead + of sizeof (buf). + * include/winuser.h: define MDIS_ALLCHILDSTYLES + * Makefile.in: entry to build glob/libglob.a: + +Thu May 23 10:38:43 1996 Doug Evans + + * fhandler.h (class fhandler_base): Make `name' private and shrink + to 32 bytes. + (set_name): Declare. + * fhandler.cc (fhandler::set_name): New function. + (fhander_base::open): Call it. + (fhander_base::init): Call it. + (fhandler_tty::ttyname): Call get_name instead of accessing `name' + directly. + + * dcrt0.cc (dll_crt0_1): Call ExitProcess instead of exit if + DLL and APP are out of sync. + +Thu May 16 03:07:18 1996 Mark Eichin + + * fhandler.cc (FakeReadFile): new function. Interface like + ReadFile, only called from fhandler_console_in::read, calls + ReadFile unless we're really reading from STD_INPUT_HANDLE and + with ENABLE_LINE_INPUT turned off, in which case we use + ReadConsoleInput instead. When using ReadConsoleInput, always read + all available events, but only block if we don't get at least one + actual character. This would be the place to implement FIONBIO on + the console tty, which doesn't actually exist yet. + (dbg_input_event): copied from select.cc, debugging code to show + detail of what events we're actually getting. + (ioctl): off-by-one on window size. + +Wed May 15 18:11:16 1996 Jim Wilson + + * fhandler.h (class fhandler_base): Use MAXPATHLEN not 100 for size + of array name. + +Wed May 15 11:14:46 1996 Doug Evans + + * fork.cc (cygwin_fork_helper1): More debugging printf's. + + * dcrt0.cc (num_ms_env_vars): Renamed from ms_env_arity. + (build_argv): Renamed from fill. + (compute_argc): Renamed from prepare. + * libccrt0.cc (cygwin_statu): Make static. + * pproc.cc (per_process::init): Move strace initialization from here, + * strace.cc (per_process::strace_init): To here. + Pass FILE_SHARE_WRITE to CreateFileA. Print error message if open + of log file fails. Create mutex for trace messages. + (__sys_printf): Always write to end of disk files. Use mutex. + (d): Delete. + * winsup.h (class per_process): Add strace_init. Reorganize. + `run_ctors' renamed to `run_ctors_p'. New member `trace_mutex'. + (d): Delete. + (PATH_MAX): Delete. + + * Makefile.in: Add header file dependencies. + + * dcrt0.cc (_exit): Add debugging printf. + * shared.h (class shared_info): Rename member mutex_a to fork_mutex. + * fork.cc (cygwin_fork_helper1): Update. + Return with error if process slot unavailable. + Set errno and release fork_mutex if failed because of split heap. + * shared.cc (shared_info::terminate): Update. + (shared_info::initialize): Update. + +Tue May 14 14:59:32 1996 Doug Evans + + * fork.cc (cygwin_fork_helper1): Avoid SIGSEGV if allocate_pid fails. + + * pproc.cc (per_process::init): Fix test. + + * winsup.h (): Rename member `parent' to `ppid'. + * fork.cc (prepare_child): Update. + (cygwin_fork_helper1): Likewise. + * hinfo.cc (hmap_init_per_process): Likewise. + (hinfo_vec::dup_for_fork): Fix message. + (hinfo_vec::dup2): Fix args to debug_printf. Delete extra printf's. + * pinfo.cc (pinfo_init_per_process): Update. + (pinfo::dump): Likewise. + (pinfo::init_self): Likewise. + * pproc.cc (per_process::init): Open strace file in append mode. + * smallprintf.c (__small_vsprintf): Support %p. + * syscalls.cc (getppid): Update. + * wait.cc (wait_for_any): Likewise. + +Mon May 13 13:45:36 1996 Mark Eichin + + * fhandler.cc (ioctl): fix TIOCGWINSZ handling: (1) check the + error return (2) if we're trying on STD_INPUT_HANDLE, substitute + STD_OUTPUT_HANDLE since GetConsoleScreenBufferInfo only works on + console output (3) check srWindow for the *screen* size, instead + of checking dwSize for the scroll buffer size. + + * include/sys/errno.h (ECONNABORTED): add another errno value. + * net.cc (errmap): add ECONNABORTED case. + + * fhandler.cc (fstat): clear the *entire* stat buf, not just the + first four bytes. + +Fri May 10 17:59:09 1996 Mark Eichin + + * select.cc: change most debugging statements to select_printf. + (dbg_input_event): new function, prints an INPUT_RECORD via select + printf. + (polled): Don't sleep around WaitForMultipleObjects; let it have a + 10ms timeout until we have time to test it with 0. If + WaitForMultipleObjects says that STD_INPUT_HANDLE has data, use + PeekConsoleInput to scan the available events. If the first one is + not a *bKeyDown* with a non-zero *AsciiChar* then use + ReadConsoleInput to rip it off the queue, and pretend it wasn't + there, so that later calls to read (and thus ReadFile) don't block + because they can't find any *real* input. (This could be optimized + later to check the whole queue, and if there are *no* real input + events, nuke them all.) + + * include/sys/strace.h (_STRACE_SELECT, select_printf): new printf + category, because select needs a *lot* of work. STRACE=256 to use it. + + * fhandler.cc (fhandler_console_in::init): IGNCR can't work + without major changes to deal with the interaction with select + (which shouldn't wake up if IGNCR causes the whole input to be + deleted...) so don't make it the default. + (fhandler_console_out::tcgetattr, fhandler_tty::tcgetattr): don't + set IGNCR based on get_r_binary either. + +Wed May 8 20:20:05 1996 Mark Eichin + + * times.cc (__to_clock_t): must cast dwLowDateTime to *unsigned* + before adding it -- otherwise we may subtract it! + (to_time_t): same. + +Wed May 8 18:21:28 1996 Mark Eichin + + * times.cc (corelocaltime): new function. Basic localtime from + newlib, with no conversions. + (gmtime): just calls corelocaltime. + (localtime): uses GetTimeZoneInformation, biases to standard time + first, then uses DaylightDate and StandardDate to figure out if + we're in DST -- and calls corelocaltime a second time with the + rebiased seconds, if we are. + (times): add debug_printf statements which work around apparent + compiler bug and 7+ minute error. + + * select.cc: revert to 's changes of 4/20 which were + accidentally backed out on 4/24. + +Tue May 7 05:29:42 1996 Mark Eichin + + * times.cc (__to_clock_t): subtract out FACTOR, the difference + between 1601 and 1970, just like to_time_t() does. + +Tue May 7 01:55:06 1996 Mark Eichin + + * times.cc (gmtime): new function. Use GetTimeZoneInformation to + compensate ahead before calling localtime (since the newlib + version doesn't know what timezone we're in.) + (localtime): use SECSPERMIN, not 60, to show that we know what + we're talking about. + + * net.cc (errmap): add WSAEADDRINUSE, WSAECONNREFUSED mappings. + +Sun May 5 00:45:59 1996 Mark Eichin + + * include/sys/socket.h: add recvfrom macro and cygwin32_recvfrom + declaration. Remove htons/htonl misdeclarations as they collide + with the macros in asm/byteorder.h. + + * include/asm/byteorder.h: enable the ntohl/ntohs declarations so + we at least get the macro versions when we optimize, even if the + library hooks aren't there. + +Wed Apr 24 23:42:49 1996 Steve Chamberlain + + * winsup.h (pinfo, pinfo_list): Remove dummy item. + * fork.cc (*): Revert changes of Apr 2. + +Sun Apr 21 17:00:14 1996 Steve Chamberlain + + * wait.cc (wait_for_any): Fix the wait heuristic. + +Sat Apr 20 13:22:03 1996 Steve Chamberlain + + * Makefile.in (.cc.o): Pass -fno-rtti. + * dcrt0.cc (globify): A single match is ok. + * exceptions.cc (i386 call_handler): optimize. + * fhandler.cc (fhandler_console_in::read): Handle ICRNL right. + (*:get_name *:always_ready): New. + * select.cc: Understand that console output doesn't signal when it's + ready. + +Fri Apr 12 14:49:34 1996 Doug Evans + + * Makefile.in (glob/libglob.a): Pass -I so glob.c finds right dirent.h. + +Wed Apr 10 16:13:30 1996 steve chamberlain + + * Makefile.in (glob/libglob.a): Call glob makefile correctly. + * winsup.h (pinfo, pinfo_list): Reorder elements to avoid + alignment bug in PPC gcc. + +Tue Apr 9 17:23:57 1996 steve chamberlain + + * dcrt0.cc (globify): Expand command line wildcards if + run from dos prompt. + + * exceptions.cc (386 call_handler): More fumblings. + * fhandler.cc (fhandler_base::stat): Initialize ino. + (fhandler_console::open): Fix test for RDONLY. + (fhandler_tty::stat): Set ino. + (fhandler_console_out::vt100 stuff): More. + * fork.cc: Lint. + * pinfo.cc (pinfo::init_self): Don't bother to DuplicateHandles + to get process info. + * signal.cc (usleep): Get correct order of magnitude. + * spawn.cc (spawn_guts): Turn of exception handling in + parent of thing which execs. + * syscalls.cc (stat): Look for and . + * wait.cc (wait_for_any): Keep waiting if WaitForMultipleObject + returns invalid result. + +Tue Apr 2 12:45:35 1996 steve chamberlain + + * dcrt0.cc (conv_path_names): Add HOME. + (dll_crt0_1): Use u->self->head_sp. + * exceptions.cc (i386 call_handler): Rewritten, now almost works + on win95. + * fhandler.cc (fhandler_base::open): Calculate namehash. + (fhandler_base::fstat): ^ name hash with file index low. + * fork.cc (*): forkee/forkerr events moved from sinfo + into pinfo. + +Fri Mar 29 16:35:02 1996 steve chamberlain + + * libcmain.cc: New. + * winsup.h: restore and myp moved from per_process to pinfo class. + * dcrt0.cc (dll_crt0_1): Cope with move. + * exceptions.cc (init_thread_exceptions): Ditto. + * signal.cc (sigprocmask): Ditto. + * fork.cc (cygwin_fork_helper1): Don't fork if split_heap_p. + * pinfo.cc (pinfo::clearout): Zero split_heap_p. + * syscalls.cc (_sbrk): Cope with not being able to + allocate contiguous chunks. + + +Tue Mar 26 09:14:32 1996 steve chamberlain + + * exceptions.cc (__cygwin_exception_handler): re-export. + +Fri Mar 22 16:49:29 1996 Michael Meissner + + * cygwin.din (__stack_trace): Export. + (__cygwin_exception_handler): Ditto. + + * exceptions.cc (i386 exception handling): Move under appropriate + x86 #ifdefs. Use the macro HAVE_INIT_THREAD_EXCEPTIONS to be + whatever a machine needs to do to initialize exceptions in this + thread. Nop for the PowerPC right now. + (__stack_trace): Make it a "C" function so there is no name + mangling, and export it. + (call_handler): Split by architecture before the function, rather + than inside it. First stab at PowerPC exception handling. + (__cygwin_exception_handler): Rename from ehandler3, and export + it. Add more status -> signal mappings. + (ctrl_c_handler, CTRL_LOGOFF_EVENT): Map to SIGHUP, not SIGQUIT. + (__stack_trace): Split into separate machine dependent functions, + rather than #ifdef'ing inside of a common function. Make the + PowerPC messages clearer. + +Mon Mar 18 13:27:05 1996 Michael Meissner + + * include/winkernel.h (CreateThread): Correctly declare function + pointer argument. + + * misc.c (wprintf): Convert to use vprintf and fix warnings. + (tgetent): Declare to return int to fix warnings. + (vhangup): Declare to return int to fix warnings. Return -1 also. + + * include/winbase.h (UnhandledExceptionFilter): Declare. + +Tue Mar 12 12:56:28 1996 Doug Evans + + * include/winkernel.h (FlushFileBuffers): Declare. + +Tue Mar 12 11:16:32 1996 Michael Meissner + + * exceptions.cc (dump_status): Make columns line up for PowerPC. + (call_handler): Right now, call exit(255) for the PowerPC. + + * strace.cc (__sys_printf): Call FlushFileBuffers after writing + out the file to make sure it really gets flushed. + + * include/winkernel.h (PowerPC CONTEXT): Add fields returned if + CONTEXT_DEBUG_REGISTERS is set. + +Sun Mar 10 15:31:17 1996 Steve Chamberlain + + * strerror.cc, syslog.cc, net.cc: New files. + * cygwin.din: Add new net functions. + * dcrt0.cc (dll_crt0_1): Fix call to build argv[0]. + * fhandler.cc (fhandler_base::open): Tidy. + * fhandler.h: Add net classes. + * hinfo.cc (hinfo_vec::build_fhandler): Add tape stuff. + * path.cc (*::mangle, *::reverse_mangle): Fix. + (mount_info::init): No trailing / now. + * select.cc (*): Rewrite. + * spawn.cc (spawn_guts): Fix leak. + * syscalls.cc (_sbrk): Keep working until memory really fills up. + +Tue Feb 20 16:53:24 1996 Steve Chamberlain + + * dcrt0.cc (dll_crt0_1): Get version from the header. + * fhandler.cc (CHUNK_SIZE): New. + (fhandler_base::read, fhandler_base::write): CRLF conversion + rewritten. + path.cc (path_conv::path_conv): Initialize mixed, binary and silent. + * smallprint.c (__small_vsprintf): Add 'c' option. + * wait.cc (wait_found): Close child handles. + +Mon Feb 19 09:11:57 1996 Michael Meissner + + * Makefile.in (real-headers): Eliminate real-headers dependency on + mspatches/*.patch, since you can't be guaranteed that it exists. + +Fri Feb 16 14:24:47 1996 Michael Meissner + + * exceptions.cc (dump_status): On the PowerPC, dump all of the + integer registers. + + * uname.c (uname): Don't assume that the only two NT systems are + i386 and PowerPC. + * exceptions.cc (call_handler): Ditto. + (dump_status): Ditto. + +Thu Feb 15 18:20:33 1996 Steve Chamberlain + + * cygwin.din (__empty): Add. + * dcrt0.cc (dos_argv_to_unix_argv): New. + (check, onetimecheck): New. + * exceptions.cc (ehandler3): Always show backtrace + if exception failed. + * fhandler.cc (*::open): Removed dos_path argument. + (fhandler_base::fstat): Use nFileIndexLow as the inode + value. + * hinfo.cc (init_std_file_from_handle): Don't default + to binary. + * paths.cc (*): Use new registry classes. + * registry.cc (*): Rewritten. + * syscalls.cc (open): Call fhandler->open without + the dos filename arg. + +Sat Feb 10 08:18:45 1996 Michael Meissner + + * configure.in (ALLOCA for powerpc): Add __allocate_stack. + +Wed Feb 7 16:41:18 1996 Steve Chamberlain + + Release-B13 + + * malloc.cc (export_*): New. Changed the way that malloc + stubs are used. + * cygwin.din: Export the export_* stuff as malloc, realloc and free. + * path.cc (link_cookie::create): Keep cookie filenames in unix + format. + (reverse_mangle): Clean up. + (readlink): Ditto. + (qfunc): Sort by name too. + * spawn.cc (spawn_guts): Handle zero length arg. + Only set errno when it's not 0. + * Makefile.in: Build new doc. + * fhandler.cc (fhandler_base::fstat): Round up block used. + * path.cc (escape_char): Now it's ^. + * syscalls.cc (errmap): ERROR_INVALID_NAME yields ENOENT. + (chown): Returns 0. + (sbrk): Clean up. + (_unlink): Only try and DeleteFile once. + +Mon Feb 5 19:15:44 1996 Steve Chamberlain + + * dcrt0.cc (dll_crt0_1): Build env string into static buffer. + * dirsearch.c (opendir): Stat on unix pathname. + * paths.cc (*): Support for mixed case filenames. + +Sun Feb 4 15:55:58 1996 Steve Chamberlain + + * *.cc: Lint. + (conv_path_names): New. + (dll_crt0_1): Use conv_path_names list. + * fctnl.cc (F_DUPFD): Look from the fd forward. + * fhandler.cc (fhandler_base::open): Understand binary modes. + (fhandler_console_in::init): Call tcsetattr with reasonable start + values. + * spawn.cc (spawn_guts): Use conv_path_names. + (queue_file_deletion): Deleted. + (unlink): Use new queue file stuff. + * delqueue.cc, delqueue.h: New files. + * shared.h: New file. + +Wed Jan 31 11:12:24 1996 Steve Chamberlain + + * crt0.cc: Hacks to probe out ppc stack. + * exceptions.cc (ehander3): Don't use 386 context info on the ppc. + * path.cc (mount_info::mangle): Turn /usi or /usp into /usr. + * uname.c (uname): Change sysname and get ppc name right. + +Fri Jan 26 15:47:31 1996 Steve Chamberlain + + * pproc.cc (per_process::init): Cope when no memory is needed. + * Makefile.in, configure.in: Cope with config directory. + * setjmp.c, longjmp.c: Moved into config/i386. + * config/ppc/setjmp.S, config/ppc/longjmp.S: New. + +Fri Jan 26 14:57:33 1996 Jason Molenda (crash@phydeaux.cygnus.com) + + * Makefile.in (DLL_OFILES): removed ppc-stub.o + ppc-stub.c: Removed. + configure: regenerated with autoconf 2.7. + +Fri Jan 26 11:18:07 1996 Kim Knuttila + + * Makefile.in (DLL_OFILES): added ppc-stub.o + +Thu Jan 25 09:33:24 1996 Steve Chamberlain + + * malloc.cc (malloc, free, realloc): Hack for ppc. + +Wed Jan 24 20:22:42 1996 Steve Chamberlain + + * cygwin.dll (loadup_dll): Remove. + * dcrt0.cc: lint. + * fhandler.* (*): Move to new class structure. + * hinfo.cc: Use new fhandler glue. + * libcfork.cc: Cope with ppc naming convention. + +Mon Jan 22 10:33:53 1996 Steve Chamberlain + + * fhandler.h, hinfo.h: New files. + * winsup.h: Split from here. + * configure.in: Set i386 entry point correctly. + * fhandler.cc (fhandler_normal:open): .com files + are executable too. + * hinfo.cc (init_std_file_from_handle): Inspect + master_fmode_binary. + * misc.cc (wcscmp, wcslen): New. + * dcrt0.cc (probe): Change way a forkee's stack is allocated. + * pproc.cc (per_process::init): Initialize using heap chunk. + * shared.cc (shared_info::initialize): Initialize heap chunk. + * syscalls.cc (_sbrk): If current chunk is used, allocate another. + * wait.cc (wait_found): Fix exit code. + +Thu Jan 18 10:09:45 1996 Steve Chamberlain + + * fhandler.cc (fhandler_normal::open) Don't test a + com port to see if it's executable. + * configure.in, cygwin.din: More powerpc configury. + +Wed Jan 17 16:25:36 1996 Steve Chamberlain + + * configure.in, Makefile.in: Build powerpc stuff. + * hinfo.cc (build_fhandler): Use new with placement. + (fhandler::operator new): New. + +Wed Jan 3 18:18:57 1996 steve chamberlain + + * select.cc: New file. + * Makefile.in: Cope with it. + +Tue Jan 2 08:58:58 1996 steve chamberlain + + * version.c: New file. + * Makefile.in: Cope with it. + * cygwin.def (setgrent, cuserid, setpgrp, mount, setmntent, endmntent, umount): New. + * dcrt0.cc: Remove obsolete vfork stuff. + (dll_crt0): Change way environ is built. Check that app is built + with correct version of dll. + * dirsearch.cc, exceptions.cc: Lint. + * fhandler.cc: Lint. Most of termios.c moved into here. + (fhandler_console:*): New. + * hinfo.cc (hinfo_vec::init_std_file_from_handle): Open stdfiles as consoles + if possible. + * libccrt0.cc: Lint. + * malloc.cc: More comments. + * path.cc (*): Cope with mount handling. + * registry.cc: Lint. + (reg_session): New. + * shared.cc: Lint. + * signal.cc (usleep): New. + * spawn.cc: Lint. Removed vfork stuff. + * stubs.c (getmntent, endgrent): Deleted. + * syscalls.c (__seterrno): Now takes arguments. + * termios.c: Much moved info fhandler.c + * times.cc (utime, utimes): New. + * uinfo.c (cuserid): New. diff --git a/winsup/cygwin/ChangeLog-1997 b/winsup/cygwin/ChangeLog-1997 new file mode 100644 index 000000000..7a5c0b3a4 --- /dev/null +++ b/winsup/cygwin/ChangeLog-1997 @@ -0,0 +1,2800 @@ +Wed Dec 31 15:00:32 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * hinfo.cc (hinfo_vec::find_unused_handle): correct + previous patch -- need to fix up vec[i].h pointers + +Wed Dec 31 14:13:22 1997 Ian Lance Taylor + + * regexp/Makefile.in (tooldir): New variable. + (install): Install regexp.h. + +Tue Dec 30 19:52:46 1997 Ian Lance Taylor + + * net.cc (inet_netof): New function. + (inet_makeaddr): New function. + * cygwin.din: Export inet_netof and inet_makeaddr. + +Tue Dec 23 17:45:07 1997 Ian Lance Taylor + + * path.cc (current_directory_name): New static variable. + (current_directory_posix_name): New static variable. + (getcwd_inner): Cache the directory name. + (chdir): Move here from syscalls.cc. Clear directory cache + variables. + * syscalls.cc (chdir): Remove; now in path.cc. + + * environ.cc (setenv): Add cast to avoid warning. + + * security.cc (get_file_attribute): Make file parameter a pointer + to const char. + (set_file_attribute): Likewise. + * winsup.c (get_file_attribute): Update declaration. + (set_file_attribute): Likewise. + + * path.cc (path_conv): Don't pass the root directory to + symlink_check_one. + +Mon Dec 22 16:34:40 1997 Ian Lance Taylor + + * path.cc (realpath): Use path_conv to resolve symlinks. + + * path.cc (path_conv::path_conv): Rewrite completely to convert to + win32 path first and then check for symlinks element by element. + (symlink_check_one): New static function based on old + symlink_check_worker, but without path conversion. + (path_prefix_p): Move definition before all uses. + (skip_n_slashes, symlink_expand, symlink_follow): Remove. + (symlink_check_worker, symlink_check): Remove. + (readlink): Rewrite to use new symlink_check_one. + (unmixedcaseify, mixedcaseify): Comment out. + * path.h (symlink_check, symlink_follow): Don't declare. + * fhandler.cc (open): Don't pass O_NOSYMLINK to path_conv. Set + errno from path_conv if it fails. + * dirsearch.cc (opendir): Check errors from path_conv, and set + errno appropriately. + * times.cc (utimes): Likewise. + * syscalls.cc (_unlink, _link, mkdir, rmdir, chdir): Likewise. + (chmod, _rename): Likewise. + (_stat_worker): Don't just pass nofollow to _open, but base + whether to pass O_NOSYMLINK on whether nofollow is set. + (lstat): Pass 1, not O_NOSYMLINK, to _stat_worker. + * strerror.cc (strerror): Add ELOOP. + +Thu Dec 18 12:30:47 1997 Ian Lance Taylor + + * fhandler.h (class fhandler_base): Remove inline definitions of + tcflush, tcsendbreak, tcdrain, tcflow, tcsetattr, tcgetattr, + tcsetpgrp, and tcgetpgrp, so that we can set proper errno values. + (class fhandler_tty): Add pgrp_ field, and virtual tcgetpgrp and + tcsetpgrp functions. + * fhandler.cc (fhandler_base::tcflush): New function. + (fhandler_base::tcsendbreak): New function. + (fhandler_base::tcdrain): New function. + (fhandler_base::tcflow): New function. + (fhandler_base::tcsetattr): New function. + (fhandler_base::tcgetattr): New function. + (fhandler_base::tcsetpgrp): New function. + (fhandler_base::tcgetpgrp): New function. + (fhandler_tty::fhandler_tty): Initialize pgrp_. + + * tty.cc (tcsetpgrp): Set errno correctly on failure. + + * include/sys/termios.h (CBAUD): Change to 037. + (B57600, B115200): Change to values that can fit in a speed_t. + + * spawn.cc (spawn_guts): Set errno correctly if we can't find the + executable. + +Mon Dec 15 16:40:07 1997 Geoffrey Noer + + patch from msnyder@cygnus.com (Michael Snyder): + * heap.cc (_sbrk): handle situation where newalloc < incr + +Mon Dec 15 16:40:07 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + Allow Cygwin32 to terminate process even when in a blocking + winsock call. + * exceptions.cc (call_handler): call to WSACancelBlockingCall() + removed. + (sighandle): call WSACleanup() before exiting the process to + cancel blocking winsock calls. + * include/mywinsock.h: add proto for WSACleanup(). + +Mon Dec 15 16:40:07 1997 Geoffrey Noer + + * Makefile.in: compile .cc files with -fno-exceptions to + decrease dll size and increase execution speed a little. + +Mon Dec 15 16:40:07 1997 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + * tty.cc (do_input): Detect CTRL-T as a special case when + STRACE_CACHE is active. Dumps the strace cache to disk. + * console.cc (fhandler_console::read): Detect CTRL-T as a special + case when STRACE_CACHE is active. Dumps the strace cache to disk. + +Sat Dec 13 15:12:53 1997 Ian Lance Taylor + + * fork.cc: Include . + (cygwin_fork_helper1): Call __malloc_copy after copying the stack + and heap to the child. + +Thu Dec 11 15:14:40 1997 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + * sigproc.cc (proc_subproc): Remove over-enthusiastic test for + process handling readiness or proc_wait will loop attempting to + handle a dying subprocess when signal handlers are not ready. + * fork.cc (cygwin_fork_helper1): Reorganize to ensure that a + forked process is capable of receiving signals when fork() + returns. + +Wed Dec 10 15:43:37 1997 Ian Lance Taylor + + * include/sys/termios.h (IXANY): Correct value. + (PARMRK): Define again. + +Wed Dec 10 00:05:23 1997 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + * dcrt0.cc (dll_crt0_1): Move start time initialization to a more + logical place (pinfo_init). + (do_exit): Reorganize to attempt to solve races when a cygwin + process occupies two windows pids (i.e., an execed process). + * exceptions.cc (lock_cs): Fix erroneous WFSO logic. + (sighandle): Use new method for determining if process was + initiated via fork. + (events_terminate): Do not close pinfo_mutex. Allow automatic + close by ExitProcess to lengthen the time that the pinfo structure + is locked, minimizing races between an exiting child and a + potentially exiting parent. + * hinfo.cc (hmap_init): Use new method for determining if process + was initiated via fork. + (hinfo_vec::de_linearize_fd_array): Fix a typo in a comment. + * pinfo.cc (clearout): Remove this function. Handled in + allocate_pid. + (pinfo_init): Move start_time setting here from dll_crt0_1. + Remove call to init_self in favor of adding three additional lines + of code. + (pinfo_list::operator []): Implement a very simple hashing + scheme for pid lookup. + (lpfu): New routine controlled by DEBUGGING conditional. When + DEBUGGING is activated, lpfu returns more information about the + state of a timed out pinfo_mutex. + (pinfo_list::get_empty_pinfo): Remove function. Move + functionality to allocate_pid. + (allocate_pid): Implement a (very) simple hashing scheme for + finding an available pid. Take advantage of reorganized pinfo + structure to zero all pertinent fields with one memset. + (pinfo::record_death_nolock): Don't bothering zeroing + inconsequential stuff. + (pinfo::record_death): Leave pinfo_mutex locked with the + understanding that this function will be called just prior to + exiting the process. This minimizes a race between a child which + is exiting at nearly the same time as its parent. + * sigproc.cc: Reformat function calls. + (sigproc_init): Clear new PID_INITIALIZING flag to indicate that + a (possibly execed) process is now capable of receiving signals. + (sig_send): Be more defensive in determining if a signal can be + sent to myself or suffer problems with execed processes. + (sigproc_terminate): Wait for sig_proc to exit to ensure that + all pending signals have been handled. Use new 'proc_terminate' + function to terminate the subprocess handling thread. + (allow_sig_dispatch): Don't bother blocking signals if signal + handling isn't active in this process yet. + (block_sig_dispatch): Don't bother blocking signals if signal + handling isn't active in this process yet. + (sig_proc): Use sig_loop_wait variable to control wait time for + signal semaphores. Uncouples this wait from wait_subproc. + Perform signal cleanup here on thread termination. + (proc_exists): More accurate tests to determine if a process + really exists. + (proc_register): Remove this function in favor of a macro. + (proc_subproc): More stringent test for being "ready" to process + subprocesses. Add more common initialization to PROC_ADDCHILD. + Remove PROC_EXIT in favor of a separate function. + (proc_terminate): New function. Replaces PROC_EXIT functionality + in proc_subproc. Terminates subproc handler thread. + (stopped_or_terminated): use lock_pinfo_for_update when modifying + child stopsig status or suffer a race. + (wait_subproc): Save sig_proc thread handle away for + synchronization when exiting. Set up 'i_am_alive' mutex inherited + by childen. Child's inability to lock this mutex means that the + parent is still alive and processing children. Use proc_loop_wait + to control WFMO. Clean up events queue on thread exit. + (zap_subproc): Clear out pinfo structure for a child. + * sigproc.h: Remove PROC_EXIT constant. Remove obsolete + proc_register declaration. + (alive_parent): New macro to determine if a parent is still alive. + * spawn.cc (spawn_guts): Fix a comment typo. Use proc_terminate + to terminate all subprocess handling prior to an exec. Use new + method for determining if this process was started via a fork. + Attempt to clean up races between execed process, its parent, and + the execed child. + * winsup.h (pinfo): Add a new handle indicating that a parent is + alive. This should be a foolproof way of determining if a parent + has gone away so that a child will know whether to remove itself + from the pinfo table. + Reorganize the structure in such a way that items to be zeroed + are grouped together at the beginning for more efficient zeroing + in allocate_pid. + Add a new PID_* constant. + New lock_pinfo_for_update macro for use when debugging cygwin. + +Wed Dec 10 00:05:23 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + Change the way to inherit fd table on spawn/exec calls. + Use STARTUPINFO structure to pass an fd table to a child process + instead of shared memory area. This is undocumented, but is used + by MSVC runtime. The desktop inheritance code added again, + otherwise user32.dll will fail to initialize after sexec calls. + * pinfo.cc (pinfo_init): delinearize fd array from STARTUPINFO + structure instead of call to copy_shared_fd_table. + * shared.cc (create_shared_fd_mapping_name): remove + (create/copy_shared_fd_table): remove + * spawn.cc (spawn_guts): use lp(cb)Reserved2 fields of STARTUPINFO + to pass fd table to a child. Remove call to + create_shared_fd_table. Inherit window station/desktop on sexec + calls. + * winsup.h: remove prototypes for create/copy_shared_fd_table. + +Fri Dec 5 18:57:42 1997 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + * kill.cc (main): Report error if kill() fails. Minor reformat. + * ps.cc (main): Only use month/day in start time when starting + time is > 24 hours in the past, not when it occurs yesterday. + +Fri Dec 5 15:54:41 1997 Geoffrey Noer + + * fcntl.cc (_fcntl): reformat + * fhandler.cc (fhandler_tty::open): new, need special open for + ttys. In addition to calling fhandler_base::open, check + flags to handle blocking vs. non-blocking I/O. Should + initialize tty to standard state (9600 bits/sec - 8 - 1 with + no flow control) but this code needs more work still. Ifdef + out for now. + (fhandler_tty::tcsendbreak): new + (fhandler_tty::tcdrain): new + (fhandler_tty::tcflow): new + (fhandler_tty::tcsetattr): add support for action arg. Use + a DCB struct to hold the values we will set. First call + GetCommState to get the current state, then reassign values + based on the contents of the termios struct. Handle the + case where t->c_ospeed is set to B0, otherwise set state.BaudRate. + Set all the other DCB struct values appropriately, based on + the contents of the termios struct. + (fhandler_tty::tcgetattr): do the inverse of tcsetattr. + Call GetCommState to get the current state and use this to set + the appropriate termios struct values. + * termios.cc: reformat + (tcsendbreak): implement -- add duration arg, + call fhandler tcsendbreak as appropriate + (tcdrain): implement -- call fhandler tcdrain as appropriate + (tcflow): implement -- call fhandler tcflow as appropriate + * fhandler.h: add new tc* protos + * include/sys/termios.h: correct values of iflag bits, + define CRTSXOFF and CRTSCTS, CBAUD, B57600 and B115200. + Add protos for tc* functions. + +Wed Nov 26 17:06:17 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * spawn.cc (perhaps_suffix): resolve symlinks to .exes. + +Mon Nov 24 17:10:49 1997 Geoffrey Noer + + * cygwin.din: remove crypt + * syscalls.cc (crypt): remove crypt stub + +Sun Nov 23 17:34:42 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * spawn.cc (spawn_guts): save the path of the script itself, + use the saved path while building the command line to execute. + +Thu Nov 20 22:58:23 1997 Geoffrey Noer + + * stubs.cc: delete file, move unimplemented stubs to the + files in which they would normally belong. + * grp.cc (setgrent): implement (was in stubs.cc) + * syscalls.cc: move regfree, mknod, setgid, set(e)uid, sync, + crypt, and PPC __chkstk/_alloca/dll_entry stubs here from stubs.cc + (sync): just return zero for now instead of -1 + (crypt): return -1 instead of 0 + +Thu Nov 20 22:41:57 1997 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + * spawn.cc (spawn_guts): A premature close of the spawned filehandle + was possible when reparenting an exited process. Fix this. + * dcrt0.cc (do_exit): Only do minimal cleanup if "pid focus" + has moved to another windows process or the other process will + become confused. + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * sigproc.cc (getsem): set errno to EPERM if existing semaphore + cannot be opened. + (wait_subproc): allow access to signal semaphores to process's + owner only except for SIGCHLD (needed for SIGCHLD delivery after + sexecXX calls). + +Thu Nov 20 00:52:58 1997 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + * syscalls.cc (hash_path_name): Ignore trailing backslash when + calculating pathname hash. + * hinfo.cc (hinfo_vec::de_linearize_fd_array): Set use_tty + if /dev/ttyn is detected in the shared_fd_table. Before this + change, executing "set CYGWIN_TTY=1", "bash", "unset CYGWIN_TTY", + "/bin/pwd" would result in pwd printing nothing because + the de_linearize code would use the wrong fhandler_xxx when + reading from the buffer inherited from the parent process. + * cygwin.din: Add new ctermid function for export. + * syscalls.cc (ctermid): New function + * exceptions.cc (call_handler): If called during a P_OVERLAY + spawn, merely set appropriate flags and return. The spawn + code will then clean up and exit. + * sigproc.cc (proc_exists): Reorganize to better detect defunct + processes. Don't clean up pinfo if process has a parent since the + parent should clean up eventually. + * spawn.cc: New global exec_exit. Set by signal handler to + value which should be used on exit from aborted spawn. + (spawn_guts): Try harder to let the child terminate (if it is + going to) before exiting on a signal. Remove obsolete code. + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * exec.cc (file_exists): Removed + * spawn.cc (spawn_guts): call perhaps_suffix to convert filename + to win32 form and to check file existance; prog variable + removed, all references changed to real_path variable. + Do not inherit parent's window station/desktop on sexecXX calls. + They are no longer needed with the new signal handling. + (_spawnve): extra file existance check removed + * winsup.h: file_exists prototype removed + +Wed Nov 19 16:23:47 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * cygwin.din: add missing exports for random -- initstate + and setstate (accessed by gawk among others?) + +Tue Nov 18 22:27:10 1997 Geoffrey Noer + + * Makefile.in: Add spaces after colons in rules for make + +Mon Nov 17 22:35:25 1997 Geoffrey Noer + + patch from proven@cygnus.com (Chris Provenzano): + * Makefile.in: set SHELL = @SHELL@, set VPATH to only @srcdir@. + Remove mingw from directories to build for now, adapt rules + for building sysdef files without fancy VPATH + * configure: regenerate + * config/i386/makefrag: add rules to build setjmp/longjmp + * regexp/Makefile.in: set SHELL = @SHELL@ + * regexp/configure: regenerate + * utils/Makefile.in: set SHELL = @SHELL@ + * utils/configure: regenerate + +Mon Nov 17 18:36:50 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * fhandler.cc (fhandler_disk_file::open): calls to symlink_XXX + replaced with path_conv class calls. + * path.cc (path_conv::path_conv): comments added, O_NOSYMLINK case + added. + * path.h (class path_conv): symlink_p, exec_p - new class members. + * spawn.cc (spawn_guts): call path_conv instead of symlink_follow. + +Sun Nov 16 15:54:27 1997 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + * dcrt0.cc (do_exit): Use new pinfo element in debug statement. + * pinfo.cc (pinfo_init): Eliminate use of "PID" environment + variable in favor of scanning the process table for a + SpawnedProcessId field matching current windows process id. + Should speed up spawned process startup slightly. Delay setting + of dwProcessId until process is capable of processing signals + since this field is used to build signal semaphores. + * signal.cc (kill_worker): Perform a `proc_exists' on the pid + in question if signal == 0. This will verify that the process + actually exists and was not abnormally terminated. + * sigproc.cc (sigproc_init): Initialize dwProcessId field after + signal processing has been initialized. + (sigproc_terminate): Remove events[0] close. + (getsem): Use GetCurrentProcessId to find the windows pid since + this dwProcessId field is not yet set up. Use proc_exists to + determine if error should be printed on OpenSemaphore error. + (proc_exists): New function. Makes more exhaustive test of + process existence. Determines if process died without going + through normal shutdown. + (wait_subproc): Close wakeup event only on thread exit. + * spawn.cc: Remove pExeced. Use new field in pinfo. + (spawn_guts): Initialize dwSpawnedProcessId field. + * utils/ps.cc (main): Perform a kill(pid, 0) on any pids that + appear to be active. This will clear out pids that have died + abnormally. 'ps -f' bypasses this. + * winsup.h (class pinfo): Add dwSpawnedProcessId field. + +Sun Nov 16 15:54:27 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * pinfo.cc ((pinfo_init): use dwProcessId for execed/spawned + check, set subproc_ready event only if the process is exec'ed. + * spawn.cc (spawn_guts): initialize hProcess and dwProcessId + fields of pinfo on exec, keep progname field on spawn. + +Sun Nov 16 15:54:27 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * dcrt0.cc: remove commented out code + * spawn.cc: fix misapplied patch problem + +Sun Nov 16 15:54:27 1997 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + * fhandler.cc (fhandler_dev_null::open): Open Windows 'nul' + device rather than "faking" a real open. + (fhandler_dev_null::close): delete. + (fhandler_dev_null::fstat): delete. + (fhandler_dev_null::ioctl): delete. + (fhandler_dev_null::read): delete. + (fhandler_dev_null::write): delete. + (fhandler_dev_null::lseek): delete. + (fhandler_dev_null::dup): delete. + * fhandler.h (class fhandler_base): delete above methods from + class. + * hinfo.cc (hinfo_vec::build_fhandler): Use new fhandler_dev_null + class which opens 'nul' device. Treat /dev/null similarly to + other Windows devices. This allows redirection of /dev/null to + non-cygwin processes. + +Sun Nov 16 15:54:27 1997 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + * dcrt0.cc (do_exit): Use EXIT_* flags to determine how exit + should proceed. Honor new EXIT_NOCLOSEALL to avoid + close_all_files. + * exceptions.cc (__cygwin32_exception_handler): Use new + EXIT_SIGNAL define to indicate exiting due to signal. + * signal.cc (sigprocmask): Slightly more defensive check against + being called prior to complete cygwin setup. + (_raise): Defensive check to guard against being called prior to + complete cygwin setup. + * sigproc.cc (stopped_or_terminated): Use new EXIT_SIGNAL define + to detect exiting due to signal. + * sigproc.h: Define flags to be used during exit process as + EXIT_*. + * spawn.cc (spawn_guts): Use EXIT_* constants to control how + do_exit proceeds after _P_OVERLAY. + +Sun Nov 16 15:54:27 1997 Geoffrey Noer + + * sysconf.cc (sysconf): return 1048576 for ARG_MAX until + we figure out the right value (_POSIX_ARG_MAX is only 4K + which is too small). + +Sun Nov 16 15:54:27 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * dcrt0.cc (dll_crt0_1): call winsock_init if neccesary. + * fhandler.cc ((fhandler_socket::fhandler_socket): moved to net.cc + * fhandler.h (class fhandler_socket): destructor prototype added. + * fork.cc (cygwin_fork_helper1): set PID_SOCKETS_USED in the + child's pinfo if parent has open socket descriptors; call + winsock_init in child code if necessary. + * net.cc: static variable winsock_init_p removed; + number_of_sockets is new global variable containing number of + opened sockets. + (winsock_init): made global, save "winsock inited" flag in process + state field. + (cygwin32_winsock calls): condition for winsock initialisation + changed + (fhandler_socket::fhandler_socket): new, moved from fhandler.cc; + increment number_of_sockets on constructor call. + (fhandler_socket::~fhandler_socket): new. Decrement + number_of_sockets on destructor call, check for negative value. + (fhandler_socket::ioctl): check for winsock initialisation added. + * spawn.cc (spawn_guts): handle PID_SOCKETS_USED in child's pinfo. + * winsup.h: PID_SOCKETS_USED - new enum value; number_of_sockets + and winsock_init() prototypes added. + +Wed Nov 12 23:02:34 1997 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + * exceptions.cc: Substitute do_exit for _exit as appropriate. + do_exit allows full 32 bits of exit value. The upper 16 bits + are used for special cygwin operations. + * winsup.h: Change definition of do_exit to allow calling from + signal handler. + * dcrt0.cc (do_exit): Change to allow calling from signal handler + in place of _exit. This is necessary to ensure that only cygwin + internal applications can exit with the upper order 16 bits set + to non-zero. + +Wed Nov 12 23:02:34 1997 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + * dcrt0.cc (do_exit): New function. Subsumes functionality of + _exit but takes a DWORD argument. Changed to avoid some shutdown + activities when called with REPARENTING bit set in argument. Also + explicitly kills any executing non-cygwin subprocess from a + spawn(P_OVERLAY)... + (_exit): Use do_exit for exiting. Ensure that only low order 1 + bits of status are used or confusion will result if exiting with + some higher order bits set. + * exceptions.cc (set_process_mask): Reflect new method for + sig_send to send signals to self. + (handle_sigsuspend): Reflect new method for sig_send to send + signals to self. + * fork.cc: A handle name was changed in the pinfo structure to + be more reflective of its use. Change forkee_stopped to + subproc_ready everywhere. + * pinfo.cc (pinfo::clearout): Change forkee_stopped to + subproc_ready. + (pinfo_init): Use PID_EXECED flag to determine if this process has + been execed. If so, signal the remaining stub in the process + which invoked us so that the stub can terminate and let us take + over as this pid. + * sigproc.cc (sig_send): Change method for determining if sending + signals to myself. A NULL pointer means communicate with my + signal handler. This is necessary to allow communication with + our own signal processors after reparenting an execed process. + Also, add an additional test to detect if a process goes away in + the middle of attempting to send it a signal. + (allow_sig_dispatch): Reflect new method for sig_send to send + signals to self. + (getsem): Use dwProcessId in names for signal semaphores. Allows + communicating with both parts of a process that is temporarily + "split in two" while execing. + (sig_proc): Avoid printing an error if WAIT_FAILED and exiting + anyway. Process requests even if loop_wait == 0. + (proc_subproc): Defensive check for manipulating processes prior + to initialization or after terminating sigproc. + Use different check for subprocesses that have been reparented. + Hopefully this will eliminate WFSO, error 6 problems. + (wait_subproc): Only exit when loop_wait == 0 and not dealing with + a process. + * spawn.cc: Set up two global variables, used on exit when + execing a non-cygwin process: hExeced - handle of non-cygwin + process which is being waited for by a stub, pExeced - windows pid + of the process. + (spawn_guts): Reorganize to always (temporarily) wait for the new + process when P_OVERLAY. If a cygwin process is invoked, then the + wait will return when an event is signalled and the new process + will be "reparented" in the ppid. If a non-cygwin process is + invoked, wait until the process exits or a signal is received + which terminates the process. In this case, the do_exit function + will terminate the non-cygwin process. + * winsup.h: Rename forkee_stopped to subproc_ready since this + event now has a dual role which is better defined by this new + name. Add a new flag (PID_EXECED) for process_state. Define a + new function `do_exit' which operates similarly to _exit + but takes > 16 quantities with the high order bit signifying + different exit actions. + +Mon Nov 10 17:11:08 1997 Geoffrey Noer + + * include/utime.h: remove (moved to newlib/libc/sys/cygwin32/sys) + so as not to conflict with the one in newlib/libc/include. + +Mon Nov 10 15:11:42 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * exceptions.cc (__cygwin32_exception_handler): exit with + "core dumped" exit code after writing "core" file. + +Mon Nov 10 15:11:42 1997 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + * console.cc: Add convenience macros and structures for handling + scrolling. + (fhandler_console::fillin_info): New function to fill in the `info' + struct. + (fhandler_console::scroll_screen): Change to scroll only the visible + portion of the screen. Honor scroll regions more stringently. + (fhandler_console::open): Use new fillin_info function. + (fhandler_console::ioctl): Use new fillin_info function which + automatically calculates screen size. + (fhandler_console::clear_screen): Use new fillin_info function. + Only clear visible portion of screen. + (fhandler_console::cursor_set): Add a flag to indicate whether + cursor positioning is absolute within buffer or is screen relative. + Use new fillin_info function to get screen information. + (fhandler_console::cursor_rel): Use new fillin_info function. + Change for new cursor_set parameter. + (fhandler_console::cursor_get): Use new fillin_info function. + (fhandler_console::char_command): Use new fillin_info function + where appropriate. Change for new cursor set parameter where + appropriate. Scroll only visible portion of screen when required. + * fhandler.h (class fhandler_console): Add fillin_info, change + cursor_set to reflect additional argument. + +Mon Nov 10 15:11:42 1997 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + * dcrt0.cc (dll_crt0_1): Register process start time. + * fork.cc (cygwin_fork_helper1): Register process start time. + * utils/ps.cc (main): Report process start time. + (start_time): New function to format time similarly to UNIX ps. + A time from today shows as HH:MM, times from previous days just + show the month and day. + * winsup.h (class pinfo): Add start_time field. + +Mon Nov 10 11:54:27 1997 Ian Lance Taylor + + * include/Windows32/Defines.h (TIME_ZONE_ID_INVALID): Define. + * times.cc (gettimeofday): The error return from + GetTimeZoneInformation is TIME_ZONE_ID_INVALID, not + TIME_ZONE_ID_UNKNOWN. + +Sun Nov 9 17:08:30 1997 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + * Makefile.in: add ../libiberty/strsignal.o + * cygwin.din: add exports for strsignal, strtosigno + * utils/kill.cc: changes to allow accepting signal name + as argument + +Sun Nov 9 17:08:30 1997 Geoffrey Noer + + * include/limits.h: define PATH_MAX here instead of + include/sys/param.h, define _POSIX_NGROUPS_MAX as 0 not 1 + (system invariant value, not implementation-specific) + * include/sys/param.h: remove PATH_MAX, change NOFILE from 64 + to 8192, delete PATHSIZE, remove safety wrapper around + MAXHOSTNAMELEN, add comments + * sysconf.cc (sysconf): return NGROUPS_MAX not zero, + return _POSIX_SAVED_IDS not zero. Return _POSIX_CHILD_MAX + not 4096. Return _POSIX_CHILD_MAX, not 8. + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * winsup.h: add proto for setdtablesize, define NOFILE_INIT + and NOFILE_INCR + * hinfo.cc (hmap_init, hinfo_vec::find_unused_handle): change to + support virtually unlimited numbers of fds. Remove setdtablesize + proto + * syscalls.cc: initialize dtable_size to NOFILE_INIT instead of + NOFILE + +Thu Nov 6 13:14:09 1997 Geoffrey Noer + + * exceptions.cc (__cygwin32_exception_handler): don't + print "In cygwin32_except_handler" for exceptions Cygwin32 + isn't going to handle. Print "(progname PID) Exception: " + to console. Redirect all detailed information including the + stack trace to .core. This should reduce confusion + about what's causing the exception (a lot of people would see "In + cygwin32..." and think the problem was in Cygwin32 when most of + the time it was in some other program). + * syscalls.cc: add fixme + * times.cc: add fixme + +Wed Nov 5 19:23:10 1997 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + * Makefile.in: force .c.os and .cc.os to be built in same + directories as source + +Wed Nov 5 19:23:10 1997 Geoffrey Noer + + * drct0.cc (dll_crt0_1): stop initializing winsock on process + startup since that slows down startup time of all processes, even + ones that don't end up making Winsock calls. + * fork.cc (cygwin_fork_helper1): don't need to call uinfo_init + or socket_checkinit after fork -- the appropriate functions will + do the necessary initialization if they are ever called. + * net.cc: init winsock_init_p to zero and make it static + (all exported functions): call winsock_init before making + any WinSock calls since this no longer happens in dcrt0.cc + startup code. Only do this if !winsock_init_p. + (winsock_init): checkinit renamed. Now just inits winsock + without checking whether it has been already initialized. + Make it static. + * uinfo.cc (uinfo_init): after we call getpwnam, we know + the passwd file has been read in so don't check initialization + of it. However, we do need to read_etc_group() if group_in_memory + isn't set. + * passwd.cc: rename global i variable to pw_pos, rename + passwd_in_memory to passwd_in_memory_p to match net.cc scheme. + Add comments. + (read_etc_passwd): make static + (various): make sure to read_etc_passwd() if passwd_in_memory + isn't set + * grp.cc: add comments, rename idx global to grp_pos, + rename group_in_memory to group_in_memory_p to match net.cc + scheme, group_in_memory_p no longer static (needs to be accessed + by uinfo_init) + * winsup.h: remove proto for socket_checkinit since that's + renamed and static within net.cc + +Tue Nov 4 01:02:20 1997 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + * signal.cc (sigprocmask): Newer versions of gcc will call + sigprocmask when a builtin constructor is activated. If this + happens prior to the setup of u->self, then a NULL dereference + will occur. Guard against this. + +Mon Nov 3 17:00:45 1997 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + * hinfo.cc (hinfo_vec::build_fhandler): Open a console for + /dev/tty when !use_tty. + +Thu Oct 30 10:28:15 1997 Tom Tromey + + * include/mapi.h: New file. + * sysdef/i386/mapi32.def (MAPISendMail@20): New export. + +Thu Oct 30 15:08:13 1997 Geoffrey Noer + + * times.cc: add comments listing standards funcs are defined in + (dump_filetime): remove unused local func + * net.cc (fail): remove local func, replace one reference with + equivalent debug_printf, add standards comments, reformat a little + (fhandler_socket::close): simplify handling of res + (fhandler_socket::fstat): set ENOSYS (unimplemented) + * stubs.cc: set ENOSYS in unimplemented funcs + * uname.cc: add standards comment + * ntea.cc: reformat + +Wed Oct 29 22:43:57 1997 Geoffrey Noer + + * times.cc (settimeofday): set ENOSYS instead of EPERM + since ENOSYS maps to "Function not implemented" which is the + case here. + * syscalls.cc (seterrno): on failure, set EACCES instead of EPERM + which is better for the unknown error case + +Fri Oct 24 01:24:07 1997 Geoffrey Noer + + patch from green@cygnus.com (Anthony Green): + * dcrt0.cc: new host_dependent_constants object with a global + instance of it which allows constants that are different in Win 95 + and NT to be saved here instead of having forks in the code and + having to check the OS type each time. Add two constants for + fhandler, one for sharing attributes and one for upper word value + for locking files. + (dll_crt0_1): call host_dependent init function + * fhandler.cc (fhandler_base::open): use above object for + setting shared attributes + (fhandler_disk_file::lock): get upper word for locking from + host_dependent_constants + * winsup.h: define host_dependent_constants class and add extern + for global instance of it + +Wed Oct 22 02:27:53 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * cygwin.din: Export getenv, putenv, setenv and unsetenv instead + of cygwin32_ wrappers + * dcrt0.cc: External variable environ removed + (dll_crt0_1): strip executable's path on console title if + environment variable CYGWIN_TITLE set to "strip", references to + environ removed. + * environ.cc: New file. Code derived from newlib sources. + * exec.cc: include stdlib.h + (execl, execv): new (derived from newlib sources). + (sexecve): reference to environ removed. + (sexecvpe): call getenv instead of cygwin32_getenv. + * grp.cc: new static variable group_in_memory + (read_etc_group): skip blank lines + (getgrgid, getgrnam, getgrent): call read_etc_group when necessary. + * misc.cc (cygwin32_getenv/putenv/setenv/unsetenv): remove + wrappers. + * passwd.cc: new static variable passwd_in_memory + (read_etc_passwd): skip blank lines + (search_for, getpwent): call read_etc_passwd when necessary. + (setpwent): fixed incorrect initialization of i var. + * pinfo.cc (pinfo_init): initialize uid with illegal value to + force read of /etc/passwd and /etc/group. + * spawn.cc: call getenv instead cygwin32_getenv + (spawn_guts): force read of /etc/passwd and /etc/group on sexec + calls. + * uinfo.cc (uinfo_init): read /etc/passwd and /etc/group only if + uid is undefined. + * winsup.h: remove protos for environ, cygwin32_getenv, + cygwin32_putenv + +Wed Oct 22 02:08:54 1997 Geoffrey Noer + + * utils/aclocal.m4: new file. Define autoconf macros for + determining whether we're compiling for the cygwin32 environment + or not and determine the executable suffix + * utils/configure.in: call AM_CYGWIN32 and AM_EXEEXT + * utils/configure: regenerate + * utils/Makefile.in: add $(exeext) after executable names so + programs will be built with the .exe suffix + +Wed Oct 22 00:50:27 1997 Geoffrey Noer + + Now that it is possible to use gdb using a stable + cygwin.dll to debug a program using a newer, potentially buggy + cygwin.dll, the strace mechanism will probably end up being + used more and more for debugging timing/race-condition bugs that + aren't easily exposed in a gdb session. The following changes + make the strace facility better for debugging timing issues by + storing the last few commands in a buffer instead of writing + to disk each function call. + + patch from cgf@bbc.com (Chris Faylor): + * dcrt0.cc (dll_crt0_1): Change to strace_init call to take + an argument (for planned future registry changes). + (_exit): Call strace_dump when appropriate. Add a debugging + printf. + * include/sys/strace.h: Add _STRACE_CACHE, _STRACE_EXITDUMP, + strace_dump (). + * strace.c (strace_init): Allow hexadecimal, octal setting of + strace flags in environment variable. Handle new cache option. + (strace_printf): Display number of seconds from last message. + Handle _STRACE_CACHE. + (strace_dump): New function. Dump cached messages to disk. + +Wed Oct 22 00:08:40 1997 Geoffrey Noer + + * cygwin.din: export socket calls without cygwin32_ prefix + * net.cc: remove unused herror function in favor of + cygwin32_herror which is exported as herror + * include/netdb.h: we are now exporting the socket calls without + the cygwin32_ prefix so we don't need the nasty remapping in + header files + * include/arpa/inet.h: ditto + * include/sys/socket.h: ditto + * select.cc (select): make extern C + +Tue Oct 21 22:52:29 1997 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + * sigproc.cc (sigproc_terminate): Fix flawed attempt to signal + any processes waiting for signal notification success when the + process receiving the signal is terminating. + (wait_subproc): Report on errors when opening the + sync_proc_subproc mutex. Move initialization of events[0] + "wakeup" signal prior to wait_subproc_inited or risk a (miniscule) + chance for a reference to a NULL handle. + * strace.cc (ta[]): Change WM_ASYNCIO entry to reflect previous + changes to WM_ASYNCIO constant. + +Tue Oct 21 14:30:14 1997 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + * sigproc.cc (proc_subproc): fix minor error output problem + +Mon Oct 20 20:19:02 1997 Geoffrey Noer + + * Makefile.in: change DLL_NAME to cygwin97r2.dll + +Mon Oct 20 20:16:47 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * window.cc (alarm): When there is a previous alarm() request + with less than one second remaining, then the return from a call + to alarm() is supposed to return 1. + +Mon Oct 20 20:16:47 1997 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + * Makefile.in: Add sigproc.o target. Add sigproc.h dependency + where appropriate. Add -s to intermediate ld of cygwin.dll to + speed up the process of building the .dll. + * dcrt0.cc: Add new sigproc.h include. + (dll_crt0_1): Replace window_init with sigproc_init for + initialization of signal/sub process handling. Change to use new + process_state field in pinfo. + (_exit): Remove spurious debugging statement. Terminate sigproc + processing. Remove signal blocking obviated by previous signal + termination. Remove SIGCHLD notification of parent as it is now + handled automatically in the parent. + (api_fatal): Terminate sigproc processing. + * exceptions.cc: Add new sigproc.h include. Change name of + ourhThread. + (ctrl_c_handler): Change to static as this is no longer called + outside of this module. + (lock_cs): Change to a function which will optionally grab new + signal dispatch mutex. Don't wait forever for cs mutex. + (unlock_cs): Change to a function which will optionally release + new signal dispatch mutex. + (init_exceptions): Detect errors from SetConsoleCtrlHandler. + Initialize new sig_dispatch mutex. This mutex is used to + control dispatching to a function on signal receipt. + (sig_dispatch_pending): New function. Called from signal + processing thread to dispatch pending signals. + (set_process_mask): Block signal dispatch during setting of new + mask, if possible. Contact signal thread to dispatch pending + signals. + (handle_sigsuspend): New function. Attempts to implement a + sigsuspend which will not lose signal notification. Called from + sigsuspend. + (call_handler): Use sigproc_printf where appropriate. + (ctrl_c_handler): Use _raise to invoke the correct signal. + (sighandle): New function. Subsumes most of ctrl_c_handler. + Change to mark as suspended signals which would dispatch for which + the sig_dispatch mutex is unavailable. Use sigproc_printf where + appropriate. + (events_init): Remove application_stopped mutex made obsolete by + new sigproc handling. + (events_terminate): Remove application_stopped mutex made + obsolete by new sigproc handling. + * fork.cc: Add new sigproc.h include. + (cygwin_fork_helper1): Use process_state field in pinfo (replaces + inuse_p). Call proc_register to add a new subproc to sigproc + handling. Call sigproc_init for new subprocess. Remove obsolete + window_init. + * heap.cc (_sbrk): Use process_state field in pinfo (replaces + split_heap_p). + * hinfo.cc (hmap_init): Use process_state field in pinfo (replaces + cygwin_parent_p). + * include/sys/strace.h: Add tracing for signal/subprocesses. + * init.cc: Add new sigproc.h include. Add waitq_storage global + for new sigproc handling. + (dll_entry): Add initialization, destruction of structures needed + by new sigproc handling. + * net.cc (fhandler_socket::ioctl): Use gethwnd() function to find + hwnd of hidden window. + * pinfo.cc: Add new sigproc.h include. + (pinfo::clearout): Use process_state field in pinfo (replaces + split_heap_p). Explicitly initialize various handles to NULL. + (pinfo_init): Use process_state field in pinfo (replaces + cygwin_parent_p). + (pinfo_list::operator): Use process_state field in pinfo (replaces + inuse_p). + (pinfo_list::alocate_pid): Initialize process_state field. + (pinfo::init_self): Remove obsolete initialization of hProcess. + (pinfo::record_death_nolock): Changes for new sigproc handling. + (pinfo::record_death): Move bulk of this code to sigproc.cc. + (pinfo::terminate): Remove function made obsolete by sigproc + handling. + (pinfo::init_from_exec): Use process_state field (replaces + inuse_p). + * signal.cc: Add new sigproc.h include. + (kill_worker): Call new sig_send function to send signals to + cygwin processes. + (_kill): Use process_state field in pinfo (replaces inuse_p). + (sigsuspend): Call handle_sigsuspend in exceptions.cc to handle + sigsuspend in a non-raceable way. + * sigproc.cc: New signal/subprocess handling module. Replaces + SendMessage method for signals with a method using semaphores. + Also detects changes in the state of child processes. + * sigproc.h: New header file defining constants and functions for + signal/subprocess handling. + * spawn.cc: Add new sigproc.h include. Clean up trailing spaces. + (spawn_guts): Reorganize to use new sigproc handling. + Use new pinfo process_state field (replaces inuse_p). + * syscalls.cc (_read): Use new pinfo process_state field (replaces + inuse_p). + (_write): ditto. + * tty.cc (tty_init): Use new pinfo process_state field (replaces + cygwin_parent_p). + * utils/ps.cc (main): Use new pinfo process_state field (replaces + inuse_p). Detect "zombie" processes similarly to UNIX ps. + * wait.cc: Add required includes. + (wait_found): Function obsoleted by new sigproc handling. + (wait4): Reorganize to use new sigproc handling. + * window.cc: Changes for new sigproc handling. + (WndProc): Remove SIGNAL handling obsoleted by new sigproc + handling. Use static window handle since the field has been + removed from pinfo. Use _raise where appropriate to send signals. + (Winmain): Replace global window handle with static since the + field has been removed from pinfo. + (window_init): Remove obsolete function. + (gethwnd): New function to allocate hidden window on demand rather + than at startup. + (window_terminate): Kill hidden window only if allocated. + (setitimer): Use gethwnd function to retrieve hidden window + handle. + * winsup.h: Remove stuff made obsolete by sigproc handling. Move + some constants to new sigproc.h header file. Remove inuse_p, + cygin_parent_p, split_heap_p. Replace with a single process_state + field. Define bit fields for process_state in an enum for easier + debugging. + +Mon Oct 20 19:17:33 1997 Geoffrey Noer + + * sysdef/i386/winserve.def: remove ancient version of cygwin.din + * include/sgtty.h: remove since Cygwin32's tty handling doesn't + support bsd syntax/semantics + * include/sys/termios.h: change winsize struct to include + ws_xpixel and ws_ypixel members + * cygwin.din: remove export of ScreenCols, ScreenGetCursor, + ScreenRows, ScreenSetCursor, get_pid__5pinfo, getkey, _getkey, + kbhit, _kbhit, __small_printf = small_printf__FPCce + * key.cc: remove. Similar functionality exists in ncurses + which can be compiled for Cygwin32 + * console.cc (ScreenCols, ScreenGetCursor, ScreenSetCursor, + ScreenRows): delete and delete SCREEN_ROWS/COLS defines + * pold.c: remove old pipe-related code that's no longer used + * include/regex.h: remove, it's not a part of cygwin.dll + * syscalls.cc: started to add comments including standards + information + (truncate): new + (ftruncate): length is an off_t, not a size_t. Add missing + return value to debug printf + * syscalls.h: ftruncate length is an off_t, add proto for truncate + + patch from cgf@bbc.com (Chris Faylor): + * console.cc (fhandler_console::write): Recognize '@' as a valid + character to follow a '\e[' sequence or get 'Bad escape' errors. + +Wed Oct 15 18:44:25 1997 Geoffrey Noer + + * cygwin.din: restore __main as an export + +Mon Oct 13 18:41:09 1997 Geoffrey Noer + + * cygwin.din: revert renaming of __assert since that's + actually what it's supposed to be called + * assert.cc: ditto + +Fri Oct 10 19:25:49 1997 Tom Tromey + + * include/Windows32/Base.h: Moved typedefs of CHAR, SHORT, etc, + before all other uses in file. + +Fri Oct 10 17:50:12 1997 Ian Lance Taylor + + * include/Windows32/Base.h: Only typedef CHAR, SHORT, and LONG if + VOID is not defined + +Thu Oct 9 00:46:40 1997 Geoffrey Noer + + * cygwin.din: remove all libgcc.a exports. They don't + belong here since libgcc.a doesn't really relate to the + purpose of cygwin.dll, and (to make things worse) the contents + change over time. + * assert.cc: rename __assert to __cygwin32_assert + * exceptions.cc: rename __stack_trace to __cygwin32_stack_trace, + __cygwin_except_handler to __cygwin32_except_handler + * version.h: increment major and minor numbers + +Tue Oct 7 12:52:25 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * dcrt0.cc (_exit): under Win 95, don't send SIGCHLD + unless special env variable is set. This works around a + problem where exiting a process can hang under Win 95. + +Mon Oct 6 23:41:34 1997 Geoffrey Noer + + * regexp: new directory containing free regexp code by + Henry Spencer. Taken from the most recent release of NetBSD. + Write configure.in and Makefile.in, based on files from + winsup/utils. + * Makefile.in: build regexp directory and include objs in + cygwin.dll. + * stubs.cc: remove all reg* stubs except for regfree which + isn't provided by above code. + +Mon Oct 6 13:35:48 1997 Geoffrey Noer + + * dcrt0.cc: remove asm idata3 terminator, now that ld is fixed + such that this is no longer necessary. + * libccrt0.cc: ditto + +Mon Oct 6 13:14:00 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * spawn.cc (spawn_guts): return child's PID on + spawn (_P_NOWAIT,...) instead of child's handle. + (cwait): rewritten as a wrapper to waitpid. + +Mon Oct 6 13:02:01 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * net.cc (socketpair): new + * cygwin.din: add socketpair export + +Mon Oct 6 13:01:51 1997 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + * dcrt0.cc: Remove obsolete call to fork_terminate. + * exceptions.cc: Respace, remove extraneous trailing whitespace. + Change critical section to mutex since there are supposedly + multi-processor problems with critical sections under NT. + Use "lock_cs" and "unlock_cs" macros to lock/unlock critical + regions. + (init_exceptions): Change critical section initialization to mutex + initialization. + (set_process_mask): Use locking macros to control access to + sig_mask. + (ctrl_c_handler): Use lock_cs/unlock_cs to control access. + (events_init): Use standard cygname function to create names for + shareable objects. + (events_init): Close cs mutex. + * fork.cc: Use event flags which are specific to the child being + forked. This prevents one process from prematurely activating + another. It also makes fork slightly more thread-safe. + (fork_init): Remove event initialization. + (fork_terminate): Remove function. + (cygwin_fork_helper1): Initialize events on a per-fork basis. + Events are inherited in child's pinfo structure. + Remove child->hThread initialization as it not needed. Use + pi.hThread where child->hThread is used. + Work around Windows 95 bug where a WaitForSingleObjects will + sometimes return ERROR_INVALID_HANDLE when it is resumed after + a suspend. + * pinfo.cc: Remove references to hThread field whereever it occurs. + * strace.cc: Use standard cygname function to create name for + strace_mutex. Prevents confusion between different .dll versions. + * wait.cc (wait_found): Remove reference to hThread. + * winsup.h (class pinfo): Remove reference to hThread. Add + per-process fork control event handles. + * include/limits.h: Increase NGROUPS_MAX from 0 to 1 to reflect + recent change to getgroups. + +Mon Oct 6 11:06:22 1997 Geoffrey Noer + + Oops. ../libio refers to objdir and is not the same + as $(srcdir)/../libio. + +Thu Oct 2 23:12:19 1997 Geoffrey Noer + + Revert patches to sources applied after Sept 16. Removed + relevant portions of ChangeLog entries. Some of those changes + may reappear later (removing the entries makes this log easier + to understand). + +Thu Oct 2 15:34:03 1997 Geoffrey Noer + + * Makefile.in: remove hardcoding of SHELL to /bin/sh, remove + ../libio from INCLUDES since $(srcdir)/../libio is already + included. + * glob/Makefile.in: remove hardcoding of SHELL to /bin/sh + +Mon Sep 29 14:06:24 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * cygwin.din: add exports for rcmd, rresvport, rexec + * net.cc (cygwin32_rcmd): new + (cygwin32_rresvport): new + (cygwin32_rexec): new + * include/mywinsock.h: add protos for Winsock calls associated + with functions called by the above. + +Mon Sep 29 13:26:24 1997 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + * grp.cc (getgrent): Change overlooked comment to reflect new + behavior. + +Thu Sep 25 18:35:49 1997 Geoffrey Noer + + * Makefile.in: remove debugdll defs since the shared memory + overlap problem is solved by the timestamp addition of Sept 23 + * version.h: rework explanations of version numbers + +Thu Sep 25 16:21:49 1997 Geoffrey Noer + + * spawn.cc: add missing cast to debug printf + +Thu Sep 25 16:14:17 1997 Ian Lance Taylor + + * path.cc (conv_to_win32_path): Call backslashify on a win32 + path. + +Tue Sep 23 17:58:17 1997 Geoffrey Noer + + Fixes for things that were causing compile-time warnings: + * exec.cc (_execve): add missing const to args to match def + of execve in newlib which this calls. + (sexecve): add missing const to def + (sexeclpe): don't need to cast argv in sexecvpe call + (sexecvpe): add missing const to def + * winsup.h: correct _execve proto, add protos for login/logout + * syscalls.h: correct sexecve, sexecvpe protos + * include/Windows32/Base.h: NULL should be defined differently + for C++ + * init.cc: respacing + +Tue Sep 23 17:05:50 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * dcrt0.cc (dll_crt0_1): don't use alloca for allocating storage + for environment blocks because setenv() uses realloc! + +Tue Sep 23 17:05:50 1997 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + * Makefile.in (LD_STUFF): Add datestamp.o after DLL_OFILES. + (datestamp.o): New target. datestamp.c is generated whenever .o + files change. It creates a file containing a "date stamp" + which is used by the function "cygname" to create named + shared memory, events, mutexes, and semaphores used by + cygwin.dll. The unique datestamp allows multiple loading of + different cygwin.dll's even when they have incompatible use + of shared memory areas. + * init.cc (dll_entry): Create the name string used by cygname + from the name of the invoking .dll + the datestamp of the + .dll from the auto-generated datestamp.c + * misc.cc (cygname): New function. Creates a standard Cygnus + shared resource name given a prefix, a name (e.g., pinfo_mutex), + and a numeric suffix (e.g., a pid). Replaces custom code in + several files. Uses cygwin_dlldate from datestamp.c to construct + names that are unique for a given cygwin load. + * shared.cc (open_shared_file_map): Use standard cygname function + to create names for sharable objects. Use static handle 'h' + so that it can be closed later by shared_terminate. + (shared_terminate): Guard against calling CloseHandle with a + NULL handle. + (create_shared_fd_mapping_name): Use cygname function to generate + the name for the "fd_map". + +Tue Sep 16 23:34:36 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * fcntl.cc (_fcntl): correct errno value (EBADF instead of + EBADFD). + +Tue Sep 16 17:22:28 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * include/Windows32/Defines.h: add missing defines needed + for NTEA usage. + * ntea.cc: remove them from here + * syscalls.cc (_link): call CreateFile with FILE_WRITE_ATTRIBUTES + flag instead of GENERIC_WRITE + +Tue Sep 16 17:22:28 1997 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + * pinfo.cc (pinfo_init): Fix a NULL pointer dereference when PID + environment variable contains garbage. + +Thu Sep 11 16:51:40 1997 Geoffrey Noer + + * syscalls.cc (ftruncate): read file pointer location at + beginning of function and restore it at the end + +Thu Sep 11 15:35:10 1997 Ian Lance Taylor + + * path.cc (backslashify): Don't turn a single trailing slash into + a double trailing slash. + +Wed Sep 10 11:40:55 1997 Ian Lance Taylor + + * include/Windows32/Structures.h: Add PACKED to PRINTDLG. + * include/Windows32/Functions.h: Add STDCALL to a few function + declarations. + +Tue Sep 9 02:12:18 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * syscalls.cc (_link): Implement hard links under NT with NTFS + using the backup API. Default to copying the file (what we did + before). + +Mon Sep 8 20:19:09 1997 Geoffrey Noer + + Merge in the following changes: + + Thu Aug 21 13:30:12 1997 Ian Lance Taylor + * assert.cc: New file. + * Makefile.in (DLL_OFILES): Add assert.o. + (assert.o): New target. + * pinfo.cc (cygwin32_winpid_to_pid): New C function. + * cygwin.din: Add cygwin32_winpid_to_pid. + * include/sys/cygwin.h: Include . + (cygwin32_winpid_to_pid): Declare. + * pinfo.cc (pinfo_init): Add debug_printf showing pid and pgid. + + Wed Aug 20 13:24:30 1997 Ian Lance Taylor + * spawn.cc (env_sort): New static function. + (spawn_guts): Sort the environment before passing it to + CreateProcess. + * exceptions.cc (exit_already): New file static variable. + (__cygwin_exception_handler): If exit_already is set, just + return. If we get an exception we don't recognize, let the next + exception handler handle it. Just ignore the INVALID_HANDLE + exception. + (really_exit): Remove file static exit_already variable; use the + global one. + (events_terminate): Set exit_already. + * include/Windows32/Defines.h (EXCEPTION_INVALID_HANDLE): Define. + (STATUS_INVALID_HANDLE): Define. + * include/Windows32/Functions.h: Declare some shell functions. + +Mon Sep 8 17:40:46 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * dcrt0.cc (_exit): Kill the foreground process group on session + leader exit only if job control is in progress. + * exceptions.cc (ctrl_c_handler): protect the code with critical + section. This helps stability under Win 95. + * include/sys/strace.h: add new wm_printf macro + * signal.cc (kill_worker): window message number changed (window + messages WM_USER-WM_USER+0x100 reserved for common controls on + windows95). Debug print added. + * spawn.cc (spawn_guts): removed unneeded flag DETACHED_PROCESS. + * strace.cc: defines for SIGNAL and ASYNCIO messages added. + * tty.cc (create_tty_master): initialize speed fields of termios + structure. + (fhandler_pty_master::open): likewise. + * window.cc (WndProc): debug print added, window message number + changed. + * winsup.h: WM_ASYNCIO number changed. + +Mon Sep 8 16:40:46 1997 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + * fhandler.h: set_w_binary/set_r_binary now defined to + return void + * grp.cc (getgroups): always return an array of length 1 where + the element is the user's gid. + * pinfo.cc (pinfo_init): verify that we haven't exceeded the + maximum number of processes + (pinfo_list::allocate_pid): ditto + * include/Windows32/Functions.h: add noreturn attrib to ExitProcess + * include/sys/strace.h: change strace defs so strace-related + printfs will automatically add __FUNCTION__: to the beginning, + rename __sys_printf to strace_printf. + * *.cc: remove function names from debug printfs in favor of the + new scheme where they are automatically added, change __sys_printf + references (now strace_printf). + * smallprint.c (__small_vsprintf): new function displayer code + to support the above changes + +Wed Sep 3 12:44:45 1997 Geoffrey Noer + + * Makefile.in: split subdir_do into subdir_dobefore and + subdir_doafter to reflect whether the subdir in question + should be built before or after the top level is built + (e.g. glob needs to be built before libcygwin.a but libcygwin.a + needs to be built before utils). + +Thu Aug 28 12:09:39 1997 Geoffrey Noer + + * configure.in: when setting up EXE_LDFLAGS, correct the + location of crt0.o to ../../newlib since EXE_LDFLAGS is used + by Cygwin32 subdirectories where newlib is two directories up + instead of one. + * configure: regenerate with autoconf + +Thu Aug 28 00:13:11 1997 Geoffrey Noer + + Replace all licensing-related headers in all Cygnus-owned + files. Instead of listing terms at the top of each file, now + we simply refer to: + * CYGWIN32_LICENSE: new file listing Cygwin32 licensing terms + +Wed Aug 27 17:40:16 1997 Geoffrey Noer + + * cygwin.din: export random, srandom + +Wed Aug 20 16:56:39 1997 Geoffrey Noer + + * Makefile.in: remove unused winsock-related build rules + that were commented out, minor comment changes, remove + test.exe build rule. + +Wed Aug 20 14:45:17 1997 Geoffrey Noer + + * Makefile.in: link cygwin.dll with -lm -lgcc -lc -lgcc instead + of -lc -lm -lm -lgcc so lgcc finds abort(). Add definitions that + will eventually be used to build a cygwindebug.dll used by gdb + so gdb can debug a buggy cygwin.dll. Change some variable names + to have underscores in them (DLL_NAME, LIB_NAME, DEF_FILE, etc.). + Comment out text.exe build rule. + +Tue Aug 19 20:41:51 1997 Geoffrey Noer + + * dcrt0.cc: respace, modify some comments slightly + +Tue Aug 19 16:17:57 1997 Geoffrey Noer + + * Makefile.in: include ../libiberty/random.o, stop including + librx since it is LGPL'd code. + * stubs.cc: add stubs for regcomp, regexec, regerror, regfree + * dcrt0.cc (dll_crt0_1): default to not support tty/pty devs, + default to not displaying the running process in the title bar. + +Fri Aug 15 18:23:43 1997 Rob Savoye + + Add mingw directory for the minimalist cygwin environment. + See mingw/ChangeLog for changes specific to that directory + + * configure.in: Add mingw to AC_CONFIG_SUBDIR. + * configure: Regenerated from autoconf 2.12 with Cygnus patches. + * Makefile.in: Use subdir_do which uses the value of $SUBDIRS + rather than having seperate target for each directory. + * glob/Makefile.in: Add a phony target for install. + * configure.in: Add mingw to AC_CONFIG_SUBDIR. + +Fri Aug 15 01:12:19 1997 Geoffrey Noer + + * times.cc: add missing extern "C"s around exported functions + +Thu Aug 14 17:00:32 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * console.cc (fhandler_console::input_tcsetattr): clear iflag_ and + lflag_ when tty support enabled. + (FakeReadFile): do not interrupt read when tty support enabled. + Do not reset signal_arrived event. + * cygwin.din: add exports - cf(g)set(i)ospeed, login, logout, ttyslot + * dcrt0.cc (_exit): kill orphaned childs with SIGHUP and SIGCONT + on group leader exit, kill foreground process group on session + leader exit. + * dirsearch.cc (closedir): check for FindFirst() was called + * exceptions.cc: include mywinsock.h. + (call_handler): call WSACancelBlockingCall to try to interrupt + blocking winsock call, do PulseEvent() instead of SetEvent(). + (ctrl_c_handler): clear pending SIGCONT on stop signals, clear all + pending stop signals on SIGCONT, suspend the thread before resuming + to avoid W95 bug, process pending signals on SIGCONT, add signals to + pending if the process is stopped. + * fcntl.cc (fcntl): some code rearrangement to always do debug printfs + on call exit. + * hinfo.cc: include stdio.h + (hinfo_vec::build_fhandler): always add ttynum to tty's filename + (hinfo_vec::dup2): fix return value initialization and errno setting. + * include/netdb.h: typedef for sig_t removed + * include/sys/termios.h: octal constants changed to hexadecimals + to simplify debugging. + * misc.cc: include unistd.h and utmp.h + (login): new + (logout): new + * pinfo.cc (lock_pinfo_for_update): debug printf added + (pinfo::record_death): mark processes as orphaned on group leader + exit. + * select.cc (cygwin32_select): ResetEvent() removed + * signal.cc: unneeded ResetEvents removed + (_kill): ignore stop signals from a member of orphaned process group, + kill self process the last on group kill. + (sigaction): reset pending SIGCHLD when the disposition is set to + default. + * spawn.cc (spawn_guts): ResetEvent removed + (cwait): do not interrupt the call + * strerror.cc: include stdio.h, reenable disabled cases, remove + duplicated cases, return decimal error value in the default case. + * syscalls.cc (setsid): set process group id to process id when setsid + called. + (setpgid): check for negative pgid + * syslog.cc (syslog): %m macro support added + * termios.cc (cfg(s)eti(o)speed): new fuctions needed to support + NIST PCTS requirements. + * tty.cc: include utmp.h. + (ttyslot): new + (tty_list::terminate): fill in utmp on tty master exit + (tty_list::allocate_tty): check for tty master pocess alive + (create_tty_master): fill in utmp + (do_input): restart tty output on interrupt + (fhandler_tty_slave::fhndler_tty_slave): ttynum logic moved to + build_fhandler. + (fhandler_tty_slave::open): set tty's session id to sid of the calling + process. + (fhandler_tty_slave::write): check for TOSTOP bit + (fhandler_tty_slave::fstat): allow access to tty to everyone + (fhandler_tty_slave::ioctl): check for TOSTOP bit + * tty.h: ttyslot prototype added + * wait.cc (wait4): check for valid value of option argument added + * winsup.h: define PID_ORPHANED, move tty_list array to the end + of shared area. + +Thu Aug 14 11:42:59 1997 Ian Lance Taylor + + * path.cc (slash_unc_prefix_p): Correct check of path[3]. Permit + numbers after the host name. + + * include/Windows32/Defines.h: Correct value for SM_CMETRICS, + SM_CXDRAG, SM_CYDRAG, SM_CXEDGE, SM_CYEDGE, SM_CXFIXEDFRAME, + SM_CYFIXEDFRAME, and add SM_MOUSEWHEELPRESENT. + +Wed Aug 13 20:11:52 1997 Ian Lance Taylor + + * fork.cc (cygwin_fork_helper1): If we don't have a console, pass + DETACHED_PROCESS to CreateProcess. + * spawn.cc (spawn_guts): Likewise. + +Tue Aug 12 19:51:32 1997 Ian Lance Taylor + + * include/Windows32/Structures.h (IMAGE_DOS_HEADER): Remove + dos_message and nt_signature fields; they aren't present in the + Windows header file. + +Wed Aug 6 16:27:13 1997 Ian Lance Taylor + + * include/Windows32/Structures.h: Define LPMEASUREITEMSTRUCT as a + pointer to MEASUREITEMSTRUCT. + + * syscalls.cc (_stat_worker): In directory case, only set + STD_WBITS in st_mode if FILE_ATTRIBUTE_READONLY is clear. + (access): Remove special case for directory. + + * include/Windows32/Defines.h (HKEY_DYN_DATA): Define. + (REG_FULL_RESOURCE_DESCRIPTOR): Define. + (REG_RESOURCE_REQUIREMENTS_LIST): Define. + +Mon Aug 4 21:15:05 1997 Andrew Cagney + + * glob/Makefile.in: Add include of newlib/libc/sys/cygwin32 to + explicit .c.o rule so that dirent.h is found. + +Thu Jul 24 02:14:24 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * cygwin.din: fpathconf, initgroups - new exports + * console.cc: new static variable CONSOLE_SCREEN_BUFFER_INFO info + (fhandler_console::scroll_screen): local variable info removed + (fhandler_console::open): likewise + (fhandler_console::ioctl): likewise + (fhandler_console::clear_screen): likewise + (fhandler_console::cursor_set): likewise + (fhandler_console::cursor_rel): likewise + (fhandler_console::cursor_get): likewise + (fhandler_console::write_normal): fixed scroll region bug, termcap + "cs" entry works now + * dcrt0.cc (dll_crt0_1): set file API to use OEM charset, convert + command line from ANSI to OEM charset. + (_exit): clear stopsig value on process exit + * exceptions.cc (call_handler): add one millisecond delay before + SetEvent() + (ctrl_c_handler): clear pending stop signals on SIGCONT, do not send + SIGCHLD to parent on process resuming; some debug printfs added; do + not call _exit() in a context of signal handling thread (would cause + more harm than good); fixed a bug with SA_NOCLDSTOP flag. + * fhandler.cc (fhandler_base::open): use full win32 path name to + generate inode number namehash instead of unix filename. + * fork.cc (cygwin_fork_helper1): block all signals while child and + parent are in fork() code + * grp.cc (initgroups): new stub added + * include/limits.h: new posix defines added + * include/sys/termios.h: typedef speed_t as unsigned char + * path.cc (mount_info::conv_to_posix_path) bugfix + * pinfo.cc (pinfo_list::operator []): PID_NOT_IN_USE check added + (pinfo::record_death): set child's ppid to 1 on parent exit + * signal.cc (sleep): correct return value if sleep call was + interrupted + (_kill): correct return value if killed pid was not found. + (sigaction): correct return value on handling non-handlable + signals, clear pending ignored signals + (sigsuspend): sigsuspend call should always return -1 and set errno + to EINTR. + * spawn.cc: respace + * syscalls.cc: map ERROR_NO_DATA to EPIPE instead of ENODATA + (isatty): fixed return value + (fpathconf): new + (pathconf): rewritten + (ttyname): fixed return value + * sysconf.cc (sysconf): misc fixes + * termios.cc (tcsendbreak): corrected errno set + (tcdrain): likewise + (tcflush): likewise + (tcflow): likewise + (tcsetattr): likewise + (tcgetattr): likewise + (tcgetpgrp): likewise + (tcsetpgrp): likewise + * tty.cc (fhandler_tty_slave::ioctl): TCGETA/TCSETA support added + * wait.cc (_wait): wait() syscall should do not terminate if + a child is stopped. + (wait4): wait calls should wait childs only; fixed a bug with + nprocinfo count; fixed signal handling. + +Thu Jul 24 02:10:25 1997 Geoffrey Noer + + * uname.cc: uname now outputs Cygwin32_NT or Cygwin32_95 + instead of Cygwin32/NT or Cygwin32/95. + +Thu Jul 24 02:10:25 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * cygwin.din: sexecve, sexecl, sexecle, sexeclp, sexeclpe, + sexecv, sexecp, sexecvpe - new exports + * exceptions.cc (ctrl_c_handler): do not raise SIGHUP on + CTRL_LOGOFF_EVENT to prevent termination of cygwin application + run as NT service on user logoff, raise SIGHUP instead of SIGQUIT + on system shutdown, clear stopped status in inuse_p on SIGCONT, + set stopped status on stop signals, call _exit() on process + termination in a context of signal thread to terminate while + in a blocking win32 syscall. + * exec.cc: include unistd.h and ctype.h. + (_execve): code moved to sexecve, call sexecve with a NULL hToken + handle. + (sexecve): new, check path, argv[0] and envp to null values, + pass nToken handle to spawn_guts(). + (sexecl): new (code derived from spawn family of functions in + spawn.cc) + (sexecle): new + (sexeclp): new + (sexeclpe): new + (sexecv): new + (sexecp): new + (strccopy): new + (sexecvpe): new + * fhandler.cc (fhandler_base::fstat): add STD_RBITS and STD_WBITS + to st_mode of non-file handles. + (fhandler_dev_floppy::open): clear O_TRUNC bit. + (fhandler_dev_tape::open): likewise + * fhandler.h (fhandler_pty_master): new member pktmode (flag to + indicate pty's packet mode) + * fork.cc (cygwin_fork_helper1): call uinfo_init () in a child code + to read /etc/passwd, /etc/group into memory. + * hinfo.cc (hinfo_vec::build_fhandler): check socket names for right + inheritance on exec(). + * include/Windows32/Defines.h: fixed a typo in LPSTR_TEXTCALLBACKA + definition + * include/Windows32/Functions.h: added prototype for + ImpersonateLoggedOnUser() API call. + * net.cc (cygwin32_socket): duplicate socket handle as inheritable + to avoid Windows95 socket inheritance bug, close the original socket. + (cygwin32_accept): likewise. + * path.cc (mount_info::conv_to_win32_path): do not add trailing + backslash to UNC device names like "\\.\a:", "\\.\tape0:" etc. + * pinfo.cc (pinfo::record_death_nolock) set PID_WAITING_FOR_PARENT + bit to inuse_p instead of assignment - inuse_p is a bit set now. + (pinfo::record_death): check PID_WAITING_FOR_PARENT bit instead of + comparison. + * select.cc (fd_pipe_map::convert_to_unix_fdset): deal with pipe + errors. + (pipethread): likewise + * shared.cc (create_shared_fd_table): allow any process to access + shared arg, needed for sexec() family implementation + * signal.cc (kill_worker): fixed a typo in debug printf + * spawn.cc (spawn_guts): new hToken argument (security token of + logged on user for sexec() calls implementation), added checks for + zero prog_arg and argv[0], if hToken is not NULL run + CreateProcessAsUser() on the current window station/desktop, or + just CreateProcess() otherwise, close hToken after the process is + created. + (_spawnve): pass NULL hToken to spawn_guts(). + * syscalls.cc (_read): set process's read status while in a read call + (_write): set process's write status while in a write call + (stat_worker): if GetFileAttributes() fails, try to call fstat to + support raw devices + * syscalls.h: include windows.h, added sexec() family functions + prototypes. + * sysdef/i386/kernel32.def: ImpersonateLoggedOnUser - new export + * tty.cc: tty attachment logic changed - tty_list::count field + counts now number of tty opens, but not a number of processes, + attached to a tty. + (tty_init): do not call attach_tty() in a exec'ed process + (attach_tty): correct return value if !use_tty. + (tty::init): initialize pgid and hwnd fields. + (tty_list::terminate): clearout tty on master exit. + (tty_list::allocate_tty): fixed a bug in a tty allocation. + (fhandler_tty_master::init): on NT allow any process to open + tty-master process for handle duplication, create synchronisation + events with a world-wide access, initialize winsize structure with + a default values. + (fhandler_tty_slave::open): if a tty doesn't have process group set, + set it to a process group of current process. + (fhandler_tty_slave::write): added missed \n to debug print, tty + write synchronization moved to a more correct place. + (fhandler_tty_slave::read): Sleep time changed for conformance with + other sleeps. + (fhandler_tty_slave::tcsetattr): synchronization added + (fhandler_tty_slave::ioctl): initialize arg.winsize with a tty-stored + value, copy the result of ioctl call to winsize. + (fhandler_pty_master::fstat): small fix + (fhandler_pty_master::open): on NT allow any process to open + pty-master process for handle duplication, initialize winsize + structure with a default values. + (fhandler_pty_master::read): check for pipe errors, changes to support + packet mode + (fhandler_pty_master::ioctl): rewritten, no longer a stub. + (fhandler_pty_master::linearize/de_linearize): save/restore pktmode + value. + * tty.h (class tty): winsize - new member + * utils/ps.cc: show process status just after tty number field + * winsup.h: defines for new bits in inuse_p added, spawn_guts() + prototype changed. + +Thu Jul 24 02:10:25 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * Makefile.in: Add tty.o to link and dependency lists, add + tty.h to headers list + * console.cc (fhandler_console::open): save open call flags + (fhandler_console::input_tcsetattr): clear all console modes if + tty support enabled + (FakeReadFile): restart read on signal delivering, changed CTRL + macro to CONTROL to avoid conflict with sys/termios.h, copy as + much as possible chars to output buffer instead of call to + undo_input after every char to prevent timeouts problem. + * cygwin.din: srandom, ptsname, grantpt, unlockpt - new exports. + * dcrt0.cc: include tty.h, new use_tty global variable. + (dll_crt0_1): call events_init() on application startup, set + use_tty to FALSE if CYGWIN_NOTTY environment variable is defined, + do not change console title if CYGWIN_NOTITLE environment + variable set, call tty_init(). + (_exit): call tty_terminate(), events_terminate() and others + in the right order. All modifications of console title are + mutexed to allow tty code to obtain console window handle right. + * exceptions.cc (exception_init): initialization of signal_arrived + event moved to events_init(). + (call_handler): raise signal arrived event after resuming main + thread. + (__cygwin_exception_handler): raise signal instead of calling + ctrl_c_handler, because exception handler is called in a context + of the thread, caused exception, and SuspendThread in call_handler + blocks itself :-) + (ctrl_c_handler): clear stopsig on SIGCONT delivery, call + ResumeThread until suspend count > 1, notify parent about child's + status changed. Care about handling SIGCONT signal. On stop + signals release vital mutexes used by stopped thread, save + signal number for wait(WUNTRACED) calls, notify parent about child's + status change. Do not stop processes running without job control + (when pgid == 0). Ensure that main thread is unblocked before + call _exit(). + (events_init): new + (events_terminate): new + * fcntl.cc (_fcntl): use saved open flags on F_GETFL/F_SETFL instead + of game with access_ variable. Is this variable longer needed? + * fhandler.cc (fhandler_base::linearize/de_linearize): save/restore + openflags_ variable. + (fhandler_base::open): save file open flags. + * fhandler.h (fhandler_base): new openflags_ member, new member + functions get_flags/set_flags, new virtual functions ptsname, + dup_for_fork, tcget(set)pgrp + (fhandler_pipe): remove always_write/except_ready because pipes + are always write ready (not true...) and selectable on read. + new classes fhandler_tty_slave, fhandler_pty_master, + fhandler_tty_master + * fork.cc (cygwin_fork_helper1): inherit control tty number on fork, + call tty_init on child startup. + * hinfo.cc: include stdlib.h and ctype.h. + (hmap_init): take care on exec'ed processes. + (init_std_file_from_handle): open /dev/tty for standard handles if + tty usage enabled. + (build_fhandler): check for tty slave and pty master devices. + * include/exceptions.h: exception handler returns "int" (exception + handling code), not "void". + * include/termios.h: new defines, struct winsize must contain + ws_xpixel and ws_ypixel members (commented now to avoid + incompabilities with existing binaries. Should be uncommented in + next release. + * net.cc (gethostbyaddr): corrected return value + * passwd.cc (parse): remove trailing newline from password + lines (user's shell was reported with trailing newline before). + * pinfo.cc (lock_pinfo_for_update): open mutex code moved to + events_init() in exceptions.cc. + (destroy_pinfo_lock): removed, pinfo_mutex is now closed in + events_terminate() in exceptions.cc. + (init_self): the initial value for pgid must be 0 (no job-controlled + process). + * select.cc: all debug_printf's changed to select_printf. + (fd_pipe_map): new class to implement (polling...) select on pipes. + (pipethread): new + (cygwin32_select): comment out socket only case since generic + code (select on different types of handles) works for sockets too + but is interruptable. The case for always_ready_used is used now + and for polling select (zero timevalue). Changes to support + select on pipes. + * shared.cc (shared_info::initialize): initialize tty table. + * signal.cc (sleep/usleep/sigsuspend/pause): signal_arrived moved + from u area to dll's address space, signal_arrived is manual reset + event now. + (_raise): implemented as kill (self, sig). + (kill_worker): new. Use SendMessage instead of PostMessage to avoid + some timing problems. + * spawn.cc: include tty.h. + (spawn_guts) call close_all_files() on exec, call tty_terminate() + before process exit. Some changes due to moving signal_arrived to + dll's address space. + (_spawnve): inherit control tty number on spawn. + * syscalls.cc (close_all_files): reenabled. The code is ok after + all! The troubles were due to incorrect usage on exec() calls. + (setsid): no longer a stub + (ptsname): new + * termios.cc: all syscall_printf's changed to termios_printf. + (tcget(set)pgrp): rewritten, no longer a stub. + * times.cc (utimes): It looks like Win32 does not allow changing + times of directories, so just return success in this case. + * tty.cc: new file + (tty_init): new + (tty_terminate): new + (attach_tty): new + (detach_tty): new + (tty::init): new + (tty_list::terminate): new + (tty_list::connect_tty): new + (tty_list::free_tty): new + (tty_list::init): new + (tty_list::allocate_tty): new + (fhandler_tty_master::fhandler_tty_master): new + (create_tty_master): new + (fhandler_tty_master::init): new + (doecho): new + (do_input): new + (process_input): new + (do_output): new + (process_output): new + (process_ioctl): new + (fhandler_tty_slave::fhandler_tty_slave): new + (fhandler_tty_slave::open): new + (fhandler_tty_slave::init): new + (fhandler_tty_slave::close): new + (fhandler_tty_slave::write): new + (fhandler_tty_slave::read): new + (fhandler_tty_slave::linearize): new + (fhandler_tty_slave::de_linearize): new + (fhandler_tty_slave::dup): new + (fhandler_tty_slave::dup_for_fork): new + (fhandler_tty_slave::fstat): new + (fhandler_tty_slave::tcgetattr): new + (fhandler_tty_slave::tcsetattr): new + (fhandler_tty_slave::tcflush): new + (fhandler_tty_slave::tcsetpgrp): new + (fhandler_tty_slave::tcgetpgrp): new + (fhandler_tty_slave::send_ioctl_request): new + (fhandler_tty_slave::ioctl): new + (fhandler_pty_master::fhandler_pty_master): new + (fhandler_pty_master::fstat): new + (fhandler_pty_master::open): new + (fhandler_pty_master::close): new + (fhandler_pty_master::write): new + (fhandler_pty_master::read): new + (fhandler_pty_master::tcgetattr): new + (fhandler_pty_master::tcsetattr): new + (fhandler_pty_master::tcflush): new + (fhandler_pty_master::ioctl): new + (fhandler_pty_master::ptsname): new + (fhandler_pty_master::linearize): new + (fhandler_pty_master::de_linearize): new + (fhandler_pty_master::dup_for_fork): new + (grantpt): new + (unlockpt): new + * tty.h: new + * utils/ps.cc: display process's control tty number. + * wait.cc (wait_for_single): removed. + (wait_for_any): all code moved to wait4(). + (wait4): rescan process table on child status changes, support for + WUNTRACED flag, avoid time races on child exit, correct return + value on timeout. + * window.cc: misc changes to wait creation of process's hidden + window to avoid race conditions on multiprocessor systems. + * winsup.h: misc changes to support all of the above. + +Thu Jul 24 02:10:25 1997 Geoffrey Noer + + * net.cc (cygwin32_shutdown): New implementation to replace + stub previously present + +Tue Jul 22 14:59:22 1997 Geoffrey Noer + + * cygwin.din: remove random, srandom + * Makefile.in: remove random/srandom-related lines + +Tue Jul 22 14:10:32 1997 Ian Lance Taylor + + * path.cc (realpath): New C function. + * cygwin.din: Export realpath. + + * cygwin.din: Export srandom. + +Wed Jul 9 12:26:03 1997 Geoffrey Noer + + * Makefile.in: libiberty random.o ends up in winsup, link + in that obj for now + +Tue Jul 8 14:02:41 1997 Ian Lance Taylor + + * libcmain.cc (main): Pass wShowWindow field from startup info to + WinMain. + +Mon Jul 7 17:47:48 1997 Geoffrey Noer + + * path.cc: respace, reword comments + * times.cc (utimes): add FIXME + +Tue Jun 24 18:31:27 1997 Geoffrey Noer + + * winsup.h: adjust protos to reflect the above, add enum os_type + which contains {winNT, win95, win32s, unknown} + * security.cc (is_nt): Delete + * syscalls.cc (windows_95): Delete + (get_os_type): New local function which returns os_type. Replaces + windows_95() and is_nt(). + + * fhandler.cc: Reformat. Call get_os_type() instead of + windows_95() and/or is_nt(), reorder so NT cases are first. + * mmap.cc: ditto + * net.cc: ditto + * syscalls.cc: ditto + * syslog.cc: ditto + + * uname.cc (uname): call get_os_type to fill new our_os local + variable, check that when filling out utsname struct, default + to i386 when we can't find out the specific Intel processor + variant. + * fhandler.cc (get_file_owner): remove doit variable + (get_file_group): ditto + * mmap.cc: extern "C" individual functions instead of wrapper + around most of file. + * misc.cc: minor reformat + * heap.cc (_sbrk): split a = b = c statement into two to + make code clearer and avoid invalid C++ casting warning during + compile. + * path.cc (symlink_follow): initialize syml_p and exec_p to zero + * select.cc: respace + (selectthread): cast first arg of WINSOCK_FD_SET + * ntea.cc (NTReadEARaw): add missing casts in front of malloc calls + * utils/mount.cc: remove mixed option since that hasn't been + supported for quite some time + +Sun Jun 22 17:27:03 1997 Ian Lance Taylor + + * include/windows.h: If RC_INVOKED is defined, don't include + limits.h, stdarg.h, Structures.h, Functions.h or Sockets.h, and + don't typedef BOOL. + * include/Windows32/Base.h: Don't do any typedefs if RC_INVOKED is + defined. + + * include/Windows32/Sockets.h (MAXHOSTNAMELEN): Don't define if + already defined. + * include/sys/param.h (MAXHOSTNAMELEN): Likewise. + +Fri Jun 20 11:06:09 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * include/sys/wait.h: correct operator precidence bug + in WIFSIGNALED + +Thu Jun 19 12:58:45 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + Handle unblocked pending signals on sig_mask changes + * exceptions.cc (return_handler): renamed to set_process_mask + (set_process_mask): new; use to set process mask instead of direct + u->self->sig_mask manipulations. + * winsup.h: rename return_handler proto to set_process_mask + * signal.cc: throughout file, call set_process_mask() instead of + direct manipulations of u->self->sig_mask. + (pause): new + * cygwin.din: add pause() export + * syscalls.cc (system): correct return value + +Wed Jun 18 22:01:56 1997 Geoffrey Noer + + * Makefile.in: add $(srcdir)/../newlib/libc/sys/cygwin32 to + the list of includes since that's where sys/dirent.h is + supposed to live + * include/sys/dirent.h: moved to newlib/libc/sys/cygwin32/sys + +Wed Jun 18 13:56:47 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * signal.cc (sigsuspend): deal with pending unblocked signals + * winsup.h: add proto for return_handler (sigset_t) + +Wed Jun 18 02:02:13 1997 Geoffrey Noer + + respaced console.cc, fhandler.cc, syscalls.cc, pinfo.cc, + fork.cc, spawn.cc + +Tue Jun 17 14:57:09 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * cygwin.din: add getpgid, killpg exports, delete duplicate + random export + * fork.cc (cygwin_fork_helper1): inherit pgid and sid on fork + * misc.cc (cygwin32_*env): save environ value in __cygwin_environ + too. Is __cygwin_environ variable really neccessary? Why not + export cygwin.dll's environ variable with "__cygwin_environ" name? + * pinfo.cc (pinfo::init_self): initialize pgid and sid + * signal.cc (kill_worker): new + (_kill): rewritten to support process groups + (killpg): new + * spawn.cc (_spawnwe): inherit pgid and sid on spawn family calls + * stubs.cc (setpgrp, getpgrp): remove stubs + * syscalls.cc (setpgid, getpgid, setpgrp, getpgrp): new + * termios.cc (setpgid): remove stub + * utils/ps.cc (main): add pgid to output, change output + format + * wait.cc (wait_for_any): add intpid argument, arrays ctable and + ptable have now fixed MAXIMUM_WAIT_OBJECTS size to avoid extra + scan of process table, changes for process groups support. + (wait4): misc changes to support process groups + * winsup.h (pinfo class): add new variables pgid, sid. + Define __cygwin_environ. + +Mon Jun 16 18:30:21 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * spawn.cc (spawn_guts): set child->hProcess and child->hThread, + CloseHandle on pi.hThread at end of spawn_guts instead of right + after starting the child process, + _P_WAIT needs to be handled separately from _P_OVERLAY + +Sun Jun 15 23:51:10 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * cygwin.din: remove setenv/getenv-related exports, + export cygwin32_ equivalents + * exec.cc: check ? + * misc.cc (cygwin32_getenv): new + (cygwin32_putenv): new + cygwin32_setenv): new + (cygwin32_unsetenv): new + * spawn.cc: call cygwin32_getenv instead of getenv, + call spawn with *u->envptr instead of environ + * winsup.h: define **environ as extern, define *cygwin32_getenv + +Sun Jun 15 20:51:09 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * Makefile.in: add ../libiberty/random.o to EXTRA_OFILES + * cygwin.din: remove exports of tgetent and _tgetent, added random + * exception.cc (exceptions_init): make OurThread handle + noniherittable, remove unused buf array. + (return_handler): add restmask argument (sig_mask value before + calling signal handler) + (call_handler): save sig_mask in user's stack before calling signal + handler, change PulseEvent() call to SetEvent() -- there were + losses of signal_arrived events if main thread was not in wait + state. + (ctrl_c_handler): add support for SIGIO signal. + * fhandler.cc (fhandler_base::linearize/delinearize): + save/restore async_ flag + (fhandler_base::fhandler_base): clear async_ flag + * fhandler.h: add async_ as new variable in fhandler_base, + add get_async/set_async functions + * misc.cc (tgetent): remove stub + * net.cc (fhandler_socket::write): raise SIGPIPE if write to + disconnected socket. + (cygwin32_accept): check the result of find_unused_handle() before + accept() call, set errno if no more file descriptors available. + (fhandler_socket::ioctl): add support for async I/O on sockets + * pinfo.cc (pinfo::clearout): clear sig_pending mask + * syscalls.cc (readv, writev): rewrite + * window.cc (WndProc): add support for async I/O + * winsup.h: define WM_ASYNCIO + +Mon Jun 9 18:51:09 1997 Geoffrey Noer + + * include/winsock.h: fix protection wrapper name + +Fri Jun 6 12:41:09 1997 Ian Lance Taylor + + * include/Windows32/Defines.h: Define CommonDlgExtendedError + return values (CDERR_*, PDERR_*, CFERR_*, FNERR_*). Define + TEXTMETRIC tmPitchAndFamily values (TMPF_*). + + * include/dlgs.h: New file; just includes windows.h. + * include/cderr.h: Likewise. + + * libcmain.cc (main): Don't pass the program name to WinMain. + + * cygwin.din: Export strlwr and strupr. + + * include/winreg.h: New file; just includes windows.h. + * include/winsock.h: New file; just includes windows.h and + Windows32/Sockets.h. + * include/Windows32/Sockets.h: Don't define u_char, et. al. if + _SYS_TYPES_H is defined. Undefine fd_set if it is defined. + + * include/Windows32/Functions.h: Define MoveMemory, FillMemory, + and ZeroMemory as macros. + + * times.cc (_timezone, _daylight, _tzname): New global variables. + (tzset): New function. + * cygwin.din: Don't set _timezone to timezone. Export tzset and + _tzset. Export _timezone, _daylight, and _tzname. + + * dcrt0.cc (__cygwin_environ): New global variable. + (dll_crt0_1): Set __cygwin_environ to environ. + * cygwin.din: Export __cygwin_environ. + +Thu Jun 5 17:52:02 1997 Ian Lance Taylor + + * times.cc (gettimeofday): Check return values and set tz_dsttime + correctly. + +Wed Jun 4 00:04:33 1997 Geoffrey Noer + + * fhandler.cc (fhandler_pipe::lseek): new virtual function + * fhandler.h: add lseek to fhandler_pipe class + +Tue Jun 3 19:20:47 1997 Ian Lance Taylor + + * include/Windows32/Defines.h (IMAGE_DOS_SIGNATURE): Define. + (IMAGE_NT_SIGNATURE): Define. + * include/Windows32/Structures.h (IMAGE_DOS_HEADER): Define. + +Tue Jun 3 13:05:26 1997 Geoffrey Noer + + * console.cc: respace + * fhandler.h: add virtual off_t lseek to fhandler_socket and + fhandler_tty defs, respacing + +Mon Jun 3 12:21:20 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * cygwin.din: export wait3, wait4 + * dcrt0.cc (_exit): call fill_rusage + * exceptions.cc (ctrl_c_handler): increment rusage_self.ru_nsignals++ + * fhandler.cc (fhandler_pipe::fhandler_pipe): new stub + * fhandler.h: add fhandler_pipe class + * hinfo.cc (hinfo_vec::build_fhandler): call + GetNumberOfConsoleInputEvents instead of GetConsoleScreenBufferInfo, + handle fhandler_pipe class + * pinfo.cc: include sys/resource.h, + (pinfo::clearout): erase memory associated with rusage_self + and rusage_children + * resource.cc (getrusage): rewrite + (add_timeval): new helper function + (add_rusage): new helper function + (fill_rusage): new helper function + * shared.cc (create_shared_fd_table): pass file mapping handle to + children letting them close it + * spawn.cc (spawn_guts): call fill_rusage and add_rusage as + appropriate + (cwait): ditto + * times.cc (__to_clock_t): add flag arg which says whether or not + to substract FACTOR from total + (times): also fill in tms_cstime and tms_cutime, add flag arg to + __to_clock_t calls + (totimeval): add extra flag passed on to __to_clock_t + (gettimeofday): add extra flag passed on to totimeval + * wait.cc (wait_for_single): add extra rusage arg, change + wait_found calls to account for extra arg + (wait_for_any): ditto + (_wait): call wait4 instead of waitpid + (wait_found): add rusage arg, deal with it calling add_rusage as + appropriate + (wait_pid): now just calls wait4 + (wait4): was wait_pid but adds extra rusage arg and deals with it + (wait3): new, calls wait4 + * winsup.h: include sys/resource.h, add rusage_self and + rusage_children to pinfo class, fix totimeval proto, add protos + for fill_rusage and add_rusage + * passwd.cc: include termios.h + (getpass): new + * stubs.cc (getpass): delete old stub + +Tue Jun 3 14:51:47 1997 Ian Lance Taylor + + * times.cc (ftime): New function. + * cygwin.din: Export ftime. + +Mon Jun 2 14:34:00 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * include/limits.h: NGROUPS_MAX should be 0 + * include/asm/socket.h: add missing additional options + including SO_SNDBUF, SO_RCVBUF, et al + * include/sys/wait.h: include sys/resource.h, add protos for + wait3() and wait4(). + +Mon Jun 2 15:26:35 1997 Ian Lance Taylor + + * utils/configure.in: Call AC_PROG_INSTALL. + * utils/configure: Rebuild. + +Mon Jun 2 11:44:14 1997 Geoffrey Noer + + * grp.cc (getgroups): new + * cygwin.din: export getgroups + +Fri May 30 16:47:38 1997 Geoffrey Noer + + * uname.cc (uname): completely rewrite, using more of the + SYSTEM_INFO struct to figure out information (now x86 type is + set correctly in Windows 95. + * version.h: increment CYGWIN_DLL_VERSION_MINOR + * include/Windows32/Structures.h: SYSTEM_INFO struct's first + member is dwOemId, not dwOemID according to MS docs + +Fri May 30 16:47:38 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * window.cc: new file + * Makefile.in: add window.cc to lists of source, object files, + and dependencies. + * console.cc: include , scroll_screen() added to + fhandler_console class, + add support for default screen attributes, + (open): set default_color on tty open + (linearize/delinearize): pass default_color to the child process + (clear_screen): fix Win95-specific bug, add support for + default_color. + (clear_to_eol): remove + (fhandler_console::fhandler_console): set default_color to + white on black + (char_command): add invisible screen attribute, misc changes + (FakeReadFile): do not convert AltGr-char to ESC-char sequence + to support international keyboards. + * cygwin.din: export setitimer, getitimer + * dcrt0.cc (dll_crt0_1): add call to window_init(), uppercase + environment vars only if started by a win32 process. + (_exit): add call to window_terminate() + * fhandler.cc: add mode argument to open() calls, + (fhandler_base::open): do not check for symlink in path_conv + calls, calls to set/get_file_attribute() instead of NTRead/WriteEA. + (fhandler_base::fstat): use get_file_attribute if possible + (fhandler_disk_file::open): remove unneeded unixattr checks + * fhandler.h: changes to support above. + * fork.cc (cygwin_fork_helper_1): pass umask value to the child, + call window_init() in child + * ntea.cc: enable EA calls, add FILE_FLAG_BACKUP_SEMANTICS + to CreateFile calls to support EA of directories. + * path.cc (symlink): add mode argument to _open call, remove + unneeded stuff + (symlink_check_worker): add checks for "system" attribute and EA. + * security.cc (get/set_file_attribute): new. Calls EA code now, + placeholders for NTFS security support. + * signal.cc (alarm): remove in favor of new implementation in + window.cc + (RemoteThread): remove + (_kill): use window messages to emulate signals on both NT and Win95 + * spawn.cc (spawn_guts): call window_terminate on exec() + (cwait): correct return result code + (_spawnve): add umask inheritance, some bug fixes + * syscalls.cc (_open): add mode argument, umask support + (umask): rewritten + (chmod): try to set file attributes, set system bit on symlinks + (stat_worker): fix nlinks of directories, add mode argument + to _open() call. + * syscalls.h: add mode argument to _open() prototype + * winsup.h: changes to support above + +Tue May 27 12:22:19 1997 Geoffrey Noer + + * times.cc (gettimeofday): return 0 on success instead of 1 + (utimes): init res to 0 + +Wed May 21 11:29:24 1997 Geoffrey Noer + + * include/limits.h: define NGROUPS_MAX + +Tue May 20 14:13:59 1997 Geoffrey Noer + + * passwd.cc: rename function setpwend to setpwent (typo) + * cygwin.din: ditto, also remove name__C9type_info from + exports list. + +Wed May 14 17:38:39 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * signal.cc (sleep): call WaitForSingleObject instead of Sleep + (usleep): ditto + +Wed May 7 15:34:07 1997 Geoffrey Noer + + Public gnu-win32 beta 18 release made + +Sun May 4 15:34:07 1997 Geoffrey Noer + + patch from Mikey : + * console.cc (FakeReadFile): FlushConsoleInputBuffer if + flags & ENABLE_LINE_INPUT and then return ReadFile + +Fri May 2 10:53:10 1997 Geoffrey Noer + + * signal.cc: make exported functions extern "C" + * include/cygwin32/socket.h: replace values assigned to + IP_ definitions with ones suitable for use with WinSock. + * cygwin.din: add exports for sigpending, sigsuspend, remove + exports for __9type_infoPCc and before__9type_infoRC9type_info + * winsup.h: remove signal-related protos from winsup.h in favor + of newlib/libc/include/sys/signal.h + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * signal.cc: (sigpending) new + (sigsuspend): new + * utils/termcap: replace with one from Linux + +Tue Apr 29 19:03:29 1997 Geoffrey Noer + + * utils/ps.cc: print Win32 pid as unsigned int so Windows 95 + pids don't show up as negative values + +Tue Apr 29 17:20:57 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * spawn.cc (spawn_guts): allocate new cygwin PID for a child + created with spawn(!_P_OVERLAY) + +Tue Apr 29 13:24:59 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * console.cc: assorted console fixes + * select.cc (fd_socket_map::convert_to_unix_fdset): only + do full debug_printf if used_ valid + * exceptions.cc: correct constants used for checking size of + stack (should be negated) + * fhandler.cc (fhandler_base::open): fix syscall_printf typo + + patch from marcus@cathcart.sysc.pdx.edu (Marcus Daniels): + * include/sys/mman.h: define MAP_ANON MAP_ANONYMOUS (typo fix) + +Mon Apr 28 15:19:44 1997 Geoffrey Noer + + * cygwin.din: remove libgcc2.a internal functions + +Mon Apr 28 14:57:04 1997 Michael Meissner + + * cygwin.din (before__9type_infoRC9type_info): Remove, the + type_info::before(type_info const &) function no longer seems to + exist. + +Mon Apr 28 14:19:44 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * console.cc (undo_input): new + (scroll_screen): new + (fhandler_console::output_tcsetattr): fix debug printf + (fhandler_console::input_tcsetattr): no longer call set_w_binary + (fhandler_console::cursor_get): fix base_chars + (fhandler_console::char_command): make savex, savey globals, + add char buf, add code to handle clears better, many other + additions + (fhandler_console::write_normal): assorted fixes + (fhandler_console::write): move screen scroll code to + scroll_screen(), support Reset Linux terminal, Restore cursor + position, Save cursor position, Skip orig_colors + (FakeReadFile): enlarge keytable to include shift/control/alt + values + Command set still missing set pelette, character sets, and + UTF codes. + +Mon Apr 28 12:19:44 1997 Geoffrey Noer + + * fhandler.cc (fhandler_base::open): only include + FILE_SHARE_DELETE in shared when running NT (Win 95 doesn't + support it). + +Thu Apr 24 18:57:21 1997 Geoffrey Noer + + patch from Jeremy Allison : + Correct problem caused by setting /dev/null fd to -1 which is + same as INVALID_HANDLE_VALUE. + * fhandler.h: set DEV_NULL_HANDLE_VALUE to -2 + * fhandler.cc (fhandler_dev_null::open): set handle to + DEV_NULL_HANDLE_VALUE instead of INVALID_HANDLE_VALUE + * hinfo.cc (hinfo_vec::build_fhandler): add case for + handle == (HANDLE) DEV_NULL_HANDLE_VALUE + +Thu Apr 24 15:12:13 1997 Geoffrey Noer + + * fhandler.cc (fhandler_base::write): catch return of raw_write + and return -1 if it failed + +Thu Apr 24 10:42:01 1997 Geoffrey Noer + + path.cc (symlink): restore chmod call for now since the NTEA code + isn't quite up to the task yet. + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * exceptions.cc (ctrl_c_handler): corrections to Apr 18 patch + * fhandler.cc: ditto + * dcrt0.cc (dll_crt0_1): move console title setting code, + set up default signal handlers + * fork.cc (cygwin_fork_helper1): also set child->sigs and + child->sig_mask + * spawn.cc (spawn_guts): if mode _P_OVERLAY, set up child + signal handlers. + +Mon Apr 21 22:29:49 1997 Geoffrey Noer + + * include/Windows32/ASCIIFunctions.h: remove old def of + GetEnvironmentStringsA, add new one based on def from Functions.h + * include/Windows32/Functions.h: define GetEnvironmentStrings as + GetEnvironmentStringsA when not unicode, remove definition of + GetEnvironmentStrings in favor of ones in ASCIIFunctions.h and + UnicodeFunctions.h + * include/Windows32/Defines.h: add missing XTYP_ definitions, + change value of XTYPF_NOBLOCK to 0x0002 from 0x2 + * include/Windows32/Sockets.h: comment out redefinitions of + errno.h-type constants since MS doesn't define them and we + have our own in errno.h + +Fri Apr 18 10:40:30 1997 Geoffrey Noer + + * include/Windows32/Structures.h: add typedefs for + LPDLGITEMTEMPLATE, PDLGITEMTEMPLATE. + * include/Windows32/Defines.h: define FW_REGULAR FW_NORMAL + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * exceptions.cc (ctrl_c_handler): do not reset signal + handler to SIG_DFL while processing the signal, instead + block the signal while handler executes. + * signal.cc (_raise): fixes related to the above + +Thu Apr 17 23:50:50 1997 Geoffrey Noer + + * path.h: increase path length in mount table to MAX_PATH + in size instad of 30. This will increase cygwin.dll memory + usage by 20K. We need to remove static allocations from + path code. + +Thu Apr 17 10:11:50 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * exceptions.cc (ctrl_c_handler): CTRL_CLOSE_EVENT should + generate SIGHUP instead of SIGQUIT + * signal.cc (_raise): rewrite + +Wed Apr 16 10:42:46 1997 Geoffrey Noer + + * version.h: increment CYGWIN_DLL_VERSION_MINOR + * syscalls.cc (system): use spawnvp instead of fork/exec + * ntea.cc: make all functions return false for now; they + were causing an obscene performance hit + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * console.cc (FakeReadFile): patch to support EINTR, EIO + * exceptions.cc: add support for return_handler, remove + control-C counter + (return_handler): new + (ctrl_c_handler): handle SIGCHLD, other assorted fixes + * fhandler.cc (fstat): reset errno to 0 + * passwd.cc (search_for): correct location of a debug printf + * select.cc: patches to handle signals better, respacing + * signal.cc (_raise): misc fixes + (_kill): call OpenProcess with PROCESS_ALL_ACCESS instead of + PROCESS_TERMINATE + * spawn.cc: more signal fixes + * syscalls.cc: add two new errors to errmap[] + (_stat_worker): fill out buf struct when stating directories + * wait.cc (wait_for_single): use INFINITE instead of large value + for timeouts + (wait_for_any): init nprocinfo to 1, not 0, other small fixes + * winsup.h: add signal_arrived to per_process class, reduce + amount of reserved space, add sig_pending to pinfo class + +Tue Apr 15 17:01:34 1997 Geoffrey Noer + + * utils/mkpasswd.c: change default shell to /bin/sh + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * utils/kill.cc: support sending numbered signals using + signal code instead of just calling TerminateProcess + +Tue Apr 15 15:24:55 1997 Ian Lance Taylor + + * utils/Makefile.in (INSTALL): Set to @INSTALL@. + (INSTALL_PROGRAM): Set to @INSTALL_PROGRAM@. + (INSTALL_DATA): Set to @INSTALL_DATA@. + (INSTALL_XFORM): Remove. + (install): Depend upon installdirs. Use $(program_transform_name) + directly, rather than using $(INSTALL_XFORM). + (installdirs): New target. + +Mon Apr 14 16:32:05 1997 Ian Lance Taylor + + * utils/Makefile.in (INSTALL): Change install.sh to install-sh. + +Mon Apr 14 12:33:22 1997 Geoffrey Noer + + * registry.cc: change key name to "Cygnus Solutions" instead + of "Cygnus Support" + * security.cc: don't include windows.h, already in winsup.h + * Makefile.in: add dependencies section entries for security.cc + and ntea.cc + +Fri Apr 11 00:03:49 1997 Geoffrey Noer + + * dcrt0.cc: add harmless cast to FreeEnvironmentStrings call + * registry.cc: added more presumed-harmless casts + * shared.cc: and another, and respacing + * utils/Makefile.in: don't need to link with -lkernel32 since it's + included automatically + * fhandler.cc: fhandler_console and FakeReadFile moved to + console.cc, stop including sys/stat.h, sys/param.h, sys/types.h, + stdio.h, ctype.h, pwd.h, grp.h, stdlib.h + reordered/respaced code so now we have all of fhandler_base, then + all of fhandler_disk_file, then all of fhandler_tty, etc... + (fhandler_base::ioctl): delete unused switch statement + * console.cc: added fhandler_console and FakeReadFile from + fhandler.cc, add includes necessary for this code + * grp.cc, Makefile.in: fix copyright dates + * ntea.cc: include string.h + +Thu Apr 10 22:00:43 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * path.cc (symlink): do NTWriteEA instead of chmod using same + flags + +Thu Apr 10 17:36:43 1997 Geoffrey Noer + + patch from gunther.ebert@ixos-leipzig.de (Gunther Ebert): + * Makefile.in: add libnetapi32.a to DLL_IMPORTS list, build security.o + * fhandler.cc (get_file_owner): new + (get_file_group): new + (fhandler_base::fstat): do another path_conv and check for error, + use get_file_owner and get_file_group to set buf->st_uid and + buf->st_gid + * fhandler.h: add protos for get_file_owner() and get_file_group() + * grp.cc (add_grp_line): new helper function + (read_etc_group): new helper function + (getgrgid): rewritten, no longer a stub + (getgrnam): rewritten, no longer a stub + (endgrent): rewritten, no longer a stub + (getgrent): rewritten, no longer a stub + * include/Windows32/ASCIIFunctions.h, include/Windows32/Base.h, + include/Windows32/Functions.h, include/Windows32/Defines.h, + include/Windows32/Structures.h, include/Windows32/UnicodeFunctions.h: + misc security/uid-related additions + * passwd.cc (add_pwd_line): new + (read_etc_passwd): new + (search_for): rewrite + (setpwend): rewritten, no longer a stub + (getpwent): rewritten, no longer a stub + (endpwent): rewritten, no longer a stub + * security.cc: new file + (get_world_sid): new + (world_full_access): new + (get_id_from_sid): new + (is_nt): new + * stubs.cc (endgrent): remove + (getgrent): remove + * syscalls.cc (rel2abssd): new + (set_process_privileges): new + (chown): now implemented for real for NT, still a stub in Win95 + (_stat_worker): use get_file_owner and get_file_group to set + buf->st_uid and buf->st_gid + * uinfo.cc: add protos for read_etc_passwd, read_etc_group + (uinfo_init): call read_etc_passwd(), read_etc_group() + * utils/Makefile.in: build mkpasswd, mkgroup + * utils/mkgroup.c: new, use to make an /etc/group file + * utils/mkpasswd.c: new, use to make an /etc/passwd file + * winsup.h: add protos for is_nt(), get_id_from_sid() + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * Makefile.in: build ntea.o + * dcrt0.cc (dll_crt0_1): move console title code here from spawn_guts + * exceptions.cc (ctrl_c_handler): small signal fixes, prepare + things so we can eventually reset the signal handler to SIG_DFL + * fhandler.cc (fhandler_disk_file::open): first check for EA info + about exec/symlink status before doing it the hard way + (fhandler_make_pipe): u->self->hmap.build_fhandler takes extra arg + (fhandler_base::open): make use of NTEA + * fhandler.h: remove init_std_file_from_handle, build_fhandler + protos + * hinfo.cc: include mywinsock.h and sys/socket.h, define + __INSIDE_CYGWIN_NET__, __INSIDE_CYGWIN32__ + (hinfo_vec::build_fhandler): takes an additional handle arg, + call GetConsoleScreenBufferInfo with it to see if are + fhandler_console, call GetCommState with it to see if we're + an fhandler_tty, call getpeername with it to see if we wamt + fhandler_socket. Old determining methods still work too. + * path.cc (symlink): chmod file to ((S_IFLNK) | (STD_RBITS) | + (STD_WBITS) | (STD_XBITS)) permissions + * select.cc: include stdio.h + (cygwin32_select): fix typo (missing an &), + assorted fixes for mixed socket/handles case + * shared.cc (create_shared_fd_table): set sa.bInheritHandle to 1 + to support reparenting + * signal.cc (_kill): add FIXME, cleanup return codes + * spawn.cc (spawn_guts): remove console title code, add code + to support reparenting of child processes + * syscalls.cc: add new third arg to hmap.build_fhandler calls + (chmod): make use of NTWriteEA + * ntea.cc: new file, NTEA handling routines + * times.cc: fix value of NSPERSEC + (utimes): fix return value + * wait.cc: changes to support reparenting, change INFINITE to + constant 500 to avoid "blocking win32 syscalls and signals" + problem + * winsup.h: add NTReadEA, NTWriteEA protos, define REPARENTING, + fix build_fhandler proto to add new arg, add handles hrProcess and + hrThread + +Tue Apr 9 00:25:33 1997 Geoffrey Noer + + * libcerr.cc: remove fixed size of sys_errlist array, figure out + sys_nerr from the sizeof the array rather than hard coding it. + * shared.cc (open_shared_file_map): add typecast + * signal.cc (_kill): SIGKILL should avoid exception handler + * fork.cc (cygwin_fork_helper1): don't call ExitProcess with a + negative arg on recreate_mmaps_after_fork failure + * include/Windows32/Defines.h: define VER_PLATFORM_WIN32_WINDOWS + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * dcrt0.cc: move reent_data from private address space to cygwin.dll + * fork.cc: copy parent's reent_data to the child + * cygwin.din: export reent_data + * winsup.h: add as public struct _reent reent_save to pinfo class + + another patch from sos@prospect.com.ru (Sergey Okhapkin): + * winsup.h: add ctrl_c_handler prototype + * exceptions.cc (init_exceptions): don't use u->self->hThread + since for a spawned process, this contains thread id of parent + Win32 process, not the child's. Instead use GetCurrent* funcs + to get thread handle. + (ctrl_c_handler): add more signal support, especially for kill + * signal.cc (_kill): more signal support, using CreateRemoteThread + under NT. Win95 only supports SIGKILL since it doesn't have this + call. + * syscalls.cc (windows_95): first version check should be an & + of 0x80000000 instead of 0x8000000 + (close_all_files): hmap[i] doesn't always exist, for now comment + out code + + patch from marcus@sysc.pdx.edu (Marcus Daniels): + * path.cc (skip_n_slashes): new local function + (symlink_check_worker): new local function, used to be symlink_check + (symlink_check): calls symlink_check_worker and returns + whether path is a symlink or not. + (symlink_expand): new local function, expand a symlink into + a file or directory path using symlink_check_worker + (path_conv::path_conv): takes extra follow_mode arg + (symlink_follow): call symlink_expand + * fhandler.cc, syscalls.cc: fix path_conv references + * path.h: fix path_conv prototype + +Mon Mar 24 19:44:28 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * select.cc: fix Feb 19 patch to select + * syscalls.cc: add statfs() and fstatfs() calls + * include/sys/vfs.h: new header file to support these + * cygwin.din: add them to dll export list + +Tue Mar 18 18:10:24 1997 Geoffrey Noer + + * dcrt0.cc: change idata3 asm section to have five null fields + instead of eight to conform to how MS does this section. + +Sun Mar 9 13:10:55 1997 Geoffrey Noer + + * include/sys/resource.h: add missing struct members to rusage struct + * resource.cc: added setting of missing fields, mostly to 0 until + we investigate how to set correct values. + +Wed Feb 19 17:44:06 1997 Jeremy Allison + + * select.cc: Added fixes from sos@prospect.com.ru (Sergey Okhapkin) + to implement blocking select on sockets/handles. This isn't + the way I finally want to do this, but I won't get chance + to do the re-write for a month or two so... + * include/Windows32/Defines.h: Added defines for NT ACL + stuff. + +Tue Feb 18 12:28:11 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * fhandler.cc: support reverse index escapes in console code + +Fri Feb 14 18:55:01 1997 Jeremy Allison + + * path.cc: Fixed normalize_posix_path() so that double slashes + are removed, except for those starting a UNC path. The command + ls .///////FILE_IN_DIRECTORY works now. + +Thu Feb 13 14:06:04 1997 Geoffrey Noer + + * path.cc: remove SLASH_P define and + * winsup.h: define it here instead + patch from scottk@utig.ig.utexas.edu (Scott Kempf): + dirsearch.cc (opendir): fix problem with accessing "/" + +Mon Feb 10 13:57:11 1997 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * misc.cc: replace nice () stub with Win32 implementation + * spawn.cc + * fork.cc: use priority returned by GetPriorityClass + +Wed Feb 5 16:56:23 1997 Geoffrey Noer + + * fhandler.cc, syscalls.cc: minor reformat + patch from sos@prospect.com.ru (Sergey Okhapkin): + * spawn.cc: set console title to reflect what's running + * winsup.h: TITLESIZE define added + +Mon Feb 3 16:53:10 1997 Geoffrey Noer + + * fhandler.h: fix typo + * fhandler.cc: check_execable_p should only take one arg now + +Mon Feb 3 16:16:39 1997 Jeremy Allison + + * fhandler.cc: Removed open_helper, turned it into + fhandler_base::open and added fhandler_disk_file::open. More + correct C++. + fhandler_disk_file: Moved check_execable_p into fhandler_disk_file. + tty ports are now closed correctly. + * fhandler.h: Changes to support the above. + +Fri Jan 31 19:14:34 1997 Geoffrey Noer + + * fhandler.cc (fhandler_base::open_helper): new function + containing the common open() code. symlink and executable + status defaults to 0. + (fhandler_tty::open): new function that calls + fhandler_base::open_helper + (fhandler_base::open): remove common code now in open_helper, + leaving symlink checking and executable checking + * fhandler.h: changes for the above, open_helper is protected + +Thu Jan 30 15:23:15 1997 Geoffrey Noer + + * hinfo.cc: also treat com3 and com4 as special files + * spawn.cc (spawn_guts): check return of WaitForSingleObject + in _P_WAIT case, some reformatting + +Tue Jan 28 10:46:16 1997 Jeremy Allison + + * net.cc: Added errors "WSAEINVAL", "WSAEFAULT" as these + can be returned for net calls. + * fhandler.cc: Added FILE_SHARE_DELETE to open share modes. + Much closer to POSIX on NT now (ignored on '95). + +Fri Jan 17 13:32:26 1997 Geoffrey Noer + + * configure.in: + * utils/configure.in: define LIB_AC_PROG_CC to get around + autoconf 1.12 problem. Invoke it instead of AC_PROG_CC. + * configure: + * utils/configure: regenerate + +Thu Jan 16 12:35:41 1997 Geoffrey Noer + + * mmap.cc: added missing copyright notice + +Tue Jan 14 12:51:12 1997 Jeremy Allison + + * cygwin.din: Added get_osfhandle, cwait and all the + spawn functions. + * exec.cc: Added include of process.h. Changed call to + spawn_guts to add extra parameter. + * libcerr.cc: Added extra error messages. Ensured + messages start at zero. + * spawn.cc: Changed spawn_guts to do wait and nowait + calls. Added all spawn functions. + * syscalls.cc: Added get_osfhandle. + * winsup.h: Removed incorrect spawn definitions, + corrected prototypes for spawn_guts and file_exists + calls. + * include/io.h: New file. Added for get_osfhandle. + +Thu Jan 9 14:20:01 1997 Jeremy Allison + + * exceptions.h: Moved from winsup to winsup/include. + * include/mywinsock.h: Added getprotobynumber and + getservbyport. + * Makefile.in: Moved exceptions.h dependency. + * cygwin.din: Added cygwin32_getprotobynumber and + cygwin32_getservbyport. + * net.cc: Added cygwin32_getprotobynumber and + cygwin32_getservbyport. + +Wed Jan 8 14:15:35 1997 Jeremy Allison + + * fhandler.cc: Fix from Scott Kempf (scottk@rimu.ig.utexas.edu) + to ensure creation_disposition is set correctly in open. + +Fri Jan 3 12:10:22 1997 Jeremy Allison + + * fork.cc: Added parameter to recreate_mmaps_after_fork + in child, and added set_child_mmap_ptr() call in parent. + Needed as cygwin.dll statics are not copied accros a fork. + * mmap.cc: Added parameter to recreate_mmaps_after_fork, + added set_child_mmap_ptr() call. + * winsup.h: Added mmap_ptr to pinfo struct. Removed obsolete + comments. + * Makefile.in: Added -I../libio, needed to rebuild source + using STL. Also added -nostdinc++ on recommendation of + Mike Stump (mrs@cygnus.com). + +Thu Jan 2 17:23:10 1997 Jeremy Allison + + * dcrt0.cc: Added a call to initialize winsock on app + init. + * fork.cc: Added call so child initializes winsock before + returning from the fork. This makes many network daemons + run correctly that did not before (apache soon...). + * net.cc: Removed calls to checkinit, this is now done on + app startup. Renamed checkinit to socket_checkinit and + removed static scope. + * winsup.h: Added prototype for socket_checkinit(). + +Thu Jan 2 12:25:06 1997 Jeremy Allison + + * dcrt0.cc (api_fatal): Check that u and u->self are + not zero before indirecting through them. + * fork.cc: Changed security descriptor for fork + mutexes to allow access by all. + * pinfo.cc: Changed security descriptor for shared + area to allow access by all. + * shared.cc: Added get_null_sd() call to return + security descriptor allowing access by all. Needed + when a cygwin32 service is running and also interactive + cygwin32 apps by the current logged in user. + * winsup.h: Added prototype for get_null_sd(). diff --git a/winsup/cygwin/ChangeLog-1998 b/winsup/cygwin/ChangeLog-1998 new file mode 100644 index 000000000..e22a158ed --- /dev/null +++ b/winsup/cygwin/ChangeLog-1998 @@ -0,0 +1,4490 @@ +Thu Dec 31 16:50:32 1998 DJ Delorie + + * mmap.cc: replaced all references to libstdc++ templates with + inline classes to remove build dependency on libstdc++ + +Thu Dec 31 00:02:40 1998 Geoffrey Noer + + * sysdef/uuid.def: remove useless stub. + * sysdef/oldnames.def: ditto. + * sysdef/largeint.def: ditto. + * sysdef/rpcndr.def: ditto. + +Wed Dec 30 20:33:09 1998 Geoffrey Noer + + * utils/cygcheck.cc: clean up misc. warnings relating to + signed vs. unsigned, char * vs. const char *, etc... + +Wed Dec 30 21:41:25 1998 Christopher Faylor + + * dcrt0.cc (do_exit): Remove previous dwProcessId + change as it presumes too much knowledge about signalling + in the wrong place in the code. + * sigproc.cc (sigproc_terminate): Move the dwProcessId + assignment here but only do it when it is necessary or + programs will die abnormally. + * fhandler.h: Add raw_write method to fhandler_serial. + * fhandler_serial.cc (raw_write): New method. Accomodates + overlapped I/O that now must be used with serial. + * utils/kill.cc (main): Allow `0' signal. Just checks + for existence of process. + +Wed Dec 30 00:01:18 1998 Geoffrey Noer + + * include/cygwin/version.h: bump API_MINOR to 8 to mark + recently exported _ctype_, _sys_errlist, _sys_nerr. Briefly + describe all API_MINOR changes to date. + +Wed Dec 30 01:31:34 1998 Christopher Faylor + + * dcrt0.cc (do_exit): Set myself->dwProcessId so that + some exit routines will not falsely believe that this + process has been execed. + * select.cc (peek_serial): Remove debugging statements. + * sigproc.cc (sigproc_terminate): Detect state where + myself->dwProcessId == 0 as indicative of not being + an exec stub. + +Tue Dec 29 21:13:33 1998 Christopher Faylor + + * dcrt0.cc (alloc_stack_hard_way): Fix a couple of thinkos + in calculating size of the new stack. Just use the size + passed from the parent. + (dll_crt0_1): Set up new frame pointers here, if appropriate. + * fork.cc (fork): Move frame pointer setup into dll_crt0_1. + +Tue Dec 29 12:57:38 1998 Geoffrey Noer + + * utils/mkpasswd.c: Include wchar.h. + * utils/mkgroup.c: Ditto. + +Tue Dec 29 12:53:23 1998 Geoffrey Noer + + * Makefile.in: remove dep for libcerr.o + +Mon Dec 28 22:02:15 1998 Christopher Faylor + + * fhandler.h: Make fhandler_serial io_status public since + select needs it. Add 'saw_error' field to select_record so + that select can detect error conditions. + * fhandler_serial.cc (fhandler_serial::raw_read): Detect + "operation aborted" error and retry. This seems to indicate + an attempt to retry an overlapped operation. + * select.cc (select_stuff::wait): Honor saw_error field when + appropriate. + (peek_serial): Rewrite to operate similarly to + fhandler_serial::raw_read. + * include/sys/termios.h: CBAUD mask was still not right. + +Mon Dec 28 09:09:27 1998 Christopher Faylor + + * libcerr.cc: Make obsolete. Move into errno.cc + * libctype.c: Make obsolete. Use newlib table. + * Makefile.in: Remove obsolete entries from LIBCOS. Define + __INSIDE_CYGWIN__ explicitly for .c -> .o compilation. + * cygwin.din: New exports: _ctype_, _sys_errlist, _sys_nerr. + * errno.cc: Move _sys_errlist and _sys_nerr here. + * dlfcn.cc: Reorganize includes to put ctype.h after winsup.h + so that __INSIDE_CYGWIN__ will be defined for use in ctype.h. + * fhandler_console.cc: Ditto. + * fhandler_tty.cc: Ditto. + * path.cc: Ditto. + * spawn.cc: Ditto. + +Sat Dec 26 00:20:48 1998 Christopher Faylor + + patch from Corinna Vinschen : + * include/Windows32/CommonFunction.h: Added proto for + NetUserChangePassword(). + +Thu Dec 24 16:15:40 1998 Christopher Faylor + + * dcrt0.cc (dll_crt0_1): Add more debugging output. + * ioctl.cc (ioctl): Can't use TC[GS]ET ioctls for pty master as + it conflicts with TIOCPKT. + * passwd.cc (passwd): Bypass tc[gs]etattr call in favor of appropriate + method or conversion confusion will result due to attempts to + appropriately convert to old-style termios structures in tc[gs]etattr. + * strace.cc (strace_vsprintf): Define t explicitly. + * termios.cc (tcsetattr): Reorganize to allow meaningful debugging + output. + (tcgetattr): Ditto. + +Wed Dec 23 15:02:11 1998 Christopher Faylor + + * winsup.h: Reorganize include order to allow thread-safe build. + +Wed Dec 23 11:45:33 1998 DJ Delorie + + * strace.cc (strace_microseconds): new function; returns elapsed + time in microseconds, using performance counters if available. + (strace_vsprintf): print timestamps and deltas as microseconds, + not seconds. + +Wed Dec 23 11:35:02 1998 DJ Delorie + + * times.cc (__to_clock_t): Change return value to unsigned long + long to prevent overflow. + +Tue Dec 22 19:37:55 1998 Christopher Faylor + + * fhandler.h: Reflect fhandler_*::init argument reordering. + Add dup and init methods to fhandler_serial. + * fhandler.cc (fhandler_base::init): Reorder arguments to mirror + open(). + * fhandler_console.cc (fhandler_console::init): Ditto. Initialize + using fhandler_base rather than fhandler_serial as console is + now being slowly uncouple from fhandler_serial. + * fhandler_serial.cc (fhandler_serial::fhandler_serial): Set size + of data structure or suffer strange behavior on exec(). + (raw_read): Add debugging output. + (fhandler_serial::init): New method. + (fhandler_serial::open): Detect call from init method and avoid + calling fhandler_base::open. Don't worry about non-blocking reads + since they are now handled correctly by _read(). + (fhandler_serial::tcsetattr): Honor ICANON in a kludgey sort of way. + (fhandler_serial::tcgetattr): Ditto. + (fhandler_serial::dup): New method. Ensures duplication of all + elements of fhandler_serial class. + * fhandler_tty.cc (fhandler_tty_master::init): Reflect init argument + reordering. + (fhandler_tty_slave::init): Ditto. + * hinfo.cc (hinfo::init_std_file_from_handle): Remove unnecessary + argument. + (hinfo_init): Reflect change to init_std_file_from_handle. + (cygwin_attach_handle_to_fd): Use more appropriate types for + arguments. + (hinfo::build_fhandler): Add some slop to allocated buffer just + for paranoia's sake. + (hinfo::dup2): Avoid dereferencing a NULL pointer when oldfd==newfd. + * pipe.cc (make_pipe): Reflect init argument change. + * shared.h: Another immigrant from winsup.h + * winsup.h: Reflect change to init_std_file_from_handle. Relocate + a declaration to shared.h so that it can be used in fhandler.h. + * include/sys/cygwin.h: Reflect change to cygwin_attach_handle_to_fd. + +Mon Dec 21 16:22:48 1998 Christopher Faylor + + * fhandler.cc (fhandler_base::open): Detect serial device as a special + case requiring an overlapped open. + * fhandler.h (fhandler_serial): Add several methods. Add new 'fixup after + fork required' field. + * fhandler_serial.cc (raw_read): Rewrite to come closer to handling VMIN + VTIME parameters and to allow EINTR. + (fhandler_serial::open): Initialize overlapped event here. Make error + messages more explicit. + (fhandler_serial::close): Close status event. + (fhandler_serial::tcsetattr): Store vtime_ as milliseconds. Attempt to + handle VMIN > 0, VTIME == 0 better. + (fhandler_serial::fixup_after_fork): Initialize a new event handle after + a fork. + (fhandler_serial::de_linearize): Ditto. + * hinfo.cc (hinfo::fixup_after_fork): Call fork fixer upper if close_on_exec + of need_fork_fixup set. + +Sun Dec 20 16:05:25 1998 Geoffrey Noer + + * include/shellapi.h: replace with stub that includes windows.h + like similar headers already do. + * scandir.cc (scandir): add parens around assignment used as truth + value. + +Sat Dec 19 00:42:44 1998 Christopher Faylor + + * thread.cc: Fix copyright info. + * thread.h: Ditto. + * libcmain.cc: gcc is now more picky about requiring a type + for main(), so add one. + * include/pthread.h: Add attribution for net contributor. + +Fri Dec 18 19:21:30 1998 Geoffrey Noer + + * pthread.cc: fix copyright header. + * shared.h: ditto. + +Fri Dec 18 19:21:30 1998 Geoffrey Noer + + patch from Corinna Vinschen : + * cygwin.din: export scandir and alphasort. + * Makefile.in: add scandir.o to deps + * scandir.cc: New file with scandir and alphasort implementations. + * include/cygwin/version.h: bump API_MINOR to 7. + +Fri Dec 18 16:44:07 1998 Geoffrey Noer + + * include/pthread.h: clean up, remove C++-style comments, + remove pthread_getsequence_np proto. + +Fri Dec 18 15:26:33 1998 Christopher Faylor + + Throughout, prepend cygwin_ to functions that are exported + as cygwin_* which previously needed to be aliased. + + * path.cc (cygwin_conv_to_win32_path): Resolve symbolic links. + Return success or failure value. + (cygwin_conv_to_full_win32_path): Ditto. + (cygwin_conv_to_posix_path): Return success or failure value. + (cygwin_win32_to_posix_path_list): Ditto. + (cygwin_posix_to_win32_path_list): Ditto. + * shared.h: New include file that incorporates parts of + winsup.h, fhandler_tty.h, path.h, and delqueue.h. + * Makefile.in: Remove old include files. + * cygwin.din: cygwin_* aliases are no longer required. + * libccrt0.cc: Store api_minor in per_process structure. + * select.cc: Change meaning of second argument to ready_for_read + to indicate whether read_ahead should be ignored. + * fhandler.h: Reflect change in second argument to ready_for_read. + * syscalls.cc (_read): Ditto. + * termios.cc: Throughout, detect attempt to use old style termios + structure and convert as appropriate. + * ioctl.cc (ioctl): Detect use of ioctl requiring termios field + and call appropriate tc[gs]et* function to handle it. + * fhandler_console.cc (fhandler_console::ioctl): Remove TC* calls + that are now handled in main ioctl. + * fhandler_tty.cc (fhandler_tty_slave::ioctl): Ditto. + * include/cygwin/version.h: Added TERMIOS defines. Bump API_MINOR + to 6. + * include/sys/cygwin.h: Reflect change in return value for some + cygwin_conv_* calls. + * include/sys/termios.h: Reformat slightly. Add conversion macros + for dealing with old style termios structure. + * include/pthread.h: add + +Fri Dec 18 15:03:33 1998 Christopher Faylor + + * Makefile.in: Cleanup pthread usage. + +Fri Dec 18 14:35:59 1998 Christopher Faylor + + * Makefile.in: Remove obsolete header dependency for + thread-safe build. + +Fri Dec 18 14:16:04 1998 Christopher Faylor + + * exceptions.cc (sig_handle): Avoid suspending top-level + processes. + * trace.cc: Remove unneeded include. + +Thu Dec 17 19:19:53 1998 Geoffrey Noer + + * cygwin.din: remove pthread_getsequence_np, _reent_clib + +Thu Dec 17 16:48:15 1998 Geoffrey Noer + + * include/cygwin/version.h: correct two typos in comments + +Thu Dec 17 19:11:31 1998 Christopher Faylor + + patch from Corinna Vinschen : + * include/Windows32/Defines.h: Add values for using Windows + function `DeviceIoControl()'. + +Thu Dec 17 18:00:34 1998 Christopher Faylor + + * dcrt0.cc (dll_crt0_1): exception_list is not a struct. + * debug.cc (thread_stub): Ditto. + +Thu Dec 17 08:24:37 1998 Christopher Faylor + + * cygwin.din: Remove leading underscores from pthread functions. + * include/cygwin/version.h: Bump DLL major version to 21, DLL minor + version to 0, and API_MINOR to 5. + +Wed Dec 16 22:54:16 1998 Christopher Faylor + + Merge in thread-safe branch changes. + +Wed Dec 16 22:54:16 1998 Christopher Faylor + + * pthread.cc: Include winsup.h. + +Wed Dec 16 22:54:16 1998 Christopher Faylor + + * thread.cc: Reformat. + * pthread.cc: New file. + * cygwin.din: Add pthread interface functions + +Wed Dec 16 22:54:16 1998 Christopher Faylor + + * configure.in: Add some --enable options. + * configure: Regenerate. + * Makefile.in: Reorganize CFLAGS to recognize new --enable options. + +Wed Dec 16 22:54:16 1998 Christopher Faylor + + * fork.cc (stack_base): Store slightly different information + in child_info_fork structure for later use in alloc_stack_hard_way. + (fork): Set frame pointer information if stack has been reallocated. + * dcrt0.cc (alloc_stack_hard_way): Reflect change in + child_info_fork structure. + (dll_crt0_1): Make thread initializers "static" and NO_COPY or death + of the main thread causes death of other threads. + * winsup.h (child_info_fork): Change structure. + +Wed Dec 16 22:54:16 1998 Christopher Faylor + + * thread.h: Remove extraneous declaration. + * include/sys/strace.h: Make a new thread_printf function + for use by new thread-safe code. + * thread.cc: Use thread_printf throughout. + +Wed Dec 16 22:54:16 1998 Christopher Faylor + + patch from Marco Fuykschot (marco@ddi.nl) + * Throughout sources add locking control for preliminary + thread-safe cygwin operation. + +Wed Dec 16 22:54:16 1998 Christopher Faylor + + * dcrt0.cc (getprogname): Should be a static. + (alloc_stack): Extend to allow forking from another + thread. + (alloc_stack_hard_way): New function used by alloc_stack. + (dll_crt0_1); Don't pass parameters since stack may be + "funny". Use statics instead. Move fork/spawn checking + into dll_crt0. + (dll_crt0): Do fork spawn checking here. alloc_stack() + will call dll_crt0_1 if forked from a non-main thread. + * fork.cc (stack_base): New function determines base + (and other values) of this thread's stack. + (fork): Use new PROC_FORK1 method for forking. Provides + more data to forkee. Use stack_base to set stack + values. + * winsup.h (child_info_fork): Changes for PROC_FORK1. + +Wed Dec 16 16:15:29 1998 Geoffrey Noer + + * include/shellapi.h: fix typo in DragQueryPoint proto. + +Mon Dec 14 12:37:43 1998 Geoffrey Noer + + * net.cc: minor respacing + (get_ifconf): new local function, combines get_winnt_ifconf and + get_win95_ifconf. + (get_win95_ifconf): delete + (get_winnt_ifconf): delete + (fhandler_socket::ioctl): adjust ifconf calls in light of above, + check returned value for safety. + * include/cygwin/version.h: bump CYGWIN_VERSION_API_MINOR to 4 + in honor of newly supported socket ioctls. + + patch from Corinna Vinschen : + * include/asm/socket.h: Added defines for ioctl() calls + SIOCGIFADDR, SIOCGIFBRDADDR and SIOCGIFNETMASK. + * net.cc (get_winnt_ifconf): Check the registry entries + instead of just calling get_win95_ifconf(). Added what argument + to support the new ioctl() calls. + (get_win95_ifconf): Check the Windows 9x registry entries as + described by Tim Newsham. + (fhandler_socket::ioctl): Support the ioctl() commands + SIOCGIFADDR, SIOCGIFBRDADDR and SIOCGIFNETMASK. + (get_if_flags): Check for a down interface. + +Wed Dec 9 18:11:31 1998 Geoffrey Noer + + * fhandler.cc (fhandler_disk_file::open): check for shell scripts + regardless of Win32 OS type. + +Sun Dec 6 19:38:11 1998 Christopher Faylor + + patch from Corinna Vinschen : + * fhandler_console.cc (fhandler_console::tcgetattr): Fix typo. + ISIG should be ored with c_lflag. + +Tue Dec 1 16:28:56 1998 Geoffrey Noer + + * include/utmp.h: delete, moved to newlib/libc/sys/cygwin/sys. + +Thu Dec 3 15:41:51 1998 Geoffrey Noer + + Released 20.1 update. + +Thu Dec 3 22:24:18 1998 Christopher Faylor + + * exceptions.cc (set_process_mask): Add `sync' parameter + to control whether signals should be synched on exit. + (handle_sigsuspend): Provide second argument to set_process_mask - + don't sync. + (call_handler): Ditto for asm handler. + * signal.cc (sigprocmask): Ensure that signals are synchronized + by calling set_process_mask with sync == 1. + * sigproc.cc (__release_signal_mutex): Third argument is not + strictly a BOOL, so change it. + * sigproc.h: Reflect above parameter changes. + +Thu Dec 3 15:30:44 1998 Christopher Faylor + + * select.cc (peek_console): Work around NT bug that + caused strange behavior with ReadFile after this + function was invoked. + +Tue Dec 1 14:43:35 1998 Christopher Faylor + + * sigproc.cc (sigproc_init): Set maintid and signal_mutex early + to avoid races in wait_sig initialization. + (__get_signal_mutex): Improve debug output. + (__release_signal_mutex): Ditto. + * spawn.cc (spawn_guts): Allocate more space for string when building + up from #! and absolute path is not known. Otherwise weird stuff + like infinite recursion or unknown file errors occur. + +Tue Dec 1 08:34:18 1998 Christopher Faylor + + * mkvers.sh: Accomodate lack of timezone in date output so that + year shows up correctly. + +Mon Nov 30 14:30:51 1998 Jeff Johnston + + * times.cc (times): Altered function so that on non-Windows-NT systems + it does not use the GetProcessTimes() API which is not supported. + +Mon Nov 30 00:38:54 1998 Christopher Faylor + + * dcrt0.cc: Fix incorrect use of struct on exception_list + typedef. + * debug.cc (thread_stub): Ditto. + * dll_init.cc: Ditto. + * include/Windows32/Structures.h: Correct typo where + typedef SYSTEM_POWER_STATUS was being used as a struct. + +Sun Nov 29 22:03:17 1998 Christopher Faylor + + patch from Corinna Vinschen : + * fhandler_console.cc (fhandler_console::ioctl): + Added ioctl commands TCGETA, TCSETA, TCSETAW, TCSETAF. + +Fri Nov 27 22:30:58 1998 Christopher Faylor + + * fhandler.h: Set aside NOEINTR bit. When this is set + cygwin will not allow the read on this device to be + interrupted by a signal. + * pipe (_pipe): Set NOEINTR bit for read end of pipes + created using this method. The vague rationale for this + is that these pipes are supposed to be more like Windows + pipes than UNIX pipes. + * syscalls.cc (_pipe): Honor NOEINTR flag. + * getopt.c: Clean up some gcc warnings. + * libcerr.c: Ditto. + +Fri Nov 27 21:56:03 1998 Christopher Faylor + + * exceptions.cc (SIG_NONMASKABLE): Update for new signal + mask method. + (handle_sigsuspend): Release of signal mutex must be + synchronous -- the signal must be delivered before the + function returns. Otherwise, there will be races in + the caller code. + * sigproc.cc (sigproc_terminate): Minor cleanup. + +Thu Nov 26 20:26:17 1998 Christopher Faylor + + * exceptions.cc (call_handler): Attempt to work around + potential race when setting signal_arrived. This + particularly affects sigsuspend. + (handle_sigsuspend): Reset signal_arrived prior to + grabbing the mutex. This should reduce the probability + of a race. + * sigproc.cc (sig_send): Don't reset signal_arrived in + the SIGSUSPEND case since this could introduce a race. + +Thu Nov 26 12:19:16 1998 Christopher Faylor + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * select.cc (MAKEready): Don't wait for signal prior to + testing for read. That introduces an unnecessary delay. + +Wed Nov 25 23:03:47 1998 Christopher Faylor + + * winsup.h: Make `isdirsep' an alias for SLASH_P. + Implement isabspath convenience macro. + Change sigprotect to a macro since it appears to + be impossible to send __FILE__ type macros to a + constructor. Change use of sig_protect throughout. + * dcrt0.cc (dll_crt0_1): Use new path macro. + * dlfcn.cc (get_full_path_of_dll): Ditto. + * path.cc (path_conv::path_conv): Ditto. + (normalize_posix_path): Ditto. + (slashify): Ditto. + (backslashify): Ditto. + * syscalls.cc (num_entries): Ditto. + * lock.cc: Redefine lock methods to pass debug info to + {get,release}_signal_mutex. + * environ.cc (environ_init): Correct strncmp test for + TERM=, otherwise it's impossible to set TERM. + * exceptions.cc: Eliminate lock_cs and unlock_cs macros. + Use {get,release}_signal_mutex throughout. + (signal_init): Don't initialize signal_mutex here. + (set_process_mask): Remove vestiges of old mutex code. + (handle_sigsuspend): Ditto. + (call_handler): Move signal_arrived SetEvent back here. + It was being triggered too often before. + Detect when the signal thread is exiting. + (sig_handle): Remove inappropriate SetEvent(signal_arrived). + (events_terminate): Move close of signal_mutex elsewhere. + * glob.cc: Increase "MAXPATHLEN" size for arguments that + are not necessarily pathnames. + * pinfo.cc (lpfu): Lower timeout for reporting possible + problem with INFINITE wait. + * sigproc.cc (wake_wait_subproc): Make this a macro with + no arguments so that its use in the code is a little + clearer. + (proc_terminate): Eliminate signal blocking here since + this should already be handled by the caller. + (sigproc_init): It makes sense to initialize signal_mutex + here, so do so. + (__allow_sig_dispatch): Rename. Take debugging arguments. + Pass arguments on to release_signal_mutex. + (__block_sig_dispatch): Rename. Take debugging arguments. + Pass arguments on to get_signal_mutex. Detect signal + thread exiting confition. + (__get_signal_mutex): Take debugging arguments. Maintain + a stack of nested mutex calls for later display in + __release_signal_mutex. Detect signal thread exit + condition. Don't bother with locking if signal thread is + executing or if just an exec stub. + (__release_signal_mutex): Don't bother with locking if signal + thread is executing or if just an exec stub. + * sigproc.h: Reflect renamed functions above. Provide + wrappers to pass in diagnostic information. + * spawn.cc (spawn_guts): More fixes to deal with nested + #! and to properly report posix argv[0] when invoked as a + script. + +Wed Nov 25 12:41:12 1998 Christopher Faylor + + * Makefile.in: Reinstate libwinspool.a/winspool.drv creation. + +Tue Nov 24 18:48:56 1998 Geoffrey Noer + + * Makefile.in: add CFLAGS_COMMON and CFLAGS_CONFIG to CFLAGS + and CXXFLAGS in FLAGS_TO_PASS. + + * include/sys/select.h: new file with select proto. Avoid + potential conflict with Winsock inclusion by Cygwin internals. + * include/sys/socket.h: remove select proto. + * winsup.h: define __INSIDE_CYGWIN__. Include windows.h after + Unix include files. + * include/mywinsock.h: delete file + * include/Windows32/Sockets.h: add ndef __INSIDE_CYGWIN__s + around portions that conflict with Unix definitions. This + yields what used to be mywinsock.h which is a blend of Unix + sockets and Winsock needed by Cygwin internals. + * exceptions.cc: define Win32_Winsock to include + Windows32/Sockets.h. No longer define __INSIDE_CYGWIN__. + * hinfo.cc: ditto + * net.cc: ditto + * select.cc: ditto + + * include/exceptions.h: change wrapper define to _EXCEPTIONS_H. + * include/sys/resource.h: move includes outside __cplusplus check. + * include/sys/wait.h: ditto. + +Sun Nov 22 23:33:19 1998 Geoffrey Noer + + * sigproc.cc (__release_signal_mutex): revert Nov 3d change. + +Sun Nov 22 17:04:44 1998 Christopher Faylor + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * regexp/Makefile.in: Add additional bits necessary to + allow correct installation of include file. + +Fri Nov 20 17:04:48 1998 Christopher Faylor + + * Makefile.in: Set "Warn about writable strings" option in CFLAGS. + * fhandler_tty.h: Fix for writable strings detection. + * grp.cc (add_grp_line): Ditto. + * mkvers.sh: Ditto. + * path.h: Ditto. + * registry.cc: (reg_key::reg_key): Ditto. + * smallprint.c (__small_vsprintf): Ditto. + * tty.cc (tty::get_event): Ditto. + * winsup.h: Give up on read_ready_thread. Move sig_protect + here since it needs to use information set up after the sigproc.h + include. + * dcrt0.cc: Ditto. + * debug.cc (WFSO): New function. Used to ensure that + function shows up on stack trace. + (WFMO): Ditto. + * debug.h: Define the above. + * exceptions.cc (ctrl_c_handler): Record last signal + for signal handler. + * select.cc (MAKEready): New macro for constructing + fhandler_*::ready_for_read function. + (fhandler_*::ready_for_read): Use macro to construct this + method throughout. + * sigproc.cc (sig_send): Work around race on process termination + where the event being waited for may disappear. + (sigproc_terminate): #ifdef code here that attempted to deal with + the above condition in sig_send. + * sigproc.h: Move sig_protect to winsup.h. + * spawn.cc (perhaps_suffix): Don't return pointer into an + automatic variable. + (find_exec): Always point known_suffix to something. + * syscalls.cc (read_handler): Refine debug output. + (read_ready_thread): Delete. + (_read): Eliminate use of read_ready_thread. Call ready_for_read + directly as appropriate. + +Thu Nov 19 15:26:40 1998 Geoffrey Noer + + * Makefile.in: remove -Wunused since that's already in -Wall + * dlfcn.cc (check_path_access): rename winenv arg to mywinenv + * path.cc (symlink): change save_errno var to saved_errno + * spawn.cc (find_exec): rename winenv arg to mywinenv + (spawn_guts): rename sigprotect handle to starting_here + * winsup.h: remove trailing comma from process_state flags + enum + * utils/aclocal.m4: regenerate + * utils/configure: regenerate + +Thu Nov 19 11:16:38 1998 Christopher Faylor + + * Makefile.in: Use correct libpthread.a target when + thread-safe is enabled. + +Thu Nov 19 10:49:27 1998 Christopher Faylor + + * path.cc (path_conv): Correct error reporting. + +Wed Nov 18 20:07:50 1998 Geoffrey Noer + + * utils/Makefile.in: remove termcap file install rule + +Wed Nov 18 18:14:18 1998 Geoffrey Noer + + More minor cleanup: + * environ.cc (winenv): don't define len twice. + * fork.cc (sync_with_parent): should NOT use rc since + this is a macro and that could have interfered with rc in + the calling function. Renamed to psync_rc. + * fhandler_serial.cc (fhandler_serial::open): change + access to myaccess since it shadows global decl. + * hinfo.cc: ditto throughout + * path.cc: ditto throughout + (path_conv::path_conv): change error to err. + +Wed Nov 18 16:17:58 1998 Geoffrey Noer + + * profil.c: include stdio.h + (print_prof): comment out unused func + (profile_ctl): should return an int + +Wed Nov 18 16:17:58 1998 Geoffrey Noer + + * utils/ps.cc: include sys/cygwin.h, make pname buf + MAXPATH in size. + + patch from Corinna Vinschen : + * utils/ps.cc (main): converting windows paths to posix + paths in output. + +Wed Nov 18 15:34:46 1998 Geoffrey Noer + + * include/wchar.h: include stddef.h. + +Wed Nov 18 17:39:15 1998 Christopher Faylor + + * environ.cc (environ_init): Fix incorrect TERM= detection. + +Tue Nov 17 17:28:09 1998 Geoffrey Noer + + * gcrt0.c: include stdlib.h, add proto for monstartup. + +Tue Nov 17 16:47:42 1998 Geoffrey Noer + + * include/wchar.h: add protos for wcslen and wcscmp. + * syscalls.cc: minor reformat. + +Tue Nov 17 15:38:45 1998 Christopher Faylor + + * fhandler.cc (fhandler_base::fhandler_base): Default non-disk + devices to binary mode. + * fhandler.h: Reformat slightly. + +Tue Nov 17 11:19:23 1998 Christopher Faylor + + * external.cc (fillout_pinfo): Copy progname using strcpy to + save on time. + * path.h: Add new enums for more fine-grained control + of path_conv. + * dir.cc (opendir): Use enum argument to path_conv. + (mkdir): Ditto. + (rmdir): Ditto. + * dlfcn.cc (get_full_path_of_dll): Ditto. + * fhandler.h: Add new set_readahead_valid to set actual + readahead. + * fhandler.cc (raw_read): Remove extraneous variable. + (fhandler_base::read): Rework to allow readahead when + not text mode. + (fhandler_disk_file::fstat): get_symlink_p() only returns + true/false now. + (fhandler_disk_file::fhandler_disk_file): Use enum argument + to path_conv. + (fhandler_disk_file::open): Ditto. + * spawn.cc (perhaps_suffix): Ditto. + * syscalls.cc (_unlink): Ditto. + (_link): Ditto. + (stat_worker): Ditto. + (_rename): Ditto. + * fhandler_serial.cc (fhandler_serial::open): Always reset timeouts. + * path.cc (path_conv::path_conv): Honor new enum arguments. + Specifically, use SYMLINK_CONTENTS for readlink interface. + (readlink): Use SYMLINK_CONTENTS argument to path_conv. + * select.cc: Rework serial support which has apparently never + worked. + +Mon Nov 16 16:15:20 1998 Geoffrey Noer + + * Makefile.in: FLAGS_TO_PASS should pass CFLAGS and CXXFLAGS + not ALL_CFLAGS and ALL_CXXFLAGS. Rework handling of CFLAGS + variables to remove duplication and make it possible to + build mingw directory. + +Mon Nov 16 09:40:21 1998 Christopher Faylor + + * syscalls.cc (_open): Use new macro to check for + NULL or empty pathname and return appropriate error. + * path.cc (check_null_empty_path*): Move macro to + path.h. + * path.h: Move macros here. + +Sun Nov 15 20:23:10 1998 Geoffrey Noer + + * include/cygwin/version.h: bump API_MINOR to 3 to mark + addition of dll_noncygwin_dllcrt0 to exports list. + +Sun Nov 15 23:05:21 1998 Christopher Faylor + + * path.cc (check_null_empty_path): New macro. + (check_null_empty_path_errno): Ditto. + (path_conv::path_conv): Check for NULL and empty + path names here and set appropriate error. + (conv_to_win32_path): Ditto. + (conv_to_full_win32_path): Ditto. + (conv_to_posix_path): Ditto. + (conv_to_full_posix_path): Ditto. + (mount_info::conv_wo_win32_path): Back out previous + change. + (mount_info::conv_to_posix_path): Ditto. + +Sun Nov 15 19:29:19 1998 Geoffrey Noer + + * include/limits.h: define CHILD_MAX to be 63. + * sysconf.cc (sysconf): return CHILD_MAX when asked for + instead of _POSIX_CHILD_MAX. + +Sun Nov 15 18:25:22 1998 Geoffrey Noer + + patch from Mumit Khan : + * path.cc (mount_info::conv_to_posix_path): Handle NULL and + empty pathnames. + (mount_info::conv_to_win32_path): Likewise. + +Sun Nov 15 18:09:06 1998 Geoffrey Noer + + * cygwin.din: export dll_noncygwin_dllcrt0. + * {libccrt0.cc, winsup.h}: minor reformat. + +Sat Nov 14 22:14:51 1998 Christopher Faylor + + * environ.cc (environ_init): Use sizeof for string lengths + rather than hard-coded values. + + patch from Mumit Khan : + * dll_init.cc (dll_foreign_dllcrt0): Rename to + dll_noncygwin_dllcrt0. + * winsup.h: Ditto. + * include/cygwin/cygwin_dll.h: Ditto. + +Sat Nov 14 14:09:33 1998 Christopher Faylor + + * hinfo.cc (hinfo::de_linearize_fd_array): Reset first fd + for open to zero after an exec. + +Sat Nov 14 01:29:23 1998 Christopher Faylor + + * fork.cc (fork): No need for intermediate jmp_buf variable. + + patch from Mumit Khan : + * libccrt0.cc (cygwin_attach_foreign_dll): New function. + * dll_init.cc (dll_foreign_dllcrt0): New function to initialize + DLLs loaded by non-cygwin apps. + (dll_dllcrt0_1): Initialize process table entry. + (dll_dllcrt0): Revert last change to do partial initialization. + * winsup.h (dll_foreign_dllcrt0): Prototype. + * include/cygwin/cygwin_dll.h (_cygwin_foreign_dll_entry): New + entry point that does partial initialization for non-cygwin apps. + +Fri Nov 13 16:17:28 1998 Geoffrey Noer + + Assorted -Wall cleanup: + * utils/mount.cc (show_mounts): remove unused var i. + * utils/cygcheck.cc (dll_info): comment out unused var ofs. + (dump_sysinfo): return a void, not an int. Comment out unused + var len in two places. Add parens around assignment used as + truth value. + * utils/kill.cc (main): remove unused var i + * utils/mkpasswd: include and . + (enum_users): remove unused var rc. + (enum_local_groups): ditto. + * utils/ps.cc (main): Add parens around assignments used as + truth values. + * utils/mkgroup.c: include and . + (enum_groups): return void, not int. Remove unused var rc. + * gmon.c: include and . + (_mcleanup): remove unused vars buf and profdir. + +Fri Nov 13 16:17:28 1998 Geoffrey Noer + + patch from Corinna Vinschen : + * include/sys/sysmacros.h: new file, define major, minor, makedev + +Fri Nov 13 17:03:52 1998 Christopher Faylor + + * dcrt0.cc: Reflect a variable name change. + * fhandler.h: *::ready_for read takes an additional argument. + * fhandler_console.cc (get_non_ascii_key): New function derived + from fhandler_console::read1. + (fhandler_console::read1): Use new function. + * select.cc (*::ready_for_read): Add new "nonblocking" argument. + (peek_console): Be more diligent in detecting when a usable + character has been entered or false positives will be returned. + (fhandler_tty_common::ready_for_read): Detect attempt to perform + a "background" read. + * syscalls.cc (read_handler): Remove code for dealing with slow + devices. Just deal with non-blocking here. + (read_ready_thread): Renamed function. Rewritten to only detect + when an fd has data ready to be read. Actual reads happen in + the main thread. + (_read): Rely on read_handler to read data for everything. Use + the read_ready_thread to indicate when data is ready to be read. + Gut the read_thread_info class since it no longer needs to return + much information. + * winsup.h: Reflect above changes to read_thread_info. Rename + to read_ready_thread_info. + +Fri Nov 13 15:09:26 1998 Christopher Faylor + + patch from Corinna Vinschen and + Ron Parker : + * path.cc (mount_info::conv_to_win32_path): Refined recognition of + UNC devices. + +Fri Nov 13 12:37:00 1998 Christopher Faylor + + * Makefile.in: Fix a typo. + +Fri Nov 13 10:59:43 1998 DJ Delorie + + * Makefile.in: "make" uses new "ld -shared" by default internally. + +Fri Nov 13 00:58:38 1998 Christopher Faylor + + * spawn.cc (find_exec): Make sure that return value is correct + in all cases. Document. + * fhandler.h (fhandler_tty_common): Give unit number to constructor. + * fhandler_tty.cc (fhandler_tty_slave::fhandler_tty_slave): Give + unit number to descriptor. Create correct UNIX path name for + tty so that ttyname() will work correctly. + * select.cc (fhandler_tty_common::ready_for_read): Don't worry + about read_for_read since the tty read routines are already + interruptible. + * syscalls.cc (_read): Reset read thread events on signal. + + patch from Mumit Khan : + * dlfcn.cc (ctype.h): Include. + (check_access): Document. + (check_path_access): Document. + (get_full_path_to_dll): Rework to handle general filenames and + symlinks. + +Thu Nov 12 17:01:52 1998 DJ Delorie + + * Makefile.in (shared): "make shared" uses the new "ld -shared" + * cygwin.din: add LIBRARY and BASE tags for "ld -shared" + +Wed Nov 11 17:16:17 1998 Christopher Faylor + + * configure.in: Add --enable options for various cygwin defines + including preliminary thread-safe defines. + * configure: Regenerate + * Makefile.in: Honor new --enable options. + * glob.h: Move BSD defines to sys/cdefs.h. + * include/sys/cdefs.h: Move __P definition here. + +Wed Nov 11 14:00:45 1998 DJ Delorie + + * cygwin.din (getpwnam): remove duplicates + +Tue Nov 10 18:27:09 1998 Geoffrey Noer + + * utils/aclocal.m4: regenerate with aclocal + * utils/configure.in: don't call AM_CYGWIN32 + * utils/configure: regenerate + +Tue Nov 10 15:56:03 1998 Geoffrey Noer + + patch from Gary V. Vaughan : + * dlfcn.cc (dlopen): return an introspective handle to the + current module if name arg is NULL. The Single UNIX + Specification, Version 2 has this as a requirement. + +Mon Nov 9 16:29:27 1998 Geoffrey Noer + + * errno.cc (strerror): all errnos in + newlib/libc/include/sys/errno.h are now listed here. + +Mon Nov 9 16:29:27 1998 Geoffrey Noer + + * include/cygwin/version.h: up DLL version, bump API_MINOR to 2 + to mark following change. + + patch from Mumit Khan : + * cygwin.din: add exports for some of the newlib bessel + functions (j1, jn, y1, yn). + +Mon Nov 9 15:10:06 1998 Geoffrey Noer + + * syscalls.cc (_link): rewrite FIXME. + +Mon Nov 9 14:51:03 1998 Geoffrey Noer + + * errno.cc (strerror): add string for EDEADLOCK. + + patch from Corinna Vinschen : + * errno.cc (errmap[]): add END_OF_MEDIA and additional Win32 + error codes. + +Sun Nov 8 21:28:01 1998 Christopher Faylor + + * fhandler.h: fhandler_pipe cannot be is_slow under + Windows9[58]. There is no way to check for EOF on a pipe + without performing a read on that system. + * syscalls.cc (read_handler): Don't check for ready_for_read + unless this is a "slow" device. + * winsup.h: Reorganize to accomdate fhandler.h requirement + for os_type. + +Sat Nov 7 23:27:05 1998 Christopher Faylor + + * fhandler.h (fhandler_console): Add a new function declaration. + * fhandler_console.cc (fhandler_console::read1): New function + renamed from console_read to allow use of class fields. + Detect readahead situation when doing line buffering and + buffer does not contain \n. + (fhandler_console::read): Reflect function name change. + * select.cc (cygwin_select): Changes for better handling + of < 1000 usec timeouts. + (select_stuff::wait): Perform a poll on timeout to + set any fd's that may have become active. + (peek_pipe): More debugging. Honor write_ready if set. + (peek_console): Can't always use WaitForSingleObject. + Detect readahead conditions set in fhandler_console::read1. + Honor write_ready if set. + (peek_windows): Honor write_ready if set. + * times.cc (__to_clock_t): Return clock_t value. + (times): Add some debugging printfs. + +Fri Nov 6 20:15:20 1998 Christopher Faylor + + patch from Corinna Vinschen : + * spawn.cc (spawn_guts): find_exec() argument mismatch + resulted in inability to run !# scripts which did not + begin with '/'. + +Tue Nov 3 16:12:59 1998 Christopher Faylor + + * exceptions.cc (handle_exceptions): Don't wait for signal + completion. + (ctrl_c_handler): Ditto. + * fhandler.h (fhandler_*): Declare new ready_for_read functions. + * select.cc: Reorganize all methods into a peek_*, a poll_*, + and a fhandler_*::ready_for_read. This is to allow the _read + function to query the state of an fd without starting a thread. + * signal.cc (kill_worker): If sending a signal from a non-main thread + don't wait for completion. + * sigproc.h (myself_nowait_nonmain): New define for use by sig_send. + * sigproc.cc (sig_send): Honor myself_nowait_nonmain. Don't wait + if not in main thread. + (__release_signal_mutex): Revert to calling ReleaseMutex only + once or mutex is released prematurely. + * syscalls.cc (read_handler): Use new ready_for_read method to + determine if an fd has data for reading. This function optionally + blocks until there is data to read. + (read_helper): Add debugging statement. + (_read): Move signal_arrived reset to before sig_protect to avoid + a race. Force read_handler thread to longjmp back to read_handler + function on signal. + +Tue Nov 3 12:18:31 1998 DJ Delorie + + * utils/cygcheck.cc (dump_sysinfo): Note when not finding a + program (like cpp) on the path is a good thing. + +Tue Nov 3 01:26:08 1998 Geoffrey Noer + + patch from Kazuhiro Fujieda : + * environ.cc (environ_init): correct size arg to parse_options + +Mon Nov 2 21:40:32 1998 Christopher Faylor + + * regexp/regexp.c (regatom): Respond to compiler warning. + +Mon Nov 2 21:36:48 1998 Christopher Faylor + + * exceptions.cc (handle_exceptions): cygwin should not + print exception information if the exception is trapped + via signal(). + Also use consistent timings for lock_cs() throughout. + +Mon Nov 2 16:46:28 1998 Geoffrey Noer + + * Makefile.in: For now, also include newlib/libc/sys/cygwin. + Eventually will stop including newlib/libc/sys/cygwin32. + +Mon Nov 2 19:38:30 1998 Christopher Faylor + + patch from Corinna Vinschen : + * syscall.cc (gethostname): function deleted + * net.cc (gethostname): new function 'gethostname' which + first calls wsock32::gethostname and only if it fails, + calls GetComputerNameA. + +Wed Oct 28 17:57:53 1998 Geoffrey Noer + + * include/cygwin/version.h: up DLL version to 20.0 in honor + of new Net release. + +Wed Oct 28 17:57:53 1998 Geoffrey Noer + + patch from Mumit Khan : + * dll_init.cc (doGlobalCTORS): Fix invocation order. + (doGlobalDTORS): Likewise. + +Wed Oct 28 17:57:53 1998 Geoffrey Noer + + * Makefile.in: add include/exceptions.h to dll_init.cc deps. + + patch from Mumit Khan : + * dll_init.cc (exceptions.h): Include. + (dll_dllcrt0_1): New function to initialize Cygwin DLL guts + properly when a non-Cygwin app uses the Cygwin DLL. + (dll_dllcrt0): Call dll_dllcrt0_1 when user_data is NULL. + +Tue Oct 27 17:35:00 1998 Geoffrey Noer + + * syslog.cc: drop "32" from CYGWIN32_LOG_NAME + +Tue Oct 27 16:09:09 1998 DJ Delorie + + * utils/cygcheck.cc (usage): cygwhich->cygcheck + +Mon Oct 26 17:47:10 1998 Geoffrey Noer + + * Makefile.in: fix deps for dll_entry.o and dll_main.o, + add dep for glob.o. + + patch from Mumit Khan : + * dll_entry.cc: New file for user DLL entry point. + * dll_main.cc: New file for user DLL main. + * Makefile.in (LIBCOS): Add dll_entry.o and dll_main.o. + +Mon Oct 26 13:47:10 1998 Geoffrey Noer + + * Makefile.in: add back install of include/net which was + removed by accident. + +Mon Oct 26 15:25:22 1998 Christopher Faylor + + * strace.cc (get_strace_mutex): Don't reset last windows + error. + (strace_printf): Preserve last windows error. + +Mon Oct 26 11:01:46 1998 Christopher Faylor + + * uname.cc (uname): Remove slash from system name. + +Mon Oct 26 02:11:44 1998 Geoffrey Noer + + * include/asm/byteorder.h: add missing __cplusplus wrapper. + +Mon Oct 26 00:46:33 1998 Christopher Faylor + + * uname.cc (uname): Remove space from the system name. + +Sun Oct 25 23:47:56 1998 Christopher Faylor + + * fhandler_console.cc (console_read): Several typos caused flaky + behavior when \r or \n detected under ENABLE_LINE_INPUT. Also ignore + first \n detected under ENABLE_LINE_INPUT if it isn't preceded by a \r. + This avoids problems when switching from "raw" mode into "cooked mode. + +Sun Oct 25 12:28:21 1998 Geoffrey Noer + + * cygwin.din: remove unnecessary __cygwin32_stack_trace and + __cygwin_stack_trace exports. + +Sat Oct 24 21:18:46 1998 Christopher Faylor + + patch from Corinna Vinschen : + * path.cc (symlink): Standard protection for symlink should + be 0777. + * syscalls.cc (num_entries): Calculated links for directory + entry should only include directories. + +Sat Oct 24 20:51:08 1998 Christopher Faylor + + * mkvers.sh: Modify check for CVS/Tag to work around ash bug. + * sigproc.cc (wait_sig): Fix detection of non-blockable signals. + +Fri Oct 23 18:24:43 1998 Geoffrey Noer + + * environ.cc: CYGWIN32 environment variable is now called CYGWIN + * window.cc: lose "32" in Cygwin32WndClass + * syslog.cc: lose "32" in WIN95_EVENT_LOG_PATH and + CYGWIN32_LOG_NAME. + +Fri Oct 23 16:32:59 1998 Geoffrey Noer + + * utils/cygcheck.cc: reformat, add copyright notice + +Fri Oct 23 18:15:28 1998 DJ Delorie + + * utils/cygcheck.cc: new file + * utils/Makefile.in: build cygcheck.exe + +Fri Oct 23 16:48:41 1998 Christopher Faylor + + * exceptions.cc (signals_init): Add error to api_fatal. + (events_init): Ditto. Collapse printfs into one. + (winsock_init): Ditto. + * net.cc (winsock_init): Remove "Cygwin" from error message. + +Fri Oct 23 13:48:10 1998 Geoffrey Noer + + * Makefile.in: install include/cygwin headers, losing the "32". + * include/cygwin32: remove + +Fri Oct 23 14:36:31 1998 Christopher Faylor + + * environ.cc (environ_init): Avoid reallocating environ array. + * exec.cc: Increase number of arguments to 1024 throughout. + * fhandler.cc (fhandler_disk_file::open): Revert to checking + a file for '#!' to find out if it is executable but add + extra check for NTEA which, if set, eliminates the need for + the read. + * sigproc.cc (sigproc_terminate): Close hwait_sig and set it + to NULL prior to closing other handles since this flags some + routines that the process is going down. + +Fri Oct 23 00:31:27 1998 Geoffrey Noer + + * utils/*: remove "32"s from cygwin32_foo function calls + +Fri Oct 23 00:24:27 1998 Geoffrey Noer + + * include/cygwin/version.h: increment CYGWIN_VERSION_DLL_MINOR + and CYGWIN_VERSION_API_MINOR since I'm changing the API in a + meaningful but backwards-compatible fashion. + + * exceptions.cc: strip "32" from cygwin32_exception_handler + debug printfs + + * net.cc: strip "32" from all net functions + * select.cc, syscalls.cc, winsup.h: lose "32" from cygwin32_select + * cygwin.din: adjust for these changes (no backwards + compatability issues here). + + * cygwin.din: rename all cygwin32_foo functions, aliasing as + cygwin_foo for backwards compat. for now but intend to lose them + at a later date. + * include/sys/cygwin.h: copy all cygwin32_ protos and make them + usable without the "32". We will remove the cygwin32_ ones at a + later date. + * external.cc, external.h: lose "32" from cygwin32_internal + * shared.cc, winsup.h: lose "32" in cygwin32_getshared + * path.cc, path.h: lose "32" in cygwin32_foo comments + * dll_init.cc: lose "32" in cygwin32_detach_dll + * hinfo.cc: lose "32" in cygwin32_attach_handle_to_fd + * libccrt0.cc: lose "32" in refs to cygwin32_attach_dll + * pinfo.cc: lose "32" in cygwin32_winpid_to_pid + + * include/cygwin32: remove all files except cygwin32_dll.h which + some people may already be including. Aim to remove this + remaining file at a later date. + * include/cygwin: move all include/cygwin32 files here. + * cygwin/cygwin_dll.h: change protos to reflect loss of "32"s + * include/net/if.h, include/netinet/in.h, include/netinet/ip.h, + include/netinet/ip_icmp.h, include/asm/socket.h: + include/sys/socket.h: include the headers in include/cygwin + * Makefile.in, winsup.h: fix references to + include/cygwin32/version.h + + * libcctype.c, smallprint.c, test.c: lose "32" in Cygwin32 refs in + comments + * include/dlfcn.h, include/exceptions.h, include/mapi.h, + include/winsock.h, include/mywinsock.h: ditto + * config/*: ditto + * profil.c: ditto, and respace + +Thu Oct 22 22:52:40 1998 Geoffrey Noer + + * net.cc, exceptions.cc, hinfo.cc, select.cc, + include/mywinsock.h: rename __INSIDE_CYGWIN32__ to + __INSIDE_CYGWIN__ + +Thu Oct 22 17:39:06 1998 Geoffrey Noer + + First round of Cygwin32 -> Cygwin renaming. In all files, + rename Cygwin32 to Cygwin in comments. + * CYGWIN32_LICENSE: delete and + * CYGWIN_LICENSE: add it back under this name + +Thu Oct 22 20:10:24 1998 Christopher Faylor + + * exceptions.cc: Eliminate cs mutex. Just use signal_mutex + throughout. Rename sig_dispatch_mutex to signal_mutex throughout. + (lock_cs): Rewrite to be a front-end for get_signal_mutex. + (unlock_cs): Rewrite to be a front-end for release_signal_mutex. + (set_process_mask): Synchronize signals after resetting mask. + * sigproc.cc (release_signal_mutex): Report on success or + failure of signal_mutex release. + * include/Windows32/Defines.h (FILE_FLAG_WRITE_THROUGH): Make + unsigned to avoid a compiler warning. + +Thu Oct 22 14:23:49 1998 Geoffrey Noer + + * utils/Makefile.in: disable building cygwin.exe. + +Thu Oct 22 14:16:10 1998 Christopher Faylor + + * exceptions.cc (sig_handle): Minimize life of cs lock during + handling of signals to reduce the potential for a race. + +Thu Oct 22 10:23:19 1998 Christopher Faylor + + * include/sys/strace.h: Minor addition from threadsafe-branch. + +Thu Oct 22 09:03:18 1998 Christopher Faylor + + * debug.cc (close_handle): Error condition needs a return value. + * environ.cc (parse_thing): char pointers should all be constant. + (add): Ditto. + * heap.cc (heap_init): Provide a little more information in + fatal printf. Use api_fatal to print errors. + * sigproc.cc (sigproc_terminate): Move code executed on + thread termination here from wait_sig since this function + may actually be executing in the signal thread. + * strace.cc (strace_open): Argument should be const. + (strace_init): Ditto. + * winsup.h: Ditto. + * include/cygwin32/version.h: Note that original shared memory + version was 0 for 98r2. + +Wed Oct 21 08:41:39 1998 Christopher Faylor + + * dcrt0.cc (__api_fatal): Remove "cygwin" identifier. + * fhandler.cc (fhandler_disk_file::open): Set symlink flag + appropriately for previous change. + * shared.cc (shared_name): Initialize static buffer to + (hopefully) force it into NO_COPY segment. + * mkvers.sh: Reorganize, add cvs tag detection, and output + cygwin "info" defines. + +Tue Oct 20 18:42:50 1998 Geoffrey Noer + + * include/cygwin32/version.h: rewrite versioning comments, + updating for new scheme but keeping historical information. + +Mon Oct 19 23:45:24 1998 Geoffrey Noer + + * include/windows.h: remove Objective-C BOOL ifdef, now taken + care of within the include/Windows32 header files. + * fhandler_console.cc: fix KeyEvent references in light of + changes to the KeyEvent struct in the Windows32 headers. + + Update include/Windows32 header files. Changes from + Mumit Khan , Corinna Vinschen + , and me. + * include/Windows32/CommonFunctions.h: new file, contents from + Functions.h. + * include/Windows32/*.h: Misc updates. + +Mon Oct 19 20:26:15 1998 Christopher Faylor + + * debug.cc: Throughout, avoid calling *_printf while lock + is active. Previous lock count was not thread-safe. + * fhandler_console.cc (console_read): Avoid sending a + \r to caller if ENABLE_LINE_INPUT. + (fhandler_console::read): Rely on console_read to handle + \r\n conversion. + +Mon Oct 19 12:10:09 1998 Christopher Faylor + + * mkvers.sh: Use more portable constructs to allow running + this with /bin/sh, bash, and ksh. + +Mon Oct 19 11:19:58 1998 Christopher Faylor + + * path.cc (mount_info::from_registry): Missed "b15.0" part + for writing mount information back to registry. + (mount_info::init): Remove obsolete stuff. + +Mon Oct 19 10:42:17 1998 Christopher Faylor + + * Makefile.in: Avoid newer GNU make construction when building + version.cc. + +Mon Oct 19 00:09:06 1998 Geoffrey Noer + + * Makefile.in: invoke mkvers.sh with $(SHELL) + +Sun Oct 18 15:19:17 1998 Christopher Faylor + + * fhandler.cc (set_name): Accept unit argument for generating + win32_name. + (fhandler_base::fhandler_base): Ditto. + (fhandler_dev_floppy::fhandler_dev_floppy): Ditto. + (fhandler_dev_tape::fhandler_dev_tape): Ditto. + (fstat): Set symlink bit only if symlink_p is positive. + * fhandler.h: Reflect unit argument changes. + * fhandler_serial.cc (fhandler_serial::fhandler_serial): Accept + unit argument for generating win32_name. + * hinfo.cc (hinfo::build_fhandler): Pass unit argument to constructor + where apropriate. + * path.cc (path_conv::path_conv): Set symlink_p to a positive + value if !nofollow, negative otherwise. + (windows_device_names): Can't default to \dev\comx. \dev part + doesn't work. + (get_device_number): Accept just "comN" for backwards compatibility. + +Sat Oct 17 01:58:15 1998 Christopher Faylor + + * dcrt0.cc (globify): Fix problem with argument corruption + due to use of pointer freed by realloc. + +Sat Oct 17 00:10:53 1998 Christopher Faylor + + Change NOT_OPEN_FD to dtable.not_open throughout. + * Makefile.in: Change .dll name to cygwin1.dll. Increment + the '1' when there are API/shared memory changes. Make + version.cc file every time .dll is linked. Remove datestamp + stuff. + * mkvers.sh: New file. Creates version.cc. + * cygwin.din: Export setdtablesize. + * dcrt0.cc: Remove obsolete version variables. + (build_argv): Use issep() macro rather than isspace since + isspace includes whitespace that the shell does not consider + a command separator. + (check_sanity_and_sync): Use new cygwin version defines and + structures for compatibility checking. + (dll_crt0_1): Ditto. + (__api_fatal): Renamed from api_fatal. Now always called from + macro which tacks program name to beginning of fmt. Increase + size of buffer. + * environ.cc (regopt): Use new reg_key class constructor + functionality. + * net.cc (getdomainname): Ditto. + * path.cc (read_mounts): Ditto. + (mount_info::from_registry): Ditto. + (mount_info::to_registry): Ditto. + (hash_path_name): No need for this to be a "C" function. + * external.cc (cygwin32_internal): Export version info strings. + * external.h: Add CW_GETVERSIONINFO. + * fhandler.cc (fhandler_base::write): Eliminate use of MIN macro. + * init.cc (set_dllname): Obsolete function. Handled in version.cc. + (dll_entry): Remove reference to set_dllname. + * libccrt0.cc (this_proc): Renamed from cygwin_statu. + (cygwin_crt0_common): Record api version in this_proc. + * mmap.cc (recreate_mmaps_after_fork): No need for this to be + a "C" function. + * syscalls.cc (close_all_files): Ditto. + * pinfo.cc (lock_pinfo_for_update): Eliminate a compiler warning. + * registry.cc: Eliminate reg_session class. Augment reg_key to handle + functionality of reg_session. + * registry.h: Ditto. + * shared.cc (shared_name): No need for this to be a "C" function. + Use new cygwin version structure. + (shared_info::initialize): Use new reg_key class constructor + functionality. + * smallprint.c (__small_vsprintf): Accept %P as a format specifier. + Signifies the program name. + * spawn.cc (spawn_guts): Quote *all* of the stuff the dcrt0.c considers + special. + * tty.cc (tty::inuse_event_exists): Remove debugging printf. It results + in too much output to strace log. + * uinfo.cc: Add a needed include. + * uname.cc (uname): Use new cygwin version structure to fill in utsname + fields. + * winsup.h: Regroup into sections. Add new version structure. + * include/utmp.h: Move login/logout function declarations here. + * include/cygwin32/version.h: Define new CYGWIN version/info + stuff here. + +Fri Oct 16 00:13:35 1998 Geoffrey Noer + + * Makefile.in: enable building mingw subdir by default + +Thu Oct 15 12:01:08 1998 Christopher Faylor + + * spawn.cc (spawn_guts): Set all security attributes + for CreateProcess so that sexec will work properly. + +Thu Oct 15 08:49:12 1998 Christopher Faylor + + * hinfo.cc (hinfo::dup2): Avoid a null pointer dereference + in a debugging printf. + +Wed Oct 14 18:06:51 1998 Geoffrey Noer + + patch from Corinna Vinschen : + * fhandler_console.cc (fhandler_console::dup): reset + default_color since the console fhandler forgets its default + colorizing when it's `dup'ed. + (fhandler_console::fhandler_console): remove unnecessary + erasing in constructor of fhandler_console. + +Mon Oct 12 22:20:59 1998 Christopher Faylor + + * fcntl.cc (fcntl): According to the "Single UNIX Specification", + F_DUPFD should *not* close its argument. Revert to previous + behavior. + * hinfo.cc (dup2): Guard against closing target fd too early. + * pinfo.cc: Always initialize myself to a dummy value so that + myself != NULL checks are avoided. + * include/sys/strace.h (strace): Remove NULL check for myself. + * dcrt0.cc (api_fatal): Ditto. + * exceptions.cc (handle_exceptions): Ditto. + * signal.cc (sigprocmask): Ditto. + (_raise): Ditto. + * strace.cc (get_strace_mutex): Ditto. + +Mon Oct 12 15:19:47 1998 DJ Delorie + + * utils/ps.cc (main): use const char *pname + +Fri Oct 9 12:32:23 1998 Christopher Faylor + + * syscalls.cc (getw): Simplify. + +Thu Oct 8 23:09:34 1998 Geoffrey Noer + + * times.cc: add missing syscall_printfs to time functions, + slight reformatting. + +Thu Oct 8 21:56:37 1998 DJ Delorie + + * hinfo.cc (cygwin32_attach_handle_to_fd): allow to pass -1 + for dup() simulation; return allocated fd. + * pinfo.cc (lock_pinfo_for_update): if the mutex is broken, + fail instead of looping. If you do loop, don't use 100% CPU. + +Thu Oct 8 18:33:02 1998 Christopher Faylor + + * dcrt0.cc: Add another per-thread object for strace. + (quoted): Fix misconception of method used to quote + quotes. + (globify): Optionally output arguments. + (build_argv): Ditto. + (dll_crt0_1): Fix typo in line reassignment. + * debug.cc (class locker): Avoid calling lock multiple times. + * exceptions.cc (call_handler): Set strace recursion flag + to zero when invoking a signal handler. + * fcntl.cc (_fcntl): F_DUPFD should close its argument. + * fork.cc (fork): Move determination of parent process to + a safer place. + * sigproc.cc (get_sig_dispatch_mutex): Rename. Use macro + interface to provide the name of the caller for strace output. + (release_sig_dispatch_mutex): Ditto. + * sigproc.h: Define *_dispatch_mutex wrappers. + * strace.cc (strace_printf): Use new per-thread object to + guard against recursion. + * winsup.h: Define per_thread_strace_protect. Redo per_thread + base class for a little more clarity. + +Wed Oct 7 22:30:43 1998 Geoffrey Noer + + * fhandler_tty.h: up NTTYs from 16 to 128 + +Wed Oct 7 09:15:55 1998 Christopher Faylor + + * fhandler_console.cc (console_read): Distinguish between + 0 byte return from CTRL-C and EOF condition. + +Tue Oct 6 22:31:44 1998 Christopher Faylor + + * dcrt0.cc (build_argv): Rewrite. Now: 1) allocates argv on + the fly, 2) inserts '@' files as they are found, 3) uses + sh-style quoting using either " or ' which may be embedded + in an argument. + (insert_file): Don't scan command line. Accept already + parsed arguments from build_argv. + (quoted): New function for parsing quoted strings. + (globify): Don't scan argv list. Accept element from + build_argv which will be tacked to end of argv as it + is being built. Extend quoting options to allow + tilde, braces, and quotes. + (dcrt0_dll_1): Simplify argv processing. Just call + build_argv, which handles everything. + +Tue Oct 6 11:04:43 1998 Christopher Faylor + + Change Create[A-Z]* calls throughout to use sec_none_nih + to avoid subprocesses accidentally inheriting handles. + * grp.cc: Hold group structures in group_buf rather than + an image of the /etc/group file. + (parse_grp): New function to parse a group line into a + struct group. + (add_grp_line): Use parse_grp to add line from /etc/group + into internal cache. + (read_etc_group): Avoid redundant feof call. Set up + default group. + (getgrgid): Just return appropriate entry from group_buf + rather than reparsing internal representation. + (getgrnam): Ditto. + (getgrent): Ditto. + * hinfo.cc (hinfo::select_*): Set errno value when attempt + is made to use an unopened fd. + * passwd.cc: Hold passwd structures in passwd_buf rather than + an image of the /etc/passwd file. + (parse_pw): New function to parse a passwd line into a + struct passwd. + (add_pw_line): Use parse_pw to add line from /etc/passwd + into internal cache. + (read_etc_passwd): Avoid redundant feof call. + (search_for): Just scan passwd_buf for matching entries. + (getpwent): Just return appropriate entry from passwd_buf + rather than reparsing internal representation. + +Mon Oct 5 18:06:31 1998 Geoffrey Noer + + patch from Corinna Vinschen : + * sysdef/kernel32.def: add missing GetDiskFreeSpaceEx lines + +Sat Oct 3 23:52:23 1998 Christopher Faylor + + * dcrt0.cc (si): Initialize so that NO_COPY will work. + * debug.cc (class locker): Fix previous change. Critical + sections are still required, so protect them if operating + in main thread to avoid signal problems. + Make any previously static use of locker global since that + appears to be the only foolproof way of marking the variable + NO_COPY. Rename these variables to something that is not + likely to be collided with. + * exceptions.cc (call_handler): Signal arrival of a dispatched + signal here and wait a long time for the mutex before giving + up. Should increase performance slightly. + * sigproc.cc (maintid): New external symbol. + * sigproc.cc (maintid): Make this global since it is used + in other places now. + (sig_dispatch_pending): Don't wait for wait_sig to complete + if there are no pending signals. Avoids a race and should + be faster. + (wait_sig): Don't set signal_arrived event here. Do it in + call_handler. + * strace.cc (strace_printf): Remove previous recursion check + since it is not signal safe. + * syscalls.cc (_read): Remove duplicate CreateEvent typo. + +Fri Oct 2 09:54:42 1998 DJ Delorie + + * strace.cc (strace_printf): protect against recursion + +Thu Oct 1 17:08:47 1998 Geoffrey Noer + + * utils/ps.cc (main): add more detailed usage printfs + +Thu Oct 1 11:05:16 1998 Christopher Faylor + + * Makefile.in: Fix typo in debug.o dependency. + * debug.cc (class locker): Give up on using critical sections + since they are not safe to use in the main thread due to signals. + +Wed Sep 30 22:34:42 1998 Christopher Faylor + + * fork.cc (fork): Close parent's parent_alive handle + if there is one or suffer a handle leak. + * syscalls.cc (_read): Make all events no access and + non-inheritable or suffer potential handle leak. + * windows.cc (gethwnd): Ditto. + +Wed Sep 30 17:22:29 1998 Geoffrey Noer + + * include/io.h: add missing setmode proto + +Tue Sep 29 23:33:11 1998 Christopher Faylor + + * fhandler_tty.cc (fhandler_pty_master::close): Make sure + both sides of both pipes associated with a tty master are + closed or suffer handle leaks. + +Tue Sep 29 16:55:00 1998 Geoffrey Noer + + * path.cc (mount_info::init): remove default mounts for + raw devices. + * utils/mount.cc (reset_mounts): ditto + (main, usage): new -f flag disables warning messages about + missing mount point directories. Two new flags, disabled for + now: -c will create missing mount point directory, -g will + select adding the mount point to the global registry location. + * include/sys/mount.h: add MOUNT_GLOBAL define, for future use. + +Tue Sep 29 14:20:30 1998 Christopher Faylor + + * exceptions.cc (exception): Use %p to denote some hex + values. + * winsup.h (read_info): Add jmp_buf to structure. Required + for syscalls.cc change below. + +Mon Sep 28 19:36:41 1998 Syd Polk + + * include/{tchar.h, direct.h}: Added so that + tcl8.1a2 can be compiled with cygwin. + +Mon Sep 28 19:36:41 1998 Christopher Faylor + + * syscalls.cc (thread_reset): Yet another method for + handling interruptible reads. + (_read): Use thread_reset to reset reads after a signal. + +Sun Sep 27 21:11:46 1998 Christopher Faylor + + * cygwin.din: New alias for __cygwin32_stack_trace. + * debug.cc (find_handle): Avoid leaving function without + unlocking. + (newh): Ditto. + * exceptions.cc (__cygwin32_stack_trace): Rename to just + `stack'. Shortens stack trace output. + (exception): Use %p to distinguish register values. + * fhandler_console.cc (fhandler_console::init): Remove + debugging sig_protect. + * init.cc (dll_entry): Move definition to avoid a + compiler warning. + * path.cc (mount_info::conv_to_win32_path): Detect + case of root directory when setting win32 relative + path. + (mount): Remove obsolete label. + * syscalls.cc (thread_sync): New function for exiting + the read helper thread. + (_read): Use new method for exiting the read helper + thread. + +Sun Sep 27 11:25:06 1998 Christopher Faylor + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * delqueue.cc (delqueue_list::process_queue): Clear queue + entry if file cannot be deleted for a reason other than + sharing violation. + +Fri Sep 25 08:52:50 1998 Christopher Faylor + + * debug.cc: locker variables should all be static. + * syscalls.cc (_read): Call ForceCloseHandle on + thread handle since it is protected. + +Thu Sep 24 18:59:25 1998 Geoffrey Noer + + * path.cc (mount): don't verify that path is an existing + directory. Instead + * utils/mount.cc: verify that path is an existing directory + and print warning if it's not. Still do the mount. + +Thu Sep 24 11:45:04 1998 Christopher Faylor + + * debug.cc: locker class variables must be NO_COPY since + they contain data that should not be precisely duplicated + after a fork. This hopefully fixes a "SIGSEGV" problem. + * select.cc (peek_pipe): Pipes apparently should set both + "read" and "exception" flags on EOF. + +Wed Sep 23 18:26:31 1998 DJ Delorie + + * doc/doctool.c (main): typo checking for --help + +Wed Sep 23 17:46:06 1998 Christopher Faylor + + * path.cc (symlink_check_one): Try much harder to ensure that + CloseHandle is called on the file which was opened to check + for a symlink. Avoid obsolete check for NULL buf. + +Wed Sep 23 17:11:50 1998 Christopher Faylor + + * syscalls.cc (_read): Close thread handle or suffer a leak. + * dir.cc (opendir): Simplify logic. + (readdir): Ditto. Close handle explicitly when hit end + of files. + (rewinddir): Close directory handle or suffer leak. + (closedir): Simplify logic. + +Wed Sep 23 14:42:12 1998 Christopher Faylor + + patch from DJ Delorie : + * path.cc (symlink_check_one): Don't re-define res or symlinks + will be undetectable. + +Wed Sep 23 12:02:39 1998 Christopher Faylor + + * Change calls to api_fatal throughout to avoid need for \n + (see below). + Adapt some *_printf()/ExitProcess combinations to use api_fatal. + * winsup.h (SIGTOMASK): Generate signal mask correctly for + programs linked with newer cygwins. + * dcrt0.cc (check_sanity_and_check): Set subtract constant for + signal mask calculation based on whether binary was linked with + "older" or "newer" cygwin. + (do_global_ctors): Accept a second argument indicating whether + the ctors should always be run. Necessary in forked processes + for cygwin constructors which may do more than just allocate memory. + (checkout): Remove obsolete function. + (dll_crt0_1): Remove obsolete function call. Call do_global_ctors + with second argument TRUE. + (api_fatal): Change to a print-style function, allowing arguments. + Always emit a "\n" after a message. + (__main): Do not force running of constructors in forked processes. + * exceptions.cc (call_handler): Simplify arguments passed to this + function. Eliminate potential race by setting signal masks here. + (sig_handle): Just calculate current sigaction pointer once. + Change call_handler arguments. + * fhandler_console.cc (fhandler_console::write_normal): Output + unknown characters to screen. + (fhandler_console::write): Make signal protection synchronous. + * fork.cc (fork): Reorganize slightly to eliminate a compiler warning. + * init.cc (dll_entry): Temporarily remove freeing of waitq_storage + on thread detach until a more robust scheme is developed. + * signal.cc (signal): Make signal protection synchronous. + (sigaction): Ditto. + * sigproc.cc (get_sig_dispatch_mutex): More debug info. + (release_sig_dispatch_mutex): Work around potential bug in windows + with double allocation of a mutex when WaitForSingleObject is + interrupted. Save errno here only if about to call sig_send + where it may be changed. + (wait_sig): Remove unnecessary sig_sign stuff. Add some debugging + output. + * termios.cc (tcflow): Signal protection. + (tcgetattr): Ditto. + (tcsetattr): Make signal protection synchronous. + * winsup.h: Add new extern for SIGTOMASK macro. Use it in SIGTOMASK + macro. Move errno stuff to end so that it can benefit from previous + declarations. + * configure.in: Move AC_CANONICAL_SYSTEM up a little to avoid having + configure generate some code (like the check for host type) twice. + * configure: Regenerate. + +Wed Sep 23 11:49:55 1998 Christopher Faylor + + * path.cc (symlink_check_one): Fix handle leak resulting + from open of file to check for symlink magic. Suggested + by Corinna Vinschen . + +Wed Sep 23 08:33:26 1998 Christopher Faylor + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * fhandler_tty.cc (process_ioctl): Use console handle + for ioctl operations. + +Tue Sep 22 23:58:20 1998 Geoffrey Noer + + based on patch from sos@prospect.com.ru (Sergey Okhapkin): + * utils/ps.cc (main): rewrite ps to give it more options, + including a, e, f, l, and u. + +Tue Sep 22 15:18:41 1998 Geoffrey Noer + + * path.cc (umount): remove initial system_printf + (mount): stat path, verify that it's an existing directory, + otherwise fail. + (strncasematch, strcasematch): return 0 instead of FALSE + * utils/mount.cc (reset_mounts): reset / to System drive, + not C: as was done in the old days. + +Mon Sep 21 18:18:18 1998 Geoffrey Noer + + * path.cc (mount, umount, setmntent, getmntent, endmntent): + make extern "C" + +Mon Sep 21 20:37:16 1998 DJ Delorie + + * doc/configure.in: don't try to find cc until we can correctly + configure it for a native cc in a cross build. + +Mon Sep 21 17:17:14 1998 Geoffrey Noer + + * fhandler.cc (fhandler_disk_file::check_execable_p): + don't check for .shc since that's non-standard. Check for + .exe first. + +Mon Sep 21 14:57:50 1998 Geoffrey Noer + + * doc/Makefile.in: reference -db2html in case docbook + tools aren't installed. + +Mon Sep 21 14:43:40 1998 Geoffrey Noer + + patch from DJ Delorie : + * doc/doctool.c (scan_file): correct off by one error in + malloc + +Mon Sep 21 14:28:38 1998 Christopher Faylor + + * fhandler.h (select_record): Clear memory in constructor. + +Mon Sep 21 08:49:22 1998 Christopher Faylor + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * select.h: Use unsigned int to hold count in fd_set + structure or suffer alignment problems. + (WINSOCK_FD_ZERO): Back out previous change as it + is no longer needed due to the above. + +Sat Sep 19 22:58:18 1998 Christopher Faylor + + * fhandler_console.cc (console_read): Keep looping in + ENABLE_LINE_INPUT mode when no characters are read. + This apparently means that a CTRL-C has been hit. + * select.cc (select_record::operator new): Remove. + (setlect_stuff::~select_stuff): Use delete to remove + record. + (pipe_cleanup): Remove unneeded statement. + (poll_socket): Add debugging statement. + (start_thread_socket): Add debugging statements. + * fhandler.h: Remove new operator from select_record. + * select.h: Make WINSOCK_FD_ZERO more aggressive. + * sigproc.cc (allow_sig_dispatch): Use new errno + saving method. + * syscalls.cc (_read): Reorganize stack freeing + code to avoid overhead when it's not needed and + to actually decommit stack memory. + +Sat Sep 19 19:16:32 1998 Christopher Faylor + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * select.cc (socket_cleanup): Avoid using a pointer + after it has been deleted. + +Fri Sep 18 13:57:37 1998 Christopher Faylor + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * Makefile.in: Really remove extra slash in INCLUDES. + Previous change didn't work. + pipe.cc (make_pipe): set close-on-exec flag for non-inheritable + pipes. + +Thu Sep 17 15:26:14 1998 Christopher Faylor + + * doc/Makefile.in: Add dummy install target. + +Thu Sep 17 12:30:49 1998 Christopher Faylor + + * winsup.h (per_thread*): New classes for storing and + manipulating per_thread information. + (threadstuff): New array of per_thread objects which are + manipulated after a fork. + (read_helper_thread_info): read() thread local storage. + (waitq_storage): wait() thread local storage. + * debug.cc (class locker): New class for generic locking + of debug table manipulation. Use this throughout for + locking access to thread/debug tables. + (debug_init): Remove in favor of automatic constructor. + * debug.h: Ditto. + * fork.cc (fork): Iterate through threadstuff looking + for thread information to clear out. Should solve some + problems for Windows 95/98. + * init.cc (dll_entry): Remove thread storage initialization. + Use per_thread class for DLL_THREAD_DETEACH. + * sigproc.cc: Use system_printf rather than alert_printf + throughout since system_printf now has the same functionality. + (sigproc_init): Use method to initialize per-thread storage. + * sigproc.h: Remove waitq_storage declaration. + * syscalls.cc (_read): Use per_thread class to manipulate + per-thread information. + * wait.cc (wait4): Ditto. + +Wed Sep 16 12:58:49 1998 Christopher Faylor + + * syscalls.c (_read): Lower timeout for signal detection after + EOF on device. Should fix recent configure performance problems. + * Makefile.in: Extend clean target into regexp directory. + +Wed Sep 16 11:44:14 1998 Christopher Faylor + + * fhandler.cc (fhandler_base::set_name): Honor no_free_names(). + (fhandler_base::linearize): Remove unneeded check for NULL + get_win32_name(). + (fhandler_disk_file::fhandler_disk_file): Set path names + to a standard constant. They should eventually be filled + out by fhandler_disk_file::open. + (fhandler_disk_file::open): Detect if win32_path_name_ is + a dummy path. Fill it out from real_path, if so. + * hinfo.cc (hinfo::init_std_file_from_handle): Improve debugging + statement. + (hinfo::linearize_fd_array): Remove unneeded check for NULL + get*_name (). + * path.cc (path_conv::path_conv): Correct problem with + symlinks found at places like E:\. + +Wed Sep 16 02:25:33 1998 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * fhandler.cc (fhandler_disk_file::open): fix typo. + +Tue Sep 15 23:52:44 1998 Christopher Faylor + + * winsup.h: Remove side effects from SLASH_P. + +Tue Sep 15 18:36:08 1998 Ben Elliston + + * sysdef/kernel32.def: Add definition for the Win32 API function + `TryEnterCriticalSection'. + +Tue Sep 15 12:26:48 1998 Christopher Faylor + + * Makefile.in: Remove extra slash in INCLUDES. + * hinfo.cc (hinfo::dup2): Always clear close-on-exec + flag for duplicated handle (problem and fix determined + by Sergey Okhapkin, sos@prospect.com.ru). + * fhandler.cc (fhandler_base::set_name): Avoid use of empty + path names. + (fhandler_base::raw_read): Show error code on failure. + (fhandler_base::linearize): Avoid copying NULL names. + (fhandler_base::open): Use NULL detection in small_printf. + (fhandler_base::dup): Move set_close_on_exec_flag to dup2 + so it is caught in all cases. + (fhandler_disk_file::fhandler_disk_file): Set "no free names" + flag. + (fhandler_disk_file::open): Clear "no free names" flag since + names have been allocated to the fhandler structure at this point. + * fhandler.h (set_no_free_names): Newconditional "no free names" + function. + * hinfo.cc (hinfo::dup2): Clear close on exec here. + (hinfo::linearize_fd_array): Avoid copying NULL names. + * path.cc (normalize_posix_path): Avoid copying trailing slash + if root. + (nofinalslash): Rename variable. + * path.h: Add flag for future use. + * regexp/regerror.c: Avoid including RCS strings in product. + * regexp/regsub.c: Ditto. + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * select.cc (thread_pipe): Sleep for 10ms on every iteration. + (start_thread_pipe): Set the handle in the select structure + so that it will be properly identified in select_stuff::wait. + +Tue Sep 15 12:28:30 1998 DJ Delorie + + * added documentation and doctool.c + +Tue Sep 15 08:37:26 1998 Christopher Faylor + + * Makefile.in: Fix LIBGCC definition for native builds. + Remove CFCOMMON in favor of configure solution. + * configure.in: Default CXXFLAGS to be == CFLAGS. + * configure: regenerate. + +Sun Sep 13 19:52:04 1998 Geoffrey Noer + + * Makefile.in: include ../libio when building + +Sun Sep 13 19:30:58 1998 Geoffrey Noer + + * include/cygwin32/version.h: bump version minor now that + we've merged in all that new code... + +Sun Sep 13 21:34:33 1998 Christopher Faylor + + * dcrt0.cc (do_global_ctors): Reverse call order + of constructors thanks to insight from Mumit Khan + (hkan@xraylith.wisc.edu). + (do_global_dtors): Reflect above change: invoke destructors + in the proper order. + * smallprint.c (__small_vsprintf): Gracefully detect a + null pointer for '%s' format. + * syscalls.cc (_read): Set correct flags to retrieve stack + information or suffer sporadic failures due to uninitialized + flag. + * regexp/regexp.c: Comment out RCS string. This provides + no useful information in the .dll. + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + Merge in experimental-980602 branch changes. + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + * path.cc (symlink_check_one): known_suffix needs to be + determined here in some cases, so deal with it here. + (path_conv::path_conv): More effort needed to propagate + the known_suffix back to caller in every case. + (has_suffix): Return suffix found. + (readlink): Avoid two passes through symlink_check_one. + * spawn.cc (find_exec): Propagate known_suffix from + perhaps_suffix back to caller, if appropriate. + (spawn_guts): Use suffix returned from find_exec to + determine if file should be scanned as a script when + a #! file is found. Avoids a duplicate call to + perhaps_suffix. + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + * path.h (suffix_info): New struct for dealing with standard + suffix (.exe, .bat, etc.) information. + (path_conv): Constructor now takes a suffix_info argument. + (std_suffixes) Standard array of suffixes to consider "special". + * path.cc (path_conv): Constructor now takes a suffix_info + argument. Record any known suffix in path_conv known_suffix + field. + (has_suffix): New function for determining if a path already + has a known suffix. + (next_suffix): New function for returning the next suffix from + a list of suffixes. + (symlink_check_one): Take an optional suffix_info argument + for suffixes to consider or tack on. + * spawn.cc (std_suffixes): Standard list of executable suffixes. + (perhaps_suffix): Pass std_suffixes to path_conv. Use + new known_suffix field in path_conv to determine if a + suffix has been detected. + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + Substitute new str{,n}casematch for strcasecmp throughout. + This implementation is faster since it only tests equality. + + Change fhandler*::open throughout to return true/false + since the pointer returned was never used for anything. + + * Use strcasestr throughout for case insensitive matches for + filenames. + * Makefile.in: Use GNU make construct for determining gcc lib. + * dcrt0.cc (check_sanity_and_sync): Make error message more + explicit. + * debug.h: Better defines for dummy functions when !DEBUGGING. + * fhandler.cc (fhandler_base::fstat): Don't bother zeroing buf + here since it is always done in the caller. + (fhandler_base::~fhandler_base): Recognize cases where *_path_name_ + should not be freed. + (fhandler_disk_file::open): Split into two functions. First + function performs a path_conv and does testing on same. This + calls new fhandler_disk_file::open with path_conv data. New + function is called by stat_worker to avoid extra path tests and + mallocs. + Also, fix long standing off-by-one typo looking for #! magic. + Also, reapply test for != WinNT when checking files for magic. + Otherwise there is a tremendous slowdown in file opening, especially + for stat(). + * fhandler.h: Add support for setting/detecting when *_path_name + should not be freed. + Add new fhandler_disk_file::open declaration. + * hinfo.cc (digits): Remove obsolete function. + (hinfo::build_fhandler): Add default name for FH_DISK. + * path.cc (path_prefix_p_): Don't check beyond len1 for leading + slash. Responsible for reported performance problems? + (path_conv::path_conv): Ensure that fileattr is filled out + correctly in all cases. Return immediately when a file + is detected in !follow_mode. + (nofinalslash): Simplify. + (strncasematch): New function similar to strncasecmp except + that it only checks for =/!= and benchmarks faster than same. + (strcasematch): Ditto, re. strcasecmp. + (strcasestr): New function which does a case-insensitive strstr. + Needed for filename matching. + * smallprint.c (__small_vsprintf): Fix off-by-one in %.ns processing. + * spawn.cc (exe_exts): Make global for eventual use by other modules. + * syscalls.cc (_fstat): Zero buf prior to use. + (stat_worker): Rename from _stat_worker. Reorganize to minimize + mallocs and path name conversions. Should now perform only one + path conversion and 0 malloc/frees. + * winsup.h: Declare new functions. + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + Clean up error messages throughout using new strace_printf + options. + * smallprint.c (__small_vsprintf): Add %E option for printing + error code. Understand %.n syntax. + * strace.cc (strace_vsprintf): Common routine for formatting + strace output. Default to always ending with \n unless + string ends with \b. + (strace_write): Common routine for writing to strace output. + (strace_printf): Use above two routines. + (system_printf): Ditto. + * path.cc (path_conv): Scan path to be converted from right + to left for efficiency. Implement extension searching + which is passed from spawn to symlink_check_one to minimize + overhead. + (symlink_check_one): Check extensions for existence for use + with spawn. + (readlink): Accomodate changes to symlink_check_one. + * spawn.cc (perhaps_suffix): Use new extension checking + capabilities of path_conv. + (find_exec_1): Delete. + (find_exec): Generalize to allow searching on any PATH like + environment variable. + * dllfcn.cc (check_path_access): Use find_exec to find a path. + This also ensures that paths are in Windows format which was + not the case before. + * environ.cc (conv_envvars): Add LD_LIBRARY_PATH. + * fork.cc (fork): Clean up dll loading slightly. + * Makefile.in: Turn on compiler warnings. + * winsup.h (save_errno): New class for saving errno from + being clobbered. + * include/sys/strace.h: Make system_printf a macro similar + to strace_printf_wrapper. + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + * sigproc.cc (sig_send): Attempt to work around Windows strangeness + when thread interrupted while waiting for completion event. + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + * dcrt0.cc: Remove debugging function DELETEME (). + * fhandler.cc (fhandler_base::fstat): Respond to compiler warning. + * signal.cc (sleep): Reset signal_arrived event before using it or + we could wake up immediately. + (usleep): Ditto. + (pause): Ditto. + * spawn.cc (spawn_guts): Ditto. Respond to compiler warning. + * sigproc.cc (sig_send): More debugging info. + (sig_dispatch_mutex): Only ping wait_sig when needed. + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + * select.cc (socket_cleanup): Close thread handle or suffer + handle leak. + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + * select.cc (verify_true): New function. + (fhandler_socket::select_*): Use verify_true for verification + function to avoid multiple calls to socket select. + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + * select.cc (select_stuff::wait): Scan entire list of fds + when WFMO wakes up. + (set_bits): Add some strace debugging output. + (thread_socket): Ditto. + (verify_ok): Return result of set_bits rather than always 1. + (start_thread_socket): Set the handle in the select structure + so that it will be properly identified in select_stuff::wait. + (fhandler_windows::select_read): Verification routine should + be `poll_windows'. + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + * sigproc.cc: Change some sigproc_printfs to only occur when + #ifdef DEBUGGING. + * spawn.cc (perhaps_suffix): Search for (PROG is the pathname to + the executable file) PROG.exe, PROG.com, PROG.bat, PROG.cmd, and + PROG and return extension found or NULL if no matching file. + (spawn_guts): If the file name of the executable ends in either + .exe, .com, .bat, or .cmd we assume that it is not a script file + and therefore do not open the file to determine if it is. + Fix "wait_failed" error when exec() called and non-cygwin parent. + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + * dir.cc (rmdir): Set correct errno when non-empty directory and + Windows9x. + * pipe.cc (pipe): Use binary mode by default for pipes. + * syscalls.cc (_read): Wait for terminated thread to exit before + clearing its stack memory. + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + * hinfo.cc (hinfo::fixup_after_fork): Start initial fd search + to zero forked processes so that a close(0)/dup(fd) will work. + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + * fhandler_windows::set_close_on_exec: Deal with possible + NULL handle. + (fhandler_windows::fixup_after_fork): Ditto. + * select.cc (select_stuff:wait): Handle return from + MsgWaitForMultipleObjects correctly for windows case. + * sigproc.cc (sig_send): Reset completion event for main thread. + * syscalls.cc (_read): Better handling of stack free condition. + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + * exceptions.cc (call_handler): Exit earlier if just running + in an exec'ed stub since the stub may own the sig_dispatch mutex, + but we still want to exit. + * select.cc (select_stuff::wait): Fix check for window activity + from MsgWaitForMultipleObjects. Handle infinite wait correctly. + (poll_windows): Add debugging output. + * spawn.cc (spawn_guts): Protect against signals interrupting + at an inopportune moment. + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + * select.cc (select_stuff:test_and_set): Take appropriate action + when a select record uses a window_handle. + (fhandler_windows::select_read): Set handle and windows_handle + appropriately. + (fhandler_windows::select_write): Ditto. + (fhandler_windows::select_except): Ditto. + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + * select.cc (cygwin32_select): Need to reset signal_arrived before + testing it or suffer loop. + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + * fork.cc (resume_child): Give up on SuspendThread synchronization + and use subproc_ready/forker_finished events. + (sync_with_parent): Ditto. + * sigproc.cc (wait_sig): Make sigcomplete_main manual reset to + allow handling of nested interrupts. + (wait_sig): Fix stupid typo on exit that would cause a + loop to run for a long time. Are exits faster now? + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + * exceptions.cc (unlock_cs): Leave decision to release + sig_dispatch_mutex to the caller. + (set_process_mask): Call release_sig_dispatch_mutex explicitly + if needed. + (handle_sigsuspend): unlock_cs no longer takes an argument. + (call_handler): Try to acquire the strace mutex prior to + suspending the main thread to ensure that the mutex is always + released. + (sig_handle): Call release_sig_dispatch_mutex explicitly. + * fhandler_console.cc (fhandler_console::write): Protect against + signals while writing. + * signal.cc (signal): Protect against signal dispatch. + (sigaction): Ditto. + * sigproc.cc (sig_dispatch_pending): Return status no longer needed. + (sig_send): Assume pending_signals if sending signal to self. + (allow_sig_dispatch): Accept synchronize argument to control whether + to wait for wait_sig to do its thing. + (release_sig_dispatch_mutex): Just awaken wait_sig loop and wait + for acknowledgement if waitfor is TRUE. + (wait_sig): Don't ever zero pending_signals to avoid a possible race. + Set pending_signals for blocked signals, too. + * sigproc.h: Add __SIGFLUSH signal. + (class sig_protect): Allow destructor to wait for signal dispatch, + or not given constructor argument. + * strace.cc (get_strace_mutex): Renamed from waitfor_strace_mutex. + (release_strace_mutex): External function for use by call_handler. + This replaces raw calls to ReleaseMutex throughout. + * syscalls.cc (_read): Use sig_protect to protect against signals. + Other cosmetic cleanups. + (_close): Protect function with sig_protect. + * termios.cc (tcsetattr): Protect function with sig_protect. + +Thu Sep 10 21:09:51 1998 DJ Delorie + + * syscalls.cc (_read): typo in matching printf format to args. + + * fhandler.cc (write): Switch to the Microsoft/DJGPP way of + writing out text files: pass \r but prepend \r to \n. + (read): Don't collapse multiple \r's. + + * delqueue.cc: rewritten for speed. Don't check *every* entry in + the list if we know the list is empty, plus check for duplicates. + * delqueue.h: ditto. + * path.cc (path_conv): If a path component is missing, short- + circuit the symlink check. + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + * fhandler.h: Reorder fhandler status field so that device is + in lower bits. This allows gcc to optimize access to the device. + * hinfo.cc: Inline not_open(). + * winsup.h: Inline hinfo::not_open(). Make hinfo::[] operator a + simple array reference. + * strace.cc: Change strace() to a macro. + * include/sys/strace.h: Ditto. + * syscalls.cc (read_handler): New function. Called directly from + _read for "non-slow" devices or via read_handler for slow devices. + (_read): Use read_handler for reading. + (read_helper): Ditto. + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + * dcrt0.cc (do_exit): Don't ignore signals if reparenting. + Besides being a race, this screws up the process which is + actually executing. + * fork.cc (fork): Don't create a new process group when + forking or subprocesses won't respond to CTRL-C. + * syscalls.cc (_read): Ensure correct setting of EINTR errno. + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + * fork.cc (sync_with_child): Consider it a success if the child + has set the subproc_ready signal regardless of whether it has + exited or not. + * init.cc (dll_entry): Set read_helper_thread_info stuff to 0 + on dll initialization. Windows 95 seems to keep garbage here, + despite documentation to the contrary. + * syscalls.cc (_read): Report on errors to create read_helper + events. + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + * dcrt0.cc (compute_argc): Limit debug_printf string argument size + or suffer a buffer overrun. + (do_exit): Add debugging statement. + * exceptions.cc (call_handler): Remove extraneous sigproc_printf. + Consolidate signal_arrived event with sig_was_dispatched. + (events_terminate): Consolidate signal_arrived event with + sig_was_dispatched. + * fhandler.h: Rename a field to something more mnemonic. + * fhandler_tty.cc: Throughout: Only set up fhandler_tty_master when + actually using ttys. Change tty_master `f' field to `console'. + * tty.cc: Ditto. + * fork.cc (sync_with_child): Add more information to "child died" + error. + * hinfo.cc (hinfo::build_fhandler): Call tty master constructor + when appropriate. + * select.cc (select_stuff::wait): Consolidate signal_arrived event + with sig_was_dispatched. + * sigproc.h: Ditto. + * syscalls.cc (_read): Ditto. + * winsup.h: Ditto. + * sigproc.cc: Ditto, throughout. + (block_sig_dispatch): Don't reset signal_arrived. Causes races. + * spawn.cc (spawn_guts): Limit debug_printf string argument size + or suffer a buffer overrun. + * include/sys/strace.h: Implement strace_minimal for very minimal + output which, hopefully, will not affect the behavior of traced + programs as much. + +Thu Sep 10 21:09:51 1998 Geoffrey Noer + + * Makefile.in: build libwinspool.a with the dll name winspool.drv + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + * dcrt0.cc (build_argv): Remove verbose debug_printf. + (dll_crt0_1): Use shared data handle passed in from parent process + when appropriate. Remove extraneous debug_printf. + * environ.cc (getwinenv): New function. Returns (possibly cached) + native version of an environment variable. + (win_env::add_cache): Add cached version of posix and win env + variables to local table. + (posify): Modify for use with native caching. + (setenv): Convert special environment variables to native here, + when they are set. + (struct parse_thing): Simplify struct. + (struct parse_things): Extend table to accomodate "envcache" + setting. + (parse_options): Add "envcache" option to control whether special + environment variables are cached. Simplify handling of remembered + parameters. + (winenv): Modify for use with getwinenv. + * exceptions.cc (unlock_cs): release_sig_dispatch takes an argument + now. + (set_process_mask): unlock_cs now wakens wait_sig when appropriate. + (handle_sigsuspend): Reorganize to take advantage of new behavior + of release_sig_dispatch_mutex and hopefully avoid a race. + (handle_sig): Avoid waking wait_sig if we couldn't get the dispatch + mutex. + * exec.cc (strccpy): Change to modify second argument to point + to position where "parse" stopped so that it doesn't have to be + recalculated by the caller. + (sexecvpe): Use find_exec () to find program to run. If you've + got a function for this, you might as well use it. + * fhandler_tty.cc (fhandler_pty_master::process_input_to_slave): + Report on signal being sent in termios_printf. Use kill_pgrp + interface. + * fork.cc (fork_copy): Just copy everything at once rather than + in individual pieces. + (fork): Potentially move up sbrk() when DEBUGGING so that parent + and child heaps are in sync. Pass cygwin_shared_h to child. + * path.cc (path_conv::path_conv): Make sure that a file is not + a symlink when returning immediately. + * sigproc.cc (sig_dispatch_pending): Return TRUE if signals were + pending. + (sigproc_init): Move sig_was_dispatched initialization here so + that it will always be available to other functions which rely + on it. Otherwise these functions would have to wait for wait_sig + to complete its initialization. + (sig_send): Rework SIGSUSPEND handling. + (release_sig_dispatch_mutex): Wait for signal to be dispatched + after releasing mutex if argument is TRUE. + (wait_sig): Remove sig_was_dispatched initialization from here. + * sigproc.h: release_sig_dispatch takes an argument. + * spawn.cc (perhaps_suffix): Take an optional argument indicating + whether the path has already been converted to win32. + (find_exec_1): Use getwinenv to get windows version of PATH. Use + windows version of individual directories to avoid posix lookups. + (spawn_guts): Call strace_dump here to cause strace output to + be slightly more synced when using strace caching. + (spawnvpe): Use find_exec () to find program to run. If you've + got a function for this, you might as well use it. + * syscalls.cc (_read): Only block signals for "slow" devices. + * winsup.h: Changes needed for previous checkin and getwinenv. + +Thu Sep 10 21:09:51 1998 DJ Delorie + + * path.cc (path_conv): bug fix when path ends in slash + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + * fhandler.cc (fhandler_base::set_name): Use fhandler + method for determining native name. Avoid path_conv + when possible. + (fhandler_disk_file::get_native): New function, returns + windows name of disk file. + * fhandler.h: Add get_native() method to fhandler_* + classes. + * fhandler_serial.cc (fhandler_serial::get_native): Return + windows name of serial port. + * fhandler_tty.cc (fhandler_tty_master::init): Use consistent + name for tty master. + * fork.cc (fork_copy): Experimental change to avoid loop. + * grp.cc (add_grp_line): Use realloc to extend group buffer. + * hinfo.cc (hinfo::release): fd object should be deleted, + not freed or suffer a memory leak. + (init_std_file_from_handle): Reset first_fd_for_open to + signal that std* locations have been opened. Avoids use + of these locations prior to full dtable setup. + * passwd.cc (add_pwd_line): Use realloc to extend passwd buffer. + * path.cc (path_conv::path_conv): Avoid checking for symlinks on + network shares. Check for existence of file prior to taking + it apart for symlink checking (this needs more work). + (windows_device_names): Make global. + (get_device_number): Detect tty master. + * sigproc.cc (wait_sig): Maintain a flag which indicates when + signals are queued due to the wait_sig's inability to get a + sig_dispatch mutex. + (sig_dispatch_pending): Don't wake up the wait_sig thread if + unless there are signals queued (see above) or force argument. + (allow_sig_dispatch): Only wait for signal dispatch if something + is queued. + * sigproc.h: allow_sig_dispatch takes a (defaulted) argument now. + * syscalls.cc (_open): Use default hinfo::find_unused_handle call. + * net.cc: Ditto, throughout. + * pipe.cc: Ditto. + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + * dcrt0.cc (do_exit): Ignore user initiated signals here. + * fhandler.cc (fhandler_disk_file::open): Detect error condition + on fhandler_base::open. + * fhandler_console.cc (undo_input): Respond to compiler warnings. + * grp.cc (getgrgid): Ditto. + * times.cc (_tzname): Ditto. + * fhandler_tty.cc (fhandler_Tty_slave::open): Cosmetic changes. + * fork.cc: Clean up debugging output. + * pinfo.cc (pinfo_init): Set pgid and sid to different values + initially. Let user program set sid appropriately if it is + to be the owner of a tty. + * sigproc.cc (allow_sig_dispatch): Try harder to detect when we + should wait for a signal dispatch. + * strace.cc (strace_open): Revert to previous mutex behavior. + * include/sys/strace.h: Ditto. + * syscalls.cc (_open): Detect error from fhandler open. + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + Global changes: + Store win32 name in fhandler structure to avoid multiple translations. + Support close_on_exec at the Win32 level for all but sockets. + Respond to gcc warnings. + Use single fstat() call for devices. + *::set_close_on_exec modified. + * dir.cc (opendir): Use win32 name in stat to speed things + up a little. + * debug.cc: New file. Provides routines for extra debugging + when -DDEBUGGING is specified. + * debug.h: New file. Definitions for debug.cc. + * exceptions.cc (signals_init): Break out signal initialization + from exceptions. + (dump_status): Add thread name to stack dump output. + (handle_exceptions): Renamed. + (set_process_mask): Don't ever mask non-maskable signals. + (ctrl_c_handler): Preliminary change to allow propagation of + cygwin signals back to gdb. + (sig_handle): Call do_exit directly from signal thread rather than + attempting to redirect the main thread. + * fhandler.cc (set_name): Store win32 name in fhandler structure. + (*::open) name field is extraneous now. Use get_win32_name () to + retrieve stored win32 name. + (fhandler_base::fstat): Default to performing fstat on a device. + (fhandler_disk_file::fstat): Renamed from fhandler_base::fstat. + Operate only on disk files. + (fhandler_base::set_close_on_exec_flag): New function sets flag + without touching the handle. + (fhandler_base::~fhandler_base): Free unix/win32 path names. + (fhandler_disk_file::close): Only call delqueue.process_queue from + this function since disk files are the only things that can + be unlinked, currently. + (fhandler_dev_null::open): Delete. + (set_inheritence): New function. Set handle inheritence. + (fhandler_*::fork_fixup): New functions. Inherit fhandler data + after a fork. + fhandler.h: *::set_output_handle - new method. + Setup methods for use by select(). + fork.cc (fork): Call fixup_after_fork in child to inherit + handles marked as non-inheritable on CreateProcess. + hinfo.cc (hinfo::build_fhandler): Use new function to detect + devices. + (dup_for_exec): Delete obsolete function. + (hinfo::dup2): Remove extraneous tests. + (hinfo::select_*): Interfaces into select(). + (hinfo::release): Free fd in dtable. + (hinfo::fixup_after_fork): New function. Inherit close-on-exec + handles from parent after fork. + path.cc (mount_info::posix_path_p): Make inline. + (path_conv::path_conv): Short circuit when path resolves to a device. + (digits): Move here from hinfo.cc. + (windows_device_names): Win32 names for Cygwin devices. + (get_device_number): New function. Return devie number given device + name. + (win32_device_name): New function. Decode a windows device name + and an optional "unit". + (mount_info::conv_to_win32_path): Short circuit when path resolves to + a device. + * path.h: add device and unit fields to path_conv class. + * select.cc: Rewrite for more structure, more OO. + * sigproc.cc: (get_sig_dispatch_mutex): New function. + (release_sig_dispatch_mutex): New function. + * sigproc.h: sig_protect class. Automatic protection from signals + when used. + * syscalls.cc (stat_dev): New function. + (stat_worker): Short-circuit when a cygwin device is detected. + * utils/ps.cc: Don't lock_pinfo when -f. Compress format to fit + more on a line. + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + * dcrt0.cc (dll_crt0_1): Register name for main thread. + * exceptions.cc (dump_status): Add thread name to diagnostic output. + (__cygwin32_exception_handler): Rename to handle_exceptions. Avoid + creating a .core file. + * exec.cc (sexecve): Reflect spawn_guts argument change. + * fhandler_tty.cc (fhandler_tty_master::init): Use makethread to + create a new thread. + * select.cc: Create pipe/socket threads each time select is called. + Use thread termination as indication of fd readiness. + * sigproc.cc (sigproc_init): Use makethread to create a new thread. + (wait_sig): Simplify default signal call slightly. + * spawn.cc (spawn_guts): Accept child pinfo pointer rather than + pid. Reorganize so that common initialization is handled once. + * strace.cc: Set strace_mutex to NULL initially to catch CreateMutex + errors. + * window.cc (gethwnd): Use makethread to create a new thread. + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + * Makefile.in: Add debug.o target. + * cygwin.din: Separate pipe from _pipe. + * dcrt0.cc (alloc_stack): New, more precise method for allocating + stack space after a fork. + (dll_crt0_1): Use new child_proc_info class to retrieve information + from possible parent process. Remove #ifdef erroneously checked in. + Remove extraneous syscall_printf. + * exceptions.cc (signals_init): New function. + * fhandler.cc (fhandler_make_pipe): Move to pipe.cc. + * fhandler.h (fhandler_base): New = operator preserves unix_path_name_. + * fhandler_tty.cc: Strip some tty functions from here into tty.cc. + * fork.cc: Remove obsolete ifdefs. Reorganize, streamline with new + fork. + * hinfo.cc: Speed up build_fhandler. + * libccrt0.cc: Remove obsolete ifdefs. + * pinfo.cc (pinfo_init): Simplified by new fork/spawn info passing + method. + * pipe.cc (make_pipe): Moved from fhandler.cc. Handles MS-style + _pipe. + (pipe): Use new arguments to make_pipe. + (_pipe): New MS-compatible function. + * shared.cc: cygwin_shared_h make global so that it can be inherited + via new fork/spawn info passing method. + (open_shared_file_map): Detect if shared info is already set up from + fork/spawn. + * sigproc.cc (sigproc_init): Initialize signals with signals_init here. + Use new fork/spawn info passing method. + * spawn.cc (spawn_guts): Pass information in a structure to spawned + process. Identify structure type with a "magic number". + * strace.cc (strace_printf): Only print program full path spec once + to save space and clutter. Preserve any windows error. + * syscalls.cc (_open): Detect and avoid error return from + build_fhandler. + * tty.cc: Accept some non-fhandler functions formerly found in + fhandler_tty.cc + * winsup.h (pinfo): Remove some fields obsoleted by new fork/spawn + info passing method. + (child_info*): New classes for passing information to forked/spawned + process. + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + * Makefile.in: Add debug.o target. + * console.cc (fhandler_console::char_command): Fix failed merge. + * dcrt0.cc (alloc_stack): New, more precise method for allocating + stack space after a fork. + (dll_crt0_1): Use new child_proc_info class to retrieve information + from possible parent process. Remove #ifdef erroneously checked in. + Remove extraneous syscall_printf. + +Thu Sep 10 21:09:51 1998 Christopher Faylor + + Global changes: + Replace pinfo hmap entry with "dtable" reference. + Replace cygwin_shared .t field with '.tty' and allow indexing via + tty into this array. + Make fhandler_ constructors set the size of the structure into any + created class. + Change fhandler settings into a bit mask. Use methods to access. + Record device type in fhandler class. + Remove old linearize/de_linearize code in favor of newer method + uses more bullet-proof method for determing device type of inherited + files. + Protect various important handles from closing when operating + under -DDEBUGGING. + * dcrt0.cc (do_global_ctors): Renamed, made static and reused + for calling from dll_crt0_1 to initialize cygwin.dll constructors. + (do_global_dtors): Renamed. + (dll_crt0_1): mark noreturn. Use new do_global_ctors function. + Call debug_init to initialize features turned on by -DDEBUGGING. + Call dtable_init to initialize dtable, hinfo_init to initialize + standard fds. + (dll_crt0): Mark noreturn. Move constructor calls to dll_crt0_1. + (__main): Use new do_global_ctors (). + Remove OLDWAY and _PPC_ conditionals. + * environ.cc (environ_init): Use appropriate strace printf. + * exceptions.cc (set_process_mask): Don't ever mask out unmaskable + signals. + * init.cc (dll_entry): Initialize storage for read_helper. + * pinfo.cc (init_from_exec): Delete obsolete function. + * sigproc.cc (sig_send): Implement myself_nowait to allow + sending a signal to myself without waiting for synchronization. + (wait_sig): Change method for determining whether signal should + be examined slightly. + * strace.cc (strace_printf): Add ability to report on thread from + which message originated. + (threadname): New function + * syscalls.cc (read_helper): New function. Invoked in separate thread + from _read. + (_read): Use a separate thread for reads that can be interrupted + with a TerminateThread(). Allows EINTR. + (setdtablesize): Use new method for extending the size. Callable + from anywhere. + (getdtablesize): Use new method for getting the current dtable size. + * tty.cc: Remove use count in favor of a method which checks tty + availability via an event. Some code cleanup. + (tty::inuse): New function for determining if a tty is + in use by any process. + (tty_list::terminate): Use new method for determining if a tty is in + use. Should avoid hangs waiting for non-existent processes to + free up a tty. + (tty::common_init): Common initialization for tty/pty master. + (fhandler_tty_master::init): New function. + (do_output): Use new method for determining if a tty is in use. + (fhandler_pty_master::open): Use comon initialization code. + (fhandler_pty_master::ptsname): static buffer is ok now. + * tty.h: Reflect inuse changes and tty.cc cleanup. + * winsup.h: Include debug.h for use when -DDEBUGGING. Remove + stuff previously here which was conditionally compiled with -DDEBUGGING. + (hinfo_vec): Rename to hinfo. Maintain argv style list of pointers + to open fds. Add methods to deal with above changes. + (pinfo): Removals due to above changes. + (shared_info): Rename t to tty. + Add common defines to extern "C" section. + +Wed Sep 9 22:24:50 1998 Christopher Faylor + + * path.cc (path_prefix_p_): Rewrite to avoid false match + against root when remote path or \\x style disk device. + * include/sys/strace.h: Implement new macro for use by + malloc_printf which does not default to "on" if STRACE=1. + This avoids massive strace logs. + +Tue Sep 8 11:31:42 1998 Christopher Faylor + + * dcrt0.cc (dll_crt0_1): Remove ill-advised ifdef NEEDOEM. + +Thu Sep 3 17:54:18 1998 Christopher Faylor + + * Makefile.in: Speed up dll links. + * path.cc (chdir): Fix previous change. + +Mon Aug 31 12:23:33 1998 Christopher Faylor + + * path.cc (chdir): Protect free from potential signal race. + +Fri Aug 28 15:59:27 1998 Geoffrey Noer + + * dlfcn.h: delete, move it + * include/dlfcn.h: here + +Thu Aug 27 14:20:38 1998 Christopher Faylor + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * path.cc (path_conv::path_conv): remove trailing backslash from + full win32 name, otherwise the last component of the path isn't + checked for symlink. + +Wed Aug 26 14:15:22 1998 Christopher Faylor + + * fhandler.h (fhandler_base): Make set_name() public and implement + clear_name() to accomodate dup2. + * hinfo.cc (dup2): Previous change exposed problem with dup2. + Same unix_path_name_ ptr was being used in two separate fds. + Fix this. + +Wed Aug 26 12:10:27 1998 Christopher Faylor + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * malloc.cc: Use malloc_printf throughout. + * path.cc (getcwd_inner): Allocate buffer with realloc to + avoid a memory leak. + * syscalls.cc (_close): delete unix_path_name_ explicitly since + destructor is never called. + * include/sys/strace.h: Add strace_malloc stuff. + +Mon Aug 24 15:45:59 1998 Geoffrey Noer + + * include/sys/ioctl.h: variable names in protos should start + with two leading underscores. + * include/sys/mman.h: ditto. + * include/sys/mount.h: ditto. + * include/sys/resource.h: ditto. + * include/sys/smallprint.h: ditto. + * include/sys/socket.h: ditto. + * include/sys/strace.h: ditto. + * include/sys/vfs.h: ditto. + * include/sys/wait.h: ditto. + * include/mntent.h: ditto. + +Tue Aug 18 17:00:20 1998 Geoffrey Noer + + patch from Trevor Yann (TYann@vet.com.au): + * uname.cc (uname): report processor type for win98 + +Tue Aug 18 16:09:13 1998 Christopher Faylor + + * fork.cc (cygwin_fork_helper1): Start initial fd search + to zero forked processes so that a close(0)/dup(fd) will work. + +Mon Aug 17 16:58:09 1998 Christopher Faylor + + * winsup.h (hinfo): Remember initial fd to start searching + for new fds. This avoid assigning std/in/out/err to + files opened early in initialization. + (hinfo_vec::find_unused_handle): New default way to search + for a new handle. Avoids using std/in/out/err until the + proper time in the initialization. + * fhandler.cc (fhandler_make_pipe): Use default method for + finding unused handle. + * net.cc: Ditto throughout. + * pipe.cc (dup): Ditto. + * syscalls.cc (_open): Ditto. + * hinfo.cc (hinfo_vec::init_std_file): Set initial fd for open + search to include std/in/out/err. + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * spawn.cc (perhaps_suffix): Use translated win32 path when + determining if a .exe extension should be added or suffer adding + a .exe extension twice. + +Mon Aug 10 15:08:49 1998 Geoffrey Noer + + * include/cygwin32/version.h: up minor version number + +Mon Aug 10 07:04:13 1998 DJ Delorie + + * delqueue.cc: rewritten for speed. Don't check *every* entry in + the list if we know the list is empty, plus check for duplicates. + * delqueue.h: ditto. + +Sat Aug 8 14:03:52 1998 Eric Bachalo + + * spawn.cc (perhaps_suffix): If report_failure_p is non-zero this + function will search for (PROG is the pathname to the executable + file) PROG.exe, PROG, PROG.com, PROG.bat, and PROG.cmd and return + either the full path name if found or NULL if not. + (spawn_guts): If the file name of the executable end in either + .exe, .com, .bat, or .cmd we assume that it is not a script file + and therefore do not open the file to determine if it is. + +Thu Aug 6 22:25:38 1998 Christopher Faylor + + * path.cc (path_conv): If a path component is missing, short- + circuit the symlink check. Bug fix for case where path ends + in a slash. + (path_conv::path_conv): Make sure that a file is not + a symlink when returning immediately. Avoid checking for + symlinks on network shares. Check for existence of file prior + to taking it apart for symlink checking (this needs more work). + +Sun Aug 2 19:17:59 1998 Christopher Faylor + + * select.cc (cleanup_pipe_thread): Cleanup thread handle or suffer + handle leak. + (cleanup_socket_thread): Ditto. + * sigproc.cc (proc_subproc): Make wait thread manual reset to + solve problem with nested waits not waiting correctly. + * fhandler_tty (fhandler_tty_slave::open): Don't create the output + mutex, just open it. If it can't be opened, its an error. + +Wed Jul 29 12:08:19 1998 Eric Bachalo + + * include/Windows32/Defines.h: Added Virtual-Key Code defines + for the Win95 keys - VK_LWIN, VK_RWIN, and VK_APPS. + +Tue Jul 21 14:47:59 1998 DJ Delorie + + * path.cc (path_prefix_p): optimize calls by comparing first + characters inline. + (path_conv): optimize by not checking both foo and foo/ for + symbolic links. + +Tue Jul 21 14:39:03 1998 Christopher Faylor + + * pinfo.cc (pinfo_init): Set myself->sid to 1 so that + a program started up outside of cygwin will not trump + other opens of ttys. Fixes problem with pgid change below. + +Tue Jul 21 12:59:21 1998 Christopher Faylor + + * path.cc (chdir): Force chdir to disk device to go to the root + directory. + +Tue Jul 21 09:32:23 1998 Christopher Faylor + + * pinfo.cc (pinfo_init): 0 is a very bad value for a default pgid. + +Fri Jul 16 15:09:50 1998 Stan Cox + + * (gcrt0.c, gmon.c, profil.c, mcount.c, gmon.h, profil.h, + config/i386/profile.h): New files for gprof cygwin support. + Some code contributed by Tim Newsham for Secure Networks, Inc. + * Makefile.in (LIBGMON_A, GMON_START, GMON_OFILES): New for gprof. + +Mon Jul 13 19:29:00 1998 Eric Bachalo + + * dcrt0.cc (insert_files): Now both -@file and @file work as + command line file insertion options. + * fhandler_serial.cc (fhandler_serial::open): Enabled RTS Control + Line by default to make full handshaking cables work for the + D10V board. (CDB.fRtsControl) + (fhandler_serial::tcsetattr): same as above + +Wed Jul 8 15:53:35 1998 Christopher Faylor + + * dcrt0.cc (dll_crt0_1): Avoid redundant strace_printf. + +Wed Jul 8 15:05:10 1998 DJ Delorie + + * fhandler.cc (fhandler_base::lseek): Note lseek so that next + write() can check for the Win95 "gap" bug. + (fhandler_base::write): If Win95 and lseek past eof + followed by write, use WriteFile to force the "gap" to be filled + with zeros rather than left to the "undefined" data Win32 specifies. + (fhandler_base::fhandler_base): initialize check_win95_lseek_bug_. + * fhandler.h (class fhandler_base): Add check_win95_lseek_bug_ + for bug: when seek past EOF and write, win95 fills with random + data (security hole). + +Thu Jul 2 10:45:15 1998 Christopher Faylor + + * environ.cc (winenv): Be more paranoid when restoring special + win32 environment variables beginning with '='. + +Thu Jul 2 09:19:32 1998 Christopher Faylor + + * environ.cc: Previous change was not rigorous enough. + Track environment variables to convert in a structure which + records the correct function for converting the environment + variable from/to POSIX format. + (isspecial): New function. + (parse_options): Use template to initialize parse array. + (posify): Use new conversion function. + (winenv): Ditto. Also restore special win32 environment variables + beginning with '='. + * path.cc (conv_path_list): Source argument should be const. + (win32_to_posix_path_list): Ditto. + (posix_to_win32_path_list): Ditto. + * path.h: Reflect changes to path.cc. + +Tue Jun 30 14:00:32 1998 Christopher Faylor + + * environ.cc (winenv): Avoid converting environment variables to + windows style if they begin with something like a 'C:'. + +Sun Jun 28 20:59:16 1998 Christopher Faylor + + * include/Windows32/Structures.h (MINMAXINFO): Add a missing + *LP... + +Thu Jun 25 10:45:38 1998 Christopher Faylor + + * signal.cc (sigpending): Stop from always reporting pending signals + when no signals are actually pending. + +Tue Jun 23 15:38:45 1998 Christopher Faylor + + * Makefile.in: Add a new target. + * cygwin.din: Add cygwin32_internal interface. + * dcrt0.cc (dll_crt0_1): Don't call main if no main set. Allows + initialization from a .dll. + * utils/ps.cc: Use new internal/external interface to cygwin to + provide an unchanging interface to some cygwin internals. + * external.h: Preliminary stab at an interface to cygwin32 for + getting at the "naughty bits". + * external.cc: External interfaces to some cygwin internal stuff. + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * exceptions.cc (sig_handle): When abnormally terminating, + close_all_files in signal thread context to prevent socket hangs. + +Thu Jun 18 15:17:06 1998 Christopher Faylor + + * pinfo.cc (pinfo_list::allocate_pid): Wrap pids at SHRT_MAX + or ash complains. + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * window.cc (WndProc): Always kill timer before starting up + a new one or eventually suffer a timer proliferation. + +Mon Jun 15 09:40:30 1998 Christopher Faylor + + * exceptions.cc: Cosmetic change. + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * syscalls.cc (system): Ignore SIGINT, SIGQUIT and SIGCHLD while + in a system() call. + +Thu Jun 11 18:37:02 1998 Geoffrey Noer + + * include/sys/syslog.h: add missing LOG_LOCALn bits + +Tue Jun 9 22:29:26 1998 Christopher Faylor + + * dll_init.cc (DllNameIterator::operator const char* ()): Add + a missing \n to a *_printf. + * fhandler_tty.cc (fhandler_tty_slave::dup): Ditto. + (fhandler_tty_slave::ioctl): Ditto. + * errno.cc (errmap): Add an unrepresented windows error. + Simplify table. + +Tue Jun 9 17:21:44 1998 Christopher Faylor + + * errno.cc (errmap): Make sure that errmap array is + terminated with a NULL or suffer a SIGSEGV. + +Tue Jun 9 10:30:02 1998 Christopher Faylor + + Change `sprintf' to `__small_sprintf' throughout cygwin. + * cygwin.din: Don't export exception handler. + * exceptions.cc (__cygwin32_exception_handler): Rename to + handle_exceptions. Make static. Redo core file generation + slightly so that __small_sprintf can be used. + (call_handler): Remove use of `rethere' in asm code. Don't + probe stack as this is potentially dangerous unless done + meticulously. + * select.cc (select): Redo to create thread whenever needed + for pipe/socket. Thread termination denotes fd readiness. + +Mon Jun 8 14:31:11 1998 Christopher Faylor + + * hinfo.cc (set_std_handle): New function to set windows + "standard" handles from cygwin handles. + (hinfo_vec::dup2): Set windows standard handle if appropriate. + * syscalls.cc (_open): Set windows standard handle if appropriate. + +Sun Jun 7 16:34:00 1998 Christopher Faylor + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * fhandler_console.cc (fhandler_console::scroll_screen): Add a + workaround for Win95 ScrollConsoleScreenBuffer bug which allowed + scrolling to work correctly in both directions. + (fhandler_console::char_command): Simulate underscore with cyan + instead of magenta like on a real linux console. + +Sat Jun 6 00:01:18 1998 Christopher Faylor + + * dcrt0.cc: Remove obsolete PPC and OLDWAY defines. + * exceptions.cc: Remove obsolete PPC defines. + +Fri Jun 5 22:18:01 1998 Christopher Faylor + + * utils/Makefile.in: install should build products if necessary. + +Fri Jun 5 17:47:11 1998 Geoffrey Noer + + * errno.cc (seterrno): shouldn't & against 0xff since there + are error codes above 255. + +Fri Jun 5 14:35:36 1998 Christopher Faylor + + * exceptions.cc (ctrl_c_handler): Ignore CTRL_LOGOFF_EVENT or + everybody gets signalled when a user logs off. Allow program + to clean up when receiving a CTRL_CLOSE_EVENT or CTRL_SHUTDOWN_EVENT. + * spawn.cc (_spawnve): Delete hmap.vec from created child since + it just gets overwritten in the child anyway. + * pinfo.cc (lpfu): u -> user_data. + +Thu Jun 4 22:45:12 1998 Geoffrey Noer + + * mmap.cc (mprotect): 3rd arg to VirtualProtect call should + be new_prot, not prot. Also, fix check for PROT_NONE (==, + not &). + +Wed Jun 3 16:37:43 1998 Geoffrey Noer + + * exceptions.cc: Fix typo in comment + (ctrl_c_handler): Add comments, return FALSE on CTRL_CLOSE_EVENT, + CTRL_LOGOFF_EVENT, and CTRL_SHUTDOWN_EVENT events. Otherwise, + we handle the console event ourselves, send a SIGINT, and return + TRUE. + +Wed Jun 3 14:36:08 1998 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * path.cc (conv_to_win32_path, conv_to_full_win32_path): resolve + symlinks before converting. + +Wed Jun 3 02:11:23 1998 Geoffrey Noer + + * exceptions.cc (ctrl_c_handler): return zero when a + CTRL_LOGOFF_EVENT occurs. + +Wed Jun 3 01:01:17 1998 Geoffrey Noer + + Reorganize fhandler-related file layout. + * Makefile.in: Remove console.o, add fhandler_console.o. Add + fhandler_serial.o. Remove tty.o, add fhandler_tty.o. + * fhandler_console.cc: Was console.cc. + * console.cc: Delete. + * fhandler_serial.cc: Was code in fhandler.cc. + * fhandler.cc: Delete fhandler_serial routines. + * fhandler.h: Fix comments describing fhandler file layout. + * fhandler_tty.cc: Was code in tty.cc. + * tty.h: Delete. + * fhandler_tty.h: Was tty.h. + * tty.cc: Delete code moved to fhandler_tty.cc. + * winsup.h: Include fhandler_tty.h instead of tty.h. + +Tue Jun 2 23:34:42 1998 Geoffrey Noer + + Don't need processor-specific sysdef directories: + * sysdef/powerpc: remove all files + * sysdef/i386: move all files to top of sysdef directory + * configure.in: stop setting processor-specific sysdef variable + * configure: regenerate + * Makefile.in: build .a files from top-level sysdef files. + +Tue Jun 2 16:52:18 1998 Geoffrey Noer + + patch from lhall@rfk.com (Larry Hall): + * console.cc (fhandler_console::fhandler_console): call + fillin_info() to check if console attributes have already been + set. If so, set the default foreground color to be the default + for the console, otherwise set it to white. + (fhandler_console::char_command): use the default color to set fg, + bg, and bold for all cases. + +Mon Jun 1 14:05:01 1998 Christopher Faylor + + * dir.cc (writable_directory): Avoid a malloc. + (opendir): Convert to fully qualified path spec. Use inode from + stat as hash instead of recalculating. + (readdir): Try hard to generate the same inode for filenames + as inodes returned from stat(). Handle '.' and '..' inodes + differently than normal files. Note that '..' will still fail + in certain pathological conditions. + * fhandler.cc (fstat): Preserve errno around path conversion. + * path.cc (path_conf::path_conv): Add an extra argument signifying + whether caller wants a fully qualified Windows spec. + (get_current_directory_name): New function. Retrieves current + directory name into internal buffer. + (getcwd_inner): Reorganize. Use get_current_directory_name() + to retrieve a (possibly cached) directory name. + (hash_path_name): Move function here from syscalls.cc. Rewrite to + deal (simplistically) with non-absolute path specs. Use + get_current_directory_name to absolutize path. + * path.h: Reflect additional argument for path_conv. + * select.cc (cygwin32_select): Remove newline from select_printf(). + * syscalls.cc (hash_path_name): Move to path.cc. + (stat_worker): Always use full path spec so that inodes are + calculated correctly. + * uinfo.cc (getlogin): Make extern "C". + * include/sys/resource.h: Put extern "C" around this file. + +Mon Jun 1 13:16:03 1998 Christopher Faylor + + * console.cc: Comment out small_printfs which issue errors + on things like invalid escape sequences. This is very much + unlike a normal terminal, or even like linux which console.cc + purports to emulate. + (console_read): Renamed from FakeReadConsole. Streamline + slightly. + (fhandler_console::read): Ditto. + +Fri May 29 22:41:18 1998 Geoffrey Noer + + * hinfo.cc: Include unistd.h, not fcntl.h. + +Fri May 29 21:38:10 1998 Christopher Faylor + + * path.cc (mount_info::binary_win32_path_p): Don't allow + the root mount to replace a //drive or //host specification. + +Fri May 29 08:20:28 1998 Geoffrey Noer + + * winsup.h: Remove exports section in favor of external + include files. Fix some comments. + * {console.cc, fcntl.cc, pipe.cc}: Include unistd.h. + * dcrt0.cc (__main): Make extern "C". + * strace.cc: Include time.h. + * wait.cc (_wait): Make extern "C". + * version.h: Bump minor version to 3 in honor of /dev/windows + support. + +Fri May 29 03:11:28 1998 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * Makefile.in: Add fhandler_windows.o target + * fhandler.h: Include . fhandler_windows: new + fhandler class that handles access to Windows message queue. + (fhandler_base::is_windows): new virtual member function + * fhandler_windows.cc: New file, fhandler_windows class + implementation. + * hinfo.cc (hinfo_vec::build_fhandler): build fhandler_windows + class for "/dev/windows". Include . + * select.cc: New fd_windows_map class + (fd_windows_map::convert_to_unix_fdset): New, check for Windows + messages in a queue. + (cygwin32_select): check for windows fd is passed to select call, + increase size of harray by one to support windows pseudo-handle, + do MsgWaitForMultipleObjects if windows fd passed to select call. + +Thu May 28 18:22:24 1998 Ian Lance Taylor + + * utils/cygpath.cc: New file. + * utils/Makefile.in (PROGS): Add cygpath$(EXEEXT). + (cygpath$(EXEEXT)): Ne target. + + * include/sys/cygwin.h: Declare more path conversion functions. + +Thu May 28 15:56:26 1998 Geoffrey Noer + + * include/sys/ioctl.h: need to include + * syscalls.h: remove ioctl proto + +Wed May 27 01:34:06 1998 Geoffrey Noer + + * cygwin.din: add sethostent/endhostent exports + * net.cc (sethostent, endhostent): new stubs + +Fri May 22 17:31:50 1998 Geoffrey Noer + + * include/cygwin32/in.h: correct typo in IPPORT_WHOIS define + +Fri May 22 17:00:48 1998 Geoffrey Noer + + * include/sys/ioctl.h: add ioctl proto + +Wed May 20 18:52:31 1998 Geoffrey Noer + + * include/sys/param.h: delete, file overlaps with newlib's. + Move it to newlib/libc/sys/cygwin32/sys where such files + are supposed to go. + +Wed May 20 18:20:35 1998 Geoffrey Noer + + * select.cc (auto_del_fd_set_map::auto_del_fd_set_map): correct + C++ problem -- can't use parens in call to new. + +Wed May 20 17:03:25 1998 Geoffrey Noer + + based on patch from newsham@lava.net (Tim Newsham): + * select.cc: FIXMEs added/adjusted + (select_sleep): new static select helper function + (cleanup_sockthread): ditto + (cleanup_pipethread): ditto + (cygwin32_select): remove degenerate goto in favor of calling + select_sleep, call cleanup_sockthread and cleanup_pipethread + instead of previously duplicated code. + +Wed May 20 02:21:37 1998 Geoffrey Noer + + patch from Christopher Faylor + * fhandler.cc (fhandler_serial::raw_read): When + vmin_ == 0, vtime_ > 0, don't force only one char at a time + to be read. + (fhandler_serial::tcsetattr): set to.ReadIntervalTimeout + and to.ReadTotalTimeoutMultiplier appropriately so reads + will time out properly when vmin_ == 0, vtime_ > 0. + +Tue May 19 09:05:46 1998 Christopher Faylor + + * init.cc (set_dllname): Use consistent "cygwin32" name for dll + if the name of the dll is actually cygwin. This will allow + better interoperability between dlls which have been renamed, + i.e., cygwindevo.dll -> cygwin98r1.dll. + +Mon May 18 22:39:35 1998 Christopher Faylor + + * winsup.h: Remove sig* undefs since this is now done in newlib. + Define SIGTOMASK define for use by signal mask operations. + * exceptions.cc (__cygwin32_exception_handler): Use SIGTOMASK. + (sig_handle): Ditto + * signal.cc (sigpending): Ditto. + (sigaddset): Use SIGTOMASK. Disallow signal 0. + (sigdelset): Ditto. + (sigismember): Ditto. + * strace.cc (strace_printf): It is possible for strace_mutex to + be an invalid handle. Open the mutex if so. Call ReleaseMutex + until exhausted since a signal may have interrupted an strace_printf. + (strace_dump): Call ReleaseMutex until exhausted. + * tty.cc (do_output): Remove strace printf to avoid filling up strace + output. + (fhandler_tty_slave::read): Use SIGTOMASK. + +Mon May 18 09:11:38 1998 Christopher Faylor + + * dcrt0.cc (dll_crt0_1): Clear errno before calling main. + +Thu May 14 00:37:01 1998 Geoffrey Noer + + * dcrt0.cc: add comments, reformatting + +Wed May 13 17:47:23 1998 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * times.cc (to_time_t): prevent stat from returning incorrect + file modification time (one second less) on fat partitions due + to round-up error. + +Wed May 13 16:03:07 1998 Geoffrey Noer + + * select.cc: add comments, FIXMEs, respace, delete old + sockets-only case that was previously commented out. + (cygwin32_select): in case where handles and sockets are + set, don't check that always_ready_used is zero (that case is + covered before). + * syscalls.cc: delete unused file_queue struct. + +Tue May 12 18:36:25 1998 Geoffrey Noer + + * syscalls.cc (get_os_type): add FIXME + +Tue May 5 14:02:12 1998 Christopher Faylor + + Throughout Cygwin replace use of "sa" SECURITY_ATTRIBUTE variables + with appropriate global variables. + * shared.cc (shared_init): Initialize global security attribute + variables for use in various places around cygwin. + * fork.cc (fork_init): Remove. Functionality replaced by above. + * dcrt0.cc (dll_crt0_1): Remove obsolete fork_init() call. + +Sat May 2 17:40:51 1998 Christopher Faylor + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * tty.cc (create_tty_master): Fill in ut_host utmp field with + local host name instead of "local" to avoid "who" command timeouts. + +Fri May 1 22:38:20 1998 Christopher Faylor + + * environ.cc: Add a global to control com port reset behavior. + (parse_options): Recognize "reset_com" as a CYGWIN32 option. + * fhandler.cc (fhandler_serial::raw_read): Handle vmin and vtime + more like UNIX. + (fhandler_serial::open): Revive code to reset com port on open. + Only reset the port if reset_com global is not set and if this + function is being called explicitly by open. + (fhandler_serial::tcsetattr): Make CRTSCTS flow control more + like UNIX -- it should turn on hardware handshaking in both + directions. Handle vmin and vtime in a manner more consistent + with UNIX. + (fhandler_serial::tcgetattr): Reflect CRTSCTS changes above when + reporting this state. + * include/sys/termios.h: Move CRTSCTS and CRTSXOFF (sic) into + 16 bits or they will never be capable of being set. + +Thu Apr 30 15:05:45 1998 Christopher Faylor + + * console.cc (fhandler_console::init): If resetting stdin, + make sure to reset the ConsoleCtrlHandler. + * exceptions.cc (set_console_handler): New function broken out + of init_exceptions(). Sets the function responsible for handling + CTRL-C. + (init_exceptions): Snipped out set_console_handler. + +Thu Apr 30 14:11:30 1998 Christopher Faylor + + * include/sys/cygwin.h: Remove cygnus-specific declaration. + * winsup.h: Move cygnus-specific cygwin32_attach_handle_to_fd + declaration here. This function may eventually be replaced by + an osf_* function. + +Tue Apr 28 17:07:46 1998 Geoffrey Noer + + * passwd.cc (parse, getpass): remove unneeded uses of NO_COPY + * grp.cc (getgrgid, getgrnam): ditto + +Tue Apr 28 16:18:03 1998 Geoffrey Noer + + * version.h: bump minor version to 2 + * errno.cc: add FIXME + +Wed Apr 22 15:43:56 1998 Geoffrey Noer + + * syscalls.cc (cygname): delete + * shared.cc (shared_name): new, was cygname + * strace.cc, exceptions.cc, sigproc.cc, shared.cc: fix + cygname references in light of above + +Wed Apr 22 14:12:09 1998 Christopher Faylor + + * select.cc (fd_set_map::remove_pair_by_handle): minor optimization + * strace.cc (strace_printf): change format for consistency + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * dcrt0.cc (dll_crt0): Call global constructors explicitly + * tty.cc (create_tty_master): Remove code which attempted to + invoke tty constructor + +Tue Apr 21 16:18:27 1998 Christopher Faylor + + * environ.cc (ucenv): inline + (posify): Ditto + (environ_init): remove obsolete function use + * path.cc (symlink_check_one): Set errno here where appropriate. + (readlink): Rely on errno set by symlink_check_one rather than + defaulting to EINVAL. Should fix problems with RCS. + +Tue Apr 21 15:36:41 1998 Christopher Faylor + + * Implement a NOSTRACE preprocessor define to allow building + Cygwin32 without any STRACE code. + * configure.in: Add entries for architecture specific programs + to allow easier cross-compile builds + * configure: Ditto + * Makefile.in: Ditto + * console.cc (fhandler_console::char_command): Fix two problems + with cursor position report: 1) it reported position relative + to beginning of buffer rather than beginning of screen, 2) it + reported y, x in reversed order + * dcrt0.cc: Remove NO_COPY from variables that don't need it. + Remove variables obsoleted by NO_COPY. + (dll_crt0_1): strace settings are now inherited. Don't try + to initialize strace early. Remove initialization of variables + which are now handled automatically by NO_COPY. Set error mode + for Cygwin32 to fail on critical errors rather than popping up + a dialog box. + * spawn.cc (spawn_guts): Always use default error mode when + spawning a new process. Move error message to more generally + useful location. Terminate signal handling in a cygwin parent + process or two processes will be handling signals. + (_spawnve): Inherit strace stuff + * exceptions.cc (events_init): Provide more information on + "Catastrophic failure". Change error message wording slightly. + * fork.cc: Remove obsolete structure + (cygwin_fork_helper1): Remove use of obsolete structure. Inherit + strace settings in child processes. + * sigproc.cc (sigproc_init): Set wait_sig priority immediately + after thread creation. + * smallprint.c: Remove unneeded include + * strace.cc: Reorganize to handle NOSTRACE + (strace_open): Use strace entries in pinfo structure which are + now inherited + (strace_dump): ditto + (strace_init): preprocessor define STRACE_HHMMSS causes strace + output to use alternate log file format. + (strace_printf): ditto + * syscalls.cc (access): Remove SetErrorMode in favor of global + cygwin32 setting in dll_crt0_1. + * fhandler.cc: Handle NOSTRACE + * tty.cc: Ditto + * window.cc: Ditto + * include/sys/strace.h: Ditto + * winsup.h: Move strace_file handle from per_process to pinfo so + that it can be inherited. Remove obsolete pinfo entry. + +Tue Apr 21 14:30:52 1998 Christopher Faylor + + * hinfo.cc (cygwin32_attach_handle_to_fd): New function + * include/sys/cygwin.h: Ditto. + * cygwin.din: Export new cygwin-specific function + +Tue Apr 21 02:32:08 1998 Geoffrey Noer + + * syscalls.cc: comment out file_queue struct that doesn't + seem to be used for anything anymore. Don't need to include + stdarg.h or sys/socket.h. Include utmp.h. Minor respacing. + Move all functions from misc.cc here. + (_read): change strace debug printf function name to _read + (logout): rename success to res + * misc.cc: delete file + * Makefile.in: adjust for above change + +Tue Apr 21 01:45:05 1998 Geoffrey Noer + + * dir.cc: new file for directory-related functions, was + dirsearch.cc. + (mkdir, rmdir, writable_directory): move here from syscalls.cc, + writable_directory no longer static + * dirsearch.cc: delete file + * winsup.h: add proto for writable_directory. + * errno.cc: new file for errno-related functions, move errmap + struct here from syscalls.cc + (seterrno): move from syscalls.cc + (strerror): move from strerror.cc + * strerror.cc: delete file + * syscalls.cc: delete everything moved to any of the above files + * Makefile.in: adjustments for above + +Thu Apr 17 16:43:23 1998 Geoffrey Noer + + * termios.cc: add comments, add extern "C" in front of exported + calls, move debugging local functions to end of file + * winsup.h: remove fork_terminate proto for function that is no + longer with us. Add strccpy proto. + * spawn.cc (_spawnve): make static + (strccpy): remove in favor of identical function in exec.cc + * exec.cc (strccpy): no longer static + + patch from newsham@lava.net (Tim Newsham): + * select.cc (cygwin32_select): fix off by one error, stop + using memcpy to copy memory over itself + +Thu Apr 16 16:23:00 1998 Geoffrey Noer + + * net.cc: respace, put all fhandler_socket functions together + (getsockopt): fix case statement bug resulting in faulty strace + output + (setsockopt): ditto + * shared.cc: throughout, rename global h to cygwin_shared_h + * strerror.cc: make error global a local variable + * fhandler.h: add comments, add virtual function always_read_ready + to fhandler_serial which should return zero to allow non-blocking + serial I/O. + * Makefile.in: select.cc should depend on select.h + +Wed Apr 15 16:14:01 1998 Geoffrey Noer + + * select.h: new file, containing macros used by select.cc. + * select.cc: remove them from here, include select.h + +Wed Apr 15 15:23:55 1998 Geoffrey Noer + + * ntea.cc (NTReadEARaw): mark as static, don't check allow_ntea + since this is only accessed by functions that have already checked + it. + +Tue Apr 14 14:07:54 1998 Geoffrey Noer + + * cygwin.din: export truncate call + +Mon Apr 13 23:15:13 1998 Geoffrey Noer + + Throughout Cygwin32, rename *u for per_process data *user_data. + Likewise, rename *s for shared memory data *cygwin_shared. + Respace where necessary. + * registry.cc: minor respace + * registry.h: ditto + * net.cc: ditto + * fhandler.cc (fhandler_base::read): don't redeclare int len + * syslog.cc: add FIXME, reformatting, remove extern "C" around + whole file, add before exported functions + (syslog): rename second cp char pointer cp2 + (setlogmask): comment out unused function + +Mon Apr 13 17:55:43 1998 Geoffrey Noer + + * environ.cc (parse_options): add "ntea" setting to CYGWIN32 + env variable. Setting determines whether NTEA is used or not. + * ntea.cc: Add allow_ntea global which is inited to FALSE. + Now instead of immediately returning FALSE, make all + functions check allow_ntea variable and use or not use NTEA + based on its value. + * ps.cc (main): widen Win32_pid field by one to better handle + Win 95 pids. + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * shared.cc (shared_info::initialize): increase default + heap_chunk_size to 128 mb to get around the problem that + Cygwin32 still can't cope with a split heap properly. + +Wed Apr 8 18:04:07 1998 Geoffrey Noer + + * net.cc (cygwin32_bind, cygwin32_getsockname, cygwin32_listen, + cygwin32_shutdown): if should check sock, not s. + +Wed Apr 8 15:00:46 1998 Geoffrey Noer + + Eliminate warnings revealed by -Wshadow -Wall: + * console.cc (FakeReadFile): fix aggregate with partly bracketed + initializer (add missing brackets). + * tty.cc (fhandler_tty_slave::close): remove unused variable tty + (fhandler_tty_slave::dup): ditto + (fhandler_tty_slave::send_ioctl_request): ditto + +Wed Apr 8 03:04:11 1998 Geoffrey Noer + + Eliminate warnings revealed by -Wshadow -Wall: + * console.cc (FakeReadFile): change variable name index to + modifier_index. + (fhandler_console::read): remove second definition of flags + * dcrt0.cc (build_argv): rename s to start, e to end + (insert_files): reformat, add parens around assign used as truth + value, make i a DWORD, remove dup def of i. + * dlfcn.cc (set_dl_error): rename s to str + (checkAccess): rename to check_access + (checkPathAccess): rename to check_path_access + (getFullPathOfDll): rename to get_full_path_of_dll, don't + redeclare len + * dll_init.cc (DllList::detachDll): rename index to dll_index + * fork.cc (cygwin_fork_helper1): rename index to dll_index, + reformat slightly, rename res in dll load section to loadres, + don't redeclare rc two additional times + (dump_jmp_buf): rename s to sbuf + * grp.cc (initgroups): rename group arg to grp + * hinfo.cc (digits): rename s to str + (hinfo_vec::build_fhandler): rename first buf variable to + buf_info, the second to buff. + (hinfo_vec::linearize_fd_array): cast sizeof return to int, + declare i in for loop + (hinfo_vec::de_linearize_fd_array): declare i in for loop + * misc.cc (nice): rename pri to priority, index to curr + (cygname): rename s to str + (login): rename tty to currtty + (logout) put missing parens around arg to sizeof calls + * net.cc (DuplicateSocket): rename function to duplicate_socket, + rename s arg to sock + (fhandler_socket::fhandler_socket): rename s arg to sock + (socketpair): rename sin to sock_in + (cygwin32_rexec): rename passwd arg to password + * passwd.cc (parse): rename stat array to tmpbuf + * resource.cc (fill_rusage): rename creation to creation_time, + exit to exit_time, kernel to kernel_time, user to user_time + (getrusage): rename rusage arg to rusage_in + * sigproc.cc (proc_terminate): move i declaration outside of + loop, get rid of extra declaration + (getsem): rename s to str + (proc_strace): declare i at top of function, remove extra two + declarations of it later + * smallprint.c: include ctype.h for isalnum proto + (__small_vsprintf): put parens around assign used as truth value + * spawn.cc (spawn_guts): rename both s variables to str, remove + redeclarations of i + * strace.cc (mark): rename s arg to str + * syscalls.cc (chown): remove unused vars group, passwd + (access): rename s to st + (ctermid): rename s to str + * termios.cc (cfsetospeed, cfsetispeed): rename s to speed + * times.cc (times): rename creation to creation_time, + exit to exit_time, kernel to kernel_time, user to user_time + (time_t_to_filetime, timeval_to_filetime): rename time to time_in + * tty.cc (create_tty_master): rename utmp variable our_utmp + (fhandler_tty_master::init): rename ttynum arg ttynum_in + +Tue Apr 7 17:18:05 1998 Geoffrey Noer + + * syscalls.cc (seterrno): add FIXME + * path.cc (symlink_check_one): change comment wording + + patch from Tom Tromey (tromey@cygnus.com) + * syscalls.cc (access): Call SetErrorMode to turn off critical + errors dialog. + + patch from Mikey (jeffdb@netzone.com): + * fhandler.cc (fhandler_disk_file::open): under Win95, set + S_IXOTH|S_IXGRP|S_IXGRP if the first two bytes of a file contain + a '#!'. + (fhandler_disk_file::check_execable_p): consider shell scripts + execable + +Mon Apr 6 20:55:06 1998 Geoffrey Noer + + * include/sys/cygwin.h: add protos for cygwin32 path conversion + functions. + +Wed Apr 1 16:12:58 1998 Geoffrey Noer + + * {fhandler.cc, fhandler.h, hinfo.cc, console.cc}: Rename + fhandler_tty class to fhandler_serial + +Tue Mar 31 16:27:36 1998 Geoffrey Noer + + * ntea.cc: temporarily disable reading/writing NTEA information + due to the large penalty incurred on NT fat partitions. + +Fri Mar 27 13:35:30 1998 Geoffrey Noer + + * environ.cc (parse_options): change struct to union to avoid + references to uninitialized fields. + +Thu Mar 26 19:03:00 1998 Eric Bachalo + + * dcrt0.cc (insert_files): added this function to replace + -@file in the command line with the contents of the file + (dll_crt0_1): calls insert_files before building argv + +Wed Mar 25 15:25:26 1998 Geoffrey Noer + + And more: + * {fhandler.cc, fhandler.h, tty.cc, net.cc, console.cc}: make + ioctl calls' cmd arg unsigned, ditto for access arg of init calls. + * console.cc (fhandler_console::fillin_info): add parens around + assignment used as truth value. + (FakeReadFile): make copied_chars a size_t + (fhandler_console::read): make i in loop unsigned + * environ.cc (setenv): make l_value unsigned, add parens around + assignments used as truth values. + * exceptions.cc (call_handler): supposed to return an int and + wasn't at the end of control flow. Now returns 1 there. + * fhandler.h (~fhandler_base): destructor should be marked virtual + * misc.cc (login): add parens around assignment used as truth + value. + * net.cc: cast INVALID_SOCKET to int in comparisons + (fhandler_socket::ioctl): remove int cast to FIONBIO since cmd + is now unsigned + (get_win95_ifconf): add cast to signed vs unsigned int comparison. + * ntea.cc (NTReadEA): add cast to signed vs unsigned int + comparison. + * path.cc (getcwd_inner): make len a size_t + * pinfo.cc (cygwin32_winpid_to_pid): add comment + * select.cc (cygwin32_select): make wait_ret an int + * signal.cc (kill_worker): add parens around assignments used as + truth values. + * sigproc.cc (wait_sig): make rc a DWORD + (sig_send): add parens around assignment used as truth value. + * strace.cc: make inqueue global a static DWORD + * tty.cc (do_output): add cast to signed vs unsigned int + comparison. + (fhandler_pty_master::open): remove unused handle nh + +Tue Mar 24 18:03:59 1998 Geoffrey Noer + + More spring cleaning: + * net.cc: move LOAD macro definition out of winsock_init, + correction to make it valid ANSI C++. + * grp.cc (read_etc_group): pass default line directly to + add_grp_line call + +Mon Mar 23 19:21:00 1998 Geoffrey Noer + + patch from cgf@bbc.com (Christopher Faylor): + * spawn.cc (spawn_guts): Don't call close_all_files if a cygwin + process has been spawned. Otherwise, we close tty handles twice. + +Fri Mar 20 23:01:24 1998 Geoffrey Noer + + * pinfo.cc (pinfo_list::init): Initialize next_pid to PBASE. + (pinfo_list::operator []): Now index is given by pid mod size(). + (pinfo_list::allocate_pid): Allow more pid numbers than spaces in + the process table. Pids now can range from PBASE (1000) to + INT_MAX. At that point they wrap to 1000 again. For speed, use + modular arithmetic to map pids into table. + * winsup.h: move PBASE to pinfo.cc, rename next_pid_index to + next_pid + * utils/ps.cc (main): reorg of what's printed where, listing pid + first. + +Thu Mar 19 15:05:07 1998 Geoffrey Noer + + * winsup.h: Change section name in NO_COPY definition. We were + using a .data$nocopy section to avoid copying certain data on + fork. The linker used to include this between __data_start__ and + __data_end__, but that broke building the cygwin32 dll. The fix + is to rename the section ".data_cygwin_nocopy" and explictly + include it after __data_end__. + +Wed Mar 18 15:03:51 1998 Geoffrey Noer + + * tty.h: fix ttyslot proto; it returns an int + * glob.h: fix glob proto; it returns an int + +Mon Mar 16 16:16:40 1998 Geoffrey Noer + + * Makefile.in: stop installing the dll in the lib directory as + well as the bindir. + * environ.cc (parse_options): don't need to call malloc + +Mon Mar 16 11:56:23 1998 Geoffrey Noer + + patch from cgf@bbc.com (Christopher Faylor): + * tty.cc (fhandler_tty_slave::dup): Don't set flags to 0. Flags + have already been set in wrapper. + * net.cc: Rename `s' variable which shadows global `s'. + * termios.cc: ditto + * time.cc: ditto + +Tue Mar 10 15:54:04 1998 Geoffrey Noer + + * version.h: up CYGWIN_DLL_VERSION_MINOR + +Tue Mar 10 15:41:29 1998 Geoffrey Noer + + patch from cgf@bbc.com (Christopher Faylor): + * spawn.cc (spawn_guts): Make argument handling after `#! pgm' + handle spaces similarly to UNIX. Close "linearized" file handles + when a non-cygwin32 binary is executed or suffer hangs on exit. + Reorganize lpReserved2 buffer to avoid conflicts with Microsoft + usage which resulted in incorrect stdin/stdout operation with + programs compiled using MSVC. + * pinfo.cc (pinfo_init): Accomodate change to lpReserved2 + organization. + +Mon Mar 9 19:27:17 1998 Geoffrey Noer + + * syscalls.cc (_open): modify to take a variable number of + arguments to match newlib's fcntl.h. + * environ.cc (parse_options): rewrite struct known to conform + to ANSI standards. Can't statically initialize, so do so + dynamically at the beginning of the function instead. + + patch from jeffdb@netzone.com (Mikey): + * dcrt0.cc (build_argv, compute_argc): need to escape quotes + +Sat Feb 28 16:41:54 1998 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * fhandler.cc (fhandler_base::init): call set_flags based on + access arg. + * net.cc: include fcntl.h + (fhandler_socket::fhandler_socket): made sockets O_RDWR + +Thu Feb 26 23:41:54 1998 Geoffrey Noer + + Beta 19 release made. + +Sun Feb 22 23:46:31 1998 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * Makefile.in: Do not link cygwinb19.dll with libwsock32.a + * exceptions.cc: add proto for i_WSACleanup. + (sig_handle): call *i_WSACleanup if winsock was inited. + * hinfo.cc: add proto for i_getpeername. + (hinfo_vec::build_fhandler): call *i_getpeername if winsock + was inited + * net.cc: wsock32, i_wsockimports - new globals. Throughout + file, call winsock functions via indirect pointers. + (winsock_init): dynamically load wsock32.dll and resolve addresses + of exports. + (cygwin32_rcmd, cygwin32_rexec, cygwin32_rresvport): resolve + addresses of exports. + * select.cc: add protos for i___WSAFDIsSet, i_WSAGetLastError, + i_select, i_socket, i_closesocket. WINSOCK_FD_ISSET changed to + use indirect pointer. Direct winsock calls changed to indirect. + (cygwin32_select): initialize winsock before calling select in + degenerate case. + * winsup.h: remove protos for ScreenRows, ScreenCols, + ScreenGetCursor, ScreenSetCursor. + +Sun Feb 22 17:44:55 1998 Geoffrey Noer + + * environ.cc (parse_options): comment out -- no longer + compiles with egcs. Will rewrite/enable later. + +Sun Feb 22 13:49:10 1998 Geoffrey Noer + + * syscalls.h: remove protos for _open, _read, _write since + they are in newlib headers that are already included + * syscalls.cc (_read): return int, not ssize_t + (_write): ditto + +Sat Feb 21 14:21:17 1998 Geoffrey Noer + + * Makefile.in: rename dll to cygwindevo.dll + +Sat Feb 21 01:33:56 1998 Geoffrey Noer + + * cygwin.din: remove dup definition of endpwent + +Thu Feb 19 14:20:21 1998 Geoffrey Noer + + * include/cygwin32/cygwin_dll.h: Correct protection wrapper + +Tue Feb 17 20:21:24 1998 Geoffrey Noer + + * include/Windows32/Structures.h: tagBITMAPFILEHEADER should + be packed. + +Tue Feb 17 19:34:41 1998 Geoffrey Noer + + patch from cgf@bbc.com (Christopher Faylor): + * cygwin.din: export sigpause + * signal.cc (sigpause): New "compatibility interface" to + sigsuspend function. Used currently by inetutils. + +Tue Feb 17 11:43:27 1998 Ian Lance Taylor + + * tty.h (class tty): Add slave_opened field. + * tty.cc (fhandler_tty_master::init): Initialize slave_opened. + (do_output): Only return with EOF if the slave has been opened. + (fhandler_tty_slave::open): Set slave_opened. + (fhandler_pty_master::open): Initialize slave_opened. + + * tty.cc (fhandler_pty_master::read): Change type of n to DWORD. + If there are no characters to read, and the descriptor is in + nonblocking mode, just return EGAIN. + +Mon Feb 16 15:11:25 1998 Ian Lance Taylor + + * tty.h (class tty): Remove handle_pid and slave_handles fields. + (class tty_list): Add getcount method. + * tty.cc (tty::init): Initialize input_handle and output_handle. + (tty_list::free_tty): If we just freed the last reference to this + tty, close input_handle and output_handle. + (fhandler_tty_master::init): Don't initialize handle_pid and + slave_handles. + (do_output): Instead of just calling ReadFile, loop using + PeekNamedPipe and check whether the tty has been closed. Return 0 + on EOF and -1 on error. + (process_output): Only print debugging error message if error + occurs in do_output. + (fhandler_tty_slave::open): Always duplicate handles from master. + Never close handles in source. Don't change slave_handles. + (fhandler_tty_slave::close): Don't change slave_handles, and don't + close tty handles. + (fhandler_tty_slave::linearize): Call attach_tty. + (fhandler_tty_slave::de_linearize): Don't call attach_tty. + (fhandler_tty_slave::dup): Don't increment slave handles. + (fhandler_pty_master::open): Don't initialize handle_pid and + slave_handles. + (fhandler_pty_master::close): Don't check slave_handles, and don't + close tty handles. + (fhandler_pty_master::read): Handle EOF return value from + do_output. + (fhandler_pty_master::linearize): Call attach_tty. + (fhandler_pty_master::de_linearize): Don't call attach_tty. + + * fork.cc (cygwin_fork_helper1): Copy strace_mask from parent to + child. + +Thu Feb 12 20:33:57 1998 Geoffrey Noer + + patch from cgf@bbc.com (Christopher Faylor): + * utils/cygwin.cc: Modify -s option to use new strace_mask entry + in pinfo. Prepare for future ability to specify an strace file. + +Thu Feb 12 11:57:26 1998 Geoffrey Noer + + * grp.cc (read_etc_group): add a default /etc/group in memory + if /etc/group isn't found + (getgrnam): return NULL if requested group isn't found instead + of returning a default group + +Wed Feb 11 15:59:10 1998 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * strace.cc (strace_open): do not close u->strace_file if it + points to stderr. + * malloc.cc (malloc_init): do not check for application's malloc + in a forkee, this breaks memory coherency in a forkee and forker. + use_internal_malloc flag now copies on fork. + +Tue Feb 10 18:11:30 1998 Geoffrey Noer + + patch from cgf@bbc.com (Christopher Faylor) + Throughout sources, mark statics and globals as NO_COPY where + appropriate. + * fork.cc (cygwin_fork_helper1): Remove #if 0 around fork_copy of + cygwin data/bss. Remove __malloc_copy since it is no longer + necessary. + +Tue Feb 10 15:30:19 1998 Geoffrey Noer + + patch from cgf@bbc.com (Christopher Faylor) + * console.cc (fhandler_console::write): Implement xterm style + escape sequences for setting title in the console title bar. + * fhandler.h: Define constants for console title escape sequence. + +Tue Feb 10 14:16:17 1998 Geoffrey Noer + + * include/a.out.h: remove junk chars introduced by mailer + when this header was sent to us + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * libccrt0.cc: rename cygwin_attach_dll to cygwin32_attach_dll + + patch from cgf@bbc.com (Christopher Faylor): + * environ.cc: fix off by one problem + +Mon Feb 9 14:56:00 1998 Geoffrey Noer + + * Makefile.in: add registry.h to environ.o deps + +Mon Feb 9 14:42:24 1998 Ian Lance Taylor + + * Makefile.in (DLL_OFILES): Rename dllinit.o to dll_init.o. + + * tty.cc (fhandler_tty_slave::close): Don't close the tty handles + if the slave and the master are the same process. + + * path.cc (read_mounts): Change key parameter to reference, to + avoiding running the destructor. + +Mon Feb 9 13:53:50 1998 Geoffrey Noer + + patch from cgf@bbc.com (Christopher Faylor): + Moves all environment manipulation into environ.cc. + Switches to CYGWIN32 for settings: + set CYGWIN32=[no]title [no]strip_title [no]binmode [no]glob + strace=mask:cache,file [no]tty + (set STRACE=whatever is still honored). + Propagates tty settings to all subprocesses regardless of + unsetting of environment variable. + Moves strace mask into pinfo structure for easier future + manipulation by external program. Moves strace_file into the + vacated position for automatic use in forked processes. + Propagates old title to execed processes so that they can + correctly restore the correct title when they exit. + * console.cc: Use PID_USETTY setting in process_state so that + tty state can be easily inherited. + (set_console_title): New function to set console title. + * syscalls.cc: Use PID_USETTY setting in process_state so that + tty state can be easily inherited. + * tty.cc: Ditto. + * hinfo.cc: Ditto. + (hinfo_vec::de_linearize_fd_array): Return last location in buffer + for further potential processing. + * dcrt0.cc: Add global variables for control of glob and title, + set by environ_init. Mark some variables as NO_COPY. + Remove routines and variables for dealing with environment. + (dll_crt0_1): Move environment initialization into separate + function. Honor 'noglob' CYGWIN32 setting. + * environ.cc (environ_init): New function to initialize the + environ table. Also scans for CYGWIN32 environment variable, + setting appropriate values. + (ucenv): New function. Upper cases an environment variable. + (parse_options): New function. Parse CYGWIN_* environment + variable. + (posify): New function. Convert a Windows env path spec to + cygwin. + (env_sort): New function. Sort an environ block. + (winenv): New function. Returns a windows style environment + block. + * fhandler.cc (fhandler_base::read): Reflect change to location of + strace_mask. + * fork.cc (cygwin_fork_helper1): Remove save/restore of some + settings since this is automatic now with new dll data copy. Save + PID_USETTY setting in child process_state. + * strace.h: Cosmetic change. + * pinfo.cc (pinfo_init): Call environ_init here since it may + affect further processing in this function. Use old console title + from "parent" process if execed process. Reflect change to + location of strace_mask. + * spawn.cc (spawn_guts): Remove environment manipulation code. + Use new winenv function call instead. Save old title in block of + memory copied to newly execed process if title is being displayed. + * strace.cc: Changes to reflect new location for strace_mask and + strace_file. These are now automatically inherited on fork. + * winsup.h: Move strace_mask into pinfo to allow possible + manipulation by other processes. Put u->strace_file in uptr + structure so that it will be automatically duplicated on fork, + removing the necessity of initializing strace in a forked + process. Add functions/variables associated with environment + manipulation and console title setting. + +Mon Feb 9 03:06:56 1998 Geoffrey Noer + + Extensive reformatting in new files from next patch. + Rename dllinit.h file to dll_init.h and likewise for dll_init.cc. + Rename cygwin_detach_dll to cygwin32_detach_dll throughout. + Similarly, rename cygwin_attach_dll and _cygwin_dll_entry. + And rename sanityAndSyncCheck to check_sanity_and_sync. + Also: + * dll_init.h: don't include winsup.h + * dll_init.cc: include winsup.h here instead + * dlfcn.cc: include winsup.h, don't include windows.h + * cygwin.din: rename cygwin_detach_dll to cygwin32_detach_dll. + + patch from giac@dalim.de (Philippe Giacinti): + Copy data areas of cygwin-compiled dlls on fork(), + implement dlopen/dlsym/dlclose/dlerror calls. + * Makefile.in: add dlfcn.o and dllinit.o to DLL_OFILES, add + dllinit.h dependencies + * cygwin.din: dll_dllcrt0, cygwin_detach_dll, dlopen, dlclose, + dlsym, dlerror, dlfork -- new exports. + * dcrt0.cc: include dllinit.h, mark u pointer as NO_COPY. + (sanityAndSyncCheck): new, code moved from dll_crt0_1. + Initialize all linked dlls before calling main(). + * dlfcn.cc: new file. + * dllinit.cc: new file. + * dllinit.h: new file. + * exceptions.cc: mark some variables with NO_COPY. + * fork.cc: include dllinit.h; declare cygwin.dll data/bss + start/end. + (cygwin_fork_helper1): copy data/bss of cygwin.dll itself to child + process (the code is disabled now); copy data areas of + linked/loaded dlls (if any); free loaded dll list on cleanup. + * include/cygwin32/cygwin_dll.h: new file. + * include/dlfcn.h: new file. + * libccrt0.cc (cygwin_crt0_common): new, code derived from + cygwin_crt0, MainFunc parameter added. + (cygwin_crt0): call cygwin_crt0_common. + (cygwin_attach_dll): new. + * shared.cc: mark some data as NO_COPY + * strace.cc: mark some data as NO_COPY + * winsup.h: add dll_dllcrt0 proto, NO_COPY macro. + +Sun Feb 8 17:51:26 1998 Geoffrey Noer + + * getopt.c: new. Import Berkeley getopt code modified for use + in Cygnus' kerberos implementation (including the writing of + getopt_long by Chris Provenzano (proven@cygnus.com)) then modified + a bit more to get it working in Cygwin32. Although we were + going to remove getopt, it appears that too many programs would + need fixing to remove it completely. Whether getopt should be + included in Cygwin32 should be decided at a later time. + * include/getopt.h: new. Import Berkeley getopt.h. + * Makefile.in: add getopt.o to LIBCOS + * utils/Makefile.in: remove include of ../../include since + getopt.h is now in winsup/include, also revert recent change + of addition of GETOPT_OBJS. + +Fri Feb 6 16:28:19 1998 Geoffrey Noer + + * cygwin.din: remove set_new_handler and cygwin_set_attributes + exports + * version.h: up major version number + * Makefile.in: rename dll to cygwinb19.dll + * syscalls.cc (cygwin_set_attributes): axe + +Thu Feb 5 18:28:37 1998 Geoffrey Noer + + * include/Windows32/Functions.h: add protos for + DdeCmpStringHandles and DdeCreateDataHandle + * Makefile.in: stop including ../libiberty/getopt* since + we aren't exporting or using them + * utils/Makefile.in: add new variable for libiberty getopt objs + which is linked in for cygwin.exe + +Thu Feb 5 17:59:12 1998 Geoffrey Noer + + syscalls.cc: move ppc dll_entry asm code to... + dcrt0.cc: ...here + + Import new globbing code from NetBSD 1.3 + * glob: delete subdirectory + * glob.c: new file + * glob.h: new file + * Makefile.in: remove glob from submakes, remove glob/libglob.a + from DLL_IMPORTS, fix dcrt0 glob.h dependency + * configure.in: don't configure glob subdirectory + * configure: regenerate + * dcrt0.cc: include glob.h, not glob/glob.h. + (globify): don't call glob with GLOB_NOESCAPE which isn't a valid + flag with this glob + +Wed Feb 4 16:14:13 1998 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + Allow system administrator to enter into the HKLM registry tree + a predefined mount table inherittable by all cygwin users. The + predefined mounts are non-mandatory so the user's mount table has + a higher priority than the default one. Cygwin reads HKLM tree + in read-only mode. + * path.cc (read_mounts): new, code derived from + mount_info::from_registry(). + (mount_info::from_registry): call read_mounts from user's table, + then from system-wide mount table. + * registry.cc (reg_session::reg_session): key and access arguments + added. + (reg_key::init): access argument added. + (reg_key::reg_key): access argument added. + * registry.h (class reg_key): init prototype changed, default + argument of reg_key added. + (class reg_session): default arguments of constructor added. + +Wed Feb 4 15:38:59 1998 Geoffrey Noer + + * include/a.out.h: new coff header file + +Wed Feb 4 01:55:18 1998 Geoffrey Noer + + * uinfo.cc: define DEFAULT_UID/GID here + * winsup.h: removed DEFAULT_UID/GID defs and unused + set_console_title proto. Did some major reorganizing, + and a little reformatting, commenting. + +Tue Feb 3 23:59:23 1998 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + Replace u->self and this_procinfo () with new `myself' pointer + wherever appropriate. Also replace get_pid() calls with a + simple ->pid reference. + +Mon Feb 2 12:34:49 1998 Geoffrey Noer + + patch from sos@prospect.com.ru (Sergey Okhapkin): + * console.cc (FakeReadFile): limit bytes to read to 30000 due to + Win NT 4.0 SP3 bug. Kill foreground process group with SIGWINCH + on console buffer size change if tty support enabled. + * include/sys/termios.h: define more constants. + * tty.cc (fhandler_pty_master::ioctl): kill foreground process + group with SIGWINCH on window resizing. + +Mon Feb 2 12:14:49 1998 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + * dcrt0.cc (dll_crt0_1): Initialize u->self here, early in a + forked process so the correct pid is used in strace output and so + signals do not end up being erroneously sent to the parent. + * exceptions.cc: Make a global variable static. Some minor + optimizations. + (call_handler): Make sure that the signal mask is restored when + sig_dispatch mutex is unavailable. + Reorder asm statements to prevent clobbering of flags register by + preceding ors or risk random inexplicable behavior when returning + from a signal handler. + * fork.cc (cygwin_fork_helper1): Put setjmp restore in child's + pinfo. Have the child figure out its pid earlier in the + initialization process. Don't print a "child failed" error if the + child failed during initialization due to a CTRL-C. This is still + not quite right (see comment). + * sigproc.cc (sig_send): Remove unlock/lock_pinfo or suffer + consistent hangs in zsh. Make {allow,block}_sig_dispatch globally + available. + (wait_sig): Fix problem where blocked signals would still be + processed if queued. Add debugging SIGNOQUEUE conditional to turn + off signal queueing, making cygwin more like traditional UNIX. + * sigproc.h: Add {allow,block}_sig_dispatch functions. + +Mon Jan 26 17:33:57 1998 Geoffrey Noer + + * path.cc (mount_info::init): don't hardcode C: as the default + slash mount. Instead, use the drive letter that the OS is loaded + on. + +Mon Jan 26 13:33:57 1998 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + * fork.cc (cygwin_fork_helper): Move setting PID_INITIALIZING + process_state here to avoid erroneously setting it permanently + via proc_register(). + * pinfo.cc (pinfo_init): Delay notifying "parent" when execing + until this process is ready to receive signals or risk a race + condition if exec parent calls sigproc_terminate prior to + the child exec. + * sigproc.cc (proc_subproc): Don't set PID_INITIALIZING here. + It is too late in the process creation. + (sig_send): Reset sigsuspend mutex prior to use to avoid a race. + (wait_sig): Create sigsuspend mutex as an auto reset to attempt + to avoid a race condition. Notify parent that this process is + ready if we were execed (code moved from pinfo_init). Change + PulseEvents to SetEvents to avoid races + * spawn.cc (spawn_guts): Move setting PID_INITIALIZING + process_state here to help avoid race. + +Fri Jan 23 12:31:37 1998 Ian Lance Taylor + + * malloc.cc (malloc_critical_section): New static variable. + (malloc_init): New function. + (__malloc_lock, __malloc_unlock): New functions. + * winsup.h (malloc_init): Declare. + * heap.cc (heap_init): Call malloc_init. + +Thu Jan 22 18:46:40 1998 Ian Lance Taylor + + * tty.h (class tty): Change slave_handles to int. + * tty.cc (fhandler_tty_slave::open): Check for invalid tty + handles. If this is the first slave, set slave_handles to 2; + otherwise, increment slave_handles. + (fhandler_tty_slave::close): Only close the tty handles if the + slave_handles field drops to 1. + (fhandler_tty_slave::write): Add a debugging message if WriteFile + fails. + (fhandler_tty_slave::dup): Set ttynum of new fhandler. Increment + slave_handles if appropriate. + (fhandler_pty_master::close): Only close the tty handles if the + tty is no longer allocated. + + * tty.h (class tty): Add handle_pid and slave_handles fields. + * tty.cc (attach_tty): Call connect_tty even if use_tty is not + set. + (detach_tty): Don't check use_tty. + (fhandler_tty_master::init): Initialize handle_pid and + slave_handles of tty. + (do_input): Treat \r as end of line character. + (do_output): Only set output_done_event if it is not NULL. + (fhandler_tty_slave::open): Don't worry if we can't open + output_done_event. Check slave_handles field of tty to decide + from where to duplicate the handles. Call detach_tty on error. + If we are now the owner of the slave handles, mark the tty + appropriately. + (fhandler_tty_slave::close): Only close output_done_event if it is + not NULL. Check for errors from CloseHandle. Close the tty + handles if we own them. + (fhandler_tty_slave::write): Only wait for output_done_event if it + is not NULL. + (fhandler_tty_slave::read): If nobody owns the tty, return EOF. + (fhandler_tty_slave::dup): Attach the tty. Don't duplicate + output_done_event if it is NULL. Detach the tty on error. + (fhandler_pty_master::open): Initialize handle_pid and + slave_handles of tty. Don't create output_done_event. + (fhandler_pty_master::close): Only close output_done_event if it + is not NULL. Check for errors from CloseHandle. Only close the + tty handles if we own them. + (fhandler_pty_master::read): Only set output_done_event if it is + not NULL. + * hinfo.cc (de_linearize_fd_array): Don't set use_tty just because + we find a tty to delinearize. + +Wed Jan 21 21:58:27 1998 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + * sigproc.cc: Changes in wait_sig/sig_send semaphore/event + signaling to attempt to eliminate races. + +Tue Jan 20 16:11:05 1998 Geoffrey Noer + + Remove last remnants of the mixed case handling support. + * path.cc (path_conv::path_conv): remove mixed_p init + (mount_info::from_registry): don't check for fmixed + (mount_info::to_registry): ditto + (mount_item::getmntent): when setting ret.mnt_opts, only consider + text vs binary flag + (mount_item::init): remove init of mixed + * path.h: remove mixed_p, mixed from path_conv class. Remove + unmixedcaseify proto. + * include/sys/mount.h: comment out MOUNT_MIXED define, protect + header against multiple inclusion + + A little header file cleanup. Mostly to protect headers against + multiple inclusion. Some aren't strictly speaking necessary but... + * include/sys/cygwin.h: protect header against multiple inclusion + * include/sys/smallprint.h: ditto, also add cplusplus wrapper + * include/sys/strace.h: comment last endif + * include/cygwin32/in.h: change _LINUX_IN_H protect defines + to _CYGWIN32_IN_H + * include/arpa/inet.h: protect header against multiple inclusion + * include/asm/types.h: ditto + * include/net/if.h: ditto + * include/netinet/ip.h: ditto + * include/netinet/ip_icmp.h: ditto + * include/netinet/in.h: ditto, remove commented out real header + file + * include/fcntl.h: protect header against multiple inclusion + * include/memory.h: ditto + * include/mntent.h: ditto + * include/strings.h: ditto + * include/syslog.h: ditto + * include/termio.h: ditto + +Tue Jan 20 12:51:59 1998 Ian Lance Taylor + + * strace.cc (strace_stderr): New static variable. + (strace_init): Set strace_stderr. + (system_printf): If not strace_stderr, use debug_printf to put the + message in a trace file. + + * fhandler.h (fhandler_pty_master): Add neednl_ field. + * tty.h (RESTART_OUTPUT_EVENT): Change to be different from + IOCTL_DONE_EVENT. + * tty.cc (fhandler_tty_master::init): Initialize neednl_. + (do_output): Handle a length of one by using neednl_ to record an + expansion of \n to \r\n which doesn't fit. Never expand \r to + \r\n. Correct order of \r\n. + (fhandler_tty_slave::open): Improve error handling. Use + DUPLICATE_CLOSE_SOURCE to close the pipes in the master process. + (fhandler_tty_slave::dup): Duplicate the handles, rather than + calling fhandler_tty_slave::open. + (fhandler_pty_master::open): Initialize neednl_. + (fhandler_pty_master::read): Return EOF for ERROR_BROKEN_PIPE, + rather than error. Set errno correctly. + * hinfo.cc (digits): New static function. + (build_fhandler): Always accept /dev/ptmx and /dev/ttyDDD, even if + use_tty is not set. use_tty now only controls the interpretation + of /dev/tty. + +Mon Jan 19 14:49:45 1998 Geoffrey Noer + + * sigproc.cc (sig_send): lock_pinfo_for_update during this + function + +Fri Jan 16 18:09:59 1998 Geoffrey Noer + + * sigproc.cc (sigproc_init): if we can't create a signal + thread or can't create sync_proc_subproc mutex, fail with + an api_fatal call rather than just returning + +Fri Jan 16 18:08:49 1998 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + Changed signal handling to use one semaphore and one shared + memory array which is manipulated via Interlocked*() functions. + * exceptions.cc (lock_cs): Comment. Report on error. + (unlock_cs): Add debugging statement. + (sig_dispatch_pending): Remove obsolete function. + (set_process_mask): Adapt to new signal method. + (call_handler): Clear wait()ing threads here while main thread is + suspended to avoid timing screwups. Avoid calling the handler if + can't get dispatch mutex (code moved from sig_handle). Return + status of acquiring the sig_dispatch mutex. + (sighandle): Adapt to new signal method. Reorganize to *always* + honor sig_dispatch mutex or suffer deadlock on fatal signals when + someone else has the mutex and we're attempting to cleanup. + (events_init): Reflect change in cygname() arguments. + * fork.cc (stack_dummy): New function. Returns address of + argument to determine bounds for eventual stack copy. + (cygwin_fork_helper1): Call subproc_init to start up subproc + thread if it is not alreay started. Ensure that signals are + blocked while forked process is initializing. Change method of + calculation for lower stack bounds to slightly more foolproof + method. Preserve some global settings in forked process. + * misc.cc (cygname): Remove an unused argument. + * pinfo.cc (pinfo_list::allocate_pid): Add a useful debugging + statement. + * shared.cc (open_shared_file_map): Reflect change in cygname() + arguments. + * signal.cc (kill_pgrp): Avoid killing dead processes. Don't + kill processes in my pgrp if not also in my ctty. + (sigaction): Adapt to new signal method. + (sigpending): Adapt to new signal method. + * sigproc.cc: Many changes to adapt to new signal method. Also + delay waits for thread initialization until the thread needs to be + contacted. + * sigproc.h: Ditto. + * spawn.cc (spawn_guts): Fix potential off-by-one error(?) in + transcribing the argument list and add paranoid code to detect + future overruns. Change priority to highest so that waiting + process will clear out quickly. + (_spawnve): Call subproc_init() to start up subproc thread if is + not already started. + * strace.cc (strace_printf): Increase size of internal buffer so + that long argument lists printed from spawn_guts do not overrun it + so easily. + * wait.cc (wait4): Set status flag to -1 prior to exit. This will + cause previous wait that was interrupted by a signal which + dispatched to another wait to return the correct error value. + * winsup.h (pinfo): Add _sigtodo array for new signal method. + Remove obsolete field. Reflect change in cygname arguments. + +Thu Jan 15 13:07:07 1998 Ian Lance Taylor + + * syscalls.cc (mkdir): Don't permit the directory to be created if + the parent directory is not writable. + + * syscalls.cc (fchmod): Call chmod with the path name, rather than + just returning zero. + + * syscalls.cc (writable_directory): New static function. + (_unlink): Don't permit the file to be removed if the directory is + not writable. + (rename): Don't permit the rename if either the source or + destination directory is not writable. + + * syscalls.cc (chown): Set username and groupname lengths to UNLEN + + 1, rather than 100. If getpwuid fails, try to look up the real + user name to see if it is the same. Don't report an error if + there is no security mapping. + +Wed Jan 14 15:34:20 1998 Ian Lance Taylor + + * syscalls.cc (setegid): New function which just returns ENOSYS. + (chroot): Likewise. + * cygwin.din: Export setegid, _setegid, chroot, and _chroot. + + * syscalls.cc (setmode): Rename from _setmode. Change to return + the old mode. Remove old setmode function. + * cygwin.din: Make _setmode an alias for setmode. + +Wed Jan 14 14:46:00 1998 Geoffrey Noer + + * Makefile.in: don't strip cygwin.dll by default + * winsup.h: minor reformatting, removed/reworded some comments + +Mon Jan 12 13:53:03 1998 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + Speed up cygwin pid calculation by staying in the range + 1000 through (1000 + PSIZE - 1). + * pinfo.cc (pinfo_list::init): Change to reflect new pid + calculation method. + (pinfo_list::operator []): Ditto. + (pinfo_list::allocate_pid): Ditto. + * winsup.h (pinfo): Move pid and ppid into non-zeroed region since + they are always set by allocate_pid. + (pinfo_list): Change pid_base to next_pid_index to reflect new pid + calculation method. + (PBASE): New constant for new pid calcuation method. + +Sat Jan 10 12:06:38 1998 Geoffrey Noer + + * syscalls.cc (process_deletion_queue): remove wrapper function + (close_all_files): call s->delqueue.process_queue instead of + going through wrapper. + * fhandler.cc (fhandler_base::close): call + s->delqueue.process_queue instead of using above wrapper. + * winsup.h: remove process_deletion_queue proto + * delqueue.h: up MAX_DELQUEUES_PENDING to 100 for now. Rename + v to dqueue for clarity. + * delqueue.cc: v renamed to dqueue throughout. Add FIXME + describing why this whole delqueue system needs rewriting. + +Fri Jan 9 13:18:44 1998 Geoffrey Noer + + Remove some historical baggage: + * syscalls.cc (cygwin_set_attributes): remove commented-out code, + add FIXME since this function should go away next time an + incompatible change to cygwin.din is made. Stop including + include/sys/cygwin.h. + * include/sys/cygwin.h: remove cygwin_set_attributes proto. + Remove CYGWIN_FMODE_ALL_BINARY define. + * hinfo (hinfo_vec::init_std_file_from_handle): remove old + commented-out code + * path.cc (unmixedcaseify): delete commented-out function + (mixedcaseify): ditto + * strerror.cc (strerror): delete commented-out code section + +Tue Jan 6 18:51:40 1998 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + Conform to POSIX method for sending SIGHUP to stopped processes. + * dcrt0.cc (do_exit): Use new kill_pgrp function to kill orphaned + children on group leader exit iff the children are stopped (per + POSIX). + * signal.cc (kill_worker): Negative signal now means to send + a SIGCONT after the signal, to wake up the target process. + (_kill): Break out pgrp handling into separate function. + (kill_pgrp): New function pulled from _kill to send signals + to processes in a given pgrp. + +Tue Jan 6 14:37:43 1998 Geoffrey Noer + + patch from cgf@bbc.com (Chris Faylor): + * fhandler.cc (fhandler_base::open): include + FILE_FLAG_BACKUP_SEMANTICS in file_attributes when file is + a directory. Allows opening of directory as a file. Allows + use of handle to perform some operations on both directories and + files. + (fhandler_base::fstat): Loop when attempting to get volume serial + number. Works around an apparent Windows NT 3.51 bug. + * times.cc (utimes): use FILE_FLAG_BACKUP_SEMANTICS flag + to allow accessing directory times (may only work under NT; + until now it didn't work under either OS). + * winsup.h: Add O_DIROPEN constant. + +Mon Jan 5 19:18:01 1998 Geoffrey Noer + + * Makefile.in: make winsup.h depend on winsup.h in accordance + with below + + patch from cgf@bbc.com (Chris Faylor): + * {*.cc, *.h}: Remove include files already present in winsup.h. + Change empty function parameter lists to (void) where appropriate. + + * fork.cc: Clean up include files. Minor change to CreateProcess + parameter list. + * signal.cc: Remove ifdef'ed stuff. + * smallprint.c: Add a necessary include file. + * winsup.h: Add a common include file. Add a function declaration + for kill_pgrp. + +Mon Jan 5 18:30:37 1998 Geoffrey Noer + + Fix spoofing of directory inodes. + * syscalls.cc (hash_path_name): instead of initializing the + hash to zero, take the value of the initial hash as a new + argument. + (_stat_worker): fix up hash_path_name reference in light of above + * dirsearch.cc (opendir): initialize dir->__d_dirhash to the + hash of the full directory name so readdir can make use of it. + (readdir): compute d_ino by combining the directory hash + calculated by opendir with the hash of the filename. + * fhandler.cc: fix up hash_path_name reference in light of above + + * winsup.h: remove unnecessary protos for getkey, kbhit. Adjust + hash_path_name proto. diff --git a/winsup/cygwin/ChangeLog-1999 b/winsup/cygwin/ChangeLog-1999 new file mode 100644 index 000000000..b459908d2 --- /dev/null +++ b/winsup/cygwin/ChangeLog-1999 @@ -0,0 +1,3552 @@ +Sat Dec 25 12:46:25 1999 Christopher Faylor + + * dlfcn.cc (dlsym): Use correct HANDLE type for GetProcAddress. + (dlclose): Ditto for FreeLibrary. + * fhandler_windows.cc (fhandler_windows::set_close_on_exec): Properly + coerce arguments to set_inheritance. + (fhandler_windows::fixup_after_fork): Ditto for fork_fixup. + * libcmain.cc (main): Simplify. + * select.cc (peek_windows): Properly coerce argument to PeekMessage. + +Sat Dec 25 12:30:25 1999 Christopher Faylor + + * Makefile.in: Eliminate unneeded .y SUFFIX. + * dcrt0.cc (__api_fatal): Make "C". + (do_global_ctors): Make __stdcall. + (getprogname): Ditto. + (insert_file): Ditto. + (globify): Ditto. + (build_argv): Ditto. + (do_exit): Ditto. + * debug.cc (regthread): Ditto. + (makethread): Ditto. + (threadname): Ditto. + (find_handle): Ditto. + (handle_list): Ditto. + (add_handle): Ditto. + * debug.h: Reflect changes to __stdcall. + * shared.h: Ditto. + * winsup.h: Ditto. + +Sat Dec 25 12:09:10 1999 Kazuhiro Fujieda + + * path.cc (symlink): Don't return error if target is a symlink to a + nonexistent file. + +1999-12-23 DJ Delorie + + * dcrt0.cc (globify): Properly handle embedded tildes in variable + names. Treat a c:\foo style path spec as "special", i.e., don't + interpret the backslashes as quoting characters. + +Fri Dec 17 10:49:13 1999 Christopher Faylor + + * path.cc (symlink): Return error if the target exists. + +Thu Dec 16 22:36:45 1999 Christopher Faylor + + * path.cc: Change method for accessing com in windows_device_names to + allow > 2 com ports. + +Thu Dec 16 00:49:30 1999 Christopher Faylor + + * Makefile.in: Only build winver.o and version.o when required. + +Sat Dec 11 11:06:45 1999 Corinna Vinschen + + * path.cc (path_conv::path_conv): Ensure that a trailing slash is added + to "x:" specifications. + +Fri Dec 10 20:22:41 1999 Christopher Faylor + + * debug.cc (WFSO): Make __stdcall. + (WFMO): Ditto. + * debug.h: Reflect above changes. + * exceptions.cc (sig_set_errno): Set errno to be in effect after a + signal handler. + (handle_sigsuspend): Use set_sig_errno to ensure that the correct errno + is set after a signal handler. + (interrupt_now): Accomodate default errno field in stack. + (intterupt_on_return): Ditto. + (sigreturn): Pop, test, and possibly restore saved errno on return from + signal handler. + * fhandler_console.cc (fhandler_console::read): Set errno to be in + effect after a signal handler. + * fhandler_serial.cc (fhandler_serial::raw_read): Ditto. + * select.cc (cygwin_select): Ditto. + (select_stuff:wait): Ditto. + (peek_serial): Ditto. + * syscalls.cc (_read): Ditto. + * wait.cc (wait4): Ditto. + * winsup.h (signal_dispatch): Add "saved_errno" field. + +Thu Dec 9 23:35:45 1999 Christopher Faylor + + * debug.cc (threadname_init): Use new_muto macro to set up a static + buffer for a muto. + (debug_init): Ditto. + (WFSO): Reinstate wrapper for WaitForSingleObject. + (WFMO): Reinstate wrapper for WaitForMultipleObject. + * debug.h: Declare the above two wrappers. + * exceptions.cc (events_init): Use new_muto macro to set up a static + buffer for a muto. + * sigproc.cc (sigproc_init): Ditto. + * sync.cc (muto::acquire): Don't bump waiters if we already own the + muto. + * sync.h (new): New operator. + (delete): Ditto. + (new_muto): New macro. + +Dec 08 23:50:00 1999 Corinna Vinschen + + * security.cc (get_nt_attribute): Add debug output. Correct behaviour + in case of NULL ACL. + * syscalls.cc (stat_worker): Allow remote drives to get stat info from + fh.fstat(). + * include/winnt.h: Add defines for W2K ACL control flags. + * include/cygwin/socket.h: Add missing PF_NETBIOS. + +Wed Dec 8 23:06:07 1999 Christopher Faylor + + * Makefile.in: Ensure that winver.o is a dependency for building the + dll. + * mkvers.sh: Attempt to call windres in a fashion that accomodates + older and newer versions. + * winver.c: Reorganize slightly to accomodate older versions of + windres. + * fhandler.cc (fhandler_disk_file::fstat): Avoid using Windows "inodes" + on disks which do not support them. + +Tue Dec 7 21:15:11 1999 Christopher Faylor + + * dll_init.cc (DllList::forkeeLoadDlls): Reverse order of Free/Load + Library calls to ensure that references are resolved. + * path.cc (mount_info::conv_to_win32_path): Ensure that returned + windows paths are always normalized regardless of whether they were in + windows format to begin with. + +Tue Dec 7 08:48:22 1999 Christopher Faylor + + * environ.cc (parse_options): Properly detect end of known array. + +Mon Dec 6 22:32:04 1999 Christopher Faylor + + * mkvers.sh: Generate winver.o from winver.rc and various other things + from include/cygwin/version.h + * winver.rc: New file (adapted from donation by Mumit Khan + ). + * configure.in: Find windres. + * configure: Regenerate. + * Makefile.in: Link winver.o into cygwin1.dll. + +Mon Dec 6 13:04:47 1999 Mumit Khan + + * init.cc (dynamically_loaded): New global variable. + (dll_entry): Use. + * winsup.h (dynamically_loaded): Declare. + * dcrt0.cc (do_global_ctors): Likewise. + (set_os_type): Make static again. + (dll_crt0_1): Handle dynamically_loaded case. + * dll_init.cc (dll_dllcrt0_1): Delete. + (dll_dllcrt0): Handle dynamically_loaded case. + (dll_noncygwin_dllcrt0): Mark obsolescent. + * libccrt0.cc (cygwin_attach_noncygwin_dll): Delete. + * pinfo.cc (pinfo_init): Don't inherit parent fds if dynamically + loaded. + * include/cygwin/cygwin_dll.h (cygwin_attach_noncygwin_dll): Delete + prototype. + (_cygwin_noncygwin_dll_entry): Mark obsolescent. + +Mon Dec 6 11:09:41 1999 Christopher Faylor + + * configure.in: Make threadsafe the default. + * configure: regenerate. + * utils/strace.cc: Fix a compiler warning. + +Sun Dec 5 15:49:43 1999 Christopher Faylor + + * environ.cc (parse_options): Reinstate unions in parse_things, to + save space. + +Fri Dec 3 22:52:05 1999 Christopher Faylor + + Implement new signal-handling scheme which ensures that a program will + not be interrupted while in a system or cygwin DLL. + * Makefile.in: Add sync.o and dll_ofiles target. + * dcrt0.cc (alloc_stack_hard_way): Add more defensive code to ensure + that the stack is really grown. + (alloc_stack): Ditto. + (dll_crt0_1): Reorganize some initialization routines to ensure that + they occur after the heap has been initialized. + * debug.cc: Use muto for locks. Eliminate attempts to avoid being + interrupted by signals. + (threadname_init): New function. + (debug_init): Ditto. + * debug.h: Declare debug_init and threadname_init. + * exceptions.cc (stack_info::stack_info): Don't check for previous use + of get(). + (handle_sigsuspend): Simply using new signal-handling scheme. + (interruptible): New function. Determines if PC should be interrupted. + (interrupt_now): New function. Causes immediate signal dispatch. + (interrupt_on_return): New function. Causes signal dispatch on return + from cygwin or system routine. + (call_handler): Simplify to use new signal-handling scheme. + (set_process_mask): Use mask_sync muto to synchronize setting of + process signal mask. + (sig_handle_tty_stop): New function. Called when have to stop process + now. + (sig_handle): Simplify to use new signal-handling scheme. + (set_process_mask): Ditto. + (events_init): Allocate mask_sync muto. + (unused_sig_wrapper): New function. Encapsulates assembly language + signal handling support. + * fhandler.h (class select_stuff): Accomodate new signal-handling + scheme. + * fhandler_console.cc (fhandler_console): Simplify to use new + signal-handling scheme. + * fhandler_serial.cc (fhandler_serial::raw_read): Ditto. + * fhandler_termios.cc (bg_check): Ditto. + * fhandler_tty.cc (process_input): Ditto. + (fhandler_tty_slave::open): Ditto. + (fhandler_tty_slave::send_ioctl_request): Ditto. + * fork.cc: Ditto. + * path.cc (chdir): Ditto. + * select.cc: Ditto, throughout. + * shared.h: Eliminate unneeded signal enum. + * signal.cc (signal): Simplify to use new signal-handling scheme. + (sleep): Ditto. + (usleep): Ditto. + (sigprocmask): Ditto. + (sigaction): Ditto. + (pause): Use handle_sigsuspend to pause for signal. + * sigproc.cc: Change signal_arrived handle to global_signal_arrived + class. Change various mutex handles to mutos. + (proc_subproc): Simplify to use new signal-handling scheme. Use muto + for locking. + (get_proc_lock): Ditto. + (proc_terminate): Ditto. + (sig_dispatch_pending): Make a "C" function. Return status of pending + signals. + (sigproc_init): Initialize global_signal_arrived. Simplify to use new + signal-handling scheme. Initialize sync_proc_subproc muto. + (sig_send): Eliminate __SIGSUSPEND considerations. Simplify to use new + signal-handling scheme. + (__allow_sig_dispatch): Delete. + (__block_sig_dispatch): Delete. + (__get_signal_mutex): Delete. + (__release_signal_mutex): Delete. + (__have_signal_mutex): Delete. + (wait_sig): Simplify to use new signal-handling scheme. + * sigproc.h: Implement signal_arrived classes. + * smallprint.c (__small_vsprintf): Avoid printing a leading '*' in + function name with %F format. + * spawn.cc (spawn_guts): Simplify to use new signal-handling scheme. + (iscmd): Don't consider a filename to be a "command" unless it contains + a ':'. + * syscalls.cc (_read): Ditto. + (_open): Ditto. + (_close): Ditto. + * termios.cc (tcsendbreak): Ditto. + (tcdrain): Ditto. + (tcflush): Ditto. + (tcflow): Ditto. + (tcsetattr): Ditto. + (tcgetattr): Ditto. + * winsup.h: Reorganize include files. Add preliminary __sig_protect + implementation. + * cygwin/version.h: Bump current version to 1.1.0. + +Thu Dec 2 22:19:40 1999 Christopher Faylor + + * sync.cc (muto::muto): Use an event rather than a semaphore for wait + synchronization. + (muto::acquire): Rewrite to use an event and try to remove races. + (muto::release): Ditto. + +1999-12-02 DJ Delorie + + * environ.cc (parse_options): switch to a static initializer; + templates are sensitive to g++ bugs. + +Fri Nov 26 12:04:23 1999 Christopher Faylor + + * net.cc (cygwin_bind): Ensure that non-Unix domain socket operations + return success correctly. + +Wed Nov 24 21:37:58 1999 Christopher Faylor + + * net.cc (cygwin_bind): Guard against incorrectly setting res to zero + when there is an error condition. + +Tue Nov 23 17:49:55 1999 Christopher Faylor + + * fhandler.cc (fhandler_base::fhandler_base): Use better initialization + scheme. + * fork.cc (stack_base): Eliminate unneeded asm stuff. + * select.cc: Sprinkle in some comments. + * include/winnt.h: Add more CONTEXT. + +Nov 23 20:51:00 1999 Corinna Vinschen + + * net.cc (cygwin_bind): Use struct sockaddr_un in AF_UNIX code. Set + errno to ENAMETOOLONG if length of pathname exceeds limit in AF_UNIX + code. Sets errno to EADDRINUSE in AF_UNIX code if file system socket + object already exists. + * syscalls.cc (setsid): Set errno to EPERM if current process is + already process group leader. + * uinfo.cc (internal_getlogin): Rearrange for better debug output. Set + pi->psid to NULL if SID can't be determined. + * include/cygwin/socket.h: Add AF_LOCAL and PF_LOCAL + (same as AF_UNIX) for POSIX compatibility. + * include/sys/un.h: Add UNIX_PATH_LEN define. Added SUN_LEN macro for + POSIX compatibility. + +Sun Nov 21 22:55:04 1999 Christopher Faylor + + * environ.cc (parse_options): Return immediately after dealing with + NULL argument. Don't try to process it. + +Tue Nov 16 23:29:17 1999 Christopher Faylor + + * signal.cc (kill_worker): Guard against NULL dereference when thread + safe. + +Sat Oct 30 00:59:38 1999 Christopher Faylor + + * Makefile.in: Some general cleanup. + * smallprint.c (__small_vsprintf): Accomodate new format for + __PRETTY_FUNCTION__. + +Wed Oct 27 16:13:36 1999 Christopher Faylor + + * path.cc (mount_info::from_registry): Don't allow the same posix path + into the mount table more than once. + * utils/mount.cc (main): Add some orthogonality to the options. + +Tue Oct 26 21:55:49 1999 Christopher Faylor + + * environ.cc (environ_init): Turn off ntsec by default. + +Wed Oct 27 00:14:11 1999 J"orn Rennecke + + * fhandler.cc (fhandler_base::lseek): Take readahead into account. + +Tue Oct 26 16:46:54 1999 Christopher Faylor + + * syscalls.cc (_unlink): Return EISDIR when attempting to unlink a + directory. + +Mon Oct 25 18:05:23 1999 Christopher Faylor + + * fhandler.cc (fhandler_base::read): Fix previous fix. + +Mon Oct 25 13:46:44 1999 Christopher Faylor + + * dll_init.cc (add): Avoid allocating name for "LINK"ed DLLs. + (DllList::forkeeLoadDlls): Only reload DLLs if they have been + dlopen'ed. + * grp.cc (parse_grp): Assign gr_mem when it is determined. + +Sun Oct 24 21:55:48 1999 Christopher Faylor + + * dll_init.cc (struct dll): Add module name. + (add): Add additional 'name' parameter for recording in dll structure. + (reserve_upto): New function. + (release_upto): Ditto. + (DllList::forkeeLoadedDlls): Ditto. + (DllList::forkeeStartLoadDlls): Remove. + (DllList::forkeeEndLoadedDlls): Ditto. + (DllNameIterator::*): Eliminate class. + (LinkedDllNameIterator::*): Ditto. + * dll_init.h: Reflect above changes. + * fork.cc (fork): Don't generate a list of dlls to load in the parent. + Let the child do it. Use new DllList::forkeeLoadDlls to load DLLs. + * smallprint.c (__small_vsprintf): No need for a sign on a Win32 error. + (small_printf): Move function here from strace(). + * strace.cc (small_printf): Move to smallprint.c + * include/sys/strace.h: Always declare small_printf. + +Sun Oct 24 02:22:13 1999 Christopher Faylor + + * fhandler.cc (fhandler_base::read): Work around C bug. + +Tue Oct 19 22:10:21 1999 Christopher Faylor + + * dll_init.cc: Add some external symbols to allow thread-safe + compilation. + +Tue Oct 19 21:09:42 1999 Christopher Faylor + + Make minor changes throughout to accomodate new gcc merge. + * Makefile.in: Remvoe -fpermissive option when compiling using g++. + * dcrt0.cc (noload): Mark as "unused" to avoid a compiler warning. + * exceptions.cc (sigreturn): Make this "extern" since it essentially + *is* extern. + * fork.cc (sync_with_parent): Modify to cause the macro to be + considered void. + * heap.cc (sbrk): Remove debugging code. + * passwd.cc (getpass): Don't use fprintf to print the prompt. + * path.cc (mount_info::conv_to_win32_path): Accomodate compiler + warning. + * select.cc (cygwin_select): Experimental version of select which + handles fd_sets with non-standard FD_SETSIZE. + (select_stuff::wait): Ditto. + * termios.cc (tcgetattr): Avoid a compiler warning. + (cftospeed): Ditto. + (cftispeed): Ditto. + * uinfo.cc (netapi32_init): Ditto. + * winsup.h (api_fatal): Simplify and avoid a compiler warning. + * include/sys/strace.h (system_printf): Ditto. + (strace_printf_wrap): Modify to cause the macro to be considered void. + (strace_printf_wrap1): Ditto. + +1999-10-19 DJ Delorie + + * Makefile.in (.cc.o): add -fpermissive to avoid g++'s conformance + madness. + * environ.cc (_findenv): rename to my_findenv to avoid newlib + prototype. + * syscalls.cc (logout): remove braces around _PATH_UTMP + +Sat Oct 16 22:53:02 1999 Christopher Faylor + + * path.cc (mount_info::cygdrive_posix_path): Properly terminate string + after Oct 11 change below. + +Fri Oct 15 23:02:39 1999 Christopher Faylor + + * exceptions.cc (stack_info): Reimplement stack handling routines in + new stack_info class. + (stack_info::brute_force): Just fill out the same structure as + StackWalk. + (stack_info::walk): Just fill out stack info. + (stack): Use stack_info class stuff to iterate over and display the + stack. + +Fri Oct 15 00:32:13 1999 Christopher Faylor + + * include/cygwin/version.h: Bump some versions. + +Oct 5 11:45:00 1999 Corinna Vinschen + + * dcrt0.cc (dll_crt0_1): Delete calls to get_WHOEVER_sid. Move call to + uinfo_init() to the end of the function. + * fhandler.cc (get_file_owner): Substitute call to get_id_from_sid() + with call to get_uid_from_sid(). + (get_file_group): Substitute call to get_id_from_sid() with call to + get_gid_from_sid(). + * fork.cc (fork): Copy new pinfo members to child. + * grp.cc (parse_grp): Rewritten. Saves gr_passwd and all user names in + gr_mem. + (read_etc_group): Variable `group_sem' avoids endless loop. + * passwd.cc (read_etc_passwd): Variable `passwd_sem' avoids endless + loop. + * security.cc (get_sid): New function to generate SID from int values. + (get_ssid): New function to generate SID from string. + (get_pw_sid): New function to generate SID from pw_gecos entry. + (get_gr_sid): New function to generate SID from gr_passwd entry. + (get_admin_sid): Rewritten to avoid using heap space. + (get_system_sid): Ditto. + (get_creator_owner_sid): Ditto. + (get_world_sid): Ditto. + (get_id_from_sid): Try to read SIDs from /etc/passwd or /etc/group + files before using RID or Lookup... function. + (legal_sid_type): New function. + (lookup_name): Rewritten to use the logon server info, if any. + (alloc_sd): Try to use SID from /etc/passwd and /etc/group files before + call to lookup_name(). + (alloc_sd): New parameter for logon server. + (set_nt_attribute): Ditto. + (set_file_attribute): Ditto. + * shared.cc (sec_user): If SID is saved in myself, use it instead of + calling lookup_name(). + * shared.h: struct pinfo got extended user information. + * spawn.cc (spawn_guts): method for forcing reread /etc files changed. + (_spawnve): Copy new pinfo members to child. + * syscalls.cc (chown): Change call to set_file_attribute(). + (chmod): Ditto. + * uinfo.cc (internal_getlogin): New function. + (uinfo_init): Calls internal_getlogin() now. + (getlogin): Uses myself->username now. + * winsup.h: extern HANDLE netapi32_handle; Change prototypes for + set_file_attribute(), lookup_name(), get_id_from_sid(). New inline + functions get_uid_from_sid() and get_gid_from_sid(). + * utils/mkgroup.c: Adapt to the new ntsec features. + * utils/mkpasswd.c: Ditto. + +Thu Oct 14 23:46:03 1999 Christopher Faylor + + Replace calls to GetCurrentProcess() with hMainProc throughout. + * autoload.h: Implement LoadDLLinitnow() function to force the loading + of a DLL. + * cygwin.din: Export cygwin_stackdump. + * dcrt0.cc (dll_crt0): Set up hMainProc and hMainThread here. + * dll_init.cc (dll_dllcrt0_1): Ditto. + * environ.cc (parse_options): New "oldstack" option for forcing the use + of the old stack walking code. + * exceptions.cc (signals_init): Remove. + (err_printf): Remove. Use small_printf throughout. + (sfta): New helper function for StackWalk. + (sgmb): Ditto. + (stack_brute_force): Renamed from old stack walk function. Now uses + frame pointer from context handler. + (stack_walk): New function. Uses Windows API to walk the stack. + (stack): Reimplement to attempt to load imagehlp.dll. If this succeeds + use stack_walk() to display stack info, otherwise use + stack_brute_force. + (cygwin_stackdump): Temporary (?) function for displaying a stack dump + from the called location. + (stackdump): Accept new parameters for passing to stack(). + (handle_exceptions): Call stackdump with new parameters needed to walk + the stack. + * fhandler.cc (fhandler_base::read): Fix potential buffer overrun. Fix + end of buffer problems when \r is not followed by a \n. + (fhandler_base::lseek): Avoid flushing read ahead when not moving the + file pointer. + * fhandler_termios.cc (fhandler_termios::set_ctty): Add a debugging + statement. + * sigproc.cc (sigproc_init): Eliminate obsolete signals_init function. + * winsup.h: Add some declarations. + +Wed Oct 13 09:02:32 1999 Kazuhiro Fujieda + + * path.cc (readlink): Return errno correctly when it can't find the + target symlink. + +Tue Oct 12 13:02:08 1999 Christopher Faylor + + * syscalls.cc (setsid): Only reset sid/pgid when NOT process group + leader. + * tty.cc (tty_list::allocate_tty): Don't set sid to myself. The first + tty open should do that. + +Mon Oct 11 23:13:29 1999 Christopher Faylor + + * dcrt0.cc (noload): Issue appropriate Windows error. + * fhandler_termios.cc (fhandler_termios::ctty): Don't automatically set + sid, etc., unless the current pid associated with the tty's sid does + not exist. + * path.cc (mount_info::cygdrive_posix_path): Avoid copying beyond the + end of buffer or suffer garbage. + * pinfo.cc (pinfo_init): Restore sid behavior of a year ago. The sid + should be the same as the pid to be equivalent to UNIX. + (pinfo_list::operator []): Add more bounds checking. + +Sun Oct 10 14:08:30 1999 Christopher Faylor + + * select.cc (select): Return error if n > FD_SETSIZE. This is a + temporary fix. + +Sun Oct 10 13:56:14 1999 Christopher Faylor + + * path.cc (iscygdrive_device): Be more precise in detecting when a + "cygdrive" device. This should allow 'mkdir -p' to work correctly. + +Fri Oct 08 08:55:31 1999 Kazuhiro Fujieda + + * path.cc (symlink_check_one): set errno to EINVAL on socket files + same as normal files. + +1999-10-06 DJ Delorie + + * include/oaidl.h (IDispatch.GetIDsOfNames): Use DISPID* not DISPID + +1999-10-06 DJ Delorie + + * exceptions.cc (err_printf): new function; print to stderr + without strace's clutter. The stacktrace functions use this, so + the stacktrace files should be cleaner. + (exception): Print segment registers also + (stack): include a peek at the function's arguments + +Tue Oct 5 16:33:17 1999 Christopher Faylor + + * hinfo.cc (hinfo::extend): Eliminate inappropriate test for boundary + condition. + +1999-10-04 DJ Delorie + + * config/i386/longjmp.c: don't restore %fs (Paul Sokolovsky + ) + +1999-10-04 DJ Delorie + + * localtime.c (tzsetwall): Handle Asian Windows strings correctly + (from Kazuhiro Fujieda ). + +Sat Oct 2 23:00:00 1999 Corinna Vinschen + + * include/lm*.h: Correct multiple problems in lan manager + header files. + +Sun Oct 3 14:29:53 1999 Christopher Faylor + + * sysdef/imagehlp.def: New file. Definitions for imagehlp.dll. + * include/imagehlp.h: Ditto. + * include/winbase.h: YA missing structure. + +Fri Oct 1 11:16:00 Corinna Vinschen + + * security.cc (alloc_sd): Correct setting of FILE_DELETE_CHILD. + (get_file_attribute): Read ntea attributes only if ntsec is disabled. + * syscalls.cc (_unlink): Don't queue file into delqueue if DeleteFile + returns ERROR_ACCESS_DENIED. + +1999-09-30 Mumit Khan + + * init.cc (dll_entry): Remove static_load case. + * dcrt0.c (set_os_type): Make it externally visible. + * dll_init.cc (dll_dllcrt0_1): Update noncygwin initialization for + post-b20.1 code. + +1999-09-30 DJ Delorie + + * times.cc: declare _timezone and _daylight properly + +Wed Sep 29 23:57:40 1999 Christopher Faylor + + * dcrt0.cc (do_exit): Remove EXIT_SIGNAL mask when exiting. It is not + correct given changes to really_exit. + * select.cc (peek_serial): Work around apparent Windows bug. + +1999-09-29 Norbert Schulze + + * times.cc (timezone): revert 'return TZ if set' patch. + * times.cc (timezone): uses now tzset() and _timezone. + * times.cc (gettimeofday): ditto. + * localtime.c (tzsetwall): no negative minutes if offset is negativ. + * localtime.c (tzsetwall): minutes place holder was missing if + minutes == 0 and seconds !=0 (h:0:s). + * localtime.c (tzsetwall): if timezone has no daylight saving + (tz.StandardDate.wMonth==0) generate no daylight saving parameters. + +Sat Sep 25 15:11:04 1999 Christopher Faylor + + * fhandler_termios.cc (fhandler_termios::bg_check): Accept a new + argument to control whether we should worry about blocking signals. + * fhandler.h: Ditto. + * syscalls.cc (read_handler): Accept a new argument for passing to + bg_check. + (read): Inform read_handler if signals are blocked or not. + * termios.cc: Throughout, reorganize to always block signals before + calling bg_check. + +Sat Sep 25 13:36:06 1999 Christopher Faylor + + * fhandler.h (fhandler_termios::line_edit): Add an extra argument. + * fhandler_serial.cc (fhandler_serial::open): Maintain consisten + fAbortOnError state. + * fhandler_termios.cc (fhandler_termios::line_edit): Use new + "always_accept" argument to control whether input_done is set + regardless of canonical state. + * fork.cc (vfork): Duplicate "parent's" fd table. + * hinfo.cc (hinfo::dup_worker): New method. + (dup2): Use new dup_worker method. + (hinfo::fixup_after_fork): Lock dtable prior to operating on it. + (hinfo::vfork_child_dup): New method. Duplicates dtable for vfork. + (hinfo::vfork_parent_restore): New method. Restores dtable when vfork + exits. + * net.cc (set_winsock_errno): Make global. + * pipe.cc (pipe): Default mode to binary unless *explicitly* set to + text. + * select.cc (set_bits): Test that {read,write,except}_selected are + active before setting a bit. + (peek_pipe): Short circuit tests if we're not checking for readable + or "except"able handles. + (thread_socket): Use read check for exitsock as old method relied on + undocumented, unreliable behavior. + (start_thread_socket): Perform more setup on exitsock to improve thread + exit signalling. + (socket_cleanup): Connect to the exitsock to force thread_socket thread + exit. + * winsup.h (hinfo): Add preliminary vfork stuff. + * include/winsock.h: Add shutdown() how types. + * include/sys/socket.h: Add socketpair declaration. + +1999-09-22 DJ Delorie + + * syscalls.cc (chown): never return ENOSYS - just pretend it + works. + +Wed Sep 22 00:47:56 1999 Christopher Faylor + + * select.cc (MAKEready): Need to initialize 'fd' or open tests in + peek fail. + +Mon Sep 20 17:07:37 1999 Christopher Faylor + + * smallprint.c (__small_vsprintf): Fix '%+' handling. + +Thu Sep 16 21:48:13 1999 Christopher Faylor + + * utils/cygcheck.cc (dump_sysinfo): Deal with a new compiler error. + * utils/strace.cc (make_command_line): Change to a void * argument, as + is required for SetConsoleCtrlHandler. + +Thu Sep 16 20:47:12 1999 Christopher Faylor + + * dcrt0.cc (__api_fatal): Rearrange slightly. + * fhandler.h (set_ctty): Change to void. + * fhandler_termios.cc (fhandler_termios::set_ctty): Ditto. + * select.cc (thread_pipe): Change to a void * argument, as is required + for thread functions. + (thread_socket): Ditto. + (thread_serial): Ditto. + * include/winbase.h: Mark ExitProcess as noexit. + +Thu Sep 16 18:32:12 1999 Christopher Faylor + + * exceptions.cc (ctrl_c_handler): Make WINAPI, as required by + SetConsoleCtrlHandler. + +Thu Sep 16 17:48:05 1999 Christopher Faylor + + * debug.cc (thread_stub): Make WINAPI, as required by CreateThread. + * fhandler_tty.cc (process_input): Ditto. + (process_output): Ditto. + (process_ioctl): Ditto. + * select.cc (thread_pipe): Ditto. + (thread_serial): Ditto. + (thread_socket): Ditto. + * sigproc.cc (wait_proc): Ditto. + (wait_sig): Ditto. + * window.cc (winMain): Ditto. + +Wed Sep 15 20:58:37 1999 Christopher Faylor + + * exceptions.cc (call_handler): Let fatal signals through regardless of + signal_mutex. + * fhandler.h (fhandler_base): Make bg_check virtual. + (fhandler_termios::bg_check): Eliminate the second argument. + * fhandler_console.cc (fhandler_console::ioctl): Check for background + operation. + * fhandler_termios.cc (fhandler_termios::bg_check): Eliminate the + second argument. A negative arg 1 means the same thing. + * ioctl.cc (ioctl): Add debugging output. + * syscalls.cc (_write): Eliminate second argument to bg_check. + * termios.cc (tcsendbreak): Check for background operation. + (tcdrain): Ditto. + (tcflush): Ditto. + (tcflow): Ditto. + (tcsetattr): Reorganize on similar lines to above routine. + +Wed Sep 15 15:25:04 1999 Christopher Faylor + + * select.cc (peek_pipe): Only set read_ready if bg_check returns <= 0. + (peek_console): Ditto. Correct PeekConsole conditional so that the for + loop breaks eventually. + +Wed Sep 15 00:21:40 1999 Christopher Faylor + + * exceptions.cc (set_console_handler): Allocate security stuff here + since it is needed earlier in the process now. Allocate a shared event + for use in synchronizing CTRL-C events that happen while the process is + still initializing. + (ctrl_c_handler): Use the above event to synchronize with the cygwin + startup process, waiting for the signal thread to come alive before + trying to send a signal. + (signals_init): Don't call set_console_handler() here, since it is now + handled much earlier in cygwin initialization. + * shared.cc (shared_init): Move out security setup. + * sigproc.cc (wait_sig): Activate the console_handler_thread_waiter so + that any waiting thread which is handling ctrl-c's will wake up and + send a signal, if appropriate. + +Tue Sep 14 23:49:39 1999 Christopher Faylor + + * exceptions.cc (ctrl_c_handler): Handle ctrl-c events ourself, using + the "UNIX way". + * fhandler_console (tty_list::get_tty): New function. + * shared.h: Add some additional things to tty_min class for handling + ctrl-c. + +1999-09-14 DJ Delorie + + * dir.cc (rmdir): return ENOTDIR for regular files on 9x + +Tue Sep 14 00:01:59 1999 Christopher Faylor + + * debug.h (ForceCloseHandle2): New macro. + * fhandler.cc (set_inheritance): Accept name of handle as optional + third argument. Use this in ForceCloseHandle2/ProtecHandle2. + * fhandler.h: Implement bg_check() method. + * fhandler_console.cc (get_tty_stuff): Initialize more tty stuff. + (fhandler_console::read): Check for background read. + * fhandler_termios.cc (fhandler_termios::bg_check): New function. + Performs appropriate action given background read or write. + * fhandler_tty.cc (fhandler_tty_slave::write): Replace background check + code with new method. + (fhandler_tty_slave::read): Ditto. + (fhandler_tty_common::set_close_on_exec): Pass output_mutex name to + set_inheritance. + * select.cc: Throughout check that the fd is still open before polling. + (peek_pipe): Check for background read. + (peek_console): Ditto. + * shared.h: Move ntty from tty into tty_min. + * syscalls.cc (read_handler): Check for background read. + (_write): Check for background write. + +Sat Sep 11 16:24:21 1999 Christopher Faylor + + * path.cc (iscygdrive_device): New macro. + (mount_info::conv_to_win32_path): Only attempt "cygdrive" translation + when passed /cygdrive/something. + (mount_info::write_cygdrive_info_to_registry): Store in-memory copy of + cygdrive prefix automatically. + (mount_info::read_cygdrive_info_from_registry): Reorganize for new + write_cygdrive_info_to_registry functionality. + (mount): Ditto. + +Fri Sep 10 15:44:11 1999 Christopher Faylor + + * syscalls.cc (pathconf): Make first arg 'const'. + +1999-09-10 DJ Delorie + + * exec.cc (_execve): check for an empty environment + +Wed Sep 8 10:24:12 1999 Christopher Faylor + + * dcrt0.cc (dll_crt0_1): Generalize test for initial zeroes in + exec/fork block. + * fhandler.cc (fhandler_disk_file::open): Don't attempt #! detection on + non-disk files. + * fhandler.h: Use generic status bit set/clear macros. Use bitmask for + fhandler_termios state. + * fhandler_console.cc: Rename "tty_stuff" to more descriptive + "shared_console_info". + (fhandler_console::read): Reset console state before a read if + appropriate. + (fhandler_console::open): Improve check for setting console state. + (fhandler_console::fixup_after_fork): Ditto. + (set_console_state_for_spawn): New function. + * fhandler_termios.cc (fhandler_termios::tcinit): Use new method for + determining if initialized. + * fhandler_tty.cc (fhandler_tty::init_console): Avoid sending handle to + init or it will be closed. + * fork.cc (per_thread::set): Make this method non-inline, temporarily. + * select.cc (peek_console): Call set_input_state to ensure that the + console is in the correct state. + * shared.h (child_info): Make zero element an array for future + tweaking. + (tty_min): Change initialized element to a bit field. Define bit field + macros for manipulating it. + * sigproc.cc (wait_sig): Wake up every half second in a (vain?) attempt + to work around Windows 98 hanging problem. + (wait_subproc): Ditto. + * spawn.cc (spawn_guts): Use new "set_console_state_for_spawn" prior to + starting a process. + * winsup.h: Define generic macros for manipulating a method's status + field. + (per_thread): Move inline method to fork. + +Mon Sep 6 13:36:34 1999 Christopher Faylor + + * fhandler_tty.cc (fhandler_tty_master::init_console): Remove retrieval + of stderr handle since it is not required for correct init operation. + * hinfo.cc (hinfo_init): Reorganize to accomodate potential closing of + console handles by fhandler_console::init. + (init_std_file_from_handle): Set standard handle as appropriate. + (hinfo::de_linearize_fd_arry): Ditto. + * fhandler_console.cc (fhandler_console::init): Conditionally close + handle only if it is valid. + +Sun Sep 5 22:43:21 1999 Christopher Faylor + + * utils/cygcheck.cc: Make sure that GetDiskFreeSpaceExA is defined as a + __stdcall function or the stack will suffer. For now, don't sort mount + output as more work copying the individual mntent elements is required. + +Sat Sep 4 19:01:00 1999 Christopher Faylor + + * include/glob.h: Ensure that glob*() functions can be properly accessed by + programs using the DLL. + +Sat Sep 4 18:49:04 1999 Christopher Faylor + + * heap.cc (heap_init): Tweak debugging output. + * sigproc.cc (sig_send): Catch obvious impossible values from + GetLastError. + +Sat Sep 4 18:43:49 1999 Christopher Faylor + + * fhandler_tty.cc (fhandler_tty_slave::open): Protect against signal + dispatch. + (fhandler_tty_slave::write): Only wait a fixed amount of time to + receive a an output_done_event. + (fhandler_tty_slave::tcflush): Protect against signal dispatch. + +Sat Sep 4 18:30:42 1999 Christopher Faylor + + * exceptions.cc (handle_sig): Temporarily remove OutputDebugString. It + seemed to be causing sporadic hangs. + (call_handler): Save and restore di and si. + (sigreturn): Ditto. + +Fri Sep 3 23:07:44 1999 Christopher Faylor + + * fhandler_termios.cc (fhandler_termios::line_edit): Properly deal with + sending characters to slave when !iscanon. + +Fri Sep 3 18:15:00 1999 Corinna Vinschen + + * fhandler_raw.cc (fhandler_dev_raw::fstat): Add S_ISCHR to mode bits. + * fhandler_tape.cc (fhandler_dev_tape::fstat): Erase setting of S_ISCHR + since it's set in fhandler_dev_raw::fstat now. + +Thu Sep 2 22:11:03 1999 Christopher Faylor + + * path.cc (mount_info::conv_to_win32_path): Fix problem with + calculating relative path at root. + +Wed Sep 1 23:24:43 1999 Christopher Faylor + + * fhandler.cc (fhandler_base::fhandler_base): Don't use default binmode + for console. + +Wed Sep 1 20:51:05 1999 Christopher Faylor + + * smallprint.c (__small_vsprintf): Allow field width argument with 'l' + modifier. Consolidate processing of field width. + * uname.cc (uname): Eliminate space in "release" field. + +Tue Aug 24 10:46:24 1999 Kazuhiro Fujieda + + * fhandler_console.cc (write_normal): Write '\n' corresponding to + DWN if the cursor is out of the window. + +Wed Aug 25 22:16:46 1999 Christopher Faylor + + * smallprint.c (rn): Deal with positive as well as negative signs. + (__small_vprintf): Handle '+', 'l', and '%' format types. + +Wed Aug 25 00:38:49 1999 Christopher Faylor + + * dcrt0.cc (dll_crt0_1): Zero heap information in user_data to + work around mutant startup code. + +Tue Aug 24 00:03:22 1999 Christopher Faylor + + * sigproc.cc (sig_send): One more end-of-process race detection. + +Mon Aug 23 21:37:07 1999 Christopher Faylor + + Throughout, remove malloc.h. + * debug.cc: Initialize handle list so that it will not be copied on + fork. + * exceptions.cc (_sigreturn): Zero windows error on exit. It's + meaningless after a signal dispatch. + * fhandler_console.cc (fhandler_console::de_linearize): Improve error + messages. + * shared.h: Increment fork magic number. + * sigproc.cc (sigproc_terminate): Close all handles prior to calling + proc_terminate if running in signal thread. + (sig_send): Eliminate bogus ResetEvent on a semaphore. Add code for + potentially dealing with problems when this code is interrupted via a + signal dispatch. + * times.cc (timezone): Use __small_sprintf. + * uname.cc (uname): Ditto. Also use strcpy instead of sprintf where + appropriate. + +1999-08-23 DJ Delorie + + * localtime.c: export timezone, daylight, tzname as _* + * times.cc: don't export timezone, daylight, tzname + (timezone): return TZ if set. + (cygwin_tzset): not needed. + +Thu Aug 19 13:46:47 1999 Christopher Faylor + + * fork.cc (fork): Remove pinfo lock. It is in allocate_pid, now. + * spawn.cc (_spawnve): Ditto. + * pinfo.cc (pinfo_init): Ditto. + (lock_pinfo_for_update): Impreove debug output. + (pinfo_list::allocate_pid): Lock pinfo mutex here. + +1999-08-19 DJ Delorie + + * Makefile.in (tooldir): If we're building natively, drop the + $(target_alias) on include and lib's install (i.e. /usr/include + instead of /usr/include/i686-cygwin). + +Thu Aug 19 01:11:25 1999 Christopher Faylor + + * sigproc.cc (sig_send): Avoid a race with proc thread when executing + due to a signal. + +Wed Aug 18 16:37:59 1999 Kazuhiro Fujieda + + * fhandler_console (fhandler_console::fillin_info): Avoid setting + scroll_region.Bottom when it is not known. + (fhandler_console::write_normal): Add various fixes for console + scrolling. + +Wed Aug 18 16:18:22 1999 Christopher Faylor + + * sigproc.cc: Add more precise end-of-process detection. + +Wed Aug 18 00:03:47 1999 Christopher Faylor + + * sigproc.cc (sig_send): Work around apparent Windows bug which + occasionally results in bogus error messages when a signal is + dispatched. + +1999-08-17 DJ Delorie + + * localtime.c (tzsetwall): Deduce TZ more accurately. + +Tue Aug 17 18:00:03 1999 Christopher Faylor + + * select.cc (peek_pipe): Correct detection of process group for + backgrounded processes. + +Tue Aug 17 10:24:49 1999 Christopher Faylor + + * include/winnt.h: Fix typo in IMAGE_FIRST_SECTION definition. + +Sun Aug 15 19:11:49 1999 Mumit Khan + + * gcrt0.c (__eprol): Avoid namespace pollution. + (_monstartup): Turn into a constructor function and prevent multiple + invocations. + +Mon Aug 16 10:03:00 Corinna Vinschen + + * utils/mkgroup.c: Correct call to LookupAccountSid for retrieval of + 'None'. + +Mon Aug 16 00:24:29 1999 Christopher Faylor + + * debug.cc (locker): Improve signal mutex locking. + * exceptions.cc (sig_handle): Pass STOP signals to call_handler to + ensure honoring of signal_mutex. + (call_handler): Move STOP code here after acquistion of signal_mutex. + * fhandler_tty.cc (fhandler_tty_common::__acquire_output_mutex): Track + lockers for debugging. + (fhandler_tty_common::__release_output_mutex): Ditto. + (fhandler_slave::write): Fix faulty signal blocking code. + * fork.cc (fork_copy): Remove ancient if 0. + (fork): Conditionalize "FORKDEBUG" under DEBUGGING. + * sigproc.cc (proc_terminate): Reduce pinfo lock time. + (sigproc_terminate): Set sig_loop_wait after getting signal_mutex. + (__get_signal_mutex): Reorganize for less strace output when not + DEBUGGING. + (__release_signal_mutex): Ditto. Reorganize case where !sig_loop_wait. + (have_signal_mutex): Returns true if current thread has the mutex. + * wait.cc (wait4): Change debugging message. + +Sat Aug 14 0:10:00 Corinna Vinschen + + * fhandler.cc (fhandler_base::raw_read): Set correct errno from Win32 + error when ReadFile fails. + (fhandler_base::raw_write): In case of ERROR_DISK_FULL, return + bytes_written only if bytes_written > 0. + * errno.cc: Map ERROR_DISK_FULL to ENOSPC. + +Fri Aug 13 14:22:12 1999 Christopher Faylor + + * select.cc (peek_pipe): Honor ignra argument. + +Fri Aug 13 00:45:00 1999 Christopher Faylor + + * spawn.cc (spawn_guts): Ensure that hExeced is set to proper state + when parent has exited. + +Thu Aug 12 14:09:30 1999 Christopher Faylor + + * sigproc.cc (getsem): Fix typo which prevented sending signals to + other processes. + +Wed Aug 11 22:06:33 1999 Christopher Faylor + + * cygwin.din: Export glob and globfree. + * glob.h: Move to include. + * Makefile.in: Correct glob.h dependencies. + +Wed Aug 11 19:41:04 1999 Sergey Okhapkin + + * fhandler.cc (fhandler_disk_file::fstat): Check if the file is unix + domain socket. + (fhandler_disk_file::open): Call set_socket_p(). + * fhandler.h: Add new fhandler type flags (FH_LOCAL, FH_FIFO). + (fhandler_base): get/set_socket_p - new member functions. + (fhandler_socket::addr_family): Add new member, currently unused. + (fhandler_socket::get/set_addr_family): Add new functions to access + addr_family. + * include/sys/un.h: New file. + * net.cc: Include + (cygwin_socket): Always create socket of AF_INET family, store + argument's family. + (get_inet_addr): New static function. Converts AF_UNIX requests into + corresponding AF_INET requests. + (cygwin_sendto): Use get_inet_addr(). + (cygwin_connect): Likewise. + (cygwin_accept): Check for sockaddr length. + (cygwin_bind): Implement AF_UNIX. + * path.h (PATH_SOCKET): Add new enum value. + (path_conv::issocket): Add new member function. + (SOCKET_COOKIE): Add new define. + * syscalls.cc (chmod): Mark socket files with system file attribute. + +Wed Aug 11 17:22:46 1999 Corinna Vinschen + + * utils/mkgroup.c (main): Generate "None" group when + invoked via mkgroup -l. + +Tue Aug 10 21:30:31 1999 Christopher Faylor + + * select.cc (peek_pipe): Handle type ahead where appropriate. + * sigproc.cc (proc_can_be_signalled): Revert to previous method for + determining signalability. + (getsem): Move PID_INITIALIZING test here. + * wait.cc (wait4): Improve debug output slightly. + +Mon Aug 9 23:27:44 1999 Christopher Faylor + + * dcrt0.cc (do_exit): Add additional check for valid hExeced. + * exceptions.cc (call_handler): Implement a raceless way to track + pending_signals. + * signal.cc (kill_worker): Make calls from non-main threads synchronous + or signals from a tty thread don't work right. + * sigproc.cc (sig_send): Localize pending_signals assignment to only + the wait_sig thread. + (__get_signal_mutex): Don't attempt to grab a mutex if signal_mutex + hasn't been assigned yet. Add more strace debugging information when + -DDEBUGGING. + (__release_signal_mutex): Don't attempt to release a mutex if + signal_mutex hasn't been assigned yet. Add more strace debugging + output. + (wait_sig): Attempt to eliminate race in setting of pending_signals. + * spawn.cc (spawn_guts): Set hExeced to INVALID_HANDLE_VALUE so that it + will be obvious when a process is actually just an execed stub. + * strace.cc (strace_vsprintf): Output a "!" after the pid when + executing in an execed stub. + +Mon Aug 9 17:17:13 1999 Christopher Faylor + + Throughout, eliminate in() and out() macros. + * winsup.h (tty_attached): Accept an argument indicating the pinfo + structure to query. + * exceptions.cc (really_exit): Cosmetic change. + * external.cc (fillout_pinfo): Use queried pinfo structure for + determining tty number, not *our* number. + * net.cc: More workarounds. + * path.cc (get_device_number): Supply argument to tty_attached. + * syscalls.cc (ctermid): Ditto. + * strace.cc (strace_dump): Remove. + * include/sys/strace.h: Eliminate obsolete stuff. + +Sun Aug 8 22:54:45 1999 Christopher Faylor + + * exceptions.cc (call_handler): Process all signals on return from a + signal dispatch. + * sigproc.cc (proc_can_be_signalled): Guard against waiting too long + when exiting. + (proc_exists): Don't report an exited process as "existing". + (proc_terminate): Close handle prior to testing for existence so that + proc_exists will not always return TRUE. Eliminate use of zap_subproc. + (stopped_or_terminated): Eliminate use of zap_subproc. + (zap_subproc): Delete. + +Sun Aug 8 22:17:36 1999 Christopher Faylor + + * fhandler_tty.cc (fhandler_tty_master::init): hThread must remain + open. Previous change to close it was wrong. + +Sun Aug 8 20:35:33 1999 Christopher Faylor + + * exceptions.cc: Initalize NO_COPY variables. + * pinfo.cc (record_death): Don't be so insistent about getting + the pinfo lock. + * sigproc.cc (proc_terminate): Tighten the region protected by + the pinfo lock. + * spawn.cc (spawn_guts): Eliminate the pinfo lock when reparenting + as it is no longer required. + (_spawnve): Tighten the region protected by the pinfo lock. + +Sun Aug 8 18:26:51 1999 Christopher Faylor + + * sigproc.cc (sig_send): Add more unfortunate guards against a + system call being interrupted by a signal dispatch. + +Sat Aug 7 15:38:42 1999 Christopher Faylor + + * security.cc (get_admin_sid): Ensure that returned buf is not copied + on a fork. + (get_system_sid): Ditto. + (get_create_owner_sid): Ditto. + (get_world_sid): Ditto. + +Sat Aug 7 15:17:25 1999 Christopher Faylor + + * fhandler_tty.cc (process_input): Reset signal_arrived event prior to + calling console read as this is now a requirement for functions which + detect signal_arrived. + (fhandler_tty_master::write): Allow signals to operate prior to raising + SIGTTOU. + (fhandler_tty_master::read): Allow signals to operate prior to raising + SIGTTIN. + * select.cc (peek_pipe): Detect attempt to read from tty not in our + process group as a "read_ready" event. + * include/shellapi.h: Add missing defines. + * utils/ps.cc: Output windows pid as unsigned for Windows 9x. + +Sat Aug 7 14:30:00 Corinna Vinschen + + * security.cc (get_creator_owner_sid): New function. + * shared.cc (sec_user): calls `get_creator_owner_sid' in creation + of the security attributes structure additionally. + +Fri Aug 6 13:04:40 1999 Christopher Faylor + + * spawn.cc (spawn_guts): Allow failure from OpenProcess. The parent + may have exited due to 7/31 change. + +Thu Aug 5 22:54:07 1999 Christopher Faylor + + * sigproc.cc (wait_for_me): Break out as a common function to check + that the current process is ready to handle signals. + (proc_can_be_signalled): Treat myself differently. + +Thu Aug 5 21:24:20 1999 Christopher Faylor + + * fhandler_console.cc (fhandler_console): Don't call tcinit here. + (fhandler_console::read): Don't reset signal_arrived here. + * syscalls.cc (_read): Set it here instead. + * fhandler_termios.cc (fhandler_termios::line_edit): Only call + accept_input when input is ready. Ignore iscanon in this case. + * fhandler_tty.cc (fhandler_tty_slave::init): Don't call tcinit here. + +Thu Aug 5 16:02:25 1999 Christopher Faylor + + * strace.cc (handle_output_debug_string): Ignore errors reading + from child memory as they seem to occur due to a process exiting. + (close_handle): New, defensive code. + +Thu Aug 5 13:32:43 1999 Christopher Faylor + + * strace.cc (remove_handle): New function. + (add_child): Speed up slightly. + (proc_child): Use output of remove_child in CloseHandle. + +Thu Aug 5 12:38:50 1999 Christopher Faylor + + * dcrt0.cc (dll_crt0_1): Don't protect subproc_ready if it is NULL. + (do_exit): Avoid calling close_all_files if exiting from exec stub. + * net.cc: Reorganize to work around some compiler bugs. + * spawn.cc (spawn_guts): Set hExeced only after child stuff has been + completely initialized. + * syscalls.cc (_open): Protect against signals. + * utils/strace.cc (warn): New function. + (add_child): Issue warning when can't duplicate child process handle. + +Wed Aug 4 21:35:28 1999 Christopher Faylor + + * psapi.h: New file. + +Thu Aug 4 10:28:00 Corinna Vinschen + + * security.cc: Eliminate MALLOC_CHECK calls. + (lookup_name): New function simplifies the retrieval of user and group + names. + (alloc_sd): Call `lookup_name' instead of `LookupAccountName'. + * shared.cc (sec_user): Call `lookup_name' instead of + `LookupAccountName'. Eliminate 'free' call on stack space. + * winsup.h: Declare `lookup_name'. + +Wed Aug 4 16:24:02 1999 Christopher Faylor + + * a.out.h: Fix cut and paste from mime email typos. + +Mon Aug 2 19:08:48 1999 Christopher Faylor + + * Makefile.in: Fix utils dependency. Make clean more assertive. + * path.cc (mount_info::conv_to_win32_path): Fill in correct destination + when a device name is detected. + * syscalls.cc (chown): Always succeed when referencing a cygwin device. + (chmod): Ditto. + * net.cc (get_ifconf): Eliminate holdover from previous change. + +Mon Aug 2 13:07:44 1999 Christopher Faylor + + * dcrt0.cc (do_global_ctors): Remove previous change. It was just + wrong. + +Sun Aug 1 23:21:28 1999 Christopher Faylor + + Throughout rename 'slave_alive' handle to 'inuse'. + * shared.h: Implement tty_attached() macro to determine when an actual + tty is associated with the process. + (class tty): Add some methods for manipulating an "inuse" event that is + common to both master and slave parts of a tty. + * dcrt0.cc (do_exit): Use tty_attached() to determine if signal should + be sent to process group. + * external.cc (fillout_pinfo): Return -1 if tty is not attached (i.e, + attached to a console). + * fhandler.h: Move more stuff into fhandler_tty_common and out from sub + classes. + * fhandler_console.cc (fhandler_console::read): Send SIGWINCH signal to + *correct* process group. + (fhandler_console::open): Fix incorrect argument ordering in set_ctty. + (fhandler_console::de_linearize): Remove unneeded handle resets. + * fhandler_tty.cc (fhandler_tty_slave::open): Fix incorrect argument + ordering in set_ctty. Use tty create_inuse method to create inuse + event. + (fhandler_tty_slave::close): Delete. + (fhandler_tty_slave::dup): Delete. + (fhandler_tty_slave::write): Minor cleanup of flow of control. + (fhandler_tty_common::dup): Subsume fhandler_tty_slave dup method. + (fhandler_pty_master::fhandler_pty_master): Zero inuse field. + (fhandler_pty_master::open): Set inuse field. + (fhandler_tty_common::close): New, superclass method. + (fhandler_tty_common::set_close_on_exec): Handle inuse field. + (fhandler_tty_common::fixup_after_fork): Ditto. + (fhandler_tty_slave::set_close_on_exec): Delete. + (fhandler_tty_slave::fixup_after_fork): Delete. + * path.cc (get_device_number): Use tty_attached() to figure out + /dev/tty. + * select.cc (peek_console): Send SIGWINCH signal to *correct* process + group. + * tty.cc (tty::master_alive): New method. + (tty::create_inuse): New method. + +Sun Aug 1 16:23:22 1999 Christopher Faylor + + * net.cc (get_ifconf): Use alloca for temporary buffer. + +Sun Aug 1 01:38:20 1999 Christopher Faylor + + Modify de_linearize methods throughout to set unix and msdos path + names. + * dcrt0.cc (do_exit): Only remove shared memory when we're done with + it. + * exceptions.cc (try_to_debug): Move static variable outside of the + function so that it can more easily be set with gdb. + * fhandler_console.cc (fhandler_console::open): Handles are typically + hexadecimal in debugging output. + (fhandler_console::open): Do not open inherit console handles by + default. + (fhandler_console::dup): Just use open method to "duplicate" a console + handle. + (fhandler_console::fixup_after_fork): Do *not* close handles here since + they have not been inherited. + (fhandler_console::de_linearize): Ditto. + * utils/strace.cc (create_child): Correct debugging flags when not + tracking forked processes. + +Sat Jul 31 20:10:58 1999 Christopher Faylor + + * dcrt0.cc (do_global_ctors): Ensure that ctors are not called more + than once per session. + * fork.cc (fork): Use sig_protect to protect against signals during + fork. + * pinfo.cc (lpfu): Show windows pid in debugging message as this is + generally more useful. + * pinfo.cc (unlock_pinfo): Issue an error if ReleaseMutex fails. + (pinfo::record_death): Actually unlock pinfo on exit rather than allow + ExitProcess to do this since ExitProcess can sometimes take a *long* + time. + * spawn.cc (spawn_guts): Ensure that pinfo is always unlocked. + +Thu Jul 29 23:43:24 1999 Christopher Faylor + + Throughout, consolidate pgid processing for console and tty into + fhandler_termios and tty_min. + * debug.h: Make WF?O functions the defaults for dealing with Waits. + These functions attempt to work around signal interrupt problems. + * debug.cc: Ditto. + * exceptions.cc (call_handler): Don't wait a long time for second + attempt to get signal mutex. + * fhandler_console.cc (fhandler_console::open): Set the "controlling + tty". + * fhandler_termios.cc: Move the ctty and pgid functions here. + (fhandler_termios::line_edit): Fix debug output. + * fhandler_tty.cc (fhandler_tty_slave_write): Use sig_protect to + protect against output_mutex deadlock. + * fork.cc (get_vfork_val): Conditionalize with NEWVFORK. + * syscalls.cc (setsid): Add debugging output. + (setpgid): Reorganize and add debugging output. + * tty.cc (tty::init): Use a method to clear the sid. + +Thu Jul 29 23:42:53 1999 Christopher Faylor + + Patch from Egor Duda : + * grp.cc (read_etc_group): Use a default /etc/group entry when one + doesn't exist. + (getgrgid): Ditto. + * passwd.cc (read_etc_passwd): Use a default /etc/passwd entry when one + doesn't exist. + (search_for): Ditto. + * uinfo.cc (read_etc_group): Remove some defines. + * winsup.h: Move them here. + +1999-07-29 Bernd Schmidt + + * Makefile.in (SUBDIRS_AFTER): Build mingw before utils. + * utils/Makefile.in (MINGW_LDFLAGS): Add "-B../mingw/" + + +Tue Jul 27 23:31:28 1999 Christopher Faylor + + * dcrt0.cc: Add experimental vfork_storage initialization. + (do_exit): Ditto. + * exec.cc: Use _spawnve throughout as a common interface for execing a + program. + * fork.cc (vfork): Add beginnings of true vfork support. + * path.cc (sort_by_posix_name): Remove special casing of zero length + names since they should now be eliminated earlier on. + (sort_by_native_name): Ditto. + (mount_info::del_item): Remove hole from mount table specifically, here + or suffer weird behavior. Suggested by Andrew Dalgleish + . + * shared.cc: Make SHAREDVER "unsigned" to avoid a compiler warning. + * spawn.cc : Accomodate additional argument to _spawnve, throughout. + (_spawnve): Make this a global function and take an hToken argument so + that it can be used by sexecve. Accomodate experimental vfork + functionality. + * winsup.h: Add initial support for per-thread vfork stuff. + * include/cygwin/version.h: Bump shared memory version number. + +Mon Jul 26 20:59:58 1999 Christopher Faylor + + * path.cc (sort_by_posix_name): Report two zero length strings as being + equal or suffer an infinite loop. + (sort_by_native_name): Ditto. + * shared.cc (shared_info::initialize): Refuse to use a different DLL's + shared memory. + * shared.h: Fix mask for child_info sanity test. + +Sun Jul 18 16:30:31 1999 Christopher Faylor + + * security.cc: Various changes from Corinna. + +Sat Jul 17 22:33:45 1999 Christopher Faylor + + * fork.cc (fork): Change DuplicateHandle slightly. + * security.cc (get_nt_attribute): Ignore error return from + set_process_privileges. + (set_nt_attribute): Ditto. + +Sat Jul 17 00:45:34 1999 Christopher Faylor + + * debug.h: Fix ForceCloseHandle1 in non-debug case. + +Fri Jul 16 23:47:31 1999 Christopher Faylor + + * sigproc.cc (proc_can_be_signalled): Accomodate different flavors of + myself. + * include/ddeml.h: Add missing struct. + * include/wingdi.h: Add missing defines. + +Fri Jul 16 23:01:30 1999 Christopher Faylor + + * Makefile.in: Attempt to cope when srcdir is a relative pathname. + * fork.cc (fork): Pass handle to parent process to fixup_after_fork. + Eliminate excess unlock_pinfos. + * hinfo.cc (hinfo::fixup_after_fork): Use inherited parent handle + rather than try to open the parent process explicitly. + * pinfo.cc (record_death): Cosmetic change. + * sigproc.cc (wait_sig): Add a debugging statement. + * winsup.h: Reflect change of argument for fixup_after_fork. + +Fri Jul 16 11:07:55 1999 Christopher Faylor + + * shared.h: Eliminate record_death_nolock. Just pass an argument to + record_death. + * pinfo.cc (record_death_nolock): Ditto. + * dcrt0.cc (__api_fatal): Use record_death with FALSE argument rather + than record_death_nolock. + * exceptions.cc (really_exit): Ditto. + * fork.cc (fork): Remove debugging statement. + +Wed Jul 14 22:08:52 1999 Christopher Faylor + + Throughout, make parent_alive a local variable. Rename 'alive_parent' + to 'my_parent_is_alive'. + * autoload.h: Improve the description of the autoload mechanism. + * dcrt0.cc: Define parent_alive here. + (dll_crt0_1): When debugging, rotect handles inherited from fork/exec. + Force signal thread to finish initializing prior to calling main. + (dll_crt0): Reorganize child_info stuff to allow common initialization. + Accept parent_alive handle from invoker and ensure that this is not + inherited by other processes. + (do_exit): Ensure that exit_state is not duplicated by a fork. + (__api_fatal): Call 'try_to_debug' directly. + * debug.cc: Increase the size of the handle list. + (threadname): Add an optional argument to control locking. + * exceptions.cc (error_start_init): Make this a "C" function. + (try_to_debug): Ditto. Also, use Sleep rather than pause and loop so + that gdb can get in to interrupt things. + (sig_handle): + * external.cc (fillout_pinfo): Reorganize slightly and plan for the + future. + * fhandler.h: Add an argument to show the name of the handle for error + messages to fork_fixup. + * fhandler.cc (fhandler_base::fork_fixup): Ditto. + (set_inheriting): Rename a variable for clarity. + (fhandler_base::fixup_after_fork): Pass in the name of the handle to + fork_fixup. + * fhandler_tty (fhandler_tty_common:fixup_after_fork): Ditto. + (fhandler_tty_slave:fixup_after_fork): Ditto. + (fhandler_tty_master:fixup_after_fork): Ditto. + * fhandler_windows.cc (fhandler_windows::fixup_after_fork): Ditto. + * fhandler_console.cc (fhandler_console::open): Specifically open + console with ENABLE_PROCESSED_INPUT. + * fork.cc (sync_with_child): Call abort when DEBUGGING and there's an + error. + (resume_child): Ditto. Also, allow an ERROR_INVALID_HANDLE error if it + can't be duplicated as they seem to occur occasionally when the parent + copies the stack. + (fork): Use init_child_info to initialize structure passed to child. + Remove start time setting in favor of common function. Don't mess with + parent's parent_alive. + * heap.cc (sbrk): Simply code slightly. + * hinfo.cc (hinfo::dup2): Improve error handling. + * pinfo.cc (set_myself): Set start time here since it is called by + everything which sets myself. + (pinfo_init): Remove start_time setting in favor of common function. + * shared.h (pinfo): Reorganize so that signal stuff falls into section + of pinfo which is automatically zeroed when a new pid is initialized. + (PROC_MAGIC): Increment to detect cygwin1.dll's memory passing + disparities. + * sigproc.cc (proc_alive): Make this a function. Wait for target pid + to initialize. + (my_parent_is_alive): Rename from alive_parent. + (proc_can_be_signalled): Renamed from proc_alive macro. + (proc_exits): Use proc_can_be_signaleed(). + (proc_subproc): Don't put parent_alive in child. + (proc_terminate): Close hwait_subproc in a race-safe way. Ditto + sync_proc_subproc. + (sigproc_terminate): Always terminate proc_subproc thread first or it + may try to use signal thread as it is going away. Wait for signal + thread to exit. + (sig_send): Use proc_can_be_signalled(). + (init_child_info): New function. Initializes memory block passed by + spawn/fork. + (mutex_stack): Add thread name field. + (sig_wait): Set active state after all handles have been set up and + before protecting the handles. Use ForceCloseHandle to close + subproc_ready as it is now protected. Close signal_mutex here. + * sigproc.h: Accomodate alive_parent rename. + * spawn.cc Use init_child_info to initilize memory block passed to + subprocess. + * strace.cc (__system_printf): Write to screen before writing to strace + log. Only write to strace log if we're actually stracing. + * winsup.h: Declare the 'action on error' functions. + * utils/Makefile.in: (Patch from Egor Duda ) Compile + strace using -mno-cygwin. + * utils/strace.cc: Allow ingw concession from Egor Duda. Attempt to + allow CTRL-C when stracing. + +Thu Jul 14 0:39:00 Corinna Vinschen + + * security.cc (alloc_sd): Delete special handling of uid/gid 513. + +Thu Jul 13 15:01:00 Corinna Vinschen + + * fhandler.cc (get_file_owner): Fix typo. + * path.cc (path_conv::path_conv) : Change `return' to `goto end' in + case of SYMLINK_IGNORE is set. + +Mon Jul 5 21:33:00 Corinna Vinschen + + * security.cc (WriteSD): Doesn't set errno if BackupWrite() + returns ERROR_INVALID_SECURITY_DESCR (which happens on FAT). + +Sat Jul 10 13:17:20 1999 Christopher Faylor + + * utils/strace.cc (error): Actually output error message. + (add_child): Duplicate inherited child process handle with all of the + privileges that we need. + +Fri Jul 9 01:37:23 1999 Geoffrey Noer + + * include/cygwin/version.h: Bump CYGWIN_VERSION_API_MINOR to 14 + in honor of snprintf and vnsprintf additions. + +Fri Jul 9 00:04:03 1999 Christopher Faylor + + * path.cc (path_conv::path_conv): Correct buffer overflow condition. + * fhandler_console.cc (fhandler_console::open): *Need* to enable + processed input or CTRL-C won't stop anything unless it's at a prompt. + (fhandler_console::input_tcsetattr): Ditto. + +Thu Jul 8 18:27:49 1999 Christopher Faylor + + * Makefile.in: Add malloc debugging options. + * dcrt0.cc (api_fatal): Call abort when debugging so that the debugger + will pop up. + * debug.cc (close_handle): Unlock in pathological case. + * fhandler_console.cc (fhandler_console::read): Always respond to + windows size changes. + (fhandler_console::open): Always set things to ~ENABLE_PROCESSED_INPUT + so that we can control INTR character. Don't set pgid here. + (fhandler_console::input_tcsetattr): Turn on windows event so that we + can see screen resizes. + (fhandler_console::init): Don't set pgid here. + * fhandler_termios (fhandler_termios::tcinit): Set pgid here. + * fhandler.h: Fix set_has_acls method return. + * utils/strace.h: Pass CTRL-Cs to child process. + +Wed Jul 7 23:59:50 1999 Christopher Faylor + + * Makefile.in: Improve dependencies. + * autoload.h: Work around "function unused" messages for autoload init + functions. + * configure.in: Use CHECK_TOOL to find CC so that it will get the + proper host alias. + * configure: Regenerate. + * dcrt0.cc (do_exit): Minor reorganization of termination function + calls. + * debug.cc (close_handle): Issue an error when an attempt is makde to + close a handle with a name different from the one used to record it + previously. + * debug.h: Implement new macros for storing arbitrary handle names. + * exceptions.cc (handle_signal): Terminate the main thread when exiting + due to signal in signal thread. + * fhandler.h: Add an extra 'fd' argument to all ready_for_read methods. + * select.cc: Ditto, throughout. + * fhandler_console (get_tty_stuff): Protect the tty_stuff handle here. + * fhandler_termios.cc (fhandler_termios::line_edit): Accomodate fd + argument to ready_for_read. + * fhandler_tty.cc (fhandler_tty_master::init): Close an unneeded thread + handle. + * fork.cc (fork): Use standard name when protecting process handle. + * spawn.cc (spawn_guts): Ditto. + * shared.cc (open_shared_file_map): Protect cygwin_shared handle here. + * sigproc.cc: Throughout, close child process handle using standard + name. + * syscalls.cc (read_handler): Check that fd is still open prior to + performing an operation. Supply fd argument for ready_for_read. + * (_read): Supply fd argument for read_for_read. + * tty.cc (tty_list::terminate): Close unneeded handles as tty is + closing down. + (tty_list::allocate): Protect against signals. + +Mon Jul 5 14:52:40 1999 Christopher Faylor + + * cygwin.din: Export new snprintf and vnsprintf functions courtesy of + Egor Duda . + +Sun Jul 4 23:54:43 1999 Christopher Faylor + + * exceptions.cc (sigbegin): New function. Called prior to dispatching + to signal handler. + (sigreturn): New function. Called after signal handler returns. + (set_process_mask): Make stdcall. + (call_handler): Remove sigwrap asm stuff in favor of new + sigbegin/sigreturn scheme. + * winsup.h: Change set_process_mask declaration. + +Sun Jul 4 22:00:14 1999 Christopher Faylor + + * syscalls.cc (stat_worker): Previous change to check for extension + found dots not in the filename part. Fix this. + +Sat Jul 3 23:22:55 1999 Christopher Faylor + + * include/wincon.h: Add some missing defines. + * environ.cc: Remove extern which is now in winsup.h. + * fhandler.cc (get_file_owner): Rename argument. Test for allow_ntsec. + (get_file_group): Ditto. + (fhandler_disk_file::fstat): Use new method inode checking. + * fhandler.h: Rename a method. + * security.cc (set_file_attribute): Take an additional argument to + determine if ntsec security setting should be used. + * dir.cc (mkdir): Pass acl info to set_file_attribute. + * syscalls.cc (chown): Ditto. + (chmod): Ditto. + * winsup.h: Define allow_ntsec here. + +Sat Jul 3 15:09:34 1999 Christopher Faylor + + * fhandler.cc (fhandler_disk_file:;fstat): Move check of disk volume to + path_conv. Use new methods for determining if file system is ACL + capable. + (fhandler_disk_file::open): Set "has acls" flag here. + * fhandler.h: Store acl information in fhandler base class. + * path.cc (path_conv): Set acl information on successful return. + * path.h: Add acl info to path_conv class. + * security.cc (get_file_attribute): Set ENOSYS if can't get extended + attributes. + * syscalls.cc (chown): Pass acl information from path_conv to + get_file_attributes. + (chmod): Ditto. + (stat_worker): Ditto. + * uinfo.cc: Make all exported functions extern "C". + * winsup.h: Add rootdir() declaration. + +Fri Jul 2 15:13:08 1999 Christopher Faylor + + * autoload.h: New file. + +Thu Jul 1 23:16:34 1999 Christopher Faylor + + * net.cc (cygwin_gethostname): Use new win32_gethostname to + disambiguate between cygwin and winsock version. + * tty.cc (creat_tty_master): Disambiguate by using cygwin_gethostname + to find the hostname. + * winsup.h: Declare cygwin_gethostname. + +Thu Jul 1 22:36:31 1999 Christopher Faylor + + Throughout, remove check for winsock initialization and indirect + references to winsock functions in favor of new dynamic DLL loading + method. + + * Makefile.in: Remove unneeded libraries. + * cygwin.din: Make gethostname == cygwin_gethostname like other network + functions. + * dcrt0.cc: Implement new "autoload" functionality for loading DLLs and + functions as they are needed. Add autoload functions for user32.dll. + (cygwin_dll_func_load): New function. + (dll_crt0): Issue a fatal error message if attempt to mix different + version DLLs is detected. + (api_fatal): Correct inexplicable use of buf + 8 when printing error + message into a buffer. + * fhandler.h: Cosmetic fixes. + * fhandler_tty.cc (fhandler_tty::close): Temporarily "if 0" out code + which sends EOF pulse to children. This should only happen when last + parent fd closes. + * heap.cc (sbrk): Implement new sbrk mechanism which returns memory to + Windows when top of heap decreases beyond a page boundary. + (getpagesize): New function. + * fork.cc (fork): Save new heap values in stuff passed to child. + * hinfo.cc (hinfo::build_fhandler): Don't do any checking on a handle + if the handle is NULL. Assume that it is a disk file. + * net.cc: Redo winsock functions to use dynamic loading scheme. + * shared.cc (shared_info::initialize): Cosmetic change. + * shared.h: Change magic number for memory block sent to child + processes. Accomodate new heap information in child_info. + * sigproc.cc (sig_dispatch_pending): Remove some memory debugging checks. + (__release_signal_mutex): Ditto. + * syscalls.cc (stat_worker): Don't attempt the .exe hack unless the + previous attempt to open the file resulted in an "ERROR_FILE_NOT_FOUND" + and the file did not already contain an extension. + * times.cc: Initialize static NO_COPY variables throughout or they will + not actually be NO_COPY. + * winsup.h: Rename heap fields in per_process to accomodate new sbrk. + Eliminate winsock stuff invalidated by dynamic loading change. + * include/winsock.h: Make this file C++ safe. + +Sun Jun 27 17:07:34 1999 Christopher Faylor + + * debug.h: Don't define MALLOC_DEBUG by default. + * fhandler.cc (fhandler_base::set_name): Always set names to NULL. Add + more slop to end of win32_path_name. + (fhandler_base::de_linearize): Set names to NULL. They'll be assigned + by the caller. + (fhandler_disk_file::get_native): Delete. + * fhandler.h: Ditto. + * hinfo.cc (hinfo::de_linearize_fd_array): Set path names after the + structure has been "delinearized". + * malloc.cc: Add debugging versions of malloc functions. + * syscalls.cc (stat_worker): Eliminate static buffer for thread safety. + +Wed Jun 23 22:53:00 Corinna Vinschen + + * fhandler.cc (fhandler_disk_file::fstat): If get_file_attribute() + signals a nonexistant acl, fstat sets default attributes now. + +Wed Jun 23 10:22:56 1999 Geoffrey Noer + + * include/cygwin/version.h: Bump CYGWIN_VERSION_API_MINOR to 13. + +Wed Jun 23 10:39:07 1999 Mumit Khan + + * cygwin.din (gamma, gammaf, lgamma, lgammaf): Export. + (j0,j0f,j1,j1f,jn,jnf): Export underscore versions as well. + +Mon Jun 21 21:34:06 1999 Christopher Faylor + + Sprinkle MALLOC_CHECK macro throughout. When turned on, this will give + a slightly better idea of where memory corruption occurs. Add slightly + modified versions of "error_start" code from Egor Duda + . + * Makefile.in: Add `utils' target. + * dcrt0.cc (do_exit): Attempt to detect loop conditions where do_exit + is called reentrantly and avoid the previously executed code in this + case. + * debug.h: Define MALLOC_CHECK macro for use with malloc debugging. + * environ.cc (environ_init): Add more slop at end of environ string + just to work around buggy programs. + (parse_options): Add error_start option to control core dumping or gdb + invocation. + * exceptions.cc (stackdump): New function. Dumps stack to stderr. + (error_start_init): New function. Initialize action on "core dumping" + error. + (handle_exceptions.cc): Use stackdump command to dump stack. Call + try_to_debug. + (set_process_mask): Must be __stdcall or compiler get's confused. + (sig_handle): Detect SIGQUIT and SIGABRT. Do a "stackdump" for these. + * fhandler.cc (get_file_owner): Add an argument to determine if + function should check for NT security. + (get_file_group): Ditto. + (fhandler_base::set_name): Don't free "fhandler_disk_dummy_name" path + names. + (rootdir): New function, pulled from the pages of syscalls.cc. + Determines the root dir of a given path. + (fhandler_disk_file::fstat): Get volume information of file in question + to determine if inodes are permanent and acls are available. This + replaces previous WinNT test. + (fhandler_base::~fhandler_base): free "fhandler_disk_dummy_name" path + names. + * fhandler.h: Change get_file_* declarations. + * fhandler_console.cc: Back out most of scroll fixes from April 17. + They caused weird scrolling behavior. + * fhandler_tty.cc (fhandler_pty_master::accept_input): Add debugging + message. + * security.cc (get_file_attribute): Add additional "check for ACL" + argument. + * path.cc (symlink_check_one): Use new argument to get_file_attribute. + * sigproc.cc (wait_subproc): Don't exit wait loop if WaitForMultipleObject + returns an error. Instead, loop for a while in case this is an expected + error. + * sigproc.h: Remove __stdcall from set_process_mask. + * spawn.cc (linebuf): Use initializers to set initial values. + (linebuf::append): Be defensive and ensure that enough space is + allocated for the new argument. + (linebuf::prepend): Ditto. + (spawn_guts): Correct logic which broke up program argument in a #! + script. + * syscalls.cc (chown): Use new argument to get_file_attribute. + (chmod): Use new argument to get_file_owner and get_file_group. + (stat_worker): Ditto. + (statfs): Break out code that determined the root directory of a given + path. Use new rootdir function instead. + * winsup.h: Reflect new get_file_attribute argument. + * include/sys/strace.h: Add "NOTALL" flag so that voluminous debugging + output can be avoided. + * utils/strace.cc: Honor NOTALL flag. Run at a higher priority. + +Mon Jun 14 18:33:08 1999 Christopher Faylor + + * syscalls.c (stat_worker): Consolidate calls to fh.fstat for both + directories and normal files. + * fhandler_tty.cc (fhandler_pty_master::close): Ensure that an "EOF + pulse" is sent to any executing child processes. + * path.cc (symlink_check_one): Check for ':\n' as well as '#!' to + determine if a file is executable. + +Mon Jun 14 16:04:00 1999 Christopher Faylor + + * fhandler_tty.cc (fhandler_pty_master::accept_input): Set read_retval + prior to performing a write to avoid a potential race condition. + * fhandler_termios.cc (fhandler_termios::line_edit): Don't set + read_retval here. It has to be set in an fhandler_tty accept_input. + * select.cc (peek_pipe): Fix typo which caused read_selected to be + tested twice rather than except_selected. + * shared.h (class tty_min): Remove read_retval from here. + (class tty) Put it here. + +Mon Jun 14 13:08:58 1999 Christopher Faylor + + * utils/Makefile.in: Consolidate and simplify. + +Mon Jun 14 12:43:32 1999 Christopher Faylor + + Throughout, remove reliance on strace_* fields in pinfo class. Use + global instead. Remove STRACE_DUMP and STRACE_CACHE logic. + * pinfo.cc (set_myself): New function. + * dcrt0.cc (dll_crt0_1): Use the new function. + * environ.cc (parse_options): Remove strace environment variable logic. + (environ_init): Ditto. + * exceptions.cc (call_handler): Remove strace mutex considerations. + * fhandler_termios (fhandler_termios::line_edit): Remove STRACE_CACHE + logic. + * localtime.cc: Define 'lint' to eliminate warnings. + * smallprint.c (__small_vsprintf): Remove text formatting of windowss + errors. This is now done in the 'strace' program. + * strace.cc: Define 'strace_active' variable to control whether strace + should be carried out. + (strace_open): Delete. + (strace_init): Delete. + (get_strace_mutex): Delete. + (release_strace_mutex): Delete. + (strace_vsprintf): Preserve last error. + (strace_write): Communicate with strace program using + OutputDebugString. + (strace_dump): Delete. + (mark): Gut. + * winsup.h: Remove a declaration. Add a new one. + * include/sys/strace.h: Modify to accomodate new strace scheme. + * utils/Makefile.in: Build strace.exe + * utils/strace.cc: New file. + +Sat Jun 12 22:22:00 1999 Corinna Vinschen + + * fhandler.cc (fhandler_disk_file::fstat): Must compute i-node numbers + via `get_namehash' for Windows 9x. + +Sat Jun 12 10:54:00 1999 Corinna Vinschen + + * fhandler.cc (fhandler_base::read): Returns correct value + if raw_read fails. + * fhandler_raw.cc: More trace output. + * fhandler_floppy.cc: Ditto. + * fhandler_tape.cc: Ditto. + +Thu Jun 10 14:01:05 1999 Christopher Faylor + + * exceptions.c (handle_exceptions): Use ".stackdump" + extension instead of ".core". + * path.cc (mount_info::read_mounts): Prescan the mount lists + for /cygdrive stuff to delete rather than attempting to + delete it in the main "add mount loop". + (mount_item::getmntent): Fix "system"/"user" determination. + * winsup.h: Use void methods in thread classes where + appropriate. + +Wed Jun 9 23:16:04 1999 Christopher Faylor + + * mkvers.sh: Issue error if can't find version information. + +1999-06-09 DJ Delorie + + * localtime.c: new file; public domain timezone handling routines. + * tz_posixrules.h: new file; POSIX default timezone data + * times.cc: comment out localtime, gmtime, replace tzset with + cygwin_tzset + * Makefile.in: add localtime.c + +Wed Jun 9 00:49:04 1999 Christopher Faylor + + * spawn.cc (spawn_guts): Correctly handle #! processing when line + ends with white space. Also correctly handle scripts that do not + begin with #!. + +Mon Jun 7 17:04:36 1999 Christopher Faylor + + * fhandler_console.cc (fhandler_console::open): Need to initialize + tc here, too. + (fhandler_console::init): Initialize tc earlier. + +Mon Jun 7 00:02:51 1999 Christopher Faylor + + * fhandler.h (fhandler_termios): Move tc initialization + into init method, etc. + (fhandler_tty_common): Ditto. + * fhandler_console.cc (fhandler_console::fhandler_console): + Move tc initialization to init method. + (fhandler_console::init): Initialize tc stuff here. + (fhandler_console::dup): Ditto. + (fhandler_console::fixup_after_fork): Ditto. + (fhandler_console::de_linearize): Ditto. + * fhandler_termios (tcinit): Rename constructor. + Accept force argument to force termios initialization. + * fhandler_tty.cc (fhandler_tty_master::init): Move tc initialization + to common_init. + (fhandler_tty_common::dup): Use tcinit () to initialize tc field. + * tty.cc (tty::common_init): Ditto. + +Sun Jun 6 22:19:09 1999 Christopher Faylor + + * tty.cc (tty_list::terminate): Add \n to output message. + (tty::init): Clear slave_opened field or we can't reopen + ttys. + +Fri Jun 4 23:58:17 1999 Christopher Faylor + + * fhandler_tty.cc (fhandler_tty_slave::open): Reorganize + slightly to avoid a race with get_ttyp()->was_opened. + +1999-06-04 DJ Delorie + + * times.cc (totimeval): scale sub properly. + (gettimeofday): don't bias by timezone. + +Thu Jun 3 13:24:17 1999 Christopher Faylor + + * fhandler.h (fhandler_tty_common): Add two new methods. + * fhandler_tty.cc: Use new {acquire,release}_output_mutex + methods throughout for output_mutex. + (fhandler_tty_common::__acquire_output_mutex): New method. + (fhandler_tty_common::__release_output_mutex): New method. + * shared.h (get_output_mutex): Rename to open_output_mutex. + +Wed Jun 2 16:06:26 1999 Geoffrey Noer + + * utils/mkpasswd.c (main): account for long int args to printfs. + +Wed Jun 2 16:08:08 1999 Christopher Faylor + + * smallprint.c (__small_vsprintf): Conditionalize display of + textual messages under CYGWIN_TEXT_ERROR. + * ntea.cc: Remove debugging code. + +Wed Jun 2 16:04:00 1999 Corinna Vinschen + + * dcrt0.cc (dll_crt0_1): Call the functions `get_admin_sid', + `get_system_sid' and `get_world_sid' before heap initialization + to avoid heap fragmentation. + * security.cc (get_nt_attribute): Don't allocate memory + anymore. All memory is taken from stack. + (set_nt_attribute): Ditto. + (alloc_sd): Ditto. Change parameters to get a pointer to a + preallocated security descriptor and a pointer to it's length. + * shared.cc (sec_user): Don't allocate memory anymore. All + memory is taken from stack. Change parameters to receive a + pointer to a preallocated security buffer. + * shared.h: Change prototype for `sec_user' and `sec_user_nih'. + * sigproc.cc (getsem): Change call to `sec_user'. Additonally + buffer for `sec_user'. + * spawn.cc (spawn_guts): Ditto. + Change all error output in function `sec_user' and in module + `security.cc' from error text to error number output. + +Tue Jun 2 21:54:21 1999 Corinna Vinschen + + * net.cc (get_if_flags): Change the UP and RUNNING state + of disconnected RAS interfaces to true. + +Thu Jun 1 22:47:00 1999 Corinna Vinschen + + * security.cc (get_system_sid): New function to create + a SID for the well known group of local system. + (alloc_sd): New function. + (alloc_sd): Give ALL permissions to `system'. + * shared.cc (sec_user): Give ALL permissions to `system'. + (sec_user): Provide additionalparameter for a second SID. + This is used for `CreateProcessAsUser' call. + (sec_user_nih): Ditto. + * shared.h: Change prototypes for `sec_user' and + `sec_user_nih'. + * spawn.cc (spawn_guts): Now using `sec_user' in + `CreateProcessAsUser' call, if ntsec is set. + +Thu Jun 1 14:17:00 1999 Corinna Vinschen + + * utils/mkpasswd.c: Change to output native names of + well known groups `Everyone' (SID 0) and `system' (SID 18). + * utils/mkgroup.c: Ditto plus output of native name of + well known group `None' (SID 513). + +Mon May 31 22:10:57 1999 Christopher Faylor + + * path.h: Use bit mask flags in path_conv to save exec, + symlink, binary status. Use methods to access and set + these flags. + * fhandler.cc: Use methods to access path_conv flags + throughout. + * path.cc: (symlink-check_one): Accept a bitmask flags + variable to accomodate path_conv changes. + (path_conv::path_conv): Propagate path_flags from mount + table to path_conv class. Avoid walking the mount table + twice to find "binary" info. + (mount_info::conv_to_win32_path): Accept additional flags + argument. Don't add trailing slash if not required. + Fill out both paths when cygdrive. + (mount_info::cygdrive_win32_path): Change debugging output + slightly. + (mount_info::set_flags_from_win32_path): Generalize from + mount_info::binary_win32_path_p. + (mount_item::getmntent): Honor MOUNT_EXEC flag. + * shared.h: Add new method to mount_info class. + * include/sys/mount.h: Add a comment. + * utils/mount.cc: Accept -x to force a mountpoint to default + to executable permission. Rename automount stuff to cygdrive. + +Mon May 31 19:00:00 1999 Corinna Vinschen + + * environ.cc (environ_init): Set ntsec option by default + if running under NT. + * security.cc (set_nt_attribute): Delete superfluoues code. + * shared.cc (sec_user): Don't set owner in created security + descriptor. + * sigproc.cc (getsem): Use `sec_user' instead of `sec_user_nih'. + * spawn.cc (spawn_guts): Set security attribute of + `CreateProcess' to `sec_user' if ntsec is set, `sec_all_nih' + otherwise. + +Mon May 31 19:27:36 1999 Christopher Faylor + + Throughout, change "automount" to cygdrive. + Throughout, change mount flags from signed to unsigned. + + * path.cc (iscygdrive): New macro. + (normalize_posix_path): Tack a '/' on the end of constructed + path only if there isn't one there already. + (mount_info::init): Simplify slightly. + (mount_info::conv_to_win32_path): Don't search for automount + stuff in the mount table. Instead special case the cygdrive + handling so that it will always be acceptable to use /cygdrive + regardless of other mounts. + (mount_info::cygdrive_posix_path): Rename from + build_automount_mountpoint_path. Fully build a posix path + given inputs. + (mount_info::cygdrive_win32_path): New function. + (mount_info::conv_to_posix_path): Precalculate the length + of the pathbuf for multiple uses. Just use cygdrive_posix_path + to derive a /cygdrive/x/foo style path. + (mount_info::read_mounts): Don't read /cygdrive/x mounts from + the registry. Delete them. + (mount_info::from_registry): Read cygdrive info earlier for + subsequent use by other mount routines. + (mount_info::add_reg_mount): Cosmetic changes. + (mount_info::read_cygdrive_info_from_registry): Always add + trailing slash to cygdrive. Precalculate the length of the + cygdrive. + (mount_item::getmntent): Cosmetic changes. + (mount): Return EINVAL on attempt to add a mount point which + begins with the current cygdrive. + * path.h: Remove unused script_p from path_conv class. + * shared.h: Add cygdrive_length to mount_list. Add new + cygdrive_win32_path method. + * include/sys/mount.h: Use enums for MOUNT_ constants. + +1999-05-29 Keith Seitz + + * errno.cc (errmap): Map ERROR_NEGATIVE_SEEK to EINVAL. + +Fri May 28 21:43:56 1999 Christopher Faylor + + * times.cc (to_time_t): Rewrite slightly to avoid compiler + overoptimization. + +Fri May 28 21:10:33 1999 Corinna Vinschen + + * sigproc.cc (getsem): Set security attribute of process + semaphore to `sec_user_nih()', if ntsec is set, `sec_none_nih' + otherwise. + +Wed May 26 22:56:51 1999 Christopher Faylor + + Rename inuse_event and inuse_event_exists to "slave_alive" + throughout. + * shared.h: Eliminate inuse_event. Replace with a boolean. + Elminate slave_opened. + Add some function declarations used by new methods. + * fhandler_tty.cc (fhandler_pty_master::hit_eof): Use better + method for determining EOF for pty master. + (fhandler_tty_slave::open): Use method to acquire output_mutex. + Always create "inuse_event". Delete call to slave_opened. + (fhandler_tty_slave::write): Reorganize debugging output + slightly. + (fhandler_tty_master::close): Eliminate reference to inuse_event. + * tty.cc (tty_list::terminate): Eliminate call to slave_opened. + (tty_list::connect_tty): Use new exists() method to find out if + a tty exists. + (tty_list::allocate_tty): Rename argument for clarity. Use + new exists method to determine tty existence. + (tty::inuse): Delete. + (tty::init): Remove reference to inuse_event. + (tty::common_init): Ditto. + (tty::slave_opened): Delete. + * winsup.h: Move some function declarations to shared.h. + +Mon May 24 22:10:34 1999 Corinna Vinschen + + * security.cc (WriteSD): Don't set errno, if BackupWrite() + returns ERROR_NOT_SUPPORTED. + * security.cc (set_nt_attribute): Change condition for + calling LookupAccountName() with domain name again. + * shared.cc (sec_user): Ditto. + +Mon May 24 22:10:34 1999 Corinna Vinschen + + * include/winnt.h: Temporary erased definitions of QuadPart + in LARGE_INTEGER and ULARGE_INTEGER. + * security.cc (set_nt_attribute): Set standard attributes so + that reading and writing attributes for user and administrators + isn't hindered. + +Mon May 24 22:10:34 1999 Corinna Vinschen + + * security.cc (ReadSD): New function. + * security.cc (WriteSD): Ditto. + * security.cc (get_admin_sid): Moved from shared.cc. + * security.cc (set_process_privileges): Moved from syscalls.cc, + shortened, changed return typ to int. Sets errno now. + * security.cc (set_file_attributes): Return type changed to int. + * security.cc (get_file_attributes): Ditto. + * security.cc (set_nt_attributes): Ditto. Cares for setting + of S_ISVTX now. + * security.cc (get_nt_attributes): Ditto. + * syscalls.cc (rel2abssd): #if 0'ed. + * syscalls.cc (set_process_privileges): Moved to security.cc. + * syscalls.cc (chown): Rewritten. + * syscalls.cc (chmod): Change call order of the functions + set_file_attributes() and SetFileAttributesA(). + * fhandler.cc (fhandler_base::fstat): Change check for + return value of get_file_attributes(). + * ntea.cc (NTReadEA): returns TRUE now, if allow_ntea is unset. + * ntea.cc (NTWriteEA): returns TRUE now, if allow_ntea is unset. + * shared.cc (get_admin_sid): Moved to security.cc. + * path.cc (symlink_check_one): Change check for return value + of get_file_attributes(). + +Mon May 24 22:10:34 1999 Corinna Vinschen + + * security.cc (get_world_sid): Rewrite. + * security.cc (world_full_access): Delete. + * grp.cc: Use gid 0 as default gid. + * grp.cc (read_etc_group): Look for account name of world group. + * fhandler.cc (fhandler_base::open): Call `set_file_attribute' + only in case of disk file. + +Mon May 24 22:10:34 1999 Corinna Vinschen + + * security.cc (get_file_attribute): Patched incorrect test + for symlink. + * security.cc (set_file_attribute): ditto. + +Mon May 24 22:10:34 1999 Corinna Vinschen + + * security.cc: Special handling for user and/or administrators + permissions to write (extended) attributes. + +Mon May 24 22:10:34 1999 Corinna Vinschen + + * security.cc: Don't allow 513(none) as user or group. + +Mon May 24 22:10:34 1999 Corinna Vinschen + + * security.cc: new functions `set_nt_attribute()', `get_nt_attribute()' + and `set_file_attribute()' with additional parameters `uid' and `gid', + to support real NT security. + * winsup.h: Prototype for `set_file_attribute()' with four + parameters. + * dir.cc (mkdir): Calls `set_file_attribute()' now. + * syscalls.cc (chown): ditto. + * syscalls.cc (chmod): ditto, with correct uid/gid. + +Mon May 24 22:10:34 1999 Corinna Vinschen + + * shared.cc: New function `get_admin_sid()' to get a SID + of the administrators group or of administrator. + New functions `sec_user()' and `sec_user_nih()' to get + SECURITY_ATTRIBUTES with all permissions for the user and + the administtrator group. + * shared.h: Prototypes for the above new functions `sec_user()' + and `sec_user_nih()'. + * sigproc.cc (getsem): Create process semaphore with + permissions set by `sec_user()'. + +Mon May 24 20:29:29 1999 Christopher Faylor + + * fhandler_console.cc (fhandler_console::output_tcsetattr): + ONLRET was erroneously used in place of ONLCR. + (fhandler_console::read): Honor get_r_no_interrupt () so + that interrupts don't screw up tty reading. + * fhandler.h: Add some methods to fhandler_tty_master. + * fhandler_termios.cc (fhandler_termios::fhandler_termios): + ONLRET was erroneously used in place of ONLCR. + * fhandler_tty.cc (fhandler_tty_master::init): Associating + console capabilities with the tty capabilities is a bad + idea. Go back to using the console's own. + (fhandler_tty_master::fixup_after_fork): New method. + (fhandler_tty_master::de_linearize): New method. + (fhandler_tty_master::init_console): New method. + +Mon May 24 09:58:02 1999 Christopher Faylor + + * include/rapi.h: Add some more definitions. + +Sat May 22 21:45:01 1999 Mumit Khan + + * scandir.cc (scandir): Handle errno correctly. Do preallocation to + reduce realloc calls. + (alphasort): Use strcoll, not strcmp. + +Sat May 22 19:03:47 1999 Mumit Khan + + * dll_init.cc (DllList::recordDll): Forkee must reload dlopened + DLLs. Also use strcasematch, not strcmp to compare file name. + +Wed May 19 14:38:57 1999 Christopher Faylor + + * spawn.cc (linebuf::prepend): Fix possible reference to + uninitialized memory. + * winsup.h: Remove WINSUP_NO_CLASS_DEFS workaround. + * libccrt0.cc: Ditto. + * utils/cygwin.cc: Ditto. + * utils/mount.cc: Ditto. + * utils/ps.cc: Ditto. + +Sun May 16 17:22:50 1999 Christopher Faylor + + * include/winnt.h: Revert the previous reversion. The problem + with this include file was completely misdiagnosed. + +Sun May 16 16:05:07 1999 Christopher Faylor + + * sysdef/rapi.def: New definition file for RAPI.DLL. + * include/rapi.h: Preliminary RAPI declarations. + +Sun May 16 15:37:15 1999 Christopher Faylor + + * Makefile.in: Remove more obsolete code. + +Fri May 14 19:30:53 1999 Christopher Faylor + + * include/winbase.h: Change conditional to correctly refer + to UNDER_CE rather than UNICODE. + +Tue May 11 21:19:59 1999 Christopher Faylor + + * exceptions.cc (call_handler): Restore previously removed + 'leave' command as its absence causes programs to crash. It + should never have been deleted. + +Tue May 11 12:04:02 1999 Norbert Schulze + + * times.cc (timezone): Properly adjust for daylight savings time. + (gettimeofday): Ditto. + (localtime): Ditto. + (tzset): Ditto. + +Mon May 10 23:31:36 1999 Christopher Faylor + + * include/winnt.h: Revert to previous version. There are problems + with the previous checkin. + * fhandler_console.cc (fhandler_console::de_linearize): Add defensive + code to ensure that console handles are opened correctly. + +Sun May 9 22:31:31 1999 Christopher Faylor + + * Makefile.in: Forgot to remove a reference to the deleted targets + below. + +Fri May 7 17:28:12 1999 Christopher Faylor + + * Makefile.in: Remove obsolete code. + * exceptions.cc (set_process_mask): Make this a __stdcall. + * sigproc.h: Fix declaration of set_process_mask. + * include/winnls.h: Add new code page defines. + * include/winnt.h: Various fixes from Anders Norlander + . + +Mon May 3 11:32:32 1999 Mumit Khan + + * smallprint.c (__small_vsprintf): Display textual messages + for "%E" format type. + * dlfcn.cc (set_dl_error): Lose the "Win32 ". + +Sun May 2 12:22:17 1999 Mumit Khan + + * utils/Makefile.in (EXE_LDFLAGS): Provide default. + +1999-04-30 DJ Delorie + + * winsup.h (WINSUP_NO_CLASS_DEFS): if defined, don't include class + definitions (work around gcc bug) + * libccrt0.cc (WINSUP_NO_CLASS_DEFS): define + * utils/cygwin.cc (WINSUP_NO_CLASS_DEFS): define + * utils/mount.cc (WINSUP_NO_CLASS_DEFS): define + * utils/ps.cc (WINSUP_NO_CLASS_DEFS): define + +Thu Apr 29 13:55:57 1999 Mumit Khan + + * shared.h (read_mounts): Change prototype to accept a reference + to reg_key, not a copy. + * path.cc (read_mounts): Likewise. + +Thu Apr 29 11:06:37 1999 Mumit Khan + + * configure.in (EXE_LDFLAGS): Always add newlib if part of the + build tree. + * configure: Regenerate. + + * utils/Makefile.in (INCLUDES): Add newlib include directories. + (LDFLAGS): Replace this with + (ALL_LDFLAGS): this to avoid being overridden from higher level + Makefiles. + +Wed Apr 28 17:01:12 1999 Christopher Faylor + + * shared.cc (open_shared): Don't call OpenFileMapping with + a null name pointer. If the name is NULL it can't be opened. + +Fri Apr 23 00:28:38 1999 Christopher Faylor + + * winsup.h: Always clear memory in thread .create method or + suffer uninitialized pointers, etc. + +Wed Apr 21 03:56:54 1999 Christopher Faylor + + * fhandler_console.cc (fhandler_console::fhandler_console): + Set fork_fixup flag to ensure that shared info is duplicated. + (get_tty_stuff): Ensure that tty_stuff is initialized. + (fhandler_console::fixup_after_fork): Really force tc and + tty_stuff initialization. Close console handles or suffer + handle leak. (needs to be fixed) + (fhandler_console::de_linearize): Force tc and tty_stuff + initialization. + +Mon Apr 19 14:54:46 1999 Geoffrey Noer + + * include/cygwin/version.h: Bump CYGWIN_VERSION_API_MINOR to 12. + +Sat Apr 17 15:35:34 1999 Christopher Faylor + + * fhandler_console (fhandler_console::fixup_after_fork): Make sure + that new shared memory for console is initialized. + (fhandler_console::scroll_screen): Set region bottom correctly. + (fhandler_console::write_normal): Fix win95 problem where attribute + was propagated to scrolled region. + * include/wingdi.h: Fix GOBJENUMPROC prototype. + +Wed Apr 7 20:00:00 1999 John Fortin (fortinj@ibm.net) + + * pthread.cc (pthread_suspend): New function. + (pthread_continue): Ditto. + * include/pthread.h: added pthread_suspend and pthread_continue + prototypes. + * cygwin.din: added above functions. + * thread.h: Add 'bool suspended' to class MTitem. Prototype + __pthread_suspend __pthread_continue. + * thread.cc (__pthread_suspend): New function. + (__pthread_continue): New function. + +Sun Apr 4 23:00:00 1999 John Fortin (fortinj@ibm.net) + + * pthread.cc (pthread_join): New function. + (pthread_detach): New function. + * include/pthread.h: added pthread_join and pthread_detach prototypes. + * cygwin.din: added above functions for exports. + * thread.h: Added char joinable to MTitem class. Add void * + return_ptr to ThreadItem class to receive pointer from pthread_exit + and pthread_join. Add __pthread_join and __pthread_detach prototypes. + * thread.cc: Change thread_init_wrapper to set item->return_ptr=ret + and comment out item->used = false. Need to look at this more. + (__pthread_join): New function. + (__pthread_detach): New function. + (__pthread_exit): Implement ( was NOT_IMP ). + * thread.cc (MTinterface::FindNextUnused) : Use joinable != 'Y' as + an additional conditional. We may need to use this info in + pthread_join. + +Mon Apr 5 23:09:06 1999 Christopher Faylor + + * dcrt0.cc (do_exit): Change a variable name to minimize confusion. + * fhandler.h (fhandler_tty): Remove ttyp field in favor of get_ttyp + method. + * fhandler_tty.cc: Use get_ttyp () method to retrieve pointer to + tty device throughout. + (fhandler_tty_master::init): Point console tc at tty's tc so + that they share the same termios structure. + * select.cc (fhandler_tty_common::ready_for_read): Use get_ttyp + method. + * tty.cc (tty::common_init): Ditto. + +Mon Apr 5 00:22:30 1999 Christopher Faylor + + * fhandler_console.cc (fhandler_console::char_command): Make + setting of scrolling region cause the cursor to be placed at + the beginning of the scrolling region. + * thread.cc (__pthread_kill): Defend against item->sigs being + uninitialized. + (__pthread_sigmask): Defened against item->sigs being uninitialized. + +Wed Mar 31 22:52:18 1999 Christopher Faylor + + * dcrt0.cc (dll_crt0): Restore pointer to shared console + terminfo structure. This allows subprocesses to set + sticky console attributes. + * fhandler_console.cc (get_tty_styff): New function. Returns + pointer to shared console terminfo structure, allocating shared + memory if required. + (fhandler_console::fhandler_console): Use get_tty_stuff(). + (fhandler_console::de_linearize): Ditto. + * fork.cc (fork): Save shared console handle for export to + subprocesses. + * spawn.cc (spawn_guts): Ditto. + * shared.cc (open_shared_file_map): Rewrite to use generic + open_shared() function. + (open_shared): New function. Generic shared memory open + used by console and cygwin shared memory. + * shared.h: Define new stuff used by above. + +Wed Mar 31 01:46:23 1999 Christopher Faylor + + * fhandler.h (fhandler_tty): Set tc = ttyp. + * fhandler_tty.cc (fhandler_tty_master::init): Ditto. + (fhandler_tty_common::dup): Ditto. + * tty.cc (tty::common_init): Ditto. + +Wed Mar 31 01:43:06 1999 Christopher Faylor + + * path.cc (mount_info::conv_to_win32_path): Reorganize to + correctly handle //x syntax. + +Tue Mar 30 14:42:05 1999 Christopher Faylor + + * strace.cc (strace_vsprintf): Fix incorrect buffer reference. + +Mon Mar 29 22:46:16 1999 Christopher Faylor + + * debug.cc (__lock): Return value for gcc bug workaround. + (__unlock): Ditto. + * fhandler_tty.cc (fhandler_tty_master::init): Remove extraneous + console initialization. Set termios to sensical values before + initializing the console. + (fhandler_tty_slave): Add some debugging output. + * strace.cc: Conditionalize stuff not required by STRACE_HHMMSS. + (strace_vsprintf): Remove dependency on time() for STRACE_HHMMSS. + +Mon Mar 29 10:50:00 Corinna Vinschen + + * utils/passwd.c (GetPW): Correct cast in call to `NetUserGetInfo'. + +Sun Mar 28 16:54:57 1999 Christopher Faylor + + * fhandler.h: Remove tty_stuff field from fhandler_console + class. Use global instead to allow all console opens to + use same settings. + * fhandler_console.cc: Add new global. + (fhandler_console::tcgetattr): Use new global for initialization. + (fhandler_console::de_linearize): Ditto. + * fhandler_termios.cc (fhandler_termios::fhandler_termios): Don't + reinitialize an already initialized termios. Do not honor + CYGWIN=binmode for console output. It's too confusing. + * shared.h: Add `initialized' field to tty_min. + +Sun Mar 28 01:55:32 1999 Christopher Faylor + + * path.cc (path_prefix_p_): Add defensive code. + (slash_drive_prefix_p): Use macro to detect whether a character + is a path separator. + (mount_info::conv_to_win32_path): Rewrite to correctly handle + relative paths. + * strace.cc (strace_printf): Remove extraneous save of LastError. + * winsup.h (per_thread): Return TlsSetValue value. This seems + to work around a g++ bug. + +Thu Mar 25 13:00:00 Corinna Vinschen + + * fhandler_raw.cc (fhandler_dev_raw::dup): New method. + * fhandler_tape.cc (fhandler_dev_tape::dup(): Ditto. + * fhandler.h: Added prototypes for the formentioned methods. + +Wed Mar 24 23:00:00 Corinna Vinschen + + * fhandler_raw.cc (fhandler_dev_raw::linearize): + Only calling base class implementation now. + * fhandler_raw.cc (fhandler_dev_raw::de_linearize): + Only calling base class implementation and allocating devbuf now. + * fhandler_tape.cc (fhandler_dev_tape::linearize): Erased. + * fhandler_tape.cc (fhandler_dev_tape::de_linearize): Erased. + * fhandler_tape.cc (fhandler_dev_tape::fhandler_dev_tape): + Additional call to `set_cb()'. + * fhandler_floppy.cc (fhandler_dev_floppy::fhandler_dev_floppy): + Ditto. + * fhandler.h: Erased prototypes for linearize and de_linearize + methods of class fhandler_dev_tape. + +Thu Mar 25 14:05:57 1999 Christopher Faylor + + * signal.cc (pause): Make sure that signal has been dispatched + prior to pause returning. + +Wed Mar 24 20:04:21 1999 Christopher Faylor + + Change get_input_handle to get_io_handle throughout. + Change output_handle_ to output_handle throughout. + Use sys/termios.h only where needed. + * Makefile.in: Add new object. + * fhandler.cc (fhandler_base::puts_readahead): New function. + Adds a string to the read ahead buffer. + (fhandler_base::put_readahead): New function. Adds a character + to the read ahead buffer. + (fhandler_base::get_readahead): New function. Gets a character + from the read ahead buffer. + (fhandler_base::peek_readahead): New function. Returns character + at beginning or end of read ahead buffer. + (fhandler_base::set_readahead_valid): Augmented from fhandler.h. + (fhandler_base::eat_readahead): Eat a character from the read + ahead buffer. + (fhandler_base::de_linearize): Reset read ahead info. + (fhandler_base::read): Honor new read ahead mechanism. + (fhandler_base::fhandler_base): Don't set binmode to default + if it has already been explicitly set. + * fhandler.h: Add *BINSET flags to track whether the binary + mode has been turned on or off explicitly. + (fhandler_base): Add elements for new read ahead method. Remove + old `readahead_'. + (fhandler_termios): New base class. + (fhandler_console): Use fhandler_termios base class. + Add new de_linearize method. + (fhandler_tty_common): Rewrite to use fhandler_termios base class. + (fhandler_pty_master): Ditto. + (fhandler_tty_master): Ditto. + * fhandler_console (fhandler_console::read): Rewrite to use functions + from fhandler_termios and read ahead for line editing. + (fhandler_console::read1): Remove. + (fhandler_console::open): Interruptible I/O is now handled in the + read function. Mark this. + (fhandler_console::output_tcsetattr): Use ONLRET to control + binary behavior since it is more closely analgous. + (fhandler_console::input_tcsetattr): Don't set console flags if + there is no change or Windows 95 will eat input. + (fhandler_console::tcsetattr): Use ONLRET to control binary behavior + since it is more closely analgous. + (fhandler_console::fhandler_console): Accomodate fhandler_termios + base class. + (fhandler_console::init): Ditto. + (fhandler_console::igncr_enabled): Ditto. + (fhandler_console::char_command): Use new read ahead method. + (fhandler_console::de_linearize): New function. + * fhandler_serial.cc: Need additional include. + * fhandler_tty.cc (fhandler_tty_master::fhandler_tty_master): + Accomodate fhandler_termios base class. + (fhandler_tty_master::init): Ditto. + (fhandler_tty_master::accept_input): New function. Sends + (possibly line-edited) input to slave. + (process_input): Use line editing capabilities of fhandler_termios + base class when processing input. + (fhandler_tty_slave::open): Accomodate fhandler_termios base class. + (fhandler_tty_slave::tcgetattr): Ditto. + (fhandler_tty_slave::ioctl): Ditto. + (fhandler_pty_master::fhandler_pty_master): Ditto. + (fhandler_pty_master::read): Ditto. + (fhandler_tty_slave::dup): Be more paranoid about setting output + handle in case of error. + * fhandler_tty.h: Accomodate new tty_min base class in tty class. + * hinfo.cc (hinfo::build_fhandler): Send tty 'unit' to constructor. + * select.cc (peek_console): Send resize event to window regardless + of tty setting. Eliminate ReadFile kludge. + * shared.h (tty_min): Rename termios field to avoid conflict. + * tty.cc (create_tty_master): Send tty number to build_fhandler. + (tty::common_init): Remove termios initialization. It's handled + via fhandler_termios, now. + * fhandler_termios: New file. Contains methods for dealing with + fhandler_termios class. + +Wed Mar 24 19:22:04 1999 Christopher Faylor + + * exceptions.cc (call_handler): Reorder to work around + gcc bug. + +Sun Mar 21 21:26:43 1999 Christopher Faylor + + * fhandler_serial.cc (fhandler_serial::raw_read): Protect + against uninitialized variable. Output debug info if + ClearCommError fails. Clear overlapped I/O on error or + signal. + (fhandler_serial::tcflow): Output debug info at start of + routine. + (fhandler_serial::tcsetattr): Add more debugging output. + Avoid re-setting parameters if there has been no change. + Setting parameters via SetCommState seems to cause loss of + input on Windows 9[58]. + +Wed Mar 17 12:56:25 1999 Geoffrey Noer + + * include/winbase.h: Fix AllocateAndInitializeSid proto. + +Tue Mar 16 21:55:12 1999 Christopher Faylor + + * exceptions.cc (handle_exceptions): Always wait for sig_send + to exit or races can result. + +Tue Mar 16 13:04:34 1999 Geoffrey Noer + + * include/cygwin/version.h: Bump CYGWIN_VERSION_API_MINOR to 11. + +Tue Mar 16 15:44:10 1999 Christopher Faylor + + * cygwin.din: Export telldir/seekdir. + +Tue Mar 16 13:50:51 1999 Corinna Vinschen + + * dir.cc: Change unused struct member __d_find_first_called to + __d_position for use in new functions. + (telldir): New function. Returns current position in DIR stream. + (seekdir): New function. Seeks to new position in DIR stream. + +Mon Mar 15 19:17:23 1999 Geoffrey Noer + + * sysdef/comctl32.def: Add InitCommonControlsEx. + +Mon Mar 15 19:45:10 1999 Christopher Faylor + + * dir.cc (mkdir): Remove final slash from a directory if + appropriate or windwows won't create the directory. + * errno.cc: Change text for EAGAIN to something a little + more sensical. + * exceptions.cc (call_handler): Add a debug message. + * fhandler.cc (fhandler_base::open): Don't attempt to set + the position of a com device. + * fhandler_serial.cc (fhandler_serial::raw_read): Reset + overlapped event if not armed. Don't attempt to find out + if characters are available if vmin_. + (fhandler_serial::raw_write): Clear pending I/O when + necessary. + (fhandler_serial::open): Set comm state to current rather + than zeroing. + (fhandler_serial::tcflush): Don't use "queue" as a flag. + TCI* defines are not bit masks. + * select.cc (peek_serial): Add debugging output. + * sigproc.cc (wait_sig): Minor cleanup. + * path.cc (nofinalslash): Make global. + * winsup.h: Ditto. + +Mon Mar 15 16:31:29 1999 Geoffrey Noer + + * include/winnt.h: Add RID defs/protos from MSDN docs. + (SECURITY_*_RID, DOMAIN_*_RID*, etc.) + * include/richedit.h: Add missing SCF_* defines. + * include/commctrl.h: Add missing PBM_ defines, PBRANGE struct. + +Mon Mar 15 12:54:48 1999 Geoffrey Noer + + * Makefile.in: Don't install include/Windows32 since it doesn't + exist any more. + * include/cygwin/version.h: Bump CYGWIN_VERSION_API_MINOR to 10. + +1999-03-12 DJ Delorie + + * net.cc (gethostbyname): support a.b.c.d notation internally, + in case there's no DNS at least partial support is there. + +Wed Mar 10 19:22:46 1999 Geoffrey Noer + + * include/commdlg.h: Add missing PageSetupDlg defines. + +Tue Mar 9 14:28:14 1999 Geoffrey Noer + + * include/*.h: Switch Win32 API header file set to the one written + by Anders Norlander . Headers now + fit the standard Win32 API header layout and are more complete. + These correspond to Anders' headers, version 0.1.5. Please read + sysdef/README for more information. + * include/Windows32/*.h: Delete in favor of above definitions. + + Changes to support the above: + * fhandler_console.cc (fhandler_console::char_command): Add newly + needed cast to DWORD *. + * fhandler_serial.cc (fhandler_serial::raw_read): Make n, minchars + DWORDs. + * fhandler_tty.cc: Include limits.h. + (fhandler_pty_master::doecho): Second arg is now DWORD. + (fhandler_pty_master::process_input_to_sl): Make n, written DWORD. + (fhandler_pty_master::process_slave_outpu): Make n DWORD. + (fhandler_tty_slave::close): Make towrite, n DWORDs. + (fhandler_tty_slave::write): Make n DWORD. + * fhandler.h: Adjust fhandler_pty_master::doecho proto. + * hinfo.cc: Include file reordering. + * malloc.cc: Ditto. + * net.cc: Ditto. + * fhandler_tape.cc (get_ll): Need to reference .u in + LARGE_INTEGER usages. + * ntea.cc: Ditto. + * pinfo.cc: Include limits.h. + * spawn.cc: Ditto. + * uinfo.cc: Ditto. + * uname.cc (uname): sysinfo struct now has anon union. + Adjust sprintf for dwProcessorType being a long now. + * syscalls.cc: Include limits.h and lmcons.h. Throughout, + reference .u in LARGE_INTEGER usages. + (logout): Make rd a DWORD. + + * utils/mkgroup.c: Always include lmaccess.h and lmapibuf.h. + Include stdio.h. + (enum_groups): Adjust for longs in fprintfs. + (main): Ditto. + * utils/mkpasswd.c: Include lmaccess.h and lmapibuf.h. + (enum_users): Adjust for longs in fprintfs. + (main): Ditto. + (enum_local_groups): Ditto. + * utils/passwd.c: Remove many Win32 API defines now in new + Win32 headers. Include lmaccess.h, lmerr.h, lmcons.h, + lmapibuf.h. + (PrintPW): Adjust for longs in fprintfs. + +Wed Mar 3 21:14:45 1999 Christopher Faylor + + * environ.cc (environ_init): Fix off-by-one error in initial + environment allocation. + * fhandler_serial.cc (fhandler_serial::tcflush): Use different + method for flushing since serial handles are now opened for + overlapped I/O. + * select.cc (cygwin_select): Make degenerate case interruptible. + * sigproc.cc (proc_exists): Recognize all kinds of myself pointers + as "existing". + +Tue Feb 16 23:00:48 1999 Christopher Faylor + + * include/Windows32/Functions.h: Correct two #ifndefs that were + switched. + +Mon Feb 15 22:41:54 1999 Christopher Faylor + + * spawn.cc (spawn_guts): Fix incorrect arg length when + constructing new arguments for #!. + +Fri Feb 12 13:25:50 1999 Drew Moseley + + * Makefile.in (install-info): Test for file existence before installing. + +Fri Feb 12 13:17:49 1999 Corinna Vinschen + + * fhandler.cc (fhandler_disk_file::fstat): Handles directories, + returns unique i-node number. + * syscalls.cc (stat_worker): On WinNT, stat_worker calls + fhandler_disk_file::fstat for directories, too. + +1999-02-10 DJ Delorie + + * doc/doctool.c (scan_directory): check for opendir failing, + add closedir. + +Tue Feb 9 13:02:25 1999 Geoffrey Noer + + * utils/mount.cc: Add fixme. + * doc/doctool.c: Correct typo in comment. + +Mon Feb 8 17:29:58 1999 Christopher Faylor + + * include/Windows32/UnicodeFunctions.h: Fix incorrect use of + BOOL -> WINBOOL. + * Windows32/ASCIIFunctions.h: Ditto. + +Fri Feb 5 09:38:25 1999 Christopher Faylor + + * path.cc (mount_info::add_item): Ensure that drive names + are added using X: notation. + +Thu Feb 4 00:28:58 1999 Christopher Faylor + + * path.cc (path_prefix_p_): Recognize ':' as a path separator. + (mount_info::conv_to_posix_path): Detect case where a '/' has + to be added to a path being constructed. + (realpath): Ensure that the full path name is returned. + +Wed Feb 3 22:57:42 1999 Christopher Faylor + + * shared.h (mount_info): Add two separate arrays to track + reverse sorting of win32/posix paths. + * path.cc (sort_by_posix_name): New function. Sorts by + posix path. + (sort_by_native_name): Rename from sort_by_name. + (mount_info::conv_to_win32_path): Use native sort order + when iterating through mount table. + (mount_info::binary_win32_path_p): Ditto. + (mount_info::getmntent): Ditto. + (mount_info::conv_to_posix_path): Use posix sort order + when iterating through mount table. + (sort): Use two arrays to track sorting of mount table. + (mount_info::add_item): Simplify slightly. + +Wed Feb 3 15:17:54 1999 Christopher Faylor + + * cygwin.din: Remove DATA attribute which was erroneously + added to __errno. + +Tue Feb 2 23:10:18 1999 Geoffrey Noer + + * path.cc: Fix comment regarding UNC paths in mount table. + (mount_info::conv_to_win32_path): Add back code to handle + // paths for now. The plan is still to remove it again at + a later date. + (mount_info::slash_drive_to_win32_path): New. Convert a // + path to a Win32 path. Bring back from among the recently departed + path functions. + * shared.h: Add mount_info proto for slash_drive_to_win32_path. + +Tue Feb 2 22:52:43 1999 Geoffrey Noer + + * include/lmaccess.h: Add stub. + * include/shlobj.h: Add stub. + +Tue Feb 2 22:34:06 1999 Christopher Faylor + + * shared.h: Change magic number associated with fork/exec + information as a temporary measure to eliminate strange + core dumps with multiple versions of cygwin1.dll. + +1999-02-02 Brendan Kehoe + + * Makefile.in (readme.txt): Add missing -I$(srcdir)/doc. + +Tue Feb 2 01:10:31 1999 Geoffrey Noer + + * sysdef/*: Replace all files with new ones by Anders + Norlander . Please read sysdef/README + for more information. + +Mon Feb 1 14:55:11 1999 Christopher Faylor + + * path.cc (sort_by_name): Sort based on length of native_path + to ensure maximal match when converting from native -> UNIX. + * cygwin.din: Make more data variables DATA. + +Mon Feb 1 13:31:43 1999 Geoffrey Noer + + * fhandler_tape.cc: Change all fhandler_tape private functions + to be named foo_bar_baz-style instead of FooBarBaz. Add some + parens around logical ors/ands for clarity. Respace. + * fhandler.h: Change protos here in light of above. + +Thu Jan 28 11:00:00 Corinna Vinschen + + * errno.cc: Support for Windows errors ERROR_CRC and ERROR_NO_READY + and for error ENOMEDIUM. + +Wed Jan 27 01:05:39 1999 Christopher Faylor + + * dir.cc (rmdir): Correct errno setting when attempting to rmdir + a non-directory. + +Tue Jan 26 17:36:12 1999 Geoffrey Noer + + * registry.cc (reg_key::build_reg): Add FIXME. + +Tue Jan 26 01:30:48 1999 Geoffrey Noer + + * path.cc (mount_info::from_registry): Import old v1 mounts + only if current mount layout doesn't exist yet in both user + and system areas (when had_to_create_mount_areas == 2). + (mount_info::import_v1_mounts): New, was upgrade_v1_mounts. + (mount_info::from_v1_registry): Add missing comma in reg_key + creation call. + (mount_info::init): Init had_to_create_mount_areas to zero. + * external.cc (cygwin_internal): Fix reference to + upgrade_v1_mounts. + * shared.h: Change upgrade_v1_mounts proto to import_v1_mounts. + Add new had_to_create_mount_areas variable in mount_info class. + * registry.cc (reg_key::build_reg): Increment + had_to_create_mount_areas whenever we create a new mount area. + + * include/sys/mount.h: Don't define MOUNT_EXEC until we actually + implement this functionality. + + * utils/mount.cc (do_mount): Print warning messages after the + actual mount attempt so we don't see warnings when mount fails. + (usage): Change name of --upgrade-old-mounts flag to + --import-old-mounts. + (main): Ditto. + +Mon Jan 25 23:56:50 1999 Geoffrey Noer + + * errno.cc (seterrno_from_win_error): New. Given a Windows + error code, set errno accordingly. + (seterrno): Just call seterrno_from_win_error with the + error code returned by a call to GetLastError. + * winsup.h: Define __seterrno_from_win_error. + * path.cc: Clean up more function description comments. + (mount_info::add_reg_mount): Don't need res, just return the + right values. + (del_reg_mount): Return int, not void. If we're deleting a + system mount, set errno to EACCES and return -1 if we don't + have a valid key handle. If mount delete fails, set errno + accordingly and return -1. Otherwise, return zero for success. + (cygwin_umount): Delete mount from registry first, only remove + from internal table if successful. + * shared.h: Make del_reg_mount proto return int. + +Mon Jan 25 22:40:15 1999 Geoffrey Noer + + * path.cc (mount_info::mount_slash): Add mount to registry + first, only add to internal table if successful. + (mount_info::conv_to_posix_path): Ditto. + (mount): Ditto. + (mount_info::add_reg_mount): Return int, not void. If we're + writing a system mount, first check if we have a valid key handle. + If we don't, set errno to EACCES and return -1. Otherwise return + zero for success. + * shared.h: Make add_reg_mount proto return int. + +Mon Jan 25 20:40:26 1999 Geoffrey Noer + + * path.cc (mount_info::init): Don't read automount info here. + (mount_info::from_registry): Read it here instead. Also, read + system registry info in KEY_READ mode. + (mount_info::read_mounts): Read mount info with KEY_READ access + permissions. + +Mon Jan 25 19:12:31 1999 Geoffrey Noer + + * path.cc: Improve several function description comments. + (mount_info::init): Read automount information from the + registry before potentially automounting slash. + (mount_info::conv_to_posix_path): Create automount with + automount_flags flags. + (mount): Now flags is more than just a toggle so we + must check it in a different manner. And simply check + MOUNT_AUTO as the indicator. If we want to change the + automount_prefix, also change automount_flags as appropriate. + Fix args to syscall_printf. + (write_automount_info_to_registry): New. Was + write_automount_prefix_to_registry. + (read_automount_info_from_registry): New. Was + read_automount_prefix_from_registry. + * shared.h: Adjust protos for function renames just mentioned. + * include/sys/mount.h: Delete MOUNT_CHANGE_AUTOMOUNT_PREFIX + since we don't really need it. + * utils.cc (mount): Pass MOUNT_AUTO as indicator of desire to + change automount prefix. + (show_mounts): Change spacing so there's room for "system,auto" + in Type column. + +Mon Jan 25 13:17:40 1999 Geoffrey Noer + + * path.cc: Change all references from "automount root" to + "automount prefix", avoiding potential nomenclature confusion + with the root of the file system. + (read_automount_prefix_from_registry): New. Was + read_automount_root_from_registry. + (read_automount_prefix_from_registry): New. Was + read_automount_root_from_registry. Also read the default + flags for automounts from registry at the same time. + (write_automount_prefix_to_registry): New. Was + write_automount_root_to_registry. Also set automount flags + in registry using new auto_flags arg. + (mount): Add flags arg to write_automount_prefix_to_registry call. + * shared.h: Add automount_flags variable to mount_info class. + Adjust protos for function renames listed above. + + * include/sys/mount.h: Comment out MOUNT_MIXED and MOUNT_SILENT + whose values could be reused now that we're using a new mount + layout. Change MOUNT_CHANGE_AUTOROOT to + MOUNT_CHANGE_AUTOMOUNT_PREFIX. + + * utils/mount.cc (change_automount_prefix): New. Was + change_automount_root. Add new flags argument so it's possible + to change the default automount flags. + (main): Option name change from --change-automount-root to + --change-automount-prefix. + (usage): Update in light of option changes. + * utils/umount.cc (remove_all_automounts): Also need to check + for mnt_type looking like "system,auto" now that it's possible + for automounts to be located in the system registry. + +Mon Jan 25 08:59:04 1999 Christopher Faylor + + * spawn.cc (linebuf::add): Ensure that there is always + enough space for line being added. Always null terminate. + (linebuf::prepend): Ditto. + +Sat Jan 23 01:30:16 1999 Geoffrey Noer + + Make mount.exe able to upgrade mounts: + * external.cc: Fix file description. + (cygwin_internal): Handle CW_READ_V1_MOUNT_TABLES case, in + which case call upgrade_v1_mounts to upgrade old registry + area mounts. + * external.h: Add CW_READ_V1_MOUNT_TABLES to enum. + * shared.h: Make upgrade_v1_mounts public. + + * utils/mount.cc: Include winsup.h, external.h, undef errno since + it's defined by winsup.h. + (usage): Add --upgrade-old-mounts option to usage info. + (main): Handle --upgrade-old-mounts flag by calling + cygwin_internal with the right constant. + +Sat Jan 23 00:40:17 1999 Geoffrey Noer + + First pass at mount table backwards compatibility with v1 + mounts: + * path.cc (mount_info::from_registry): For now, upgrade from + old v1 mount registry area if nmounts==0 after reading new mount + areas. + (mount_info::read_v1_mounts): New function. Given a regkey, read + the mounts in the old v1 registry layout corresponding to the key. + A "which" arg tells us which registry we're reading so that we + can include MOUNT_SYSTEM when reading old system mounts. + (mount_info::from_v1_registry): New function. Retrieve old v1 + mount table area mounts. + (mount_info::upgrade_v1_mounts): New function. Retrieve old + v1 mounts, add them to the current registry mount location. + (mount_info::to_registry): New function. For every mount in + the internal mount table, add it to the correct registry. + * shared.h: Add protos for new mount_info functions -- + from_v1_registry, read_v1_mounts, upgrade_v1_mounts, to_registry. + Don't need class name in protos for + build_automount_mountpoint_path, write_automount_root_to_registry, + and read_automount_root_from_registry. + +Fri Jan 22 22:45:07 1999 Christopher Faylor + + * spawn.cc (spawn_guts): Arg 2 missing from special case + command/cmd handling. + +Fri Jan 22 22:40:32 1998 Corinna Vinschen + + * fhandler_raw.cc (fhandler_dev_raw::raw_read): bytes_to_read + corrected to multiple of 512 bytes instead of multiple to + devbufsiz. Insert break on ReadFile returned 0 Bytes. + +Fri Jan 22 15:50:49 1999 Christopher Faylor + + * mkvers.sh: Fix handling of CVS tag output. + * errno.cc: Mark exported data as __declspec(dllexport). + * times.cc: Ditto. + * fhandler.cc (fhandler_base::open): Yet another stab + at correcting handling of binmode/textmode ramifications. + * path.cc (hash_path_name): Make /. == '' for purposes + of generating a hash. + +Fri Jan 22 11:45:28 1999 Christopher Faylor + + * path.cc (slash_unc_prefix_p): Generalize to allow + either type of slash. + (mount_info::add_item): Don't disallow UNC specs in + the mount table. + * utils/Makefile.in: Always use current stub library. + +Fri Jan 22 08:52:36 1999 Christopher Faylor + + * environ.cc (regopt): Use correct registry key for Program + Options given new mount layout. + * cygwin.din: export __mb_cur_max from newlib. + +Thu Jan 21 16:52:20 1999 Geoffrey Noer + + * path.cc (cygwin_split_path): Adjust two FIXMEs. + (mount_info::write_automount_root_to_registry): Return int, + 0 on success, -1 if path is problematic. + (mount): Check return of write_automount_root_to_registry + and act appropriately. Do syscall_printf when adjusting automount + as well as regular mount. + * shared.h: mount_info::write_automount_root_to_registry now + returns an int. + * utils/mount.cc (main): don't sanity-check automount path + here, instead let the DLL take care of that. + +Thu Jan 21 17:12:26 1999 Christopher Faylor + + * spawn.cc (spawn_guts): Rewrite argument handling for + cleaner, one-pass operation. + (linebuf::add): New method for adding arguments to end + of the argument list. + (linebuf::prepend): New method for pushing arguments on + the front of the argument list. + +Wed Jan 20 19:06:30 1999 Geoffrey Noer + + * path.cc (mount_info::mount_slash): only call add_reg_mount if + add_item succeeded. + (mount_info::add_item): Fail if native path doesn't start with + : or if posix path doesn't start with a slash. + +Wed Jan 20 19:06:30 1999 Geoffrey Noer + + * fhandler_raw.cc: Correct copyright date, reformat. + * fhandler_floppy.cc: Ditto. + * fhandler_tape.cc: Ditto. + +Wed Jan 20 17:54:02 1999 Geoffrey Noer + + Remove /// support. Add support for automounts in + user registry area. + * path.cc: Rewrite, reformat docs at top in light of removing + /// support and new automount support. Add more function + description comments. + (slash_drive_prefix_p): Remove function. + (build_slash_drive_prefix): Ditto. + (slash_drive_to_win32_path): Ditto. + (mount_info::init): After everything else, read the automount_root + by calling read_automount_root_from_registry(). + (mount_info::mount_slash): Automount slash with MOUNT_AUTO. + (mount_info::conv_to_win32_path): Remove /// support code. + (mount_info::build_automount_mountpoint_path): Construct the name + of an automount POSIX path, given automount_root and the Win32 + path that needs to be automounted. + (mount_info::conv_to_posix_path): Automount missing drive letter + and call conv_to_posix_path again if path isn't covered by the + mount table but starts with ":". + (mount_info::read_automount_root_from_registry): New function. + Read in the value of automount_root from the current_user + registry mount area. If there isn't one, use default of + "/cygdrive" and write that to the registry by calling + write_automount_root_to_registry(). + (write_automount_root_to_registry): Write a value of + automount_root to the user registry area. + (mount_info::del_item): Add new flags arg to specify which + registry to delete the mount from. + (mount_info::del_reg_mount): Ditto. + (mount_item::getmntent): Use mount_info mnt_foo strings to store + strings passed back in the mntent struct. Otherwise if you + delete a mount item while using getmntent, the pointer may + change on the user. Add ",auto" to mnt_type if MOUNT_AUTO flag is + set. + (mount): Add support to set auto_root to path if flags is set + to the special MOUNT_CHANGE_AUTOROOT flag otherwise do the normal + thing. + (umount): Call cygwin_umount with flags value of 0. + (cygwin_umount): New exported function. Same as umount but + takes an additional flag argument that specifies which registry + area from which umount should remove the mount point. + * cygwin.din: Export the cygwin_umount call. + * shared.h (mount_info): Add public automount_root string. + Add public proto for write_automount_root_to_registry(). + Add private protos for build_automount_mountpoint_path() and + read_automount_root_from_registry(). Add flags arg to del_item + and del_reg_mount protos. Add strings used by getmntent et al + including mnt_type, mnt_opts, mnt_fsname, mnt_dir. (Can't just + pass back pointers to mount paths because they may change as + a result of a umount call. + + * include/sys/mount.h: Add new MOUNT_AUTO and + MOUNT_CHANGE_AUTOROOT flags. Add proto for cygwin_umount + function. + * include/cygwin/version.h: Bump CYGWIN_VERSION_API_MINOR to 9. + + * utils/mount.cc: Change missing_dir_warning flag to force + and init to FALSE instead of TRUE. Throughout swap names and + setting as appropriate. Include errno.h. + (usage): Remove info about --reset. Add info for new + --change-automount-root option. + (main): Don't check the --reset flag. Call change_automount_root + if invoked with --change-automount-root. Only call do_mount + if !mount_already_exists unless force flag is TRUE. Otherwise + fail. + (mount_already_exists): New helper function. Returns 1 + if the mount point of the same registry location is already + mounted. + (reset_mounts): Remove function. + (change_automount_root): New function that changes the + automount root in the registry via Cygwin by passing the new + path to mount() with the special MOUNT_CHANGE_AUTOROOT flag. + * utils/umount.cc: Add progname, set to argv[0]. Include string.h. + (usage): New function to print out usage info. + (main): Loop through argcs. Handle new flags to remove all mounts + of a specific type including --remove-all-mounts, + --remove-user-mounts, --remove-system-mounts, and + --remove-auto-mounts. New flag to specify removing a system + mount. Call cygwin_umount instead of umount, providing flags + as appropriate. + (remove_all_mounts): New function. Remove all mounts in + both tables. + (remove_all_automounts): Remove all mounts marked auto. + (remove_all_user_mounts): Remove all user mounts, including auto + mounts. + (remove_all_system_mounts): Remove all system mounts. + + * registry.cc (reg_key::get_string): Fix description comment. + * strace.cc: Minor reformatting. + +Wed Jan 20 17:49:20 1999 DJ Delorie + + * fhandler.cc (raw_write): Make sure that a disk full error + is properly signalled. + (fhandler_base::open): Only tapes are read/write, cd-roms may be + read-only (from Corinna). + +Wed Jan 20 10:46:48 Corinna Vinschen + + [applied by DJ Delorie ] + + * fhandler_raw.cc (fhandler_dev_raw::writebuf): Writes only + as much bytes as needed, instead of full buffer size. + + * fhandler_tape.cc (fhandler_dev_tape::close): Corrected error + handling in case of error while writing buffer content to dev. + + * fhandler_floppy.cc (fhandler_dev_floppy::close): Ditto. + + * fhandler_tape.cc (fhandler_dev_tape::writebuf): Delete function + + * fhandler_floppy.cc (fhandler_dev_floppy::writebuf): Ditto. + + Patch suggested by Ron Parker + * path.cc (mount_info::conv_to_win32_path): Change the + recognition of UNC devices, to support also paths of type + `\\.\UNC\'. + + * fhandler_tape.cc (fhandler_dev_tape::close): Fixed rewind + to block 1 instead of block 0 on rewind tapes in case of + uncaught signal (e.g. Ctrl-C). + + * path.cc (get_raw_device_number): New static function, + checks path for windows raw device. + + * path.cc (get_device_number): Change for recognition of + windows raw device paths by calling `get_raw_device_number()'. + + * path.h: Change prototype for `get_device_number()'. + + * Makefile.in: Added file 'fhandler_raw.o' to dependencies. + + * include/cygwin/rdevio.h: New file to support ioctl commands + on random access raw devices. At the time only get/set buffersize + for raw_read/raw_write. + + * fhandler.h: Change class hierarchy. 'fhandler_dev_floppy' + and 'fhandler_dev_tape' are now derived classes of + 'fhandler_dev_raw', which is derived from 'fhandler_base'. + + * fhandler_raw.cc: New file for implementation of class + 'fhandler_dev_raw' which is now base class for support of + mass storage raw devices. + + * fhandler_dev_tape.cc: Rewritten. + + * fhandler_dev_floppy.cc: Rewritten. Now supporting correct + lseek (seeking only to positions on 512 byte boundaries, + like supported from WinNT). + + * Makefile.in: Added file 'fhandler_floppy.o' to dependencies. + + * fhandler_floppy.cc: New file to support raw devices + including multi volume operations. + + * fhandler.cc: Delete 'fhandler_dev_floppy' implementation. + + * fhandler.h: Extend class fhandler_dev_floppy. + + * fhandler_tape.cc: Rewrite for correct support + of multi volume operations. Supports Setmarks now. + + * fhandler.h: Add private method `clear()' to class + fhandler_dev_tape. + + * Makefile.in: Add file 'fhandler_tape.o' to dependencies. + + * path.cc (mount_info::conv_to_win32_path): Change the + recognition of UNC devices, to support devices, which + are not partitions, too. + + * fhandler.h: Extend struct 'fhandler_dev_tape' for tape support. + Add method 'fstat' to fhandler_dev_floppy to get S_ISBLK(). + + * fhandler.cc (fhandler_base::open): In any case 'access_' has to + be GENERIC_READ | GENERIC_WRITE for tapes, to allow tape control. + No 'SetFilePointer' for tapes. + + * fhandler_tape.cc: New file to support rewind (/dev/stX) and + norewind (/dev/nstX) tapes. Supports ioctl() calls, described + in... + + * include/sys/mtio.h, include/cygwin/mtio.h: New header files + for tape support. + +Sat Jan 16 21:59:36 1999 Geoffrey Noer + + * registry.h: Delete; move contents into shared.h except for + posix_path_p() routine which disappears. + * {Makefile.in, environ.cc, net.cc, path.cc, registry.cc, + shared.cc}: No longer include registry.h. + * dcrt0.cc (dll_crt0_1): don't check posix_path_p() + + * include/mntent.h (struct mntent): Drop const from strings. + * include/sys/mount.h: Change MOUNT_GLOBAL flag that nobody has + used yet to MOUNT_SYSTEM. Add MOUNT_EXEC flag. + * include/cygwin/version.h: Bump CYGWIN_VERSION_MOUNT_REGISTRY to + 2. Change CYGWIN_INFO_CYGWIN_REGISTRY_NAME to "Cygwin". + Change CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME to "mounts v2". + + * registry.cc (reg_key::reg_key): Default key doesn't end in + "mounts" any more. + (reg_key::kill): Return error code from RegDeleteKeyA. + * path.cc: Reformat, reorder functionality, add comments + throughout. + (mount_info::init): Automount slash if it's not already mounted. + (mount_info::mount_slash): New private helper function. + (mount_info::binary_win32_path_p): Check flags to determine + if mount is binary or not, not binary_p. + (mount_info::read_mounts): Remove unneeded access argument. Use + RegEnumKeyEx to enumerate mount points in current registry + location where each key name returned is a posix_path mount + location. Use a subkey reg_key to read the posix_path's + corresponding native_path and flags. + (mount_info::from_registry): Access HKEY_LOCAL_MACHINE registry + with full access privs (which will fail if not administrator). + Fix registry path used to initialize HKEY_LOCAL_MACHINE reg_key. + (mount_info::to_registry): Delete function. Replaced by + add_reg_mount. + (mount_info::add_reg_mount): New function which adds a specified + mount point to the registry. + (mount_info::del_reg_mount): New function which deletes the + posix_path argument from the highest priority registry table it + can (first user, than system-wide). + (sort_by_name): If the two posix_paths are the same, then + differentiate between them looking at MOUNT_SYSTEM in their flags. + (mount_info::add_item): Also make sure that neither path is NULL. + Never claim mount point is busy: replace an existing posix_path + as long as it came from the same registry location. + (mount_info::del_item): Also make sure that neither path is NULL. + (mount_item::getmntent): Use mnt_type field to store user vs. + system registry location string. Cast all strings to char *. + Handle flags instead of binary_p. Change names of strings + returned in mnt_opts field. + (mount_item::init): Set flags, instead of dealing with binary_p + and silent_p. + (mount): Call add_reg_mount instead of to_registry. + (umount): Call del_reg_mount instead of to_registry. + (path_conv::path_conv): Remove reference to silent_p. + * path.h (path_conv): Remove silent_p. + + * utils/mount.cc: Add -s to usage (was a commented-out -g). + Or in MOUNT_SYSTEM if -s flag given. Add similar commented-out + support for future MOUNT_EXEC flag that will be added with -e. + (reset_mounts): Automount slash with zero for flags, not + MOUNT_SILENT which we no longer use for anything. + * utils/umount.cc: Also print out usage if the first argument + starts with a dash. + +Fri Jan 15 11:27:51 1999 DJ Delorie + + * strace.cc: add macros to protect against buffer overruns + (strace_printf): increase buffer from 6000 to 1000 to build devo + * include/sys/strace.h: allow -DNOSTRACE again + +Fri Jan 15 11:27:51 1999 DJ Delorie + + * dcrt0.cc (alloc_stack): add 16384 to work around Win95 page + fault during builds + * fork.cc (fork): try various things to avoid page faults during + win95 builds. + +Fri Jan 15 11:18:23 1999 DJ Delorie + + * fhandler.cc (raw_write): check for disk full. + +Fri Jan 15 11:18:23 1999 DJ Delorie + + * init.cc (dll_entry): if the DLL is being LoadLibrary'd, + initialize some things. + * heap.cc (_sbrk): detect uninitialized heap and initialize + * dcrt0.cc (user_data): initialize to something useful. + (do_global_ctors): make global for init.cc + +Thu Jan 14 02:16:44 1999 Geoffrey Noer + + * dll_init.cc: Add missing FIXME in comment. + * fhandler_console: Ditto. + +Thu Jan 14 00:53:25 1999 Christopher Faylor + + * spawn.cc (iscmd): New function. + (spawn_guts): Treat command /c and cmd /c as special + cases. Don't quote arguments to these programs if + there are exactly three arguments. + * dcrt0.cc (dll_crt0_1): Initialize exceptions prior + to fork to allow forked processes to "dump core". + * errno.cc (seterrno): No need for this to be extern "C". + * winsup.h: Ditto. + +Wed Jan 13 19:06:08 1999 Geoffrey Noer + + * registry.cc: Add comments corresponding to various reg_key + functions, minor reformatting. + (reg_key::reg_key): Delete already-commented-out function + +Wed Jan 13 15:41:34 1999 DJ Delorie + + * errno.cc (_sys_errlist): Add "extern" to work around new gcc + restrictions. + +Mon Jan 11 14:56:27 1999 Christopher Faylor + + * spawn.cc (spawn_guts): Fix problem with #! and relative + directories. + +Mon Jan 11 09:00:29 1999 Christopher Faylor + + * fhandler_console.cc (fhandler_console::read1): Handle EOF as a + specific case. + +Sun Jan 10 23:44:22 1999 Christopher Faylor + + * fhandler.h: Define __fmode for convenience. Use throughout. + * environ.cc (parse_options): Use O_TEXT when nobinmode. + * fhandler.cc (fhandler_base::open): Don't honor __fmode + when disk file. Default to O_TEXT if no mode is specified. + (fhandler_base::fhandler_base): Don't honor __fmode when disk + file. Otherwise default to O_BINARY. + * pipe.cc (make_pipe): Default to O_BINARY if no mode specified. + +Sat Jan 9 20:58:34 1999 Christopher Faylor + + * Makefile.in: Correct previously messed up patch. + * thread.h: Add back a needed include. + * sigproc.cc (sigproc_init): Work around problem with older + compilers. + * wait.cc (wait4): Ditto. + * winsup.h (per_thread_waitq): Ditto. + * include/Windows32/CommonFunctions.h: Temporary change to + work around problems with older compilers. + +Fri Jan 8 12:53:53 1999 Christopher Faylor + + * environ.cc (parse_options): Add "forkchunk" debug setting. + Takes a value which is used to limit the size of individual memory + copies in a fork. + * fork.cc (fork_copy): Rewrite slightly to allow copying of + individual chunks of memory rather than all in one gulp. + Controlled by chunksize global variable. + +Thu Jan 7 22:02:18 1999 Christopher Faylor + + patch from Corinna Vinschen : + * utils/passwd.c: New file. + * utils/Makefile.in: Add dependencies for passwd. + * syscalls.cc (chmod): Change permission checking in case + of readonly test. + (stat_dev): Change default permission bits to allow writing + for all users. + (chown): Retry LookupAccountName with username set to domain\\username, + if returned SID-Type is not SidTypeUser. + + +Thu Jan 7 17:50:49 1999 Christopher Faylor + + * fhandler.cc (fhandler_base::set_name): Fix bug which + disallowed '%' in a file name. + +Thu Jan 7 00:21:41 1999 Geoffrey Noer + + * path.cc: Add comments. + * path.h: Correct file description comment. + +Tue Jan 5 16:07:15 1999 Christopher Faylor + + * fhandler_serial.cc (fhandler_serial::raw_read): Be more defensive + about not calling problematic functions when the overlapped I/O is + armed. Reset the overlapped event prior to calling read or suffer + an "operation aborted". + * select.cc (peek_serial): Ditto. + +Mon Jan 4 15:16:22 1999 Geoffrey Noer + + Eliminate warnings: + * utils/mount.cc (show_mounts): make format a const char *. + * utils/ps.cc (main): make literal strings const char *s. + * utils/cygpath.cc (long_options): cast literal strings to char *s. + (main): + +Sun Jan 3 20:46:12 1999 Christopher Faylor + + * select.cc (peek_console): Remove #if 0 around NT code workaround. + +Sat Jan 2 00:04:01 1999 Christopher Faylor + + * Makefile.in: Remove include directories made obsolete by + recent changes to mmap.cc. Also remove libraries that appear + to be unnecessary for linking. + * mkvers.sh: Put contents of .snapshot-date, if available, into + the DLL. + +Fri Jan 1 22:44:49 1999 Christopher Faylor + + * fhandler.h (fhandler_serial): Add flag to track state of + overlapped serial I/O. Add overlapped_setup method for common + setup of overlapped structure. + * fhandler_serial.cc (fhandler_serial::overlapped_setup): New + method. Sets up the overlapped structure for overlapped serial I/O. + (fhandler_serial::raw_read): Use overlapped_armed flag to avoid + calling functions which perform overlapped operations if overlapped + I/O is in already progress. This should only be the case if a + previous operation was interrupted or select has detected serial I/O. + (fhandler_serial::open): Use overlapped_setup. + (fhandler_serial::fixup_after_fork): Ditto. + (fhandler_serial::de_linearize): Ditto. + (fhandler_serial::dup): Ditto. + (fhandler_serial::tcsetattr): Fix typo which caused IGNPAR + to be ignored. + * hinfo.cc (hinfo::select_read): Set saw_error to zero explicitly + to avoid spurious reporting of select errors. + (hinfo::select_write): Ditto. + (hinfo::select_except): Ditto. + * select.cc (peek_serial): Use overlapped_armed to avoid calling + functions which perform overlapped operations if overlapped I/O + is already in progress. diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in new file mode 100644 index 000000000..c7a5cab33 --- /dev/null +++ b/winsup/cygwin/Makefile.in @@ -0,0 +1,341 @@ +# Makefile.in for Cygwin. +# Copyright 1995, 1996, 1997, 1998, 1999, 2000 Cygnus Solutions. +# +# This file is part of Cygwin. +# +# This software is a copyrighted work licensed under the terms of the +# Cygwin license. Please consult the file "CYGWIN_LICENSE" for +# details. + +# This makefile requires GNU make. + +CONFIG_DIR:=@srcdir@/config/@CONFIG_DIR@ +SHELL:=@SHELL@ +VPATH:=@srcdir@:$(CONFIG_DIR):@srcdir@/regexp +srcdir:=@srcdir@ +objdir:=. + +target_alias:=@target_alias@ +build_alias:=@build_alias@ +host_alias:=@host_alias@ +prefix:=@prefix@ + +program_transform_name:=@program_transform_name@ +exec_prefix:=@exec_prefix@ +bindir:=@bindir@ +libdir:=@libdir@ +ifeq ($(target_alias),$(host_alias)) +ifeq ($(build_alias),$(host_alias)) +tooldir:=$(exec_prefix) +else +tooldir:=$(exec_prefix)/$(target_alias) +endif +else +tooldir:=$(exec_prefix)/$(target_alias) +endif +datadir:=@datadir@ +infodir:=@infodir@ +includedir:=@includedir@ + +INSTALL:=@INSTALL@ +INSTALL_PROGRAM:=@INSTALL_PROGRAM@ + +# +# --enable options from configure +# +MT_SAFE = @MT_SAFE@ +DEFS = @DEFS@ + +CC:=@CC@ +# FIXME: Which is it, CC or CC_FOR_TARGET? +CC_FOR_TARGET:=$(CC) +CFLAGS:=@CFLAGS@ +CXXFLAGS:=@CXXFLAGS@ + +# For linking mount, etc. crt0.o isn't accessable in a fresh build. +EXE_LDFLAGS:=@EXE_LDFLAGS@ + +AR:=@AR@ +AR_FLAGS:=qv +RANLIB:=@RANLIB@ +LD:=@LD@ +DLLTOOL:=@DLLTOOL@ +WINDRES:=@WINDRES@ +AS:=@AS@ + +# +# Include common definitions for winsup directory +# +include $(srcdir)/../Makefile.common + +INSTALL_DATA:=$(SHELL) $(updir1)/install-sh -c + +COMPILE_CC+=-D__INSIDE_CYGWIN__ + +@SET_MAKE@ + +# Setup the testing framework, if you have one +EXPECT = `if [ -f $${rootme}/../../expect/expect$(EXEEXT) ] ; then \ + echo $${rootme}/../../expect/expect$(EXEEXT) ; \ + else echo expect ; fi` + +RUNTEST = `if [ -f $${srcdir}/../dejagnu/runtest ] ; then \ + echo $${srcdir}/../dejagnu/runtest ; \ + else echo runtest; fi` +RUNTESTFLAGS = + +ifdef MT_SAFE +MT_SAFE_HEADERS:=thread.h +MT_SAFE_OBJECTS:=pthread.o thread.o +endif + +# Parameters used in building the cygwin.dll. +# We build as new-cygwin.dll and rename at install time to overcome +# native rebuilding issues (we don't want the build tools to see a partially +# built cygwin.dll and attempt to use it instead of the old one). + +DLL_NAME:=cygwin1.dll +LIB_NAME:=libcygwin.a +DEF_FILE:=cygwin.def +DLL_ENTRY:=@DLL_ENTRY@ + +LIBGMON_A:=libgmon.a +GMON_START:=gcrt0.o + +# Some things want these from libc, but they have their own static +# data which apps can get to, which is a pain in the dll, so we +# include them directly into the library. + +LIBCOS:=libccrt0.o libcmain.o getopt.o dll_entry.o dll_main.o + +# Build all source files in the config directory + +EXTRA_DLL_OFILES:=${addsuffix .o,${basename ${notdir ${wildcard $(CONFIG_DIR)/*.c}}}} + +EXTRA_OFILES=$(bupdir1)/libiberty/random.o $(bupdir1)/libiberty/strsignal.o + +DLL_IMPORTS:=$(w32api_lib)/libkernel32.a $(w32api_lib)/libadvapi32.a + +DLL_OFILES:=assert.o dcrt0.o debug.o delqueue.o dir.o dlfcn.o dll_init.o \ + environ.o errno.o exceptions.o exec.o external.o fcntl.o fhandler.o \ + fhandler_console.o fhandler_serial.o fhandler_termios.o fhandler_tty.o \ + fhandler_windows.o fhandler_raw.o fhandler_floppy.o fhandler_tape.o fhandler_zero.o \ + fork.o glob.o grp.o heap.o hinfo.o init.o ioctl.o localtime.o malloc.o \ + mmap.o net.o ntea.o passwd.o path.o pinfo.o pipe.o regexp.o regerror.o \ + regsub.o registry.o resource.o scandir.o security.o select.o shared.o \ + signal.o sigproc.o smallprint.o spawn.o strace.o strsep.o sync.o \ + syscalls.o sysconf.o syslog.o termios.o times.o tty.o uinfo.o uname.o \ + wait.o window.o \ + $(EXTRA_DLL_OFILES) $(EXTRA_OFILES) $(MT_SAFE_OBJECTS) + +GMON_OFILES:= gmon.o mcount.o profil.o + +LD_STUFF=--dll $(DLL_OFILES) version.o winver.o $(DLL_IMPORTS) $(LIBM) $(LIBC) $(LIBGCC) -e $(DLL_ENTRY) --image-base=0x61000000 + +.PHONY: all force dll_ofiles install + +.SUFFIXES: +.SUFFIXES: .c .cc .def .a .o + +all: new-$(DLL_NAME) $(LIBGMON_A) $(LIB_NAME) cygrun.exe force + +force: + +install: all + $(INSTALL_DATA) new-$(DLL_NAME) $(bindir)/$(DLL_NAME) ; \ + $(INSTALL_DATA) $(LIB_NAME) $(tooldir)/lib/$(LIB_NAME); \ + cd $(srcdir); \ + for sub in `find include -name '[a-z]*' -type d -print | sort`; do \ + for i in $$sub/*.h ; do \ + $(INSTALL_DATA) $$i $(tooldir)/$$sub/`basename $$i` ; \ + done ; \ + done + +clean: + -rm -f *.o *.dll *.a *.exp junk *.base version.cc regexp/*.o winver_stamp + +maintainer-clean realclean: clean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + -rm -fr configure + +# Rule to build libcygwin.a + +$(LIB_NAME): $(DEF_FILE) $(LIBCOS) + $(DLLTOOL) --as=$(AS) --dllname $(DLL_NAME) --def $(DEF_FILE) --output-lib temp.a + $(AR) rcv temp.a $(LIBCOS) + mv temp.a $(LIB_NAME) + +# Rule to make stub library used by "make check" + +new-$(LIB_NAME): $(DEF_FILE) $(LIBCOS) + $(DLLTOOL) --as=$(AS) --dllname new-$(DLL_NAME) --def $(DEF_FILE) --output-lib temp.a + $(AR) rcv temp.a $(LIBCOS) + mv temp.a new-$(LIB_NAME) + +# Rule to build cygwin.dll + +new-$(DLL_NAME): $(DLL_OFILES) $(DEF_FILE) $(DLL_IMPORTS) $(LIBC) $(LIBM) Makefile winver_stamp + $(LD) -shared -o $@ -e $(DLL_ENTRY) cygwin.def $(DLL_OFILES) version.o \ + winver.o $(DLL_IMPORTS) $(LIBM) $(LIBGCC) $(MALLOC_OBJ) $(LIBC) $(LIBGCC) + +dll_ofiles: $(DLL_OFILES) + +$(LIBGMON_A): $(GMON_OFILES) $(GMON_START) + $(AR) rcv $(LIBGMON_A) $(GMON_OFILES) + +version.cc winver.o: winver_stamp + @ : + +winver_stamp: mkvers.sh include/cygwin/version.h winver.rc $(DLL_OFILES) + @echo "Making version.o and winver.o";\ + $(SHELL) ${word 1,$^} ${word 2,$^} ${word 3,$^} $(WINDRES); \ + touch $@; \ + $(COMPILE_CXX) -o version.o version.cc + +cygrun.exe : $(srcdir)/cygrun.c $(DLL_IMPORTS) $(w32api_lib)/libuser32.a \ + $(w32api_lib)/libshell32.a + $(CC) -o $@ $^ + +# + +# These targets are for the dejagnu testsuites. The file site.exp +# contains global variables that all the testsuites will use. + +# Set to $(target_alias)/ for cross. +target_subdir = @target_subdir@ + +site.exp: ./config.status Makefile + @echo "Making a new config file..." + -@rm -f ./tmp? + @touch site.exp + -@mv site.exp site.bak + @echo "## these variables are automatically generated by make ##" > ./tmp0 + @echo "# Do not edit here. If you wish to override these values" >> ./tmp0 + @echo "# add them to the last section" >> ./tmp0 + @echo "set rootme \"`pwd`\"" >> ./tmp0 + @echo "set srcdir \"`cd ${srcdir}; pwd`\"" >> ./tmp0 + @echo "set host_triplet $(host_canonical)" >> ./tmp0 + @echo "set build_triplet $(build_canonical)" >> ./tmp0 + @echo "set target_triplet $(target)" >> ./tmp0 + @echo "set target_alias $(target_alias)" >> ./tmp0 + @echo "set CC \"$(CC)\"" >> ./tmp0 +# CFLAGS is set even though it's empty to show we reserve the right to set it. + @echo "set CFLAGS \"\"" >> ./tmp0 + echo "set tmpdir $(objdir)/testsuite" >> ./tmp0 + @echo "set srcdir \"\$${srcdir}/testsuite\"" >> ./tmp0 + @echo "## All variables above are generated by configure. Do Not Edit ##" >> ./tmp0 + @cat ./tmp0 > site.exp + @cat site.bak | sed \ + -e '1,/^## All variables above are.*##/ d' >> site.exp + -@rm -f ./tmp? + +testsuite/site.exp: site.exp + if [ -d testsuite ]; then \ + true; \ + else \ + mkdir testsuite; \ + fi + rm -rf testsuite/site.exp + cp site.exp testsuite/site.exp + +# Note: we set the PATH so that we can pick up new-cygwin1.dll + +check: testsuite/site.exp + -rootme=`pwd`; export rootme; \ + srcdir=`cd ${srcdir}; pwd` ; export srcdir ; \ + cd testsuite; \ + EXPECT=${EXPECT} ; export EXPECT ; \ + if [ -f $${rootme}/../expect/expect ] ; then \ + TCL_LIBRARY=`cd .. ; cd ${srcdir}/../tcl/library ; pwd` ; \ + export TCL_LIBRARY ; fi ; \ + PATH=$${rootme}:$${PATH} ;\ + $(RUNTEST) --tool winsup $(RUNTESTFLAGS) + +# + +Makefile: cygwin.din + +# .h file dependencies +# This may be overkill, but it's better than the previous situation. +# As files/dependencies are added and removed from Cygwin, please keep +# this list up to date. + +WINSUP_H:=winsup.h fhandler.h path.h shared.h \ + sigproc.h include/cygwin/version.h \ + $(MT_SAFE_HEADERS) + +winsup.h: config.h +assert.o: $(WINSUP_H) +dcrt0.o: $(WINSUP_H) include/exceptions.h include/glob.h dll_init.h autoload.h +debug.o: $(WINSUP_H) debug.h sync.h +delqueue.o: $(WINSUP_H) +dir.o: $(WINSUP_H) +dlfcn.o: $(WINSUP_H) dll_init.h +dll_entry.o: $(WINSUP_H) include/cygwin/cygwin_dll.h +dll_init.o: $(WINSUP_H) include/exceptions.h dll_init.h +dll_main.o: +environ.o: $(WINSUP_H) +errno.o: $(WINSUP_H) +exceptions.o: $(WINSUP_H) include/exceptions.h sync.h autoload.h +exec.o: $(WINSUP_H) +external.o: $(WINSUP_H) external.h +fcntl.o: $(WINSUP_H) +fhandler.o: $(WINSUP_H) +fhandler_console.o: $(WINSUP_H) +fhandler_serial.o: $(WINSUP_H) +fhandler_termios.o: $(WINSUP_H) +fhandler_tty.o: $(WINSUP_H) +fhandler_windows.o: $(WINSUP_H) +fhandler_raw.o: $(WINSUP_H) +fhandler_floppy.o: $(WINSUP_H) +fhandler_tape.o: $(WINSUP_H) +fhandler_zero.o: $(WINSUP_H) +fork.o: $(WINSUP_H) dll_init.h +glob.o: include/glob.h +gmon.o: profil.h gmon.h +grp.o: $(WINSUP_H) +heap.o: $(WINSUP_H) +hinfo.o: $(WINSUP_H) +init.o: $(WINSUP_H) +ioctl.o: $(WINSUP_H) +libccrt0.o: $(WINSUP_H) +libcmain.o: $(WINSUP_H) +localtime.o: tz_posixrules.h +malloc.o: $(WINSUP_H) +mcount.o: gmon.h +mmap.o: $(WINSUP_H) +net.o: $(WINSUP_H) autoload.h +ntea.o: +passwd.o: $(WINSUP_H) +path.o: $(WINSUP_H) +pinfo.o: $(WINSUP_H) +pipe.o: $(WINSUP_H) +profile.o: profil.h +pthread.o: $(WINSUP_H) +registry.o: $(WINSUP_H) +resource.o: $(WINSUP_H) +scandir.o: +security.o: $(WINSUP_H) +select.o: $(WINSUP_H) select.h +shared.o: $(WINSUP_H) +signal.o: $(WINSUP_H) +sigproc.o: $(WINSUP_H) sync.h +smallprint.o: $(WINSUP_H) +spawn.o: $(WINSUP_H) +strace.o: $(WINSUP_H) +strsep.o: +sync.o: $(WINSUP_H) sync.h +syscalls.o: $(WINSUP_H) +sysconf.o: $(WINSUP_H) +syslog.o: $(WINSUP_H) +termios.o: $(WINSUP_H) +test.o: $(WINSUP_H) +times.o: $(WINSUP_H) +tty.o: $(WINSUP_H) +uinfo.o: $(WINSUP_H) +uname.o: $(WINSUP_H) +wait.o: $(WINSUP_H) +window.o: $(WINSUP_H) +thread.o: $(WINSUP_H) + diff --git a/winsup/cygwin/ROADMAP b/winsup/cygwin/ROADMAP new file mode 100644 index 000000000..c8ed7eb36 --- /dev/null +++ b/winsup/cygwin/ROADMAP @@ -0,0 +1,129 @@ + + WINSUP ROADMAP + +The purpose of this document is to give the briefest overview of how +the various parts of cygwin work together and where everything can be +found. The intended audience is people developing the cygwin dll +itself. Comments to dj@cygnus.com. + +=== cygwin1.dll source files + +- overhead +.h winsup autoload debug external shared sync +.cc assert dcrt0 debug external init ntea registry security + shared smallprint strace sync +.din cygwin +.rc winver +.sgml external shared + +- processes +.h sigproc +.cc exec fork pinfo resource signal sigproc spawn wait + +- signals +.cc exceptions window + +- files and I/O +.h delqueue fhandler path select +.cc delqueue dir fhandler* hinfo path pipe select tty +.sgml hinfo path + +- common unix functions +.h dll_init tz_posixrules +.cc dlfcn dll_init environ errno fcntl flog grp ioctl localtime + malloc passwd scandir strsep syscalls sysconf syslog termios +.c longjmp setjmp +.sgml dll_init + +- unix emulation +.cc heap mmap net times unifo uname + + +--- if MT_SAFE +.h thread +.cc pthread thread + +--- from other places +regex/* +../libiberty/{random,strsignal} +../newlib/* (libc) + +=== libcygwin.a source files + +libccrt0.cc +libcmain.cc +dll_entry.cc +dll_main.cc +getopt.c + +=== gmon (profiling, -pg) + +gcrt0.c +gmon.c gmon.h +mcount.c +profil.c profil.h + +=== entry points + +- normal cygwin program + +newlib/libc/sys/cygwin/crt0.c has mainCRTStartup() and calls cygwin_crt0() + +libccrt0.cc has cygwin_crt0() and calls dll_crt0() + +dcrt0.cc - has dll_crt0() + +Note: dll_init.cc has nothing to do with initializing the cygwin dll. +It initializes the dlls you have dl_open'd. + +- cygwin-built dll + +dll_entry.cc - has a macro for wrapping your dll startup function + (equivalent of DllMain()) in such a way that you get your + cygwin environment set up automatically when your dll is + loaded. + +dll_main.cc - has empty DllMain() in case you don't have your own + +- manually loading cygwin1.dll + +init.cc - has dll_entry() which is called by the OS when the dll is + loaded. It doesn't do much except note if you linked + cygwin1.dll or are manually loading it. + +=== About "fhandlers" + +An fhandler is a file type handler. This is where the unix device +emulation happens. + +hinfo.cc maps posix file descriptors to a table of file handlers (type +fhandler) in the dll. It's mostly concerned with managing the table +of descriptors (open, dup, fork, select). Most of the posix I/O +system calls (syscalls.cc) use the hinfo table to call the right +fhandler directly. + +fhandler.cc is the base class; specific types are derived as +appropriate (see fhandler.h). hinfo.cc is in charge of selecting and +creating a suitable fhandler when you open a file. path.cc handles +emulated files in /dev (like /dev/null) by returning an FH_* value +from get_device_number (which hinfo.cc calls in hinfo::build_fhandler). + +Note: if you're looking for read() and write(), they call _read() and +_write() in syscalls.cc. The non-underscored ones are in +newlib/libc/syscalls and just call the underscored ones. + +=== How "fork" works + +It all starts in fork() in fork.cc. + +Set up a pid in the shared memory area for the new child. Use +setjmp() to capture state. First time (parent), set up some stuff and +use CreateProcess to run a second copy of the same executable. The +second copy will note in the shared memory area that it's a fork, and +do the longjmp. They sync up and the parent copies all it's program +memory to the child's address space. There's also code to reload +dlls, map shared memory and mmap'd files, etc. + +Handling the special startup for the child is done in dcrt0.cc in many +places. This case is triggered by a special StartupInfo structure +that's passed from the parent to the child in CreateProcessA. diff --git a/winsup/cygwin/acconfig.h b/winsup/cygwin/acconfig.h new file mode 100644 index 000000000..5b796e897 --- /dev/null +++ b/winsup/cygwin/acconfig.h @@ -0,0 +1,15 @@ +/* Define if DEBUGGING support is requested. */ +#undef DEBUGGING + +/* Define if building "extra" thread-safe Cygwin DLL. */ +#undef _CYG_THREAD_FAILSAFE + +/* Define if GCC supports builtin memset. */ +#undef HAVE_BUILTIN_MEMSET + +/* Define if building thread-safe Cygwin DLL. */ +#undef _MT_SAFE + +/* Define if strace log output has date/time stamp. */ +#undef STRACE_HHMMSS + diff --git a/winsup/cygwin/ansi.sgml b/winsup/cygwin/ansi.sgml new file mode 100644 index 000000000..d6a41ab31 --- /dev/null +++ b/winsup/cygwin/ansi.sgml @@ -0,0 +1,59 @@ + +Compatibility with ANSI + +The following functions are compatible with ANSI: + +stdio + +clearerr, fclose, feof, ferror, fflush, fgetc, fgetpos, fgets, fopen, +fprintf, fputc, fputs, fread, freopen, fscanf, fseek, fsetpos, ftell, +fwrite, getc, getchar, gets, perror, printf, putc, putchar, puts, +remove, rename, rewind, scanf, setbuf, setvbuf, sprintf, sscanf, +tmpfile, tmpnam, vfprintf, ungetc, vprintf, vsprintf, + + +string + +memchr, memcmp, memcpy, memmove, memset, strcat, strchr, strcmp, +strcoll, strcpy, strcspn, strerror, strlen, strncat, strncmp, strncpy, +strpbrk, strrchr, strspn, strstr, strtok, strxfrm + + +stdlib + +abort, abs, assert, atexit, atof, atoi, atol, bsearch, calloc, div, +exit, free, getenv, labs, ldiv, longjmp, malloc, mblen, mbstowcs, +mbtowc, qsort, rand, realloc, setjmp, srand, strtod, strtol, strtoul, +system, wcstombs, wctomb + + +time + +asctime, gmtime, localtime, time, clock, ctime, difftime, mktime, +strftime + + +signals + +raise, signal + + +ctype + +isalnum, isalpha, iscntrl, isdigit, isgraph, islower, isprint, +ispunct, isspace, isupper, isxdigit, tolower, toupper + + +math + +acos, asin, atan, atan2, ceil, cos, cosh, exp, fabs, floor, fmod, +frexp, ldexp, log, log10, modf, pow, sin, sinh, sqrt, tan, tanh + + +misc + +localeconv, setlocale, va_arg, va_end, va_start + + + + \ No newline at end of file diff --git a/winsup/cygwin/assert.cc b/winsup/cygwin/assert.cc new file mode 100644 index 000000000..98acb6d88 --- /dev/null +++ b/winsup/cygwin/assert.cc @@ -0,0 +1,50 @@ +/* assert.cc: Handle the assert macro for WIN32. + + Copyright 1997, 1998, 2000 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include "winsup.h" + +#include +#include +#include + +/* This function is called when the assert macro fails. This will + override the function of the same name in newlib. */ + +extern "C" void +__assert (const char *file, int line, const char *failedexpr) +{ + HANDLE h; + + /* If we don't have a console in a Windows program, then bring up a + message box for the assertion failure. */ + + h = CreateFileA ("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE, &sec_none_nih, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE || h == 0) + { + char *buf; + + buf = (char *) alloca (100 + strlen (failedexpr)); + siprintf (buf, "Failed assertion\n\t%s\nat line %d of file %s", + failedexpr, line, file); + MessageBox (NULL, buf, NULL, MB_OK | MB_ICONERROR | MB_TASKMODAL); + } + else + { + CloseHandle (h); + (void) fiprintf (stderr, + "assertion \"%s\" failed: file \"%s\", line %d\n", + failedexpr, file, line); + } + + abort (); + + /* NOTREACHED */ +} diff --git a/winsup/cygwin/config.h.in b/winsup/cygwin/config.h.in new file mode 100644 index 000000000..e160104f3 --- /dev/null +++ b/winsup/cygwin/config.h.in @@ -0,0 +1,38 @@ +/* config.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define if using alloca.c. */ +#undef C_ALLOCA + +/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems. + This function is required for alloca.c support on those systems. */ +#undef CRAY_STACKSEG_END + +/* Define if you have alloca, as a function or macro. */ +#undef HAVE_ALLOCA + +/* Define if you have and it should be used (not on Ultrix). */ +#undef HAVE_ALLOCA_H + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown + */ +#undef STACK_DIRECTION + +/* Define if DEBUGGING support is requested. */ +#undef DEBUGGING + +/* Define if building "extra" thread-safe Cygwin DLL. */ +#undef _CYG_THREAD_FAILSAFE + +/* Define if GCC supports builtin memset. */ +#undef HAVE_BUILTIN_MEMSET + +/* Define if building thread-safe Cygwin DLL. */ +#undef _MT_SAFE + +/* Define if strace log output has date/time stamp. */ +#undef STRACE_HHMMSS diff --git a/winsup/cygwin/config/i386/longjmp.c b/winsup/cygwin/config/i386/longjmp.c new file mode 100644 index 000000000..d663e20f7 --- /dev/null +++ b/winsup/cygwin/config/i386/longjmp.c @@ -0,0 +1,51 @@ +/* longjmp.c + + Copyright 1996, 1998 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#ifdef __i386__ +#if 1 +asm (" .globl _longjmp \n" +"_longjmp: \n" +" pushl %ebp \n" +" movl %esp,%ebp \n" +" movl 8(%ebp),%edi \n" +" movl 12(%ebp),%eax \n" +" testl %eax,%eax \n" +" jne 0f \n" +" incl %eax \n" +"0: \n" +" movl %eax,0(%edi) \n" +" movl 24(%edi),%ebp \n" +" pushfl \n" +" popl %ebx \n" +" movw 42(%edi),%ax \n" +" movw %ax,%ss \n" +" movl 28(%edi),%esp \n" +" pushl 32(%edi) \n" +" pushl %ebx \n" +" movw 36(%edi),%ax \n" +" movw %ax,%es \n" +#if 0 +/* fs is a system register in windows; don't muck with it */ +" movw 38(%edi),%ax \n" +" movw %ax,%fs \n" +#endif +" movw 40(%edi),%ax \n" +" movw %ax,%gs \n" +" movl 0(%edi),%eax \n" +" movl 4(%edi),%ebx \n" +" movl 8(%edi),%ecx \n" +" movl 12(%edi),%edx \n" +" movl 16(%edi),%esi \n" +" movl 20(%edi),%edi \n" +" popfl \n" +" ret \n"); +#endif + +#endif /* __i386__ */ diff --git a/winsup/cygwin/config/i386/makefrag b/winsup/cygwin/config/i386/makefrag new file mode 100644 index 000000000..a8b394221 --- /dev/null +++ b/winsup/cygwin/config/i386/makefrag @@ -0,0 +1,17 @@ +# makefrag: included by the main Cygwin Makefile.in + +# Copyright 1996, 1998 Cygnus Solutions. + +# This file is part of Cygwin. + +# This software is a copyrighted work licensed under the terms of the +# Cygwin license. Please consult the file "CYGWIN_LICENSE" for +# details. + +EXTRA_DLL_OFILES=setjmp.o longjmp.o + +setjmp.o:config/i386/setjmp.c + $(CC) -c $(ALL_CFLAGS) $< + +longjmp.o:config/i386/longjmp.c + $(CC) -c $(ALL_CFLAGS) $< diff --git a/winsup/cygwin/config/i386/profile.h b/winsup/cygwin/config/i386/profile.h new file mode 100644 index 000000000..ad5f625d0 --- /dev/null +++ b/winsup/cygwin/config/i386/profile.h @@ -0,0 +1,58 @@ +/* $NetBSD: profile.h,v 1.6 1995/03/28 18:17:08 jtc Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)profile.h 8.1 (Berkeley) 6/11/93 + */ + +#define _MCOUNT_DECL static inline void _mcount + +#define MCOUNT \ +void \ +mcount() \ +{ \ + int selfpc, frompcindex; \ + /* \ + * find the return address for mcount, \ + * and the return address for mcount's caller. \ + * \ + * selfpc = pc pushed by mcount call \ + */ \ + __asm("movl 4(%%ebp),%0" : "=r" (selfpc)); \ + /* \ + * frompcindex = pc pushed by call into self. \ + */ \ + __asm("movl (%%ebp),%0;movl 4(%0),%0" : "=r" (frompcindex)); \ + _mcount(frompcindex, selfpc); \ +} + diff --git a/winsup/cygwin/config/i386/setjmp.c b/winsup/cygwin/config/i386/setjmp.c new file mode 100644 index 000000000..befd7e683 --- /dev/null +++ b/winsup/cygwin/config/i386/setjmp.c @@ -0,0 +1,48 @@ +/* setjmp.c + + Copyright 1996, 1998 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#ifdef __i386__ + +#if 1 +asm(" .globl _setjmp \n" +"_setjmp: \n" +" pushl %ebp \n" +" movl %esp,%ebp \n" +" pushl %edi \n" +" movl 8(%ebp),%edi \n" +" movl %eax,0(%edi) \n" +" movl %ebx,4(%edi) \n" +" movl %ecx,8(%edi) \n" +" movl %edx,12(%edi) \n" +" movl %esi,16(%edi) \n" +" movl -4(%ebp),%eax \n" +" movl %eax,20(%edi) \n" +" movl 0(%ebp),%eax \n" +" movl %eax,24(%edi) \n" +" movl %esp,%eax \n" +" addl $12,%eax \n" +" movl %eax,28(%edi) \n" +" movl 4(%ebp),%eax \n" +" movl %eax,32(%edi) \n" +" movw %es, %ax \n" +" movw %ax, 36(%edi) \n" +" movw %fs, %ax \n" +" movw %ax, 38(%edi) \n" +" movw %gs, %ax \n" +" movw %ax, 40(%edi) \n" +" movw %ss, %ax \n" +" movw %ax, 42(%edi) \n" +" popl %edi \n" +" movl $0,%eax \n" +" leave \n" +" ret \n"); +#endif + +#endif /* __i386__ */ diff --git a/winsup/cygwin/configure b/winsup/cygwin/configure new file mode 100755 index 000000000..f69feda13 --- /dev/null +++ b/winsup/cygwin/configure @@ -0,0 +1,2335 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.13 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_help="$ac_help + --enable-strace-hhmmss strace log output has date/time stamp" +ac_help="$ac_help + --enable-threadsafe=[runtime] Build a cygwin DLL which is thread safe" +ac_help="$ac_help + --enable-extra-threadsafe-checking Build a cygwin DLL which is thread safe with extra consistency checking" +ac_help="$ac_help + --enable-debugging Build a cygwin DLL which has more consistency checking for debugging" + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +sitefile= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --site-file=FILE use FILE as the site file + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -site-file | --site-file | --site-fil | --site-fi | --site-f) + ac_prev=sitefile ;; + -site-file=* | --site-file=* | --site-fil=* | --site-fi=* | --site-f=*) + sitefile="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.13" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=init.cc + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$sitefile"; then + if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi + fi +else + CONFIG_SITE="$sitefile" +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +ac_exeext= +ac_objext=o +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + + + +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:577: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + + + + + + +# Do some error checking and defaulting for the host and target type. +# The inputs are: +# configure --host=HOST --target=TARGET --build=BUILD NONOPT +# +# The rules are: +# 1. You are not allowed to specify --host, --target, and nonopt at the +# same time. +# 2. Host defaults to nonopt. +# 3. If nonopt is not specified, then host defaults to the current host, +# as determined by config.guess. +# 4. Target and build default to nonopt. +# 5. If nonopt is not specified, then target and build default to host. + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +case $host---$target---$nonopt in +NONE---*---* | *---NONE---* | *---*---NONE) ;; +*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;; +esac + + +# Make sure we can run config.sub. +if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then : +else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } +fi + +echo $ac_n "checking host system type""... $ac_c" 1>&6 +echo "configure:661: checking host system type" >&5 + +host_alias=$host +case "$host_alias" in +NONE) + case $nonopt in + NONE) + if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then : + else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } + fi ;; + *) host_alias=$nonopt ;; + esac ;; +esac + +host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias` +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$host" 1>&6 + +echo $ac_n "checking target system type""... $ac_c" 1>&6 +echo "configure:682: checking target system type" >&5 + +target_alias=$target +case "$target_alias" in +NONE) + case $nonopt in + NONE) target_alias=$host_alias ;; + *) target_alias=$nonopt ;; + esac ;; +esac + +target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias` +target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$target" 1>&6 + +echo $ac_n "checking build system type""... $ac_c" 1>&6 +echo "configure:700: checking build system type" >&5 + +build_alias=$build +case "$build_alias" in +NONE) + case $nonopt in + NONE) build_alias=$host_alias ;; + *) build_alias=$nonopt ;; + esac ;; +esac + +build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias` +build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$build" 1>&6 + +test "$host_alias" != "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + + +if test $host != $build; then + ac_tool_prefix=${host_alias}- +else + ac_tool_prefix= +fi + +# Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:732: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + +if test -z "$ac_cv_prog_CC"; then +if test -n "$ac_tool_prefix"; then + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:764: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_CC" && ac_cv_prog_CC="gcc" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +else + CC="gcc" +fi +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:800: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_prog_rejected=no + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:849: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes + ac_test_CFLAGS="${CFLAGS+set}" + ac_save_CFLAGS="$CFLAGS" + CFLAGS= + echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:873: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 + if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" + elif test $ac_cv_prog_cc_g = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-O2" + fi + if test "$ac_test_CXXFLAGS" != set; then + CXXFLAGS='$(CFLAGS)' + fi +else + GCC= + test "${CFLAGS+set}" = set || CFLAGS="-g" +fi + + +# Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:907: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +AR="$ac_cv_prog_AR" +if test -n "$AR"; then + echo "$ac_t""$AR" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + +if test -z "$ac_cv_prog_AR"; then +if test -n "$ac_tool_prefix"; then + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:939: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AR="ar" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_AR" && ac_cv_prog_AR="ar" +fi +fi +AR="$ac_cv_prog_AR" +if test -n "$AR"; then + echo "$ac_t""$AR" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +else + AR="ar" +fi +fi + + +# Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args. +set dummy ${ac_tool_prefix}as; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:975: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AS'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AS"; then + ac_cv_prog_AS="$AS" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AS="${ac_tool_prefix}as" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +AS="$ac_cv_prog_AS" +if test -n "$AS"; then + echo "$ac_t""$AS" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + +if test -z "$ac_cv_prog_AS"; then +if test -n "$ac_tool_prefix"; then + # Extract the first word of "as", so it can be a program name with args. +set dummy as; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1007: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AS'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AS"; then + ac_cv_prog_AS="$AS" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AS="as" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_AS" && ac_cv_prog_AS="as" +fi +fi +AS="$ac_cv_prog_AS" +if test -n "$AS"; then + echo "$ac_t""$AS" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +else + AS="as" +fi +fi + + +# Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1043: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + +if test -z "$ac_cv_prog_RANLIB"; then +if test -n "$ac_tool_prefix"; then + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1075: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="ranlib" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB="ranlib" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +else + RANLIB="ranlib" +fi +fi + + +# Extract the first word of "${ac_tool_prefix}ld", so it can be a program name with args. +set dummy ${ac_tool_prefix}ld; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1111: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_LD'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$LD"; then + ac_cv_prog_LD="$LD" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_LD="${ac_tool_prefix}ld" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +LD="$ac_cv_prog_LD" +if test -n "$LD"; then + echo "$ac_t""$LD" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + +if test -z "$ac_cv_prog_LD"; then +if test -n "$ac_tool_prefix"; then + # Extract the first word of "ld", so it can be a program name with args. +set dummy ld; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1143: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_LD'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$LD"; then + ac_cv_prog_LD="$LD" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_LD="ld" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_LD" && ac_cv_prog_LD="ld" +fi +fi +LD="$ac_cv_prog_LD" +if test -n "$LD"; then + echo "$ac_t""$LD" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +else + LD="ld" +fi +fi + + +# Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. +set dummy ${ac_tool_prefix}dlltool; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1179: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_DLLTOOL'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$DLLTOOL"; then + ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +DLLTOOL="$ac_cv_prog_DLLTOOL" +if test -n "$DLLTOOL"; then + echo "$ac_t""$DLLTOOL" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + +if test -z "$ac_cv_prog_DLLTOOL"; then +if test -n "$ac_tool_prefix"; then + # Extract the first word of "dlltool", so it can be a program name with args. +set dummy dlltool; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1211: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_DLLTOOL'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$DLLTOOL"; then + ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_DLLTOOL="dlltool" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_DLLTOOL" && ac_cv_prog_DLLTOOL="dlltool" +fi +fi +DLLTOOL="$ac_cv_prog_DLLTOOL" +if test -n "$DLLTOOL"; then + echo "$ac_t""$DLLTOOL" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +else + DLLTOOL="dlltool" +fi +fi + + +# Extract the first word of "${ac_tool_prefix}windres", so it can be a program name with args. +set dummy ${ac_tool_prefix}windres; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1247: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_WINDRES'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$WINDRES"; then + ac_cv_prog_WINDRES="$WINDRES" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_WINDRES="${ac_tool_prefix}windres" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +WINDRES="$ac_cv_prog_WINDRES" +if test -n "$WINDRES"; then + echo "$ac_t""$WINDRES" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + +if test -z "$ac_cv_prog_WINDRES"; then +if test -n "$ac_tool_prefix"; then + # Extract the first word of "windres", so it can be a program name with args. +set dummy windres; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1279: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_WINDRES'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$WINDRES"; then + ac_cv_prog_WINDRES="$WINDRES" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_WINDRES="windres" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_WINDRES" && ac_cv_prog_WINDRES="windres" +fi +fi +WINDRES="$ac_cv_prog_WINDRES" +if test -n "$WINDRES"; then + echo "$ac_t""$WINDRES" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +else + WINDRES="windres" +fi +fi + + + +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:1314: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1335: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1352: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -nologo -E" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1369: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works +# for constant arguments. Useless! +echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6 +echo "configure:1396: checking for working alloca.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int main() { +char *p = alloca(2 * sizeof(int)); +; return 0; } +EOF +if { (eval echo configure:1408: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_header_alloca_h=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_alloca_h=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_header_alloca_h" 1>&6 +if test $ac_cv_header_alloca_h = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_ALLOCA_H 1 +EOF + +fi + +echo $ac_n "checking for alloca""... $ac_c" 1>&6 +echo "configure:1429: checking for alloca" >&5 +if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +# define alloca _alloca +# else +# if HAVE_ALLOCA_H +# include +# else +# ifdef _AIX + #pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ +char *alloca (); +# endif +# endif +# endif +# endif +#endif + +int main() { +char *p = (char *) alloca(1); +; return 0; } +EOF +if { (eval echo configure:1462: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_func_alloca_works=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_func_alloca_works=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_func_alloca_works" 1>&6 +if test $ac_cv_func_alloca_works = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_ALLOCA 1 +EOF + +fi + +if test $ac_cv_func_alloca_works = no; then + # The SVR3 libPW and SVR4 libucb both contain incompatible functions + # that cause trouble. Some versions do not even contain alloca or + # contain a buggy version. If you still want to use their alloca, + # use ar to extract alloca.o from them instead of compiling alloca.c. + ALLOCA=alloca.${ac_objext} + cat >> confdefs.h <<\EOF +#define C_ALLOCA 1 +EOF + + +echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6 +echo "configure:1494: checking whether alloca needs Cray hooks" >&5 +if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <&5 | + egrep "webecray" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_os_cray=yes +else + rm -rf conftest* + ac_cv_os_cray=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_os_cray" 1>&6 +if test $ac_cv_os_cray = yes; then +for ac_func in _getb67 GETB67 getb67; do + echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:1524: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1552: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <&6 +fi + +done +fi + +echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6 +echo "configure:1579: checking stack direction for C alloca" >&5 +if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_c_stack_direction=0 +else + cat > conftest.$ac_ext < addr) ? 1 : -1; +} +main () +{ + exit (find_stack_direction() < 0); +} +EOF +if { (eval echo configure:1606: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_c_stack_direction=1 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_c_stack_direction=-1 +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_c_stack_direction" 1>&6 +cat >> confdefs.h <&6 +echo "configure:1630: checking whether ${MAKE-make} sets \${MAKE}" >&5 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftestmake <<\EOF +all: + @echo 'ac_maketemp="${MAKE}"' +EOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftestmake +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$ac_t""yes" 1>&6 + SET_MAKE= +else + echo "$ac_t""no" 1>&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + + +# Test for builtin mem* functions. + +ac_ext=C +# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cxx_cross + +cat > conftest.$ac_ext < +void foo(char *s, int c, size_t n) +{ + __builtin_memset(s, c, n); +} + +int main() { + +; return 0; } +EOF +if { (eval echo configure:1680: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + use_builtin_memset=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + use_builtin_memset=no +fi +rm -f conftest* +if test $use_builtin_memset = "yes"; then + cat >> confdefs.h <<\EOF +#define HAVE_BUILTIN_MEMSET 1 +EOF + +fi +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + + +# Check whether --enable-strace-hhmmss or --disable-strace-hhmmss was given. +if test "${enable_strace_hhmmss+set}" = set; then + enableval="$enable_strace_hhmmss" + case "${enableval}" in +yes) + cat >> confdefs.h <<\EOF +#define STRACE_HHMMSS 1 +EOF + + ;; +no) + ;; +*) + { echo "configure: error: bad value ${enableval} given for enable-strace-hhmmss option" 1>&2; exit 1; } + ;; +esac + +fi + + +mt_safe_val=1 +MT_SAFE=yes +PTH_ALLOW='' + +# Check whether --enable-threadsafe or --disable-threadsafe was given. +if test "${enable_threadsafe+set}" = set; then + enableval="$enable_threadsafe" + case "${enableval}" in +yes) + ;; +runtime) + mt_safe_val=2 + MT_SAFE=yes + ;; +no) + mt_safe_val=0 + MT_SAFE=no + PTH_ALLOW=';' + ;; +esac + +fi + + +# Check whether --enable-extra-threadsafe-checking or --disable-extra-threadsafe-checking was given. +if test "${enable_extra_threadsafe_checking+set}" = set; then + enableval="$enable_extra_threadsafe_checking" + case "${enableval}" in +yes) + mt_safe_val=1 + MT_SAFE=yes + cat >> confdefs.h <<\EOF +#define _CYG_THREAD_FAILSAFE 1 +EOF + + ;; +no) + ;; +esac + +fi + + +if test "$MT_SAFE" = "yes"; then + cat >> confdefs.h <> confdefs.h <<\EOF +#define DEBUGGING 1 +EOF + ;; +no) ;; +esac + +fi + + + + + + +echo $ac_n "checking if newlib is part of the build tree""... $ac_c" 1>&6 +echo "configure:1796: checking if newlib is part of the build tree" >&5 + +EXE_LDFLAGS= +if test -d ../newlib +then + echo "$ac_t""yes" 1>&6 + EXE_LDFLAGS="-B../../newlib/ -B../" +else + echo "$ac_t""no" 1>&6 +fi + + +if test x"$EXE_LDFLAGS" = x +then + echo $ac_n "checking if installed newlib needed""... $ac_c" 1>&6 +echo "configure:1811: checking if installed newlib needed" >&5 + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + echo "$ac_t""no" 1>&6 + +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + echo "$ac_t""yes" 1>&6 + echo "configure: warning: newlib not found - utility .exe's may not link" 1>&2 +fi +rm -f conftest* +fi + + +case "$target_cpu" in + i386|i486|i586|i686) DLL_ENTRY="_dll_entry@12" + DEF_DLL_ENTRY="dll_entry@12" + ALLOCA="_alloca" + CONFIG_DIR="i386" ;; + powerpc*) DLL_ENTRY="dll_entry" + DEF_DLL_ENTRY="dll_entry" + ALLOCA=" __allocate_stack" + CONFIG_DIR="ppc" ;; + *) { echo "configure: error: Invalid target processor \"$target_cpu\"" 1>&2; exit 1; } ;; +esac + + + + + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +DEFS=-DHAVE_CONFIG_H + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS </dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.13" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir +ac_given_INSTALL="$INSTALL" + +trap 'rm -fr `echo "Makefile cygwin.def:cygwin.din config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@SHELL@%$SHELL%g +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@FFLAGS@%$FFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@host@%$host%g +s%@host_alias@%$host_alias%g +s%@host_cpu@%$host_cpu%g +s%@host_vendor@%$host_vendor%g +s%@host_os@%$host_os%g +s%@target@%$target%g +s%@target_alias@%$target_alias%g +s%@target_cpu@%$target_cpu%g +s%@target_vendor@%$target_vendor%g +s%@target_os@%$target_os%g +s%@build@%$build%g +s%@build_alias@%$build_alias%g +s%@build_cpu@%$build_cpu%g +s%@build_vendor@%$build_vendor%g +s%@build_os@%$build_os%g +s%@CC@%$CC%g +s%@AR@%$AR%g +s%@AS@%$AS%g +s%@RANLIB@%$RANLIB%g +s%@LD@%$LD%g +s%@DLLTOOL@%$DLLTOOL%g +s%@WINDRES@%$WINDRES%g +s%@CPP@%$CPP%g +s%@ALLOCA@%$ALLOCA%g +s%@subdirs@%$subdirs%g +s%@SET_MAKE@%$SET_MAKE%g +s%@MT_SAFE@%$MT_SAFE%g +s%@PTH_ALLOW@%$PTH_ALLOW%g +s%@EXE_LDFLAGS@%$EXE_LDFLAGS%g +s%@DLL_ENTRY@%$DLL_ENTRY%g +s%@DEF_DLL_ENTRY@%$DEF_DLL_ENTRY%g +s%@CONFIG_DIR@%$CONFIG_DIR%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +s%@INSTALL@%$INSTALL%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +if test "${CONFIG_HEADERS+set}" != set; then +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + cat $ac_file_inputs > conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +cat > conftest.hdr <<\EOF +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF + +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + +if test "$no_recursion" != yes; then + + # Remove --cache-file and --srcdir arguments so they do not pile up. + ac_sub_configure_args= + ac_prev= + for ac_arg in $ac_configure_args; do + if test -n "$ac_prev"; then + ac_prev= + continue + fi + case "$ac_arg" in + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + ;; + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + ;; + *) ac_sub_configure_args="$ac_sub_configure_args $ac_arg" ;; + esac + done + + for ac_config_dir in utils doc; do + + # Do not complain, so a configure script can configure whichever + # parts of a large source tree are present. + if test ! -d $srcdir/$ac_config_dir; then + continue + fi + + echo configuring in $ac_config_dir + + case "$srcdir" in + .) ;; + *) + if test -d ./$ac_config_dir || mkdir ./$ac_config_dir; then :; + else + { echo "configure: error: can not create `pwd`/$ac_config_dir" 1>&2; exit 1; } + fi + ;; + esac + + ac_popdir=`pwd` + cd $ac_config_dir + + # A "../" for each directory in /$ac_config_dir. + ac_dots=`echo $ac_config_dir|sed -e 's%^\./%%' -e 's%[^/]$%&/%' -e 's%[^/]*/%../%g'` + + case "$srcdir" in + .) # No --srcdir option. We are building in place. + ac_sub_srcdir=$srcdir ;; + /*) # Absolute path. + ac_sub_srcdir=$srcdir/$ac_config_dir ;; + *) # Relative path. + ac_sub_srcdir=$ac_dots$srcdir/$ac_config_dir ;; + esac + + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_sub_srcdir/configure; then + ac_sub_configure=$ac_sub_srcdir/configure + elif test -f $ac_sub_srcdir/configure.in; then + ac_sub_configure=$ac_configure + else + echo "configure: warning: no configuration information is in $ac_config_dir" 1>&2 + ac_sub_configure= + fi + + # The recursion is here. + if test -n "$ac_sub_configure"; then + + # Make the cache file name correct relative to the subdirectory. + case "$cache_file" in + /*) ac_sub_cache_file=$cache_file ;; + *) # Relative path. + ac_sub_cache_file="$ac_dots$cache_file" ;; + esac + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + + echo "running ${CONFIG_SHELL-/bin/sh} $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_sub_srcdir" + # The eval makes quoting arguments work. + if eval ${CONFIG_SHELL-/bin/sh} $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_sub_srcdir + then : + else + { echo "configure: error: $ac_sub_configure failed for $ac_config_dir" 1>&2; exit 1; } + fi + fi + + cd $ac_popdir + done +fi + + diff --git a/winsup/cygwin/configure.in b/winsup/cygwin/configure.in new file mode 100644 index 000000000..0aaea9bbd --- /dev/null +++ b/winsup/cygwin/configure.in @@ -0,0 +1,229 @@ +dnl Autoconf configure script for Cygwin. +dnl Copyright 1996, 1997, 1998, 2000 Cygnus Solutions. +dnl +dnl This file is part of Cygwin. +dnl +dnl This software is a copyrighted work licensed under the terms of the +dnl Cygwin license. Please consult the file "CYGWIN_LICENSE" for +dnl details. +dnl +dnl Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.12)dnl +AC_INIT(init.cc) +AC_CONFIG_HEADER(config.h) + +AC_PROG_INSTALL + +dnl FIXME: We temporarily define our own version of AC_PROG_CC. This is +dnl copied from autoconf 2.12, but does not call AC_PROG_CC_WORKS. We +dnl are probably using a cross compiler, which will not be able to fully +dnl link an executable. This should really be fixed in autoconf +dnl itself. + +AC_DEFUN(LIB_AC_PROG_CC, +[AC_BEFORE([$0], [AC_PROG_CPP])dnl +AC_CHECK_TOOL(CC, gcc, gcc) +if test -z "$CC"; then + AC_CHECK_PROG(CC, cc, cc, , , /usr/ucb/cc) + test -z "$CC" && AC_MSG_ERROR([no acceptable cc found in \$PATH]) +fi + +AC_PROG_CC_GNU + +if test $ac_cv_prog_gcc = yes; then + GCC=yes +dnl Check whether -g works, even if CFLAGS is set, in case the package +dnl plays around with CFLAGS (such as to build both debugging and +dnl normal versions of a library), tasteless as that idea is. + ac_test_CFLAGS="${CFLAGS+set}" + ac_save_CFLAGS="$CFLAGS" + CFLAGS= + AC_PROG_CC_G + if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" + elif test $ac_cv_prog_cc_g = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-O2" + fi + if test "$ac_test_CXXFLAGS" != set; then + CXXFLAGS='$(CFLAGS)' + fi +else + GCC= + test "${CFLAGS+set}" = set || CFLAGS="-g" +fi +]) + +AC_CANONICAL_SYSTEM + +LIB_AC_PROG_CC + +AC_CHECK_TOOL(AR, ar, ar) +AC_SUBST(AR) +AC_CHECK_TOOL(AS, as, as) +AC_SUBST(AS) +AC_CHECK_TOOL(RANLIB, ranlib, ranlib) +AC_SUBST(RANLIB) +AC_CHECK_TOOL(LD, ld, ld) +AC_SUBST(LD) +AC_CHECK_TOOL(DLLTOOL, dlltool, dlltool) +AC_SUBST(DLLTOOL) +AC_CHECK_TOOL(WINDRES, windres, windres) +AC_SUBST(WINDRES) + +AC_ALLOCA +AC_CONFIG_SUBDIRS(utils doc) +AC_PROG_MAKE_SET + +dnl check whether gcc supports __builtin_memset. +# Test for builtin mem* functions. +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +AC_TRY_COMPILE([ +#include +void foo(char *s, int c, size_t n) +{ + __builtin_memset(s, c, n); +} +], [ ], +use_builtin_memset=yes, use_builtin_memset=no) +if test $use_builtin_memset = "yes"; then + AC_DEFINE(HAVE_BUILTIN_MEMSET) +fi +AC_LANG_RESTORE + +AC_ARG_ENABLE(strace-hhmmss, +[ --enable-strace-hhmmss strace log output has date/time stamp], +[case "${enableval}" in +yes) + AC_DEFINE(STRACE_HHMMSS) + ;; +no) + ;; +*) + AC_MSG_ERROR(bad value ${enableval} given for enable-strace-hhmmss option) + ;; +esac +]) + +dnl set default mt safeness and then process the options. +mt_safe_val=1 +MT_SAFE=yes +PTH_ALLOW='' + +AC_ARG_ENABLE(threadsafe, +[ --enable-threadsafe=[runtime] Build a cygwin DLL which is thread safe], +[case "${enableval}" in +yes) + dnl default. + ;; +runtime) + mt_safe_val=2 + MT_SAFE=yes + ;; +no) + mt_safe_val=0 + MT_SAFE=no + PTH_ALLOW=';' + ;; +esac +]) + +AC_ARG_ENABLE(extra-threadsafe-checking, +[ --enable-extra-threadsafe-checking Build a cygwin DLL which is thread safe with extra consistency checking], +[case "${enableval}" in +yes) + mt_safe_val=1 + MT_SAFE=yes + AC_DEFINE(_CYG_THREAD_FAILSAFE) + ;; +no) + dnl Don't do anything here to avoid overriding --enable-threadsafe. + ;; +esac +]) + +if test "$MT_SAFE" = "yes"; then + AC_DEFINE_UNQUOTED(_MT_SAFE,$mt_safe_val) +fi + +dnl Makefile uses MT_SAFE, so we subst as well as defining it. +AC_SUBST(MT_SAFE) +AC_SUBST(PTH_ALLOW) + +AC_ARG_ENABLE(debugging, +[ --enable-debugging Build a cygwin DLL which has more consistency checking for debugging], +[case "${enableval}" in +yes) AC_DEFINE(DEBUGGING) ;; +no) ;; +esac +]) + + +dnl The only time we might want to transform the install names +dnl is for unix x cygwin. Otherwise we don't. For now we don't +dnl transform names. + +dnl if test "x$cross_compiling" = "xno" -a ; then +dnl if test "x$program_transform_name" = "xs,x,x,"; then +dnl program_transform_name="" +dnl fi +dnl if test "x$program_transform_name" = "x"; then +dnl program_transform_name="s,^,$target_alias-," +dnl else +dnl program_transform_name="$program_transform_name -e s,^,$target_alias-," +dnl fi +dnl fi + +dnl +dnl If newlib is part of build tree, always set EXE_LDFLAGS to point to +dnl it; this is important in cases where the installed newlib is perhaps +dnl not compatible. Check and warn for installed newlib only if it's not +dnl part of the build tree. +dnl + +AC_MSG_CHECKING([if newlib is part of the build tree]) + +EXE_LDFLAGS= +if test -d ../newlib +then + AC_MSG_RESULT(yes) + EXE_LDFLAGS="-B../../newlib/ -B../" +else + AC_MSG_RESULT(no) +fi + AC_SUBST(EXE_LDFLAGS) + +if test x"$EXE_LDFLAGS" = x +then + AC_MSG_CHECKING([if installed newlib needed]) + AC_TRY_LINK(, + [/* main already defined */] + , + AC_MSG_RESULT(no) + , + AC_MSG_RESULT(yes) + AC_MSG_WARN(newlib not found - utility .exe's may not link)) +fi +AC_SUBST(EXE_LDFLAGS) + +case "$target_cpu" in + i386|i486|i586|i686) DLL_ENTRY="_dll_entry@12" + DEF_DLL_ENTRY="dll_entry@12" + ALLOCA="_alloca" + CONFIG_DIR="i386" ;; + powerpc*) DLL_ENTRY="dll_entry" + DEF_DLL_ENTRY="dll_entry" + ALLOCA=" __allocate_stack" + CONFIG_DIR="ppc" ;; + *) AC_MSG_ERROR(Invalid target processor \"$target_cpu\") ;; +esac + +AC_SUBST(DLL_ENTRY) +AC_SUBST(DEF_DLL_ENTRY) +AC_SUBST(ALLOCA) +AC_SUBST(CONFIG_DIR) +AC_OUTPUT(Makefile cygwin.def:cygwin.din) + diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din new file mode 100644 index 000000000..fd814133a --- /dev/null +++ b/winsup/cygwin/cygwin.din @@ -0,0 +1,1051 @@ +LIBRARY "cygwin1.dll" BASE=0x61000000 + +EXPORTS +__assert +__eprintf +__errno +__infinity +__main +__srget +__swbuf +__vc__10pinfo_listi +@ALLOCA@ +cygwin_stackdump +_strace_wm +abort +_abort = abort +abs +_abs = abs +access +_access = access +acos +_acos = acos +acosf +_acosf = acosf +acosh +_acosh = acosh +acoshf +_acoshf = acoshf +alarm +_alarm = alarm +alphasort +_alphasort = alphasort +asctime +_asctime = asctime +asin +_asin = asin +asinf +_asinf = asinf +asinh +_asinh = asinh +asinhf +_asinhf = asinhf +atan +_atan = atan +atan2 +_atan2 = atan2 +atan2f +_atan2f = atan2f +atanf +_atanf = atanf +atanh +_atanh = atanh +atanhf +_atanhf = atanhf +atexit +_atexit = atexit +atof +_atof = atof +atoff +_atoff = atoff +atoi +_atoi = atoi +atol +_atol = atol +bcmp +_bcmp = bcmp +bcopy +_bcopy = bcopy +bsearch +_bsearch = bsearch +bzero +_bzero = bzero +cabs +_cabs = cabs +cabsf +_cabsf = cabsf +calloc = export_calloc +_calloc = export_calloc +cbrt +_cbrt = cbrt +cbrtf +_cbrtf = cbrtf +ceil +_ceil = ceil +ceilf +_ceilf = ceilf +cfgetospeed +cfgetispeed +cfsetospeed +cfsetispeed +chdir +_chdir = chdir +chmod +_chmod = chmod +chown +_chown = chown +cleanup_glue +clearerr +_clearerr = clearerr +clock +_clock = clock +close +_close = close +closedir +_closedir = closedir +copysign +_copysign = copysign +copysignf +_copysignf = copysignf +cos +_cos = cos +cosf +_cosf = cosf +cosh +_cosh = cosh +coshf +_coshf = coshf +creat +_creat = creat +ctime +_ctime = ctime +cwait +_cwait = cwait +difftime +_difftime = difftime +div +_div = div +dll_crt0__FP11per_process +dll_dllcrt0 +dll_noncygwin_dllcrt0 +cygwin_detach_dll +cygwin32_detach_dll = cygwin_detach_dll +@DEF_DLL_ENTRY@ +drem +_drem = drem +dremf +_dremf = dremf +dup +_dup = dup +dup2 +_dup2 = dup2 +ecvt +_ecvt = ecvt +ecvtbuf +_ecvtbuf = ecvtbuf +ecvtf +_ecvtf = ecvtf +endgrent +_endgrent = endgrent +erf +_erf = erf +erfc +_erfc = erfc +erfcf +_erfcf = erfcf +erff +_erff = erff +execl +_execl = execl +execle +_execle = execle +execlp +_execlp = execlp +execv +_execv = execv +execve +_execve = execve +execvp +_execvp = execvp +exit +_exit +exp +_exp = exp +expf +_expf = expf +expm1 +_expm1 = expm1 +expm1f +_expm1f = expm1f +fabs +_fabs = fabs +fabsf +_fabsf = fabsf +fchmod +_fchmod = fchmod +fclose +_fclose = fclose +fcntl +_fcntl = fcntl +fcvt +_fcvt = fcvt +fcvtbuf +_fcvtbuf = fcvtbuf +fcvtf +_fcvtf = fcvtf +fdopen +_fdopen = fdopen +feof +_feof = feof +ferror +_ferror = ferror +fflush +_fflush = fflush +fgetc +_fgetc = fgetc +fgetpos +_fgetpos = fgetpos +fgets +_fgets = fgets +ffs +_ffs = ffs +fileno +_fileno = fileno +finite +_finite = finite +finitef +_finitef = finitef +fiprintf +_fiprintf = fiprintf +floor +_floor = floor +floorf +_floorf = floorf +fmod +_fmod = fmod +fmodf +_fmodf = fmodf +fopen +_fopen = fopen +fork +_fork = fork +fpathconf +fprintf +_fprintf = fprintf +fputc +_fputc = fputc +fputs +_fputs = fputs +fread +_fread = fread +free = export_free +_free = export_free +freopen +_freopen = freopen +frexp +_frexp = frexp +frexpf +_frexpf = frexpf +fscanf +_fscanf = fscanf +fseek +_fseek = fseek +fsetpos +_fsetpos = fsetpos +fstat +_fstat = fstat +fstatfs +_fstatfs = fstatfs +fsync +_fsync = fsync +ftell +_ftell = ftell +ftime +_ftime = ftime +ftruncate +_ftruncate = ftruncate +fwrite +_fwrite = fwrite +gamma +_gamma = gamma +gammaf +_gammaf = gammaf +gcvt +_gcvt = gcvt +gcvtf +_gcvtf = gcvtf +getc +_getc = getc +getchar +_getchar = getchar +getcwd +_getcwd = getcwd +getdtablesize +_getdtablesize = getdtablesize +getegid +_getegid = getegid +geteuid +_geteuid = geteuid +getgid +_getgid = getgid +getgrgid +_getgrgid = getgrgid +getgrnam +_getgrnam = getgrnam +getgroups +_getgroups = getgroups +gethostname = cygwin_gethostname +_gethostname = cygwin_gethostname +getlogin +_getlogin = getlogin +getmntent +_getmntent = getmntent +get_osfhandle +_get_osfhandle = get_osfhandle +getpagesize +_getpagesize = getpagesize +getpass +_getpass = getpass +getpid +_getpid = getpid +getppid +_getppid = getppid +getrusage +_getrusage = getrusage +gets +_gets = gets +gettimeofday +_gettimeofday = gettimeofday +getuid +_getuid = getuid +glob +_glob = glob +globfree +_globfree = globfree +gmtime +_gmtime = gmtime +h_errno DATA +hypot +_hypot = hypot +hypotf +_hypotf = hypotf +ilogb +_ilogb = ilogb +ilogbf +_ilogbf = ilogbf +index +_index = index +infinity +_infinity = infinity +infinityf +_infinityf = infinityf +initgroups +ioctl +_ioctl = ioctl +iprintf +_iprintf = iprintf +isalnum +_isalnum = isalnum +isalpha +_isalpha = isalpha +isascii +_isascii = isascii +isatty +_isatty = isatty +iscntrl +_iscntrl = iscntrl +isdigit +_isdigit = isdigit +isgraph +_isgraph = isgraph +isinf +_isinf = isinf +isinff +_isinff = isinff +islower +_islower = islower +isnan +_isnan = isnan +isnanf +_isnanf = isnanf +isprint +_isprint = isprint +ispunct +_ispunct = ispunct +isspace +_isspace = isspace +isupper +_isupper = isupper +isxdigit +_isxdigit = isxdigit +j0 +_j0 = j0 +j0f +_j0f = j0f +j1 +_j1 = j1 +j1f +_j1f = j1f +jn +_jn = jn +jnf +_jnf = jnf +kill +_kill = kill +labs +_labs = labs +ldexp +_ldexp = ldexp +ldexpf +_ldexpf = ldexpf +ldiv +_ldiv = ldiv +lgamma +_lgamma = lgamma +lgammaf +_lgammaf = lgammaf +link +_link = link +localeconv +_localeconv = localeconv +localtime +_localtime = localtime +log +_log = log +log10 +_log10 = log10 +log10f +_log10f = log10f +log1p +_log1p = log1p +log1pf +_log1pf = log1pf +logb +_logb = logb +logbf +_logbf = logbf +logf +_logf = logf +login +logout +longjmp +_longjmp = longjmp +lseek +_lseek = lseek +lstat +_lstat = lstat +malloc = export_malloc +_malloc = export_malloc +matherr +_matherr = matherr +mblen +_mblen = mblen +mbstowcs +_mbstowcs = mbstowcs +mbtowc +_mbtowc = mbtowc +memchr +_memchr = memchr +memcmp +_memcmp = memcmp +memcpy +_memcpy = memcpy +memmove +_memmove = memmove +memset +_memset = memset +mkdir +_mkdir = mkdir +mknod +_mknod = mknod +mkstemp +_mkstemp = mkstemp +mktemp +_mktemp = mktemp +mktime +_mktime = mktime +mmap +mprotect +msync +munmap +modf +_modf = modf +modff +_modff = modff +nan +_nan = nan +nanf +_nanf = nanf +nextafter +_nextafter = nextafter +nextafterf +_nextafterf = nextafterf +open +_open = open +opendir +_opendir = opendir +pathconf +_pathconf = pathconf +perror +_perror = perror +pipe +_pipe +pow +_pow = pow +powf +_powf = powf +printf +_printf = printf +putc +_putc = putc +putchar +_putchar = putchar +puts +_puts = puts +putw +_putw = putw +qsort +_qsort = qsort +raise +_raise = raise +rand +_rand = rand +random +initstate +setstate +read +_read = read +readdir +_readdir = readdir +readlink +_readlink = readlink +readv +_readv = readv +realloc = export_realloc +_realloc = export_realloc +regcomp +_regcomp = regcomp +regexec +_regexec = regexec +regerror +_regerror = regerror +regfree +_regfree = regfree +remainder +_remainder = remainder +remainderf +_remainderf = remainderf +remove +_remove = remove +rename +_rename = rename +rewind +_rewind = rewind +rewinddir +_rewinddir = rewinddir +rindex +_rindex = rindex +rint +_rint = rint +rintf +_rintf = rintf +rmdir +_rmdir = rmdir +sbrk +_sbrk = sbrk +scalb +_scalb = scalb +scalbf +_scalbf = scalbf +scalbn +_scalbn = scalbn +scalbnf +_scalbnf = scalbnf +scandir +_scandir = scandir +scanf +_scanf = scanf +seekdir +_seekdir = seekdir +setbuf +_setbuf = setbuf +setdtablesize +_setdtablesize = setdtablesize +setgid +_setgid = setgid +setjmp +_setjmp = setjmp +setlocale +_setlocale = setlocale +setpgid +_setpgid = setpgid +setsid +_setsid = setsid +settimeofday +_settimeofday = settimeofday +seteuid +_seteuid = seteuid +setegid +_setegid = setegid +setuid +_setuid = setuid +chroot +_chroot = chroot +setvbuf +_setvbuf = setvbuf +sigaction +_sigaction = sigaction +sigaddset +_sigaddset = sigaddset +sigdelset +_sigdelset = sigdelset +sigismember +_sigismember = sigismember +sigemptyset +_sigemptyset = sigemptyset +sigfillset +_sigfillset = sigfillset +signal +_signal = signal +significand +_significand = significand +significandf +_significandf = significandf +sigpending +_sigpending = sigpending +sigprocmask +_sigprocmask = sigprocmask +sigsuspend +_sigsuspend = sigsuspend +sin +_sin = sin +sinf +_sinf = sinf +sinh +_sinh = sinh +sinhf +_sinhf = sinhf +siprintf +_siprintf = siprintf +sleep +_sleep = sleep +spawnl +_spawnl = spawnl +spawnle +_spawnle = spawnle +spawnlp +_spawnlp = spawnlp +spawnlpe +_spawnlpe = spawnlpe +spawnv +_spawnv = spawnv +spawnve +_spawnve = spawnve +spawnvp +_spawnvp = spawnvp +spawnvpe +_spawnvpe = spawnvpe +sprintf +_sprintf = sprintf +snprintf +_snprintf = snprintf +sqrt +_sqrt = sqrt +sqrtf +_sqrtf = sqrtf +srand +_srand = srand +srandom +sscanf +_sscanf = sscanf +stat +_stat = stat +statfs +_statfs = statfs +strcasecmp +_strcasecmp = strcasecmp +strcat +_strcat = strcat +strchr +_strchr = strchr +strcmp +_strcmp = strcmp +strcoll +_strcoll = strcoll +strcpy +_strcpy = strcpy +strcspn +_strcspn = strcspn +strdup +_strdup = strdup +strerror +_strerror = strerror +strlen +_strlen = strlen +strlwr +_strlwr = strlwr +strncasecmp +_strncasecmp = strncasecmp +strncat +_strncat = strncat +strncmp +_strncmp = strncmp +strncpy +_strncpy = strncpy +strpbrk +_strpbrk = strpbrk +strrchr +_strrchr = strrchr +strspn +_strspn = strspn +strstr +_strstr = strstr +strtod +_strtod = strtod +strtodf +_strtodf = strtodf +strtok +_strtok = strtok +strtol +_strtol = strtol +strtoul +_strtoul = strtoul +strupr +_strupr = strupr +strxfrm +_strxfrm = strxfrm +swab +_swab = swab +symlink +_symlink = symlink +sync +_sync = sync +sysconf +_sysconf = sysconf +system +_system = system +tan +_tan = tan +tanf +_tanf = tanf +tanh +_tanh = tanh +tanhf +_tanhf = tanhf +tcdrain +_tcdrain = tcdrain +tcflow +_tcflow = tcflow +tcflush +_tcflush = tcflush +tcgetattr +_tcgetattr = tcgetattr +tcgetpgrp +_tcgetpgrp = tcgetpgrp +tcsendbreak +_tcsendbreak = tcsendbreak +tcsetattr +_tcsetattr = tcsetattr +tcsetpgrp +_tcsetpgrp = tcsetpgrp +telldir +_telldir = telldir +tempnam +_tempnam = tempnam +time +_time = time +times +_times = times +timezone +tmpfile +_tmpfile = tmpfile +tmpnam +_tmpnam = tmpnam +toascii +_toascii = toascii +tolower +_tolower = tolower +toupper +_toupper = toupper +truncate +_truncate = truncate +ttyname +_ttyname = ttyname +tzset +_tzset = tzset +umask +_umask = umask +uname +_uname = uname +ungetc +_ungetc = ungetc +unlink +_unlink = unlink +utime +_utime = utime +utimes +_utimes = utimes +vfiprintf +_vfiprintf = vfiprintf +vfork +_vfork = vfork +vfprintf +_vfprintf = vfprintf +vprintf +_vprintf = vprintf +vsprintf +_vsprintf = vsprintf +vsnprintf +_vsnprintf = vsnprintf +wait +_wait = wait +waitpid +_waitpid = waitpid +wait3 +wait4 +wcstombs +_wcstombs = wcstombs +wctomb +_wctomb = wctomb +write +_write = write +writev +_writev = writev +y0 +y0f +y1 +y1f +yn +ynf +setmode +_setmode = setmode +__assertfail +getw +_getw = getw +getwd +_getwd = getwd +popen +_popen = popen +pclose +_pclose = pclose +strftime +_strftime = strftime +setgrent +_setgrent = setgrent +cuserid +_cuserid = cuserid +setpgrp +_setpgrp = setpgrp +mount +_mount = mount +setmntent +_setmntent = setmntent +endmntent +_endmntent = endmntent +umount +_umount = umount +wcscmp +_wcscmp = wcscmp +wcslen +_wcslen = wcslen +usleep +_usleep = usleep +wprintf +_wprintf = wprintf +memccpy +_memccpy = memccpy +getpwent +_getpwent = getpwent +endpwent +_endpwent = endpwent +setpwent +_setpwent = setpwent +getpwduid +_getpwduid = getpwduid +getpwnam +_getpwnam = getpwnam +getpwuid +_getpwuid = getpwuid +getpgrp +_getpgrp = getpgrp +getgrent +_getgrent = getgrent +__empty +ntohl +_ntohl = ntohl +htonl +_htonl = htonl +htons +_htons = htons +ntohs +_ntohs = ntohs +accept = cygwin_accept +bind = cygwin_bind +connect = cygwin_connect +herror = cygwin_herror +inet_addr = cygwin_inet_addr +inet_netof +inet_makeaddr +listen = cygwin_listen +getdomainname +_getdomainname = getdomainname +gethostbyaddr = cygwin_gethostbyaddr +gethostbyname = cygwin_gethostbyname +getpeername = cygwin_getpeername +getprotobyname = cygwin_getprotobyname +getprotobynumber = cygwin_getprotobynumber +getservbyname = cygwin_getservbyname +getservbyport = cygwin_getservbyport +getsockname = cygwin_getsockname +getsockopt = cygwin_getsockopt +recv = cygwin_recv +select = cygwin_select +_select = cygwin_select +send = cygwin_send +socket = cygwin_socket +setsockopt = cygwin_setsockopt +inet_ntoa = cygwin_inet_ntoa +recvfrom = cygwin_recvfrom +sendto = cygwin_sendto +shutdown = cygwin_shutdown +sethostent +endhostent +setpassent +_setpassent = setpassent +strsep +_strsep = strsep +syslog +_syslog = syslog +closelog +_closelog = closelog +openlog +_openlog = openlog +vhangup +_vhangup = vhangup +nice +_nice = nice +cygwin_getshared +cygwin32_getshared = cygwin_getshared +cygwin_conv_to_win32_path +cygwin_conv_to_full_win32_path +cygwin_conv_to_posix_path +cygwin_conv_to_full_posix_path +cygwin_posix_path_list_p +cygwin_win32_to_posix_path_list_buf_size +cygwin_posix_to_win32_path_list_buf_size +cygwin_win32_to_posix_path_list +cygwin_posix_to_win32_path_list +cygwin_split_path +cygwin_umount +cygwin32_conv_to_win32_path = cygwin_conv_to_win32_path +cygwin32_conv_to_full_win32_path = cygwin_conv_to_full_win32_path +cygwin32_conv_to_posix_path = cygwin_conv_to_posix_path +cygwin32_conv_to_full_posix_path = cygwin_conv_to_full_posix_path +cygwin32_posix_path_list_p = cygwin_posix_path_list_p +cygwin32_win32_to_posix_path_list_buf_size = cygwin_win32_to_posix_path_list_buf_size +cygwin32_posix_to_win32_path_list_buf_size = cygwin_posix_to_win32_path_list_buf_size +cygwin32_win32_to_posix_path_list = cygwin_win32_to_posix_path_list +cygwin32_posix_to_win32_path_list = cygwin_posix_to_win32_path_list +cygwin32_split_path = cygwin_split_path +cygwin_winpid_to_pid +cygwin32_winpid_to_pid = cygwin_winpid_to_pid +realpath +reent_data DATA +getenv +_getenv = getenv +putenv +_putenv = putenv +setenv +_setenv = setenv +unsetenv +_unsetenv = unsetenv +setitimer +getitimer +getpgid +killpg +pause +__cygwin_environ DATA +_ctype_ DATA +_sys_errlist DATA +_sys_nerr DATA +__mb_cur_max DATA +_timezone DATA +_daylight DATA +_tzname DATA +ptsname +grantpt +unlockpt +sexecve +sexecl +sexecle +sexeclp +sexeclpe +sexecv +sexecp +sexecvpe +ttyslot +rcmd = cygwin_rcmd +rresvport = cygwin_rresvport +rexec = cygwin_rexec +socketpair +strsignal +strtosigno +ctermid +dlopen +dlclose +dlsym +dlerror +dlfork +sigpause +cygwin_attach_handle_to_fd +cygwin32_attach_handle_to_fd = cygwin_attach_handle_to_fd +cygwin_internal +cygwin32_internal = cygwin_internal +@PTH_ALLOW@pthread_create +@PTH_ALLOW@pthread_attr_init +@PTH_ALLOW@pthread_attr_destroy +@PTH_ALLOW@pthread_attr_setstacksize +@PTH_ALLOW@pthread_attr_getstacksize +@PTH_ALLOW@pthread_exit +@PTH_ALLOW@pthread_join +@PTH_ALLOW@pthread_detach +@PTH_ALLOW@pthread_suspend +@PTH_ALLOW@pthread_continue +@PTH_ALLOW@pthread_key_create +@PTH_ALLOW@pthread_key_delete +@PTH_ALLOW@pthread_setspecific +@PTH_ALLOW@pthread_getspecific +@PTH_ALLOW@pthread_kill +@PTH_ALLOW@pthread_sigmask +@PTH_ALLOW@pthread_self +@PTH_ALLOW@pthread_equal +@PTH_ALLOW@pthread_mutex_init +@PTH_ALLOW@pthread_mutex_lock +@PTH_ALLOW@pthread_mutex_trylock +@PTH_ALLOW@pthread_mutex_unlock +@PTH_ALLOW@pthread_mutex_destroy +@PTH_ALLOW@sem_init +@PTH_ALLOW@sem_destroy +@PTH_ALLOW@sem_wait +@PTH_ALLOW@sem_trywait +@PTH_ALLOW@sem_post +acl +_acl = acl +facl +_facl = facl +aclcheck +_aclcheck = aclcheck +aclsort +_aclsort = aclsort +acltomode +_acltomode = acltomode +aclfrommode +_aclfrommode = aclfrommode +acltopbits +_acltopbits = acltopbits +aclfrompbits +_aclfrompbits = aclfrompbits +acltotext +_acltotext = acltotext +aclfromtext +_aclfromtext = aclfromtext diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc new file mode 100644 index 000000000..10652044e --- /dev/null +++ b/winsup/cygwin/dcrt0.cc @@ -0,0 +1,1063 @@ +/* dcrt0.cc -- essentially the main() for the Cygwin dll + + Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include "winsup.h" +#include "glob.h" +#include "exceptions.h" +#include "dll_init.h" +#include "autoload.h" +#include + +#define MAX_AT_FILE_LEVEL 10 + +HANDLE NO_COPY hMainProc = NULL; +HANDLE NO_COPY hMainThread = NULL; + +static per_process dummy_user_data = {0}; +per_process NO_COPY *user_data = &dummy_user_data; + +per_thread_waitq NO_COPY waitq_storage; +per_thread_vfork NO_COPY vfork_storage; +per_thread_signal_dispatch NO_COPY signal_dispatch_storage; + +per_thread NO_COPY *threadstuff[] = {&waitq_storage, + &vfork_storage, + &signal_dispatch_storage, + NULL}; + +BOOL display_title = FALSE; +BOOL strip_title_path = FALSE; +BOOL allow_glob = TRUE; + +HANDLE NO_COPY parent_alive = NULL; + +/* Used in SIGTOMASK for generating a bit for insertion into a sigset_t. + This is subtracted from the signal number prior to shifting the bit. + In older versions of cygwin, the signal was used as-is to shift the + bit for masking. So, we'll temporarily detect this and set it to zero + for programs that are linked using older cygwins. This is just a stopgap + measure to allow an orderly transfer to the new, correct sigmask method. */ +unsigned int signal_shift_subtract = 1; + +extern "C" +{ + /* This is an exported copy of environ which can be used by DLLs + which use cygwin.dll. */ + char **__cygwin_environ; + /* __progname used in getopt error message */ + char *__progname; + struct _reent reent_data; +}; + +static void dll_crt0_1 (); + +char *old_title = NULL; +char title_buf[TITLESIZE + 1]; + +static void +do_global_dtors (void) +{ + if (user_data->dtors) + { + void (**pfunc)() = user_data->dtors; + while (*++pfunc) + (*pfunc) (); + } +} + +static void __stdcall +do_global_ctors (void (**in_pfunc)(), int force) +{ + if (!force) + { + if (user_data->forkee || user_data->run_ctors_p) + return; // inherit constructed stuff from parent pid + user_data->run_ctors_p = 1; + } + + /* Run ctors backwards, so skip the first entry and find how many + there are, then run them. */ + + void (**pfunc)() = in_pfunc; + + while (*++pfunc) + ; + while (--pfunc > in_pfunc) + (*pfunc) (); + + if (user_data != &dummy_user_data) + atexit (do_global_dtors); +} + +/* remember the type of Win32 OS being run for future use. */ +os_type NO_COPY os_being_run; + +/* set_os_type: Set global variable os_being_run with type of Win32 + operating system being run. This information is used internally + to manage the inconsistency in Win32 API calls between Win32 OSes. */ +/* Cygwin internal */ +static void +set_os_type () +{ + OSVERSIONINFO os_version_info; + os_version_info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); + + GetVersionEx (&os_version_info); + + switch (os_version_info.dwPlatformId) + { + case VER_PLATFORM_WIN32_NT: + os_being_run = winNT; + break; + case VER_PLATFORM_WIN32_WINDOWS: + if (os_version_info.dwMinorVersion == 0) + os_being_run = win95; + else /* os_version_info.dwMinorVersion == 10 */ + os_being_run = win98; + break; + case VER_PLATFORM_WIN32s: + os_being_run = win32s; + break; + default: + os_being_run = unknown; + break; + } +} + +host_dependent_constants NO_COPY host_dependent; + +/* Constructor for host_dependent_constants. */ + +void +host_dependent_constants::init (void) +{ + /* fhandler_disk_file::lock needs a platform specific upper word + value for locking entire files. + + fhandler_base::open requires host dependent file sharing + attributes. */ + + switch (os_being_run) + { + case winNT: + win32_upper = 0xffffffff; + shared = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + break; + + case win98: + case win95: + case win32s: + win32_upper = 0x00000000; + shared = FILE_SHARE_READ | FILE_SHARE_WRITE; + break; + + default: + api_fatal ("unrecognized system type"); + } +} + +/* Save the program name. It's used in debugging messages and by + the fork code (forking spawns a copy of us). Copy it into a temp and + then into the final spot because debugging messages use + myself->progname. Try getting the absolute path from the + module handle, if this fails get the name from the path. + This call references $PATH so we can't do this until the environment + vars are set up. */ +/* FIXME: What if argv[0] is relative, $PATH changes, and then the program + tries to do a fork? */ + +static void __stdcall +getprogname (char *argv0) +{ + char tmp[MAX_PATH]; + + if (user_data->hmodule != 0) + { + if (GetModuleFileName (user_data->hmodule, tmp, MAX_PATH) == 0) + find_exec (argv0, tmp); + } + else + find_exec (argv0, tmp); + strcpy (myself->progname, tmp); +} + +/* + * Replaces -@file in the command line with the contents of the file. + * There may be multiple -@file's in a single command line + * A \-@file is replaced with -@file so that echo \-@foo would print + * -@foo and not the contents of foo. + */ +static int __stdcall +insert_file (char *name, char *&cmd) +{ + HANDLE f; + DWORD size; + + f = CreateFile (name + 1, + GENERIC_READ, /* open for reading */ + FILE_SHARE_READ, /* share for reading */ + &sec_none_nih, /* no security */ + OPEN_EXISTING, /* existing file only */ + FILE_ATTRIBUTE_NORMAL, /* normal file */ + NULL); /* no attr. template */ + + if (f == INVALID_HANDLE_VALUE) + { + debug_printf ("couldn't open file '%s', %E", name); + return FALSE; + } + + /* This only supports files up to about 4 billion bytes in + size. I am making the bold assumption that this is big + enough for this feature */ + size = GetFileSize (f, NULL); + if (size == 0xFFFFFFFF) + { + debug_printf ("couldn't get file size for '%s', %E", name); + return FALSE; + } + + int new_size = strlen (cmd) + size + 2; + char *tmp = (char *) malloc (new_size); + if (!tmp) + { + debug_printf ("malloc failed, %E"); + return FALSE; + } + + /* realloc passed as it should */ + DWORD rf_read; + BOOL rf_result; + rf_result = ReadFile (f, tmp, size, &rf_read, NULL); + CloseHandle (f); + if (!rf_result || (rf_read != size)) + { + debug_printf ("ReadFile failed, %E"); + return FALSE; + } + + tmp[size++] = ' '; + strcpy (tmp + size, cmd); + cmd = tmp; + return TRUE; +} + +static inline int +isquote (char c) +{ + char ch = c; + return ch == '"' || ch == '\''; +} + +/* Step over a run of characters delimited by quotes */ +static __inline char * +quoted (char *word, char *cmd, int winshell) +{ + char *p; + char quote = *cmd; + + /* If this is being run from a Windows shell then we have + to preserve quotes for globify to play with later. */ + if (winshell) + { + while (*++cmd) + if ((p = strchr (cmd, quote)) == NULL) + { + cmd = strchr (cmd, '\0'); // no closing quote + break; + } + else if (p[1] == quote) + { + *p++ = '\\'; + cmd = p; // a quoted quote + } + else + { + cmd = p + 1; // point to after end + break; + } + return cmd; + } + + /* When running as a child of a cygwin process, the quoted + characters should have been placed here by spawn_guts, so + we'll just pinch them out of the command string unless + they're quoted with a preceding \ */ + strcpy (cmd, cmd + 1); + while (*cmd) + { + if (*cmd != quote) + cmd++; + else if (cmd[1] == quote) + strcpy (cmd++, cmd + 1); + else + { + strcpy (cmd, cmd + 1); + break; + } + } + return cmd; +} + +/* Perform a glob on word if it contains wildcard characters. + Also quote every character between quotes to force glob to + treat the characters literally. */ +static int __stdcall +globify (char *word, char **&argv, int &argc, int &argvlen) +{ + if (*word != '~' && strpbrk (word, "?*[\"\'(){}") == NULL) + return 0; + + int n = 0; + char *p, *s; + int dos_spec = isalpha(*word) && word[1] == ':' ? 1 : 0; + + /* We'll need more space if there are quoting characters in + word. If that is the case, doubling the size of the + string should provide more than enough space. */ + if (strpbrk (word, "'\"")) + n = strlen (word); + char pattern[strlen (word) + ((dos_spec + 1) * n) + 1]; + + /* Fill pattern with characters from word, quoting any + characters found within quotes. */ + for (p = pattern, s = word; *s != '\000'; s++, p++) + if (!isquote (*s)) + { + if (dos_spec && *s == '\\') + *p++ = '\\'; + *p = *s; + } + else + { + char quote = *s; + while (*++s && *s != quote) + { + if (*s == '\\' && s[1] == quote) + s++; + *p++ = '\\'; + *p++ = *s; + } + if (*s == quote) + p--; + if (*s == '\0') + break; + } + + *p = '\0'; + + glob_t gl; + gl.gl_offs = 0; + + /* Attempt to match the argument. Return just word (minus quoting) if no match. */ + if (glob (pattern, GLOB_TILDE | GLOB_NOCHECK | GLOB_BRACE | GLOB_QUOTE, NULL, &gl) || !gl.gl_pathc) + return 0; + + /* Allocate enough space in argv for the matched filenames. */ + n = argc; + if ((argc += gl.gl_pathc) > argvlen) + { + argvlen = argc + 10; + argv = (char **) realloc (argv, (1 + argvlen) * sizeof (argv[0])); + } + + /* Copy the matched filenames to argv. */ + char **gv = gl.gl_pathv; + char **av = argv + n; + while (*gv) + { + debug_printf ("argv[%d] = '%s'\n", n++, *gv); + *av++ = *gv++; + } + + /* Clean up after glob. */ + free (gl.gl_pathv); + return 1; +} + +/* Build argv, argc from string passed from Windows. */ + +static void __stdcall +build_argv (char *cmd, char **&argv, int &argc, int winshell) +{ + int argvlen = 0; + char *alloc_cmd = NULL; // command allocated by insert_file + int nesting = 0; // monitor "nesting" from insert_file + + argc = 0; + argvlen = 0; + argv = NULL; + + /* Scan command line until there is nothing left. */ + while (*cmd) + { + /* Ignore spaces */ + if (issep (*cmd)) + { + cmd++; + continue; + } + + /* Found the beginning of an argument. */ + char *word = cmd; + char *sawquote = NULL; + while (*cmd) + { + if (*cmd != '"' && (!winshell || *cmd != '\'')) + cmd++; // Skip over this character + else + /* Skip over characters until the closing quote */ + { + sawquote = cmd; + cmd = quoted (word, cmd, winshell); + } + if (issep (*cmd)) // End of argument if space + break; + } + if (*cmd) + *cmd++ = '\0'; // Terminate `word' + + /* Possibly look for @file construction assuming that this isn't + the very first argument and the @ wasn't quoted */ + if (argc && sawquote != word && *word == '@') + { + if (++nesting > MAX_AT_FILE_LEVEL) + api_fatal ("Too many levels of nesting for %s", word); + if (insert_file (word, cmd)) + { + if (alloc_cmd) + free (alloc_cmd); // Free space from previous insert_file + alloc_cmd = cmd; // and remember it for next time. + continue; // There's new stuff in cmd now + } + } + + /* See if we need to allocate more space for argv */ + if (argc >= argvlen) + { + argvlen = argc + 10; + argv = (char **) realloc (argv, (1 + argvlen) * sizeof (argv[0])); + } + + /* Add word to argv file after (optional) wildcard expansion. */ + if (!winshell || !argc || !globify (word, argv, argc, argvlen)) + { + debug_printf ("argv[%d] = '%s'\n", argc, word); + argv[argc++] = word; + } + } + + argv[argc] = NULL; + debug_printf ("argv[%d] = '%s'\n", argc, argv[argc]); +} + +/* sanity and sync check */ +void __stdcall +check_sanity_and_sync (per_process *p) +{ + /* Sanity check to make sure developers didn't change the per_process */ + /* struct without updating SIZEOF_PER_PROCESS [it makes them think twice */ + /* about changing it]. */ + if (sizeof (per_process) != SIZEOF_PER_PROCESS) + { + api_fatal ("per_process sanity check failed"); + } + + /* Make sure that the app and the dll are in sync. */ + + /* Complain if older than last incompatible change */ + if (p->dll_major < CYGWIN_VERSION_DLL_EPOCH) + api_fatal ("cygwin DLL and APP are out of sync -- DLL version mismatch %d < %d", + p->dll_major, CYGWIN_VERSION_DLL_EPOCH); + + /* magic_biscuit != 0 if using the old style version numbering scheme. */ + if (p->magic_biscuit != SIZEOF_PER_PROCESS) + api_fatal ("Incompatible cygwin .dll -- incompatible per_process info %d != %d", + p->magic_biscuit, SIZEOF_PER_PROCESS); + + /* Complain if incompatible API changes made */ + if (p->api_major != cygwin_version.api_major) + api_fatal ("cygwin DLL and APP are out of sync -- API version mismatch %d < %d", + p->api_major, cygwin_version.api_major); + + if (CYGWIN_VERSION_DLL_MAKE_COMBINED (p->dll_major, p->dll_minor) <= + CYGWIN_VERSION_DLL_BAD_SIGNAL_MASK) + signal_shift_subtract = 0; +} + +static NO_COPY STARTUPINFO si; +# define ciresrv ((struct child_info_fork *)(si.lpReserved2)) +child_info_fork NO_COPY *child_proc_info = NULL; +static MEMORY_BASIC_INFORMATION sm; + +#define EBP 6 +#define ESP 7 + +extern void __inline__ +alloc_stack_hard_way (child_info_fork *ci, volatile char *b) +{ + void *new_stack_pointer; + MEMORY_BASIC_INFORMATION m; + + if (!VirtualAlloc (ci->stacktop, + (DWORD) ci->stackbottom - (DWORD) ci->stacktop, + MEM_RESERVE, PAGE_NOACCESS)) + api_fatal ("fork: can't reserve memory for stack %p - %p, %E", + ci->stacktop, ci->stackbottom); + + new_stack_pointer = (void *) ((LPBYTE) ci->stackbottom - ci->stacksize); + + if (!VirtualAlloc (new_stack_pointer, ci->stacksize, MEM_COMMIT, + PAGE_EXECUTE_READWRITE)) + api_fatal ("fork: can't commit memory for stack %p(%d), %E", + new_stack_pointer, ci->stacksize); + if (!VirtualQuery ((LPCVOID) new_stack_pointer, &m, sizeof m)) + api_fatal ("fork: couldn't get new stack info, %E"); + m.BaseAddress = (LPVOID)((DWORD)m.BaseAddress - 1); + if (!VirtualAlloc ((LPVOID) m.BaseAddress, 1, MEM_COMMIT, + PAGE_EXECUTE_READWRITE|PAGE_GUARD)) + api_fatal ("fork: couldn't allocate new stack guard page %p, %E", + m.BaseAddress); + if (!VirtualQuery ((LPCVOID) m.BaseAddress, &m, sizeof m)) + api_fatal ("fork: couldn't get new stack info, %E"); + ci->stacktop = m.BaseAddress; + *b = 0; +} + +/* extend the stack prior to fork longjmp */ + +extern void __inline__ +alloc_stack (child_info_fork *ci) +{ + /* FIXME: adding 16384 seems to avoid a stack copy problem during + fork on Win95, but I don't know exactly why yet. DJ */ + volatile char b[ci->stacksize + 16384]; + + if (ci->type == PROC_FORK) + ci->stacksize = 0; // flag to fork not to do any funny business + else + { + if (!VirtualQuery ((LPCVOID) &b, &sm, sizeof sm)) + api_fatal ("fork: couldn't get stack info, %E"); + + if (sm.AllocationBase != ci->stacktop) + alloc_stack_hard_way (ci, b + sizeof(b) - 1); + else + ci->stacksize = 0; + } + + return; +} + +/* These must be static due to the way we have to deal with forked + processes. */ +static NO_COPY LPBYTE info = NULL; +static NO_COPY int mypid = 0; +static int argc = 0; +static char **argv = NULL; + +#ifdef _MT_SAFE +ResourceLocks _reslock NO_COPY; +MTinterface _mtinterf NO_COPY; +#endif + +/* Take over from libc's crt0.o and start the application. Note the + various special cases when Cygwin DLL is being runtime loaded (as + opposed to being link-time loaded by Cygwin apps) from a non + cygwin app via LoadLibrary. */ +static void +dll_crt0_1 () +{ + /* According to onno@stack.urc.tue.nl, the exception handler record must + be on the stack. */ + /* FIXME: Verify forked children get their exception handler set up ok. */ + exception_list cygwin_except_entry; + + do_global_ctors (&__CTOR_LIST__, 1); + +#ifdef DEBUGGING + if (child_proc_info) + switch (child_proc_info->type) + { + case PROC_FORK: + case PROC_FORK1: + ProtectHandle (child_proc_info->forker_finished); + case PROC_EXEC: + ProtectHandle (child_proc_info->subproc_ready); + } + ProtectHandle (hMainProc); + ProtectHandle (hMainThread); +#endif + + regthread ("main", GetCurrentThreadId ()); + + check_sanity_and_sync (user_data); + + /* Nasty static stuff needed by newlib -- point to a local copy of + the reent stuff. + Note: this MUST be done here (before the forkee code) as the + fork copy code doesn't copy the data in libccrt0.cc (that's why we + pass in the per_process struct into the .dll from libccrt0). */ + + *(user_data->impure_ptr_ptr) = &reent_data; + _impure_ptr = &reent_data; + +#ifdef _MT_SAFE + user_data->resourcelocks = &_reslock; + user_data->resourcelocks->Init(); + + user_data->threadinterface = &_mtinterf; + user_data->threadinterface->Init0(); +#endif + + /* Set the os_being_run global. */ + set_os_type (); + + /* If we didn't call SetFileApisToOEM, console I/O calls would use a + different codepage than other Win32 API calls. In some languages + (not English), this would result in "cat > filename" creating a file + by a different name than if CreateFile was used to create filename. + SetFileApisToOEM prevents this problem by making all calls use the + OEM codepage. */ + + SetFileApisToOEM (); + + /* Initialize the host dependent constants object. */ + host_dependent.init (); + + /* Initialize the cygwin subsystem if this is the first process, + or attach to the shared data structure if it's already running. */ + shared_init (); + + if (mypid) + set_myself (cygwin_shared->p[mypid]); + + (void) SetErrorMode (SEM_FAILCRITICALERRORS); + + /* Initialize the heap. */ + heap_init (); + + /* Initialize events. */ + events_init (); + + threadname_init (); + debug_init (); + + /* Initialize SIGSEGV handling, etc... Because the exception handler + references data in the shared area, this must be done after + shared_init. */ + init_exceptions (&cygwin_except_entry); + + if (user_data->forkee) + { + /* If we've played with the stack, stacksize != 0. That means that + fork() was invoked from other than the main thread. Make sure that + frame pointer is referencing the new stack so that the OS knows what + to do when it needs to increase the size of the stack. + + NOTE: Don't do anything that involves the stack until you've completed + this step. */ + if (ciresrv->stacksize) + { + asm ("movl %0,%%fs:4" : : "r" (ciresrv->stackbottom)); + asm ("movl %0,%%fs:8" : : "r" (ciresrv->stacktop)); + } + + longjmp (ciresrv->jmp, ciresrv->cygpid); + } + + /* Initialize our process table entry. Don't use the parent info for + dynamically loaded case. */ + pinfo_init ((dynamically_loaded) ? NULL : info); + + if (!old_title && GetConsoleTitle (title_buf, TITLESIZE)) + old_title = title_buf; + + /* Nasty static stuff needed by newlib - initialize it. + Note that impure_ptr has already been set up to point to this above + NB. This *MUST* be done here, just after the forkee code as some + of the calls below (eg. uinfo_init) do stdio calls - this area must + be set to zero before then. */ + +#ifdef _MT_SAFE + user_data->threadinterface->ClearReent(); + user_data->threadinterface->Init1(); +#else + memset (&reent_data, 0, sizeof (reent_data)); + reent_data._errno = 0; + reent_data._stdin = reent_data.__sf + 0; + reent_data._stdout = reent_data.__sf + 1; + reent_data._stderr = reent_data.__sf + 2; +#endif + + char *line = GetCommandLineA (); + CharToOem (line, line); + + line = strcpy ((char *) alloca (strlen (line) + 1), line); + + /* Set new console title if appropriate. */ + + if (display_title && !dynamically_loaded) + { + char *cp = line; + if (strip_title_path) + for (char *ptr = cp; *ptr && *ptr != ' '; ptr++) + if (isdirsep (*ptr)) + cp = ptr + 1; + set_console_title (cp); + } + + /* Allocate dtable */ + dtable_init (); + + /* Initialize signal/subprocess handling. */ + sigproc_init (); + + /* Connect to tty. */ + tty_init (); + + /* Set up standard fds in file descriptor table. */ + hinfo_init (); + +#if 0 + /* Initialize uid, gid. */ + uinfo_init (); +#endif + + syscall_printf ("Application CYGWIN version: %d.%d, api: %d.%d", + user_data->dll_major, user_data->dll_minor, + user_data->api_major, user_data->api_minor); + syscall_printf ("CYGWIN DLL version: %d.%d, api: %d.%d", + cygwin_version.dll_major, cygwin_version.dll_minor, + cygwin_version.api_major, cygwin_version.api_minor); + + /* Scan the command line and build argv. Expand wildcards if not + called from another cygwin process. */ + build_argv (line, argv, argc, + NOTSTATE (myself, PID_CYGPARENT) && allow_glob); + + /* Convert argv[0] to posix rules if it's currently blatantly + win32 style. */ + if ((strchr (argv[0], ':')) || (strchr (argv[0], '\\'))) + { + char *new_argv0 = (char *) alloca (MAX_PATH); + cygwin_conv_to_posix_path (argv[0], new_argv0); + argv[0] = new_argv0; + } + + getprogname (argv[0]); + /* Set up __progname for getopt error call. */ + __progname = argv[0]; + + /* Call init of loaded dlls. */ + DllList::the().initAll(); + + set_errno (0); + debug_printf ("user_data->main %p", user_data->main); + + /* Flush signals and ensure that signal thread is up and running. Can't + do this for noncygwin case since the signal thread is blocked due to + LoadLibrary serialization. */ + if (!dynamically_loaded) + sig_send (NULL, __SIGFLUSH); + + /* Initialize uid, gid. */ + uinfo_init (); + + if (user_data->main && !dynamically_loaded) + exit (user_data->main (argc, argv, *user_data->envptr)); +} + +/* Wrap the real one, otherwise gdb gets confused about + two symbols with the same name, but different addresses. + + UPTR is a pointer to global data that lives on the libc side of the + line [if one distinguishes the application from the dll]. */ + +void +dll_crt0 (per_process *uptr) +{ + char zeros[sizeof (ciresrv->zero)] = {0}; + /* Set the local copy of the pointer into the user space. */ + user_data = uptr; + user_data->heapbase = user_data->heapptr = user_data->heaptop = NULL; + + set_console_handler (); + if (!DuplicateHandle (GetCurrentProcess (), GetCurrentProcess (), + GetCurrentProcess (), &hMainProc, 0, FALSE, + DUPLICATE_SAME_ACCESS)) + hMainProc = GetCurrentProcess (); + + DuplicateHandle (hMainProc, GetCurrentThread (), hMainProc, + &hMainThread, 0, FALSE, DUPLICATE_SAME_ACCESS); + + GetStartupInfo (&si); + if (si.cbReserved2 >= EXEC_MAGIC_SIZE && + memcmp (ciresrv->zero, zeros, sizeof (zeros)) == 0) + { + switch (ciresrv->type) + { + case PROC_EXEC: + case PROC_SPAWN: + case PROC_FORK: + case PROC_FORK1: + { + HANDLE me = hMainProc; + child_proc_info = ciresrv; + mypid = child_proc_info->cygpid; + cygwin_shared_h = child_proc_info->shared_h; + console_shared_h = child_proc_info->console_h; + + /* We don't want subprocesses to inherit this */ + if (!dynamically_loaded) + { + if (!DuplicateHandle (me, child_proc_info->parent_alive, + me, &parent_alive, 0, 0, + DUPLICATE_SAME_ACCESS + | DUPLICATE_CLOSE_SOURCE)) + system_printf ("parent_alive DuplicateHandle failed, %E"); + } + else if (parent_alive) + parent_alive = NULL; + + switch (child_proc_info->type) + { + case PROC_EXEC: + case PROC_SPAWN: + info = si.lpReserved2 + ciresrv->cb; + break; + case PROC_FORK: + case PROC_FORK1: + user_data->forkee = child_proc_info->cygpid; + user_data->heaptop = child_proc_info->heaptop; + user_data->heapbase = child_proc_info->heapbase; + user_data->heapptr = child_proc_info->heapptr; + alloc_stack (ciresrv); // may never return + } + break; + } + default: + if ((ciresrv->type & PROC_MAGIC_MASK) == PROC_MAGIC_GENERIC) + api_fatal ("conflicting versions of cygwin1.dll detected. Use only the most recent version.\n"); + } + } + dll_crt0_1 (); +} + +extern "C" void +__main (void) +{ + do_global_ctors (user_data->ctors, FALSE); +} + +enum + { + ES_SIGNAL = 1, + ES_CLOSEALL = 2, + ES_SIGPROCTERMINATE = 3 + }; + +extern "C" void __stdcall +do_exit (int status) +{ + BOOL cleanup_pinfo; + UINT n = (UINT) status; + static int NO_COPY exit_state = 0; + + syscall_printf ("do_exit (%d)", n); + + vfork_save *vf = vfork_storage.val (); + if (vf != NULL && vf->pid < 0) + { + vf->pid = status < 0 ? status : -status; + longjmp (vf->j, 1); + } + + if (exit_state < ES_SIGNAL) + { + exit_state = ES_SIGNAL; + if (!(n & EXIT_REPARENTING)) + { + signal (SIGCHLD, SIG_IGN); + signal (SIGHUP, SIG_IGN); + signal (SIGINT, SIG_IGN); + signal (SIGQUIT, SIG_IGN); + } + } + + if ((hExeced && hExeced != INVALID_HANDLE_VALUE) || (n & EXIT_NOCLOSEALL)) + n &= ~EXIT_NOCLOSEALL; + else if (exit_state < ES_CLOSEALL) + { + exit_state = ES_CLOSEALL; + close_all_files (); + } + + if (exit_state < ES_SIGPROCTERMINATE) + { + exit_state = ES_SIGPROCTERMINATE; + sigproc_terminate (); + } + + if (n & EXIT_REPARENTING) + { + n &= ~EXIT_REPARENTING; + cleanup_pinfo = FALSE; + } + else + { + myself->stopsig = 0; + + /* restore console title */ + if (old_title && display_title) + set_console_title (old_title); + + /* Kill orphaned children on group leader exit */ + if (myself->pid == myself->pgid) + { + sigproc_printf ("%d == pgrp %d, send SIG{HUP,CONT} to stopped children", + myself->pid, myself->pgid); + kill_pgrp (myself->pgid, -SIGHUP); + } + + /* Kill the foreground process group on session leader exit */ + if (getpgrp () > 0 && myself->pid == myself->sid && tty_attached (myself)) + { + tty *tp = cygwin_shared->tty[myself->ctty]; + sigproc_printf ("%d == sid %d, send SIGHUP to children", + myself->pid, myself->sid); + + if (tp->getsid () == myself->sid) + kill (-tp->getpgid (), SIGHUP); + } + tty_terminate (); + cleanup_pinfo = TRUE; + } + + window_terminate (); + fill_rusage (&myself->rusage_self, hMainProc); + + events_terminate (); + + if (hExeced && hExeced != INVALID_HANDLE_VALUE) + { + debug_printf ("Killing(%d) non-cygwin process, handle %p", n, hExeced); + TerminateProcess (hExeced, n); + ForceCloseHandle1 (hExeced, childhProc); + } + + if (cleanup_pinfo) + myself->record_death (); // Locks pinfo mutex + else + sigproc_printf ("not cleanup_pinfo"); + + shared_terminate (); + + sigproc_printf ("calling ExitProcess %d", n); + minimal_printf ("winpid %d, exit %d", GetCurrentProcessId (), n); + ExitProcess (n); +} + +extern "C" void +_exit (int n) +{ + do_exit ((DWORD) n & 0xffff); +} + +extern "C" void +__api_fatal (const char *fmt, ...) +{ + char buf[4096]; + va_list ap; + + va_start (ap, fmt); + __small_vsprintf (buf, fmt, ap); + va_end (ap); + small_printf ("%s\n", buf); + + /* We are going down without mercy. Make sure we reset + our process_state. */ + if (user_data != NULL) + { + sigproc_terminate (); + myself->record_death (FALSE); + } +#ifdef DEBUGGING + (void) try_to_debug (); +#endif + ExitProcess (1); +} + +extern "C" { +static void noload (char *s) __asm__ ("noload"); +static void __attribute__((unused)) +noload (char *s) +{ + api_fatal ("couldn't dynamically determine load address for '%s', %E", s); +} + +__asm__ (" +.globl cygwin_dll_func_load +cygwin_dll_func_load: + movl (%esp),%eax # 'Return address' contains load info + addl $8,%eax # Address of name of function to load + pushl %eax # Second argument + movl -4(%eax),%eax # Address of Handle to DLL + pushl (%eax) # Handle to DLL + call _GetProcAddress@8# Load it + test %eax,%eax # Success? + jne gotit # Yes + popl %eax # No. Get back + addl $8,%eax # pointer to name + pushl %eax # and + call noload # issue an error +gotit: + popl %ecx # Pointer to 'return address' + movb $0xe0,-1(%ecx) # Turn preceding call to a jmp *%eax + movl %eax,(%ecx) # Point dispatch to address loaded above + jmp *%eax +"); +} + +LoadDLLinitfunc (user32) +{ + HANDLE h; + + if ((h = LoadLibrary ("user32.dll")) != NULL) + user32_handle = h; + else if (!user32_handle) + api_fatal ("could not load user32.dll, %E"); + + return 0; /* Already done by another thread? */ +} + +LoadDLLinit (user32) +LoadDLLfunc (CharToOemA, CharToOemA@8, user32) +LoadDLLfunc (CreateWindowExA, CreateWindowExA@48, user32) +LoadDLLfunc (DefWindowProcA, DefWindowProcA@16, user32) +LoadDLLfunc (DispatchMessageA, DispatchMessageA@4, user32) +LoadDLLfunc (FindWindowA, FindWindowA@8, user32) +LoadDLLfunc (GetMessageA, GetMessageA@16, user32) +LoadDLLfunc (GetProcessWindowStation, GetProcessWindowStation@0, user32) +LoadDLLfunc (GetThreadDesktop, GetThreadDesktop@4, user32) +LoadDLLfunc (GetUserObjectInformationA, GetUserObjectInformationA@20, user32) +LoadDLLfunc (KillTimer, KillTimer@8, user32) +LoadDLLfunc (MessageBoxA, MessageBoxA@16, user32) +LoadDLLfunc (MsgWaitForMultipleObjects, MsgWaitForMultipleObjects@20, user32) +LoadDLLfunc (OemToCharW, OemToCharW@8, user32) +LoadDLLfunc (PeekMessageA, PeekMessageA@20, user32) +LoadDLLfunc (PostMessageA, PostMessageA@16, user32) +LoadDLLfunc (PostQuitMessage, PostQuitMessage@4, user32) +LoadDLLfunc (RegisterClassA, RegisterClassA@4, user32) +LoadDLLfunc (SendMessageA, SendMessageA@16, user32) +LoadDLLfunc (SetTimer, SetTimer@16, user32) +LoadDLLfunc (SetUserObjectSecurity, SetUserObjectSecurity@12, user32) diff --git a/winsup/cygwin/debug.cc b/winsup/cygwin/debug.cc new file mode 100644 index 000000000..cbf3179be --- /dev/null +++ b/winsup/cygwin/debug.cc @@ -0,0 +1,326 @@ +/* debug.cc + + Copyright 1998, 1999, 2000 Cygnus Solutions. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#define NO_DEBUG_DEFINES +#include "winsup.h" +#include "exceptions.h" + +static muto NO_COPY *threadname_lock = NULL; +#define lock_threadname() \ + do {if (threadname_lock) threadname_lock->acquire (INFINITE); } while (0) + +#define unlock_threadname() \ + do {if (threadname_lock) threadname_lock->release (); } while (0) + +typedef struct + { + DWORD id; + const char *name; + } thread_info; + +static NO_COPY thread_info threads[32] = {{0}}; // increase as necessary +#define NTHREADS (sizeof(threads) / sizeof(threads[0])) + +void +threadname_init () +{ + threadname_lock = new_muto (FALSE, NULL); +} + +void __stdcall +regthread (const char *name, DWORD tid) +{ + lock_threadname (); + for (DWORD i = 0; i < NTHREADS; i++) + if (threads[i].name == NULL || strcmp (threads[i].name, name) == 0 || + threads[i].id == tid) + { + threads[i].name = name; + threads[i].id = tid; + break; + } + unlock_threadname (); +} + +struct thread_start + { + LONG notavail; + LPTHREAD_START_ROUTINE func; + VOID *arg; + }; + +/* A place to store arguments to thread_stub since they can't be + stored on the stack. An available element is !notavail. */ +thread_start NO_COPY start_buf[NTHREADS] = {{0, NULL,NULL}}; + +/* Initial stub called by makethread. Performs initial per-thread + initialization. */ +static DWORD WINAPI +thread_stub (VOID *arg) +{ + LPTHREAD_START_ROUTINE threadfunc = ((thread_start *) arg)->func; + VOID *threadarg = ((thread_start *) arg)->arg; + + exception_list except_entry; + + /* Give up our slot in the start_buf array */ + InterlockedExchange (&((thread_start *) arg)->notavail, 0); + +#ifdef _MT_SAFE + /* marco@ddi.nl: Needed for the reent's of this local dll thread + I assume that the local threads are using the reent structure of + the main thread + */ + if ( !TlsSetValue(user_data->threadinterface->reent_index, + &user_data->threadinterface->reents) ) + api_fatal(" Sig proc MT init failed\n"); +#endif + + /* Initialize this threads ability to respond to things like + SIGSEGV or SIGFPE. */ + init_exceptions (&except_entry); + + return threadfunc (threadarg); +} + +/* Wrapper for CreateThread. Registers the thread name/id and ensures that + cygwin threads are properly initialized. */ +HANDLE __stdcall +makethread (LPTHREAD_START_ROUTINE start, LPVOID param, DWORD flags, + const char *name) +{ + DWORD tid; + HANDLE h; + SECURITY_ATTRIBUTES *sa; + thread_start *info; /* Various information needed by the newly created thread */ + + for (;;) + { + /* Search the start_buf array for an empty slot to use */ + for (info = start_buf; info < start_buf + NTHREADS; info++) + if (!InterlockedExchange (&info->notavail, 1)) + goto out; + + /* Should never hit here, but be defensive anyway. */ + Sleep (0); + } + +out: + info->func = start; /* Real function to start */ + info->arg = param; /* The single parameter to the thread */ + + if (*name != '+') + sa = &sec_none_nih; /* The handle should not be inherited by subprocesses. */ + else + { + name++; + sa = &sec_none; /* The handle should be inherited by subprocesses. */ + } + + if ((h = CreateThread (sa, 0, thread_stub, (VOID *) info, flags, &tid))) + regthread (name, tid); /* Register this name/thread id for debugging output. */ + + return h; +} + +/* Return the symbolic name of the current thread for debugging. + */ +const char * __stdcall +threadname (DWORD tid, int lockit) +{ + const char *res = NULL; + if (!tid) + tid = GetCurrentThreadId (); + + if (lockit) + lock_threadname (); + for (DWORD i = 0; i < NTHREADS && threads[i].name != NULL; i++) + if (threads[i].id == tid) + { + res = threads[i].name; + break; + } + if (lockit) + unlock_threadname (); + + if (!res) + { + static char buf[30] NO_COPY = {0}; + __small_sprintf (buf, "unknown (%p)", tid); + res = buf; + } + + return res; +} + +#ifdef DEBUGGING +/* Here lies extra debugging routines which help track down internal + Cygwin problems when compiled with -DDEBUGGING . */ +#include + +typedef struct _h + { + BOOL allocated; + HANDLE h; + const char *name; + const char *func; + int ln; + struct _h *next; + } handle_list; + +static NO_COPY handle_list starth = {0}; +static NO_COPY handle_list *endh = NULL; + +static handle_list NO_COPY freeh[1000] = {{0}}; +#define NFREEH (sizeof (freeh) / sizeof (freeh[0])) + +static muto NO_COPY *debug_lock = NULL; + +#define lock_debug() \ + do {if (debug_lock) debug_lock->acquire (INFINITE); } while (0) + +#define unlock_debug() \ + do {if (debug_lock) debug_lock->release (); } while (0) + +void +debug_init () +{ + debug_lock = new_muto (FALSE, NULL); +} + +/* Find a registered handle in the linked list of handles. */ +static handle_list * __stdcall +find_handle (HANDLE h) +{ + handle_list *hl; + for (hl = &starth; hl->next != NULL; hl = hl->next) + if (hl->next->h == h) + goto out; + endh = hl; + hl = NULL; + +out: + return hl; +} + +/* Create a new handle record */ +static handle_list * __stdcall +newh () +{ + handle_list *hl; + lock_debug (); + for (hl = freeh; hl < freeh + NFREEH; hl++) + if (hl->name == NULL) + goto out; + + /* All used up??? */ + if ((hl = (handle_list *)malloc (sizeof *hl)) != NULL) + { + memset (hl, 0, sizeof (*hl)); + hl->allocated = TRUE; + } + +out: + unlock_debug (); + return hl; +} + +/* Add a handle to the linked list of known handles. */ +void __stdcall +add_handle (const char *func, int ln, HANDLE h, const char *name) +{ + handle_list *hl; + lock_debug (); + + if (find_handle (h)) + goto out; /* Already did this once */ + + if ((hl = newh()) == NULL) + { + unlock_debug (); + system_printf ("couldn't allocate memory for %s(%d): %s(%p)", + func, ln, name, h); + return; + } + hl->h = h; + hl->name = name; + hl->func = func; + hl->ln = ln; + hl->next = NULL; + endh->next = hl; + endh = hl; + +out: + unlock_debug (); +} + +/* Close a known handle. Complain if !force and closing a known handle or + if the name of the handle being closed does not match the registered name. */ +BOOL __stdcall +close_handle (const char *func, int ln, HANDLE h, const char *name, BOOL force) +{ + BOOL ret; + handle_list *hl; + lock_debug (); + + if ((hl = find_handle (h)) && !force) + { + hl = hl->next; + unlock_debug (); // race here + system_printf ("attempt to close protected handle %s:%d(%s<%p>)", + hl->func, hl->ln, hl->name, hl->h); + system_printf (" by %s:%d(%s<%p>)", func, ln, name, h); + return FALSE; + } + + handle_list *hln; + if (hl && (hln = hl->next) && strcmp (name, hln->name)) + { + system_printf ("closing protected handle %s:%d(%s<%p>)", + hln->func, hln->ln, hln->name, hln->h); + system_printf (" by %s:%d(%s<%p>)", func, ln, name, h); + } + ret = CloseHandle (h); + if (hl) + { + handle_list *hnuke = hl->next; + hl->next = hl->next->next; + if (hnuke->allocated) + free (hnuke); + else + memset (hnuke, 0, sizeof (*hnuke)); + } + + unlock_debug (); + return ret; +} +#endif /*DEBUGGING*/ + +extern "C" { +/* Provide a stack frame when calling WaitFor* functions */ + +#undef WaitForSingleObject + +DWORD __stdcall +WFSO (HANDLE hHandle, DWORD dwMilliseconds) +{ + DWORD ret; + ret = WaitForSingleObject (hHandle, dwMilliseconds); + return ret; +} + +#undef WaitForMultipleObjects + +DWORD __stdcall +WFMO (DWORD nCount, CONST HANDLE *lpHandles, BOOL fWaitAll, DWORD dwMilliseconds) +{ + DWORD ret; + ret = WaitForMultipleObjects (nCount, lpHandles, fWaitAll, dwMilliseconds); + return ret; +} +} diff --git a/winsup/cygwin/debug.h b/winsup/cygwin/debug.h new file mode 100644 index 000000000..c8e28ba64 --- /dev/null +++ b/winsup/cygwin/debug.h @@ -0,0 +1,69 @@ +/* debug.h + + Copyright 1998, 1999, 2000 Cygnus Solutions. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#ifndef MALLOC_DEBUG +#define MALLOC_CHECK do {} while (0) +#else +#define MALLOC_CHECK ({\ + debug_printf ("checking malloc pool");\ + (void)mallinfo ();\ +}) +#endif + +extern "C" { +DWORD __stdcall WFSO (HANDLE, DWORD); +DWORD __stdcall WFMO (DWORD, CONST HANDLE *, BOOL, DWORD); +} + +#define WaitForSingleObject WFSO +#define WaitForMultipleObject WFMO + +#if !defined(_DEBUG_H_) +#define _DEBUG_H_ + +void threadname_init (); +HANDLE __stdcall makethread (LPTHREAD_START_ROUTINE, LPVOID, DWORD, const char *); +const char * __stdcall threadname (DWORD, int lockit = TRUE); +void __stdcall regthread (const char *, DWORD); + +#ifndef DEBUGGING +# define ForceCloseHandle CloseHandle +# define ForceCloseHandle1(h, n) CloseHandle (h) +# define ForceCloseHandle2(h, n) CloseHandle (h) +# define ProtectHandle(h) do {} while (0) +# define ProtectHandle1(h,n) do {} while (0) +# define ProtectHandle2(h,n) do {} while (0) +# define debug_init() do {} while (0) + +#else + +# ifdef NO_DEBUG_DEFINES +# undef NO_DEBUG_DEFINES +# else +# define CloseHandle(h) \ + close_handle (__PRETTY_FUNCTION__, __LINE__, (h), #h, FALSE) +# define ForceCloseHandle(h) \ + close_handle (__PRETTY_FUNCTION__, __LINE__, (h), #h, TRUE) +# define ForceCloseHandle1(h,n) \ + close_handle (__PRETTY_FUNCTION__, __LINE__, (h), #n, TRUE) +# define ForceCloseHandle2(h,n) \ + close_handle (__PRETTY_FUNCTION__, __LINE__, (h), n, TRUE) +# define lock_pinfo_for_update(n) lpfu(__PRETTY_FUNCTION__, __LINE__, n) +# endif + +# define ProtectHandle(h) add_handle (__PRETTY_FUNCTION__, __LINE__, (h), #h) +# define ProtectHandle1(h,n) add_handle (__PRETTY_FUNCTION__, __LINE__, (h), #n) +# define ProtectHandle2(h,n) add_handle (__PRETTY_FUNCTION__, __LINE__, (h), n) + +void debug_init (); +void __stdcall add_handle (const char *, int, HANDLE, const char *); +BOOL __stdcall close_handle (const char *, int, HANDLE, const char *, BOOL); +int __stdcall lpfu (const char *, int, DWORD timeout); + +#endif /*DEBUGGING*/ +#endif /*_DEBUG_H_*/ diff --git a/winsup/cygwin/delqueue.cc b/winsup/cygwin/delqueue.cc new file mode 100644 index 000000000..81d2bd68b --- /dev/null +++ b/winsup/cygwin/delqueue.cc @@ -0,0 +1,99 @@ +/* delqueue.cc + + Copyright 1996, 1998 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include "winsup.h" + +/* FIXME: this delqueue module is very flawed and should be rewritten. + First, having an array of a fixed size for keeping track of the + unlinked but not yet deleted files is bad. Second, some programs + will unlink files and then create a new one in the same location + and this behavior is not supported in the current code. Probably + we should find a move/rename function that will work on open files, + and move delqueue files to some special location or some such + hack... */ + +void +delqueue_list::init () +{ + empty = 1; + memset(inuse, 0, MAX_DELQUEUES_PENDING); +} + +void +delqueue_list::queue_file (const char *dosname) +{ + char temp[MAX_PATH], *end; + GetFullPathName (dosname, sizeof (temp), temp, &end); + + /* Note about race conditions: The only time we get to this point is + when a delete fails because someone's holding the descriptor open. + In those cases, other programs will be unable to delete the file + also, so any entries referring to that file will not be removed + from the queue while we're here. */ + + if (!empty) + { + /* check for duplicates */ + for (int i=0; i < MAX_DELQUEUES_PENDING; i++) + if (inuse[i] && strcmp(name[i], temp) == 0) + return; + } + + for (int i = 0; i < MAX_DELQUEUES_PENDING; i++) + if (!inuse[i]) + { + /* set the name first, in case someone else is running the + queue they'll get a valid name */ + strcpy(name[i], temp); + inuse[i] = 1; + empty = 0; + return; + } + + system_printf ("Out of queue slots"); +} + +void +delqueue_list::process_queue () +{ + if (empty) + return; + /* We set empty to 1 here, rather than later, to avoid a race + condition - some other program might queue up a file while we're + processing, and it will zero out empty also. */ + empty = 1; /* but might get set to zero again, below */ + + syscall_printf ("Running delqueue"); + + for (int i = 0; i < MAX_DELQUEUES_PENDING; i++) + if (inuse[i]) + { + if (DeleteFileA (name[i])) + { + syscall_printf ("Deleted %s", name[i]); + inuse[i] = 0; + } + else + { + int res = GetLastError (); + empty = 0; + if (res == ERROR_SHARING_VIOLATION) + { + /* File still inuse, that's ok */ + syscall_printf ("Still using %s", name[i]); + } + else + { + syscall_printf ("Hmm, don't know what to do with '%s', %E", name[i]); + inuse[i] = 0; + } + } + } +} diff --git a/winsup/cygwin/dir.cc b/winsup/cygwin/dir.cc new file mode 100644 index 000000000..48187a20c --- /dev/null +++ b/winsup/cygwin/dir.cc @@ -0,0 +1,340 @@ +/* dir.cc: Posix directory-related routines + + Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include +#include "winsup.h" + +#define _COMPILING_NEWLIB +#include "dirent.h" + +/* Cygwin internal */ +/* Return whether the directory of a file is writable. Return 1 if it + is. Otherwise, return 0, and set errno appropriately. */ +int __stdcall +writable_directory (const char *file) +{ + char dir[strlen (file) + 1]; + + strcpy (dir, file); + + const char *usedir; + char *slash = strrchr (dir, '\\'); + if (slash == NULL) + usedir = "."; + else + { + *slash = '\0'; + usedir = dir; + } + + int acc = access (usedir, W_OK); + + return acc == 0; +} + +/* opendir: POSIX 5.1.2.1 */ +extern "C" DIR * +opendir (const char *dirname) +{ + int len; + DIR *dir; + DIR *res = 0; + struct stat statbuf; + + path_conv real_dirname (dirname, SYMLINK_FOLLOW, 1); + + if (real_dirname.error) + { + set_errno (real_dirname.error); + goto failed; + } + + if (stat (real_dirname.get_win32 (), &statbuf) == -1) + goto failed; + + if (!(statbuf.st_mode & S_IFDIR)) + { + set_errno (ENOTDIR); + goto failed; + } + + len = strlen (real_dirname.get_win32 ()); + if (len > MAX_PATH - 3) + { + set_errno (ENAMETOOLONG); + goto failed; + } + + if ((dir = (DIR *) malloc (sizeof (DIR))) == NULL) + { + set_errno (ENOMEM); + goto failed; + } + if ((dir->__d_dirname = (char *) malloc (len + 3)) == NULL) + { + free (dir); + set_errno (ENOMEM); + goto failed; + } + if ((dir->__d_dirent = + (struct dirent *) malloc (sizeof (struct dirent))) == NULL) + { + free (dir->__d_dirname); + free (dir); + set_errno (ENOMEM); + goto failed; + } + strcpy (dir->__d_dirname, real_dirname.get_win32 ()); + /* FindFirstFile doesn't seem to like duplicate /'s. */ + len = strlen (dir->__d_dirname); + if (len == 0 || SLASH_P (dir->__d_dirname[len - 1])) + strcat (dir->__d_dirname, "*"); + else + strcat (dir->__d_dirname, "\\*"); /**/ + dir->__d_cookie = __DIRENT_COOKIE; + dir->__d_u.__d_data.__handle = INVALID_HANDLE_VALUE; + dir->__d_position = 0; + dir->__d_dirhash = statbuf.st_ino; + + res = dir; + +failed: + syscall_printf ("%p = opendir (%s)", res, dirname); + return res; +} + +/* readdir: POSIX 5.1.2.1 */ +extern "C" struct dirent * +readdir (DIR * dir) +{ + WIN32_FIND_DATA buf; + HANDLE handle; + struct dirent *res = 0; + int prior_errno; + + if (dir->__d_cookie != __DIRENT_COOKIE) + { + set_errno (EBADF); + syscall_printf ("%p = readdir (%p)", res, dir); + return res; + } + + if (dir->__d_u.__d_data.__handle != INVALID_HANDLE_VALUE) + { + if (FindNextFileA (dir->__d_u.__d_data.__handle, &buf) == 0) + { + prior_errno = get_errno(); + (void) FindClose (dir->__d_u.__d_data.__handle); + dir->__d_u.__d_data.__handle = INVALID_HANDLE_VALUE; + __seterrno (); + /* POSIX says you shouldn't set errno when readdir can't + find any more files; if another error we leave it set. */ + if (get_errno () == ENMFILE) + set_errno (prior_errno); + syscall_printf ("%p = readdir (%p)", res, dir); + return res; + } + } + else + { + handle = FindFirstFileA (dir->__d_dirname, &buf); + + if (handle == INVALID_HANDLE_VALUE) + { + /* It's possible that someone else deleted or emptied the directory + or some such between the opendir () call and here. */ + prior_errno = get_errno (); + __seterrno (); + /* POSIX says you shouldn't set errno when readdir can't + find any more files; if another error we leave it set. */ + if (get_errno () == ENMFILE) + set_errno (prior_errno); + syscall_printf ("%p = readdir (%p)", res, dir); + return res; + } + dir->__d_u.__d_data.__handle = handle; + } + + /* We get here if `buf' contains valid data. */ + strcpy (dir->__d_dirent->d_name, buf.cFileName); + + /* Compute d_ino by combining filename hash with the directory hash + (which was stored in dir->__d_dirhash when opendir was called). */ + if (buf.cFileName[0] == '.') + { + if (buf.cFileName[1] == '\0') + dir->__d_dirent->d_ino = dir->__d_dirhash; + else if (buf.cFileName[1] != '.' || buf.cFileName[2] != '\0') + goto hashit; + else + { + char *p, up[strlen (dir->__d_dirname) + 1]; + strcpy (up, dir->__d_dirname); + if (!(p = strrchr (up, '\\'))) + goto hashit; + *p = '\0'; + if (!(p = strrchr (up, '\\'))) + dir->__d_dirent->d_ino = hash_path_name (0, "."); + else + { + *p = '\0'; + dir->__d_dirent->d_ino = hash_path_name (0, up); + } + } + } + else + { + hashit: + ino_t dino = hash_path_name (dir->__d_dirhash, "\\"); + dir->__d_dirent->d_ino = hash_path_name (dino, buf.cFileName); + } + + ++dir->__d_position; + res = dir->__d_dirent; + syscall_printf ("%p = readdir (%p) (%s)", + &dir->__d_dirent, dir, buf.cFileName); + return res; +} + +/* telldir */ +extern "C" off_t +telldir (DIR * dir) +{ + if (dir->__d_cookie != __DIRENT_COOKIE) + return 0; + return dir->__d_position; +} + +/* seekdir */ +extern "C" void +seekdir (DIR * dir, off_t loc) +{ + if (dir->__d_cookie != __DIRENT_COOKIE) + return; + rewinddir (dir); + while (loc > dir->__d_position) + if (! readdir (dir)) + break; +} + +/* rewinddir: POSIX 5.1.2.1 */ +extern "C" void +rewinddir (DIR * dir) +{ + syscall_printf ("rewinddir (%p)", dir); + + if (dir->__d_cookie != __DIRENT_COOKIE) + return; + if (dir->__d_u.__d_data.__handle != INVALID_HANDLE_VALUE) + { + (void) FindClose (dir->__d_u.__d_data.__handle); + dir->__d_u.__d_data.__handle = INVALID_HANDLE_VALUE; + dir->__d_position = 0; + } +} + +/* closedir: POSIX 5.1.2.1 */ +extern "C" int +closedir (DIR * dir) +{ + if (dir->__d_cookie != __DIRENT_COOKIE) + { + set_errno (EBADF); + syscall_printf ("-1 = closedir (%p)", dir); + return -1; + } + + if (dir->__d_u.__d_data.__handle != INVALID_HANDLE_VALUE && + FindClose (dir->__d_u.__d_data.__handle) == 0) + { + __seterrno (); + syscall_printf ("-1 = closedir (%p)", dir); + return -1; + } + + /* Reset the marker in case the caller tries to use `dir' again. */ + dir->__d_cookie = 0; + + free (dir->__d_dirname); + free (dir->__d_dirent); + free (dir); + syscall_printf ("0 = closedir (%p)", dir); + return 0; +} + +/* mkdir: POSIX 5.4.1.1 */ +extern "C" int +mkdir (const char *dir, mode_t mode) +{ + int res = -1; + + path_conv real_dir (dir, SYMLINK_NOFOLLOW); + + if (real_dir.error) + { + set_errno (real_dir.error); + goto done; + } + + nofinalslash(real_dir.get_win32 (), real_dir.get_win32 ()); + if (! writable_directory (real_dir.get_win32 ())) + goto done; + + if (CreateDirectoryA (real_dir.get_win32 (), 0)) + { + set_file_attribute (real_dir.has_acls (), real_dir.get_win32 (), + (mode & 0777) & ~myself->umask); + res = 0; + } + else + __seterrno (); + +done: + syscall_printf ("%d = mkdir (%s, %d)", res, dir, mode); + return res; +} + +/* rmdir: POSIX 5.5.2.1 */ +extern "C" int +rmdir (const char *dir) +{ + int res = -1; + + path_conv real_dir (dir, SYMLINK_NOFOLLOW); + + if (real_dir.error) + { + set_errno (real_dir.error); + goto done; + } + + if (RemoveDirectoryA (real_dir.get_win32 ())) + res = 0; + else if (os_being_run != winNT && GetLastError() == ERROR_ACCESS_DENIED) + { + /* Under Windows 95 & 98, ERROR_ACCESS_DENIED is returned + if you try to remove a file or a non-empty directory. */ + if (GetFileAttributes (real_dir.get_win32()) != FILE_ATTRIBUTE_DIRECTORY) + set_errno (ENOTDIR); + else + set_errno (ENOTEMPTY); + } + else if (GetLastError () == ERROR_DIRECTORY) + set_errno (ENOTDIR); + else + __seterrno (); + +done: + syscall_printf ("%d = rmdir (%s)", res, dir); + return res; +} diff --git a/winsup/cygwin/dlfcn.cc b/winsup/cygwin/dlfcn.cc new file mode 100644 index 000000000..21c6e5bd0 --- /dev/null +++ b/winsup/cygwin/dlfcn.cc @@ -0,0 +1,236 @@ +/* dlfcn.cc + + Copyright 1998, 2000 Cygnus Solutions + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include "winsup.h" +#include +#include "dlfcn.h" +#include "dll_init.h" + +#ifdef _MT_SAFE +#define _dl_error _reent_winsup()->_dl_error +#define _dl_buffer _reent_winsup()->_dl_buffer +#else +static int _dl_error = 0; +static char _dl_buffer[256]; +#endif + +static void __stdcall +set_dl_error (const char *str) +{ + __small_sprintf (_dl_buffer, "%s: %E", str); + _dl_error = 1; +} + +// +// this function checks for existence of a file specified by the +// directory and name components. If successful, return a pointer +// the full pathname (static buffer), or else return 0. +// +static const char * __stdcall +check_access (const char *dir, const char *name) +{ + static char buf[MAX_PATH]; + const char *ret = 0; + + buf[0] = 0; + strcpy (buf, dir); + strcat (buf, "\\"); + strcat (buf, name); + + if (!access (buf, F_OK)) + ret = buf; + return ret; +} + +// +// this function looks for an executable file given the name and the +// environment variable to use for searching (eg., PATH); returns +// the full pathname (static buffer) if found or NULL if not. +// +static const char * __stdcall +check_path_access (const char *mywinenv, const char *name) +{ + static char buf[MAX_PATH]; + return find_exec (name, buf, mywinenv, TRUE); +} + +// +// This function simulates the same search as LoadLibary + check +// environment variable LD_LIBRARY_PATH. If found, return the full +// pathname (static buffer); if illegal, return the input string +// unchanged and let the caller deal with it; return NULL otherwise. +// +// Note that this should never be called with a NULL string, since +// that is the introspective case, and the caller should not call +// this function at all. +// +static const char * __stdcall +get_full_path_of_dll (const char* str) +{ + int len = (str) ? strlen (str) : 0; + + // NULL or empty string or too long to be legal win32 pathname? + if (len == 0 || len >= MAX_PATH - 1) + return str; + + char buf[MAX_PATH]; + static char name[MAX_PATH]; + const char *ret = 0; + + strcpy (name, str); + + // add extension if necessary, but leave a trailing '.', if any, alone. + // Files with trailing '.'s are handled differently by win32 API. + if (str[len - 1] != '.') + { + // add .dll only if no extension provided. Handle various cases: + // + // ./shlib --> ./shlib.dll + // ./dir/shlib.so --> ./dir/shlib.so + // shlib --> shlib.dll + // shlib.dll --> shlib.dll + // shlib.so --> shlib.so + // + const char *p = strrchr (str, '.'); + if (!p || isdirsep (p[1])) + strcat (name, ".dll"); + } + + // deal with fully qualified filename right away. Do the actual + // conversion to win32 filename just before returning however. + if (isabspath (str)) + ret = name; + + // current directory + if (!ret) + { + if (GetCurrentDirectory (MAX_PATH, buf) == 0) + small_printf ("WARNING: get_full_path_of_dll can't get current directory win32 %E\n"); + else + ret = check_access (buf, name); + } + + // LD_LIBRARY_PATH + if (!ret) + ret = check_path_access ("LD_LIBRARY_PATH=", name); + + if (!ret) + { + // system directory + if (GetSystemDirectory (buf, MAX_PATH) == 0) + small_printf ("WARNING: get_full_path_of_dll can't get system directory win32 %E\n"); + else + ret = check_access (buf, name); + } + + // 16 bits system directory + if (!ret && (os_being_run == winNT)) + { + // we assume last dir was xxxxx\SYSTEM32, so we remove 32 + len = strlen (buf); + buf[len - 2] = 0; + ret = check_access (buf, name); + } + + // windows directory + if (!ret) + { + if (GetWindowsDirectory (buf, MAX_PATH) == 0) + small_printf ("WARNING: get_full_path_of_dll can't get Windows directory win32 %E\n"); + else + ret = check_access (buf, name); + } + + // PATH + if (!ret) + ret = check_path_access ("PATH=", name); + + // + // now do a final conversion to win32 pathname. This step is necessary + // to resolve symlinks etc so that win32 API finds the underlying file. + // + if (ret) + { + path_conv real_filename (ret, SYMLINK_FOLLOW, 1); + if (real_filename.error) + ret = 0; + else + { + strcpy (name, real_filename.get_win32 ()); + ret = name; + } + } + return ret; +} + +void * +dlopen (const char *name, int) +{ + SetResourceLock(LOCK_DLL_LIST,READ_LOCK|WRITE_LOCK," dlopen"); + + void *ret = 0; + + if (!name) + { + // handle for the current module + ret = (void *) GetModuleHandle (0); + } + else + { + // handle for the named library + const char *fullpath = get_full_path_of_dll (name); + DllList::the().currentDlOpenedLib (fullpath); + ret = (void *) LoadLibrary (fullpath); + } + + if (!ret) + set_dl_error ("dlopen"); + debug_printf ("ret %p", ret); + + ReleaseResourceLock(LOCK_DLL_LIST,READ_LOCK|WRITE_LOCK," dlopen"); + return ret; +} + +void * +dlsym (void *handle, const char *name) +{ + void *ret = (void *) GetProcAddress ((HMODULE) handle, name); + if (!ret) + set_dl_error ("dlsym"); + debug_printf ("ret %p", ret); + return ret; +} + +int +dlclose (void *handle) +{ + SetResourceLock(LOCK_DLL_LIST,READ_LOCK|WRITE_LOCK," dlclose"); + + int ret = -1; + if (FreeLibrary ((HMODULE) handle)) + ret = 0; + if (ret) + set_dl_error ("dlclose"); + + ReleaseResourceLock(LOCK_DLL_LIST,READ_LOCK|WRITE_LOCK," dlclose"); + return ret; +} + +char * +dlerror () +{ + char *ret = 0; + if (_dl_error) + ret = _dl_buffer; + return ret; +} diff --git a/winsup/cygwin/dll_init.cc b/winsup/cygwin/dll_init.cc new file mode 100644 index 000000000..a1d217576 --- /dev/null +++ b/winsup/cygwin/dll_init.cc @@ -0,0 +1,499 @@ +/* dll_init.cc + + Copyright 1998, 1999, 2000 Cygnus Solutions. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include "winsup.h" +#include "exceptions.h" +#include "dll_init.h" + +extern void __stdcall check_sanity_and_sync (per_process *); + +#ifdef _MT_SAFE +extern ResourceLocks _reslock NO_COPY; +extern MTinterface _mtinterf NO_COPY; +#endif /*_MT_SAFE*/ + +/* WARNING: debug can't be called before init !!!! */ + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// the private structure + +typedef enum { NONE, LINK, LOAD } dllType; + +struct dll +{ + per_process *p; + HMODULE handle; + const char *name; + dllType type; +}; + +//----------------------------------------------------------------------------- + +#define MAX_DLL_BEFORE_INIT 100 // FIXME: enough ??? +static dll _list_before_init[MAX_DLL_BEFORE_INIT]; + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// local variables + +static DllList _the; +static int _last = 0; +static int _max = MAX_DLL_BEFORE_INIT; +static dll *_list = _list_before_init; +static int _initCalled = 0; +static int _numberOfOpenedDlls = 0; +static int _forkeeMustReloadDlls = 0; +static int _in_forkee = 0; +static const char *_dlopenedLib = 0; +static int _dlopenIndex = -1; + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +static int __dll_global_dtors_recorded = 0; + +static void +__dll_global_dtors() +{ + _the.doGlobalDestructorsOfDlls(); +} + +static void +doGlobalCTORS (per_process *p) +{ + void (**pfunc)() = p->ctors; + + /* Run ctors backwards, so skip the first entry and find how many + there are, then run them. */ + + if (pfunc) + { + int i; + for (i = 1; pfunc[i]; i++); + + for (int j = i - 1; j > 0; j-- ) + (pfunc[j]) (); + } +} + +static void +doGlobalDTORS (per_process *p) +{ + if (!p) + return; + void (**pfunc)() = p->dtors; + for (int i = 1; pfunc[i]; i++) + (pfunc[i]) (); +} + +#define INC 500 + +static int +add (HMODULE h, char *name, per_process *p, dllType type) +{ + int ret = -1; + + if (p) + check_sanity_and_sync (p); + + if (_last == _max) + { + if (!_initCalled) // we try to load more than MAX_DLL_BEFORE_INIT + { + small_printf ("try to load more dll than max allowed=%d\n", + MAX_DLL_BEFORE_INIT); + ExitProcess (1); + } + + dll* newArray = new dll[_max+INC]; + if (_list) + { + memcpy (newArray, _list, _max * sizeof (dll)); + if (_list != _list_before_init) + delete []_list; + } + _list = newArray; + _max += INC; + } + + _list[_last].name = name && type == LOAD ? strdup (name) : NULL; + _list[_last].handle = h; + _list[_last].p = p; + _list[_last].type = type; + + ret = _last++; + return ret; +} + +static int +initOneDll (per_process *p) +{ + /* global variable user_data must be initialized */ + if (user_data == NULL) + { + small_printf ("WARNING: process not inited while trying to init a DLL!\n"); + return 0; + } + + /* init impure_ptr */ + *(p->impure_ptr_ptr) = *(user_data->impure_ptr_ptr); + + /* FIXME: init environment (useful?) */ + *(p->envptr) = *(user_data->envptr); + + /* FIXME: need other initializations? */ + + int ret = 1; + if (!_in_forkee) + { + /* global contructors */ + doGlobalCTORS (p); + + /* entry point of dll (use main of per_process with null args...) */ + if (p->main) + ret = (*(p->main)) (0, 0, 0); + } + + return ret; +} + +DllList& +DllList::the () +{ + return _the; +} + +void +DllList::currentDlOpenedLib (const char *name) +{ + if (_dlopenedLib != 0) + small_printf ("WARNING: previous dlopen of %s wasn't correctly performed\n", _dlopenedLib); + _dlopenedLib = name; + _dlopenIndex = -1; +} + +int +DllList::recordDll (HMODULE h, per_process *p) +{ + int ret = -1; + + /* debug_printf ("Record a dll p=%p\n", p); see WARNING */ + dllType type = LINK; + if (_initCalled) + { + type = LOAD; + _numberOfOpenedDlls++; + forkeeMustReloadDlls (1); + } + + if (_in_forkee) + { + ret = 0; // Just a flag + goto out; + } + + char buf[MAX_PATH]; + GetModuleFileName (h, buf, MAX_PATH); + + if (type == LOAD && _dlopenedLib !=0) + { + // it is not the current dlopened lib + // so we insert one empty lib to preserve place for current dlopened lib + if (!strcasematch (_dlopenedLib, buf)) + { + if (_dlopenIndex == -1) + _dlopenIndex = add (0, 0, 0, NONE); + ret = add (h, buf, p, type); + } + else // it is the current dlopened lib + { + if (_dlopenIndex != -1) + { + _list[_dlopenIndex].handle = h; + _list[_dlopenIndex].p = p; + _list[_dlopenIndex].type = type; + ret = _dlopenIndex; + _dlopenIndex = -1; + } + else // it this case the dlopened lib doesn't need other lib + ret = add (h, buf, p, type); + _dlopenedLib = 0; + } + } + else + ret = add (h, buf, p, type); + +out: + if (_initCalled) // main module is already initialized + { + if (!initOneDll (p)) + ret = -1; + } + return ret; +} + +void +DllList::detachDll (int dll_index) +{ + if (dll_index != -1) + { + dll *aDll = &(_list[dll_index]); + doGlobalDTORS (aDll->p); + if (aDll->type == LOAD) + _numberOfOpenedDlls--; + aDll->type = NONE; + } + else + small_printf ("WARNING: try to detach an already detached dll ...\n"); +} + +void +DllList::initAll () +{ + // init for destructors + // because initAll isn't called in forked process, this exit function will + // be recorded only once + if (!__dll_global_dtors_recorded) + { + atexit (__dll_global_dtors); + __dll_global_dtors_recorded = 1; + } + + if (!_initCalled) + { + debug_printf ("call to DllList::initAll"); + for (int i = 0; i < _last; i++) + { + per_process *p = _list[i].p; + if (p) + initOneDll (p); + } + _initCalled = 1; + } +} + +void +DllList::doGlobalDestructorsOfDlls () +{ + // global destructors in reverse order + for (int i = _last - 1; i >= 0; i--) + { + if (_list[i].type != NONE) + { + per_process *p = _list[i].p; + if (p) + doGlobalDTORS (p); + } + } +} + +int +DllList::numberOfOpenedDlls () +{ + return _numberOfOpenedDlls; +} + +int +DllList::forkeeMustReloadDlls () +{ + return _forkeeMustReloadDlls; +} + +void +DllList::forkeeMustReloadDlls (int i) +{ + _forkeeMustReloadDlls = i; +} + +#define A64K (64 * 1024) + +/* Mark every memory address up to "here" as reserved. This may force + Windows NT to load a DLL in the next available, lowest slot. */ +void +reserve_upto (const char *name, DWORD here) +{ + DWORD size; + MEMORY_BASIC_INFORMATION mb; + for (DWORD start = 0x10000; start < here; start += size) + if (!VirtualQuery ((void *) start, &mb, sizeof (mb))) + size = 64 * 1024; + else + { + size = A64K * ((mb.RegionSize + A64K - 1) / A64K); + start = A64K * (((DWORD) mb.BaseAddress + A64K - 1) / A64K); + + if (start + size > here) + size = here - start; + if (mb.State == MEM_FREE && + !VirtualAlloc ((void *) start, size, MEM_RESERVE, PAGE_NOACCESS)) + api_fatal ("couldn't allocate memory %p(%d) for '%s' alignment, %E\n", + start, size, name); + } +} + +/* Release all of the memory previously allocated by "upto" above. + Note that this may also free otherwise reserved memory. If that becomes + a problem, we'll have to keep track of the memory that we reserve above. */ +void +release_upto (const char *name, DWORD here) +{ + DWORD size; + MEMORY_BASIC_INFORMATION mb; + for (DWORD start = 0x10000; start < here; start += size) + if (!VirtualQuery ((void *) start, &mb, sizeof (mb))) + size = 64 * 1024; + else + { + size = mb.RegionSize; + if (!(mb.State == MEM_RESERVE && mb.AllocationProtect == PAGE_NOACCESS && + ((void *) start < user_data->heapbase || (void *) start > user_data->heaptop))) + continue; + if (!VirtualFree ((void *) start, 0, MEM_RELEASE)) + api_fatal ("couldn't release memory %p(%d) for '%s' alignment, %E\n", + start, size, name); + } +} + +/* Reload DLLs after a fork. Iterates over the list of dynamically loaded DLLs + and attempts to load them in the same place as they were loaded in the parent. */ +void +DllList::forkeeLoadDlls () +{ + _initCalled = 1; + _in_forkee = 1; + int try2 = 0; + for (int i = 0; i < _last; i++) + if (_list[i].type == LOAD) + { + const char *name = _list[i].name; + HMODULE handle = _list[i].handle; + HMODULE h = LoadLibraryEx (name, NULL, DONT_RESOLVE_DLL_REFERENCES); + + if (h == handle) + { + FreeLibrary (h); + LoadLibrary (name); + } + else if (try2) + api_fatal ("unable to remap %s to same address as parent -- %p", name, h); + else + { + FreeLibrary (h); + reserve_upto (name, (DWORD) handle); + try2 = 1; + i--; + continue; + } + if (try2) + { + release_upto (name, (DWORD) handle); + try2 = 0; + } + } + _in_forkee = 0; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// iterators + +DllListIterator::DllListIterator (int type) : _type (type), _index (-1) +{ + operator++ (); +} + +DllListIterator::~DllListIterator () +{ +} + +DllListIterator::operator per_process* () +{ + return _list[index ()].p; +} + +void +DllListIterator::operator++ () +{ + _index++; + while (_index < _last && (int) (_list[_index].type) != _type) + _index++; + if (_index == _last) + _index = -1; +} + +LinkedDllIterator::LinkedDllIterator () : DllListIterator ((int) LINK) +{ +} + +LinkedDllIterator::~LinkedDllIterator () +{ +} + +LoadedDllIterator::LoadedDllIterator () : DllListIterator ((int) LOAD) +{ +} + +LoadedDllIterator::~LoadedDllIterator () +{ +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// the extern symbols + +extern "C" +{ + /* This is an exported copy of environ which can be used by DLLs + which use cygwin.dll. */ + extern struct _reent reent_data; +}; + +extern "C" +int +dll_dllcrt0 (HMODULE h, per_process *p) +{ + /* Partially initialize Cygwin guts for non-cygwin apps. */ + if (dynamically_loaded && (! user_data || user_data->magic_biscuit == 0)) + { + dll_crt0 (p); + } + return _the.recordDll (h, p); +} + +/* OBSOLETE: This function is obsolescent and will go away in the + future. Cygwin can now handle being loaded from a noncygwin app + using the same entry point. */ + +extern "C" +int +dll_noncygwin_dllcrt0 (HMODULE h, per_process *p) +{ + return dll_dllcrt0 (h, p); +} + +extern "C" +void +cygwin_detach_dll (int dll_index) +{ + _the.detachDll (dll_index); +} + +extern "C" +void +dlfork (int val) +{ + _the.forkeeMustReloadDlls (val); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- diff --git a/winsup/cygwin/dll_init.h b/winsup/cygwin/dll_init.h new file mode 100644 index 000000000..ca2cc2c20 --- /dev/null +++ b/winsup/cygwin/dll_init.h @@ -0,0 +1,102 @@ +/* dll_init.h + + Copyright 1998 Cygnus Solutions + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +//----------------------------------------------------------------------------- +// list of loaded DLL (used by fork & init) +class DllList +{ +public: + static DllList& the (); + + // return dll index used for freeDll + int recordDll (HMODULE, per_process*); + void detachDll (int dll_index); + + // called after initialization of main module in dll_crt0 + void initAll (); + + // global destructors of loaded dlls + void doGlobalDestructorsOfDlls (); + + // number of dlls dlopened + int numberOfOpenedDlls (); + + // boolean to determine if forked process must reload dlls opened with + // LoadLibrary or dlopen ... + // default = 0 (FALSE) + int forkeeMustReloadDlls (); + void forkeeMustReloadDlls (int); + + void forkeeLoadDlls (); + + // set name of current library opened with dlopen + void currentDlOpenedLib (const char*); +}; + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +class DllListIterator +{ + int _type; + int _index; + +protected: + DllListIterator (int type); + int index () const { return _index; } + +public: + virtual ~DllListIterator(); + + int ok() { return _index!=-1; } + void operator++ (); + void operator++ (int) { operator++ (); } + operator per_process* (); +}; + +//----------------------------------------------------------------------------- + +class LinkedDllIterator : public DllListIterator +{ +public: + LinkedDllIterator (); + ~LinkedDllIterator (); +}; + +//----------------------------------------------------------------------------- + +class LoadedDllIterator : public DllListIterator +{ +public: + LoadedDllIterator (); + ~LoadedDllIterator (); +}; + +//----------------------------------------------------------------------------- + +#define DO_LINKED_DLL(var) \ +{ \ +LinkedDllIterator iterator; \ +while (iterator.ok ()) \ +{ \ + per_process *var = (per_process *) iterator; + +#define DO_LOADED_DLL(var) \ +{ \ +LoadedDllIterator iterator; \ +while (iterator.ok ()) \ +{ \ + per_process *var = (per_process *) iterator; + +#define DLL_DONE \ + iterator++; \ +} \ +} + diff --git a/winsup/cygwin/dll_init.sgml b/winsup/cygwin/dll_init.sgml new file mode 100644 index 000000000..38070390c --- /dev/null +++ b/winsup/cygwin/dll_init.sgml @@ -0,0 +1,11 @@ + + +cygwin_detach_dll + + +extern "C" void +cygwin_detach_dll +int dll_index + + + diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc new file mode 100644 index 000000000..27af8709f --- /dev/null +++ b/winsup/cygwin/dtable.cc @@ -0,0 +1,603 @@ +/* hinfo.cc: file descriptor support. + + Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#define __INSIDE_CYGWIN_NET__ + +#include +#include +#include +#include +#include +#include +#include + +#define Win32_Winsock +#include "winsup.h" + +hinfo dtable; + +/* Set aside space for the table of fds */ +void +dtable_init (void) +{ + if (!dtable.size) + dtable.extend(NOFILE_INCR); +} + +void __stdcall +set_std_handle (int fd) +{ + if (fd == 0) + SetStdHandle (STD_INPUT_HANDLE, dtable[fd]->get_handle ()); + else if (fd == 1) + SetStdHandle (STD_OUTPUT_HANDLE, dtable[fd]->get_output_handle ()); + else if (fd == 2) + SetStdHandle (STD_ERROR_HANDLE, dtable[fd]->get_output_handle ()); +} + +int +hinfo::extend (int howmuch) +{ + int new_size = size + howmuch; + fhandler_base **newfds; + + if (howmuch <= 0) + return 0; + + /* Try to allocate more space for fd table. We can't call realloc() + here to preserve old table if memory allocation fails */ + +debug_printf ("here size %d", size); + + if (!(newfds = (fhandler_base **) calloc (new_size, sizeof newfds[0]))) + { + debug_printf ("calloc failed"); + return 0; + } + if (fds) + { + memcpy (newfds, fds, size * sizeof (fds[0])); + free (fds); + } + + size = new_size; + fds = newfds; + debug_printf ("size %d, fds %d", size, fds); + return 1; +} + +/* Initialize the file descriptor/handle mapping table. + We only initialize the parent table here. The child table is + initialized at each fork () call. */ + +void +hinfo_init (void) +{ + /* Set these before trying to output anything from strace. + Also, always set them even if we're to pick up our parent's fds + in case they're missed. */ + + if (!parent_alive && NOTSTATE(myself, PID_CYGPARENT)) + { + HANDLE in = GetStdHandle (STD_INPUT_HANDLE); + HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); + HANDLE err = GetStdHandle (STD_ERROR_HANDLE); + + dtable.init_std_file_from_handle (0, in, GENERIC_READ, "{stdin}"); + + /* STD_ERROR_HANDLE has been observed to be the same as + STD_OUTPUT_HANDLE. We need separate handles (e.g. using pipes + to pass data from child to parent). */ + if (out == err) + { + /* Since this code is not invoked for forked tasks, we don't have + to worry about the close-on-exec flag here. */ + if (!DuplicateHandle (hMainProc, out, hMainProc, &err, 0, + 1, DUPLICATE_SAME_ACCESS)) + { + /* If that fails, do this as a fall back. */ + err = out; + system_printf ("couldn't make stderr distinct from stdout"); + } + } + + dtable.init_std_file_from_handle (1, out, GENERIC_WRITE, "{stdout}"); + dtable.init_std_file_from_handle (2, err, GENERIC_WRITE, "{stderr}"); + } +} + +int +hinfo::not_open (int fd) +{ + SetResourceLock(LOCK_FD_LIST,READ_LOCK," not_open"); + + int res = fd < 0 || fd >= (int)size || fds[fd] == NULL; + + ReleaseResourceLock(LOCK_FD_LIST,READ_LOCK," not open"); + return res; +} + +int +hinfo::find_unused_handle (int start) +{ + AssertResourceOwner(LOCK_FD_LIST,READ_LOCK); + + do + { + for (int i = start; i < (int) size; i++) + if (not_open (i)) + return i; + } + while (extend (NOFILE_INCR)); + return -1; +} + +void +hinfo::release (int fd) +{ + if (!not_open (fd)) + { +MALLOC_CHECK; + delete (fds[fd]); +MALLOC_CHECK; + fds[fd] = NULL; + } +} + +void +hinfo::init_std_file_from_handle (int fd, HANDLE handle, + DWORD myaccess, const char *name) +{ + int bin = __fmode; + /* Check to see if we're being redirected - if not then + we open then as consoles */ + if (fd == 0 || fd == 1 || fd == 2) + { + first_fd_for_open = 0; + /* See if we can consoleify it - if it is a console, + don't open it in binary. That will screw up our crlfs*/ + CONSOLE_SCREEN_BUFFER_INFO buf; + if (GetConsoleScreenBufferInfo (handle, &buf)) + { + bin = 0; + if (ISSTATE (myself, PID_USETTY)) + name = "/dev/tty"; + else + name = "/dev/conout"; + } + else if (FlushConsoleInputBuffer (handle)) + { + bin = 0; + if (ISSTATE (myself, PID_USETTY)) + name = "/dev/tty"; + else + name = "/dev/conin"; + } + } + + build_fhandler (fd, name, handle)->init (handle, myaccess, bin); + set_std_handle (fd); + paranoid_printf ("fd %d, handle %p", fd, handle); +} + +extern "C" +int +cygwin_attach_handle_to_fd (char *name, int fd, HANDLE handle, mode_t bin, + DWORD myaccess) +{ + if (fd == -1) + fd = dtable.find_unused_handle(); + fhandler_base *res = dtable.build_fhandler (fd, name, handle); + res->init (handle, myaccess, bin); + return fd; +} + +fhandler_base * +hinfo::build_fhandler (int fd, const char *name, HANDLE handle) +{ + int unit; + DWORD devn; + + if ((devn = get_device_number (name, unit)) == FH_BAD) + { + struct sockaddr sa; + int sal = sizeof (sa); + CONSOLE_SCREEN_BUFFER_INFO cinfo; + DCB dcb; + + if (handle == NULL) + devn = FH_DISK; + else if (GetNumberOfConsoleInputEvents (handle, (DWORD *) &cinfo)) + devn = FH_CONIN; + else if (GetConsoleScreenBufferInfo (handle, &cinfo)) + devn= FH_CONOUT; + else if (wsock32_handle && getpeername ((SOCKET) handle, &sa, &sal)) + devn = FH_SOCKET; + else if (GetFileType (handle) == FILE_TYPE_PIPE) + devn = FH_PIPE; + else if (GetCommState (handle, &dcb)) + devn = FH_SERIAL; + else + devn = FH_DISK; + } + + return build_fhandler (fd, devn, name, unit); +} + +fhandler_base * +hinfo::build_fhandler (int fd, DWORD dev, const char *name, int unit) +{ + fhandler_base *fh; + void *buf = calloc (1, sizeof (fhandler_union) + 100); + + switch (dev & FH_DEVMASK) + { + case FH_TTYM: + fh = new (buf) fhandler_tty_master (name, unit); + break; + case FH_CONSOLE: + case FH_CONIN: + case FH_CONOUT: + fh = new (buf) fhandler_console (name); + break; + case FH_PTYM: + fh = new (buf) fhandler_pty_master (name); + break; + case FH_TTYS: + if (unit < 0) + fh = new (buf) fhandler_tty_slave (name); + else + fh = new (buf) fhandler_tty_slave (unit, name); + break; + case FH_WINDOWS: + fh = new (buf) fhandler_windows (name); + break; + case FH_SERIAL: + fh = new (buf) fhandler_serial (name, FH_SERIAL, unit); + break; + case FH_PIPE: + case FH_PIPER: + case FH_PIPEW: + fh = new (buf) fhandler_pipe (name); + break; + case FH_SOCKET: + fh = new (buf) fhandler_socket (name); + break; + case FH_DISK: + fh = new (buf) fhandler_disk_file (NULL); + break; + case FH_FLOPPY: + fh = new (buf) fhandler_dev_floppy (name, unit); + break; + case FH_TAPE: + fh = new (buf) fhandler_dev_tape (name, unit); + break; + case FH_NULL: + fh = new (buf) fhandler_dev_null (name); + break; + case FH_ZERO: + fh = new (buf) fhandler_dev_zero (name); + break; + default: + /* FIXME - this could recurse forever */ + return build_fhandler (fd, name, NULL); + } + + debug_printf ("%s - cb %d, fd %d, fh %p", fh->get_name () ?: "", fh->cb, + fd, fh); + return fd >= 0 ? (fds[fd] = fh) : fh; +} + +fhandler_base * +hinfo::dup_worker (fhandler_base *oldfh) +{ + fhandler_base *newfh = build_fhandler (-1, oldfh->get_device (), NULL); + *newfh = *oldfh; + newfh->set_io_handle (NULL); + if (oldfh->dup (newfh)) + { + free (newfh); + newfh = NULL; + return NULL; + } + + newfh->set_close_on_exec_flag (0); + MALLOC_CHECK; + return newfh; +} + +int +hinfo::dup2 (int oldfd, int newfd) +{ + int res = -1; + fhandler_base *newfh = NULL; // = NULL to avoid an incorrect warning + + MALLOC_CHECK; + debug_printf ("dup2 (%d, %d)", oldfd, newfd); + + if (not_open (oldfd)) + { + syscall_printf("dup2: fd %d not open", oldfd); + set_errno (EBADF); + goto done; + } + + if (newfd == oldfd) + { + res = 0; + goto done; + } + + if ((newfh = dup_worker (fds[oldfd])) == NULL) + { + res = -1; + goto done; + } + + SetResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK,"dup"); + if (!not_open (newfd)) + _close (newfd); + fds[newfd] = newfh; + ReleaseResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK,"dup"); + MALLOC_CHECK; + + if ((res = newfd) <= 2) + set_std_handle (res); + + MALLOC_CHECK; +done: + syscall_printf ("%d = dup2 (%d, %d)", res, oldfd, newfd); + + return res; +} + +select_record * +hinfo::select_read (int fd, select_record *s) +{ + if (dtable.not_open (fd)) + { + set_errno (EBADF); + return NULL; + } + fhandler_base *fh = dtable[fd]; + s = fh->select_read (s); + s->fd = fd; + s->fh = fh; + s->saw_error = 0; + debug_printf ("%s fd %d", fh->get_name (), fd); + return s; +} + +select_record * +hinfo::select_write (int fd, select_record *s) +{ + if (dtable.not_open (fd)) + { + set_errno (EBADF); + return NULL; + } + fhandler_base *fh = dtable[fd]; + s = fh->select_write (s); + s->fd = fd; + s->fh = fh; + s->saw_error = 0; + debug_printf ("%s fd %d", fh->get_name (), fd); + return s; +} + +select_record * +hinfo::select_except (int fd, select_record *s) +{ + if (dtable.not_open (fd)) + { + set_errno (EBADF); + return NULL; + } + fhandler_base *fh = dtable[fd]; + s = fh->select_except (s); + s->fd = fd; + s->fh = fh; + s->saw_error = 0; + debug_printf ("%s fd %d", fh->get_name (), fd); + return s; +} + +/* + * Function to take an existant hinfo array + * and linearize it into a memory buffer. + * If memory buffer is NULL, it returns the size + * of memory buffer needed to do the linearization. + * On error returns -1. + */ + +int +hinfo::linearize_fd_array (unsigned char *in_buf, int buflen) +{ + /* If buf == NULL, just precalculate length */ + if (in_buf == NULL) + { + buflen = sizeof (size_t); + for (int i = 0, max_used_fd = -1; i < (int)size; i++) + if (!not_open (i) && !fds[i]->get_close_on_exec ()) + { + buflen += i - (max_used_fd + 1); + buflen += fds[i]->cb + strlen (fds[i]->get_name ()) + 1 + + strlen (fds[i]->get_win32_name ()) + 1; + max_used_fd = i; + } + debug_printf ("needed buflen %d", buflen); + return buflen; + } + + debug_printf ("in_buf = %x, buflen = %d", in_buf, buflen); + + /* + * Now linearize each open fd (write a 0xff byte for a closed fd). + * Write the name of the open fd first (null terminated). This + * allows the de_linearizeing code to determine what kind of fhandler_xxx + * to create. + */ + + size_t i; + int len, total_size; + + total_size = sizeof (size_t); + if (total_size > buflen) + { + system_printf ("FATAL: linearize_fd_array exceeded buffer size"); + return -1; + } + + unsigned char *buf = in_buf; + buf += sizeof (size_t); /* skip over length which is added later */ + + for (i = 0, total_size = sizeof (size_t); total_size < buflen; i++) + { + if (not_open (i) || fds[i]->get_close_on_exec ()) + { + debug_printf ("linearizing closed fd %d",i); + *buf = 0xff; /* place holder */ + len = 1; + } + else + { + len = fds[i]->linearize (buf); + debug_printf ("fd %d, len %d, name %s, device %p", i, len, buf, + fds[i]->get_device ()); + } + + total_size += len; + buf += len; + } + + i--; + memcpy (in_buf, &i, sizeof (size_t)); + if (total_size != buflen) + system_printf ("out of sync %d != %d", total_size, buflen); + return total_size; +} + +/* + * Function to take a linearized hinfo array in a memory buffer and + * re-create the original hinfo array. + */ + +LPBYTE +hinfo::de_linearize_fd_array (LPBYTE buf) +{ + int len; + size_t max_used_fd, inc_size; + + debug_printf ("buf %x", buf); + + /* First get the number of fd's - use this to set the dtablesize. + NB. This is the only place in the code this should be done !! + */ + + memcpy ((char *) &max_used_fd, buf, sizeof (int)); + buf += sizeof (size_t); + + inc_size = NOFILE_INCR * ((max_used_fd + NOFILE_INCR - 1) / NOFILE_INCR) - + size; + debug_printf ("max_used_fd %d, inc size %d", max_used_fd, inc_size); + if (inc_size > 0 && !extend (inc_size)) + { + system_printf ("out of memory"); + return NULL; + } + + for (size_t i = 0; i <= max_used_fd; i++) + { + /* 0xFF means closed */ + if (*buf == 0xff) + { + fds[i] = NULL; + buf++; + debug_printf ("closed fd %d", i); + continue; + } + /* fd was open - de_linearize it */ + /* Get the null-terminated name. It is followed by an image of + the actual fhandler_* structure. Use the status field from + this to build a new fhandler type. */ + + DWORD status; + LPBYTE obuf = buf; + char *win32; + win32 = strchr ((char *)obuf, '\0') + 1; + buf = (LPBYTE)strchr ((char *)win32, '\0') + 1; + memcpy ((char *)&status, buf + FHSTATOFF, sizeof(DWORD)); + debug_printf ("fd %d, name %s, win32 name %s, status %p", + i, obuf, win32, status); + len = build_fhandler (i, status, (const char *) NULL)-> + de_linearize ((char *) buf, (char *) obuf, win32); + set_std_handle (i); + buf += len; + debug_printf ("len %d", buf - obuf); + } + first_fd_for_open = 0; + return buf; +} + +void +hinfo::fixup_after_fork (HANDLE parent) +{ + SetResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK,"dup"); + for (size_t i = 0; i < size; i++) + if (!not_open (i)) + { + fhandler_base *fh = fds[i]; + if (fh->get_close_on_exec () || fh->get_need_fork_fixup ()) + { + debug_printf ("fd %d(%s)", i, fh->get_name ()); + fh->fixup_after_fork (parent); + } + } + ReleaseResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK,"dup"); +} + +int +hinfo::vfork_child_dup () +{ + fhandler_base **newtable; + newtable = (fhandler_base **) calloc (size, sizeof(fds[0])); + int res = 1; + + SetResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK,"dup"); + for (size_t i = 0; i < size; i++) + if (not_open (i)) + continue; + else if ((newtable[i] = dup_worker (fds[i])) == NULL) + { + res = 0; + set_errno (EBADF); + goto out; + } + fds_on_hold = fds; + fds = newtable; +out: + ReleaseResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK,"dup"); + return 1; +} + +void +hinfo::vfork_parent_restore () +{ + SetResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK,"dup"); + + close_all_files (); + fhandler_base **deleteme = fds; + fds = fds_on_hold; + fds_on_hold = NULL; + free (deleteme); + + ReleaseResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK,"dup"); + return; +} diff --git a/winsup/cygwin/dtable.sgml b/winsup/cygwin/dtable.sgml new file mode 100644 index 000000000..9f292ee73 --- /dev/null +++ b/winsup/cygwin/dtable.sgml @@ -0,0 +1,20 @@ + + +cygwin_attach_handle_to_fd + + +extern "C" int +cygwin_attach_handle_to_fd +char *name +int fd +HANDLE handle +int bin +int access + + +This function can be used to turn a Win32 "handle" into a +posix-style file handle. fd may be -1 to +make cygwin allocate a handle; the actual handle is returned +in all cases. + + diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc new file mode 100644 index 000000000..249e95c99 --- /dev/null +++ b/winsup/cygwin/environ.cc @@ -0,0 +1,567 @@ +/* environ.cc: Cygwin-adopted functions from newlib to manipulate + process's environment. + + Copyright 1997, 1998, 1999, 2000 Cygnus Solutions. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include "winsup.h" +#include +#include +#include +#include + +#define environ (*user_data->envptr) + +extern BOOL allow_glob; +extern BOOL allow_ntea; +extern BOOL strip_title_path; +extern DWORD chunksize; +extern BOOL oldstack; +BOOL threadsafe; +BOOL reset_com = TRUE; +static BOOL envcache = TRUE; + +/* List of names which are converted from dos to unix + * on the way in and back again on the way out. + * + * PATH needs to be here because CreateProcess uses it and gdb uses + * CreateProcess. HOME is here because most shells use it and would be + * confused by Windows style path names. + */ +static int return_MAX_PATH (const char *) {return MAX_PATH;} +static win_env conv_envvars[] = + { + {"PATH=", 5, NULL, NULL, cygwin_win32_to_posix_path_list, + cygwin_posix_to_win32_path_list, + cygwin_win32_to_posix_path_list_buf_size, + cygwin_posix_to_win32_path_list_buf_size}, + {"HOME=", 5, NULL, NULL, cygwin_conv_to_full_posix_path, cygwin_conv_to_full_win32_path, + return_MAX_PATH, return_MAX_PATH}, + {"LD_LIBRARY_PATH=", 16, NULL, NULL, cygwin_conv_to_full_posix_path, + cygwin_conv_to_full_win32_path, return_MAX_PATH, return_MAX_PATH}, + {NULL} + }; + +void +win_env::add_cache (const char *in_posix, const char *in_native) +{ + posix = (char *) realloc (posix, strlen (in_posix) + 1); + strcpy (posix, in_posix); + if (in_native) + { + native = (char *) realloc (native, namelen + 1 + strlen (in_native)); + (void) strcpy (native, name); + (void) strcpy (native + namelen, in_native); + } + else + { + native = (char *) realloc (native, namelen + 1 + win32_len (in_posix)); + (void) strcpy (native, name); + towin32 (in_posix, native + namelen); + } + debug_printf ("posix %s", posix); + debug_printf ("native %s", native); +} + + +/* Check for a "special" environment variable name. *env is the pointer + * to the beginning of the environment variable name. n is the length + * of the name including a mandatory '='. Returns a pointer to the + * appropriate conversion structure. + */ +win_env * +getwinenv (const char *env, const char *in_posix) +{ + for (int i = 0; conv_envvars[i].name != NULL; i++) + if (strncasematch (env, conv_envvars[i].name, conv_envvars[i].namelen)) + { + win_env *we = conv_envvars + i; + const char *val; + if (!environ || !(val = in_posix ?: getenv(we->name))) + debug_printf ("can't set native for %s since no environ yet", + we->name); + else if (!envcache || !we->posix || strcmp (val, we->posix)) + we->add_cache (val); + return we; + } + return NULL; +} + +/* Convert windows path specs to POSIX, if appropriate. + */ +static void __stdcall +posify (char **here, const char *value) +{ + char *src = *here; + win_env *conv; + int len = strcspn (src, "=") + 1; + + if (!(conv = getwinenv (src))) + return; + + /* Turn all the items from c:; into their + mounted equivalents - if there is one. */ + + char *outenv = (char *) malloc (1 + len + conv->posix_len (value)); + memcpy (outenv, src, len); + conv->toposix (value, outenv + len); + conv->add_cache (outenv + len, value); + + debug_printf ("env var converted to %s", outenv); + *here = outenv; + free (src); +} + +/* + * my_findenv -- + * Returns pointer to value associated with name, if any, else NULL. + * Sets offset to be the offset of the name/value combination in the + * environment array, for use by setenv(3) and unsetenv(3). + * Explicitly removes '=' in argument name. + */ + +static char * __stdcall +my_findenv (const char *name, int *offset) +{ + register int len; + register char **p; + const char *c; + + c = name; + len = 0; + while (*c && *c != '=') + { + c++; + len++; + } + + for (p = environ; *p; ++p) + if (!strncmp (*p, name, len)) + if (*(c = *p + len) == '=') + { + *offset = p - environ; + return (char *) (++c); + } + return NULL; +} + +/* + * getenv -- + * Returns ptr to value associated with name, if any, else NULL. + */ + +extern "C" +char * +getenv (const char *name) +{ + int offset; + + return my_findenv (name, &offset); +} + +/* putenv -- + * Sets an environment variable + */ + +extern "C" +int +putenv (const char *str) +{ + register char *p, *equal; + int rval; + + if (!(p = strdup (str))) + return 1; + if (!(equal = index (p, '='))) + { + (void) free (p); + return 1; + } + *equal = '\0'; + rval = setenv (p, equal + 1, 1); + (void) free (p); + return rval; +} + +/* + * setenv -- + * Set the value of the environment variable "name" to be + * "value". If rewrite is set, replace any current value. + */ + +extern "C" +int +setenv (const char *name, const char *value, int rewrite) +{ + register char *C; + unsigned int l_value; + int offset; + + if (*value == '=') /* no `=' in value */ + ++value; + l_value = strlen (value); + if ((C = my_findenv (name, &offset))) + { /* find if already exists */ + if (!rewrite) + return 0; + if (strlen (C) >= l_value) + { /* old larger; copy over */ + while ((*C++ = *value++)); + return 0; + } + } + else + { /* create new slot */ + register int cnt; + register char **P; + + for (P = environ, cnt = 0; *P; ++P, ++cnt) + ; + __cygwin_environ = environ = (char **) realloc ((char *) environ, + (size_t) (sizeof (char *) * (cnt + 2))); + if (!environ) + return -1; + environ[cnt + 1] = NULL; + offset = cnt; + } + + for (C = (char *) name; *C && *C != '='; ++C); /* no `=' in name */ + + if (!(environ[offset] = /* name + `=' + value */ + (char *) malloc ((size_t) ((int) (C - name) + l_value + 2)))) + return -1; + for (C = environ[offset]; (*C = *name++) && *C != '='; ++C); + *C++ = '='; + strcpy (C, value); + + win_env *spenv; + if ((spenv = getwinenv (environ[offset]))) + spenv->add_cache (value); + + return 0; +} + +/* + * unsetenv(name) -- + * Delete environment variable "name". + */ + +extern "C" +void +unsetenv (const char *name) +{ + register char **P; + int offset; + + while (my_findenv (name, &offset)) /* if set multiple times */ + for (P = &environ[offset];; ++P) + if (!(*P = *(P + 1))) + break; +} + +/* Turn environment variable part of a=b string into uppercase. */ + +static void __inline +ucenv (char *p, char *eq) +{ + /* Amazingly, NT has a case sensitive environment name list, + but only sometimes. + It's normal to have NT set your "Path" to something. + Later, you set "PATH" to something else. This alters "Path". + But if you try and do a naive getenv on "PATH" you'll get nothing. + + So we upper case the labels here to prevent confusion later but + we only do it for the first process in a session group. */ + for (; p < eq; p++) + if (islower (*p)) + *p = toupper (*p); +} + +/* Parse CYGWIN options */ + +static NO_COPY BOOL export_settings = FALSE; + +enum settings + { + justset, + isfunc, + setbit, + set_process_state, + }; + +/* The structure below is used to set up an array which is used to + * parse the CYGWIN environment variable or, if enabled, options from + * the registry. + */ +struct parse_thing + { + const char *name; + union parse_setting + { + BOOL *b; + DWORD *x; + int *i; + void (*func)(const char *); + } setting; + + enum settings disposition; + char *remember; + union parse_values + { + DWORD i; + const char *s; + } values[2]; + } known[] = +{ + {"binmode", {&__fmode}, justset, NULL, {{O_TEXT}, {O_BINARY}}}, + {"envcache", {&envcache}, justset, NULL, {{TRUE}, {FALSE}}}, + {"error_start", {func: &error_start_init}, isfunc, NULL, {{0}, {0}}}, + {"export", {&export_settings}, justset, NULL, {{FALSE}, {TRUE}}}, + {"forkchunk", {x: &chunksize}, justset, NULL, {{8192}, {0}}}, + {"glob", {&allow_glob}, justset, NULL, {{FALSE}, {TRUE}}}, + {"ntea", {&allow_ntea}, justset, NULL, {{FALSE}, {TRUE}}}, + {"ntsec", {&allow_ntsec}, justset, NULL, {{FALSE}, {TRUE}}}, + {"oldstack", {&oldstack}, justset, NULL, {{FALSE}, {TRUE}}}, + {"reset_com", {&reset_com}, justset, NULL, {{FALSE}, {TRUE}}}, + {"strip_title", {&strip_title_path}, justset, NULL, {{FALSE}, {TRUE}}}, + {"title", {&display_title}, justset, NULL, {{FALSE}, {TRUE}}}, + {"tty", {NULL}, set_process_state, NULL, {{0}, {PID_USETTY}}}, + {"threadsafe", {&threadsafe}, justset, NULL, {{TRUE}, {FALSE}}}, + {NULL, {0}, justset, 0, {{0}, {0}}} +}; + +/* Parse a string of the form "something=stuff somethingelse=more-stuff", + * silently ignoring unknown "somethings". + */ +static void __stdcall +parse_options (char *buf) +{ + int istrue; + char *p; + parse_thing *k; + + if (buf == NULL) + { + char newbuf[MAX_PATH + 7] = "CYGWIN"; + for (k = known; k->name != NULL; k++) + if (k->remember) + { + strcat (strcat (newbuf, " "), k->remember); + free (k->remember); + k->remember = NULL; + } + if (!export_settings) + return; + newbuf[sizeof ("CYGWIN") - 1] = '='; + debug_printf ("%s", newbuf); + putenv (newbuf); + return; + } + + buf = strcpy ((char *) alloca (strlen (buf) + 1), buf); + for (p = strtok (buf, " \t"); p != NULL; p = strtok (NULL, " \t")) + { + if (!(istrue = !strncasematch (p, "no", 2))) + p += 2; + else if (!(istrue = *p != '-')) + p++; + + char ch, *eq; + if ((eq = strchr (p, '=')) != NULL || (eq = strchr (p, ':')) != NULL) + ch = *eq, *eq++ = '\0'; + else + ch = 0; + + for (parse_thing *k = known; k->name != NULL; k++) + if (strcasematch (p, k->name)) + { + switch (k->disposition) + { + case isfunc: + k->setting.func ((!eq || !istrue) ? + k->values[istrue].s : eq); + debug_printf ("%s (called func)", k->name); + break; + case justset: + if (!istrue || !eq) + *k->setting.x = k->values[istrue].i; + else + *k->setting.x = strtol (eq, NULL, 0); + debug_printf ("%s %d", k->name, *k->setting.x); + break; + case set_process_state: + k->setting.x = &myself->process_state; + /* fall through */ + case setbit: + *k->setting.x &= ~k->values[istrue].i; + if (istrue || (eq && strtol (eq, NULL, 0))) + *k->setting.x |= k->values[istrue].i; + debug_printf ("%s %x", k->name, *k->setting.x); + break; + } + + if (eq) + *--eq = ch; + + int n = eq - p; + p = strdup (p); + if (n > 0) + p[n] = ':'; + k->remember = p; + break; + } + } + debug_printf ("returning"); + return; +} + +/* Set options from the registry. */ + +static void __stdcall +regopt (const char *name) +{ + MALLOC_CHECK; + /* FIXME: should not be under mount */ + reg_key r (KEY_READ, CYGWIN_INFO_PROGRAM_OPTIONS_NAME, NULL); + char buf[MAX_PATH]; + char lname[strlen(name) + 1]; + strlwr (strcpy (lname, name)); + MALLOC_CHECK; + if (r.get_string (lname, buf, sizeof (buf) - 1, "") == ERROR_SUCCESS) + parse_options (buf); + MALLOC_CHECK; +} + +/* Initialize the environ array. Look for the CYGWIN environment + * environment variable and set appropriate options from it. + */ +void +environ_init (void) +{ + const char * const rawenv = GetEnvironmentStrings (); + int envsize, i; + char *newp, **envp; + const char *p; + int sawTERM = 0; + + /* Allocate space for environment + trailing NULL + CYGWIN env. */ + envp = (char **) malloc ((4 + (envsize = 100)) * sizeof (char *)); + + regopt ("default"); + if (myself->progname[0]) + regopt (myself->progname); + +#ifdef NTSEC_ON_BY_DEFAULT + /* Set ntsec explicit as default, if NT is running */ + if (os_being_run == winNT) + allow_ntsec = TRUE; +#endif + + /* Current directory information is recorded as variables of the + form "=X:=X:\foo\bar; these must be changed into something legal + (we could just ignore them but maybe an application will + eventually want to use them). */ + for (i = 0, p = rawenv; *p != '\0'; p = strchr (p, '\0') + 1, i++) + { + newp = strdup (p); + if (i >= envsize) + envp = (char **) realloc (envp, (4 + (envsize += 100)) * + sizeof (char *)); + envp[i] = newp; + if (*newp == '=') + *newp = '!'; + char *eq; + if ((eq = strchr (newp, '=')) == NULL) + eq = strchr (newp, '\0'); + if (!parent_alive) + ucenv (newp, eq); + if (strncmp (newp, "TERM=", 5) == 0) + sawTERM = 1; + if (strncmp (newp, "CYGWIN=", sizeof("CYGWIN=") - 1) == 0) + parse_options (newp + sizeof("CYGWIN=") - 1); + if (*eq) + posify (envp + i, *++eq ? eq : --eq); + debug_printf ("%s", envp[i]); + } + + if (!sawTERM) + envp[i++] = strdup ("TERM=cygwin"); + envp[i] = NULL; + __cygwin_environ = *user_data->envptr = envp; + FreeEnvironmentStringsA ((char *) rawenv); + parse_options (NULL); + MALLOC_CHECK; +} + +/* Function called by qsort to sort environment strings. + */ +static int +env_sort (const void *a, const void *b) +{ + const char **p = (const char **) a; + const char **q = (const char **) b; + + return strcmp (*p, *q); +} + +/* Create a Windows-style environment block, i.e. a typical character buffer + * filled with null terminated strings, terminated by double null characters. + * Converts environment variables noted in conv_envvars into win32 form + * prior to placing them in the string. + */ +char * +winenv (const char * const *envp) +{ + int len, n, tl; + const char * const *srcp; + const char * *dstp; + + for (n = 0; envp[n]; n++) + continue; + + const char *newenvp[n + 1]; + + for (tl = 0, srcp = envp, dstp = newenvp; *srcp; srcp++, dstp++) + { + len = strcspn (*srcp, "=") + 1; + win_env *conv; + + if ((conv = getwinenv (*srcp, *srcp + len))) + *dstp = conv->native; + else + *dstp = *srcp; + tl += strlen (*dstp) + 1; + if ((*dstp)[0] == '!' && isalpha((*dstp)[1]) && (*dstp)[2] == ':' && + (*dstp)[3] == '=') + { + char *p = (char *) alloca (strlen (*dstp) + 1); + strcpy (p, *dstp); + *p = '='; + *dstp = p; + } + } + + *dstp = NULL; /* Terminate */ + + int envlen = dstp - newenvp; + debug_printf ("env count %d, bytes %d", envlen, tl); + + /* Windows programs expect the environment block to be sorted. */ + qsort (newenvp, envlen, sizeof (char *), env_sort); + + /* Create an environment block suitable for passing to CreateProcess. */ + char *ptr, *envblock; + envblock = (char *) malloc (tl + 2); + for (srcp = newenvp, ptr = envblock; *srcp; srcp++) + { + len = strlen (*srcp); + memcpy (ptr, *srcp, len + 1); + ptr += len + 1; + } + *ptr = '\0'; /* Two null bytes at the end */ + + return envblock; +} diff --git a/winsup/cygwin/errno.cc b/winsup/cygwin/errno.cc new file mode 100644 index 000000000..40e161654 --- /dev/null +++ b/winsup/cygwin/errno.cc @@ -0,0 +1,669 @@ +/* errno.cc: errno-related functions + + Copyright 1996, 1997, 1998, 1999 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#define _REENT_ONLY +#include +#include "winsup.h" +#include + +/* Table to map Windows error codes to Errno values. */ +/* FIXME: Doing things this way is a little slow. It's trivial to change + this into a big case statement if necessary. Left as is for now. */ + +#define X(w, e) {ERROR_##w, #w, e} + +static const struct + { + int w; /* windows version of error */ + const char *s; /* text of windows version */ + int e; /* errno version of error */ + } +errmap[] = +{ + /* FIXME: Some of these choices are arbitrary! */ + X (INVALID_FUNCTION, EBADRQC), + X (FILE_NOT_FOUND, ENOENT), + X (PATH_NOT_FOUND, ENOENT), + X (TOO_MANY_OPEN_FILES, EMFILE), + X (ACCESS_DENIED, EACCES), + X (INVALID_HANDLE, EBADF), + X (NOT_ENOUGH_MEMORY, ENOMEM), + X (INVALID_DATA, EINVAL), + X (OUTOFMEMORY, ENOMEM), + X (INVALID_DRIVE, ENODEV), + X (NOT_SAME_DEVICE, EXDEV), + X (NO_MORE_FILES, ENMFILE), + X (WRITE_PROTECT, EROFS), + X (BAD_UNIT, ENODEV), + X (SHARING_VIOLATION, EACCES), + X (LOCK_VIOLATION, EACCES), + X (SHARING_BUFFER_EXCEEDED, ENOLCK), + X (HANDLE_EOF, ENODATA), + X (HANDLE_DISK_FULL, ENOSPC), + X (NOT_SUPPORTED, ENOSYS), + X (REM_NOT_LIST, ENONET), + X (DUP_NAME, ENOTUNIQ), + X (BAD_NETPATH, ENXIO), + X (FILE_EXISTS, EEXIST), + X (CANNOT_MAKE, EPERM), + X (INVALID_PARAMETER, EINVAL), + X (NO_PROC_SLOTS, EAGAIN), + X (BROKEN_PIPE, EPIPE), + X (OPEN_FAILED, EIO), + X (NO_MORE_SEARCH_HANDLES, ENFILE), + X (CALL_NOT_IMPLEMENTED, ENOSYS), + X (INVALID_NAME, ENOENT), + X (WAIT_NO_CHILDREN, ECHILD), + X (CHILD_NOT_COMPLETE, EBUSY), + X (DIR_NOT_EMPTY, ENOTEMPTY), + X (SIGNAL_REFUSED, EIO), + X (BAD_PATHNAME, EINVAL), + X (SIGNAL_PENDING, EBUSY), + X (MAX_THRDS_REACHED, EAGAIN), + X (BUSY, EBUSY), + X (ALREADY_EXISTS, EEXIST), + X (NO_SIGNAL_SENT, EIO), + X (FILENAME_EXCED_RANGE, EINVAL), + X (META_EXPANSION_TOO_LONG, EINVAL), + X (INVALID_SIGNAL_NUMBER, EINVAL), + X (THREAD_1_INACTIVE, EINVAL), + X (BAD_PIPE, EINVAL), + X (PIPE_BUSY, EBUSY), + X (NO_DATA, EPIPE), + X (PIPE_NOT_CONNECTED, ECOMM), + X (MORE_DATA, EAGAIN), + X (DIRECTORY, EISDIR), + X (PIPE_CONNECTED, EBUSY), + X (PIPE_LISTENING, ECOMM), + X (NO_TOKEN, EINVAL), + X (PROCESS_ABORTED, EFAULT), + X (BAD_DEVICE, ENODEV), + X (BAD_USERNAME, EINVAL), + X (NOT_CONNECTED, ENOLINK), + X (OPEN_FILES, EAGAIN), + X (ACTIVE_CONNECTIONS, EAGAIN), + X (DEVICE_IN_USE, EAGAIN), + X (INVALID_AT_INTERRUPT_TIME, EINTR), + X (IO_DEVICE, EIO), + X (NOT_OWNER, EPERM), + X (END_OF_MEDIA, ENOSPC), + X (EOM_OVERFLOW, ENOSPC), + X (BEGINNING_OF_MEDIA, ESPIPE), + X (SETMARK_DETECTED, ESPIPE), + X (NO_DATA_DETECTED, ENOSPC), + X (POSSIBLE_DEADLOCK, EDEADLOCK), + X (CRC, EIO), + X (NEGATIVE_SEEK, EINVAL), + X (NOT_READY, ENOMEDIUM), + X (DISK_FULL, ENOSPC), + { 0, NULL, 0} +}; + +/* seterrno_from_win_error: Given a Windows error code, set errno + as appropriate. */ +void +seterrno_from_win_error (const char *file, int line, int code) +{ + int i; + + for (i = 0; errmap[i].w != 0; ++i) + if (code == errmap[i].w) + break; + + if (errmap[i].w != 0) + { + if (strace_active) + strace_printf (_STRACE_SYSCALL, "%s:%d seterrno: %d (%s) -> %d", + file, line, code, errmap[i].s, errmap[i].e); + set_errno (errmap[i].e); + } + else + { + if (strace_active) + strace_printf (_STRACE_SYSCALL, "%s:%d seterrno: unknown error %d", file, line, code); + set_errno (EACCES); + } +} + +/* seterrno: Set `errno' based on GetLastError (). */ +void +seterrno (const char *file, int line) +{ + seterrno_from_win_error (file, line, GetLastError ()); +} + +extern char *_user_strerror _PARAMS ((int)); + +extern const char __declspec(dllexport) * const _sys_errlist[]= +{ +/* NOERROR 0 */ "No error", +/* EPERM 1 */ "Not super-user", +/* ENOENT 2 */ "No such file or directory", +/* ESRCH 3 */ "No such process", +/* EINTR 4 */ "Interrupted system call", +/* EIO 5 */ "I/O error", +/* ENXIO 6 */ "No such device or address", +/* E2BIG 7 */ "Arg list too long", +/* ENOEXEC 8 */ "Exec format error", +/* EBADF 9 */ "Bad file number", +/* ECHILD 10 */ "No children", +/* EAGAIN 11 */ "Resource temporarily unavailable", +/* ENOMEM 12 */ "Not enough core", +/* EACCES 13 */ "Permission denied", +/* EFAULT 14 */ "Bad address", +/* ENOTBLK 15 */ "Block device required", +/* EBUSY 16 */ "Mount device busy", +/* EEXIST 17 */ "File exists", +/* EXDEV 18 */ "Cross-device link", +/* ENODEV 19 */ "No such device", +/* ENOTDIR 20 */ "Not a directory", +/* EISDIR 21 */ "Is a directory", +/* EINVAL 22 */ "Invalid argument", +/* ENFILE 23 */ "Too many open files in system", +/* EMFILE 24 */ "Too many open files", +/* ENOTTY 25 */ "Not a typewriter", +/* ETXTBSY 26 */ "Text file busy", +/* EFBIG 27 */ "File too large", +/* ENOSPC 28 */ "No space left on device", +/* ESPIPE 29 */ "Illegal seek", +/* EROFS 30 */ "Read only file system", +/* EMLINK 31 */ "Too many links", +/* EPIPE 32 */ "Broken pipe", +/* EDOM 33 */ "Math arg out of domain of func", +/* ERANGE 34 */ "Math result not representable", +/* ENOMSG 35 */ "No message of desired type", +/* EIDRM 36 */ "Identifier removed", +/* ECHRNG 37 */ "Channel number out of range", +/* EL2NSYNC 38 */ "Level 2 not synchronized", +/* EL3HLT 39 */ "Level 3 halted", +/* EL3RST 40 */ "Level 3 reset", +/* ELNRNG 41 */ "Link number out of range", +/* EUNATCH 42 */ "Protocol driver not attached", +/* ENOCSI 43 */ "No CSI structure available", +/* EL2HLT 44 */ "Level 2 halted", +/* EDEADLK 45 */ "Deadlock condition", +/* ENOLCK 46 */ "No record locks available", + "47", + "48", + "49", +/* EBADE 50 */ "Invalid exchange", +/* EBADR 51 */ "Invalid request descriptor", +/* EXFULL 52 */ "Exchange full", +/* ENOANO 53 */ "No anode", +/* EBADRQC 54 */ "Invalid request code", +/* EBADSLT 55 */ "Invalid slot", +/* EDEADLOCK 56 */ "File locking deadlock error", +/* EBFONT 57 */ "Bad font file fmt", + "58", + "59", +/* ENOSTR 60 */ "Device not a stream", +/* ENODATA 61 */ "No data (for no delay io)", +/* ETIME 62 */ "Timer expired", +/* ENOSR 63 */ "Out of streams resources", +/* ENONET 64 */ "Machine is not on the network", +/* ENOPKG 65 */ "Package not installed", +/* EREMOTE 66 */ "The object is remote", +/* ENOLINK 67 */ "The link has been severed", +/* EADV 68 */ "Advertise error", +/* ESRMNT 69 */ "Srmount error", +/* ECOMM 70 */ "Communication error on send", +/* EPROTO 71 */ "Protocol error", + "72", + "73", +/* EMULTIHOP 74 */ "Multihop attempted", +/* ELBIN 75 */ "Inode is remote (not really error)", +/* EDOTDOT 76 */ "Cross mount point (not really error)", +/* EBADMSG 77 */ "Trying to read unreadable message", + "78", + "79", +/* ENOTUNIQ 80 */ "Given log. name not unique", +/* EBADFD 81 */ "f.d. invalid for this operation", +/* EREMCHG 82 */ "Remote address changed", +/* ELIBACC 83 */ "Can't access a needed shared lib", +/* ELIBBAD 84 */ "Accessing a corrupted shared lib", +/* ELIBSCN 85 */ ".lib section in a.out corrupted", +/* ELIBMAX 86 */ "Attempting to link in too many libs", +/* ELIBEXEC 87 */ "Attempting to exec a shared library", +/* ENOSYS 88 */ "Function not implemented", +/* ENMFILE 89 */ "No more files", +/* ENOTEMPTY 90 */ "Directory not empty", +/* ENAMETOOLONG 91 */ "File or path name too long", +/* ELOOP 92 */ "Too many symbolic links", + "93", + "94", +/* EOPNOTSUPP 95 */ "Operation not supported on transport endpoint", +/* EPFNOSUPPORT 96 */ "Protocol family not supported", + "97", + "98", + "99", + "100", + "101", + "102", + "103", +/* ECONNRESET 104 */ "Connection reset by peer", +/* ENOBUFS 105 */ "No buffer space available", +/* EAFNOSUPPORT 106 */ "Address family not supported by protocol", +/* EPROTOTYPE 107 */ "Protocol wrong type for transport endpoint", +/* ENOTSOCK 108 */ "Socket operation on non-socket" +/* ENOPROTOOPT 109 */ "Protocol not available", +/* ESHUTDOWN 110 */ "Cannot send after transport endpoint shutdown", +/* ECONNREFUSED 111 */ "Connection refused", +/* EADDRINUSE 112 */ "Address already in use" +/* ECONNABORTED 113 */ "Connection aborted", +/* ENETUNREACH 114 */ "Network is unreachable", +/* ENETDOWN 115 */ "Network is down", +/* ETIMEDOUT 116 */ "Connection timed out", +/* EHOSTDOWN 117 */ "Host is down", +/* EHOSTUNREACH 118 */ "No route to host", +/* EINPROGRESS 119 */ "Operation now in progress", +/* EALREADY 120 */ "Operation already in progress", +/* EDESTADDRREQ 121 */ "Destination address required", +/* EMSGSIZE 122 */ "Message too long", +/* EPROTONOSUPPORT 123 */ "Protocol not supported", +/* ESOCKTNOSUPPORT 124 */ "Socket type not supported", +/* EADDRNOTAVAIL 125 */ "Cannot assign requested address", +/* ENETRESET 126 */ "Network dropped connection because of reset", +/* EISCONN 127 */ "Transport endpoint is already connected", +/* ENOTCONN 128 */ "Transport endpoint is not connected", +/* ETOOMANYREFS 129 */ "Too many references: cannot splice", +/* EPROCLIM 130 */ "Process limit exceeded", +/* EUSERS 131 */ "Too many users", +/* EDQUOT 132 */ "Quota exceeded", +/* ESTALE 133 */ "Stale NFS file handle", +/* ENOTSUP 134 */ "134", +/* ENOMEDIUM 135 */ "no medium" +}; + +int __declspec(dllexport) _sys_nerr = + sizeof (_sys_errlist) / sizeof (_sys_errlist[0]); + +/* FIXME: Why is strerror() a long switch and not just: + return sys_errlist[errnum]; + (or moral equivalent). + Some entries in sys_errlist[] don't match the corresponding + entries in strerror(). This seems odd. +*/ + +/* CYGWIN internal */ +/* strerror: convert from errno values to error strings */ +extern "C" char * +strerror (int errnum) +{ + const char *error; + switch (errnum) + { + case EPERM: + error = "Not owner"; + break; + case ENOENT: + error = "No such file or directory"; + break; + case ESRCH: + error = "No such process"; + break; + case EINTR: + error = "Interrupted system call"; + break; + case EIO: + error = "I/O error"; + break; + case ENXIO: + error = "No such device or address"; + break; + case E2BIG: + error = "Arg list too long"; + break; + case ENOEXEC: + error = "Exec format error"; + break; + case EBADF: + error = "Bad file number"; + break; + case ECHILD: + error = "No children"; + break; + case EAGAIN: + error = "No more processes"; + break; + case ENOMEM: + error = "Not enough memory"; + break; + case EACCES: + error = "Permission denied"; + break; + case EFAULT: + error = "Bad address"; + break; + case ENOTBLK: + error = "Block device required"; + break; + case EBUSY: + error = "Device or resource busy"; + break; + case EEXIST: + error = "File exists"; + break; + case EXDEV: + error = "Cross-device link"; + break; + case ENODEV: + error = "No such device"; + break; + case ENOTDIR: + error = "Not a directory"; + break; + case EISDIR: + error = "Is a directory"; + break; + case EINVAL: + error = "Invalid argument"; + break; + case ENFILE: + error = "Too many open files in system"; + break; + case EMFILE: + error = "Too many open files"; + break; + case ENOTTY: + error = "Not a character device"; + break; + case ETXTBSY: + error = "Text file busy"; + break; + case EFBIG: + error = "File too large"; + break; + case ENOSPC: + error = "No space left on device"; + break; + case ESPIPE: + error = "Illegal seek"; + break; + case EROFS: + error = "Read-only file system"; + break; + case EMLINK: + error = "Too many links"; + break; + case EPIPE: + error = "Broken pipe"; + break; + case EDOM: + error = "Math arg out of domain of func"; + break; + case ERANGE: + error = "Math result out of range"; + break; + case ENOMSG: + error = "No message of desired type"; + break; + case EIDRM: + error = "Identifier removed"; + break; + case ECHRNG: + error = "Channel number out of range"; + break; + case EL2NSYNC: + error = "Level 2 not synchronized"; + break; + case EL3HLT: + error = "Level 3 halted"; + break; + case EL3RST: + error = "Level 3 reset"; + break; + case ELNRNG: + error = "Link number out of range"; + break; + case EUNATCH: + error = "Protocol driver not attached"; + break; + case ENOCSI: + error = "No CSI structure available"; + break; + case EL2HLT: + error = "Level 2 halted"; + break; + case EDEADLK: + error = "Deadlock condition"; + break; + case ENOLCK: + error = "No lock"; + break; + case EBADE: + error = "Invalid exchange"; + break; + case EBADR: + error = "Invalid request descriptor"; + break; + case EXFULL: + error = "Exchange full"; + break; + case ENOANO: + error = "No anode"; + break; + case EBADRQC: + error = "Invalid request code"; + break; + case EBADSLT: + error = "Invalid slot"; + break; + case EDEADLOCK: + error = "File locking deadlock error"; + break; + case EBFONT: + error = "Bad font file fmt"; + break; + case ENOSTR: + error = "Not a stream"; + break; + case ENODATA: + error = "No data (for no delay io)"; + break; + case ETIME: + error = "Stream ioctl timeout"; + break; + case ENOSR: + error = "No stream resources"; + break; + case ENONET: + error = "Machine is not on the network"; + break; + case ENOPKG: + error = "No package"; + break; + case EREMOTE: + error = "Resource is remote"; + break; + case ENOLINK: + error = "Virtual circuit is gone"; + break; + case EADV: + error = "Advertise error"; + break; + case ESRMNT: + error = "Srmount error"; + break; + case ECOMM: + error = "Communication error"; + break; + case EPROTO: + error = "Protocol error"; + break; + case EMULTIHOP: + error = "Multihop attempted"; + break; + case ELBIN: + error = "Inode is remote (not really error)"; + break; + case EDOTDOT: + error = "Cross mount point (not really error)"; + break; + case EBADMSG: + error = "Bad message"; + break; + case ENOTUNIQ: + error = "Given log. name not unique"; + break; + case EBADFD: + error = "f.d. invalid for this operation"; + break; + case EREMCHG: + error = "Remote address changed"; + break; + case ELIBACC: + error = "Cannot access a needed shared library"; + break; + case ELIBBAD: + error = "Accessing a corrupted shared library"; + break; + case ELIBSCN: + error = ".lib section in a.out corrupted"; + break; + case ELIBMAX: + error = "Attempting to link in more shared libraries than system limit"; + break; + case ELIBEXEC: + error = "Cannot exec a shared library directly"; + break; + case ENOSYS: + error = "Function not implemented"; + break; + case ENMFILE: + error = "No more files"; + break; + case ENOTEMPTY: + error = "Directory not empty"; + break; + case ENAMETOOLONG: + error = "File or path name too long"; + break; + case ELOOP: + error = "Too many symbolic links"; + break; + case EOPNOTSUPP: + error = "Operation not supported on transport endpoint"; + break; + case EPFNOSUPPORT: + error = "Protocol family not supported"; + break; + case ECONNRESET: + error = "Connection reset by peer"; + break; + case ENOBUFS: + error = "No buffer space available; the socket cannot be connected"; + break; + case EAFNOSUPPORT: + error = "Addresses in the specified family cannot be used with this socket"; + break; + case EPROTOTYPE: + error = "errno EPROTOTYPE triggered"; + break; + case ENOTSOCK: + error = "The descriptor is a file, not a socket"; + break; + case ENOPROTOOPT: + error = "This option is unsupported"; + break; + case ESHUTDOWN: + error = "errno ESHUTDOWN triggered"; + break; + case ECONNREFUSED: + error = "Connection refused"; + break; + case EADDRINUSE: + error = "Address already in use"; + break; + case ECONNABORTED: + error = "The connection was aborted"; + break; + case ENETUNREACH: + error ="The network can't be reached from this host at this time"; + break; + case ENETDOWN: + error = "Network failed."; + break; + case ETIMEDOUT: + error = "Attempt to connect timed out without establishing a connection"; + break; + case EHOSTDOWN: + error = "errno EHOSTDOWN triggered"; + break; + case EHOSTUNREACH: + error = "errno EHOSTUNREACH triggered"; + break; + case EINPROGRESS: + error = "errno EINPROGRESS triggered"; + break; + case EALREADY: + error = "errno EALREADY triggered"; + break; + case EDESTADDRREQ: + error = "errno EDESTADDRREQ triggered"; + break; + case EMSGSIZE: + error = "errno EMSGSIZE triggered"; + break; + + case EPROTONOSUPPORT: + error = "errno EPROTONOSUPPORT triggered"; + break; + case ESOCKTNOSUPPORT: + error = "errno ESOCKTNOSUPPORT triggered"; + break; + case EADDRNOTAVAIL: + error = "errno EADDRNOTAVAIL triggered"; + break; + case ENETRESET: + error = "errno ENETRESET triggered"; + break; + case EISCONN: + error = "The socket is already connected"; + break; + case ENOTCONN: + error = "The socket is not connected"; + break; + case ETOOMANYREFS: + error = "errno ETOOMANYREFS triggered"; + break; + case EPROCLIM: + error = "errno EPROCLIM triggered"; + break; + case EUSERS: + error = "errno EUSERS triggered"; + break; + case EDQUOT: + error = "errno EDQUOT triggered"; + break; + case ESTALE: + error = "errno ESTALE triggered"; + break; + case ENOTSUP: + error = "errno ENOTSUP triggered"; + break; + case ENOMEDIUM: + error = "no medium"; + break; + default: +#ifdef _MT_SAFE + char *buf= _reent_winsup()->_strerror_buf; +#else + static NO_COPY char buf[20]; +#endif + __small_sprintf (buf, "error %d", errnum); + error = buf; + break; + } + + /* FIXME: strerror should really be const in the appropriate newlib + include files. */ + return (char *) error; +} + diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc new file mode 100644 index 000000000..fad70f887 --- /dev/null +++ b/winsup/cygwin/exceptions.cc @@ -0,0 +1,1066 @@ +/* exceptions.cc + + Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include + +#define Win32_Winsock +#include "winsup.h" +#include "exceptions.h" +#undef DECLSPEC_IMPORT +#define DECLSPEC_IMPORT +#include +#include "autoload.h" + +char debugger_command[2 * MAX_PATH + 20]; + +extern "C" { +static int handle_exceptions (EXCEPTION_RECORD *, void *, CONTEXT *, void *); +extern void sigreturn (); +extern void sigdelayed (); +extern void siglast (); +extern DWORD __sigfirst, __siglast; +}; + +static BOOL WINAPI ctrl_c_handler (DWORD); +static void really_exit (int); + +/* This is set to indicate that we have already exited. */ + +static NO_COPY int exit_already = 0; +static NO_COPY muto *mask_sync = NULL; + +HANDLE NO_COPY console_handler_thread_waiter = NULL; + +static const struct +{ + unsigned int code; + const char *name; +} status_info[] NO_COPY = +{ +#define X(s) s, #s + { X (STATUS_ABANDONED_WAIT_0) }, + { X (STATUS_ACCESS_VIOLATION) }, + { X (STATUS_ARRAY_BOUNDS_EXCEEDED) }, + { X (STATUS_BREAKPOINT) }, + { X (STATUS_CONTROL_C_EXIT) }, + { X (STATUS_DATATYPE_MISALIGNMENT) }, + { X (STATUS_FLOAT_DENORMAL_OPERAND) }, + { X (STATUS_FLOAT_DIVIDE_BY_ZERO) }, + { X (STATUS_FLOAT_INEXACT_RESULT) }, + { X (STATUS_FLOAT_INVALID_OPERATION) }, + { X (STATUS_FLOAT_OVERFLOW) }, + { X (STATUS_FLOAT_STACK_CHECK) }, + { X (STATUS_FLOAT_UNDERFLOW) }, + { X (STATUS_GUARD_PAGE_VIOLATION) }, + { X (STATUS_ILLEGAL_INSTRUCTION) }, + { X (STATUS_INTEGER_DIVIDE_BY_ZERO) }, + { X (STATUS_INTEGER_OVERFLOW) }, + { X (STATUS_INVALID_DISPOSITION) }, + { X (STATUS_IN_PAGE_ERROR) }, + { X (STATUS_NONCONTINUABLE_EXCEPTION) }, + { X (STATUS_NO_MEMORY) }, + { X (STATUS_PENDING) }, + { X (STATUS_PRIVILEGED_INSTRUCTION) }, + { X (STATUS_SINGLE_STEP) }, + { X (STATUS_STACK_OVERFLOW) }, + { X (STATUS_TIMEOUT) }, + { X (STATUS_USER_APC) }, + { X (STATUS_WAIT_0) }, + { 0, 0 } +#undef X +}; + +/* Initialization code. */ + +#ifdef __i386__ + +// Set up the exception handler for the current thread. The PowerPC & Mips +// use compiler generated tables to set up the exception handlers for each +// region of code, and the kernel walks the call list until it finds a region +// of code that handles exceptions. The x86 on the other hand uses segment +// register fs, offset 0 to point to the current exception handler. + +asm (".equ __except_list,0"); + +extern exception_list *_except_list asm ("%fs:__except_list"); + +static void +init_exception_handler (exception_list *el) +{ + el->handler = handle_exceptions; + el->prev = _except_list; + _except_list = el; +} + +#define INIT_EXCEPTION_HANDLER(el) init_exception_handler (el) +#endif + +void +set_console_handler () +{ + /* Initialize global security attribute stuff */ + + sec_none.nLength = sec_none_nih.nLength = + sec_all.nLength = sec_all_nih.nLength = sizeof (SECURITY_ATTRIBUTES); + sec_none.bInheritHandle = sec_all.bInheritHandle = TRUE; + sec_none_nih.bInheritHandle = sec_all_nih.bInheritHandle = FALSE; + sec_none.lpSecurityDescriptor = sec_none_nih.lpSecurityDescriptor = NULL; + sec_all.lpSecurityDescriptor = sec_all_nih.lpSecurityDescriptor = + get_null_sd (); + + /* Allocate the event needed for ctrl_c_handler synchronization with + wait_sig. */ + if (!console_handler_thread_waiter) + CreateEvent (&sec_none_nih, TRUE, TRUE, NULL); + (void) SetConsoleCtrlHandler (ctrl_c_handler, FALSE); + if (!SetConsoleCtrlHandler (ctrl_c_handler, TRUE)) + system_printf ("SetConsoleCtrlHandler failed, %E"); +} + +extern "C" void +init_exceptions (exception_list *el) +{ +#ifdef INIT_EXCEPTION_HANDLER + INIT_EXCEPTION_HANDLER (el); +#endif +} + +extern "C" void +error_start_init (const char *buf) +{ + if (!buf || !*buf) + { + debugger_command[0] = '\0'; + return; + } + + char myself_posix_name[MAX_PATH]; + + /* FIXME: gdb cannot use win32 paths, but what if debugger isn't gdb? */ + cygwin_conv_to_posix_path (myself->progname, myself_posix_name); + __small_sprintf (debugger_command, "%s %s", buf, myself_posix_name); +} + +/* Utilities for dumping the stack, etc. */ + +static void +exception (EXCEPTION_RECORD *e, CONTEXT *in) +{ + const char *exception_name = 0; + + if (e) + { + for (int i = 0; status_info[i].name; i++) + { + if (status_info[i].code == e->ExceptionCode) + { + exception_name = status_info[i].name; + break; + } + } + } + +#ifdef __i386__ +#define HAVE_STATUS + if (exception_name) + small_printf ("Exception: %s at eip=%08x\r\n", exception_name, in->Eip); + else + small_printf ("Exception %d at eip=%08x\r\n", e->ExceptionCode, in->Eip); + small_printf ("eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\r\n", + in->Eax, in->Ebx, in->Ecx, in->Edx, in->Esi, in->Edi); + small_printf ("ebp=%08x esp=%08x program=%s\r\n", + in->Ebp, in->Esp, myself->progname); + small_printf ("cs=%04x ds=%04x es=%04x fs=%04x gs=%04x ss=%04x\r\n", + in->SegCs, in->SegDs, in->SegEs, in->SegFs, in->SegGs, in->SegSs); +#endif + +#ifndef HAVE_STATUS + system_printf ("Had an exception"); +#endif +} + +extern "C" { +static LPVOID __stdcall +sfta(HANDLE, DWORD) +{ + return NULL; +} + +static DWORD __stdcall +sgmb(HANDLE, DWORD) +{ + return 4; +} + +#ifdef __i386__ +/* Print a stack backtrace. */ + +#define HAVE_STACK_TRACE + +/* Set from CYGWIN environment variable if want to use old method. */ +BOOL NO_COPY oldstack = 0; + +/* The function used to load the imagehlp DLL. Returns TRUE if the + DLL was found. */ +static LoadDLLinitfunc (imagehlp) +{ + imagehlp_handle = LoadLibrary ("imagehlp.dll"); + return !!imagehlp_handle; +} + +LoadDLLinit (imagehlp) /* Set up storage for imagehlp.dll autoload */ +LoadDLLfunc (StackWalk, StackWalk@36, imagehlp) + +/* A class for manipulating the stack. */ +class stack_info +{ + int first_time; /* True if just starting to iterate. */ + HANDLE hproc; /* Handle of process to inspect. */ + HANDLE hthread; /* Handle of thread to inspect. */ + int (stack_info::*get) (HANDLE, HANDLE); /* Gets the next stack frame */ +public: + STACKFRAME sf; /* For storing the stack information */ + int walk (HANDLE, HANDLE); /* Uses the StackWalk function */ + int brute_force (HANDLE, HANDLE); /* Uses the "old" method */ + void init (CONTEXT *); /* Called the first time that stack info is needed */ + + /* The constructor remembers hproc and hthread and determines which stack walking + method to use */ + stack_info (int use_old_stack, HANDLE hp, HANDLE ht): hproc(hp), hthread(ht) + { + if (!use_old_stack && LoadDLLinitnow (imagehlp)) + get = &stack_info::walk; + else + get = &stack_info::brute_force; + } + /* Postfix ++ iterates over the stack, returning zero when nothing is left. */ + int operator ++(int) { return (this->*get) (hproc, hthread); } +}; + +/* The number of parameters used in STACKFRAME */ +#define NPARAMS (sizeof(thestack->sf.Params) / sizeof(thestack->sf.Params[0])) + +/* This is the main stack frame info for this process. */ +static stack_info *thestack = NULL; +static signal_dispatch sigsave; + +/* Initialize everything needed to start iterating. */ +void +stack_info::init (CONTEXT *cx) +{ + first_time = 1; + memset (&sf, 0, sizeof(sf)); + sf.AddrPC.Offset = cx->Eip; + sf.AddrPC.Mode = AddrModeFlat; + sf.AddrStack.Offset = cx->Esp; + sf.AddrStack.Mode = AddrModeFlat; + sf.AddrFrame.Offset = cx->Ebp; + sf.AddrFrame.Mode = AddrModeFlat; +} + +/* Walk the stack by looking at successive stored 'bp' frames. + This is not foolproof. */ +int +stack_info::brute_force (HANDLE, HANDLE) +{ + char **ebp; + if (first_time) + /* Everything is filled out already */ + ebp = (char **) sf.AddrFrame.Offset; + else if ((ebp = (char **) *(char **) sf.AddrFrame.Offset) != NULL) + { + sf.AddrFrame.Offset = (DWORD) ebp; + sf.AddrPC.Offset = sf.AddrReturn.Offset; + } + else + return 0; + + first_time = 0; + if (!sf.AddrPC.Offset) + return 0; /* stack frames are exhausted */ + + /* The return address always follows the stack pointer */ + sf.AddrReturn.Offset = (DWORD) *++ebp; + + /* The arguments follow the return address */ + for (unsigned i = 0; i < NPARAMS; i++) + sf.Params[i] = (DWORD) *++ebp; + return 1; +} + +/* Use Win32 StackWalk() API to display the stack. This is theoretically + more foolproof than the brute force method above. */ +int +stack_info::walk (HANDLE hproc, HANDLE hthread) +{ +#ifdef SOMEDAY + /* It would be nice to get more information (like DLL symbols and module name) + for each stack frame but in order to do that we have to call SymInitialize. + It doesn't seem to be possible to do this inside of an excaption handler for + some reason. */ + static int initialized = 0; + if (!initialized && !SymInitialize(hproc, NULL, TRUE)) + small_printf("SymInitialize error, %E\n"); + initialized = 1; +#endif + + return StackWalk (IMAGE_FILE_MACHINE_I386, hproc, hthread, &sf, NULL, NULL, + sfta, sgmb, NULL) && !!sf.AddrFrame.Offset; +} + +/* Dump the stack using either the old method or the new Win32 API method */ +void +stack (HANDLE hproc, HANDLE hthread, CONTEXT *cx) +{ + int i; + + /* Set this up if it's the first time. */ + if (!thestack) + thestack = new stack_info (oldstack, hproc, hthread); + + thestack->init (cx); /* Initialize from the input CONTEXT */ + small_printf ("Stack trace:\r\nFrame Function Args\r\n"); + for (i = 0; i < 16 && (*thestack)++ ; i++) + { + small_printf ("%08x %08x ", thestack->sf.AddrFrame.Offset, + thestack->sf.AddrPC.Offset); + for (unsigned j = 0; j < NPARAMS; j++) + small_printf ("%s%08x", j == 0 ? " (" : ", ", thestack->sf.Params[j]); + small_printf (")\r\n"); + } + small_printf ("End of stack trace%s", + i == 16 ? " (more stack frames may be present)" : ""); +} + +/* Temporary (?) function for external callers to get a stack dump */ +extern "C" void +cygwin_stackdump() +{ + CONTEXT c; + c.ContextFlags = CONTEXT_FULL; + HANDLE h1 = GetCurrentProcess (); + HANDLE h2 = GetCurrentThread (); + GetThreadContext (h2, &c); + stack(h1, h2, &c); +} + +static int NO_COPY keep_looping = 0; + +extern "C" int +try_to_debug () +{ + debug_printf ("debugger_command %s", debugger_command); + if (*debugger_command == '\0') + return 0; + + __small_sprintf (strchr (debugger_command, '\0'), " %u", GetCurrentProcessId ()); + + BOOL dbg; + + PROCESS_INFORMATION pi = {0}; + + STARTUPINFO si = {0}; + si.lpReserved = NULL; + si.lpDesktop = NULL; + si.dwFlags = 0; + si.cb = sizeof (si); + + /* FIXME: need to know handles of all running threads to + suspend_all_threads_except (current_thread_id); + */ + + /* if any of these mutexes is owned, we will fail to start any cygwin app + until trapped app exits */ + + ReleaseMutex (pinfo_mutex); + ReleaseMutex (title_mutex); + + dbg = CreateProcess (NULL, + debugger_command, + NULL, + NULL, + FALSE, + CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP, + NULL, + NULL, + &si, + &pi); + if (!dbg) + { + system_printf ("Failed to start debugger: %E"); + /* FIXME: need to know handles of all running threads to + resume_all_threads_except (current_thread_id); + */ + } + else + { + keep_looping = 1; + while (keep_looping) + Sleep (10000); + } + + return 0; +} + +void +stackdump (HANDLE hproc, HANDLE hthread, EXCEPTION_RECORD *e, CONTEXT *in) +{ + char *p; + if (myself->progname[0]) + { + /* write to progname.stackdump if possible */ + if ((p = strrchr (myself->progname, '\\'))) + p++; + else + p = myself->progname; + char corefile[strlen(p) + sizeof(".stackdump")]; + __small_sprintf (corefile, "%s.stackdump", p); + HANDLE h = CreateFile (corefile, GENERIC_WRITE, 0, &sec_none_nih, + CREATE_ALWAYS, 0, 0); + if (h != INVALID_HANDLE_VALUE) + { + system_printf ("Dumping stack trace to %s", corefile); + SetStdHandle (STD_ERROR_HANDLE, h); + } + } + if (e) + exception (e, in); + stack (hproc, hthread, in); +} + +/* Main exception handler. */ + +static int +handle_exceptions (EXCEPTION_RECORD *e, void *arg, CONTEXT *in, void *x) +{ + int sig; + + /* If we've already exited, don't do anything here. Returning 1 + tells Windows to keep looking for an exception handler. */ + if (exit_already) + return 1; + + /* Coerce win32 value to posix value. */ + switch (e->ExceptionCode) + { + case STATUS_FLOAT_DENORMAL_OPERAND: + case STATUS_FLOAT_DIVIDE_BY_ZERO: + case STATUS_FLOAT_INEXACT_RESULT: + case STATUS_FLOAT_INVALID_OPERATION: + case STATUS_FLOAT_OVERFLOW: + case STATUS_FLOAT_STACK_CHECK: + case STATUS_FLOAT_UNDERFLOW: + case STATUS_INTEGER_DIVIDE_BY_ZERO: + case STATUS_INTEGER_OVERFLOW: + sig = SIGFPE; + break; + + case STATUS_ILLEGAL_INSTRUCTION: + case STATUS_PRIVILEGED_INSTRUCTION: + case STATUS_NONCONTINUABLE_EXCEPTION: + sig = SIGILL; + break; + + case STATUS_TIMEOUT: + sig = SIGALRM; + break; + + case STATUS_ACCESS_VIOLATION: + case STATUS_DATATYPE_MISALIGNMENT: + case STATUS_ARRAY_BOUNDS_EXCEEDED: + case STATUS_GUARD_PAGE_VIOLATION: + case STATUS_IN_PAGE_ERROR: + case STATUS_NO_MEMORY: + case STATUS_INVALID_DISPOSITION: + case STATUS_STACK_OVERFLOW: + sig = SIGSEGV; + break; + + case STATUS_CONTROL_C_EXIT: + sig = SIGINT; + break; + + case STATUS_INVALID_HANDLE: + /* CloseHandle will throw this exception if it is given an + invalid handle. We don't care about the exception; we just + want CloseHandle to return an error. This can be revisited + if gcc ever supports Windows style structured exception + handling. */ + return 0; + + default: + /* If we don't recognize the exception, we have to assume that + we are doing structured exception handling, and we let + something else handle it. */ + return 1; + } + + debug_printf ("In cygwin_except_handler exc %p at %p sp %p", e->ExceptionCode, in->Eip, in->Esp); + debug_printf ("In cygwin_except_handler sig = %d at %p", sig, in->Eip); + + if (myself->getsig(sig).sa_mask & SIGTOMASK (sig)) + syscall_printf ("signal %d, masked %p", sig, myself->getsig(sig).sa_mask); + + if (!myself->progname[0] + || (void *) myself->getsig(sig).sa_handler == (void *) SIG_DFL + || (void *) myself->getsig(sig).sa_handler == (void *) SIG_IGN + || (void *) myself->getsig(sig).sa_handler == (void *) SIG_ERR) + { + static NO_COPY int traced = 0; + + /* Print the exception to the console */ + if (e) + { + for (int i = 0; status_info[i].name; i++) + { + if (status_info[i].code == e->ExceptionCode) + { + system_printf ("Exception: %s", status_info[i].name); + break; + } + } + } + + /* Another exception could happen while tracing or while exiting. + Only do this once. */ + if (traced++) + system_printf ("Error while dumping state (probably corrupted stack)"); + else + { + HANDLE hthread; + DuplicateHandle (hMainProc, GetCurrentThread (), + hMainProc, &hthread, 0, FALSE, DUPLICATE_SAME_ACCESS); + stackdump (hMainProc, hthread, e, in); + } + try_to_debug (); + really_exit (EXIT_SIGNAL | sig); + } + + debug_printf ("In cygwin_except_handler calling %p", + myself->getsig(sig).sa_handler); + + DWORD *bp = (DWORD *)in->Esp; + for (DWORD *bpend = bp - 8; bp > bpend; bp--) + if (*bp == in->SegCs && bp[-1] == in->Eip) + { + bp -= 2; + break; + } + + in->Ebp = (DWORD) bp; + sigsave.cx = in; + sig_send (NULL, sig); // Signal myself + sigsave.cx = NULL; + return 0; +} +#endif /* __i386__ */ + +#ifndef HAVE_STACK_TRACE +void +stack (void) +{ + system_printf ("Stack trace not yet supported on this machine."); +} +#endif +} + +/* Utilities to call a user supplied exception handler. */ + +#define SIG_NONMASKABLE (SIGTOMASK (SIGCONT) | SIGTOMASK (SIGKILL) | SIGTOMASK (SIGSTOP)) + +#ifdef __i386__ +#define HAVE_CALL_HANDLER + +/* Non-raceable sigsuspend + * Note: This implementation is based on the Single UNIX Specification + * man page. This indicates that sigsuspend always returns -1 and that + * attempts to block unblockable signals will be silently ignored. + * This is counter to what appears to be documented in some UNIX + * man pages, e.g. Linux. + */ +int __stdcall +handle_sigsuspend (sigset_t tempmask) +{ + sigset_t oldmask = myself->getsigmask (); // Remember for restoration + + set_process_mask (tempmask & ~SIG_NONMASKABLE);// Let signals we're + // interested in through. + sigproc_printf ("old mask %x, new mask %x", oldmask, tempmask); + + sig_dispatch_pending (0); + WaitForSingleObject (signal_arrived, INFINITE); + + set_sig_errno (EINTR); // Per POSIX + + /* A signal dispatch function will have been added to our stack and will + be hit eventually. Set the old mask to be restored when the signal + handler returns. */ + + sigsave.oldmask = oldmask; // Will be restored by signal handler + return -1; +} + +extern DWORD exec_exit; // Possible exit value for exec +extern int pending_signals; + +extern __inline int +interruptible (DWORD pc) +{ + DWORD pchigh = pc & 0xf0000000; + return ((pc >= (DWORD) &__sigfirst) && (pc <= (DWORD) &__siglast)) || + !(pchigh == 0xb0000000 || pchigh == 0x70000000 || pchigh == 0x60000000); +} + +void +interrupt_now (CONTEXT *ctx, int sig, struct sigaction& siga, void *handler) +{ + DWORD oldmask = myself->getsigmask (); + set_process_mask (myself->getsigmask () | siga.sa_mask | SIGTOMASK (sig)); + + DWORD *sp = (DWORD *) ctx->Esp; + *(--sp) = ctx->Eip; /* ctxinal IP where program was suspended */ + *(--sp) = ctx->EFlags; + *(--sp) = ctx->Esi; + *(--sp) = ctx->Edi; + *(--sp) = ctx->Edx; + *(--sp) = ctx->Ecx; + *(--sp) = ctx->Ebx; + *(--sp) = ctx->Eax; + *(--sp) = (DWORD)-1; /* no saved errno. */ + *(--sp) = oldmask; + *(--sp) = sig; + *(--sp) = (DWORD) sigreturn; + + ctx->Esp = (DWORD) sp; + ctx->Eip = (DWORD) handler; + + SetThreadContext (myself->getthread2signal(), ctx); /* Restart the thread */ +} + +int +interrupt_on_return (CONTEXT *ctx, int sig, struct sigaction& siga, void *handler) +{ + int i; + + if (sigsave.sig) + return 0; /* Already have a signal stacked up */ + + /* Set this up if it's the first time. */ + /* FIXME: Eventually augment to handle more than one thread */ + if (!thestack) + thestack = new stack_info (oldstack, hMainProc, hMainThread); + + thestack->init (ctx); /* Initialize from the input CONTEXT */ + for (i = 0; i < 32 && (*thestack)++ ; i++) + if (interruptible (thestack->sf.AddrReturn.Offset)) + { + DWORD *addr_retaddr = ((DWORD *)thestack->sf.AddrFrame.Offset) + 1; + if (*addr_retaddr != thestack->sf.AddrReturn.Offset) + break; + sigsave.retaddr = *addr_retaddr; + *addr_retaddr = (DWORD) sigdelayed; + sigsave.oldmask = myself->getsigmask (); // Remember for restoration + set_process_mask (myself->getsigmask () | siga.sa_mask | SIGTOMASK (sig)); + sigsave.func = (void (*)(int)) handler; + sigsave.sig = sig; + sigsave.saved_errno = -1; // Flag: no errno to save + break; + } + + return 1; +} + +extern "C" void __stdcall +set_sig_errno (int e) +{ + set_errno (e); + sigsave.saved_errno = e; +} + +static int +call_handler (int sig, struct sigaction& siga, void *handler) +{ + CONTEXT *cx, orig; + int res; + + if (hExeced != NULL && hExeced != INVALID_HANDLE_VALUE) + { + SetEvent (signal_arrived); // For an EINTR case + sigproc_printf ("armed signal_arrived"); + exec_exit = sig; // Maybe we'll exit with this value + return 1; + } + + /* Suspend the running thread, grab its context somewhere safe + and run the exception handler in the context of the thread - + we have to do that since sometimes they don't return - and if + this thread doesn't return, you won't ever get another exception. */ + + sigproc_printf ("Suspending %p (mainthread)", myself->getthread2signal()); + HANDLE hth = myself->getthread2signal (); + res = SuspendThread (hth); + sigproc_printf ("suspend said %d, %E", res); + + /* Clear any waiting threads prior to dispatching to handler function */ + proc_subproc(PROC_CLEARWAIT, 0); + + if (sigsave.cx) + { + cx = sigsave.cx; + sigsave.cx = NULL; + } + else + { + cx = &orig; + /* FIXME - this does not preserve FPU state */ + orig.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; + if (!GetThreadContext (hth, cx)) + { + system_printf ("couldn't get context of main thread, %E"); + ResumeThread (hth); + goto out; + } + } + + if (cx == &orig && interruptible (cx->Eip)) + interrupt_now (cx, sig, siga, handler); + else if (!interrupt_on_return (cx, sig, siga, handler)) + { + pending_signals = 1; /* FIXME: Probably need to be more tricky here */ + sig_set_pending (sig); + } + + (void) ResumeThread (hth); + (void) SetEvent (signal_arrived); // For an EINTR case + sigproc_printf ("armed signal_arrived %p, res %d", signal_arrived, res); + +out: + sigproc_printf ("returning"); + return 1; +} +#endif /* i386 */ + +#ifndef HAVE_CALL_HANDLER +#error "Need to supply machine dependent call_handler" +#endif + +/* Keyboard interrupt handler. */ +static BOOL WINAPI +ctrl_c_handler (DWORD type) +{ + if (type == CTRL_LOGOFF_EVENT) + return TRUE; + + /* Wait for sigproc_init to tell us that it's safe to send something. + This event will always be in a signalled state when wait_sig is + ready to process signals. */ + (void) WaitForSingleObject (console_handler_thread_waiter, 5000); + + if ((type == CTRL_CLOSE_EVENT) || (type == CTRL_SHUTDOWN_EVENT)) + /* Return FALSE to prevent an "End task" dialog box from appearing + for each Cygwin process window that's open when the computer + is shut down or console window is closed. */ + { + sig_send (NULL, SIGHUP); + return FALSE; + } + tty_min *t = cygwin_shared->tty.get_tty(myself->ctty); + /* Ignore this if we're not the process group lead since it should be handled + *by* the process group leader. */ + if (t->getpgid () != myself->pid || + (GetTickCount () - t->last_ctrl_c) < MIN_CTRL_C_SLOP) + return TRUE; + else + /* Otherwise we just send a SIGINT to the process group and return TRUE (to indicate + that we have handled the signal). At this point, type should be + a CTRL_C_EVENT or CTRL_BREAK_EVENT. */ + { + t->last_ctrl_c = GetTickCount (); + kill (-myself->pid, SIGINT); + t->last_ctrl_c = GetTickCount (); + return TRUE; + } +} + +/* Set the signal mask for this process. + * Note that some signals are unmaskable, as in UNIX. + */ +extern "C" void __stdcall +set_process_mask (sigset_t newmask) +{ + mask_sync->acquire (INFINITE); + newmask &= ~SIG_NONMASKABLE; + sigproc_printf ("old mask = %x, new mask = %x", myself->getsigmask (), newmask); + myself->setsigmask (newmask); // Set a new mask + mask_sync->release (); + return; +} + +extern "C" { +static void +sig_handle_tty_stop (int sig) +{ +#if 0 + HANDLE waitbuf[2]; + + /* Be sure that process's main thread isn't an owner of vital + mutex to prevent cygwin subsystem lockups */ + waitbuf[0] = pinfo_mutex; + waitbuf[1] = title_mutex; + WaitForMultipleObjects (2, waitbuf, TRUE, INFINITE); + ReleaseMutex (pinfo_mutex); + ReleaseMutex (title_mutex); +#endif + myself->stopsig = sig; + myself->process_state |= PID_STOPPED; + /* See if we have a living parent. If so, send it a special signal. + * It will figure out exactly which pid has stopped by scanning + * its list of subprocesses. + */ + if (my_parent_is_alive ()) + { + pinfo *parent = procinfo(myself->ppid); + sig_send (parent, __SIGCHILDSTOPPED); + } + sigproc_printf ("process %d stopped by signal %d, parent_alive %p", + myself->pid, sig, parent_alive); + /* There is a small race here with the above two mutexes */ + SuspendThread (hMainThread); + return; +} +} + +int __stdcall +sig_handle (int sig) +{ + int rc = 0; + + sigproc_printf ("signal %d", sig); + + struct sigaction thissig = myself->getsig(sig); + void *handler = (void *) thissig.sa_handler; + + myself->rusage_self.ru_nsignals++; + + /* Clear pending SIGCONT on stop signals */ + if (sig == SIGSTOP || sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) + sig_clear (SIGCONT); + + if (sig == SIGKILL) + goto exit_sig; + + if (sig == SIGSTOP) + goto stop; + + /* FIXME: Should we still do this if SIGCONT has a handler? */ + if (sig == SIGCONT) + { + myself->stopsig = 0; + myself->process_state &= ~PID_STOPPED; + /* Clear pending stop signals */ + sig_clear (SIGSTOP); + sig_clear (SIGTSTP); + sig_clear (SIGTTIN); + sig_clear (SIGTTOU); + /* Windows 95 hangs on resuming non-suspended thread */ + SuspendThread (hMainThread); + while (ResumeThread (hMainThread) > 1) + ; + /* process pending signals */ + sig_dispatch_pending (); + } + +#if 0 + char sigmsg[24]; + __small_sprintf (sigmsg, "cygwin: signal %d\n", sig); + OutputDebugString (sigmsg); +#endif + + if (handler == (void *) SIG_DFL) + { + if (sig == SIGCHLD || sig == SIGIO || sig == SIGCONT || sig == SIGWINCH) + { + sigproc_printf ("default signal %d ignored", sig); + goto done; + } + + if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) + goto stop; + + goto exit_sig; + } + + if (handler == (void *) SIG_IGN) + { + sigproc_printf ("signal %d ignored", sig); + goto done; + } + + if (handler == (void *) SIG_ERR) + goto exit_sig; + + if ((sig == SIGCHLD) && (thissig.sa_flags & SA_NOCLDSTOP)) + goto done; + + goto dosig; + +stop: + handler = (void *) sig_handle_tty_stop; + +dosig: + /* Dispatch to the appropriate function. */ + sigproc_printf ("signal %d, about to call %p", sig, thissig.sa_handler); + rc = call_handler (sig, thissig, handler); + +done: + sigproc_printf ("returning %d", rc); + return rc; + +exit_sig: + if (sig == SIGQUIT || sig == SIGABRT) + { + stackdump (NULL, NULL, NULL, NULL); + try_to_debug (); + } + sigproc_printf ("signal %d, about to call do_exit", sig); + TerminateThread (hMainThread, 0); + /* FIXME: This just works around the problem so that we don't attempt to + use a resource lock when exiting. */ + user_data->resourcelocks->Delete(); + user_data->resourcelocks->Init(); + do_exit (EXIT_SIGNAL | (sig << 8)); + /* Never returns */ +} + +/* Cover function to `do_exit' to handle exiting even in presence of more + exceptions. We use to call exit, but a SIGSEGV shouldn't cause atexit + routines to run. */ + +static void +really_exit (int rc) +{ + /* If the exception handler gets a trap, we could recurse awhile. + If this is non-zero, skip the cleaning up and exit NOW. */ + + if (exit_already++) + { + /* We are going down - reset our process_state without locking. */ + myself->record_death (FALSE); + ExitProcess (rc); + } + + do_exit (rc); +} + +HANDLE NO_COPY pinfo_mutex = NULL; +HANDLE NO_COPY title_mutex = NULL; + +void +events_init (void) +{ + /* pinfo_mutex protects access to process table */ + + if (!(pinfo_mutex = CreateMutex (&sec_all_nih, FALSE, + shared_name ("pinfo_mutex", 0)))) + api_fatal ("catastrophic failure - unable to create pinfo_mutex, %E"); + + ProtectHandle (pinfo_mutex); + + /* title_mutex protects modification of console title. It's neccessary + while finding console window handle */ + + if (!(title_mutex = CreateMutex (&sec_all_nih, FALSE, + shared_name ("title_mutex", 0)))) + api_fatal ("can't create title mutex, %E"); + + ProtectHandle (title_mutex); + mask_sync = new_muto (FALSE, NULL); +} + +void +events_terminate (void) +{ +//CloseHandle (pinfo_mutex); // Use implicit close on exit to avoid race + ForceCloseHandle (title_mutex); + exit_already = 1; +} + +#define pid_offset (unsigned)(((pinfo *)NULL)->pid) +extern "C" { +void unused_sig_wrapper() +{ +/* Signal cleanup stuff. Cleans up stack (too bad that we didn't + prototype signal handlers as __stdcall), calls _set_process_mask + to restore any mask, restores any potentially clobbered registered + and returns to orignal caller. */ +__asm__ volatile (" + .text +___sigfirst: + .globl __raise +__raise: + pushl %%ebp + movl %%esp,%%ebp + movl 8(%%ebp),%%eax + pushl %%eax + movl $_myself,%%eax + pushl %6(%%eax) + call __kill + mov %%ebp,%%esp + popl %%ebp + ret + +_sigreturn: + addl $4,%%esp + call _set_process_mask@4 + popl %%eax # saved errno + testl %%eax,%%eax # lt 0 + jl 1f # yup. ignore it + movl %1,%%ebx + movl %%eax,(%%ebx) +1: popl %%eax + popl %%ebx + popl %%ecx + popl %%edx + popl %%edi + popl %%esi + popf + ret + +_sigdelayed: + # addl 4,%%esp + cmpl $0,_pending_signals + je 2f + pushl $0 + call _sig_dispatch_pending@4 +2: pushl %2 # original return address + pushf + pushl %%esi + pushl %%edi + pushl %%edx + pushl %%ecx + pushl %%ebx + pushl %%eax + pushl %7 # saved errno + pushl %3 # oldmask + pushl %4 # signal argument + pushl $_sigreturn + movl $0,%0 + pushl $_signal_arrived + call _ResetEvent@4 + jmp *%5 + +___siglast: +" : "=m" (sigsave.sig) : "m" (&_impure_ptr->_errno), + "g" (sigsave.retaddr), "g" (sigsave.oldmask), "g" (sigsave.sig), + "g" (sigsave.func), "o" (pid_offset), "g" (sigsave.saved_errno) + ); +} +} diff --git a/winsup/cygwin/exec.cc b/winsup/cygwin/exec.cc new file mode 100644 index 000000000..54d2c9577 --- /dev/null +++ b/winsup/cygwin/exec.cc @@ -0,0 +1,204 @@ +/* exec.cc: exec system call support. + + Copyright 1996, 1997, 1998, 2000 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include +#include +#include "winsup.h" + +/* This is called _execve and not execve because the real execve is defined + in libc/posix/execve.c. It calls us. */ + +extern "C" +pid_t +_execve (const char *path, const char *const argv[], const char *const envp[]) +{ + static char *const empty_env[] = { 0 }; + MALLOC_CHECK; + if (!envp) + envp = empty_env; + return _spawnve (NULL, _P_OVERLAY, path, argv, envp); +} + +extern "C" +int +execl (const char *path, const char *arg0, ...) +{ + int i; + va_list args; + const char *argv[1024]; + + va_start (args, arg0); + argv[0] = arg0; + i = 1; + do + argv[i] = va_arg (args, const char *); + while (argv[i++] != NULL); + va_end (args); + MALLOC_CHECK; + return _execve (path, (char * const *) argv, *user_data->envptr); +} + +extern "C" +int +execv (const char *path, char * const *argv) +{ + MALLOC_CHECK; + return _execve (path, (char * const *) argv, *user_data->envptr); +} + +/* the same as a standard exec() calls family, but with NT security support */ + +extern "C" +pid_t +sexecve (HANDLE hToken, const char *path, const char *const argv[], + const char *const envp[]) +{ + _spawnve (hToken, _P_OVERLAY, path, argv, envp); + return -1; +} + +extern "C" +int +sexecl (HANDLE hToken, const char *path, const char *arg0, ...) +{ + int i; + va_list args; + const char *argv[1024]; + + va_start (args, arg0); + argv[0] = arg0; + i = 1; + + do + argv[i] = va_arg (args, const char *); + while (argv[i++] != NULL); + + va_end (args); + + MALLOC_CHECK; + return sexecve (hToken, path, (char * const *) argv, *user_data->envptr); +} + +extern "C" +int +sexecle (HANDLE hToken, const char *path, const char *arg0, ...) +{ + int i; + va_list args; + const char * const *envp; + const char *argv[1024]; + + va_start (args, arg0); + argv[0] = arg0; + i = 1; + + do + argv[i] = va_arg (args, const char *); + while (argv[i++] != NULL); + + envp = va_arg (args, const char * const *); + va_end (args); + + MALLOC_CHECK; + return sexecve(hToken, path, (char * const *) argv, (char * const *) envp); +} + +extern "C" +int +sexeclp (HANDLE hToken, const char *path, const char *arg0, ...) +{ + int i; + va_list args; + const char *argv[1024]; + + va_start (args, arg0); + argv[0] = arg0; + i = 1; + + do + argv[i] = va_arg (args, const char *); + while (argv[i++] != NULL); + + va_end (args); + + MALLOC_CHECK; + return sexecvpe (hToken, path, (const char * const *) argv, + *user_data->envptr); +} + +extern "C" +int +sexeclpe (HANDLE hToken, const char *path, const char *arg0, ...) +{ + int i; + va_list args; + const char * const *envp; + const char *argv[1024]; + + va_start (args, arg0); + argv[0] = arg0; + i = 1; + + do + argv[i] = va_arg (args, const char *); + while (argv[i++] != NULL); + + envp = va_arg (args, const char * const *); + va_end (args); + + MALLOC_CHECK; + return sexecvpe (hToken, path, argv, envp); +} + +extern "C" +int +sexecv (HANDLE hToken, const char *path, const char * const *argv) +{ + MALLOC_CHECK; + return sexecve (hToken, path, argv, *user_data->envptr); +} + +extern "C" +int +sexecp (HANDLE hToken, const char *path, const char * const *argv) +{ + MALLOC_CHECK; + return sexecvpe (hToken, path, argv, *user_data->envptr); +} + +/* + * Copy string, until c or is encountered. + * NUL-terminate the destination string (s1). + * Return pointer to terminating byte in dst string. + */ + +char * __stdcall +strccpy (char *s1, const char **s2, char c) +{ + while (**s2 && **s2 != c) + *s1++ = *((*s2)++); + *s1 = 0; + + MALLOC_CHECK; + return s1; +} + +extern "C" +int +sexecvpe (HANDLE hToken, const char *file, const char * const *argv, + const char *const *envp) +{ + char buf[MAXNAMLEN]; + MALLOC_CHECK; + return sexecve (hToken, find_exec (file, buf), argv, envp); +} diff --git a/winsup/cygwin/external.cc b/winsup/cygwin/external.cc new file mode 100644 index 000000000..539e0ba7e --- /dev/null +++ b/winsup/cygwin/external.cc @@ -0,0 +1,107 @@ +/* external.cc: Interface to Cygwin internals from external programs. + + Copyright 1997, 1998, 1999 Cygnus Solutions. + + Written by Christopher Faylor + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include "winsup.h" +#include "external.h" + +static external_pinfo * +fillout_pinfo (DWORD pid) +{ + BOOL nextpid; + pinfo *p = NULL; + int i; + static external_pinfo ep; + + if ((nextpid = !!(pid & CW_NEXTPID))) + pid ^= CW_NEXTPID; + for (i = 0; i < cygwin_shared->p.size(); i++, p = NULL) + { + p = cygwin_shared->p.vec + i; + if (!pid || (DWORD) p->pid == pid) + { + if (nextpid && pid) + { + pid = 0; + nextpid = 0; + } + else if (p->pid && NOTSTATE(p, PID_CLEAR)) + break; + } + } + + if (p == NULL) + return 0; + + memset (&ep, 0, sizeof ep); + ep.ctty = tty_attached (p) ? p->ctty : -1; + ep.pid = p->pid; + ep.ppid = p->ppid; + ep.hProcess = p->hProcess; + ep.dwProcessId = p->dwProcessId; +//ep.dwSpawnedProcessId = p->dwSpawnedProcessId; + ep.uid = p->uid; + ep.gid = p->gid; + ep.pgid = p->pgid; + ep.sid = p->sid; + ep.umask = p->umask; + ep.start_time = p->start_time; + ep.rusage_self = p->rusage_self; + ep.rusage_children = p->rusage_children; + strcpy (ep.progname, p->progname); + ep.strace_mask = 0; + ep.strace_file = 0; + + ep.process_state = p->process_state; + return &ep; +} + +extern "C" DWORD +cygwin_internal (cygwin_getinfo_types t, ...) +{ + va_list arg; + va_start (arg, t); + + switch (t) + { + case CW_LOCK_PINFO: + return lock_pinfo_for_update (va_arg (arg, DWORD)); + break; + + case CW_UNLOCK_PINFO: + unlock_pinfo (); + return 1; + + case CW_GETTHREADNAME: + return (DWORD) threadname (va_arg (arg, DWORD)); + + case CW_SETTHREADNAME: + { + char *name = va_arg (arg, char *); + regthread (name, va_arg (arg, DWORD)); + return 1; + } + + case CW_GETPINFO: + return (DWORD) fillout_pinfo (va_arg (arg, DWORD)); + + case CW_GETVERSIONINFO: + return (DWORD) cygwin_version_strings; + + case CW_READ_V1_MOUNT_TABLES: + /* Upgrade old v1 registry mounts to new location. */ + cygwin_shared->mount.import_v1_mounts (); + return 0; + + default: + return (DWORD) -1; + } +} diff --git a/winsup/cygwin/external.sgml b/winsup/cygwin/external.sgml new file mode 100644 index 000000000..a41d34936 --- /dev/null +++ b/winsup/cygwin/external.sgml @@ -0,0 +1,16 @@ + + +cygwin_internal + + +extern "C" DWORD +cygwin_internal +cygwin_getinfo_types t +... + + +This function gives you access to various internal data and functions. +Stay away unless you know what you're doing. + + + diff --git a/winsup/cygwin/fcntl.cc b/winsup/cygwin/fcntl.cc new file mode 100644 index 000000000..a82a10521 --- /dev/null +++ b/winsup/cygwin/fcntl.cc @@ -0,0 +1,106 @@ +/* fcntl.cc: fcntl syscall + + Copyright 1996, 1997, 1998 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include +#include "winsup.h" + +extern "C" +int +_fcntl (int fd, int cmd,...) +{ + va_list args; + int arg = 0; + int res; + SetResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK, "_fcntl"); + + if (dtable.not_open (fd)) + { + set_errno (EBADF); + res = -1; + goto done; + } + + switch (cmd) + { + case F_DUPFD: + va_start (args, cmd); + arg = va_arg (args,int); + va_end (args); + res = dup2 (fd, dtable.find_unused_handle (arg)); + goto done; + + case F_GETFD: + res = dtable[fd]->get_close_on_exec () ? FD_CLOEXEC : 0; + goto done; + + case F_SETFD: + va_start (args, cmd); + arg = va_arg (args, int); + va_end (args); + dtable[fd]->set_close_on_exec (arg); + res = 0; + goto done; + + case F_GETFL: + { + res = dtable[fd]->get_flags (); + goto done; + } + case F_SETFL: + { + int temp = 0; + + va_start (args, cmd); + arg = va_arg (args, int); + va_end (args); + + if (arg & O_RDONLY) + temp |= GENERIC_READ; + if (arg & O_WRONLY) + temp |= GENERIC_WRITE; + + syscall_printf ("fcntl (%d, F_SETFL, %d)", arg); + + dtable[fd]->set_access (temp); + dtable[fd]->set_flags (arg); + + res = 0; + goto done; + } + + case F_GETLK: + case F_SETLK: + case F_SETLKW: + { + struct flock *fl; + va_start (args, cmd); + fl = va_arg (args,struct flock *); + va_end (args); + res = dtable[fd]->lock (cmd, fl); + goto done; + } + default: + set_errno (EINVAL); + res = -1; + goto done; + } + + set_errno (ENOSYS); + res = -1; + + done: + ReleaseResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK,"_fcntl"); + + syscall_printf ("%d = fcntl (%d, %d, %d)", res, fd, cmd, arg); + return res; +} diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc new file mode 100644 index 000000000..58521d48b --- /dev/null +++ b/winsup/cygwin/fhandler.cc @@ -0,0 +1,1501 @@ +/* fhandler.cc. See console.cc for fhandler_console functions. + + Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include +#include "winsup.h" + +static NO_COPY const int CHUNK_SIZE = 1024; /* Used for crlf conversions */ + +static char fhandler_disk_dummy_name[] = "some disk file"; + +int +fhandler_base::puts_readahead (const char *s, size_t len = (size_t) -1) +{ + int success = 1; + while ((((len == (size_t) -1) && *s) || len--) && + (success = put_readahead (*s++) > 0)) + continue; + return success; +} + +int +fhandler_base::put_readahead (char value) +{ + char *newrabuf; + if (raixput < rabuflen) + /* Nothing to do */; + else if ((newrabuf = (char *) realloc (rabuf, rabuflen += 32))) + rabuf = newrabuf; + else + return 0; + + rabuf[raixput++] = value; + ralen++; + return 1; +} + +int +fhandler_base::get_readahead () +{ + int chret = -1; + if (raixget < ralen) + chret = ((unsigned char)rabuf[raixget++]) & 0xff; + /* FIXME - not thread safe */ + if (raixget >= ralen) + raixget = raixput = ralen = 0; + return chret; +} + +int +fhandler_base::peek_readahead (int queryput) +{ + int chret = -1; + if (!queryput && raixget < ralen) + chret = ((unsigned char) rabuf[raixget]) & 0xff; + else if (queryput && raixput > 0) + chret = ((unsigned char) rabuf[raixput - 1]) & 0xff; + return chret; +} + +void +fhandler_base::set_readahead_valid (int val, int ch = -1) +{ + if (!val) + ralen = raixget = raixput = 0; + if (ch != -1) + put_readahead(ch); +} + +int +fhandler_base::eat_readahead (int n) +{ + int oralen = ralen; + if (n < 0) + n = ralen; + if (n > 0 && ralen) + { + if ((ralen -= n) < 0) + ralen = 0; + + if (raixget >= ralen) + raixget = raixput = ralen = 0; + else if (raixput > ralen) + raixput = ralen; + } + + return oralen; +} + +uid_t __stdcall +get_file_owner (int use_ntsec, const char *filename) +{ + if (use_ntsec && allow_ntsec) + { + extern LONG ReadSD(const char *, PSECURITY_DESCRIPTOR, LPDWORD); + DWORD sd_size = 4096; + char psd_buffer[4096]; + PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) psd_buffer; + PSID psid; + BOOL bOwnerDefaulted = TRUE; + + if (ReadSD (filename, psd, &sd_size) <= 0) + return getuid(); + + if (!GetSecurityDescriptorOwner (psd, &psid, &bOwnerDefaulted)) + return getuid (); + + return psid ? get_uid_from_sid (psid) : getuid (); + } + + return getuid(); +} + +gid_t __stdcall +get_file_group (int use_ntsec, const char *filename) +{ + if (use_ntsec && allow_ntsec) + { + extern LONG ReadSD(const char *, PSECURITY_DESCRIPTOR, LPDWORD); + DWORD sd_size = 4096; + char psd_buffer[4096]; + PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) psd_buffer; + PSID psid; + BOOL bGroupDefaulted = TRUE; + + if (ReadSD (filename, psd, &sd_size) <= 0) + return getgid(); + + if (!GetSecurityDescriptorGroup (psd, &psid, &bGroupDefaulted)) + return getgid (); + + return psid ? get_gid_from_sid (psid) : getuid (); + } + + return getgid (); +} + +/**********************************************************************/ +/* fhandler_base */ + +/* Record the file name. + Filenames are used mostly for debugging messages, and it's hoped that + in cases where the name is really required, the filename wouldn't ever + be too long (e.g. devices or some such). +*/ + +void +fhandler_base::set_name (const char *unix, const char *win32, int unit) +{ + if (!no_free_names ()) + { + if (unix_path_name_ != NULL && unix_path_name_ != fhandler_disk_dummy_name) + free (unix_path_name_); + if (win32_path_name_ != NULL && unix_path_name_ != fhandler_disk_dummy_name) + free (win32_path_name_); + } + + unix_path_name_ = win32_path_name_ = NULL; + if (unix == NULL || !*unix) + return; + + unix_path_name_ = strdup (unix); + if (unix_path_name_ == NULL) + { + system_printf ("fatal error. strdup failed"); + exit (ENOMEM); + } + + if (win32) + win32_path_name_ = strdup (win32); + else + { + const char *fmt = get_native_name (); + win32_path_name_ = (char *) malloc (strlen(fmt) + 16); + __small_sprintf (win32_path_name_, fmt, unit); + } + + if (win32_path_name_ == NULL) + { + system_printf ("fatal error. strdup failed"); + exit (ENOMEM); + } +} + +/* Normal file i/o handlers. */ + +/* Cover function to ReadFile to achieve (as much as possible) Posix style + semantics and use of errno. */ +int +fhandler_base::raw_read (void *ptr, size_t ulen) +{ + DWORD bytes_read; + + if (!ReadFile (get_handle(), ptr, ulen, &bytes_read, 0)) + { + int errcode; + + /* Some errors are not really errors. Detect such cases here. */ + + errcode = GetLastError (); + switch (errcode) + { + case ERROR_BROKEN_PIPE: + /* This is really EOF. */ + bytes_read = 0; + break; + case ERROR_MORE_DATA: + /* `bytes_read' is supposedly valid. */ + break; + default: + syscall_printf ("ReadFile %s failed, %E", unix_path_name_); + __seterrno_from_win_error (errcode); + return -1; + break; + } + } + + return bytes_read; +} + +int +fhandler_base::linearize (unsigned char *buf) +{ + unsigned char *orig_buf = buf; +#define cbuf ((char *)buf) + strcpy (cbuf, get_name() ?: ""); + char *p = strcpy (strchr (cbuf, '\0') + 1, get_win32_name ()); + buf = (unsigned char *)memcpy (strchr (p, '\0') + 1, this, cb); + debug_printf ("access_ %p, status %p, io_handle %p, output_handle %p", + access_, status, get_io_handle (), get_output_handle ()); + return (buf + cb) - orig_buf; +#undef cbuf +} + +int +fhandler_base::de_linearize (const char *buf, const char *unix_name, + const char *win32_name) +{ + int thiscb = cb; + memcpy(this, buf, cb); + unix_path_name_ = win32_path_name_ = NULL; + set_name (unix_name, win32_name); + debug_printf ("access_ %p, status %p, io_handle %p, output_handle %p", + access_, status, get_io_handle (), get_output_handle ()); + if (thiscb != cb) + system_printf ("mismatch in linearize/delinearize %d != %d", thiscb, cb); + raixput = raixget = ralen = rabuflen = 0; + rabuf = NULL; + return cb; +} + +/* Cover function to WriteFile to provide Posix interface and semantics + (as much as possible). */ +int +fhandler_base::raw_write (const void *ptr, size_t len) +{ + DWORD bytes_written; + + if (!WriteFile (get_handle(), ptr, len, &bytes_written, 0)) + { + if (GetLastError () == ERROR_DISK_FULL && bytes_written > 0) + return bytes_written; + __seterrno (); + if (get_errno () == EPIPE) + raise (SIGPIPE); + return -1; + } + return bytes_written; +} + +/* Open system call handler function. + Path is now already checked for symlinks */ +int +fhandler_base::open (int flags, mode_t mode) +{ + int res = 0; + HANDLE x; + int file_attributes; + int shared; + int creation_distribution; + + syscall_printf ("(%s, %p)", get_win32_name (), flags); + + set_flags (flags); + + if (get_win32_name () == NULL) + { + set_errno (ENOENT); + goto done; + } + + if (get_device () == FH_TAPE) + { + access_ = GENERIC_READ | GENERIC_WRITE; + } + else if ((flags & (O_RDONLY | O_WRONLY | O_RDWR)) == O_RDONLY) + { + access_ = GENERIC_READ; + } + else if ((flags & (O_RDONLY | O_WRONLY | O_RDWR)) == O_WRONLY) + { + access_ = GENERIC_WRITE; + } + else + { + access_ = GENERIC_READ | GENERIC_WRITE; + } + + /* FIXME: O_EXCL handling? */ + + if ((flags & O_TRUNC) && ((flags & O_ACCMODE) != O_RDONLY)) + { + if (flags & O_CREAT) + { + creation_distribution = CREATE_ALWAYS; + } + else + { + creation_distribution = TRUNCATE_EXISTING; + } + } + else if (flags & O_CREAT) + creation_distribution = OPEN_ALWAYS; + else + creation_distribution = OPEN_EXISTING; + + if ((flags & O_EXCL) && (flags & O_CREAT)) + { + creation_distribution = CREATE_NEW; + } + + if (flags & O_APPEND) + set_append_p(); + + /* These flags are host dependent. */ + shared = host_dependent.shared; + + file_attributes = FILE_ATTRIBUTE_NORMAL; + if (flags & O_DIROPEN) + file_attributes |= FILE_FLAG_BACKUP_SEMANTICS; + if (get_device () == FH_SERIAL) + file_attributes |= FILE_FLAG_OVERLAPPED; + + x = CreateFileA (get_win32_name (), access_, shared, + &sec_none, creation_distribution, + file_attributes, + 0); + + syscall_printf ("%d = CreateFileA (%s, %p, %p, %p, %p, %p, 0)", + x, + get_win32_name (), access_, shared, + &sec_none, creation_distribution, + file_attributes); + + if (x == INVALID_HANDLE_VALUE) + { + if (GetLastError () == ERROR_INVALID_HANDLE) + set_errno (ENOENT); + else + __seterrno (); + goto done; + } + + if (flags & O_CREAT && get_device () == FH_DISK) + set_file_attribute (has_acls (), get_win32_name (), mode); + + namehash_ = hash_path_name (0, get_win32_name ()); + set_io_handle (x); + rpos_ = 0; + rsize_ = -1; + int bin; + if (flags & (O_BINARY | O_TEXT)) + bin = flags & O_TEXT ? 0 : O_BINARY; + else if (get_device () == FH_DISK) + bin = get_w_binary () || get_r_binary (); + else + bin = (__fmode & O_BINARY) || get_w_binary () || get_r_binary (); + + set_r_binary (bin); + set_w_binary (bin); + syscall_printf ("filemode set to %s", bin ? "binary" : "text"); + + if (get_device () != FH_TAPE + && get_device () != FH_FLOPPY + && get_device () != FH_SERIAL) + { + if (flags & O_APPEND) + SetFilePointer (get_handle(), 0, 0, FILE_END); + else + SetFilePointer (get_handle(), 0, 0, FILE_BEGIN); + } + + res = 1; +done: + syscall_printf ("%d = fhandler_base::open (%s, %p)", res, get_win32_name (), + flags); + return res; +} + +/* states: + open buffer in binary mode? Just do the read. + + open buffer in text mode? Scan buffer for control zs and handle + the first one found. Then scan buffer, converting every \r\n into + an \n. If last char is an \r, look ahead one more char, if \n then + modify \r, if not, remember char. +*/ +int +fhandler_base::read (void *in_ptr, size_t in_len) +{ + int len = (int) in_len; + char *ctrlzpos; + char *ptr = (char *) in_ptr; + + int c; + int copied_chars = 0; + + while (len) + if ((c = get_readahead ()) < 0) + break; + else + { + ptr[copied_chars++] = (unsigned char) (c & 0xff); + len--; + } + + if (len) + { + int readlen = raw_read (ptr + copied_chars, len); + if (copied_chars == 0) + copied_chars = readlen; /* Propagate error or EOF */ + else if (readlen > 0) /* FIXME: should flag EOF for next read */ + copied_chars += readlen; + } + + if (copied_chars <= 0 || get_r_binary ()) + return copied_chars; + + /* Scan buffer for a control-z and shorten the buffer to that length */ + + ctrlzpos = (char *) memchr ((char *) ptr, 0x1a, copied_chars); + if (ctrlzpos) + { + lseek ((ctrlzpos - ((char *) ptr + copied_chars)), SEEK_CUR); + copied_chars = ctrlzpos - (char *) ptr; + } + + if (copied_chars == 0) + return 0; + + /* Scan buffer and turn \r\n into \n */ + register char *src= (char *) ptr; + register char *dst = (char *) ptr; + register char *end = src + copied_chars - 1; + + /* Read up to the last but one char - the last char needs special handling */ + while (src < end) + { + *dst = *src++; + if (*dst != '\r' || *src != '\n') + dst++; + } + + c = *src; + /* if last char is a '\r' then read one more to see if we should + translate this one too */ + if (c == '\r') + { + char c1 = 0; + len = raw_read (&c1, 1); + if (len <= 0) + /* nothing */; + else if (c1 == '\n') + c = '\n'; + else + set_readahead_valid (1, c1); + } + + *dst++ = c; + copied_chars = dst - (char *) ptr; + + rpos_ += copied_chars; + +#ifndef NOSTRACE + if (strace_active) + { + char buf[16 * 6 + 1]; + char *p = buf; + + for (int i = 0; i < copied_chars && i < 16; ++i) + { + unsigned char c = ((unsigned char *) ptr)[i]; + /* >= 33 so space prints in hex */ + __small_sprintf (p, c >= 33 && c <= 127 ? " %c" : " %p", c); + p += strlen (p); + } + debug_printf ("read %d bytes (%s%s)", copied_chars, buf, + copied_chars > 16 ? " ..." : ""); + } +#endif + + return copied_chars; +} + +int +fhandler_base::write (const void *ptr, size_t len) +{ + int res; + + if (get_append_p ()) + SetFilePointer (get_handle(), 0, 0, FILE_END); + else if (os_being_run != winNT && get_check_win95_lseek_bug ()) + { + /* Note: this bug doesn't happen on NT4, even though the documentation + for WriteFile() says that it *may* happen on any OS. */ + int actual_length, current_position; + set_check_win95_lseek_bug (0); /* don't do it again */ + actual_length = GetFileSize (get_handle (), NULL); + current_position = SetFilePointer (get_handle (), 0, 0, FILE_CURRENT); + if (current_position > actual_length) + { + /* Oops, this is the bug case - Win95 uses whatever is on the disk + instead of some known (safe) value, so we must seek back and + fill in the gap with zeros. - DJ */ + char zeros[512]; + int number_of_zeros_to_write = current_position - actual_length; + memset(zeros, 0, 512); + SetFilePointer (get_handle (), 0, 0, FILE_END); + while (number_of_zeros_to_write > 0) + { + DWORD zeros_this_time = (number_of_zeros_to_write > 512 + ? 512 : number_of_zeros_to_write); + DWORD written; + if (!WriteFile (get_handle (), zeros, zeros_this_time, &written, + NULL)) + { + __seterrno (); + if (get_errno () == EPIPE) + raise (SIGPIPE); + /* This might fail, but it's the best we can hope for */ + SetFilePointer (get_handle (), current_position, 0, FILE_BEGIN); + return -1; + + } + if (written < zeros_this_time) /* just in case */ + { + set_errno (ENOSPC); + /* This might fail, but it's the best we can hope for */ + SetFilePointer (get_handle (), current_position, 0, FILE_BEGIN); + return -1; + } + number_of_zeros_to_write -= written; + } + } + } + + if (get_w_binary ()) + { + res = raw_write (ptr, len); + } + else + { +#ifdef NOTDEF + /* Keep track of previous \rs, we don't want to turn existing + \r\n's into \r\n\n's */ + register int pr = 0; + + /* Copy things in chunks */ + char buf[CHUNK_SIZE]; + + for (unsigned int i = 0; i < len; i += sizeof (buf) / 2) + { + register const char *src = (char *)ptr + i; + int todo; + if ((todo = len - i) > sizeof (buf) / 2) + todo = sizeof (buf) / 2; + register const char *end = src + todo; + register char *dst = buf; + while (src < end) + { + if (*src == '\n' && !pr) + { + /* Emit a cr lf here */ + *dst ++ = '\r'; + *dst ++ = '\n'; + } + else if (*src == '\r') + { + *dst ++ = '\r'; + pr = 1; + } + else + { + *dst ++ = *src; + pr = 0; + } + src++; + } + int want = dst - buf; + if ((res = raw_write (buf, want)) != want) + { + if (res == -1) + return -1; + /* FIXME: */ + /* Tricky... Didn't write everything we wanted.. How can + we work out exactly which chars were sent? We don't... + This will only happen in pretty nasty circumstances. */ + rpos_ += i; + return i; + } + } +#else + /* This is the Microsoft/DJGPP way. Still not ideal, but it's + compatible. */ + + int left_in_data = len; + char *data = (char *)ptr; + + while (left_in_data > 0) + { + char buf[CHUNK_SIZE], *buf_ptr = buf; + int left_in_buf = CHUNK_SIZE; + + while (left_in_buf > 0 && left_in_data > 0) + { + if (*data == '\n') + { + if (left_in_buf == 1) + { + /* Not enough room for \r and \n */ + break; + } + *buf_ptr++ = '\r'; + left_in_buf--; + } + *buf_ptr++ = *data++; + left_in_buf--; + left_in_data--; + } + + /* We've got a buffer-full, or we're out of data. Write it out */ + int want = buf_ptr - buf; + if ((res = raw_write (buf, want)) != want) + { + if (res == -1) + return -1; + /* FIXME: */ + /* Tricky... Didn't write everything we wanted.. How can + we work out exactly which chars were sent? We don't... + This will only happen in pretty nasty circumstances. */ + int i = (len-left_in_data) - left_in_buf; + rpos_ += i; + /* just in case the math is off, guarantee it looks like + a disk full error */ + if (i >= (int)len) + i = len-1; + if (i < 0) + i = 0; + return i; + } + } +#endif + + /* Done everything, update by the chars that the user sent */ + rpos_ += len; + /* Length of file has changed */ + rsize_ = -1; + res = len; + debug_printf ("after write, name %s, rpos %d", unix_path_name_, rpos_); + } + return res; +} + +off_t +fhandler_base::lseek (off_t offset, int whence) +{ + off_t res; + + /* Seeks on text files is tough, we rewind and read till we get to the + right place. */ + + if (whence != SEEK_CUR || offset != 0) + { + if (whence == SEEK_CUR) + offset -= ralen - raixget; + set_readahead_valid (0); + } + + debug_printf ("lseek (%s, %d, %d)", unix_path_name_, offset, whence); + +#if 0 /* lseek has no business messing about with text-mode stuff */ + + if (!get_r_binary ()) + { + int newplace; + + if (whence == 0) + { + newplace = offset; + } + else if (whence ==1) + { + newplace = rpos + offset; + } + else + { + /* Seek from the end of a file.. */ + if (rsize == -1) + { + /* Find the size of the file by reading till the end */ + + char b[CHUNK_SIZE]; + while (read (b, sizeof (b)) > 0) + ; + rsize = rpos; + } + newplace = rsize + offset; + } + + if (rpos > newplace) + { + SetFilePointer (handle, 0, 0, 0); + rpos = 0; + } + + /* You can never shrink something more than 50% by turning CRLF into LF, + so we binary chop looking for the right place */ + + while (rpos < newplace) + { + char b[CHUNK_SIZE]; + size_t span = (newplace - rpos) / 2; + if (span == 0) + span = 1; + if (span > sizeof (b)) + span = sizeof (b); + + debug_printf ("lseek (%s, %d, %d) span %d, rpos %d newplace %d", + name, offset, whence,span,rpos, newplace); + read (b, span); + } + + debug_printf ("Returning %d", newplace); + return newplace; + } +#endif /* end of deleted code dealing with text mode */ + + DWORD win32_whence = whence == SEEK_SET ? FILE_BEGIN + : (whence == SEEK_CUR ? FILE_CURRENT : FILE_END); + + res = SetFilePointer (get_handle(), offset, 0, win32_whence); + if (res == -1) + { + __seterrno (); + } + else + { + /* When next we write(), we will check to see if *this* seek went beyond + the end of the file, and back-seek and fill with zeros if so - DJ */ + set_check_win95_lseek_bug (); + + /* If this was a SEEK_CUR with offset 0, we still might have + readahead that we have to take into account when calculating + the actual position for the application. */ + if (whence == SEEK_CUR) + res -= ralen - raixget; + } + + return res; +} + +int +fhandler_base::close (void) +{ + int res = -1; + + syscall_printf ("handle %p", get_handle()); + if (CloseHandle (get_handle())) + res = 0; + else + { + paranoid_printf ("CloseHandle (%d <%s>) failed", get_handle(), + get_name ()); + + __seterrno (); + } + return res; +} + +int +fhandler_base::ioctl (unsigned int cmd, void *buf) +{ + if (cmd == FIONBIO) + syscall_printf ("ioctl (FIONBIO, %p)", buf); + else + syscall_printf ("ioctl (%x, %p)", cmd, buf); + + set_errno (EINVAL); + return -1; +} + +int +fhandler_base::lock (int, struct flock *) +{ + set_errno (ENOSYS); + return -1; +} + +int +fhandler_base::fstat (struct stat *buf) +{ + return stat_dev (get_device (), get_unit (), get_namehash (), buf); + return 0; +} + +extern "C" char * __stdcall +rootdir(char *full_path) +{ + /* Possible choices: + * d:... -> d:/ + * \\server\share... -> \\server\share\ + * else current drive. + */ + char *root=full_path; + + if (full_path[1] == ':') + strcpy (full_path + 2, "\\"); + else if (full_path[0] == '\\' && full_path[1] == '\\') + { + char *cp = full_path + 2; + while (*cp && *cp != '\\') + cp++; + if (!*cp) + { + set_errno (ENOTDIR); + return NULL; + } + cp++; + while (*cp && *cp != '\\') + cp++; + strcpy (cp, "\\"); + } + else + root = NULL; + + return root; +} + +int +fhandler_disk_file::fstat (struct stat *buf) +{ + int res = 0; // avoid a compiler warning + BY_HANDLE_FILE_INFORMATION local; + int old_errno = get_errno (); + + memset (buf, 0, sizeof (*buf)); + + if (is_device ()) + return stat_dev (get_device (), get_unit (), get_namehash (), buf); + + /* NT 3.51 seems to have a bug when attempting to get vol serial + numbers. This loop gets around this. */ + for (int i = 0; i < 2; i++) + { + if (!(res = GetFileInformationByHandle (get_handle (), &local))) + break; + if (local.dwVolumeSerialNumber && (long) local.dwVolumeSerialNumber != -1) + break; + } + debug_printf ("%d = GetFileInformationByHandle (%s, %d)", + res, get_win32_name (), get_handle ()); + if (res == 0) + { + /* GetFileInformationByHandle will fail if it's given stdin/out/err + or a pipe*/ + DWORD lsize, hsize; + + if (GetFileType (get_handle ()) != FILE_TYPE_DISK) + buf->st_mode = S_IFCHR; + + lsize = GetFileSize (get_handle (), &hsize); + if (lsize == 0xffffffff && GetLastError () != NO_ERROR) + buf->st_mode = S_IFCHR; + else + buf->st_size = lsize; + /* We expect these to fail! */ + buf->st_mode |= STD_RBITS | STD_WBITS; + buf->st_blksize = S_BLKSIZE; + buf->st_ino = get_namehash (); + syscall_printf ("0 = fstat (, %p)", buf); + return 0; + } + + if (!get_win32_name ()) + { + set_errno (ENOENT); + return -1; + } + + set_errno (old_errno); + + buf->st_atime = to_time_t (&local.ftLastAccessTime); + buf->st_mtime = to_time_t (&local.ftLastWriteTime); + buf->st_ctime = to_time_t (&local.ftCreationTime); + buf->st_nlink = local.nNumberOfLinks; + buf->st_dev = local.dwVolumeSerialNumber; + buf->st_size = local.nFileSizeLow; + + /* Allocate some place to determine the root directory. */ + char root[strlen (get_win32_name ()) + 1]; + strcpy (root, get_win32_name ()); + + /* Assume that if a drive has ACL support it MAY have valid "inodes". + It definitely does not have valid inodes if it does not have ACL + support. */ + switch (has_acls () ? GetDriveType (rootdir (root)) : DRIVE_UNKNOWN) + { + case DRIVE_FIXED: + case DRIVE_REMOVABLE: + case DRIVE_CDROM: + case DRIVE_RAMDISK: + /* Although the documentation indicates otherwise, it seems like + "inodes" on these devices are persistent, at least across reboots. */ + buf->st_ino = local.nFileIndexHigh | local.nFileIndexLow; + break; + default: + /* Either the nFileIndex* fields are unreliable or unavailable. Use the + next best alternative. */ + buf->st_ino = get_namehash (); + break; + } + + buf->st_blksize = S_BLKSIZE; + buf->st_blocks = (buf->st_size + S_BLKSIZE-1) / S_BLKSIZE; + buf->st_uid = get_file_owner (has_acls (), get_win32_name ()); + buf->st_gid = get_file_group (has_acls (), get_win32_name ()); + + /* Using a side effect: get_file_attibutes checks for + directory. This is used, to set S_ISVTX, if needed. */ + if (local.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + buf->st_mode |= S_IFDIR; + if (! get_file_attribute (has_acls (), get_win32_name (), &buf->st_mode)) + { + buf->st_mode &= ~S_IFMT; + if (get_symlink_p ()) + buf->st_mode |= S_IFLNK; + else if (get_socket_p ()) + buf->st_mode |= S_IFSOCK; + else if (local.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + buf->st_mode |= S_IFDIR; + else + buf->st_mode |= S_IFREG; + } + else + { + buf->st_mode = 0; + buf->st_mode |= STD_RBITS; + + if (! (local.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) + buf->st_mode |= STD_WBITS; + /* | S_IWGRP | S_IWOTH; we don't give write to group etc */ + + if (get_symlink_p ()) + buf->st_mode |= S_IFLNK; + else if (get_socket_p ()) + buf->st_mode |= S_IFSOCK; + else + switch (GetFileType (get_handle ())) + { + case FILE_TYPE_CHAR: + case FILE_TYPE_UNKNOWN: + buf->st_mode |= S_IFCHR; + break; + case FILE_TYPE_DISK: + if (local.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + buf->st_mode |= S_IFDIR | STD_XBITS; + else + { + buf->st_mode |= S_IFREG; + if (get_execable_p ()) + buf->st_mode |= STD_XBITS; + } + break; + case FILE_TYPE_PIPE: + buf->st_mode |= S_IFSOCK; + break; + } + } + + syscall_printf ("0 = fstat (, %p) st_atime=%x st_size=%d, st_mode=%p, st_ino=%d, sizeof=%d", + buf, buf->st_atime, buf->st_size, buf->st_mode, + (int) buf->st_ino, sizeof (*buf)); + + return 0; +} + +void +fhandler_base::init (HANDLE f, DWORD a, mode_t bin) +{ + set_io_handle (f); + set_r_binary (bin); + set_w_binary (bin); + access_ = a; + a &= GENERIC_READ | GENERIC_WRITE; + if (a == GENERIC_READ) + set_flags (O_RDONLY); + if (a == GENERIC_WRITE) + set_flags (O_WRONLY); + if (a == (GENERIC_READ | GENERIC_WRITE)) + set_flags (O_RDWR); + debug_printf ("created new fhandler_base for handle %p", f); +} + +void +fhandler_base::dump (void) +{ + paranoid_printf ("here"); +} + +void +fhandler_base::set_io_handle (HANDLE x) +{ + debug_printf ("set handle to %p", x); + io_handle = x; +} + +int +fhandler_base::dup (fhandler_base *child) +{ + debug_printf ("in fhandler_base dup"); + + HANDLE nh; + if (!DuplicateHandle (hMainProc, get_handle(), hMainProc, &nh, 0, TRUE, + DUPLICATE_SAME_ACCESS)) + { + system_printf ("dup(%s) failed, handle %x, %E", + get_name (), get_handle()); + __seterrno (); + return -1; + } + + child->set_io_handle (nh); + return 0; +} + +/* Base terminal handlers. These just return errors. */ + +int +fhandler_base::tcflush (int queue) +{ + set_errno (ENOTTY); + return -1; +} + +int +fhandler_base::tcsendbreak (int duration) +{ + set_errno (ENOTTY); + return -1; +} + +int +fhandler_base::tcdrain (void) +{ + set_errno (ENOTTY); + return -1; +} + +int +fhandler_base::tcflow (int action) +{ + set_errno (ENOTTY); + return -1; +} + +int +fhandler_base::tcsetattr (int a, const struct termios *t) +{ + set_errno (ENOTTY); + return -1; +} + +int +fhandler_base::tcgetattr (struct termios *t) +{ + set_errno (ENOTTY); + return -1; +} + +int +fhandler_base::tcsetpgrp (const pid_t pid) +{ + set_errno (ENOTTY); + return -1; +} + +int +fhandler_base::tcgetpgrp (void) +{ + set_errno (ENOTTY); + return -1; +} + +/* Normal I/O constructor */ +fhandler_base::fhandler_base (DWORD devtype, const char *name, int unit): + access_ (0), + io_handle (NULL), + rpos_ (0), + rsize_ (0), + namehash_ (0), + openflags_ (0), + rabuf (NULL), + ralen (0), + raixget (0), + raixput (0), + rabuflen (0) +{ + status = devtype; + int bin = __fmode & O_TEXT ? 0 : 1; + if (status != FH_DISK && status != FH_CONSOLE) + { + if (!get_r_binset ()) + set_r_binary (bin); + if (!get_w_binset ()) + set_w_binary (bin); + } + unix_path_name_ = win32_path_name_ = NULL; + set_name (name, NULL, unit); +} + +/* Normal I/O destructor */ +fhandler_base::~fhandler_base (void) +{ + if (!no_free_names ()) + { + if (unix_path_name_ != NULL && unix_path_name_ != fhandler_disk_dummy_name) + free (unix_path_name_); + if (win32_path_name_ != NULL && win32_path_name_ != fhandler_disk_dummy_name) + free (win32_path_name_); + } + unix_path_name_ = win32_path_name_ = NULL; +} + +/**********************************************************************/ +/* fhandler_disk_file */ + +fhandler_disk_file::fhandler_disk_file (const char *name) : + fhandler_base (FH_DISK, name) +{ + set_cb (sizeof *this); + set_no_free_names (); + unix_path_name_ = win32_path_name_ = fhandler_disk_dummy_name; +} + +int +fhandler_disk_file::open (const char *path, int flags, mode_t mode) +{ + syscall_printf ("(%s, %p)", path, flags); + + /* O_NOSYMLINK is an internal flag for implementing lstat, nothing more. */ + path_conv real_path (path, (flags & O_NOSYMLINK) ? SYMLINK_NOFOLLOW:SYMLINK_FOLLOW); + + if (real_path.error && + (flags & O_NOSYMLINK || real_path.error != ENOENT || !(flags & O_CREAT))) + { + set_errno (real_path.error); + syscall_printf ("0 = fhandler_disk_file::open (%s, %p)", path, flags); + return 0; + } + + set_name (path, real_path.get_win32 ()); + set_no_free_names (0); + return open (real_path, flags, mode); +} + +int +fhandler_disk_file::open (path_conv& real_path, int flags, mode_t mode) +{ + if (get_win32_name () == fhandler_disk_dummy_name) + { + win32_path_name_ = real_path.get_win32 (); + set_no_free_names (); + } + /* If necessary, do various other things to see if path is a program. */ + if (!real_path.isexec ()) + real_path.set_exec (check_execable_p (get_win32_name ())); + + if (real_path.isbinary ()) + { + set_r_binary (1); + set_w_binary (1); + } + + set_has_acls (real_path.has_acls ()); + + int res = this->fhandler_base::open (flags, mode); + + if (!res) + goto out; + + extern BOOL allow_ntea; + + if (!real_path.isexec () && !allow_ntea && + GetFileType (get_handle ()) == FILE_TYPE_DISK) + { + DWORD done; + char magic[3]; + /* FIXME should we use /etc/magic ? */ + magic[0] = magic[1] = magic[2] = '\0'; + ReadFile (get_handle (), magic, 3, &done, 0); + if ((magic[0] == ':' && magic[1] == '\n') || + (magic[0] == '#' && magic[1] == '!')) + real_path.set_exec (); + if (!(flags & O_APPEND)) + SetFilePointer (get_handle(), 0, 0, FILE_BEGIN); + } + + if (flags & O_APPEND) + SetFilePointer (get_handle(), 0, 0, FILE_END); + + set_symlink_p (real_path.issymlink ()); + set_execable_p (real_path.isexec ()); + set_socket_p (real_path.issocket ()); + +out: + syscall_printf ("%d = fhandler_disk_file::open (%s, %p)", res, + get_win32_name (), flags); + return res; +} + +int +fhandler_disk_file::close () +{ + int res; + if ((res = this->fhandler_base::close ()) == 0) + cygwin_shared->delqueue.process_queue (); + return res; +} + +/* + * FIXME !!! + * The correct way to do this to get POSIX locking + * semantics is to keep a linked list of posix lock + * requests and map them into Win32 locks. The problem + * is that Win32 does not deal correctly with overlapping + * lock requests. Also another pain is that Win95 doesn't do + * non-blocking or non exclusive locks at all. For '95 just + * convert all lock requests into blocking,exclusive locks. + * This shouldn't break many apps but denying all locking + * would. + * For now just convert to Win32 locks and hope for the best. + */ + +int +fhandler_disk_file::lock (int cmd, struct flock *fl) +{ + DWORD win32_start; + DWORD win32_len; + DWORD win32_upper; + DWORD startpos; + + /* + * We don't do getlck calls yet. + */ + + if (cmd == F_GETLK) + { + set_errno (ENOSYS); + return -1; + } + + /* + * Calculate where in the file to start from, + * then adjust this by fl->l_start. + */ + + switch (fl->l_whence) + { + case SEEK_SET: + startpos = 0; + break; + case SEEK_CUR: + if ((startpos = lseek (0, SEEK_CUR)) < 0) + return -1; + break; + case SEEK_END: + { + BY_HANDLE_FILE_INFORMATION finfo; + if (GetFileInformationByHandle (get_handle(), &finfo) == 0) + { + __seterrno (); + return -1; + } + startpos = finfo.nFileSizeLow; /* Nowhere to keep high word */ + break; + } + default: + set_errno (EINVAL); + return -1; + } + + /* + * Now the fun starts. Adjust the start and length + * fields until they make sense. + */ + + win32_start = startpos + fl->l_start; + if (fl->l_len < 0) + { + win32_start -= fl->l_len; + win32_len = -fl->l_len; + } + else + win32_len = fl->l_len; + + if (win32_start < 0) + { + win32_len -= win32_start; + if (win32_len <= 0) + { + /* Failure ! */ + set_errno (EINVAL); + return -1; + } + win32_start = 0; + } + + /* + * Special case if len == 0 for POSIX means lock + * to the end of the entire file (and all future extensions). + */ + if (win32_len == 0) + { + win32_len = 0xffffffff; + win32_upper = host_dependent.win32_upper; + } + else + win32_upper = 0; + + BOOL res; + + if (os_being_run == winNT) + { + DWORD lock_flags = (cmd == F_SETLK) ? LOCKFILE_FAIL_IMMEDIATELY : 0; + lock_flags |= (fl->l_type == F_WRLCK) ? LOCKFILE_EXCLUSIVE_LOCK : 0; + + OVERLAPPED ov; + + ov.Internal = 0; + ov.InternalHigh = 0; + ov.Offset = win32_start; + ov.OffsetHigh = 0; + ov.hEvent = (HANDLE) 0; + + if (fl->l_type == F_UNLCK) + { + res = UnlockFileEx (get_handle (), 0, win32_len, win32_upper, &ov); + } + else + { + res = LockFileEx (get_handle (), lock_flags, 0, win32_len, + win32_upper, &ov); + /* Deal with the fail immediately case. */ + /* + * FIXME !! I think this is the right error to check for + * but I must admit I haven't checked.... + */ + if ((res == 0) && (lock_flags & LOCKFILE_FAIL_IMMEDIATELY) && + (GetLastError () == ERROR_LOCK_FAILED)) + { + set_errno (EAGAIN); + return -1; + } + } + } + else + { + /* Windows 95 -- use primitive lock call */ + if (fl->l_type == F_UNLCK) + res = UnlockFile (get_handle (), win32_start, 0, win32_len, + win32_upper); + else + res = LockFile (get_handle (), win32_start, 0, win32_len, win32_upper); + } + + if (res == 0) + { + __seterrno (); + return -1; + } + + return 0; +} + +/* Perform various heuristics on PATH to see if it's a program. */ + +int +fhandler_disk_file::check_execable_p (const char *path) +{ + int len = strlen (path); + const char *ch = path + (len > 4 ? len - 4 : len); + + if (strcasematch (".exe", ch) + || strcasematch (".bat", ch) + || strcasematch (".com", ch)) + return 1; + return 0; +} + +/**********************************************************************/ +/* /dev/null */ + +fhandler_dev_null::fhandler_dev_null (const char *name) : + fhandler_base (FH_NULL, name) +{ + set_cb (sizeof *this); +} + +void +fhandler_dev_null::dump (void) +{ + paranoid_printf ("here"); +} + +/**********************************************************************/ +/* fhandler_pipe */ + +fhandler_pipe::fhandler_pipe (const char *name) : + fhandler_base (FH_PIPE, name) +{ + set_cb (sizeof *this); +} + +off_t +fhandler_pipe::lseek (off_t offset, int whence) +{ + debug_printf ("(%d, %d)", offset, whence); + set_errno (ESPIPE); + return -1; +} + +void __stdcall +set_inheritance (HANDLE &h, int not_inheriting, const char *name) +{ + HANDLE newh; + + if (!DuplicateHandle (hMainProc, h, hMainProc, &newh, 0, !not_inheriting, + DUPLICATE_SAME_ACCESS)) + debug_printf ("DuplicateHandle %E"); +#ifndef DEBUGGING + else + { + CloseHandle (h); + h = newh; + } +#else + else if (!name) + { + CloseHandle (h); + h = newh; + } + else + { + ForceCloseHandle2 (h, name); + h = newh; + ProtectHandle2 (h, name); + } +#endif +} + +void +fhandler_base::fork_fixup (HANDLE parent, HANDLE &h, const char *name) +{ + if (!DuplicateHandle (parent, h, hMainProc, &h, 0, !get_close_on_exec (), + DUPLICATE_SAME_ACCESS)) + system_printf ("%s - %E, handle %s<%p>", get_name (), name, h); +} + +void +fhandler_base::set_close_on_exec (int val) +{ + set_inheritance (io_handle, val); + set_close_on_exec_flag (val); + debug_printf ("set close_on_exec for %s to %d", get_name (), val); +} + +void +fhandler_base::fixup_after_fork (HANDLE parent) +{ + debug_printf ("inheriting '%s' from parent", get_name ()); + fork_fixup (parent, io_handle, "io_handle"); +} diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h new file mode 100644 index 000000000..cf1924809 --- /dev/null +++ b/winsup/cygwin/fhandler.h @@ -0,0 +1,804 @@ +/* fhandler.h + + Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#ifndef _FHANDLER_H_ +#define _FHANDLER_H_ + +#include + +/* Classes + + Code is located in fhandler.cc unless another file name is given. + + fhandler_base normal I/O + + fhandler_disk_file + fhandler_serial Adds vmin and vtime. + fhandler_dev_null Not really I/O + fhandler_dev_zero Faked + + fhandler_dev_raw (fhandler_raw.cc) + fhandler_dev_floppy (fhandler_floppy.cc) + fhandler_dev_tape (fhandler_tape.cc) + + fhandler_pipe + fhandler_socket (net.cc) + + fhandler_tty_slave (tty.cc) + fhandler_pty_master (tty.cc) + fhandler_tty_master (tty.cc) + + fhandler_console Out with ansi control. (console.cc) + + fhandler_windows Windows messages I/O (fhandler_windows.cc) + + fhandler_proc Interesting possibility, not implemented yet +*/ + +enum +{ + FH_RBINARY = 0x00001000, /* binary read mode */ + FH_WBINARY = 0x00002000, /* binary write mode */ + FH_CLOEXEC = 0x00004000, /* close-on-exec */ + FH_RBINSET = 0x00008000, /* binary read mode has been explicitly set */ + FH_WBINSET = 0x00010000, /* binary write mode has been explicitly set */ + FH_APPEND = 0x00020000, /* always append */ + FH_ASYNC = 0x00040000, /* async I/O */ + FH_HADEOF = 0x00080000, /* EOF seen */ + + FH_SYMLINK = 0x00100000, /* is a symlink */ + FH_EXECABL = 0x00200000, /* file looked like it would run: + * ends in .exe or .bat or begins with #! */ + FH_W95LSBUG= 0x00400000, /* set when lseek is called as a flag that + * _write should check if we've moved beyond + * EOF, zero filling if so. */ + FH_NOFRNAME= 0x00800000, /* Set if shouldn't free unix_path_name_ and + windows_path_name_ on destruction. */ + FH_NOEINTR = 0x01000000, /* Set if I/O should be uninterruptible. */ + FH_FFIXUP = 0x02000000, /* Set if need to fixup after fork. */ + FH_LOCAL = 0x04000000, /* File is unix domain socket */ + FH_FIFO = 0x08000000, /* File is FIFO */ + FH_HASACLS = 0x40000000, /* True if fs of file has ACLS */ + + /* Device flags */ + + /* Slow devices */ + FH_CONSOLE = 0x00000001, /* is a console */ + FH_CONIN = 0x00000002, /* console input */ + FH_CONOUT = 0x00000003, /* console output */ + FH_TTYM = 0x00000004, /* is a tty master */ + FH_TTYS = 0x00000005, /* is a tty slave */ + FH_PTYM = 0x00000006, /* is a pty master */ + FH_SERIAL = 0x00000007, /* is a serial port */ + FH_PIPE = 0x00000008, /* is a pipe */ + FH_PIPER = 0x00000009, /* read end of a pipe */ + FH_PIPEW = 0x0000000a, /* write end of a pipe */ + FH_SOCKET = 0x0000000b, /* is a socket */ + FH_WINDOWS = 0x0000000c, /* is a window */ + + FH_SLOW = 0x00000010, /* "slow" device if below this */ + + /* Fast devices */ + FH_DISK = 0x00000010, /* is a disk */ + FH_FLOPPY = 0x00000011, /* is a floppy */ + FH_TAPE = 0x00000012, /* is a tape */ + FH_NULL = 0x00000013, /* is the null device */ + FH_ZERO = 0x00000014, /* is the zero device */ + + FH_NDEV = 0x00000015, /* Maximum number of devices */ + FH_DEVMASK = 0x00000fff, /* devices live here */ + FH_BAD = 0xffffffff +}; + +#define FHDEVN(n) ((n) & FH_DEVMASK) +#define FHISSETF(x) __ISSETF (this, x, FH) +#define FHSETF(x) __SETF (this, x, FH) +#define FHCLEARF(x) __CLEARF (this, x, FH) +#define FHCONDSETF(n, x) __CONDSETF(n, this, x, FH) + +#define FHSTATOFF 0 + +extern const char *windows_device_names[]; +#define __fmode (*(user_data->fmode_ptr)) + +class select_record; +class path_conv; +class fhandler_disk_file; + +class fhandler_base +{ +private: + DWORD status; +public: + int cb; +private: + int access_; + HANDLE io_handle; + + int rpos_; /* Used in text reading */ + int rsize_; + + unsigned long namehash_; /* hashed filename, used as inode num */ + + /* Full unix path name of this file */ + /* File open flags from open () and fcntl () calls */ + int openflags_; + +protected: + char *rabuf; /* used for crlf conversion in text files */ + size_t ralen; + size_t raixget; + size_t raixput; + size_t rabuflen; + + char *unix_path_name_; + char *win32_path_name_; + +public: + void set_name (const char *unix, const char *win32 = NULL, int unit = 0); + + virtual fhandler_base& operator =(fhandler_base &x) + { + memcpy (this, &x, sizeof *this); + unix_path_name_ = x.unix_path_name_ ? strdup (x.unix_path_name_) : NULL; + win32_path_name_ = x.win32_path_name_ ? strdup (x.win32_path_name_) : NULL; + return *this; + }; + fhandler_base (DWORD dev, const char *name = 0, int unit = 0); + virtual ~fhandler_base (); + + /* Non-virtual simple accessor functions. */ + void set_io_handle (HANDLE); + + void set_cb (size_t size) { cb = size; } + DWORD get_device () { return status & FH_DEVMASK; } + virtual int get_unit () { return 0; } + virtual BOOL is_slow () { return get_device () < FH_SLOW; } + + int get_access () { return access_; } + void set_access (int x) { access_ = x; } + + int get_async () { return FHISSETF (ASYNC); } + void set_async (int x) { FHCONDSETF (x, ASYNC); } + + int get_flags () { return openflags_; } + void set_flags (int x) { openflags_ = x; } + + int get_w_binary () { return FHISSETF (WBINARY); } + int get_r_binary () { return FHISSETF (RBINARY); } + + int get_w_binset () { return FHISSETF (WBINSET); } + int get_r_binset () { return FHISSETF (RBINSET); } + + void set_w_binary (int b) { FHCONDSETF (b, WBINARY); FHSETF (WBINSET); } + void set_r_binary (int b) { FHCONDSETF (b, RBINARY); FHSETF (RBINSET); } + + int get_r_no_interrupt () { return FHISSETF (NOEINTR); } + void set_r_no_interrupt (int b) { FHCONDSETF (b, NOEINTR); } + + int get_close_on_exec () { return FHISSETF (CLOEXEC); } + int set_close_on_exec_flag (int b) { return FHCONDSETF (b, CLOEXEC); } + + void set_check_win95_lseek_bug (int b = 1) { FHCONDSETF (b, W95LSBUG); } + int get_check_win95_lseek_bug () { return FHISSETF (W95LSBUG); } + + int get_need_fork_fixup () { return FHISSETF (FFIXUP); } + void set_need_fork_fixup () { FHSETF (FFIXUP); } + + virtual void set_close_on_exec (int val); + virtual void fixup_after_fork (HANDLE parent); + + int get_symlink_p () { return FHISSETF (SYMLINK); } + void set_symlink_p (int val) { FHCONDSETF (val, SYMLINK); } + void set_symlink_p () { FHSETF (SYMLINK); } + + int get_socket_p () { return FHISSETF (LOCAL); } + void set_socket_p (int val) { FHCONDSETF (val, LOCAL); } + void set_socket_p () { FHSETF (LOCAL); } + + int get_execable_p () { return FHISSETF (EXECABL); } + void set_execable_p (int val) { FHCONDSETF (val, EXECABL); } + void set_execable_p () { FHSETF (EXECABL); } + + int get_append_p () { return FHISSETF (APPEND); } + void set_append_p (int val) { FHCONDSETF (val, APPEND); } + void set_append_p () { FHSETF (APPEND); } + + int get_readahead_valid () { return raixget < ralen; } + int puts_readahead (const char *s, size_t len = (size_t) -1); + int put_readahead (char value); + + int get_readahead (); + int peek_readahead (int queryput = 0); + + int eat_readahead (int n); + + void set_readahead_valid (int val, int ch = -1); + + int has_acls () { return FHISSETF (HASACLS); } + void set_has_acls (int val) { FHCONDSETF (val, HASACLS); } + + int no_free_names () { return FHISSETF (NOFRNAME); } + void set_no_free_names (int val) { FHCONDSETF (val, NOFRNAME); } + void set_no_free_names () { FHSETF (NOFRNAME); } + + const char *get_name () { return unix_path_name_; } + const char *get_win32_name () { return win32_path_name_; } + unsigned long get_namehash () { return namehash_; } + + + /* fixup fd possibly non-inherited handles after fork */ + void fork_fixup (HANDLE parent, HANDLE &h, const char *name); + + /* Potentially overridden virtual functions. */ + virtual int open (const char *, int flags, mode_t mode = 0) + { + return open (flags, mode); + } + virtual int open (int flags, mode_t mode = 0); + virtual int close (); + virtual int fstat (struct stat *buf); + virtual int ioctl (unsigned int cmd, void *); + virtual char const * ttyname () { return get_name(); } + virtual int read (void *ptr, size_t len); + virtual int write (const void *ptr, size_t len); + virtual off_t lseek (off_t offset, int whence); + virtual int lock (int, struct flock *); + virtual void dump (); + virtual int dup (fhandler_base *child); + + void *operator new (size_t, void *p) {return p;} + + virtual void init (HANDLE, DWORD, mode_t); + + virtual int tcflush (int); + virtual int tcsendbreak (int); + virtual int tcdrain (); + virtual int tcflow (int); + virtual int tcsetattr (int a, const struct termios *t); + virtual int tcgetattr (struct termios *t); + virtual int tcsetpgrp (const pid_t pid); + virtual int tcgetpgrp (); + virtual int is_tty () { return 0; } + virtual BOOL is_device () { return TRUE; } + virtual char *ptsname () { return NULL;} + virtual class fhandler_socket *is_socket () { return 0; } + virtual class fhandler_console *is_console () { return 0; } + virtual int is_windows () {return 0; } + + virtual int raw_read (void *ptr, size_t ulen); + virtual int raw_write (const void *ptr, size_t ulen); + + /* Function to save state of a fhandler_base into memory. */ + virtual int linearize (unsigned char *); + /* Function to de-linearize into a fd */ + virtual int de_linearize (const char *, const char *, const char *); + + /* Virtual accessor functions to hide the fact + that some fd's have two handles. */ + virtual HANDLE get_handle () const { return io_handle; } + virtual HANDLE get_io_handle () const { return io_handle; } + virtual HANDLE get_output_handle () const { return io_handle; } + virtual BOOL hit_eof () {return FALSE;} + virtual select_record *select_read (select_record *s); + virtual select_record *select_write (select_record *s); + virtual select_record *select_except (select_record *s); + virtual int ready_for_read (int fd, DWORD howlong, int ignra); + virtual const char * get_native_name () + { + return windows_device_names[FHDEVN (status)]; + } + virtual int bg_check (int, int x = 0) {return 1;} +}; + +class fhandler_socket: public fhandler_base +{ +private: + int addr_family; +public: + fhandler_socket (const char *name = 0); + fhandler_socket (unsigned int, const char *name = 0); + ~fhandler_socket (); + int get_socket () const { return (int) get_handle(); } + fhandler_socket * is_socket () { return this; } + int write (const void *ptr, size_t len); + int read (void *ptr, size_t len); + int ioctl (unsigned int cmd, void *); + off_t lseek (off_t offset, int whence) { return 0; } + int close (); + + select_record *select_read (select_record *s); + select_record *select_write (select_record *s); + select_record *select_except (select_record *s); + int ready_for_read (int fd, DWORD howlong, int ignra); + int get_addr_family () {return addr_family;} + void set_addr_family (int af) {addr_family = af;} +}; + +class fhandler_pipe: public fhandler_base +{ +public: + fhandler_pipe (const char *name = 0); + off_t lseek (off_t offset, int whence); + /* This strange test is due to the fact that we can't rely on + Windows shells to "do the right thing" with pipes. Apparently + the can keep one end of the pipe open when it shouldn't be. */ + BOOL is_slow () {return os_being_run == winNT;} + select_record *select_read (select_record *s); + select_record *select_write (select_record *s); + select_record *select_except (select_record *s); + int ready_for_read (int fd, DWORD howlong, int ignra); +}; + +class fhandler_dev_raw: public fhandler_base +{ +protected: + char *devbuf; + size_t devbufsiz; + size_t devbufstart; + size_t devbufend; + int eom_detected : 1; + int eof_detected : 1; + int lastblk_to_read : 1; + int is_writing : 1; + int has_written : 1; + int unit; + + virtual void clear (void); + virtual int writebuf (void); + + /* returns not null, if `win_error' determines an end of media condition */ + virtual int is_eom(int win_error) = 0; + /* returns not null, if `win_error' determines an end of file condition */ + virtual int is_eof(int win_error) = 0; + + fhandler_dev_raw (DWORD dev, const char *name, int unit); + +public: + ~fhandler_dev_raw (void); + + /* Function to de-linearize into a fd */ + int de_linearize (const char *, const char *, const char *); + + int open (const char *path, int flags, mode_t mode = 0); + int close (void); + + int raw_read (void *ptr, size_t ulen); + int raw_write (const void *ptr, size_t ulen); + + int fstat (struct stat *buf); + + int dup (fhandler_base *child); + + int ioctl (unsigned int cmd, void *buf); +}; + +class fhandler_dev_floppy: public fhandler_dev_raw +{ +protected: + virtual int is_eom (int win_error); + virtual int is_eof (int win_error); + +public: + fhandler_dev_floppy (const char *name, int unit); + + virtual int open (const char *path, int flags, mode_t mode = 0); + virtual int close (void); + + virtual off_t lseek (off_t offset, int whence); + + virtual int ioctl (unsigned int cmd, void *buf); +}; + +class fhandler_dev_tape: public fhandler_dev_raw +{ + int norewind; + int lasterr; + +protected: + virtual void clear (void); + + virtual int is_eom (int win_error); + virtual int is_eof (int win_error); + +public: + fhandler_dev_tape (const char *name, int unit); + + virtual int open (const char *path, int flags, mode_t mode = 0); + virtual int close (void); + + virtual off_t lseek (off_t offset, int whence); + + virtual int fstat (struct stat *buf); + + virtual int dup (fhandler_base *child); + + virtual int ioctl (unsigned int cmd, void *buf); + +private: + int tape_write_marks (int marktype, DWORD len); + int tape_get_pos (unsigned long *ret); + int tape_set_pos (int mode, long count, BOOLEAN sfm_func = FALSE); + int tape_erase (int mode); + int tape_prepare (int action); + BOOLEAN tape_get_feature (DWORD parm); + int tape_get_blocksize (long *min, long *def, long *max, long *cur); + int tape_set_blocksize (long count); + int tape_status (struct mtget *get); + int tape_compression (long count); +}; + +/* Standard disk file */ + +class fhandler_disk_file: public fhandler_base +{ +private: + int check_execable_p (const char *path); + +public: + fhandler_disk_file (const char *name); + + int open (const char *path, int flags, mode_t mode = 0); + int open (path_conv& real_path, int flags, mode_t mode); + int close (); + int lock (int, struct flock *); + BOOL is_device () { return FALSE; } + int fstat (struct stat *buf); +}; + +class fhandler_serial: public fhandler_base +{ +private: + unsigned int vmin_; /* from termios */ + unsigned int vtime_; /* from termios */ + pid_t pgrp_; + +public: + int overlapped_armed; + OVERLAPPED io_status; + + /* Constructor */ + fhandler_serial (const char *name, DWORD devtype = FH_SERIAL, int unit = 0); + + int open (const char *path, int flags, mode_t mode); + int close (); + void init (HANDLE h, DWORD a, mode_t flags); + void overlapped_setup (); + int dup (fhandler_base *child); + int raw_read (void *ptr, size_t ulen); + int raw_write (const void *ptr, size_t ulen); + int tcsendbreak (int); + int tcdrain (); + int tcflow (int); + int tcsetattr (int a, const struct termios *t); + int tcgetattr (struct termios *t); + off_t lseek (off_t offset, int whence) { return 0; } + int tcflush (int); + void dump (); + int is_tty () { return 1; } + void fixup_after_fork (HANDLE parent); + int de_linearize (const char *, const char *, const char *); + + /* We maintain a pgrp so that tcsetpgrp and tcgetpgrp work, but we + don't use it for permissions checking. fhandler_tty_slave does + permission checking on pgrps. */ + virtual int tcgetpgrp () { return pgrp_; } + virtual int tcsetpgrp (const pid_t pid) { pgrp_ = pid; return 0; } + select_record *select_read (select_record *s); + select_record *select_write (select_record *s); + select_record *select_except (select_record *s); + int ready_for_read (int fd, DWORD howlong, int ignra); +}; + +class fhandler_termios: public fhandler_base +{ +protected: + HANDLE output_handle; + virtual void doecho (const void *str, DWORD len) {}; + virtual int accept_input () {return 1;}; +public: + tty_min *tc; + fhandler_termios (DWORD dev, const char *name = 0, int unit = 0) : + fhandler_base (dev, name, unit) + { + // nothing to do + } + HANDLE restart_output_event; + HANDLE get_output_handle () const { return output_handle; } + int line_edit (const char *rptr, int nread, int always_accept = 0); + void set_output_handle (HANDLE h) { output_handle = h; } + void tcinit (tty_min *this_tc, int force = FALSE); + virtual int is_tty () { return 1; } + int tcgetpgrp (); + int tcsetpgrp (int pid); + void set_ctty (int ttynum, int flags); + int bg_check (int sig, int blocksigs = 1); +}; + +/* This is a input and output console handle */ +class fhandler_console: public fhandler_termios +{ +private: + +/* Output state */ + + // enum {normal, gotesc, gotsquare, gotarg1, gotcommand} state; +#define normal 1 +#define gotesc 2 +#define gotsquare 3 +#define gotarg1 4 +#define gotrsquare 5 +#define gotcommand 6 +#define gettitle 7 +#define eattitle 8 +#define MAXARGS 10 + int state_; + int args_[MAXARGS]; + int nargs_; + + DWORD default_color; + +/* Output calls */ + + BOOL fillin_info (); + void clear_screen (int, int, int, int); + void scroll_screen (int, int, int, int, int, int); + void cursor_set (BOOL, int, int); + void cursor_get (int *, int *); + void cursor_rel (int, int); + const unsigned char * write_normal (unsigned const char*, unsigned const char *); + void char_command (char); + int output_tcsetattr (int a, const struct termios *t); + +/* Input calls */ + int igncr_enabled (); + int input_tcsetattr (int a, const struct termios *t); + +public: + + fhandler_console (const char *name); + + fhandler_console* is_console () { return this; } + + int open (const char *path, int flags, mode_t mode = 0); + + int write (const void *ptr, size_t len); + void doecho (const void *str, DWORD len) { (void) write (str, len); } + int read (void *ptr, size_t len); + int close (); + + int tcflush (int); + int tcsetattr (int a, const struct termios *t); + int tcgetattr (struct termios *t); + + int tcsetpgrp (const pid_t pid) { tc->pgid = pid; return 0; } + + /* Special dup as we must dup two handles */ + int dup (fhandler_base *child); + + int ioctl (unsigned int cmd, void *); + void init (HANDLE, DWORD, mode_t); + + select_record *select_read (select_record *s); + select_record *select_write (select_record *s); + select_record *select_except (select_record *s); + int ready_for_read (int fd, DWORD howlong, int ignra); + int de_linearize (const char *, const char *, const char *); + void set_close_on_exec (int val); + void fixup_after_fork (HANDLE parent); + void set_input_state () + { + if (TTYISSETF (RSTCONS)) + input_tcsetattr (0, &tc->ti); + } +}; + +class fhandler_tty_common: public fhandler_termios +{ +public: + fhandler_tty_common (DWORD dev, const char *name = 0, int unit = 0) : + fhandler_termios (dev, name, unit), + ttynum (unit) + { + // nothing to do + } + HANDLE output_done_event; // Raised by master when tty's output buffer + // written. Write status in tty::write_retval. + HANDLE ioctl_request_event; // Raised by slave to perform ioctl() request. + // Ioctl() request in tty::cmd/arg. + HANDLE ioctl_done_event; // Raised by master on ioctl() completion. + // Ioctl() status in tty::ioctl_retval. + HANDLE output_mutex; + HANDLE inuse; // used to indicate that a tty is in use + + + DWORD __acquire_output_mutex (const char *fn, int ln, DWORD ms); + void __release_output_mutex (const char *fn, int ln); + + int ttynum; // Master tty num. + virtual int dup (fhandler_base *child); + + tty *get_ttyp () { return (tty *)tc; } + int get_unit () { return ttynum; } + + int close (); + void set_close_on_exec (int val); + void fixup_after_fork (HANDLE parent); + select_record *select_read (select_record *s); + select_record *select_write (select_record *s); + select_record *select_except (select_record *s); + int ready_for_read (int fd, DWORD howlong, int ignra); +}; + +class fhandler_tty_slave: public fhandler_tty_common +{ + void send_ioctl_request (); + +public: + /* Constructor */ + fhandler_tty_slave (const char *name); + fhandler_tty_slave (int, const char *name); + + int open (const char *path, int flags, mode_t mode = 0); + int write (const void *ptr, size_t len); + int read (void *ptr, size_t len); + void init (HANDLE, DWORD, mode_t); + + int tcsetattr (int a, const struct termios *t); + int tcgetattr (struct termios *t); + int tcflush (int); + int ioctl (unsigned int cmd, void *); + + off_t lseek (off_t offset, int whence) { return 0; } +}; + +class fhandler_pty_master: public fhandler_tty_common +{ + int pktmode; // non-zero if pty in a packet mode. +public: + int neednl_; // Next read should start with \n + + /* Constructor */ + fhandler_pty_master (const char *name, DWORD devtype = FH_PTYM, int unit = -1); + + int process_slave_output (char *buf, size_t len); + void doecho (const void *str, DWORD len); + int accept_input (); + int open (const char *path, int flags, mode_t mode = 0); + int write (const void *ptr, size_t len); + int read (void *ptr, size_t len); + int close (); + + int tcsetattr (int a, const struct termios *t); + int tcgetattr (struct termios *t); + int tcflush (int); + int ioctl (unsigned int cmd, void *); + + off_t lseek (off_t offset, int whence) { return 0; } + char *ptsname (); + + void set_close_on_exec (int val); + void fixup_after_fork (HANDLE parent); + BOOL hit_eof (); +}; + +class fhandler_tty_master: public fhandler_pty_master +{ +public: + /* Constructor */ + fhandler_tty_master (const char *name, int unit); + fhandler_console *console; // device handler to perform real i/o. + HANDLE hThread; // process_output thread handle. + + int init (int); + int init_console (); + void fixup_after_fork (HANDLE parent); + int de_linearize (const char *, const char *, const char *); +}; + +class fhandler_dev_null: public fhandler_base +{ +public: + fhandler_dev_null (const char *name); + + void dump (); + select_record *select_read (select_record *s); + select_record *select_write (select_record *s); + select_record *select_except (select_record *s); +}; + +class fhandler_dev_zero: public fhandler_base +{ +public: + fhandler_dev_zero (const char *name); + int open (const char *path, int flags, mode_t mode = 0); + int write (const void *ptr, size_t len); + int read (void *ptr, size_t len); + off_t lseek (off_t offset, int whence); + int close (void); + + void dump (); +}; + +class fhandler_windows: public fhandler_base +{ +private: + HWND hWnd_; // the window whose messages are to be retrieved by read() call + int method_; // write method (Post or Send) +public: + fhandler_windows (const char *name = 0); + int is_windows (void) { return 1; } + int open (const char *path, int flags, mode_t mode = 0); + int write (const void *ptr, size_t len); + int read (void *ptr, size_t len); + int ioctl (unsigned int cmd, void *); + off_t lseek (off_t offset, int whence) { return 0; } + int close (void) { return 0; } + + void set_close_on_exec (int val); + void fixup_after_fork (HANDLE parent); + select_record *select_read (select_record *s); + select_record *select_write (select_record *s); + select_record *select_except (select_record *s); + int ready_for_read (int fd, DWORD howlong, int ignra); +}; + +#if 0 +/* You can't do this */ +typedef union +{ + fhandler_normal normal; + fhandler_dev_null dev_null; + fhandler bare; + fhandler_serial tty; +} fhandler_union; +#else +#define fhandler_union fhandler_console +#endif +struct select_record +{ + int fd; + HANDLE h; + fhandler_base *fh; + BOOL saw_error; + BOOL windows_handle; + BOOL read_ready, write_ready, except_ready; + BOOL read_selected, write_selected, except_selected; + select_record (fhandler_base *in_fh = NULL) {memset (this, 0, sizeof(select_record)); fh = in_fh;} + int (*startup) (select_record *me, class select_stuff *stuff); + int (*poll) (select_record *me, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds); + int (*verify) (select_record *me, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds); + void (*cleanup) (select_record *me, class select_stuff *stuff); + struct select_record *next; +}; + +class select_stuff +{ +public: + ~select_stuff (); + BOOL always_ready, windows_used; + int total; + select_record start; + void *device_specific[FH_NDEV]; + + int test_and_set (int i, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds); + int poll (fd_set *readfds, fd_set *writefds, fd_set *exceptfds); + int wait (fd_set *readfds, fd_set *writefds, fd_set *exceptfds, DWORD ms); +}; + +uid_t __stdcall get_file_owner (int, const char *); +gid_t __stdcall get_file_group (int, const char *); + +void __stdcall set_inheritance (HANDLE &h, int val, const char *name = NULL); + +#endif /* _FHANDLER_H_ */ diff --git a/winsup/cygwin/fhandler_console.cc b/winsup/cygwin/fhandler_console.cc new file mode 100644 index 000000000..188c79c56 --- /dev/null +++ b/winsup/cygwin/fhandler_console.cc @@ -0,0 +1,1387 @@ +/* fhandler_console.cc + + Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +/* FIXMES: + Should the constructor call tcinit() explicitly rather than having + it sprinkled throughout here? */ + +#include +#include +#include +#include +#include +#include +#include "winsup.h" +#include + +/* + * Scroll the screen context. + * x1, y1 - ul corner + * x2, y2 - dr corner + * xn, yn - new ul corner + * Negative values represents current screen dimensions + */ +static struct + { + short Top, Bottom; + } scroll_region = {0, -1}; + +#define srTop (info.winTop + scroll_region.Top) +#define srBottom ((scroll_region.Bottom < 0) ? info.winBottom : info.winTop + scroll_region.Bottom) + +#define use_tty ISSTATE (myself, PID_USETTY) + +const char * get_nonascii_key (INPUT_RECORD& input_rec); + +HANDLE console_shared_h; + +static tty_min NO_COPY *shared_console_info = NULL; + +/* Allocate and initialize the shared record for the current console. + Returns a pointer to shared_console_info. */ +static __inline tty_min * +get_tty_stuff (int force = 0) +{ + if (shared_console_info && !force) + return shared_console_info; + + shared_console_info = (tty_min *) open_shared (NULL, console_shared_h, + sizeof (*shared_console_info), + NULL); + ProtectHandle (console_shared_h); + shared_console_info->setntty (TTY_CONSOLE); + shared_console_info->setsid (myself->sid); + return shared_console_info; +} + +/* Return the tty structure associated with a given tty number. If the + tty number is < 0, just return a dummy record. */ +tty_min * +tty_list::get_tty (int n) +{ + static tty_min nada; + if (n == TTY_CONSOLE) + return get_tty_stuff (); + else if (n >= 0) + return &cygwin_shared->tty.ttys[n]; + else + return &nada; +} + + +/* Determine if a console is associated with this process prior to a spawn. + If it is, then we'll return 1. If the console has been initialized, then + set it into a more friendly state for non-cygwin apps. */ +int __stdcall +set_console_state_for_spawn () +{ + HANDLE h = CreateFileA ("CONIN$", GENERIC_READ, FILE_SHARE_WRITE, + &sec_none_nih, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + + if (h == INVALID_HANDLE_VALUE || h == NULL) + return 0; + + if (shared_console_info != NULL) + { +# define tc shared_console_info /* ACK. Temporarily define for use in TTYSETF macro */ + SetConsoleMode (h, ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT); + TTYSETF (RSTCONS); +#if 0 + char ch; + DWORD n; + /* NOTE -- This ReadFile is apparently necessary for correct functioning on + Windows NT 4.0. Without this, the next ReadFile returns garbage. */ + (void) ReadFile (h, &ch, 0, &n, NULL); +#endif +# undef tc + } + + CloseHandle (h); + return 1; +} + +int +fhandler_console::read (void *pv, size_t buflen) +{ + if (!buflen) + return 0; + + HANDLE h = get_io_handle (); + int copied_chars = 0; + +#define buf ((char *) pv) + + int ch; + set_input_state (); + while (buflen) + if ((ch = get_readahead ()) < 0) + break; + else + { + buf[copied_chars++] = (unsigned char)(ch & 0xff); + buflen--; + } + + if (copied_chars) + return copied_chars; + + HANDLE w4[2]; + DWORD nwait; + + w4[0] = h; + nwait = 2; + w4[1] = signal_arrived; + + for (;;) + { + int bgres; + if ((bgres = bg_check (SIGTTIN)) <= 0) + return bgres; + + switch (WaitForMultipleObjects (nwait, w4, FALSE, INFINITE)) + { + case WAIT_OBJECT_0: + break; + case WAIT_OBJECT_0 + 1: + set_sig_errno (EINTR); + return -1; + default: + __seterrno (); + return -1; + } + DWORD nread; + INPUT_RECORD input_rec; + const char *toadd; + + if (!ReadConsoleInput (h, &input_rec, 1, &nread)) + { + syscall_printf ("ReadConsoleInput failed, %E"); + __seterrno (); + return -1; /* seems to be failure */ + } + +#define ich (input_rec.Event.KeyEvent.uChar.AsciiChar) + + /* check if we're just disposing of this one */ + + if (input_rec.EventType == WINDOW_BUFFER_SIZE_EVENT) + { + kill_pgrp (tc->getpgid (), SIGWINCH); + continue; + } +debug_printf ("ich %d, keydown %d, type %d", ich, input_rec.Event.KeyEvent.bKeyDown, input_rec.EventType); + if (input_rec.EventType != KEY_EVENT || + !input_rec.Event.KeyEvent.bKeyDown) + continue; + + if (ich == 0) /* arrow/function keys */ + { + toadd = get_nonascii_key (input_rec); + if (!toadd) + continue; + nread = strlen (toadd); + } + else if (!(input_rec.Event.KeyEvent.dwControlKeyState & LEFT_ALT_PRESSED)) + toadd = &ich; + else + { + static char tmp[2]; + tmp[0] = '\033'; + tmp[1] = tolower (ich); + toadd = tmp; + nread = 2; + } + + if (line_edit (toadd, nread)) + break; +#undef ich + } + + while (buflen) + if ((ch = get_readahead ()) < 0) + break; + else + { + buf[copied_chars++] = (unsigned char)(ch & 0xff); + buflen--; + } +#undef buf + + return copied_chars; +} + +static struct + { + SHORT winTop; + SHORT winBottom; + COORD dwWinSize; + COORD dwCursorPosition; + WORD wAttributes; + } info; + +BOOL +fhandler_console::fillin_info (void) +{ + BOOL ret; + CONSOLE_SCREEN_BUFFER_INFO linfo; + + if ((ret = GetConsoleScreenBufferInfo (get_output_handle(), &linfo))) + { + info.winTop = linfo.srWindow.Top; + info.winBottom = linfo.srWindow.Bottom; + info.dwWinSize.Y = 1 + linfo.srWindow.Bottom - linfo.srWindow.Top; + info.dwWinSize.X = 1 + linfo.srWindow.Right - linfo.srWindow.Left; + info.dwCursorPosition = linfo.dwCursorPosition; + info.wAttributes = linfo.wAttributes; + } + else + { + memset (&info, 0, sizeof info); + info.dwWinSize.Y = 25; + info.dwWinSize.X = 80; + info.winBottom = 24; + } + + return ret; +} + +void +fhandler_console::scroll_screen (int x1, int y1, int x2, int y2, int xn, int yn) +{ + SMALL_RECT sr1, sr2; + CHAR_INFO fill; + COORD dest; + + (void)fillin_info (); + sr1.Left = x1 >= 0 ? x1 : info.dwWinSize.X - 1; + if (y1 == 0) + sr1.Top = info.winTop; + else + sr1.Top = y1 > 0 ? y1 : info.winBottom; + sr1.Right = x2 >= 0 ? x2 : info.dwWinSize.X - 1; + if (y2 == 0) + sr1.Bottom = info.winTop; + else + sr1.Bottom = y2 > 0 ? y2 : info.winBottom; + sr2.Top = srTop; + sr2.Left = 0; + sr2.Bottom = srBottom; + sr2.Right = info.dwWinSize.X - 1; + if (sr1.Bottom > sr2.Bottom && sr1.Top <= sr2.Bottom) + sr1.Bottom = sr2.Bottom; + dest.X = xn >= 0 ? xn : info.dwWinSize.X - 1; + if (yn == 0) + dest.Y = info.winTop; + else + dest.Y = yn > 0 ? yn : info.winBottom; + fill.Char.AsciiChar = ' '; + fill.Attributes = default_color; + ScrollConsoleScreenBuffer (get_output_handle (), &sr1, &sr2, dest, &fill); + + /* ScrollConsoleScreenBuffer on Windows 95 is buggy - when scroll distance + * is more than half of screen, filling doesn't work as expected */ + + if (sr1.Top != sr1.Bottom) + if (dest.Y <= sr1.Top) /* forward scroll */ + clear_screen (0, 1 + dest.Y + sr1.Bottom - sr1.Top, sr2.Right, sr2.Bottom); + else /* reverse scroll */ + clear_screen (0, sr1.Top, sr2.Right, dest.Y - 1); +} + +int +fhandler_console::open (const char *, int flags, mode_t) +{ + HANDLE h; + + tcinit (get_tty_stuff ()); + + set_io_handle (INVALID_HANDLE_VALUE); + set_output_handle (INVALID_HANDLE_VALUE); + + set_flags (flags); + + /* Open the input handle as handle_ */ + h = CreateFileA ("CONIN$", GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, &sec_none, + OPEN_EXISTING, 0, 0); + + if (h == INVALID_HANDLE_VALUE) + { + __seterrno (); + return 0; + } + set_io_handle (h); + set_r_no_interrupt (1); // Handled explicitly in read code + + h = CreateFileA ("CONOUT$", GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_WRITE | FILE_SHARE_WRITE, &sec_none, + OPEN_EXISTING, 0, 0); + + if (h == INVALID_HANDLE_VALUE) + { + __seterrno (); + return 0; + } + set_output_handle (h); + + if (fillin_info ()) + default_color = info.wAttributes; + + DWORD cflags; + if (GetConsoleMode (get_io_handle (), &cflags)) + { + cflags |= ENABLE_PROCESSED_INPUT; + SetConsoleMode (get_io_handle (), ENABLE_WINDOW_INPUT | cflags); + } + + TTYCLEARF (RSTCONS); + set_ctty (TTY_CONSOLE, flags); + debug_printf("opened conin$ %p, conout$ %p", + get_io_handle (), get_output_handle ()); + + return 1; +} + +int +fhandler_console::close (void) +{ + CloseHandle (get_io_handle ()); + CloseHandle (get_output_handle ()); + set_io_handle (INVALID_HANDLE_VALUE); + set_output_handle (INVALID_HANDLE_VALUE); + return 0; +} + +/* + * Special console dup to duplicate input and output + * handles. + */ + +int +fhandler_console::dup (fhandler_base *child) +{ + fhandler_console *fhc = (fhandler_console *) child; + + if (!fhc->open(get_name (), get_flags (), 0)) + system_printf ("error opening console, %E"); + + fhc->state_ = state_; + fhc->default_color = default_color; + + return 0; +} + +int +fhandler_console::ioctl (unsigned int cmd, void *buf) +{ + switch (cmd) + { + case TIOCGWINSZ: + int st; + + st = fillin_info (); + if (st) + { + /* *not* the buffer size, the actual screen size... */ + /* based on Left Top Right Bottom of srWindow */ + ((struct winsize *) buf)->ws_row = info.dwWinSize.Y; + ((struct winsize *) buf)->ws_col = info.dwWinSize.X; + syscall_printf ("WINSZ: (row=%d,col=%d)", + ((struct winsize *) buf)->ws_row, + ((struct winsize *) buf)->ws_col); + return 0; + } + else + { + syscall_printf ("WINSZ failed"); + __seterrno (); + return -1; + } + return 0; + case TIOCSWINSZ: + (void) bg_check (SIGTTOU, 0); + return 0; + } + + return fhandler_base::ioctl (cmd, buf); +} + +int +fhandler_console::tcflush (int queue) +{ + int res = 0; + if (queue == TCIFLUSH + || queue == TCIOFLUSH) + { + if (!FlushConsoleInputBuffer (get_io_handle ())) + { + __seterrno (); + res = -1; + } + } + return res; +} + +int +fhandler_console::output_tcsetattr (int, struct termios const *t) +{ + /* Ignore the optional_actions stuff, since all output is emitted + instantly */ + + /* Enable/disable LF -> CRLF conversions */ + set_w_binary ((t->c_oflag & ONLCR) ? 0 : 1); + + /* All the output bits we can ignore */ + + DWORD flags = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT; + + int res = SetConsoleMode (get_output_handle (), flags) ? 0 : -1; + syscall_printf ("%d = tcsetattr (,%x) (ENABLE FLAGS %x) (lflag %x oflag %x)", + res, t, flags, t->c_lflag, t->c_oflag); + return res; +} + +int +fhandler_console::input_tcsetattr (int, struct termios const *t) +{ + /* Ignore the optional_actions stuff, since all output is emitted + instantly */ + + DWORD oflags; + + if (!GetConsoleMode (get_io_handle (), &oflags)) + oflags = 0; + DWORD flags = 0; + + /* Enable/disable LF -> CRLF conversions */ + set_r_binary ((t->c_iflag & INLCR) ? 0 : 1); + + /* There's some disparity between what we need and what's + available. We've got ECHO and ICANON, they've + got ENABLE_ECHO_INPUT and ENABLE_LINE_INPUT. */ + + tc->ti = *t; + + if (t->c_lflag & ECHO) + { + flags |= ENABLE_ECHO_INPUT; + } + if (t->c_lflag & ICANON) + { + flags |= ENABLE_LINE_INPUT; + } + + if (flags & ENABLE_ECHO_INPUT + && !(flags & ENABLE_LINE_INPUT)) + { + /* This is illegal, so turn off the echo here, and fake it + when we read the characters */ + + flags &= ~ENABLE_ECHO_INPUT; + } + + if (t->c_lflag & ISIG) + { + flags |= ENABLE_PROCESSED_INPUT; + } + /* What about ENABLE_WINDOW_INPUT + and ENABLE_MOUSE_INPUT ? */ + + if (use_tty) + { + flags = 0; // ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT; + tc->ti.c_iflag = 0; + tc->ti.c_lflag = 0; + } + + flags |= ENABLE_WINDOW_INPUT; + + int res; + if (flags == oflags) + res = 0; + else + { + res = SetConsoleMode (get_io_handle (), flags) ? 0 : -1; + if (res < 0) + __seterrno (); + syscall_printf ("%d = tcsetattr (,%x) enable flags %p, c_lflag %p iflag %p", + res, t, flags, t->c_lflag, t->c_iflag); + } + + TTYCLEARF (RSTCONS); + return res; +} + +int +fhandler_console::tcsetattr (int a, struct termios const *t) +{ + int res = output_tcsetattr (a, t); + if (res != 0) + return res; + return input_tcsetattr (a, t); +} + +int +fhandler_console::tcgetattr (struct termios *t) +{ + int res; + *t = tc->ti; + + t->c_cflag |= CS8; + +#if 0 + if (!get_r_binary ()) + t->c_iflag |= IGNCR; + if (!get_w_binary ()) + t->c_oflag |= ONLCR; +#endif + + DWORD flags; + + if (!GetConsoleMode (get_io_handle (), &flags)) + { + __seterrno (); + res = -1; + } + else + { + if (flags & ENABLE_ECHO_INPUT) + t->c_lflag |= ECHO; + + if (flags & ENABLE_LINE_INPUT) + t->c_lflag |= ICANON; + + if (flags & ENABLE_PROCESSED_INPUT) + t->c_lflag |= ISIG; + + /* What about ENABLE_WINDOW_INPUT + and ENABLE_MOUSE_INPUT ? */ + + /* All the output bits we can ignore */ + res = 0; + } + syscall_printf ("%d = tcgetattr (%p) enable flags %p, t->lflag %p, t->iflag %p", + res, t, flags, t->c_lflag, t->c_iflag); + return res; +} + +/* + * Constructor. + */ + +fhandler_console::fhandler_console (const char *name) : + fhandler_termios (FH_CONSOLE, name, -1) +{ + set_cb (sizeof *this); + state_ = normal; + set_need_fork_fixup (); +} + +/* + * Clear the screen context from x1/y1 to x2/y2 cell. + * Negative values represents current screen dimensions + */ +void +fhandler_console::clear_screen (int x1, int y1, int x2, int y2) +{ + COORD tlc; + DWORD done; + int num; + + (void)fillin_info (); + + if (x1 < 0) + x1 = info.dwWinSize.X-1; + if (y1 < 0) + y1 = info.winBottom; + if (x2 < 0) + x2 = info.dwWinSize.X-1; + if (y2 < 0) + y2 = info.winBottom; + + num = abs (y1 - y2) * info.dwWinSize.X + abs (x1 - x2) + 1; + + if ((y2 * info.dwWinSize.X + x2) > (y1 * info.dwWinSize.X + x1)) + { + tlc.X = x1; + tlc.Y = y1; + } + else + { + tlc.X = x2; + tlc.Y = y2; + } + FillConsoleOutputCharacterA (get_output_handle (), ' ', + num, + tlc, + &done); + FillConsoleOutputAttribute (get_output_handle (), + default_color, + num, + tlc, + &done); +} + +void +fhandler_console::cursor_set (BOOL rel_to_top, int x, int y) +{ + COORD pos; + + (void)fillin_info (); + if (y > info.winBottom) + y = info.winBottom; + else if (y < 0) + y = 0; + else if (rel_to_top) + y += info.winTop; + + if (x > info.dwWinSize.X) + x = info.dwWinSize.X - 1; + else if (x < 0) + x = 0; + + pos.X = x; + pos.Y = y; + SetConsoleCursorPosition (get_output_handle (), pos); +} + +void +fhandler_console::cursor_rel (int x, int y) +{ + fillin_info (); + x += info.dwCursorPosition.X; + y += info.dwCursorPosition.Y; + cursor_set (FALSE, x, y); +} + +void +fhandler_console::cursor_get (int *x, int *y) +{ + fillin_info (); + *y = info.dwCursorPosition.Y; + *x = info.dwCursorPosition.X; +} + +#define BAK 1 +#define ESC 2 +#define NOR 0 +#define IGN 4 +#if 0 +#define ERR 5 +#else +#define ERR NOR +#endif +#define DWN 6 +#define BEL 7 +#define TAB 8 /* We should't let the console deal with these */ +#define CR 13 +#define LF 10 + +static const char base_chars[256] = +{ +/*00 01 02 03 04 05 06 07 */ IGN, ERR, ERR, NOR, NOR, NOR, NOR, BEL, +/*08 09 0A 0B 0C 0D 0E 0F */ BAK, TAB, DWN, ERR, ERR, CR, ERR, IGN, +/*10 11 12 13 14 15 16 17 */ NOR, NOR, ERR, ERR, ERR, ERR, ERR, ERR, +/*18 19 1A 1B 1C 1D 1E 1F */ NOR, NOR, ERR, ESC, ERR, ERR, ERR, ERR, +/* ! " # $ % & ' */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR, +/*( ) * + , - . / */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR, +/*0 1 2 3 4 5 6 7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR, +/*8 9 : ; < = > ? */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR, +/*@ A B C D E F G */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR, +/*H I J K L M N O */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR, +/*P Q R S T U V W */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR, +/*X Y Z [ \ ] ^ _ */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR, +/*` a b c d e f g */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR, +/*h i j k l m n o */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR, +/*p q r s t u v w */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR, +/*x y z { | } ~ 7F */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR, +/*80 81 82 83 84 85 86 87 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR, +/*88 89 8A 8B 8C 8D 8E 8F */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR, +/*90 91 92 93 94 95 96 97 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR, +/*98 99 9A 9B 9C 9D 9E 9F */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR, +/*A0 A1 A2 A3 A4 A5 A6 A7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR, +/*A8 A9 AA AB AC AD AE AF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR, +/*B0 B1 B2 B3 B4 B5 B6 B7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR, +/*B8 B9 BA BB BC BD BE BF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR, +/*C0 C1 C2 C3 C4 C5 C6 C7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR, +/*C8 C9 CA CB CC CD CE CF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR, +/*D0 D1 D2 D3 D4 D5 D6 D7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR, +/*D8 D9 DA DB DC DD DE DF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR, +/*E0 E1 E2 E3 E4 E5 E6 E7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR, +/*E8 E9 EA EB EC ED EE EF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR, +/*F0 F1 F2 F3 F4 F5 F6 F7 */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR, +/*F8 F9 FA FB FC FD FE FF */ NOR, NOR, NOR, NOR, NOR, NOR, NOR, NOR }; + +/*#define syscall_printf small_printf*/ + +static int savex, savey; /* for CSI s, CSI u */ + +void +fhandler_console::char_command (char c) +{ + // Keep the background intensity with the colr since there doesn't seem + // to be a way to set this with termcap/terminfo. + static int fg = default_color & (FOREGROUND_BLUE | FOREGROUND_GREEN | + FOREGROUND_RED), + bg = default_color & (BACKGROUND_BLUE | BACKGROUND_GREEN | + BACKGROUND_RED | BACKGROUND_INTENSITY), + bold = default_color & FOREGROUND_INTENSITY; + int x, y; + char buf[40]; + + switch (c) + { + case 'm': /* Set Graphics Rendition */ + int i; + + for (i = 0; i <= nargs_; i++) + switch (args_[i]) + { + case 0: /* normal color */ + fg = default_color & (FOREGROUND_BLUE | FOREGROUND_GREEN | + FOREGROUND_RED); + bg = default_color & (BACKGROUND_BLUE | BACKGROUND_GREEN | + BACKGROUND_RED | BACKGROUND_INTENSITY); + bold = default_color & FOREGROUND_INTENSITY; + break; + case 1: /* bold */ + fg = default_color & (FOREGROUND_BLUE | FOREGROUND_GREEN | + FOREGROUND_RED); + bg = default_color & (BACKGROUND_BLUE | BACKGROUND_GREEN | + BACKGROUND_RED | BACKGROUND_INTENSITY); + bold = FOREGROUND_INTENSITY; + break; + case 4: /* underline - simulate with cyan */ + fg = FOREGROUND_BLUE | FOREGROUND_GREEN; + bg = default_color & (BACKGROUND_BLUE | BACKGROUND_GREEN | + BACKGROUND_RED | BACKGROUND_INTENSITY); + bold = default_color & FOREGROUND_INTENSITY; + break; + case 5: /* blink mode */ + fg = default_color & (FOREGROUND_BLUE | FOREGROUND_GREEN | + FOREGROUND_RED); + bg = default_color & (BACKGROUND_BLUE | BACKGROUND_GREEN | + BACKGROUND_RED | BACKGROUND_INTENSITY); + bold = default_color & FOREGROUND_INTENSITY; + break; + case 7: /* reverse */ + fg = (default_color & BACKGROUND_BLUE) ? FOREGROUND_BLUE : 0; + fg |= (default_color & BACKGROUND_GREEN) ? FOREGROUND_GREEN : 0; + fg |= (default_color & BACKGROUND_RED) ? FOREGROUND_RED : 0; + fg |= (default_color & BACKGROUND_INTENSITY) ? + FOREGROUND_INTENSITY : 0; + bg = (default_color & FOREGROUND_BLUE) ? BACKGROUND_BLUE : 0; + bg |= (default_color & FOREGROUND_GREEN) ? BACKGROUND_GREEN : 0; + bg |= (default_color & FOREGROUND_RED) ? BACKGROUND_RED : 0; + bg |= (default_color & FOREGROUND_INTENSITY) ? + BACKGROUND_INTENSITY : 0; + break; + case 8: /* invisible */ + fg = (default_color & BACKGROUND_BLUE) ? FOREGROUND_BLUE : 0; + fg |= (default_color & BACKGROUND_GREEN) ? FOREGROUND_GREEN : 0; + fg |= (default_color & BACKGROUND_RED) ? FOREGROUND_RED : 0; + bg = default_color & (BACKGROUND_BLUE | BACKGROUND_GREEN | + BACKGROUND_RED | BACKGROUND_INTENSITY); + bold = (default_color & BACKGROUND_INTENSITY) ? + FOREGROUND_INTENSITY : 0; + break; + case 9: /* dim */ + fg = default_color & (FOREGROUND_BLUE | FOREGROUND_GREEN | + FOREGROUND_RED); + bg = default_color & (BACKGROUND_BLUE | BACKGROUND_GREEN | + BACKGROUND_RED | BACKGROUND_INTENSITY); + bold = (fg == 0) ? FOREGROUND_INTENSITY : 0; + break; + case 30: /* BLACK foreground */ + fg = 0; + break; + case 31: /* RED foreground */ + fg = FOREGROUND_RED; + break; + case 32: /* GREEN foreground */ + fg = FOREGROUND_GREEN; + break; + case 33: /* YELLOW foreground */ + fg = FOREGROUND_RED | FOREGROUND_GREEN; + break; + case 34: /* BLUE foreground */ + fg = FOREGROUND_BLUE; + break; + case 35: /* MAGENTA foreground */ + fg = FOREGROUND_RED | FOREGROUND_BLUE; + break; + case 36: /* CYAN foreground */ + fg = FOREGROUND_BLUE | FOREGROUND_GREEN; + break; + case 37: /* WHITE foreg */ + fg = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; + break; + case 40: /* BLACK background */ + bg = 0; + break; + case 41: /* RED background */ + bg = BACKGROUND_RED; + break; + case 42: /* GREEN background */ + bg = BACKGROUND_GREEN; + break; + case 43: /* YELLOW background */ + bg = BACKGROUND_RED | BACKGROUND_GREEN; + break; + case 44: /* BLUE background */ + bg = BACKGROUND_BLUE; + break; + case 45: /* MAGENTA background */ + bg = BACKGROUND_RED | BACKGROUND_BLUE; + break; + case 46: /* CYAN background */ + bg = BACKGROUND_BLUE | BACKGROUND_GREEN; + break; + case 47: /* WHITE background */ + bg = BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED; + break; + default: + fg = default_color & (FOREGROUND_BLUE | FOREGROUND_GREEN | + FOREGROUND_RED); + bg = default_color & (BACKGROUND_BLUE | BACKGROUND_GREEN | + BACKGROUND_RED | BACKGROUND_INTENSITY); + bold = default_color & FOREGROUND_INTENSITY; + break; + } + SetConsoleTextAttribute (get_output_handle (), fg | bg | bold); + break; + case 'h': + case 'l': + /* Ignore */ + break; + case 'J': + switch (args_[0]) + { + case 0: /* Clear to end of screen */ + cursor_get (&x, &y); + clear_screen (x, y, -1, -1); + break; + case 1: /* Clear from beginning of screen to cursor */ + cursor_get (&x, &y); + clear_screen (0, 0, x, y); + break; + case 2: /* Clear screen */ + clear_screen (0, 0, -1, -1); + cursor_set (TRUE, 0,0); + break; + default: + goto bad_escape; + } + break; + + case 'A': + cursor_rel (0, -(args_[0] ? args_[0] : 1)); + break; + case 'B': + cursor_rel (0, args_[0] ? args_[0] : 1); + break; + case 'C': + cursor_rel (args_[0] ? args_[0] : 1, 0); + break; + case 'D': + cursor_rel (-(args_[0] ? args_[0] : 1),0); + break; + case 'K': + switch (args_[0]) + { + case 0: /* Clear to end of line */ + cursor_get (&x, &y); + clear_screen (x, y, -1, y); + break; + case 2: /* Clear line */ + cursor_get (&x, &y); + clear_screen (0, y, -1, y); + break; + case 1: /* Clear from bol to cursor */ + cursor_get (&x, &y); + clear_screen (0, y, x, y); + break; + default: + goto bad_escape; + } + break; + case 'H': + case 'f': + cursor_set (TRUE, (args_[1] ? args_[1] : 1) - 1, + (args_[0] ? args_[0] : 1) - 1); + break; + case 'G': /* hpa - position cursor at column n - 1 */ + cursor_get (&x, &y); + cursor_set (FALSE, (args_[0] ? args_[0] - 1 : 0), y); + break; + case 'd': /* vpa - position cursor at line n */ + cursor_get (&x, &y); + cursor_set (TRUE, x, (args_[0] ? args_[0] - 1 : 0)); + break; + case 's': /* Save cursor position */ + cursor_get (&savex, &savey); + break; + case 'u': /* Restore cursor position */ + cursor_set (FALSE, savex, savey); + break; + case 'I': /* TAB */ + cursor_get (&x, &y); + cursor_set (FALSE, 8*(x/8+1), y); + break; + case 'L': /* AL - insert blank lines */ + args_[0] = args_[0] ? args_[0] : 1; + cursor_get (&x, &y); + scroll_screen (0, y, -1, -1, 0, y + args_[0]); + break; + case 'M': /* DL - delete lines */ + args_[0] = args_[0] ? args_[0] : 1; + cursor_get (&x, &y); + scroll_screen (0, y + args_[0], -1, -1, 0, y); + break; + case '@': /* IC - insert chars */ + args_[0] = args_[0] ? args_[0] : 1; + cursor_get (&x, &y); + scroll_screen (x, y, -1, y, x + args_[0], y); + break; + case 'P': /* DC - delete chars */ + args_[0] = args_[0] ? args_[0] : 1; + cursor_get (&x, &y); + scroll_screen (x + args_[0], y, -1, y, x, y); + break; + case 'S': /* SF - Scroll forward */ + args_[0] = args_[0] ? args_[0] : 1; + scroll_screen(0, args_[0], -1, -1, 0, 0); + break; + case 'T': /* SR - Scroll down */ + fillin_info (); + args_[0] = args_[0] ? args_[0] : 1; + scroll_screen (0, 0, -1, -1, 0, info.winTop + args_[0]); + break; + case 'X': /* ec - erase chars */ + args_[0] = args_[0] ? args_[0] : 1; + cursor_get (&x, &y); + scroll_screen (x + args_[0], y, -1, y, x, y); + scroll_screen (x, y, -1, y, x + args_[0], y); + break; + case 'Z': /* Back tab */ + cursor_get (&x, &y); + cursor_set (FALSE, ((8 * (x / 8 + 1)) - 8), y); + break; + case 'b': /* Repeat char #1 #2 times */ + while (args_[1]--) + WriteFile (get_output_handle (), &args_[0], 1, (DWORD *) &x, 0); + break; + case 'c': /* u9 - Terminal enquire string */ + strcpy (buf, "\033[?6c"); + puts_readahead (buf); + break; + case 'n': + switch (args_[0]) + { + case 6: /* u7 - Cursor position request */ + cursor_get (&x, &y); + y -= info.winTop; + /* x -= info.winLeft; // not available yet */ + __small_sprintf (buf, "\033[%d;%dR", y + 1, x + 1); + puts_readahead (buf); + break; + default: + goto bad_escape; + } + break; + case 'r': /* Set Scroll region */ + scroll_region.Top = args_[0] ? args_[0] - 1 : 0; + scroll_region.Bottom = args_[1] ? args_[1] - 1 : -1; + cursor_set (TRUE, 0, 0); + break; + case 'g': /* TAB set/clear */ + break; + default: +bad_escape: + break; + } +} + +const unsigned char * +fhandler_console::write_normal (const unsigned char *src, + const unsigned char *end) +{ + /* Scan forward to see what a char which needs special treatment */ + DWORD done; + const unsigned char *found = src; + + while (found < end) + { + if (base_chars[*found] != NOR) + break; + found++; + } + /* Print all the base ones out */ + if (found != src) + { + if (! WriteFile (get_output_handle (), src, found - src, &done, 0)) + { + debug_printf ("write failed, handle %p", get_output_handle ()); + __seterrno (); + return 0; + } + src += done; + } + if (src < end) + { + int x, y; + switch (base_chars[*src]) + { + case BEL: + Beep (412, 100); + break; + case ESC: + state_ = gotesc; + break; + case DWN: /* WriteFile("\n") always adds CR... */ + cursor_get (&x, &y); + if (y >= srBottom) + { + if (y < info.winBottom || scroll_region.Top) + { + scroll_screen (0, srTop + 1, -1, srBottom, 0, srTop); + y--; + } + else + WriteFile (get_output_handle (), "\n", 1, &done, 0); + } + if (!get_w_binary ()) + x = 0; + cursor_set (FALSE, x, y + 1); + break; + case BAK: + cursor_rel (-1, 0); + break; + case IGN: + cursor_rel (1, 0); + break; + case CR: + cursor_get (&x, &y); + cursor_set (FALSE, 0, y); + break; + case ERR: + WriteFile (get_output_handle (), src, 1, &done, 0); + break; + case TAB: + cursor_get (&x, &y); + cursor_set (FALSE, 8 * (x / 8 + 1), y); + break; + } + src ++; + } + return src; +} + +int +fhandler_console::write (const void *vsrc, size_t len) +{ + /* Run and check for ansi sequences */ + unsigned const char *src = (unsigned char *) vsrc; + unsigned const char *end = src + len; + static NO_COPY unsigned rarg; + static NO_COPY char my_title_buf[TITLESIZE + 1]; + + debug_printf ("%x, %d", vsrc, len); + + while (src < end) + { + debug_printf ("at %d(%c) state is %d", *src, isprint (*src) ? *src : ' ', + state_); + switch (state_) + { + case normal: + src = write_normal (src, end); + if (src == 0) /* write_normal fail */ + return -1; + break; + case gotesc: + if (*src == '[') + { + state_ = gotsquare; + for (nargs_ = 0; nargs_ < MAXARGS; nargs_++) + args_[nargs_] = 0; + nargs_ = 0; + } + else if (*src == ']') + { + rarg = 0; + my_title_buf[0] = '\0'; + state_ = gotrsquare; + } + else if (*src == 'M') /* Reverse Index */ + { + fillin_info (); + scroll_screen (0, 0, -1, -1, 0, info.winTop + 1); + state_ = normal; + } + else if (*src == 'c') /* Reset Linux terminal */ + { + clear_screen (0, 0, -1, -1); + cursor_set (TRUE, 0, 0); + state_ = normal; + } + else if (*src == '8') /* Restore cursor position */ + { + cursor_set (FALSE, savex, savey); + state_ = normal; + } + else if (*src == '7') /* Save cursor position */ + { + cursor_get (&savex, &savey); + state_ = normal; + } + else if (*src == 'R') + state_ = normal; + else + { + state_ = normal; + } + src++; + break; + case gotarg1: + if (isdigit (*src)) + { + args_[nargs_] = args_[nargs_] * 10 + *src - '0'; + src++; + } + else if (*src == ';') + { + src++; + nargs_++; + if (nargs_ >= MAXARGS) + nargs_--; + } + else + { + state_ = gotcommand; + } + break; + case gotcommand: + char_command (*src++); + state_ = normal; + break; + case gotrsquare: + if (isdigit(*src)) + rarg = rarg * 10 + (*src - '0'); + else if (*src == ';' && (rarg == 2 || rarg == 0)) + state_ = gettitle; + else + state_ = eattitle; + src++; + break; + case eattitle: + case gettitle: + { + int n = strlen (my_title_buf); + if (*src < ' ' || *src >= '\177') + { + if (*src == '\007' && state_ == gettitle) + { + if (old_title) + strcpy (old_title, my_title_buf); + set_console_title (my_title_buf); + } + state_ = normal; + } + else if (n < TITLESIZE) + { + my_title_buf[n++] = *src; + my_title_buf[n] = '\0'; + } + src++; + break; + } + case gotsquare: + if (*src == ';') + { + state_ = gotarg1; + nargs_++; + src++; + } + else if (isalpha (*src)) + { + state_ = gotcommand; + } + else if (*src != '@' && !isalpha (*src) && !isdigit (*src)) + { + /* ignore any extra chars between [ and first arg or command */ + src++; + } + else + state_ = gotarg1; + break; + } + } + syscall_printf ("%d = write_console (,..%d)", len, len); + + return len; +} + +static struct { + int vk; + const char *val[4]; +} keytable[] = { + /* NORMAL */ /* SHIFT */ /* CTRL */ /* ALT */ + {VK_LEFT, {"\033[D", NULL, NULL, NULL}}, + {VK_RIGHT, {"\033[C", NULL, NULL, NULL}}, + {VK_UP, {"\033[A", NULL, NULL, NULL}}, + {VK_DOWN, {"\033[B", NULL, NULL, NULL}}, + {VK_PRIOR, {"\033[5~", NULL, NULL, NULL}}, + {VK_NEXT, {"\033[6~", NULL, NULL, NULL}}, + {VK_HOME, {"\033[1~", NULL, NULL, NULL}}, + {VK_END, {"\033[4~", NULL, NULL, NULL}}, + {VK_INSERT, {"\033[2~", NULL, NULL, NULL}}, + {VK_DELETE, {"\033[3~", NULL, NULL, NULL}}, + {VK_F1, {"\033[[A", "\033[23~", NULL, NULL}}, + {VK_F2, {"\033[[B", "\033[24~", NULL, NULL}}, + {VK_F3, {"\033[[C", "\033[25~", NULL, NULL}}, + {VK_F4, {"\033[[D", "\033[26~", NULL, NULL}}, + {VK_F5, {"\033[[E", "\033[28~", NULL, NULL}}, + {VK_F6, {"\033[17~", "\033[29~", "\036", NULL}}, + {VK_F7, {"\033[18~", "\033[31~", NULL, NULL}}, + {VK_F8, {"\033[19~", "\033[32~", NULL, NULL}}, + {VK_F9, {"\033[20~", "\033[33~", NULL, NULL}}, + {VK_F10, {"\033[21~", "\033[34~", NULL, NULL}}, + {VK_F11, {"\033[23~", NULL, NULL, NULL}}, + {VK_F12, {"\033[24~", NULL, NULL, NULL}}, + {VK_NUMPAD5, {"\033[G", NULL, NULL, NULL}}, + {'6', {NULL, NULL, "\036", NULL}}, + {0, {"", NULL, NULL, NULL}} +}; + +const char * +get_nonascii_key (INPUT_RECORD& input_rec) +{ +#define NORMAL 0 +#define SHIFT 1 +#define CONTROL 2 +#define ALT 3 + int modifier_index = NORMAL; + + if (input_rec.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) + modifier_index = SHIFT; + else if (input_rec.Event.KeyEvent.dwControlKeyState & + (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) + modifier_index = CONTROL; + else if (input_rec.Event.KeyEvent.dwControlKeyState & + (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) + modifier_index = ALT; + + for (int i = 0; keytable[i].vk; i++) + if (input_rec.Event.KeyEvent.wVirtualKeyCode == keytable[i].vk) + return keytable[i].val[modifier_index]; + + return NULL; +} + +void +fhandler_console::init (HANDLE f, DWORD a, mode_t bin) +{ + this->fhandler_termios::init (f, bin, a); + + /* Ensure both input and output console handles are open */ + int mode = 0; + + a &= GENERIC_READ | GENERIC_WRITE; + if (a == GENERIC_READ) + mode = O_RDONLY; + if (a == GENERIC_WRITE) + mode = O_WRONLY; + if (a == (GENERIC_READ | GENERIC_WRITE)) + mode = O_RDWR; + open (0, mode); + if (f != INVALID_HANDLE_VALUE) + CloseHandle (f); /* Reopened by open */ + + output_tcsetattr (0, &tc->ti); +} + +int +fhandler_console::igncr_enabled (void) +{ + return tc->ti.c_iflag & IGNCR; +} + +void +fhandler_console::set_close_on_exec (int val) +{ + this->fhandler_base::set_close_on_exec (val); + set_inheritance (output_handle, val); +} + +void +fhandler_console::fixup_after_fork (HANDLE parent) +{ + HANDLE h = get_handle (); + HANDLE oh = get_output_handle (); + + /* Windows does not allow duplication of console handles between processes + so open the console explicitly. */ + + if (!open(get_name (), get_flags (), 0)) + system_printf ("error opening console after fork, %E"); + + if (!get_close_on_exec ()) + { + CloseHandle (h); + CloseHandle (oh); + } +} + +void __stdcall +set_console_title (char *title) +{ + int rc; + char buf[257]; + strncpy(buf, title, sizeof(buf) - 1); + buf[sizeof(buf) - 1] = '\0'; + if ((rc = WaitForSingleObject (title_mutex, 15000)) != WAIT_OBJECT_0) + sigproc_printf ("wait for title mutex failed rc %d, %E", rc); + SetConsoleTitle (buf); + ReleaseMutex (title_mutex); + debug_printf ("title '%s'", buf); +} + +int +fhandler_console::de_linearize (const char *buf, const char *unix_name, + const char *win32_name) +{ + int res = fhandler_base::de_linearize (buf, unix_name, win32_name); + HANDLE h = get_handle (); + HANDLE oh = get_output_handle (); + + if (!open(get_name (), get_flags (), 0)) + { + int sawerr = 0; + if (!get_io_handle ()) + { + system_printf ("error opening input console handle after exec, errno %d, %E", get_errno ()); + sawerr = 1; + } + if (!get_output_handle ()) + { + system_printf ("error opening input console handle after exec, errno %d, %E", get_errno ()); + sawerr = 1; + } + + if (!sawerr) + system_printf ("error opening console after exec, errno %d, %E", get_errno ()); + } + + CloseHandle (h); + CloseHandle (oh); + return res; +} diff --git a/winsup/cygwin/fhandler_floppy.cc b/winsup/cygwin/fhandler_floppy.cc new file mode 100644 index 000000000..7c589824d --- /dev/null +++ b/winsup/cygwin/fhandler_floppy.cc @@ -0,0 +1,90 @@ +/* fhandler_floppy.cc. See fhandler.h for a description of the + fhandler classes. + + Copyright 1999 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include +#include "winsup.h" + +/**********************************************************************/ +/* fhandler_dev_floppy */ + +int +fhandler_dev_floppy::is_eom (int win_error) +{ + int ret = (win_error == ERROR_INVALID_PARAMETER); + if (ret) + debug_printf ("end of medium"); + return ret; +} + +int +fhandler_dev_floppy::is_eof (int win_error) +{ + int ret = 0; + if (ret) + debug_printf ("end of file"); + return ret; +} + +fhandler_dev_floppy::fhandler_dev_floppy (const char *name, int unit) : fhandler_dev_raw (FH_FLOPPY, name, unit) +{ + set_cb (sizeof *this); +} + +int +fhandler_dev_floppy::open (const char *path, int flags, mode_t) +{ + /* The correct size of the buffer would be 512 bytes, + * which is the atomic size, supported by WinNT. + * Unfortunately, the performance is worse than + * access to file system on same device! + * Setting buffer size to a relatively big value + * increases performance by means. + * The new ioctl call with 'rdevio.h' header file + * supports changing this value. + * + * Let's be smart: Let's take a multiplier of typical tar + * and cpio buffer sizes by default! + */ + devbufsiz = 61440L; /* 512L; */ + return fhandler_dev_raw::open (path, flags); +} + +int +fhandler_dev_floppy::close (void) +{ + int ret; + + ret = writebuf (); + if (ret) + { + fhandler_dev_raw::close (); + return ret; + } + return fhandler_dev_raw::close (); +} + +off_t +fhandler_dev_floppy::lseek (off_t offset, int whence) +{ + /* FIXME: Need to implement better. */ + offset = (offset / 512) * 512; + return fhandler_base::lseek (offset, whence); +} + +int +fhandler_dev_floppy::ioctl (unsigned int cmd, void *buf) +{ + return fhandler_dev_raw::ioctl (cmd, buf); +} + diff --git a/winsup/cygwin/fhandler_raw.cc b/winsup/cygwin/fhandler_raw.cc new file mode 100644 index 000000000..a1c166627 --- /dev/null +++ b/winsup/cygwin/fhandler_raw.cc @@ -0,0 +1,495 @@ +/* fhandler_raw.cc. See fhandler.h for a description of the fhandler classes. + + Copyright 1999, 2000 Cygnus Solutions. + + This file is part of Cygwin. + + This software is a copyrighted work licensed under the terms of the + Cygwin license. Please consult the file "CYGWIN_LICENSE" for + details. */ + +#include +#include +#include +#include +#include "winsup.h" + +#include +#include + +/**********************************************************************/ +/* fhandler_dev_raw */ + +void +fhandler_dev_raw::clear (void) +{ + devbuf = NULL; + devbufsiz = 0; + devbufstart = 0; + devbufend = 0; + eom_detected = 0; + eof_detected = 0; + lastblk_to_read = 0; + unit = 0; +} + +int +fhandler_dev_raw::writebuf (void) +{ + DWORD written; + int ret = 0; + + if (is_writing && devbuf && devbufend) + { + memset (devbuf + devbufend, 0, devbufsiz - devbufend); + DWORD to_write = ((devbufend - 1) / 512 + 1) * 512; + ret = 0; + + if (!WriteFile (get_handle (), devbuf, to_write, &written, 0)) + { + ret = GetLastError (); + if (is_eom (ret)) + eom_detected = 1; + } + + if (written) + has_written = 1; + + syscall_printf ("%d = WriteFile(%d, %d, write %d, written %d, 0)\n", + ret, get_handle (), devbuf, to_write, written); + devbufstart = devbufend = 0; + } + is_writing = 0; + return ret; +} + +fhandler_dev_raw::fhandler_dev_raw (DWORD devtype, const char *name, int unit) : fhandler_base (devtype, name) +{ + clear (); + this->unit = unit; +} + +fhandler_dev_raw::~fhandler_dev_raw (void) +{ + delete[]devbuf; + clear (); +} + +int +fhandler_dev_raw::de_linearize (const char *buf, const char *unix_name, + const char *win32_name) +{ + int ret = fhandler_base::de_linearize (buf, unix_name, win32_name); + if (devbufsiz > 1L) + { + devbuf = new char[devbufsiz]; + devbufstart = devbufend = 0; + } + return ret; +} + +int +fhandler_dev_raw::open (const char *path, int flags, mode_t) +{ + path_conv real_path (path, SYMLINK_IGNORE); + int ret; + + set_name (path, real_path.get_win32 ()); + + /* Always open a raw device existing */ + ret = fhandler_base::open (path, flags & ~(O_CREAT | O_TRUNC)); + if (ret) + { + if (devbufsiz > 1L) + { + devbuf = new char[devbufsiz]; + } + } + else + { + devbufsiz = 0; + } + return ret; +} + +int +fhandler_dev_raw::close (void) +{ + return fhandler_base::close (); +} + +int +fhandler_dev_raw::fstat (struct stat *buf) +{ + if (!buf) + { + set_errno (EINVAL); + return -1; + } + + memset (buf, 0, sizeof *buf); + buf->st_mode = S_IFCHR | + S_IRUSR | S_IWUSR | + S_IRGRP | S_IWGRP | + S_IROTH | S_IWOTH; + buf->st_nlink = 1; + buf->st_blksize = devbuf ? devbufsiz : 1; + buf->st_dev = buf->st_rdev = get_device () << 8 | (unit & 0xff); + + return 0; +} + +int +fhandler_dev_raw::raw_read (void *ptr, size_t ulen) +{ + DWORD bytes_read = 0; + DWORD read2; + DWORD bytes_to_read; + int ret; + size_t len = ulen; + char *tgt; + + /* In mode O_RDWR the buffer has to be written to device first */ + ret = writebuf (); + if (ret) + { + set_errno (is_eom (ret) ? ENOSPC : EACCES); + return -1; + } + + /* Checking a previous end of file */ + if (eof_detected && !lastblk_to_read) + { + eof_detected = 0; + return 0; + } + + /* Checking a previous end of media */ + if (eom_detected && !lastblk_to_read) + { + set_errno (ENOSPC); + return -1; + } + + if (devbuf) + { + while (len > 0) + { + if (devbufstart < devbufend) + { + bytes_to_read = min (len, devbufend - devbufstart); + debug_printf ("read %d bytes from buffer (rest %d)\n", + bytes_to_read, devbufstart - devbufend); + memcpy (ptr, devbuf + devbufstart, bytes_to_read); + len -= bytes_to_read; + ptr = (void *) ((char *) ptr + bytes_to_read); + bytes_read += bytes_to_read; + devbufstart += bytes_to_read; + + if (lastblk_to_read) + { + lastblk_to_read = 0; + break; + } + } + if (len > 0) + { + if (len >= devbufsiz) + { + bytes_to_read = (len / 512) * 512; + tgt = (char *) ptr; + debug_printf ("read %d bytes direct from file\n", + bytes_to_read); + } + else + { + bytes_to_read = devbufsiz; + tgt = devbuf; + debug_printf ("read %d bytes from file into buffer\n", + bytes_to_read); + } + if (!ReadFile (get_handle (), tgt, bytes_to_read, &read2, 0)) + { + ret = GetLastError (); + syscall_printf ("ReadFile %s failed with error %d\n", + get_name (), ret); + if (!is_eof (ret) && !is_eom (ret)) + { + debug_printf ("return -1, set errno to EACCES"); + set_errno (EACCES); + return -1; + } + + if (is_eof (ret)) + eof_detected = 1; + else + eom_detected = 1; + + if (!read2) + { + if (!bytes_read && is_eom (ret)) + { + debug_printf ("return -1, set errno to ENOSPC"); + set_errno (ENOSPC); + return -1; + } + break; + } + lastblk_to_read = 1; + } + if (! read2) + break; + if (tgt == devbuf) + { + devbufstart = 0; + devbufend = read2; + } + else + { + len -= bytes_to_read; + ptr = (void *) ((char *) ptr + bytes_to_read); + bytes_read += bytes_to_read; + } + } + } + } + else if (!ReadFile (get_handle (), ptr, len, &bytes_read, 0)) + { + ret = GetLastError (); + syscall_printf ("ReadFile %s failed with error %d\n", + get_name (), ret); + if (!is_eof (ret) && !is_eom (ret)) + { + debug_printf ("return -1, set errno to EACCES"); + set_errno (EACCES); + return -1; + } + if (bytes_read) + { + if (is_eof (ret)) + eof_detected = 1; + else + eom_detected = 1; + } + else if (is_eom (ret)) + { + debug_printf ("return -1, set errno to ENOSPC"); + set_errno (ENOSPC); + return -1; + } + } + + return bytes_read; +} + +int +fhandler_dev_raw::raw_write (const void *ptr, size_t len) +{ + DWORD bytes_written = 0; + DWORD bytes_to_write; + DWORD written; + char *p = (char *) ptr; + char *tgt; + int ret; + + /* Checking a previous end of media on tape */ + if (eom_detected) + { + set_errno (ENOSPC); + return -1; + } + + if (!is_writing) + devbufstart = devbufend = 0; + is_writing = 1; + + if (devbuf) + { + while (len > 0) + { + if ((len < devbufsiz || devbufend > 0) && devbufend < devbufsiz) + { + bytes_to_write = min (len, devbufsiz - devbufend); + memcpy (devbuf + devbufend, p, bytes_to_write); + bytes_written += bytes_to_write; + devbufend += bytes_to_write; + p += bytes_to_write; + len -= bytes_to_write; + } + else + { + if (devbufend == devbufsiz) + { + bytes_to_write = devbufsiz; + tgt = devbuf; + } + else + { + bytes_to_write = (len / devbufsiz) * devbufsiz; + tgt = p; + } + + ret = 0; + if (!WriteFile (get_handle (), tgt, bytes_to_write, &written, 0)) + ret = GetLastError (); + syscall_printf ("%d = WriteFile(%d, %d, write %d, written %d, 0)\n", + ret, get_handle (), tgt, bytes_to_write, written); + if (written) + has_written = 1; + + if (ret) + { + if (!is_eom (ret)) + { + __seterrno (); + return -1; + } + + eom_detected = 1; + + if (!written && !bytes_written) + { + set_errno (ENOSPC); + return -1; + } + + if (tgt == p) + bytes_written += written; + + break; // from while (len > 0) + } + + if (tgt == devbuf) + { + if (written != devbufsiz) + memmove (devbuf, devbuf + written, devbufsiz - written); + devbufend = devbufsiz - written; + } + else + { + len -= written; + p += written; + bytes_written += written; + } + } + } + } + else if (len > 0) + { + if (!WriteFile (get_handle (), ptr, len, &bytes_written, 0)) + { + ret = GetLastError (); + syscall_printf ("WriteFile %s failed with error %d\n", + get_name (), ret); + if (bytes_written) + has_written = 1; + if (!is_eom (ret)) + { + set_errno (EACCES); + return -1; + } + eom_detected = 1; + if (!bytes_written) + { + set_errno (ENOSPC); + return -1; + } + } + has_written = 1; + } + return bytes_written; +} + +int +fhandler_dev_raw::dup (fhandler_base *child) +{ + int ret = fhandler_base::dup (child); + + if (! ret) + { + fhandler_dev_raw *fhc = (fhandler_dev_raw *) child; + + fhc->devbufsiz = devbufsiz; + if (devbufsiz > 1L) + { + fhc->devbuf = new char[devbufsiz]; + memcpy (fhc->devbuf, devbuf, devbufend); + } + fhc->devbufstart = devbufstart; + fhc->devbufend = devbufend; + fhc->eom_detected = eom_detected; + fhc->eof_detected = eof_detected; + fhc->lastblk_to_read = lastblk_to_read; + fhc->unit = unit; + } + return ret; +} + +int +fhandler_dev_raw::ioctl (unsigned int cmd, void *buf) +{ + int ret = NO_ERROR; + + if (cmd == RDIOCDOP) + { + struct rdop *op = (struct rdop *) buf; + + if (!op) + ret = ERROR_INVALID_PARAMETER; + else + switch (op->rd_op) + { + case RDSETBLK: + if (get_device () == FH_TAPE) + { + struct mtop mop; + + mop.mt_op = MTSETBLK; + mop.mt_count = op->rd_parm; + ret = ioctl (MTIOCTOP, &mop); + } + else if (op->rd_parm % 512) + ret = ERROR_INVALID_PARAMETER; + else if (devbuf && op->rd_parm < devbufend - devbufstart) + ret = ERROR_INVALID_PARAMETER; + else if (!devbuf || op->rd_parm != devbufsiz) + { + char *buf = new char[op->rd_parm]; + if (devbuf) + { + memcpy (buf, devbuf + devbufstart, devbufend - devbufstart); + devbufend -= devbufstart; + delete[]devbuf; + } + else + devbufend = 0; + + devbufstart = 0; + devbuf = buf; + devbufsiz = op->rd_parm; + } + break; + default: + break; + } + } + else if (cmd == RDIOCGET) + { + struct rdget *get = (struct rdget *) buf; + + if (!get) + ret = ERROR_INVALID_PARAMETER; + else + get->bufsiz = devbufsiz ? devbufsiz : 1L; + } + else + return fhandler_base::ioctl (cmd, buf); + + if (ret != NO_ERROR) + { + SetLastError (ret); + __seterrno (); + return -1; + } + return 0; +} diff --git a/winsup/cygwin/fhandler_serial.cc b/winsup/cygwin/fhandler_serial.cc new file mode 100644 index 000000000..de4c7fedd --- /dev/null +++ b/winsup/cygwin/fhandler_serial.cc @@ -0,0 +1,883 @@ +/* fhandler_serial.cc + + Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include +#include "winsup.h" + +/**********************************************************************/ +/* fhandler_serial */ + +fhandler_serial::fhandler_serial (const char *name, DWORD devtype, int unit) : + fhandler_base (devtype, name, unit) +{ + set_cb (sizeof *this); + vmin_ = 0; + vtime_ = 0; + pgrp_ = myself->pgid; + set_need_fork_fixup (); +} + +void +fhandler_serial::overlapped_setup () +{ + memset (&io_status, 0, sizeof (io_status)); + io_status.hEvent = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL); + ProtectHandle (io_status.hEvent); + overlapped_armed = 0; +} + +int +fhandler_serial::raw_read (void *ptr, size_t ulen) +{ + int tot; + DWORD n; + HANDLE w4[2]; + DWORD minchars = vmin_ ?: ulen; + + w4[0] = io_status.hEvent; + w4[1] = signal_arrived; + + debug_printf ("ulen %d, vmin_ %d, vtime_ %d, hEvent %p", ulen, vmin_, vtime_, + io_status.hEvent); + if (!overlapped_armed) + { + (void) SetCommMask (get_handle (), EV_RXCHAR); + ResetEvent (io_status.hEvent); + } + + for (n = 0, tot = 0; ulen; ulen -= n, ptr = (char *)ptr + n) + { + DWORD ev; + COMSTAT st; + DWORD inq = 1; + + n = 0; + + if (!vtime_ && !vmin_) + inq = ulen; + else if (vtime_) + { + inq = ulen; // non-interruptible -- have to use kernel timeouts + // also note that this is not strictly correct. + // if vmin > ulen then things won't work right. + overlapped_armed = -1; + } + if (!overlapped_armed) + { + if (!ClearCommError (get_handle (), &ev, &st)) + goto err; + else if (ev) + termios_printf ("error detected %x", ev); + else if (st.cbInQue) + inq = st.cbInQue; + else if ((size_t)tot >= minchars) + break; + else if (WaitCommEvent (get_handle (), &ev, &io_status)) + { + debug_printf ("WaitCommEvent succeeded: ev %x", ev); + if (!ev) + continue; + } + else if (GetLastError () != ERROR_IO_PENDING) + goto err; + else + { + overlapped_armed = 1; + switch (WaitForMultipleObjects (2, w4, FALSE, INFINITE)) + { + case WAIT_OBJECT_0: + if (!GetOverlappedResult (get_handle (), &io_status, &n, FALSE)) + goto err; + debug_printf ("n %d, ev %x", n, ev); + break; + case WAIT_OBJECT_0 + 1: + tot = -1; + PurgeComm (get_handle (), PURGE_RXABORT); + overlapped_armed = 0; + set_sig_errno (EINTR); + goto out; + default: + goto err; + } + } + } + + overlapped_armed = 0; + ResetEvent (io_status.hEvent); + if (inq > ulen) + inq = ulen; + debug_printf ("inq %d", inq); + if (ReadFile (get_handle(), ptr, min (inq, ulen), &n, &io_status)) + /* Got something */; + else if (GetLastError () != ERROR_IO_PENDING) + goto err; + else if (!GetOverlappedResult (get_handle (), &io_status, &n, TRUE)) + goto err; + + tot += n; + debug_printf ("vtime_ %d, vmin_ %d, n %d, tot %d", vtime_, vmin_, n, tot); + if (vtime_ || !vmin_ || !n) + break; + continue; + + err: + PurgeComm (get_handle (), PURGE_RXABORT); + debug_printf ("err %E"); + if (GetLastError () == ERROR_OPERATION_ABORTED) + n = 0; + else + { + tot = -1; + __seterrno (); + break; + } + } + +out: + return tot; +} + +/* Cover function to WriteFile to provide Posix interface and semantics + (as much as possible). */ +int +fhandler_serial::raw_write (const void *ptr, size_t len) +{ + DWORD bytes_written; + + if (overlapped_armed) + PurgeComm (get_handle (), PURGE_TXABORT | PURGE_RXABORT); + ResetEvent (io_status.hEvent); + + for (;;) + { + overlapped_armed = TRUE; + if (WriteFile (get_handle(), ptr, len, &bytes_written, &io_status)) + break; + + switch (GetLastError ()) + { + case ERROR_OPERATION_ABORTED: + continue; + case ERROR_IO_PENDING: + break; + default: + goto err; + } + + if (!GetOverlappedResult (get_handle (), &io_status, &bytes_written, TRUE)) + goto err; + + break; + } + + overlapped_armed = FALSE; + return bytes_written; + +err: + __seterrno (); + return -1; +} + +void +fhandler_serial::dump (void) +{ + paranoid_printf ("here"); +} + +void +fhandler_serial::init (HANDLE f, DWORD flags, mode_t bin) +{ + fhandler_base::init (f, flags, bin); + (void) open (NULL, flags, bin ? O_BINARY : 0); +} + +int +fhandler_serial::open (const char *name, int flags, mode_t mode) +{ + int res; + COMMTIMEOUTS to; + extern BOOL reset_com; + + syscall_printf ("fhandler_serial::open (%s, %p, %p)", + get_name (), flags, mode); + + if (name && !(res = this->fhandler_base::open (flags, mode))) + return 0; + else + res = 1; + + (void) SetCommMask (get_handle (), EV_RXCHAR); + + set_r_no_interrupt (1); // Handled explicitly in read code + + overlapped_setup (); + + memset (&to, 0, sizeof (to)); + (void) SetCommTimeouts (get_handle (), &to); + + /* Reset serial port to known state of 9600-8-1-no flow control + on open for better behavior under Win 95. + + FIXME: This should only be done when explicitly opening the com + port. It should not be reset if an fd is inherited. + Using __progname in this way, to determine how far along in the + initialization we are, is really a terrible kludge and should + be fixed ASAP. + */ + extern char *__progname; + if (reset_com && __progname) + { + DCB state; + GetCommState (get_handle (), &state); + syscall_printf ("setting initial state on %s (reset_com %d)", + get_name (), reset_com); + state.BaudRate = CBR_9600; + state.ByteSize = 8; + state.StopBits = ONESTOPBIT; + state.Parity = NOPARITY; /* FIXME: correct default? */ + state.fBinary = TRUE; /* binary xfer */ + state.EofChar = 0; /* no end-of-data in binary mode */ + state.fNull = FALSE; /* don't discard nulls in binary mode */ + state.fParity = FALSE; /* ignore parity errors */ + state.fErrorChar = FALSE; + state.fTXContinueOnXoff = TRUE; /* separate TX and RX flow control */ + state.fOutX = FALSE; /* disable transmission flow control */ + state.fInX = FALSE; /* disable reception flow control */ + state.XonChar = 0x11; + state.XoffChar = 0x13; + state.fOutxDsrFlow = FALSE; /* disable DSR flow control */ + state.fRtsControl = RTS_CONTROL_ENABLE; /* ignore lead control except + DTR */ + state.fOutxCtsFlow = FALSE; /* disable output flow control */ + state.fDtrControl = DTR_CONTROL_ENABLE; /* assert DTR */ + state.fDsrSensitivity = FALSE; /* don't assert DSR */ + state.fAbortOnError = TRUE; + if (!SetCommState (get_handle (), &state)) + system_printf ("couldn't set initial state for %s, %E", get_name ()); + } + + SetCommMask (get_handle (), EV_RXCHAR); + syscall_printf ("%p = fhandler_serial::open (%s, %p, %p)", + res, get_name (), flags, mode); + return res; +} + +int +fhandler_serial::close () +{ + (void) ForceCloseHandle (io_status.hEvent); + return fhandler_base::close (); +} + +/* tcsendbreak: POSIX 7.2.2.1 */ +/* Break for 250-500 milliseconds if duration == 0 */ +/* Otherwise, units for duration are undefined */ +int +fhandler_serial::tcsendbreak (int duration) +{ + unsigned int sleeptime = 300; + + if (duration > 0) + sleeptime *= duration; + + if (SetCommBreak (get_handle ()) == 0) + return -1; + + /* FIXME: need to send zero bits during duration */ + usleep (sleeptime); + + if (ClearCommBreak (get_handle ()) == 0) + return -1; + + syscall_printf ("0 = fhandler_serial:tcsendbreak (%d)", duration); + + return 0; +} + +/* tcdrain: POSIX 7.2.2.1 */ +int +fhandler_serial::tcdrain (void) +{ + if (FlushFileBuffers (get_handle ()) == 0) + return -1; + + return 0; +} + +/* tcflow: POSIX 7.2.2.1 */ +int +fhandler_serial::tcflow (int action) +{ + DWORD win32action = 0; + DCB dcb; + char xchar; + + termios_printf ("action %d", action); + + switch (action) + { + case TCOOFF: + win32action = SETXOFF; + break; + case TCOON: + win32action = SETXON; + break; + case TCION: + case TCIOFF: + if (GetCommState (get_handle (), &dcb) == 0) + return -1; + if (action == TCION) + xchar = (dcb.XonChar ? dcb.XonChar : 0x11); + else + xchar = (dcb.XoffChar ? dcb.XoffChar : 0x13); + if (TransmitCommChar (get_handle (), xchar) == 0) + return -1; + return 0; + break; + default: + return -1; + break; + } + + if (EscapeCommFunction (get_handle (), win32action) == 0) + return -1; + + return 0; +} + +/* tcflush: POSIX 7.2.2.1 */ +int +fhandler_serial::tcflush (int queue) +{ + if (queue == TCOFLUSH || queue == TCIOFLUSH) + PurgeComm (get_handle (), PURGE_TXABORT | PURGE_TXCLEAR); + + if (queue == TCIFLUSH | queue == TCIOFLUSH) + /* Input flushing by polling until nothing turns up + (we stop after 1000 chars anyway) */ + for (int max = 1000; max > 0; max--) + { + DWORD ev; + COMSTAT st; + if (!PurgeComm (get_handle (), PURGE_RXABORT | PURGE_RXCLEAR)) + break; + Sleep (100); + if (!ClearCommError (get_handle (), &ev, &st) || !st.cbInQue) + break; + } + + return 0; +} + +/* tcsetattr: POSIX 7.2.1.1 */ +int +fhandler_serial::tcsetattr (int action, const struct termios *t) +{ + /* Possible actions: + TCSANOW: immediately change attributes. + TCSADRAIN: flush output, then change attributes. + TCSAFLUSH: flush output and discard input, then change attributes. + */ + + BOOL dropDTR = FALSE; + COMMTIMEOUTS to; + DCB ostate, state; + unsigned int ovtime = vtime_, ovmin = vmin_; + + termios_printf ("action %d", action); + if ((action == TCSADRAIN) || (action == TCSAFLUSH)) + { + FlushFileBuffers (get_handle ()); + termios_printf ("flushed file buffers"); + } + if (action == TCSAFLUSH) + PurgeComm (get_handle (), (PURGE_RXABORT | PURGE_RXCLEAR)); + + /* get default/last comm state */ + if (!GetCommState (get_handle (), &ostate)) + return -1; + + state = ostate; + + /* -------------- Set baud rate ------------------ */ + /* FIXME: WIN32 also has 14400, 56000, 128000, and 256000. + Unix also has 230400. */ + + switch (t->c_ospeed) + { + case B0: /* drop DTR */ + dropDTR = TRUE; + state.BaudRate = 0; + break; + case B110: + state.BaudRate = CBR_110; + break; + case B300: + state.BaudRate = CBR_300; + break; + case B600: + state.BaudRate = CBR_600; + break; + case B1200: + state.BaudRate = CBR_1200; + break; + case B2400: + state.BaudRate = CBR_2400; + break; + case B4800: + state.BaudRate = CBR_4800; + break; + case B9600: + state.BaudRate = CBR_9600; + break; + case B19200: + state.BaudRate = CBR_19200; + break; + case B38400: + state.BaudRate = CBR_38400; + break; + case B57600: + state.BaudRate = CBR_57600; + break; + case B115200: + state.BaudRate = CBR_115200; + break; + default: + /* Unsupported baud rate! */ + termios_printf ("Invalid t->c_ospeed %d", t->c_ospeed); + set_errno (EINVAL); + return -1; + } + + /* -------------- Set byte size ------------------ */ + + switch (t->c_cflag & CSIZE) + { + case CS5: + state.ByteSize = 5; + break; + case CS6: + state.ByteSize = 6; + break; + case CS7: + state.ByteSize = 7; + break; + case CS8: + state.ByteSize = 8; + break; + default: + /* Unsupported byte size! */ + termios_printf ("Invalid t->c_cflag byte size %d", + t->c_cflag & CSIZE); + set_errno (EINVAL); + return -1; + } + + /* -------------- Set stop bits ------------------ */ + + if (t->c_cflag & CSTOPB) + state.StopBits = TWOSTOPBITS; + else + state.StopBits = ONESTOPBIT; + + /* -------------- Set parity ------------------ */ + + if (t->c_cflag & PARENB) + state.Parity = (t->c_cflag & PARODD) ? ODDPARITY : EVENPARITY; + else + state.Parity = NOPARITY; + + state.fBinary = TRUE; /* Binary transfer */ + state.EofChar = 0; /* No end-of-data in binary mode */ + state.fNull = FALSE; /* Don't discard nulls in binary mode */ + + /* -------------- Parity errors ------------------ */ + /* fParity combines the function of INPCK and NOT IGNPAR */ + + if ((t->c_iflag & INPCK) && !(t->c_iflag & IGNPAR)) + state.fParity = TRUE; /* detect parity errors */ + else + state.fParity = FALSE; /* ignore parity errors */ + + /* Only present in Win32, Unix has no equivalent */ + state.fErrorChar = FALSE; + state.ErrorChar = 0; + + /* -------------- Set software flow control ------------------ */ + /* Set fTXContinueOnXoff to FALSE. This prevents the triggering of a + premature XON when the remote device interprets a received character + as XON (same as IXANY on the remote side). Otherwise, a TRUE + value separates the TX and RX functions. */ + + state.fTXContinueOnXoff = TRUE; /* separate TX and RX flow control */ + + /* Transmission flow control */ + if (t->c_iflag & IXON) + state.fOutX = TRUE; /* enable */ + else + state.fOutX = FALSE; /* disable */ + + /* Reception flow control */ + if (t->c_iflag & IXOFF) + state.fInX = TRUE; /* enable */ + else + state.fInX = FALSE; /* disable */ + + /* XoffLim and XonLim are left at default values */ + + state.XonChar = (t->c_cc[VSTART] ? t->c_cc[VSTART] : 0x11); + state.XoffChar = (t->c_cc[VSTOP] ? t->c_cc[VSTOP] : 0x13); + + /* -------------- Set hardware flow control ------------------ */ + + /* Disable DSR flow control */ + state.fOutxDsrFlow = FALSE; + + /* Some old flavors of Unix automatically enabled hardware flow + control when software flow control was not enabled. Since newer + Unices tend to require explicit setting of hardware flow-control, + this is what we do. */ + + /* RTS/CTS flow control */ + if (t->c_cflag & CRTSCTS) + { /* enable */ + state.fOutxCtsFlow = TRUE; + state.fRtsControl = RTS_CONTROL_HANDSHAKE; + } + else + { /* disable */ + state.fRtsControl = RTS_CONTROL_ENABLE; + state.fOutxCtsFlow = FALSE; + } + + if (t->c_cflag & CRTSXOFF) + state.fRtsControl = RTS_CONTROL_HANDSHAKE; + + /* -------------- DTR ------------------ */ + /* Assert DTR on device open */ + + state.fDtrControl = DTR_CONTROL_ENABLE; + + /* -------------- DSR ------------------ */ + /* Assert DSR at the device? */ + + if (t->c_cflag & CLOCAL) + state.fDsrSensitivity = FALSE; /* no */ + else + state.fDsrSensitivity = TRUE; /* yes */ + + /* -------------- Error handling ------------------ */ + /* Since read/write operations terminate upon error, we + will use ClearCommError() to resume. */ + + state.fAbortOnError = TRUE; + + /* -------------- Set state and exit ------------------ */ + if (memcmp (&ostate, &state, sizeof (state)) != 0) + SetCommState (get_handle (), &state); + + set_r_binary ((t->c_iflag & IGNCR) ? 0 : 1); + set_w_binary ((t->c_oflag & ONLCR) ? 0 : 1); + + if (dropDTR == TRUE) + EscapeCommFunction (get_handle (), CLRDTR); + else + { + /* FIXME: Sometimes when CLRDTR is set, setting + state.fDtrControl = DTR_CONTROL_ENABLE will fail. This + is a problem since a program might want to change some + parameters while DTR is still down. */ + + EscapeCommFunction (get_handle (), SETDTR); + } + + /* + The following documentation on was taken from "Linux Serial Programming + HOWTO". It explains how MIN (t->c_cc[VMIN] || vmin_) and TIME + (t->c_cc[VTIME] || vtime_) is to be used. + + In non-canonical input processing mode, input is not assembled into + lines and input processing (erase, kill, delete, etc.) does not + occur. Two parameters control the behavior of this mode: c_cc[VTIME] + sets the character timer, and c_cc[VMIN] sets the minimum number of + characters to receive before satisfying the read. + + If MIN > 0 and TIME = 0, MIN sets the number of characters to receive + before the read is satisfied. As TIME is zero, the timer is not used. + + If MIN = 0 and TIME > 0, TIME serves as a timeout value. The read will + be satisfied if a single character is read, or TIME is exceeded (t = + TIME *0.1 s). If TIME is exceeded, no character will be returned. + + If MIN > 0 and TIME > 0, TIME serves as an inter-character timer. The + read will be satisfied if MIN characters are received, or the time + between two characters exceeds TIME. The timer is restarted every time + a character is received and only becomes active after the first + character has been received. + + If MIN = 0 and TIME = 0, read will be satisfied immediately. The + number of characters currently available, or the number of characters + requested will be returned. According to Antonino (see contributions), + you could issue a fcntl(fd, F_SETFL, FNDELAY); before reading to get + the same result. + */ + + if (t->c_lflag & ICANON) + { + vmin_ = MAXDWORD; + vtime_ = 0; + } + else + { + vtime_ = t->c_cc[VTIME] * 100; + vmin_ = t->c_cc[VMIN]; + } + + debug_printf ("vtime %d, vmin %d\n", vtime_, vmin_); + + if (ovmin == vmin_ && ovtime == vtime_) + return 0; + + memset (&to, 0, sizeof (to)); + + if ((vmin_ > 0) && (vtime_ == 0)) + { + /* Returns immediately with whatever is in buffer on a ReadFile(); + or blocks if nothing found. We will keep calling ReadFile(); until + vmin_ characters are read */ + to.ReadIntervalTimeout = to.ReadTotalTimeoutMultiplier = MAXDWORD; + to.ReadTotalTimeoutConstant = MAXDWORD - 1; + } + else if ((vmin_ == 0) && (vtime_ > 0)) + { + /* set timeoout constant appropriately and we will only try to + read one character in ReadFile() */ + to.ReadTotalTimeoutConstant = vtime_; + to.ReadIntervalTimeout = to.ReadTotalTimeoutMultiplier = MAXDWORD; + } + else if ((vmin_ > 0) && (vtime_ > 0)) + { + /* time applies to the interval time for this case */ + to.ReadIntervalTimeout = vtime_; + } + else if ((vmin_ == 0) && (vtime_ == 0)) + { + /* returns immediately with whatever is in buffer as per + Time-Outs docs in Win32 SDK API docs */ + to.ReadIntervalTimeout = MAXDWORD; + } + + debug_printf ("ReadTotalTimeoutConstant %d, ReadIntervalTimeout %d, ReadTotalTimeoutMultiplier %d", + to.ReadTotalTimeoutConstant, to.ReadIntervalTimeout, to.ReadTotalTimeoutMultiplier); + int res = SetCommTimeouts (get_handle (), &to); + if (!res) + { + system_printf ("SetCommTimeout failed, %E"); + __seterrno (); + return -1; + } + + return 0; +} + +/* tcgetattr: POSIX 7.2.1.1 */ +int +fhandler_serial::tcgetattr (struct termios *t) +{ + DCB state; + + /* Get current Win32 comm state */ + if (GetCommState (get_handle (), &state) == 0) + return -1; + + /* for safety */ + memset (t, 0, sizeof (*t)); + + /* -------------- Baud rate ------------------ */ + + switch (state.BaudRate) + { + case 0: + /* FIXME: need to drop DTR */ + t->c_cflag = t->c_ospeed = t->c_ispeed = B0; + break; + case CBR_110: + t->c_cflag = t->c_ospeed = t->c_ispeed = B110; + break; + case CBR_300: + t->c_cflag = t->c_ospeed = t->c_ispeed = B300; + break; + case CBR_600: + t->c_cflag = t->c_ospeed = t->c_ispeed = B600; + break; + case CBR_1200: + t->c_cflag = t->c_ospeed = t->c_ispeed = B1200; + break; + case CBR_2400: + t->c_cflag = t->c_ospeed = t->c_ispeed = B2400; + break; + case CBR_4800: + t->c_cflag = t->c_ospeed = t->c_ispeed = B4800; + break; + case CBR_9600: + t->c_cflag = t->c_ospeed = t->c_ispeed = B9600; + break; + case CBR_19200: + t->c_cflag = t->c_ospeed = t->c_ispeed = B19200; + break; + case CBR_38400: + t->c_cflag = t->c_ospeed = t->c_ispeed = B38400; + break; + case CBR_57600: + t->c_cflag = t->c_ospeed = t->c_ispeed = B57600; + break; + case CBR_115200: + t->c_cflag = t->c_ospeed = t->c_ispeed = B115200; + break; + default: + /* Unsupported baud rate! */ + termios_printf ("Invalid baud rate %d", state.BaudRate); + set_errno (EINVAL); + return -1; + } + + /* -------------- Byte size ------------------ */ + + switch (state.ByteSize) + { + case 5: + t->c_cflag |= CS5; + break; + case 6: + t->c_cflag |= CS6; + break; + case 7: + t->c_cflag |= CS7; + break; + case 8: + t->c_cflag |= CS8; + break; + default: + /* Unsupported byte size! */ + termios_printf ("Invalid byte size %d", state.ByteSize); + set_errno (EINVAL); + return -1; + } + + /* -------------- Stop bits ------------------ */ + + if (state.StopBits == TWOSTOPBITS) + t->c_cflag |= CSTOPB; + + /* -------------- Parity ------------------ */ + + if (state.Parity == ODDPARITY) + t->c_cflag |= (PARENB | PARODD); + if (state.Parity == EVENPARITY) + t->c_cflag |= PARENB; + + /* -------------- Parity errors ------------------ */ + + /* fParity combines the function of INPCK and NOT IGNPAR */ + if (state.fParity == TRUE) + t->c_iflag |= INPCK; + else + t->c_iflag |= IGNPAR; /* not necessarily! */ + + /* -------------- Software flow control ------------------ */ + + /* transmission flow control */ + if (state.fOutX) + t->c_iflag |= IXON; + + /* reception flow control */ + if (state.fInX) + t->c_iflag |= IXOFF; + + t->c_cc[VSTART] = (state.XonChar ? state.XonChar : 0x11); + t->c_cc[VSTOP] = (state.XoffChar ? state.XoffChar : 0x13); + + /* -------------- Hardware flow control ------------------ */ + /* Some old flavors of Unix automatically enabled hardware flow + control when software flow control was not enabled. Since newer + Unices tend to require explicit setting of hardware flow-control, + this is what we do. */ + + /* Input flow-control */ + if ((state.fRtsControl == RTS_CONTROL_HANDSHAKE) && + (state.fOutxCtsFlow == TRUE)) + t->c_cflag |= CRTSCTS; + if (state.fRtsControl == RTS_CONTROL_HANDSHAKE) + t->c_cflag |= CRTSXOFF; + + /* -------------- CLOCAL --------------- */ + /* DSR is only lead toggled only by CLOCAL. Check it to see if + CLOCAL was called. */ + /* FIXME: If tcsetattr() hasn't been called previously, this may + give a false CLOCAL. */ + + if (state.fDsrSensitivity == FALSE) + t->c_cflag |= CLOCAL; + + /* FIXME: need to handle IGNCR */ +#if 0 + if (!get_r_binary ()) + t->c_iflag |= IGNCR; +#endif + + if (!get_w_binary ()) + t->c_oflag |= ONLCR; + + debug_printf ("vmin_ %d, vtime_ %d", vmin_, vtime_); + if (vmin_ == MAXDWORD) + { + t->c_lflag |= ICANON; + t->c_cc[VTIME] = t->c_cc[VMIN] = 0; + } + else + { + t->c_cc[VTIME] = vtime_ / 100; + t->c_cc[VMIN] = vmin_; + } + + return 0; +} + +void +fhandler_serial::fixup_after_fork (HANDLE parent) +{ + if (get_close_on_exec ()) + this->fhandler_base::fixup_after_fork (parent); + overlapped_setup (); + debug_printf ("io_status.hEvent %p", io_status.hEvent); +} + +int +fhandler_serial::de_linearize (const char *buf, const char *unix_name, + const char *win32_name) +{ + int res = fhandler_base::de_linearize (buf, unix_name, win32_name); + overlapped_setup (); + debug_printf ("io_status.hEvent %p", io_status.hEvent); + return res; +} + +int +fhandler_serial::dup (fhandler_base *child) +{ + fhandler_serial *fhc = (fhandler_serial *) child; + overlapped_setup (); + fhc->vmin_ = vmin_; + fhc->vtime_ = vtime_; + return fhandler_base::dup (child); +} diff --git a/winsup/cygwin/fhandler_tape.cc b/winsup/cygwin/fhandler_tape.cc new file mode 100644 index 000000000..7b25e9f4b --- /dev/null +++ b/winsup/cygwin/fhandler_tape.cc @@ -0,0 +1,829 @@ +/* fhandler_tape.cc. See fhandler.h for a description of the fhandler + classes. + + Copyright 1999, 2000 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include +#include "winsup.h" + +#include + +/**********************************************************************/ +/* fhandler_dev_tape */ + +void +fhandler_dev_tape::clear (void) +{ + norewind = 0; + lasterr = 0; + fhandler_dev_raw::clear (); +} + +int +fhandler_dev_tape::is_eom (int win_error) +{ + int ret = ((win_error == ERROR_END_OF_MEDIA) + || (win_error == ERROR_EOM_OVERFLOW) + || (win_error == ERROR_NO_DATA_DETECTED)); + if (ret) + debug_printf ("end of medium"); + return ret; +} + +int +fhandler_dev_tape::is_eof (int win_error) +{ + int ret = ((win_error == ERROR_FILEMARK_DETECTED) + || (win_error == ERROR_SETMARK_DETECTED)); + if (ret) + debug_printf ("end of file"); + return ret; +} + +fhandler_dev_tape::fhandler_dev_tape (const char *name, int unit) : fhandler_dev_raw (FH_TAPE, name, unit) +{ + set_cb (sizeof *this); +} + +int +fhandler_dev_tape::open (const char *path, int flags, mode_t) +{ + int ret; + int minor; + + if (get_device_number (path, minor) != FH_TAPE) + { + set_errno (EINVAL); + return -1; + } + + norewind = (minor >= 128); + devbufsiz = 1L; + + ret = fhandler_dev_raw::open (path, flags); + if (ret) + { + struct mtget get; + struct mtop op; + struct mtpos pos; + + if (! ioctl (MTIOCGET, &get)) + { + devbufsiz = get.mt_dsreg; + } + + if (devbufsiz > 1L) + { + devbuf = new char [ devbufsiz ]; + } + + /* + * The following rewind in position 0 solves a problem which appears + * in case of multi volume archives: The last ReadFile on first medium + * returns ERROR_NO_DATA_DETECTED. After media change, all subsequent + * ReadFile calls return ERROR_NO_DATA_DETECTED, too! + * The call to tape_set_pos seems to reset some internal flags! + */ + if ((! ioctl (MTIOCPOS, &pos)) && (! pos.mt_blkno)) + { + op.mt_op = MTREW; + ioctl (MTIOCTOP, &op); + } + + if (flags & O_APPEND) + { + /* In append mode, seek to beginning of next filemark */ + op.mt_op = MTFSFM; + op.mt_count = 1; + ioctl (MTIOCTOP, &op); + } + } + + return ret; +} + +int +fhandler_dev_tape::close (void) +{ + struct mtop op; + int ret = 0; + + if (is_writing) + { + ret = writebuf (); + if ((has_written) && (! eom_detected)) + { + /* if last operation was writing, write a filemark */ + debug_printf ("writing filemark\n"); + op.mt_op = MTWEOF; + op.mt_count = 1; + ioctl (MTIOCTOP, &op); + } + } + + // To protected reads on signaling (e.g. Ctrl-C) + eof_detected = 1; + + if (! norewind) + { + debug_printf ("rewinding\n"); + op.mt_op = MTREW; + ioctl (MTIOCTOP, &op); + } + + if (ret) + { + fhandler_dev_raw::close (); + return ret; + } + + return fhandler_dev_raw::close (); +} + +int +fhandler_dev_tape::fstat (struct stat *buf) +{ + int ret; + + if (! (ret = fhandler_dev_raw::fstat (buf))) + { + struct mtget get; + + if (! ioctl (MTIOCGET, &get)) + { + buf->st_blocks = get.mt_capacity / buf->st_blksize; + } + } + + return ret; +} + +off_t +fhandler_dev_tape::lseek (off_t offset, int whence) +{ + struct mtop op; + struct mtpos pos; + + debug_printf ("lseek (%s, %d, %d)\n", get_name (), offset, whence); + + writebuf (); + eom_detected = eof_detected = 0; + lastblk_to_read = 0; + devbufstart = devbufend = 0; + + if (ioctl (MTIOCPOS, &pos)) + { + return (off_t) -1; + } + + switch (whence) + { + case SEEK_END: + op.mt_op = MTFSF; + op.mt_count = 1; + if (ioctl (MTIOCTOP, &op)) + return -1; + break; + case SEEK_SET: + if (whence == SEEK_SET && offset < 0) + { + set_errno (EINVAL); + return -1; + } + break; + case SEEK_CUR: + break; + default: + set_errno (EINVAL); + return -1; + } + + op.mt_op = MTFSR; + op.mt_count = offset / devbufsiz + - (whence == SEEK_SET ? pos.mt_blkno : 0); + + if (op.mt_count < 0) + { + op.mt_op = MTBSR; + op.mt_count = -op.mt_count; + } + + if (ioctl (MTIOCTOP, &op) || ioctl (MTIOCPOS, &pos)) + return -1; + + return (pos.mt_blkno * devbufsiz); +} + +int +fhandler_dev_tape::dup (fhandler_base *child) +{ + fhandler_dev_tape *fhc = (fhandler_dev_tape *) child; + + fhc->norewind = norewind; + fhc->lasterr = lasterr; + return fhandler_dev_raw::dup (child); +} + +int +fhandler_dev_tape::ioctl (unsigned int cmd, void *buf) +{ + int ret = NO_ERROR; + unsigned long block; + + if (cmd == MTIOCTOP) + { + struct mtop *op = (struct mtop *) buf; + + if (! op) + ret = ERROR_INVALID_PARAMETER; + else + switch (op->mt_op) + { + case MTRESET: + break; + case MTFSF: + ret = tape_set_pos (TAPE_SPACE_FILEMARKS, op->mt_count); + break; + case MTBSF: + ret = tape_set_pos (TAPE_SPACE_FILEMARKS, -op->mt_count); + break; + case MTFSR: + ret = tape_set_pos (TAPE_SPACE_RELATIVE_BLOCKS, op->mt_count); + break; + case MTBSR: + ret = tape_set_pos (TAPE_SPACE_RELATIVE_BLOCKS, -op->mt_count); + break; + case MTWEOF: + ret = tape_write_marks (TAPE_FILEMARKS, op->mt_count); + break; + case MTREW: + ret = tape_set_pos (TAPE_REWIND, 0); + break; + case MTOFFL: + ret = tape_prepare (TAPE_UNLOAD); + break; + case MTNOP: + break; + case MTRETEN: + if (! tape_get_feature (TAPE_DRIVE_END_OF_DATA)) + { + ret = ERROR_INVALID_PARAMETER; + break; + } + if (! (ret = tape_set_pos (TAPE_REWIND, 0, FALSE))) + { + ret = tape_prepare (TAPE_TENSION); + } + break; + case MTBSFM: + ret = tape_set_pos (TAPE_SPACE_FILEMARKS, -op->mt_count, TRUE); + break; + case MTFSFM: + ret = tape_set_pos (TAPE_SPACE_FILEMARKS, op->mt_count, TRUE); + break; + case MTEOM: + if (tape_get_feature (TAPE_DRIVE_END_OF_DATA)) + { + ret = tape_set_pos (TAPE_SPACE_END_OF_DATA, 0); + } + else + { + ret = tape_set_pos (TAPE_SPACE_FILEMARKS, 32767); + } + break; + case MTERASE: + ret = tape_erase (TAPE_ERASE_SHORT); + break; + case MTRAS1: + case MTRAS2: + case MTRAS3: + ret = ERROR_INVALID_PARAMETER; + break; + case MTSETBLK: + { + long min, max; + + if (! tape_get_feature (TAPE_DRIVE_SET_BLOCK_SIZE)) + { + ret = ERROR_INVALID_PARAMETER; + break; + } + ret = tape_get_blocksize (&min, NULL, &max, NULL); + if (ret) + { + break; + } + if (op->mt_count < min || op->mt_count > max) + { + ret = ERROR_INVALID_PARAMETER; + break; + } + if (devbuf && (size_t) op->mt_count == devbufsiz) + { + ret = 0; + break; + } + if (devbuf && (size_t) op->mt_count < devbufend - devbufstart) + { + ret = ERROR_INVALID_PARAMETER; + break; + } + if (! (ret = tape_set_blocksize (op->mt_count))) + { + char *buf = new char [ op->mt_count ]; + if (devbuf) + { + memcpy(buf,devbuf + devbufstart, devbufend - devbufstart); + devbufend -= devbufstart; + delete [] devbuf; + } + else + { + devbufend = 0; + } + devbufstart = 0; + devbuf = buf; + devbufsiz = op->mt_count; + } + } + break; + case MTSETDENSITY: + ret = ERROR_INVALID_PARAMETER; + break; + case MTSEEK: + if (tape_get_feature (TAPE_DRIVE_ABSOLUTE_BLK)) + { + ret = tape_set_pos (TAPE_ABSOLUTE_BLOCK, op->mt_count); + break; + } + if (! (ret = tape_get_pos (&block))) + { + ret = tape_set_pos (TAPE_SPACE_RELATIVE_BLOCKS, + op->mt_count - block); + } + break; + case MTTELL: + if (! (ret = tape_get_pos (&block))) + op->mt_count = block; + break; + case MTSETDRVBUFFER: + ret = ERROR_INVALID_PARAMETER; + break; + case MTFSS: + ret = tape_set_pos (TAPE_SPACE_SETMARKS, op->mt_count); + break; + case MTBSS: + ret = tape_set_pos (TAPE_SPACE_SETMARKS, -op->mt_count); + break; + case MTWSM: + ret = tape_write_marks (TAPE_SETMARKS, op->mt_count); + break; + case MTLOCK: + ret = tape_prepare (TAPE_LOCK); + break; + case MTUNLOCK: + ret = tape_prepare (TAPE_UNLOCK); + break; + case MTLOAD: + ret = tape_prepare (TAPE_LOAD); + break; + case MTUNLOAD: + ret = tape_prepare (TAPE_UNLOAD); + break; + case MTCOMPRESSION: + ret = tape_compression (op->mt_count); + break; + case MTSETPART: + case MTMKPART: + default: + ret = ERROR_INVALID_PARAMETER; + break; + } + } + else if (cmd == MTIOCGET) + ret = tape_status ((struct mtget *) buf); + else if (cmd == MTIOCPOS) + { + ret = ERROR_INVALID_PARAMETER; + if (buf && (ret = tape_get_pos (&block))) + ((struct mtpos *) buf)->mt_blkno = block; + } + else + return fhandler_dev_raw::ioctl (cmd, buf); + + if (ret != NO_ERROR) + { + SetLastError (ret); + __seterrno (); + return -1; + } + + return 0; +} + +/* ------------------------------------------------------------------ */ +/* Private functions used by `ioctl' */ +/* ------------------------------------------------------------------ */ + +static int +tape_error (DWORD lasterr, const char *txt) +{ + if (lasterr) + debug_printf ("%s: error: %d\n", txt, lasterr); + + return lasterr; +} + +int +fhandler_dev_tape::tape_write_marks (int marktype, DWORD len) +{ + syscall_printf ("write_tapemark\n"); + while (((lasterr = WriteTapemark (get_handle (), + marktype, + len, + FALSE)) == ERROR_MEDIA_CHANGED) + || (lasterr == ERROR_BUS_RESET)) + ; + + return tape_error (lasterr, "tape_write_marks"); +} + +int +fhandler_dev_tape::tape_get_pos (unsigned long *ret) +{ + DWORD part, low, high; + + while (((lasterr = GetTapePosition (get_handle (), + TAPE_ABSOLUTE_POSITION, + &part, + &low, + &high)) == ERROR_MEDIA_CHANGED) + || (lasterr == ERROR_BUS_RESET)) + ; + if (! tape_error (lasterr, "tape_get_pos") && ret) + *ret = low; + + return lasterr; +} + +static int _tape_set_pos (HANDLE hTape, int mode, long count) +{ + int err; + + while (((err = SetTapePosition (hTape, + mode, + 1, + count, + count < 0 ? -1 : 0, + FALSE)) == ERROR_MEDIA_CHANGED) + || (err == ERROR_BUS_RESET)) + ; + + return err; +} + +int +fhandler_dev_tape::tape_set_pos (int mode, long count, BOOLEAN sfm_func) +{ + unsigned long pos, tgtpos; + + switch (mode) + { + case TAPE_SPACE_RELATIVE_BLOCKS: + lasterr = tape_get_pos (&pos); + + if (lasterr) + return lasterr; + + tgtpos = pos + count; + + while (((lasterr = _tape_set_pos (get_handle (), + mode, + count)) == ERROR_FILEMARK_DETECTED) + || (lasterr == ERROR_SETMARK_DETECTED)) + { + lasterr = tape_get_pos (&pos); + if (lasterr) + return lasterr; + count = tgtpos - pos; + } + + if (lasterr == ERROR_BEGINNING_OF_MEDIA && ! tgtpos) + lasterr = NO_ERROR; + + break; + case TAPE_SPACE_FILEMARKS: + if (count < 0) + { + if (pos > 0) + { + if ((! _tape_set_pos (get_handle (), + TAPE_SPACE_RELATIVE_BLOCKS, + -1)) + || (sfm_func)) + ++count; + _tape_set_pos (get_handle (), TAPE_SPACE_RELATIVE_BLOCKS, 1); + } + + while (! (lasterr = _tape_set_pos (get_handle (), mode, -1)) + && count++ < 0) + ; + + if (lasterr == ERROR_BEGINNING_OF_MEDIA) + { + if (! count) + lasterr = NO_ERROR; + } + else if (! sfm_func) + lasterr = _tape_set_pos (get_handle (), mode, 1); + } + else + { + if (sfm_func) + { + if (_tape_set_pos (get_handle (), + TAPE_SPACE_RELATIVE_BLOCKS, + 1) == ERROR_FILEMARK_DETECTED) + ++count; + _tape_set_pos (get_handle (), TAPE_SPACE_RELATIVE_BLOCKS, -1); + } + + if (! (lasterr = _tape_set_pos (get_handle (), mode, count)) + && sfm_func) + lasterr = _tape_set_pos (get_handle (), mode, -1); + } + break; + case TAPE_SPACE_SETMARKS: + case TAPE_ABSOLUTE_BLOCK: + case TAPE_SPACE_END_OF_DATA: + case TAPE_REWIND: + lasterr = _tape_set_pos (get_handle (), mode, count); + break; + } + + return tape_error (lasterr, "tape_set_pos"); +} + +int +fhandler_dev_tape::tape_erase (int mode) +{ + DWORD varlen; + TAPE_GET_DRIVE_PARAMETERS dp; + + while (((lasterr = GetTapeParameters (get_handle (), + GET_TAPE_DRIVE_INFORMATION, + (varlen = sizeof dp, &varlen), + &dp)) == ERROR_MEDIA_CHANGED) + || (lasterr == ERROR_BUS_RESET)) + ; + + switch (mode) + { + case TAPE_ERASE_SHORT: + if (! lasterr && ! (dp.FeaturesLow & TAPE_DRIVE_ERASE_SHORT)) + mode = TAPE_ERASE_LONG; + break; + case TAPE_ERASE_LONG: + if (! lasterr && ! (dp.FeaturesLow & TAPE_DRIVE_ERASE_LONG)) + mode = TAPE_ERASE_SHORT; + break; + } + + return tape_error (EraseTape (get_handle (), mode, FALSE), "tape_erase"); +} + +int +fhandler_dev_tape::tape_prepare (int action) +{ + while (((lasterr = PrepareTape (get_handle (), + action, + FALSE)) == ERROR_MEDIA_CHANGED) + || (lasterr == ERROR_BUS_RESET)) + ; + return tape_error (lasterr, "tape_prepare"); +} + +BOOLEAN +fhandler_dev_tape::tape_get_feature (DWORD parm) +{ + DWORD varlen; + TAPE_GET_DRIVE_PARAMETERS dp; + + while (((lasterr = GetTapeParameters (get_handle (), + GET_TAPE_DRIVE_INFORMATION, + (varlen = sizeof dp, &varlen), + &dp)) == ERROR_MEDIA_CHANGED) + || (lasterr == ERROR_BUS_RESET)) + ; + + if (lasterr) + return FALSE; + + return ((parm & TAPE_DRIVE_HIGH_FEATURES) + ? ((dp.FeaturesHigh & parm) != 0) + : ((dp.FeaturesLow & parm) != 0)); +} + +int +fhandler_dev_tape::tape_get_blocksize (long *min, long *def, long *max, long *cur) +{ + DWORD varlen; + TAPE_GET_DRIVE_PARAMETERS dp; + TAPE_GET_MEDIA_PARAMETERS mp; + + while (((lasterr = GetTapeParameters (get_handle (), + GET_TAPE_DRIVE_INFORMATION, + (varlen = sizeof dp, &varlen), + &dp)) == ERROR_MEDIA_CHANGED) + || (lasterr == ERROR_BUS_RESET)) + ; + + if (lasterr) + return tape_error (lasterr, "tape_get_blocksize"); + + while (((lasterr = GetTapeParameters (get_handle (), + GET_TAPE_MEDIA_INFORMATION, + (varlen = sizeof mp, &varlen), + &mp)) == ERROR_MEDIA_CHANGED) + || (lasterr == ERROR_BUS_RESET)) + ; + + if (lasterr) + return tape_error (lasterr, "tape_get_blocksize"); + + if (min) + *min = (long) dp.MinimumBlockSize; + if (def) + *def = (long) dp.DefaultBlockSize; + if (max) + *max = (long) dp.MaximumBlockSize; + if (cur) + *cur = (long) mp.BlockSize; + + return tape_error (lasterr, "tape_get_blocksize"); +} + +int +fhandler_dev_tape::tape_set_blocksize (long count) +{ + long min, max; + TAPE_SET_MEDIA_PARAMETERS mp; + + lasterr = tape_get_blocksize (&min, NULL, &max, NULL); + + if (lasterr) + return lasterr; + + if (count < min || count > max) + return tape_error (ERROR_INVALID_PARAMETER, "tape_set_blocksize"); + + mp.BlockSize = count; + + return tape_error (SetTapeParameters (get_handle (), + SET_TAPE_MEDIA_INFORMATION, + &mp), + "tape_set_blocksize"); +} + +static long long +get_ll (PLARGE_INTEGER i) +{ + long long l = 0; + + l = i->HighPart; + l <<= 32; + l |= i->LowPart; + return l; +} + +int +fhandler_dev_tape::tape_status (struct mtget *get) +{ + DWORD varlen; + TAPE_GET_DRIVE_PARAMETERS dp; + TAPE_GET_MEDIA_PARAMETERS mp; + int notape = 0; + + if (! get) + return ERROR_INVALID_PARAMETER; + + while (((lasterr = GetTapeParameters (get_handle (), + GET_TAPE_DRIVE_INFORMATION, + (varlen = sizeof dp, &varlen), + &dp)) == ERROR_MEDIA_CHANGED) + || (lasterr == ERROR_BUS_RESET)) + ; + + if ((lasterr) || (lasterr = GetTapeParameters (get_handle (), + GET_TAPE_MEDIA_INFORMATION, + (varlen = sizeof mp, &varlen), + &mp))) + notape = 1; + + memset (get, 0, sizeof *get); + + get->mt_type = MT_ISUNKNOWN; + + if (! notape && (dp.FeaturesLow & TAPE_DRIVE_TAPE_REMAINING)) + { + get->mt_remaining = get_ll (&mp.Remaining); + get->mt_resid = get->mt_remaining >> 10; + } + + if ((dp.FeaturesHigh & TAPE_DRIVE_SET_BLOCK_SIZE) && ! notape) + get->mt_dsreg = mp.BlockSize; + else + get->mt_dsreg = dp.DefaultBlockSize; + + if (notape) + get->mt_gstat |= GMT_DR_OPEN (-1); + + if (! notape) + { + if (dp.FeaturesLow & TAPE_DRIVE_GET_ABSOLUTE_BLK) + tape_get_pos ((unsigned long *) &get->mt_blkno); + + if (! get->mt_blkno) + get->mt_gstat |= GMT_BOT (-1); + + get->mt_gstat |= GMT_ONLINE (-1); + + if ((dp.FeaturesLow & TAPE_DRIVE_WRITE_PROTECT) && mp.WriteProtected) + get->mt_gstat |= GMT_WR_PROT (-1); + + if (dp.FeaturesLow & TAPE_DRIVE_TAPE_CAPACITY) + get->mt_capacity = get_ll (&mp.Capacity); + } + + if ((dp.FeaturesLow & TAPE_DRIVE_COMPRESSION) && dp.Compression) + get->mt_gstat |= GMT_HW_COMP (-1); + + if ((dp.FeaturesLow & TAPE_DRIVE_ECC) && dp.ECC) + get->mt_gstat |= GMT_HW_ECC (-1); + + if ((dp.FeaturesLow & TAPE_DRIVE_PADDING) && dp.DataPadding) + get->mt_gstat |= GMT_PADDING (-1); + + if ((dp.FeaturesLow & TAPE_DRIVE_REPORT_SMKS) && dp.ReportSetmarks) + get->mt_gstat |= GMT_IM_REP_EN (-1); + + get->mt_erreg = lasterr; + + get->mt_minblksize = dp.MinimumBlockSize; + get->mt_maxblksize = dp.MaximumBlockSize; + get->mt_defblksize = dp.DefaultBlockSize; + get->mt_featureslow = dp.FeaturesLow; + get->mt_featureshigh = dp.FeaturesHigh; + + return 0; +} + +int +fhandler_dev_tape::tape_compression (long count) +{ + DWORD varlen; + TAPE_GET_DRIVE_PARAMETERS dpg; + TAPE_SET_DRIVE_PARAMETERS dps; + + while (((lasterr = GetTapeParameters (get_handle (), + GET_TAPE_DRIVE_INFORMATION, + (varlen = sizeof dpg, &varlen), + &dpg)) == ERROR_MEDIA_CHANGED) + || (lasterr == ERROR_BUS_RESET)) + ; + + if (lasterr) + return tape_error (lasterr, "tape_compression"); + + if (! (dpg.FeaturesLow & TAPE_DRIVE_COMPRESSION)) + return ERROR_INVALID_PARAMETER; + + if (count) + { + dps.ECC = dpg.ECC; + dps.Compression = count ? TRUE : FALSE; + dps.DataPadding = dpg.DataPadding; + dps.ReportSetmarks = dpg.ReportSetmarks; + dps.EOTWarningZoneSize = dpg.EOTWarningZoneSize; + lasterr = SetTapeParameters (get_handle (), + SET_TAPE_DRIVE_INFORMATION, + &dps); + + if (lasterr) + return tape_error (lasterr, "tape_compression"); + + dpg.Compression = dps.Compression; + } + + return 0; +} + diff --git a/winsup/cygwin/fhandler_termios.cc b/winsup/cygwin/fhandler_termios.cc new file mode 100644 index 000000000..5c34178e6 --- /dev/null +++ b/winsup/cygwin/fhandler_termios.cc @@ -0,0 +1,293 @@ +/* fhandler_termios.cc + + Copyright 1996, 1997, 1998 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include +#include "winsup.h" +#include + +/* Common functions shared by tty/console */ + +void +fhandler_termios::tcinit (tty_min *this_tc, int force) +{ + /* Initial termios values */ + + tc = this_tc; + + if (force || !TTYISSETF (INITIALIZED)) + { + tc->ti.c_iflag = BRKINT | ICRNL | IXON; + tc->ti.c_oflag = OPOST | ONLCR; + tc->ti.c_cflag = B38400 | CS8 | CREAD; + tc->ti.c_lflag = ISIG | ICANON | ECHO | IEXTEN; + + tc->ti.c_cc[VDISCARD] = CFLUSH; + tc->ti.c_cc[VEOL] = CEOL; + tc->ti.c_cc[VEOL2] = CEOL2; + tc->ti.c_cc[VEOF] = CEOF; + tc->ti.c_cc[VERASE] = CERASE; + tc->ti.c_cc[VINTR] = CINTR; + tc->ti.c_cc[VKILL] = CKILL; + tc->ti.c_cc[VLNEXT] = CLNEXT; + tc->ti.c_cc[VMIN] = 1; + tc->ti.c_cc[VQUIT] = CQUIT; + tc->ti.c_cc[VREPRINT] = CRPRNT; + tc->ti.c_cc[VSTART] = CSTART; + tc->ti.c_cc[VSTOP] = CSTOP; + tc->ti.c_cc[VSUSP] = CSUSP; + tc->ti.c_cc[VSWTC] = CSWTCH; + tc->ti.c_cc[VTIME] = 0; + tc->ti.c_cc[VWERASE] = CWERASE; + + tc->ti.c_ispeed = tc->ti.c_ospeed = B38400; + tc->pgid = myself->pgid; + TTYSETF (INITIALIZED); + } +} + +int +fhandler_termios::tcsetpgrp (const pid_t pgid) +{ + termios_printf ("pgid %d, sid %d, tsid %d", pgid, + myself->sid, tc->getsid ()); + if (myself->sid != tc->getsid ()) + { + set_errno (EPERM); + return -1; + } + tc->setpgid (pgid); + return 0; +} + +int +fhandler_termios::tcgetpgrp () +{ + return tc->pgid; +} + +void +fhandler_termios::set_ctty (int ttynum, int flags) +{ + if ((myself->ctty < 0 || myself->ctty == ttynum) && !(flags & O_NOCTTY)) + { + myself->ctty = ttynum; + syscall_printf ("attached tty%d sid %d, pid %d, tty->pgid %d, tty->sid %d", + ttynum, myself->sid, myself->pid, tc->pgid, tc->getsid ()); + + pinfo *p = procinfo (tc->getsid ()); + if (myself->sid == myself->pid && + (p == myself || !proc_exists (p))) + { + paranoid_printf ("resetting tty%d sid. Was %d, now %d. pgid was %d, now %d.", + ttynum, tc->getsid(), myself->sid, tc->getpgid (), myself->pgid); + /* We are the session leader */ + tc->setsid (myself->sid); + tc->setpgid (myself->pgid); + } + else + myself->sid = tc->getsid (); + if (tc->getpgid () == 0) + tc->setpgid (myself->pgid); + } +} + +int +fhandler_termios::bg_check (int sig, int blocksigs) +{ + if (!myself->pgid || tc->getpgid () == myself->pgid || + myself->ctty != tc->ntty || + ((sig == SIGTTOU) && !(tc->ti.c_lflag & TOSTOP))) + return 1; + + if (sig < 0) + sig = -sig; + + termios_printf("bg I/O pgid %d, tpgid %d, ctty %d", + myself->pgid, tc->getpgid (), myself->ctty); + + if (tc->getsid () == 0) + { + /* The pty has been closed by the master. Return an EOF + indication. FIXME: There is nothing to stop somebody + from reallocating this pty. I think this is the case + which is handled by unlockpt on a Unix system. */ + termios_printf ("closed by master"); + return 0; + } + + /* If the process group is no more or if process is ignoring or blocks 'sig', + return with error */ + int pgid_gone = !proc_exists (procinfo (myself->pgid)); + int sigs_ignored = + ((void *) myself->getsig(sig).sa_handler == (void *) SIG_IGN) || + (myself->getsigmask () & SIGTOMASK (sig)); + + if (pgid_gone) + goto setEIO; + else if (!sigs_ignored) + /* nothing */; + else if (sig == SIGTTOU) + return 1; /* Just allow the output */ + else + goto setEIO; /* This is an output error */ + + _raise (sig); + return 1; + +setEIO: + set_errno (EIO); + return -1; +} + +#define set_input_done(x) input_done = input_done || (x) + +int +fhandler_termios::line_edit (const char *rptr, int nread, int always_accept) +{ + char c; + int input_done = 0; + int iscanon = tc->ti.c_lflag & ICANON; + + while (nread-- > 0) + { + c = *rptr++; + + termios_printf ("char %c", c); + + /* Check for special chars */ + + if (c == '\r') + { + if (tc->ti.c_iflag & IGNCR) + continue; + if (tc->ti.c_iflag & ICRNL) + { + c = '\n'; + set_input_done (iscanon); + } + } + else if (c == '\n') + { + if (tc->ti.c_iflag & INLCR) + c = '\r'; + else + set_input_done (iscanon); + } + + if (tc->ti.c_iflag & ISTRIP) + c &= 0x7f; + if (tc->ti.c_lflag & ISIG) + { + int sig; + if (c == tc->ti.c_cc[VINTR]) + sig = SIGINT; + else if (c == tc->ti.c_cc[VQUIT]) + sig = SIGQUIT; + else if (c == tc->ti.c_cc[VSUSP]) + sig = SIGTSTP; + else + goto not_a_sig; + + termios_printf ("got interrupt %d, sending signal %d", c, sig); + kill_pgrp (tc->getpgid (), sig); + tc->ti.c_lflag &= ~FLUSHO; + goto restart_output; + } + not_a_sig: + if (tc->ti.c_iflag & IXON) + { + if (c == tc->ti.c_cc[VSTOP]) + { + tc->OutputStopped++; + continue; + } + else if (c == tc->ti.c_cc[VSTART]) + { + restart_output: + tc->OutputStopped = 0; + SetEvent (restart_output_event); + continue; + } + else if ((tc->ti.c_iflag & IXANY) && tc->OutputStopped) + goto restart_output; + } + if (tc->ti.c_lflag & IEXTEN && c == tc->ti.c_cc[VDISCARD]) + { + tc->ti.c_lflag ^= FLUSHO; + continue; + } + if (!iscanon) + /* nothing */; + else if (c == tc->ti.c_cc[VERASE]) + { + if (eat_readahead (1)) + doecho ("\b \b", 3); + continue; + } + else if (c == tc->ti.c_cc[VWERASE]) + { + int ch; + do + if (!eat_readahead (1)) + break; + else + doecho ("\b \b", 3); + while ((ch = peek_readahead (1)) >= 0 && !isspace (ch)); + continue; + } + else if (c == tc->ti.c_cc[VKILL]) + { + int nchars = eat_readahead (-1); + while (nchars--) + doecho ("\b \b", 3); + continue; + } + else if (c == tc->ti.c_cc[VREPRINT]) + { + doecho ("\n\r", 2); + doecho (rabuf, ralen); + continue; + } + else if (c == tc->ti.c_cc[VEOF]) + { + termios_printf ("EOF"); + input_done = 1; + continue; + } + else if (c == tc->ti.c_cc[VEOL] || + c == tc->ti.c_cc[VEOL2] || + c == '\n') + { + set_input_done (1); + termios_printf ("EOL"); + } + + if (tc->ti.c_iflag & IUCLC && isupper (c)) + c = tolower (c); + + if (tc->ti.c_lflag & ECHO) + doecho (&c, 1); + put_readahead (c); + } + + if (!iscanon || always_accept) + set_input_done (ralen > 0); + + /* FIXME: It's not clear that this code will ever do anything. + Currently, it doesn't look like accept_input will ever return + a negative number. */ + if (input_done) + (void) accept_input (); + + return input_done; +} diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc new file mode 100644 index 000000000..c4ede333a --- /dev/null +++ b/winsup/cygwin/fhandler_tty.cc @@ -0,0 +1,1070 @@ +/* fhandler_tty.cc + + Copyright 1997, 1998, 2000 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include +#include +#include "winsup.h" +#include +#include + +/* Tty master stuff */ + +fhandler_tty_master NO_COPY *tty_master; + +static DWORD WINAPI process_input (void *); // Input queue thread +static DWORD WINAPI process_output (void *); // Output queue thread +static DWORD WINAPI process_ioctl (void *); // Ioctl requests thread + +fhandler_tty_master::fhandler_tty_master (const char *name, int unit) : + fhandler_pty_master (name, FH_TTYM, unit) +{ + set_cb (sizeof *this); + console = NULL; + hThread = NULL; +} + +int +fhandler_tty_master::init (int ntty) +{ + HANDLE h; + termios_printf ("Creating master for tty%d", ntty); + + if (init_console ()) + { + termios_printf ("can't create fhandler"); + return -1; + } + + termios ti; + memset (&ti, 0, sizeof (ti)); + console->tcsetattr (0, &ti); + + ttynum = ntty; + + cygwin_shared->tty[ttynum]->common_init (this); + + h = makethread (process_input, NULL, 0, "ttyin"); + if (h == NULL) + { + termios_printf ("can't create input thread"); + return -1; + } + else + { + SetThreadPriority (h, THREAD_PRIORITY_HIGHEST); + CloseHandle (h); + } + + h = makethread (process_ioctl, NULL, 0, "ttyioctl"); + if (h == NULL) + { + termios_printf ("can't create ioctl thread"); + return -1; + } + else + { + SetThreadPriority (h, THREAD_PRIORITY_HIGHEST); + CloseHandle (h); + } + + hThread = makethread (process_output, NULL, 0, "ttyout"); + if (hThread != NULL) + SetThreadPriority (hThread, THREAD_PRIORITY_HIGHEST); + else + { + termios_printf ("can't create output thread"); + return -1; + } + + return 0; +} + +#ifdef DEBUGGING +static class mutex_stack +{ +public: + const char *fn; + int ln; + const char *tname; +} ostack[100]; + +static int osi = 0; +#endif /*DEBUGGING*/ + +DWORD +fhandler_tty_common::__acquire_output_mutex (const char *fn, int ln, + DWORD ms) +{ + if (strace_active) + strace_printf (_STRACE_TERMIOS, "%F (%d): tty output_mutex: waiting %d ms", fn, ln, ms); + DWORD res = WaitForSingleObject (output_mutex, ms); + if (res == WAIT_OBJECT_0) + { +#ifdef DEBUGGING + ostack[osi].fn = fn; + ostack[osi].ln = ln; + ostack[osi].tname = threadname (0, 0); + termios_printf ("acquired for %s:%d, osi %d", fn, ln, osi); + osi++; +#endif + } + if (strace_active) + strace_printf (_STRACE_TERMIOS, "%F (%d): tty output_mutex: acquired", fn, ln, res); + return res; +} + +void +fhandler_tty_common::__release_output_mutex (const char *fn, int ln) +{ + if (ReleaseMutex (output_mutex)) + { +#ifdef DEBUGGING + if (osi > 0) + osi--; + termios_printf ("released at %s:%d, osi %d", fn, ln, osi); + termios_printf(" for %s:%d (%s)", ostack[osi].fn, ostack[osi].ln, ostack[osi].tname); + ostack[osi].ln = -ln; +#endif + } + if (strace_active) + strace_printf (_STRACE_TERMIOS, "%F (%d): tty output_mutex released", fn, ln); +} + +#define acquire_output_mutex(ms) \ + __acquire_output_mutex (__PRETTY_FUNCTION__, __LINE__, ms); + +#define release_output_mutex() \ + __release_output_mutex (__PRETTY_FUNCTION__, __LINE__); + +/* Process tty input. */ + +void +fhandler_pty_master::doecho (const void *str, DWORD len) +{ + acquire_output_mutex (INFINITE); + WriteFile (get_ttyp ()->to_master, str, len, &len, NULL); +// WaitForSingleObject (output_done_event, INFINITE); + release_output_mutex (); +} + +int +fhandler_pty_master::accept_input () +{ + DWORD written; + DWORD n; + const char dummy[1] = {'X'}; + const char *buf; + + n = get_ttyp ()->read_retval = eat_readahead (-1); + + if (n != 0) + buf = rabuf; + else + { + n = 1; + buf = dummy; + termios_printf ("sending EOF to slave"); + } + termios_printf ("about to write %d chars to slave", n); + if (!WriteFile (get_output_handle (), buf, n, &written, NULL)) + return -1; + return get_ttyp ()->read_retval; +} + +static DWORD WINAPI +process_input (void *arg) +{ + char rawbuf[INP_BUFFER_SIZE]; + + while (1) + { + int nraw = tty_master->console->read ((void *) rawbuf, + (size_t) INP_BUFFER_SIZE); + tty_master->line_edit (rawbuf, nraw); + } +} + +BOOL +fhandler_pty_master::hit_eof () +{ + if (get_ttyp ()->was_opened && !get_ttyp ()->slave_alive ()) + { + /* We have the only remaining open handle to this pty, and + the slave pty has been opened at least once. We treat + this as EOF. */ + termios_printf ("all other handles closed"); + return 1; + } + return 0; +} + +/* Process tty output requests */ + +int +fhandler_pty_master::process_slave_output (char *buf, size_t len) +{ + size_t rlen; + char outbuf[OUT_BUFFER_SIZE]; + DWORD n; + int column = 0; + +again: + + if (len == 0) + return 0; + + if (neednl_) + { + /* We need to return a left over \n character, resulting from + \r\n conversion. Note that we already checked for FLUSHO and + OutputStopped at the time that we read the character, so we + don't check again here. */ + buf[0] = '\n'; + neednl_ = 0; + return 1; + } + + /* Set RLEN to the number of bytes to read from the pipe. */ + rlen = len; + if (get_ttyp ()->ti.c_oflag & OPOST && get_ttyp ()->ti.c_oflag & ONLCR) + { + /* We are going to expand \n to \r\n, so don't read more than + half of the number of bytes requested. */ + rlen /= 2; + if (rlen == 0) + rlen = 1; + } + if (rlen > sizeof outbuf) + rlen = sizeof outbuf; + + HANDLE handle = get_io_handle (); + + /* Doing a busy wait like this is quite inefficient, but nothing + else seems to work completely. Windows should provide some sort + of overlapped I/O for pipes, or something, but it doesn't. */ + DWORD avail; + while (1) + { + if (! PeekNamedPipe (handle, NULL, 0, NULL, &avail, NULL)) + { + if (GetLastError () == ERROR_BROKEN_PIPE) + return 0; + __seterrno (); + return -1; + } + if (avail > 0) + break; + if (hit_eof ()) + return 0; + Sleep (10); + } + + if (ReadFile (handle, outbuf, rlen, &n, NULL) == FALSE) + { + if (GetLastError () == ERROR_BROKEN_PIPE) + return 0; + __seterrno (); + return -1; + } + + termios_printf ("len=%u", n); + + if (get_ttyp ()->ti.c_lflag & FLUSHO) + { + get_ttyp ()->write_retval = n; + if (output_done_event != NULL) + SetEvent (output_done_event); + goto again; + } + + if (get_ttyp ()->OutputStopped) + WaitForSingleObject (restart_output_event, INFINITE); + + if (get_ttyp ()->ti.c_oflag & OPOST) // post-process output + { + char *iptr = outbuf, *optr = buf; + + while (n--) + { + switch (*iptr) + { + case '\r': + if ((get_ttyp ()->ti.c_oflag & ONOCR) && column == 0) + { + iptr++; + continue; + } + if (get_ttyp ()->ti.c_oflag & OCRNL) + *iptr = '\n'; + else + column = 0; + break; + case '\n': + if (get_ttyp ()->ti.c_oflag & ONLCR) + { + *optr++ = '\r'; + column = 0; + } + if (get_ttyp ()->ti.c_oflag & ONLRET) + column = 0; + break; + default: + column++; + break; + } + + /* Don't store data past the end of the user's buffer. This + can happen if the user requests a read of 1 byte when + doing \r\n expansion. */ + if (optr - buf >= (int) len) + { + neednl_ = 1; + if (*iptr != '\n' || n != 0) + system_printf ("internal error: %d unexpected characters", n); + break; + } + + *optr++ = *iptr++; + } + return optr - buf; + } + else // raw output mode + { + memcpy (buf, outbuf, n); + return n; + } +} + +static DWORD WINAPI +process_output (void *arg) +{ + char buf[OUT_BUFFER_SIZE*2]; + int n; + + while (1) + { + n = tty_master->process_slave_output (buf, OUT_BUFFER_SIZE); + if (n < 0) + { + termios_printf ("ReadFile %E"); + ExitThread (0); + } + if (n == 0) + { + /* End of file. */ + ExitThread (0); + } + n = tty_master->console->write ((void *) buf, (size_t) n); + tty_master->get_ttyp ()->write_retval = n == -1 ? -get_errno () : n; + SetEvent (tty_master->output_done_event); + } +} + + +/* Process tty ioctl requests */ + +static DWORD WINAPI +process_ioctl (void *arg) +{ + while (1) + { + WaitForSingleObject (tty_master->ioctl_request_event, INFINITE); + termios_printf ("ioctl() request"); + tty_master->get_ttyp ()->ioctl_retval = + tty_master->console->ioctl (tty_master->get_ttyp ()->cmd, + (void *) &tty_master->get_ttyp ()->arg); + SetEvent (tty_master->ioctl_done_event); + } +} + +/**********************************************************************/ +/* Tty slave stuff */ + +fhandler_tty_slave::fhandler_tty_slave(int num, const char *name) : + fhandler_tty_common (FH_TTYS, name, num) +{ + set_cb (sizeof *this); + ttynum = num; + /* FIXME: This is wasteful. We should rewrite the set_name path to eliminate the + need for double allocates. */ + unix_path_name_ = (char *) realloc (unix_path_name_, strlen(win32_path_name_) + 1); + strcpy (unix_path_name_, win32_path_name_); + unix_path_name_[0] = unix_path_name_[4] = '/'; + debug_printf ("unix '%s', win32 '%s'", unix_path_name_, win32_path_name_); + inuse = NULL; +} + +fhandler_tty_slave::fhandler_tty_slave(const char *name) : + fhandler_tty_common (FH_TTYS, name, 0) +{ + set_cb (sizeof *this); + debug_printf ("here"); + inuse = NULL; +} + +int +fhandler_tty_slave::open (const char *, int flags, mode_t) +{ + tcinit (cygwin_shared->tty[ttynum]); + + attach_tty (ttynum); + set_ctty (ttynum, flags); + + set_flags (flags); + /* Create synchronisation events */ + char buf[40]; + + /* output_done_event may or may not exist. It will exist if the tty + was opened by fhandler_tty_master::init, normally called at + startup if use_tty is non-zero. It will not exist if this is a + pty opened by fhandler_pty_master::open. In the former case, tty + output is handled by a separate thread which controls output. */ + __small_sprintf (buf, OUTPUT_DONE_EVENT, ttynum); + output_done_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf); + + if (!(output_mutex = get_ttyp()->open_output_mutex (TRUE))) + { + termios_printf ("open output mutex failed, %E"); + __seterrno (); + return 0; + } + + /* The ioctl events may or may not exist. See output_done_event, + above. */ + __small_sprintf (buf, IOCTL_REQUEST_EVENT, ttynum); + ioctl_request_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf); + __small_sprintf (buf, IOCTL_DONE_EVENT, ttynum); + ioctl_done_event = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf); + + /* FIXME: Needs a method to eliminate tty races */ + { + acquire_output_mutex (500); + inuse = get_ttyp ()->create_inuse (TTY_SLAVE_ALIVE); + get_ttyp ()->was_opened = TRUE; + release_output_mutex (); + } + + /* Duplicate tty handles. */ + + if (!get_ttyp ()->from_slave || !get_ttyp ()->to_slave) + { + termios_printf ("tty handles have been closed"); + set_errno (EACCES); + return 0; + } + + HANDLE tty_owner = OpenProcess (PROCESS_DUP_HANDLE, FALSE, + get_ttyp ()->master_pid); + if (tty_owner == NULL) + { + termios_printf ("can't open tty(%d) handle process %d", + ttynum, get_ttyp ()->master_pid); + __seterrno (); + return 0; + } + + HANDLE nh; + if (!DuplicateHandle (tty_owner, get_ttyp ()->from_master, hMainProc, &nh, 0, TRUE, + DUPLICATE_SAME_ACCESS)) + { + termios_printf ("can't duplicate input, %E"); + __seterrno (); + return 0; + } + set_io_handle (nh); + termios_printf ("duplicated from_master %p->%p from tty_owner %p", + get_ttyp ()->from_master, nh, tty_owner); + if (!DuplicateHandle (tty_owner, get_ttyp ()->to_master, hMainProc, &nh, 0, TRUE, + DUPLICATE_SAME_ACCESS)) + { + termios_printf ("can't duplicate output, %E"); + __seterrno (); + return 0; + } + set_output_handle (nh); + CloseHandle (tty_owner); + + termios_printf("tty%d opened", ttynum); + + return 1; +} + +void +fhandler_tty_slave::init (HANDLE f, DWORD a, mode_t) +{ + int mode = 0; + + a &= GENERIC_READ | GENERIC_WRITE; + if (a == GENERIC_READ) + mode = O_RDONLY; + if (a == GENERIC_WRITE) + mode = O_WRONLY; + if (a == (GENERIC_READ | GENERIC_WRITE)) + mode = O_RDWR; + + open (0, mode); +} + +int +fhandler_tty_slave::write (const void *ptr, size_t len) +{ + DWORD n, towrite = len; + + termios_printf("tty%d, write(%x, %d)", ttynum, ptr, len); + + acquire_output_mutex (INFINITE); + + while (len) + { + n = min (OUT_BUFFER_SIZE, len); + char *buf = (char *)ptr; + ptr = (char *) ptr + n; + len -= n; + + if (WriteFile (get_output_handle (), buf, n, &n, NULL) == FALSE) + { + termios_printf ("WriteFile failed, %E"); + towrite = (DWORD) -1; + _raise (SIGHUP); /* FIXME: Should this be SIGTTOU? */ + break; + } + + if (output_done_event != NULL) + { + termios_printf("tty%d waiting for output_done", ttynum); + WaitForSingleObject (output_done_event, n * 1000); + } + + if (get_ttyp ()->write_retval < 0) + { + set_errno (-get_ttyp ()->write_retval); + towrite = (DWORD) -1; + break; + } + } + release_output_mutex (); + return towrite; +} + +int +fhandler_tty_slave::read (void *ptr, size_t len) +{ + DWORD n; + int totalread = 0; + int vmin = INT_MAX; + int vtime = 0; /* Initialized to prevent -Wuninitialized warning */ + char buf[INP_BUFFER_SIZE]; + + termios_printf("read(%x, %d) handle %d", ptr, len, get_handle ()); + + if (!(get_ttyp ()->ti.c_lflag & ICANON)) + { + vmin = get_ttyp ()->ti.c_cc[VMIN]; + vtime = get_ttyp ()->ti.c_cc[VTIME]; + } + + while (len) + { + wait: + termios_printf ("reading %d bytes (vtime %d)", + min ((unsigned) vmin, min (len, sizeof (buf))), vtime); + if (ReadFile (get_handle (), (unsigned *) buf, + min ((unsigned) vmin, min (len, sizeof (buf))), &n, NULL) == FALSE) + { + termios_printf ("read failed, %E"); + _raise (SIGHUP); + } + if (get_ttyp ()->read_retval < 0) // read error + { + set_errno (-get_ttyp ()->read_retval); + totalread = -1; + break; + } + if (get_ttyp ()->read_retval == 0) //EOF + { + termios_printf ("saw EOF"); + break; + } + len -= n; + totalread += n; + memcpy (ptr, buf, n); + ptr = (char *) ptr + n; + if (get_ttyp ()->ti.c_lflag & ICANON) + break; + else if (totalread >= vmin) + break; + + if (!PeekNamedPipe (get_handle (), NULL, 0, NULL, &n, NULL)) + { + termios_printf("PeekNamedPipe failed, %E"); + break; + } + if (n == 0) + { + if (get_flags () & (O_NONBLOCK | O_NDELAY)) + break; + + /* We can't enter to blocking Readfile - signals will be lost! + * So, poll the pipe for data. + * FIXME: try to avoid polling... + * FIXME: Current EINTR scheme does not take vmin/vtime into account. + */ + if (!(get_ttyp ()->ti.c_lflag & ICANON)) + { + termios_printf("vmin %d vtime %d", vmin, vtime); + if (vmin == 0 && vtime == 0) + return 0; // min = 0, time = 0 + if (vtime == 0) + goto wait; // min > 0, time = 0 + while (vtime--) + { + PeekNamedPipe (get_handle (), NULL, 0, NULL, &n, NULL); + if (n) + break; + Sleep(10); + } + if (vtime == 0) + return totalread; + } + } + } + termios_printf ("%d=read(%x, %d)", totalread, ptr, len); + return totalread; +} + +int +fhandler_tty_common::dup (fhandler_base *child) +{ + fhandler_tty_slave *fts = (fhandler_tty_slave *) child; + int errind; + + termios_printf ("here"); + fts->ttynum = ttynum; + fts->tcinit (get_ttyp ()); + + attach_tty (ttynum); + + HANDLE nh; + + if (output_done_event == NULL) + fts->output_done_event = NULL; + else if (!DuplicateHandle (hMainProc, output_done_event, hMainProc, + &fts->output_done_event, 0, 1, + DUPLICATE_SAME_ACCESS)) + { + errind = 1; + goto err; + } + if (ioctl_request_event == NULL) + fts->ioctl_request_event = NULL; + else if (!DuplicateHandle (hMainProc, ioctl_request_event, hMainProc, + &fts->ioctl_request_event, 0, 1, + DUPLICATE_SAME_ACCESS)) + { + errind = 2; + goto err; + } + if (ioctl_done_event == NULL) + fts->ioctl_done_event = NULL; + else if (!DuplicateHandle (hMainProc, ioctl_done_event, hMainProc, + &fts->ioctl_done_event, 0, 1, + DUPLICATE_SAME_ACCESS)) + { + errind = 3; + goto err; + } + if (!DuplicateHandle (hMainProc, output_mutex, hMainProc, + &fts->output_mutex, 0, 1, + DUPLICATE_SAME_ACCESS)) + { + errind = 4; + goto err; + } + if (!DuplicateHandle (hMainProc, get_handle (), hMainProc, + &nh, 0, 1, + DUPLICATE_SAME_ACCESS)) + { + errind = 5; + goto err; + } + fts->set_io_handle (nh); + + if (!DuplicateHandle (hMainProc, get_output_handle (), hMainProc, + &nh, 0, 1, + DUPLICATE_SAME_ACCESS)) + { + errind = 6; + goto err; + } + fts->set_output_handle (nh); + + if (inuse == NULL) + fts->inuse = NULL; + else if (!DuplicateHandle (hMainProc, inuse, hMainProc, + &fts->inuse, 0, 1, + DUPLICATE_SAME_ACCESS)) + { + errind = 7; + goto err; + } + return 0; + +err: + __seterrno (); + termios_printf ("dup %d failed in DuplicateHandle, %E", errind); + return -1; +} + +int +fhandler_tty_slave::tcgetattr (struct termios *t) +{ + *t = get_ttyp ()->ti; + return 0; +} + +int +fhandler_tty_slave::tcsetattr (int a, const struct termios *t) +{ + acquire_output_mutex (INFINITE); + get_ttyp ()->ti = *t; + release_output_mutex (); + return 0; +} + +int +fhandler_tty_slave::tcflush (int a) +{ + return 0; +} + +void +fhandler_tty_slave::send_ioctl_request (void) +{ + if (ioctl_request_event == NULL || ioctl_done_event == NULL) // slave of pty + return; + + acquire_output_mutex (INFINITE); + SetEvent (ioctl_request_event); + WaitForSingleObject (ioctl_done_event, INFINITE); + release_output_mutex (); +} + +int +fhandler_tty_slave::ioctl (unsigned int cmd, void *arg) +{ + termios_printf ("ioctl (%x)", cmd); + + if (myself->pgid && get_ttyp ()->getpgid () != myself->pgid && + myself->ctty == ttynum && (get_ttyp ()->ti.c_lflag & TOSTOP)) + { + /* background process */ + termios_printf("bg ioctl pgid %d, tpgid %d, ctty %d", + myself->pgid, get_ttyp ()->getpgid (), myself->ctty); + _raise (SIGTTOU); + } + get_ttyp ()->cmd = cmd; + get_ttyp ()->ioctl_retval = 0; + switch (cmd) + { + case TIOCGWINSZ: + get_ttyp ()->arg.winsize = get_ttyp ()->winsize; + send_ioctl_request (); + * (struct winsize *) arg = get_ttyp ()->arg.winsize; + get_ttyp ()->winsize = get_ttyp ()->arg.winsize; + break; + case TIOCSWINSZ: + get_ttyp ()->ioctl_retval = -1; + get_ttyp ()->arg.winsize = * (struct winsize *) arg; + send_ioctl_request (); + break; + case FIONBIO: + if (* (int *) arg) + set_flags (get_flags () | O_NONBLOCK); + else + set_flags (get_flags () & ~O_NONBLOCK); + break; + default: + set_errno (EINVAL); + return -1; + } + termios_printf ("%d = ioctl (%x)", get_ttyp ()->ioctl_retval, cmd); + return get_ttyp ()->ioctl_retval; +} + +/******************************************************* + fhandler_pty_master +*/ +fhandler_pty_master::fhandler_pty_master (const char *name, DWORD devtype, int unit) : + fhandler_tty_common (devtype, name, unit) +{ + set_cb (sizeof *this); + ioctl_request_event = NULL; + ioctl_done_event = NULL; + restart_output_event = NULL; + pktmode = neednl_ = 0; + inuse = NULL; +} + +int +fhandler_pty_master::open (const char *, int flags, mode_t) +{ + ttynum = cygwin_shared->tty.allocate_tty (0); + if (ttynum < 0) + return 0; + + cygwin_shared->tty[ttynum]->common_init (this); + inuse = get_ttyp ()->create_inuse (TTY_MASTER_ALIVE); + set_flags (flags); + + termios_printf ("opened pty master tty%d<%p>", ttynum, this); + return 1; +} + +int +fhandler_tty_common::close () +{ +termios_printf ("here %p", this); + if (output_done_event && !CloseHandle (output_done_event)) + termios_printf ("CloseHandle (output_done_event), %E"); + if (ioctl_done_event && !CloseHandle (ioctl_done_event)) + termios_printf ("CloseHandle (ioctl_done_event), %E"); + if (ioctl_request_event && !CloseHandle (ioctl_request_event)) + termios_printf ("CloseHandle (ioctl_request_event), %E"); + if (restart_output_event && !CloseHandle (restart_output_event)) + termios_printf ("CloseHandle (restart_output_event), %E"); + if (inuse && !CloseHandle (inuse)) + termios_printf ("CloseHandle (inuse), %E"); + if (!ForceCloseHandle (output_mutex)) + termios_printf ("CloseHandle (output_mutex<%p>), %E", output_mutex); + if (!CloseHandle (get_handle ())) + termios_printf ("CloseHandle (get_handle ()<%p>), %E", get_handle ()); + if (!CloseHandle (get_output_handle ())) + termios_printf ("CloseHandle (get_output_handle ()<%p>), %E", get_output_handle ()); + + inuse = NULL; + termios_printf ("tty%d closed", ttynum); + return 0; +} + +int +fhandler_pty_master::close () +{ +#if 0 + while (accept_input () > 0) + continue; +#endif + this->fhandler_tty_common::close (); + + if (!get_ttyp ()->master_alive ()) + { + termios_printf ("freeing tty%d (%d)", ttynum, get_ttyp ()->ntty); + if (get_ttyp ()->to_slave) + CloseHandle (get_ttyp ()->to_slave); + if (get_ttyp ()->from_slave) + CloseHandle (get_ttyp ()->from_slave); + if (get_ttyp ()->from_master) + CloseHandle (get_ttyp ()->from_master); + if (get_ttyp ()->to_master) + CloseHandle (get_ttyp ()->to_master); + get_ttyp ()->init (); + } + + return 0; +} + +int +fhandler_pty_master::write (const void *ptr, size_t len) +{ + line_edit ((char *) ptr, len); + return len; +} + +int +fhandler_pty_master::read (void *ptr, size_t len) +{ + DWORD n; + char *cptr = (char *) ptr; + + if (! PeekNamedPipe (get_handle (), NULL, 0, NULL, &n, NULL)) + { + if (GetLastError () == ERROR_BROKEN_PIPE) + { + /* On Unix, a read from a broken pipe returns EOF. */ + return 0; + } + __seterrno (); + return -1; + } + if (n == 0 + && (get_flags () & (O_NONBLOCK | O_NDELAY)) != 0) + { + set_errno (EAGAIN); + return -1; + } + if (pktmode) + { + *cptr++ = TIOCPKT_DATA; + len--; + } + n = process_slave_output (cptr, len); + if (n < 0) + return -1; + if (output_done_event != NULL) + SetEvent (output_done_event); + if (pktmode && n > 0) + n++; + return n; +} + +int +fhandler_pty_master::tcgetattr (struct termios *t) +{ + *t = cygwin_shared->tty[ttynum]->ti; + return 0; +} + +int +fhandler_pty_master::tcsetattr (int a, const struct termios *t) +{ + cygwin_shared->tty[ttynum]->ti = *t; + return 0; +} + +int +fhandler_pty_master::tcflush (int a) +{ + return 0; +} + +int +fhandler_pty_master::ioctl (unsigned int cmd, void *arg) +{ + switch (cmd) + { + case TIOCPKT: + pktmode = * (int *) arg; + break; + case TIOCGWINSZ: + * (struct winsize *) arg = get_ttyp ()->winsize; + break; + case TIOCSWINSZ: + get_ttyp ()->winsize = * (struct winsize *) arg; + _kill (-get_ttyp ()->getpgid (), SIGWINCH); + break; + case FIONBIO: + if (* (int *) arg) + set_flags (get_flags () | O_NONBLOCK); + else + set_flags (get_flags () & ~O_NONBLOCK); + break; + default: + set_errno (EINVAL); + return -1; + } + return 0; +} + +char * +fhandler_pty_master::ptsname (void) +{ + static char buf[32]; + + __small_sprintf (buf, "/dev/tty%d", ttynum); + return buf; +} + +void +fhandler_tty_common::set_close_on_exec (int val) +{ + this->fhandler_base::set_close_on_exec (val); + if (output_done_event) + set_inheritance (output_done_event, val); + if (ioctl_request_event) + set_inheritance (ioctl_request_event, val); + if (ioctl_done_event) + set_inheritance (ioctl_done_event, val); + if (inuse) + set_inheritance (inuse, val); + set_inheritance (output_mutex, val, "output_mutex"); + set_inheritance (output_handle, val); +} + +void +fhandler_tty_common::fixup_after_fork (HANDLE parent) +{ + this->fhandler_base::fixup_after_fork (parent); + if (output_done_event) + fork_fixup (parent, output_done_event, "output_done_event"); + if (ioctl_request_event) + fork_fixup (parent, ioctl_request_event, "ioctl_request_event"); + if (ioctl_done_event) + fork_fixup (parent, ioctl_done_event, "ioctl_done_event"); + if (output_mutex) + { + fork_fixup (parent, output_mutex, "output_mutex"); + ProtectHandle (output_mutex); + } + fork_fixup (parent, output_handle, "output_handle"); + fork_fixup (parent, inuse, "inuse"); +} + +void +fhandler_pty_master::set_close_on_exec (int val) +{ + this->fhandler_tty_common::set_close_on_exec (val); + set_inheritance (restart_output_event, val); + + /* FIXME: There is a console handle leak here. */ + if (get_ttyp ()->master_pid == GetCurrentProcessId ()) + { + get_ttyp ()->from_slave = get_handle (); + get_ttyp ()->to_slave = get_output_handle (); + } +} + +void +fhandler_pty_master::fixup_after_fork (HANDLE child) +{ + this->fhandler_tty_common::fixup_after_fork (child); + if (restart_output_event) + fork_fixup (child, restart_output_event, "restart_output_event"); +} + +void +fhandler_tty_master::fixup_after_fork (HANDLE child) +{ + this->fhandler_pty_master::fixup_after_fork (child); + console->fixup_after_fork (child); +} + +int +fhandler_tty_master::de_linearize (const char *buf, const char *unix_name, + const char *win32_name) +{ + int res = fhandler_base::de_linearize (buf, unix_name, win32_name); + console->close (); + init_console (); + return res; +} + +int +fhandler_tty_master::init_console () +{ + console = (fhandler_console *) dtable.build_fhandler (-1, FH_CONSOLE, "/dev/ttym"); + if (console == NULL) + return -1; + + console->init (INVALID_HANDLE_VALUE, GENERIC_READ | GENERIC_WRITE, O_BINARY); + console->set_r_no_interrupt (1); + return 0; +} diff --git a/winsup/cygwin/fhandler_windows.cc b/winsup/cygwin/fhandler_windows.cc new file mode 100644 index 000000000..eee8286e1 --- /dev/null +++ b/winsup/cygwin/fhandler_windows.cc @@ -0,0 +1,145 @@ +/* fhandler_windows.cc: code to access windows message queues. + + Copyright 1998 Cygnus Solutions. + + Written by Sergey S. Okhapkin (sos@prospect.com.ru). + Feedback and testing by Andy Piper (andyp@parallax.co.uk). + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include "winsup.h" + +/* +The following unix-style calls are supported: + + open ("/dev/windows", flags, mode=0) + - create a unix fd for message queue. + O_NONBLOCK flag controls the read() call behavior. + + read (fd, buf, len) + - return next message from queue. buf must point to MSG + structure, len must be >= sizeof (MSG). If read is set to + non-blocking and the queue is empty, read call returns -1 + immediately with errno set to EAGAIN, otherwise it blocks + untill the message will be received. + + write (fd, buf, len) + - send a message pointed by buf. len argument ignored. + + ioctl (fd, command, *param) + - control read()/write() behavior. + ioctl (fd, WINDOWS_POST, NULL): write() will PostMessage(); + ioctl (fd, WINDOWS_SEND, NULL): write() will SendMessage(); + ioctl (fd, WINDOWS_HWND, &hWnd): read() messages for + hWnd window. + + select () call marks read fd when any message posted to queue. +*/ + +fhandler_windows::fhandler_windows (const char *name) : + fhandler_base (FH_WINDOWS, name) +{ + set_cb (sizeof *this); + hWnd_ = NULL; + method_ = WINDOWS_POST; +} + +int +fhandler_windows::open (const char *, int flags, mode_t) +{ + set_flags (flags); + set_close_on_exec_flag (1); + return 1; +} + +int +fhandler_windows::write (const void *buf, size_t) +{ + MSG *ptr = (MSG *) buf; + + if (method_ == WINDOWS_POST) + { + if (!PostMessage (ptr->hwnd, ptr->message, ptr->wParam, ptr->lParam)) + { + __seterrno (); + return -1; + } + else + return sizeof (MSG); + } + else + return SendMessage (ptr->hwnd, ptr->message, ptr->wParam, ptr->lParam); +} + +int +fhandler_windows::read (void *buf, size_t len) +{ + MSG *ptr = (MSG *) buf; + int ret; + + if (len < sizeof (MSG)) + { + set_errno (EINVAL); + return -1; + } + + ret = GetMessage (ptr, hWnd_, 0, 0); + + if (ret == -1) + { + __seterrno (); + } + set_errno (0); + return ret; +} + +int +fhandler_windows::ioctl (unsigned int cmd, void *val) +{ + switch (cmd) + { + case WINDOWS_POST: + case WINDOWS_SEND: + method_ = cmd; + break; + case WINDOWS_HWND: + if (val == NULL) + { + set_errno (EINVAL); + return -1; + } + hWnd_ = * ((HWND *) val); + break; + default: + set_errno (EINVAL); + return -1; + } + return 0; +} + +void +fhandler_windows::set_close_on_exec (int val) +{ + if (get_handle ()) + this->fhandler_base::set_close_on_exec (val); + else + this->fhandler_base::set_close_on_exec_flag (val); + void *h = hWnd_; + if (h) + set_inheritance (h, val); +} + +void +fhandler_windows::fixup_after_fork (HANDLE parent) +{ + if (get_handle ()) + this->fhandler_base::fixup_after_fork (parent); + void *h = hWnd_; + if (h) + fork_fixup (parent, h, "hWnd_"); +} diff --git a/winsup/cygwin/fhandler_zero.cc b/winsup/cygwin/fhandler_zero.cc new file mode 100644 index 000000000..eb76037fb --- /dev/null +++ b/winsup/cygwin/fhandler_zero.cc @@ -0,0 +1,58 @@ +/* fhandler_dev_zero.cc: code to access /dev/zero + + Copyright 2000 Cygnus Solutions. + + Written by DJ Delorie (dj@cygnus.com) + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include "winsup.h" + +fhandler_dev_zero::fhandler_dev_zero (const char *name) + : fhandler_base (FH_ZERO, name) +{ + set_cb (sizeof *this); +} + +int +fhandler_dev_zero::open (const char *path, int flags, mode_t mode = 0) +{ + set_flags (flags); + return 1; +} + +int +fhandler_dev_zero::write (const void *ptr, size_t len) +{ + return len; +} + +int +fhandler_dev_zero::read (void *ptr, size_t len) +{ + memset(ptr, 0, len); + return len; +} + +off_t +fhandler_dev_zero::lseek (off_t offset, int whence) +{ + return 0; +} + +int +fhandler_dev_zero::close (void) +{ + return 0; +} + +void +fhandler_dev_zero::dump () +{ + paranoid_printf("here, fhandler_dev_zero"); +} diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc new file mode 100644 index 000000000..c08eab292 --- /dev/null +++ b/winsup/cygwin/fork.cc @@ -0,0 +1,625 @@ +/* fork.cc + + Copyright 1996, 1997, 1998, 1999 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include +#include +#include +#include "winsup.h" +#include "dll_init.h" + +DWORD chunksize = 0; +/* Timeout to wait for child to start, parent to init child, etc. */ +/* FIXME: Once things stabilize, bump up to a few minutes. */ +#define FORK_WAIT_TIMEOUT (300 * 1000) /* 300 seconds */ + +#define dll_data_start &_data_start__ +#define dll_data_end &_data_end__ +#define dll_bss_start &_bss_start__ +#define dll_bss_end &_bss_end__ + +void +per_thread::set (void *s) + { + if (s == PER_THREAD_FORK_CLEAR) + { + tls = TlsAlloc (); + s = NULL; + } + TlsSetValue (get_tls (), s); + } + +static void +stack_base (child_info_fork &ch) +{ + MEMORY_BASIC_INFORMATION m; + memset (&m, 0, sizeof m); + if (!VirtualQuery ((LPCVOID) &m, &m, sizeof m)) + system_printf ("couldn't get memory info, %E"); + + ch.stacktop = m.AllocationBase; + ch.stackbottom = (LPBYTE) m.BaseAddress + m.RegionSize; + ch.stacksize = (DWORD) ch.stackbottom - (DWORD) &m; + debug_printf ("bottom %p, top %p, stack %p, size %d, reserve %d", + ch.stackbottom, ch.stacktop, &m, ch.stacksize, + (DWORD) ch.stackbottom - (DWORD) ch.stacktop); +} + +/* Copy memory from parent to child. + The result is a boolean indicating success. */ + +static int +fork_copy (PROCESS_INFORMATION &pi, const char *what, ...) +{ + va_list args; + char *low; + int pass = 0; + + va_start (args, what); + + while ((low = va_arg (args, char *))) + { + char *high = va_arg (args, char *); + DWORD todo = chunksize ?: high - low; + char *here; + + for (here = low; here < high; here += todo) + { + DWORD done = 0; + if (here + todo > high) + todo = high - here; + int res = WriteProcessMemory (pi.hProcess, here, here, todo, &done); + debug_printf ("child handle %p, low %p, high %p, res %d", pi.hProcess, + low, high, res); + if (!res || todo != done) + { + if (!res) + __seterrno (); + /* If this happens then there is a bug in our fork + implementation somewhere. */ + system_printf ("%s pass %d failed, %p..%p, done %d, %E", + what, pass, low, high, done); + goto err; + } + } + + pass++; + } + + debug_printf ("done"); + return 1; + +err: + TerminateProcess (pi.hProcess, 1); + set_errno (EAGAIN); + return 0; +} + +/* Wait for child to finish what it's doing and signal us. + We don't want to wait forever here.If there's a problem somewhere + it'll hang the entire system (since all forks are mutex'd). If we + time out, set errno = EAGAIN and hope the app tries again. */ +static int +sync_with_child (PROCESS_INFORMATION &pi, HANDLE subproc_ready, + BOOL hang_child, const char *s) +{ + /* We also add the child process handle to the wait. If the child fails + to initialize (eg. because of a missing dll). Then this + handle will become signalled. This stops a *looong* timeout wait. + */ + HANDLE w4[2]; + + debug_printf ("waiting for child. reason: %s", s); + w4[1] = pi.hProcess; + w4[0] = subproc_ready; + DWORD rc = WaitForMultipleObjects (2, w4, FALSE, FORK_WAIT_TIMEOUT); + + if (rc == WAIT_OBJECT_0 || + WaitForSingleObject (subproc_ready, 0) == WAIT_OBJECT_0) + /* That's ok */; + else if (rc == WAIT_FAILED || rc == WAIT_TIMEOUT) + { + if (rc != WAIT_FAILED) + system_printf ("WaitForMultipleObjects timed out"); + else + system_printf ("WaitForMultipleObjects failed, %E"); + set_errno (EAGAIN); + syscall_printf ("-1 = fork(), WaitForMultipleObjects failed"); + TerminateProcess (pi.hProcess, 1); + return 0; + } + else + { + /* Child died. Clean up and exit. */ + DWORD errcode; + GetExitCodeProcess (pi.hProcess, &errcode); + /* Fix me. This is not enough. The fork should not be considered + * to have failed if the process was essentially killed by a signal. + */ + if (errcode != STATUS_CONTROL_C_EXIT) + { + system_printf ("child %d(%p) died before initialization with status code %p", + pi.dwProcessId, pi.hProcess, errcode); + system_printf ("*** child state %s", s); +#ifdef DEBUGGING + abort (); +#endif + } + set_errno (EAGAIN); + syscall_printf ("Child died before subproc_ready signalled"); + return 0; + } + + debug_printf ("child signalled me"); + if (hang_child) + { + int n = SuspendThread (pi.hThread); + debug_printf ("suspend count %d", n); \ + } + return 1; +} + +static int +resume_child (PROCESS_INFORMATION &pi, HANDLE subproc_ready, + HANDLE forker_finished) +{ + int rc; + + debug_printf ("here"); + SetEvent (forker_finished); + + rc = ResumeThread (pi.hThread); + + debug_printf ("rc %d", rc); + if (rc == 1) + return 1; // Successful resumption + + /* Can't resume the thread. Not sure why this would happen unless + there's a bug in the system. Things seem to be working OK now + though, so flag this with EAGAIN, but print a message on the + console. */ + small_printf ("fork: ResumeThread failed, rc = %d, %E\n", rc); + set_errno (EAGAIN); + syscall_printf ("-1 = fork(), ResumeThread failed"); + TerminateProcess (pi.hProcess, 1); + return 0; +} + +/* Notify parent that it is time for the next step. + Note that this has to be a macro since the parent may be messing with + our stack. */ +#define sync_with_parent(s, hang_self) \ +((void) ({ \ + debug_printf ("signalling parent: %s", s); \ + /* Tell our parent we're waiting. */ \ + if (!SetEvent (child_proc_info->subproc_ready)) \ + api_fatal ("fork child - SetEvent failed, %E"); \ + if (hang_self) \ + { \ + /* Wait for the parent to fill in our stack and heap. \ + Don't wait forever here. If our parent dies we don't want to clog \ + the system. If the wait fails, we really can't continue so exit. */ \ + DWORD psync_rc = WaitForSingleObject (child_proc_info->forker_finished, FORK_WAIT_TIMEOUT); \ + switch (psync_rc) \ + { \ + case WAIT_TIMEOUT: \ + api_fatal ("sync_with_parent - WFSO timed out"); \ + break; \ + case WAIT_FAILED: \ + if (GetLastError () == ERROR_INVALID_HANDLE && \ + WaitForSingleObject (child_proc_info->forker_finished, 1) != WAIT_FAILED) \ + break; \ + api_fatal ("sync_with_parent - WFSO failed, fork_finished %p, %E", child_proc_info->forker_finished); \ + break; \ + default: \ + break; \ + } \ + debug_printf ("awake"); \ + } \ + 0; \ +})) + +static volatile void grow_stack_slack(); + +static void * +stack_dummy (int here) +{ + return &here; +} + +extern "C" int +fork () +{ + int res; + DWORD rc; + HANDLE hParent; + pinfo *child; + HANDLE subproc_ready, forker_finished; + void *stack_here; + int x; + PROCESS_INFORMATION pi = {0}; + + MALLOC_CHECK; + + /* FIXME: something is broken when copying the stack from the parent + to the child; we try various tricks here to make sure that the + stack is good enough to prevent page faults, but the true cause + is still unknown. DJ */ + volatile char dummy[4096]; + dummy[0] = dummy[4095] = 0; // Just to leave some slack in the stack + + grow_stack_slack (); + + debug_printf ("entering"); + /* Calculate how much of stack to copy to child */ + stack_here = stack_dummy (0); + + if (ISSTATE(myself, PID_SPLIT_HEAP)) + { + system_printf ("The heap has been split, CYGWIN can't fork this process."); + system_printf ("Increase the heap_chunk_size in the registry and try again."); + set_errno (ENOMEM); + syscall_printf ("-1 = fork (), split heap"); + return -1; + } + + /* Don't start the fork until we have the lock. */ + child = cygwin_shared->p.allocate_pid (); + if (!child) + { + set_errno (EAGAIN); + syscall_printf ("-1 = fork (), process table full"); + return -1; + } + + static child_info_fork ch; + x = setjmp (ch.jmp); + + if (x == 0) + { + + /* This will help some of the confusion. */ + fflush (stdout); + + debug_printf ("parent pid %d, child pid %d", myself->pid, child->pid); + + subproc_ready = CreateEvent (&sec_all, FALSE, FALSE, NULL); + forker_finished = CreateEvent (&sec_all, FALSE, FALSE, NULL); + ProtectHandle (subproc_ready); + ProtectHandle (forker_finished); + + /* If we didn't obtain all the resources we need to fork, allow the program + to continue, but record the fact that fork won't work. */ + if (forker_finished == NULL || subproc_ready == NULL) + { + system_printf ("unable to allocate fork() resources."); + system_printf ("fork() disabled."); + return -1; + } + + subproc_init (); + + debug_printf ("about to call setjmp"); + /* Parent. */ +#ifdef DEBUGGING + /* The ProtectHandle call allocates memory so we need to make sure + that enough is set aside here so that the sbrk pointer does not + move when ProtectHandle is called after the child is started. + Otherwise the sbrk pointers in the parent will not agree with + the child and when user_data is (regrettably) copied over, + the user_data->ptr field will not be accurate. */ + free (malloc (4096)); +#endif + + init_child_info (PROC_FORK1, &ch, child->pid, subproc_ready); + + ch.forker_finished = forker_finished; + ch.heaptop = user_data->heaptop; + ch.heapbase = user_data->heapbase; + ch.heapptr = user_data->heapptr; + + stack_base (ch); + + /* Initialize things that are done later in dll_crt0_1 that aren't done + for the forkee. */ + strcpy(child->progname, myself->progname); + + STARTUPINFO si = {0}; + + si.cb = sizeof (STARTUPINFO); + si.lpReserved2 = (LPBYTE)&ch; + si.cbReserved2 = sizeof(ch); + + int c_flags = GetPriorityClass (hMainProc) /*| + CREATE_NEW_PROCESS_GROUP*/; + + /* If we don't have a console, then don't create a console for the + child either. */ + HANDLE console_handle = CreateFileA ("CONOUT$", GENERIC_WRITE, + FILE_SHARE_WRITE, &sec_none_nih, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, + NULL); + + syscall_printf ("CreateProcessA (%s, %s,0,0,1,%x, 0,0,%p,%p)", + myself->progname, myself->progname, c_flags, &si, &pi); + if (console_handle != INVALID_HANDLE_VALUE && console_handle != 0) + CloseHandle (console_handle); + else + c_flags |= DETACHED_PROCESS; + + hParent = NULL; + if (!DuplicateHandle (hMainProc, hMainProc, hMainProc, &hParent, 0, 1, + DUPLICATE_SAME_ACCESS)) + { + system_printf ("couldn't create handle to myself for child, %E"); + goto cleanup; + } + + rc = CreateProcessA (myself->progname, /* image to run */ + myself->progname, /* what we send in arg0 */ + &sec_none_nih, /* process security attrs */ + &sec_none_nih, /* thread security attrs */ + TRUE, /* inherit handles from parent */ + c_flags, + NULL, /* environment filled in later */ + 0, /* use current drive/directory */ + &si, + &pi); + + CloseHandle (hParent); + + if (!rc) + { + __seterrno (); + syscall_printf ("-1 = fork(), CreateProcessA failed"); + child->process_state = PID_NOT_IN_USE; + ForceCloseHandle(subproc_ready); + ForceCloseHandle(forker_finished); + subproc_ready = forker_finished = NULL; + return -1; + } + + ProtectHandle (pi.hThread); + /* Protect the handle but name it similarly to the way it will + be called in subproc handling. */ + ProtectHandle1 (pi.hProcess, childhProc); + + /* Fill in fields in the child's process table entry. */ + child->ppid = myself->pid; + child->hProcess = pi.hProcess; + child->dwProcessId = pi.dwProcessId; + child->uid = myself->uid; + child->gid = myself->gid; + child->pgid = myself->pgid; + child->sid = myself->sid; + child->ctty = myself->ctty; + child->umask = myself->umask; + child->copysigs(myself); + child->process_state |= PID_INITIALIZING | + (myself->process_state & PID_USETTY); + memcpy (child->username, myself->username, MAX_USER_NAME); + child->psid = myself->psid; + memcpy (child->sidbuf, myself->sidbuf, 40); + memcpy (child->logsrv, myself->logsrv, 256); + memcpy (child->domain, myself->domain, MAX_COMPUTERNAME_LENGTH+1); + set_child_mmap_ptr (child); + + /* Wait for subproc to initialize itself. */ + if (!sync_with_child(pi, subproc_ready, TRUE, "waiting for longjmp")) + goto cleanup; + + /* CHILD IS STOPPED */ + debug_printf ("child is alive (but stopped)"); + + /* Initialize, in order: data, bss, heap, stack, dll data, dll bss + Note: variables marked as NO_COPY will not be copied + since they are placed in a protected segment. */ + + + MALLOC_CHECK; + rc = fork_copy (pi, "user/cygwin data", + user_data->data_start, user_data->data_end, + user_data->bss_start, user_data->bss_end, + ch.heapbase, ch.heapptr, + stack_here, ch.stackbottom, + dll_data_start, dll_data_end, + dll_bss_start, dll_bss_end, NULL); + + MALLOC_CHECK; + if (!rc) + goto cleanup; + + /* Now fill data/bss of linked dll */ + DO_LINKED_DLL (p) + { + debug_printf ("copying data/bss of a linked dll"); + if (!fork_copy (pi, "linked dll data/bss", p->data_start, p->data_end, + p->bss_start, p->bss_end, + NULL)) + goto cleanup; + } + DLL_DONE; + + proc_register (child); + int load_dll = DllList::the().forkeeMustReloadDlls() && + DllList::the().numberOfOpenedDlls(); + + /* Start thread, and wait for it to reload dlls. */ + if (!resume_child (pi, subproc_ready, forker_finished) || + !sync_with_child (pi, subproc_ready, load_dll, "child loading dlls")) + goto cleanup; + + /* child reload dlls & then write their data and bss */ + if (load_dll) + { + /* CHILD IS STOPPED */ + /* write memory of reloaded dlls */ + DO_LOADED_DLL (p) + { + debug_printf ("copying data/bss for a loaded dll"); + if (!fork_copy (pi, "loaded dll data/bss", p->data_start, p->data_end, + p->bss_start, p->bss_end, + NULL)) + goto cleanup; + } + DLL_DONE; + /* Start the child up again. */ + (void) resume_child (pi, subproc_ready, forker_finished); + } + + ForceCloseHandle (subproc_ready); + ForceCloseHandle (pi.hThread); + ForceCloseHandle (forker_finished); + forker_finished = NULL; + pi.hThread = NULL; + + res = child->pid; + } + else + { + /**** Child *****/ + + /* We arrive here via a longjmp from "crt0". */ + (void) stack_dummy (0); // Just to make sure + debug_printf ("child is running %d", x); + + debug_printf ("self %p, pid %d, ppid %d", + myself, x, myself ? myself->ppid : -1); + + sync_with_parent ("after longjmp.", TRUE); + ProtectHandle (hParent); + +#ifdef DEBUGGING + char c; + if (GetEnvironmentVariable ("FORKDEBUG", &c, 1)) + try_to_debug (); +#endif + + /* If we've played with the stack, stacksize != 0. That means that + fork() was invoked from other than the main thread. Make sure that + when the "main" thread exits it calls do_exit, like a normal process. + Exit with a status code of 0. */ + if (child_proc_info->stacksize) + { + ((DWORD *)child_proc_info->stackbottom)[-17] = (DWORD)do_exit; + ((DWORD *)child_proc_info->stackbottom)[-15] = (DWORD)0; + } + + MALLOC_CHECK; + + dtable.fixup_after_fork (hParent); + ForceCloseHandle (hParent); + + MALLOC_CHECK; + + /* reload dlls if necessary */ + if (!DllList::the().forkeeMustReloadDlls() || + !DllList::the().numberOfOpenedDlls()) + sync_with_parent ("performed fork fixup.", FALSE); + else + { + DllList::the().forkeeLoadDlls(); + sync_with_parent ("loaded dlls", TRUE); + } + + (void) ForceCloseHandle (child_proc_info->subproc_ready); + (void) ForceCloseHandle (child_proc_info->forker_finished); + + if (recreate_mmaps_after_fork (myself->mmap_ptr)) + api_fatal ("recreate_mmaps_after_fork_failed"); + + res = 0; + /* Set thread local stuff to zero. Under Windows 95/98 this is sometimes + non-zero, for some reason. + FIXME: There is a memory leak here after a fork. */ + for (per_thread **t = threadstuff; *t; t++) + if ((*t)->clear_on_fork ()) + (*t)->set (); + + /* Initialize signal/process handling */ + sigproc_init (); + } + + + MALLOC_CHECK; + syscall_printf ("%d = fork()", res); + return res; + +/* Common cleanup code for failure cases */ +cleanup: + /* Remember to de-allocate the fd table. */ + child->process_state = PID_NOT_IN_USE; + if (pi.hProcess) + ForceCloseHandle1 (pi.hProcess, childhProc); + if (pi.hThread) + ForceCloseHandle (pi.hThread); + if (subproc_ready) + ForceCloseHandle (subproc_ready); + if (forker_finished) + ForceCloseHandle (forker_finished); + forker_finished = subproc_ready = child->hProcess = NULL; + return -1; +} + +static volatile void +grow_stack_slack () +{ + volatile char dummy[16384]; + dummy[0] = dummy[16383] = 0; // Just to make some slack in the stack +} + +#ifdef NEWVFORK +/* Dummy function to force second assignment below to actually be + carried out */ +static vfork_save * +get_vfork_val () +{ + return vfork_storage.val (); +} +#endif + +extern "C" +int +vfork () +{ +#ifndef NEWVFORK + return fork (); +#else + vfork_save *vf = get_vfork_val (); + + if (vf == NULL) + vf = vfork_storage.create (); + + if (!setjmp (vf->j)) + { + vf->pid = -1; + __asm__ volatile ("movl %%ebp,%0": "=r" (vf->vfork_ebp):); + __asm__ volatile ("movl (%%ebp),%0": "=r" (vf->caller_ebp):); + __asm__ volatile ("movl 4(%%ebp),%0": "=r" (vf->retaddr):); + return dtable.vfork_child_dup () ? 0 : -1; + } + + dtable.vfork_parent_restore (); + + vf = get_vfork_val (); + if (vf->pid < 0) + { + int exitval = -vf->pid; + if ((vf->pid = fork ()) == 0) + exit (exitval); + } + + vf->vfork_ebp[0] = vf->caller_ebp; + vf->vfork_ebp[1] = vf->retaddr; + return vf->pid; +#endif +} diff --git a/winsup/cygwin/gcrt0.c b/winsup/cygwin/gcrt0.c new file mode 100644 index 000000000..e565f092f --- /dev/null +++ b/winsup/cygwin/gcrt0.c @@ -0,0 +1,41 @@ +/* gcrt0.c + + Copyright 1998 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include + +extern u_char etext asm ("etext"); +extern u_char eprol asm ("__eprol"); +extern void _mcleanup (void); +extern void monstartup (u_long, u_long); + +void _monstartup (void) __attribute__((__constructor__)); + +/* startup initialization for -pg support */ + +void +_monstartup (void) +{ + static int called; + + /* Guard against multiple calls that may happen if DLLs are linked + with profile option set as well. Addede side benefit is that it + makes profiling backward compatible (GCC used to emit a call to + _monstartup when compiling main with profiling enabled). */ + if (called++) + return; + + monstartup ((u_long) &eprol, (u_long) &etext); + atexit (&_mcleanup); +} + +asm (".text"); +asm ("__eprol:"); + diff --git a/winsup/cygwin/glob.c b/winsup/cygwin/glob.c new file mode 100644 index 000000000..eaede4942 --- /dev/null +++ b/winsup/cygwin/glob.c @@ -0,0 +1,871 @@ +/* $NetBSD: __glob13.c,v 1.1.2.1 1997/10/22 06:41:27 thorpej Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Guido van Rossum. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +/* + * glob(3) -- a superset of the one defined in POSIX 1003.2. + * + * The [!...] convention to negate a range is supported (SysV, Posix, ksh). + * + * Optional extra services, controlled by flags not defined by POSIX: + * + * GLOB_QUOTE: + * Escaping convention: \ inhibits any special meaning the following + * character might have (except \ at end of string is retained). + * GLOB_MAGCHAR: + * Set in gl_flags if pattern contained a globbing character. + * GLOB_NOMAGIC: + * Same as GLOB_NOCHECK, but it will only append pattern if it did + * not contain any magic characters. [Used in csh style globbing] + * GLOB_ALTDIRFUNC: + * Use alternately specified directory access functions. + * GLOB_TILDE: + * expand ~user/foo to the /home/dir/of/user/foo + * GLOB_BRACE: + * expand {1,2}{a,b} to 1a 1b 2a 2b + * gl_matchc: + * Number of matches in the current invocation of glob. + */ + +/* CYGNUS LOCAL: don't include */ +/* #include "namespace.h" */ +/* end CYGNUS LOCAL */ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef __weak_alias +#ifdef __LIBC12_SOURCE__ +__weak_alias(glob,_glob); +__weak_alias(globfree,_globfree); +#else +#error "XXX THESE ARE NOT RIGHT!" +__weak_alias(__glob13,___glob13); +__weak_alias(__globfree13,___globfree13); +#endif /* __LIBC12_SOURCE__ */ +#endif /* __weak_alias */ + +#ifdef __LIBC12_SOURCE__ +#define STAT stat12 +#else +#define STAT stat +#endif + +#define DOLLAR '$' +#define DOT '.' +#define EOS '\0' +#define LBRACKET '[' +#define NOT '!' +#define QUESTION '?' +#define QUOTE '\\' +#define RANGE '-' +#define RBRACKET ']' +#define SEP '/' +#define STAR '*' +#define TILDE '~' +#define UNDERSCORE '_' +#define LBRACE '{' +#define RBRACE '}' +#define SLASH '/' +#define COMMA ',' + +#ifndef DEBUG + +#define M_QUOTE 0x8000 +#define M_PROTECT 0x4000 +#define M_MASK 0xffff +#define M_ASCII 0x00ff + +typedef u_short Char; + +#else + +#define M_QUOTE 0x80 +#define M_PROTECT 0x40 +#define M_MASK 0xff +#define M_ASCII 0x7f + +typedef char Char; + +#endif + + +#define CHAR(c) ((Char)((c)&M_ASCII)) +#define META(c) ((Char)((c)|M_QUOTE)) +#define M_ALL META('*') +#define M_END META(']') +#define M_NOT META('!') +#define M_ONE META('?') +#define M_RNG META('-') +#define M_SET META('[') +#define ismeta(c) (((c)&M_QUOTE) != 0) + + +static int compare __P((const void *, const void *)); +static void g_Ctoc __P((const Char *, char *)); +static int g_lstat __P((Char *, struct STAT *, glob_t *)); +static DIR *g_opendir __P((Char *, glob_t *)); +static Char *g_strchr __P((Char *, int)); +#ifdef notdef +static Char *g_strcat __P((Char *, const Char *)); +#endif +static int g_stat __P((Char *, struct STAT *, glob_t *)); +static int glob0 __P((const Char *, glob_t *)); +static int glob1 __P((Char *, glob_t *)); +static int glob2 __P((Char *, Char *, Char *, glob_t *)); +static int glob3 __P((Char *, Char *, Char *, Char *, glob_t *)); +static int globextend __P((const Char *, glob_t *)); +static const Char * globtilde __P((const Char *, Char *, glob_t *)); +static int globexp1 __P((const Char *, glob_t *)); +static int globexp2 __P((const Char *, const Char *, glob_t *, int *)); +static int match __P((Char *, Char *, Char *)); +#ifdef DEBUG +static void qprintf __P((const char *, Char *)); +#endif + +#undef MAXPATHLEN +#define MAXPATHLEN 16384 + +int +glob(pattern, flags, errfunc, pglob) + const char *pattern; + int flags, (*errfunc) __P((const char *, int)); + glob_t *pglob; +{ + const u_char *patnext; + int c; + Char *bufnext, *bufend, patbuf[MAXPATHLEN+1]; + + patnext = (u_char *) pattern; + if (!(flags & GLOB_APPEND)) { + pglob->gl_pathc = 0; + pglob->gl_pathv = NULL; + if (!(flags & GLOB_DOOFFS)) + pglob->gl_offs = 0; + } + pglob->gl_flags = flags & ~GLOB_MAGCHAR; + pglob->gl_errfunc = errfunc; + pglob->gl_matchc = 0; + + bufnext = patbuf; + bufend = bufnext + MAXPATHLEN; + if (flags & GLOB_QUOTE) { + /* Protect the quoted characters. */ + while (bufnext < bufend && (c = *patnext++) != EOS) + if (c == QUOTE) { + if ((c = *patnext++) == EOS) { + c = QUOTE; + --patnext; + } + *bufnext++ = c | M_PROTECT; + } + else + *bufnext++ = c; + } + else + while (bufnext < bufend && (c = *patnext++) != EOS) + *bufnext++ = c; + *bufnext = EOS; + + if (flags & GLOB_BRACE) + return globexp1(patbuf, pglob); + else + return glob0(patbuf, pglob); +} + +/* + * Expand recursively a glob {} pattern. When there is no more expansion + * invoke the standard globbing routine to glob the rest of the magic + * characters + */ +static int globexp1(pattern, pglob) + const Char *pattern; + glob_t *pglob; +{ + const Char* ptr = pattern; + int rv; + + /* Protect a single {}, for find(1), like csh */ + if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) + return glob0(pattern, pglob); + + while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL) + if (!globexp2(ptr, pattern, pglob, &rv)) + return rv; + + return glob0(pattern, pglob); +} + + +/* + * Recursive brace globbing helper. Tries to expand a single brace. + * If it succeeds then it invokes globexp1 with the new pattern. + * If it fails then it tries to glob the rest of the pattern and returns. + */ +static int globexp2(ptr, pattern, pglob, rv) + const Char *ptr, *pattern; + glob_t *pglob; + int *rv; +{ + int i; + Char *lm, *ls; + const Char *pe, *pm, *pl; + Char patbuf[MAXPATHLEN + 1]; + + /* copy part up to the brace */ + for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++) + continue; + ls = lm; + + /* Find the balanced brace */ + for (i = 0, pe = ++ptr; *pe; pe++) + if (*pe == LBRACKET) { + /* Ignore everything between [] */ + for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++) + continue; + if (*pe == EOS) { + /* + * We could not find a matching RBRACKET. + * Ignore and just look for RBRACE + */ + pe = pm; + } + } + else if (*pe == LBRACE) + i++; + else if (*pe == RBRACE) { + if (i == 0) + break; + i--; + } + + /* Non matching braces; just glob the pattern */ + if (i != 0 || *pe == EOS) { + *rv = glob0(patbuf, pglob); + return 0; + } + + for (i = 0, pl = pm = ptr; pm <= pe; pm++) + switch (*pm) { + case LBRACKET: + /* Ignore everything between [] */ + for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++) + continue; + if (*pm == EOS) { + /* + * We could not find a matching RBRACKET. + * Ignore and just look for RBRACE + */ + pm = pl; + } + break; + + case LBRACE: + i++; + break; + + case RBRACE: + if (i) { + i--; + break; + } + /* FALLTHROUGH */ + case COMMA: + if (i && *pm == COMMA) + break; + else { + /* Append the current string */ + for (lm = ls; (pl < pm); *lm++ = *pl++) + continue; + /* + * Append the rest of the pattern after the + * closing brace + */ + for (pl = pe + 1; (*lm++ = *pl++) != EOS;) + continue; + + /* Expand the current pattern */ +#ifdef DEBUG + qprintf("globexp2:", patbuf); +#endif + *rv = globexp1(patbuf, pglob); + + /* move after the comma, to the next string */ + pl = pm + 1; + } + break; + + default: + break; + } + *rv = 0; + return 0; +} + + + +/* + * expand tilde from the passwd file. + */ +static const Char * +globtilde(pattern, patbuf, pglob) + const Char *pattern; + Char *patbuf; + glob_t *pglob; +{ + struct passwd *pwd; + char *h; + const Char *p; + Char *b; + + if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE)) + return pattern; + + /* Copy up to the end of the string or / */ + for (p = pattern + 1, h = (char *) patbuf; *p && *p != SLASH; + *h++ = *p++) + continue; + + *h = EOS; + + if (((char *) patbuf)[0] == EOS) { + /* + * handle a plain ~ or ~/ by expanding $HOME + * first and then trying the password file + */ + if ((h = getenv("HOME")) == NULL) { + if ((pwd = getpwuid(getuid())) == NULL) + return pattern; + else + h = pwd->pw_dir; + } + } + else { + /* + * Expand a ~user + */ + if ((pwd = getpwnam((char*) patbuf)) == NULL) + return pattern; + else + h = pwd->pw_dir; + } + + /* Copy the home directory */ + for (b = patbuf; *h; *b++ = *h++) + continue; + + /* Append the rest of the pattern */ + while ((*b++ = *p++) != EOS) + continue; + + return patbuf; +} + + +/* + * The main glob() routine: compiles the pattern (optionally processing + * quotes), calls glob1() to do the real pattern matching, and finally + * sorts the list (unless unsorted operation is requested). Returns 0 + * if things went well, nonzero if errors occurred. It is not an error + * to find no matches. + */ +static int +glob0(pattern, pglob) + const Char *pattern; + glob_t *pglob; +{ + const Char *qpatnext; + int c, err, oldpathc; + Char *bufnext, patbuf[MAXPATHLEN+1]; + + qpatnext = globtilde(pattern, patbuf, pglob); + oldpathc = pglob->gl_pathc; + bufnext = patbuf; + + /* We don't need to check for buffer overflow any more. */ + while ((c = *qpatnext++) != EOS) { + switch (c) { + case LBRACKET: + c = *qpatnext; + if (c == NOT) + ++qpatnext; + if (*qpatnext == EOS || + g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) { + *bufnext++ = LBRACKET; + if (c == NOT) + --qpatnext; + break; + } + *bufnext++ = M_SET; + if (c == NOT) + *bufnext++ = M_NOT; + c = *qpatnext++; + do { + *bufnext++ = CHAR(c); + if (*qpatnext == RANGE && + (c = qpatnext[1]) != RBRACKET) { + *bufnext++ = M_RNG; + *bufnext++ = CHAR(c); + qpatnext += 2; + } + } while ((c = *qpatnext++) != RBRACKET); + pglob->gl_flags |= GLOB_MAGCHAR; + *bufnext++ = M_END; + break; + case QUESTION: + pglob->gl_flags |= GLOB_MAGCHAR; + *bufnext++ = M_ONE; + break; + case STAR: + pglob->gl_flags |= GLOB_MAGCHAR; + /* collapse adjacent stars to one, + * to avoid exponential behavior + */ + if (bufnext == patbuf || bufnext[-1] != M_ALL) + *bufnext++ = M_ALL; + break; + default: + *bufnext++ = CHAR(c); + break; + } + } + *bufnext = EOS; +#ifdef DEBUG + qprintf("glob0:", patbuf); +#endif + + if ((err = glob1(patbuf, pglob)) != 0) + return(err); + + /* + * If there was no match we are going to append the pattern + * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified + * and the pattern did not contain any magic characters + * GLOB_NOMAGIC is there just for compatibility with csh. + */ + if (pglob->gl_pathc == oldpathc && + ((pglob->gl_flags & GLOB_NOCHECK) || + ((pglob->gl_flags & GLOB_NOMAGIC) && + !(pglob->gl_flags & GLOB_MAGCHAR)))) + return(globextend(pattern, pglob)); + else if (!(pglob->gl_flags & GLOB_NOSORT)) + qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc, + pglob->gl_pathc - oldpathc, sizeof(char *), compare); + return(0); +} + +static int +compare(p, q) + const void *p, *q; +{ + return(strcmp(*(char **)p, *(char **)q)); +} + +static int +glob1(pattern, pglob) + Char *pattern; + glob_t *pglob; +{ + Char pathbuf[MAXPATHLEN+1]; + + /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */ + if (*pattern == EOS) + return(0); + return(glob2(pathbuf, pathbuf, pattern, pglob)); +} + +/* + * The functions glob2 and glob3 are mutually recursive; there is one level + * of recursion for each segment in the pattern that contains one or more + * meta characters. + */ +static int +glob2(pathbuf, pathend, pattern, pglob) + Char *pathbuf, *pathend, *pattern; + glob_t *pglob; +{ + struct STAT sb; + Char *p, *q; + int anymeta; + + /* + * Loop over pattern segments until end of pattern or until + * segment with meta character found. + */ + for (anymeta = 0;;) { + if (*pattern == EOS) { /* End of pattern? */ + *pathend = EOS; + if (g_lstat(pathbuf, &sb, pglob)) + return(0); + + if (((pglob->gl_flags & GLOB_MARK) && + pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) + || (S_ISLNK(sb.st_mode) && + (g_stat(pathbuf, &sb, pglob) == 0) && + S_ISDIR(sb.st_mode)))) { + *pathend++ = SEP; + *pathend = EOS; + } + ++pglob->gl_matchc; + return(globextend(pathbuf, pglob)); + } + + /* Find end of next segment, copy tentatively to pathend. */ + q = pathend; + p = pattern; + while (*p != EOS && *p != SEP) { + if (ismeta(*p)) + anymeta = 1; + *q++ = *p++; + } + + if (!anymeta) { /* No expansion, do next segment. */ + pathend = q; + pattern = p; + while (*pattern == SEP) + *pathend++ = *pattern++; + } else /* Need expansion, recurse. */ + return(glob3(pathbuf, pathend, pattern, p, pglob)); + } + /* NOTREACHED */ +} + +static int +glob3(pathbuf, pathend, pattern, restpattern, pglob) + Char *pathbuf, *pathend, *pattern, *restpattern; + glob_t *pglob; +{ + register struct dirent *dp; + DIR *dirp; + int err; + char buf[MAXPATHLEN]; + + /* + * The readdirfunc declaration can't be prototyped, because it is + * assigned, below, to two functions which are prototyped in glob.h + * and dirent.h as taking pointers to differently typed opaque + * structures. + */ + struct dirent *(*readdirfunc) __P((void *)); + + *pathend = EOS; + errno = 0; + + if ((dirp = g_opendir(pathbuf, pglob)) == NULL) { + /* TODO: don't call for ENOENT or ENOTDIR? */ + if (pglob->gl_errfunc) { + g_Ctoc(pathbuf, buf); + if (pglob->gl_errfunc(buf, errno) || + pglob->gl_flags & GLOB_ERR) + return (GLOB_ABEND); + } + return(0); + } + + err = 0; + + /* Search directory for matching names. */ + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + readdirfunc = pglob->gl_readdir; + else + readdirfunc = (struct dirent *(*)__P((void *))) readdir; + while ((dp = (*readdirfunc)(dirp))) { + register u_char *sc; + register Char *dc; + + /* Initial DOT must be matched literally. */ + if (dp->d_name[0] == DOT && *pattern != DOT) + continue; + for (sc = (u_char *) dp->d_name, dc = pathend; + (*dc++ = *sc++) != EOS;) + continue; + if (!match(pathend, pattern, restpattern)) { + *pathend = EOS; + continue; + } + err = glob2(pathbuf, --dc, restpattern, pglob); + if (err) + break; + } + + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + (*pglob->gl_closedir)(dirp); + else + closedir(dirp); + return(err); +} + + +/* + * Extend the gl_pathv member of a glob_t structure to accomodate a new item, + * add the new item, and update gl_pathc. + * + * This assumes the BSD realloc, which only copies the block when its size + * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic + * behavior. + * + * Return 0 if new item added, error code if memory couldn't be allocated. + * + * Invariant of the glob_t structure: + * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and + * gl_pathv points to (gl_offs + gl_pathc + 1) items. + */ +static int +globextend(path, pglob) + const Char *path; + glob_t *pglob; +{ + register char **pathv; + register int i; + u_int newsize; + char *copy; + const Char *p; + + newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); + pathv = pglob->gl_pathv ? + realloc((char *)pglob->gl_pathv, newsize) : + malloc(newsize); + if (pathv == NULL) + return(GLOB_NOSPACE); + + if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { + /* first time around -- clear initial gl_offs items */ + pathv += pglob->gl_offs; + for (i = pglob->gl_offs; --i >= 0; ) + *--pathv = NULL; + } + pglob->gl_pathv = pathv; + + for (p = path; *p++;) + continue; + if ((copy = malloc(p - path)) != NULL) { + g_Ctoc(path, copy); + pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; + } + pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; + return(copy == NULL ? GLOB_NOSPACE : 0); +} + + +/* + * pattern matching function for filenames. Each occurrence of the * + * pattern causes a recursion level. + */ +static int +match(name, pat, patend) + register Char *name, *pat, *patend; +{ + int ok, negate_range; + Char c, k; + + while (pat < patend) { + c = *pat++; + switch (c & M_MASK) { + case M_ALL: + if (pat == patend) + return(1); + do + if (match(name, pat, patend)) + return(1); + while (*name++ != EOS); + return(0); + case M_ONE: + if (*name++ == EOS) + return(0); + break; + case M_SET: + ok = 0; + if ((k = *name++) == EOS) + return(0); + if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS) + ++pat; + while (((c = *pat++) & M_MASK) != M_END) + if ((*pat & M_MASK) == M_RNG) { + if (c <= k && k <= pat[1]) + ok = 1; + pat += 2; + } else if (c == k) + ok = 1; + if (ok == negate_range) + return(0); + break; + default: + if (*name++ != c) + return(0); + break; + } + } + return(*name == EOS); +} + +/* Free allocated data belonging to a glob_t structure. */ +void +globfree(pglob) + glob_t *pglob; +{ + register int i; + register char **pp; + + if (pglob->gl_pathv != NULL) { + pp = pglob->gl_pathv + pglob->gl_offs; + for (i = pglob->gl_pathc; i--; ++pp) + if (*pp) + free(*pp); + free(pglob->gl_pathv); + } +} + +static DIR * +g_opendir(str, pglob) + register Char *str; + glob_t *pglob; +{ + char buf[MAXPATHLEN]; + + if (!*str) + strcpy(buf, "."); + else + g_Ctoc(str, buf); + + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + return((*pglob->gl_opendir)(buf)); + + return(opendir(buf)); +} + +static int +g_lstat(fn, sb, pglob) + register Char *fn; + struct STAT *sb; + glob_t *pglob; +{ + char buf[MAXPATHLEN]; + + g_Ctoc(fn, buf); + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + return((*pglob->gl_lstat)(buf, sb)); + return(lstat(buf, sb)); +} + +static int +g_stat(fn, sb, pglob) + register Char *fn; + struct STAT *sb; + glob_t *pglob; +{ + char buf[MAXPATHLEN]; + + g_Ctoc(fn, buf); + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + return((*pglob->gl_stat)(buf, sb)); + return(stat(buf, sb)); +} + +static Char * +g_strchr(str, ch) + Char *str; + int ch; +{ + do { + if (*str == ch) + return (str); + } while (*str++); + return (NULL); +} + +#ifdef notdef +static Char * +g_strcat(dst, src) + Char *dst; + const Char* src; +{ + Char *sdst = dst; + + while (*dst++) + continue; + --dst; + while((*dst++ = *src++) != EOS) + continue; + + return (sdst); +} +#endif + +static void +g_Ctoc(str, buf) + register const Char *str; + char *buf; +{ + register char *dc; + + for (dc = buf; (*dc++ = *str++) != EOS;) + continue; +} + +#ifdef DEBUG +static void +qprintf(str, s) + const char *str; + register Char *s; +{ + register Char *p; + + (void)printf("%s:\n", str); + for (p = s; *p; p++) + (void)printf("%c", CHAR(*p)); + (void)printf("\n"); + for (p = s; *p; p++) + (void)printf("%c", *p & M_PROTECT ? '"' : ' '); + (void)printf("\n"); + for (p = s; *p; p++) + (void)printf("%c", ismeta(*p) ? '_' : ' '); + (void)printf("\n"); +} +#endif diff --git a/winsup/cygwin/gmon.c b/winsup/cygwin/gmon.c new file mode 100644 index 000000000..6187a7c8f --- /dev/null +++ b/winsup/cygwin/gmon.c @@ -0,0 +1,277 @@ +/*- + * Copyright (c) 1983, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if !defined(lint) && defined(LIBC_SCCS) +static char rcsid[] = "$OpenBSD: gmon.c,v 1.8 1997/07/23 21:11:27 kstailey Exp $"; +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include + +/* XXX needed? */ +//extern char *minbrk __asm ("minbrk"); + +struct gmonparam _gmonparam = { GMON_PROF_OFF }; + +static int s_scale; +/* see profil(2) where this is describe (incorrectly) */ +#define SCALE_1_TO_1 0x10000L + +#define ERR(s) write(2, s, sizeof(s)) + +void moncontrol __P((int)); + +static void * +fake_sbrk(int size) +{ + return malloc(size); +} + +void +monstartup(lowpc, highpc) + u_long lowpc; + u_long highpc; +{ + register int o; + char *cp; + struct gmonparam *p = &_gmonparam; + + /* + * round lowpc and highpc to multiples of the density we're using + * so the rest of the scaling (here and in gprof) stays in ints. + */ + p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER)); + p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER)); + p->textsize = p->highpc - p->lowpc; + p->kcountsize = p->textsize / HISTFRACTION; + p->hashfraction = HASHFRACTION; + p->fromssize = p->textsize / p->hashfraction; + p->tolimit = p->textsize * ARCDENSITY / 100; + if (p->tolimit < MINARCS) + p->tolimit = MINARCS; + else if (p->tolimit > MAXARCS) + p->tolimit = MAXARCS; + p->tossize = p->tolimit * sizeof(struct tostruct); + + cp = fake_sbrk(p->kcountsize + p->fromssize + p->tossize); + if (cp == (char *)-1) { + ERR("monstartup: out of memory\n"); + return; + } +#ifdef notdef + bzero(cp, p->kcountsize + p->fromssize + p->tossize); +#endif + p->tos = (struct tostruct *)cp; + cp += p->tossize; + p->kcount = (u_short *)cp; + cp += p->kcountsize; + p->froms = (u_short *)cp; + + /* XXX minbrk needed? */ + //minbrk = fake_sbrk(0); + p->tos[0].link = 0; + + o = p->highpc - p->lowpc; + if (p->kcountsize < o) { +#ifndef notdef + s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1; +#else /* avoid floating point */ + int quot = o / p->kcountsize; + + if (quot >= 0x10000) + s_scale = 1; + else if (quot >= 0x100) + s_scale = 0x10000 / quot; + else if (o >= 0x800000) + s_scale = 0x1000000 / (o / (p->kcountsize >> 8)); + else + s_scale = 0x1000000 / ((o << 8) / p->kcountsize); +#endif + } else + s_scale = SCALE_1_TO_1; + + moncontrol(1); +} + +void +_mcleanup() +{ + int fd; + int hz; + int fromindex; + int endfrom; + u_long frompc; + int toindex; + struct rawarc rawarc; + struct gmonparam *p = &_gmonparam; + struct gmonhdr gmonhdr, *hdr; + char *proffile; +#ifdef DEBUG + int log, len; + char dbuf[200]; +#endif + + if (p->state == GMON_PROF_ERROR) + ERR("_mcleanup: tos overflow\n"); + + hz = PROF_HZ; + moncontrol(0); + +#ifdef nope + if ((profdir = getenv("PROFDIR")) != NULL) { + extern char *__progname; + char *s, *t, *limit; + pid_t pid; + long divisor; + + /* If PROFDIR contains a null value, no profiling + output is produced */ + if (*profdir == '\0') { + return; + } + + limit = buf + sizeof buf - 1 - 10 - 1 - + strlen(__progname) - 1; + t = buf; + s = profdir; + while((*t = *s) != '\0' && t < limit) { + t++; + s++; + } + *t++ = '/'; + + /* + * Copy and convert pid from a pid_t to a string. For + * best performance, divisor should be initialized to + * the largest power of 10 less than PID_MAX. + */ + pid = getpid(); + divisor=10000; + while (divisor > pid) divisor /= 10; /* skip leading zeros */ + do { + *t++ = (pid/divisor) + '0'; + pid %= divisor; + } while (divisor /= 10); + *t++ = '.'; + + s = __progname; + while ((*t++ = *s++) != '\0') + ; + + proffile = buf; + } else { + proffile = "gmon.out"; + } +#else + proffile = "gmon.out"; +#endif + + fd = open(proffile , O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0666); + if (fd < 0) { + perror( proffile ); + return; + } +#ifdef DEBUG + log = open("gmon.log", O_CREAT|O_TRUNC|O_WRONLY, 0664); + if (log < 0) { + perror("mcount: gmon.log"); + return; + } + len = sprintf(dbuf, "[mcleanup1] kcount 0x%x ssiz %d\n", + p->kcount, p->kcountsize); + write(log, dbuf, len); +#endif + hdr = (struct gmonhdr *)&gmonhdr; + hdr->lpc = p->lowpc; + hdr->hpc = p->highpc; + hdr->ncnt = p->kcountsize + sizeof(gmonhdr); + hdr->version = GMONVERSION; + hdr->profrate = hz; + write(fd, (char *)hdr, sizeof *hdr); + write(fd, p->kcount, p->kcountsize); + endfrom = p->fromssize / sizeof(*p->froms); + for (fromindex = 0; fromindex < endfrom; fromindex++) { + if (p->froms[fromindex] == 0) + continue; + + frompc = p->lowpc; + frompc += fromindex * p->hashfraction * sizeof(*p->froms); + for (toindex = p->froms[fromindex]; toindex != 0; + toindex = p->tos[toindex].link) { +#ifdef DEBUG + len = sprintf(dbuf, + "[mcleanup2] frompc 0x%x selfpc 0x%x count %d\n" , + frompc, p->tos[toindex].selfpc, + p->tos[toindex].count); + write(log, dbuf, len); +#endif + rawarc.raw_frompc = frompc; + rawarc.raw_selfpc = p->tos[toindex].selfpc; + rawarc.raw_count = p->tos[toindex].count; + write(fd, &rawarc, sizeof rawarc); + } + } + close(fd); +} + +/* + * Control profiling + * profiling is what mcount checks to see if + * all the data structures are ready. + */ +void +moncontrol(mode) + int mode; +{ + struct gmonparam *p = &_gmonparam; + + if (mode) { + /* start */ + profil((char *)p->kcount, p->kcountsize, p->lowpc, + s_scale); + p->state = GMON_PROF_ON; + } else { + /* stop */ + profil((char *)0, 0, 0, 0); + p->state = GMON_PROF_OFF; + } +} + + diff --git a/winsup/cygwin/gmon.h b/winsup/cygwin/gmon.h new file mode 100644 index 000000000..be016791e --- /dev/null +++ b/winsup/cygwin/gmon.h @@ -0,0 +1,166 @@ +/* $OpenBSD: gmon.h,v 1.3 1996/04/21 22:31:46 deraadt Exp $ */ +/* $NetBSD: gmon.h,v 1.5 1996/04/09 20:55:30 cgd Exp $ */ + +/*- + * Copyright (c) 1982, 1986, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)gmon.h 8.2 (Berkeley) 1/4/94 + */ + +#ifndef _SYS_GMON_H_ +#define _SYS_GMON_H_ + +#ifndef __P +#define __P(x) x +#endif + +#include + +/* + * Structure prepended to gmon.out profiling data file. + */ +struct gmonhdr { + u_long lpc; /* base pc address of sample buffer */ + u_long hpc; /* max pc address of sampled buffer */ + int ncnt; /* size of sample buffer (plus this header) */ + int version; /* version number */ + int profrate; /* profiling clock rate */ + int spare[3]; /* reserved */ +}; +#define GMONVERSION 0x00051879 + +/* + * histogram counters are unsigned shorts (according to the kernel). + */ +#define HISTCOUNTER unsigned short + +/* + * fraction of text space to allocate for histogram counters here, 1/2 + */ +#define HISTFRACTION 2 + +/* + * Fraction of text space to allocate for from hash buckets. + * The value of HASHFRACTION is based on the minimum number of bytes + * of separation between two subroutine call points in the object code. + * Given MIN_SUBR_SEPARATION bytes of separation the value of + * HASHFRACTION is calculated as: + * + * HASHFRACTION = MIN_SUBR_SEPARATION / (2 * sizeof(short) - 1); + * + * For example, on the VAX, the shortest two call sequence is: + * + * calls $0,(r0) + * calls $0,(r0) + * + * which is separated by only three bytes, thus HASHFRACTION is + * calculated as: + * + * HASHFRACTION = 3 / (2 * 2 - 1) = 1 + * + * Note that the division above rounds down, thus if MIN_SUBR_FRACTION + * is less than three, this algorithm will not work! + * + * In practice, however, call instructions are rarely at a minimal + * distance. Hence, we will define HASHFRACTION to be 2 across all + * architectures. This saves a reasonable amount of space for + * profiling data structures without (in practice) sacrificing + * any granularity. + */ +#define HASHFRACTION 2 + +/* + * percent of text space to allocate for tostructs with a minimum. + */ +#define ARCDENSITY 2 +#define MINARCS 50 +#define MAXARCS ((1 << (8 * sizeof(HISTCOUNTER))) - 2) + +struct tostruct { + u_long selfpc; + long count; + u_short link; + u_short pad; +}; + +/* + * a raw arc, with pointers to the calling site and + * the called site and a count. + */ +struct rawarc { + u_long raw_frompc; + u_long raw_selfpc; + long raw_count; +}; + +/* + * general rounding functions. + */ +#define ROUNDDOWN(x,y) (((x)/(y))*(y)) +#define ROUNDUP(x,y) ((((x)+(y)-1)/(y))*(y)) + +/* + * The profiling data structures are housed in this structure. + */ +struct gmonparam { + int state; + u_short *kcount; + u_long kcountsize; + u_short *froms; + u_long fromssize; + struct tostruct *tos; + u_long tossize; + long tolimit; + u_long lowpc; + u_long highpc; + u_long textsize; + u_long hashfraction; +}; +extern struct gmonparam _gmonparam; + +/* + * Possible states of profiling. + */ +#define GMON_PROF_ON 0 +#define GMON_PROF_BUSY 1 +#define GMON_PROF_ERROR 2 +#define GMON_PROF_OFF 3 + +/* + * Sysctl definitions for extracting profiling information from the kernel. + */ +#define GPROF_STATE 0 /* int: profiling enabling variable */ +#define GPROF_COUNT 1 /* struct: profile tick count buffer */ +#define GPROF_FROMS 2 /* struct: from location hash bucket */ +#define GPROF_TOS 3 /* struct: destination/count structure */ +#define GPROF_GMONPARAM 4 /* struct: profiling parameters (see above) */ +#endif /* !_SYS_GMONH_ */ diff --git a/winsup/cygwin/grp.cc b/winsup/cygwin/grp.cc new file mode 100644 index 000000000..5263c536b --- /dev/null +++ b/winsup/cygwin/grp.cc @@ -0,0 +1,283 @@ +/* grp.cc + + Copyright 1996, 1997, 1998, 2000 Cygnus Solutions. + + Original stubs by Jason Molenda of Cygnus Support, crash@cygnus.com + First implementation by Gunther Ebert, gunther.ebert@ixos-leipzig.de + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include "winsup.h" + +/* Read /etc/group only once for better performance. This is done + on the first call that needs information from it. */ + +#define MAX_DOMAIN_NAME 100 + +static NO_COPY const char *etc_group = "/etc/group"; +static struct group *group_buf = NULL; /* group contents in memory */ +static int curr_lines = 0; +static int max_lines = 0; + +/* Position in the group cache */ +#ifdef _MT_SAFE +#define grp_pos _reent_winsup()->_grp_pos +#else +static int grp_pos = 0; +#endif + +/* Set to 1 when /etc/group has been read in by read_etc_group (). */ +/* Functions in this file need to check the value of group_in_memory_p + and read in the group file if it isn't set. */ +/* FIXME: This should be static but this is called in uinfo_init outside + this file */ +int group_in_memory_p = 0; + +static int +parse_grp (struct group &grp, const char *line) +{ + int len = strlen(line); + char *newline = (char *) malloc (len + 1); + (void) memcpy (newline, line, len + 1); + + if (newline[--len] == '\n') + newline[len] = '\0'; + + char *dp = strchr (newline, ':'); + + if (!dp) + return 0; + + *dp++ = '\0'; + grp.gr_name = newline; + + grp.gr_passwd = dp; + dp = strchr (grp.gr_passwd, ':'); + if (dp) + { + *dp++ = '\0'; + if (!strlen (grp.gr_passwd)) + grp.gr_passwd = NULL; + + grp.gr_gid = atoi (dp); + dp = strchr (dp, ':'); + if (dp) + { + if (*++dp) + { + int i = 0; + char *cp; + + for (cp = dp; (cp = strchr (cp, ',')) != NULL; ++cp) + ++i; + char **namearray = (char **) calloc (i + 2, sizeof (char *)); + if (namearray) + { + i = 0; + for (cp = dp; (cp = strchr (dp, ',')) != NULL; dp = cp + 1) + { + *cp = '\0'; + namearray[i++] = dp; + } + namearray[i++] = dp; + namearray[i] = NULL; + } + grp.gr_mem = namearray; + } + else + grp.gr_mem = NULL; + return 1; + } + } + return 0; +} + +/* Read one line from /etc/group into the group cache */ +static void +add_grp_line (const char *line) +{ + if (curr_lines == max_lines) + { + max_lines += 10; + group_buf = (struct group *) realloc (group_buf, max_lines * sizeof (struct group)); + } + if (parse_grp (group_buf[curr_lines], line)) + curr_lines++; +} + +extern PSID get_admin_sid (); + +/* Cygwin internal */ +/* Read in /etc/group and save contents in the group cache */ +/* This sets group_in_memory_p to 1 so functions in this file can + tell that /etc/group has been read in */ +/* FIXME: should be static but this is called in uinfo_init outside this + file */ +void +read_etc_group () +{ + extern int group_sem; + char linebuf [ 200 ]; + char group_name [ MAX_USER_NAME ]; + DWORD group_name_len = MAX_USER_NAME; + + strncpy (group_name, "Administrators", sizeof (group_name)); + + ++group_sem; + FILE *f = fopen (etc_group, "r"); + --group_sem; + + if (f) + { + while (fgets (linebuf, sizeof (linebuf), f) != NULL) + { + if (strlen (linebuf)) + add_grp_line (linebuf); + } + + fclose (f); + } + else /* /etc/group doesn't exist -- create default one in memory */ + { + char domain_name [ MAX_DOMAIN_NAME ]; + DWORD domain_name_len = MAX_DOMAIN_NAME; + SID_NAME_USE acType; + debug_printf ("Emulating /etc/group"); + if (! LookupAccountSidA (NULL , + get_admin_sid () , + group_name, + &group_name_len, + domain_name, + &domain_name_len, + &acType)) + { + strcpy (group_name, "unknown"); + debug_printf ("Failed to get local admins group name. %E"); + } + + snprintf (linebuf, sizeof (linebuf), "%s::%u:\n", group_name, DEFAULT_GID); + add_grp_line (linebuf); + } + + group_in_memory_p = 1; +} + +extern "C" +struct group * +getgrgid (gid_t gid) +{ + struct group * default_grp = NULL; + if (!group_in_memory_p) + read_etc_group(); + + for (int i = 0; i < curr_lines; i++) + { + if (group_buf[i].gr_gid == DEFAULT_GID) + default_grp = group_buf + i; + if (group_buf[i].gr_gid == gid) + return group_buf + i; + } + + return default_grp; +} + +extern "C" +struct group * +getgrnam (const char *name) +{ + if (!group_in_memory_p) + read_etc_group(); + + for (int i = 0; i < curr_lines; i++) + if (strcasematch (group_buf[i].gr_name, name)) + return group_buf + i; + + /* Didn't find requested group */ + return NULL; +} + +extern "C" +void +endgrent() +{ + grp_pos = 0; +} + +extern "C" +struct group * +getgrent() +{ + if (!group_in_memory_p) + read_etc_group(); + + if (grp_pos < curr_lines) + return group_buf + grp_pos++; + + return NULL; +} + +extern "C" +void +setgrent () +{ + grp_pos = 0; +} + +int +getgroups (int gidsetsize, gid_t *grouplist, gid_t gid, const char *username) +{ + if (!group_in_memory_p) + read_etc_group(); + + int cnt = 0; + + for (int i = 0; i < curr_lines; ++i) + if (gid == group_buf[i].gr_gid) + { + if (cnt < gidsetsize) + grouplist[cnt] = group_buf[i].gr_gid; + ++cnt; + if (gidsetsize && cnt >= gidsetsize) + goto out; + } + else if (group_buf[i].gr_mem) + for (int gi = 0; group_buf[i].gr_mem[gi]; ++gi) + if (! strcasecmp (username, group_buf[i].gr_mem[gi])) + { + if (cnt < gidsetsize) + grouplist[cnt] = group_buf[i].gr_gid; + ++cnt; + if (gidsetsize && cnt >= gidsetsize) + goto out; + } +out: + return cnt; +} + +extern "C" +int +getgroups (int gidsetsize, gid_t *grouplist) +{ +#if 0 + if (gidsetsize <= 0) + return 0; + grouplist[0] = myself->gid; + return 1; +#else + return getgroups (gidsetsize, grouplist, myself->gid, myself->username); +#endif +} + +extern "C" +int +initgroups (const char *user, gid_t grp) +{ + return 0; +} diff --git a/winsup/cygwin/heap.cc b/winsup/cygwin/heap.cc new file mode 100644 index 000000000..7bbe882d8 --- /dev/null +++ b/winsup/cygwin/heap.cc @@ -0,0 +1,140 @@ +/* heap.cc: Cygwin heap manager. + + Copyright 1996, 1997, 1998, 1999 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include "winsup.h" + +#define brksize ((char *) user_data->heaptop - (char *) user_data->heapbase) +#define brk (user_data->heapptr) +#define brkbase (user_data->heapbase) +#define brktop (user_data->heaptop) +#define brkchunk (cygwin_shared->heap_chunk_size ()) +#define assert(x) + +static unsigned page_const = 0; + +static int __inline +getpagesize(void) +{ + SYSTEM_INFO si; + GetSystemInfo(&si); + return (int)si.dwPageSize; +} + +/* Initialize the heap at process start up. */ + +void +heap_init () +{ + /* If we're the forkee, we must allocate the heap at exactly the same place + as our parent. If not, we don't care where it ends up. */ + + page_const = getpagesize(); + if (brkbase) + { + DWORD chunk = brkchunk; /* allocation chunk */ + /* total size commited in parent */ + DWORD allocsize = (char *) brktop - (char *) brkbase; + /* round up by chunk size */ + DWORD reserve_size = chunk * ((allocsize + (chunk - 1)) / chunk); + + /* Loop until we've managed to reserve an adequate amount of memory. */ + char *p; + for (;;) + { + p = (char *) VirtualAlloc (brkbase, reserve_size, + MEM_RESERVE, PAGE_READWRITE); + if (p) + break; + if ((reserve_size -= page_const) <= allocsize) + break; + } + if (p == NULL) + api_fatal ("1. unable to allocate heap, heap_chunk_size %d, pid %d, %E", + brkchunk, myself->pid); + if (p != brkbase) + api_fatal ("heap allocated but not at %p", brkbase); + if (! VirtualAlloc (brkbase, allocsize, MEM_COMMIT, PAGE_READWRITE)) + api_fatal ("MEM_COMMIT failed, %E"); + } + else + { + /* Initialize page mask and default heap size. Preallocate a heap + * to assure contiguous memory. */ + brk = brktop = brkbase = VirtualAlloc(NULL, brkchunk, MEM_RESERVE, PAGE_NOACCESS); + if (brkbase == NULL) + api_fatal ("2. unable to allocate heap, heap_chunk_size %d, %E", + brkchunk); + } + + page_const--; + malloc_init (); +} + +#define pround(n) (((size_t)(n) + page_const) & ~page_const) + +/* FIXME: This function no longer handles "split heaps". */ + +extern "C" void * +_sbrk(int n) +{ + char *newtop, *newbrk; + unsigned commitbytes, newbrksize; + + if (n == 0) + return brk; /* Just wanted to find current brk address */ + + newbrk = (char *) brk + n; /* Where new brk will be */ + newtop = (char *) pround (newbrk); /* Actual top of allocated memory - + on page boundary */ + + if (newtop == brktop) + goto good; + + if (n < 0) + { /* Freeing memory */ + assert(newtop < brktop); + n = (char *) brktop - newtop; + if (VirtualFree(newtop, n, MEM_DECOMMIT)) /* Give it back to OS */ + goto good; /* Didn't take */ + else + goto err; + } + + assert(newtop > brktop); + + /* Need to grab more pages from the OS. If this fails it may be because + * we have used up previously reserved memory. Or, we're just plumb out + * of memory. */ + commitbytes = pround (newtop - (char *) brktop); + if (VirtualAlloc(brktop, commitbytes, MEM_COMMIT, PAGE_READWRITE) != NULL) + goto good; + + /* Couldn't allocate memory. Maybe we can reserve some more. + Reserve either the maximum of the standard brkchunk or the requested + amount. Then attempt to actually allocate it. */ + + if ((newbrksize = brkchunk) < commitbytes) + newbrksize = commitbytes; + + if ((VirtualAlloc(brktop, newbrksize, MEM_RESERVE, PAGE_NOACCESS) != NULL) && + (VirtualAlloc(brktop, commitbytes, MEM_COMMIT, PAGE_READWRITE) != NULL)) + goto good; + +err: + set_errno (ENOMEM); + return (void *) -1; + +good: + void *oldbrk = brk; + brk = newbrk; + brktop = newtop; + return oldbrk; +} diff --git a/winsup/cygwin/include/a.out.h b/winsup/cygwin/include/a.out.h new file mode 100644 index 000000000..493c63cce --- /dev/null +++ b/winsup/cygwin/include/a.out.h @@ -0,0 +1,421 @@ +#ifndef _A_OUT_H_ +#define _A_OUT_H_ + +#ifdef __cplusplus +extern "C" { +#endif +#define COFF_IMAGE_WITH_PE +#define COFF_LONG_SECTION_NAMES + +/*** coff information for Intel 386/486. */ + + +/********************** FILE HEADER **********************/ + +struct external_filehdr { + short f_magic; /* magic number */ + short f_nscns; /* number of sections */ + unsigned long f_timdat; /* time & date stamp */ + unsigned long f_symptr; /* file pointer to symtab */ + unsigned long f_nsyms; /* number of symtab entries */ + short f_opthdr; /* sizeof(optional hdr) */ + short f_flags; /* flags */ +}; + +/* Bits for f_flags: + * F_RELFLG relocation info stripped from file + * F_EXEC file is executable (no unresolved external references) + * F_LNNO line numbers stripped from file + * F_LSYMS local symbols stripped from file + * F_AR32WR file has byte ordering of an AR32WR machine (e.g. vax) + */ + +#define F_RELFLG (0x0001) +#define F_EXEC (0x0002) +#define F_LNNO (0x0004) +#define F_LSYMS (0x0008) + + + +#define I386MAGIC 0x14c +#define I386PTXMAGIC 0x154 +#define I386AIXMAGIC 0x175 + +/* This is Lynx's all-platform magic number for executables. */ + +#define LYNXCOFFMAGIC 0415 + +#define I386BADMAG(x) (((x).f_magic != I386MAGIC) \ + && (x).f_magic != I386AIXMAGIC \ + && (x).f_magic != I386PTXMAGIC \ + && (x).f_magic != LYNXCOFFMAGIC) + +#define FILHDR struct external_filehdr +#define FILHSZ 20 + + +/********************** AOUT "OPTIONAL HEADER"= + **********************/ + + +typedef struct +{ + unsigned short magic; /* type of file */ + unsigned short vstamp; /* version stamp */ + unsigned long tsize; /* text size in bytes, padded to FW bdry*/ + unsigned long dsize; /* initialized data " " */ + unsigned long bsize; /* uninitialized data " " */ + unsigned long entry; /* entry pt. */ + unsigned long text_start; /* base of text used for this file */ + unsigned long data_start; /* base of data used for this file= + */ +} +AOUTHDR; + +#define AOUTSZ 28 +#define AOUTHDRSZ 28 + +#define OMAGIC 0404 /* object files, eg as output */ +#define ZMAGIC 0413 /* demand load format, eg normal ld output */ +#define STMAGIC 0401 /* target shlib */ +#define SHMAGIC 0443 /* host shlib */ + + +/* define some NT default values */ +/* #define NT_IMAGE_BASE 0x400000 moved to internal.h */ +#define NT_SECTION_ALIGNMENT 0x1000 +#define NT_FILE_ALIGNMENT 0x200 +#define NT_DEF_RESERVE 0x100000 +#define NT_DEF_COMMIT 0x1000 + +/********************** SECTION HEADER **********************/ + + +struct external_scnhdr { + char s_name[8]; /* section name */ + unsigned long s_paddr; /* physical address, offset + of last addr in scn */ + unsigned long s_vaddr; /* virtual address */ + unsigned long s_size; /* section size */ + unsigned long s_scnptr; /* file ptr to raw data for section */ + unsigned long s_relptr; /* file ptr to relocation */ + unsigned long s_lnnoptr; /* file ptr to line numbers */ + unsigned short s_nreloc; /* number of relocation entries */ + unsigned short s_nlnno; /* number of line number entries*/ + unsigned long s_flags; /* flags */ +}; + +#define SCNHDR struct external_scnhdr +#define SCNHSZ 40 + +/* + * names of "special" sections + */ +#define _TEXT ".text" +#define _DATA ".data" +#define _BSS ".bss" +#define _COMMENT ".comment" +#define _LIB ".lib" + +/********************** LINE NUMBERS **********************/ + +/* 1 line number entry for every "breakpointable" source line in a section. + * Line numbers are grouped on a per function basis; first entry in a function + * grouping will have l_lnno = 0 and in place of physical address will be the + * symbol table index of the function name. + */ +struct external_lineno { + union { + unsigned long l_symndx; /* function name symbol index, iff l_lnno 0 */ + unsigned long l_paddr; /* (physical) address of line number */ + } l_addr; + unsigned short l_lnno; /* line number */ +}; + +#define LINENO struct external_lineno +#define LINESZ 6 + +/********************** SYMBOLS **********************/ + +#define E_SYMNMLEN 8 /* # characters in a symbol name */ +#define E_FILNMLEN 14 /* # characters in a file name */ +#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */ + +struct external_syment +{ + union { + char e_name[E_SYMNMLEN]; + struct { + unsigned long e_zeroes; + unsigned long e_offset; + } e; + } e; + unsigned long e_value; + unsigned short e_scnum; + unsigned short e_type; + char e_sclass[1]; + char e_numaux[1]; +}; + +#define N_BTMASK (0xf) +#define N_TMASK (0x30) +#define N_BTSHFT (4) +#define N_TSHIFT (2) + +union external_auxent { + struct { + unsigned long x_tagndx; /* str, un, or enum tag indx */ + union { + struct { + unsigned short x_lnno; /* declaration line number */ + unsigned short x_size; /* str/union/array size */ + } x_lnsz; + unsigned long x_fsize; /* size of function */ + } x_misc; + union { + struct { /* if ISFCN, tag, or .bb */ + unsigned long x_lnnoptr;/* ptr to fcn line # */ + unsigned long x_endndx; /* entry ndx past block end */ + } x_fcn; + struct { /* if ISARY, up to 4 dimen. */ + char x_dimen[E_DIMNUM][2]; + } x_ary; + } x_fcnary; + unsigned short x_tvndx; /* tv index */ + } x_sym; + + union { + char x_fname[E_FILNMLEN]; + struct { + unsigned long x_zeroes; + unsigned long x_offset; + } x_n; + } x_file; + + struct { + unsigned long x_scnlen; /* section length */ + unsigned short x_nreloc; /* # relocation entries */ + unsigned short x_nlinno; /* # line numbers */ + unsigned long x_checksum; /* section COMDAT checksum */ + unsigned short x_associated;/* COMDAT associated section index */ + char x_comdat[1]; /* COMDAT selection number */ + } x_scn; + + struct { + unsigned long x_tvfill; /* tv fill value */ + unsigned short x_tvlen; /* length of .tv */ + char x_tvran[2][2]; /* tv range */ + } x_tv; /* info about .tv section (in auxent of symbol .tv)) */ + +}; + +#define SYMENT struct external_syment +#define SYMESZ 18 +#define AUXENT union external_auxent +#define AUXESZ 18 + +#define _ETEXT "etext" + +/********************** RELOCATION DIRECTIVES **********************/ + +struct external_reloc { + char r_vaddr[4]; + char r_symndx[4]; + char r_type[2]; +}; + +#define RELOC struct external_reloc +#define RELSZ 10 + +/* end of coff/i386.h */ + +/* PE COFF header information */ + +#ifndef _PE_H +#define _PE_H + +/* NT specific file attributes */ +#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 +#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 +#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 +#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 +#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 +#define IMAGE_FILE_32BIT_MACHINE 0x0100 +#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 +#define IMAGE_FILE_SYSTEM 0x1000 +#define IMAGE_FILE_DLL 0x2000 +#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 + +/* additional flags to be set for section headers to allow the NT loader to + read and write to the section data (to replace the addresses of data in + dlls for one thing); also to execute the section in .text's case= + */ +#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 +#define IMAGE_SCN_MEM_READ 0x40000000 +#define IMAGE_SCN_MEM_WRITE 0x80000000 + +/* + * Section characteristics added for ppc-nt + */ + +#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 /* Reserved. */ + +#define IMAGE_SCN_CNT_CODE 0x00000020 /* Section contains code. */ +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 /* Section contains initialized data. */ +#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 /* Section contains uninitialized data. */ + +#define IMAGE_SCN_LNK_OTHER 0x00000100 /* Reserved. */ +#define IMAGE_SCN_LNK_INFO 0x00000200 /* Section contains comments or some other type of information. */ +#define IMAGE_SCN_LNK_REMOVE 0x00000800 /* Section contents will not become part of image. */ +#define IMAGE_SCN_LNK_COMDAT 0x00001000 /* Section contents comdat. */ + +#define IMAGE_SCN_MEM_FARDATA 0x00008000 + +#define IMAGE_SCN_MEM_PURGEABLE 0x00020000 +#define IMAGE_SCN_MEM_16BIT 0x00020000 +#define IMAGE_SCN_MEM_LOCKED 0x00040000 +#define IMAGE_SCN_MEM_PRELOAD 0x00080000 + +#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 +#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 +#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 +#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 +#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 /* Default alignment if no others are specified. */ +#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 +#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 + + +#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 /* Section contains extended relocations. */ +#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 /* Section is not cachable. */ +#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 /* Section is not pageable. */ +#define IMAGE_SCN_MEM_SHARED 0x10000000 /* Section is shareable. */ + +/* COMDAT selection codes. */ + +#define IMAGE_COMDAT_SELECT_NODUPLICATES (1) /* Warn if duplicates. */ +#define IMAGE_COMDAT_SELECT_ANY (2) /* No warning. */ +#define IMAGE_COMDAT_SELECT_SAME_SIZE (3) /* Warn if different size. */ +#define IMAGE_COMDAT_SELECT_EXACT_MATCH (4) /* Warn if different. */ +#define IMAGE_COMDAT_SELECT_ASSOCIATIVE (5) /* Base on other section. */ + +/* Magic values that are true for all dos/nt implementations */ +#define DOSMAGIC 0x5a4d +#define NT_SIGNATURE 0x00004550 + +/* NT allows long filenames, we want to accommodate this. This may break + some of the bfd functions */ +#undef FILNMLEN +#define FILNMLEN 18 /* # characters in a file name */ + + +#ifdef COFF_IMAGE_WITH_PE +/* The filehdr is only weired in images */ + +#undef FILHDR +struct external_PE_filehdr +{ + /* DOS header fields */ + unsigned short e_magic; /* Magic number, 0x5a4d */ + unsigned short e_cblp; /* Bytes on last page of file, 0x90 */ + unsigned short e_cp; /* Pages in file, 0x3 */ + unsigned short e_crlc; /* Relocations, 0x0 */ + unsigned short e_cparhdr; /* Size of header in paragraphs, 0x4 */ + unsigned short e_minalloc; /* Minimum extra paragraphs needed, 0x0 */ + unsigned short e_maxalloc; /* Maximum extra paragraphs needed, 0xFFFF */ + unsigned short e_ss; /* Initial (relative) SS value, 0x0 */ + unsigned short e_sp; /* Initial SP value, 0xb8 */ + unsigned short e_csum; /* Checksum, 0x0 */ + unsigned short e_ip; /* Initial IP value, 0x0 */ + unsigned short e_cs; /* Initial (relative) CS value, 0x0 */ + unsigned short e_lfarlc; /* File address of relocation table, 0x40 */ + unsigned short e_ovno; /* Overlay number, 0x0 */ + char e_res[4][2]; /* Reserved words, all 0x0 */ + unsigned short e_oemid; /* OEM identifier (for e_oeminfo), 0x0 */ + unsigned short e_oeminfo; /* OEM information; e_oemid specific, 0x0 */ + char e_res2[10][2]; /* Reserved words, all 0x0 */ + unsigned long e_lfanew; /* File address of new exe header, 0x80 */ + char dos_message[16][4]; /* other stuff, always follow DOS header */ + unsigned int nt_signature; /* required NT signature, 0x4550 */ + + /* From standard header */ + + unsigned short f_magic; /* magic number */ + unsigned short f_nscns; /* number of sections */ + unsigned long f_timdat; /* time & date stamp */ + unsigned long f_symptr; /* file pointer to symtab */ + unsigned long f_nsyms; /* number of symtab entries */ + unsigned short f_opthdr; /* sizeof(optional hdr) */ + unsigned short f_flags; /* flags */ +}; + + +#define FILHDR struct external_PE_filehdr +#undef FILHSZ +#define FILHSZ 152 + +#endif + +typedef struct +{ + unsigned short magic; /* type of file */ + unsigned short vstamp; /* version stamp */ + unsigned long tsize; /* text size in bytes, padded to FW bdry*/ + unsigned long dsize; /* initialized data " " */ + unsigned long bsize; /* uninitialized data " " */ + unsigned long entry; /* entry pt. */ + unsigned long text_start; /* base of text used for this file */ + unsigned long data_start; /* base of all data used for this file */ + + /* NT extra fields; see internal.h for descriptions */ + unsigned long ImageBase; + unsigned long SectionAlignment; + unsigned long FileAlignment; + unsigned short MajorOperatingSystemVersion; + unsigned short MinorOperatingSystemVersion; + unsigned short MajorImageVersion; + unsigned short MinorImageVersion; + unsigned short MajorSubsystemVersion; + unsigned short MinorSubsystemVersion; + char Reserved1[4]; + unsigned long SizeOfImage; + unsigned long SizeOfHeaders; + unsigned long CheckSum; + unsigned short Subsystem; + unsigned short DllCharacteristics; + unsigned long SizeOfStackReserve; + unsigned long SizeOfStackCommit; + unsigned long SizeOfHeapReserve; + unsigned long SizeOfHeapCommit; + unsigned long LoaderFlags; + unsigned long NumberOfRvaAndSizes; + /* IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; */ + char DataDirectory[16][2][4]; /* 16 entries, 2 elements/entry, 4 chars */ + +} PEAOUTHDR; + + +#undef AOUTSZ +#define AOUTSZ (AOUTHDRSZ + 196) + +#undef E_FILNMLEN +#define E_FILNMLEN 18 /* # characters in a file name */ +#endif + +/* end of coff/pe.h */ + +#define DT_NON (0) /* no derived type */ +#define DT_PTR (1) /* pointer */ +#define DT_FCN (2) /* function */ +#define DT_ARY (3) /* array */ + +#define ISPTR(x) (((x) & N_TMASK) == (DT_PTR << N_BTSHFT)) +#define ISFCN(x) (((x) & N_TMASK) == (DT_FCN << N_BTSHFT)) +#define ISARY(x) (((x) & N_TMASK) == (DT_ARY << N_BTSHFT)) + +#ifdef __cplusplus +} +#endif + +#endif /* _A_OUT_H_ */ + diff --git a/winsup/cygwin/include/arpa/ftp.h b/winsup/cygwin/include/arpa/ftp.h new file mode 100644 index 000000000..7d39a3e7a --- /dev/null +++ b/winsup/cygwin/include/arpa/ftp.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 1983, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ftp.h 8.1 (Berkeley) 6/2/93 + */ + +#ifndef _ARPA_FTP_H +#define _ARPA_FTP_H + +/* Definitions for FTP; see RFC-765. */ + +/* + * Reply codes. + */ +#define PRELIM 1 /* positive preliminary */ +#define COMPLETE 2 /* positive completion */ +#define CONTINUE 3 /* positive intermediate */ +#define TRANSIENT 4 /* transient negative completion */ +#define ERROR 5 /* permanent negative completion */ + +/* + * Type codes + */ +#define TYPE_A 1 /* ASCII */ +#define TYPE_E 2 /* EBCDIC */ +#define TYPE_I 3 /* image */ +#define TYPE_L 4 /* local byte size */ + +#ifdef FTP_NAMES +char *typenames[] = {"0", "ASCII", "EBCDIC", "Image", "Local" }; +#endif + +/* + * Form codes + */ +#define FORM_N 1 /* non-print */ +#define FORM_T 2 /* telnet format effectors */ +#define FORM_C 3 /* carriage control (ASA) */ +#ifdef FTP_NAMES +char *formnames[] = {"0", "Nonprint", "Telnet", "Carriage-control" }; +#endif + +/* + * Structure codes + */ +#define STRU_F 1 /* file (no record structure) */ +#define STRU_R 2 /* record structure */ +#define STRU_P 3 /* page structure */ +#ifdef FTP_NAMES +char *strunames[] = {"0", "File", "Record", "Page" }; +#endif + +/* + * Mode types + */ +#define MODE_S 1 /* stream */ +#define MODE_B 2 /* block */ +#define MODE_C 3 /* compressed */ +#ifdef FTP_NAMES +char *modenames[] = {"0", "Stream", "Block", "Compressed" }; +#endif + +/* + * Record Tokens + */ +#define REC_ESC '\377' /* Record-mode Escape */ +#define REC_EOR '\001' /* Record-mode End-of-Record */ +#define REC_EOF '\002' /* Record-mode End-of-File */ + +/* + * Block Header + */ +#define BLK_EOR 0x80 /* Block is End-of-Record */ +#define BLK_EOF 0x40 /* Block is End-of-File */ +#define BLK_ERRORS 0x20 /* Block is suspected of containing errors */ +#define BLK_RESTART 0x10 /* Block is Restart Marker */ + +#define BLK_BYTECOUNT 2 /* Bytes in this block */ + +#endif /* !_ARPA_FTP_H */ diff --git a/winsup/cygwin/include/arpa/inet.h b/winsup/cygwin/include/arpa/inet.h new file mode 100644 index 000000000..5b6966ce3 --- /dev/null +++ b/winsup/cygwin/include/arpa/inet.h @@ -0,0 +1,25 @@ +#ifndef _ARPA_INET_H +#define _ARPA_INET_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef __INSIDE_CYGWIN_NET__ +unsigned long inet_addr (const char *); +int inet_aton (const char *, struct in_addr *); +unsigned long inet_lnaof (struct in_addr); +struct in_addr inet_makeaddr (unsigned long , unsigned long); +unsigned int inet_netof (struct in_addr); +unsigned int inet_network (const char *); +char *inet_ntoa (struct in_addr); +#endif + +#ifdef __cplusplus +}; +#endif + +#endif /* _ARPA_INET_H */ diff --git a/winsup/cygwin/include/arpa/telnet.h b/winsup/cygwin/include/arpa/telnet.h new file mode 100644 index 000000000..3e523ea97 --- /dev/null +++ b/winsup/cygwin/include/arpa/telnet.h @@ -0,0 +1,322 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)telnet.h 8.2 (Berkeley) 12/15/93 + */ + +#ifndef _ARPA_TELNET_H +#define _ARPA_TELNET_H + +/* + * Definitions for the TELNET protocol. + */ +#define IAC 255 /* interpret as command: */ +#define DONT 254 /* you are not to use option */ +#define DO 253 /* please, you use option */ +#define WONT 252 /* I won't use option */ +#define WILL 251 /* I will use option */ +#define SB 250 /* interpret as subnegotiation */ +#define GA 249 /* you may reverse the line */ +#define EL 248 /* erase the current line */ +#define EC 247 /* erase the current character */ +#define AYT 246 /* are you there */ +#define AO 245 /* abort output--but let prog finish */ +#define IP 244 /* interrupt process--permanently */ +#define BREAK 243 /* break */ +#define DM 242 /* data mark--for connect. cleaning */ +#define NOP 241 /* nop */ +#define SE 240 /* end sub negotiation */ +#define EOR 239 /* end of record (transparent mode) */ +#define ABORT 238 /* Abort process */ +#define SUSP 237 /* Suspend process */ +#define xEOF 236 /* End of file: EOF is already used... */ + +#define SYNCH 242 /* for telfunc calls */ + +#ifdef TELCMDS +char *telcmds[] = { + "EOF", "SUSP", "ABORT", "EOR", + "SE", "NOP", "DMARK", "BRK", "IP", "AO", "AYT", "EC", + "EL", "GA", "SB", "WILL", "WONT", "DO", "DONT", "IAC", 0, +}; +#else +extern char *telcmds[]; +#endif + +#define TELCMD_FIRST xEOF +#define TELCMD_LAST IAC +#define TELCMD_OK(x) ((unsigned int)(x) <= TELCMD_LAST && \ + (unsigned int)(x) >= TELCMD_FIRST) +#define TELCMD(x) telcmds[(x)-TELCMD_FIRST] + +/* telnet options */ +#define TELOPT_BINARY 0 /* 8-bit data path */ +#define TELOPT_ECHO 1 /* echo */ +#define TELOPT_RCP 2 /* prepare to reconnect */ +#define TELOPT_SGA 3 /* suppress go ahead */ +#define TELOPT_NAMS 4 /* approximate message size */ +#define TELOPT_STATUS 5 /* give status */ +#define TELOPT_TM 6 /* timing mark */ +#define TELOPT_RCTE 7 /* remote controlled transmission and echo */ +#define TELOPT_NAOL 8 /* negotiate about output line width */ +#define TELOPT_NAOP 9 /* negotiate about output page size */ +#define TELOPT_NAOCRD 10 /* negotiate about CR disposition */ +#define TELOPT_NAOHTS 11 /* negotiate about horizontal tabstops */ +#define TELOPT_NAOHTD 12 /* negotiate about horizontal tab disposition */ +#define TELOPT_NAOFFD 13 /* negotiate about formfeed disposition */ +#define TELOPT_NAOVTS 14 /* negotiate about vertical tab stops */ +#define TELOPT_NAOVTD 15 /* negotiate about vertical tab disposition */ +#define TELOPT_NAOLFD 16 /* negotiate about output LF disposition */ +#define TELOPT_XASCII 17 /* extended ascic character set */ +#define TELOPT_LOGOUT 18 /* force logout */ +#define TELOPT_BM 19 /* byte macro */ +#define TELOPT_DET 20 /* data entry terminal */ +#define TELOPT_SUPDUP 21 /* supdup protocol */ +#define TELOPT_SUPDUPOUTPUT 22 /* supdup output */ +#define TELOPT_SNDLOC 23 /* send location */ +#define TELOPT_TTYPE 24 /* terminal type */ +#define TELOPT_EOR 25 /* end or record */ +#define TELOPT_TUID 26 /* TACACS user identification */ +#define TELOPT_OUTMRK 27 /* output marking */ +#define TELOPT_TTYLOC 28 /* terminal location number */ +#define TELOPT_3270REGIME 29 /* 3270 regime */ +#define TELOPT_X3PAD 30 /* X.3 PAD */ +#define TELOPT_NAWS 31 /* window size */ +#define TELOPT_TSPEED 32 /* terminal speed */ +#define TELOPT_LFLOW 33 /* remote flow control */ +#define TELOPT_LINEMODE 34 /* Linemode option */ +#define TELOPT_XDISPLOC 35 /* X Display Location */ +#define TELOPT_OLD_ENVIRON 36 /* Old - Environment variables */ +#define TELOPT_AUTHENTICATION 37/* Authenticate */ +#define TELOPT_ENCRYPT 38 /* Encryption option */ +#define TELOPT_NEW_ENVIRON 39 /* New - Environment variables */ +#define TELOPT_EXOPL 255 /* extended-options-list */ +#define TELOPT_ENVIRON TELOPT_OLD_ENVIRON + +#define NTELOPTS (1+TELOPT_NEW_ENVIRON) +#ifdef TELOPTS +char *telopts[NTELOPTS+1] = { + "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME", + "STATUS", "TIMING MARK", "RCTE", "NAOL", "NAOP", + "NAOCRD", "NAOHTS", "NAOHTD", "NAOFFD", "NAOVTS", + "NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO", + "DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT", + "SEND LOCATION", "TERMINAL TYPE", "END OF RECORD", + "TACACS UID", "OUTPUT MARKING", "TTYLOC", + "3270 REGIME", "X.3 PAD", "NAWS", "TSPEED", "LFLOW", + "LINEMODE", "XDISPLOC", "OLD-ENVIRON", "AUTHENTICATION", + "ENCRYPT", "NEW-ENVIRON", + 0, +}; +#define TELOPT_FIRST TELOPT_BINARY +#define TELOPT_LAST TELOPT_NEW_ENVIRON +#define TELOPT_OK(x) ((unsigned int)(x) <= TELOPT_LAST) +#define TELOPT(x) telopts[(x)-TELOPT_FIRST] +#endif + +/* sub-option qualifiers */ +#define TELQUAL_IS 0 /* option is... */ +#define TELQUAL_SEND 1 /* send option */ +#define TELQUAL_INFO 2 /* ENVIRON: informational version of IS */ +#define TELQUAL_REPLY 2 /* AUTHENTICATION: client version of IS */ +#define TELQUAL_NAME 3 /* AUTHENTICATION: client version of IS */ + +#define LFLOW_OFF 0 /* Disable remote flow control */ +#define LFLOW_ON 1 /* Enable remote flow control */ +#define LFLOW_RESTART_ANY 2 /* Restart output on any char */ +#define LFLOW_RESTART_XON 3 /* Restart output only on XON */ + +/* + * LINEMODE suboptions + */ + +#define LM_MODE 1 +#define LM_FORWARDMASK 2 +#define LM_SLC 3 + +#define MODE_EDIT 0x01 +#define MODE_TRAPSIG 0x02 +#define MODE_ACK 0x04 +#define MODE_SOFT_TAB 0x08 +#define MODE_LIT_ECHO 0x10 + +#define MODE_MASK 0x1f + +/* Not part of protocol, but needed to simplify things... */ +#define MODE_FLOW 0x0100 +#define MODE_ECHO 0x0200 +#define MODE_INBIN 0x0400 +#define MODE_OUTBIN 0x0800 +#define MODE_FORCE 0x1000 + +#define SLC_SYNCH 1 +#define SLC_BRK 2 +#define SLC_IP 3 +#define SLC_AO 4 +#define SLC_AYT 5 +#define SLC_EOR 6 +#define SLC_ABORT 7 +#define SLC_EOF 8 +#define SLC_SUSP 9 +#define SLC_EC 10 +#define SLC_EL 11 +#define SLC_EW 12 +#define SLC_RP 13 +#define SLC_LNEXT 14 +#define SLC_XON 15 +#define SLC_XOFF 16 +#define SLC_FORW1 17 +#define SLC_FORW2 18 + +#define NSLC 18 + +/* + * For backwards compatability, we define SLC_NAMES to be the + * list of names if SLC_NAMES is not defined. + */ +#define SLC_NAMELIST "0", "SYNCH", "BRK", "IP", "AO", "AYT", "EOR", \ + "ABORT", "EOF", "SUSP", "EC", "EL", "EW", "RP", \ + "LNEXT", "XON", "XOFF", "FORW1", "FORW2", 0, +#ifdef SLC_NAMES +char *slc_names[] = { + SLC_NAMELIST +}; +#else +extern char *slc_names[]; +#define SLC_NAMES SLC_NAMELIST +#endif + +#define SLC_NAME_OK(x) ((unsigned int)(x) <= NSLC) +#define SLC_NAME(x) slc_names[x] + +#define SLC_NOSUPPORT 0 +#define SLC_CANTCHANGE 1 +#define SLC_VARIABLE 2 +#define SLC_DEFAULT 3 +#define SLC_LEVELBITS 0x03 + +#define SLC_FUNC 0 +#define SLC_FLAGS 1 +#define SLC_VALUE 2 + +#define SLC_ACK 0x80 +#define SLC_FLUSHIN 0x40 +#define SLC_FLUSHOUT 0x20 + +#define OLD_ENV_VAR 1 +#define OLD_ENV_VALUE 0 +#define NEW_ENV_VAR 0 +#define NEW_ENV_VALUE 1 +#define ENV_ESC 2 +#define ENV_USERVAR 3 + +#define ENV_VALUE 0 +#define ENV_VAR 1 + +/* + * AUTHENTICATION suboptions + */ + +/* + * Who is authenticating who ... + */ +#define AUTH_WHO_CLIENT 0 /* Client authenticating server */ +#define AUTH_WHO_SERVER 1 /* Server authenticating client */ +#define AUTH_WHO_MASK 1 + +/* + * amount of authentication done + */ +#define AUTH_HOW_ONE_WAY 0 +#define AUTH_HOW_MUTUAL 2 +#define AUTH_HOW_MASK 2 + +#define AUTHTYPE_NULL 0 +#define AUTHTYPE_KERBEROS_V4 1 +#define AUTHTYPE_KERBEROS_V5 2 +#define AUTHTYPE_SPX 3 +#define AUTHTYPE_MINK 4 +#define AUTHTYPE_CNT 5 + +#define AUTHTYPE_TEST 99 + +#ifdef AUTH_NAMES +char *authtype_names[] = { + "NULL", "KERBEROS_V4", "KERBEROS_V5", "SPX", "MINK", 0, +}; +#else +extern char *authtype_names[]; +#endif + +#define AUTHTYPE_NAME_OK(x) ((unsigned int)(x) < AUTHTYPE_CNT) +#define AUTHTYPE_NAME(x) authtype_names[x] + +/* + * ENCRYPTion suboptions + */ +#define ENCRYPT_IS 0 /* I pick encryption type ... */ +#define ENCRYPT_SUPPORT 1 /* I support encryption types ... */ +#define ENCRYPT_REPLY 2 /* Initial setup response */ +#define ENCRYPT_START 3 /* Am starting to send encrypted */ +#define ENCRYPT_END 4 /* Am ending encrypted */ +#define ENCRYPT_REQSTART 5 /* Request you start encrypting */ +#define ENCRYPT_REQEND 6 /* Request you send encrypting */ +#define ENCRYPT_ENC_KEYID 7 +#define ENCRYPT_DEC_KEYID 8 +#define ENCRYPT_CNT 9 + +#define ENCTYPE_ANY 0 +#define ENCTYPE_DES_CFB64 1 +#define ENCTYPE_DES_OFB64 2 +#define ENCTYPE_CNT 3 + +#ifdef ENCRYPT_NAMES +char *encrypt_names[] = { + "IS", "SUPPORT", "REPLY", "START", "END", + "REQUEST-START", "REQUEST-END", "ENC-KEYID", "DEC-KEYID", + 0, +}; +char *enctype_names[] = { + "ANY", "DES_CFB64", "DES_OFB64", 0, +}; +#else +extern char *encrypt_names[]; +extern char *enctype_names[]; +#endif + + +#define ENCRYPT_NAME_OK(x) ((unsigned int)(x) < ENCRYPT_CNT) +#define ENCRYPT_NAME(x) encrypt_names[x] + +#define ENCTYPE_NAME_OK(x) ((unsigned int)(x) < ENCTYPE_CNT) +#define ENCTYPE_NAME(x) enctype_names[x] +#endif /* _ARPA_TELNET_H */ diff --git a/winsup/cygwin/include/asm/byteorder.h b/winsup/cygwin/include/asm/byteorder.h new file mode 100644 index 000000000..5ccd9850a --- /dev/null +++ b/winsup/cygwin/include/asm/byteorder.h @@ -0,0 +1,93 @@ +#ifndef _I386_BYTEORDER_H +#define _I386_BYTEORDER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if 0 +#undef ntohl +#undef ntohs +#undef htonl +#undef htons +#endif + +#ifndef __LITTLE_ENDIAN +#define __LITTLE_ENDIAN 1234 +#endif + +#ifndef __LITTLE_ENDIAN_BITFIELD +#define __LITTLE_ENDIAN_BITFIELD +#endif + +#if 1 +extern unsigned long int ntohl(unsigned long int); +extern unsigned short int ntohs(unsigned short int); +extern unsigned long int htonl(unsigned long int); +extern unsigned short int htons(unsigned short int); + +extern __inline__ unsigned long int __ntohl(unsigned long int); +extern __inline__ unsigned short int __ntohs(unsigned short int); +extern __inline__ unsigned long int __constant_ntohl(unsigned long int); +extern __inline__ unsigned short int __constant_ntohs(unsigned short int); + +extern __inline__ unsigned long int +__ntohl(unsigned long int x) +{ + __asm__("xchgb %b0,%h0\n\t" /* swap lower bytes */ + "rorl $16,%0\n\t" /* swap words */ + "xchgb %b0,%h0" /* swap higher bytes */ + :"=q" (x) + : "0" (x)); + return x; +} + +#define __constant_ntohl(x) \ + ((unsigned long int)((((unsigned long int)(x) & 0x000000ffU) << 24) | \ + (((unsigned long int)(x) & 0x0000ff00U) << 8) | \ + (((unsigned long int)(x) & 0x00ff0000U) >> 8) | \ + (((unsigned long int)(x) & 0xff000000U) >> 24))) + +extern __inline__ unsigned short int +__ntohs(unsigned short int x) +{ + __asm__("xchgb %b0,%h0" /* swap bytes */ + : "=q" (x) + : "0" (x)); + return x; +} + +#define __constant_ntohs(x) \ + ((unsigned short int)((((unsigned short int)(x) & 0x00ff) << 8) | \ + (((unsigned short int)(x) & 0xff00) >> 8))) \ + +#define __htonl(x) __ntohl(x) +#define __htons(x) __ntohs(x) +#define __constant_htonl(x) __constant_ntohl(x) +#define __constant_htons(x) __constant_ntohs(x) + +#ifdef __OPTIMIZE__ +# define ntohl(x) \ +(__builtin_constant_p((long)(x)) ? \ + __constant_ntohl((x)) : \ + __ntohl((x))) +# define ntohs(x) \ +(__builtin_constant_p((short)(x)) ? \ + __constant_ntohs((x)) : \ + __ntohs((x))) +# define htonl(x) \ +(__builtin_constant_p((long)(x)) ? \ + __constant_htonl((x)) : \ + __htonl((x))) +# define htons(x) \ +(__builtin_constant_p((short)(x)) ? \ + __constant_htons((x)) : \ + __htons((x))) +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/winsup/cygwin/include/asm/socket.h b/winsup/cygwin/include/asm/socket.h new file mode 100644 index 000000000..167919765 --- /dev/null +++ b/winsup/cygwin/include/asm/socket.h @@ -0,0 +1,58 @@ +#ifndef _ASM_SOCKET_H +#define _ASM_SOCKET_H + +#include + +#define IOCPARM_MASK 0x7f /* parameters must be < 128 bytes */ +#define IOC_VOID 0x20000000 /* no parameters */ +#define IOC_OUT 0x40000000 /* copy out parameters */ +#define IOC_IN 0x80000000 /* copy in parameters */ + +#define _IO(x,y) (IOC_VOID|(x<<8)|y) +#define _IOR(x,y,t) (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y) +#define _IOW(x,y,t) (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y) + +#define SIOCATMARK _IOR('s', 7, u_long) /* at oob mark? */ +#define FIONREAD _IOR('f', 127, u_long) /* get # bytes to read */ +#define FIONBIO 0x8004667e /* To be compatible with termiost version */ +#define REAL_FIONBIO _IOW('f', 126, u_long) /* set/clear non-blocking i/o */ +#define FIOASYNC _IOW('f', 125, u_long) /* set/clear async i/o */ +#define SIOCSHIWAT _IOW('s', 0, u_long) /* set high watermark */ +#define SIOCGHIWAT _IOR('s', 1, u_long) /* get high watermark */ +#define SIOCSLOWAT _IOW('s', 2, u_long) /* set low watermark */ +#define SIOCGLOWAT _IOR('s', 3, u_long) /* get low watermark */ + +/* Needed for if queries */ +#define SIOCGIFCONF _IOW('s', 100, struct ifconf) /* get if list */ +#define SIOCGIFFLAGS _IOW('s', 101, struct ifreq) /* Get if flags */ +#define SIOCGIFADDR _IOW('s', 102, struct ifreq) /* Get if addr */ +#define SIOCGIFBRDADDR _IOW('s', 103, struct ifreq) /* Get if broadcastaddr */ +#define SIOCGIFNETMASK _IOW('s', 104, struct ifreq) /* Get if netmask */ + +#define SOL_SOCKET 0xffff /* options for socket level */ + +#define SO_DEBUG 0x0001 /* turn on debugging info recording */ +#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */ +#define SO_REUSEADDR 0x0004 /* allow local address reuse */ +#define SO_KEEPALIVE 0x0008 /* keep connections alive */ +#define SO_DONTROUTE 0x0010 /* just use interface addresses */ +#define SO_BROADCAST 0x0020 /* permit sending of broadcast msgs */ +#define SO_USELOOPBACK 0x0040 /* bypass hardware when possible */ +#define SO_LINGER 0x0080 /* linger on close if data present */ +#define SO_OOBINLINE 0x0100 /* leave received OOB data in line */ +#define SO_DONTLINGER (u_int)(~SO_LINGER) + +/* + * Additional options. + */ +#define SO_SNDBUF 0x1001 /* send buffer size */ +#define SO_RCVBUF 0x1002 /* receive buffer size */ +#define SO_SNDLOWAT 0x1003 /* send low-water mark */ +#define SO_RCVLOWAT 0x1004 /* receive low-water mark */ +#define SO_SNDTIMEO 0x1005 /* send timeout */ +#define SO_RCVTIMEO 0x1006 /* receive timeout */ +#define SO_ERROR 0x1007 /* get error status and clear */ +#define SO_TYPE 0x1008 /* get socket type */ + +#endif /* _ASM_SOCKET_H */ + diff --git a/winsup/cygwin/include/asm/types.h b/winsup/cygwin/include/asm/types.h new file mode 100644 index 000000000..be1177d3c --- /dev/null +++ b/winsup/cygwin/include/asm/types.h @@ -0,0 +1,13 @@ +#ifndef _ASM_TYPES_H +#define _ASM_TYPES_H + +typedef __signed__ char __s8; +typedef unsigned char __u8; + +typedef __signed__ short __s16; +typedef unsigned short __u16; + +typedef __signed__ int __s32; +typedef unsigned int __u32; + +#endif /* _ASM_TYPES_H */ diff --git a/winsup/cygwin/include/cygwin/acl.h b/winsup/cygwin/include/cygwin/acl.h new file mode 100644 index 000000000..d54655a5a --- /dev/null +++ b/winsup/cygwin/include/cygwin/acl.h @@ -0,0 +1,81 @@ +/* cygwin/acl.h header file for Cygwin. + + Copyright 1999, 2000 Cygnus Solutions. + Written by C. Vinschen. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#ifndef _CYGWIN_ACL_H +#ifdef __cplusplus +extern "C" { +#endif +#define _CYGWIN_ACL_H + +#include <_ansi.h> + +#include +#include + +/* Values for `cmd' in calls to acl(2) and facl(2) */ +#define SETACL (0x0) +#define GETACL (0x1) +#define GETACLCNT (0x2) + +#define MIN_ACL_ENTRIES (4) // minimal acl entries from GETACLCNT +#define MAX_ACL_ENTRIES (256) // max entries of each type + +// Return values of aclcheck(3) in case of error */ +#define GRP_ERROR (0x1) +#define USER_ERROR (0x2) +#define CLASS_ERROR (0x3) +#define OTHER_ERROR (0x4) +#define DUPLICATE_ERROR (0x5) +#define ENTRY_ERROR (0x6) +#define MISS_ERROR (0x7) // which = -1 +#define MEM_ERROR (0x8) // which = -1 + +// Values for entry type of struct acl +#define USER_OBJ (0x0001) // owner +#define USER (0x0002) // additional user +#define GROUP_OBJ (0x0004) // owning group +#define GROUP (0x0008) // additional group +#define CLASS_OBJ (0x0010) // mask entry +#define OTHER_OBJ (0x0020) // others +#define ACL_DEFAULT (0x1000) // default flag +#define DEF_USER_OBJ (ACL_DEFAULT|USER_OBJ) // default owner +#define DEF_USER (ACL_DEFAULT|USER) // default additional user +#define DEF_GROUP_OBJ (ACL_DEFAULT|GROUP_OBJ) // default owning group +#define DEF_GROUP (ACL_DEFAULT|GROUP) // default additional group +#define DEF_CLASS_OBJ (ACL_DEFAULT|CLASS_OBJ) // default mask entry +#define DEF_OTHER_OBJ (ACL_DEFAULT|OTHER_OBJ) // default others +// Values with equivalent meanings +#define USER_OWNER USER_OBJ +#define GROUP_OWNER GROUP_OBJ +#define MASK CLASS_OBJ +#define OTHER OTHER_OBJ + +typedef struct acl { + int a_type; /* entry type */ + uid_t a_id; /* UID | GID */ + mode_t a_perm; /* permissions */ +} aclent_t; + +int _EXFUN(acl,(const char *path, int cmd, int nentries, aclent_t *aclbufp)); +int _EXFUN(facl,(int fd, int cmd, int nentries, aclent_t *aclbufp)); +int _EXFUN(aclcheck,(aclent_t *aclbufp, int nentries, int *which)); +int _EXFUN(aclsort,(int nentries, int calclass, aclent_t *aclbufp)); +int _EXFUN(acltomode,(aclent_t *aclbufp, int nentries, mode_t *modep)); +int _EXFUN(aclfrommode,(aclent_t *aclbufp, int nentries, mode_t *modep)); +int _EXFUN(acltopbits,(aclent_t *aclbufp, int nentries, mode_t *pbitsp)); +int _EXFUN(aclfrompbits,(aclent_t *aclbufp, int nentries, mode_t *pbitsp)); +char *_EXFUN(acltotext,(aclent_t *aclbufp, int aclcnt)); +aclent_t *_EXFUN(aclfromtext,(char *acltextp, int *aclcnt)); + +#ifdef __cplusplus +} +#endif +#endif /* _CYGWIN_ACL_H */ diff --git a/winsup/cygwin/include/cygwin/cygwin_dll.h b/winsup/cygwin/include/cygwin/cygwin_dll.h new file mode 100644 index 000000000..08cdbdf00 --- /dev/null +++ b/winsup/cygwin/include/cygwin/cygwin_dll.h @@ -0,0 +1,96 @@ +/* cygwin_dll.h + + Copyright 1998 Cygnus Solutions + +This file is part of Cygwin32. + +This software is a copyrighted work licensed under the terms of the +Cygwin32 license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#ifndef __CYGWIN_CYGWIN_DLL_H__ +#define __CYGWIN_CYGWIN_DLL_H__ + +#include + +#ifdef __cplusplus +#define CDECL_BEGIN extern "C" { +#define CDECL_END } +#else +#define CDECL_BEGIN +#define CDECL_END +#endif + +#define DECLARE_CYGWIN_DLL(Entry) \ + \ +CDECL_BEGIN \ + int WINAPI _cygwin_dll_entry (HANDLE h, DWORD reason, void *ptr); \ + int WINAPI _cygwin_noncygwin_dll_entry (HANDLE h, DWORD reason, void *ptr); \ + \ + int WINAPI Entry (HANDLE h, DWORD reason, void *ptr); \ + extern int cygwin_attach_dll (); \ + extern void cygwin_detach_dll (); \ +CDECL_END \ + \ +static HANDLE storedHandle; \ +static DWORD storedReason; \ +static void* storedPtr; \ + \ +static int __dllMain (int a, char **b, char **c) \ +{ \ + return Entry (storedHandle, storedReason, storedPtr); \ +} \ + \ +static int dll_index; \ + \ +int WINAPI _cygwin_dll_entry (HANDLE h, DWORD reason, void *ptr) \ +{ \ + int ret; \ + ret = 1; \ + \ + switch (reason) \ + { \ + case DLL_PROCESS_ATTACH: \ + { \ + storedHandle = h; \ + storedReason = reason; \ + storedPtr = ptr; \ + dll_index = cygwin_attach_dll (h, &__dllMain); \ + if (dll_index == -1) \ + ret = 0; \ + } \ + break; \ + \ + case DLL_PROCESS_DETACH: \ + { \ + ret = Entry (h, reason, ptr); \ + if (ret) \ + { \ + cygwin_detach_dll (dll_index); \ + dll_index = -1; \ + } \ + } \ + break; \ + \ + case DLL_THREAD_ATTACH: \ + { \ + ret = Entry (h, reason, ptr); \ + } \ + break; \ + \ + case DLL_THREAD_DETACH: \ + { \ + ret = Entry (h, reason, ptr); \ + } \ + break; \ + } \ + return ret; \ +} \ + \ +/* OBSOLETE: This is only provided for source level compatibility. */ \ +int WINAPI _cygwin_noncygwin_dll_entry (HANDLE h, DWORD reason, void *ptr) \ +{ \ + return _cygwin_dll_entry (h, reason, ptr); \ +} \ + +#endif /* __CYGWIN_CYGWIN_DLL_H__ */ diff --git a/winsup/cygwin/include/cygwin/icmp.h b/winsup/cygwin/include/cygwin/icmp.h new file mode 100644 index 000000000..7e7aedccd --- /dev/null +++ b/winsup/cygwin/include/cygwin/icmp.h @@ -0,0 +1 @@ +/* icmp.h */ diff --git a/winsup/cygwin/include/cygwin/if.h b/winsup/cygwin/include/cygwin/if.h new file mode 100644 index 000000000..f16b82992 --- /dev/null +++ b/winsup/cygwin/include/cygwin/if.h @@ -0,0 +1,74 @@ +#ifndef _CYGWIN_IF_H_ +#define _CYGWIN_IF_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include +#include + +/* Standard interface flags. */ +#define IFF_UP 0x1 /* interface is up */ +#define IFF_BROADCAST 0x2 /* broadcast address valid */ +#define IFF_LOOPBACK 0x8 /* is a loopback net */ +#define IFF_NOTRAILERS 0x20 /* avoid use of trailers */ +#define IFF_RUNNING 0x40 /* resources allocated */ +#define IFF_PROMISC 0x100 /* receive all packets */ +#define IFF_MULTICAST 0x1000 /* Supports multicast */ + +/* + * Interface request structure used for socket + * ioctl's. All interface ioctl's must have parameter + * definitions which begin with ifr_name. The + * remainder may be interface specific. + */ + +struct ifreq +{ +#define IFNAMSIZ 16 + union + { + char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + } ifr_ifrn; + + union { + struct sockaddr ifru_addr; + struct sockaddr ifru_broadaddr; + struct sockaddr ifru_netmask; + short ifru_flags; + int ifru_metric; + int ifru_mtu; + } ifr_ifru; +}; + +#define ifr_name ifr_ifrn.ifrn_name /* interface name */ +#define ifr_addr ifr_ifru.ifru_addr /* address */ +#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ +#define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */ +#define ifr_flags ifr_ifru.ifru_flags /* flags */ + +/* + * Structure used in SIOCGIFCONF request. + * Used to retrieve interface configuration + * for machine (useful for programs which + * must know all networks accessible). + */ + +struct ifconf +{ + int ifc_len; /* size of buffer */ + union + { + caddr_t ifcu_buf; + struct ifreq *ifcu_req; + } ifc_ifcu; +}; +#define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ +#define ifc_req ifc_ifcu.ifcu_req /* array of structures */ + +#ifdef __cplusplus +}; +#endif /* __cplusplus */ + +#endif /* _CYGWIN_IF_H_ */ diff --git a/winsup/cygwin/include/cygwin/in.h b/winsup/cygwin/include/cygwin/in.h new file mode 100644 index 000000000..d9ab331b3 --- /dev/null +++ b/winsup/cygwin/include/cygwin/in.h @@ -0,0 +1,188 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions of the Internet Protocol. + * + * Version: @(#)in.h 1.0.1 04/21/93 + * + * Authors: Original taken from the GNU Project file. + * Fred N. van Kempen, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _CYGWIN_IN_H +#define _CYGWIN_IN_H + +#include + +/* Standard well-defined IP protocols. */ +enum { + IPPROTO_IP = 0, /* Dummy protocol for TCP */ + IPPROTO_ICMP = 1, /* Internet Control Message Protocol */ + IPPROTO_IGMP = 2, /* Internet Gateway Management Protocol */ + IPPROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94) */ + IPPROTO_TCP = 6, /* Transmission Control Protocol */ + IPPROTO_EGP = 8, /* Exterior Gateway Protocol */ + IPPROTO_PUP = 12, /* PUP protocol */ + IPPROTO_UDP = 17, /* User Datagram Protocol */ + IPPROTO_IDP = 22, /* XNS IDP protocol */ + + IPPROTO_RAW = 255, /* Raw IP packets */ + IPPROTO_MAX +}; + +/* Standard well-known ports. *//* from winsup/include/netinet/in.h */ +enum + { + IPPORT_ECHO = 7, /* Echo service. */ + IPPORT_DISCARD = 9, /* Discard transmissions service. */ + IPPORT_SYSTAT = 11, /* System status service. */ + IPPORT_DAYTIME = 13, /* Time of day service. */ + IPPORT_NETSTAT = 15, /* Network status service. */ + IPPORT_FTP = 21, /* File Transfer Protocol. */ + IPPORT_TELNET = 23, /* Telnet protocol. */ + IPPORT_SMTP = 25, /* Simple Mail Transfer Protocol. */ + IPPORT_TIMESERVER = 37, /* Timeserver service. */ + IPPORT_NAMESERVER = 42, /* Domain Name Service. */ + IPPORT_WHOIS = 43, /* Internet Whois service. */ + IPPORT_MTP = 57, + + IPPORT_TFTP = 69, /* Trivial File Transfer Protocol. */ + IPPORT_RJE = 77, + IPPORT_FINGER = 79, /* Finger service. */ + IPPORT_TTYLINK = 87, + IPPORT_SUPDUP = 95, /* SUPDUP protocol. */ + + + IPPORT_EXECSERVER = 512, /* execd service. */ + IPPORT_LOGINSERVER = 513, /* rlogind service. */ + IPPORT_CMDSERVER = 514, + IPPORT_EFSSERVER = 520, + + /* UDP ports. */ + IPPORT_BIFFUDP = 512, + IPPORT_WHOSERVER = 513, + IPPORT_ROUTESERVER = 520, + + /* Ports less than this value are reserved for privileged processes. */ + IPPORT_RESERVED = 1024, + + /* Ports greater this value are reserved for (non-privileged) servers. */ + IPPORT_USERRESERVED = 5000 + }; + + +/* Internet address. */ +struct in_addr { + unsigned int s_addr; +}; + +/* Request struct for multicast socket ops */ + +struct ip_mreq +{ + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_interface; /* local IP address of interface */ +}; + + +/* Structure describing an Internet (IP) socket address. */ +#define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */ +struct sockaddr_in { + short int sin_family; /* Address family */ + unsigned short int sin_port; /* Port number */ + struct in_addr sin_addr; /* Internet address */ + + /* Pad to size of `struct sockaddr'. */ + unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) - + sizeof(unsigned short int) - sizeof(struct in_addr)]; +}; +#define sin_zero __pad /* for BSD UNIX comp. -FvK */ + + +/* + * Definitions of the bits in an Internet address integer. + * On subnets, host and network parts are found according + * to the subnet mask, not these masks. + */ +#define IN_CLASSA(a) ((((long int) (a)) & 0x80000000) == 0) +#define IN_CLASSA_NET 0xff000000 +#define IN_CLASSA_NSHIFT 24 +#define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET) +#define IN_CLASSA_MAX 128 + +#define IN_CLASSB(a) ((((long int) (a)) & 0xc0000000) == 0x80000000) +#define IN_CLASSB_NET 0xffff0000 +#define IN_CLASSB_NSHIFT 16 +#define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET) +#define IN_CLASSB_MAX 65536 + +#define IN_CLASSC(a) ((((long int) (a)) & 0xe0000000) == 0xc0000000) +#define IN_CLASSC_NET 0xffffff00 +#define IN_CLASSC_NSHIFT 8 +#define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET) + +#define IN_CLASSD(a) ((((long int) (a)) & 0xf0000000) == 0xe0000000) +#define IN_MULTICAST(a) IN_CLASSD(a) +#define IN_MULTICAST_NET 0xF0000000 + +#define IN_EXPERIMENTAL(a) ((((long int) (a)) & 0xe0000000) == 0xe0000000) +#define IN_BADCLASS(a) ((((long int) (a)) & 0xf0000000) == 0xf0000000) + +/* Address to accept any incoming messages. */ +#define INADDR_ANY ((unsigned long int) 0x00000000) + +/* Address to send to all hosts. */ +#define INADDR_BROADCAST ((unsigned long int) 0xffffffff) + +/* Address indicating an error return. */ +#define INADDR_NONE 0xffffffff + +/* Network number for local host loopback. */ +#define IN_LOOPBACKNET 127 + +/* Address to loopback in software to local host. */ +#define INADDR_LOOPBACK 0x7f000001 /* 127.0.0.1 */ +#define IN_LOOPBACK(a) ((((long int) (a)) & 0xff000000) == 0x7f000000) + +/* Defines for Multicast INADDR */ +#define INADDR_UNSPEC_GROUP 0xe0000000 /* 224.0.0.0 */ +#define INADDR_ALLHOSTS_GROUP 0xe0000001 /* 224.0.0.1 */ +#define INADDR_MAX_LOCAL_GROUP 0xe00000ff /* 224.0.0.255 */ + +/* contains the htonl type stuff.. */ + +#include + +/* Some random defines to make it easier in the kernel.. */ +#ifdef __KERNEL__ + +#define LOOPBACK(x) (((x) & htonl(0xff000000)) == htonl(0x7f000000)) +#define MULTICAST(x) (((x) & htonl(0xf0000000)) == htonl(0xe0000000)) + +#endif + +/* + * IPv6 definitions as we start to include them. This is just + * a beginning dont get excited 8) + */ + +struct in_addr6 +{ + unsigned char s6_addr[16]; +}; + +struct sockaddr_in6 +{ + unsigned short sin6_family; + unsigned short sin6_port; + unsigned long sin6_flowinfo; + struct in_addr6 sin6_addr; +}; + +#endif /* _CYGWIN_IN_H */ diff --git a/winsup/cygwin/include/cygwin/mtio.h b/winsup/cygwin/include/cygwin/mtio.h new file mode 100644 index 000000000..53ed42c76 --- /dev/null +++ b/winsup/cygwin/include/cygwin/mtio.h @@ -0,0 +1,190 @@ +/* + * cygwin/mtio.h header file for Cygwin. + * + * Original written by H. Bergman for Linux. + * Changed for Cygwin by C. Vinschen. + */ + +#ifndef _CYGWIN_MTIO_H +#define _CYGWIN_MTIO_H + +#include +#include + +/* + * Structures and definitions for mag tape io control commands + */ + +/* structure for MTIOCTOP - mag tape op command */ +struct mtop { + short mt_op; /* operations defined below */ + int mt_count; /* how many of them */ +}; + +/* Magnetic Tape operations [Not all operations supported by all drivers]: */ +#define MTRESET 0 /* +reset drive in case of problems */ +#define MTFSF 1 /* forward space over FileMark, + * position at first record of next file + */ +#define MTBSF 2 /* backward space FileMark (position before FM) */ +#define MTFSR 3 /* forward space record */ +#define MTBSR 4 /* backward space record */ +#define MTWEOF 5 /* write an end-of-file record (mark) */ +#define MTREW 6 /* rewind */ +#define MTOFFL 7 /* rewind and put the drive offline (eject?) */ +#define MTNOP 8 /* no op, set status only (read with MTIOCGET) */ +#define MTRETEN 9 /* retension tape */ +#define MTBSFM 10 /* +backward space FileMark, position at FM */ +#define MTFSFM 11 /* +forward space FileMark, position at FM */ +#define MTEOM 12 /* goto end of recorded media (for appending files). + * MTEOM positions after the last FM, ready for + * appending another file. + */ +#define MTERASE 13 /* erase tape -- be careful! */ + +#define MTRAS1 14 /* run self test 1 (nondestructive) */ +#define MTRAS2 15 /* run self test 2 (destructive) */ +#define MTRAS3 16 /* reserved for self test 3 */ + +#define MTSETBLK 20 /* set block length (SCSI) */ +#define MTSETDENSITY 21 /* set tape density (SCSI) */ +#define MTSEEK 22 /* seek to block (Tandberg, etc.) */ +#define MTTELL 23 /* tell block (Tandberg, etc.) */ +#define MTSETDRVBUFFER 24 /* set the drive buffering according to SCSI-2 */ + /* ordinary buffered operation with code 1 */ +#define MTFSS 25 /* space forward over setmarks */ +#define MTBSS 26 /* space backward over setmarks */ +#define MTWSM 27 /* write setmarks */ + +#define MTLOCK 28 /* lock the drive door */ +#define MTUNLOCK 29 /* unlock the drive door */ +#define MTLOAD 30 /* execute the SCSI load command */ +#define MTUNLOAD 31 /* execute the SCSI unload command */ +#define MTCOMPRESSION 32/* control compression with SCSI mode page 15 */ +#define MTSETPART 33 /* Change the active tape partition */ +#define MTMKPART 34 /* Format the tape with one or two partitions */ + +/* structure for MTIOCGET - mag tape get status command */ + +struct mtget { + long mt_type; /* type of magtape device + * Cygwin: MT_ISUNKNOWN */ + long mt_resid; /* residual count: (not sure) + * number of bytes ignored, or + * number of files not skipped, or + * number of records not skipped. + * Cygwin: remaining KB. + */ + /* the following registers are device dependent */ + long mt_dsreg; /* status register */ + long mt_gstat; /* generic (device independent) status */ + long mt_erreg; /* error register */ + /* The next two fields are not always used */ + long mt_fileno; /* number of current file on tape */ + long mt_blkno; /* current block number */ + /* The next are Windows NT specific */ + long long mt_capacity; /* Tape capacity in bytes */ + long long mt_remaining; /* Remaining bytes */ + int mt_minblksize; + int mt_maxblksize; + int mt_defblksize; + unsigned long mt_featureslow; + unsigned long mt_featureshigh; +}; + +/* structure for MTIOCPOS - mag tape get position command */ + +struct mtpos { + long mt_blkno; /* current block number */ +}; + + +/* mag tape io control commands */ +#define MTIOCTOP _IOW('m', 1, struct mtop) /* do a mag tape op */ +#define MTIOCGET _IOR('m', 2, struct mtget) /* get tape status */ +#define MTIOCPOS _IOR('m', 3, struct mtpos) /* get tape position */ + +/* Generic Mag Tape (device independent) status macros for examining + * mt_gstat -- HP-UX compatible. + * There is room for more generic status bits here, but I don't + * know which of them are reserved. At least three or so should + * be added to make this really useful. + */ +#define GMT_EOF(x) ((x) & 0x80000000) +#define GMT_BOT(x) ((x) & 0x40000000) +#define GMT_EOT(x) ((x) & 0x20000000) +#define GMT_SM(x) ((x) & 0x10000000) /* DDS setmark */ +#define GMT_EOD(x) ((x) & 0x08000000) /* DDS EOD */ +#define GMT_WR_PROT(x) ((x) & 0x04000000) +/* #define GMT_ ? ((x) & 0x02000000) */ +#define GMT_ONLINE(x) ((x) & 0x01000000) +#define GMT_D_6250(x) ((x) & 0x00800000) +#define GMT_D_1600(x) ((x) & 0x00400000) +#define GMT_D_800(x) ((x) & 0x00200000) +#define GMT_PADDING(x) ((x) & 0x00100000) /* data padding */ +#define GMT_HW_ECC(x) ((x) & 0x00080000) /* HW error correction */ +#define GMT_DR_OPEN(x) ((x) & 0x00040000) /* door open (no tape) */ +#define GMT_HW_COMP(x) ((x) & 0x00020000) /* HW compression */ +#define GMT_IM_REP_EN(x) ((x) & 0x00010000) /* immediate report mode */ +/* 16 generic status bits unused */ + + +/* SCSI-tape specific definitions */ +/* Bitfield shifts in the status mt_dsreg */ +#define MT_ST_BLKSIZE_SHIFT 0 +#define MT_ST_BLKSIZE_MASK 0xffffff +#define MT_ST_DENSITY_SHIFT 24 +#define MT_ST_DENSITY_MASK 0xff000000 + +#define MT_ST_SOFTERR_SHIFT 0 +#define MT_ST_SOFTERR_MASK 0xffff + +/* + * Constants for mt_type. Not all of these are supported, + * and these are not all of the ones that are supported. + */ +#define MT_ISUNKNOWN 0x01 +#define MT_ISQIC02 0x02 /* Generic QIC-02 tape streamer */ +#define MT_ISWT5150 0x03 /* Wangtek 5150EQ, QIC-150, QIC-02 */ +#define MT_ISARCHIVE_5945L2 0x04 /* Archive 5945L-2, QIC-24, QIC-02? */ +#define MT_ISCMSJ500 0x05 /* CMS Jumbo 500 (QIC-02?) */ +#define MT_ISTDC3610 0x06 /* Tandberg 6310, QIC-24 */ +#define MT_ISARCHIVE_VP60I 0x07 /* Archive VP60i, QIC-02 */ +#define MT_ISARCHIVE_2150L 0x08 /* Archive Viper 2150L */ +#define MT_ISARCHIVE_2060L 0x09 /* Archive Viper 2060L */ +#define MT_ISARCHIVESC499 0x0A /* Archive SC-499 QIC-36 controller */ +#define MT_ISQIC02_ALL_FEATURES 0x0F /* Generic QIC-02 with all features */ +#define MT_ISWT5099EEN24 0x11 /* Wangtek 5099-een24, 60MB, QIC-24 */ +#define MT_ISTEAC_MT2ST 0x12 /* Teac MT-2ST 155mb drive, Teac DC-1 card (Wangtek type) */ +#define MT_ISEVEREX_FT40A 0x32 /* Everex FT40A (QIC-40) */ +#define MT_ISDDS1 0x51 /* DDS device without partitions */ +#define MT_ISDDS2 0x52 /* DDS device with partitions */ +#define MT_ISSCSI1 0x71 /* Generic ANSI SCSI-1 tape unit */ +#define MT_ISSCSI2 0x72 /* Generic ANSI SCSI-2 tape unit */ + +struct mt_tape_info { + long t_type; /* device type id (mt_type) */ + char *t_name; /* descriptive name */ +}; + +#define MT_TAPE_INFO { \ + {MT_ISUNKNOWN, "Unknown type of tape device"}, \ + {MT_ISQIC02, "Generic QIC-02 tape streamer"}, \ + {MT_ISWT5150, "Wangtek 5150, QIC-150"}, \ + {MT_ISARCHIVE_5945L2, "Archive 5945L-2"}, \ + {MT_ISCMSJ500, "CMS Jumbo 500"}, \ + {MT_ISTDC3610, "Tandberg TDC 3610, QIC-24"}, \ + {MT_ISARCHIVE_VP60I, "Archive VP60i, QIC-02"}, \ + {MT_ISARCHIVE_2150L, "Archive Viper 2150L"}, \ + {MT_ISARCHIVE_2060L, "Archive Viper 2060L"}, \ + {MT_ISARCHIVESC499, "Archive SC-499 QIC-36 controller"}, \ + {MT_ISQIC02_ALL_FEATURES, "Generic QIC-02 tape, all features"}, \ + {MT_ISWT5099EEN24, "Wangtek 5099-een24, 60MB"}, \ + {MT_ISTEAC_MT2ST, "Teac MT-2ST 155mb data cassette drive"}, \ + {MT_ISEVEREX_FT40A, "Everex FT40A, QIC-40"}, \ + {MT_ISSCSI1, "Generic SCSI-1 tape"}, \ + {MT_ISSCSI2, "Generic SCSI-2 tape"}, \ + {0, NULL} \ +} + +#endif /* _CYGWIN_MTIO_H */ diff --git a/winsup/cygwin/include/cygwin/rdevio.h b/winsup/cygwin/include/cygwin/rdevio.h new file mode 100644 index 000000000..49726fe0e --- /dev/null +++ b/winsup/cygwin/include/cygwin/rdevio.h @@ -0,0 +1,30 @@ +/* + * cygwin/rdevio.h header file for Cygwin. + * + * Written by C. Vinschen. + */ + +#ifndef _CYGWIN_RDEVIO_H +#define _CYGWIN_RDEVIO_H + +/* structure for RDIOCDOP - raw device operation */ +struct rdop { + short rd_op; + unsigned long rd_parm; +}; + +/* Raw device operations */ +#define RDSETBLK 1 /* set buffer for driver */ + +/* structure for RDIOCGET - get raw device */ +struct rdget { + unsigned long bufsiz; +}; + +/* + * ioctl commands +*/ +#define RDIOCDOP _IOW('r', 128, struct rdop) +#define RDIOCGET _IOR('r', 129, struct rdget) + +#endif /* _CYGWIN_RDEVIO_H */ diff --git a/winsup/cygwin/include/cygwin/socket.h b/winsup/cygwin/include/cygwin/socket.h new file mode 100644 index 000000000..fad1efdf0 --- /dev/null +++ b/winsup/cygwin/include/cygwin/socket.h @@ -0,0 +1,152 @@ +#ifndef _CYGWIN_SOCKET_H +#define _CYGWIN_SOCKET_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +struct sockaddr { + unsigned short sa_family; /* address family, AF_xxx */ + char sa_data[14]; /* 14 bytes of protocol address */ +}; + +#include /* arch-dependent defines */ +#include /* the SIOCxxx I/O controls */ +#include /* iovec support */ +#include + +struct linger { + unsigned short l_onoff; /* Linger active */ + unsigned short l_linger; /* How long to linger for */ +}; + +struct msghdr +{ + void * msg_name; /* Socket name */ + int msg_namelen; /* Length of name */ + struct iovec * msg_iov; /* Data blocks */ + int msg_iovlen; /* Number of blocks */ + void * msg_accrights; /* Per protocol magic (eg BSD file descriptor passing) */ + int msg_accrightslen; /* Length of rights list */ +}; + +/* Socket types. */ +#define SOCK_STREAM 1 /* stream (connection) socket */ +#define SOCK_DGRAM 2 /* datagram (conn.less) socket */ +#define SOCK_RAW 3 /* raw socket */ +#define SOCK_RDM 4 /* reliably-delivered message */ +#define SOCK_SEQPACKET 5 /* sequential packet socket */ +#define SOCK_PACKET 10 /* CYGWIN specific way of */ + /* getting packets at the dev */ + /* level. For writing rarp and */ + /* other similar things on the */ + /* user level. */ + +/* Supported address families. */ +/* + * Address families. + */ +#define AF_UNSPEC 0 /* unspecified */ +#define AF_UNIX 1 /* local to host (pipes, portals) */ +#define AF_LOCAL 1 /* POSIX name for AF_UNIX */ +#define AF_INET 2 /* internetwork: UDP, TCP, etc. */ +#define AF_IMPLINK 3 /* arpanet imp addresses */ +#define AF_PUP 4 /* pup protocols: e.g. BSP */ +#define AF_CHAOS 5 /* mit CHAOS protocols */ +#define AF_NS 6 /* XEROX NS protocols */ +#define AF_ISO 7 /* ISO protocols */ +#define AF_OSI AF_ISO /* OSI is ISO */ +#define AF_ECMA 8 /* european computer manufacturers */ +#define AF_DATAKIT 9 /* datakit protocols */ +#define AF_CCITT 10 /* CCITT protocols, X.25 etc */ +#define AF_SNA 11 /* IBM SNA */ +#define AF_DECnet 12 /* DECnet */ +#define AF_DLI 13 /* Direct data link interface */ +#define AF_LAT 14 /* LAT */ +#define AF_HYLINK 15 /* NSC Hyperchannel */ +#define AF_APPLETALK 16 /* AppleTalk */ +#define AF_NETBIOS 17 /* NetBios-style addresses */ + +#define AF_MAX 18 +/* + * Protocol families, same as address families for now. + */ +#define PF_UNSPEC AF_UNSPEC +#define PF_UNIX AF_UNIX +#define PF_LOCAL AF_LOCAL +#define PF_INET AF_INET +#define PF_IMPLINK AF_IMPLINK +#define PF_PUP AF_PUP +#define PF_CHAOS AF_CHAOS +#define PF_NS AF_NS +#define PF_ISO AF_ISO +#define PF_OSI AF_OSI +#define PF_ECMA AF_ECMA +#define PF_DATAKIT AF_DATAKIT +#define PF_CCITT AF_CCITT +#define PF_SNA AF_SNA +#define PF_DECnet AF_DECnet +#define PF_DLI AF_DLI +#define PF_LAT AF_LAT +#define PF_HYLINK AF_HYLINK +#define PF_APPLETALK AF_APPLETALK +#define PF_NETBIOS AF_NETBIOS + +#define PF_MAX AF_MAX + +/* Maximum queue length specificable by listen. */ +#define SOMAXCONN 5 + +/* Flags we can use with send/ and recv. */ +#define MSG_OOB 0x1 /* process out-of-band data */ +#define MSG_PEEK 0x2 /* peek at incoming message */ +#define MSG_DONTROUTE 0x4 /* send without using routing tables */ + +/* Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx */ +#define SOL_IP 0 +#define SOL_IPX 256 +#define SOL_AX25 257 +#define SOL_ATALK 258 +#define SOL_NETROM 259 +#define SOL_TCP 6 +#define SOL_UDP 17 + +/* IP options */ +#define IPTOS_LOWDELAY 0x10 +#define IPTOS_THROUGHPUT 0x08 +#define IPTOS_RELIABILITY 0x04 + +/* These need to appear somewhere around here */ +#define IP_DEFAULT_MULTICAST_TTL 1 +#define IP_DEFAULT_MULTICAST_LOOP 1 +#define IP_MAX_MEMBERSHIPS 20 + +/* IP options for use with WinSock */ + +#define IP_OPTIONS 1 +#define IP_MULTICAST_IF 2 +#define IP_MULTICAST_TTL 3 +#define IP_MULTICAST_LOOP 4 +#define IP_ADD_MEMBERSHIP 5 +#define IP_DROP_MEMBERSHIP 6 +#define IP_TTL 7 +#define IP_TOS 8 +#define IP_DONTFRAGMENT 9 + +/* IPX options */ +#define IPX_TYPE 1 + +/* TCP options - this way around because someone left a set in the c library includes */ +#define TCP_NODELAY 0x0001 +#define TCP_MAXSEG 2 + +/* The various priorities. */ +#define SOPRI_INTERACTIVE 0 +#define SOPRI_NORMAL 1 +#define SOPRI_BACKGROUND 2 + +#ifdef __cplusplus +}; +#endif /* __cplusplus */ + +#endif /* _CYGWIN_SOCKET_H */ diff --git a/winsup/cygwin/include/cygwin/sockios.h b/winsup/cygwin/include/cygwin/sockios.h new file mode 100644 index 000000000..2e756954e --- /dev/null +++ b/winsup/cygwin/include/cygwin/sockios.h @@ -0,0 +1 @@ +/* sockios.h */ diff --git a/winsup/cygwin/include/cygwin/types.h b/winsup/cygwin/include/cygwin/types.h new file mode 100644 index 000000000..51e349710 --- /dev/null +++ b/winsup/cygwin/include/cygwin/types.h @@ -0,0 +1 @@ +/* types.h */ diff --git a/winsup/cygwin/include/cygwin/uio.h b/winsup/cygwin/include/cygwin/uio.h new file mode 100644 index 000000000..18c77ae65 --- /dev/null +++ b/winsup/cygwin/include/cygwin/uio.h @@ -0,0 +1 @@ +/* uio.h */ diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h new file mode 100644 index 000000000..eea5d9b91 --- /dev/null +++ b/winsup/cygwin/include/cygwin/version.h @@ -0,0 +1,159 @@ +/* version.h -- Cygwin version numbers and accompanying documentation. + + Copyright 1996, 1997, 1998, 1999 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +/* Cygwin versioning is relatively complicated because of its status + as a shared library. Let's start with how versioning used to be done. + + Historical versioning in Cygwin 16.0 to 19.5: + + In the olden days of Cygwin, we had a dll major and minor version + and a registry version. The major number started at 16 because the + "b15" GNU-Win32 release of the compiler tools was out when this + scheme was started. We incremented the DLL name frequently (for + every official release) and towards the end of this period every + release used a different shared memory area to prevent DLLs from + interfering with each other (embedding a build timestamp into the + name of the shared memory area). This turned out to be a Bad Idea + (tm) because people needed to mingle separate releases and have + them work together more than we thought they would. This was + especially problematic when tty info needed to be retained when an + old Cygwin executable executed a newer one. + + In the old scheme, we incremented the major number whenever a + change to the dll invalidated existing executables. This can + happen for a number of reasons, including when functions are + removed from the export list of the dll. The minor number was + incremented when a change was made that we wanted to record, but + that didn't invalidate existing executables. Both numbers were + recorded in the executable and in the dll. + + In October 1998 (starting with Cygwin 19.6), we started a new + means of Cygwin versioning: */ + + /* The DLL major and minor numbers correspond to the "version of + the Cygwin library". This version is used to track important + changes to the DLL and is mainly informative in nature. */ + + /* The current cygwin version is 1.1.0 */ + +#define CYGWIN_VERSION_DLL_MAJOR 1001 +#define CYGWIN_VERSION_DLL_MINOR 0 + + /* Major numbers before CYGWIN_VERSION_DLL_EPOCH are + incompatible. */ + +#define CYGWIN_VERSION_DLL_EPOCH 19 + + /* CYGWIN_VERSION_DLL_COMBINED gives us a single number + representing the combined DLL major and minor numbers. */ + +#define CYGWIN_VERSION_DLL_MAKE_COMBINED(maj, min) (((maj) * 1000) + min) +#define CYGWIN_VERSION_DLL_COMBINED \ + CYGWIN_VERSION_DLL_MAKE_COMBINED (CYGWIN_DLL_VERSION_MAJOR, CYGWIN_DLL_VERSION_MINOR) + + /* Every version of cygwin <= this uses an old, incorrect method + to determine signal masks. */ + +#define CYGWIN_VERSION_DLL_BAD_SIGNAL_MASK 19005 + + /* API versions <= this had a termios structure whose members were + too small to accomodate modern settings. */ +#define CYGWIN_VERSION_DLL_OLD_TERMIOS 00005 +#define CYGWIN_VERSION_DLL_IS_OLD_TERMIOS \ + (CYGWIN_VERSION_DLL_MAKE_COMBINED (user_data->api_major, user_data->api_minor) <= \ + CYGWIN_VERSION_DLL_OLD_TERMIOS) + + /* We used to use the DLL major/minor to track + non-backward-compatible interface changes to the API. Now we + use an API major/minor number for this purpose. */ + + /* API_MAJOR 0.0: Initial version. API_MINOR changes: + 1: Export cygwin32_ calls as cygwin_ as well. + 2: Export j1, jn, y1, yn. + 3: Export dll_noncygwin_dllcrt0. + 4: New socket ioctls, revamped ifconf support. + 5: Thread support/exports. + 6: Change in termios handling. + 7: Export scandir and alphasort. + 8: Export _ctype_, _sys_errlist, _sys_nerr. + 9: Mount-related changes, new cygwin_umount export. + Raw device support (tape, floppies). + 10: Fast math routine support added. + 11: Export seekdir, telldir. + 12: Export pthread_join, pthread_detach. + 13: Export math funcs gamma and friends, also _j0, _j1, etc. + 14: Export snprintf and vnsprintf. + 15: Export glob + 16: Export cygwin_stackdump + */ + +#define CYGWIN_VERSION_API_MAJOR 0 +#define CYGWIN_VERSION_API_MINOR 16 + + /* There is also a compatibity version number associated with the + shared memory regions. It is incremented when incompatible + changes are made to the shared memory region *or* to any named + shared mutexes, semaphores, etc. The arbitrary starting + version was 0 (cygwin release 98r2). */ + +#define CYGWIN_VERSION_SHARED_DATA 3 + + /* An identifier used in the names used to create shared objects. + The full names include the CYGWIN_VERSION_SHARED_DATA version + as well as this identifier. */ + +#define CYGWIN_VERSION_DLL_IDENTIFIER "cygwin1" + + /* 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 compatible fashion. Increment this + version number whenever incompatible changes in mount table + registry usage are made. + + 1: Original number version. + 2: New mount registry layout, system-wide mount accessibility. + */ + +#define CYGWIN_VERSION_MOUNT_REGISTRY 2 + + /* Identifiers used in the Win32 registry. */ + +#define CYGWIN_INFO_CYGNUS_REGISTRY_NAME "Cygnus Solutions" +#define CYGWIN_INFO_CYGWIN_REGISTRY_NAME "Cygwin" +#define CYGWIN_INFO_PROGRAM_OPTIONS_NAME "Program Options" +#define CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME "mounts v2" + + /* In addition to the above version number strings, the build + process adds some strings that may be useful in + debugging/identifying a particular Cygwin DLL: + + The mkvers.sh script at the top level produces a .cc file + which initializes a cygwin_version structure based on the + above version information and creates a string table for + grepping via "fgrep '%%%' cygwinwhatever.dll" if you are + using GNU grep. Otherwise you may want to do a + "strings cygwinwhatever.dll | fgrep '%%%'" instead. + + This will produce output such as: + + %%% Cygwin dll_identifier: cygwin + %%% Cygwin api_major: 0 + %%% Cygwin api_minor: 0 + %%% Cygwin dll_major: 19 + %%% Cygwin dll_minor: 6 + %%% Cygwin shared_data: 1 + %%% Cygwin registry: b15 + %%% Cygwin build date: Wed Oct 14 16:26:51 EDT 1998 + %%% Cygwin shared id: cygwinS1 + + This information can also be obtained through a call to + cygwin_internal (CW_GETVERSIONINFO). + */ + diff --git a/winsup/cygwin/include/dlfcn.h b/winsup/cygwin/include/dlfcn.h new file mode 100644 index 000000000..753da0277 --- /dev/null +++ b/winsup/cygwin/include/dlfcn.h @@ -0,0 +1,41 @@ +/* dlfcn.h + + Copyright 1998 Cygnus Solutions + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#ifndef _DLFCN_H +#define _DLFCN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* declarations used for dynamic linking support routines */ +extern void *dlopen (const char *, int); +extern void *dlsym (void *, const char *); +extern int dlclose (void *); +extern char *dlerror (void); + +/* specific to CYGWIN */ +#define FORK_RELOAD 1 +#define FORK_NO_RELOAD 0 + +extern void dlfork (int); + +/* following doesn't exist in Win32 API .... */ + +/* valid values for mode argument to dlopen */ +#define RTLD_LAZY 1 /* lazy function call binding */ +#define RTLD_NOW 2 /* immediate function call binding */ +#define RTLD_GLOBAL 4 /* symbols in this dlopen'ed obj are visible to other dlopen'ed objs */ + +#ifdef __cplusplus +} +#endif + +#endif /* _DLFCN_H */ diff --git a/winsup/cygwin/include/exceptions.h b/winsup/cygwin/include/exceptions.h new file mode 100644 index 000000000..44528bb25 --- /dev/null +++ b/winsup/cygwin/include/exceptions.h @@ -0,0 +1,120 @@ +/* exceptions.h + + Copyright 1996, 1997, 1998 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#ifndef _EXCEPTIONS_H +#define _EXCEPTIONS_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Documentation on the innards of exception handling (i.e. from the + perspective of a compiler implementor) apparently doesn't exist. Sigh. + However, the following came from Onno Hovers + +The first pointer to the chain of handlers is in the thread environment block +at FS:[0]. This chain has the following format: + +typedef struct __EXCEPTION_FRAME +{ + struct __EXCEPTION_FRAME *Prev; /-* pointer to the previous frame *-/ + PEXCEPTION_HANDLER Handler; /-* handler function *-/ +} + +You register an exception handler in your compiler with this simple ASM +sequence: + PUSH _MyExceptionHandler + PUSH FS:[0] + MOV FS:[0],ESP +An exception frame MUST be on the stack! The frame may have more fields and +both Visual C++ and Borland C++ use more fields for themselves. + +When an exception occurs the system calls all handlers starting with the +handler at FS:0, and then the previous etc. until one handler returns +ExceptionContinueExecution, which is 0. If a handler does not want to handle +the exception it should just return ExceptionContinueSearch, which is 1. + +The handler has the following parameters: +ehandler ( + PEXCEPTION_RECORD erecord, + PEXCEPTION_FRAME myframe, + PCONTEXT context, /-* context before and after *-/ + PVOID dispatch ) /-* something *-/ + +When a handler wants to handle the exception, it has some alternatives: + +-one is to do do something about the exception condition, like emulating +an invalid instruction, mapping memory where there was a page fault, etc. +If the handler wants to have the context of the thread that causes the +exception changed, it should make that change in the context passed to the +handler. + +-the second alternative is to call all exception handlers again, indicating +that you want them to clean up. This way all the __finally blocks get +executed. After doing that you change the context passed to the handler so +the code starts executing in the except block. For this purpose you could +call RtlUnwind. This (undocumented) function calls all exception handlers +up to but not including the exception frame passed to it. If NULL is passed +as exception frame RtlUnwind calls all exception handlers and then exits the +process. The parameters to RtlUnwind are: + +RtlUnwind ( + PEXCEPTION_FRAME endframe, + PVOID unusedEip, + PEXCEPTION_RECORD erecord, + DWORD returnEax) + +You should set unusedEip to the address where RtlUnwind should return like +this: + PUSH 0 + PUSH OFFSET ReturnUnwind + PUSH 0 + PUSH 0 + CALL RtlUnwind +ReturnUnwind: + ..... + +If no EXCEPTION_RECORD is passed, RtlUnwind makes a default exception +record. In any case, the ExceptionFlags part of this record has the +EH_UNWINDING (=2), flag set. (and EH_EXIT_UNWIND (=4), when NULL is passed as the end +frame.). + +The handler for a exception as well as a for unwinds may be executed in the +thread causing the exception, but may also be executed in another (special +exception) thread. So it is not wise to make any assumptions about that! + +As an alternative you may consider the SetUnhandledExceptionFilter API +to install your own exception filter. This one is documented. +*/ + +/* The January 1994 MSJ has an article entitled "Clearer, More Comprehensive + Error Processing with Win32 Structured Exception Handling". It goes into + a teensy bit of detail of the innards of exception handling (i.e. what we + have to do). */ + +typedef int (exception_handler) + (EXCEPTION_RECORD *, void *, CONTEXT *, void *); + +typedef struct _exception_list +{ + struct _exception_list *prev; + exception_handler *handler; + + /* We're apparently free to add more stuff here. + At present we don't need any. */ +} exception_list; + +void init_exceptions (exception_list *); + +#ifdef __cplusplus +}; +#endif /* __cplusplus */ + +#endif /* _EXCEPTIONS_H */ diff --git a/winsup/cygwin/include/fcntl.h b/winsup/cygwin/include/fcntl.h new file mode 100644 index 000000000..90cfab0d4 --- /dev/null +++ b/winsup/cygwin/include/fcntl.h @@ -0,0 +1,7 @@ +#ifndef _FCNTL_H +#define _FCNTL_H + +#include +#define O_NDELAY _FNDELAY + +#endif /* _FCNTL_H */ diff --git a/winsup/cygwin/include/features.h b/winsup/cygwin/include/features.h new file mode 100644 index 000000000..206902f7d --- /dev/null +++ b/winsup/cygwin/include/features.h @@ -0,0 +1 @@ +/* features.h */ diff --git a/winsup/cygwin/include/getopt.h b/winsup/cygwin/include/getopt.h new file mode 100644 index 000000000..851ac67e2 --- /dev/null +++ b/winsup/cygwin/include/getopt.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 1987, 1993, 1994, 1996 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __GETOPT_H__ +#define __GETOPT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +struct option { + char * name; + int has_arg; + int * flag; + int val; +}; + +extern int opterr; /* if error message should be printed */ +extern int optind; /* index into parent argv vector */ +extern int optopt; /* character checked for validity */ +extern int optreset; /* reset getopt */ +extern char *optarg; /* argument associated with option */ + +int getopt (int, char * const *, const char *); + +int getopt_long (int, char **, char *, struct option *, int *); + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +#ifdef __cplusplus +} +#endif + +#endif /* __GETOPT_H__ */ diff --git a/winsup/cygwin/include/glob.h b/winsup/cygwin/include/glob.h new file mode 100644 index 000000000..3fdf3e8ae --- /dev/null +++ b/winsup/cygwin/include/glob.h @@ -0,0 +1,111 @@ +/* $NetBSD: glob.h,v 1.6.2.2 1997/11/04 23:38:33 thorpej Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Guido van Rossum. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)glob.h 8.1 (Berkeley) 6/2/93 + */ + +#ifndef _GLOB_H_ +#define _GLOB_H_ + +/* CYGNUS LOCAL: end */ + +#include +#include +#include + +typedef struct { + int gl_pathc; /* Count of total paths so far. */ + int gl_matchc; /* Count of paths matching pattern. */ + int gl_offs; /* Reserved at beginning of gl_pathv. */ + int gl_flags; /* Copy of flags parameter to glob. */ + char **gl_pathv; /* List of paths matching pattern. */ + /* Copy of errfunc parameter to glob. */ + int (*gl_errfunc) __P((const char *, int)); + + /* + * Alternate filesystem access methods for glob; replacement + * versions of closedir(3), readdir(3), opendir(3), stat(2) + * and lstat(2). + */ + void (*gl_closedir) __P((void *)); + struct dirent *(*gl_readdir) __P((void *)); + void *(*gl_opendir) __P((const char *)); +#ifdef __LIBC12_SOURCE__ + int (*gl_lstat) __P((const char *, struct stat12 *)); + int (*gl_stat) __P((const char *, struct stat12 *)); +#else + int (*gl_lstat) __P((const char *, struct stat *)); + int (*gl_stat) __P((const char *, struct stat *)); +#endif +} glob_t; + +#define GLOB_APPEND 0x0001 /* Append to output from previous call. */ +#define GLOB_DOOFFS 0x0002 /* Use gl_offs. */ +#define GLOB_ERR 0x0004 /* Return on error. */ +#define GLOB_MARK 0x0008 /* Append / to matching directories. */ +#define GLOB_NOCHECK 0x0010 /* Return pattern itself if nothing matches. */ +#define GLOB_NOSORT 0x0020 /* Don't sort. */ + +#ifndef _POSIX_SOURCE +#define GLOB_ALTDIRFUNC 0x0040 /* Use alternately specified directory funcs. */ +#define GLOB_BRACE 0x0080 /* Expand braces ala csh. */ +#define GLOB_MAGCHAR 0x0100 /* Pattern had globbing characters. */ +#define GLOB_NOMAGIC 0x0200 /* GLOB_NOCHECK without magic chars (csh). */ +#define GLOB_QUOTE 0x0400 /* Quote special chars with \. */ +#define GLOB_TILDE 0x0800 /* Expand tilde names from the passwd file. */ +#endif + +#define GLOB_NOSPACE (-1) /* Malloc call failed. */ +#define GLOB_ABEND (-2) /* Unignored error. */ + +__BEGIN_DECLS +/* CYGNUS LOCAL: normal protos */ + +#undef DLLEXPORT +#ifdef __INSIDE_CYGWIN__ +# define DLLEXPORT +#else +# define DLLEXPORT __declspec(dllimport) +#endif +int DLLEXPORT glob(const char *, int, int (*)(const char *, int), glob_t *); +void DLLEXPORT globfree(glob_t *); + +#undef DLLEXPORT +/* end CYGNUS LOCAL */ +__END_DECLS + +#endif /* !_GLOB_H_ */ diff --git a/winsup/cygwin/include/icmp.h b/winsup/cygwin/include/icmp.h new file mode 100644 index 000000000..7e7aedccd --- /dev/null +++ b/winsup/cygwin/include/icmp.h @@ -0,0 +1 @@ +/* icmp.h */ diff --git a/winsup/cygwin/include/io.h b/winsup/cygwin/include/io.h new file mode 100644 index 000000000..e757816b3 --- /dev/null +++ b/winsup/cygwin/include/io.h @@ -0,0 +1,28 @@ +/* io.h + + Copyright 1999, 2000 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#ifndef _IO_H_ +#define _IO_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * Function to return a Win32 HANDLE from a fd. + */ +extern long get_osfhandle(int); +extern int setmode (int __fd, int __mode); + +#ifdef __cplusplus +}; +#endif /* __cplusplus */ + +#endif /* _IO_H_ */ diff --git a/winsup/cygwin/include/lastlog.h b/winsup/cygwin/include/lastlog.h new file mode 100644 index 000000000..4a5a8f87f --- /dev/null +++ b/winsup/cygwin/include/lastlog.h @@ -0,0 +1,12 @@ +#ifndef _LASTLOG_H +#define _LASTLOG_H + +#include + +struct lastlog { + long ll_time; + char ll_line[UT_LINESIZE]; + char ll_host[UT_HOSTSIZE]; +}; + +#endif diff --git a/winsup/cygwin/include/limits.h b/winsup/cygwin/include/limits.h new file mode 100644 index 000000000..397ba2030 --- /dev/null +++ b/winsup/cygwin/include/limits.h @@ -0,0 +1,144 @@ +/* limits.h + + Copyright 1999, 2000 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#ifndef _LIMITS_H___ +#ifndef _MACH_MACHLIMITS_H_ + +/* _MACH_MACHLIMITS_H_ is used on OSF/1. */ +#define _LIMITS_H___ +#define _MACH_MACHLIMITS_H_ + +/* Number of bits in a `char'. */ +#undef CHAR_BIT +#define CHAR_BIT 8 + +/* Maximum length of a multibyte character. */ +#ifndef MB_LEN_MAX +#define MB_LEN_MAX 1 +#endif + +/* Minimum and maximum values a `signed char' can hold. */ +#undef SCHAR_MIN +#define SCHAR_MIN (-128) +#undef SCHAR_MAX +#define SCHAR_MAX 127 + +/* Maximum value an `unsigned char' can hold. (Minimum is 0). */ +#undef UCHAR_MAX +#define UCHAR_MAX 255 + +/* Minimum and maximum values a `char' can hold. */ +#ifdef __CHAR_UNSIGNED__ +#undef CHAR_MIN +#define CHAR_MIN 0 +#undef CHAR_MAX +#define CHAR_MAX 255 +#else +#undef CHAR_MIN +#define CHAR_MIN (-128) +#undef CHAR_MAX +#define CHAR_MAX 127 +#endif + +/* Minimum and maximum values a `signed short int' can hold. */ +#undef SHRT_MIN +#define SHRT_MIN (-32768) +#undef SHRT_MAX +#define SHRT_MAX 32767 + +/* Maximum value an `unsigned short int' can hold. (Minimum is 0). */ +#undef USHRT_MAX +#define USHRT_MAX 65535 + +/* Minimum and maximum values a `signed int' can hold. */ +#ifndef __INT_MAX__ +#define __INT_MAX__ 2147483647 +#endif +#undef INT_MIN +#define INT_MIN (-INT_MAX-1) +#undef INT_MAX +#define INT_MAX __INT_MAX__ + +/* Maximum value an `unsigned int' can hold. (Minimum is 0). */ +#undef UINT_MAX +#define UINT_MAX (INT_MAX * 2U + 1) + +/* Minimum and maximum values a `signed long int' can hold. + (Same as `int'). */ +#ifndef __LONG_MAX__ +#ifndef __alpha__ +#define __LONG_MAX__ 2147483647L +#else +#define __LONG_MAX__ 9223372036854775807L +# endif /* __alpha__ */ +#endif +#undef LONG_MIN +#define LONG_MIN (-LONG_MAX-1) +#undef LONG_MAX +#define LONG_MAX __LONG_MAX__ + +/* Maximum value an `unsigned long int' can hold. (Minimum is 0). */ +#undef ULONG_MAX +#define ULONG_MAX (LONG_MAX * 2UL + 1) + +#if defined (__GNU_LIBRARY__) ? defined (__USE_GNU) : !defined (__STRICT_ANSI__) +/* Minimum and maximum values a `signed long long int' can hold. */ +#ifndef __LONG_LONG_MAX__ +#define __LONG_LONG_MAX__ 9223372036854775807LL +#endif +#undef LONG_LONG_MIN +#define LONG_LONG_MIN (-LONG_LONG_MAX-1) +#undef LONG_LONG_MAX +#define LONG_LONG_MAX __LONG_LONG_MAX__ + +/* Maximum value an `unsigned long long int' can hold. (Minimum is 0). */ +#undef ULONG_LONG_MAX +#define ULONG_LONG_MAX (LONG_LONG_MAX * 2ULL + 1) +#endif + +/* Maximum number of iovcnt in a writev */ +#undef IOV_MAX +#define IOV_MAX (__INT_MAX__-1) + +/* Maximum size of ssize_t */ +#undef SSIZE_MAX +#define SSIZE_MAX (__LONG_MAX__) + +/* Maximum length of a path */ +#define PATH_MAX (260 - 1 /*NUL*/) + +/* Max num groups for a user, value taken from NT documentation */ +/* Must match NGROUPS */ +#define NGROUPS_MAX 16 + +/* WaitForMultipleObjects can't handle waiting for more than 64 objects. + This limits how many children we can fork/spawn off. */ +#define CHILD_MAX 63 + +/* POSIX values */ +/* These should never vary from one system type to another */ +/* They represent the minimum values that POSIX systems must support. + POSIX-conforming apps must not require larger values. */ +#define _POSIX_ARG_MAX 4096 +#define _POSIX_CHILD_MAX 6 +#define _POSIX_LINK_MAX 8 +#define _POSIX_MAX_CANON 255 +#define _POSIX_MAX_INPUT 255 +#define _POSIX_NAME_MAX 14 +#define _POSIX_NGROUPS_MAX 0 +#define _POSIX_OPEN_MAX 16 +#define _POSIX_PATH_MAX 255 +#define _POSIX_PIPE_BUF 512 +#define _POSIX_SSIZE_MAX 32767 +#define _POSIX_STREAM_MAX 8 +#define _POSIX_TZNAME_MAX 3 + +#endif /* _MACH_MACHLIMITS_H_ */ +#endif /* _LIMITS_H___ */ diff --git a/winsup/cygwin/include/mapi.h b/winsup/cygwin/include/mapi.h new file mode 100644 index 000000000..5e1769f1d --- /dev/null +++ b/winsup/cygwin/include/mapi.h @@ -0,0 +1,102 @@ +/* mapi.h + + Copyright 1997, 1998 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#ifndef _MAPI_H +#define _MAPI_H + +/* Currently this doesn't include all the definitions. It does cover + the parts of Simple MAPI required to send mail. */ + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* FIXME: should this be elsewhere? */ +typedef unsigned long FLAGS; + + /* FIXME: should this be elsewhere? */ +#define SUCCESS_SUCCESS 0 + + /* FIXME: should this be elsewhere? */ +typedef unsigned long LHANDLE, FAR *LPLHANDLE; + + +#define MAPI_E_AMBIGUOUS_RECIPIENT 0x15 +#define MAPI_E_ATTACHMENT_NOT_FOUND 0xb +#define MAPI_E_ATTACHMENT_OPEN_FAILURE 0xc +#define MAPI_E_BAD_RECIPTYPE 0xf +#define MAPI_E_FAILURE 0x2 +#define MAPI_E_INSUFFICIENT_MEMORY 0x5 +#define MAPI_E_INVALID_RECIPS 0x19 +#define MAPI_E_LOGIN_FAILURE 0x3 +#define MAPI_E_TEXT_TOO_LARGE 0x12 +#define MAPI_E_TOO_MANY_FILES 0x9 +#define MAPI_E_TOO_MANY_RECIPIENTS 0xa +#define MAPI_E_UNKNOWN_RECIPIENT 0xe +#define MAPI_E_USER_ABORT 0x1 +#define MAPI_E_TEXT_TOO_LARGE 0x12 +#define MAPI_DIALOG 0x8 +#define MAPI_NEW_SESSION 0x2 +#define MAPI_LOGON_UI 0x1 +#define MAPI_RECEIPT_REQUESTED 0x2 +#define MAPI_SENT 0x4 +#define MAPI_UNREAD 0x1 +#define MAPI_OLE 0x1 +#define MAPI_OLE_STATIC 0x2 + +#define MAPI_ORIG 0 +#define MAPI_TO 1 +#define MAPI_CC 2 +#define MAPI_BCC 3 + +typedef struct +{ + ULONG ulReserved; + ULONG flFlags; + ULONG nPosition; + LPTSTR lpszPathName; + LPTSTR lpszFileName; + LPVOID lpFileType; +} MapiFileDesc, FAR *lpMapiFileDesc; + +typedef struct +{ + ULONG ulReserved; + ULONG ulRecipClass; + LPTSTR lpszName; + LPTSTR lpszAddress; + ULONG ulEIDSize; + LPVOID lpEntryID; +} MapiRecipDesc, FAR *lpMapiRecipDesc; + +typedef struct +{ + ULONG ulReserved; + LPTSTR lpszSubject; + LPTSTR lpszNoteText; + LPTSTR lpszMessageType; + LPTSTR lpszDateReceived; + LPTSTR lpszConversationID; + FLAGS flFlags; + lpMapiRecipDesc lpOriginator; + ULONG nRecipCount; + lpMapiRecipDesc lpRecips; + ULONG nFileCount; + lpMapiFileDesc lpFiles; +} MapiMessage, FAR *lpMapiMessage; + +ULONG FAR PASCAL MAPISendMail (LHANDLE, ULONG, lpMapiMessage, FLAGS, ULONG); + +#ifdef __cplusplus +} +#endif + +#endif /* _MAPI_H */ diff --git a/winsup/cygwin/include/memory.h b/winsup/cygwin/include/memory.h new file mode 100644 index 000000000..dd2bd6cbf --- /dev/null +++ b/winsup/cygwin/include/memory.h @@ -0,0 +1,7 @@ +#ifndef _MEMORY_H +#define _MEMORY_H + +/* This allows more things to compile. */ +#include + +#endif /* _MEMORY_H */ diff --git a/winsup/cygwin/include/mntent.h b/winsup/cygwin/include/mntent.h new file mode 100644 index 000000000..0f0580a8e --- /dev/null +++ b/winsup/cygwin/include/mntent.h @@ -0,0 +1,35 @@ +#ifndef _MNTENT_H +#define _MNTENT_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct mntent +{ + char *mnt_fsname; + char *mnt_dir; + char *mnt_type; + char *mnt_opts; + int mnt_freq; + int mnt_passno; +}; + +FILE *setmntent (const char *__filep, const char *__type); +struct mntent *getmntent (FILE *__filep); +int addmntent (FILE *__filep, const struct mntent *__mnt); +int endmntent (FILE *__filep); +char *hasmntopt (const struct mntent *__mnt, const char *__opt); + +/* This next file doesn't exist, it is in the registry, + however applications need the define to pass to + the above calls. +*/ +#ifndef MOUNTED +#define MOUNTED "/etc/mtab" +#endif +#ifdef __cplusplus +}; +#endif + +#endif /* _MNTENT_H */ diff --git a/winsup/cygwin/include/net/if.h b/winsup/cygwin/include/net/if.h new file mode 100644 index 000000000..b7df5264e --- /dev/null +++ b/winsup/cygwin/include/net/if.h @@ -0,0 +1,6 @@ +#ifndef _NET_IF_H +#define _NET_IF_H + +#include + +#endif /* _NET_IF_H */ diff --git a/winsup/cygwin/include/netdb.h b/winsup/cygwin/include/netdb.h new file mode 100644 index 000000000..d1acc5e0a --- /dev/null +++ b/winsup/cygwin/include/netdb.h @@ -0,0 +1,167 @@ +/* Original linux netdb.h merged with winsock.h types */ + +/*- + * Copyright (c) 1980, 1983, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)netdb.h 8.1 (Berkeley) 6/2/93 + * netdb.h,v 1.1.1.1 1995/02/18 05:34:07 hjl Exp + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +#ifndef _NETDB_H_ +#define _NETDB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Structures returned by network data base library. All addresses are + * supplied in host order, and returned in network order (suitable for + * use in system calls). + */ + + /* Different from the linux versions - note the shorts.. */ +struct hostent { + const char *h_name; /* official name of host */ + char **h_aliases; /* alias list */ + short h_addrtype; /* host address type */ + short h_length; /* length of address */ + char **h_addr_list; /* list of addresses from name server */ +#define h_addr h_addr_list[0] /* address, for backward compatiblity */ +}; + +/* + * Assumption here is that a network number + * fits in an unsigned long -- probably a poor one. + */ + +struct netent { + char *n_name; /* official name of net */ + char **n_aliases; /* alias list */ + short n_addrtype; /* net address type */ + unsigned long n_net; /* network # */ +}; + +struct servent { + char *s_name; /* official service name */ + char **s_aliases; /* alias list */ + short s_port; /* port # */ + char *s_proto; /* protocol to use */ +}; + +struct protoent +{ + char *p_name; /* official protocol name */ + char **p_aliases; /* alias list */ + short p_proto; /* protocol # */ +}; + +struct rpcent { + char *r_name; /* name of server for this rpc program */ + char **r_aliases; /* alias list */ + int r_number; /* rpc program number */ +}; + +/* + * Error return codes from gethostbyname() and gethostbyaddr() + * (left in extern int h_errno). + */ + +#ifdef __INSIDE_CYGWIN_NET__ +extern int h_errno; +#else +extern __declspec(dllimport) int h_errno; +#endif + +#define NETDB_INTERNAL -1 /* see errno */ +#define NETDB_SUCCESS 0 /* no problem */ +#define HOST_NOT_FOUND 1 /* Authoritative Answer Host not found */ +#define TRY_AGAIN 2 /* Non-Authoritive Host not found, or SERVERFAIL */ +#define NO_RECOVERY 3 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */ +#define NO_DATA 4 /* Valid name, no data record of requested type */ +#define NO_ADDRESS NO_DATA /* no address, look for MX record */ + +#ifndef __INSIDE_CYGWIN_NET__ +void endhostent (void); +void endnetent (void); +void endprotoent (void); +void endservent (void); +void endrpcent (void); +struct hostent *gethostbyaddr (const char *, int, int); +struct hostent *gethostbyname (const char *); +struct hostent *gethostent (void); +struct netent *getnetbyaddr (long, int); /* u_long? */ +struct netent *getnetbyname (const char *); +struct netent *getnetent (void); +struct protoent *getprotobyname (const char *); +struct protoent *getprotobynumber (int); +struct protoent *getprotoent (void); +struct servent *getservbyname (const char *, const char *); +struct servent *getservbyport (int, const char *); +struct servent *getservent (void); +struct rpcent *getrpcent (void); +struct rpcent *getrpcbyname (const char *); +struct rpcent *getrpcbynumber (int); +void herror (const char *); +void sethostent (int); +void setnetent (int); +void setprotoent (int); +void setservent (int); +void setrpcent (int); +#endif + +#ifdef __cplusplus +}; +#endif + +#endif /* !_NETDB_H_ */ + diff --git a/winsup/cygwin/include/netinet/in.h b/winsup/cygwin/include/netinet/in.h new file mode 100644 index 000000000..8536f551e --- /dev/null +++ b/winsup/cygwin/include/netinet/in.h @@ -0,0 +1,6 @@ +#ifndef _NETINET_IN_H +#define _NETINET_IN_H + +#include + +#endif /* _NETINET_IN_H */ diff --git a/winsup/cygwin/include/netinet/ip.h b/winsup/cygwin/include/netinet/ip.h new file mode 100644 index 000000000..f50d7da2b --- /dev/null +++ b/winsup/cygwin/include/netinet/ip.h @@ -0,0 +1,6 @@ +#ifndef _NETINET_IP_H +#define _NETINET_IP_H + +#include + +#endif /* _NETINET_IP_H */ diff --git a/winsup/cygwin/include/netinet/ip_icmp.h b/winsup/cygwin/include/netinet/ip_icmp.h new file mode 100644 index 000000000..547a03a85 --- /dev/null +++ b/winsup/cygwin/include/netinet/ip_icmp.h @@ -0,0 +1,6 @@ +#ifndef _NETINET_IP_ICMP_H +#define _NETINET_IP_ICMP_H + +#include + +#endif /* _NETINET_IP_ICMP_H */ diff --git a/winsup/cygwin/include/paths.h b/winsup/cygwin/include/paths.h new file mode 100644 index 000000000..c4180873f --- /dev/null +++ b/winsup/cygwin/include/paths.h @@ -0,0 +1,9 @@ +#ifndef _PATHS_H_ +#define _PATHS_H_ + +#define _PATH_DEV "/dev/" +#define _PATH_BSHELL "/bin/sh" +#define _PATH_LASTLOG "/var/log/lastlog" +#define _PATH_UTMP "/var/run/utmp" +#define _PATH_WTMP "/var/log/wtmp" +#endif /* _PATHS_H_ */ diff --git a/winsup/cygwin/include/pthread.h b/winsup/cygwin/include/pthread.h new file mode 100644 index 000000000..4826e0897 --- /dev/null +++ b/winsup/cygwin/include/pthread.h @@ -0,0 +1,92 @@ +/* pthread.h: POSIX pthread interface + + Copyright 1996, 1997, 1998 Cygnus Solutions. + + Written by Marco Fuykschot + + This file is part of Cygwin. + + This software is a copyrighted work licensed under the terms of the + Cygwin license. Please consult the file "CYGWIN_LICENSE" for + details. */ + +#include +#include + +#ifndef _PTHREAD_H +#define _PTHREAD_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define TFD(n) void*(*n)(void*) + +typedef int pthread_t; +typedef int pthread_mutex_t; +typedef int sem_t; + +typedef struct pthread_key + { + } +pthread_key_t; + +typedef struct pthread_attr + { + size_t stacksize; + } +pthread_attr_t; + +typedef struct pthread_mutexattr + { + } +pthread_mutexattr_t; + +/* ThreadCreation */ +int pthread_create (pthread_t * thread, const pthread_attr_t * attr, TFD (function), void *arg); +int pthread_attr_init (pthread_attr_t * attr); +int pthread_attr_destroy (pthread_attr_t * attr); +int pthread_attr_setstacksize (pthread_attr_t * attr, size_t size); +int pthread_attr_getstacksize (pthread_attr_t * attr, size_t * size); +/* + pthread_attr_setstackaddr(...); + pthread_attr_getstackaddr(...); +*/ + +/* Thread Exit */ +int pthread_exit (void *value_ptr); + +/* Thread SpecificData */ +int pthread_key_create (pthread_key_t * key); +int pthread_key_delete (pthread_key_t * key); +int pthread_setspecific (pthread_key_t * key, const void *value); +void *pthread_getspecific (pthread_key_t * key); + +/* Thread signal */ +int pthread_kill (pthread_t * thread, int sig); +int pthread_sigmask (int operation, const sigset_t * set, sigset_t * old_set); + +/* ID */ +pthread_t pthread_self (); +int pthread_equal (pthread_t t1, pthread_t t2); + +/* Mutexes */ +int pthread_mutex_init (pthread_mutex_t * mutex, const pthread_mutexattr_t *); +int pthread_mutex_lock (pthread_mutex_t * mutext); +int pthread_mutex_trylock (pthread_mutex_t * mutext); +int pthread_mutex_unlock (pthread_mutex_t * mutext); +int pthread_mutex_destroy (pthread_mutex_t * mutext); + +/* Solaris Semaphores */ +int sem_init (sem_t * sem, int pshared, unsigned int value); +int sem_destroy (sem_t * sem); +int sem_wait (sem_t * sem); +int sem_trywait (sem_t * sem); +int sem_post (sem_t * sem); + +#ifdef __cplusplus +} +#endif + +#endif /* _PTHREAD_H */ diff --git a/winsup/cygwin/include/strings.h b/winsup/cygwin/include/strings.h new file mode 100644 index 000000000..e9d2839f2 --- /dev/null +++ b/winsup/cygwin/include/strings.h @@ -0,0 +1,6 @@ +#ifndef _STRINGS_H +#define _STRINGS_H + +#include + +#endif /* _STRINGS_H */ diff --git a/winsup/cygwin/include/sys/acl.h b/winsup/cygwin/include/sys/acl.h new file mode 100644 index 000000000..3fbef06da --- /dev/null +++ b/winsup/cygwin/include/sys/acl.h @@ -0,0 +1,17 @@ +/* sys/acl.h header file for Cygwin. + + Copyright 1999, 2000 Cygnus Solutions. + Written by C. Vinschen. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#ifndef _SYS_ACL_H +#define _SYS_ACL_H + +#include + +#endif /* _SYS_ACL_H */ diff --git a/winsup/cygwin/include/sys/cdefs.h b/winsup/cygwin/include/sys/cdefs.h new file mode 100644 index 000000000..bb99f7d0b --- /dev/null +++ b/winsup/cygwin/include/sys/cdefs.h @@ -0,0 +1,12 @@ +#ifndef _SYS_CDEFS_H +#define _SYS_CDEFS_H +#ifdef __cplusplus +#define __BEGIN_DECLS extern "C" { +#define __END_DECLS } +#else +#define __BEGIN_DECLS +#define __END_DECLS +#endif +#define __P(protos) protos /* full-blown ANSI C */ +#endif + diff --git a/winsup/cygwin/include/sys/copying.dj b/winsup/cygwin/include/sys/copying.dj new file mode 100644 index 000000000..7d048f70d --- /dev/null +++ b/winsup/cygwin/include/sys/copying.dj @@ -0,0 +1,41 @@ +This is the file "copying.dj". It does not apply to any sources +copyrighted by UCB Berkeley or the Free Software Foundation. + + Copyright Information for sources and executables that are marked + Copyright (C) DJ Delorie + 24 Kirsten Ave + Rochester NH 03867-2954 + +This document is Copyright (C) DJ Delorie and may be distributed +verbatim, but changing it is not allowed. + +Source code copyright DJ Delorie is distributed under the terms of the +GNU General Public Licence, with the following exceptions: + +* Any existing copyright or authorship information in any given source +file must remain intact. If you modify a source file, a notice to that +effect must be added to the authorship information in the source file. + +* binaries provided in djgpp may be distributed without sources ONLY if +the recipient is given sufficient information to obtain a copy of djgpp +themselves. This primarily applies to go32.exe, emu387, stub.exe, and +the graphics drivers. + +* modified versions of the binaries provided in djgpp must be +distributed under the terms of the GPL. + +* objects and libraries linked into an application may be distributed +without sources. + +----- + +Changes to source code copyright BSD or FSF are copyright DJ Delorie, but +fall under the terms of the original copyright. + +A copy of the file "COPYING" is included with this document. If you did not +receive a copy of "COPYING", you may obtain one from whence this document +was obtained, or by writing: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA diff --git a/winsup/cygwin/include/sys/cygwin.h b/winsup/cygwin/include/sys/cygwin.h new file mode 100644 index 000000000..3a3dd6e9b --- /dev/null +++ b/winsup/cygwin/include/sys/cygwin.h @@ -0,0 +1,44 @@ +#ifndef _SYS_CYGWIN_H +#define _SYS_CYGWIN_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern pid_t cygwin32_winpid_to_pid (int); +extern void cygwin32_win32_to_posix_path_list (const char *, char *); +extern int cygwin32_win32_to_posix_path_list_buf_size (const char *); +extern void cygwin32_posix_to_win32_path_list (const char *, char *); +extern int cygwin32_posix_to_win32_path_list_buf_size (const char *); +extern int cygwin32_conv_to_win32_path (const char *, char *); +extern int cygwin32_conv_to_full_win32_path (const char *, char *); +extern void cygwin32_conv_to_posix_path (const char *, char *); +extern void cygwin32_conv_to_full_posix_path (const char *, char *); +extern int cygwin32_posix_path_list_p (const char *); +extern void cygwin32_split_path (const char *, char *, char *); + +extern pid_t cygwin_winpid_to_pid (int); +extern int cygwin_win32_to_posix_path_list (const char *, char *); +extern int cygwin_win32_to_posix_path_list_buf_size (const char *); +extern int cygwin_posix_to_win32_path_list (const char *, char *); +extern int cygwin_posix_to_win32_path_list_buf_size (const char *); +extern int cygwin_conv_to_win32_path (const char *, char *); +extern int cygwin_conv_to_full_win32_path (const char *, char *); +extern int cygwin_conv_to_posix_path (const char *, char *); +extern int cygwin_conv_to_full_posix_path (const char *, char *); +extern int cygwin_posix_path_list_p (const char *); +extern void cygwin_split_path (const char *, char *, char *); + +#ifdef _GNU_H_WINDOWS32_BASE +/* included if is included */ +extern int cygwin32_attach_handle_to_fd (char *, int, HANDLE, int, int); +extern int cygwin_attach_handle_to_fd (char *, int, HANDLE, mode_t, unsigned); +#endif + +#ifdef __cplusplus +}; +#endif + +#endif /* _SYS_CYGWIN_H */ diff --git a/winsup/cygwin/include/sys/file.h b/winsup/cygwin/include/sys/file.h new file mode 100644 index 000000000..79f5f65f5 --- /dev/null +++ b/winsup/cygwin/include/sys/file.h @@ -0,0 +1,31 @@ +/* This is file FILE.H */ +/* +** Copyright (C) 1991 DJ Delorie, 24 Kirsten Ave, Rochester NH 03867-2954 +** +** This file is distributed under the terms listed in the document +** "copying.dj", available from DJ Delorie at the address above. +** A copy of "copying.dj" should accompany this file; if not, a copy +** should be available from where this file was obtained. This file +** may not be distributed without a verbatim copy of "copying.dj". +** +** This file is distributed WITHOUT ANY WARRANTY; without even the implied +** warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +*/ + +#ifndef _FILE_H_ +#define _FILE_H_ + +#include + +#define L_SET 0 +#define L_CURR 1 +#define L_INCR 1 +#define L_XTND 2 + + +#define F_OK 0 /* does file exist */ +#define X_OK 1 /* is it executable by caller */ +#define W_OK 2 /* is it writable by caller */ +#define R_OK 4 /* is it readable by caller */ + +#endif diff --git a/winsup/cygwin/include/sys/ioctl.h b/winsup/cygwin/include/sys/ioctl.h new file mode 100644 index 000000000..8164de85e --- /dev/null +++ b/winsup/cygwin/include/sys/ioctl.h @@ -0,0 +1,20 @@ +/* sys/ioctl.h */ + +#ifndef _SYS_IOCTL_H +#define _SYS_IOCTL_H + +#include + +/* /dev/windows ioctls */ + +#define WINDOWS_POST 0 /* Set write() behavior to PostMessage() */ +#define WINDOWS_SEND 1 /* Set write() behavior to SendMessage() */ +#define WINDOWS_HWND 2 /* Set hWnd for read() calls */ + +__BEGIN_DECLS + +int ioctl (int __fd, int __cmd, void *); + +__END_DECLS + +#endif diff --git a/winsup/cygwin/include/sys/mman.h b/winsup/cygwin/include/sys/mman.h new file mode 100644 index 000000000..9f36bc323 --- /dev/null +++ b/winsup/cygwin/include/sys/mman.h @@ -0,0 +1,40 @@ +#ifndef _SYS_MMAN_H_ +#define _SYS_MMAN_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include +#include + +#define PROT_NONE 0 +#define PROT_READ 1 +#define PROT_WRITE 2 +#define PROT_EXEC 4 + +#define MAP_FILE 0 +#define MAP_SHARED 1 +#define MAP_PRIVATE 2 +#define MAP_TYPE 0xF +#define MAP_FIXED 0x10 +#define MAP_ANONYMOUS 0x20 +#define MAP_ANON MAP_ANONYMOUS + +/* + * Flags for msync. + */ +#define MS_ASYNC 1 +#define MS_SYNC 2 +#define MS_INVALIDATE 4 + +extern caddr_t mmap (caddr_t __addr, size_t __len, int __prot, int __flags, int __fd, off_t __off); +extern int munmap (caddr_t __addr, size_t __len); +extern int mprotect (caddr_t __addr, size_t __len, int __prot); +extern int msync (caddr_t __addr, size_t __len, int __flags); + +#ifdef __cplusplus +}; +#endif /* __cplusplus */ + +#endif /* _SYS_MMAN_H_ */ diff --git a/winsup/cygwin/include/sys/mount.h b/winsup/cygwin/include/sys/mount.h new file mode 100644 index 000000000..2c4ad30a3 --- /dev/null +++ b/winsup/cygwin/include/sys/mount.h @@ -0,0 +1,25 @@ +#ifndef _SYS_MOUNT_H +#define _SYS_MOUNT_H + +#ifdef __cplusplus +extern "C" { +#endif + +enum + { + /* MOUNT_SYMLINK = 1, place holder. Do not use it. */ + MOUNT_BINARY = 2, /* "binary" format read/writes */ + MOUNT_SYSTEM = 8, /* mount point came from system table */ + MOUNT_EXEC = 16, /* Any file in the mounted directory gets 'x' bit */ + MOUNT_AUTO = 32 /* mount point refers to auto device mount */ + }; + +int mount (const char *, const char *, unsigned __flags); +int umount (const char *); +int cygwin_umount (const char *__path, unsigned __flags); + +#ifdef __cplusplus +}; +#endif + +#endif /* _SYS_MOUNT_H */ diff --git a/winsup/cygwin/include/sys/mtio.h b/winsup/cygwin/include/sys/mtio.h new file mode 100644 index 000000000..e21e4fff5 --- /dev/null +++ b/winsup/cygwin/include/sys/mtio.h @@ -0,0 +1,11 @@ +/* + * sys/mtio.h header file for Cygwin. + * + */ + +#ifndef _SYS_MTIO_H +#define _SYS_MTIO_H + +#include + +#endif /* _SYS_MTIO_H */ diff --git a/winsup/cygwin/include/sys/resource.h b/winsup/cygwin/include/sys/resource.h new file mode 100644 index 000000000..42907bc7b --- /dev/null +++ b/winsup/cygwin/include/sys/resource.h @@ -0,0 +1,40 @@ +#ifndef _SYS_RESOURCE_H_ +#define _SYS_RESOURCE_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define RUSAGE_SELF 0 /* calling process */ +#define RUSAGE_CHILDREN -1 /* terminated child processes */ + +struct rusage { + struct timeval ru_utime; /* user time used */ + struct timeval ru_stime; /* system time used */ + long ru_maxrss; + long ru_ixrss; /* XXX: 0 */ + long ru_idrss; /* XXX: sum of rm_asrss */ + long ru_isrss; /* XXX: 0 */ + long ru_minflt; /* any page faults not requiring I/O */ + long ru_majflt; /* any page faults requiring I/O */ + long ru_nswap; /* swaps */ + long ru_inblock; /* block input operations */ + long ru_oublock; /* block output operations */ + long ru_msgsnd; /* messages sent */ + long ru_msgrcv; /* messages received */ + long ru_nsignals; /* signals received */ + long ru_nvcsw; /* voluntary context switches */ + long ru_nivcsw; /* involuntary " */ +#define ru_last ru_nivcsw +}; + +int getrusage (int __who, struct rusage *__rusage); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/winsup/cygwin/include/sys/select.h b/winsup/cygwin/include/sys/select.h new file mode 100644 index 000000000..d4e811437 --- /dev/null +++ b/winsup/cygwin/include/sys/select.h @@ -0,0 +1,35 @@ +/* select.h + Copyright 1998 Cygnus Solutions. + + Written by Geoffrey Noer + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#ifndef _SYS_SELECT_H +#define _SYS_SELECT_H + +#if !defined (_POSIX_SOURCE) && !defined (__INSIDE_CYGWIN_NET__) + +#include + +/* Get fd_set, and macros like FD_SET */ +#include + +/* Get definition of timeval. */ +#include +#include + +__BEGIN_DECLS + +int select __P ((int __n, fd_set *__readfds, fd_set *__writefds, + fd_set *__exceptfds, struct timeval *__timeout)); + +__END_DECLS + +#endif /* !_POSIX_SOURCE, !__INSIDE_CYGWIN_NET__ */ + +#endif /* sys/select.h */ diff --git a/winsup/cygwin/include/sys/smallprint.h b/winsup/cygwin/include/sys/smallprint.h new file mode 100644 index 000000000..617e12a8c --- /dev/null +++ b/winsup/cygwin/include/sys/smallprint.h @@ -0,0 +1,17 @@ +#ifndef _SYS_SMALLPRINT_H +#define _SYS_SMALLPRINT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int __small_sprintf (char *__dst, const char *__fmt, ...); +int __small_vsprintf (char *__dst, const char *__fmt, va_list __ap); + +#ifdef __cplusplus +}; +#endif + +#endif /* _SYS_SMALLPRINT_H */ diff --git a/winsup/cygwin/include/sys/socket.h b/winsup/cygwin/include/sys/socket.h new file mode 100644 index 000000000..13217a068 --- /dev/null +++ b/winsup/cygwin/include/sys/socket.h @@ -0,0 +1,38 @@ +#ifndef _SYS_SOCKET_H +#define _SYS_SOCKET_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef __INSIDE_CYGWIN_NET__ + int accept (int, struct sockaddr *__peer, int *); + int bind (int, struct sockaddr *__my_addr, int __addrlen); + int connect (int, const struct sockaddr *, int); + int getpeername (int, struct sockaddr *__peer, int *); + int getsockname (int, struct sockaddr *__addr, int *); + int listen (int, int __n); + int recv (int, void *__buff, int __len, unsigned int __flags); + int recvfrom (int, char *__buff, int __len, int __flags, + struct sockaddr *__from, int *__fromlen); + int send (int, const void *__buff, int __len, unsigned int __flags); + int sendto (int, const void *, int, unsigned int, const struct sockaddr *, int); + int setsockopt (int __s, int __level, int __optname, const void *optval, int __optlen); + int getsockopt (int __s, int __level, int __optname, void *__optval, int *__optlen); + int shutdown (int, int); + int socket (int __family, int __type, int __protocol); + int socketpair (int __domain, int __type, int __protocol, int *__socket_vec); + + struct servent *getservbyname (const char *__name, const char *__proto); +#endif + +#ifdef __cplusplus +}; +#endif + +#endif /* _SYS_SOCKET_H */ diff --git a/winsup/cygwin/include/sys/strace.h b/winsup/cygwin/include/sys/strace.h new file mode 100644 index 000000000..7ee509983 --- /dev/null +++ b/winsup/cygwin/include/sys/strace.h @@ -0,0 +1,96 @@ +/* sys/strace.h */ + +/* This file contains routines for tracing system calls and other internal + phenomenon. + + When tracing system calls, try to use the same style throughout: + + result = syscall (arg1, arg2, arg3) [optional extra stuff] + + If a system call can block (eg: read, write, wait), print another message + before hanging so the user will know why the program has stopped. + + Note: __seterrno will also print a trace message. Have that printed + *first*. This will make it easy to always know what __seterrno is + refering to. For the same reason, try not to have __seterrno messages + printed alone. +*/ + +#ifndef _SYS_STRACE_H +#define _SYS_STRACE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define _STRACE_INTERFACE_ACTIVATE_ADDR -1 + +/* Bitmasks of tracing messages to print. */ + +#define _STRACE_ALL 0x00001 // so behaviour of strace=1 is unchanged +#define _STRACE_FLUSH 0x00002 // flush output buffer after every message +#define _STRACE_INHERIT 0x00004 // children inherit mask from parent +#define _STRACE_UHOH 0x00008 // unusual or weird phenomenon +#define _STRACE_SYSCALL 0x00010 // system calls +#define _STRACE_STARTUP 0x00020 // argc/envp printout at startup +#define _STRACE_DEBUG 0x00040 // info to help debugging +#define _STRACE_PARANOID 0x00080 // paranoid info +#define _STRACE_TERMIOS 0x00100 // info for debugging termios stuff +#define _STRACE_SELECT 0x00200 // info on ugly select internals +#define _STRACE_WM 0x00400 // trace windows messages (enable _strace_wm) +#define _STRACE_SIGP 0x00800 // trace signal and process handling +#define _STRACE_MINIMAL 0x01000 // very minimal strace output +#define _STRACE_EXITDUMP 0x04000 // dump strace cache on exit +#define _STRACE_CACHE 0x08000 // cache strace messages +#define _STRACE_NOMUTEX 0x10000 // don't use mutex for synchronization +#define _STRACE_MALLOC 0x20000 // trace malloc calls +#define _STRACE_THREAD 0x40000 // thread-locking calls +#define _STRACE_NOTALL 0x80000 // don't include if _STRACE_ALL + +void small_printf (const char *, ...); + +#ifdef NOSTRACE +#define strace_printf(category, fmt...) 0 +#define strace_printf_wrap(category, fmt...) 0 +#define strace_printf_wrap1(category, fmt...) 0 +#define strace_wm(category, msg...) 0 +#else +/* Output message to strace log */ +void strace_printf (unsigned, const char *, ...); +void __system_printf (const char *, ...); + +#define system_printf(fmt, args...) \ + __system_printf("%F: " fmt, __PRETTY_FUNCTION__ , ## args) + +void _strace_wm (int __message, int __word, int __lon); + +#define strace_printf_wrap(what, fmt, args...) \ + ((void) ({\ + if (strace_active) \ + strace_printf(_STRACE_ ## what, "%F: " fmt, __PRETTY_FUNCTION__ , ## args); \ + 0; \ + })) +#define strace_printf_wrap1(what, fmt, args...) \ + ((void) ({\ + if (strace_active) \ + strace_printf((_STRACE_ ## what) | _STRACE_NOTALL, "%F: " fmt, __PRETTY_FUNCTION__ , ## args); \ + 0; \ + })) +#endif /*NOSTRACE*/ + +#define debug_printf(fmt, args...) strace_printf_wrap(DEBUG, fmt , ## args) +#define syscall_printf(fmt, args...) strace_printf_wrap(SYSCALL, fmt , ## args) +#define paranoid_printf(fmt, args...) strace_printf_wrap(PARANOID, fmt , ## args) +#define termios_printf(fmt, args...) strace_printf_wrap(TERMIOS, fmt , ## args) +#define select_printf(fmt, args...) strace_printf_wrap(SELECT, fmt , ## args) +#define wm_printf(fmt, args...) strace_printf_wrap(WM, fmt , ## args) +#define sigproc_printf(fmt, args...) strace_printf_wrap(SIGP, fmt , ## args) +#define minimal_printf(fmt, args...) strace_printf_wrap1(MINIMAL, fmt , ## args) +#define malloc_printf(fmt, args...) strace_printf_wrap1(MALLOC, fmt , ## args) +#define thread_printf(fmt, args...) strace_printf_wrap1(THREAD, fmt , ## args) + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_STRACE_H */ diff --git a/winsup/cygwin/include/sys/syslog.h b/winsup/cygwin/include/sys/syslog.h new file mode 100644 index 000000000..65c6688f2 --- /dev/null +++ b/winsup/cygwin/include/sys/syslog.h @@ -0,0 +1,73 @@ +#ifndef _SYS_LOG_H +#define _SYS_LOG_H + +#include +#define LOG_EMERG 0 +#define LOG_ALERT 1 +#define LOG_CRIT 2 +#define LOG_ERR 3 +#define LOG_WARNING 4 +#define LOG_NOTICE 5 +#define LOG_INFO 6 +#define LOG_DEBUG 7 + +#define LOG_PRIMASK 0x07 + +#define LOG_PRI(p) ((p) & LOG_PRIMASK) +#define LOG_MAKEPRI(fac, pri) (((fac) << 3) | (pri)) + +#define LOG_KERN (0<<3) +#define LOG_USER (1<<3) +#define LOG_MAIL (2<<3) +#define LOG_DAEMON (3<<3) +#define LOG_AUTH (4<<3) +#define LOG_SYSLOG (5<<3) +#define LOG_LPR (6<<3) +#define LOG_NEWS (7<<3) +#define LOG_UUCP (8<<3) +#define LOG_CRON (9<<3) +#define LOG_AUTHPRIV (10<<3) +#define LOG_FTP (11<<3) + +/* Codes through 15 are reserved for system use */ +#define LOG_LOCAL0 (16<<3) +#define LOG_LOCAL1 (17<<3) +#define LOG_LOCAL2 (18<<3) +#define LOG_LOCAL3 (19<<3) +#define LOG_LOCAL4 (20<<3) +#define LOG_LOCAL5 (21<<3) +#define LOG_LOCAL6 (22<<3) +#define LOG_LOCAL7 (23<<3) + +#define LOG_NFACILITIES 24 +#define LOG_FACMASK 0x03f8 +#define LOG_FAC(p) (((p) & LOG_FACMASK) >> 3) + +#define LOG_MASK(pri) (1 << (pri)) +#define LOG_UPTO(pri) ((1 << ((pri)+1)) - 1) + +/* + * Option flags for openlog. + * + * LOG_ODELAY no longer does anything. + * LOG_NDELAY is the inverse of what it used to be. + */ +#define LOG_PID 0x01 /* log the pid with each message */ +#define LOG_CONS 0x02 /* log on the console if errors in sending */ +#define LOG_ODELAY 0x04 /* delay open until first syslog() (default) */ +#define LOG_NDELAY 0x08 /* don't delay open */ +#define LOG_NOWAIT 0x10 /* don't wait for console forks: DEPRECATED */ +#define LOG_PERROR 0x20 /* log to stderr as well */ + +__BEGIN_DECLS + + +void closelog (void); +void openlog (const char *, int, int); +int setlogmask (int); +void syslog (int, const char *, ...); + +__END_DECLS + + +#endif /* _SYS_LOG_H */ diff --git a/winsup/cygwin/include/sys/sysmacros.h b/winsup/cygwin/include/sys/sysmacros.h new file mode 100644 index 000000000..ecf3a3ae7 --- /dev/null +++ b/winsup/cygwin/include/sys/sysmacros.h @@ -0,0 +1,8 @@ +#ifndef _SYS_SYSMACROS_H +#define _SYS_SYSMACROS_H + +#define major(dev) ((int)(((dev) >> 8) & 0xff)) +#define minor(dev) ((int)((dev) & 0xff)) +#define makedev(major, minor) (((major) << 8) | (minor)) + +#endif /* _SYS_SYSMACROS_H */ diff --git a/winsup/cygwin/include/sys/termio.h b/winsup/cygwin/include/sys/termio.h new file mode 100644 index 000000000..75b815146 --- /dev/null +++ b/winsup/cygwin/include/sys/termio.h @@ -0,0 +1,2 @@ +#include + diff --git a/winsup/cygwin/include/sys/termios.h b/winsup/cygwin/include/sys/termios.h new file mode 100644 index 000000000..b0a242a33 --- /dev/null +++ b/winsup/cygwin/include/sys/termios.h @@ -0,0 +1,295 @@ +/* sys/termios.h */ + +#ifndef _SYS_TERMIOS_H +#define _SYS_TERMIOS_H + +#define TCOOFF 0 +#define TCOON 1 +#define TCIOFF 2 +#define TCION 3 + +#define TCGETA 5 +#define TCSETA 6 +#define TCSETAW 7 +#define TCSETAF 8 + +#define TCIFLUSH 0 +#define TCOFLUSH 1 +#define TCIOFLUSH 2 +#define TCFLSH 3 + +#define TCSAFLUSH 1 +#define TCSANOW 2 +#define TCSADRAIN 3 +#define TCSADFLUSH 4 + +#define TIOCPKT 6 + +#define TIOCPKT_DATA 0 +#define TIOCPKT_FLUSHREAD 1 +#define TIOCPKT_FLUSHWRITE 2 +#define TIOCPKT_STOP 4 +#define TIOCPKT_START 8 +#define TIOCPKT_NOSTOP 16 +#define TIOCPKT_DOSTOP 32 + +#define FIONBIO 0x8004667e /* To be compatible with socket version */ + +#define CTRL(ch) ((ch)&0x1F) + +#define CNUL 0 +#define CDEL 0x0007f +#define CESC '\\' +#define CINTR CTRL('C') +#define CQUIT 0x0001c +#define CERASE CTRL('H') +#define CKILL CTRL('U') +#define CEOT CTRL('D') +#define CEOL 0 +#define CEOL2 0 +#define CEOF CTRL('D') +#define CSTART CTRL('Q') +#define CSTOP CTRL('S') +#define CSWTCH 0x0001a +#define NSWTCH 0 +#define CSUSP CTRL('Z') +#define CDSUSP CTRL('Y') +#define CRPRNT CTRL('R') +#define CFLUSH CTRL('O') +#define CWERASE CTRL('W') +#define CLNEXT CTRL('V') + +/* iflag bits */ +#define IGNBRK 0x00001 +#define BRKINT 0x00002 +#define IGNPAR 0x00004 +#define IMAXBEL 0x00008 +#define INPCK 0x00010 +#define ISTRIP 0x00020 +#define INLCR 0x00040 +#define IGNCR 0x00080 +#define ICRNL 0x00100 +#define IXON 0x00400 +#define IXOFF 0x01000 +#define IUCLC 0x04000 +#define IXANY 0x08000 +#define PARMRK 0x10000 + +/* oflag bits */ + +#define OPOST 0x00001 +#define OLCUC 0x00002 +#define OCRNL 0x00004 +#define ONLCR 0x00008 +#define ONOCR 0x00010 +#define ONLRET 0x00020 +#define OFILL 0x00040 +#define CRDLY 0x00180 +#define CR0 0x00000 +#define CR1 0x00080 +#define CR2 0x00100 +#define CR3 0x00180 +#define NLDLY 0x00200 +#define NL0 0x00000 +#define NL1 0x00200 +#define BSDLY 0x00400 +#define BS0 0x00000 +#define BS1 0x00400 +#define TABDLY 0x01800 +#define TAB0 0x00000 +#define TAB1 0x00800 +#define TAB2 0x01000 +#define TAB3 0x01800 +#define XTABS 0x01800 +#define VTDLY 0x02000 +#define VT0 0x00000 +#define VT1 0x02000 +#define FFDLY 0x04000 +#define FF0 0x00000 +#define FF1 0x04000 +#define OFDEL 0x08000 + +/* cflag bits */ + +/* Baud rate values. These must fit in speed_t, which is unsigned + char. See also the extended baud rates below. These baud rates + set an additional bit. */ +#define CBAUD 0x0100f +#define B0 0x00000 +#define B50 0x00001 +#define B75 0x00002 +#define B110 0x00003 +#define B134 0x00004 +#define B150 0x00005 +#define B200 0x00006 +#define B300 0x00007 +#define B600 0x00008 +#define B1200 0x00009 +#define B1800 0x0000a +#define B2400 0x0000b +#define B4800 0x0000c +#define B9600 0x0000d +#define B19200 0x0000e +#define B38400 0x0000f + +#define CSIZE 0x00030 +#define CS5 0x00000 +#define CS6 0x00010 +#define CS7 0x00020 +#define CS8 0x00030 +#define CSTOPB 0x00040 +#define CREAD 0x00080 +#define PARENB 0x00100 +#define PARODD 0x00200 +#define HUPCL 0x00400 +#define CLOCAL 0x00800 +#define CBAUDEX 0x0100f +#define B57600 0x01001 +#define B115200 0x01002 +#define B128000 0x01003 +#define B256000 0x01003 +#define CRTSXOFF 0x04000 +#define CRTSCTS 0x08000 + +/* lflag bits */ +#define ISIG 0x0001 +#define ICANON 0x0002 +#define ECHO 0x0004 +#define ECHOE 0x0008 +#define ECHOK 0x0010 +#define ECHONL 0x0020 +#define NOFLSH 0x0040 +#define TOSTOP 0x0080 +#define IEXTEN 0x0100 +#define FLUSHO 0x0200 +#define ECHOKE 0x0400 +#define ECHOCTL 0x0800 + +#define VDISCARD 1 +#define VEOL 2 +#define VEOL2 3 +#define VEOF 4 +#define VERASE 5 +#define VINTR 6 +#define VKILL 7 +#define VLNEXT 8 +#define VMIN 9 +#define VQUIT 10 +#define VREPRINT 11 +#define VSTART 12 +#define VSTOP 13 +#define VSUSP 14 +#define VSWTC 15 +#define VTIME 16 +#define VWERASE 17 + +#define NCCS 18 + +typedef unsigned char cc_t; +typedef unsigned int tcflag_t; +typedef unsigned int speed_t; +typedef unsigned short otcflag_t; +typedef unsigned char ospeed_t; + +struct __oldtermios { + otcflag_t c_iflag; + otcflag_t c_oflag; + otcflag_t c_cflag; + otcflag_t c_lflag; + char c_line; + cc_t c_cc[NCCS]; + ospeed_t c_ispeed; + ospeed_t c_ospeed; +}; + +struct termios { + tcflag_t c_iflag; + tcflag_t c_oflag; + tcflag_t c_cflag; + tcflag_t c_lflag; + char c_line; + cc_t c_cc[NCCS]; + speed_t c_ispeed; + speed_t c_ospeed; +}; + +#ifdef CYGWIN_VERSION_DLL_IS_OLD_TERMIOS +#ifdef __GNUC__ +# define __tonew_termios(ti) \ + ({ \ + struct termios *__newti; \ + \ + if (!CYGWIN_VERSION_DLL_IS_OLD_TERMIOS) \ + __newti = (struct termios *) ti; \ + else \ + { \ + __newti = (struct termios *) alloca(sizeof(struct termios)); \ + __newti->c_iflag = ((struct __oldtermios *)ti)->c_iflag; \ + __newti->c_oflag = ((struct __oldtermios *)ti)->c_oflag; \ + __newti->c_cflag = ((struct __oldtermios *)ti)->c_cflag; \ + __newti->c_lflag = ((struct __oldtermios *)ti)->c_lflag; \ + __newti->c_line = ((struct __oldtermios *)ti)->c_line; \ + __newti->c_ispeed = ((struct __oldtermios *)ti)->c_ispeed; \ + __newti->c_ospeed = ((struct __oldtermios *)ti)->c_ospeed; \ + memcpy (__newti->c_cc, ((struct __oldtermios *)ti)->c_cc, sizeof(__newti->c_cc)); \ + } \ + __newti; \ + }) + +# define __makenew_termios(ti) \ + (CYGWIN_VERSION_DLL_IS_OLD_TERMIOS ? \ + (struct termios *) alloca (sizeof (struct termios)) : (ti)) + +# define __toapp_termios(toti, fromti) \ + ({ \ + if (!CYGWIN_VERSION_DLL_IS_OLD_TERMIOS) \ + toti = fromti; \ + else \ + { \ + ((struct __oldtermios *)toti)->c_iflag = fromti->c_iflag; \ + ((struct __oldtermios *)toti)->c_oflag = fromti->c_oflag; \ + ((struct __oldtermios *)toti)->c_cflag = fromti->c_cflag; \ + ((struct __oldtermios *)toti)->c_lflag = fromti->c_lflag; \ + ((struct __oldtermios *)toti)->c_line = fromti->c_line; \ + ((struct __oldtermios *)toti)->c_ispeed = fromti->c_ispeed; \ + ((struct __oldtermios *)toti)->c_ospeed = fromti->c_ospeed; \ + memcpy (((struct __oldtermios*)toti)->c_cc, fromti->c_cc, sizeof(fromti->c_cc)); \ + } \ + toti; \ + }) +#endif /*__GNUC__*/ +#endif + +#define termio termios + +#define cfgetospeed(tp) ((tp)->c_ospeed) +#define cfgetispeed(tp) ((tp)->c_ispeed) +#define cfsetospeed(tp,s) (((tp)->c_ospeed = (s)), 0) +#define cfsetispeed(tp,s) (((tp)->c_ispeed = (s)), 0) + +#ifdef __cplusplus +extern "C" { +#endif + +int tcgetattr (int, struct termios *); +int tcsetattr (int, int, const struct termios *); +int tcsendbreak (int, int); +int tcdrain (int); +int tcflush (int, int); +int tcflow (int, int); + +#ifdef __cplusplus +} +#endif + +/* Extra stuff to make porting stuff easier. */ +struct winsize +{ + unsigned short ws_row, ws_col; + unsigned short ws_xpixel, ws_ypixel; +}; + +#define TIOCGWINSZ (('T' << 8) | 1) +#define TIOCSWINSZ (('T' << 8) | 2) + +#endif /* _SYS_TERMIOS_H */ diff --git a/winsup/cygwin/include/sys/ttychars.h b/winsup/cygwin/include/sys/ttychars.h new file mode 100644 index 000000000..2d313646f --- /dev/null +++ b/winsup/cygwin/include/sys/ttychars.h @@ -0,0 +1 @@ +/* ttychars.h */ diff --git a/winsup/cygwin/include/sys/uio.h b/winsup/cygwin/include/sys/uio.h new file mode 100644 index 000000000..dad9dc17f --- /dev/null +++ b/winsup/cygwin/include/sys/uio.h @@ -0,0 +1,25 @@ +#ifndef _UIO_H_ +#define _UIO_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* For size_t */ +#include +/* For ssize_t */ +#include + +/* + * Define the uio buffers used for writev, readv. + */ + +struct iovec { + caddr_t iov_base; + int iov_len; +}; + +#ifdef __cplusplus +}; +#endif /* __cplusplus */ +#endif /* _UIO_H_ */ diff --git a/winsup/cygwin/include/sys/un.h b/winsup/cygwin/include/sys/un.h new file mode 100644 index 000000000..6f49c7b06 --- /dev/null +++ b/winsup/cygwin/include/sys/un.h @@ -0,0 +1,16 @@ +#ifndef _SYS_UN_H +#define _SYS_UN_H + +/* POSIX requires only at least 100 bytes */ +#define UNIX_PATH_LEN 108 + +struct sockaddr_un { + unsigned short sun_family; /* address family AF_LOCAL/AF_UNIX */ + char sun_path[UNIX_PATH_LEN]; /* 108 bytes of socket address */ +}; + +/* Evaluates the actual length of `sockaddr_un' structure. */ +#define SUN_LEN(p) ((size_t)(((struct sockaddr_un *) NULL)->sun_path) \ + + strlen ((p)->sun_path)) + +#endif diff --git a/winsup/cygwin/include/sys/utsname.h b/winsup/cygwin/include/sys/utsname.h new file mode 100644 index 000000000..bbfa9a6d0 --- /dev/null +++ b/winsup/cygwin/include/sys/utsname.h @@ -0,0 +1,23 @@ +#ifndef _SYS_UTSNAME_H +#define _SYS_UTSNAME_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct utsname +{ + char sysname[20]; + char nodename[20]; + char release[20]; + char version[20]; + char machine[20]; +}; + +int uname (struct utsname *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/winsup/cygwin/include/sys/vfs.h b/winsup/cygwin/include/sys/vfs.h new file mode 100644 index 000000000..4d3b0b6e0 --- /dev/null +++ b/winsup/cygwin/include/sys/vfs.h @@ -0,0 +1,28 @@ +#ifndef _SYS_VFS_H_ +#define _SYS_VFS_H_ + +struct statfs { + long f_type; /* type of filesystem (see below) */ + long f_bsize; /* optimal transfer block size */ + long f_blocks; /* total data blocks in file system */ + long f_bfree; /* free blocks in fs */ + long f_bavail; /* free blocks avail to non-superuser */ + long f_files; /* total file nodes in file system */ + long f_ffree; /* free file nodes in fs */ + long f_fsid; /* file system id */ + long f_namelen; /* maximum length of filenames */ + long f_spare[6]; /* spare for later */ +}; + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +int statfs (const char *__path, struct statfs *__buf); +int fstatfs (int __fd, struct statfs *__buf); + +#ifdef __cplusplus +}; +#endif /* __cplusplus */ + +#endif /*_SYS_VFS_H_*/ diff --git a/winsup/cygwin/include/sys/wait.h b/winsup/cygwin/include/sys/wait.h new file mode 100644 index 000000000..a9648eec2 --- /dev/null +++ b/winsup/cygwin/include/sys/wait.h @@ -0,0 +1,63 @@ +#ifndef _SYS_WAIT_H +#define _SYS_WAIT_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define WNOHANG 1 +#define WUNTRACED 2 + +/* A status looks like: + <2 bytes info> <2 bytes code> + + == 0, child has exited, info is the exit value + == 1..7e, child has exited, info is the signal number. + == 7f, child has stopped, info was the signal number. + == 80, there was a core dump. +*/ + +#define WIFEXITED(w) (((w) & 0xff) == 0) +#define WIFSIGNALED(w) (((w) & 0x7f) > 0 && (((w) & 0x7f) < 0x7f)) +#define WIFSTOPPED(w) (((w) & 0xff) == 0x7f) +#define WEXITSTATUS(w) (((w) >> 8) & 0xff) +#define WTERMSIG(w) ((w) & 0x7f) +#define WSTOPSIG WEXITSTATUS + +pid_t wait (int *); +pid_t waitpid (pid_t, int *, int); +pid_t wait3 (int *__status, int __options, struct rusage *__rusage); +pid_t wait4 (pid_t __pid, int *__status, int __options, struct rusage *__rusage); + +union wait + { + int w_status; + struct + { + unsigned int __w_termsig:7; /* Terminating signal. */ + unsigned int __w_coredump:1; /* Set if dumped core. */ + unsigned int __w_retcode:8; /* Return code if exited normally. */ + unsigned int:16; + } __wait_terminated; + struct + { + unsigned int __w_stopval:8; /* W_STOPPED if stopped. */ + unsigned int __w_stopsig:8; /* Stopping signal. */ + unsigned int:16; + } __wait_stopped; + }; + +#define w_termsig __wait_terminated.__w_termsig +#define w_coredump __wait_terminated.__w_coredump +#define w_retcode __wait_terminated.__w_retcode +#define w_stopsig __wait_stopped.__w_stopsig +#define w_stopval __wait_stopped.__w_stopval + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/winsup/cygwin/include/syslog.h b/winsup/cygwin/include/syslog.h new file mode 100644 index 000000000..ac2c0dc49 --- /dev/null +++ b/winsup/cygwin/include/syslog.h @@ -0,0 +1,6 @@ +#ifndef _SYSLOG_H +#define _SYSLOG_H + +#include + +#endif /* _SYSLOG_H */ diff --git a/winsup/cygwin/include/termio.h b/winsup/cygwin/include/termio.h new file mode 100644 index 000000000..8a9b3395f --- /dev/null +++ b/winsup/cygwin/include/termio.h @@ -0,0 +1,6 @@ +#ifndef _TERMIO_H +#define _TERMIO_H + +#include + +#endif diff --git a/winsup/cygwin/include/tzfile.h b/winsup/cygwin/include/tzfile.h new file mode 100644 index 000000000..9cce33cd1 --- /dev/null +++ b/winsup/cygwin/include/tzfile.h @@ -0,0 +1,10 @@ +#ifndef _TZFILE_H +#define _TZFILE_H + +#define SECSPERDAY (60*60*24) +#define DAYSPERNYEAR 365 +#define DAYSPERLYEAR 366 + +#define isleap(y) (((y) % 4) == 0 && ((y) % 100) != 0 || ((y) % 400) == 0) +#endif + diff --git a/winsup/cygwin/init.cc b/winsup/cygwin/init.cc new file mode 100644 index 000000000..a159def55 --- /dev/null +++ b/winsup/cygwin/init.cc @@ -0,0 +1,58 @@ +/* init.cc for WIN32. + + Copyright 1996, 1997, 1998, 1999 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include "winsup.h" + +extern "C" +{ + int WINAPI dll_entry (HANDLE h, DWORD reason, void *ptr); +}; + +extern "C" void *export_malloc (unsigned int); +extern "C" void *export_realloc (void *,unsigned int); +extern "C" void *export_calloc (unsigned int,unsigned int); +extern "C" void export_free (void *); + +extern void do_global_ctors (void (**in_pfunc)(), int force); + +int NO_COPY dynamically_loaded; + +int +WINAPI dll_entry (HANDLE hdll, DWORD reason, void *static_load) +{ + switch (reason) + { + case DLL_PROCESS_ATTACH: + dynamically_loaded = (static_load == NULL); + break; + case DLL_THREAD_ATTACH: + break; + case DLL_PROCESS_DETACH: + break; + case DLL_THREAD_DETACH: +#if 0 // FIXME: REINSTATE SOON + waitq *w; + if ((w = waitq_storage.get ()) != NULL) + { + if (w->thread_ev != NULL) + { + system_printf ("closing %p", w->thread_ev); + (void) CloseHandle (w->thread_ev); + } + memset (w, 0, sizeof(*w)); // FIXME: memory leak + } + // FIXME: Need to add other per_thread stuff here +#endif + break; + } + return 1; +} diff --git a/winsup/cygwin/ioctl.cc b/winsup/cygwin/ioctl.cc new file mode 100644 index 000000000..1fb5f3b59 --- /dev/null +++ b/winsup/cygwin/ioctl.cc @@ -0,0 +1,44 @@ +/* ioctl.cc: ioctl routines. + + Copyright 1996, 1998 Cygnus Solutions. + + Written by Doug Evans of Cygnus Support + dje@cygnus.com + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include "winsup.h" + +extern "C" +int +ioctl (int fd, int cmd, void *buf) +{ + if (dtable.not_open (fd)) + { + set_errno (EBADF); + return -1; + } + + debug_printf ("fd %d, cmd %x\n", fd, cmd); + fhandler_base *fh = dtable[fd]; + if (fh->is_tty () && fh->get_device () != FH_PTYM) + switch (cmd) + { + case TCGETA: + return tcgetattr (fd, (struct termios *) buf); + case TCSETA: + return tcsetattr (fd, TCSANOW, (struct termios *) buf); + case TCSETAW: + return tcsetattr (fd, TCSADRAIN, (struct termios *) buf); + case TCSETAF: + return tcsetattr (fd, TCSAFLUSH, (struct termios *) buf); + } + + return fh->ioctl (cmd, buf); +} diff --git a/winsup/cygwin/malloc_wrapper.cc b/winsup/cygwin/malloc_wrapper.cc new file mode 100644 index 000000000..aa4891b8e --- /dev/null +++ b/winsup/cygwin/malloc_wrapper.cc @@ -0,0 +1,221 @@ +/* malloc.cc for WIN32. + + Copyright 1996, 1997, 1998 Cygnus Solutions. + + Written by Steve Chamberlain of Cygnus Support + sac@cygnus.com + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include "winsup.h" +#include + +/* we provide these stubs to call into a user's + provided malloc if there is one - otherwise + functions we provide - like strdup will cause + problems if malloced on our heap and free'd on theirs. +*/ + +static int export_malloc_called = 0; +static int use_internal_malloc = 1; + +#undef in +#undef out +#define in(x) +#define out(x) + +#ifdef MALLOC_DEBUG +extern "C" void * _sbrk (size_t incr_arg); + +#if 0 +extern "C" void * +_sbrk_r (struct _reent *, size_t incr_arg) +{ + return _sbrk (incr_arg); +} +#endif + +extern "C" void * +_malloc_r (struct _reent *, size_t size) +{ + export_malloc_called = 1; + return malloc (size); +} +#undef malloc + +extern "C" void * +_calloc_r (struct _reent *, size_t nmemb, size_t size) +{ + export_malloc_called = 1; + return calloc (nmemb, size); +} +#undef calloc + +extern "C" void +_free_r (struct _reent *, void *p) +{ + export_malloc_called = 1; + free (p); +} +#undef free + +extern "C" void * +_realloc_r (struct _reent *, void *p, size_t size) +{ + export_malloc_called = 1; + return realloc (p, size); +} +#undef realloc + +extern "C" char * +strdup_dbg (const char *s, const char *file, int line) +{ + char *p; + export_malloc_called = 1; + if ((p = (char *) malloc_dbg (strlen (s) + 1, file, line)) != NULL) + strcpy (p, s); + return p; +} + +#undef strdup +extern "C" char * +strdup (const char *s) +{ + return strdup_dbg (s, __FILE__, __LINE__); +} +#else +/* Call though the application pointer, + which either points to export_malloc, or the application's + own version. */ + +void * +malloc (size_t size) +{ + void *res; + res = user_data->malloc (size); + return res; +} + +void +free (void *p) +{ + user_data->free (p); +} + +void * +realloc (void *p, size_t size) +{ + void *res; + res = user_data->realloc (p, size); + return res; +} + +void * +calloc (size_t nmemb, size_t size) +{ + void *res; + res = user_data->calloc (nmemb, size); + return res; +} +#endif + +/* These routines are used by the application if it + doesn't provide its own malloc. */ + +extern "C" +void +export_free (void *p) +{ + malloc_printf ("(%p), called by %x", p, ((int *)&p)[-1]); + if (use_internal_malloc) + _free_r (_impure_ptr, p); + else + user_data->free (p); +} + +extern "C" +void * +export_malloc (int size) +{ + void *res; + export_malloc_called = 1; + if (use_internal_malloc) + res = _malloc_r (_impure_ptr, size); + else + res = user_data->malloc (size); + malloc_printf ("(%d) = %x, called by %x", size, res, ((int *)&size)[-1]); + return res; +} + +extern "C" +void * +export_realloc (void *p, int size) +{ + void *res; + if (use_internal_malloc) + res = _realloc_r (_impure_ptr, p, size); + else + res = user_data->realloc (p, size); + malloc_printf ("(%x, %d) = %x, called by %x", p, size, res, ((int *)&p)[-1]); + return res; +} + +extern "C" +void * +export_calloc (size_t nmemb, size_t size) +{ + void *res; + if (use_internal_malloc) + res = _calloc_r (_impure_ptr, nmemb, size); + else + res = user_data->calloc (nmemb, size); + malloc_printf ("(%d, %d) = %x, called by %x", nmemb, size, res, ((int *)&nmemb)[-1]); + return res; +} + +/* We use a critical section to lock access to the malloc data + structures. This permits malloc to be called from different + threads. Note that it does not make malloc reentrant, and it does + not permit a signal handler to call malloc. The malloc code in + newlib will call __malloc_lock and __malloc_unlock at appropriate + times. */ + +static NO_COPY CRITICAL_SECTION malloc_critical_section; + +void +malloc_init () +{ + InitializeCriticalSection (&malloc_critical_section); + /* Check if mallock is provided by application. If so, redirect all + calls to export_malloc/free/realloc to application provided. This may + happen if some other dll calls cygwin's malloc, but main code provides + its own malloc */ + if (!user_data->forkee) + { +#ifdef MALLOC_DEBUG + _free_r (NULL, _malloc_r (NULL, 16)); +#else + free (malloc (16)); +#endif + if (!export_malloc_called) + use_internal_malloc = 0; + } +} + +extern "C" +void +__malloc_lock (struct _reent *ptr) +{ + SetResourceLock(LOCK_MEMORY_LIST,WRITE_LOCK|READ_LOCK," __malloc_lock"); +} + +extern "C" +void +__malloc_unlock (struct _reent *ptr) +{ + ReleaseResourceLock(LOCK_MEMORY_LIST,WRITE_LOCK|READ_LOCK," __malloc_unlock"); +} diff --git a/winsup/cygwin/mcount.c b/winsup/cygwin/mcount.c new file mode 100644 index 000000000..a8c5e3ea6 --- /dev/null +++ b/winsup/cygwin/mcount.c @@ -0,0 +1,174 @@ +/*- + * Copyright (c) 1983, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if !defined(lint) && !defined(_KERNEL) && defined(LIBC_SCCS) +static char rcsid[] = "$OpenBSD: mcount.c,v 1.6 1997/07/23 21:11:27 kstailey Exp $"; +#endif + +#include +#include +#include +#include + +/* + * mcount is called on entry to each function compiled with the profiling + * switch set. _mcount(), which is declared in a machine-dependent way + * with _MCOUNT_DECL, does the actual work and is either inlined into a + * C routine or called by an assembly stub. In any case, this magic is + * taken care of by the MCOUNT definition in . + * + * _mcount updates data structures that represent traversals of the + * program's call graph edges. frompc and selfpc are the return + * address and function address that represents the given call graph edge. + * + * Note: the original BSD code used the same variable (frompcindex) for + * both frompcindex and frompc. Any reasonable, modern compiler will + * perform this optimization. + */ +//_MCOUNT_DECL __P((u_long frompc, u_long selfpc)); +_MCOUNT_DECL(frompc, selfpc) /* _mcount; may be static, inline, etc */ + register u_long frompc, selfpc; +{ + register u_short *frompcindex; + register struct tostruct *top, *prevtop; + register struct gmonparam *p; + register long toindex; + + p = &_gmonparam; + /* + * check that we are profiling + * and that we aren't recursively invoked. + */ + if (p->state != GMON_PROF_ON) + return; + p->state = GMON_PROF_BUSY; + /* + * check that frompcindex is a reasonable pc value. + * for example: signal catchers get called from the stack, + * not from text space. too bad. + */ + frompc -= p->lowpc; + if (frompc > p->textsize) + goto done; + +#if (HASHFRACTION & (HASHFRACTION - 1)) == 0 + if (p->hashfraction == HASHFRACTION) + frompcindex = + &p->froms[frompc / (HASHFRACTION * sizeof(*p->froms))]; + else +#endif + frompcindex = + &p->froms[frompc / (p->hashfraction * sizeof(*p->froms))]; + toindex = *frompcindex; + if (toindex == 0) { + /* + * first time traversing this arc + */ + toindex = ++p->tos[0].link; + if (toindex >= p->tolimit) + /* halt further profiling */ + goto overflow; + + *frompcindex = toindex; + top = &p->tos[toindex]; + top->selfpc = selfpc; + top->count = 1; + top->link = 0; + goto done; + } + top = &p->tos[toindex]; + if (top->selfpc == selfpc) { + /* + * arc at front of chain; usual case. + */ + top->count++; + goto done; + } + /* + * have to go looking down chain for it. + * top points to what we are looking at, + * prevtop points to previous top. + * we know it is not at the head of the chain. + */ + for (; /* goto done */; ) { + if (top->link == 0) { + /* + * top is end of the chain and none of the chain + * had top->selfpc == selfpc. + * so we allocate a new tostruct + * and link it to the head of the chain. + */ + toindex = ++p->tos[0].link; + if (toindex >= p->tolimit) + goto overflow; + + top = &p->tos[toindex]; + top->selfpc = selfpc; + top->count = 1; + top->link = *frompcindex; + *frompcindex = toindex; + goto done; + } + /* + * otherwise, check the next arc on the chain. + */ + prevtop = top; + top = &p->tos[top->link]; + if (top->selfpc == selfpc) { + /* + * there it is. + * increment its count + * move it to the head of the chain. + */ + top->count++; + toindex = prevtop->link; + prevtop->link = top->link; + top->link = *frompcindex; + *frompcindex = toindex; + goto done; + } + } +done: + p->state = GMON_PROF_ON; + return; +overflow: + p->state = GMON_PROF_ERROR; + return; +} + +/* + * Actual definition of mcount function. Defined in , + * which is included by + */ +MCOUNT + diff --git a/winsup/cygwin/misc-std.sgml b/winsup/cygwin/misc-std.sgml new file mode 100644 index 000000000..1c02311f0 --- /dev/null +++ b/winsup/cygwin/misc-std.sgml @@ -0,0 +1,73 @@ + +Compatibility with Miscellaneous Other Standards + +The following functions are compatible with miscellaneous other +standards: + + +Networking + +(Standardized by POSIX 1.g, which is probably still in draft?) + +accept, bind, connect, getdomainname, gethostbyaddr, +gethostbyname, getpeername, getprotobyname, getprotobynumber, +getservbyname, getservbyport, getsockname, getsockopt, herror, htonl, +htons, inet_addr, inet_makeaddr, inet_netof, inet_ntoa, listen, ntohl, +ntohs, rcmd, recv, recvfrom, rexec, rresvport, send, sendto, +setsockopt, shutdown, socket, socketpair + +Of these networking calls, rexec, rcmd and rresvport are +implemented in MS IP stack but may not be implemented in other +vendors' stacks. + + + +Other + +chroot, closelog, cwait, dlclose, dlerror, dlfork, dlopen, dlsym, +endgrent, ffs, fstatfs, ftime, get_osfhandle, getdtablesize, getgrent, +gethostname, getitimer, getmntent, getpagesize, getpgid, getpwent, +gettimeofday, grantpt, initgroups, ioctl, killpg, login, logout, +lstat, mknod, memccpy, nice, openlog, pclose, popen, ptsname, putenv, +random, readv, realpath, regfree, rexec, select, setegid setenv, +seterrno, seteuid, setitimer, setmntent, setmode, setpassent, setpgrp, +setpwent, settimeofday, sexecl, sexecle, sexeclp, sexeclpe, sexeclpe, +sexecp, sexecv, sexecve, sexecvpe, sigpause, spawnl, spawnle, spawnlp, +spawnlpe, spawnv, spawnve, spawnvp, spawnvpe, srandom, statfs, +strsignal, strtosigno, swab, syslog, timezone, truncate, ttyslot, +unlockpt, unsetenv, usleep, utimes, vfork, vhangup, wait3, wait4, +wcscmp, wcslen, wprintf, writev + +Implementation Notes + + initgroups does nothing + + chroot, mknod, +settimeofday, and vhangup +always return -1 and sets errno to ENOSYS. + + nice allows Cygwin programs to alter their +current runtime priority through the use of its incr argument. Cygwin +processes can be set to IDLE_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, +HIGH_PRIORITY_CLASS, or REALTIME_PRIORITY_CLASS with the +nice call. NORMAL_PRIORITY_CLASS is the +default. If you pass a positive number to nice(), then the priority +level will decrease by one (within the above list of priorities). A +negative number would make it increase by one. It is not possible to +change it by more than one at a time without making repeated calls. +An increment above REALTIME_PRIORITY_CLASS results in the process +staying at that priority. Likewise, a decrement to +IDLE_PRIORITY_CLASS has it stay at that priority. Note that in the +Win32 API, there are 32 priorities. So currently we only give access +to four of these through nice. + + seteuid, setegid, and +settimeofday always return 0 and sets errno to +ENOSYS. + +vfork just calls +fork + + + + diff --git a/winsup/cygwin/mkvers.sh b/winsup/cygwin/mkvers.sh new file mode 100755 index 000000000..cda56195a --- /dev/null +++ b/winsup/cygwin/mkvers.sh @@ -0,0 +1,165 @@ +#!/bin/sh +# mkvers.sh - Make version information for cygwin DLL +# +# Copyright 1998, 1999, 2000 Cygnus Solutions. +# +# This file is part of Cygwin. +# +# This software is a copyrighted work licensed under the terms of the +# Cygwin license. Please consult the file "CYGWIN_LICENSE" for +# details. + +exec 9> version.cc +trap "rm -f /tmp/version.cc" 1 2 15 + +# +# Arg 1 is the name of the version include file +# +incfile="$1" +rcfile="$2" +windres="$3" + +[ -r $incfile ] || { + echo "**** Couldn't open file '$incfile'. Aborting." +} + +# +# Load the current date so we can work on individual fields +# +build_date=`date` +set -$- $build_date +# +# Translate the month into a number +# +case "$2" in + Jan) m=01 ;; + Feb) m=02 ;; + Mar) m=03 ;; + Apr) m=04 ;; + May) m=05 ;; + Jun) m=06 ;; + Jul) m=07 ;; + Aug) m=08 ;; + Sep) m=09 ;; + Oct) m=10 ;; + Nov) m=11 ;; + Dec) m=12 ;; +esac + +if [ "$3" -le 10 ]; then + d=0$3 +else + d=$3 +fi +# +# Set date into YYYY-MM-DD HH:MM:SS format +# +builddate="${6-$5}-$m-$d $4" + +set -$- '' + +# +# Output the initial part of version.cc +# +cat <&9 +#include + +#define strval(x) #x +#define str(x) strval(x) +#define shared_data_version str(CYGWIN_VERSION_SHARED_DATA) + +const char *cygwin_version_strings = + "BEGIN_CYGWIN_VERSION_INFO\n" +EOF + +# +# Split version file into dir and filename components +# +dir=`dirname $incfile` +fn=`basename $incfile` + +# +# Look in the include file CVS directory for a CVS Tag file. This file, +# if it exists, will contain the name of the sticky tag associated with +# the current build. Save that for output later. +# +cvs_tag="`sed 's%^.\(.*\)%\1%' $dir/CVS/Tag 2>/dev/null`" + +[ -n "$cvs_tag" ] && cvs_tag=" CVS tag"' +'"$cvs_tag" + +# +# Look in the source directory containing the include/cygwin/version.h +# file for a ".snapshot-date" file. If one is found then this information +# will be saved for output to the DLL. +# +dir=`echo $dir | sed -e 's%/include/cygwin.*$%%' -e 's%include/cygwin.*$%.%'` +if [ -r "$dir/.snapshot-date" ]; then + read snapshot < "$dir/.snapshot-date" + snapshot="snapshot date +$snapshot" +fi + +# +# Scan the version.h file for strings that begin with CYGWIN_INFO or +# CYGWIN_VERSION. Perform crude parsing on the lines to get the values +# associated with these values and then pipe it into a while loop which +# outputs these values in C palatable format for inclusion in the DLL +# with a '%% ' identifier that will introduce "interesting" strings. +# These strings are strictly for use by a user to scan the DLL for +# interesting information. +# +(sed -n -e 's%#define CYGWIN_\(INFO\|VERSION\)_\([A-Z_]*\)[ ][ ]*\([a-zA-Z0-9"][^/]*\).*%_\2\ +\3%p' $incfile | sed -e 's/["\\]//g' -e '/^_/y/ABCDEFGHIJKLMNOPQRSTUVWXYZ_/abcdefghijklmnopqrstuvwxyz /'; +echo ' build date'; echo $build_date; [ -n "$cvs_tag" ] && echo "$cvs_tag";\ +[ -n "$snapshot" ] && echo "$snapshot" +) | while read var; do + read val +cat <&9 + +trap "rm -f /tmp/mkvers.$$" 0 1 2 15 + +# +# Finally, output the shared ID and set up the cygwin_version structure +# for use by Cygwin itself. +# +cat <&9 +#ifdef DEBUGGING + "%%% Cygwin 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" +#endif + "END_CYGWIN_VERSION_INFO\n\0"; + +cygwin_version_info cygwin_version = +{ + CYGWIN_VERSION_API_MAJOR, CYGWIN_VERSION_API_MINOR, + CYGWIN_VERSION_DLL_MAJOR, CYGWIN_VERSION_DLL_MINOR, + CYGWIN_VERSION_SHARED_DATA, + CYGWIN_VERSION_MOUNT_REGISTRY, + "$builddate", +#ifdef DEBUGGING + CYGWIN_VERSION_DLL_IDENTIFIER "S" shared_data_version "-$builddate" +#else + CYGWIN_VERSION_DLL_IDENTIFIER "S" shared_data_version +#endif +}; +EOF + +# +# Generate winver.o using cygwin/version.h information. +# Turn the cygwin major number from some large number to something like 1.1.0. +# +eval `sed -n 's/^.*dll \(m[ai][jn]or\): \([0-9]*\)[^0-9]*$/\1=\2/p' /tmp/mkvers.$$` +cygverhigh=`expr $major / 1000` +cygverlow=`expr $major % 1000` +cygwin_ver="$cygverhigh.$cygverlow.$minor" +if [ -n "$cvs_tag" ]; then + cygwin_ver="$cygwin_ver ($cvs_tag)" +fi + +set -$- $builddate +$windres --include-dir $dir/../w32api/include --include-dir $dir/include --define CYGWIN_BUILD_DATE="$1" --define CYGWIN_BUILD_TIME="$2" --define CYGWIN_VERSION='"'"$cygwin_ver"'"' $rcfile winver.o diff --git a/winsup/cygwin/mmap.cc b/winsup/cygwin/mmap.cc new file mode 100644 index 000000000..c0cffc285 --- /dev/null +++ b/winsup/cygwin/mmap.cc @@ -0,0 +1,474 @@ +/* mmap.cc + + Copyright 1996, 1997, 1998, 2000 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include + +#include "winsup.h" + +/* + * Simple class used to keep a record of all current + * mmap areas in a process. Needed so that + * they can be duplicated after a fork(). + */ + +class mmap_record +{ + private: + HANDLE mapping_handle_; + DWORD access_mode_; + DWORD offset_; + DWORD size_to_map_; + void *base_address_; + + public: + mmap_record (HANDLE h, DWORD ac, DWORD o, DWORD s, void *b) : + mapping_handle_ (h), access_mode_ (ac), offset_ (o), + size_to_map_ (s), base_address_ (b) { ; } + + /* Default Copy constructor/operator=/destructor are ok */ + + /* Simple accessors */ + HANDLE get_handle () const { return mapping_handle_; } + DWORD get_access () const { return access_mode_; } + DWORD get_offset () const { return offset_; } + DWORD get_size () const { return size_to_map_; } + void *get_address () const { return base_address_; } +}; + +class list { +public: + mmap_record *recs; + int nrecs, maxrecs; + int fd; + list (); + ~list (); + void add_record (mmap_record r); + void erase (int i); +}; + +list::list () +{ + recs = (mmap_record *) malloc (10 * sizeof(mmap_record)); + nrecs = 0; + maxrecs = 10; + fd = 0; +} + +list::~list () +{ + free (recs); +} + +void +list::add_record (mmap_record r) +{ + if (nrecs == maxrecs) + { + maxrecs += 5; + recs = (mmap_record *) realloc (recs, maxrecs * sizeof (mmap_record)); + } + recs[nrecs++] = r; +} + +void +list::erase (int i) +{ + while (i < nrecs-1) + recs[i] = recs[i+1]; + nrecs--; +} + +class map { +public: + list **lists; + int nlists, maxlists; + map (); + ~map (); + list *get_list_by_fd (int fd); + list *add_list (list *l, int fd); + void erase (int i); +}; + +map::map () +{ + lists = (list **) malloc (10 * sizeof(list *)); + nlists = 0; + maxlists = 10; +} + +map::~map () +{ + free (lists); +} + +list * +map::get_list_by_fd (int fd) +{ + int i; + for (i=0; ifd == fd) + return lists[i]; + return 0; +} + +list * +map::add_list (list *l, int fd) +{ + l->fd = fd; + if (nlists == maxlists) + { + maxlists += 5; + lists = (list **) realloc (lists, maxlists * sizeof (list *)); + } + lists[nlists++] = l; + return lists[nlists-1]; +} + +void +map::erase (int i) +{ + while (i < nlists-1) + lists[i] = lists[i+1]; + nlists--; +} + +/* + * Code to keep a record of all mmap'ed areas in a process. + * Needed to duplicate tham in a child of fork(). + * mmap_record classes are kept in an STL list in an STL map, keyed + * by file descriptor. This is *NOT* duplicated accross a fork(), it + * needs to be specially handled by the fork code. + */ + +static NO_COPY map *mmapped_areas; + +extern "C" +caddr_t +mmap (caddr_t addr, size_t len, int prot, int flags, int fd, off_t off) +{ + syscall_printf ("addr %x, len %d, prot %x, flags %x, fd %d, off %d", + addr, len, prot, flags, fd, off); + + SetResourceLock(LOCK_MMAP_LIST,READ_LOCK|WRITE_LOCK," mmap"); + + /* Windows 95 does not have fixed addresses */ + if ((os_being_run != winNT) && (flags & MAP_FIXED)) + { + set_errno (EINVAL); + syscall_printf ("-1 = mmap(): win95 and MAP_FIXED"); + return (caddr_t) -1; + } + + if (mmapped_areas == 0) + { + /* First mmap call, create STL map */ + mmapped_areas = new map; + if (mmapped_areas == 0) + { + set_errno (ENOMEM); + syscall_printf ("-1 = mmap(): ENOMEM"); + return (caddr_t) -1; + } + } + + DWORD access = (prot & PROT_WRITE) ? FILE_MAP_WRITE : FILE_MAP_READ; + if (flags & MAP_PRIVATE) + access = FILE_MAP_COPY; + DWORD protect; + + if (access & FILE_MAP_COPY) + protect = PAGE_WRITECOPY; + else if (access & FILE_MAP_WRITE) + protect = PAGE_READWRITE; + else + protect = PAGE_READONLY; + + HANDLE hFile; + + if (fd == -1) + hFile = (HANDLE) 0xFFFFFFFF; + else + { + /* Ensure that fd is open */ + if (dtable.not_open (fd)) + { + set_errno (EBADF); + syscall_printf ("-1 = mmap(): EBADF"); + ReleaseResourceLock(LOCK_MMAP_LIST,READ_LOCK|WRITE_LOCK," mmap"); + return (caddr_t) -1; + } + hFile = dtable[fd]->get_handle (); + } + + HANDLE h = CreateFileMapping (hFile, &sec_none, protect, 0, len, NULL); + if (h == 0) + { + __seterrno (); + syscall_printf ("-1 = mmap(): CreateFileMapping failed with %E"); + ReleaseResourceLock(LOCK_MMAP_LIST,READ_LOCK|WRITE_LOCK," mmap"); + return (caddr_t) -1; + } + + void *base; + + if (flags & MAP_FIXED) + { + base = MapViewOfFileEx (h, access, 0, off, len, addr); + if (base != addr) + { + __seterrno (); + syscall_printf ("-1 = mmap(): MapViewOfFileEx failed with %E"); + CloseHandle (h); + ReleaseResourceLock(LOCK_MMAP_LIST,READ_LOCK|WRITE_LOCK," mmap"); + return (caddr_t) -1; + } + } + else + { + base = MapViewOfFile (h, access, 0, off, len); + if (base == 0) + { + __seterrno (); + syscall_printf ("-1 = mmap(): MapViewOfFile failed with %E"); + CloseHandle (h); + ReleaseResourceLock(LOCK_MMAP_LIST,READ_LOCK|WRITE_LOCK," mmap"); + return (caddr_t) -1; + } + } + + /* Now we should have a successfully mmaped area. + Need to save it so forked children can reproduce it. + */ + + mmap_record mmap_rec (h, access, off, len, base); + + /* Get list of mmapped areas for this fd, create a new one if + one does not exist yet. + */ + + list *l = mmapped_areas->get_list_by_fd (fd); + if (l == 0) + { + /* Create a new one */ + l = new list; + if (l == 0) + { + UnmapViewOfFile (base); + CloseHandle (h); + set_errno (ENOMEM); + syscall_printf ("-1 = mmap(): ENOMEM"); + ReleaseResourceLock(LOCK_MMAP_LIST,READ_LOCK|WRITE_LOCK," mmap"); + return (caddr_t) -1; + } + l = mmapped_areas->add_list (l, fd); + } + + /* Insert into the list */ + l->add_record (mmap_rec); + + syscall_printf ("%x = mmap() succeeded", base); + ReleaseResourceLock(LOCK_MMAP_LIST,READ_LOCK|WRITE_LOCK," mmap"); + return (caddr_t) base; +} + +/* munmap () removes an mmapped area. It insists that base area + requested is the same as that mmapped, error if not. */ + +extern "C" +int +munmap (caddr_t addr, size_t len) +{ + syscall_printf ("munmap (addr %x, len %d)", addr, len); + + SetResourceLock(LOCK_MMAP_LIST,WRITE_LOCK|READ_LOCK," munmap"); + /* Check if a mmap'ed area was ever created */ + if (mmapped_areas == 0) + { + syscall_printf ("-1 = munmap(): mmapped_areas == 0"); + set_errno (EINVAL); + ReleaseResourceLock(LOCK_MMAP_LIST,WRITE_LOCK|READ_LOCK," munmap"); + return -1; + } + + /* Iterate through the map, looking for the mmapped area. + Error if not found. */ + + int it; + for (it = 0; it < mmapped_areas->nlists; ++it) + { + list *l = mmapped_areas->lists[it]; + if (l != 0) + { + int li; + for (li = 0; li < l->nrecs; ++li) + { + mmap_record rec = l->recs[li]; + if (rec.get_address () == addr) + { + /* Unmap the area */ + UnmapViewOfFile (addr); + CloseHandle (rec.get_handle ()); + /* Delete the entry. */ + l->erase (li); + syscall_printf ("0 = munmap(): %x", addr); + ReleaseResourceLock(LOCK_MMAP_LIST,WRITE_LOCK|READ_LOCK," munmap"); + return 0; + } + } + } + } + set_errno (EINVAL); + + syscall_printf ("-1 = munmap(): EINVAL"); + + ReleaseResourceLock(LOCK_MMAP_LIST,WRITE_LOCK|READ_LOCK," munmap"); + return -1; +} + +/* Sync file with memory. Ignore flags for now. */ + +extern "C" +int +msync (caddr_t addr, size_t len, int flags) +{ + syscall_printf ("addr = %x, len = %d, flags = %x", + addr, len, flags); + + if (FlushViewOfFile (addr, len) == 0) + { + syscall_printf ("-1 = msync: %E"); + __seterrno (); + return -1; + } + syscall_printf ("0 = msync"); + return 0; +} + +/* Set memory protection */ + +extern "C" +int +mprotect (caddr_t addr, size_t len, int prot) +{ + DWORD old_prot; + DWORD new_prot = 0; + + syscall_printf ("mprotect (addr %x, len %d, prot %x)", addr, len, prot); + + if (prot == PROT_NONE) + new_prot = PAGE_NOACCESS; + else + { + switch (prot) + { + case PROT_READ | PROT_WRITE | PROT_EXEC: + new_prot = PAGE_EXECUTE_READWRITE; + break; + case PROT_READ | PROT_WRITE: + new_prot = PAGE_READWRITE; + break; + case PROT_READ | PROT_EXEC: + new_prot = PAGE_EXECUTE_READ; + break; + case PROT_READ: + new_prot = PAGE_READONLY; + break; + default: + syscall_printf ("-1 = mprotect (): invalid prot value"); + set_errno (EINVAL); + return -1; + } + } + + if (VirtualProtect (addr, len, new_prot, &old_prot) == 0) + { + __seterrno (); + syscall_printf ("-1 = mprotect (): %E"); + return -1; + } + + syscall_printf ("0 = mprotect ()"); + return 0; +} + +/* + * Call to re-create all the file mappings in a forked + * child. Called from the child in initialization. At this + * point we are passed a valid mmaped_areas map, and all the + * HANDLE's are valid for the child, but none of the + * mapped areas are in our address space. We need to iterate + * through the map, doing the MapViewOfFile calls. + */ + +int __stdcall +recreate_mmaps_after_fork (void *param) +{ + map *areas = (map *)param; + void *base; + + debug_printf ("recreate_mmaps_after_fork, mmapped_areas %p", areas); + + /* Check if a mmapped area was ever created */ + if (areas == 0) + return 0; + + /* Iterate through the map */ + + int it; + + for (it = 0; it < areas->nlists; ++it) + { + list *l = areas->lists[it]; + if (l != 0) + { + int li; + for (li = 0; li < l->nrecs; ++li) + { + mmap_record rec = l->recs[li]; + + debug_printf ("h %x, access %x, offset %d, size %d, address %p", + rec.get_handle (), rec.get_access (), rec.get_offset (), + rec.get_size (), rec.get_address ()); + + /* Now re-create the MapViewOfFileEx call */ + base = MapViewOfFileEx (rec.get_handle (), + rec.get_access (), 0, + rec.get_offset (), + rec.get_size (), + rec.get_address ()); + if (base != rec.get_address ()) + { + system_printf ("base address %p fails to match requested address %p", + rec.get_address ()); + return -1; + } + } + } + } + + /* Now set our mmap record in case the child forks. */ + mmapped_areas = areas; + + debug_printf ("succeeded"); + + return 0; +} + +/* Set a child mmap ptr from our static one. Used to set child mmap + pointer for fork. */ + +void __stdcall +set_child_mmap_ptr (pinfo *child) +{ + child->mmap_ptr = (void *) mmapped_areas; +} diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc new file mode 100644 index 000000000..1cff9b309 --- /dev/null +++ b/winsup/cygwin/net.cc @@ -0,0 +1,1827 @@ +/* net.cc: network-related routines. + + Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +/* #define DEBUG_NEST_ON 1 */ + +#define __INSIDE_CYGWIN_NET__ + +#include +#include +#include + +#define Win32_Winsock +#include "winsup.h" +#include +#include +#include +#include "autoload.h" +#include + +/* We only want to initialize WinSock in a child process if socket + handles are inheritted. This global allows us to know whether this + should be done or not */ +int number_of_sockets = 0; + +extern "C" +{ +int h_errno; + +int __stdcall rcmd (char **ahost, unsigned short inport, char *locuser, + char *remuser, char *cmd, SOCKET *fd2p); +int __stdcall rexec (char **ahost, unsigned short inport, char *locuser, + char *password, char *cmd, SOCKET *fd2p); +int __stdcall rresvport (int *); +int sscanf (const char *, const char *, ...); +} /* End of "C" section */ + +/* Cygwin internal */ +static SOCKET +duplicate_socket (SOCKET sock) +{ + /* Do not duplicate socket on Windows NT because of problems with + MS winsock proxy server. + */ + if (os_being_run == winNT) + return sock; + + SOCKET newsock; + if (DuplicateHandle (hMainProc, (HANDLE) sock, hMainProc, (HANDLE *) &newsock, + 0, TRUE, DUPLICATE_SAME_ACCESS)) + { + closesocket (sock); + sock = newsock; + } + else + small_printf ("DuplicateHandle failed %E"); + return sock; +} + +/* htonl: standards? */ +extern "C" +unsigned long int +htonl (unsigned long int x) +{ + MARK (); + return ((((x & 0x000000ffU) << 24) | + ((x & 0x0000ff00U) << 8) | + ((x & 0x00ff0000U) >> 8) | + ((x & 0xff000000U) >> 24))); +} + +/* ntohl: standards? */ +extern "C" +unsigned long int +ntohl (unsigned long int x) +{ + return htonl (x); +} + +/* htons: standards? */ +extern "C" +unsigned short +htons (unsigned short x) +{ + MARK (); + return ((((x & 0x000000ffU) << 8) | + ((x & 0x0000ff00U) >> 8))); +} + +/* ntohs: standards? */ +extern "C" +unsigned short +ntohs (unsigned short x) +{ + return htons (x); +} + +/* Cygwin internal */ +static void +dump_protoent (struct protoent *p) +{ + if (p) + debug_printf ("protoent %s %x %x", p->p_name, p->p_aliases, p->p_proto); +} + +/* exported as inet_ntoa: standards? */ +extern "C" +char * +cygwin_inet_ntoa (struct in_addr in) +{ + char *res = inet_ntoa (in); + return res; +} + +/* exported as inet_addr: standards? */ +extern "C" +unsigned long +cygwin_inet_addr (const char *cp) +{ + unsigned long res = inet_addr (cp); + return res; +} + +/* inet_netof is in the standard BSD sockets library. It is useless + for modern networks, since it assumes network values which are no + longer meaningful, but some existing code calls it. */ + +extern "C" +unsigned long +inet_netof (struct in_addr in) +{ + unsigned long i, res; + + + i = ntohl (in.s_addr); + if (IN_CLASSA (i)) + res = (i & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT; + else if (IN_CLASSB (i)) + res = (i & IN_CLASSB_NET) >> IN_CLASSB_NSHIFT; + else + res = (i & IN_CLASSC_NET) >> IN_CLASSC_NSHIFT; + + + return res; +} + +/* inet_makeaddr is in the standard BSD sockets library. It is + useless for modern networks, since it assumes network values which + are no longer meaningful, but some existing code calls it. */ + +extern "C" +struct in_addr +inet_makeaddr (int net, int lna) +{ + unsigned long i; + struct in_addr in; + + + if (net < IN_CLASSA_MAX) + i = (net << IN_CLASSA_NSHIFT) | (lna & IN_CLASSA_HOST); + else if (net < IN_CLASSB_MAX) + i = (net << IN_CLASSB_NSHIFT) | (lna & IN_CLASSB_HOST); + else if (net < 0x1000000) + i = (net << IN_CLASSC_NSHIFT) | (lna & IN_CLASSC_HOST); + else + i = net | lna; + + in.s_addr = htonl (i); + + + return in; +} + +struct tl +{ + int w; + const char *s; + int e; +}; + +static struct tl errmap[] = +{ + {WSAEWOULDBLOCK, "WSAEWOULDBLOCK", EWOULDBLOCK}, + {WSAEINPROGRESS, "WSAEINPROGRESS", EINPROGRESS}, + {WSAEALREADY, "WSAEALREADY", EALREADY}, + {WSAENOTSOCK, "WSAENOTSOCK", ENOTSOCK}, + {WSAEDESTADDRREQ, "WSAEDESTADDRREQ", EDESTADDRREQ}, + {WSAEMSGSIZE, "WSAEMSGSIZE", EMSGSIZE}, + {WSAEPROTOTYPE, "WSAEPROTOTYPE", EPROTOTYPE}, + {WSAENOPROTOOPT, "WSAENOPROTOOPT", ENOPROTOOPT}, + {WSAEPROTONOSUPPORT, "WSAEPROTONOSUPPORT", EPROTONOSUPPORT}, + {WSAESOCKTNOSUPPORT, "WSAESOCKTNOSUPPORT", ESOCKTNOSUPPORT}, + {WSAEOPNOTSUPP, "WSAEOPNOTSUPP", EOPNOTSUPP}, + {WSAEPFNOSUPPORT, "WSAEPFNOSUPPORT", EPFNOSUPPORT}, + {WSAEAFNOSUPPORT, "WSAEAFNOSUPPORT", EAFNOSUPPORT}, + {WSAEADDRINUSE, "WSAEADDRINUSE", EADDRINUSE}, + {WSAEADDRNOTAVAIL, "WSAEADDRNOTAVAIL", EADDRNOTAVAIL}, + {WSAENETDOWN, "WSAENETDOWN", ENETDOWN}, + {WSAENETUNREACH, "WSAENETUNREACH", ENETUNREACH}, + {WSAENETRESET, "WSAENETRESET", ENETRESET}, + {WSAECONNABORTED, "WSAECONNABORTED", ECONNABORTED}, + {WSAECONNRESET, "WSAECONNRESET", ECONNRESET}, + {WSAENOBUFS, "WSAENOBUFS", ENOBUFS}, + {WSAEISCONN, "WSAEISCONN", EISCONN}, + {WSAENOTCONN, "WSAENOTCONN", ENOTCONN}, + {WSAESHUTDOWN, "WSAESHUTDOWN", ESHUTDOWN}, + {WSAETOOMANYREFS, "WSAETOOMANYREFS", ETOOMANYREFS}, + {WSAETIMEDOUT, "WSAETIMEDOUT", ETIMEDOUT}, + {WSAECONNREFUSED, "WSAECONNREFUSED", ECONNREFUSED}, + {WSAELOOP, "WSAELOOP", ELOOP}, + {WSAENAMETOOLONG, "WSAENAMETOOLONG", ENAMETOOLONG}, + {WSAEHOSTDOWN, "WSAEHOSTDOWN", EHOSTDOWN}, + {WSAEHOSTUNREACH, "WSAEHOSTUNREACH", EHOSTUNREACH}, + {WSAENOTEMPTY, "WSAENOTEMPTY", ENOTEMPTY}, + {WSAEPROCLIM, "WSAEPROCLIM", EPROCLIM}, + {WSAEUSERS, "WSAEUSERS", EUSERS}, + {WSAEDQUOT, "WSAEDQUOT", EDQUOT}, + {WSAESTALE, "WSAESTALE", ESTALE}, + {WSAEREMOTE, "WSAEREMOTE", EREMOTE}, + {WSAEINVAL, "WSAEINVAL", EINVAL}, + {WSAEFAULT, "WSAEFAULT", EFAULT}, + {0} +}; + +/* Cygwin internal */ +void +set_winsock_errno () +{ + int i; + int why = WSAGetLastError (); + for (i = 0; errmap[i].w != 0; ++i) + if (why == errmap[i].w) + break; + + if (errmap[i].w != 0) + { + syscall_printf ("%d (%s) -> %d", why, errmap[i].s, errmap[i].e); + set_errno (errmap[i].e); + } + else + { + syscall_printf ("unknown error %d", why); + set_errno (EPERM); + } +} + +static struct tl host_errmap[] = +{ + {WSAHOST_NOT_FOUND, "WSAHOST_NOT_FOUND", HOST_NOT_FOUND}, + {WSATRY_AGAIN, "WSATRY_AGAIN", TRY_AGAIN}, + {WSANO_RECOVERY, "WSANO_RECOVERY", NO_RECOVERY}, + {WSANO_DATA, "WSANO_DATA", NO_DATA}, + {0} +}; + +/* Cygwin internal */ +static void +set_host_errno () +{ + int i; + + int why = WSAGetLastError (); + for (i = 0; i < host_errmap[i].w != 0; ++i) + if (why == host_errmap[i].w) + break; + + if (host_errmap[i].w != 0) + h_errno = host_errmap[i].e; + else + h_errno = NETDB_INTERNAL; +} + +/* exported as getprotobyname: standards? */ +extern "C" +struct protoent * +cygwin_getprotobyname (const char *p) +{ + + struct protoent *res = getprotobyname (p); + if (!res) + set_winsock_errno (); + + dump_protoent (res); + return res; +} + +/* exported as getprotobynumber: standards? */ +extern "C" +struct protoent * +cygwin_getprotobynumber (int number) +{ + + struct protoent *res = getprotobynumber (number); + if (!res) + set_winsock_errno (); + + dump_protoent (res); + return res; +} + +void +fdsock (int fd, const char *name, SOCKET soc) +{ + fhandler_base *fh = dtable.build_fhandler(fd, FH_SOCKET, name); + fh->set_io_handle ((HANDLE) soc); + fh->set_flags (O_RDWR); +} + +/* exported as socket: standards? */ +extern "C" +int +cygwin_socket (int af, int type, int protocol) +{ + int res = -1; + SetResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK," socket"); + + SOCKET soc; + + int fd = dtable.find_unused_handle (); + + if (fd < 0) + { + set_errno (ENMFILE); + } + else + { + debug_printf ("socket (%d, %d, %d)", af, type, protocol); + + soc = socket (AF_INET, type, 0); + + if (soc == INVALID_SOCKET) + { + set_winsock_errno (); + goto done; + } + + soc = duplicate_socket (soc); + + const char *name; + if (af == AF_INET) + name = (type == SOCK_STREAM ? "/dev/tcp" : "/dev/udp"); + else + name = (type == SOCK_STREAM ? "/dev/streamsocket" : "/dev/dgsocket"); + + fdsock (fd, name, soc); + res = fd; + fhandler_socket *h = (fhandler_socket *) dtable[fd]; + + h->set_addr_family (af); + } + +done: + syscall_printf ("%d = socket (%d, %d, %d)", res, af, type, protocol); + ReleaseResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK," socket"); + return res; +} + +/* cygwin internal: map sockaddr into internet domain address */ + +static int get_inet_addr (const struct sockaddr *in, int inlen, + struct sockaddr_in *out, int *outlen) +{ + if (in->sa_family == AF_INET) + { + *out = * (sockaddr_in *)in; + *outlen = inlen; + return 1; + } + else if (in->sa_family == AF_UNIX) + { + sockaddr_in sin; + char buf[32]; + + memset (buf, 0, sizeof buf); + int fd = open (in->sa_data, O_RDONLY); + if (fd == -1) + return 0; + if (read (fd, buf, sizeof buf) == -1) + return 0; + sin.sin_family = AF_INET; + sscanf (buf + strlen (SOCKET_COOKIE), "%hu", &sin.sin_port); + sin.sin_port = htons (sin.sin_port); + sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + *out = sin; + *outlen = sizeof sin; + return 1; + } + else + { + set_errno (EAFNOSUPPORT); + return 0; + } +} + +/* exported as sendto: standards? */ +extern "C" +int +cygwin_sendto (int fd, + const void *buf, + int len, + unsigned int flags, + const struct sockaddr *to, + int tolen) +{ + fhandler_socket *h = (fhandler_socket *) dtable[fd]; + sockaddr_in sin; + + if (get_inet_addr (to, tolen, &sin, &tolen) == 0) + return -1; + + int res = sendto (h->get_socket (), (const char *) buf, len, + flags, to, tolen); + if (res == SOCKET_ERROR) + { + set_winsock_errno (); + res = -1; + } + return res; +} + +/* exported as recvfrom: standards? */ +extern "C" +int +cygwin_recvfrom (int fd, + char *buf, + int len, + int flags, + struct sockaddr *from, + int *fromlen) +{ + fhandler_socket *h = (fhandler_socket *) dtable[fd]; + + debug_printf ("recvfrom %d", h->get_socket ()); + + int res = recvfrom (h->get_socket (), buf, len, flags, from, fromlen); + if (res == SOCKET_ERROR) + { + set_winsock_errno (); + res = -1; + } + + return res; +} + +/* Cygwin internal */ +fhandler_socket * +get (int fd) +{ + if (dtable.not_open (fd)) + { + set_errno (EINVAL); + return 0; + } + + return dtable[fd]->is_socket (); +} + +/* exported as setsockopt: standards? */ +extern "C" +int +cygwin_setsockopt (int fd, + int level, + int optname, + const void *optval, + int optlen) +{ + fhandler_socket *h = get (fd); + int res = -1; + const char *name = "error"; + + if (h) + { + /* For the following debug_printf */ + switch (optname) + { + case SO_DEBUG: + name="SO_DEBUG"; + break; + case SO_ACCEPTCONN: + name="SO_ACCEPTCONN"; + break; + case SO_REUSEADDR: + name="SO_REUSEADDR"; + break; + case SO_KEEPALIVE: + name="SO_KEEPALIVE"; + break; + case SO_DONTROUTE: + name="SO_DONTROUTE"; + break; + case SO_BROADCAST: + name="SO_BROADCAST"; + break; + case SO_USELOOPBACK: + name="SO_USELOOPBACK"; + break; + case SO_LINGER: + name="SO_LINGER"; + break; + case SO_OOBINLINE: + name="SO_OOBINLINE"; + break; + } + + res = setsockopt (h->get_socket (), level, optname, + (const char *) optval, optlen); + + if (optlen == 4) + syscall_printf ("setsockopt optval=%x", *(long *) optval); + + if (res) + set_winsock_errno (); + } + + syscall_printf ("%d = setsockopt (%d, %d, %x (%s), %x, %d)", + res, fd, level, optname, name, optval, optlen); + return res; +} + +/* exported as getsockopt: standards? */ +extern "C" +int +cygwin_getsockopt (int fd, + int level, + int optname, + void *optval, + int *optlen) +{ + fhandler_socket *h = get (fd); + int res = -1; + const char *name = "error"; + if (h) + { + /* For the following debug_printf */ + switch (optname) + { + case SO_DEBUG: + name="SO_DEBUG"; + break; + case SO_ACCEPTCONN: + name="SO_ACCEPTCONN"; + break; + case SO_REUSEADDR: + name="SO_REUSEADDR"; + break; + case SO_KEEPALIVE: + name="SO_KEEPALIVE"; + break; + case SO_DONTROUTE: + name="SO_DONTROUTE"; + break; + case SO_BROADCAST: + name="SO_BROADCAST"; + break; + case SO_USELOOPBACK: + name="SO_USELOOPBACK"; + break; + case SO_LINGER: + name="SO_LINGER"; + break; + case SO_OOBINLINE: + name="SO_OOBINLINE"; + break; + } + + res = getsockopt (h->get_socket (), level, optname, + (char *) optval, (int *) optlen); + + if (res) + set_winsock_errno (); + } + + syscall_printf ("%d = getsockopt (%d, %d, %x (%s), %x, %d)", + res, fd, level, optname, name, optval, optlen); + return res; +} + +/* exported as connect: standards? */ +extern "C" +int +cygwin_connect (int fd, + const struct sockaddr *name, + int namelen) +{ + int res; + fhandler_socket *sock = get (fd); + sockaddr_in sin; + + if (get_inet_addr (name, namelen, &sin, &namelen) == 0) + return -1; + + if (!sock) + { + res = -1; + } + else + { + res = connect (sock->get_socket (), (sockaddr *) &sin, namelen); + if (res) + set_winsock_errno (); + } + return res; +} + +/* exported as getservbyname: standards? */ +extern "C" +struct servent * +cygwin_getservbyname (const char *name, const char *proto) +{ + struct servent *p = getservbyname (name, proto); + if (!p) + set_winsock_errno (); + + syscall_printf ("%x = getservbyname (%s, %s)", p, name, proto); + return p; +} + +/* exported as getservbyport: standards? */ +extern "C" +struct servent * +cygwin_getservbyport (int port, const char *proto) +{ + struct servent *p = getservbyport (port, proto); + if (!p) + set_winsock_errno (); + + syscall_printf ("%x = getservbyport (%d, %s)", p, port, proto); + return p; +} + +extern "C" +int +cygwin_gethostname (char *name, size_t len) +{ + int PASCAL win32_gethostname(char*,int); + + if (wsock32_handle == NULL || + win32_gethostname (name, len) == SOCKET_ERROR) + { + DWORD local_len = len; + + if (!GetComputerNameA (name, &local_len)) + { + set_winsock_errno (); + return -1; + } + } + debug_printf ("name %s\n", name); + h_errno = 0; + return 0; +} + +/* exported as gethostbyname: standards? */ +extern "C" +struct hostent * +cygwin_gethostbyname (const char *name) +{ + static unsigned char tmp_addr[4]; + static struct hostent tmp; + static char *tmp_aliases[1] = {0}; + static char *tmp_addr_list[2] = {0,0}; + static int a, b, c, d; + if (sscanf(name, "%d.%d.%d.%d", &a, &b, &c, &d) == 4) + { + /* In case you don't have DNS, at least x.x.x.x still works */ + memset(&tmp, 0, sizeof(tmp)); + tmp_addr[0] = a; + tmp_addr[1] = b; + tmp_addr[2] = c; + tmp_addr[3] = d; + tmp_addr_list[0] = (char *)tmp_addr; + tmp.h_name = name; + tmp.h_aliases = tmp_aliases; + tmp.h_addrtype = 2; + tmp.h_length = 4; + tmp.h_addr_list = tmp_addr_list; + return &tmp; + } + + struct hostent *ptr = gethostbyname (name); + if (!ptr) + { + set_winsock_errno (); + set_host_errno (); + } + else + { + debug_printf ("h_name %s", ptr->h_name); + h_errno = 0; + } + return ptr; +} + +/* exported as accept: standards? */ +extern "C" +int +cygwin_accept (int fd, struct sockaddr *peer, int *len) +{ + int res = -1; + + fhandler_socket *sock = get (fd); + if (sock) + { + /* accept on NT fails if len < sizeof (sockaddr_in) + * some programs set len to + * sizeof(name.sun_family) + strlen(name.sun_path) for UNIX domain + */ + if (len && ((unsigned) *len < sizeof (struct sockaddr_in))) + *len = sizeof (struct sockaddr_in); + + res = accept (sock->get_socket (), peer, len); // can't use a blocking call inside a lock + + SetResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK," accept"); + + int res_fd = dtable.find_unused_handle (); + if (res_fd == -1) + { + /* FIXME: what is correct errno? */ + set_errno (EMFILE); + goto done; + } + if ((SOCKET) res == (SOCKET) INVALID_SOCKET) + set_winsock_errno (); + else + { + res = duplicate_socket (res); + + fdsock (res_fd, sock->get_name (), res); + res = res_fd; + } + } +done: + syscall_printf ("%d = accept (%d, %x, %x)", res, fd, peer, len); + ReleaseResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK," accept"); + return res; +} + +/* exported as bind: standards? */ +extern "C" +int +cygwin_bind (int fd, struct sockaddr *my_addr, int addrlen) +{ + int res = -1; + + fhandler_socket *sock = get (fd); + if (sock) + { + if (my_addr->sa_family == AF_UNIX) + { +#define un_addr ((struct sockaddr_un *) my_addr) + struct sockaddr_in sin; + int len = sizeof sin; + int fd; + + if (strlen (un_addr->sun_path) >= UNIX_PATH_LEN) + { + set_errno (ENAMETOOLONG); + goto out; + } + sin.sin_family = AF_INET; + sin.sin_port = 0; + sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + if (bind (sock->get_socket (), (sockaddr *) &sin, len)) + { + syscall_printf ("AF_UNIX: bind failed %d", get_errno ()); + set_winsock_errno (); + goto out; + } + if (getsockname (sock->get_socket (), (sockaddr *) &sin, &len)) + { + syscall_printf ("AF_UNIX: getsockname failed %d", get_errno ()); + set_winsock_errno (); + goto out; + } + + sin.sin_port = ntohs (sin.sin_port); + debug_printf ("AF_UNIX: socket bound to port %u", sin.sin_port); + + /* bind must fail if file system socket object already exists + so _open() is called with O_EXCL flag. */ + fd = _open (un_addr->sun_path, + O_WRONLY | O_CREAT | O_EXCL | O_BINARY, + 0); + if (fd < 0) + { + if (get_errno () == EEXIST) + set_errno (EADDRINUSE); + goto out; + } + + char buf[sizeof (SOCKET_COOKIE) + 10]; + __small_sprintf (buf, "%s%u", SOCKET_COOKIE, sin.sin_port); + len = strlen (buf) + 1; + + /* Note that the terminating nul is written. */ + if (_write (fd, buf, len) != len) + { + save_errno here; + _close (fd); + _unlink (un_addr->sun_path); + } + else + { + _close (fd); + chmod (un_addr->sun_path, + (S_IFSOCK | S_IRWXU | S_IRWXG | S_IRWXO) & ~myself->umask); + res = 0; + } +#undef un_addr + } + else if (bind (sock->get_socket (), my_addr, addrlen)) + set_winsock_errno (); + else + res = 0; + } + +out: + syscall_printf ("%d = bind (%d, %x, %d)", res, fd, my_addr, addrlen); + return res; +} + +/* exported as getsockname: standards? */ +extern "C" +int +cygwin_getsockname (int fd, struct sockaddr *addr, int *namelen) +{ + int res = -1; + + fhandler_socket *sock = get (fd); + if (sock) + { + res = getsockname (sock->get_socket (), addr, namelen); + if (res) + set_winsock_errno (); + + } + syscall_printf ("%d = getsockname (%d, %x, %d)", res, fd, addr, namelen); + return res; +} + +/* exported as gethostbyaddr: standards? */ +extern "C" +struct hostent * +cygwin_gethostbyaddr (const char *addr, int len, int type) +{ + struct hostent *ptr = gethostbyaddr (addr, len, type); + if (!ptr) + { + set_winsock_errno (); + set_host_errno (); + } + else + { + debug_printf ("h_name %s", ptr->h_name); + h_errno = 0; + } + return ptr; +} + +/* exported as listen: standards? */ +extern "C" +int +cygwin_listen (int fd, int backlog) +{ + int res = -1; + + + fhandler_socket *sock = get (fd); + if (sock) + { + res = listen (sock->get_socket (), backlog); + if (res) + set_winsock_errno (); + } + syscall_printf ("%d = listen (%d, %d)", res, fd, backlog); + return res; +} + +/* exported as shutdown: standards? */ +extern "C" +int +cygwin_shutdown (int fd, int how) +{ + int res = -1; + + + fhandler_socket *sock = get (fd); + if (sock) + { + res = shutdown (sock->get_socket (), how); + if (res) + set_winsock_errno (); + } + syscall_printf ("%d = shutdown (%d, %d)", res, fd, how); + return res; +} + +/* exported as herror: standards? */ +extern "C" +void +cygwin_herror (const char *p) +{ + debug_printf ("********%d*************", __LINE__); +} + +/* exported as getpeername: standards? */ +extern "C" +int +cygwin_getpeername (int fd, struct sockaddr *name, int *len) +{ + fhandler_socket *h = (fhandler_socket *) dtable[fd]; + + debug_printf ("getpeername %d", h->get_socket ()); + int res = getpeername (h->get_socket (), name, len); + if (res) + set_winsock_errno (); + + debug_printf ("%d = getpeername %d", res, h->get_socket ()); + return res; +} + +/* exported as recv: standards? */ +extern "C" +int +cygwin_recv (int fd, void *buf, int len, unsigned int flags) +{ + fhandler_socket *h = (fhandler_socket *) dtable[fd]; + + int res = recv (h->get_socket (), (char *) buf, len, flags); + if (res == SOCKET_ERROR) + { + set_winsock_errno (); + res = -1; + } + +#if 0 + if (res > 0 && res < 200) + for (int i=0; i < res; i++) + system_printf ("%d %x %c", i, ((char *) buf)[i], ((char *) buf)[i]); +#endif + + syscall_printf ("%d = recv (%d, %x, %x, %x)", res, fd, buf, len, flags); + + return res; +} + +/* exported as send: standards? */ +extern "C" +int +cygwin_send (int fd, const void *buf, int len, unsigned int flags) +{ + fhandler_socket *h = (fhandler_socket *) dtable[fd]; + + int res = send (h->get_socket (), (const char *) buf, len, flags); + if (res == SOCKET_ERROR) + { + set_winsock_errno (); + res = -1; + } + + syscall_printf ("%d = send (%d, %x, %d, %x)", res, fd, buf, len, flags); + + return res; +} + +/* getdomainname: standards? */ +extern "C" +int +getdomainname (char *domain, int len) +{ + /* + * This works for Win95 only if the machine is configured to use MS-TCP. + * If a third-party TCP is being used this will fail. + * FIXME: On Win95, is there a way to portably check the TCP stack + * in use and include paths for the Domain name in each ? + * Punt for now and assume MS-TCP on Win95. + */ + reg_key r (HKEY_LOCAL_MACHINE, KEY_READ, + (os_being_run != winNT) ? "System" : "SYSTEM", + "CurrentControlSet", "Services", + (os_being_run != winNT) ? "MSTCP" : "Tcpip", + NULL); + + /* FIXME: Are registry keys case sensitive? */ + if (r.error () || r.get_string ("Domain", domain, len, "") != ERROR_SUCCESS) + { + __seterrno (); + return -1; + } + + return 0; +} + +/* Cygwin internal */ +/* Fill out an ifconf struct. + * + * Windows NT: + * Look at the Bind value in + * HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Linkage\ + * This is a REG_MULTI_SZ with strings of the form: + * \Device\, where netcard is the name of the net device. + * Then look under: + * HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\\ + * Parameters\Tcpip + * at the IPAddress, Subnetmask and DefaultGateway values for the + * required values. + * + * Windows 9x: + * We originally just did a gethostbyname, assuming that it's pretty + * unlikely Win9x will ever have more than one netcard. When this + * succeeded, we got the interface plus a loopback. + * Currently, we read all + * "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Class\NetTrans\*" + * entries from the Registry and use all entries that have legal + * "IPAddress" and "IPMask" values. + */ +static int +get_ifconf (struct ifconf *ifc, int what) +{ + if (os_being_run == winNT) + { + HKEY key; + DWORD type, size; + unsigned long lip, lnp; + int cnt = 1; + char *binding = (char *) 0; + struct sockaddr_in *sa; + + /* Union maps buffer to correct struct */ + struct ifreq *ifr = ifc->ifc_req; + + /* Ensure we have space for two struct ifreqs, fail if not. */ + if (ifc->ifc_len < (int) (2 * sizeof (struct ifreq))) + { + set_errno (EFAULT); + return -1; + } + + /* Set up interface lo0 first */ + strcpy (ifr->ifr_name, "lo0"); + memset (&ifr->ifr_addr, '\0', sizeof (ifr->ifr_addr)); + switch (what) + { + case SIOCGIFCONF: + case SIOCGIFADDR: + sa = (struct sockaddr_in *) &ifr->ifr_addr; + sa->sin_addr.s_addr = htonl (INADDR_LOOPBACK); + break; + case SIOCGIFBRDADDR: + lip = htonl (INADDR_LOOPBACK); + lnp = cygwin_inet_addr ("255.0.0.0"); + sa = (struct sockaddr_in *) &ifr->ifr_broadaddr; + sa->sin_addr.s_addr = lip & lnp | ~lnp; + break; + case SIOCGIFNETMASK: + sa = (struct sockaddr_in *) &ifr->ifr_netmask; + sa->sin_addr.s_addr = cygwin_inet_addr ("255.0.0.0"); + break; + default: + set_errno (EINVAL); + return -1; + } + sa->sin_family = AF_INET; + sa->sin_port = 0; + + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, + "SYSTEM\\" + "CurrentControlSet\\" + "Services\\" + "Tcpip\\" + "Linkage", + 0, KEY_READ, &key) == ERROR_SUCCESS) + { + if (RegQueryValueEx (key, "Bind", + NULL, &type, + NULL, &size) == ERROR_SUCCESS) + { + binding = (char *) alloca (size); + if (RegQueryValueEx (key, "Bind", + NULL, &type, + (unsigned char *) binding, + &size) != ERROR_SUCCESS) + { + binding = NULL; + } + } + RegCloseKey (key); + } + + if (binding) + { + char *bp, eth[2]; + char cardkey[256], ipaddress[256], netmask[256]; + + eth[0] = '/'; + eth[1] = '\0'; + for (bp = binding; *bp; bp += strlen(bp) + 1) + { + bp += strlen ("\\Device\\"); + strcpy (cardkey, "SYSTEM\\CurrentControlSet\\Services\\"); + strcat (cardkey, bp); + strcat (cardkey, "\\Parameters\\Tcpip"); + + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, cardkey, + 0, KEY_READ, &key) != ERROR_SUCCESS) + continue; + + if (RegQueryValueEx (key, "IPAddress", + NULL, &type, + (unsigned char *) &ipaddress, + (size = 256, &size)) == ERROR_SUCCESS + && RegQueryValueEx (key, "SubnetMask", + NULL, &type, + (unsigned char *) &netmask, + (size = 256, &size)) == ERROR_SUCCESS) + { + char *ip, *np; + char sub[2]; + char dhcpaddress[256], dhcpnetmask[256]; + + sub[0] = '/'; + sub[1] = '\0'; + if (strncmp (bp, "NdisWan", 7)) + ++*eth; + for (ip = ipaddress, np = netmask; + *ip && *np; + ip += strlen (ip) + 1, np += strlen (np) + 1) + { + if ((caddr_t) ++ifr > ifc->ifc_buf + + ifc->ifc_len + - sizeof (struct ifreq)) + break; + + if (! strncmp (bp, "NdisWan", 7)) + { + strcpy (ifr->ifr_name, "ppp"); + strcat (ifr->ifr_name, bp + 7); + } + else + { + strcpy (ifr->ifr_name, "eth"); + strcat (ifr->ifr_name, eth); + } + ++*sub; + if (*sub >= '1') + strcat (ifr->ifr_name, sub); + memset (&ifr->ifr_addr, '\0', sizeof ifr->ifr_addr); + if (cygwin_inet_addr (ip) == 0L + && RegQueryValueEx (key, "DhcpIPAddress", + NULL, &type, + (unsigned char *) &dhcpaddress, + (size = 256, &size)) + == ERROR_SUCCESS + && RegQueryValueEx (key, "DhcpSubnetMask", + NULL, &type, + (unsigned char *) &dhcpnetmask, + (size = 256, &size)) + == ERROR_SUCCESS) + { + switch (what) + { + case SIOCGIFCONF: + case SIOCGIFADDR: + sa = (struct sockaddr_in *) &ifr->ifr_addr; + sa->sin_addr.s_addr = + cygwin_inet_addr (dhcpaddress); + break; + case SIOCGIFBRDADDR: + lip = cygwin_inet_addr (dhcpaddress); + lnp = cygwin_inet_addr (dhcpnetmask); + sa = (struct sockaddr_in *) &ifr->ifr_broadaddr; + sa->sin_addr.s_addr = lip & lnp | ~lnp; + break; + case SIOCGIFNETMASK: + sa = (struct sockaddr_in *) &ifr->ifr_netmask; + sa->sin_addr.s_addr = + cygwin_inet_addr (dhcpnetmask); + break; + } + } + else + { + switch (what) + { + case SIOCGIFCONF: + case SIOCGIFADDR: + sa = (struct sockaddr_in *) &ifr->ifr_addr; + sa->sin_addr.s_addr = cygwin_inet_addr (ip); + break; + case SIOCGIFBRDADDR: + lip = cygwin_inet_addr (ip); + lnp = cygwin_inet_addr (np); + sa = (struct sockaddr_in *) &ifr->ifr_broadaddr; + sa->sin_addr.s_addr = lip & lnp | ~lnp; + break; + case SIOCGIFNETMASK: + sa = (struct sockaddr_in *) &ifr->ifr_netmask; + sa->sin_addr.s_addr = cygwin_inet_addr (np); + break; + } + } + sa->sin_family = AF_INET; + sa->sin_port = 0; + ++cnt; + } + } + RegCloseKey (key); + } + } + + /* Set the correct length */ + ifc->ifc_len = cnt * sizeof (struct ifreq); + } + else /* Windows 9x */ + { + HKEY key, subkey; + FILETIME update; + LONG res; + DWORD type, size; + unsigned long lip, lnp; + char ifname[256], ip[256], np[256]; + int cnt = 1; + struct sockaddr_in *sa; + + /* Union maps buffer to correct struct */ + struct ifreq *ifr = ifc->ifc_req; + char eth[2]; + + eth[0] = '/'; + eth[1] = '\0'; + + /* Ensure we have space for two struct ifreqs, fail if not. */ + if (ifc->ifc_len < (int) (2 * sizeof (struct ifreq))) + { + set_errno (EFAULT); + return -1; + } + + /* Set up interface lo0 first */ + strcpy (ifr->ifr_name, "lo0"); + memset (&ifr->ifr_addr, '\0', sizeof ifr->ifr_addr); + switch (what) + { + case SIOCGIFCONF: + case SIOCGIFADDR: + sa = (struct sockaddr_in *) &ifr->ifr_addr; + sa->sin_addr.s_addr = htonl (INADDR_LOOPBACK); + break; + case SIOCGIFBRDADDR: + lip = htonl(INADDR_LOOPBACK); + lnp = cygwin_inet_addr ("255.0.0.0"); + sa = (struct sockaddr_in *) &ifr->ifr_broadaddr; + sa->sin_addr.s_addr = lip & lnp | ~lnp; + break; + case SIOCGIFNETMASK: + sa = (struct sockaddr_in *) &ifr->ifr_netmask; + sa->sin_addr.s_addr = cygwin_inet_addr ("255.0.0.0"); + break; + default: + set_errno (EINVAL); + return -1; + } + sa->sin_family = AF_INET; + sa->sin_port = 0; + + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, + "SYSTEM\\" + "CurrentControlSet\\" + "Services\\" + "Class\\" + "NetTrans", + 0, KEY_READ, &key) == ERROR_SUCCESS) + { + for (int i = 0; + (res = RegEnumKeyEx (key, i, ifname, + (size = sizeof ifname, &size), + 0, 0, 0, &update)) != ERROR_NO_MORE_ITEMS; + ++i) + { + if (res != ERROR_SUCCESS + || RegOpenKeyEx (key, ifname, 0, + KEY_READ, &subkey) != ERROR_SUCCESS) + continue; + if (RegQueryValueEx (subkey, "IPAddress", 0, + &type, (unsigned char *) ip, + (size = sizeof ip, &size)) == ERROR_SUCCESS + || RegQueryValueEx (subkey, "IPMask", 0, + &type, (unsigned char *) np, + (size = sizeof np, &size)) == ERROR_SUCCESS) + { + if ((caddr_t)++ifr > ifc->ifc_buf + + ifc->ifc_len + - sizeof(struct ifreq)) + break; + ++*eth; + strcpy (ifr->ifr_name, "eth"); + strcat (ifr->ifr_name, eth); + switch (what) + { + case SIOCGIFCONF: + case SIOCGIFADDR: + sa = (struct sockaddr_in *) &ifr->ifr_addr; + sa->sin_addr.s_addr = cygwin_inet_addr (ip); + break; + case SIOCGIFBRDADDR: + lip = cygwin_inet_addr (ip); + lnp = cygwin_inet_addr (np); + sa = (struct sockaddr_in *) &ifr->ifr_broadaddr; + sa->sin_addr.s_addr = lip & lnp | ~lnp; + break; + case SIOCGIFNETMASK: + sa = (struct sockaddr_in *) &ifr->ifr_netmask; + sa->sin_addr.s_addr = cygwin_inet_addr (np); + break; + } + sa->sin_family = AF_INET; + sa->sin_port = 0; + ++cnt; + } + RegCloseKey (subkey); + } + } + + /* Set the correct length */ + ifc->ifc_len = cnt * sizeof (struct ifreq); + } + + return 0; +} + +/* exported as rcmd: standards? */ +extern "C" +int +cygwin_rcmd (char **ahost, unsigned short inport, char *locuser, + char *remuser, char *cmd, int *fd2p) +{ + int res = -1; + SOCKET fd2s; + + int res_fd = dtable.find_unused_handle (); + if (res_fd == -1) + goto done; + + if (fd2p) + { + *fd2p = dtable.find_unused_handle (res_fd + 1); + if (*fd2p == -1) + goto done; + } + + res = rcmd (ahost, inport, locuser, remuser, cmd, fd2p? &fd2s: NULL); + if (res == (int) INVALID_SOCKET) + goto done; + else + { + res = duplicate_socket (res); + + fdsock (res_fd, "/dev/tcp", res); + res = res_fd; + } + if (fd2p) + { + fd2s = duplicate_socket (fd2s); + + fdsock (*fd2p, "/dev/tcp", fd2s); + } +done: + syscall_printf ("%d = rcmd (...)", res); + return res; +} + +/* exported as rresvport: standards? */ +extern "C" +int +cygwin_rresvport (int *port) +{ + int res = -1; + + int res_fd = dtable.find_unused_handle (); + if (res_fd == -1) + goto done; + res = rresvport (port); + + if (res == (int) INVALID_SOCKET) + goto done; + else + { + res = duplicate_socket (res); + + fdsock (res_fd, "/dev/tcp", res); + res = res_fd; + } +done: + syscall_printf ("%d = rresvport (%d)", res, port ? *port : 0); + return res; +} + +/* exported as rexec: standards? */ +extern "C" +int +cygwin_rexec (char **ahost, unsigned short inport, char *locuser, + char *password, char *cmd, int *fd2p) +{ + int res = -1; + SOCKET fd2s; + + int res_fd = dtable.find_unused_handle (); + if (res_fd == -1) + goto done; + if (fd2p) + { + *fd2p = dtable.find_unused_handle (res_fd + 1); + if (*fd2p == -1) + goto done; + } + res = rexec (ahost, inport, locuser, password, cmd, fd2p ? &fd2s : NULL); + if (res == (int) INVALID_SOCKET) + goto done; + else + { + res = duplicate_socket (res); + + fdsock (res_fd, "/dev/tcp", res); + res = res_fd; + } + if (fd2p) + { + fd2s = duplicate_socket (fd2s); + + fdsock (*fd2p, "/dev/tcp", fd2s); +#if 0 /* ??? */ + fhandler_socket *h; + p->hmap.vec[*fd2p].h = h = + new (&p->hmap.vec[*fd2p].item) fhandler_socket (fd2s, "/dev/tcp"); +#endif + } +done: + syscall_printf ("%d = rexec (...)", res); + return res; +} + +/* socketpair: standards? */ +/* Win32 supports AF_INET only, so ignore domain and protocol arguments */ +extern "C" +int +socketpair (int, int type, int, int *sb) +{ + int res = -1; + SOCKET insock, outsock, newsock; + struct sockaddr_in sock_in; + int len = sizeof (sock_in); + + SetResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK," socketpair"); + + sb[0] = dtable.find_unused_handle (); + if (sb[0] == -1) + { + set_errno (EMFILE); + goto done; + } + sb[1] = dtable.find_unused_handle (sb[0] + 1); + if (sb[1] == -1) + { + set_errno (EMFILE); + goto done; + } + + /* create a listening socket */ + newsock = socket (AF_INET, type, 0); + if (newsock == INVALID_SOCKET) + { + set_winsock_errno (); + goto done; + } + + /* bind the socket to any unused port */ + sock_in.sin_family = AF_INET; + sock_in.sin_port = 0; + sock_in.sin_addr.s_addr = INADDR_ANY; + + if (bind (newsock, (struct sockaddr *) &sock_in, sizeof (sock_in)) < 0) + { + set_winsock_errno (); + closesocket (newsock); + goto done; + } + + if (getsockname (newsock, (struct sockaddr *) &sock_in, &len) < 0) + { + debug_printf ("getsockname error"); + set_winsock_errno (); + closesocket (newsock); + goto done; + } + + listen (newsock, 2); + + /* create a connecting socket */ + outsock = socket (AF_INET, type, 0); + if (outsock == INVALID_SOCKET) + { + debug_printf ("can't create outsock"); + set_winsock_errno (); + closesocket (newsock); + goto done; + } + + sock_in.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + + /* Do a connect and accept the connection */ + if (connect (outsock, (struct sockaddr *) &sock_in, + sizeof (sock_in)) < 0) + { + debug_printf ("connect error"); + set_winsock_errno (); + closesocket (newsock); + closesocket (outsock); + goto done; + } + + insock = accept (newsock, (struct sockaddr *) &sock_in, &len); + if (insock == INVALID_SOCKET) + { + debug_printf ("accept error"); + set_winsock_errno (); + closesocket (newsock); + closesocket (outsock); + goto done; + } + + closesocket (newsock); + res = 0; + + insock = duplicate_socket (insock); + + fdsock (sb[0], "/dev/tcp", insock); + + outsock = duplicate_socket (outsock); + fdsock (sb[1], "/dev/tcp", outsock); + +done: + syscall_printf ("%d = socketpair (...)", res); + ReleaseResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK," socketpair"); + return res; +} + +/**********************************************************************/ +/* fhandler_socket */ + +fhandler_socket::fhandler_socket (const char *name) : + fhandler_base (FH_SOCKET, name) +{ + set_cb (sizeof *this); + number_of_sockets++; +} + +/* sethostent: standards? */ +extern "C" +void +sethostent (int) +{ +} + +/* endhostent: standards? */ +extern "C" +void +endhostent (void) +{ +} + +fhandler_socket::~fhandler_socket () +{ + if (--number_of_sockets < 0) + { + number_of_sockets = 0; + system_printf("socket count < 0"); + } +} + +int +fhandler_socket::read (void *ptr, size_t len) +{ + int res = recv (get_socket (), (char *) ptr, len, 0); + if (res == SOCKET_ERROR) + { + set_winsock_errno (); + } + return res; +} + +int +fhandler_socket::write (const void *ptr, size_t len) +{ + int res = send (get_socket (), (const char *) ptr, len, 0); + if (res == SOCKET_ERROR) + { + set_winsock_errno (); + if (get_errno () == ECONNABORTED || get_errno () == ECONNRESET) + _raise (SIGPIPE); + } + return res; +} + +/* Cygwin internal */ +int +fhandler_socket::close () +{ + int res = 0; + + if (closesocket (get_socket ())) + { + set_winsock_errno (); + res = -1; + } + + return res; +} + +/* Cygwin internal */ +/* + * Return the flags settings for an interface. + */ +static int +get_if_flags (struct ifreq *ifr) +{ + struct sockaddr_in *sa = (struct sockaddr_in *) &ifr->ifr_addr; + + short flags = IFF_NOTRAILERS | IFF_UP | IFF_RUNNING; + if (sa->sin_addr.s_addr == INADDR_LOOPBACK) + flags |= IFF_LOOPBACK; + else + flags |= IFF_BROADCAST; + + ifr->ifr_flags = flags; + return 0; +} + +#define ASYNC_MASK (FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT) + +/* Cygwin internal */ +int +fhandler_socket::ioctl (unsigned int cmd, void *p) +{ + int res; + struct ifconf *ifc; + struct ifreq *ifr; + + switch (cmd) + { + case SIOCGIFCONF: + ifc = (struct ifconf *) p; + if (ifc == 0) + { + set_errno (EINVAL); + return -1; + } + res = get_ifconf (ifc, cmd); + if (res) + debug_printf ("error in get_ifconf\n"); + break; + case SIOCGIFFLAGS: + ifr = (struct ifreq *) p; + if (ifr == 0) + { + set_errno (EINVAL); + return -1; + } + res = get_if_flags (ifr); + break; + case SIOCGIFBRDADDR: + case SIOCGIFNETMASK: + case SIOCGIFADDR: + { + char buf[2048]; + struct ifconf ifc; + ifc.ifc_len = sizeof(buf); + ifc.ifc_buf = buf; + struct ifreq *ifrp; + + struct ifreq *ifr = (struct ifreq *) p; + if (ifr == 0) + { + debug_printf("ifr == NULL\n"); + set_errno (EINVAL); + return -1; + } + + res = get_ifconf (&ifc, cmd); + if (res) + { + debug_printf ("error in get_ifconf\n"); + break; + } + + debug_printf(" name: %s\n", ifr->ifr_name); + for (ifrp = ifc.ifc_req; + (caddr_t) ifrp < ifc.ifc_buf + ifc.ifc_len; + ++ifrp) + { + debug_printf("testname: %s\n", ifrp->ifr_name); + if (! strcmp (ifrp->ifr_name, ifr->ifr_name)) + { + switch (cmd) + { + case SIOCGIFADDR: + ifr->ifr_addr = ifrp->ifr_addr; + break; + case SIOCGIFBRDADDR: + ifr->ifr_broadaddr = ifrp->ifr_broadaddr; + break; + case SIOCGIFNETMASK: + ifr->ifr_netmask = ifrp->ifr_netmask; + break; + } + break; + } + } + if ((caddr_t) ifrp >= ifc.ifc_buf + ifc.ifc_len) + { + set_errno (EINVAL); + return -1; + } + break; + } + case FIOASYNC: + res = WSAAsyncSelect (get_socket (), gethwnd (), WM_ASYNCIO, + *(int *) p ? ASYNC_MASK : 0); + syscall_printf ("Async I/O on socket %s", + *(int *) p ? "started" : "cancelled"); + set_async (*(int *) p); + break; + default: + /* We must cancel WSAAsyncSelect (if any) before settting socket to + * blocking mode + */ + if (cmd == FIONBIO && *(int *) p == 0) + WSAAsyncSelect (get_socket (), gethwnd (), 0, 0); + res = ioctlsocket (get_socket (), cmd, (unsigned long *) p); + if (res == SOCKET_ERROR) + set_winsock_errno (); + if (cmd == FIONBIO) + { + syscall_printf ("socket is now %sblocking", + *(int *) p ? "un" : ""); + /* Start AsyncSelect if async socket unblocked */ + if (*(int *) p && get_async ()) + WSAAsyncSelect (get_socket (), gethwnd (), WM_ASYNCIO, ASYNC_MASK); + } + break; + } + syscall_printf ("%d = ioctl_socket (%x, %x)", res, cmd, p); + return res; +} + +/* Initialize WinSock */ +LoadDLLinitfunc (wsock32) +{ + WSADATA p; + int res; + HANDLE h; + + if ((h = LoadLibrary ("wsock32.dll")) != NULL) + wsock32_handle = h; + else if (!wsock32_handle) + api_fatal ("could not load wsock32.dll. Is TCP/IP installed?"); + else + return 0; /* Already done by another thread? */ + + res = WSAStartup ((2<<8) | 2, &p); + + debug_printf ("res %d", res); + debug_printf ("wVersion %d", p.wVersion); + debug_printf ("wHighVersion %d", p.wHighVersion); + debug_printf ("szDescription %s",p.szDescription); + debug_printf ("szSystemStatus %s",p.szSystemStatus); + debug_printf ("iMaxSockets %d", p.iMaxSockets); + debug_printf ("iMaxUdpDg %d", p.iMaxUdpDg); + debug_printf ("lpVendorInfo %d", p.lpVendorInfo); + + if (FIONBIO != REAL_FIONBIO) + debug_printf ("**************** FIONBIO != REAL_FIONBIO"); + + return 0; +} + +LoadDLLinit (wsock32) + +LoadDLLfunc (WSAAsyncSelect, WSAAsyncSelect@16, wsock32) +LoadDLLfunc (WSACleanup, WSACleanup@0, wsock32) +LoadDLLfunc (WSAGetLastError, WSAGetLastError@0, wsock32) +LoadDLLfunc (WSAStartup, WSAStartup@8, wsock32) +LoadDLLfunc (__WSAFDIsSet, __WSAFDIsSet@8, wsock32) +LoadDLLfunc (accept, accept@12, wsock32) +LoadDLLfunc (bind, bind@12, wsock32) +LoadDLLfunc (closesocket, closesocket@4, wsock32) +LoadDLLfunc (connect, connect@12, wsock32) +LoadDLLfunc (gethostbyaddr, gethostbyaddr@12, wsock32) +LoadDLLfunc (gethostbyname, gethostbyname@4, wsock32) +LoadDLLfunc (gethostname, gethostname@8, wsock32) +LoadDLLfunc (getpeername, getpeername@12, wsock32) +LoadDLLfunc (getprotobyname, getprotobyname@4, wsock32) +LoadDLLfunc (getprotobynumber, getprotobynumber@4, wsock32) +LoadDLLfunc (getservbyname, getservbyname@8, wsock32) +LoadDLLfunc (getservbyport, getservbyport@8, wsock32) +LoadDLLfunc (getsockname, getsockname@12, wsock32) +LoadDLLfunc (getsockopt, getsockopt@20, wsock32) +LoadDLLfunc (inet_addr, inet_addr@4, wsock32) +LoadDLLfunc (inet_ntoa, inet_ntoa@4, wsock32) +LoadDLLfunc (ioctlsocket, ioctlsocket@12, wsock32) +LoadDLLfunc (listen, listen@8, wsock32) +LoadDLLfunc (rcmd, rcmd@24, wsock32) +LoadDLLfunc (recv, recv@16, wsock32) +LoadDLLfunc (recvfrom, recvfrom@24, wsock32) +LoadDLLfunc (rexec, rexec@24, wsock32) +LoadDLLfunc (rresvport, rresvport@4, wsock32) +LoadDLLfunc (select, select@20, wsock32) +LoadDLLfunc (send, send@16, wsock32) +LoadDLLfunc (sendto, sendto@24, wsock32) +LoadDLLfunc (setsockopt, setsockopt@20, wsock32) +LoadDLLfunc (shutdown, shutdown@8, wsock32) +LoadDLLfunc (socket, socket@12, wsock32) diff --git a/winsup/cygwin/ntea.cc b/winsup/cygwin/ntea.cc new file mode 100644 index 000000000..278eb771f --- /dev/null +++ b/winsup/cygwin/ntea.cc @@ -0,0 +1,335 @@ +/* ntea.cc: code for manipulating NTEA information + + Copyright 1997, 1998, 2000 Cygnus Solutions. + + Written by Sergey S. Okhapkin (sos@prospect.com.ru) + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include + +/* Default to not using NTEA information */ +BOOL allow_ntea = FALSE; + +/* +From Windows NT DDK: + +FILE_FULL_EA_INFORMATION provides extended attribute information. +This structure is used primarily by network drivers. + +Members + +NextEntryOffset +The offset of the next FILE_FULL_EA_INFORMATION-type entry. This member is +zero if no other entries follow this one. + +Flags +Can be zero or can be set with FILE_NEED_EA, indicating that the file to which +the EA belongs cannot be interpreted without understanding the associated +extended attributes. + +EaNameLength +The length in bytes of the EaName array. This value does not include a +zero-terminator to EaName. + +EaValueLength +The length in bytes of each EA value in the array. + +EaName +An array of characters naming the EA for this entry. + +Comments +This structure is longword-aligned. If a set of FILE_FULL_EA_INFORMATION +entries is buffered, NextEntryOffset value in each entry, except the last, +falls on a longword boundary. +The value(s) associated with each entry follows the EaName array. That is, an +EA's values are located at EaName + (EaNameLength + 1). +*/ + +typedef struct _FILE_FULL_EA_INFORMATION { + ULONG NextEntryOffset; + UCHAR Flags; + UCHAR EaNameLength; + USHORT EaValueLength; + CHAR EaName[1]; +} FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION; + +/* Functions prototypes */ + +int NTReadEA (const char *file, const char *attrname, char *buf, int len); +static PFILE_FULL_EA_INFORMATION NTReadEARaw (HANDLE file, int *len); +BOOL NTWriteEA(const char *file, const char *attrname, char *buf, int len); + +/* + * NTReadEA - read file's Extended Attribute. + * + * Parameters: + * file - pointer to filename + * attrname- pointer to EA name (case insensitivy. EAs are sored in upper + * case). + * attrbuf - pointer to buffer to store EA's value. + * len - length of attrbuf. + * Return value: + * 0 - if file or attribute "attrname" not found. + * N - number of bytes stored in attrbuf if succes. + * -1 - attrbuf too small for EA value. + */ + +int __stdcall +NTReadEA (const char *file, const char *attrname, char *attrbuf, int len) +{ + /* return immediately if NTEA usage is turned off */ + if (! allow_ntea) + return FALSE; + + HANDLE hFileSource; + int eafound = 0; + PFILE_FULL_EA_INFORMATION ea, sea; + int easize; + + hFileSource = CreateFile (file, FILE_READ_EA, + FILE_SHARE_READ | FILE_SHARE_WRITE, + &sec_none_nih, // sa + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL + ); + + if (hFileSource == INVALID_HANDLE_VALUE) + return 0; + + /* Read in raw array of EAs */ + ea = sea = NTReadEARaw (hFileSource, &easize); + + /* Search for requested attribute */ + while (sea) + { + if (strcasematch (ea->EaName, attrname)) /* EA found */ + { + if (ea->EaValueLength > len) + { + eafound = -1; /* buffer too small */ + break; + } + memcpy (attrbuf, ea->EaName + (ea->EaNameLength + 1), + ea->EaValueLength); + eafound = ea->EaValueLength; + break; + } + if ((ea->NextEntryOffset == 0) || ((int) ea->NextEntryOffset > easize)) + break; + ea = (PFILE_FULL_EA_INFORMATION) ((char *) ea + ea->NextEntryOffset); + } + + if (sea) + free (sea); + CloseHandle (hFileSource); + + return eafound; +} + +/* + * NTReadEARaw - internal routine to read EAs array to malloced buffer. The + * caller should free this buffer after usage. + * Parameters: + * hFileSource - handle to file. This handle should have FILE_READ_EA + * rights. + * len - pointer to int variable where length of buffer will + * be stored. + * Return value: + * pointer to buffer with file's EAs, or NULL if any error occured. + */ + +static +PFILE_FULL_EA_INFORMATION +NTReadEARaw (HANDLE hFileSource, int *len) +{ + WIN32_STREAM_ID StreamId; + DWORD dwBytesWritten; + LPVOID lpContext; + DWORD StreamSize; + PFILE_FULL_EA_INFORMATION eafound = NULL; + + lpContext = NULL; + StreamSize = sizeof (WIN32_STREAM_ID) - sizeof (WCHAR**); + + /* Read the WIN32_STREAM_ID in */ + + while (BackupRead (hFileSource, (LPBYTE) &StreamId, StreamSize, + &dwBytesWritten, + FALSE, // don't abort yet + FALSE, // don't process security + &lpContext)) + { + DWORD sl,sh; + + if (dwBytesWritten == 0) /* No more Stream IDs */ + break; + /* skip StreamName */ + if (StreamId.dwStreamNameSize) + { + unsigned char *buf; + buf = (unsigned char *) malloc (StreamId.dwStreamNameSize); + + if (buf == NULL) + break; + + if (!BackupRead (hFileSource, buf, // buffer to read + StreamId.dwStreamNameSize, // num bytes to read + &dwBytesWritten, + FALSE, // don't abort yet + FALSE, // don't process security + &lpContext)) // Stream name read error + { + free (buf); + break; + } + free (buf); + } + + /* Is it EA stream? */ + if (StreamId.dwStreamId == BACKUP_EA_DATA) + { + unsigned char *buf; + buf = (unsigned char *) malloc (StreamId.Size.LowPart); + + if (buf == NULL) + break; + if (!BackupRead (hFileSource, buf, // buffer to read + StreamId.Size.LowPart, // num bytes to write + &dwBytesWritten, + FALSE, // don't abort yet + FALSE, // don't process security + &lpContext)) + { + free (buf); /* EA read error */ + break; + } + eafound = (PFILE_FULL_EA_INFORMATION) buf; + *len = StreamId.Size.LowPart; + break; + } + /* Skip current stream */ + if (!BackupSeek (hFileSource, + StreamId.Size.LowPart, + StreamId.Size.HighPart, + &sl, + &sh, + &lpContext)) + break; + } + + /* free context */ + BackupRead ( + hFileSource, + NULL, // buffer to write + 0, // number of bytes to write + &dwBytesWritten, + TRUE, // abort + FALSE, // don't process security + &lpContext); + + return eafound; +} + +/* + * NTWriteEA - write file's Extended Attribute. + * + * Parameters: + * file - pointer to filename + * attrname- pointer to EA name (case insensitivy. EAs are sored in upper + * case). + * buf - pointer to buffer with EA value. + * len - length of buf. + * Return value: + * TRUE if success, FALSE otherwice. + * Note: if len=0 given EA will be deleted. + */ + +BOOL __stdcall +NTWriteEA (const char *file, const char *attrname, char *buf, int len) +{ + /* return immediately if NTEA usage is turned off */ + if (! allow_ntea) + return TRUE; + + HANDLE hFileSource; + WIN32_STREAM_ID StreamId; + DWORD dwBytesWritten; + LPVOID lpContext; + DWORD StreamSize, easize; + BOOL bSuccess=FALSE; + PFILE_FULL_EA_INFORMATION ea; + + hFileSource = CreateFile (file, FILE_WRITE_EA, + FILE_SHARE_READ | FILE_SHARE_WRITE, + &sec_none_nih, // sa + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + + if (hFileSource == INVALID_HANDLE_VALUE) + return FALSE; + + lpContext = NULL; + StreamSize = sizeof (WIN32_STREAM_ID) - sizeof (WCHAR**); + + /* FILE_FULL_EA_INFORMATION structure is longword-aligned */ + easize = sizeof (*ea) - sizeof (WCHAR**) + strlen (attrname) + 1 + len + + (sizeof (DWORD) - 1); + easize &= ~(sizeof (DWORD) - 1); + + if ((ea = (PFILE_FULL_EA_INFORMATION) malloc (easize)) == NULL) + goto cleanup; + + memset (ea, 0, easize); + ea->EaNameLength = strlen (attrname); + ea->EaValueLength = len; + strcpy (ea->EaName, attrname); + memcpy (ea->EaName + (ea->EaNameLength + 1), buf, len); + + StreamId.dwStreamId = BACKUP_EA_DATA; + StreamId.dwStreamAttributes = 0; + StreamId.Size.HighPart = 0; + StreamId.Size.LowPart = easize; + StreamId.dwStreamNameSize = 0; + + if (!BackupWrite (hFileSource, (LPBYTE) &StreamId, StreamSize, + &dwBytesWritten, + FALSE, // don't abort yet + FALSE, // don't process security + &lpContext)) + goto cleanup; + + if (!BackupWrite (hFileSource, (LPBYTE) ea, easize, + &dwBytesWritten, + FALSE, // don't abort yet + FALSE, // don't process security + &lpContext)) + goto cleanup; + + bSuccess = TRUE; + /* free context */ + +cleanup: + BackupRead (hFileSource, + NULL, // buffer to write + 0, // number of bytes to write + &dwBytesWritten, + TRUE, // abort + FALSE, // don't process security + &lpContext); + + CloseHandle (hFileSource); + if (ea) + free (ea); + + return bSuccess; +} diff --git a/winsup/cygwin/passwd.cc b/winsup/cygwin/passwd.cc new file mode 100644 index 000000000..51c5450b4 --- /dev/null +++ b/winsup/cygwin/passwd.cc @@ -0,0 +1,275 @@ +/* passwd.cc: getpwnam () and friends + + Copyright 1996, 1997, 1998 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include +#include "winsup.h" + +/* Read /etc/passwd only once for better performance. This is done + on the first call that needs information from it. */ + +static struct passwd *passwd_buf = NULL; /* passwd contents in memory */ +static int curr_lines = 0; +static int max_lines = 0; + +/* Set to 1 when /etc/passwd has been read in by read_etc_passwd (). */ +/* Functions in this file need to check the value of passwd_in_memory_p + and read in the password file if it isn't set. */ +static int passwd_in_memory_p = 0; + +/* Position in the passwd cache */ +#ifdef _MT_SAFE +#define pw_pos _reent_winsup()->_pw_pos +#else +static int pw_pos = 0; +#endif + +/* Remove a : teminated string from the buffer, and increment the pointer */ +static char * +grab_string (char **p) +{ + char *src = *p; + char *res = src; + + while (*src && *src != ':' && *src != '\n') + src++; + + if (*src == ':') + { + *src = 0; + src++; + } + *p = src; + return res; +} + +/* same, for ints */ +static int +grab_int (char **p) +{ + char *src = *p; + int val = atoi (src); + while (*src && *src != ':' && *src != '\n') + src++; + if (*src == ':') + src++; + *p = src; + return val; +} + +/* Parse /etc/passwd line into passwd structure. */ +void +parse_pwd (struct passwd &res, char *buf) +{ + /* Allocate enough room for the passwd struct and all the strings + in it in one go */ + size_t len = strlen (buf); + char *mybuf = (char *) malloc (len + 1); + (void) memcpy (mybuf, buf, len + 1); + if (mybuf[--len] == '\n') + mybuf[len] = '\0'; + + res.pw_name = strlwr(grab_string (&mybuf)); + res.pw_passwd = grab_string (&mybuf); + res.pw_uid = grab_int (&mybuf); + res.pw_gid = grab_int (&mybuf); + res.pw_comment = 0; + res.pw_gecos = grab_string (&mybuf); + res.pw_dir = grab_string (&mybuf); + res.pw_shell = grab_string (&mybuf); +} + +/* Add one line from /etc/passwd into the password cache */ +static void +add_pwd_line (char *line) +{ + if (curr_lines >= max_lines) + { + max_lines += 10; + passwd_buf = (struct passwd *) realloc (passwd_buf, max_lines * sizeof (struct passwd)); + } + parse_pwd (passwd_buf[curr_lines++], line); +} + +/* Read in /etc/passwd and save contents in the password cache. + This sets passwd_in_memory_p to 1 so functions in this file can + tell that /etc/passwd has been read in */ +static void +read_etc_passwd () +{ + extern int passwd_sem; + char linebuf[1024]; + ++passwd_sem; + FILE *f = fopen ("/etc/passwd", "r"); + --passwd_sem; + + if (f) + { + while (fgets (linebuf, sizeof (linebuf), f) != NULL) + { + if (strlen (linebuf)) + add_pwd_line (linebuf); + } + + fclose (f); + } + else + { + debug_printf ("Emulating /etc/passwd"); + char user_name [ MAX_USER_NAME ]; + DWORD user_name_len = MAX_USER_NAME; + if (! GetUserNameA (user_name, &user_name_len)) + { + strncpy (user_name, "Administrator", MAX_USER_NAME); + debug_printf ("Failed to get current user name. %E"); + } + snprintf (linebuf, sizeof (linebuf), "%s::%u:%u::%s:/bin/sh", user_name, + DEFAULT_UID, DEFAULT_GID, getenv ("HOME") ?: "/"); + add_pwd_line (linebuf); + } + passwd_in_memory_p = 1; +} + +/* Cygwin internal */ +static struct passwd * +search_for (uid_t uid, const char *name) +{ + struct passwd *res = 0; + struct passwd *default_pw = 0; + + for (int i = 0; i < curr_lines; i++) + { + res = passwd_buf + i; + if (res->pw_uid == DEFAULT_UID) + default_pw = res; + /* on Windows NT user names are case-insensitive */ + if (name) + { + if (strcasematch (name, res->pw_name)) + return res; + } + else if (uid == res->pw_uid) + return res; + } + + return default_pw; +} + +extern "C" +struct passwd * +getpwuid (uid_t uid) +{ + if (!passwd_in_memory_p) + read_etc_passwd(); + + return search_for (uid, 0); +} + +extern "C" +struct passwd * +getpwnam (const char *name) +{ + if (!passwd_in_memory_p) + read_etc_passwd(); + + return search_for (0, name); +} + +extern "C" +struct passwd * +getpwent (void) +{ + if (!passwd_in_memory_p) + read_etc_passwd(); + + if (pw_pos < curr_lines) + return passwd_buf + pw_pos++; + + return NULL; +} + +extern "C" +struct passwd * +getpwduid (uid_t uid) +{ + if (!passwd_in_memory_p) + read_etc_passwd(); + + return NULL; +} + +extern "C" +void +setpwent (void) +{ + if (!passwd_in_memory_p) + read_etc_passwd(); + + pw_pos = 0; +} + +extern "C" +void +endpwent (void) +{ + if (!passwd_in_memory_p) + read_etc_passwd(); + + pw_pos = 0; +} + +extern "C" +int +setpassent () +{ + if (!passwd_in_memory_p) + read_etc_passwd(); + + return 0; +} + +extern "C" +char * +getpass (const char * prompt) +{ +#ifdef _MT_SAFE + char *pass=_reent_winsup()->_pass; +#else + static char pass[_PASSWORD_LEN]; +#endif + struct termios ti, newti; + + if (!passwd_in_memory_p) + read_etc_passwd(); + + if (dtable.not_open (0)) + { + set_errno (EBADF); + pass[0] = '\0'; + } + else + { + fhandler_base *fhstdin = dtable[0]; + fhstdin->tcgetattr (&ti); + newti = ti; + newti.c_lflag &= ~ECHO; + fhstdin->tcsetattr (TCSANOW, &newti); + fputs (prompt, stderr); + fgets (pass, _PASSWORD_LEN, stdin); + fprintf (stderr, "\n"); + for (int i=0; pass[i]; i++) + if (pass[i] == '\r' || pass[i] == '\n') + pass[i] = '\0'; + fhstdin->tcsetattr (TCSANOW, &ti); + } + return pass; +} diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc new file mode 100644 index 000000000..8fcfb4633 --- /dev/null +++ b/winsup/cygwin/path.cc @@ -0,0 +1,2836 @@ +/* path.cc: path support. + + Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +/* This module's job is to + - convert between POSIX and Win32 style filenames, + - support the `mount' functionality, + - support symlinks for files and directories + + Pathnames are handled as follows: + + - / is equivalent to \ + - Paths beginning with // (or \\) are not translated (i.e. looked + up in the mount table) and are assumed to be UNC path names. + - Paths containing a : are not translated (paths like + /foo/bar/baz:qux: don't make much sense but having the rule written + this way allows one to use strchr). + + The goal in the above set of rules is to allow both POSIX and Win32 + flavors of pathnames without either interfering. The rules are + intended to be as close to a superset of both as possible. + + A possible future enhancement would be to allow people to + disable/enable the mount table handling to support pure Win32 + pathnames. Hopefully this won't be needed. The suggested way to + do this would be an environment variable because + a) we need something that is inherited from parent to child, + b) environment variables can be passed from the DOS shell to a + cygwin app, + c) it allows disabling the feature on an app by app basis within + the same session (whereas playing about with the registry wouldn't + -- without getting too complicated). Example: + CYGWIN=pathrules[=@]{win32,posix}. If CYGWIN=pathrules=win32, + mount table handling is disabled. [The intent is to have CYGWIN be + a catchall for tweaking various cygwin.dll features]. + + Note that you can have more than one path to a file. The mount + table is always prefered when translating Win32 paths to POSIX + paths. Win32 paths in mount table entries may be UNC paths or + standard Win32 paths starting with : + + In converting from a Win32 to a POSIX pathname, if there is no + mount point that will allow the conversion to take place, a user + mount point will be automatically created under + cygdrive/ and the translation will be redone, this + time successfully. + + Text vs Binary issues are not considered here in path style + decisions. + + / and \ are treated as equivalent. One or the other is prefered in + certain situations (e.g. / is preferred in result of getcwd, \ is + preferred in arguments to Win32 api calls), but this code will + translate as necessary. + + Apps wishing to translate to/from pure Win32 and POSIX-like + pathnames can use cygwin_foo. + + Removing mounted filesystem support would simplify things greatly, + but having it gives us a mechanism of treating disk that lives on a + UNIX machine as having UNIX semantics [it allows one to edit a text + file on that disk and not have cr's magically appear and perhaps + break apps running on UNIX boxes]. It also useful to be able to + layout a hierarchy without changing the underlying directories. + + The semantics of mounting file systems is not intended to precisely + follow normal UNIX systems. + + Each DOS drive is defined to have a current directory. Supporting + this would complicate things so for now things are defined so that + c: means c:\. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include "winsup.h" +#include + +static int symlink_check_one (const char *path, char *buf, int buflen, + DWORD& fileattr, unsigned *pflags, + const suffix_info *suffixes, + char *&found_suffix); +static int normalize_win32_path (const char *cwd, const char *src, char *dst); +static char *getcwd_inner (char *buf, size_t ulen, int posix_p); +static void slashify (const char *src, char *dst, int trailing_slash_p); +static void backslashify (const char *src, char *dst, int trailing_slash_p); +static int path_prefix_p_ (const char *path1, const char *path2, int len1); +static int get_current_directory_name (); + +static NO_COPY const char escape_char = '^'; + +/********************** Path Helper Functions *************************/ + +#define path_prefix_p(p1, p2, l1) \ + ((tolower(*(p1))==tolower(*(p2))) && \ + path_prefix_p_(p1, p2, l1)) + +#define SYMLINKATTR(x) \ + (((x) & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY)) == \ + FILE_ATTRIBUTE_SYSTEM) + +/* Return non-zero if PATH1 is a prefix of PATH2. + Both are assumed to be of the same path style and / vs \ usage. + Neither may be "". + LEN1 = strlen (PATH1). It's passed because often it's already known. + + Examples: + /foo/ is a prefix of /foo <-- may seem odd, but desired + /foo is a prefix of /foo/ + / is a prefix of /foo/bar + / is not a prefix of foo/bar + foo/ is a prefix foo/bar + /foo is not a prefix of /foobar +*/ + +/* Determine if path prefix matches current cygdrive */ +#define iscygdrive(path) \ + (path_prefix_p (cygwin_shared->mount.cygdrive, (path), cygwin_shared->mount.cygdrive_len)) + +#define iscygdrive_device(path) \ + (iscygdrive(path) && isalpha(path[cygwin_shared->mount.cygdrive_len]) && \ + (isdirsep(path[cygwin_shared->mount.cygdrive_len + 1]) || \ + !path[cygwin_shared->mount.cygdrive_len + 1])) + +/******************** Directory-related Support **************************/ + +/* Cache getcwd value. FIXME: We need a lock for these in order to + support multiple threads. */ + +#ifdef _MT_SAFE +#define current_directory_name _reent_winsup()->_current_directory_name +#define current_directory_posix_name _reent_winsup()->_current_directory_posix_name +#define current_directory_hash _reent_winsup()->_current_directory_hash +#else +static char *current_directory_name; +static char *current_directory_posix_name; +static unsigned long current_directory_hash; +#endif + +static int +path_prefix_p_ (const char *path1, const char *path2, int len1) +{ + /* Handle case where PATH1 has trailing '/' and when it doesn't. */ + if (len1 > 0 && SLASH_P (path1[len1 - 1])) + len1--; + + if (len1 == 0) + return SLASH_P (path2[0]) && !SLASH_P (path2[1]); + + if (!strncasematch (path1, path2, len1)) + return 0; + + return SLASH_P (path2[len1]) || path2[len1] == 0 || path1[len1 - 1] == ':'; +} + +/* Convert an arbitrary path SRC to a pure Win32 path, suitable for + passing to Win32 API routines. + + If an error occurs, `error' is set to the errno value. + Otherwise it is set to 0. + + follow_mode values: + SYMLINK_FOLLOW - convert to PATH symlink points to + SYMLINK_NOFOLLOW - convert to PATH of symlink itself + SYMLINK_IGNORE - do not check PATH for symlinks + SYMLINK_CONTENTS - just return symlink contents +*/ + +path_conv::path_conv (const char *src, symlink_follow follow_mode, + int use_full_path, const suffix_info *suffixes) +{ + /* This array is used when expanding symlinks. It is MAX_PATH * 2 + in length so that we can hold the expanded symlink plus a + trailer. */ + char work_buf[MAX_PATH * 3 + 3]; + char tmp_buf[MAX_PATH]; + char path_buf[MAX_PATH]; + + char *rel_path, *full_path; + + if ((error = check_null_empty_path (src))) + return; + + if (use_full_path) + rel_path = path_buf, full_path = this->path; + else + rel_path = this->path, full_path = path_buf; + + char *sym_buf = work_buf + MAX_PATH + 1; + /* This loop handles symlink expansion. */ + int loop = 0; + path_flags = 0; + known_suffix = NULL; + fileattr = (DWORD) -1; + for (;;) + { + MALLOC_CHECK; + /* Must look up path in mount table, etc. */ + error = cygwin_shared->mount.conv_to_win32_path (src, rel_path, + full_path, + devn, unit, &path_flags); + MALLOC_CHECK; + if (error != 0) + return; + if (devn != FH_BAD) + { + fileattr = 0; + return; + } + + /* Eat trailing slashes */ + char *tail = strchr (full_path, '\0'); + /* If path is only a drivename, Windows interprets it as + the current working directory on this drive instead of + the root dir which is what we want. So we need + the trailing backslash in this case. */ + while (tail > full_path + 3 && (*--tail == '\\')) + *tail = '\0'; + if (full_path[0] && full_path[1] == ':' && full_path[2] == '\0') + strcat (full_path, "\\"); + + if (follow_mode == SYMLINK_IGNORE) + { + fileattr = GetFileAttributesA (path); + goto out; + } + + /* Make a copy of the path that we can munge up */ + char path_copy[strlen (full_path) + 2]; + strcpy (path_copy, full_path); + + tail = path_copy + 1 + (tail - full_path); // Point to end of copy + + *sym_buf = '\0'; // Paranoid + + /* Scan path_copy from right to left looking either for a symlink + or an actual existing file. If an existing file is found, just + return. If a symlink is found exit the for loop. + Also: be careful to preserve the errno returned from + symlink_check_one as the caller may need it. */ + /* FIXME: Do we have to worry about multiple \'s here? */ + int component = 0; // Number of translated components + DWORD attr; + for (;;) + { + save_errno s (0); + unsigned dummy_flags, *fp; + const suffix_info *suff; + + /* Don't allow symlink_check_one to set anything in the path_conv + class if we're working on an inner component of the path */ + if (component) + { + fp = &dummy_flags; + suff = NULL; + } + else + { + fp = &path_flags; + suff = suffixes; + } + MALLOC_CHECK; + int len = symlink_check_one (path_copy, sym_buf, MAX_PATH, attr, + fp, suff, known_suffix); + MALLOC_CHECK; + + /* If symlink_check_one found an existing non-symlink file, then + it returns a length of 0 and sets errno to EINVAL. It also sets + any suffix found into `sym_buf'. */ + if (!len && get_errno () == EINVAL) + { + if (component == 0) + { + fileattr = attr; + if (follow_mode == SYMLINK_CONTENTS) + goto out; + else if (*sym_buf) + { + known_suffix = strchr (this->path, '\0'); + strcpy (known_suffix, sym_buf); + } + else if (known_suffix) + known_suffix = this->path + (known_suffix - path_copy); + } + goto out; // file found + } + /* Found a symlink if len > 0. If component == 0, then the + src path itself was a symlink. If !follow_mode then + we're done. Otherwise we have to insert the path found + into the full path that we are building and perform all of + these operations again on the newly derived path. */ + else if (len > 0) + { + if (component == 0) + { + if (follow_mode != SYMLINK_FOLLOW) + { + set_symlink (); // last component of path's a symlink. + fileattr = attr; + if (follow_mode == SYMLINK_CONTENTS) + strcpy (path, sym_buf); + goto out; + } + } + break; + } + + s.reset (); // remember errno from symlink_check_one + + if (!(tail = strrchr (path_copy, '\\')) || + (tail > path_copy && tail[-1] == ':')) + goto out; // all done + + /* Haven't found a valid pathname component yet. + Pinch off the tail and try again. */ + *tail = '\0'; + component++; + } + + /* Arrive here if above loop detected a symlink. */ + if (++loop > MAX_LINK_DEPTH) + { + error = ELOOP; // Eep. + return; + } + MALLOC_CHECK; + + tail = full_path + (tail - path_copy); + int taillen = strlen (tail); + int buflen = strlen (sym_buf); + if (buflen + taillen > MAX_PATH) + { + error = ENAMETOOLONG; + strcpy (path, "::ENAMETOOLONG::"); + return; + } + + /* Copy tail of full_path to discovered symlink. */ + char *p; + for (p = sym_buf + buflen; *tail; tail++) + *p++ = *tail == '\\' ? '/' : *tail; + *p = '\0'; + + /* If symlink referred to an absolute path, then we + just use sym_buf and loop. Otherwise tack the head of + path_copy before sym_buf and translate it back from a + Win32-style path to a POSIX-style one. */ + if (isabspath (sym_buf)) + src = sym_buf; + else if (!(tail = strrchr (path_copy, '\\'))) + system_printf ("problem parsing %s - '%s'", src, full_path); + else + { + int headlen = 1 + tail - path_copy; + p = sym_buf - headlen; + memcpy (p, path_copy, headlen); + MALLOC_CHECK; + error = cygwin_shared->mount.conv_to_posix_path (p, tmp_buf, 1); + MALLOC_CHECK; + if (error) + return; + src = tmp_buf; + } + } +out: + DWORD serial, volflags; + + char root[strlen(full_path) + 10]; + strcpy (root, full_path); + if (!rootdir (root) || + !GetVolumeInformation (root, NULL, 0, &serial, NULL, &volflags, NULL, 0)) + set_has_acls (FALSE); + else + set_has_acls (volflags & FS_PERSISTENT_ACLS); +} + +#define deveq(s) (strcasematch (name, (s))) +#define deveqn(s, n) (strncasematch (name, (s), (n))) + +static __inline int +digits (const char *name) +{ + char *p; + int n = strtol(name, &p, 10); + + return p > name && !*p ? n : -1; +} + +const char *windows_device_names[] = +{ + NULL, + "\\dev\\console", + "conin", + "conout", + "\\dev\\ttym", + "\\dev\\tty%d", + "\\dev\\ptym", + "\\\\.\\com%d", + "\\dev\\pipe", + "\\dev\\piper", + "\\dev\\pipew", + "\\dev\\socket", + "\\dev\\windows", + + NULL, NULL, NULL, + + "\\dev\\disk", + "\\dev\\fd%d", + "\\dev\\st%d", + "nul", + "\\dev\\zero", +}; + +static int +get_raw_device_number (const char *uxname, const char *w32path, int &unit) +{ + DWORD devn = FH_BAD; + + if (strncasecmp (w32path, "\\\\.\\tape", 8) == 0) + { + devn = FH_TAPE; + unit = digits (w32path + 8); + // norewind tape devices have leading n in name + if (! strncasecmp (uxname, "/dev/n", 6)) + unit += 128; + } + else if (isalpha (w32path[4]) && w32path[5] == ':') + { + devn = FH_FLOPPY; + unit = tolower (w32path[4]) - 'a'; + } + else if (strncasecmp (w32path, "\\\\.\\physicaldrive", 17) == 0) + { + devn = FH_FLOPPY; + unit = digits (w32path + 17) + 128; + } + return devn; +} + +int __stdcall +get_device_number (const char *name, int &unit, BOOL from_conv) +{ + DWORD devn = FH_BAD; + unit = 0; + + if ((*name == '/' && deveqn ("/dev/", 5)) || + (*name == '\\' && deveqn ("\\dev\\", 5))) + { + name += 5; + if (deveq ("tty")) + { + if (tty_attached (myself)) + { + unit = myself->ctty; + devn = FH_TTYS; + } + else if (myself->ctty > 0) + devn = FH_CONSOLE; + } + else if (deveqn ("tty", 3) && (unit = digits (name + 3)) >= 0) + devn = FH_TTYS; + else if (deveq ("ttym")) + devn = FH_TTYM; + else if (deveq ("ptmx")) + devn = FH_PTYM; + else if (deveq ("windows")) + devn = FH_WINDOWS; + else if (deveq ("conin")) + devn = FH_CONIN; + else if (deveq ("conout")) + devn = FH_CONOUT; + else if (deveq ("null")) + devn = FH_NULL; + else if (deveq ("zero")) + devn = FH_ZERO; + else if (deveqn ("com", 3) && (unit = digits (name + 3)) >= 0) + devn = FH_SERIAL; + else if (deveq ("pipe") || deveq ("piper") || deveq ("pipew")) + devn = FH_PIPE; + else if (deveq ("tcp") || deveq ("udp") || deveq ("streamsocket") + || deveq ("dgsocket")) + devn = FH_SOCKET; + else if (! from_conv) + devn = get_raw_device_number (name - 5, + path_conv (name - 5, + SYMLINK_IGNORE).get_win32 (), + unit); + } + else if (deveqn ("com", 3) && (unit = digits (name + 3)) >= 0) + devn = FH_SERIAL; + + return devn; +} + +/* Return TRUE if src_path is a Win32 device name, filling out the device + name in win32_path */ + +static BOOL +win32_device_name (const char *src_path, char *win32_path, + DWORD &devn, int &unit) +{ + const char *devfmt; + + devn = get_device_number (src_path, unit, TRUE); + + if (devn == FH_BAD) + return FALSE; + + if ((devfmt = windows_device_names[FHDEVN (devn)]) == NULL) + return FALSE; + __small_sprintf (win32_path, devfmt, unit); + return TRUE; +} + +/* Normalize a POSIX path. + \'s are converted to /'s in the process. + All duplicate /'s, except for 2 leading /'s, are deleted. + The result is 0 for success, or an errno error value. */ + +static __inline int +normalize_posix_path (const char *cwd, const char *src, char *dst) +{ + const char *src_start = src; + char *dst_start = dst; + + if (! SLASH_P (src[0])) + { + if (strlen (cwd) + 1 + strlen (src) >= MAX_PATH) + { + debug_printf ("ENAMETOOLONG = normalize_posix_path (%s)", src); + return ENAMETOOLONG; + } + strcpy (dst, cwd); + dst = strchr (dst, '\0'); + if (dst > dst_start && !isdirsep(dst[-1])) + *dst++ = '/'; + } + /* Two leading /'s? If so, preserve them. */ + else if (SLASH_P (src[1])) + { + *dst++ = '/'; + *dst++ = '/'; + src += 2; + if (SLASH_P(*src)) + { /* Starts with three or more slashes - reset. */ + dst = dst_start; + *dst++ = '/'; + src = src_start + 1; + } + } + + while (*src) + { + /* Strip runs of /'s. */ + if (SLASH_P (*src)) + { + *dst++ = '/'; + src++; + while (SLASH_P(*src)) + src++; + } + /* Ignore "./". */ + else if (src[0] == '.' && SLASH_P (src[1]) + && (src == src_start || SLASH_P (src[-1]))) + { + src += 2; + while(SLASH_P(src[0])) + src++; + } + /* Backup if "..". */ + else if (src[0] == '.' && src[1] == '.' + /* dst must be greater than dst_start */ + && isdirsep (dst[-1]) + && (SLASH_P (src[2]) || src[2] == 0)) + { + /* Back up over /, but not if it's the first one. */ + if (dst > dst_start + 1) + dst--; + /* Now back up to the next /. */ + while (dst > dst_start + 1 && !isdirsep (dst[-1])) + dst--; + src += 2; + while (SLASH_P (*src)) + src++; + } + /* Otherwise, add char to result. */ + else + { + if (*src == '\\') + *dst++ = '/'; + else + *dst++ = *src; + ++src; + } + } + *dst = 0; + debug_printf ("%s = normalize_posix_path (%s)", dst_start, src_start); + return 0; +} + +/* Normalize a Win32 path. + /'s are converted to \'s in the process. + All duplicate \'s, except for 2 leading \'s, are deleted. + + The result is 0 for success, or an errno error value. + FIXME: A lot of this should be mergeable with the POSIX critter. */ + +static int +normalize_win32_path (const char *cwd, const char *src, char *dst) +{ + const char *src_start = src; + char *dst_start = dst; + + if (! SLASH_P (src[0]) + && strchr (src, ':') == NULL) + { + if (strlen (cwd) + 1 + strlen (src) >= MAX_PATH) + { + debug_printf ("ENAMETOOLONG = normalize_win32_path (%s)", src); + return ENAMETOOLONG; + } + strcpy (dst, cwd); + dst += strlen (dst); + *dst++ = '\\'; + } + /* Two leading \'s? If so, preserve them. */ + else if (SLASH_P (src[0]) && SLASH_P (src[1])) + { + *dst++ = '\\'; + ++src; + } + + while (*src) + { + /* Strip duplicate /'s. */ + if (SLASH_P (src[0]) && SLASH_P (src[1])) + src++; + /* Ignore "./". */ + else if (src[0] == '.' && SLASH_P (src[1]) + && (src == src_start || SLASH_P (src[-1]))) + { + src += 2; + } + + /* Backup if "..". */ + else if (src[0] == '.' && src[1] == '.' + /* dst must be greater than dst_start */ + && dst[-1] == '\\' + && (SLASH_P (src[2]) || src[2] == 0)) + { + /* Back up over /, but not if it's the first one. */ + if (dst > dst_start + 1) + dst--; + /* Now back up to the next /. */ + while (dst > dst_start + 1 && dst[-1] != '\\' && dst[-2] != ':') + dst--; + src += 2; + if (SLASH_P (*src)) + src++; + } + /* Otherwise, add char to result. */ + else + { + if (*src == '/') + *dst++ = '\\'; + else + *dst++ = *src; + ++src; + } + } + *dst = 0; + debug_printf ("%s = normalize_win32_path (%s)", dst_start, src_start); + return 0; +} + + +/* Various utilities. */ + +/* slashify: Convert all back slashes in src path to forward slashes + in dst path. Add a trailing slash to dst when trailing_slash_p arg + is set to 1. */ + +static void +slashify (const char *src, char *dst, int trailing_slash_p) +{ + const char *start = src; + + while (*src) + { + if (*src == '\\') + *dst++ = '/'; + else + *dst++ = *src; + ++src; + } + if (trailing_slash_p + && src > start + && !isdirsep (src[-1])) + *dst++ = '/'; + *dst++ = 0; +} + +/* backslashify: Convert all forward slashes in src path to back slashes + in dst path. Add a trailing slash to dst when trailing_slash_p arg + is set to 1. */ + +static void +backslashify (const char *src, char *dst, int trailing_slash_p) +{ + const char *start = src; + + while (*src) + { + if (*src == '/') + *dst++ = '\\'; + else + *dst++ = *src; + ++src; + } + if (trailing_slash_p + && src > start + && !isdirsep (src[-1])) + *dst++ = '\\'; + *dst++ = 0; +} + +/* nofinalslash: Remove trailing / and \ from SRC (except for the + first one). It is ok for src == dst. */ + +void __stdcall +nofinalslash (const char *src, char *dst) +{ + int len = strlen (src); + if (src != dst) + memcpy (dst, src, len + 1); + while (len > 1 && SLASH_P (dst[--len])) + dst[len] = '\0'; +} + +/* slash_drive_prefix_p: Return non-zero if PATH begins with + //. */ + +static int +slash_drive_prefix_p (const char *path) +{ + return (isdirsep(path[0]) + && isdirsep(path[1]) + && isalpha (path[2]) + && (path[3] == 0 || path[3] == '/')); +} + +/* slash_unc_prefix_p: Return non-zero if PATH begins with //UNC/SHARE */ + +int __stdcall +slash_unc_prefix_p (const char *path) +{ + char *p = NULL; + int ret = (isdirsep (path[0]) + && isdirsep (path[1]) + && isalpha (path[2]) + && path[3] != 0 + && !isdirsep (path[3]) + && ((p = strchr(&path[3], '/')) != NULL)); + if (!ret || p == NULL) + return ret; + return ret && isalnum (p[1]); +} + +/* conv_path_list: Convert a list of path names to/from Win32/POSIX. + + SRC is not a const char * because we temporarily modify it to ease + the implementation. + + I believe Win32 always has '.' in $PATH. POSIX obviously doesn't. + We certainly don't want to handle that here, but it is something for + the caller to think about. */ + +static void +conv_path_list (const char *src, char *dst, int to_posix_p) +{ + char *s; + char *d = dst; + char src_delim = to_posix_p ? ';' : ':'; + char dst_delim = to_posix_p ? ':' : ';'; + int (*conv_fn) (const char *, char *) = (to_posix_p + ? cygwin_conv_to_posix_path + : cygwin_conv_to_win32_path); + + do + { + s = strchr (src, src_delim); + if (s) + { + *s = 0; + (*conv_fn) (src[0] != 0 ? src : ".", d); + d += strlen (d); + *d++ = dst_delim; + *s = src_delim; + src = s + 1; + } + else + { + /* Last one. */ + (*conv_fn) (src[0] != 0 ? src : ".", d); + } + } + while (s != NULL); +} + +/************************* mount_info class ****************************/ + +/* init: Initialize the mount table. */ + +void +mount_info::init () +{ + int found_slash = 0; + + nmounts = 0; + had_to_create_mount_areas = 0; + + /* Fetch the mount table and cygdrive-related information from + the registry. */ + from_registry (); + + /* If slash isn't already mounted, mount system directory as slash. */ + if (nmounts != 0) + for (int i = 0; i < nmounts; i++) + { + if (strcmp (mount[i].posix_path, "/") == 0) + { + found_slash = 1; + break; + } + } + + if (!found_slash) + mount_slash (); +} + +/* mount_slash: mount the system partition as slash. */ + +void +mount_info::mount_slash () +{ + char drivestring[MAX_PATH]; + GetSystemDirectory (drivestring, MAX_PATH); + drivestring[2] = 0; /* truncate path to ":" */ + + if (add_reg_mount (drivestring, "/", 0) == 0) + add_item (drivestring, "/", 0); +} + +/* conv_to_win32_path: Ensure src_path is a pure Win32 path and store + the result in win32_path. + + If win32_path != NULL, the relative path, if possible to keep, is + stored in win32_path. If the relative path isn't possible to keep, + the full path is stored. + + If full_win32_path != NULL, the full path is stored there. + + The result is zero for success, or an errno value. + + {,full_}win32_path must have sufficient space (i.e. MAX_PATH bytes). */ + +int +mount_info::conv_to_win32_path (const char *src_path, char *win32_path, + char *full_win32_path, DWORD &devn, int &unit, unsigned *flags) +{ + int src_path_len = strlen (src_path); + int trailing_slash_p = (src_path_len > 0 + && SLASH_P (src_path[src_path_len - 1])); + MALLOC_CHECK; + int isrelpath; + unsigned dummy_flags; + + devn = FH_BAD; + unit = 0; + + if (!flags) + flags = &dummy_flags; + + *flags = 0; + debug_printf ("conv_to_win32_path (%s)", src_path); + + if (src_path_len >= MAX_PATH) + { + debug_printf ("ENAMETOOLONG = conv_to_win32_path (%s)", src_path); + return ENAMETOOLONG; + } + + int i, rc; + char *dst = NULL; + mount_item *mi = NULL; /* initialized to avoid compiler warning */ + char pathbuf[MAX_PATH]; + + /* The rule is :'s can't appear in [our] POSIX path names so this is a safe + test; if ':' is present it already be in Win32 form. */ + if (strchr (src_path, ':') != NULL) + { + debug_printf ("%s already win32", src_path); + rc = normalize_win32_path ("", src_path, pathbuf); + if (rc) + return rc; + /* FIXME: Do we have to worry about trailing_slash_p here? */ + if (win32_path != NULL) + strcpy (win32_path, pathbuf); + if (full_win32_path != NULL) + strcpy (full_win32_path, pathbuf); + *flags = set_flags_from_win32_path (pathbuf); + goto out; + } + + /* Normalize the path, taking out ../../ stuff, we need to do this + so that we can move from one mounted directory to another with relative + stuff. + + eg mounting c:/foo /foo + d:/bar /bar + + cd /bar + ls ../foo + + should look in c:/foo, not d:/foo. + + We do this by first getting an absolute UNIX-style path and then + converting it to a DOS-style path, looking up the appropriate drive + in the mount table. */ + + char cwd[MAX_PATH]; + + /* No need to fetch cwd if path is absolute. */ + if ((isrelpath = ! SLASH_P (*src_path))) + getcwd_inner (cwd, MAX_PATH, TRUE); /* FIXME: check rc */ + else + strcpy (cwd, "/"); /* some innocuous value */ + + rc = normalize_posix_path (cwd, src_path, pathbuf); + MALLOC_CHECK; + if (rc != 0) + { + debug_printf ("%d = conv_to_win32_path (%s)", rc, src_path); + *flags = 0; + return rc; + } + nofinalslash (pathbuf, pathbuf); + + /* Determine where the destination should be placed. */ + if (full_win32_path != NULL) + dst = full_win32_path; + else if (win32_path != NULL) + dst = win32_path; + + if (dst == NULL) + goto out; /* Sanity check. */ + + /* See if this is a cygwin "device" */ + if (win32_device_name (pathbuf, dst, devn, unit)) + { + *flags = MOUNT_BINARY; /* FIXME: Is this a sensible default for devices? */ + goto fillin; + } + + /* Check if the cygdrive prefix was specified. If so, just strip + off the prefix and transform it into an MS-DOS path. */ + MALLOC_CHECK; + if (iscygdrive_device (pathbuf)) + { + if (!cygdrive_win32_path (pathbuf, dst, trailing_slash_p)) + return ENOENT; + *flags = cygdrive_flags; + goto fillin; + } + + /* Check the mount table for prefix matches. */ + for (i = 0; i < nmounts; i++) + { + mi = mount + posix_sorted[i]; + if (path_prefix_p (mi->posix_path, pathbuf, mi->posix_pathlen)) + break; + } + + if (i >= nmounts) + { + if (slash_drive_prefix_p (pathbuf)) + slash_drive_to_win32_path (pathbuf, dst, trailing_slash_p); + else + backslashify (src_path, dst, trailing_slash_p); /* just convert */ + *flags = 0; + } + else + { + int n = mi->native_pathlen; + memcpy (dst, mi->native_path, n); + char *p = pathbuf + mi->posix_pathlen; + if (!trailing_slash_p && !*p) + dst[n] = '\0'; + else + { + /* Do not add trailing \ to UNC device names like \\.\a: */ + if (*p != '/' && /* FIXME: this test seems wrong. */ + (strncmp (mi->native_path, "\\\\.\\", 4) != 0 || + strncmp (mi->native_path + 4, "UNC\\", 4) == 0)) + dst[n++] = '\\'; + strcpy (dst + n, p); + } + backslashify (dst, dst, trailing_slash_p); + *flags = mi->flags; + } + +fillin: + /* Compute relative path if asked to and able to. */ + unsigned cwdlen; + cwdlen = 0; /* avoid a (hopefully) bogus compiler warning */ + if (win32_path == NULL) + /* nothing to do */; + else if (isrelpath && + path_prefix_p (current_directory_name, dst, + cwdlen = strlen (current_directory_name))) + { + if (strlen (dst) == cwdlen) + dst += cwdlen; + else + dst += isdirsep (current_directory_name[cwdlen - 1]) ? cwdlen : cwdlen + 1; + + memmove (win32_path, dst, strlen (dst) + 1); + if (!*win32_path) + { + strcpy (win32_path, "."); + if (trailing_slash_p) + strcat (win32_path, "\\"); + } + } + else if (win32_path != dst) + strcpy (win32_path, dst); + +out: + MALLOC_CHECK; + debug_printf ("%s(rel), %s(abs) %p(flags) = conv_to_win32_path (%s)", + win32_path, full_win32_path, *flags, + src_path); + return 0; +} + +/* Convert PATH (for which slash_drive_prefix_p returns 1) to WIN32 form. */ + +void +mount_info::slash_drive_to_win32_path (const char *path, char *buf, + int trailing_slash_p) +{ + buf[0] = path[2]; + buf[1] = ':'; + if (path[3] == '0') + strcpy (buf + 2, "\\"); + else + backslashify (path + 3, buf + 2, trailing_slash_p); +} + +/* cygdrive_posix_path: Build POSIX path used as the + mount point for cygdrives created when there is no other way to + obtain a POSIX path from a Win32 one. */ + +void +mount_info::cygdrive_posix_path (const char *src, char *dst, int trailing_slash_p) +{ + int len = cygdrive_len; + + memcpy (dst, cygdrive, len + 1); + + /* Now finish the path off with the drive letter to be used. + The cygdrive prefix always ends with a trailing slash so + the drive letter is added after the path. */ + dst[len++] = tolower (src[0]); + if (!src[2]) + dst[len++] = '\000'; + else + { + dst[len++] = '/'; + strcpy (dst + len, src + 3); + } + slashify (dst, dst, trailing_slash_p); +} + +int +mount_info::cygdrive_win32_path (const char *src, char *dst, int trailing_slash_p) +{ + const char *p = src + cygdrive_len; + if (!isalpha (*p) || (!isdirsep (p[1]) && p[1])) + return 0; + dst[0] = *p; + dst[1] = ':'; + strcpy (dst + 2, p + 1); + backslashify (dst, dst, trailing_slash_p || !dst[2]); + debug_printf ("src '%s', dst '%s'", src, dst); + return 1; +} + +/* conv_to_posix_path: Ensure src_path is a POSIX path. + + The result is zero for success, or an errno value. + posix_path must have sufficient space (i.e. MAX_PATH bytes). + If keep_rel_p is non-zero, relative paths stay that way. */ + +int +mount_info::conv_to_posix_path (const char *src_path, char *posix_path, + int keep_rel_p) +{ + int src_path_len = strlen (src_path); + int trailing_slash_p = (src_path_len > 0 + && SLASH_P (src_path[src_path_len - 1])); + int relative_path_p = (! SLASH_P (*src_path) + && strchr (src_path, ':') == NULL); + + debug_printf ("conv_to_posix_path (%s, %s)", src_path, + keep_rel_p ? "keep-rel" : "no-keep-rel"); + MALLOC_CHECK; + + if (src_path_len >= MAX_PATH) + { + debug_printf ("ENAMETOOLONG"); + return ENAMETOOLONG; + } + + /* FIXME: For now, if the path is relative and it's supposed to stay + that way, skip mount table processing. */ + MALLOC_CHECK; + if (keep_rel_p && relative_path_p) + { + slashify (src_path, posix_path, 0); + debug_printf ("%s = conv_to_posix_path (%s)", posix_path, src_path); + return 0; + } + + char pathbuf[MAX_PATH]; + char cwd[MAX_PATH]; + + /* No need to fetch cwd if path is absolute. */ + if (relative_path_p) + getcwd_inner (cwd, MAX_PATH, 0); /* FIXME: check rc */ + else + strcpy (cwd, "/"); /* some innocuous value */ + MALLOC_CHECK; + int rc = normalize_win32_path (cwd, src_path, pathbuf); + MALLOC_CHECK; + if (rc != 0) + { + debug_printf ("%d = conv_to_posix_path (%s)", rc, src_path); + return rc; + } + nofinalslash (pathbuf, pathbuf); + MALLOC_CHECK; + + int pathbuflen = strlen (pathbuf); + for (int i = 0; i < nmounts; ++i) + { + mount_item &mi = mount[native_sorted[i]]; + if (! path_prefix_p (mi.native_path, pathbuf, mi.native_pathlen)) + continue; + + /* SRC_PATH is in the mount table. */ + int nextchar; + if (!pathbuf[mi.native_pathlen]) + nextchar = 0; + else if (isdirsep (pathbuf[mi.native_pathlen])) + nextchar = -1; + else + nextchar = 1; + + int addslash = nextchar > 0 ? 1 : 0; + if ((mi.posix_pathlen + (pathbuflen - mi.native_pathlen) + addslash) >= MAX_PATH) + return ENAMETOOLONG; + strcpy (posix_path, mi.posix_path); + if (addslash) + strcat (posix_path, "/"); + if (nextchar) + slashify (pathbuf + mi.native_pathlen, + posix_path + addslash + (mi.posix_pathlen == 1 ? 0 : mi.posix_pathlen), + trailing_slash_p); + goto out; + } + + /* Not in the database. This should [theoretically] only happen if either + the path begins with //, or / isn't mounted, or the path has a drive + letter not covered by the mount table. If it's a relative path then the + caller must want an absolute path (otherwise we would have returned + above). So we always return an absolute path at this point. */ + if ((isalpha (pathbuf[0])) && (pathbuf[1] == ':')) + cygdrive_posix_path (pathbuf, posix_path, trailing_slash_p && + pathbuflen > 3); + else + { + /* The use of src_path and not pathbuf here is intentional. + We couldn't translate the path, so just ensure no \'s are present. */ + slashify (src_path, posix_path, trailing_slash_p); + } + +out: + debug_printf ("%s = conv_to_posix_path (%s)", posix_path, src_path); + MALLOC_CHECK; + return 0; +} + +/* Return flags associated with a mount point given the win32 path. */ + +unsigned +mount_info::set_flags_from_win32_path (const char *p) +{ + for (int i = 0; i < nmounts; i++) + { + mount_item &mi = mount[native_sorted[i]]; + if (path_prefix_p (mi.native_path, p, mi.native_pathlen)) + return mi.flags; + } + return 0; +} + +/* read_mounts: Given a specific regkey, read mounts from under its + key. */ + +void +mount_info::read_mounts (reg_key& r) +{ + char posix_path[MAX_PATH]; + HKEY key = r.get_key (); + DWORD i, posix_path_size; + +loop: + for (i = 0; ;i++) + { + posix_path_size = MAX_PATH; + LONG err = RegEnumKeyEx (key, i, posix_path, &posix_path_size, NULL, + NULL, NULL, NULL); + + if (err != ERROR_SUCCESS) + break; + + if (iscygdrive (posix_path)) + { + /* This shouldn't be in the mount table. */ + (void) r.kill (posix_path); + goto loop; + } + } + + /* Loop through subkeys */ + /* FIXME: we would like to not check MAX_MOUNTS but the heap in the + shared area is currently statically allocated so we can't have an + arbitrarily large number of mounts. */ + for (DWORD i = 0; i < MAX_MOUNTS; i++) + { + char native_path[MAX_PATH]; + int mount_flags; + + posix_path_size = MAX_PATH; + /* FIXME: if maximum posix_path_size is 256, we're going to + run into problems if we ever try to store a mount point that's + over 256 but is under MAX_PATH! */ + LONG err = RegEnumKeyEx (key, i, posix_path, &posix_path_size, NULL, + NULL, NULL, NULL); + + if (err == ERROR_NO_MORE_ITEMS) + break; + else if (err != ERROR_SUCCESS) + { + debug_printf ("RegEnumKeyEx failed, error %d!\n", err); + break; + } + + if (iscygdrive (posix_path)) + { + /* This shouldn't be in the mount table. */ + // (void) r.kill (posix_path); + continue; + } + + /* Get a reg_key based on i. */ + reg_key subkey = reg_key (key, KEY_READ, posix_path, NULL); + + /* Check the mount table for prefix matches. */ + for (int j = 0; j < nmounts; j++) + if (strcasematch (mount[j].posix_path, posix_path)) + goto next; /* Can't have more than one */ + + /* Fetch info from the subkey. */ + subkey.get_string ("native", native_path, sizeof (native_path), ""); + mount_flags = subkey.get_int ("flags", 0); + + /* Add mount_item corresponding to registry mount point. */ + cygwin_shared->mount.add_item (native_path, posix_path, mount_flags); + next: + continue; + } +} + +/* from_registry: Build the entire mount table from the registry. Also, + read in cygdrive-related information from its registry location. */ + +void +mount_info::from_registry () +{ + /* Use current mount areas if either user or system mount areas + already exist. Otherwise, import old mounts. */ + + reg_key r; + + /* Retrieve cygdrive-related information. */ + read_cygdrive_info_from_registry (); + + nmounts = 0; + + /* First read mounts from user's table. */ + read_mounts (r); + + /* Then read mounts from system-wide mount table. */ + reg_key r1 (HKEY_LOCAL_MACHINE, KEY_READ, "SOFTWARE", + CYGWIN_INFO_CYGNUS_REGISTRY_NAME, + CYGWIN_INFO_CYGWIN_REGISTRY_NAME, + CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME, + NULL); + read_mounts (r1); + + /* If we had to create both user and system mount areas, import + old mounts. */ + if (had_to_create_mount_areas == 2) + import_v1_mounts (); + + sort (); +} + +/* add_reg_mount: Add mount item to registry. Return zero on success, + non-zero on failure. */ +/* FIXME: Need a mutex to avoid collisions with other tasks. */ + +int +mount_info::add_reg_mount (const char * native_path, const char * posix_path, unsigned mountflags) +{ + /* Add the mount to the right registry location, depending on + whether MOUNT_SYSTEM is set in the mount flags. */ + if (!(mountflags & MOUNT_SYSTEM)) /* current_user mount */ + { + /* reg_key for user mounts in HKEY_CURRENT_USER. */ + reg_key reg_user; + + /* Start by deleting existing mount if one exists. */ + reg_user.kill (posix_path); + + /* Create the new mount. */ + reg_key subkey = reg_key (reg_user.get_key (), + KEY_ALL_ACCESS, + posix_path, NULL); + subkey.set_string ("native", native_path); + subkey.set_int ("flags", mountflags); + } + else /* local_machine mount */ + { + /* reg_key for system mounts in HKEY_LOCAL_MACHINE. */ + reg_key reg_sys (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, "SOFTWARE", + CYGWIN_INFO_CYGNUS_REGISTRY_NAME, + CYGWIN_INFO_CYGWIN_REGISTRY_NAME, + CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME, + NULL); + + if (reg_sys.get_key () == INVALID_HANDLE_VALUE) + { + set_errno (EACCES); + return -1; + } + + /* Start by deleting existing mount if one exists. */ + reg_sys.kill (posix_path); + + /* Create the new mount. */ + reg_key subkey = reg_key (reg_sys.get_key (), + KEY_ALL_ACCESS, + posix_path, NULL); + subkey.set_string ("native", native_path); + subkey.set_int ("flags", mountflags); + } + + return 0; /* Success! */ +} + +/* del_reg_mount: delete mount item from registry indicated in flags. + Return zero on success, non-zero on failure.*/ +/* FIXME: Need a mutex to avoid collisions with other tasks. */ + +int +mount_info::del_reg_mount (const char * posix_path, unsigned flags) +{ + int killres; + + if ((flags & MOUNT_SYSTEM) == 0) /* Delete from user registry */ + { + reg_key reg_user (KEY_ALL_ACCESS, + CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME, NULL); + killres = reg_user.kill (posix_path); + } + else /* Delete from system registry */ + { + reg_key reg_sys (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, "SOFTWARE", + CYGWIN_INFO_CYGNUS_REGISTRY_NAME, + CYGWIN_INFO_CYGWIN_REGISTRY_NAME, + CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME, + NULL); + + if (reg_sys.get_key () == INVALID_HANDLE_VALUE) + { + set_errno (EACCES); + return -1; + } + + killres = reg_sys.kill (posix_path); + } + + if (killres != ERROR_SUCCESS) + { + __seterrno_from_win_error (killres); + return -1; + } + + return 0; /* Success! */ +} + +/* read_cygdrive_info_from_registry: Read the default prefix and flags + to use when creating cygdrives from the special user registry + location used to store cygdrive information. */ + +void +mount_info::read_cygdrive_info_from_registry () +{ + /* reg_key for user mounts in HKEY_CURRENT_USER. */ + reg_key r; + + if (r.get_string ("cygdrive prefix", cygdrive, sizeof (cygdrive), "") != 0) + { + /* Didn't find it so write the default to the registry and use it. */ + write_cygdrive_info_to_registry ("/cygdrive", MOUNT_AUTO); + } + else + { + /* Fetch cygdrive_flags from registry; returns MOUNT_AUTO on error. */ + cygdrive_flags = r.get_int ("cygdrive flags", MOUNT_AUTO); + slashify (cygdrive, cygdrive, 1); + cygdrive_len = strlen(cygdrive); + } +} + +/* write_cygdrive_info_to_registry: Write the default prefix and flags + to use when creating cygdrives to the special user registry + location used to store cygdrive information. */ + +int +mount_info::write_cygdrive_info_to_registry (const char *cygdrive_prefix, unsigned flags) +{ + /* reg_key for user mounts in HKEY_CURRENT_USER. */ + reg_key r; + + /* Verify cygdrive prefix starts with a forward slash and if there's + another character, it's not a slash. */ + if ((cygdrive_prefix == NULL) || (*cygdrive_prefix == 0) || + (cygdrive_prefix[0] != '/') || + ((cygdrive_prefix[1] != '\0') && (SLASH_P (cygdrive_prefix[1])))) + { + set_errno (EINVAL); + return -1; + } + + char hold_cygdrive_prefix[strlen (cygdrive_prefix) + 1]; + /* Ensure that there is never a final slash */ + nofinalslash (cygdrive_prefix, hold_cygdrive_prefix); + + r.set_string ("cygdrive prefix", hold_cygdrive_prefix); + r.set_int ("cygdrive flags", flags); + + /* This also needs to go in the in-memory copy of "cygdrive" */ + slashify (cygdrive_prefix, cygwin_shared->mount.cygdrive, 1); + cygwin_shared->mount.cygdrive_flags = flags; + cygwin_shared->mount.cygdrive_len = strlen(cygwin_shared->mount.cygdrive); + + return 0; +} + +struct mntent * +mount_info::getmntent (int x) +{ + if (x < 0 || x >= nmounts) + return NULL; + + return mount[native_sorted[x]].getmntent (); +} + +static mount_item *mounts_for_sort; + +/* sort_by_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_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 longest posix path first so that the most + obvious path will be chosen. */ + size_t alen = strlen (ap->posix_path); + size_t blen = strlen (bp->posix_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) == 0) /* user mount */ + return 1; + else + return -1; + } + + return res; +} + +/* sort_by_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_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 longest win32 path first so that the most + obvious path will be chosen. */ + size_t alen = strlen (ap->native_path); + size_t blen = 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 = strcasecmp (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) == 0) /* user mount */ + return 1; + else + return -1; + } + + return res; +} + +void +mount_info::sort () +{ + for (int i = 0; i < nmounts; i++) + native_sorted[i] = 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); +} + +/* Add an entry to the in-memory mount table. + Returns 0 on success, -1 on failure and errno is set. + + This is where all argument validation is done. It may not make sense to + do this when called internally, but it's cleaner to keep it all here. */ + +int +mount_info::add_item (const char *native, const char *posix, unsigned mountflags) +{ + /* Can't add more than MAX_MOUNTS. */ + if (nmounts == MAX_MOUNTS) + { + set_errno (EMFILE); + return -1; + } + + /* Something's wrong if either path is NULL or empty, or if it's + not a UNC or absolute path. */ + + if ((native == NULL) || (*native == 0) || + (posix == NULL) || (*posix == 0) || + (!slash_unc_prefix_p (native) && !isabspath (native))) + { + set_errno (EINVAL); + return -1; + } + + /* Make sure both paths do not end in /. */ + char nativetmp[MAX_PATH]; + char posixtmp[MAX_PATH]; + + if (slash_drive_prefix_p (native)) + slash_drive_to_win32_path (native, nativetmp, 0); + else + { + backslashify (native, nativetmp, 0); + nofinalslash (nativetmp, nativetmp); + } + + slashify (posix, posixtmp, 0); + nofinalslash (posixtmp, posixtmp); + + debug_printf ("%s[%s], %s[%s], %p", + native, nativetmp, posix, posixtmp, mountflags); + + /* Duplicate /'s in path are an error. */ + for (char *p = posixtmp + 1; *p; ++p) + { + if (p[-1] == '/' && p[0] == '/') + { + set_errno (EINVAL); + return -1; + } + } + + /* Write over an existing mount item with the same POSIX path if + it exists and is from the same registry area. */ + for (int i = 0; i < nmounts; i++) + { + if ((strcmp (mount[i].posix_path, posixtmp) == 0) && + ((mount[i].flags & MOUNT_SYSTEM) == (mountflags & MOUNT_SYSTEM))) + { + /* replace existing mount item */ + mount[i].init (nativetmp, posixtmp, mountflags); + goto sortit; + } + } + + mount[nmounts++].init (nativetmp, posixtmp, mountflags); + +sortit: + sort (); + + return 0; +} + +/* Delete a mount table entry where path is either a Win32 or POSIX + path. Since the mount table is really just a table of aliases, + deleting / is ok (although running without a slash mount is + strongly discouraged because some programs may run erratically + without one). If MOUNT_SYSTEM is set in flags, remove from system + registry, otherwise remove the user registry mount. +*/ + +int +mount_info::del_item (const char *path, unsigned flags) +{ + char pathtmp[MAX_PATH]; + + /* Something's wrong if path is NULL or empty. */ + if ((path == NULL) || (*path == 0)) + { + set_errno (EINVAL); + return -1; + } + + slashify (path, pathtmp, 0); + nofinalslash (pathtmp, pathtmp); + + debug_printf ("%s[%s]", path, pathtmp); + + for (int i = 0; i < nmounts; i++) + { + /* Delete if paths and mount locations match. */ + if (((strcmp (mount[i].posix_path, pathtmp) == 0 + || strcmp (mount[i].native_path, pathtmp) == 0)) && + ((mount[i].flags & MOUNT_SYSTEM) == (flags & MOUNT_SYSTEM))) + { + nmounts--; /* One less mount table entry */ + /* Fill in the hole if not at the end of the table */ + if (i < nmounts) + memcpy (mount + i, mount + i + 1, + sizeof (mount[i]) * (nmounts - i)); + sort (); /* Resort the table */ + return 0; + } + } + set_errno (EINVAL); + return -1; +} + +/* read_v1_mounts: Given a reg_key to an old mount table registry area, + read in the mounts. The "which" arg contains zero if we're reading + the user area and MOUNT_SYSTEM if we're reading the system area. + This way we can store the mounts read in the appropriate place when + they are written back to the new registry layout. */ + +void +mount_info::read_v1_mounts (reg_key r, unsigned which) +{ + unsigned mountflags = 0; + + /* MAX_MOUNTS was 30 when we stopped using the v1 layout */ + for (int i = 0; i < 30; i++) + { + char key_name[10]; + char win32path[MAX_PATH]; + char unixpath[MAX_PATH]; + + __small_sprintf (key_name, "%02x", i); + + reg_key k (r.get_key (), KEY_ALL_ACCESS, key_name, NULL); + + /* The registry names are historical but useful so are left alone. */ + k.get_string ("native", win32path, sizeof (win32path), ""); + k.get_string ("unix", unixpath, sizeof (unixpath), ""); + + /* Does this entry contain something? */ + if (*win32path != 0) + { + mountflags = 0; + + if (k.get_int ("fbinary", 0)) + mountflags |= MOUNT_BINARY; + + /* Or in zero or MOUNT_SYSTEM depending on which table + we're reading. */ + mountflags |= which; + + cygwin_shared->mount.add_item (win32path, unixpath, mountflags); + } + } +} + +/* from_v1_registry: Build the entire mount table from the old v1 registry + mount area. */ + +void +mount_info::from_v1_registry () +{ + reg_key r (HKEY_CURRENT_USER, KEY_ALL_ACCESS, + "SOFTWARE", + "Cygnus Solutions", + "CYGWIN.DLL setup", + "b15.0", + "mounts", + NULL); + + nmounts = 0; + + /* First read mounts from user's table. */ + read_v1_mounts (r, 0); + + /* Then read mounts from system-wide mount table. */ + reg_key r1 (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, + "SOFTWARE", + "Cygnus Solutions", + "CYGWIN.DLL setup", + "b15.0", + "mounts", + NULL); + read_v1_mounts (r1, MOUNT_SYSTEM); + + /* Note: we don't need to sort internal table here since it is + done in main from_registry call after this function would be + run. */ +} + +/* import_v1_mounts: If v1 mounts are present, load them and write + the new entries to the new registry area. */ + +void +mount_info::import_v1_mounts () +{ + /* Read in old mounts into memory. */ + from_v1_registry (); + + /* Write all mounts to the new registry. */ + to_registry (); +} + +/* to_registry: For every mount point in memory, add a corresponding + registry mount point. */ + +void +mount_info::to_registry () +{ + for (int i = 0; i < MAX_MOUNTS; i++) + { + if (i < nmounts) + { + mount_item *p = mount + i; + + add_reg_mount (p->native_path, p->posix_path, p->flags); + + debug_printf ("%02x: %s, %s, %d", + i, p->native_path, p->posix_path, p->flags); + } + } +} + +/************************* mount_item class ****************************/ + +struct mntent * +mount_item::getmntent () +{ +#ifdef _MT_SAFE + struct mntent &ret=_reent_winsup()->_ret; +#else + static NO_COPY struct mntent ret; +#endif + + /* Pass back pointers to mount_info strings reserved for use by + getmntent rather than pointers to strings in the internal mount + table because the mount table might change, causing weird effects + from the getmntent user's point of view. */ + + strcpy (cygwin_shared->mount.mnt_fsname, native_path); + ret.mnt_fsname = cygwin_shared->mount.mnt_fsname; + strcpy (cygwin_shared->mount.mnt_dir, posix_path); + ret.mnt_dir = cygwin_shared->mount.mnt_dir; + + if (!(flags & MOUNT_SYSTEM)) /* user mount */ + strcpy (cygwin_shared->mount.mnt_type, (char *) "user"); + else /* system mount */ + strcpy (cygwin_shared->mount.mnt_type, (char *) "system"); + + if ((flags & MOUNT_AUTO)) /* cygdrive */ + strcat (cygwin_shared->mount.mnt_type, (char *) ",auto"); + + ret.mnt_type = cygwin_shared->mount.mnt_type; + + /* mnt_opts is a string that details mount params such as + binary or textmode, or exec. We don't print + `silent' here; it's a magic internal thing. */ + + if (! (flags & MOUNT_BINARY)) + strcpy (cygwin_shared->mount.mnt_opts, (char *) "textmode"); + else + strcpy (cygwin_shared->mount.mnt_opts, (char *) "binmode"); + + if (flags & MOUNT_EXEC) + strcat (cygwin_shared->mount.mnt_opts, (char *) ",exec"); + + ret.mnt_opts = cygwin_shared->mount.mnt_opts; + + ret.mnt_freq = 1; + ret.mnt_passno = 1; + return &ret; +} + +/* Fill in the fields of a mount table entry. */ + +void +mount_item::init (const char *native, const char *posix, unsigned mountflags) +{ + strcpy ((char *) native_path, native); + strcpy ((char *) posix_path, posix); + + native_pathlen = strlen (native_path); + posix_pathlen = strlen (posix_path); + + flags = mountflags; +} + +/********************** Mount System Calls **************************/ + +/* Mount table system calls. + Note that these are exported to the application. */ + +/* mount: Add a mount to the mount table in memory and to the registry + that will cause paths under win32_path to be translated to paths + under posix_path. */ + +extern "C" +int +mount (const char *win32_path, const char *posix_path, unsigned flags) +{ + int res = -1; + + if (flags & MOUNT_AUTO) /* normal mount */ + { + /* When flags include MOUNT_AUTO, take this to mean that + we actually want to change the cygdrive prefix and flags + without actually mounting anything. */ + res = cygwin_shared->mount.write_cygdrive_info_to_registry (posix_path, flags); + win32_path = NULL; + } + else + { + if (iscygdrive (posix_path)) + { + set_errno (EINVAL); + return res; /* Don't try to add cygdrive prefix. */ + } + + res = cygwin_shared->mount.add_reg_mount (win32_path, posix_path, flags); + + if (res == 0) + cygwin_shared->mount.add_item (win32_path, posix_path, flags); + } + + syscall_printf ("%d = mount (%s, %s, %p)", res, win32_path, posix_path, flags); + return res; +} + +/* umount: The standard umount call only has a path parameter. Since + it is not possible for this call to specify whether to remove the + mount from the user or global mount registry table, assume the user + table. */ + +extern "C" +int +umount (const char *path) +{ + return cygwin_umount (path, 0); +} + +/* cygwin_umount: This is like umount but takes an additional flags + parameter that specifies whether to umount from the user or system-wide + registry area. */ + +extern "C" +int +cygwin_umount (const char *path, unsigned flags) +{ + int res = cygwin_shared->mount.del_reg_mount (path, flags); + + if (res == 0) + cygwin_shared->mount.del_item (path, flags); + + syscall_printf ("%d = cygwin_umount (%s, %d)", res, path, flags); + return res; +} + +#ifdef _MT_SAFE +#define iteration _reent_winsup()->_iteration +#else +static int iteration; +#endif + +extern "C" +FILE * +setmntent (const char *filep, const char *) +{ + iteration = 0; + return (FILE *) filep; +} + +extern "C" +struct mntent * +getmntent (FILE *) +{ + return cygwin_shared->mount.getmntent (iteration++); +} + +extern "C" +int +endmntent (FILE *) +{ + return 1; +} + +/********************** Symbolic Link Support **************************/ + +/* Create a symlink from FROMPATH to TOPATH. */ + +extern "C" +int +symlink (const char *topath, const char *frompath) +{ + HANDLE h; + int res = -1; + + path_conv win32_path (frompath, SYMLINK_NOFOLLOW); + if (win32_path.error) + { + set_errno (win32_path.error); + goto done; + } + + syscall_printf ("symlink (%s, %s)", topath, win32_path.get_win32 ()); + + if (topath[0] == 0) + { + set_errno (EINVAL); + goto done; + } + if (strlen (topath) >= MAX_PATH) + { + set_errno (ENAMETOOLONG); + goto done; + } + + if (win32_path.is_device () || + win32_path.file_attributes () != (DWORD) -1) + { + set_errno (EEXIST); + goto done; + } + + h = CreateFileA(win32_path.get_win32 (), GENERIC_WRITE, 0, &sec_none_nih, + CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0); + if (h == INVALID_HANDLE_VALUE) + __seterrno (); + else + { + char buf[sizeof (SYMLINK_COOKIE) + MAX_PATH + 10]; + + __small_sprintf (buf, "%s%s", SYMLINK_COOKIE, topath); + DWORD len = strlen (buf) + 1; + + /* Note that the terminating nul is written. */ + DWORD written; + if (!WriteFile (h, buf, len, &written, NULL) || written != len) + { + __seterrno (); + CloseHandle (h); + DeleteFileA (win32_path.get_win32 ()); + } + else + { + CloseHandle (h); + chmod (frompath, S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO); + res = 0; + } + } + +done: + syscall_printf ("%d = symlink (%s, %s)", res, topath, frompath); + return res; +} + +static __inline char * +has_suffix (const char *path, const suffix_info *suffixes) +{ + char *ext = strrchr (path, '.'); + if (ext) + for (const suffix_info *ex = suffixes; ex->name != NULL; ex++) + if (strcasematch (ext, ex->name)) + return ext; + return NULL; +} + +static int __inline +next_suffix (char *ext_here, const suffix_info *&suffixes) +{ + if (!suffixes) + return 1; + + while (suffixes && suffixes->name) + if (!suffixes->addon) + suffixes++; + else + { + strcpy (ext_here, suffixes->name); + suffixes++; + return 1; + } + return 0; +} + +/* Check if PATH is a symlink. PATH must be a valid Win32 path name. + + If PATH is a symlink, put the value of the symlink--the file to + which it points--into BUF. The value stored in BUF is not + necessarily null terminated. BUFLEN is the length of BUF; only up + to BUFLEN characters will be stored in BUF. BUF may be NULL, in + which case nothing will be stored. + + Set *SYML if PATH is a symlink. + + Set *EXEC if PATH appears to be executable. This is an efficiency + hack because we sometimes have to open the file anyhow. *EXEC will + not be set for every executable file. + + Return -1 on error, 0 if PATH is not a symlink, or the length + stored into BUF if PATH is a symlink. */ + +static int +symlink_check_one (const char *in_path, char *buf, int buflen, DWORD& fileattr, + unsigned *pflags, const suffix_info *suffixes, char *&known_suffix) +{ + HANDLE h; + int res = 0; + char extbuf[buflen + 5]; + char *ext_here; + const char *path = in_path; + + if (!suffixes) + ext_here = NULL; + else if ((known_suffix = has_suffix (in_path, suffixes)) != NULL) + { + suffixes = NULL; + ext_here = NULL; + } + else + { + path = strcpy (extbuf, in_path); + ext_here = strchr (path, '\0'); + } + + *buf = '\0'; + do + { + if (!next_suffix (ext_here, suffixes)) + break; + fileattr = GetFileAttributesA (path); + if (fileattr == (DWORD) -1) + { + /* The GetFileAttributesA call can fail for reasons that don't + matter, so we just return 0. For example, getting the + attributes of \\HOST will typically fail. */ + debug_printf ("GetFileAttributesA (%s) failed", path); + __seterrno (); + continue; + } + + /* Windows allows path\. even when `path' isn't a directory. + Detect this scenario and disallow it, since it is non-UNIX like. */ + char *p = strchr (path, '\0'); + if (p > path + 1 && p[-1] == '.' && SLASH_P (p[-2]) && + !(fileattr & FILE_ATTRIBUTE_DIRECTORY)) + { + debug_printf ("\\. specified on non-directory"); + set_errno (ENOTDIR); + return 0; + } + + /* A symlink will have the `system' file attribute. */ + /* Only files can be symlinks (which can be symlinks to directories). */ + if (!SYMLINKATTR (fileattr)) + goto file_not_symlink; + + /* Check the file's extended attributes, if it has any. */ + int unixattr = 0; + if (fileattr & FILE_ATTRIBUTE_DIRECTORY) + unixattr |= S_IFDIR; + + if (! get_file_attribute (TRUE, path, &unixattr)) + { + if (unixattr & STD_XBITS) + *pflags |= PATH_EXEC; + if (! S_ISLNK (unixattr)) + ; + } + + /* Open the file. */ + + h = CreateFileA (path, GENERIC_READ, FILE_SHARE_READ, &sec_none_nih, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, 0); + + res = -1; + if (h == INVALID_HANDLE_VALUE) + __seterrno (); + else + { + char cookie_buf[sizeof (SYMLINK_COOKIE) - 1]; + DWORD got; + + if (! ReadFile (h, cookie_buf, sizeof (cookie_buf), &got, 0)) + set_errno (EIO); + else if (got == sizeof (cookie_buf) + && memcmp (cookie_buf, SYMLINK_COOKIE, + sizeof (cookie_buf)) == 0) + { + /* It's a symlink. */ + *pflags = PATH_SYMLINK; + + res = ReadFile (h, buf, buflen, &got, 0); + if (!res) + set_errno (EIO); + else + { + /* Versions prior to b16 stored several trailing + NULs with the path (to fill the path out to 1024 + chars). Current versions only store one trailing + NUL. The length returned is the path without + *any* trailing NULs. We also have to handle (or + at least not die from) corrupted paths. */ + if (memchr (buf, 0, got) != NULL) + res = strlen (buf); + else + res = got; + } + } + else if (got == sizeof (cookie_buf) + && memcmp (cookie_buf, SOCKET_COOKIE, + sizeof (cookie_buf)) == 0) + { + res = 0; + *pflags |= PATH_SOCKET; + goto close_and_return; + } + else if (*pflags & PATH_EXEC) + goto close_and_return; + else if (!(*pflags & PATH_EXEC)) + { + /* Not a symlink, see if executable. */ + if (got >= 2 && + ((cookie_buf[0] == '#' && cookie_buf[1] == '!') || + (cookie_buf[0] == ':' && cookie_buf[1] == '\n'))) + *pflags |= PATH_EXEC; + close_and_return: + CloseHandle (h); + goto file_not_symlink; + } + } + CloseHandle (h); + break; + } + while (suffixes); + goto out; + +file_not_symlink: + set_errno (EINVAL); + if (ext_here) + strcpy (buf, ext_here); + res = 0; + +out: + syscall_printf ("%d = symlink_check_one (%s, %p, %d) (%p)", + res, path, buf, buflen, *pflags); + + return res; +} + +/* readlink system call */ + +extern "C" +int +readlink (const char *path, char *buf, int buflen) +{ + path_conv pathbuf (path, SYMLINK_CONTENTS); + if (pathbuf.error) + { + set_errno (pathbuf.error); + syscall_printf ("-1 = readlink (%s, %p, %d)", path, buf, buflen); + return -1; + } + + if (!pathbuf.issymlink ()) + { + if (pathbuf.fileattr != (DWORD) -1) + set_errno (EINVAL); + return -1; + } + + int len = strlen (pathbuf.get_win32 ()); + if (len > (buflen - 1)) + { + set_errno (ENAMETOOLONG); + return -1; + } + memcpy (buf, pathbuf.get_win32 (), len); + buf[len] = '\0'; + + /* errno set by symlink_check_one if error */ + return len; +} + +/* Some programs rely on st_dev/st_ino being unique for each file. + Hash the path name and hope for the best. The hash arg is not + always initialized to zero since readdir needs to compute the + dirent ino_t based on a combination of the hash of the directory + done during the opendir call and the hash or the filename within + the directory. FIXME: Not bullet-proof. */ +/* Cygwin internal */ + +unsigned long __stdcall +hash_path_name (unsigned long hash, const char *name) +{ + if (!*name) + return hash; + + /* Perform some initial permutations on the pathname if this is + not "seeded" */ + if (!hash) + { + /* Simplistic handling of drives. If there is a drive specified, + make sure that the initial letter is upper case. If there is + no \ after the ':' assume access through the root directory + of that drive. + FIXME: Should really honor MS-Windows convention of using + the environment to track current directory on various drives. */ + if (name[1] == ':') + { + char *nn, *newname = (char *) alloca (strlen (name) + 2); + nn = strncpy (newname, name, 2); + if (islower (*nn)) + *newname = toupper (*nn); + *(nn += 2) = '\0'; + name += 2; + if (*name != '\\') + { + *nn = '\\'; + *++nn = '\0'; + } + strcpy (nn, name); + name = newname; + goto hashit; + } + + /* Fill out the hashed path name with the current working directory if + this is not an absolute path and there is no pre-specified hash value. + Otherwise the inodes same will differ depending on whether a file is + referenced with an absolute value or relatively. */ + + if (*name != '\\' && (current_directory_name == NULL || + get_current_directory_name ())) + { + hash = current_directory_hash; + if (name[0] == '.' && name[1] == '\0') + return hash; + hash = hash_path_name (hash, "\\"); + } + } + +hashit: + /* Build up hash. Ignore single trailing slash or \a\b\ != \a\b or + \a\b\. but allow a single \ if that's all there is. */ + do + { + hash += *name + (*name << 17); + hash ^= hash >> 2; + } + while (*++name != '\0' && + !(*name == '\\' && (!name[1] || (name[1] == '.' && !name[2])))); + return hash; +} + +static int +get_current_directory_name () +{ + DWORD dlen, len; + + for (dlen = 256; ; dlen *= 2) + { + current_directory_name = (char *) realloc (current_directory_name, dlen + 2); + if ((len = GetCurrentDirectoryA (dlen, current_directory_name)) < dlen) + break; + } + + if (len == 0) + __seterrno (); + else + current_directory_hash = hash_path_name (0, current_directory_name); + + return len; +} + +/* getcwd */ + +static char * +getcwd_inner (char *buf, size_t ulen, int posix_p) +{ + char *resbuf = NULL; + size_t len = ulen; + + if (current_directory_name == NULL && !get_current_directory_name ()) + return NULL; + + if (!posix_p) + { + if (strlen (current_directory_name) >= len) + set_errno (ERANGE); + else + { + strcpy (buf, current_directory_name); + resbuf = buf; + } + + syscall_printf ("%p (%s) = getcwd_inner (%p, %d, win32) (cached)", + resbuf, resbuf ? resbuf : "", buf, len); + return resbuf; + } + else if (current_directory_posix_name != NULL) + { + if (strlen (current_directory_posix_name) >= len) + set_errno (ERANGE); + else + { + strcpy (buf, current_directory_posix_name); + resbuf = buf; + } + + syscall_printf ("%p (%s) = getcwd_inner (%p, %d, posix) (cached)", + resbuf, resbuf ? resbuf : "", buf, len); + return resbuf; + } + + /* posix_p required and current_directory_posix_name == NULL */ + + char temp[MAX_PATH]; + + /* Turn from Win32 style to our style. */ + cygwin_shared->mount.conv_to_posix_path (current_directory_name, temp, 0); + + size_t tlen = strlen (temp); + + current_directory_posix_name = (char *) realloc ( + current_directory_posix_name, tlen + 1); + if (current_directory_posix_name != NULL) + strcpy (current_directory_posix_name, temp); + + if (tlen >= ulen) + { + /* len was too small */ + set_errno (ERANGE); + } + else + { + strcpy (buf, temp); + resbuf = buf; + } + + syscall_printf ("%p (%s) = getcwd_inner (%p, %d, %s)", + resbuf, resbuf ? resbuf : "", + buf, len, posix_p ? "posix" : "win32"); + return resbuf; +} + +char * +getcwd (char *buf, size_t ulen) +{ + char *res; + + if (buf == NULL || ulen == 0) + { + buf = (char *) alloca (MAX_PATH); + res = getcwd_inner (buf, MAX_PATH, 1); + res = strdup (buf); + } + else + { + res = getcwd_inner (buf, ulen, 1); + } + + return res; +} + +/* getwd: standards? */ +extern "C" +char * +getwd (char *buf) +{ + return getcwd (buf, MAX_PATH); +} + +/* chdir: POSIX 5.2.1.1 */ +extern "C" +int +chdir (const char *dir) +{ + path_conv path (dir); + + if (path.error) + { + set_errno (path.error); + syscall_printf ("-1 = chdir (%s)", dir); + return -1; + } + + char *native_dir = path.get_win32 (); + + /* Check to see if path translates to something like C:. + If it does, append a \ to the native directory specification to + defeat the Windows 95 (i.e. MS-DOS) tendency of returning to + the last directory visited on the given drive. */ + if (isalpha (native_dir[0]) && native_dir[1] == ':' && !native_dir[2]) + { + native_dir[2] = '\\'; + native_dir[3] = '\0'; + } + int res = SetCurrentDirectoryA (native_dir); + if (!res) + __seterrno (); + + /* Clear the cache until we need to retrieve the directory again. */ + if (current_directory_name != NULL) + { + free (current_directory_name); + current_directory_name = NULL; + } + if (current_directory_posix_name != NULL) + { + free (current_directory_posix_name); + current_directory_posix_name = NULL; + } + + syscall_printf ("%d = chdir (%s) (dos %s)", res ? 0 : -1, dir, native_dir); + return res ? 0 : -1; +} + +/******************** Exported Path Routines *********************/ + +/* Cover functions to the path conversion routines. + These are exported to the world as cygwin_foo by cygwin.din. */ + +extern "C" +int +cygwin_conv_to_win32_path (const char *path, char *win32_path) +{ + path_conv p (path, SYMLINK_FOLLOW, 0); + if (p.error) + { + set_errno (p.error); + return -1; + } + + strcpy (win32_path, p.get_win32 ()); + return 0; +} + +extern "C" +int +cygwin_conv_to_full_win32_path (const char *path, char *win32_path) +{ + path_conv p (path, SYMLINK_FOLLOW, 1); + if (p.error) + { + set_errno (p.error); + return -1; + } + + strcpy (win32_path, p.get_win32 ()); + return 0; +} + +/* This is exported to the world as cygwin_foo by cygwin.din. */ + +extern "C" +int +cygwin_conv_to_posix_path (const char *path, char *posix_path) +{ + if (check_null_empty_path_errno (path)) + return -1; + cygwin_shared->mount.conv_to_posix_path (path, posix_path, 1); + return 0; +} + +extern "C" +int +cygwin_conv_to_full_posix_path (const char *path, char *posix_path) +{ + if (check_null_empty_path_errno (path)) + return -1; + cygwin_shared->mount.conv_to_posix_path (path, posix_path, 0); + return 0; +} + +/* The realpath function is supported on some UNIX systems. */ + +extern "C" +char * +realpath (const char *path, char *resolved) +{ + int err; + + path_conv real_path (path, SYMLINK_FOLLOW, 1); + + if (real_path.error) + err = real_path.error; + else + { + err = cygwin_shared->mount.conv_to_posix_path (real_path.get_win32 (), resolved, 0); + if (err == 0) + return resolved; + } + + /* FIXME: on error, we are supposed to put the name of the path + component which could not be resolved into RESOLVED. */ + resolved[0] = '\0'; + + set_errno (err); + return NULL; +} + +/* Return non-zero if path is a POSIX path list. + This is exported to the world as cygwin_foo by cygwin.din. + +DOCTOOL-START + + Rather than use a mode to say what the "proper" path list + format is, we allow any, and give apps the tools they need to + convert between the two. If a ';' is present in the path list it's + a Win32 path list. Otherwise, if the first path begins with + [letter]: (in which case it can be the only element since if it + wasn't a ';' would be present) it's a Win32 path list. Otherwise, + it's a POSIX path list. + +DOCTOOL-END + */ + +extern "C" +int +cygwin_posix_path_list_p (const char *path) +{ + int posix_p = ! (strchr (path, ';') + || (isalpha (path[0]) && path[1] == ':')); + return posix_p; +} + +/* These are used for apps that need to convert env vars like PATH back and + forth. The conversion is a two step process. First, an upper bound on the + size of the buffer needed is computed. Then the conversion is done. This + allows the caller to use alloca if it wants. */ + +static int +conv_path_list_buf_size (const char *path_list, int to_posix_p) +{ + int i, num_elms, max_mount_path_len, size; + const char *p; + + /* The theory is that an upper bound is + current_size + (num_elms * max_mount_path_len) */ + + char delim = to_posix_p ? ';' : ':'; + p = path_list; + for (num_elms = 1; (p = strchr (p, delim)) != NULL; ++num_elms) + ++p; + + /* 7: strlen ("//c") + slop, a conservative initial value */ + for (max_mount_path_len = 7, i = 0; i < cygwin_shared->mount.nmounts; ++i) + { + int mount_len = (to_posix_p + ? cygwin_shared->mount.mount[i].posix_pathlen + : cygwin_shared->mount.mount[i].native_pathlen); + if (max_mount_path_len < mount_len) + max_mount_path_len = mount_len; + } + + /* 100: slop */ + size = strlen (path_list) + (num_elms * max_mount_path_len) + 100; + return size; +} + +extern "C" +int +cygwin_win32_to_posix_path_list_buf_size (const char *path_list) +{ + return conv_path_list_buf_size (path_list, 1); +} + +extern "C" +int +cygwin_posix_to_win32_path_list_buf_size (const char *path_list) +{ + return conv_path_list_buf_size (path_list, 0); +} + +extern "C" +int +cygwin_win32_to_posix_path_list (const char *win32, char *posix) +{ + conv_path_list (win32, posix, 1); + return 0; +} + +extern "C" +int +cygwin_posix_to_win32_path_list (const char *posix, char *win32) +{ + conv_path_list (posix, win32, 0); + return 0; +} + +/* cygwin_split_path: Split a path into directory and file name parts. + Buffers DIR and FILE are assumed to be big enough. + + Examples (path -> `dir' / `file'): + / -> `/' / `' + "" -> `.' / `' + . -> `.' / `.' (FIXME: should this be `.' / `'?) + .. -> `.' / `..' (FIXME: should this be `..' / `'?) + foo -> `.' / `foo' + foo/bar -> `foo' / `bar' + foo/bar/ -> `foo' / `bar' + /foo -> `/' / `foo' + /foo/bar -> `/foo' / `bar' + c: -> `c:/' / `' + c:/ -> `c:/' / `' + c:foo -> `c:/' / `foo' + c:/foo -> `c:/' / `foo' + */ + +extern "C" +void +cygwin_split_path (const char *path, char *dir, char *file) +{ + int dir_started_p = 0; + + /* Deal with drives. + Remember that c:foo <==> c:/foo. */ + if (isalpha (path[0]) && path[1] == ':') + { + *dir++ = *path++; + *dir++ = *path++; + *dir++ = '/'; + if (! *path) + { + *dir = 0; + *file = 0; + return; + } + if (SLASH_P (*path)) + ++path; + dir_started_p = 1; + } + + /* Determine if there are trailing slashes and "delete" them if present. + We pretend as if they don't exist. */ + const char *end = path + strlen (path); + /* path + 1: keep leading slash. */ + while (end > path + 1 && SLASH_P (end[-1])) + --end; + + /* At this point, END points to one beyond the last character + (with trailing slashes "deleted"). */ + + /* Point LAST_SLASH at the last slash (duh...). */ + const char *last_slash; + for (last_slash = end - 1; last_slash >= path; --last_slash) + if (SLASH_P (*last_slash)) + break; + + if (last_slash == path) + { + *dir++ = '/'; + *dir = 0; + } + else if (last_slash > path) + { + memcpy (dir, path, last_slash - path); + dir[last_slash - path] = 0; + } + else + { + if (dir_started_p) + ; /* nothing to do */ + else + *dir++ = '.'; + *dir = 0; + } + + memcpy (file, last_slash + 1, end - last_slash - 1); + file[end - last_slash - 1] = 0; +} + +/********************** String Helper Functions ************************/ + +#define CHXOR ('a' ^ 'A') +#define ch_case_eq(ch1, ch2) \ + ({ \ + unsigned char x; \ + !((x = ((unsigned char)ch1 ^ (unsigned char)ch2)) && \ + (x != CHXOR || !isalpha (ch1))); \ + }) + +int __stdcall +strncasematch (const char *s1, const char *s2, size_t n) +{ + if (s1 == s2) + return 1; + + n++; + while (--n && *s1) + { + if (!ch_case_eq (*s1, *s2)) + return 0; + s1++; s2++; + } + return !n || *s2 == '\0'; +} + +int __stdcall +strcasematch (const char *s1, const char *s2) +{ + if (s1 == s2) + return 1; + + while (*s1) + { + if (!ch_case_eq (*s1, *s2)) + return 0; + s1++; s2++; + } + return *s2 == '\0'; +} + +char * __stdcall +strcasestr (const char *searchee, const char *lookfor) +{ + if (*searchee == 0) + { + if (*lookfor) + return NULL; + return (char *) searchee; + } + + while (*searchee) + { + int i = 0; + while (1) + { + if (lookfor[i] == 0) + return (char *) searchee; + + if (!ch_case_eq (lookfor[i], searchee[i])) + break; + lookfor++; + } + searchee++; + } + + return NULL; +} diff --git a/winsup/cygwin/path.h b/winsup/cygwin/path.h new file mode 100644 index 000000000..3c0efccae --- /dev/null +++ b/winsup/cygwin/path.h @@ -0,0 +1,98 @@ +/* path.h: path data structures + + Copyright 1996, 1997, 1998, 2000 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +struct suffix_info +{ + const char *name; + int addon; + suffix_info (const char *s, int addit = 0) {name = s, addon = addit;} +}; + +enum symlink_follow +{ + SYMLINK_FOLLOW, + SYMLINK_NOFOLLOW, + SYMLINK_IGNORE, + SYMLINK_CONTENTS +}; + +#include + +enum +{ + PATH_SYMLINK = 1, + PATH_BINARY = MOUNT_BINARY, + PATH_EXEC = MOUNT_EXEC, + PATH_SOCKET = 0x40000000, + PATH_HASACLS = 0x80000000 +}; + + +class path_conv +{ + char path[MAX_PATH]; + public: + + unsigned path_flags; + + int has_acls () {return path_flags & PATH_HASACLS;} + int hasgood_inode () {return path_flags & PATH_HASACLS;} // Not strictly correct + int isbinary () {return path_flags & PATH_BINARY;} + int issymlink () {return path_flags & PATH_SYMLINK;} + int issocket () {return path_flags & PATH_SOCKET;} + int isexec () {return path_flags & PATH_EXEC;} + + void set_binary () {path_flags |= PATH_BINARY;} + void set_symlink () {path_flags |= PATH_SYMLINK;} + void set_exec (int x = 1) {path_flags |= x ? PATH_EXEC : 0;} + void set_has_acls (int x = 1) {path_flags |= x ? PATH_HASACLS : 0;} + + char *known_suffix; + + int error; + DWORD devn; + int unit; + + DWORD fileattr; + + path_conv (const char * const, symlink_follow follow_mode = SYMLINK_FOLLOW, + int use_full_path = 0, const suffix_info *suffixes = NULL); + inline char *get_win32 () { return path; } + BOOL is_device () {return devn != FH_BAD;} + DWORD get_devn () {return devn == FH_BAD ? FH_DISK : devn;} + short get_unitn () {return devn == FH_BAD ? 0 : unit;} + DWORD file_attributes () {return fileattr;} +}; + +/* Symlink marker */ +#define SYMLINK_COOKIE "!" + +/* Socket marker */ +#define SOCKET_COOKIE "!" + +/* Maximum depth of symlinks (after which ELOOP is issued). */ +#define MAX_LINK_DEPTH 10 + +extern suffix_info std_suffixes[]; + +int __stdcall get_device_number (const char *name, int &unit, BOOL from_conv = FALSE); +int __stdcall slash_unc_prefix_p (const char *path); + +/* Common macros for checking for invalid path names */ +#define check_null_empty_path(src) \ + (!(src) ? EFAULT : *(src) ? 0 : ENOENT) + +#define check_null_empty_path_errno(src) \ +({ \ + int __err; \ + if ((__err = check_null_empty_path(src))) \ + set_errno (__err); \ + __err; \ +}) diff --git a/winsup/cygwin/path.sgml b/winsup/cygwin/path.sgml new file mode 100644 index 000000000..6030c8f78 --- /dev/null +++ b/winsup/cygwin/path.sgml @@ -0,0 +1,205 @@ + +cygwin_posix_to_win32_path_list + + +extern "C" void +cygwin_posix_to_win32_path_list +const char *posix +char *win32 + + +Given a POSIX path-style string (i.e. /foo:/bar) convert it to +the equivalent Win32 path-style string (i.e. d:\;e:\bar). +win32 must point to a sufficiently large +buffer. + + +Example use of cygwin_posix_to_win32_path_list + +char *_epath; +char *_win32epath; +_epath = _win32epath = getenv (NAME); +/* If we have a POSIX path list, convert to win32 path list */ +if (_epath != NULL && *_epath != 0 + && cygwin_posix_path_list_p (_epath)) + { + _win32epath = (char *) xmalloc + (cygwin_posix_to_win32_path_list_buf_size (_epath)); + cygwin_posix_to_win32_path_list (_epath, _win32epath); + } + + + +See also +cygwin_posix_to_win32_path_list_buf_size + + + + +cygwin_win32_to_posix_path_list + + +extern "C" void +cygwin_win32_to_posix_path_list +const char *win32 +char *posix + + +Given a Win32 path-style string (i.e. d:\;e:\bar) convert it to +the equivalent POSIX path-style string (i.e. /foo:/bar). +posix must point to a sufficiently large +buffer. See also +cygwin_win32_to_posix_path_list_buf_size + + + + +cygwin_posix_to_win32_path_list_buf_size + + +extern "C" int +cygwin_posix_to_win32_path_list_buf_size +const char *path_list + + +Returns the number of bytes needed to hold the result of calling + +cygwin_posix_to_win32_path_list. + + + + +cygwin_win32_to_posix_path_list_buf_size + + +extern "C" int +cygwin_win32_to_posix_path_list_buf_size +const char *path_list + + +Tells you how many bytes are needed for the results of +cygwin_win32_to_posix_path_list. + + + + +cygwin_conv_to_posix_path + + +extern "C" void +cygwin_conv_to_posix_path +const char *path +char *posix_path + + +Converts a Win32 path to a POSIX path. If +path is already a POSIX path, leaves it alone. +If path is relative, then +posix_path will also be relative. Note that +posix_path must point to a buffer of sufficient +size; use MAX_PATH if needed. + + + + +cygwin_conv_to_win32_path + + +extern "C" void +cygwin_conv_to_win32_path +const char *path +char *win32_path + + +Converts a POSIX path to a Win32 path. If +path is already a Win32 path, leaves it alone. +If path is relative, then +win32_path will also be relative. Note that +win32_path must point to a buffer of sufficient +size; use MAX_PATH if needed. + + + +cygwin_conv_to_full_posix_path + + +extern "C" void +cygwin_conv_to_full_posix_path +const char *path +char *posix_path + + +Converts a Win32 path to a POSIX path. If +path is already a POSIX path, leaves it alone. +If path is relative, then +posix_path will be converted to an absolute +path. Note that posix_path must point to a +buffer of sufficient size; use MAX_PATH if needed. + + + + +cygwin_conv_to_full_win32_path + + +extern "C" void +cygwin_conv_to_full_win32_path +const char *path +char *win32_path + + +Converts a POSIX path to a Win32 path. If +path is already a Win32 path, leaves it alone. +If path is relative, then +win32_path will be converted to an absolute +path. Note that win32_path must point to a +buffer of sufficient size; use MAX_PATH if needed. + + + + +cygwin_posix_path_list_p + + +extern "C" int +posix_path_list_p +const char *path + + +This function tells you if the supplied +path is a POSIX-style path (i.e. posix names, +forward slashes, colon delimiters) or a Win32-style path (drive +letters, reverse slashes, semicolon delimiters. The return value is +true if the path is a POSIX path. Note that "_p" means "predicate", a +lisp term meaning that the function tells you something about the +parameter. + + + + +cygwin_split_path + + +extern "C" void +cygwin_split_path + +const char * path +char * dir +char * file + + +Split a path into the directory and the file portions. Both +dir and file are +expected to point to buffers of sufficient size. + + +Example use of cygwin_split_path + +char dir[200], file[100]; +cygwin_split_path("c:/foo/bar.c", dir, file); +printf("dir=%s, file=%s\n", dir, file); + + + diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc new file mode 100644 index 000000000..789a47920 --- /dev/null +++ b/winsup/cygwin/pinfo.cc @@ -0,0 +1,413 @@ +/* pinfo.cc: process table support + + Copyright 1996, 1997, 1998, 2000 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include +#include "winsup.h" + +/* The first pid used; also the lowest value allowed. */ +#define PBASE 1000 + +static char NO_COPY pinfo_dummy[sizeof(pinfo)] = {0}; + +pinfo NO_COPY *myself = (pinfo *)&pinfo_dummy; // Avoid myself != NULL checks + +/* Initialize the process table. + This is done once when the dll is first loaded. */ + +void +pinfo_list::init (void) +{ + next_pid = PBASE; /* Next pid to try to allocate. */ + + /* We assume the shared data area is already initialized to zeros. + Note that SIG_DFL is zero. */ +} + +pinfo * __stdcall +set_myself (pinfo *p) +{ + myself = p; + if (!p) + return NULL; + + myself->start_time = time (NULL); /* Register our starting time. */ + + char buf[30]; + __small_sprintf (buf, "cYg%8x %x %x", _STRACE_INTERFACE_ACTIVATE_ADDR, + &strace_active); + OutputDebugString (buf); + return myself; +} + +/* Initialize the process table entry for the current task. + This is not called for fork'd tasks, only exec'd ones. */ +void __stdcall +pinfo_init (LPBYTE info) +{ + if (info != NULL) + { + /* The process was execed. Reuse entry from the original + owner of this pid. */ + environ_init (); /* Needs myself but affects calls below */ + + /* spawn has already set up a pid structure for us so we'll use that */ + + myself->process_state |= PID_CYGPARENT; + + /* Inherit file descriptor information from parent in info. + */ + LPBYTE b = dtable.de_linearize_fd_array (info); + extern char title_buf[]; + if (b && *b) + old_title = strcpy (title_buf, (char *)b); + } + else + { + /* Invent our own pid. */ + + if (!set_myself (cygwin_shared->p.allocate_pid ())) + api_fatal ("No more processes"); + + (void) GetModuleFileName (NULL, myself->progname, + sizeof(myself->progname)); + myself->ppid = myself->pgid = myself->sid = myself->pid; + myself->ctty = -1; + myself->uid = USHRT_MAX; + + environ_init (); /* call after myself has been set up */ + } + + debug_printf ("pid %d, pgid %d", myself->pid, myself->pgid); +} + +/* [] operator. This is the mechanism for table lookups. */ +/* Returns the index into the pinfo_list table for pid arg */ + +pinfo * +pinfo_list::operator[] (pid_t pid) +{ + if (pid <= 0) + return NULL; + + pinfo *p = vec + (pid % size ()); + + if (p->pid != pid || p->process_state == PID_NOT_IN_USE) + return NULL; + else + return p; +} + +struct sigaction& +pinfo::getsig(int sig) +{ +#ifdef _MT_SAFE + if ( thread2signal ) + return thread2signal->sigs[sig]; + return sigs[sig]; +#else + return sigs[sig]; +#endif +}; + +sigset_t& +pinfo::getsigmask () +{ +#ifdef _MT_SAFE + if ( thread2signal ) + return *thread2signal->sigmask; + return sig_mask; +#else + return sig_mask; +#endif +}; + +void +pinfo::setsigmask (sigset_t _mask) +{ +#ifdef _MT_SAFE + if ( thread2signal ) + *(thread2signal->sigmask) = _mask; + sig_mask=_mask; +#else + sig_mask=_mask; +#endif +} + +LONG * +pinfo::getsigtodo(int sig) +{ +#ifdef _MT_SAFE + if ( thread2signal ) + return thread2signal->sigtodo + __SIGOFFSET + sig; + return _sigtodo + __SIGOFFSET + sig; +#else + return _sigtodo + __SIGOFFSET + sig; +#endif +} + +extern HANDLE hMainThread; + +HANDLE +pinfo::getthread2signal() +{ +#ifdef _MT_SAFE + if ( thread2signal ) + return thread2signal->win32_obj_id; + return hMainThread; +#else + return hMainThread; +#endif +} + +void +pinfo::setthread2signal(void *_thr) +{ +#ifdef _MT_SAFE + // assert has myself lock + thread2signal=(ThreadItem*)_thr; +#else +#endif +} + +void +pinfo::copysigs(pinfo *_other) +{ + sigs = _other->sigs; +} + +pinfo * __stdcall +procinfo (int pid) +{ + return cygwin_shared->p[pid]; +} + +#ifdef DEBUGGING +/* + * Code to lock/unlock the process table. + */ + +int __stdcall +lpfu (const char *func, int ln, DWORD timeout) +{ + int rc; + DWORD t; + + debug_printf ("timeout %d, pinfo_mutex %p", timeout, pinfo_mutex); + t = (timeout == INFINITE) ? 10000 : timeout; + SetLastError(0); + while ((rc = WaitForSingleObject (pinfo_mutex, t)) != WAIT_OBJECT_0) + { + if (rc == WAIT_ABANDONED_0) + break; + system_printf ("%s:%d having problems getting lock", func, ln); + system_printf ("*** %s, rc %d, %E", cygwin_shared->p.lock_info, rc); + if (t == timeout) + break; + } + + __small_sprintf (cygwin_shared->p.lock_info, "%s(%d), pid %d ", func, ln, + (user_data && myself) ? (int)myself->dwProcessId : -1); + return rc; +} + +void +unlock_pinfo (void) +{ + + debug_printf ("handle %d", pinfo_mutex); + + if (!cygwin_shared->p.lock_info[0]) + system_printf ("lock_info not set?"); + else + strcat (cygwin_shared->p.lock_info, " unlocked"); + if (!ReleaseMutex (pinfo_mutex)) + system_printf ("ReleaseMutext (pinfo_mutex<%p>) failed, %E", pinfo_mutex); +} +#else +/* + * Code to lock/unlock the process table. + */ + +int __stdcall +lock_pinfo_for_update (DWORD timeout) +{ + DWORD rc; + DWORD t; + + debug_printf ("timeout %d, pinfo_mutex %p", timeout, pinfo_mutex); + t = (timeout == INFINITE) ? 10000 : timeout; + SetLastError(0); + while ((rc = WaitForSingleObject (pinfo_mutex, t)) != WAIT_OBJECT_0) + { + if (rc == WAIT_ABANDONED_0) + break; + system_printf ("rc %d, pinfo_mutex %p, %E", pinfo_mutex, rc); + if (t == timeout) + break; + if (rc == WAIT_FAILED) + /* sigh, must be properly fixed up later. */ + return rc; + Sleep(10); /* to prevent 100% CPU in those rare cases */ + } + + return (int)rc; +} + +void +unlock_pinfo (void) +{ + + debug_printf ("handle %d", pinfo_mutex); + + ReleaseMutex (pinfo_mutex); +} +#endif + + +/* Allocate a process table entry by finding an empty slot in the + fixed-size process table. We could use a linked list, but this + would probably be too slow. + + Try to allocate next_pid, incrementing next_pid and trying again + up to size() times at which point we reach the conclusion that + table is full. Eventually at this point we would grow the table + by size() and start over. If we find a pid to use, + + If all else fails, sweep through the loop looking for processes that + may have died abnormally without registering themselves as "dead". + Clear out these pinfo structures. Then scan the table again. + + Note that the process table is in the shared data space and thus + is susceptible to corruption. The amount of time spent scanning the + table is presumably quite small compared with the total time to + create a process. +*/ + +pinfo * +pinfo_list::allocate_pid (void) +{ + + pinfo *newp; + + lock_pinfo_for_update (INFINITE); + for (int tries = 0; ; tries++) + { + for (int i = next_pid; i < (next_pid + size ()); i++) + { + /* i mod size() gives place to check */ + newp = vec + (i % size()); + if (newp->process_state == PID_NOT_IN_USE) + { + debug_printf ("found empty slot %d for pid %d", + (i % size ()), i); + next_pid = i; + goto gotit; + } + } + + if (tries > 0) + break; + + /* try once to remove bogus dead processes */ + debug_printf ("clearing out deadwood"); + for (newp = vec; newp < vec + size(); newp++) + proc_exists (newp); + } + + /* The process table is full. */ + debug_printf ("process table is full"); + unlock_pinfo (); + + return NULL; + +gotit: + + /* Set new pid based on the position of this element in the pinfo list */ + newp->pid = next_pid; + + /* Determine next slot to consider, wrapping if we hit the end of + * the array. Since allocation involves looping through size () pids, + * don't allow next_pid to be greater than SHRT_MAX - size (). + */ + if (next_pid < (SHRT_MAX - size ())) + next_pid++; + else + next_pid = PBASE; + + newp->process_state = PID_IN_USE; + unlock_pinfo (); + + memset (newp, 0, PINFO_ZERO); + debug_printf ("pid %d, state %x", newp->pid, newp->process_state); + return newp; +} + +void +pinfo::record_death (int lock) +{ + int unlock = lock ? 0 : lock_pinfo_for_update (999); + if (dwProcessId == GetCurrentProcessId () && !my_parent_is_alive ()) + { + process_state = PID_NOT_IN_USE; + hProcess = NULL; + } + + if (unlock) + unlock_pinfo (); +} + +/* DOCTOOL-START + + + cygwin_winpid_to_pid + + + extern "C" pid_t + cygwin_winpid_to_pid + + int winpid + + + Given a windows pid, converts to the corresponding Cygwin +pid, if any. Returns -1 if windows pid does not correspond to +a cygwin pid. + + Example use of cygwin_winpid_to_pid + + extern "C" cygwin_winpid_to_pid (int winpid); + pid_t mypid; + mypid = cygwin_winpid_to_pid (windows_pid); + + + + + DOCTOOL-END */ + +extern "C" pid_t +cygwin_winpid_to_pid (int winpid) +{ + for (int i = 0; i < cygwin_shared->p.size (); i++) + { + pinfo *p = &cygwin_shared->p.vec[i]; + + if (p->process_state == PID_NOT_IN_USE) + continue; + + /* FIXME: signed vs unsigned comparison: winpid can be < 0 !!! */ + if (p->dwProcessId == (DWORD)winpid) + return p->pid; + } + + set_errno (ESRCH); + return (pid_t) -1; +} diff --git a/winsup/cygwin/pipe.cc b/winsup/cygwin/pipe.cc new file mode 100644 index 000000000..2ba99cd10 --- /dev/null +++ b/winsup/cygwin/pipe.cc @@ -0,0 +1,93 @@ +/* pipe.cc: pipe for WIN32. + + Copyright 1996, 1998, 1999 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include "winsup.h" + +static int +make_pipe (int fildes[2], unsigned int psize, int mode) +{ + SetResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK," make_pipe"); + + HANDLE r, w; + int fdr, fdw; + SECURITY_ATTRIBUTES *sa = (mode & O_NOINHERIT) ? &sec_none_nih : &sec_none; + + if ((fdr = dtable.find_unused_handle ()) < 0) + set_errno (ENMFILE); + else if ((fdw = dtable.find_unused_handle (fdr + 1)) < 0) + set_errno ( ENMFILE); + else if (!CreatePipe (&r, &w, sa, psize)) + __seterrno (); + else + { + fhandler_base *fhr = dtable.build_fhandler (fdr, FH_PIPE, "/dev/piper"); + fhandler_base *fhw = dtable.build_fhandler (fdw, FH_PIPE, "/dev/pipew"); + + int binmode = mode & O_TEXT ? 0 : 1; + fhr->init (r, GENERIC_READ, binmode); + fhw->init (w, GENERIC_WRITE, binmode); + if (mode & O_NOINHERIT) + { + fhr->set_close_on_exec_flag (1); + fhw->set_close_on_exec_flag (1); + } + + fildes[0] = fdr; + fildes[1] = fdw; + + debug_printf ("0 = pipe (%p) (%d:%p, %d:%p)", fildes, + fdr, fhr->get_handle (), fdw, fhw->get_handle ()); + + ReleaseResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK," make_pipe"); + return 0; + } + + syscall_printf ("-1 = pipe (%p)", fildes); + ReleaseResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK," make_pipe"); + return -1; +} + +extern "C" int +pipe (int filedes[2]) +{ + return make_pipe (filedes, 16384, (!__fmode || __fmode == O_BINARY) ? O_BINARY : O_TEXT); +} + +extern "C" int +_pipe (int filedes[2], unsigned int psize, int mode) +{ + int res = make_pipe (filedes, psize, mode); + /* This type of pipe is not interruptible so set the appropriate flag. */ + if (!res) + dtable[filedes[0]]->set_r_no_interrupt (1); + return res; +} + +int +dup (int fd) +{ + int res; + SetResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK," dup"); + + res = dup2 (fd, dtable.find_unused_handle ()); + + ReleaseResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK," dup"); + + return res; +} + +int +dup2 (int oldfd, int newfd) +{ + return dtable.dup2 (oldfd, newfd); +} diff --git a/winsup/cygwin/posix.sgml b/winsup/cygwin/posix.sgml new file mode 100644 index 000000000..5d00f5709 --- /dev/null +++ b/winsup/cygwin/posix.sgml @@ -0,0 +1,88 @@ + +Compatibility with POSIX.1 + +The following functions are compatible with POSIX.1: + +Process Primitives (Section 3) + +fork, execl, execle, execlp, execv, execve, execvp, wait, waitpid, +_exit, kill, sigemptyset, sigfillset, sigaddset, sigdelset, +sigismember, sigaction, pthread_sigmask, sigprocmask, sigpending, +sigsuspend, alarm, pause, sleep, pthread_kill, pthread_sigmask + +Process Environment (Section 4) + +getpid, getppid, getuid, geteuid, getgid, getegid, setuid, setgid, +getgroups, getlogin, getpgrp, setsid, setpgid, uname, time, times, +getenv, ctermid, ttyname, isatty, sysconf + +Files and Directories (Section 5) + +opendir, readdir, rewinddir, closedir, chdir, getcwd, open, creat, +umask, link, mkdir, unlink, rmdir, rename, stat, fstat, access, chmod, +fchmod, chown, utime, ftruncate, pathconf, fpathconf + +Input and Output Primitives (Section 6) + +pipe, dup, dup2, close, read, write, fcntl, lseek, fsync + +Device- and Class-Specific Functions (Section 7) + +cfgetispeed, cfgetospeed, cfsetispeed, cfsetospeed, tcdrain, tcflow, +tcflush, tcgetattr, tcgetpgrp, tcsendbreak, tcsetattr, tcsetpgrp + +Language-Specific Services for the C Programming Language (Section 8) + +abort, exit, fclose, fdopen, fflush, fgetc, fgets, fileno, fopen, +fprintf, fputc, fputs, fread, freopen, fscanf, fseek, ftell, fwrite, +getc, getchar, gets, perror, printf, putc, putchar, puts, remove, +rewind, scanf, setlocale, siglongjmp, sigsetjmp, tmpfile, tmpnam, +tzset + +System Databases (Section 9) + +getgrgid, getgrnam, getpwnam, getpwuid + +Synchronization (Section 11) + +sem_init, sem_destroy, sem_wait, sem_trywait, sem_post, +pthread_mutex_init, pthread_mutex_destroy, pthread_mutex_lock, +pthread_mutex_trylock, pthread_mutex_unlock + +Memory Management (Section 12) + +mmap, mprotect, msync, munmap + +Thread Management (Section 16) + +pthread_attr_init, pthread_attr_destroy, pthread_attr_setstacksize, +pthread_attr_getstacksize, pthread_create, pthread_exit, pthread_self, +pthread_equal + +Thread-Specific Data Functions (Section 17) + +pthread_key_create, pthread_setspecific, pthread_getspecific, +pthread_key_delete + + + +Implementation Details + +setuid and setgid +always return ENOSYS. + +link will copy the file if it can't +implement a true symbolic link. Currently, symbolic links work, if at +all, only under Windows NT. + +chown always returns zero. + +fcntl doesn't support F_GETLK - it returns +-1 and sets errno to ENOSYS. + +lseek only works properly on binary +files. + + + + \ No newline at end of file diff --git a/winsup/cygwin/profil.c b/winsup/cygwin/profil.c new file mode 100644 index 000000000..956519b4e --- /dev/null +++ b/winsup/cygwin/profil.c @@ -0,0 +1,173 @@ +/* profil.c -- win32 profil.c equivalent + + Copyright 1998 Cygnus Solutions. + + This file is part of Cygwin. + + This software is a copyrighted work licensed under the terms of the + Cygwin license. Please consult the file "CYGWIN_LICENSE" for + details. */ + +#include +#include +#include +#include +#include + +#include + +#define SLEEPTIME (1000 / PROF_HZ) + +/* global profinfo for profil() call */ +static struct profinfo prof; + +/* Get the pc for thread THR */ + +static u_long +get_thrpc (HANDLE thr) +{ + CONTEXT ctx; + u_long pc; + int res; + + res = SuspendThread (thr); + if (res == -1) + return (u_long) - 1; + ctx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; + pc = (u_long) - 1; + if (GetThreadContext (thr, &ctx)) + pc = ctx.Eip; + ResumeThread (thr); + return pc; +} + +/* Display cell of profile buffer */ +#if 0 +static void +print_prof (struct profinfo *p) +{ + printf ("profthr %x\ttarget thr %x\n", p->profthr, p->targthr); + printf ("pc: %x - %x\n", p->lowpc, p->highpc); + printf ("scale: %x\n", p->scale); + return; +} +#endif + +/* Everytime we wake up use the main thread pc to hash into the cell in the + profile buffer ARG. */ + +static DWORD CALLBACK +profthr_func (LPVOID arg) +{ + struct profinfo *p = (struct profinfo *) arg; + u_long pc, idx; + + for (;;) + { + pc = (u_long) get_thrpc (p->targthr); + if (pc >= p->lowpc && pc < p->highpc) + { + idx = PROFIDX (pc, p->lowpc, p->scale); + p->counter[idx]++; + } +#if 0 + print_prof (p); +#endif + Sleep (SLEEPTIME); + } + return 0; +} + +/* Stop profiling to the profiling buffer pointed to by P. */ + +static int +profile_off (struct profinfo *p) +{ + if (p->profthr) + { + TerminateThread (p->profthr, 0); + CloseHandle (p->profthr); + } + if (p->targthr) + CloseHandle (p->targthr); + return 0; +} + +/* Create a timer thread and pass it a pointer P to the profiling buffer. */ + +static int +profile_on (struct profinfo *p) +{ + int thrid; + + /* get handle for this thread */ + if (!DuplicateHandle (GetCurrentProcess (), GetCurrentThread (), + GetCurrentProcess (), &p->targthr, 0, FALSE, + DUPLICATE_SAME_ACCESS)) + { + errno = ESRCH; + return -1; + } + + p->profthr = CreateThread (0, 0, profthr_func, (void *) p, 0, &thrid); + if (!p->profthr) + { + CloseHandle (p->targthr); + p->targthr = 0; + errno = EAGAIN; + return -1; + } + return 0; +} + +/* + * start or stop profiling + * + * profiling goes into the SAMPLES buffer of size SIZE (which is treated + * as an array of u_shorts of size size/2) + * + * each bin represents a range of pc addresses from OFFSET. The number + * of pc addresses in a bin depends on SCALE. (A scale of 65536 maps + * each bin to two addresses, A scale of 32768 maps each bin to 4 addresses, + * a scale of 1 maps each bin to 128k addreses). Scale may be 1 - 65536, + * or zero to turn off profiling + */ +int +profile_ctl (struct profinfo * p, char *samples, size_t size, + u_long offset, u_int scale) +{ + u_long maxbin; + + if (scale > 65536) + { + errno = EINVAL; + return -1; + } + + profile_off (p); + if (scale) + { + memset (samples, 0, size); + memset (p, 0, sizeof *p); + maxbin = size >> 1; + prof.counter = (u_short *) samples; + prof.lowpc = offset; + prof.highpc = PROFADDR (maxbin, offset, scale); + prof.scale = scale; + + return profile_on (p); + } + return 0; +} + +/* Equivalent to unix profil() + Every SLEEPTIME interval, the user's program counter (PC) is examined: + offset is subtracted and the result is multiplied by scale. + The word pointed to by this address is incremented. Buf is unused. */ + +int +profil (char *samples, size_t size, u_long offset, u_int scale) +{ + return profile_ctl (&prof, samples, size, offset, scale); +} + diff --git a/winsup/cygwin/profil.h b/winsup/cygwin/profil.h new file mode 100644 index 000000000..c62f92251 --- /dev/null +++ b/winsup/cygwin/profil.h @@ -0,0 +1,44 @@ +/* profil.h: gprof profiling header file + + Copyright 1998 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +/* profiling frequency. (No larger than 1000) */ +#define PROF_HZ 100 + +/* convert an addr to an index */ +#define PROFIDX(pc, base, scale) \ + ({ \ + size_t i = (pc - base) / 2; \ + if (sizeof (unsigned long long int) > sizeof (size_t)) \ + i = (unsigned long long int) i * scale / 65536; \ + else \ + i = i / 65536 * scale + i % 65536 * scale / 65536; \ + i; \ + }) + +/* convert an index into an address */ +#define PROFADDR(idx, base, scale) \ + ((base) + ((((idx) << 16) / (scale)) << 1)) + +/* convert a bin size into a scale */ +#define PROFSCALE(range, bins) (((bins) << 16) / ((range) >> 1)) + +typedef void *_WINHANDLE; + +struct profinfo { + _WINHANDLE targthr; /* thread to profile */ + _WINHANDLE profthr; /* profiling thread */ + u_short *counter; /* profiling counters */ + u_long lowpc, highpc; /* range to be profiled */ + u_int scale; /* scale value of bins */ +}; + +int profile_ctl(struct profinfo *, char *, size_t, u_long, u_int); +int profil(char *, size_t, u_long, u_int); + diff --git a/winsup/cygwin/pthread.cc b/winsup/cygwin/pthread.cc new file mode 100644 index 000000000..f535318fe --- /dev/null +++ b/winsup/cygwin/pthread.cc @@ -0,0 +1,203 @@ +/* pthread.cc: posix pthread interface for Cygwin + + Copyright 1998 Cygnus Solutions. + + Written by Marco Fuykschot + + This file is part of Cygwin. + + This software is a copyrighted work licensed under the terms of the + Cygwin license. Please consult the file "CYGWIN_LICENSE" for + details. */ + +#include "winsup.h" + +extern "C" { +/* ThreadCreation */ +int +pthread_create (pthread_t * thread, const pthread_attr_t * attr, void *(*start_routine) (void *), void *arg) +{ + return __pthread_create (thread, attr, start_routine, arg); +} + +int +pthread_attr_init (pthread_attr_t * attr) +{ + return __pthread_attr_init (attr); +} + +int +pthread_attr_destroy (pthread_attr_t * attr) +{ + return __pthread_attr_destroy (attr); +} + +int +pthread_attr_setstacksize (pthread_attr_t * attr, size_t size) +{ + return __pthread_attr_setstacksize (attr, size); +} + +int +pthread_attr_getstacksize (pthread_attr_t * attr, size_t * size) +{ + return __pthread_attr_getstacksize (attr, size); +} + + +/* + pthread_attr_setstackaddr(...){}; + pthread_attr_getstackaddr(...){}; + */ + +/* Thread Exit */ +int +pthread_exit (void * value_ptr) +{ + return __pthread_exit (value_ptr); +} + +int +pthread_join(pthread_t thread, void **return_val) +{ + return __pthread_join(&thread, (void **)return_val); +} + +int +pthread_detach(pthread_t thread) +{ + return __pthread_detach(&thread); +} + +int +pthread_suspend(pthread_t thread) +{ + return __pthread_suspend(&thread); +} + +int +pthread_continue(pthread_t thread) +{ + return __pthread_continue(&thread); +} + +unsigned long +pthread_getsequence_np (pthread_t * thread) +{ + return __pthread_getsequence_np (thread); +} + +/* Thread SpecificData */ +int +pthread_key_create (pthread_key_t * key) +{ + return __pthread_key_create (key); +} + +int +pthread_key_delete (pthread_key_t * key) +{ + return __pthread_key_delete (key); +} + +int +pthread_setspecific (pthread_key_t * key, const void *value) +{ + return __pthread_setspecific (key, value); +} + +void * +pthread_getspecific (pthread_key_t * key) +{ + return (void *) __pthread_getspecific (key); +} + +/* Thread signal */ +int +pthread_kill (pthread_t * thread, int sig) +{ + return __pthread_kill (thread, sig); +} + +int +pthread_sigmask (int operation, const sigset_t * set, sigset_t * old_set) +{ + return __pthread_sigmask (operation, set, old_set); +} + +/* ID */ + +pthread_t +pthread_self () +{ + return __pthread_self (); +} + +int +pthread_equal (pthread_t t1, pthread_t t2) +{ + return __pthread_equal ( &t1, &t2); +} + +/* Mutexes */ +int +pthread_mutex_init (pthread_mutex_t * mutex, const pthread_mutexattr_t * attr) +{ + return __pthread_mutex_init (mutex, attr); +} + +int +pthread_mutex_lock (pthread_mutex_t * mutex) +{ + return __pthread_mutex_lock (mutex); +} + +int +pthread_mutex_trylock (pthread_mutex_t * mutex) +{ + return __pthread_mutex_trylock (mutex); +} + +int +pthread_mutex_unlock (pthread_mutex_t * mutex) +{ + return __pthread_mutex_unlock (mutex); +} + +int +pthread_mutex_destroy (pthread_mutex_t * mutex) +{ + return __pthread_mutex_destroy (mutex); +} + +/* Semaphores */ +int +sem_init (sem_t * sem, int pshared, unsigned int value) +{ + return __sem_init (sem, pshared, value); +} + +int +sem_destroy (sem_t * sem) +{ + return __sem_destroy (sem); +} + +int +sem_wait (sem_t * sem) +{ + return __sem_wait (sem); +} + +int +sem_trywait (sem_t * sem) +{ + return __sem_trywait (sem); +} + +int +sem_post (sem_t * sem) +{ + return __sem_post (sem); +} +} diff --git a/winsup/cygwin/regexp/COPYRIGHT b/winsup/cygwin/regexp/COPYRIGHT new file mode 100644 index 000000000..48b3f4339 --- /dev/null +++ b/winsup/cygwin/regexp/COPYRIGHT @@ -0,0 +1,22 @@ +This entire subtree is copyright the University of Toronto. +The following copyright notice applies to all files found here. None of +these files contain AT&T proprietary source code. +_____________________________________________________________________________ + + Copyright (c) 1986 by University of Toronto. + Written by Henry Spencer. Not derived from licensed software. + + Permission is granted to anyone to use this software for any + purpose on any computer system, and to redistribute it freely, + subject to the following restrictions: + + 1. The author is not responsible for the consequences of use of + this software, no matter how awful, even if they arise + from defects in it. + + 2. The origin of this software must not be misrepresented, either + by explicit claim or by omission. + + 3. Altered versions must be plainly marked as such, and must not + be misrepresented as being the original software. + diff --git a/winsup/cygwin/regexp/README b/winsup/cygwin/regexp/README new file mode 100644 index 000000000..37d6f51c7 --- /dev/null +++ b/winsup/cygwin/regexp/README @@ -0,0 +1,84 @@ +This is a nearly-public-domain reimplementation of the V8 regexp(3) package. +It gives C programs the ability to use egrep-style regular expressions, and +does it in a much cleaner fashion than the analogous routines in SysV. + + Copyright (c) 1986 by University of Toronto. + Written by Henry Spencer. Not derived from licensed software. + + Permission is granted to anyone to use this software for any + purpose on any computer system, and to redistribute it freely, + subject to the following restrictions: + + 1. The author is not responsible for the consequences of use of + this software, no matter how awful, even if they arise + from defects in it. + + 2. The origin of this software must not be misrepresented, either + by explicit claim or by omission. + + 3. Altered versions must be plainly marked as such, and must not + be misrepresented as being the original software. + +Barring a couple of small items in the BUGS list, this implementation is +believed 100% compatible with V8. It should even be binary-compatible, +sort of, since the only fields in a "struct regexp" that other people have +any business touching are declared in exactly the same way at the same +location in the struct (the beginning). + +This implementation is *NOT* AT&T/Bell code, and is not derived from licensed +software. Even though U of T is a V8 licensee. This software is based on +a V8 manual page sent to me by Dennis Ritchie (the manual page enclosed +here is a complete rewrite and hence is not covered by AT&T copyright). +The software was nearly complete at the time of arrival of our V8 tape. +I haven't even looked at V8 yet, although a friend elsewhere at U of T has +been kind enough to run a few test programs using the V8 regexp(3) to resolve +a few fine points. I admit to some familiarity with regular-expression +implementations of the past, but the only one that this code traces any +ancestry to is the one published in Kernighan & Plauger (from which this +one draws ideas but not code). + +Simplistically: put this stuff into a source directory, copy regexp.h into +/usr/include, inspect Makefile for compilation options that need changing +to suit your local environment, and then do "make r". This compiles the +regexp(3) functions, compiles a test program, and runs a large set of +regression tests. If there are no complaints, then put regexp.o, regsub.o, +and regerror.o into your C library, and regexp.3 into your manual-pages +directory. + +Note that if you don't put regexp.h into /usr/include *before* compiling, +you'll have to add "-I." to CFLAGS before compiling. + +The files are: + +Makefile instructions to make everything +regexp.3 manual page +regexp.h header file, for /usr/include +regexp.c source for regcomp() and regexec() +regsub.c source for regsub() +regerror.c source for default regerror() +regmagic.h internal header file +try.c source for test program +timer.c source for timing program +tests test list for try and timer + +This implementation uses nondeterministic automata rather than the +deterministic ones found in some other implementations, which makes it +simpler, smaller, and faster at compiling regular expressions, but slower +at executing them. In theory, anyway. This implementation does employ +some special-case optimizations to make the simpler cases (which do make +up the bulk of regular expressions actually used) run quickly. In general, +if you want blazing speed you're in the wrong place. Replacing the insides +of egrep with this stuff is probably a mistake; if you want your own egrep +you're going to have to do a lot more work. But if you want to use regular +expressions a little bit in something else, you're in luck. Note that many +existing text editors use nondeterministic regular-expression implementations, +so you're in good company. + +This stuff should be pretty portable, given appropriate option settings. +If your chars have less than 8 bits, you're going to have to change the +internal representation of the automaton, although knowledge of the details +of this is fairly localized. There are no "reserved" char values except for +NUL, and no special significance is attached to the top bit of chars. +The string(3) functions are used a fair bit, on the grounds that they are +probably faster than coding the operations in line. Some attempts at code +tuning have been made, but this is invariably a bit machine-specific. diff --git a/winsup/cygwin/regexp/regexp.h b/winsup/cygwin/regexp/regexp.h new file mode 100644 index 000000000..9e9cd9eb6 --- /dev/null +++ b/winsup/cygwin/regexp/regexp.h @@ -0,0 +1,24 @@ +/* + * Definitions etc. for regexp(3) routines. + * + * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof], + * not the System V one. + * + * $Id$ + */ + +#define NSUBEXP 10 +typedef struct regexp { + char *startp[NSUBEXP]; + char *endp[NSUBEXP]; + char regstart; /* Internal use only. */ + char reganch; /* Internal use only. */ + char *regmust; /* Internal use only. */ + int regmlen; /* Internal use only. */ + char program[1]; /* Unwarranted chumminess with compiler. */ +} regexp; + +extern regexp *regcomp(); +extern int regexec(); +extern void regsub(); +extern void regerror(); diff --git a/winsup/cygwin/regexp/regmagic.h b/winsup/cygwin/regexp/regmagic.h new file mode 100644 index 000000000..9eb4eaf96 --- /dev/null +++ b/winsup/cygwin/regexp/regmagic.h @@ -0,0 +1,7 @@ +/* $Id$ */ + +/* + * The first byte of the regexp internal "program" is actually this magic + * number; the start node begins in the second byte. + */ +#define MAGIC 0234 diff --git a/winsup/cygwin/registry.cc b/winsup/cygwin/registry.cc new file mode 100644 index 000000000..321b13fc9 --- /dev/null +++ b/winsup/cygwin/registry.cc @@ -0,0 +1,176 @@ +/* registry.cc: registry interface + + Copyright 1996, 1997, 1998, 1999 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include "winsup.h" + +char cygnus_class[] = "cygnus"; + +reg_key::reg_key (HKEY top, REGSAM access, ...) +{ + va_list av; + va_start (av, access); + build_reg (top, access, av); + va_end (av); +} + +reg_key::reg_key (REGSAM access, ...) +{ + va_list av; + + new (this) reg_key (HKEY_CURRENT_USER, access, "SOFTWARE", + CYGWIN_INFO_CYGNUS_REGISTRY_NAME, + CYGWIN_INFO_CYGWIN_REGISTRY_NAME, NULL); + + HKEY top = key; + va_start (av, access); + build_reg (top, KEY_READ, av); + va_end (av); + if (top != key) + RegCloseKey (top); +} + +reg_key::reg_key (REGSAM access) +{ + new (this) reg_key (HKEY_CURRENT_USER, access, "SOFTWARE", + CYGWIN_INFO_CYGNUS_REGISTRY_NAME, + CYGWIN_INFO_CYGWIN_REGISTRY_NAME, + CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME, NULL); +} + +void +reg_key::build_reg (HKEY top, REGSAM access, va_list av) +{ + char *name; + HKEY r = top; + + /* FIXME: Most of the time a valid mount area should exist. Perhaps + we should just try an open of the correct key first and only resort + to this method in the unlikely situation that it's the first time + the current mount areas are being used. */ + + while ((name = va_arg (av, char *)) != NULL) + { + DWORD disp; + int res = RegCreateKeyExA (r, + name, + 0, + cygnus_class, + REG_OPTION_NON_VOLATILE, + access, + &sec_none_nih, + &key, + &disp); + if (r != top) + RegCloseKey (r); + r = key; + if (res != ERROR_SUCCESS) + { + key = (HKEY) INVALID_HANDLE_VALUE; + debug_printf ("failed to create key %s in the registry", name); + break; + } + + /* If we're considering the mounts key, check if it had to + be created and set had_to_create appropriately. */ + if (strcmp (name, CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME) == 0) + if (disp == REG_CREATED_NEW_KEY) + cygwin_shared->mount.had_to_create_mount_areas++; + } +} + +/* Given the current registry key, return the specific int value + requested. Return def on failure. */ + +int +reg_key::get_int (const char *name, int def) +{ + DWORD type; + DWORD dst; + DWORD size = sizeof (dst); + + LONG res = RegQueryValueExA (key, + name, + 0, + &type, + (unsigned char *) &dst, &size); + + if (type != REG_DWORD || res != ERROR_SUCCESS) + return def; + + return dst; +} + +/* Given the current registry key, set a specific int value. */ + +int +reg_key::set_int (const char *name, int val) +{ + DWORD value = val; + return (int) RegSetValueExA (key, name, 0, REG_DWORD, + (unsigned char *) &value, sizeof (value)); +} + +/* Given the current registry key, return the specific string value + requested. Return zero on success, non-zero on failure. */ + +int +reg_key::get_string (const char *name, char *dst, size_t max, const char * def) +{ + DWORD size = max; + DWORD type; + LONG res = RegQueryValueExA (key, name, 0, &type, (unsigned char *) dst, + &size); + + if ((def != 0) && ((type != REG_SZ) || (res != ERROR_SUCCESS))) + { + strcpy (dst, def); + } + return (int) res; +} + +/* Given the current registry key, set a specific string value. */ + +int +reg_key::set_string (const char *name, const char *src) +{ + return (int) RegSetValueExA (key, name, 0, REG_SZ, (unsigned char*) src, + strlen (src) + 1); +} + +int +reg_key::setone_string (const char *src, const char *name) +{ + return (int) RegSetValueExA (key, name, 0, REG_SZ, + (const unsigned char *) src, strlen (src) + 1); +} + +/* Return the handle to key. */ + +HKEY +reg_key::get_key () +{ + return key; +} + +/* Delete subkey of current key. Returns the error code from the + RegDeleteKeyA invocation. */ + +int +reg_key::kill (const char *name) +{ + return RegDeleteKeyA (key, name); +} + +reg_key::~reg_key () +{ + if (key != (HKEY) INVALID_HANDLE_VALUE) + RegCloseKey (key); + key = (HKEY) INVALID_HANDLE_VALUE; +} diff --git a/winsup/cygwin/resource.cc b/winsup/cygwin/resource.cc new file mode 100644 index 000000000..9f1f46c1c --- /dev/null +++ b/winsup/cygwin/resource.cc @@ -0,0 +1,94 @@ +/* resource.cc: getrusage () and friends. + + Copyright 1996, 1997, 1998, 2000 Cygnus Solutions. + + Written by Steve Chamberlain (sac@cygnus.com), Doug Evans (dje@cygnus.com), + Geoffrey Noer (noer@cygnus.com) of Cygnus Support. + Rewritten by Sergey S. Okhapkin (sos@prospect.com.ru) + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include "winsup.h" + +/* add timeval values */ +static void +add_timeval (struct timeval *tv1, struct timeval *tv2) +{ + tv1->tv_sec += tv2->tv_sec; + tv1->tv_usec += tv2->tv_usec; + if (tv1->tv_usec >= 1000000) + { + tv1->tv_usec -= 1000000; + tv1->tv_sec++; + } +} + +/* add rusage values of r2 to r1 */ +void __stdcall +add_rusage (struct rusage *r1, struct rusage *r2) +{ + add_timeval (&r1->ru_utime, &r2->ru_utime); + add_timeval (&r1->ru_stime, &r2->ru_stime); + r1->ru_maxrss += r2->ru_maxrss; + r1->ru_ixrss += r2->ru_ixrss; + r1->ru_idrss += r2->ru_idrss; + r1->ru_isrss += r2->ru_isrss; + r1->ru_minflt += r2->ru_minflt; + r1->ru_majflt += r2->ru_majflt; + r1->ru_nswap += r2->ru_nswap; + r1->ru_inblock += r2->ru_inblock; + r1->ru_oublock += r2->ru_oublock; + r1->ru_msgsnd += r2->ru_msgsnd; + r1->ru_msgrcv += r2->ru_msgrcv; + r1->ru_nsignals += r2->ru_nsignals; + r1->ru_nvcsw += r2->ru_nvcsw; + r1->ru_nivcsw += r2->ru_nivcsw; +} + +/* FIXME: what about other fields? */ +void __stdcall +fill_rusage (struct rusage *r, HANDLE h) +{ + FILETIME creation_time = {0,0}; + FILETIME exit_time = {0,0}; + FILETIME kernel_time = {0,0}; + FILETIME user_time = {0,0}; + + struct timeval tv; + + GetProcessTimes (h, &creation_time, &exit_time, &kernel_time, &user_time); + totimeval (&tv, &kernel_time, 0, 0); + add_timeval (&r->ru_stime, &tv); + totimeval (&tv, &user_time, 0, 0); + add_timeval (&r->ru_utime, &tv); +} + +extern "C" +int +getrusage (int intwho, struct rusage *rusage_in) +{ + int res = 0; + struct rusage r; + + if (intwho == RUSAGE_SELF) + { + memset (&r, 0, sizeof (r)); + fill_rusage (&r, hMainProc); + *rusage_in = r; + } + else if (intwho == RUSAGE_CHILDREN) + *rusage_in = myself->rusage_children; + else + { + set_errno (EINVAL); + res = -1; + } + + syscall_printf ("%d = getrusage (%d, %p)", res, intwho, rusage_in); + return res; +} diff --git a/winsup/cygwin/scandir.cc b/winsup/cygwin/scandir.cc new file mode 100644 index 000000000..bbe582f12 --- /dev/null +++ b/winsup/cygwin/scandir.cc @@ -0,0 +1,101 @@ +/* scandir.cc + + Copyright 1998 Cygnus Solutions. + + Written by Corinna Vinschen + + This file is part of Cygwin. + + This software is a copyrighted work licensed under the terms of the + Cygwin license. Please consult the file "CYGWIN_LICENSE" for + details. */ + +#include +#include +#include +#include +#include "winsup.h" + +extern "C" +int +scandir (const char *dir, + struct dirent ***namelist, + int (*select) (const struct dirent *), + int (*compar) (const struct dirent **, const struct dirent **)) +{ + DIR *dirp; + struct dirent *ent, *etmp, **nl = NULL, **ntmp; + int count = 0; + int allocated = 0; + + if (!(dirp = opendir (dir))) + return -1; + + int prior_errno = get_errno (); + set_errno (0); + + while ((ent = readdir (dirp))) + { + if (!select || select (ent)) + { + + /* Ignore error from readdir/select. See POSIX specs. */ + set_errno (0); + + if (count == allocated) + { + + if (allocated == 0) + allocated = 10; + else + allocated *= 2; + + ntmp = (struct dirent **) realloc (nl, allocated * sizeof *nl); + if (!ntmp) + { + set_errno (ENOMEM); + break; + } + nl = ntmp; + } + + if (!(etmp = (struct dirent *) malloc (sizeof *ent))) + { + set_errno (ENOMEM); + break; + } + *etmp = *ent; + nl[count++] = etmp; + } + } + + if ((prior_errno = get_errno ()) != 0) + { + closedir (dirp); + if (nl) + { + while (count > 0) + free (nl[--count]); + free (nl); + } + /* Ignore errors from closedir() and what not else. */ + set_errno (prior_errno); + return -1; + } + + closedir (dirp); + set_errno (prior_errno); + + qsort (nl, count, sizeof *nl, (int (*)(const void *, const void *)) compar); + if (namelist) + *namelist = nl; + return count; +} + +extern "C" +int +alphasort (const struct dirent **a, const struct dirent **b) +{ + return strcoll ((*a)->d_name, (*b)->d_name); +} + diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc new file mode 100644 index 000000000..df62f1a7d --- /dev/null +++ b/winsup/cygwin/security.cc @@ -0,0 +1,2084 @@ +/* security.cc: NT security functions + + Copyright 1997, 1998, 1999, 2000 Cygnus Solutions. + + Originaly written by Gunther Ebert, gunther.ebert@ixos-leipzig.de + Extensions by Corinna Vinschen + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "winsup.h" +#include + +#define MAX_SID_LEN 40 + +extern BOOL allow_ntea; +BOOL allow_ntsec = FALSE; + +SID_IDENTIFIER_AUTHORITY sid_auth[] = { + {SECURITY_NULL_SID_AUTHORITY}, + {SECURITY_WORLD_SID_AUTHORITY}, + {SECURITY_LOCAL_SID_AUTHORITY}, + {SECURITY_CREATOR_SID_AUTHORITY}, + {SECURITY_NON_UNIQUE_AUTHORITY}, + {SECURITY_NT_AUTHORITY} +}; + +#define DONT_INHERIT (0) +#define INHERIT_ALL (CONTAINER_INHERIT_ACE|OBJECT_INHERIT_ACE) +#define INHERIT_ONLY (INHERIT_ONLY_ACE|CONTAINER_INHERIT_ACE|OBJECT_INHERIT_ACE) + +PSID +get_sid (PSID psid, DWORD s, DWORD cnt, DWORD *r) +{ + DWORD i; + + if (! psid || s > 5 || cnt < 1 || cnt > 8) + return NULL; + + InitializeSid(psid, &sid_auth[s], cnt); + for (i = 0; i < cnt; ++i) + memcpy ((char *) psid + 8 + sizeof (DWORD) * i, &r[i], sizeof (DWORD)); + return psid; +} + +PSID +get_ssid (PSID psid, const char *sid_str) +{ + char sid_buf[256]; + char *t; + DWORD cnt = 0; + DWORD s = 0; + DWORD i, r[8]; + + if (! sid_str || strncmp (sid_str, "S-1-", 4)) + return NULL; + + strcpy (sid_buf, sid_str); + + for (t = sid_buf + 4, i = 0; cnt < 8 && (t = strtok (t, "-")); t = NULL, ++i) + if (i == 0) + s = strtoul (t, NULL, 10); + else + r[cnt++] = strtoul (t, NULL, 10); + + return get_sid (psid, s, cnt, r); +} + +BOOL +get_pw_sid (PSID sid, struct passwd *pw) +{ + char *sp = strrchr (pw->pw_gecos, ','); + + if (!sp) + return FALSE; + return get_ssid (sid, ++sp) != NULL; +} + +BOOL +get_gr_sid (PSID sid, struct group *gr) +{ + return get_ssid (sid, gr->gr_passwd) != NULL; +} + +PSID +get_admin_sid () +{ + static NO_COPY char admin_sid_buf[MAX_SID_LEN]; + static NO_COPY PSID admin_sid = NULL; + + if (!admin_sid) + { + admin_sid = (PSID) admin_sid_buf; + get_ssid (admin_sid, "S-1-5-32-544"); + } + return admin_sid; +} + +PSID +get_system_sid () +{ + static NO_COPY char system_sid_buf[MAX_SID_LEN]; + static NO_COPY PSID system_sid = NULL; + + if (!system_sid) + { + system_sid = (PSID) system_sid_buf; + get_ssid (system_sid, "S-1-5-18"); + } + return system_sid; +} + +PSID +get_creator_owner_sid () +{ + static NO_COPY char owner_sid_buf[MAX_SID_LEN]; + static NO_COPY PSID owner_sid = NULL; + + if (!owner_sid) + { + owner_sid = (PSID) owner_sid_buf; + get_ssid (owner_sid, "S-1-3-0"); + } + return owner_sid; +} + +PSID +get_world_sid () +{ + static NO_COPY char world_sid_buf[MAX_SID_LEN]; + static NO_COPY PSID world_sid = NULL; + + if (!world_sid) + { + world_sid = (PSID) world_sid_buf; + get_ssid (world_sid, "S-1-1-0"); + } + return world_sid; +} + +int passwd_sem = 0; +int group_sem = 0; + +static int +get_id_from_sid (PSID psid, BOOL search_grp, int *type) +{ + if (!IsValidSid (psid)) + { + __seterrno (); + small_printf ("IsValidSid failed with %E"); + return -1; + } + + /* First try to get SID from passwd or group entry */ + if (allow_ntsec) + { + char sidbuf[MAX_SID_LEN]; + PSID sid = (PSID) sidbuf; + int id = -1; + + if (! search_grp) + { + if (passwd_sem > 0) + return 0; + ++passwd_sem; + + struct passwd *pw; + while ((pw = getpwent ()) != NULL) + { + if (get_pw_sid (sid, pw) && EqualSid (psid, sid)) + { + id = pw->pw_uid; + break; + } + } + endpwent (); + --passwd_sem; + if (id >= 0) + { + if (type) + *type = USER; + return id; + } + } + if (search_grp || type) + { + if (group_sem > 0) + return 0; + ++group_sem; + + struct group *gr; + while ((gr = getgrent ()) != NULL) + { + if (get_gr_sid (sid, gr) && EqualSid (psid, sid)) + { + id = gr->gr_gid; + break; + } + } + endgrent (); + --group_sem; + if (id >= 0) + { + if (type) + *type = GROUP; + return id; + } + } + } + + /* We use the RID as default UID/GID */ + int id = *GetSidSubAuthority(psid, *GetSidSubAuthorityCount(psid) - 1); + + /* + * The RID maybe -1 if accountname == computername. + * In this case we search for the accountname in the passwd and group files. + * If type is needed, we search in each case. + */ + if (id == -1 || type) + { + char account[MAX_USER_NAME]; + char domain[MAX_COMPUTERNAME_LENGTH+1]; + DWORD acc_len = MAX_USER_NAME; + DWORD dom_len = MAX_COMPUTERNAME_LENGTH+1; + SID_NAME_USE acc_type; + + if (!LookupAccountSid (NULL, psid, account, &acc_len, + domain, &dom_len, &acc_type)) + { + __seterrno (); + return -1; + } + + switch (acc_type) + { + case SidTypeGroup: + case SidTypeAlias: + case SidTypeWellKnownGroup: + if (type) + *type = GROUP; + if (id == -1) + { + struct group *gr = getgrnam (account); + if (gr) + id = gr->gr_gid; + } + break; + case SidTypeUser: + if (type) + *type = USER; + if (id == -1) + { + struct passwd *pw = getpwnam (account); + if (pw) + id = pw->pw_uid; + } + break; + default: + break; + } + } + if (id == -1) + id = getuid (); + return id; +} + +int +get_id_from_sid (PSID psid, BOOL search_grp) +{ + return get_id_from_sid (psid, search_grp, NULL); +} + +static BOOL +legal_sid_type (SID_NAME_USE type) +{ + return type == SidTypeUser || type == SidTypeGroup + || SidTypeAlias || SidTypeWellKnownGroup; +} + +BOOL +is_grp_member (uid_t uid, gid_t gid) +{ + extern int getgroups (int, gid_t *, gid_t, const char *); + BOOL grp_member = TRUE; + + if (!group_sem && !passwd_sem) + { + struct passwd *pw = getpwuid (uid); + gid_t grps[NGROUPS_MAX]; + int cnt = getgroups (NGROUPS_MAX, grps, + pw ? pw->pw_gid : myself->gid, + pw ? pw->pw_name : myself->username); + int i; + for (i = 0; i < cnt; ++i) + if (grps[i] == gid) + break; + grp_member = (i < cnt); + } + return grp_member; +} + +BOOL +lookup_name (const char *name, const char *logsrv, PSID ret_sid) +{ + char sidbuf[MAX_SID_LEN]; + PSID sid = (PSID) sidbuf; + DWORD sidlen; + char domuser[MAX_COMPUTERNAME_LENGTH+MAX_USER_NAME+1]; + char dom[MAX_COMPUTERNAME_LENGTH+1]; + DWORD domlen; + SID_NAME_USE acc_type; + + debug_printf ("name : %s", name ? name : "NULL"); + + if (! name) + return FALSE; + + if (logsrv && *logsrv) + { + if (LookupAccountName (logsrv, name, + sid, (sidlen = MAX_SID_LEN, &sidlen), + dom, (domlen = MAX_COMPUTERNAME_LENGTH, &domlen), + &acc_type) + && legal_sid_type (acc_type)) + goto got_it; + if (acc_type == SidTypeDomain) + { + strcat (strcat (strcpy (domuser, dom), "\\"), name); + if (LookupAccountName (logsrv, domuser, + sid,(sidlen = MAX_SID_LEN, &sidlen), + dom,(domlen = MAX_COMPUTERNAME_LENGTH,&domlen), + &acc_type)) + goto got_it; + } + } + if (LookupAccountName (NULL, name, + sid, (sidlen = MAX_SID_LEN, &sidlen), + dom, (domlen = 100, &domlen), + &acc_type) + && legal_sid_type (acc_type)) + goto got_it; + if (acc_type == SidTypeDomain) + { + strcat (strcat (strcpy (domuser, dom), "\\"), name); + if (LookupAccountName (NULL, domuser, + sid, (sidlen = MAX_SID_LEN, &sidlen), + dom, (domlen = MAX_COMPUTERNAME_LENGTH, &domlen), + &acc_type)) + goto got_it; + } + debug_printf ("LookupAccountName(%s) %E", name); + __seterrno (); + return FALSE; + +got_it: + debug_printf ("sid : [%d]", *GetSidSubAuthority((PSID) sid, + *GetSidSubAuthorityCount((PSID) sid) - 1)); + + if (ret_sid) + memcpy (ret_sid, sid, sidlen); + + return TRUE; +} + +/* ReadSD reads a security descriptor from a file. + In case of error, -1 is returned and errno is set. + If the file doesn't have a SD, 0 is returned. + Otherwise, the size of the SD is returned and + the SD is copied to the buffer, pointed to by sdBuf. + sdBufSize contains the size of the buffer. If + it's too small, to contain the complete SD, 0 is + returned and sdBufSize is set to the needed size + of the buffer. +*/ + +LONG +ReadSD(const char *file, PSECURITY_DESCRIPTOR sdBuf, LPDWORD sdBufSize) +{ + /* Check parameters */ + if (! sdBufSize) + { + set_errno (EINVAL); + return -1; + } + + /* Open file for read */ + HANDLE hFile = CreateFile (file, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + &sec_none_nih, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, + NULL); + + if (hFile == INVALID_HANDLE_VALUE) + { + __seterrno (); + return -1; + } + + /* step through the backup streams and search for the security data */ + WIN32_STREAM_ID header; + DWORD bytes_read = 0; + LPVOID context = NULL; + PSECURITY_DESCRIPTOR psd = NULL; + DWORD datasize; + LONG ret = 0; + + while (BackupRead (hFile, (LPBYTE) &header, + 3 * sizeof (DWORD) + sizeof (LARGE_INTEGER), + &bytes_read, FALSE, TRUE, &context)) + { + if (header.dwStreamId != BACKUP_SECURITY_DATA) + continue; + + /* security data found */ + datasize = header.Size.LowPart + header.dwStreamNameSize; + char b[datasize]; + + if (! BackupRead (hFile, (LPBYTE) b, datasize, &bytes_read, + FALSE, TRUE, &context)) + { + __seterrno (); + ret = -1; + break; + } + + /* Check validity of the SD */ + psd = (PSECURITY_DESCRIPTOR) &b[header.dwStreamNameSize]; + if (! IsValidSecurityDescriptor (psd)) + continue; + + /* It's a valid SD */ + datasize -= header.dwStreamNameSize; + debug_printf ("SD-Size: %d", datasize); + + /* buffer to small? */ + if (*sdBufSize < datasize) + { + *sdBufSize = datasize; + ret = 0; + break; + } + + if (sdBuf) + memcpy (sdBuf, psd, datasize); + + ret = *sdBufSize = datasize; + break; + + } + BackupRead (hFile, NULL, 0, &bytes_read, TRUE, TRUE, &context); + CloseHandle (hFile); + return ret; +} + +LONG +WriteSD(const char *file, PSECURITY_DESCRIPTOR sdBuf, DWORD sdBufSize) +{ + /* Check parameters */ + if (! sdBuf || ! sdBufSize) + { + set_errno (EINVAL); + return -1; + } + + HANDLE hFile = CreateFile (file, + WRITE_OWNER | WRITE_DAC, + FILE_SHARE_READ | FILE_SHARE_WRITE, + &sec_none_nih, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, + NULL); + + if (hFile == INVALID_HANDLE_VALUE) + { + __seterrno (); + return -1; + } + + LPVOID context = NULL; + DWORD bytes_written = 0; + WIN32_STREAM_ID header; + + memset (&header, 0, sizeof (header)); + /* write new security info header */ + header.dwStreamId = BACKUP_SECURITY_DATA; + header.dwStreamAttributes = STREAM_CONTAINS_SECURITY; + header.Size.HighPart = 0; + header.Size.LowPart = sdBufSize; + header.dwStreamNameSize = 0; + if (!BackupWrite (hFile, (LPBYTE) &header, + 3 * sizeof (DWORD) + sizeof (LARGE_INTEGER), + &bytes_written, FALSE, TRUE, &context)) + { + __seterrno (); + CloseHandle (hFile); + return -1; + } + + /* write new security descriptor */ + if (!BackupWrite (hFile, (LPBYTE) sdBuf, + header.Size.LowPart + header.dwStreamNameSize, + &bytes_written, FALSE, TRUE, &context)) + { + /* Samba returns ERROR_NOT_SUPPORTED. + FAT returns ERROR_INVALID_SECURITY_DESCR. + This shouldn't return as error, but better be ignored. */ + DWORD ret = GetLastError (); + if (ret != ERROR_NOT_SUPPORTED && ret != ERROR_INVALID_SECURITY_DESCR) + { + __seterrno (); + BackupWrite (hFile, NULL, 0, &bytes_written, TRUE, TRUE, &context); + CloseHandle (hFile); + return -1; + } + } + + /* terminate the restore process */ + BackupWrite (hFile, NULL, 0, &bytes_written, TRUE, TRUE, &context); + CloseHandle (hFile); + return 0; +} + +static int +set_process_privileges () +{ + HANDLE hProcess = NULL; + HANDLE hToken = NULL; + LUID restore_priv; + LUID backup_priv; + char buf[sizeof (TOKEN_PRIVILEGES) + 2 * sizeof (LUID_AND_ATTRIBUTES)]; + TOKEN_PRIVILEGES *new_priv = (TOKEN_PRIVILEGES *) buf; + int ret = -1; + + hProcess = OpenProcess (PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId ()); + if (! hProcess) + { + __seterrno (); + goto out; + } + + if (! OpenProcessToken (hProcess, + TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, + &hToken)) + { + __seterrno (); + goto out; + } + + if (! LookupPrivilegeValue (NULL, SE_RESTORE_NAME, &restore_priv)) + { + __seterrno (); + goto out; + } + if (! LookupPrivilegeValue (NULL, SE_BACKUP_NAME, &backup_priv)) + { + __seterrno (); + goto out; + } + + new_priv->PrivilegeCount = 2; + new_priv->Privileges[0].Luid = restore_priv; + new_priv->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + new_priv->Privileges[1].Luid = backup_priv; + new_priv->Privileges[1].Attributes = SE_PRIVILEGE_ENABLED; + + if (! AdjustTokenPrivileges (hToken, FALSE, new_priv, 0, NULL, NULL)) + { + __seterrno (); + goto out; + } + + ret = 0; + + if (ret == -1) + __seterrno (); + +out: + if (hToken) + CloseHandle (hToken); + if (hProcess) + CloseHandle (hProcess); + + syscall_printf ("%d = set_process_privileges ()", ret); + return ret; +} + +static int +get_nt_attribute (const char *file, int *attribute) +{ + if (os_being_run != winNT) + return 0; + + syscall_printf ("file: %s", file); + + if (set_process_privileges () < 0) + return -1; + + /* Yeah, sounds too much, but I've seen SDs of 2100 bytes! */ + DWORD sd_size = 4096; + char sd_buf[4096]; + PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf; + + int ret; + if ((ret = ReadSD (file, psd, &sd_size)) <= 0) + { + debug_printf ("ReadSD %E"); + return ret; + } + + PSID owner_sid; + PSID group_sid; + BOOL dummy; + + if (! GetSecurityDescriptorOwner (psd, &owner_sid, &dummy)) + debug_printf ("GetSecurityDescriptorOwner %E"); + if (! GetSecurityDescriptorGroup (psd, &group_sid, &dummy)) + debug_printf ("GetSecurityDescriptorGroup %E"); + + PACL acl; + BOOL acl_exists; + + if (! GetSecurityDescriptorDacl (psd, &acl_exists, &acl, &dummy)) + { + __seterrno (); + debug_printf ("GetSecurityDescriptorDacl %E"); + return -1; + } + + if (! acl_exists || ! acl) + { + *attribute |= S_IRWXU | S_IRWXG | S_IRWXO; + syscall_printf ("file: %s No ACL = %x", file, *attribute); + return 0; + } + + BOOL grp_member = is_grp_member (get_uid_from_sid (owner_sid), + get_gid_from_sid (group_sid)); + + ACCESS_ALLOWED_ACE *ace; + int allow = 0; + int deny = 0; + int *flags, *anti; + + for (DWORD i = 0; i < acl->AceCount; ++i) + { + if (!GetAce (acl, i, (PVOID *) &ace)) + continue; + if (ace->Header.AceFlags & INHERIT_ONLY_ACE) + continue; + switch (ace->Header.AceType) + { + case ACCESS_ALLOWED_ACE_TYPE: + flags = &allow; + anti = &deny; + break; + case ACCESS_DENIED_ACE_TYPE: + flags = &deny; + anti = &allow; + break; + default: + continue; + } + + PSID ace_sid = (PSID) &ace->SidStart; + if (owner_sid && EqualSid (ace_sid, owner_sid)) + { + if (ace->Mask & FILE_READ_DATA) + *flags |= S_IRUSR; + if (ace->Mask & FILE_WRITE_DATA) + *flags |= S_IWUSR; + if (ace->Mask & FILE_EXECUTE) + *flags |= S_IXUSR; + } + else if (group_sid && EqualSid (ace_sid, group_sid)) + { + if (ace->Mask & FILE_READ_DATA) + *flags |= S_IRGRP + | ((grp_member && !(*anti & S_IRUSR)) ? S_IRUSR : 0); + if (ace->Mask & FILE_WRITE_DATA) + *flags |= S_IWGRP + | ((grp_member && !(*anti & S_IWUSR)) ? S_IWUSR : 0); + if (ace->Mask & FILE_EXECUTE) + *flags |= S_IXGRP + | ((grp_member && !(*anti & S_IXUSR)) ? S_IXUSR : 0); + } + else if (EqualSid (ace_sid, get_world_sid ())) + { + if (ace->Mask & FILE_READ_DATA) + *flags |= S_IROTH + | ((!(*anti & S_IRGRP)) ? S_IRGRP : 0) + | ((!(*anti & S_IRUSR)) ? S_IRUSR : 0); + if (ace->Mask & FILE_WRITE_DATA) + *flags |= S_IWOTH + | ((!(*anti & S_IWGRP)) ? S_IWGRP : 0) + | ((!(*anti & S_IWUSR)) ? S_IWUSR : 0); + if (ace->Mask & FILE_EXECUTE) + { + *flags |= S_IXOTH + | ((!(*anti & S_IXGRP)) ? S_IXGRP : 0) + | ((!(*anti & S_IXUSR)) ? S_IXUSR : 0); + // Sticky bit for directories according to linux rules. + // No sense for files. + if (! (ace->Mask & FILE_DELETE_CHILD) + && S_ISDIR(*attribute) + && !(*anti & S_ISVTX)) + *flags |= S_ISVTX; + } + } + } + *attribute &= ~(S_IRWXU|S_IRWXG|S_IRWXO|S_ISVTX); + *attribute |= allow; + *attribute &= ~deny; + syscall_printf ("file: %s %x", file, *attribute); + return 0; +} + +int +get_file_attribute (int use_ntsec, const char *file, int *attribute) +{ + if (!attribute) + { + set_errno (EINVAL); + return -1; + } + + int res; + + if (use_ntsec && allow_ntsec) + { + res = get_nt_attribute (file, attribute); + if (!res) + return 0; + } + + res = NTReadEA (file, ".UNIXATTR", (char *) attribute, sizeof (*attribute)); + + // symlinks are anything for everyone! + if ((*attribute & S_IFLNK) == S_IFLNK) + *attribute |= S_IRWXU | S_IRWXG | S_IRWXO; + + if (res > 0) + return 0; + set_errno (ENOSYS); + return -1; +} + +BOOL add_access_allowed_ace (PACL acl, int offset, DWORD attributes, + PSID sid, size_t &len_add, DWORD inherit) +{ + if (! AddAccessAllowedAce (acl, ACL_REVISION, attributes, sid)) + { + __seterrno (); + return FALSE; + } + ACCESS_ALLOWED_ACE *ace; + if (GetAce(acl, offset, (PVOID *) &ace)) + ace->Header.AceFlags |= inherit; + len_add += sizeof (ACCESS_DENIED_ACE) - sizeof (DWORD) + + GetLengthSid (sid); + return TRUE; +} + +BOOL add_access_denied_ace (PACL acl, int offset, DWORD attributes, + PSID sid, size_t &len_add, DWORD inherit) +{ + if (! AddAccessDeniedAce (acl, ACL_REVISION, attributes, sid)) + { + __seterrno (); + return FALSE; + } + ACCESS_DENIED_ACE *ace; + if (GetAce(acl, offset, (PVOID *) &ace)) + ace->Header.AceFlags |= inherit; + len_add += sizeof (ACCESS_DENIED_ACE) - sizeof (DWORD) + + GetLengthSid (sid); + return TRUE; +} + +PSECURITY_DESCRIPTOR +alloc_sd (uid_t uid, gid_t gid, const char *logsrv, int attribute, + PSECURITY_DESCRIPTOR sd_ret, DWORD *sd_size_ret) +{ + BOOL dummy; + + if (os_being_run != winNT) + return NULL; + + if (! sd_ret || ! sd_size_ret) + { + set_errno (EINVAL); + return NULL; + } + + // Get SID and name of new owner + char owner[MAX_USER_NAME]; + char *owner_sid_buf[MAX_SID_LEN]; + PSID owner_sid = NULL; + struct passwd *pw = getpwuid (uid); + strcpy (owner, pw ? pw->pw_name : getlogin ()); + owner_sid = (PSID) owner_sid_buf; + if ((! pw || ! get_pw_sid (owner_sid, pw)) + && ! lookup_name (owner, logsrv, owner_sid)) + return NULL; + debug_printf ("owner: %s [%d]", owner, + *GetSidSubAuthority((PSID) owner_sid, + *GetSidSubAuthorityCount((PSID) owner_sid) - 1)); + + // Get SID and name of new group + char *group_sid_buf[MAX_SID_LEN]; + PSID group_sid = NULL; + struct group *grp = getgrgid (gid); + if (grp) + { + group_sid = (PSID) group_sid_buf; + if ((! grp || ! get_gr_sid (group_sid, grp)) + && ! lookup_name (grp->gr_name, logsrv, group_sid)) + return NULL; + } + else + debug_printf ("no group"); + + // Initialize local security descriptor + SECURITY_DESCRIPTOR sd; + PSECURITY_DESCRIPTOR psd = NULL; + if (! InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION)) + { + __seterrno (); + return NULL; + } + + if (! SetSecurityDescriptorOwner(&sd, owner_sid, FALSE)) + { + __seterrno (); + return NULL; + } + if (group_sid + && ! SetSecurityDescriptorGroup(&sd, group_sid, FALSE)) + { + __seterrno (); + return NULL; + } + + // Initialize local access control list + char acl_buf[3072]; + PACL acl = (PACL) acl_buf; + if (! InitializeAcl (acl, 3072, ACL_REVISION)) + { + __seterrno (); + return NULL; + } + + // VTX bit may only be set if executable for `other' is set. + // For correct handling under WinNT, FILE_DELETE_CHILD has to + // be (un)set in each ACE. + if (! (attribute & S_IXOTH)) + attribute &= ~S_ISVTX; + + // From here fill ACL + size_t acl_len = sizeof (ACL); + int ace_off = 0; + + // Construct allow attribute for owner + DWORD owner_allow = (STANDARD_RIGHTS_ALL & ~DELETE) + | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA; + if (attribute & S_IRUSR) + owner_allow |= FILE_GENERIC_READ; + if (attribute & S_IWUSR) + owner_allow |= FILE_GENERIC_WRITE | DELETE; + if (attribute & S_IXUSR) + owner_allow |= FILE_GENERIC_EXECUTE; + if (! (attribute & S_ISVTX)) + owner_allow |= FILE_DELETE_CHILD; + + // Construct allow attribute for group + DWORD group_allow = STANDARD_RIGHTS_READ + | FILE_READ_ATTRIBUTES | FILE_READ_EA; + if (attribute & S_IRGRP) + group_allow |= FILE_GENERIC_READ; + if (attribute & S_IWGRP) + group_allow |= STANDARD_RIGHTS_ALL | FILE_GENERIC_WRITE | DELETE; + if (attribute & S_IXGRP) + group_allow |= FILE_GENERIC_EXECUTE; + if (! (attribute & S_ISVTX)) + group_allow |= FILE_DELETE_CHILD; + + // Construct allow attribute for everyone + DWORD other_allow = STANDARD_RIGHTS_READ + | FILE_READ_ATTRIBUTES | FILE_READ_EA; + if (attribute & S_IROTH) + other_allow |= FILE_GENERIC_READ; + if (attribute & S_IWOTH) + other_allow |= STANDARD_RIGHTS_ALL | FILE_GENERIC_WRITE | DELETE; + if (attribute & S_IXOTH) + other_allow |= FILE_GENERIC_EXECUTE; + if (! (attribute & S_ISVTX)) + other_allow |= FILE_DELETE_CHILD; + + // Construct deny attributes for owner and group + DWORD owner_deny = 0; + if (is_grp_member (uid, gid)) + owner_deny = ~owner_allow & (group_allow | other_allow); + else + owner_deny = ~owner_allow & other_allow; + owner_deny &= ~(STANDARD_RIGHTS_READ + | FILE_READ_ATTRIBUTES | FILE_READ_EA + | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA); + DWORD group_deny = ~group_allow & other_allow; + group_deny &= ~(STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES | FILE_READ_EA); + + // Set deny ACE for owner + if (owner_deny + && ! add_access_denied_ace (acl, ace_off++, owner_deny, + owner_sid, acl_len, INHERIT_ALL)) + return NULL; + // Set allow ACE for owner + if (! add_access_allowed_ace (acl, ace_off++, owner_allow, + owner_sid, acl_len, INHERIT_ALL)) + return NULL; + // Set deny ACE for group + if (group_deny + && ! add_access_denied_ace (acl, ace_off++, group_deny, + group_sid, acl_len, INHERIT_ALL)) + return NULL; + // Set allow ACE for group + if (! add_access_allowed_ace (acl, ace_off++, group_allow, + group_sid, acl_len, INHERIT_ALL)) + return NULL; + + // Get owner and group from current security descriptor + PSID cur_owner_sid = NULL; + PSID cur_group_sid = NULL; + if (! GetSecurityDescriptorOwner (sd_ret, &cur_owner_sid, &dummy)) + debug_printf ("GetSecurityDescriptorOwner %E"); + if (! GetSecurityDescriptorGroup (sd_ret, &cur_group_sid, &dummy)) + debug_printf ("GetSecurityDescriptorGroup %E"); + + // Fill ACL with unrelated ACEs from current security descriptor + PACL oacl; + BOOL acl_exists; + ACCESS_ALLOWED_ACE *ace; + if (GetSecurityDescriptorDacl (sd_ret, &acl_exists, &oacl, &dummy) + && acl_exists && oacl) + for (DWORD i = 0; i < oacl->AceCount; ++i) + if (GetAce (oacl, i, (PVOID *) &ace)) + { + PSID ace_sid = (PSID) &ace->SidStart; + // Check for related ACEs + if ((cur_owner_sid && EqualSid (ace_sid, cur_owner_sid)) + || (owner_sid && EqualSid (ace_sid, owner_sid)) + || (cur_group_sid && EqualSid (ace_sid, cur_group_sid)) + || (group_sid && EqualSid (ace_sid, group_sid)) + || (EqualSid (ace_sid, get_world_sid ()))) + continue; + // Add unrelated ACCESS_DENIED_ACE to the beginning but + // behind the owner_deny, ACCESS_ALLOWED_ACE to the end + // but in front of the `everyone' ACE. + if (! AddAce(acl, ACL_REVISION, + ace->Header.AceType == ACCESS_DENIED_ACE_TYPE ? + (owner_deny ? 1 : 0) : MAXDWORD, + (LPVOID) ace, ace->Header.AceSize)) + { + __seterrno (); + return NULL; + } + acl_len += ace->Header.AceSize; + ++ace_off; + } + + // Set allow ACE for everyone + if (! add_access_allowed_ace (acl, ace_off++, other_allow, + get_world_sid (), acl_len, INHERIT_ALL)) + return NULL; + + // Set AclSize to computed value + acl->AclSize = acl_len; + debug_printf ("ACL-Size: %d", acl_len); + + // Create DACL for local security descriptor + if (! SetSecurityDescriptorDacl (&sd, TRUE, acl, FALSE)) + { + __seterrno (); + return NULL; + } + + // Make self relative security descriptor + *sd_size_ret = 0; + MakeSelfRelativeSD (&sd, sd_ret, sd_size_ret); + if (*sd_size_ret <= 0) + { + __seterrno (); + return NULL; + } + if (! MakeSelfRelativeSD (&sd, sd_ret, sd_size_ret)) + { + __seterrno (); + return NULL; + } + psd = sd_ret; + debug_printf ("Created SD-Size: %d", *sd_size_ret); + + return psd; +} + +static int +set_nt_attribute (const char *file, uid_t uid, gid_t gid, + const char *logsrv, int attribute) +{ + if (os_being_run != winNT) + return 0; + + if (set_process_privileges () < 0) + return -1; + + DWORD sd_size = 4096; + char sd_buf[4096]; + PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf; + + int ret; + if ((ret = ReadSD (file, psd, &sd_size)) <= 0) + { + debug_printf ("ReadSD %E"); + return ret; + } + + sd_size = 4096; + if (! (psd = alloc_sd (uid, gid, logsrv, attribute, psd, &sd_size))) + return -1; + + return WriteSD (file, psd, sd_size); +} + +int +set_file_attribute (int use_ntsec, const char *file, + uid_t uid, gid_t gid, + int attribute, const char *logsrv) +{ + // symlinks are anything for everyone! + if ((attribute & S_IFLNK) == S_IFLNK) + attribute |= S_IRWXU | S_IRWXG | S_IRWXO; + + BOOL ret = NTWriteEA (file, ".UNIXATTR", + (char *) &attribute, sizeof (attribute)); + if (!use_ntsec || !allow_ntsec) + { + if (! ret) + { + __seterrno (); + return -1; + } + return 0; + } + + int ret2 = set_nt_attribute (file, uid, gid, logsrv, attribute); + syscall_printf ("%d = set_file_attribute (%s, %d, %d, %p)", + ret2, file, uid, gid, attribute); + return ret2; +} + +int +set_file_attribute (int use_ntsec, const char *file, int attribute) +{ + return set_file_attribute (use_ntsec, file, + myself->uid, myself->gid, + attribute, myself->logsrv); +} + +static int +searchace (aclent_t *aclp, int nentries, int type, int id = -1) +{ + int i; + + for (i = 0; i < nentries; ++i) + if ((aclp[i].a_type == type && (id < 0 || aclp[i].a_id == id)) + || !aclp[i].a_type) + return i; + return -1; +} + +static int +setacl (const char *file, int nentries, aclent_t *aclbufp) +{ + DWORD sd_size = 4096; + char sd_buf[4096]; + PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf; + + if (ReadSD (file, psd, &sd_size) <= 0) + { + debug_printf ("ReadSD %E"); + return -1; + } + + BOOL dummy; + + // Get owner SID + PSID owner_sid = NULL; + if (! GetSecurityDescriptorOwner (psd, &owner_sid, &dummy)) + { + __seterrno (); + return -1; + } + char owner_buf[MAX_SID_LEN]; + if (!CopySid (MAX_SID_LEN, (PSID) owner_buf, owner_sid)) + { + __seterrno (); + return -1; + } + owner_sid = (PSID) owner_buf; + + // Get group SID + PSID group_sid = NULL; + if (! GetSecurityDescriptorGroup (psd, &group_sid, &dummy)) + { + __seterrno (); + return -1; + } + char group_buf[MAX_SID_LEN]; + if (!CopySid (MAX_SID_LEN, (PSID) group_buf, group_sid)) + { + __seterrno (); + return -1; + } + group_sid = (PSID) group_buf; + + // Initialize local security descriptor + SECURITY_DESCRIPTOR sd; + if (! InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION)) + { + __seterrno (); + return -1; + } + if (! SetSecurityDescriptorOwner(&sd, owner_sid, FALSE)) + { + __seterrno (); + return -1; + } + if (group_sid + && ! SetSecurityDescriptorGroup(&sd, group_sid, FALSE)) + { + __seterrno (); + return -1; + } + + // Fill access control list + char acl_buf[3072]; + PACL acl = (PACL) acl_buf; + size_t acl_len = sizeof (ACL); + int ace_off = 0; + + char sidbuf[MAX_SID_LEN]; + PSID sid = (PSID) sidbuf; + struct passwd *pw; + struct group *gr; + int pos; + + if (! InitializeAcl (acl, 3072, ACL_REVISION)) + { + __seterrno (); + return -1; + } + for (int i = 0; i < nentries; ++i) + { + DWORD allow = STANDARD_RIGHTS_READ + | FILE_READ_ATTRIBUTES | FILE_READ_EA; + if (aclbufp[i].a_perm & S_IROTH) + allow |= FILE_GENERIC_READ; + if (aclbufp[i].a_perm & S_IWOTH) + allow |= STANDARD_RIGHTS_ALL | FILE_GENERIC_WRITE + | DELETE | FILE_DELETE_CHILD; + if (aclbufp[i].a_perm & S_IXOTH) + allow |= FILE_GENERIC_EXECUTE; + // Set inherit property + DWORD inheritance = (aclbufp[i].a_type & ACL_DEFAULT) + ? INHERIT_ONLY : DONT_INHERIT; + // If a specific acl contains a corresponding default entry with + // identical permissions, only one Windows ACE with proper + // inheritance bits is created. + if (!(aclbufp[i].a_type & ACL_DEFAULT) + && (pos = searchace (aclbufp, nentries, + aclbufp[i].a_type | ACL_DEFAULT, + (aclbufp[i].a_type & (USER|GROUP)) + ? aclbufp[i].a_id : -1)) >= 0 + && pos < nentries + && aclbufp[i].a_perm == aclbufp[pos].a_perm) + { + inheritance = INHERIT_ALL; + // This eliminates the corresponding default entry. + aclbufp[pos].a_type = 0; + } + switch (aclbufp[i].a_type) + { + case USER_OBJ: + case DEF_USER_OBJ: + allow |= STANDARD_RIGHTS_ALL & ~DELETE; + if (! add_access_allowed_ace (acl, ace_off++, allow, + owner_sid, acl_len, inheritance)) + return -1; + break; + case USER: + case DEF_USER: + if (!(pw = getpwuid (aclbufp[i].a_id)) + || ! get_pw_sid (sid, pw) + || ! add_access_allowed_ace (acl, ace_off++, allow, + sid, acl_len, inheritance)) + return -1; + break; + case GROUP_OBJ: + case DEF_GROUP_OBJ: + if (! add_access_allowed_ace (acl, ace_off++, allow, + group_sid, acl_len, inheritance)) + return -1; + break; + case GROUP: + case DEF_GROUP: + if (!(gr = getgrgid (aclbufp[i].a_id)) + || ! get_gr_sid (sid, gr) + || ! add_access_allowed_ace (acl, ace_off++, allow, + sid, acl_len, inheritance)) + return -1; + break; + case OTHER_OBJ: + case DEF_OTHER_OBJ: + if (! add_access_allowed_ace (acl, ace_off++, allow, + get_world_sid(), acl_len, inheritance)) + return -1; + break; + } + } + // Set AclSize to computed value + acl->AclSize = acl_len; + debug_printf ("ACL-Size: %d", acl_len); + // Create DACL for local security descriptor + if (! SetSecurityDescriptorDacl (&sd, TRUE, acl, FALSE)) + { + __seterrno (); + return -1; + } + // Make self relative security descriptor in psd + sd_size = 0; + MakeSelfRelativeSD (&sd, psd, &sd_size); + if (sd_size <= 0) + { + __seterrno (); + return -1; + } + if (! MakeSelfRelativeSD (&sd, psd, &sd_size)) + { + __seterrno (); + return -1; + } + debug_printf ("Created SD-Size: %d", sd_size); + return WriteSD (file, psd, sd_size); +} + +static void +getace (aclent_t &acl, int type, int id, DWORD win_ace_mask, DWORD win_ace_type) +{ + acl.a_type = type; + acl.a_id = id; + + if (win_ace_mask & FILE_READ_DATA) + if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE) + acl.a_perm |= (acl.a_perm & S_IRGRP) ? 0 : S_IRUSR; + else if (win_ace_type == ACCESS_DENIED_ACE_TYPE) + acl.a_perm &= ~S_IRGRP; + + if (win_ace_mask & FILE_WRITE_DATA) + if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE) + acl.a_perm |= (acl.a_perm & S_IWGRP) ? 0 : S_IWUSR; + else if (win_ace_type == ACCESS_DENIED_ACE_TYPE) + acl.a_perm &= ~S_IWGRP; + + if (win_ace_mask & FILE_EXECUTE) + if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE) + acl.a_perm |= (acl.a_perm & S_IXGRP) ? 0 : S_IXUSR; + else if (win_ace_type == ACCESS_DENIED_ACE_TYPE) + acl.a_perm &= ~S_IXGRP; +} + +static int +getacl (const char *file, DWORD attr, int nentries, aclent_t *aclbufp) +{ + DWORD sd_size = 4096; + char sd_buf[4096]; + PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf; + + int ret; + if ((ret = ReadSD (file, psd, &sd_size)) <= 0) + { + debug_printf ("ReadSD %E"); + return ret; + } + + PSID owner_sid; + PSID group_sid; + BOOL dummy; + uid_t uid; + gid_t gid; + + if (! GetSecurityDescriptorOwner (psd, &owner_sid, &dummy)) + { + debug_printf ("GetSecurityDescriptorOwner %E"); + __seterrno (); + return -1; + } + uid = get_uid_from_sid (owner_sid); + + if (! GetSecurityDescriptorGroup (psd, &group_sid, &dummy)) + { + debug_printf ("GetSecurityDescriptorGroup %E"); + __seterrno (); + return -1; + } + gid = get_gid_from_sid (group_sid); + + aclent_t lacl[MAX_ACL_ENTRIES]; + memset (&lacl, 0, MAX_ACL_ENTRIES * sizeof (aclent_t)); + lacl[0].a_type = USER_OBJ; + lacl[0].a_id = uid; + lacl[1].a_type = GROUP_OBJ; + lacl[1].a_id = gid; + lacl[2].a_type = OTHER_OBJ; + + PACL acl; + BOOL acl_exists; + + if (! GetSecurityDescriptorDacl (psd, &acl_exists, &acl, &dummy)) + { + __seterrno (); + debug_printf ("GetSecurityDescriptorDacl %E"); + return -1; + } + + int pos, i; + + if (! acl_exists || ! acl) + { + for (pos = 0; pos < MIN_ACL_ENTRIES; ++pos) + lacl[pos].a_perm = S_IRWXU | S_IRWXG | S_IRWXO; + pos = nentries < MIN_ACL_ENTRIES ? nentries : MIN_ACL_ENTRIES; + memcpy (aclbufp, lacl, pos * sizeof (aclent_t)); + return pos; + } + + for (i = 0; i < acl->AceCount && (!nentries || i < nentries); ++i) + { + ACCESS_ALLOWED_ACE *ace; + + if (!GetAce (acl, i, (PVOID *) &ace)) + continue; + + PSID ace_sid = (PSID) &ace->SidStart; + int id; + int type = 0; + + if (EqualSid (ace_sid, owner_sid)) + { + type = USER_OBJ; + id = uid; + } + else if (EqualSid (ace_sid, group_sid)) + { + type = GROUP_OBJ; + id = gid; + } + else if (EqualSid (ace_sid, get_world_sid ())) + { + type = OTHER_OBJ; + id = 0; + } + else + { + id = get_id_from_sid (ace_sid, FALSE, &type); + if (type != GROUP) + { + int type2 = 0; + int id2 = get_id_from_sid (ace_sid, TRUE, &type2); + if (type2 == GROUP) + { + id = id2; + type = GROUP; + } + } + } + if (!type) + continue; + if (!(ace->Header.AceFlags & INHERIT_ONLY_ACE)) + { + if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, id)) >= 0) + getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType); + } + if ((ace->Header.AceFlags & INHERIT_ALL) + && (attr & FILE_ATTRIBUTE_DIRECTORY)) + { + type |= ACL_DEFAULT; + if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, id)) >= 0) + getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType); + } + } + if ((pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) < 0) + pos = MAX_ACL_ENTRIES; + for (i = 0; i < pos; ++i) + { + lacl[i].a_perm = (lacl[i].a_perm & S_IRWXU) + & ~((lacl[i].a_perm & S_IRWXG) << 3); + lacl[i].a_perm |= (lacl[i].a_perm & S_IRWXU) >> 3 + | (lacl[i].a_perm & S_IRWXU) >> 6; + } + if ((searchace (lacl, MAX_ACL_ENTRIES, USER) >= 0 + || searchace (lacl, MAX_ACL_ENTRIES, GROUP) >= 0) + && (pos = searchace (lacl, MAX_ACL_ENTRIES, CLASS_OBJ)) >= 0) + { + lacl[pos].a_type = CLASS_OBJ; + lacl[pos].a_perm = + lacl[searchace (lacl, MAX_ACL_ENTRIES, GROUP_OBJ)].a_perm; + } + int dgpos; + if ((searchace (lacl, MAX_ACL_ENTRIES, DEF_USER) >= 0 + || searchace (lacl, MAX_ACL_ENTRIES, DEF_GROUP) >= 0) + && (dgpos = searchace (lacl, MAX_ACL_ENTRIES, DEF_GROUP_OBJ)) >= 0 + && (pos = searchace (lacl, MAX_ACL_ENTRIES, DEF_CLASS_OBJ)) >= 0 + && (attr & FILE_ATTRIBUTE_DIRECTORY)) + { + lacl[pos].a_type = DEF_CLASS_OBJ; + lacl[pos].a_perm = lacl[dgpos].a_perm; + } + if ((pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) < 0) + pos = MAX_ACL_ENTRIES; + if (pos > nentries) + pos = nentries; + if (aclbufp) + memcpy (aclbufp, lacl, pos * sizeof (aclent_t)); + aclsort (pos, 0, aclbufp); + syscall_printf ("%d = getacl (%s)", pos, file); + return pos; +} + +int +acl_access (const char *path, int flags) +{ + aclent_t acls[MAX_ACL_ENTRIES]; + int cnt; + + if ((cnt = acl (path, GETACL, MAX_ACL_ENTRIES, acls)) < 1) + return -1; + + // Only check existance. + if (!(flags & (R_OK|W_OK|X_OK))) + return 0; + + for (int i = 0; i < cnt; ++i) + { + switch (acls[i].a_type) + { + case USER_OBJ: + case USER: + if (acls[i].a_id != myself->uid) + { + // Check if user is a NT group: + // Take SID from passwd, search SID in group, check is_grp_member + char owner_sidbuf[MAX_SID_LEN]; + PSID owner_sid = (PSID) owner_sidbuf; + char group_sidbuf[MAX_SID_LEN]; + PSID group_sid = (PSID) group_sidbuf; + struct passwd *pw; + struct group *gr = NULL; + + if (group_sem > 0) + continue; + ++group_sem; + if ((pw = getpwuid (acls[i].a_id)) != NULL + && get_pw_sid (owner_sid, pw)) + { + while ((gr = getgrent ())) + if (get_gr_sid (group_sid, gr) + && EqualSid (owner_sid, group_sid) + && is_grp_member (myself->uid, gr->gr_gid)) + break; + endgrent (); + } + --group_sem; + if (! gr) + continue; + } + break; + case GROUP_OBJ: + case GROUP: + if (acls[i].a_id != myself->gid && + !is_grp_member (myself->uid, acls[i].a_id)) + continue; + break; + case OTHER_OBJ: + break; + default: + continue; + } + if ((!(flags & R_OK) || (acls[i].a_perm & S_IREAD)) + && (!(flags & W_OK) || (acls[i].a_perm & S_IWRITE)) + && (!(flags & X_OK) || (acls[i].a_perm & S_IEXEC))) + return 0; + } + set_errno (EACCES); + return -1; +} + +extern "C" +int +acl (const char *path, int cmd, int nentries, aclent_t *aclbufp) +{ + if (set_process_privileges () < 0) + return -1; + + path_conv real_path (path); + if (real_path.error) + { + set_errno (real_path.error); + syscall_printf ("-1 = acl (%s)", path); + return -1; + } + if (!real_path.has_acls ()) + { + struct stat st; + int ret = -1; + + switch (cmd) + { + case SETACL: + set_errno (ENOSYS); + break; + case GETACL: + if (nentries < 1) + set_errno (EINVAL); + else if (! stat (path, &st)) + { + aclent_t lacl[4]; + if (nentries > 0) + { + lacl[0].a_type = USER_OBJ; + lacl[0].a_id = st.st_uid; + lacl[0].a_perm = (st.st_mode & S_IRWXU) + | (st.st_mode & S_IRWXU) >> 3 + | (st.st_mode & S_IRWXU) >> 6; + } + if (nentries > 1) + { + lacl[1].a_type = GROUP_OBJ; + lacl[1].a_id = st.st_gid; + lacl[1].a_perm = (st.st_mode & S_IRWXG) + | (st.st_mode & S_IRWXG) << 3 + | (st.st_mode & S_IRWXG) >> 3; + } + if (nentries > 2) + { + lacl[2].a_type = OTHER_OBJ; + lacl[2].a_id = 0; + lacl[2].a_perm = (st.st_mode & S_IRWXO) + | (st.st_mode & S_IRWXO) << 6 + | (st.st_mode & S_IRWXO) << 3; + } + if (nentries > 3) + { + lacl[3].a_type = CLASS_OBJ; + lacl[3].a_id = 0; + lacl[3].a_perm = (st.st_mode & S_IRWXG) + | (st.st_mode & S_IRWXG) << 3 + | (st.st_mode & S_IRWXG) >> 3; + } + if (nentries > 4) + nentries = 4; + if (aclbufp) + memcpy (aclbufp, lacl, nentries * sizeof (aclent_t)); + ret = nentries; + } + break; + case GETACLCNT: + ret = 4; + break; + } + syscall_printf ("%d = acl (%s)", ret, path); + return ret; + } + switch (cmd) + { + case SETACL: + if (!aclsort(nentries, 0, aclbufp)) + return setacl (real_path.get_win32 (), + nentries, aclbufp); + break; + case GETACL: + if (nentries < 1) + break; + return getacl (real_path.get_win32 (), + real_path.file_attributes (), + nentries, aclbufp); + case GETACLCNT: + return getacl (real_path.get_win32 (), + real_path.file_attributes (), + 0, NULL); + default: + break; + } + set_errno (EINVAL); + syscall_printf ("-1 = acl (%s)", path); + return -1; +} + +extern "C" +int +facl (int fd, int cmd, int nentries, aclent_t *aclbufp) +{ + if (dtable.not_open (fd)) + { + syscall_printf ("-1 = facl (%d)", fd); + set_errno (EBADF); + return -1; + } + const char *path = dtable[fd]->get_name (); + if (path == NULL) + { + syscall_printf ("-1 = facl (%d) (no name)", fd); + set_errno (ENOSYS); + return -1; + } + syscall_printf ("facl (%d): calling acl (%s)", fd, path); + return acl (path, cmd, nentries, aclbufp); +} + +extern "C" +int +aclcheck (aclent_t *aclbufp, int nentries, int *which) +{ + BOOL has_user_obj = FALSE; + BOOL has_group_obj = FALSE; + BOOL has_other_obj = FALSE; + BOOL has_class_obj = FALSE; + BOOL has_ug_objs = FALSE; + BOOL has_def_user_obj = FALSE; + BOOL has_def_group_obj = FALSE; + BOOL has_def_other_obj = FALSE; + BOOL has_def_class_obj = FALSE; + BOOL has_def_ug_objs = FALSE; + int pos2; + + for (int pos = 0; pos < nentries; ++pos) + switch (aclbufp[pos].a_type) + { + case USER_OBJ: + if (has_user_obj) + { + if (which) + *which = pos; + return USER_ERROR; + } + has_user_obj = TRUE; + break; + case GROUP_OBJ: + if (has_group_obj) + { + if (which) + *which = pos; + return GRP_ERROR; + } + has_group_obj = TRUE; + break; + case OTHER_OBJ: + if (has_other_obj) + { + if (which) + *which = pos; + return OTHER_ERROR; + } + has_other_obj = TRUE; + break; + case CLASS_OBJ: + if (has_class_obj) + { + if (which) + *which = pos; + return CLASS_ERROR; + } + has_class_obj = TRUE; + break; + case USER: + case GROUP: + if ((pos2 = searchace (aclbufp + pos + 1, nentries - pos - 1, + aclbufp[pos].a_type, aclbufp[pos].a_id)) >= 0) + { + if (which) + *which = pos2; + return DUPLICATE_ERROR; + } + has_ug_objs = TRUE; + break; + case DEF_USER_OBJ: + if (has_def_user_obj) + { + if (which) + *which = pos; + return USER_ERROR; + } + has_def_user_obj = TRUE; + break; + case DEF_GROUP_OBJ: + if (has_def_group_obj) + { + if (which) + *which = pos; + return GRP_ERROR; + } + has_def_group_obj = TRUE; + break; + case DEF_OTHER_OBJ: + if (has_def_other_obj) + { + if (which) + *which = pos; + return OTHER_ERROR; + } + has_def_other_obj = TRUE; + break; + case DEF_CLASS_OBJ: + if (has_def_class_obj) + { + if (which) + *which = pos; + return CLASS_ERROR; + } + has_def_class_obj = TRUE; + break; + case DEF_USER: + case DEF_GROUP: + if ((pos2 = searchace (aclbufp + pos + 1, nentries - pos - 1, + aclbufp[pos].a_type, aclbufp[pos].a_id)) >= 0) + { + if (which) + *which = pos2; + return DUPLICATE_ERROR; + } + has_def_ug_objs = TRUE; + break; + default: + return ENTRY_ERROR; + } + if (!has_user_obj + || !has_group_obj + || !has_other_obj +#if 0 + // These checks are not ok yet since CLASS_OBJ isn't fully implemented. + || (has_ug_objs && !has_class_obj) + || (has_def_ug_objs && !has_def_class_obj) +#endif + ) + { + if (which) + *which = -1; + return MISS_ERROR; + } + return 0; +} + +extern "C" +int acecmp (const void *a1, const void *a2) +{ +#define ace(i) ((const aclent_t *) a##i) + int ret = ace(1)->a_type - ace(2)->a_type; + if (!ret) + ret = ace(1)->a_id - ace(2)->a_id; + return ret; +#undef ace +} + +extern "C" +int +aclsort (int nentries, int calclass, aclent_t *aclbufp) +{ + if (aclcheck (aclbufp, nentries, NULL)) + return -1; + if (!aclbufp || nentries < 1) + { + set_errno (EINVAL); + return -1; + } + qsort((void *) aclbufp, nentries, sizeof (aclent_t), acecmp); + return 0; +} + +extern "C" +int +acltomode (aclent_t *aclbufp, int nentries, mode_t *modep) +{ + int pos; + + if (!aclbufp || nentries < 1 || ! modep) + { + set_errno (EINVAL); + return -1; + } + *modep = 0; + if ((pos = searchace (aclbufp, nentries, USER_OBJ)) < 0) + { + set_errno (EINVAL); + return -1; + } + *modep |= aclbufp[pos].a_perm & S_IRWXU; + if ((pos = searchace (aclbufp, nentries, GROUP_OBJ)) < 0) + { + set_errno (EINVAL); + return -1; + } + if (searchace (aclbufp, nentries, CLASS_OBJ) < 0) + pos = searchace (aclbufp, nentries, CLASS_OBJ); + *modep |= (aclbufp[pos].a_perm & S_IRWXU) >> 3; + if ((pos = searchace (aclbufp, nentries, OTHER_OBJ)) < 0) + { + set_errno (EINVAL); + return -1; + } + *modep |= (aclbufp[pos].a_perm & S_IRWXU) >> 6; + return 0; +} + +extern "C" +int +aclfrommode(aclent_t *aclbufp, int nentries, mode_t *modep) +{ + int pos; + + if (!aclbufp || nentries < 1 || ! modep) + { + set_errno (EINVAL); + return -1; + } + if ((pos = searchace (aclbufp, nentries, USER_OBJ)) < 0) + { + set_errno (EINVAL); + return -1; + } + aclbufp[pos].a_perm = (*modep & S_IRWXU) + | (*modep & S_IRWXU) >> 3 + | (*modep & S_IRWXU) >> 6; + if ((pos = searchace (aclbufp, nentries, GROUP_OBJ)) < 0) + { + set_errno (EINVAL); + return -1; + } + if (searchace (aclbufp, nentries, CLASS_OBJ) < 0) + pos = searchace (aclbufp, nentries, CLASS_OBJ); + aclbufp[pos].a_perm = (*modep & S_IRWXG) + | (*modep & S_IRWXG) << 3 + | (*modep & S_IRWXG) >> 3; + if ((pos = searchace (aclbufp, nentries, OTHER_OBJ)) < 0) + { + set_errno (EINVAL); + return -1; + } + aclbufp[pos].a_perm = (*modep & S_IRWXO) + | (*modep & S_IRWXO) << 6 + | (*modep & S_IRWXO) << 3; + return 0; +} + +extern "C" +int +acltopbits (aclent_t *aclbufp, int nentries, mode_t *pbitsp) +{ + return acltomode (aclbufp, nentries, pbitsp); +} + +extern "C" +int +aclfrompbits (aclent_t *aclbufp, int nentries, mode_t *pbitsp) +{ + return aclfrommode (aclbufp, nentries, pbitsp); +} + +static char * +permtostr (mode_t perm) +{ + static char pbuf[4]; + + pbuf[0] = (perm & S_IREAD) ? 'r' : '-'; + pbuf[1] = (perm & S_IWRITE) ? 'w' : '-'; + pbuf[2] = (perm & S_IEXEC) ? 'x' : '-'; + pbuf[3] = '\0'; + return pbuf; +} + +extern "C" +char * +acltotext (aclent_t *aclbufp, int aclcnt) +{ + if (!aclbufp || aclcnt < 1 || aclcnt > MAX_ACL_ENTRIES + || aclcheck (aclbufp, aclcnt, NULL)) + { + set_errno (EINVAL); + return NULL; + } + char buf[32000]; + buf[0] = '\0'; + BOOL first = TRUE; + + for (int pos = 0; pos < aclcnt; ++pos) + { + if (!first) + strcat (buf, ","); + first = FALSE; + if (aclbufp[pos].a_type & ACL_DEFAULT) + strcat (buf, "default"); + switch (aclbufp[pos].a_type) + { + case USER_OBJ: + sprintf (buf + strlen (buf), "user::%s", + permtostr (aclbufp[pos].a_perm)); + break; + case USER: + sprintf (buf + strlen (buf), "user:%d:%s", + aclbufp[pos].a_id, permtostr (aclbufp[pos].a_perm)); + break; + case GROUP_OBJ: + sprintf (buf + strlen (buf), "group::%s", + permtostr (aclbufp[pos].a_perm)); + break; + case GROUP: + sprintf (buf + strlen (buf), "group:%d:%s", + aclbufp[pos].a_id, permtostr (aclbufp[pos].a_perm)); + break; + case CLASS_OBJ: + sprintf (buf + strlen (buf), "mask::%s", + permtostr (aclbufp[pos].a_perm)); + break; + case OTHER_OBJ: + sprintf (buf + strlen (buf), "other::%s", + permtostr (aclbufp[pos].a_perm)); + break; + default: + set_errno (EINVAL); + return NULL; + } + } + return strdup (buf); +} + +static mode_t +permfromstr (char *perm) +{ + mode_t mode = 0; + + if (strlen (perm) != 3) + return 01000; + if (perm[0] == 'r') + mode |= S_IRUSR | S_IRGRP | S_IROTH; + else if (perm[0] != '-') + return 01000; + if (perm[1] == 'w') + mode |= S_IWUSR | S_IWGRP | S_IWOTH; + else if (perm[1] != '-') + return 01000; + if (perm[2] == 'x') + mode |= S_IXUSR | S_IXGRP | S_IXOTH; + else if (perm[2] != '-') + return 01000; + return mode; +} + +extern "C" +aclent_t * +aclfromtext (char *acltextp, int *aclcnt) +{ + if (!acltextp) + { + set_errno (EINVAL); + return NULL; + } + char buf[strlen (acltextp) + 1]; + aclent_t lacl[MAX_ACL_ENTRIES]; + memset (lacl, 0, sizeof lacl); + int pos = 0; + for (char *c = strtok (buf, ","); c; c = strtok (NULL, ",")) + { + if (!strncmp (c, "default", 7)) + { + lacl[pos].a_type |= ACL_DEFAULT; + c += 7; + } + if (!strncmp (c, "user:", 5)) + { + if (c[5] == ':') + lacl[pos].a_type |= USER_OBJ; + else + { + lacl[pos].a_type |= USER; + c += 5; + if (isalpha (*c)) + { + struct passwd *pw = getpwnam (c); + if (!pw) + { + set_errno (EINVAL); + return NULL; + } + lacl[pos].a_id = pw->pw_uid; + c = strchr (c, ':'); + } + else if (isdigit (*c)) + lacl[pos].a_id = strtol (c, &c, 10); + if (!c || *c != ':') + { + set_errno (EINVAL); + return NULL; + } + } + } + else if (!strncmp (c, "group:", 6)) + { + if (c[5] == ':') + lacl[pos].a_type |= GROUP_OBJ; + else + { + lacl[pos].a_type |= GROUP; + c += 5; + if (isalpha (*c)) + { + struct group *gr = getgrnam (c); + if (!gr) + { + set_errno (EINVAL); + return NULL; + } + lacl[pos].a_id = gr->gr_gid; + c = strchr (c, ':'); + } + else if (isdigit (*c)) + lacl[pos].a_id = strtol (c, &c, 10); + if (!c || *c != ':') + { + set_errno (EINVAL); + return NULL; + } + } + } + else if (!strncmp (c, "mask:", 5)) + { + if (c[5] == ':') + lacl[pos].a_type |= CLASS_OBJ; + else + { + set_errno (EINVAL); + return NULL; + } + } + else if (!strncmp (c, "other:", 6)) + { + if (c[5] == ':') + lacl[pos].a_type |= OTHER_OBJ; + else + { + set_errno (EINVAL); + return NULL; + } + } + if ((lacl[pos].a_perm = permfromstr (c)) == 01000) + { + set_errno (EINVAL); + return NULL; + } + ++pos; + } + aclent_t *aclp = (aclent_t *) malloc (pos * sizeof (aclent_t)); + if (aclp) + memcpy (aclp, lacl, pos * sizeof (aclent_t)); + return aclp; +} + diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc new file mode 100644 index 000000000..84518e1b2 --- /dev/null +++ b/winsup/cygwin/select.cc @@ -0,0 +1,1380 @@ +/* select.cc + + Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions. + + Written by Christopher Faylor of Cygnus Solutions + cgf@cygnus.com + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +/* + * The following line means that the BSD socket + * definitions for fd_set, FD_ISSET etc. are used in this + * file. + */ + +#define __INSIDE_CYGWIN_NET__ +#define Win32_Winsock + +#include +#include +#include +#include + +#include "winsup.h" +#include +#include +#include +#include +#include "select.h" + +/* + * All these defines below should be in sys/types.h + * but because of the includes above, they may not have + * been included. We create special UNIX_xxxx versions here. + */ + +#ifndef NBBY +#define NBBY 8 /* number of bits in a byte */ +#endif /* NBBY */ + +/* + * Select uses bit masks of file descriptors in longs. + * These macros manipulate such bit fields (the filesystem macros use chars). + * FD_SETSIZE may be defined by the user, but the default here + * should be >= NOFILE (param.h). + */ + +typedef long fd_mask; +#define UNIX_NFDBITS (sizeof (fd_mask) * NBBY) /* bits per mask */ +#ifndef unix_howmany +#define unix_howmany(x,y) (((x)+((y)-1))/(y)) +#endif + +#define unix_fd_set fd_set + +#define NULL_fd_set ((fd_set *)NULL) +#define sizeof_fd_set(n) \ + ((unsigned) (NULL_fd_set->fds_bits + unix_howmany((n), UNIX_NFDBITS))) +#define UNIX_FD_SET(n, p) \ + ((p)->fds_bits[(n)/UNIX_NFDBITS] |= (1L << ((n) % UNIX_NFDBITS))) +#define UNIX_FD_CLR(n, p) \ + ((p)->fds_bits[(n)/UNIX_NFDBITS] &= ~(1L << ((n) % UNIX_NFDBITS))) +#define UNIX_FD_ISSET(n, p) \ + ((p)->fds_bits[(n)/UNIX_NFDBITS] & (1L << ((n) % UNIX_NFDBITS))) +#define UNIX_FD_ZERO(p, n) \ + bzero ((caddr_t)(p), sizeof_fd_set ((n))) + +#define allocfd_set(n) ((fd_set *) alloca (sizeof_fd_set (n))) +#define copyfd_set(to, from, n) memcpy (to, from, sizeof_fd_set (n)); + +/* Make a fhandler_foo::ready_for_ready method. + Assumption: The "ready_for_read" methods are called with one level of + signal blocking. */ +#define MAKEready(what) \ +int \ +fhandler_##what::ready_for_read (int fd, DWORD howlong, int ignra) \ +{ \ + select_record me (this); \ + me.fd = fd; \ + (void) select_read (&me); \ + while (!peek_##what (&me, ignra) && howlong == INFINITE) \ + if (fd >= 0 && dtable.not_open (fd)) \ + break; \ + else if (WaitForSingleObject (signal_arrived, 10) == WAIT_OBJECT_0) \ + break; \ + return me.read_ready; \ +} + +#define set_handle_or_return_if_not_open(h, s) \ + h = (s)->fh->get_handle (); \ + if (dtable.not_open ((s)->fd)) \ + { \ + (s)->saw_error = TRUE; \ + set_errno (EBADF); \ + return -1; \ + } \ + +/* The main select code. + */ +extern "C" +int +cygwin_select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + struct timeval *to) +{ + select_stuff sel; + fd_set *dummy_readfds = allocfd_set (n); + fd_set *dummy_writefds = allocfd_set (n); + fd_set *dummy_exceptfds = allocfd_set (n); + +#if 0 + if (n > FD_SETSIZE) + { + set_errno (EINVAL); + return -1; + } +#endif + + select_printf ("%d, %p, %p, %p, %p", n, readfds, writefds, exceptfds, to); + + memset (&sel, 0, sizeof (sel)); + if (!readfds) + { + UNIX_FD_ZERO (dummy_readfds, n); + readfds = dummy_readfds; + } + if (!writefds) + { + UNIX_FD_ZERO (dummy_writefds, n); + writefds = dummy_writefds; + } + if (!exceptfds) + { + UNIX_FD_ZERO (dummy_exceptfds, n); + exceptfds = dummy_exceptfds; + } + + for (int i = 0; i < n; i++) + if (!sel.test_and_set (i, readfds, writefds, exceptfds)) + { + select_printf ("aborting due to test_and_set error"); + return -1; /* Invalid fd, maybe? */ + } + + /* Convert to milliseconds or INFINITE if to == NULL */ + DWORD ms = to ? (to->tv_sec * 1000) + (to->tv_usec / 1000) : INFINITE; + if (ms == 0 && to->tv_usec) + ms = 1; /* At least 1 ms granularity */ + + if (to) + select_printf ("to->tv_sec %d, to->tv_usec %d, ms %d", to->tv_sec, to->tv_usec, ms); + else + select_printf ("to NULL, ms %x", ms); + + select_printf ("sel.total %d, sel.always_ready %d", sel.total, sel.always_ready); + + /* Degenerate case. No fds to wait for. Just wait. */ + if (sel.total == 0) + { + if (WaitForSingleObject (signal_arrived, ms) == WAIT_OBJECT_0) + { + select_printf ("signal received"); + set_sig_errno (EINTR); + return -1; + } + return 0; + } + + /* If one of the selected fds is "always ready" just poll everything and return + the result. There is no need to wait. */ + if (sel.always_ready || ms == 0) + { + UNIX_FD_ZERO (readfds, n); + UNIX_FD_ZERO (writefds, n); + UNIX_FD_ZERO (exceptfds, n); + return sel.poll (readfds, writefds, exceptfds); + } + + /* Wait for an fd to come alive */ + return sel.wait (readfds, writefds, exceptfds, ms); +} + +/* Cleanup */ +select_stuff::~select_stuff () +{ + select_record *s = &start; + + select_printf ("calling cleanup routines"); + while ((s = s->next)) + if (s->cleanup) + s->cleanup (s, this); + + select_record *snext = start.next; + + select_printf ("deleting select records"); + while ((s = snext)) + { + snext = s->next; + delete s; + } +} + +/* Add a record to the select chain */ +int +select_stuff::test_and_set (int i, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds) +{ + select_record *s = NULL; + if (UNIX_FD_ISSET (i, readfds) && (s = dtable.select_read (i, s)) == NULL) + return 0; /* error */ + if (UNIX_FD_ISSET (i, writefds) && (s = dtable.select_write (i, s)) == NULL) + return 0; /* error */ + if (UNIX_FD_ISSET (i, exceptfds) && (s = dtable.select_except (i, s)) == NULL) + return 0; /* error */ + if (s == NULL) + return 1; /* nothing to do */ + + if (s->read_ready || s->write_ready || s->except_ready) + always_ready = TRUE; + + if (s->windows_handle || s->windows_handle || s->windows_handle) + windows_used = TRUE; + + s->next = start.next; + start.next = s; + total++; + return 1; +} + +/* Poll every fd in the select chain. Set appropriate fd in mask. */ +int +select_stuff::poll (fd_set *readfds, fd_set *writefds, fd_set *exceptfds) +{ + int n = 0; + select_record *s = &start; + while ((s = s->next)) + n += s->poll (s, readfds, writefds, exceptfds); + select_printf ("returning %d", n); + return n; +} + +/* The heart of select. Waits for an fd to do something interesting. */ +int +select_stuff::wait (fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + DWORD ms) +{ + int wait_ret; + HANDLE w4[total + 1]; + select_record *s = &start; + int m = 0; + + w4[m++] = signal_arrived; /* Always wait for the arrival of a signal. */ + /* Loop through the select chain, starting up anything appropriate and + counting the number of active fds. */ + while ((s = s->next)) + { + if (!s->startup (s, this)) + { + __seterrno (); + return -1; + } + if (s->h == NULL) + continue; + for (int i = 1; i < m; i++) + if (w4[i] == s->h) + goto next_while; + w4[m++] = s->h; + next_while: + continue; + } + + int n = m - 1; + DWORD start_time = GetTickCount (); /* Record the current time for later use. */ + + /* Allocate some fd_set structures using the number of fds as a guide. */ + fd_set *r = allocfd_set (n); + fd_set *w = allocfd_set (n); + fd_set *e = allocfd_set (n); + UNIX_FD_ZERO (r, n); + UNIX_FD_ZERO (w, n); + UNIX_FD_ZERO (e, n); + debug_printf ("n %d, ms %u", n, ms); + for (;;) + { + if (!windows_used) + wait_ret = WaitForMultipleObjects (m, w4, FALSE, ms); + else + wait_ret = MsgWaitForMultipleObjects (m, w4, FALSE, ms, QS_ALLINPUT); + + switch (wait_ret) + { + case WAIT_OBJECT_0: + select_printf ("signal received"); + set_sig_errno (EINTR); + return -1; + case WAIT_FAILED: + select_printf ("WaitForMultipleObjects failed"); + __seterrno (); + return -1; + case WAIT_TIMEOUT: + select_printf ("timed out"); + goto out; + } + + select_printf ("woke up. wait_ret %d. verifying", wait_ret); + s = &start; + int gotone = FALSE; + while ((s = s->next)) + if (s->saw_error) + return -1; /* Somebody detected an error */ + else if ((((wait_ret >= m && s->windows_handle) || s->h == w4[wait_ret])) && + s->verify (s, r, w, e)) + gotone = TRUE; + + select_printf ("gotone %d", gotone); + if (gotone) + goto out; + + if (ms == INFINITE) + { + select_printf ("looping"); + continue; + } + select_printf ("recalculating ms"); + + DWORD now = GetTickCount (); + if (now > (start_time + ms)) + { + select_printf ("timed out after verification"); + goto out; + } + ms -= (now - start_time); + start_time = now; + select_printf ("ms now %u", ms); + } + +out: + copyfd_set (readfds, r, n); + copyfd_set (writefds, w, n); + copyfd_set (exceptfds, e, n); + + return poll (readfds, writefds, exceptfds); +} + +static int +set_bits (select_record *me, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds) +{ + int ready = 0; + select_printf ("me %p, testing fd %d (%s)", me, me->fd, me->fh->get_name ()); + if (me->read_selected && me->read_ready) + { + UNIX_FD_SET (me->fd, readfds); + ready++; + } + if (me->write_selected && me->write_ready) + { + UNIX_FD_SET (me->fd, writefds); + ready++; + } + if (me->except_ready && me->except_ready) + { + UNIX_FD_SET (me->fd, exceptfds); + ready++; + } + select_printf ("ready %d", ready); + return ready; +} + +static int +verify_true (select_record *me, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds) +{ + return 1; +} + +static int +verify_ok (select_record *me, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds) +{ + return set_bits (me, readfds, writefds, exceptfds); +} + +static int +no_startup (select_record *me, select_stuff *stuff) +{ + return 1; +} + +static int +no_verify (select_record *, fd_set *, fd_set *, fd_set *) +{ + return 0; +} + +static int +peek_pipe (select_record *s, int ignra) +{ + int n = 0; + int gotone = 0; + fhandler_base *fh = s->fh; + + HANDLE h; + set_handle_or_return_if_not_open (h, s); + + /* Don't perform complicated tests if we don't need to. */ + if (!s->read_selected && !s->except_selected) + goto out; + + if (s->read_selected && fh->bg_check (SIGTTIN) <= 0) + { + gotone = s->read_ready = 1; + goto out; + } + + if (!ignra && fh->get_readahead_valid ()) + { + select_printf ("readahead"); + gotone = s->read_ready = 1; + goto out; + } + + else if (!PeekNamedPipe (h, NULL, 0, NULL, (DWORD *) &n, NULL)) + { + select_printf ("%s, PeekNamedPipe failed, %E", fh->get_name ()); + n = -1; + } + + if (n < 0) + { + select_printf ("%s, n %d", fh->get_name (), n); + if (s->except_selected) + gotone += s->except_ready = TRUE; + if (s->read_selected) + gotone += s->read_ready = TRUE; + } + if (n > 0 && s->read_selected) + { + select_printf ("%s, ready for read", fh->get_name ()); + gotone += s->read_ready = TRUE; + } + if (!gotone && s->fh->hit_eof ()) + { + select_printf ("%s, saw EOF", fh->get_name ()); + if (s->except_selected) + gotone = s->except_ready = TRUE; + if (s->read_selected) + gotone += s->read_ready = TRUE; + } + +out: + return gotone || s->write_ready; +} + +static int +poll_pipe (select_record *me, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds) +{ + return peek_pipe (me, 0) ? + set_bits (me, readfds, writefds, exceptfds) : + 0; +} + +MAKEready(pipe) + +static int start_thread_pipe (select_record *me, select_stuff *stuff); + +struct pipeinf + { + HANDLE thread; + BOOL stop_thread_pipe; + select_record *start; + }; + +static DWORD WINAPI +thread_pipe (void *arg) +{ + pipeinf *pi = (pipeinf *)arg; + BOOL gotone = FALSE; + + for (;;) + { + select_record *s = pi->start; + while ((s = s->next)) + if (s->startup == start_thread_pipe) + { + if (peek_pipe (s, 0)) + gotone = TRUE; + if (pi->stop_thread_pipe) + { + select_printf ("stopping"); + goto out; + } + } + if (gotone) + break; + Sleep (10); + } +out: + return 0; +} + +static int +start_thread_pipe (select_record *me, select_stuff *stuff) +{ + if (stuff->device_specific[FHDEVN(FH_PIPE)]) + { + me->h = ((pipeinf *) stuff->device_specific[FHDEVN(FH_PIPE)])->thread; + return 1; + } + pipeinf *pi = new pipeinf; + pi->start = &stuff->start; + pi->stop_thread_pipe = FALSE; + pi->thread = me->h = makethread (thread_pipe, (LPVOID)pi, 0, "select_pipe"); + if (!me->h) + return 0; + stuff->device_specific[FHDEVN(FH_PIPE)] = (void *)pi; + return 1; +} + +static void +pipe_cleanup (select_record *me, select_stuff *stuff) +{ + pipeinf *pi = (pipeinf *)stuff->device_specific[FHDEVN(FH_PIPE)]; + if (pi && pi->thread) + { + pi->stop_thread_pipe = TRUE; + WaitForSingleObject (pi->thread, INFINITE); + CloseHandle (pi->thread); + delete pi; + stuff->device_specific[FHDEVN(FH_PIPE)] = NULL; + } +} + +select_record * +fhandler_pipe::select_read (select_record *s) +{ + if (!s) + s = new select_record; + s->startup = start_thread_pipe; + s->poll = poll_pipe; + s->verify = verify_ok; + s->read_selected = TRUE; + s->cleanup = pipe_cleanup; + return s; +} + +select_record * +fhandler_pipe::select_write (select_record *s) +{ + if (!s) + { + s = new select_record; + s->startup = no_startup; + s->poll = poll_pipe; + s->verify = no_verify; + } + s->write_selected = TRUE; + s->write_ready = TRUE; + return s; +} + +select_record * +fhandler_pipe::select_except (select_record *s) +{ + if (!s) + s = new select_record; + s->startup = start_thread_pipe; + s->poll = poll_pipe; + s->verify = verify_ok; + s->cleanup = pipe_cleanup; + s->except_selected = TRUE; + return s; +} + +static int +peek_console (select_record *me, int ignra) +{ + extern const char * get_nonascii_key (INPUT_RECORD& input_rec); + fhandler_console *fh = (fhandler_console *)me->fh; + + if (!me->read_selected) + return me->write_ready; + + if (!ignra && fh->get_readahead_valid ()) + { + select_printf ("readahead"); + return me->read_ready = 1; + } + + INPUT_RECORD irec; + DWORD events_read; + HANDLE h; + set_handle_or_return_if_not_open (h, me); + + for (;;) + if (fh->bg_check (SIGTTIN) <= 0) + return me->read_ready = 1; + else if (!PeekConsoleInput (h, &irec, 1, &events_read) || !events_read) + break; + else + { + if (irec.EventType == WINDOW_BUFFER_SIZE_EVENT) + kill_pgrp (fh->tc->getpgid (), SIGWINCH); + else if (irec.EventType == KEY_EVENT && irec.Event.KeyEvent.bKeyDown == TRUE && + (irec.Event.KeyEvent.uChar.AsciiChar || get_nonascii_key (irec))) + return me->read_ready = 1; + + /* Read and discard the event */ + ReadConsoleInput (h, &irec, 1, &events_read); + } + + return me->write_ready; +} + +static int +poll_console (select_record *me, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds) +{ + return peek_console (me, 0) ? + set_bits (me, readfds, writefds, exceptfds) : + 0; +} + +MAKEready (console) + +select_record * +fhandler_console::select_read (select_record *s) +{ + if (!s) + { + s = new select_record; + s->startup = no_startup; + s->poll = poll_console; + s->verify = poll_console; + } + + s->h = get_handle (); + s->read_selected = TRUE; + return s; +} + +select_record * +fhandler_console::select_write (select_record *s) +{ + if (!s) + { + s = new select_record; + s->startup = no_startup; + s->poll = poll_console; + s->verify = no_verify; + } + + s->write_selected = TRUE; + s->write_ready = TRUE; + return s; +} + +select_record * +fhandler_console::select_except (select_record *s) +{ + if (!s) + { + s = new select_record; + s->startup = no_startup; + s->poll = poll_console; + s->verify = no_verify; + } + + s->except_selected = TRUE; + return s; +} + +int +fhandler_tty_common::ready_for_read (int fd, DWORD howlong, int ignra) +{ +#if 0 + if (myself->pgid && get_ttyp ()->getpgid () != myself->pgid && + myself->ctty == ttynum) // background process? + return 1; // Yes. Let read return an error +#endif + return ((fhandler_pipe*)this)->fhandler_pipe::ready_for_read (fd, howlong, ignra); +} + +select_record * +fhandler_tty_common::select_read (select_record *s) +{ + return ((fhandler_pipe*)this)->fhandler_pipe::select_read (s); +} + +select_record * +fhandler_tty_common::select_write (select_record *s) +{ + return ((fhandler_pipe *)this)->fhandler_pipe::select_write (s); +} + +select_record * +fhandler_tty_common::select_except (select_record *s) +{ + return ((fhandler_pipe *)this)->fhandler_pipe::select_except (s); +} + +select_record * +fhandler_dev_null::select_read (select_record *s) +{ + if (!s) + { + s = new select_record; + s->startup = no_startup; + s->poll = set_bits; + s->verify = no_verify; + } + s->h = get_handle (); + s->read_selected = TRUE; + return s; +} + +select_record * +fhandler_dev_null::select_write (select_record *s) +{ + if (!s) + { + s = new select_record; + s->startup = no_startup; + s->poll = set_bits; + s->verify = no_verify; + } + s->h = get_handle (); + s->write_selected = TRUE; + return s; +} + +select_record * +fhandler_dev_null::select_except (select_record *s) +{ + if (!s) + { + s = new select_record; + s->startup = no_startup; + s->poll = set_bits; + s->verify = no_verify; + } + s->h = get_handle (); + s->except_selected = TRUE; + s->except_ready = TRUE; + return s; +} + +static int start_thread_serial (select_record *me, select_stuff *stuff); + +struct serialinf + { + HANDLE thread; + BOOL stop_thread_serial; + select_record *start; + }; + +static int +peek_serial (select_record *s, int) +{ + DWORD ev; + COMSTAT st; + + fhandler_serial *fh = (fhandler_serial *)s->fh; + + if (fh->get_readahead_valid () || fh->overlapped_armed < 0) + return s->read_ready = 1; + + select_printf ("fh->overlapped_armed %d", fh->overlapped_armed); + + HANDLE h; + set_handle_or_return_if_not_open (h, s); + int ready = 0; + (void) SetCommMask (h, EV_RXCHAR); + + if (!fh->overlapped_armed) + { + DWORD ev; + COMSTAT st; + + ResetEvent (fh->io_status.hEvent); + + if (!ClearCommError (h, &ev, &st)) + { + debug_printf ("ClearCommError"); + goto err; + } + else if (st.cbInQue) + return s->read_ready = 1; + else if (WaitCommEvent (h, &ev, &fh->io_status)) + return s->read_ready = 1; + else if (GetLastError () == ERROR_IO_PENDING) + fh->overlapped_armed = 1; + else + { + debug_printf ("WaitCommEvent"); + goto err; + } + } + + HANDLE w4[2]; + DWORD to; + + w4[0] = fh->io_status.hEvent; + w4[1] = signal_arrived; + to = 10; + + switch (WaitForMultipleObjects (2, w4, FALSE, to)) + { + case WAIT_OBJECT_0: + if (!ClearCommError (h, &ev, &st)) + { + debug_printf ("ClearCommError"); + goto err; + } + else if (!st.cbInQue) + Sleep (to); + else + { + return s->read_ready = 1; + select_printf ("got something"); + } + PurgeComm (h, PURGE_TXABORT | PURGE_RXABORT); + break; + case WAIT_OBJECT_0 + 1: + PurgeComm (h, PURGE_TXABORT | PURGE_RXABORT); + select_printf ("interrupt"); + set_sig_errno (EINTR); + ready = -1; + break; + case WAIT_TIMEOUT: + PurgeComm (h, PURGE_TXABORT | PURGE_RXABORT); + break; + default: + PurgeComm (h, PURGE_TXABORT | PURGE_RXABORT); + debug_printf ("WaitForMultipleObjects"); + goto err; + } + + return ready; + +err: + if (GetLastError () == ERROR_OPERATION_ABORTED) + { + select_printf ("operation aborted"); + return ready; + } + + __seterrno (); + s->saw_error = TRUE; + select_printf ("error %E"); + return -1; +} + +static DWORD WINAPI +thread_serial (void *arg) +{ + serialinf *si = (serialinf *)arg; + BOOL gotone= FALSE; + + for (;;) + { + select_record *s = si->start; + while ((s = s->next)) + if (s->startup == start_thread_serial) + { + if (peek_serial (s, 0)) + gotone = TRUE; + } + if (si->stop_thread_serial) + { + select_printf ("stopping"); + break; + } + if (gotone) + break; + } + + select_printf ("exiting"); + return 0; +} + +static int +start_thread_serial (select_record *me, select_stuff *stuff) +{ + if (stuff->device_specific[FHDEVN(FH_SERIAL)]) + { + me->h = ((pipeinf *) stuff->device_specific[FHDEVN(FH_SERIAL)])->thread; + return 1; + } + serialinf *si = new serialinf; + si->start = &stuff->start; + si->stop_thread_serial = FALSE; + si->thread = me->h = makethread (thread_serial, (LPVOID)si, 0, "select_serial"); + if (!me->h) + return 0; + stuff->device_specific[FHDEVN(FH_SERIAL)] = (void *)si; + return 1; +} + +static void +serial_cleanup (select_record *me, select_stuff *stuff) +{ + serialinf *si = (serialinf *)stuff->device_specific[FHDEVN(FH_SERIAL)]; + if (si && si->thread) + { + si->stop_thread_serial = TRUE; + WaitForSingleObject (si->thread, INFINITE); + CloseHandle (si->thread); + delete si; + stuff->device_specific[FHDEVN(FH_SERIAL)] = NULL; + } +} + +static int +poll_serial (select_record *me, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds) + +{ + return peek_serial (me, 0) ? + set_bits (me, readfds, writefds, exceptfds) : + 0; +} + +MAKEready (serial) + +select_record * +fhandler_serial::select_read (select_record *s) +{ + if (!s) + { + s = new select_record; + s->startup = start_thread_serial; + s->poll = poll_serial; + s->verify = verify_ok; + s->cleanup = serial_cleanup; + } + s->read_selected = TRUE; + return s; +} + +select_record * +fhandler_serial::select_write (select_record *s) +{ + if (!s) + { + s = new select_record; + s->startup = no_startup; + s->poll = set_bits; + s->verify = verify_ok; + } + s->h = get_handle (); + s->write_selected = TRUE; + s->write_ready = TRUE; + return s; +} + +select_record * +fhandler_serial::select_except (select_record *s) +{ + if (!s) + { + s = new select_record; + s->startup = no_startup; + s->poll = set_bits; + s->verify = verify_ok; + } + s->h = NULL; + s->except_selected = FALSE; // Can't do this + return s; +} + +int +fhandler_base::ready_for_read (int, DWORD, int) +{ + return 1; +} + +select_record * +fhandler_base::select_read (select_record *s) +{ + if (!s) + { + s = new select_record; + s->startup = no_startup; + s->poll = set_bits; + s->verify = verify_ok; + } + s->h = get_handle (); + s->read_selected = TRUE; + s->read_ready = TRUE; + return s; +} + +select_record * +fhandler_base::select_write (select_record *s) +{ + if (!s) + { + s = new select_record; + s->startup = no_startup; + s->poll = set_bits; + s->verify = verify_ok; + } + s->h = get_handle (); + s->write_selected = TRUE; + s->write_ready = TRUE; + return s; +} + +select_record * +fhandler_base::select_except (select_record *s) +{ + if (!s) + { + s = new select_record; + s->startup = no_startup; + s->poll = set_bits; + s->verify = verify_ok; + } + s->h = NULL; + s->write_selected = TRUE; + return s; +} + +struct socketinf + { + HANDLE thread; + winsock_fd_set readfds, writefds, exceptfds; + SOCKET exitsock; + struct sockaddr_in sin; + select_record *start; + }; + +static int +peek_socket (select_record *me, int) +{ + winsock_fd_set ws_readfds, ws_writefds, ws_exceptfds; + struct timeval tv = {0}; + WINSOCK_FD_ZERO (&ws_readfds); + WINSOCK_FD_ZERO (&ws_writefds); + WINSOCK_FD_ZERO (&ws_exceptfds); + int gotone = 0; + + HANDLE h; + set_handle_or_return_if_not_open (h, me); + select_printf ("considering handle %p", h); + + if (me->read_selected) + { + select_printf ("adding read fd_set %s, fd %d", me->fh->get_name (), + me->fd); + WINSOCK_FD_SET (h, &ws_readfds); + } + if (me->write_selected) + { + select_printf ("adding write fd_set %s, fd %d", me->fh->get_name (), + me->fd); + WINSOCK_FD_SET (h, &ws_writefds); + } + if (me->except_selected) + { + select_printf ("adding except fd_set %s, fd %d", me->fh->get_name (), + me->fd); + WINSOCK_FD_SET (h, &ws_exceptfds); + } + int r = WINSOCK_SELECT (0, &ws_readfds, &ws_writefds, &ws_exceptfds, &tv); + select_printf ("WINSOCK_SELECT returned %d", r); + if (r == -1) + { + select_printf ("error %d", WSAGetLastError ()); + return 0; + } + + if (WINSOCK_FD_ISSET (h, &ws_readfds)) + gotone = me->read_ready = TRUE; + if (WINSOCK_FD_ISSET (h, &ws_writefds)) + gotone = me->write_ready = TRUE; + if (WINSOCK_FD_ISSET (h, &ws_exceptfds)) + gotone = me->except_ready = TRUE; + return gotone; +} + +static int +poll_socket (select_record *me, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds) +{ + return peek_socket (me, 0) ? + set_bits (me, readfds, writefds, exceptfds) : + 0; +} + +MAKEready (socket) + +static int start_thread_socket (select_record *, select_stuff *); + +static DWORD WINAPI +thread_socket (void *arg) +{ + socketinf *si = (socketinf *)arg; + + select_printf ("stuff_start %p", &si->start); + int r = WINSOCK_SELECT (0, &si->readfds, &si->writefds, &si->exceptfds, NULL); + select_printf ("Win32 select returned %d", r); + if (r == -1) + select_printf ("error %d", WSAGetLastError ()); + select_record *s = si->start; + while ((s = s->next)) + if (s->startup == start_thread_socket) + { + HANDLE h = s->fh->get_handle (); + select_printf ("s %p, testing fd %d (%s)", s, s->fd, s->fh->get_name ()); + if (WINSOCK_FD_ISSET (h, &si->readfds)) + { + select_printf ("read_ready"); + s->read_ready = TRUE; + } + if (WINSOCK_FD_ISSET (h, &si->writefds)) + { + select_printf ("write_ready"); + s->write_ready = TRUE; + } + if (WINSOCK_FD_ISSET (h, &si->exceptfds)) + { + select_printf ("except_ready"); + s->except_ready = TRUE; + } + } + + if (WINSOCK_FD_ISSET (si->exitsock, &si->readfds)) + select_printf ("saw exitsock read"); + + return 0; +} + +extern "C" unsigned long htonl (unsigned long); + +static int +start_thread_socket (select_record *me, select_stuff *stuff) +{ + socketinf *si; + + if ((si = (socketinf *)stuff->device_specific[FHDEVN(FH_SOCKET)])) + { + me->h = si->thread; + return 1; + } + + si = new socketinf; + WINSOCK_FD_ZERO (&si->readfds); + WINSOCK_FD_ZERO (&si->writefds); + WINSOCK_FD_ZERO (&si->exceptfds); + select_record *s = &stuff->start; + while ((s = s->next)) + if (s->startup == start_thread_socket) + { + HANDLE h = s->fh->get_handle (); + select_printf ("Handle %p", h); + if (s->read_selected) + { + WINSOCK_FD_SET (h, &si->readfds); + select_printf ("Added to readfds"); + } + if (s->write_selected) + { + WINSOCK_FD_SET (h, &si->writefds); + select_printf ("Added to writefds"); + } + if (s->except_selected) + { + WINSOCK_FD_SET (h, &si->exceptfds); + select_printf ("Added to exceptfds"); + } + } + + if ((si->exitsock = socket (PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) + { + set_winsock_errno (); + select_printf ("cannot create socket, %E"); + return -1; + } + /* Allow rapid reuse of the port. */ + int tmp = 1; + (void) setsockopt (si->exitsock, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp, sizeof (tmp)); + + int sin_len = sizeof(si->sin); + memset (&si->sin, 0, sizeof (si->sin)); + si->sin.sin_family = AF_INET; + si->sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + if (bind (si->exitsock, (struct sockaddr *) &si->sin, sizeof (si->sin)) < 0) + { + select_printf ("cannot bind socket, %E"); + goto err; + } + + if (getsockname (si->exitsock, (struct sockaddr *) &si->sin, &sin_len) < 0) + { + select_printf ("getsockname error"); + goto err; + } + + if (listen (si->exitsock, 1)) + { + select_printf ("listen failed, %E"); + goto err; + } + + select_printf ("exitsock %p", si->exitsock); + WINSOCK_FD_SET ((HANDLE) si->exitsock, &si->readfds); + WINSOCK_FD_SET ((HANDLE) si->exitsock, &si->exceptfds); + stuff->device_specific[FHDEVN(FH_SOCKET)] = (void *) si; + si->start = &stuff->start; + select_printf ("stuff_start %p", &stuff->start); + si->thread = me->h = makethread (thread_socket, (LPVOID)si, 0, + "select_socket"); + return !!me->h; + +err: + set_winsock_errno (); + closesocket (si->exitsock); + return -1; +} + +void +socket_cleanup (select_record *me, select_stuff *stuff) +{ + socketinf *si = (socketinf *)stuff->device_specific[FHDEVN(FH_SOCKET)]; + select_printf ("si %p si->thread %p", si, si ? si->thread : NULL); + if (si && si->thread) + { + select_printf ("connection to si->exitsock %p", si->exitsock); + SOCKET s = socket (AF_INET, SOCK_STREAM, 0); + /* Connecting to si->exitsock will cause any executing select to wake + up. When this happens then the exitsock condition will cause the + thread to terminate. */ + if (connect (s, (struct sockaddr *) &si->sin, sizeof (si->sin)) < 0) + { + set_winsock_errno (); + select_printf ("connect failed"); + /* FIXME: now what? */ + } + closesocket (s); + + /* Wait for thread to go away */ + WaitForSingleObject (si->thread, INFINITE); + closesocket (si->exitsock); + CloseHandle (si->thread); + stuff->device_specific[FHDEVN(FH_SOCKET)] = NULL; + delete si; + } + select_printf ("returning"); +} + +select_record * +fhandler_socket::select_read (select_record *s) +{ + if (!s) + { + s = new select_record; + s->startup = start_thread_socket; + s->poll = poll_socket; + s->verify = verify_true; + s->cleanup = socket_cleanup; + } + s->read_selected = TRUE; + return s; +} + +select_record * +fhandler_socket::select_write (select_record *s) +{ + if (!s) + { + s = new select_record; + s->startup = start_thread_socket; + s->poll = poll_socket; + s->verify = verify_true; + s->cleanup = socket_cleanup; + } + s->write_selected = TRUE; + return s; +} + +select_record * +fhandler_socket::select_except (select_record *s) +{ + if (!s) + { + s = new select_record; + s->startup = start_thread_socket; + s->poll = poll_socket; + s->verify = verify_true; + s->cleanup = socket_cleanup; + } + s->except_selected = TRUE; + return s; +} + +static int +peek_windows (select_record *me, int) +{ + MSG m; + HANDLE h; + set_handle_or_return_if_not_open (h, me); + if (PeekMessage (&m, (HWND) h, 0, 0, PM_NOREMOVE)) + { + me->read_ready = TRUE; + select_printf ("window %d(%p) ready", me->fd, me->fh->get_handle ()); + return 1; + } + + select_printf ("window %d(%p) not ready", me->fd, me->fh->get_handle ()); + return me->write_ready; +} + +static int +poll_windows (select_record *me, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds) +{ + + return peek_windows (me, 0) ? + set_bits (me, readfds, writefds, exceptfds) : + 0; +} + +MAKEready (windows) + +select_record * +fhandler_windows::select_read (select_record *s) +{ + if (!s) + { + s = new select_record; + s->startup = no_startup; + s->poll = poll_windows; + s->verify = poll_windows; + } + s->h = get_handle (); + s->read_selected = TRUE; + s->h = get_handle (); + s->windows_handle = TRUE; + return s; +} + +select_record * +fhandler_windows::select_write (select_record *s) +{ + if (!s) + { + s = new select_record; + s->startup = no_startup; + s->poll = set_bits; + s->verify = verify_ok; + } + s->h = get_handle (); + s->write_selected = TRUE; + s->write_ready = TRUE; + s->windows_handle = TRUE; + return s; +} + +select_record * +fhandler_windows::select_except (select_record *s) +{ + if (!s) + { + s = new select_record; + s->startup = no_startup; + s->poll = set_bits; + s->verify = verify_ok; + } + s->h = get_handle (); + s->except_selected = TRUE; + s->except_ready = TRUE; + s->windows_handle = TRUE; + return s; +} diff --git a/winsup/cygwin/select.h b/winsup/cygwin/select.h new file mode 100644 index 000000000..286951ebc --- /dev/null +++ b/winsup/cygwin/select.h @@ -0,0 +1,56 @@ +/* select.h + + Copyright 1998 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +/* Winsock select() types and macros */ + +/* + * Use this struct to interface to + * the system provided select. + */ +typedef struct winsock_fd_set +{ + unsigned int fd_count; + HANDLE fd_array[1024]; /* Dynamically allocated. */ +} winsock_fd_set; + +/* + * Define the Win32 winsock definitions to have a prefix WINSOCK_ + * so we can be explicit when we are using them. + */ +#define WINSOCK_FD_ISSET(fd, set) __WSAFDIsSet ((SOCKET)fd, (fd_set *)set) +#define WINSOCK_FD_SET(fd, set) do { \ + (set)->fd_array[(set)->fd_count++]=fd;\ +} while(0) +#define WINSOCK_FD_ZERO(set) ((set)->fd_count = 0) +#define WINSOCK_FD_CLR(fd, set) do { \ + u_int __i; \ + for (__i = 0; __i < (set)->fd_count ; __i++) { \ + if ((set)->fd_array[__i] == fd) { \ + while (__i < (set)->fd_count-1) { \ + (set)->fd_array[__i] = \ + (set)->fd_array[__i+1]; \ + __i++; \ + } \ + (set)->fd_count--; \ + break; \ + } \ + } \ +} while(0) + +extern "C" int PASCAL __WSAFDIsSet(SOCKET, fd_set*); +extern "C" int PASCAL win32_select(int, fd_set*, fd_set*, fd_set*, const struct timeval*); + +/* + * call to winsock's select() - + * type coercion need to appease confused prototypes + */ +#define WINSOCK_SELECT(nfd, rd, wr, ex, timeo) \ + win32_select (nfd, (fd_set *)rd, (fd_set *)wr, (fd_set *)ex, timeo) + diff --git a/winsup/cygwin/shared.cc b/winsup/cygwin/shared.cc new file mode 100644 index 000000000..f153cfe19 --- /dev/null +++ b/winsup/cygwin/shared.cc @@ -0,0 +1,287 @@ +/* shared.cc: shared data area support. + + Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include +#include +#include "winsup.h" + +#define SHAREDVER (unsigned)(cygwin_version.api_major << 16 | \ + cygwin_version.api_minor) + +shared_info NO_COPY *cygwin_shared = NULL; + +/* The handle of the shared data area. */ +HANDLE cygwin_shared_h = NULL; + +/* General purpose security attribute objects for global use. */ +SECURITY_ATTRIBUTES NO_COPY sec_none; +SECURITY_ATTRIBUTES NO_COPY sec_none_nih; +SECURITY_ATTRIBUTES NO_COPY sec_all; +SECURITY_ATTRIBUTES NO_COPY sec_all_nih; + +char * __stdcall +shared_name (const char *str, int num) +{ + static NO_COPY char buf[MAX_PATH] = {0}; + char envbuf[6]; + + __small_sprintf (buf, "%s.%s.%d", cygwin_version.shared_id, str, num); + if (GetEnvironmentVariable("CYGWIN_TESTING", envbuf, 5)) + strcat(buf, cygwin_version.dll_build_date); + return buf; +} + +/* Open the shared memory map. */ +static void __stdcall +open_shared_file_map () +{ + cygwin_shared = (shared_info *) open_shared ("shared", + cygwin_shared_h, + sizeof (*cygwin_shared), + (void *)0xa000000); + ProtectHandle (cygwin_shared); +} + +void * __stdcall +open_shared (const char *name, HANDLE &shared_h, DWORD size, void *addr) +{ + void *shared; + + if (!shared_h) + { + char *mapname; + if (!name) + mapname = NULL; + else + { + mapname = shared_name (name, 0); + shared_h = OpenFileMappingA (FILE_MAP_READ | FILE_MAP_WRITE, + TRUE, mapname); + } + if (!shared_h && + !(shared_h = CreateFileMappingA ((HANDLE) 0xffffffff, + &sec_all, + PAGE_READWRITE, + 0, + size, + mapname))) + api_fatal ("CreateFileMappingA, %E. Terminating."); + } + + shared = (shared_info *) MapViewOfFileEx (shared_h, + FILE_MAP_READ | FILE_MAP_WRITE, + 0, 0, 0, addr); + + if (!shared) + { + /* Probably win95, so try without specifying the address. */ + shared = (shared_info *) MapViewOfFileEx (shared_h, + FILE_MAP_READ|FILE_MAP_WRITE, + 0,0,0,0); + } + + if (!shared) + api_fatal ("MapViewOfFileEx, %E. Terminating."); + + debug_printf ("name %s, shared %p, h %p", name, shared, shared_h); + + /* FIXME: I couldn't find anywhere in the documentation a note about + whether the memory is initialized to zero. The code assumes it does + and since this part seems to be working, we'll leave it as is. */ + return shared; +} + +void +shared_info::initialize () +{ + /* Ya, Win32 provides a way for a dll to watch when it's first loaded. + We may eventually want to use it but for now we have this. */ + if (inited) + { + if (inited != SHAREDVER) + api_fatal ("shared region is corrupted. inited %x", inited); + return; + } + + /* Initialize the mount table. */ + mount.init (); + + /* Initialize the process table. */ + p.init (); + + /* Initialize the queue of deleted files. */ + delqueue.init (); + + /* Initialize tty table. */ + tty.init (); + + /* Fetch misc. registry entries. */ + + reg_key reg (KEY_READ, NULL); + + /* Note that reserving a huge amount of heap space does not result in + swapping since we are not committing it. */ + /* FIXME: We should not be restricted to a fixed size heap no matter + what the fixed size is. */ + + heap_chunk_in_mb = reg.get_int ("heap_chunk_in_mb", 128); + if (heap_chunk_in_mb < 4) + { + heap_chunk_in_mb = 4; + reg.set_int ("heap_chunk_in_mb", heap_chunk_in_mb); + } + + inited = SHAREDVER; +} + +void __stdcall +shared_init () +{ + open_shared_file_map (); + + cygwin_shared->initialize (); +} + +void __stdcall +shared_terminate () +{ + if (cygwin_shared_h) + ForceCloseHandle (cygwin_shared_h); +} + +unsigned +shared_info::heap_chunk_size () +{ + return heap_chunk_in_mb << 20; +} + +/* For apps that wish to access the shared data. */ + +shared_info * +cygwin_getshared () +{ + return cygwin_shared; +} + +/* + * Function to return a common SECURITY_DESCRIPTOR * that + * allows all access. + */ + +static NO_COPY SECURITY_DESCRIPTOR *null_sdp = 0; + +SECURITY_DESCRIPTOR *__stdcall +get_null_sd () +{ + static NO_COPY SECURITY_DESCRIPTOR sd; + + if (null_sdp == 0) + { + InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION); + SetSecurityDescriptorDacl (&sd, TRUE, 0, FALSE); + null_sdp = &sd; + } + return null_sdp; +} + +extern PSID get_admin_sid (); +extern PSID get_system_sid (); +extern PSID get_creator_owner_sid (); + +PSECURITY_ATTRIBUTES __stdcall +sec_user (PVOID sa_buf, PSID sid2, BOOL inherit) +{ + if (! sa_buf) + return inherit ? &sec_none_nih : &sec_none; + + PSECURITY_ATTRIBUTES psa = (PSECURITY_ATTRIBUTES) sa_buf; + PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) + ((char *) sa_buf + sizeof (*psa)); + PACL acl = (PACL) ((char *) sa_buf + sizeof (*psa) + sizeof (*psd)); + + char sid_buf[40]; + PSID sid = (PSID) sid_buf; + + if (myself->psid) + CopySid (40, sid, myself->psid); + else if (! lookup_name (getlogin (), myself->logsrv, sid)) + return inherit ? &sec_none_nih : &sec_none; + + size_t acl_len = sizeof (ACL) + + 4 * (sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD)) + + GetLengthSid (sid) + + GetLengthSid (get_admin_sid ()) + + GetLengthSid (get_system_sid ()) + + GetLengthSid (get_creator_owner_sid ()); + if (sid2) + acl_len += sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD) + + GetLengthSid (sid2); + + if (! InitializeAcl (acl, acl_len, ACL_REVISION)) + debug_printf("InitializeAcl %E"); + + if (! AddAccessAllowedAce (acl, ACL_REVISION, + SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL, + sid)) + debug_printf("AddAccessAllowedAce(%s) %E", getlogin()); + + if (! AddAccessAllowedAce (acl, ACL_REVISION, + SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL, + get_admin_sid ())) + debug_printf("AddAccessAllowedAce(admin) %E"); + + if (! AddAccessAllowedAce (acl, ACL_REVISION, + SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL, + get_system_sid ())) + debug_printf("AddAccessAllowedAce(system) %E"); + + if (! AddAccessAllowedAce (acl, ACL_REVISION, + SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL, + get_creator_owner_sid ())) + debug_printf("AddAccessAllowedAce(creator_owner) %E"); + + if (sid2) + if (! AddAccessAllowedAce (acl, ACL_REVISION, + SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL, + sid2)) + debug_printf("AddAccessAllowedAce(sid2) %E"); + + if (! InitializeSecurityDescriptor (psd, + SECURITY_DESCRIPTOR_REVISION)) + debug_printf("InitializeSecurityDescriptor %E"); + +/* + * Setting the owner lets the created security attribute not work + * on NT4 SP3 Server. Don't know why, but the function still does + * what it should do also if the owner isn't set. +*/ +#if 0 + if (! SetSecurityDescriptorOwner (psd, sid, FALSE)) + debug_printf("SetSecurityDescriptorOwner %E"); +#endif + + if (! SetSecurityDescriptorDacl (psd, TRUE, acl, FALSE)) + debug_printf("SetSecurityDescriptorDacl %E"); + + psa->nLength = sizeof (SECURITY_ATTRIBUTES); + psa->lpSecurityDescriptor = psd; + psa->bInheritHandle = inherit; + return psa; +} + +SECURITY_ATTRIBUTES *__stdcall +sec_user_nih (PVOID sa_buf, PSID sid2) +{ + return sec_user (sa_buf, sid2, FALSE); +} + diff --git a/winsup/cygwin/shared.sgml b/winsup/cygwin/shared.sgml new file mode 100644 index 000000000..f43d654e2 --- /dev/null +++ b/winsup/cygwin/shared.sgml @@ -0,0 +1,17 @@ + + +cygwin_getshared + + +shared_info * +cygwin_getshared + + + +Returns a pointer to an internal Cygwin memory structure +containing shared information used by cooperating cygwin processes. +This function is intended for use only by "system" programs like +mount and ps. + + + diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc new file mode 100644 index 000000000..5682b868b --- /dev/null +++ b/winsup/cygwin/signal.cc @@ -0,0 +1,367 @@ +/* signal.cc + + Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions. + + Written by Steve Chamberlain of Cygnus Support, sac@cygnus.com + Significant changes by Sergey Okhapkin + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include "winsup.h" + +extern "C" +_sig_func_ptr +signal (int sig, _sig_func_ptr func) +{ + _sig_func_ptr prev; + + /* check that sig is in right range */ + if (sig < 0 || sig >= NSIG) + { + set_errno (EINVAL); + syscall_printf ("SIG_ERR = signal (%d, %p)", sig, func); + return (_sig_func_ptr) SIG_ERR; + } + + prev = myself->getsig(sig).sa_handler; + myself->getsig(sig).sa_handler = func; + myself->getsig(sig).sa_mask = 0; + syscall_printf ("%p = signal (%d, %p)", prev, sig, func); + return prev; +} + +extern "C" +unsigned int +sleep (unsigned int seconds) +{ + int res; + unsigned start_time; + + start_time = GetTickCount (); + + syscall_printf ("sleep (%d)", seconds); + res = WaitForSingleObject (signal_arrived, seconds * 1000); + if (res == WAIT_TIMEOUT) + { + syscall_printf ("0 = sleep (%d)", seconds); + return 0; + } + return (GetTickCount () - start_time)/1000; +} + +extern "C" +unsigned int +usleep (unsigned int useconds) +{ + syscall_printf ("usleep (%d)", useconds); + WaitForSingleObject (signal_arrived, (useconds + 500) / 1000); + syscall_printf ("0 = usleep (%d)", useconds); + return 0; +} + +extern "C" +int +sigprocmask (int sig, const sigset_t *set, sigset_t *oldset) +{ + /* check that sig is in right range */ + if (sig < 0 || sig >= NSIG) + { + set_errno (EINVAL); + syscall_printf ("SIG_ERR = sigprocmask sig %d out of range", sig); + return -1; + } + + /* gcc can call sigprocmask when a builtin contructor is activated. + This can happen prior to the setup of myself */ + if (!user_data) + return 0; + + if (oldset) + *oldset = myself->getsigmask (); + if (set) + { + sigset_t newmask = myself->getsigmask (); + switch (sig) + { + case SIG_BLOCK: + /* add set to current mask */ + newmask |= *set; + break; + case SIG_UNBLOCK: + /* remove set from current mask */ + newmask &= ~*set; + break; + case SIG_SETMASK: + /* just set it */ + newmask = *set; + break; + default: + set_errno (EINVAL); + return -1; + } + (void) set_process_mask (newmask); + } + return 0; +} + +#if 0 +/* This is called _raise because the real raise is in newlib. */ +int +_raise (int sig) +{ + if (!user_data) + { + set_errno (ESRCH); + return -1; + } + + return _kill (myself->pid, sig); +} +#endif + +static int +kill_worker (pid_t pid, int sig) +{ + int res = 0; + pinfo *dest = procinfo (pid); + BOOL sendSIGCONT; + + if (!dest) + { + set_errno (ESRCH); + return -1; + } + + dest->setthread2signal(NULL); + + if ((sendSIGCONT = (sig < 0))) + sig = -sig; + +#if 0 + if (dest == myself && !sendSIGCONT) + dest = myself_nowait_nonmain; +#endif + if (sig == 0) + res = proc_exists (dest) ? 0 : -1; + else if ((res = sig_send (dest, sig))) + { + sigproc_printf ("%d = sig_send, %E ", res); + res = -1; + } + else if (sendSIGCONT) + (void) sig_send (dest, SIGCONT); + + syscall_printf ("%d = kill_worker (%d, %d)", res, pid, sig); + return res; +} + +/* This is called _kill because the real kill is in newlib. */ +int +_kill (pid_t pid, int sig) +{ + syscall_printf ("kill (%d, %d)", pid, sig); + /* check that sig is in right range */ + if (sig < 0 || sig >= NSIG) + { + set_errno (EINVAL); + syscall_printf ("sig %d out of range", sig); + return -1; + } + + /* Silently ignore stop signals from a member of orphaned process group. + FIXME: Why??? */ + if (ISSTATE(myself, PID_ORPHANED) && + (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU)) + sig = 0; + + return (pid > 0) ? kill_worker (pid, sig) : kill_pgrp (-pid, sig); +} + +int +kill_pgrp (pid_t pid, int sig) +{ + int res = 0; + int found = 0; + int killself = 0; + + sigproc_printf ("pid %d, sig %d", pid, sig); + + for (int i = 0; i < cygwin_shared->p.size (); i++) + { + pinfo *p = &cygwin_shared->p.vec[i]; + + if (!proc_exists (p)) + continue; + + /* Is it a process we want to kill? */ + if (pid == 0 && (p->pgid != myself->pgid || p->ctty != myself->ctty)) + continue; + if (pid > 1 && p->pgid != pid) + continue; + if (sig < 0 && NOTSTATE(p, PID_STOPPED)) + continue; + sigproc_printf ("killing pid %d, pgrp %d, p->ctty %d, myself->ctty %d", + p->pid, p->pgid, p->ctty, myself->ctty); + if (p == myself) + killself++; + else if (kill_worker (p->pid, sig)) + res = -1; + found++; + } + + if (killself && kill_worker (myself->pid, sig)) + res = -1; + + if (!found) + { + set_errno (ESRCH); + res = -1; + } + syscall_printf ("%d = kill (%d, %d)", res, pid, sig); + return res; +} + +extern "C" +int +killpg (int pgrp, int sig) +{ + return _kill (-pgrp, sig); +} + +extern "C" +int +sigaction (int sig, + const struct sigaction *newaction, + struct sigaction *oldaction) +{ + /* check that sig is in right range */ + if (sig < 0 || sig >= NSIG) + { + set_errno (EINVAL); + syscall_printf ("SIG_ERR = sigaction sig %d out of range", sig); + return -1; + } + + if (oldaction) + *oldaction = myself->getsig(sig); + + if (newaction) + { + if ((sig == SIGKILL || sig == SIGSTOP) && newaction->sa_handler != SIG_DFL) + { + set_errno (EINVAL); + return -1; + } + myself->getsig(sig) = *newaction; + if (newaction->sa_handler == SIG_IGN) + sig_clear (sig); + if (newaction->sa_handler == SIG_DFL && sig == SIGCHLD) + sig_clear (sig); + } + + return 0; +} + +extern "C" +int +sigaddset (sigset_t *set, const int sig) +{ + /* check that sig is in right range */ + if (sig <= 0 || sig >= NSIG) + { + set_errno (EINVAL); + syscall_printf ("SIG_ERR = sigaddset sig %d out of range", sig); + return -1; + } + + *set |= SIGTOMASK (sig); + return 0; +} + +extern "C" +int +sigdelset (sigset_t *set, const int sig) +{ + /* check that sig is in right range */ + if (sig <= 0 || sig >= NSIG) + { + set_errno (EINVAL); + syscall_printf ("SIG_ERR = sigdelset sig %d out of range", sig); + return -1; + } + + *set &= ~SIGTOMASK (sig); + return 0; +} + +extern "C" +int +sigismember (const sigset_t *set, int sig) +{ + /* check that sig is in right range */ + if (sig <= 0 || sig >= NSIG) + { + set_errno (EINVAL); + syscall_printf ("SIG_ERR = sigdelset sig %d out of range", sig); + return -1; + } + + if (*set & SIGTOMASK (sig)) + return 1; + else + return 0; +} + +extern "C" +int +sigemptyset (sigset_t *set) +{ + *set = (sigset_t) 0; + return 0; +} + +extern "C" +int +sigfillset (sigset_t *set) +{ + *set = ~((sigset_t) 0); + return 0; +} + +extern "C" +int +sigpending (sigset_t *set) +{ + unsigned bit; + *set = 0; + for (int sig = 1; sig < NSIG; sig++) + if (*myself->getsigtodo(sig) && myself->getsigmask () & (bit = SIGTOMASK (sig))) + *set |= bit; + return 0; +} + +extern "C" +int +sigsuspend (const sigset_t *set) +{ + return handle_sigsuspend (*set); +} + +extern "C" +int +sigpause (int signal_mask) +{ + return handle_sigsuspend ((sigset_t) signal_mask); +} + +extern "C" +int +pause (void) +{ + return handle_sigsuspend (myself->getsigmask ()); +} diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc new file mode 100644 index 000000000..97a0f3a35 --- /dev/null +++ b/winsup/cygwin/sigproc.cc @@ -0,0 +1,1345 @@ +/* sigproc.cc: inter/intra signal and sub process handler + + Copyright 1997, 1998, 1999, 2000 Cygnus Solutions. + + Written by Christopher Faylor + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include +#include +#include "winsup.h" + +extern BOOL allow_ntsec; + +/* + * Convenience defines + */ +#define WSSC 60000 // Wait for signal completion +#define WPSP 40000 // Wait for proc_subproc mutex +#define WSPX 20000 // Wait for wait_sig to terminate +#define WWSP 20000 // Wait for wait_subproc to terminate + +#define WAIT_SIG_PRIORITY THREAD_PRIORITY_HIGHEST + +#define TOTSIGS (NSIG + __SIGOFFSET) + +#define sip_printf(fmt, args...) sigproc_printf (fmt , ## args) + +#define wake_wait_subproc() SetEvent (events[0]) + +#define no_signals_available() (!hwait_sig || !sig_loop_wait) + +/* + * Global variables + */ +const char *__sp_fn ; +int __sp_ln; + +char NO_COPY myself_nowait_dummy[1] = {'0'};// Flag to sig_send that signal goes to + // current process but no wait is required +char NO_COPY myself_nowait_nonmain_dummy[1] = {'1'};// Flag to sig_send that signal goes to + // current process but no wait is required + // if this is not the main thread. + +HANDLE NO_COPY signal_arrived; // Event signaled when a signal has + // resulted in a user-specified + // function call +/* + * Common variables + */ + + +/* How long to wait for message/signals. Normally this is infinite. + * On termination, however, these are set to zero as a flag to exit. + */ + +#define Static static NO_COPY + +Static DWORD proc_loop_wait = 500; // Wait for subprocesses to exit +Static DWORD sig_loop_wait = 500; // Wait for signals to arrive + +Static HANDLE sigcatch_nonmain = NULL; // The semaphore signaled when + // signals are available for + // processing from non-main thread +Static HANDLE sigcatch_main = NULL; // Signalled when main thread sends a + // signal +Static HANDLE sigcatch_nosync = NULL; // Signal wait_sig to scan sigtodo + // but not to bother with any + // synchronization +Static HANDLE sigcomplete_main = NULL; // Event signaled when a signal has + // finished processing for the main + // thread +Static HANDLE sigcomplete_nonmain = NULL;// Semaphore raised for non-main + // threads when a signal has finished + // processing +Static HANDLE hwait_sig = NULL; // Handle of wait_sig thread +Static HANDLE hwait_subproc = NULL; // Handle of sig_subproc thread + +Static HANDLE wait_sig_inited = NULL; // Control synchronization of + // message queue startup +Static muto *sync_proc_subproc = NULL; // Control access to + // subproc stuff + +/* Used by WaitForMultipleObjects. These are handles to child processes. + */ +Static HANDLE events[PSIZE + 1] = {0}; // All my children's handles++ +#define hchildren (events + 1) // Where the children handles begin +Static pinfo *pchildren[PSIZE] = {NULL};// All my children info +Static pinfo *zombies[PSIZE] = {NULL}; // All my deceased children info +Static int nchildren = 0; // Number of active children +Static int nzombies = 0; // Number of deceased children + +Static waitq waitq_head = {0}; // Start of queue for wait'ing threads +Static waitq waitq_main; // Storage for main thread + +DWORD NO_COPY maintid = 0; // ID of the main thread +Static DWORD sigtid = 0; // ID of the signal thread + +int NO_COPY pending_signals = 0; // TRUE if signals pending + +/* Functions + */ +static int __stdcall checkstate (waitq *); +static BOOL __inline get_proc_lock (DWORD, DWORD); +static HANDLE __stdcall getsem (pinfo *, const char *, int, int); +static void __stdcall remove_child (int); +static void __stdcall remove_zombie (int); +static DWORD WINAPI wait_sig (VOID *arg); +static int __stdcall stopped_or_terminated (waitq *, pinfo *); +static DWORD WINAPI wait_subproc (VOID *); + +/* Determine if the parent process is alive. + */ + +BOOL __stdcall +my_parent_is_alive () +{ + DWORD res; + if (!parent_alive) + { + debug_printf ("No parent_alive mutex"); + res = FALSE; + } + else + for (int i = 0; i < 2; i++) + switch (res = WaitForSingleObject (parent_alive, 0)) + { + case WAIT_OBJECT_0: + debug_printf ("parent dead."); + res = FALSE; + goto out; + case WAIT_TIMEOUT: + debug_printf ("parent still alive"); + res = TRUE; + goto out; + case WAIT_FAILED: + DWORD werr = GetLastError (); + if (werr == ERROR_INVALID_HANDLE && i == 0) + continue; + system_printf ("WFSO for parent_alive(%p) failed, error %d", + parent_alive, werr); + res = FALSE; + goto out; + } +out: + return res; +} + +__inline static void +wait_for_me () +{ + /* See if this is the first signal call after initialization. + * If so, wait for notification that all initialization has completed. + * Then set the handle to NULL to avoid checking this again. + */ + if (wait_sig_inited) + { + (void) WaitForSingleObject (wait_sig_inited, INFINITE); + (void) ForceCloseHandle (wait_sig_inited); + wait_sig_inited = NULL; + } +} + +static BOOL __stdcall +proc_can_be_signalled (pinfo *p) +{ + if (p == myself_nowait || p == myself_nowait_nonmain || p == myself) + { + wait_for_me (); + return 1; + } + + return ISSTATE (p, PID_INITIALIZING) || + (((p)->process_state & (PID_ACTIVE | PID_IN_USE)) == + (PID_ACTIVE | PID_IN_USE)); +} + +/* Test to determine if a process really exists and is processing + * signals. + */ +BOOL __stdcall +proc_exists (pinfo *p) +{ + HANDLE h; + + if (p == NULL) + return FALSE; + + if (p == myself || p == myself_nowait_nonmain || p == myself_nowait) + return TRUE; + + if (p->process_state == PID_NOT_IN_USE || !p->dwProcessId) + return FALSE; + + sip_printf ("checking for existence of pid %d, window pid %d", p->pid, + p->dwProcessId); + if (p->ppid == myself->pid && p->hProcess != NULL) + { + sip_printf ("it's mine, process_state %x", p->process_state); + return proc_can_be_signalled (p); + } + + /* Note: Process is alive if OpenProcess() call fails due to permissions */ + if (((h = OpenProcess (STANDARD_RIGHTS_REQUIRED, FALSE, p->dwProcessId)) + != NULL) || (GetLastError () == ERROR_ACCESS_DENIED)) + { + sip_printf ("it exists, %p", h); + if (h) + { + DWORD rc = WaitForSingleObject (h, 0); + CloseHandle (h); + if (rc == WAIT_OBJECT_0) + return 0; + } + return proc_can_be_signalled (p); + } + + sip_printf ("it doesn't exist"); + /* If the parent pid does not exist, clean this process out of the pinfo + * table. It must have died abnormally. + */ + if ((p->pid == p->ppid) || (p->ppid == 1) || !proc_exists (procinfo (p->ppid))) + { + p->hProcess = NULL; + p->process_state = PID_NOT_IN_USE; + } + return FALSE; +} + +/* Handle all subprocess requests + */ +#define vchild ((pinfo *) val) +int __stdcall +proc_subproc (DWORD what, DWORD val) +{ + int rc = 1; + int potential_match; + DWORD exitcode; + pinfo *child; + int send_sigchld = 0; + waitq *w; + +#define wval ((waitq *) val) + + sip_printf ("args: %x, %d", what, val); + + if (!get_proc_lock (what, val)) // Serialize access to this function + { + sip_printf ("I am not ready"); + goto out1; + } + + switch (what) + { + /* Add a new subprocess to the children arrays. + * (usually called from the main thread) + */ + case PROC_ADDCHILD: + if (nchildren >= PSIZE - 1) + system_printf ("nchildren too large %d", nchildren); + if (WaitForSingleObject (vchild->hProcess, 0) != WAIT_TIMEOUT) + { + system_printf ("invalid process handle %p. pid %d, win pid %d", + vchild->hProcess, vchild->pid, vchild->dwProcessId); + rc = 0; + break; + } + + pchildren[nchildren] = vchild; + hchildren[nchildren] = vchild->hProcess; + ProtectHandle (vchild->hProcess); + sip_printf ("added pid %d to wait list, slot %d, winpid %p, handle %p", + vchild->pid, nchildren, vchild->dwProcessId, + vchild->hProcess); + + nchildren++; + wake_wait_subproc (); + break; + + /* A child is in the stopped state. Scan wait() queue to see if anyone + * should be notified. (Called from wait_sig thread) + */ + case PROC_CHILDSTOPPED: + child = myself; // Just to avoid accidental NULL dereference + sip_printf ("Received stopped notification"); + goto scan_wait; + + /* A child process had terminated. + * Possibly this is just due to an exec(). Cygwin implements an exec() + * as a "handoff" from one windows process to another. If child->hProcess + * is different from what is recorded in hchildren, then this is an exec(). + * Otherwise this is a normal child termination event. + * (called from wait_subproc thread) + */ + case PROC_CHILDTERMINATED: + rc = 0; + child = pchildren[val]; + if (GetExitCodeProcess (hchildren[val], &exitcode) && + hchildren[val] != child->hProcess) + { + sip_printf ("pid %d[%d], reparented old hProcess %p, new %p", + child->pid, val, hchildren[val], child->hProcess); + ForceCloseHandle1 (hchildren[val], childhProc); + hchildren[val] = child->hProcess; /* Filled out by child */ + ProtectHandle1 (child->hProcess, childhProc); + wake_wait_subproc (); + break; // This was an exec() + } + + sip_printf ("pid %d[%d] terminated, handle %p, nchildren %d, nzombies %d", + child->pid, val, hchildren[val], nchildren, nzombies); + remove_child (val); // Remove from children arrays + zombies[nzombies++] = child; // Add to zombie array + wake_wait_subproc (); // Notify wait_subproc thread that + // nchildren has changed. + child->process_state = PID_ZOMBIE;// Walking dead + if (!proc_loop_wait) // Don't bother if wait_subproc is + break; // exiting + + send_sigchld = 1; + + scan_wait: + /* Scan the linked list of wait()ing threads. If a wait's parameters + * match this pid, then activate it. + */ + for (w = &waitq_head; w->next != NULL; w = w->next) + { + if ((potential_match = checkstate (w)) > 0) + sip_printf ("released waiting thread"); + else if (potential_match < 0) + sip_printf ("only found non-terminated children"); + else if (potential_match == 0) // nothing matched + { + sip_printf ("waiting thread found no children"); + HANDLE oldw = w->next->ev; + w->next->ev = NULL; + if (!SetEvent (oldw)) + system_printf ("couldn't wake up wait event %p, %E", oldw); + w->next = w->next->next; + } + if (w->next == NULL) + break; + } + + sip_printf ("finished processing terminated/stopped child"); + if (!send_sigchld) + break; // No need to send a SIGCHLD + + /* Send a SIGCHLD to myself. */ + sync_proc_subproc->release (); // Avoid a potential deadlock + rc = sig_send (NULL, SIGCHLD); // Send a SIGCHLD + goto out1; // Don't try to unlock. We don't have a lock. + + + /* Clear all waiting threads. Called from exceptions.cc prior to + * the main thread's dispatch to a signal handler function. + * (called from wait_sig thread) + */ + case PROC_CLEARWAIT: + /* Clear all "wait"ing threads. */ + sip_printf ("clear waiting threads"); + for (w = &waitq_head; w->next != NULL; w = w->next) + { + sip_printf ("clearing waiting thread, pid %d", w->next->pid); + w->next->status = -1; /* flag that a signal was received */ + if (!SetEvent (w->next->ev)) + system_printf ("Couldn't wake up wait event, %E"); + } + waitq_head.next = NULL; + sip_printf ("finished clearing"); + break; + + /* Handle a wait4() operation. Allocates an event for the calling + * thread which is signaled when the appropriate pid exits or stops. + * (usually called from the main thread) + */ + case PROC_WAIT: + wval->ev = NULL; // Don't know event flag yet + + if (wval->pid <= 0) + child = NULL; // Not looking for a specific pid + else if ((child = procinfo (wval->pid)) == NULL) + goto out; // invalid pid. flag no such child + + wval->status = 0; // Don't know status yet + + /* Put waitq structure at the end of a linked list. */ + for (w = &waitq_head; w->next != NULL; w = w->next) + if (w->next == wval && (w->next = w->next->next) == NULL) + break; + + wval->next = NULL; /* This will be last in the list */ + sip_printf ("wval->pid %d, wval->options %d", wval->pid, wval->options); + + /* If the first time for this thread, create a new event, otherwise + * reset the event. + */ + if ((wval->ev = wval->thread_ev) == NULL) + { + wval->ev = wval->thread_ev = CreateEvent (&sec_none_nih, TRUE, + FALSE, NULL); + ProtectHandle (wval->ev); + } + ResetEvent (wval->ev); + + /* Scan list of children to see if any have died. + * If so, the event flag is set so that the wait* () + * process will return immediately. + * + * If no children were found and the wait option was WNOHANG, + * then set the pid to 0 and remove the waitq value from + * consideration. + */ + w->next = wval; /* set at end of wait queue */ + if ((potential_match = checkstate (w)) <= 0) + { + if (!potential_match) + { + w->next = NULL; // don't want to keep looking + wval->ev = NULL; // flag that there are no children + sip_printf ("no appropriate children, %p, %p", + wval->thread_ev, wval->ev); + } + else if (wval->options & WNOHANG) + { + w->next = NULL; // don't want to keep looking + wval->pid = 0; // didn't find a pid + if (!SetEvent (wval->ev)) // wake up wait4 () immediately + system_printf ("Couldn't wake up wait event, %E"); + sip_printf ("WNOHANG and no terminated children, %p, %p", + wval->thread_ev, wval->ev); + } + } + if (w->next != NULL) + sip_printf ("wait activated %p, %p", wval->thread_ev, wval->ev); + else if (wval->ev != NULL) + sip_printf ("wait activated %p. Reaped zombie.", wval->ev); + else + sip_printf ("wait not activated %p, %p", wval->thread_ev, wval->ev); + break; + } + +out: + sync_proc_subproc->release (); // Release the lock +out1: + sip_printf ("returning %d", rc); + return rc; +} + +/* Terminate the wait_subproc thread. + * Called on process exit. + * Also called by spawn_guts to disassociate any subprocesses from this + * process. Subprocesses will then know to clean up after themselves and + * will not become zombies. + */ +void __stdcall +proc_terminate (void) +{ + sip_printf ("nchildren %d, nzombies %d", nchildren, nzombies); + /* Signal processing is assumed to be blocked in this routine. */ + if (hwait_subproc) + { + int rc; + proc_loop_wait = 0; // Tell wait_subproc thread to exit + wake_wait_subproc (); // Wake wait_subproc loop + + /* Wait for wait_subproc thread to exit (but not *too* long) */ + if ((rc = WaitForSingleObject (hwait_subproc, WWSP)) != WAIT_OBJECT_0) + if (rc == WAIT_TIMEOUT) + system_printf ("WFSO(hwait_subproc) timed out"); + else + system_printf ("WFSO(hwait_subproc), rc %d, %E", rc); + + HANDLE h = hwait_subproc; + hwait_subproc = NULL; + ForceCloseHandle1 (h, hwait_subproc); + + sync_proc_subproc->acquire(WPSP); + (void) proc_subproc (PROC_CLEARWAIT, 0); + + lock_pinfo_for_update (INFINITE); + /* Clean out zombie processes from the pid list. */ + int i; + for (i = 0; i < nzombies; i++) + { + pinfo *child; + if ((child = zombies[i])->hProcess) + { + ForceCloseHandle1 (child->hProcess, childhProc); + child->hProcess = NULL; + } + child->process_state = PID_NOT_IN_USE; + } + + /* Disassociate my subprocesses */ + for (i = 0; i < nchildren; i++) + { + pinfo *child; + if ((child = pchildren[i])->process_state == PID_NOT_IN_USE) + continue; // Should never happen + if (!child->hProcess) + sip_printf ("%d(%d) hProcess cleared already?", child->pid, + child->dwProcessId); + else + { + ForceCloseHandle1 (child->hProcess, childhProc); + child->hProcess = NULL; + if (!proc_exists (child)) + { + sip_printf ("%d(%d) doesn't exist", child->pid, + child->dwProcessId); + child->process_state = PID_NOT_IN_USE; /* a reaped child */ + } + else + { + sip_printf ("%d(%d) closing active child handle", child->pid, + child->dwProcessId); + child->ppid = 1; + if (child->pgid == myself->pid) + child->process_state |= PID_ORPHANED; + } + } + } + unlock_pinfo (); + nchildren = nzombies = 0; + + /* Attempt to close and release sync_proc_subproc in a + * non-raceable manner. + */ + muto *m = sync_proc_subproc; + sync_proc_subproc = NULL; + delete m; + } + sip_printf ("leaving"); +} + +/* Clear pending signal from the sigtodo array + */ +void __stdcall +sig_clear (int sig) +{ + (void) InterlockedExchange (myself->getsigtodo(sig), 0L); + return; +} + +/* Force the wait_sig thread to wake up and scan the sigtodo array. + */ +extern "C" int __stdcall +sig_dispatch_pending (int force) +{ + if (!hwait_sig) + return 0; + + int was_pending = pending_signals; +#ifdef DEBUGGING + sip_printf ("pending_signals %d", was_pending); +#endif + if (!was_pending && !force) +#ifdef DEBUGGING + sip_printf ("no need to wake anything up"); +#else + ; +#endif + else + { + wait_for_me (); + if (ReleaseSemaphore (sigcatch_nosync, 1, NULL)) +#ifdef DEBUGGING + sip_printf ("woke up wait_sig"); +#else + ; +#endif + else if (no_signals_available ()) + /*sip_printf ("I'm going away now")*/; + else + system_printf ("%E releasing sigcatch_nosync(%p)", sigcatch_nosync); + } + return was_pending; +} + +/* Message initialization. Called from dll_crt0_1 + * + * This routine starts the signal handling thread. The wait_sig_inited + * event is used to signal that the thread is ready to handle signals. + * We don't wait for this during initialization but instead detect it + * in sig_send to gain a little concurrency. + */ +void __stdcall +sigproc_init () +{ + wait_sig_inited = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL); + ProtectHandle (wait_sig_inited); + + /* local event signaled when main thread has been dispatched + to a signal handler function. */ + signal_arrived = CreateEvent(&sec_none_nih, TRUE, FALSE, NULL); + + maintid = GetCurrentThreadId ();// For use in determining if signals + // should be blocked. + + if (!(hwait_sig = makethread (wait_sig, NULL, 0, "sig"))) + { + system_printf ("cannot create wait_sig thread, %E"); + api_fatal ("terminating"); + } + + ProtectHandle (hwait_sig); + + /* sync_proc_subproc is used by proc_subproc. It serialises + * access to the children and zombie arrays. + */ + sync_proc_subproc = new_muto (FALSE, NULL); + + /* Initialize waitq structure for main thread. A waitq structure is + * allocated for each thread that executes a wait to allow multiple threads + * to perform waits. Pre-allocate a waitq structure for the main thread. + */ + waitq *w; + if ((w = (waitq *)waitq_storage.get ()) == NULL) + { + w = &waitq_main; + waitq_storage.set (w); + } + memset (w, 0, sizeof *w); // Just to be safe + + sip_printf ("process/signal handling enabled(%x)", myself->process_state); + return; +} + +/* Called on process termination to terminate signal and process threads. + */ +void __stdcall +sigproc_terminate (void) +{ + HANDLE h = hwait_sig; + hwait_sig = NULL; + + if (GetCurrentThreadId () == sigtid) + { + ForceCloseHandle (sigcomplete_main); + for (int i = 0; i < 20; i++) + (void) ReleaseSemaphore (sigcomplete_nonmain, 1, NULL); + ForceCloseHandle (sigcomplete_nonmain); + ForceCloseHandle (sigcatch_main); + ForceCloseHandle (sigcatch_nonmain); + ForceCloseHandle (sigcatch_nosync); + } + proc_terminate (); // Terminate process handling thread + + if (!sig_loop_wait) + sip_printf ("sigproc_terminate: sigproc handling not active"); + else + { + sigproc_printf ("entering"); + sig_loop_wait = 0; // Tell wait_sig to exit when it is + // finished with anything it is doing + sig_dispatch_pending (TRUE); // wake up and die + + /* If !hwait_sig, then the process probably hasn't even finished + * its initialization phase. + */ + if (hwait_sig) + { + if (GetCurrentThreadId () != sigtid) + WaitForSingleObject (h, 10000); + ForceCloseHandle1 (h, hwait_sig); + + /* Exiting thread. Cleanup. Don't set to inactive if a child has been + execed with the same pid. */ + if (!myself->dwProcessId || myself->dwProcessId == GetCurrentProcessId ()) + myself->process_state &= ~PID_ACTIVE; + else + sip_printf ("Did not clear PID_ACTIVE since %d != %d", + myself->dwProcessId, GetCurrentProcessId ()); + + /* In case of a sigsuspend */ + SetEvent (signal_arrived); + + if (GetCurrentThreadId () != sigtid) + { + ForceCloseHandle (sigcomplete_main); + ForceCloseHandle (sigcomplete_nonmain); + ForceCloseHandle (sigcatch_main); + ForceCloseHandle (sigcatch_nonmain); + ForceCloseHandle (sigcatch_nosync); + } + } + sip_printf ("done"); + } + + /* Set this so that subsequent tests will succeed. */ + if (!myself->dwProcessId) + myself->dwProcessId = GetCurrentProcessId (); + + return; +} + +/* Send a signal to another process by raising its signal semaphore. + * If pinfo *p == NULL, send to the current process. + * If sending to this process, wait for notification that a signal has + * completed before returning. + */ +int __stdcall +sig_send (pinfo *p, int sig) +{ + int rc = 1; + DWORD tid = GetCurrentThreadId (); + BOOL its_me; + HANDLE thiscatch = NULL; + HANDLE thiscomplete = NULL; + BOOL wait_for_completion; + + if (p == myself_nowait_nonmain) + p = (tid == maintid) ? myself : myself_nowait; + if (!(its_me = (p == NULL || p == myself || p == myself_nowait))) + wait_for_completion = FALSE; + else + { + if (no_signals_available ()) + goto out; // Either exiting or not yet initializing + wait_for_me (); + wait_for_completion = p != myself_nowait; + p = myself; + } + + /* It is possible that the process is not yet ready to receive messages + * or that it has exited. Detect this. + */ + if (!proc_can_be_signalled (p)) /* Is the process accepting messages? */ + { + sip_printf ("invalid pid %d(%x), signal %d", + p->pid, p->process_state, sig); + set_errno (ESRCH); + goto out; + } + + sip_printf ("pid %d, signal %d, its_me %d", p->pid, sig, its_me); + + if (its_me) + { + if (!wait_for_completion) + thiscatch = sigcatch_nosync; + else if (tid != maintid) + { + thiscatch = sigcatch_nonmain; + thiscomplete = sigcomplete_nonmain; + } + else + { + thiscatch = sigcatch_main; + thiscomplete = sigcomplete_main; + ResetEvent (thiscomplete); + } + } + else if (!(thiscatch = getsem (p, "sigcatch", 0, 0))) + goto out; // Couldn't get the semaphore. getsem issued + // an error, if appropriate. + +#if WHEN_MULTI_THREAD_SIGNALS_WORK + signal_dispatch *sd; + sd = signal_dispatch_storage.get (); + if (sd == NULL) + sd = signal_dispatch_storage.create (); +#endif + /* Increment the sigtodo array to signify which signal to assert. + */ + (void) InterlockedIncrement (p->getsigtodo(sig)); + + /* Notify the process that a signal has arrived. + */ + SetLastError (0); + if (!ReleaseSemaphore (thiscatch, 1, NULL) && (int) GetLastError () > 0) + { + /* Couldn't signal the semaphore. This probably means that the + * process is exiting. + */ + if (!its_me) + ForceCloseHandle (thiscatch); + else + { + if (no_signals_available ()) + sip_printf ("I'm going away now"); + else if ((int) GetLastError () == -1) + rc = WaitForSingleObject (thiscomplete, 500); + else + system_printf ("error sending signal %d to pid %d, semaphore %p, %E", + sig, p->pid, thiscatch); + } + goto out; + } + + /* No need to wait for signal completion unless this was a signal to + * this process. + * + * If it was a signal to this process, wait for a dispatched signal. + * Otherwise just wait for the wait_sig to signal that it has finished + * processing the signal. + */ + if (!wait_for_completion) + { + rc = WAIT_OBJECT_0; + sip_printf ("Not waiting for sigcomplete. its_me %d sig %d", its_me, sig); + if (!its_me) + ForceCloseHandle (thiscatch); + } + else + { + sip_printf ("Waiting for thiscomplete %p", thiscomplete); + + SetLastError (0); + rc = WaitForSingleObject (thiscomplete, WSSC); + /* Check for strangeness due to this thread being redirected by the + signal handler. Sometimes a WAIT_TIMEOUT will occur when the + thread hasn't really timed out. So, check again. + FIXME: This isn't foolproof. */ + if (rc != WAIT_OBJECT_0 && + WaitForSingleObject (thiscomplete, 0) == WAIT_OBJECT_0) + rc = WAIT_OBJECT_0; + } + + if (rc == WAIT_OBJECT_0) + rc = 0; // Successful exit + else + { + /* It's an error unless sig_loop_wait == 0 (the process is exiting). */ + if (!no_signals_available ()) + system_printf ("wait for sig_complete event failed, sig %d, rc %d, %E", + sig, rc); + set_errno (ENOSYS); + rc = -1; + } + +out: + sip_printf ("returning %d from sending signal %d", rc, sig); + return rc; +} + +/* Set pending signal from the sigtodo array + */ +void __stdcall +sig_set_pending (int sig) +{ + (void) InterlockedIncrement (myself->getsigtodo(sig)); + return; +} + +/* Initialize the wait_subproc thread. + * Called from fork() or spawn() to initialize the handling of subprocesses. + */ +void __stdcall +subproc_init (void) +{ + if (hwait_subproc) + return; + + /* A "wakeup" handle which can be toggled to make wait_subproc reexamine + * the hchildren array. + */ + events[0] = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL); + if (!(hwait_subproc = makethread (wait_subproc, NULL, 0, "+proc"))) + system_printf ("cannot create wait_subproc thread, %E"); + ProtectHandle (events[0]); + ProtectHandle (hwait_subproc); + sip_printf ("started wait_subproc thread %p", hwait_subproc); +} + +/* Initialize some of the memory block passed to child processes + by fork/spawn/exec. */ + +void __stdcall +init_child_info (DWORD chtype, child_info *ch, int pid, HANDLE subproc_ready) +{ + subproc_init (); + memset (ch, 0, sizeof *ch); + ch->cb = sizeof *ch; + ch->type = chtype; + ch->cygpid = pid; + ch->shared_h = cygwin_shared_h; + ch->console_h = console_shared_h; + ch->subproc_ready = subproc_ready; + if (chtype != PROC_EXEC || !parent_alive) + ch->parent_alive = hwait_subproc; + else if (parent_alive) + DuplicateHandle (hMainProc, parent_alive, hMainProc, &ch->parent_alive, + 0, 1, DUPLICATE_SAME_ACCESS); +} + +/* Check the state of all of our children to see if any are stopped or + * terminated. + */ +static int __stdcall +checkstate (waitq *w) +{ + int i, x, potential_match = 0; + pinfo *child; + + sip_printf ("nchildren %d, nzombies %d", nchildren, nzombies); + + /* Check already dead processes first to see if they match the criteria + * given in w->next. + */ + for (i = 0; i < nzombies; i++) + if ((x = stopped_or_terminated (w, child = zombies[i])) < 0) + potential_match = -1; + else if (x > 0) + { + remove_zombie (i); + potential_match = 1; + goto out; + } + + sip_printf ("checking alive children"); + + /* No dead terminated children matched. Check for stopped children. */ + for (i = 0; i < nchildren; i++) + if ((x = stopped_or_terminated (w, pchildren[i])) < 0) + potential_match = -1; + else if (x > 0) + { + potential_match = 1; + break; + } + +out: + sip_printf ("returning %d", potential_match); + return potential_match; +} + +/* Get or create a process specific semaphore used in message passing. + */ +static HANDLE __stdcall +getsem (pinfo *p, const char *str, int init, int max) +{ + HANDLE h; + + if (p != NULL) + { + if (!proc_can_be_signalled (p)) + { + set_errno (ESRCH); + return NULL; + } + int wait = 10000; + sip_printf ("pid %d, ppid %d, wait %d, initializing %x", p->pid, p->ppid, wait, + ISSTATE (p, PID_INITIALIZING)); + for (int i = 0; ISSTATE (p, PID_INITIALIZING) && i < wait; i++) + Sleep (1); + } + + SetLastError (0); + if (p == NULL) + { + char sa_buf[1024]; + + DWORD winpid = GetCurrentProcessId (); + h = CreateSemaphore (allow_ntsec ? sec_user (sa_buf) : &sec_none_nih, + init, max, str = shared_name (str, winpid)); + p = myself; + } + else + { + h = OpenSemaphore (SEMAPHORE_ALL_ACCESS, FALSE, + str = shared_name (str, p->dwProcessId)); + + if (h == NULL) + { + if (GetLastError () == ERROR_FILE_NOT_FOUND && !proc_exists (p)) + set_errno (ESRCH); + else + set_errno (EPERM); + return NULL; + } + } + + if (!h) + { + system_printf ("can't %s %s, %E", p ? "open" : "create", str); + set_errno (ESRCH); + } + return h; +} + +/* Get the sync_proc_subproc muto to control access to + * children, zombie arrays. + * Attempt to handle case where process is exiting as we try to grab + * the mutex. + */ +static BOOL __inline +get_proc_lock (DWORD what, DWORD val) +{ + Static int lastwhat = -1; + if (!sync_proc_subproc) + return FALSE; + if (sync_proc_subproc->acquire (WPSP)) + { + lastwhat = what; + return TRUE; + } + if (!sync_proc_subproc) + return FALSE; + system_printf ("Couldn't aquire sync_proc_subproc for(%d,%d), %E, last %d", + what, val, lastwhat); + return TRUE; +} + +/* Remove a child from pchildren/hchildren by swapping it with the + * last child in the list. + */ +static void __stdcall +remove_child (int ci) +{ + sip_printf ("removing [%d], pid %d, handle %p, nchildren %d", + ci, pchildren[ci]->pid, hchildren[ci], nchildren); + if (ci < --nchildren) + { + pchildren[ci] = pchildren[nchildren]; + hchildren[ci] = hchildren[nchildren]; + } + + return; +} + +/* Remove a zombie from zombies by swapping it with the last child in the list. + */ +static void __stdcall +remove_zombie (int ci) +{ + sip_printf ("removing %d, pid %d, nzombies %d", ci, zombies[ci]->pid, + nzombies); + if (ci < --nzombies) + zombies[ci] = zombies[nzombies]; + + return; +} + +/* Check status of child process vs. waitq member. + * + * parent_w is the pointer to the parent of the waitq member in question. + * child is the subprocess being considered. + * + * Returns + * 1 if stopped or terminated child matches parent_w->next criteria + * -1 if a non-stopped/terminated child matches parent_w->next criteria + * 0 if child does not match parent_w->next criteria + */ +static int __stdcall +stopped_or_terminated (waitq *parent_w, pinfo *child) +{ + int potential_match; + waitq *w = parent_w->next; + + sip_printf ("considering pid %d", child->pid); + if (w->pid == -1) + potential_match = 1; + else if (w->pid == 0) + potential_match = child->pgid == myself->pgid; + else if (w->pid < 0) + potential_match = child->pgid == -w->pid; + else + potential_match = (w->pid == child->pid); + + if (!potential_match) + return 0; + + BOOL terminated; + + if ((terminated = child->process_state == PID_ZOMBIE) || + (w->options & WUNTRACED) && child->stopsig) + { + parent_w->next = w->next; /* successful wait. remove from wait queue */ + w->pid = child->pid; + + if (!terminated) + { + sip_printf ("stopped child"); + w->status = (child->stopsig << 8) | 0x7f; + child->stopsig = 0; + } + else + { + DWORD status; + if (!GetExitCodeProcess (child->hProcess, &status)) + status = 0xffff; + if (status & EXIT_SIGNAL) + w->status = (status >> 8) & 0xff; /* exited due to signal */ + else + w->status = (status & 0xff) << 8; /* exited via "exit ()" */ + + add_rusage (&myself->rusage_children, &child->rusage_children); + add_rusage (&myself->rusage_children, &child->rusage_self); + + if (w->rusage) + { + add_rusage ((struct rusage *) w->rusage, &child->rusage_children); + add_rusage ((struct rusage *) w->rusage, &child->rusage_self); + } + ForceCloseHandle1 (child->hProcess, childhProc); + child->hProcess = NULL; + child->process_state = PID_NOT_IN_USE; /* a reaped child */ + } + + if (!SetEvent (w->ev)) /* wake up wait4 () immediately */ + system_printf ("couldn't wake up wait event %p, %E", w->ev); + return 1; + } + + return -potential_match; +} + +/* Process signals by waiting for a semaphore to become signaled. + * Then scan an in-memory array representing queued signals. + * Executes in a separate thread. + * + * Signals sent from this process are sent a completion signal so + * that returns from kill/raise do not occur until the signal has + * has been handled, as per POSIX. + */ +static DWORD WINAPI +wait_sig (VOID *arg) +{ + /* Initialization */ + (void) SetThreadPriority (hwait_sig, WAIT_SIG_PRIORITY); + + /* sigcatch_nosync - semaphore incremented by sig_dispatch_pending and + * by foreign processes to force an examination of + * the sigtodo array. + * sigcatch_main - ditto for local main thread. + * sigcatch_nonmain - ditto for local non-main threads. + * + * sigcomplete_main - event used to signal main thread on signal + * completion + * sigcomplete_nonmain - semaphore signaled for non-main thread on signal + * completion + */ + sigcatch_nosync = getsem (NULL, "sigcatch", 0, MAXLONG); + sigcatch_nonmain = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL); + sigcatch_main = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL); + sigcomplete_nonmain = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL); + sigcomplete_main = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL); + sigproc_printf ("sigcatch_nonmain %p", sigcatch_nonmain); + + /* Setting dwProcessId flags that this process is now capable of receiving + * signals. Prior to this, dwProcessId was set to the windows pid of + * of the original windows process which spawned us unless this was a + * "toplevel" process. + */ + myself->dwProcessId = GetCurrentProcessId (); + myself->process_state |= PID_ACTIVE; + myself->process_state &= ~PID_INITIALIZING; + + ProtectHandle (sigcatch_nosync); + ProtectHandle (sigcatch_nonmain); + ProtectHandle (sigcatch_main); + ProtectHandle (sigcomplete_nonmain); + ProtectHandle (sigcomplete_main); + + /* If we've been execed, then there is still a stub left in the previous + * windows process waiting to see if it's started a cygwin process or not. + * Signalling subproc_ready indicates that we are a cygwin process. + */ + if (child_proc_info && child_proc_info->type == PROC_EXEC) + { + debug_printf ("subproc_ready %p", child_proc_info->subproc_ready); + if (!SetEvent (child_proc_info->subproc_ready)) + system_printf ("SetEvent (subproc_ready) failed, %E"); + ForceCloseHandle (child_proc_info->subproc_ready); + } + + SetEvent (wait_sig_inited); + sigtid = GetCurrentThreadId (); + + /* If we got something like a SIGINT while we were initializing, the + signal thread should be waiting for this event. This signals the + thread that it's ok to send the signal since the wait_sig thread + is now active. */ + extern HANDLE console_handler_thread_waiter; + SetEvent (console_handler_thread_waiter); + + HANDLE catchem[] = {sigcatch_main, sigcatch_nonmain, sigcatch_nosync}; + sigproc_printf ("Ready. dwProcessid %d", myself->dwProcessId); + for (;;) + { + DWORD rc = WaitForMultipleObjects (3, catchem, FALSE, sig_loop_wait); + + /* sigproc_terminate sets sig_loop_wait to zero to indicate that + * this thread should terminate. + */ + if (rc == WAIT_TIMEOUT) + if (!sig_loop_wait) + break; // Exiting + else + continue; + + if (rc == WAIT_FAILED) + { + if (sig_loop_wait != 0) + system_printf ("WFMO failed, %E"); + break; + } + + rc -= WAIT_OBJECT_0; + int dispatched = FALSE; + sip_printf ("awake"); + /* A sigcatch semaphore has been signaled. Scan the sigtodo + * array looking for any unprocessed signals. + */ + pending_signals = 0; + for (int sig = -__SIGOFFSET; sig < NSIG; sig++) + { +#ifdef NOSIGQUEUE + if (InterlockedExchange (myself->getsigtodo(sig), 0L) > 0) +#else + while (InterlockedDecrement (myself->getsigtodo(sig)) >= 0) +#endif + { + if (sig > 0 && sig != SIGCONT && sig != SIGKILL && sig != SIGSTOP && + (sigismember (& myself->getsigmask (), sig) || + myself->process_state & PID_STOPPED)) + { + sip_printf ("sig %d blocked", sig); + break; + } + + /* Found a signal to process */ + sip_printf ("processing signal %d", sig); + switch (sig) + { + case __SIGFLUSH: + /* just forcing the loop */ + break; + + /* Internal signal to force a flush of strace data to disk. */ + case __SIGSTRACE: + // proc_strace (); // Dump cached strace_printf stuff. + break; + + /* Signalled from a child process that it has stopped */ + case __SIGCHILDSTOPPED: + sip_printf ("Received child stopped notification"); + dispatched |= sig_handle (SIGCHLD); + if (proc_subproc (PROC_CHILDSTOPPED, 0)) + dispatched |= 1; + break; + + /* A normal UNIX signal */ + default: + sip_printf ("Got signal %d", sig); + dispatched |= sig_handle (sig); + goto nextsig; + } + } +#ifndef NOSIGQUEUE + /* Decremented too far. */ + if (InterlockedIncrement (myself->getsigtodo(sig)) > 0) + pending_signals = 1; +#endif + nextsig: + continue; + } + + /* Signal completion of signal handling depending on which semaphore + * woke up the WaitForMultipleObjects above. + */ + switch (rc) + { + case 0: + SetEvent (sigcomplete_main); + break; + case 1: + ReleaseSemaphore (sigcomplete_nonmain, 1, NULL); + break; + default: + /* Signal from another process. No need to synchronize. */ + break; + } + + if (dispatched < 0) + pending_signals = 1; + sip_printf ("looping"); + } + + sip_printf ("done"); + return 0; +} + +/* Wait for subprocesses to terminate. Executes in a separate thread. */ +static DWORD WINAPI +wait_subproc (VOID *arg) +{ + sip_printf ("starting"); + int errloop = 0; + + for (;;) + { + DWORD rc = WaitForMultipleObjects (nchildren + 1, events, FALSE, + proc_loop_wait); + if (rc == WAIT_TIMEOUT) + if (!proc_loop_wait) + break; // Exiting + else + continue; + + if (rc == WAIT_FAILED) + { + if (!proc_loop_wait) + break; + + /* It's ok to get an ERROR_INVALID_HANDLE since another thread may have + closed a handle in the children[] array. So, we try looping a couple + of times to stabilize. FIXME - this is not foolproof. Probably, this + thread should be responsible for closing the children. */ + if (++errloop < 10 && GetLastError () == ERROR_INVALID_HANDLE) + continue; + + system_printf ("wait failed. nchildren %d, wait %d, %E", + nchildren, proc_loop_wait); + + for (int i = 0; i < nchildren + 1; i++) + if ((rc = WaitForSingleObject (events[i], 0)) == WAIT_OBJECT_0 || + rc == WAIT_TIMEOUT) + continue; + else + system_printf ("event[%d] %p, %E", i, events[0]); + break; + } + + errloop = 0; + rc -= WAIT_OBJECT_0; + if (rc-- != 0) + (void)proc_subproc (PROC_CHILDTERMINATED, rc); + sip_printf ("looping"); + } + + ForceCloseHandle (events[0]); + events[0] = NULL; + sip_printf ("done"); + return 0; +} diff --git a/winsup/cygwin/sigproc.h b/winsup/cygwin/sigproc.h new file mode 100644 index 000000000..b1b4eafc0 --- /dev/null +++ b/winsup/cygwin/sigproc.h @@ -0,0 +1,66 @@ +/* sigproc.h + + Copyright 1997, 1998, 2000 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#define EXIT_SIGNAL 0x010000 +#define EXIT_REPARENTING 0x020000 +#define EXIT_NOCLOSEALL 0x040000 + +enum procstuff +{ + PROC_ADDCHILD = 1, // add a new subprocess to list + PROC_CHILDSTOPPED = 2, // a child stopped + PROC_CHILDTERMINATED = 3, // a child died + PROC_CLEARWAIT = 4, // clear all waits - signal arrived + PROC_WAIT = 5 // setup for wait() for subproc +}; + +typedef struct struct_waitq +{ + int pid; + int options; + int status; + HANDLE ev; + void *rusage; /* pointer to potential rusage */ + struct struct_waitq *next; + HANDLE thread_ev; +} waitq; + +extern HANDLE signal_arrived; + +BOOL __stdcall my_parent_is_alive (); +extern "C" int __stdcall sig_dispatch_pending (int force = FALSE) __asm__ ("sig_dispatch_pending"); +extern "C" void __stdcall set_process_mask (sigset_t newmask); +int __stdcall sig_handle (int); +void __stdcall sig_clear (int); +void __stdcall sig_set_pending (int); +int __stdcall handle_sigsuspend (sigset_t); + +void __stdcall proc_terminate (); +void __stdcall sigproc_init (); +void __stdcall subproc_init (); +void __stdcall sigproc_terminate (); +BOOL __stdcall proc_exists (pinfo *); +int __stdcall proc_subproc (DWORD, DWORD); +int __stdcall sig_send (pinfo *, int); + +extern char myself_nowait_dummy[]; +extern char myself_nowait_nonmain_dummy[]; +extern DWORD maintid; +extern HANDLE hExeced; // Process handle of new window + // process created by spawn_guts() + +#define WAIT_SIG_EXITING (WAIT_OBJECT_0 + 1) + +#define allow_sig_dispatch(n) __allow_sig_dispatch (__FILE__, __LINE__, (n)) + +#define myself_nowait ((pinfo *)myself_nowait_dummy) +#define myself_nowait_nonmain ((pinfo *)myself_nowait_nonmain_dummy) +#define proc_register(child) \ + proc_subproc (PROC_ADDCHILD, (DWORD) (child)) diff --git a/winsup/cygwin/smallprint.c b/winsup/cygwin/smallprint.c new file mode 100644 index 000000000..3bfbda2da --- /dev/null +++ b/winsup/cygwin/smallprint.c @@ -0,0 +1,229 @@ +/* smallprint.c: small print routines for WIN32 + + Copyright 1996, 1998, 2000 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include +#include + +int __small_sprintf (char *dst, const char *fmt,...); +int __small_vsprintf (char *dst, const char *fmt, va_list ap); + +static char * +rn (char *dst, int base, int dosign, int val, int len, int pad) +{ + /* longest number is 4294967295, 10 digits */ + unsigned uval; + char res[10]; + static const char str[16] = "0123456789ABCDEF"; + int l = 0; + + if (dosign && val < 0) + { + *dst++ = '-'; + uval = -val; + } + else if (dosign > 0 && val > 0) + { + *dst++ = '+'; + uval = val; + } + else + { + uval = val; + } + + do + { + res[l++] = str[uval % base]; + uval /= base; + } + while (uval); + + while (len -- > l) + *dst++ = pad; + + while (l > 0) + { + *dst++ = res[--l]; + } + + return dst; +} + +int +__small_vsprintf (char *dst, const char *fmt, va_list ap) +{ + char tmp[MAX_PATH + 1]; + char *orig = dst; + const char *s; + + while (*fmt) + { + int i, n = 0x7fff; + if (*fmt != '%') + *dst++ = *fmt++; + else + { + int len = 0; + char pad = ' '; + int addsign = -1; + + switch (*++fmt) + { + case '+': + addsign = 1; + fmt++; + break; + case '%': + *dst++ = *fmt++; + continue; + } + + for (;;) + { + char c = *fmt++; + switch (c) + { + case '0': + if (len == 0) + { + pad = '0'; + continue; + } + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + len = len * 10 + (c - '0'); + continue; + case 'l': + continue; + case 'c': + { + int c = va_arg (ap,int); + if (c > ' ' && c <= 127) + *dst++ = c; + else + { + *dst++ = '0'; + *dst++ = 'x'; + dst = rn (dst, 16, 0, c, len, pad); + } + } + break; + case 'E': + strcpy (dst, "Win32 error "); + dst = rn (dst + sizeof ("Win32 error"), 10, 0, GetLastError (), len, pad); + break; + case 'd': + dst = rn (dst, 10, addsign, va_arg (ap, int), len, pad); + break; + case 'u': + dst = rn (dst, 10, 0, va_arg (ap, int), len, pad); + break; + case 'p': + *dst++ = '0'; + *dst++ = 'x'; + /* fall through */ + case 'x': + dst = rn (dst, 16, 0, va_arg (ap, int), len, pad); + break; + case 'P': + if (!GetModuleFileName (NULL, tmp, MAX_PATH)) + s = "cygwin program"; + else + s = tmp; + goto fillin; + case '.': + n = strtol (fmt, (char **)&fmt, 10); + if (*fmt++ != 's') + goto endfor; + case 's': + s = va_arg (ap, char *); + if (s == NULL) + s = "(null)"; + fillin: + for (i = 0; *s && i < n; i++) + *dst++ = *s++; + break; + case 'F': + { + const char *p, *pe; + s = va_arg (ap, char *); + for (p = s; (pe = strchr (p, '(')); p = pe + 1) + if (isalnum ((int)pe[-1]) || pe[-1] == '_') + break; + else if (isspace((int)pe[-1])) + { + pe--; + break; + } + if (!pe) + pe = strchr (s, '\0'); + for (p = pe; p > s; p--) + if (p != pe && *p == ' ') + { + p++; + break; + } + if (*p == '*') + p++; + while (p < pe) + *dst++ = *p++; + break; + } + default: + *dst++ = '?'; + *dst++ = fmt[-1]; + } + endfor: + break; + } + } + } + *dst = 0; + return dst - orig; +} + +int +__small_sprintf (char *dst, const char *fmt,...) +{ + int r; + va_list ap; + va_start (ap, fmt); + r = __small_vsprintf (dst, fmt, ap); + va_end (ap); + return r; +} + +void +small_printf (const char *fmt,...) +{ + char buf[2000]; + va_list ap; + DWORD done; + int count; + +#if 0 /* Turn on to force console errors */ + extern SECURITY_ATTRIBUTES sec_none; + HANDLE h = CreateFileA ("CONOUT$", GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_WRITE | FILE_SHARE_WRITE, &sec_none, + OPEN_EXISTING, 0, 0); + if (h) + SetStdHandle (STD_ERROR_HANDLE, h); +#endif + + va_start (ap, fmt); + count = __small_vsprintf (buf, fmt, ap); + va_end (ap); + + WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, count, &done, 0); + FlushFileBuffers (GetStdHandle (STD_ERROR_HANDLE)); +} diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc new file mode 100644 index 000000000..510031911 --- /dev/null +++ b/winsup/cygwin/spawn.cc @@ -0,0 +1,980 @@ +/* spawn.cc + + Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include +#include +#include +#include +#include "winsup.h" +#include +#include "paths.h" + +extern BOOL allow_ntsec; + +#define LINE_BUF_CHUNK (MAX_PATH * 2) + +suffix_info std_suffixes[] = +{ + suffix_info (".exe", 1), suffix_info ("", 1), + suffix_info (".com"), suffix_info (".cmd"), + suffix_info (".bat"), suffix_info (".dll"), + suffix_info (NULL) +}; + +/* Add .exe to PROG if not already present and see if that exists. + If not, return PROG (converted from posix to win32 rules if necessary). + The result is always BUF. + + Returns (possibly NULL) suffix */ + +static const char * +perhaps_suffix (const char *prog, char *buf) +{ + char *ext; + + debug_printf ("prog '%s'", prog); + path_conv temp (prog, SYMLINK_FOLLOW, 1, std_suffixes); + strcpy (buf, temp.get_win32 ()); + + if (temp.file_attributes () & FILE_ATTRIBUTE_DIRECTORY) + ext = NULL; + else if (temp.known_suffix) + ext = buf + (temp.known_suffix - temp.get_win32 ()); + else + ext = strchr (buf, '\0'); + + debug_printf ("buf %s, suffix found '%s'", buf, ext); + return ext; +} + +/* Find an executable name, possibly by appending known executable + suffixes to it. The win32-translated name is placed in 'buf'. + Any found suffix is returned in known_suffix. + + If the file is not found and !null_if_not_found then the win32 version + of name is placed in buf and returned. Otherwise the contents of buf + is undefined and NULL is returned. */ + +const char * __stdcall +find_exec (const char *name, char *buf, const char *mywinenv, + int null_if_notfound, const char **known_suffix) +{ + const char *suffix = ""; + debug_printf ("find_exec (%s)", name); + char *retval = buf; + + /* Check to see if file can be opened as is first. + Win32 systems always check . first, but PATH may not be set up to + do this. */ + if ((suffix = perhaps_suffix (name, buf)) != NULL) + goto out; + + win_env *winpath; + const char *path; + char tmp[MAX_PATH]; + + /* Return the error condition if this is an absolute path or if there + is no PATH to search. */ + if (strchr (name, '/') || strchr (name, '\\') || + isalpha (name[0]) && name[1] == ':' || + !(winpath = getwinenv (mywinenv)) || + !(path = winpath->get_native ()) || + *path == '\0') + goto errout; + + debug_printf ("%s%s", mywinenv, path); + + /* Iterate over the specified path, looking for the file with and + without executable extensions. */ + do + { + char *eotmp = strccpy (tmp, &path, ';'); + /* An empty path or '.' means the current directory, but we've + already tried that. */ + if (tmp[0] == '\0' || (tmp[0] == '.' && tmp[1] == '\0')) + continue; + + *eotmp++ = '\\'; + strcpy (eotmp, name); + + debug_printf ("trying %s", tmp); + + if ((suffix = perhaps_suffix (tmp, buf)) != NULL) + goto out; + } + while (*path && *++path); + +errout: + /* Couldn't find anything in the given path. + Take the appropriate action based on null_if_not_found. */ + if (null_if_notfound) + retval = NULL; + else + strcpy (buf, path_conv (name).get_win32 ()); + +out: + debug_printf ("%s = find_exec (%s)", buf, name); + if (known_suffix) + *known_suffix = suffix ?: strchr (buf, '\0'); + return retval; +} + +/* Utility for spawn_guts. */ + +static HANDLE +handle (int n, int direction) +{ + fhandler_base *fh = dtable[n]; + + if (!fh) + return INVALID_HANDLE_VALUE; + if (fh->get_close_on_exec ()) + return INVALID_HANDLE_VALUE; + if (direction == 0) + return fh->get_handle (); + return fh->get_output_handle (); +} + +/* Cover function for CreateProcess. + + This function is used by both the routines that search $PATH and those + that do not. This should work out ok as according to the documentation, + CreateProcess only searches $PATH if PROG has no directory elements. + + Spawning doesn't fit well with Posix's fork/exec (one can argue the merits + of either but that's beside the point). If we're exec'ing we want to + record the child pid for fork. If we're spawn'ing we don't want to do + this. It is up to the caller to handle both cases. + + The result is the process id. The handle of the created process is + stored in H. +*/ + +HANDLE NO_COPY hExeced = NULL; +DWORD NO_COPY exec_exit = 0; + +int +iscmd (const char *argv0, const char *what) +{ + int n; + n = strlen (argv0) - strlen (what); + if (n >= 2 && argv0[1] != ':') + return 0; + return n >= 0 && strcasecmp (argv0 + n, what) == 0 && + (n == 0 || isdirsep (argv0[n - 1])); +} + +class linebuf +{ +public: + size_t ix; + char *buf; + size_t alloced; + linebuf () : ix (0), buf (NULL), alloced (0) + { + } + ~linebuf () {/* if (buf) free (buf);*/} + void add (const char *what, int len); + void add (const char *what) {add (what, strlen (what));} + void prepend (const char *what, int len); +}; + +void +linebuf::add (const char *what, int len) +{ + size_t newix; + if ((newix = ix + len) >= alloced || !buf) + { + alloced += LINE_BUF_CHUNK + newix; + buf = (char *) realloc (buf, alloced + 1); + } + memcpy (buf + ix, what, len); + ix = newix; + buf[ix] = '\0'; +} + +void +linebuf::prepend (const char *what, int len) +{ + int buflen; + size_t newix; + if ((newix = ix + len) >= alloced) + { + alloced += LINE_BUF_CHUNK + newix; + buf = (char *) realloc (buf, alloced + 1); + buf[ix] = '\0'; + } + if ((buflen = strlen (buf))) + memmove (buf + len, buf, buflen + 1); + else + buf[newix] = '\0'; + memcpy (buf, what, len); + ix = newix; +} + +int __stdcall +spawn_guts (HANDLE hToken, const char * prog_arg, const char *const *argv, + const char *const envp[], pinfo *child, int mode) +{ + int i; + BOOL rc; + int argc; + + hExeced = NULL; + + MALLOC_CHECK; + + if (prog_arg == NULL) + { + syscall_printf ("prog_arg is NULL"); + set_errno(EINVAL); + return -1; + } + + syscall_printf ("spawn_guts (%.132s)", prog_arg); + + if (argv == NULL) + { + syscall_printf ("argv is NULL"); + set_errno(EINVAL); + return (-1); + } + + /* CreateProcess takes one long string that is the command line (sigh). + We need to quote any argument that has whitespace or embedded "'s. */ + + for (argc = 0; argv[argc]; argc++) + /* nothing */; + + char *real_path; + char real_path_buf[MAX_PATH]; + + linebuf one_line; + + if (argc == 3 && argv[1][0] == '/' && argv[1][1] == 'c' && + (iscmd (argv[0], "command.com") || iscmd (argv[0], "cmd.exe"))) + { + one_line.add (argv[0]); + one_line.add (" "); + one_line.add (argv[1]); + one_line.add (" "); + real_path = NULL; + one_line.add (argv[2]); + strcpy (real_path_buf, argv[0]); + goto skip_arg_parsing; + } + + MALLOC_CHECK; + + real_path = real_path_buf; + + const char *saved_prog_arg; + const char *newargv0, **firstarg; + const char *ext; + + if ((ext = perhaps_suffix (prog_arg, real_path)) == NULL) + { + set_errno (ENOENT); + return -1; + } + + MALLOC_CHECK; + saved_prog_arg = prog_arg; + newargv0 = argv[0]; + firstarg = &newargv0; + + /* If the file name ends in either .exe, .com, .bat, or .cmd we assume + that it is NOT a script file */ + while (*ext == '\0') + { + HANDLE hnd = CreateFileA (real_path, + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + &sec_none_nih, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + 0); + if (hnd == INVALID_HANDLE_VALUE) + { + __seterrno (); + return -1; + } + + DWORD done; + + char buf[2 * MAX_PATH + 1]; + buf[0] = buf[1] = buf[2] = buf[sizeof(buf) - 1] = '\0'; + if (! ReadFile (hnd, buf, sizeof (buf) - 1, &done, 0)) + { + CloseHandle (hnd); + __seterrno (); + return -1; + } + + CloseHandle (hnd); + + if (buf[0] == 'M' && buf[1] == 'Z') + break; + + debug_printf ("%s is a script", prog_arg); + + char *ptr, *pgm, *arg1; + + if (buf[0] != '#' || buf[1] != '!') + { + strcpy (buf, "sh"); /* shell script without magic */ + pgm = buf; + ptr = buf + 2; + arg1 = NULL; + } + else + { + pgm = buf + 2; + pgm += strspn (pgm, " \t"); + for (ptr = pgm, arg1 = NULL; + *ptr && *ptr != '\r' && *ptr != '\n'; + ptr++) + if (!arg1 && (*ptr == ' ' || *ptr == '\t')) + { + /* Null terminate the initial command and step over + any additional white space. If we've hit the + end of the line, exit the loop. Otherwise, position + we've found the first argument. Position the current + pointer on the last known white space. */ + *ptr = '\0'; + char *newptr = ptr + 1; + newptr += strspn (newptr, " \t"); + if (!*newptr || *newptr == '\r' || *newptr == '\n') + break; + arg1 = newptr; + ptr = newptr - 1; + } + + + *ptr = '\0'; + } + + char buf2[MAX_PATH + 1]; + + /* pointers: + * pgm interpreter name + * arg1 optional string + * ptr end of string + */ + + if (!arg1) + one_line.prepend (" ", 1); + else + { + one_line.prepend ("\" ", 2); + one_line.prepend (arg1, strlen (arg1)); + one_line.prepend (" \"", 2); + } + + find_exec (pgm, real_path, "PATH=", 0, &ext); + cygwin_conv_to_posix_path (real_path, buf2); + one_line.prepend (buf2, strlen (buf2)); + + /* If script had absolute path, add it to script name now! + * This is necessary if script has been found via PATH. + * For example, /usr/local/bin/tkman started as "tkman": + * #!/usr/local/bin/wish -f + * ... + * We should run /usr/local/bin/wish -f /usr/local/bin/tkman, + * but not /usr/local/bin/wish -f tkman! + * We don't modify anything, if script has qulified path. + */ + if (firstarg) + *firstarg = saved_prog_arg; + + debug_printf ("prog_arg '%s', copy '%s'", prog_arg, one_line.buf); + firstarg = NULL; + } + + for (; *argv; argv++) + { + char *p = NULL; + const char *a = newargv0 ?: *argv; + + MALLOC_CHECK; + + newargv0 = NULL; + int len = strlen (a); + if (len != 0 && !(p = strpbrk (a, " \t\n\r\""))) + one_line.add (a, len); + else + { + one_line.add ("\"", 1); + for (; p; a = p, p = strchr (p, '"')) + { + one_line.add (a, ++p - a); + if (p[-1] == '"') + one_line.add ("\"", 1); + } + if (*a) + one_line.add (a); + one_line.add ("\"", 1); + } + MALLOC_CHECK; + one_line.add (" ", 1); + MALLOC_CHECK; + } + + MALLOC_CHECK; + if (one_line.ix) + one_line.buf[one_line.ix - 1] = '\0'; + else + one_line.add ("", 1); + MALLOC_CHECK; + +skip_arg_parsing: + PROCESS_INFORMATION pi = {0}; + + STARTUPINFO si = {0}; + si.lpReserved = NULL; + si.lpDesktop = NULL; + si.dwFlags = STARTF_USESTDHANDLES; + si.hStdInput = handle (0, 0); /* Get input handle */ + si.hStdOutput = handle (1, 1); /* Get output handle */ + si.hStdError = handle (2, 1); /* Get output handle */ + si.cb = sizeof (si); + + /* Pass fd table to a child */ + + MALLOC_CHECK; + int len = dtable.linearize_fd_array (0, 0); + MALLOC_CHECK; + if (len == -1) + { + system_printf ("FATAL error in linearize_fd_array"); + return -1; + } + int titlelen = 1 + (old_title && mode == _P_OVERLAY ? strlen (old_title) : 0); + si.cbReserved2 = len + titlelen + sizeof(child_info); + si.lpReserved2 = (LPBYTE) alloca (si.cbReserved2); + +# define ciresrv ((child_info *)si.lpReserved2) + HANDLE spr = NULL; + DWORD chtype; + if (mode != _P_OVERLAY) + chtype = PROC_SPAWN; + else + { + spr = CreateEvent(&sec_all, TRUE, FALSE, NULL); + ProtectHandle (spr); + chtype = PROC_EXEC; + } + + init_child_info (chtype, ciresrv, child->pid, spr); + + LPBYTE resrv = si.lpReserved2 + sizeof *ciresrv; +# undef ciresrv + + if (dtable.linearize_fd_array (resrv, len) < 0) + { + system_printf ("FATAL error in second linearize_fd_array"); + return -1; + } + + if (titlelen > 1) + strcpy ((char *) resrv + len, old_title); + else + resrv[len] = '\0'; + + /* We print the translated program and arguments here so the user can see + what was done to it. */ + syscall_printf ("spawn_guts (%s, %.132s)", real_path, one_line.buf); + + int flags = CREATE_DEFAULT_ERROR_MODE | CREATE_SUSPENDED | + GetPriorityClass (hMainProc); + + if (mode == _P_DETACH || !set_console_state_for_spawn ()) + flags |= DETACHED_PROCESS; + + MALLOC_CHECK; + /* Build windows style environment list */ + char *envblock = winenv (envp); + MALLOC_CHECK; + + /* Preallocated buffer for `sec_user' call */ + char sa_buf[1024]; + + if (hToken) + { + /* allow the child to interact with our window station/desktop */ + HANDLE hwst, hdsk; + SECURITY_INFORMATION dsi = DACL_SECURITY_INFORMATION; + DWORD n; + char wstname[1024]; + char dskname[1024]; + + hwst = GetProcessWindowStation(); + SetUserObjectSecurity(hwst, &dsi, get_null_sd ()); + GetUserObjectInformation(hwst, UOI_NAME, wstname, 1024, &n); + hdsk = GetThreadDesktop(GetCurrentThreadId()); + SetUserObjectSecurity(hdsk, &dsi, get_null_sd ()); + GetUserObjectInformation(hdsk, UOI_NAME, dskname, 1024, &n); + strcat (wstname, "\\"); + strcat (wstname, dskname); + si.lpDesktop = wstname; + /* force the new process to reread /etc/passwd and /etc/group */ + child->uid = USHRT_MAX; + child->username[0] = '\0'; + + char tu[1024]; + PSID sid = NULL; + DWORD ret_len; + if (GetTokenInformation (hToken, TokenUser, + (LPVOID) &tu, sizeof tu, + &ret_len)) + sid = ((TOKEN_USER *) &tu)->User.Sid; + else + system_printf ("GetTokenInformation: %E"); + + rc = CreateProcessAsUser (hToken, + real_path, /* image name - with full path */ + one_line.buf, /* what was passed to exec */ + /* process security attrs */ + allow_ntsec && sid ? sec_user (sa_buf, sid) + : &sec_all_nih, + /* thread security attrs */ + allow_ntsec && sid ? sec_user (sa_buf, sid) + : &sec_all_nih, + TRUE, /* inherit handles from parent */ + flags, + envblock,/* environment */ + 0, /* use current drive/directory */ + &si, + &pi); + } + else + rc = CreateProcessA (real_path, /* image name - with full path */ + one_line.buf, /* what was passed to exec */ + /* process security attrs */ + allow_ntsec ? sec_user (sa_buf) : &sec_all_nih, + /* thread security attrs */ + allow_ntsec ? sec_user (sa_buf) : &sec_all_nih, + TRUE, /* inherit handles from parent */ + flags, + envblock,/* environment */ + 0, /* use current drive/directory */ + &si, + &pi); + + MALLOC_CHECK; + free (envblock); + MALLOC_CHECK; + + /* Set errno now so that debugging messages from it appear before our + final debugging message [this is a general rule for debugging + messages]. */ + if (!rc) + __seterrno (); + + MALLOC_CHECK; + /* Name the handle similarly to proc_subproc. */ + ProtectHandle1 (pi.hProcess, childhProc); + ProtectHandle (pi.hThread); + MALLOC_CHECK; + + /* We print the original program name here so the user can see that too. */ + syscall_printf ("%d = spawn_guts (%s, %.132s)", + rc ? pi.dwProcessId : (unsigned int) -1, + prog_arg, one_line.buf); + + if (!rc) + { + if (spr) + ForceCloseHandle (spr); + return -1; + } + + /* Set up child's signal handlers */ + for (i = 0; i < NSIG; i++) + { + child->getsig(i).sa_mask = 0; + if (myself->getsig(i).sa_handler != SIG_IGN || (mode != _P_OVERLAY)) + child->getsig(i).sa_handler = SIG_DFL; + } + + if (mode == _P_OVERLAY) + { + close_all_files (); + strcpy (child->progname, real_path_buf); + proc_terminate (); + hExeced = pi.hProcess; + } + else + { + child->dwProcessId = pi.dwProcessId; + child->hProcess = pi.hProcess; + child->process_state |= PID_INITIALIZING; + proc_register (child); + } + + sigproc_printf ("spawned windows pid %d", pi.dwProcessId); + /* Start the child running */ + ResumeThread (pi.hThread); + ForceCloseHandle (pi.hThread); + + if (hToken) + CloseHandle (hToken); + + DWORD res; + + if (mode == _P_OVERLAY) + { + BOOL exited; + + HANDLE waitbuf[3] = {pi.hProcess, signal_arrived, spr}; + int nwait = 3; + + SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST); + res = 0; + DWORD timeout = INFINITE; + exec_exit = 1; + exited = FALSE; + MALLOC_CHECK; + waitfor: + switch (WaitForMultipleObjects (nwait, waitbuf, FALSE, timeout)) + { + case WAIT_TIMEOUT: + syscall_printf ("WFMO timed out after signal"); + if (WaitForSingleObject (pi.hProcess, 0) != WAIT_OBJECT_0) + { + sigproc_printf ("subprocess still alive after signal"); + res = exec_exit; + } + else + { + sigproc_printf ("subprocess exited after signal"); + case WAIT_OBJECT_0: + sigproc_printf ("subprocess exited"); + if (!GetExitCodeProcess (pi.hProcess, &res)) + res = exec_exit; + exited = TRUE; + } + if (nwait > 2) + if (WaitForSingleObject (spr, 1) == WAIT_OBJECT_0) + res |= EXIT_REPARENTING; + else if (!(res & EXIT_REPARENTING)) + { + MALLOC_CHECK; + close_all_files (); + MALLOC_CHECK; + } + break; + case WAIT_OBJECT_0 + 1: + sigproc_printf ("signal arrived"); + timeout = 10; + goto waitfor; + case WAIT_OBJECT_0 + 2: + res = EXIT_REPARENTING; + MALLOC_CHECK; + ForceCloseHandle (spr); + MALLOC_CHECK; + if (!parent_alive) + { + nwait = 1; + sigproc_terminate (); + goto waitfor; + } + break; + case WAIT_FAILED: + DWORD r; + system_printf ("wait failed: nwait %d, pid %d, winpid %d, %E", + nwait, myself->pid, myself->dwProcessId); + system_printf ("waitbuf[0] %p %d", waitbuf[0], + GetHandleInformation (waitbuf[0], &r)); + system_printf ("waitbuf[1] %p = %d", waitbuf[1], + GetHandleInformation (waitbuf[1], &r)); + set_errno (ECHILD); + return -1; + } + + if (nwait > 2) + ForceCloseHandle (spr); + + sigproc_printf ("res = %x", res); + + if (res & EXIT_REPARENTING) + { + /* Try to reparent child process. + * Make handles to child available to parent process and exit with + * EXIT_REPARENTING status. Wait() syscall in parent will then wait + * for newly created child. + */ + if (my_parent_is_alive ()) + { + pinfo *parent = procinfo (myself->ppid); + sigproc_printf ("parent = %p", parent); + HANDLE hP = OpenProcess (PROCESS_ALL_ACCESS, FALSE, + parent->dwProcessId); + sigproc_printf ("parent's handle = %d", hP); + if (hP == NULL && GetLastError () == ERROR_INVALID_PARAMETER) + res = 1; + else if (hP) + { + ProtectHandle (hP); + res = DuplicateHandle (hMainProc, pi.hProcess, hP, + &myself->hProcess, 0, FALSE, + DUPLICATE_SAME_ACCESS); + sigproc_printf ("Dup hP %d", res); + ForceCloseHandle (hP); + } + if (!res) + { + system_printf ("Reparent failed, parent handle %p, %E", hP); + system_printf ("my dwProcessId %d, myself->dwProcessId %d", + GetCurrentProcessId(), myself->dwProcessId); + system_printf ("myself->process_state %x", + myself->process_state); + system_printf ("myself->hProcess %x", myself->hProcess); + } + } + res = EXIT_REPARENTING; + ForceCloseHandle1 (hExeced, childhProc); + hExeced = INVALID_HANDLE_VALUE; + } + else if (exited) + { + ForceCloseHandle1 (hExeced, childhProc); + hExeced = INVALID_HANDLE_VALUE; // stop do_exit from attempting to terminate child + } + + MALLOC_CHECK; + do_exit (res | EXIT_NOCLOSEALL); + } + + if (mode == _P_WAIT) + { + waitpid (child->pid, (int *) &res, 0); + } + else if (mode == _P_DETACH) + { + /* Lose all memory of this child. */ + res = 0; + } + else if ((mode == _P_NOWAIT) || (mode == _P_NOWAITO)) + { + res = child->pid; + } + + return (int) res; +} + +extern "C" +int +cwait (int *result, int pid, int) +{ + return waitpid (pid, result, 0); +} + +/* + * Helper function for spawn runtime calls. + * Doesn't search the path. + */ + +extern "C" int +_spawnve (HANDLE hToken, int mode, const char *path, const char *const *argv, + const char *const *envp) +{ + pinfo *child; + int ret; + vfork_save *vf = vfork_storage.val (); + + if (vf != NULL && (vf->pid < 0) && mode == _P_OVERLAY) + mode = _P_NOWAIT; + else + vf = NULL; + + syscall_printf ("_spawnve (%s, %s, %x)", path, argv[0], envp); + + switch (mode) + { + case _P_OVERLAY: + /* We do not pass _P_SEARCH_PATH here. execve doesn't search PATH.*/ + /* Just act as an exec if _P_OVERLAY set. */ + spawn_guts (hToken, path, argv, envp, myself, mode); + /* Errno should be set by spawn_guts. */ + ret = -1; + break; + case _P_NOWAIT: + case _P_NOWAITO: + case _P_WAIT: + case _P_DETACH: + child = cygwin_shared->p.allocate_pid (); + if (!child) + { + set_errno (EAGAIN); + syscall_printf ("-1 = spawnve (), process table full"); + return -1; + } + strcpy (child->progname, path); + child->ppid = myself->pid; + child->uid = myself->uid; + child->gid = myself->gid; + child->pgid = myself->pgid; + child->sid = myself->sid; + child->ctty = myself->ctty; + child->umask = myself->umask; + child->process_state |= PID_INITIALIZING; + memcpy (child->username, myself->username, MAX_USER_NAME); + child->psid = myself->psid; + memcpy (child->sidbuf, myself->sidbuf, 40); + memcpy (child->logsrv, myself->logsrv, 256); + memcpy (child->domain, myself->domain, MAX_COMPUTERNAME_LENGTH+1); + subproc_init (); + ret = spawn_guts (hToken, path, argv, envp, child, mode); + if (ret == -1) + child->process_state = PID_NOT_IN_USE; + + if (vf) + { + vf->pid = child->pid; + longjmp (vf->j, 1); + } + break; + default: + set_errno (EINVAL); + ret = -1; + break; + } + return ret; +} + +/* + * spawn functions as implemented in the MS runtime library. + * Most of these based on (and copied from) newlib/libc/posix/execXX.c + */ + +extern "C" +int +spawnl (int mode, const char *path, const char *arg0, ...) +{ + int i; + va_list args; + const char *argv[256]; + + va_start (args, arg0); + argv[0] = arg0; + i = 1; + + do + argv[i] = va_arg (args, const char *); + while (argv[i++] != NULL); + + va_end (args); + + return _spawnve (NULL, mode, path, (char * const *) argv, + *user_data->envptr); +} + +extern "C" +int +spawnle (int mode, const char *path, const char *arg0, ...) +{ + int i; + va_list args; + const char * const *envp; + const char *argv[256]; + + va_start (args, arg0); + argv[0] = arg0; + i = 1; + + do + argv[i] = va_arg (args, const char *); + while (argv[i++] != NULL); + + envp = va_arg (args, const char * const *); + va_end (args); + + return _spawnve (NULL, mode, path, (char * const *) argv, + (char * const *) envp); +} + +extern "C" +int +spawnlp (int mode, const char *path, const char *arg0, ...) +{ + int i; + va_list args; + const char *argv[256]; + + va_start (args, arg0); + argv[0] = arg0; + i = 1; + + do + argv[i] = va_arg (args, const char *); + while (argv[i++] != NULL); + + va_end (args); + + return spawnvpe (mode, path, (char * const *) argv, *user_data->envptr); +} + +extern "C" +int +spawnlpe (int mode, const char *path, const char *arg0, ...) +{ + int i; + va_list args; + const char * const *envp; + const char *argv[256]; + + va_start (args, arg0); + argv[0] = arg0; + i = 1; + + do + argv[i] = va_arg (args, const char *); + while (argv[i++] != NULL); + + envp = va_arg (args, const char * const *); + va_end (args); + + return spawnvpe (mode, path, (char * const *) argv, envp); +} + +extern "C" +int +spawnv (int mode, const char *path, const char * const *argv) +{ + return _spawnve (NULL, mode, path, argv, *user_data->envptr); +} + +extern "C" +int +spawnve (int mode, const char *path, char * const *argv, + const char * const *envp) +{ + return _spawnve (NULL, mode, path, argv, envp); +} + +extern "C" +int +spawnvp (int mode, const char *path, const char * const *argv) +{ + return spawnvpe (mode, path, argv, *user_data->envptr); +} + +extern "C" +int +spawnvpe (int mode, const char *file, const char * const *argv, + const char * const *envp) +{ + char buf[MAXNAMLEN]; + return _spawnve (NULL, mode, find_exec (file, buf), argv, envp); +} diff --git a/winsup/cygwin/strace.cc b/winsup/cygwin/strace.cc new file mode 100644 index 000000000..d66d9c7b2 --- /dev/null +++ b/winsup/cygwin/strace.cc @@ -0,0 +1,409 @@ +/* strace.cc: system/windows tracing + + Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include +#include "winsup.h" + +#define PROTECT(x) x[sizeof(x)-1] = 0 +#define CHECK(x) if (x[sizeof(x)-1] != 0) { small_printf("array bound exceeded %d\n", __LINE__); ExitProcess(1); } + +DWORD NO_COPY strace_active = 0; + +/* 'twould be nice to declare this in winsup.h but winsup.h doesn't require + stdarg.h, so we declare it here instead. */ + +#ifndef NOSTRACE + +#ifndef STRACE_HHMMSS +static long long hires_frequency = 0; +static int hires_initted = 0; + +static int strace_microseconds() +{ + static int first_microsec = 0; + int microsec; + if (!hires_initted) + { + hires_initted = 1; + QueryPerformanceFrequency ((LARGE_INTEGER *) &hires_frequency); + if (hires_frequency == 0) + hires_initted = 2; + } + if (hires_initted == 2) + { + int count = GetTickCount (); + microsec = count * 1000; + } + else + { + long long thiscount; + QueryPerformanceCounter ((LARGE_INTEGER *) &thiscount); + thiscount = (long long) (((double) thiscount/(double) hires_frequency) + * 1000000.0); + microsec = thiscount; + } + if (first_microsec == 0) + first_microsec = microsec; + return microsec - first_microsec; +} +#endif + +/* sprintf analog for use by output routines. */ +static int +strace_vsprintf (char *buf, const char *infmt, va_list ap) +{ + int count; + char fmt[80], unkfmt[80]; + static int nonewline = FALSE; + DWORD err = GetLastError (); + +#ifndef STRACE_HHMMSS + static int lmicrosec = 0; + int microsec = strace_microseconds (); + int dmicrosec = lmicrosec ? microsec - lmicrosec : 0; + lmicrosec = microsec; + + __small_sprintf (fmt, "%5d %7d [%s] %s ", + dmicrosec, microsec, threadname (0), "%s %d%s"); + __small_sprintf (unkfmt, "%6d %7d [%s] %s ", + dmicrosec, microsec, threadname (0), + "(unknown)"); +#else + SYSTEMTIME st; + GetLocalTime (&st); + const char *tn = threadname (0); + __small_sprintf (fmt, "%02d:%02d:%02d [%s] %s ", + st.wHour, st.wMinute, st.wSecond, tn, "%s %d%s"); + __small_sprintf (unkfmt, "%02d:%02d:%02d [%s] %s ", + st.wHour, st.wMinute, st.wSecond, tn, "***"); +#endif + + SetLastError (err); + if (nonewline) + { + count = 0; + if (strncmp (infmt, "%F: ", 4) == 0) + { + infmt += 4; + (void) va_arg (ap, char *); + } + } + else + { + char *p, progname[sizeof (myself->progname)]; + static BOOL NO_COPY output_path_once = FALSE; + if (!output_path_once) + output_path_once = !!(p = myself->progname); + else + { + if ((p = strrchr (myself->progname, '\\')) != NULL) + p++; + else + p = myself->progname; + strcpy (progname, p); + if ((p = strrchr (progname, '.')) != NULL) + *p = '\000'; + p = progname; + } + count = __small_sprintf (buf, fmt, p && *p ? p : "(unknown)", + myself->pid, hExeced ? "!" : ""); + } + + count += __small_vsprintf (buf + count, infmt, ap); + char *p; + for (p = buf + count; p > buf; p--) + switch (p[-1]) + { + case '\n': + p[-1] = '\0'; + break; + case '\b': + *--p = '\0'; + nonewline = TRUE; + goto done; + default: + goto addnl; + } + +addnl: + *p++ = '\n'; + *p = '\0'; + nonewline = FALSE; + +done: + return p - buf; +} + +/* Write to strace file or strace queue. */ +static void +strace_write (unsigned category, const char *buf, int count) +{ +# define PREFIX (3 + 8 + 1 + 8 + 1) + char outbuf[PREFIX + 1 + count + 1]; +# define outstuff (outbuf + 12) + __small_sprintf (outstuff, "%x %s", category, buf); + __small_sprintf (outbuf, "cYg%08x", strlen (outstuff) + 1); + outstuff[-1] = ' '; + OutputDebugString (outbuf); +} + +/* Printf function used when tracing system calls. + Warning: DO NOT SET ERRNO HERE! */ + +void +strace_printf (unsigned category, const char *fmt,...) +{ + DWORD err = GetLastError (); + if (strace_active) + { + int count; + va_list ap; + char buf[10000]; + + PROTECT(buf); + va_start (ap, fmt); + SetLastError (err); + count = strace_vsprintf (buf, fmt, ap); + va_end (ap); + CHECK(buf); + + strace_write (category, buf, count); + } + SetLastError (err); +} + +void __stdcall +mark (const char *fn, int i) +{ +} + +static const struct tab +{ + int v; + const char *n; +} +ta[] = +{ + { WM_NULL, "WM_NULL" }, + { WM_CREATE, "WM_CREATE" }, + { WM_DESTROY, "WM_DESTROY" }, + { WM_MOVE, "WM_MOVE" }, + { WM_SIZE, "WM_SIZE" }, + { WM_ACTIVATE, "WM_ACTIVATE" }, + { WM_SETFOCUS, "WM_SETFOCUS" }, + { WM_KILLFOCUS, "WM_KILLFOCUS" }, + { WM_ENABLE, "WM_ENABLE" }, + { WM_SETREDRAW, "WM_SETREDRAW" }, + { WM_SETTEXT, "WM_SETTEXT" }, + { WM_GETTEXT, "WM_GETTEXT" }, + { WM_GETTEXTLENGTH, "WM_GETTEXTLENGTH" }, + { WM_PAINT, "WM_PAINT" }, + { WM_CLOSE, "WM_CLOSE" }, + { WM_QUERYENDSESSION, "WM_QUERYENDSESSION" }, + { WM_QUIT, "WM_QUIT" }, + { WM_QUERYOPEN, "WM_QUERYOPEN" }, + { WM_ERASEBKGND, "WM_ERASEBKGND" }, + { WM_SYSCOLORCHANGE, "WM_SYSCOLORCHANGE" }, + { WM_ENDSESSION, "WM_ENDSESSION" }, + { WM_SHOWWINDOW, "WM_SHOWWINDOW" }, + { WM_WININICHANGE, "WM_WININICHANGE" }, + { WM_DEVMODECHANGE, "WM_DEVMODECHANGE" }, + { WM_ACTIVATEAPP, "WM_ACTIVATEAPP" }, + { WM_FONTCHANGE, "WM_FONTCHANGE" }, + { WM_TIMECHANGE, "WM_TIMECHANGE" }, + { WM_CANCELMODE, "WM_CANCELMODE" }, + { WM_SETCURSOR, "WM_SETCURSOR" }, + { WM_MOUSEACTIVATE, "WM_MOUSEACTIVATE" }, + { WM_CHILDACTIVATE, "WM_CHILDACTIVATE" }, + { WM_QUEUESYNC, "WM_QUEUESYNC" }, + { WM_GETMINMAXINFO, "WM_GETMINMAXINFO" }, + { WM_PAINTICON, "WM_PAINTICON" }, + { WM_ICONERASEBKGND, "WM_ICONERASEBKGND" }, + { WM_NEXTDLGCTL, "WM_NEXTDLGCTL" }, + { WM_SPOOLERSTATUS, "WM_SPOOLERSTATUS" }, + { WM_DRAWITEM, "WM_DRAWITEM" }, + { WM_MEASUREITEM, "WM_MEASUREITEM" }, + { WM_DELETEITEM, "WM_DELETEITEM" }, + { WM_VKEYTOITEM, "WM_VKEYTOITEM" }, + { WM_CHARTOITEM, "WM_CHARTOITEM" }, + { WM_SETFONT, "WM_SETFONT" }, + { WM_GETFONT, "WM_GETFONT" }, + { WM_SETHOTKEY, "WM_SETHOTKEY" }, + { WM_GETHOTKEY, "WM_GETHOTKEY" }, + { WM_QUERYDRAGICON, "WM_QUERYDRAGICON" }, + { WM_COMPAREITEM, "WM_COMPAREITEM" }, + { WM_COMPACTING, "WM_COMPACTING" }, + { WM_WINDOWPOSCHANGING, "WM_WINDOWPOSCHANGING" }, + { WM_WINDOWPOSCHANGED, "WM_WINDOWPOSCHANGED" }, + { WM_POWER, "WM_POWER" }, + { WM_COPYDATA, "WM_COPYDATA" }, + { WM_CANCELJOURNAL, "WM_CANCELJOURNAL" }, + { WM_NCCREATE, "WM_NCCREATE" }, + { WM_NCDESTROY, "WM_NCDESTROY" }, + { WM_NCCALCSIZE, "WM_NCCALCSIZE" }, + { WM_NCHITTEST, "WM_NCHITTEST" }, + { WM_NCPAINT, "WM_NCPAINT" }, + { WM_NCACTIVATE, "WM_NCACTIVATE" }, + { WM_GETDLGCODE, "WM_GETDLGCODE" }, + { WM_NCMOUSEMOVE, "WM_NCMOUSEMOVE" }, + { WM_NCLBUTTONDOWN, "WM_NCLBUTTONDOWN" }, + { WM_NCLBUTTONUP, "WM_NCLBUTTONUP" }, + { WM_NCLBUTTONDBLCLK, "WM_NCLBUTTONDBLCLK" }, + { WM_NCRBUTTONDOWN, "WM_NCRBUTTONDOWN" }, + { WM_NCRBUTTONUP, "WM_NCRBUTTONUP" }, + { WM_NCRBUTTONDBLCLK, "WM_NCRBUTTONDBLCLK" }, + { WM_NCMBUTTONDOWN, "WM_NCMBUTTONDOWN" }, + { WM_NCMBUTTONUP, "WM_NCMBUTTONUP" }, + { WM_NCMBUTTONDBLCLK, "WM_NCMBUTTONDBLCLK" }, + { WM_KEYFIRST, "WM_KEYFIRST" }, + { WM_KEYDOWN, "WM_KEYDOWN" }, + { WM_KEYUP, "WM_KEYUP" }, + { WM_CHAR, "WM_CHAR" }, + { WM_DEADCHAR, "WM_DEADCHAR" }, + { WM_SYSKEYDOWN, "WM_SYSKEYDOWN" }, + { WM_SYSKEYUP, "WM_SYSKEYUP" }, + { WM_SYSCHAR, "WM_SYSCHAR" }, + { WM_SYSDEADCHAR, "WM_SYSDEADCHAR" }, + { WM_KEYLAST, "WM_KEYLAST" }, + { WM_INITDIALOG, "WM_INITDIALOG" }, + { WM_COMMAND, "WM_COMMAND" }, + { WM_SYSCOMMAND, "WM_SYSCOMMAND" }, + { WM_TIMER, "WM_TIMER" }, + { WM_HSCROLL, "WM_HSCROLL" }, + { WM_VSCROLL, "WM_VSCROLL" }, + { WM_INITMENU, "WM_INITMENU" }, + { WM_INITMENUPOPUP, "WM_INITMENUPOPUP" }, + { WM_MENUSELECT, "WM_MENUSELECT" }, + { WM_MENUCHAR, "WM_MENUCHAR" }, + { WM_ENTERIDLE, "WM_ENTERIDLE" }, + { WM_CTLCOLORMSGBOX, "WM_CTLCOLORMSGBOX" }, + { WM_CTLCOLOREDIT, "WM_CTLCOLOREDIT" }, + { WM_CTLCOLORLISTBOX, "WM_CTLCOLORLISTBOX" }, + { WM_CTLCOLORBTN, "WM_CTLCOLORBTN" }, + { WM_CTLCOLORDLG, "WM_CTLCOLORDLG" }, + { WM_CTLCOLORSCROLLBAR, "WM_CTLCOLORSCROLLBAR" }, + { WM_CTLCOLORSTATIC, "WM_CTLCOLORSTATIC" }, + { WM_MOUSEFIRST, "WM_MOUSEFIRST" }, + { WM_MOUSEMOVE, "WM_MOUSEMOVE" }, + { WM_LBUTTONDOWN, "WM_LBUTTONDOWN" }, + { WM_LBUTTONUP, "WM_LBUTTONUP" }, + { WM_LBUTTONDBLCLK, "WM_LBUTTONDBLCLK" }, + { WM_RBUTTONDOWN, "WM_RBUTTONDOWN" }, + { WM_RBUTTONUP, "WM_RBUTTONUP" }, + { WM_RBUTTONDBLCLK, "WM_RBUTTONDBLCLK" }, + { WM_MBUTTONDOWN, "WM_MBUTTONDOWN" }, + { WM_MBUTTONUP, "WM_MBUTTONUP" }, + { WM_MBUTTONDBLCLK, "WM_MBUTTONDBLCLK" }, + { WM_MOUSELAST, "WM_MOUSELAST" }, + { WM_PARENTNOTIFY, "WM_PARENTNOTIFY" }, + { WM_ENTERMENULOOP, "WM_ENTERMENULOOP" }, + { WM_EXITMENULOOP, "WM_EXITMENULOOP" }, + { WM_MDICREATE, "WM_MDICREATE" }, + { WM_MDIDESTROY, "WM_MDIDESTROY" }, + { WM_MDIACTIVATE, "WM_MDIACTIVATE" }, + { WM_MDIRESTORE, "WM_MDIRESTORE" }, + { WM_MDINEXT, "WM_MDINEXT" }, + { WM_MDIMAXIMIZE, "WM_MDIMAXIMIZE" }, + { WM_MDITILE, "WM_MDITILE" }, + { WM_MDICASCADE, "WM_MDICASCADE" }, + { WM_MDIICONARRANGE, "WM_MDIICONARRANGE" }, + { WM_MDIGETACTIVE, "WM_MDIGETACTIVE" }, + { WM_MDISETMENU, "WM_MDISETMENU" }, + { WM_DROPFILES, "WM_DROPFILES" }, + { WM_MDIREFRESHMENU, "WM_MDIREFRESHMENU" }, + { WM_CUT, "WM_CUT" }, + { WM_COPY, "WM_COPY" }, + { WM_PASTE, "WM_PASTE" }, + { WM_CLEAR, "WM_CLEAR" }, + { WM_UNDO, "WM_UNDO" }, + { WM_RENDERFORMAT, "WM_RENDERFORMAT" }, + { WM_RENDERALLFORMATS, "WM_RENDERALLFORMATS" }, + { WM_DESTROYCLIPBOARD, "WM_DESTROYCLIPBOARD" }, + { WM_DRAWCLIPBOARD, "WM_DRAWCLIPBOARD" }, + { WM_PAINTCLIPBOARD, "WM_PAINTCLIPBOARD" }, + { WM_VSCROLLCLIPBOARD, "WM_VSCROLLCLIPBOARD" }, + { WM_SIZECLIPBOARD, "WM_SIZECLIPBOARD" }, + { WM_ASKCBFORMATNAME, "WM_ASKCBFORMATNAME" }, + { WM_CHANGECBCHAIN, "WM_CHANGECBCHAIN" }, + { WM_HSCROLLCLIPBOARD, "WM_HSCROLLCLIPBOARD" }, + { WM_QUERYNEWPALETTE, "WM_QUERYNEWPALETTE" }, + { WM_PALETTEISCHANGING, "WM_PALETTEISCHANGING" }, + { WM_PALETTECHANGED, "WM_PALETTECHANGED" }, + { WM_HOTKEY, "WM_HOTKEY" }, + { WM_PENWINFIRST, "WM_PENWINFIRST" }, + { WM_PENWINLAST, "WM_PENWINLAST" }, + { WM_ASYNCIO, "ASYNCIO" }, + { 0, 0 }}; + +void _strace_wm (int message, int word, int lon) +{ + if (strace_active) + { + int i; + + for (i = 0; ta[i].n; i++) + { + if (ta[i].v == message) + { + strace_printf (_STRACE_WM, "wndproc %d %s %d %d", message, ta[i].n, word, lon); + return; + } + } + strace_printf (_STRACE_WM, "wndproc %d unknown %d %d", message, word, lon); + } +} + +/* Print a message on stderr (bypassing anything that could prevent the + message from being printed, for example a buggy or corrupted stdio). + This is used, for example, to print diagnostics of fatal errors. */ + +void +__system_printf (const char *fmt,...) +{ + char buf[6000]; + va_list ap; + int count; + + PROTECT (buf); + va_start (ap, fmt); + count = strace_vsprintf (buf, fmt, ap); + va_end (ap); + CHECK (buf); + + DWORD done; + WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, count, &done, 0); + FlushFileBuffers (GetStdHandle (STD_ERROR_HANDLE)); + +#ifndef NOSTRACE + if (strace_active) + strace_write (1, buf, count); +#endif + +#ifdef DEBUGGING +// try_to_debug (); +#endif +} + +#else + +/* empty functions for when strace is disabled */ + +void +strace_init (const char *buf) +{} + +extern "C" { +void _strace_wm (int message, int word, int lon) +{} +} +#endif /*NOSTRACE*/ diff --git a/winsup/cygwin/strsep.cc b/winsup/cygwin/strsep.cc new file mode 100644 index 000000000..0a421f6e1 --- /dev/null +++ b/winsup/cygwin/strsep.cc @@ -0,0 +1,65 @@ +/* strsep.cc: strsep call */ + +#include + +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +extern "C" +char * +strsep (char **stringp, + const char *delim) +{ + register char *s; + register const char *spanp; + register int c, sc; + char *tok; + + if ((s = *stringp) == NULL) + return (NULL); + for (tok = s;;) { + c = *s++; + spanp = delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = 0; + *stringp = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} diff --git a/winsup/cygwin/sync.cc b/winsup/cygwin/sync.cc new file mode 100644 index 000000000..89d92ce06 --- /dev/null +++ b/winsup/cygwin/sync.cc @@ -0,0 +1,112 @@ +/* sync.cc: Synchronization functions for cygwin. + + This file implements the methods for controlling the "muto" class + which is intended to operate similarly to a mutex but attempts to + avoid making expensive calls to the kernel. + + Copyright 1999 Cygnus Solutions. + + Written by Christopher Faylor + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include +#include +#include "winsup.h" + +/* Constructor */ +muto::muto(int inh, const char *name) : sync (0), visits(0), waiters(-1), tid (0) +{ + /* Create event which is used in the fallback case when blocking is necessary */ + if (!(bruteforce = CreateEvent (inh ? &sec_all_nih : &sec_none_nih, FALSE, FALSE, name))) + { + DWORD oerr = GetLastError (); + SetLastError (oerr); + return; + } +} + +/* Destructor */ +muto::~muto () +{ + /* Just need to close the event handle */ + if (bruteforce) + CloseHandle (bruteforce); +} + +/* Acquire the lock. Argument is the number of milliseconds to wait for + the lock. Multiple visits from the same thread are allowed and should + be handled correctly. */ +int +muto::acquire (DWORD ms) +{ + DWORD this_tid = GetCurrentThreadId (); + + if (tid != this_tid) + { + /* Increment the waiters part of the class. Need to do this first to + avoid potential races. */ + LONG was_waiting = InterlockedIncrement (&waiters); + + /* This is deceptively simple. Basically, it allows multiple attempts to + lock the same muto to succeed without attempting to manipulate sync. + If the muto is already locked then this thread will wait for ms until + it is signalled by muto::release. Then it will attempt to grab the + sync field. If it succeeds, then this thread owns the mutex. + + There is a pathological condition where a thread times out waiting for + bruteforce but the release code triggers the bruteforce event. In this + case, it is possible for a thread which is going to wait for bruteforce + to wake up immediately. It will then attempt to grab sync but will fail + and go back to waiting. */ + while (tid != this_tid && (was_waiting || InterlockedExchange (&sync, 1) != 0)) + { + switch (WaitForSingleObject (bruteforce, ms)) + { + case WAIT_OBJECT_0: + was_waiting = 0; + break; + default: + InterlockedDecrement (&waiters); + return 0; /* failed. */ + } + } + } + + tid = this_tid; /* register this thread. */ + return ++visits; /* Increment visit count. */ +} + +/* Return the muto lock. Needs to be called once per every acquire. */ +int +muto::release () +{ + DWORD this_tid = GetCurrentThreadId (); + + if (tid != this_tid || !visits) + { + SetLastError (ERROR_NOT_OWNER); /* Didn't have the lock. */ + return 0; /* failed. */ + } + + /* FIXME: Need to check that other thread has not exited, too. */ + if (!--visits) + { + tid = 0; /* We were the last unlocker. */ + InterlockedExchange (&sync, 0); /* Reset trigger. */ + /* This thread had incremented waiters but had never decremented it. + Decrement it now. If it is >= 0 then there are possibly other + threads waiting for the lock, so trigger bruteforce. */ + if (InterlockedDecrement (&waiters) >= 0) + (void) SetEvent (bruteforce); /* Wake up one of the waiting threads */ + } + + return 1; /* success. */ +} diff --git a/winsup/cygwin/sync.h b/winsup/cygwin/sync.h new file mode 100644 index 000000000..18cff7800 --- /dev/null +++ b/winsup/cygwin/sync.h @@ -0,0 +1,48 @@ +/* sync.h: Header file for cygwin synchronization primitives. + + Copyright 1999 Cygnus Solutions. + + Written by Christopher Faylor + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +/* FIXME: Note that currently this class cannot be allocated via `new' since + there are issues with malloc and fork. */ +class muto +{ + LONG sync; /* Used to serialize access to this class. */ + LONG visits; /* Count of number of times a thread has called acquire. */ + LONG waiters; /* Number of threads waiting for lock. */ + HANDLE bruteforce; /* event handle used to control waiting for lock. */ + DWORD tid; /* Thread Id of lock owner. */ +public: + void *operator new (size_t, void *p) {return p;} + void *operator new (size_t n) {return ::new muto; } + void operator delete (void *p) {;} /* can't handle allocated mutos + currently */ + + /* This simple constructor is used for cases where no bruteforce + event handling is required. */ + muto(): sync(0), visits(0), waiters(-1), bruteforce(0), tid(0) {;} + /* A more complicated constructor. */ + muto(int inh, const char *name); + ~muto (); + int acquire (DWORD ms = INFINITE); /* Acquire the lock. */ + int release (); /* Release the lock. */ + + /* Return true if caller thread owns the lock. */ + int ismine () {return tid == GetCurrentThreadId ();} +}; + +/* Use a statically allocated buffer as the storage for a muto */ +#define new_muto(__inh, __name) \ +({ \ + static NO_COPY char __mbuf[sizeof(class muto) + 100] = {0}; \ + muto *m; \ + m = new (__mbuf) muto ((__inh), (__name)); \ + m; \ +}) diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc new file mode 100644 index 000000000..650f71566 --- /dev/null +++ b/winsup/cygwin/syscalls.cc @@ -0,0 +1,1939 @@ +/* syscalls.cc: syscalls + + Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include /* needed for statfs */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "winsup.h" +#include /* for UNLEN */ +#include + +extern BOOL allow_ntsec; + +/* Close all files and process any queued deletions. + Lots of unix style applications will open a tmp file, unlink it, + but never call close. This function is called by _exit to + ensure we don't leave any such files lying around. */ + +void __stdcall +close_all_files (void) +{ + for (int i = 0; i < (int)dtable.size; i++) + if (!dtable.not_open (i)) + _close (i); + + cygwin_shared->delqueue.process_queue (); +} + +extern "C" +int +_unlink (const char *ourname) +{ + int res = -1; + + path_conv win32_name (ourname, SYMLINK_NOFOLLOW); + + if (win32_name.error) + { + set_errno (win32_name.error); + goto done; + } + + syscall_printf ("_unlink (%s)", win32_name.get_win32 ()); + + DWORD atts; + atts = win32_name.file_attributes (); + if (atts != 0xffffffff && atts & FILE_ATTRIBUTE_DIRECTORY) + { + syscall_printf ("unlinking a directory"); + set_errno (EPERM); + goto done; + } + + /* Windows won't check the directory mode, so we do that ourselves. */ + if (! writable_directory (win32_name.get_win32 ())) + { + syscall_printf ("non-writable directory"); + goto done; + } + + if (DeleteFileA (win32_name.get_win32 ())) + res = 0; + else + { + res = GetLastError (); + + /* if access denied, chmod to be writable in case it is not + and try again */ + /* FIXME!!! Should check whether ourname is directory or file + and only try again if permissions are not sufficient */ + if (res == ERROR_ACCESS_DENIED) + { + /* chmod ourname to be writable here */ + res = chmod (ourname, 0777); + + if (DeleteFileA (win32_name.get_win32 ())) + { + res = 0; + goto done; + } + res = GetLastError (); + } + + /* If we get ERROR_SHARING_VIOLATION, the file may still be open - + Windows NT doesn't support deleting a file while it's open. */ + if (res == ERROR_SHARING_VIOLATION) + { + cygwin_shared->delqueue.queue_file (win32_name.get_win32 ()); + res = 0; + } + else + { + __seterrno (); + res = -1; + } + } + +done: + syscall_printf ("%d = unlink (%s)", res, ourname); + return res; +} + +extern "C" +pid_t +_getpid () +{ + return myself->pid; +} + +/* getppid: POSIX 4.1.1.1 */ +extern "C" +pid_t +getppid () +{ + return myself->ppid; +} + +/* setsid: POSIX 4.3.2.1 */ +extern "C" +pid_t +setsid (void) +{ + /* FIXME: for now */ + if (myself->pgid != _getpid ()) + { + myself->ctty = -1; + myself->sid = _getpid (); + myself->pgid = _getpid (); + syscall_printf ("sid %d, pgid %d, ctty %d", myself->sid, myself->pgid, myself->ctty); + return myself->sid; + } + set_errno (EPERM); + return -1; +} + +static int +read_handler (int fd, void *ptr, size_t len, int blocksigs) +{ + int res; + fhandler_base *fh = dtable[fd]; + + if (dtable.not_open (fd)) + { + set_errno (EBADF); + return -1; + } + + if ((fh->get_flags() & (O_NONBLOCK | O_NDELAY)) && !fh->ready_for_read (fd, 0, 0)) + { + syscall_printf ("nothing to read"); + set_errno (EAGAIN); + return -1; + } + + /* Check to see if this is a background read from a "tty", + sending a SIGTTIN, if appropriate */ + res = fh->bg_check (SIGTTIN, blocksigs); + if (res > 0) + { + myself->process_state |= PID_TTYIN; + res = fh->read (ptr, len); + myself->process_state &= ~PID_TTYIN; + } + syscall_printf ("%d = read (%d<%s>, %p, %d)", res, fd, fh->get_name (), ptr, len); + return res; +} + +extern "C" int +_read (int fd, void *ptr, size_t len) +{ + if (dtable.not_open (fd)) + { + set_errno (EBADF); + return -1; + } + + fhandler_base *fh = dtable[fd]; + + /* Could block, so let user know we at least got here. */ + syscall_printf ("read (%d, %p, %d)", fd, ptr, len); + + if (!fh->is_slow () || (fh->get_flags () & (O_NONBLOCK | O_NDELAY)) || + fh->get_r_no_interrupt ()) + { + debug_printf ("non-interruptible read\n"); + return read_handler (fd, ptr, len, 0); + } + + if (fh->ready_for_read (fd, INFINITE, 0)) + return read_handler (fd, ptr, len, 1); + + set_sig_errno (EINTR); + syscall_printf ("%d = read (%d<%s>, %p, %d), errno %d", -1, fd, fh->get_name (), + ptr, len, get_errno ()); + MALLOC_CHECK; + return -1; +} + +extern "C" +int +_write (int fd, const void *ptr, size_t len) +{ + int res = -1; + + if (dtable.not_open (fd)) + { + set_errno (EBADF); + goto done; + } + + /* Could block, so let user know we at least got here. */ + if (fd == 1 || fd == 2) + paranoid_printf ("write (%d, %p, %d)", fd, ptr, len); + else + syscall_printf ("write (%d, %p, %d)", fd, ptr, len); + + fhandler_base *fh; + fh = dtable[fd]; + + res = fh->bg_check (SIGTTOU, 0); + if (res > 0) + { + myself->process_state |= PID_TTYOU; + res = fh->write (ptr, len); + myself->process_state &= ~PID_TTYOU; + } + +done: + if (fd == 1 || fd == 2) + paranoid_printf ("%d = write (%d, %p, %d)", res, fd, ptr, len); + else + syscall_printf ("%d = write (%d, %p, %d)", res, fd, ptr, len); + + MALLOC_CHECK; + return (ssize_t)res; +} + +/* + * FIXME - should really move this interface into fhandler, and implement + * write in terms of it. There are devices in Win32 that could do this with + * overlapped I/O much more efficiently - we should eventually use + * these. + */ + +extern "C" +ssize_t +writev (int fd, const struct iovec *iov, int iovcnt) +{ + int i; + ssize_t len, total; + char *base; + + if (iovcnt < 1 || iovcnt > IOV_MAX) + { + set_errno (EINVAL); + return -1; + } + + /* Ensure that the sum of the iov_len values is less than + SSIZE_MAX (per spec), if so, we must fail with no output (per spec). + */ + total = 0; + for (i = 0; i < iovcnt; ++i) + { + total += iov[i].iov_len; + if (total > SSIZE_MAX) + { + set_errno (EINVAL); + return -1; + } + } + /* Now write the data */ + for (i = 0, total = 0; i < iovcnt; i++, iov++) + { + len = iov->iov_len; + base = iov->iov_base; + while (len > 0) + { + register int nbytes; + nbytes = write (fd, base, len); + if (nbytes < 0 && total == 0) + return -1; + if (nbytes <= 0) + return total; + len -= nbytes; + total += nbytes; + base += nbytes; + } + } + return total; +} + +/* + * FIXME - should really move this interface into fhandler, and implement + * read in terms of it. There are devices in Win32 that could do this with + * overlapped I/O much more efficiently - we should eventually use + * these. + */ + +extern "C" +ssize_t +readv (int fd, const struct iovec *iov, int iovcnt) +{ + int i; + ssize_t len, total; + char *base; + + for (i = 0, total = 0; i < iovcnt; i++, iov++) + { + len = iov->iov_len; + base = iov->iov_base; + while (len > 0) + { + register int nbytes; + nbytes = read (fd, base, len); + if (nbytes < 0 && total == 0) + return -1; + if (nbytes <= 0) + return total; + len -= nbytes; + total += nbytes; + base += nbytes; + } + } + return total; +} + +/* _open */ +/* newlib's fcntl.h defines _open as taking variable args so we must + correspond. The third arg if it exists is: mode_t mode. */ +extern "C" +int +_open (const char *unix_path, int flags, ...) +{ + int fd; + int res = -1; + va_list ap; + mode_t mode = 0; + fhandler_base *fh; + + syscall_printf ("open (%s, %p)", unix_path, flags); + if (!check_null_empty_path_errno(unix_path)) + { + SetResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK," open "); + + /* check for optional mode argument */ + va_start (ap, flags); + mode = va_arg (ap, mode_t); + va_end (ap); + + fd = dtable.find_unused_handle (); + + if (fd < 0) + set_errno (ENMFILE); + else if ((fh = dtable.build_fhandler (fd, unix_path, NULL)) == NULL) + res = -1; // errno already set + else if (!fh->open (unix_path, flags, (mode & 0777) & ~myself->umask)) + { + dtable.release (fd); + res = -1; + } + else if ((res = fd) <= 2) + set_std_handle (res); + ReleaseResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK," open"); + } + + syscall_printf ("%d = open (%s, %p)", res, unix_path, flags); + return res; +} + +extern "C" +off_t +_lseek (int fd, off_t pos, int dir) +{ + off_t res; + + if (dtable.not_open (fd)) + { + set_errno (EBADF); + res = -1; + } + else + { + res = dtable[fd]->lseek (pos, dir); + } + syscall_printf ("%d = lseek (%d, %d, %d)", res, fd, pos, dir); + + return res; +} + +extern "C" +int +_close (int fd) +{ + int res; + + syscall_printf ("close (%d)", fd); + + MALLOC_CHECK; + if (dtable.not_open (fd)) + { + debug_printf ("handle %d not open", fd); + set_errno (EBADF); + res = -1; + } + else + { + SetResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK," close"); + res = dtable[fd]->close (); + dtable.release (fd); + ReleaseResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK," close"); + } + + syscall_printf ("%d = close (%d)", res, fd); + MALLOC_CHECK; + return res; +} + +extern "C" +int +isatty (int fd) +{ + int res; + + if (dtable.not_open (fd)) + { + syscall_printf ("0 = isatty (%d)", fd); + return 0; + } + + res = dtable[fd]->is_tty (); + syscall_printf ("%d = isatty (%d)", res, fd); + return res; +} + +/* Under NT, try to make a hard link using backup API. If that + fails or we are Win 95, just copy the file. + FIXME: We should actually be checking partition type, not OS. + Under NTFS, we should support hard links. On FAT partitions, + we should just copy the file. +*/ + +extern "C" +int +_link (const char *a, const char *b) +{ + int res = -1; + path_conv real_a (a, SYMLINK_NOFOLLOW); + + if (real_a.error) + { + set_errno (real_a.error); + syscall_printf ("-1 = link (%s, %s)", a, b); + return -1; + } + + path_conv real_b (b, SYMLINK_NOFOLLOW); + + if (real_b.error) + { + set_errno (real_b.error); + syscall_printf ("-1 = link (%s, %s)", a, b); + return -1; + } + + /* Try to make hard link first on Windows NT */ + if (os_being_run == winNT) + { + HANDLE hFileSource; + + WIN32_STREAM_ID StreamId; + DWORD dwBytesWritten; + LPVOID lpContext; + DWORD cbPathLen; + DWORD StreamSize; + WCHAR wbuf[MAX_PATH]; + char buf[MAX_PATH]; + + BOOL bSuccess; + + hFileSource = CreateFile ( + real_a.get_win32 (), + FILE_WRITE_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE /*| FILE_SHARE_DELETE*/, + &sec_none_nih, // sa + OPEN_EXISTING, + 0, + NULL + ); + + if (hFileSource == INVALID_HANDLE_VALUE) + { + syscall_printf ("cannot open source, %E"); + goto docopy; + } + + lpContext = NULL; + cygwin_conv_to_full_win32_path (real_b.get_win32 (), buf); + OemToCharW (buf, wbuf); + cbPathLen = (strlen (buf) + 1) * sizeof (WCHAR); + + StreamId.dwStreamId = BACKUP_LINK; + StreamId.dwStreamAttributes = 0; + StreamId.dwStreamNameSize = 0; + StreamId.Size.HighPart = 0; + StreamId.Size.LowPart = cbPathLen; + + StreamSize = sizeof (WIN32_STREAM_ID) - sizeof (WCHAR**) + + StreamId.dwStreamNameSize; + + /* Write the WIN32_STREAM_ID */ + bSuccess = BackupWrite ( + hFileSource, + (LPBYTE) &StreamId, // buffer to write + StreamSize, // number of bytes to write + &dwBytesWritten, + FALSE, // don't abort yet + FALSE, // don't process security + &lpContext); + + if (bSuccess) + { + /* write the buffer containing the path */ + /* FIXME: BackupWrite sometimes traps if linkname is invalid. + Need to handle. */ + bSuccess = BackupWrite ( + hFileSource, + (LPBYTE) wbuf, // buffer to write + cbPathLen, // number of bytes to write + &dwBytesWritten, + FALSE, // don't abort yet + FALSE, // don't process security + &lpContext + ); + + if (!bSuccess) + syscall_printf ("cannot write linkname, %E"); + + /* Free context */ + BackupWrite ( + hFileSource, + NULL, // buffer to write + 0, // number of bytes to write + &dwBytesWritten, + TRUE, // abort + FALSE, // don't process security + &lpContext + ); + } + else + syscall_printf ("cannot write streamId, %E"); + + CloseHandle (hFileSource); + + if (!bSuccess) + goto docopy; + + res = 0; + goto done; + } +docopy: + /* do this with a copy */ + if (CopyFileA (real_a.get_win32 (), real_b.get_win32 (), 1)) + res = 0; + else + __seterrno (); + +done: + syscall_printf ("%d = link (%s, %s)", res, a, b); + return res; +} + +#if 0 +static BOOL +rel2abssd (PSECURITY_DESCRIPTOR psd_rel, PSECURITY_DESCRIPTOR psd_abs, + DWORD abslen) +{ +#ifdef _MT_SAFE + struct _winsup_t *r=_reent_winsup(); + char *dacl_buf=r->_dacl_buf; + char *sacl_buf=r->_sacl_buf; + char *ownr_buf=r->_ownr_buf; + char *grp_buf=r->_grp_buf; +#else + static char dacl_buf[1024]; + static char sacl_buf[1024]; + static char ownr_buf[1024]; + static char grp_buf[1024]; +#endif + DWORD dacl_len = 1024; + DWORD sacl_len = 1024; + DWORD ownr_len = 1024; + DWORD grp_len = 1024; + + BOOL res = MakeAbsoluteSD (psd_rel, psd_abs, &abslen, (PACL) dacl_buf, + &dacl_len, (PACL) sacl_buf, &sacl_len, + (PSID) ownr_buf, &ownr_len, (PSID) grp_buf, + &grp_len); + + syscall_printf ("%d = rel2abssd (...)", res); + return res; +} +#endif + +/* chown: POSIX 5.6.5.1 */ +/* + * chown() is only implemented for Windows NT. Under other operating + * systems, it is only a stub that always returns zero. + * + * Note: the SetFileSecurity API in NT can only set the current + * user as file owner so we have to use the Backup API instead. + */ +extern "C" +int +chown (const char * name, uid_t uid, gid_t gid) +{ + int res; + + if (os_being_run != winNT) // real chown only works on NT + res = 0; // return zero (and do nothing) under Windows 9x + else + { + /* we need Win32 path names because of usage of Win32 API functions */ + path_conv win32_path (name); + + if (win32_path.error) + { + set_errno (win32_path.error); + res = -1; + goto done; + } + + /* FIXME: This makes chown on a device succeed always. Someday we'll want + to actually allow chown to work properly on devices. */ + if (win32_path.is_device ()) + { + res = 0; + goto done; + } + + DWORD attrib = 0; + if (win32_path.file_attributes () & FILE_ATTRIBUTE_DIRECTORY) + attrib |= S_IFDIR; + int has_acls; + has_acls = allow_ntsec && win32_path.has_acls (); + res = get_file_attribute (has_acls, win32_path.get_win32 (), (int *) &attrib); + if (!res) + res = set_file_attribute (win32_path.has_acls (), + win32_path.get_win32 (), + uid, gid, attrib, + myself->logsrv); + + if (res != 0 && get_errno () == ENOSYS) + { + /* fake - if not supported, pretend we're like win95 + where it just works */ + res = 0; + } + } + +done: + syscall_printf ("%d = chown (%s,...)", res, name); + return res; +} + +/* umask: POSIX 5.3.3.1 */ +extern "C" +mode_t +umask (mode_t mask) +{ + mode_t oldmask; + + oldmask = myself->umask; + myself->umask = mask & 0777; + return oldmask; +} + +/* chmod: POSIX 5.6.4.1 */ +extern "C" +int +chmod (const char *path, mode_t mode) +{ + int res = -1; + + path_conv win32_path (path); + + if (win32_path.error) + { + set_errno (win32_path.error); + goto done; + } + + /* FIXME: This makes chmod on a device succeed always. Someday we'll want + to actually allow chmod to work properly on devices. */ + if (win32_path.is_device ()) + { + res = 0; + goto done; + } + + if (win32_path.file_attributes () == (DWORD)-1) + __seterrno (); + else + { + DWORD attr = win32_path.file_attributes (); + /* temporary erase read only bit, to be able to set file security */ + SetFileAttributesA (win32_path.get_win32 (), + attr & ~FILE_ATTRIBUTE_READONLY); + + int has_acls = allow_ntsec && win32_path.has_acls (); + uid_t uid = get_file_owner (has_acls, win32_path.get_win32 ()); + if (! set_file_attribute (has_acls, win32_path.get_win32 (), + uid, + get_file_group (has_acls, + win32_path.get_win32 ()), + mode, + myself->logsrv) + && allow_ntsec) + res = 0; + + /* if the mode we want has any write bits set, we can't + be read only. */ + if (mode & (S_IWUSR | S_IWGRP | S_IWOTH)) + attr &= ~FILE_ATTRIBUTE_READONLY; + else + attr |= FILE_ATTRIBUTE_READONLY; + + if (S_ISLNK (mode) || S_ISSOCK (mode)) + attr |= FILE_ATTRIBUTE_SYSTEM; + + if (!SetFileAttributesA (win32_path.get_win32 (), attr)) + __seterrno (); + else + { + /* Correct NTFS security attributes have higher priority */ + if (res == 0 || !allow_ntsec) + res = 0; + } + } + +done: + syscall_printf ("%d = chmod (%s, %p)", res, path, mode); + return res; +} + +/* fchmod: P96 5.6.4.1 */ + +extern "C" +int +fchmod (int fd, mode_t mode) +{ + if (dtable.not_open (fd)) + { + syscall_printf ("-1 = fchmod (%d, 0%o)", fd, mode); + set_errno (EBADF); + return -1; + } + + const char *path = dtable[fd]->get_name (); + + if (path == NULL) + { + syscall_printf ("-1 = fchmod (%d, 0%o) (no name)", fd, mode); + set_errno (ENOSYS); + return -1; + } + + syscall_printf ("fchmod (%d, 0%o): calling chmod (%s, 0%o)", + fd, mode, path, mode); + return chmod (path, mode); +} + +/* Cygwin internal */ +static int +num_entries (const char *win32_name) +{ + WIN32_FIND_DATA buf; + HANDLE handle; + char buf1[MAX_PATH]; + int count = 0; + + strcpy (buf1, win32_name); + int len = strlen (buf1); + if (len == 0 || isdirsep (buf1[len - 1])) + strcat (buf1, "*"); + else + strcat (buf1, "/*"); /* */ + + handle = FindFirstFileA (buf1, &buf); + + if (handle == INVALID_HANDLE_VALUE) + return 0; + count ++; + while (FindNextFileA (handle, &buf)) + { + if ((buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + count ++; + } + FindClose (handle); + return count; +} + +extern "C" +int +_fstat (int fd, struct stat *buf) +{ + int r; + + if (dtable.not_open (fd)) + { + syscall_printf ("-1 = fstat (%d, %p)", fd, buf); + set_errno (EBADF); + r = -1; + } + else + { + memset (buf, 0, sizeof (struct stat)); + r = dtable[fd]->fstat (buf); + syscall_printf ("%d = fstat (%d, %x)", r,fd,buf); + } + + return r; +} + +/* fsync: P96 6.6.1.1 */ +extern "C" +int +fsync (int fd) +{ + if (dtable.not_open (fd)) + { + syscall_printf ("-1 = fsync (%d)", fd); + set_errno (EBADF); + return -1; + } + + HANDLE h = dtable[fd]->get_handle (); + + if (FlushFileBuffers (h) == 0) + { + __seterrno (); + return -1; + } + return 0; +} + +/* sync: standards? */ +extern "C" +int +sync () +{ + return 0; +} + +int __stdcall +stat_dev (DWORD devn, int unit, unsigned long ino, struct stat *buf) +{ + switch (devn) + { + case FH_CONOUT: + case FH_PIPEW: + buf->st_mode = STD_WBITS; + break; + case FH_CONIN: + case FH_PIPER: + buf->st_mode = STD_RBITS; + break; + default: + buf->st_mode = STD_RBITS | S_IWUSR | S_IWGRP | S_IWOTH; + break; + } + + buf->st_mode |= S_IFCHR; + buf->st_blksize = S_BLKSIZE; + buf->st_nlink = 1; + buf->st_dev = buf->st_rdev = FHDEVN (devn) << 8 | (unit & 0xff); + buf->st_ino = ino; + buf->st_atime = buf->st_mtime = buf->st_ctime = time (NULL); + return 0; +} + +/* Cygwin internal */ +static int +stat_worker (const char *caller, const char *name, struct stat *buf, + int nofollow) +{ + int res = -1; + int atts; + char *win32_name; + char drive[4] = "X:\\"; + MALLOC_CHECK; + + debug_printf ("%s (%s, %p)", caller, name, buf); + + path_conv real_path (name, nofollow ? SYMLINK_NOFOLLOW : SYMLINK_FOLLOW, 1); + if (real_path.error) + { + set_errno (real_path.error); + goto done; + } + + memset (buf, 0, sizeof (struct stat)); + + win32_name = real_path.get_win32 (); + if (real_path.is_device ()) + return stat_dev (real_path.get_devn (), real_path.get_unitn (), + hash_path_name (0, win32_name), buf); + + atts = real_path.file_attributes (); + +/* FIXME: this is of dubious merit and is fundamentally flawed. + E.g., what if the .exe file is a symlink? This is not accounted + for here. Also, what about all of the other special extensions? + + This could be "fixed" by passing the appropriate extension list + to path_conv but I'm not sure that this is really justified. */ + + /* If we can't find the name, try again with a .exe suffix + [but only if not already present]. */ + if (atts == -1 && GetLastError () == ERROR_FILE_NOT_FOUND && + !(strrchr (win32_name, '.') > strrchr (win32_name, '\\'))) + { + debug_printf ("trying with .exe suffix"); + strcat (win32_name, ".exe"); + atts = (int) GetFileAttributesA (win32_name); + if (atts == -1) + strchr (win32_name, '\0')[4] = '\0'; + } + + debug_printf ("%d = GetFileAttributesA (%s)", atts, win32_name); + + drive[0] = win32_name[0]; + UINT dtype; + + if (atts == -1 || !(atts & FILE_ATTRIBUTE_DIRECTORY) || + (os_being_run == winNT + && (((dtype = GetDriveType (drive)) != DRIVE_NO_ROOT_DIR + //&& dtype != DRIVE_REMOTE + && dtype != DRIVE_UNKNOWN)))) + { + fhandler_disk_file fh (NULL); + + if (fh.open (real_path, O_RDONLY | O_BINARY | O_DIROPEN | + (nofollow ? O_NOSYMLINK : 0), 0)) + { + res = fh.fstat (buf); + fh.close (); + if (atts != -1 && (atts & FILE_ATTRIBUTE_DIRECTORY)) + buf->st_nlink = num_entries (win32_name); + } + } + else + { + WIN32_FIND_DATA wfd; + HANDLE handle; + /* hmm, the number of links to a directory includes the + number of entries in the directory, since all the things + in the directory point to it */ + buf->st_nlink += num_entries (win32_name); + buf->st_dev = FHDEVN(FH_DISK) << 8; + buf->st_ino = hash_path_name (0, real_path.get_win32 ()); + buf->st_mode = S_IFDIR | STD_RBITS | STD_XBITS; + if ((atts & FILE_ATTRIBUTE_READONLY) == 0) + buf->st_mode |= STD_WBITS; + + int has_acls = allow_ntsec && real_path.has_acls (); + + buf->st_uid = get_file_owner (has_acls, real_path.get_win32 ()); + buf->st_gid = get_file_group (has_acls, real_path.get_win32 ()); + + if ((handle = FindFirstFile (real_path.get_win32(), &wfd)) != INVALID_HANDLE_VALUE) + { + buf->st_atime = to_time_t (&wfd.ftLastAccessTime); + buf->st_mtime = to_time_t (&wfd.ftLastWriteTime); + buf->st_ctime = to_time_t (&wfd.ftCreationTime); + buf->st_size = wfd.nFileSizeLow; + buf->st_blksize = S_BLKSIZE; + buf->st_blocks = (buf->st_size + S_BLKSIZE-1) / S_BLKSIZE; + FindClose (handle); + } + res = 0; + } + + done: + MALLOC_CHECK; + syscall_printf ("%d = %s (%s, %p)", res, caller, name, buf); + return res; +} + +extern "C" +int +_stat (const char *name, struct stat *buf) +{ + return stat_worker ("stat", name, buf, 0); +} + +/* lstat: Provided by SVR4 and 4.3+BSD, POSIX? */ +extern "C" +int +lstat (const char *name, struct stat *buf) +{ + return stat_worker ("lstat", name, buf, 1); +} + +extern int acl_access (const char *, int); + +extern "C" +int +access (const char *fn, int flags) +{ + // flags were incorrectly specified + if (flags & ~(F_OK|R_OK|W_OK|X_OK)) + { + set_errno (EINVAL); + return -1; + } + + if (allow_ntsec) + return acl_access (fn, flags); + + struct stat st; + int r = stat (fn, &st); + if (r) + return -1; + r = -1; + if (flags & R_OK) + { + if (st.st_uid == myself->uid) + { + if (!(st.st_mode & S_IRUSR)) + goto done; + } + else if (st.st_gid == myself->gid) + { + if (!(st.st_mode & S_IRGRP)) + goto done; + } + else if (!(st.st_mode & S_IROTH)) + goto done; + } + if (flags & W_OK) + { + if (st.st_uid == myself->uid) + { + if (!(st.st_mode & S_IWUSR)) + goto done; + } + else if (st.st_gid == myself->gid) + { + if (!(st.st_mode & S_IWGRP)) + goto done; + } + else if (!(st.st_mode & S_IWOTH)) + goto done; + } + if (flags & X_OK) + { + if (st.st_uid == myself->uid) + { + if (!(st.st_mode & S_IXUSR)) + goto done; + } + else if (st.st_gid == myself->gid) + { + if (!(st.st_mode & S_IXGRP)) + goto done; + } + else if (!(st.st_mode & S_IXOTH)) + goto done; + } + r = 0; +done: + if (r) + set_errno (EACCES); + return r; +} + +extern "C" +int +_rename (const char *oldpath, const char *newpath) +{ + int res = 0; + + path_conv real_old (oldpath, SYMLINK_NOFOLLOW); + + if (real_old.error) + { + set_errno (real_old.error); + syscall_printf ("-1 = rename (%s, %s)", oldpath, newpath); + return -1; + } + + path_conv real_new (newpath, SYMLINK_NOFOLLOW); + + if (real_new.error) + { + set_errno (real_new.error); + syscall_printf ("-1 = rename (%s, %s)", oldpath, newpath); + return -1; + } + + if (! writable_directory (real_old.get_win32 ()) + || ! writable_directory (real_new.get_win32 ())) + { + syscall_printf ("-1 = rename (%s, %s)", oldpath, newpath); + return -1; + } + + int oldatts = GetFileAttributesA (real_old.get_win32 ()); + int newatts = GetFileAttributesA (real_new.get_win32 ()); + + if (oldatts == -1) /* file to move doesn't exist */ + { + syscall_printf ("file to move doesn't exist"); + return (-1); + } + + if (newatts != -1 && newatts & FILE_ATTRIBUTE_READONLY) + { + /* Destination file exists and is read only, change that or else + the rename won't work. */ + SetFileAttributesA (real_new.get_win32 (), newatts & ~ FILE_ATTRIBUTE_READONLY); + } + + /* First make sure we have the permissions */ + if (!MoveFileEx (real_old.get_win32 (), real_new.get_win32 (), MOVEFILE_REPLACE_EXISTING)) + { + res = -1; + + /* !!! fixme, check for windows version before trying this.. */ + if (GetLastError () == ERROR_CALL_NOT_IMPLEMENTED) + { + /* How sad, we must be on win95, try it the stupid way */ + syscall_printf ("try win95 hack"); + for (;;) + { + if (MoveFile (real_old.get_win32 (), real_new.get_win32 ())) + { + res = 0; + break; + } + + if (GetLastError () != ERROR_ALREADY_EXISTS) + { + syscall_printf ("%s already_exists", real_new.get_win32 ()); + break; + } + + if (!DeleteFileA (real_new.get_win32 ()) && + GetLastError () != ERROR_FILE_NOT_FOUND) + { + syscall_printf ("deleting %s to be paranoid", + real_new.get_win32 ()); + break; + } + } + } + if (res) + __seterrno (); + } + + if (res == 0) + { + /* make the new file have the permissions of the old one */ + SetFileAttributesA (real_new.get_win32 (), oldatts); + } + + syscall_printf ("%d = rename (%s, %s)", res, real_old.get_win32 (), + real_new.get_win32 ()); + + return res; +} + +extern "C" +int +system (const char *cmdstring) +{ + int res; + const char* command[4]; + _sig_func_ptr oldint, oldquit; + sigset_t child_block, old_mask; + + if (cmdstring == (const char *) NULL) + return 1; + + oldint = signal (SIGINT, SIG_IGN); + oldquit = signal (SIGQUIT, SIG_IGN); + sigemptyset (&child_block); + sigaddset (&child_block, SIGCHLD); + (void) sigprocmask (SIG_BLOCK, &child_block, &old_mask); + + command[0] = "sh"; + command[1] = "-c"; + command[2] = cmdstring; + command[3] = (const char *) NULL; + + if ((res = spawnvp (_P_WAIT, "sh", command)) == -1) + { + // when exec fails, return value should be as if shell + // executed exit (127) + res = 127; + } + + signal (SIGINT, oldint); + signal (SIGQUIT, oldquit); + (void) sigprocmask (SIG_SETMASK, &old_mask, 0); + return res; +} + +extern "C" +void +setdtablesize (int size) +{ + if (size > (int)dtable.size) + dtable.extend (size); +} + +extern "C" +int +getdtablesize () +{ + return dtable.size; +} + +extern "C" +size_t +getpagesize () +{ + return sysconf (_SC_PAGESIZE); +} + +/* FIXME: not all values are correct... */ +extern "C" +long int +fpathconf (int fd, int v) +{ + switch (v) + { + case _PC_LINK_MAX: + return _POSIX_LINK_MAX; + case _PC_MAX_CANON: + case _PC_MAX_INPUT: + if (isatty (fd)) + return _POSIX_MAX_CANON; + else + { + set_errno (EBADF); + return -1; + } + case _PC_NAME_MAX: + case _PC_PATH_MAX: + return PATH_MAX; + case _PC_PIPE_BUF: + return 4096; + case _PC_CHOWN_RESTRICTED: + case _PC_NO_TRUNC: + return -1; + case _PC_VDISABLE: + if (isatty (fd)) + return -1; + else + { + set_errno (EBADF); + return -1; + } + default: + set_errno (EINVAL); + return -1; + } +} + +extern "C" +long int +pathconf (const char *file, int v) +{ + switch (v) + { + case _PC_PATH_MAX: + return PATH_MAX - strlen (file); + case _PC_NAME_MAX: + return PATH_MAX; + case _PC_LINK_MAX: + return _POSIX_LINK_MAX; + case _PC_MAX_CANON: + case _PC_MAX_INPUT: + return _POSIX_MAX_CANON; + case _PC_PIPE_BUF: + return 4096; + case _PC_CHOWN_RESTRICTED: + case _PC_NO_TRUNC: + return -1; + case _PC_VDISABLE: + return -1; + default: + set_errno (EINVAL); + return -1; + } +} + +extern "C" +char * +ctermid (char *str) +{ + static NO_COPY char buf[16]; + if (str == NULL) + str = buf; + if (!tty_attached (myself)) + strcpy (str, "/dev/conin"); + else + __small_sprintf (str, "/dev/tty%d", myself->ctty); + return str; +} + +extern "C" +char * +ttyname (int fd) +{ + if (dtable.not_open (fd) || !dtable[fd]->is_tty ()) + { + return 0; + } + return (char *)(dtable[fd]->ttyname ()); +} + +/* Set a file descriptor into text or binary mode, returning the + previous mode. */ + +extern "C" +int +setmode (int fd, int mode) +{ + if (dtable.not_open (fd)) + { + set_errno (EBADF); + return -1; + } + if (mode != O_BINARY && mode != O_TEXT) + { + set_errno (EINVAL); + return -1; + } + + fhandler_base *p = dtable[fd]; + + /* Note that we have no way to indicate the case that writes are + binary but not reads, or vice-versa. These cases can arise when + using the tty or console interface. People using those + interfaces should not use setmode. */ + + int res; + if (p->get_w_binary () && p->get_r_binary ()) + res = O_BINARY; + else + res = O_TEXT; + + if (mode & O_BINARY) + { + p->set_w_binary (1); + p->set_r_binary (1); + } + else + { + p->set_w_binary (0); + p->set_r_binary (0); + } + + return res; +} + +/* ftruncate: P96 5.6.7.1 */ +extern "C" +int +ftruncate (int fd, off_t length) +{ + int res = -1; + + if (dtable.not_open (fd)) + { + set_errno (EBADF); + } + else + { + HANDLE h = dtable[fd]->get_handle (); + off_t prev_loc; + + if (h) + { + /* remember curr file pointer location */ + prev_loc = dtable[fd]->lseek (0, SEEK_CUR); + + dtable[fd]->lseek (length, SEEK_SET); + if (!SetEndOfFile (h)) + { + __seterrno (); + } + else + res = 0; + + /* restore original file pointer location */ + dtable[fd]->lseek (prev_loc, 0); + } + } + syscall_printf ("%d = ftruncate (%d, %d)", res, fd, length); + + return res; +} + +/* truncate: Provided by SVR4 and 4.3+BSD. Not part of POSIX.1 or XPG3 */ +/* FIXME: untested */ +extern "C" +int +truncate (const char *pathname, off_t length) +{ + int fd; + int res = -1; + + fd = open (pathname, O_RDWR); + + if (fd == -1) + { + set_errno (EBADF); + } + else + { + res = ftruncate (fd, length); + close (fd); + } + syscall_printf ("%d = truncate (%s, %d)", res, pathname, length); + + return res; +} + +extern "C" +long +get_osfhandle (int fd) +{ + long res = -1; + + if (dtable.not_open (fd)) + { + set_errno ( EBADF); + } + else + { + res = (long) dtable[fd]->get_handle (); + } + syscall_printf ("%d = get_osfhandle(%d)", res, fd); + + return res; +} + +extern "C" +int +statfs (const char *fname, struct statfs *sfs) +{ + char full_path[MAX_PATH]; + + if (!sfs) + { + set_errno (EFAULT); + return -1; + } + cygwin_conv_to_full_win32_path (fname, full_path); + + char *root = rootdir (full_path); + + syscall_printf ("statfs %s", root); + + DWORD spc, bps, freec, totalc; + + if (!GetDiskFreeSpace (root, &spc, &bps, &freec, &totalc)) + { + __seterrno (); + return -1; + } + + DWORD vsn, maxlen, flags; + + if (!GetVolumeInformation (root, NULL, 0, &vsn, &maxlen, &flags, NULL, 0)) + { + __seterrno (); + return -1; + } + sfs->f_type = flags; + sfs->f_bsize = spc*bps; + sfs->f_blocks = totalc; + sfs->f_bfree = sfs->f_bavail = freec; + sfs->f_files = -1; + sfs->f_ffree = -1; + sfs->f_fsid = vsn; + sfs->f_namelen = maxlen; + return 0; +} + +extern "C" +int +fstatfs (int fd, struct statfs *sfs) +{ + if (dtable.not_open (fd)) + { + set_errno (EBADF); + return -1; + } + fhandler_disk_file *f = (fhandler_disk_file *) dtable[fd]; + return statfs (f->get_name (), sfs); +} + +/* setpgid: POSIX 4.3.3.1 */ +extern "C" +int +setpgid (pid_t pid, pid_t pgid) +{ + int res = -1; + if (pid == 0) + pid = getpid (); + if (pgid == 0) + pgid = pid; + + if (pgid < 0) + { + set_errno (EINVAL); + goto out; + } + pinfo *p; + p = procinfo (pid); + if (p == NULL) + { + set_errno (ESRCH); + goto out; + } + /* A process may only change the process group of itself and its children */ + if (p == myself || p->ppid == myself->pid) + { + p->pgid = pgid; + res = 0; + } + else + { + set_errno (EPERM); + goto out; + } +out: + syscall_printf ("pid %d, pgid %d, res %d", pid, pgid, res); + return res; +} + +extern "C" +pid_t +getpgid (pid_t pid) +{ + if (pid == 0) + pid = getpid (); + + pinfo *p = procinfo (pid); + if (p == 0) + { + set_errno (ESRCH); + return -1; + } + return p->pgid; +} + +extern "C" +int +setpgrp (void) +{ + return setpgid (0, 0); +} + +extern "C" +pid_t +getpgrp (void) +{ + return getpgid (0); +} + +extern "C" +char * +ptsname (int fd) +{ + if (dtable.not_open (fd)) + { + set_errno (EBADF); + return 0; + } + return (char *)(dtable[fd]->ptsname ()); +} + +/* FIXME: what is this? */ +extern "C" +int +regfree () +{ + return 0; +} + +/* mknod was the call to create directories before the introduction + of mkdir in 4.2BSD and SVR3. Use of mknod required superuser privs + so the mkdir command had to be setuid root. + Although mknod hasn't been implemented yet, some GNU tools (e.g. the + fileutils) assume its existence so we must provide a stub that always + fails. */ +extern "C" +int +mknod () +{ + set_errno (ENOSYS); + return -1; +} + +/* setgid: POSIX 4.2.2.1 */ +/* FIXME: unimplemented! */ +extern "C" +int +setgid (gid_t a) +{ + set_errno (ENOSYS); + return 0; +} + +/* setuid: POSIX 4.2.2.1 */ +/* FIXME: unimplemented! */ +extern "C" +int +setuid (uid_t b) +{ + set_errno (ENOSYS); + return 0; +} + +/* seteuid: standards? */ +extern "C" +int +seteuid (uid_t c) +{ + set_errno (ENOSYS); + return 0; +} + +/* setegid: from System V. */ +extern "C" +int +setegid (gid_t a) +{ + set_errno (ENOSYS); + return 0; +} + +/* chroot: privileged Unix system call. */ +extern "C" +int +chroot (const char *path) +{ + set_errno (ENOSYS); + return -1; +} + +extern "C" +int +creat (const char *path, mode_t mode) +{ + return open (path, O_WRONLY | O_CREAT | O_TRUNC, mode); +} + +extern "C" +void +__assertfail () +{ + exit (99); +} + +extern "C" +int +getw (FILE *fp) +{ + int w, ret; + ret = fread (&w, sizeof (int), 1, fp); + return ret != 1 ? EOF : w; +} + +extern "C" +int +putw (int w, FILE *fp) +{ + int ret; + ret = fwrite (&w, sizeof (int), 1, fp); + if (feof (fp) || ferror (fp)) + return -1; + return 0; +} + +extern "C" +int +wcscmp (wchar_t *s1, wchar_t *s2) +{ + while (*s1 && *s1 == *s2) + { + s1++; + s2++; + } + + return (*(unsigned short *) s1) - (*(unsigned short *) s2); +} + +extern "C" +int +wcslen (wchar_t *s1) +{ + int l = 0; + while (s1[l]) + l++; + return l; +} + +/* FIXME: to do this right, maybe work out the usoft va_list machine + and use wsvprintfW instead? +*/ +extern "C" +int +wprintf (const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start (ap, fmt); + ret = vprintf (fmt, ap); + va_end (ap); + return ret; +} + +extern "C" +int +vhangup () +{ + set_errno (ENOSYS); + return -1; +} + +extern "C" +_PTR +memccpy (_PTR out, const _PTR in, int c, size_t len) +{ + const char *inc = (char *) in; + char *outc = (char *) out; + + while (len) + { + char x = *inc++; + *outc++ = x; + if (x == c) + return outc; + len --; + } + return 0; +} + +extern "C" +int +nice (int incr) +{ + DWORD priority[] = + { + IDLE_PRIORITY_CLASS, + IDLE_PRIORITY_CLASS, + NORMAL_PRIORITY_CLASS, + HIGH_PRIORITY_CLASS, + REALTIME_PRIORITY_CLASS, + REALTIME_PRIORITY_CLASS + }; + int curr = 2; + + switch (GetPriorityClass (hMainProc)) + { + case IDLE_PRIORITY_CLASS: + curr = 1; + break; + case NORMAL_PRIORITY_CLASS: + curr = 2; + break; + case HIGH_PRIORITY_CLASS: + curr = 3; + break; + case REALTIME_PRIORITY_CLASS: + curr = 4; + break; + } + if (incr > 0) + incr = -1; + else if (incr < 0) + incr = 1; + + if (SetPriorityClass (hMainProc, priority[curr + incr]) == FALSE) + { + __seterrno (); + return -1; + } + + return 0; +} + +/* + * Find the first bit set in I. + */ + +extern "C" +int +ffs (int i) +{ + static const unsigned char table[] = + { + 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 + }; + unsigned long int a; + unsigned long int x = i & -i; + + a = x <= 0xffff ? (x <= 0xff ? 0 : 8) : (x <= 0xffffff ? 16 : 24); + + return table[x >> a] + a; +} + +extern "C" +void +swab (const void *src, void *dst, ssize_t n) +{ + const char *from = (const char *) src; + char *to = (char *) dst; + + while (n > 1) + { + const char b0 = from[--n], b1 = from[--n]; + to[n] = b0; + to[n + 1] = b1; + } +} + +extern "C" +void +login (struct utmp *ut) +{ + register int fd; + int currtty = ttyslot (); + + if (currtty >= 0 && (fd = open (_PATH_UTMP, O_WRONLY | O_CREAT | O_BINARY, + 0644)) >= 0) + { + (void) lseek (fd, (long) (currtty * sizeof (struct utmp)), SEEK_SET); + (void) write (fd, (char *) ut, sizeof (struct utmp)); + (void) close (fd); + } + if ((fd = open (_PATH_WTMP, O_WRONLY | O_APPEND | O_BINARY, 0)) >= 0) + { + (void) write (fd, (char *) ut, sizeof (struct utmp)); + (void) close (fd); + } +} + +/* It isn't possible to use unix-style I/O function in logout code because +cygwin's I/O subsystem may be inaccessible at logout() call time. +*/ +extern "C" +int +logout (char *line) +{ + int res = 0; + HANDLE ut_fd; + static const char path_utmp[] = _PATH_UTMP; + + path_conv win32_path (path_utmp); + if (win32_path.error) + return 0; + + ut_fd = CreateFile (win32_path.get_win32 (), + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + &sec_none_nih, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (ut_fd != INVALID_HANDLE_VALUE) + { + struct utmp *ut; + struct utmp ut_buf[100]; + off_t pos = 0; /* Position in file */ + DWORD rd; + + while (!res && ReadFile (ut_fd, ut_buf, sizeof ut_buf, &rd, NULL) + && rd != 0) + { + struct utmp *ut_end = (struct utmp *) ((char *) ut_buf + rd); + + for (ut = ut_buf; ut < ut_end; ut++, pos += sizeof (*ut)) + if (ut->ut_name[0] + && strncmp (ut->ut_line, line, sizeof (ut->ut_line)) == 0) + /* Found the entry for LINE; mark it as logged out. */ + { + /* Zero out entries describing who's logged in. */ + bzero (ut->ut_name, sizeof (ut->ut_name)); + bzero (ut->ut_host, sizeof (ut->ut_host)); + time (&ut->ut_time); + + /* Now seek back to the position in utmp at which UT occured, + and write the new version of UT there. */ + if ((SetFilePointer (ut_fd, pos, 0, FILE_BEGIN) != 0xFFFFFFFF) + && (WriteFile (ut_fd, (char *) ut, sizeof (*ut), + &rd, NULL))) + { + res = 1; + break; + } + } + } + + CloseHandle (ut_fd); + } + + return res; +} diff --git a/winsup/cygwin/sysconf.cc b/winsup/cygwin/sysconf.cc new file mode 100644 index 000000000..6dcb08afc --- /dev/null +++ b/winsup/cygwin/sysconf.cc @@ -0,0 +1,62 @@ +/* sysconf.cc + + Copyright 1996, 1997, 1998 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include +#include "winsup.h" + +/* sysconf: POSIX 4.8.1.1 */ +/* Allows a portable app to determine quantities of resources or + presence of an option at execution time. */ +long int +sysconf (int in) +{ + switch (in) + { + case _SC_ARG_MAX: + /* FIXME: what's the right value? _POSIX_ARG_MAX is only 4K */ + return 1048576; + case _SC_OPEN_MAX: + /* FIXME: this returns the current limit which can increase + if and when hinfo::find_unused_handle is called. Perhaps + we should return NOFILE or OPEN_MAX instead? */ + return dtable.size; + case _SC_PAGESIZE: + { + SYSTEM_INFO b; + GetSystemInfo (&b); + return b.dwPageSize; + } + case _SC_CLK_TCK: + return CLOCKS_PER_SEC; + case _SC_JOB_CONTROL: + return _POSIX_JOB_CONTROL; + case _SC_CHILD_MAX: + return CHILD_MAX; + case _SC_NGROUPS_MAX: + return NGROUPS_MAX; + case _SC_SAVED_IDS: + return _POSIX_SAVED_IDS; + case _SC_VERSION: + return _POSIX_VERSION; +#if 0 /* FIXME -- unimplemented */ + case _SC_TZNAME_MAX: + return _POSIX_TZNAME_MAX; + case _SC_STREAM_MAX: + return _POSIX_STREAM_MAX; +#endif + } + + /* Invalid input or unimplemented sysconf name */ + set_errno (EINVAL); + return -1; +} diff --git a/winsup/cygwin/syslog.cc b/winsup/cygwin/syslog.cc new file mode 100644 index 000000000..2c0290c4e --- /dev/null +++ b/winsup/cygwin/syslog.cc @@ -0,0 +1,395 @@ +/* syslog.cc + + Copyright 1996, 1997, 1998 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include +#include +#include "winsup.h" + +/* FIXME: These should probably be in the registry. */ +/* FIXME: The Win95 path should be whatever slash is */ + +#define WIN95_EVENT_LOG_PATH "C:\\CYGWIN_SYSLOG.TXT" +#define CYGWIN_LOG_NAME "Cygwin" + +/* + * Utility function to help enable moving + * WIN95_EVENT_LOG_PATH into registry later. + */ +static const char * +get_win95_event_log_path () +{ + return WIN95_EVENT_LOG_PATH; +} + +/* FIXME: For MT safe code these will need to be replaced */ + +#ifdef _MT_SAFE +#define process_ident _reent_winsup()->_process_ident +#define process_logopt _reent_winsup()->_process_logopt +#define process_facility _reent_winsup()->_process_facility + /* Default priority logmask */ +#define process_logmask _reent_winsup()->_process_logmask +#else +static char *process_ident = 0; +static int process_logopt = 0; +static int process_facility = 0; + +/* Default priority logmask */ +static int process_logmask = LOG_UPTO (LOG_DEBUG); +#endif + +/* + * openlog: save the passed args. Don't open the + * system log (NT) or log file (95) yet. + */ +extern "C" +void +openlog (const char *ident, int logopt, int facility) +{ + debug_printf ("openlog called with (%s, %d, %d)", + ident ? ident : "", logopt, facility); + + if (process_ident != 0) + { + free (process_ident); + process_ident = 0; + } + if (ident) + { + process_ident = (char *) malloc (strlen (ident) + 1); + if (process_ident == 0) + { + debug_printf ("failed to allocate memory for process_ident"); + return; + } + strcpy (process_ident, ident); + } + process_logopt = logopt; + process_facility = facility; +} + +/* setlogmask: set the log priority mask and return previous mask. + If maskpri is zero, just return previous. */ +#if 0 +/* FIXME: nobody calls setlogmask? */ +int +setlogmask (int maskpri) +{ + if (maskpri == 0) + return process_logmask; + + int old_mask = process_logmask; + process_logmask = maskpri & LOG_PRIMASK; + + return old_mask; +} +#endif + +/* Private class used to handle formatting of syslog message */ +/* It is named pass_handler because it does a two-pass handling of log + strings. The first pass counts the length of the string, and the second + one builds the string. */ + +class pass_handler +{ + private: + FILE *fp_; + char *message_; + int total_len_; + + void shutdown (); + + /* Explicitly disallow copies */ + pass_handler (const pass_handler &); + pass_handler & operator = (const pass_handler &); + + public: + pass_handler (); + ~pass_handler (); + + int initialize (int); + + int print (const char *,...); + int print_va (const char *, va_list); + char *get_message () const { return message_; } +}; + +pass_handler::pass_handler () : fp_ (0), message_ (0), total_len_ (0) +{ + ; +} + +pass_handler::~pass_handler () +{ + shutdown (); +} + +void +pass_handler::shutdown () +{ + if (fp_ != 0) + { + fclose (fp_); + fp_ = 0; + } + if (message_ != 0) + delete[] message_; +} + +int +pass_handler::initialize (int pass_number) +{ + shutdown (); + if (pass_number == 0) + { + fp_ = fopen ("/dev/null", "wb"); + if (fp_ == 0) + { + debug_printf ("failed to open /dev/null"); + return -1; + } + total_len_ = 0; + } + else + { + message_ = new char[total_len_ + 1]; + if (message_ == 0) + { + debug_printf ("failed to allocate message_"); + return -1; + } + message_[0] = '\0'; + } + return 0; +} + +int +pass_handler::print (const char *fmt, ...) +{ + va_list ap; + va_start (ap, fmt); + int ret = print_va (fmt, ap); + va_end (ap); + return ret; +} + +int +pass_handler::print_va (const char *fmt, va_list list) +{ + if (fp_ != 0) + { + int len = vfprintf (fp_, fmt, list); + if (len < 0) + return -1; + total_len_ += len; + return 0; + } + else if (message_ != 0) + { + char *printpos = &message_[strlen (message_)]; + vsprintf (printpos, fmt, list); + return 0; + } + debug_printf ("FAILURE ! fp_ and message_ both 0!! "); + return -1; +} + +/* + * syslog: creates the log message and writes to system + * log (NT) or log file (95). FIXME. WinNT log error messages + * don't look pretty, but in order to fix this we have to + * embed resources in the code and tell the NT registry + * where we are, blech (what happens if we move ?). + * We could, however, add the resources in Cygwin and + * always point to that. + */ + +extern "C" +void +syslog (int priority, const char *message, ...) +{ + debug_printf ("%x %s", priority, message); + /* If the priority fails the current mask, reject */ + if (((priority & LOG_PRIMASK) & process_logmask) == 0) + { + debug_printf ("failing message %x due to priority mask %x", + priority, process_logmask); + return; + } + + /* Translate %m in the message to error text */ + char *errtext = strerror (get_errno ()); + int errlen = strlen (errtext); + int numfound = 0; + + for (const char *cp = message; *cp; cp++) + if (*cp == '%' && cp[1] == 'm') + numfound++; + + char *newmessage = new char [strlen (message) + (errlen * numfound)]; + + if (newmessage == 0) + { + debug_printf ("failed to allocate newmessage"); + return; + } + + char *dst = newmessage; + for (const char *cp2 = message; *cp2; cp2++) + if (*cp2 == '%' && cp2[1] == 'm') + { + cp2++; + strcpy (dst, errtext); + while (*dst) + dst++; + } + else + *dst++ = *cp2; + + *dst = '\0'; + message = newmessage; + + /* Work out the priority type - we ignore the facility for now.. */ + WORD eventType; + switch (LOG_PRI (priority)) + { + case LOG_ERR: + eventType = EVENTLOG_ERROR_TYPE; + break; + case LOG_WARNING: + eventType = EVENTLOG_WARNING_TYPE; + break; + case LOG_INFO: + eventType = EVENTLOG_INFORMATION_TYPE; + break; + default: + eventType = EVENTLOG_ERROR_TYPE; + break; + } + + /* We need to know how long the buffer needs to be. + The only legal way I can see of doing this is to + do a vfprintf to /dev/null, and count the bytes + output, then do it again to a malloc'ed string. This + is ugly, slow, but prevents core dumps :-). + */ + int pass_number = 0; + va_list ap; + + pass_handler pass; + for (; pass_number < 2; ++pass_number) + { + if (pass.initialize (pass_number) == -1) + return; + + /* Deal with ident_string */ + if (process_ident != 0) + { + if (pass.print ("%s : ", process_ident) == -1) + return; + } + if (process_logopt & LOG_PID) + { + if (pass.print ("Win32 Process Id = 0x%X : Cygwin Process Id = 0x%X : ", + GetCurrentProcessId(), getpid ()) == -1) + return; + } + + if (os_being_run != winNT) + { + /* Add a priority string - not needed for NT + as NT has its own priority codes. */ + switch (LOG_PRI (priority)) + { + case LOG_ERR: + pass.print ("%s : ", "LOG_ERR"); + break; + case LOG_WARNING: + pass.print ("%s : ", "LOG_WARNING"); + break; + case LOG_INFO: + pass.print ("%s : ", "LOG_INFO"); + break; + default: + pass.print ("%s : ", "LOG_ERR"); + break; + } + } + + /* Print out the variable part */ + va_start (ap, message); + if (pass.print_va (message, ap) == -1) + return; + va_end (ap); + + } + const char *msg_strings[1]; + char *total_msg = pass.get_message (); + int len = strlen (total_msg); + if (len != 0 && (total_msg[len - 1] == '\n')) + total_msg[len - 1] = '\0'; + + msg_strings[0] = total_msg; + + if (os_being_run == winNT) + { + /* For NT, open the event log and send the message */ + HANDLE hEventSrc = RegisterEventSourceA (NULL, (process_ident != 0) ? + process_ident : CYGWIN_LOG_NAME); + if (hEventSrc == 0) + { + debug_printf ("RegisterEventSourceA failed with %E"); + return; + } + ReportEventA (hEventSrc, eventType, 0, 0, + NULL, 1, 0, msg_strings, NULL); + DeregisterEventSource (hEventSrc); + } + else + { + /* Under Windows 95, append the message to the log file */ + FILE *fp = fopen (get_win95_event_log_path (), "a"); + if (fp == 0) + { + debug_printf ("failed to open file %s", + get_win95_event_log_path ()); + return; + } + /* Now to prevent several syslog messages from being + interleaved, we must lock the first byte of the file + This works on Win32 even if we created the file above. + */ + HANDLE fHandle = dtable[fileno (fp)]->get_handle (); + if (LockFile (fHandle, 0, 0, 1, 0) == FALSE) + { + debug_printf ("failed to lock file %s", get_win95_event_log_path()); + fclose (fp); + return; + } + fputs (msg_strings[0], fp); + fputc ('\n', fp); + UnlockFile (fHandle, 0, 0, 1, 0); + if (ferror (fp)) + { + debug_printf ("error in writing syslog"); + } + fclose (fp); + } +} + +extern "C" +void +closelog (void) +{ + ; +} diff --git a/winsup/cygwin/termios.cc b/winsup/cygwin/termios.cc new file mode 100644 index 000000000..69aaf1943 --- /dev/null +++ b/winsup/cygwin/termios.cc @@ -0,0 +1,274 @@ +/* termios.cc: termios for WIN32. + + Copyright 1996, 1997, 1998, 2000 Cygnus Solutions. + + Written by Doug Evans and Steve Chamberlain of Cygnus Support + dje@cygnus.com, sac@cygnus.com + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include "winsup.h" + +/* tcsendbreak: POSIX 7.2.2.1 */ +extern "C" +int +tcsendbreak (int fd, int duration) +{ + int res = -1; + + if (dtable.not_open (fd)) + { + set_errno (EBADF); + goto out; + } + + fhandler_base *fh; + fh = dtable[fd]; + + if (!fh->is_tty ()) + set_errno (ENOTTY); + else + { + if ((res = fh->bg_check (-SIGTTOU)) > 0) + res = fh->tcsendbreak (duration); + } + +out: + syscall_printf ("%d = tcsendbreak (%d, %d )", res, fd, duration); + return res; +} + +/* tcdrain: POSIX 7.2.2.1 */ +extern "C" +int +tcdrain (int fd) +{ + int res = -1; + + termios_printf ("tcdrain"); + + if (dtable.not_open (fd)) + { + set_errno (EBADF); + goto out; + } + + fhandler_base *fh; + fh = dtable[fd]; + + if (!fh->is_tty ()) + set_errno (ENOTTY); + else + { + if ((res = fh->bg_check (-SIGTTOU)) > 0) + res = fh->tcdrain (); + } + +out: + syscall_printf ("%d = tcdrain (%d)", res, fd); + return res; +} + +/* tcflush: POSIX 7.2.2.1 */ +extern "C" +int +tcflush (int fd, int queue) +{ + int res = -1; + + if (dtable.not_open (fd)) + { + set_errno (EBADF); + goto out; + } + + fhandler_base *fh; + fh = dtable[fd]; + + if (!fh->is_tty ()) + set_errno (ENOTTY); + else + { + if ((res = fh->bg_check (-SIGTTOU)) > 0) + res = fh->tcflush (queue); + } + +out: + termios_printf ("%d = tcflush (%d, %d)", res, fd, queue); + return res; +} + +/* tcflow: POSIX 7.2.2.1 */ +extern "C" +int +tcflow (int fd, int action) +{ + int res = -1; + + if (dtable.not_open (fd)) + { + set_errno (EBADF); + goto out; + } + + fhandler_base *fh; + fh = dtable[fd]; + + if (!fh->is_tty ()) + set_errno (ENOTTY); + else + { + if ((res = fh->bg_check (-SIGTTOU)) > 0) + res = fh->tcflow (action); + } + +out: + syscall_printf ("%d = tcflow (%d, %d)", res, fd, action); + return res; +} + +/* tcsetattr: POSIX96 7.2.1.1 */ +extern "C" +int +tcsetattr (int fd, int a, const struct termios *t) +{ + int res = -1; + + t = __tonew_termios (t); + if (dtable.not_open (fd)) + { + set_errno (EBADF); + goto out; + } + + fhandler_base *fh; + fh = dtable[fd]; + + if (!fh->is_tty ()) + set_errno (ENOTTY); + else + { + if ((res = fh->bg_check (-SIGTTOU)) > 0) + res = fh->tcsetattr (a, t); + } + +out: + termios_printf ("iflag %x, oflag %x, cflag %x, lflag %x, VMIN %d, VTIME %d", + t->c_iflag, t->c_oflag, t->c_cflag, t->c_lflag, t->c_cc[VMIN], + t->c_cc[VTIME]); + termios_printf ("%d = tcsetattr (%d, %d, %x)", res, fd, a, t); + return res; +} + +/* tcgetattr: POSIX 7.2.1.1 */ +extern "C" +int +tcgetattr (int fd, struct termios *in_t) +{ + int res = -1; + struct termios *t = __makenew_termios (in_t); + + if (dtable.not_open (fd)) + set_errno (EBADF); + else if (!dtable[fd]->is_tty ()) + set_errno (ENOTTY); + else + { + if ((res = dtable[fd]->tcgetattr (t)) == 0) + (void) __toapp_termios (in_t, t); + } + + if (res) + termios_printf ("%d = tcgetattr (%d, %x)", res, fd, in_t); + else + termios_printf ("iflag %x, oflag %x, cflag %x, lflag %x, VMIN %d, VTIME %d", + t->c_iflag, t->c_oflag, t->c_cflag, t->c_lflag, t->c_cc[VMIN], + t->c_cc[VTIME]); + + return res; +} + +/* tcgetpgrp: POSIX 7.2.3.1 */ +extern "C" +int +tcgetpgrp (int fd) +{ + int res = -1; + + if (dtable.not_open (fd)) + set_errno (EBADF); + else if (!dtable[fd]->is_tty ()) + set_errno (ENOTTY); + else + res = dtable[fd]->tcgetpgrp (); + + termios_printf ("%d = tcgetpgrp (%d)", res, fd); + return res; +} + +/* tcsetpgrp: POSIX 7.2.4.1 */ +extern "C" +int +tcsetpgrp (int fd, pid_t pgid) +{ + int res = -1; + + if (dtable.not_open (fd)) + set_errno (EBADF); + else if (!dtable[fd]->is_tty ()) + set_errno (ENOTTY); + else + res = dtable[fd]->tcsetpgrp (pgid); + + termios_printf ("%d = tcsetpgrp (%d, %x)", res, fd, pgid); + return res; +} + +/* NIST PCTS requires not macro-only implementation */ +#undef cfgetospeed +#undef cfgetispeed +#undef cfsetospeed +#undef cfsetispeed + +/* cfgetospeed: POSIX96 7.1.3.1 */ +extern "C" +speed_t +cfgetospeed (struct termios *tp) +{ + return __tonew_termios(tp)->c_ospeed; +} + +/* cfgetispeed: POSIX96 7.1.3.1 */ +extern "C" +speed_t +cfgetispeed (struct termios *tp) +{ + return __tonew_termios(tp)->c_ispeed; +} + +/* cfsetospeed: POSIX96 7.1.3.1 */ +extern "C" +int +cfsetospeed (struct termios *in_tp, speed_t speed) +{ + struct termios *tp = __tonew_termios (in_tp); + tp->c_ospeed = speed; + (void) __toapp_termios (in_tp, tp); + return 0; +} + +/* cfsetispeed: POSIX96 7.1.3.1 */ +extern "C" +int +cfsetispeed (struct termios *in_tp, speed_t speed) +{ + struct termios *tp = __tonew_termios (in_tp); + tp->c_ispeed = speed; + (void) __toapp_termios (in_tp, tp); + return 0; +} diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc new file mode 100644 index 000000000..0ed42e7d8 --- /dev/null +++ b/winsup/cygwin/thread.cc @@ -0,0 +1,1001 @@ +/* thread.cc: Locking and threading module functions + + Copyright 1998, 2000 Cygnus Solutions. + + Written by Marco Fuykschot + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef _MT_SAFE +#include +#include "winsup.h" +#include + +#include +#include + +extern int threadsafe; + +#define MT_INTERFACE user_data->threadinterface + +#define NOT_IMP(n) system_printf("not implemented %s\n",n); return 0; + +#define CHECKHANDLE(rval,release) \ + if ( ! item->HandleOke() ) { \ + if ( release ) item->used=false; \ + return rval; }; + +#define GETTHREAD(n) \ + if ( ! thread ) system_printf("thread is NULL");\ + SetResourceLock(LOCK_THREAD_LIST,READ_LOCK,n);\ + ThreadItem *item=user_data->threadinterface->GetThread(thread); \ + ReleaseResourceLock(LOCK_THREAD_LIST,READ_LOCK,n); \ + if ( ! item ) return EINVAL; \ + CHECKHANDLE(EINVAL,0); + +#define GETMUTEX(n) \ + SetResourceLock(LOCK_MUTEX_LIST,READ_LOCK,n); \ + MutexItem* item=user_data->threadinterface->GetMutex(mutex); \ + ReleaseResourceLock(LOCK_MUTEX_LIST,READ_LOCK,n); \ + if ( ! item ) return EINVAL; \ + CHECKHANDLE(EINVAL,0); + +#define GETSEMA(n) \ + SetResourceLock(LOCK_SEM_LIST,READ_LOCK,n); \ + SemaphoreItem* item=user_data->threadinterface->GetSemaphore(sem); \ + ReleaseResourceLock(LOCK_SEM_LIST,READ_LOCK,n); \ + if ( ! item ) return EINVAL; \ + CHECKHANDLE(EINVAL,0); + +#define CHECKITEM(rn,rm,fn) \ + if ( ! item ) { \ + ReleaseResourceLock(rn,rm,fn); \ + return EINVAL; }; \ + +struct _reent * +_reent_clib () +{ + int tmp = GetLastError (); + struct __reent_t *_r = (struct __reent_t *) TlsGetValue (MT_INTERFACE->reent_index); + +#ifdef _CYG_THREAD_FAILSAFE + if (_r == 0) + { + system_printf ("local thread storage not inited"); + } +#endif + + SetLastError (tmp); + return _r->_clib; +}; + +struct _winsup_t * +_reent_winsup () +{ + int tmp = GetLastError (); + struct __reent_t *_r; + _r = (struct __reent_t *) TlsGetValue (MT_INTERFACE->reent_index); +#ifdef _CYG_THREAD_FAILSAFE + if (_r == 0) + { + system_printf ("local thread storage not inited"); + } +#endif + SetLastError (tmp); + return _r->_winsup; +}; + +void +SetResourceLock (int _res_id, int _mode, const char *_function) +{ +#if 0 + if (!threadsafe) + return; +#endif + thread_printf ("Set resource lock %d mode %d for %s start", _res_id, _mode, _function); + EnterCriticalSection (user_data->resourcelocks->Lock (_res_id)); + +#ifdef _CYG_THREAD_FAILSAFE + user_data->resourcelocks->owner = GetCurrentThreadId (); + user_data->resourcelocks->count++; +#endif +} + +void +ReleaseResourceLock (int _res_id, int _mode, const char *_function) +{ +#if 0 + if (!threadsafe) + return; +#endif + thread_printf ("Release resource lock %d mode %d for %s done", _res_id, _mode, _function); + +#ifdef _CYG_THREAD_FAILSAFE + AssertResourceOwner (_res_id, _mode); + user_data->resourcelocks->count--; + if (user_data->resourcelocks->count == 0) + user_data->resourcelocks->owner = 0; +#endif + + LeaveCriticalSection (user_data->resourcelocks->Lock (_res_id)); +}; + +#ifdef _CYG_THREAD_FAILSAFE +void +AssertResourceOwner (int _res_id, int _mode) +{ + + thread_printf ("Assert Resource lock %d ==> for %p , real : %d , threadid %d count %d owner %d", _res_id, user_data, (myself ? myself->pid : -1), GetCurrentThreadId (), user_data->resourcelocks->count, user_data->resourcelocks->owner); + if (user_data && (user_data->resourcelocks->owner != GetCurrentThreadId ())) + { + system_printf ("assertion failed, not the resource owner"); + }; +} + +#endif + +LPCRITICAL_SECTION +ResourceLocks::Lock (int _resid) +{ + if (!inited) + { + system_printf ("lock called before initialization"); + }; + + thread_printf ("Get Resource lock %d ==> %p for %p , real : %d , threadid %d ", _resid, &lock, user_data, (myself ? myself->pid : -1), GetCurrentThreadId ()); + return &lock; +}; + +void +ResourceLocks::Init () +{ + thread_printf ("Init resource lock %p -> %p", this, &lock); + + InitializeCriticalSection (&lock); + inited = true; + +#ifdef _CYG_THREAD_FAILSAFE + owner = 0; + count = 0; +#endif + + thread_printf ("Resource lock %p inited by %p , %d", &lock, user_data, (myself ? myself->pid : -1)); +}; + +void +ResourceLocks::Delete () +{ + if (inited) + { + thread_printf ("Close Resource Locks %p ", &lock); + DeleteCriticalSection (&lock); + inited = false; + }; +}; + + +// Thread interface + +void +MTinterface::ReleaseItem (MTitem * _item) +{ + _item->used = false; +}; + +MTitem * +MTinterface::Find (void *_value, int (*comp) (void *, void *), register int &_index, MTList * _list) +{ + register MTitem *current = NULL; + for (; _index < _list->index; _index++) + { + current = _list->items[_index]; + if (current->used && comp (current, _value)) + break; + current = NULL; + }; + return current; +}; + +int +MTinterface::Find (MTitem & _item, MTList * _list) +{ + register MTitem *current; + register int _index = 0; + for (; _index < _list->index; _index++) + { + current = _list->items[_index]; + if (current->used && current == &_item) + break; + }; + return (_index == _list->index ? -1 : _index); +}; + +int +MTinterface::FindNextUnused (MTList * _list) +{ + register int i = 0; + for (; i < _list->index && _list->items[i] != NULL && _list->items[i]->used && _list->items[i]->joinable != 'Y'; i++); + return i; +}; + +MTitem * +MTinterface::GetItem (int _index, MTList * _list) +{ + return (_index < _list->index ? _list->items[_index] : NULL); +}; + +MTitem * +MTinterface::SetItem (int _index, MTitem * _item, MTList * _list) +{ + if (_index == _list->index && _list->index < MT_MAX_ITEMS) + _list->index++; + return (_index < _list->index ? _list->items[_index] = _item : NULL); +}; + +int +CmpPthreadObj (void *_i, void *_value) +{ + return ((MTitem *) _i)->Id () == *(int *) _value; +}; + +int +CmpThreadId (void *_i, void *_id) +{ + return ((ThreadItem *) _i)->thread_id == *(DWORD *) _id; +}; + +void +MTinterface::Init0 () +{ + for (int i = 0; i < MT_MAX_ITEMS; i++) + { + threadlist.items[i] = NULL; + mutexlist.items[i] = NULL; + semalist.items[i] = NULL; + }; + + threadlist.index = 0; + mutexlist.index = 0; + semalist.index = 0; + + reent_index = TlsAlloc (); + + reents._clib = _impure_ptr; + reents._winsup = &winsup_reent; + + winsup_reent._process_logmask = LOG_UPTO (LOG_DEBUG); + winsup_reent._grp_pos = 0; + winsup_reent._process_ident = 0; + winsup_reent._process_logopt = 0; + winsup_reent._process_facility = 0; + + TlsSetValue (reent_index, &reents); + // the static reent_data will be used in the main thread + +}; + +void +MTinterface::Init1 () +{ + // create entry for main thread + + int i = FindNextUnused (&threadlist); + assert (i == 0); + ThreadItem *item = (ThreadItem *) GetItem (i, &threadlist); + + item = (ThreadItem *) SetItem (i, &mainthread, &threadlist); + item->used = true; + item->win32_obj_id = myself->hProcess; + item->thread_id = GetCurrentThreadId (); + item->function = NULL; + + item->sigs = NULL; + item->sigmask = NULL; + item->sigtodo = NULL; +}; + +void +MTinterface::ClearReent () +{ + struct _reent *r = _REENT; + memset (r, 0, sizeof (struct _reent)); + + r->_errno = 0; + r->_stdin = &r->__sf[0]; + r->_stdout = &r->__sf[1]; + r->_stderr = &r->__sf[2]; + +}; + + +ThreadItem * +MTinterface::CreateThread (pthread_t * t, TFD (func), void *arg, pthread_attr_t a) +{ + AssertResourceOwner (LOCK_THREAD_LIST, WRITE_LOCK | READ_LOCK); + + int i = FindNextUnused (&threadlist); + + ThreadItem *item = (ThreadItem *) GetItem (i, &threadlist); + if (!item) + item = (ThreadItem *) SetItem (i, new ThreadItem (), &threadlist); + if (!item) + system_printf ("thread creation failed"); + + item->used = true; + item->function = func; + item->arg = arg; + item->attr = a; + + item->win32_obj_id = ::CreateThread (&sec_none_nih, item->attr.stacksize, + (LPTHREAD_START_ROUTINE) thread_init_wrapper, item, 0, &item->thread_id); + + CHECKHANDLE (NULL, 1); + + *t = (pthread_t) item->win32_obj_id; + + return item; +}; + + +MutexItem * +MTinterface::CreateMutex (pthread_mutex_t * mutex) +{ + AssertResourceOwner (LOCK_MUTEX_LIST, WRITE_LOCK | READ_LOCK); + + int i = FindNextUnused (&mutexlist); + + MutexItem *item = (MutexItem *) GetItem (i, &mutexlist); + if (!item) + item = (MutexItem *) SetItem (i, new MutexItem (), &mutexlist); + if (!item) + system_printf ("mutex creation failed"); + item->used = true; + + item->win32_obj_id = ::CreateMutex (&sec_none_nih, false, NULL); + + CHECKHANDLE (NULL, 1); + + *mutex = (pthread_mutex_t) item->win32_obj_id; + + return item; +} + +ThreadItem * +MTinterface::GetCallingThread () +{ + AssertResourceOwner (LOCK_THREAD_LIST, READ_LOCK); + DWORD id = GetCurrentThreadId (); + int index = 0; + return (ThreadItem *) Find (&id, &CmpThreadId, index, &threadlist); +}; + +ThreadItem * +MTinterface::GetThread (pthread_t * _t) +{ + AssertResourceOwner (LOCK_THREAD_LIST, READ_LOCK); + int index = 0; + return (ThreadItem *) Find (_t, &CmpPthreadObj, index, &threadlist); +}; + +MutexItem * +MTinterface::GetMutex (pthread_mutex_t * mp) +{ + AssertResourceOwner (LOCK_MUTEX_LIST, READ_LOCK); + int index = 0; + return (MutexItem *) Find (mp, &CmpPthreadObj, index, &mutexlist); +} + +SemaphoreItem * +MTinterface::GetSemaphore (sem_t * sp) +{ + AssertResourceOwner (LOCK_SEM_LIST, READ_LOCK); + int index = 0; + return (SemaphoreItem *) Find (sp, &CmpPthreadObj, index, &semalist); +} + + +void +MTitem::Destroy () +{ + CloseHandle (win32_obj_id); +}; + +int +MutexItem::Lock () +{ + return WaitForSingleObject (win32_obj_id, INFINITE); +}; + +int +MutexItem::TryLock () +{ + return WaitForSingleObject (win32_obj_id, 0); +}; + +int +MutexItem::UnLock () +{ + return ReleaseMutex (win32_obj_id); +} + +SemaphoreItem * +MTinterface::CreateSemaphore (sem_t * _s, int pshared, int _v) +{ + AssertResourceOwner (LOCK_SEM_LIST, WRITE_LOCK | READ_LOCK); + + int i = FindNextUnused (&semalist); + + SemaphoreItem *item = (SemaphoreItem *) GetItem (i, &semalist); + if (!item) + item = (SemaphoreItem *) SetItem (i, new SemaphoreItem (), &semalist); + if (!item) + system_printf ("semaphore creation failed"); + item->used = true; + item->shared = pshared; + + item->win32_obj_id = ::CreateSemaphore (&sec_none_nih, _v, _v, NULL); + + CHECKHANDLE (NULL, 1); + + *_s = (sem_t) item->win32_obj_id; + + return item; +}; + +int +SemaphoreItem::Wait () +{ + return WaitForSingleObject (win32_obj_id, INFINITE); +}; + +int +SemaphoreItem::Post () +{ + long pc; + return ReleaseSemaphore (win32_obj_id, 1, &pc); +}; + +int +SemaphoreItem::TryWait () +{ + return WaitForSingleObject (win32_obj_id, 0); +}; + + +////////////////////////// Pthreads + +void * +thread_init_wrapper (void *_arg) +{ +// Setup the local/global storage of this thread + + ThreadItem *thread = (ThreadItem *) _arg; + struct __reent_t local_reent; + struct _winsup_t local_winsup; + struct _reent local_clib; + + struct sigaction _sigs[NSIG]; + sigset_t _sig_mask; /* one set for everything to ignore. */ + LONG _sigtodo[NSIG + __SIGOFFSET]; + +// setup signal structures + thread->sigs = _sigs; + thread->sigmask = &_sig_mask; + thread->sigtodo = _sigtodo; + + memset (&local_clib, 0, sizeof (struct _reent)); + memset (&local_winsup, 0, sizeof (struct _winsup_t)); + + local_clib._errno = 0; + local_clib._stdin = &local_clib.__sf[0]; + local_clib._stdout = &local_clib.__sf[1]; + local_clib._stderr = &local_clib.__sf[2]; + + local_reent._clib = &local_clib; + local_reent._winsup = &local_winsup; + + local_winsup._process_logmask = LOG_UPTO (LOG_DEBUG); + + + if (!TlsSetValue (MT_INTERFACE->reent_index, &local_reent)) + system_printf ("local storage for thread couldn't be set"); + +#ifdef _CYG_THREAD_FAILSAFE + if (_REENT == _impure_ptr) + system_printf ("local storage for thread isn't setup correctly"); +#endif + + + thread_printf ("started thread %p %p %p %p %p %p", _arg, &local_clib, _impure_ptr, thread, thread->function, thread->arg); + + +// call the user's thread + void *ret = thread->function (thread->arg); + +// FIX ME : cleanup code + +// thread->used = false; // release thread entry + thread->return_ptr = ret; + return ret; +} + +int +__pthread_create (pthread_t * thread, const pthread_attr_t * attr, TFD (start_routine), void *arg) +{ + SetResourceLock (LOCK_THREAD_LIST, WRITE_LOCK | READ_LOCK, "__pthread_create"); + + pthread_attr_t a; + ThreadItem *item; + + if (attr) + item = MT_INTERFACE->CreateThread (thread, start_routine, arg, *attr); + else + { + __pthread_attr_init (&a); + item = MT_INTERFACE->CreateThread (thread, start_routine, arg, a); + }; + + + + CHECKITEM (LOCK_THREAD_LIST, WRITE_LOCK | READ_LOCK, "__pthread_create") + + ReleaseResourceLock (LOCK_THREAD_LIST, WRITE_LOCK | READ_LOCK, "__pthread_create"); + return 0; +}; + +int +__pthread_attr_init (pthread_attr_t * attr) +{ + attr->stacksize = 0; + return 0; +}; + +int +__pthread_attr_setstacksize (pthread_attr_t * attr, size_t size) +{ + attr->stacksize = size; + return 0; +}; + +int +__pthread_attr_getstacksize (pthread_attr_t * attr, size_t * size) +{ + *size = attr->stacksize; + return 0; +}; + +int +__pthread_attr_destroy (pthread_attr_t * attr) +{ + return 0; +}; + +int +__pthread_exit (void *value_ptr) +{ + ThreadItem *item = MT_INTERFACE->GetCallingThread(); + item->return_ptr = value_ptr; + ExitThread(0); + return 0; +} + +int +__pthread_join(pthread_t * thread, void **return_val) +{ + ThreadItem *item=user_data->threadinterface->GetThread(thread); + + + if (!item) + return ESRCH; + + if (item->joinable == 'N') + { + if (return_val) + *return_val = NULL; + return EINVAL; + } + else + { + item->joinable = 'N'; + WaitForSingleObject((HANDLE)*thread, INFINITE); + if (return_val) + *return_val = item->return_ptr; + }/* End if*/ + + return 0; +}; + +int +__pthread_detach(pthread_t * thread) +{ + ThreadItem *item=user_data->threadinterface->GetThread(thread); + if (!item) + return ESRCH; + + if (item->joinable == 'N') + { + item->return_ptr = NULL; + return EINVAL; + } + + item->joinable = 'N'; + return 0; +} + +int +__pthread_suspend(pthread_t * thread) +{ + ThreadItem *item=user_data->threadinterface->GetThread(thread); + if (!item) + return ESRCH; + + if (item->suspended == false) + { + item->suspended = true; + SuspendThread( (HANDLE)*thread); + } + + return 0; +} + + +int +__pthread_continue(pthread_t * thread) +{ + ThreadItem *item=user_data->threadinterface->GetThread(thread); + if (!item) + return ESRCH; + + if (item->suspended == true) + ResumeThread( (HANDLE)*thread); + item->suspended = false; + + return 0; +} + + + + +unsigned long +__pthread_getsequence_np (pthread_t * thread) +{ + GETTHREAD ("__pthread_getsequence_np"); + return item->GetThreadId (); +}; + +/* Thread SpecificData */ +int +__pthread_key_create (pthread_key_t * key) +{ + NOT_IMP ("_p_key_create\n"); +}; + +int +__pthread_key_delete (pthread_key_t * key) +{ + NOT_IMP ("_p_key_delete\n"); +}; +int +__pthread_setspecific (pthread_key_t * key, const void *value) +{ + NOT_IMP ("_p_key_setsp\n"); +}; +void * +__pthread_getspecific (pthread_key_t * key) +{ + NOT_IMP ("_p_key_getsp\n"); +}; + +/* Thread signal */ +int +__pthread_kill (pthread_t * thread, int sig) +{ +// lock myself, for the use of thread2signal + // two differ kills might clash: FIX ME + GETTHREAD ("__pthread_kill"); + + if (item->sigs) + myself->setthread2signal (item); + + int rval = sig_send (myself, sig); + +// unlock myself + return rval; + +}; + +int +__pthread_sigmask (int operation, const sigset_t * set, sigset_t * old_set) +{ + SetResourceLock (LOCK_THREAD_LIST, READ_LOCK, "__pthread_sigmask"); + ThreadItem *item = MT_INTERFACE->GetCallingThread (); + ReleaseResourceLock (LOCK_THREAD_LIST, READ_LOCK, "__pthread_sigmask"); + +// lock this myself, for the use of thread2signal + // two differt kills might clash: FIX ME + + if (item->sigs) + myself->setthread2signal (item); + + int rval = sigprocmask (operation, set, old_set); + +// unlock this myself + + return rval; +}; + +/* ID */ +pthread_t +__pthread_self () +{ + SetResourceLock (LOCK_THREAD_LIST, READ_LOCK, "__pthread_self"); + + ThreadItem *item = MT_INTERFACE->GetCallingThread (); + + ReleaseResourceLock (LOCK_THREAD_LIST, READ_LOCK, "__pthread_self"); + return (pthread_t) item->Id (); + +}; + +int +__pthread_equal (pthread_t * t1, pthread_t * t2) +{ + return (*t1 - *t2); +}; + +/* Mutexes */ + +int +__pthread_mutex_init (pthread_mutex_t * mutex, const pthread_mutexattr_t * _attr) +{ + SetResourceLock (LOCK_MUTEX_LIST, WRITE_LOCK | READ_LOCK, "__pthread_mutex_init"); + + MutexItem *item = MT_INTERFACE->CreateMutex (mutex); + + CHECKITEM (LOCK_MUTEX_LIST, WRITE_LOCK | READ_LOCK, "__pthread_mutex_init"); + + ReleaseResourceLock (LOCK_MUTEX_LIST, WRITE_LOCK | READ_LOCK, "__pthread_mutex_init"); + return 0; +}; + +int +__pthread_mutex_lock (pthread_mutex_t * mutex) +{ + GETMUTEX ("_ptherad_mutex_lock"); + + item->Lock (); + + return 0; +}; + +int +__pthread_mutex_trylock (pthread_mutex_t * mutex) +{ + GETMUTEX ("_ptherad_mutex_lock"); + + if (item->TryLock () == WAIT_TIMEOUT) + return EBUSY; + + return 0; +}; + +int +__pthread_mutex_unlock (pthread_mutex_t * mutex) +{ + GETMUTEX ("_ptherad_mutex_lock"); + + item->UnLock (); + + return 0; +}; + +int +__pthread_mutex_destroy (pthread_mutex_t * mutex) +{ + SetResourceLock (LOCK_MUTEX_LIST, READ_LOCK | WRITE_LOCK, "__pthread_mutex_destroy"); + + MutexItem *item = MT_INTERFACE->GetMutex (mutex); + + CHECKITEM (LOCK_MUTEX_LIST, WRITE_LOCK | READ_LOCK, "__pthread_mutex_init"); + + item->Destroy (); + + MT_INTERFACE->ReleaseItem (item); + + ReleaseResourceLock (LOCK_MUTEX_LIST, READ_LOCK | WRITE_LOCK, "__pthread_mutex_destroy"); + return 0; +}; + +/* Semaphores */ +int +__sem_init (sem_t * sem, int pshared, unsigned int value) +{ + SetResourceLock (LOCK_SEM_LIST, READ_LOCK | WRITE_LOCK, "__sem_init"); + + SemaphoreItem *item = MT_INTERFACE->CreateSemaphore (sem, pshared, value); + + CHECKITEM (LOCK_SEM_LIST, READ_LOCK | WRITE_LOCK, "__sem_init"); + + ReleaseResourceLock (LOCK_SEM_LIST, READ_LOCK | WRITE_LOCK, "__sem_init"); + return 0; +}; + +int +__sem_destroy (sem_t * sem) +{ + SetResourceLock (LOCK_SEM_LIST, READ_LOCK | WRITE_LOCK, "__sem_destroy"); + + SemaphoreItem *item = MT_INTERFACE->GetSemaphore (sem); + + CHECKITEM (LOCK_SEM_LIST, READ_LOCK | WRITE_LOCK, "__sem_init"); + + item->Destroy (); + + MT_INTERFACE->ReleaseItem (item); + + ReleaseResourceLock (LOCK_SEM_LIST, READ_LOCK | WRITE_LOCK, "__sem_destroy"); + return 0; +}; + +int +__sem_wait (sem_t * sem) +{ + GETSEMA ("__sem_wait"); + + item->Wait (); + + return 0; +}; + +int +__sem_trywait (sem_t * sem) +{ + GETSEMA ("__sem_trywait"); + + if (item->TryWait () == WAIT_TIMEOUT) + return EAGAIN; + + return 0; +}; + +int +__sem_post (sem_t * sem) +{ + GETSEMA ("__sem_post"); + + item->Post (); + + return 0; +}; + + +#else + +// empty functions needed when makeing the dll without mt_safe support +extern "C" +{ + int __pthread_create (pthread_t *, const pthread_attr_t *, TFD (start_routine), void *arg) + { + return -1; + }; + int __pthread_attr_init (pthread_attr_t * attr) + { + return -1; + }; + int __pthread_attr_destroy (pthread_attr_t * attr) + { + return -1; + }; + int __pthread_attr_setstacksize (pthread_attr_t * attr, size_t size) + { + return -1; + }; + int __pthread_attr_getstacksize (pthread_attr_t * attr, size_t * size) + { + return -1; + }; +/* + __pthread_attr_setstackaddr(...){ return -1; }; + __pthread_attr_getstackaddr(...){ return -1; }; + */ + int __pthread_exit (void *value_ptr) + { + return -1; + }; + + int __pthread_join(pthread_t thread_id, void **return_val) + { + return -1; + } + + unsigned long __pthread_getsequence_np (pthread_t * thread) + { + return 0; + }; + int __pthread_key_create (pthread_key_t * key) + { + return -1; + }; + int __pthread_key_delete (pthread_key_t * key) + { + return -1; + }; + int __pthread_setspecific (pthread_key_t * key, const void *value) + { + return -1; + }; + void *__pthread_getspecific (pthread_key_t * key) + { + return NULL; + }; + int __pthread_kill (pthread_t * thread, int sig) + { + return -1; + }; + int __pthread_sigmask (int operation, const sigset_t * set, sigset_t * old_set) + { + return -1; + }; + pthread_t __pthread_self () + { + return -1; + }; + int __pthread_equal (pthread_t * t1, pthread_t * t2) + { + return -1; + }; + int __pthread_mutex_init (pthread_mutex_t *, const pthread_mutexattr_t *) + { + return -1; + }; + int __pthread_mutex_lock (pthread_mutex_t *) + { + return -1; + }; + int __pthread_mutex_trylock (pthread_mutex_t *) + { + return -1; + }; + int __pthread_mutex_unlock (pthread_mutex_t *) + { + return -1; + }; + int __pthread_mutex_destroy (pthread_mutex_t *) + { + return -1; + }; + int __sem_init (sem_t * sem, int pshared, unsigned int value) + { + return -1; + }; + int __sem_destroy (sem_t * sem) + { + return -1; + }; + int __sem_wait (sem_t * sem) + { + return -1; + }; + int __sem_trywait (sem_t * sem) + { + return -1; + }; + int __sem_post (sem_t * sem) + { + return -1; + }; + struct _reent *_reent_clib () + { + return NULL; + }; +} + +#endif // MT_SAFE diff --git a/winsup/cygwin/thread.h b/winsup/cygwin/thread.h new file mode 100644 index 000000000..9aca0c61a --- /dev/null +++ b/winsup/cygwin/thread.h @@ -0,0 +1,312 @@ +/* thread.h: Locking and threading module definitions + + Copyright 1998, 1999 Cygnus Solutions. + + Written by Marco Fuykschot + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#ifndef _CYGNUS_THREADS_ +#define _CYGNUS_THREADS_ + +#define LOCK_FD_LIST 1 +#define LOCK_MEMORY_LIST 2 +#define LOCK_MMAP_LIST 3 +#define LOCK_DLL_LIST 4 +#define LOCK_THREAD_LIST 5 +#define LOCK_MUTEX_LIST 6 +#define LOCK_SEM_LIST 7 + +#define WRITE_LOCK 1 +#define READ_LOCK 2 + +extern "C" +{ +#if defined (_CYG_THREAD_FAILSAFE) && defined (_MT_SAFE) + void AssertResourceOwner (int, int); +#else +#define AssertResourceOwner(i,ii) +#endif +} + +#ifndef _MT_SAFE + +#define SetResourceLock(i,n,c) +#define ReleaseResourceLock(i,n,c) + +#else + +#include +#include +#include +#include +#include +#include + +extern "C" { + +struct _winsup_t +{ +/* + Needed for the group functions +*/ + struct group _grp; + char *_namearray[2]; + char _linebuf[100]; + int _grp_pos; + +/* console.cc */ + unsigned _rarg; + char _my_title_buf[TITLESIZE + 1]; + +/* dlfcn.cc */ + int _dl_error; + char _dl_buffer[256]; + +/* passwd.cc */ + struct passwd _res; + char _tmpbuf[100]; + char _pass[_PASSWORD_LEN]; + int _pw_pos; + +/* path.cc */ + struct mntent _ret; + char *_current_directory_name; + char *_current_directory_posix_name; + unsigned long _current_directory_hash; + int _iteration; + +/* strerror */ + char _strerror_buf[20]; + +/* syscalls.cc */ + char _dacl_buf[1024]; + char _sacl_buf[1024]; + char _ownr_buf[1024]; + char _grp_buf[1024]; + +/* sysloc.cc */ + char *_process_ident; + int _process_logopt; + int _process_facility; + int _process_logmask; + +/* times.cc */ + char _b[20]; + struct tm _localtime_buf; + char _buf1[33]; + char _buf2[33]; + +/* uinfo.cc */ + char _username[MAX_USER_NAME]; +}; + + +struct __reent_t +{ + struct _reent *_clib; + struct _winsup_t *_winsup; +}; + +_reent *_reent_clib (); +_winsup_t *_reent_winsup (); +void SetResourceLock (int, int, const char *); +void ReleaseResourceLock (int, int, const char *); + +#ifdef _CYG_THREAD_FAILSAFE +void AssertResourceOwner (int, int); +#else +#define AssertResourceOwner(i,ii) +#endif +} + +class per_process; +class pinfo; + +class ResourceLocks +{ +public: +ResourceLocks ():inited (false) {}; +LPCRITICAL_SECTION Lock (int); +void Init (); +void Delete (); +#ifdef _CYG_THREAD_FAILSAFE +DWORD owner; +DWORD count; +#endif +private: +CRITICAL_SECTION lock; +bool inited; +}; + + +#define MT_MAX_ITEMS 128 + +// thread classes\lists + +class MTitem +{ +public: +HANDLE win32_obj_id; +UINT return_value; +bool used; +char joinable; // for thread only +bool HandleOke () {return win32_obj_id;}; +virtual void Destroy (); +virtual int Id () {return (int) win32_obj_id;}; +}; + +class ThreadItem:public MTitem +{ +public: +pthread_attr_t attr; +TFD (function); +void *arg; +void *return_ptr; +bool suspended; +DWORD thread_id; +DWORD GetThreadId () {return thread_id;}; + +/* signal handling */ +struct sigaction *sigs; +sigset_t *sigmask; +LONG *sigtodo; +}; + +class MutexItem:public MTitem +{ +public: +int Lock (); +int TryLock (); +int UnLock (); +}; + +class SemaphoreItem:public MTitem +{ +public: +int shared; +int Wait (); +int Post (); +int TryWait (); +}; + + +typedef struct +{ +MTitem *items[MT_MAX_ITEMS]; +int index; +} +MTList; + +class MTinterface +{ +public: +// General +DWORD reent_index; +DWORD thread_key; + +// Used for main thread data, and sigproc thread +struct __reent_t reents; +struct _winsup_t winsup_reent; +ThreadItem mainthread; + +void Init0 (); +void Init1 (); +void ClearReent (); + +void ReleaseItem (MTitem *); + +// Thread functions +ThreadItem *CreateThread (pthread_t *, TFD (func), void *, pthread_attr_t); +ThreadItem *GetCallingThread (); +ThreadItem *GetThread (pthread_t *); + +// Mutex functions +MutexItem *CreateMutex (pthread_mutex_t *); +MutexItem *GetMutex (pthread_mutex_t *); + +// Semaphore functions +SemaphoreItem *CreateSemaphore (sem_t *, int, int); +SemaphoreItem *GetSemaphore (sem_t * t); + +private: +// General Administration +MTitem * Find (void *, int (*compare) (void *, void *), int &, MTList *); +MTitem *GetItem (int, MTList *); +MTitem *SetItem (int, MTitem *, MTList *); +int Find (MTitem &, MTList *); +int FindNextUnused (MTList *); + +MTList threadlist; +MTList mutexlist; +MTList semalist; +}; + + +extern "C" +{ + +void *thread_init_wrapper (void *); + +/* ThreadCreation */ +int __pthread_create (pthread_t * thread, const pthread_attr_t * attr, TFD (start_routine), void *arg); +int __pthread_attr_init (pthread_attr_t * attr); +int __pthread_attr_destroy (pthread_attr_t * attr); +int __pthread_attr_setstacksize (pthread_attr_t * attr, size_t size); +int __pthread_attr_getstacksize (pthread_attr_t * attr, size_t * size); +/* +__pthread_attr_setstackaddr(...); +__pthread_attr_getstackaddr(...); +*/ + +/* Thread Exit */ +int __pthread_exit (void *value_ptr); +int __pthread_join(pthread_t *thread, void **return_val); +int __pthread_detach(pthread_t *thread); + +/* Thread suspend */ + +int __pthread_suspend(pthread_t *thread); +int __pthread_continue(pthread_t *thread); + +unsigned long __pthread_getsequence_np (pthread_t * thread); + +/* Thread SpecificData */ +int __pthread_key_create (pthread_key_t * key); +int __pthread_key_delete (pthread_key_t * key); +int __pthread_setspecific (pthread_key_t * key, const void *value); +void *__pthread_getspecific (pthread_key_t * key); + + +/* Thread signal */ +int __pthread_kill (pthread_t * thread, int sig); +int __pthread_sigmask (int operation, const sigset_t * set, sigset_t * old_set); + +/* ID */ +pthread_t __pthread_self (); +int __pthread_equal (pthread_t * t1, pthread_t * t2); + + +/* Mutexes */ +int __pthread_mutex_init (pthread_mutex_t *, const pthread_mutexattr_t *); +int __pthread_mutex_lock (pthread_mutex_t *); +int __pthread_mutex_trylock (pthread_mutex_t *); +int __pthread_mutex_unlock (pthread_mutex_t *); +int __pthread_mutex_destroy (pthread_mutex_t *); + +/* Semaphores */ +int __sem_init (sem_t * sem, int pshared, unsigned int value); +int __sem_destroy (sem_t * sem); +int __sem_wait (sem_t * sem); +int __sem_trywait (sem_t * sem); +int __sem_post (sem_t * sem); + +}; + +#endif // MT_SAFE + +#endif // _CYGNUS_THREADS_ diff --git a/winsup/cygwin/times.cc b/winsup/cygwin/times.cc new file mode 100644 index 000000000..6ee283b5c --- /dev/null +++ b/winsup/cygwin/times.cc @@ -0,0 +1,540 @@ +/* times.cc + + Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include +#include +#include +#include +#include "winsup.h" + +extern time_t __declspec(dllexport) _timezone; +extern int __declspec(dllexport) _daylight; + +#define FACTOR (0x19db1ded53ea710LL) +#define NSPERSEC 10000000LL + +static void __stdcall timeval_to_filetime (timeval *time, FILETIME *out); + +/* Cygwin internal */ +static unsigned long long __stdcall +__to_clock_t (FILETIME * src, int flag) +{ + unsigned long long total = ((unsigned long long) src->dwHighDateTime << 32) + ((unsigned)src->dwLowDateTime); + syscall_printf ("dwHighDateTime %u, dwLowDateTime %u", src->dwHighDateTime, src->dwLowDateTime); + + /* Convert into clock ticks - the total is in 10ths of a usec. */ + if (flag) + total -= FACTOR; + + total /= (unsigned long long) (NSPERSEC / CLOCKS_PER_SEC); + syscall_printf ("total %08x %08x\n", (unsigned)(total>>32), (unsigned)(total)); + return total; +} + +/* times: POSIX 4.5.2.1 */ +extern "C" clock_t +times (struct tms * buf) +{ + FILETIME creation_time, exit_time, kernel_time, user_time; + + DWORD ticks = GetTickCount (); + /* Ticks is in milliseconds, convert to our ticks. Use long long to prevent + overflow. */ + clock_t tc = (clock_t) ((long long) ticks * CLOCKS_PER_SEC / 1000); + if (os_being_run == winNT) + { + GetProcessTimes (hMainProc, &creation_time, &exit_time, + &kernel_time, &user_time); + + syscall_printf ("ticks %d, CLOCKS_PER_SEC %d", ticks, CLOCKS_PER_SEC); + syscall_printf ("user_time %d, kernel_time %d, creation_time %d, exit_time %d", + user_time, kernel_time, creation_time, exit_time); + buf->tms_stime = __to_clock_t (&kernel_time, 0); + buf->tms_utime = __to_clock_t (&user_time, 0); + timeval_to_filetime (&myself->rusage_children.ru_stime, &kernel_time); + buf->tms_cstime = __to_clock_t (&kernel_time, 1); + timeval_to_filetime (&myself->rusage_children.ru_utime, &user_time); + buf->tms_cutime = __to_clock_t (&user_time, 1); + } + else + /* GetProcessTimes() does not work for non-NT versions of Windows. The + return values are undefined, so instead just copy the ticks value + into utime so that clock() will work properly on these systems */ + { + buf->tms_utime = tc; + buf->tms_stime = 0; + buf->tms_cstime = 0; + buf->tms_cutime = 0; + } + + return tc; +} + +extern "C" clock_t +_times (struct tms * buf) +{ + return times (buf); +} + +/* settimeofday: BSD */ +extern "C" int +settimeofday (const struct timeval *, const struct timezone *) +{ + set_errno (ENOSYS); + return -1; +} + +/* timezone: standards? */ +extern "C" char * +timezone () +{ +#ifdef _MT_SAFE + char *b=_reent_winsup()->_b; +#else + static NO_COPY char b[20] = {0}; +#endif + + tzset(); + __small_sprintf (b,"GMT%+d:%02d", (int) (-_timezone / 3600), (int) (abs(_timezone / 60) % 60)); + return b; +} + +/* Cygwin internal */ +void __stdcall +totimeval (struct timeval *dst, FILETIME *src, int sub, int flag) +{ + long long x = __to_clock_t (src, flag); + + x *= (int) (1e6) / CLOCKS_PER_SEC; /* Turn x into usecs */ + x -= (long long) sub * (int) (1e6); + + dst->tv_usec = x % (long long) (1e6); /* And split */ + dst->tv_sec = x / (long long) (1e6); +} + +/* gettimeofday: BSD */ +extern "C" int +gettimeofday (struct timeval *p, struct timezone *z) +{ + int res = 0; + + if (p != NULL) + { + SYSTEMTIME t; + FILETIME f; + + GetSystemTime (&t); + if (! SystemTimeToFileTime (&t, &f)) + res = -1; + totimeval (p, &f, 0, 1); + } + + if (z != NULL) + { + tzset(); + z->tz_minuteswest = _timezone / 60; + z->tz_dsttime = _daylight; + } + + syscall_printf ("%d = gettimeofday (%x, %x)", res, p, z); + + return res; +} + +extern "C" +int +_gettimeofday (struct timeval *p, struct timezone *z) +{ + return gettimeofday (p, z); +} + +#if 0 +/* Work out magic constant below */ +genf () +{ + SYSTEMTIME s; + FILETIME f; + s.wYear = 1970; + s.wMonth = 1; + s.wDayOfWeek = 5; + s.wDay = 1; + s.wHour = 0; + s.wMinute = 0; + s.wSecond = 0; + s.wMilliseconds = 1; + SystemTimeToFileTime (&s, &f); + + small_printf ("FILE TIME is %08x%08x\n", + f.dwHighDateTime, + f.dwLowDateTime); +} +#endif + +/* Cygwin internal */ +void +time_t_to_filetime (time_t time_in, FILETIME *out) +{ + long long x = time_in * NSPERSEC + FACTOR; + out->dwHighDateTime = x >> 32; + out->dwLowDateTime = x; +} + +/* Cygwin internal */ +static void __stdcall +timeval_to_filetime (timeval *time_in, FILETIME *out) +{ + long long x = time_in->tv_sec * NSPERSEC + + time_in->tv_usec * (NSPERSEC/1000000) + FACTOR; + out->dwHighDateTime = x >> 32; + out->dwLowDateTime = x; +} + +/* Cygwin internal */ +static timeval __stdcall +time_t_to_timeval (time_t in) +{ + timeval res; + res.tv_sec = in; + res.tv_usec = 0; + return res; +} + +/* Cygwin internal */ +/* Convert a Win32 time to "UNIX" format. */ +long __stdcall +to_time_t (FILETIME *ptr) +{ + /* A file time is the number of 100ns since jan 1 1601 + stuffed into two long words. + A time_t is the number of seconds since jan 1 1970. */ + + long rem; + long long x = ((long long) ptr->dwHighDateTime << 32) + ((unsigned)ptr->dwLowDateTime); + x -= FACTOR; /* number of 100ns between 1601 and 1970 */ + rem = x % ((long long)NSPERSEC); + rem += (NSPERSEC / 2); + x /= (long long) NSPERSEC; /* number of 100ns in a second */ + x += (long long) (rem / NSPERSEC); + return x; +} + +/* time: POSIX 4.5.1.1, C 4.12.2.4 */ +/* Return number of seconds since 00:00 UTC on jan 1, 1970 */ +extern "C" +time_t +time (time_t * ptr) +{ + time_t res; + SYSTEMTIME systemtime; + FILETIME filetime; + + GetSystemTime (&systemtime); + SystemTimeToFileTime (&systemtime, &filetime); + res = to_time_t (&filetime); + if (ptr) + *ptr = res; + + syscall_printf ("%d = time (%x)", res, ptr); + + return res; +} + +/* + * localtime_r.c + * Original Author: Adapted from tzcode maintained by Arthur David Olson. + * + * Converts the calendar time pointed to by tim_p into a broken-down time + * expressed as local time. Returns a pointer to a structure containing the + * broken-down time. + */ + +#define SECSPERMIN 60 +#define MINSPERHOUR 60 +#define HOURSPERDAY 24 +#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) +#define SECSPERDAY (SECSPERHOUR * HOURSPERDAY) +#define DAYSPERWEEK 7 +#define MONSPERYEAR 12 + +#define YEAR_BASE 1900 +#define EPOCH_YEAR 1970 +#define EPOCH_WDAY 4 + +#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) + +#if 0 /* POSIX_LOCALTIME */ + +static _CONST int mon_lengths[2][MONSPERYEAR] = { + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} +}; + +static _CONST int year_lengths[2] = { + 365, + 366 +}; + +/* + * Convert a time_t into a struct tm *. + * Does NO timezone conversion. + */ + +/* Cygwin internal */ +static struct tm * __stdcall +corelocaltime (const time_t * tim_p) +{ + long days, rem; + int y; + int yleap; + _CONST int *ip; +#ifdef _MT_SAFE + struct tm &localtime_buf=_reent_winsup()->_localtime_buf; +#else + static NO_COPY struct tm localtime_buf = {0}; +#endif + + time_t tim = *tim_p; + struct tm *res = &localtime_buf; + + days = ((long) tim) / SECSPERDAY; + rem = ((long) tim) % SECSPERDAY; + + while (rem < 0) + { + rem += SECSPERDAY; + --days; + } + while (rem >= SECSPERDAY) + { + rem -= SECSPERDAY; + ++days; + } + + /* compute hour, min, and sec */ + res->tm_hour = (int) (rem / SECSPERHOUR); + rem %= SECSPERHOUR; + res->tm_min = (int) (rem / SECSPERMIN); + res->tm_sec = (int) (rem % SECSPERMIN); + + /* compute day of week */ + if ((res->tm_wday = ((EPOCH_WDAY + days) % DAYSPERWEEK)) < 0) + res->tm_wday += DAYSPERWEEK; + + /* compute year & day of year */ + y = EPOCH_YEAR; + if (days >= 0) + { + for (;;) + { + yleap = isleap (y); + if (days < year_lengths[yleap]) + break; + y++; + days -= year_lengths[yleap]; + } + } + else + { + do + { + --y; + yleap = isleap (y); + days += year_lengths[yleap]; + } while (days < 0); + } + + res->tm_year = y - YEAR_BASE; + res->tm_yday = days; + ip = mon_lengths[yleap]; + for (res->tm_mon = 0; days >= ip[res->tm_mon]; ++res->tm_mon) + days -= ip[res->tm_mon]; + res->tm_mday = days + 1; + + /* set daylight saving time flag */ + res->tm_isdst = -1; + + syscall_printf ("%d = corelocaltime (%x)", res, tim_p); + + return (res); +} + +/* localtime: POSIX 8.1.1, C 4.12.3.4 */ +/* + * localtime takes a time_t (which is in UTC) + * and formats it into a struct tm as a local time. + */ +extern "C" +struct tm * +localtime (const time_t *tim_p) +{ + time_t tim = *tim_p; + struct tm *rtm; + + tzset(); + + tim -= _timezone; + + rtm = corelocaltime (&tim); + + rtm->tm_isdst = _daylight; + + syscall_printf ("%x = localtime (%x)", rtm, tim_p); + + return rtm; +} + +/* gmtime: C 4.12.3.3 */ +/* + * gmtime takes a time_t (which is already in UTC) + * and just puts it into a struct tm. + */ +extern "C" +struct tm * +gmtime (const time_t *tim_p) +{ + time_t tim = *tim_p; + + struct tm *rtm = corelocaltime (&tim); + /* UTC has no daylight savings time */ + rtm->tm_isdst = 0; + + syscall_printf ("%x = gmtime (%x)", rtm, tim_p); + + return rtm; +} + +#endif /* POSIX_LOCALTIME */ + +/* utimes: standards? */ +extern "C" +int +utimes (const char *path, struct timeval *tvp) +{ + int res = 0; + struct timeval tmp[2]; + path_conv win32 (path); + + if (win32.error) + { + set_errno (win32.error); + syscall_printf ("-1 = utimes (%s, %x)", path, tvp); + return -1; + } + + /* MSDN suggests using FILE_FLAG_BACKUP_SEMANTICS for accessing + the times of directories. FIXME: what about Win95??? */ + HANDLE h = CreateFileA (win32.get_win32 (), + GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + &sec_none_nih, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, + 0); + + if (h == INVALID_HANDLE_VALUE) + { + if ((res = GetFileAttributes (win32.get_win32 ())) != -1 && + (res & FILE_ATTRIBUTE_DIRECTORY)) + { + /* What we can do with directories more? */ + res = 0; + } + else + { + res = -1; + __seterrno (); + } + } + else + { + if (tvp == 0) + { + gettimeofday (&tmp[0], 0); + tmp[1] = tmp[0]; + tvp = tmp; + } + + FILETIME lastaccess; + FILETIME lastwrite; + + timeval_to_filetime (tvp + 0, &lastaccess); + timeval_to_filetime (tvp + 1, &lastwrite); + + debug_printf ("incoming lastaccess %08x %08x", + tvp->tv_sec, + tvp->tv_usec); + +// dump_filetime (lastaccess); +// dump_filetime (lastwrite); + + /* FIXME: SetFileTime needs a handle with a write lock + on the file whose time is being modified. So calls to utime() + fail for read only files. */ + + if (!SetFileTime (h, 0, &lastaccess, &lastwrite)) + { + __seterrno (); + res = -1; + } + else + res = 0; + CloseHandle (h); + } + + syscall_printf ("%d = utimes (%s, %x); (h%d)", + res, path, tvp, h); + return res; +} + +/* utime: POSIX 5.6.6.1 */ +extern "C" +int +utime (const char *path, struct utimbuf *buf) +{ + struct timeval tmp[2]; + + if (buf == 0) + return utimes (path, 0); + + debug_printf ("incoming utime act %x", buf->actime); + tmp[0] = time_t_to_timeval (buf->actime); + tmp[1] = time_t_to_timeval (buf->modtime); + + return utimes (path, tmp); +} + +/* ftime: standards? */ +extern "C" +int +ftime (struct timeb *tp) +{ + struct timeval tv; + struct timezone tz; + + if (gettimeofday (&tv, &tz) < 0) + return -1; + + tp->time = tv.tv_sec; + tp->millitm = tv.tv_usec / 1000; + tp->timezone = tz.tz_minuteswest; + tp->dstflag = tz.tz_dsttime; + + return 0; +} + +/* obsolete, changed to cygwin_tzset when localtime.c was added - dj */ +extern "C" +void +cygwin_tzset () +{ +} diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc new file mode 100644 index 000000000..ef9bec5a3 --- /dev/null +++ b/winsup/cygwin/tty.cc @@ -0,0 +1,417 @@ +/* tty.cc + + Copyright 1997, 1998, 2000 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include +#include "winsup.h" + +extern fhandler_tty_master *tty_master; + +extern "C" +int +grantpt (void) +{ + return 0; +} + +extern "C" +int +unlockpt (void) +{ + return 0; +} + +extern "C" +int +ttyslot (void) +{ + if (NOTSTATE (myself, PID_USETTY)) + return -1; + return myself->ctty; +} + +void __stdcall +tty_init (void) +{ + if (NOTSTATE (myself, PID_USETTY)) + return; + if (myself->ctty == -1) + if (NOTSTATE (myself, PID_CYGPARENT)) + myself->ctty = attach_tty (myself->ctty); + else + return; + if (myself->ctty == -1) + termios_printf ("Can't attach to tty"); +} + +/* Create session's master tty */ + +void __stdcall +create_tty_master (int ttynum) +{ + tty_master = (fhandler_tty_master *) dtable.build_fhandler (-1, FH_TTYM, + "/dev/ttym", ttynum); + if (tty_master->init (ttynum)) + api_fatal ("Can't create master tty"); + else + { + /* Log utmp entry */ + struct utmp our_utmp; + + bzero ((char *) &our_utmp, sizeof (utmp)); + (void) time (&our_utmp.ut_time); + strncpy (our_utmp.ut_name, getlogin (), sizeof (our_utmp.ut_name)); + cygwin_gethostname (our_utmp.ut_host, sizeof (our_utmp.ut_host)); + __small_sprintf (our_utmp.ut_line, "tty%d", ttynum); + our_utmp.ut_type = USER_PROCESS; + myself->ctty = ttynum; + login (&our_utmp); + } +} + +void __stdcall +tty_terminate (void) +{ + if (NOTSTATE (myself, PID_USETTY)) + return; + cygwin_shared->tty.terminate (); +} + +int __stdcall +attach_tty (int num) +{ + if (num != -1) + { + return cygwin_shared->tty.connect_tty (num); + } + if (NOTSTATE (myself, PID_USETTY)) + return -1; + return cygwin_shared->tty.allocate_tty (1); +} + +void +tty_list::terminate (void) +{ + int ttynum = myself->ctty; + + /* Keep master running till there are connected clients */ + if (ttynum != -1 && ttys[ttynum].master_pid == GetCurrentProcessId ()) + { + tty *t = ttys + ttynum; + CloseHandle (t->from_master); + CloseHandle (t->to_master); + /* Wait for children which rely on tty handling in this process to + go away */ + for (int i = 0; ; i++) + { + if (!t->slave_alive ()) + break; + if (i >= 100) + { + small_printf ("waiting for children using tty%d to terminate\n", + ttynum); + i = 0; + } + + Sleep (200); + } + + termios_printf ("tty %d master about to finish", ttynum); + CloseHandle (t->to_slave); + CloseHandle (t->from_slave); + WaitForSingleObject (tty_master->hThread, INFINITE); + t->init (); + + char buf[20]; + __small_sprintf (buf, "tty%d", ttynum); + logout (buf); + } +} + +int +tty_list::connect_tty (int ttynum) +{ + if (ttynum < 0 || ttynum >= NTTYS) + { + termios_printf ("ttynum (%d) out of range", ttynum); + return -1; + } + if (!ttys[ttynum].exists ()) + { + termios_printf ("tty %d was not allocated", ttynum); + return -1; + } + + return ttynum; +} + +void +tty_list::init (void) +{ + for (int i = 0; i < NTTYS; i++) + { + ttys[i].init (); + ttys[i].setntty (i); + } +} + +/* Search for tty class for our console. Allocate new tty if our process is + the only cygwin process in the current console. + Return tty number or -1 if error. + If flag == 0, just find a free tty. + */ +int +tty_list::allocate_tty (int with_console) +{ + HWND console; + + /* FIXME: This whole function needs a protective mutex. */ + + if (!with_console) + console = NULL; + else + { + char *oldtitle = new char [TITLESIZE]; + + if (!oldtitle) + { + termios_printf ("Can't *allocate console title buffer"); + return -1; + } + if (!GetConsoleTitle (oldtitle, TITLESIZE)) + { + termios_printf ("Can't read console title"); + return -1; + } + + if (WaitForSingleObject (title_mutex, INFINITE) == WAIT_FAILED) + termios_printf ("WFSO for title_mutext %p failed, %E", title_mutex); + + char buf[40]; + + __small_sprintf (buf, "cygwin.find.console.%d", myself->pid); + SetConsoleTitle (buf); + Sleep (40); + console = FindWindow (NULL, buf); + SetConsoleTitle (oldtitle); + Sleep (40); + ReleaseMutex (title_mutex); + if (console == NULL) + { + termios_printf ("Can't find console window"); + return -1; + } + } + /* Is a tty allocated for console? */ + + int freetty = -1; + for (int i = 0; i < NTTYS; i++) + { + if (!ttys[i].exists ()) + { + if (freetty < 0) /* Scanning? */ + freetty = i; /* Yes. */ + if (!with_console) /* Do we want to attach this to a console? */ + break; /* No. We've got one. */ + } + + if (with_console && ttys[i].gethwnd () == console) + { + termios_printf ("console %x already associated with tty%d", + console, i); + /* Is the master alive? */ + HANDLE hMaster; + hMaster = OpenProcess (PROCESS_DUP_HANDLE, FALSE, ttys[i].master_pid); + if (hMaster) + { + CloseHandle (hMaster); + return i; + } + /* Master is dead */ + freetty = i; + break; + } + } + + /* There is no tty allocated to console, allocate the first free found */ + if (freetty == -1) + { + system_printf ("No free ttys available"); + return -1; + } + tty *t = ttys + freetty; + t->init (); + t->setsid (-1); + t->setpgid (myself->pgid); + t->sethwnd (console); + + if (with_console) + { + termios_printf ("console %x associated with tty%d", console, freetty); + create_tty_master (freetty); + } + else + termios_printf ("tty%d allocated", freetty); + return freetty; +} + +BOOL +tty::slave_alive () +{ + return alive (TTY_SLAVE_ALIVE); +} + +BOOL +tty::master_alive () +{ + return alive (TTY_MASTER_ALIVE); +} + +BOOL +tty::alive (const char *fmt) +{ + HANDLE ev; + char buf[sizeof (TTY_MASTER_ALIVE) + 16]; + + __small_sprintf (buf, fmt, ntty); + if ((ev = OpenEvent (EVENT_ALL_ACCESS, TRUE, buf))) + CloseHandle (ev); + return ev != NULL; +} + +HANDLE +tty::create_inuse (const char *fmt) +{ + HANDLE h; + char buf[sizeof (TTY_MASTER_ALIVE) + 16]; + + __small_sprintf (buf, fmt, ntty); + h = CreateEvent (&sec_all, TRUE, FALSE, buf); + termios_printf ("%s = %p", buf, h); + if (!h) + termios_printf ("couldn't open inuse event, %E", buf); + return h; +} + +void +tty::init (void) +{ + OutputStopped = 0; + setsid (0); + pgid = 0; + hwnd = NULL; + to_slave = NULL; + from_slave = NULL; + was_opened = 0; +} + +HANDLE +tty::get_event (const char *fmt, BOOL inherit) +{ + HANDLE hev; + char buf[40]; + + __small_sprintf (buf, fmt, ntty); + if (!(hev = CreateEvent (inherit ? &sec_all : &sec_all_nih, FALSE, FALSE, buf))) + { + termios_printf ("couldn't create %s", buf); + set_errno (ENOENT); /* FIXME this can't be the right errno */ + return NULL; + } + + termios_printf ("created event %s", buf); + return hev; +} + +int +tty::make_pipes (fhandler_pty_master *ptym) +{ + /* Create communication pipes */ + + /* FIXME: should this be sec_none_nih? */ + if (CreatePipe (&from_master, &to_slave, &sec_all, 0) == FALSE) + { + termios_printf ("can't create input pipe"); + set_errno (ENOENT); + return FALSE; + } + + if (CreatePipe (&from_slave, &to_master, &sec_all, 0) == FALSE) + { + termios_printf ("can't create output pipe"); + set_errno (ENOENT); + return FALSE; + } + termios_printf ("tty%d from_slave %p, to_slave %p", ntty, from_slave, + to_slave); + ptym->set_io_handle (from_slave); + ptym->set_output_handle (to_slave); + return TRUE; +} + +BOOL +tty::common_init (fhandler_pty_master *ptym) +{ + /* Set termios information. Force initialization. */ + ptym->tcinit (this, TRUE); + + if (!make_pipes (ptym)) + return FALSE; + ptym->neednl_ = 0; + + /* Save our pid */ + + master_pid = GetCurrentProcessId (); + + /* Allow the others to open us (for handle duplication) */ + + if ((os_being_run == winNT) && + (SetKernelObjectSecurity (hMainProc, DACL_SECURITY_INFORMATION, + get_null_sd ()) == FALSE)) + small_printf ("Can't set process security, %E"); + + /* Create synchronisation events */ + + if (!(ptym->restart_output_event = get_event (RESTART_OUTPUT_EVENT, TRUE))) + return FALSE; + + if (ptym->get_device () != FH_TTYM) + { + ptym->output_done_event = ptym->ioctl_done_event = + ptym->ioctl_request_event = NULL; + } + else + { + if (!(ptym->output_done_event = get_event (OUTPUT_DONE_EVENT, FALSE))) + return FALSE; + if (!(ptym->ioctl_done_event = get_event (IOCTL_DONE_EVENT, FALSE))) + return FALSE; + if (!(ptym->ioctl_request_event = get_event (IOCTL_REQUEST_EVENT, FALSE))) + return FALSE; + } + + char buf[40]; + __small_sprintf (buf, OUTPUT_MUTEX, ntty); + if (!(ptym->output_mutex = CreateMutex (&sec_all, FALSE, buf))) + { + termios_printf ("can't create %s", buf); + set_errno (ENOENT); + return FALSE; + } + + ProtectHandle1 (ptym->output_mutex, output_mutex); + winsize.ws_col = 80; + winsize.ws_row = 25; + + termios_printf("tty%d opened", ntty); + return TRUE; +} diff --git a/winsup/cygwin/tz_posixrules.h b/winsup/cygwin/tz_posixrules.h new file mode 100644 index 000000000..6059d67f7 --- /dev/null +++ b/winsup/cygwin/tz_posixrules.h @@ -0,0 +1,48 @@ +/* generated with bin2h from zoneinfo/posixrules */ + +static unsigned char _posixrules_data[] = { +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0, +0,1,16,0,0,0,2,0,0,0,8,0,151,254,240,1,135,225,224,2,119,224,240,3,112,254,96,4,96,253,112,5,80, +224,96,6,64,223,112,7,48,194,96,7,141,25,112,9,16,164,96,9,173,148,240,10,240,134,96,11,224,133,112,12,217,162, +224,13,192,103,112,14,185,132,224,15,169,131,240,16,153,102,224,17,137,101,240,18,121,72,224,19,105,71,240,20,89,42,224, +21,73,41,240,22,57,12,224,23,41,11,240,24,34,41,96,25,8,237,240,26,2,11,96,26,242,10,112,27,225,237,96,28, +209,236,112,29,193,207,96,30,177,206,112,31,161,177,96,32,118,0,240,33,129,147,96,34,85,226,240,35,106,175,224,36,53, +196,240,37,74,145,224,38,21,166,240,39,42,115,224,39,254,195,112,41,10,85,224,41,222,165,112,42,234,55,224,43,190,135, +112,44,211,84,96,45,158,105,112,46,179,54,96,47,126,75,112,48,147,24,96,49,103,103,240,50,114,250,96,51,71,73,240, +52,82,220,96,53,39,43,240,54,50,190,96,55,7,13,240,56,27,218,224,56,230,239,240,57,251,188,224,58,198,209,240,59, +219,158,224,60,175,238,112,61,187,128,224,62,143,208,112,63,155,98,224,64,111,178,112,65,132,127,96,66,79,148,112,67,100, +97,96,68,47,118,112,69,68,67,96,70,15,88,112,71,36,37,96,71,248,116,240,73,4,7,96,73,216,86,240,74,227,233, +96,75,184,56,240,76,205,5,224,77,152,26,240,78,172,231,224,79,119,252,240,80,140,201,224,81,97,25,112,82,108,171,224, +83,64,251,112,84,76,141,224,85,32,221,112,86,44,111,224,87,0,191,112,88,21,140,96,88,224,161,112,89,245,110,96,90, +192,131,112,91,213,80,96,92,169,159,240,93,181,50,96,94,137,129,240,95,149,20,96,96,105,99,240,97,126,48,224,98,73, +69,240,99,94,18,224,100,41,39,240,101,61,244,224,102,18,68,112,103,29,214,224,103,242,38,112,104,253,184,224,105,210,8, +112,106,221,154,224,107,177,234,112,108,198,183,96,109,145,204,112,110,166,153,96,111,113,174,112,112,134,123,96,113,90,202,240, +114,102,93,96,115,58,172,240,116,70,63,96,117,26,142,240,118,47,91,224,118,250,112,240,120,15,61,224,120,218,82,240,121, +239,31,224,122,186,52,240,123,207,1,224,124,163,81,112,125,174,227,224,126,131,51,112,127,142,197,224,128,99,21,112,129,119, +226,96,130,66,247,112,131,87,196,96,132,34,217,112,133,55,166,96,134,11,245,240,135,23,136,96,135,235,215,240,136,247,106, +96,137,203,185,240,138,215,76,96,139,171,155,240,140,192,104,224,141,139,125,240,142,160,74,224,143,107,95,240,144,128,44,224, +145,84,124,112,146,96,14,224,147,52,94,112,148,63,240,224,149,20,64,112,150,41,13,96,150,244,34,112,152,8,239,96,152, +212,4,112,153,232,209,96,154,189,32,240,155,200,179,96,156,157,2,240,157,168,149,96,158,124,228,240,159,136,119,96,160,92, +198,240,161,113,147,224,162,60,168,240,163,81,117,224,164,28,138,240,165,49,87,224,166,5,167,112,167,17,57,224,167,229,137, +112,168,241,27,224,169,197,107,112,170,218,56,96,171,165,77,112,172,186,26,96,173,133,47,112,174,153,252,96,175,101,17,112, +176,121,222,96,177,78,45,240,178,89,192,96,179,46,15,240,180,57,162,96,181,13,241,240,182,34,190,224,182,237,211,240,184, +2,160,224,184,205,181,240,185,226,130,224,186,182,210,112,187,194,100,224,188,150,180,112,189,162,70,224,190,118,150,112,191,130, +40,224,192,86,120,112,193,107,69,96,194,54,90,112,195,75,39,96,196,22,60,112,197,43,9,96,197,255,88,240,199,10,235, +96,199,223,58,240,200,234,205,96,201,191,28,240,202,211,233,224,203,158,254,240,204,179,203,224,205,126,224,240,206,147,173,224, +207,103,253,112,208,115,143,224,209,71,223,112,210,83,113,224,211,39,193,112,212,51,83,224,213,7,163,112,214,28,112,96,214, +231,133,112,215,252,82,96,216,199,103,112,217,220,52,96,218,176,131,240,219,188,22,96,220,144,101,240,221,155,248,96,222,112, +71,240,223,133,20,224,224,80,41,240,225,100,246,224,226,48,11,240,227,68,216,224,228,15,237,240,229,36,186,224,229,249,10, +112,231,4,156,224,231,216,236,112,232,228,126,224,233,184,206,112,234,205,155,96,235,152,176,112,236,173,125,96,237,120,146,112, +238,141,95,96,239,97,174,240,240,109,65,96,241,65,144,240,242,77,35,96,243,33,114,240,244,45,5,96,245,1,84,240,246, +22,33,224,246,225,54,240,247,246,3,224,248,193,24,240,249,213,229,224,250,160,250,240,251,181,199,224,252,138,23,112,253,149, +169,224,254,105,249,112,255,117,139,224,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0, +1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1, +0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0, +1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1, +0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0, +1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1, +0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0, +1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1, +0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,255,255,199,192,1,0,255,255,185,176,0,4,69,68,84, +0,69,83,84,0,0,0 +}; diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc new file mode 100644 index 000000000..fbf2eca2a --- /dev/null +++ b/winsup/cygwin/uinfo.cc @@ -0,0 +1,200 @@ +/* uinfo.cc: user info (uid, gid, etc...) + + Copyright 1996, 1997, 1998 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include "winsup.h" +#include +#include +#include +#include "autoload.h" +#include +#include +#include + +/* FIXME: shouldn't violate internal object space -- these two + should be static inside grp.cc */ +void read_etc_group (); +extern int group_in_memory_p; + +char * +internal_getlogin (struct pinfo *pi) +{ + DWORD username_len = MAX_USER_NAME; + LPWKSTA_USER_INFO_1 ui = NULL; + + if (! pi) + api_fatal ("pinfo pointer is NULL!\n"); + + if (os_being_run == winNT) + { + int ret = NetWkstaUserGetInfo (NULL, 1, (LPBYTE *)&ui); + if (! ret) + { + wcstombs (pi->domain, + ui->wkui1_logon_domain, + (wcslen (ui->wkui1_logon_domain) + 1) * sizeof (WCHAR)); + debug_printf ("Domain: %s", pi->domain); + wcstombs (pi->logsrv, + ui->wkui1_logon_server, + (wcslen (ui->wkui1_logon_server) + 1) * sizeof (WCHAR)); + if (! *pi->logsrv) + { + LPWSTR logon_srv = NULL; + + if (!NetGetAnyDCName (NULL, + ui->wkui1_logon_domain, + (LPBYTE *)&logon_srv)) + wcstombs (pi->logsrv, + logon_srv, // filter leading double backslashes + (wcslen (logon_srv) + 1) * sizeof (WCHAR)); + if (logon_srv) + NetApiBufferFree (logon_srv); + debug_printf ("AnyDC Server: %s", pi->logsrv); + } + else + debug_printf ("Logon Server: %s", pi->logsrv); + wcstombs (pi->username, + ui->wkui1_username, + (wcslen (ui->wkui1_username) + 1) * sizeof (WCHAR)); + debug_printf ("Windows Username: %s", pi->username); + NetApiBufferFree (ui); + } + else + { + debug_printf ("%d = NetWkstaUserGetInfo ()\n", ret); + if (! GetUserName (pi->username, &username_len)) + strcpy (pi->username, "unknown"); + } + if (!lookup_name (pi->username, pi->logsrv, pi->psid)) + { + debug_printf ("myself->psid = NULL"); + pi->psid = NULL; + } + else if (allow_ntsec) + { + extern BOOL get_pw_sid (PSID, struct passwd*); + struct passwd *pw; + char psidbuf[40]; + PSID psid = (PSID) psidbuf; + + while ((pw = getpwent ()) != NULL) + if (get_pw_sid (psid, pw) && EqualSid (pi->psid, psid)) + { + strcpy (pi->username, pw->pw_name); + break; + } + endpwent (); + } + } + else + { + debug_printf ("myself->psid = NULL"); + pi->psid = NULL; + if (! GetUserName (pi->username, &username_len)) + strcpy (pi->username, "unknown"); + } + debug_printf ("Cygwins Username: %s\n", pi->username); + return pi->username; +} + +void +uinfo_init () +{ + struct passwd *p; + + if (myself->username[0]) + return; + + myself->psid = (PSID) myself->sidbuf; + if ((p = getpwnam (internal_getlogin (myself))) != NULL) + { + /* calling getpwnam assures us that /etc/password has been + read in, but we can't be sure about /etc/group */ + + if (!group_in_memory_p) + read_etc_group (); + + myself->uid = p->pw_uid; + myself->gid = p->pw_gid; + } + else + { + myself->uid = DEFAULT_UID; + myself->gid = DEFAULT_GID; + } +} + +extern "C" char * +getlogin (void) +{ +#ifdef _MT_SAFE + char *this_username=_reent_winsup()->_username; +#else + static NO_COPY char this_username[MAX_USER_NAME]; +#endif + + uinfo_init (); + return strcpy (this_username, myself->username); +} + +extern "C" uid_t +getuid (void) +{ + return myself->uid; +} + +extern "C" gid_t +getgid (void) +{ + return myself->gid; +} + +extern "C" uid_t +geteuid (void) +{ + return getuid (); +} + +extern "C" gid_t +getegid (void) +{ + return getgid (); +} + +/* Not quite right - cuserid can change, getlogin can't */ +extern "C" char * +cuserid (char *src) +{ + if (src) + { + strcpy (src, getlogin ()); + return src; + } + else + { + return getlogin (); + } +} + +LoadDLLinitfunc (netapi32) +{ + HANDLE h; + + if ((h = LoadLibrary ("netapi32.dll")) != NULL) + netapi32_handle = h; + else if (! netapi32_handle) + api_fatal ("could not load netapi32.dll. %d", GetLastError ()); + return 0; +} +LoadDLLinit (netapi32) +LoadDLLfunc (NetWkstaUserGetInfo, NetWkstaUserGetInfo@12, netapi32) +LoadDLLfunc (NetGetAnyDCName, NetGetAnyDCName@12, netapi32) +LoadDLLfunc (NetApiBufferFree, NetApiBufferFree@4, netapi32) + diff --git a/winsup/cygwin/uname.cc b/winsup/cygwin/uname.cc new file mode 100644 index 000000000..101855cd7 --- /dev/null +++ b/winsup/cygwin/uname.cc @@ -0,0 +1,110 @@ +/* uname.cc + + Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions. + Written by Steve Chamberlain of Cygnus Support, sac@cygnus.com + Rewritten by Geoffrey Noer of Cygnus Solutions, noer@cygnus.com + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include "winsup.h" + +/* uname: POSIX 4.4.1.1 */ +extern "C" +int +uname (struct utsname *name) +{ + DWORD len; + SYSTEM_INFO sysinfo; + OSVERSIONINFO os_version_info; + + os_version_info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); + GetVersionEx (&os_version_info); + + GetSystemInfo (&sysinfo); + + /* Computer name */ + memset (name, 0, sizeof (*name)); + len = sizeof (name->nodename) - 1; + GetComputerNameA (name->nodename, &len); + + /* Operating system type */ + switch (os_being_run) + { + case winNT: + strcpy (name->sysname, "CYGWIN_NT"); + break; + case win98: + strcpy (name->sysname, "CYGWIN_98"); + break; + case win95: + strcpy (name->sysname, "CYGWIN_95"); + break; + default: + strcpy (name->sysname, "CYGWIN_??"); + break; + } + + __small_sprintf (strchr (name->sysname, '\0'), "-%d.%d", + os_version_info.dwMajorVersion, + os_version_info.dwMinorVersion); + + + /* Cygwin dll release */ + __small_sprintf (name->release, "%d.%d.%d(%d.%d/%d/%d)", + 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" aka build date */ + strcpy (name->version, cygwin_version.dll_build_date); + + /* CPU type */ + switch (sysinfo.wProcessorArchitecture) + { + case PROCESSOR_ARCHITECTURE_INTEL: + /* But which of the x86 chips are we? */ + /* Default to i386 if the specific chip cannot be determined */ + switch (os_being_run) + { + case win95: + case win98: + /* dwProcessorType only valid in Windows 95 */ + if ((sysinfo.dwProcessorType == PROCESSOR_INTEL_386) || + (sysinfo.dwProcessorType == PROCESSOR_INTEL_486) || + (sysinfo.dwProcessorType == PROCESSOR_INTEL_PENTIUM)) + __small_sprintf (name->machine, "i%d", sysinfo.dwProcessorType); + else + strcpy (name->machine, "i386"); + break; + case winNT: + /* wProcessorLevel only valid in Windows NT */ + __small_sprintf (name->machine, "i%d86", sysinfo.wProcessorLevel); + break; + default: + strcpy (name->machine, "i386"); + break; + } + break; + case PROCESSOR_ARCHITECTURE_ALPHA: + strcpy (name->machine, "alpha"); + break; + case PROCESSOR_ARCHITECTURE_MIPS: + strcpy (name->machine, "mips"); + break; + default: + strcpy (name->machine, "unknown"); + break; + } + + return 0; +} diff --git a/winsup/cygwin/wait.cc b/winsup/cygwin/wait.cc new file mode 100644 index 000000000..182240022 --- /dev/null +++ b/winsup/cygwin/wait.cc @@ -0,0 +1,113 @@ +/* wait.cc: Posix wait routines. + + Copyright 1996, 1997, 1998, 1999 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include "winsup.h" + +/* This is called _wait and not wait because the real wait is defined + in libc/syscalls/syswait.c. It calls us. */ + +extern "C" +pid_t +_wait (int *status) +{ + return wait4 (-1, status, 0, NULL); +} + +pid_t +waitpid (pid_t intpid, int *status, int options) +{ + return wait4 (intpid, status, options, NULL); +} + +pid_t +wait3 (int *status, int options, struct rusage *r) +{ + return wait4 (-1, status, options, r); +} + +/* Wait for any child to complete. + * Note: this is not thread safe. Use of wait in multiple threads will + * not work correctly. + */ + +pid_t +wait4 (int intpid, int *status, int options, struct rusage *r) +{ + int rc; + waitq *w; + HANDLE waitfor; + + if (options & ~(WNOHANG | WUNTRACED)) + { + set_errno (EINVAL); + return -1; + } + + if (r) + memset (r, 0, sizeof (*r)); + + if ((w = (waitq *) waitq_storage.get ()) == NULL) + w = (waitq *) waitq_storage.create (); + + w->pid = intpid; + w->options = options; + w->rusage = r; + sigproc_printf("calling proc_subproc, pid %d, options %d", + w->pid, w->options); + if (!proc_subproc(PROC_WAIT, (DWORD)w)) + { + set_errno(ENOSYS); + paranoid_printf ("proc_subproc returned 0"); + rc = -1; + goto done; + } + + if ((waitfor = w->ev) == NULL) + goto nochildren; + + rc = WaitForSingleObject (waitfor, INFINITE); + + sigproc_printf ("%d = WaitForSingleObject (...)", rc); + + if (w->ev == NULL) + { + nochildren: + /* found no children */ + set_errno (ECHILD); + rc = -1; + goto done; + } + + if (w->status == -1) + { + set_sig_errno (EINTR); + rc = -1; + } + else if (rc != WAIT_OBJECT_0) + { + /* We shouldn't set errno to any random value if we can help it. + See the Posix manual for a list of valid values for `errno'. */ + set_errno (EINVAL); + rc = -1; + } + else if ((rc = w->pid) != 0 && status) + *status = w->status; + +done: + sigproc_printf ("intpid %d, status %p, w->status %d, options %d, rc %d", + intpid, status, w->status, options, rc); + w->status = -1; + if (rc < 0) + sigproc_printf("*** errno = %d", get_errno()); + return rc; +} diff --git a/winsup/cygwin/window.cc b/winsup/cygwin/window.cc new file mode 100644 index 000000000..567d9a806 --- /dev/null +++ b/winsup/cygwin/window.cc @@ -0,0 +1,231 @@ +/* window.cc: hidden windows for signals/itimer support + + Copyright 1997, 1998, 2000 Cygnus Solutions. + + Written by Sergey Okhapkin + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include "winsup.h" + +static NO_COPY UINT timer_active = 0; +static NO_COPY struct itimerval itv; +static NO_COPY DWORD start_time; +static NO_COPY HWND ourhwnd = NULL; + +static LRESULT CALLBACK +WndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ +#ifndef NOSTRACE + _strace_wm (uMsg, wParam, lParam); +#endif + switch (uMsg) + { + case WM_PAINT: + return 0; + case WM_DESTROY: + PostQuitMessage (0); + return 0; + case WM_TIMER: + if (wParam == timer_active) + { + UINT elapse = itv.it_interval.tv_sec * 1000 + + itv.it_interval.tv_usec / 1000; + KillTimer (hwnd, timer_active); + if (!elapse) + { + timer_active = 0; + } + else + { + timer_active = SetTimer (hwnd, 1, elapse, NULL); + start_time = GetTickCount (); + itv.it_value = itv.it_interval; + } + raise(SIGALRM); + } + return 0; + case WM_ASYNCIO: + raise (SIGIO); + return 0; + default: + return DefWindowProc (hwnd, uMsg, wParam, lParam); + } +} + +static HANDLE window_started; + +static DWORD WINAPI +Winmain (VOID *arg) +{ + MSG msg; + WNDCLASS wc; + static char classname[] = "CygwinWndClass"; + + /* Register the window class for the main window. */ + + wc.style = 0; + wc.lpfnWndProc = (WNDPROC) WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = user_data->hmodule; + wc.hIcon = NULL; + wc.hCursor = NULL; + wc.hbrBackground = NULL; + wc.lpszMenuName = NULL; + wc.lpszClassName = classname; + + if (!RegisterClass (&wc)) + { + system_printf ("Cannot register window class"); + return FALSE; + } + + /* Create hidden window. */ + ourhwnd = CreateWindow (classname, classname, + WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, (HWND) NULL, + (HMENU) NULL, user_data->hmodule, (LPVOID) NULL); + + SetEvent (window_started); + + if (!ourhwnd) + { + system_printf ("Cannot create window"); + return FALSE; + } + + /* Start the message loop. */ + + while (GetMessage (&msg, ourhwnd, 0, 0) == TRUE) + { + DispatchMessage (&msg); + } + + return msg.wParam; +} + +HWND __stdcall +gethwnd () +{ + if (ourhwnd != NULL) + return ourhwnd; + + HANDLE hThread; + + window_started = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL); + hThread = makethread (Winmain, NULL, 0, "win"); + if (!hThread) + { + system_printf ("Cannot start window thread"); + } + else + { + SetThreadPriority (hThread, THREAD_PRIORITY_HIGHEST); + CloseHandle (hThread); + } + WaitForSingleObject (window_started, INFINITE); + CloseHandle (window_started); + return ourhwnd; +} + +void __stdcall +window_terminate () +{ + if (ourhwnd) + SendMessage (ourhwnd, WM_DESTROY, 0, 0); +} + +extern "C" +int +setitimer (int which, const struct itimerval *value, struct itimerval *oldvalue) +{ + UINT elapse; + + if (which != ITIMER_REAL) + { + set_errno (EINVAL); + return -1; + } + if (timer_active) + { + KillTimer (gethwnd(), timer_active); + timer_active = 0; + } + if (oldvalue) + *oldvalue = itv; + if (value == NULL) + { + set_errno (EFAULT); + return -1; + } + itv = *value; + elapse = itv.it_value.tv_sec * 1000 + itv.it_value.tv_usec / 1000; + if (elapse == 0) + return 0; + if (!(timer_active = SetTimer (gethwnd(), 1, elapse, NULL))) + { + __seterrno (); + return -1; + } + start_time = GetTickCount (); + return 0; +} + +extern "C" +int +getitimer (int which, struct itimerval *value) +{ + UINT elapse, val; + + if (which != ITIMER_REAL) + { + set_errno (EINVAL); + return -1; + } + if (value == NULL) + { + set_errno (EFAULT); + return -1; + } + *value = itv; + if (!timer_active) + { + value->it_value.tv_sec = 0; + value->it_value.tv_usec = 0; + return 0; + } + elapse = GetTickCount () - start_time; + val = itv.it_value.tv_sec * 1000 + itv.it_value.tv_usec / 1000; + val -= elapse; + value->it_value.tv_sec = val/1000; + value->it_value.tv_usec = val%1000; + return 0; +} + +extern "C" +unsigned int +alarm (unsigned int seconds) +{ + int ret; + struct itimerval newt, oldt; + + getitimer (ITIMER_REAL, &oldt); + + newt.it_value.tv_sec = seconds; + newt.it_value.tv_usec = 0; + newt.it_interval.tv_sec = 0; + newt.it_interval.tv_usec = 0; + setitimer (ITIMER_REAL, &newt, NULL); + ret = oldt.it_value.tv_sec; + if (ret == 0 && oldt.it_value.tv_usec) + ret = 1; + return ret; +} diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h new file mode 100644 index 000000000..7b486d077 --- /dev/null +++ b/winsup/cygwin/winsup.h @@ -0,0 +1,595 @@ +/* winsup.h: main Cygwin header file. + + Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#define __INSIDE_CYGWIN__ + +#define alloca(x) __builtin_alloca (x) +#define strlen __builtin_strlen +#define strcpy __builtin_strcpy +#define memcpy __builtin_memcpy +#define memcmp __builtin_memcmp +#ifdef HAVE_BUILTIN_MEMSET +# define memset __builtin_memset +#endif + +#include +#include +#include +#include +#include +#include + +#undef strchr +#define strchr cygwin_strchr +extern inline char * strchr(const char * s, int c) +{ +register char * __res; +__asm__ __volatile__( + "movb %%al,%%ah\n" + "1:\tmovb (%1),%%al\n\t" + "cmpb %%ah,%%al\n\t" + "je 2f\n\t" + "incl %1\n\t" + "testb %%al,%%al\n\t" + "jne 1b\n\t" + "xorl %1,%1\n" + "2:\tmovl %1,%0\n\t" + :"=a" (__res), "=r" (s) + :"0" (c), "1" (s)); +return __res; +} + +#include + +/* Used for runtime OS check/decisions. */ +enum os_type {winNT = 1, win95, win98, win32s, unknown}; +extern os_type os_being_run; + +/* Used to check if Cygwin DLL is dynamically loaded. */ +extern int dynamically_loaded; + +#include + +#define TITLESIZE 1024 +#define MAX_USER_NAME 20 +#define DEFAULT_UID 500 +#define DEFAULT_GID 544 + +/* status bit manipulation */ +#define __ISSETF(what, x, prefix) \ + ((what)->status & prefix##_##x) +#define __SETF(what, x, prefix) \ + ((what)->status |= prefix##_##x) +#define __CLEARF(what, x, prefix) \ + ((what)->status &= ~prefix##_##x) +#define __CONDSETF(n, what, x, prefix) \ + ((n) ? __SETF (what, x, prefix) : __CLEARF (what, x, prefix)) + +#include "thread.h" +#include "shared.h" + +extern HANDLE hMainThread; +extern HANDLE hMainProc; + +#include "sync.h" + +/* Now that pinfo has been defined, include... */ +#include "debug.h" +#include "sigproc.h" +#include "fhandler.h" +#include "path.h" +#include + +/********************** Application Interface **************************/ + +/* This lives in the app and is initialized before jumping into the DLL. + It should only contain stuff which the user's process needs to see, or + which is needed before the user pointer is initialized, or is needed to + carry inheritance information from parent to child. Note that it cannot + be used to carry inheritance information across exec! + + Remember, this structure is linked into the application's executable. + Changes to this can invalidate existing executables, so we go to extra + lengths to avoid having to do it. + + When adding/deleting members, remember to adjust {public,internal}_reserved. + The size of the class shouldn't change [unless you really are prepared to + invalidate all existing executables]. The program does a check (using + SIZEOF_PER_PROCESS) to make sure you remember to make the adjustment. +*/ + +class per_process +{ + public: + char *initial_sp; + + /* The offset of these 3 values can never change. */ + /* magic_biscuit is the size of this class and should never change. */ + DWORD magic_biscuit; + DWORD dll_major; + DWORD dll_minor; + + struct _reent **impure_ptr_ptr; + char ***envptr; + + /* Used to point to the memory machine we should use. Usually these + point back into the dll, but they can be overridden by the user. */ + void *(*malloc)(size_t); + void (*free)(void *); + void *(*realloc)(void *, size_t); + + int *fmode_ptr; + + int (*main)(int, char **, char **); + void (**ctors)(void); + void (**dtors)(void); + + /* For fork */ + void *data_start; + void *data_end; + void *bss_start; + void *bss_end; + + void *(*calloc)(size_t, size_t); + /* For future expansion of values set by the app. */ + void *public_reserved[4]; + + /* The rest are *internal* to cygwin.dll. + Those that are here because we want the child to inherit the value from + the parent (which happens when bss is copied) are marked as such. */ + + /* non-zero of ctors have been run. Inherited from parent. */ + int run_ctors_p; + + /* These will be non-zero if the above (malloc,free,realloc) have been + overridden. */ + /* FIXME: not currently used */ + int __imp_malloc; + int __imp_free; + int __imp_realloc; + + /* Heap management. Inherited from parent. */ + void *heapbase; /* bottom of the heap */ + void *heapptr; /* current index into heap */ + void *heaptop; /* current top of heap */ + + HANDLE reserved1; /* unused */ + + /* Non-zero means the task was forked. The value is the pid. + Inherited from parent. */ + int forkee; + + HMODULE hmodule; + + DWORD api_major; /* API version that this program was */ + DWORD api_minor; /* linked with */ + /* For future expansion, so apps won't have to be relinked if we + add an item. */ +#ifdef _MT_SAFE + ResourceLocks *resourcelocks; + MTinterface *threadinterface; + void *internal_reserved[6]; +#else + void *internal_reserved[8]; +#endif +}; + +extern per_process *user_data; /* Pointer into application's static data */ + +/* We use the following to test that sizeof hasn't changed. When adding + or deleting members, insert fillers or use the reserved entries. + Do not change this value. */ +#define SIZEOF_PER_PROCESS (42 * 4) + +class hinfo +{ + fhandler_base **fds; + fhandler_base **fds_on_hold; + int first_fd_for_open; +public: + size_t size; + hinfo () {first_fd_for_open = 3;} + int vfork_child_dup (); + void vfork_parent_restore (); + fhandler_base *dup_worker (fhandler_base *oldfh); + int extend (int howmuch); + void fixup_after_fork (HANDLE parent); + fhandler_base *build_fhandler (int fd, DWORD dev, const char *name, + int unit = -1); + fhandler_base *build_fhandler (int fd, const char *name, HANDLE h); + int not_open (int n); + int find_unused_handle (int start); + int find_unused_handle () { return find_unused_handle (first_fd_for_open);} + void release (int fd); + void init_std_file_from_handle (int fd, HANDLE handle, DWORD access, const char *name); + int dup2 (int oldfd, int newfd); + int linearize_fd_array (unsigned char *buf, int buflen); + LPBYTE de_linearize_fd_array (LPBYTE buf); + fhandler_base *operator [](int fd) { return fds[fd]; } + select_record *select_read (int fd, select_record *s); + select_record *select_write (int fd, select_record *s); + select_record *select_except (int fd, select_record *s); +}; + +/******************* Host-dependent constants **********************/ +/* Portions of the cygwin DLL require special constants whose values + are dependent on the host system. Rather than dynamically + determine those values whenever they are required, initialize these + values once at process start-up. */ + +class host_dependent_constants +{ + public: + void init (void); + + /* Used by fhandler_disk_file::lock which needs a platform-specific + upper word value for locking entire files. */ + DWORD win32_upper; + + /* fhandler_base::open requires host dependent file sharing + attributes. */ + int shared; +}; + +extern host_dependent_constants host_dependent; + +/* Events/mutexes */ +extern HANDLE pinfo_mutex; +extern HANDLE title_mutex; + + + +/*************************** Per Thread ******************************/ + +#define PER_THREAD_FORK_CLEAR ((void *)0xffffffff) +class per_thread +{ + DWORD tls; + int clear_on_fork_p; +public: + per_thread (int forkval = 1) {tls = TlsAlloc (); clear_on_fork_p = forkval;} + DWORD get_tls () {return tls;} + int clear_on_fork () {return clear_on_fork_p;} + + virtual void *get () {return TlsGetValue (get_tls ());} + virtual size_t size () {return 0;} + virtual void set (void *s = NULL); + virtual void set (int n) {TlsSetValue (get_tls (), (void *)n);} + virtual void *create () + { + void *s = new char [size ()]; + memset (s, 0, size ()); + set (s); + return s; + } +}; + +class per_thread_waitq : public per_thread +{ +public: + per_thread_waitq () : per_thread (0) {} + void *get () {return (waitq *) this->per_thread::get ();} + void *create () {return (waitq *) this->per_thread::create ();} + size_t size () {return sizeof (waitq);} +}; + +struct vfork_save +{ + int pid; + jmp_buf j; + char **vfork_ebp; + char *caller_ebp; + char *retaddr; + int is_active () { return pid < 0; } +}; + +class per_thread_vfork : public per_thread +{ +public: + vfork_save *val () { return (vfork_save *) this->per_thread::get (); } + vfork_save *create () {return (vfork_save *) this->per_thread::create ();} + size_t size () {return sizeof (vfork_save);} +}; + +extern "C" { +struct signal_dispatch +{ + int arg; + void (*func) (int); + int sig; + int saved_errno; + CONTEXT *cx; + DWORD oldmask; + DWORD retaddr; +}; +}; + +struct per_thread_signal_dispatch : public per_thread +{ + signal_dispatch *get () { return (signal_dispatch *) this->per_thread::get (); } + signal_dispatch *create () {return (signal_dispatch *) this->per_thread::create ();} + size_t size () {return sizeof (signal_dispatch);} +}; + +extern per_thread_waitq waitq_storage; +extern per_thread_vfork vfork_storage; +extern per_thread_signal_dispatch signal_dispatch_storage; + +extern per_thread *threadstuff[]; + +/**************************** Convenience ******************************/ + +#define NO_COPY __attribute__((section(".data_cygwin_nocopy"))) + +/* Used when treating / and \ as equivalent. */ +#define SLASH_P(ch) \ + ({ \ + char __c = (ch); \ + ((__c) == '/' || (__c) == '\\'); \ + }) + +/* Convert a signal to a signal mask */ +#define SIGTOMASK(sig) (1<<((sig) - signal_shift_subtract)) +extern unsigned int signal_shift_subtract; + +#ifdef NOSTRACE +#define MARK() 0 +#else +#define MARK() mark (__FILE__,__LINE__) +#endif + +#define api_fatal(fmt, args...) \ + __api_fatal ("%P: *** " fmt, ## args) + +#undef issep +#define issep(ch) (strchr (" \t\n\r", (ch)) != NULL) + +#define isdirsep SLASH_P +#define isabspath(p) \ + (isdirsep (*(p)) || (isalpha (*(p)) && (p)[1] == ':')) + +/******************** Initialization/Termination **********************/ + +/* cygwin .dll initialization */ +void dll_crt0 (per_process *); + +/* dynamically loaded dll initialization */ +extern "C" int dll_dllcrt0 (HMODULE,per_process*); + +/* dynamically loaded dll initialization for non-cygwin apps */ +extern "C" int dll_noncygwin_dllcrt0 (HMODULE, per_process *); + +/* exit the program */ +extern "C" void __stdcall do_exit (int) __attribute__ ((noreturn)); + +/* Initialize the environment */ +void environ_init (void); + +/* Heap management. */ +void heap_init (void); +void malloc_init (void); + +/* fd table */ +void dtable_init (void); +void hinfo_init (void); +extern hinfo dtable; + +/* UID/GID */ +void uinfo_init (void); + +/* various events */ +void events_init (void); +void events_terminate (void); + +void __stdcall close_all_files (void); + +/* Strace facility. See strace.cc, sys/strace.h and utils/strace.cc. */ +extern DWORD strace_active; + +/* Invisible window initialization/termination. */ +HWND __stdcall gethwnd (void); +void __stdcall window_terminate (void); + +/* Globals that handle initialization of winsock in a child process. */ +extern HANDLE wsock32_handle; + +/* Globals that handle initialization of netapi in a child process. */ +extern HANDLE netapi32_handle; + +/* debug_on_trap support. see exceptions.cc:try_to_debug() */ +extern "C" void error_start_init (const char*); +extern "C" int try_to_debug (); + +/**************************** Miscellaneous ******************************/ + +const char * __stdcall find_exec (const char *name, char *buf, const char *winenv = "PATH=", + int null_if_notfound = 0, const char **known_suffix = NULL); + +/* File manipulation */ +int __stdcall get_file_attribute (int, const char *, int *); +int __stdcall set_file_attribute (int, const char *, int); +int __stdcall set_file_attribute (int, const char *, uid_t, gid_t, int, const char *); +void __stdcall set_std_handle (int); +int __stdcall writable_directory (const char *file); +int __stdcall stat_dev (DWORD, int, unsigned long, struct stat *); +extern BOOL allow_ntsec; + +/* `lookup_name' should be called instead of LookupAccountName. + * logsrv may be NULL, in this case only the local system is used for lookup. + * The buffer for ret_sid (40 Bytes) has to be allocated by the caller! */ +BOOL __stdcall lookup_name (const char *name, const char *logsrv, PSID ret_sid); + +unsigned long __stdcall hash_path_name (unsigned long hash, const char *name); +void __stdcall nofinalslash (const char *src, char *dst); +extern "C" char *__stdcall rootdir (char *full_path); + +void __stdcall mark (const char *, int); + +extern "C" int _spawnve (HANDLE hToken, int mode, const char *path, + const char *const *argv, const char *const *envp); +int __stdcall spawn_guts (HANDLE hToken, const char *prog_arg, + const char *const *argv, const char *const envp[], + pinfo *child, int mode); + +/* For mmaps across fork(). */ +int __stdcall recreate_mmaps_after_fork (void *); +void __stdcall set_child_mmap_ptr (pinfo *); + +/* String manipulation */ +char *__stdcall strccpy (char *s1, const char **s2, char c); +int __stdcall strcasematch (const char *s1, const char *s2); +int __stdcall strncasematch (const char *s1, const char *s2, size_t n); +char *__stdcall strcasestr (const char *searchee, const char *lookfor); + +/* Time related */ +void __stdcall totimeval (struct timeval *dst, FILETIME * src, int sub, int flag); +long __stdcall to_time_t (FILETIME * ptr); + +/* pinfo table manipulation */ +#ifndef lock_pinfo_for_update +int __stdcall lock_pinfo_for_update (DWORD timeout); +#endif +void unlock_pinfo (void); +pinfo *__stdcall set_myself (pinfo *); + +/* Retrieve a security descriptor that allows all access */ +SECURITY_DESCRIPTOR *__stdcall get_null_sd (void); + +int __stdcall get_id_from_sid (PSID, BOOL); +extern inline int get_uid_from_sid (PSID psid) { return get_id_from_sid (psid, FALSE);} +extern inline int get_gid_from_sid (PSID psid) { return get_id_from_sid (psid, TRUE); } + +int __stdcall NTReadEA (const char *file, const char *attrname, char *buf, int len); +BOOL __stdcall NTWriteEA (const char *file, const char *attrname, char *buf, int len); + +void __stdcall set_console_title (char *); +void set_console_handler (); + +void __stdcall fill_rusage (struct rusage *, HANDLE); +void __stdcall add_rusage (struct rusage *, struct rusage *); + +void set_winsock_errno (); + +/**************************** Exports ******************************/ + +extern "C" { +int cygwin_select (int , fd_set *, fd_set *, fd_set *, + struct timeval *to); +int cygwin_gethostname (char *__name, size_t __len); + +int kill_pgrp (pid_t, int); +int _kill (int, int); +int _raise (int sig); + +int getdtablesize (); +void setdtablesize (int); + +extern char _data_start__, _data_end__, _bss_start__, _bss_end__; +extern void (*__CTOR_LIST__) (void); +extern void (*__DTOR_LIST__) (void); +}; + +/*************************** Unsorted ******************************/ + +/* The size of the console title */ +#define TITLESIZE 1024 + +#define WM_ASYNCIO 0x8000 // WM_APP + +/* Note that MAX_PATH is defined in the windows headers */ +/* There is also PATH_MAX and MAXPATHLEN. + PATH_MAX is from Posix and does *not* include the trailing NUL. + MAXPATHLEN is from Unix. + + Thou shalt use MAX_PATH throughout. It avoids the NUL vs no-NUL + issue and is neither of the Unixy ones [so we can punt on which + one is the right one to use]. */ + +/* Initial and increment values for cygwin's fd table */ +#define NOFILE_INCR 32 + +#ifdef __cplusplus +extern "C" { +#endif +#include + +#define STD_RBITS S_IRUSR | S_IRGRP | S_IROTH +#define STD_WBITS S_IWUSR +#define STD_XBITS S_IXUSR | S_IXGRP | S_IXOTH + +#define O_NOSYMLINK 0x080000 +#define O_DIROPEN 0x100000 + +#ifdef __cplusplus +} +#endif + +/*************************** Environment ******************************/ + +/* The structure below is used to control conversion to/from posix-style + * file specs. Currently, only PATH and HOME are converted, but PATH + * needs to use a "convert path list" function while HOME needs a simple + * "convert to posix/win32". For the simple case, where a calculated length + * is required, just return MAX_PATH. *FIXME* + */ +struct win_env + { + const char *name; + size_t namelen; + char *posix; + char *native; + int (*toposix) (const char *, char *); + int (*towin32) (const char *, char *); + int (*posix_len) (const char *); + int (*win32_len) (const char *); + void add_cache (const char *in_posix, const char *in_native = NULL); + const char * get_native () {return native ? native + namelen : NULL;} + }; + +win_env *getwinenv (const char *name, const char *posix = NULL); + +char *winenv (const char * const *); +extern char **__cygwin_environ; + +/* The title on program start. */ +extern char *old_title; +extern BOOL display_title; + + +/*************************** errno manipulation ******************************/ + +void seterrno_from_win_error (const char *file, int line, int code); +void seterrno (const char *, int line); + +#define __seterrno() seterrno (__FILE__, __LINE__) +#define __seterrno_from_win_error(val) seterrno_from_win_error (__FILE__, __LINE__, val) +#undef errno +#define errno dont_use_this_since_were_in_a_shared library +#define set_errno(val) (_impure_ptr->_errno = (val)) +#define get_errno() (_impure_ptr->_errno) +extern "C" void __stdcall set_sig_errno (int e); + +class save_errno + { + int saved; + public: + save_errno () {saved = get_errno ();} + save_errno (int what) {saved = get_errno (); set_errno (what); } + void set (int what) {set_errno (what); saved = what;} + void reset () {saved = get_errno ();} + ~save_errno () {set_errno (saved);} + }; + +extern const char *__sp_fn; +extern int __sp_ln; diff --git a/winsup/cygwin/winver.rc b/winsup/cygwin/winver.rc new file mode 100644 index 000000000..160428f19 --- /dev/null +++ b/winsup/cygwin/winver.rc @@ -0,0 +1,53 @@ +#include +#include + +#define STRINGIFY1(x) #x +#define STRINGIFY(x) STRINGIFY1(x) + +#define CYGWIN_DLL_NAME CYGWIN_VERSION_DLL_IDENTIFIER STRINGIFY(.dll) + +#define CYGWIN_REGISTRY_KEY CYGWIN_INFO_CYGNUS_REGISTRY_NAME "\\" \ + CYGWIN_INFO_CYGWIN_REGISTRY_NAME + +#define CYGWIN_API_VERSION STRINGIFY(CYGWIN_VERSION_API_MAJOR) "." \ + STRINGIFY(CYGWIN_VERSION_API_MINOR) + +#define CYGWIN_BUILD_DATE_TIME STRINGIFY(CYGWIN_BUILD_DATE) " " \ + STRINGIFY(CYGWIN_BUILD_TIME) + +VS_VERSION_INFO VERSIONINFO + FILEVERSION CYGWIN_VERSION_DLL_MAJOR,CYGWIN_VERSION_DLL_MINOR,0,0 + PRODUCTVERSION CYGWIN_VERSION_DLL_MAJOR,CYGWIN_VERSION_DLL_MINOR,0,0 + FILEFLAGSMASK 0x3fL +#ifdef DEBUGGING + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "Cygnus Solutions" + VALUE "FileDescription", "Cygwin\256 POSIX Emulation DLL" + VALUE "FileVersion", STRINGIFY(CYGWIN_VERSION) + VALUE "InternalName", CYGWIN_DLL_NAME + VALUE "LegalCopyright", "Copyright \251 Cygnus Solutions. 1996-1999" + VALUE "OriginalFilename", CYGWIN_DLL_NAME + VALUE "ProductName", "Cygwin" + VALUE "ProductVersion", STRINGIFY(CYGWIN_VERSION) + VALUE "APIVersion", CYGWIN_API_VERSION + VALUE "SharedMemoryVersion", STRINGIFY(CYGWIN_VERSION_SHARED_DATA) + VALUE "RegistryKey", CYGWIN_REGISTRY_KEY + VALUE "BuildDate", CYGWIN_BUILD_DATE_TIME + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END -- cgit v1.2.3