| /* Copyright (C) 1992-2014 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 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 |
| Lesser General Public License for more details. |
| |
| 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 <hurd.h> |
| #include <hurd/msg_server.h> |
| #include <hurd/fd.h> |
| #include <unistd.h> |
| #include <limits.h> |
| #include <string.h> |
| #include <argz.h> |
| |
| |
| #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) |
| { |
| 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); |
| } |
| |
| 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; |
| } |
| |
| 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) |
| { |
| mach_msg_type_number_t i; |
| error_t err; |
| |
| 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) |
| { |
| if (err = _hurd_ports_set (i, ports[i])) |
| return err; |
| else |
| __mach_port_deallocate (__mach_task_self (), ports[i]); |
| } |
| |
| return 0; |
| } |
| |
| /* Snarfing and frobbing the init ints. */ |
| |
| static kern_return_t |
| get_int (int which, int *value) |
| { |
| switch (which) |
| { |
| case INIT_UMASK: |
| *value = _hurd_umask; |
| return 0; |
| case INIT_SIGMASK: |
| { |
| struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread); |
| __spin_lock (&ss->lock); |
| *value = ss->blocked; |
| __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); |
| 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); |
| __spin_unlock (&ss->lock); |
| *value = ign; |
| return 0; |
| } |
| 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; |
| } |
| |
| |
| 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)); |
| } |
| |
| /* 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; |
| } |
| |
| |
| /* 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; } |