summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Faylor <cgf@redhat.com>2003-02-14 03:03:26 +0000
committerChristopher Faylor <cgf@redhat.com>2003-02-14 03:03:26 +0000
commite07f1ec5d50d3781167acad813023c327a98bfd8 (patch)
treed14e67e6282ef41f8e1efda6dcbc41cc8a62e90a
parent335bdeb9375bfba164a07467a0ce6e9341a89a55 (diff)
downloadgdb-e07f1ec5d50d3781167acad813023c327a98bfd8.tar.gz
merge from trunk.
Reorganize includes throughout so that path.h comes before fhandler.h. Eliminate path_conv arguments from fhandler functions which take them, throughout. Use get_name() and get_win32_name() consistently throughout for fhandler objects. Use build_fh_* functions throughout, where appropriate. * fhandler.h (fhandler_base): Store path_conv struct here. Remove dev. * dtable.h (dtable::build_fhandler_*): Remove. (build_fh_dev): New. (build_fh_pc): New. (build_fh_name): New. * dtable.cc (build_fh_dev): New. (build_fh_pc): New. (build_fh_name): New. * fhandler.h (fhandler_base::set_name): Change argument. * fhandler.cc (fhandler_base::set_name): Just accept a path_conv argument. (executable_states): Move. * path.h (executable_state): Accept. * syscalls.cc (stat_worker): Make static. * winsup.h (stat_worker): Remove definition.
-rw-r--r--winsup/cygwin/ChangeLog28
-rw-r--r--winsup/cygwin/ChangeLog.branch24
-rw-r--r--winsup/cygwin/Makefile.in1
-rw-r--r--winsup/cygwin/autoload.cc1
-rw-r--r--winsup/cygwin/cygheap.cc2
-rw-r--r--winsup/cygwin/dcrt0.cc2
-rw-r--r--winsup/cygwin/debug.cc227
-rw-r--r--winsup/cygwin/devices.h2
-rw-r--r--winsup/cygwin/dir.cc345
-rw-r--r--winsup/cygwin/dlfcn.cc2
-rw-r--r--winsup/cygwin/dll_init.cc425
-rw-r--r--winsup/cygwin/dtable.cc120
-rw-r--r--winsup/cygwin/dtable.h15
-rw-r--r--winsup/cygwin/environ.cc1002
-rw-r--r--winsup/cygwin/exceptions.cc5
-rw-r--r--winsup/cygwin/exec.cc103
-rw-r--r--winsup/cygwin/external.cc252
-rw-r--r--winsup/cygwin/fcntl.cc49
-rw-r--r--winsup/cygwin/fhandler.cc85
-rw-r--r--winsup/cygwin/fhandler.h126
-rw-r--r--winsup/cygwin/fhandler_clipboard.cc7
-rw-r--r--winsup/cygwin/fhandler_console.cc14
-rw-r--r--winsup/cygwin/fhandler_disk_file.cc134
-rw-r--r--winsup/cygwin/fhandler_dsp.cc3
-rw-r--r--winsup/cygwin/fhandler_fifo.cc6
-rw-r--r--winsup/cygwin/fhandler_floppy.cc5
-rw-r--r--winsup/cygwin/fhandler_mem.cc15
-rw-r--r--winsup/cygwin/fhandler_nodevice.cc4
-rw-r--r--winsup/cygwin/fhandler_proc.cc15
-rw-r--r--winsup/cygwin/fhandler_process.cc10
-rw-r--r--winsup/cygwin/fhandler_random.cc7
-rw-r--r--winsup/cygwin/fhandler_raw.cc8
-rw-r--r--winsup/cygwin/fhandler_registry.cc10
-rw-r--r--winsup/cygwin/fhandler_serial.cc7
-rw-r--r--winsup/cygwin/fhandler_socket.cc10
-rw-r--r--winsup/cygwin/fhandler_tape.cc12
-rw-r--r--winsup/cygwin/fhandler_termios.cc1
-rw-r--r--winsup/cygwin/fhandler_tty.cc13
-rw-r--r--winsup/cygwin/fhandler_virtual.cc6
-rw-r--r--winsup/cygwin/fhandler_windows.cc3
-rw-r--r--winsup/cygwin/fhandler_zero.cc3
-rw-r--r--winsup/cygwin/fork.cc751
-rw-r--r--winsup/cygwin/grp.cc2
-rw-r--r--winsup/cygwin/heap.cc2
-rw-r--r--winsup/cygwin/include/cygwin/in.h2
-rw-r--r--winsup/cygwin/include/cygwin/types.h16
-rw-r--r--winsup/cygwin/ioctl.cc65
-rw-r--r--winsup/cygwin/malloc_wrapper.cc316
-rw-r--r--winsup/cygwin/mmap.cc7
-rw-r--r--winsup/cygwin/net.cc6
-rw-r--r--winsup/cygwin/passwd.cc2
-rw-r--r--winsup/cygwin/path.cc7
-rw-r--r--winsup/cygwin/path.h22
-rw-r--r--winsup/cygwin/pinfo.cc2
-rw-r--r--winsup/cygwin/pipe.cc6
-rw-r--r--winsup/cygwin/poll.cc139
-rw-r--r--winsup/cygwin/sec_acl.cc2
-rw-r--r--winsup/cygwin/sec_helper.cc2
-rw-r--r--winsup/cygwin/security.cc2
-rw-r--r--winsup/cygwin/select.cc2
-rw-r--r--winsup/cygwin/shared.cc2
-rw-r--r--winsup/cygwin/sigproc.cc1310
-rw-r--r--winsup/cygwin/spawn.cc2
-rw-r--r--winsup/cygwin/strace.cc2
-rw-r--r--winsup/cygwin/syscalls.cc51
-rw-r--r--winsup/cygwin/sysconf.cc102
-rw-r--r--winsup/cygwin/syslog.cc412
-rw-r--r--winsup/cygwin/termios.cc2
-rw-r--r--winsup/cygwin/times.cc665
-rw-r--r--winsup/cygwin/tty.cc5
-rw-r--r--winsup/cygwin/uinfo.cc2
-rw-r--r--winsup/cygwin/winsup.h4
72 files changed, 6586 insertions, 435 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 4ab015db396..4c36e54705a 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,27 @@
+2003-02-13 Christopher Faylor <cgf@redhat.com>
+
+ * exceptions.cc (try_to_debug): Don't reset priority when returning
+ from non-waitloop call.
+
+2003-02-13 Vaclav Haisman <V.Haisman@sh.cvut.cz>
+ Christopher Faylor <cgf@redhat.com>
+
+ * fhandler_console.cc (fhandler_console::write_normal): Use MessageBeep
+ for bell sound.
+ * autoload.cc (MessageBeep): Add.
+
+2003-02-13 Christopher Faylor <cgf@redhat.com>
+
+ * include/cygwin/types.h: Use correct ifdef guard for u_ definitions.
+
+2003-02-13 Christopher Faylor <cgf@redhat.com>
+
+ * environ.cc (environ_init): Use strechr.
+
+2003-02-13 Christopher Faylor <cgf@redhat.com>
+
+ * include/cygwin/in.h (sockaddr_in): Fix typo.
+
2003-02-12 Christopher Faylor <cgf@redhat.com>
* path.h (path_conv): Reorganize slightly.
@@ -269,10 +293,10 @@
2003-01-29 Christopher Faylor <cgf@redhat.com>
- * lib/getopt.c: Allow environment variable control of POSIXLY_CORRECT
+ * lib/getopt.c: Allow environment variable control of POSIXLY_INCORRECT
behavior.
-2003-01-28 Corinna Vinschen <corinna@vinschen.de>
+2003-01-28 Corinna Vinschen <corinna@vinschen.de>
* fhandler_socket.cc (fhandler_socket::accept): On successful execution
set connection state of returned socket to CONNECTED.
diff --git a/winsup/cygwin/ChangeLog.branch b/winsup/cygwin/ChangeLog.branch
index 6cb007ea4b6..d319f36efb1 100644
--- a/winsup/cygwin/ChangeLog.branch
+++ b/winsup/cygwin/ChangeLog.branch
@@ -1,3 +1,27 @@
+2003-02-13 Christopher Faylor <cgf@redhat.com>
+
+ Reorganize includes throughout so that path.h comes before fhandler.h.
+ Eliminate path_conv arguments from fhandler functions which take them,
+ throughout.
+ Use get_name() and get_win32_name() consistently throughout for
+ fhandler objects.
+ Use build_fh_* functions throughout, where appropriate.
+ * fhandler.h (fhandler_base): Store path_conv struct here. Remove dev.
+ * dtable.h (dtable::build_fhandler_*): Remove.
+ (build_fh_dev): New.
+ (build_fh_pc): New.
+ (build_fh_name): New.
+ * dtable.cc (build_fh_dev): New.
+ (build_fh_pc): New.
+ (build_fh_name): New.
+ * fhandler.h (fhandler_base::set_name): Change argument.
+ * fhandler.cc (fhandler_base::set_name): Just accept a path_conv
+ argument.
+ (executable_states): Move.
+ * path.h (executable_state): Accept.
+ * syscalls.cc (stat_worker): Make static.
+ * winsup.h (stat_worker): Remove definition.
+
2003-01-28 Corinna Vinschen <corinna@vinschen.de>
* devices.gperf: Remove obsolete win32 device names.
diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in
index f124d74767c..489c4d21ffa 100644
--- a/winsup/cygwin/Makefile.in
+++ b/winsup/cygwin/Makefile.in
@@ -49,6 +49,7 @@ DEFS:=@DEFS@
# cygheap_CFLAGS:=-fomit-frame-pointer
malloc_CFLAGS:=-fomit-frame-pointer
+malloc_wrapper_CFLAGS:=-fomit-frame-pointer
shared_CFLAGS:=-fomit-frame-pointer
cygthread_CFLAGS:=-fomit-frame-pointer
miscfuncs_CFLAGS:=-fomit-frame-pointer
diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc
index 3c21d1e2908..805055c82ce 100644
--- a/winsup/cygwin/autoload.cc
+++ b/winsup/cygwin/autoload.cc
@@ -419,6 +419,7 @@ LoadDLLfunc (GetProcessWindowStation, 0, user32)
LoadDLLfunc (GetThreadDesktop, 4, user32)
LoadDLLfunc (GetUserObjectInformationA, 20, user32)
LoadDLLfunc (KillTimer, 8, user32)
+LoadDLLfunc (MessageBeep, 4, user32)
LoadDLLfunc (MessageBoxA, 16, user32)
LoadDLLfunc (MsgWaitForMultipleObjects, 20, user32)
LoadDLLfunc (OemToCharBuffA, 12, user32)
diff --git a/winsup/cygwin/cygheap.cc b/winsup/cygwin/cygheap.cc
index 7fdb87a3e14..cfc24051e95 100644
--- a/winsup/cygwin/cygheap.cc
+++ b/winsup/cygwin/cygheap.cc
@@ -14,8 +14,8 @@
#include <assert.h>
#include <stdlib.h>
#include "security.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "cygerrno.h"
#include "cygheap.h"
diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc
index d008bd97e3a..37212730008 100644
--- a/winsup/cygwin/dcrt0.cc
+++ b/winsup/cygwin/dcrt0.cc
@@ -24,8 +24,8 @@ details. */
#define NEED_VFORK
#include "perprocess.h"
#include "security.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
#include "child_info_magic.h"
diff --git a/winsup/cygwin/debug.cc b/winsup/cygwin/debug.cc
new file mode 100644
index 00000000000..e85717bcac9
--- /dev/null
+++ b/winsup/cygwin/debug.cc
@@ -0,0 +1,227 @@
+/* debug.cc
+
+ Copyright 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include "sync.h"
+#include "sigproc.h"
+#include "pinfo.h"
+#include "perthread.h"
+#include "perprocess.h"
+#include "security.h"
+#include "cygerrno.h"
+#ifdef DEBUGGING
+#include <errno.h>
+#include "path.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "cygheap.h"
+#endif
+
+#undef CloseHandle
+
+#ifdef DEBUGGING
+/* Here lies extra debugging routines which help track down internal
+ Cygwin problems when compiled with -DDEBUGGING . */
+#include <stdlib.h>
+#define NFREEH (sizeof (cygheap->debug.freeh) / sizeof (cygheap->debug.freeh[0]))
+
+class lock_debug
+{
+ static muto *locker;
+ bool acquired;
+ public:
+ lock_debug () : acquired (0)
+ {
+ extern int exit_state;
+ if (locker && !exit_state)
+ acquired = !!locker->acquire (INFINITE);
+ }
+ void unlock ()
+ {
+ if (locker && acquired)
+ {
+ locker->release ();
+ acquired = false;
+ }
+ }
+ ~lock_debug () {unlock ();}
+ friend void debug_init ();
+};
+
+muto NO_COPY *lock_debug::locker = NULL;
+
+static bool __stdcall mark_closed (const char *, int, HANDLE, const char *, BOOL);
+
+void
+debug_init ()
+{
+ muto *debug_lock_muto;
+ lock_debug::locker = new_muto (debug_lock_muto);
+}
+
+/* Find a registered handle in the linked list of handles. */
+static handle_list * __stdcall
+find_handle (HANDLE h)
+{
+ handle_list *hl;
+ for (hl = &cygheap->debug.starth; hl->next != NULL; hl = hl->next)
+ if (hl->next->h == h)
+ goto out;
+ cygheap->debug.endh = hl;
+ hl = NULL;
+
+out:
+ return hl;
+}
+
+#ifdef DEBUGGING_AND_FDS_PROTECTED
+void
+setclexec (HANDLE oh, HANDLE nh, bool not_inheriting)
+{
+ handle_list *hl = find_handle (oh);
+ if (hl)
+ {
+ hl = hl->next;
+ hl->inherited = !not_inheriting;
+ hl->h = nh;
+ }
+}
+#endif
+
+/* Create a new handle record */
+static handle_list * __stdcall
+newh ()
+{
+ handle_list *hl;
+ lock_debug here;
+
+ for (hl = cygheap->debug.freeh; hl < cygheap->debug.freeh + NFREEH; hl++)
+ if (hl->name == NULL)
+ return hl;
+
+ return NULL;
+}
+
+/* Add a handle to the linked list of known handles. */
+void __stdcall
+add_handle (const char *func, int ln, HANDLE h, const char *name, bool inh)
+{
+ handle_list *hl;
+ lock_debug here;
+
+ if ((hl = find_handle (h)))
+ {
+ hl = hl->next;
+ if (hl->name == name && hl->func == func && hl->ln == ln)
+ return;
+ system_printf ("%s:%d - multiple attempts to add handle %s<%p>", func,
+ ln, name, h);
+ system_printf (" previously allocated by %s:%d(%s<%p>) winpid %d",
+ hl->func, hl->ln, hl->name, hl->h, hl->pid);
+ return;
+ }
+
+ if ((hl = newh ()) == NULL)
+ {
+ here.unlock ();
+ debug_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;
+ hl->inherited = inh;
+ hl->pid = GetCurrentProcessId ();
+ cygheap->debug.endh->next = hl;
+ cygheap->debug.endh = hl;
+ debug_printf ("protecting handle '%s', inherited flag %d", hl->name, hl->inherited);
+
+ return;
+}
+
+static void __stdcall
+delete_handle (handle_list *hl)
+{
+ handle_list *hnuke = hl->next;
+ debug_printf ("nuking handle '%s'", hnuke->name);
+ hl->next = hl->next->next;
+ memset (hnuke, 0, sizeof (*hnuke));
+}
+
+void
+debug_fixup_after_fork_exec ()
+{
+ /* No lock needed at this point */
+ handle_list *hl;
+ for (hl = &cygheap->debug.starth; hl->next != NULL; /* nothing */)
+ if (hl->next->inherited)
+ hl = hl->next;
+ else
+ delete_handle (hl); // removes hl->next
+}
+
+static bool __stdcall
+mark_closed (const char *func, int ln, HANDLE h, const char *name, BOOL force)
+{
+ handle_list *hl;
+ lock_debug here;
+
+ if ((hl = find_handle (h)) && !force)
+ {
+ hl = hl->next;
+ here.unlock (); // race here
+ system_printf ("attempt to close protected handle %s:%d(%s<%p>) winpid %d",
+ hl->func, hl->ln, hl->name, hl->h, hl->pid);
+ 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);
+ }
+
+ if (hl)
+ delete_handle (hl);
+
+ return TRUE;
+}
+
+/* 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;
+ lock_debug here;
+
+ if (!mark_closed (func, ln, h, name, force))
+ return FALSE;
+
+ ret = CloseHandle (h);
+
+#if 0 /* Uncomment to see CloseHandle failures */
+ if (!ret)
+ small_printf ("CloseHandle(%s) failed %s:%d\n", name, func, ln);
+#endif
+ return ret;
+}
+
+int __stdcall
+__set_errno (const char *func, int ln, int val)
+{
+ debug_printf ("%s:%d val %d", func, ln, val);
+ return _impure_ptr->_errno = val;
+}
+#endif /*DEBUGGING*/
diff --git a/winsup/cygwin/devices.h b/winsup/cygwin/devices.h
index c91b0df7622..a3853f4c0ae 100644
--- a/winsup/cygwin/devices.h
+++ b/winsup/cygwin/devices.h
@@ -1,6 +1,6 @@
/* devices.h
- Copyright 2002 Red Hat, Inc.
+ Copyright 2002, 2003 Red Hat, Inc.
This file is part of Cygwin.
diff --git a/winsup/cygwin/dir.cc b/winsup/cygwin/dir.cc
new file mode 100644
index 00000000000..3eb148c9188
--- /dev/null
+++ b/winsup/cygwin/dir.cc
@@ -0,0 +1,345 @@
+/* dir.cc: Posix directory-related routines
+
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#define _COMPILING_NEWLIB
+#include <dirent.h>
+
+#include "pinfo.h"
+#include "cygerrno.h"
+#include "security.h"
+#include "path.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "cygheap.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)
+{
+#if 0
+ char dir[strlen (file) + 1];
+
+ strcpy (dir, file);
+
+ const char *usedir;
+ char *slash = strrchr (dir, '\\');
+ if (slash == NULL)
+ usedir = ".";
+ else if (slash == dir)
+ {
+ usedir = "\\";
+ }
+ else
+ {
+ *slash = '\0';
+ usedir = dir;
+ }
+
+ int acc = access (usedir, W_OK);
+
+ return acc == 0;
+#else
+ return 1;
+#endif
+}
+
+extern "C" int
+dirfd (DIR *dir)
+{
+ if (check_null_invalid_struct_errno (dir))
+ return -1;
+ if (dir->__d_cookie != __DIRENT_COOKIE)
+ {
+ set_errno (EBADF);
+ syscall_printf ("-1 = dirfd (%p)", dir);
+ return -1;
+ }
+ return dir->__d_dirent->d_fd;
+}
+
+/* opendir: POSIX 5.1.2.1 */
+extern "C" DIR *
+opendir (const char *name)
+{
+ fhandler_base *fh;
+ DIR *res;
+
+ fh = build_fh_name (name, NULL, PC_SYM_FOLLOW | PC_FULL);
+ if (!fh)
+ res = NULL;
+ else if (fh->exists ())
+ res = fh->opendir ();
+ else
+ {
+ set_errno (ENOENT);
+ res = NULL;
+ }
+
+ if (!res && fh)
+ delete fh;
+ return res;
+}
+
+/* readdir: POSIX 5.1.2.1 */
+extern "C" struct dirent *
+readdir (DIR *dir)
+{
+ if (check_null_invalid_struct_errno (dir))
+ return NULL;
+
+ if (dir->__d_cookie != __DIRENT_COOKIE)
+ {
+ set_errno (EBADF);
+ syscall_printf ("%p = readdir (%p)", NULL, dir);
+ return NULL;
+ }
+
+ dirent *res = ((fhandler_base *) dir->__d_u.__d_data.__fh)->readdir (dir);
+
+ if (res)
+ {
+ /* Compute d_ino by combining filename hash with the directory hash
+ (which was stored in dir->__d_dirhash when opendir was called). */
+ if (res->d_name[0] == '.')
+ {
+ if (res->d_name[1] == '\0')
+ dir->__d_dirent->d_ino = dir->__d_dirhash;
+ else if (res->d_name[1] != '.' || res->d_name[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, res->d_name);
+ }
+ }
+ return res;
+}
+
+extern "C" __off64_t
+telldir64 (DIR *dir)
+{
+ if (check_null_invalid_struct_errno (dir))
+ return -1;
+
+ if (dir->__d_cookie != __DIRENT_COOKIE)
+ return 0;
+ return ((fhandler_base *) dir->__d_u.__d_data.__fh)->telldir (dir);
+}
+
+/* telldir */
+extern "C" __off32_t
+telldir (DIR *dir)
+{
+ return telldir64 (dir);
+}
+
+extern "C" void
+seekdir64 (DIR *dir, __off64_t loc)
+{
+ if (check_null_invalid_struct_errno (dir))
+ return;
+
+ if (dir->__d_cookie != __DIRENT_COOKIE)
+ return;
+ return ((fhandler_base *) dir->__d_u.__d_data.__fh)->seekdir (dir, loc);
+}
+
+/* seekdir */
+extern "C" void
+seekdir (DIR *dir, __off32_t loc)
+{
+ seekdir64 (dir, (__off64_t)loc);
+}
+
+/* rewinddir: POSIX 5.1.2.1 */
+extern "C" void
+rewinddir (DIR *dir)
+{
+ if (check_null_invalid_struct_errno (dir))
+ return;
+
+ if (dir->__d_cookie != __DIRENT_COOKIE)
+ return;
+ return ((fhandler_base *) dir->__d_u.__d_data.__fh)->rewinddir (dir);
+}
+
+/* closedir: POSIX 5.1.2.1 */
+extern "C" int
+closedir (DIR *dir)
+{
+ if (check_null_invalid_struct_errno (dir))
+ return -1;
+
+ if (dir->__d_cookie != __DIRENT_COOKIE)
+ {
+ set_errno (EBADF);
+ syscall_printf ("-1 = closedir (%p)", dir);
+ return -1;
+ }
+
+ /* Reset the marker in case the caller tries to use `dir' again. */
+ dir->__d_cookie = 0;
+
+ int res = ((fhandler_base *) dir->__d_u.__d_data.__fh)->closedir (dir);
+
+ cygheap->fdtab.release (dir->__d_dirent->d_fd);
+
+ free (dir->__d_dirname);
+ free (dir->__d_dirent);
+ free (dir);
+ syscall_printf ("%d = closedir (%p)", res);
+ return res;
+}
+
+/* mkdir: POSIX 5.4.1.1 */
+extern "C" int
+mkdir (const char *dir, mode_t mode)
+{
+ int res = -1;
+ SECURITY_ATTRIBUTES sa = sec_none_nih;
+
+ path_conv real_dir (dir, PC_SYM_NOFOLLOW);
+
+ if (real_dir.error)
+ {
+ set_errno (real_dir.case_clash ? ECASECLASH : real_dir.error);
+ goto done;
+ }
+
+ nofinalslash (real_dir.get_win32 (), real_dir.get_win32 ());
+ if (! writable_directory (real_dir.get_win32 ()))
+ goto done;
+
+ if (allow_ntsec && real_dir.has_acls ())
+ set_security_attribute (S_IFDIR | ((mode & 07777) & ~cygheap->umask),
+ &sa, alloca (4096), 4096);
+
+ if (CreateDirectoryA (real_dir.get_win32 (), &sa))
+ {
+ if (!allow_ntsec && allow_ntea)
+ set_file_attribute (real_dir.has_acls (), real_dir.get_win32 (),
+ S_IFDIR | ((mode & 07777) & ~cygheap->umask));
+#ifdef HIDDEN_DOT_FILES
+ char *c = strrchr (real_dir.get_win32 (), '\\');
+ if ((c && c[1] == '.') || *real_dir.get_win32 () == '.')
+ SetFileAttributes (real_dir.get_win32 (), FILE_ATTRIBUTE_HIDDEN);
+#endif
+ 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;
+ DWORD devn;
+
+ path_conv real_dir (dir, PC_SYM_NOFOLLOW);
+
+ if (real_dir.error)
+ set_errno (real_dir.error);
+ else if ((devn = real_dir.get_devn ()) == FH_PROC || devn == FH_REGISTRY
+ || devn == FH_PROCESS)
+ set_errno (EROFS);
+ else if (!real_dir.exists ())
+ set_errno (ENOENT);
+ else if (!real_dir.isdir ())
+ set_errno (ENOTDIR);
+ else
+ {
+ /* Even own directories can't be removed if R/O attribute is set. */
+ if (real_dir.has_attribute (FILE_ATTRIBUTE_READONLY))
+ SetFileAttributes (real_dir,
+ (DWORD) real_dir & ~FILE_ATTRIBUTE_READONLY);
+
+ if (RemoveDirectory (real_dir))
+ {
+ /* RemoveDirectory on a samba drive doesn't return an error if the
+ directory can't be removed because it's not empty. Checking for
+ existence afterwards keeps us informed about success. */
+ if (GetFileAttributes (real_dir) != INVALID_FILE_ATTRIBUTES)
+ set_errno (ENOTEMPTY);
+ else
+ res = 0;
+ }
+ else
+ {
+ /* This kludge detects if we are attempting to remove the current working
+ directory. If so, we will move elsewhere to potentially allow the
+ rmdir to succeed. This means that cygwin's concept of the current working
+ directory != Windows concept but, hey, whaddaregonnado?
+ Note that this will not cause something like the following to work:
+ $ cd foo
+ $ rmdir .
+ since the shell will have foo "open" in the above case and so Windows will
+ not allow the deletion.
+ FIXME: A potential workaround for this is for cygwin apps to *never* call
+ SetCurrentDirectory. */
+ if (strcasematch (real_dir, cygheap->cwd.win32)
+ && !strcasematch ("c:\\", cygheap->cwd.win32))
+ {
+ DWORD err = GetLastError ();
+ if (!SetCurrentDirectory ("c:\\"))
+ SetLastError (err);
+ else if ((res = rmdir (dir)))
+ SetCurrentDirectory (cygheap->cwd.win32);
+ }
+ if (res)
+ {
+ if (GetLastError () != ERROR_ACCESS_DENIED
+ || !wincap.access_denied_on_delete ())
+ __seterrno ();
+ else
+ set_errno (ENOTEMPTY); /* On 9X ERROR_ACCESS_DENIED is
+ returned if you try to remove a
+ non-empty directory. */
+
+ /* If directory still exists, restore R/O attribute. */
+ if (real_dir.has_attribute (FILE_ATTRIBUTE_READONLY))
+ SetFileAttributes (real_dir, real_dir);
+ }
+ }
+ }
+
+ syscall_printf ("%d = rmdir (%s)", res, dir);
+ return res;
+}
diff --git a/winsup/cygwin/dlfcn.cc b/winsup/cygwin/dlfcn.cc
index b03f685fc6a..563f2db8ab9 100644
--- a/winsup/cygwin/dlfcn.cc
+++ b/winsup/cygwin/dlfcn.cc
@@ -14,9 +14,9 @@ details. */
#include <unistd.h>
#include <ctype.h>
#include "security.h"
+#include "path.h"
#include "fhandler.h"
#include "perprocess.h"
-#include "path.h"
#include "thread.h"
#include "dlfcn.h"
#include "dll_init.h"
diff --git a/winsup/cygwin/dll_init.cc b/winsup/cygwin/dll_init.cc
new file mode 100644
index 00000000000..3b26607c9f6
--- /dev/null
+++ b/winsup/cygwin/dll_init.cc
@@ -0,0 +1,425 @@
+/* dll_init.cc
+
+ Copyright 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include <stdlib.h>
+#include <errno.h>
+#include "cygerrno.h"
+#include "perprocess.h"
+#include "dll_init.h"
+#include "environ.h"
+#include "security.h"
+#include "path.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "cygheap.h"
+#include "pinfo.h"
+
+extern void __stdcall check_sanity_and_sync (per_process *);
+
+dll_list NO_COPY dlls;
+
+static NO_COPY int in_forkee = 0;
+static int dll_global_dtors_recorded;
+
+/* Run destructors for all DLLs on exit. */
+static void
+dll_global_dtors ()
+{
+ for (dll *d = dlls.istart (DLL_ANY); d; d = dlls.inext ())
+ d->p.run_dtors ();
+}
+
+/* Run all constructors associated with a dll */
+void
+per_module::run_ctors ()
+{
+ void (**pfunc)() = 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]) ();
+ }
+}
+
+/* Run all destructors associated with a dll */
+void
+per_module::run_dtors ()
+{
+ void (**pfunc)() = dtors;
+ for (int i = 1; pfunc[i]; i++)
+ (pfunc[i]) ();
+}
+
+/* Initialize an individual DLL */
+int
+dll::init ()
+{
+ int ret = 1;
+
+ /* Why didn't we just import this variable? */
+ *(p.envptr) = __cygwin_environ;
+
+ /* Don't run constructors or the "main" if we've forked. */
+ if (!in_forkee)
+ {
+ /* global contructors */
+ p.run_ctors ();
+
+ /* entry point of dll (use main of per_process with null args...) */
+ if (p.main)
+ ret = (*(p.main)) (0, 0, 0);
+ }
+
+ return ret;
+}
+
+/* Look for a dll based on name */
+dll *
+dll_list::operator[] (const char *name)
+{
+ dll *d = &start;
+ while ((d = d->next) != NULL)
+ if (strcasematch (name, d->name))
+ return d;
+
+ return NULL;
+}
+
+#define RETRIES 1000
+
+/* Allocate space for a dll struct contiguous with the just-loaded dll. */
+dll *
+dll_list::alloc (HINSTANCE h, per_process *p, dll_type type)
+{
+ char name[MAX_PATH + 1];
+ DWORD namelen = GetModuleFileName (h, name, sizeof (name));
+
+ /* Already loaded? */
+ dll *d = dlls[name];
+ if (d)
+ {
+ d->count++; /* Yes. Bump the usage count. */
+ return d; /* Return previously allocated pointer. */
+ }
+
+ SYSTEM_INFO s1;
+ GetSystemInfo (&s1);
+
+ int i;
+ void *s = p->bss_end;
+ DWORD n;
+ MEMORY_BASIC_INFORMATION m;
+ /* Search for space after the DLL */
+ for (i = 0; i <= RETRIES; i++, s = (char *) m.BaseAddress + m.RegionSize)
+ {
+ if (!VirtualQuery (s, &m, sizeof (m)))
+ return NULL; /* Can't do it. */
+ if (m.State == MEM_FREE)
+ {
+ /* Couldn't find any. Uh oh. FIXME: Issue an error? */
+ if (i == RETRIES)
+ return NULL; /* Oh well. Couldn't locate free space. */
+
+ /* Ensure that this is rounded to the nearest page boundary.
+ FIXME: Should this be ensured by VirtualQuery? */
+ n = (DWORD) m.BaseAddress;
+ DWORD r = n % s1.dwAllocationGranularity;
+
+ if (r)
+ n = ((n - r) + s1.dwAllocationGranularity);
+
+ /* First reserve the area of memory, then commit it. */
+ if (VirtualAlloc ((void *) n, sizeof (dll), MEM_RESERVE, PAGE_READWRITE))
+ d = (dll *) VirtualAlloc ((void *) n, sizeof (dll), MEM_COMMIT,
+ PAGE_READWRITE);
+ if (d)
+ break;
+ }
+ }
+
+ /* Did we succeed? */
+ if (d == NULL)
+ { /* Nope. */
+#ifdef DEBUGGING
+ system_printf ("VirtualAlloc failed, %E");
+#endif
+ __seterrno ();
+ return NULL;
+ }
+
+ /* Now we've allocated a block of information. Fill it in with the supplied
+ info about this DLL. */
+ d->count = 1;
+ d->namelen = namelen;
+ strcpy (d->name, name);
+ d->handle = h;
+ d->p = p;
+ d->type = type;
+ if (end == NULL)
+ end = &start; /* Point to "end" of dll chain. */
+ end->next = d; /* Standard linked list stuff. */
+ d->next = NULL;
+ d->prev = end;
+ end = d;
+ tot++;
+ if (type == DLL_LOAD)
+ loaded_dlls++;
+ return d;
+}
+
+/* Detach a DLL from the chain. */
+void
+dll_list::detach (void *retaddr)
+{
+ if (!myself || myself->process_state == PID_EXITED)
+ return;
+ MEMORY_BASIC_INFORMATION m;
+ if (!VirtualQuery (retaddr, &m, sizeof m))
+ return;
+ HMODULE h = (HMODULE) m.AllocationBase;
+
+ dll *d = &start;
+ while ((d = d->next))
+ if (d->handle != h)
+ continue;
+ else if (d->count <= 0)
+ system_printf ("WARNING: try to detach an already detached dll ...");
+ else if (--d->count == 0)
+ {
+ d->p.run_dtors ();
+ d->prev->next = d->next;
+ if (d->next)
+ d->next->prev = d->prev;
+ if (d->type == DLL_LOAD)
+ loaded_dlls--;
+ if (end == d)
+ end = d->prev;
+ VirtualFree (d, 0, MEM_RELEASE);
+ break;
+ }
+}
+
+/* Initialization for all linked DLLs, called by dll_crt0_1. */
+void
+dll_list::init ()
+{
+ /* Make sure that destructors are called on exit. */
+ if (!dll_global_dtors_recorded)
+ {
+ atexit (dll_global_dtors);
+ dll_global_dtors_recorded = 1;
+ }
+
+ /* Walk the dll chain, initializing each dll */
+ dll *d = &start;
+ while ((d = d->next))
+ d->init ();
+}
+
+#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. */
+static 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 = A64K;
+ 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. */
+static 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 < cygheap->user_heap.base
+ || (void *) start > cygheap->user_heap.top) &&
+ ((void *) start < (void *) cygheap
+ | (void *) start > (void *) ((char *) cygheap + CYGHEAPSIZE)))))
+ 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
+dll_list::load_after_fork (HANDLE parent, dll *first)
+{
+ in_forkee = 1;
+ int try2 = 0;
+ dll d;
+
+ void *next = first;
+ while (next)
+ {
+ DWORD nb;
+ /* Read the dll structure from the parent. */
+ if (!ReadProcessMemory (parent, next, &d, sizeof (dll), &nb) ||
+ nb != sizeof (dll))
+ return;
+
+ /* We're only interested in dynamically loaded dlls.
+ Hopefully, this function wouldn't even have been called unless
+ the parent had some of those. */
+ if (d.type == DLL_LOAD)
+ {
+ HMODULE h = LoadLibraryEx (d.name, NULL, DONT_RESOLVE_DLL_REFERENCES);
+
+ /* See if DLL will load in proper place. If so, free it and reload
+ it the right way.
+ It sort of stinks that we can't invert the order of the FreeLibrary
+ and LoadLibrary since Microsoft documentation seems to imply that that
+ should do what we want. However, since the library was loaded above,
+ the second LoadLibrary does not execute it's startup code unless it
+ is first unloaded. */
+ if (h == d.handle)
+ {
+ FreeLibrary (h);
+ LoadLibrary (d.name);
+ }
+ else if (try2)
+ api_fatal ("unable to remap %s to same address as parent(%p) != %p",
+ d.name, d.handle, h);
+ else
+ {
+ /* It loaded in the wrong place. Dunno why this happens but it always
+ seems to happen when there are multiple DLLs attempting to load into
+ the same address space. In the "forked" process, the second DLL always
+ loads into a different location. */
+ FreeLibrary (h);
+ /* Block all of the memory up to the new load address. */
+ reserve_upto (d.name, (DWORD) d.handle);
+ try2 = 1; /* And try */
+ continue; /* again. */
+ }
+ /* If we reached here, and try2 is set, then there is a lot of memory to
+ release. */
+ if (try2)
+ {
+ release_upto (d.name, (DWORD) d.handle);
+ try2 = 0;
+ }
+ }
+ next = d.next; /* Get the address of the next DLL. */
+ }
+ in_forkee = 0;
+}
+
+extern "C" int
+dll_dllcrt0 (HMODULE h, per_process *p)
+{
+ if (p == NULL)
+ p = &__cygwin_user_data;
+ else
+ *(p->impure_ptr_ptr) = __cygwin_user_data.impure_ptr;
+
+ /* Partially initialize Cygwin guts for non-cygwin apps. */
+ if (dynamically_loaded && user_data->magic_biscuit == 0)
+ dll_crt0 (p);
+ else
+ check_sanity_and_sync (p);
+
+ dll_type type;
+
+ /* If this function is called before cygwin has finished
+ initializing, then the DLL must be a cygwin-aware DLL
+ that was explicitly linked into the program rather than
+ a dlopened DLL. */
+ if (!cygwin_finished_initializing)
+ type = DLL_LINK;
+ else
+ {
+ type = DLL_LOAD;
+ dlls.reload_on_fork = 1;
+ }
+
+ /* Allocate and initialize space for the DLL. */
+ dll *d = dlls.alloc (h, p, type);
+
+ /* If d == NULL, then something is broken.
+ Otherwise, if we've finished initializing, it's ok to
+ initialize the DLL. If we haven't finished initializing,
+ it may not be safe to call the dll's "main" since not
+ all of cygwin's internal structures may have been set up. */
+ if (!d || (cygwin_finished_initializing && !d->init ()))
+ return -1;
+
+ return (DWORD) d;
+}
+
+/* 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 (dll *)
+{
+ dlls.detach (__builtin_return_address (0));
+}
+
+extern "C" void
+dlfork (int val)
+{
+ dlls.reload_on_fork = val;
+}
+
+/* Called from various places to update all of the individual
+ ideas of the environ block. Explain to me again why we didn't
+ just import __cygwin_environ? */
+void __stdcall
+update_envptrs ()
+{
+ extern char ***main_environ;
+ for (dll *d = dlls.istart (DLL_ANY); d; d = dlls.inext ())
+ {
+ *(d->p.envptr) = __cygwin_environ;
+ }
+ *main_environ = __cygwin_environ;
+}
diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc
index 5f1ffb98ec2..6a87469a637 100644
--- a/winsup/cygwin/dtable.cc
+++ b/winsup/cygwin/dtable.cc
@@ -27,8 +27,8 @@ details. */
#include "cygerrno.h"
#include "perprocess.h"
#include "security.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
#include "ntdll.h"
@@ -107,12 +107,12 @@ dtable::get_debugger_info ()
for (int i = 0; i < 3; i++)
if (std[i][0])
{
- path_conv pc;
HANDLE h = GetStdHandle (std_consts[i]);
- fhandler_base *fh = build_fhandler_from_name (i, std[i], NULL, pc);
+ fhandler_base *fh = build_fh_name (std[i]);
if (!fh)
continue;
- if (!fh->open (&pc, (i ? O_WRONLY : O_RDONLY) | O_BINARY, 0777))
+ fds[i] = fh;
+ if (!fh->open ((i ? O_WRONLY : O_RDONLY) | O_BINARY, 0777))
release (i);
else
CloseHandle (h);
@@ -206,9 +206,9 @@ cygwin_attach_handle_to_fd (char *name, int fd, HANDLE handle, mode_t bin,
if (fd == -1)
fd = cygheap->fdtab.find_unused_handle ();
path_conv pc;
- fhandler_base *res = cygheap->fdtab.build_fhandler_from_name (fd, name, handle,
- pc);
- res->init (handle, myaccess, bin ?: pc.binmode ());
+ fhandler_base *fh = build_fh_name (name);
+ cygheap->fdtab[fd] = fh;
+ fh->init (handle, myaccess, bin ?: fh->pc_binmode ());
return fd;
}
@@ -270,13 +270,15 @@ dtable::init_std_file_from_handle (int fd, HANDLE handle)
fds[fd] = NULL;
else
{
- path_conv pc;
fhandler_base *fh;
if (dev)
- fh = build_fhandler (fd, dev);
+ fh = build_fh_dev (dev);
else
- fh = build_fhandler_from_name (fd, name, handle, pc);
+ fh = build_fh_name (name);
+
+ if (fh)
+ cygheap->fdtab[fd] = fh;
if (!bin)
{
@@ -286,7 +288,7 @@ dtable::init_std_file_from_handle (int fd, HANDLE handle)
else if (dev)
bin = O_BINARY;
else if (name != unknown_file)
- bin = pc.binmode ();
+ bin = fh->pc_binmode ();
}
fh->init (handle, GENERIC_READ | GENERIC_WRITE, bin);
@@ -296,41 +298,51 @@ dtable::init_std_file_from_handle (int fd, HANDLE handle)
}
fhandler_base *
-dtable::build_fhandler_from_name (int fd, const char *name, HANDLE handle,
- path_conv& pc, unsigned opt, suffix_info *si)
+build_fh_name (const char *name, HANDLE h, unsigned opt, suffix_info *si)
{
- pc.check (name, opt | PC_NULLEMPTY | PC_FULL | PC_POSIX, si);
+ path_conv pc (name, opt | PC_NULLEMPTY | PC_FULL | PC_POSIX, si);
if (pc.error)
{
set_errno (pc.error);
return NULL;
}
- if (!pc.exists () && handle)
- pc.fillin (handle);
+ if (!pc.exists () && h)
+ pc.fillin (h);
- fhandler_base *fh = build_fhandler (fd, pc.dev,
- pc.return_and_clear_normalized_path (),
- pc);
- return fh;
+ return build_fh_pc (pc);
}
fhandler_base *
-dtable::build_fhandler (int fd, const device& dev, const char *unix_name,
- const char *win32_name)
+build_fh_dev (const device& dev, const char *unix_name)
{
- return build_fhandler (fd, dev, cstrdup (unix_name), win32_name);
+ path_conv pc (dev);
+ char *w32buf = const_cast<char *> (pc.get_win32 ());
+
+ __small_sprintf (w32buf, dev.fmt, dev.minor);
+ if (unix_name)
+ pc.normalized_path = cstrdup (unix_name);
+ else if (!dev.upper)
+ pc.normalized_path = cstrdup (dev.name);
+ else
+ {
+ pc.normalized_path = cstrdup (w32buf);
+ for (char *p = strchr (pc.normalized_path, '\\');
+ p;
+ p = strchr (p + 1, '\\'))
+ *p = '/';
+ }
+ return build_fh_pc (pc);
}
#define cnew(name) new ((void *) ccalloc (HEAP_FHANDLER, 1, sizeof (name))) name
fhandler_base *
-dtable::build_fhandler (int fd, const device& dev, char *unix_name,
- const char *win32_name)
+build_fh_pc (path_conv& pc)
{
fhandler_base *fh = NULL;
- if (dev.upper)
- switch (dev.major)
+ if (pc.dev.upper)
+ switch (pc.dev.major)
{
case DEV_TTYS_MAJOR:
fh = cnew (fhandler_tty_slave) ();
@@ -352,13 +364,16 @@ dtable::build_fhandler (int fd, const device& dev, char *unix_name,
break;
}
else
- switch (dev)
+ switch (pc.dev)
{
case FH_CONSOLE:
case FH_CONIN:
case FH_CONOUT:
if ((fh = cnew (fhandler_console) ()))
- inc_console_fds ();
+ cygheap->fdtab.inc_console_fds ();
+ break;
+ case FH_CYGDRIVE:
+ fh = cnew (fhandler_cygdrive) ();
break;
case FH_PTYM:
fh = cnew (fhandler_pty_master) ();
@@ -379,7 +394,7 @@ dtable::build_fhandler (int fd, const device& dev, char *unix_name,
break;
case FH_SOCKET:
if ((fh = cnew (fhandler_socket) ()))
- inc_need_fixup_before ();
+ cygheap->fdtab.inc_need_fixup_before ();
break;
case FH_FS:
fh = cnew (fhandler_disk_file) ();
@@ -415,13 +430,13 @@ dtable::build_fhandler (int fd, const device& dev, char *unix_name,
break;
case FH_TTY:
{
- device newdev = dev;
+ device newdev = pc.dev;
newdev.tty_to_real_device ();
switch (newdev)
{
case FH_CONSOLE:
if ((fh = cnew (fhandler_console) ()))
- inc_console_fds ();
+ cygheap->fdtab.inc_console_fds ();
break;
case FH_TTYS:
fh = cnew (fhandler_tty_slave) ();
@@ -433,44 +448,15 @@ dtable::build_fhandler (int fd, const device& dev, char *unix_name,
if (!fh)
fh = cnew (fhandler_nodevice) ();
- char w32buf[MAX_PATH + 1];
- if (!unix_name || !*unix_name)
- {
- if (!win32_name && dev.fmt && *dev.fmt)
- {
- sprintf (w32buf, dev.fmt, dev.minor);
- win32_name = w32buf;
- }
- if (win32_name)
- {
- unix_name = cstrdup (w32buf);
- for (char *p = strchr (unix_name, '\\'); p; p = strchr (p + 1, '\\'))
- *p = '/';
- }
- }
-
- fh->dev = dev;
- if (unix_name)
- {
- if (!win32_name)
- {
- /* FIXME: ? Should we call win32_device_name here?
- It seems like overkill, but... */
- win32_name = strcpy (w32buf, unix_name);
- for (char *p = w32buf; (p = strchr (p, '/')); p++)
- *p = '\\';
- }
- fh->set_name (unix_name, win32_name);
- }
-
- debug_printf ("fd %d, fh %p", fd, fh);
- return fd >= 0 ? (fds[fd] = fh) : fh;
+ fh->set_name (pc);
+ debug_printf ("fh %p", fh);
+ return fh;
}
fhandler_base *
dtable::dup_worker (fhandler_base *oldfh)
{
- fhandler_base *newfh = build_fhandler (-1, oldfh->dev);
+ fhandler_base *newfh = build_fh_pc (oldfh->pc);
*newfh = *oldfh;
newfh->set_io_handle (NULL);
if (oldfh->dup (newfh))
@@ -817,9 +803,7 @@ handle_to_fn (HANDLE h, char *posix_fn)
|| !QueryDosDevice (NULL, fnbuf, sizeof (fnbuf)))
return strcpy (posix_fn, win32_fn);
- char *p = strchr (win32_fn + DEVICE_PREFIX_LEN, '\\');
- if (!p)
- p = strchr (win32_fn + DEVICE_PREFIX_LEN, '\0');
+ char *p = strechr (win32_fn + DEVICE_PREFIX_LEN, '\\');
int n = p - win32_fn;
int maxmatchlen = 0;
diff --git a/winsup/cygwin/dtable.h b/winsup/cygwin/dtable.h
index 07c976e86b3..f1f0d456c3d 100644
--- a/winsup/cygwin/dtable.h
+++ b/winsup/cygwin/dtable.h
@@ -16,6 +16,7 @@ details. */
class suffix_info;
class fhandler_fifo;
+#define BFH_OPTS (PC_NULLEMPTY | PC_FULL | PC_POSIX)
class dtable
{
fhandler_base **fds;
@@ -50,14 +51,6 @@ public:
void fixup_before_exec (DWORD win_proc_id);
void fixup_before_fork (DWORD win_proc_id);
void fixup_after_fork (HANDLE);
- fhandler_base *build_fhandler (int fd, const device& dev, const char *unix_name,
- const char *win32_name = NULL);
- fhandler_base *build_fhandler (int fd, const device& dev, char *unix_name = NULL,
- const char *win32_name = NULL);
- fhandler_base *build_fhandler_from_name (int fd, const char *name, HANDLE h,
- path_conv& pc,
- unsigned opts = PC_SYM_FOLLOW,
- suffix_info *si = NULL);
inline int not_open (int fd)
{
SetResourceLock (LOCK_FD_LIST, READ_LOCK, "not_open");
@@ -73,7 +66,7 @@ public:
void init_std_file_from_handle (int fd, HANDLE handle);
int dup2 (int oldfd, int newfd);
void fixup_after_exec (HANDLE);
- inline fhandler_base *operator [](int fd) const { return fds[fd]; }
+ inline fhandler_base *&operator [](int fd) const { 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);
@@ -85,6 +78,10 @@ public:
fhandler_fifo *find_fifo (ATOM);
};
+fhandler_base *build_fh_dev (const device&, const char * = NULL);
+fhandler_base *build_fh_name (const char *unix_name, HANDLE = NULL, unsigned = 0, suffix_info * = NULL);
+fhandler_base *build_fh_pc (path_conv& pc);
+
void dtable_init (void);
void stdio_init (void);
extern dtable fdtab;
diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc
new file mode 100644
index 00000000000..6a112518ee7
--- /dev/null
+++ b/winsup/cygwin/environ.cc
@@ -0,0 +1,1002 @@
+/* environ.cc: Cygwin-adopted functions from newlib to manipulate
+ process's environment.
+
+ Copyright 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <ctype.h>
+#include <assert.h>
+#include <sys/cygwin.h>
+#include <cygwin/version.h>
+#include "pinfo.h"
+#include "perprocess.h"
+#include "security.h"
+#include "path.h"
+#include "fhandler.h"
+#include "cygerrno.h"
+#include "dtable.h"
+#include "cygheap.h"
+#include "registry.h"
+#include "environ.h"
+#include "child_info.h"
+
+extern BOOL allow_daemon;
+extern BOOL allow_glob;
+extern bool ignore_case_with_glob;
+extern BOOL allow_ntea;
+extern BOOL allow_smbntsec;
+extern BOOL allow_winsymlinks;
+extern BOOL strip_title_path;
+extern int pcheck_case;
+extern int subauth_id;
+BOOL reset_com = FALSE;
+static BOOL envcache = TRUE;
+
+static char **lastenviron;
+
+#define ENVMALLOC \
+ (CYGWIN_VERSION_DLL_MAKE_COMBINED (user_data->api_major, user_data->api_minor) \
+ <= CYGWIN_VERSION_DLL_MALLOC_ENV)
+
+#define NL(x) x, (sizeof (x) - 1)
+/* 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 NO_COPY win_env conv_envvars[] =
+ {
+ {NL ("PATH="), 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},
+ {NL ("HOME="), NULL, NULL, cygwin_conv_to_full_posix_path,
+ cygwin_conv_to_full_win32_path, return_MAX_PATH, return_MAX_PATH},
+ {NL ("LD_LIBRARY_PATH="), NULL, NULL, cygwin_conv_to_full_posix_path,
+ cygwin_conv_to_full_win32_path, return_MAX_PATH, return_MAX_PATH},
+ {NL ("TMPDIR="), NULL, NULL, cygwin_conv_to_full_posix_path,
+ cygwin_conv_to_full_win32_path, return_MAX_PATH, return_MAX_PATH},
+ {NL ("TMP="), NULL, NULL, cygwin_conv_to_full_posix_path,
+ cygwin_conv_to_full_win32_path, return_MAX_PATH, return_MAX_PATH},
+ {NL ("TEMP="), NULL, NULL, cygwin_conv_to_full_posix_path,
+ cygwin_conv_to_full_win32_path, return_MAX_PATH, return_MAX_PATH},
+ {NULL, 0, NULL, NULL, NULL, NULL, 0, 0}
+ };
+
+static unsigned char conv_start_chars[256] = {0};
+
+void
+win_env::add_cache (const char *in_posix, const char *in_native)
+{
+ MALLOC_CHECK;
+ 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);
+ }
+ MALLOC_CHECK;
+ 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. *in_posix is any
+ known posix value for the environment variable. Returns a pointer to
+ the appropriate conversion structure. */
+win_env * __stdcall
+getwinenv (const char *env, const char *in_posix)
+{
+ if (!conv_start_chars[(unsigned char)*env])
+ return NULL;
+
+ for (int i = 0; conv_envvars[i].name != NULL; i++)
+ if (strncmp (env, conv_envvars[i].name, conv_envvars[i].namelen) == 0)
+ {
+ win_env * const we = conv_envvars + i;
+ const char *val;
+ if (!cur_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) != 0)
+ 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;
+
+ if (!(conv = getwinenv (src)))
+ return;
+
+ int len = strcspn (src, "=") + 1;
+
+ /* 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 != '/' ? value : NULL);
+
+ debug_printf ("env var converted to %s", outenv);
+ *here = outenv;
+ free (src);
+ MALLOC_CHECK;
+}
+
+/*
+ * 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 = cur_environ (); *p; ++p)
+ if (!strncmp (*p, name, len))
+ if (*(c = *p + len) == '=')
+ {
+ *offset = p - cur_environ ();
+ return (char *) (++c);
+ }
+ MALLOC_CHECK;
+ 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);
+}
+
+static int __stdcall
+envsize (const char * const *in_envp)
+{
+ const char * const *envp;
+ for (envp = in_envp; *envp; envp++)
+ continue;
+ return (1 + envp - in_envp) * sizeof (const char *);
+}
+
+/* Takes similar arguments to setenv except that overwrite is
+ either -1, 0, or 1. 0 or 1 signify that the function should
+ perform similarly to setenv. Otherwise putenv is assumed. */
+static int __stdcall
+_addenv (const char *name, const char *value, int overwrite)
+{
+ int issetenv = overwrite >= 0;
+ int offset;
+ char *p;
+
+ unsigned int valuelen = strlen (value);
+ if ((p = my_findenv (name, &offset)))
+ { /* Already exists. */
+ if (!overwrite) /* Ok to overwrite? */
+ return 0; /* No. Wanted to add new value. FIXME: Right return value? */
+
+ /* We've found the offset into environ. If this is a setenv call and
+ there is room in the current environment entry then just overwrite it.
+ Otherwise handle this case below. */
+ if (issetenv && strlen (p) >= valuelen)
+ {
+ strcpy (p, value);
+ return 0;
+ }
+ }
+ else
+ { /* Create new slot. */
+ int sz = envsize (cur_environ ());
+ int allocsz = sz + (2 * sizeof (char *));
+
+ offset = (sz - 1) / sizeof (char *);
+
+ /* Allocate space for additional element plus terminating NULL. */
+ if (cur_environ () == lastenviron)
+ lastenviron = __cygwin_environ = (char **) realloc (cur_environ (),
+ allocsz);
+ else if ((lastenviron = (char **) malloc (allocsz)) != NULL)
+ __cygwin_environ = (char **) memcpy ((char **) lastenviron,
+ __cygwin_environ, sz);
+
+ if (!__cygwin_environ)
+ {
+#ifdef DEBUGGING
+ try_to_debug ();
+#endif
+ return -1; /* Oops. No more memory. */
+ }
+
+ __cygwin_environ[offset + 1] = NULL; /* NULL terminate. */
+ update_envptrs (); /* Update any local copies of 'environ'. */
+ }
+
+ char *envhere;
+ if (!issetenv)
+ /* Not setenv. Just overwrite existing. */
+ envhere = cur_environ ()[offset] = (char *) (ENVMALLOC ? strdup (name) : name);
+ else
+ { /* setenv */
+ /* Look for an '=' in the name and ignore anything after that if found. */
+ for (p = (char *) name; *p && *p != '='; p++)
+ continue;
+
+ int namelen = p - name; /* Length of name. */
+ /* Allocate enough space for name + '=' + value + '\0' */
+ envhere = cur_environ ()[offset] = (char *) malloc (namelen + valuelen + 2);
+ if (!envhere)
+ return -1; /* Oops. No more memory. */
+
+ /* Put name '=' value into current slot. */
+ strncpy (envhere, name, namelen);
+ envhere[namelen] = '=';
+ strcpy (envhere + namelen + 1, value);
+ }
+
+ /* Update cygwin's cache, if appropriate */
+ win_env *spenv;
+ if ((spenv = getwinenv (envhere)))
+ spenv->add_cache (value);
+
+ MALLOC_CHECK;
+ return 0;
+}
+
+/* putenv Sets an environment variable */
+extern "C" int
+putenv (const char *str)
+{
+ int res;
+ if ((res = check_null_empty_str (str)))
+ {
+ if (res == ENOENT)
+ return 0;
+ set_errno (res);
+ return -1;
+ }
+ char *eq = strchr (str, '=');
+ if (eq)
+ return _addenv (str, eq + 1, -1);
+
+ /* Remove str from the environment. */
+ unsetenv (str);
+ return 0;
+}
+
+/* setenv -- Set the value of the environment variable "name" to be
+ "value". If overwrite is set, replace any current value. */
+extern "C" int
+setenv (const char *name, const char *value, int overwrite)
+{
+ int res;
+ if ((res = check_null_empty_str (value)) == EFAULT)
+ {
+ set_errno (res);
+ return -1;
+ }
+ if ((res = check_null_empty_str (name)))
+ {
+ if (res == ENOENT)
+ return 0;
+ set_errno (res);
+ return -1;
+ }
+ if (*value == '=')
+ value++;
+ return _addenv (name, value, !!overwrite);
+}
+
+/* unsetenv(name) -- Delete environment variable "name". */
+extern "C" void
+unsetenv (const char *name)
+{
+ register char **e;
+ int offset;
+
+ while (my_findenv (name, &offset)) /* if set multiple times */
+ /* Move up the rest of the array */
+ for (e = cur_environ () + offset; ; e++)
+ if (!(*e = *(e + 1)))
+ break;
+}
+
+/* Turn environment variable part of a=b string into uppercase. */
+static __inline__ void
+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 = cyg_toupper (*p);
+}
+
+/* Parse CYGWIN options */
+
+static NO_COPY BOOL export_settings = false;
+
+enum settings
+ {
+ justset,
+ isfunc,
+ setbit,
+ set_process_state,
+ };
+
+/* When BUF is:
+ null or empty: disables globbing
+ "ignorecase": enables case-insensitive globbing
+ anything else: enables case-sensitive globbing */
+static void
+glob_init (const char *buf)
+{
+ if (!buf || !*buf)
+ {
+ allow_glob = FALSE;
+ ignore_case_with_glob = FALSE;
+ }
+ else if (strncasematch (buf, "ignorecase", 10))
+ {
+ allow_glob = TRUE;
+ ignore_case_with_glob = TRUE;
+ }
+ else
+ {
+ allow_glob = TRUE;
+ ignore_case_with_glob = FALSE;
+ }
+}
+
+static void
+check_case_init (const char *buf)
+{
+ if (!buf || !*buf)
+ return;
+
+ if (strncmp (buf, "relax", 5)== 0)
+ {
+ pcheck_case = PCHECK_RELAXED;
+ debug_printf ("File case checking set to RELAXED");
+ }
+ else if (strcasematch (buf, "adjust"))
+ {
+ pcheck_case = PCHECK_ADJUST;
+ debug_printf ("File case checking set to ADJUST");
+ }
+ else if (strcasematch (buf, "strict"))
+ {
+ pcheck_case = PCHECK_STRICT;
+ debug_printf ("File case checking set to STRICT");
+ }
+ else
+ {
+ debug_printf ("Wrong case checking name: %s", buf);
+ }
+}
+
+void
+set_file_api_mode (codepage_type cp)
+{
+ if (cp == oem_cp)
+ {
+ SetFileApisToOEM ();
+ debug_printf ("File APIs set to OEM");
+ }
+ else if (cp == ansi_cp)
+ {
+ SetFileApisToANSI ();
+ debug_printf ("File APIs set to ANSI");
+ }
+}
+
+static void
+codepage_init (const char *buf)
+{
+ if (!buf || !*buf)
+ return;
+
+ if (strcasematch (buf, "oem"))
+ {
+ current_codepage = oem_cp;
+ set_file_api_mode (current_codepage);
+ }
+ else if (strcasematch (buf, "ansi"))
+ {
+ current_codepage = ansi_cp;
+ set_file_api_mode (current_codepage);
+ }
+ else
+ debug_printf ("Wrong codepage name: %s", buf);
+}
+
+static void
+subauth_id_init (const char *buf)
+{
+ if (!buf || !*buf)
+ return;
+
+ int i = strtol (buf, NULL, 0);
+
+ /* 0..127 are reserved by Microsoft, 132 is IIS subauthentication. */
+ if (i > 127 && i != 132 && i <= 255)
+ subauth_id = i;
+}
+
+static void
+set_chunksize (const char *buf)
+{
+ wincap.set_chunksize (strtol (buf, NULL, 0));
+}
+
+/* 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. */
+static 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[] NO_COPY =
+{
+ {"binmode", {x: &binmode}, justset, NULL, {{O_TEXT}, {O_BINARY}}},
+ {"check_case", {func: &check_case_init}, isfunc, NULL, {{0}, {0}}},
+ {"codepage", {func: &codepage_init}, isfunc, NULL, {{0}, {0}}},
+ {"daemon", {&allow_daemon}, justset, NULL, {{FALSE}, {TRUE}}},
+ {"envcache", {&envcache}, justset, NULL, {{TRUE}, {FALSE}}},
+ {"error_start", {func: &error_start_init}, isfunc, NULL, {{0}, {0}}},
+ {"export", {&export_settings}, justset, NULL, {{FALSE}, {TRUE}}},
+ {"forkchunk", {func: set_chunksize}, isfunc, NULL, {{0}, {0}}},
+ {"glob", {func: &glob_init}, isfunc, NULL, {{0}, {s: "normal"}}},
+ {"ntea", {&allow_ntea}, justset, NULL, {{FALSE}, {TRUE}}},
+ {"ntsec", {&allow_ntsec}, justset, NULL, {{FALSE}, {TRUE}}},
+ {"smbntsec", {&allow_smbntsec}, justset, NULL, {{FALSE}, {TRUE}}},
+ {"reset_com", {&reset_com}, justset, NULL, {{FALSE}, {TRUE}}},
+ {"strip_title", {&strip_title_path}, justset, NULL, {{FALSE}, {TRUE}}},
+ {"subauth_id", {func: &subauth_id_init}, isfunc, NULL, {{0}, {0}}},
+ {"title", {&display_title}, justset, NULL, {{FALSE}, {TRUE}}},
+ {"tty", {NULL}, set_process_state, NULL, {{0}, {PID_USETTY}}},
+ {"winsymlinks", {&allow_winsymlinks}, justset, NULL, {{FALSE}, {TRUE}}},
+ {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, *lasts;
+ parse_thing *k;
+
+ if (buf == NULL)
+ {
+ char newbuf[MAX_PATH + 7];
+ newbuf[0] = '\0';
+ for (k = known; k->name != NULL; k++)
+ if (k->remember)
+ {
+ strcat (strcat (newbuf, " "), k->remember);
+ free (k->remember);
+ k->remember = NULL;
+ }
+
+ if (export_settings)
+ {
+ debug_printf ("%s", newbuf + 1);
+ setenv ("CYGWIN", newbuf + 1, 1);
+ }
+ return;
+ }
+
+ buf = strcpy ((char *) alloca (strlen (buf) + 1), buf);
+ for (p = strtok_r (buf, " \t", &lasts);
+ p != NULL;
+ p = strtok_r (NULL, " \t", &lasts))
+ {
+ char *keyword_here = p;
+ 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 (keyword_here);
+ if (n > 0)
+ p[n] = ':';
+ k->remember = p;
+ break;
+ }
+ }
+ debug_printf ("returning");
+ return;
+}
+
+/* Set options from the registry. */
+static bool __stdcall
+regopt (const char *name)
+{
+ bool parsed_something = false;
+ /* 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));
+
+ if (r.get_string (lname, buf, sizeof (buf) - 1, "") == ERROR_SUCCESS)
+ {
+ parse_options (buf);
+ parsed_something = true;
+ }
+ else
+ {
+ reg_key r1 (HKEY_LOCAL_MACHINE, KEY_READ, "SOFTWARE",
+ CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
+ CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
+ CYGWIN_INFO_PROGRAM_OPTIONS_NAME, NULL);
+ if (r1.get_string (lname, buf, sizeof (buf) - 1, "") == ERROR_SUCCESS)
+ {
+ parse_options (buf);
+ parsed_something = true;
+ }
+ }
+ MALLOC_CHECK;
+ return parsed_something;
+}
+
+/* Initialize the environ array. Look for the CYGWIN environment
+ environment variable and set appropriate options from it. */
+void
+environ_init (char **envp, int envc)
+{
+ char *rawenv;
+ int i;
+ char *p;
+ char *newp;
+ int sawTERM = 0;
+ bool envp_passed_in;
+ bool got_something_from_registry;
+ static char NO_COPY cygterm[] = "TERM=cygwin";
+
+ static int initted;
+ if (!initted)
+ {
+ for (int i = 0; conv_envvars[i].name != NULL; i++)
+ {
+ conv_start_chars[(int) cyg_tolower (conv_envvars[i].name[0])] = 1;
+ conv_start_chars[(int) cyg_toupper (conv_envvars[i].name[0])] = 1;
+ }
+ initted = 1;
+ }
+
+ got_something_from_registry = regopt ("default");
+ if (myself->progname[0])
+ got_something_from_registry = regopt (myself->progname) || got_something_from_registry;
+
+ /* Set ntsec explicit as default, if NT is running */
+ if (wincap.has_security ())
+ allow_ntsec = TRUE;
+
+ if (!envp)
+ envp_passed_in = 0;
+ else
+ {
+ envc++;
+ envc *= sizeof (char *);
+ char **newenv = (char **) malloc (envc);
+ memcpy (newenv, envp, envc);
+ cfree (envp);
+
+ /* Older applications relied on the fact that cygwin malloced elements of the
+ environment list. */
+ envp = newenv;
+ if (ENVMALLOC)
+ for (char **e = newenv; *e; e++)
+ {
+ char *p = *e;
+ *e = strdup (p);
+ cfree (p);
+ }
+ envp_passed_in = 1;
+ goto out;
+ }
+
+ /* Allocate space for environment + trailing NULL + CYGWIN env. */
+ lastenviron = envp = (char **) malloc ((4 + (envc = 100)) * sizeof (char *));
+ rawenv = GetEnvironmentStrings ();
+
+ /* 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 >= envc)
+ envp = (char **) realloc (envp, (4 + (envc += 100)) * sizeof (char *));
+ envp[i] = newp;
+ if (*newp == '=')
+ *newp = '!';
+ char *eq = strechr (newp, '=');
+ if (!child_proc_info)
+ ucenv (newp, eq);
+ if (*newp == 'T' && strncmp (newp, "TERM=", 5) == 0)
+ sawTERM = 1;
+ if (*newp == 'C' && strncmp (newp, "CYGWIN=", sizeof ("CYGWIN=") - 1) == 0)
+ parse_options (newp + sizeof ("CYGWIN=") - 1);
+ if (*eq && conv_start_chars[(unsigned char)envp[i][0]])
+ posify (envp + i, *++eq ? eq : --eq);
+ debug_printf ("%p: %s", envp[i], envp[i]);
+ }
+
+ if (!sawTERM)
+ envp[i++] = cygterm;
+ envp[i] = NULL;
+ FreeEnvironmentStrings (rawenv);
+
+out:
+ __cygwin_environ = envp;
+ update_envptrs ();
+ if (envp_passed_in)
+ {
+ p = getenv ("CYGWIN");
+ if (p)
+ parse_options (p);
+ }
+
+ if (got_something_from_registry)
+ parse_options (NULL); /* possibly export registry settings to
+ environment */
+ 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);
+}
+
+char * __stdcall
+getwinenveq (const char *name, size_t namelen, int x)
+{
+ char dum[1];
+ char name0[namelen - 1];
+ memcpy (name0, name, namelen - 1);
+ name0[namelen - 1] = '\0';
+ int totlen = GetEnvironmentVariable (name0, dum, 0);
+ if (totlen > 0)
+ {
+ totlen++;
+ if (x == HEAP_1_STR)
+ totlen += namelen;
+ else
+ namelen = 0;
+ char *p = (char *) cmalloc ((cygheap_types) x, totlen);
+ if (namelen)
+ strcpy (p, name);
+ if (GetEnvironmentVariable (name0, p + namelen, totlen))
+ {
+ debug_printf ("using value from GetEnvironmentVariable for '%s'",
+ name0);
+ return p;
+ }
+ else
+ cfree (p);
+ }
+
+ debug_printf ("warning: %s not present in environment", name);
+ return NULL;
+}
+
+struct spenv
+{
+ const char *name;
+ size_t namelen;
+ const char * (cygheap_user::*from_cygheap) (const char *, size_t);
+ char *retrieve (bool, const char * const = NULL)
+ __attribute__ ((regparm (3)));
+};
+
+#define env_dontadd almost_null
+
+/* Keep this list in upper case and sorted */
+static NO_COPY spenv spenvs[] =
+{
+ {NL ("HOMEDRIVE="), &cygheap_user::env_homedrive},
+ {NL ("HOMEPATH="), &cygheap_user::env_homepath},
+ {NL ("LOGONSERVER="), &cygheap_user::env_logsrv},
+ {NL ("SYSTEMDRIVE="), NULL},
+ {NL ("SYSTEMROOT="), NULL},
+ {NL ("USERDOMAIN="), &cygheap_user::env_domain},
+ {NL ("USERNAME="), &cygheap_user::env_name},
+ {NL ("USERPROFILE="), &cygheap_user::env_userprofile},
+};
+
+char *
+spenv::retrieve (bool no_envblock, const char *const envname)
+{
+ if (envname && !strncasematch (envname, name, namelen))
+ return NULL;
+
+ debug_printf ("no_envblock %d", no_envblock);
+
+ if (from_cygheap)
+ {
+ const char *p;
+ if (envname && !cygheap->user.issetuid ())
+ {
+ debug_printf ("duping existing value for '%s'", name);
+ return cstrdup1 (envname); /* Don't really care what it's set to
+ if we're calling a cygwin program */
+ }
+
+ /* Calculate (potentially) value for given environment variable. */
+ p = (cygheap->user.*from_cygheap) (name, namelen);
+ if (!p || (no_envblock && !envname) || (p == env_dontadd))
+ return env_dontadd;
+ char *s = (char *) cmalloc (HEAP_1_STR, namelen + strlen (p) + 1);
+ strcpy (s, name);
+ (void) strcpy (s + namelen, p);
+ debug_printf ("using computed value for '%s'", name);
+ return s;
+ }
+
+ if (envname)
+ return cstrdup1 (envname);
+
+ return getwinenveq (name, namelen, HEAP_1_STR);
+}
+
+#define SPENVS_SIZE (sizeof (spenvs) / sizeof (spenvs[0]))
+
+/* 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 ** __stdcall
+build_env (const char * const *envp, char *&envblock, int &envc,
+ bool no_envblock)
+{
+ int len, n;
+ const char * const *srcp;
+ char **dstp;
+ bool saw_spenv[SPENVS_SIZE] = {0};
+
+ debug_printf ("envp %p", envp);
+
+ /* How many elements? */
+ for (n = 0; envp[n]; n++)
+ continue;
+
+ /* Allocate a new "argv-style" environ list with room for extra stuff. */
+ char **newenv = (char **) cmalloc (HEAP_1_ARGV, sizeof (char *) *
+ (n + SPENVS_SIZE + 1));
+
+ int tl = 0;
+ /* Iterate over input list, generating a new environment list and refreshing
+ "special" entries, if necessary. */
+ for (srcp = envp, dstp = newenv; *srcp; srcp++)
+ {
+ /* Look for entries that require special attention */
+ for (unsigned i = 0; i < SPENVS_SIZE; i++)
+ if (!saw_spenv[i] && (*dstp = spenvs[i].retrieve (no_envblock, *srcp)))
+ {
+ saw_spenv[i] = 1;
+ if (*dstp == env_dontadd)
+ goto next1;
+ goto next0;
+ }
+
+ /* Add entry to new environment */
+ *dstp = cstrdup1 (*srcp);
+
+ next0:
+ /* If necessary, calculate rough running total for envblock size */
+ if (!no_envblock)
+ tl += strlen (*dstp) + 1;
+ dstp++;
+ next1:
+ continue;
+ }
+
+ assert ((srcp - envp) == n);
+ /* Fill in any required-but-missing environment variables. */
+ for (unsigned i = 0; i < SPENVS_SIZE; i++)
+ if (!saw_spenv[i])
+ {
+ *dstp = spenvs[i].retrieve (no_envblock);
+ if (*dstp && !no_envblock && *dstp != env_dontadd)
+ {
+ tl += strlen (*dstp) + 1;
+ dstp++;
+ }
+ }
+
+ envc = dstp - newenv; /* Number of entries in newenv */
+ assert ((size_t) envc <= (n + SPENVS_SIZE));
+ *dstp = NULL; /* Terminate */
+
+ if (no_envblock)
+ envblock = NULL;
+ else
+ {
+ debug_printf ("env count %d, bytes %d", envc, tl);
+
+ /* Windows programs expect the environment block to be sorted. */
+ qsort (newenv, envc, sizeof (char *), env_sort);
+
+ /* Create an environment block suitable for passing to CreateProcess. */
+ char *s;
+ envblock = (char *) malloc (2 + tl);
+ int new_tl = 0;
+ for (srcp = newenv, s = envblock; *srcp; srcp++)
+ {
+ const char *p;
+ win_env *conv;
+ len = strcspn (*srcp, "=") + 1;
+
+ /* See if this entry requires posix->win32 conversion. */
+ conv = getwinenv (*srcp, *srcp + len);
+ if (conv)
+ p = conv->native; /* Use win32 path */
+ else
+ p = *srcp; /* Don't worry about it */
+
+ len = strlen (p);
+ new_tl += len + 1; /* Keep running total of block length so far */
+
+ /* See if we need to increase the size of the block. */
+ if (new_tl > tl)
+ {
+ tl = new_tl + 100;
+ char *new_envblock =
+ (char *) realloc (envblock, 2 + tl);
+ /* If realloc moves the block, move `s' with it. */
+ if (new_envblock != envblock)
+ {
+ s += new_envblock - envblock;
+ envblock = new_envblock;
+ }
+ }
+
+ memcpy (s, p, len + 1);
+
+ /* See if environment variable is "special" in a Windows sense.
+ Under NT, the current directories for visited drives are stored
+ as =C:=\bar. Cygwin converts the '=' to '!' for hopefully obvious
+ reasons. We need to convert it back when building the envblock */
+ if (s[0] == '!' && (isdrive (s + 1) || (s[1] == ':' && s[2] == ':'))
+ && s[3] == '=')
+ *s = '=';
+ s += len + 1;
+ }
+ *s = '\0'; /* Two null bytes at the end */
+ assert ((s - envblock) <= tl); /* Detect if we somehow ran over end
+ of buffer */
+ }
+
+ debug_printf ("envp %p, envc %d", newenv, envc);
+ return newenv;
+}
+
+/* This idiocy is necessary because the early implementers of cygwin
+ did not seem to know about importing data variables from the DLL.
+ So, we have to synchronize cygwin's idea of the environment with the
+ main program's with each reference to the environment. */
+extern "C" char ** __stdcall
+cur_environ ()
+{
+ if (*main_environ != __cygwin_environ)
+ {
+ __cygwin_environ = *main_environ;
+ update_envptrs ();
+ }
+
+ return __cygwin_environ;
+}
diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc
index 352cda0d064..e2df0c91315 100644
--- a/winsup/cygwin/exceptions.cc
+++ b/winsup/cygwin/exceptions.cc
@@ -392,17 +392,16 @@ try_to_debug (bool waitloop)
system_printf ("Failed to start debugger: %E");
else
{
- SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_IDLE);
if (!waitloop)
return 1;
+ SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_IDLE);
while (!being_debugged ())
Sleep (0);
Sleep (2000);
small_printf ("*** continuing from debugger call\n");
+ SetThreadPriority (GetCurrentThread (), prio);
}
- SetThreadPriority (GetCurrentThread (), prio);
-
/* FIXME: need to know handles of all running threads to
resume_all_threads_except (current_thread_id);
*/
diff --git a/winsup/cygwin/exec.cc b/winsup/cygwin/exec.cc
new file mode 100644
index 00000000000..af345be99fe
--- /dev/null
+++ b/winsup/cygwin/exec.cc
@@ -0,0 +1,103 @@
+/* exec.cc: exec system call support.
+
+ Copyright 1996, 1997, 1998, 2000, 2001, 2002 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#define _execve __FOO_execve_
+#include "winsup.h"
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <process.h>
+#include "perprocess.h"
+#include "security.h"
+#include "path.h"
+#include "fhandler.h"
+#include "pinfo.h"
+#include "environ.h"
+#include "cygerrno.h"
+#undef _execve
+
+/* This is called _execve and not execve because the real execve is defined
+ in libc/posix/execve.c. It calls us. */
+
+extern "C" int
+execve (const char *path, char *const argv[], char *const envp[])
+{
+ static char *const empty_env[] = { 0 };
+ MALLOC_CHECK;
+ if (!envp)
+ envp = empty_env;
+ return spawnve (_P_OVERLAY, path, argv, envp);
+}
+
+extern "C" int _execve (const char *, char *const [], char *const [])
+ __attribute__ ((alias ("execve")));
+
+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, cur_environ ());
+}
+
+extern "C" int
+execv (const char *path, char * const *argv)
+{
+ MALLOC_CHECK;
+ return execve (path, (char * const *) argv, cur_environ ());
+}
+
+extern "C" pid_t
+sexecve_is_bad ()
+{
+ set_errno (ENOSYS);
+ return 0;
+}
+
+/*
+ * 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
+execvp (const char *path, char * const *argv)
+{
+ path_conv buf;
+ return execv (find_exec (path, buf), argv);
+}
+
+extern "C" int
+execvpe (const char *path, char * const *argv, char *const *envp)
+{
+ path_conv buf;
+ return execve (find_exec (path, buf), argv, envp);
+}
diff --git a/winsup/cygwin/external.cc b/winsup/cygwin/external.cc
new file mode 100644
index 00000000000..9ce62cb3865
--- /dev/null
+++ b/winsup/cygwin/external.cc
@@ -0,0 +1,252 @@
+/* external.cc: Interface to Cygwin internals from external programs.
+
+ Copyright 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+
+ 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 <errno.h>
+#include "security.h"
+#include "sigproc.h"
+#include "pinfo.h"
+#include <exceptions.h>
+#include "shared_info.h"
+#include "cygwin_version.h"
+#include "perprocess.h"
+#include "cygerrno.h"
+#include "path.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "cygheap.h"
+#include "wincap.h"
+#include "heap.h"
+#include "cygthread.h"
+
+static external_pinfo *
+fillout_pinfo (pid_t pid, int winpid)
+{
+ BOOL nextpid;
+ static external_pinfo ep;
+
+ if ((nextpid = !!(pid & CW_NEXTPID)))
+ pid ^= CW_NEXTPID;
+
+ static winpids pids (0);
+
+ static unsigned int i;
+ if (!pids.npids || !nextpid)
+ {
+ pids.set (winpid);
+ i = 0;
+ }
+
+ if (!pid)
+ i = 0;
+
+ memset (&ep, 0, sizeof ep);
+ while (i < pids.npids)
+ {
+ DWORD thispid = pids.winpid (i);
+ _pinfo *p = pids[i];
+ i++;
+
+ if (!p)
+ {
+ if (!nextpid && thispid != (DWORD) pid)
+ continue;
+ ep.pid = cygwin_pid (thispid);
+ ep.dwProcessId = thispid;
+ ep.process_state = PID_IN_USE;
+ ep.ctty = -1;
+ break;
+ }
+ else if (nextpid || p->pid == pid || (winpid && thispid == (DWORD) pid))
+ {
+ ep.ctty = p->ctty;
+ ep.pid = p->pid;
+ ep.ppid = p->ppid;
+ ep.hProcess = p->hProcess;
+ ep.dwProcessId = p->dwProcessId;
+ ep.uid = p->uid;
+ ep.gid = p->gid;
+ ep.pgid = p->pgid;
+ ep.sid = p->sid;
+ ep.umask = 0;
+ 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.version = EXTERNAL_PINFO_VERSION;
+
+ ep.process_state = p->process_state;
+
+ ep.uid32 = p->uid;
+ ep.gid32 = p->gid;
+ break;
+ }
+ }
+
+ if (!ep.pid)
+ {
+ i = 0;
+ pids.reset ();
+ return 0;
+ }
+ return &ep;
+}
+
+static DWORD
+get_cygdrive_info (char *user, char *system, char *user_flags,
+ char *system_flags)
+{
+ int res = mount_table->get_cygdrive_info (user, system, user_flags,
+ system_flags);
+ return (res == ERROR_SUCCESS) ? 1 : 0;
+}
+
+static DWORD
+get_cygdrive_prefixes (char *user, char *system)
+{
+ char user_flags[MAX_PATH];
+ char system_flags[MAX_PATH];
+ DWORD res = get_cygdrive_info (user, system, user_flags, system_flags);
+ return res;
+}
+
+extern "C" DWORD
+cygwin_internal (cygwin_getinfo_types t, ...)
+{
+ va_list arg;
+ va_start (arg, t);
+ if (t != CW_USER_DATA)
+ {
+ wincap.init ();
+ if (!myself)
+ {
+ memory_init ();
+ malloc_init ();
+ set_myself (1);
+ }
+ }
+
+ switch (t)
+ {
+ case CW_LOCK_PINFO:
+ return 1;
+
+ case CW_UNLOCK_PINFO:
+ return 1;
+
+ case CW_GETTHREADNAME:
+ return (DWORD) cygthread::name (va_arg (arg, DWORD));
+
+ case CW_SETTHREADNAME:
+ {
+ set_errno (ENOSYS);
+ return 0;
+ }
+
+ case CW_GETPINFO:
+ return (DWORD) fillout_pinfo (va_arg (arg, DWORD), 0);
+
+ case CW_GETVERSIONINFO:
+ return (DWORD) cygwin_version_strings;
+
+ case CW_READ_V1_MOUNT_TABLES:
+ set_errno (ENOSYS);
+ return 1;
+
+ case CW_USER_DATA:
+ return (DWORD) &__cygwin_user_data;
+
+ case CW_PERFILE:
+ perfile_table = va_arg (arg, struct __cygwin_perfile *);
+ return 0;
+
+ case CW_GET_CYGDRIVE_PREFIXES:
+ {
+ char *user = va_arg (arg, char *);
+ char *system = va_arg (arg, char *);
+ return get_cygdrive_prefixes (user, system);
+ }
+
+ case CW_GETPINFO_FULL:
+ return (DWORD) fillout_pinfo (va_arg (arg, pid_t), 1);
+
+ case CW_INIT_EXCEPTIONS:
+ init_exceptions (va_arg (arg, exception_list *));
+ return 0;
+
+ case CW_GET_CYGDRIVE_INFO:
+ {
+ char *user = va_arg (arg, char *);
+ char *system = va_arg (arg, char *);
+ char *user_flags = va_arg (arg, char *);
+ char *system_flags = va_arg (arg, char *);
+ return get_cygdrive_info (user, system, user_flags, system_flags);
+ }
+
+ case CW_SET_CYGWIN_REGISTRY_NAME:
+ {
+ const char *cr = va_arg (arg, char *);
+ if (check_null_empty_str_errno (cr))
+ return (DWORD) NULL;
+ cygheap->cygwin_regname = (char *) crealloc (cygheap->cygwin_regname,
+ strlen (cr) + 1);
+ strcpy (cygheap->cygwin_regname, cr);
+ }
+ case CW_GET_CYGWIN_REGISTRY_NAME:
+ return (DWORD) cygheap->cygwin_regname;
+
+ case CW_STRACE_TOGGLE:
+ {
+ pid_t pid = va_arg (arg, pid_t);
+ pinfo p (pid);
+ if (p)
+ {
+ sig_send (p, __SIGSTRACE);
+ return 0;
+ }
+ else
+ {
+ set_errno (ESRCH);
+ return (DWORD) -1;
+ }
+ }
+
+ case CW_STRACE_ACTIVE:
+ {
+ return strace.active;
+ }
+
+ case CW_CYGWIN_PID_TO_WINPID:
+ {
+ pinfo p (va_arg (arg, pid_t));
+ return p ? p->dwProcessId : 0;
+ }
+ case CW_EXTRACT_DOMAIN_AND_USER:
+ {
+ struct passwd *pw = va_arg (arg, struct passwd *);
+ char *domain = va_arg (arg, char *);
+ char *user = va_arg (arg, char *);
+ extract_nt_dom_user (pw, domain, user);
+ return 0;
+ }
+ case CW_CMDLINE:
+ {
+ size_t n;
+ pid_t pid = va_arg (arg, pid_t);
+ pinfo p (pid);
+ return (DWORD) p->cmdline (n);
+ }
+ default:
+ return (DWORD) -1;
+ }
+}
diff --git a/winsup/cygwin/fcntl.cc b/winsup/cygwin/fcntl.cc
new file mode 100644
index 00000000000..6d99a98c4b7
--- /dev/null
+++ b/winsup/cygwin/fcntl.cc
@@ -0,0 +1,49 @@
+/* fcntl.cc: fcntl syscall
+
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include <stdarg.h>
+#include <errno.h>
+#include <unistd.h>
+#include "security.h"
+#include "path.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "cygerrno.h"
+#include "cygheap.h"
+#include "thread.h"
+
+extern "C"
+int
+_fcntl (int fd, int cmd,...)
+{
+ void *arg = NULL;
+ va_list args;
+ int res;
+
+ cygheap_fdget cfd (fd, true);
+ if (cfd < 0)
+ {
+ res = -1;
+ goto done;
+ }
+
+ va_start (args, cmd);
+ arg = va_arg (args, void *);
+ if (cmd != F_DUPFD)
+ res = cfd->fcntl(cmd, arg);
+ else
+ res = dup2 (fd, cygheap_fdnew (((int) arg) - 1));
+ va_end (args);
+
+done:
+ syscall_printf ("%d = fcntl (%d, %d, %p)", res, fd, cmd, arg);
+ return res;
+}
diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc
index 664cac0b610..4e706d4bf92 100644
--- a/winsup/cygwin/fhandler.cc
+++ b/winsup/cygwin/fhandler.cc
@@ -19,8 +19,8 @@ details. */
#include "perprocess.h"
#include "security.h"
#include "cygwin/version.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
#include "shared_info.h"
@@ -38,8 +38,7 @@ inline fhandler_base&
fhandler_base::operator =(fhandler_base &x)
{
memcpy (this, &x, sizeof *this);
- unix_path_name = x.unix_path_name ? cstrdup (x.unix_path_name) : NULL;
- win32_path_name = x.win32_path_name ? cstrdup (x.win32_path_name) : NULL;
+ pc.normalized_path = cstrdup (pc.normalized_path);
rabuf = NULL;
ralen = 0;
raixget = 0;
@@ -144,57 +143,12 @@ fhandler_base::get_readahead_into_buffer (char *buf, size_t buflen)
return copied_chars;
}
-/* 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).
- The unix_path_name is also used by virtual fhandlers. */
+/* Record the file name. and name hash */
void
-fhandler_base::set_name (const char *unix_path, const char *win32_path)
+fhandler_base::set_name (path_conv &in_pc)
{
- if (unix_path == NULL || !*unix_path)
- return;
-
- if (win32_path)
- win32_path_name = cstrdup (win32_path);
- else
- {
- const char *fmt = get_native_name ();
- char *w = (char *) cmalloc (HEAP_STR, strlen (fmt) + 16);
- __small_sprintf (w, fmt, get_unit ());
- win32_path_name = w;
- }
-
- if (win32_path_name == NULL)
- {
- system_printf ("fatal error. strdup failed");
- exit (ENOMEM);
- }
-
- assert (unix_path_name == NULL);
- /* FIXME: This isn't really right. It ignores the first argument if we're
- building names for a device and just converts the device name from the
- win32 name since it has theoretically been previously detected by
- path_conv. Ideally, we should pass in a format string and build the
- unix_path, too. */
- if (!is_auto_device () || *win32_path_name != '\\')
- unix_path_name = unix_path;
- else
- {
- char *p = cstrdup (win32_path_name);
- unix_path_name = p;
- while ((p = strchr (p, '\\')) != NULL)
- *p++ = '/';
- if (unix_path)
- cfree ((void *) unix_path);
- }
-
- if (unix_path_name == NULL)
- {
- system_printf ("fatal error. strdup failed");
- exit (ENOMEM);
- }
- namehash = hash_path_name (0, win32_path_name);
+ memcpy (&pc, &in_pc, in_pc.size ());
+ namehash = hash_path_name (0, get_win32_name ());
}
/* Detect if we are sitting at EOF for conditions where Windows
@@ -302,7 +256,7 @@ fhandler_base::raw_read (void *ptr, size_t& ulen)
break;
}
default:
- syscall_printf ("ReadFile %s failed, %E", unix_path_name);
+ syscall_printf ("ReadFile %s failed, %E", get_name ());
__seterrno_from_win_error (errcode);
bytes_read = -1;
break;
@@ -377,7 +331,7 @@ fhandler_base::device_access_denied (int flags)
/* Open system call handler function. */
int
-fhandler_base::open (path_conv *pc, int flags, mode_t mode)
+fhandler_base::open (int flags, mode_t mode)
{
int res = 0;
HANDLE x;
@@ -451,7 +405,7 @@ fhandler_base::open (path_conv *pc, int flags, mode_t mode)
share returns some handle, even if file doesn't exist. This code
works around this bug. */
if (get_query_open () && isremote () &&
- creation_distribution == OPEN_EXISTING && pc && !pc->exists ())
+ creation_distribution == OPEN_EXISTING && !pc.exists ())
{
set_errno (ENOENT);
goto done;
@@ -475,7 +429,7 @@ fhandler_base::open (path_conv *pc, int flags, mode_t mode)
if (x == INVALID_HANDLE_VALUE)
{
- if (!wincap.can_open_directories () && pc && pc->isdir ())
+ if (!wincap.can_open_directories () && pc.isdir ())
{
if (flags & (O_CREAT | O_EXCL) == (O_CREAT | O_EXCL))
set_errno (EEXIST);
@@ -501,7 +455,7 @@ fhandler_base::open (path_conv *pc, int flags, mode_t mode)
set_file_attribute (has_acls (), get_win32_name (), mode);
set_io_handle (x);
- set_flags (flags, pc ? pc->binmode () : 0);
+ set_flags (flags, pc.binmode ());
res = 1;
set_open_status ();
@@ -873,7 +827,7 @@ fhandler_base::lseek (__off64_t offset, int whence)
set_readahead_valid (0);
}
- debug_printf ("lseek (%s, %D, %d)", unix_path_name, offset, whence);
+ debug_printf ("lseek (%s, %D, %d)", get_name (), offset, whence);
DWORD win32_whence = whence == SEEK_SET ? FILE_BEGIN
: (whence == SEEK_CUR ? FILE_CURRENT : FILE_END);
@@ -981,12 +935,12 @@ rootdir (char *full_path)
}
int __stdcall
-fhandler_base::fstat (struct __stat64 *buf, path_conv *pc)
+fhandler_base::fstat (struct __stat64 *buf)
{
debug_printf ("here");
if (is_fs_special ())
- return fstat_fs (buf, pc);
+ return fstat_fs (buf);
switch (get_device ())
{
@@ -1186,8 +1140,6 @@ fhandler_base::fhandler_base ():
raixget (0),
raixput (0),
rabuflen (0),
- unix_path_name (NULL),
- win32_path_name (NULL),
open_status (0),
read_state (NULL)
{
@@ -1196,13 +1148,10 @@ fhandler_base::fhandler_base ():
/* Normal I/O destructor */
fhandler_base::~fhandler_base (void)
{
- if (unix_path_name != NULL)
- cfree ((void *) unix_path_name);
- if (win32_path_name != NULL)
- cfree ((void *) win32_path_name);
+ if (pc.normalized_path)
+ cfree (pc.normalized_path);
if (rabuf)
free (rabuf);
- unix_path_name = win32_path_name = NULL;
}
/**********************************************************************/
@@ -1287,7 +1236,7 @@ fhandler_base::set_nonblocking (int yes)
}
DIR *
-fhandler_base::opendir (path_conv&)
+fhandler_base::opendir ()
{
set_errno (ENOTDIR);
return NULL;
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 930f199b713..477c89045ff 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -11,9 +11,6 @@ details. */
#ifndef _FHANDLER_H_
#define _FHANDLER_H_
-#include <sys/ioctl.h>
-#include <fcntl.h>
-
enum
{
FH_RBINARY = 0x00001000, /* binary read mode */
@@ -44,8 +41,6 @@ enum
or write access */
};
-#include "devices.h"
-
#define FHDEVN(n) (n)
#define FHISSETF(x) __ISSETF (this, x, FH)
#define FHSETF(x) __SETF (this, x, FH)
@@ -78,7 +73,6 @@ extern const char proc[];
extern const int proc_len;
class select_record;
-class path_conv;
class fhandler_disk_file;
typedef struct __DIR DIR;
struct dirent;
@@ -101,16 +95,9 @@ enum bg_check_types
bg_signalled = 2
};
-enum executable_states
-{
- is_executable,
- dont_care_if_executable,
- not_executable = dont_care_if_executable,
- dont_know_if_executable
-};
-
class fhandler_base
{
+ friend class dtable;
protected:
DWORD status;
private:
@@ -130,14 +117,17 @@ class fhandler_base
size_t raixput;
size_t rabuflen;
- const char *unix_path_name;
- const char *win32_path_name;
DWORD open_status;
HANDLE read_state;
+ path_conv pc;
public:
- device dev;
- void set_name (const char *unix_path, const char *win32_path = NULL);
+ void set_name (path_conv &pc);
+ int error () const {return pc.error;}
+ bool exists () const {return pc.exists ();}
+ int pc_binmode () const {return pc.binmode ();}
+ device& dev () {return pc.dev;}
+ operator DWORD& () {return (DWORD) pc;}
virtual fhandler_base& operator =(fhandler_base &x);
fhandler_base ();
@@ -146,10 +136,10 @@ class fhandler_base
/* Non-virtual simple accessor functions. */
void set_io_handle (HANDLE x) { io_handle = x; }
- DWORD get_device () const { return dev.devn; }
- DWORD get_major () const { return dev.major; }
- DWORD get_minor () const { return dev.minor; }
- virtual int get_unit () const { return dev.minor; }
+ DWORD get_device () { return dev ().devn; }
+ DWORD get_major () { return dev ().major; }
+ DWORD get_minor () { return dev ().minor; }
+ virtual int get_unit () { return dev ().minor; }
int get_access () const { return access; }
void set_access (int x) { access = x; }
@@ -258,8 +248,8 @@ class fhandler_base
bool isremote () { return FHISSETF (ISREMOTE); }
void set_isremote (int val) { FHCONDSETF (val, ISREMOTE); }
- const char *get_name () { return unix_path_name; }
- const char *get_win32_name () { return win32_path_name; }
+ const char *get_name () const { return pc.normalized_path; }
+ const char *get_win32_name () { return pc.get_win32 (); }
unsigned long get_namehash () { return namehash; }
virtual void hclose (HANDLE h) {CloseHandle (h);}
@@ -268,13 +258,13 @@ class fhandler_base
/* fixup fd possibly non-inherited handles after fork */
void fork_fixup (HANDLE parent, HANDLE &h, const char *name);
- virtual int open (path_conv *real_path, int flags, mode_t mode = 0);
- int open_fs (path_conv *real_path, int flags, mode_t mode = 0);
+ virtual int open (int flags, mode_t mode = 0);
+ int open_fs (int flags, mode_t mode = 0);
virtual int close ();
int close_fs ();
- virtual int __stdcall fstat (struct __stat64 *buf, path_conv *) __attribute__ ((regparm (3)));
- int __stdcall fstat_fs (struct __stat64 *buf, path_conv *) __attribute__ ((regparm (3)));
- int __stdcall fstat_helper (struct __stat64 *buf, path_conv *pc,
+ virtual int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2)));
+ int __stdcall fstat_fs (struct __stat64 *buf) __attribute__ ((regparm (2)));
+ int __stdcall fstat_helper (struct __stat64 *buf,
FILETIME ftCreateionTime,
FILETIME ftLastAccessTime,
FILETIME ftLastWriteTime,
@@ -284,8 +274,8 @@ class fhandler_base
DWORD nFileIndexLow = 0,
DWORD nNumberOfLinks = 1)
__attribute__ ((regparm (3)));
- int __stdcall fstat_by_handle (struct __stat64 *buf, path_conv *pc) __attribute__ ((regparm (3)));
- int __stdcall fstat_by_name (struct __stat64 *buf, path_conv *pc) __attribute__ ((regparm (3)));
+ int __stdcall fstat_by_handle (struct __stat64 *buf) __attribute__ ((regparm (2)));
+ int __stdcall fstat_by_name (struct __stat64 *buf) __attribute__ ((regparm (2)));
virtual int ioctl (unsigned int cmd, void *);
virtual int fcntl (int cmd, void *);
virtual char const *ttyname () { return get_name(); }
@@ -340,7 +330,7 @@ class fhandler_base
virtual int ready_for_read (int fd, DWORD howlong);
virtual const char *get_native_name ()
{
- return dev.fmt;
+ return dev ().fmt;
}
virtual bg_check_types bg_check (int) {return bg_ok;}
void clear_readahead ()
@@ -351,15 +341,15 @@ class fhandler_base
void operator delete (void *);
virtual HANDLE get_guard () const {return NULL;}
virtual void set_eof () {}
- virtual DIR *opendir (path_conv& pc);
+ virtual DIR *opendir ();
virtual dirent *readdir (DIR *);
virtual __off64_t telldir (DIR *);
virtual void seekdir (DIR *, __off64_t);
virtual void rewinddir (DIR *);
virtual int closedir (DIR *);
virtual bool is_slow () {return 0;}
- bool is_auto_device () {return isdevice () && !dev.isfs ();}
- bool is_fs_special () {return dev.isfs ();}
+ bool is_auto_device () {return isdevice () && !dev ().isfs ();}
+ bool is_fs_special () {return dev ().isfs ();}
bool device_access_denied (int) __attribute__ ((regparm (1)));
};
@@ -436,7 +426,7 @@ class fhandler_socket: public fhandler_base
int check_peer_secret_event (struct sockaddr_in *peer, int *secret = NULL);
void signal_secret_event ();
void close_secret_event ();
- int __stdcall fstat (struct __stat64 *buf, path_conv *) __attribute__ ((regparm (3)));
+ int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2)));
bool is_slow () {return 1;}
};
@@ -480,7 +470,7 @@ class fhandler_fifo: public fhandler_pipe
long write_use;
public:
fhandler_fifo ();
- int open (path_conv *, int flags, mode_t mode = 0);
+ int open (int flags, mode_t mode = 0);
int open_not_mine (int flags) __attribute__ ((regparm (2)));
int close ();
void set_use (int flags) __attribute__ ((regparm (2)));
@@ -519,7 +509,7 @@ class fhandler_dev_raw: public fhandler_base
public:
~fhandler_dev_raw (void);
- int open (path_conv *, int flags, mode_t mode = 0);
+ int open (int flags, mode_t mode = 0);
int close (void);
void raw_read (void *ptr, size_t& ulen);
@@ -542,7 +532,7 @@ class fhandler_dev_floppy: public fhandler_dev_raw
public:
fhandler_dev_floppy ();
- virtual int open (path_conv *, int flags, mode_t mode = 0);
+ virtual int open (int flags, mode_t mode = 0);
virtual int close (void);
virtual __off64_t lseek (__off64_t offset, int whence);
@@ -565,12 +555,12 @@ class fhandler_dev_tape: public fhandler_dev_raw
public:
fhandler_dev_tape ();
- virtual int open (path_conv *, int flags, mode_t mode = 0);
+ virtual int open (int flags, mode_t mode = 0);
virtual int close (void);
virtual __off64_t lseek (__off64_t offset, int whence);
- virtual int __stdcall fstat (struct __stat64 *buf, path_conv *) __attribute__ ((regparm (3)));
+ virtual int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2)));
virtual int dup (fhandler_base *child);
@@ -596,18 +586,18 @@ class fhandler_disk_file: public fhandler_base
public:
fhandler_disk_file ();
- int open (path_conv *real_path, int flags, mode_t mode);
+ int open (int flags, mode_t mode);
int close ();
int lock (int, struct flock *);
bool isdevice () { return false; }
- int __stdcall fstat (struct __stat64 *buf, path_conv *pc) __attribute__ ((regparm (3)));
+ int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2)));
HANDLE mmap (caddr_t *addr, size_t len, DWORD access, int flags, __off64_t off);
int munmap (HANDLE h, caddr_t addr, size_t len);
int msync (HANDLE h, caddr_t addr, size_t len, int flags);
BOOL fixup_mmap_after_fork (HANDLE h, DWORD access, DWORD offset,
DWORD size, void *address);
- DIR *opendir (path_conv& pc);
+ DIR *opendir ();
struct dirent *readdir (DIR *);
__off64_t telldir (DIR *);
void seekdir (DIR *, __off64_t);
@@ -621,15 +611,15 @@ class fhandler_cygdrive: public fhandler_disk_file
const char *pdrive;
void set_drives ();
public:
- bool iscygdrive_root () const { return !dev.minor; }
+ bool iscygdrive_root () { return !dev ().minor; }
fhandler_cygdrive ();
- DIR *opendir (path_conv& pc);
+ DIR *opendir ();
struct dirent *readdir (DIR *);
__off64_t telldir (DIR *);
void seekdir (DIR *, __off64_t);
void rewinddir (DIR *);
int closedir (DIR *);
- int __stdcall fstat (struct __stat64 *buf, path_conv *pc) __attribute__ ((regparm (3)));
+ int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2)));
};
class fhandler_serial: public fhandler_base
@@ -649,7 +639,7 @@ class fhandler_serial: public fhandler_base
/* Constructor */
fhandler_serial ();
- int open (path_conv *, int flags, mode_t mode);
+ int open (int flags, mode_t mode);
int close ();
void init (HANDLE h, DWORD a, mode_t flags);
void overlapped_setup ();
@@ -819,7 +809,7 @@ class fhandler_console: public fhandler_termios
fhandler_console* is_console () { return this; }
- int open (path_conv *, int flags, mode_t mode = 0);
+ int open (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); }
@@ -891,7 +881,7 @@ class fhandler_tty_slave: public fhandler_tty_common
/* Constructor */
fhandler_tty_slave ();
- int open (path_conv *, int flags, mode_t mode = 0);
+ int open (int flags, mode_t mode = 0);
int write (const void *ptr, size_t len);
void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3)));
void init (HANDLE, DWORD, mode_t);
@@ -921,7 +911,7 @@ public:
int process_slave_output (char *buf, size_t len, int pktmode_on);
void doecho (const void *str, DWORD len);
int accept_input ();
- int open (path_conv *, int flags, mode_t mode = 0);
+ int open (int flags, mode_t mode = 0);
int write (const void *ptr, size_t len);
void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3)));
int close ();
@@ -969,7 +959,7 @@ class fhandler_dev_zero: public fhandler_base
{
public:
fhandler_dev_zero ();
- int open (path_conv *, int flags, mode_t mode = 0);
+ int open (int flags, mode_t mode = 0);
int write (const void *ptr, size_t len);
void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3)));
__off64_t lseek (__off64_t offset, int whence);
@@ -989,7 +979,7 @@ class fhandler_dev_random: public fhandler_base
public:
fhandler_dev_random ();
- int open (path_conv *, int flags, mode_t mode = 0);
+ int open (int flags, mode_t mode = 0);
int write (const void *ptr, size_t len);
void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3)));
__off64_t lseek (__off64_t offset, int whence);
@@ -1009,12 +999,12 @@ class fhandler_dev_mem: public fhandler_base
fhandler_dev_mem ();
~fhandler_dev_mem (void);
- int open (path_conv *, int flags, mode_t mode = 0);
+ int open (int flags, mode_t mode = 0);
int write (const void *ptr, size_t ulen);
void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3)));
__off64_t lseek (__off64_t offset, int whence);
int close (void);
- int __stdcall fstat (struct __stat64 *buf, path_conv *) __attribute__ ((regparm (3)));
+ int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2)));
int dup (fhandler_base *child);
HANDLE mmap (caddr_t *addr, size_t len, DWORD access, int flags, __off64_t off);
@@ -1031,7 +1021,7 @@ class fhandler_dev_clipboard: public fhandler_base
public:
fhandler_dev_clipboard ();
int is_windows (void) { return 1; }
- int open (path_conv *, int flags, mode_t mode = 0);
+ int open (int flags, mode_t mode = 0);
int write (const void *ptr, size_t len);
void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3)));
__off64_t lseek (__off64_t offset, int whence);
@@ -1056,7 +1046,7 @@ class fhandler_windows: public fhandler_base
public:
fhandler_windows ();
int is_windows (void) { return 1; }
- int open (path_conv *, int flags, mode_t mode = 0);
+ int open (int flags, mode_t mode = 0);
int write (const void *ptr, size_t len);
void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3)));
int ioctl (unsigned int cmd, void *);
@@ -1083,7 +1073,7 @@ class fhandler_dev_dsp : public fhandler_base
fhandler_dev_dsp ();
~fhandler_dev_dsp();
- int open (path_conv *, int flags, mode_t mode = 0);
+ int open (int flags, mode_t mode = 0);
int write (const void *ptr, size_t len);
void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3)));
int ioctl (unsigned int cmd, void *);
@@ -1107,7 +1097,7 @@ class fhandler_virtual : public fhandler_base
virtual ~fhandler_virtual();
virtual int exists();
- DIR *opendir (path_conv& pc);
+ DIR *opendir ();
__off64_t telldir (DIR *);
void seekdir (DIR *, __off64_t);
void rewinddir (DIR *);
@@ -1116,9 +1106,9 @@ class fhandler_virtual : public fhandler_base
void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3)));
__off64_t lseek (__off64_t, int);
int dup (fhandler_base *child);
- int open (path_conv *, int flags, mode_t mode = 0);
+ int open (int flags, mode_t mode = 0);
int close (void);
- int __stdcall fstat (struct stat *buf, path_conv *pc) __attribute__ ((regparm (3)));
+ int __stdcall fstat (struct stat *buf) __attribute__ ((regparm (2)));
virtual bool fill_filebuf ();
void fixup_after_exec (HANDLE);
};
@@ -1131,8 +1121,8 @@ class fhandler_proc: public fhandler_virtual
struct dirent *readdir (DIR *);
static DWORD get_proc_fhandler(const char *path);
- int open (path_conv *real_path, int flags, mode_t mode = 0);
- int __stdcall fstat (struct __stat64 *buf, path_conv *) __attribute__ ((regparm (3)));
+ int open (int flags, mode_t mode = 0);
+ int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2)));
bool fill_filebuf ();
};
@@ -1149,8 +1139,8 @@ class fhandler_registry: public fhandler_proc
void rewinddir (DIR *);
int closedir (DIR *);
- int open (path_conv *real_path, int flags, mode_t mode = 0);
- int __stdcall fstat (struct __stat64 *buf, path_conv *) __attribute__ ((regparm (3)));
+ int open (int flags, mode_t mode = 0);
+ int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2)));
bool fill_filebuf ();
int close (void);
};
@@ -1163,15 +1153,15 @@ class fhandler_process: public fhandler_proc
fhandler_process ();
int exists();
struct dirent *readdir (DIR *);
- int open (path_conv *real_path, int flags, mode_t mode = 0);
- int __stdcall fstat (struct __stat64 *buf, path_conv *) __attribute__ ((regparm (3)));
+ int open (int flags, mode_t mode = 0);
+ int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2)));
bool fill_filebuf ();
};
struct fhandler_nodevice: public fhandler_base
{
fhandler_nodevice ();
- int open (path_conv *real_path, int flags, mode_t mode = 0);
+ int open (int flags, mode_t mode = 0);
// int __stdcall fstat (struct __stat64 *buf, path_conv *);
};
diff --git a/winsup/cygwin/fhandler_clipboard.cc b/winsup/cygwin/fhandler_clipboard.cc
index 6f8559740be..ae78ff99166 100644
--- a/winsup/cygwin/fhandler_clipboard.cc
+++ b/winsup/cygwin/fhandler_clipboard.cc
@@ -1,6 +1,6 @@
/* fhandler_dev_clipboard: code to access /dev/clipboard
- Copyright 2000, 2001, 2002 Red Hat, Inc
+ Copyright 2000, 2001, 2002, 2003 Red Hat, Inc
Written by Charles Wilson (cwilson@ece.gatech.edu)
@@ -20,6 +20,7 @@ details. */
#include <winuser.h>
#include "cygerrno.h"
#include "security.h"
+#include "path.h"
#include "fhandler.h"
/*
@@ -52,7 +53,7 @@ fhandler_dev_clipboard::dup (fhandler_base * child)
{
fhandler_dev_clipboard *fhc = (fhandler_dev_clipboard *) child;
- if (!fhc->open (NULL, get_flags (), 0))
+ if (!fhc->open (get_flags (), 0))
system_printf ("error opening clipboard, %E");
fhc->membuffer = membuffer;
@@ -63,7 +64,7 @@ fhandler_dev_clipboard::dup (fhandler_base * child)
}
int
-fhandler_dev_clipboard::open (path_conv *, int flags, mode_t)
+fhandler_dev_clipboard::open (int flags, mode_t)
{
set_flags (flags | O_TEXT);
eof = false;
diff --git a/winsup/cygwin/fhandler_console.cc b/winsup/cygwin/fhandler_console.cc
index 747ba551c38..df8e940054f 100644
--- a/winsup/cygwin/fhandler_console.cc
+++ b/winsup/cygwin/fhandler_console.cc
@@ -22,8 +22,8 @@ details. */
#include <sys/cygwin.h>
#include "cygerrno.h"
#include "security.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
#include "sigproc.h"
@@ -581,7 +581,7 @@ fhandler_console::scroll_screen (int x1, int y1, int x2, int y2, int xn, int yn)
}
int
-fhandler_console::open (path_conv *, int flags, mode_t)
+fhandler_console::open (int flags, mode_t)
{
HANDLE h;
@@ -656,7 +656,7 @@ fhandler_console::dup (fhandler_base *child)
{
fhandler_console *fhc = (fhandler_console *) child;
- if (!fhc->open (NULL, get_flags () & ~O_NOCTTY, 0))
+ if (!fhc->open (get_flags () & ~O_NOCTTY, 0))
system_printf ("error opening console, %E");
return 0;
@@ -1406,7 +1406,7 @@ fhandler_console::write_normal (const unsigned char *src,
switch (base_chars[*src])
{
case BEL:
- Beep (412, 100);
+ MessageBeep (0xFFFFFFFF);
break;
case ESC:
dev_state->state_ = gotesc;
@@ -1673,7 +1673,7 @@ fhandler_console::init (HANDLE f, DWORD a, mode_t bin)
flags = O_WRONLY;
if (a == (GENERIC_READ | GENERIC_WRITE))
flags = O_RDWR;
- open ((path_conv *) NULL, flags | O_BINARY);
+ open (flags | O_BINARY);
if (f != INVALID_HANDLE_VALUE)
CloseHandle (f); /* Reopened by open */
@@ -1702,7 +1702,7 @@ fhandler_console::fixup_after_fork (HANDLE)
/* Windows does not allow duplication of console handles between processes
so open the console explicitly. */
- if (!open (NULL, O_NOCTTY | get_flags (), 0))
+ if (!open (O_NOCTTY | get_flags (), 0))
system_printf ("error opening console after fork, %E");
if (!get_close_on_exec ())
@@ -1732,7 +1732,7 @@ fhandler_console::fixup_after_exec (HANDLE)
HANDLE h = get_handle ();
HANDLE oh = get_output_handle ();
- if (!open (NULL, O_NOCTTY | get_flags (), 0))
+ if (!open (O_NOCTTY | get_flags (), 0))
{
int sawerr = 0;
if (!get_io_handle ())
diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc
index 01df5f2ccb4..f7d76bfb8db 100644
--- a/winsup/cygwin/fhandler_disk_file.cc
+++ b/winsup/cygwin/fhandler_disk_file.cc
@@ -18,8 +18,8 @@ details. */
#include "perprocess.h"
#include "security.h"
#include "cygwin/version.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
#include "shared_info.h"
@@ -65,7 +65,7 @@ num_entries (const char *win32_name)
}
int __stdcall
-fhandler_base::fstat_by_handle (struct __stat64 *buf, path_conv *pc)
+fhandler_base::fstat_by_handle (struct __stat64 *buf)
{
int res = 0;
BY_HANDLE_FILE_INFORMATION local;
@@ -90,7 +90,7 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf, path_conv *pc)
local.nFileSizeLow = GetFileSize (get_handle (), &local.nFileSizeHigh);
}
- return fstat_helper (buf, pc,
+ return fstat_helper (buf,
local.ftCreationTime,
local.ftLastAccessTime,
local.ftLastWriteTime,
@@ -102,11 +102,11 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf, path_conv *pc)
}
int __stdcall
-fhandler_base::fstat_by_name (struct __stat64 *buf, path_conv *pc)
+fhandler_base::fstat_by_name (struct __stat64 *buf)
{
int res;
- if (!pc->exists ())
+ if (!pc.exists ())
{
debug_printf ("already determined that pc does not exist");
set_errno (ENOENT);
@@ -116,14 +116,14 @@ fhandler_base::fstat_by_name (struct __stat64 *buf, path_conv *pc)
{
char drivebuf[5];
char *name;
- if ((*pc)[3] != '\0' || !isalpha ((*pc)[0]) || (*pc)[1] != ':' || (*pc)[2] != '\\')
- name = *pc;
+ if ((pc)[3] != '\0' || !isalpha ((pc)[0]) || (pc)[1] != ':' || (pc)[2] != '\\')
+ name = pc;
else
{
/* FIXME: Does this work on empty disks? */
- drivebuf[0] = (*pc)[0];
- drivebuf[1] = (*pc)[1];
- drivebuf[2] = (*pc)[2];
+ drivebuf[0] = pc[0];
+ drivebuf[1] = pc[1];
+ drivebuf[2] = pc[2];
drivebuf[3] = '*';
drivebuf[4] = '\0';
name = drivebuf;
@@ -140,7 +140,7 @@ fhandler_base::fstat_by_name (struct __stat64 *buf, path_conv *pc)
else
{
FindClose (h);
- res = fstat_helper (buf, pc,
+ res = fstat_helper (buf,
local.ftCreationTime,
local.ftLastAccessTime,
local.ftLastWriteTime,
@@ -152,7 +152,7 @@ fhandler_base::fstat_by_name (struct __stat64 *buf, path_conv *pc)
}
int __stdcall
-fhandler_base::fstat_fs (struct __stat64 *buf, path_conv *pc)
+fhandler_base::fstat_fs (struct __stat64 *buf)
{
int res = -1;
int oret;
@@ -164,29 +164,29 @@ fhandler_base::fstat_fs (struct __stat64 *buf, path_conv *pc)
if (get_io_handle ())
{
if (get_nohandle ())
- return fstat_by_name (buf, pc);
+ return fstat_by_name (buf);
else
- return fstat_by_handle (buf, pc);
+ return fstat_by_handle (buf);
}
/* If we don't care if the file is executable or we already know if it is,
then just do a "query open" as it is apparently much faster. */
- if (pc->exec_state () != dont_know_if_executable)
+ if (pc.exec_state () != dont_know_if_executable)
set_query_open (query_open_already = true);
else
query_open_already = false;
- if (query_open_already && strncasematch (pc->volname (), "FAT", 3)
+ if (query_open_already && strncasematch (pc.volname (), "FAT", 3)
&& !strpbrk (get_win32_name (), "?*|<>"))
oret = 0;
- else if (!(oret = open_fs (pc, open_flags, 0)))
+ else if (!(oret = open_fs (open_flags, 0)))
{
mode_t ntsec_atts = 0;
/* If we couldn't open the file, try a "query open" with no permissions.
This will allow us to determine *some* things about the file, at least. */
set_query_open (true);
- if (!query_open_already && (oret = open (pc, open_flags, 0)))
+ if (!query_open_already && (oret = open (open_flags, 0)))
/* ok */;
- else if (allow_ntsec && pc->has_acls () && get_errno () == EACCES
+ else if (allow_ntsec && pc.has_acls () && get_errno () == EACCES
&& !get_file_attribute (TRUE, get_win32_name (), &ntsec_atts, &uid, &gid)
&& !ntsec_atts && uid == myself->uid && gid == myself->gid)
{
@@ -196,16 +196,16 @@ fhandler_base::fstat_fs (struct __stat64 *buf, path_conv *pc)
in a failing open call in the same process. Check that
case. */
set_file_attribute (TRUE, get_win32_name (), 0400);
- oret = open (pc, open_flags, 0);
+ oret = open (open_flags, 0);
set_file_attribute (TRUE, get_win32_name (), ntsec_atts);
}
}
if (!oret || get_nohandle ())
- res = fstat_by_name (buf, pc);
+ res = fstat_by_name (buf);
else
{
- res = fstat_by_handle (buf, pc);
+ res = fstat_by_handle (buf);
close_fs ();
}
@@ -213,7 +213,7 @@ fhandler_base::fstat_fs (struct __stat64 *buf, path_conv *pc)
}
int __stdcall
-fhandler_base::fstat_helper (struct __stat64 *buf, path_conv *pc,
+fhandler_base::fstat_helper (struct __stat64 *buf,
FILETIME ftCreationTime,
FILETIME ftLastAccessTime,
FILETIME ftLastWriteTime,
@@ -234,20 +234,20 @@ fhandler_base::fstat_helper (struct __stat64 *buf, path_conv *pc,
to_timestruc_t (&ftLastAccessTime, &buf->st_atim);
to_timestruc_t (&ftLastWriteTime, &buf->st_mtim);
to_timestruc_t (&ftCreationTime, &buf->st_ctim);
- buf->st_dev = pc->volser ();
+ buf->st_dev = pc.volser ();
buf->st_size = ((__off64_t)nFileSizeHigh << 32) + nFileSizeLow;
/* Unfortunately the count of 2 confuses `find (1)' command. So
let's try it with `1' as link count. */
- if (pc->isdir () && !pc->isremote () && nNumberOfLinks == 1)
- buf->st_nlink = num_entries (pc->get_win32 ());
+ if (pc.isdir () && !pc.isremote () && nNumberOfLinks == 1)
+ buf->st_nlink = num_entries (pc.get_win32 ());
else
buf->st_nlink = nNumberOfLinks;
/* 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 (pc->has_acls () && (nFileIndexHigh || nFileIndexLow)
- ? pc->drive_type () : DRIVE_UNKNOWN)
+ switch (pc.has_acls () && (nFileIndexHigh || nFileIndexLow)
+ ? pc.drive_type () : DRIVE_UNKNOWN)
{
case DRIVE_FIXED:
case DRIVE_REMOVABLE:
@@ -270,20 +270,20 @@ fhandler_base::fstat_helper (struct __stat64 *buf, path_conv *pc,
buf->st_mode = 0;
/* Using a side effect: get_file_attibutes checks for
directory. This is used, to set S_ISVTX, if needed. */
- if (pc->isdir ())
+ if (pc.isdir ())
buf->st_mode = S_IFDIR;
- else if (pc->issymlink ())
+ else if (pc.issymlink ())
buf->st_mode = S_IFLNK;
- else if (pc->issocket ())
+ else if (pc.issocket ())
buf->st_mode = S_IFSOCK;
__uid32_t uid;
__gid32_t gid;
- if (get_file_attribute (pc->has_acls (), get_win32_name (), &buf->st_mode,
+ if (get_file_attribute (pc.has_acls (), get_win32_name (), &buf->st_mode,
&uid, &gid) == 0)
{
/* If read-only attribute is set, modify ntsec return value */
- if (pc->has_attribute (FILE_ATTRIBUTE_READONLY) && !get_symlink_p ())
+ if (pc.has_attribute (FILE_ATTRIBUTE_READONLY) && !get_symlink_p ())
buf->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
if (!(buf->st_mode & S_IFMT))
@@ -293,7 +293,7 @@ fhandler_base::fstat_helper (struct __stat64 *buf, path_conv *pc,
{
buf->st_mode |= STD_RBITS;
- if (!pc->has_attribute (FILE_ATTRIBUTE_READONLY))
+ if (!pc.has_attribute (FILE_ATTRIBUTE_READONLY))
buf->st_mode |= STD_WBITS;
/* | S_IWGRP | S_IWOTH; we don't give write to group etc */
@@ -301,17 +301,17 @@ fhandler_base::fstat_helper (struct __stat64 *buf, path_conv *pc,
buf->st_mode |= S_IFDIR | STD_XBITS;
else if (buf->st_mode & S_IFMT)
/* nothing */;
- else if (pc->issocket ())
+ else if (pc.issocket ())
buf->st_mode |= S_IFSOCK;
else if (is_fs_special ())
{
- buf->st_dev = dev;
- buf->st_mode = dev.mode;
+ buf->st_dev = dev ();
+ buf->st_mode = dev ().mode;
}
else
{
buf->st_mode |= S_IFREG;
- if (pc->exec_state () == dont_know_if_executable)
+ if (pc.exec_state () == dont_know_if_executable)
{
DWORD cur, done;
char magic[3];
@@ -329,7 +329,7 @@ fhandler_base::fstat_helper (struct __stat64 *buf, path_conv *pc,
&& has_exec_chars (magic, done))
{
set_execable_p ();
- pc->set_exec ();
+ pc.set_exec ();
buf->st_mode |= STD_XBITS;
}
(void) SetFilePointer (get_handle (), cur, NULL, FILE_BEGIN);
@@ -337,7 +337,7 @@ fhandler_base::fstat_helper (struct __stat64 *buf, path_conv *pc,
}
}
- if (pc->exec_state () == is_executable)
+ if (pc.exec_state () == is_executable)
buf->st_mode |= STD_XBITS;
}
@@ -357,9 +357,9 @@ fhandler_base::fstat_helper (struct __stat64 *buf, path_conv *pc,
}
int __stdcall
-fhandler_disk_file::fstat (struct __stat64 *buf, path_conv *pc)
+fhandler_disk_file::fstat (struct __stat64 *buf)
{
- return fstat_fs (buf, pc);
+ return fstat_fs (buf);
}
fhandler_disk_file::fhandler_disk_file () :
@@ -368,25 +368,25 @@ fhandler_disk_file::fhandler_disk_file () :
}
int
-fhandler_disk_file::open (path_conv *real_path, int flags, mode_t mode)
+fhandler_disk_file::open (int flags, mode_t mode)
{
- return open_fs (real_path, flags, mode);
+ return open_fs (flags, mode);
}
int
-fhandler_base::open_fs (path_conv *real_path, int flags, mode_t mode)
+fhandler_base::open_fs (int flags, mode_t mode)
{
- if (real_path->case_clash && flags & O_CREAT)
+ if (pc.case_clash && flags & O_CREAT)
{
debug_printf ("case clash detected");
set_errno (ECASECLASH);
return 0;
}
- set_has_acls (real_path->has_acls ());
- set_isremote (real_path->isremote ());
+ set_has_acls (pc.has_acls ());
+ set_isremote (pc.isremote ());
- int res = fhandler_base::open (real_path, flags | O_DIROPEN, mode);
+ int res = fhandler_base::open (flags | O_DIROPEN, mode);
if (!res)
goto out;
@@ -396,7 +396,7 @@ fhandler_base::open_fs (path_conv *real_path, int flags, mode_t mode)
The only known file system to date is the SUN NFS Solstice Client 3.1
which returns a valid handle when trying to open a file in a nonexistent
directory. */
- if (real_path->has_buggy_open () && !real_path->exists ())
+ if (pc.has_buggy_open () && !pc.exists ())
{
debug_printf ("Buggy open detected.");
close_fs ();
@@ -404,9 +404,9 @@ fhandler_base::open_fs (path_conv *real_path, int flags, mode_t mode)
return 0;
}
- set_symlink_p (real_path->issymlink ());
- set_execable_p (real_path->exec_state ());
- set_socket_p (real_path->issocket ());
+ set_symlink_p (pc.issymlink ());
+ set_execable_p (pc.exec_state ());
+ set_socket_p (pc.issocket ());
out:
syscall_printf ("%d = fhandler_disk_file::open (%s, %p)", res,
@@ -582,15 +582,15 @@ fhandler_disk_file::lock (int cmd, struct flock *fl)
}
DIR *
-fhandler_disk_file::opendir (path_conv& real_name)
+fhandler_disk_file::opendir ()
{
DIR *dir;
DIR *res = NULL;
size_t len;
- if (!real_name.isdir ())
+ if (!pc.isdir ())
set_errno (ENOTDIR);
- else if ((len = strlen (real_name))> MAX_PATH - 3)
+ else if ((len = strlen (pc))> MAX_PATH - 3)
set_errno (ENAMETOOLONG);
else if ((dir = (DIR *) malloc (sizeof (DIR))) == NULL)
set_errno (ENOMEM);
@@ -608,7 +608,7 @@ fhandler_disk_file::opendir (path_conv& real_name)
}
else
{
- strcpy (dir->__d_dirname, real_name.get_win32 ());
+ strcpy (dir->__d_dirname, get_win32_name ());
dir->__d_dirent->d_version = __DIRENT_VERSION;
cygheap_fdnew fd;
fd = this;
@@ -746,10 +746,8 @@ void
fhandler_cygdrive::set_drives ()
{
const int len = 1 + 26 * DRVSZ;
- char *p = (char *) crealloc ((void *) win32_path_name,
- sizeof (".") + sizeof ("..") + len);
-
- win32_path_name = pdrive = p;
+ char *p = const_cast<char *> (get_win32_name ());
+ pdrive = p;
strcpy (p, ".");
strcpy (p + sizeof ("."), "..");
p += sizeof (".") + sizeof ("..");
@@ -757,10 +755,10 @@ fhandler_cygdrive::set_drives ()
}
int
-fhandler_cygdrive::fstat (struct __stat64 *buf, path_conv *pc)
+fhandler_cygdrive::fstat (struct __stat64 *buf)
{
if (!iscygdrive_root ())
- return fhandler_disk_file::fstat (buf, pc);
+ return fhandler_disk_file::fstat (buf);
buf->st_mode = S_IFDIR | 0555;
if (!ndrives)
set_drives ();
@@ -769,11 +767,11 @@ fhandler_cygdrive::fstat (struct __stat64 *buf, path_conv *pc)
}
DIR *
-fhandler_cygdrive::opendir (path_conv& real_name)
+fhandler_cygdrive::opendir ()
{
DIR *dir;
- dir = fhandler_disk_file::opendir (real_name);
+ dir = fhandler_disk_file::opendir ();
if (dir && iscygdrive_root () && !ndrives)
set_drives ();
@@ -822,7 +820,7 @@ fhandler_cygdrive::seekdir (DIR *dir, __off64_t loc)
if (!iscygdrive_root ())
return fhandler_disk_file::seekdir (dir, loc);
- for (pdrive = win32_path_name, dir->__d_position = -1; *pdrive;
+ for (pdrive = get_win32_name (), dir->__d_position = -1; *pdrive;
pdrive = strchr (pdrive, '\0') + 1)
if (++dir->__d_position >= loc)
break;
@@ -835,7 +833,7 @@ fhandler_cygdrive::rewinddir (DIR *dir)
{
if (!iscygdrive_root ())
return fhandler_disk_file::rewinddir (dir);
- pdrive = win32_path_name;
+ pdrive = get_win32_name ();
dir->__d_position = 0;
return;
}
@@ -845,6 +843,6 @@ fhandler_cygdrive::closedir (DIR *dir)
{
if (!iscygdrive_root ())
return fhandler_disk_file::closedir (dir);
- pdrive = win32_path_name;
+ pdrive = get_win32_name ();
return -1;
}
diff --git a/winsup/cygwin/fhandler_dsp.cc b/winsup/cygwin/fhandler_dsp.cc
index daa9a629807..8668e1a5813 100644
--- a/winsup/cygwin/fhandler_dsp.cc
+++ b/winsup/cygwin/fhandler_dsp.cc
@@ -18,6 +18,7 @@ details. */
#include <mmsystem.h>
#include "cygerrno.h"
#include "security.h"
+#include "path.h"
#include "fhandler.h"
//------------------------------------------------------------------------
@@ -429,7 +430,7 @@ fhandler_dev_dsp::~fhandler_dev_dsp ()
}
int
-fhandler_dev_dsp::open (path_conv *, int flags, mode_t mode)
+fhandler_dev_dsp::open (int flags, mode_t mode)
{
// currently we only support writing
if ((flags & (O_WRONLY | O_RDONLY | O_RDWR)) != O_WRONLY)
diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc
index f391648f9a1..655da260e3c 100644
--- a/winsup/cygwin/fhandler_fifo.cc
+++ b/winsup/cygwin/fhandler_fifo.cc
@@ -16,8 +16,8 @@
#include "cygerrno.h"
#include "perprocess.h"
#include "security.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
#include "pinfo.h"
@@ -133,12 +133,12 @@ out:
}
int
-fhandler_fifo::open (path_conv *pc, int flags, mode_t)
+fhandler_fifo::open (int flags, mode_t)
{
int res = 1;
char buf[24];
- upand = GlobalAddAtom (*pc);
+ upand = GlobalAddAtom (pc);
__small_sprintf (buf, "%x.owner", upand);
debug_printf ("mutex %s", buf);
diff --git a/winsup/cygwin/fhandler_floppy.cc b/winsup/cygwin/fhandler_floppy.cc
index 8e804e9aa07..9ec58e3352d 100644
--- a/winsup/cygwin/fhandler_floppy.cc
+++ b/winsup/cygwin/fhandler_floppy.cc
@@ -18,6 +18,7 @@ details. */
#include <cygwin/hdreg.h>
#include <cygwin/fs.h>
#include "security.h"
+#include "path.h"
#include "fhandler.h"
#include "cygerrno.h"
@@ -48,7 +49,7 @@ fhandler_dev_floppy::fhandler_dev_floppy ()
}
int
-fhandler_dev_floppy::open (path_conv *real_path, int flags, mode_t)
+fhandler_dev_floppy::open (int flags, mode_t)
{
/* The correct size of the buffer would be 512 bytes,
* which is the atomic size, supported by WinNT.
@@ -63,7 +64,7 @@ fhandler_dev_floppy::open (path_conv *real_path, int flags, mode_t)
* and cpio buffer sizes by default!
*/
devbufsiz = 61440L; /* 512L; */
- return fhandler_dev_raw::open (real_path, flags);
+ return fhandler_dev_raw::open (flags);
}
int
diff --git a/winsup/cygwin/fhandler_mem.cc b/winsup/cygwin/fhandler_mem.cc
index 52554a3cb14..e19891e8485 100644
--- a/winsup/cygwin/fhandler_mem.cc
+++ b/winsup/cygwin/fhandler_mem.cc
@@ -16,6 +16,7 @@
#include "cygerrno.h"
#include "security.h"
+#include "path.h"
#include "fhandler.h"
#include "ntdll.h"
@@ -32,7 +33,7 @@ fhandler_dev_mem::fhandler_dev_mem ()
return;
}
- if (dev == FH_MEM) /* /dev/mem */
+ if (dev () == FH_MEM) /* /dev/mem */
{
NTSTATUS ret;
SYSTEM_BASIC_INFORMATION sbi;
@@ -48,12 +49,12 @@ fhandler_dev_mem::fhandler_dev_mem ()
mem_size = sbi.PhysicalPageSize * sbi.NumberOfPhysicalPages;
debug_printf ("MemSize: %d MB", mem_size >> 20);
}
- else if (dev == FH_KMEM) /* /dev/kmem - Not yet supported */
+ else if (dev () == FH_KMEM) /* /dev/kmem - Not yet supported */
{
mem_size = 0;
debug_printf ("KMemSize: %d MB", mem_size >> 20);
}
- else if (dev == FH_ZERO) /* /dev/port == First 64K of /dev/mem */
+ else if (dev () == FH_ZERO) /* /dev/port == First 64K of /dev/mem */
{
mem_size = 65536;
debug_printf ("PortSize: 64 KB");
@@ -70,12 +71,12 @@ fhandler_dev_mem::~fhandler_dev_mem (void)
}
int
-fhandler_dev_mem::open (path_conv *, int flags, mode_t)
+fhandler_dev_mem::open (int flags, mode_t)
{
if (!wincap.has_physical_mem_access ())
{
set_errno (ENOENT);
- debug_printf ("%s is accessible under NT/W2K only", dev.name);
+ debug_printf ("%s is accessible under NT/W2K only", dev ().name);
return 0;
}
@@ -404,9 +405,9 @@ fhandler_dev_mem::fixup_mmap_after_fork (HANDLE h, DWORD access, DWORD offset,
}
int
-fhandler_dev_mem::fstat (struct __stat64 *buf, path_conv *pc)
+fhandler_dev_mem::fstat (struct __stat64 *buf)
{
- fhandler_base::fstat (buf, pc);
+ fhandler_base::fstat (buf);
buf->st_mode = S_IFCHR;
if (wincap.has_physical_mem_access ())
buf->st_mode |= S_IRUSR | S_IWUSR |
diff --git a/winsup/cygwin/fhandler_nodevice.cc b/winsup/cygwin/fhandler_nodevice.cc
index 8f2b26c6dbe..fba7900df5d 100644
--- a/winsup/cygwin/fhandler_nodevice.cc
+++ b/winsup/cygwin/fhandler_nodevice.cc
@@ -19,8 +19,8 @@ details. */
#include "perprocess.h"
#include "security.h"
#include "cygwin/version.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
#include "shared_info.h"
@@ -29,7 +29,7 @@ details. */
#include <limits.h>
int
-fhandler_nodevice::open (path_conv *, int, mode_t)
+fhandler_nodevice::open (int, mode_t)
{
set_errno (ENODEV);
return 0;
diff --git a/winsup/cygwin/fhandler_proc.cc b/winsup/cygwin/fhandler_proc.cc
index ce7c107a5e6..c0888e86e16 100644
--- a/winsup/cygwin/fhandler_proc.cc
+++ b/winsup/cygwin/fhandler_proc.cc
@@ -16,8 +16,8 @@ details. */
#include <ntdef.h>
#include "cygerrno.h"
#include "security.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "pinfo.h"
#include "dtable.h"
#include "cygheap.h"
@@ -84,9 +84,8 @@ fhandler_proc::get_proc_fhandler (const char *path)
debug_printf ("get_proc_fhandler(%s)", path);
path += proc_len;
/* Since this method is called from path_conv::check we can't rely on
- * it being normalised and therefore the path may have runs of slashes
- * in it.
- */
+ it being normalised and therefore the path may have runs of slashes
+ in it. */
while (isdirsep (*path))
path++;
@@ -143,13 +142,13 @@ fhandler_proc::fhandler_proc ():
}
int
-fhandler_proc::fstat (struct __stat64 *buf, path_conv *pc)
+fhandler_proc::fstat (struct __stat64 *buf)
{
const char *path = get_name ();
debug_printf ("fstat (%s)", path);
path += proc_len;
- (void) fhandler_base::fstat (buf, pc);
+ (void) fhandler_base::fstat (buf);
buf->st_mode &= ~_IFMT & NO_W;
@@ -204,11 +203,11 @@ fhandler_proc::readdir (DIR * dir)
}
int
-fhandler_proc::open (path_conv *pc, int flags, mode_t mode)
+fhandler_proc::open (int flags, mode_t mode)
{
int proc_file_no = -1;
- int res = fhandler_virtual::open (pc, flags, mode);
+ int res = fhandler_virtual::open (flags, mode);
if (!res)
goto out;
diff --git a/winsup/cygwin/fhandler_process.cc b/winsup/cygwin/fhandler_process.cc
index 054c9e373cd..2f339654221 100644
--- a/winsup/cygwin/fhandler_process.cc
+++ b/winsup/cygwin/fhandler_process.cc
@@ -16,9 +16,9 @@ details. */
#include <ntdef.h>
#include "cygerrno.h"
#include "security.h"
+#include "path.h"
#include "fhandler.h"
#include "pinfo.h"
-#include "path.h"
#include "shared_info.h"
#include "dtable.h"
#include "cygheap.h"
@@ -102,11 +102,11 @@ fhandler_process::fhandler_process ():
}
int
-fhandler_process::fstat (struct __stat64 *buf, path_conv *pc)
+fhandler_process::fstat (struct __stat64 *buf)
{
const char *path = get_name ();
int file_type = exists ();
- (void) fhandler_base::fstat (buf, pc);
+ (void) fhandler_base::fstat (buf);
path += proc_len + 1;
pid = atoi (path);
pinfo p (pid);
@@ -159,11 +159,11 @@ fhandler_process::readdir (DIR * dir)
}
int
-fhandler_process::open (path_conv *pc, int flags, mode_t mode)
+fhandler_process::open (int flags, mode_t mode)
{
int process_file_no = -1;
- int res = fhandler_virtual::open (pc, flags, mode);
+ int res = fhandler_virtual::open (flags, mode);
if (!res)
goto out;
diff --git a/winsup/cygwin/fhandler_random.cc b/winsup/cygwin/fhandler_random.cc
index e1faed4bb62..4742d7c7ff9 100644
--- a/winsup/cygwin/fhandler_random.cc
+++ b/winsup/cygwin/fhandler_random.cc
@@ -15,6 +15,7 @@ details. */
#include <limits.h>
#include "cygerrno.h"
#include "security.h"
+#include "path.h"
#include "fhandler.h"
#define RANDOM 8
@@ -29,7 +30,7 @@ fhandler_dev_random::fhandler_dev_random ()
}
int
-fhandler_dev_random::open (path_conv *, int flags, mode_t)
+fhandler_dev_random::open (int flags, mode_t)
{
set_flags ((flags & ~O_TEXT) | O_BINARY);
set_nohandle (true);
@@ -85,7 +86,7 @@ fhandler_dev_random::write (const void *ptr, size_t len)
memcpy (buf, ptr, limited_len);
/* Mess up system entropy source. Return error if device is /dev/random. */
- if (!crypt_gen_random (buf, limited_len) && dev == FH_RANDOM)
+ if (!crypt_gen_random (buf, limited_len) && dev () == FH_RANDOM)
{
__seterrno ();
return -1;
@@ -129,7 +130,7 @@ fhandler_dev_random::read (void *ptr, size_t& len)
/* If device is /dev/urandom, use pseudo number generator as fallback.
Don't do this for /dev/random since it's intended for uses that need
very high quality randomness. */
- if (dev == FH_URANDOM)
+ if (dev () == FH_URANDOM)
{
len = pseudo_read (ptr, len);
return;
diff --git a/winsup/cygwin/fhandler_raw.cc b/winsup/cygwin/fhandler_raw.cc
index 5e566a1aa35..302af884717 100644
--- a/winsup/cygwin/fhandler_raw.cc
+++ b/winsup/cygwin/fhandler_raw.cc
@@ -19,8 +19,8 @@
#include "cygerrno.h"
#include "perprocess.h"
#include "security.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
#include "ntdll.h"
@@ -131,12 +131,12 @@ fhandler_dev_raw::~fhandler_dev_raw (void)
}
int
-fhandler_dev_raw::open (path_conv *real_path, int flags, mode_t)
+fhandler_dev_raw::open (int flags, mode_t)
{
if (!wincap.has_raw_devices ())
{
set_errno (ENOENT);
- debug_printf ("%s is accessible under NT/W2K only",real_path->get_win32());
+ debug_printf ("%s is accessible under NT/W2K only", get_win32_name ());
return 0;
}
@@ -160,7 +160,7 @@ fhandler_dev_raw::open (path_conv *real_path, int flags, mode_t)
extern void str2buf2uni (UNICODE_STRING &, WCHAR *, const char *);
UNICODE_STRING dev;
WCHAR devname[MAX_PATH + 1];
- str2buf2uni (dev, devname, real_path->get_win32 ());
+ str2buf2uni (dev, devname, get_win32_name ());
OBJECT_ATTRIBUTES attr;
InitializeObjectAttributes (&attr, &dev, OBJ_CASE_INSENSITIVE, NULL, NULL);
diff --git a/winsup/cygwin/fhandler_registry.cc b/winsup/cygwin/fhandler_registry.cc
index a98ef0758ed..6d74ae5991a 100644
--- a/winsup/cygwin/fhandler_registry.cc
+++ b/winsup/cygwin/fhandler_registry.cc
@@ -17,8 +17,8 @@ details. */
#include <sys/cygwin.h>
#include "cygerrno.h"
#include "security.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
#include <assert.h>
@@ -193,9 +193,9 @@ fhandler_proc ()
}
int
-fhandler_registry::fstat (struct __stat64 *buf, path_conv *pc)
+fhandler_registry::fstat (struct __stat64 *buf)
{
- fhandler_base::fstat (buf, pc);
+ fhandler_base::fstat (buf);
buf->st_mode &= ~_IFMT & NO_W;
int file_type = exists ();
switch (file_type)
@@ -396,13 +396,13 @@ fhandler_registry::closedir (DIR * dir)
}
int
-fhandler_registry::open (path_conv * pc, int flags, mode_t mode)
+fhandler_registry::open (int flags, mode_t mode)
{
int pathlen;
const char *file;
HKEY handle;
- int res = fhandler_virtual::open (pc, flags, mode);
+ int res = fhandler_virtual::open (flags, mode);
if (!res)
goto out;
diff --git a/winsup/cygwin/fhandler_serial.cc b/winsup/cygwin/fhandler_serial.cc
index 4049af4c210..932a4b0ccb6 100644
--- a/winsup/cygwin/fhandler_serial.cc
+++ b/winsup/cygwin/fhandler_serial.cc
@@ -14,6 +14,7 @@ details. */
#include <stdlib.h>
#include "cygerrno.h"
#include "security.h"
+#include "path.h"
#include "fhandler.h"
#include "sigproc.h"
#include "pinfo.h"
@@ -201,11 +202,11 @@ fhandler_serial::dump (void)
void
fhandler_serial::init (HANDLE f, DWORD flags, mode_t bin)
{
- (void) open (NULL, flags, bin & (O_BINARY | O_TEXT));
+ (void) open (flags, bin & (O_BINARY | O_TEXT));
}
int
-fhandler_serial::open (path_conv *, int flags, mode_t mode)
+fhandler_serial::open (int flags, mode_t mode)
{
int res;
COMMTIMEOUTS to;
@@ -214,7 +215,7 @@ fhandler_serial::open (path_conv *, int flags, mode_t mode)
syscall_printf ("fhandler_serial::open (%s, %p, %p)",
get_name (), flags, mode);
- if (!fhandler_base::open (NULL, flags, mode))
+ if (!fhandler_base::open (flags, mode))
return 0;
res = 1;
diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc
index e4cfe231243..a760c86a609 100644
--- a/winsup/cygwin/fhandler_socket.cc
+++ b/winsup/cygwin/fhandler_socket.cc
@@ -26,8 +26,8 @@
#include "security.h"
#include "cygwin/version.h"
#include "perprocess.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
#include "sigproc.h"
@@ -116,10 +116,10 @@ fhandler_socket::set_connect_secret ()
{
void *buf = malloc (sizeof (fhandler_dev_random));
entropy_source = new (buf) fhandler_dev_random ();
- entropy_source->dev = *urandom_dev;
+ entropy_source->dev () = *urandom_dev;
}
if (entropy_source &&
- !entropy_source->open (NULL, O_RDONLY))
+ !entropy_source->open (O_RDONLY))
{
delete entropy_source;
entropy_source = NULL;
@@ -307,9 +307,9 @@ fhandler_socket::dup (fhandler_base *child)
}
int __stdcall
-fhandler_socket::fstat (struct __stat64 *buf, path_conv *pc)
+fhandler_socket::fstat (struct __stat64 *buf)
{
- int res = fhandler_base::fstat (buf, pc);
+ int res = fhandler_base::fstat (buf);
if (!res)
{
buf->st_mode &= ~_IFMT;
diff --git a/winsup/cygwin/fhandler_tape.cc b/winsup/cygwin/fhandler_tape.cc
index 7affc5524b9..46f5fa4a0ad 100644
--- a/winsup/cygwin/fhandler_tape.cc
+++ b/winsup/cygwin/fhandler_tape.cc
@@ -17,8 +17,8 @@ details. */
#include "cygerrno.h"
#include "perprocess.h"
#include "security.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
@@ -56,17 +56,17 @@ fhandler_dev_tape::is_eof (int win_error)
fhandler_dev_tape::fhandler_dev_tape ()
: fhandler_dev_raw ()
{
- debug_printf ("unit: %d", dev.minor);
+ debug_printf ("unit: %d", dev ().minor);
}
int
-fhandler_dev_tape::open (path_conv *real_path, int flags, mode_t)
+fhandler_dev_tape::open (int flags, mode_t)
{
int ret;
devbufsiz = 1L;
- ret = fhandler_dev_raw::open (real_path, flags);
+ ret = fhandler_dev_raw::open (flags);
if (ret)
{
struct mtget get;
@@ -146,11 +146,11 @@ fhandler_dev_tape::close (void)
}
int
-fhandler_dev_tape::fstat (struct __stat64 *buf, path_conv *pc)
+fhandler_dev_tape::fstat (struct __stat64 *buf)
{
int ret;
- if (!(ret = fhandler_base::fstat (buf, pc)))
+ if (!(ret = fhandler_base::fstat (buf)))
{
struct mtget get;
diff --git a/winsup/cygwin/fhandler_termios.cc b/winsup/cygwin/fhandler_termios.cc
index 4116464153b..48cb0e67170 100644
--- a/winsup/cygwin/fhandler_termios.cc
+++ b/winsup/cygwin/fhandler_termios.cc
@@ -16,6 +16,7 @@ details. */
#include <ctype.h>
#include "cygerrno.h"
#include "security.h"
+#include "path.h"
#include "fhandler.h"
#include "sigproc.h"
#include "pinfo.h"
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 4c9da4bb649..080d2346da1 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -17,8 +17,8 @@ details. */
#include <limits.h>
#include "cygerrno.h"
#include "security.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "sigproc.h"
#include "pinfo.h"
@@ -43,7 +43,7 @@ fhandler_tty_master::fhandler_tty_master ()
int
fhandler_tty_slave::get_unit ()
{
- return dev == FH_TTY ? myself->ctty : dev.minor;
+ return dev () == FH_TTY ? myself->ctty : dev ().minor;
}
void
@@ -61,7 +61,7 @@ fhandler_tty_master::init ()
{
termios_printf ("Creating master for tty%d", get_unit ());
- slave = dev;
+ slave = dev ();
if (init_console ())
{
@@ -441,7 +441,7 @@ fhandler_tty_slave::fhandler_tty_slave ()
/* FIXME: This function needs to close handles when it has
a failing condition. */
int
-fhandler_tty_slave::open (path_conv *, int flags, mode_t)
+fhandler_tty_slave::open (int flags, mode_t)
{
tcinit (cygwin_shared->tty[get_unit ()]);
@@ -1010,7 +1010,7 @@ fhandler_pty_master::fhandler_pty_master ()
}
int
-fhandler_pty_master::open (path_conv *, int flags, mode_t)
+fhandler_pty_master::open (int flags, mode_t)
{
int ntty = cygwin_shared->tty.allocate_tty (0);
if (ntty < 0)
@@ -1252,8 +1252,7 @@ fhandler_tty_master::fixup_after_exec (HANDLE)
int
fhandler_tty_master::init_console ()
{
- console = (fhandler_console *)
- cygheap->fdtab.build_fhandler (-1, *console_dev, "/dev/ttym");
+ console = (fhandler_console *) build_fh_dev (*console_dev, "/dev/ttym");
if (console == NULL)
return -1;
diff --git a/winsup/cygwin/fhandler_virtual.cc b/winsup/cygwin/fhandler_virtual.cc
index 4487275bf31..fe83f90e8a3 100644
--- a/winsup/cygwin/fhandler_virtual.cc
+++ b/winsup/cygwin/fhandler_virtual.cc
@@ -15,8 +15,8 @@ details. */
#include <sys/cygwin.h>
#include "cygerrno.h"
#include "security.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "shared_info.h"
#include "cygheap.h"
@@ -46,7 +46,7 @@ fhandler_virtual::fixup_after_exec (HANDLE)
}
DIR *
-fhandler_virtual::opendir (path_conv& pc)
+fhandler_virtual::opendir ()
{
DIR *dir;
DIR *res = NULL;
@@ -204,7 +204,7 @@ fhandler_virtual::write (const void *ptr, size_t len)
/* low-level open for all proc files */
int
-fhandler_virtual::open (path_conv *, int flags, mode_t mode)
+fhandler_virtual::open (int flags, mode_t mode)
{
set_r_binary (1);
set_w_binary (1);
diff --git a/winsup/cygwin/fhandler_windows.cc b/winsup/cygwin/fhandler_windows.cc
index e62ba10e13f..81972bf132b 100644
--- a/winsup/cygwin/fhandler_windows.cc
+++ b/winsup/cygwin/fhandler_windows.cc
@@ -17,6 +17,7 @@ details. */
#include <winuser.h>
#include "cygerrno.h"
#include "security.h"
+#include "path.h"
#include "fhandler.h"
/*
@@ -52,7 +53,7 @@ fhandler_windows::fhandler_windows ()
}
int
-fhandler_windows::open (path_conv *, int flags, mode_t)
+fhandler_windows::open (int flags, mode_t)
{
set_flags ((flags & ~O_TEXT) | O_BINARY);
set_close_on_exec_flag (1);
diff --git a/winsup/cygwin/fhandler_zero.cc b/winsup/cygwin/fhandler_zero.cc
index 64ad21fdc8f..3051769a138 100644
--- a/winsup/cygwin/fhandler_zero.cc
+++ b/winsup/cygwin/fhandler_zero.cc
@@ -13,6 +13,7 @@ details. */
#include "winsup.h"
#include <errno.h>
#include "security.h"
+#include "path.h"
#include "fhandler.h"
fhandler_dev_zero::fhandler_dev_zero ()
@@ -21,7 +22,7 @@ fhandler_dev_zero::fhandler_dev_zero ()
}
int
-fhandler_dev_zero::open (path_conv *, int flags, mode_t)
+fhandler_dev_zero::open (int flags, mode_t)
{
set_flags ((flags & ~O_TEXT) | O_BINARY);
set_nohandle (true);
diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc
new file mode 100644
index 00000000000..7639a621d47
--- /dev/null
+++ b/winsup/cygwin/fork.cc
@@ -0,0 +1,751 @@
+/* fork.cc
+
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include "security.h"
+#include "path.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "cygerrno.h"
+#include "sigproc.h"
+#include "pinfo.h"
+#include "cygheap.h"
+#include "child_info.h"
+#define NEED_VFORK
+#include "perthread.h"
+#include "perprocess.h"
+#include "dll_init.h"
+#include "sync.h"
+#include "shared_info.h"
+#include "cygmalloc.h"
+#include "cygthread.h"
+
+#ifdef DEBUGGING
+static int npid;
+static int npid_max;
+static pid_t fork_pids[100];
+#endif
+
+/* 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 = wincap.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, windows pid %u, %E",
+ what, pass, low, high, done, pi.dwProcessId);
+ 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, hang_child %d", s,
+ hang_child);
+ 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");
+ return 1;
+}
+
+static int
+resume_child (PROCESS_INFORMATION &pi, HANDLE forker_finished)
+{
+ SetEvent (forker_finished);
+ debug_printf ("signalled child");
+ return 1;
+}
+
+/* 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. */
+static void __stdcall
+sync_with_parent (const char *s, bool hang_self)
+{
+ debug_printf ("signalling parent: %s", s);
+ /* Tell our parent we're waiting. */
+ if (!SetEvent (fork_info->subproc_ready))
+ api_fatal ("fork child - SetEvent for %s failed, %E", s);
+ if (hang_self)
+ {
+ HANDLE h = fork_info->forker_finished;
+ /* 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 (h, FORK_WAIT_TIMEOUT);
+ debug_printf ("awake");
+ switch (psync_rc)
+ {
+ case WAIT_TIMEOUT:
+ api_fatal ("WFSO timed out for %s", s);
+ break;
+ case WAIT_FAILED:
+ if (GetLastError () == ERROR_INVALID_HANDLE &&
+ WaitForSingleObject (fork_info->forker_finished, 1) != WAIT_FAILED)
+ break;
+ api_fatal ("WFSO failed for %s, fork_finished %p, %E", s,
+ fork_info->forker_finished);
+ break;
+ default:
+ debug_printf ("no problems");
+ break;
+ }
+ }
+}
+
+static int __stdcall
+fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls)
+{
+ debug_printf ("child is running. pid %d, ppid %d, stack here %p",
+ myself->pid, myself->ppid, __builtin_frame_address (0));
+
+ /* Restore the inheritance state as in parent
+ Don't call setuid here! The flags are already set. */
+ if (cygheap->user.impersonated)
+ {
+ debug_printf ("Impersonation of child, token: %d", cygheap->user.token);
+ if (cygheap->user.token == INVALID_HANDLE_VALUE)
+ RevertToSelf (); // probably not needed
+ else if (!ImpersonateLoggedOnUser (cygheap->user.token))
+ system_printf ("Impersonate for forked child failed: %E");
+ }
+
+ sync_with_parent ("after longjmp.", TRUE);
+ sigproc_printf ("hParent %p, child 1 first_dll %p, load_dlls %d", hParent,
+ first_dll, load_dlls);
+
+#ifdef DEBUGGING
+ char c;
+ if (GetEnvironmentVariable ("FORKDEBUG", &c, 1))
+ try_to_debug ();
+ char buf[80];
+ /* This is useful for debugging fork problems. Use gdb to attach to
+ the pid reported here. */
+ if (GetEnvironmentVariable ("CYGWIN_FORK_SLEEP", buf, sizeof (buf)))
+ {
+ small_printf ("Sleeping %d after fork, pid %u\n", atoi (buf), GetCurrentProcessId ());
+ Sleep (atoi (buf));
+ }
+#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 (fork_info->stacksize)
+ {
+ ((DWORD *)fork_info->stackbottom)[-17] = (DWORD)do_exit;
+ ((DWORD *)fork_info->stackbottom)[-15] = (DWORD)0;
+ }
+
+ set_file_api_mode (current_codepage);
+
+ MALLOC_CHECK;
+
+ if (fixup_mmaps_after_fork (hParent))
+ api_fatal ("recreate_mmaps_after_fork_failed");
+
+
+ MALLOC_CHECK;
+
+ /* If we haven't dynamically loaded any dlls, just signal
+ the parent. Otherwise, load all the dlls, tell the parent
+ that we're done, and wait for the parent to fill in the.
+ loaded dlls' data/bss. */
+ if (!load_dlls)
+ {
+ cygheap->fdtab.fixup_after_fork (hParent);
+ ProtectHandleINH (hParent);
+ sync_with_parent ("performed fork fixup.", FALSE);
+ }
+ else
+ {
+ dlls.load_after_fork (hParent, first_dll);
+ cygheap->fdtab.fixup_after_fork (hParent);
+ ProtectHandleINH (hParent);
+ sync_with_parent ("loaded dlls", TRUE);
+ }
+
+ ForceCloseHandle (hParent);
+ (void) ForceCloseHandle1 (fork_info->subproc_ready, subproc_ready);
+ (void) ForceCloseHandle1 (fork_info->forker_finished, forker_finished);
+
+ if (fixup_shms_after_fork ())
+ api_fatal ("recreate_shm areas after fork failed");
+
+ pinfo_fixup_after_fork ();
+ signal_fixup_after_fork ();
+
+ /* 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 ();
+
+ pthread::atforkchild ();
+ wait_for_sigthread ();
+ cygbench ("fork-child");
+ return 0;
+}
+
+static void
+slow_pid_reuse (HANDLE h)
+{
+ static NO_COPY HANDLE last_fork_procs[8] = {0};
+ static NO_COPY unsigned nfork_procs = 0;
+
+ if (nfork_procs >= (sizeof (last_fork_procs) / sizeof (last_fork_procs [0])))
+ nfork_procs = 0;
+ /* Keep a list of handles to forked processes sitting around to prevent
+ Windows from reusing the same pid n times in a row. Having the same pids
+ close in succesion confuses bash. Keeping a handle open will stop
+ windows from reusing the same pid. */
+ if (last_fork_procs[nfork_procs])
+ ForceCloseHandle1 (last_fork_procs[nfork_procs], fork_stupidity);
+ if (DuplicateHandle (hMainProc, h, hMainProc, &last_fork_procs[nfork_procs],
+ 0, FALSE, DUPLICATE_SAME_ACCESS))
+ ProtectHandle1 (last_fork_procs[nfork_procs], fork_stupidity);
+ else
+ {
+ last_fork_procs[nfork_procs] = NULL;
+ system_printf ("couldn't create last_fork_proc, %E");
+ }
+ nfork_procs++;
+}
+
+static int __stdcall
+fork_parent (HANDLE& hParent, dll *&first_dll,
+ bool& load_dlls, void *stack_here, child_info_fork &ch)
+{
+ HANDLE subproc_ready, forker_finished;
+ DWORD rc;
+ PROCESS_INFORMATION pi = {0, NULL, 0, 0};
+
+ pthread::atforkprepare ();
+
+ subproc_init ();
+
+ int c_flags = GetPriorityClass (hMainProc) /*|
+ CREATE_NEW_PROCESS_GROUP*/;
+ STARTUPINFO si = {0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL};
+
+ /* If we don't have a console, then don't create a console for the
+ child either. */
+ HANDLE console_handle = CreateFile ("CONOUT$", GENERIC_WRITE,
+ FILE_SHARE_WRITE, &sec_none_nih,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (console_handle != INVALID_HANDLE_VALUE)
+ CloseHandle (console_handle);
+ else
+ c_flags |= DETACHED_PROCESS;
+
+ /* Some file types (currently only sockets) need extra effort in the
+ parent after CreateProcess and before copying the datastructures
+ to the child. So we have to start the child in suspend state,
+ unfortunately, to avoid a race condition. */
+ if (cygheap->fdtab.need_fixup_before ())
+ c_flags |= CREATE_SUSPENDED;
+
+ /* Create an inheritable handle to pass to the child process. This will
+ allow the child to duplicate handles from the parent to itself. */
+ hParent = NULL;
+ if (!DuplicateHandle (hMainProc, hMainProc, hMainProc, &hParent, 0, 1,
+ DUPLICATE_SAME_ACCESS))
+ {
+ system_printf ("couldn't create handle to myself for child, %E");
+ return -1;
+ }
+
+ /* Remember the address of the first loaded dll and decide
+ if we need to load dlls. We do this here so that this
+ information will be available in the parent and, when
+ the stack is copied, in the child. */
+ first_dll = dlls.start.next;
+ load_dlls = dlls.reload_on_fork && dlls.loaded_dlls;
+
+ /* This will help some of the confusion. */
+ fflush (stdout);
+
+ subproc_ready = CreateEvent (&sec_all, FALSE, FALSE, NULL);
+ if (subproc_ready == NULL)
+ {
+ CloseHandle (hParent);
+ system_printf ("unable to allocate subproc_ready event, %E");
+ return -1;
+ }
+ forker_finished = CreateEvent (&sec_all, FALSE, FALSE, NULL);
+ if (forker_finished == NULL)
+ {
+ CloseHandle (hParent);
+ CloseHandle (subproc_ready);
+ system_printf ("unable to allocate forker_finished event, %E");
+ return -1;
+ }
+
+ ProtectHandleINH (subproc_ready);
+ ProtectHandleINH (forker_finished);
+
+ init_child_info (PROC_FORK, &ch, 1, subproc_ready);
+
+ ch.forker_finished = forker_finished;
+
+ stack_base (ch);
+
+ si.cb = sizeof (STARTUPINFO);
+ si.lpReserved2 = (LPBYTE)&ch;
+ si.cbReserved2 = sizeof (ch);
+
+ /* Remove impersonation */
+ if (cygheap->user.issetuid ())
+ RevertToSelf ();
+
+ ch.parent = hParent;
+#ifdef DEBUGGING
+ if (npid_max)
+ {
+ for (int pass = 0; pass < 2; pass++)
+ {
+ pid_t pid;
+ while ((pid = fork_pids[npid++]))
+ if (!pinfo (pid))
+ {
+ ch.cygpid = pid;
+ goto out;
+ }
+ npid = 0;
+ }
+ }
+ out:
+#endif
+
+ char sa_buf[1024];
+ PSECURITY_ATTRIBUTES sec_attribs = sec_user_nih (sa_buf);
+ syscall_printf ("CreateProcess (%s, %s, 0, 0, 1, %x, 0, 0, %p, %p)",
+ myself->progname, myself->progname, c_flags, &si, &pi);
+ __malloc_lock ();
+ void *newheap;
+ newheap = cygheap_setup_for_child (&ch, cygheap->fdtab.need_fixup_before ());
+ rc = CreateProcess (myself->progname, /* image to run */
+ myself->progname, /* what we send in arg0 */
+ sec_attribs,
+ sec_attribs,
+ 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 ("CreateProcessA failed, %E");
+ ForceCloseHandle (subproc_ready);
+ ForceCloseHandle (forker_finished);
+ /* Restore impersonation */
+ if (cygheap->user.issetuid ())
+ ImpersonateLoggedOnUser (cygheap->user.token);
+ cygheap_setup_for_child_cleanup (newheap, &ch, 0);
+ return -1;
+ }
+
+ /* Fixup the parent datastructure if needed and resume the child's
+ main thread. */
+ if (!cygheap->fdtab.need_fixup_before ())
+ cygheap_setup_for_child_cleanup (newheap, &ch, 0);
+ else
+ {
+ cygheap->fdtab.fixup_before_fork (pi.dwProcessId);
+ cygheap_setup_for_child_cleanup (newheap, &ch, 1);
+ ResumeThread (pi.hThread);
+ }
+
+#ifdef DEBUGGING
+ pinfo forked ((ch.cygpid != 1 ? ch.cygpid : cygwin_pid (pi.dwProcessId)), 1);
+#else
+ pinfo forked (cygwin_pid (pi.dwProcessId), 1);
+#endif
+
+ /* Initialize things that are done later in dll_crt0_1 that aren't done
+ for the forkee. */
+ strcpy (forked->progname, myself->progname);
+
+ /* Restore impersonation */
+ if (cygheap->user.issetuid ())
+ ImpersonateLoggedOnUser (cygheap->user.token);
+
+ 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. */
+ forked->hProcess = pi.hProcess;
+ forked->dwProcessId = pi.dwProcessId;
+ forked->copysigs (myself);
+
+ /* Hopefully, this will succeed. The alternative to doing things this
+ way is to reserve space prior to calling CreateProcess and then fill
+ it in afterwards. This requires more bookkeeping than I like, though,
+ so we'll just do it the easy way. So, terminate any child process if
+ we can't actually record the pid in the internal table. */
+ if (!forked.remember ())
+ {
+ TerminateProcess (pi.hProcess, 1);
+ set_errno (EAGAIN);
+ goto cleanup;
+ }
+
+ slow_pid_reuse (pi.hProcess);
+
+ /* 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,
+ cygheap->user_heap.base, cygheap->user_heap.ptr,
+ stack_here, ch.stackbottom,
+ dll_data_start, dll_data_end,
+ dll_bss_start, dll_bss_end, NULL);
+
+ __malloc_unlock ();
+ MALLOC_CHECK;
+ if (!rc)
+ goto cleanup;
+
+ /* Now fill data/bss of any DLLs that were linked into the program. */
+ for (dll *d = dlls.istart (DLL_LINK); d; d = dlls.inext ())
+ {
+ debug_printf ("copying data/bss of a linked dll");
+ if (!fork_copy (pi, "linked dll data/bss", d->p.data_start, d->p.data_end,
+ d->p.bss_start, d->p.bss_end,
+ NULL))
+ goto cleanup;
+ }
+
+ /* Start thread, and wait for it to reload dlls. */
+ if (!resume_child (pi, forker_finished) ||
+ !sync_with_child (pi, subproc_ready, load_dlls, "child loading dlls"))
+ goto cleanup;
+
+ /* If DLLs were loaded in the parent, then the child has reloaded all
+ of them and is now waiting to have all of the individual data and
+ bss sections filled in. */
+ if (load_dlls)
+ {
+ /* CHILD IS STOPPED */
+ /* write memory of reloaded dlls */
+ for (dll *d = dlls.istart (DLL_LOAD); d; d = dlls.inext ())
+ {
+ debug_printf ("copying data/bss for a loaded dll");
+ if (!fork_copy (pi, "loaded dll data/bss", d->p.data_start, d->p.data_end,
+ d->p.bss_start, d->p.bss_end,
+ NULL))
+ goto cleanup;
+ }
+ /* Start the child up again. */
+ (void) resume_child (pi, forker_finished);
+ }
+
+ ForceCloseHandle (subproc_ready);
+ ForceCloseHandle (pi.hThread);
+ ForceCloseHandle (forker_finished);
+ forker_finished = NULL;
+ pi.hThread = NULL;
+ pthread::atforkparent ();
+
+ return forked->pid;
+
+/* Common cleanup code for failure cases */
+ cleanup:
+ /* Remember to de-allocate the fd table. */
+ 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);
+ return -1;
+}
+
+extern "C" int
+fork ()
+{
+ struct
+ {
+ HANDLE hParent;
+ dll *first_dll;
+ bool load_dlls;
+ } grouped;
+
+ MALLOC_CHECK;
+ sigframe thisframe (mainthread);
+
+ debug_printf ("entering");
+ grouped.hParent = grouped.first_dll = NULL;
+ grouped.load_dlls = 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;
+ }
+
+ void *esp;
+ __asm__ volatile ("movl %%esp,%0": "=r" (esp));
+
+ myself->set_has_pgid_children ();
+
+ child_info_fork ch;
+
+ int res = setjmp (ch.jmp);
+
+ if (res)
+ res = fork_child (grouped.hParent, grouped.first_dll, grouped.load_dlls);
+ else
+ res = fork_parent (grouped.hParent, grouped.first_dll, grouped.load_dlls, esp, ch);
+
+ MALLOC_CHECK;
+ syscall_printf ("%d = fork()", res);
+ return res;
+}
+#ifdef DEBUGGING
+void
+fork_init ()
+{
+ char buf[1024];
+ if (!GetEnvironmentVariable ("CYGWIN_FORK_PIDS", buf, 1024))
+ return;
+ pid_t pid;
+ char *p, *pe;
+ for (p = buf; (pid = strtol (p, &pe, 10)); p = pe)
+ fork_pids[npid_max++] = pid;
+}
+#endif /*DEBUGGING*/
+
+#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
+ sigframe thisframe;
+ vfork_save *vf = get_vfork_val ();
+ char **esp, **pp;
+
+ if (vf == NULL)
+ vf = vfork_storage.create ();
+ else if (vf->pid)
+ return fork ();
+
+ if (!setjmp (vf->j))
+ {
+ vf->pid = -1;
+ __asm__ volatile ("movl %%esp,%0": "=r" (vf->vfork_esp):);
+ __asm__ volatile ("movl %%ebp,%0": "=r" (vf->vfork_ebp):);
+ for (pp = (char **)vf->frame, esp = vf->vfork_esp;
+ esp <= vf->vfork_ebp + 2; pp++, esp++)
+ *pp = *esp;
+ vf->ctty = myself->ctty;
+ vf->sid = myself->sid;
+ vf->pgid = myself->pgid;
+ int res = cygheap->fdtab.vfork_child_dup () ? 0 : -1;
+ debug_printf ("%d = vfork()", res);
+ return res;
+ }
+
+ vf = get_vfork_val ();
+
+ for (pp = (char **)vf->frame, esp = vf->vfork_esp;
+ esp <= vf->vfork_ebp + 2; pp++, esp++)
+ *esp = *pp;
+
+ thisframe.init (mainthread);
+ cygheap->fdtab.vfork_parent_restore ();
+
+ myself->ctty = vf->ctty;
+ myself->sid = vf->sid;
+ myself->pgid = vf->pgid;
+
+ if (vf->pid < 0)
+ {
+ int exitval = vf->exitval;
+ vf->pid = 0;
+ if ((vf->pid = fork ()) == 0)
+ exit (exitval);
+ }
+
+ int pid = vf->pid;
+ vf->pid = 0;
+ debug_printf ("exiting vfork, pid %d", pid);
+ sig_dispatch_pending ();
+ return pid;
+#endif
+}
diff --git a/winsup/cygwin/grp.cc b/winsup/cygwin/grp.cc
index 2d385c6ff10..7a654ba15cf 100644
--- a/winsup/cygwin/grp.cc
+++ b/winsup/cygwin/grp.cc
@@ -19,8 +19,8 @@ details. */
#include <errno.h>
#include "pinfo.h"
#include "security.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "cygerrno.h"
#include "cygheap.h"
diff --git a/winsup/cygwin/heap.cc b/winsup/cygwin/heap.cc
index fb1e37c896e..ae8a9d0a7b2 100644
--- a/winsup/cygwin/heap.cc
+++ b/winsup/cygwin/heap.cc
@@ -16,8 +16,8 @@ details. */
#include "heap.h"
#include "shared_info.h"
#include "security.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
#include "registry.h"
diff --git a/winsup/cygwin/include/cygwin/in.h b/winsup/cygwin/include/cygwin/in.h
index ed73b26db70..58ebb0e7d5c 100644
--- a/winsup/cygwin/include/cygwin/in.h
+++ b/winsup/cygwin/include/cygwin/in.h
@@ -103,7 +103,7 @@ struct sockaddr_in
struct in_addr sin_addr; /* Internet address */
/* Pad to size of `struct sockaddr'. */
- unsigned chari __pad[__SOCK_SIZE__ - sizeof(short int)
+ 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 */
diff --git a/winsup/cygwin/include/cygwin/types.h b/winsup/cygwin/include/cygwin/types.h
index c4ba3a656b8..793157e614d 100644
--- a/winsup/cygwin/include/cygwin/types.h
+++ b/winsup/cygwin/include/cygwin/types.h
@@ -145,20 +145,20 @@ typedef __uint32_t uint32_t;
typedef __uint64_t uint64_t;
#endif
-#ifndef __uint8_t_defined
-#define __uint8_t_defined
+#ifndef __u_int8_t_defined
+#define __u_int8_t_defined
typedef unsigned char u_int8_t;
#endif
-#ifndef __uint16_t_defined
-#define __uint16_t_defined
+#ifndef __u_int16_t_defined
+#define __u_int16_t_defined
typedef __uint16_t u_int16_t;
#endif
-#ifndef __uint32_t_defined
-#define __uint32_t_defined
+#ifndef __u_int32_t_defined
+#define __u_int32_t_defined
typedef __uint32_t u_int32_t;
#endif
-#ifndef __uint64_t_defined
-#define __uint64_t_defined
+#ifndef __u_int64_t_defined
+#define __u_int64_t_defined
typedef __uint64_t u_int64_t;
#endif
diff --git a/winsup/cygwin/ioctl.cc b/winsup/cygwin/ioctl.cc
new file mode 100644
index 00000000000..5d9ec87d0cb
--- /dev/null
+++ b/winsup/cygwin/ioctl.cc
@@ -0,0 +1,65 @@
+/* ioctl.cc: ioctl routines.
+
+ Copyright 1996, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+
+ 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 "winsup.h"
+#include <sys/ioctl.h>
+#include <errno.h>
+#include "cygerrno.h"
+#include "security.h"
+#include "path.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "cygheap.h"
+#include "sigproc.h"
+#include <sys/termios.h>
+
+extern "C" int
+ioctl (int fd, int cmd, ...)
+{
+ sigframe thisframe (mainthread);
+
+ cygheap_fdget cfd (fd);
+ if (cfd < 0)
+ return -1;
+
+ /* check for optional mode argument */
+ va_list ap;
+ va_start (ap, cmd);
+ char *argp = va_arg (ap, char *);
+ va_end (ap);
+
+ debug_printf ("fd %d, cmd %x", fd, cmd);
+ int res;
+ if (cfd->is_tty () && cfd->get_device () != FH_PTYM)
+ switch (cmd)
+ {
+ case TCGETA:
+ res = tcgetattr (fd, (struct termios *) argp);
+ goto out;
+ case TCSETA:
+ res = tcsetattr (fd, TCSANOW, (struct termios *) argp);
+ goto out;
+ case TCSETAW:
+ res = tcsetattr (fd, TCSADRAIN, (struct termios *) argp);
+ goto out;
+ case TCSETAF:
+ res = tcsetattr (fd, TCSAFLUSH, (struct termios *) argp);
+ goto out;
+ }
+
+ res = cfd->ioctl (cmd, argp);
+
+out:
+ debug_printf ("returning %d", res);
+ return res;
+}
diff --git a/winsup/cygwin/malloc_wrapper.cc b/winsup/cygwin/malloc_wrapper.cc
new file mode 100644
index 00000000000..494fbf13c5b
--- /dev/null
+++ b/winsup/cygwin/malloc_wrapper.cc
@@ -0,0 +1,316 @@
+/* malloc_wrapper.cc
+
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+
+ Originally 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>
+#include <assert.h>
+#include "security.h"
+#include "path.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include <errno.h>
+#include "cygerrno.h"
+#include "cygheap.h"
+#include "heap.h"
+#include "sync.h"
+#include "perprocess.h"
+#include "cygmalloc.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;
+static int use_internal_malloc = 1;
+
+#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;
+ assert (!incygheap (p));
+ assert (inheap (p));
+ free (p);
+}
+#undef free
+
+extern "C" void *
+_realloc_r (struct _reent *, void *p, size_t size)
+{
+ export_malloc_called = 1;
+ assert (!incygheap (p));
+ assert (inheap (p));
+ 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
+#endif
+/* These routines are used by the application if it
+ doesn't provide its own malloc. */
+
+extern "C" void
+free (void *p)
+{
+ malloc_printf ("(%p), called by %p", p, __builtin_return_address (0));
+ if (!use_internal_malloc)
+ user_data->free (p);
+ else
+ {
+ __malloc_lock ();
+ dlfree (p);
+ __malloc_unlock ();
+ }
+}
+
+extern "C" void *
+malloc (size_t size)
+{
+ void *res;
+ export_malloc_called = 1;
+ if (!use_internal_malloc)
+ res = user_data->malloc (size);
+ else
+ {
+ __malloc_lock ();
+ res = dlmalloc (size);
+ __malloc_unlock ();
+ }
+ malloc_printf ("(%d) = %x, called by %p", size, res, __builtin_return_address (0));
+ return res;
+}
+
+extern "C" void *
+realloc (void *p, size_t size)
+{
+ void *res;
+ if (!use_internal_malloc)
+ res = user_data->realloc (p, size);
+ else
+ {
+ __malloc_lock ();
+ res = dlrealloc (p, size);
+ __malloc_unlock ();
+ }
+ malloc_printf ("(%x, %d) = %x, called by %x", p, size, res, __builtin_return_address (0));
+ return res;
+}
+
+extern "C" void *
+calloc (size_t nmemb, size_t size)
+{
+ void *res;
+ if (!use_internal_malloc)
+ res = user_data->calloc (nmemb, size);
+ else
+ {
+ __malloc_lock ();
+ res = dlcalloc (nmemb, size);
+ __malloc_unlock ();
+ }
+ malloc_printf ("(%d, %d) = %x, called by %x", nmemb, size, res, __builtin_return_address (0));
+ return res;
+}
+
+extern "C" void *
+memalign (size_t alignment, size_t bytes)
+{
+ void *res;
+ if (!use_internal_malloc)
+ {
+ set_errno (ENOSYS);
+ res = NULL;
+ }
+ else
+ {
+ __malloc_lock ();
+ res = dlmemalign (alignment, bytes);
+ __malloc_unlock ();
+ }
+
+ return res;
+}
+
+extern "C" void *
+valloc (size_t bytes)
+{
+ void *res;
+ if (!use_internal_malloc)
+ {
+ set_errno (ENOSYS);
+ res = NULL;
+ }
+ else
+ {
+ __malloc_lock ();
+ res = dlvalloc (bytes);
+ __malloc_unlock ();
+ }
+
+ return res;
+}
+
+extern "C" size_t
+malloc_usable_size (void *p)
+{
+ size_t res;
+ if (!use_internal_malloc)
+ {
+ set_errno (ENOSYS);
+ res = 0;
+ }
+ else
+ {
+ __malloc_lock ();
+ res = dlmalloc_usable_size (p);
+ __malloc_unlock ();
+ }
+
+ return res;
+}
+
+extern "C" int
+malloc_trim (size_t pad)
+{
+ size_t res;
+ if (!use_internal_malloc)
+ {
+ set_errno (ENOSYS);
+ res = 0;
+ }
+ else
+ {
+ __malloc_lock ();
+ res = dlmalloc_trim (pad);
+ __malloc_unlock ();
+ }
+
+ return res;
+}
+
+extern "C" int
+mallopt (int p, int v)
+{
+ int res;
+ if (!use_internal_malloc)
+ {
+ set_errno (ENOSYS);
+ res = 0;
+ }
+ else
+ {
+ __malloc_lock ();
+ res = dlmallopt (p, v);
+ __malloc_unlock ();
+ }
+
+ return res;
+}
+
+extern "C" void
+malloc_stats ()
+{
+ if (!use_internal_malloc)
+ set_errno (ENOSYS);
+ else
+ {
+ __malloc_lock ();
+ dlmalloc_stats ();
+ __malloc_unlock ();
+ }
+
+ return;
+}
+
+extern "C" char *
+strdup (const char *s)
+{
+ char *p;
+ size_t len = strlen (s) + 1;
+ if ((p = (char *) malloc (len)) != NULL)
+ memcpy (p, s, len);
+ return p;
+}
+
+/* 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. */
+
+NO_COPY muto *mallock = NULL;
+
+void
+malloc_init ()
+{
+ new_muto (mallock);
+ /* Check if mallock is provided by application. If so, redirect all
+ calls to 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
+ user_data->free (user_data->malloc (16));
+#endif
+ if (!export_malloc_called)
+ use_internal_malloc = 0;
+ }
+}
diff --git a/winsup/cygwin/mmap.cc b/winsup/cygwin/mmap.cc
index 6ddae2ae540..d076f629555 100644
--- a/winsup/cygwin/mmap.cc
+++ b/winsup/cygwin/mmap.cc
@@ -15,8 +15,8 @@ details. */
#include <sys/mman.h>
#include <errno.h>
#include "security.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "cygerrno.h"
#include "cygheap.h"
@@ -62,7 +62,7 @@ class mmap_record
{
dev.devn = 0;
if (fd >= 0 && !cygheap->fdtab.not_open (fd))
- dev = cygheap->fdtab[fd]->dev;
+ dev = cygheap->fdtab[fd]->dev ();
}
/* Default Copy constructor/operator=/destructor are ok */
@@ -244,12 +244,13 @@ mmap_record::alloc_fh ()
return &fh_paging_file;
}
+ static path_conv pc; // should be thread safe - CGF
/* The file descriptor could have been closed or, even
worse, could have been reused for another file before
the call to fork(). This requires creating a fhandler
of the correct type to be sure to call the method of the
correct class. */
- return cygheap->fdtab.build_fhandler (-1, get_device ());
+ return build_fh_dev (get_device ());
}
void
diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc
index 8e3f8dea307..371643a4fac 100644
--- a/winsup/cygwin/net.cc
+++ b/winsup/cygwin/net.cc
@@ -27,8 +27,8 @@ details. */
#include <winsock2.h>
#include "cygerrno.h"
#include "security.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
#include "sigproc.h"
@@ -521,10 +521,10 @@ fdsock (int &fd, const char *name, SOCKET soc)
else
debug_printf ("not setting socket inheritance since winsock2_active %d",
winsock2_active);
- fhandler_socket *fh =
- (fhandler_socket *) cygheap->fdtab.build_fhandler (fd, *socket_dev, name);
+ fhandler_socket *fh = (fhandler_socket *) build_fh_dev (*socket_dev, name);
if (!fh)
return NULL;
+ cygheap->fdtab[fd] = fh;
fh->set_io_handle ((HANDLE) soc);
fh->set_flags (O_RDWR | O_BINARY);
fh->set_r_no_interrupt (winsock2_active);
diff --git a/winsup/cygwin/passwd.cc b/winsup/cygwin/passwd.cc
index cdb73b0d9e4..38876d21710 100644
--- a/winsup/cygwin/passwd.cc
+++ b/winsup/cygwin/passwd.cc
@@ -15,8 +15,8 @@ details. */
#include <errno.h>
#include "cygerrno.h"
#include "security.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "pinfo.h"
#include "cygheap.h"
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index bcbae01041d..3ff8b458d63 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -64,8 +64,8 @@ details. */
#include <cygwin/version.h>
#include "cygerrno.h"
#include "security.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "sync.h"
#include "sigproc.h"
#include "pinfo.h"
@@ -553,9 +553,9 @@ path_conv::check (const char *src, unsigned opt,
else if (isvirtual_dev (dev.devn))
{
/* FIXME: Calling build_fhandler here is not the right way to handle this. */
- fhandler_virtual *fh =
- (fhandler_virtual *) cygheap->fdtab.build_fhandler (-1, dev, (const char *) path_copy, NULL);
+ fhandler_virtual *fh = (fhandler_virtual *) build_fh_dev (dev, path_copy);
int file_type = fh->exists ();
+ delete fh;
switch (file_type)
{
case 1:
@@ -569,7 +569,6 @@ path_conv::check (const char *src, unsigned opt,
fileattr = INVALID_FILE_ATTRIBUTES;
break;
}
- delete fh;
goto out;
}
/* devn should not be a device. If it is, then stop parsing now. */
diff --git a/winsup/cygwin/path.h b/winsup/cygwin/path.h
index b2b8fb8e18e..95ae845d352 100644
--- a/winsup/cygwin/path.h
+++ b/winsup/cygwin/path.h
@@ -8,6 +8,19 @@ This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
+#include "devices.h"
+
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+enum executable_states
+{
+ is_executable,
+ dont_care_if_executable,
+ not_executable = dont_care_if_executable,
+ dont_know_if_executable
+};
+
struct suffix_info
{
const char *name;
@@ -129,6 +142,9 @@ class path_conv
void check (const char *src, unsigned opt = PC_SYM_FOLLOW,
const suffix_info *suffixes = NULL) __attribute__ ((regparm(3)));
+ path_conv (const device& in_dev): fileattr (INVALID_FILE_ATTRIBUTES),
+ path_flags (0), known_suffix (NULL), error (0), dev (in_dev) {}
+
path_conv (int, const char *src, unsigned opt = PC_SYM_FOLLOW,
const suffix_info *suffixes = NULL)
{
@@ -162,6 +178,11 @@ class path_conv
DWORD volser () { return fs.serial; }
const char *volname () {return fs.name; }
void fillin (HANDLE h);
+ inline size_t size ()
+ {
+ return (sizeof (*this) - sizeof (path)) + strlen (path) + 1;
+ }
+
char *normalized_path;
private:
char path[MAX_PATH];
@@ -217,6 +238,7 @@ int path_prefix_p (const char *path1, const char *path2, int len1) __attribute__
#define MAX_ETC_FILES 2
class etc
{
+ friend class dtable;
static int curr_ix;
static bool change_possible[MAX_ETC_FILES + 1];
static const char *fn[MAX_ETC_FILES + 1];
diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc
index c55d44b2a5d..b3fdbb51785 100644
--- a/winsup/cygwin/pinfo.cc
+++ b/winsup/cygwin/pinfo.cc
@@ -15,8 +15,8 @@ details. */
#include <limits.h>
#include <stdarg.h>
#include "security.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "cygerrno.h"
#include "sigproc.h"
diff --git a/winsup/cygwin/pipe.cc b/winsup/cygwin/pipe.cc
index f2a518186bf..082f1938544 100644
--- a/winsup/cygwin/pipe.cc
+++ b/winsup/cygwin/pipe.cc
@@ -16,8 +16,8 @@ details. */
#include <sys/socket.h>
#include "cygerrno.h"
#include "security.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
#include "thread.h"
@@ -189,8 +189,8 @@ fhandler_pipe::create (fhandler_pipe *fhs[2], unsigned psize, int mode, bool fif
__seterrno ();
else
{
- fhs[0] = (fhandler_pipe *) cygheap->fdtab.build_fhandler (-1, *piper_dev, "/dev/piper");
- fhs[1] = (fhandler_pipe *) cygheap->fdtab.build_fhandler (-1, *pipew_dev, "/dev/pipew");
+ fhs[0] = (fhandler_pipe *) build_fh_dev (*piper_dev);
+ fhs[1] = (fhandler_pipe *) build_fh_dev (*pipew_dev);
int binmode = mode & O_TEXT ?: O_BINARY;
fhs[0]->init (r, GENERIC_READ, binmode);
diff --git a/winsup/cygwin/poll.cc b/winsup/cygwin/poll.cc
new file mode 100644
index 00000000000..da2f80b0d3c
--- /dev/null
+++ b/winsup/cygwin/poll.cc
@@ -0,0 +1,139 @@
+/* poll.cc. Implements poll(2) via usage of select(2) call.
+
+ Copyright 2000, 2001, 2002 Red Hat, Inc.
+
+ This file is part of Cygwin.
+
+ This software is a copyrighted work licensed under the terms of the
+ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+ details. */
+
+#define __INSIDE_CYGWIN_NET__
+
+#include "winsup.h"
+#include <sys/time.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <stdlib.h>
+#define USE_SYS_TYPES_FD_SET
+#include <winsock2.h>
+#include "security.h"
+#include "path.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "cygerrno.h"
+#include "cygheap.h"
+#include "sigproc.h"
+
+extern "C"
+int
+poll (struct pollfd *fds, unsigned int nfds, int timeout)
+{
+ int max_fd = 0;
+ fd_set *read_fds, *write_fds, *except_fds;
+ struct timeval tv = { timeout / 1000, (timeout % 1000) * 1000 };
+ sigframe thisframe (mainthread);
+
+ for (unsigned int i = 0; i < nfds; ++i)
+ if (fds[i].fd > max_fd)
+ max_fd = fds[i].fd;
+
+ size_t fds_size = howmany (max_fd + 1, NFDBITS) * sizeof (fd_mask);
+
+ read_fds = (fd_set *) alloca (fds_size);
+ write_fds = (fd_set *) alloca (fds_size);
+ except_fds = (fd_set *) alloca (fds_size);
+
+ if (!read_fds || !write_fds || !except_fds)
+ {
+ set_errno (ENOMEM);
+ return -1;
+ }
+
+ memset (read_fds, 0, fds_size);
+ memset (write_fds, 0, fds_size);
+ memset (except_fds, 0, fds_size);
+
+ int invalid_fds = 0;
+ for (unsigned int i = 0; i < nfds; ++i)
+ {
+ fds[i].revents = 0;
+ if (!cygheap->fdtab.not_open (fds[i].fd))
+ {
+ if (fds[i].events & POLLIN)
+ FD_SET(fds[i].fd, read_fds);
+ if (fds[i].events & POLLOUT)
+ FD_SET(fds[i].fd, write_fds);
+ if (fds[i].events & POLLPRI)
+ FD_SET(fds[i].fd, except_fds);
+ }
+ else if (fds[i].fd >= 0)
+ {
+ ++invalid_fds;
+ fds[i].revents = POLLNVAL;
+ }
+ }
+
+ if (invalid_fds)
+ return invalid_fds;
+
+ int ret = cygwin_select (max_fd + 1, read_fds, write_fds, except_fds, timeout < 0 ? NULL : &tv);
+
+ if (ret > 0)
+ for (unsigned int i = 0; i < nfds; ++i)
+ {
+ if (fds[i].fd >= 0)
+ {
+ if (cygheap->fdtab.not_open (fds[i].fd))
+ fds[i].revents = POLLHUP;
+ else
+ {
+ if (FD_ISSET(fds[i].fd, read_fds))
+ {
+ char peek[1];
+ fhandler_socket *sock =
+ cygheap->fdtab[fds[i].fd]->is_socket ();
+ if (!sock)
+ fds[i].revents |= POLLIN;
+ else
+ {
+ /* The following action can change errno. We have to
+ reset it to it's old value. */
+ int old_errno = get_errno ();
+ switch (sock->recvfrom (peek, sizeof (peek), MSG_PEEK,
+ NULL, NULL))
+ {
+ case -1: /* Something weird happened */
+ /* When select returns that data is available,
+ that could mean that the socket is in
+ listen mode and a client tries to connect.
+ Unfortunately, recvfrom() doesn't make much
+ sense then. It returns WSAENOTCONN in that
+ case. Since that's not actually an error,
+ we must not set POLLERR but POLLIN. */
+ if (WSAGetLastError () != WSAENOTCONN)
+ fds[i].revents |= POLLERR;
+ else
+ fds[i].revents |= POLLIN;
+ break;
+ case 0: /* Closed on the read side. */
+ fds[i].revents |= POLLHUP;
+ break;
+ default:
+ fds[i].revents |= POLLIN;
+ break;
+ }
+ set_errno (old_errno);
+ }
+ }
+ if (FD_ISSET(fds[i].fd, write_fds))
+ fds[i].revents |= POLLOUT;
+ if (FD_ISSET(fds[i].fd, except_fds))
+ fds[i].revents |= POLLPRI;
+ }
+ }
+ }
+
+ return ret;
+}
diff --git a/winsup/cygwin/sec_acl.cc b/winsup/cygwin/sec_acl.cc
index febda4fb275..1a67dcd41d5 100644
--- a/winsup/cygwin/sec_acl.cc
+++ b/winsup/cygwin/sec_acl.cc
@@ -25,8 +25,8 @@ details. */
#include <winuser.h>
#include "cygerrno.h"
#include "security.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "pinfo.h"
#include "cygheap.h"
diff --git a/winsup/cygwin/sec_helper.cc b/winsup/cygwin/sec_helper.cc
index 749596e63f1..e5d8d6f5cb9 100644
--- a/winsup/cygwin/sec_helper.cc
+++ b/winsup/cygwin/sec_helper.cc
@@ -26,8 +26,8 @@ details. */
#include <wininet.h>
#include "cygerrno.h"
#include "security.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "pinfo.h"
#include "cygheap.h"
diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc
index 35ac5cfac63..e32b24c8c6f 100644
--- a/winsup/cygwin/security.cc
+++ b/winsup/cygwin/security.cc
@@ -31,8 +31,8 @@ details. */
#include <aclapi.h>
#include "cygerrno.h"
#include "security.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "pinfo.h"
#include "cygheap.h"
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index f7d160c9c4e..1a829984f78 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -35,8 +35,8 @@ details. */
#include "select.h"
#include "cygerrno.h"
#include "security.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
#include "sigproc.h"
diff --git a/winsup/cygwin/shared.cc b/winsup/cygwin/shared.cc
index ae30e73f792..8eb544472d9 100644
--- a/winsup/cygwin/shared.cc
+++ b/winsup/cygwin/shared.cc
@@ -17,8 +17,8 @@ details. */
#include <errno.h>
#include "pinfo.h"
#include "security.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "cygerrno.h"
#include "cygheap.h"
diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc
new file mode 100644
index 00000000000..2a3bd945e9a
--- /dev/null
+++ b/winsup/cygwin/sigproc.cc
@@ -0,0 +1,1310 @@
+/* sigproc.cc: inter/intra signal and sub process handler
+
+ Copyright 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+
+ 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 <stdlib.h>
+#include <time.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/cygwin.h>
+#include <assert.h>
+#include "cygerrno.h"
+#include "sync.h"
+#include "sigproc.h"
+#include "pinfo.h"
+#include "security.h"
+#include "path.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "cygheap.h"
+#include "child_info_magic.h"
+#define NEED_VFORK
+#include "perthread.h"
+#include "shared_info.h"
+#include "cygthread.h"
+
+/*
+ * 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 TOTSIGS (NSIG + __SIGOFFSET)
+
+#define wake_wait_subproc() SetEvent (events[0])
+
+#define no_signals_available() (!hwait_sig || !sig_loop_wait)
+
+#define NZOMBIES 256
+
+/*
+ * 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 = 1000; // Wait for subprocesses to exit
+Static DWORD sig_loop_wait = INFINITE; // Wait for signals to arrive
+
+Static HANDLE sigcatch_nonmain; // The semaphore signaled when
+ // signals are available for
+ // processing from non-main thread
+Static HANDLE sigcatch_main; // Signalled when main thread sends a
+ // signal
+Static HANDLE sigcatch_nosync; // Signal wait_sig to scan sigtodo
+ // but not to bother with any
+ // synchronization
+Static HANDLE sigcomplete_main; // Event signaled when a signal has
+ // finished processing for the main
+ // thread
+Static HANDLE sigcomplete_nonmain; // Semaphore raised for non-main
+ // threads when a signal has finished
+ // processing
+HANDLE NO_COPY sigCONT; // Used to "STOP" a process
+Static cygthread *hwait_sig; // Handle of wait_sig thread
+Static cygthread *hwait_subproc; // Handle of sig_subproc thread
+
+Static HANDLE wait_sig_inited; // Control synchronization of
+ // message queue startup
+
+/* Used by WaitForMultipleObjects. These are handles to child processes.
+ */
+Static HANDLE events[PSIZE + 1]; // All my children's handles++
+#define hchildren (events + 1) // Where the children handles begin
+Static char cpchildren[PSIZE * sizeof (pinfo)]; // All my children info
+Static int nchildren; // Number of active children
+Static char czombies[(NZOMBIES + 1) * sizeof (pinfo)]; // All my deceased children info
+Static int nzombies; // Number of deceased children
+
+#define pchildren ((pinfo *) cpchildren)
+#define zombies ((pinfo *) czombies)
+
+Static waitq waitq_head = {0, 0, 0, 0, 0, 0, 0};// Start of queue for wait'ing threads
+Static waitq waitq_main; // Storage for main thread
+
+muto NO_COPY *sync_proc_subproc = NULL; // Control access to subproc stuff
+
+DWORD NO_COPY sigtid = 0; // ID of the signal thread
+
+int NO_COPY pending_signals = 0; // TRUE if signals pending
+
+/* Functions
+ */
+static int __stdcall checkstate (waitq *);
+static __inline__ BOOL get_proc_lock (DWORD, DWORD);
+static HANDLE __stdcall getsem (_pinfo *, const char *, int, 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 (!myself->ppid_handle)
+ {
+ debug_printf ("No myself->ppid_handle");
+ res = FALSE;
+ }
+ else
+ for (int i = 0; i < 2; i++)
+ switch (res = WaitForSingleObject (myself->ppid_handle, 0))
+ {
+ case WAIT_OBJECT_0:
+ debug_printf ("parent dead.");
+ res = FALSE;
+ goto out;
+ case WAIT_TIMEOUT:
+ debug_printf ("parent still alive");
+ res = TRUE;
+ goto out;
+ case WAIT_FAILED:
+ DWORD werr = GetLastError ();
+ if (werr == ERROR_INVALID_HANDLE && i == 0)
+ continue;
+ system_printf ("WFSO for myself->ppid_handle(%p) failed, error %d",
+ myself->ppid_handle, werr);
+ res = FALSE;
+ goto out;
+ }
+out:
+ return res;
+}
+
+void __stdcall
+wait_for_sigthread ()
+{
+ assert (wait_sig_inited);
+ (void) WaitForSingleObject (wait_sig_inited, INFINITE);
+ (void) ForceCloseHandle (wait_sig_inited);
+ wait_sig_inited = NULL;
+}
+
+/* Get the sync_proc_subproc muto to control access to
+ * children, zombie arrays.
+ * Attempt to handle case where process is exiting as we try to grab
+ * the mutex.
+ */
+static BOOL
+get_proc_lock (DWORD what, DWORD val)
+{
+ Static int lastwhat = -1;
+ if (!sync_proc_subproc)
+ 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;
+}
+
+static BOOL __stdcall
+proc_can_be_signalled (_pinfo *p)
+{
+ if (p == myself_nowait || p == myself_nowait_nonmain || p == myself)
+ {
+ assert (!wait_sig_inited);
+ return 1;
+ }
+
+ return ISSTATE (p, PID_INITIALIZING) ||
+ (((p)->process_state & (PID_ACTIVE | PID_IN_USE)) ==
+ (PID_ACTIVE | PID_IN_USE));
+}
+
+BOOL __stdcall
+pid_exists (pid_t pid)
+{
+ pinfo p (pid);
+ return proc_exists (p);
+}
+
+/* Test to determine if a process really exists and is processing signals.
+ */
+BOOL __stdcall
+proc_exists (_pinfo *p)
+{
+ return p && !(p->process_state & PID_EXITED);
+}
+
+/* Return 1 if this is one of our children, zero otherwise.
+ FIXME: This really should be integrated with the rest of the proc_subproc
+ testing. Scanning these lists twice is inefficient. */
+int __stdcall
+mychild (int pid)
+{
+ for (int i = 0; i < nchildren; i++)
+ if (pchildren[i]->pid == pid)
+ return 1;
+ for (int i = 0; i < nzombies; i++)
+ if (zombies[i]->pid == pid)
+ return 1;
+ return 0;
+}
+
+/* Handle all subprocess requests
+ */
+#define vchild (*((pinfo *) val))
+int __stdcall
+proc_subproc (DWORD what, DWORD val)
+{
+ int rc = 1;
+ int potential_match;
+ _pinfo *child;
+ int clearing;
+ waitq *w;
+
+#define wval ((waitq *) val)
+
+ sigproc_printf ("args: %x, %d", what, val);
+
+ if (!get_proc_lock (what, val)) // Serialize access to this function
+ {
+ system_printf ("couldn't get proc lock. Something is wrong.");
+ goto out1;
+ }
+
+ switch (what)
+ {
+ /* Add a new subprocess to the children arrays.
+ * (usually called from the main thread)
+ */
+ case PROC_ADDCHILD:
+ if (nchildren >= PSIZE - 1)
+ {
+ rc = 0;
+ break;
+ }
+ pchildren[nchildren] = vchild;
+ hchildren[nchildren] = vchild->hProcess;
+ if (!DuplicateHandle (hMainProc, vchild->hProcess, hMainProc, &vchild->pid_handle,
+ 0, 0, DUPLICATE_SAME_ACCESS))
+ system_printf ("Couldn't duplicate child handle for pid %d, %E", vchild->pid);
+ ProtectHandle1 (vchild->pid_handle, pid_handle);
+
+ if (!DuplicateHandle (hMainProc, hMainProc, vchild->hProcess, &vchild->ppid_handle,
+ 0, TRUE, DUPLICATE_SAME_ACCESS))
+ system_printf ("Couldn't duplicate my handle<%p> for pid %d, %E", hMainProc, vchild->pid);
+ vchild->ppid = myself->pid;
+ vchild->uid = myself->uid;
+ vchild->gid = myself->gid;
+ vchild->pgid = myself->pgid;
+ vchild->sid = myself->sid;
+ vchild->ctty = myself->ctty;
+ vchild->process_state |= PID_INITIALIZING | (myself->process_state & PID_USETTY);
+
+ sigproc_printf ("added pid %d to wait list, slot %d, winpid %p, handle %p",
+ vchild->pid, nchildren, vchild->dwProcessId,
+ vchild->hProcess);
+ nchildren++;
+
+ wake_wait_subproc ();
+ break;
+
+ /* A child process had terminated.
+ Possibly this is just due to an exec(). Cygwin implements an exec()
+ as a "handoff" from one windows process to another. If child->hProcess
+ is different from what is recorded in hchildren, then this is an exec().
+ Otherwise this is a normal child termination event.
+ (called from wait_subproc thread) */
+ case PROC_CHILDTERMINATED:
+ if (hchildren[val] != pchildren[val]->hProcess)
+ {
+ sigproc_printf ("pid %d[%d], reparented old hProcess %p, new %p",
+ pchildren[val]->pid, val, hchildren[val], pchildren[val]->hProcess);
+ HANDLE h = hchildren[val];
+ hchildren[val] = pchildren[val]->hProcess; /* Filled out by child */
+ sync_proc_subproc->release (); // Release the lock ASAP
+ ForceCloseHandle1 (h, childhProc);
+ ProtectHandle1 (pchildren[val]->hProcess, childhProc);
+ rc = 0;
+ goto out; // This was an exec()
+ }
+
+ sigproc_printf ("pid %d[%d] terminated, handle %p, nchildren %d, nzombies %d",
+ pchildren[val]->pid, val, hchildren[val], nchildren, nzombies);
+
+ int thiszombie;
+ thiszombie = nzombies;
+ zombies[nzombies] = pchildren[val]; // Add to zombie array
+ zombies[nzombies++]->process_state = PID_ZOMBIE;// Walking dead
+
+ sigproc_printf ("zombifying [%d], pid %d, handle %p, nchildren %d",
+ val, pchildren[val]->pid, hchildren[val], nchildren);
+ if ((int) val < --nchildren)
+ {
+ hchildren[val] = hchildren[nchildren];
+ pchildren[val] = pchildren[nchildren];
+ }
+
+ /* See if we should care about the this terminated process. If we've
+ filled up our table or if we're ignoring SIGCHLD, then we immediately
+ remove the process and move on. Otherwise, this process becomes a zombie
+ which must be reaped by a wait() call. */
+ if (nzombies >= NZOMBIES
+ || myself->getsig (SIGCHLD).sa_handler == (void *) SIG_IGN)
+ {
+ sigproc_printf ("automatically removing zombie %d", thiszombie);
+ remove_zombie (thiszombie);
+ }
+
+ /* Don't scan the wait queue yet. Caller will send SIGCHLD to this process.
+ This will cause an eventual scan of waiters. */
+ break;
+
+ /* Handle a wait4() operation. Allocates an event for the calling
+ * thread which is signaled when the appropriate pid exits or stops.
+ * (usually called from the main thread)
+ */
+ case PROC_WAIT:
+ wval->ev = NULL; // Don't know event flag yet
+
+ if (wval->pid <= 0)
+ child = NULL; // Not looking for a specific pid
+ else if (!mychild (wval->pid))
+ goto out; // invalid pid. flag no such child
+
+ wval->status = 0; // Don't know status yet
+ sigproc_printf ("wval->pid %d, wval->options %d", wval->pid, wval->options);
+
+ /* If the first time for this thread, create a new event, otherwise
+ * reset the event.
+ */
+ if ((wval->ev = wval->thread_ev) == NULL)
+ {
+ wval->ev = wval->thread_ev = CreateEvent (&sec_none_nih, TRUE,
+ FALSE, NULL);
+ ProtectHandle (wval->ev);
+ }
+
+ ResetEvent (wval->ev);
+ w = waitq_head.next;
+ waitq_head.next = wval; /* Add at the beginning. */
+ wval->next = w; /* Link in rest of the list. */
+ clearing = 0;
+ goto scan_wait;
+
+ /* Clear all waiting threads. Called from exceptions.cc prior to
+ * the main thread's dispatch to a signal handler function.
+ * (called from wait_sig thread)
+ */
+ case PROC_CLEARWAIT:
+ /* Clear all "wait"ing threads. */
+ if (val)
+ sigproc_printf ("clear waiting threads");
+ else
+ sigproc_printf ("looking for processes to reap");
+ clearing = val;
+
+ scan_wait:
+ /* Scan the linked list of wait()ing threads. If a wait's parameters
+ * match this pid, then activate it.
+ */
+ for (w = &waitq_head; w->next != NULL; w = w->next)
+ {
+ if ((potential_match = checkstate (w)) > 0)
+ sigproc_printf ("released waiting thread");
+ else if (!clearing && !(w->next->options & WNOHANG) && potential_match < 0)
+ sigproc_printf ("only found non-terminated children");
+ else if (potential_match <= 0) // nothing matched
+ {
+ sigproc_printf ("waiting thread found no children");
+ HANDLE oldw = w->next->ev;
+ w->next->pid = 0;
+ if (clearing)
+ w->next->status = -1; /* flag that a signal was received */
+ else if (!potential_match || !(w->next->options & WNOHANG))
+ w->next->ev = NULL;
+ if (!SetEvent (oldw))
+ system_printf ("couldn't wake up wait event %p, %E", oldw);
+ w->next = w->next->next;
+ }
+ if (w->next == NULL)
+ break;
+ }
+
+ if (!clearing)
+ sigproc_printf ("finished processing terminated/stopped child");
+ else
+ {
+ waitq_head.next = NULL;
+ sigproc_printf ("finished clearing");
+ }
+ break;
+ }
+
+out:
+ sync_proc_subproc->release (); // Release the lock
+out1:
+ sigproc_printf ("returning %d", rc);
+ return rc;
+}
+
+/* Terminate the wait_subproc thread.
+ * Called on process exit.
+ * Also called by spawn_guts to disassociate any subprocesses from this
+ * process. Subprocesses will then know to clean up after themselves and
+ * will not become zombies.
+ */
+void __stdcall
+proc_terminate (void)
+{
+ sigproc_printf ("nchildren %d, nzombies %d", nchildren, nzombies);
+ /* Signal processing is assumed to be blocked in this routine. */
+ if (hwait_subproc)
+ {
+ proc_loop_wait = 0; // Tell wait_subproc thread to exit
+ sync_proc_subproc->acquire (WPSP);
+ wake_wait_subproc (); // Wake wait_subproc loop
+ hwait_subproc = NULL;
+
+ (void) proc_subproc (PROC_CLEARWAIT, 1);
+
+ /* Clean out zombie processes from the pid list. */
+ int i;
+ for (i = 0; i < nzombies; i++)
+ {
+ if (zombies[i]->hProcess)
+ {
+ ForceCloseHandle1 (zombies[i]->hProcess, childhProc);
+ ForceCloseHandle1 (zombies[i]->pid_handle, pid_handle);
+ }
+ zombies[i]->ppid = 1;
+ zombies[i]->process_state = PID_EXITED; /* CGF FIXME - still needed? */
+ zombies[i].release (); // FIXME: this breaks older gccs for some reason
+ }
+
+ /* Disassociate my subprocesses */
+ for (i = 0; i < nchildren; i++)
+ {
+ if (!pchildren[i]->hProcess)
+ sigproc_printf ("%d(%d) hProcess cleared already?", pchildren[i]->pid,
+ pchildren[i]->dwProcessId);
+ else
+ {
+ ForceCloseHandle1 (pchildren[i]->hProcess, childhProc);
+ sigproc_printf ("%d(%d) closed child handle", pchildren[i]->pid,
+ pchildren[i]->dwProcessId);
+ pchildren[i]->ppid = 1;
+ if (pchildren[i]->pgid == myself->pid)
+ pchildren[i]->process_state |= PID_ORPHANED;
+ }
+ pchildren[i].release ();
+ }
+ nchildren = nzombies = 0;
+ /* Just zero sync_proc_subproc as the delete below seems to cause
+ problems for older gccs. */
+ sync_proc_subproc = NULL;
+ }
+ sigproc_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 justwake)
+{
+ if (!hwait_sig)
+ return 0;
+ DWORD tid = GetCurrentThreadId ();
+
+ sigframe thisframe (mainthread);
+
+ if (tid == sigtid && !justwake)
+ justwake = 1;
+
+ int was_pending = pending_signals;
+#ifdef DEBUGGING
+ sigproc_printf ("pending_signals %d", was_pending);
+#endif
+ if (!was_pending && !justwake)
+#ifdef DEBUGGING
+ sigproc_printf ("no need to wake anything up");
+#else
+ ;
+#endif
+ else
+ {
+ if (!justwake)
+ (void) sig_send (myself, __SIGFLUSH);
+ else if (ReleaseSemaphore (sigcatch_nosync, 1, NULL))
+#ifdef DEBUGGING
+ sigproc_printf ("woke up wait_sig");
+#else
+ ;
+#endif
+ else if (no_signals_available ())
+ /*sigproc_printf ("I'm going away now")*/;
+ else
+ system_printf ("%E releasing sigcatch_nosync(%p)", sigcatch_nosync);
+
+ }
+ if (was_pending && !justwake)
+ thisframe.call_signal_handler ();
+
+ 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, TRUE, FALSE, NULL);
+ ProtectHandle (wait_sig_inited);
+
+ /* sync_proc_subproc is used by proc_subproc. It serialises
+ * access to the children and zombie arrays.
+ */
+ new_muto (sync_proc_subproc);
+
+ /* local event signaled when main thread has been dispatched
+ to a signal handler function. */
+ signal_arrived = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
+ ProtectHandle (signal_arrived);
+
+ hwait_sig = new cygthread (wait_sig, cygself, "sig");
+ hwait_sig->zap_h ();
+
+ /* Initialize waitq structure for main thread. A waitq structure is
+ * allocated for each thread that executes a wait to allow multiple threads
+ * to perform waits. Pre-allocate a waitq structure for the main thread.
+ */
+ waitq *w;
+ if ((w = (waitq *)waitq_storage.get ()) == NULL)
+ {
+ w = &waitq_main;
+ waitq_storage.set (w);
+ }
+ memset (w, 0, sizeof *w); // Just to be safe
+
+ myself->getsig (SIGSTOP).sa_flags = SA_RESTART | SA_NODEFER;
+ sigproc_printf ("process/signal handling enabled(%x)", myself->process_state);
+ return;
+}
+
+/* Called on process termination to terminate signal and process threads.
+ */
+void __stdcall
+sigproc_terminate (void)
+{
+ hwait_sig = NULL;
+
+ if (!sig_loop_wait)
+ sigproc_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 (1);
+ }
+
+ 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
+
+ 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, DWORD ebp, bool exception)
+{
+ int rc = 1;
+ DWORD tid = GetCurrentThreadId ();
+ BOOL its_me;
+ HANDLE thiscatch = NULL;
+ HANDLE thiscomplete = NULL;
+ BOOL wait_for_completion;
+ sigframe thisframe;
+
+ if (p == myself_nowait_nonmain)
+ p = (tid == mainthread.id) ? (_pinfo *) 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
+ assert (!wait_sig_inited);
+ 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? */
+ {
+ sigproc_printf ("invalid pid %d(%x), signal %d",
+ p->pid, p->process_state, sig);
+ set_errno (ESRCH);
+ goto out;
+ }
+
+ sigproc_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 != mainthread.id)
+ {
+ thiscatch = sigcatch_nonmain;
+ thiscomplete = sigcomplete_nonmain;
+ }
+ else
+ {
+ thiscatch = sigcatch_main;
+ thiscomplete = sigcomplete_main;
+ thisframe.set (mainthread, ebp, exception);
+ }
+ }
+ 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 0
+ int prio;
+ prio = GetThreadPriority (GetCurrentThread ());
+ (void) SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL);
+#endif
+
+ 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 ())
+ sigproc_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;
+ sigproc_printf ("Not waiting for sigcomplete. its_me %d signal %d", its_me, sig);
+ if (!its_me)
+ ForceCloseHandle (thiscatch);
+ }
+ else
+ {
+ sigproc_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 0
+ SetThreadPriority (GetCurrentThread (), prio);
+#endif
+
+ 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, signal %d, rc %d, %E",
+ sig, rc);
+ set_errno (ENOSYS);
+ rc = -1;
+ }
+
+out:
+ sigproc_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);
+ hwait_subproc = new cygthread (wait_subproc, NULL, "proc");
+ hwait_subproc->zap_h ();
+ ProtectHandle (events[0]);
+ sigproc_printf ("started wait_subproc thread");
+}
+
+/* Initialize some of the memory block passed to child processes
+ by fork/spawn/exec. */
+
+void __stdcall
+init_child_info (DWORD chtype, child_info *ch, pid_t pid, HANDLE subproc_ready)
+{
+ memset (ch, 0, sizeof *ch);
+ ch->cb = chtype == PROC_FORK ? sizeof (child_info_fork) : sizeof (child_info);
+ ch->intro = PROC_MAGIC_GENERIC;
+ ch->magic = CHILD_INFO_MAGIC;
+ ch->type = chtype;
+ ch->cygpid = pid;
+ ch->subproc_ready = subproc_ready;
+ ch->pppid_handle = myself->ppid_handle;
+ ch->fhandler_union_cb = sizeof (fhandler_union);
+ ch->mount_h = cygwin_mount_h;
+}
+
+/* Check the state of all of our children to see if any are stopped or
+ * terminated.
+ */
+static int __stdcall
+checkstate (waitq *parent_w)
+{
+ int potential_match = 0;
+
+ sigproc_printf ("nchildren %d, nzombies %d", nchildren, nzombies);
+
+ /* Check already dead processes first to see if they match the criteria
+ * given in w->next.
+ */
+ for (int i = 0; i < nzombies; i++)
+ switch (stopped_or_terminated (parent_w, zombies[i]))
+ {
+ case -1:
+ potential_match = -1;
+ break;
+ case 1:
+ remove_zombie (i);
+ potential_match = 1;
+ goto out;
+ }
+
+ sigproc_printf ("checking alive children");
+
+ /* No dead terminated children matched. Check for stopped children. */
+ for (int i = 0; i < nchildren; i++)
+ switch (stopped_or_terminated (parent_w, pchildren[i]))
+ {
+ case -1:
+ potential_match = -1;
+ break;
+ case 1:
+ potential_match = 1;
+ goto out;
+ }
+
+out:
+ sigproc_printf ("returning %d", potential_match);
+ return potential_match;
+}
+
+/* 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 = 1000;
+ /* Wait for new process to generate its semaphores. */
+ sigproc_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++)
+ low_priority_sleep (1);
+ }
+
+ SetLastError (0);
+ if (p == NULL)
+ {
+ char sa_buf[1024];
+
+ DWORD winpid = GetCurrentProcessId ();
+ h = CreateSemaphore (sec_user_nih (sa_buf), init, max,
+ str = shared_name (str, winpid));
+ p = myself;
+ if (!h)
+ {
+ system_printf ("can't create semaphore %s, %E", str);
+ __seterrno ();
+ }
+ }
+ else
+ {
+ h = OpenSemaphore (SEMAPHORE_ALL_ACCESS, FALSE,
+ shared_name (str, p->dwProcessId));
+
+ if (!h)
+ {
+ if (GetLastError () == ERROR_FILE_NOT_FOUND && !proc_exists (p))
+ set_errno (ESRCH); /* No such process */
+ else
+ set_errno (EPERM); /* Couldn't access the semaphore --
+ different cygwin DLL maybe? */
+ }
+ }
+
+ return h;
+}
+
+/* Remove a zombie from zombies by swapping it with the last child in the list.
+ */
+static void __stdcall
+remove_zombie (int ci)
+{
+ sigproc_printf ("removing %d, pid %d, nzombies %d", ci, zombies[ci]->pid,
+ nzombies);
+
+ if (zombies[ci])
+ {
+ ForceCloseHandle1 (zombies[ci]->hProcess, childhProc);
+ ForceCloseHandle1 (zombies[ci]->pid_handle, pid_handle);
+ zombies[ci].release ();
+ }
+
+ if (ci < --nzombies)
+ zombies[ci] = zombies[nzombies];
+
+ return;
+}
+
+/* Check status of child process vs. waitq member.
+ *
+ * parent_w is the pointer to the parent of the waitq member in question.
+ * child is the subprocess being considered.
+ *
+ * Returns
+ * 1 if stopped or terminated child matches parent_w->next criteria
+ * -1 if a non-stopped/terminated child matches parent_w->next criteria
+ * 0 if child does not match parent_w->next criteria
+ */
+static int __stdcall
+stopped_or_terminated (waitq *parent_w, _pinfo *child)
+{
+ int potential_match;
+ waitq *w = parent_w->next;
+
+ sigproc_printf ("considering pid %d", child->pid);
+ if (w->pid == -1)
+ potential_match = 1;
+ else if (w->pid == 0)
+ potential_match = child->pgid == myself->pgid;
+ else if (w->pid < 0)
+ potential_match = child->pgid == -w->pid;
+ else
+ potential_match = (w->pid == child->pid);
+
+ if (!potential_match)
+ return 0;
+
+ BOOL terminated;
+
+ if ((terminated = child->process_state == PID_ZOMBIE) ||
+ ((w->options & WUNTRACED) && child->stopsig))
+ {
+ parent_w->next = w->next; /* successful wait. remove from wait queue */
+ w->pid = child->pid;
+
+ if (!terminated)
+ {
+ sigproc_printf ("stopped child");
+ w->status = (child->stopsig << 8) | 0x7f;
+ child->stopsig = 0;
+ }
+ else /* Should only get here when child has been moved to the zombies array */
+ {
+ DWORD status;
+ if (!GetExitCodeProcess (child->hProcess, &status))
+ status = 0xffff;
+ if (status & EXIT_SIGNAL)
+ w->status = (status >> 8) & 0xff; /* exited due to signal */
+ else
+ w->status = (status & 0xff) << 8; /* exited via "exit ()" */
+
+ add_rusage (&myself->rusage_children, &child->rusage_children);
+ add_rusage (&myself->rusage_children, &child->rusage_self);
+
+ if (w->rusage)
+ {
+ add_rusage ((struct rusage *) w->rusage, &child->rusage_children);
+ add_rusage ((struct rusage *) w->rusage, &child->rusage_self);
+ }
+ }
+
+ if (!SetEvent (w->ev)) /* wake up wait4 () immediately */
+ system_printf ("couldn't wake up wait event %p, %E", w->ev);
+ return 1;
+ }
+
+ return -potential_match;
+}
+
+static void
+talktome ()
+{
+ winpids pids;
+ for (unsigned i = 0; i < pids.npids; i++)
+ if (pids[i]->hello_pid == myself->pid)
+ pids[i]->commune_recv ();
+}
+
+/* Process signals by waiting for a semaphore to become signaled.
+ * Then scan an in-memory array representing queued signals.
+ * Executes in a separate thread.
+ *
+ * Signals sent from this process are sent a completion signal so
+ * that returns from kill/raise do not occur until the signal has
+ * has been handled, as per POSIX.
+ */
+static DWORD WINAPI
+wait_sig (VOID *self)
+{
+ /* Initialization */
+ (void) SetThreadPriority (GetCurrentThread (), 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, FALSE, FALSE, NULL);
+ sigproc_printf ("sigcatch_nonmain %p, sigcatch_main %p", sigcatch_nonmain, sigcatch_main);
+ sigCONT = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL);
+
+ /* Setting dwProcessId flags that this process is now capable of receiving
+ * signals. Prior to this, dwProcessId was set to the windows pid of
+ * of the original windows process which spawned us unless this was a
+ * "toplevel" process.
+ */
+ myself->dwProcessId = GetCurrentProcessId ();
+ myself->process_state |= PID_ACTIVE;
+ myself->process_state &= ~PID_INITIALIZING;
+
+ ProtectHandle (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");
+ ForceCloseHandle1 (child_proc_info->subproc_ready, subproc_ready);
+ /* Initialize an "indirect" pid block so that if someone looks up this
+ process via its Windows PID it will be redirected to the appropriate
+ Cygwin PID shared memory block. */
+ static pinfo NO_COPY myself_identity;
+ myself_identity.init (cygwin_pid (myself->dwProcessId), PID_EXECED);
+ }
+
+ SetEvent (wait_sig_inited);
+ sigtid = GetCurrentThreadId ();
+
+ 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);
+ (void) SetThreadPriority (GetCurrentThread (), WAIT_SIG_PRIORITY);
+
+ /* 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;
+ sigproc_printf ("awake");
+ /* A sigcatch semaphore has been signaled. Scan the sigtodo
+ * array looking for any unprocessed signals.
+ */
+ pending_signals = -1;
+ int saw_pending_signals = 0;
+ int saw_sigchld = 0;
+ for (int sig = -__SIGOFFSET; sig < NSIG; sig++)
+ {
+ while (InterlockedDecrement (myself->getsigtodo (sig)) >= 0)
+ {
+ if (sig == SIGCHLD)
+ saw_sigchld = 1;
+
+ if (sig > 0 && sig != SIGKILL && sig != SIGSTOP &&
+ (sigismember (&myself->getsigmask (), sig) ||
+ main_vfork->pid ||
+ (sig != SIGCONT && ISSTATE (myself, PID_STOPPED))))
+ {
+ sigproc_printf ("signal %d blocked", sig);
+ break;
+ }
+
+ /* Found a signal to process */
+ sigproc_printf ("processing signal %d", sig);
+ switch (sig)
+ {
+ case __SIGFLUSH:
+ /* just forcing the loop */
+ break;
+
+ /* Internal signal to turn on stracing. */
+ case __SIGSTRACE:
+ strace.hello ();
+ break;
+
+ case __SIGCOMMUNE:
+ talktome ();
+ break;
+
+ /* A normal UNIX signal */
+ default:
+ sigproc_printf ("Got signal %d", sig);
+ sig_handle (sig, rc != 2);
+ /* Need to decrement again to offset increment below since
+ we really do want to decrement in this case. */
+ InterlockedDecrement (myself->getsigtodo (sig));
+ goto nextsig; /* FIXME: shouldn't this allow the loop to continue? */
+ }
+ }
+
+ nextsig:
+ /* Decremented too far. */
+ if (InterlockedIncrement (myself->getsigtodo (sig)) > 0)
+ saw_pending_signals = 1;
+ }
+
+ if (pending_signals < 0 && !saw_pending_signals)
+ pending_signals = 0;
+
+ if (saw_sigchld)
+ proc_subproc (PROC_CLEARWAIT, 0);
+
+ /* Signal completion of signal handling depending on which semaphore
+ * woke up the WaitForMultipleObjects above.
+ */
+ switch (rc)
+ {
+ case 0:
+ SetEvent (sigcomplete_main);
+ sigproc_printf ("set main thread completion event");
+ break;
+ case 1:
+ ReleaseSemaphore (sigcomplete_nonmain, 1, NULL);
+ break;
+ default:
+ /* Signal from another process. No need to synchronize. */
+ break;
+ }
+ sigproc_printf ("looping");
+ }
+
+ sigproc_printf ("done");
+ ExitThread (0);
+}
+
+/* Wait for subprocesses to terminate. Executes in a separate thread. */
+static DWORD WINAPI
+wait_subproc (VOID *)
+{
+ sigproc_printf ("starting");
+ int errloop = 0;
+
+ for (;;)
+ {
+ DWORD rc = WaitForMultipleObjects (nchildren + 1, events, FALSE,
+ proc_loop_wait);
+ if (rc == WAIT_TIMEOUT)
+ if (!proc_loop_wait)
+ break; // Exiting
+ else
+ continue;
+
+ if (rc == WAIT_FAILED)
+ {
+ if (!proc_loop_wait)
+ break;
+
+ /* It's ok to get an ERROR_INVALID_HANDLE since another thread may have
+ closed a handle in the children[] array. So, we try looping a couple
+ of times to stabilize. FIXME - this is not foolproof. Probably, this
+ thread should be responsible for closing the children. */
+ if (!errloop++)
+ proc_subproc (PROC_NOTHING, 0); // Just synchronize and continue
+ if (errloop < 10)
+ continue;
+
+ system_printf ("wait failed. nchildren %d, wait %d, %E",
+ nchildren, proc_loop_wait);
+
+ for (int i = 0; i <= nchildren; i++)
+ if ((rc = WaitForSingleObject (events[i], 0)) == WAIT_OBJECT_0 ||
+ rc == WAIT_TIMEOUT)
+ continue;
+ else if (i == 0)
+ system_printf ("nchildren %d, event[%d] %p, %E", nchildren, i, events[i]);
+ else
+ {
+ system_printf ("nchildren %d, event[%d] %p, pchildren[%d] %p, events[0] %p, %E",
+ nchildren, i, events[i], i - 1, (_pinfo *) pchildren[i - 1], events[0]);
+ system_printf ("pid %d, dwProcessId %u, hProcess %p, progname '%s'",
+ pchildren[i - 1]->pid, pchildren[i - 1]->dwProcessId,
+ pchildren[i - 1]->hProcess, pchildren[i - 1]->progname);
+ }
+ break;
+ }
+
+ errloop = 0;
+ rc -= WAIT_OBJECT_0;
+ if (rc-- != 0)
+ {
+ rc = proc_subproc (PROC_CHILDTERMINATED, rc);
+ if (!proc_loop_wait) // Don't bother if wait_subproc is
+ break; // exiting
+
+ /* Send a SIGCHLD to myself. We do this here, rather than in proc_subproc
+ to avoid the proc_subproc lock since the signal thread will eventually
+ be calling proc_subproc and could unnecessarily block. */
+ if (rc)
+ sig_send (myself_nowait, SIGCHLD);
+ }
+ sigproc_printf ("looping");
+ }
+
+ ForceCloseHandle (events[0]);
+ events[0] = NULL;
+ sigproc_printf ("done");
+ ExitThread (0);
+}
+
+extern "C" {
+/* Provide a stack frame when calling WaitFor* functions */
+
+#undef WaitForSingleObject
+
+DWORD __stdcall
+WFSO (HANDLE hHandle, DWORD dwMilliseconds)
+{
+ DWORD ret;
+ sigframe thisframe (mainthread);
+ ret = WaitForSingleObject (hHandle, dwMilliseconds);
+ return ret;
+}
+
+#undef WaitForMultipleObjects
+
+DWORD __stdcall
+WFMO (DWORD nCount, CONST HANDLE *lpHandles, BOOL fWaitAll, DWORD dwMilliseconds)
+{
+ DWORD ret;
+ sigframe thisframe (mainthread);
+ ret = WaitForMultipleObjects (nCount, lpHandles, fWaitAll, dwMilliseconds);
+ return ret;
+}
+}
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index f6863e88d24..d9e7fbfe7bf 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -22,8 +22,8 @@ details. */
#include "cygerrno.h"
#include <sys/cygwin.h>
#include "security.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "sigproc.h"
#include "cygheap.h"
diff --git a/winsup/cygwin/strace.cc b/winsup/cygwin/strace.cc
index 38cf2590790..283f019141f 100644
--- a/winsup/cygwin/strace.cc
+++ b/winsup/cygwin/strace.cc
@@ -21,8 +21,8 @@ details. */
#include "hires.h"
#include "security.h"
#include "cygthread.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "cygerrno.h"
#include "cygheap.h"
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index 889d3cc698c..fea94f4f3c7 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -34,8 +34,8 @@ details. */
#include "cygerrno.h"
#include "perprocess.h"
#include "security.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "sigproc.h"
#include "pinfo.h"
@@ -58,6 +58,9 @@ SYSTEM_INFO system_info;
static int __stdcall mknod_worker (const char *, mode_t, mode_t, _major_t,
_minor_t);
+static int __stdcall stat_worker (const char *name, struct __stat64 *buf,
+ int nofollow) __attribute__ ((regparm (3)));
+
/* 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
@@ -532,22 +535,24 @@ open (const char *unix_path, int flags, ...)
if (fd >= 0)
{
- path_conv pc;
- if (!(fh = cygheap->fdtab.build_fhandler_from_name (fd, unix_path,
- NULL, pc)))
+ if (!(fh = build_fh_name (unix_path)))
res = -1; // errno already set
else if (fh->is_fs_special () && fh->device_access_denied (flags))
{
- fd.release ();
+ delete fh;
res = -1;
}
- else if (!fh->open (&pc, flags, (mode & 07777) & ~cygheap->umask))
+ else if (!fh->open (flags, (mode & 07777) & ~cygheap->umask))
{
- fd.release ();
+ delete fh;
res = -1;
}
- else if ((res = fd) <= 2)
- set_std_handle (res);
+ else
+ {
+ cygheap->fdtab[fd] = fh;
+ if ((res = fd) <= 2)
+ set_std_handle (res);
+ }
}
}
@@ -1032,9 +1037,8 @@ fstat64 (int fd, struct __stat64 *buf)
res = -1;
else
{
- path_conv pc (cfd->get_win32_name (), PC_SYM_NOFOLLOW);
memset (buf, 0, sizeof (struct __stat64));
- res = cfd->fstat (buf, &pc);
+ res = cfd->fstat (buf);
if (!res)
{
if (!buf->st_ino)
@@ -1095,36 +1099,29 @@ suffix_info stat_suffixes[] =
};
/* Cygwin internal */
-int __stdcall
-stat_worker (const char *name, struct __stat64 *buf, int nofollow,
- path_conv *pc)
+static int __stdcall
+stat_worker (const char *name, struct __stat64 *buf, int nofollow)
{
int res = -1;
- path_conv real_path;
fhandler_base *fh = NULL;
if (check_null_invalid_struct_errno (buf))
goto done;
- if (!pc)
- pc = &real_path;
-
- fh = cygheap->fdtab.build_fhandler_from_name (-1, name, NULL, *pc,
- (nofollow ? PC_SYM_NOFOLLOW
- : PC_SYM_FOLLOW)
- | PC_FULL, stat_suffixes);
+ fh = build_fh_name (name, NULL, (nofollow ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW)
+ | PC_FULL, stat_suffixes);
- if (pc->error)
+ if (fh->error ())
{
- debug_printf ("got %d error from build_fhandler_from_name", pc->error);
- set_errno (pc->error);
+ debug_printf ("got %d error from build_fh_name", fh->error ());
+ set_errno (fh->error ());
}
else
{
debug_printf ("(%s, %p, %d, %p), file_attributes %d", name, buf, nofollow,
- pc, (DWORD) real_path);
+ fh, (DWORD) *fh);
memset (buf, 0, sizeof (*buf));
- res = fh->fstat (buf, pc);
+ res = fh->fstat (buf);
if (!res)
{
if (!buf->st_ino)
diff --git a/winsup/cygwin/sysconf.cc b/winsup/cygwin/sysconf.cc
new file mode 100644
index 00000000000..608f1877671
--- /dev/null
+++ b/winsup/cygwin/sysconf.cc
@@ -0,0 +1,102 @@
+/* sysconf.cc
+
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include <unistd.h>
+#include <errno.h>
+#include <time.h>
+#include <limits.h>
+#include <ntdef.h>
+#include "security.h"
+#include "path.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "cygerrno.h"
+#include "cygheap.h"
+#include "ntdll.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:
+ return getdtablesize ();
+ case _SC_PAGESIZE:
+ return getpagesize ();
+ 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_LOGIN_NAME_MAX:
+ case _SC_GETPW_R_SIZE_MAX:
+ case _SC_GETGR_R_SIZE_MAX:
+ return 16*1024;
+ 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
+ case _SC_NPROCESSORS_CONF:
+ case _SC_NPROCESSORS_ONLN:
+ if (!wincap.supports_smp ())
+ return 1;
+ /*FALLTHRU*/
+ case _SC_PHYS_PAGES:
+ case _SC_AVPHYS_PAGES:
+ if (wincap.supports_smp ())
+ {
+ NTSTATUS ret;
+ SYSTEM_BASIC_INFORMATION sbi;
+ if ((ret = NtQuerySystemInformation (SystemBasicInformation,
+ (PVOID) &sbi,
+ sizeof sbi, NULL))
+ != STATUS_SUCCESS)
+ {
+ __seterrno_from_win_error (RtlNtStatusToDosError (ret));
+ debug_printf ("NtQuerySystemInformation: ret = %d, "
+ "Dos(ret) = %d",
+ ret, RtlNtStatusToDosError (ret));
+ return -1;
+ }
+ switch (in)
+ {
+ case _SC_NPROCESSORS_CONF:
+ return sbi.NumberProcessors;
+ case _SC_NPROCESSORS_ONLN:
+ return sbi.ActiveProcessors;
+ case _SC_PHYS_PAGES:
+ return sbi.NumberOfPhysicalPages;
+ case _SC_AVPHYS_PAGES:
+ return sbi.HighestPhysicalPage - sbi.LowestPhysicalPage + 1;
+ }
+ }
+ break;
+ }
+
+ /* 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 00000000000..7e358df3a51
--- /dev/null
+++ b/winsup/cygwin/syslog.cc
@@ -0,0 +1,412 @@
+/* syslog.cc
+
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include "security.h"
+#include "path.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "cygerrno.h"
+#include "cygheap.h"
+#include "thread.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 != NULL)
+ {
+ free (process_ident);
+ process_ident = 0;
+ }
+ if (ident)
+ {
+ process_ident = (char *) malloc (strlen (ident) + 1);
+ if (process_ident == NULL)
+ {
+ 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. */
+int
+setlogmask (int maskpri)
+{
+ if (maskpri == 0)
+ return process_logmask;
+
+ int old_mask = process_logmask;
+ process_logmask = maskpri & LOG_PRIMASK;
+
+ return old_mask;
+}
+
+/* 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_; }
+ void set_message (char *s) { message_ = s; *message_ = '\0'; }
+};
+
+pass_handler::pass_handler () : fp_ (0), message_ (0), total_len_ (0)
+{
+ ;
+}
+
+pass_handler::~pass_handler ()
+{
+ shutdown ();
+}
+
+void
+pass_handler::shutdown ()
+{
+ if (fp_ != NULL)
+ {
+ fclose (fp_);
+ fp_ = 0;
+ }
+}
+
+int
+pass_handler::initialize (int pass_number)
+{
+ shutdown ();
+ if (pass_number)
+ return total_len_ + 1;
+
+ fp_ = fopen ("/dev/null", "wb");
+ if (fp_ == NULL)
+ {
+ debug_printf ("failed to open /dev/null");
+ return -1;
+ }
+ total_len_ = 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_ != NULL)
+ {
+ int len = vfprintf (fp_, fmt, list);
+ if (len < 0)
+ return -1;
+ total_len_ += len;
+ return 0;
+ }
+ else if (message_ != NULL)
+ {
+ 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 = (char *) alloca (strlen (message) +
+ (errlen * numfound) + 1);
+
+ if (newmessage == NULL)
+ {
+ 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_EMERG:
+ case LOG_ALERT:
+ case LOG_CRIT:
+ case LOG_ERR:
+ eventType = EVENTLOG_ERROR_TYPE;
+ break;
+ case LOG_WARNING:
+ eventType = EVENTLOG_WARNING_TYPE;
+ break;
+ case LOG_NOTICE:
+ case LOG_INFO:
+ case LOG_DEBUG:
+ 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 :-).
+ */
+ va_list ap;
+
+ pass_handler pass;
+ for (int pass_number = 0; pass_number < 2; ++pass_number)
+ {
+ int n = pass.initialize (pass_number);
+ if (n == -1)
+ return;
+ else if (n > 0)
+ pass.set_message ((char *) alloca (n));
+
+ /* Deal with ident_string */
+ if (process_ident != NULL)
+ {
+ 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 (!wincap.has_eventlog ())
+ {
+ /* Add a priority string - not needed for systems with
+ eventlog capability. */
+ switch (LOG_PRI (priority))
+ {
+ case LOG_EMERG:
+ pass.print ("%s : ", "LOG_EMERG");
+ break;
+ case LOG_ALERT:
+ pass.print ("%s : ", "LOG_ALERT");
+ break;
+ case LOG_CRIT:
+ pass.print ("%s : ", "LOG_CRIT");
+ break;
+ case LOG_ERR:
+ pass.print ("%s : ", "LOG_ERR");
+ break;
+ case LOG_WARNING:
+ pass.print ("%s : ", "LOG_WARNING");
+ break;
+ case LOG_NOTICE:
+ pass.print ("%s : ", "LOG_NOTICE");
+ break;
+ case LOG_INFO:
+ pass.print ("%s : ", "LOG_INFO");
+ break;
+ case LOG_DEBUG:
+ pass.print ("%s : ", "LOG_DEBUG");
+ 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 (wincap.has_eventlog ())
+ {
+ /* For NT, open the event log and send the message */
+ HANDLE hEventSrc = RegisterEventSourceA (NULL, (process_ident != NULL) ?
+ process_ident : CYGWIN_LOG_NAME);
+ if (hEventSrc == NULL)
+ {
+ debug_printf ("RegisterEventSourceA failed with %E");
+ return;
+ }
+ ReportEventA (hEventSrc, eventType, 0, 0,
+ cygheap->user.sid (), 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 == NULL)
+ {
+ 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 = cygheap->fdtab[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
index ac1c89bf0a8..dc9933b0f05 100644
--- a/winsup/cygwin/termios.cc
+++ b/winsup/cygwin/termios.cc
@@ -17,8 +17,8 @@ details. */
#include <stdlib.h>
#include "cygerrno.h"
#include "security.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
#include "cygwin/version.h"
diff --git a/winsup/cygwin/times.cc b/winsup/cygwin/times.cc
new file mode 100644
index 00000000000..87b8c858981
--- /dev/null
+++ b/winsup/cygwin/times.cc
@@ -0,0 +1,665 @@
+/* times.cc
+
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include <time.h>
+#include <sys/times.h>
+#include <sys/timeb.h>
+#include <utime.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "cygerrno.h"
+#include "security.h"
+#include "path.h"
+#include "fhandler.h"
+#include "pinfo.h"
+#include "hires.h"
+
+#define FACTOR (0x19db1ded53e8000LL)
+#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", (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;
+
+ if (check_null_invalid_struct_errno (buf))
+ return ((clock_t) -1);
+
+ 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 (wincap.has_get_process_times ())
+ {
+ 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 *) __attribute__((alias ("times")));
+
+/* settimeofday: BSD */
+extern "C" int
+settimeofday (const struct timeval *tv, const struct timezone *tz)
+{
+ SYSTEMTIME st;
+ struct tm *ptm;
+ int res;
+
+ tz = tz; /* silence warning about unused variable */
+
+ ptm = gmtime (&tv->tv_sec);
+ st.wYear = ptm->tm_year + 1900;
+ st.wMonth = ptm->tm_mon + 1;
+ st.wDayOfWeek = ptm->tm_wday;
+ st.wDay = ptm->tm_mday;
+ st.wHour = ptm->tm_hour;
+ st.wMinute = ptm->tm_min;
+ st.wSecond = ptm->tm_sec;
+ st.wMilliseconds = tv->tv_usec / 1000;
+
+ res = !SetSystemTime (&st);
+
+ syscall_printf ("%d = settimeofday (%x, %x)", res, tv, tz);
+
+ return res;
+}
+
+/* timezone: standards? */
+extern "C" char *
+timezone ()
+{
+#ifdef _MT_SAFE
+ char *b=_reent_winsup ()->timezone_buf;
+#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);
+}
+
+/* FIXME: Make thread safe */
+extern "C" int
+gettimeofday (struct timeval *tv, struct timezone *tz)
+{
+ static hires_ms gtod;
+ static bool tzflag;
+ LONGLONG now = gtod.usecs (false);
+ if (now == (LONGLONG) -1)
+ return -1;
+
+ tv->tv_sec = now / 1000000;
+ tv->tv_usec = now % 1000000;
+
+ if (tz != NULL)
+ {
+ if (!tzflag)
+ {
+ tzset ();
+ tzflag = true;
+ }
+ tz->tz_minuteswest = _timezone / 60;
+ tz->tz_dsttime = _daylight;
+ }
+
+ return 0;
+}
+
+extern "C" int _gettimeofday (struct timeval *, struct timezone *)
+ __attribute__((alias ("gettimeofday")));
+
+/* 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 long x = ((long long) ptr->dwHighDateTime << 32) + ((unsigned)ptr->dwLowDateTime);
+
+ /* pass "no time" as epoch */
+ if (x == 0)
+ return 0;
+
+ x -= FACTOR; /* number of 100ns between 1601 and 1970 */
+ x /= (long long) NSPERSEC; /* number of 100ns in a second */
+ return x;
+}
+
+/* Cygwin internal */
+/* Convert a Win32 time to "UNIX" timestruc_t format. */
+void __stdcall
+to_timestruc_t (FILETIME *ptr, timestruc_t *out)
+{
+ /* A file time is the number of 100ns since jan 1 1601
+ stuffed into two long words.
+ A timestruc_t is the number of seconds and microseconds since jan 1 1970
+ stuffed into a time_t and a long. */
+
+ long rem;
+ long long x = ((long long) ptr->dwHighDateTime << 32) + ((unsigned)ptr->dwLowDateTime);
+
+ /* pass "no time" as epoch */
+ if (x == 0)
+ {
+ out->tv_sec = 0;
+ out->tv_nsec = 0;
+ return;
+ }
+
+ x -= FACTOR; /* number of 100ns between 1601 and 1970 */
+ rem = x % ((long long)NSPERSEC);
+ x /= (long long) NSPERSEC; /* number of 100ns in a second */
+ out->tv_nsec = rem * 100; /* as tv_nsec is in nanoseconds */
+ out->tv_sec = x;
+}
+
+/* Cygwin internal */
+/* Get the current time as a "UNIX" timestruc_t format. */
+void __stdcall
+time_as_timestruc_t (timestruc_t * out)
+{
+ SYSTEMTIME systemtime;
+ FILETIME filetime;
+
+ GetSystemTime (&systemtime);
+ SystemTimeToFileTime (&systemtime, &filetime);
+ to_timestruc_t (&filetime, out);
+}
+
+/* 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. */
+ /* Note: It's not documented in MSDN that FILE_WRITE_ATTRIBUTES is
+ sufficient to change the timestamps... */
+ HANDLE h = CreateFile (win32, FILE_WRITE_ATTRIBUTES,
+ 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 (win32.isdir ())
+ {
+ /* 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 ()
+{
+}
+
+void
+hires_us::prime ()
+{
+ LARGE_INTEGER ifreq;
+ if (!QueryPerformanceFrequency (&ifreq))
+ {
+ inited = -1;
+ return;
+ }
+
+ FILETIME f;
+ int priority = GetThreadPriority (GetCurrentThread ());
+ SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL);
+ if (!QueryPerformanceCounter (&primed_pc))
+ {
+ SetThreadPriority (GetCurrentThread (), priority);
+ inited = -1;
+ return;
+ }
+
+ GetSystemTimeAsFileTime (&f);
+ SetThreadPriority (GetCurrentThread (), priority);
+
+ inited = 1;
+ primed_ft.HighPart = f.dwHighDateTime;
+ primed_ft.LowPart = f.dwLowDateTime;
+ primed_ft.QuadPart -= FACTOR;
+ primed_ft.QuadPart /= 10;
+ freq = (double) ((double) 1000000. / (double) ifreq.QuadPart);
+ return;
+}
+
+LONGLONG
+hires_us::usecs (bool justdelta)
+{
+ if (!inited)
+ prime ();
+ if (inited < 0)
+ {
+ set_errno (ENOSYS);
+ return (long long) -1;
+ }
+
+ LARGE_INTEGER now;
+ if (!QueryPerformanceCounter (&now))
+ {
+ set_errno (ENOSYS);
+ return -1;
+ }
+
+ // FIXME: Use round() here?
+ now.QuadPart = (LONGLONG) (freq * (double) (now.QuadPart - primed_pc.QuadPart));
+ return justdelta ? now.QuadPart : primed_ft.QuadPart + now.QuadPart;
+}
+
+void
+hires_ms::prime ()
+{
+ TIMECAPS tc;
+ FILETIME f;
+ int priority = GetThreadPriority (GetCurrentThread ());
+ SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL);
+
+ if (timeGetDevCaps (&tc, sizeof (tc)) != TIMERR_NOERROR)
+ minperiod = 0;
+ else
+ {
+ minperiod = min (max (tc.wPeriodMin, 1), tc.wPeriodMax);
+ timeBeginPeriod (minperiod);
+ }
+
+ initime_ms = timeGetTime ();
+ GetSystemTimeAsFileTime (&f);
+ SetThreadPriority (GetCurrentThread (), priority);
+
+ inited = 1;
+ initime_us.HighPart = f.dwHighDateTime;
+ initime_us.LowPart = f.dwLowDateTime;
+ initime_us.QuadPart -= FACTOR;
+ initime_us.QuadPart /= 10;
+}
+
+LONGLONG
+hires_ms::usecs (bool justdelta)
+{
+ if (!inited)
+ prime ();
+ DWORD now = timeGetTime ();
+ // FIXME: Not sure how this will handle the 49.71 day wrap around
+ LONGLONG res = initime_us.QuadPart + ((LONGLONG) (now - initime_ms) * 1000);
+ return res;
+}
+
+hires_ms::~hires_ms ()
+{
+ timeEndPeriod (minperiod);
+}
diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc
index aaabdd509c0..b9417d18da9 100644
--- a/winsup/cygwin/tty.cc
+++ b/winsup/cygwin/tty.cc
@@ -17,8 +17,8 @@ details. */
#include <sys/cygwin.h>
#include "cygerrno.h"
#include "security.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
#include "pinfo.h"
@@ -75,8 +75,7 @@ create_tty_master (int ttynum)
{
device ttym = *ttym_dev;
ttym.setunit (ttynum); /* CGF FIXME device */
- tty_master = (fhandler_tty_master *)
- cygheap->fdtab.build_fhandler (-1, ttym, "/dev/ttym", NULL);
+ tty_master = (fhandler_tty_master *) build_fh_dev (ttym);
if (tty_master->init ())
api_fatal ("Can't create master tty");
else
diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc
index cb620d8f48d..1bde7086d58 100644
--- a/winsup/cygwin/uinfo.cc
+++ b/winsup/cygwin/uinfo.cc
@@ -21,8 +21,8 @@ details. */
#include <sys/cygwin.h>
#include "pinfo.h"
#include "security.h"
-#include "fhandler.h"
#include "path.h"
+#include "fhandler.h"
#include "dtable.h"
#include "cygerrno.h"
#include "cygheap.h"
diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h
index a2b54199fd7..fc6a06fd922 100644
--- a/winsup/cygwin/winsup.h
+++ b/winsup/cygwin/winsup.h
@@ -238,10 +238,6 @@ extern "C" int __small_sprintf (char *dst, const char *fmt, ...) /*__attribute__
extern "C" int __small_vsprintf (char *dst, const char *fmt, va_list ap) /*__attribute__ ((regparm (3)))*/;
extern void multiple_cygwin_problem (const char *, unsigned, unsigned);
-class path_conv;
-int __stdcall stat_worker (const char *name, struct __stat64 *buf, int nofollow,
- path_conv *pc = NULL) __attribute__ ((regparm (3)));
-
int symlink_worker (const char *, const char *, bool, bool)
__attribute__ ((regparm (3)));