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