OSDN Git Service

* cygwin.din (ualarm): New export.
[pf3gnuchains/sourceware.git] / winsup / cygwin / dcrt0.cc
index 8682685..84754b2 100644 (file)
@@ -1,6 +1,6 @@
 /* dcrt0.cc -- essentially the main() for the Cygwin dll
 
-   Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions.
+   Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
 
 This file is part of Cygwin.
 
@@ -15,28 +15,30 @@ details. */
 #include "exceptions.h"
 #include <ctype.h>
 #include <limits.h>
+#include <wingdi.h>
+#include <winuser.h>
+#include <errno.h>
 #include "sync.h"
 #include "sigproc.h"
 #include "pinfo.h"
-#include "cygheap.h"
 #include "heap.h"
 #include "cygerrno.h"
-#include "fhandler.h"
-#include "child_info.h"
 #define NEED_VFORK
-#include "perthread.h"
+#include "perprocess.h"
+#include "security.h"
+#include "fhandler.h"
 #include "path.h"
 #include "dtable.h"
+#include "cygheap.h"
+#include "child_info.h"
+#include "perthread.h"
 #include "shared_info.h"
 #include "cygwin_version.h"
-#include "perprocess.h"
 #include "dll_init.h"
-#include "host_dependent.h"
-#include "security.h"
 
 #define MAX_AT_FILE_LEVEL 10
 
-#define PREMAIN_LEN (sizeof(user_data->premain) / sizeof (user_data->premain[0]))
+#define PREMAIN_LEN (sizeof (user_data->premain) / sizeof (user_data->premain[0]))
 
 HANDLE NO_COPY hMainProc = NULL;
 HANDLE NO_COPY hMainThread = NULL;
@@ -52,12 +54,12 @@ per_thread NO_COPY *threadstuff[] = {&waitq_storage,
                                     &signal_dispatch_storage,
                                     NULL};
 
-BOOL display_title = FALSE;
-BOOL strip_title_path = FALSE;
+BOOL display_title;
+BOOL strip_title_path;
 BOOL allow_glob = TRUE;
+codepage_type current_codepage = ansi_cp;
 
-HANDLE NO_COPY parent_alive = NULL;
-int cygwin_finished_initializing = 0;
+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.
@@ -65,10 +67,13 @@ int cygwin_finished_initializing = 0;
    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;
+unsigned NO_COPY int signal_shift_subtract = 1;
 
 ResourceLocks _reslock NO_COPY;
-MTinterface _mtinterf NO_COPY;
+MTinterface _mtinterf;
+
+bool NO_COPY _cygwin_testing;
+unsigned NO_COPY _cygwin_testing_magic;
 
 extern "C"
 {
@@ -82,8 +87,8 @@ extern "C"
   char **__cygwin_environ;
   char ***main_environ;
   /* __progname used in getopt error message */
-  char *__progname = NULL;
-  struct _reent reent_data;
+  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,
@@ -97,19 +102,23 @@ extern "C"
    /* calloc */ export_calloc,
    /* premain */ {NULL, NULL, NULL, NULL},
    /* run_ctors_p */ 0,
-    /* unused */ { 0, 0, 0},
-   /* heapbase */ NULL, /* heapptr */ NULL, /* heaptop */ NULL,
-   /* unused1 */ 0, /* forkee */ 0, /* hmodule */ NULL,
+   /* 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 = FALSE;
+  bool ignore_case_with_glob;
+  int __declspec (dllexport) _check_for_executable = TRUE;
+#ifdef DEBUGGING
+  int pinger;
+#endif
 };
 
-char *old_title = NULL;
+char *old_title;
 char title_buf[TITLESIZE + 1];
 
 static void
@@ -147,91 +156,6 @@ do_global_ctors (void (**in_pfunc)(), int force)
     atexit (do_global_dtors);
 }
 
-/* remember the type of Win32 OS being run for future use. */
-os_type NO_COPY os_being_run;
-char NO_COPY osname[40];
-
-/* 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;
-  const char *os;
-
-  memset (&os_version_info, 0, sizeof 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;
-       os = "NT";
-       break;
-      case VER_PLATFORM_WIN32_WINDOWS:
-       if (os_version_info.dwMinorVersion == 0)
-         {
-           os_being_run = win95;
-           os = "95";
-         }
-       else if (os_version_info.dwMinorVersion < 90)
-         {
-           os_being_run = win98;
-           os = "98";
-         }
-       else /* os_version_info.dwMinorVersion == 90 */
-         {
-           os_being_run = winME;
-           os = "ME";
-         }
-       break;
-      default:
-       os_being_run = unknown;
-       os = "??";
-       break;
-    }
-  __small_sprintf (osname, "%s-%d.%d", os, os_version_info.dwMajorVersion,
-                  os_version_info.dwMinorVersion);
-}
-
-host_dependent_constants NO_COPY host_dependent;
-
-/* Constructor for host_dependent_constants.  */
-
-void
-host_dependent_constants::init ()
-{
-  extern DWORD chunksize;
-  /* 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 winME:
-    case win98:
-    case win95:
-    case win32s:
-      win32_upper = 0x00000000;
-      shared = FILE_SHARE_READ | FILE_SHARE_WRITE;
-      chunksize = 32 * 1024 * 1024;
-      break;
-
-    default:
-      api_fatal ("unrecognized system type");
-    }
-}
-
 /*
  * Replaces -@file in the command line with the contents of the file.
  * There may be multiple -@file's in a single command line
@@ -354,7 +278,7 @@ globify (char *word, char **&argv, int &argc, int &argvlen)
   int n = 0;
   char *p, *s;
   int dos_spec = isdrive (word);
-  if (!dos_spec && isquote(*word) && word[1] && word[2])
+  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
@@ -533,6 +457,8 @@ static NO_COPY STARTUPINFO si;
 child_info_fork NO_COPY *child_proc_info = NULL;
 static MEMORY_BASIC_INFORMATION sm;
 
+#define CYGWIN_GUARD ((wincap.has_page_guard ()) ? PAGE_GUARD : PAGE_NOACCESS)
+
 // __inline__ void
 extern void
 alloc_stack_hard_way (child_info_fork *ci, volatile char *b)
@@ -572,7 +498,7 @@ alloc_stack_hard_way (child_info_fork *ci, volatile char *b)
     {
       m.BaseAddress = (LPVOID)((DWORD)m.BaseAddress - 1);
       if (!VirtualAlloc ((LPVOID) m.BaseAddress, 1, MEM_COMMIT,
-                        PAGE_EXECUTE_READWRITE|PAGE_GUARD))
+                        PAGE_EXECUTE_READWRITE|CYGWIN_GUARD))
        api_fatal ("fork: couldn't allocate new stack guard page %p, %E",
                   m.BaseAddress);
     }
@@ -591,25 +517,21 @@ alloc_stack (child_info_fork *ci)
      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 (!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;
-    }
+  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 = 0;
-char _declspec(dllexport) **__argv = NULL;
+int _declspec(dllexport) __argc;
+char _declspec(dllexport) **__argv;
+vfork_save NO_COPY *main_vfork = NULL;
 
 void
 sigthread::init (const char *s)
@@ -630,15 +552,13 @@ dll_crt0_1 ()
   /* FIXME: Verify forked children get their exception handler set up ok. */
   exception_list cygwin_except_entry;
 
-  /* Initialize SIGSEGV handling, etc...  Because the exception handler
-     references data in the shared area, this must be done after
-     shared_init. */
+  /* Initialize SIGSEGV handling, etc. */
   init_exceptions (&cygwin_except_entry);
 
   do_global_ctors (&__CTOR_LIST__, 1);
 
   /* Set the os_being_run global. */
-  set_os_type ();
+  wincap.init ();
   check_sanity_and_sync (user_data);
 
   /* Nasty static stuff needed by newlib -- point to a local copy of
@@ -654,7 +574,7 @@ dll_crt0_1 ()
 
   threadname_init ();
   debug_init ();
-  cygheap_init ();     /* Initialize cygheap muto */
+  (void) getpagesize ();       /* initialize page size constant */
 
   regthread ("main", GetCurrentThreadId ());
   mainthread.init ("mainthread"); // For use in determining if signals
@@ -665,43 +585,35 @@ dll_crt0_1 ()
 
   if (child_proc_info)
     {
-      cygheap = child_proc_info->cygheap;
-      cygheap_max = child_proc_info->cygheap_max;
-      switch (child_proc_info->type)
+      switch (child_proc_info->type - _cygwin_testing_magic)
        {
-         case PROC_FORK:
-         case PROC_FORK1:
-           cygheap_fixup_in_child (child_proc_info->parent, 0);
+         case _PROC_FORK:
+           cygheap_fixup_in_child (child_proc_info, 0);
            alloc_stack (fork_info);
            set_myself (mypid);
-           user_data->heaptop = child_proc_info->heaptop;
-           user_data->heapbase = child_proc_info->heapbase;
-           user_data->heapptr = child_proc_info->heapptr;
            ProtectHandle (child_proc_info->forker_finished);
            break;
-         case PROC_SPAWN:
-           CloseHandle (spawn_info->hexec_proc);
+         case _PROC_SPAWN:
+           if (spawn_info->hexec_proc)
+             CloseHandle (spawn_info->hexec_proc);
            goto around;
-         case PROC_EXEC:
+         case _PROC_EXEC:
            hexec_proc = spawn_info->hexec_proc;
          around:
            HANDLE h;
-           cygheap_fixup_in_child (spawn_info->parent, 1);
+           cygheap_fixup_in_child (spawn_info, 1);
            if (!spawn_info->moreinfo->myself_pinfo ||
                !DuplicateHandle (hMainProc, spawn_info->moreinfo->myself_pinfo,
                                  hMainProc, &h, 0, 0,
                                  DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
              h = NULL;
            set_myself (mypid, h);
+           myself->uid = spawn_info->moreinfo->uid;
            __argc = spawn_info->moreinfo->argc;
            __argv = spawn_info->moreinfo->argv;
            envp = spawn_info->moreinfo->envp;
            envc = spawn_info->moreinfo->envc;
-           cygcwd.fixup_after_exec (spawn_info->moreinfo->cwd_win32,
-                                    spawn_info->moreinfo->cwd_posix,
-                                    spawn_info->moreinfo->cwd_hash);
-           fdtab.fixup_after_exec (spawn_info->parent, spawn_info->moreinfo->nfds,
-                                   spawn_info->moreinfo->fds);
+           cygheap->fdtab.fixup_after_exec (spawn_info->parent);
            signal_fixup_after_exec (child_proc_info->type == PROC_SPAWN);
            CloseHandle (spawn_info->parent);
            if (spawn_info->moreinfo->old_title)
@@ -709,35 +621,30 @@ dll_crt0_1 ()
                old_title = strcpy (title_buf, spawn_info->moreinfo->old_title);
                cfree (spawn_info->moreinfo->old_title);
              }
-           ProtectHandle (child_proc_info->subproc_ready);
-           myself->uid = spawn_info->moreinfo->uid;
+           if (child_proc_info->subproc_ready)
+             ProtectHandle (child_proc_info->subproc_ready);
            if (myself->uid == USHRT_MAX)
-             myself->use_psid = 0;
+             cygheap->user.set_sid (NULL);
            break;
        }
     }
   ProtectHandle (hMainProc);
   ProtectHandle (hMainThread);
 
-  /* 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 ();
+     or attach to shared data structures if it's already running. */
+  memory_init ();
+  cygheap->fdtab.vfork_child_fixup ();
 
   (void) SetErrorMode (SEM_FAILCRITICALERRORS);
 
-  /* Initialize the heap. */
-  heap_init ();
-
   /* Initialize events. */
   events_init ();
 
-  cygcwd.init ();
+  cygheap->cwd.init ();
+  main_vfork = vfork_storage.create ();
 
   cygbench ("pre-forkee");
-
   if (user_data->forkee)
     {
       /* If we've played with the stack, stacksize != 0.  That means that
@@ -756,13 +663,20 @@ dll_crt0_1 ()
       longjmp (fork_info->jmp, fork_info->cygpid);
     }
 
+#ifdef DEBUGGING
+  {
+  extern void fork_init ();
+  fork_init ();
+  }
+#endif
+
   /* Initialize our process table entry. */
   pinfo_init (envp, envc);
 
   if (!old_title && GetConsoleTitle (title_buf, TITLESIZE))
       old_title = title_buf;
 
-  /* Allocate fdtab */
+  /* Allocate cygheap->fdtab */
   dtable_init ();
 
 /* Initialize uid, gid. */
@@ -774,14 +688,14 @@ dll_crt0_1 ()
   /* Connect to tty. */
   tty_init ();
 
-  /* Set up standard fds in file descriptor table. */
-  stdio_init ();
-
   if (!__argc)
     {
       char *line = GetCommandLineA ();
       line = strcpy ((char *) alloca (strlen (line) + 1), line);
 
+      if (current_codepage == oem_cp)
+       CharToOemA (line, line);
+
       /* Scan the command line and build argv.  Expand wildcards if not
         called from another cygwin process. */
       build_argv (line, __argv, __argc,
@@ -802,7 +716,10 @@ dll_crt0_1 ()
 
   if (user_data->premain[0])
     for (unsigned int i = 0; i < PREMAIN_LEN / 2; i++)
-      user_data->premain[i] (__argc, __argv);
+      user_data->premain[i] (__argc, __argv, user_data);
+
+  /* Set up standard fds in file descriptor table. */
+  stdio_init ();
 
   /* Set up __progname for getopt error call. */
   __progname = __argv[0];
@@ -826,7 +743,7 @@ dll_crt0_1 ()
   /* Execute any specified "premain" functions */
   if (user_data->premain[PREMAIN_LEN / 2])
     for (unsigned int i = PREMAIN_LEN / 2; i < PREMAIN_LEN; i++)
-      user_data->premain[i] (__argc, __argv);
+      user_data->premain[i] (__argc, __argv, user_data);
 
   debug_printf ("user_data->main %p", user_data->main);
 
@@ -852,6 +769,31 @@ dll_crt0_1 ()
     exit (user_data->main (__argc, __argv, *user_data->envptr));
 }
 
+void
+initial_env ()
+{
+  char buf[MAX_PATH + 1];
+#ifdef DEBUGGING
+  if (GetEnvironmentVariable ("CYGWIN_SLEEP", buf, sizeof (buf) - 1))
+    {
+      console_printf ("Sleeping %d, pid %u\n", atoi (buf), GetCurrentProcessId ());
+      Sleep (atoi (buf));
+    }
+#endif
+
+  if (GetEnvironmentVariable ("CYGWIN_TESTING", buf, sizeof (buf) - 1))
+    {
+      _cygwin_testing = 1;
+      DWORD len;
+      if ((len = GetModuleFileName (cygwin_hmodule, buf, MAX_PATH))
+         && len > sizeof ("new-cygwin1.dll")
+         && strcasematch (buf + len - sizeof ("new-cygwin1.dll"),
+                          "\\new-cygwin1.dll"))
+       _cygwin_testing_magic = 0x10;
+    }
+}
+
+
 /* Wrap the real one, otherwise gdb gets confused about
    two symbols with the same name, but different addresses.
 
@@ -861,25 +803,15 @@ dll_crt0_1 ()
 extern "C" void __stdcall
 _dll_crt0 ()
 {
+  DECLARE_TLS_STORAGE;
+  initial_env ();
   char zeros[sizeof (fork_info->zero)] = {0};
 #ifdef DEBUGGING
   strace.microseconds ();
 #endif
 
-  /* Set the os_being_run global. */
-  set_os_type ();
-
-#ifdef DEBUGGING
-  char buf[80];
-  if (GetEnvironmentVariable ("CYGWIN_SLEEP", buf, sizeof (buf)))
-    {
-      small_printf ("Sleeping %d, pid %u\n", atoi (buf), GetCurrentProcessId ());
-      Sleep (atoi(buf));
-    }
-#endif
-
   main_environ = user_data->envptr;
-  user_data->heapbase = user_data->heapptr = user_data->heaptop = NULL;
+  *main_environ = NULL;
 
   set_console_handler ();
   if (!DuplicateHandle (GetCurrentProcess (), GetCurrentProcess (),
@@ -888,40 +820,32 @@ _dll_crt0 ()
     hMainProc = GetCurrentProcess ();
 
   DuplicateHandle (hMainProc, GetCurrentThread (), hMainProc,
-                  &hMainThread, 0, FALSE, DUPLICATE_SAME_ACCESS);
+                  &hMainThread, 0, false, DUPLICATE_SAME_ACCESS);
 
   GetStartupInfo (&si);
   if (si.cbReserved2 >= EXEC_MAGIC_SIZE &&
       memcmp (fork_info->zero, zeros, sizeof (zeros)) == 0)
     {
-      switch (fork_info->type)
+      switch (fork_info->type - _cygwin_testing_magic)
        {
-         case PROC_FORK:
-         case PROC_FORK1:
+         case _PROC_FORK:
            user_data->forkee = fork_info->cygpid;
-         case PROC_SPAWN:
-           CloseHandle (fork_info->pppid_handle);
-         case PROC_EXEC:
+         case _PROC_SPAWN:
+           if (fork_info->pppid_handle)
+             CloseHandle (fork_info->pppid_handle);
+         case _PROC_EXEC:
            {
              child_proc_info = fork_info;
+             cygwin_mount_h = child_proc_info->mount_h;
              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)
-               parent_alive = NULL;
-             else if (!DuplicateHandle (hMainProc, child_proc_info->parent_alive,
-                                       hMainProc, &parent_alive, 0, 0,
-                                       DUPLICATE_SAME_ACCESS
-                                       | DUPLICATE_CLOSE_SOURCE))
-                 system_printf ("parent_alive DuplicateHandle failed, %E");
-
              break;
            }
          default:
-           if ((fork_info->type & PROC_MAGIC_MASK) == PROC_MAGIC_GENERIC)
-             api_fatal ("conflicting versions of cygwin1.dll detected.  Use only the most recent version.\n");
+           if (_cygwin_testing)
+             fork_info = NULL;
+           else if ((fork_info->type & PROC_MAGIC_MASK) == PROC_MAGIC_GENERIC)
+             multiple_cygwin_die ();
+           break;
        }
     }
   dll_crt0_1 ();
@@ -930,6 +854,7 @@ _dll_crt0 ()
 void
 dll_crt0 (per_process *uptr)
 {
+  DECLARE_TLS_STORAGE;
   /* Set the local copy of the pointer into the user space. */
   if (uptr && uptr != user_data)
     {
@@ -945,7 +870,6 @@ cygwin_dll_init ()
 {
   static char **envp;
   static int _fmode;
-  user_data->heapbase = user_data->heapptr = user_data->heaptop = NULL;
 
   if (!DuplicateHandle (GetCurrentProcess (), GetCurrentProcess (),
                       GetCurrentProcess (), &hMainProc, 0, FALSE,
@@ -1033,7 +957,7 @@ do_exit (int status)
        }
 
       /* Kill the foreground process group on session leader exit */
-      if (getpgrp () > 0 && myself->pid == myself->sid && tty_attached (myself))
+      if (getpgrp () > 0 && myself->pid == myself->sid && real_tty_attached (myself))
        {
          tty *tp = cygwin_shared->tty[myself->ctty];
          sigproc_printf ("%d == sid %d, send SIGHUP to children",
@@ -1095,6 +1019,17 @@ __api_fatal (const char *fmt, ...)
   myself->exit (1);
 }
 
+void
+multiple_cygwin_die ()
+{
+  api_fatal ("\
+You have multiple copies of cygwin1.dll on your system.\n\
+Search for cygwin1.dll using the Windows Start->Find/Search facility\n\
+and delete all but the most recent version.  This will probably be\n\
+the one that resides in x:\\cygwin\\bin, where 'x' is the drive on which\n\
+you have installed the cygwin distribution.\n");
+}
+
 #ifdef DEBUGGING
 void __stdcall
 cygbench (const char *s)