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