📄 dcrt0.cc
字号:
/* dcrt0.cc -- essentially the main() for the Cygwin dll Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.This file is part of Cygwin.This software is a copyrighted work licensed under the terms of theCygwin license. Please consult the file "CYGWIN_LICENSE" fordetails. */#include "winsup.h"#include <unistd.h>#include <stdlib.h>#include "glob.h"#include "exceptions.h"#include <ctype.h>#include <limits.h>#include <wingdi.h>#include <winuser.h>#include <errno.h>#include "sigproc.h"#include "pinfo.h"#include "cygerrno.h"#define NEED_VFORK#include "perprocess.h"#include "security.h"#include "fhandler.h"#include "path.h"#include "dtable.h"#include "cygheap.h"#include "child_info_magic.h"#include "perthread.h"#include "shared_info.h"#include "cygwin_version.h"#include "dll_init.h"#include "cygthread.h"#define MAX_AT_FILE_LEVEL 10#define PREMAIN_LEN (sizeof (user_data->premain) / sizeof (user_data->premain[0]))HANDLE NO_COPY hMainProc;HANDLE NO_COPY hMainThread;sigthread NO_COPY mainthread; // ID of the main threadper_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;BOOL strip_title_path;BOOL allow_glob = TRUE;codepage_type current_codepage = ansi_cp;int cygwin_finished_initializing;/* 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 NO_COPY int signal_shift_subtract = 1;ResourceLocks _reslock NO_COPY;MTinterface _mtinterf;bool NO_COPY _cygwin_testing;unsigned NO_COPY _cygwin_testing_magic;char NO_COPY almost_null[1];extern "C"{ /* This is an exported copy of environ which can be used by DLLs which use cygwin.dll. */ char **__cygwin_environ; char ***main_environ; /* __progname used in getopt error message */ char *__progname; struct _reent reent_data = _REENT_INIT(reent_data); struct per_process __cygwin_user_data = {/* initial_sp */ 0, /* magic_biscuit */ 0, /* dll_major */ CYGWIN_VERSION_DLL_MAJOR, /* dll_major */ CYGWIN_VERSION_DLL_MINOR, /* impure_ptr_ptr */ NULL, /* envptr */ NULL, /* malloc */ malloc, /* free */ free, /* realloc */ realloc, /* fmode_ptr */ NULL, /* main */ NULL, /* ctors */ NULL, /* dtors */ NULL, /* data_start */ NULL, /* data_end */ NULL, /* bss_start */ NULL, /* bss_end */ NULL, /* calloc */ calloc, /* premain */ {NULL, NULL, NULL, NULL}, /* run_ctors_p */ 0, /* unused */ {0, 0, 0, 0, 0, 0, 0}, /* forkee */ 0, /* hmodule */ NULL, /* api_major */ CYGWIN_VERSION_API_MAJOR, /* api_minor */ CYGWIN_VERSION_API_MINOR, /* unused2 */ {0, 0, 0, 0, 0}, /* resourcelocks */ &_reslock, /* threadinterface */ &_mtinterf, /* impure_ptr */ &reent_data, }; bool ignore_case_with_glob; int __declspec (dllexport) _check_for_executable = TRUE;#ifdef DEBUGGING int pinger;#endif};char *old_title;char title_buf[TITLESIZE + 1];static voiddo_global_dtors (void){ if (user_data->dtors) { void (**pfunc)() = user_data->dtors; while (*++pfunc) (*pfunc) (); }}static void __stdcalldo_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->magic_biscuit == SIZEOF_PER_PROCESS) atexit (do_global_dtors);}/* * 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 __stdcallinsert_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 intisquote (char c){ char ch = c; return ch == '"' || ch == '\'';}/* Step over a run of characters delimited by quotes */static /*__inline*/ char *quoted (char *cmd, int winshell){ char *p; char quote = *cmd; if (!winshell) { char *p; strcpy (cmd, cmd + 1); if ((p = strchr (cmd, quote)) != NULL) strcpy (p, p + 1); else p = strchr (cmd, '\0'); return p; } const char *s = quote == '\'' ? "'" : "\\\""; /* This must have been run from a Windows shell, so preserve quotes for globify to play with later. */ while (*cmd && *++cmd) if ((p = strpbrk (cmd, s)) == NULL) { cmd = strchr (cmd, '\0'); // no closing quote break; } else if (*p == '\\') cmd = ++p; else if (quote == '"' && p[1] == '"') { *p = '\\'; cmd = ++p; // a quoted quote } else { cmd = p + 1; // point to after end 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 __stdcallglobify (char *word, char **&argv, int &argc, int &argvlen){ if (*word != '~' && strpbrk (word, "?*[\"\'(){}") == NULL) return 0; int n = 0; char *p, *s; int dos_spec = isdrive (word); if (!dos_spec && isquote (*word) && word[1] && word[2]) dos_spec = isdrive (word + 1); /* 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 (dos_spec || *s != '\\') /* nothing */; else if (s[1] == quote || s[1] == '\\') 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++, *gv); *av++ = *gv++; } /* Clean up after glob. */ free (gl.gl_pathv); return 1;}/* Build argv, argc from string passed from Windows. */static void __stdcallbuild_argv (char *cmd, char **&argv, int &argc, int winshell){ int argvlen = 0; 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 (cmd, winshell && argc > 0); } 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)) 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'", argc, word); argv[argc++] = word; } } argv[argc] = NULL; debug_printf ("argc %d", argc);}/* sanity and sync check */void __stdcallcheck_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;}child_info NO_COPY *child_proc_info = NULL;static MEMORY_BASIC_INFORMATION NO_COPY sm;#define CYGWIN_GUARD ((wincap.has_page_guard ()) ? \ PAGE_EXECUTE_READWRITE|PAGE_GUARD : PAGE_NOACCESS)// __inline__ voidextern voidalloc_stack_hard_way (child_info_fork *ci, volatile char *b){ void *new_stack_pointer; MEMORY_BASIC_INFORMATION m; void *newbase; int newlen; LPBYTE curbot = (LPBYTE) sm.BaseAddress + sm.RegionSize; bool noguard; if (ci->stacktop > (LPBYTE) sm.AllocationBase && ci->stacktop < curbot) { newbase = curbot; newlen = (LPBYTE) ci->stackbottom - (LPBYTE) curbot; noguard = 1; } else { newbase = ci->stacktop; newlen = (DWORD) ci->stackbottom - (DWORD) ci->stacktop; noguard = 0; } if (!VirtualAlloc (newbase, newlen, 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"); if (!noguard) { m.BaseAddress = (LPVOID)((DWORD)m.BaseAddress - 1); if (!VirtualAlloc ((LPVOID) m.BaseAddress, 1, MEM_COMMIT, CYGWIN_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 */static voidalloc_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 (!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;}static NO_COPY int mypid = 0;int _declspec(dllexport) __argc;char _declspec(dllexport) **__argv;vfork_save NO_COPY *main_vfork = NULL;voidsigthread::init (const char *s){ InitializeCriticalSection (&lock); id = GetCurrentThreadId ();}/* 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 voiddll_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; /* Initialize SIGSEGV handling, etc. */ init_exceptions (&cygwin_except_entry); /* Set the os_being_run global. */ wincap.init (); check_sanity_and_sync (user_data); do_global_ctors (&__CTOR_LIST__, 1); /* 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). */ _impure_ptr = &reent_data; user_data->resourcelocks->Init (); user_data->threadinterface->Init (user_data->forkee);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -