xref: /plan9-contrib/sys/src/9/port/sysproc.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include	"u.h"
2 #include	"../port/lib.h"
3 #include	"mem.h"
4 #include	"dat.h"
5 #include	"fns.h"
6 #include	"../port/error.h"
7 
8 #include	<a.out.h>
9 
10 int	shargs(char*, int, char**);
11 
12 long
13 sysr1(ulong *arg)
14 {
15 	xsummary();
16 	print("[%s %s %d] r1 = %d\n", u->p->user, u->p->text, u->p->pid, arg[0]);
17 	return 0;
18 }
19 
20 long
21 sysrfork(ulong *arg)
22 {
23 	KMap *k;
24 	Pgrp *opg;
25 	Egrp *oeg;
26 	Fgrp *ofg;
27 	int n, i;
28 	Proc *p, *parent;
29 	ulong upa, pid, flag;
30 	/*
31 	 * used to compute last valid system stack address for copy
32 	 */
33 	int lastvar;
34 
35 	flag = arg[0];
36 	p = u->p;
37 	if((flag&RFPROC) == 0) {
38 		if(flag & (RFNAMEG|RFCNAMEG)) {
39 			if((flag & (RFNAMEG|RFCNAMEG)) == (RFNAMEG|RFCNAMEG))
40 				error(Ebadarg);
41 			opg = p->pgrp;
42 			p->pgrp = newpgrp();
43 			if(flag & RFNAMEG)
44 				pgrpcpy(p->pgrp, opg);
45 			closepgrp(opg);
46 		}
47 		if(flag & (RFENVG|RFCENVG)) {
48 			if((flag & (RFENVG|RFCENVG)) == (RFENVG|RFCENVG))
49 				error(Ebadarg);
50 			oeg = p->egrp;
51 			p->egrp = smalloc(sizeof(Egrp));
52 			p->egrp->ref = 1;
53 			if(flag & RFENVG)
54 				envcpy(p->egrp, oeg);
55 			closeegrp(oeg);
56 		}
57 		if(flag & RFFDG) {
58 			ofg = p->fgrp;
59 			p->fgrp = dupfgrp(ofg);
60 			closefgrp(ofg);
61 		}
62 		else
63 		if(flag & RFCFDG) {
64 			ofg = p->fgrp;
65 			p->fgrp = smalloc(sizeof(Fgrp));
66 			p->fgrp->ref = 1;
67 			closefgrp(ofg);
68 		}
69 		if(flag & RFNOTEG)
70 			p->noteid = incref(&noteidalloc);
71 		if(flag & (RFMEM|RFNOWAIT))
72 			error(Ebadarg);
73 		return 0;
74 	}
75 	/* Check flags before we commit */
76 	if((flag & (RFFDG|RFCFDG)) == (RFFDG|RFCFDG))
77 		error(Ebadarg);
78 	if((flag & (RFNAMEG|RFCNAMEG)) == (RFNAMEG|RFCNAMEG))
79 		error(Ebadarg);
80 	if((flag & (RFENVG|RFCENVG)) == (RFENVG|RFCENVG))
81 		error(Ebadarg);
82 
83 	p = newproc();
84 	parent = u->p;
85 
86 	/* Page va of upage used as check in mapstack */
87 	p->upage = newpage(0, 0, USERADDR|(p->pid&0xFFFF));
88 	k = kmap(p->upage);
89 	upa = VA(k);
90 
91 	/* Save time: only copy u-> data and useful stack */
92 	memmove((void*)upa, u, sizeof(User));
93 	n = USERADDR+BY2PG - (ulong)&lastvar;
94 	n = (n+32) & ~(BY2WD-1);
95 	memmove((void*)(upa+BY2PG-n), (void*)(USERADDR+BY2PG-n), n);
96 	((User *)upa)->p = p;
97 	kunmap(k);
98 
99 	/* Make a new set of memory segments */
100 	n = flag & RFMEM;
101 	for(i = 0; i < NSEG; i++)
102 		if(parent->seg[i])
103 			p->seg[i] = dupseg(parent->seg, i, n);
104 
105 	/* Refs */
106 	incref(u->dot);
107 
108 	/* File descriptors */
109 	if(flag & (RFFDG|RFCFDG)) {
110 		if(flag & RFFDG)
111 			p->fgrp = dupfgrp(parent->fgrp);
112 		else {
113 			p->fgrp = smalloc(sizeof(Fgrp));
114 			p->fgrp->ref = 1;
115 		}
116 	}
117 	else {
118 		p->fgrp = parent->fgrp;
119 		incref(p->fgrp);
120 	}
121 
122 	/* Process groups */
123 	if(flag & (RFNAMEG|RFCNAMEG)) {
124 		p->pgrp = newpgrp();
125 		if(flag & RFNAMEG)
126 			pgrpcpy(p->pgrp, parent->pgrp);
127 	}
128 	else {
129 		p->pgrp = parent->pgrp;
130 		incref(p->pgrp);
131 	}
132 
133 	/* Environment group */
134 	if(flag & (RFENVG|RFCENVG)) {
135 		p->egrp = smalloc(sizeof(Egrp));
136 		p->egrp->ref = 1;
137 		if(flag & RFENVG)
138 			envcpy(p->egrp, parent->egrp);
139 	}
140 	else {
141 		p->egrp = parent->egrp;
142 		incref(p->egrp);
143 	}
144 
145 	p->hang = parent->hang;
146 	p->procmode = parent->procmode;
147 
148 	if(setlabel(&p->sched)){
149 		/*
150 		 *  use u->p instead of p, because we don't trust the compiler, after a
151 		 *  gotolabel, to find the correct contents of a local variable.
152 		 */
153 		p = u->p;
154 		p->state = Running;
155 		p->mach = m;
156 		m->proc = p;
157 		spllo();
158 		return 0;
159 	}
160 
161 	p->parent = parent;
162 	p->parentpid = parent->pid;
163 	if(flag&RFNOWAIT)
164 		p->parentpid = 1;
165 	else {
166 		lock(&parent->exl);
167 		parent->nchild++;
168 		unlock(&parent->exl);
169 	}
170 	if((flag&RFNOTEG) == 0)
171 		p->noteid = parent->noteid;
172 
173 	p->fpstate = parent->fpstate;
174 	pid = p->pid;
175 	memset(p->time, 0, sizeof(p->time));
176 	p->time[TReal] = MACHP(0)->ticks;
177 	memmove(p->text, parent->text, NAMELEN);
178 	memmove(p->user, parent->user, NAMELEN);
179 	/*
180 	 *  since the bss/data segments are now shareable,
181 	 *  any mmu info about this process is now stale
182 	 *  (i.e. has bad properties) and has to be discarded.
183 	 */
184 	flushmmu();
185 	p->priority = u->p->priority;
186 	p->basepri = u->p->basepri;
187 	p->mp = u->p->mp;
188 	ready(p);
189 	sched();
190 	return pid;
191 }
192 
193 static ulong
194 l2be(long l)
195 {
196 	uchar *cp;
197 
198 	cp = (uchar*)&l;
199 	return (cp[0]<<24) | (cp[1]<<16) | (cp[2]<<8) | cp[3];
200 }
201 
202 long
203 sysexec(ulong *arg)
204 {
205 	Proc *p;
206 	Segment *s, *ts;
207 	ulong t, d, b;
208 	int i;
209 	Chan *tc;
210 	char **argv, **argp;
211 	char *a, *charp, *file;
212 	char *progarg[sizeof(Exec)/2+1], elem[NAMELEN];
213 	ulong ssize, spage, nargs, nbytes, n, bssend;
214 	int indir;
215 	Exec exec;
216 	char line[sizeof(Exec)];
217 	Fgrp *f;
218 	Image *img;
219 	ulong magic, text, entry, data, bss;
220 
221 	p = u->p;
222 	validaddr(arg[0], 1, 0);
223 	file = (char*)arg[0];
224 	indir = 0;
225     Header:
226 	tc = namec(file, Aopen, OEXEC, 0);
227 	if(waserror()){
228 		close(tc);
229 		nexterror();
230 	}
231 	if(!indir)
232 		strcpy(elem, u->elem);
233 
234 	n = (*devtab[tc->type].read)(tc, &exec, sizeof(Exec), 0);
235 	if(n < 2)
236     Err:
237 		error(Ebadexec);
238 	magic = l2be(exec.magic);
239 	text = l2be(exec.text);
240 	entry = l2be(exec.entry);
241 	if(n==sizeof(Exec) && magic==AOUT_MAGIC){
242 		if((text&KZERO)
243 		|| entry < UTZERO+sizeof(Exec)
244 		|| entry >= UTZERO+sizeof(Exec)+text)
245 			goto Err;
246 		goto Binary;
247 	}
248 
249 	/*
250 	 * Process #! /bin/sh args ...
251 	 */
252 	memmove(line, &exec, sizeof(Exec));
253 	if(indir || line[0]!='#' || line[1]!='!')
254 		goto Err;
255 	n = shargs(line, n, progarg);
256 	if(n == 0)
257 		goto Err;
258 	indir = 1;
259 	/*
260 	 * First arg becomes complete file name
261 	 */
262 	progarg[n++] = file;
263 	progarg[n] = 0;
264 	validaddr(arg[1], BY2WD, 1);
265 	arg[1] += BY2WD;
266 	file = progarg[0];
267 	progarg[0] = elem;
268 	poperror();
269 	close(tc);
270 	goto Header;
271 
272     Binary:
273 	poperror();
274 	data = l2be(exec.data);
275 	bss = l2be(exec.bss);
276 	t = (UTZERO+sizeof(Exec)+text+(BY2PG-1)) & ~(BY2PG-1);
277 	d = (t + data + (BY2PG-1)) & ~(BY2PG-1);
278 	bssend = t + data + bss;
279 	b = (bssend + (BY2PG-1)) & ~(BY2PG-1);
280 	if((t|d|b) & KZERO)
281 		error(Ebadexec);
282 
283 	/*
284 	 * Args: pass 1: count
285 	 */
286 	nbytes = BY2WD;		/* hole for profiling clock at top of stack */
287 	nargs = 0;
288 	if(indir){
289 		argp = progarg;
290 		while(*argp){
291 			a = *argp++;
292 			nbytes += strlen(a) + 1;
293 			nargs++;
294 		}
295 	}
296 	evenaddr(arg[1]);
297 	argp = (char**)arg[1];
298 	validaddr((ulong)argp, BY2WD, 0);
299 	while(*argp){
300 		a = *argp++;
301 		if(((ulong)argp&(BY2PG-1)) < BY2WD)
302 			validaddr((ulong)argp, BY2WD, 0);
303 		validaddr((ulong)a, 1, 0);
304 		nbytes += (vmemchr(a, 0, 0x7FFFFFFF) - a) + 1;
305 		nargs++;
306 	}
307 	ssize = BY2WD*(nargs+1) + ((nbytes+(BY2WD-1)) & ~(BY2WD-1));
308 
309 	/*
310 	 * 8-byte align SP for those (e.g. sparc) that need it.
311 	 * execregs() will subtract another 4 bytes for argc.
312 	 */
313 	if((ssize+4) & 7)
314 		ssize += 4;
315 	spage = (ssize+(BY2PG-1)) >> PGSHIFT;
316 	/*
317 	 * Build the stack segment, putting it in kernel virtual for the moment
318 	 */
319 	if(spage > TSTKSIZ)
320 		error(Enovmem);
321 
322 	p->seg[ESEG] = newseg(SG_STACK, TSTKTOP-USTKSIZE, USTKSIZE/BY2PG);
323 
324 	/*
325 	 * Args: pass 2: assemble; the pages will be faulted in
326 	 */
327 	argv = (char**)(TSTKTOP - ssize);
328 	charp = (char*)(TSTKTOP - nbytes);
329 	if(indir)
330 		argp = progarg;
331 	else
332 		argp = (char**)arg[1];
333 
334 	for(i=0; i<nargs; i++){
335 		if(indir && *argp==0) {
336 			indir = 0;
337 			argp = (char**)arg[1];
338 		}
339 		*argv++ = charp + (USTKTOP-TSTKTOP);
340 		n = strlen(*argp) + 1;
341 		memmove(charp, *argp++, n);
342 		charp += n;
343 	}
344 
345 	memmove(p->text, elem, NAMELEN);
346 
347 	/*
348 	 * Committed.
349 	 * Free old memory.
350 	 * Special segments are maintained accross exec
351 	 */
352 	for(i = SSEG; i <= BSEG; i++) {
353 		putseg(p->seg[i]);
354 		/* prevent a second free if we have an error */
355 		p->seg[i] = 0;
356 	}
357 	for(i = BSEG+1; i < NSEG; i++) {
358 		s = p->seg[i];
359 		if(s != 0 && (s->type&SG_CEXEC)) {
360 			putseg(s);
361 			p->seg[i] = 0;
362 		}
363 	}
364 
365 	/*
366 	 * Close on exec
367 	 */
368 	f = u->p->fgrp;
369 	for(i=0; i<=f->maxfd; i++)
370 		fdclose(i, CCEXEC);
371 
372 	/* Text.  Shared. Attaches to cache image if possible */
373 	/* attachimage returns a locked cache image */
374 	img = attachimage(SG_TEXT|SG_RONLY, tc, UTZERO, (t-UTZERO)>>PGSHIFT);
375 	ts = img->s;
376 	p->seg[TSEG] = ts;
377 	ts->flushme = 1;
378 	ts->fstart = 0;
379 	ts->flen = sizeof(Exec)+text;
380 	unlock(img);
381 
382 	/* Data. Shared. */
383 	s = newseg(SG_DATA, t, (d-t)>>PGSHIFT);
384 	p->seg[DSEG] = s;
385 
386 	/* Attached by hand */
387 	incref(img);
388 	s->image = img;
389 	s->fstart = ts->fstart+ts->flen;
390 	s->flen = data;
391 
392 	/* BSS. Zero fill on demand */
393 	p->seg[BSEG] = newseg(SG_BSS, d, (b-d)>>PGSHIFT);
394 
395 	/*
396 	 * Move the stack
397 	 */
398 	s = p->seg[ESEG];
399 	p->seg[ESEG] = 0;
400 	p->seg[SSEG] = s;
401 	s->base = USTKTOP-USTKSIZE;
402 	s->top = USTKTOP;
403 	relocateseg(s, TSTKTOP-USTKTOP);
404 
405 	/*
406 	 *  '/' processes are higher priority (hack to make /ip more responsive).
407 	 */
408 	if(devchar[tc->type] == L'/')
409 		u->p->basepri = PriRoot;
410 	u->p->priority = u->p->basepri;
411 	close(tc);
412 
413 	/*
414 	 *  At this point, the mmu contains info about the old address
415 	 *  space and needs to be flushed
416 	 */
417 	flushmmu();
418 	qlock(&p->debug);
419 	u->nnote = 0;
420 	u->notify = 0;
421 	u->notified = 0;
422 	procsetup(p);
423 	qunlock(&p->debug);
424 	if(p->hang)
425 		p->procctl = Proc_stopme;
426 
427 	return execregs(entry, ssize, nargs);
428 }
429 
430 int
431 shargs(char *s, int n, char **ap)
432 {
433 	int i;
434 
435 	s += 2;
436 	n -= 2;		/* skip #! */
437 	for(i=0; s[i]!='\n'; i++)
438 		if(i == n-1)
439 			return 0;
440 	s[i] = 0;
441 	*ap = 0;
442 	i = 0;
443 	for(;;){
444 		while(*s==' ' || *s=='\t')
445 			s++;
446 		if(*s == 0)
447 			break;
448 		i++;
449 		*ap++ = s;
450 		*ap = 0;
451 		while(*s && *s!=' ' && *s!='\t')
452 			s++;
453 		if(*s == 0)
454 			break;
455 		else
456 			*s++ = 0;
457 	}
458 	return i;
459 }
460 
461 int
462 return0(void *a)
463 {
464 	USED(a);
465 	return 0;
466 }
467 
468 long
469 syssleep(ulong *arg)
470 {
471 	int n;
472 
473 	n = arg[0];
474 	if(n == 0){
475 		sched();	/* yield */
476 		return 0;
477 	}
478 	if(MS2TK(n) == 0)	/* sleep for at least one tick */
479 		n = TK2MS(1);
480 	tsleep(&u->p->sleep, return0, 0, n);
481 
482 	return 0;
483 }
484 
485 long
486 sysalarm(ulong *arg)
487 {
488 	return procalarm(arg[0]);
489 }
490 
491 long
492 sysexits(ulong *arg)
493 {
494 	char *status;
495 	char *inval = "invalid exit string";
496 	char buf[ERRLEN];
497 
498 	status = (char*)arg[0];
499 	if(status){
500 		if(waserror())
501 			status = inval;
502 		else{
503 			validaddr((ulong)status, 1, 0);
504 			if(vmemchr(status, 0, ERRLEN) == 0){
505 				memmove(buf, status, ERRLEN);
506 				buf[ERRLEN-1] = 0;
507 				status = buf;
508 			}
509 		}
510 		poperror();
511 
512 	}
513 	pexit(status, 1);
514 	return 0;		/* not reached */
515 }
516 
517 long
518 syswait(ulong *arg)
519 {
520 	if(arg[0]){
521 		validaddr(arg[0], sizeof(Waitmsg), 1);
522 		evenaddr(arg[0]);
523 	}
524 	return pwait((Waitmsg*)arg[0]);
525 }
526 
527 long
528 sysdeath(ulong *arg)
529 {
530 	USED(arg);
531 	pprint("deprecated system call\n");
532 	pexit("Suicide", 0);
533 	return 0;	/* not reached */
534 }
535 
536 long
537 syserrstr(ulong *arg)
538 {
539 	char tmp[ERRLEN];
540 
541 	validaddr(arg[0], ERRLEN, 1);
542 	memmove(tmp, (char*)arg[0], ERRLEN);
543 	memmove((char*)arg[0], u->error, ERRLEN);
544 	memmove(u->error, tmp, ERRLEN);
545 	return 0;
546 }
547 
548 long
549 sysnotify(ulong *arg)
550 {
551 	USED(arg);
552 	if(arg[0] != 0)
553 		validaddr(arg[0], sizeof(ulong), 0);
554 	u->notify = (int(*)(void*, char*))(arg[0]);
555 	return 0;
556 }
557 
558 long
559 sysnoted(ulong *arg)
560 {
561 	if(arg[0]!=NRSTR && !u->notified)
562 		error(Egreg);
563 	return 0;
564 }
565 
566 long
567 syssegbrk(ulong *arg)
568 {
569 	Segment *s;
570 	int i;
571 
572 	for(i = 0; i < NSEG; i++) {
573 		if(s = u->p->seg[i]) {
574 			if(arg[0] >= s->base && arg[0] < s->top) {
575 				switch(s->type&SG_TYPE) {
576 				case SG_TEXT:
577 				case SG_DATA:
578 				case SG_STACK:
579 					error(Ebadarg);
580 				default:
581 					return ibrk(arg[1], i);
582 				}
583 			}
584 		}
585 	}
586 
587 	error(Ebadarg);
588 	return 0;		/* not reached */
589 }
590 
591 long
592 syssegattach(ulong *arg)
593 {
594 	return segattach(u->p, arg[0], (char*)arg[1], arg[2], arg[3]);
595 }
596 
597 long
598 syssegdetach(ulong *arg)
599 {
600 	int i;
601 	Segment *s;
602 
603 	s = 0;
604 	for(i = 0; i < NSEG; i++)
605 		if(s = u->p->seg[i]) {
606 			qlock(&s->lk);
607 			if((arg[0] >= s->base && arg[0] < s->top) ||
608 			   (s->top == s->base && arg[0] == s->base))
609 				goto found;
610 			qunlock(&s->lk);
611 		}
612 
613 	error(Ebadarg);
614 
615 found:
616 	if((ulong)arg >= s->base && (ulong)arg < s->top) {
617 		qunlock(&s->lk);
618 		error(Ebadarg);
619 	}
620 	u->p->seg[i] = 0;
621 	qunlock(&s->lk);
622 	putseg(s);
623 
624 	/* Ensure we flush any entries from the lost segment */
625 	flushmmu();
626 	return 0;
627 }
628 
629 long
630 syssegfree(ulong *arg)
631 {
632 	Segment *s;
633 	ulong from, pages;
634 
635 	from = PGROUND(arg[0]);
636 	s = seg(u->p, from, 1);
637 	if(s == 0)
638 		error(Ebadarg);
639 
640 	pages = (arg[1]+BY2PG-1)/BY2PG;
641 
642 	if(from+pages*BY2PG > s->top) {
643 		qunlock(&s->lk);
644 		error(Ebadarg);
645 	}
646 
647 	mfreeseg(s, from, pages);
648 	qunlock(&s->lk);
649 	flushmmu();
650 
651 	return 0;
652 }
653 
654 /* For binary compatability */
655 long
656 sysbrk_(ulong *arg)
657 {
658 	return ibrk(arg[0], BSEG);
659 }
660 
661 long
662 sysrendezvous(ulong *arg)
663 {
664 	Proc *p, **l;
665 	int tag;
666 	ulong val;
667 
668 	tag = arg[0];
669 	l = &REND(u->p->pgrp, tag);
670 
671 	lock(u->p->pgrp);
672 	for(p = *l; p; p = p->rendhash) {
673 		if(p->rendtag == tag) {
674 			*l = p->rendhash;
675 			val = p->rendval;
676 			p->rendval = arg[1];
677 			/* Hard race avoidance */
678 			while(p->mach != 0)
679 				;
680 			ready(p);
681 			unlock(u->p->pgrp);
682 			return val;
683 		}
684 		l = &p->rendhash;
685 	}
686 
687 	/* Going to sleep here */
688 	p = u->p;
689 	p->rendtag = tag;
690 	p->rendval = arg[1];
691 	p->rendhash = *l;
692 	*l = p;
693 	u->p->state = Rendezvous;
694 	unlock(p->pgrp);
695 
696 	sched();
697 
698 	return u->p->rendval;
699 }
700