could have too many directories to examine
[unix-history] / usr / src / sys / kern / kern_exec.c
CommitLineData
da7c5cc6
KM
1/*
2 * Copyright (c) 1982 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
1daa95c7 6 * @(#)kern_exec.c 6.14 (Berkeley) %G%
da7c5cc6 7 */
28db9b87
SL
8
9#include "../machine/reg.h"
10#include "../machine/pte.h"
11#include "../machine/psl.h"
12
94368568
JB
13#include "param.h"
14#include "systm.h"
15#include "map.h"
16#include "dir.h"
17#include "user.h"
18#include "kernel.h"
19#include "proc.h"
20#include "buf.h"
21#include "inode.h"
22#include "seg.h"
23#include "vm.h"
24#include "text.h"
25#include "file.h"
26#include "uio.h"
27#include "acct.h"
28#include "exec.h"
28db9b87 29
e3d5bfde
SL
30#ifdef vax
31#include "../vax/mtpr.h"
32#endif
33
28db9b87
SL
34/*
35 * exec system call, with and without environments.
36 */
37struct execa {
38 char *fname;
39 char **argp;
40 char **envp;
41};
42
43execv()
44{
45 ((struct execa *)u.u_ap)->envp = NULL;
46 execve();
47}
48
49execve()
50{
51 register nc;
52 register char *cp;
53 register struct buf *bp;
54 register struct execa *uap;
f3aaea26 55 int na, ne, ucp, ap, len, cc;
28db9b87
SL
56 int indir, uid, gid;
57 char *sharg;
58 struct inode *ip;
59 swblk_t bno;
60 char cfname[MAXCOMLEN + 1];
9fd50f35 61#define SHSIZE 32
28db9b87 62 char cfarg[SHSIZE];
9fd50f35
SL
63 union {
64 char ex_shell[SHSIZE]; /* #! and name of interpreter */
65 struct exec ex_exec;
66 } exdata;
715baff1 67 register struct nameidata *ndp = &u.u_nd;
f3aaea26 68 int resid, error;
28db9b87 69
715baff1
KM
70 ndp->ni_nameiop = LOOKUP | FOLLOW;
71 ndp->ni_segflg = UIO_USERSPACE;
72 ndp->ni_dirp = ((struct execa *)u.u_ap)->fname;
73 if ((ip = namei(ndp)) == NULL)
28db9b87
SL
74 return;
75 bno = 0;
76 bp = 0;
77 indir = 0;
78 uid = u.u_uid;
79 gid = u.u_gid;
80 if (ip->i_mode & ISUID)
81 uid = ip->i_uid;
82 if (ip->i_mode & ISGID)
83 gid = ip->i_gid;
84
85 again:
86 if (access(ip, IEXEC))
87 goto bad;
88 if ((u.u_procp->p_flag&STRC) && access(ip, IREAD))
89 goto bad;
90 if ((ip->i_mode & IFMT) != IFREG ||
91 (ip->i_mode & (IEXEC|(IEXEC>>3)|(IEXEC>>6))) == 0) {
92 u.u_error = EACCES;
93 goto bad;
94 }
95
96 /*
f3aaea26 97 * Read in first few bytes of file for segment sizes, magic number:
28db9b87
SL
98 * 407 = plain executable
99 * 410 = RO text
100 * 413 = demand paged RO text
101 * Also an ASCII line beginning with #! is
102 * the file name of a ``shell'' and arguments may be prepended
103 * to the argument list if given here.
104 *
105 * SHELL NAMES ARE LIMITED IN LENGTH.
106 *
107 * ONLY ONE ARGUMENT MAY BE PASSED TO THE SHELL FROM
108 * THE ASCII LINE.
109 */
9fd50f35 110 exdata.ex_shell[0] = '\0'; /* for zero length files */
f3aaea26
SL
111 u.u_error = rdwri(UIO_READ, ip, (caddr_t)&exdata, sizeof (exdata),
112 0, 1, &resid);
28db9b87
SL
113 if (u.u_error)
114 goto bad;
28db9b87 115#ifndef lint
ce66cb03 116 if (resid > sizeof(exdata) - sizeof(exdata.ex_exec) &&
9fd50f35 117 exdata.ex_shell[0] != '#') {
28db9b87
SL
118 u.u_error = ENOEXEC;
119 goto bad;
120 }
121#endif
9fd50f35 122 switch (exdata.ex_exec.a_magic) {
28db9b87
SL
123
124 case 0407:
9fd50f35
SL
125 exdata.ex_exec.a_data += exdata.ex_exec.a_text;
126 exdata.ex_exec.a_text = 0;
28db9b87
SL
127 break;
128
129 case 0413:
130 case 0410:
9fd50f35 131 if (exdata.ex_exec.a_text == 0) {
28db9b87
SL
132 u.u_error = ENOEXEC;
133 goto bad;
134 }
135 break;
136
137 default:
9fd50f35
SL
138 if (exdata.ex_shell[0] != '#' ||
139 exdata.ex_shell[1] != '!' ||
28db9b87
SL
140 indir) {
141 u.u_error = ENOEXEC;
142 goto bad;
143 }
9fd50f35
SL
144 cp = &exdata.ex_shell[2]; /* skip "#!" */
145 while (cp < &exdata.ex_shell[SHSIZE]) {
28db9b87
SL
146 if (*cp == '\t')
147 *cp = ' ';
148 else if (*cp == '\n') {
149 *cp = '\0';
150 break;
151 }
152 cp++;
153 }
154 if (*cp != '\0') {
155 u.u_error = ENOEXEC;
156 goto bad;
157 }
9fd50f35 158 cp = &exdata.ex_shell[2];
28db9b87
SL
159 while (*cp == ' ')
160 cp++;
715baff1 161 ndp->ni_dirp = cp;
28db9b87
SL
162 while (*cp && *cp != ' ')
163 cp++;
ce66cb03 164 cfarg[0] = '\0';
28db9b87
SL
165 if (*cp) {
166 *cp++ = '\0';
167 while (*cp == ' ')
168 cp++;
ce66cb03 169 if (*cp)
28db9b87 170 bcopy((caddr_t)cp, (caddr_t)cfarg, SHSIZE);
28db9b87 171 }
28db9b87
SL
172 indir = 1;
173 iput(ip);
715baff1
KM
174 ndp->ni_nameiop = LOOKUP | FOLLOW;
175 ndp->ni_segflg = UIO_SYSSPACE;
176 ip = namei(ndp);
28db9b87
SL
177 if (ip == NULL)
178 return;
ce66cb03
MK
179 bcopy((caddr_t)ndp->ni_dent.d_name, (caddr_t)cfname,
180 MAXCOMLEN);
181 cfname[MAXCOMLEN] = '\0';
28db9b87
SL
182 goto again;
183 }
184
185 /*
186 * Collect arguments on "file" in swap space.
187 */
188 na = 0;
189 ne = 0;
190 nc = 0;
f3aaea26 191 cc = 0;
28db9b87 192 uap = (struct execa *)u.u_ap;
9fd50f35
SL
193 bno = rmalloc(argmap, (long)ctod(clrnd((int)btoc(NCARGS))));
194 if (bno == 0) {
d03b3d84 195 swkill(u.u_procp, "exec: no swap space");
28db9b87
SL
196 goto bad;
197 }
198 if (bno % CLSIZE)
199 panic("execa rmalloc");
f3aaea26
SL
200 /*
201 * Copy arguments into file in argdev area.
202 */
28db9b87
SL
203 if (uap->argp) for (;;) {
204 ap = NULL;
ce66cb03
MK
205 sharg = NULL;
206 if (indir && na == 0) {
207 sharg = cfname;
208 ap = (int)sharg;
209 uap->argp++; /* ignore argv[0] */
210 } else if (indir && (na == 1 && cfarg[0])) {
211 sharg = cfarg;
212 ap = (int)sharg;
213 } else if (indir && (na == 1 || na == 2 && cfarg[0]))
28db9b87
SL
214 ap = (int)uap->fname;
215 else if (uap->argp) {
216 ap = fuword((caddr_t)uap->argp);
217 uap->argp++;
218 }
f3aaea26 219 if (ap == NULL && uap->envp) {
28db9b87 220 uap->argp = NULL;
f3aaea26
SL
221 if ((ap = fuword((caddr_t)uap->envp)) != NULL)
222 uap->envp++, ne++;
28db9b87
SL
223 }
224 if (ap == NULL)
225 break;
226 na++;
f3aaea26 227 if (ap == -1) {
1daa95c7 228 u.u_error = EFAULT;
f3aaea26
SL
229 break;
230 }
28db9b87 231 do {
f3aaea26
SL
232 if (cc <= 0) {
233 /*
234 * We depend on NCARGS being a multiple of
235 * CLSIZE*NBPG. This way we need only check
236 * overflow before each buffer allocation.
237 */
238 if (nc >= NCARGS-1) {
239 error = E2BIG;
240 break;
241 }
28db9b87
SL
242 if (bp)
243 bdwrite(bp);
f3aaea26
SL
244 cc = CLSIZE*NBPG;
245 bp = getblk(argdev, bno + ctod(nc/NBPG), cc);
28db9b87
SL
246 cp = bp->b_un.b_addr;
247 }
ce66cb03 248 if (sharg) {
f3aaea26 249 error = copystr(sharg, cp, cc, &len);
ce66cb03
MK
250 sharg += len;
251 } else {
f3aaea26 252 error = copyinstr((caddr_t)ap, cp, cc, &len);
ce66cb03
MK
253 ap += len;
254 }
f3aaea26
SL
255 cp += len;
256 nc += len;
257 cc -= len;
258 } while (error == ENOENT);
259 if (error) {
260 u.u_error = error;
261 if (bp)
262 brelse(bp);
263 bp = 0;
264 goto badarg;
265 }
28db9b87
SL
266 }
267 if (bp)
268 bdwrite(bp);
269 bp = 0;
270 nc = (nc + NBPW-1) & ~(NBPW-1);
9fd50f35 271 getxfile(ip, &exdata.ex_exec, nc + (na+4)*NBPW, uid, gid);
28db9b87
SL
272 if (u.u_error) {
273badarg:
f3aaea26
SL
274 for (cc = 0; cc < nc; cc += CLSIZE*NBPG) {
275 bp = baddr(argdev, bno + ctod(cc/NBPG), CLSIZE*NBPG);
28db9b87
SL
276 if (bp) {
277 bp->b_flags |= B_AGE; /* throw away */
278 bp->b_flags &= ~B_DELWRI; /* cancel io */
279 brelse(bp);
280 bp = 0;
281 }
282 }
283 goto bad;
284 }
ce66cb03
MK
285 iput(ip);
286 ip = NULL;
28db9b87
SL
287
288 /*
f3aaea26 289 * Copy back arglist.
28db9b87
SL
290 */
291 ucp = USRSTACK - nc - NBPW;
292 ap = ucp - na*NBPW - 3*NBPW;
293 u.u_ar0[SP] = ap;
294 (void) suword((caddr_t)ap, na-ne);
295 nc = 0;
72d4f41a 296 cc = 0;
28db9b87
SL
297 for (;;) {
298 ap += NBPW;
f3aaea26 299 if (na == ne) {
28db9b87
SL
300 (void) suword((caddr_t)ap, 0);
301 ap += NBPW;
302 }
303 if (--na < 0)
304 break;
305 (void) suword((caddr_t)ap, ucp);
306 do {
72d4f41a 307 if (cc <= 0) {
28db9b87
SL
308 if (bp)
309 brelse(bp);
72d4f41a
SL
310 cc = CLSIZE*NBPG;
311 bp = bread(argdev, bno + ctod(nc / NBPG), cc);
28db9b87
SL
312 bp->b_flags |= B_AGE; /* throw away */
313 bp->b_flags &= ~B_DELWRI; /* cancel io */
314 cp = bp->b_un.b_addr;
315 }
72d4f41a
SL
316 error = copyoutstr(cp, (caddr_t)ucp, cc, &len);
317 ucp += len;
318 cp += len;
319 nc += len;
320 cc -= len;
321 } while (error == ENOENT);
322 if (error == EFAULT)
323 panic("exec: EFAULT");
28db9b87
SL
324 }
325 (void) suword((caddr_t)ap, 0);
ce66cb03
MK
326
327 /*
328 * Reset caught signals. Held signals
329 * remain held through p_sigmask.
330 */
331 while (u.u_procp->p_sigcatch) {
332 nc = ffs(u.u_procp->p_sigcatch);
333 u.u_procp->p_sigcatch &= ~sigmask(nc);
334 u.u_signal[nc] = SIG_DFL;
335 }
336 /*
337 * Reset stack state to the user stack.
338 * Clear set of signals caught on the signal stack.
339 */
340 u.u_onstack = 0;
341 u.u_sigsp = 0;
342 u.u_sigonstack = 0;
343
344 for (nc = u.u_lastfile; nc >= 0; --nc) {
345 if (u.u_pofile[nc] & UF_EXCLOSE) {
346 closef(u.u_ofile[nc]);
347 u.u_ofile[nc] = NULL;
348 u.u_pofile[nc] = 0;
349 }
350 u.u_pofile[nc] &= ~UF_MAPPED;
351 }
352 while (u.u_lastfile >= 0 && u.u_ofile[u.u_lastfile] == NULL)
353 u.u_lastfile--;
9fd50f35 354 setregs(exdata.ex_exec.a_entry);
715baff1
KM
355 /*
356 * Remember file name for accounting.
357 */
358 u.u_acflag &= ~AFORK;
ce66cb03
MK
359 if (indir)
360 bcopy((caddr_t)cfname, (caddr_t)u.u_comm, MAXCOMLEN);
361 else {
362 if (ndp->ni_dent.d_namlen > MAXCOMLEN)
363 ndp->ni_dent.d_namlen = MAXCOMLEN;
364 bcopy((caddr_t)ndp->ni_dent.d_name, (caddr_t)u.u_comm,
365 (unsigned)(ndp->ni_dent.d_namlen + 1));
366 }
28db9b87
SL
367bad:
368 if (bp)
369 brelse(bp);
370 if (bno)
371 rmfree(argmap, (long)ctod(clrnd((int) btoc(NCARGS))), bno);
ce66cb03
MK
372 if (ip)
373 iput(ip);
28db9b87
SL
374}
375
376/*
377 * Read in and set up memory for executed file.
378 */
9fd50f35 379getxfile(ip, ep, nargc, uid, gid)
28db9b87 380 register struct inode *ip;
9fd50f35 381 register struct exec *ep;
28db9b87
SL
382 int nargc, uid, gid;
383{
0c48b03e 384 size_t ts, ds, ids, uds, ss;
28db9b87
SL
385 int pagi;
386
9fd50f35 387 if (ep->a_magic == 0413)
28db9b87
SL
388 pagi = SPAGI;
389 else
390 pagi = 0;
ce08d752
MK
391 if (ip->i_flag & IXMOD) { /* XXX */
392 u.u_error = ETXTBSY;
393 goto bad;
394 }
9fd50f35
SL
395 if (ep->a_text != 0 && (ip->i_flag&ITEXT) == 0 &&
396 ip->i_count != 1) {
28db9b87
SL
397 register struct file *fp;
398
399 for (fp = file; fp < fileNFILE; fp++) {
400 if (fp->f_type == DTYPE_INODE &&
401 fp->f_count > 0 &&
402 (struct inode *)fp->f_data == ip &&
403 (fp->f_flag&FWRITE)) {
404 u.u_error = ETXTBSY;
405 goto bad;
406 }
407 }
408 }
409
410 /*
411 * Compute text and data sizes and make sure not too large.
0c48b03e
KM
412 * NB - Check data and bss separately as they may overflow
413 * when summed together.
28db9b87 414 */
9fd50f35 415 ts = clrnd(btoc(ep->a_text));
0c48b03e
KM
416 ids = clrnd(btoc(ep->a_data));
417 uds = clrnd(btoc(ep->a_bss));
f3aaea26 418 ds = clrnd(btoc(ep->a_data + ep->a_bss));
28db9b87 419 ss = clrnd(SSIZE + btoc(nargc));
0c48b03e 420 if (chksize((unsigned)ts, (unsigned)ids, (unsigned)uds, (unsigned)ss))
28db9b87
SL
421 goto bad;
422
423 /*
424 * Make sure enough space to start process.
425 */
426 u.u_cdmap = zdmap;
427 u.u_csmap = zdmap;
428 if (swpexpand(ds, ss, &u.u_cdmap, &u.u_csmap) == NULL)
429 goto bad;
430
431 /*
432 * At this point, committed to the new image!
433 * Release virtual memory resources of old process, and
434 * initialize the virtual memory of the new process.
435 * If we resulted from vfork(), instead wakeup our
436 * parent who will set SVFDONE when he has taken back
437 * our resources.
438 */
439 if ((u.u_procp->p_flag & SVFORK) == 0)
440 vrelvm();
441 else {
442 u.u_procp->p_flag &= ~SVFORK;
443 u.u_procp->p_flag |= SKEEP;
444 wakeup((caddr_t)u.u_procp);
445 while ((u.u_procp->p_flag & SVFDONE) == 0)
446 sleep((caddr_t)u.u_procp, PZERO - 1);
447 u.u_procp->p_flag &= ~(SVFDONE|SKEEP);
448 }
dd012d1e 449 u.u_procp->p_flag &= ~(SPAGI|SSEQL|SUANOM|SOUSIG);
28db9b87
SL
450 u.u_procp->p_flag |= pagi;
451 u.u_dmap = u.u_cdmap;
452 u.u_smap = u.u_csmap;
453 vgetvm(ts, ds, ss);
454
455 if (pagi == 0)
456 u.u_error =
457 rdwri(UIO_READ, ip,
458 (char *)ctob(dptov(u.u_procp, 0)),
9fd50f35
SL
459 (int)ep->a_data,
460 (int)(sizeof (struct exec) + ep->a_text),
28db9b87 461 0, (int *)0);
9fd50f35 462 xalloc(ip, ep, pagi);
28db9b87
SL
463 if (pagi && u.u_procp->p_textp)
464 vinifod((struct fpte *)dptopte(u.u_procp, 0),
465 PG_FTEXT, u.u_procp->p_textp->x_iptr,
9fd50f35 466 (long)(1 + ts/CLSIZE), (int)btoc(ep->a_data));
28db9b87
SL
467
468#ifdef vax
469 /* THIS SHOULD BE DONE AT A LOWER LEVEL, IF AT ALL */
28db9b87
SL
470 mtpr(TBIA, 0);
471#endif
472
473 if (u.u_error)
d03b3d84 474 swkill(u.u_procp, "exec: I/O error mapping pages");
28db9b87
SL
475 /*
476 * set SUID/SGID protections, if no tracing
477 */
478 if ((u.u_procp->p_flag&STRC)==0) {
479 u.u_uid = uid;
480 u.u_procp->p_uid = uid;
481 u.u_gid = gid;
482 } else
483 psignal(u.u_procp, SIGTRAP);
484 u.u_tsize = ts;
485 u.u_dsize = ds;
486 u.u_ssize = ss;
d4a03a57 487 u.u_prof.pr_scale = 0;
28db9b87
SL
488bad:
489 return;
490}