aboutsummaryrefslogtreecommitdiff
path: root/exec/hashexec.c
diff options
context:
space:
mode:
Diffstat (limited to 'exec/hashexec.c')
-rw-r--r--exec/hashexec.c205
1 files changed, 128 insertions, 77 deletions
diff --git a/exec/hashexec.c b/exec/hashexec.c
index 748f8e1b..2aa3844b 100644
--- a/exec/hashexec.c
+++ b/exec/hashexec.c
@@ -1,5 +1,5 @@
/* GNU Hurd standard exec server, #! script execution support.
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,97,98,99,2000,02 Free Software Foundation, Inc.
Written by Roland McGrath.
This file is part of the GNU Hurd.
@@ -18,11 +18,11 @@ 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. */
-
#include "priv.h"
#include <hurd/sigpreempt.h>
#include <unistd.h>
#include <envz.h>
+#include <sys/param.h>
/* This is called to check E for a #! interpreter specification. E has
already been prepared (successfully) and checked (unsuccessfully). If
@@ -43,13 +43,10 @@ check_hashbang (struct execdata *e,
mach_port_t *deallocnames, u_int ndeallocnames,
mach_port_t *destroynames, u_int ndestroynames)
{
- char *ibuf = NULL;
- size_t ibufsiz = 0;
char *p;
char *interp, *arg; /* Interpreter file name, and first argument */
- size_t interp_len, len;
+ size_t interp_len, arg_len;
file_t interp_file; /* Port open on the interpreter file. */
- FILE *f = &e->stream;
char *new_argv;
size_t new_argvlen;
mach_port_t *new_dtable = NULL;
@@ -57,12 +54,18 @@ check_hashbang (struct execdata *e,
file_t user_fd (int fd)
{
- if (fd < 0 || fd >= dtablesize || dtable[fd] == MACH_PORT_NULL)
+ if (fd >= 0 && fd < dtablesize)
{
- errno = EBADF;
- return MACH_PORT_NULL;
+ const file_t dport = dtable[fd];
+ if (dport != MACH_PORT_NULL)
+ {
+ mach_port_mod_refs (mach_task_self (), dport,
+ MACH_PORT_RIGHT_SEND, +1);
+ return dport;
+ }
}
- return dtable[fd];
+ errno = EBADF;
+ return MACH_PORT_NULL;
}
file_t user_crdir, user_cwdir;
error_t user_port (int which, error_t (*operate) (mach_port_t))
@@ -71,6 +74,9 @@ check_hashbang (struct execdata *e,
{
error_t err;
mach_port_t ref;
+
+ /* MAKE_SEND is safe here because we destroy REF ourselves. */
+
error_t uauth (auth_t auth)
{
return auth_user_authenticate (auth,
@@ -121,50 +127,81 @@ check_hashbang (struct execdata *e,
name, flags, 0, result);
}
- rewind (f);
+ const char *page;
+ char interp_buf[vm_page_size - 2 + 1];
- /* Check for our ``magic number''--"#!". */
+ e->error = 0;
+ page = map (e, 0, 2);
- errno = 0;
- if (getc (f) != '#' || getc (f) != '!')
+ if (!page)
{
- /* No `#!' here. If there was a read error (not including EOF),
- return that error indication. Otherwise return ENOEXEC to
- say it's not a file we know how to execute. */
- e->error = ferror (f) ? errno : ENOEXEC;
+ if (!e->error)
+ e->error = ENOEXEC;
return;
}
- /* Read the rest of the first line of the file. */
-
- interp_len = getline (&ibuf, &ibufsiz, f);
- if (ferror (f))
+ /* Check for our ``magic number''--"#!". */
+ if (page[0] != '#' || page[1] != '!')
{
- e->error = errno ?: EIO;
+ /* These are not the droids we're looking for. */
+ e->error = ENOEXEC;
return;
}
- if (ibuf[interp_len - 1] == '\n')
- ibuf[--interp_len] = '\0';
- /* Find the name of the interpreter. */
- p = ibuf + strspn (ibuf, " \t");
- interp = strsep (&p, " \t");
+ /* Read the rest of the first line of the file.
+ We in fact impose an arbitrary limit of about a page on this. */
- if (p)
- /* Skip remaining blanks, and the rest of the line is the argument. */
+ p = memccpy (interp_buf, page + 2, '\n',
+ MIN (map_fsize (e) - 2, sizeof interp_buf));
+ if (p == NULL)
{
- p += strspn (p, " \t");
- arg = p;
- len = interp_len - (arg - ibuf);
+ /* The first line went on for more than sizeof INTERP_BUF! */
+ interp_len = sizeof interp_buf;
+ interp_buf[interp_len - 1] = '\0';
}
else
- /* There is no argument. */
- len = 0;
+ {
+ interp_len = p - interp_buf; /* Includes null terminator. */
+ *--p = '\0'; /* Kill the newline. */
+ }
+
+ /* We are now done reading the script file. */
+ finish (e, 0);
+
+
+ /* Find the name of the interpreter. */
+ interp = interp_buf + strspn (interp_buf, " \t");
+ p = strpbrk (interp, " \t");
+
+ if (p)
+ {
+ /* Terminate the interpreter name. */
+ *p++ = '\0';
- if (len == 0)
- arg = NULL;
+ /* Skip remaining blanks, and the rest of the line is the argument. */
+
+ arg = p + strspn (p, " \t");
+ arg_len = interp_len - 1 - (arg - interp_buf); /* without null here */
+ interp_len = p - interp; /* This one includes the null. */
+
+ if (arg_len == 0)
+ arg = NULL;
+ else
+ {
+ /* Trim trailing blanks after the argument. */
+ size_t i = arg_len - 1;
+ while (arg[i] == ' ' || arg[i] == '\t')
+ arg[i--] = '\0';
+ arg_len = i + 2; /* Include the terminating null. */
+ }
+ }
else
- ++len; /* Include the terminating null. */
+ {
+ /* There is no argument. */
+ arg = NULL;
+ arg_len = 0;
+ interp_len -= interp - interp_buf; /* Account for blanks skipped. */
+ }
user_crdir = user_cwdir = MACH_PORT_NULL;
@@ -179,7 +216,7 @@ check_hashbang (struct execdata *e,
jmp_buf args_faulted;
void fault_handler (int signo)
{ longjmp (args_faulted, 1); }
- error_t setup_args (struct hurd_signal_preempter *preempter)
+ error_t setup_args (struct hurd_signal_preemptor *preemptor)
{
size_t namelen;
char * volatile file_name = NULL;
@@ -197,14 +234,13 @@ check_hashbang (struct execdata *e,
char *name;
int free_name = 0; /* True if we should free NAME. */
file_t name_file;
- mach_port_t fileid;
- dev_t filedev;
+ mach_port_t fileid, filefsid;
ino_t fileno;
/* Search $PATH for NAME, opening a port NAME_FILE on it.
This is encapsulated in a function so we can catch faults
reading the user's environment. */
- error_t search_path (struct hurd_signal_preempter *preempter)
+ error_t search_path (struct hurd_signal_preemptor *preemptor)
{
error_t err;
char *path = envz_get (envp, envplen, "PATH"), *pfxed_name;
@@ -228,9 +264,10 @@ check_hashbang (struct execdata *e,
return err;
}
- error = io_identity (file, &fileid, &filedev, &fileno);
+ error = io_identity (file, &fileid, &filefsid, &fileno);
if (error)
goto out;
+ mach_port_deallocate (mach_task_self (), filefsid);
if (memchr (argv, '\0', argvlen) == NULL)
{
@@ -251,11 +288,15 @@ check_hashbang (struct execdata *e,
if (!error && name_file != MACH_PORT_NULL)
{
- mach_port_t id;
- dev_t dev;
+ mach_port_t id, fsid;
ino_t ino;
- error = io_identity (name_file, &id, &dev, &ino);
- __mach_port_deallocate (__mach_task_self (), id);
+ error = io_identity (name_file, &id, &fsid, &ino);
+ mach_port_deallocate (mach_task_self (), name_file);
+ if (!error)
+ {
+ mach_port_deallocate (mach_task_self (), fsid);
+ mach_port_deallocate (mach_task_self (), id);
+ }
if (!error && id == fileid)
{
file_name = name;
@@ -263,10 +304,9 @@ check_hashbang (struct execdata *e,
}
else if (free_name)
free (name);
- __mach_port_deallocate (__mach_task_self (), name_file);
}
- __mach_port_deallocate (__mach_task_self (), fileid);
+ mach_port_deallocate (mach_task_self (), fileid);
}
if (file_name == NULL)
@@ -298,33 +338,50 @@ check_hashbang (struct execdata *e,
/* Prepare the arguments to pass to the interpreter from the original
arguments and the name of the script file. The args will look
- like `ARGV[0] {ARG} FILE_NAME ARGV[1..n]' (ARG might have been
+ like `INTERP {ARG} FILE_NAME ARGV[1..n]' (ARG might have been
omitted). */
namelen = strlen (file_name) + 1;
- new_argvlen = argvlen + len + namelen;
- e->error = vm_allocate (mach_task_self (),
- (vm_address_t *) &new_argv,
- new_argvlen, 1);
- if (e->error)
- return e->error;
+ new_argvlen
+ = (argvlen - strlen (argv) - 1) /* existing args - old argv[0] */
+ + interp_len + arg_len + namelen; /* New args */
+
+ new_argv = mmap (0, new_argvlen, PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ if (new_argv == (caddr_t) -1)
+ {
+ e->error = errno;
+ return e->error;
+ }
+ else
+ e->error = 0;
if (! setjmp (args_faulted))
{
char *other_args;
- other_args = memccpy (new_argv, argv, '\0', argvlen);
- p = &new_argv[other_args ? other_args - new_argv : argvlen];
+
+ p = new_argv;
+
+ /* INTERP */
+ memcpy (p, interp, interp_len);
+ p += interp_len;
+
+ /* Maybe ARG */
if (arg)
{
- memcpy (p, arg, len);
- p += len;
+ memcpy (p, arg, arg_len);
+ p += arg_len;
}
+
+ /* FILE_NAME */
memcpy (p, file_name, namelen);
p += namelen;
- if (other_args)
- memcpy (p, other_args - new_argv + argv,
- argvlen - (other_args - new_argv));
+
+ /* Maybe remaining args */
+ other_args = argv + strlen (argv) + 1;
+ if (other_args - argv < argvlen)
+ memcpy (p, other_args, argvlen - (other_args - argv));
}
else
{
@@ -332,7 +389,7 @@ check_hashbang (struct execdata *e,
char *n = stpncpy (new_argv,
"**fault in exec server reading argv[0]**",
argvlen);
- memcpy (memcpy (n, arg, len) + len, file_name, namelen);
+ memcpy (memcpy (n, arg, arg_len) + arg_len, file_name, namelen);
}
if (free_file_name)
@@ -347,10 +404,6 @@ check_hashbang (struct execdata *e,
&setup_args, &fault_handler);
}
- /* We are now done reading the script file. */
- finish (e, 0);
- free (ibuf);
-
rwlock_reader_unlock (&std_lock);
if (user_crdir != MACH_PORT_NULL)
@@ -384,21 +437,19 @@ check_hashbang (struct execdata *e,
task_resume (oldtask); /* Our caller suspended it. */
mach_port_deallocate (mach_task_self (), oldtask);
if (! argv_copy)
- vm_deallocate (mach_task_self (), (vm_address_t) argv, argvlen);
+ munmap (argv, argvlen);
if (! envp_copy)
- vm_deallocate (mach_task_self (), (vm_address_t) envp, envplen);
+ munmap (envp, envplen);
for (i = 0; i < dtablesize; ++i)
- mach_port_deallocate (mach_task_self (), dtable[i]);
+ if (MACH_PORT_VALID (dtable[i]))
+ mach_port_deallocate (mach_task_self (), dtable[i]);
if (! dtable_copy)
- vm_deallocate (mach_task_self (), (vm_address_t) dtable,
- dtablesize * sizeof *dtable);
+ munmap (dtable, dtablesize * sizeof *dtable);
for (i = 0; i < nports; ++i)
mach_port_deallocate (mach_task_self (), portarray[i]);
if (! portarray_copy)
- vm_deallocate (mach_task_self (), (vm_address_t) portarray,
- nports * sizeof *portarray);
+ munmap (portarray, nports * sizeof *portarray);
if (! intarray_copy)
- vm_deallocate (mach_task_self (), (vm_address_t) intarray,
- nints * sizeof *intarray);
+ munmap (intarray, nints * sizeof *intarray);
}
}