xref: /original-bsd/sys/kern/kern_proc.c (revision 6c57d260)
1 /*	kern_proc.c	4.12	81/04/28	*/
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 "/usr/include/wait.h"
16 #include "../h/pte.h"
17 #include "../h/vm.h"
18 #include "../h/text.h"
19 #include "../h/psl.h"
20 #include "../h/vlimit.h"
21 #include "../h/file.h"
22 
23 /*
24  * exec system call, with and without environments.
25  */
26 struct execa {
27 	char	*fname;
28 	char	**argp;
29 	char	**envp;
30 };
31 
32 exec()
33 {
34 	((struct execa *)u.u_ap)->envp = NULL;
35 	exece();
36 }
37 
38 exece()
39 {
40 	register nc;
41 	register char *cp;
42 	register struct buf *bp;
43 	register struct execa *uap;
44 	int na, ne, ucp, ap, c;
45 	int indir, uid, gid;
46 	char *sharg;
47 	struct inode *ip;
48 	swblk_t bno;
49 	char cfname[DIRSIZ];
50 	char cfarg[SHSIZE];
51 
52 	if ((ip = namei(uchar, 0)) == NULL)
53 		return;
54 
55 	bno = 0;
56 	bp = 0;
57 	indir = 0;
58 	uid = u.u_uid;
59 	gid = u.u_gid;
60 
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_base = (caddr_t)&u.u_exdata;
92 	u.u_count = sizeof(u.u_exdata);
93 	u.u_offset = 0;
94 	u.u_segflg = 1;
95 	readi(ip);
96 	u.u_segflg = 0;
97 	if(u.u_error)
98 		goto bad;
99 	if (u.u_count > sizeof(u.u_exdata) - sizeof(u.u_exdata.Ux_A)
100 		&& u.u_exdata.ux_shell[0] != '#') {
101 		u.u_error = ENOEXEC;
102 		goto bad;
103 	}
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 		bcopy((caddr_t)u.u_dbuf, (caddr_t)cfname, DIRSIZ);
157 		indir = 1;
158 		iput(ip);
159 		ip = namei(schar, 0);
160 		if (ip == NULL)
161 			return;
162 		goto again;
163 	}
164 
165 	/*
166 	 * Collect arguments on "file" in swap space.
167 	 */
168 	na = 0;
169 	ne = 0;
170 	nc = 0;
171 	uap = (struct execa *)u.u_ap;
172 	if ((bno = rmalloc(argmap, ctod(clrnd((int) btoc(NCARGS))))) == 0) {
173 		swkill(u.u_procp, "exece");
174 		goto bad;
175 	}
176 	if (bno % CLSIZE)
177 		panic("execa rmalloc");
178 	if (uap->argp) for (;;) {
179 		ap = NULL;
180 		if (indir && (na == 1 || na == 2 && sharg))
181 			ap = (int)uap->fname;
182 		else if (uap->argp) {
183 			ap = fuword((caddr_t)uap->argp);
184 			uap->argp++;
185 		}
186 		if (ap==NULL && uap->envp) {
187 			uap->argp = NULL;
188 			if ((ap = fuword((caddr_t)uap->envp)) == NULL)
189 				break;
190 			uap->envp++;
191 			ne++;
192 		}
193 		if (ap==NULL)
194 			break;
195 		na++;
196 		if(ap == -1)
197 			u.u_error = EFAULT;
198 		do {
199 			if (nc >= NCARGS-1)
200 				u.u_error = E2BIG;
201 			if (indir && na == 2 && sharg != NULL)
202 				c = *sharg++ & 0377;
203 			else if ((c = fubyte((caddr_t)ap++)) < 0)
204 				u.u_error = EFAULT;
205 			if (u.u_error) {
206 				if (bp)
207 					brelse(bp);
208 				bp = 0;
209 				goto badarg;
210 			}
211 			if ((nc&BMASK) == 0) {
212 				if (bp)
213 					bdwrite(bp);
214 				bp = getblk(argdev,
215 				    (daddr_t)(dbtofsb(bno)+(nc>>BSHIFT)));
216 				cp = bp->b_un.b_addr;
217 			}
218 			nc++;
219 			*cp++ = c;
220 		} while (c>0);
221 	}
222 	if (bp)
223 		bdwrite(bp);
224 	bp = 0;
225 	nc = (nc + NBPW-1) & ~(NBPW-1);
226 	if (indir)
227 		bcopy((caddr_t)cfname, (caddr_t)u.u_dbuf, DIRSIZ);
228 	getxfile(ip, nc + (na+4)*NBPW, uid, gid);
229 	if (u.u_error) {
230 badarg:
231 		for (c = 0; c < nc; c += BSIZE)
232 			if (bp = baddr(argdev, dbtofsb(bno)+(c>>BSHIFT))) {
233 				bp->b_flags |= B_AGE;		/* throw away */
234 				bp->b_flags &= ~B_DELWRI;	/* cancel io */
235 				brelse(bp);
236 				bp = 0;
237 			}
238 		goto bad;
239 	}
240 
241 	/*
242 	 * copy back arglist
243 	 */
244 
245 	ucp = USRSTACK - nc - NBPW;
246 	ap = ucp - na*NBPW - 3*NBPW;
247 	u.u_ar0[SP] = ap;
248 	(void) suword((caddr_t)ap, na-ne);
249 	nc = 0;
250 	for (;;) {
251 		ap += NBPW;
252 		if (na==ne) {
253 			(void) suword((caddr_t)ap, 0);
254 			ap += NBPW;
255 		}
256 		if (--na < 0)
257 			break;
258 		(void) suword((caddr_t)ap, ucp);
259 		do {
260 			if ((nc&BMASK) == 0) {
261 				if (bp)
262 					brelse(bp);
263 				bp = bread(argdev,
264 				    (daddr_t)(dbtofsb(bno)+(nc>>BSHIFT)));
265 				bp->b_flags |= B_AGE;		/* throw away */
266 				bp->b_flags &= ~B_DELWRI;	/* cancel io */
267 				cp = bp->b_un.b_addr;
268 			}
269 			(void) subyte((caddr_t)ucp++, (c = *cp++));
270 			nc++;
271 		} while(c&0377);
272 	}
273 	(void) suword((caddr_t)ap, 0);
274 	(void) suword((caddr_t)ucp, 0);
275 	setregs();
276 bad:
277 	if (bp)
278 		brelse(bp);
279 	if (bno)
280 		rmfree(argmap, ctod(clrnd((int) btoc(NCARGS))), bno);
281 	iput(ip);
282 }
283 
284 /*
285  * Read in and set up memory for executed file.
286  */
287 getxfile(ip, nargc, uid, gid)
288 register struct inode *ip;
289 {
290 	register size_t ts, ds, ss;
291 	int pagi;
292 
293 	if (u.u_exdata.ux_mag == 0413)
294 		pagi = SPAGI;
295 	else
296 		pagi = 0;
297 
298 	if(u.u_exdata.ux_tsize!=0 && (ip->i_flag&ITEXT)==0 && ip->i_count!=1) {
299 		register struct file *fp;
300 
301 		for (fp = file; fp < fileNFILE; fp++)
302 			if (fp->f_inode == ip && (fp->f_flag&FWRITE)) {
303 				u.u_error = ETXTBSY;
304 				goto bad;
305 			}
306 	}
307 
308 	/*
309 	 * find text and data sizes
310 	 * try them out for possible
311 	 * exceed of max sizes
312 	 */
313 
314 	ts = clrnd(btoc(u.u_exdata.ux_tsize));
315 	ds = clrnd(btoc((u.u_exdata.ux_dsize+u.u_exdata.ux_bsize)));
316 	ss = clrnd(SSIZE + btoc(nargc));
317 	if (chksize(ts, ds, ss))
318 		goto bad;
319 	u.u_cdmap = zdmap;
320 	u.u_csmap = zdmap;
321 	if (swpexpand(ds, ss, &u.u_cdmap, &u.u_csmap) == NULL)
322 		goto bad;
323 
324 	/*
325 	 * At this point, committed to the new image!
326 	 * Release virtual memory resources of old process, and
327 	 * initialize the virtual memory of the new process.
328 	 * If we resulted from vfork(), instead wakeup our
329 	 * parent who will set SVFDONE when he has taken back
330 	 * our resources.
331 	 */
332 	u.u_prof.pr_scale = 0;
333 	if ((u.u_procp->p_flag & SVFORK) == 0)
334 		vrelvm();
335 	else {
336 		u.u_procp->p_flag &= ~SVFORK;
337 		u.u_procp->p_flag |= SKEEP;
338 		wakeup((caddr_t)u.u_procp);
339 		while ((u.u_procp->p_flag & SVFDONE) == 0)
340 			sleep((caddr_t)u.u_procp, PZERO - 1);
341 		u.u_procp->p_flag &= ~(SVFDONE|SKEEP);
342 	}
343 	u.u_procp->p_flag &= ~(SPAGI|SSEQL|SUANOM|SNUSIG);
344 	u.u_procp->p_flag |= pagi;
345 	u.u_dmap = u.u_cdmap;
346 	u.u_smap = u.u_csmap;
347 	vgetvm(ts, ds, ss);
348 
349 	if (pagi == 0) {
350 		/*
351 		 * Read in data segment.
352 		 */
353 		u.u_base = (char *)ctob(ts);
354 		u.u_offset = sizeof(u.u_exdata)+u.u_exdata.ux_tsize;
355 		u.u_count = u.u_exdata.ux_dsize;
356 		readi(ip);
357 	}
358 	xalloc(ip, pagi);
359 	if (pagi && u.u_procp->p_textp)
360 		vinifod((struct fpte *)dptopte(u.u_procp, 0),
361 		    PG_FTEXT, u.u_procp->p_textp->x_iptr,
362 		    1 + ts/CLSIZE, (int)btoc(u.u_exdata.ux_dsize));
363 
364 	/* THIS SHOULD BE DONE AT A LOWER LEVEL, IF AT ALL */
365 	mtpr(TBIA, 0);
366 
367 	/*
368 	 * set SUID/SGID protections, if no tracing
369 	 */
370 	if ((u.u_procp->p_flag&STRC)==0) {
371 #ifndef	MELB
372 		if(u.u_uid != 0)
373 #endif
374 		{
375 			u.u_uid = uid;
376 			u.u_procp->p_uid = uid;
377 		}
378 		u.u_gid = gid;
379 	} else
380 		psignal(u.u_procp, SIGTRAP);
381 	u.u_tsize = ts;
382 	u.u_dsize = ds;
383 	u.u_ssize = ss;
384 bad:
385 	return;
386 }
387 
388 /*
389  * Clear registers on exec
390  */
391 setregs()
392 {
393 	register int (**rp)();
394 	register i;
395 	long sigmask;
396 
397 	for(rp = &u.u_signal[0], sigmask = 1L; rp < &u.u_signal[NSIG];
398 	    sigmask <<= 1, rp++) {
399 		switch (*rp) {
400 
401 		case SIG_IGN:
402 		case SIG_DFL:
403 		case SIG_HOLD:
404 			continue;
405 
406 		default:
407 			/*
408 			 * Normal or deferring catch; revert to default.
409 			 */
410 			(void) spl6();
411 			*rp = SIG_DFL;
412 			if ((int)*rp & 1)
413 				u.u_procp->p_siga0 |= sigmask;
414 			else
415 				u.u_procp->p_siga1 &= ~sigmask;
416 			if ((int)*rp & 2)
417 				u.u_procp->p_siga1 |= sigmask;
418 			else
419 				u.u_procp->p_siga1 &= ~sigmask;
420 			(void) spl0();
421 			continue;
422 		}
423 	}
424 /*
425 	for(rp = &u.u_ar0[0]; rp < &u.u_ar0[16];)
426 		*rp++ = 0;
427 */
428 	u.u_ar0[PC] = u.u_exdata.ux_entloc + 2; /* skip over entry mask */
429 	for(i=0; i<NOFILE; i++) {
430 		if (u.u_pofile[i]&EXCLOSE) {
431 			closef(u.u_ofile[i]);
432 			u.u_ofile[i] = NULL;
433 			u.u_pofile[i] &= ~EXCLOSE;
434 		}
435 	}
436 	/*
437 	 * Remember file name for accounting.
438 	 */
439 	u.u_acflag &= ~AFORK;
440 	bcopy((caddr_t)u.u_dbuf, (caddr_t)u.u_comm, DIRSIZ);
441 }
442 
443 /*
444  * exit system call:
445  * pass back caller's arg
446  */
447 rexit()
448 {
449 	register struct a {
450 		int	rval;
451 	} *uap;
452 
453 	uap = (struct a *)u.u_ap;
454 	exit((uap->rval & 0377) << 8);
455 }
456 
457 /*
458  * Release resources.
459  * Save u. area for parent to look at.
460  * Enter zombie state.
461  * Wake up parent and init processes,
462  * and dispose of children.
463  */
464 exit(rv)
465 {
466 	register int i;
467 	register struct proc *p, *q;
468 	register struct file *f;
469 	register int x;
470 
471 #ifdef PGINPROF
472 	vmsizmon();
473 #endif
474 	p = u.u_procp;
475 	p->p_flag &= ~(STRC|SULOCK);
476 	p->p_flag |= SWEXIT;
477 	p->p_clktim = 0;
478 	(void) spl6();
479 	if ((int)SIG_IGN & 1)
480 		p->p_siga0 = ~0;
481 	else
482 		p->p_siga0 = 0;
483 	if ((int)SIG_IGN & 2)
484 		p->p_siga1 = ~0;
485 	else
486 		p->p_siga1 = 0;
487 	(void) spl0();
488 	p->p_cpticks = 0;
489 	p->p_pctcpu = 0;
490 	for(i=0; i<NSIG; i++)
491 		u.u_signal[i] = SIG_IGN;
492 	/*
493 	 * Release virtual memory.  If we resulted from
494 	 * a vfork(), instead give the resources back to
495 	 * the parent.
496 	 */
497 	if ((p->p_flag & SVFORK) == 0)
498 		vrelvm();
499 	else {
500 		p->p_flag &= ~SVFORK;
501 		wakeup((caddr_t)p);
502 		while ((p->p_flag & SVFDONE) == 0)
503 			sleep((caddr_t)p, PZERO - 1);
504 		p->p_flag &= ~SVFDONE;
505 	}
506 	for(i=0; i<NOFILE; i++) {
507 		f = u.u_ofile[i];
508 		u.u_ofile[i] = NULL;
509 		closef(f);
510 	}
511 	plock(u.u_cdir);
512 	iput(u.u_cdir);
513 	if (u.u_rdir) {
514 		plock(u.u_rdir);
515 		iput(u.u_rdir);
516 	}
517 	u.u_limit[LIM_FSIZE] = INFINITY;
518 	acct();
519 	vrelpt(u.u_procp);
520 	vrelu(u.u_procp, 0);
521 	multprog--;
522 /*	spl7();			/* clock will get mad because of overlaying */
523 	p->p_stat = SZOMB;
524 	noproc = 1;
525 	i = PIDHASH(p->p_pid);
526 	x = p - proc;
527 	if (pidhash[i] == x)
528 		pidhash[i] = p->p_idhash;
529 	else {
530 		for (i = pidhash[i]; i != 0; i = proc[i].p_idhash)
531 			if (proc[i].p_idhash == x) {
532 				proc[i].p_idhash = p->p_idhash;
533 				goto done;
534 			}
535 		panic("exit");
536 	}
537 	if (p->p_pid == 1)
538 		panic("init died");
539 done:
540 	((struct xproc *)p)->xp_xstat = rv;		/* overlay */
541 	((struct xproc *)p)->xp_vm = u.u_vm;		/* overlay */
542 	vmsadd(&((struct xproc *)p)->xp_vm, &u.u_cvm);
543 	for(q = proc; q < procNPROC; q++)
544 		if(q->p_pptr == p) {
545 			q->p_pptr = &proc[1];
546 			q->p_ppid = 1;
547 			wakeup((caddr_t)&proc[1]);
548 			/*
549 			 * Traced processes are killed
550 			 * since their existence means someone is screwing up.
551 			 * Stopped processes are sent a hangup and a continue.
552 			 * This is designed to be ``safe'' for setuid
553 			 * processes since they must be willing to tolerate
554 			 * hangups anyways.
555 			 */
556 			if (q->p_flag&STRC) {
557 				q->p_flag &= ~STRC;
558 				psignal(q, SIGKILL);
559 			} else if (q->p_stat == SSTOP) {
560 				psignal(q, SIGHUP);
561 				psignal(q, SIGCONT);
562 			}
563 			/*
564 			 * Protect this process from future
565 			 * tty signals, clear TSTP/TTIN/TTOU if pending,
566 			 * and set SDETACH bit on procs.
567 			 */
568 			(void) spgrp(q, -1);
569 		}
570 	wakeup((caddr_t)p->p_pptr);
571 	psignal(p->p_pptr, SIGCHLD);
572 	swtch();
573 }
574 
575 wait()
576 {
577 	struct vtimes vm;
578 	struct vtimes *vp;
579 
580 	if ((u.u_ar0[PS] & PSL_ALLCC) != PSL_ALLCC) {
581 		wait1(0, (struct vtimes *)0);
582 		return;
583 	}
584 	vp = (struct vtimes *)u.u_ar0[R1];
585 	wait1(u.u_ar0[R0], &vm);
586 	if (u.u_error)
587 		return;
588 	(void) copyout((caddr_t)&vm, (caddr_t)vp, sizeof (struct vtimes));
589 }
590 
591 /*
592  * Wait system call.
593  * Search for a terminated (zombie) child,
594  * finally lay it to rest, and collect its status.
595  * Look also for stopped (traced) children,
596  * and pass back status from them.
597  */
598 wait1(options, vp)
599 	register options;
600 	struct vtimes *vp;
601 {
602 	register f;
603 	register struct proc *p;
604 
605 	f = 0;
606 loop:
607 	for(p = proc; p < procNPROC; p++)
608 	if(p->p_pptr == u.u_procp) {
609 		f++;
610 		if(p->p_stat == SZOMB) {
611 			u.u_r.r_val1 = p->p_pid;
612 			u.u_r.r_val2 = ((struct xproc *)p)->xp_xstat;
613 			((struct xproc *)p)->xp_xstat = 0;
614 			if (vp)
615 				*vp = ((struct xproc *)p)->xp_vm;
616 			vmsadd(&u.u_cvm, &((struct xproc *)p)->xp_vm);
617 			((struct xproc *)p)->xp_vm = zvms;
618 			p->p_stat = NULL;
619 			p->p_pid = 0;
620 			p->p_ppid = 0;
621 			p->p_pptr = 0;
622 			p->p_sig = 0;
623 			p->p_siga0 = 0;
624 			p->p_siga1 = 0;
625 			p->p_pgrp = 0;
626 			p->p_flag = 0;
627 			p->p_wchan = 0;
628 			p->p_cursig = 0;
629 			return;
630 		}
631 		if (p->p_stat == SSTOP && (p->p_flag&SWTED)==0 &&
632 		    (p->p_flag&STRC || options&WUNTRACED)) {
633 			p->p_flag |= SWTED;
634 			u.u_r.r_val1 = p->p_pid;
635 			u.u_r.r_val2 = (p->p_cursig<<8) | WSTOPPED;
636 			return;
637 		}
638 	}
639 	if (f==0) {
640 		u.u_error = ECHILD;
641 		return;
642 	}
643 	if (options&WNOHANG) {
644 		u.u_r.r_val1 = 0;
645 		return;
646 	}
647 	if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) {
648 		u.u_eosys = RESTARTSYS;
649 		return;
650 	}
651 	sleep((caddr_t)u.u_procp, PWAIT);
652 	goto loop;
653 }
654 
655 /*
656  * fork system call.
657  */
658 fork()
659 {
660 
661 	u.u_cdmap = zdmap;
662 	u.u_csmap = zdmap;
663 	if (swpexpand(u.u_dsize, u.u_ssize, &u.u_cdmap, &u.u_csmap) == 0) {
664 		u.u_r.r_val2 = 0;
665 		return;
666 	}
667 	fork1(0);
668 }
669 
670 fork1(isvfork)
671 {
672 	register struct proc *p1, *p2;
673 	register a;
674 
675 	a = 0;
676 	p2 = NULL;
677 	for(p1 = proc; p1 < procNPROC; p1++) {
678 		if (p1->p_stat==NULL && p2==NULL)
679 			p2 = p1;
680 		else {
681 			if (p1->p_uid==u.u_uid && p1->p_stat!=NULL)
682 				a++;
683 		}
684 	}
685 	/*
686 	 * Disallow if
687 	 *  No processes at all;
688 	 *  not su and too many procs owned; or
689 	 *  not su and would take last slot.
690 	 */
691 	if (p2==NULL)
692 		tablefull("proc");
693 	if (p2==NULL || (u.u_uid!=0 && (p2==procNPROC-1 || a>MAXUPRC))) {
694 		u.u_error = EAGAIN;
695 		if (!isvfork) {
696 			(void) vsexpand(0, &u.u_cdmap, 1);
697 			(void) vsexpand(0, &u.u_csmap, 1);
698 		}
699 		goto out;
700 	}
701 	p1 = u.u_procp;
702 	if(newproc(isvfork)) {
703 		u.u_r.r_val1 = p1->p_pid;
704 		u.u_r.r_val2 = 1;  /* child */
705 		u.u_start = time;
706 		u.u_acflag = AFORK;
707 		return;
708 	}
709 	u.u_r.r_val1 = p2->p_pid;
710 
711 out:
712 	u.u_r.r_val2 = 0;
713 }
714 
715 /*
716  * break system call.
717  *  -- bad planning: "break" is a dirty word in C.
718  */
719 sbreak()
720 {
721 	struct a {
722 		char	*nsiz;
723 	};
724 	register int n, d;
725 
726 	/*
727 	 * set n to new data size
728 	 * set d to new-old
729 	 */
730 
731 	n = btoc(((struct a *)u.u_ap)->nsiz);
732 	if (!u.u_sep)
733 		n -= ctos(u.u_tsize) * stoc(1);
734 	if (n < 0)
735 		n = 0;
736 	d = clrnd(n - u.u_dsize);
737 	if (ctob(u.u_dsize+d) > u.u_limit[LIM_DATA]) {
738 		u.u_error = ENOMEM;
739 		return;
740 	}
741 	if (chksize(u.u_tsize, u.u_dsize+d, u.u_ssize))
742 		return;
743 	if (swpexpand(u.u_dsize+d, u.u_ssize, &u.u_dmap, &u.u_smap)==0)
744 		return;
745 	expand(d, P0BR);
746 }
747