xref: /inferno-os/emu/OpenBSD/os.c (revision ebcf8d9b30a1bc12ed7da82c9b1bae3bf11ef0dd)
1 #include	"dat.h"
2 #include	"fns.h"
3 #include	"error.h"
4 #undef getwd
5 #include <sys/types.h>
6 #include <sys/mman.h>
7 #include	<sys/param.h>
8 #include	<sys/resource.h>
9 #include 	<sys/socket.h>
10 #include	<sys/time.h>
11 #include	<signal.h>
12 #include	<time.h>
13 #include	<termios.h>
14 #include	<sched.h>
15 #include	<pwd.h>
16 #include	<errno.h>
17 #include	<unistd.h>
18 #include	<fpuctl.h>
19 
20 enum
21 {
22 	DELETE  = 0x7F,
23 	NSTACKSPERALLOC = 16,
24 	X11STACK=	256*1024
25 };
26 char *hosttype = "OpenBSD";
27 
28 int rfork_thread(int, void *, void (*)(void *), void *);
29 
30 extern void unlockandexit(int*);
31 extern void executeonnewstack(void*, void (*f)(void*), void*);
32 static void *stackalloc(Proc *p, void **tos);
33 static void stackfreeandexit(void *stack);
34 
35 extern int dflag;
36 
37 void
38 pexit(char *msg, int t)
39 {
40 	Osenv *e;
41 	Proc *p;
42 	void *kstack;
43 
44 	lock(&procs.l);
45 	p = up;
46 	if(p->prev)
47 		p->prev->next = p->next;
48 	else
49 		procs.head = p->next;
50 
51 	if(up->next)
52 		p->next->prev = p->prev;
53 	else
54 		procs.tail = p->prev;
55 	unlock(&procs.l);
56 
57 	if(0)
58 		print("pexit: %s: %s\n", up->text, msg);
59 
60 	e = up->env;
61 	if(e != nil) {
62 		closefgrp(e->fgrp);
63 		closepgrp(e->pgrp);
64 		closeegrp(e->egrp);
65 		closesigs(e->sigs);
66 	}
67 	kstack = p->kstack;
68 	free(p->prog);
69 	free(p);
70 	if(kstack != nil)
71 		stackfreeandexit(kstack);
72 }
73 
74 void
75 trapBUS(int signo, siginfo_t *info, void *context)
76 {
77 	if(info)
78 		print("trapBUS: signo: %d code: %d addr: %lx\n",
79 		info->si_signo, info->si_code, info->si_addr);
80 	else
81 		print("trapBUS: no info\n");
82 	disfault(nil, "Bus error");
83 }
84 
85 static void
86 trapUSR1(int signo)
87 {
88 	int intwait;
89 
90 	USED(signo);
91 
92 	intwait = up->intwait;
93 	up->intwait = 0;	/* clear it to let proc continue in osleave */
94 
95 	if(up->type != Interp)		/* Used to unblock pending I/O */
96 		return;
97 	if(intwait == 0)		/* Not posted so its a sync error */
98 		disfault(nil, Eintr);	/* Should never happen */
99 }
100 
101 static void
102 trapUSR2(int signo)
103 {
104 	USED(signo);
105 	/* we've done our work of interrupting sigsuspend */
106 }
107 
108 static void
109 trapILL(int signo)
110 {
111 	disfault(nil, "Illegal instruction");
112 }
113 
114 static void
115 trapSEGV(int signo)
116 {
117 	disfault(nil, "Segmentation violation");
118 }
119 
120 static void
121 trapFPE(int signo)
122 {
123 	char buf[64];
124 	USED(signo);
125 	snprint(buf, sizeof(buf), "sys: fp: exception status=%.4lux", getfsr());
126 	disfault(nil, buf);
127 }
128 
129 static sigset_t initmask;
130 
131 static void
132 setsigs(void)
133 {
134 	struct sigaction act;
135 	sigset_t mask;
136 
137 	memset(&act, 0 , sizeof(act));
138 	sigemptyset(&initmask);
139 
140 	signal(SIGPIPE, SIG_IGN);	/* prevent signal when devcmd child exits */
141 	if(signal(SIGTERM, SIG_IGN) != SIG_IGN)
142 		signal(SIGTERM, cleanexit);
143 
144 	act.sa_handler = trapUSR1;
145 	act.sa_mask = initmask;
146 	sigaction(SIGUSR1, &act, nil);
147 
148 	act.sa_handler = trapUSR2;
149 	sigaction(SIGUSR2, &act, nil);
150 	sigemptyset(&mask);
151 	sigaddset(&mask, SIGUSR2);
152 	sigaddset(&initmask, SIGUSR2);
153 	sigprocmask(SIG_BLOCK, &mask, NULL);
154 
155 	/*
156  	 * prevent Zombies forming when any process terminates
157 	 */
158 	act.sa_sigaction = 0;
159 	act.sa_flags |= SA_NOCLDWAIT;
160 	if(sigaction(SIGCHLD, &act, nil))
161 		panic("sigaction SIGCHLD");
162 
163 	if(sflag == 0) {
164 		act.sa_sigaction = trapBUS;
165 		act.sa_flags |= SA_SIGINFO;
166 		if(sigaction(SIGBUS, &act, nil))
167 			panic("sigaction SIGBUS");
168 		act.sa_handler = trapILL;
169 		if(sigaction(SIGILL, &act, nil))
170 			panic("sigaction SIGBUS");
171 		act.sa_handler = trapSEGV;
172 		if(sigaction(SIGSEGV, &act, nil))
173 			panic("sigaction SIGSEGV");
174 		act.sa_handler = trapFPE;
175 		if(sigaction(SIGFPE, &act, nil))
176 			panic("sigaction SIGFPE");
177 		if(sigaddset(&initmask, SIGINT) == -1)
178 			panic("sigaddset");
179 	}
180 	if(sigprocmask(SIG_BLOCK, &initmask, nil)!= 0)
181 		panic("sigprocmask");
182 }
183 
184 static void
185 tramp(void *arg)
186 {
187 	Proc *p;
188 
189 	p = arg;
190 	p->pid = p->sigid = getpid();
191 	sigprocmask(SIG_BLOCK, &initmask, nil);	/* in 5.3, rfork_thread doesn't copy from parent, contrary to docs? */
192 	(*p->func)(p->arg);
193 	pexit("{Tramp}", 0);
194 	_exit(0);
195 }
196 
197 int
198 kproc(char *name, void (*func)(void*), void *arg, int flags)
199 {
200 	Proc *p;
201 	Pgrp *pg;
202 	Fgrp *fg;
203 	Egrp *eg;
204 	int pid;
205 	void *tos;
206 
207 	p = newproc();
208 
209 	if(flags & KPDUPPG) {
210 		pg = up->env->pgrp;
211 		incref(&pg->r);
212 		p->env->pgrp = pg;
213 	}
214 	if(flags & KPDUPFDG) {
215 		fg = up->env->fgrp;
216 		incref(&fg->r);
217 		p->env->fgrp = fg;
218 	}
219 	if(flags & KPDUPENVG) {
220 		eg = up->env->egrp;
221 		incref(&eg->r);
222 		p->env->egrp = eg;
223 	}
224 
225 	p->env->uid = up->env->uid;
226 	p->env->gid = up->env->gid;
227 	kstrdup(&p->env->user, up->env->user);
228 
229 	strcpy(p->text, name);
230 
231 	p->func = func;
232 	p->arg = arg;
233 
234 	lock(&procs.l);
235 	if(procs.tail != nil) {
236 		p->prev = procs.tail;
237 		procs.tail->next = p;
238 	}
239 	else {
240 		procs.head = p;
241 		p->prev = nil;
242 	}
243 	procs.tail = p;
244 	unlock(&procs.l);
245 
246 	if(flags & KPX11){
247 		p->kstack = nil;	/* never freed; also up not defined */
248 		tos = (char*)mallocz(X11STACK, 0) + X11STACK - sizeof(void*);
249 	}else
250 		p->kstack = stackalloc(p, &tos);
251 	pid = rfork_thread(RFPROC|RFMEM|RFNOWAIT, tos, tramp, p);
252 	if(pid < 0)
253 		panic("ourfork");
254 
255 	return pid;
256 
257 }
258 
259 void
260 oshostintr(Proc *p)
261 {
262 	kill(p->sigid, SIGUSR1);
263 }
264 
265 void
266 osblock(void)
267 {
268 	sigset_t mask;
269 
270 	sigprocmask(SIG_SETMASK, NULL, &mask);
271 	sigdelset(&mask, SIGUSR2);
272 	sigsuspend(&mask);
273 }
274 
275 void
276 osready(Proc *p)
277 {
278 	if(kill(p->sigid, SIGUSR2) < 0)
279 		fprint(2, "emu: osready failed: pid %d: %s\n", p->sigid, strerror(errno));
280 }
281 
282 void
283 oslongjmp(void *regs, osjmpbuf env, int val)
284 {
285 	USED(regs);
286 	siglongjmp(env, val);
287 }
288 
289 struct termios tinit;
290 
291 static void
292 termset(void)
293 {
294 	struct termios t;
295 
296 	tcgetattr(0, &t);
297 	tinit = t;
298 	t.c_lflag &= ~(ICANON|ECHO|ISIG);
299 	t.c_cc[VMIN] = 1;
300 	t.c_cc[VTIME] = 0;
301 	tcsetattr(0, TCSANOW, &t);
302 }
303 
304 static void
305 termrestore(void)
306 {
307 	tcsetattr(0, TCSANOW, &tinit);
308 }
309 
310 void
311 cleanexit(int x)
312 {
313 	USED(x);
314 
315 	if(up->intwait) {
316 		up->intwait = 0;
317 		return;
318 	}
319 
320 	if(dflag == 0)
321 		termrestore();
322 
323 	kill(0, SIGKILL);
324 	exit(0);
325 }
326 
327 void
328 osreboot(char *file, char **argv)
329 {
330 	if(dflag == 0)
331 		termrestore();
332 	execvp(file, argv);
333 	panic("reboot failure");
334 }
335 
336 int gidnobody= -1, uidnobody= -1;
337 
338 void
339 getnobody()
340 {
341 	struct passwd *pwd;
342 
343 	if(pwd = getpwnam("nobody")) {
344 		uidnobody = pwd->pw_uid;
345 		gidnobody = pwd->pw_gid;
346 	}
347 }
348 
349 void
350 libinit(char *imod)
351 {
352 	struct passwd *pw;
353 	Proc *p;
354 	void *tos;
355 	char sys[64];
356 
357 	setsid();
358 
359 	gethostname(sys, sizeof(sys));
360 	kstrdup(&ossysname, sys);
361 	getnobody();
362 
363 	if(dflag == 0)
364 		termset();
365 
366 	setsigs();
367 
368 	p = newproc();
369 	p->kstack = stackalloc(p, &tos);
370 
371 	pw = getpwuid(getuid());
372 	if(pw != nil)
373 		kstrdup(&eve, pw->pw_name);
374 	else
375 		print("cannot getpwuid\n");
376 
377 	p->env->uid = getuid();
378 	p->env->gid = getgid();
379 
380 	executeonnewstack(tos, emuinit, imod);
381 }
382 
383 int
384 readkbd(void)
385 {
386 	int n;
387 	char buf[1];
388 
389 	n = read(0, buf, sizeof(buf));
390 	if(n < 0)
391 		print("keyboard close (n=%d, %s)\n", n, strerror(errno));
392 	if(n <= 0)
393 		pexit("keyboard thread", 0);
394 
395 	switch(buf[0]) {
396 	case '\r':
397 		buf[0] = '\n';
398 		break;
399 	case DELETE:
400 		cleanexit(0);
401 		break;
402 	}
403 	return buf[0];
404 }
405 
406 /*
407  * Return an abitrary millisecond clock time
408  */
409 long
410 osmillisec(void)
411 {
412 	static long sec0 = 0, usec0;
413 	struct timeval t;
414 
415 	if(gettimeofday(&t,(struct timezone*)0)<0)
416 		return 0;
417 	if(sec0==0) {
418 		sec0 = t.tv_sec;
419 		usec0 = t.tv_usec;
420 	}
421 	return (t.tv_sec-sec0)*1000+(t.tv_usec-usec0+500)/1000;
422 }
423 
424 int
425 limbosleep(ulong milsec)
426 {
427 	return osmillisleep(milsec);
428 }
429 
430 /*
431  * Return the time since the epoch in nanoseconds and microseconds
432  * The epoch is defined at 1 Jan 1970
433  */
434 vlong
435 osnsec(void)
436 {
437 	struct timeval t;
438 
439 	gettimeofday(&t, nil);
440 	return (vlong)t.tv_sec*1000000000L + t.tv_usec*1000;
441 }
442 
443 vlong
444 osusectime(void)
445 {
446 	struct timeval t;
447 
448 	gettimeofday(&t, nil);
449 	return (vlong)t.tv_sec * 1000000 + t.tv_usec;
450 }
451 
452 int
453 osmillisleep(ulong milsec)
454 {
455 	struct timespec time;
456 
457 	time.tv_sec = milsec / 1000;
458 	time.tv_nsec = (milsec % 1000) * 1000000;
459 	nanosleep(&time, 0);
460 	return 0;
461 }
462 
463 void
464 osyield(void)
465 {
466 	sched_yield();
467 }
468 
469 void
470 ospause(void)
471 {
472 	for(;;)
473 		pause();
474 }
475 
476 void
477 oslopri(void)
478 {
479 	setpriority(PRIO_PROCESS, 0, getpriority(PRIO_PROCESS,0)+4);
480 }
481 
482 static struct {
483 	Lock l;
484 	void *free;
485 } stacklist;
486 
487 static void
488 _stackfree(void *stack)
489 {
490 	*((void **)stack) = stacklist.free;
491 	stacklist.free = stack;
492 }
493 
494 static void
495 stackfreeandexit(void *stack)
496 {
497 	lock(&stacklist.l);
498 	_stackfree(stack);
499 	unlockandexit(&stacklist.l.val);
500 }
501 
502 static void *
503 stackalloc(Proc *p, void **tos)
504 {
505 	void *rv;
506 	lock(&stacklist.l);
507 	if (stacklist.free == 0) {
508 		int x;
509 		/*
510 		 * obtain some more by using sbrk()
511 		 */
512 		void *more = sbrk(KSTACK * (NSTACKSPERALLOC + 1));
513 		if (more == 0)
514 			panic("stackalloc: no more stacks");
515 		/*
516 		 * align to KSTACK
517 		 */
518 		more = (void *)((((unsigned long)more) + (KSTACK - 1)) & ~(KSTACK - 1));
519 		/*
520 		 * free all the new stacks onto the freelist
521 		 */
522 		for (x = 0; x < NSTACKSPERALLOC; x++)
523 			_stackfree((char *)more + KSTACK * x);
524 	}
525 	rv = stacklist.free;
526 	stacklist.free = *(void **)rv;
527 	unlock(&stacklist.l);
528 	*tos = rv + KSTACK - sizeof(void*);
529 	*(Proc **)rv = p;
530 	return rv;
531 }
532 
533 int
534 segflush(void *p, ulong n)
535 {
536 	return mprotect(p, n, PROT_EXEC|PROT_READ|PROT_WRITE);
537 }
538