OSDN Git Service

* dcrt0.cc (dll_crt0_0): Remove myself settings.
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / pinfo.cc
1 /* pinfo.cc: process table support
2
3    Copyright 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005,
4    2006, 2007, 2008, 2009 Red Hat, Inc.
5
6 This file is part of Cygwin.
7
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
10 details. */
11
12 #include "winsup.h"
13 #include "miscfuncs.h"
14 #include <stdlib.h>
15 #include "cygerrno.h"
16 #include "security.h"
17 #include "path.h"
18 #include "fhandler.h"
19 #include "dtable.h"
20 #include "sigproc.h"
21 #include "pinfo.h"
22 #include "perprocess.h"
23 #include "environ.h"
24 #include <assert.h>
25 #include "ntdll.h"
26 #include "shared_info.h"
27 #include "cygheap.h"
28 #include "cygmalloc.h"
29 #include "cygtls.h"
30 #include "tls_pbuf.h"
31 #include "child_info.h"
32
33 class pinfo_basic: public _pinfo
34 {
35 public:
36   pinfo_basic();
37 };
38
39 pinfo_basic::pinfo_basic()
40 {
41   pid = dwProcessId = GetCurrentProcessId ();
42   GetModuleFileNameW (NULL, progname, sizeof (progname));
43 }
44
45 pinfo_basic myself_initial NO_COPY;
46
47 pinfo NO_COPY myself (static_cast<_pinfo *> (&myself_initial)); // Avoid myself != NULL checks
48
49 bool is_toplevel_proc;
50
51 /* Setup the pinfo structure for this process.  There may already be a
52    _pinfo for this "pid" if h != NULL. */
53
54 void
55 pinfo::thisproc (HANDLE h)
56 {
57   procinfo = NULL;
58
59   if (!h)
60     cygheap->pid = cygwin_pid (myself_initial.pid);
61
62   init (cygheap->pid, PID_IN_USE, h ?: INVALID_HANDLE_VALUE);
63   procinfo->process_state |= PID_IN_USE;
64   procinfo->dwProcessId = myself_initial.pid;
65   procinfo->sendsig = myself_initial.sendsig;
66   wcscpy (procinfo->progname, myself_initial.progname);
67   strace.hello ();
68   debug_printf ("myself->dwProcessId %u", procinfo->dwProcessId);
69   if (h)
70     {
71       /* here if execed */
72       static pinfo NO_COPY myself_identity;
73       myself_identity.init (cygwin_pid (procinfo->dwProcessId), PID_EXECED, NULL);
74       procinfo->exec_sendsig = NULL;
75       procinfo->exec_dwProcessId = 0;
76     }
77   else if (!child_proc_info)    /* child_proc_info is only set when this process
78                                    was started by another cygwin process */
79     procinfo->start_time = time (NULL); /* Register our starting time. */
80   else if (cygheap->pid_handle)
81     {
82       ForceCloseHandle (cygheap->pid_handle);
83       cygheap->pid_handle = NULL;
84     }
85 }
86
87 /* Initialize the process table entry for the current task.
88    This is not called for forked tasks, only execed ones.  */
89 void __stdcall
90 pinfo_init (char **envp, int envc)
91 {
92   if (envp)
93     {
94       environ_init (envp, envc);
95       /* spawn has already set up a pid structure for us so we'll use that */
96       myself->process_state |= PID_CYGPARENT;
97     }
98   else
99     {
100       /* Invent our own pid.  */
101
102       myself.thisproc (NULL);
103       myself->ppid = 1;
104       myself->pgid = myself->sid = myself->pid;
105       myself->ctty = -1;
106       myself->uid = ILLEGAL_UID;
107       myself->gid = UNKNOWN_GID;
108       environ_init (NULL, 0);   /* call after myself has been set up */
109       myself->nice = winprio_to_nice (GetPriorityClass (GetCurrentProcess ()));
110       debug_printf ("Set nice to %d", myself->nice);
111     }
112
113   myself->process_state |= PID_ACTIVE;
114   myself->process_state &= ~(PID_INITIALIZING | PID_EXITED);
115   debug_printf ("pid %d, pgid %d", myself->pid, myself->pgid);
116 }
117
118 static DWORD
119 status_exit (DWORD x)
120 {
121   const char *find_first_notloaded_dll (path_conv &);
122   switch (x)
123     {
124     case STATUS_DLL_NOT_FOUND:
125       {
126         char posix_prog[NT_MAX_PATH];
127         UNICODE_STRING uc;
128         RtlInitUnicodeString(&uc, myself->progname);
129         path_conv pc (&uc, PC_NOWARN);
130         mount_table->conv_to_posix_path (pc.get_win32 (), posix_prog, 1);
131         small_printf ("%s: error while loading shared libraries: %s: cannot open shared object file: No such file or directory\n",
132                       posix_prog, find_first_notloaded_dll (pc));
133         x = 127;
134       }
135       break;
136     case STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION: /* custom error value */
137       /* We've already printed the error message in pseudo-reloc.c */
138       x = 127;
139       break;
140     default:
141       x = 127;
142     }
143   return x;
144 }
145
146 # define self (*this)
147 void
148 pinfo::set_exit_code (DWORD x)
149 {
150   if (x >= 0xc0000000UL)
151     x = status_exit (x);
152   self->exitcode = EXITCODE_SET | (sigExeced ?: (x & 0xff) << 8);
153 }
154
155 void
156 pinfo::maybe_set_exit_code_from_windows ()
157 {
158   DWORD x = 0xdeadbeef;
159   DWORD oexitcode = self->exitcode;
160
161   if (hProcess && !(self->exitcode & EXITCODE_SET))
162     {
163       WaitForSingleObject (hProcess, INFINITE); /* just to be safe, in case
164                                                    process hasn't quite exited
165                                                    after closing pipe */
166       GetExitCodeProcess (hProcess, &x);
167       set_exit_code (x);
168     }
169   sigproc_printf ("pid %d, exit value - old %p, windows %p, cygwin %p",
170                   self->pid, oexitcode, x, self->exitcode);
171 }
172
173 void
174 pinfo::exit (DWORD n)
175 {
176   minimal_printf ("winpid %d, exit %d", GetCurrentProcessId (), n);
177   lock_process until_exit ();
178   cygthread::terminate ();
179
180   if (n != EXITCODE_NOSET)
181     self->exitcode = EXITCODE_SET | n;/* We're really exiting.  Record the UNIX exit code. */
182   else
183     {
184       exit_state = ES_EXEC_EXIT;
185       maybe_set_exit_code_from_windows ();
186     }
187
188   sigproc_terminate (ES_FINAL);
189
190   /* FIXME:  There is a potential race between an execed process and its
191      parent here.  I hated to add a mutex just for that, though.  */
192   struct rusage r;
193   fill_rusage (&r, GetCurrentProcess ());
194   add_rusage (&self->rusage_self, &r);
195   int exitcode = self->exitcode & 0xffff;
196   if (!self->cygstarted)
197     exitcode = ((exitcode & 0xff) << 8) | ((exitcode >> 8) & 0xff);
198   sigproc_printf ("Calling ExitProcess n %p, exitcode %p", n, exitcode);
199   ExitProcess (exitcode);
200 }
201 # undef self
202
203 void
204 pinfo::init (pid_t n, DWORD flag, HANDLE h0)
205 {
206   shared_locations shloc;
207   h = NULL;
208   if (myself && !(flag & PID_EXECED)
209       && (n == myself->pid || (DWORD) n == myself->dwProcessId))
210     {
211       procinfo = myself;
212       destroy = 0;
213       return;
214     }
215
216   void *mapaddr;
217   int createit = flag & (PID_IN_USE | PID_EXECED);
218   DWORD access = FILE_MAP_READ
219                  | (flag & (PID_IN_USE | PID_EXECED | PID_MAP_RW)
220                     ? FILE_MAP_WRITE : 0);
221   if (!h0)
222     shloc = (flag & (PID_IN_USE | PID_EXECED)) ? SH_JUSTCREATE : SH_JUSTOPEN;
223   else
224     {
225       shloc = SH_MYSELF;
226       if (h0 == INVALID_HANDLE_VALUE)
227         h0 = NULL;
228     }
229
230   procinfo = NULL;
231   PSECURITY_ATTRIBUTES sa_buf = (PSECURITY_ATTRIBUTES) alloca (1024);
232   PSECURITY_ATTRIBUTES sec_attribs = sec_user_nih (sa_buf, cygheap->user.sid(),
233                                                    well_known_world_sid,
234                                                    FILE_MAP_READ);
235
236   for (int i = 0; i < 20; i++)
237     {
238       DWORD mapsize;
239       if (flag & PID_EXECED)
240         mapsize = PINFO_REDIR_SIZE;
241       else
242         mapsize = sizeof (_pinfo);
243
244       procinfo = (_pinfo *) open_shared (L"cygpid", n, h0, mapsize, &shloc,
245                                          sec_attribs, access);
246       if (!h0)
247         {
248           if (createit)
249             __seterrno ();
250           return;
251         }
252
253       if (!procinfo)
254         {
255           if (exit_state)
256             return;
257
258           switch (GetLastError ())
259             {
260             case ERROR_INVALID_HANDLE:
261               api_fatal ("MapViewOfFileEx h0 %p, i %d failed, %E", h0, i);
262             case ERROR_INVALID_ADDRESS:
263               mapaddr = NULL;
264             }
265           debug_printf ("MapViewOfFileEx h0 %p, i %d failed, %E", h0, i);
266           yield ();
267           continue;
268         }
269
270       bool created = shloc != SH_JUSTOPEN;
271
272       if ((procinfo->process_state & PID_INITIALIZING) && (flag & PID_NOREDIR)
273           && cygwin_pid (procinfo->dwProcessId) != procinfo->pid)
274         {
275           set_errno (ESRCH);
276           break;
277         }
278
279       if (procinfo->process_state & PID_EXECED)
280         {
281           assert (i == 0);
282           pid_t realpid = procinfo->pid;
283           debug_printf ("execed process windows pid %d, cygwin pid %d", n, realpid);
284           if (realpid == n)
285             api_fatal ("retrieval of execed process info for pid %d failed due to recursion.", n);
286
287           n = realpid;
288           CloseHandle (h0);
289           h0 = NULL;
290           goto loop;
291         }
292
293       /* In certain pathological cases, it is possible for the shared memory
294          region to exist for a while after a process has exited.  This should
295          only be a brief occurrence, so rather than introduce some kind of
296          locking mechanism, just loop.  */
297       if (!created && createit && (procinfo->process_state & PID_EXITED))
298         {
299           debug_printf ("looping because pid %d, procinfo->pid %d, "
300                         "procinfo->dwProcessid %u has PID_EXITED set",
301                         n, procinfo->pid, procinfo->dwProcessId);
302           goto loop;
303         }
304
305       if (!created)
306         /* nothing */;
307       else if (!(flag & PID_EXECED))
308         procinfo->pid = n;
309       else
310         {
311           procinfo->process_state |= PID_IN_USE | PID_EXECED;
312           procinfo->pid = myself->pid;
313         }
314
315       h = h0;   /* Success! */
316       break;
317
318     loop:
319       release ();
320       if (h0)
321         yield ();
322     }
323
324   if (h)
325     {
326       destroy = 1;
327       ProtectHandle1 (h, pinfo_shared_handle);
328     }
329   else
330     {
331       h = h0;
332       release ();
333     }
334 }
335
336 void
337 pinfo::set_acl()
338 {
339   PACL acl_buf = (PACL) alloca (1024);
340   SECURITY_DESCRIPTOR sd;
341   NTSTATUS status;
342
343   sec_acl (acl_buf, true, true, cygheap->user.sid (),
344            well_known_world_sid, FILE_MAP_READ);
345   if (!InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION))
346     debug_printf ("InitializeSecurityDescriptor %E");
347   else if (!SetSecurityDescriptorDacl (&sd, TRUE, acl_buf, FALSE))
348     debug_printf ("SetSecurityDescriptorDacl %E");
349   else if ((status = NtSetSecurityObject (h, DACL_SECURITY_INFORMATION, &sd)))
350     debug_printf ("NtSetSecurityObject %lx", status);
351 }
352
353 const char *
354 _pinfo::_ctty (char *buf)
355 {
356   if (ctty == TTY_CONSOLE)
357     strcpy (buf, "ctty /dev/console");
358   else if (ctty < 0)
359     strcpy (buf, "no ctty");
360   else
361     __small_sprintf (buf, "ctty /dev/tty%d", ctty);
362   return buf;
363 }
364
365 void
366 _pinfo::set_ctty (tty_min *tc, int flags, fhandler_tty_slave *arch)
367 {
368   debug_printf ("old %s", __ctty ());
369   if ((ctty < 0 || ctty == tc->ntty) && !(flags & O_NOCTTY))
370     {
371       ctty = tc->ntty;
372       lock_ttys here;
373       syscall_printf ("attaching %s sid %d, pid %d, pgid %d, tty->pgid %d, tty->sid %d",
374                       __ctty (), sid, pid, pgid, tc->getpgid (), tc->getsid ());
375
376       pinfo p (tc->getsid ());
377       if (sid == pid && (!p || p->pid == pid || !p->exists ()))
378         {
379 #ifdef DEBUGGING
380           debug_printf ("resetting %s sid.  Was %d, now %d.  pgid was %d, now %d.",
381                            __ctty (), tc->getsid (), sid, tc->getpgid (), pgid);
382 #else
383           paranoid_printf ("resetting %s sid.  Was %d, now %d.  pgid was %d, now %d.",
384                            __ctty (), tc->getsid (), sid, tc->getpgid (), pgid);
385 #endif
386           /* We are the session leader */
387           tc->setsid (sid);
388           tc->setpgid (pgid);
389         }
390       else
391         sid = tc->getsid ();
392       if (tc->getpgid () == 0)
393 {debug_printf ("setting pgid to %d", pgid);
394           tc->setpgid (pgid);
395 }
396       if (cygheap->ctty != arch)
397         {
398           debug_printf ("cygheap->ctty %p, arch %p", cygheap->ctty, arch);
399           if (!cygheap->ctty)
400             syscall_printf ("ctty NULL");
401           else
402             {
403               syscall_printf ("ctty %p, usecount %d", cygheap->ctty,
404                               cygheap->ctty->usecount);
405               cygheap->ctty->close ();
406             }
407           cygheap->ctty = arch;
408           if (arch)
409             {
410               arch->usecount++;
411               /* guard ctty arch */
412               cygheap->manage_console_count ("_pinfo::set_ctty", 1);
413               report_tty_counts (cygheap->ctty, "ctty", "");
414             }
415         }
416     }
417 }
418
419 /* Test to determine if a process really exists and is processing signals.
420  */
421 bool __stdcall
422 _pinfo::exists ()
423 {
424   return this && !(process_state & PID_EXITED);
425 }
426
427 bool
428 _pinfo::alive ()
429 {
430   HANDLE h = OpenProcess (PROCESS_QUERY_INFORMATION, false, dwProcessId);
431   if (h)
432     CloseHandle (h);
433   return !!h;
434 }
435
436 DWORD WINAPI
437 commune_process (void *arg)
438 {
439   siginfo_t& si = *((siginfo_t *) arg);
440   tmp_pathbuf tp;
441   char *path = tp.c_get ();
442   DWORD nr;
443   HANDLE& tothem = si._si_commune._si_write_handle;
444   HANDLE process_sync =
445     OpenSemaphore (SYNCHRONIZE, false, shared_name (path, "commune", si.si_pid));
446   if (process_sync)             // FIXME: this test shouldn't be necessary
447     ProtectHandle (process_sync);
448
449   lock_process now ();
450   if (si._si_commune._si_code & PICOM_EXTRASTR)
451     si._si_commune._si_str = (char *) (&si + 1);
452
453   switch (si._si_commune._si_code)
454     {
455     case PICOM_CMDLINE:
456       {
457         sigproc_printf ("processing PICOM_CMDLINE");
458         unsigned n = 0;
459         const char *argv[__argc_safe + 1];
460
461         for (int i = 0; i < __argc_safe; i++)
462           {
463             if (IsBadStringPtr (__argv[i], INT32_MAX))
464               argv[i] = "";
465             else
466               argv[i] = __argv[i];
467             n += strlen (argv[i]) + 1;
468           }
469         argv[__argc_safe] = NULL;
470         if (!WriteFile (tothem, &n, sizeof n, &nr, NULL))
471           {
472             /*__seterrno ();*/  // this is run from the signal thread, so don't set errno
473             sigproc_printf ("WriteFile sizeof argv failed, %E");
474           }
475         else
476           for (const char **a = argv; *a; a++)
477             if (!WriteFile (tothem, *a, strlen (*a) + 1, &nr, NULL))
478               {
479                 sigproc_printf ("WriteFile arg %d failed, %E", a - argv);
480                 break;
481               }
482         break;
483       }
484     case PICOM_CWD:
485       {
486         sigproc_printf ("processing PICOM_CWD");
487         unsigned int n = strlen (cygheap->cwd.get (path, 1, 1, NT_MAX_PATH)) + 1;
488         if (!WriteFile (tothem, &n, sizeof n, &nr, NULL))
489           sigproc_printf ("WriteFile sizeof cwd failed, %E");
490         else if (!WriteFile (tothem, path, n, &nr, NULL))
491           sigproc_printf ("WriteFile cwd failed, %E");
492         break;
493       }
494     case PICOM_ROOT:
495       {
496         sigproc_printf ("processing PICOM_ROOT");
497         unsigned n;
498         if (cygheap->root.exists ())
499           n = strlen (strcpy (path, cygheap->root.posix_path ())) + 1;
500         else
501           n = strlen (strcpy (path, "/")) + 1;
502         if (!WriteFile (tothem, &n, sizeof n, &nr, NULL))
503           sigproc_printf ("WriteFile sizeof root failed, %E");
504         else if (!WriteFile (tothem, path, n, &nr, NULL))
505           sigproc_printf ("WriteFile root failed, %E");
506         break;
507       }
508     case PICOM_FDS:
509       {
510         sigproc_printf ("processing PICOM_FDS");
511         unsigned int n = 0;
512         int fd;
513         cygheap_fdenum cfd;
514         while ((fd = cfd.next ()) >= 0)
515           n += sizeof (int);
516         cfd.rewind ();
517         if (!WriteFile (tothem, &n, sizeof n, &nr, NULL))
518           sigproc_printf ("WriteFile sizeof fds failed, %E");
519         else
520           while ((fd = cfd.next ()) >= 0)
521             if (!WriteFile (tothem, &fd, sizeof fd, &nr, NULL))
522               {
523                 sigproc_printf ("WriteFile fd %d failed, %E", fd);
524                 break;
525               }
526         break;
527       }
528     case PICOM_PIPE_FHANDLER:
529       {
530         sigproc_printf ("processing PICOM_FDS");
531         HANDLE hdl = si._si_commune._si_pipe_fhandler;
532         unsigned int n = 0;
533         cygheap_fdenum cfd;
534         while (cfd.next () >= 0)
535           if (cfd->get_handle () == hdl)
536             {
537               fhandler_pipe *fh = cfd;
538               n = sizeof *fh;
539               if (!WriteFile (tothem, &n, sizeof n, &nr, NULL))
540                 sigproc_printf ("WriteFile sizeof hdl failed, %E");
541               else if (!WriteFile (tothem, fh, n, &nr, NULL))
542                 sigproc_printf ("WriteFile hdl failed, %E");
543               break;
544             }
545         if (!n && !WriteFile (tothem, &n, sizeof n, &nr, NULL))
546           sigproc_printf ("WriteFile sizeof hdl failed, %E");
547         break;
548       }
549     case PICOM_FD:
550       {
551         sigproc_printf ("processing PICOM_FD");
552         int fd = si._si_commune._si_fd;
553         unsigned int n = 0;
554         cygheap_fdget cfd (fd);
555         if (cfd < 0)
556           n = strlen (strcpy (path, "")) + 1;
557         else
558           n = strlen (cfd->get_proc_fd_name (path)) + 1;
559         if (!WriteFile (tothem, &n, sizeof n, &nr, NULL))
560           sigproc_printf ("WriteFile sizeof fd failed, %E");
561         else if (!WriteFile (tothem, path, n, &nr, NULL))
562           sigproc_printf ("WriteFile fd failed, %E");
563         break;
564       }
565     }
566   if (process_sync)
567     {
568       DWORD res = WaitForSingleObject (process_sync, 5000);
569       if (res != WAIT_OBJECT_0)
570         sigproc_printf ("WFSO failed - %d, %E", res);
571       else
572         sigproc_printf ("synchronized with pid %d", si.si_pid);
573       ForceCloseHandle (process_sync);
574     }
575   CloseHandle (tothem);
576   _my_tls._ctinfo->auto_release ();
577   return 0;
578 }
579
580 commune_result
581 _pinfo::commune_request (__uint32_t code, ...)
582 {
583   DWORD nr;
584   commune_result res;
585   va_list args;
586   siginfo_t si = {0};
587   HANDLE& hp = si._si_commune._si_process_handle;
588   HANDLE& fromthem = si._si_commune._si_read_handle;
589   HANDLE request_sync = NULL;
590   bool locked = false;
591
592   res.s = NULL;
593   res.n = 0;
594
595   if (!this || !pid)
596     {
597       set_errno (ESRCH);
598       goto err;
599     }
600
601   va_start (args, code);
602   si._si_commune._si_code = code;
603   switch (code)
604     {
605     case PICOM_PIPE_FHANDLER:
606       si._si_commune._si_pipe_fhandler = va_arg (args, HANDLE);
607       break;
608
609     case PICOM_FD:
610       si._si_commune._si_fd = va_arg (args, int);
611       break;
612
613     break;
614     }
615   va_end (args);
616
617   locked = true;
618   char name_buf[MAX_PATH];
619   request_sync = CreateSemaphore (&sec_none_nih, 0, LONG_MAX,
620                                   shared_name (name_buf, "commune", myself->pid));
621   if (!request_sync)
622     goto err;
623   ProtectHandle (request_sync);
624
625   si.si_signo = __SIGCOMMUNE;
626   if (sig_send (this, si))
627     {
628       ForceCloseHandle (request_sync);  /* don't signal semaphore since there was apparently no receiving process */
629       request_sync = NULL;
630       goto err;
631     }
632
633   size_t n;
634   switch (code)
635     {
636     case PICOM_CMDLINE:
637     case PICOM_CWD:
638     case PICOM_ROOT:
639     case PICOM_FDS:
640     case PICOM_FD:
641     case PICOM_PIPE_FHANDLER:
642       if (!ReadFile (fromthem, &n, sizeof n, &nr, NULL) || nr != sizeof n)
643         {
644           __seterrno ();
645           goto err;
646         }
647       if (!n)
648         res.s = NULL;
649       else
650         {
651           res.s = (char *) cmalloc_abort (HEAP_COMMUNE, n);
652           char *p;
653           for (p = res.s; n && ReadFile (fromthem, p, n, &nr, NULL); p += nr, n -= nr)
654             continue;
655           if (n)
656             {
657               __seterrno ();
658               goto err;
659             }
660           res.n = p - res.s;
661         }
662       break;
663     }
664   goto out;
665
666 err:
667   memset (&res, 0, sizeof (res));
668
669 out:
670   if (request_sync)
671     {
672       LONG res;
673       ReleaseSemaphore (request_sync, 1, &res);
674       ForceCloseHandle (request_sync);
675     }
676   if (hp)
677     CloseHandle (hp);
678   if (fromthem)
679     CloseHandle (fromthem);
680   return res;
681 }
682
683 fhandler_pipe *
684 _pinfo::pipe_fhandler (HANDLE hdl, size_t &n)
685 {
686   if (!this || !pid)
687     return NULL;
688   if (pid == myself->pid)
689     return NULL;
690   commune_result cr = commune_request (PICOM_PIPE_FHANDLER, hdl);
691   n = cr.n;
692   return (fhandler_pipe *) cr.s;
693 }
694
695 char *
696 _pinfo::fd (int fd, size_t &n)
697 {
698   char *s;
699   if (!this || !pid)
700     return NULL;
701   if (pid != myself->pid)
702     {
703       commune_result cr = commune_request (PICOM_FD, fd);
704       s = cr.s;
705       n = cr.n;
706     }
707   else
708     {
709       cygheap_fdget cfd (fd);
710       if (cfd < 0)
711         s = cstrdup ("");
712       else
713         s = cfd->get_proc_fd_name ((char *) cmalloc_abort (HEAP_COMMUNE, NT_MAX_PATH));
714       n = strlen (s) + 1;
715     }
716   return s;
717 }
718
719 char *
720 _pinfo::fds (size_t &n)
721 {
722   char *s;
723   if (!this || !pid)
724     return NULL;
725   if (pid != myself->pid)
726     {
727       commune_result cr = commune_request (PICOM_FDS);
728       s = cr.s;
729       n = cr.n;
730     }
731   else
732     {
733       n = 0;
734       int fd;
735       cygheap_fdenum cfd (true);
736       while ((fd = cfd.next ()) >= 0)
737         n += sizeof (int);
738       cfd.rewind ();
739       s = (char *) cmalloc_abort (HEAP_COMMUNE, n);
740       int *p = (int *) s;
741       while ((fd = cfd.next ()) >= 0 && (char *) p - s < (int) n)
742         *p++ = fd;
743     }
744   return s;
745 }
746
747 char *
748 _pinfo::root (size_t& n)
749 {
750   char *s;
751   if (!this || !pid)
752     return NULL;
753   if (pid != myself->pid)
754     {
755       commune_result cr = commune_request (PICOM_ROOT);
756       s = cr.s;
757       n = cr.n;
758     }
759   else
760     {
761       if (cygheap->root.exists ())
762         s = cstrdup (cygheap->root.posix_path ());
763       else
764         s = cstrdup ("/");
765       n = strlen (s) + 1;
766     }
767   return s;
768 }
769
770 char *
771 _pinfo::cwd (size_t& n)
772 {
773   char *s;
774   if (!this || !pid)
775     return NULL;
776   if (pid != myself->pid)
777     {
778       commune_result cr = commune_request (PICOM_CWD);
779       s = cr.s;
780       n = cr.n;
781     }
782   else
783     {
784       s = (char *) cmalloc_abort (HEAP_COMMUNE, NT_MAX_PATH);
785       cygheap->cwd.get (s, 1, 1, NT_MAX_PATH);
786       n = strlen (s) + 1;
787     }
788   return s;
789 }
790
791 char *
792 _pinfo::cmdline (size_t& n)
793 {
794   char *s;
795   if (!this || !pid)
796     return NULL;
797   if (pid != myself->pid)
798     {
799       commune_result cr = commune_request (PICOM_CMDLINE);
800       s = cr.s;
801       n = cr.n;
802     }
803   else
804     {
805       n = 0;
806       for (char **a = __argv; *a; a++)
807         n += strlen (*a) + 1;
808       char *p;
809       p = s = (char *) cmalloc_abort (HEAP_COMMUNE, n);
810       for (char **a = __argv; *a; a++)
811         {
812           strcpy (p, *a);
813           p = strchr (p, '\0') + 1;
814         }
815     }
816   return s;
817 }
818
819 /* This is the workhorse which waits for the write end of the pipe
820    created during new process creation.  If the pipe is closed or a zero
821    is received on the pipe, it is assumed that the cygwin pid has exited.
822    Otherwise, various "signals" can be sent to the parent to inform the
823    parent to perform a certain action. */
824 static DWORD WINAPI
825 proc_waiter (void *arg)
826 {
827   pinfo vchild = *(pinfo *) arg;
828   ((pinfo *) arg)->waiter_ready = true;
829
830   siginfo_t si = {0};
831   si.si_signo = SIGCHLD;
832   si.si_code = CLD_EXITED;
833   si.si_pid = vchild->pid;
834 #if 0   // FIXME: This is tricky to get right
835   si.si_utime = pchildren[rc]->rusage_self.ru_utime;
836   si.si_stime = pchildren[rc].rusage_self.ru_stime;
837 #endif
838   pid_t pid = vchild->pid;
839
840   for (;;)
841     {
842       DWORD nb;
843       char buf = '\0';
844
845       if (!ReadFile (vchild.rd_proc_pipe, &buf, 1, &nb, NULL)
846           && GetLastError () != ERROR_BROKEN_PIPE)
847         {
848           system_printf ("error on read of child wait pipe %p, %E", vchild.rd_proc_pipe);
849           break;
850         }
851
852       si.si_uid = vchild->uid;
853
854       switch (buf)
855         {
856         case __ALERT_ALIVE:
857           continue;
858         case 0:
859           /* Child exited.  Do some cleanup and signal myself.  */
860           CloseHandle (vchild.rd_proc_pipe);
861           vchild.rd_proc_pipe = NULL;
862           vchild.maybe_set_exit_code_from_windows ();
863           if (WIFEXITED (vchild->exitcode))
864             si.si_code = CLD_EXITED;
865           else if (WCOREDUMP (vchild->exitcode))
866             si.si_code = CLD_DUMPED;
867           else
868             si.si_code = CLD_KILLED;
869           si.si_status = vchild->exitcode;
870           vchild->process_state = PID_EXITED;
871           /* This should always be last.  Do not use vchild-> beyond this point */
872           break;
873         case SIGTTIN:
874         case SIGTTOU:
875         case SIGTSTP:
876         case SIGSTOP:
877           if (ISSTATE (myself, PID_NOCLDSTOP))  // FIXME: No need for this flag to be in _pinfo any longer
878             continue;
879           /* Child stopped.  Signal myself.  */
880           si.si_code = CLD_STOPPED;
881           break;
882         case SIGCONT:
883           continue;
884         default:
885           system_printf ("unknown value %d on proc pipe", buf);
886           continue;
887         }
888
889       /* Special case:  If the "child process" that died is us, then we're
890          execing.  Just call proc_subproc directly and then exit this loop.
891          We're done here.  */
892       if (hExeced)
893         {
894           /* execing.  no signals available now. */
895           proc_subproc (PROC_CLEARWAIT, 0);
896           break;
897         }
898
899       /* Send a SIGCHLD to myself.   We do this here, rather than in proc_subproc
900          to avoid the proc_subproc lock since the signal thread will eventually
901          be calling proc_subproc and could unnecessarily block. */
902       sig_send (myself_nowait, si);
903
904       /* If we're just stopped or got a continue signal, keep looping.
905          Otherwise, return this thread to the pool. */
906       if (buf != '\0')
907         sigproc_printf ("looping");
908       else
909         break;
910     }
911
912   sigproc_printf ("exiting wait thread for pid %d", pid);
913   vchild.wait_thread = NULL;
914   _my_tls._ctinfo->auto_release ();     /* automatically return the cygthread to the cygthread pool */
915   return 0;
916 }
917
918 HANDLE
919 _pinfo::dup_proc_pipe (HANDLE hProcess)
920 {
921   DWORD flags = DUPLICATE_SAME_ACCESS;
922   HANDLE orig_wr_proc_pipe = wr_proc_pipe;
923   /* Can't set DUPLICATE_CLOSE_SOURCE for exec case because we could be
924      execing a non-cygwin process and we need to set the exit value before the
925      parent sees it.  */
926   if (this != myself || is_toplevel_proc)
927     flags |= DUPLICATE_CLOSE_SOURCE;
928   bool res = DuplicateHandle (GetCurrentProcess (), wr_proc_pipe,
929                               hProcess, &wr_proc_pipe, 0, FALSE, flags);
930   if (!res && WaitForSingleObject (hProcess, 0) != WAIT_OBJECT_0)
931     {
932       wr_proc_pipe = orig_wr_proc_pipe;
933       system_printf ("DuplicateHandle failed, pid %d, hProcess %p, wr_proc_pipe %p, %E",
934                      pid, hProcess, wr_proc_pipe);
935     }
936   else
937     {
938       wr_proc_pipe_owner = dwProcessId;
939       sigproc_printf ("duped wr_proc_pipe %p for pid %d(%u)", wr_proc_pipe,
940                       pid, dwProcessId);
941     }
942   return orig_wr_proc_pipe;
943 }
944
945 /* function to set up the process pipe and kick off proc_waiter */
946 int
947 pinfo::wait ()
948 {
949   /* FIXME: execed processes should be able to wait for pids that were started
950      by the process which execed them. */
951   if (!CreatePipe (&rd_proc_pipe, &((*this)->wr_proc_pipe), &sec_none_nih, 16))
952     {
953       system_printf ("Couldn't create pipe tracker for pid %d, %E",
954                      (*this)->pid);
955       return 0;
956     }
957
958   if (!(*this)->dup_proc_pipe (hProcess))
959     {
960       system_printf ("Couldn't duplicate pipe topid %d(%p), %E", (*this)->pid, hProcess);
961       return 0;
962     }
963
964   preserve ();          /* Preserve the shared memory associated with the pinfo */
965
966   waiter_ready = false;
967   /* Fire up a new thread to track the subprocess */
968   cygthread *h = new cygthread (proc_waiter, this, "proc_waiter");
969   if (!h)
970     sigproc_printf ("tracking thread creation failed for pid %d", (*this)->pid);
971   else
972     {
973       wait_thread = h;
974       sigproc_printf ("created tracking thread for pid %d, winpid %p, rd_pipe %p",
975                       (*this)->pid, (*this)->dwProcessId, rd_proc_pipe);
976     }
977
978   return 1;
979 }
980
981 void
982 _pinfo::sync_proc_pipe ()
983 {
984   if (wr_proc_pipe && wr_proc_pipe != INVALID_HANDLE_VALUE)
985     while (wr_proc_pipe_owner != GetCurrentProcessId ())
986       yield ();
987 }
988
989 /* function to send a "signal" to the parent when something interesting happens
990    in the child. */
991 bool
992 _pinfo::alert_parent (char sig)
993 {
994   DWORD nb = 0;
995
996   /* Send something to our parent.  If the parent has gone away, close the pipe.
997      Don't send if this is an exec stub.
998
999      FIXME: Is there a race here if we run this while another thread is attempting
1000      to exec()? */
1001   if (wr_proc_pipe == INVALID_HANDLE_VALUE || !myself->wr_proc_pipe || hExeced)
1002     /* no parent */;
1003   else
1004     {
1005       sync_proc_pipe ();
1006       if (WriteFile (wr_proc_pipe, &sig, 1, &nb, NULL))
1007         /* all is well */;
1008       else if (GetLastError () != ERROR_BROKEN_PIPE)
1009         debug_printf ("sending %d notification to parent failed, %E", sig);
1010       else
1011         {
1012           ppid = 1;
1013           HANDLE closeit = wr_proc_pipe;
1014           wr_proc_pipe = INVALID_HANDLE_VALUE;
1015           CloseHandle (closeit);
1016         }
1017     }
1018   return (bool) nb;
1019 }
1020
1021 void
1022 pinfo::release ()
1023 {
1024   if (procinfo)
1025     {
1026       void *unmap_procinfo = procinfo;
1027       procinfo = NULL;
1028       UnmapViewOfFile (unmap_procinfo);
1029     }
1030   if (h)
1031     {
1032       HANDLE close_h = h;
1033       h = NULL;
1034       ForceCloseHandle1 (close_h, pinfo_shared_handle);
1035     }
1036 }
1037
1038 /* DOCTOOL-START
1039
1040 <sect1 id="func-cygwin-winpid-to-pid">
1041   <title>cygwin_winpid_to_pid</title>
1042
1043   <funcsynopsis><funcprototype>
1044     <funcdef>extern "C" pid_t
1045       <function>cygwin_winpid_to_pid</function>
1046       </funcdef>
1047       <paramdef>int <parameter>winpid</parameter></paramdef>
1048   </funcprototype></funcsynopsis>
1049
1050   <para>Given a windows pid, converts to the corresponding Cygwin
1051 pid, if any.  Returns -1 if windows pid does not correspond to
1052 a cygwin pid.</para>
1053   <example>
1054     <title>Example use of cygwin_winpid_to_pid</title>
1055     <programlisting>
1056       extern "C" cygwin_winpid_to_pid (int winpid);
1057       pid_t mypid;
1058       mypid = cygwin_winpid_to_pid (windows_pid);
1059     </programlisting>
1060   </example>
1061 </sect1>
1062
1063    DOCTOOL-END */
1064
1065 extern "C" pid_t
1066 cygwin_winpid_to_pid (int winpid)
1067 {
1068   pinfo p (cygwin_pid (winpid));
1069   if (p)
1070     return p->pid;
1071
1072   set_errno (ESRCH);
1073   return (pid_t) -1;
1074 }
1075
1076
1077 #define slop_pidlist 200
1078 #define size_pidlist(i) (sizeof (pidlist[0]) * ((i) + 1))
1079 #define size_pinfolist(i) (sizeof (pinfolist[0]) * ((i) + 1))
1080 class _onreturn
1081 {
1082   HANDLE *h;
1083 public:
1084   ~_onreturn ()
1085   {
1086     if (h && *h)
1087       {
1088         CloseHandle (*h);
1089         *h = NULL;
1090         h = NULL;
1091       }
1092   }
1093   void no_close_p_handle () {h = NULL;}
1094   _onreturn (HANDLE& _h): h (&_h) {}
1095 };
1096
1097 inline void
1098 winpids::add (DWORD& nelem, bool winpid, DWORD pid)
1099 {
1100   pid_t cygpid = cygwin_pid (pid);
1101
1102   if (nelem >= npidlist)
1103     {
1104       npidlist += slop_pidlist;
1105       pidlist = (DWORD *) realloc (pidlist, size_pidlist (npidlist + 1));
1106       pinfolist = (pinfo *) realloc (pinfolist, size_pinfolist (npidlist + 1));
1107     }
1108
1109   pinfo& p = pinfolist[nelem];
1110
1111   /* Open a the process to prevent a subsequent exit from invalidating the
1112      shared memory region. */
1113   p.hProcess = OpenProcess (PROCESS_QUERY_INFORMATION, false, pid);
1114   _onreturn onreturn (p.hProcess);
1115
1116   /* If we couldn't open the process then we don't have rights to it and should
1117      make a copy of the shared memory area if it exists (it may not).
1118   */
1119   bool perform_copy;
1120   if (!p.hProcess)
1121     perform_copy = true;
1122   else
1123     perform_copy = make_copy;
1124
1125   p.init (cygpid, PID_NOREDIR | pinfo_access, NULL);
1126
1127   /* If we're just looking for winpids then don't do any special cygwin "stuff* */
1128   if (winpid)
1129     goto out;
1130
1131   /* !p means that we couldn't find shared memory for this pid.  Probably means
1132      that it isn't a cygwin process. */
1133   if (!p)
1134     {
1135       if (!pinfo_access)
1136         return;
1137       p.init (cygpid, PID_NOREDIR, NULL);
1138       if (!p)
1139         return;
1140       }
1141
1142   /* Scan list of previously recorded pids to make sure that this pid hasn't
1143      shown up before.  This can happen when a process execs. */
1144   for (unsigned i = 0; i < nelem; i++)
1145     if (pinfolist[i]->pid == p->pid)
1146       {
1147         if ((_pinfo *) p != (_pinfo *) myself)
1148           p.release ();
1149         return;
1150       }
1151
1152 out:
1153   /* Exit here.
1154
1155      If p is "false" then, eventually any opened process handle will be closed and
1156      the function will exit without adding anything to the pid list.
1157
1158      If p is "true" then we've discovered a cygwin process.
1159
1160      Handle "myself" differently.  Don't copy it and close/zero the handle we
1161      just opened to it.
1162      If not performing a copy, then keep the process handle open for the duration
1163      of the life of the procinfo region to potential races when a new process uses
1164      this pid.
1165      Otherwise, malloc some memory for a copy of the shared memory.
1166
1167      If the malloc failed, then "oh well".  Just keep the shared memory around
1168      and eventually close the handle when the winpids goes out of scope.
1169
1170      If malloc succeeds, copy the procinfo we just grabbed into the new region,
1171      release the shared memory and allow the handle to be closed when this
1172      function returns.
1173
1174      Oh, and add the pid to the list and bump the number of elements.  */
1175
1176   if (p)
1177     {
1178       if (p == (_pinfo *) myself)
1179         /* handle specially.  Close the handle but (eventually) don't
1180            deallocate procinfo in release call */;
1181       else if (!perform_copy)
1182         onreturn.no_close_p_handle ();  /* Don't close the handle until release */
1183       else
1184         {
1185           _pinfo *pnew = (_pinfo *) malloc (sizeof (*p.procinfo));
1186           if (!pnew)
1187             onreturn.no_close_p_handle ();
1188           else
1189             {
1190               *pnew = *p.procinfo;
1191               if ((_pinfo *) p != (_pinfo *) myself)
1192                 p.release ();
1193               p.procinfo = pnew;
1194               p.destroy = false;
1195             }
1196         }
1197     }
1198   if (p || winpid)
1199     pidlist[nelem++] = pid;
1200 }
1201
1202 DWORD
1203 winpids::enum_processes (bool winpid)
1204 {
1205   static DWORD szprocs;
1206   static SYSTEM_PROCESSES *procs;
1207
1208   DWORD nelem = 0;
1209   if (!szprocs)
1210     procs = (SYSTEM_PROCESSES *) malloc (sizeof (*procs) + (szprocs = 200 * sizeof (*procs)));
1211
1212   NTSTATUS res;
1213   for (;;)
1214     {
1215       res = NtQuerySystemInformation (SystemProcessesAndThreadsInformation,
1216                                       procs, szprocs, NULL);
1217       if (res == 0)
1218         break;
1219
1220       if (res == STATUS_INFO_LENGTH_MISMATCH)
1221         procs =  (SYSTEM_PROCESSES *) realloc (procs, szprocs += 200 * sizeof (*procs));
1222       else
1223         {
1224           system_printf ("error %p reading system process information", res);
1225           return 0;
1226         }
1227     }
1228
1229   SYSTEM_PROCESSES *px = procs;
1230   for (;;)
1231     {
1232       if (px->ProcessId)
1233         add (nelem, winpid, px->ProcessId);
1234       if (!px->NextEntryDelta)
1235         break;
1236       px = (SYSTEM_PROCESSES *) ((char *) px + px->NextEntryDelta);
1237     }
1238
1239   return nelem;
1240 }
1241
1242 void
1243 winpids::set (bool winpid)
1244 {
1245   __malloc_lock ();
1246   npids = enum_processes (winpid);
1247   if (pidlist)
1248     pidlist[npids] = 0;
1249   __malloc_unlock ();
1250 }
1251
1252 DWORD
1253 winpids::enum_init (bool winpid)
1254 {
1255   return enum_processes (winpid);
1256 }
1257
1258 void
1259 winpids::release ()
1260 {
1261   _pinfo *p;
1262   for (unsigned i = 0; i < npids; i++)
1263     if (pinfolist[i] == (_pinfo *) myself)
1264       continue;
1265     else if (pinfolist[i].hProcess)
1266       {
1267         if (pinfolist[i])
1268           pinfolist[i].release ();
1269         CloseHandle (pinfolist[i].hProcess);
1270       }
1271     else if ((p = pinfolist[i]))
1272       {
1273         pinfolist[i].procinfo = NULL;
1274         free (p);
1275       }
1276 }
1277
1278 winpids::~winpids ()
1279 {
1280   if (npidlist)
1281     {
1282       release ();
1283       free (pidlist);
1284       free (pinfolist);
1285     }
1286 }