don't feather, removes stuff like rogue .o's
[unix-history] / usr / src / sys / kern / kern_exec.c
CommitLineData
b11be056 1/* kern_exec.c 6.1 83/07/29 */
28db9b87
SL
2
3#include "../machine/reg.h"
4#include "../machine/pte.h"
5#include "../machine/psl.h"
6
7#include "../h/param.h"
8#include "../h/systm.h"
9#include "../h/map.h"
10#include "../h/dir.h"
11#include "../h/user.h"
12#include "../h/kernel.h"
13#include "../h/proc.h"
14#include "../h/buf.h"
15#include "../h/inode.h"
16#include "../h/seg.h"
17#include "../h/vm.h"
18#include "../h/text.h"
19#include "../h/file.h"
20#include "../h/uio.h"
21#include "../h/nami.h"
22#include "../h/acct.h"
23
e3d5bfde
SL
24#ifdef vax
25#include "../vax/mtpr.h"
26#endif
27
28db9b87
SL
28/*
29 * exec system call, with and without environments.
30 */
31struct execa {
32 char *fname;
33 char **argp;
34 char **envp;
35};
36
37execv()
38{
39 ((struct execa *)u.u_ap)->envp = NULL;
40 execve();
41}
42
43execve()
44{
45 register nc;
46 register char *cp;
47 register struct buf *bp;
48 register struct execa *uap;
49 int na, ne, ucp, ap, c;
50 int indir, uid, gid;
51 char *sharg;
52 struct inode *ip;
53 swblk_t bno;
54 char cfname[MAXCOMLEN + 1];
55 char cfarg[SHSIZE];
56 int resid;
57
58 if ((ip = namei(uchar, LOOKUP, 1)) == NULL)
59 return;
60 bno = 0;
61 bp = 0;
62 indir = 0;
63 uid = u.u_uid;
64 gid = u.u_gid;
65 if (ip->i_mode & ISUID)
66 uid = ip->i_uid;
67 if (ip->i_mode & ISGID)
68 gid = ip->i_gid;
69
70 again:
71 if (access(ip, IEXEC))
72 goto bad;
73 if ((u.u_procp->p_flag&STRC) && access(ip, IREAD))
74 goto bad;
75 if ((ip->i_mode & IFMT) != IFREG ||
76 (ip->i_mode & (IEXEC|(IEXEC>>3)|(IEXEC>>6))) == 0) {
77 u.u_error = EACCES;
78 goto bad;
79 }
80
81 /*
82 * Read in first few bytes of file for segment sizes, ux_mag:
83 * 407 = plain executable
84 * 410 = RO text
85 * 413 = demand paged RO text
86 * Also an ASCII line beginning with #! is
87 * the file name of a ``shell'' and arguments may be prepended
88 * to the argument list if given here.
89 *
90 * SHELL NAMES ARE LIMITED IN LENGTH.
91 *
92 * ONLY ONE ARGUMENT MAY BE PASSED TO THE SHELL FROM
93 * THE ASCII LINE.
94 */
95 u.u_exdata.ux_shell[0] = 0; /* for zero length files */
96 u.u_error = rdwri(UIO_READ, ip, (caddr_t)&u.u_exdata, sizeof (u.u_exdata),
97 0, 1, &resid);
98 if (u.u_error)
99 goto bad;
100 u.u_count = resid;
101#ifndef lint
102 if (u.u_count > sizeof(u.u_exdata) - sizeof(u.u_exdata.Ux_A) &&
103 u.u_exdata.ux_shell[0] != '#') {
104 u.u_error = ENOEXEC;
105 goto bad;
106 }
107#endif
108 switch (u.u_exdata.ux_mag) {
109
110 case 0407:
111 u.u_exdata.ux_dsize += u.u_exdata.ux_tsize;
112 u.u_exdata.ux_tsize = 0;
113 break;
114
115 case 0413:
116 case 0410:
117 if (u.u_exdata.ux_tsize == 0) {
118 u.u_error = ENOEXEC;
119 goto bad;
120 }
121 break;
122
123 default:
124 if (u.u_exdata.ux_shell[0] != '#' ||
125 u.u_exdata.ux_shell[1] != '!' ||
126 indir) {
127 u.u_error = ENOEXEC;
128 goto bad;
129 }
130 cp = &u.u_exdata.ux_shell[2]; /* skip "#!" */
131 while (cp < &u.u_exdata.ux_shell[SHSIZE]) {
132 if (*cp == '\t')
133 *cp = ' ';
134 else if (*cp == '\n') {
135 *cp = '\0';
136 break;
137 }
138 cp++;
139 }
140 if (*cp != '\0') {
141 u.u_error = ENOEXEC;
142 goto bad;
143 }
144 cp = &u.u_exdata.ux_shell[2];
145 while (*cp == ' ')
146 cp++;
147 u.u_dirp = cp;
148 while (*cp && *cp != ' ')
149 cp++;
150 sharg = NULL;
151 if (*cp) {
152 *cp++ = '\0';
153 while (*cp == ' ')
154 cp++;
155 if (*cp) {
156 bcopy((caddr_t)cp, (caddr_t)cfarg, SHSIZE);
157 sharg = cfarg;
158 }
159 }
160 if (u.u_dent.d_namlen > MAXCOMLEN)
161 u.u_dent.d_namlen = MAXCOMLEN;
162 bcopy((caddr_t)u.u_dent.d_name, (caddr_t)cfname,
163 (unsigned)(u.u_dent.d_namlen + 1));
164 cfname[MAXCOMLEN] = 0;
165 indir = 1;
166 iput(ip);
167 ip = namei(schar, LOOKUP, 1);
168 if (ip == NULL)
169 return;
170 goto again;
171 }
172
173 /*
174 * Collect arguments on "file" in swap space.
175 */
176 na = 0;
177 ne = 0;
178 nc = 0;
179 uap = (struct execa *)u.u_ap;
180 if ((bno = rmalloc(argmap, (long)ctod(clrnd((int)btoc(NCARGS))))) == 0) {
181 swkill(u.u_procp, "exece");
182 goto bad;
183 }
184 if (bno % CLSIZE)
185 panic("execa rmalloc");
186 if (uap->argp) for (;;) {
187 ap = NULL;
188 if (indir && (na == 1 || na == 2 && sharg))
189 ap = (int)uap->fname;
190 else if (uap->argp) {
191 ap = fuword((caddr_t)uap->argp);
192 uap->argp++;
193 }
194 if (ap==NULL && uap->envp) {
195 uap->argp = NULL;
196 if ((ap = fuword((caddr_t)uap->envp)) == NULL)
197 break;
198 uap->envp++;
199 ne++;
200 }
201 if (ap == NULL)
202 break;
203 na++;
204 if (ap == -1)
205 u.u_error = EFAULT;
206 do {
207 if (nc >= NCARGS-1)
208 u.u_error = E2BIG;
209 if (indir && na == 2 && sharg != NULL)
210 c = *sharg++ & 0377;
211 else if ((c = fubyte((caddr_t)ap++)) < 0)
212 u.u_error = EFAULT;
213 if (u.u_error) {
214 if (bp)
215 brelse(bp);
216 bp = 0;
217 goto badarg;
218 }
219 if (nc % (CLSIZE*NBPG) == 0) {
220 if (bp)
221 bdwrite(bp);
222 bp = getblk(argdev, bno + ctod(nc / NBPG),
223 CLSIZE*NBPG);
224 cp = bp->b_un.b_addr;
225 }
226 nc++;
227 *cp++ = c;
228 } while (c > 0);
229 }
230 if (bp)
231 bdwrite(bp);
232 bp = 0;
233 nc = (nc + NBPW-1) & ~(NBPW-1);
234 if (indir) {
235 u.u_dent.d_namlen = strlen(cfname);
236 bcopy((caddr_t)cfname, (caddr_t)u.u_dent.d_name,
237 (unsigned)(u.u_dent.d_namlen + 1));
238 }
239 getxfile(ip, nc + (na+4)*NBPW, uid, gid);
240 if (u.u_error) {
241badarg:
242 for (c = 0; c < nc; c += CLSIZE*NBPG) {
243 bp = baddr(argdev, bno + ctod(c / NBPG), CLSIZE*NBPG);
244 if (bp) {
245 bp->b_flags |= B_AGE; /* throw away */
246 bp->b_flags &= ~B_DELWRI; /* cancel io */
247 brelse(bp);
248 bp = 0;
249 }
250 }
251 goto bad;
252 }
253
254 /*
255 * copy back arglist
256 */
257 ucp = USRSTACK - nc - NBPW;
258 ap = ucp - na*NBPW - 3*NBPW;
259 u.u_ar0[SP] = ap;
260 (void) suword((caddr_t)ap, na-ne);
261 nc = 0;
262 for (;;) {
263 ap += NBPW;
264 if (na==ne) {
265 (void) suword((caddr_t)ap, 0);
266 ap += NBPW;
267 }
268 if (--na < 0)
269 break;
270 (void) suword((caddr_t)ap, ucp);
271 do {
272 if (nc % (CLSIZE*NBPG) == 0) {
273 if (bp)
274 brelse(bp);
275 bp = bread(argdev, bno + ctod(nc / NBPG),
276 CLSIZE*NBPG);
277 bp->b_flags |= B_AGE; /* throw away */
278 bp->b_flags &= ~B_DELWRI; /* cancel io */
279 cp = bp->b_un.b_addr;
280 }
281 (void) subyte((caddr_t)ucp++, (c = *cp++));
282 nc++;
283 } while(c&0377);
284 }
285 (void) suword((caddr_t)ap, 0);
286 setregs();
287bad:
288 if (bp)
289 brelse(bp);
290 if (bno)
291 rmfree(argmap, (long)ctod(clrnd((int) btoc(NCARGS))), bno);
292 iput(ip);
293}
294
295/*
296 * Read in and set up memory for executed file.
297 */
298getxfile(ip, nargc, uid, gid)
299 register struct inode *ip;
300 int nargc, uid, gid;
301{
302 register size_t ts, ds, ss;
303 int pagi;
304
305 if (u.u_exdata.ux_mag == 0413)
306 pagi = SPAGI;
307 else
308 pagi = 0;
309 if (u.u_exdata.ux_tsize!=0 && (ip->i_flag&ITEXT)==0 &&
310 ip->i_count!=1) {
311 register struct file *fp;
312
313 for (fp = file; fp < fileNFILE; fp++) {
314 if (fp->f_type == DTYPE_INODE &&
315 fp->f_count > 0 &&
316 (struct inode *)fp->f_data == ip &&
317 (fp->f_flag&FWRITE)) {
318 u.u_error = ETXTBSY;
319 goto bad;
320 }
321 }
322 }
323
324 /*
325 * Compute text and data sizes and make sure not too large.
326 */
327 ts = clrnd(btoc(u.u_exdata.ux_tsize));
328 ds = clrnd(btoc((u.u_exdata.ux_dsize+u.u_exdata.ux_bsize)));
329 ss = clrnd(SSIZE + btoc(nargc));
330 if (chksize((unsigned)ts, (unsigned)ds, (unsigned)ss))
331 goto bad;
332
333 /*
334 * Make sure enough space to start process.
335 */
336 u.u_cdmap = zdmap;
337 u.u_csmap = zdmap;
338 if (swpexpand(ds, ss, &u.u_cdmap, &u.u_csmap) == NULL)
339 goto bad;
340
341 /*
342 * At this point, committed to the new image!
343 * Release virtual memory resources of old process, and
344 * initialize the virtual memory of the new process.
345 * If we resulted from vfork(), instead wakeup our
346 * parent who will set SVFDONE when he has taken back
347 * our resources.
348 */
349 if ((u.u_procp->p_flag & SVFORK) == 0)
350 vrelvm();
351 else {
352 u.u_procp->p_flag &= ~SVFORK;
353 u.u_procp->p_flag |= SKEEP;
354 wakeup((caddr_t)u.u_procp);
355 while ((u.u_procp->p_flag & SVFDONE) == 0)
356 sleep((caddr_t)u.u_procp, PZERO - 1);
357 u.u_procp->p_flag &= ~(SVFDONE|SKEEP);
358 }
dd012d1e 359 u.u_procp->p_flag &= ~(SPAGI|SSEQL|SUANOM|SOUSIG);
28db9b87
SL
360 u.u_procp->p_flag |= pagi;
361 u.u_dmap = u.u_cdmap;
362 u.u_smap = u.u_csmap;
363 vgetvm(ts, ds, ss);
364
365 if (pagi == 0)
366 u.u_error =
367 rdwri(UIO_READ, ip,
368 (char *)ctob(dptov(u.u_procp, 0)),
369 (int)u.u_exdata.ux_dsize,
370 (int)(sizeof(u.u_exdata)+u.u_exdata.ux_tsize),
371 0, (int *)0);
372 xalloc(ip, pagi);
373 if (pagi && u.u_procp->p_textp)
374 vinifod((struct fpte *)dptopte(u.u_procp, 0),
375 PG_FTEXT, u.u_procp->p_textp->x_iptr,
376 (long)(1 + ts/CLSIZE), (int)btoc(u.u_exdata.ux_dsize));
377
378#ifdef vax
379 /* THIS SHOULD BE DONE AT A LOWER LEVEL, IF AT ALL */
28db9b87
SL
380 mtpr(TBIA, 0);
381#endif
382
383 if (u.u_error)
384 swkill(u.u_procp, "i/o error mapping pages");
385 /*
386 * set SUID/SGID protections, if no tracing
387 */
388 if ((u.u_procp->p_flag&STRC)==0) {
389 u.u_uid = uid;
390 u.u_procp->p_uid = uid;
391 u.u_gid = gid;
392 } else
393 psignal(u.u_procp, SIGTRAP);
394 u.u_tsize = ts;
395 u.u_dsize = ds;
396 u.u_ssize = ss;
397bad:
398 return;
399}
400
401/*
402 * Clear registers on exec
403 */
404setregs()
405{
a30e6d48 406 register int i;
dd012d1e 407 register struct proc *p = u.u_procp;
28db9b87 408
a30e6d48
SL
409 /*
410 * Reset caught signals. Held signals
411 * remain held through p_sigmask.
412 */
413 while (p->p_sigcatch) {
414 (void) spl6();
415 i = ffs(p->p_sigcatch);
416 p->p_sigcatch &= ~(1 << (i - 1));
417 u.u_signal[i] = SIG_DFL;
418 (void) spl0();
419 }
a30e6d48
SL
420#ifdef notdef
421 /* should pass args to init on the stack */
28db9b87
SL
422 for (rp = &u.u_ar0[0]; rp < &u.u_ar0[16];)
423 *rp++ = 0;
a30e6d48 424#endif
28db9b87 425 u.u_ar0[PC] = u.u_exdata.ux_entloc+2;
28db9b87
SL
426 for (i=0; i<NOFILE; i++) {
427 if (u.u_pofile[i]&UF_EXCLOSE) {
55dfda24 428 closef(u.u_ofile[i]);
28db9b87
SL
429 u.u_ofile[i] = NULL;
430 u.u_pofile[i] = 0;
431 }
432 u.u_pofile[i] &= ~UF_MAPPED;
433 }
434
435 /*
436 * Remember file name for accounting.
437 */
438 u.u_acflag &= ~AFORK;
439 bcopy((caddr_t)u.u_dent.d_name, (caddr_t)u.u_comm,
440 (unsigned)(u.u_dent.d_namlen + 1));
28db9b87 441}