Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin/dcrt0.cc')
-rw-r--r--winsup/cygwin/dcrt0.cc1063
1 files changed, 1063 insertions, 0 deletions
diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc
new file mode 100644
index 000000000..10652044e
--- /dev/null
+++ b/winsup/cygwin/dcrt0.cc
@@ -0,0 +1,1063 @@
+/* dcrt0.cc -- essentially the main() for the Cygwin dll
+
+ Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include "winsup.h"
+#include "glob.h"
+#include "exceptions.h"
+#include "dll_init.h"
+#include "autoload.h"
+#include <ctype.h>
+
+#define MAX_AT_FILE_LEVEL 10
+
+HANDLE NO_COPY hMainProc = NULL;
+HANDLE NO_COPY hMainThread = NULL;
+
+static per_process dummy_user_data = {0};
+per_process NO_COPY *user_data = &dummy_user_data;
+
+per_thread_waitq NO_COPY waitq_storage;
+per_thread_vfork NO_COPY vfork_storage;
+per_thread_signal_dispatch NO_COPY signal_dispatch_storage;
+
+per_thread NO_COPY *threadstuff[] = {&waitq_storage,
+ &vfork_storage,
+ &signal_dispatch_storage,
+ NULL};
+
+BOOL display_title = FALSE;
+BOOL strip_title_path = FALSE;
+BOOL allow_glob = TRUE;
+
+HANDLE NO_COPY parent_alive = NULL;
+
+/* Used in SIGTOMASK for generating a bit for insertion into a sigset_t.
+ This is subtracted from the signal number prior to shifting the bit.
+ In older versions of cygwin, the signal was used as-is to shift the
+ bit for masking. So, we'll temporarily detect this and set it to zero
+ for programs that are linked using older cygwins. This is just a stopgap
+ measure to allow an orderly transfer to the new, correct sigmask method. */
+unsigned int signal_shift_subtract = 1;
+
+extern "C"
+{
+ /* This is an exported copy of environ which can be used by DLLs
+ which use cygwin.dll. */
+ char **__cygwin_environ;
+ /* __progname used in getopt error message */
+ char *__progname;
+ struct _reent reent_data;
+};
+
+static void dll_crt0_1 ();
+
+char *old_title = NULL;
+char title_buf[TITLESIZE + 1];
+
+static void
+do_global_dtors (void)
+{
+ if (user_data->dtors)
+ {
+ void (**pfunc)() = user_data->dtors;
+ while (*++pfunc)
+ (*pfunc) ();
+ }
+}
+
+static void __stdcall
+do_global_ctors (void (**in_pfunc)(), int force)
+{
+ if (!force)
+ {
+ if (user_data->forkee || user_data->run_ctors_p)
+ return; // inherit constructed stuff from parent pid
+ user_data->run_ctors_p = 1;
+ }
+
+ /* Run ctors backwards, so skip the first entry and find how many
+ there are, then run them. */
+
+ void (**pfunc)() = in_pfunc;
+
+ while (*++pfunc)
+ ;
+ while (--pfunc > in_pfunc)
+ (*pfunc) ();
+
+ if (user_data != &dummy_user_data)
+ atexit (do_global_dtors);
+}
+
+/* remember the type of Win32 OS being run for future use. */
+os_type NO_COPY os_being_run;
+
+/* set_os_type: Set global variable os_being_run with type of Win32
+ operating system being run. This information is used internally
+ to manage the inconsistency in Win32 API calls between Win32 OSes. */
+/* Cygwin internal */
+static void
+set_os_type ()
+{
+ OSVERSIONINFO os_version_info;
+ os_version_info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
+
+ GetVersionEx (&os_version_info);
+
+ switch (os_version_info.dwPlatformId)
+ {
+ case VER_PLATFORM_WIN32_NT:
+ os_being_run = winNT;
+ break;
+ case VER_PLATFORM_WIN32_WINDOWS:
+ if (os_version_info.dwMinorVersion == 0)
+ os_being_run = win95;
+ else /* os_version_info.dwMinorVersion == 10 */
+ os_being_run = win98;
+ break;
+ case VER_PLATFORM_WIN32s:
+ os_being_run = win32s;
+ break;
+ default:
+ os_being_run = unknown;
+ break;
+ }
+}
+
+host_dependent_constants NO_COPY host_dependent;
+
+/* Constructor for host_dependent_constants. */
+
+void
+host_dependent_constants::init (void)
+{
+ /* fhandler_disk_file::lock needs a platform specific upper word
+ value for locking entire files.
+
+ fhandler_base::open requires host dependent file sharing
+ attributes. */
+
+ switch (os_being_run)
+ {
+ case winNT:
+ win32_upper = 0xffffffff;
+ shared = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+ break;
+
+ case win98:
+ case win95:
+ case win32s:
+ win32_upper = 0x00000000;
+ shared = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ break;
+
+ default:
+ api_fatal ("unrecognized system type");
+ }
+}
+
+/* Save the program name. It's used in debugging messages and by
+ the fork code (forking spawns a copy of us). Copy it into a temp and
+ then into the final spot because debugging messages use
+ myself->progname. Try getting the absolute path from the
+ module handle, if this fails get the name from the path.
+ This call references $PATH so we can't do this until the environment
+ vars are set up. */
+/* FIXME: What if argv[0] is relative, $PATH changes, and then the program
+ tries to do a fork? */
+
+static void __stdcall
+getprogname (char *argv0)
+{
+ char tmp[MAX_PATH];
+
+ if (user_data->hmodule != 0)
+ {
+ if (GetModuleFileName (user_data->hmodule, tmp, MAX_PATH) == 0)
+ find_exec (argv0, tmp);
+ }
+ else
+ find_exec (argv0, tmp);
+ strcpy (myself->progname, tmp);
+}
+
+/*
+ * Replaces -@file in the command line with the contents of the file.
+ * There may be multiple -@file's in a single command line
+ * A \-@file is replaced with -@file so that echo \-@foo would print
+ * -@foo and not the contents of foo.
+ */
+static int __stdcall
+insert_file (char *name, char *&cmd)
+{
+ HANDLE f;
+ DWORD size;
+
+ f = CreateFile (name + 1,
+ GENERIC_READ, /* open for reading */
+ FILE_SHARE_READ, /* share for reading */
+ &sec_none_nih, /* no security */
+ OPEN_EXISTING, /* existing file only */
+ FILE_ATTRIBUTE_NORMAL, /* normal file */
+ NULL); /* no attr. template */
+
+ if (f == INVALID_HANDLE_VALUE)
+ {
+ debug_printf ("couldn't open file '%s', %E", name);
+ return FALSE;
+ }
+
+ /* This only supports files up to about 4 billion bytes in
+ size. I am making the bold assumption that this is big
+ enough for this feature */
+ size = GetFileSize (f, NULL);
+ if (size == 0xFFFFFFFF)
+ {
+ debug_printf ("couldn't get file size for '%s', %E", name);
+ return FALSE;
+ }
+
+ int new_size = strlen (cmd) + size + 2;
+ char *tmp = (char *) malloc (new_size);
+ if (!tmp)
+ {
+ debug_printf ("malloc failed, %E");
+ return FALSE;
+ }
+
+ /* realloc passed as it should */
+ DWORD rf_read;
+ BOOL rf_result;
+ rf_result = ReadFile (f, tmp, size, &rf_read, NULL);
+ CloseHandle (f);
+ if (!rf_result || (rf_read != size))
+ {
+ debug_printf ("ReadFile failed, %E");
+ return FALSE;
+ }
+
+ tmp[size++] = ' ';
+ strcpy (tmp + size, cmd);
+ cmd = tmp;
+ return TRUE;
+}
+
+static inline int
+isquote (char c)
+{
+ char ch = c;
+ return ch == '"' || ch == '\'';
+}
+
+/* Step over a run of characters delimited by quotes */
+static __inline char *
+quoted (char *word, char *cmd, int winshell)
+{
+ char *p;
+ char quote = *cmd;
+
+ /* If this is being run from a Windows shell then we have
+ to preserve quotes for globify to play with later. */
+ if (winshell)
+ {
+ while (*++cmd)
+ if ((p = strchr (cmd, quote)) == NULL)
+ {
+ cmd = strchr (cmd, '\0'); // no closing quote
+ break;
+ }
+ else if (p[1] == quote)
+ {
+ *p++ = '\\';
+ cmd = p; // a quoted quote
+ }
+ else
+ {
+ cmd = p + 1; // point to after end
+ break;
+ }
+ return cmd;
+ }
+
+ /* When running as a child of a cygwin process, the quoted
+ characters should have been placed here by spawn_guts, so
+ we'll just pinch them out of the command string unless
+ they're quoted with a preceding \ */
+ strcpy (cmd, cmd + 1);
+ while (*cmd)
+ {
+ if (*cmd != quote)
+ cmd++;
+ else if (cmd[1] == quote)
+ strcpy (cmd++, cmd + 1);
+ else
+ {
+ strcpy (cmd, cmd + 1);
+ break;
+ }
+ }
+ return cmd;
+}
+
+/* Perform a glob on word if it contains wildcard characters.
+ Also quote every character between quotes to force glob to
+ treat the characters literally. */
+static int __stdcall
+globify (char *word, char **&argv, int &argc, int &argvlen)
+{
+ if (*word != '~' && strpbrk (word, "?*[\"\'(){}") == NULL)
+ return 0;
+
+ int n = 0;
+ char *p, *s;
+ int dos_spec = isalpha(*word) && word[1] == ':' ? 1 : 0;
+
+ /* We'll need more space if there are quoting characters in
+ word. If that is the case, doubling the size of the
+ string should provide more than enough space. */
+ if (strpbrk (word, "'\""))
+ n = strlen (word);
+ char pattern[strlen (word) + ((dos_spec + 1) * n) + 1];
+
+ /* Fill pattern with characters from word, quoting any
+ characters found within quotes. */
+ for (p = pattern, s = word; *s != '\000'; s++, p++)
+ if (!isquote (*s))
+ {
+ if (dos_spec && *s == '\\')
+ *p++ = '\\';
+ *p = *s;
+ }
+ else
+ {
+ char quote = *s;
+ while (*++s && *s != quote)
+ {
+ if (*s == '\\' && s[1] == quote)
+ s++;
+ *p++ = '\\';
+ *p++ = *s;
+ }
+ if (*s == quote)
+ p--;
+ if (*s == '\0')
+ break;
+ }
+
+ *p = '\0';
+
+ glob_t gl;
+ gl.gl_offs = 0;
+
+ /* Attempt to match the argument. Return just word (minus quoting) if no match. */
+ if (glob (pattern, GLOB_TILDE | GLOB_NOCHECK | GLOB_BRACE | GLOB_QUOTE, NULL, &gl) || !gl.gl_pathc)
+ return 0;
+
+ /* Allocate enough space in argv for the matched filenames. */
+ n = argc;
+ if ((argc += gl.gl_pathc) > argvlen)
+ {
+ argvlen = argc + 10;
+ argv = (char **) realloc (argv, (1 + argvlen) * sizeof (argv[0]));
+ }
+
+ /* Copy the matched filenames to argv. */
+ char **gv = gl.gl_pathv;
+ char **av = argv + n;
+ while (*gv)
+ {
+ debug_printf ("argv[%d] = '%s'\n", n++, *gv);
+ *av++ = *gv++;
+ }
+
+ /* Clean up after glob. */
+ free (gl.gl_pathv);
+ return 1;
+}
+
+/* Build argv, argc from string passed from Windows. */
+
+static void __stdcall
+build_argv (char *cmd, char **&argv, int &argc, int winshell)
+{
+ int argvlen = 0;
+ char *alloc_cmd = NULL; // command allocated by insert_file
+ int nesting = 0; // monitor "nesting" from insert_file
+
+ argc = 0;
+ argvlen = 0;
+ argv = NULL;
+
+ /* Scan command line until there is nothing left. */
+ while (*cmd)
+ {
+ /* Ignore spaces */
+ if (issep (*cmd))
+ {
+ cmd++;
+ continue;
+ }
+
+ /* Found the beginning of an argument. */
+ char *word = cmd;
+ char *sawquote = NULL;
+ while (*cmd)
+ {
+ if (*cmd != '"' && (!winshell || *cmd != '\''))
+ cmd++; // Skip over this character
+ else
+ /* Skip over characters until the closing quote */
+ {
+ sawquote = cmd;
+ cmd = quoted (word, cmd, winshell);
+ }
+ if (issep (*cmd)) // End of argument if space
+ break;
+ }
+ if (*cmd)
+ *cmd++ = '\0'; // Terminate `word'
+
+ /* Possibly look for @file construction assuming that this isn't
+ the very first argument and the @ wasn't quoted */
+ if (argc && sawquote != word && *word == '@')
+ {
+ if (++nesting > MAX_AT_FILE_LEVEL)
+ api_fatal ("Too many levels of nesting for %s", word);
+ if (insert_file (word, cmd))
+ {
+ if (alloc_cmd)
+ free (alloc_cmd); // Free space from previous insert_file
+ alloc_cmd = cmd; // and remember it for next time.
+ continue; // There's new stuff in cmd now
+ }
+ }
+
+ /* See if we need to allocate more space for argv */
+ if (argc >= argvlen)
+ {
+ argvlen = argc + 10;
+ argv = (char **) realloc (argv, (1 + argvlen) * sizeof (argv[0]));
+ }
+
+ /* Add word to argv file after (optional) wildcard expansion. */
+ if (!winshell || !argc || !globify (word, argv, argc, argvlen))
+ {
+ debug_printf ("argv[%d] = '%s'\n", argc, word);
+ argv[argc++] = word;
+ }
+ }
+
+ argv[argc] = NULL;
+ debug_printf ("argv[%d] = '%s'\n", argc, argv[argc]);
+}
+
+/* sanity and sync check */
+void __stdcall
+check_sanity_and_sync (per_process *p)
+{
+ /* Sanity check to make sure developers didn't change the per_process */
+ /* struct without updating SIZEOF_PER_PROCESS [it makes them think twice */
+ /* about changing it]. */
+ if (sizeof (per_process) != SIZEOF_PER_PROCESS)
+ {
+ api_fatal ("per_process sanity check failed");
+ }
+
+ /* Make sure that the app and the dll are in sync. */
+
+ /* Complain if older than last incompatible change */
+ if (p->dll_major < CYGWIN_VERSION_DLL_EPOCH)
+ api_fatal ("cygwin DLL and APP are out of sync -- DLL version mismatch %d < %d",
+ p->dll_major, CYGWIN_VERSION_DLL_EPOCH);
+
+ /* magic_biscuit != 0 if using the old style version numbering scheme. */
+ if (p->magic_biscuit != SIZEOF_PER_PROCESS)
+ api_fatal ("Incompatible cygwin .dll -- incompatible per_process info %d != %d",
+ p->magic_biscuit, SIZEOF_PER_PROCESS);
+
+ /* Complain if incompatible API changes made */
+ if (p->api_major != cygwin_version.api_major)
+ api_fatal ("cygwin DLL and APP are out of sync -- API version mismatch %d < %d",
+ p->api_major, cygwin_version.api_major);
+
+ if (CYGWIN_VERSION_DLL_MAKE_COMBINED (p->dll_major, p->dll_minor) <=
+ CYGWIN_VERSION_DLL_BAD_SIGNAL_MASK)
+ signal_shift_subtract = 0;
+}
+
+static NO_COPY STARTUPINFO si;
+# define ciresrv ((struct child_info_fork *)(si.lpReserved2))
+child_info_fork NO_COPY *child_proc_info = NULL;
+static MEMORY_BASIC_INFORMATION sm;
+
+#define EBP 6
+#define ESP 7
+
+extern void __inline__
+alloc_stack_hard_way (child_info_fork *ci, volatile char *b)
+{
+ void *new_stack_pointer;
+ MEMORY_BASIC_INFORMATION m;
+
+ if (!VirtualAlloc (ci->stacktop,
+ (DWORD) ci->stackbottom - (DWORD) ci->stacktop,
+ MEM_RESERVE, PAGE_NOACCESS))
+ api_fatal ("fork: can't reserve memory for stack %p - %p, %E",
+ ci->stacktop, ci->stackbottom);
+
+ new_stack_pointer = (void *) ((LPBYTE) ci->stackbottom - ci->stacksize);
+
+ if (!VirtualAlloc (new_stack_pointer, ci->stacksize, MEM_COMMIT,
+ PAGE_EXECUTE_READWRITE))
+ api_fatal ("fork: can't commit memory for stack %p(%d), %E",
+ new_stack_pointer, ci->stacksize);
+ if (!VirtualQuery ((LPCVOID) new_stack_pointer, &m, sizeof m))
+ api_fatal ("fork: couldn't get new stack info, %E");
+ m.BaseAddress = (LPVOID)((DWORD)m.BaseAddress - 1);
+ if (!VirtualAlloc ((LPVOID) m.BaseAddress, 1, MEM_COMMIT,
+ PAGE_EXECUTE_READWRITE|PAGE_GUARD))
+ api_fatal ("fork: couldn't allocate new stack guard page %p, %E",
+ m.BaseAddress);
+ if (!VirtualQuery ((LPCVOID) m.BaseAddress, &m, sizeof m))
+ api_fatal ("fork: couldn't get new stack info, %E");
+ ci->stacktop = m.BaseAddress;
+ *b = 0;
+}
+
+/* extend the stack prior to fork longjmp */
+
+extern void __inline__
+alloc_stack (child_info_fork *ci)
+{
+ /* FIXME: adding 16384 seems to avoid a stack copy problem during
+ fork on Win95, but I don't know exactly why yet. DJ */
+ volatile char b[ci->stacksize + 16384];
+
+ if (ci->type == PROC_FORK)
+ ci->stacksize = 0; // flag to fork not to do any funny business
+ else
+ {
+ if (!VirtualQuery ((LPCVOID) &b, &sm, sizeof sm))
+ api_fatal ("fork: couldn't get stack info, %E");
+
+ if (sm.AllocationBase != ci->stacktop)
+ alloc_stack_hard_way (ci, b + sizeof(b) - 1);
+ else
+ ci->stacksize = 0;
+ }
+
+ return;
+}
+
+/* These must be static due to the way we have to deal with forked
+ processes. */
+static NO_COPY LPBYTE info = NULL;
+static NO_COPY int mypid = 0;
+static int argc = 0;
+static char **argv = NULL;
+
+#ifdef _MT_SAFE
+ResourceLocks _reslock NO_COPY;
+MTinterface _mtinterf NO_COPY;
+#endif
+
+/* Take over from libc's crt0.o and start the application. Note the
+ various special cases when Cygwin DLL is being runtime loaded (as
+ opposed to being link-time loaded by Cygwin apps) from a non
+ cygwin app via LoadLibrary. */
+static void
+dll_crt0_1 ()
+{
+ /* According to onno@stack.urc.tue.nl, the exception handler record must
+ be on the stack. */
+ /* FIXME: Verify forked children get their exception handler set up ok. */
+ exception_list cygwin_except_entry;
+
+ do_global_ctors (&__CTOR_LIST__, 1);
+
+#ifdef DEBUGGING
+ if (child_proc_info)
+ switch (child_proc_info->type)
+ {
+ case PROC_FORK:
+ case PROC_FORK1:
+ ProtectHandle (child_proc_info->forker_finished);
+ case PROC_EXEC:
+ ProtectHandle (child_proc_info->subproc_ready);
+ }
+ ProtectHandle (hMainProc);
+ ProtectHandle (hMainThread);
+#endif
+
+ regthread ("main", GetCurrentThreadId ());
+
+ check_sanity_and_sync (user_data);
+
+ /* Nasty static stuff needed by newlib -- point to a local copy of
+ the reent stuff.
+ Note: this MUST be done here (before the forkee code) as the
+ fork copy code doesn't copy the data in libccrt0.cc (that's why we
+ pass in the per_process struct into the .dll from libccrt0). */
+
+ *(user_data->impure_ptr_ptr) = &reent_data;
+ _impure_ptr = &reent_data;
+
+#ifdef _MT_SAFE
+ user_data->resourcelocks = &_reslock;
+ user_data->resourcelocks->Init();
+
+ user_data->threadinterface = &_mtinterf;
+ user_data->threadinterface->Init0();
+#endif
+
+ /* Set the os_being_run global. */
+ set_os_type ();
+
+ /* If we didn't call SetFileApisToOEM, console I/O calls would use a
+ different codepage than other Win32 API calls. In some languages
+ (not English), this would result in "cat > filename" creating a file
+ by a different name than if CreateFile was used to create filename.
+ SetFileApisToOEM prevents this problem by making all calls use the
+ OEM codepage. */
+
+ SetFileApisToOEM ();
+
+ /* Initialize the host dependent constants object. */
+ host_dependent.init ();
+
+ /* Initialize the cygwin subsystem if this is the first process,
+ or attach to the shared data structure if it's already running. */
+ shared_init ();
+
+ if (mypid)
+ set_myself (cygwin_shared->p[mypid]);
+
+ (void) SetErrorMode (SEM_FAILCRITICALERRORS);
+
+ /* Initialize the heap. */
+ heap_init ();
+
+ /* Initialize events. */
+ events_init ();
+
+ threadname_init ();
+ debug_init ();
+
+ /* Initialize SIGSEGV handling, etc... Because the exception handler
+ references data in the shared area, this must be done after
+ shared_init. */
+ init_exceptions (&cygwin_except_entry);
+
+ if (user_data->forkee)
+ {
+ /* If we've played with the stack, stacksize != 0. That means that
+ fork() was invoked from other than the main thread. Make sure that
+ frame pointer is referencing the new stack so that the OS knows what
+ to do when it needs to increase the size of the stack.
+
+ NOTE: Don't do anything that involves the stack until you've completed
+ this step. */
+ if (ciresrv->stacksize)
+ {
+ asm ("movl %0,%%fs:4" : : "r" (ciresrv->stackbottom));
+ asm ("movl %0,%%fs:8" : : "r" (ciresrv->stacktop));
+ }
+
+ longjmp (ciresrv->jmp, ciresrv->cygpid);
+ }
+
+ /* Initialize our process table entry. Don't use the parent info for
+ dynamically loaded case. */
+ pinfo_init ((dynamically_loaded) ? NULL : info);
+
+ if (!old_title && GetConsoleTitle (title_buf, TITLESIZE))
+ old_title = title_buf;
+
+ /* Nasty static stuff needed by newlib - initialize it.
+ Note that impure_ptr has already been set up to point to this above
+ NB. This *MUST* be done here, just after the forkee code as some
+ of the calls below (eg. uinfo_init) do stdio calls - this area must
+ be set to zero before then. */
+
+#ifdef _MT_SAFE
+ user_data->threadinterface->ClearReent();
+ user_data->threadinterface->Init1();
+#else
+ memset (&reent_data, 0, sizeof (reent_data));
+ reent_data._errno = 0;
+ reent_data._stdin = reent_data.__sf + 0;
+ reent_data._stdout = reent_data.__sf + 1;
+ reent_data._stderr = reent_data.__sf + 2;
+#endif
+
+ char *line = GetCommandLineA ();
+ CharToOem (line, line);
+
+ line = strcpy ((char *) alloca (strlen (line) + 1), line);
+
+ /* Set new console title if appropriate. */
+
+ if (display_title && !dynamically_loaded)
+ {
+ char *cp = line;
+ if (strip_title_path)
+ for (char *ptr = cp; *ptr && *ptr != ' '; ptr++)
+ if (isdirsep (*ptr))
+ cp = ptr + 1;
+ set_console_title (cp);
+ }
+
+ /* Allocate dtable */
+ dtable_init ();
+
+ /* Initialize signal/subprocess handling. */
+ sigproc_init ();
+
+ /* Connect to tty. */
+ tty_init ();
+
+ /* Set up standard fds in file descriptor table. */
+ hinfo_init ();
+
+#if 0
+ /* Initialize uid, gid. */
+ uinfo_init ();
+#endif
+
+ syscall_printf ("Application CYGWIN version: %d.%d, api: %d.%d",
+ user_data->dll_major, user_data->dll_minor,
+ user_data->api_major, user_data->api_minor);
+ syscall_printf ("CYGWIN DLL version: %d.%d, api: %d.%d",
+ cygwin_version.dll_major, cygwin_version.dll_minor,
+ cygwin_version.api_major, cygwin_version.api_minor);
+
+ /* Scan the command line and build argv. Expand wildcards if not
+ called from another cygwin process. */
+ build_argv (line, argv, argc,
+ NOTSTATE (myself, PID_CYGPARENT) && allow_glob);
+
+ /* Convert argv[0] to posix rules if it's currently blatantly
+ win32 style. */
+ if ((strchr (argv[0], ':')) || (strchr (argv[0], '\\')))
+ {
+ char *new_argv0 = (char *) alloca (MAX_PATH);
+ cygwin_conv_to_posix_path (argv[0], new_argv0);
+ argv[0] = new_argv0;
+ }
+
+ getprogname (argv[0]);
+ /* Set up __progname for getopt error call. */
+ __progname = argv[0];
+
+ /* Call init of loaded dlls. */
+ DllList::the().initAll();
+
+ set_errno (0);
+ debug_printf ("user_data->main %p", user_data->main);
+
+ /* Flush signals and ensure that signal thread is up and running. Can't
+ do this for noncygwin case since the signal thread is blocked due to
+ LoadLibrary serialization. */
+ if (!dynamically_loaded)
+ sig_send (NULL, __SIGFLUSH);
+
+ /* Initialize uid, gid. */
+ uinfo_init ();
+
+ if (user_data->main && !dynamically_loaded)
+ exit (user_data->main (argc, argv, *user_data->envptr));
+}
+
+/* Wrap the real one, otherwise gdb gets confused about
+ two symbols with the same name, but different addresses.
+
+ UPTR is a pointer to global data that lives on the libc side of the
+ line [if one distinguishes the application from the dll]. */
+
+void
+dll_crt0 (per_process *uptr)
+{
+ char zeros[sizeof (ciresrv->zero)] = {0};
+ /* Set the local copy of the pointer into the user space. */
+ user_data = uptr;
+ user_data->heapbase = user_data->heapptr = user_data->heaptop = NULL;
+
+ set_console_handler ();
+ if (!DuplicateHandle (GetCurrentProcess (), GetCurrentProcess (),
+ GetCurrentProcess (), &hMainProc, 0, FALSE,
+ DUPLICATE_SAME_ACCESS))
+ hMainProc = GetCurrentProcess ();
+
+ DuplicateHandle (hMainProc, GetCurrentThread (), hMainProc,
+ &hMainThread, 0, FALSE, DUPLICATE_SAME_ACCESS);
+
+ GetStartupInfo (&si);
+ if (si.cbReserved2 >= EXEC_MAGIC_SIZE &&
+ memcmp (ciresrv->zero, zeros, sizeof (zeros)) == 0)
+ {
+ switch (ciresrv->type)
+ {
+ case PROC_EXEC:
+ case PROC_SPAWN:
+ case PROC_FORK:
+ case PROC_FORK1:
+ {
+ HANDLE me = hMainProc;
+ child_proc_info = ciresrv;
+ mypid = child_proc_info->cygpid;
+ cygwin_shared_h = child_proc_info->shared_h;
+ console_shared_h = child_proc_info->console_h;
+
+ /* We don't want subprocesses to inherit this */
+ if (!dynamically_loaded)
+ {
+ if (!DuplicateHandle (me, child_proc_info->parent_alive,
+ me, &parent_alive, 0, 0,
+ DUPLICATE_SAME_ACCESS
+ | DUPLICATE_CLOSE_SOURCE))
+ system_printf ("parent_alive DuplicateHandle failed, %E");
+ }
+ else if (parent_alive)
+ parent_alive = NULL;
+
+ switch (child_proc_info->type)
+ {
+ case PROC_EXEC:
+ case PROC_SPAWN:
+ info = si.lpReserved2 + ciresrv->cb;
+ break;
+ case PROC_FORK:
+ case PROC_FORK1:
+ user_data->forkee = child_proc_info->cygpid;
+ user_data->heaptop = child_proc_info->heaptop;
+ user_data->heapbase = child_proc_info->heapbase;
+ user_data->heapptr = child_proc_info->heapptr;
+ alloc_stack (ciresrv); // may never return
+ }
+ break;
+ }
+ default:
+ if ((ciresrv->type & PROC_MAGIC_MASK) == PROC_MAGIC_GENERIC)
+ api_fatal ("conflicting versions of cygwin1.dll detected. Use only the most recent version.\n");
+ }
+ }
+ dll_crt0_1 ();
+}
+
+extern "C" void
+__main (void)
+{
+ do_global_ctors (user_data->ctors, FALSE);
+}
+
+enum
+ {
+ ES_SIGNAL = 1,
+ ES_CLOSEALL = 2,
+ ES_SIGPROCTERMINATE = 3
+ };
+
+extern "C" void __stdcall
+do_exit (int status)
+{
+ BOOL cleanup_pinfo;
+ UINT n = (UINT) status;
+ static int NO_COPY exit_state = 0;
+
+ syscall_printf ("do_exit (%d)", n);
+
+ vfork_save *vf = vfork_storage.val ();
+ if (vf != NULL && vf->pid < 0)
+ {
+ vf->pid = status < 0 ? status : -status;
+ longjmp (vf->j, 1);
+ }
+
+ if (exit_state < ES_SIGNAL)
+ {
+ exit_state = ES_SIGNAL;
+ if (!(n & EXIT_REPARENTING))
+ {
+ signal (SIGCHLD, SIG_IGN);
+ signal (SIGHUP, SIG_IGN);
+ signal (SIGINT, SIG_IGN);
+ signal (SIGQUIT, SIG_IGN);
+ }
+ }
+
+ if ((hExeced && hExeced != INVALID_HANDLE_VALUE) || (n & EXIT_NOCLOSEALL))
+ n &= ~EXIT_NOCLOSEALL;
+ else if (exit_state < ES_CLOSEALL)
+ {
+ exit_state = ES_CLOSEALL;
+ close_all_files ();
+ }
+
+ if (exit_state < ES_SIGPROCTERMINATE)
+ {
+ exit_state = ES_SIGPROCTERMINATE;
+ sigproc_terminate ();
+ }
+
+ if (n & EXIT_REPARENTING)
+ {
+ n &= ~EXIT_REPARENTING;
+ cleanup_pinfo = FALSE;
+ }
+ else
+ {
+ myself->stopsig = 0;
+
+ /* restore console title */
+ if (old_title && display_title)
+ set_console_title (old_title);
+
+ /* Kill orphaned children on group leader exit */
+ if (myself->pid == myself->pgid)
+ {
+ sigproc_printf ("%d == pgrp %d, send SIG{HUP,CONT} to stopped children",
+ myself->pid, myself->pgid);
+ kill_pgrp (myself->pgid, -SIGHUP);
+ }
+
+ /* Kill the foreground process group on session leader exit */
+ if (getpgrp () > 0 && myself->pid == myself->sid && tty_attached (myself))
+ {
+ tty *tp = cygwin_shared->tty[myself->ctty];
+ sigproc_printf ("%d == sid %d, send SIGHUP to children",
+ myself->pid, myself->sid);
+
+ if (tp->getsid () == myself->sid)
+ kill (-tp->getpgid (), SIGHUP);
+ }
+ tty_terminate ();
+ cleanup_pinfo = TRUE;
+ }
+
+ window_terminate ();
+ fill_rusage (&myself->rusage_self, hMainProc);
+
+ events_terminate ();
+
+ if (hExeced && hExeced != INVALID_HANDLE_VALUE)
+ {
+ debug_printf ("Killing(%d) non-cygwin process, handle %p", n, hExeced);
+ TerminateProcess (hExeced, n);
+ ForceCloseHandle1 (hExeced, childhProc);
+ }
+
+ if (cleanup_pinfo)
+ myself->record_death (); // Locks pinfo mutex
+ else
+ sigproc_printf ("not cleanup_pinfo");
+
+ shared_terminate ();
+
+ sigproc_printf ("calling ExitProcess %d", n);
+ minimal_printf ("winpid %d, exit %d", GetCurrentProcessId (), n);
+ ExitProcess (n);
+}
+
+extern "C" void
+_exit (int n)
+{
+ do_exit ((DWORD) n & 0xffff);
+}
+
+extern "C" void
+__api_fatal (const char *fmt, ...)
+{
+ char buf[4096];
+ va_list ap;
+
+ va_start (ap, fmt);
+ __small_vsprintf (buf, fmt, ap);
+ va_end (ap);
+ small_printf ("%s\n", buf);
+
+ /* We are going down without mercy. Make sure we reset
+ our process_state. */
+ if (user_data != NULL)
+ {
+ sigproc_terminate ();
+ myself->record_death (FALSE);
+ }
+#ifdef DEBUGGING
+ (void) try_to_debug ();
+#endif
+ ExitProcess (1);
+}
+
+extern "C" {
+static void noload (char *s) __asm__ ("noload");
+static void __attribute__((unused))
+noload (char *s)
+{
+ api_fatal ("couldn't dynamically determine load address for '%s', %E", s);
+}
+
+__asm__ ("
+.globl cygwin_dll_func_load
+cygwin_dll_func_load:
+ movl (%esp),%eax # 'Return address' contains load info
+ addl $8,%eax # Address of name of function to load
+ pushl %eax # Second argument
+ movl -4(%eax),%eax # Address of Handle to DLL
+ pushl (%eax) # Handle to DLL
+ call _GetProcAddress@8# Load it
+ test %eax,%eax # Success?
+ jne gotit # Yes
+ popl %eax # No. Get back
+ addl $8,%eax # pointer to name
+ pushl %eax # and
+ call noload # issue an error
+gotit:
+ popl %ecx # Pointer to 'return address'
+ movb $0xe0,-1(%ecx) # Turn preceding call to a jmp *%eax
+ movl %eax,(%ecx) # Point dispatch to address loaded above
+ jmp *%eax
+");
+}
+
+LoadDLLinitfunc (user32)
+{
+ HANDLE h;
+
+ if ((h = LoadLibrary ("user32.dll")) != NULL)
+ user32_handle = h;
+ else if (!user32_handle)
+ api_fatal ("could not load user32.dll, %E");
+
+ return 0; /* Already done by another thread? */
+}
+
+LoadDLLinit (user32)
+LoadDLLfunc (CharToOemA, CharToOemA@8, user32)
+LoadDLLfunc (CreateWindowExA, CreateWindowExA@48, user32)
+LoadDLLfunc (DefWindowProcA, DefWindowProcA@16, user32)
+LoadDLLfunc (DispatchMessageA, DispatchMessageA@4, user32)
+LoadDLLfunc (FindWindowA, FindWindowA@8, user32)
+LoadDLLfunc (GetMessageA, GetMessageA@16, user32)
+LoadDLLfunc (GetProcessWindowStation, GetProcessWindowStation@0, user32)
+LoadDLLfunc (GetThreadDesktop, GetThreadDesktop@4, user32)
+LoadDLLfunc (GetUserObjectInformationA, GetUserObjectInformationA@20, user32)
+LoadDLLfunc (KillTimer, KillTimer@8, user32)
+LoadDLLfunc (MessageBoxA, MessageBoxA@16, user32)
+LoadDLLfunc (MsgWaitForMultipleObjects, MsgWaitForMultipleObjects@20, user32)
+LoadDLLfunc (OemToCharW, OemToCharW@8, user32)
+LoadDLLfunc (PeekMessageA, PeekMessageA@20, user32)
+LoadDLLfunc (PostMessageA, PostMessageA@16, user32)
+LoadDLLfunc (PostQuitMessage, PostQuitMessage@4, user32)
+LoadDLLfunc (RegisterClassA, RegisterClassA@4, user32)
+LoadDLLfunc (SendMessageA, SendMessageA@16, user32)
+LoadDLLfunc (SetTimer, SetTimer@16, user32)
+LoadDLLfunc (SetUserObjectSecurity, SetUserObjectSecurity@12, user32)