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 = "DragonFly";
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 char buf[64];
118 USED(signo);
119 snprint(buf, sizeof(buf), "sys: fp: exception status=%.4lux", getfsr());
120 disfault(nil, buf);
121 }
122
123 static sigset_t initmask;
124
125 static void
setsigs(void)126 setsigs(void)
127 {
128 struct sigaction act;
129 sigset_t mask;
130
131 memset(&act, 0 , sizeof(act));
132 sigemptyset(&initmask);
133
134 signal(SIGPIPE, SIG_IGN); /* prevent signal when devcmd child exits */
135 if(signal(SIGTERM, SIG_IGN) != SIG_IGN)
136 signal(SIGTERM, cleanexit);
137
138 act.sa_handler = trapUSR1;
139 act.sa_mask = initmask;
140 sigaction(SIGUSR1, &act, nil);
141
142 act.sa_handler = trapUSR2;
143 sigaction(SIGUSR2, &act, nil);
144 sigemptyset(&mask);
145 sigaddset(&mask, SIGUSR2);
146 sigaddset(&initmask, SIGUSR2);
147 sigprocmask(SIG_BLOCK, &mask, NULL);
148
149 /*
150 * prevent Zombies forming when any process terminates
151 */
152 act.sa_sigaction = 0;
153 act.sa_flags |= SA_NOCLDWAIT;
154 if(sigaction(SIGCHLD, &act, nil))
155 panic("sigaction SIGCHLD");
156
157 if(sflag == 0) {
158 act.sa_sigaction = trapBUS;
159 act.sa_flags |= SA_SIGINFO;
160 if(sigaction(SIGBUS, &act, nil))
161 panic("sigaction SIGBUS");
162 act.sa_handler = trapILL;
163 if(sigaction(SIGILL, &act, nil))
164 panic("sigaction SIGBUS");
165 act.sa_handler = trapSEGV;
166 if(sigaction(SIGSEGV, &act, nil))
167 panic("sigaction SIGSEGV");
168 act.sa_handler = trapFPE;
169 if(sigaction(SIGFPE, &act, nil))
170 panic("sigaction SIGFPE");
171 if(sigaddset(&initmask, SIGINT) == -1)
172 panic("sigaddset");
173 }
174 if(sigprocmask(SIG_BLOCK, &initmask, nil)!= 0)
175 panic("sigprocmask");
176 }
177
178 static int
tramp(void * arg)179 tramp(void *arg)
180 {
181 Proc *p;
182
183 p = arg;
184 p->pid = p->sigid = getpid();
185 sigprocmask(SIG_BLOCK, &initmask, nil); /* in 5.3, rfork_thread doesn't copy from parent, contrary to docs? */
186 (*p->func)(p->arg);
187 pexit("{Tramp}", 0);
188 _exit(0);
189 }
190
191 void
kproc(char * name,void (* func)(void *),void * arg,int flags)192 kproc(char *name, void (*func)(void*), void *arg, int flags)
193 {
194 Proc *p;
195 Pgrp *pg;
196 Fgrp *fg;
197 Egrp *eg;
198 int pid;
199 void *tos;
200
201 p = newproc();
202
203 if(flags & KPDUPPG) {
204 pg = up->env->pgrp;
205 incref(&pg->r);
206 p->env->pgrp = pg;
207 }
208 if(flags & KPDUPFDG) {
209 fg = up->env->fgrp;
210 incref(&fg->r);
211 p->env->fgrp = fg;
212 }
213 if(flags & KPDUPENVG) {
214 eg = up->env->egrp;
215 incref(&eg->r);
216 p->env->egrp = eg;
217 }
218
219 p->env->uid = up->env->uid;
220 p->env->gid = up->env->gid;
221 kstrdup(&p->env->user, up->env->user);
222
223 strcpy(p->text, name);
224
225 p->func = func;
226 p->arg = arg;
227
228 lock(&procs.l);
229 if(procs.tail != nil) {
230 p->prev = procs.tail;
231 procs.tail->next = p;
232 }
233 else {
234 procs.head = p;
235 p->prev = nil;
236 }
237 procs.tail = p;
238 unlock(&procs.l);
239
240 if(flags & KPX11){
241 p->kstack = nil; /* never freed; also up not defined */
242 tos = (char*)mallocz(X11STACK, 0) + X11STACK - sizeof(void*);
243 }else
244 p->kstack = stackalloc(p, &tos);
245 pid = rfork_thread(RFPROC|RFMEM|RFNOWAIT, tos, tramp, p);
246 if(pid < 0)
247 panic("rfork");
248 }
249
250 void
oshostintr(Proc * p)251 oshostintr(Proc *p)
252 {
253 kill(p->sigid, SIGUSR1);
254 }
255
256 void
osblock(void)257 osblock(void)
258 {
259 sigset_t mask;
260
261 sigprocmask(SIG_SETMASK, NULL, &mask);
262 sigdelset(&mask, SIGUSR2);
263 sigsuspend(&mask);
264 }
265
266 void
osready(Proc * p)267 osready(Proc *p)
268 {
269 if(kill(p->sigid, SIGUSR2) < 0)
270 fprint(2, "emu: osready failed: pid %d: %s\n", p->sigid, strerror(errno));
271 }
272
273 void
oslongjmp(void * regs,osjmpbuf env,int val)274 oslongjmp(void *regs, osjmpbuf env, int val)
275 {
276 USED(regs);
277 siglongjmp(env, val);
278 }
279
280 struct termios tinit;
281
282 static void
termset(void)283 termset(void)
284 {
285 struct termios t;
286
287 tcgetattr(0, &t);
288 tinit = t;
289 t.c_lflag &= ~(ICANON|ECHO|ISIG);
290 t.c_cc[VMIN] = 1;
291 t.c_cc[VTIME] = 0;
292 tcsetattr(0, TCSANOW, &t);
293 }
294
295 static void
termrestore(void)296 termrestore(void)
297 {
298 tcsetattr(0, TCSANOW, &tinit);
299 }
300
301 void
cleanexit(int x)302 cleanexit(int x)
303 {
304 USED(x);
305
306 if(up->intwait) {
307 up->intwait = 0;
308 return;
309 }
310
311 if(dflag == 0)
312 termrestore();
313
314 kill(0, SIGKILL);
315 exit(0);
316 }
317
318 void
osreboot(char * file,char ** argv)319 osreboot(char *file, char **argv)
320 {
321 if(dflag == 0)
322 termrestore();
323 execvp(file, argv);
324 panic("reboot failure");
325 }
326
327 int gidnobody= -1, uidnobody= -1;
328
329 void
getnobody()330 getnobody()
331 {
332 struct passwd *pwd;
333
334 if(pwd = getpwnam("nobody")) {
335 uidnobody = pwd->pw_uid;
336 gidnobody = pwd->pw_gid;
337 }
338 }
339
340 void
libinit(char * imod)341 libinit(char *imod)
342 {
343 struct passwd *pw;
344 Proc *p;
345 void *tos;
346 char sys[64];
347
348 setsid();
349
350 gethostname(sys, sizeof(sys));
351 kstrdup(&ossysname, sys);
352 getnobody();
353
354 if(dflag == 0)
355 termset();
356
357 setsigs();
358
359 p = newproc();
360 p->kstack = stackalloc(p, &tos);
361
362 pw = getpwuid(getuid());
363 if(pw != nil)
364 kstrdup(&eve, pw->pw_name);
365 else
366 print("cannot getpwuid\n");
367
368 p->env->uid = getuid();
369 p->env->gid = getgid();
370
371 executeonnewstack(tos, emuinit, imod);
372 }
373
374 int
readkbd(void)375 readkbd(void)
376 {
377 int n;
378 char buf[1];
379
380 n = read(0, buf, sizeof(buf));
381 if(n < 0)
382 print("keyboard close (n=%d, %s)\n", n, strerror(errno));
383 if(n <= 0)
384 pexit("keyboard thread", 0);
385
386 switch(buf[0]) {
387 case '\r':
388 buf[0] = '\n';
389 break;
390 case DELETE:
391 cleanexit(0);
392 break;
393 }
394 return buf[0];
395 }
396
397 /*
398 * Return an abitrary millisecond clock time
399 */
400 long
osmillisec(void)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 int
limbosleep(ulong milsec)416 limbosleep(ulong milsec)
417 {
418 return osmillisleep(milsec);
419 }
420
421 /*
422 * Return the time since the epoch in nanoseconds and microseconds
423 * The epoch is defined at 1 Jan 1970
424 */
425 vlong
osnsec(void)426 osnsec(void)
427 {
428 struct timeval t;
429
430 gettimeofday(&t, nil);
431 return (vlong)t.tv_sec*1000000000L + t.tv_usec*1000;
432 }
433
434 vlong
osusectime(void)435 osusectime(void)
436 {
437 struct timeval t;
438
439 gettimeofday(&t, nil);
440 return (vlong)t.tv_sec * 1000000 + t.tv_usec;
441 }
442
443 int
osmillisleep(ulong milsec)444 osmillisleep(ulong milsec)
445 {
446 struct timespec time;
447
448 time.tv_sec = milsec / 1000;
449 time.tv_nsec = (milsec % 1000) * 1000000;
450 nanosleep(&time, 0);
451 return 0;
452 }
453
454 void
osyield(void)455 osyield(void)
456 {
457 sched_yield();
458 }
459
460 void
ospause(void)461 ospause(void)
462 {
463 for(;;)
464 pause();
465 }
466
467 void
oslopri(void)468 oslopri(void)
469 {
470 setpriority(PRIO_PROCESS, 0, getpriority(PRIO_PROCESS,0)+4);
471 }
472
473 static struct {
474 Lock l;
475 void *free;
476 } stacklist;
477
478 static void
_stackfree(void * stack)479 _stackfree(void *stack)
480 {
481 *((void **)stack) = stacklist.free;
482 stacklist.free = stack;
483 }
484
485 static void
stackfreeandexit(void * stack)486 stackfreeandexit(void *stack)
487 {
488 lock(&stacklist.l);
489 _stackfree(stack);
490 unlockandexit(&stacklist.l.val);
491 }
492
493 static void *
stackalloc(Proc * p,void ** tos)494 stackalloc(Proc *p, void **tos)
495 {
496 void *rv;
497 lock(&stacklist.l);
498 if (stacklist.free == 0) {
499 int x;
500 /*
501 * obtain some more by using sbrk()
502 */
503 void *more = sbrk(KSTACK * (NSTACKSPERALLOC + 1));
504 if (more == 0)
505 panic("stackalloc: no more stacks");
506 /*
507 * align to KSTACK
508 */
509 more = (void *)((((unsigned long)more) + (KSTACK - 1)) & ~(KSTACK - 1));
510 /*
511 * free all the new stacks onto the freelist
512 */
513 for (x = 0; x < NSTACKSPERALLOC; x++)
514 _stackfree((char *)more + KSTACK * x);
515 }
516 rv = stacklist.free;
517 stacklist.free = *(void **)rv;
518 unlock(&stacklist.l);
519 *tos = rv + KSTACK - sizeof(void*);
520 *(Proc **)rv = p;
521 return rv;
522 }
523
524 int
segflush(void * a,ulong n)525 segflush(void *a, ulong n)
526 {
527 USED(a);
528 USED(n);
529 return 0;
530 }
531