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 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 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 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 96 trapUSR2(int signo) 97 { 98 USED(signo); 99 /* we've done our work of interrupting sigsuspend */ 100 } 101 102 static void 103 trapILL(int signo) 104 { 105 disfault(nil, "Illegal instruction"); 106 } 107 108 static void 109 trapSEGV(int signo) 110 { 111 disfault(nil, "Segmentation violation"); 112 } 113 114 static void 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 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 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 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 252 oshostintr(Proc *p) 253 { 254 kill(p->sigid, SIGUSR1); 255 } 256 257 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 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 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 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 297 termrestore(void) 298 { 299 tcsetattr(0, TCSANOW, &tinit); 300 } 301 302 void 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 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 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 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 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 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 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 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 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 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 456 osyield(void) 457 { 458 sched_yield(); 459 } 460 461 void 462 ospause(void) 463 { 464 for(;;) 465 pause(); 466 } 467 468 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 480 _stackfree(void *stack) 481 { 482 *((void **)stack) = stacklist.free; 483 stacklist.free = stack; 484 } 485 486 static void 487 stackfreeandexit(void *stack) 488 { 489 lock(&stacklist.l); 490 _stackfree(stack); 491 unlockandexit(&stacklist.l.val); 492 } 493 494 static void * 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 526 segflush(void *a, ulong n) 527 { 528 USED(a); 529 USED(n); 530 return 0; 531 } 532