OSDN Git Service

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