00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <stdio.h>
00012 #include <unistd.h>
00013 #include <stdlib.h>
00014 #include <fcntl.h>
00015 #include <stdarg.h>
00016 #include <errno.h>
00017 #include "winsup.h"
00018 #include "dll_init.h"
00019
00020 DWORD NO_COPY chunksize = 0;
00021
00022
00023 #define FORK_WAIT_TIMEOUT (300 * 1000)
00024
00025 #define dll_data_start &_data_start__
00026 #define dll_data_end &_data_end__
00027 #define dll_bss_start &_bss_start__
00028 #define dll_bss_end &_bss_end__
00029
00030 void
00031 per_thread::set (void *s)
00032 {
00033 if (s == PER_THREAD_FORK_CLEAR)
00034 {
00035 tls = TlsAlloc ();
00036 s = NULL;
00037 }
00038 TlsSetValue (get_tls (), s);
00039 }
00040
00041 static void
00042 stack_base (child_info_fork &ch)
00043 {
00044 MEMORY_BASIC_INFORMATION m;
00045 memset (&m, 0, sizeof m);
00046 if (!VirtualQuery ((LPCVOID) &m, &m, sizeof m))
00047 system_printf ("couldn't get memory info, %E");
00048
00049 ch.stacktop = m.AllocationBase;
00050 ch.stackbottom = (LPBYTE) m.BaseAddress + m.RegionSize;
00051 ch.stacksize = (DWORD) ch.stackbottom - (DWORD) &m;
00052 debug_printf ("bottom %p, top %p, stack %p, size %d, reserve %d",
00053 ch.stackbottom, ch.stacktop, &m, ch.stacksize,
00054 (DWORD) ch.stackbottom - (DWORD) ch.stacktop);
00055 }
00056
00057
00058
00059
00060 static int
00061 fork_copy (PROCESS_INFORMATION &pi, const char *what, ...)
00062 {
00063 va_list args;
00064 char *low;
00065 int pass = 0;
00066
00067 va_start (args, what);
00068
00069 while ((low = va_arg (args, char *)))
00070 {
00071 char *high = va_arg (args, char *);
00072 DWORD todo = chunksize ?: high - low;
00073 char *here;
00074
00075 for (here = low; here < high; here += todo)
00076 {
00077 DWORD done = 0;
00078 if (here + todo > high)
00079 todo = high - here;
00080 int res = WriteProcessMemory (pi.hProcess, here, here, todo, &done);
00081 debug_printf ("child handle %p, low %p, high %p, res %d", pi.hProcess,
00082 low, high, res);
00083 if (!res || todo != done)
00084 {
00085 if (!res)
00086 __seterrno ();
00087
00088
00089 system_printf ("%s pass %d failed, %p..%p, done %d, %E",
00090 what, pass, low, high, done);
00091 goto err;
00092 }
00093 }
00094
00095 pass++;
00096 }
00097
00098 debug_printf ("done");
00099 return 1;
00100
00101 err:
00102 TerminateProcess (pi.hProcess, 1);
00103 set_errno (EAGAIN);
00104 return 0;
00105 }
00106
00107
00108
00109
00110
00111 static int
00112 sync_with_child (PROCESS_INFORMATION &pi, HANDLE subproc_ready,
00113 BOOL hang_child, const char *s)
00114 {
00115
00116
00117
00118
00119 HANDLE w4[2];
00120
00121 debug_printf ("waiting for child. reason: %s", s);
00122 w4[1] = pi.hProcess;
00123 w4[0] = subproc_ready;
00124 DWORD rc = WaitForMultipleObjects (2, w4, FALSE, FORK_WAIT_TIMEOUT);
00125
00126 if (rc == WAIT_OBJECT_0 ||
00127 WaitForSingleObject (subproc_ready, 0) == WAIT_OBJECT_0)
00128 ;
00129 else if (rc == WAIT_FAILED || rc == WAIT_TIMEOUT)
00130 {
00131 if (rc != WAIT_FAILED)
00132 system_printf ("WaitForMultipleObjects timed out");
00133 else
00134 system_printf ("WaitForMultipleObjects failed, %E");
00135 set_errno (EAGAIN);
00136 syscall_printf ("-1 = fork(), WaitForMultipleObjects failed");
00137 TerminateProcess (pi.hProcess, 1);
00138 return 0;
00139 }
00140 else
00141 {
00142
00143 DWORD errcode;
00144 GetExitCodeProcess (pi.hProcess, &errcode);
00145
00146
00147
00148 if (errcode != STATUS_CONTROL_C_EXIT)
00149 {
00150 system_printf ("child %d(%p) died before initialization with status code %p",
00151 pi.dwProcessId, pi.hProcess, errcode);
00152 system_printf ("*** child state %s", s);
00153 #ifdef DEBUGGING
00154 abort ();
00155 #endif
00156 }
00157 set_errno (EAGAIN);
00158 syscall_printf ("Child died before subproc_ready signalled");
00159 return 0;
00160 }
00161
00162 debug_printf ("child signalled me");
00163 if (hang_child)
00164 {
00165 int n = SuspendThread (pi.hThread);
00166 debug_printf ("suspend count %d", n); \
00167 }
00168 return 1;
00169 }
00170
00171 static int
00172 resume_child (PROCESS_INFORMATION &pi, HANDLE forker_finished)
00173 {
00174 int rc;
00175
00176 debug_printf ("here");
00177 SetEvent (forker_finished);
00178
00179 rc = ResumeThread (pi.hThread);
00180
00181 debug_printf ("rc %d", rc);
00182 if (rc == 1)
00183 return 1;
00184
00185
00186
00187
00188
00189 small_printf ("fork: ResumeThread failed, rc = %d, %E\n", rc);
00190 set_errno (EAGAIN);
00191 syscall_printf ("-1 = fork(), ResumeThread failed");
00192 TerminateProcess (pi.hProcess, 1);
00193 return 0;
00194 }
00195
00196
00197
00198
00199 #define sync_with_parent(s, hang_self) \
00200 ((void) ({ \
00201 debug_printf ("signalling parent: %s", s); \
00202 \
00203 if (!SetEvent (child_proc_info->subproc_ready)) \
00204 api_fatal ("fork child - SetEvent failed, %E"); \
00205 if (hang_self) \
00206 { \
00207
00208
00209 \
00210 DWORD psync_rc = WaitForSingleObject (child_proc_info->forker_finished, FORK_WAIT_TIMEOUT); \
00211 switch (psync_rc) \
00212 { \
00213 case WAIT_TIMEOUT: \
00214 api_fatal ("sync_with_parent - WFSO timed out"); \
00215 break; \
00216 case WAIT_FAILED: \
00217 if (GetLastError () == ERROR_INVALID_HANDLE && \
00218 WaitForSingleObject (child_proc_info->forker_finished, 1) != WAIT_FAILED) \
00219 break; \
00220 api_fatal ("sync_with_parent - WFSO failed, fork_finished %p, %E", child_proc_info->forker_finished); \
00221 break; \
00222 default: \
00223 break; \
00224 } \
00225 debug_printf ("awake"); \
00226 } \
00227 0; \
00228 }))
00229
00230 static volatile void grow_stack_slack();
00231
00232 static void *
00233 stack_dummy (int here)
00234 {
00235 return &here;
00236 }
00237
00238 extern "C" int
00239 fork ()
00240 {
00241 int res;
00242 DWORD rc;
00243 HANDLE hParent;
00244 pinfo *child;
00245 HANDLE subproc_ready, forker_finished;
00246 void *stack_here;
00247 int x;
00248 PROCESS_INFORMATION pi = {0, NULL, 0, 0};
00249
00250 MALLOC_CHECK;
00251
00252
00253
00254
00255
00256 volatile char dummy[4096];
00257 dummy[0] = dummy[4095] = 0;
00258
00259 grow_stack_slack ();
00260
00261 debug_printf ("entering");
00262
00263 stack_here = stack_dummy (0);
00264
00265 if (ISSTATE(myself, PID_SPLIT_HEAP))
00266 {
00267 system_printf ("The heap has been split, CYGWIN can't fork this process.");
00268 system_printf ("Increase the heap_chunk_size in the registry and try again.");
00269 set_errno (ENOMEM);
00270 syscall_printf ("-1 = fork (), split heap");
00271 return -1;
00272 }
00273
00274
00275 child = cygwin_shared->p.allocate_pid ();
00276 if (!child)
00277 {
00278 set_errno (EAGAIN);
00279 syscall_printf ("-1 = fork (), process table full");
00280 return -1;
00281 }
00282
00283
00284
00285
00286
00287 dll *first_dll = dlls.start.next;
00288 int load_dlls = dlls.reload_on_fork && dlls.loaded_dlls;
00289
00290 static child_info_fork ch;
00291 x = setjmp (ch.jmp);
00292
00293 if (x == 0)
00294 {
00295
00296
00297 fflush (stdout);
00298
00299 debug_printf ("parent pid %d, child pid %d", myself->pid, child->pid);
00300
00301 subproc_ready = CreateEvent (&sec_all, FALSE, FALSE, NULL);
00302 forker_finished = CreateEvent (&sec_all, FALSE, FALSE, NULL);
00303 ProtectHandle (subproc_ready);
00304 ProtectHandle (forker_finished);
00305
00306
00307
00308 if (forker_finished == NULL || subproc_ready == NULL)
00309 {
00310 system_printf ("unable to allocate fork() resources.");
00311 system_printf ("fork() disabled.");
00312 return -1;
00313 }
00314
00315 subproc_init ();
00316
00317 debug_printf ("about to call setjmp");
00318
00319 #ifdef DEBUGGING
00320
00321
00322
00323
00324
00325
00326 free (malloc (4096));
00327 #endif
00328
00329 init_child_info (PROC_FORK1, &ch, child->pid, subproc_ready);
00330
00331 ch.forker_finished = forker_finished;
00332 ch.heaptop = user_data->heaptop;
00333 ch.heapbase = user_data->heapbase;
00334 ch.heapptr = user_data->heapptr;
00335
00336 stack_base (ch);
00337
00338
00339
00340 strcpy(child->progname, myself->progname);
00341
00342 STARTUPINFO si = {0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL};
00343
00344 si.cb = sizeof (STARTUPINFO);
00345 si.lpReserved2 = (LPBYTE)&ch;
00346 si.cbReserved2 = sizeof(ch);
00347
00348 int c_flags = GetPriorityClass (hMainProc)
00349 ;
00350
00351
00352
00353 HANDLE console_handle = CreateFileA ("CONOUT$", GENERIC_WRITE,
00354 FILE_SHARE_WRITE, &sec_none_nih,
00355 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
00356 NULL);
00357
00358 syscall_printf ("CreateProcessA (%s, %s,0,0,1,%x, 0,0,%p,%p)",
00359 myself->progname, myself->progname, c_flags, &si, &pi);
00360 if (console_handle != INVALID_HANDLE_VALUE && console_handle != 0)
00361 CloseHandle (console_handle);
00362 else
00363 c_flags |= DETACHED_PROCESS;
00364
00365 hParent = NULL;
00366 if (!DuplicateHandle (hMainProc, hMainProc, hMainProc, &hParent, 0, 1,
00367 DUPLICATE_SAME_ACCESS))
00368 {
00369 system_printf ("couldn't create handle to myself for child, %E");
00370 goto cleanup;
00371 }
00372
00373
00374 uid_t uid = geteuid();
00375 if (myself->impersonated && myself->token != INVALID_HANDLE_VALUE)
00376 seteuid (myself->orig_uid);
00377
00378 char sa_buf[1024];
00379 rc = CreateProcessA (myself->progname,
00380 myself->progname,
00381 allow_ntsec ? sec_user (sa_buf) : &sec_none_nih,
00382 allow_ntsec ? sec_user (sa_buf) : &sec_none_nih,
00383 TRUE,
00384 c_flags,
00385 NULL,
00386 0,
00387 &si,
00388 &pi);
00389
00390 CloseHandle (hParent);
00391
00392 if (!rc)
00393 {
00394 __seterrno ();
00395 syscall_printf ("-1 = fork(), CreateProcessA failed");
00396 child->process_state = PID_NOT_IN_USE;
00397 ForceCloseHandle(subproc_ready);
00398 ForceCloseHandle(forker_finished);
00399 subproc_ready = forker_finished = NULL;
00400
00401 if (myself->impersonated && myself->token != INVALID_HANDLE_VALUE)
00402 seteuid (uid);
00403 return -1;
00404 }
00405
00406
00407 if (myself->impersonated && myself->token != INVALID_HANDLE_VALUE)
00408 seteuid (uid);
00409
00410 ProtectHandle (pi.hThread);
00411
00412
00413 ProtectHandle1 (pi.hProcess, childhProc);
00414
00415
00416 child->ppid = myself->pid;
00417 child->hProcess = pi.hProcess;
00418 child->dwProcessId = pi.dwProcessId;
00419 child->uid = myself->uid;
00420 child->gid = myself->gid;
00421 child->pgid = myself->pgid;
00422 child->sid = myself->sid;
00423 child->ctty = myself->ctty;
00424 child->umask = myself->umask;
00425 child->copysigs(myself);
00426 child->process_state |= PID_INITIALIZING |
00427 (myself->process_state & PID_USETTY);
00428 memcpy (child->username, myself->username, MAX_USER_NAME);
00429 memcpy (child->sidbuf, myself->sidbuf, MAX_SID_LEN);
00430 if (myself->psid)
00431 child->psid = child->sidbuf;
00432 memcpy (child->logsrv, myself->logsrv, MAX_HOST_NAME);
00433 memcpy (child->domain, myself->domain, MAX_COMPUTERNAME_LENGTH+1);
00434 child->token = myself->token;
00435 child->impersonated = myself->impersonated;
00436 child->orig_uid = myself->orig_uid;
00437 child->orig_gid = myself->orig_gid;
00438 child->real_uid = myself->real_uid;
00439 child->real_gid = myself->real_gid;
00440 memcpy (child->root, myself->root, MAX_PATH+1);
00441 child->rootlen = myself->rootlen;
00442 set_child_mmap_ptr (child);
00443
00444
00445 if (!sync_with_child(pi, subproc_ready, TRUE, "waiting for longjmp"))
00446 goto cleanup;
00447
00448
00449 debug_printf ("child is alive (but stopped)");
00450
00451
00452
00453
00454
00455
00456 MALLOC_CHECK;
00457 rc = fork_copy (pi, "user/cygwin data",
00458 user_data->data_start, user_data->data_end,
00459 user_data->bss_start, user_data->bss_end,
00460 ch.heapbase, ch.heapptr,
00461 stack_here, ch.stackbottom,
00462 dll_data_start, dll_data_end,
00463 dll_bss_start, dll_bss_end, NULL);
00464
00465 MALLOC_CHECK;
00466 if (!rc)
00467 goto cleanup;
00468
00469
00470 for (dll *d = dlls.istart (DLL_LINK); d; d = dlls.inext ())
00471 {
00472 debug_printf ("copying data/bss of a linked dll");
00473 if (!fork_copy (pi, "linked dll data/bss", d->p.data_start, d->p.data_end,
00474 d->p.bss_start, d->p.bss_end,
00475 NULL))
00476 goto cleanup;
00477 }
00478
00479 proc_register (child);
00480
00481
00482 if (!resume_child (pi, forker_finished) ||
00483 !sync_with_child (pi, subproc_ready, load_dlls, "child loading dlls"))
00484 goto cleanup;
00485
00486
00487
00488
00489 if (load_dlls)
00490 {
00491
00492
00493 for (dll *d = dlls.istart (DLL_LOAD); d; d = dlls.inext ())
00494 {
00495 debug_printf ("copying data/bss for a loaded dll");
00496 if (!fork_copy (pi, "loaded dll data/bss", d->p.data_start, d->p.data_end,
00497 d->p.bss_start, d->p.bss_end,
00498 NULL))
00499 goto cleanup;
00500 }
00501
00502 (void) resume_child (pi, forker_finished);
00503 }
00504
00505 ForceCloseHandle (subproc_ready);
00506 ForceCloseHandle (pi.hThread);
00507 ForceCloseHandle (forker_finished);
00508 forker_finished = NULL;
00509 pi.hThread = NULL;
00510
00511 res = child->pid;
00512 }
00513 else
00514 {
00515
00516
00517
00518 (void) stack_dummy (0);
00519 debug_printf ("child is running %d", x);
00520
00521 debug_printf ("self %p, pid %d, ppid %d",
00522 myself, x, myself ? myself->ppid : -1);
00523
00524
00525
00526 if (myself->impersonated)
00527 {
00528 debug_printf ("Impersonation of child, token: %d", myself->token);
00529 if (myself->token == INVALID_HANDLE_VALUE)
00530 RevertToSelf ();
00531 else if (!ImpersonateLoggedOnUser (myself->token))
00532 system_printf ("Impersonate for forked child failed: %E");
00533 }
00534
00535 sync_with_parent ("after longjmp.", TRUE);
00536 ProtectHandle (hParent);
00537
00538 #ifdef DEBUGGING
00539 char c;
00540 if (GetEnvironmentVariable ("FORKDEBUG", &c, 1))
00541 try_to_debug ();
00542 char buf[80];
00543
00544
00545 if (GetEnvironmentVariable ("CYGWIN_FORK_SLEEP", buf, sizeof (buf)))
00546 {
00547 small_printf ("Sleeping %d after fork, pid %u\n", atoi (buf), GetCurrentProcessId ());
00548 Sleep (atoi(buf));
00549 }
00550 #endif
00551
00552
00553
00554
00555
00556 if (child_proc_info->stacksize)
00557 {
00558 ((DWORD *)child_proc_info->stackbottom)[-17] = (DWORD)do_exit;
00559 ((DWORD *)child_proc_info->stackbottom)[-15] = (DWORD)0;
00560 }
00561
00562 MALLOC_CHECK;
00563
00564 dtable.fixup_after_fork (hParent);
00565 signal_fixup_after_fork ();
00566
00567 MALLOC_CHECK;
00568
00569
00570
00571
00572
00573 if (!load_dlls)
00574 sync_with_parent ("performed fork fixup.", FALSE);
00575 else
00576 {
00577 dlls.load_after_fork (hParent, first_dll);
00578 sync_with_parent ("loaded dlls", TRUE);
00579 }
00580
00581 ForceCloseHandle (hParent);
00582 (void) ForceCloseHandle (child_proc_info->subproc_ready);
00583 (void) ForceCloseHandle (child_proc_info->forker_finished);
00584
00585 if (recreate_mmaps_after_fork (myself->mmap_ptr))
00586 api_fatal ("recreate_mmaps_after_fork_failed");
00587
00588 res = 0;
00589
00590
00591
00592 for (per_thread **t = threadstuff; *t; t++)
00593 if ((*t)->clear_on_fork ())
00594 (*t)->set ();
00595
00596
00597 sigproc_init ();
00598 }
00599
00600
00601 MALLOC_CHECK;
00602 syscall_printf ("%d = fork()", res);
00603 return res;
00604
00605
00606 cleanup:
00607
00608 child->process_state = PID_NOT_IN_USE;
00609 if (pi.hProcess)
00610 ForceCloseHandle1 (pi.hProcess, childhProc);
00611 if (pi.hThread)
00612 ForceCloseHandle (pi.hThread);
00613 if (subproc_ready)
00614 ForceCloseHandle (subproc_ready);
00615 if (forker_finished)
00616 ForceCloseHandle (forker_finished);
00617 forker_finished = subproc_ready = child->hProcess = NULL;
00618 return -1;
00619 }
00620
00621 static volatile void
00622 grow_stack_slack ()
00623 {
00624 volatile char dummy[16384];
00625 dummy[0] = dummy[16383] = 0;
00626 }
00627
00628 #ifdef NEWVFORK
00629
00630
00631 static vfork_save *
00632 get_vfork_val ()
00633 {
00634 return vfork_storage.val ();
00635 }
00636 #endif
00637
00638 extern "C"
00639 int
00640 vfork ()
00641 {
00642 #ifndef NEWVFORK
00643 return fork ();
00644 #else
00645 vfork_save *vf = get_vfork_val ();
00646
00647 if (vf == NULL)
00648 vf = vfork_storage.create ();
00649
00650 if (!setjmp (vf->j))
00651 {
00652 vf->pid = -1;
00653 __asm__ volatile ("movl %%ebp,%0": "=r" (vf->vfork_ebp):);
00654 __asm__ volatile ("movl (%%ebp),%0": "=r" (vf->caller_ebp):);
00655 __asm__ volatile ("movl 4(%%ebp),%0": "=r" (vf->retaddr):);
00656 return dtable.vfork_child_dup () ? 0 : -1;
00657 }
00658
00659 dtable.vfork_parent_restore ();
00660
00661 vf = get_vfork_val ();
00662 if (vf->pid < 0)
00663 {
00664 int exitval = -vf->pid;
00665 if ((vf->pid = fork ()) == 0)
00666 exit (exitval);
00667 }
00668
00669 vf->vfork_ebp[0] = vf->caller_ebp;
00670 vf->vfork_ebp[1] = vf->retaddr;
00671 return vf->pid;
00672 #endif
00673 }