2002-01-02 Roland McGrath <roland@frob.com>
[kopensolaris-gnu/glibc.git] / hurd / hurdmsg.c
index 86da657..ffcce61 100644 (file)
-/* Copyright (C) 1992, 1994 Free Software Foundation, Inc.
-This file is part of the GNU C Library.
+/* Copyright (C) 1992, 1994, 1995, 1996, 1997 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
 
 #include <hurd.h>
-#include "hurd/msg_server.h"
+#include <hurd/msg_server.h>
+#include <hurd/fd.h>
+#include <unistd.h>
+#include <limits.h>
+#include <string.h>
+#include <argz.h>
 
-error_t
-__get_init_port (mach_port_t msgport, mach_port_t auth,
-                int which, mach_port_t *port)
+
+#define AUTHCHECK \
+  if (auth != mach_task_self () && ! __USEPORT (AUTH, port == auth)) \
+    return EPERM
+
+
+/* Snarfing and frobbing the init ports.  */
+
+kern_return_t
+  _S_msg_get_init_port (mach_port_t msgport, mach_port_t auth, int which,
+                       mach_port_t *result, mach_msg_type_name_t *result_type)
 {
-  if (auth != mach_task_self () && ! __USEPORT (AUTH, port == auth))
-    return EPERM;
+  AUTHCHECK;
+  *result_type = MACH_MSG_TYPE_MOVE_SEND;
+  /* This function adds a new user reference for the *RESULT it gives back.
+     Our reply message uses a move-send right that consumes this reference.  */
+  return _hurd_ports_get (which, result);
+}
 
-  switch (which)
-    {
-    case INIT_PORT_CWDIR:
-      *port = get (&_hurd_cwdir);
-      return 0;
-    case INIT_PORT_CRDIR:
-      *port = get (&_hurd_crdir);
-      return 0;
-    case INIT_PORT_PROC:
-      *port = get (&_hurd_proc);
-      return 0;
-    case INIT_PORT_AUTH:
-      *port = get (&_hurd_auth);
-      return 0;
-    case INIT_PORT_LOGINCOLL:
-      return EOPNOTSUPP;       /* XXX */
-    case INIT_PORT_BOOTSTRAP:
-      return __task_get_special_port (__mach_task_self (),
-                                     TASK_BOOTSTRAP_PORT,
-                                     port);
-    default:
-      return EINVAL;
-    }
+kern_return_t
+_S_msg_set_init_port (mach_port_t msgport, mach_port_t auth,
+                     int which, mach_port_t port)
+{
+  error_t err;
+
+  AUTHCHECK;
+
+  err = _hurd_ports_set (which, port);
+  if (err == 0)
+    __mach_port_deallocate (__mach_task_self (), port);
+
+  return 0;
 }
 
-error_t
-__set_init_port (mach_port_t msgport, mach_port_t auth,
-                int which, mach_port_t port)
+kern_return_t
+_S_msg_get_init_ports (mach_port_t msgport, mach_port_t auth,
+                      mach_port_t **ports,
+                      mach_msg_type_name_t *ports_type,
+                      mach_msg_type_number_t *nports)
 {
-  if (auth != mach_task_self () && ! __USEPORT (AUTH, port == auth))
-    return EPERM;
+  mach_msg_type_number_t i;
+  error_t err;
 
-  switch (which)
+  AUTHCHECK;
+
+  if (err = __vm_allocate (__mach_task_self (), (vm_address_t *) ports,
+                          _hurd_nports * sizeof (mach_port_t), 1))
+    return err;
+  *nports = _hurd_nports;
+
+  for (i = 0; i < _hurd_nports; ++i)
+    /* This function adds a new user ref for the *RESULT it gives back.
+       Our reply message uses move-send rights that consumes this ref.  */
+    if (err = _hurd_ports_get (i, &(*ports)[i]))
+      {
+       /* Died part way through.  Deallocate the ports already fetched.  */
+       while (i-- > 0)
+         __mach_port_deallocate (__mach_task_self (), (*ports)[i]);
+       __vm_deallocate (__mach_task_self (),
+                        (vm_address_t) *ports,
+                        *nports * sizeof (mach_port_t));
+       return err;
+      }
+
+  *ports_type = MACH_MSG_TYPE_MOVE_SEND;
+  return 0;
+}
+
+kern_return_t
+_S_msg_set_init_ports (mach_port_t msgport, mach_port_t auth,
+                      mach_port_t *ports, mach_msg_type_number_t nports)
+{
+  mach_msg_type_number_t i;
+  error_t err;
+
+  AUTHCHECK;
+
+  for (i = 0; i < _hurd_nports; ++i)
     {
-    case INIT_PORT_CWDIR:
-      set (&_hurd_cwdir);
-      return 0;
-    case INIT_PORT_CRDIR:
-      set (&_hurd_crdir);
-      return 0;
-    case INIT_PORT_PROC:
-      set (&_hurd_proc); /* XXX do more? */
-      return 0;
-    case INIT_PORT_AUTH:
-      __setauth (&_hurd_auth);
-      return errno;            /* XXX can't clobber errno */
-    case INIT_PORT_LOGINCOLL:
-      return EOPNOTSUPP;       /* XXX */
-    case INIT_PORT_BOOTSTRAP:
-      return __task_set_special_port (__mach_task_self (),
-                                     TASK_BOOTSTRAP_PORT,
-                                     port);
-    default:
-      return EINVAL;
+      if (err = _hurd_ports_set (i, ports[i]))
+       return err;
+      else
+       __mach_port_deallocate (__mach_task_self (), ports[i]);
     }
+
+  return 0;
 }
+\f
+/* Snarfing and frobbing the init ints.  */
 
-error_t
-__get_init_int (mach_port_t msgport, mach_port_t auth,
-               int which, int *value)
+static kern_return_t
+get_int (int which, int *value)
 {
-  if (task != mach_task_self () &&
-      _HURD_PORT_USE (&_hurd_auth, auth != port))
-    return EPERM;
-
   switch (which)
     {
     case INIT_UMASK:
@@ -98,26 +124,297 @@ __get_init_int (mach_port_t msgport, mach_port_t auth,
       return 0;
     case INIT_SIGMASK:
       {
-       struct _hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread);
+       struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread);
+       __spin_lock (&ss->lock);
        *value = ss->blocked;
-       __mutex_unlock (&ss->lock);
+       __spin_unlock (&ss->lock);
+       return 0;
+      }
+    case INIT_SIGPENDING:
+      {
+       struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread);
+       __spin_lock (&ss->lock);
+       *value = ss->pending;
+       __spin_unlock (&ss->lock);
        return 0;
       }
     case INIT_SIGIGN:
       {
-       struct _hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread);
+       struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread);
        sigset_t ign;
        int sig;
+       __spin_lock (&ss->lock);
        __sigemptyset (&ign);
        for (sig = 1; sig < NSIG; ++sig)
          if (ss->actions[sig].sa_handler == SIG_IGN)
            __sigaddset (&ign, sig);
-       __mutex_unlock (&ss->lock);
+       __spin_unlock (&ss->lock);
        *value = ign;
        return 0;
       }
-      /* XXX ctty crap */
     default:
       return EINVAL;
     }
 }
+
+kern_return_t
+_S_msg_get_init_int (mach_port_t msgport, mach_port_t auth,
+                    int which, int *value)
+{
+  AUTHCHECK;
+
+  return get_int (which, value);
+}
+
+kern_return_t
+_S_msg_get_init_ints (mach_port_t msgport, mach_port_t auth,
+                     int **values, mach_msg_type_number_t *nvalues)
+{
+  error_t err;
+  mach_msg_type_number_t i;
+
+  AUTHCHECK;
+
+  if (err = __vm_allocate (__mach_task_self (), (vm_address_t *) values,
+                          INIT_INT_MAX * sizeof (int), 1))
+    return err;
+  *nvalues = INIT_INT_MAX;
+
+  for (i = 0; i < INIT_INT_MAX; ++i)
+    switch (err = get_int (i, &(*values)[i]))
+      {
+      case 0:                  /* Success.  */
+       break;
+      case EINVAL:             /* Unknown index.  */
+       (*values)[i] = 0;
+       break;
+      default:                 /* Lossage.  */
+       __vm_deallocate (__mach_task_self (),
+                        (vm_address_t) *values, INIT_INT_MAX * sizeof (int));
+       return err;
+      }
+
+  return 0;
+}
+
+
+static kern_return_t
+set_int (int which, int value)
+{
+  switch (which)
+    {
+    case INIT_UMASK:
+      _hurd_umask = value;
+      return 0;
+
+      /* These are pretty odd things to do.  But you asked for it.  */
+    case INIT_SIGMASK:
+      {
+       struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread);
+       __spin_lock (&ss->lock);
+       ss->blocked = value;
+       __spin_unlock (&ss->lock);
+       return 0;
+      }
+    case INIT_SIGPENDING:
+      {
+       struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread);
+       __spin_lock (&ss->lock);
+       ss->pending = value;
+       __spin_unlock (&ss->lock);
+       return 0;
+      }
+    case INIT_SIGIGN:
+      {
+       struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread);
+       int sig;
+       const sigset_t ign = value;
+       __spin_lock (&ss->lock);
+       for (sig = 1; sig < NSIG; ++sig)
+         {
+           if (__sigismember (&ign, sig))
+             ss->actions[sig].sa_handler = SIG_IGN;
+           else if (ss->actions[sig].sa_handler == SIG_IGN)
+             ss->actions[sig].sa_handler = SIG_DFL;
+         }
+       __spin_unlock (&ss->lock);
+       return 0;
+
+      case INIT_TRACEMASK:
+       _hurdsig_traced = value;
+       return 0;
+      }
+    default:
+      return EINVAL;
+    }
+}
+
+kern_return_t
+_S_msg_set_init_int (mach_port_t msgport, mach_port_t auth,
+                    int which, int value)
+{
+  AUTHCHECK;
+
+  return set_int (which, value);
+}
+
+kern_return_t
+_S_msg_set_init_ints (mach_port_t msgport, mach_port_t auth,
+                     int *values, mach_msg_type_number_t nvalues)
+{
+  error_t err;
+  mach_msg_type_number_t i;
+
+  AUTHCHECK;
+
+  for (i = 0; i < INIT_INT_MAX; ++i)
+    switch (err = set_int (i, values[i]))
+      {
+      case 0:                  /* Success.  */
+       break;
+      case EINVAL:             /* Unknown index.  */
+       break;
+      default:                 /* Lossage.  */
+       return err;
+      }
+
+  return 0;
+}
+\f
+
+kern_return_t
+_S_msg_get_fd (mach_port_t msgport, mach_port_t auth, int which,
+              mach_port_t *result, mach_msg_type_name_t *result_type)
+{
+  AUTHCHECK;
+
+  /* This creates a new user reference for the send right.
+     Our reply message will move that reference to the caller.  */
+  *result = __getdport (which);
+  if (*result == MACH_PORT_NULL)
+    return errno;
+  *result_type = MACH_MSG_TYPE_MOVE_SEND;
+
+  return 0;
+}
+
+kern_return_t
+_S_msg_set_fd (mach_port_t msgport, mach_port_t auth,
+              int which, mach_port_t port)
+{
+  AUTHCHECK;
+
+  /* We consume the reference if successful.  */
+  return HURD_FD_USE (which, (_hurd_port2fd (descriptor, port, 0), 0));
+}
+\f
+/* Snarfing and frobbing environment variables.  */
+
+kern_return_t
+_S_msg_get_env_variable (mach_port_t msgport,
+                        char *variable,
+                        char **data, mach_msg_type_number_t *datalen)
+{
+  error_t err;
+  mach_msg_type_number_t valuelen;
+  const char *value = getenv (variable);
+
+  if (value == NULL)
+    return ENOENT;
+
+  valuelen = strlen (value);
+  if (valuelen > *datalen)
+    {
+      if (err = __vm_allocate (__mach_task_self (), 
+                              (vm_address_t *) data, valuelen, 1))
+       return err;
+    }
+
+  memcpy (*data, value, valuelen);
+  *datalen = valuelen;
+
+  return 0;
+}
+
+
+kern_return_t
+_S_msg_set_env_variable (mach_port_t msgport, mach_port_t auth,
+                        char *variable,
+                        char *value,
+                        int replace)
+{
+  AUTHCHECK;
+
+  if (setenv (variable, value, replace)) /* XXX name space */
+    return errno;
+  return 0;
+}
+
+kern_return_t
+_S_msg_get_environment (mach_port_t msgport,
+                       char **data, mach_msg_type_number_t *datalen)
+{
+  /* Pack the environment into an array with nulls separating elements.  */
+  if (__environ != NULL)
+    {
+      char *ap, **p;
+      size_t envlen = 0;
+
+      for (p = __environ; *p != NULL; ++p)
+       envlen += strlen (*p) + 1;
+
+      if (envlen > *datalen)
+       {
+         if (__vm_allocate (__mach_task_self (),
+                            (vm_address_t *) data, envlen, 1))
+           return ENOMEM;
+       }
+
+      ap = *data;
+      for (p = __environ; *p != NULL; ++p)
+       ap = __memccpy (ap, *p, '\0', ULONG_MAX);
+
+      *datalen = envlen;
+    }
+  else
+    *datalen = 0;
+
+  return 0;
+}
+
+kern_return_t
+_S_msg_set_environment (mach_port_t msgport, mach_port_t auth,
+                       char *data, mach_msg_type_number_t datalen)
+{
+  int _hurd_split_args (char *, mach_msg_type_number_t, char **);
+  int envc;
+  char **envp;
+
+  AUTHCHECK;
+
+  envc = __argz_count (data, datalen);
+  envp = malloc ((envc + 1) * sizeof (char *));
+  if (envp == NULL)
+    return errno;
+  __argz_extract (data, datalen, envp);
+  __environ = envp;            /* XXX cooperate with loadenv et al */
+  return 0;
+}
+\f
+
+/* XXX */
+
+kern_return_t
+_S_msg_get_dtable (mach_port_t process,
+                  mach_port_t refport,
+                  portarray_t *dtable,
+                  mach_msg_type_name_t *dtablePoly,
+                  mach_msg_type_number_t *dtableCnt)
+{ return EOPNOTSUPP; }
+
+kern_return_t
+_S_msg_set_dtable (mach_port_t process,
+                  mach_port_t refport,
+                  portarray_t dtable,
+                  mach_msg_type_number_t dtableCnt)
+{ return EOPNOTSUPP; }