| @@ -0,0 +1,532 @@ |
| | 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 | } |