xref: /inferno-os/emu/Solaris/os.c (revision 7ef44d652ae9e5e1f5b3465d73684e4a54de73c0)
1 #include	"dat.h"
2 #include	"fns.h"
3 #include	"error.h"
4 #undef _POSIX_C_SOURCE
5 #undef getwd
6 #include	<unistd.h>
7 #include	<thread.h>
8 #include	<time.h>
9 #include	<termios.h>
10 #include	<signal.h>
11 #include 	<pwd.h>
12 #include	<sys/resource.h>
13 #include	<sys/time.h>
14 
15 enum
16 {
17 	DELETE  = 0x7F
18 };
19 char *hosttype = "Solaris";
20 
21 static thread_key_t	prdakey;
22 
23 static siginfo_t siginfo;
24 
25 extern int dflag;
26 
27 Proc*
28 getup(void)
29 {
30 	void *vp;
31 
32 	if (thr_getspecific(prdakey, &vp))
33 		return nil;
34 	return vp;
35 }
36 
37 void
38 pexit(char *msg, int t)
39 {
40 	Osenv *e;
41 
42 	lock(&procs.l);
43 	if(up->prev)
44 		up->prev->next = up->next;
45 	else
46 		procs.head = up->next;
47 
48 	if(up->next)
49 		up->next->prev = up->prev;
50 	else
51 		procs.tail = up->prev;
52 	unlock(&procs.l);
53 
54 	/*print("pexit: %s: %s\n", up->text, msg);*/
55 	e = up->env;
56 	if(e != nil) {
57 		closefgrp(e->fgrp);
58 		closepgrp(e->pgrp);
59 		closeegrp(e->egrp);
60 		closesigs(e->sigs);
61 	}
62 	free(up->prog);
63 	sema_destroy(up->os);
64 	free(up->os);
65 	free(up);
66 	thr_exit(0);
67 }
68 
69 static void *
70 tramp(void *v)
71 {
72 	struct Proc *Up;
73 
74 	if(thr_setspecific(prdakey, v)) {
75 		print("set specific data failed in tramp\n");
76 		thr_exit(0);
77 	}
78 	Up = v;
79 	Up->sigid = thr_self();
80 	Up->func(Up->arg);
81 	pexit("", 0);
82 }
83 
84 void
85 kproc(char *name, void (*func)(void*), void *arg, int flags)
86 {
87 	thread_t thread;
88 	Proc *p;
89 	Pgrp *pg;
90 	Fgrp *fg;
91 	Egrp *eg;
92 	sema_t *sem;
93 
94 	p = newproc();
95 
96 	sem = malloc(sizeof(*sem));
97 	if(sem == nil)
98 		panic("can't allocate semaphore");
99 	sema_init(sem, 0, USYNC_THREAD, 0);
100 	p->os = sem;
101 
102 	if(flags & KPDUPPG) {
103 		pg = up->env->pgrp;
104 		incref(&pg->r);
105 		p->env->pgrp = pg;
106 	}
107 	if(flags & KPDUPFDG) {
108 		fg = up->env->fgrp;
109 		incref(&fg->r);
110 		p->env->fgrp = fg;
111 	}
112 	if(flags & KPDUPENVG) {
113 		eg = up->env->egrp;
114 		incref(&eg->r);
115 		p->env->egrp = eg;
116 	}
117 
118 	p->env->uid = up->env->uid;
119 	p->env->gid = up->env->gid;
120 	kstrdup(&p->env->user, up->env->user);
121 
122 	strcpy(p->text, name);
123 
124 	p->func = func;
125 	p->arg = arg;
126 
127 	lock(&procs.l);
128 	if(procs.tail != nil) {
129 		p->prev = procs.tail;
130 		procs.tail->next = p;
131 	}
132 	else {
133 		procs.head = p;
134 		p->prev = nil;
135 	}
136 	procs.tail = p;
137 	unlock(&procs.l);
138 
139 	if(thr_create(0, 0, &tramp, p, THR_BOUND|THR_DETACHED, &thread))
140 		panic("thr_create failed\n");
141 	thr_yield();
142 }
143 
144 /* to get pc on trap use siginfo.si_pc field and define all trap handlers
145 	as printILL - have to set sa_sigaction, sa_flags not sa_handler
146 */
147 
148 static void
149 trapUSR1(void)
150 {
151 	int intwait;
152 
153 	intwait = up->intwait;
154 	up->intwait = 0;	/* clear it to let proc continue in osleave */
155 
156 	if(up->type != Interp)		/* Used to unblock pending I/O */
157 		return;
158 	if(intwait == 0)		/* Not posted so its a sync error */
159 		disfault(nil, Eintr);	/* Should never happen */
160 }
161 
162 static void
163 trapILL(void)
164 {
165 	disfault(nil, "Illegal instruction");
166 }
167 
168 static void
169 printILL(int sig, siginfo_t *siginfo, void *v)
170 {
171 	panic("Illegal instruction with code=%d at address=%x, opcode=%x.\n",
172 		siginfo->si_code, siginfo->si_addr,*(char*)siginfo->si_addr);
173 }
174 
175 static void
176 trapBUS(void)
177 {
178 	disfault(nil, "Bus error");
179 }
180 
181 static void
182 trapSEGV(void)
183 {
184 	disfault(nil, "Segmentation violation");
185 }
186 
187 static void
188 trapFPE(void)
189 {
190 	disfault(nil, "Floating point exception");
191 }
192 
193 void
194 oshostintr(Proc *p)
195 {
196 	thr_kill(p->sigid, SIGUSR1);
197 }
198 
199 void
200 osblock(void)
201 {
202 	while(sema_wait(up->os))
203 		;	/* retry on signals */
204 }
205 
206 void
207 osready(Proc *p)
208 {
209 	sema_post(p->os);
210 }
211 
212 void
213 oslongjmp(void *regs, osjmpbuf env, int val)
214 {
215 	USED(regs);
216 	siglongjmp(env, val);
217 }
218 
219 static struct termios tinit;
220 
221 static void
222 termset(void)
223 {
224 	struct termios t;
225 
226 	tcgetattr(0, &t);
227 	tinit = t;
228 	t.c_lflag &= ~(ICANON|ECHO|ISIG);
229 	t.c_cc[VMIN] = 1;
230 	t.c_cc[VTIME] = 0;
231 	tcsetattr(0, TCSANOW, &t);
232 }
233 
234 static void
235 termrestore(void)
236 {
237 	tcsetattr(0, TCSANOW, &tinit);
238 }
239 
240 void
241 cleanexit(int x)
242 {
243 	USED(x);
244 
245 	if(up->intwait) {
246 		up->intwait = 0;
247 		return;
248 	}
249 
250 	if(dflag == 0)
251 		termrestore();
252 	exit(0);
253 }
254 
255 int gidnobody= -1, uidnobody= -1;
256 
257 void
258 getnobody(void)
259 {
260 	struct passwd *pwd;
261 
262 	if (pwd=getpwnam("nobody")) {
263 		uidnobody = pwd->pw_uid;
264 		gidnobody = pwd->pw_gid;
265 	}
266 }
267 
268 void
269 osreboot(char *file, char **argv)
270 {
271 	if(dflag == 0)
272 		termrestore();
273 	execvp(file, argv);
274 	panic("reboot failure");
275 }
276 
277 void
278 libinit(char *imod)
279 {
280 	struct Proc *Up;
281 	struct sigaction act;
282 	struct passwd *pw;
283 	char sys[64];
284 
285 	setsid();
286 
287 	if(dflag == 0)
288 		termset();
289 
290 	gethostname(sys, sizeof(sys));
291 	kstrdup(&ossysname, sys);
292 	getnobody();
293 
294 	memset(&act, 0 , sizeof(act));
295 	act.sa_handler=trapUSR1;
296 	sigaction(SIGUSR1, &act, nil);
297 	/*
298 	 * For the correct functioning of devcmd in the
299 	 * face of exiting slaves
300 	 */
301 	signal(SIGPIPE, SIG_IGN);
302 	if(signal(SIGTERM, SIG_IGN) != SIG_IGN)
303 		signal(SIGTERM, cleanexit);
304 	if(sflag == 0) {
305 		act.sa_handler = trapBUS;
306 		sigaction(SIGBUS, &act, nil);
307 		act.sa_handler = trapILL;
308 		sigaction(SIGILL, &act, nil);
309 		act.sa_handler = trapSEGV;
310 		sigaction(SIGSEGV, &act, nil);
311 		act.sa_handler = trapFPE;
312 		sigaction(SIGFPE, &act, nil);
313 		if(signal(SIGINT, SIG_IGN) != SIG_IGN)
314 			signal(SIGINT, cleanexit);
315 	} else{
316 		act.sa_sigaction = printILL;
317 		act.sa_flags=SA_SIGINFO;
318 		sigaction(SIGILL, &act, nil);
319 	}
320 
321 	if(thr_keycreate(&prdakey,NULL))
322 		print("keycreate failed\n");
323 
324 	Up = newproc();
325 	if(thr_setspecific(prdakey,Up))
326 		panic("set specific thread data failed\n");
327 
328 	pw = getpwuid(getuid());
329 	if(pw != nil)
330 		kstrdup(&eve, pw->pw_name);
331 	else
332 		print("cannot getpwuid\n");
333 
334 	up->env->uid = getuid();
335 	up->env->gid = getgid();
336 	emuinit(imod);
337 }
338 
339 int
340 readkbd(void)
341 {
342 	int n;
343 	char buf[1];
344 
345 	n = read(0, buf, sizeof(buf));
346 	if(n < 0)
347 		fprint(2, "keyboard read: %s\n", strerror(errno));
348 	if(n <= 0)
349 		pexit("keyboard thread", 0);
350 
351 	switch(buf[0]) {
352 	case '\r':
353 		buf[0] = '\n';
354 		break;
355 	case DELETE:
356 		cleanexit(0);
357 		break;
358 	}
359 	return buf[0];
360 }
361 
362 /*
363  * Return an abitrary millisecond clock time
364  */
365 long
366 osmillisec(void)
367 {
368 	static long sec0 = 0, usec0;
369 	struct timeval t;
370 
371 	if(gettimeofday(&t, NULL)<0)
372 		return(0);
373 	if(sec0==0){
374 		sec0 = t.tv_sec;
375 		usec0 = t.tv_usec;
376 	}
377 	return((t.tv_sec-sec0)*1000+(t.tv_usec-usec0+500)/1000);
378 }
379 
380 /*
381  * Return the time since the epoch in nanoseconds and microseconds
382  * The epoch is defined at 1 Jan 1970
383  */
384 vlong
385 osnsec(void)
386 {
387 	struct timeval t;
388 
389 	gettimeofday(&t, nil);
390 	return (vlong)t.tv_sec*1000000000L + t.tv_usec*1000;
391 }
392 
393 vlong
394 osusectime(void)
395 {
396 	struct timeval t;
397 
398 	gettimeofday(&t, nil);
399 	return (vlong)t.tv_sec * 1000000 + t.tv_usec;
400 }
401 
402 int
403 osmillisleep(ulong milsec)
404 {
405 	struct  timespec time;
406 
407 	time.tv_sec = milsec/1000;
408 	time.tv_nsec= (milsec%1000)*1000000;
409 	nanosleep(&time,nil);
410 	return 0;
411 }
412 
413 int
414 limbosleep(ulong milsec)
415 {
416 	return osmillisleep(milsec);
417 }
418 
419 void
420 osyield(void)
421 {
422 	thr_yield();
423 }
424 
425 void
426 ospause(void)
427 {
428 	for(;;)
429 		pause();
430 }
431 
432 void
433 oslopri(void)
434 {
435 	setpriority(PRIO_PROCESS, 0, getpriority(PRIO_PROCESS,0)+4);
436 }
437