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