]> www.cygwin.com Git - newlib-cygwin.git/blob - winsup/cygwin/spawn.cc
Revert "Cygwin: fix permission problem when writing DAC info on Samba shares"
[newlib-cygwin.git] / winsup / cygwin / spawn.cc
1 /* spawn.cc
2
3 This file is part of Cygwin.
4
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
7 details. */
8
9 #include "winsup.h"
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <process.h>
13 #include <sys/wait.h>
14 #include <wchar.h>
15 #include <ctype.h>
16 #include <sys/cygwin.h>
17 #include "cygerrno.h"
18 #include "security.h"
19 #include "sigproc.h"
20 #include "pinfo.h"
21 #include "path.h"
22 #include "fhandler.h"
23 #include "dtable.h"
24 #include "cygheap.h"
25 #include "child_info.h"
26 #include "environ.h"
27 #include "cygtls.h"
28 #include "tls_pbuf.h"
29 #include "winf.h"
30 #include "ntdll.h"
31
32 static const suffix_info exe_suffixes[] =
33 {
34 suffix_info ("", 1),
35 suffix_info (".exe", 1),
36 suffix_info (".com"),
37 suffix_info (NULL)
38 };
39
40 /* Add .exe to PROG if not already present and see if that exists.
41 If not, return PROG (converted from posix to win32 rules if necessary).
42 The result is always BUF.
43
44 Returns (possibly NULL) suffix */
45
46 static const char *
47 perhaps_suffix (const char *prog, path_conv& buf, int& err, unsigned opt)
48 {
49 const char *ext;
50
51 err = 0;
52 debug_printf ("prog '%s'", prog);
53 buf.check (prog, PC_SYM_FOLLOW | PC_NULLEMPTY | PC_POSIX,
54 (opt & FE_DLL) ? stat_suffixes : exe_suffixes);
55
56 if (buf.isdir ())
57 {
58 err = EACCES;
59 ext = NULL;
60 }
61 else if (!buf.exists ())
62 {
63 err = ENOENT;
64 ext = NULL;
65 }
66 else if (buf.known_suffix ())
67 ext = buf.get_win32 () + (buf.known_suffix () - buf.get_win32 ());
68 else
69 ext = strchr (buf.get_win32 (), '\0');
70
71 debug_printf ("buf %s, suffix found '%s'", (char *) buf.get_win32 (), ext);
72 return ext;
73 }
74
75 /* Find an executable name, possibly by appending known executable suffixes
76 to it. The path_conv struct 'buf' is filled and contains both, win32 and
77 posix path of the target file. Any found suffix is returned in known_suffix.
78 Eventually the posix path in buf is overwritten with the exact path as it
79 gets constructed for the path search. The reason is that the path is used
80 to create argv[0] in av::setup, and this requires that the filename stays
81 intact, instead of being resolved if the file is a symlink.
82
83 If the file is not found and !FE_NNF then the POSIX version of name is
84 placed in buf and returned. Otherwise the contents of buf is undefined
85 and NULL is returned. */
86 const char * __reg3
87 find_exec (const char *name, path_conv& buf, const char *search,
88 unsigned opt, const char **known_suffix)
89 {
90 const char *suffix = "";
91 const char *retval = NULL;
92 tmp_pathbuf tp;
93 char *tmp_path;
94 char *tmp = tp.c_get ();
95 bool has_slash = !!strpbrk (name, "/\\");
96 int err = 0;
97
98 debug_printf ("find_exec (%s)", name);
99
100 /* Check to see if file can be opened as is first. */
101 if ((has_slash || opt & FE_CWD)
102 && (suffix = perhaps_suffix (name, buf, err, opt)) != NULL)
103 {
104 /* Overwrite potential symlink target with original path.
105 See comment preceeding this method. */
106 tmp_path = tmp;
107 if (!has_slash)
108 tmp_path = stpcpy (tmp, "./");
109 stpcpy (tmp_path, name);
110 buf.set_posix (tmp);
111 retval = buf.get_posix ();
112 goto out;
113 }
114
115 const char *path;
116 /* If it starts with a slash, it's a PATH-like pathlist. Otherwise it's
117 the name of an environment variable. */
118 if (strchr (search, '/'))
119 *stpncpy (tmp, search, NT_MAX_PATH - 1) = '\0';
120 else if (has_slash || isdrive (name) || !(path = getenv (search)) || !*path)
121 goto errout;
122 else
123 *stpncpy (tmp, path, NT_MAX_PATH - 1) = '\0';
124
125 path = tmp;
126 debug_printf ("searchpath %s", path);
127
128 tmp_path = tp.c_get ();
129 do
130 {
131 char *eotmp = strccpy (tmp_path, &path, ':');
132 /* An empty path or '.' means the current directory, but we've
133 already tried that. */
134 if ((opt & FE_CWD) && (tmp_path[0] == '\0'
135 || (tmp_path[0] == '.' && tmp_path[1] == '\0')))
136 continue;
137
138 *eotmp++ = '/';
139 stpcpy (eotmp, name);
140
141 debug_printf ("trying %s", tmp_path);
142
143 int err1;
144
145 if ((suffix = perhaps_suffix (tmp_path, buf, err1, opt)) != NULL)
146 {
147 if (buf.has_acls () && check_file_access (buf, X_OK, true))
148 continue;
149 /* Overwrite potential symlink target with original path.
150 See comment preceeding this method. */
151 buf.set_posix (tmp_path);
152 retval = buf.get_posix ();
153 goto out;
154 }
155
156 }
157 while (*path && *++path);
158
159 errout:
160 /* Couldn't find anything in the given path.
161 Take the appropriate action based on FE_NNF. */
162 if (!(opt & FE_NNF))
163 {
164 buf.check (name, PC_SYM_FOLLOW | PC_POSIX);
165 retval = buf.get_posix ();
166 }
167
168 out:
169 debug_printf ("%s = find_exec (%s)", (char *) buf.get_posix (), name);
170 if (known_suffix)
171 *known_suffix = suffix ?: strchr (buf.get_win32 (), '\0');
172 if (!retval && err)
173 set_errno (err);
174 return retval;
175 }
176
177 /* Utility for child_info_spawn::worker. */
178
179 static HANDLE
180 handle (int fd, bool writing)
181 {
182 HANDLE h;
183 cygheap_fdget cfd (fd);
184
185 if (cfd < 0)
186 h = INVALID_HANDLE_VALUE;
187 else if (cfd->close_on_exec ())
188 h = INVALID_HANDLE_VALUE;
189 else if (!writing)
190 h = cfd->get_handle_nat ();
191 else
192 h = cfd->get_output_handle_nat ();
193
194 return h;
195 }
196
197 static bool
198 is_console_app (WCHAR *filename)
199 {
200 HANDLE h;
201 const int id_offset = 92;
202 h = CreateFileW (filename, GENERIC_READ, FILE_SHARE_READ,
203 NULL, OPEN_EXISTING, 0, NULL);
204 char buf[1024];
205 DWORD n;
206 ReadFile (h, buf, sizeof (buf), &n, 0);
207 CloseHandle (h);
208 char *p = (char *) memmem (buf, n, "PE\0\0", 4);
209 if (p && p + id_offset <= buf + n)
210 return p[id_offset] == '\003'; /* 02: GUI, 03: console */
211 else
212 return false;
213 }
214
215 int
216 iscmd (const char *argv0, const char *what)
217 {
218 int n;
219 n = strlen (argv0) - strlen (what);
220 if (n >= 2 && argv0[1] != ':')
221 return 0;
222 return n >= 0 && strcasematch (argv0 + n, what) &&
223 (n == 0 || isdirsep (argv0[n - 1]));
224 }
225
226 #define ILLEGAL_SIG_FUNC_PTR ((_sig_func_ptr) (-2))
227 struct system_call_handle
228 {
229 _sig_func_ptr oldint;
230 _sig_func_ptr oldquit;
231 sigset_t oldmask;
232 bool is_system_call ()
233 {
234 return oldint != ILLEGAL_SIG_FUNC_PTR;
235 }
236 system_call_handle (bool issystem)
237 {
238 if (!issystem)
239 oldint = ILLEGAL_SIG_FUNC_PTR;
240 else
241 {
242 sig_send (NULL, __SIGHOLD);
243 oldint = NULL;
244 }
245 }
246 void arm()
247 {
248 if (is_system_call ())
249 {
250 sigset_t child_block;
251 oldint = signal (SIGINT, SIG_IGN);
252 oldquit = signal (SIGQUIT, SIG_IGN);
253 sigemptyset (&child_block);
254 sigaddset (&child_block, SIGCHLD);
255 sigprocmask (SIG_BLOCK, &child_block, &oldmask);
256 sig_send (NULL, __SIGNOHOLD);
257 }
258 }
259 ~system_call_handle ()
260 {
261 if (is_system_call ())
262 {
263 signal (SIGINT, oldint);
264 signal (SIGQUIT, oldquit);
265 sigprocmask (SIG_SETMASK, &oldmask, NULL);
266 }
267 }
268 # undef cleanup
269 };
270
271 child_info_spawn NO_COPY ch_spawn;
272
273 extern "C" void __posix_spawn_sem_release (void *sem, int error);
274
275 extern DWORD mutex_timeout; /* defined in fhandler_termios.cc */
276
277 int
278 child_info_spawn::worker (const char *prog_arg, const char *const *argv,
279 const char *const envp[], int mode,
280 int in__stdin, int in__stdout)
281 {
282 bool rc;
283 int res = -1;
284 pid_t ctty_pgid = 0;
285
286 /* Search for CTTY and retrieve its PGID */
287 cygheap_fdenum cfd (false);
288 while (cfd.next () >= 0)
289 if (cfd->get_major () == DEV_PTYS_MAJOR ||
290 cfd->get_major () == DEV_CONS_MAJOR)
291 {
292 fhandler_termios *fh = (fhandler_termios *) (fhandler_base *) cfd;
293 if (fh->tc ()->ntty == myself->ctty)
294 {
295 ctty_pgid = fh->tc ()->getpgid ();
296 break;
297 }
298 }
299
300 /* Check if we have been called from exec{lv}p or spawn{lv}p and mask
301 mode to keep only the spawn mode. */
302 bool p_type_exec = !!(mode & _P_PATH_TYPE_EXEC);
303 mode = _P_MODE (mode);
304
305 if (prog_arg == NULL)
306 {
307 syscall_printf ("prog_arg is NULL");
308 set_errno (EFAULT); /* As on Linux. */
309 return -1;
310 }
311 if (!prog_arg[0])
312 {
313 syscall_printf ("prog_arg is empty");
314 set_errno (ENOENT); /* Per POSIX */
315 return -1;
316 }
317
318 syscall_printf ("mode = %d, prog_arg = %.9500s", mode, prog_arg);
319
320 /* FIXME: This is no error condition on Linux. */
321 if (argv == NULL)
322 {
323 syscall_printf ("argv is NULL");
324 set_errno (EINVAL);
325 return -1;
326 }
327
328 av newargv;
329 linebuf cmd;
330 PWCHAR envblock = NULL;
331 path_conv real_path;
332 bool reset_sendsig = false;
333
334 tmp_pathbuf tp;
335 PWCHAR runpath = tp.w_get ();
336 int c_flags;
337
338 bool null_app_name = false;
339 STARTUPINFOW si = {};
340 int looped = 0;
341
342 system_call_handle system_call (mode == _P_SYSTEM);
343
344 __try
345 {
346 child_info_types chtype;
347 if (mode == _P_OVERLAY)
348 chtype = _CH_EXEC;
349 else
350 chtype = _CH_SPAWN;
351
352 moreinfo = cygheap_exec_info::alloc ();
353
354 /* CreateProcess takes one long string that is the command line (sigh).
355 We need to quote any argument that has whitespace or embedded "'s. */
356
357 int ac;
358 for (ac = 0; argv[ac]; ac++)
359 /* nothing */;
360
361 int err;
362 const char *ext;
363 if ((ext = perhaps_suffix (prog_arg, real_path, err, FE_NADA)) == NULL)
364 {
365 set_errno (err);
366 res = -1;
367 __leave;
368 }
369
370 res = newargv.setup (prog_arg, real_path, ext, ac, argv, p_type_exec);
371
372 if (res)
373 __leave;
374
375 if (!real_path.iscygexec () && ::cygheap->cwd.get_error ())
376 {
377 small_printf ("Error: Current working directory %s.\n"
378 "Can't start native Windows application from here.\n\n",
379 ::cygheap->cwd.get_error_desc ());
380 set_errno (::cygheap->cwd.get_error ());
381 res = -1;
382 __leave;
383 }
384
385 if (ac == 3 && argv[1][0] == '/' && tolower (argv[1][1]) == 'c' &&
386 (iscmd (argv[0], "command.com") || iscmd (argv[0], "cmd.exe")))
387 {
388 real_path.check (prog_arg);
389 cmd.add ("\"");
390 if (!real_path.error)
391 cmd.add (real_path.get_win32 ());
392 else
393 cmd.add (argv[0]);
394 cmd.add ("\"");
395 cmd.add (" ");
396 cmd.add (argv[1]);
397 cmd.add (" ");
398 cmd.add (argv[2]);
399 real_path.set_path (argv[0]);
400 null_app_name = true;
401 }
402 else
403 {
404 if (real_path.iscygexec ())
405 {
406 moreinfo->argc = newargv.argc;
407 moreinfo->argv = newargv;
408 }
409 if ((wincmdln || !real_path.iscygexec ())
410 && !cmd.fromargv (newargv, real_path.get_win32 (),
411 real_path.iscygexec ()))
412 {
413 res = -1;
414 __leave;
415 }
416
417
418 if (mode != _P_OVERLAY || !real_path.iscygexec ()
419 || !DuplicateHandle (GetCurrentProcess (), myself.shared_handle (),
420 GetCurrentProcess (), &moreinfo->myself_pinfo,
421 0, TRUE, DUPLICATE_SAME_ACCESS))
422 moreinfo->myself_pinfo = NULL;
423 else
424 VerifyHandle (moreinfo->myself_pinfo);
425 }
426
427 PROCESS_INFORMATION pi;
428 pi.hProcess = pi.hThread = NULL;
429 pi.dwProcessId = pi.dwThreadId = 0;
430
431 c_flags = GetPriorityClass (GetCurrentProcess ());
432 sigproc_printf ("priority class %d", c_flags);
433
434 c_flags |= CREATE_SEPARATE_WOW_VDM | CREATE_UNICODE_ENVIRONMENT;
435
436 /* Add CREATE_DEFAULT_ERROR_MODE flag for non-Cygwin processes so they
437 get the default error mode instead of inheriting the mode Cygwin
438 uses. This allows things like Windows Error Reporting/JIT debugging
439 to work with processes launched from a Cygwin shell. */
440 if (!real_path.iscygexec ())
441 c_flags |= CREATE_DEFAULT_ERROR_MODE;
442
443 /* We're adding the CREATE_BREAKAWAY_FROM_JOB flag here to workaround
444 issues with the "Program Compatibility Assistant (PCA) Service".
445 For some reason, when starting long running sessions from mintty(*),
446 the affected svchost.exe process takes more and more memory and at one
447 point takes over the CPU. At this point the machine becomes
448 unresponsive. The only way to get back to normal is to stop the
449 entire mintty session, or to stop the PCA service. However, a process
450 which is controlled by PCA is part of a compatibility job, which
451 allows child processes to break away from the job. This helps to
452 avoid this issue.
453
454 First we call IsProcessInJob. It fetches the information whether or
455 not we're part of a job 20 times faster than QueryInformationJobObject.
456
457 (*) Note that this is not mintty's fault. It has just been observed
458 with mintty in the first place. See the archives for more info:
459 http://cygwin.com/ml/cygwin-developers/2012-02/msg00018.html */
460 JOBOBJECT_BASIC_LIMIT_INFORMATION jobinfo;
461 BOOL is_in_job;
462
463 if (IsProcessInJob (GetCurrentProcess (), NULL, &is_in_job)
464 && is_in_job
465 && QueryInformationJobObject (NULL, JobObjectBasicLimitInformation,
466 &jobinfo, sizeof jobinfo, NULL)
467 && (jobinfo.LimitFlags & (JOB_OBJECT_LIMIT_BREAKAWAY_OK
468 | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK)))
469 {
470 debug_printf ("Add CREATE_BREAKAWAY_FROM_JOB");
471 c_flags |= CREATE_BREAKAWAY_FROM_JOB;
472 }
473
474 if (mode == _P_DETACH)
475 c_flags |= DETACHED_PROCESS;
476 else
477 fhandler_console::need_invisible ();
478
479 if (mode != _P_OVERLAY)
480 myself->exec_sendsig = NULL;
481 else
482 {
483 /* Reset sendsig so that any process which wants to send a signal
484 to this pid will wait for the new process to become active.
485 Save the old value in case the exec fails. */
486 if (!myself->exec_sendsig)
487 {
488 myself->exec_sendsig = myself->sendsig;
489 myself->exec_dwProcessId = myself->dwProcessId;
490 myself->sendsig = NULL;
491 reset_sendsig = true;
492 }
493 }
494
495 if (null_app_name)
496 runpath = NULL;
497 else
498 {
499 USHORT len = real_path.get_nt_native_path ()->Length / sizeof (WCHAR);
500 if (RtlEqualUnicodePathPrefix (real_path.get_nt_native_path (),
501 &ro_u_natp, FALSE))
502 {
503 runpath = real_path.get_wide_win32_path (runpath);
504 /* If the executable path length is < MAX_PATH, make sure the long
505 path win32 prefix is removed from the path to make subsequent
506 not long path aware native Win32 child processes happy. */
507 if (len < MAX_PATH + 4)
508 {
509 if (runpath[5] == ':')
510 runpath += 4;
511 else if (len < MAX_PATH + 6)
512 *(runpath += 6) = L'\\';
513 }
514 }
515 else if (len < NT_MAX_PATH - ro_u_globalroot.Length / sizeof (WCHAR))
516 {
517 UNICODE_STRING rpath;
518
519 RtlInitEmptyUnicodeString (&rpath, runpath,
520 (NT_MAX_PATH - 1) * sizeof (WCHAR));
521 RtlCopyUnicodeString (&rpath, &ro_u_globalroot);
522 RtlAppendUnicodeStringToString (&rpath,
523 real_path.get_nt_native_path ());
524 }
525 else
526 {
527 set_errno (ENAMETOOLONG);
528 res = -1;
529 __leave;
530 }
531 }
532
533 cygbench ("spawn-worker");
534
535 if (!real_path.iscygexec())
536 ::cygheap->fdtab.set_file_pointers_for_exec ();
537
538 /* If we switch the user, merge the user's Windows environment. */
539 bool switch_user = ::cygheap->user.issetuid ()
540 && (::cygheap->user.saved_uid
541 != ::cygheap->user.real_uid);
542 moreinfo->envp = build_env (envp, envblock, moreinfo->envc,
543 real_path.iscygexec (),
544 switch_user ? ::cygheap->user.primary_token ()
545 : NULL);
546 if (!moreinfo->envp || !envblock)
547 {
548 set_errno (E2BIG);
549 res = -1;
550 __leave;
551 }
552 set (chtype, real_path.iscygexec ());
553 __stdin = in__stdin;
554 __stdout = in__stdout;
555 record_children ();
556
557 si.lpReserved2 = (LPBYTE) this;
558 si.cbReserved2 = sizeof (*this);
559
560 /* Depends on set call above.
561 Some file types might need extra effort in the parent after CreateProcess
562 and before copying the datastructures to the child. So we have to start
563 the child in suspend state, unfortunately, to avoid a race condition. */
564 if (!newargv.win16_exe
565 && (!iscygwin () || mode != _P_OVERLAY
566 || ::cygheap->fdtab.need_fixup_before ()))
567 c_flags |= CREATE_SUSPENDED;
568 /* If a native application should be spawned, we test here if the spawning
569 process is running in a console and, if so, if it's a foreground or
570 background process. If it's a background process, we start the native
571 process with the CREATE_NEW_PROCESS_GROUP flag set. This lets the native
572 process ignore Ctrl-C by default. If we don't do that, pressing Ctrl-C
573 in a console will break native processes running in the background,
574 because the Ctrl-C event is sent to all processes in the console, unless
575 they ignore it explicitely. CREATE_NEW_PROCESS_GROUP does that for us. */
576 if (!iscygwin () && ctty_pgid && ctty_pgid != myself->pgid)
577 c_flags |= CREATE_NEW_PROCESS_GROUP;
578 refresh_cygheap ();
579
580 if (c_flags & CREATE_NEW_PROCESS_GROUP)
581 myself->process_state |= PID_NEW_PG;
582
583 if (mode == _P_DETACH)
584 /* all set */;
585 else if (mode != _P_OVERLAY || !my_wr_proc_pipe)
586 prefork ();
587 else
588 wr_proc_pipe = my_wr_proc_pipe;
589
590 /* Don't allow child to inherit these handles if it's not a Cygwin program.
591 wr_proc_pipe will be injected later. parent won't be used by the child
592 so there is no reason for the child to have it open as it can confuse
593 ps into thinking that children of windows processes are all part of
594 the same "execed" process.
595 FIXME: Someday, make it so that parent is never created when starting
596 non-Cygwin processes. */
597 if (!iscygwin ())
598 {
599 SetHandleInformation (wr_proc_pipe, HANDLE_FLAG_INHERIT, 0);
600 SetHandleInformation (parent, HANDLE_FLAG_INHERIT, 0);
601 }
602 /* FIXME: racy */
603 if (mode != _P_OVERLAY)
604 SetHandleInformation (my_wr_proc_pipe, HANDLE_FLAG_INHERIT, 0);
605 parent_winpid = GetCurrentProcessId ();
606
607 PSECURITY_ATTRIBUTES sa = (PSECURITY_ATTRIBUTES) tp.w_get ();
608 if (!sec_user_nih (sa, cygheap->user.sid (),
609 well_known_authenticated_users_sid,
610 PROCESS_QUERY_LIMITED_INFORMATION))
611 sa = &sec_none_nih;
612
613 fhandler_pty_slave *ptys_primary = NULL;
614 fhandler_console *cons_native = NULL;
615 termios *cons_ti = NULL;
616 pid_t cons_owner = 0;
617 for (int i = 0; i < 3; i ++)
618 {
619 const int chk_order[] = {1, 0, 2};
620 int fd = chk_order[i];
621 fhandler_base *fh = ::cygheap->fdtab[fd];
622 if (fh && fh->get_major () == DEV_PTYS_MAJOR)
623 {
624 fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
625 if (ptys_primary == NULL)
626 ptys_primary = ptys;
627 }
628 else if (fh && fh->get_major () == DEV_CONS_MAJOR)
629 {
630 fhandler_console *cons = (fhandler_console *) fh;
631 if (!iscygwin ())
632 {
633 if (cons_native == NULL)
634 {
635 cons_native = cons;
636 cons_ti = &((tty *)cons->tc ())->ti;
637 cons_owner = cons->get_owner ();
638 }
639 tty::cons_mode conmode =
640 (ctty_pgid && ctty_pgid == myself->pgid) ?
641 tty::native : tty::restore;
642 if (fd == 0)
643 fhandler_console::set_input_mode (conmode,
644 cons_ti, cons->get_handle_set ());
645 else if (fd == 1 || fd == 2)
646 fhandler_console::set_output_mode (conmode,
647 cons_ti, cons->get_handle_set ());
648 }
649 }
650 }
651 struct fhandler_console::handle_set_t cons_handle_set = { 0, };
652 if (cons_native)
653 /* Console handles will be closed by close_all_files(),
654 therefore, duplicate them here */
655 cons_native->get_duplicated_handle_set (&cons_handle_set);
656
657 if (!iscygwin ())
658 {
659 int fd;
660 cfd.rewind ();
661 while ((fd = cfd.next ()) >= 0)
662 if (cfd->get_major () == DEV_PTYS_MAJOR)
663 {
664 fhandler_pty_slave *ptys =
665 (fhandler_pty_slave *)(fhandler_base *) cfd;
666 ptys->create_invisible_console ();
667 ptys->setup_locale ();
668 }
669 else if (cfd->get_dev () == FH_PIPEW
670 && (fd == (in__stdout < 0 ? 1 : in__stdout) || fd == 2))
671 {
672 fhandler_pipe *pipe = (fhandler_pipe *)(fhandler_base *) cfd;
673 pipe->close_query_handle ();
674 pipe->set_pipe_non_blocking (false);
675 }
676 else if (cfd->get_dev () == FH_PIPER
677 && fd == (in__stdin < 0 ? 0 : in__stdin))
678 {
679 fhandler_pipe *pipe = (fhandler_pipe *)(fhandler_base *) cfd;
680 pipe->set_pipe_non_blocking (false);
681 }
682 }
683
684 bool enable_pcon = false;
685 HANDLE ptys_from_master_nat = NULL;
686 HANDLE ptys_input_available_event = NULL;
687 HANDLE ptys_pcon_mutex = NULL;
688 HANDLE ptys_input_mutex = NULL;
689 tty *ptys_ttyp = NULL;
690 bool stdin_is_ptys = false;
691 if (!iscygwin () && ptys_primary && is_console_app (runpath))
692 {
693 bool nopcon = mode != _P_OVERLAY && mode != _P_WAIT;
694 if (disable_pcon || !ptys_primary->term_has_pcon_cap (envblock))
695 nopcon = true;
696 ptys_ttyp = ptys_primary->get_ttyp ();
697 WaitForSingleObject (ptys_primary->pcon_mutex, INFINITE);
698 if (ptys_primary->setup_pseudoconsole (nopcon))
699 enable_pcon = true;
700 ReleaseMutex (ptys_primary->pcon_mutex);
701 HANDLE h_stdin = handle ((in__stdin < 0 ? 0 : in__stdin), false);
702 if (h_stdin == ptys_primary->get_handle_nat ())
703 stdin_is_ptys = true;
704 ptys_from_master_nat = ptys_primary->get_handle_nat ();
705 DuplicateHandle (GetCurrentProcess (), ptys_from_master_nat,
706 GetCurrentProcess (), &ptys_from_master_nat,
707 0, 0, DUPLICATE_SAME_ACCESS);
708 ptys_input_available_event =
709 ptys_primary->get_input_available_event ();
710 DuplicateHandle (GetCurrentProcess (), ptys_input_available_event,
711 GetCurrentProcess (), &ptys_input_available_event,
712 0, 0, DUPLICATE_SAME_ACCESS);
713 DuplicateHandle (GetCurrentProcess (), ptys_primary->pcon_mutex,
714 GetCurrentProcess (), &ptys_pcon_mutex,
715 0, 0, DUPLICATE_SAME_ACCESS);
716 DuplicateHandle (GetCurrentProcess (), ptys_primary->input_mutex,
717 GetCurrentProcess (), &ptys_input_mutex,
718 0, 0, DUPLICATE_SAME_ACCESS);
719 if (!enable_pcon && ptys_ttyp->getpgid () == myself->pgid
720 && stdin_is_ptys
721 && ptys_ttyp->pcon_input_state_eq (tty::to_cyg))
722 {
723 WaitForSingleObject (ptys_input_mutex, mutex_timeout);
724 fhandler_pty_slave::transfer_input (tty::to_nat,
725 ptys_primary->get_handle (),
726 ptys_ttyp, ptys_input_available_event);
727 ReleaseMutex (ptys_input_mutex);
728 }
729 }
730
731 /* Set up needed handles for stdio */
732 si.dwFlags = STARTF_USESTDHANDLES;
733 si.hStdInput = handle ((in__stdin < 0 ? 0 : in__stdin), false);
734 si.hStdOutput = handle ((in__stdout < 0 ? 1 : in__stdout), true);
735 si.hStdError = handle (2, true);
736
737 si.cb = sizeof (si);
738
739 if (!iscygwin ())
740 init_console_handler (myself->ctty > 0);
741
742 loop:
743 /* When ruid != euid we create the new process under the current original
744 account and impersonate in child, this way maintaining the different
745 effective vs. real ids.
746 FIXME: If ruid != euid and ruid != saved_uid we currently give
747 up on ruid. The new process will have ruid == euid. */
748 ::cygheap->user.deimpersonate ();
749
750 if (!real_path.iscygexec () && mode == _P_OVERLAY)
751 myself->process_state |= PID_NOTCYGWIN;
752
753 cygpid = (mode != _P_OVERLAY) ? create_cygwin_pid () : myself->pid;
754
755 wchar_t wcmd[(size_t) cmd];
756 if (!::cygheap->user.issetuid ()
757 || (::cygheap->user.saved_uid == ::cygheap->user.real_uid
758 && ::cygheap->user.saved_gid == ::cygheap->user.real_gid
759 && !::cygheap->user.groups.issetgroups ()
760 && !::cygheap->user.setuid_to_restricted))
761 {
762 rc = CreateProcessW (runpath, /* image name w/ full path */
763 cmd.wcs (wcmd), /* what was passed to exec */
764 sa, /* process security attrs */
765 sa, /* thread security attrs */
766 TRUE, /* inherit handles */
767 c_flags,
768 envblock, /* environment */
769 NULL,
770 &si,
771 &pi);
772 }
773 else
774 {
775 /* Give access to myself */
776 if (mode == _P_OVERLAY)
777 myself.set_acl();
778
779 HWINSTA hwst = NULL;
780 HWINSTA hwst_orig = GetProcessWindowStation ();
781 HDESK hdsk = NULL;
782 HDESK hdsk_orig = GetThreadDesktop (GetCurrentThreadId ());
783 /* Don't create WindowStation and Desktop for restricted child. */
784 if (!::cygheap->user.setuid_to_restricted)
785 {
786 PSECURITY_ATTRIBUTES sa;
787 WCHAR sid[128];
788 WCHAR wstname[1024] = { L'\0' };
789
790 sa = sec_user ((PSECURITY_ATTRIBUTES) alloca (1024),
791 ::cygheap->user.sid ());
792 /* We're creating a window station per user, not per logon
793 session First of all we might not have a valid logon session
794 for the user (logon by create_token), and second, it doesn't
795 make sense in terms of security to create a new window
796 station for every logon of the same user. It just fills up
797 the system with window stations for no good reason. */
798 hwst = CreateWindowStationW (::cygheap->user.get_windows_id (sid),
799 0, GENERIC_READ | GENERIC_WRITE, sa);
800 if (!hwst)
801 system_printf ("CreateWindowStation failed, %E");
802 else if (!SetProcessWindowStation (hwst))
803 system_printf ("SetProcessWindowStation failed, %E");
804 else if (!(hdsk = CreateDesktopW (L"Default", NULL, NULL, 0,
805 GENERIC_ALL, sa)))
806 system_printf ("CreateDesktop failed, %E");
807 else
808 {
809 wcpcpy (wcpcpy (wstname, sid), L"\\Default");
810 si.lpDesktop = wstname;
811 debug_printf ("Desktop: %W", si.lpDesktop);
812 }
813 }
814
815 rc = CreateProcessAsUserW (::cygheap->user.primary_token (),
816 runpath, /* image name w/ full path */
817 cmd.wcs (wcmd), /* what was passed to exec */
818 sa, /* process security attrs */
819 sa, /* thread security attrs */
820 TRUE, /* inherit handles */
821 c_flags,
822 envblock, /* environment */
823 NULL,
824 &si,
825 &pi);
826 if (hwst)
827 {
828 SetProcessWindowStation (hwst_orig);
829 CloseWindowStation (hwst);
830 }
831 if (hdsk)
832 {
833 SetThreadDesktop (hdsk_orig);
834 CloseDesktop (hdsk);
835 }
836 }
837
838 if (mode != _P_OVERLAY)
839 SetHandleInformation (my_wr_proc_pipe, HANDLE_FLAG_INHERIT,
840 HANDLE_FLAG_INHERIT);
841
842 /* Set errno now so that debugging messages from it appear before our
843 final debugging message [this is a general rule for debugging
844 messages]. */
845 if (!rc)
846 {
847 __seterrno ();
848 syscall_printf ("CreateProcess failed, %E");
849 /* If this was a failed exec, restore the saved sendsig. */
850 if (reset_sendsig)
851 {
852 myself->sendsig = myself->exec_sendsig;
853 myself->exec_sendsig = NULL;
854 }
855 myself->process_state &= ~PID_NOTCYGWIN;
856 /* Reset handle inheritance to default when the execution of a'
857 non-Cygwin process fails. Only need to do this for _P_OVERLAY
858 since the handle will be closed otherwise. Don't need to do
859 this for 'parent' since it will be closed in every case.
860 See FIXME above. */
861 if (!iscygwin () && mode == _P_OVERLAY)
862 SetHandleInformation (wr_proc_pipe, HANDLE_FLAG_INHERIT,
863 HANDLE_FLAG_INHERIT);
864 if (wr_proc_pipe == my_wr_proc_pipe)
865 wr_proc_pipe = NULL; /* We still own it: don't nuke in destructor */
866
867 /* Restore impersonation. In case of _P_OVERLAY this isn't
868 allowed since it would overwrite child data. */
869 if (mode != _P_OVERLAY)
870 ::cygheap->user.reimpersonate ();
871
872 res = -1;
873 __leave;
874 }
875
876 /* The CREATE_SUSPENDED case is handled below */
877 if (iscygwin () && !(c_flags & CREATE_SUSPENDED))
878 strace.write_childpid (pi.dwProcessId);
879
880 /* Fixup the parent data structures if needed and resume the child's
881 main thread. */
882 if (::cygheap->fdtab.need_fixup_before ())
883 ::cygheap->fdtab.fixup_before_exec (pi.dwProcessId);
884
885 /* Print the original program name here so the user can see that too. */
886 syscall_printf ("pid %d, prog_arg %s, cmd line %.9500s)",
887 rc ? cygpid : (unsigned int) -1, prog_arg, (const char *) cmd);
888
889 /* Name the handle similarly to proc_subproc. */
890 ProtectHandle1 (pi.hProcess, childhProc);
891
892 if (mode == _P_OVERLAY)
893 {
894 myself->dwProcessId = pi.dwProcessId;
895 strace.execing = 1;
896 myself.hProcess = hExeced = pi.hProcess;
897 HANDLE old_winpid_hdl = myself.shared_winpid_handle ();
898 if (!real_path.iscygexec ())
899 {
900 /* If the child process is not a Cygwin process, we have to
901 create a new winpid symlink on behalf of the child process
902 not being able to do this by itself. */
903 myself.create_winpid_symlink ();
904 }
905 NtClose (old_winpid_hdl);
906 real_path.get_wide_win32_path (myself->progname); // FIXME: race?
907 sigproc_printf ("new process name %W", myself->progname);
908 if (!iscygwin ())
909 close_all_files ();
910 }
911 else
912 {
913 myself->set_has_pgid_children ();
914 ProtectHandle (pi.hThread);
915 pinfo child (cygpid,
916 PID_IN_USE | (real_path.iscygexec () ? 0 : PID_NOTCYGWIN));
917 if (!child)
918 {
919 syscall_printf ("pinfo failed");
920 if (get_errno () != ENOMEM)
921 set_errno (EAGAIN);
922 res = -1;
923 __leave;
924 }
925 child->dwProcessId = pi.dwProcessId;
926 child.hProcess = pi.hProcess;
927
928 real_path.get_wide_win32_path (child->progname);
929 /* This introduces an unreferenced, open handle into the child.
930 The purpose is to keep the pid shared memory open so that all
931 of the fields filled out by child.remember do not disappear
932 and so there is not a brief period during which the pid is
933 not available. */
934 DuplicateHandle (GetCurrentProcess (), child.shared_handle (),
935 pi.hProcess, NULL, 0, 0, DUPLICATE_SAME_ACCESS);
936 if (!real_path.iscygexec ())
937 {
938 /* If the child process is not a Cygwin process, we have to
939 create a new winpid symlink and induce it into the child
940 process as well to keep it over the lifetime of the child. */
941 child.create_winpid_symlink ();
942 DuplicateHandle (GetCurrentProcess (),
943 child.shared_winpid_handle (),
944 pi.hProcess, NULL, 0, 0, DUPLICATE_SAME_ACCESS);
945 }
946 child->start_time = time (NULL); /* Register child's starting time. */
947 child->nice = myself->nice;
948 postfork (child);
949 if (mode != _P_DETACH
950 && (!child.remember () || !child.attach ()))
951 {
952 /* FIXME: Child in strange state now */
953 CloseHandle (pi.hProcess);
954 ForceCloseHandle (pi.hThread);
955 res = -1;
956 __leave;
957 }
958 }
959
960 /* Start the child running */
961 if (c_flags & CREATE_SUSPENDED)
962 {
963 /* Inject a non-inheritable wr_proc_pipe handle into child so that we
964 can accurately track when the child exits without keeping this
965 process waiting around for it to exit. */
966 if (!iscygwin ())
967 DuplicateHandle (GetCurrentProcess (), wr_proc_pipe, pi.hProcess, NULL,
968 0, false, DUPLICATE_SAME_ACCESS);
969 ResumeThread (pi.hThread);
970 if (iscygwin ())
971 strace.write_childpid (pi.dwProcessId);
972 }
973 ForceCloseHandle (pi.hThread);
974
975 sigproc_printf ("spawned windows pid %d", pi.dwProcessId);
976
977 bool synced;
978 if ((mode == _P_DETACH || mode == _P_NOWAIT) && !iscygwin ())
979 synced = false;
980 else
981 /* Just mark a non-cygwin process as 'synced'. We will still eventually
982 wait for it to exit in maybe_set_exit_code_from_windows(). */
983 synced = iscygwin () ? sync (pi.dwProcessId, pi.hProcess, INFINITE) : true;
984
985 switch (mode)
986 {
987 case _P_OVERLAY:
988 myself.hProcess = pi.hProcess;
989 if (!synced)
990 {
991 if (!proc_retry (pi.hProcess))
992 {
993 looped++;
994 goto loop;
995 }
996 close_all_files (true);
997 }
998 else
999 {
1000 if (iscygwin ())
1001 close_all_files (true);
1002 if (!my_wr_proc_pipe
1003 && WaitForSingleObject (pi.hProcess, 0) == WAIT_TIMEOUT)
1004 wait_for_myself ();
1005 }
1006 if (sem)
1007 __posix_spawn_sem_release (sem, 0);
1008 if (enable_pcon || ptys_ttyp || cons_native)
1009 WaitForSingleObject (pi.hProcess, INFINITE);
1010 if (ptys_ttyp)
1011 {
1012 ptys_ttyp->wait_pcon_fwd ();
1013 if (ptys_ttyp->getpgid () == myself->pgid && stdin_is_ptys
1014 && ptys_ttyp->pcon_input_state_eq (tty::to_nat))
1015 {
1016 WaitForSingleObject (ptys_input_mutex, mutex_timeout);
1017 fhandler_pty_slave::transfer_input (tty::to_cyg,
1018 ptys_from_master_nat, ptys_ttyp,
1019 ptys_input_available_event);
1020 ReleaseMutex (ptys_input_mutex);
1021 }
1022 CloseHandle (ptys_from_master_nat);
1023 CloseHandle (ptys_input_mutex);
1024 CloseHandle (ptys_input_available_event);
1025 WaitForSingleObject (ptys_pcon_mutex, INFINITE);
1026 fhandler_pty_slave::close_pseudoconsole (ptys_ttyp);
1027 ReleaseMutex (ptys_pcon_mutex);
1028 CloseHandle (ptys_pcon_mutex);
1029 }
1030 if (cons_native)
1031 {
1032 tty::cons_mode conmode =
1033 cons_owner == myself->pid ? tty::restore : tty::cygwin;
1034 fhandler_console::set_output_mode (conmode, cons_ti,
1035 &cons_handle_set);
1036 fhandler_console::set_input_mode (conmode, cons_ti,
1037 &cons_handle_set);
1038 fhandler_console::close_handle_set (&cons_handle_set);
1039 }
1040 myself.exit (EXITCODE_NOSET);
1041 break;
1042 case _P_WAIT:
1043 case _P_SYSTEM:
1044 system_call.arm ();
1045 if (waitpid (cygpid, &res, 0) != cygpid)
1046 res = -1;
1047 if (ptys_ttyp)
1048 {
1049 ptys_ttyp->wait_pcon_fwd ();
1050 if (ptys_ttyp->getpgid () == myself->pgid && stdin_is_ptys
1051 && ptys_ttyp->pcon_input_state_eq (tty::to_nat))
1052 {
1053 WaitForSingleObject (ptys_input_mutex, mutex_timeout);
1054 fhandler_pty_slave::transfer_input (tty::to_cyg,
1055 ptys_from_master_nat, ptys_ttyp,
1056 ptys_input_available_event);
1057 ReleaseMutex (ptys_input_mutex);
1058 }
1059 CloseHandle (ptys_from_master_nat);
1060 CloseHandle (ptys_input_mutex);
1061 CloseHandle (ptys_input_available_event);
1062 WaitForSingleObject (ptys_pcon_mutex, INFINITE);
1063 fhandler_pty_slave::close_pseudoconsole (ptys_ttyp);
1064 ReleaseMutex (ptys_pcon_mutex);
1065 CloseHandle (ptys_pcon_mutex);
1066 }
1067 if (cons_native)
1068 {
1069 tty::cons_mode conmode =
1070 cons_owner == myself->pid ? tty::restore : tty::cygwin;
1071 fhandler_console::set_output_mode (conmode, cons_ti,
1072 &cons_handle_set);
1073 fhandler_console::set_input_mode (conmode, cons_ti,
1074 &cons_handle_set);
1075 fhandler_console::close_handle_set (&cons_handle_set);
1076 }
1077 break;
1078 case _P_DETACH:
1079 res = 0; /* Lost all memory of this child. */
1080 break;
1081 case _P_NOWAIT:
1082 case _P_NOWAITO:
1083 case _P_VFORK:
1084 res = cygpid;
1085 break;
1086 default:
1087 break;
1088 }
1089 }
1090 __except (NO_ERROR)
1091 {
1092 if (get_errno () == ENOMEM)
1093 set_errno (E2BIG);
1094 else
1095 set_errno (EFAULT);
1096 res = -1;
1097 }
1098 __endtry
1099 this->cleanup ();
1100 if (envblock)
1101 free (envblock);
1102
1103 return (int) res;
1104 }
1105
1106 extern "C" int
1107 cwait (int *result, int pid, int)
1108 {
1109 return waitpid (pid, result, 0);
1110 }
1111
1112 /*
1113 * Helper function for spawn runtime calls.
1114 * Doesn't search the path.
1115 */
1116
1117 extern "C" int
1118 spawnve (int mode, const char *path, const char *const *argv,
1119 const char *const *envp)
1120 {
1121 static char *const empty_env[] = { NULL };
1122
1123 int ret;
1124
1125 syscall_printf ("spawnve (%s, %s, %p)", path, argv[0], envp);
1126
1127 if (!envp)
1128 envp = empty_env;
1129
1130 switch (_P_MODE (mode))
1131 {
1132 case _P_OVERLAY:
1133 ch_spawn.worker (path, argv, envp, mode);
1134 /* Errno should be set by worker. */
1135 ret = -1;
1136 break;
1137 case _P_VFORK:
1138 case _P_NOWAIT:
1139 case _P_NOWAITO:
1140 case _P_WAIT:
1141 case _P_DETACH:
1142 case _P_SYSTEM:
1143 ret = ch_spawn.worker (path, argv, envp, mode);
1144 break;
1145 default:
1146 set_errno (EINVAL);
1147 ret = -1;
1148 break;
1149 }
1150 return ret;
1151 }
1152
1153 /*
1154 * spawn functions as implemented in the MS runtime library.
1155 * Most of these based on (and copied from) newlib/libc/posix/execXX.c
1156 */
1157
1158 extern "C" int
1159 spawnl (int mode, const char *path, const char *arg0, ...)
1160 {
1161 int i;
1162 va_list args;
1163 const char *argv[256];
1164
1165 va_start (args, arg0);
1166 argv[0] = arg0;
1167 i = 1;
1168
1169 do
1170 argv[i] = va_arg (args, const char *);
1171 while (argv[i++] != NULL);
1172
1173 va_end (args);
1174
1175 return spawnve (mode, path, (char * const *) argv, cur_environ ());
1176 }
1177
1178 extern "C" int
1179 spawnle (int mode, const char *path, const char *arg0, ...)
1180 {
1181 int i;
1182 va_list args;
1183 const char * const *envp;
1184 const char *argv[256];
1185
1186 va_start (args, arg0);
1187 argv[0] = arg0;
1188 i = 1;
1189
1190 do
1191 argv[i] = va_arg (args, const char *);
1192 while (argv[i++] != NULL);
1193
1194 envp = va_arg (args, const char * const *);
1195 va_end (args);
1196
1197 return spawnve (mode, path, (char * const *) argv, (char * const *) envp);
1198 }
1199
1200 extern "C" int
1201 spawnlp (int mode, const char *file, const char *arg0, ...)
1202 {
1203 int i;
1204 va_list args;
1205 const char *argv[256];
1206 path_conv buf;
1207
1208 va_start (args, arg0);
1209 argv[0] = arg0;
1210 i = 1;
1211
1212 do
1213 argv[i] = va_arg (args, const char *);
1214 while (argv[i++] != NULL);
1215
1216 va_end (args);
1217
1218 return spawnve (mode | _P_PATH_TYPE_EXEC, find_exec (file, buf),
1219 (char * const *) argv, cur_environ ());
1220 }
1221
1222 extern "C" int
1223 spawnlpe (int mode, const char *file, const char *arg0, ...)
1224 {
1225 int i;
1226 va_list args;
1227 const char * const *envp;
1228 const char *argv[256];
1229 path_conv buf;
1230
1231 va_start (args, arg0);
1232 argv[0] = arg0;
1233 i = 1;
1234
1235 do
1236 argv[i] = va_arg (args, const char *);
1237 while (argv[i++] != NULL);
1238
1239 envp = va_arg (args, const char * const *);
1240 va_end (args);
1241
1242 return spawnve (mode | _P_PATH_TYPE_EXEC, find_exec (file, buf),
1243 (char * const *) argv, envp);
1244 }
1245
1246 extern "C" int
1247 spawnv (int mode, const char *path, const char * const *argv)
1248 {
1249 return spawnve (mode, path, argv, cur_environ ());
1250 }
1251
1252 extern "C" int
1253 spawnvp (int mode, const char *file, const char * const *argv)
1254 {
1255 path_conv buf;
1256 return spawnve (mode | _P_PATH_TYPE_EXEC,
1257 find_exec (file, buf, "PATH", FE_NNF) ?: "",
1258 argv, cur_environ ());
1259 }
1260
1261 extern "C" int
1262 spawnvpe (int mode, const char *file, const char * const *argv,
1263 const char * const *envp)
1264 {
1265 path_conv buf;
1266 return spawnve (mode | _P_PATH_TYPE_EXEC,
1267 find_exec (file, buf, "PATH", FE_NNF) ?: "",
1268 argv, envp);
1269 }
1270
1271 int
1272 av::setup (const char *prog_arg, path_conv& real_path, const char *ext,
1273 int argc, const char *const *argv, bool p_type_exec)
1274 {
1275 const char *p;
1276 bool exeext = ascii_strcasematch (ext, ".exe");
1277 new (this) av (argc, argv);
1278 if ((exeext && real_path.iscygexec ()) || ascii_strcasematch (ext, ".bat")
1279 || (!*ext && ((p = ext - 4) > real_path.get_win32 ())
1280 && (ascii_strcasematch (p, ".bat") || ascii_strcasematch (p, ".cmd")
1281 || ascii_strcasematch (p, ".btm"))))
1282 /* no extra checks needed */;
1283 else
1284 while (1)
1285 {
1286 char *pgm = NULL;
1287 char *arg1 = NULL;
1288 char *ptr, *buf;
1289 OBJECT_ATTRIBUTES attr;
1290 IO_STATUS_BLOCK io;
1291 HANDLE h;
1292 NTSTATUS status;
1293 LARGE_INTEGER size;
1294
1295 status = NtOpenFile (&h, SYNCHRONIZE | GENERIC_READ,
1296 real_path.get_object_attr (attr, sec_none_nih),
1297 &io, FILE_SHARE_VALID_FLAGS,
1298 FILE_SYNCHRONOUS_IO_NONALERT
1299 | FILE_OPEN_FOR_BACKUP_INTENT
1300 | FILE_NON_DIRECTORY_FILE);
1301 if (status == STATUS_IO_REPARSE_TAG_NOT_HANDLED)
1302 {
1303 /* This is most likely an app execution alias (such as the
1304 Windows Store version of Python, i.e. not a Cygwin program */
1305 real_path.set_cygexec (false);
1306 break;
1307 }
1308 if (!NT_SUCCESS (status))
1309 {
1310 /* File is not readable? Doesn't mean it's not executable.
1311 Test for executability and if so, just assume the file is
1312 a cygwin executable and go ahead. */
1313 if (status == STATUS_ACCESS_DENIED && real_path.has_acls ()
1314 && check_file_access (real_path, X_OK, true) == 0)
1315 {
1316 real_path.set_cygexec (true);
1317 break;
1318 }
1319 SetLastError (RtlNtStatusToDosError (status));
1320 goto err;
1321 }
1322 if (!GetFileSizeEx (h, &size))
1323 {
1324 NtClose (h);
1325 goto err;
1326 }
1327 if (size.QuadPart > (LONGLONG) wincap.allocation_granularity ())
1328 size.LowPart = wincap.allocation_granularity ();
1329
1330 HANDLE hm = CreateFileMapping (h, &sec_none_nih, PAGE_READONLY,
1331 0, 0, NULL);
1332 NtClose (h);
1333 if (!hm)
1334 {
1335 /* ERROR_FILE_INVALID indicates very likely an empty file. */
1336 if (GetLastError () == ERROR_FILE_INVALID)
1337 {
1338 debug_printf ("zero length file, treat as script.");
1339 goto just_shell;
1340 }
1341 goto err;
1342 }
1343 /* Try to map the first 64K of the image. That's enough for the local
1344 tests, and it's enough for hook_or_detect_cygwin to compute the IAT
1345 address. */
1346 buf = (char *) MapViewOfFile (hm, FILE_MAP_READ, 0, 0, size.LowPart);
1347 if (!buf)
1348 {
1349 CloseHandle (hm);
1350 goto err;
1351 }
1352
1353 {
1354 __try
1355 {
1356 if (buf[0] == 'M' && buf[1] == 'Z')
1357 {
1358 WORD subsys;
1359 unsigned off = (unsigned char) buf[0x18] | (((unsigned char) buf[0x19]) << 8);
1360 win16_exe = off < sizeof (IMAGE_DOS_HEADER);
1361 if (!win16_exe)
1362 real_path.set_cygexec (hook_or_detect_cygwin (buf, NULL,
1363 subsys, hm));
1364 else
1365 real_path.set_cygexec (false);
1366 UnmapViewOfFile (buf);
1367 CloseHandle (hm);
1368 break;
1369 }
1370 }
1371 __except (NO_ERROR)
1372 {
1373 UnmapViewOfFile (buf);
1374 CloseHandle (hm);
1375 real_path.set_cygexec (false);
1376 break;
1377 }
1378 __endtry
1379 }
1380 CloseHandle (hm);
1381
1382 debug_printf ("%s is possibly a script", real_path.get_win32 ());
1383
1384 ptr = buf;
1385 if (*ptr++ == '#' && *ptr++ == '!')
1386 {
1387 ptr += strspn (ptr, " \t");
1388 size_t len = strcspn (ptr, "\r\n");
1389 while (ptr[len - 1] == ' ' || ptr[len - 1] == '\t')
1390 len--;
1391 if (len)
1392 {
1393 char *namebuf = (char *) alloca (len + 1);
1394 memcpy (namebuf, ptr, len);
1395 namebuf[len] = '\0';
1396 for (ptr = pgm = namebuf; *ptr; ptr++)
1397 if (!arg1 && (*ptr == ' ' || *ptr == '\t'))
1398 {
1399 /* Null terminate the initial command and step over any
1400 additional white space. If we've hit the end of the
1401 line, exit the loop. Otherwise, we've found the first
1402 argument. Position the current pointer on the last known
1403 white space. */
1404 *ptr = '\0';
1405 char *newptr = ptr + 1;
1406 newptr += strspn (newptr, " \t");
1407 if (!*newptr)
1408 break;
1409 arg1 = newptr;
1410 ptr = newptr - 1;
1411 }
1412 }
1413 }
1414 UnmapViewOfFile (buf);
1415 just_shell:
1416 /* Check if script is executable. Otherwise we start non-executable
1417 scripts successfully, which is incorrect behaviour. */
1418 if (real_path.has_acls ()
1419 && check_file_access (real_path, X_OK, true) < 0)
1420 return -1; /* errno is already set. */
1421
1422 if (!pgm)
1423 {
1424 if (!p_type_exec)
1425 {
1426 /* Not called from exec[lv]p. Don't try to treat as script. */
1427 debug_printf ("%s is not a valid executable",
1428 real_path.get_win32 ());
1429 set_errno (ENOEXEC);
1430 return -1;
1431 }
1432 if (ascii_strcasematch (ext, ".com"))
1433 break;
1434 pgm = (char *) "/bin/sh";
1435 arg1 = NULL;
1436 }
1437
1438 /* Replace argv[0] with the full path to the script if this is the
1439 first time through the loop. */
1440 replace0_maybe (prog_arg);
1441
1442 /* pointers:
1443 * pgm interpreter name
1444 * arg1 optional string
1445 */
1446 if (arg1)
1447 unshift (arg1);
1448
1449 find_exec (pgm, real_path, "PATH", FE_NADA, &ext);
1450 unshift (real_path.get_posix ());
1451 }
1452 if (real_path.iscygexec ())
1453 dup_all ();
1454 return 0;
1455
1456 err:
1457 __seterrno ();
1458 return -1;
1459 }
1460
1461 /* The following __posix_spawn_* functions are called from newlib's posix_spawn
1462 implementation. The original code in newlib has been taken from FreeBSD,
1463 and the core code relies on specific, non-portable behaviour of vfork(2).
1464 Our replacement implementation uses a semaphore to synchronize parent and
1465 child process. Note: __posix_spawn_fork in fork.cc is part of the set. */
1466
1467 /* Create an inheritable semaphore. Set it to 0 (== non-signalled), so the
1468 parent can wait on the semaphore immediately. */
1469 extern "C" int
1470 __posix_spawn_sem_create (void **semp)
1471 {
1472 HANDLE sem;
1473 OBJECT_ATTRIBUTES attr;
1474 NTSTATUS status;
1475
1476 if (!semp)
1477 return EINVAL;
1478 InitializeObjectAttributes (&attr, NULL, OBJ_INHERIT, NULL, NULL);
1479 status = NtCreateSemaphore (&sem, SEMAPHORE_ALL_ACCESS, &attr, 0, INT_MAX);
1480 if (!NT_SUCCESS (status))
1481 return geterrno_from_nt_status (status);
1482 *semp = sem;
1483 return 0;
1484 }
1485
1486 /* Signal the semaphore. "error" should be 0 if all went fine and the
1487 exec'd child process is up and running, a useful POSIX error code otherwise.
1488 After releasing the semaphore, the value of the semaphore reflects
1489 the error code + 1. Thus, after WFMO in__posix_spawn_sem_wait_and_close,
1490 querying the value of the semaphore returns either 0 if all went well,
1491 or a value > 0 equivalent to the POSIX error code. */
1492 extern "C" void
1493 __posix_spawn_sem_release (void *sem, int error)
1494 {
1495 ReleaseSemaphore (sem, error + 1, NULL);
1496 }
1497
1498 /* Helper to check the semaphore value. */
1499 static inline int
1500 __posix_spawn_sem_query (void *sem)
1501 {
1502 SEMAPHORE_BASIC_INFORMATION sbi;
1503
1504 NtQuerySemaphore (sem, SemaphoreBasicInformation, &sbi, sizeof sbi, NULL);
1505 return sbi.CurrentCount;
1506 }
1507
1508 /* Called from parent to wait for fork/exec completion. We're waiting for
1509 the semaphore as well as the child's process handle, so even if the
1510 child crashes without signalling the semaphore, we won't wait infinitely. */
1511 extern "C" int
1512 __posix_spawn_sem_wait_and_close (void *sem, void *proc)
1513 {
1514 int ret = 0;
1515 HANDLE w4[2] = { sem, proc };
1516
1517 switch (WaitForMultipleObjects (2, w4, FALSE, INFINITE))
1518 {
1519 case WAIT_OBJECT_0:
1520 ret = __posix_spawn_sem_query (sem);
1521 break;
1522 case WAIT_OBJECT_0 + 1:
1523 /* If we return here due to the child process dying, the semaphore is
1524 very likely not signalled. Check this here and return a valid error
1525 code. */
1526 ret = __posix_spawn_sem_query (sem);
1527 if (ret == 0)
1528 ret = ECHILD;
1529 break;
1530 default:
1531 ret = geterrno_from_win_error ();
1532 break;
1533 }
1534
1535 CloseHandle (sem);
1536 return ret;
1537 }
1538
1539 /* Replacement for execve/execvpe, called from forked child in newlib's
1540 posix_spawn. The relevant difference is the additional semaphore
1541 so the worker method (which is not supposed to return on success)
1542 can signal the semaphore after sync'ing with the exec'd child. */
1543 extern "C" int
1544 __posix_spawn_execvpe (const char *path, char * const *argv, char *const *envp,
1545 HANDLE sem, int use_env_path)
1546 {
1547 path_conv buf;
1548
1549 static char *const empty_env[] = { NULL };
1550 if (!envp)
1551 envp = empty_env;
1552 ch_spawn.set_sem (sem);
1553 ch_spawn.worker (use_env_path ? (find_exec (path, buf, "PATH", FE_NNF) ?: "")
1554 : path,
1555 argv, envp,
1556 _P_OVERLAY | (use_env_path ? _P_PATH_TYPE_EXEC : 0));
1557 __posix_spawn_sem_release (sem, errno);
1558 return -1;
1559 }
This page took 0.120979 seconds and 5 git commands to generate.