Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin')
-rw-r--r--winsup/cygwin/CYGWIN_LICENSE46
-rw-r--r--winsup/cygwin/ChangeLog229
-rw-r--r--winsup/cygwin/ChangeLog-1995177
-rw-r--r--winsup/cygwin/ChangeLog-19962031
-rw-r--r--winsup/cygwin/ChangeLog-19972800
-rw-r--r--winsup/cygwin/ChangeLog-19984490
-rw-r--r--winsup/cygwin/ChangeLog-19993552
-rw-r--r--winsup/cygwin/Makefile.in341
-rw-r--r--winsup/cygwin/ROADMAP129
-rw-r--r--winsup/cygwin/acconfig.h15
-rw-r--r--winsup/cygwin/ansi.sgml59
-rw-r--r--winsup/cygwin/assert.cc50
-rw-r--r--winsup/cygwin/config.h.in38
-rw-r--r--winsup/cygwin/config/i386/longjmp.c51
-rw-r--r--winsup/cygwin/config/i386/makefrag17
-rw-r--r--winsup/cygwin/config/i386/profile.h58
-rw-r--r--winsup/cygwin/config/i386/setjmp.c48
-rwxr-xr-xwinsup/cygwin/configure2335
-rw-r--r--winsup/cygwin/configure.in229
-rw-r--r--winsup/cygwin/cygwin.din1051
-rw-r--r--winsup/cygwin/dcrt0.cc1063
-rw-r--r--winsup/cygwin/debug.cc326
-rw-r--r--winsup/cygwin/debug.h69
-rw-r--r--winsup/cygwin/delqueue.cc99
-rw-r--r--winsup/cygwin/dir.cc340
-rw-r--r--winsup/cygwin/dlfcn.cc236
-rw-r--r--winsup/cygwin/dll_init.cc499
-rw-r--r--winsup/cygwin/dll_init.h102
-rw-r--r--winsup/cygwin/dll_init.sgml11
-rw-r--r--winsup/cygwin/dtable.cc603
-rw-r--r--winsup/cygwin/dtable.sgml20
-rw-r--r--winsup/cygwin/environ.cc567
-rw-r--r--winsup/cygwin/errno.cc669
-rw-r--r--winsup/cygwin/exceptions.cc1066
-rw-r--r--winsup/cygwin/exec.cc204
-rw-r--r--winsup/cygwin/external.cc107
-rw-r--r--winsup/cygwin/external.sgml16
-rw-r--r--winsup/cygwin/fcntl.cc106
-rw-r--r--winsup/cygwin/fhandler.cc1501
-rw-r--r--winsup/cygwin/fhandler.h804
-rw-r--r--winsup/cygwin/fhandler_console.cc1387
-rw-r--r--winsup/cygwin/fhandler_floppy.cc90
-rw-r--r--winsup/cygwin/fhandler_raw.cc495
-rw-r--r--winsup/cygwin/fhandler_serial.cc883
-rw-r--r--winsup/cygwin/fhandler_tape.cc829
-rw-r--r--winsup/cygwin/fhandler_termios.cc293
-rw-r--r--winsup/cygwin/fhandler_tty.cc1070
-rw-r--r--winsup/cygwin/fhandler_windows.cc145
-rw-r--r--winsup/cygwin/fhandler_zero.cc58
-rw-r--r--winsup/cygwin/fork.cc625
-rw-r--r--winsup/cygwin/gcrt0.c41
-rw-r--r--winsup/cygwin/glob.c871
-rw-r--r--winsup/cygwin/gmon.c277
-rw-r--r--winsup/cygwin/gmon.h166
-rw-r--r--winsup/cygwin/grp.cc283
-rw-r--r--winsup/cygwin/heap.cc140
-rw-r--r--winsup/cygwin/include/a.out.h421
-rw-r--r--winsup/cygwin/include/arpa/ftp.h109
-rw-r--r--winsup/cygwin/include/arpa/inet.h25
-rw-r--r--winsup/cygwin/include/arpa/telnet.h322
-rw-r--r--winsup/cygwin/include/asm/byteorder.h93
-rw-r--r--winsup/cygwin/include/asm/socket.h58
-rw-r--r--winsup/cygwin/include/asm/types.h13
-rw-r--r--winsup/cygwin/include/cygwin/acl.h81
-rw-r--r--winsup/cygwin/include/cygwin/cygwin_dll.h96
-rw-r--r--winsup/cygwin/include/cygwin/icmp.h1
-rw-r--r--winsup/cygwin/include/cygwin/if.h74
-rw-r--r--winsup/cygwin/include/cygwin/in.h188
-rw-r--r--winsup/cygwin/include/cygwin/mtio.h190
-rw-r--r--winsup/cygwin/include/cygwin/rdevio.h30
-rw-r--r--winsup/cygwin/include/cygwin/socket.h152
-rw-r--r--winsup/cygwin/include/cygwin/sockios.h1
-rw-r--r--winsup/cygwin/include/cygwin/types.h1
-rw-r--r--winsup/cygwin/include/cygwin/uio.h1
-rw-r--r--winsup/cygwin/include/cygwin/version.h159
-rw-r--r--winsup/cygwin/include/dlfcn.h41
-rw-r--r--winsup/cygwin/include/exceptions.h120
-rw-r--r--winsup/cygwin/include/fcntl.h7
-rw-r--r--winsup/cygwin/include/features.h1
-rw-r--r--winsup/cygwin/include/getopt.h66
-rw-r--r--winsup/cygwin/include/glob.h111
-rw-r--r--winsup/cygwin/include/icmp.h1
-rw-r--r--winsup/cygwin/include/io.h28
-rw-r--r--winsup/cygwin/include/lastlog.h12
-rw-r--r--winsup/cygwin/include/limits.h144
-rw-r--r--winsup/cygwin/include/mapi.h102
-rw-r--r--winsup/cygwin/include/memory.h7
-rw-r--r--winsup/cygwin/include/mntent.h35
-rw-r--r--winsup/cygwin/include/net/if.h6
-rw-r--r--winsup/cygwin/include/netdb.h167
-rw-r--r--winsup/cygwin/include/netinet/in.h6
-rw-r--r--winsup/cygwin/include/netinet/ip.h6
-rw-r--r--winsup/cygwin/include/netinet/ip_icmp.h6
-rw-r--r--winsup/cygwin/include/paths.h9
-rw-r--r--winsup/cygwin/include/pthread.h92
-rw-r--r--winsup/cygwin/include/strings.h6
-rw-r--r--winsup/cygwin/include/sys/acl.h17
-rw-r--r--winsup/cygwin/include/sys/cdefs.h12
-rw-r--r--winsup/cygwin/include/sys/copying.dj41
-rw-r--r--winsup/cygwin/include/sys/cygwin.h44
-rw-r--r--winsup/cygwin/include/sys/file.h31
-rw-r--r--winsup/cygwin/include/sys/ioctl.h20
-rw-r--r--winsup/cygwin/include/sys/mman.h40
-rw-r--r--winsup/cygwin/include/sys/mount.h25
-rw-r--r--winsup/cygwin/include/sys/mtio.h11
-rw-r--r--winsup/cygwin/include/sys/resource.h40
-rw-r--r--winsup/cygwin/include/sys/select.h35
-rw-r--r--winsup/cygwin/include/sys/smallprint.h17
-rw-r--r--winsup/cygwin/include/sys/socket.h38
-rw-r--r--winsup/cygwin/include/sys/strace.h96
-rw-r--r--winsup/cygwin/include/sys/syslog.h73
-rw-r--r--winsup/cygwin/include/sys/sysmacros.h8
-rw-r--r--winsup/cygwin/include/sys/termio.h2
-rw-r--r--winsup/cygwin/include/sys/termios.h295
-rw-r--r--winsup/cygwin/include/sys/ttychars.h1
-rw-r--r--winsup/cygwin/include/sys/uio.h25
-rw-r--r--winsup/cygwin/include/sys/un.h16
-rw-r--r--winsup/cygwin/include/sys/utsname.h23
-rw-r--r--winsup/cygwin/include/sys/vfs.h28
-rw-r--r--winsup/cygwin/include/sys/wait.h63
-rw-r--r--winsup/cygwin/include/syslog.h6
-rw-r--r--winsup/cygwin/include/termio.h6
-rw-r--r--winsup/cygwin/include/tzfile.h10
-rw-r--r--winsup/cygwin/init.cc58
-rw-r--r--winsup/cygwin/ioctl.cc44
-rw-r--r--winsup/cygwin/malloc_wrapper.cc221
-rw-r--r--winsup/cygwin/mcount.c174
-rw-r--r--winsup/cygwin/misc-std.sgml73
-rwxr-xr-xwinsup/cygwin/mkvers.sh165
-rw-r--r--winsup/cygwin/mmap.cc474
-rw-r--r--winsup/cygwin/net.cc1827
-rw-r--r--winsup/cygwin/ntea.cc335
-rw-r--r--winsup/cygwin/passwd.cc275
-rw-r--r--winsup/cygwin/path.cc2836
-rw-r--r--winsup/cygwin/path.h98
-rw-r--r--winsup/cygwin/path.sgml205
-rw-r--r--winsup/cygwin/pinfo.cc413
-rw-r--r--winsup/cygwin/pipe.cc93
-rw-r--r--winsup/cygwin/posix.sgml88
-rw-r--r--winsup/cygwin/profil.c173
-rw-r--r--winsup/cygwin/profil.h44
-rw-r--r--winsup/cygwin/pthread.cc203
-rw-r--r--winsup/cygwin/regexp/COPYRIGHT22
-rw-r--r--winsup/cygwin/regexp/README84
-rw-r--r--winsup/cygwin/regexp/regexp.h24
-rw-r--r--winsup/cygwin/regexp/regmagic.h7
-rw-r--r--winsup/cygwin/registry.cc176
-rw-r--r--winsup/cygwin/resource.cc94
-rw-r--r--winsup/cygwin/scandir.cc101
-rw-r--r--winsup/cygwin/security.cc2084
-rw-r--r--winsup/cygwin/select.cc1380
-rw-r--r--winsup/cygwin/select.h56
-rw-r--r--winsup/cygwin/shared.cc287
-rw-r--r--winsup/cygwin/shared.sgml17
-rw-r--r--winsup/cygwin/signal.cc367
-rw-r--r--winsup/cygwin/sigproc.cc1345
-rw-r--r--winsup/cygwin/sigproc.h66
-rw-r--r--winsup/cygwin/smallprint.c229
-rw-r--r--winsup/cygwin/spawn.cc980
-rw-r--r--winsup/cygwin/strace.cc409
-rw-r--r--winsup/cygwin/strsep.cc65
-rw-r--r--winsup/cygwin/sync.cc112
-rw-r--r--winsup/cygwin/sync.h48
-rw-r--r--winsup/cygwin/syscalls.cc1939
-rw-r--r--winsup/cygwin/sysconf.cc62
-rw-r--r--winsup/cygwin/syslog.cc395
-rw-r--r--winsup/cygwin/termios.cc274
-rw-r--r--winsup/cygwin/thread.cc1001
-rw-r--r--winsup/cygwin/thread.h312
-rw-r--r--winsup/cygwin/times.cc540
-rw-r--r--winsup/cygwin/tty.cc417
-rw-r--r--winsup/cygwin/tz_posixrules.h48
-rw-r--r--winsup/cygwin/uinfo.cc200
-rw-r--r--winsup/cygwin/uname.cc110
-rw-r--r--winsup/cygwin/wait.cc113
-rw-r--r--winsup/cygwin/window.cc231
-rw-r--r--winsup/cygwin/winsup.h595
-rw-r--r--winsup/cygwin/winver.rc53
178 files changed, 59860 insertions, 0 deletions
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 <cgf@cygnus.com>
+
+ * Makefile.in: cygrun needs libshell32.a.
+
+Sun Feb 6 22:17:58 2000 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * Makefile.in: Fix install target so that directories will be created
+ when necessary.
+
+Sun Feb 6 18:12:17 2000 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * dcrt0.cc (isquote): Convert to inline function.
+
+Sat Feb 5 00:26:01 2000 Christopher Faylor <cgf@cygnus.com>
+
+ 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 <salvador@inti.gov.ar>
+
+ * include/io.h: add return type to setmode()
+
+2000-01-27 DJ Delorie <dj@cygnus.com>
+
+ * include/netdb.h (h_errno): change __imp_ to dllimport
+ * cygwin.din (reent_data): add DATA
+
+Thu Jan 27 01:07:14 2000 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * sync.h (new_muto): Workaround change in gcc behavior.
+
+Wed Jan 26 12:57:13 2000 Christopher Faylor <cgf@cygnus.com>
+
+ * Makefile.in: Ensure that all required libraries are built prior
+ to linking cygrun.exe.
+
+Tue Jan 25 21:26:57 2000 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <dj@cygnus.com>
+
+ * ROADMAP: new
+
+2000-01-11 DJ Delorie <dj@cygnus.com>
+
+ * 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 <dj@cygnus.com>
+
+ * mmap.cc (mmap): MSDN says *one* of FILE_MAP_*, fix flags for
+ MAP_PRIVATE.
+
+Mon Jan 10 01:11:00 2000 Corinna Vinschen <corinna@vinschen.de>
+
+ * 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 <corinna@vinschen.de>
+
+ * fhandler.cc (get_file_owner): Use of ReadSD() instead of
+ GetFileSecurity().
+ (get_file_group): Ditto.
+
+Sun Jan 9 15:43:07 2000 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <corinna@vinschen.de>
+
+ * 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 <cgf@cygnus.com>
+
+ * mkvers.h: Reorg fix.
+
+Sat Jan 8 20:00:00 2000 Corinna Vinschen <corinna@vinschen.de>
+
+ * 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 <cgf@cygnus.com>
+
+ * Makefile.in: Add cygwin DLL specific CFLAGS define.
+
+Fri Jan 7 21:01:57 2000 Christopher Faylor <cgf@cygnus.com>
+
+ * exceptions.cc (interrupt_on_return): Properly coerce assignment of
+ sigsave.func.
+
+2000-01-07 Mumit Khan <khan@xraylith.wisc.edu>
+
+ * 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 <cgf@cygnus.com>
+
+ * dcrt0.cc (dll_crt0): Allow signal handling for dynamically loaded
+ case.
+
+Thu Jan 6 00:30:12 2000 Corinna Vinschen <corinna@vinschen.de>
+
+ * 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 <cgf@cygnus.com>
+
+ 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 <corinna@vinschen.de>
+
+ * 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 <sac@slash.cygnus.com>
+
+ 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 <meissner@tiktok.cygnus.com>
+
+ * 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 <sac@slash.cygnus.com>
+
+ 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<letter> 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 <sac@slash.cygnus.com>
+
+ * 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 <sac@slash.cygnus.com>
+
+ * 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 <sac@slash.cygnus.com>
+
+ * 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 <sac@slash.cygnus.com>
+
+ * syscalls.cc (_rename): Fix for win95.
+
+Fri Oct 27 20:53:47 1995 steve chamberlain <sac@slash.cygnus.com>
+
+ * Everything changed.
+
+Thu Oct 19 10:47:52 1995 steve chamberlain <sac@slash.cygnus.com>
+
+ * 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 <sac@slash.cygnus.com>
+
+ * Makefile.in: Cope with target configury.
+
+Wed Oct 18 15:34:49 1995 steve chamberlain <sac@slash.cygnus.com>
+
+ * 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 <jra@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * syscalls.cc (_rename): fix code so we really do
+ return -1 if _rename fails.
+
+Tue Dec 17 12:12:29 1996 Jeremy Allison <jra@cygnus.com>
+
+ * fhandler.cc: Added Sergeys patch for FakeReadFile.
+ * cygwin.din: Re-ordered network calls.
+
+Mon Dec 16 16:47:26 1996 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <jra@cygnus.com>
+
+ * path.cc: Added support for UNC paths.
+
+Fri Dec 13 10:56:21 1996 Jeremy Allison <jra@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * version.h: bump CYGWIN_DLL_VERSION_MINOR to 4
+
+ patch from Marcus Daniels <marcus@sysc.pdx.edu>:
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * version.h: increment minor dll number in conjunction
+ with gnu-win32 beta 17 release
+
+Tue Dec 3 15:05:57 1996 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * include/sys/copying.dj: new file whose presence is
+ required by include/sys/file.h
+
+Tue Dec 3 13:37:27 1996 Geoffrey Noer <noer@cygnus.com>
+
+ Throughout all Cygnus-developped source files: put all
+ code under GPL
+
+Tue Dec 3 10:54:01 1996 Jeremy Allison <jra@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * include/utime.h: add ifdef _UTIME_U wrapper around header
+
+Mon Dec 2 15:45:46 1996 Jeremy Allison <jra@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * Makefile.in: change rules around so new-cygwin.dll is
+ only rebuilt when necessary
+ * spawn.cc: include <stdlib.h>
+
+Mon Nov 18 21:08:15 1996 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <jra@cygnus.com>
+
+ * cygwin.din: Added readv
+ * syscalls.cc: Added readv code.
+ * syscalls.h: Added readv prototype.
+
+Wed Nov 13 15:55:14 1996 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * dcrt0.cc
+ * dirsearch.cc
+ * malloc.cc
+ * passwd.cc
+ * path.cc,
+ * pinfo.cc
+ * syslog.cc
+ * utils/kill.cc
+ * utils/cygwin.cc:
+ need to #include <stdlib.h> 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 <jra@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <jra@cygnus.com>
+
+ * 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 <jra@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * cygwin.din: also export "_execl = execl" and the same
+ for _execle and _execlp
+
+Thu Oct 24 01:43:29 1996 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <stdlib.h>
+ * 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 <jra@cygnus.com>
+
+ * 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 <jra@cygnus.com>
+
+ * hinfo.cc: Removed previous change. This is not the
+ correct place to flush input events.
+
+Tue Oct 22 09:25:32 1996 Jeremy Allison <jra@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <jra@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * Makefile.in: install headers from new Windows32 dir
+
+Sat Oct 19 00:47:58 1996 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * key.cc: remove extra blank lines, change ASCIICHAR to AsciiChar
+ * registry.cc: remove #include <winbase.h> since it's already
+ included in windows.h
+
+Tue Oct 15 09:51:48 1996 Jeremy Allison <jra@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <jra@cygnus.com>
+
+ * 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 <jra@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <jra@cygnus.com>
+
+ * dcrt0.cc (dll_crt_1): Moved initialization of _reent to correct
+ position.
+
+Fri Sep 27 14:24:05 1996 Jeremy Allison <jra@cygnus.com>
+
+ * 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 <jra@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * select.cc: change long millisec to unsigned int,
+ respaced file
+
+ patch from Sergey Okhapkin <sos@prospect.com.ru>:
+ * 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 <jra@cygnus.com>
+
+ * fhandler.cc (fhandler_base::read): rewrite text mode read
+
+Fri Sep 13 14:58:17 1996 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <jra@cygnus.com>
+
+ * 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 <jra@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ patch from Sergey Okhapkin <sos@prospect.com.ru>:
+ * 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 <noer@cygnus.com>
+
+ * syscalls.cc (system): fix system call
+
+Fri Sep 6 09:33:13 1996 Doug Evans <dje@canuck.cygnus.com>
+
+ * 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 <dje@canuck.cygnus.com>
+
+ * fork.cc: Don't include <ctype.h>. Delete find_exec and support.
+ * spawn.cc: Include <ctype.h>. 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 <dje@canuck.cygnus.com>
+
+ * path.cc (readlink): Make more bulletproof.
+
+Wed Aug 28 16:44:24 1996 Geoffrey Noer <noer@cygnus.com>
+
+ * syscalls.cc (system): use execlp
+ * public release beta 16 made
+
+Tue Aug 27 09:58:14 1996 Doug Evans <dje@canuck.cygnus.com>
+
+ * version.h (CYGWIN_DLL_VERSION_MINOR): Bump up to 2.
+
+Mon Aug 26 15:12:44 1996 Geoffrey Noer <noer@cygnus.com>
+
+ * syscalls.cc (system): added basic system() call.
+
+Mon Aug 26 13:46:30 1996 Doug Evans <dje@canuck.cygnus.com>
+
+ * 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 <fcntl.h>.
+ (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 <jra@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * registry.cc: fix new registry code
+ * syscalls.cc: make Windows95 check function extern "C"
+
+Wed Aug 21 16:15:47 1996 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <jra@cygnus.com>
+
+ * 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 <dje@canuck.cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * dirsearch.cc: reformatted, removed a couple of gotos
+
+Thu Aug 15 17:56:08 1996 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <wilson@cygnus.com>
+
+ * config/i386/longjmp.c: Increment %eax if it is zero.
+
+Wed Aug 7 15:51:04 1996 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <dje@canuck.cygnus.com>
+
+ * libccrt0.cc (__version): Deleted, unused.
+
+ * uname.c (uname): Print CYGWIN_DLL_VERSION is version field.
+
+Mon Jul 15 16:48:29 1996 Doug Evans <dje@canuck.cygnus.com>
+
+ * version.h (CYGWIN_DLL_VERSION_MINOR): Bump up to 1.
+
+ Path handling clean up, pass 2 (use //<letter>, not /.<letter>.).
+ * 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 //<letter>, not /.<letter>.
+ (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 <meissner@tiktok.cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * Makefile.in: also make install in utils subdir so "mount"
+ et al gets installed.
+
+Thu Jul 11 17:53:31 1996 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <dje@canuck.cygnus.com>
+
+ * 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 <dje@canuck.cygnus.com>
+
+ * 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 <dje@canuck.cygnus.com>
+
+ * 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 <dje@canuck.cygnus.com>
+
+ * 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 <dje@canuck.cygnus.com>
+
+ * 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 <dje@canuck.cygnus.com>
+
+ * 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 <dje@canuck.cygnus.com>
+
+ * 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 <eichin@cygnus.com>
+
+ * 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 <dje@canuck.cygnus.com>
+
+ * dcrt0.cc (dll_crt0_1): Convert argv[0] to posix style if necessary.
+
+Sun Jun 23 17:21:41 1996 Doug Evans <dje@canuck.cygnus.com>
+
+ * 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 <dje@canuck.cygnus.com>
+
+ * 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 <dje@canuck.cygnus.com>
+
+ * 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): /.<letter>. is a drive spec.
+ (path_conv::path_conv): Likewise.
+ (mount_info::win32_path_to_posix_path): Convert unknown drives to
+ /.<letter>. 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 <dje@canuck.cygnus.com>
+
+ * 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 <dje@canuck.cygnus.com>
+
+ 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 <dje@canuck.cygnus.com>
+
+ * register.h, registry.cc: Whitespace cleanup.
+
+Thu Jun 13 20:57:28 1996 Doug Evans <dje@canuck.cygnus.com>
+
+ * Makefile.in (install): Install cygwin.dll in $(bindir).
+
+Tue Jun 11 13:46:17 1996 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <dje@canuck.cygnus.com>
+
+ * 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 <onno@stack.urc.tue.nl>.
+ (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 <dje@canuck.cygnus.com>
+
+ * 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 <krk@cygnus.com>
+
+ * dcrt0.cc (dll_crt0_1): Removed reference to reent_data._next.
+
+Tue Jun 4 15:52:29 1996 Geoffrey Noer <noer@cygnus.com>
+
+ * include/winkernel.h: fixed typo
+
+Tue May 28 13:08:25 1996 Doug Evans <dje@canuck.cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <dje@canuck.cygnus.com>
+
+ * 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 <eichin@cygnus.com>
+
+ * 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 <wilson@chestnut.cygnus.com>
+
+ * fhandler.h (class fhandler_base): Use MAXPATHLEN not 100 for size
+ of array name.
+
+Wed May 15 11:14:46 1996 Doug Evans <dje@canuck.cygnus.com>
+
+ * 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 <dje@canuck.cygnus.com>
+
+ * 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 <eichin@cygnus.com>
+
+ * 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 <eichin@cygnus.com>
+
+ * 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 <eichin@cygnus.com>
+
+ * 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 <eichin@cygnus.com>
+
+ * 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 <sac>'s changes of 4/20 which were
+ accidentally backed out on 4/24.
+
+Tue May 7 05:29:42 1996 Mark Eichin <eichin@cygnus.com>
+
+ * 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 <eichin@cygnus.com>
+
+ * 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 <eichin@cygnus.com>
+
+ * 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 <sac@dilithium.transmeta.com>
+
+ * winsup.h (pinfo, pinfo_list): Remove dummy item.
+ * fork.cc (*): Revert changes of Apr 2.
+
+Sun Apr 21 17:00:14 1996 Steve Chamberlain <sac@slash.cygnus.com>
+
+ * wait.cc (wait_for_any): Fix the wait heuristic.
+
+Sat Apr 20 13:22:03 1996 Steve Chamberlain <sac@slash.cygnus.com>
+
+ * 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 <dje@canuck.cygnus.com>
+
+ * Makefile.in (glob/libglob.a): Pass -I so glob.c finds right dirent.h.
+
+Wed Apr 10 16:13:30 1996 steve chamberlain <sac@slash.cygnus.com>
+
+ * 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 <sac@slash.cygnus.com>
+
+ * 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 <file> and <file.exe>.
+ * wait.cc (wait_for_any): Keep waiting if WaitForMultipleObject
+ returns invalid result.
+
+Tue Apr 2 12:45:35 1996 steve chamberlain <sac@slash.cygnus.com>
+
+ * 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 <sac@slash.cygnus.com>
+
+ * 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 <sac@slash.cygnus.com>
+
+ * exceptions.cc (__cygwin_exception_handler): re-export.
+
+Fri Mar 22 16:49:29 1996 Michael Meissner <meissner@tiktok.cygnus.com>
+
+ * 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 <meissner@tiktok.cygnus.com>
+
+ * 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 <dje@charmed.cygnus.com>
+
+ * include/winkernel.h (FlushFileBuffers): Declare.
+
+Tue Mar 12 11:16:32 1996 Michael Meissner <meissner@tiktok.cygnus.com>
+
+ * 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 <sac@slash.cygnus.com>
+
+ * 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 <sac@slash.cygnus.com>
+
+ * 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 <meissner@tiktok.cygnus.com>
+
+ * 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 <meissner@tiktok.cygnus.com>
+
+ * 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 <sac@slash.cygnus.com>
+
+ * 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 <meissner@tiktok.cygnus.com>
+
+ * configure.in (ALLOCA for powerpc): Add __allocate_stack.
+
+Wed Feb 7 16:41:18 1996 Steve Chamberlain <sac@slash.cygnus.com>
+
+ 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 <sac@slash.cygnus.com>
+
+ * 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 <sac@slash.cygnus.com>
+
+ * *.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 <sac@slash.cygnus.com>
+
+ * 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 <sac@slash.cygnus.com>
+
+ * 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 <krk@cygnus.com>
+
+ * Makefile.in (DLL_OFILES): added ppc-stub.o
+
+Thu Jan 25 09:33:24 1996 Steve Chamberlain <sac@slash.cygnus.com>
+
+ * malloc.cc (malloc, free, realloc): Hack for ppc.
+
+Wed Jan 24 20:22:42 1996 Steve Chamberlain <sac@slash.cygnus.com>
+
+ * 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 <sac@slash.cygnus.com>
+
+ * 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 <sac@slash.cygnus.com>
+
+ * 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 <sac@slash.cygnus.com>
+
+ * 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 <sac@slash.cygnus.com>
+
+ * select.cc: New file.
+ * Makefile.in: Cope with it.
+
+Tue Jan 2 08:58:58 1996 steve chamberlain <sac@slash.cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <ian@cygnus.com>
+
+ * regexp/Makefile.in (tooldir): New variable.
+ (install): Install regexp.h.
+
+Tue Dec 30 19:52:46 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * 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 <ian@cygnus.com>
+
+ * 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 <ian@cygnus.com>
+
+ * 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 <ian@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ patch from msnyder@cygnus.com (Michael Snyder):
+ * heap.cc (_sbrk): handle situation where newalloc < incr
+
+Mon Dec 15 16:40:07 1997 Geoffrey Noer <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <ian@cygnus.com>
+
+ * fork.cc: Include <malloc.h>.
+ (cygwin_fork_helper1): Call __malloc_copy after copying the stack
+ and heap to the child.
+
+Thu Dec 11 15:14:40 1997 Geoffrey Noer <noer@cygnus.com>
+
+ 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 <ian@cygnus.com>
+
+ * include/sys/termios.h (IXANY): Correct value.
+ (PARMRK): Define again.
+
+Wed Dec 10 00:05:23 1997 Geoffrey Noer <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * cygwin.din: remove crypt
+ * syscalls.cc (crypt): remove crypt stub
+
+Sun Nov 23 17:34:42 1997 Geoffrey Noer <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * Makefile.in: Add spaces after colons in rules for make
+
+Mon Nov 17 22:35:25 1997 Geoffrey Noer <noer@cygnus.com>
+
+ 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 <noer@rtl.cygnus.com>
+
+ 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 <noer@rtl.cygnus.com>
+
+ 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 <noer@rtl.cygnus.com>
+
+ 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 <noer@rtl.cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <ian@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * exceptions.cc (__cygwin32_exception_handler): don't
+ print "In cygwin32_except_handler" for exceptions Cygwin32
+ isn't going to handle. Print "(progname PID) Exception: <type>"
+ to console. Redirect all detailed information including the
+ stack trace to <progname>.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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <tromey@cygnus.com>
+
+ * include/mapi.h: New file.
+ * sysdef/i386/mapi32.def (MAPISendMail@20): New export.
+
+Thu Oct 30 15:08:13 1997 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * Makefile.in: change DLL_NAME to cygwin97r2.dll
+
+Mon Oct 20 20:16:47 1997 Geoffrey Noer <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * cygwin.din: restore __main as an export
+
+Mon Oct 13 18:41:09 1997 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <tromey@cygnus.com>
+
+ * 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 <ian@cygnus.com>
+
+ * include/Windows32/Base.h: Only typedef CHAR, SHORT, and LONG if
+ VOID is not defined
+
+Thu Oct 9 00:46:40 1997 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ Oops. ../libio refers to objdir and is not the same
+ as $(srcdir)/../libio.
+
+Thu Oct 2 23:12:19 1997 Geoffrey Noer <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * spawn.cc: add missing cast to debug printf
+
+Thu Sep 25 16:14:17 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * path.cc (conv_to_win32_path): Call backslashify on a win32
+ path.
+
+Tue Sep 23 17:58:17 1997 Geoffrey Noer <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <ian@cygnus.com>
+
+ * 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 <ian@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ Merge in the following changes:
+
+ Thu Aug 21 13:30:12 1997 Ian Lance Taylor <ian@cygnus.com>
+ * 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 <sys/types.h>.
+ (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 <ian@cygnus.com>
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * cygwin.din: export random, srandom
+
+Wed Aug 20 16:56:39 1997 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * dcrt0.cc: respace, modify some comments slightly
+
+Tue Aug 19 16:17:57 1997 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <rob@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * times.cc: add missing extern "C"s around exported functions
+
+Thu Aug 14 17:00:32 1997 Geoffrey Noer <noer@cygnus.com>
+
+ 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 <ian@cygnus.com>
+
+ * 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 <ian@cygnus.com>
+
+ * 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 <ian@cygnus.com>
+
+ * 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 <ian@cygnus.com>
+
+ * 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 <cagney@b1.cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * net.cc (cygwin32_shutdown): New implementation to replace
+ stub previously present
+
+Tue Jul 22 14:59:22 1997 Geoffrey Noer <noer@cygnus.com>
+
+ * cygwin.din: remove random, srandom
+ * Makefile.in: remove random/srandom-related lines
+
+Tue Jul 22 14:10:32 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * path.cc (realpath): New C function.
+ * cygwin.din: Export realpath.
+
+ * cygwin.din: Export srandom.
+
+Wed Jul 9 12:26:03 1997 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <ian@cygnus.com>
+
+ * libcmain.cc (main): Pass wShowWindow field from startup info to
+ WinMain.
+
+Mon Jul 7 17:47:48 1997 Geoffrey Noer <noer@cygnus.com>
+
+ * path.cc: respace, reword comments
+ * times.cc (utimes): add FIXME
+
+Tue Jun 24 18:31:27 1997 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <ian@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ respaced console.cc, fhandler.cc, syscalls.cc, pinfo.cc,
+ fork.cc, spawn.cc
+
+Tue Jun 17 14:57:09 1997 Geoffrey Noer <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * include/winsock.h: fix protection wrapper name
+
+Fri Jun 6 12:41:09 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * 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 <ian@cygnus.com>
+
+ * times.cc (gettimeofday): Check return values and set tz_dsttime
+ correctly.
+
+Wed Jun 4 00:04:33 1997 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <ian@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <ian@cygnus.com>
+
+ * times.cc (ftime): New function.
+ * cygwin.din: Export ftime.
+
+Mon Jun 2 14:34:00 1997 Geoffrey Noer <noer@cygnus.com>
+
+ 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 <ian@cygnus.com>
+
+ * utils/configure.in: Call AC_PROG_INSTALL.
+ * utils/configure: Rebuild.
+
+Mon Jun 2 11:44:14 1997 Geoffrey Noer <noer@cygnus.com>
+
+ * grp.cc (getgroups): new
+ * cygwin.din: export getgroups
+
+Fri May 30 16:47:38 1997 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <stdlib.h>, 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 <noer@cygnus.com>
+
+ * times.cc (gettimeofday): return 0 on success instead of 1
+ (utimes): init res to 0
+
+Wed May 21 11:29:24 1997 Geoffrey Noer <noer@cygnus.com>
+
+ * include/limits.h: define NGROUPS_MAX
+
+Tue May 20 14:13:59 1997 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ Public gnu-win32 beta 18 release made
+
+Sun May 4 15:34:07 1997 Geoffrey Noer <noer@cygnus.com>
+
+ patch from Mikey <jeffdb@netzone.com>:
+ * console.cc (FakeReadFile): FlushConsoleInputBuffer if
+ flags & ENABLE_LINE_INPUT and then return ReadFile
+
+Fri May 2 10:53:10 1997 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * cygwin.din: remove libgcc2.a internal functions
+
+Mon Apr 28 14:57:04 1997 Michael Meissner <meissner@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ patch from Jeremy Allison <jra@cygnus.com>:
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <ian@cygnus.com>
+
+ * 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 <ian@cygnus.com>
+
+ * utils/Makefile.in (INSTALL): Change install.sh to install-sh.
+
+Mon Apr 14 12:33:22 1997 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <jra@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <jra@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * fhandler.h: fix typo
+ * fhandler.cc: check_execable_p should only take one arg now
+
+Mon Feb 3 16:16:39 1997 Jeremy Allison <jra@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <jra@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * mmap.cc: added missing copyright notice
+
+Tue Jan 14 12:51:12 1997 Jeremy Allison <jra@cygnus.com>
+
+ * 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 <jra@cygnus.com>
+
+ * 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 <jra@cygnus.com>
+
+ * 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 <jra@cygnus.com>
+
+ * 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 <jra@cygnus.com>
+
+ * 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 <jra@cygnus.com>
+
+ * 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 <dj@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * utils/mkpasswd.c: Include wchar.h.
+ * utils/mkgroup.c: Ditto.
+
+Tue Dec 29 12:53:23 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * Makefile.in: remove dep for libcerr.o
+
+Mon Dec 28 22:02:15 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ patch from Corinna Vinschen <corinna.vinschen@cityweb.de>:
+ * include/Windows32/CommonFunction.h: Added proto for
+ NetUserChangePassword().
+
+Thu Dec 24 16:15:40 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * winsup.h: Reorganize include order to allow thread-safe build.
+
+Wed Dec 23 11:45:33 1998 DJ Delorie <dj@cygnus.com>
+
+ * 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 <dj@cygnus.com>
+
+ * times.cc (__to_clock_t): Change return value to unsigned long
+ long to prevent overflow.
+
+Tue Dec 22 19:37:55 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * pthread.cc: fix copyright header.
+ * shared.h: ditto.
+
+Fri Dec 18 19:21:30 1998 Geoffrey Noer <noer@cygnus.com>
+
+ patch from Corinna Vinschen <corinna.vinschen@cityweb.de>:
+ * 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 <noer@cygnus.com>
+
+ * include/pthread.h: clean up, remove C++-style comments,
+ remove pthread_getsequence_np proto.
+
+Fri Dec 18 15:26:33 1998 Christopher Faylor <cgf@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ * Makefile.in: Cleanup pthread usage.
+
+Fri Dec 18 14:35:59 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * Makefile.in: Remove obsolete header dependency for
+ thread-safe build.
+
+Fri Dec 18 14:16:04 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * exceptions.cc (sig_handle): Avoid suspending top-level
+ processes.
+ * trace.cc: Remove unneeded include.
+
+Thu Dec 17 19:19:53 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * cygwin.din: remove pthread_getsequence_np, _reent_clib
+
+Thu Dec 17 16:48:15 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * include/cygwin/version.h: correct two typos in comments
+
+Thu Dec 17 19:11:31 1998 Christopher Faylor <cgf@cygnus.com>
+
+ patch from Corinna Vinschen <corinna.vinschen@cityweb.de>:
+ * include/Windows32/Defines.h: Add values for using Windows
+ function `DeviceIoControl()'.
+
+Thu Dec 17 18:00:34 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ Merge in thread-safe branch changes.
+
+Wed Dec 16 22:54:16 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * pthread.cc: Include winsup.h.
+
+Wed Dec 16 22:54:16 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * thread.cc: Reformat.
+ * pthread.cc: New file.
+ * cygwin.din: Add pthread interface functions
+
+Wed Dec 16 22:54:16 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * include/shellapi.h: fix typo in DragQueryPoint proto.
+
+Mon Dec 14 12:37:43 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <corinna.vinschen@cityweb.de>:
+ * 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 <noer@cygnus.com>
+
+ * fhandler.cc (fhandler_disk_file::open): check for shell scripts
+ regardless of Win32 OS type.
+
+Sun Dec 6 19:38:11 1998 Christopher Faylor <cgf@cygnus.com>
+
+ patch from Corinna Vinschen <corinna.vinschen@cityweb.de>:
+ * fhandler_console.cc (fhandler_console::tcgetattr): Fix typo.
+ ISIG should be ored with c_lflag.
+
+Tue Dec 1 16:28:56 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * include/utmp.h: delete, moved to newlib/libc/sys/cygwin/sys.
+
+Thu Dec 3 15:41:51 1998 Geoffrey Noer <noer@cygnus.com>
+
+ Released 20.1 update.
+
+Thu Dec 3 22:24:18 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * mkvers.sh: Accomodate lack of timezone in date output so that
+ year shows up correctly.
+
+Mon Nov 30 14:30:51 1998 Jeff Johnston <jjohnstn@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ patch from Corinna Vinschen <corinna.vinschen@cityweb.de>:
+ * fhandler_console.cc (fhandler_console::ioctl):
+ Added ioctl commands TCGETA, TCSETA, TCSETAW, TCSETAF.
+
+Fri Nov 27 22:30:58 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * Makefile.in: Reinstate libwinspool.a/winspool.drv creation.
+
+Tue Nov 24 18:48:56 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * sigproc.cc (__release_signal_mutex): revert Nov 3d change.
+
+Sun Nov 22 17:04:44 1998 Christopher Faylor <cgf@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * Makefile.in: Use correct libpthread.a target when
+ thread-safe is enabled.
+
+Thu Nov 19 10:49:27 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * path.cc (path_conv): Correct error reporting.
+
+Wed Nov 18 20:07:50 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * utils/Makefile.in: remove termcap file install rule
+
+Wed Nov 18 18:14:18 1998 Geoffrey Noer <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * utils/ps.cc: include sys/cygwin.h, make pname buf
+ MAXPATH in size.
+
+ patch from Corinna Vinschen <corinna.vinschen@cityweb.de>:
+ * utils/ps.cc (main): converting windows paths to posix
+ paths in output.
+
+Wed Nov 18 15:34:46 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * include/wchar.h: include stddef.h.
+
+Wed Nov 18 17:39:15 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * environ.cc (environ_init): Fix incorrect TERM= detection.
+
+Tue Nov 17 17:28:09 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * gcrt0.c: include stdlib.h, add proto for monstartup.
+
+Tue Nov 17 16:47:42 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * include/wchar.h: add protos for wcslen and wcscmp.
+ * syscalls.cc: minor reformat.
+
+Tue Nov 17 15:38:45 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ patch from Mumit Khan <khan@xraylith.wisc.edu>:
+ * 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 <noer@cygnus.com>
+
+ * cygwin.din: export dll_noncygwin_dllcrt0.
+ * {libccrt0.cc, winsup.h}: minor reformat.
+
+Sat Nov 14 22:14:51 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * environ.cc (environ_init): Use sizeof for string lengths
+ rather than hard-coded values.
+
+ patch from Mumit Khan <khan@xraylith.wisc.edu>:
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * fork.cc (fork): No need for intermediate jmp_buf variable.
+
+ patch from Mumit Khan <khan@xraylith.wisc.edu>:
+ * 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 <noer@cygnus.com>
+
+ 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 <ctype.h> and <stdlib.h>.
+ (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 <ctype.h> and <stdlib.h>.
+ (enum_groups): return void, not int. Remove unused var rc.
+ * gmon.c: include <stdio.h> and <unistd.h>.
+ (_mcleanup): remove unused vars buf and profdir.
+
+Fri Nov 13 16:17:28 1998 Geoffrey Noer <noer@cygnus.com>
+
+ patch from Corinna Vinschen <corinna.vinschen@cityweb.de>:
+ * include/sys/sysmacros.h: new file, define major, minor, makedev
+
+Fri Nov 13 17:03:52 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ patch from Corinna Vinschen <corinna.vinschen@cityweb.de> and
+ Ron Parker <rdparker@butlermfg.org>:
+ * path.cc (mount_info::conv_to_win32_path): Refined recognition of
+ UNC devices.
+
+Fri Nov 13 12:37:00 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * Makefile.in: Fix a typo.
+
+Fri Nov 13 10:59:43 1998 DJ Delorie <dj@cygnus.com>
+
+ * Makefile.in: "make" uses new "ld -shared" by default internally.
+
+Fri Nov 13 00:58:38 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <khan@xraylith.wisc.edu>:
+ * 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 <dj@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <dj@cygnus.com>
+
+ * cygwin.din (getpwnam): remove duplicates
+
+Tue Nov 10 18:27:09 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ patch from Gary V. Vaughan <gvaughan@oranda.demon.co.uk>:
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * include/cygwin/version.h: up DLL version, bump API_MINOR to 2
+ to mark following change.
+
+ patch from Mumit Khan <khan@xraylith.wisc.edu>:
+ * cygwin.din: add exports for some of the newlib bessel
+ functions (j1, jn, y1, yn).
+
+Mon Nov 9 15:10:06 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * syscalls.cc (_link): rewrite FIXME.
+
+Mon Nov 9 14:51:03 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * errno.cc (strerror): add string for EDEADLOCK.
+
+ patch from Corinna Vinschen <corinna.vinschen@cityweb.de>:
+ * errno.cc (errmap[]): add END_OF_MEDIA and additional Win32
+ error codes.
+
+Sun Nov 8 21:28:01 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ patch from Corinna Vinschen <corinna.vinschen@cityweb.de>:
+ * 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 <cgf@cygnus.com>
+
+ * 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 <dj@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ patch from Kazuhiro Fujieda <fujieda@jaist.ac.jp>:
+ * environ.cc (environ_init): correct size arg to parse_options
+
+Mon Nov 2 21:40:32 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * regexp/regexp.c (regatom): Respond to compiler warning.
+
+Mon Nov 2 21:36:48 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ patch from Corinna Vinschen <corinna.vinschen@cityweb.de>:
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ patch from Mumit Khan <khan@xraylith.wisc.edu>:
+ * dll_init.cc (doGlobalCTORS): Fix invocation order.
+ (doGlobalDTORS): Likewise.
+
+Wed Oct 28 17:57:53 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * Makefile.in: add include/exceptions.h to dll_init.cc deps.
+
+ patch from Mumit Khan <khan@xraylith.wisc.edu>:
+ * 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 <noer@cygnus.com>
+
+ * syslog.cc: drop "32" from CYGWIN32_LOG_NAME
+
+Tue Oct 27 16:09:09 1998 DJ Delorie <dj@cygnus.com>
+
+ * utils/cygcheck.cc (usage): cygwhich->cygcheck
+
+Mon Oct 26 17:47:10 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * Makefile.in: fix deps for dll_entry.o and dll_main.o,
+ add dep for glob.o.
+
+ patch from Mumit Khan <khan@xraylith.wisc.edu>:
+ * 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 <noer@cygnus.com>
+
+ * Makefile.in: add back install of include/net which was
+ removed by accident.
+
+Mon Oct 26 15:25:22 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * uname.cc (uname): Remove slash from system name.
+
+Mon Oct 26 02:11:44 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * include/asm/byteorder.h: add missing __cplusplus wrapper.
+
+Mon Oct 26 00:46:33 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * uname.cc (uname): Remove space from the system name.
+
+Sun Oct 25 23:47:56 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * cygwin.din: remove unnecessary __cygwin32_stack_trace and
+ __cygwin_stack_trace exports.
+
+Sat Oct 24 21:18:46 1998 Christopher Faylor <cgf@cygnus.com>
+
+ patch from Corinna Vinschen <corinna.vinschen@cityweb.de>:
+ * 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 <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * utils/cygcheck.cc: reformat, add copyright notice
+
+Fri Oct 23 18:15:28 1998 DJ Delorie <dj@cygnus.com>
+
+ * utils/cygcheck.cc: new file
+ * utils/Makefile.in: build cygcheck.exe
+
+Fri Oct 23 16:48:41 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * Makefile.in: install include/cygwin headers, losing the "32".
+ * include/cygwin32: remove
+
+Fri Oct 23 14:36:31 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * utils/*: remove "32"s from cygwin32_foo function calls
+
+Fri Oct 23 00:24:27 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * utils/Makefile.in: disable building cygwin.exe.
+
+Thu Oct 22 14:16:10 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * include/sys/strace.h: Minor addition from threadsafe-branch.
+
+Thu Oct 22 09:03:18 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * include/cygwin32/version.h: rewrite versioning comments,
+ updating for new scheme but keeping historical information.
+
+Mon Oct 19 23:45:24 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <khan@xraylith.wisc.edu>, Corinna Vinschen
+ <corinna.vinschen@cityweb.de>, 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * Makefile.in: Avoid newer GNU make construction when building
+ version.cc.
+
+Mon Oct 19 00:09:06 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * Makefile.in: invoke mkvers.sh with $(SHELL)
+
+Sun Oct 18 15:19:17 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * Makefile.in: enable building mingw subdir by default
+
+Thu Oct 15 12:01:08 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * hinfo.cc (hinfo::dup2): Avoid a null pointer dereference
+ in a debugging printf.
+
+Wed Oct 14 18:06:51 1998 Geoffrey Noer <noer@cygnus.com>
+
+ patch from Corinna Vinschen <corinna.vinschen@cityweb.de>:
+ * 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 <cgf@cygnus.com>
+
+ * 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 <dj@cygnus.com>
+
+ * utils/ps.cc (main): use const char *pname
+
+Fri Oct 9 12:32:23 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * syscalls.cc (getw): Simplify.
+
+Thu Oct 8 23:09:34 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * times.cc: add missing syscall_printfs to time functions,
+ slight reformatting.
+
+Thu Oct 8 21:56:37 1998 DJ Delorie <dj@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * fhandler_tty.h: up NTTYs from 16 to 128
+
+Wed Oct 7 09:15:55 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ patch from Corinna Vinschen <corinna.vinschen@cityweb.de>:
+ * sysdef/kernel32.def: add missing GetDiskFreeSpaceEx lines
+
+Sat Oct 3 23:52:23 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <dj@cygnus.com>
+
+ * strace.cc (strace_printf): protect against recursion
+
+Thu Oct 1 17:08:47 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * utils/ps.cc (main): add more detailed usage printfs
+
+Thu Oct 1 11:05:16 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * include/io.h: add missing setmode proto
+
+Tue Sep 29 23:33:11 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <spolk@cygnus.com>
+
+ * include/{tchar.h, direct.h}: Added so that
+ tcl8.1a2 can be compiled with cygwin.
+
+Mon Sep 28 19:36:41 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <dj@cygnus.com>
+
+ * doc/doctool.c (main): typo checking for --help
+
+Wed Sep 23 17:46:06 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ patch from DJ Delorie <dj@cygnus.com>:
+ * path.cc (symlink_check_one): Don't re-define res or symlinks
+ will be undetectable.
+
+Wed Sep 23 12:02:39 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * path.cc (symlink_check_one): Fix handle leak resulting
+ from open of file to check for symlink magic. Suggested
+ by Corinna Vinschen <corinna.vinschen@cityweb.de> .
+
+Wed Sep 23 08:33:26 1998 Christopher Faylor <cgf@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * path.cc (mount, umount, setmntent, getmntent, endmntent):
+ make extern "C"
+
+Mon Sep 21 20:37:16 1998 DJ Delorie <dj@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * doc/Makefile.in: reference -db2html in case docbook
+ tools aren't installed.
+
+Mon Sep 21 14:43:40 1998 Geoffrey Noer <noer@cygnus.com>
+
+ patch from DJ Delorie <dj@cygnus.com>:
+ * doc/doctool.c (scan_file): correct off by one error in
+ malloc
+
+Mon Sep 21 14:28:38 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * fhandler.h (select_record): Clear memory in constructor.
+
+Mon Sep 21 08:49:22 1998 Christopher Faylor <cgf@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ * doc/Makefile.in: Add dummy install target.
+
+Thu Sep 17 12:30:49 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ * winsup.h: Remove side effects from SLASH_P.
+
+Tue Sep 15 18:36:08 1998 Ben Elliston <bje@cygnus.com>
+
+ * sysdef/kernel32.def: Add definition for the Win32 API function
+ `TryEnterCriticalSection'.
+
+Tue Sep 15 12:26:48 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <dj@cygnus.com>
+
+ * added documentation and doctool.c
+
+Tue Sep 15 08:37:26 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * Makefile.in: include ../libio when building
+
+Sun Sep 13 19:30:58 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ Merge in experimental-980602 branch changes.
+
+Thu Sep 10 21:09:51 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * select.cc (socket_cleanup): Close thread handle or suffer
+ handle leak.
+
+Thu Sep 10 21:09:51 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * select.cc (cygwin32_select): Need to reset signal_arrived before
+ testing it or suffer loop.
+
+Thu Sep 10 21:09:51 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <dj@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * Makefile.in: build libwinspool.a with the dll name winspool.drv
+
+Thu Sep 10 21:09:51 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <dj@cygnus.com>
+
+ * path.cc (path_conv): bug fix when path ends in slash
+
+Thu Sep 10 21:09:51 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * dcrt0.cc (dll_crt0_1): Remove ill-advised ifdef NEEDOEM.
+
+Thu Sep 3 17:54:18 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * Makefile.in: Speed up dll links.
+ * path.cc (chdir): Fix previous change.
+
+Mon Aug 31 12:23:33 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * path.cc (chdir): Protect free from potential signal race.
+
+Fri Aug 28 15:59:27 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * dlfcn.h: delete, move it
+ * include/dlfcn.h: here
+
+Thu Aug 27 14:20:38 1998 Christopher Faylor <cgf@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * include/cygwin32/version.h: up minor version number
+
+Mon Aug 10 07:04:13 1998 DJ Delorie <dj@cygnus.com>
+
+ * 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 <ebachalo@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <ebachalo@loony.cygnus.com>
+
+ * 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 <dj@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * path.cc (chdir): Force chdir to disk device to go to the root
+ directory.
+
+Tue Jul 21 09:32:23 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * pinfo.cc (pinfo_init): 0 is a very bad value for a default pgid.
+
+Fri Jul 16 15:09:50 1998 Stan Cox <scox@cygnus.com>
+
+ * (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 <ebachalo@loony.cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * dcrt0.cc (dll_crt0_1): Avoid redundant strace_printf.
+
+Wed Jul 8 15:05:10 1998 DJ Delorie <dj@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * environ.cc (winenv): Be more paranoid when restoring special
+ win32 environment variables beginning with '='.
+
+Thu Jul 2 09:19:32 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * include/Windows32/Structures.h (MINMAXINFO): Add a missing
+ *LP...
+
+Thu Jun 25 10:45:38 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * signal.cc (sigpending): Stop from always reporting pending signals
+ when no signals are actually pending.
+
+Tue Jun 23 15:38:45 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * include/sys/syslog.h: add missing LOG_LOCALn bits
+
+Tue Jun 9 22:29:26 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ * dcrt0.cc: Remove obsolete PPC and OLDWAY defines.
+ * exceptions.cc: Remove obsolete PPC defines.
+
+Fri Jun 5 22:18:01 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * utils/Makefile.in: install should build products if necessary.
+
+Fri Jun 5 17:47:11 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * errno.cc (seterrno): shouldn't & against 0xff since there
+ are error codes above 255.
+
+Fri Jun 5 14:35:36 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * exceptions.cc (ctrl_c_handler): return zero when a
+ CTRL_LOGOFF_EVENT occurs.
+
+Wed Jun 3 01:01:17 1998 Geoffrey Noer <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * hinfo.cc: Include unistd.h, not fcntl.h.
+
+Fri May 29 21:38:10 1998 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ patch from sos@prospect.com.ru (Sergey Okhapkin):
+ * Makefile.in: Add fhandler_windows.o target
+ * fhandler.h: Include <sys/ioctl.h>. 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 <sys/ioctl.h>.
+ * 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 <ian@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * include/sys/ioctl.h: need to include <sys/cdefs.h>
+ * syscalls.h: remove ioctl proto
+
+Wed May 27 01:34:06 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * cygwin.din: add sethostent/endhostent exports
+ * net.cc (sethostent, endhostent): new stubs
+
+Fri May 22 17:31:50 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * include/cygwin32/in.h: correct typo in IPPORT_WHOIS define
+
+Fri May 22 17:00:48 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * include/sys/ioctl.h: add ioctl proto
+
+Wed May 20 18:52:31 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ patch from Christopher Faylor <cgf@cygnus.com>
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * dcrt0.cc (dll_crt0_1): Clear errno before calling main.
+
+Thu May 14 00:37:01 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * dcrt0.cc: add comments, reformatting
+
+Wed May 13 17:47:23 1998 Geoffrey Noer <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * syscalls.cc (get_os_type): add FIXME
+
+Tue May 5 14:02:12 1998 Christopher Faylor <cgf@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * passwd.cc (parse, getpass): remove unneeded uses of NO_COPY
+ * grp.cc (getgrgid, getgrnam): ditto
+
+Tue Apr 28 16:18:03 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * version.h: bump minor version to 2
+ * errno.cc: add FIXME
+
+Wed Apr 22 15:43:56 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * cygwin.din: export truncate call
+
+Mon Apr 13 23:15:13 1998 Geoffrey Noer <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * include/sys/cygwin.h: add protos for cygwin32 path conversion
+ functions.
+
+Wed Apr 1 16:12:58 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * {fhandler.cc, fhandler.h, hinfo.cc, console.cc}: Rename
+ fhandler_tty class to fhandler_serial
+
+Tue Mar 31 16:27:36 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * environ.cc (parse_options): change struct to union to avoid
+ references to uninitialized fields.
+
+Thu Mar 26 19:03:00 1998 Eric Bachalo <ebachalo@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * version.h: up CYGWIN_DLL_VERSION_MINOR
+
+Tue Mar 10 15:41:29 1998 Geoffrey Noer <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ Beta 19 release made.
+
+Sun Feb 22 23:46:31 1998 Geoffrey Noer <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * environ.cc (parse_options): comment out -- no longer
+ compiles with egcs. Will rewrite/enable later.
+
+Sun Feb 22 13:49:10 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * Makefile.in: rename dll to cygwindevo.dll
+
+Sat Feb 21 01:33:56 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * cygwin.din: remove dup definition of endpwent
+
+Thu Feb 19 14:20:21 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * include/cygwin32/cygwin_dll.h: Correct protection wrapper
+
+Tue Feb 17 20:21:24 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * include/Windows32/Structures.h: tagBITMAPFILEHEADER should
+ be packed.
+
+Tue Feb 17 19:34:41 1998 Geoffrey Noer <noer@cygnus.com>
+
+ 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 <ian@cygnus.com>
+
+ * 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 <ian@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * Makefile.in: add registry.h to environ.o deps
+
+Mon Feb 9 14:42:24 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * include/a.out.h: new coff header file
+
+Wed Feb 4 01:55:18 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <ian@cygnus.com>
+
+ * 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 <ian@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <ian@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * sigproc.cc (sig_send): lock_pinfo_for_update during this
+ function
+
+Fri Jan 16 18:09:59 1998 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <ian@cygnus.com>
+
+ * 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 <ian@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <fujieda@jaist.ac.jp>
+
+ * path.cc (symlink): Don't return error if target is a symlink to a
+ nonexistent file.
+
+1999-12-23 DJ Delorie <dj@cygnus.com
+
+ * Makefile.in: add support for "make check"
+ * shared.cc: if $CYGWIN_TESTING is set, use a private shared area
+ * cygrun.c: new, used to isolate dll-in-test
+ * testsuite/*: new, rudimentary testsuite framework
+
+Wed Dec 22 01:05:44 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * path.cc (symlink): Return error if the target exists.
+
+Thu Dec 16 22:36:45 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * Makefile.in: Only build winver.o and version.o when required.
+
+Sat Dec 11 11:06:45 1999 Corinna Vinschen <corinna@vinschen.de>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <corinna@vinschen.de>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * environ.cc (parse_options): Properly detect end of known array.
+
+Mon Dec 6 22:32:04 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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
+ <khan@xraylith.wisc.edu>).
+ * configure.in: Find windres.
+ * configure: Regenerate.
+ * Makefile.in: Link winver.o into cygwin1.dll.
+
+Mon Dec 6 13:04:47 1999 Mumit Khan <khan@xraylith.wisc.edu>
+
+ * 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 <cgf@cygnus.com>
+
+ * configure.in: Make threadsafe the default.
+ * configure: regenerate.
+ * utils/strace.cc: Fix a compiler warning.
+
+Sun Dec 5 15:49:43 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * environ.cc (parse_options): Reinstate unions in parse_things, to
+ save space.
+
+Fri Dec 3 22:52:05 1999 Christopher Faylor <cgf@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ * 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 <dj@cygnus.com>
+
+ * environ.cc (parse_options): switch to a static initializer;
+ templates are sensitive to g++ bugs.
+
+Fri Nov 26 12:04:23 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * net.cc (cygwin_bind): Ensure that non-Unix domain socket operations
+ return success correctly.
+
+Wed Nov 24 21:37:58 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <corinna@vinschen.de>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * signal.cc (kill_worker): Guard against NULL dereference when thread
+ safe.
+
+Sat Oct 30 00:59:38 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * Makefile.in: Some general cleanup.
+ * smallprint.c (__small_vsprintf): Accomodate new format for
+ __PRETTY_FUNCTION__.
+
+Wed Oct 27 16:13:36 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * environ.cc (environ_init): Turn off ntsec by default.
+
+Wed Oct 27 00:14:11 1999 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * fhandler.cc (fhandler_base::lseek): Take readahead into account.
+
+Tue Oct 26 16:46:54 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * syscalls.cc (_unlink): Return EISDIR when attempting to unlink a
+ directory.
+
+Mon Oct 25 18:05:23 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * fhandler.cc (fhandler_base::read): Fix previous fix.
+
+Mon Oct 25 13:46:44 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * fhandler.cc (fhandler_base::read): Work around C bug.
+
+Tue Oct 19 22:10:21 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * dll_init.cc: Add some external symbols to allow thread-safe
+ compilation.
+
+Tue Oct 19 21:09:42 1999 Christopher Faylor <cgf@cygnus.com>
+
+ 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 <dj@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * path.cc (mount_info::cygdrive_posix_path): Properly terminate string
+ after Oct 11 change below.
+
+Fri Oct 15 23:02:39 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * include/cygwin/version.h: Bump some versions.
+
+Oct 5 11:45:00 1999 Corinna Vinschen <corinna@vinschen.de>
+
+ * 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 <cgf@cygnus.com>
+
+ 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 <fujieda@jaist.ac.jp>
+
+ * path.cc (readlink): Return errno correctly when it can't find the
+ target symlink.
+
+Tue Oct 12 13:02:08 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * select.cc (select): Return error if n > FD_SETSIZE. This is a
+ temporary fix.
+
+Sun Oct 10 13:56:14 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <fujieda@jaist.ac.jp>
+
+ * path.cc (symlink_check_one): set errno to EINVAL on socket files
+ same as normal files.
+
+1999-10-06 DJ Delorie <dj@cygnus.com>
+
+ * include/oaidl.h (IDispatch.GetIDsOfNames): Use DISPID* not DISPID
+
+1999-10-06 DJ Delorie <dj@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * hinfo.cc (hinfo::extend): Eliminate inappropriate test for boundary
+ condition.
+
+1999-10-04 DJ Delorie <dj@cygnus.com>
+
+ * config/i386/longjmp.c: don't restore %fs (Paul Sokolovsky
+ <paul-ml@is.lg.ua>)
+
+1999-10-04 DJ Delorie <dj@cygnus.com>
+
+ * localtime.c (tzsetwall): Handle Asian Windows strings correctly
+ (from Kazuhiro Fujieda <fujieda@jaist.ac.jp>).
+
+Sat Oct 2 23:00:00 1999 Corinna Vinschen <corinna@vinschen.de>
+
+ * include/lm*.h: Correct multiple problems in lan manager
+ header files.
+
+Sun Oct 3 14:29:53 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <corinna@vinschen.de>
+
+ * 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 <khan@xraylith.wisc.edu>
+
+ * 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 <dj@cygnus.com>
+
+ * times.cc: declare _timezone and _daylight properly
+
+Wed Sep 29 23:57:40 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <Norbert.Schulze@rhein-neckar.de>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <dj@cygnus.com>
+
+ * syscalls.cc (chown): never return ENOSYS - just pretend it
+ works.
+
+Wed Sep 22 00:47:56 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * select.cc (MAKEready): Need to initialize 'fd' or open tests in
+ peek fail.
+
+Mon Sep 20 17:07:37 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * smallprint.c (__small_vsprintf): Fix '%+' handling.
+
+Thu Sep 16 21:48:13 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * exceptions.cc (ctrl_c_handler): Make WINAPI, as required by
+ SetConsoleCtrlHandler.
+
+Thu Sep 16 17:48:05 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <dj@cygnus.com>
+
+ * dir.cc (rmdir): return ENOTDIR for regular files on 9x
+
+Tue Sep 14 00:01:59 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * syscalls.cc (pathconf): Make first arg 'const'.
+
+1999-09-10 DJ Delorie <dj@cygnus.com>
+
+ * exec.cc (_execve): check for an empty environment
+
+Wed Sep 8 10:24:12 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <corinna@vinschen.de>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * fhandler.cc (fhandler_base::fhandler_base): Don't use default binmode
+ for console.
+
+Wed Sep 1 20:51:05 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <fujieda@jaist.ac.jp>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * sigproc.cc (sig_send): One more end-of-process race detection.
+
+Mon Aug 23 21:37:07 1999 Christopher Faylor <cgf@cygnus.com>
+
+ 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 <dj@envy.delorie.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <dj@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <fujieda@jaist.ac.jp>
+
+ * 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 <cgf@cygnus.com>
+
+ * sigproc.cc: Add more precise end-of-process detection.
+
+Wed Aug 18 00:03:47 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <dj@cygnus.com>
+
+ * localtime.c (tzsetwall): Deduce TZ more accurately.
+
+Tue Aug 17 18:00:03 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * select.cc (peek_pipe): Correct detection of process group for
+ backgrounded processes.
+
+Tue Aug 17 10:24:49 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * include/winnt.h: Fix typo in IMAGE_FIRST_SECTION definition.
+
+Sun Aug 15 19:11:49 1999 Mumit Khan <khan@xraylith.wisc.edu>
+
+ * gcrt0.c (__eprol): Avoid namespace pollution.
+ (_monstartup): Turn into a constructor function and prevent multiple
+ invocations.
+
+Mon Aug 16 10:03:00 Corinna Vinschen <corinna@vinschen.de>
+
+ * utils/mkgroup.c: Correct call to LookupAccountSid for retrieval of
+ 'None'.
+
+Mon Aug 16 00:24:29 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <corinna@vinschen.de>
+
+ * 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 <cgf@cygnus.com>
+
+ * select.cc (peek_pipe): Honor ignra argument.
+
+Fri Aug 13 00:45:00 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * sigproc.cc (getsem): Fix typo which prevented sending signals to
+ other processes.
+
+Wed Aug 11 22:06:33 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <sos@prospect.com.ru>
+
+ * 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 <sys/un.h>
+ (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 <corinna@vinschen.de>
+
+ * utils/mkgroup.c (main): Generate "None" group when
+ invoked via mkgroup -l.
+
+Tue Aug 10 21:30:31 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <corinna@vinschen.de>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * psapi.h: New file.
+
+Thu Aug 4 10:28:00 Corinna Vinschen <corinna@vinschen.de>
+
+ * 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 <cgf@cygnus.com>
+
+ * a.out.h: Fix cut and paste from mime email typos.
+
+Mon Aug 2 19:08:48 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * dcrt0.cc (do_global_ctors): Remove previous change. It was just
+ wrong.
+
+Sun Aug 1 23:21:28 1999 Christopher Faylor <cgf@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ * net.cc (get_ifconf): Use alloca for temporary buffer.
+
+Sun Aug 1 01:38:20 1999 Christopher Faylor <cgf@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ Patch from Egor Duda <deo@logos-m.ru>:
+ * 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 <bernds@cygnus.co.uk>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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
+ <andrewd@axonet.com.au>.
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * security.cc: Various changes from Corinna.
+
+Sat Jul 17 22:33:45 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * debug.h: Fix ForceCloseHandle1 in non-debug case.
+
+Fri Jul 16 23:47:31 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ 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 <deo@logos-m.ru>) 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 <corinna@vinschen.de>
+
+ * security.cc (alloc_sd): Delete special handling of uid/gid 513.
+
+Thu Jul 13 15:01:00 Corinna Vinschen <corinna@vinschen.de>
+
+ * 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 <corinna@vinschen.de>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * cygwin.din: Export new snprintf and vnsprintf functions courtesy of
+ Egor Duda <deo@logos-m.ru>.
+
+Sun Jul 4 23:54:43 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * autoload.h: New file.
+
+Thu Jul 1 23:16:34 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ * 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 <corinna@vinschen.de>
+
+ * 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 <noer@cygnus.com>
+
+ * include/cygwin/version.h: Bump CYGWIN_VERSION_API_MINOR to 13.
+
+Wed Jun 23 10:39:07 1999 Mumit Khan <khan@xraylith.wisc.edu>
+
+ * 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 <cgf@cygnus.com>
+
+ 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
+ <deo@logos-m.ru>.
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * utils/Makefile.in: Consolidate and simplify.
+
+Mon Jun 14 12:43:32 1999 Christopher Faylor <cgf@cygnus.com>
+
+ 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 <corinna@vinschen.de>
+
+ * 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 <corinna@vinschen.de>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * mkvers.sh: Issue error if can't find version information.
+
+1999-06-09 DJ Delorie <dj@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * fhandler_tty.cc (fhandler_tty_slave::open): Reorganize
+ slightly to avoid a race with get_ttyp()->was_opened.
+
+1999-06-04 DJ Delorie <dj@cygnus.com>
+
+ * times.cc (totimeval): scale sub properly.
+ (gettimeofday): don't bias by timezone.
+
+Thu Jun 3 13:24:17 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * utils/mkpasswd.c (main): account for long int args to printfs.
+
+Wed Jun 2 16:08:08 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <corinna@vinschen.de>
+
+ * 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 <corinna@vinschen.de>
+
+ * 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 <corinna@vinschen.de>
+
+ * 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 <corinna@vinschen.de>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <corinna@vinschen.de>
+
+ * 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 <cgf@cygnus.com>
+
+ 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 <keiths@cygnus.com>
+
+ * errno.cc (errmap): Map ERROR_NEGATIVE_SEEK to EINVAL.
+
+Fri May 28 21:43:56 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * times.cc (to_time_t): Rewrite slightly to avoid compiler
+ overoptimization.
+
+Fri May 28 21:10:33 1999 Corinna Vinschen <corinna@vinschen.de>
+
+ * 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 <cgf@cygnus.com>
+
+ 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 <corinna@vinschen.de>
+
+ * 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 <corinna@vinschen.de>
+
+ * 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 <corinna@vinschen.de>
+
+ * 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 <corinna@vinschen.de>
+
+ * 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 <corinna@vinschen.de>
+
+ * 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 <corinna@vinschen.de>
+
+ * security.cc: Special handling for user and/or administrators
+ permissions to write (extended) attributes.
+
+Mon May 24 22:10:34 1999 Corinna Vinschen <corinna@vinschen.de>
+
+ * security.cc: Don't allow 513(none) as user or group.
+
+Mon May 24 22:10:34 1999 Corinna Vinschen <corinna@vinschen.de>
+
+ * 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 <corinna@vinschen.de>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * include/rapi.h: Add some more definitions.
+
+Sat May 22 21:45:01 1999 Mumit Khan <khan@xraylith.wisc.edu>
+
+ * 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 <khan@xraylith.wisc.edu>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * sysdef/rapi.def: New definition file for RAPI.DLL.
+ * include/rapi.h: Preliminary RAPI declarations.
+
+Sun May 16 15:37:15 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * Makefile.in: Remove more obsolete code.
+
+Fri May 14 19:30:53 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * include/winbase.h: Change conditional to correctly refer
+ to UNDER_CE rather than UNICODE.
+
+Tue May 11 21:19:59 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <Norbert.Schulze@rhein-neckar.de>
+
+ * times.cc (timezone): Properly adjust for daylight savings time.
+ (gettimeofday): Ditto.
+ (localtime): Ditto.
+ (tzset): Ditto.
+
+Mon May 10 23:31:36 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * Makefile.in: Forgot to remove a reference to the deleted targets
+ below.
+
+Fri May 7 17:28:12 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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
+ <anorland@hem2.passagen.se>.
+
+Mon May 3 11:32:32 1999 Mumit Khan <khan@xraylith.wisc.edu>
+
+ * 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 <khan@xraylith.wisc.edu>
+
+ * utils/Makefile.in (EXE_LDFLAGS): Provide default.
+
+1999-04-30 DJ Delorie <dj@cygnus.com>
+
+ * 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 <khan@xraylith.wisc.edu>
+
+ * 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 <khan@xraylith.wisc.edu>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * winsup.h: Always clear memory in thread .create method or
+ suffer uninitialized pointers, etc.
+
+Wed Apr 21 03:56:54 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * include/cygwin/version.h: Bump CYGWIN_VERSION_API_MINOR to 12.
+
+Sat Apr 17 15:35:34 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * path.cc (mount_info::conv_to_win32_path): Reorganize to
+ correctly handle //x syntax.
+
+Tue Mar 30 14:42:05 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * strace.cc (strace_vsprintf): Fix incorrect buffer reference.
+
+Mon Mar 29 22:46:16 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <corinna.vinschen@cityweb.de>
+
+ * utils/passwd.c (GetPW): Correct cast in call to `NetUserGetInfo'.
+
+Sun Mar 28 16:54:57 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <corinna.vinschen@cityweb.de>
+
+ * 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 <corinna.vinschen@cityweb.de>
+
+ * 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 <cgf@cygnus.com>
+
+ * signal.cc (pause): Make sure that signal has been dispatched
+ prior to pause returning.
+
+Wed Mar 24 20:04:21 1999 Christopher Faylor <cgf@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ * exceptions.cc (call_handler): Reorder to work around
+ gcc bug.
+
+Sun Mar 21 21:26:43 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * include/winbase.h: Fix AllocateAndInitializeSid proto.
+
+Tue Mar 16 21:55:12 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * exceptions.cc (handle_exceptions): Always wait for sig_send
+ to exit or races can result.
+
+Tue Mar 16 13:04:34 1999 Geoffrey Noer <noer@cygnus.com>
+
+ * include/cygwin/version.h: Bump CYGWIN_VERSION_API_MINOR to 11.
+
+Tue Mar 16 15:44:10 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * cygwin.din: Export telldir/seekdir.
+
+Tue Mar 16 13:50:51 1999 Corinna Vinschen <corinna.vinschen@cityweb.de>
+
+ * 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 <noer@cygnus.com>
+
+ * sysdef/comctl32.def: Add InitCommonControlsEx.
+
+Mon Mar 15 19:45:10 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <dj@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * include/commdlg.h: Add missing PageSetupDlg defines.
+
+Tue Mar 9 14:28:14 1999 Geoffrey Noer <noer@cygnus.com>
+
+ * include/*.h: Switch Win32 API header file set to the one written
+ by Anders Norlander <anorland@hem2.passagen.se>. 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * include/Windows32/Functions.h: Correct two #ifndefs that were
+ switched.
+
+Mon Feb 15 22:41:54 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * spawn.cc (spawn_guts): Fix incorrect arg length when
+ constructing new arguments for #!.
+
+Fri Feb 12 13:25:50 1999 Drew Moseley <dmoseley@cygnus.com>
+
+ * Makefile.in (install-info): Test for file existence before installing.
+
+Fri Feb 12 13:17:49 1999 Corinna Vinschen <corinna.vinschen@cityweb.de>
+
+ * 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 <dj@cygnus.com>
+
+ * doc/doctool.c (scan_directory): check for opendir failing,
+ add closedir.
+
+Tue Feb 9 13:02:25 1999 Geoffrey Noer <noer@cygnus.com>
+
+ * utils/mount.cc: Add fixme.
+ * doc/doctool.c: Correct typo in comment.
+
+Mon Feb 8 17:29:58 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * include/Windows32/UnicodeFunctions.h: Fix incorrect use of
+ BOOL -> WINBOOL.
+ * Windows32/ASCIIFunctions.h: Ditto.
+
+Fri Feb 5 09:38:25 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * path.cc (mount_info::add_item): Ensure that drive names
+ are added using X: notation.
+
+Thu Feb 4 00:28:58 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * cygwin.din: Remove DATA attribute which was erroneously
+ added to __errno.
+
+Tue Feb 2 23:10:18 1999 Geoffrey Noer <noer@cygnus.com>
+
+ * path.cc: Fix comment regarding UNC paths in mount table.
+ (mount_info::conv_to_win32_path): Add back code to handle
+ //<drive> 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 //<drive>
+ 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 <noer@cygnus.com>
+
+ * include/lmaccess.h: Add stub.
+ * include/shlobj.h: Add stub.
+
+Tue Feb 2 22:34:06 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <brendan@cygnus.com>
+
+ * Makefile.in (readme.txt): Add missing -I$(srcdir)/doc.
+
+Tue Feb 2 01:10:31 1999 Geoffrey Noer <noer@cygnus.com>
+
+ * sysdef/*: Replace all files with new ones by Anders
+ Norlander <anorland@hem2.passagen.se>. Please read sysdef/README
+ for more information.
+
+Mon Feb 1 14:55:11 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <corinna.vinschen@cityweb.de>
+
+ * 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 <cgf@cygnus.com>
+
+ * dir.cc (rmdir): Correct errno setting when attempting to rmdir
+ a non-directory.
+
+Tue Jan 26 17:36:12 1999 Geoffrey Noer <noer@cygnus.com>
+
+ * registry.cc (reg_key::build_reg): Add FIXME.
+
+Tue Jan 26 01:30:48 1999 Geoffrey Noer <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <noer@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ * spawn.cc (spawn_guts): Arg 2 missing from special case
+ command/cmd handling.
+
+Fri Jan 22 22:40:32 1998 Corinna Vinschen <corinna.vinsche@cityweb.de>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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
+ <drive letter>: or if posix path doesn't start with a slash.
+
+Wed Jan 20 19:06:30 1999 Geoffrey Noer <noer@cygnus.com>
+
+ * fhandler_raw.cc: Correct copyright date, reformat.
+ * fhandler_floppy.cc: Ditto.
+ * fhandler_tape.cc: Ditto.
+
+Wed Jan 20 17:54:02 1999 Geoffrey Noer <noer@cygnus.com>
+
+ Remove //<drive>/ support. Add support for automounts in
+ user registry area.
+ * path.cc: Rewrite, reformat docs at top in light of removing
+ //<drive>/ 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 //<drive>/ 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 "<letter>:".
+ (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 <dj@cygnus.com>
+
+ * 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 <corinna.vinschen@cityweb.de>
+
+ [applied by DJ Delorie <dj@cygnus.com>]
+
+ * 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 <rdparker@butlermfg.org>
+ * 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 <noer@cygnus.com>
+
+ * 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 <dj@cygnus.com>
+
+ * 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 <dj@cygnus.com>
+
+ * 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 <dj@cygnus.com>
+
+ * fhandler.cc (raw_write): check for disk full.
+
+Fri Jan 15 11:18:23 1999 DJ Delorie <dj@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * dll_init.cc: Add missing FIXME in comment.
+ * fhandler_console: Ditto.
+
+Thu Jan 14 00:53:25 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ * 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 <dj@cygnus.com>
+
+ * errno.cc (_sys_errlist): Add "extern" to work around new gcc
+ restrictions.
+
+Mon Jan 11 14:56:27 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * spawn.cc (spawn_guts): Fix problem with #! and relative
+ directories.
+
+Mon Jan 11 09:00:29 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * fhandler_console.cc (fhandler_console::read1): Handle EOF as a
+ specific case.
+
+Sun Jan 10 23:44:22 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ patch from Corinna Vinschen <corinna.vinschen@cityweb.de>:
+ * 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 <cgf@cygnus.com>
+
+ * fhandler.cc (fhandler_base::set_name): Fix bug which
+ disallowed '%' in a file name.
+
+Thu Jan 7 00:21:41 1999 Geoffrey Noer <noer@cygnus.com>
+
+ * path.cc: Add comments.
+ * path.h: Correct file description comment.
+
+Tue Jan 5 16:07:15 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <noer@cygnus.com>
+
+ 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 <cgf@cygnus.com>
+
+ * select.cc (peek_console): Remove #if 0 around NT code workaround.
+
+Sat Jan 2 00:04:01 1999 Christopher Faylor <cgf@cygnus.com>
+
+ * 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 <cgf@cygnus.com>
+
+ * 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 @@
+<sect1 id="std-ansi">
+<title>Compatibility with ANSI</title>
+
+<para>The following functions are compatible with ANSI:</para>
+
+<sect2><title>stdio</title><para>
+
+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,
+
+</para></sect2>
+<sect2><title>string</title><para>
+
+memchr, memcmp, memcpy, memmove, memset, strcat, strchr, strcmp,
+strcoll, strcpy, strcspn, strerror, strlen, strncat, strncmp, strncpy,
+strpbrk, strrchr, strspn, strstr, strtok, strxfrm
+
+</para></sect2>
+<sect2><title>stdlib</title><para>
+
+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
+
+</para></sect2>
+<sect2><title>time</title><para>
+
+asctime, gmtime, localtime, time, clock, ctime, difftime, mktime,
+strftime
+
+</para></sect2>
+<sect2><title>signals</title><para>
+
+raise, signal
+
+</para></sect2>
+<sect2><title>ctype</title><para>
+
+isalnum, isalpha, iscntrl, isdigit, isgraph, islower, isprint,
+ispunct, isspace, isupper, isxdigit, tolower, toupper
+
+</para></sect2>
+<sect2><title>math</title><para>
+
+acos, asin, atan, atan2, ceil, cos, cosh, exp, fabs, floor, fmod,
+frexp, ldexp, log, log10, modf, pow, sin, sinh, sqrt, tan, tanh
+
+</para></sect2>
+<sect2><title>misc</title><para>
+
+localeconv, setlocale, va_arg, va_end, va_start
+
+</para></sect2>
+
+</sect1> \ 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 <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/* 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 <alloca.h> and it should be used (not on Ultrix). */
+#undef HAVE_ALLOCA_H
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+ */
+#undef STACK_DIRECTION
+
+/* Define if DEBUGGING support is requested. */
+#undef DEBUGGING
+
+/* Define if building "extra" thread-safe Cygwin DLL. */
+#undef _CYG_THREAD_FAILSAFE
+
+/* Define if GCC supports builtin memset. */
+#undef HAVE_BUILTIN_MEMSET
+
+/* Define if 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 <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:858: \"$ac_try\") 1>&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 <<EOF
+#line 1329 "configure"
+#include "confdefs.h"
+#include <assert.h>
+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 <<EOF
+#line 1346 "configure"
+#include "confdefs.h"
+#include <assert.h>
+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 <<EOF
+#line 1363 "configure"
+#include "confdefs.h"
+#include <assert.h>
+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 <<EOF
+#line 1401 "configure"
+#include "confdefs.h"
+#include <alloca.h>
+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 <<EOF
+#line 1434 "configure"
+#include "confdefs.h"
+
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+#else
+# ifdef _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+# else
+# if HAVE_ALLOCA_H
+# include <alloca.h>
+# 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 <<EOF
+#line 1499 "configure"
+#include "confdefs.h"
+#if defined(CRAY) && ! defined(CRAY2)
+webecray
+#else
+wenotbecray
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&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 <<EOF
+#line 1529 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* 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 <<EOF
+#define CRAY_STACKSEG_END $ac_func
+EOF
+
+ break
+else
+ echo "$ac_t""no" 1>&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 <<EOF
+#line 1587 "configure"
+#include "confdefs.h"
+find_stack_direction ()
+{
+ static char *addr = 0;
+ auto char dummy;
+ if (addr == 0)
+ {
+ addr = &dummy;
+ return find_stack_direction ();
+ }
+ else
+ return (&dummy > 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 <<EOF
+#define STACK_DIRECTION $ac_cv_c_stack_direction
+EOF
+
+fi
+
+subdirs="utils doc"
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&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 <<EOF
+#line 1667 "configure"
+#include "confdefs.h"
+
+#include <string.h>
+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 <<EOF
+#define _MT_SAFE $mt_safe_val
+EOF
+
+fi
+
+
+
+
+# Check whether --enable-debugging or --disable-debugging was given.
+if test "${enable_debugging+set}" = set; then
+ enableval="$enable_debugging"
+ case "${enableval}" in
+yes) cat >> confdefs.h <<\EOF
+#define DEBUGGING 1
+EOF
+ ;;
+no) ;;
+esac
+
+fi
+
+
+
+
+
+
+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 <<EOF
+#line 1813 "configure"
+#include "confdefs.h"
+
+int main() {
+/* main already defined */
+
+; return 0; }
+EOF
+if { (eval echo configure:1821: \"$ac_link\") 1>&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 <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/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 <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > 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 <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile cygwin.def:cygwin.din"}
+EOF
+cat >> $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 <<EOF
+ CONFIG_HEADERS="config.h"
+EOF
+cat >> $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 <<CEOF' >> $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 <<EOF
+
+EOF
+cat >> $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 <string.h>
+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 <unistd.h>
+#include <stdlib.h>
+#include "winsup.h"
+#include "glob.h"
+#include "exceptions.h"
+#include "dll_init.h"
+#include "autoload.h"
+#include <ctype.h>
+
+#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 <stdlib.h>
+
+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 <unistd.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <errno.h>
+#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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "winsup.h"
+#include <ctype.h>
+#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 <stdlib.h>
+#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 @@
+
+<sect1 id="func-cygwin-detach-dll">
+<title>cygwin_detach_dll</title>
+
+<funcsynopsis>
+<funcdef>extern "C" void
+<function>cygwin_detach_dll</function></funcdef>
+<paramdef>int <parameter>dll_index</parameter></paramdef>
+</funcsynopsis>
+
+</sect1>
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 <errno.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#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 @@
+
+<sect1 id="func-cygwin-attach-handle-to-fd">
+<title>cygwin_attach_handle_to_fd</title>
+
+<funcsynopsis>
+<funcdef>extern "C" int
+<function>cygwin_attach_handle_to_fd</function></funcdef>
+<paramdef>char *<parameter>name</parameter></paramdef>
+<paramdef>int <parameter>fd</parameter></paramdef>
+<paramdef>HANDLE <parameter>handle</parameter></paramdef>
+<paramdef>int <parameter>bin</parameter></paramdef>
+<paramdef>int <parameter>access</parameter></paramdef>
+</funcsynopsis>
+
+<para>This function can be used to turn a Win32 "handle" into a
+posix-style file handle. <parameter>fd</parameter> may be -1 to
+make cygwin allocate a handle; the actual handle is returned
+in all cases.</para>
+
+</sect1>
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 <stdlib.h>
+#include <stddef.h>
+#include <ctype.h>
+#include <fcntl.h>
+
+#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:<foo>;<bar> 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 <stdio.h>
+#include "winsup.h"
+#include <errno.h>
+
+/* 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 <stdio.h>
+#include <errno.h>
+
+#define Win32_Winsock
+#include "winsup.h"
+#include "exceptions.h"
+#undef DECLSPEC_IMPORT
+#define DECLSPEC_IMPORT
+#include <imagehlp.h>
+#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 <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <process.h>
+#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 <nul> 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 <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. */
+
+#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 @@
+
+<sect1 id="func-cygwin-internal">
+<title>cygwin_internal</title>
+
+<funcsynopsis>
+<funcdef>extern "C" DWORD
+<function>cygwin_internal</function></funcdef>
+<paramdef>cygwin_getinfo_types <parameter>t</parameter></paramdef>
+<paramdef><parameter>...</parameter></paramdef>
+</funcsynopsis>
+
+<para>This function gives you access to various internal data and functions.
+Stay away unless you know what you're doing.</para>
+
+</sect1>
+
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 <fcntl.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <unistd.h>
+#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 <sys/fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#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 <sys/ioctl.h>
+
+/* 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 <sys/termios.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include "winsup.h"
+#include <ctype.h>
+
+/*
+ * 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 <sys/termios.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#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 <sys/termios.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include "winsup.h"
+
+#include <cygwin/rdevio.h>
+#include <sys/mtio.h>
+
+/**********************************************************************/
+/* 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 <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#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 <sys/termios.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include "winsup.h"
+
+#include <sys/mtio.h>
+
+/**********************************************************************/
+/* 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 <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include "winsup.h"
+#include <ctype.h>
+
+/* 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 <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "winsup.h"
+#include <ctype.h>
+#include <limits.h>
+
+/* 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 <errno.h>
+#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 <errno.h>
+#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 <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <errno.h>
+#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 <sys/types.h>
+#include <stdlib.h>
+
+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 <sys/cdefs.h>
+
+/*
+ * 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 <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <glob.h>
+
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#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 <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <gmon.h>
+
+#include <profil.h>
+
+/* 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 <profile.h>
+
+/*
+ * 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 <grp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#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 <errno.h>
+#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 <netinet/in.h>
+
+#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 <cygwin/if.h>
+
+#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 <sys/types.h>
+#include <sys/stat.h>
+
+/* 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 <windows.h>
+
+#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 <sys/types.h>
+#include <sys/socket.h>
+
+/* 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 <netinet/in.h> file.
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *
+ * 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 <cygwin/types.h>
+
+/* 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 */
+
+/* <asm/byteorder.h> contains the htonl type stuff.. */
+
+#include <asm/byteorder.h>
+
+/* 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 <sys/ioctl.h>
+#include <asm/socket.h>
+
+/*
+ * 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 <asm/socket.h> /* arch-dependent defines */
+#include <cygwin/sockios.h> /* the SIOCxxx I/O controls */
+#include <cygwin/uio.h> /* iovec support */
+#include <sys/types.h>
+
+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 <onno@stack.urc.tue.nl>
+
+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 <sys/fcntl.h>
+#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 <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+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 <utmp.h>
+
+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 <sys/param.h> 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 <string.h>
+
+#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 <cygwin/if.h>
+
+#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 <cygwin/in.h>
+
+#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 <cygwin/ip.h>
+
+#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 <cygwin/icmp.h>
+
+#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 <marco@ddi.nl>
+
+ 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 <sys/types.h>
+#include <signal.h>
+
+#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 <string.h>
+
+#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 <cygwin/acl.h>
+
+#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 <sys/types.h>
+
+#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 <windows.h> 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 <fcntl.h>
+
+#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 <sys/cdefs.h>
+
+/* /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 <stddef.h>
+#include <sys/types.h>
+
+#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 <cygwin/mtio.h>
+
+#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 <sys/time.h>
+
+#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 <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. */
+
+#ifndef _SYS_SELECT_H
+#define _SYS_SELECT_H
+
+#if !defined (_POSIX_SOURCE) && !defined (__INSIDE_CYGWIN_NET__)
+
+#include <sys/cdefs.h>
+
+/* Get fd_set, and macros like FD_SET */
+#include <sys/types.h>
+
+/* Get definition of timeval. */
+#include <sys/time.h>
+#include <time.h>
+
+__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 <stdarg.h>
+
+#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 <features.h>
+#include <cygwin/socket.h>
+#include <sys/time.h>
+
+#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 <sys/cdefs.h>
+#define LOG_EMERG 0
+#define LOG_ALERT 1
+#define LOG_CRIT 2
+#define LOG_ERR 3
+#define LOG_WARNING 4
+#define LOG_NOTICE 5
+#define LOG_INFO 6
+#define LOG_DEBUG 7
+
+#define LOG_PRIMASK 0x07
+
+#define LOG_PRI(p) ((p) & LOG_PRIMASK)
+#define LOG_MAKEPRI(fac, pri) (((fac) << 3) | (pri))
+
+#define LOG_KERN (0<<3)
+#define LOG_USER (1<<3)
+#define LOG_MAIL (2<<3)
+#define LOG_DAEMON (3<<3)
+#define LOG_AUTH (4<<3)
+#define LOG_SYSLOG (5<<3)
+#define LOG_LPR (6<<3)
+#define LOG_NEWS (7<<3)
+#define LOG_UUCP (8<<3)
+#define LOG_CRON (9<<3)
+#define LOG_AUTHPRIV (10<<3)
+#define LOG_FTP (11<<3)
+
+/* Codes through 15 are reserved for system use */
+#define LOG_LOCAL0 (16<<3)
+#define LOG_LOCAL1 (17<<3)
+#define LOG_LOCAL2 (18<<3)
+#define LOG_LOCAL3 (19<<3)
+#define LOG_LOCAL4 (20<<3)
+#define LOG_LOCAL5 (21<<3)
+#define LOG_LOCAL6 (22<<3)
+#define LOG_LOCAL7 (23<<3)
+
+#define LOG_NFACILITIES 24
+#define LOG_FACMASK 0x03f8
+#define LOG_FAC(p) (((p) & LOG_FACMASK) >> 3)
+
+#define LOG_MASK(pri) (1 << (pri))
+#define LOG_UPTO(pri) ((1 << ((pri)+1)) - 1)
+
+/*
+ * Option flags for openlog.
+ *
+ * LOG_ODELAY no longer does anything.
+ * LOG_NDELAY is the inverse of what it used to be.
+ */
+#define LOG_PID 0x01 /* log the pid with each message */
+#define LOG_CONS 0x02 /* log on the console if errors in sending */
+#define LOG_ODELAY 0x04 /* delay open until first syslog() (default) */
+#define LOG_NDELAY 0x08 /* don't delay open */
+#define LOG_NOWAIT 0x10 /* don't wait for console forks: DEPRECATED */
+#define LOG_PERROR 0x20 /* log to stderr as well */
+
+__BEGIN_DECLS
+
+
+void closelog (void);
+void openlog (const char *, int, int);
+int setlogmask (int);
+void syslog (int, const char *, ...);
+
+__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 <sys/termios.h>
+
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 <stddef.h>
+/* For ssize_t */
+#include <sys/types.h>
+
+/*
+ * 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 <sys/types.h>
+#include <sys/resource.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define WNOHANG 1
+#define WUNTRACED 2
+
+/* A status looks like:
+ <2 bytes info> <2 bytes code>
+
+ <code> == 0, child has exited, info is the exit value
+ <code> == 1..7e, child has exited, info is the signal number.
+ <code> == 7f, child has stopped, info was the signal number.
+ <code> == 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 <sys/syslog.h>
+
+#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 <sys/termio.h>
+
+#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 <stdlib.h>
+#include <ctype.h>
+#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 <sys/ioctl.h>
+#include <errno.h>
+#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 <stdlib.h>
+
+/* 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 <sys/param.h>
+#include <sys/types.h>
+#include <sys/strace.h>
+#include <gmon.h>
+
+/*
+ * 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 <machine/profile.h>.
+ *
+ * _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 <machine/profile.h>,
+ * which is included by <sys/gmon.h>
+ */
+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 @@
+<sect1 id="std-misc">
+<title>Compatibility with Miscellaneous Other Standards</title>
+
+<para>The following functions are compatible with miscellaneous other
+standards:</para>
+
+
+<sect2><title>Networking</title><para>
+
+<para>(Standardized by POSIX 1.g, which is probably still in draft?)</para>
+
+<para>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</para>
+
+<para>Of these networking calls, rexec, rcmd and rresvport are
+implemented in MS IP stack but may not be implemented in other
+vendors' stacks. </para>
+
+</sect2>
+
+<sect2><title>Other</title><para>
+
+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
+
+<sect2><title>Implementation Notes</title>
+
+<para> <function>initgroups</function> does nothing</para>
+
+<para> <function>chroot</function>, <function>mknod</function>,
+<function>settimeofday</function>, and <function>vhangup</function>
+always return -1 and sets errno to ENOSYS.</para>
+
+<para> <function>nice</function> 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
+<function>nice</function> 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 <function>nice</function>.
+
+<para> <function>seteuid</function>, <function>setegid</function>, and
+<function>settimeofday</function> always return 0 and sets errno to
+ENOSYS.</para>
+
+<para><function>vfork</function> just calls
+<function>fork</function></para>
+
+</sect2>
+
+</sect1>
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 <<EOF 1>&9
+#include <winsup.h>
+
+#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 <<EOF
+ "%%% Cygwin $var: $val\n"
+EOF
+done | tee /tmp/mkvers.$$ 1>&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 <<EOF 1>&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 <stdlib.h>
+#include <stddef.h>
+#include <sys/mman.h>
+#include <errno.h>
+
+#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; i<nlists; i++)
+ if (lists[i]->fd == 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 <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#define Win32_Winsock
+#include "winsup.h"
+#include <netdb.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "autoload.h"
+#include <winsock.h>
+
+/* 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\<Netcard>, where netcard is the name of the net device.
+ * Then look under:
+ * HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\<NetCard>\
+ * 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 <winsup.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* 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 <stdlib.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <errno.h>
+#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 <drive-letter>:
+
+ 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/<drive> 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 <stdio.h>
+#include <stdlib.h>
+#include <sys/mount.h>
+#include <mntent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include "winsup.h"
+#include <ctype.h>
+
+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
+ //<letter>. */
+
+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 "<drive>:" */
+
+ 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
+<sect1 id="add-func-cygwin-posix-path-list-p">
+ <para>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.</para>
+</sect1>
+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 <sys/mount.h>
+
+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 "!<symlink>"
+
+/* Socket marker */
+#define SOCKET_COOKIE "!<socket >"
+
+/* 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 @@
+<sect1 id="func-cygwin-posix-to-win32-path-list">
+<title>cygwin_posix_to_win32_path_list</title>
+
+<funcsynopsis>
+<funcdef>extern "C" void
+<function>cygwin_posix_to_win32_path_list</function></funcdef>
+<paramdef>const char *<parameter>posix</parameter></paramdef>
+<paramdef>char *<parameter>win32</parameter></paramdef>
+</funcsynopsis>
+
+<para>Given a POSIX path-style string (i.e. /foo:/bar) convert it to
+the equivalent Win32 path-style string (i.e. d:\;e:\bar).
+<parameter>win32</parameter> must point to a sufficiently large
+buffer.</para>
+
+<example>
+<title>Example use of cygwin_posix_to_win32_path_list</title>
+<programlisting>
+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);
+ }
+</programlisting>
+</example>
+
+<para>See also <link linkend="func-cygwin-posix-to-win32-path-list-buf-size">
+cygwin_posix_to_win32_path_list_buf_size</link></para>
+
+</sect1>
+
+<sect1 id="func-cygwin-win32-to-posix-path-list">
+<title>cygwin_win32_to_posix_path_list</title>
+
+<funcsynopsis>
+<funcdef>extern "C" void
+<function>cygwin_win32_to_posix_path_list</function></funcdef>
+<paramdef>const char *<parameter>win32</parameter></paramdef>
+<paramdef>char *<parameter>posix</parameter></paramdef>
+</funcsynopsis>
+
+<para>Given a Win32 path-style string (i.e. d:\;e:\bar) convert it to
+the equivalent POSIX path-style string (i.e. /foo:/bar).
+<parameter>posix</parameter> must point to a sufficiently large
+buffer. See also <link
+linkend="func-cygwin-win32-to-posix-path-list-buf-size">
+cygwin_win32_to_posix_path_list_buf_size</link></para>
+
+</sect1>
+
+<sect1 id="func-cygwin-posix-to-win32-path-list-buf-size">
+<title>cygwin_posix_to_win32_path_list_buf_size</title>
+
+<funcsynopsis>
+<funcdef>extern "C" int
+<function>cygwin_posix_to_win32_path_list_buf_size</function></funcdef>
+<paramdef>const char *<parameter>path_list</parameter></paramdef>
+</funcsynopsis>
+
+<para>Returns the number of bytes needed to hold the result of calling
+<link linkend="func-cygwin-posix-to-win32-path-list">
+cygwin_posix_to_win32_path_list</link>.</para>
+
+</sect1>
+
+<sect1 id="func-cygwin-win32-to-posix-path-list-buf-size">
+<title>cygwin_win32_to_posix_path_list_buf_size</title>
+
+<funcsynopsis>
+<funcdef>extern "C" int
+<function>cygwin_win32_to_posix_path_list_buf_size</function></funcdef>
+<paramdef>const char *<parameter>path_list</parameter></paramdef>
+</funcsynopsis>
+
+<para>Tells you how many bytes are needed for the results of <link
+linkend="func-cygwin-win32-to-posix-path-list">
+cygwin_win32_to_posix_path_list</link>.</para>
+
+</sect1>
+
+<sect1 id="func-cygwin-conv-to-posix-path">
+<title>cygwin_conv_to_posix_path</title>
+
+<funcsynopsis>
+<funcdef>extern "C" void
+<function>cygwin_conv_to_posix_path</function></funcdef>
+<paramdef>const char *<parameter>path</parameter></paramdef>
+<paramdef>char *<parameter>posix_path</parameter></paramdef>
+</funcsynopsis>
+
+<para>Converts a Win32 path to a POSIX path. If
+<parameter>path</parameter> is already a POSIX path, leaves it alone.
+If <parameter>path</parameter> is relative, then
+<parameter>posix_path</parameter> will also be relative. Note that
+<parameter>posix_path</parameter> must point to a buffer of sufficient
+size; use MAX_PATH if needed.</para>
+
+</sect1>
+
+<sect1 id="func-cygwin-conv-to-win32-path">
+<title>cygwin_conv_to_win32_path</title>
+
+<funcsynopsis>
+<funcdef>extern "C" void
+<function>cygwin_conv_to_win32_path</function></funcdef>
+<paramdef>const char *<parameter>path</parameter></paramdef>
+<paramdef>char *<parameter>win32_path</parameter></paramdef>
+</funcsynopsis>
+
+<para>Converts a POSIX path to a Win32 path. If
+<parameter>path</parameter> is already a Win32 path, leaves it alone.
+If <parameter>path</parameter> is relative, then
+<parameter>win32_path</parameter> will also be relative. Note that
+<parameter>win32_path</parameter> must point to a buffer of sufficient
+size; use MAX_PATH if needed.</para>
+
+</sect1>
+<sect1 id="func-cygwin-conv-to-full-posix-path">
+<title>cygwin_conv_to_full_posix_path</title>
+
+<funcsynopsis>
+<funcdef>extern "C" void
+<function>cygwin_conv_to_full_posix_path</function></funcdef>
+<paramdef>const char *<parameter>path</parameter></paramdef>
+<paramdef>char *<parameter>posix_path</parameter></paramdef>
+</funcsynopsis>
+
+<para>Converts a Win32 path to a POSIX path. If
+<parameter>path</parameter> is already a POSIX path, leaves it alone.
+If <parameter>path</parameter> is relative, then
+<parameter>posix_path</parameter> will be converted to an absolute
+path. Note that <parameter>posix_path</parameter> must point to a
+buffer of sufficient size; use MAX_PATH if needed.</para>
+
+</sect1>
+
+<sect1 id="func-cygwin-conv-to-full-win32-path">
+<title>cygwin_conv_to_full_win32_path</title>
+
+<funcsynopsis>
+<funcdef>extern "C" void
+<function>cygwin_conv_to_full_win32_path</function></funcdef>
+<paramdef>const char *<parameter>path</parameter></paramdef>
+<paramdef>char *<parameter>win32_path</parameter></paramdef>
+</funcsynopsis>
+
+<para>Converts a POSIX path to a Win32 path. If
+<parameter>path</parameter> is already a Win32 path, leaves it alone.
+If <parameter>path</parameter> is relative, then
+<parameter>win32_path</parameter> will be converted to an absolute
+path. Note that <parameter>win32_path</parameter> must point to a
+buffer of sufficient size; use MAX_PATH if needed.</para>
+
+</sect1>
+
+<sect1 id="func-cygwin-posix-path-list-p">
+<title>cygwin_posix_path_list_p</title>
+
+<funcsynopsis>
+<funcdef>extern "C" int
+<function>posix_path_list_p</function></funcdef>
+<paramdef>const char *<parameter>path</parameter></paramdef>
+</funcsynopsis>
+
+<para>This function tells you if the supplied
+<parameter>path</parameter> 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.</para>
+
+</sect1>
+
+<sect1 id="func-cygwin-split-path">
+<title>cygwin_split_path</title>
+
+<funcsynopsis>
+<funcdef>extern "C" void
+<function>cygwin_split_path</function>
+</funcdef>
+<paramdef>const char * <parameter>path</parameter></paramdef>
+<paramdef>char * <parameter>dir</parameter></paramdef>
+<paramdef>char * <parameter>file</parameter></paramdef>
+</funcsynopsis>
+
+<para>Split a path into the directory and the file portions. Both
+<parameter>dir</parameter> and <parameter>file</parameter> are
+expected to point to buffers of sufficient size. </para>
+
+<example>
+<title>Example use of cygwin_split_path</title>
+<programlisting>
+char dir[200], file[100];
+cygwin_split_path("c:/foo/bar.c", dir, file);
+printf("dir=%s, file=%s\n", dir, file);
+</programlisting>
+</example>
+</sect1>
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 <stdlib.h>
+#include <time.h>
+#include <errno.h>
+#include <limits.h>
+#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
+
+<sect1 id="func-cygwin-winpid-to-pid">
+ <title>cygwin_winpid_to_pid</title>
+
+ <funcsynopsis>
+ <funcdef>extern "C" pid_t
+ <function>cygwin_winpid_to_pid</function>
+ </funcdef>
+ <paramdef>int <parameter>winpid</parameter></paramdef>
+ </funcsynopsis>
+
+ <para>Given a windows pid, converts to the corresponding Cygwin
+pid, if any. Returns -1 if windows pid does not correspond to
+a cygwin pid.</para>
+ <example>
+ <title>Example use of cygwin_winpid_to_pid</title>
+ <programlisting>
+ extern "C" cygwin_winpid_to_pid (int winpid);
+ pid_t mypid;
+ mypid = cygwin_winpid_to_pid (windows_pid);
+ </programlisting>
+ </example>
+</sect1>
+
+ 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 <unistd.h>
+#include <sys/fcntl.h>
+#include <errno.h>
+#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 @@
+<sect1 id="std-posix">
+<title>Compatibility with POSIX.1</title>
+
+<para>The following functions are compatible with POSIX.1:</para>
+
+<sect2><title>Process Primitives (Section 3) </title><para>
+
+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
+
+<sect2><title>Process Environment (Section 4) </title><para>
+
+getpid, getppid, getuid, geteuid, getgid, getegid, setuid, setgid,
+getgroups, getlogin, getpgrp, setsid, setpgid, uname, time, times,
+getenv, ctermid, ttyname, isatty, sysconf
+
+<sect2><title>Files and Directories (Section 5) </title><para>
+
+opendir, readdir, rewinddir, closedir, chdir, getcwd, open, creat,
+umask, link, mkdir, unlink, rmdir, rename, stat, fstat, access, chmod,
+fchmod, chown, utime, ftruncate, pathconf, fpathconf
+
+<sect2><title>Input and Output Primitives (Section 6) </title><para>
+
+pipe, dup, dup2, close, read, write, fcntl, lseek, fsync
+
+<sect2><title>Device- and Class-Specific Functions (Section 7) </title><para>
+
+cfgetispeed, cfgetospeed, cfsetispeed, cfsetospeed, tcdrain, tcflow,
+tcflush, tcgetattr, tcgetpgrp, tcsendbreak, tcsetattr, tcsetpgrp
+
+<sect2><title>Language-Specific Services for the C Programming Language (Section 8) </title><para>
+
+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
+
+<sect2><title>System Databases (Section 9) </title><para>
+
+getgrgid, getgrnam, getpwnam, getpwuid
+
+<sect2><title>Synchronization (Section 11) </title><para>
+
+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
+
+<sect2><title>Memory Management (Section 12) </title><para>
+
+mmap, mprotect, msync, munmap
+
+<sect2><title>Thread Management (Section 16) </title><para>
+
+pthread_attr_init, pthread_attr_destroy, pthread_attr_setstacksize,
+pthread_attr_getstacksize, pthread_create, pthread_exit, pthread_self,
+pthread_equal
+
+<sect2><title>Thread-Specific Data Functions (Section 17) </title><para>
+
+pthread_key_create, pthread_setspecific, pthread_getspecific,
+pthread_key_delete
+
+</sect2>
+
+<sect2><title>Implementation Details</title>
+
+<para><function>setuid</function> and <function>setgid</function>
+always return ENOSYS.</para>
+
+<para><function>link</function> will copy the file if it can't
+implement a true symbolic link. Currently, symbolic links work, if at
+all, only under Windows NT.</para>
+
+<para><function>chown</function> always returns zero.</para>
+
+<para><function>fcntl</function> doesn't support F_GETLK - it returns
+-1 and sets errno to ENOSYS.</para>
+
+<para><function>lseek</function> only works properly on binary
+files.</para>
+
+</sect2>
+
+</sect1> \ 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 <windows.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <math.h>
+
+#include <profil.h>
+
+#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 <marco@ddi.nl>
+
+ 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 <errno.h>
+#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 <corinna.vinschen@cityweb.de>
+
+ This file is part of Cygwin.
+
+ This software is a copyrighted work licensed under the terms of the
+ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+ details. */
+
+#include <dirent.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#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 <corinna.vinschen@cityweb.de>
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include <grp.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/acl.h>
+#include "winsup.h"
+#include <ctype.h>
+
+#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 <errno.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+#include "winsup.h"
+#include <netdb.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <winsock.h>
+#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 <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <grp.h>
+#include <pwd.h>
+#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 @@
+
+<sect1 id="func-cygwin-getshared">
+<title>cygwin_getshared</title>
+
+<funcsynopsis>
+<funcdef>shared_info *
+<function>cygwin_getshared</function></funcdef>
+<void>
+</funcsynopsis>
+
+<para>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
+<filename>mount</filename> and <filename>ps</filename>.
+</para>
+
+</sect1>
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 <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 <errno.h>
+#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 <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. */
+
+#include <stdlib.h>
+#include <time.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <stdlib.h>
+#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 <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <windows.h>
+
+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 <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <process.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <limits.h>
+#include "winsup.h"
+#include <ctype.h>
+#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 <ctype.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <time.h>
+#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 <stdio.h>
+
+/*-
+ * 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 <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. */
+
+#include <stdlib.h>
+#include <time.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <stdlib.h>
+#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 <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. */
+
+/* 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 <sys/stat.h>
+#include <sys/vfs.h> /* needed for statfs */
+#include <fcntl.h>
+#include <pwd.h>
+#include <grp.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <process.h>
+#include <utmp.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <limits.h>
+#include "winsup.h"
+#include <lmcons.h> /* for UNLEN */
+#include <unistd.h>
+
+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 <unistd.h>
+#include <errno.h>
+#include <time.h>
+#include <limits.h>
+#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 <stdlib.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <unistd.h>
+#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 : "<NULL>", 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 <errno.h>
+#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 <marco@ddi.nl>
+
+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 <errno.h>
+#include "winsup.h"
+#include <assert.h>
+
+#include <stdlib.h>
+#include <syslog.h>
+
+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 <marco@ddi.nl>
+
+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 <pthread.h>
+#include <pwd.h>
+#include <grp.h>
+#include <stdio.h>
+#include <mntent.h>
+#include <time.h>
+
+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 <time.h>
+#include <sys/times.h>
+#include <sys/timeb.h>
+#include <utime.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#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 <errno.h>
+#include <unistd.h>
+#include <utmp.h>
+#include <ctype.h>
+#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 <pwd.h>
+#include "winsup.h"
+#include <utmp.h>
+#include <limits.h>
+#include <unistd.h>
+#include "autoload.h"
+#include <stdlib.h>
+#include <wchar.h>
+#include <lm.h>
+
+/* 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 <stdio.h>
+#include <sys/utsname.h>
+#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 <sys/wait.h>
+#include <stdlib.h>
+#include <errno.h>
+#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 <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 <sys/time.h>
+#include <stdlib.h>
+#include <errno.h>
+#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 <sys/types.h>
+#include <sys/strace.h>
+#include <sys/resource.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <string.h>
+
+#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 <windows.h>
+
+/* 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 <cygwin/version.h>
+
+#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 <sys/cygwin.h>
+
+/********************** 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 <sys/reent.h>
+
+#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 <winver.h>
+#include <cygwin/version.h>
+
+#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