print errno if init exec fails
[unix-history] / usr / src / sys / kern / kern_exec.c
CommitLineData
da7c5cc6 1/*
0880b18e 2 * Copyright (c) 1982, 1986 Regents of the University of California.
da7c5cc6
KM
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
609e7cfa 6 * @(#)kern_exec.c 7.4 (Berkeley) %G%
da7c5cc6 7 */
28db9b87
SL
8
9#include "../machine/reg.h"
10#include "../machine/pte.h"
11#include "../machine/psl.h"
fb1db32c 12#include "../machine/mtpr.h"
28db9b87 13
94368568
JB
14#include "param.h"
15#include "systm.h"
16#include "map.h"
17#include "dir.h"
18#include "user.h"
19#include "kernel.h"
20#include "proc.h"
21#include "buf.h"
22#include "inode.h"
23#include "seg.h"
24#include "vm.h"
25#include "text.h"
26#include "file.h"
27#include "uio.h"
28#include "acct.h"
29#include "exec.h"
28db9b87
SL
30
31/*
32 * exec system call, with and without environments.
33 */
34struct execa {
35 char *fname;
36 char **argp;
37 char **envp;
38};
39
40execv()
41{
42 ((struct execa *)u.u_ap)->envp = NULL;
43 execve();
44}
45
46execve()
47{
48 register nc;
49 register char *cp;
50 register struct buf *bp;
51 register struct execa *uap;
8011f5df
MK
52 int na, ne, ucp, ap, cc;
53 unsigned len;
28db9b87
SL
54 int indir, uid, gid;
55 char *sharg;
56 struct inode *ip;
57 swblk_t bno;
58 char cfname[MAXCOMLEN + 1];
cb9392ae 59 char cfarg[MAXINTERP];
9fd50f35 60 union {
cb9392ae 61 char ex_shell[MAXINTERP]; /* #! and interpreter name */
9fd50f35
SL
62 struct exec ex_exec;
63 } exdata;
715baff1 64 register struct nameidata *ndp = &u.u_nd;
f3aaea26 65 int resid, error;
ec67a3ce
MK
66#ifdef SECSIZE
67 extern long argdbsize; /* XXX */
68#endif SECSIZE
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 111 u.u_error = rdwri(UIO_READ, ip, (caddr_t)&exdata, sizeof (exdata),
8011f5df 112 (off_t)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
aec7dd3b 122 switch ((int)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 144 cp = &exdata.ex_shell[2]; /* skip "#!" */
cb9392ae 145 while (cp < &exdata.ex_shell[MAXINTERP]) {
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)
cb9392ae 170 bcopy((caddr_t)cp, (caddr_t)cfarg, MAXINTERP);
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;
ec67a3ce
MK
193#ifdef SECSIZE
194 bno = rmalloc(argmap, (clrnd((int)btoc(NCARGS))) * CLBYTES / argdbsize);
195#else SECSIZE
9fd50f35 196 bno = rmalloc(argmap, (long)ctod(clrnd((int)btoc(NCARGS))));
ec67a3ce 197#endif SECSIZE
9fd50f35 198 if (bno == 0) {
d03b3d84 199 swkill(u.u_procp, "exec: no swap space");
28db9b87
SL
200 goto bad;
201 }
202 if (bno % CLSIZE)
203 panic("execa rmalloc");
f3aaea26
SL
204 /*
205 * Copy arguments into file in argdev area.
206 */
28db9b87
SL
207 if (uap->argp) for (;;) {
208 ap = NULL;
ce66cb03
MK
209 sharg = NULL;
210 if (indir && na == 0) {
211 sharg = cfname;
212 ap = (int)sharg;
213 uap->argp++; /* ignore argv[0] */
214 } else if (indir && (na == 1 && cfarg[0])) {
215 sharg = cfarg;
216 ap = (int)sharg;
217 } else if (indir && (na == 1 || na == 2 && cfarg[0]))
28db9b87
SL
218 ap = (int)uap->fname;
219 else if (uap->argp) {
220 ap = fuword((caddr_t)uap->argp);
221 uap->argp++;
222 }
f3aaea26 223 if (ap == NULL && uap->envp) {
28db9b87 224 uap->argp = NULL;
f3aaea26
SL
225 if ((ap = fuword((caddr_t)uap->envp)) != NULL)
226 uap->envp++, ne++;
28db9b87
SL
227 }
228 if (ap == NULL)
229 break;
230 na++;
f3aaea26 231 if (ap == -1) {
1daa95c7 232 u.u_error = EFAULT;
f3aaea26
SL
233 break;
234 }
28db9b87 235 do {
f3aaea26
SL
236 if (cc <= 0) {
237 /*
238 * We depend on NCARGS being a multiple of
ec67a3ce 239 * CLBYTES. This way we need only check
f3aaea26
SL
240 * overflow before each buffer allocation.
241 */
242 if (nc >= NCARGS-1) {
243 error = E2BIG;
244 break;
245 }
28db9b87
SL
246 if (bp)
247 bdwrite(bp);
ec67a3ce
MK
248 cc = CLBYTES;
249#ifdef SECSIZE
250 bp = getblk(argdev, bno + nc / argdbsize, cc,
251 argdbsize);
252#else SECSIZE
f3aaea26 253 bp = getblk(argdev, bno + ctod(nc/NBPG), cc);
ec67a3ce 254#endif SECSIZE
28db9b87
SL
255 cp = bp->b_un.b_addr;
256 }
ce66cb03 257 if (sharg) {
8011f5df 258 error = copystr(sharg, cp, (unsigned)cc, &len);
ce66cb03
MK
259 sharg += len;
260 } else {
8011f5df
MK
261 error = copyinstr((caddr_t)ap, cp, (unsigned)cc,
262 &len);
ce66cb03
MK
263 ap += len;
264 }
f3aaea26
SL
265 cp += len;
266 nc += len;
267 cc -= len;
268 } while (error == ENOENT);
269 if (error) {
270 u.u_error = error;
271 if (bp)
272 brelse(bp);
273 bp = 0;
274 goto badarg;
275 }
28db9b87
SL
276 }
277 if (bp)
278 bdwrite(bp);
279 bp = 0;
280 nc = (nc + NBPW-1) & ~(NBPW-1);
9fd50f35 281 getxfile(ip, &exdata.ex_exec, nc + (na+4)*NBPW, uid, gid);
28db9b87
SL
282 if (u.u_error) {
283badarg:
f3aaea26 284 for (cc = 0; cc < nc; cc += CLSIZE*NBPG) {
ec67a3ce
MK
285#ifdef SECSIZE
286 bp = baddr(argdev, bno + cc / argdbsize, CLSIZE*NBPG,
287 argdbsize);
288#else SECSIZE
f3aaea26 289 bp = baddr(argdev, bno + ctod(cc/NBPG), CLSIZE*NBPG);
ec67a3ce 290#endif SECSIZE
28db9b87
SL
291 if (bp) {
292 bp->b_flags |= B_AGE; /* throw away */
293 bp->b_flags &= ~B_DELWRI; /* cancel io */
294 brelse(bp);
295 bp = 0;
296 }
297 }
298 goto bad;
299 }
ce66cb03
MK
300 iput(ip);
301 ip = NULL;
28db9b87
SL
302
303 /*
f3aaea26 304 * Copy back arglist.
28db9b87
SL
305 */
306 ucp = USRSTACK - nc - NBPW;
307 ap = ucp - na*NBPW - 3*NBPW;
308 u.u_ar0[SP] = ap;
309 (void) suword((caddr_t)ap, na-ne);
310 nc = 0;
72d4f41a 311 cc = 0;
28db9b87
SL
312 for (;;) {
313 ap += NBPW;
f3aaea26 314 if (na == ne) {
28db9b87
SL
315 (void) suword((caddr_t)ap, 0);
316 ap += NBPW;
317 }
318 if (--na < 0)
319 break;
320 (void) suword((caddr_t)ap, ucp);
321 do {
72d4f41a 322 if (cc <= 0) {
28db9b87
SL
323 if (bp)
324 brelse(bp);
ec67a3ce
MK
325 cc = CLBYTES;
326#ifdef SECSIZE
327 bp = bread(argdev, bno + nc / argdbsize, cc,
328 argdbsize);
329#else SECSIZE
72d4f41a 330 bp = bread(argdev, bno + ctod(nc / NBPG), cc);
ec67a3ce 331#endif SECSIZE
28db9b87
SL
332 bp->b_flags |= B_AGE; /* throw away */
333 bp->b_flags &= ~B_DELWRI; /* cancel io */
334 cp = bp->b_un.b_addr;
335 }
8011f5df
MK
336 error = copyoutstr(cp, (caddr_t)ucp, (unsigned)cc,
337 &len);
72d4f41a
SL
338 ucp += len;
339 cp += len;
340 nc += len;
341 cc -= len;
342 } while (error == ENOENT);
343 if (error == EFAULT)
344 panic("exec: EFAULT");
28db9b87
SL
345 }
346 (void) suword((caddr_t)ap, 0);
ce66cb03
MK
347
348 /*
349 * Reset caught signals. Held signals
350 * remain held through p_sigmask.
351 */
352 while (u.u_procp->p_sigcatch) {
8011f5df 353 nc = ffs((long)u.u_procp->p_sigcatch);
ce66cb03
MK
354 u.u_procp->p_sigcatch &= ~sigmask(nc);
355 u.u_signal[nc] = SIG_DFL;
356 }
357 /*
358 * Reset stack state to the user stack.
359 * Clear set of signals caught on the signal stack.
360 */
361 u.u_onstack = 0;
362 u.u_sigsp = 0;
363 u.u_sigonstack = 0;
364
365 for (nc = u.u_lastfile; nc >= 0; --nc) {
366 if (u.u_pofile[nc] & UF_EXCLOSE) {
367 closef(u.u_ofile[nc]);
368 u.u_ofile[nc] = NULL;
369 u.u_pofile[nc] = 0;
370 }
371 u.u_pofile[nc] &= ~UF_MAPPED;
372 }
373 while (u.u_lastfile >= 0 && u.u_ofile[u.u_lastfile] == NULL)
374 u.u_lastfile--;
9fd50f35 375 setregs(exdata.ex_exec.a_entry);
715baff1
KM
376 /*
377 * Remember file name for accounting.
378 */
379 u.u_acflag &= ~AFORK;
ce66cb03
MK
380 if (indir)
381 bcopy((caddr_t)cfname, (caddr_t)u.u_comm, MAXCOMLEN);
382 else {
383 if (ndp->ni_dent.d_namlen > MAXCOMLEN)
384 ndp->ni_dent.d_namlen = MAXCOMLEN;
385 bcopy((caddr_t)ndp->ni_dent.d_name, (caddr_t)u.u_comm,
386 (unsigned)(ndp->ni_dent.d_namlen + 1));
387 }
28db9b87
SL
388bad:
389 if (bp)
390 brelse(bp);
391 if (bno)
ec67a3ce
MK
392#ifdef SECSIZE
393 rmfree(argmap, (clrnd((int)btoc(NCARGS))) * CLBYTES / argdbsize,
394 bno);
395#else SECSIZE
28db9b87 396 rmfree(argmap, (long)ctod(clrnd((int) btoc(NCARGS))), bno);
ec67a3ce 397#endif SECSIZE
ce66cb03
MK
398 if (ip)
399 iput(ip);
28db9b87
SL
400}
401
402/*
403 * Read in and set up memory for executed file.
404 */
9fd50f35 405getxfile(ip, ep, nargc, uid, gid)
28db9b87 406 register struct inode *ip;
9fd50f35 407 register struct exec *ep;
28db9b87
SL
408 int nargc, uid, gid;
409{
0c48b03e 410 size_t ts, ds, ids, uds, ss;
28db9b87
SL
411 int pagi;
412
9fd50f35 413 if (ep->a_magic == 0413)
28db9b87
SL
414 pagi = SPAGI;
415 else
416 pagi = 0;
cdb14d96 417 if (ip->i_text && (ip->i_text->x_flag & XTRC)) {
ce08d752
MK
418 u.u_error = ETXTBSY;
419 goto bad;
420 }
9fd50f35
SL
421 if (ep->a_text != 0 && (ip->i_flag&ITEXT) == 0 &&
422 ip->i_count != 1) {
28db9b87
SL
423 register struct file *fp;
424
425 for (fp = file; fp < fileNFILE; fp++) {
426 if (fp->f_type == DTYPE_INODE &&
427 fp->f_count > 0 &&
428 (struct inode *)fp->f_data == ip &&
429 (fp->f_flag&FWRITE)) {
430 u.u_error = ETXTBSY;
431 goto bad;
432 }
433 }
434 }
435
436 /*
437 * Compute text and data sizes and make sure not too large.
0c48b03e
KM
438 * NB - Check data and bss separately as they may overflow
439 * when summed together.
28db9b87 440 */
9fd50f35 441 ts = clrnd(btoc(ep->a_text));
0c48b03e
KM
442 ids = clrnd(btoc(ep->a_data));
443 uds = clrnd(btoc(ep->a_bss));
f3aaea26 444 ds = clrnd(btoc(ep->a_data + ep->a_bss));
28db9b87 445 ss = clrnd(SSIZE + btoc(nargc));
0c48b03e 446 if (chksize((unsigned)ts, (unsigned)ids, (unsigned)uds, (unsigned)ss))
28db9b87
SL
447 goto bad;
448
449 /*
450 * Make sure enough space to start process.
451 */
452 u.u_cdmap = zdmap;
453 u.u_csmap = zdmap;
454 if (swpexpand(ds, ss, &u.u_cdmap, &u.u_csmap) == NULL)
455 goto bad;
456
457 /*
458 * At this point, committed to the new image!
459 * Release virtual memory resources of old process, and
460 * initialize the virtual memory of the new process.
461 * If we resulted from vfork(), instead wakeup our
462 * parent who will set SVFDONE when he has taken back
463 * our resources.
464 */
465 if ((u.u_procp->p_flag & SVFORK) == 0)
466 vrelvm();
467 else {
468 u.u_procp->p_flag &= ~SVFORK;
469 u.u_procp->p_flag |= SKEEP;
470 wakeup((caddr_t)u.u_procp);
471 while ((u.u_procp->p_flag & SVFDONE) == 0)
472 sleep((caddr_t)u.u_procp, PZERO - 1);
473 u.u_procp->p_flag &= ~(SVFDONE|SKEEP);
474 }
dd012d1e 475 u.u_procp->p_flag &= ~(SPAGI|SSEQL|SUANOM|SOUSIG);
28db9b87
SL
476 u.u_procp->p_flag |= pagi;
477 u.u_dmap = u.u_cdmap;
478 u.u_smap = u.u_csmap;
479 vgetvm(ts, ds, ss);
480
481 if (pagi == 0)
482 u.u_error =
483 rdwri(UIO_READ, ip,
484 (char *)ctob(dptov(u.u_procp, 0)),
9fd50f35 485 (int)ep->a_data,
8011f5df 486 (off_t)(sizeof (struct exec) + ep->a_text),
28db9b87 487 0, (int *)0);
9fd50f35 488 xalloc(ip, ep, pagi);
fb1db32c
MK
489#if defined(tahoe)
490 /*
491 * Define new keys.
492 */
493 if (u.u_procp->p_textp == 0) { /* use existing code key if shared */
494 ckeyrelease(u.u_procp->p_ckey);
495 u.u_procp->p_ckey = getcodekey();
496 }
497 mtpr(CCK, u.u_procp->p_ckey);
498 dkeyrelease(u.u_procp->p_dkey);
499 u.u_procp->p_dkey = getdatakey();
500 mtpr(DCK, u.u_procp->p_dkey);
501#endif
28db9b87
SL
502 if (pagi && u.u_procp->p_textp)
503 vinifod((struct fpte *)dptopte(u.u_procp, 0),
504 PG_FTEXT, u.u_procp->p_textp->x_iptr,
8011f5df 505 (long)(1 + ts/CLSIZE), (size_t)btoc(ep->a_data));
28db9b87 506
fb1db32c 507#if defined(vax) || defined(tahoe)
28db9b87 508 /* THIS SHOULD BE DONE AT A LOWER LEVEL, IF AT ALL */
28db9b87
SL
509 mtpr(TBIA, 0);
510#endif
511
512 if (u.u_error)
d03b3d84 513 swkill(u.u_procp, "exec: I/O error mapping pages");
28db9b87
SL
514 /*
515 * set SUID/SGID protections, if no tracing
516 */
517 if ((u.u_procp->p_flag&STRC)==0) {
518 u.u_uid = uid;
519 u.u_procp->p_uid = uid;
520 u.u_gid = gid;
521 } else
522 psignal(u.u_procp, SIGTRAP);
523 u.u_tsize = ts;
524 u.u_dsize = ds;
525 u.u_ssize = ss;
d4a03a57 526 u.u_prof.pr_scale = 0;
fb1db32c
MK
527#if defined(tahoe)
528 u.u_pcb.pcb_savacc.faddr = (float *)NULL;
529#endif
28db9b87
SL
530bad:
531 return;
532}