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