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