]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - hurd/hurdsig.c
Replace FSF snail mail address with URLs.
[thirdparty/glibc.git] / hurd / hurdsig.c
index 1f58d13436cab04943c77570837741036e689fb2..e1e0919fa00104dea141722ede2027cb61889b8b 100644 (file)
@@ -1,29 +1,36 @@
-/* Copyright (C) 1991, 92, 93, 94, 95, 96, 1996 Free Software Foundation, Inc.
-This file is part of the GNU C Library.
+/* Copyright (C) 1991,92,93,94,95,96,97,98,99,2000,2001,2002,2005,2008
+       Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
 
-The GNU C Library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Library General Public License as
-published by the Free Software Foundation; either version 2 of the
-License, or (at your option) any later version.
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
 
-The GNU C Library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Library General Public License for more details.
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
 
-You should have received a copy of the GNU Library General Public
-License along with the GNU C Library; see the file COPYING.LIB.  If
-not, write to the Free Software Foundation, Inc., 675 Mass Ave,
-Cambridge, MA 02139, USA.  */
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
 
-#include <stdlib.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <cthreads.h>          /* For `struct mutex'.  */
+#include <mach.h>
+#include <mach/thread_switch.h>
+
 #include <hurd.h>
+#include <hurd/id.h>
 #include <hurd/signal.h>
-#include <cthreads.h>          /* For `struct mutex'.  */
-#include <string.h>
+
 #include "hurdfault.h"
 #include "hurdmalloc.h"                /* XXX */
+#include "../locale/localeinfo.h"
 
 const char *_hurdsig_getenv (const char *);
 
@@ -39,6 +46,11 @@ thread_t _hurd_msgport_thread;
 /* Thread which receives task-global signals.  */
 thread_t _hurd_sigthread;
 
+/* These are set up by _hurdsig_init.  */
+unsigned long int __hurd_sigthread_stack_base;
+unsigned long int __hurd_sigthread_stack_end;
+unsigned long int *__hurd_sigthread_variables;
+
 /* Linked-list of per-thread signal state.  */
 struct hurd_sigstate *_hurd_sigstates;
 
@@ -78,8 +90,8 @@ _hurd_thread_sigstate (thread_t thread)
       __sigemptyset (&ss->blocked);
       __sigemptyset (&ss->pending);
       memset (&ss->sigaltstack, 0, sizeof (ss->sigaltstack));
-      ss->preempters = NULL;
-      ss->suspended = 0;
+      ss->preemptors = NULL;
+      ss->suspended = MACH_PORT_NULL;
       ss->intr_port = MACH_PORT_NULL;
       ss->context = NULL;
 
@@ -114,18 +126,18 @@ _hurd_thread_sigstate (thread_t thread)
 
 #include <hurd/fd.h>
 #include <hurd/crash.h>
+#include <hurd/resource.h>
 #include <hurd/paths.h>
 #include <setjmp.h>
 #include <fcntl.h>
 #include <sys/wait.h>
-#include "thread_state.h"
+#include <thread_state.h>
 #include <hurd/msg_server.h>
 #include <hurd/msg_reply.h>    /* For __msg_sig_post_reply.  */
 #include <hurd/interrupt.h>
 #include <assert.h>
 #include <unistd.h>
 
-int _hurd_core_limit;  /* XXX */
 
 /* Call the crash dump server to mummify us before we die.
    Returns nonzero if a core file was written.  */
@@ -137,6 +149,15 @@ write_corefile (int signo, const struct hurd_signal_detail *detail)
   file_t file, coredir;
   const char *name;
 
+  /* Don't bother locking since we just read the one word.  */
+  rlim_t corelimit = _hurd_rlimits[RLIMIT_CORE].rlim_cur;
+
+  if (corelimit == 0)
+    /* No core dumping, thank you very much.  Note that this makes
+       `ulimit -c 0' prevent crash-suspension too, which is probably
+       what the user wanted.  */
+    return 0;
+
   /* XXX RLIMIT_CORE:
      When we have a protocol to make the server return an error
      for RLIMIT_FSIZE, then tell the corefile fs server the RLIMIT_CORE
@@ -153,17 +174,16 @@ write_corefile (int signo, const struct hurd_signal_detail *detail)
     return 0;
 
   /* Get a port to the directory where the new core file will reside.  */
+  file = MACH_PORT_NULL;
   name = _hurdsig_getenv ("COREFILE");
   if (name == NULL)
     name = "core";
   coredir = __file_name_split (name, (char **) &name);
-  if (coredir == MACH_PORT_NULL)
-    return 0;
-  /* Create the new file, but don't link it into the directory yet.  */
-  if (err = __dir_mkfile (coredir, O_WRONLY|O_CREAT,
-                         0600 & ~_hurd_umask, /* XXX ? */
-                         &file))
-    return 0;
+  if (coredir != MACH_PORT_NULL)
+    /* Create the new file, but don't link it into the directory yet.  */
+    __dir_mkfile (coredir, O_WRONLY|O_CREAT,
+                 0600 & ~_hurd_umask, /* XXX ? */
+                 &file);
 
   /* Call the core dumping server to write the core file.  */
   err = __crash_dump_task (coreserver,
@@ -174,13 +194,14 @@ write_corefile (int signo, const struct hurd_signal_detail *detail)
                           _hurd_ports[INIT_PORT_CTTYID].port,
                           MACH_MSG_TYPE_COPY_SEND);
   __mach_port_deallocate (__mach_task_self (), coreserver);
-  if (! err)
+
+  if (! err && file != MACH_PORT_NULL)
     /* The core dump into FILE succeeded, so now link it into the
        directory.  */
-    err = __dir_link (file, coredir, name, 1);
+    err = __dir_link (coredir, file, name, 1);
   __mach_port_deallocate (__mach_task_self (), file);
   __mach_port_deallocate (__mach_task_self (), coredir);
-  return !err;
+  return !err && file != MACH_PORT_NULL;
 }
 
 
@@ -234,7 +255,7 @@ interrupted_reply_port_location (struct machine_thread_all_state *thread_state,
 }
 \f
 #include <hurd/sigpreempt.h>
-#include "intr-msg.h"
+#include <intr-msg.h>
 
 /* Timeout on interrupt_operation calls.  */
 mach_msg_timeout_t _hurdsig_interrupt_timeout = 1000;
@@ -421,9 +442,12 @@ abort_all_rpcs (int signo, struct machine_thread_all_state *state, int live)
       }
 }
 
-struct hurd_signal_preempter *_hurdsig_preempters;
+struct hurd_signal_preemptor *_hurdsig_preemptors = 0;
 sigset_t _hurdsig_preempted_set;
 
+/* XXX temporary to deal with spelling fix */
+weak_alias (_hurdsig_preemptors, _hurdsig_preempters)
+
 /* Mask of stop signals.  */
 #define STOPSIGS (sigmask (SIGTTIN) | sigmask (SIGTTOU) | \
                  sigmask (SIGSTOP) | sigmask (SIGTSTP))
@@ -439,7 +463,6 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
   error_t err;
   struct machine_thread_all_state thread_state;
   enum { stop, ignore, core, term, handle } act;
-  struct hurd_signal_preempter *pe;
   sighandler_t handler;
   sigset_t pending;
   int ss_suspended;
@@ -540,27 +563,45 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
 
   /* Check for a preempted signal.  Preempted signals can arrive during
      critical sections.  */
+  {
+    inline sighandler_t try_preemptor (struct hurd_signal_preemptor *pe)
+      {                                /* PE cannot be null.  */
+       do
+         {
+           if (HURD_PREEMPT_SIGNAL_P (pe, signo, detail->code))
+             {
+               if (pe->preemptor)
+                 {
+                   sighandler_t handler = (*pe->preemptor) (pe, ss,
+                                                            &signo, detail);
+                   if (handler != SIG_ERR)
+                     return handler;
+                 }
+               else
+                 return pe->handler;
+             }
+           pe = pe->next;
+         } while (pe != 0);
+       return SIG_ERR;
+      }
 
-  handler = SIG_ERR;
-  for (pe = ss->preempters; pe && handler == SIG_ERR; pe = pe->next)
-    if (HURD_PREEMPT_SIGNAL_P (pe, signo, detail->code))
-      handler = (*pe->preempter) (pe, ss, &signo, detail);
+    handler = ss->preemptors ? try_preemptor (ss->preemptors) : SIG_ERR;
 
-  if (handler == SIG_ERR && (__sigmask (signo) & _hurdsig_preempted_set))
-    {
-      __mutex_lock (&_hurd_siglock);
-      for (pe = _hurdsig_preempters; pe && handler == SIG_ERR; pe = pe->next)
-       if (HURD_PREEMPT_SIGNAL_P (pe, signo, detail->code))
-         handler = (*pe->preempter) (pe, ss, &signo, detail);
-      __mutex_unlock (&_hurd_siglock);
-    }
+    /* If no thread-specific preemptor, check for a global one.  */
+    if (handler == SIG_ERR && __sigismember (&_hurdsig_preempted_set, signo))
+      {
+       __mutex_lock (&_hurd_siglock);
+       handler = try_preemptor (_hurdsig_preemptors);
+       __mutex_unlock (&_hurd_siglock);
+      }
+  }
 
   ss_suspended = 0;
 
   if (handler == SIG_IGN)
     /* Ignore the signal altogether.  */
     act = ignore;
-  if (handler != SIG_ERR)
+  else if (handler != SIG_ERR)
     /* Run the preemption-provided handler.  */
     act = handle;
   else
@@ -648,7 +689,7 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
       if (__sigmask (signo) & STOPSIGS)
        /* Stop signals clear a pending SIGCONT even if they
           are handled or ignored (but not if preempted).  */
-       ss->pending &= ~sigmask (SIGCONT);
+       __sigdelset (&ss->pending, SIGCONT);
       else
        {
          if (signo == SIGCONT)
@@ -701,6 +742,11 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
       break;
 
     case ignore:
+      if (detail->exc)
+       /* Blocking or ignoring a machine exception is fatal.
+          Otherwise we could just spin on the faulting instruction.  */
+       goto fatal;
+
       /* Nobody cares about this signal.  If there was a call to resume
         above in SIGCONT processing and we've left a thread suspended,
         now's the time to set it going. */
@@ -717,6 +763,8 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
         Nothing to do but die; BSD gets SIGILL in this case.  */
       detail->code = signo;    /* XXX ? */
       signo = SIGILL;
+
+    fatal:
       act = core;
       /* FALLTHROUGH */
 
@@ -809,7 +857,7 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
                                      /* In a critical section, any RPC
                                         should be cancelled instead of
                                         restarted, regardless of
-                                        SA_RESTART, so the the entire
+                                        SA_RESTART, so the entire
                                         "atomic" operation can be aborted
                                         as a unit.  */
                                      crit ? 0 : signo, 1,
@@ -885,9 +933,20 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
        /* Backdoor extra argument to signal handler.  */
        scp->sc_error = detail->error;
 
-       /* Block SIGNO and requested signals while running the handler.  */
+       /* Block requested signals while running the handler.  */
        scp->sc_mask = ss->blocked;
-       ss->blocked |= __sigmask (signo) | ss->actions[signo].sa_mask;
+       __sigorset (&ss->blocked, &ss->blocked, &ss->actions[signo].sa_mask);
+
+       /* Also block SIGNO unless we're asked not to.  */
+       if (! (ss->actions[signo].sa_flags & (SA_RESETHAND | SA_NODEFER)))
+         __sigaddset (&ss->blocked, signo);
+
+       /* Reset to SIG_DFL if requested.  SIGILL and SIGTRAP cannot
+           be automatically reset when delivered; the system silently
+           enforces this restriction.  */
+       if (ss->actions[signo].sa_flags & SA_RESETHAND
+           && signo != SIGILL && signo != SIGTRAP)
+         ss->actions[signo].sa_handler = SIG_DFL;
 
        /* Start the thread running the handler (or possibly waiting for an
           RPC reply before running the handler).  */
@@ -973,16 +1032,11 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
            /* There is a sigsuspend waiting.  Tell it to wake up.  */
            error_t err;
            mach_msg_header_t msg;
-           err = __mach_port_insert_right (__mach_task_self (),
-                                           ss->suspended, ss->suspended,
-                                           MACH_MSG_TYPE_MAKE_SEND);
-           assert_perror (err);
-           msg.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_MOVE_SEND, 0);
+           msg.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_MAKE_SEND, 0);
            msg.msgh_remote_port = ss->suspended;
            msg.msgh_local_port = MACH_PORT_NULL;
            /* These values do not matter.  */
            msg.msgh_id = 8675309; /* Jenny, Jenny.  */
-           msg.msgh_seqno = 17; /* Random.  */
            ss->suspended = MACH_PORT_NULL;
            err = __mach_msg (&msg, MACH_SEND_MSG, sizeof msg, 0,
                              MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
@@ -1079,6 +1133,7 @@ signal_allowed (int signo, mach_port_t refport)
              }
            _hurd_port_free (&_hurd_dtable[d]->port, &ulink, port);
          }
+       __mutex_unlock (&_hurd_dtable_lock);
        /* If we found a lucky winner, we've set D to -1 in the loop.  */
        if (lucky)
          goto win;
@@ -1158,10 +1213,11 @@ extern void __mig_init (void *);
    thread.  */
 
 void
-_hurdsig_init (void)
+_hurdsig_init (const int *intarray, size_t intarraysize)
 {
   error_t err;
   vm_size_t stacksize;
+  struct hurd_sigstate *ss;
 
   __mutex_init (&_hurd_siglock);
 
@@ -1177,38 +1233,103 @@ _hurdsig_init (void)
                                  MACH_MSG_TYPE_MAKE_SEND);
   assert_perror (err);
 
+  /* Initialize the main thread's signal state.  */
+  ss = _hurd_self_sigstate ();
+
+  /* Copy inherited values from our parent (or pre-exec process state)
+     into the signal settings of the main thread.  */
+  if (intarraysize > INIT_SIGMASK)
+    ss->blocked = intarray[INIT_SIGMASK];
+  if (intarraysize > INIT_SIGPENDING)
+    ss->pending = intarray[INIT_SIGPENDING];
+  if (intarraysize > INIT_SIGIGN && intarray[INIT_SIGIGN] != 0)
+    {
+      int signo;
+      for (signo = 1; signo < NSIG; ++signo)
+       if (intarray[INIT_SIGIGN] & __sigmask(signo))
+         ss->actions[signo].sa_handler = SIG_IGN;
+    }
+
   /* Set the default thread to receive task-global signals
      to this one, the main (first) user thread.  */
-  _hurd_sigthread = __mach_thread_self ();
+  _hurd_sigthread = ss->thread;
 
   /* Start the signal thread listening on the message port.  */
 
-  err = __thread_create (__mach_task_self (), &_hurd_msgport_thread);
-  assert_perror (err);
-
-  stacksize = __vm_page_size * 4; /* Small stack for signal thread.  */
-  err = __mach_setup_thread (__mach_task_self (), _hurd_msgport_thread,
-                            _hurd_msgport_receive,
-                            (vm_address_t *) &__hurd_sigthread_stack_base,
-                            &stacksize);
-  assert_perror (err);
-
-  __hurd_sigthread_stack_end = __hurd_sigthread_stack_base + stacksize;
-  __hurd_sigthread_variables =
-    malloc (__hurd_threadvar_max * sizeof (unsigned long int));
-  if (__hurd_sigthread_variables == NULL)
-    __libc_fatal ("hurd: Can't allocate thread variables for signal thread\n");
+  if (__hurd_threadvar_stack_mask == 0)
+    {
+      err = __thread_create (__mach_task_self (), &_hurd_msgport_thread);
+      assert_perror (err);
 
-  /* Reinitialize the MiG support routines so they will use a per-thread
-     variable for the cached reply port.  */
-  __mig_init ((void *) __hurd_sigthread_stack_base);
+      stacksize = __vm_page_size * 8; /* Small stack for signal thread.  */
+      err = __mach_setup_thread (__mach_task_self (), _hurd_msgport_thread,
+                                _hurd_msgport_receive,
+                                (vm_address_t *) &__hurd_sigthread_stack_base,
+                                &stacksize);
+      assert_perror (err);
 
-  err = __thread_resume (_hurd_msgport_thread);
-  assert_perror (err);
+      __hurd_sigthread_stack_end = __hurd_sigthread_stack_base + stacksize;
+      __hurd_sigthread_variables =
+       malloc (__hurd_threadvar_max * sizeof (unsigned long int));
+      if (__hurd_sigthread_variables == NULL)
+       __libc_fatal ("hurd: Can't allocate threadvars for signal thread\n");
+      memset (__hurd_sigthread_variables, 0,
+             __hurd_threadvar_max * sizeof (unsigned long int));
+      __hurd_sigthread_variables[_HURD_THREADVAR_LOCALE]
+       = (unsigned long int) &_nl_global_locale;
+
+      /* Reinitialize the MiG support routines so they will use a per-thread
+        variable for the cached reply port.  */
+      __mig_init ((void *) __hurd_sigthread_stack_base);
+
+      err = __thread_resume (_hurd_msgport_thread);
+      assert_perror (err);
+    }
+  else
+    {
+      /* When cthreads is being used, we need to make the signal thread a
+         proper cthread.  Otherwise it cannot use mutex_lock et al, which
+         will be the cthreads versions.  Various of the message port RPC
+         handlers need to take locks, so we need to be able to call into
+         cthreads code and meet its assumptions about how our thread and
+         its stack are arranged.  Since cthreads puts it there anyway,
+         we'll let the signal thread's per-thread variables be found as for
+         any normal cthread, and just leave the magic __hurd_sigthread_*
+         values all zero so they'll be ignored.  */
+#pragma weak cthread_fork
+#pragma weak cthread_detach
+      cthread_detach (cthread_fork ((cthread_fn_t) &_hurd_msgport_receive, 0));
+
+      /* XXX We need the thread port for the signal thread further on
+         in this thread (see hurdfault.c:_hurdsigfault_init).
+         Therefore we block until _hurd_msgport_thread is initialized
+         by the newly created thread.  This really shouldn't be
+         necessary; we should be able to fetch the thread port for a
+         cthread from here.  */
+      while (_hurd_msgport_thread == 0)
+       __swtch_pri (0);
+    }
 
   /* Receive exceptions on the signal port.  */
+#ifdef TASK_EXCEPTION_PORT
   __task_set_special_port (__mach_task_self (),
                           TASK_EXCEPTION_PORT, _hurd_msgport);
+#elif defined (EXC_MASK_ALL)
+  __task_set_exception_ports (__mach_task_self (),
+                             EXC_MASK_ALL & ~(EXC_MASK_SYSCALL
+                                              | EXC_MASK_MACH_SYSCALL
+                                              | EXC_MASK_RPC_ALERT),
+                             _hurd_msgport,
+                             EXCEPTION_DEFAULT, MACHINE_THREAD_STATE);
+#else
+# error task_set_exception_port?
+#endif
+
+  /* Sanity check.  Any pending, unblocked signals should have been
+     taken by our predecessor incarnation (i.e. parent or pre-exec state)
+     before packing up our init ints.  This assert is last (not above)
+     so that signal handling is all set up to handle the abort.  */
+  assert ((ss->pending &~ ss->blocked) == 0);
 }
 \f                              /* XXXX */
 /* Reauthenticate with the proc server.  */
@@ -1229,6 +1350,16 @@ reauth_proc (mach_port_t new)
     __mach_port_deallocate (__mach_task_self (), ignore);
   __mach_port_destroy (__mach_task_self (), ref);
 
+  /* Set the owner of the process here too. */
+  mutex_lock (&_hurd_id.lock);
+  if (!_hurd_check_ids ())
+    HURD_PORT_USE (&_hurd_ports[INIT_PORT_PROC],
+                  __proc_setowner (port,
+                                   (_hurd_id.gen.nuids
+                                    ? _hurd_id.gen.uids[0] : 0),
+                                   !_hurd_id.gen.nuids));
+  mutex_unlock (&_hurd_id.lock);
+
   (void) &reauth_proc;         /* Silence compiler warning.  */
 }
 text_set_element (_hurd_reauth_hook, reauth_proc);
@@ -1239,6 +1370,9 @@ text_set_element (_hurd_reauth_hook, reauth_proc);
 const char *
 _hurdsig_getenv (const char *variable)
 {
+  if (__libc_enable_secure)
+    return NULL;
+
   if (_hurdsig_catch_memory_fault (__environ))
     /* We bombed in getenv.  */
     return NULL;
@@ -1250,22 +1384,21 @@ _hurdsig_getenv (const char *variable)
       while (*ep)
        {
          const char *p = *ep;
-         _hurdsig_fault_preempter.first = (long int) p;
-         _hurdsig_fault_preempter.last = VM_MAX_ADDRESS;
+         _hurdsig_fault_preemptor.first = (long int) p;
+         _hurdsig_fault_preemptor.last = VM_MAX_ADDRESS;
          if (! strncmp (p, variable, len) && p[len] == '=')
            {
-             char *value;
              size_t valuelen;
              p += len + 1;
              valuelen = strlen (p);
-             _hurdsig_fault_preempter.last = (long int) (p + valuelen);
+             _hurdsig_fault_preemptor.last = (long int) (p + valuelen);
              value = malloc (++valuelen);
              if (value)
                memcpy (value, p, valuelen);
              break;
            }
-         _hurdsig_fault_preempter.first = (long int) ++ep;
-         _hurdsig_fault_preempter.last = (long int) (ep + 1);
+         _hurdsig_fault_preemptor.first = (long int) ++ep;
+         _hurdsig_fault_preemptor.last = (long int) (ep + 1);
        }
       _hurdsig_end_catch_fault ();
       return value;