aboutsummaryrefslogtreecommitdiff
path: root/proc/host.c
diff options
context:
space:
mode:
Diffstat (limited to 'proc/host.c')
-rw-r--r--proc/host.c371
1 files changed, 173 insertions, 198 deletions
diff --git a/proc/host.c b/proc/host.c
index 3b1e03c8..2b3c4f3c 100644
--- a/proc/host.c
+++ b/proc/host.c
@@ -1,5 +1,5 @@
/* Proc server host management calls
- Copyright (C) 1992, 1993, 1994, 1996 Free Software Foundation
+ Copyright (C) 1992,93,94,96,97,2001,02 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -8,7 +8,7 @@ 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,
+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.
@@ -31,13 +31,12 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <hurd/exec.h>
#include <unistd.h>
#include <assert.h>
+#include <version.h>
+#include <sys/mman.h>
#include "proc.h"
#include "process_S.h"
-static long hostid;
-static char *hostname;
-static int hostnamelen;
static mach_port_t *std_port_array;
static int *std_int_array;
static int n_std_ports, n_std_ints;
@@ -47,93 +46,17 @@ struct server_version
{
char *name;
char *version;
- char *release;
} *server_versions;
int nserver_versions, server_versions_nalloc;
-struct execdata_notify
+struct execdata_notify
{
mach_port_t notify_port;
struct execdata_notify *next;
} *execdata_notifys;
-/* Implement proc_sethostid as described in <hurd/proc.defs>. */
-kern_return_t
-S_proc_sethostid (struct proc *p,
- int newhostid)
-{
- if (!p)
- return EOPNOTSUPP;
-
- if (! check_uid (p, 0))
- return EPERM;
-
- hostid = newhostid;
-
- return 0;
-}
-
-/* Implement proc_gethostid as described in <hurd/proc.defs>. */
-kern_return_t
-S_proc_gethostid (struct proc *p,
- int *outhostid)
-{
- /* No need to check P here; we don't use it. */
- *outhostid = hostid;
- return 0;
-}
-/* Implement proc_sethostname as described in <hurd/proc.defs>. */
-kern_return_t
-S_proc_sethostname (struct proc *p,
- char *newhostname,
- u_int newhostnamelen)
-{
- int len;
- if (!p)
- return EOPNOTSUPP;
-
- if (! check_uid (p, 0))
- return EPERM;
-
- if (hostname)
- free (hostname);
-
- hostname = malloc (newhostnamelen + 1);
- hostnamelen = newhostnamelen;
-
- bcopy (newhostname, hostname, newhostnamelen);
- hostname[newhostnamelen] = '\0';
-
- len = newhostnamelen + 1;
- if (len > sizeof uname_info.nodename)
- len = sizeof uname_info.nodename;
- bcopy (hostname, uname_info.nodename, len);
- uname_info.nodename[sizeof uname_info.nodename - 1] = '\0';
-
- return 0;
-}
-
-/* Implement proc_gethostname as described in <hurd/proc.defs>. */
-kern_return_t
-S_proc_gethostname (struct proc *p,
- char **outhostname,
- u_int *outhostnamelen)
-{
- /* No need to check P here; we don't use it. */
-
- if (*outhostnamelen < hostnamelen + 1)
- vm_allocate (mach_task_self (), (vm_address_t *)outhostname,
- hostnamelen + 1, 1);
- *outhostnamelen = hostnamelen + 1;
- if (hostname)
- bcopy (hostname, *outhostname, hostnamelen + 1);
- else
- **outhostname = '\0';
- return 0;
-}
-
-/* Implement proc_getprivports as described in <hurd/proc.defs>. */
+/* Implement proc_getprivports as described in <hurd/process.defs>. */
kern_return_t
S_proc_getprivports (struct proc *p,
mach_port_t *hostpriv,
@@ -141,33 +64,47 @@ S_proc_getprivports (struct proc *p,
{
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>. */
+/* Implement proc_setexecdata as described in <hurd/process.defs>. */
kern_return_t
S_proc_setexecdata (struct proc *p,
mach_port_t *ports,
- u_int nports,
+ size_t nports,
int *ints,
- u_int nints)
+ size_t nints)
{
int i;
struct execdata_notify *n;
-
+ mach_port_t *std_port_array_new;
+ int *std_int_array_new;
+
if (!p)
return EOPNOTSUPP;
-
+
if (!check_uid (p, 0))
return EPERM;
-
+
+ /* Allocate memory up front. */
+ std_port_array_new = malloc (sizeof (mach_port_t) * nports);
+ if (! std_port_array_new)
+ return ENOMEM;
+
+ std_int_array_new = malloc (sizeof (int) * nints);
+ if (! std_int_array_new)
+ {
+ free (std_port_array_new);
+ return ENOMEM;
+ }
+
if (std_port_array)
{
for (i = 0; i < n_std_ports; i++)
@@ -176,75 +113,98 @@ S_proc_setexecdata (struct proc *p,
}
if (std_int_array)
free (std_int_array);
-
- std_port_array = malloc (sizeof (mach_port_t) * nports);
+
+ std_port_array = std_port_array_new;
n_std_ports = nports;
- bcopy (ports, std_port_array, sizeof (mach_port_t) * nports);
-
- std_int_array = malloc (sizeof (int) * nints);
+ memcpy (std_port_array, ports, sizeof (mach_port_t) * nports);
+
+ std_int_array = std_int_array_new;
n_std_ints = nints;
- bcopy (ints, std_int_array, sizeof (int) * nints);
-
+ memcpy (std_int_array, ints, 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
+/* Implement proc_getexecdata as described in <hurd/process.defs>. */
+kern_return_t
S_proc_getexecdata (struct proc *p,
mach_port_t **ports,
mach_msg_type_name_t *portspoly,
- u_int *nports,
+ size_t *nports,
int **ints,
- u_int *nints)
+ size_t *nints)
{
+ int i;
+ int ports_allocated = 0;
/* 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));
+ {
+ *ports = mmap (0, round_page (n_std_ports * sizeof (mach_port_t)),
+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (*ports == MAP_FAILED)
+ return ENOMEM;
+ ports_allocated = 1;
+ }
+ memcpy (*ports, std_port_array, 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));
+ {
+ *ints = mmap (0, round_page (n_std_ints * sizeof (int)),
+ PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (*ints == MAP_FAILED)
+ {
+ if (ports_allocated)
+ munmap (*ports, round_page (n_std_ports * sizeof (mach_port_t)));
+ return ENOMEM;
+ }
+ }
+ memcpy (*ints, std_int_array, n_std_ints * sizeof (int));
*nints = n_std_ints;
+ for (i = 0; i < n_std_ports; i++)
+ mach_port_mod_refs (mach_task_self (), std_port_array[i], MACH_PORT_RIGHT_SEND, 1);
+ *portspoly = MACH_MSG_TYPE_MOVE_SEND;
+
return 0;
}
-/* Implement proc_execdata_notify as described in <hurd/proc.defs>. */
+/* Implement proc_execdata_notify as described in <hurd/process.defs>. */
kern_return_t
S_proc_execdata_notify (struct proc *p,
mach_port_t notify)
{
- struct execdata_notify *n = malloc (sizeof (struct execdata_notify));
+ struct execdata_notify *n;
mach_port_t foo;
/* No need to check P here; we don't use it. */
+ n = malloc (sizeof (struct execdata_notify));
+ if (! n)
+ return ENOMEM;
+
n->notify_port = notify;
n->next = execdata_notifys;
execdata_notifys = n;
- mach_port_request_notification (mach_task_self (), notify,
+ 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,
+ exec_setexecdata (n->notify_port, std_port_array, MACH_MSG_TYPE_COPY_SEND,
n_std_ports, std_int_array, n_std_ints);
return 0;
}
@@ -255,7 +215,7 @@ 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)
@@ -271,14 +231,17 @@ check_dead_execdata_notify (mach_port_t port)
/* Version information handling.
- A server registers its name, release, and version with
- startup_register_version. The uname version string is composed of all
- the server names and versions. The uname release is composed of the
- differing server releases in order of decreasing popularity (just one if
- they all agree).
+ 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;
- The Hurd release comes from <hurd/hurd_types.h> and
- is compiled into proc as well as the other servers. */
/* Rebuild the uname version string. */
static void
@@ -314,72 +277,58 @@ rebuild_uname (void)
*p++ = '/';
}
- /* Collect all the differing release strings and count how many
+ /* Collect all the differing version strings and count how many
servers use each. */
- struct release
+ struct version
{
- const char *release;
+ const char *version;
unsigned int count;
- } releases[nserver_versions];
- int compare_releases (const void *a, const void *b)
+ } versions[nserver_versions];
+ int compare_versions (const void *a, const void *b)
{
- return (((const struct release *) b)->count -
- ((const struct release *) a)->count);
+ return (((const struct version *) b)->count -
+ ((const struct version *) a)->count);
}
- unsigned int nreleases = 0;
+ unsigned int nversions = 0;
for (i = 0; i < nserver_versions; ++i)
{
- for (j = 0; j < nreleases; ++j)
- if (! strcmp (releases[j].release, server_versions[i].release))
+ for (j = 0; j < nversions; ++j)
+ if (! strcmp (versions[j].version, server_versions[i].version))
{
- ++releases[j].count;
+ ++versions[j].count;
break;
}
- if (j == nreleases)
+ if (j == nversions)
{
- releases[nreleases].release = server_versions[i].release;
- releases[nreleases].count = 1;
- ++nreleases;
+ versions[nversions].version = server_versions[i].version;
+ versions[nversions].count = 1;
+ ++nversions;
}
}
- /* Sort the releases in order of decreasing popularity. */
- qsort (releases, nreleases, sizeof (struct release), compare_releases);
+ /* Sort the versions in order of decreasing popularity. */
+ qsort (versions, nversions, sizeof (struct version), compare_versions);
/* Now build the uname strings. */
- initstr (uname_info.release);
- for (i = 0; i < nreleases; ++i)
- addstr (NULL, releases[i].release);
+ /* release is the most popular version */
+ strcpy (uname_info.release, versions[0].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';
+ initstr (uname_info.version);
- for (i = 2; i < nserver_versions; i++)
- if (strcmp (server_versions[i].version, server_versions[1].version))
- break;
+ addstr (kernel_name, kernel_version);
- initstr (uname_info.version);
+ if (versions[0].count > 1)
+ addstr ("Hurd", versions[0].version);
- if (i == nserver_versions)
- {
- /* All the servers after [0] (the microkernel version)
- are the same, so just write one "hurd" version. */
- addstr (server_versions[0].name, server_versions[0].version);
- addstr ("Hurd", server_versions[1].version);
- }
- else
+ /* 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++)
- addstr (server_versions[i].name, server_versions[i].version);
+ 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
@@ -393,52 +342,58 @@ rebuild_uname (void)
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 kernel_version;
+ kernel_version_t kv;
char *p;
struct host_basic_info info;
- unsigned int n = sizeof info;
+ size_t 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);
+ err = host_info (mach_host_self (), HOST_BASIC_INFO,
+ (host_info_t) &info, &n);
assert (! err);
- snprintf (uname_info.machine, sizeof uname_info.machine, "%s/%s",
+ 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. */
+ variables. */
server_versions = malloc (sizeof (struct server_version) * 10);
+ assert (server_versions);
server_versions_nalloc = 10;
- err = host_kernel_version (mach_host_self (), kernel_version);
+ err = host_kernel_version (mach_host_self (), kv);
assert (! err);
- p = index (kernel_version, ':');
+ /* Make sure the result is null-terminated, as the kernel doesn't
+ guarantee it. */
+ kv[sizeof (kv) - 1] = '\0';
+ p = index (kv, ':');
if (p)
*p = '\0';
- p = index (kernel_version, ' ');
+ p = index (kv, ' ');
if (p)
*p = '\0';
- server_versions[0].name = strdup (p ? kernel_version : "mach");
- server_versions[0].release = strdup (HURD_RELEASE);
- server_versions[0].version = strdup (p ? p + 1 : kernel_version);
+ kernel_name = strdup (p ? kv : "mach");
+ assert (kernel_name);
+ kernel_version = strdup (p ? p + 1 : kv);
+ assert (kernel_version);
- server_versions[1].name = strdup (OUR_SERVER_NAME);
- server_versions[1].release = strdup (HURD_RELEASE);
- server_versions[1].version = strdup (OUR_VERSION);
+ server_versions[0].name = strdup ("proc");
+ assert (server_versions[0].name);
+ server_versions[0].version = strdup (HURD_VERSION);
+ assert (server_versions[0].version);
- nserver_versions = 2;
+ nserver_versions = 1;
rebuild_uname ();
-
+
uname_info.nodename[0] = '\0';
}
@@ -455,9 +410,10 @@ kern_return_t
S_proc_register_version (pstruct_t server,
mach_port_t credential,
char *name,
- char *release,
+ char *release,
char *version)
{
+ error_t err = 0;
int i;
/* No need to check SERVER here; we don't use it. */
@@ -465,17 +421,19 @@ S_proc_register_version (pstruct_t server,
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);
- free (server_versions[i].release);
server_versions[i].version = malloc (strlen (version) + 1);
- server_versions[i].release = malloc (strlen (version) + 1);
+ if (! server_versions[i].version)
+ {
+ err = ENOMEM;
+ goto out;
+ }
strcpy (server_versions[i].version, version);
- strcpy (server_versions[i].release, release);
break;
}
if (i == nserver_versions)
@@ -483,23 +441,40 @@ S_proc_register_version (pstruct_t server,
/* Didn't find it; extend. */
if (nserver_versions == server_versions_nalloc)
{
+ void *new = realloc (server_versions,
+ sizeof (struct server_version) *
+ server_versions_nalloc * 2);
+ if (! new)
+ {
+ err = ENOMEM;
+ goto out;
+ }
+
server_versions_nalloc *= 2;
- server_versions = realloc (server_versions,
- sizeof (struct server_version) *
- server_versions_nalloc);
+ server_versions = new;
}
server_versions[nserver_versions].name = malloc (strlen (name) + 1);
- server_versions[nserver_versions].version = malloc (strlen (version)
- + 1);
- server_versions[nserver_versions].release = malloc (strlen (release)
+ if (! server_versions[nserver_versions].name)
+ {
+ err = ENOMEM;
+ goto out;
+ }
+ server_versions[nserver_versions].version = malloc (strlen (version)
+ 1);
+ if (! server_versions[nserver_versions].version)
+ {
+ free (server_versions[nserver_versions].name);
+ err = ENOMEM;
+ goto out;
+ }
strcpy (server_versions[nserver_versions].name, name);
strcpy (server_versions[nserver_versions].version, version);
- strcpy (server_versions[nserver_versions].release, release);
nserver_versions++;
}
-
+
rebuild_uname ();
- mach_port_deallocate (mach_task_self (), credential);
- return 0;
+out:
+ if (!err)
+ mach_port_deallocate (mach_task_self (), credential);
+ return err;
}