xref: /inferno-os/emu/Irix/os.c (revision 5d0c4cf3fc288434c41cba52dd998ab1d7375a7b)
1 /* Link with -lfpe. See man pages for fpc
2  * and /usr/include/sigfpe.h, sys/fpu.h.
3  */
4 #include	"dat.h"
5 #include	"fns.h"
6 #include	"error.h"
7 #include	<time.h>
8 #include	<ulocks.h>
9 #include	<termios.h>
10 #include 	<sigfpe.h>
11 #include	<sys/prctl.h>
12 #include 	<sys/fpu.h>
13 #include	<sys/cachectl.h>
14 #undef _POSIX_SOURCE		/* SGI incompetence */
15 #include	<signal.h>
16 #define _BSD_TIME
17 /* for gettimeofday(), which isn't POSIX,
18  * but is fairly common
19  */
20 #include 	<sys/time.h>
21 #define _POSIX_SOURCE
22 #include 	<pwd.h>
23 
24 extern	int	rebootargc;
25 extern	char**	rebootargv;
26 
27 int	gidnobody = -1;
28 int	uidnobody = -1;
29 Proc**	Xup;
30 
31 #define MAXSPROC 30000	/* max procs == MAXPID */
32 static int	sproctbl[MAXSPROC];
33 
34 enum
35 {
36 	KSTACK	= 64*1024,
37 	DELETE	= 0x7F
38 };
39 char *hosttype = "Irix";
40 char *cputype = "mips";
41 
42 extern int dflag;
43 
44 void
45 pexit(char *msg, int t)
46 {
47 	Osenv *e;
48 
49 	lock(&procs.l);
50 	if(up->prev)
51 		up->prev->next = up->next;
52 	else
53 		procs.head = up->next;
54 
55 	if(up->next)
56 		up->next->prev = up->prev;
57 	else
58 		procs.tail = up->prev;
59 
60 	sproctbl[getpid()] = -1;
61 
62 	unlock(&procs.l);
63 
64 /*	print("pexit: %s: %s\n", up->text, msg); /**/
65 	e = up->env;
66 	if(e != nil) {
67 		closefgrp(e->fgrp);
68 		closepgrp(e->pgrp);
69 		closeegrp(e->egrp);
70 		closesigs(e->sigs);
71 	}
72 	free(up->prog);
73 	free(up);
74 	exit(0);
75 }
76 
77 static void
78 tramp(void *p, size_t stacksz)
79 {
80 	up = p;
81 	up->sigid = getpid();
82 	up->func(up->arg);
83 	pexit("", 0);
84 }
85 
86 void
87 kproc(char *name, void (*func)(void*), void *arg, int flags)
88 {
89 	Proc *p;
90 	Pgrp *pg;
91 	Fgrp *fg;
92 	Egrp *eg;
93 	int pid;
94 	int id;
95 	int i;
96 
97 	p = newproc();
98 
99 	if(flags & KPDUPPG) {
100 		pg = up->env->pgrp;
101 		incref(&pg->r);
102 		p->env->pgrp = pg;
103 	}
104 	if(flags & KPDUPFDG) {
105 		fg = up->env->fgrp;
106 		incref(&fg->r);
107 		p->env->fgrp = fg;
108 	}
109 	if(flags & KPDUPENVG) {
110 		eg = up->env->egrp;
111 		incref(&eg->r);
112 		p->env->egrp = eg;
113 	}
114 
115 	p->env->uid = up->env->uid;
116 	p->env->gid = up->env->gid;
117 	kstrdup(&p->env->user, up->env->user);
118 
119 	strcpy(p->text, name);
120 
121 	p->func = func;
122 	p->arg = arg;
123 
124 	lock(&procs.l);
125 	if(procs.tail != nil) {
126 		p->prev = procs.tail;
127 		procs.tail->next = p;
128 	}
129 	else {
130 		procs.head = p;
131 		p->prev = nil;
132 	}
133 	procs.tail = p;
134 
135 	for(i = 1; i < MAXSPROC; i++) {
136 		if(sproctbl[i] == -1) {
137 			break;
138 		}
139 	}
140 
141 	if(i==MAXSPROC)
142 		return -1;
143 
144 	sproctbl[i] = -i - 1; /* temporary hold of table index outside of lock */
145 
146 	unlock(&procs.l);
147 
148 	pid = sprocsp(tramp, PR_SALL, p, 0, KSTACK);
149 
150 	if(pid >= 0)
151 		sproctbl[i] = pid;
152 	else
153 		sproctbl[i] = -1;
154 }
155 
156 void
157 osblock(void)
158 {
159 	blockproc(up->sigid);
160 }
161 
162 void
163 osready(Proc *p)
164 {
165 	unblockproc(p->sigid);
166 }
167 
168 void
169 trapUSR1(void)
170 {
171 	int intwait;
172 
173 	intwait = up->intwait;
174 	up->intwait = 0;	/* clear it to let proc continue in osleave */
175 
176 	if(up->type != Interp)		/* Used to unblock pending I/O */
177 		return;
178 
179 	if(intwait == 0)		/* Not posted so it's a sync error */
180 		disfault(nil, Eintr);	/* Should never happen */
181 }
182 
183 void
184 trapILL(void)
185 {
186 	disfault(nil, "Illegal instruction");
187 }
188 
189 void
190 trapBUS(void)
191 {
192 	disfault(nil, "Bus error");
193 }
194 
195 void
196 trapSEGV(void)
197 {
198 	disfault(nil, "Segmentation violation");
199 }
200 
201 /*
202  * This is not a signal handler but rather a vector from real/FPcontrol-Irix.c
203  */
204 void
205 trapFPE(unsigned exception[5], int value[2])
206 {
207 	disfault(nil, "Floating point exception");
208 }
209 
210 void
211 oshostintr(Proc *p)
212 {
213 	kill(p->sigid, SIGUSR1);
214 }
215 
216 void
217 oslongjmp(void *regs, osjmpbuf env, int val)
218 {
219 	USED(regs);
220 	siglongjmp(env, val);
221 }
222 
223 static struct termios tinit;
224 
225 static void
226 termset(void)
227 {
228 	struct termios t;
229 
230 	tcgetattr(0, &t);
231 	tinit = t;
232 	t.c_lflag &= ~(ICANON|ECHO|ISIG);
233 	t.c_cc[VMIN] = 1;
234 	t.c_cc[VTIME] = 0;
235 	tcsetattr(0, TCSANOW, &t);
236 }
237 
238 static void
239 termrestore(void)
240 {
241 	tcsetattr(0, TCSANOW, &tinit);
242 
243 /*	if(sproctbl[0] < 0)
244 		panic("corrupt sproc tbl");
245 
246 	kill(sproctbl[0], SIGUSR2);
247 	sginap(10000); */
248 }
249 
250 void
251 trapUSR2(void)
252 {
253 	int i;
254 
255 	for(i = MAXSPROC - 1; i > 0; i--) {
256 		if(sproctbl[i] != -1)
257 			kill(sproctbl[i], SIGKILL);
258 		sproctbl[i] = -1;
259 	}
260 
261 	execvp(rebootargv[0], rebootargv);
262 	panic("reboot failure");
263 }
264 
265 void
266 cleanexit(int x)
267 {
268 	USED(x);
269 
270 	if(up->intwait) {
271 		up->intwait = 0;
272 		return;
273 	}
274 
275 	if(dflag == 0)
276 		termrestore();
277 	kill(0, SIGKILL);
278 	exit(0);
279 }
280 
281 void
282 getnobody(void)
283 {
284 	struct passwd *pwd;
285 
286 	pwd = getpwnam("nobody");
287 	if(pwd != nil) {
288 		uidnobody = pwd->pw_uid;
289 		gidnobody = pwd->pw_gid;
290 	}
291 }
292 
293 void
294 osreboot(char *file, char **argv)
295 {
296 	if(dflag == 0)
297 		termrestore();
298 	execvp(file, argv);
299 	panic("reboot failure");
300 }
301 
302 void
303 libinit(char *imod)
304 {
305 	struct sigaction act;
306 	struct passwd *pw;
307 	int i;
308 	char sys[64];
309 
310 	setsid();
311 
312 	for(i=0; i<MAXSPROC; i++)
313 		sproctbl[i] = -1;
314 
315 	sproctbl[0] = getpid();
316 
317 	gethostname(sys, sizeof(sys));
318 	kstrdup(&ossysname, sys);
319 
320 	if(dflag == 0)
321 		termset();
322 
323 	if(signal(SIGTERM, SIG_IGN) != SIG_IGN)
324 		signal(SIGTERM, cleanexit);
325 	if(signal(SIGINT, SIG_IGN) != SIG_IGN)
326 		signal(SIGINT, cleanexit);
327 	signal(SIGUSR2, trapUSR2);
328 	/* For the correct functioning of devcmd in the
329 	 * face of exiting slaves
330 	 */
331 	signal(SIGCLD, SIG_IGN);
332 	signal(SIGPIPE, SIG_IGN);
333 	memset(&act, 0 , sizeof(act));
334 	act.sa_handler=trapUSR1;
335 	sigaction(SIGUSR1, &act, nil);
336 	if(sflag == 0) {
337 		act.sa_handler=trapBUS;
338 		sigaction(SIGBUS, &act, nil);
339 		act.sa_handler=trapILL;
340 		sigaction(SIGILL, &act, nil);
341 		act.sa_handler=trapSEGV;
342 		sigaction(SIGSEGV, &act, nil);
343 	}
344 
345 	if(usconfig(CONF_INITUSERS, 1000) < 0)
346 		panic("usconfig");
347 
348 	Xup = (Proc**)PRDA->usr_prda.fill;
349 	up = newproc();
350 
351 	pw = getpwuid(getuid());
352 	if(pw != nil) {
353 		if (strlen(pw->pw_name) + 1 <= KNAMELEN)
354 			strcpy(eve, pw->pw_name);
355 		else
356 			print("pw_name too long\n");
357 	}
358 	else
359 		print("cannot getpwuid\n");
360 
361 	/* after setting up, since this takes locks */
362 	getnobody();
363 	up->env->uid = getuid();
364 	up->env->gid = getgid();
365 	emuinit(imod);
366 }
367 
368 int
369 readkbd(void)
370 {
371 	int n;
372 	char buf[1];
373 
374 	n = read(0, buf, sizeof(buf));
375 	if(n < 0)
376 		fprint(2, "keyboard read error: %s\n", strerror(errno));
377 	if(n <= 0)
378 		pexit("keyboard thread", 0);
379 	switch(buf[0]) {
380 	case '\r':
381 		buf[0] = '\n';
382 		break;
383 	case DELETE:
384 		cleanexit(0);
385 		break;
386 	}
387 	return buf[0];
388 }
389 
390 int
391 segflush(void *a, ulong n)
392 {
393 	cacheflush(a, n, BCACHE);
394 	return 0;
395 }
396 
397 /*
398  * Return an abitrary millisecond clock time
399  */
400 long
401 osmillisec(void)
402 {
403 	static long sec0 = 0, usec0;
404 	struct timeval t;
405 
406 	if(gettimeofday(&t,(struct timezone*)0)<0)
407 		return(0);
408 	if(sec0==0){
409 		sec0 = t.tv_sec;
410 		usec0 = t.tv_usec;
411 	}
412 	return((t.tv_sec-sec0)*1000+(t.tv_usec-usec0+500)/1000);
413 }
414 
415 /*
416  * Return the time since the epoch in nanoseconds and microseconds
417  * The epoch is defined at 1 Jan 1970
418  */
419 vlong
420 osnsec(void)
421 {
422 	struct timeval t;
423 
424 	gettimeofday(&t, nil);
425 	return (vlong)t.tv_sec*1000000000L + t.tv_usec*1000;
426 }
427 
428 vlong
429 osusectime(void)
430 {
431 	struct timeval t;
432 
433 	gettimeofday(&t, nil);
434 	return (vlong)t.tv_sec * 1000000 + t.tv_usec;
435 }
436 
437 int
438 osmillisleep(ulong milsec)
439 {
440 	static int tick;
441 
442 	/*
443 	 * Posix-conforming CLK_TCK implementations tend to call sysconf,
444 	 * and we don't need the overhead.
445 	 */
446 	if(tick == 0)
447 		tick = CLK_TCK;
448 	sginap((tick*milsec)/1000);
449 	return 0;
450 }
451 
452 int
453 limbosleep(ulong milsec)
454 {
455 	return osmillisleep(milsec);
456 }
457 
458 void
459 osyield(void)
460 {
461 	sginap(0);
462 }
463 
464 void
465 ospause(void)
466 {
467 	for(;;)
468 		pause();
469 }
470 
471 void
472 oslopri(void)
473 {
474 	nice(2);
475 }
476