diff options
49 files changed, 1725 insertions, 933 deletions
diff --git a/winsup/cygwin/ChangeLog.branch b/winsup/cygwin/ChangeLog.branch index 3095997e39d..53554a274ec 100644 --- a/winsup/cygwin/ChangeLog.branch +++ b/winsup/cygwin/ChangeLog.branch @@ -1,3 +1,48 @@ +2003-09-09 Christopher Faylor <cgf@redhat.com> + + * exceptions.cc (sig_handle_tty_stop): Check parent PID_NOCLDSTOP + rather than erroneously checking *my own* sigtodo. + (set_process_mask): Remove pending_signals setting. + (sig_handle): Per SUSv3 allow any SIGCONT to clear stopped signals and + continue execution. Accept a mask argument. + * pinfo.h: Remove signal enums. + (_pinfo::getsigmask): Simplify for now. + (_pinfo::setsigmask): Ditto. + (_pinfo::getsigtodo): Ditto. + (_pinfo::setthread2signal): Ditto. + (_pinfo::sendsig): New variable. + (_pinfo::sigtodo): Eliminate. + * signal.cc (kill_worker): Remove reference to thread2signal. + * sigproc.cc: Massive signal handling rewrite. + (sigelem): New class. + (pending_signals): Ditto. + (sigqueue): New variable. + (sigcatch_nonmain): Delete. + (sigcatch_main): Ditto. + (sigcatch_nosync): Ditto. + (pending_signals): Delete variable. + (sig_clear): Send negative signal to signal thread to clear it. + (sigpending): Send __SIGPENDING signal to signal thread to have it fill + out pending signal mask. + (sig_dispatch_pending): Check sigqueue.next flag to determine if + anything queued. + (sigproc_terminate): Remove semaphore stuff. Just close write side of + signal pipe. + (sig_send): Rewrite to use new signal pipe stuff. + (wait_sig): Ditto. + (sig_set_pending): Delete. + (getevent): Delete. + (pending_signals::add): New function. + (pending_signals::del): Ditto. + (pending_signals::next): Ditto. + * sigproc.h: Move signal enum here. + (sig_dispatch_pending): Make this a standard c++ function rather than a + "C" function. + (sig_handle): Accept an extra argument. + * thread.cc (pthread::thread_init_wrapper): Remove nonsensical setting + of sigtodo to a local array (!?!). + (pthread_kill): Comment out calls to setthread2signal. + 2003-03-19 Christopher Faylor <cgf@redhat.com> * dtable.cc (cygwin_attach_handle_to_fd): Eliminate unused variable. diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in index d0fc32c7c40..30a75226550 100644 --- a/winsup/cygwin/Makefile.in +++ b/winsup/cygwin/Makefile.in @@ -74,6 +74,10 @@ fhandler_tty_CFLAGS:=-fomit-frame-pointer fhandler_virtual_CFLAGS:=-fomit-frame-pointer fhandler_windows_CFLAGS:=-fomit-frame-pointer fhandler_zero_CFLAGS:=-fomit-frame-pointer +regcomp_CFLAGS=-fomit-frame-pointer +regerror_CFLAGS=-fomit-frame-pointer +regexec_CFLAGS=-fomit-frame-pointer +regfree_CFLAGS=-fomit-frame-pointer CC:=@CC@ # FIXME: Which is it, CC or CC_FOR_TARGET? @@ -144,9 +148,9 @@ DLL_IMPORTS:=$(w32api_lib)/libkernel32.a MT_SAFE_OBJECTS:= # Please maintain this list in sorted order, with maximum files per 80 col line -DLL_OFILES:=assert.o autoload.o cxx.o cygheap.o cygthread.o dcrt0.o debug.o \ - delqueue.o devices.o dir.o dlfcn.o dll_init.o dtable.o environ.o errno.o \ - exceptions.o exec.o external.o fcntl.o fhandler.o \ +DLL_OFILES:=assert.o autoload.o cxx.o bsdlib.o cygheap.o cygthread.o dcrt0.o \ + debug.o delqueue.o devices.o dir.o dlfcn.o dll_init.o dtable.o environ.o \ + errno.o exceptions.o exec.o external.o fcntl.o fhandler.o \ fhandler_clipboard.o fhandler_console.o fhandler_disk_file.o \ fhandler_dsp.o fhandler_fifo.o fhandler_floppy.o fhandler_mem.o \ fhandler_nodevice.o fhandler_proc.o fhandler_process.o \ diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc index c2c7ae3528b..6344a6d0c14 100644 --- a/winsup/cygwin/autoload.cc +++ b/winsup/cygwin/autoload.cc @@ -509,6 +509,7 @@ LoadDLLfuncEx2 (IsDebuggerPresent, 0, kernel32, 1, 1) LoadDLLfunc (IsProcessorFeaturePresent, 4, kernel32); LoadDLLfuncEx (Process32First, 8, kernel32, 1) LoadDLLfuncEx (Process32Next, 8, kernel32, 1) +LoadDLLfuncEx (RegisterServiceProcess, 8, kernel32, 1) LoadDLLfuncEx (SignalObjectAndWait, 16, kernel32, 1) LoadDLLfuncEx (SwitchToThread, 0, kernel32, 1) LoadDLLfunc (TryEnterCriticalSection, 4, kernel32) diff --git a/winsup/cygwin/cxx.cc b/winsup/cygwin/cxx.cc new file mode 100644 index 00000000000..9cc1342fe89 --- /dev/null +++ b/winsup/cygwin/cxx.cc @@ -0,0 +1,46 @@ +/* cxx.cc + + Copyright 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. */ + +#if (__GNUC__ >= 3) + +#include "winsup.h" +#include <stdlib.h> + +void * +operator new (size_t s) +{ + void *p = calloc (1, s); + return p; +} + +void +operator delete (void *p) +{ + free (p); +} + +void * +operator new[] (size_t s) +{ + return ::operator new (s); +} + +void +operator delete[] (void *p) +{ + ::operator delete (p); +} + +extern "C" void +__cxa_pure_virtual (void) +{ + api_fatal ("pure virtual method called"); +} +#endif diff --git a/winsup/cygwin/cygheap.cc b/winsup/cygwin/cygheap.cc index f681a5ca2b3..f87cfc41527 100644 --- a/winsup/cygwin/cygheap.cc +++ b/winsup/cygwin/cygheap.cc @@ -179,14 +179,14 @@ _csbrk (int sbs) { void *prebrk = cygheap_max; void *prebrka = pagetrunc (prebrk); - (char *) cygheap_max += sbs; + cygheap_max = (char *) cygheap_max + sbs; if (!sbs || (prebrk != prebrka && prebrka == pagetrunc (cygheap_max))) /* nothing to do */; else if (!VirtualAlloc (prebrk, (DWORD) sbs, MEM_COMMIT, PAGE_READWRITE)) { malloc_printf ("couldn't commit memory for cygwin heap, %E"); __seterrno (); - (char *) cygheap_max -= sbs; + cygheap_max = (char *) cygheap_max - sbs; return NULL; } diff --git a/winsup/cygwin/cygheap.h b/winsup/cygwin/cygheap.h index 6939507a53c..a06ee9260b0 100644 --- a/winsup/cygwin/cygheap.h +++ b/winsup/cygwin/cygheap.h @@ -259,7 +259,7 @@ struct init_cygheap struct sigaction *sigs; }; -#define CYGHEAPSIZE (sizeof (init_cygheap) + (16000 * sizeof (fhandler_union)) + (5 * 65536)) +#define CYGHEAPSIZE (sizeof (init_cygheap) + (20000 * sizeof (fhandler_union)) + (5 * 65536)) extern init_cygheap *cygheap; extern void *cygheap_max; diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din index 85840137abd..227d13569b4 100644 --- a/winsup/cygwin/cygwin.din +++ b/winsup/cygwin/cygwin.din @@ -141,6 +141,30 @@ alarm _alarm = alarm alphasort _alphasort = alphasort +argz_add +__argz_add = argz_add +argz_add_sep +__argz_add_sep = argz_add_sep +argz_append +__argz_append = argz_append +argz_count +__argz_count = argz_count +argz_create +__argz_create = argz_create +argz_create_sep +__argz_create_sep = argz_create_sep +argz_delete +__argz_delete = argz_delete +argz_extract +__argz_extract = argz_extract +argz_insert +__argz_insert = argz_insert +argz_next +__argz_next = argz_next +argz_replace +__argz_replace = argz_replace +argz_stringify +__argz_stringify = argz_stringify asctime _asctime = asctime asctime_r @@ -265,6 +289,7 @@ cygwin32_detach_dll = cygwin_detach_dll cygwin_dll_init endprotoent = cygwin_endprotoent endservent = cygwin_endservent +endusershell gethostbyaddr = cygwin_gethostbyaddr gethostbyname = cygwin_gethostbyname _gethostname = cygwin_gethostname @@ -278,6 +303,7 @@ getservbyport = cygwin_getservbyport getservent = cygwin_getservent getsockname = cygwin_getsockname getsockopt = cygwin_getsockopt +getusershell herror = cygwin_herror hstrerror = cygwin_hstrerror inet_addr = cygwin_inet_addr @@ -311,6 +337,7 @@ cygwin_set_impersonation_token setprotoent = cygwin_setprotoent setservent = cygwin_setservent setsockopt = cygwin_setsockopt +setusershell shutdown = cygwin_shutdown socket = cygwin_socket cygwin_split_path @@ -323,6 +350,7 @@ cygwin_win32_to_posix_path_list_buf_size cygwin32_win32_to_posix_path_list_buf_size = cygwin_win32_to_posix_path_list_buf_size cygwin_winpid_to_pid cygwin32_winpid_to_pid = cygwin_winpid_to_pid +daemon difftime _difftime = difftime dirfd @@ -362,6 +390,18 @@ endpwent _endpwent = endpwent endutent _endutent = endutent +envz_add +__envz_add = envz_add +envz_entry +__envz_entry = envz_entry +envz_get +__envz_get = envz_get +envz_merge +__envz_merge = envz_merge +envz_remove +__envz_remove = envz_remove +envz_strip +__envz_strip = envz_strip erand48 _erand48 = erand48 erf @@ -470,6 +510,7 @@ _fopen = fopen _fopen64 = fopen64 fork _fork = fork +forkpty fpathconf fprintf _fprintf = fprintf @@ -777,7 +818,10 @@ _logbf = logbf logf _logf = logf login +login_tty logout +logwtmp +updwtmp longjmp _longjmp = longjmp lrand48 @@ -878,6 +922,7 @@ opendir _opendir = opendir openlog _openlog = openlog +openpty pathconf _pathconf = pathconf pause @@ -1022,6 +1067,7 @@ remquo remquof rename _rename = rename +revoke rewind _rewind = rewind rewinddir diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index afaeff08805..20b2460bb38 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -521,6 +521,7 @@ alloc_stack (child_info_fork *ci) } static NO_COPY int mypid = 0; +int __argc_safe; int _declspec(dllexport) __argc; char _declspec(dllexport) **__argv; vfork_save NO_COPY *main_vfork = NULL; @@ -722,6 +723,7 @@ dll_crt0_1 () } } + __argc_safe = __argc; if (user_data->premain[0]) for (unsigned int i = 0; i < PREMAIN_LEN / 2; i++) user_data->premain[i] (__argc, __argv, user_data); diff --git a/winsup/cygwin/dir.cc b/winsup/cygwin/dir.cc index 88a1689e6fd..902746edf6f 100644 --- a/winsup/cygwin/dir.cc +++ b/winsup/cygwin/dir.cc @@ -71,6 +71,14 @@ dirfd (DIR *dir) return dir->__d_dirent->d_fd; } +enum opendir_states +{ + opendir_ok = 0, + opendir_saw_dot = 1, + opendir_saw_dot_dot = 2, + opendir_saw_eof = 4 +}; + /* opendir: POSIX 5.1.2.1 */ extern "C" DIR * opendir (const char *name) @@ -89,7 +97,9 @@ opendir (const char *name) res = NULL; } - if (!res && fh) + if (res) + res->__flags = 0; + else if (fh) delete fh; return res; } @@ -108,7 +118,23 @@ readdir (DIR *dir) return NULL; } - dirent *res = ((fhandler_base *) dir->__d_u.__d_data.__fh)->readdir (dir); + dirent *res = ((fhandler_base *) dir->__fh)->readdir (dir); + + if (!res) + { + if (!(dir->__flags & opendir_saw_dot)) + { + res = dir->__d_dirent; + strcpy (res->d_name, "."); + dir->__flags |= opendir_saw_dot; + } + else if (!(dir->__flags & opendir_saw_dot_dot)) + { + res = dir->__d_dirent; + strcpy (res->d_name, ".."); + dir->__flags |= opendir_saw_dot_dot; + } + } if (res) { @@ -117,11 +143,15 @@ readdir (DIR *dir) if (res->d_name[0] == '.') { if (res->d_name[1] == '\0') - dir->__d_dirent->d_ino = dir->__d_dirhash; + { + dir->__d_dirent->d_ino = dir->__d_dirhash; + dir->__flags |= opendir_saw_dot; + } else if (res->d_name[1] != '.' || res->d_name[2] != '\0') goto hashit; else { + dir->__flags |= opendir_saw_dot_dot; char *p, up[strlen (dir->__d_dirname) + 1]; strcpy (up, dir->__d_dirname); if (!(p = strrchr (up, '\\'))) @@ -142,8 +172,8 @@ readdir (DIR *dir) __ino64_t dino = hash_path_name (dir->__d_dirhash, "\\"); dir->__d_dirent->d_ino = hash_path_name (dino, res->d_name); } + res->__ino32 = dir->__d_dirent->d_ino; // for legacy applications } - dir->__d_dirent->old_d_ino = dir->__d_dirent->d_ino; // just truncate return res; } @@ -155,7 +185,7 @@ telldir64 (DIR *dir) if (dir->__d_cookie != __DIRENT_COOKIE) return 0; - return ((fhandler_base *) dir->__d_u.__d_data.__fh)->telldir (dir); + return ((fhandler_base *) dir->__fh)->telldir (dir); } /* telldir */ @@ -173,7 +203,8 @@ seekdir64 (DIR *dir, _off64_t loc) if (dir->__d_cookie != __DIRENT_COOKIE) return; - return ((fhandler_base *) dir->__d_u.__d_data.__fh)->seekdir (dir, loc); + dir->__flags = 0; + return ((fhandler_base *) dir->__fh)->seekdir (dir, loc); } /* seekdir */ @@ -192,7 +223,8 @@ rewinddir (DIR *dir) if (dir->__d_cookie != __DIRENT_COOKIE) return; - return ((fhandler_base *) dir->__d_u.__d_data.__fh)->rewinddir (dir); + dir->__flags = 0; + return ((fhandler_base *) dir->__fh)->rewinddir (dir); } /* closedir: POSIX 5.1.2.1 */ @@ -212,7 +244,7 @@ closedir (DIR *dir) /* 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); + int res = ((fhandler_base *) dir->__fh)->closedir (dir); cygheap->fdtab.release (dir->__d_dirent->d_fd); diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index c63ed20584e..48699b14d54 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -11,12 +11,14 @@ details. */ #include "winsup.h" #include <imagehlp.h> #include <stdlib.h> +#include <setjmp.h> #include "exceptions.h" #include "sync.h" #include "sigproc.h" #include "pinfo.h" #include "cygerrno.h" +#define NEED_VFORK #include "perthread.h" #include "shared_info.h" #include "perprocess.h" @@ -611,14 +613,13 @@ sig_handle_tty_stop (int sig) if (my_parent_is_alive ()) { pinfo parent (myself->ppid); - if (!(parent->getsig (SIGCHLD).sa_flags & SA_NOCLDSTOP)) + if (NOTSTATE (parent, PID_NOCLDSTOP)) sig_send (parent, SIGCHLD); } sigproc_printf ("process %d stopped by signal %d, myself->ppid_handle %p", myself->pid, sig, myself->ppid_handle); if (WaitForSingleObject (sigCONT, INFINITE) != WAIT_OBJECT_0) api_fatal ("WaitSingleObject failed, %E"); - (void) ResetEvent (sigCONT); return; } } @@ -963,7 +964,7 @@ set_process_mask (sigset_t newmask) sigproc_printf ("old mask = %x, new mask = %x", myself->getsigmask (), newmask); myself->setsigmask (newmask); // Set a new mask mask_sync->release (); - if (oldmask != newmask) + if (oldmask & ~newmask) sig_dispatch_pending (); else sigproc_printf ("not calling sig_dispatch_pending. sigtid %p current %p", @@ -972,12 +973,33 @@ set_process_mask (sigset_t newmask) } int __stdcall -sig_handle (int sig) +sig_handle (int sig, sigset_t mask) { - int rc = 1; + if (sig == SIGCONT) + { + DWORD stopped = myself->process_state & PID_STOPPED; + myself->stopsig = 0; + myself->process_state &= ~PID_STOPPED; + /* Clear pending stop signals */ + sig_clear (SIGSTOP); + sig_clear (SIGTSTP); + sig_clear (SIGTTIN); + sig_clear (SIGTTOU); + if (stopped) + SetEvent (sigCONT); + } - sigproc_printf ("signal %d", sig); + if (sig != SIGKILL && sig != SIGSTOP + && (sigismember (&mask, sig) || main_vfork->pid + || ISSTATE (myself, PID_STOPPED))) + { + sigproc_printf ("signal %d blocked", sig); + return -1; + } + int rc = 1; + + sigproc_printf ("signal %d processing", sig); struct sigaction thissig = myself->getsig (sig); void *handler = (void *) thissig.sa_handler; @@ -993,25 +1015,6 @@ sig_handle (int sig) if (sig == SIGSTOP) goto stop; - /* FIXME: Should we still do this if SIGCONT has a handler? */ - if (sig == SIGCONT) - { - DWORD stopped = myself->process_state & PID_STOPPED; - myself->stopsig = 0; - myself->process_state &= ~PID_STOPPED; - /* Clear pending stop signals */ - sig_clear (SIGSTOP); - sig_clear (SIGTSTP); - sig_clear (SIGTTIN); - sig_clear (SIGTTOU); - if (stopped) - SetEvent (sigCONT); - /* process pending signals */ -#if 0 // FIXME? - sig_dispatch_pending (); -#endif - } - #if 0 char sigmsg[24]; __small_sprintf (sigmsg, "cygwin: signal %d\n", sig); @@ -1044,23 +1047,23 @@ sig_handle (int sig) goto dosig; - stop: +stop: /* Eat multiple attempts to STOP */ if (ISSTATE (myself, PID_STOPPED)) goto done; handler = (void *) sig_handle_tty_stop; thissig = myself->getsig (SIGSTOP); - dosig: +dosig: /* Dispatch to the appropriate function. */ sigproc_printf ("signal %d, about to call %p", sig, handler); rc = setup_handler (sig, handler, thissig); - done: +done: sigproc_printf ("returning %d", rc); return rc; - exit_sig: +exit_sig: if (sig == SIGQUIT || sig == SIGABRT) { CONTEXT c; diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc index 9ecc9edda5c..34f4c531ed7 100644 --- a/winsup/cygwin/fhandler.cc +++ b/winsup/cygwin/fhandler.cc @@ -207,7 +207,7 @@ fhandler_base::set_flags (int flags, int supplied_bin) void fhandler_base::raw_read (void *ptr, size_t& ulen) { -#define bytes_read ((ssize_t) ulen) +#define bytes_read ulen HANDLE h = NULL; /* grumble */ int prio = 0; /* ditto */ @@ -253,13 +253,13 @@ fhandler_base::raw_read (void *ptr, size_t& ulen) if (openflags & O_DIROPEN) { set_errno (EISDIR); - bytes_read = -1; + bytes_read = (size_t) -1; break; } default: syscall_printf ("ReadFile %s failed, %E", get_name ()); __seterrno_from_win_error (errcode); - bytes_read = -1; + bytes_read = (size_t) -1; break; } } diff --git a/winsup/cygwin/fhandler_console.cc b/winsup/cygwin/fhandler_console.cc index 9409cddd4ee..d85da9e6b5a 100644 --- a/winsup/cygwin/fhandler_console.cc +++ b/winsup/cygwin/fhandler_console.cc @@ -507,12 +507,12 @@ fhandler_console::read (void *pv, size_t& buflen) err: __seterrno (); - (ssize_t) buflen = -1; + buflen = (size_t) -1; return; - sig_exit: +sig_exit: set_sig_errno (EINTR); - (ssize_t) buflen = -1; + buflen = (size_t) -1; return; } diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc index 5495e889a7b..b034e1f54de 100644 --- a/winsup/cygwin/fhandler_disk_file.cc +++ b/winsup/cygwin/fhandler_disk_file.cc @@ -612,7 +612,7 @@ fhandler_disk_file::opendir () fd = this; fd->set_nohandle (true); dir->__d_dirent->d_fd = fd; - dir->__d_u.__d_data.__fh = this; + dir->__fh = this; /* FindFirstFile doesn't seem to like duplicate /'s. */ len = strlen (dir->__d_dirname); if (len == 0 || isdirsep (dir->__d_dirname[len - 1])) @@ -620,7 +620,7 @@ fhandler_disk_file::opendir () else strcat (dir->__d_dirname, "\\*"); /**/ dir->__d_cookie = __DIRENT_COOKIE; - dir->__d_u.__d_data.__handle = INVALID_HANDLE_VALUE; + dir->__handle = INVALID_HANDLE_VALUE; dir->__d_position = 0; dir->__d_dirhash = get_namehash (); @@ -641,25 +641,25 @@ fhandler_disk_file::readdir (DIR *dir) HANDLE handle; struct dirent *res = NULL; - if (dir->__d_u.__d_data.__handle == INVALID_HANDLE_VALUE + if (dir->__handle == INVALID_HANDLE_VALUE && dir->__d_position == 0) { handle = FindFirstFileA (dir->__d_dirname, &buf); DWORD lasterr = GetLastError (); - dir->__d_u.__d_data.__handle = handle; + dir->__handle = handle; if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) { seterrno_from_win_error (__FILE__, __LINE__, lasterr); return res; } } - else if (dir->__d_u.__d_data.__handle == INVALID_HANDLE_VALUE) + else if (dir->__handle == INVALID_HANDLE_VALUE) return res; - else if (!FindNextFileA (dir->__d_u.__d_data.__handle, &buf)) + else if (!FindNextFileA (dir->__handle, &buf)) { DWORD lasterr = GetLastError (); - (void) FindClose (dir->__d_u.__d_data.__handle); - dir->__d_u.__d_data.__handle = INVALID_HANDLE_VALUE; + (void) FindClose (dir->__handle); + dir->__handle = INVALID_HANDLE_VALUE; /* POSIX says you shouldn't set errno when readdir can't find any more files; so, if another error we leave it set. */ if (lasterr != ERROR_NO_MORE_FILES) @@ -716,10 +716,10 @@ fhandler_disk_file::seekdir (DIR *dir, _off64_t loc) void fhandler_disk_file::rewinddir (DIR *dir) { - if (dir->__d_u.__d_data.__handle != INVALID_HANDLE_VALUE) + if (dir->__handle != INVALID_HANDLE_VALUE) { - (void) FindClose (dir->__d_u.__d_data.__handle); - dir->__d_u.__d_data.__handle = INVALID_HANDLE_VALUE; + (void) FindClose (dir->__handle); + dir->__handle = INVALID_HANDLE_VALUE; } dir->__d_position = 0; } @@ -728,8 +728,8 @@ int fhandler_disk_file::closedir (DIR *dir) { int res = 0; - if (dir->__d_u.__d_data.__handle != INVALID_HANDLE_VALUE && - FindClose (dir->__d_u.__d_data.__handle) == 0) + if (dir->__handle != INVALID_HANDLE_VALUE && + FindClose (dir->__handle) == 0) { __seterrno (); res = -1; @@ -747,12 +747,9 @@ fhandler_cygdrive::fhandler_cygdrive () : void fhandler_cygdrive::set_drives () { - const int len = 1 + 26 * DRVSZ; + const int len = 2 + 26 * DRVSZ; char *p = const_cast<char *> (get_win32_name ()); pdrive = p; - strcpy (p, "."); - strcpy (p + sizeof ("."), ".."); - p += sizeof (".") + sizeof (".."); ndrives = GetLogicalDriveStrings (len, p) / DRVSZ; } diff --git a/winsup/cygwin/fhandler_mem.cc b/winsup/cygwin/fhandler_mem.cc index 883412f2f7f..70a36371c0a 100644 --- a/winsup/cygwin/fhandler_mem.cc +++ b/winsup/cygwin/fhandler_mem.cc @@ -185,7 +185,7 @@ fhandler_dev_mem::read (void *ptr, size_t& ulen) if (!(get_access () & GENERIC_READ)) { set_errno (EINVAL); - (ssize_t) ulen = -1; + ulen = (size_t) -1; return; } @@ -210,7 +210,7 @@ fhandler_dev_mem::read (void *ptr, size_t& ulen) PAGE_READONLY)) != STATUS_SUCCESS) { __seterrno_from_win_error (RtlNtStatusToDosError (ret)); - (ssize_t) ulen = -1; + ulen = (size_t) -1; return; } @@ -219,7 +219,7 @@ fhandler_dev_mem::read (void *ptr, size_t& ulen) if (!NT_SUCCESS (ret = NtUnmapViewOfSection (INVALID_HANDLE_VALUE, viewmem))) { __seterrno_from_win_error (RtlNtStatusToDosError (ret)); - (ssize_t) ulen = -1; + ulen = (size_t) -1; return; } diff --git a/winsup/cygwin/fhandler_random.cc b/winsup/cygwin/fhandler_random.cc index 55953348f6e..5117ba9f033 100644 --- a/winsup/cygwin/fhandler_random.cc +++ b/winsup/cygwin/fhandler_random.cc @@ -119,7 +119,7 @@ fhandler_dev_random::read (void *ptr, size_t& len) if (!ptr) { set_errno (EINVAL); - (ssize_t) len = -1; + len = (size_t) -1; return; } @@ -136,7 +136,7 @@ fhandler_dev_random::read (void *ptr, size_t& len) } __seterrno (); - (ssize_t) len = -1; + len = (size_t) -1; } _off64_t diff --git a/winsup/cygwin/fhandler_raw.cc b/winsup/cygwin/fhandler_raw.cc index eae73ed7bfc..38ef837d0e1 100644 --- a/winsup/cygwin/fhandler_raw.cc +++ b/winsup/cygwin/fhandler_raw.cc @@ -329,11 +329,11 @@ fhandler_dev_raw::raw_read (void *ptr, size_t& ulen) } } - (ssize_t) ulen = bytes_read; + ulen = (size_t) bytes_read; return; err: - (ssize_t) ulen = -1; + ulen = (size_t) -1; return; } diff --git a/winsup/cygwin/fhandler_registry.cc b/winsup/cygwin/fhandler_registry.cc index 42c87e3540b..e9bc37edffd 100644 --- a/winsup/cygwin/fhandler_registry.cc +++ b/winsup/cygwin/fhandler_registry.cc @@ -291,13 +291,13 @@ fhandler_registry::readdir (DIR * dir) res = dir->__d_dirent; goto out; } - if (dir->__d_u.__d_data.__handle == INVALID_HANDLE_VALUE + if (dir->__handle == INVALID_HANDLE_VALUE && dir->__d_position == 0) { handle = open_key (path + 1, KEY_READ, false); - dir->__d_u.__d_data.__handle = handle; + dir->__handle = handle; } - if (dir->__d_u.__d_data.__handle == INVALID_HANDLE_VALUE) + if (dir->__handle == INVALID_HANDLE_VALUE) goto out; if (dir->__d_position < SPECIAL_DOT_FILE_COUNT) { @@ -311,12 +311,12 @@ retry: /* For the moment, the type of key is ignored here. when write access is added, * maybe add an extension for the type of each value? */ - error = RegEnumValue ((HKEY) dir->__d_u.__d_data.__handle, + error = RegEnumValue ((HKEY) dir->__handle, (dir->__d_position & ~REG_ENUM_VALUES_MASK) >> 16, buf, &buf_size, NULL, NULL, NULL, NULL); else error = - RegEnumKeyEx ((HKEY) dir->__d_u.__d_data.__handle, dir->__d_position - + RegEnumKeyEx ((HKEY) dir->__handle, dir->__d_position - SPECIAL_DOT_FILE_COUNT, buf, &buf_size, NULL, NULL, NULL, NULL); if (error == ERROR_NO_MORE_ITEMS @@ -329,8 +329,8 @@ retry: } if (error != ERROR_SUCCESS && error != ERROR_MORE_DATA) { - RegCloseKey ((HKEY) dir->__d_u.__d_data.__handle); - dir->__d_u.__d_data.__handle = INVALID_HANDLE_VALUE; + RegCloseKey ((HKEY) dir->__handle); + dir->__handle = INVALID_HANDLE_VALUE; if (error != ERROR_NO_MORE_ITEMS) seterrno_from_win_error (__FILE__, __LINE__, error); goto out; @@ -372,10 +372,10 @@ fhandler_registry::seekdir (DIR * dir, _off64_t loc) void fhandler_registry::rewinddir (DIR * dir) { - if (dir->__d_u.__d_data.__handle != INVALID_HANDLE_VALUE) + if (dir->__handle != INVALID_HANDLE_VALUE) { - (void) RegCloseKey ((HKEY) dir->__d_u.__d_data.__handle); - dir->__d_u.__d_data.__handle = INVALID_HANDLE_VALUE; + (void) RegCloseKey ((HKEY) dir->__handle); + dir->__handle = INVALID_HANDLE_VALUE; } dir->__d_position = 0; return; @@ -385,8 +385,8 @@ int fhandler_registry::closedir (DIR * dir) { int res = 0; - if (dir->__d_u.__d_data.__handle != INVALID_HANDLE_VALUE && - RegCloseKey ((HKEY) dir->__d_u.__d_data.__handle) != ERROR_SUCCESS) + if (dir->__handle != INVALID_HANDLE_VALUE && + RegCloseKey ((HKEY) dir->__handle) != ERROR_SUCCESS) { __seterrno (); res = -1; diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc index ecb13416a93..602c6348970 100644 --- a/winsup/cygwin/fhandler_tty.cc +++ b/winsup/cygwin/fhandler_tty.cc @@ -737,7 +737,7 @@ fhandler_tty_slave::read (void *ptr, size_t& len) if (totalread > 0) break; set_sig_errno (EINTR); - (ssize_t) len = -1; + len = (size_t) -1; return; } @@ -762,7 +762,7 @@ fhandler_tty_slave::read (void *ptr, size_t& len) if (!vmin && !time_to_wait) { ReleaseMutex (input_mutex); - (ssize_t) len = bytes_in_pipe; + len = (size_t) bytes_in_pipe; return; } @@ -842,7 +842,7 @@ fhandler_tty_slave::read (void *ptr, size_t& len) waiter = time_to_wait; } termios_printf ("%d=read(%x, %d)", totalread, ptr, len); - (ssize_t) len = totalread; + len = (size_t) totalread; return; } @@ -1154,7 +1154,7 @@ fhandler_pty_master::write (const void *ptr, size_t len) void __stdcall fhandler_pty_master::read (void *ptr, size_t& len) { - (ssize_t) len = process_slave_output ((char *) ptr, len, pktmode); + len = (size_t) process_slave_output ((char *) ptr, len, pktmode); return; } diff --git a/winsup/cygwin/fhandler_virtual.cc b/winsup/cygwin/fhandler_virtual.cc index aedaf018726..258cba287da 100644 --- a/winsup/cygwin/fhandler_virtual.cc +++ b/winsup/cygwin/fhandler_virtual.cc @@ -77,9 +77,9 @@ fhandler_virtual::opendir () fd = this; fd->set_nohandle (true); dir->__d_dirent->d_fd = fd; - dir->__d_u.__d_data.__fh = this; + dir->__fh = this; dir->__d_cookie = __DIRENT_COOKIE; - dir->__d_u.__d_data.__handle = INVALID_HANDLE_VALUE; + dir->__handle = INVALID_HANDLE_VALUE; dir->__d_position = 0; dir->__d_dirhash = get_namehash (); @@ -179,18 +179,18 @@ fhandler_virtual::read (void *ptr, size_t& len) if (openflags & O_DIROPEN) { set_errno (EISDIR); - (ssize_t) len = -1; + len = (size_t) -1; return; } if (!filebuf) { - (ssize_t) len = 0; + len = (size_t) 0; return; } if ((ssize_t) len > filesize - position) - (ssize_t) len = filesize - position; + len = (size_t) (filesize - position); if ((ssize_t) len < 0) - (ssize_t) len = 0; + len = 0; else memcpy (ptr, filebuf + position, len); position += len; diff --git a/winsup/cygwin/fhandler_windows.cc b/winsup/cygwin/fhandler_windows.cc index 4affbc6faf4..5964052fa4c 100644 --- a/winsup/cygwin/fhandler_windows.cc +++ b/winsup/cygwin/fhandler_windows.cc @@ -87,11 +87,11 @@ fhandler_windows::read (void *buf, size_t& len) if (len < sizeof (MSG)) { set_errno (EINVAL); - (ssize_t) len = -1; + len = (size_t) -1; return; } - (ssize_t) len = GetMessage (ptr, hWnd_, 0, 0); + len = (size_t) GetMessage (ptr, hWnd_, 0, 0); if ((ssize_t) len == -1) __seterrno (); diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc index 616c7467fef..2fe73667af8 100644 --- a/winsup/cygwin/fork.cc +++ b/winsup/cygwin/fork.cc @@ -633,15 +633,6 @@ fork () 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)); diff --git a/winsup/cygwin/heap.cc b/winsup/cygwin/heap.cc index 60cbb4fe134..1bbac313482 100644 --- a/winsup/cygwin/heap.cc +++ b/winsup/cygwin/heap.cc @@ -146,7 +146,7 @@ sbrk (int n) || VirtualAlloc (cygheap->user_heap.top, newbrksize = commitbytes, MEM_RESERVE, PAGE_NOACCESS)) && VirtualAlloc (cygheap->user_heap.top, commitbytes, MEM_COMMIT, PAGE_READWRITE) != NULL) { - (char *) cygheap->user_heap.max += pround (newbrksize); + cygheap->user_heap.max = (char *) cygheap->user_heap.max + pround (newbrksize); goto good; } diff --git a/winsup/cygwin/hires.h b/winsup/cygwin/hires.h new file mode 100644 index 00000000000..df4c44c4a1f --- /dev/null +++ b/winsup/cygwin/hires.h @@ -0,0 +1,57 @@ +/* hires.h: Definitions for hires clock calculations + + Copyright 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. */ + +#ifndef __HIRES_H__ +#define __HIRES_H__ + +#include <mmsystem.h> + +/* Largest delay in ms for sleep and alarm calls. + Allow actual delay to exceed requested delay by 10 s. + Express as multiple of 1000 (i.e. seconds) + max resolution + The tv_sec argument in timeval structures cannot exceed + HIRES_DELAY_MAX / 1000 - 1, so that adding fractional part + and rounding won't exceed HIRES_DELAY_MAX */ +#define HIRES_DELAY_MAX (((UINT_MAX - 10000) / 1000) * 1000) + 10 + +class hires_base +{ + protected: + int inited; + public: + virtual LONGLONG usecs (bool justdelta) {return 0LL;} + virtual ~hires_base () {} +}; + +class hires_us : hires_base +{ + LARGE_INTEGER primed_ft; + LARGE_INTEGER primed_pc; + double freq; + void prime (); + public: + LONGLONG usecs (bool justdelta); +}; + +class hires_ms : hires_base +{ + DWORD initime_ms; + LARGE_INTEGER initime_us; + static UINT minperiod; + UINT prime (); + public: + LONGLONG usecs (bool justdelta); + UINT dmsecs () { return timeGetTime (); } + UINT resolution () { return minperiod ?: prime (); } + +}; + +extern hires_ms gtod; +#endif /*__HIRES_H__*/ diff --git a/winsup/cygwin/include/cygwin/in.h b/winsup/cygwin/include/cygwin/in.h index a2124552ffd..76bdaaa3e02 100644 --- a/winsup/cygwin/include/cygwin/in.h +++ b/winsup/cygwin/include/cygwin/in.h @@ -170,6 +170,7 @@ struct sockaddr_in #endif +#ifdef USE_IPV6 /* IPv6 definitions as we start to include them. This is just a beginning dont get excited 8) */ struct in6_addr @@ -184,4 +185,5 @@ struct sockaddr_in6 unsigned long sin6_flowinfo; struct in6_addr sin6_addr; }; +#endif #endif /* _CYGWIN_IN_H */ diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h index b99b0640421..c37f52910d8 100644 --- a/winsup/cygwin/include/cygwin/version.h +++ b/winsup/cygwin/include/cygwin/version.h @@ -210,12 +210,20 @@ details. */ 88: Export _getreent 89: Export __mempcpy 90: Export _fopen64 + 91: Export argz_add argz_add_sep argz_append argz_count argz_create + argz_create_sep argz_delete argz_extract argz_insert + argz_next argz_replace argz_stringify envz_add envz_entry + envz_get envz_merge envz_remove envz_strip + 92: Export getusershell, setusershell, endusershell + 93: Export daemon, forkpty, openpty, iruserok, ruserok, login_tty, + openpty, forkpty, revoke, logwtmp, updwtmp + */ /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */ #define CYGWIN_VERSION_API_MAJOR 0 -#define CYGWIN_VERSION_API_MINOR 90 +#define CYGWIN_VERSION_API_MINOR 93 /* There is also a compatibity version number associated with the shared memory regions. It is incremented when incompatible diff --git a/winsup/cygwin/include/paths.h b/winsup/cygwin/include/paths.h new file mode 100644 index 00000000000..fd03f979034 --- /dev/null +++ b/winsup/cygwin/include/paths.h @@ -0,0 +1,21 @@ +/* paths.h + + Copyright 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. */ + +#ifndef _PATHS_H_ +#define _PATHS_H_ + +#define _PATH_DEV "/dev/" +#define _PATH_BSHELL "/bin/sh" +#define _PATH_LASTLOG "/var/log/lastlog" +#define _PATH_UTMP "/var/run/utmp" +#define _PATH_WTMP "/var/log/wtmp" +#define _PATH_DEVNULL "/dev/null" + +#endif /* _PATHS_H_ */ diff --git a/winsup/cygwin/include/pty.h b/winsup/cygwin/include/pty.h new file mode 100644 index 00000000000..e4b4da03f57 --- /dev/null +++ b/winsup/cygwin/include/pty.h @@ -0,0 +1,18 @@ +#ifndef __PTY_H__ +#define __PTY_H__ + +#include <_ansi.h> +#include <sys/termios.h> + +#ifdef __cplusplus +extern "C" { +#endif + +int _EXFUN(openpty ,(int *, int *, char *, struct termios *, struct winsize *)); +int _EXFUN(forkpty ,(int *, char *, struct termios *, struct winsize *)); + +#ifdef __cplusplus +} +#endif + +#endif /* __PTY_H__ */ diff --git a/winsup/cygwin/include/sys/cygwin.h b/winsup/cygwin/include/sys/cygwin.h index e117175e0c2..9dd46db16ab 100644 --- a/winsup/cygwin/include/sys/cygwin.h +++ b/winsup/cygwin/include/sys/cygwin.h @@ -89,8 +89,7 @@ enum PID_ORPHANED = 0x0020, /* Member of an orphaned process group. */ PID_ACTIVE = 0x0040, /* Pid accepts signals. */ PID_CYGPARENT = 0x0080, /* Set if parent was a cygwin app. */ - PID_SPLIT_HEAP = 0x0100, /* Set if the heap has been split, */ - /* which means we can't fork again. */ + PID_UNUSED = 0x0100, /* ... */ PID_MYSELF = 0x0200, /* Flag that pid is me. */ PID_NOCLDSTOP = 0x0400, /* Set if no SIGCHLD signal on stop. */ PID_INITIALIZING = 0x0800, /* Set until ready to receive signals. */ diff --git a/winsup/cygwin/include/sys/dirent.h b/winsup/cygwin/include/sys/dirent.h index a077169b99b..c3d77c4fbe0 100644 --- a/winsup/cygwin/include/sys/dirent.h +++ b/winsup/cygwin/include/sys/dirent.h @@ -1,6 +1,6 @@ /* Posix dirent.h for WIN32. - Copyright 2001 Red Hat, Inc. + Copyright 2001, 2002, 2003 Red Hat, Inc. This software is a copyrighted work licensed under the terms of the Cygwin license. Please consult the file "CYGWIN_LICENSE" for @@ -23,7 +23,7 @@ struct dirent __ino64_t d_ino; /* still junk but with more bits */ long d_fd; /* File descriptor of open directory. Used since Cygwin 1.3.3. */ - __ino32_t old_d_ino; /* Just for compatibility, it's junk */ + unsigned __ino32; char d_name[256]; /* FIXME: use NAME_MAX? */ }; #else @@ -33,7 +33,7 @@ struct dirent long d_version; ino_t d_ino; long d_fd; - unsigned long old_d_ino; + unsigned long __ino32; char d_name[256]; }; #else @@ -51,6 +51,7 @@ struct dirent #define __DIRENT_COOKIE 0xdede4242 +#pragma pack(push,4) typedef struct __DIR { /* This is first to set alignment in non _COMPILING_NEWLIB case. */ @@ -58,20 +59,12 @@ typedef struct __DIR struct dirent *__d_dirent; char *__d_dirname; /* directory name with trailing '*' */ _off_t __d_position; /* used by telldir/seekdir */ - unsigned long __d_dirhash; /* hash of directory name for use by - readdir */ - union - { -#ifdef __INSIDE_CYGWIN__ - struct - { - void *__handle; - void *__fh; - } __d_data; -#endif - char __d_filler[16]; - } __d_u; + __ino64_t __d_dirhash; /* hash of directory name for use by readdir */ + void *__handle; + void *__fh; + unsigned __flags; } DIR; +#pragma pack(pop) DIR *opendir (const char *); struct dirent *readdir (DIR *); diff --git a/winsup/cygwin/include/sys/mman.h b/winsup/cygwin/include/sys/mman.h index 5059f894af8..13393e9cc27 100644 --- a/winsup/cygwin/include/sys/mman.h +++ b/winsup/cygwin/include/sys/mman.h @@ -41,11 +41,11 @@ extern "C" { #define MS_INVALIDATE 4 #ifndef __INSIDE_CYGWIN__ -extern caddr_t mmap (caddr_t __addr, size_t __len, int __prot, int __flags, int __fd, off_t __off); +extern void *mmap (void *__addr, size_t __len, int __prot, int __flags, int __fd, off_t __off); #endif -extern int munmap (caddr_t __addr, size_t __len); -extern int mprotect (caddr_t __addr, size_t __len, int __prot); -extern int msync (caddr_t __addr, size_t __len, int __flags); +extern int munmap (void *__addr, size_t __len); +extern int mprotect (void *__addr, size_t __len, int __prot); +extern int msync (void *__addr, size_t __len, int __flags); #ifdef __cplusplus }; diff --git a/winsup/cygwin/include/sys/utmp.h b/winsup/cygwin/include/sys/utmp.h index 2d959d80683..b78c5631749 100644 --- a/winsup/cygwin/include/sys/utmp.h +++ b/winsup/cygwin/include/sys/utmp.h @@ -60,7 +60,8 @@ extern void utmpname (const char *); void login (struct utmp *); int logout (char *); int login_tty (int); -void logwtmp (char *, char *, char *); +void updwtmp (const char *, const struct utmp *); +void logwtmp (const char *, const char *, const char *); #ifdef __cplusplus } diff --git a/winsup/cygwin/lib/iruserok.c b/winsup/cygwin/lib/iruserok.c new file mode 100644 index 00000000000..5e957184ed9 --- /dev/null +++ b/winsup/cygwin/lib/iruserok.c @@ -0,0 +1,319 @@ +/* Based on the rcmd.c.new file distributed with linux libc 5.4.19 + Adapted to inetutils by Bernhard Rosenkraenzer <bero@startrek.in-trier.de> + + Note that a lot in this file is superfluous; hopefully it won't be a + problem for systems that need it for iruserok &c.... */ +/* + * Copyright (c) 1983, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef __CYGWIN__ +#define HAVE_MALLOC_H +#define HAVE_STDLIB_H +#define HAVE_STRING_H +#define TIME_WITH_SYS_TIME +#define PATH_HEQUIV "/etc/hosts.equiv" + +static int __ivaliduser(); +static int __icheckhost(); + +struct hostent *cygwin_gethostbyname (const char *name); +unsigned long cygwin_inet_addr (const char *cp); + +#define gethostbyname cygwin_gethostbyname +#define inet_addr cygwin_inet_addr +#endif + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <pwd.h> +#include <sys/file.h> +#include <sys/signal.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/uio.h> +#include <sys/param.h> +#include <sys/socket.h> +#ifdef HAVE_MALLOC_H +#include <malloc.h> +#endif +#if defined(STDC_HEADERS) || defined(HAVE_STDLIB_H) +#include <stdlib.h> +#endif +#ifdef HAVE_STRING_H +# include <string.h> +#endif +#include <netinet/in.h> +#ifdef HAVE_ARPA_NAMESER_H +# include <arpa/nameser.h> +#endif +#include <netdb.h> +#include <unistd.h> +#include <ctype.h> +#include <stdio.h> +#include <errno.h> +#ifdef TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif +#ifndef __CYGWIN__ +#include <resolv.h> +#endif + +int __check_rhosts_file = 1; +const char *__rcmd_errstr; + +int +ruserok(rhost, superuser, ruser, luser) + const char *rhost; + int superuser; + const char *ruser; + const char *luser; +{ + struct hostent *hp; + u_long addr; + char **ap; + + if ((hp = gethostbyname(rhost)) == NULL) + return (-1); + for (ap = hp->h_addr_list; *ap; ++ap) { + bcopy(*ap, &addr, sizeof(addr)); + if (iruserok(addr, superuser, ruser, luser) == 0) + return (0); + } + return (-1); +} + +/* + * New .rhosts strategy: We are passed an ip address. We spin through + * hosts.equiv and .rhosts looking for a match. When the .rhosts only + * has ip addresses, we don't have to trust a nameserver. When it + * contains hostnames, we spin through the list of addresses the nameserver + * gives us and look for a match. + * + * Returns 0 if ok, -1 if not ok. + */ +int +iruserok(raddr, superuser, ruser, luser) + u_long raddr; + int superuser; + const char *ruser; + const char *luser; +{ + register const char *cp; + struct stat sbuf; + struct passwd *pwd; + FILE *hostf; + uid_t uid; + int first = 1; + char *pbuf; + + first = 1; + hostf = superuser ? NULL : fopen(PATH_HEQUIV, "r"); +again: + if (hostf) { + if (__ivaliduser(hostf, raddr, luser, ruser) == 0) { + (void) fclose(hostf); + return(0); + } + (void) fclose(hostf); + } + if (first == 1 && (__check_rhosts_file || superuser)) { + first = 0; + if ((pwd = getpwnam(luser)) == NULL) + return(-1); + + pbuf = malloc (strlen (pwd->pw_dir) + sizeof "/.rhosts"); + if (! pbuf) + { + errno = ENOMEM; + return -1; + } + strcpy (pbuf, pwd->pw_dir); + strcat (pbuf, "/.rhosts"); + + /* + * Change effective uid while opening .rhosts. If root and + * reading an NFS mounted file system, can't read files that + * are protected read/write owner only. + */ + uid = geteuid(); + (void)seteuid(pwd->pw_uid); + hostf = fopen(pbuf, "r"); + (void)seteuid(uid); + + if (hostf == NULL) + return(-1); + /* + * If not a regular file, or is owned by someone other than + * user or root or if writeable by anyone but the owner, quit. + */ + cp = NULL; + if (lstat(pbuf, &sbuf) < 0) + cp = ".rhosts not regular file"; + else if (!S_ISREG(sbuf.st_mode)) + cp = ".rhosts not regular file"; + else if (fstat(fileno(hostf), &sbuf) < 0) + cp = ".rhosts fstat failed"; + else if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) + cp = "bad .rhosts owner"; + else if (sbuf.st_mode & (S_IWGRP|S_IWOTH)) + cp = ".rhosts writeable by other than owner"; + /* If there were any problems, quit. */ + if (cp) { + __rcmd_errstr = (char *) cp; + fclose(hostf); + return(-1); + } + goto again; + } + return (-1); +} + +/* + * XXX + * Don't make static, used by lpd(8). + * + * Returns 0 if ok, -1 if not ok. + */ +#ifdef __CYGWIN__ +static +#endif +int +__ivaliduser(hostf, raddr, luser, ruser) + FILE *hostf; + u_long raddr; + const char *luser; + const char *ruser; +{ + size_t buf_offs = 0; + size_t buf_len = 256; + char *buf = malloc (buf_len); + + if (! buf) + return -1; + + while (fgets(buf + buf_offs, buf_len - buf_offs, hostf)) { + /*int ch;*/ + register char *user, *p; + + if (strchr(buf + buf_offs, '\n') == NULL) { + /* No newline yet, read some more. */ + buf_offs += strlen (buf + buf_offs); + + if (buf_offs >= buf_len - 1) { + /* Make more room in BUF. */ + char *new_buf; + + buf_len += buf_len; + new_buf = realloc (buf, buf_len); + + if (! new_buf) { + free (buf); + return -1; + } + + buf = new_buf; + } + + continue; + } + + buf_offs = 0; /* Start at beginning next time around. */ + + p = buf; + while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') { + /* *p = isupper(*p) ? tolower(*p) : *p; -- Uli */ + *p = tolower(*p); /* works for linux libc */ + p++; + } + if (*p == ' ' || *p == '\t') { + *p++ = '\0'; + while (*p == ' ' || *p == '\t') + p++; + user = p; + while (*p != '\n' && *p != ' ' && + *p != '\t' && *p != '\0') + p++; + } else + user = p; + *p = '\0'; + + if (__icheckhost(raddr, buf) && !strcmp(ruser, *user ? user : luser)) { + free (buf); + return (0); + } + } + + free (buf); + + return (-1); +} + +/* + * Returns "true" if match, 0 if no match. + */ +#ifdef __CYGWIN__ +static +#endif +int +__icheckhost(raddr, lhost) + u_long raddr; + register char *lhost; +{ + register struct hostent *hp; + register u_long laddr; + register char **pp; + + /* Try for raw ip address first. */ + if (isdigit(*lhost) && (long)(laddr = inet_addr(lhost)) != -1) + return (raddr == laddr); + + /* Better be a hostname. */ + if ((hp = gethostbyname(lhost)) == NULL) + return (0); + + /* Spin through ip addresses. */ + for (pp = hp->h_addr_list; *pp; ++pp) + if (!bcmp(&raddr, *pp, sizeof(u_long))) + return (1); + + /* No match. */ + return (0); +} diff --git a/winsup/cygwin/libc/bsdlib.cc b/winsup/cygwin/libc/bsdlib.cc new file mode 100644 index 00000000000..acf43adbfb0 --- /dev/null +++ b/winsup/cygwin/libc/bsdlib.cc @@ -0,0 +1,165 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * CV 2003-09-10: Cygwin specific changes applied. Code simplified just + * for Cygwin alone. + */ + +#include "winsup.h" +#include <stdlib.h> +#include <utmp.h> +#include <unistd.h> +#include <sys/termios.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include "cygerrno.h" + +extern "C" int +daemon (int nochdir, int noclose) +{ + int fd; + + switch (fork ()) + { + case -1: + return -1; + case 0: + if (!wincap.is_winnt ()) + { + /* Register as service under 9x/Me which allows to close + the parent window with the daemon still running. + This function only exists on 9x/Me and is autoloaded + so it fails silently on NT. */ + DWORD WINAPI RegisterServiceProcess (DWORD, DWORD); + RegisterServiceProcess (0, 1); + } + break; + default: + /* This sleep avoids a race condition which kills the + child process if parent is started by a NT/W2K service. + FIXME: Is that still true? */ + Sleep (1000L); + _exit (0); + } + if (setsid () == -1) + return -1; + if (!nochdir) + chdir ("/"); + if (!noclose && (fd = open (_PATH_DEVNULL, O_RDWR, 0)) >= 0) + { + dup2 (fd, STDIN_FILENO); + dup2 (fd, STDOUT_FILENO); + dup2 (fd, STDERR_FILENO); + if (fd > 2) + close (fd); + } + return 0; +} + +extern "C" int +login_tty (int fd) +{ + char *fdname; + int newfd; + + if (setsid () == -1) + return -1; + if ((fdname = ttyname (fd))) + { + if (fd != STDIN_FILENO) + close (STDIN_FILENO); + if (fd != STDOUT_FILENO) + close (STDOUT_FILENO); + if (fd != STDERR_FILENO) + close (STDERR_FILENO); + newfd = open (fdname, O_RDWR); + close (newfd); + } + dup2 (fd, STDIN_FILENO); + dup2 (fd, STDOUT_FILENO); + dup2 (fd, STDERR_FILENO); + if (fd > 2) + close (fd); + return 0; +} + +extern "C" int +openpty (int *amaster, int *aslave, char *name, struct termios *termp, + struct winsize *winp) +{ + int master, slave; + char pts[MAX_PATH]; + + if ((master = open ("/dev/ptmx", O_RDWR | O_NOCTTY)) >= 0) + { + grantpt (master); + unlockpt (master); + strcpy (pts, ptsname (master)); + revoke (pts); + if ((slave = open (pts, O_RDWR | O_NOCTTY)) >= 0) + { + if (amaster) + *amaster = master; + if (aslave) + *aslave = slave; + if (name) + strcpy (name, pts); + if (termp) + tcsetattr (slave, TCSAFLUSH, termp); + if (winp) + ioctl (slave, TIOCSWINSZ, (char *) winp); + return 0; + } + close (master); + } + set_errno (ENOENT); + return -1; +} + +extern "C" int +forkpty (int *amaster, char *name, struct termios *termp, struct winsize *winp) +{ + int master, slave, pid; + + if (openpty (&master, &slave, name, termp, winp) == -1) + return -1; + switch (pid = fork ()) + { + case -1: + return -1; + case 0: + close (master); + login_tty (slave); + return 0; + } + if (amaster) + *amaster = master; + close (slave); + return pid; +} + diff --git a/winsup/cygwin/mmap.cc b/winsup/cygwin/mmap.cc index d2583d2eb44..5ed774273b5 100644 --- a/winsup/cygwin/mmap.cc +++ b/winsup/cygwin/mmap.cc @@ -27,15 +27,29 @@ details. */ #define PGBITS (sizeof (DWORD)*8) #define MAPSIZE(pages) howmany ((pages), PGBITS) -#define MAP_SET(n) (map_map_[(n)/PGBITS] |= (1L << ((n) % PGBITS))) -#define MAP_CLR(n) (map_map_[(n)/PGBITS] &= ~(1L << ((n) % PGBITS))) -#define MAP_ISSET(n) (map_map_[(n)/PGBITS] & (1L << ((n) % PGBITS))) +#define MAP_SET(n) (page_map_[(n)/PGBITS] |= (1L << ((n) % PGBITS))) +#define MAP_CLR(n) (page_map_[(n)/PGBITS] &= ~(1L << ((n) % PGBITS))) +#define MAP_ISSET(n) (page_map_[(n)/PGBITS] & (1L << ((n) % PGBITS))) -/* - * Simple class used to keep a record of all current - * mmap areas in a process. Needed so that - * they can be duplicated after a fork(). - */ +/* Used for accessing the page file (anonymous mmaps). */ +static fhandler_disk_file fh_paging_file; + +/* Class structure used to keep a record of all current mmap areas + in a process. Needed for bookkeeping all mmaps in a process and + for duplicating all mmaps after fork() since mmaps are not propagated + to child processes by Windows. All information must be duplicated + by hand, see fixup_mmaps_after_fork(). + + The class structure: + + One member of class map per process, global variable mmapped_areas. + Contains a dynamic class list array. Each list entry represents all + mapping to a file, keyed by file descriptor and file name hash. + Each list entry contains a dynamic class mmap_record array. Each + mmap_record represents exactly one mapping. For each mapping, there's + an additional so called `page_map'. It's an array of bits, one bit + per mapped memory page. The bit is set if the page is accessible, + unset otherwise. */ class mmap_record { @@ -46,7 +60,7 @@ class mmap_record _off64_t offset_; DWORD size_to_map_; caddr_t base_address_; - DWORD *map_map_; + DWORD *page_map_; device dev; public: @@ -57,16 +71,13 @@ class mmap_record offset_ (o), size_to_map_ (s), base_address_ (b), - map_map_ (NULL) + page_map_ (NULL) { dev.devn = 0; if (fd >= 0 && !cygheap->fdtab.not_open (fd)) dev = cygheap->fdtab[fd]->dev (); } - /* Default Copy constructor/operator=/destructor are ok */ - - /* Simple accessors */ int get_fd () const { return fdesc_; } HANDLE get_handle () const { return mapping_handle_; } device& get_device () { return dev; } @@ -74,22 +85,61 @@ class mmap_record DWORD get_offset () const { return offset_; } DWORD get_size () const { return size_to_map_; } caddr_t get_address () const { return base_address_; } - DWORD *get_map () const { return map_map_; } - void alloc_map (_off64_t off, DWORD len); - void free_map () { if (map_map_) cfree (map_map_); } - - DWORD find_empty (DWORD pages); - _off64_t map_map (_off64_t off, DWORD len); - BOOL unmap_map (caddr_t addr, DWORD len); - void fixup_map (void); + + bool alloc_page_map (_off64_t off, DWORD len); + void free_page_map () { if (page_map_) cfree (page_map_); } + void fixup_page_map (void); + + DWORD find_unused_pages (DWORD pages); + _off64_t map_pages (_off64_t off, DWORD len); + BOOL unmap_pages (caddr_t addr, DWORD len); int access (caddr_t address); fhandler_base *alloc_fh (); void free_fh (fhandler_base *fh); }; +class list +{ + private: + mmap_record *recs; + int nrecs, maxrecs; + int fd; + DWORD hash; + + public: + int get_fd () const { return fd; } + DWORD get_hash () const { return hash; } + mmap_record *get_record (int i) { return i >= nrecs ? NULL : recs + i; } + + void set (int nfd); + mmap_record *add_record (mmap_record r, _off64_t off, DWORD len); + bool del_record (int i); + void free_recs () { if (recs) cfree (recs); } + mmap_record *search_record (_off64_t off, DWORD len); + long search_record (caddr_t addr, DWORD len, caddr_t &m_addr, DWORD &m_len, + long start); +}; + +class map +{ + private: + list *lists; + int nlists, maxlists; + + public: + list *get_list (int i) { return i >= nlists ? NULL : lists + i; } + list *get_list_by_fd (int fd); + list *add_list (int fd); + void del_list (int i); +}; + +/* This is the global map structure pointer. It's allocated once on the + first call to mmap64(). */ +static map *mmapped_areas; + DWORD -mmap_record::find_empty (DWORD pages) +mmap_record::find_unused_pages (DWORD pages) { DWORD mapped_pages = PAGE_CNT (size_to_map_); DWORD start; @@ -109,12 +159,15 @@ mmap_record::find_empty (DWORD pages) return (DWORD)-1; } -void -mmap_record::alloc_map (_off64_t off, DWORD len) +bool +mmap_record::alloc_page_map (_off64_t off, DWORD len) { /* Allocate one bit per page */ - map_map_ = (DWORD *) ccalloc (HEAP_MMAP, MAPSIZE (PAGE_CNT (size_to_map_)), - sizeof (DWORD)); + if (!(page_map_ = (DWORD *) ccalloc (HEAP_MMAP, + MAPSIZE (PAGE_CNT (size_to_map_)), + sizeof (DWORD)))) + return false; + if (wincap.virtual_protect_works_on_shared_pages ()) { DWORD old_prot; @@ -135,15 +188,16 @@ mmap_record::alloc_map (_off64_t off, DWORD len) while (len-- > 0) MAP_SET (off + len); } + return true; } _off64_t -mmap_record::map_map (_off64_t off, DWORD len) +mmap_record::map_pages (_off64_t off, DWORD len) { /* Used ONLY if this mapping matches into the chunk of another already performed mapping in a special case of MAP_ANON|MAP_PRIVATE. - Otherwise it's job is now done by alloc_map(). */ + Otherwise it's job is now done by alloc_page_map(). */ DWORD prot, old_prot; switch (access_mode_) { @@ -158,10 +212,10 @@ mmap_record::map_map (_off64_t off, DWORD len) break; } - debug_printf ("map_map (fd=%d, off=%D, len=%u)", fdesc_, off, len); + debug_printf ("map_pages (fd=%d, off=%D, len=%u)", fdesc_, off, len); len = PAGE_CNT (len); - if ((off = find_empty (len)) == (DWORD)-1) + if ((off = find_unused_pages (len)) == (DWORD)-1) return 0L; if (wincap.virtual_protect_works_on_shared_pages () && !VirtualProtect (base_address_ + off * getpagesize (), @@ -177,7 +231,7 @@ mmap_record::map_map (_off64_t off, DWORD len) } BOOL -mmap_record::unmap_map (caddr_t addr, DWORD len) +mmap_record::unmap_pages (caddr_t addr, DWORD len) { DWORD old_prot; DWORD off = addr - base_address_; @@ -186,20 +240,20 @@ mmap_record::unmap_map (caddr_t addr, DWORD len) if (wincap.virtual_protect_works_on_shared_pages () && !VirtualProtect (base_address_ + off * getpagesize (), len * getpagesize (), PAGE_NOACCESS, &old_prot)) - syscall_printf ("-1 = unmap_map (): %E"); + syscall_printf ("-1 = unmap_pages (): %E"); for (; len-- > 0; ++off) MAP_CLR (off); /* Return TRUE if all pages are free'd which may result in unmapping the whole chunk. */ for (len = MAPSIZE (PAGE_CNT (size_to_map_)); len > 0; ) - if (map_map_[--len]) + if (page_map_[--len]) return FALSE; return TRUE; } void -mmap_record::fixup_map () +mmap_record::fixup_page_map () { if (!wincap.virtual_protect_works_on_shared_pages ()) return; @@ -232,8 +286,6 @@ mmap_record::access (caddr_t address) return MAP_ISSET (off); } -static fhandler_disk_file fh_paging_file; - fhandler_base * mmap_record::alloc_fh () { @@ -259,57 +311,38 @@ mmap_record::free_fh (fhandler_base *fh) cfree (fh); } -class list { -public: - mmap_record *recs; - int nrecs, maxrecs; - int fd; - DWORD hash; - list (); - ~list (); - mmap_record *add_record (mmap_record r, _off64_t off, DWORD len); - void erase (int i); - void erase (); - mmap_record *match (_off64_t off, DWORD len); - long match (caddr_t addr, DWORD len, caddr_t &m_addr, DWORD &m_len, - long start); -}; - -list::list () -: nrecs (0), maxrecs (10), fd (0), hash (0) -{ - recs = (mmap_record *) cmalloc (HEAP_MMAP, 10 * sizeof (mmap_record)); -} - -list::~list () -{ - for (mmap_record *rec = recs; nrecs-- > 0; ++rec) - rec->free_map (); - cfree (recs); -} - mmap_record * list::add_record (mmap_record r, _off64_t off, DWORD len) { if (nrecs == maxrecs) { + mmap_record *new_recs; + if (maxrecs == 0) + new_recs = (mmap_record *) + cmalloc (HEAP_MMAP, 5 * sizeof (mmap_record)); + else + new_recs = (mmap_record *) + crealloc (recs, (maxrecs + 5) * sizeof (mmap_record)); + if (!new_recs) + return NULL; maxrecs += 5; - recs = (mmap_record *) crealloc (recs, maxrecs * sizeof (mmap_record)); + recs = new_recs; } recs[nrecs] = r; - recs[nrecs].alloc_map (off, len); + if (!recs[nrecs].alloc_page_map (off, len)) + return NULL; return recs + nrecs++; } /* Used in mmap() */ mmap_record * -list::match (_off64_t off, DWORD len) +list::search_record (_off64_t off, DWORD len) { if (fd == -1 && !off) { len = PAGE_CNT (len); for (int i = 0; i < nrecs; ++i) - if (recs[i].find_empty (len) != (DWORD)-1) + if (recs[i].find_unused_pages (len) != (DWORD)-1) return recs + i; } else @@ -325,7 +358,7 @@ list::match (_off64_t off, DWORD len) /* Used in munmap() */ long -list::match (caddr_t addr, DWORD len, caddr_t &m_addr, DWORD &m_len, +list::search_record (caddr_t addr, DWORD len, caddr_t &m_addr, DWORD &m_len, _off_t start) { caddr_t low, high; @@ -347,41 +380,27 @@ list::match (caddr_t addr, DWORD len, caddr_t &m_addr, DWORD &m_len, } void -list::erase (int i) -{ - recs[i].free_map (); - for (; i < nrecs-1; i++) - recs[i] = recs[i+1]; - nrecs--; -} - -void -list::erase () -{ - erase (nrecs-1); -} - -class map { -public: - list **lists; - int nlists, maxlists; - map (); - ~map (); - list *get_list_by_fd (int fd); - list *add_list (list *l, int fd); - void erase (int i); -}; - -map::map () +list::set (int nfd) { - lists = (list **) cmalloc (HEAP_MMAP, 10 * sizeof (list *)); - nlists = 0; - maxlists = 10; + if ((fd = nfd) != -1) + hash = cygheap->fdtab[fd]->get_namehash (); + nrecs = maxrecs = 0; + recs = NULL; } -map::~map () +bool +list::del_record (int i) { - cfree (lists); + if (i < nrecs) + { + recs[i].free_page_map (); + for (; i < nrecs - 1; i++) + recs[i] = recs[i + 1]; + nrecs--; + } + /* Return true if the list is empty which allows the caller to remove + this list from the list array. */ + return !nrecs; } list * @@ -389,52 +408,49 @@ map::get_list_by_fd (int fd) { int i; for (i=0; i<nlists; i++) -#if 0 /* The fd isn't sufficient since it could already be another file. */ - if (lists[i]->fd == fd -#else /* so we use the name hash value to identify the file unless - it's not an anonymous mapping. */ - if ((fd == -1 && lists[i]->fd == -1) - || (fd != -1 && lists[i]->hash == cygheap->fdtab[fd]->get_namehash ())) -#endif - return lists[i]; + /* The fd isn't sufficient since it could already be the fd of another + file. So we use the name hash value to identify the file unless + it's an anonymous mapping in which case the fd (-1) is sufficient. */ + if ((fd == -1 && lists[i].get_fd () == -1) + || (fd != -1 + && lists[i].get_hash () == cygheap->fdtab[fd]->get_namehash ())) + return lists + i; return 0; } list * -map::add_list (list *l, int fd) +map::add_list (int fd) { - l->fd = fd; - if (fd != -1) - l->hash = cygheap->fdtab[fd]->get_namehash (); if (nlists == maxlists) { + list *new_lists; + if (maxlists == 0) + new_lists = (list *) cmalloc (HEAP_MMAP, 5 * sizeof (list)); + else + new_lists = (list *) crealloc (lists, (maxlists + 5) * sizeof (list)); + if (!new_lists) + return NULL; maxlists += 5; - lists = (list **) crealloc (lists, maxlists * sizeof (list *)); + lists = new_lists; } - lists[nlists++] = l; - return lists[nlists-1]; + lists[nlists].set (fd); + return lists + nlists++; } void -map::erase (int i) +map::del_list (int i) { - for (; i < nlists-1; i++) - lists[i] = lists[i+1]; - nlists--; + if (i < nlists) + { + lists[i].free_recs (); + for (; i < nlists - 1; i++) + lists[i] = lists[i + 1]; + nlists--; + } } -/* - * Code to keep a record of all mmap'ed areas in a process. - * Needed to duplicate tham in a child of fork(). - * mmap_record classes are kept in an STL list in an STL map, keyed - * by file descriptor. This is *NOT* duplicated across a fork(), it - * needs to be specially handled by the fork code. - */ - -static map *mmapped_areas; - -extern "C" caddr_t -mmap64 (caddr_t addr, size_t len, int prot, int flags, int fd, _off64_t off) +extern "C" void * +mmap64 (void *addr, size_t len, int prot, int flags, int fd, _off64_t off) { syscall_printf ("addr %x, len %u, prot %x, flags %x, fd %d, off %D", addr, len, prot, flags, fd, off); @@ -464,7 +480,7 @@ mmap64 (caddr_t addr, size_t len, int prot, int flags, int fd, _off64_t off) if (mmapped_areas == NULL) { /* First mmap call, create STL map */ - mmapped_areas = new map; + mmapped_areas = (map *) ccalloc (HEAP_MMAP, 1, sizeof (map)); if (mmapped_areas == NULL) { set_errno (ENOMEM); @@ -531,9 +547,9 @@ mmap64 (caddr_t addr, size_t len, int prot, int flags, int fd, _off64_t off) if (map_list && fd == -1 && off == 0 && !(flags & MAP_FIXED)) { mmap_record *rec; - if ((rec = map_list->match (off, len)) != NULL) + if ((rec = map_list->search_record (off, len)) != NULL) { - if ((off = rec->map_map (off, len)) == (_off64_t)-1) + if ((off = rec->map_pages (off, len)) == (_off64_t)-1) { syscall_printf ("-1 = mmap()"); ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK|WRITE_LOCK, "mmap"); @@ -561,7 +577,7 @@ mmap64 (caddr_t addr, size_t len, int prot, int flags, int fd, _off64_t off) && (wincap.has_working_copy_on_write () || fd != -1)) access = FILE_MAP_COPY; - caddr_t base = addr; + caddr_t base = (caddr_t)addr; /* This shifts the base address to the next lower 64K boundary. The offset is re-added when evaluating the return value. */ if (base) @@ -575,9 +591,8 @@ mmap64 (caddr_t addr, size_t len, int prot, int flags, int fd, _off64_t off) return MAP_FAILED; } - /* Now we should have a successfully mmapped area. - Need to save it so forked children can reproduce it. - */ + /* At this point we should have a successfully mmapped area. + Now it's time for bookkeeping stuff. */ if (fd == -1) gran_len = PAGE_CNT (gran_len) * getpagesize (); mmap_record mmap_rec (fd, h, access, gran_off, gran_len, base); @@ -588,7 +603,7 @@ mmap64 (caddr_t addr, size_t len, int prot, int flags, int fd, _off64_t off) if (!map_list) { /* Create a new one */ - map_list = new list; + map_list = mmapped_areas->add_list (fd); if (!map_list) { fh->munmap (h, base, gran_len); @@ -597,19 +612,28 @@ mmap64 (caddr_t addr, size_t len, int prot, int flags, int fd, _off64_t off) ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap"); return MAP_FAILED; } - map_list = mmapped_areas->add_list (map_list, fd); } /* Insert into the list */ - mmap_record *rec = map_list->add_record (mmap_rec, off, len > gran_len ? gran_len : len); + mmap_record *rec = map_list->add_record (mmap_rec, off, + len > gran_len ? gran_len : len); + if (!rec) + { + fh->munmap (h, base, gran_len); + set_errno (ENOMEM); + syscall_printf ("-1 = mmap(): ENOMEM"); + ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap"); + return MAP_FAILED; + } + caddr_t ret = rec->get_address () + (off - gran_off); syscall_printf ("%x = mmap() succeeded", ret); ReleaseResourceLock (LOCK_MMAP_LIST, READ_LOCK | WRITE_LOCK, "mmap"); return ret; } -extern "C" caddr_t -mmap (caddr_t addr, size_t len, int prot, int flags, int fd, _off_t off) +extern "C" void * +mmap (void *addr, size_t len, int prot, int flags, int fd, _off_t off) { return mmap64 (addr, len, prot, flags, fd, (_off64_t)off); } @@ -617,7 +641,7 @@ mmap (caddr_t addr, size_t len, int prot, int flags, int fd, _off_t off) /* munmap () removes all mmapped pages between addr and addr+len. */ extern "C" int -munmap (caddr_t addr, size_t len) +munmap (void *addr, size_t len) { syscall_printf ("munmap (addr %x, len %u)", addr, len); @@ -640,27 +664,33 @@ munmap (caddr_t addr, size_t len) /* Iterate through the map, unmap pages between addr and addr+len in all maps. */ - - for (int it = 0; it < mmapped_areas->nlists; ++it) + list *map_list; + for (int list_idx = 0; + (map_list = mmapped_areas->get_list (list_idx)); + ++list_idx) { - list *map_list = mmapped_areas->lists[it]; - if (map_list) - { - long li = -1; - caddr_t u_addr; - DWORD u_len; + long record_idx = -1; + caddr_t u_addr; + DWORD u_len; - while ((li = map_list->match(addr, len, u_addr, u_len, li)) >= 0) + while ((record_idx = map_list->search_record((caddr_t)addr, len, u_addr, + u_len, record_idx)) >= 0) + { + mmap_record *rec = map_list->get_record (record_idx); + if (rec->unmap_pages (u_addr, u_len)) { - mmap_record *rec = map_list->recs + li; - if (rec->unmap_map (u_addr, u_len)) - { - fhandler_base *fh = rec->alloc_fh (); - fh->munmap (rec->get_handle (), addr, len); - rec->free_fh (fh); + /* The whole record has been unmapped, so... */ + fhandler_base *fh = rec->alloc_fh (); + fh->munmap (rec->get_handle (), (caddr_t)addr, len); + rec->free_fh (fh); - /* Delete the entry. */ - map_list->erase (li); + /* ...delete the record. */ + if (map_list->del_record (record_idx--)) + { + /* Yay, the last record has been removed from the list, + we can remove the list now, too. */ + mmapped_areas->del_list (list_idx--); + break; } } } @@ -674,7 +704,7 @@ munmap (caddr_t addr, size_t len) /* Sync file with memory. Ignore flags for now. */ extern "C" int -msync (caddr_t addr, size_t len, int flags) +msync (void *addr, size_t len, int flags) { syscall_printf ("addr = %x, len = %u, flags = %x", addr, len, flags); @@ -701,33 +731,35 @@ msync (caddr_t addr, size_t len, int flags) /* Iterate through the map, looking for the mmapped area. Error if not found. */ - for (int it = 0; it < mmapped_areas->nlists; ++it) + list *map_list; + for (int list_idx = 0; + (map_list = mmapped_areas->get_list (list_idx)); + ++list_idx) { - list *map_list = mmapped_areas->lists[it]; - if (map_list != 0) + mmap_record *rec; + for (int record_idx = 0; + (rec = map_list->get_record (record_idx)); + ++record_idx) { - for (int li = 0; li < map_list->nrecs; ++li) + if (rec->access ((caddr_t)addr)) { - mmap_record *rec = map_list->recs + li; - if (rec->access (addr)) - { - /* Check whole area given by len. */ - for (DWORD i = getpagesize (); i < len; ++i) - if (!rec->access (addr + i)) - goto invalid_address_range; - fhandler_base *fh = rec->alloc_fh (); - int ret = fh->msync (rec->get_handle (), addr, len, flags); - rec->free_fh (fh); - - if (ret) - syscall_printf ("%d = msync(): %E", ret); - else - syscall_printf ("0 = msync()"); - - ReleaseResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, - "msync"); - return 0; - } + /* Check whole area given by len. */ + for (DWORD i = getpagesize (); i < len; ++i) + if (!rec->access ((caddr_t)addr + i)) + goto invalid_address_range; + fhandler_base *fh = rec->alloc_fh (); + int ret = fh->msync (rec->get_handle (), (caddr_t)addr, len, + flags); + rec->free_fh (fh); + + if (ret) + syscall_printf ("%d = msync(): %E", ret); + else + syscall_printf ("0 = msync()"); + + ReleaseResourceLock (LOCK_MMAP_LIST, WRITE_LOCK | READ_LOCK, + "msync"); + return 0; } } } @@ -741,6 +773,62 @@ invalid_address_range: return -1; } +/* Set memory protection */ + +extern "C" int +mprotect (void *addr, size_t len, int prot) +{ + DWORD old_prot; + DWORD new_prot = 0; + + syscall_printf ("mprotect (addr %x, len %u, prot %x)", addr, len, prot); + + if (!wincap.virtual_protect_works_on_shared_pages () + && addr >= (caddr_t)0x80000000 && addr <= (caddr_t)0xBFFFFFFF) + { + syscall_printf ("0 = mprotect (9x: No VirtualProtect on shared memory)"); + return 0; + } + + switch (prot) + { + case PROT_READ | PROT_WRITE | PROT_EXEC: + case PROT_WRITE | PROT_EXEC: + new_prot = PAGE_EXECUTE_READWRITE; + break; + case PROT_READ | PROT_WRITE: + case PROT_WRITE: + new_prot = PAGE_READWRITE; + break; + case PROT_READ | PROT_EXEC: + new_prot = PAGE_EXECUTE_READ; + break; + case PROT_READ: + new_prot = PAGE_READONLY; + break; + case PROT_EXEC: + new_prot = PAGE_EXECUTE; + break; + case PROT_NONE: + new_prot = PAGE_NOACCESS; + break; + default: + syscall_printf ("-1 = mprotect (): invalid prot value"); + set_errno (EINVAL); + return -1; + } + + if (VirtualProtect (addr, len, new_prot, &old_prot) == 0) + { + __seterrno (); + syscall_printf ("-1 = mprotect (): %E"); + return -1; + } + + syscall_printf ("0 = mprotect ()"); + return 0; +} + /* * Base implementation: * @@ -900,62 +988,6 @@ fhandler_disk_file::fixup_mmap_after_fork (HANDLE h, DWORD access, DWORD offset, return base == address; } -/* Set memory protection */ - -extern "C" int -mprotect (caddr_t addr, size_t len, int prot) -{ - DWORD old_prot; - DWORD new_prot = 0; - - syscall_printf ("mprotect (addr %x, len %u, prot %x)", addr, len, prot); - - if (!wincap.virtual_protect_works_on_shared_pages () - && addr >= (caddr_t)0x80000000 && addr <= (caddr_t)0xBFFFFFFF) - { - syscall_printf ("0 = mprotect (9x: No VirtualProtect on shared memory)"); - return 0; - } - - switch (prot) - { - case PROT_READ | PROT_WRITE | PROT_EXEC: - case PROT_WRITE | PROT_EXEC: - new_prot = PAGE_EXECUTE_READWRITE; - break; - case PROT_READ | PROT_WRITE: - case PROT_WRITE: - new_prot = PAGE_READWRITE; - break; - case PROT_READ | PROT_EXEC: - new_prot = PAGE_EXECUTE_READ; - break; - case PROT_READ: - new_prot = PAGE_READONLY; - break; - case PROT_EXEC: - new_prot = PAGE_EXECUTE; - break; - case PROT_NONE: - new_prot = PAGE_NOACCESS; - break; - default: - syscall_printf ("-1 = mprotect (): invalid prot value"); - set_errno (EINVAL); - return -1; - } - - if (VirtualProtect (addr, len, new_prot, &old_prot) == 0) - { - __seterrno (); - syscall_printf ("-1 = mprotect (): %E"); - return -1; - } - - syscall_printf ("0 = mprotect ()"); - return 0; -} - /* * Call to re-create all the file mappings in a forked * child. Called from the child in initialization. At this @@ -976,94 +1008,94 @@ fixup_mmaps_after_fork (HANDLE parent) return 0; /* Iterate through the map */ - for (int it = 0; it < mmapped_areas->nlists; ++it) + list *map_list; + for (int list_idx = 0; + (map_list = mmapped_areas->get_list (list_idx)); + ++list_idx) { - list *map_list = mmapped_areas->lists[it]; - if (map_list) + mmap_record *rec; + for (int record_idx = 0; + (rec = map_list->get_record (record_idx)); + ++record_idx) { - int li; - for (li = 0; li < map_list->nrecs; ++li) - { - mmap_record *rec = map_list->recs + li; - - debug_printf ("fd %d, h %x, access %x, offset %D, size %u, address %p", - rec->get_fd (), rec->get_handle (), rec->get_access (), - rec->get_offset (), rec->get_size (), rec->get_address ()); - fhandler_base *fh = rec->alloc_fh (); - BOOL ret = fh->fixup_mmap_after_fork (rec->get_handle (), - rec->get_access (), - rec->get_offset (), - rec->get_size (), - rec->get_address ()); - rec->free_fh (fh); - - if (!ret) - return -1; - if (rec->get_access () == FILE_MAP_COPY) - { - for (char *address = rec->get_address (); - address < rec->get_address () + rec->get_size (); - address += getpagesize ()) - if (rec->access (address) - && !ReadProcessMemory (parent, address, address, - getpagesize (), NULL)) + debug_printf ("fd %d, h %x, access %x, offset %D, size %u, address %p", + rec->get_fd (), rec->get_handle (), rec->get_access (), + rec->get_offset (), rec->get_size (), rec->get_address ()); + + fhandler_base *fh = rec->alloc_fh (); + BOOL ret = fh->fixup_mmap_after_fork (rec->get_handle (), + rec->get_access (), + rec->get_offset (), + rec->get_size (), + rec->get_address ()); + rec->free_fh (fh); + + if (!ret) + return -1; + if (rec->get_access () == FILE_MAP_COPY) + { + for (char *address = rec->get_address (); + address < rec->get_address () + rec->get_size (); + address += getpagesize ()) + if (rec->access (address) + && !ReadProcessMemory (parent, address, address, + getpagesize (), NULL)) + { + DWORD old_prot; + DWORD last_error = GetLastError (); + + if (last_error != ERROR_PARTIAL_COPY + && last_error != ERROR_NOACCESS + || !wincap.virtual_protect_works_on_shared_pages ()) { - DWORD old_prot; - DWORD last_error = GetLastError (); - - if (last_error != ERROR_PARTIAL_COPY - && last_error != ERROR_NOACCESS - || !wincap.virtual_protect_works_on_shared_pages ()) - { - system_printf ("ReadProcessMemory failed for " - "MAP_PRIVATE address %p, %E", - rec->get_address ()); - return -1; - } - if (!VirtualProtectEx (parent, - address, getpagesize (), - PAGE_READONLY, &old_prot)) + system_printf ("ReadProcessMemory failed for " + "MAP_PRIVATE address %p, %E", + rec->get_address ()); + return -1; + } + if (!VirtualProtectEx (parent, + address, getpagesize (), + PAGE_READONLY, &old_prot)) + { + system_printf ("VirtualProtectEx failed for " + "MAP_PRIVATE address %p, %E", + rec->get_address ()); + return -1; + } + else + { + BOOL ret; + DWORD dummy_prot; + + ret = ReadProcessMemory (parent, address, address, + getpagesize (), NULL); + if (!VirtualProtectEx(parent, + address, getpagesize (), + old_prot, &dummy_prot)) + system_printf ("WARNING: VirtualProtectEx to " + "return to previous state " + "in parent failed for " + "MAP_PRIVATE address %p, %E", + rec->get_address ()); + if (!VirtualProtect (address, getpagesize (), + old_prot, &dummy_prot)) + system_printf ("WARNING: VirtualProtect to copy " + "protection to child failed for" + "MAP_PRIVATE address %p, %E", + rec->get_address ()); + if (!ret) { - system_printf ("VirtualProtectEx failed for " + system_printf ("ReadProcessMemory (2nd try) " + "failed for " "MAP_PRIVATE address %p, %E", rec->get_address ()); return -1; } - else - { - BOOL ret; - DWORD dummy_prot; - - ret = ReadProcessMemory (parent, address, address, - getpagesize (), NULL); - if (!VirtualProtectEx(parent, - address, getpagesize (), - old_prot, &dummy_prot)) - system_printf ("WARNING: VirtualProtectEx to " - "return to previous state " - "in parent failed for " - "MAP_PRIVATE address %p, %E", - rec->get_address ()); - if (!VirtualProtect (address, getpagesize (), - old_prot, &dummy_prot)) - system_printf ("WARNING: VirtualProtect to copy " - "protection to child failed for" - "MAP_PRIVATE address %p, %E", - rec->get_address ()); - if (!ret) - { - system_printf ("ReadProcessMemory (2nd try) " - "failed for " - "MAP_PRIVATE address %p, %E", - rec->get_address ()); - return -1; - } - } } - } - rec->fixup_map (); + } } + rec->fixup_page_map (); } } diff --git a/winsup/cygwin/passwd.cc b/winsup/cygwin/passwd.cc index 01e9a6ba163..0c66d993d52 100644 --- a/winsup/cygwin/passwd.cc +++ b/winsup/cygwin/passwd.cc @@ -183,6 +183,7 @@ getpwuid_r32 (__uid32_t uid, struct passwd *pwd, char *buffer, size_t bufsize, s pwd->pw_dir = pwd->pw_name + strlen (temppw->pw_name) + 1; pwd->pw_shell = pwd->pw_dir + strlen (temppw->pw_dir) + 1; pwd->pw_gecos = pwd->pw_shell + strlen (temppw->pw_shell) + 1; + pwd->pw_comment = NULL; pwd->pw_passwd = pwd->pw_gecos + strlen (temppw->pw_gecos) + 1; strcpy (pwd->pw_name, temppw->pw_name); strcpy (pwd->pw_dir, temppw->pw_dir); @@ -240,6 +241,7 @@ getpwnam_r (const char *nam, struct passwd *pwd, char *buffer, size_t bufsize, s pwd->pw_dir = pwd->pw_name + strlen (temppw->pw_name) + 1; pwd->pw_shell = pwd->pw_dir + strlen (temppw->pw_dir) + 1; pwd->pw_gecos = pwd->pw_shell + strlen (temppw->pw_shell) + 1; + pwd->pw_comment = NULL; pwd->pw_passwd = pwd->pw_gecos + strlen (temppw->pw_gecos) + 1; strcpy (pwd->pw_name, temppw->pw_name); strcpy (pwd->pw_dir, temppw->pw_dir); diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index ca8f207f77e..79b521bc1f1 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -3486,6 +3486,10 @@ conv_path_list_buf_size (const char *path_list, bool to_posix) + (num_elms * max_mount_path_len) + (nrel * strlen (to_posix ? pc.normalized_path : pc.get_win32 ())) + 100; + + cfree (pc.normalized_path); // FIXME - probably should be in a destructor but + // it's hard to justify a destructor for the few + // places where this is needed return size; } diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc index 9cb06c48cd6..61ed29d1588 100644 --- a/winsup/cygwin/pinfo.cc +++ b/winsup/cygwin/pinfo.cc @@ -292,18 +292,27 @@ _pinfo::commune_recv () { unsigned n = 1; CloseHandle (__fromthem); __fromthem = NULL; - for (char **a = __argv; *a; a++) - n += strlen (*a) + 1; + extern int __argc_safe; + const char *argv[__argc_safe + 1]; + for (int i = 0; i < __argc_safe; i++) + { + if (IsBadStringPtr (__argv[i], 0x7fffffff)) + argv[i] = ""; + else + argv[i] = __argv[i]; + n += strlen (argv[i]) + 1; + } + argv[__argc_safe] = NULL; if (!WriteFile (__tothem, &n, sizeof n, &nr, NULL)) { /*__seterrno ();*/ // this is run from the signal thread, so don't set errno sigproc_printf ("WriteFile sizeof argv failed, %E"); } else - for (char **a = __argv; *a; a++) + for (const char **a = argv; *a; a++) if (!WriteFile (__tothem, *a, strlen (*a) + 1, &nr, NULL)) { - sigproc_printf ("WriteFile arg %d failed, %E", a - __argv); + sigproc_printf ("WriteFile arg %d failed, %E", a - argv); break; } if (!WriteFile (__tothem, "", 1, &nr, NULL)) diff --git a/winsup/cygwin/pinfo.h b/winsup/cygwin/pinfo.h index 030c7e91b43..9bdcb71c000 100644 --- a/winsup/cygwin/pinfo.h +++ b/winsup/cygwin/pinfo.h @@ -12,14 +12,6 @@ details. */ #define _PINFO_H /* Signal constants (have to define them here, unfortunately) */ -enum -{ - __SIGFLUSH = -2, - __SIGSTRACE = -1, - __SIGCOMMUNE = 0, - __SIGOFFSET = 2 -}; - #define PSIZE 63 #include <sys/resource.h> @@ -119,24 +111,19 @@ public: inline sigset_t& getsigmask () { - return thread2signal ? *thread2signal->sigmask : sig_mask; + return sig_mask; } inline void setsigmask (sigset_t mask) { - if (thread2signal) - *(thread2signal->sigmask) = mask; sig_mask = mask; } - inline LONG* getsigtodo (int sig) {return _sigtodo + __SIGOFFSET + sig;} - inline HANDLE getthread2signal () { - return thread2signal ? thread2signal->win32_obj_id : hMainThread; + return hMainThread; } - inline void setthread2signal (void *thr) {thread2signal = (pthread *) thr;} void commune_recv (); commune_result commune_send (DWORD, ...); bool alive (); @@ -144,10 +131,10 @@ public: friend void __stdcall set_myself (pid_t, HANDLE); + /* signals */ + HANDLE sendsig; private: - sigset_t sig_mask; /* one set for everything to ignore. */ - LONG _sigtodo[NSIG + __SIGOFFSET]; - pthread *thread2signal; // NULL means thread any other means a pthread + sigset_t sig_mask; CRITICAL_SECTION lock; }; diff --git a/winsup/cygwin/pipe.cc b/winsup/cygwin/pipe.cc index a1e99b27e25..242556ad6c4 100644 --- a/winsup/cygwin/pipe.cc +++ b/winsup/cygwin/pipe.cc @@ -76,7 +76,7 @@ fhandler_pipe::read (void *in_ptr, size_t& in_len) ResetEvent (read_state); cygthread *th = new cygthread (read_pipe, &pi, "read_pipe"); if (th->detach (read_state) && !in_len) - (ssize_t) in_len = -1; /* received a signal */ + in_len = (size_t) -1; /* received a signal */ } (void) ReleaseMutex (guard); return; diff --git a/winsup/cygwin/shared.cc b/winsup/cygwin/shared.cc index 1f1145840fa..997e0f622cd 100644 --- a/winsup/cygwin/shared.cc +++ b/winsup/cygwin/shared.cc @@ -145,24 +145,40 @@ open_shared (const char *name, int n, HANDLE &shared_h, DWORD size, shared_locat } void -shared_info::initialize () +shared_info::initialize (const char *user_name) { - if (version) + DWORD sversion = (DWORD) InterlockedExchange ((LONG *) &version, SHARED_VERSION_MAGIC); + if (!sversion) + { + /* Initialize the queue of deleted files. */ + delqueue.init (); + + /* Initialize tty table. */ + tty.init (); + } + else { if (version != SHARED_VERSION_MAGIC) - multiple_cygwin_problem ("shared", version, SHARED_VERSION_MAGIC); - else if (cb != SHARED_INFO_CB) - multiple_cygwin_problem ("shared size", cb, SHARED_INFO_CB); - return; + { + multiple_cygwin_problem ("shared", version, SHARED_VERSION_MAGIC); + InterlockedExchange ((LONG *) &version, sversion); + } + while (!cb) + low_priority_sleep (0); // Should be hit only very very rarely + } + + /* Initialize the Cygwin heap, if necessary */ + if (!cygheap) + { + cygheap_init (); + cygheap->user.set_name (user_name); } - /* Initialize the queue of deleted files. */ - delqueue.init (); + heap_init (); + + if (!sversion) + cb = sizeof (*this); // Do last, after all shared memory initializion - /* Initialize tty table. */ - tty.init (); - version = SHARED_VERSION_MAGIC; - cb = sizeof (*this); if (cb != SHARED_INFO_CB) system_printf ("size of shared memory region changed from %u to %u", SHARED_INFO_CB, cb); @@ -172,6 +188,13 @@ void __stdcall memory_init () { getpagesize (); + + char user_name[UNLEN + 1]; + DWORD user_name_len = UNLEN + 1; + + if (!GetUserName (user_name, &user_name_len)) + strcpy (user_name, "unknown"); + /* Initialize general shared memory */ HANDLE shared_h = cygheap ? cygheap->shared_h : NULL; cygwin_shared = (shared_info *) open_shared ("shared", @@ -180,27 +203,12 @@ memory_init () sizeof (*cygwin_shared), SH_CYGWIN_SHARED); - cygwin_shared->initialize (); - - /* Allocate memory for the per-user mount table */ - char user_name[UNLEN + 1]; - DWORD user_name_len = UNLEN + 1; - - if (!GetUserName (user_name, &user_name_len)) - strcpy (user_name, "unknown"); - - /* Initialize the Cygwin heap, if necessary */ - if (!cygheap) - { - cygheap_init (); - cygheap->user.set_name (user_name); - } + cygwin_shared->initialize (user_name); cygheap->shared_h = shared_h; ProtectHandleINH (cygheap->shared_h); - heap_init (); - + /* Allocate memory for the per-user mount table */ mount_table = (mount_info *) open_shared (user_name, MOUNT_VERSION, cygwin_mount_h, sizeof (mount_info), SH_MOUNT_TABLE); diff --git a/winsup/cygwin/shared_info.h b/winsup/cygwin/shared_info.h index 7014c56daff..b11ecb3ac76 100644 --- a/winsup/cygwin/shared_info.h +++ b/winsup/cygwin/shared_info.h @@ -141,7 +141,7 @@ public: #define SHARED_INFO_CB 47112 -#define CURR_SHARED_MAGIC 0x359218a2U +#define CURR_SHARED_MAGIC 0x53f1a7f4U /* NOTE: Do not make gratuitous changes to the names or organization of the below class. The layout is checksummed to determine compatibility between @@ -156,7 +156,7 @@ class shared_info tty_list tty; delqueue_list delqueue; - void initialize (); + void initialize (const char *); unsigned heap_chunk_size (); }; diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc index 2b890dd624f..a85e151d988 100644 --- a/winsup/cygwin/signal.cc +++ b/winsup/cygwin/signal.cc @@ -17,6 +17,7 @@ details. */ #include <sys/cygwin.h> #include "sigproc.h" #include "pinfo.h" +#include "hires.h" int sigcatchers; /* FIXME: Not thread safe. */ @@ -73,20 +74,22 @@ nanosleep (const struct timespec *rqtp, struct timespec *rmtp) sigframe thisframe (mainthread); pthread_testcancel (); - if (rqtp->tv_sec < 0 || rqtp->tv_nsec < 0 || rqtp->tv_nsec > 999999999) + if ((unsigned int) rqtp->tv_sec > (HIRES_DELAY_MAX / 1000 - 1) + || (unsigned int) rqtp->tv_nsec > 999999999) { set_errno (EINVAL); return -1; } - - DWORD req = rqtp->tv_sec * 1000 + (rqtp->tv_nsec + 500000) / 1000000; - DWORD start_time = GetTickCount (); - DWORD end_time = start_time + req; + DWORD resolution = gtod.resolution (); + DWORD req = ((rqtp->tv_sec * 1000 + (rqtp->tv_nsec + 999999) / 1000000 + + resolution - 1) / resolution ) * resolution; + DWORD end_time = gtod.dmsecs () + req; syscall_printf ("nanosleep (%ld)", req); int rc = pthread::cancelable_wait (signal_arrived, req); - DWORD now = GetTickCount (); - DWORD rem = (rc == WAIT_TIMEOUT || now >= end_time) ? 0 : end_time - now; + DWORD rem; + if ((rem = end_time - gtod.dmsecs ()) > HIRES_DELAY_MAX) + rem = 0; if (rc == WAIT_OBJECT_0) { (void) thisframe.call_signal_handler (); @@ -111,7 +114,7 @@ sleep (unsigned int seconds) req.tv_sec = seconds; req.tv_nsec = 0; nanosleep (&req, &rem); - return rem.tv_sec + (rem.tv_nsec + 500000000) / 1000000000; + return rem.tv_sec + (rem.tv_nsec > 0); } extern "C" unsigned int @@ -179,8 +182,6 @@ kill_worker (pid_t pid, int sig) return -1; } - dest->setthread2signal (NULL); - if ((sendSIGCONT = (sig < 0))) sig = -sig; diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index 6ce58fed804..12ef3be144c 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -28,7 +28,6 @@ details. */ #include "dtable.h" #include "cygheap.h" #include "child_info_magic.h" -#define NEED_VFORK #include "perthread.h" #include "shared_info.h" #include "cygthread.h" @@ -49,14 +48,33 @@ details. */ #define NZOMBIES 256 -static LONG local_sigtodo[TOTSIGS]; -struct sigaction *global_sigs; +class sigelem +{ + int sig; + class sigelem *next; + friend class pending_signals; + friend int __stdcall sig_dispatch_pending (); +}; -inline LONG * -getlocal_sigtodo (int sig) +class pending_signals { - return local_sigtodo + __SIGOFFSET + sig; -} + sigelem sigs[NSIG + 1]; + sigelem start; + sigelem *end; + sigelem *prev; + sigelem *curr; + int empty; +public: + void reset () {curr = &start; prev = &start;} + void add (int sig); + void del (); + int next (); + friend int __stdcall sig_dispatch_pending (); +}; + +static pending_signals sigqueue; + +struct sigaction *global_sigs; void __stdcall sigalloc () @@ -107,20 +125,9 @@ HANDLE NO_COPY signal_arrived; // Event signaled when a signal has 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 @@ -147,13 +154,10 @@ muto NO_COPY *sync_proc_subproc = NULL; // Control access to subproc stuff DWORD NO_COPY sigtid = 0; // ID of the signal thread -static bool NO_COPY pending_signals = false; // true if signals pending - /* Functions */ static int __stdcall checkstate (waitq *) __attribute__ ((regparm (1))); static __inline__ BOOL get_proc_lock (DWORD, DWORD); -static HANDLE __stdcall getevent (_pinfo *, const char *) __attribute__ ((regparm (2))); static void __stdcall remove_zombie (int); static DWORD WINAPI wait_sig (VOID *arg); static int __stdcall stopped_or_terminated (waitq *, _pinfo *); @@ -201,7 +205,6 @@ wait_for_sigthread () { sigproc_printf ("wait_sig_inited %p", wait_sig_inited); HANDLE hsig_inited = wait_sig_inited; - assert (hsig_inited); (void) WaitForSingleObject (hsig_inited, INFINITE); wait_sig_inited = NULL; (void) ForceCloseHandle1 (hsig_inited, wait_sig_inited); @@ -531,56 +534,45 @@ proc_terminate (void) sigproc_printf ("leaving"); } -/* Clear pending signal from the sigtodo array - */ +/* Clear pending signal */ void __stdcall -sig_clear (int sig) +sig_clear (int target_sig) { - (void) InterlockedExchange (myself->getsigtodo (sig), 0L); - (void) InterlockedExchange (getlocal_sigtodo (sig), 0L); + if (GetCurrentThreadId () != sigtid) + sig_send (myself, -target_sig); + else + { + int sig; + sigqueue.reset (); + while ((sig = sigqueue.next ())) + if (sig == target_sig) + { + sigqueue.del (); + break; + } + } return; } extern "C" int -sigpending (sigset_t *set) +sigpending (sigset_t *mask) { - unsigned bit; - *set = 0; - for (int sig = 1; sig < NSIG; sig++) - if ((*getlocal_sigtodo (sig) || *myself->getsigtodo (sig)) - && (myself->getsigmask () & (bit = SIGTOMASK (sig)))) - *set |= bit; + sigset_t outset = (sigset_t) sig_send (myself, __SIGPENDING); + if (outset == SIG_BAD_MASK) + return -1; + *mask = outset; return 0; } -/* Force the wait_sig thread to wake up and scan the sigtodo array. - */ -extern "C" int __stdcall +/* Force the wait_sig thread to wake up and scan for pending signals */ +int __stdcall sig_dispatch_pending () { - if (!hwait_sig || GetCurrentThreadId () == sigtid) + if (!hwait_sig || GetCurrentThreadId () == sigtid || !sigqueue.start.next) return 0; sigframe thisframe (mainthread); - -#ifdef DEBUGGING - sigproc_printf ("pending_signals %d", pending_signals); -#endif - - if (!pending_signals) -#ifdef DEBUGGING - sigproc_printf ("no need to wake anything up"); -#else - ; -#endif - else - { - (void) sig_send (myself, __SIGFLUSH); -#ifdef DEBUGGING - sigproc_printf ("woke up wait_sig"); -#endif - } - + (void) sig_send (myself, __SIGFLUSH); return thisframe.call_signal_handler (); } @@ -642,12 +634,7 @@ sigproc_terminate (void) sig_loop_wait = 0; // Tell wait_sig to exit when it is // finished with anything it is doing 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); + CloseHandle (myself->sendsig); } proc_terminate (); // Terminate process handling thread @@ -665,15 +652,15 @@ 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; + HANDLE sendsig; + 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; + wait_for_completion = false; else { if (no_signals_available ()) @@ -697,74 +684,76 @@ sig_send (_pinfo *p, int sig, DWORD ebp, bool exception) sigproc_printf ("pid %d, signal %d, its_me %d", p->pid, sig, its_me); - LONG *todo; - bool issem; if (its_me) { - if (!wait_for_completion) + if (wait_for_completion) { - thiscatch = sigcatch_nosync; - todo = myself->getsigtodo (sig); - issem = false; + thisframe.set (mainthread, ebp, exception); + thiscomplete = sigcomplete_main; } - else if (tid != mainthread.id) + sendsig = myself->sendsig; + } + else + { + HANDLE hp = OpenProcess (PROCESS_DUP_HANDLE, false, p->dwProcessId); + if (!hp) { - thiscatch = sigcatch_nonmain; - thiscomplete = sigcomplete_nonmain; - todo = getlocal_sigtodo (sig); - issem = true; + __seterrno (); + goto out; } - else + if (!DuplicateHandle (hp, p->sendsig, hMainProc, &sendsig, false, 0, + DUPLICATE_SAME_ACCESS) || !sendsig) { - thiscatch = sigcatch_main; - thiscomplete = sigcomplete_main; - thisframe.set (mainthread, ebp, exception); - todo = getlocal_sigtodo (sig); - issem = true; + __seterrno (); + goto out; } } - else if ((thiscatch = getevent (p, "sigcatch"))) - { - todo = p->getsigtodo (sig); - issem = false; - } - else - goto out; // Couldn't get the semaphore. getevent 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 (todo); - - /* Notify the process that a signal has arrived. - */ - if (issem ? !ReleaseSemaphore (thiscatch, 1, NULL) : !SetEvent (thiscatch)) + DWORD nb; + if (!WriteFile (sendsig, &sig, sizeof (sig), &nb, NULL) || nb != sizeof (sig)) { /* Couldn't signal the semaphore. This probably means that the * process is exiting. */ if (!its_me) - ForceCloseHandle (thiscatch); + { + __seterrno (); + ForceCloseHandle (sendsig); + } 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); + system_printf ("error sending signal %d to pid %d, pipe handle %p, %E", + sig, p->pid, sendsig); } goto out; } + /* Write completion handle or NULL */ + if (!WriteFile (sendsig, &thiscomplete, sizeof (thiscomplete), &nb, NULL) + || nb != sizeof (thiscomplete)) + { + __seterrno (); + goto out; + } + + sigset_t pending; + sigset_t *mask; + if (sig == __SIGPENDING) + mask = &pending; + else if (sig == __SIGFLUSH || sig > 0) + mask = &myself->getsigmask (); + else + mask = NULL; + if (mask && !WriteFile (sendsig, &mask, sizeof (mask), &nb, NULL) + || nb != sizeof (pending)) + { + __seterrno (); + goto out; + } + /* No need to wait for signal completion unless this was a signal to * this process. * @@ -777,7 +766,7 @@ sig_send (_pinfo *p, int sig, DWORD ebp, bool exception) rc = WAIT_OBJECT_0; sigproc_printf ("Not waiting for sigcomplete. its_me %d signal %d", its_me, sig); if (!its_me) - ForceCloseHandle (thiscatch); + ForceCloseHandle (sendsig); } else { @@ -798,19 +787,16 @@ sig_send (_pinfo *p, int sig, DWORD ebp, bool exception) } out: - sigproc_printf ("returning %d from sending signal %d", rc, sig); + if (sig != __SIGPENDING) + /* nothing */; + else if (!rc) + rc = (int) pending; + else + rc = SIG_BAD_MASK; + sigproc_printf ("returning %p from sending signal %d", rc, sig); return rc; } -/* Set pending signal from the sigtodo array - */ -void __stdcall -sig_set_pending (int sig) -{ - (void) InterlockedIncrement (getlocal_sigtodo (sig)); - return; -} - /* Initialize the wait_subproc thread. * Called from fork() or spawn() to initialize the handling of subprocesses. */ @@ -892,71 +878,6 @@ out: return potential_match; } -/* Get or create a process specific semaphore used in message passing. - */ -static HANDLE __stdcall -getevent (_pinfo *p, const char *str) -{ - HANDLE h; - char sem_name[MAX_PATH]; - - 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); - } - - if (p == NULL) - { - char sa_buf[1024]; - - DWORD winpid = GetCurrentProcessId (); -#if 0 - h = CreateSemaphore (sec_user_nih (sa_buf), init, max, - str = shared_name (sem_name, str, winpid)); -#else - h = CreateEvent (sec_user_nih (sa_buf), FALSE, FALSE, - str = shared_name (sem_name, str, winpid)); -#endif - p = myself; - if (!h) - { - system_printf ("can't create semaphore %s, %E", str); - __seterrno (); - } - } - else - { -#if 0 - h = OpenSemaphore (SEMAPHORE_ALL_ACCESS, FALSE, - shared_name (sem_name, str, p->dwProcessId)); -#else - h = OpenEvent (EVENT_ALL_ACCESS, FALSE, - shared_name (sem_name, str, p->dwProcessId)); -#endif - - 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 @@ -1058,62 +979,94 @@ talktome () pids[i]->commune_recv (); } -#define RC_MAIN 0 -#define RC_NONMAIN 1 -#define RC_NOSYNC 2 /* 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. - */ + 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. */ + +void +pending_signals::add (int sig) +{ + sigelem *se; + for (se = start.next; se; se = se->next) + if (se->sig == sig) + return; + while (sigs[empty].sig) + if (++empty == NSIG) + empty = 0; + se = sigs + empty; + se->sig = sig; + se->next = NULL; + if (end) + end->next = se; + end = se; + if (!start.next) + start.next = se; + empty++; +} + +void +pending_signals::del () +{ + sigelem *next = curr->next; + prev->next = next; + curr->sig = 0; +#ifdef DEBUGGING + curr->next = NULL; +#endif + if (end == curr) + end = prev; + empty = curr - sigs; + curr = next; +} + +int +pending_signals::next () +{ + int sig; + prev = curr; + if (!curr || !(curr = curr->next)) + sig = 0; + else + sig = curr->sig; + return sig; +} + +/* Process signals by waiting for signal data to arrive in a pipe. + Set a completion event if one was specified. */ static DWORD WINAPI wait_sig (VOID *self) { - LONG *todos[] = {getlocal_sigtodo (0), myself->getsigtodo (0)}; + HANDLE readsig; + char sa_buf[1024]; + /* 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 = getevent (NULL, "sigcatch"); - 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 - event used to signal main thread on signal + completion */ + if (!CreatePipe (&readsig, &myself->sendsig, sec_user_nih (sa_buf), 0)) + api_fatal ("couldn't create signal pipe, %E"); sigcomplete_main = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL); - sigproc_printf ("sigcatch_nonmain %p, sigcatch_main %p", sigcatch_nonmain, sigcatch_main); + sigproc_printf ("sigcomplete_main %p", sigcomplete_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. - */ + 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. - */ + 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); @@ -1130,149 +1083,82 @@ wait_sig (VOID *self) SetEvent (wait_sig_inited); sigtid = GetCurrentThreadId (); - HANDLE catchem[] = {sigcatch_main, sigcatch_nonmain, sigcatch_nosync}; - sigproc_printf ("Ready. dwProcessid %d", myself->dwProcessId); - DWORD rc = RC_NOSYNC; - bool flush = false; for (;;) { - DWORD i; - if (rc == RC_MAIN || rc == RC_NONMAIN) - i = RC_NOSYNC; - else - i = RC_MAIN; - rc = WaitForSingleObject (catchem[i], 0); - if (rc != WAIT_OBJECT_0) - rc = WaitForMultipleObjects (3, catchem, FALSE, sig_loop_wait); - else - rc = i + WAIT_OBJECT_0; - (void) SetThreadPriority (GetCurrentThread (), WAIT_SIG_PRIORITY); + int sig; + DWORD nb; + if (!ReadFile (readsig, &sig, sizeof (sig), &nb, NULL)) + break; - /* sigproc_terminate sets sig_loop_wait to zero to indicate that - this thread should terminate. */ - if (rc == WAIT_TIMEOUT) + HANDLE wakeup; + if (!ReadFile (readsig, &wakeup, sizeof (wakeup), &nb, NULL) + || nb != sizeof (wakeup)) { - if (!sig_loop_wait) - break; // Exiting - else - continue; + system_printf ("signal notification handle read failure, %E"); + continue; } - if (rc == WAIT_FAILED) + if (!sig) + continue; /* Just checking to see if we exist */ + + sigset_t *mask; + if ((sig == __SIGFLUSH || sig == __SIGPENDING || sig > 0) + && (!ReadFile (readsig, &mask, sizeof (mask), &nb, NULL) + || nb != sizeof (mask))) { - if (sig_loop_wait != 0) - system_printf ("WFMO failed, %E"); - break; + system_printf ("signal mask handle read failure, %E"); + continue; } - rc -= WAIT_OBJECT_0; - sigproc_printf ("awake, rc %d", rc); - LONG *todo; - if (rc != RC_NOSYNC) - todo = todos[0]; - else - todo = todos[1]; - - /* A sigcatch semaphore has been signaled. Scan the sigtodo - array looking for any unprocessed signals. */ - pending_signals = false; - unsigned more_signals = 0; - bool saw_failed_interrupt = false; - do + switch (sig) { - more_signals = 0; - for (int sig = -__SIGOFFSET; sig < NSIG; sig++) + case __SIGCOMMUNE: + talktome (); + continue; + case __SIGSTRACE: + strace.hello (); + continue; + case __SIGPENDING: + *mask = 0; + unsigned bit; + sigqueue.reset (); + while ((sig = sigqueue.next ())) + if (myself->getsigmask () & (bit = SIGTOMASK (sig))) + *mask |= bit; + break; + default: + if (sig > 0) { - LONG x = InterlockedDecrement (todo + sig); - if (x < 0) - InterlockedIncrement (todo + sig); - else if (x >= 0) - { - /* If x > 0, we have to deal with a signal at some later point */ - if (rc != RC_NOSYNC && x > 0) - pending_signals = true; // There should be an armed semaphore, in this case - - 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); - x = InterlockedIncrement (myself->getsigtodo (sig)); - pending_signals = true; - } - else - { - sigproc_printf ("processing signal %d", sig); - switch (sig) - { - case __SIGFLUSH: - if (rc == RC_MAIN) - { - flush = true; - SetEvent (sigcatch_nosync); - goto out1; - } - 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); - if (!sig_handle (sig)) - { - saw_failed_interrupt = true; - x = InterlockedIncrement (myself->getsigtodo (sig)); - pending_signals = true; - } - } - if (rc == RC_NOSYNC && x > 0) - more_signals++; - } - - if (sig == SIGCHLD) - proc_subproc (PROC_CLEARWAIT, 0); - - /* Need to take special action if an interrupt failed due to main thread not - getting around to calling handler yet. */ - if (saw_failed_interrupt || rc != RC_NOSYNC) - goto out; - } + int sh; + for (int i = 0; !(sh = sig_handle (sig, *mask)) && i < 100 ; i++) + low_priority_sleep (0); // hopefully a temporary condition + if (sh <= 0) +{if (!sh) small_printf ("*********sh == 0\n"); + sigqueue.add (sig); // FIXME: Shouldn't add this in !sh condition +} + if (sig == SIGCHLD) + proc_subproc (PROC_CLEARWAIT, 0); } -#ifdef DEBUGGING - if (more_signals > 100) - system_printf ("hmm. infinite loop? more_signals %u\n", more_signals); -#endif - } - while (more_signals && sig_loop_wait); - - out: - /* Signal completion of signal handling depending on which semaphore - woke up the WaitForMultipleObjects above. */ - if (rc == RC_NONMAIN) // FIXME: This is broken - ReleaseSemaphore (sigcomplete_nonmain, 1, NULL); - else if (rc == RC_MAIN || flush) - { - SetEvent (sigcomplete_main); - sigproc_printf ("set main thread completion event"); - flush = false; - } - - out1: - if (saw_failed_interrupt) - { - SetEvent (sigcatch_nosync); - low_priority_sleep (0); /* Hopefully, other thread will be waking up soon. */ + else + { + int target_sig = -sig; + sigqueue.reset (); + while ((sig = sigqueue.next ())) + if (sig == target_sig) + { + sigqueue.del (); + break; + } + } + case __SIGFLUSH: + sigqueue.reset (); + while ((sig = sigqueue.next ())) + if (sig_handle (sig, *mask) > 0) + sigqueue.del (); + break; } - sigproc_printf ("looping"); + if (wakeup) + SetEvent (wakeup); } sigproc_printf ("done"); diff --git a/winsup/cygwin/sigproc.h b/winsup/cygwin/sigproc.h index 360ae8bcba3..4bc9615ce4a 100644 --- a/winsup/cygwin/sigproc.h +++ b/winsup/cygwin/sigproc.h @@ -16,6 +16,18 @@ details. */ #define EXIT_REPARENTING 0x020000 #define EXIT_NOCLOSEALL 0x040000 +#ifdef NSIG +enum +{ + __SIGFLUSH = -(NSIG + 1), + __SIGSTRACE = -(NSIG + 2), + __SIGCOMMUNE = -(NSIG + 3), + __SIGPENDING = -(NSIG + 4) +}; +#endif + +#define SIG_BAD_MASK (1 << (SIGKILL - 1)) + enum procstuff { PROC_ADDCHILD = 1, // add a new subprocess to list @@ -75,10 +87,10 @@ public: if (!oframe) t.get_winapi_lock (); } - inline void init (sigthread &t, DWORD ebp = (DWORD) __builtin_frame_address (0)) + inline void init (sigthread &t, DWORD ebp = (DWORD) __builtin_frame_address (0), bool is_exception = 0) { - if (!t.frame && t.id == GetCurrentThreadId ()) - set (t, ebp); + if (is_exception || (!t.frame && t.id == GetCurrentThreadId ())) + set (t, ebp, is_exception); else st = NULL; } @@ -98,10 +110,10 @@ extern HANDLE signal_arrived; extern HANDLE sigCONT; BOOL __stdcall my_parent_is_alive (); -extern "C" int __stdcall sig_dispatch_pending (); +int __stdcall sig_dispatch_pending (); extern "C" void __stdcall set_process_mask (sigset_t newmask); extern "C" void __stdcall reset_signal_arrived (); -int __stdcall sig_handle (int) __attribute__ ((regparm (1))); +int __stdcall sig_handle (int, sigset_t) __attribute__ ((regparm (2))); void __stdcall sig_clear (int) __attribute__ ((regparm (1))); void __stdcall sig_set_pending (int) __attribute__ ((regparm (1))); int __stdcall handle_sigsuspend (sigset_t); diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 4fd7e7aea64..a3d7a81558e 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -30,6 +30,8 @@ details. */ #include <process.h> #include <utmp.h> #include <sys/uio.h> +#include <errno.h> +#include <ctype.h> #include <limits.h> #include <unistd.h> #include <setjmp.h> @@ -2427,6 +2429,8 @@ chroot (const char *newroot) syscall_printf ("%d = chroot (%s)", ret ? get_errno () : 0, newroot ? newroot : "NULL"); + if (path.normalized_path) + cfree (path.normalized_path); return ret; } @@ -2594,21 +2598,18 @@ ffs (int i) } extern "C" void -login (struct utmp *ut) +updwtmp (const char *wtmp_file, const struct utmp *ut) { - sigframe thisframe (mainthread); - register int fd; - - pututline (ut); - endutent (); /* Writing to wtmp must be atomic to prevent mixed up data. */ char mutex_name[MAX_PATH]; - HANDLE mutex = CreateMutex (NULL, FALSE, - shared_name (mutex_name, "wtmp_mutex", 0)); + HANDLE mutex; + int fd; + + mutex = CreateMutex (NULL, FALSE, shared_name (mutex_name, "wtmp_mutex", 0)); if (mutex) while (WaitForSingleObject (mutex, INFINITE) == WAIT_ABANDONED) ; - if ((fd = open (_PATH_WTMP, O_WRONLY | O_APPEND | O_BINARY, 0)) >= 0) + if ((fd = open (wtmp_file, O_WRONLY | O_APPEND | O_BINARY, 0)) >= 0) { write (fd, ut, sizeof *ut); close (fd); @@ -2620,6 +2621,33 @@ login (struct utmp *ut) } } +extern "C" void +logwtmp (const char *line, const char *user, const char *host) +{ + sigframe thisframe (mainthread); + struct utmp ut; + memset (&ut, 0, sizeof ut); + ut.ut_type = USER_PROCESS; + ut.ut_pid = getpid (); + if (line) + strncpy (ut.ut_line, line, sizeof ut.ut_line); + time (&ut.ut_time); + if (user) + strncpy (ut.ut_user, user, sizeof ut.ut_user); + if (host) + strncpy (ut.ut_host, host, sizeof ut.ut_host); + updwtmp (_PATH_WTMP, &ut); +} + +extern "C" void +login (struct utmp *ut) +{ + sigframe thisframe (mainthread); + pututline (ut); + endutent (); + updwtmp (_PATH_WTMP, ut); +} + extern "C" int logout (char *line) { @@ -2633,29 +2661,11 @@ logout (char *line) if (ut) { - int fd; - ut->ut_type = DEAD_PROCESS; memset (ut->ut_user, 0, sizeof ut->ut_user); time (&ut->ut_time); - /* Writing to wtmp must be atomic to prevent mixed up data. */ - char mutex_name[MAX_PATH]; - HANDLE mutex = CreateMutex (NULL, FALSE, - shared_name (mutex_name, "wtmp_mutex", 0)); - if (mutex) - while (WaitForSingleObject (mutex, INFINITE) == WAIT_ABANDONED) - ; - if ((fd = open (_PATH_WTMP, O_WRONLY | O_APPEND | O_BINARY, 0)) >= 0) - { - write (fd, &ut_buf, sizeof ut_buf); - debug_printf ("set logout time for %s", line); - close (fd); - } - if (mutex) - { - ReleaseMutex (mutex); - CloseHandle (mutex); - } + updwtmp (_PATH_WTMP, &ut_buf); + debug_printf ("set logout time for %s", line); memset (ut->ut_line, 0, sizeof ut_buf.ut_line); ut->ut_time = 0; pututline (ut); @@ -2962,3 +2972,67 @@ long gethostid(void) return hostid; } + +#define ETC_SHELLS "/etc/shells" +static int shell_index; +static FILE *shell_fp; + +extern "C" char * +getusershell () +{ + /* List of default shells if no /etc/shells exists, defined as on Linux. + FIXME: SunOS has a far longer list, containing all shells which + might be shipped with the OS. Should we do the same for the Cygwin + distro, adding bash, tcsh, ksh, pdksh and zsh? */ + static NO_COPY const char *def_shells[] = { + "/bin/sh", + "/bin/csh", + "/usr/bin/sh", + "/usr/bin/csh", + NULL + }; + static char buf[MAX_PATH]; + int ch, buf_idx; + + if (!shell_fp && !(shell_fp = fopen (ETC_SHELLS, "rt"))) + { + if (def_shells[shell_index]) + return strcpy (buf, def_shells[shell_index++]); + return NULL; + } + /* Skip white space characters. */ + while ((ch = getc (shell_fp)) != EOF && isspace (ch)) + ; + /* Get each non-whitespace character as part of the shell path as long as + it fits in buf. */ + for (buf_idx = 0; + ch != EOF && !isspace (ch) && buf_idx < MAX_PATH; + buf_idx++, ch = getc (shell_fp)) + buf[buf_idx] = ch; + /* Skip any trailing non-whitespace character not fitting in buf. If the + path is longer than MAX_PATH, it's invalid anyway. */ + while (ch != EOF && !isspace (ch)) + ch = getc (shell_fp); + if (buf_idx) + { + buf[buf_idx] = '\0'; + return buf; + } + return NULL; +} + +extern "C" void +setusershell () +{ + if (shell_fp) + fseek (shell_fp, 0L, SEEK_SET); + shell_index = 0; +} + +extern "C" void +endusershell () +{ + if (shell_fp) + fclose (shell_fp); + shell_index = 0; +} diff --git a/winsup/cygwin/sysconf.cc b/winsup/cygwin/sysconf.cc index 4c253a1c2e3..b5a2b383de1 100644 --- a/winsup/cygwin/sysconf.cc +++ b/winsup/cygwin/sysconf.cc @@ -69,7 +69,6 @@ sysconf (int in) return 1; /*FALLTHRU*/ case _SC_PHYS_PAGES: - case _SC_AVPHYS_PAGES: if (wincap.supports_smp ()) { NTSTATUS ret; @@ -100,11 +99,27 @@ sysconf (int in) } case _SC_PHYS_PAGES: return sbi.NumberOfPhysicalPages; - case _SC_AVPHYS_PAGES: - return sbi.HighestPhysicalPage - sbi.LowestPhysicalPage + 1; } } break; + case _SC_AVPHYS_PAGES: + if (wincap.supports_smp ()) + { + NTSTATUS ret; + SYSTEM_PERFORMANCE_INFORMATION spi; + if ((ret = NtQuerySystemInformation (SystemPerformanceInformation, + (PVOID) &spi, + sizeof spi, NULL)) + != STATUS_SUCCESS) + { + __seterrno_from_win_error (RtlNtStatusToDosError (ret)); + debug_printf ("NtQuerySystemInformation: ret = %d, " + "Dos(ret) = %d", + ret, RtlNtStatusToDosError (ret)); + return -1; + } + return spi.AvailablePages; + } } /* Invalid input or unimplemented sysconf name */ diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc index 516cb8d2b81..937406a8a48 100644 --- a/winsup/cygwin/thread.cc +++ b/winsup/cygwin/thread.cc @@ -1786,12 +1786,11 @@ pthread::thread_init_wrapper (void *_arg) struct sigaction _sigs[NSIG]; sigset_t _sig_mask; /* one set for everything to ignore. */ - LONG _sigtodo[NSIG + __SIGOFFSET]; // setup signal structures thread->sigs = _sigs; thread->sigmask = &_sig_mask; - thread->sigtodo = _sigtodo; + thread->sigtodo = NULL; memset (&local_winsup, 0, sizeof (struct _winsup_t)); @@ -2784,8 +2783,10 @@ pthread_kill (pthread_t thread, int sig) if (!pthread::is_good_object (&thread)) return EINVAL; +#if 0 if (thread->sigs) myself->setthread2signal (thread); +#endif int rval = raise (sig); @@ -2796,6 +2797,7 @@ pthread_kill (pthread_t thread, int sig) extern "C" int pthread_sigmask (int operation, const sigset_t *set, sigset_t *old_set) { +#if 0 pthread *thread = pthread::self (); // lock this myself, for the use of thread2signal @@ -2803,6 +2805,7 @@ pthread_sigmask (int operation, const sigset_t *set, sigset_t *old_set) if (thread->sigs) myself->setthread2signal (thread); +#endif int rval = sigprocmask (operation, set, old_set); diff --git a/winsup/cygwin/times.cc b/winsup/cygwin/times.cc index 86e9f634356..2def51f45b2 100644 --- a/winsup/cygwin/times.cc +++ b/winsup/cygwin/times.cc @@ -142,11 +142,13 @@ totimeval (struct timeval *dst, FILETIME *src, int sub, int flag) dst->tv_sec = x / (long long) (1e6); } +hires_ms gtod; +UINT NO_COPY hires_ms::minperiod; + /* 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) @@ -620,45 +622,45 @@ hires_us::usecs (bool justdelta) return justdelta ? now.QuadPart : primed_ft.QuadPart + now.QuadPart; } -void +UINT 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); - } + if (!minperiod) + if (timeGetDevCaps (&tc, sizeof (tc)) != TIMERR_NOERROR) + minperiod = 1; + else + { + minperiod = min (max (tc.wPeriodMin, 1), tc.wPeriodMax); + timeBeginPeriod (minperiod); + } - initime_ms = timeGetTime (); - GetSystemTimeAsFileTime (&f); - SetThreadPriority (GetCurrentThread (), priority); + if (!inited) + { + int priority = GetThreadPriority (GetCurrentThread ()); + SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL); + 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; + inited = 1; + initime_us.HighPart = f.dwHighDateTime; + initime_us.LowPart = f.dwLowDateTime; + initime_us.QuadPart -= FACTOR; + initime_us.QuadPart /= 10; + } + return minperiod; } LONGLONG hires_ms::usecs (bool justdelta) { - if (!inited) + if (!minperiod) /* NO_COPY variable */ 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 120ffb5de40..943e9b4f8e9 100644 --- a/winsup/cygwin/tty.cc +++ b/winsup/cygwin/tty.cc @@ -40,6 +40,13 @@ unlockpt (int fd) } extern "C" int +revoke (char *ttyname) +{ + set_errno (ENOSYS); + return -1; +} + +extern "C" int ttyslot (void) { if (NOTSTATE (myself, PID_USETTY)) |