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