aboutsummaryrefslogtreecommitdiff
path: root/proc/host.c
diff options
context:
space:
mode:
Diffstat (limited to 'proc/host.c')
-rw-r--r--proc/host.c408
1 files changed, 408 insertions, 0 deletions
diff --git a/proc/host.c b/proc/host.c
new file mode 100644
index 00000000..8f9460cb
--- /dev/null
+++ b/proc/host.c
@@ -0,0 +1,408 @@
+/* Proc server host management calls
+ Copyright (C) 1992, 1993, 1994, 1996, 1997 Free Software Foundation
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Michael I. Bushnell. */
+
+#include <mach.h>
+#include <hurd.h>
+#include <sys/types.h>
+#include <hurd/hurd_types.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <mach/notify.h>
+#include <string.h>
+#include <stdio.h>
+#include <hurd/exec.h>
+#include <unistd.h>
+#include <assert.h>
+#include <version.h>
+
+#include "proc.h"
+#include "process_S.h"
+
+static mach_port_t *std_port_array;
+static int *std_int_array;
+static int n_std_ports, n_std_ints;
+static struct utsname uname_info;
+
+struct server_version
+{
+ char *name;
+ char *version;
+} *server_versions;
+int nserver_versions, server_versions_nalloc;
+
+struct execdata_notify
+{
+ mach_port_t notify_port;
+ struct execdata_notify *next;
+} *execdata_notifys;
+
+
+/* Implement proc_getprivports as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_getprivports (struct proc *p,
+ mach_port_t *hostpriv,
+ mach_port_t *devpriv)
+{
+ if (!p)
+ return EOPNOTSUPP;
+
+ if (! check_uid (p, 0))
+ return EPERM;
+
+ *hostpriv = master_host_port;
+ *devpriv = master_device_port;
+ return 0;
+}
+
+
+/* Implement proc_setexecdata as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_setexecdata (struct proc *p,
+ mach_port_t *ports,
+ u_int nports,
+ int *ints,
+ u_int nints)
+{
+ int i;
+ struct execdata_notify *n;
+
+ if (!p)
+ return EOPNOTSUPP;
+
+ if (!check_uid (p, 0))
+ return EPERM;
+
+ if (std_port_array)
+ {
+ for (i = 0; i < n_std_ports; i++)
+ mach_port_deallocate (mach_task_self (), std_port_array[i]);
+ free (std_port_array);
+ }
+ if (std_int_array)
+ free (std_int_array);
+
+ std_port_array = malloc (sizeof (mach_port_t) * nports);
+ n_std_ports = nports;
+ bcopy (ports, std_port_array, sizeof (mach_port_t) * nports);
+
+ std_int_array = malloc (sizeof (int) * nints);
+ n_std_ints = nints;
+ bcopy (ints, std_int_array, sizeof (int) * nints);
+
+ for (n = execdata_notifys; n; n = n->next)
+ exec_setexecdata (n->notify_port, std_port_array, MACH_MSG_TYPE_COPY_SEND,
+ n_std_ports, std_int_array, n_std_ints);
+
+ return 0;
+}
+
+/* Implement proc_getexecdata as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_getexecdata (struct proc *p,
+ mach_port_t **ports,
+ mach_msg_type_name_t *portspoly,
+ u_int *nports,
+ int **ints,
+ u_int *nints)
+{
+ /* No need to check P here; we don't use it. */
+
+ /* XXX memory leak here */
+
+ if (!std_port_array)
+ return ENOENT;
+
+ if (*nports < n_std_ports)
+ *ports = malloc (n_std_ports * sizeof (mach_port_t));
+ bcopy (std_port_array, *ports, n_std_ports * sizeof (mach_port_t));
+ *nports = n_std_ports;
+
+ if (*nints < n_std_ints)
+ *ints = malloc (n_std_ints * sizeof (mach_port_t));
+ bcopy (std_int_array, *ints, n_std_ints * sizeof (int));
+ *nints = n_std_ints;
+
+ return 0;
+}
+
+/* Implement proc_execdata_notify as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_execdata_notify (struct proc *p,
+ mach_port_t notify)
+{
+ struct execdata_notify *n = malloc (sizeof (struct execdata_notify));
+ mach_port_t foo;
+
+ /* No need to check P here; we don't use it. */
+
+ n->notify_port = notify;
+ n->next = execdata_notifys;
+ execdata_notifys = n;
+
+ mach_port_request_notification (mach_task_self (), notify,
+ MACH_NOTIFY_DEAD_NAME, 1,
+ generic_port, MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &foo);
+
+ if (foo)
+ mach_port_deallocate (mach_task_self (), foo);
+
+ if (std_port_array)
+ exec_setexecdata (n->notify_port, std_port_array, MACH_MSG_TYPE_COPY_SEND,
+ n_std_ports, std_int_array, n_std_ints);
+ return 0;
+}
+
+/* Check all the execdata notify ports and see if one of them is
+ PORT; if it is, then free it. */
+void
+check_dead_execdata_notify (mach_port_t port)
+{
+ struct execdata_notify *en, **prevp;
+
+ for (en = execdata_notifys, prevp = &execdata_notifys; en; en = *prevp)
+ {
+ if (en->notify_port == port)
+ {
+ mach_port_deallocate (mach_task_self (), port);
+ *prevp = en->next;
+ free (en);
+ }
+ else
+ prevp = &en->next;
+ }
+}
+
+/* Version information handling.
+
+ A server registers its name and version with
+ startup_register_version.
+
+ The uname release is the most popular version number.
+
+ The uname version string is composed of all the server names and
+ versions, omitting special mention of those which match the uname
+ release, plus the kernel version string. */
+
+char *kernel_name, *kernel_version;
+
+
+/* Rebuild the uname version string. */
+static void
+rebuild_uname (void)
+{
+ unsigned int i, j;
+ char *p, *end;
+
+ /* Set up for addstr to write into STRING. */
+ inline void initstr (char *string)
+ {
+ p = string;
+ end = p + _UTSNAME_LENGTH;
+ }
+ /* If NAME is not null, write "name-version/", else "version/". */
+ inline void addstr (const char *name, const char *version)
+ {
+ size_t len;
+ if (name)
+ {
+ len = strlen (name);
+ if (p + len + 1 < end)
+ memcpy (p, name, len);
+ p += len;
+ if (p < end)
+ *p++ = '-';
+ }
+ len = strlen (version);
+ if (p + len + 1 < end)
+ memcpy (p, version, len);
+ p += len;
+ if (p < end)
+ *p++ = '/';
+ }
+
+ /* Collect all the differing version strings and count how many
+ servers use each. */
+ struct version
+ {
+ const char *version;
+ unsigned int count;
+ } versions[nserver_versions];
+ int compare_versions (const void *a, const void *b)
+ {
+ return (((const struct version *) b)->count -
+ ((const struct version *) a)->count);
+ }
+ unsigned int nversions = 0;
+
+ for (i = 0; i < nserver_versions; ++i)
+ {
+ for (j = 0; j < nversions; ++j)
+ if (! strcmp (versions[j].version, server_versions[i].version))
+ {
+ ++versions[j].count;
+ break;
+ }
+ if (j == nversions)
+ {
+ versions[nversions].version = server_versions[i].version;
+ versions[nversions].count = 1;
+ ++nversions;
+ }
+ }
+
+ /* Sort the versions in order of decreasing popularity. */
+ qsort (versions, nversions, sizeof (struct version), compare_versions);
+
+ /* Now build the uname strings. */
+
+ /* release is the most popular version */
+ strcpy (uname_info.release, versions[0].version);
+
+ initstr (uname_info.version);
+
+ addstr (kernel_name, kernel_version);
+
+ if (versions[0].count > 1)
+ addstr ("Hurd", versions[0].version);
+
+ /* Now, for any which differ (if there might be any), write it out
+ separately. */
+ if (versions[0].count != nserver_versions)
+ for (i = 0; i < nserver_versions; i++)
+ if (versions[0].count == 1
+ || strcmp (server_versions[i].version, versions[0].version))
+ addstr (server_versions[i].name, server_versions[i].version);
+
+ if (p > end)
+#ifdef notyet
+ syslog (LOG_EMERG,
+ "_UTSNAME_LENGTH %u too short; inform bug-glibc@prep.ai.mit.edu\n",
+ p - end)
+#endif
+ ;
+ else
+ p[-1] = '\0';
+ end[-1] = '\0';
+}
+
+void
+initialize_version_info (void)
+{
+ extern const char *const mach_cpu_types[];
+ extern const char *const mach_cpu_subtypes[][32];
+ kernel_version_t kv;
+ char *p;
+ struct host_basic_info info;
+ unsigned int n = sizeof info;
+ error_t err;
+
+ /* Fill in fixed slots sysname and machine. */
+ strcpy (uname_info.sysname, "GNU");
+
+ err = host_info (mach_host_self (), HOST_BASIC_INFO, (int *) &info, &n);
+ assert (! err);
+ snprintf (uname_info.machine, sizeof uname_info.machine, "%s-%s",
+ mach_cpu_types[info.cpu_type],
+ mach_cpu_subtypes[info.cpu_type][info.cpu_subtype]);
+
+ /* Notice Mach's and our own version and initialize server version
+ varables. */
+ server_versions = malloc (sizeof (struct server_version) * 10);
+ server_versions_nalloc = 10;
+
+ err = host_kernel_version (mach_host_self (), kv);
+ assert (! err);
+ p = index (kv, ':');
+ if (p)
+ *p = '\0';
+ p = index (kv, ' ');
+ if (p)
+ *p = '\0';
+ kernel_name = strdup (p ? kv : "mach");
+ kernel_version = strdup (p ? p + 1 : kv);
+
+ server_versions[0].name = strdup ("proc");
+ server_versions[0].version = strdup (HURD_VERSION);
+
+ nserver_versions = 1;
+
+ rebuild_uname ();
+
+ uname_info.nodename[0] = '\0';
+}
+
+kern_return_t
+S_proc_uname (pstruct_t process,
+ struct utsname *uname)
+{
+ /* No need to check PROCESS here, we don't use it. */
+ *uname = uname_info;
+ return 0;
+}
+
+kern_return_t
+S_proc_register_version (pstruct_t server,
+ mach_port_t credential,
+ char *name,
+ char *release,
+ char *version)
+{
+ int i;
+
+ /* No need to check SERVER here; we don't use it. */
+
+ if (credential != master_host_port)
+ /* Must be privileged to register for uname. */
+ return EPERM;
+
+ for (i = 0; i < nserver_versions; i++)
+ if (!strcmp (name, server_versions[i].name))
+ {
+ /* Change this entry. */
+ free (server_versions[i].version);
+ server_versions[i].version = malloc (strlen (version) + 1);
+ strcpy (server_versions[i].version, version);
+ break;
+ }
+ if (i == nserver_versions)
+ {
+ /* Didn't find it; extend. */
+ if (nserver_versions == server_versions_nalloc)
+ {
+ server_versions_nalloc *= 2;
+ server_versions = realloc (server_versions,
+ sizeof (struct server_version) *
+ server_versions_nalloc);
+ }
+ server_versions[nserver_versions].name = malloc (strlen (name) + 1);
+ server_versions[nserver_versions].version = malloc (strlen (version)
+ + 1);
+ strcpy (server_versions[nserver_versions].name, name);
+ strcpy (server_versions[nserver_versions].version, version);
+ nserver_versions++;
+ }
+
+ rebuild_uname ();
+ mach_port_deallocate (mach_task_self (), credential);
+ return 0;
+}
+