2 * Copyright (c) 1992 William Jolitz. All rights reserved.
3 * Written by William Jolitz 1/92
5 * Redistribution and use in source and binary forms are freely permitted
6 * provided that the above copyright notice and attribution and date of work
7 * and this paragraph are duplicated in all such forms.
8 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
9 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
10 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
12 * This procedure implements a minimal program execution facility for
13 * 386BSD. It interfaces to the BSD kernel as the execve system call.
14 * Significant limitations and lack of compatiblity with POSIX are
15 * present with this version, to make its basic operation more clear.
29 #include "signalvar.h"
33 #include "vm/vm_param.h"
34 #include "vm/vm_map.h"
35 #include "vm/vm_kern.h"
37 #include "machine/reg.h"
39 static char rcsid[] = "$Header: /pub/NetBSD/misc/repositories/cvsroot/src/sys/kern/Attic/kern_execve,v 1.1 1993/03/21 09:46:30 cgd Exp $";
42 * Bill's first-cut execve() system call. Puts hair on your chest.
46 execve(p, uap, retval)
48 register struct args {
55 register struct nameidata *ndp;
59 char **kargbuf, **kargbufp, *kstringbuf, *kstringbufp;
60 char **org, **vectp, *ep;
61 u_int needsenv, limitonargs, stringlen;
67 int tsize, dsize, bsize, cnt, foff;
70 * Step 1. Lookup filename to see if we have something to execute.
73 ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
74 ndp->ni_segflg = UIO_USERSPACE;
75 ndp->ni_dirp = uap->fname;
78 if (rv = namei(ndp, p))
81 /* is it a regular file? */
82 if (ndp->ni_vp->v_type != VREG) {
87 /* is it executable? */
88 rv = VOP_ACCESS(ndp->ni_vp, VEXEC, p->p_ucred, p);
92 rv = vn_stat(ndp->ni_vp, &statb, p);
97 * Step 2. Does the file contain a format we can
98 * understand and execute
100 rv = vn_rdwr(UIO_READ, ndp->ni_vp, (caddr_t)&hdr, sizeof(hdr),
101 0, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &amt, p);
103 /* big enough to hold a header? */
107 /* that we recognize? */
109 if (hdr.a_magic != ZMAGIC)
112 /* sanity check "ain't not such thing as a sanity clause" -groucho */
113 if (/*hdr.a_text == 0 || */ hdr.a_text > MAXTSIZ
114 || hdr.a_text % NBPG || hdr.a_text > statb.st_size)
117 if (hdr.a_data == 0 || hdr.a_data > DFLDSIZ
118 || hdr.a_data > statb.st_size
119 || hdr.a_data + hdr.a_text > statb.st_size)
122 if (hdr.a_bss > MAXDSIZ)
125 if (hdr.a_text + hdr.a_data + hdr.a_bss > MAXTSIZ + MAXDSIZ)
129 * Step 3. File and header are valid. Now, dig out the strings
130 * out of the old process image.
133 /* assumption: most execve's have less than 256 arguments, with a
134 * total of string storage space not exceeding 2K. It is more
135 * frequent that when this fails, string space falls short first
136 * (e.g. as when a large termcap environment variable is present).
137 * It is infrequent when more than 256 arguments are used that take
138 * up less than 2K of space (e.g. args average more than 8 chars).
140 * What we give up in this implementation is a dense encoding of
141 * the data structure in the receiving program's address space.
142 * This means that there is plenty of wasted space (up to 6KB)
143 * as the price we pay for a fast, single pass algorithm.
145 * Our alternative would be to accumulate strings and pointers
146 * in the first pass, then, knowing the sizes and number of the
147 * strings, pack them neatly and tightly togeither in the second
148 * pass. This means two copies of the strings, and string copying
149 * is much of the cost of exec.
152 /* allocate string buffer and arg buffer */
153 org = kargbuf = (char **) kmem_alloc_wait(exec_map,
154 (NCARGS + PAGE_SIZE)/PAGE_SIZE);
155 kstringbuf = kstringbufp = ((char *)kargbuf) + NBPG/2;
156 kargbuf += NBPG/(4*sizeof(int));
165 /* for each envp, copy in string */
166 limitonargs = NCARGS;
167 if(vectp == 0) goto dont_bother;
169 /* did we outgrow initial argbuf, if so, die */
170 if (kargbufp == (char **)kstringbuf)
173 /* get an string pointer */
174 ep = (char *)fuword(vectp++);
175 if (ep == (char *)-1) {
180 /* if not null pointer, copy in string */
182 if (rv = copyinstr(ep, kstringbufp, limitonargs,
183 &stringlen)) goto exec_fail;
184 /* assume that strings usually all fit in last page */
185 *kargbufp = (char *)(kstringbufp - kstringbuf
186 + USRSTACK - NBPG + NBPG/2);
189 kstringbufp += stringlen;
190 limitonargs -= stringlen + sizeof(long);
193 limitonargs -= sizeof(long);
196 } while (limitonargs > 0);
199 if (limitonargs <= 0) {
211 kargbuf[-1] = (char *)argc;
214 * Step 4. Build the new processes image.
217 /* At this point, we are committed -- destroy old executable */
220 size = USRSTACK - addr;
221 /* blow away all address space */
222 rv = vm_deallocate(&vs->vm_map, addr, size, FALSE);
226 /* build a new address space */
228 if (hdr.a_text == 0) {
231 hdr.a_data += hdr.a_text;
233 tsize = roundup(hdr.a_text, NBPG);
236 dsize = roundup(hdr.a_data, NBPG);
237 bsize = roundup(hdr.a_bss + dsize, NBPG);
241 rv = vm_mmap(&vs->vm_map, &addr, tsize+dsize, VM_PROT_ALL,
242 MAP_FILE|MAP_COPY|MAP_FIXED, (caddr_t)ndp->ni_vp, foff);
246 /* r/w data, ro text */
249 rv = vm_protect(&vs->vm_map, addr, tsize, FALSE, VM_PROT_READ|VM_PROT_EXECUTE);
254 /* create anonymous memory region for bss */
255 addr = dsize + tsize;
256 rv = vm_allocate(&vs->vm_map, &addr, bsize, FALSE);
260 /* create anonymous memory region for stack */
261 addr = USRSTACK - MAXSSIZ;
262 rv = vm_allocate(&vs->vm_map, &addr, MAXSSIZ, FALSE);
267 * Step 5. Prepare process for execution.
270 /* touchup process information */
271 vs->vm_tsize = tsize/NBPG; /* text size (pages) XXX */
272 vs->vm_dsize = (dsize+bsize)/NBPG; /* data size (pages) XXX */
273 vs->vm_ssize = MAXSSIZ/NBPG; /* stack size (pages) */
274 vs->vm_taddr = 0; /* user virtual address of text XXX */
275 vs->vm_daddr = (caddr_t)tsize; /* user virtual address of data XXX */
276 /* user VA at max stack growth */
277 vs->vm_maxsaddr = (caddr_t)(USRSTACK - MAXSSIZ);
279 /* everything fits in a single page, no fixups, no more work */
280 /* (groan) due to bug in vm_map_copy, can't remap. copy for now. */
281 rv = copyout((caddr_t)org, (caddr_t)USRSTACK - NBPG, NBPG);
285 /* close files on exec, fixup signals */
289 p->p_regs[SP] = USRSTACK - NBPG + NBPG/4 - 4;
290 vs->vm_ssize = 1; /* stack size (pages) */
291 setregs(p, hdr.a_entry);
292 kmem_free_wakeup(exec_map, org, (NCARGS + PAGE_SIZE)/PAGE_SIZE);
301 /* untested and probably bogus */
302 kmem_free_wakeup(exec_map, org, (NCARGS + PAGE_SIZE)/PAGE_SIZE);
304 exit(p, W_EXITCODE(0, SIGABRT));