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