]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygwin/spawn.cc
* spawn.cc (pthread_cleanup): New struct.
[newlib-cygwin.git] / winsup / cygwin / spawn.cc
CommitLineData
1fd5e000
CF
1/* spawn.cc
2
d1fb625d 3 Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
1fd5e000
CF
4
5This file is part of Cygwin.
6
7This software is a copyrighted work licensed under the terms of the
8Cygwin license. Please consult the file "CYGWIN_LICENSE" for
9details. */
10
4c8d72de 11#include "winsup.h"
1fd5e000
CF
12#include <stdlib.h>
13#include <stdarg.h>
14#include <unistd.h>
15#include <process.h>
16#include <sys/wait.h>
1fd5e000 17#include <limits.h>
d0b178fe
DD
18#include <wingdi.h>
19#include <winuser.h>
1fd5e000 20#include <ctype.h>
bccd5e0d 21#include "cygerrno.h"
f0338f54 22#include <sys/cygwin.h>
6b91b8d5 23#include "security.h"
d1fb625d 24#include "fhandler.h"
bc54734d 25#include "path.h"
e2ebe117 26#include "dtable.h"
bccd5e0d 27#include "sigproc.h"
8dec7b03 28#include "cygheap.h"
488c7683 29#include "child_info.h"
2a6fc028 30#include "shared_info.h"
e2ebe117 31#include "pinfo.h"
f0338f54 32#define NEED_VFORK
bccd5e0d 33#include "perthread.h"
f0338f54
CF
34#include "registry.h"
35#include "environ.h"
3f5046a5 36#include "cygthread.h"
1fd5e000 37
1fd5e000
CF
38#define LINE_BUF_CHUNK (MAX_PATH * 2)
39
4c45a897 40static suffix_info std_suffixes[] =
1fd5e000
CF
41{
42 suffix_info (".exe", 1), suffix_info ("", 1),
43 suffix_info (".com"), suffix_info (".cmd"),
44 suffix_info (".bat"), suffix_info (".dll"),
45 suffix_info (NULL)
46};
47
4c45a897 48HANDLE hExeced;
c0a8e8d0 49DWORD dwExeced;
4c45a897 50
1fd5e000
CF
51/* Add .exe to PROG if not already present and see if that exists.
52 If not, return PROG (converted from posix to win32 rules if necessary).
53 The result is always BUF.
54
55 Returns (possibly NULL) suffix */
56
57static const char *
c0a8e8d0 58perhaps_suffix (const char *prog, path_conv& buf)
1fd5e000
CF
59{
60 char *ext;
61
62 debug_printf ("prog '%s'", prog);
5bc584ba 63 buf.check (prog, PC_SYM_FOLLOW | PC_FULL, std_suffixes);
1fd5e000 64
af39152f 65 if (!buf.exists () || buf.isdir ())
1fd5e000 66 ext = NULL;
55fc91b9 67 else if (buf.known_suffix)
47063f00 68 ext = (char *) buf + (buf.known_suffix - buf.get_win32 ());
1fd5e000
CF
69 else
70 ext = strchr (buf, '\0');
71
55fc91b9 72 debug_printf ("buf %s, suffix found '%s'", (char *) buf, ext);
1fd5e000
CF
73 return ext;
74}
75
76/* Find an executable name, possibly by appending known executable
77 suffixes to it. The win32-translated name is placed in 'buf'.
78 Any found suffix is returned in known_suffix.
79
80 If the file is not found and !null_if_not_found then the win32 version
81 of name is placed in buf and returned. Otherwise the contents of buf
82 is undefined and NULL is returned. */
83
84const char * __stdcall
55fc91b9 85find_exec (const char *name, path_conv& buf, const char *mywinenv,
6ea0c04e 86 unsigned opt, const char **known_suffix)
1fd5e000
CF
87{
88 const char *suffix = "";
89 debug_printf ("find_exec (%s)", name);
45d2ea8a 90 const char *retval = buf;
6ea0c04e
CF
91 char tmp[MAX_PATH];
92 const char *posix = (opt & FE_NATIVE) ? NULL : name;
93 bool has_slash = strchr (name, '/');
1fd5e000
CF
94
95 /* Check to see if file can be opened as is first.
96 Win32 systems always check . first, but PATH may not be set up to
97 do this. */
6ea0c04e
CF
98 if ((has_slash || opt & FE_CWD)
99 && (suffix = perhaps_suffix (name, buf)) != NULL)
100 {
101 if (posix && !has_slash)
102 {
103 tmp[0] = '.';
104 tmp[1] = '/';
105 strcpy (tmp + 2, name);
106 posix = tmp;
107 }
108 goto out;
109 }
1fd5e000
CF
110
111 win_env *winpath;
112 const char *path;
6ea0c04e 113 const char *posix_path;
1fd5e000
CF
114
115 /* Return the error condition if this is an absolute path or if there
116 is no PATH to search. */
117 if (strchr (name, '/') || strchr (name, '\\') ||
75858e8a 118 isdrive (name) ||
1fd5e000
CF
119 !(winpath = getwinenv (mywinenv)) ||
120 !(path = winpath->get_native ()) ||
121 *path == '\0')
122 goto errout;
123
124 debug_printf ("%s%s", mywinenv, path);
125
6ea0c04e
CF
126 posix = (opt & FE_NATIVE) ? NULL : tmp;
127 posix_path = winpath->get_posix () - 1;
1fd5e000
CF
128 /* Iterate over the specified path, looking for the file with and
129 without executable extensions. */
130 do
131 {
6ea0c04e 132 posix_path++;
1fd5e000
CF
133 char *eotmp = strccpy (tmp, &path, ';');
134 /* An empty path or '.' means the current directory, but we've
135 already tried that. */
6ea0c04e 136 if (opt & FE_CWD && (tmp[0] == '\0' || (tmp[0] == '.' && tmp[1] == '\0')))
1fd5e000
CF
137 continue;
138
139 *eotmp++ = '\\';
140 strcpy (eotmp, name);
141
142 debug_printf ("trying %s", tmp);
143
144 if ((suffix = perhaps_suffix (tmp, buf)) != NULL)
6ea0c04e
CF
145 {
146 if (posix == tmp)
147 {
148 eotmp = strccpy (tmp, &posix_path, ':');
149 if (eotmp == tmp)
150 *eotmp++ = '.';
151 *eotmp++ = '/';
152 strcpy (eotmp, name);
153 }
154 goto out;
155 }
1fd5e000 156 }
6ea0c04e 157 while (*path && *++path && (posix_path = strchr (posix_path, ':')));
1fd5e000 158
0a047e8f 159 errout:
6ea0c04e 160 posix = NULL;
1fd5e000
CF
161 /* Couldn't find anything in the given path.
162 Take the appropriate action based on null_if_not_found. */
6ea0c04e 163 if (opt & FE_NNF)
1fd5e000 164 retval = NULL;
6ea0c04e 165 else if (opt & FE_NATIVE)
55fc91b9 166 buf.check (name);
45d2ea8a
CF
167 else
168 retval = name;
1fd5e000 169
0a047e8f 170 out:
6ea0c04e
CF
171 if (posix)
172 buf.set_path (posix);
55fc91b9 173 debug_printf ("%s = find_exec (%s)", (char *) buf, name);
1fd5e000
CF
174 if (known_suffix)
175 *known_suffix = suffix ?: strchr (buf, '\0');
176 return retval;
177}
178
179/* Utility for spawn_guts. */
180
181static HANDLE
182handle (int n, int direction)
183{
0381fec6 184 fhandler_base *fh = cygheap->fdtab[n];
1fd5e000
CF
185
186 if (!fh)
187 return INVALID_HANDLE_VALUE;
188 if (fh->get_close_on_exec ())
189 return INVALID_HANDLE_VALUE;
190 if (direction == 0)
191 return fh->get_handle ();
192 return fh->get_output_handle ();
193}
194
1fd5e000
CF
195int
196iscmd (const char *argv0, const char *what)
197{
198 int n;
199 n = strlen (argv0) - strlen (what);
200 if (n >= 2 && argv0[1] != ':')
201 return 0;
ebbd4e8f 202 return n >= 0 && strcasematch (argv0 + n, what) &&
1fd5e000
CF
203 (n == 0 || isdirsep (argv0[n - 1]));
204}
205
206class linebuf
207{
0a047e8f 208 public:
1fd5e000
CF
209 size_t ix;
210 char *buf;
211 size_t alloced;
a333dca2 212 linebuf () : ix (0), buf (NULL), alloced (0) {}
7a44ba05 213 ~linebuf () {if (buf) free (buf);}
1fd5e000
CF
214 void add (const char *what, int len);
215 void add (const char *what) {add (what, strlen (what));}
216 void prepend (const char *what, int len);
217};
218
219void
220linebuf::add (const char *what, int len)
221{
222 size_t newix;
223 if ((newix = ix + len) >= alloced || !buf)
224 {
225 alloced += LINE_BUF_CHUNK + newix;
226 buf = (char *) realloc (buf, alloced + 1);
227 }
228 memcpy (buf + ix, what, len);
229 ix = newix;
230 buf[ix] = '\0';
231}
232
233void
234linebuf::prepend (const char *what, int len)
235{
236 int buflen;
237 size_t newix;
238 if ((newix = ix + len) >= alloced)
239 {
240 alloced += LINE_BUF_CHUNK + newix;
241 buf = (char *) realloc (buf, alloced + 1);
242 buf[ix] = '\0';
243 }
244 if ((buflen = strlen (buf)))
245 memmove (buf + len, buf, buflen + 1);
246 else
247 buf[newix] = '\0';
248 memcpy (buf, what, len);
249 ix = newix;
250}
251
99d7d12a 252class av
b0e82b74 253{
b0e82b74 254 char **argv;
99d7d12a 255 int calloced;
0a047e8f 256 public:
7da53596 257 int error;
99d7d12a 258 int argc;
7da53596 259 av (int ac, const char * const *av) : calloced (0), error (false), argc (ac)
b0e82b74 260 {
aece55b9 261 argv = (char **) cmalloc (HEAP_1_ARGV, (argc + 5) * sizeof (char *));
b0e82b74
CF
262 memcpy (argv, av, (argc + 1) * sizeof (char *));
263 }
264 ~av ()
265 {
7da53596
CF
266 if (argv)
267 {
268 for (int i = 0; i < calloced; i++)
269 if (argv[i])
270 cfree (argv[i]);
271 cfree (argv);
272 }
b0e82b74
CF
273 }
274 int unshift (const char *what, int conv = 0);
275 operator char **() {return argv;}
99d7d12a
CF
276 void all_calloced () {calloced = argc;}
277 void replace0_maybe (const char *arg0)
278 {
279 /* Note: Assumes that argv array has not yet been "unshifted" */
7da53596
CF
280 if (!calloced
281 && (argv[0] = cstrdup1 (arg0)))
282 calloced = true;
283 else
284 error = errno;
99d7d12a 285 }
fb5956da 286 void dup_maybe (int i)
99d7d12a 287 {
7da53596
CF
288 if (i >= calloced
289 && !(argv[i] = cstrdup1 (argv[i])))
290 error = errno;
99d7d12a
CF
291 }
292 void dup_all ()
293 {
294 for (int i = calloced; i < argc; i++)
7da53596
CF
295 if (!(argv[i] = cstrdup1 (argv[i])))
296 error = errno;
99d7d12a 297 }
b0e82b74
CF
298};
299
300int
301av::unshift (const char *what, int conv)
302{
303 char **av;
304 av = (char **) crealloc (argv, (argc + 2) * sizeof (char *));
305 if (!av)
306 return 0;
307
308 argv = av;
309 memmove (argv + 1, argv, (argc + 1) * sizeof (char *));
310 char buf[MAX_PATH + 1];
311 if (conv)
312 {
313 cygwin_conv_to_posix_path (what, buf);
314 char *p = strchr (buf, '\0') - 4;
315 if (p > buf && strcasematch (p, ".exe"))
316 *p = '\0';
317 what = buf;
318 }
7da53596
CF
319 if (!(*argv = cstrdup1 (what)))
320 error = errno;
b0e82b74
CF
321 argc++;
322 calloced++;
323 return 1;
324}
325
0199487e
CF
326struct pthread_cleanup
327{
328 _sig_func_ptr oldint;
329 _sig_func_ptr oldquit;
330 sigset_t oldmask;
331 pthread_cleanup (): oldint (NULL), oldquit (NULL), oldmask (0) {}
332};
333
334static void
335do_cleanup (void *args)
336{
337# define cleanup ((pthread_cleanup *) args)
338 if (cleanup->oldint)
339 signal (SIGINT, cleanup->oldint);
340 if (cleanup->oldquit)
341 signal (SIGQUIT, cleanup->oldquit);
342 if (cleanup->oldmask)
343 sigprocmask (SIG_SETMASK, &(cleanup->oldmask), NULL);
344# undef cleanup
345}
346
347
84c7d409 348static int __stdcall
380aaf2d 349spawn_guts (const char * prog_arg, const char *const *argv,
84c7d409 350 const char *const envp[], int mode)
1fd5e000 351{
1fd5e000 352 BOOL rc;
84c7d409 353 pid_t cygpid;
e46db834 354 sigframe thisframe (mainthread);
1fd5e000 355
1fd5e000
CF
356 MALLOC_CHECK;
357
358 if (prog_arg == NULL)
359 {
360 syscall_printf ("prog_arg is NULL");
51cb7ca7 361 set_errno (EINVAL);
1fd5e000
CF
362 return -1;
363 }
364
d8ee8ca5 365 syscall_printf ("spawn_guts (%d, %.9500s)", mode, prog_arg);
1fd5e000
CF
366
367 if (argv == NULL)
368 {
369 syscall_printf ("argv is NULL");
51cb7ca7 370 set_errno (EINVAL);
7da53596 371 return -1;
1fd5e000
CF
372 }
373
b0e82b74
CF
374 path_conv real_path;
375
376 linebuf one_line;
377
378 STARTUPINFO si = {0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL};
379
380 child_info_spawn ciresrv;
381 si.lpReserved2 = (LPBYTE) &ciresrv;
382 si.cbReserved2 = sizeof (ciresrv);
383
b0e82b74 384 DWORD chtype;
8af0f81d 385 if (mode != _P_OVERLAY)
b0e82b74
CF
386 chtype = PROC_SPAWN;
387 else
aece55b9
CF
388 chtype = PROC_EXEC;
389
0301bfd0 390 HANDLE subproc_ready;
8af0f81d 391 if (chtype != PROC_EXEC)
0301bfd0 392 subproc_ready = NULL;
5457dfcb
CF
393 else
394 {
0301bfd0
CF
395 subproc_ready = CreateEvent (&sec_all, TRUE, FALSE, NULL);
396 ProtectHandleINH (subproc_ready);
5457dfcb 397 }
b0e82b74 398
8af0f81d 399 init_child_info (chtype, &ciresrv, (mode == _P_OVERLAY) ? myself->pid : 1,
0301bfd0 400 subproc_ready);
b0e82b74
CF
401 if (!DuplicateHandle (hMainProc, hMainProc, hMainProc, &ciresrv.parent, 0, 1,
402 DUPLICATE_SAME_ACCESS))
403 {
404 system_printf ("couldn't create handle to myself for child, %E");
405 return -1;
406 }
407
e5648465 408 ciresrv.moreinfo = (cygheap_exec_info *) ccalloc (HEAP_1_EXEC, 1, sizeof (cygheap_exec_info));
1dc16fc7 409 ciresrv.moreinfo->old_title = NULL;
b0e82b74 410
1fd5e000
CF
411 /* CreateProcess takes one long string that is the command line (sigh).
412 We need to quote any argument that has whitespace or embedded "'s. */
413
b0e82b74
CF
414 int ac;
415 for (ac = 0; argv[ac]; ac++)
1fd5e000
CF
416 /* nothing */;
417
b0e82b74 418 av newargv (ac, argv);
1fd5e000 419
a333dca2 420 int null_app_name = 0;
b0e82b74 421 if (ac == 3 && argv[1][0] == '/' && argv[1][1] == 'c' &&
1fd5e000
CF
422 (iscmd (argv[0], "command.com") || iscmd (argv[0], "cmd.exe")))
423 {
a333dca2 424 real_path.check (prog_arg);
b0de2aa2 425 one_line.add ("\"");
a333dca2
CF
426 if (!real_path.error)
427 one_line.add (real_path);
428 else
429 one_line.add (argv[0]);
b0de2aa2 430 one_line.add ("\"");
1fd5e000
CF
431 one_line.add (" ");
432 one_line.add (argv[1]);
433 one_line.add (" ");
1fd5e000 434 one_line.add (argv[2]);
b0e82b74 435 strcpy (real_path, argv[0]);
a333dca2 436 null_app_name = 1;
1fd5e000
CF
437 goto skip_arg_parsing;
438 }
439
1fd5e000 440 const char *ext;
b0e82b74 441 if ((ext = perhaps_suffix (prog_arg, real_path)) == NULL)
1fd5e000
CF
442 {
443 set_errno (ENOENT);
444 return -1;
445 }
446
447 MALLOC_CHECK;
1fd5e000
CF
448
449 /* If the file name ends in either .exe, .com, .bat, or .cmd we assume
450 that it is NOT a script file */
451 while (*ext == '\0')
452 {
580e99a1
CF
453 HANDLE hnd = CreateFile (real_path, GENERIC_READ,
454 FILE_SHARE_READ | FILE_SHARE_WRITE,
455 &sec_none_nih, OPEN_EXISTING,
456 FILE_ATTRIBUTE_NORMAL, 0);
1fd5e000
CF
457 if (hnd == INVALID_HANDLE_VALUE)
458 {
459 __seterrno ();
460 return -1;
461 }
462
463 DWORD done;
464
465 char buf[2 * MAX_PATH + 1];
51cb7ca7 466 buf[0] = buf[1] = buf[2] = buf[sizeof (buf) - 1] = '\0';
90fe7739 467 if (!ReadFile (hnd, buf, sizeof (buf) - 1, &done, 0))
1fd5e000
CF
468 {
469 CloseHandle (hnd);
470 __seterrno ();
471 return -1;
472 }
473
474 CloseHandle (hnd);
475
476 if (buf[0] == 'M' && buf[1] == 'Z')
477 break;
478
99d7d12a 479 debug_printf ("%s is a script", (char *) real_path);
1fd5e000 480
99d7d12a 481 char *pgm, *arg1;
1fd5e000
CF
482
483 if (buf[0] != '#' || buf[1] != '!')
484 {
b0e82b74 485 pgm = (char *) "/bin/sh";
1fd5e000
CF
486 arg1 = NULL;
487 }
488 else
489 {
99d7d12a 490 char *ptr;
1fd5e000
CF
491 pgm = buf + 2;
492 pgm += strspn (pgm, " \t");
493 for (ptr = pgm, arg1 = NULL;
494 *ptr && *ptr != '\r' && *ptr != '\n';
495 ptr++)
496 if (!arg1 && (*ptr == ' ' || *ptr == '\t'))
497 {
498 /* Null terminate the initial command and step over
499 any additional white space. If we've hit the
90fe7739
CF
500 end of the line, exit the loop. Otherwise, we've
501 found the first argument. Position the current
1fd5e000
CF
502 pointer on the last known white space. */
503 *ptr = '\0';
504 char *newptr = ptr + 1;
505 newptr += strspn (newptr, " \t");
506 if (!*newptr || *newptr == '\r' || *newptr == '\n')
507 break;
508 arg1 = newptr;
509 ptr = newptr - 1;
510 }
511
1fd5e000
CF
512 *ptr = '\0';
513 }
514
99d7d12a
CF
515 /* Replace argv[0] with the full path to the script if this is the
516 first time through the loop. */
b9631756 517 newargv.replace0_maybe (prog_arg);
75a57bf0 518
1fd5e000
CF
519 /* pointers:
520 * pgm interpreter name
521 * arg1 optional string
1fd5e000 522 */
b0e82b74
CF
523 if (arg1)
524 newargv.unshift (arg1);
1fd5e000 525
6ea0c04e 526 /* FIXME: This should not be using FE_NATIVE. It should be putting
9c510edc 527 the posix path on the argv list. */
6ea0c04e 528 find_exec (pgm, real_path, "PATH=", FE_NATIVE, &ext);
b0e82b74 529 newargv.unshift (real_path, 1);
1fd5e000
CF
530 }
531
b0e82b74 532 if (real_path.iscygexec ())
99d7d12a 533 newargv.dup_all ();
b0e82b74 534 else
1fd5e000 535 {
b0e82b74 536 for (int i = 0; i < newargv.argc; i++)
1fd5e000 537 {
b0e82b74
CF
538 char *p = NULL;
539 const char *a;
540
99d7d12a 541 newargv.dup_maybe (i);
4eafa56e 542 a = i ? newargv[i] : (char *) real_path;
b0e82b74
CF
543 int len = strlen (a);
544 if (len != 0 && !strpbrk (a, " \t\n\r\""))
545 one_line.add (a, len);
546 else
1fd5e000 547 {
b0e82b74 548 one_line.add ("\"", 1);
9784d54d
CF
549 /* Handle embedded special characters " and \.
550 A " is always preceded by a \.
551 A \ is not special unless it precedes a ". If it does,
552 then all preceding \'s must be doubled to avoid having
553 the Windows command line parser interpret the \ as quoting
554 the ". This rule applies to a string of \'s before the end
555 of the string, since cygwin/windows uses a " to delimit the
556 argument. */
b0e82b74
CF
557 for (; (p = strpbrk (a, "\"\\")); a = ++p)
558 {
559 one_line.add (a, p - a);
9784d54d
CF
560 /* Find length of string of backslashes */
561 int n = strspn (p, "\\");
562 if (!n)
563 one_line.add ("\\\"", 2); /* No backslashes, so it must be a ".
564 The " has to be protected with a backslash. */
565 else
099efae0 566 {
9784d54d
CF
567 one_line.add (p, n); /* Add the run of backslashes */
568 /* Need to double up all of the preceding
569 backslashes if they precede a quote or EOS. */
570 if (!p[n] || p[n] == '"')
571 one_line.add (p, n);
572 p += n - 1; /* Point to last backslash */
099efae0 573 }
b0e82b74
CF
574 }
575 if (*a)
576 one_line.add (a);
577 one_line.add ("\"", 1);
1fd5e000 578 }
b0e82b74
CF
579 MALLOC_CHECK;
580 one_line.add (" ", 1);
581 MALLOC_CHECK;
1fd5e000 582 }
b0e82b74 583
1fd5e000 584 MALLOC_CHECK;
b0e82b74
CF
585 if (one_line.ix)
586 one_line.buf[one_line.ix - 1] = '\0';
587 else
588 one_line.add ("", 1);
1fd5e000
CF
589 MALLOC_CHECK;
590 }
99d7d12a 591
da086d02 592 char *envblock;
99d7d12a 593 newargv.all_calloced ();
7da53596
CF
594 if (newargv.error)
595 {
596 set_errno (newargv.error);
597 return -1;
598 }
599
b0e82b74
CF
600 ciresrv.moreinfo->argc = newargv.argc;
601 ciresrv.moreinfo->argv = newargv;
166b2571 602 ciresrv.hexec_proc = hexec_proc;
da086d02 603
b0e82b74 604 if (mode != _P_OVERLAY ||
16828fc5
CF
605 !DuplicateHandle (hMainProc, myself.shared_handle (), hMainProc,
606 &ciresrv.moreinfo->myself_pinfo, 0,
b0e82b74
CF
607 TRUE, DUPLICATE_SAME_ACCESS))
608 ciresrv.moreinfo->myself_pinfo = NULL;
1fd5e000 609
0a047e8f 610 skip_arg_parsing:
01cf5d0f 611 PROCESS_INFORMATION pi = {NULL, 0, 0, 0};
1fd5e000
CF
612 si.lpReserved = NULL;
613 si.lpDesktop = NULL;
614 si.dwFlags = STARTF_USESTDHANDLES;
615 si.hStdInput = handle (0, 0); /* Get input handle */
616 si.hStdOutput = handle (1, 1); /* Get output handle */
617 si.hStdError = handle (2, 1); /* Get output handle */
618 si.cb = sizeof (si);
619
166b2571 620 int flags = CREATE_DEFAULT_ERROR_MODE | GetPriorityClass (hMainProc);
1fd5e000
CF
621
622 if (mode == _P_DETACH || !set_console_state_for_spawn ())
623 flags |= DETACHED_PROCESS;
166b2571
CF
624 if (mode != _P_OVERLAY)
625 flags |= CREATE_SUSPENDED;
1fd5e000 626
dd4f0b23
CV
627 /* Some file types (currently only sockets) need extra effort in the
628 parent after CreateProcess and before copying the datastructures
629 to the child. So we have to start the child in suspend state,
630 unfortunately, to avoid a race condition. */
0381fec6 631 if (cygheap->fdtab.need_fixup_before ())
dd4f0b23
CV
632 flags |= CREATE_SUSPENDED;
633
634
a333dca2
CF
635 const char *runpath = null_app_name ? NULL : (const char *) real_path;
636
d8ee8ca5 637 syscall_printf ("null_app_name %d (%s, %.9500s)", null_app_name, runpath, one_line.buf);
a333dca2 638
e2e07827 639 void *newheap;
380aaf2d
CF
640 /* Preallocated buffer for `sec_user' call */
641 char sa_buf[1024];
642
a333dca2 643 cygbench ("spawn-guts");
9a771b29 644
fef1edbc 645 cygheap->fdtab.set_file_pointers_for_exec ();
70249d56 646 cygheap->user.deimpersonate ();
271c1935
CV
647 /* When ruid != euid we create the new process under the current original
648 account and impersonate in child, this way maintaining the different
649 effective vs. real ids.
1498189c 650 FIXME: If ruid != euid and ruid != saved_uid we currently give
271c1935
CV
651 up on ruid. The new process will have ruid == euid. */
652 if (!cygheap->user.issetuid ()
1498189c
CV
653 || (cygheap->user.saved_uid == cygheap->user.real_uid
654 && cygheap->user.saved_gid == cygheap->user.real_gid
271c1935 655 && !cygheap->user.groups.issetgroups ()))
166b2571 656 {
d5377829 657 PSECURITY_ATTRIBUTES sec_attribs = sec_user_nih (sa_buf);
9a771b29
CF
658 ciresrv.moreinfo->envp = build_env (envp, envblock, ciresrv.moreinfo->envc,
659 real_path.iscygexec ());
6d171b44 660 newheap = cygheap_setup_for_child (&ciresrv, cygheap->fdtab.need_fixup_before ());
a333dca2 661 rc = CreateProcess (runpath, /* image name - with full path */
166b2571 662 one_line.buf, /* what was passed to exec */
d5377829
CF
663 sec_attribs, /* process security attrs */
664 sec_attribs, /* thread security attrs */
665 TRUE, /* inherit handles from parent */
166b2571 666 flags,
d5377829
CF
667 envblock, /* environment */
668 0, /* use current drive/directory */
166b2571
CF
669 &si,
670 &pi);
671 }
672 else
1fd5e000 673 {
9a771b29
CF
674 PSID sid = cygheap->user.sid ();
675
676 /* Set security attributes with sid */
cecb74ae 677 PSECURITY_ATTRIBUTES sec_attribs = sec_user_nih (sa_buf, sid);
57ff940d 678
1fd5e000
CF
679 /* allow the child to interact with our window station/desktop */
680 HANDLE hwst, hdsk;
681 SECURITY_INFORMATION dsi = DACL_SECURITY_INFORMATION;
682 DWORD n;
683 char wstname[1024];
684 char dskname[1024];
685
51cb7ca7
CF
686 hwst = GetProcessWindowStation ();
687 SetUserObjectSecurity (hwst, &dsi, get_null_sd ());
688 GetUserObjectInformation (hwst, UOI_NAME, wstname, 1024, &n);
689 hdsk = GetThreadDesktop (GetCurrentThreadId ());
690 SetUserObjectSecurity (hdsk, &dsi, get_null_sd ());
691 GetUserObjectInformation (hdsk, UOI_NAME, dskname, 1024, &n);
1fd5e000
CF
692 strcat (wstname, "\\");
693 strcat (wstname, dskname);
694 si.lpDesktop = wstname;
1fd5e000 695
9a771b29
CF
696 ciresrv.moreinfo->envp = build_env (envp, envblock, ciresrv.moreinfo->envc,
697 real_path.iscygexec ());
6d171b44 698 newheap = cygheap_setup_for_child (&ciresrv, cygheap->fdtab.need_fixup_before ());
70249d56 699 rc = CreateProcessAsUser (cygheap->user.token (),
a333dca2 700 runpath, /* image name - with full path */
1fd5e000 701 one_line.buf, /* what was passed to exec */
b0e82b74
CF
702 sec_attribs, /* process security attrs */
703 sec_attribs, /* thread security attrs */
d5377829 704 TRUE, /* inherit handles from parent */
1fd5e000 705 flags,
d5377829
CF
706 envblock, /* environment */
707 0, /* use current drive/directory */
1fd5e000
CF
708 &si,
709 &pi);
710 }
d1fb625d
CF
711
712 /* FIXME: There is a small race here */
713
0199487e
CF
714 DWORD res;
715 pthread_cleanup cleanup;
716 pthread_cleanup_push (do_cleanup, (void *) &cleanup);
d1fb625d
CF
717 if (mode == _P_SYSTEM)
718 {
719 sigset_t child_block;
0199487e
CF
720 cleanup.oldint = signal (SIGINT, SIG_IGN);
721 cleanup.oldquit = signal (SIGQUIT, SIG_IGN);
d1fb625d
CF
722 sigemptyset (&child_block);
723 sigaddset (&child_block, SIGCHLD);
0199487e 724 (void) sigprocmask (SIG_BLOCK, &child_block, &cleanup.oldmask);
d1fb625d
CF
725 }
726
271c1935
CV
727 /* Restore impersonation. In case of _P_OVERLAY this isn't
728 allowed since it would overwrite child data. */
70249d56
CV
729 if (mode != _P_OVERLAY)
730 cygheap->user.reimpersonate ();
1fd5e000
CF
731
732 MALLOC_CHECK;
b0e82b74
CF
733 if (envblock)
734 free (envblock);
1fd5e000
CF
735 MALLOC_CHECK;
736
737 /* Set errno now so that debugging messages from it appear before our
738 final debugging message [this is a general rule for debugging
739 messages]. */
47026c07
CF
740 if (!rc)
741 {
47026c07
CF
742 __seterrno ();
743 syscall_printf ("CreateProcess failed, %E");
0301bfd0
CF
744 if (subproc_ready)
745 ForceCloseHandle (subproc_ready);
e2e07827 746 cygheap_setup_for_child_cleanup (newheap, &ciresrv, 0);
47026c07
CF
747 return -1;
748 }
1fd5e000 749
dd4f0b23
CV
750 /* Fixup the parent datastructure if needed and resume the child's
751 main thread. */
e2e07827
CF
752 if (!cygheap->fdtab.need_fixup_before ())
753 cygheap_setup_for_child_cleanup (newheap, &ciresrv, 0);
754 else
dd4f0b23 755 {
0381fec6 756 cygheap->fdtab.fixup_before_exec (pi.dwProcessId);
e2e07827 757 cygheap_setup_for_child_cleanup (newheap, &ciresrv, 1);
dd4f0b23 758 if (mode == _P_OVERLAY)
969203ce
CF
759 {
760 ResumeThread (pi.hThread);
761 cygthread::terminate ();
762 }
dd4f0b23
CV
763 }
764
3f5046a5 765 if (mode != _P_OVERLAY)
84c7d409 766 cygpid = cygwin_pid (pi.dwProcessId);
3f5046a5
CF
767 else
768 cygpid = myself->pid;
1fd5e000
CF
769
770 /* We print the original program name here so the user can see that too. */
d8ee8ca5 771 syscall_printf ("%d = spawn_guts (%s, %.9500s)",
164a681c 772 rc ? cygpid : (unsigned int) -1, prog_arg, one_line.buf);
1fd5e000 773
84c7d409
CF
774 /* Name the handle similarly to proc_subproc. */
775 ProtectHandle1 (pi.hProcess, childhProc);
1fd5e000
CF
776
777 if (mode == _P_OVERLAY)
778 {
166b2571
CF
779 /* These are both duplicated in the child code. We do this here,
780 primarily for strace. */
4c45a897
CF
781 strace.execing = 1;
782 hExeced = pi.hProcess;
c0a8e8d0 783 dwExeced = pi.dwProcessId;
12520587 784 strcpy (myself->progname, real_path);
e5ba4c06 785 close_all_files ();
1fd5e000
CF
786 }
787 else
788 {
f8f9b12e 789 myself->set_has_pgid_children ();
166b2571 790 ProtectHandle (pi.hThread);
84c7d409
CF
791 pinfo child (cygpid, 1);
792 if (!child)
793 {
794 set_errno (EAGAIN);
795 syscall_printf ("-1 = spawnve (), process table full");
796 return -1;
797 }
1fd5e000
CF
798 child->dwProcessId = pi.dwProcessId;
799 child->hProcess = pi.hProcess;
84c7d409 800 child.remember ();
12520587 801 strcpy (child->progname, real_path);
8af0f81d 802 /* FIXME: This introduces an unreferenced, open handle into the child.
9c510edc 803 The purpose is to keep the pid shared memory open so that all of
8af0f81d
CF
804 the fields filled out by child.remember do not disappear and so there
805 is not a brief period during which the pid is not available.
806 However, we should try to find another way to do this eventually. */
807 (void) DuplicateHandle (hMainProc, child.shared_handle (), pi.hProcess,
808 NULL, 0, 0, DUPLICATE_SAME_ACCESS);
166b2571
CF
809 /* Start the child running */
810 ResumeThread (pi.hThread);
1fd5e000
CF
811 }
812
1fd5e000
CF
813 ForceCloseHandle (pi.hThread);
814
166b2571
CF
815 sigproc_printf ("spawned windows pid %d", pi.dwProcessId);
816
aece55b9 817 BOOL exited;
1fd5e000 818
aece55b9
CF
819 res = 0;
820 exited = FALSE;
821 MALLOC_CHECK;
5457dfcb 822 if (mode == _P_OVERLAY)
aece55b9 823 {
5457dfcb 824 int nwait = 3;
0301bfd0 825 HANDLE waitbuf[3] = {pi.hProcess, signal_arrived, subproc_ready};
5457dfcb 826 for (int i = 0; i < 100; i++)
1fd5e000 827 {
5457dfcb 828 switch (WaitForMultipleObjects (nwait, waitbuf, FALSE, INFINITE))
1fd5e000 829 {
5457dfcb
CF
830 case WAIT_OBJECT_0:
831 sigproc_printf ("subprocess exited");
832 DWORD exitcode;
833 if (!GetExitCodeProcess (pi.hProcess, &exitcode))
834 exitcode = 1;
835 res |= exitcode;
836 exited = TRUE;
837 break;
838 case WAIT_OBJECT_0 + 1:
839 sigproc_printf ("signal arrived");
840 reset_signal_arrived ();
841 continue;
842 case WAIT_OBJECT_0 + 2:
0c8fe172 843 if (my_parent_is_alive ())
941fa5ad 844 res |= EXIT_REPARENTING;
0c8fe172 845 else if (!myself->ppid_handle)
332600d8 846 {
5457dfcb 847 nwait = 2;
aece55b9
CF
848 sigproc_terminate ();
849 continue;
332600d8 850 }
5457dfcb
CF
851 break;
852 case WAIT_FAILED:
853 system_printf ("wait failed: nwait %d, pid %d, winpid %d, %E",
854 nwait, myself->pid, myself->dwProcessId);
855 system_printf ("waitbuf[0] %p %d", waitbuf[0],
856 WaitForSingleObject (waitbuf[0], 0));
857 system_printf ("waitbuf[1] %p = %d", waitbuf[1],
858 WaitForSingleObject (waitbuf[1], 0));
859 system_printf ("waitbuf[w] %p = %d", waitbuf[2],
860 WaitForSingleObject (waitbuf[2], 0));
861 set_errno (ECHILD);
862 try_to_debug ();
863 return -1;
1fd5e000 864 }
1fd5e000 865 break;
1fd5e000
CF
866 }
867
0301bfd0 868 ForceCloseHandle (subproc_ready);
1fd5e000 869
5457dfcb 870 sigproc_printf ("res = %x", res);
1fd5e000 871
5457dfcb 872 if (res & EXIT_REPARENTING)
1fd5e000 873 {
5457dfcb
CF
874 /* Try to reparent child process.
875 * Make handles to child available to parent process and exit with
876 * EXIT_REPARENTING status. Wait() syscall in parent will then wait
877 * for newly created child.
878 */
879 HANDLE oldh = myself->hProcess;
880 HANDLE h = myself->ppid_handle;
881 sigproc_printf ("parent handle %p", h);
882 int rc = DuplicateHandle (hMainProc, pi.hProcess, h, &myself->hProcess,
883 0, FALSE, DUPLICATE_SAME_ACCESS);
884 sigproc_printf ("%d = DuplicateHandle, oldh %p, newh %p",
885 rc, oldh, myself->hProcess);
886 if (!rc && my_parent_is_alive ())
887 {
888 system_printf ("Reparent failed, parent handle %p, %E", h);
889 system_printf ("my dwProcessId %d, myself->dwProcessId %d",
890 GetCurrentProcessId (), myself->dwProcessId);
891 system_printf ("old hProcess %p, hProcess %p", oldh, myself->hProcess);
892 }
1fd5e000 893 }
aece55b9 894
5457dfcb 895 }
07c3cd5b 896
aece55b9 897 MALLOC_CHECK;
1fd5e000 898
b0e82b74
CF
899 switch (mode)
900 {
aece55b9 901 case _P_OVERLAY:
166b2571 902 ForceCloseHandle1 (pi.hProcess, childhProc);
aece55b9 903 proc_terminate ();
eca7c729 904 myself->exit (res, 1);
aece55b9 905 break;
b0e82b74 906 case _P_WAIT:
d1fb625d 907 case _P_SYSTEM:
b0e82b74
CF
908 waitpid (cygpid, (int *) &res, 0);
909 break;
910 case _P_DETACH:
911 res = 0; /* Lose all memory of this child. */
912 break;
913 case _P_NOWAIT:
914 case _P_NOWAITO:
915 case _P_VFORK:
916 res = cygpid;
917 break;
918 default:
919 break;
920 }
1fd5e000 921
0199487e 922 pthread_cleanup_pop (1);
1fd5e000
CF
923 return (int) res;
924}
925
0a047e8f 926extern "C" int
1fd5e000
CF
927cwait (int *result, int pid, int)
928{
929 return waitpid (pid, result, 0);
930}
931
932/*
933 * Helper function for spawn runtime calls.
934 * Doesn't search the path.
935 */
936
937extern "C" int
380aaf2d
CF
938spawnve (int mode, const char *path, const char *const *argv,
939 const char *const *envp)
1fd5e000 940{
1fd5e000
CF
941 int ret;
942 vfork_save *vf = vfork_storage.val ();
943
944 if (vf != NULL && (vf->pid < 0) && mode == _P_OVERLAY)
945 mode = _P_NOWAIT;
946 else
947 vf = NULL;
948
380aaf2d 949 syscall_printf ("spawnve (%s, %s, %x)", path, argv[0], envp);
1fd5e000
CF
950
951 switch (mode)
952 {
b0e82b74
CF
953 case _P_OVERLAY:
954 /* We do not pass _P_SEARCH_PATH here. execve doesn't search PATH.*/
955 /* Just act as an exec if _P_OVERLAY set. */
380aaf2d 956 spawn_guts (path, argv, envp, mode);
b0e82b74
CF
957 /* Errno should be set by spawn_guts. */
958 ret = -1;
959 break;
960 case _P_VFORK:
961 case _P_NOWAIT:
962 case _P_NOWAITO:
963 case _P_WAIT:
964 case _P_DETACH:
d1fb625d 965 case _P_SYSTEM:
b0e82b74 966 subproc_init ();
380aaf2d 967 ret = spawn_guts (path, argv, envp, mode);
8dca9e23 968 if (vf)
b0e82b74 969 {
12520587 970 debug_printf ("longjmping due to vfork");
8dca9e23
CF
971 if (ret < 0)
972 vf->restore_exit (ret);
973 else
974 vf->restore_pid (ret);
b0e82b74
CF
975 }
976 break;
977 default:
978 set_errno (EINVAL);
979 ret = -1;
980 break;
1fd5e000
CF
981 }
982 return ret;
983}
984
985/*
986 * spawn functions as implemented in the MS runtime library.
987 * Most of these based on (and copied from) newlib/libc/posix/execXX.c
988 */
989
0a047e8f 990extern "C" int
1fd5e000
CF
991spawnl (int mode, const char *path, const char *arg0, ...)
992{
993 int i;
994 va_list args;
995 const char *argv[256];
996
997 va_start (args, arg0);
998 argv[0] = arg0;
999 i = 1;
1000
1001 do
1002 argv[i] = va_arg (args, const char *);
1003 while (argv[i++] != NULL);
1004
1005 va_end (args);
1006
380aaf2d 1007 return spawnve (mode, path, (char * const *) argv, cur_environ ());
1fd5e000
CF
1008}
1009
0a047e8f 1010extern "C" int
1fd5e000
CF
1011spawnle (int mode, const char *path, const char *arg0, ...)
1012{
1013 int i;
1014 va_list args;
1015 const char * const *envp;
1016 const char *argv[256];
1017
1018 va_start (args, arg0);
1019 argv[0] = arg0;
1020 i = 1;
1021
1022 do
1023 argv[i] = va_arg (args, const char *);
1024 while (argv[i++] != NULL);
1025
1026 envp = va_arg (args, const char * const *);
1027 va_end (args);
1028
380aaf2d 1029 return spawnve (mode, path, (char * const *) argv, (char * const *) envp);
1fd5e000
CF
1030}
1031
0a047e8f 1032extern "C" int
1fd5e000
CF
1033spawnlp (int mode, const char *path, const char *arg0, ...)
1034{
1035 int i;
1036 va_list args;
1037 const char *argv[256];
1038
1039 va_start (args, arg0);
1040 argv[0] = arg0;
1041 i = 1;
1042
1043 do
1044 argv[i] = va_arg (args, const char *);
1045 while (argv[i++] != NULL);
1046
1047 va_end (args);
1048
4c8d72de 1049 return spawnvpe (mode, path, (char * const *) argv, cur_environ ());
1fd5e000
CF
1050}
1051
0a047e8f 1052extern "C" int
1fd5e000
CF
1053spawnlpe (int mode, const char *path, const char *arg0, ...)
1054{
1055 int i;
1056 va_list args;
1057 const char * const *envp;
1058 const char *argv[256];
1059
1060 va_start (args, arg0);
1061 argv[0] = arg0;
1062 i = 1;
1063
1064 do
1065 argv[i] = va_arg (args, const char *);
1066 while (argv[i++] != NULL);
1067
1068 envp = va_arg (args, const char * const *);
1069 va_end (args);
1070
1071 return spawnvpe (mode, path, (char * const *) argv, envp);
1072}
1073
0a047e8f 1074extern "C" int
1fd5e000
CF
1075spawnv (int mode, const char *path, const char * const *argv)
1076{
380aaf2d 1077 return spawnve (mode, path, argv, cur_environ ());
1fd5e000
CF
1078}
1079
0a047e8f 1080extern "C" int
1fd5e000
CF
1081spawnvp (int mode, const char *path, const char * const *argv)
1082{
4c8d72de 1083 return spawnvpe (mode, path, argv, cur_environ ());
1fd5e000
CF
1084}
1085
0a047e8f 1086extern "C" int
1fd5e000
CF
1087spawnvpe (int mode, const char *file, const char * const *argv,
1088 const char * const *envp)
1089{
55fc91b9 1090 path_conv buf;
380aaf2d 1091 return spawnve (mode, find_exec (file, buf), argv, envp);
1fd5e000 1092}
This page took 0.337037 seconds and 5 git commands to generate.