]>
Commit | Line | Data |
---|---|---|
1fd5e000 CF |
1 | /* dcrt0.cc -- essentially the main() for the Cygwin dll |
2 | ||
33ad2bf9 | 3 | Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. |
1fd5e000 CF |
4 | |
5 | This file is part of Cygwin. | |
6 | ||
7 | This software is a copyrighted work licensed under the terms of the | |
8 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
9 | details. */ | |
10 | ||
4c8d72de | 11 | #include "winsup.h" |
1fd5e000 CF |
12 | #include <unistd.h> |
13 | #include <stdlib.h> | |
1fd5e000 CF |
14 | #include "glob.h" |
15 | #include "exceptions.h" | |
1fd5e000 | 16 | #include <ctype.h> |
166b2571 | 17 | #include <limits.h> |
ee1d77e4 CF |
18 | #include <wingdi.h> |
19 | #include <winuser.h> | |
df63bd49 | 20 | #include <errno.h> |
bccd5e0d | 21 | #include "sigproc.h" |
e2ebe117 | 22 | #include "pinfo.h" |
9e2baf8d | 23 | #include "cygerrno.h" |
f0338f54 | 24 | #define NEED_VFORK |
95a8465b | 25 | #include "perprocess.h" |
6b91b8d5 | 26 | #include "security.h" |
0381fec6 | 27 | #include "fhandler.h" |
ac5561f2 | 28 | #include "path.h" |
47063f00 | 29 | #include "dtable.h" |
0381fec6 | 30 | #include "cygheap.h" |
77f4a250 | 31 | #include "child_info_magic.h" |
0381fec6 | 32 | #include "perthread.h" |
29ac7f89 | 33 | #include "shared_info.h" |
f0338f54 | 34 | #include "cygwin_version.h" |
f0338f54 | 35 | #include "dll_init.h" |
b6bd7037 | 36 | #include "cygthread.h" |
1fd5e000 CF |
37 | |
38 | #define MAX_AT_FILE_LEVEL 10 | |
39 | ||
0312ede4 | 40 | #define PREMAIN_LEN (sizeof (user_data->premain) / sizeof (user_data->premain[0])) |
14a3bc2f | 41 | |
b6bd7037 CF |
42 | HANDLE NO_COPY hMainProc; |
43 | HANDLE NO_COPY hMainThread; | |
1fd5e000 | 44 | |
12e659ef CF |
45 | sigthread NO_COPY mainthread; // ID of the main thread |
46 | ||
1fd5e000 CF |
47 | per_thread_waitq NO_COPY waitq_storage; |
48 | per_thread_vfork NO_COPY vfork_storage; | |
49 | per_thread_signal_dispatch NO_COPY signal_dispatch_storage; | |
50 | ||
51 | per_thread NO_COPY *threadstuff[] = {&waitq_storage, | |
52 | &vfork_storage, | |
53 | &signal_dispatch_storage, | |
54 | NULL}; | |
55 | ||
08b78edf CF |
56 | BOOL display_title; |
57 | BOOL strip_title_path; | |
1fd5e000 | 58 | BOOL allow_glob = TRUE; |
ee1d77e4 | 59 | codepage_type current_codepage = ansi_cp; |
1fd5e000 | 60 | |
08b78edf | 61 | int cygwin_finished_initializing; |
1fd5e000 CF |
62 | |
63 | /* Used in SIGTOMASK for generating a bit for insertion into a sigset_t. | |
64 | This is subtracted from the signal number prior to shifting the bit. | |
65 | In older versions of cygwin, the signal was used as-is to shift the | |
66 | bit for masking. So, we'll temporarily detect this and set it to zero | |
67 | for programs that are linked using older cygwins. This is just a stopgap | |
68 | measure to allow an orderly transfer to the new, correct sigmask method. */ | |
57c89867 | 69 | unsigned NO_COPY int signal_shift_subtract = 1; |
1fd5e000 | 70 | |
737a86d3 | 71 | ResourceLocks _reslock NO_COPY; |
f9229ef7 | 72 | MTinterface _mtinterf; |
737a86d3 | 73 | |
9867ecfd | 74 | bool NO_COPY _cygwin_testing; |
57013c31 | 75 | unsigned NO_COPY _cygwin_testing_magic; |
9867ecfd | 76 | |
179cae11 CF |
77 | char NO_COPY almost_null[1]; |
78 | ||
1fd5e000 CF |
79 | extern "C" |
80 | { | |
81 | /* This is an exported copy of environ which can be used by DLLs | |
82 | which use cygwin.dll. */ | |
83 | char **__cygwin_environ; | |
2eb392bd | 84 | char ***main_environ; |
1fd5e000 | 85 | /* __progname used in getopt error message */ |
08b78edf | 86 | char *__progname; |
f97e7d75 | 87 | struct _reent reent_data = _REENT_INIT(reent_data); |
737a86d3 CF |
88 | struct per_process __cygwin_user_data = |
89 | {/* initial_sp */ 0, /* magic_biscuit */ 0, | |
90 | /* dll_major */ CYGWIN_VERSION_DLL_MAJOR, | |
91 | /* dll_major */ CYGWIN_VERSION_DLL_MINOR, | |
a0f7b496 | 92 | /* impure_ptr_ptr */ NULL, /* envptr */ NULL, |
c7e2187a CF |
93 | /* malloc */ malloc, /* free */ free, |
94 | /* realloc */ realloc, | |
737a86d3 CF |
95 | /* fmode_ptr */ NULL, /* main */ NULL, /* ctors */ NULL, |
96 | /* dtors */ NULL, /* data_start */ NULL, /* data_end */ NULL, | |
97 | /* bss_start */ NULL, /* bss_end */ NULL, | |
c7e2187a | 98 | /* calloc */ calloc, |
737a86d3 CF |
99 | /* premain */ {NULL, NULL, NULL, NULL}, |
100 | /* run_ctors_p */ 0, | |
1ff9f4b9 CF |
101 | /* unused */ {0, 0, 0, 0, 0, 0, 0}, |
102 | /* forkee */ 0, | |
103 | /* hmodule */ NULL, | |
737a86d3 CF |
104 | /* api_major */ CYGWIN_VERSION_API_MAJOR, |
105 | /* api_minor */ CYGWIN_VERSION_API_MINOR, | |
106 | /* unused2 */ {0, 0, 0, 0, 0}, | |
107 | /* resourcelocks */ &_reslock, /* threadinterface */ &_mtinterf, | |
108 | /* impure_ptr */ &reent_data, | |
109 | }; | |
08b78edf | 110 | bool ignore_case_with_glob; |
79201150 | 111 | int __declspec (dllexport) _check_for_executable = TRUE; |
95a8465b | 112 | #ifdef DEBUGGING |
08b78edf | 113 | int pinger; |
95a8465b | 114 | #endif |
1fd5e000 CF |
115 | }; |
116 | ||
08b78edf | 117 | char *old_title; |
1fd5e000 CF |
118 | char title_buf[TITLESIZE + 1]; |
119 | ||
120 | static void | |
121 | do_global_dtors (void) | |
122 | { | |
123 | if (user_data->dtors) | |
124 | { | |
125 | void (**pfunc)() = user_data->dtors; | |
126 | while (*++pfunc) | |
127 | (*pfunc) (); | |
128 | } | |
129 | } | |
130 | ||
131 | static void __stdcall | |
132 | do_global_ctors (void (**in_pfunc)(), int force) | |
133 | { | |
134 | if (!force) | |
135 | { | |
136 | if (user_data->forkee || user_data->run_ctors_p) | |
b0e82b74 | 137 | return; // inherit constructed stuff from parent pid |
1fd5e000 CF |
138 | user_data->run_ctors_p = 1; |
139 | } | |
140 | ||
141 | /* Run ctors backwards, so skip the first entry and find how many | |
142 | there are, then run them. */ | |
143 | ||
144 | void (**pfunc)() = in_pfunc; | |
145 | ||
146 | while (*++pfunc) | |
147 | ; | |
148 | while (--pfunc > in_pfunc) | |
149 | (*pfunc) (); | |
150 | ||
14a3bc2f | 151 | if (user_data->magic_biscuit == SIZEOF_PER_PROCESS) |
1fd5e000 CF |
152 | atexit (do_global_dtors); |
153 | } | |
154 | ||
1fd5e000 | 155 | /* |
052e90e9 CF |
156 | * Replaces @file in the command line with the contents of the file. |
157 | * There may be multiple @file's in a single command line | |
158 | * A \@file is replaced with @file so that echo \@foo would print | |
159 | * @foo and not the contents of foo. | |
1fd5e000 CF |
160 | */ |
161 | static int __stdcall | |
eafa31fb | 162 | insert_file (char *name, char *&cmd) |
1fd5e000 CF |
163 | { |
164 | HANDLE f; | |
165 | DWORD size; | |
166 | ||
167 | f = CreateFile (name + 1, | |
168 | GENERIC_READ, /* open for reading */ | |
169 | FILE_SHARE_READ, /* share for reading */ | |
170 | &sec_none_nih, /* no security */ | |
171 | OPEN_EXISTING, /* existing file only */ | |
172 | FILE_ATTRIBUTE_NORMAL, /* normal file */ | |
173 | NULL); /* no attr. template */ | |
174 | ||
175 | if (f == INVALID_HANDLE_VALUE) | |
176 | { | |
177 | debug_printf ("couldn't open file '%s', %E", name); | |
178 | return FALSE; | |
179 | } | |
180 | ||
181 | /* This only supports files up to about 4 billion bytes in | |
182 | size. I am making the bold assumption that this is big | |
183 | enough for this feature */ | |
184 | size = GetFileSize (f, NULL); | |
185 | if (size == 0xFFFFFFFF) | |
186 | { | |
187 | debug_printf ("couldn't get file size for '%s', %E", name); | |
188 | return FALSE; | |
189 | } | |
190 | ||
191 | int new_size = strlen (cmd) + size + 2; | |
192 | char *tmp = (char *) malloc (new_size); | |
193 | if (!tmp) | |
194 | { | |
195 | debug_printf ("malloc failed, %E"); | |
196 | return FALSE; | |
197 | } | |
198 | ||
199 | /* realloc passed as it should */ | |
200 | DWORD rf_read; | |
201 | BOOL rf_result; | |
202 | rf_result = ReadFile (f, tmp, size, &rf_read, NULL); | |
203 | CloseHandle (f); | |
204 | if (!rf_result || (rf_read != size)) | |
205 | { | |
206 | debug_printf ("ReadFile failed, %E"); | |
207 | return FALSE; | |
208 | } | |
209 | ||
210 | tmp[size++] = ' '; | |
211 | strcpy (tmp + size, cmd); | |
212 | cmd = tmp; | |
213 | return TRUE; | |
214 | } | |
215 | ||
216 | static inline int | |
217 | isquote (char c) | |
218 | { | |
219 | char ch = c; | |
220 | return ch == '"' || ch == '\''; | |
221 | } | |
222 | ||
223 | /* Step over a run of characters delimited by quotes */ | |
8e382d80 | 224 | static /*__inline*/ char * |
9cec3d45 | 225 | quoted (char *cmd, int winshell) |
1fd5e000 CF |
226 | { |
227 | char *p; | |
228 | char quote = *cmd; | |
229 | ||
b0e82b74 | 230 | if (!winshell) |
1fd5e000 | 231 | { |
b0e82b74 CF |
232 | char *p; |
233 | strcpy (cmd, cmd + 1); | |
234 | if ((p = strchr (cmd, quote)) != NULL) | |
235 | strcpy (p, p + 1); | |
4f46dbc7 CF |
236 | else |
237 | p = strchr (cmd, '\0'); | |
99d7d12a | 238 | return p; |
1fd5e000 CF |
239 | } |
240 | ||
4eafa56e | 241 | const char *s = quote == '\'' ? "'" : "\\\""; |
b0e82b74 CF |
242 | /* This must have been run from a Windows shell, so preserve |
243 | quotes for globify to play with later. */ | |
4eafa56e CF |
244 | while (*cmd && *++cmd) |
245 | if ((p = strpbrk (cmd, s)) == NULL) | |
b0e82b74 CF |
246 | { |
247 | cmd = strchr (cmd, '\0'); // no closing quote | |
248 | break; | |
249 | } | |
b0e82b74 CF |
250 | else if (*p == '\\') |
251 | cmd = ++p; | |
4eafa56e | 252 | else if (quote == '"' && p[1] == '"') |
b0e82b74 CF |
253 | { |
254 | *p = '\\'; | |
255 | cmd = ++p; // a quoted quote | |
256 | } | |
257 | else | |
258 | { | |
259 | cmd = p + 1; // point to after end | |
260 | break; | |
261 | } | |
262 | return cmd; | |
1fd5e000 CF |
263 | } |
264 | ||
265 | /* Perform a glob on word if it contains wildcard characters. | |
266 | Also quote every character between quotes to force glob to | |
267 | treat the characters literally. */ | |
268 | static int __stdcall | |
269 | globify (char *word, char **&argv, int &argc, int &argvlen) | |
270 | { | |
271 | if (*word != '~' && strpbrk (word, "?*[\"\'(){}") == NULL) | |
272 | return 0; | |
273 | ||
274 | int n = 0; | |
275 | char *p, *s; | |
75858e8a | 276 | int dos_spec = isdrive (word); |
0312ede4 | 277 | if (!dos_spec && isquote (*word) && word[1] && word[2]) |
75858e8a | 278 | dos_spec = isdrive (word + 1); |
1fd5e000 CF |
279 | |
280 | /* We'll need more space if there are quoting characters in | |
281 | word. If that is the case, doubling the size of the | |
282 | string should provide more than enough space. */ | |
283 | if (strpbrk (word, "'\"")) | |
284 | n = strlen (word); | |
285 | char pattern[strlen (word) + ((dos_spec + 1) * n) + 1]; | |
286 | ||
287 | /* Fill pattern with characters from word, quoting any | |
288 | characters found within quotes. */ | |
289 | for (p = pattern, s = word; *s != '\000'; s++, p++) | |
290 | if (!isquote (*s)) | |
291 | { | |
292 | if (dos_spec && *s == '\\') | |
293 | *p++ = '\\'; | |
294 | *p = *s; | |
295 | } | |
296 | else | |
297 | { | |
298 | char quote = *s; | |
299 | while (*++s && *s != quote) | |
300 | { | |
25ba8f30 | 301 | if (dos_spec || *s != '\\') |
c845acff | 302 | /* nothing */; |
c845acff | 303 | else if (s[1] == quote || s[1] == '\\') |
1fd5e000 CF |
304 | s++; |
305 | *p++ = '\\'; | |
306 | *p++ = *s; | |
307 | } | |
308 | if (*s == quote) | |
309 | p--; | |
310 | if (*s == '\0') | |
311 | break; | |
312 | } | |
313 | ||
314 | *p = '\0'; | |
315 | ||
316 | glob_t gl; | |
317 | gl.gl_offs = 0; | |
318 | ||
319 | /* Attempt to match the argument. Return just word (minus quoting) if no match. */ | |
320 | if (glob (pattern, GLOB_TILDE | GLOB_NOCHECK | GLOB_BRACE | GLOB_QUOTE, NULL, &gl) || !gl.gl_pathc) | |
321 | return 0; | |
322 | ||
323 | /* Allocate enough space in argv for the matched filenames. */ | |
324 | n = argc; | |
325 | if ((argc += gl.gl_pathc) > argvlen) | |
326 | { | |
327 | argvlen = argc + 10; | |
328 | argv = (char **) realloc (argv, (1 + argvlen) * sizeof (argv[0])); | |
329 | } | |
330 | ||
331 | /* Copy the matched filenames to argv. */ | |
332 | char **gv = gl.gl_pathv; | |
333 | char **av = argv + n; | |
334 | while (*gv) | |
335 | { | |
336 | debug_printf ("argv[%d] = '%s'\n", n++, *gv); | |
337 | *av++ = *gv++; | |
338 | } | |
339 | ||
340 | /* Clean up after glob. */ | |
341 | free (gl.gl_pathv); | |
342 | return 1; | |
343 | } | |
344 | ||
345 | /* Build argv, argc from string passed from Windows. */ | |
346 | ||
347 | static void __stdcall | |
348 | build_argv (char *cmd, char **&argv, int &argc, int winshell) | |
349 | { | |
350 | int argvlen = 0; | |
1fd5e000 CF |
351 | int nesting = 0; // monitor "nesting" from insert_file |
352 | ||
353 | argc = 0; | |
354 | argvlen = 0; | |
355 | argv = NULL; | |
356 | ||
357 | /* Scan command line until there is nothing left. */ | |
358 | while (*cmd) | |
359 | { | |
360 | /* Ignore spaces */ | |
361 | if (issep (*cmd)) | |
362 | { | |
363 | cmd++; | |
364 | continue; | |
365 | } | |
366 | ||
367 | /* Found the beginning of an argument. */ | |
368 | char *word = cmd; | |
369 | char *sawquote = NULL; | |
370 | while (*cmd) | |
371 | { | |
372 | if (*cmd != '"' && (!winshell || *cmd != '\'')) | |
373 | cmd++; // Skip over this character | |
374 | else | |
375 | /* Skip over characters until the closing quote */ | |
376 | { | |
377 | sawquote = cmd; | |
2768430b | 378 | cmd = quoted (cmd, winshell && argc > 0); |
1fd5e000 CF |
379 | } |
380 | if (issep (*cmd)) // End of argument if space | |
381 | break; | |
382 | } | |
383 | if (*cmd) | |
384 | *cmd++ = '\0'; // Terminate `word' | |
385 | ||
386 | /* Possibly look for @file construction assuming that this isn't | |
387 | the very first argument and the @ wasn't quoted */ | |
388 | if (argc && sawquote != word && *word == '@') | |
389 | { | |
390 | if (++nesting > MAX_AT_FILE_LEVEL) | |
391 | api_fatal ("Too many levels of nesting for %s", word); | |
eafa31fb | 392 | if (insert_file (word, cmd)) |
1fd5e000 | 393 | continue; // There's new stuff in cmd now |
1fd5e000 CF |
394 | } |
395 | ||
396 | /* See if we need to allocate more space for argv */ | |
397 | if (argc >= argvlen) | |
398 | { | |
399 | argvlen = argc + 10; | |
400 | argv = (char **) realloc (argv, (1 + argvlen) * sizeof (argv[0])); | |
401 | } | |
402 | ||
403 | /* Add word to argv file after (optional) wildcard expansion. */ | |
404 | if (!winshell || !argc || !globify (word, argv, argc, argvlen)) | |
405 | { | |
406 | debug_printf ("argv[%d] = '%s'\n", argc, word); | |
407 | argv[argc++] = word; | |
408 | } | |
409 | } | |
410 | ||
411 | argv[argc] = NULL; | |
b0e82b74 CF |
412 | |
413 | debug_printf ("argc %d", argc); | |
1fd5e000 CF |
414 | } |
415 | ||
416 | /* sanity and sync check */ | |
417 | void __stdcall | |
418 | check_sanity_and_sync (per_process *p) | |
419 | { | |
420 | /* Sanity check to make sure developers didn't change the per_process */ | |
421 | /* struct without updating SIZEOF_PER_PROCESS [it makes them think twice */ | |
422 | /* about changing it]. */ | |
423 | if (sizeof (per_process) != SIZEOF_PER_PROCESS) | |
424 | { | |
425 | api_fatal ("per_process sanity check failed"); | |
426 | } | |
427 | ||
428 | /* Make sure that the app and the dll are in sync. */ | |
429 | ||
430 | /* Complain if older than last incompatible change */ | |
431 | if (p->dll_major < CYGWIN_VERSION_DLL_EPOCH) | |
432 | api_fatal ("cygwin DLL and APP are out of sync -- DLL version mismatch %d < %d", | |
433 | p->dll_major, CYGWIN_VERSION_DLL_EPOCH); | |
434 | ||
435 | /* magic_biscuit != 0 if using the old style version numbering scheme. */ | |
436 | if (p->magic_biscuit != SIZEOF_PER_PROCESS) | |
437 | api_fatal ("Incompatible cygwin .dll -- incompatible per_process info %d != %d", | |
438 | p->magic_biscuit, SIZEOF_PER_PROCESS); | |
439 | ||
440 | /* Complain if incompatible API changes made */ | |
441 | if (p->api_major != cygwin_version.api_major) | |
442 | api_fatal ("cygwin DLL and APP are out of sync -- API version mismatch %d < %d", | |
443 | p->api_major, cygwin_version.api_major); | |
444 | ||
445 | if (CYGWIN_VERSION_DLL_MAKE_COMBINED (p->dll_major, p->dll_minor) <= | |
446 | CYGWIN_VERSION_DLL_BAD_SIGNAL_MASK) | |
447 | signal_shift_subtract = 0; | |
448 | } | |
449 | ||
6ea3e429 | 450 | child_info NO_COPY *child_proc_info = NULL; |
109e4822 | 451 | static MEMORY_BASIC_INFORMATION NO_COPY sm; |
1fd5e000 | 452 | |
a54ad580 CF |
453 | #define CYGWIN_GUARD ((wincap.has_page_guard ()) ? \ |
454 | PAGE_EXECUTE_READWRITE|PAGE_GUARD : PAGE_NOACCESS) | |
e13ea334 | 455 | |
b0e82b74 CF |
456 | // __inline__ void |
457 | extern void | |
1fd5e000 CF |
458 | alloc_stack_hard_way (child_info_fork *ci, volatile char *b) |
459 | { | |
460 | void *new_stack_pointer; | |
461 | MEMORY_BASIC_INFORMATION m; | |
b0e82b74 CF |
462 | void *newbase; |
463 | int newlen; | |
464 | LPBYTE curbot = (LPBYTE) sm.BaseAddress + sm.RegionSize; | |
465 | bool noguard; | |
1fd5e000 | 466 | |
b0e82b74 CF |
467 | if (ci->stacktop > (LPBYTE) sm.AllocationBase && ci->stacktop < curbot) |
468 | { | |
469 | newbase = curbot; | |
470 | newlen = (LPBYTE) ci->stackbottom - (LPBYTE) curbot; | |
471 | noguard = 1; | |
472 | } | |
473 | else | |
474 | { | |
475 | newbase = ci->stacktop; | |
476 | newlen = (DWORD) ci->stackbottom - (DWORD) ci->stacktop; | |
477 | noguard = 0; | |
478 | } | |
479 | if (!VirtualAlloc (newbase, newlen, MEM_RESERVE, PAGE_NOACCESS)) | |
1fd5e000 CF |
480 | api_fatal ("fork: can't reserve memory for stack %p - %p, %E", |
481 | ci->stacktop, ci->stackbottom); | |
482 | ||
483 | new_stack_pointer = (void *) ((LPBYTE) ci->stackbottom - ci->stacksize); | |
484 | ||
485 | if (!VirtualAlloc (new_stack_pointer, ci->stacksize, MEM_COMMIT, | |
486 | PAGE_EXECUTE_READWRITE)) | |
487 | api_fatal ("fork: can't commit memory for stack %p(%d), %E", | |
488 | new_stack_pointer, ci->stacksize); | |
489 | if (!VirtualQuery ((LPCVOID) new_stack_pointer, &m, sizeof m)) | |
490 | api_fatal ("fork: couldn't get new stack info, %E"); | |
b0e82b74 CF |
491 | if (!noguard) |
492 | { | |
493 | m.BaseAddress = (LPVOID)((DWORD)m.BaseAddress - 1); | |
494 | if (!VirtualAlloc ((LPVOID) m.BaseAddress, 1, MEM_COMMIT, | |
a54ad580 | 495 | CYGWIN_GUARD)) |
b0e82b74 CF |
496 | api_fatal ("fork: couldn't allocate new stack guard page %p, %E", |
497 | m.BaseAddress); | |
498 | } | |
1fd5e000 CF |
499 | if (!VirtualQuery ((LPCVOID) m.BaseAddress, &m, sizeof m)) |
500 | api_fatal ("fork: couldn't get new stack info, %E"); | |
501 | ci->stacktop = m.BaseAddress; | |
502 | *b = 0; | |
503 | } | |
504 | ||
505 | /* extend the stack prior to fork longjmp */ | |
506 | ||
b0e82b74 | 507 | static void |
1fd5e000 CF |
508 | alloc_stack (child_info_fork *ci) |
509 | { | |
510 | /* FIXME: adding 16384 seems to avoid a stack copy problem during | |
511 | fork on Win95, but I don't know exactly why yet. DJ */ | |
512 | volatile char b[ci->stacksize + 16384]; | |
513 | ||
57013c31 CF |
514 | if (!VirtualQuery ((LPCVOID) &b, &sm, sizeof sm)) |
515 | api_fatal ("fork: couldn't get stack info, %E"); | |
1fd5e000 | 516 | |
57013c31 CF |
517 | if (sm.AllocationBase != ci->stacktop) |
518 | alloc_stack_hard_way (ci, b + sizeof (b) - 1); | |
519 | else | |
520 | ci->stacksize = 0; | |
1fd5e000 CF |
521 | |
522 | return; | |
523 | } | |
524 | ||
1fd5e000 | 525 | static NO_COPY int mypid = 0; |
08b78edf CF |
526 | int _declspec(dllexport) __argc; |
527 | char _declspec(dllexport) **__argv; | |
9661a0c8 | 528 | vfork_save NO_COPY *main_vfork = NULL; |
1fd5e000 | 529 | |
f343a326 CF |
530 | void |
531 | sigthread::init (const char *s) | |
532 | { | |
c0188ae7 | 533 | InitializeCriticalSection (&lock); |
167095f6 | 534 | id = GetCurrentThreadId (); |
f343a326 CF |
535 | } |
536 | ||
1fd5e000 CF |
537 | /* Take over from libc's crt0.o and start the application. Note the |
538 | various special cases when Cygwin DLL is being runtime loaded (as | |
539 | opposed to being link-time loaded by Cygwin apps) from a non | |
540 | cygwin app via LoadLibrary. */ | |
541 | static void | |
542 | dll_crt0_1 () | |
543 | { | |
b0e82b74 CF |
544 | /* According to onno@stack.urc.tue.nl, the exception handler record must |
545 | be on the stack. */ | |
546 | /* FIXME: Verify forked children get their exception handler set up ok. */ | |
547 | exception_list cygwin_except_entry; | |
1fd5e000 | 548 | |
2a6fc028 | 549 | /* Initialize SIGSEGV handling, etc. */ |
b0e82b74 CF |
550 | init_exceptions (&cygwin_except_entry); |
551 | ||
b0e82b74 | 552 | /* Set the os_being_run global. */ |
ba946828 | 553 | wincap.init (); |
1fd5e000 CF |
554 | check_sanity_and_sync (user_data); |
555 | ||
fe4283af CF |
556 | do_global_ctors (&__CTOR_LIST__, 1); |
557 | ||
1fd5e000 CF |
558 | /* Nasty static stuff needed by newlib -- point to a local copy of |
559 | the reent stuff. | |
560 | Note: this MUST be done here (before the forkee code) as the | |
561 | fork copy code doesn't copy the data in libccrt0.cc (that's why we | |
562 | pass in the per_process struct into the .dll from libccrt0). */ | |
563 | ||
1fd5e000 CF |
564 | _impure_ptr = &reent_data; |
565 | ||
b0e82b74 | 566 | user_data->resourcelocks->Init (); |
166b2571 | 567 | user_data->threadinterface->Init (user_data->forkee); |
4f7ac76a | 568 | |
c0188ae7 CF |
569 | mainthread.init ("mainthread"); // For use in determining if signals |
570 | // should be blocked. | |
b0e82b74 | 571 | |
166b2571 | 572 | int envc = 0; |
b0e82b74 CF |
573 | char **envp = NULL; |
574 | ||
575 | if (child_proc_info) | |
576 | { | |
c03dba93 CF |
577 | bool close_ppid_handle = false; |
578 | bool close_hexec_proc = false; | |
77f4a250 | 579 | switch (child_proc_info->type) |
b0e82b74 | 580 | { |
57013c31 | 581 | case _PROC_FORK: |
6ea3e429 | 582 | cygheap_fixup_in_child (0); |
b0e82b74 CF |
583 | alloc_stack (fork_info); |
584 | set_myself (mypid); | |
c03dba93 | 585 | close_ppid_handle = !!child_proc_info->pppid_handle; |
b0e82b74 | 586 | break; |
57013c31 | 587 | case _PROC_SPAWN: |
c03dba93 CF |
588 | /* Have to delay closes until after cygheap is setup */ |
589 | close_hexec_proc = !!spawn_info->hexec_proc; | |
590 | close_ppid_handle = !!child_proc_info->pppid_handle; | |
166b2571 | 591 | goto around; |
57013c31 | 592 | case _PROC_EXEC: |
166b2571 CF |
593 | hexec_proc = spawn_info->hexec_proc; |
594 | around: | |
b0e82b74 | 595 | HANDLE h; |
6ea3e429 | 596 | cygheap_fixup_in_child (1); |
b0e82b74 CF |
597 | if (!spawn_info->moreinfo->myself_pinfo || |
598 | !DuplicateHandle (hMainProc, spawn_info->moreinfo->myself_pinfo, | |
1dc16fc7 CF |
599 | hMainProc, &h, 0, 0, |
600 | DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE)) | |
b0e82b74 CF |
601 | h = NULL; |
602 | set_myself (mypid, h); | |
603 | __argc = spawn_info->moreinfo->argc; | |
604 | __argv = spawn_info->moreinfo->argv; | |
166b2571 CF |
605 | envp = spawn_info->moreinfo->envp; |
606 | envc = spawn_info->moreinfo->envc; | |
0381fec6 | 607 | cygheap->fdtab.fixup_after_exec (spawn_info->parent); |
166b2571 | 608 | signal_fixup_after_exec (child_proc_info->type == PROC_SPAWN); |
b0e82b74 CF |
609 | CloseHandle (spawn_info->parent); |
610 | if (spawn_info->moreinfo->old_title) | |
611 | { | |
612 | old_title = strcpy (title_buf, spawn_info->moreinfo->old_title); | |
613 | cfree (spawn_info->moreinfo->old_title); | |
614 | } | |
b0e82b74 CF |
615 | break; |
616 | } | |
c03dba93 CF |
617 | if (close_hexec_proc) |
618 | CloseHandle (spawn_info->hexec_proc); | |
619 | if (close_ppid_handle) | |
620 | CloseHandle (child_proc_info->pppid_handle); | |
b0e82b74 | 621 | } |
1fd5e000 | 622 | |
1fd5e000 | 623 | /* Initialize the cygwin subsystem if this is the first process, |
6a4878cf CF |
624 | or attach to shared data structures if it's already running. */ |
625 | memory_init (); | |
b6bd7037 | 626 | cygthread::init (); |
3d0ba393 | 627 | |
0301bfd0 CF |
628 | ProtectHandle (hMainProc); |
629 | ProtectHandle (hMainThread); | |
630 | ||
3d0ba393 CF |
631 | /* Initialize debug muto, if DLL is built with --enable-debugging. |
632 | Need to do this before any helper threads start. */ | |
633 | debug_init (); | |
634 | ||
0381fec6 | 635 | cygheap->fdtab.vfork_child_fixup (); |
1fd5e000 | 636 | |
1fd5e000 CF |
637 | (void) SetErrorMode (SEM_FAILCRITICALERRORS); |
638 | ||
1fd5e000 CF |
639 | /* Initialize events. */ |
640 | events_init (); | |
641 | ||
431ba7dd | 642 | cygheap->cwd.init (); |
9661a0c8 | 643 | main_vfork = vfork_storage.create (); |
6e8f36bc | 644 | |
166b2571 | 645 | cygbench ("pre-forkee"); |
1fd5e000 CF |
646 | if (user_data->forkee) |
647 | { | |
648 | /* If we've played with the stack, stacksize != 0. That means that | |
649 | fork() was invoked from other than the main thread. Make sure that | |
650 | frame pointer is referencing the new stack so that the OS knows what | |
651 | to do when it needs to increase the size of the stack. | |
652 | ||
653 | NOTE: Don't do anything that involves the stack until you've completed | |
654 | this step. */ | |
b0e82b74 | 655 | if (fork_info->stacksize) |
1fd5e000 | 656 | { |
b0e82b74 CF |
657 | asm ("movl %0,%%fs:4" : : "r" (fork_info->stackbottom)); |
658 | asm ("movl %0,%%fs:8" : : "r" (fork_info->stacktop)); | |
1fd5e000 CF |
659 | } |
660 | ||
b0e82b74 | 661 | longjmp (fork_info->jmp, fork_info->cygpid); |
1fd5e000 CF |
662 | } |
663 | ||
84aeff41 CF |
664 | #ifdef DEBUGGING |
665 | { | |
666 | extern void fork_init (); | |
667 | fork_init (); | |
668 | } | |
669 | #endif | |
670 | ||
b0e82b74 | 671 | /* Initialize our process table entry. */ |
166b2571 | 672 | pinfo_init (envp, envc); |
1fd5e000 CF |
673 | |
674 | if (!old_title && GetConsoleTitle (title_buf, TITLESIZE)) | |
675 | old_title = title_buf; | |
676 | ||
0381fec6 | 677 | /* Allocate cygheap->fdtab */ |
e2ebe117 | 678 | dtable_init (); |
1fd5e000 | 679 | |
9a771b29 CF |
680 | /* Initialize uid, gid if necessary. */ |
681 | if (child_proc_info == NULL || spawn_info->moreinfo->uid == ILLEGAL_UID) | |
682 | uinfo_init (); | |
7054be8b | 683 | |
1fd5e000 CF |
684 | /* Initialize signal/subprocess handling. */ |
685 | sigproc_init (); | |
686 | ||
687 | /* Connect to tty. */ | |
688 | tty_init (); | |
689 | ||
b0e82b74 | 690 | if (!__argc) |
1fd5e000 | 691 | { |
166b2571 CF |
692 | char *line = GetCommandLineA (); |
693 | line = strcpy ((char *) alloca (strlen (line) + 1), line); | |
694 | ||
ee1d77e4 | 695 | if (current_codepage == oem_cp) |
077ec4cb | 696 | CharToOemA (line, line); |
ee1d77e4 | 697 | |
b0e82b74 CF |
698 | /* Scan the command line and build argv. Expand wildcards if not |
699 | called from another cygwin process. */ | |
700 | build_argv (line, __argv, __argc, | |
701 | NOTSTATE (myself, PID_CYGPARENT) && allow_glob); | |
702 | ||
703 | /* Convert argv[0] to posix rules if it's currently blatantly | |
704 | win32 style. */ | |
705 | if ((strchr (__argv[0], ':')) || (strchr (__argv[0], '\\'))) | |
706 | { | |
707 | char *new_argv0 = (char *) alloca (MAX_PATH); | |
708 | cygwin_conv_to_posix_path (__argv[0], new_argv0); | |
b0e82b74 CF |
709 | __argv[0] = new_argv0; |
710 | } | |
1fd5e000 CF |
711 | } |
712 | ||
b0e82b74 CF |
713 | if (user_data->premain[0]) |
714 | for (unsigned int i = 0; i < PREMAIN_LEN / 2; i++) | |
95a8465b | 715 | user_data->premain[i] (__argc, __argv, user_data); |
b0e82b74 | 716 | |
1ac6d1a1 | 717 | /* Set up standard fds in file descriptor table. */ |
083abe54 | 718 | cygheap->fdtab.stdio_init (); |
1ac6d1a1 | 719 | |
1fd5e000 | 720 | /* Set up __progname for getopt error call. */ |
eba23038 CV |
721 | if (__argv[0] && (__progname = strrchr (__argv[0], '/'))) |
722 | ++__progname; | |
723 | else | |
724 | __progname = __argv[0]; | |
725 | if (__progname) | |
726 | { | |
727 | char *cp = strchr (__progname, '\0') - 4; | |
728 | if (cp > __progname && strcasematch (cp, ".exe")) | |
729 | *cp = '\0'; | |
730 | } | |
1fd5e000 | 731 | |
1dc16fc7 CF |
732 | /* Set new console title if appropriate. */ |
733 | ||
734 | if (display_title && !dynamically_loaded) | |
735 | { | |
736 | char *cp = __progname; | |
737 | if (strip_title_path) | |
738 | for (char *ptr = cp; *ptr && *ptr != ' '; ptr++) | |
739 | if (isdirsep (*ptr)) | |
740 | cp = ptr + 1; | |
741 | set_console_title (cp); | |
742 | } | |
743 | ||
2eb392bd CF |
744 | cygwin_finished_initializing = 1; |
745 | /* Call init of loaded dlls. */ | |
746 | dlls.init (); | |
1fd5e000 | 747 | |
14a3bc2f | 748 | /* Execute any specified "premain" functions */ |
737a86d3 | 749 | if (user_data->premain[PREMAIN_LEN / 2]) |
14a3bc2f | 750 | for (unsigned int i = PREMAIN_LEN / 2; i < PREMAIN_LEN; i++) |
95a8465b | 751 | user_data->premain[i] (__argc, __argv, user_data); |
14a3bc2f CF |
752 | |
753 | debug_printf ("user_data->main %p", user_data->main); | |
2eb392bd | 754 | |
5bc584ba CF |
755 | if (dynamically_loaded) |
756 | { | |
757 | set_errno (0); | |
758 | return; | |
759 | } | |
760 | ||
6ccb6bcf CF |
761 | /* Disable case-insensitive globbing */ |
762 | ignore_case_with_glob = FALSE; | |
763 | ||
5bc584ba CF |
764 | /* Flush signals and ensure that signal thread is up and running. Can't |
765 | do this for noncygwin case since the signal thread is blocked due to | |
766 | LoadLibrary serialization. */ | |
3cb62bd6 | 767 | wait_for_sigthread (); |
5bc584ba | 768 | |
2eb392bd CF |
769 | set_errno (0); |
770 | ||
b0e82b74 | 771 | MALLOC_CHECK; |
166b2571 | 772 | cygbench (__progname); |
64b30629 | 773 | if (user_data->main) |
b0e82b74 | 774 | exit (user_data->main (__argc, __argv, *user_data->envptr)); |
1fd5e000 CF |
775 | } |
776 | ||
c03dba93 CF |
777 | #ifdef DEBUGGING |
778 | void | |
779 | break_here () | |
780 | { | |
781 | debug_printf ("break here"); | |
782 | } | |
783 | #endif | |
784 | ||
57013c31 CF |
785 | void |
786 | initial_env () | |
787 | { | |
c03dba93 | 788 | DWORD len; |
57013c31 CF |
789 | char buf[MAX_PATH + 1]; |
790 | #ifdef DEBUGGING | |
791 | if (GetEnvironmentVariable ("CYGWIN_SLEEP", buf, sizeof (buf) - 1)) | |
792 | { | |
6d8bd861 | 793 | DWORD ms = atoi (buf); |
c03dba93 CF |
794 | buf[0] = '\0'; |
795 | len = GetModuleFileName (NULL, buf, MAX_PATH); | |
6d8bd861 CF |
796 | console_printf ("Sleeping %d, pid %u %s\n", ms, GetCurrentProcessId (), buf); |
797 | Sleep (ms); | |
57013c31 | 798 | } |
c03dba93 CF |
799 | if (GetEnvironmentVariable ("CYGWIN_DEBUG", buf, sizeof (buf) - 1)) |
800 | { | |
801 | char buf1[MAX_PATH + 1]; | |
802 | len = GetModuleFileName (NULL, buf1, MAX_PATH); | |
56a42791 CF |
803 | strlwr (buf1); |
804 | strlwr (buf); | |
c03dba93 CF |
805 | char *p = strchr (buf, '='); |
806 | if (!p) | |
3d0ba393 | 807 | p = (char *) "gdb.exe -nw"; |
c03dba93 CF |
808 | else |
809 | *p++ = '\0'; | |
810 | if (strstr (buf1, buf)) | |
811 | { | |
812 | error_start_init (p); | |
813 | try_to_debug (); | |
814 | break_here (); | |
815 | } | |
816 | } | |
57013c31 CF |
817 | #endif |
818 | ||
819 | if (GetEnvironmentVariable ("CYGWIN_TESTING", buf, sizeof (buf) - 1)) | |
820 | { | |
821 | _cygwin_testing = 1; | |
57013c31 CF |
822 | if ((len = GetModuleFileName (cygwin_hmodule, buf, MAX_PATH)) |
823 | && len > sizeof ("new-cygwin1.dll") | |
824 | && strcasematch (buf + len - sizeof ("new-cygwin1.dll"), | |
825 | "\\new-cygwin1.dll")) | |
826 | _cygwin_testing_magic = 0x10; | |
827 | } | |
828 | } | |
829 | ||
1fd5e000 CF |
830 | /* Wrap the real one, otherwise gdb gets confused about |
831 | two symbols with the same name, but different addresses. | |
832 | ||
833 | UPTR is a pointer to global data that lives on the libc side of the | |
834 | line [if one distinguishes the application from the dll]. */ | |
835 | ||
72f8054f CF |
836 | extern "C" void __stdcall |
837 | _dll_crt0 () | |
1fd5e000 | 838 | { |
4d029f39 | 839 | DECLARE_TLS_STORAGE; |
57013c31 | 840 | initial_env (); |
a4785603 | 841 | char zeros[sizeof (fork_info->zero)] = {0}; |
6ea3e429 | 842 | static NO_COPY STARTUPINFO si; |
a4785603 CF |
843 | #ifdef DEBUGGING |
844 | strace.microseconds (); | |
845 | #endif | |
846 | ||
2eb392bd | 847 | main_environ = user_data->envptr; |
a4785603 | 848 | *main_environ = NULL; |
1fd5e000 | 849 | |
c0a8e8d0 | 850 | early_stuff_init (); |
1fd5e000 CF |
851 | if (!DuplicateHandle (GetCurrentProcess (), GetCurrentProcess (), |
852 | GetCurrentProcess (), &hMainProc, 0, FALSE, | |
853 | DUPLICATE_SAME_ACCESS)) | |
854 | hMainProc = GetCurrentProcess (); | |
855 | ||
856 | DuplicateHandle (hMainProc, GetCurrentThread (), hMainProc, | |
74509af2 | 857 | &hMainThread, 0, false, DUPLICATE_SAME_ACCESS); |
1fd5e000 CF |
858 | |
859 | GetStartupInfo (&si); | |
6ea3e429 | 860 | child_proc_info = (child_info *) si.lpReserved2; |
8698edb8 CF |
861 | if (si.cbReserved2 < EXEC_MAGIC_SIZE || !child_proc_info |
862 | || memcmp (child_proc_info->zero, zeros, sizeof (zeros)) != 0) | |
863 | child_proc_info = NULL; | |
864 | else | |
1fd5e000 | 865 | { |
6ea3e429 CF |
866 | if ((child_proc_info->intro & OPROC_MAGIC_MASK) == OPROC_MAGIC_GENERIC) |
867 | multiple_cygwin_problem ("proc", child_proc_info->intro, 0); | |
868 | else if (child_proc_info->intro == PROC_MAGIC_GENERIC | |
869 | && child_proc_info->magic != CHILD_INFO_MAGIC) | |
6d8bd861 CF |
870 | multiple_cygwin_problem ("proc", child_proc_info->magic, |
871 | CHILD_INFO_MAGIC); | |
872 | else if (child_proc_info->cygheap != (void *) &_cygheap_start) | |
873 | multiple_cygwin_problem ("cygheap", (DWORD) child_proc_info->cygheap, | |
874 | (DWORD) &_cygheap_start); | |
aaf219f0 | 875 | unsigned should_be_cb = 0; |
6ea3e429 | 876 | switch (child_proc_info->type) |
1fd5e000 | 877 | { |
57013c31 | 878 | case _PROC_FORK: |
6ea3e429 | 879 | user_data->forkee = child_proc_info->cygpid; |
aaf219f0 | 880 | should_be_cb = sizeof (child_info_fork); |
5daa0835 | 881 | /* fall through */; |
57013c31 | 882 | case _PROC_SPAWN: |
57013c31 | 883 | case _PROC_EXEC: |
aaf219f0 CF |
884 | if (!should_be_cb) |
885 | should_be_cb = sizeof (child_info); | |
6ea3e429 CF |
886 | if (should_be_cb != child_proc_info->cb) |
887 | multiple_cygwin_problem ("proc size", child_proc_info->cb, should_be_cb); | |
888 | else if (sizeof (fhandler_union) != child_proc_info->fhandler_union_cb) | |
889 | multiple_cygwin_problem ("fhandler size", child_proc_info->fhandler_union_cb, sizeof (fhandler_union)); | |
aaf219f0 CF |
890 | else |
891 | { | |
aaf219f0 CF |
892 | cygwin_mount_h = child_proc_info->mount_h; |
893 | mypid = child_proc_info->cygpid; | |
894 | break; | |
895 | } | |
1fd5e000 | 896 | default: |
6ea3e429 | 897 | system_printf ("unknown exec type %d", child_proc_info->type); |
6d8bd861 CF |
898 | /* intentionally fall through */ |
899 | case _PROC_WHOOPS: | |
6ea3e429 | 900 | child_proc_info = NULL; |
c08e6c44 | 901 | break; |
1fd5e000 CF |
902 | } |
903 | } | |
904 | dll_crt0_1 (); | |
905 | } | |
906 | ||
14a3bc2f CF |
907 | void |
908 | dll_crt0 (per_process *uptr) | |
909 | { | |
4d029f39 | 910 | DECLARE_TLS_STORAGE; |
14a3bc2f | 911 | /* Set the local copy of the pointer into the user space. */ |
2eb392bd | 912 | if (uptr && uptr != user_data) |
737a86d3 CF |
913 | { |
914 | memcpy (user_data, uptr, per_process_overwrite); | |
915 | *(user_data->impure_ptr_ptr) = &reent_data; | |
916 | } | |
72f8054f | 917 | _dll_crt0 (); |
14a3bc2f CF |
918 | } |
919 | ||
48b87053 | 920 | /* This must be called by anyone who uses LoadLibrary to load cygwin1.dll */ |
737a86d3 | 921 | extern "C" void |
48b87053 DD |
922 | cygwin_dll_init () |
923 | { | |
48b87053 DD |
924 | static char **envp; |
925 | static int _fmode; | |
48b87053 DD |
926 | |
927 | if (!DuplicateHandle (GetCurrentProcess (), GetCurrentProcess (), | |
928 | GetCurrentProcess (), &hMainProc, 0, FALSE, | |
929 | DUPLICATE_SAME_ACCESS)) | |
930 | hMainProc = GetCurrentProcess (); | |
931 | ||
932 | DuplicateHandle (hMainProc, GetCurrentThread (), hMainProc, | |
933 | &hMainThread, 0, FALSE, DUPLICATE_SAME_ACCESS); | |
48b87053 DD |
934 | user_data->magic_biscuit = sizeof (per_process); |
935 | ||
48b87053 DD |
936 | user_data->envptr = &envp; |
937 | user_data->fmode_ptr = &_fmode; | |
938 | ||
48b87053 DD |
939 | dll_crt0_1 (); |
940 | } | |
941 | ||
1fd5e000 CF |
942 | extern "C" void |
943 | __main (void) | |
944 | { | |
945 | do_global_ctors (user_data->ctors, FALSE); | |
946 | } | |
947 | ||
948 | enum | |
949 | { | |
950 | ES_SIGNAL = 1, | |
951 | ES_CLOSEALL = 2, | |
952 | ES_SIGPROCTERMINATE = 3 | |
953 | }; | |
954 | ||
955 | extern "C" void __stdcall | |
956 | do_exit (int status) | |
957 | { | |
1fd5e000 CF |
958 | UINT n = (UINT) status; |
959 | static int NO_COPY exit_state = 0; | |
960 | ||
961 | syscall_printf ("do_exit (%d)", n); | |
962 | ||
963 | vfork_save *vf = vfork_storage.val (); | |
964 | if (vf != NULL && vf->pid < 0) | |
8dca9e23 | 965 | vf->restore_exit (status); |
1fd5e000 CF |
966 | |
967 | if (exit_state < ES_SIGNAL) | |
968 | { | |
969 | exit_state = ES_SIGNAL; | |
970 | if (!(n & EXIT_REPARENTING)) | |
971 | { | |
972 | signal (SIGCHLD, SIG_IGN); | |
973 | signal (SIGHUP, SIG_IGN); | |
974 | signal (SIGINT, SIG_IGN); | |
975 | signal (SIGQUIT, SIG_IGN); | |
976 | } | |
977 | } | |
978 | ||
166b2571 | 979 | if (exit_state < ES_CLOSEALL) |
1fd5e000 CF |
980 | { |
981 | exit_state = ES_CLOSEALL; | |
982 | close_all_files (); | |
983 | } | |
984 | ||
985 | if (exit_state < ES_SIGPROCTERMINATE) | |
986 | { | |
987 | exit_state = ES_SIGPROCTERMINATE; | |
988 | sigproc_terminate (); | |
989 | } | |
990 | ||
991 | if (n & EXIT_REPARENTING) | |
aece55b9 | 992 | n &= ~EXIT_REPARENTING; |
1fd5e000 CF |
993 | else |
994 | { | |
995 | myself->stopsig = 0; | |
996 | ||
997 | /* restore console title */ | |
998 | if (old_title && display_title) | |
999 | set_console_title (old_title); | |
1000 | ||
1001 | /* Kill orphaned children on group leader exit */ | |
f8f9b12e | 1002 | if (myself->has_pgid_children && myself->pid == myself->pgid) |
1fd5e000 CF |
1003 | { |
1004 | sigproc_printf ("%d == pgrp %d, send SIG{HUP,CONT} to stopped children", | |
1005 | myself->pid, myself->pgid); | |
1006 | kill_pgrp (myself->pgid, -SIGHUP); | |
1007 | } | |
1008 | ||
1009 | /* Kill the foreground process group on session leader exit */ | |
b98ebf54 | 1010 | if (getpgrp () > 0 && myself->pid == myself->sid && real_tty_attached (myself)) |
1fd5e000 CF |
1011 | { |
1012 | tty *tp = cygwin_shared->tty[myself->ctty]; | |
1013 | sigproc_printf ("%d == sid %d, send SIGHUP to children", | |
1014 | myself->pid, myself->sid); | |
1015 | ||
45a7e957 | 1016 | /* CGF FIXME: This can't be right. */ |
1fd5e000 | 1017 | if (tp->getsid () == myself->sid) |
083abe54 | 1018 | tp->kill_pgrp (SIGHUP); |
1fd5e000 | 1019 | } |
ec300c99 | 1020 | |
1fd5e000 | 1021 | tty_terminate (); |
1fd5e000 CF |
1022 | } |
1023 | ||
1024 | window_terminate (); | |
1fd5e000 | 1025 | events_terminate (); |
1fd5e000 | 1026 | shared_terminate (); |
aea1f301 | 1027 | cygthread::terminate (); |
1fd5e000 | 1028 | |
1fd5e000 | 1029 | minimal_printf ("winpid %d, exit %d", GetCurrentProcessId (), n); |
1dc16fc7 | 1030 | myself->exit (n); |
1fd5e000 CF |
1031 | } |
1032 | ||
1033 | extern "C" void | |
1034 | _exit (int n) | |
1035 | { | |
1036 | do_exit ((DWORD) n & 0xffff); | |
1037 | } | |
1038 | ||
1039 | extern "C" void | |
1040 | __api_fatal (const char *fmt, ...) | |
1041 | { | |
1042 | char buf[4096]; | |
1043 | va_list ap; | |
1044 | ||
1045 | va_start (ap, fmt); | |
1046 | __small_vsprintf (buf, fmt, ap); | |
1047 | va_end (ap); | |
ec300c99 CF |
1048 | strcat (buf, "\n"); |
1049 | int len = strlen (buf); | |
1050 | DWORD done; | |
1051 | (void) WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, len, &done, 0); | |
1052 | ||
1053 | /* Make sure that the message shows up on the screen, too, since this is | |
1054 | a serious error. */ | |
1055 | if (GetFileType (GetStdHandle (STD_ERROR_HANDLE)) != FILE_TYPE_CHAR) | |
1056 | { | |
580e99a1 CF |
1057 | HANDLE h = CreateFile ("CONOUT$", GENERIC_READ | GENERIC_WRITE, |
1058 | FILE_SHARE_WRITE | FILE_SHARE_WRITE, | |
1059 | &sec_none, OPEN_EXISTING, 0, 0); | |
1060 | if (h != INVALID_HANDLE_VALUE) | |
ec300c99 CF |
1061 | (void) WriteFile (h, buf, len, &done, 0); |
1062 | } | |
1fd5e000 CF |
1063 | |
1064 | /* We are going down without mercy. Make sure we reset | |
1065 | our process_state. */ | |
737a86d3 | 1066 | sigproc_terminate (); |
1fd5e000 CF |
1067 | #ifdef DEBUGGING |
1068 | (void) try_to_debug (); | |
1069 | #endif | |
1dc16fc7 | 1070 | myself->exit (1); |
1fd5e000 CF |
1071 | } |
1072 | ||
d3fee5ec | 1073 | void |
77f4a250 | 1074 | multiple_cygwin_problem (const char *what, unsigned magic_version, unsigned version) |
d3fee5ec | 1075 | { |
6d8bd861 | 1076 | if (_cygwin_testing && (strstr (what, "proc") || strstr (what, "cygheap"))) |
aaf219f0 | 1077 | { |
6d8bd861 | 1078 | child_proc_info->type = _PROC_WHOOPS; |
aaf219f0 CF |
1079 | return; |
1080 | } | |
5daa0835 CF |
1081 | |
1082 | char buf[1024]; | |
1083 | if (GetEnvironmentVariable ("CYGWIN_MISMATCH_OK", buf, sizeof (buf))) | |
1084 | return; | |
1085 | ||
1086 | if (CYGWIN_VERSION_MAGIC_VERSION (magic_version) == version) | |
1087 | system_printf ("%s magic number mismatch detected - %p/%p", what, magic_version, version); | |
1088 | else | |
77f4a250 | 1089 | api_fatal ("%s version mismatch detected - %p/%p.\n\ |
d3fee5ec CF |
1090 | You have multiple copies of cygwin1.dll on your system.\n\ |
1091 | Search for cygwin1.dll using the Windows Start->Find/Search facility\n\ | |
77f4a250 CF |
1092 | and delete all but the most recent version. The most recent version *should*\n\ |
1093 | reside in x:\\cygwin\\bin, where 'x' is the drive on which you have\n\ | |
1094 | installed the cygwin distribution.", what, magic_version, version); | |
d3fee5ec CF |
1095 | } |
1096 | ||
166b2571 CF |
1097 | #ifdef DEBUGGING |
1098 | void __stdcall | |
1099 | cygbench (const char *s) | |
1100 | { | |
1101 | char buf[1024]; | |
1102 | if (GetEnvironmentVariable ("CYGWIN_BENCH", buf, sizeof (buf))) | |
1103 | small_printf ("%05d ***** %s : %10d\n", GetCurrentProcessId (), s, strace.microseconds ()); | |
1104 | } | |
1105 | #endif |