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