diff options
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))); |