]> sourceware.org Git - newlib-cygwin.git/blob - winsup/cygwin/dcrt0.cc
2003-09-15 Pierre Humblet <pierre.humblet@ieee.org>
[newlib-cygwin.git] / winsup / cygwin / dcrt0.cc
1 /* dcrt0.cc -- essentially the main() for the Cygwin dll
2
3 Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
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
11 #include "winsup.h"
12 #include <unistd.h>
13 #include <stdlib.h>
14 #include "glob.h"
15 #include "exceptions.h"
16 #include <ctype.h>
17 #include <limits.h>
18 #include <wingdi.h>
19 #include <winuser.h>
20 #include "sigproc.h"
21 #include "pinfo.h"
22 #include "cygerrno.h"
23 #define NEED_VFORK
24 #include "perprocess.h"
25 #include "security.h"
26 #include "fhandler.h"
27 #include "path.h"
28 #include "dtable.h"
29 #include "cygheap.h"
30 #include "child_info_magic.h"
31 #include "perthread.h"
32 #include "shared_info.h"
33 #include "cygwin_version.h"
34 #include "dll_init.h"
35 #include "cygthread.h"
36 #include "sync.h"
37
38 #define MAX_AT_FILE_LEVEL 10
39
40 #define PREMAIN_LEN (sizeof (user_data->premain) / sizeof (user_data->premain[0]))
41
42 HANDLE NO_COPY hMainProc;
43 HANDLE NO_COPY hMainThread;
44
45 sigthread NO_COPY mainthread; // ID of the main thread
46
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
56 bool display_title;
57 bool strip_title_path;
58 bool allow_glob = TRUE;
59 codepage_type current_codepage = ansi_cp;
60
61 int cygwin_finished_initializing;
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. */
69 unsigned NO_COPY int signal_shift_subtract = 1;
70
71 ResourceLocks _reslock NO_COPY;
72 MTinterface _mtinterf;
73
74 bool NO_COPY _cygwin_testing;
75 unsigned NO_COPY _cygwin_testing_magic;
76
77 char NO_COPY almost_null[1];
78
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;
84 char ***main_environ;
85 /* __progname used in getopt error message */
86 char *__progname;
87 struct _reent reent_data = _REENT_INIT(reent_data);
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,
92 /* impure_ptr_ptr */ NULL, /* envptr */ NULL,
93 /* malloc */ malloc, /* free */ free,
94 /* realloc */ realloc,
95 /* fmode_ptr */ NULL, /* main */ NULL, /* ctors */ NULL,
96 /* dtors */ NULL, /* data_start */ NULL, /* data_end */ NULL,
97 /* bss_start */ NULL, /* bss_end */ NULL,
98 /* calloc */ calloc,
99 /* premain */ {NULL, NULL, NULL, NULL},
100 /* run_ctors_p */ 0,
101 /* unused */ {0, 0, 0, 0, 0, 0, 0},
102 /* forkee */ 0,
103 /* hmodule */ NULL,
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 };
110 bool ignore_case_with_glob;
111 int __declspec (dllexport) _check_for_executable = TRUE;
112 #ifdef DEBUGGING
113 int pinger;
114 #endif
115 };
116
117 char *old_title;
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)
137 return; // inherit constructed stuff from parent pid
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
151 if (user_data->magic_biscuit == SIZEOF_PER_PROCESS)
152 atexit (do_global_dtors);
153 }
154
155 /*
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.
160 */
161 static int __stdcall
162 insert_file (char *name, char *&cmd)
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 */
224 static /*__inline*/ char *
225 quoted (char *cmd, int winshell)
226 {
227 char *p;
228 char quote = *cmd;
229
230 if (!winshell)
231 {
232 char *p;
233 strcpy (cmd, cmd + 1);
234 if (*(p = strechr (cmd, quote)))
235 strcpy (p, p + 1);
236 return p;
237 }
238
239 const char *s = quote == '\'' ? "'" : "\\\"";
240 /* This must have been run from a Windows shell, so preserve
241 quotes for globify to play with later. */
242 while (*cmd && *++cmd)
243 if ((p = strpbrk (cmd, s)) == NULL)
244 {
245 cmd = strchr (cmd, '\0'); // no closing quote
246 break;
247 }
248 else if (*p == '\\')
249 cmd = ++p;
250 else if (quote == '"' && p[1] == '"')
251 {
252 *p = '\\';
253 cmd = ++p; // a quoted quote
254 }
255 else
256 {
257 cmd = p + 1; // point to after end
258 break;
259 }
260 return cmd;
261 }
262
263 /* Perform a glob on word if it contains wildcard characters.
264 Also quote every character between quotes to force glob to
265 treat the characters literally. */
266 static int __stdcall
267 globify (char *word, char **&argv, int &argc, int &argvlen)
268 {
269 if (*word != '~' && strpbrk (word, "?*[\"\'(){}") == NULL)
270 return 0;
271
272 int n = 0;
273 char *p, *s;
274 int dos_spec = isdrive (word);
275 if (!dos_spec && isquote (*word) && word[1] && word[2])
276 dos_spec = isdrive (word + 1);
277
278 /* We'll need more space if there are quoting characters in
279 word. If that is the case, doubling the size of the
280 string should provide more than enough space. */
281 if (strpbrk (word, "'\""))
282 n = strlen (word);
283 char pattern[strlen (word) + ((dos_spec + 1) * n) + 1];
284
285 /* Fill pattern with characters from word, quoting any
286 characters found within quotes. */
287 for (p = pattern, s = word; *s != '\000'; s++, p++)
288 if (!isquote (*s))
289 {
290 if (dos_spec && *s == '\\')
291 *p++ = '\\';
292 *p = *s;
293 }
294 else
295 {
296 char quote = *s;
297 while (*++s && *s != quote)
298 {
299 if (dos_spec || *s != '\\')
300 /* nothing */;
301 else if (s[1] == quote || s[1] == '\\')
302 s++;
303 *p++ = '\\';
304 *p++ = *s;
305 }
306 if (*s == quote)
307 p--;
308 if (*s == '\0')
309 break;
310 }
311
312 *p = '\0';
313
314 glob_t gl;
315 gl.gl_offs = 0;
316
317 /* Attempt to match the argument. Return just word (minus quoting) if no match. */
318 if (glob (pattern, GLOB_TILDE | GLOB_NOCHECK | GLOB_BRACE | GLOB_QUOTE, NULL, &gl) || !gl.gl_pathc)
319 return 0;
320
321 /* Allocate enough space in argv for the matched filenames. */
322 n = argc;
323 if ((argc += gl.gl_pathc) > argvlen)
324 {
325 argvlen = argc + 10;
326 argv = (char **) realloc (argv, (1 + argvlen) * sizeof (argv[0]));
327 }
328
329 /* Copy the matched filenames to argv. */
330 char **gv = gl.gl_pathv;
331 char **av = argv + n;
332 while (*gv)
333 {
334 debug_printf ("argv[%d] = '%s'", n++, *gv);
335 *av++ = *gv++;
336 }
337
338 /* Clean up after glob. */
339 free (gl.gl_pathv);
340 return 1;
341 }
342
343 /* Build argv, argc from string passed from Windows. */
344
345 static void __stdcall
346 build_argv (char *cmd, char **&argv, int &argc, int winshell)
347 {
348 int argvlen = 0;
349 int nesting = 0; // monitor "nesting" from insert_file
350
351 argc = 0;
352 argvlen = 0;
353 argv = NULL;
354
355 /* Scan command line until there is nothing left. */
356 while (*cmd)
357 {
358 /* Ignore spaces */
359 if (issep (*cmd))
360 {
361 cmd++;
362 continue;
363 }
364
365 /* Found the beginning of an argument. */
366 char *word = cmd;
367 char *sawquote = NULL;
368 while (*cmd)
369 {
370 if (*cmd != '"' && (!winshell || *cmd != '\''))
371 cmd++; // Skip over this character
372 else
373 /* Skip over characters until the closing quote */
374 {
375 sawquote = cmd;
376 cmd = quoted (cmd, winshell && argc > 0);
377 }
378 if (issep (*cmd)) // End of argument if space
379 break;
380 }
381 if (*cmd)
382 *cmd++ = '\0'; // Terminate `word'
383
384 /* Possibly look for @file construction assuming that this isn't
385 the very first argument and the @ wasn't quoted */
386 if (argc && sawquote != word && *word == '@')
387 {
388 if (++nesting > MAX_AT_FILE_LEVEL)
389 api_fatal ("Too many levels of nesting for %s", word);
390 if (insert_file (word, cmd))
391 continue; // There's new stuff in cmd now
392 }
393
394 /* See if we need to allocate more space for argv */
395 if (argc >= argvlen)
396 {
397 argvlen = argc + 10;
398 argv = (char **) realloc (argv, (1 + argvlen) * sizeof (argv[0]));
399 }
400
401 /* Add word to argv file after (optional) wildcard expansion. */
402 if (!winshell || !argc || !globify (word, argv, argc, argvlen))
403 {
404 debug_printf ("argv[%d] = '%s'", argc, word);
405 argv[argc++] = word;
406 }
407 }
408
409 argv[argc] = NULL;
410
411 debug_printf ("argc %d", argc);
412 }
413
414 /* sanity and sync check */
415 void __stdcall
416 check_sanity_and_sync (per_process *p)
417 {
418 /* Sanity check to make sure developers didn't change the per_process */
419 /* struct without updating SIZEOF_PER_PROCESS [it makes them think twice */
420 /* about changing it]. */
421 if (sizeof (per_process) != SIZEOF_PER_PROCESS)
422 {
423 api_fatal ("per_process sanity check failed");
424 }
425
426 /* Make sure that the app and the dll are in sync. */
427
428 /* Complain if older than last incompatible change */
429 if (p->dll_major < CYGWIN_VERSION_DLL_EPOCH)
430 api_fatal ("cygwin DLL and APP are out of sync -- DLL version mismatch %d < %d",
431 p->dll_major, CYGWIN_VERSION_DLL_EPOCH);
432
433 /* magic_biscuit != 0 if using the old style version numbering scheme. */
434 if (p->magic_biscuit != SIZEOF_PER_PROCESS)
435 api_fatal ("Incompatible cygwin .dll -- incompatible per_process info %d != %d",
436 p->magic_biscuit, SIZEOF_PER_PROCESS);
437
438 /* Complain if incompatible API changes made */
439 if (p->api_major != cygwin_version.api_major)
440 api_fatal ("cygwin DLL and APP are out of sync -- API version mismatch %d < %d",
441 p->api_major, cygwin_version.api_major);
442
443 if (CYGWIN_VERSION_DLL_MAKE_COMBINED (p->dll_major, p->dll_minor) <=
444 CYGWIN_VERSION_DLL_BAD_SIGNAL_MASK)
445 signal_shift_subtract = 0;
446 }
447
448 child_info NO_COPY *child_proc_info = NULL;
449 static MEMORY_BASIC_INFORMATION NO_COPY sm;
450
451 #define CYGWIN_GUARD ((wincap.has_page_guard ()) ? \
452 PAGE_EXECUTE_READWRITE|PAGE_GUARD : PAGE_NOACCESS)
453
454 // __inline__ void
455 extern void
456 alloc_stack_hard_way (child_info_fork *ci, volatile char *b)
457 {
458 void *new_stack_pointer;
459 MEMORY_BASIC_INFORMATION m;
460 void *newbase;
461 int newlen;
462 LPBYTE curbot = (LPBYTE) sm.BaseAddress + sm.RegionSize;
463 bool noguard;
464
465 if (ci->stacktop > (LPBYTE) sm.AllocationBase && ci->stacktop < curbot)
466 {
467 newbase = curbot;
468 newlen = (LPBYTE) ci->stackbottom - (LPBYTE) curbot;
469 noguard = 1;
470 }
471 else
472 {
473 newbase = ci->stacktop;
474 newlen = (DWORD) ci->stackbottom - (DWORD) ci->stacktop;
475 noguard = 0;
476 }
477 if (!VirtualAlloc (newbase, newlen, MEM_RESERVE, PAGE_NOACCESS))
478 api_fatal ("fork: can't reserve memory for stack %p - %p, %E",
479 ci->stacktop, ci->stackbottom);
480
481 new_stack_pointer = (void *) ((LPBYTE) ci->stackbottom - ci->stacksize);
482
483 if (!VirtualAlloc (new_stack_pointer, ci->stacksize, MEM_COMMIT,
484 PAGE_EXECUTE_READWRITE))
485 api_fatal ("fork: can't commit memory for stack %p(%d), %E",
486 new_stack_pointer, ci->stacksize);
487 if (!VirtualQuery ((LPCVOID) new_stack_pointer, &m, sizeof m))
488 api_fatal ("fork: couldn't get new stack info, %E");
489 if (!noguard)
490 {
491 m.BaseAddress = (LPVOID)((DWORD)m.BaseAddress - 1);
492 if (!VirtualAlloc ((LPVOID) m.BaseAddress, 1, MEM_COMMIT,
493 CYGWIN_GUARD))
494 api_fatal ("fork: couldn't allocate new stack guard page %p, %E",
495 m.BaseAddress);
496 }
497 if (!VirtualQuery ((LPCVOID) m.BaseAddress, &m, sizeof m))
498 api_fatal ("fork: couldn't get new stack info, %E");
499 ci->stacktop = m.BaseAddress;
500 *b = 0;
501 }
502
503 /* extend the stack prior to fork longjmp */
504
505 static void
506 alloc_stack (child_info_fork *ci)
507 {
508 /* FIXME: adding 16384 seems to avoid a stack copy problem during
509 fork on Win95, but I don't know exactly why yet. DJ */
510 volatile char b[ci->stacksize + 16384];
511
512 if (!VirtualQuery ((LPCVOID) &b, &sm, sizeof sm))
513 api_fatal ("fork: couldn't get stack info, %E");
514
515 if (sm.AllocationBase != ci->stacktop)
516 alloc_stack_hard_way (ci, b + sizeof (b) - 1);
517 else
518 ci->stacksize = 0;
519
520 return;
521 }
522
523 static NO_COPY int mypid = 0;
524 int __argc_safe;
525 int _declspec(dllexport) __argc;
526 char _declspec(dllexport) **__argv;
527 vfork_save NO_COPY *main_vfork = NULL;
528
529 void
530 sigthread::init (const char *s)
531 {
532 InitializeCriticalSection (&lock);
533 id = GetCurrentThreadId ();
534 }
535
536 /* Take over from libc's crt0.o and start the application. Note the
537 various special cases when Cygwin DLL is being runtime loaded (as
538 opposed to being link-time loaded by Cygwin apps) from a non
539 cygwin app via LoadLibrary. */
540 static void
541 dll_crt0_1 ()
542 {
543 /* According to onno@stack.urc.tue.nl, the exception handler record must
544 be on the stack. */
545 /* FIXME: Verify forked children get their exception handler set up ok. */
546 exception_list cygwin_except_entry;
547
548 /* Initialize SIGSEGV handling, etc. */
549 init_exceptions (&cygwin_except_entry);
550
551 /* Set the os_being_run global. */
552 wincap.init ();
553 check_sanity_and_sync (user_data);
554
555 do_global_ctors (&__CTOR_LIST__, 1);
556
557 /* Nasty static stuff needed by newlib -- point to a local copy of
558 the reent stuff.
559 Note: this MUST be done here (before the forkee code) as the
560 fork copy code doesn't copy the data in libccrt0.cc (that's why we
561 pass in the per_process struct into the .dll from libccrt0). */
562
563 _impure_ptr = &reent_data;
564
565 user_data->resourcelocks->Init ();
566 user_data->threadinterface->Init ();
567
568 mainthread.init ("mainthread"); // For use in determining if signals
569 // should be blocked.
570
571 winpids::init ();
572
573 int envc = 0;
574 char **envp = NULL;
575
576 if (!child_proc_info)
577 memory_init ();
578 else
579 {
580 bool close_ppid_handle = false;
581 bool close_hexec_proc = false;
582 switch (child_proc_info->type)
583 {
584 case _PROC_FORK:
585 alloc_stack (fork_info);
586 cygheap_fixup_in_child (0);
587 memory_init ();
588 set_myself (mypid);
589 close_ppid_handle = !!child_proc_info->pppid_handle;
590 break;
591 case _PROC_SPAWN:
592 /* Have to delay closes until after cygheap is setup */
593 close_hexec_proc = !!spawn_info->hexec_proc;
594 close_ppid_handle = !!child_proc_info->pppid_handle;
595 goto around;
596 case _PROC_EXEC:
597 hexec_proc = spawn_info->hexec_proc;
598 around:
599 HANDLE h;
600 cygheap_fixup_in_child (1);
601 memory_init ();
602 if (!spawn_info->moreinfo->myself_pinfo ||
603 !DuplicateHandle (hMainProc, spawn_info->moreinfo->myself_pinfo,
604 hMainProc, &h, 0, 0,
605 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
606 h = NULL;
607 set_myself (mypid, h);
608 __argc = spawn_info->moreinfo->argc;
609 __argv = spawn_info->moreinfo->argv;
610 envp = spawn_info->moreinfo->envp;
611 envc = spawn_info->moreinfo->envc;
612 cygheap->fdtab.fixup_after_exec (spawn_info->parent);
613 signal_fixup_after_exec ();
614 CloseHandle (spawn_info->parent);
615 if (spawn_info->moreinfo->old_title)
616 {
617 old_title = strcpy (title_buf, spawn_info->moreinfo->old_title);
618 cfree (spawn_info->moreinfo->old_title);
619 }
620 break;
621 }
622 if (close_hexec_proc)
623 CloseHandle (spawn_info->hexec_proc);
624 if (close_ppid_handle)
625 CloseHandle (child_proc_info->pppid_handle);
626 }
627
628 ProtectHandle (hMainProc);
629 ProtectHandle (hMainThread);
630 cygthread::init ();
631
632 /* Initialize pthread mainthread when not forked and it is save to call new,
633 otherwise it is reinitalized in fixup_after_fork */
634 if (!user_data->forkee)
635 pthread::init_mainthread ();
636
637 #ifdef DEBUGGING
638 strace.microseconds ();
639 #endif
640
641 /* Initialize debug muto, if DLL is built with --enable-debugging.
642 Need to do this before any helper threads start. */
643 debug_init ();
644
645 cygheap->fdtab.vfork_child_fixup ();
646
647 (void) SetErrorMode (SEM_FAILCRITICALERRORS);
648
649 /* Initialize events. */
650 events_init ();
651
652 cygheap->cwd.init ();
653 main_vfork = vfork_storage.create ();
654
655 cygbench ("pre-forkee");
656 if (user_data->forkee)
657 {
658 /* If we've played with the stack, stacksize != 0. That means that
659 fork() was invoked from other than the main thread. Make sure that
660 frame pointer is referencing the new stack so that the OS knows what
661 to do when it needs to increase the size of the stack.
662
663 NOTE: Don't do anything that involves the stack until you've completed
664 this step. */
665 if (fork_info->stacksize)
666 {
667 asm ("movl %0,%%fs:4" : : "r" (fork_info->stackbottom));
668 asm ("movl %0,%%fs:8" : : "r" (fork_info->stacktop));
669 }
670
671 longjmp (fork_info->jmp, fork_info->cygpid);
672 }
673
674 #ifdef DEBUGGING
675 {
676 extern void fork_init ();
677 fork_init ();
678 }
679 #endif
680
681 /* Init global well known SID objects */
682 cygsid::init ();
683
684 /* Initialize our process table entry. */
685 pinfo_init (envp, envc);
686
687 if (!old_title && GetConsoleTitle (title_buf, TITLESIZE))
688 old_title = title_buf;
689
690 /* Allocate cygheap->fdtab */
691 dtable_init ();
692
693 /* Initialize user info. */
694 uinfo_init ();
695
696 /* Initialize signal/subprocess handling. */
697 sigproc_init ();
698
699 /* Connect to tty. */
700 tty_init ();
701
702 if (!__argc)
703 {
704 char *line = GetCommandLineA ();
705 line = strcpy ((char *) alloca (strlen (line) + 1), line);
706
707 if (current_codepage == oem_cp)
708 CharToOemA (line, line);
709
710 /* Scan the command line and build argv. Expand wildcards if not
711 called from another cygwin process. */
712 build_argv (line, __argv, __argc,
713 NOTSTATE (myself, PID_CYGPARENT) && allow_glob);
714
715 /* Convert argv[0] to posix rules if it's currently blatantly
716 win32 style. */
717 if ((strchr (__argv[0], ':')) || (strchr (__argv[0], '\\')))
718 {
719 char *new_argv0 = (char *) alloca (MAX_PATH);
720 cygwin_conv_to_posix_path (__argv[0], new_argv0);
721 __argv[0] = new_argv0;
722 }
723 }
724
725 __argc_safe = __argc;
726 if (user_data->premain[0])
727 for (unsigned int i = 0; i < PREMAIN_LEN / 2; i++)
728 user_data->premain[i] (__argc, __argv, user_data);
729
730 /* Set up standard fds in file descriptor table. */
731 cygheap->fdtab.stdio_init ();
732
733 /* Set up __progname for getopt error call. */
734 if (__argv[0] && (__progname = strrchr (__argv[0], '/')))
735 ++__progname;
736 else
737 __progname = __argv[0];
738 if (__progname)
739 {
740 char *cp = strchr (__progname, '\0') - 4;
741 if (cp > __progname && strcasematch (cp, ".exe"))
742 *cp = '\0';
743 }
744
745 /* Set new console title if appropriate. */
746
747 if (display_title && !dynamically_loaded)
748 {
749 char *cp = __progname;
750 if (strip_title_path)
751 for (char *ptr = cp; *ptr && *ptr != ' '; ptr++)
752 if (isdirsep (*ptr))
753 cp = ptr + 1;
754 set_console_title (cp);
755 }
756
757 cygwin_finished_initializing = 1;
758 /* Call init of loaded dlls. */
759 dlls.init ();
760
761 /* Execute any specified "premain" functions */
762 if (user_data->premain[PREMAIN_LEN / 2])
763 for (unsigned int i = PREMAIN_LEN / 2; i < PREMAIN_LEN; i++)
764 user_data->premain[i] (__argc, __argv, user_data);
765
766 debug_printf ("user_data->main %p", user_data->main);
767
768 if (dynamically_loaded)
769 {
770 set_errno (0);
771 return;
772 }
773
774 /* Disable case-insensitive globbing */
775 ignore_case_with_glob = FALSE;
776
777 /* Flush signals and ensure that signal thread is up and running. Can't
778 do this for noncygwin case since the signal thread is blocked due to
779 LoadLibrary serialization. */
780 wait_for_sigthread ();
781
782 set_errno (0);
783
784 MALLOC_CHECK;
785 cygbench (__progname);
786 if (user_data->main)
787 exit (user_data->main (__argc, __argv, *user_data->envptr));
788 }
789
790 #ifdef DEBUGGING
791 void
792 break_here ()
793 {
794 debug_printf ("break here");
795 }
796 #endif
797
798 void
799 initial_env ()
800 {
801 DWORD len;
802 char buf[MAX_PATH + 1];
803 #ifdef DEBUGGING
804 if (GetEnvironmentVariable ("CYGWIN_SLEEP", buf, sizeof (buf) - 1))
805 {
806 DWORD ms = atoi (buf);
807 buf[0] = '\0';
808 len = GetModuleFileName (NULL, buf, MAX_PATH);
809 console_printf ("Sleeping %d, pid %u %s\n", ms, GetCurrentProcessId (), buf);
810 Sleep (ms);
811 }
812 if (GetEnvironmentVariable ("CYGWIN_DEBUG", buf, sizeof (buf) - 1))
813 {
814 char buf1[MAX_PATH + 1];
815 len = GetModuleFileName (NULL, buf1, MAX_PATH);
816 strlwr (buf1);
817 strlwr (buf);
818 char *p = strchr (buf, ':');
819 if (!p)
820 p = (char *) "gdb.exe -nw";
821 else
822 *p++ = '\0';
823 if (strstr (buf1, buf))
824 {
825 error_start_init (p);
826 try_to_debug ();
827 break_here ();
828 }
829 }
830 #endif
831
832 if (GetEnvironmentVariable ("CYGWIN_TESTING", buf, sizeof (buf) - 1))
833 {
834 _cygwin_testing = 1;
835 if ((len = GetModuleFileName (cygwin_hmodule, buf, MAX_PATH))
836 && len > sizeof ("new-cygwin1.dll")
837 && strcasematch (buf + len - sizeof ("new-cygwin1.dll"),
838 "\\new-cygwin1.dll"))
839 _cygwin_testing_magic = 0x10;
840 }
841 }
842
843 /* Wrap the real one, otherwise gdb gets confused about
844 two symbols with the same name, but different addresses.
845
846 UPTR is a pointer to global data that lives on the libc side of the
847 line [if one distinguishes the application from the dll]. */
848
849 extern "C" void __stdcall
850 _dll_crt0 ()
851 {
852 DECLARE_TLS_STORAGE;
853 initial_env ();
854 char zeros[sizeof (fork_info->zero)] = {0};
855 static NO_COPY STARTUPINFO si;
856
857 main_environ = user_data->envptr;
858 *main_environ = NULL;
859
860 init_console_handler ();
861 init_global_security ();
862 if (!DuplicateHandle (GetCurrentProcess (), GetCurrentProcess (),
863 GetCurrentProcess (), &hMainProc, 0, FALSE,
864 DUPLICATE_SAME_ACCESS))
865 hMainProc = GetCurrentProcess ();
866
867 DuplicateHandle (hMainProc, GetCurrentThread (), hMainProc,
868 &hMainThread, 0, false, DUPLICATE_SAME_ACCESS);
869
870 GetStartupInfo (&si);
871 child_proc_info = (child_info *) si.lpReserved2;
872 if (si.cbReserved2 < EXEC_MAGIC_SIZE || !child_proc_info
873 || memcmp (child_proc_info->zero, zeros, sizeof (zeros)) != 0)
874 child_proc_info = NULL;
875 else
876 {
877 if ((child_proc_info->intro & OPROC_MAGIC_MASK) == OPROC_MAGIC_GENERIC)
878 multiple_cygwin_problem ("proc", child_proc_info->intro, 0);
879 else if (child_proc_info->intro == PROC_MAGIC_GENERIC
880 && child_proc_info->magic != CHILD_INFO_MAGIC)
881 multiple_cygwin_problem ("proc", child_proc_info->magic,
882 CHILD_INFO_MAGIC);
883 else if (child_proc_info->cygheap != (void *) &_cygheap_start)
884 multiple_cygwin_problem ("cygheap", (DWORD) child_proc_info->cygheap,
885 (DWORD) &_cygheap_start);
886 unsigned should_be_cb = 0;
887 switch (child_proc_info->type)
888 {
889 case _PROC_FORK:
890 user_data->forkee = child_proc_info->cygpid;
891 should_be_cb = sizeof (child_info_fork);
892 /* fall through */;
893 case _PROC_SPAWN:
894 case _PROC_EXEC:
895 if (!should_be_cb)
896 should_be_cb = sizeof (child_info);
897 if (should_be_cb != child_proc_info->cb)
898 multiple_cygwin_problem ("proc size", child_proc_info->cb, should_be_cb);
899 else if (sizeof (fhandler_union) != child_proc_info->fhandler_union_cb)
900 multiple_cygwin_problem ("fhandler size", child_proc_info->fhandler_union_cb, sizeof (fhandler_union));
901 else
902 {
903 cygwin_mount_h = child_proc_info->mount_h;
904 mypid = child_proc_info->cygpid;
905 break;
906 }
907 default:
908 system_printf ("unknown exec type %d", child_proc_info->type);
909 /* intentionally fall through */
910 case _PROC_WHOOPS:
911 child_proc_info = NULL;
912 break;
913 }
914 }
915 dll_crt0_1 ();
916 }
917
918 void
919 dll_crt0 (per_process *uptr)
920 {
921 DECLARE_TLS_STORAGE;
922 /* Set the local copy of the pointer into the user space. */
923 if (uptr && uptr != user_data)
924 {
925 memcpy (user_data, uptr, per_process_overwrite);
926 *(user_data->impure_ptr_ptr) = &reent_data;
927 }
928 _dll_crt0 ();
929 }
930
931 /* This must be called by anyone who uses LoadLibrary to load cygwin1.dll */
932 extern "C" void
933 cygwin_dll_init ()
934 {
935 static char **envp;
936 static int _fmode;
937
938 if (!DuplicateHandle (GetCurrentProcess (), GetCurrentProcess (),
939 GetCurrentProcess (), &hMainProc, 0, FALSE,
940 DUPLICATE_SAME_ACCESS))
941 hMainProc = GetCurrentProcess ();
942
943 DuplicateHandle (hMainProc, GetCurrentThread (), hMainProc,
944 &hMainThread, 0, FALSE, DUPLICATE_SAME_ACCESS);
945 user_data->magic_biscuit = sizeof (per_process);
946
947 user_data->envptr = &envp;
948 user_data->fmode_ptr = &_fmode;
949
950 dll_crt0_1 ();
951 }
952
953 extern "C" void
954 __main (void)
955 {
956 do_global_ctors (user_data->ctors, FALSE);
957 }
958
959 enum exit_states
960 {
961 ES_NOT_EXITING = 0,
962 ES_THREADTERM,
963 ES_SIGNAL,
964 ES_CLOSEALL,
965 ES_SIGPROCTERMINATE,
966 ES_TITLE,
967 ES_HUP_PGRP,
968 ES_HUP_SID,
969 ES_TTY_TERMINATE,
970 ES_EVENTS_TERMINATE
971 };
972
973 exit_states NO_COPY exit_state;
974 extern CRITICAL_SECTION exit_lock;
975
976 extern "C" void __stdcall
977 do_exit (int status)
978 {
979 EnterCriticalSection (&exit_lock);
980 UINT n = (UINT) status;
981
982 syscall_printf ("do_exit (%d)", n);
983
984 vfork_save *vf = vfork_storage.val ();
985 if (vf != NULL && vf->pid < 0)
986 vf->restore_exit (status);
987
988 if (exit_state < ES_THREADTERM)
989 {
990 exit_state = ES_THREADTERM;
991 cygthread::terminate ();
992 }
993
994 if (exit_state < ES_SIGNAL)
995 {
996 exit_state = ES_SIGNAL;
997 if (!(n & EXIT_REPARENTING))
998 {
999 signal (SIGCHLD, SIG_IGN);
1000 signal (SIGHUP, SIG_IGN);
1001 signal (SIGINT, SIG_IGN);
1002 signal (SIGQUIT, SIG_IGN);
1003 }
1004 }
1005
1006 if (exit_state < ES_CLOSEALL)
1007 {
1008 exit_state = ES_CLOSEALL;
1009 close_all_files ();
1010 }
1011
1012 if (exit_state < ES_SIGPROCTERMINATE)
1013 {
1014 exit_state = ES_SIGPROCTERMINATE;
1015 sigproc_terminate ();
1016 }
1017
1018 myself->stopsig = 0;
1019 if (exit_state < ES_TITLE)
1020 {
1021 exit_state = ES_TITLE;
1022 /* restore console title */
1023 if (old_title && display_title)
1024 set_console_title (old_title);
1025 }
1026
1027 if (exit_state < ES_HUP_PGRP)
1028 {
1029 exit_state = ES_HUP_PGRP;
1030 /* Kill orphaned children on group leader exit */
1031 if (myself->has_pgid_children && myself->pid == myself->pgid)
1032 {
1033 sigproc_printf ("%d == pgrp %d, send SIG{HUP,CONT} to stopped children",
1034 myself->pid, myself->pgid);
1035 kill_pgrp (myself->pgid, -SIGHUP);
1036 }
1037 }
1038
1039 if (exit_state < ES_HUP_SID)
1040 {
1041 exit_state = ES_HUP_SID;
1042 /* Kill the foreground process group on session leader exit */
1043 if (getpgrp () > 0 && myself->pid == myself->sid && real_tty_attached (myself))
1044 {
1045 tty *tp = cygwin_shared->tty[myself->ctty];
1046 sigproc_printf ("%d == sid %d, send SIGHUP to children",
1047 myself->pid, myself->sid);
1048
1049 /* CGF FIXME: This can't be right. */
1050 if (tp->getsid () == myself->sid)
1051 tp->kill_pgrp (SIGHUP);
1052 }
1053
1054 }
1055
1056 if (exit_state < ES_TTY_TERMINATE)
1057 {
1058 exit_state = ES_TTY_TERMINATE;
1059 tty_terminate ();
1060 }
1061
1062 if (exit_state < ES_EVENTS_TERMINATE)
1063 {
1064 exit_state = ES_EVENTS_TERMINATE;
1065 events_terminate ();
1066 }
1067
1068 minimal_printf ("winpid %d, exit %d", GetCurrentProcessId (), n);
1069 myself->exit (n);
1070 }
1071
1072 static muto *atexit_lock;
1073
1074 extern "C" int
1075 cygwin_atexit (void (*function)(void))
1076 {
1077 int res;
1078 if (!atexit_lock)
1079 new_muto (atexit_lock);
1080 atexit_lock->acquire ();
1081 res = atexit (function);
1082 atexit_lock->release ();
1083 return res;
1084 }
1085
1086 extern "C" void
1087 cygwin_exit (int n)
1088 {
1089 if (atexit_lock)
1090 atexit_lock->acquire ();
1091 exit (n);
1092 }
1093
1094 extern "C" void
1095 _exit (int n)
1096 {
1097 do_exit ((DWORD) n & 0xffff);
1098 }
1099
1100 extern "C" void
1101 __api_fatal (const char *fmt, ...)
1102 {
1103 char buf[4096];
1104 va_list ap;
1105
1106 va_start (ap, fmt);
1107 __small_vsprintf (buf, fmt, ap);
1108 va_end (ap);
1109 strcat (buf, "\n");
1110 int len = strlen (buf);
1111 DWORD done;
1112 (void) WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, len, &done, 0);
1113
1114 /* Make sure that the message shows up on the screen, too, since this is
1115 a serious error. */
1116 if (GetFileType (GetStdHandle (STD_ERROR_HANDLE)) != FILE_TYPE_CHAR)
1117 {
1118 HANDLE h = CreateFile ("CONOUT$", GENERIC_READ | GENERIC_WRITE,
1119 FILE_SHARE_WRITE | FILE_SHARE_WRITE,
1120 &sec_none, OPEN_EXISTING, 0, 0);
1121 if (h != INVALID_HANDLE_VALUE)
1122 (void) WriteFile (h, buf, len, &done, 0);
1123 }
1124
1125 /* We are going down without mercy. Make sure we reset
1126 our process_state. */
1127 sigproc_terminate ();
1128 #ifdef DEBUGGING
1129 (void) try_to_debug ();
1130 #endif
1131 myself->exit (1);
1132 }
1133
1134 void
1135 multiple_cygwin_problem (const char *what, unsigned magic_version, unsigned version)
1136 {
1137 if (_cygwin_testing && (strstr (what, "proc") || strstr (what, "cygheap")))
1138 {
1139 child_proc_info->type = _PROC_WHOOPS;
1140 return;
1141 }
1142
1143 char buf[1024];
1144 if (GetEnvironmentVariable ("CYGWIN_MISMATCH_OK", buf, sizeof (buf)))
1145 return;
1146
1147 if (CYGWIN_VERSION_MAGIC_VERSION (magic_version) == version)
1148 system_printf ("%s magic number mismatch detected - %p/%p", what, magic_version, version);
1149 else
1150 api_fatal ("%s version mismatch detected - %p/%p.\n\
1151 You have multiple copies of cygwin1.dll on your system.\n\
1152 Search for cygwin1.dll using the Windows Start->Find/Search facility\n\
1153 and delete all but the most recent version. The most recent version *should*\n\
1154 reside in x:\\cygwin\\bin, where 'x' is the drive on which you have\n\
1155 installed the cygwin distribution.", what, magic_version, version);
1156 }
1157
1158 #ifdef DEBUGGING
1159 void __stdcall
1160 cygbench (const char *s)
1161 {
1162 char buf[1024];
1163 if (GetEnvironmentVariable ("CYGWIN_BENCH", buf, sizeof (buf)))
1164 small_printf ("%05d ***** %s : %10d\n", GetCurrentProcessId (), s, strace.microseconds ());
1165 }
1166 #endif
This page took 0.094823 seconds and 5 git commands to generate.