diff options
Diffstat (limited to 'proc/host.c')
-rw-r--r-- | proc/host.c | 371 |
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; } |