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