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