]>
Commit | Line | Data |
---|---|---|
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 | |
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 | ||
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 |
32 | class pinfo_basic: public _pinfo |
33 | { | |
34 | public: | |
35 | pinfo_basic(); | |
36 | }; | |
37 | ||
9ffe887f | 38 | pinfo_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 |
47 | pinfo_basic myself_initial NO_COPY; |
48 | ||
49 | pinfo 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 | 54 | void |
9ac42168 | 55 | pinfo::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 | 83 | void __stdcall |
166b2571 | 84 | pinfo_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 |
113 | DWORD |
114 | pinfo::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 |
155 | void |
156 | pinfo::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 | 164 | void |
37d5841f | 165 | pinfo::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 | ||
182 | void | |
183 | pinfo::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 |
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 | ||
1fd5e000 | 237 | void |
9a0b76dc | 238 | pinfo::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 |
381 | void |
382 | pinfo::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 |
398 | pinfo::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 |
427 | const 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 |
441 | bool |
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 | */ | |
495 | bool __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 |
501 | bool |
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 |
510 | DWORD WINAPI |
511 | commune_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 | 655 | commune_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 | ||
742 | err: | |
7ac61736 CF |
743 | memset (&res, 0, sizeof (res)); |
744 | ||
831d6fa5 | 745 | out: |
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 |
759 | fhandler_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 |
771 | char * |
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 | ||
795 | char * | |
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 |
823 | char * |
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 | ||
846 | char * | |
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 | 867 | char * |
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 |
900 | static DWORD WINAPI |
901 | proc_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 | 990 | bool |
8cb359d9 CF |
991 | pinfo::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 | 1012 | bool |
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 |
1039 | void |
1040 | pinfo::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 | |
1071 | pid, if any. Returns -1 if windows pid does not correspond to | |
1072 | a 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 | ||
1085 | extern "C" pid_t | |
1086 | cygwin_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 |
1100 | class _onreturn |
1101 | { | |
dcd0465b | 1102 | HANDLE *h; |
f3ea02b1 CF |
1103 | public: |
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 |
1117 | inline void |
1118 | winpids::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 | ||
1172 | out: | |
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 | ||
1221 | DWORD | |
570858c3 | 1222 | winpids::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 | 1326 | void |
883bbc64 | 1327 | winpids::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 |
1336 | DWORD |
1337 | winpids::enum_init (bool winpid) | |
84c7d409 | 1338 | { |
570858c3 | 1339 | return enum_processes (winpid); |
0c9ae85d CF |
1340 | } |
1341 | ||
1342 | void | |
1343 | winpids::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 | ||
1358 | winpids::~winpids () | |
1359 | { | |
1360 | if (npidlist) | |
1361 | { | |
1362 | release (); | |
1363 | free (pidlist); | |
1364 | free (pinfolist); | |
1365 | } | |
1fd5e000 | 1366 | } |