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

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin/pinfo.cc')
-rw-r--r--winsup/cygwin/pinfo.cc1292
1 files changed, 0 insertions, 1292 deletions
diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc
deleted file mode 100644
index 03f85e548..000000000
--- a/winsup/cygwin/pinfo.cc
+++ /dev/null
@@ -1,1292 +0,0 @@
-/* pinfo.cc: process table support
-
- Copyright 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005,
- 2006, 2007, 2008, 2009 Red Hat, Inc.
-
-This file is part of Cygwin.
-
-This software is a copyrighted work licensed under the terms of the
-Cygwin license. Please consult the file "CYGWIN_LICENSE" for
-details. */
-
-#include "winsup.h"
-#include "miscfuncs.h"
-#include <stdlib.h>
-#include "cygerrno.h"
-#include "security.h"
-#include "path.h"
-#include "fhandler.h"
-#include "dtable.h"
-#include "sigproc.h"
-#include "pinfo.h"
-#include "perprocess.h"
-#include "environ.h"
-#include <assert.h>
-#include "ntdll.h"
-#include "shared_info.h"
-#include "cygheap.h"
-#include "cygmalloc.h"
-#include "cygtls.h"
-#include "tls_pbuf.h"
-#include "child_info.h"
-
-class pinfo_basic: public _pinfo
-{
-public:
- pinfo_basic();
-};
-
-pinfo_basic::pinfo_basic()
-{
- pid = dwProcessId = GetCurrentProcessId ();
- GetModuleFileNameW (NULL, progname, sizeof (progname));
-}
-
-pinfo_basic myself_initial NO_COPY;
-
-pinfo NO_COPY myself (static_cast<_pinfo *> (&myself_initial)); // Avoid myself != NULL checks
-
-bool is_toplevel_proc;
-
-/* Setup the pinfo structure for this process. There may already be a
- _pinfo for this "pid" if h != NULL. */
-
-void
-pinfo::thisproc (HANDLE h)
-{
- procinfo = NULL;
-
- if (!h)
- cygheap->pid = cygwin_pid (myself_initial.pid);
-
- init (cygheap->pid, PID_IN_USE, h ?: INVALID_HANDLE_VALUE);
- procinfo->process_state |= PID_IN_USE;
- procinfo->dwProcessId = myself_initial.pid;
- procinfo->sendsig = myself_initial.sendsig;
- wcscpy (procinfo->progname, myself_initial.progname);
- strace.hello ();
- debug_printf ("myself->dwProcessId %u", procinfo->dwProcessId);
- if (h)
- {
- /* here if execed */
- static pinfo NO_COPY myself_identity;
- myself_identity.init (cygwin_pid (procinfo->dwProcessId), PID_EXECED, NULL);
- procinfo->exec_sendsig = NULL;
- procinfo->exec_dwProcessId = 0;
- }
- else if (!child_proc_info) /* child_proc_info is only set when this process
- was started by another cygwin process */
- procinfo->start_time = time (NULL); /* Register our starting time. */
- else if (cygheap->pid_handle)
- {
- ForceCloseHandle (cygheap->pid_handle);
- cygheap->pid_handle = NULL;
- }
-}
-
-/* Initialize the process table entry for the current task.
- This is not called for forked tasks, only execed ones. */
-void __stdcall
-pinfo_init (char **envp, int envc)
-{
- if (envp)
- {
- environ_init (envp, envc);
- /* spawn has already set up a pid structure for us so we'll use that */
- myself->process_state |= PID_CYGPARENT;
- }
- else
- {
- /* Invent our own pid. */
-
- myself.thisproc (NULL);
- myself->ppid = 1;
- myself->pgid = myself->sid = myself->pid;
- myself->ctty = -1;
- myself->uid = ILLEGAL_UID;
- myself->gid = UNKNOWN_GID;
- environ_init (NULL, 0); /* call after myself has been set up */
- myself->nice = winprio_to_nice (GetPriorityClass (GetCurrentProcess ()));
- debug_printf ("Set nice to %d", myself->nice);
- }
-
- myself->process_state |= PID_ACTIVE;
- myself->process_state &= ~(PID_INITIALIZING | PID_EXITED);
- debug_printf ("pid %d, pgid %d", myself->pid, myself->pgid);
-}
-
-static DWORD
-status_exit (DWORD x)
-{
- const char *find_first_notloaded_dll (path_conv &);
- switch (x)
- {
- case STATUS_DLL_NOT_FOUND:
- {
- char posix_prog[NT_MAX_PATH];
- UNICODE_STRING uc;
- RtlInitUnicodeString(&uc, myself->progname);
- path_conv pc (&uc, PC_NOWARN);
- mount_table->conv_to_posix_path (pc.get_win32 (), posix_prog, 1);
- small_printf ("%s: error while loading shared libraries: %s: cannot open shared object file: No such file or directory\n",
- posix_prog, find_first_notloaded_dll (pc));
- x = 127;
- }
- break;
- case STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION: /* custom error value */
- /* We've already printed the error message in pseudo-reloc.c */
- x = 127;
- break;
- default:
- debug_printf ("*** STATUS_%p\n", x);
- x = 127;
- }
- return x;
-}
-
-# define self (*this)
-void
-pinfo::set_exit_code (DWORD x)
-{
- if (x >= 0xc0000000UL)
- x = status_exit (x);
- self->exitcode = EXITCODE_SET | (sigExeced ?: (x & 0xff) << 8);
-}
-
-void
-pinfo::maybe_set_exit_code_from_windows ()
-{
- DWORD x = 0xdeadbeef;
- DWORD oexitcode = self->exitcode;
-
- if (hProcess && !(self->exitcode & EXITCODE_SET))
- {
- WaitForSingleObject (hProcess, INFINITE); /* just to be safe, in case
- process hasn't quite exited
- after closing pipe */
- GetExitCodeProcess (hProcess, &x);
- set_exit_code (x);
- }
- sigproc_printf ("pid %d, exit value - old %p, windows %p, cygwin %p",
- self->pid, oexitcode, x, self->exitcode);
-}
-
-void
-pinfo::exit (DWORD n)
-{
- minimal_printf ("winpid %d, exit %d", GetCurrentProcessId (), n);
- lock_process until_exit ();
- cygthread::terminate ();
-
- if (n != EXITCODE_NOSET)
- self->exitcode = EXITCODE_SET | n;/* We're really exiting. Record the UNIX exit code. */
- else
- {
- exit_state = ES_EXEC_EXIT;
- maybe_set_exit_code_from_windows ();
- }
-
- sigproc_terminate (ES_FINAL);
- if (myself->ctty >= 0 && myself->ctty != TTY_CONSOLE)
- {
- lock_ttys here;
- tty *t = cygwin_shared->tty[myself->ctty];
- if (!t->slave_alive ())
- t->setpgid (0);
- }
-
- /* FIXME: There is a potential race between an execed process and its
- parent here. I hated to add a mutex just for that, though. */
- struct rusage r;
- fill_rusage (&r, GetCurrentProcess ());
- add_rusage (&self->rusage_self, &r);
- int exitcode = self->exitcode & 0xffff;
- if (!self->cygstarted)
- exitcode = ((exitcode & 0xff) << 8) | ((exitcode >> 8) & 0xff);
- sigproc_printf ("Calling ExitProcess n %p, exitcode %p", n, exitcode);
- ExitProcess (exitcode);
-}
-# undef self
-
-void
-pinfo::init (pid_t n, DWORD flag, HANDLE h0)
-{
- shared_locations shloc;
- h = NULL;
- if (myself && !(flag & PID_EXECED)
- && (n == myself->pid || (DWORD) n == myself->dwProcessId))
- {
- procinfo = myself;
- destroy = 0;
- return;
- }
-
- void *mapaddr;
- int createit = flag & (PID_IN_USE | PID_EXECED);
- DWORD access = FILE_MAP_READ
- | (flag & (PID_IN_USE | PID_EXECED | PID_MAP_RW)
- ? FILE_MAP_WRITE : 0);
- if (!h0)
- shloc = (flag & (PID_IN_USE | PID_EXECED)) ? SH_JUSTCREATE : SH_JUSTOPEN;
- else
- {
- shloc = SH_MYSELF;
- if (h0 == INVALID_HANDLE_VALUE)
- h0 = NULL;
- }
-
- procinfo = NULL;
- PSECURITY_ATTRIBUTES sa_buf = (PSECURITY_ATTRIBUTES) alloca (1024);
- PSECURITY_ATTRIBUTES sec_attribs = sec_user_nih (sa_buf, cygheap->user.sid(),
- well_known_world_sid,
- FILE_MAP_READ);
-
- for (int i = 0; i < 20; i++)
- {
- DWORD mapsize;
- if (flag & PID_EXECED)
- mapsize = PINFO_REDIR_SIZE;
- else
- mapsize = sizeof (_pinfo);
-
- procinfo = (_pinfo *) open_shared (L"cygpid", n, h0, mapsize, &shloc,
- sec_attribs, access);
- if (!h0)
- {
- if (createit)
- __seterrno ();
- return;
- }
-
- if (!procinfo)
- {
- if (exit_state)
- return;
-
- switch (GetLastError ())
- {
- case ERROR_INVALID_HANDLE:
- api_fatal ("MapViewOfFileEx h0 %p, i %d failed, %E", h0, i);
- case ERROR_INVALID_ADDRESS:
- mapaddr = NULL;
- }
- debug_printf ("MapViewOfFileEx h0 %p, i %d failed, %E", h0, i);
- yield ();
- continue;
- }
-
- bool created = shloc != SH_JUSTOPEN;
-
- if ((procinfo->process_state & PID_INITIALIZING) && (flag & PID_NOREDIR)
- && cygwin_pid (procinfo->dwProcessId) != procinfo->pid)
- {
- set_errno (ESRCH);
- break;
- }
-
- if (procinfo->process_state & PID_EXECED)
- {
- assert (i == 0);
- pid_t realpid = procinfo->pid;
- debug_printf ("execed process windows pid %d, cygwin pid %d", n, realpid);
- if (realpid == n)
- api_fatal ("retrieval of execed process info for pid %d failed due to recursion.", n);
-
- n = realpid;
- CloseHandle (h0);
- h0 = NULL;
- goto loop;
- }
-
- /* In certain pathological cases, it is possible for the shared memory
- region to exist for a while after a process has exited. This should
- only be a brief occurrence, so rather than introduce some kind of
- locking mechanism, just loop. */
- if (!created && createit && (procinfo->process_state & PID_EXITED))
- {
- debug_printf ("looping because pid %d, procinfo->pid %d, "
- "procinfo->dwProcessid %u has PID_EXITED set",
- n, procinfo->pid, procinfo->dwProcessId);
- goto loop;
- }
-
- if (!created)
- /* nothing */;
- else if (!(flag & PID_EXECED))
- procinfo->pid = n;
- else
- {
- procinfo->process_state |= PID_IN_USE | PID_EXECED;
- procinfo->pid = myself->pid;
- }
-
- h = h0; /* Success! */
- break;
-
- loop:
- release ();
- if (h0)
- yield ();
- }
-
- if (h)
- {
- destroy = 1;
- ProtectHandle1 (h, pinfo_shared_handle);
- }
- else
- {
- h = h0;
- release ();
- }
-}
-
-void
-pinfo::set_acl()
-{
- PACL acl_buf = (PACL) alloca (1024);
- SECURITY_DESCRIPTOR sd;
- NTSTATUS status;
-
- sec_acl (acl_buf, true, true, cygheap->user.sid (),
- well_known_world_sid, FILE_MAP_READ);
- if (!InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION))
- debug_printf ("InitializeSecurityDescriptor %E");
- else if (!SetSecurityDescriptorDacl (&sd, TRUE, acl_buf, FALSE))
- debug_printf ("SetSecurityDescriptorDacl %E");
- else if ((status = NtSetSecurityObject (h, DACL_SECURITY_INFORMATION, &sd)))
- debug_printf ("NtSetSecurityObject %lx", status);
-}
-
-const char *
-_pinfo::_ctty (char *buf)
-{
- if (ctty == TTY_CONSOLE)
- strcpy (buf, "ctty /dev/console");
- else if (ctty < 0)
- strcpy (buf, "no ctty");
- else
- __small_sprintf (buf, "ctty /dev/tty%d", ctty);
- return buf;
-}
-
-void
-_pinfo::set_ctty (tty_min *tc, int flags, fhandler_tty_slave *arch)
-{
- debug_printf ("old %s", __ctty ());
- if ((ctty < 0 || ctty == tc->ntty) && !(flags & O_NOCTTY))
- {
- ctty = tc->ntty;
- lock_ttys here;
- syscall_printf ("attaching %s sid %d, pid %d, pgid %d, tty->pgid %d, tty->sid %d",
- __ctty (), sid, pid, pgid, tc->getpgid (), tc->getsid ());
-
- pinfo p (tc->getsid ());
- if (sid == pid && (!p || p->pid == pid || !p->exists ()))
- {
-#ifdef DEBUGGING
- debug_printf ("resetting %s sid. Was %d, now %d. pgid was %d, now %d.",
- __ctty (), tc->getsid (), sid, tc->getpgid (), pgid);
-#else
- paranoid_printf ("resetting %s sid. Was %d, now %d. pgid was %d, now %d.",
- __ctty (), tc->getsid (), sid, tc->getpgid (), pgid);
-#endif
- /* We are the session leader */
- tc->setsid (sid);
- tc->setpgid (pgid);
- }
- else
- sid = tc->getsid ();
- if (tc->getpgid () == 0)
- tc->setpgid (pgid);
- if (cygheap->ctty != arch)
- {
- debug_printf ("cygheap->ctty %p, arch %p", cygheap->ctty, arch);
- if (!cygheap->ctty)
- syscall_printf ("ctty NULL");
- else
- {
- syscall_printf ("ctty %p, usecount %d", cygheap->ctty,
- cygheap->ctty->usecount);
- cygheap->ctty->close ();
- }
- cygheap->ctty = arch;
- if (arch)
- {
- arch->usecount++;
- /* guard ctty arch */
- cygheap->manage_console_count ("_pinfo::set_ctty", 1);
- report_tty_counts (cygheap->ctty, "ctty", "");
- }
- }
- }
-}
-
-/* Test to determine if a process really exists and is processing signals.
- */
-bool __stdcall
-_pinfo::exists ()
-{
- return this && !(process_state & PID_EXITED);
-}
-
-bool
-_pinfo::alive ()
-{
- HANDLE h = OpenProcess (PROCESS_QUERY_INFORMATION, false, dwProcessId);
- if (h)
- CloseHandle (h);
- return !!h;
-}
-
-DWORD WINAPI
-commune_process (void *arg)
-{
- siginfo_t& si = *((siginfo_t *) arg);
- tmp_pathbuf tp;
- char *path = tp.c_get ();
- DWORD nr;
- HANDLE& tothem = si._si_commune._si_write_handle;
- HANDLE process_sync =
- OpenSemaphore (SYNCHRONIZE, false, shared_name (path, "commune", si.si_pid));
- if (process_sync) // FIXME: this test shouldn't be necessary
- ProtectHandle (process_sync);
-
- lock_process now ();
- if (si._si_commune._si_code & PICOM_EXTRASTR)
- si._si_commune._si_str = (char *) (&si + 1);
-
- switch (si._si_commune._si_code)
- {
- case PICOM_CMDLINE:
- {
- sigproc_printf ("processing PICOM_CMDLINE");
- unsigned n = 0;
- const char *argv[__argc_safe + 1];
-
- for (int i = 0; i < __argc_safe; i++)
- {
- if (IsBadStringPtr (__argv[i], INT32_MAX))
- 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 (const char **a = argv; *a; a++)
- if (!WriteFile (tothem, *a, strlen (*a) + 1, &nr, NULL))
- {
- sigproc_printf ("WriteFile arg %d failed, %E", a - argv);
- break;
- }
- break;
- }
- case PICOM_CWD:
- {
- sigproc_printf ("processing PICOM_CWD");
- unsigned int n = strlen (cygheap->cwd.get (path, 1, 1, NT_MAX_PATH)) + 1;
- if (!WriteFile (tothem, &n, sizeof n, &nr, NULL))
- sigproc_printf ("WriteFile sizeof cwd failed, %E");
- else if (!WriteFile (tothem, path, n, &nr, NULL))
- sigproc_printf ("WriteFile cwd failed, %E");
- break;
- }
- case PICOM_ROOT:
- {
- sigproc_printf ("processing PICOM_ROOT");
- unsigned n;
- if (cygheap->root.exists ())
- n = strlen (strcpy (path, cygheap->root.posix_path ())) + 1;
- else
- n = strlen (strcpy (path, "/")) + 1;
- if (!WriteFile (tothem, &n, sizeof n, &nr, NULL))
- sigproc_printf ("WriteFile sizeof root failed, %E");
- else if (!WriteFile (tothem, path, n, &nr, NULL))
- sigproc_printf ("WriteFile root failed, %E");
- break;
- }
- case PICOM_FDS:
- {
- sigproc_printf ("processing PICOM_FDS");
- unsigned int n = 0;
- int fd;
- cygheap_fdenum cfd;
- while ((fd = cfd.next ()) >= 0)
- n += sizeof (int);
- cfd.rewind ();
- if (!WriteFile (tothem, &n, sizeof n, &nr, NULL))
- sigproc_printf ("WriteFile sizeof fds failed, %E");
- else
- while ((fd = cfd.next ()) >= 0)
- if (!WriteFile (tothem, &fd, sizeof fd, &nr, NULL))
- {
- sigproc_printf ("WriteFile fd %d failed, %E", fd);
- break;
- }
- break;
- }
- case PICOM_PIPE_FHANDLER:
- {
- sigproc_printf ("processing PICOM_FDS");
- HANDLE hdl = si._si_commune._si_pipe_fhandler;
- unsigned int n = 0;
- cygheap_fdenum cfd;
- while (cfd.next () >= 0)
- if (cfd->get_handle () == hdl)
- {
- fhandler_pipe *fh = cfd;
- n = sizeof *fh;
- if (!WriteFile (tothem, &n, sizeof n, &nr, NULL))
- sigproc_printf ("WriteFile sizeof hdl failed, %E");
- else if (!WriteFile (tothem, fh, n, &nr, NULL))
- sigproc_printf ("WriteFile hdl failed, %E");
- break;
- }
- if (!n && !WriteFile (tothem, &n, sizeof n, &nr, NULL))
- sigproc_printf ("WriteFile sizeof hdl failed, %E");
- break;
- }
- case PICOM_FD:
- {
- sigproc_printf ("processing PICOM_FD");
- int fd = si._si_commune._si_fd;
- unsigned int n = 0;
- cygheap_fdget cfd (fd);
- if (cfd < 0)
- n = strlen (strcpy (path, "")) + 1;
- else
- n = strlen (cfd->get_proc_fd_name (path)) + 1;
- if (!WriteFile (tothem, &n, sizeof n, &nr, NULL))
- sigproc_printf ("WriteFile sizeof fd failed, %E");
- else if (!WriteFile (tothem, path, n, &nr, NULL))
- sigproc_printf ("WriteFile fd failed, %E");
- break;
- }
- }
- if (process_sync)
- {
- DWORD res = WaitForSingleObject (process_sync, 5000);
- if (res != WAIT_OBJECT_0)
- sigproc_printf ("WFSO failed - %d, %E", res);
- else
- sigproc_printf ("synchronized with pid %d", si.si_pid);
- ForceCloseHandle (process_sync);
- }
- CloseHandle (tothem);
- _my_tls._ctinfo->auto_release ();
- return 0;
-}
-
-commune_result
-_pinfo::commune_request (__uint32_t code, ...)
-{
- DWORD nr;
- commune_result res;
- va_list args;
- siginfo_t si = {0};
- HANDLE& hp = si._si_commune._si_process_handle;
- HANDLE& fromthem = si._si_commune._si_read_handle;
- HANDLE request_sync = NULL;
- bool locked = false;
-
- res.s = NULL;
- res.n = 0;
-
- if (!this || !pid)
- {
- set_errno (ESRCH);
- goto err;
- }
-
- va_start (args, code);
- si._si_commune._si_code = code;
- switch (code)
- {
- case PICOM_PIPE_FHANDLER:
- si._si_commune._si_pipe_fhandler = va_arg (args, HANDLE);
- break;
-
- case PICOM_FD:
- si._si_commune._si_fd = va_arg (args, int);
- break;
-
- break;
- }
- va_end (args);
-
- locked = true;
- char name_buf[MAX_PATH];
- request_sync = CreateSemaphore (&sec_none_nih, 0, LONG_MAX,
- shared_name (name_buf, "commune", myself->pid));
- if (!request_sync)
- goto err;
- ProtectHandle (request_sync);
-
- si.si_signo = __SIGCOMMUNE;
- if (sig_send (this, si))
- {
- ForceCloseHandle (request_sync); /* don't signal semaphore since there was apparently no receiving process */
- request_sync = NULL;
- goto err;
- }
-
- size_t n;
- switch (code)
- {
- case PICOM_CMDLINE:
- case PICOM_CWD:
- case PICOM_ROOT:
- case PICOM_FDS:
- case PICOM_FD:
- case PICOM_PIPE_FHANDLER:
- if (!ReadFile (fromthem, &n, sizeof n, &nr, NULL) || nr != sizeof n)
- {
- __seterrno ();
- goto err;
- }
- if (!n)
- res.s = NULL;
- else
- {
- res.s = (char *) cmalloc_abort (HEAP_COMMUNE, n);
- char *p;
- for (p = res.s; n && ReadFile (fromthem, p, n, &nr, NULL); p += nr, n -= nr)
- continue;
- if (n)
- {
- __seterrno ();
- goto err;
- }
- res.n = p - res.s;
- }
- break;
- }
- goto out;
-
-err:
- memset (&res, 0, sizeof (res));
-
-out:
- if (request_sync)
- {
- LONG res;
- ReleaseSemaphore (request_sync, 1, &res);
- ForceCloseHandle (request_sync);
- }
- if (hp)
- CloseHandle (hp);
- if (fromthem)
- CloseHandle (fromthem);
- return res;
-}
-
-fhandler_pipe *
-_pinfo::pipe_fhandler (HANDLE hdl, size_t &n)
-{
- if (!this || !pid)
- return NULL;
- if (pid == myself->pid)
- return NULL;
- commune_result cr = commune_request (PICOM_PIPE_FHANDLER, hdl);
- n = cr.n;
- return (fhandler_pipe *) cr.s;
-}
-
-char *
-_pinfo::fd (int fd, size_t &n)
-{
- char *s;
- if (!this || !pid)
- return NULL;
- if (pid != myself->pid)
- {
- commune_result cr = commune_request (PICOM_FD, fd);
- s = cr.s;
- n = cr.n;
- }
- else
- {
- cygheap_fdget cfd (fd);
- if (cfd < 0)
- s = cstrdup ("");
- else
- s = cfd->get_proc_fd_name ((char *) cmalloc_abort (HEAP_COMMUNE, NT_MAX_PATH));
- n = strlen (s) + 1;
- }
- return s;
-}
-
-char *
-_pinfo::fds (size_t &n)
-{
- char *s;
- if (!this || !pid)
- return NULL;
- if (pid != myself->pid)
- {
- commune_result cr = commune_request (PICOM_FDS);
- s = cr.s;
- n = cr.n;
- }
- else
- {
- n = 0;
- int fd;
- cygheap_fdenum cfd (true);
- while ((fd = cfd.next ()) >= 0)
- n += sizeof (int);
- cfd.rewind ();
- s = (char *) cmalloc_abort (HEAP_COMMUNE, n);
- int *p = (int *) s;
- while ((fd = cfd.next ()) >= 0 && (char *) p - s < (int) n)
- *p++ = fd;
- }
- return s;
-}
-
-char *
-_pinfo::root (size_t& n)
-{
- char *s;
- if (!this || !pid)
- return NULL;
- if (pid != myself->pid)
- {
- commune_result cr = commune_request (PICOM_ROOT);
- s = cr.s;
- n = cr.n;
- }
- else
- {
- if (cygheap->root.exists ())
- s = cstrdup (cygheap->root.posix_path ());
- else
- s = cstrdup ("/");
- n = strlen (s) + 1;
- }
- return s;
-}
-
-char *
-_pinfo::cwd (size_t& n)
-{
- char *s;
- if (!this || !pid)
- return NULL;
- if (pid != myself->pid)
- {
- commune_result cr = commune_request (PICOM_CWD);
- s = cr.s;
- n = cr.n;
- }
- else
- {
- s = (char *) cmalloc_abort (HEAP_COMMUNE, NT_MAX_PATH);
- cygheap->cwd.get (s, 1, 1, NT_MAX_PATH);
- n = strlen (s) + 1;
- }
- return s;
-}
-
-char *
-_pinfo::cmdline (size_t& n)
-{
- char *s;
- if (!this || !pid)
- return NULL;
- if (pid != myself->pid)
- {
- commune_result cr = commune_request (PICOM_CMDLINE);
- s = cr.s;
- n = cr.n;
- }
- else
- {
- n = 0;
- for (char **a = __argv; *a; a++)
- n += strlen (*a) + 1;
- char *p;
- p = s = (char *) cmalloc_abort (HEAP_COMMUNE, n);
- for (char **a = __argv; *a; a++)
- {
- strcpy (p, *a);
- p = strchr (p, '\0') + 1;
- }
- }
- return s;
-}
-
-/* This is the workhorse which waits for the write end of the pipe
- created during new process creation. If the pipe is closed or a zero
- is received on the pipe, it is assumed that the cygwin pid has exited.
- Otherwise, various "signals" can be sent to the parent to inform the
- parent to perform a certain action. */
-static DWORD WINAPI
-proc_waiter (void *arg)
-{
- pinfo vchild = *(pinfo *) arg;
- ((pinfo *) arg)->waiter_ready = true;
-
- siginfo_t si = {0};
- si.si_signo = SIGCHLD;
- si.si_code = CLD_EXITED;
- si.si_pid = vchild->pid;
-#if 0 // FIXME: This is tricky to get right
- si.si_utime = pchildren[rc]->rusage_self.ru_utime;
- si.si_stime = pchildren[rc].rusage_self.ru_stime;
-#endif
- pid_t pid = vchild->pid;
-
- for (;;)
- {
- DWORD nb;
- char buf = '\0';
-
- if (!ReadFile (vchild.rd_proc_pipe, &buf, 1, &nb, NULL)
- && GetLastError () != ERROR_BROKEN_PIPE)
- {
- system_printf ("error on read of child wait pipe %p, %E", vchild.rd_proc_pipe);
- break;
- }
-
- si.si_uid = vchild->uid;
-
- switch (buf)
- {
- case __ALERT_ALIVE:
- continue;
- case 0:
- /* Child exited. Do some cleanup and signal myself. */
- CloseHandle (vchild.rd_proc_pipe);
- vchild.rd_proc_pipe = NULL;
- vchild.maybe_set_exit_code_from_windows ();
- if (WIFEXITED (vchild->exitcode))
- si.si_code = CLD_EXITED;
- else if (WCOREDUMP (vchild->exitcode))
- si.si_code = CLD_DUMPED;
- else
- si.si_code = CLD_KILLED;
- si.si_status = vchild->exitcode;
- vchild->process_state = PID_EXITED;
- /* This should always be last. Do not use vchild-> beyond this point */
- break;
- case SIGTTIN:
- case SIGTTOU:
- case SIGTSTP:
- case SIGSTOP:
- if (ISSTATE (myself, PID_NOCLDSTOP)) // FIXME: No need for this flag to be in _pinfo any longer
- continue;
- /* Child stopped. Signal myself. */
- si.si_code = CLD_STOPPED;
- break;
- case SIGCONT:
- continue;
- default:
- system_printf ("unknown value %d on proc pipe", buf);
- continue;
- }
-
- /* Special case: If the "child process" that died is us, then we're
- execing. Just call proc_subproc directly and then exit this loop.
- We're done here. */
- if (hExeced)
- {
- /* execing. no signals available now. */
- proc_subproc (PROC_CLEARWAIT, 0);
- break;
- }
-
- /* Send a SIGCHLD to myself. We do this here, rather than in proc_subproc
- to avoid the proc_subproc lock since the signal thread will eventually
- be calling proc_subproc and could unnecessarily block. */
- sig_send (myself_nowait, si);
-
- /* If we're just stopped or got a continue signal, keep looping.
- Otherwise, return this thread to the pool. */
- if (buf != '\0')
- sigproc_printf ("looping");
- else
- break;
- }
-
- sigproc_printf ("exiting wait thread for pid %d", pid);
- vchild.wait_thread = NULL;
- _my_tls._ctinfo->auto_release (); /* automatically return the cygthread to the cygthread pool */
- return 0;
-}
-
-HANDLE
-_pinfo::dup_proc_pipe (HANDLE hProcess)
-{
- DWORD flags = DUPLICATE_SAME_ACCESS;
- HANDLE orig_wr_proc_pipe = wr_proc_pipe;
- /* Can't set DUPLICATE_CLOSE_SOURCE for exec case because we could be
- execing a non-cygwin process and we need to set the exit value before the
- parent sees it. */
- if (this != myself || is_toplevel_proc)
- flags |= DUPLICATE_CLOSE_SOURCE;
- bool res = DuplicateHandle (GetCurrentProcess (), wr_proc_pipe,
- hProcess, &wr_proc_pipe, 0, FALSE, flags);
- if (!res && WaitForSingleObject (hProcess, 0) != WAIT_OBJECT_0)
- {
- wr_proc_pipe = orig_wr_proc_pipe;
- system_printf ("DuplicateHandle failed, pid %d, hProcess %p, wr_proc_pipe %p, %E",
- pid, hProcess, wr_proc_pipe);
- }
- else
- {
- wr_proc_pipe_owner = dwProcessId;
- sigproc_printf ("duped wr_proc_pipe %p for pid %d(%u)", wr_proc_pipe,
- pid, dwProcessId);
- }
- return orig_wr_proc_pipe;
-}
-
-/* function to set up the process pipe and kick off proc_waiter */
-int
-pinfo::wait ()
-{
- /* FIXME: execed processes should be able to wait for pids that were started
- by the process which execed them. */
- if (!CreatePipe (&rd_proc_pipe, &((*this)->wr_proc_pipe), &sec_none_nih, 16))
- {
- system_printf ("Couldn't create pipe tracker for pid %d, %E",
- (*this)->pid);
- return 0;
- }
-
- if (!(*this)->dup_proc_pipe (hProcess))
- {
- system_printf ("Couldn't duplicate pipe topid %d(%p), %E", (*this)->pid, hProcess);
- return 0;
- }
-
- preserve (); /* Preserve the shared memory associated with the pinfo */
-
- waiter_ready = false;
- /* Fire up a new thread to track the subprocess */
- cygthread *h = new cygthread (proc_waiter, this, "proc_waiter");
- if (!h)
- sigproc_printf ("tracking thread creation failed for pid %d", (*this)->pid);
- else
- {
- wait_thread = h;
- sigproc_printf ("created tracking thread for pid %d, winpid %p, rd_pipe %p",
- (*this)->pid, (*this)->dwProcessId, rd_proc_pipe);
- }
-
- return 1;
-}
-
-void
-_pinfo::sync_proc_pipe ()
-{
- if (wr_proc_pipe && wr_proc_pipe != INVALID_HANDLE_VALUE)
- while (wr_proc_pipe_owner != GetCurrentProcessId ())
- yield ();
-}
-
-/* function to send a "signal" to the parent when something interesting happens
- in the child. */
-bool
-_pinfo::alert_parent (char sig)
-{
- DWORD nb = 0;
-
- /* Send something to our parent. If the parent has gone away, close the pipe.
- Don't send if this is an exec stub.
-
- FIXME: Is there a race here if we run this while another thread is attempting
- to exec()? */
- if (wr_proc_pipe == INVALID_HANDLE_VALUE || !myself->wr_proc_pipe || hExeced)
- /* no parent */;
- else
- {
- sync_proc_pipe ();
- if (WriteFile (wr_proc_pipe, &sig, 1, &nb, NULL))
- /* all is well */;
- else if (GetLastError () != ERROR_BROKEN_PIPE)
- debug_printf ("sending %d notification to parent failed, %E", sig);
- else
- {
- ppid = 1;
- HANDLE closeit = wr_proc_pipe;
- wr_proc_pipe = INVALID_HANDLE_VALUE;
- CloseHandle (closeit);
- }
- }
- return (bool) nb;
-}
-
-void
-pinfo::release ()
-{
- if (procinfo)
- {
- void *unmap_procinfo = procinfo;
- procinfo = NULL;
- UnmapViewOfFile (unmap_procinfo);
- }
- if (h)
- {
- HANDLE close_h = h;
- h = NULL;
- ForceCloseHandle1 (close_h, pinfo_shared_handle);
- }
-}
-
-/* DOCTOOL-START
-
-<sect1 id="func-cygwin-winpid-to-pid">
- <title>cygwin_winpid_to_pid</title>
-
- <funcsynopsis><funcprototype>
- <funcdef>extern "C" pid_t
- <function>cygwin_winpid_to_pid</function>
- </funcdef>
- <paramdef>int <parameter>winpid</parameter></paramdef>
- </funcprototype></funcsynopsis>
-
- <para>Given a windows pid, converts to the corresponding Cygwin
-pid, if any. Returns -1 if windows pid does not correspond to
-a cygwin pid.</para>
- <example>
- <title>Example use of cygwin_winpid_to_pid</title>
- <programlisting>
- extern "C" cygwin_winpid_to_pid (int winpid);
- pid_t mypid;
- mypid = cygwin_winpid_to_pid (windows_pid);
- </programlisting>
- </example>
-</sect1>
-
- DOCTOOL-END */
-
-extern "C" pid_t
-cygwin_winpid_to_pid (int winpid)
-{
- pinfo p (cygwin_pid (winpid));
- if (p)
- return p->pid;
-
- set_errno (ESRCH);
- return (pid_t) -1;
-}
-
-
-#define slop_pidlist 200
-#define size_pidlist(i) (sizeof (pidlist[0]) * ((i) + 1))
-#define size_pinfolist(i) (sizeof (pinfolist[0]) * ((i) + 1))
-class _onreturn
-{
- HANDLE *h;
-public:
- ~_onreturn ()
- {
- if (h && *h)
- {
- CloseHandle (*h);
- *h = NULL;
- h = NULL;
- }
- }
- void no_close_p_handle () {h = NULL;}
- _onreturn (HANDLE& _h): h (&_h) {}
-};
-
-inline void
-winpids::add (DWORD& nelem, bool winpid, DWORD pid)
-{
- pid_t cygpid = cygwin_pid (pid);
-
- if (nelem >= npidlist)
- {
- npidlist += slop_pidlist;
- pidlist = (DWORD *) realloc (pidlist, size_pidlist (npidlist + 1));
- pinfolist = (pinfo *) realloc (pinfolist, size_pinfolist (npidlist + 1));
- }
-
- pinfo& p = pinfolist[nelem];
-
- /* Open a the process to prevent a subsequent exit from invalidating the
- shared memory region. */
- p.hProcess = OpenProcess (PROCESS_QUERY_INFORMATION, false, pid);
- _onreturn onreturn (p.hProcess);
-
- /* If we couldn't open the process then we don't have rights to it and should
- make a copy of the shared memory area if it exists (it may not).
- */
- bool perform_copy;
- if (!p.hProcess)
- perform_copy = true;
- else
- perform_copy = make_copy;
-
- p.init (cygpid, PID_NOREDIR | pinfo_access, NULL);
-
- /* If we're just looking for winpids then don't do any special cygwin "stuff* */
- if (winpid)
- goto out;
-
- /* !p means that we couldn't find shared memory for this pid. Probably means
- that it isn't a cygwin process. */
- if (!p)
- {
- if (!pinfo_access)
- return;
- p.init (cygpid, PID_NOREDIR, NULL);
- if (!p)
- return;
- }
-
- /* Scan list of previously recorded pids to make sure that this pid hasn't
- shown up before. This can happen when a process execs. */
- for (unsigned i = 0; i < nelem; i++)
- if (pinfolist[i]->pid == p->pid)
- {
- if ((_pinfo *) p != (_pinfo *) myself)
- p.release ();
- return;
- }
-
-out:
- /* Exit here.
-
- If p is "false" then, eventually any opened process handle will be closed and
- the function will exit without adding anything to the pid list.
-
- If p is "true" then we've discovered a cygwin process.
-
- Handle "myself" differently. Don't copy it and close/zero the handle we
- just opened to it.
- If not performing a copy, then keep the process handle open for the duration
- of the life of the procinfo region to potential races when a new process uses
- this pid.
- Otherwise, malloc some memory for a copy of the shared memory.
-
- If the malloc failed, then "oh well". Just keep the shared memory around
- and eventually close the handle when the winpids goes out of scope.
-
- If malloc succeeds, copy the procinfo we just grabbed into the new region,
- release the shared memory and allow the handle to be closed when this
- function returns.
-
- Oh, and add the pid to the list and bump the number of elements. */
-
- if (p)
- {
- if (p == (_pinfo *) myself)
- /* handle specially. Close the handle but (eventually) don't
- deallocate procinfo in release call */;
- else if (!perform_copy)
- onreturn.no_close_p_handle (); /* Don't close the handle until release */
- else
- {
- _pinfo *pnew = (_pinfo *) malloc (sizeof (*p.procinfo));
- if (!pnew)
- onreturn.no_close_p_handle ();
- else
- {
- *pnew = *p.procinfo;
- if ((_pinfo *) p != (_pinfo *) myself)
- p.release ();
- p.procinfo = pnew;
- p.destroy = false;
- }
- }
- }
- if (p || winpid)
- pidlist[nelem++] = pid;
-}
-
-DWORD
-winpids::enum_processes (bool winpid)
-{
- static DWORD szprocs;
- static SYSTEM_PROCESSES *procs;
-
- DWORD nelem = 0;
- if (!szprocs)
- procs = (SYSTEM_PROCESSES *) malloc (sizeof (*procs) + (szprocs = 200 * sizeof (*procs)));
-
- NTSTATUS res;
- for (;;)
- {
- res = NtQuerySystemInformation (SystemProcessesAndThreadsInformation,
- procs, szprocs, NULL);
- if (res == 0)
- break;
-
- if (res == STATUS_INFO_LENGTH_MISMATCH)
- procs = (SYSTEM_PROCESSES *) realloc (procs, szprocs += 200 * sizeof (*procs));
- else
- {
- system_printf ("error %p reading system process information", res);
- return 0;
- }
- }
-
- SYSTEM_PROCESSES *px = procs;
- for (;;)
- {
- if (px->ProcessId)
- add (nelem, winpid, px->ProcessId);
- if (!px->NextEntryDelta)
- break;
- px = (SYSTEM_PROCESSES *) ((char *) px + px->NextEntryDelta);
- }
-
- return nelem;
-}
-
-void
-winpids::set (bool winpid)
-{
- __malloc_lock ();
- npids = enum_processes (winpid);
- if (pidlist)
- pidlist[npids] = 0;
- __malloc_unlock ();
-}
-
-DWORD
-winpids::enum_init (bool winpid)
-{
- return enum_processes (winpid);
-}
-
-void
-winpids::release ()
-{
- _pinfo *p;
- for (unsigned i = 0; i < npids; i++)
- if (pinfolist[i] == (_pinfo *) myself)
- continue;
- else if (pinfolist[i].hProcess)
- {
- if (pinfolist[i])
- pinfolist[i].release ();
- CloseHandle (pinfolist[i].hProcess);
- }
- else if ((p = pinfolist[i]))
- {
- pinfolist[i].procinfo = NULL;
- free (p);
- }
-}
-
-winpids::~winpids ()
-{
- if (npidlist)
- {
- release ();
- free (pidlist);
- free (pinfolist);
- }
-}