Index: emulation/ibcs2/coff/imgact_coff.c
===================================================================
RCS file: /nfs/daver/cvs-repos/cvs-dragonflybsd/src/sys/emulation/ibcs2/coff/imgact_coff.c,v
retrieving revision 1.7
diff -u -u -r1.7 imgact_coff.c
--- emulation/ibcs2/coff/imgact_coff.c	23 Sep 2003 05:03:50 -0000	1.7
+++ emulation/ibcs2/coff/imgact_coff.c	11 Nov 2003 06:38:37 -0000
@@ -333,11 +333,6 @@
 	       ((const char*)(imgp->image_header) + sizeof(struct filehdr) +
 		sizeof(struct aouthdr));
 
-	if ((error = exec_extract_strings(imgp)) != 0) {
-		DPRINTF(("%s(%d):  return %d\n", __FILE__, __LINE__, error));
-		return error;
-	}
-
 	exec_new_vmspace(imgp);
 	vmspace = imgp->proc->p_vmspace;
 
Index: emulation/linux/i386/imgact_linux.c
===================================================================
RCS file: /nfs/daver/cvs-repos/cvs-dragonflybsd/src/sys/emulation/linux/i386/imgact_linux.c,v
retrieving revision 1.4
diff -u -u -r1.4 imgact_linux.c
--- emulation/linux/i386/imgact_linux.c	27 Aug 2003 06:30:03 -0000	1.4
+++ emulation/linux/i386/imgact_linux.c	10 Nov 2003 10:44:04 -0000
@@ -109,11 +109,6 @@
 	a_out->a_data + bss_size > imgp->proc->p_rlimit[RLIMIT_DATA].rlim_cur)
 	return (ENOMEM);
 
-    /* copy in arguments and/or environment from old process */
-    error = exec_extract_strings(imgp);
-    if (error)
-	return (error);
-
     /*
      * Destroy old process VM and create a new one (with a new stack)
      */
Index: emulation/linux/i386/linux_sysvec.c
===================================================================
RCS file: /nfs/daver/cvs-repos/cvs-dragonflybsd/src/sys/emulation/linux/i386/linux_sysvec.c,v
retrieving revision 1.10
diff -u -u -r1.10 linux_sysvec.c
--- emulation/linux/i386/linux_sysvec.c	10 Nov 2003 06:12:11 -0000	1.10
+++ emulation/linux/i386/linux_sysvec.c	11 Nov 2003 03:13:23 -0000
@@ -197,13 +197,13 @@
 	register_t *argv, *envp;
 
 	argv = *stack_base;
-	envp = *stack_base + (imgp->argc + 1);
+	envp = *stack_base + (imgp->args->argc + 1);
 	(*stack_base)--;
 	**stack_base = (intptr_t)(void *)envp;
 	(*stack_base)--;
 	**stack_base = (intptr_t)(void *)argv;
 	(*stack_base)--;
-	**stack_base = imgp->argc;
+	**stack_base = imgp->args->argc;
 	return 0;
 }
 
@@ -213,7 +213,7 @@
 	Elf32_Auxargs *args = (Elf32_Auxargs *)imgp->auxargs;
 	register_t *pos;
              
-	pos = *stack_base + (imgp->argc + imgp->envc + 2);  
+	pos = *stack_base + (imgp->args->argc + imgp->args->envc + 2);  
     
 	if (args->trace) {
 		AUXARGS_ENTRY(pos, AT_DEBUG, 1);
@@ -238,7 +238,7 @@
 	imgp->auxargs = NULL;
 
 	(*stack_base)--;
-	**stack_base = (long)imgp->argc;
+	**stack_base = (long)imgp->args->argc;
 	return 0;
 }
 
Index: emulation/svr4/imgact_svr4.c
===================================================================
RCS file: /nfs/daver/cvs-repos/cvs-dragonflybsd/src/sys/emulation/svr4/imgact_svr4.c,v
retrieving revision 1.5
diff -u -u -r1.5 imgact_svr4.c
--- emulation/svr4/imgact_svr4.c	27 Aug 2003 06:07:10 -0000	1.5
+++ emulation/svr4/imgact_svr4.c	11 Nov 2003 06:38:57 -0000
@@ -109,11 +109,6 @@
 	a_out->a_data + bss_size > imgp->proc->p_rlimit[RLIMIT_DATA].rlim_cur)
 	return (ENOMEM);
 
-    /* copy in arguments and/or environment from old process */
-    error = exec_extract_strings(imgp);
-    if (error)
-	return (error);
-
     /*
      * Destroy old process VM and create a new one (with a new stack)
      */
Index: emulation/svr4/svr4_sysvec.c
===================================================================
RCS file: /nfs/daver/cvs-repos/cvs-dragonflybsd/src/sys/emulation/svr4/svr4_sysvec.c,v
retrieving revision 1.8
diff -u -u -r1.8 svr4_sysvec.c
--- emulation/svr4/svr4_sysvec.c	23 Sep 2003 05:03:51 -0000	1.8
+++ emulation/svr4/svr4_sysvec.c	11 Nov 2003 06:36:01 -0000
@@ -203,7 +203,7 @@
 	Elf32_Auxargs *args = (Elf32_Auxargs *)imgp->auxargs;
 	register_t *pos;
              
-	pos = *stack_base + (imgp->argc + imgp->envc + 2);  
+	pos = *stack_base + (imgp->args->argc + imgp->args->envc + 2);  
     
 	if (args->trace) {
 		AUXARGS_ENTRY(pos, AT_DEBUG, 1);
@@ -228,7 +228,7 @@
 	imgp->auxargs = NULL;
 
 	(*stack_base)--;
-	**stack_base = (int)imgp->argc;
+	**stack_base = (int)imgp->args->argc;
 	return 0;
 }
 
Index: kern/imgact_aout.c
===================================================================
RCS file: /nfs/daver/cvs-repos/cvs-dragonflybsd/src/sys/kern/imgact_aout.c,v
retrieving revision 1.6
diff -u -u -r1.6 imgact_aout.c
--- kern/imgact_aout.c	27 Aug 2003 01:43:07 -0000	1.6
+++ kern/imgact_aout.c	10 Nov 2003 00:21:39 -0000
@@ -165,11 +165,6 @@
 		imgp->proc->p_rlimit[RLIMIT_DATA].rlim_cur)
 			return (ENOMEM);
 
-	/* copy in arguments and/or environment from old process */
-	error = exec_extract_strings(imgp);
-	if (error)
-		return (error);
-
 	/*
 	 * Destroy old process VM and create a new one (with a new stack)
 	 */
Index: kern/imgact_elf.c
===================================================================
RCS file: /nfs/daver/cvs-repos/cvs-dragonflybsd/src/sys/kern/imgact_elf.c,v
retrieving revision 1.14
diff -u -u -r1.14 imgact_elf.c
--- kern/imgact_elf.c	10 Nov 2003 18:09:12 -0000	1.14
+++ kern/imgact_elf.c	11 Nov 2003 06:26:42 -0000
@@ -362,7 +362,6 @@
 	 * Initialize part of the common data
 	 */
 	imgp->proc = p;
-	imgp->uap = NULL;
 	imgp->attr = attr;
 	imgp->firstpage = NULL;
 	imgp->image_header = (char *)kmem_alloc_wait(exec_map, PAGE_SIZE);
@@ -494,6 +493,8 @@
 	Elf_Brandinfo *brand_info;
 	char *path;
 
+	error = 0;
+
 	/*
 	 * Do we have a valid ELF header ?
 	 */
@@ -516,9 +517,6 @@
 	 * From this point on, we may have resources that need to be freed.
 	 */
 
-	if ((error = exec_extract_strings(imgp)) != 0)
-		goto fail;
-
 	exec_new_vmspace(imgp);
 
 	/*
@@ -724,7 +722,7 @@
 	Elf_Auxargs *args = (Elf_Auxargs *)imgp->auxargs;
 	register_t *pos;
 
-	pos = *stack_base + (imgp->argc + imgp->envc + 2);
+	pos = *stack_base + (imgp->args->argc + imgp->args->envc + 2);
 
 	if (args->trace) {
 		AUXARGS_ENTRY(pos, AT_DEBUG, 1);
@@ -745,7 +743,7 @@
 	imgp->auxargs = NULL;
 
 	(*stack_base)--;
-	suword(*stack_base, (long) imgp->argc);
+	suword(*stack_base, (long) imgp->args->argc);
 	return 0;
 } 
 
Index: kern/imgact_gzip.c
===================================================================
RCS file: /nfs/daver/cvs-repos/cvs-dragonflybsd/src/sys/kern/imgact_gzip.c,v
retrieving revision 1.3
diff -u -u -r1.3 imgact_gzip.c
--- kern/imgact_gzip.c	26 Aug 2003 21:09:02 -0000	1.3
+++ kern/imgact_gzip.c	11 Nov 2003 06:38:03 -0000
@@ -219,12 +219,6 @@
 	/* Find out how far we should go */
 	gz->file_end = gz->file_offset + gz->a_out.a_text + gz->a_out.a_data;
 
-	/* copy in arguments and/or environment from old process */
-	error = exec_extract_strings(gz->ip);
-	if (error) {
-		gz->where = __LINE__;
-		return (error);
-	}
 	/*
 	 * Destroy old process VM and create a new one (with a new stack)
 	 */
Index: kern/imgact_shell.c
===================================================================
RCS file: /nfs/daver/cvs-repos/cvs-dragonflybsd/src/sys/kern/imgact_shell.c,v
retrieving revision 1.2
diff -u -u -r1.2 imgact_shell.c
--- kern/imgact_shell.c	17 Jun 2003 04:28:41 -0000	1.2
+++ kern/imgact_shell.c	11 Nov 2003 06:09:45 -0000
@@ -42,15 +42,14 @@
 
 /*
  * Shell interpreter image activator. A interpreter name beginning
- *	at imgp->stringbase is the minimal successful exit requirement.
+ *	at imgp->args->begin_argv is the minimal successful exit requirement.
  */
 int
-exec_shell_imgact(imgp)
-	struct image_params *imgp;
+exec_shell_imgact(struct image_params *imgp)
 {
 	const char *image_header = imgp->image_header;
-	const char *ihp, *line_endp;
-	char *interp;
+	const char *ihp;
+	int error, length, offset;
 
 	/* a shell script? */
 	if (((const short *) image_header)[0] != SHELLMAGIC)
@@ -66,64 +65,83 @@
 	imgp->interpreted = 1;
 
 	/*
-	 * Copy shell name and arguments from image_header into string
-	 *	buffer.
+	 * We must determine how far to offset the contents of the buffer
+	 * to make room for the interpreter + args and the full path of
+	 * the interpreted file while overwriting the first argument
+	 * currently in the buffer.
 	 */
-
-	/*
-	 * Find end of line; return if the line > MAXSHELLCMDLEN long.
-	 */
-	for (ihp = &image_header[2]; *ihp != '\n' && *ihp != '#'; ++ihp) {
-		if (ihp >= &image_header[MAXSHELLCMDLEN])
-			return(ENAMETOOLONG);
-	}
-	line_endp = ihp;
-
-	/* reset for another pass */
 	ihp = &image_header[2];
+	offset = 0;
+	while (ihp < &image_header[MAXSHELLCMDLEN]) {
+		/* Skip any whitespace */
+		while ((*ihp == ' ') || (*ihp == '\t'))
+			ihp++;
+
+		/* End of line? */
+		if ((*ihp == '\n') || (*ihp == '#'))
+			break;
+
+		/* Found a token */
+		while ((*ihp != ' ') && (*ihp != '\t') && (*ihp != '\n') &&
+		    (*ihp != '#')) {
+			offset++;
+			ihp++;
+		}
+		/* Include terminating nulls in the offset */
+		offset++;
+	}
 
-	/* Skip over leading spaces - until the interpreter name */
-	while ((*ihp == ' ') || (*ihp == '\t')) ihp++;
-
-	/* copy the interpreter name */
-	interp = imgp->interpreter_name;
-	while ((ihp < line_endp) && (*ihp != ' ') && (*ihp != '\t'))
-		*interp++ = *ihp++;
-	*interp = '\0';
-
-	/* Disallow a null interpreter filename */
-	if (*imgp->interpreter_name == '\0')
-		return(ENOEXEC);
+	/* If the script gives a null line as the interpreter, we bail */
+	if (offset == 0)
+		return (ENOEXEC);
+
+	/* Check that we aren't too big */
+	if (offset > MAXSHELLCMDLEN)
+		return (ENAMETOOLONG);
+
+	/* The file name is used to replace argv[0] */
+	offset += strlen(imgp->args->fname) + 1;
+	offset -= strlen(imgp->args->begin_argv) + 1;
+
+	if (offset > imgp->args->space)
+		return (E2BIG);
+
+	/* Move the contents of imgp->args->buf by offset bytes. */
+	bcopy(imgp->args->buf, imgp->args->buf + offset,
+	    ARG_MAX - imgp->args->space);
 
-	/* reset for another pass */
+	/*
+	 * Loop through the interpreter name yet again, copying as
+	 * we go.
+	 */
 	ihp = &image_header[2];
+	offset = 0;
+	while (ihp < &image_header[MAXSHELLCMDLEN]) {
+		/* Skip whitespace */
+		while ((*ihp == ' ' || *ihp == '\t'))
+			ihp++;
+
+		/* End of line? */
+		if ((*ihp == '\n') || (*ihp == '#'))
+			break;
+
+		/* Found a token, copy it */
+		while ((*ihp != ' ') && (*ihp != '\t') && (*ihp != '\n') &&
+		   (*ihp != '#'))
+			imgp->args->buf[offset++] = *ihp++;
 
-	/* copy the interpreter name and arguments */
-	while (ihp < line_endp) {
-		/* Skip over leading spaces */
-		while ((*ihp == ' ') || (*ihp == '\t')) ihp++;
-
-		if (ihp < line_endp) {
-			/*
-			 * Copy to end of token. No need to watch stringspace
-			 *	because this is at the front of the string buffer
-			 *	and the maximum shell command length is tiny.
-			 */
-			while ((ihp < line_endp) && (*ihp != ' ') && (*ihp != '\t')) {
-				*imgp->stringp++ = *ihp++;
-				imgp->stringspace--;
-			}
-
-			*imgp->stringp++ = 0;
-			imgp->stringspace--;
-
-			imgp->argc++;
-		}
+		imgp->args->buf[offset++] = '\0';
+		imgp->args->argc++;
 	}
 
-	imgp->argv0 = imgp->uap->fname;
+	error = copystr(imgp->args->fname, imgp->args->buf + offset,
+	    imgp->args->space, &length);
+
+	if (error == 0)
+		error = copystr(imgp->args->begin_argv,
+		    imgp->interpreter_name, MAXSHELLCMDLEN, &length);
 
-	return(0);
+	return (error);
 }
 
 /*
Index: kern/kern_exec.c
===================================================================
RCS file: /nfs/daver/cvs-repos/cvs-dragonflybsd/src/sys/kern/kern_exec.c,v
retrieving revision 1.13
diff -u -u -r1.13 kern_exec.c
--- kern/kern_exec.c	5 Nov 2003 23:26:20 -0000	1.13
+++ kern/kern_exec.c	11 Nov 2003 05:06:22 -0000
@@ -38,6 +38,7 @@
 #include <sys/exec.h>
 #include <sys/imgact.h>
 #include <sys/imgact_elf.h>
+#include <sys/kern_syscall.h>
 #include <sys/wait.h>
 #include <sys/malloc.h>
 #include <sys/proc.h>
@@ -83,27 +84,50 @@
 int ps_argsopen = 1;
 SYSCTL_INT(_kern, OID_AUTO, ps_argsopen, CTLFLAG_RW, &ps_argsopen, 0, "");
 
+void print_execve_args(struct image_args *args);
+int debug_execve_args = 0;
+SYSCTL_INT(_kern, OID_AUTO, debug_execve_args, CTLFLAG_RW, &debug_execve_args,
+    0, "");
+
+void
+print_execve_args(struct image_args *args)
+{
+	char *cp;
+	int ndx;
+
+	cp = args->begin_argv;
+	for (ndx = 0; ndx < args->argc; ndx++) {
+		printf("\targv[%d]: %s\n", ndx, cp);
+		while (*cp++ != '\0');
+	}
+	for (ndx = 0; ndx < args->envc; ndx++) {
+		printf("\tenvv[%d]: %s\n", ndx, cp);
+		while (*cp++ != '\0');
+	}
+}
+
 /*
  * Each of the items is a pointer to a `const struct execsw', hence the
  * double pointer here.
  */
 static const struct execsw **execsw;
 
-/*
- * execve() system call.
- */
 int
-execve(struct execve_args *uap)
+kern_execve(struct nameidata *ndp, struct image_args *args)
 {
 	struct thread *td = curthread;
 	struct proc *p = td->td_proc;
-	struct nameidata nd, *ndp;
 	register_t *stack_base;
 	int error, len, i;
 	struct image_params image_params, *imgp;
 	struct vattr attr;
 	int (*img_first) (struct image_params *);
 
+	if (debug_execve_args) {
+		printf("%s()\n", __func__);
+		print_execve_args(args);
+	}
+
 	KKASSERT(p);
 	imgp = &image_params;
 
@@ -120,14 +144,11 @@
 	 * Initialize part of the common data
 	 */
 	imgp->proc = p;
-	imgp->uap = uap;
+	imgp->args = args;
 	imgp->attr = &attr;
-	imgp->argc = imgp->envc = 0;
-	imgp->argv0 = NULL;
 	imgp->entry_addr = 0;
 	imgp->vmspace_destroyed = 0;
 	imgp->interpreted = 0;
-	imgp->interpreter_name[0] = '\0';
 	imgp->auxargs = NULL;
 	imgp->vp = NULL;
 	imgp->firstpage = NULL;
@@ -137,34 +158,26 @@
 	 * Allocate temporary demand zeroed space for argument and
 	 *	environment strings
 	 */
-	imgp->stringbase = (char *)kmem_alloc_wait(exec_map, ARG_MAX + PAGE_SIZE);
-	if (imgp->stringbase == NULL) {
+	imgp->image_header = (char *)kmem_alloc_wait(exec_map, PAGE_SIZE);
+	if (imgp->image_header == NULL) {
 		error = ENOMEM;
 		goto exec_fail;
 	}
-	imgp->stringp = imgp->stringbase;
-	imgp->stringspace = ARG_MAX;
-	imgp->image_header = imgp->stringbase + ARG_MAX;
+
+interpret:
 
 	/*
 	 * Translate the file name. namei() returns a vnode pointer
 	 *	in ni_vp amoung other things.
 	 */
-	ndp = &nd;
-	NDINIT(ndp, NAMEI_LOOKUP, CNP_LOCKLEAF | CNP_FOLLOW | CNP_SAVENAME,
-	    UIO_USERSPACE, uap->fname, td);
-
-interpret:
-
 	error = namei(ndp);
 	if (error) {
-		kmem_free_wakeup(exec_map, (vm_offset_t)imgp->stringbase,
-			ARG_MAX + PAGE_SIZE);
+		kmem_free_wakeup(exec_map, (vm_offset_t)imgp->image_header,
+		    PAGE_SIZE);
 		goto exec_fail;
 	}
 
 	imgp->vp = ndp->ni_vp;
-	imgp->fname = uap->fname;
 
 	/*
 	 * Check file permissions (also 'opens' file)
@@ -180,6 +193,12 @@
 	if (error)
 		goto exec_fail_dealloc;
 
+	if (debug_execve_args && imgp->interpreted) {
+		printf("    target is interpreted -- recursive pass\n");
+		printf("    interpreter: %s\n", imgp->interpreter_name);
+		print_execve_args(args);
+	}
+
 	/*
 	 *	If the current process has a special image activator it
 	 *	wants to try first, call it.   For example, emulating shell 
@@ -238,7 +257,7 @@
 	if (p->p_sysent->sv_fixup)
 		(*p->p_sysent->sv_fixup)(&stack_base, imgp);
 	else
-		suword(--stack_base, imgp->argc);
+		suword(--stack_base, imgp->args->argc);
 
 	/*
 	 * For security and other reasons, the file descriptor table cannot
@@ -389,26 +408,19 @@
 	setregs(p, imgp->entry_addr, (u_long)(uintptr_t)stack_base,
 	    imgp->ps_strings);
 
-	/*
-	 * The syscall result is returned in registers to the new program.
-	 * Linux will register %edx as an atexit function and we must be
-	 * sure to set it to 0.  XXX
-	 */
-	uap->sysmsg_result64 = 0;
-
 	/* Free any previous argument cache */
 	if (p->p_args && --p->p_args->ar_ref == 0)
 		FREE(p->p_args, M_PARGS);
 	p->p_args = NULL;
 
 	/* Cache arguments if they fit inside our allowance */
-	i = imgp->endargs - imgp->stringbase;
+	i = imgp->args->begin_envv - imgp->args->begin_argv;
 	if (ps_arg_cache_limit >= i + sizeof(struct pargs)) {
 		MALLOC(p->p_args, struct pargs *, sizeof(struct pargs) + i, 
 		    M_PARGS, M_WAITOK);
 		p->p_args->ar_ref = 1;
 		p->p_args->ar_length = i;
-		bcopy(imgp->stringbase, p->p_args->ar_args, i);
+		bcopy(imgp->args->begin_argv, p->p_args->ar_args, i);
 	}
 
 exec_fail_dealloc:
@@ -419,9 +431,9 @@
 	if (imgp->firstpage)
 		exec_unmap_first_page(imgp);
 
-	if (imgp->stringbase != NULL)
-		kmem_free_wakeup(exec_map, (vm_offset_t)imgp->stringbase,
-			ARG_MAX + PAGE_SIZE);
+	if (imgp->image_header != NULL)
+		kmem_free_wakeup(exec_map, (vm_offset_t)imgp->image_header,
+		    PAGE_SIZE);
 
 	if (imgp->vp) {
 		NDFREE(ndp, NDF_ONLY_PNBUF);
@@ -444,6 +456,39 @@
 	}
 }
 
+/*
+ * execve() system call.
+ */
+int
+execve(struct execve_args *uap)
+{
+	struct thread *td = curthread;
+	struct nameidata nd;
+	struct image_args args;
+	int error;
+
+	NDINIT(&nd, NAMEI_LOOKUP, CNP_LOCKLEAF | CNP_FOLLOW | CNP_SAVENAME,
+	    UIO_USERSPACE, uap->fname, td);
+
+	error = exec_copyin_args(&args, uap->fname, PATH_USERSPACE,
+	    uap->argv, uap->envv);
+	if (error)
+		return (error);
+
+	error = kern_execve(&nd, &args);
+
+	exec_free_args(&args);
+
+	/*
+	 * The syscall result is returned in registers to the new program.
+	 * Linux will register %edx as an atexit function and we must be
+	 * sure to set it to 0.  XXX
+	 */
+	uap->sysmsg_result64 = 0;
+
+	return (error);
+}
+
 int
 exec_map_first_page(struct image_params *imgp)
 {
@@ -572,70 +617,97 @@
  *	address space into the temporary string buffer.
  */
 int
-exec_extract_strings(imgp)
-	struct image_params *imgp;
+exec_copyin_args(struct image_args *args, char *fname,
+    enum exec_path_segflg segflg, char **argv, char **envv)
 {
-	char	**argv, **envv;
 	char	*argp, *envp;
-	int	error;
+	int	error = 0;
 	size_t	length;
 
+	args->buf = (char *) kmem_alloc_wait(exec_map, PATH_MAX + ARG_MAX);
+	if (args->buf == NULL)
+		return (ENOMEM);
+	args->begin_argv = args->buf;
+	args->endp = args->begin_argv;
+	args->space = ARG_MAX;
+	args->argc = 0;
+	args->envc = 0;
+
+	args->fname = args->buf + ARG_MAX;
+
 	/*
-	 * extract arguments first
+	 * Copy the file name.
 	 */
+	if (segflg == PATH_SYSSPACE) {
+		error = copystr(fname, args->fname, PATH_MAX, &length);
+	} else if (segflg == PATH_USERSPACE) {
+		error = copyinstr(fname, args->fname, PATH_MAX, &length);
+	}
 
-	argv = imgp->uap->argv;
+	/*
+	 * extract argument strings
+	 */
 
 	if (argv) {
 		argp = (caddr_t) (intptr_t) fuword(argv);
-		if (argp == (caddr_t) -1)
-			return (EFAULT);
-		if (argp)
-			argv++;
-		if (imgp->argv0)
-			argp = imgp->argv0;
-		if (argp) {
-			do {
-				if (argp == (caddr_t) -1)
-					return (EFAULT);
-				if ((error = copyinstr(argp, imgp->stringp,
-				    imgp->stringspace, &length))) {
-					if (error == ENAMETOOLONG)
-						return(E2BIG);
-					return (error);
-				}
-				imgp->stringspace -= length;
-				imgp->stringp += length;
-				imgp->argc++;
-			} while ((argp = (caddr_t) (intptr_t) fuword(argv++)));
+		/*
+		 * First argument is a special case.  If it is a null
+		 * string, we must copy the file name into the string
+		 * buffer as the first argument.  This guarantees that
+		 * the interpreter knows what file to open in the case
+		 * that we exec an interpreted file.
+		 */
+		while ((argp = (caddr_t) (intptr_t) fuword(argv++))) {
+			if (argp == (caddr_t) -1) {
+				error = EFAULT;
+				goto cleanup;
+			}
+			error = copyinstr(argp, args->endp,
+			    args->space, &length);
+			if (error == ENAMETOOLONG)
+				error = E2BIG;
+			if (error)
+				goto cleanup;
+			args->space -= length;
+			args->endp += length;
+			args->argc++;
 		}
 	}	
 
-	imgp->endargs = imgp->stringp;
+	args->begin_envv = args->endp;
 
 	/*
 	 * extract environment strings
 	 */
 
-	envv = imgp->uap->envv;
-
 	if (envv) {
 		while ((envp = (caddr_t) (intptr_t) fuword(envv++))) {
-			if (envp == (caddr_t) -1)
-				return (EFAULT);
-			if ((error = copyinstr(envp, imgp->stringp,
-			    imgp->stringspace, &length))) {
-				if (error == ENAMETOOLONG)
-					return(E2BIG);
-				return (error);
+			if (envp == (caddr_t) -1) {
+				error = EFAULT;
+				goto cleanup;
 			}
-			imgp->stringspace -= length;
-			imgp->stringp += length;
-			imgp->envc++;
+			error = copyinstr(envp, args->endp, args->space,
+			    &length);
+			if (error == ENAMETOOLONG)
+				error = E2BIG;
+			if (error)
+				goto cleanup;
+			args->space -= length;
+			args->endp += length;
+			args->envc++;
 		}
 	}
 
-	return (0);
+cleanup:
+	if (error)
+		exec_free_args(args);
+	return (error);
+}
+
+void
+exec_free_args(struct image_args *args)
+{
+	kmem_free_wakeup(exec_map, (vm_offset_t)args->buf, PATH_MAX + ARG_MAX);
 }
 
 /*
@@ -644,8 +716,7 @@
  *	so that it can be used as the initial stack pointer.
  */
 register_t *
-exec_copyout_strings(imgp)
-	struct image_params *imgp;
+exec_copyout_strings(struct image_params *imgp)
 {
 	int argc, envc;
 	char **vectp;
@@ -661,14 +732,14 @@
 	arginfo = (struct ps_strings *)PS_STRINGS;
 	szsigcode = *(imgp->proc->p_sysent->sv_szsigcode);
 	destp =	(caddr_t)arginfo - szsigcode - SPARE_USRSPACE -
-		roundup((ARG_MAX - imgp->stringspace), sizeof(char *));
+	    roundup((ARG_MAX - imgp->args->space), sizeof(char *));
 
 	/*
 	 * install sigcode
 	 */
 	if (szsigcode)
 		copyout(imgp->proc->p_sysent->sv_sigcode,
-			((caddr_t)arginfo - szsigcode), szsigcode);
+		    ((caddr_t)arginfo - szsigcode), szsigcode);
 
 	/*
 	 * If we have a valid auxargs ptr, prepare some room
@@ -680,29 +751,30 @@
 	 * arg and env vector sets, and 'AT_COUNT*2' is room for the
 	 * ELF Auxargs data.
 	 */
-		vectp = (char **)(destp - (imgp->argc + imgp->envc + 2 +
-				  AT_COUNT*2) * sizeof(char*));
+		vectp = (char **)(destp - (imgp->args->argc +
+		    imgp->args->envc + 2 + AT_COUNT*2) * sizeof(char*));
 	else 
 	/*
 	 * The '+ 2' is for the null pointers at the end of each of the
 	 * arg and env vector sets
 	 */
 		vectp = (char **)
-			(destp - (imgp->argc + imgp->envc + 2) * sizeof(char*));
+		    (destp - (imgp->args->argc + imgp->args->envc + 2) *
+		    sizeof(char*));
 
 	/*
 	 * vectp also becomes our initial stack base
 	 */
 	stack_base = (register_t *)vectp;
 
-	stringp = imgp->stringbase;
-	argc = imgp->argc;
-	envc = imgp->envc;
+	stringp = imgp->args->begin_argv;
+	argc = imgp->args->argc;
+	envc = imgp->args->envc;
 
 	/*
 	 * Copy out strings - arguments and environment.
 	 */
-	copyout(stringp, destp, ARG_MAX - imgp->stringspace);
+	copyout(stringp, destp, ARG_MAX - imgp->args->space);
 
 	/*
 	 * Fill in "ps_strings" struct for ps, w, etc.
Index: sys/imgact.h
===================================================================
RCS file: /nfs/daver/cvs-repos/cvs-dragonflybsd/src/sys/sys/imgact.h,v
retrieving revision 1.3
diff -u -u -r1.3 imgact.h
--- sys/imgact.h	20 Aug 2003 07:31:21 -0000	1.3
+++ sys/imgact.h	11 Nov 2003 04:26:52 -0000
@@ -39,33 +39,41 @@
 
 #define MAXSHELLCMDLEN	128
 
+struct image_args {
+	char *buf;		/* pointer to string buffer */
+	char *begin_argv;	/* beginning of argv in buf */
+	char *begin_envv;	/* beginning of envv in buf */
+	char *endp;		/* current `end' pointer of arg & env strings */
+	char *fname;		/* beginning of file name */
+	int space;		/* space left in arg & env buffer */
+	int argc;		/* count of argument strings */
+	int envc;		/* count of environment strings */
+};
+
 struct image_params {
 	struct proc *proc;	/* our process struct */
-	struct execve_args *uap; /* syscall arguments */
+	struct image_args *args;	/* syscall arguments */
 	struct vnode *vp;	/* pointer to vnode of file to exec */
 	struct vattr *attr;	/* attributes of file */
 	const char *image_header; /* head of file to exec */
-	char *stringbase;	/* base address of tmp string storage */
-	char *stringp;		/* current 'end' pointer of tmp strings */
-	char *endargs;		/* end of argv vector */
-	int stringspace;	/* space left in tmp string storage area */
-	int argc, envc;		/* count of argument and environment strings */
-	char *argv0;		/* Replacement for argv[0] when interpreting */
 	unsigned long entry_addr; /* entry address of target executable */
 	char vmspace_destroyed;	/* flag - we've blown away original vm space */
 	char interpreted;	/* flag - this executable is interpreted */
 	char interpreter_name[MAXSHELLCMDLEN]; /* name of the interpreter */
 	void *auxargs;		/* ELF Auxinfo structure pointer */
 	struct vm_page *firstpage;	/* first page that we mapped */
-	char *fname;            /* pointer to filename of executable (user space) */
 	unsigned long ps_strings; /* PS_STRINGS for BSD/OS binaries */
 };
 
 #ifdef _KERNEL
+enum	exec_path_segflg {PATH_SYSSPACE, PATH_USERSPACE};
+
 int	exec_check_permissions (struct image_params *);
-int	exec_extract_strings (struct image_params *);
 int	exec_new_vmspace (struct image_params *);
 int	exec_shell_imgact (struct image_params *);
+int	exec_copyin_args(struct image_args *, char *, enum exec_path_segflg,
+	char **, char **);
+void	exec_free_args(struct image_args *);
 #endif
 
 #endif /* !_SYS_IMGACT_H_ */
Index: sys/kern_syscall.h
===================================================================
RCS file: /nfs/daver/cvs-repos/cvs-dragonflybsd/src/sys/sys/kern_syscall.h,v
retrieving revision 1.11
diff -u -u -r1.11 kern_syscall.h
--- sys/kern_syscall.h	10 Nov 2003 20:57:17 -0000	1.11
+++ sys/kern_syscall.h	11 Nov 2003 06:26:56 -0000
@@ -33,6 +33,7 @@
 
 enum dup_type {DUP_FIXED, DUP_VARIABLE};
 union fcntl_dat;
+struct image_args;
 struct mbuf;
 struct msghdr;
 struct nameidata;
@@ -57,6 +58,11 @@
 int kern_dup(enum dup_type type, int old, int new, int *res);
 int kern_fcntl(int fd, int cmd, union fcntl_dat *dat);
 int kern_fstat(int fd, struct stat *st);
+
+/*
+ * Prototypes for syscalls in kern/kern_exec.c
+ */
+int kern_execve(struct nameidata *nd, struct image_args *args);
 
 /*
  * Prototypes for syscalls in kern/kern_exit.c

