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