date and time created 80/04/09 16:04:26 by bill
[unix-history] / usr / src / sys / kern / kern_proc.c
CommitLineData
29dd101b
BJ
1/* kern_proc.c 3.1 %H% */
2
3#include "../h/param.h"
4#include "../h/systm.h"
5#include "../h/map.h"
6#include "../h/mtpr.h"
7#include "../h/dir.h"
8#include "../h/user.h"
9#include "../h/proc.h"
10#include "../h/buf.h"
11#include "../h/reg.h"
12#include "../h/inode.h"
13#include "../h/seg.h"
14#include "../h/acct.h"
15#include "../h/pte.h"
16#include "../h/vm.h"
17#include "../h/text.h"
18
19/*
20 * exec system call, with and without environments.
21 */
22struct execa {
23 char *fname;
24 char **argp;
25 char **envp;
26};
27
28exec()
29{
30 ((struct execa *)u.u_ap)->envp = NULL;
31 exece();
32}
33
34exece()
35{
36 register nc;
37 register char *cp;
38 register struct buf *bp;
39 register struct execa *uap;
40 int na, ne, ucp, ap, c;
41 struct inode *ip;
42 swblk_t bno;
43
44 if ((ip = namei(uchar, 0)) == NULL)
45 return;
46 bno = 0;
47 bp = 0;
48 if(access(ip, IEXEC))
49 goto bad;
50 if((ip->i_mode & IFMT) != IFREG ||
51 (ip->i_mode & (IEXEC|(IEXEC>>3)|(IEXEC>>6))) == 0) {
52 u.u_error = EACCES;
53 goto bad;
54 }
55 /*
56 * Collect arguments on "file" in swap space.
57 */
58 na = 0;
59 ne = 0;
60 nc = 0;
61 uap = (struct execa *)u.u_ap;
62 if ((bno = malloc(swapmap, ctod(clrnd((int) btoc(NCARGS))))) == 0) {
63 swkill(u.u_procp, "exece");
64 goto bad;
65 }
66 if (bno % CLSIZE)
67 panic("execa malloc");
68 if (uap->argp) for (;;) {
69 ap = NULL;
70 if (uap->argp) {
71 ap = fuword((caddr_t)uap->argp);
72 uap->argp++;
73 }
74 if (ap==NULL && uap->envp) {
75 uap->argp = NULL;
76 if ((ap = fuword((caddr_t)uap->envp)) == NULL)
77 break;
78 uap->envp++;
79 ne++;
80 }
81 if (ap==NULL)
82 break;
83 na++;
84 if(ap == -1)
85 u.u_error = EFAULT;
86 do {
87 if (nc >= NCARGS-1)
88 u.u_error = E2BIG;
89 if ((c = fubyte((caddr_t)ap++)) < 0)
90 u.u_error = EFAULT;
91 if (u.u_error)
92 goto badarg;
93 if ((nc&BMASK) == 0) {
94 if (bp)
95 bdwrite(bp);
96 bp = getblk(swapdev, (daddr_t)(dbtofsb(swplo+bno)+(nc>>BSHIFT)));
97 cp = bp->b_un.b_addr;
98 }
99 nc++;
100 *cp++ = c;
101 } while (c>0);
102 }
103 if (bp)
104 bdwrite(bp);
105 bp = 0;
106 nc = (nc + NBPW-1) & ~(NBPW-1);
107 if (getxfile(ip, nc) || u.u_error) {
108badarg:
109 for (c = 0; c < nc; c += BSIZE)
110 if (bp = baddr(swapdev, dbtofsb(swplo+bno)+(c>>BSHIFT))) {
111 bp->b_flags |= B_AGE; /* throw away */
112 bp->b_flags &= ~B_DELWRI; /* cancel io */
113 brelse(bp);
114 bp = 0;
115 }
116 goto bad;
117 }
118
119 /*
120 * copy back arglist
121 */
122
123 ucp = USRSTACK - nc - NBPW;
124 ap = ucp - na*NBPW - 3*NBPW;
125 u.u_ar0[SP] = ap;
126 VOID suword((caddr_t)ap, na-ne);
127 nc = 0;
128 for (;;) {
129 ap += NBPW;
130 if (na==ne) {
131 VOID suword((caddr_t)ap, 0);
132 ap += NBPW;
133 }
134 if (--na < 0)
135 break;
136 VOID suword((caddr_t)ap, ucp);
137 do {
138 if ((nc&BMASK) == 0) {
139 if (bp)
140 brelse(bp);
141 bp = bread(swapdev, (daddr_t)(dbtofsb(swplo+bno)+(nc>>BSHIFT)));
142 bp->b_flags |= B_AGE; /* throw away */
143 bp->b_flags &= ~B_DELWRI; /* cancel io */
144 cp = bp->b_un.b_addr;
145 }
146 VOID subyte((caddr_t)ucp++, (c = *cp++));
147 nc++;
148 } while(c&0377);
149 }
150 VOID suword((caddr_t)ap, 0);
151 VOID suword((caddr_t)ucp, 0);
152 setregs();
153bad:
154 if (bp)
155 brelse(bp);
156 if (bno)
157 mfree(swapmap, ctod(clrnd((int) btoc(NCARGS))), bno);
158 iput(ip);
159}
160
161/*
162 * Read in and set up memory for executed file.
163 * Zero return is normal;
164 * non-zero means only the text is being replaced
165 */
166getxfile(ip, nargc)
167register struct inode *ip;
168{
169 register sep;
170 register size_t ts, ds, ss;
171 register int overlay;
172 int pagi = 0;
173
174 /*
175 * read in first few bytes
176 * of file for segment
177 * sizes:
178 * ux_mag = 407/410/411/405
179 * 407 is plain executable
180 * 410 is RO text
181 * 411 is separated ID
182 * 405 is overlaid text
183 * 412 is demand paged plain executable (NOT IMPLEMENTED)
184 * 413 is demand paged RO text
185 */
186
187 u.u_base = (caddr_t)&u.u_exdata;
188 u.u_count = sizeof(u.u_exdata);
189 u.u_offset = 0;
190 u.u_segflg = 1;
191 readi(ip);
192 u.u_segflg = 0;
193 if(u.u_error)
194 goto bad;
195 if (u.u_count!=0) {
196 u.u_error = ENOEXEC;
197 goto bad;
198 }
199 sep = 0;
200 overlay = 0;
201 switch (u.u_exdata.ux_mag) {
202
203 case 0405:
204 overlay++;
205 break;
206
207 case 0412:
208 u.u_error = ENOEXEC;
209 goto bad;
210
211 case 0407:
212 u.u_exdata.ux_dsize += u.u_exdata.ux_tsize;
213 u.u_exdata.ux_tsize = 0;
214 break;
215
216 case 0413:
217 pagi = SPAGI;
218 /* fall into ... */
219
220 case 0410:
221 if (u.u_exdata.ux_tsize == 0) {
222 u.u_error = ENOEXEC;
223 goto bad;
224 }
225 break;
226
227 case 0411:
228 u.u_error = ENOEXEC;
229 goto bad;
230
231 default:
232 u.u_error = ENOEXEC;
233 goto bad;
234 }
235 if(u.u_exdata.ux_tsize!=0 && (ip->i_flag&ITEXT)==0 && ip->i_count!=1) {
236 u.u_error = ETXTBSY;
237 goto bad;
238 }
239
240 /*
241 * find text and data sizes
242 * try them out for possible
243 * exceed of max sizes
244 */
245
246 ts = clrnd(btoc(u.u_exdata.ux_tsize));
247 ds = clrnd(btoc((u.u_exdata.ux_dsize+u.u_exdata.ux_bsize)));
248 ss = clrnd(SSIZE + btoc(nargc));
249 if (overlay) {
250 if ((u.u_procp->p_flag & SPAGI) || u.u_sep==0 && ctos(ts) != ctos(u.u_tsize) || nargc) {
251 u.u_error = ENOMEM;
252 goto bad;
253 }
254 ds = u.u_dsize;
255 ss = u.u_ssize;
256 sep = u.u_sep;
257 xfree();
258 xalloc(ip, pagi);
259 u.u_ar0[PC] = u.u_exdata.ux_entloc + 2; /* skip over entry mask */
260 } else {
261 if (chksize(ts, ds, ss))
262 goto bad;
263 u.u_cdmap = zdmap;
264 u.u_csmap = zdmap;
265 if (swpexpand(ds, ss, &u.u_cdmap, &u.u_csmap) == NULL)
266 goto bad;
267
268 /*
269 * At this point, committed to the new image!
270 * Release virtual memory resources of old process, and
271 * initialize the virtual memory of the new process.
272 * If we resulted from vfork(), instead wakeup our
273 * parent who will set SVFDONE when he has taken back
274 * our resources.
275 */
276 u.u_prof.pr_scale = 0;
277 if ((u.u_procp->p_flag & SVFORK) == 0)
278 vrelvm();
279 else {
280 u.u_procp->p_flag &= ~SVFORK;
281 u.u_procp->p_flag |= SKEEP;
282 wakeup((caddr_t)u.u_procp);
283 while ((u.u_procp->p_flag & SVFDONE) == 0)
284 sleep((caddr_t)u.u_procp, PZERO - 1);
285 u.u_procp->p_flag &= ~(SVFDONE|SKEEP);
286 }
287 u.u_procp->p_flag &= ~(SPAGI|SANOM|SUANOM);
288 u.u_procp->p_flag |= pagi;
289 u.u_dmap = u.u_cdmap;
290 u.u_smap = u.u_csmap;
291 vgetvm(ts, ds, ss);
292
293 if (pagi == 0) {
294 /*
295 * Read in data segment.
296 */
297 u.u_base = (char *)ctob(ts);
298 u.u_offset = sizeof(u.u_exdata)+u.u_exdata.ux_tsize;
299 u.u_count = u.u_exdata.ux_dsize;
300 readi(ip);
301 }
302 xalloc(ip, pagi);
303 if (pagi && u.u_procp->p_textp)
304 vinifod((struct fpte *)dptopte(u.u_procp, 0),
305 PG_FTEXT, u.u_procp->p_textp->x_iptr,
306 1 + ts/CLSIZE, (int)btoc(u.u_exdata.ux_dsize));
307
308 /* THIS SHOULD BE DONE AT A LOWER LEVEL, IF AT ALL */
309 mtpr(TBIA,1);
310
311 /*
312 * set SUID/SGID protections, if no tracing
313 */
314 if ((u.u_procp->p_flag&STRC)==0) {
315 if(ip->i_mode&ISUID)
316 if(u.u_uid != 0) {
317 u.u_uid = ip->i_uid;
318 u.u_procp->p_uid = ip->i_uid;
319 }
320 if(ip->i_mode&ISGID)
321 u.u_gid = ip->i_gid;
322 } else
323 psignal(u.u_procp, SIGTRC);
324 }
325 u.u_tsize = ts;
326 u.u_dsize = ds;
327 u.u_ssize = ss;
328 u.u_sep = sep;
329bad:
330 return(overlay);
331}
332
333/*
334 * Clear registers on exec
335 */
336setregs()
337{
338 register int *rp;
339 register i;
340
341 for(rp = &u.u_signal[0]; rp < &u.u_signal[NSIG]; rp++)
342 if((*rp & 1) == 0)
343 *rp = 0;
344/*
345 for(rp = &u.u_ar0[0]; rp < &u.u_ar0[16];)
346 *rp++ = 0;
347*/
348 u.u_ar0[PC] = u.u_exdata.ux_entloc + 2; /* skip over entry mask */
349 for(i=0; i<NOFILE; i++) {
350 if (u.u_pofile[i]&EXCLOSE) {
351 closef(u.u_ofile[i]);
352 u.u_ofile[i] = NULL;
353 }
354 u.u_pofile[i] &= ~EXCLOSE;
355 }
356 /*
357 * Remember file name for accounting.
358 */
359 u.u_acflag &= ~AFORK;
360 bcopy((caddr_t)u.u_dbuf, (caddr_t)u.u_comm, DIRSIZ);
361}
362
363/*
364 * exit system call:
365 * pass back caller's arg
366 */
367rexit()
368{
369 register struct a {
370 int rval;
371 } *uap;
372
373 uap = (struct a *)u.u_ap;
374 exit((uap->rval & 0377) << 8);
375}
376
377/*
378 * Release resources.
379 * Save u. area for parent to look at.
380 * Enter zombie state.
381 * Wake up parent and init processes,
382 * and dispose of children.
383 */
384exit(rv)
385{
386 register int i;
387 register struct proc *p, *q;
388 register struct file *f;
389 register int x;
390
391#ifdef PGINPROF
392 vmsizmon();
393#endif
394 p = u.u_procp;
395 p->p_flag &= ~(STRC|SULOCK);
396 p->p_flag |= SWEXIT;
397 p->p_clktim = 0;
398 rate.v_pgin -= p->p_aveflt;
399 p->p_aveflt = 0;
400 for(i=0; i<NSIG; i++)
401 u.u_signal[i] = 1;
402 /*
403 * Release virtual memory. If we resulted from
404 * a vfork(), instead give the resources back to
405 * the parent.
406 */
407 if ((p->p_flag & SVFORK) == 0)
408 vrelvm();
409 else {
410 p->p_flag &= ~SVFORK;
411 wakeup((caddr_t)p);
412 while ((p->p_flag & SVFDONE) == 0)
413 sleep((caddr_t)p, PZERO - 1);
414 p->p_flag &= ~SVFDONE;
415 }
416 for(i=0; i<NOFILE; i++) {
417 f = u.u_ofile[i];
418 u.u_ofile[i] = NULL;
419 closef(f);
420 }
421 plock(u.u_cdir);
422 iput(u.u_cdir);
423 if (u.u_rdir) {
424 plock(u.u_rdir);
425 iput(u.u_rdir);
426 }
427 acct();
428 vrelpt(u.u_procp);
429 vrelu(u.u_procp, 0);
430 multprog--;
431 spl7(); /* clock will get mad because of overlaying */
432 p->p_stat = SZOMB;
433 i = PIDHASH(p->p_pid);
434 x = p - proc;
435 if (pidhash[i] == x)
436 pidhash[i] = p->p_idhash;
437 else {
438 for (i = pidhash[i]; i != 0; i = proc[i].p_idhash)
439 if (proc[i].p_idhash == x) {
440 proc[i].p_idhash = p->p_idhash;
441 goto done;
442 }
443 panic("exit");
444 }
445done:
446 ((struct xproc *)p)->xp_xstat = rv; /* overlay */
447 ((struct xproc *)p)->xp_vm = u.u_vm; /* overlay */
448 vmsadd(&((struct xproc *)p)->xp_vm, &u.u_cvm);
449 for(q = &proc[0]; q < &proc[NPROC]; q++)
450 if(q->p_ppid == p->p_pid) {
451 wakeup((caddr_t)&proc[1]);
452 q->p_ppid = 1;
453 if (q->p_stat==SSTOP)
454 setrun(q);
455 }
456 q = pfind(p->p_ppid);
457 if (q)
458 wakeup((caddr_t)q);
459 swtch();
460}
461
462wait()
463{
464
465 wait1((struct vtimes *)0);
466}
467
468/*
469 * Wait system call.
470 * Search for a terminated (zombie) child,
471 * finally lay it to rest, and collect its status.
472 * Look also for stopped (traced) children,
473 * and pass back status from them.
474 */
475wait1(vp)
476 struct vtimes *vp;
477{
478 register f;
479 register struct proc *p;
480
481 f = 0;
482
483loop:
484 for(p = &proc[0]; p < &proc[NPROC]; p++)
485 if(p->p_ppid == u.u_procp->p_pid) {
486 f++;
487 if(p->p_stat == SZOMB) {
488 u.u_r.r_val1 = p->p_pid;
489 u.u_r.r_val2 = ((struct xproc *)p)->xp_xstat;
490 ((struct xproc *)p)->xp_xstat = 0;
491 if (vp)
492 *vp = ((struct xproc *)p)->xp_vm;
493 vmsadd(&u.u_cvm, &((struct xproc *)p)->xp_vm);
494 ((struct xproc *)p)->xp_vm = zvms;
495 p->p_stat = NULL;
496 p->p_pid = 0;
497 p->p_ppid = 0;
498 p->p_sig = 0;
499 p->p_pgrp = 0;
500 p->p_flag = 0;
501 p->p_wchan = 0;
502 return;
503 }
504 if(p->p_stat == SSTOP) {
505 if((p->p_flag&SWTED) == 0) {
506 p->p_flag |= SWTED;
507 u.u_r.r_val1 = p->p_pid;
508 u.u_r.r_val2 = (fsig(p)<<8) | 0177;
509 return;
510 }
511 continue;
512 }
513 }
514 if(f) {
515 sleep((caddr_t)u.u_procp, PWAIT);
516 goto loop;
517 }
518 u.u_error = ECHILD;
519}
520
521/*
522 * fork system call.
523 */
524fork()
525{
526
527 u.u_cdmap = zdmap;
528 u.u_csmap = zdmap;
529 if (swpexpand(u.u_dsize, u.u_ssize, &u.u_cdmap, &u.u_csmap) == 0) {
530 u.u_r.r_val2 = 0;
531 return;
532 }
533 fork1(0);
534}
535
536fork1(isvfork)
537{
538 register struct proc *p1, *p2;
539 register a;
540
541 a = 0;
542 p2 = NULL;
543 for(p1 = &proc[0]; p1 < &proc[NPROC]; p1++) {
544 if (p1->p_stat==NULL && p2==NULL)
545 p2 = p1;
546 else {
547 if (p1->p_uid==u.u_uid && p1->p_stat!=NULL)
548 a++;
549 }
550 }
551 /*
552 * Disallow if
553 * No processes at all;
554 * not su and too many procs owned; or
555 * not su and would take last slot.
556 */
557 if (p2==NULL || (u.u_uid!=0 && (p2==&proc[NPROC-1] || a>MAXUPRC))) {
558 u.u_error = EAGAIN;
559 if (!isvfork) {
560 VOID vsexpand(0, &u.u_cdmap, 1);
561 VOID vsexpand(0, &u.u_csmap, 1);
562 }
563 goto out;
564 }
565 p1 = u.u_procp;
566 if(newproc(isvfork)) {
567 u.u_r.r_val1 = p1->p_pid;
568 u.u_r.r_val2 = 1; /* child */
569 u.u_start = time;
570 u.u_acflag = AFORK;
571 return;
572 }
573 u.u_r.r_val1 = p2->p_pid;
574
575out:
576 u.u_r.r_val2 = 0;
577}
578
579/*
580 * break system call.
581 * -- bad planning: "break" is a dirty word in C.
582 */
583sbreak()
584{
585 struct a {
586 char *nsiz;
587 };
588 register int n, d;
589
590 /*
591 * set n to new data size
592 * set d to new-old
593 */
594
595 n = btoc(((struct a *)u.u_ap)->nsiz);
596 if (!u.u_sep)
597 n -= ctos(u.u_tsize) * stoc(1);
598 if (n < 0)
599 n = 0;
600 d = clrnd(n - u.u_dsize);
601 if (chksize(u.u_tsize, u.u_dsize+d, u.u_ssize))
602 return;
603 if (swpexpand(u.u_dsize+d, u.u_ssize, &u.u_dmap, &u.u_smap)==0)
604 return;
605 expand(d, P0BR);
606}