#include #include #include #include "dat.h" #include "fns.h" #include "linux.h" static int timernotefd; static void timerproc(void*); static int pidhash(int pid) { return (pid - 1) % MAXPROC; } Uproc* getproc(int tid) { Uproc *p; if(tid > 0){ p = &proctab.proc[pidhash(tid)]; if(p->tid == tid) return p; } return nil; } Uproc* getprocn(int n) { Uproc *p; p = &proctab.proc[n]; if(p->tid > 0) return p; return nil; } static Uproc* allocproc(void) { Uproc *p; int tid, i; for(i=0; itid <= 0){ proctab.alloc++; p->tid = tid; p->pid = tid; p->pgid = tid; p->psid = tid; return p; } } trace("allocproc(): out of processes"); return nil; } static void freeproc(Uproc *p) { Uwait *w; while(w = p->freewait){ p->freewait = w->next; free(w); } exittrace(p); free(p->comm); free(p->root); free(p->cwd); free(p->kcwd); memset(p, 0, sizeof(*p)); proctab.alloc--; } void initproc(void) { Uproc *p; char buf[1024]; int pid; proctab.nextpid = 10; p = allocproc(); p->kpid = getpid(); snprint(buf, sizeof(buf), "/proc/%d/note", p->kpid); p->notefd = open(buf, OWRITE); snprint(buf, sizeof(buf), "/proc/%d/args", p->kpid); p->argsfd = open(buf, ORDWR); current = p; inittrace(); inittime(); initsignal(); initmem(); inittls(); initfile(); if((pid = procfork(timerproc, nil, 0)) < 0) panic("initproc: unable to fork timerproc: %r"); snprint(buf, sizeof(buf), "/proc/%d/note", pid); timernotefd = open(buf, OWRITE); current->root = nil; current->cwd = kstrdup(getwd(buf, sizeof(buf))); current->kcwd = kstrdup(current->cwd); current->linkloop = 0; current->starttime = nsec(); inittrap(); } void setprocname(char *s) { if(current == nil){ char buf[32]; int fd; snprint(buf, sizeof(buf), "/proc/%d/args", getpid()); if((fd = open(buf, OWRITE)) >= 0){ write(fd, s, strlen(s)); close(fd); } } else { write(current->argsfd, s, strlen(s)); } } static void intrnote(void *, char *msg) { if(strncmp(msg, "interrupt", 9) == 0) noted(NCONT); noted(NDFLT); } struct kprocforkargs { int flags; void (*func)(void *aux); void *aux; }; static int kprocfork(void *arg) { struct kprocforkargs args; int pid; memmove(&args, arg, sizeof(args)); if((pid = rfork(RFPROC|RFMEM|args.flags)) != 0) return pid; notify(intrnote); unmapuserspace(); current = nil; profme(); args.func(args.aux); longjmp(exitjmp, 1); return -1; } /* * procfork starts a kernel process running on kstack. * that process will have linux memory segments (stack, private, * shared) unmapped but plan9 segments (text, bss, stack) shared. * here is no Uproc associated with it! current will be set to nil so * you cant call sys_????() functions in here. * procfork returns the plan9 pid. (usefull for posting notes) */ int procfork(void (*func)(void *aux), void *aux, int flags) { struct kprocforkargs args; args.flags = flags; args.func = func; args.aux = aux; return onstack(kstack, kprocfork, &args); } static void *Intr = (void*)~0; static char Notifyme[] = "notifyme"; static char Wakeme[] = "wakeme"; static char Xchange[] = "xchange"; static char Wakeup[] = "wakeup"; static char Abort[] = "abort"; int notifyme(int on) { Uproc *p; p = current; qlock(p); if(on){ if(p->notified || signalspending(p)){ qunlock(p); return 1; } if(p->state == nil) p->state = Notifyme; } else { p->state = nil; } qunlock(p); return 0; } void wakeme(int on) { Uproc *p; p = current; qlock(p); if(on){ if(p->state == nil) p->state = Wakeme; } else { p->state = nil; } qunlock(p); } int sleepproc(QLock *l, int flags) { Uproc *p; void *ret; char *x; p = current; qlock(p); x = p->state; if(x == nil || x == Wakeme){ p->xstate = x; p->state = Xchange; if(l != nil) qunlock(l); qunlock(p); if(flags && signalspending(p)){ ret = Intr; } else { ret = rendezvous(p, Xchange); } if(ret == Intr){ qlock(p); if(p->state != Xchange){ while((ret = rendezvous(p, Xchange)) == Intr) ; } else { p->state = x; } qunlock(p); } if(l != nil) qlock(l); } else { p->state = Wakeme; ret = x; qunlock(p); } return (ret == Wakeup) ? 0 : -ERESTART; } static int wakeup(Uproc *proc, char *m, int force) { char *x; if(proc != nil){ qlock(proc); x = proc->state; if(x == Wakeme){ proc->state = m; qunlock(proc); return 1; } if(x == Xchange){ proc->state = proc->xstate; proc->xstate = nil; qunlock(proc); while(rendezvous(proc, m) == Intr) ; return 1; } if((m != Wakeup) && (proc->notified == 0)){ if(x == Notifyme) proc->state = nil; if(x == Notifyme || force){ proc->notified = 1; qunlock(proc); write(proc->notefd, "interrupt", 9); return 1; } } qunlock(proc); } return 0; } Uwait* addwaitq(Uwaitq *q) { Uproc *p; Uwait *w; p = current; if(w = p->freewait){ p->freewait = w->next; } else { w = kmalloc(sizeof(*w)); } w->next = nil; w->proc = p; w->file = nil; w->q = q; qlock(q); w->nextq = q->w; q->w = w; qunlock(q); return w; } void delwaitq(Uwait *w) { Uwaitq *q; Uwait **x; q = w->q; qlock(q); for(x = &q->w; *x; x=&((*x)->nextq)){ if(*x == w){ *x = w->nextq; break; } } qunlock(q); w->q = nil; w->nextq = nil; w->proc = nil; putfile(w->file); w->file = nil; w->next = current->freewait; current->freewait = w; } int requeue(Uwaitq *q1, Uwaitq *q2, int nrequeue) { int n; Uwait *w; n = 1000; for(;;){ qlock(q1); if(canqlock(q2)) break; qunlock(q1); if(--n <= 0) return 0; sleep(0); } n = 0; while((w = q1->w) && (n < nrequeue)){ q1->w = w->nextq; w->q = q2; w->nextq = q2->w; q2->w = w; n++; } qunlock(q2); qunlock(q1); return n; } int wakeq(Uwaitq *q, int nwake) { int n; Uwait *w; n = 0; if(q != nil){ qlock(q); for(w = q->w; w && n < nwake; w=w->nextq) n += wakeup(w->proc, Wakeup, 0); qunlock(q); } return n; } int sleepq(Uwaitq *q, QLock *l, int flags) { Uwait *w; int ret; w = addwaitq(q); ret = sleepproc(l, flags); delwaitq(w); return ret; } static Uproc *alarmq; int procsetalarm(Uproc *proc, vlong t) { Uproc **pp; int ret; if(proc->alarm && t >= proc->alarm) return 0; ret = (alarmq == nil) || (t < alarmq->alarm); for(pp = &alarmq; *pp; pp = &((*pp)->alarmq)){ if(*pp == proc){ *pp = proc->alarmq; break; } } for(pp = &alarmq; *pp; pp = &((*pp)->alarmq)) if((*pp)->alarm > t) break; proc->alarm = t; proc->alarmq = *pp; *pp = proc; return ret; } void setalarm(vlong t) { qlock(&proctab); if(procsetalarm(current, t)) write(timernotefd, "interrupt", 9); qunlock(&proctab); } /* signal.c */ extern void alarmtimer(Uproc *proc, vlong now); static void timerproc(void*) { Uproc *h; vlong now; long m; setprocname("timerproc()"); while(proctab.alloc > 0){ qlock(&proctab); m = 2000; now = nsec(); while(h = alarmq){ if(now < h->alarm){ m = (h->alarm - now) / 1000000; break; } alarmq = h->alarmq; h->alarm = 0; h->alarmq = nil; if(h->timeout){ if(now >= h->timeout){ h->timeout = 0; wakeup(h, Wakeup, 0); } else procsetalarm(h, h->timeout); } alarmtimer(h, now); } qunlock(&proctab); sleep((m + (1000/HZ-1))/(1000/HZ)); } } /* static void timerproc(void *) { Uproc *p; vlong expire, now, wake, dead; int err, i, alive; char c; setprocname("timerproc()"); dead = 0; for(;;){ qlock(&proctab); now = nsec(); wake = now + 60000000000LL; alive = 0; for(i=0; iwstate & WEXITED) continue; if(p->kpid <= 0) continue; if(now >= dead){ if(read(p->argsfd, &c, 1) < 0){ err = mkerror(); if(err != -EINTR && err != -ERESTART){ p->kpid = 0; qunlock(&proctab); exitproc(p, SIGKILL, 1); qlock(&proctab); continue; } } } alive++; expire = p->timeout; if(expire > 0){ if(now >= expire){ p->timeout = 0; wakeup(p, Wakeup, 0); } else { if(expire < wake) wake = expire; } } expire = alarmtimer(p, now, wake); if(expire < wake) wake = expire; } qunlock(&proctab); if(now >= dead) dead = now + 5000000000LL; if(dead < wake) wake = dead; if(alive == 0) break; wake -= now; sleep(wake/1000000LL); } } */ int sys_waitpid(int pid, int *pexit, int opt) { int i, n, m, status; Uproc *p; trace("sys_waitpid(%d, %p, %d)", pid, pexit, opt); m = WEXITED; if(opt & WUNTRACED) m |= WSTOPPED; if(opt & WCONTINUED) m |= WCONTINUED; qlock(&proctab); for(;;){ n = 0; for(i=0; iexitsignal != SIGCHLD) && (opt & (WALL|WCLONE))==0) continue; if(p->ppid != current->pid) continue; if(pid > 0){ if(p->pid != pid) continue; } else if(pid == 0){ if(p->pgid != current->pgid) continue; } else if(pid < -1){ if(p->pgid != -pid) continue; } n++; trace("sys_waitpid(): child %d wstate %x", p->pid, p->wstate); if(p->wevent & m) goto found; } if(n == 0){ qunlock(&proctab); trace("sys_waitpid(): no children we can wait for"); return -ECHILD; } if(opt & WNOHANG){ qunlock(&proctab); trace("sys_waitpid(): no exited/stoped/cont children"); return 0; } if((i = sleepproc(&proctab, 1)) < 0){ qunlock(&proctab); return i; } } found: pid = p->pid; status = p->exitcode; p->wevent &= ~(p->wevent & m); if(p->wstate & WEXITED){ trace("sys_waitpid(): found zombie %d exitcode %d", pid, status); freeproc(p); } qunlock(&proctab); if(pexit) *pexit = status; return pid; } struct linux_rusage { struct linux_timeval ru_utime; /* user time used */ struct linux_timeval ru_stime; /* system time used */ long ru_maxrss; /* maximum resident set size */ long ru_ixrss; /* integral shared memory size */ long ru_idrss; /* integral unshared data size */ long ru_isrss; /* integral unshared stack size */ long ru_minflt; /* page reclaims */ long ru_majflt; /* page faults */ long ru_nswap; /* swaps */ long ru_inblock; /* block input operations */ long ru_oublock; /* block output operations */ long ru_msgsnd; /* messages sent */ long ru_msgrcv; /* messages received */ long ru_nsignals; /* signals received */ long ru_nvcsw; /* voluntary context switches */ long ru_nivcsw; /* involuntary context switches */ }; int sys_wait4(int pid, int *pexit, int opt, void *prusage) { int ret; struct linux_rusage *ru = prusage; trace("sys_wait4(%d, %p, %d, %p)", pid, pexit, opt, prusage); ret = sys_waitpid(pid, pexit, opt); if(ru != nil) memset(ru, 0, sizeof(*ru)); return ret; } int threadcount(int pid) { Uproc *p; int i, n; n = 0; for(i = 0; ipid == pid) n++; } return n; } int killproc(Uproc *p, Usiginfo *info, int group) { int i, n; Uproc *w; int sig, err; if((err = sendsignal(p, info, group)) <= 0) return err; w = p; sig = info->signo; if(group && !wantssignal(w, sig)){ for(i=1, n = p->tid + 1; ipid != w->pid) continue; if(!wantssignal(p, info->signo)) continue; w = p; break; } } wakeup(w, Abort, (sig == SIGKILL || sig == SIGSTOP || sig == SIGALRM)); return 0; } enum { CLD_EXITED = 1, CLD_KILLED, CLD_DUMPED, CLD_TRAPPED, CLD_STOPPED, CLD_CONTINUED, }; /* * queue the exit signal into the parent process. this * doesnt do the wakeup like killproc(). */ static int sendexitsignal(Uproc *parent, Uproc *proc, int sig, int code) { Usiginfo si; memset(&si, 0, sizeof(si)); switch(si.signo = sig){ case SIGCHLD: switch(code & 0xFF){ case 0: si.code = CLD_EXITED; break; case SIGSTOP: si.code = CLD_STOPPED; break; case SIGCONT: si.code = CLD_CONTINUED; break; case SIGKILL: si.code = CLD_KILLED; break; default: si.code = CLD_DUMPED; break; } si.chld.pid = proc->pid; si.chld.uid = proc->uid; si.chld.status = code; } return sendsignal(parent, &si, 1); } /* * wakeup all threads who are in the same thread group * as p including p. must be called with proctab locked. */ static void wakeupall(Uproc *p, char *m, int force) { int pid, i, n; pid = p->pid; for(i=0, n = p->tid; ipid == pid) wakeup(p, m, force); } static void zap(void *) { exitproc(current, 0, 0); } void zapthreads(void) { Uproc *p; int i, n, z; for(;;){ z = 0; for(i=1, n = current->tid+1; ipid != current->pid || p == current) continue; if(p->kpid <= 0) continue; trace("zapthreads() zapping thread %p", p); p->tracearg = current; p->traceproc = zap; wakeup(p, Abort, 1); z++; } if(z == 0) break; sleepproc(&proctab, 0); } } struct kexitprocargs { Uproc *proc; int code; int group; }; #pragma profile off static int kexitproc(void *arg) { struct kexitprocargs *args; Uproc *proc; int code, group; Uproc *parent, *child, **pp; int i; args = arg; proc = args->proc; code = args->code; group = args->group; if(proc == current){ trace("kexitproc: cleartidptr = %p", proc->cleartidptr); if(okaddr(proc->cleartidptr, sizeof(*proc->cleartidptr), 1)) *proc->cleartidptr = 0; sys_futex((ulong*)proc->cleartidptr, 1, MAXPROC, nil, nil, 0); qlock(&proctab); exitsignal(); qunlock(&proctab); exitmem(); } exitfile(proc); close(proc->notefd); proc->notefd = -1; close(proc->argsfd); proc->argsfd = -1; qlock(&proctab); for(pp = &alarmq; *pp; pp = &((*pp)->alarmq)){ if(*pp == proc){ *pp = proc->alarmq; proc->alarmq = nil; break; } } /* reparent children, and reap when zombies */ for(i=0; ippid != proc->pid) continue; child->ppid = 0; if(child->wstate & WEXITED) freeproc(child); } /* if we got zapped, just free the proc and wakeup zapper */ if((proc == current) && (proc->traceproc == zap) && (parent = proc->tracearg)){ freeproc(proc); wakeup(parent, Wakeup, 0); goto zapped; } if(group && proc == current) zapthreads(); parent = getproc(proc->ppid); if((threadcount(proc->pid)==1) && parent && (proc->exitsignal == SIGCHLD) && !ignoressignal(parent, SIGCHLD)){ /* we are zombie */ proc->exitcode = code; proc->wstate = WEXITED; proc->wevent = proc->wstate; if(proc == current){ current->kpid = 0; sendexitsignal(parent, proc, proc->exitsignal, code); wakeupall(parent, Abort, 0); qunlock(&proctab); longjmp(exitjmp, 1); } else { sendexitsignal(parent, proc, proc->exitsignal, code); } } else { /* we are clone */ if(parent && proc->exitsignal > 0) sendexitsignal(parent, proc, proc->exitsignal, code); freeproc(proc); } if(parent) wakeupall(parent, Abort, 0); zapped: qunlock(&proctab); if(proc == current) longjmp(exitjmp, 1); return 0; } void exitproc(Uproc *proc, int code, int group) { struct kexitprocargs args; trace("exitproc(%p, %d, %d)", proc, code, group); args.proc = proc; args.code = code; args.group = group; if(proc == current){ onstack(kstack, kexitproc, &args); } else { kexitproc(&args); } } struct kstoparg { Uproc *stopper; int code; }; static void stop(void *aux) { struct kstoparg *arg = aux; stopproc(current, arg->code, 0); } void stopproc(Uproc *proc, int code, int group) { struct kstoparg *arg; Uproc *p, *parent; int i, n, z; trace("stopproc(%p, %d, %d)", proc, code, group); qlock(&proctab); proc->exitcode = code; proc->wstate = WSTOPPED; proc->wevent = proc->wstate; if((proc == current) && (proc->traceproc == stop) && (arg = proc->tracearg)){ proc->traceproc = nil; proc->tracearg = nil; wakeup(arg->stopper, Wakeup, 0); qunlock(&proctab); return; } /* put all threads in the stopped state */ arg = nil; while(group){ if(arg == nil){ arg = kmalloc(sizeof(*arg)); arg->stopper = current; arg->code = code; } z = 0; for(i=1, n = proc->tid+1; ipid != proc->pid || p == proc) continue; if(p->kpid <= 0) continue; if(p->wstate & (WSTOPPED | WEXITED)) continue; trace("stopproc() stopping thread %p", p); p->tracearg = arg; p->traceproc = stop; wakeup(p, Abort, 1); z++; } if(z == 0) break; sleepproc(&proctab, 0); } free(arg); if(parent = getproc(proc->ppid)){ if(group && !ignoressignal(parent, SIGCHLD)) sendexitsignal(parent, proc, SIGCHLD, code); wakeupall(parent, Abort, 0); } qunlock(&proctab); } void contproc(Uproc *proc, int code, int group) { Uproc *p, *parent; int i, n; trace("contproc(%p, %d, %d)", proc, code, group); qlock(&proctab); proc->exitcode = code; proc->wstate = WCONTINUED; proc->wevent = proc->wstate; if(group){ for(i=1, n = proc->tid+1; ipid != proc->pid || p == proc) continue; if(p->kpid <= 0) continue; if((p->wstate & WSTOPPED) == 0) continue; if(p->wstate & (WCONTINUED | WEXITED)) continue; trace("contproc() waking thread %p", p); p->exitcode = code; p->wstate = WCONTINUED; p->wevent = p->wstate; wakeup(p, Wakeup, 0); } } if(parent = getproc(proc->ppid)){ if(group && !ignoressignal(parent, SIGCHLD)) sendexitsignal(parent, proc, SIGCHLD, code); wakeupall(parent, Abort, 0); } qunlock(&proctab); } int sys_exit(int code) { trace("sys_exit(%d)", code); exitproc(current, (code & 0xFF)<<8, 0); return -1; } int sys_exit_group(int code) { trace("sys_exit_group(%d)", code); exitproc(current, (code & 0xFF)<<8, 1); return -1; } struct kcloneprocargs { int flags; void *newstack; int *parenttidptr; void *tlsdescr; int *childtidptr; }; static int kcloneproc(void *arg) { struct kcloneprocargs args; struct linux_user_desc tls; Ureg ureg; int rflags, pid, tid; char buf[80]; Uproc *new; memmove(&args, arg, sizeof(args)); memmove(&ureg, current->ureg, sizeof(ureg)); if(args.flags & CLONE_SETTLS){ if(!okaddr(args.tlsdescr, sizeof(tls), 0)) return -EFAULT; memmove(&tls, args.tlsdescr, sizeof(tls)); } qlock(&proctab); if((new = allocproc()) == nil){ qunlock(&proctab); return -EAGAIN; } tid = new->tid; if(args.flags & CLONE_PARENT_SETTID){ if(!okaddr(args.parenttidptr, sizeof(*args.parenttidptr), 1)){ freeproc(new); qunlock(&proctab); return -EFAULT; } *args.parenttidptr = tid; } rflags = RFPROC; if(args.flags & CLONE_VM) rflags |= RFMEM; qlock(current); if((pid = rfork(rflags)) < 0){ freeproc(new); qunlock(current); qunlock(&proctab); trace("kcloneproc(): rfork failed: %r"); return mkerror(); } if(pid){ /* parent */ new->kpid = pid; new->exitsignal = args.flags & 0xFF; new->innote = 0; new->ureg = &ureg; new->syscall = current->syscall; new->sysret = current->sysret; new->comm = nil; new->ncomm = 0; new->linkloop = 0; new->root = current->root ? kstrdup(current->root) : nil; new->cwd = kstrdup(current->cwd); new->kcwd = kstrdup(current->kcwd); new->starttime = nsec(); snprint(buf, sizeof(buf), "/proc/%d/note", pid); new->notefd = open(buf, OWRITE); snprint(buf, sizeof(buf), "/proc/%d/args", pid); new->argsfd = open(buf, ORDWR); if(args.flags & (CLONE_THREAD | CLONE_PARENT)){ new->ppid = current->ppid; } else { new->ppid = current->pid; } if(args.flags & CLONE_THREAD) new->pid = current->pid; new->cleartidptr = nil; if(args.flags & CLONE_CHILD_CLEARTID) new->cleartidptr = args.childtidptr; new->pgid = current->pgid; new->psid = current->psid; new->uid = current->uid; new->gid = current->gid; clonetrace(new, !(args.flags & CLONE_THREAD)); clonesignal(new, !(args.flags & CLONE_SIGHAND), !(args.flags & CLONE_THREAD)); clonemem(new, !(args.flags & CLONE_VM)); clonefile(new, !(args.flags & CLONE_FILES)); clonetls(new); qunlock(&proctab); while(rendezvous(new, 0) == (void*)~0) ; qunlock(current); return tid; } /* child */ current = new; profme(); /* wait for parent to copy our resources */ while(rendezvous(new, 0) == (void*)~0) ; trace("kcloneproc(): hello world"); if(args.flags & CLONE_SETTLS) sys_set_thread_area(&tls); if(args.flags & CLONE_CHILD_SETTID) if(okaddr(args.childtidptr, sizeof(*args.childtidptr), 1)) *args.childtidptr = tid; if(args.newstack != nil) current->ureg->sp = (ulong)args.newstack; current->sysret(0); retuser(); return -1; } #pragma profile on int sys_linux_clone(int flags, void *newstack, int *parenttidptr, int *tlsdescr, void *childtidptr) { struct kcloneprocargs a; trace("sys_linux_clone(%x, %p, %p, %p, %p)", flags, newstack, parenttidptr, childtidptr, tlsdescr); a.flags = flags; a.newstack = newstack; a.parenttidptr = parenttidptr; a.childtidptr = childtidptr; a.tlsdescr = tlsdescr; return onstack(kstack, kcloneproc, &a); } int sys_fork(void) { trace("sys_fork()"); return sys_linux_clone(SIGCHLD, nil, nil, nil, nil); } int sys_vfork(void) { trace("sys_vfork()"); return sys_fork(); } int sys_getpid(void) { trace("sys_getpid()"); return current->pid; } int sys_getppid(void) { trace("sys_getppid()"); return current->ppid; } int sys_gettid(void) { trace("sys_gettid()"); return current->tid; } int sys_setpgid(int pid, int pgid) { int i, n; trace("sys_setpgid(%d, %d)", pid, pgid); if(pgid == 0) pgid = current->pgid; if(pid == 0) pid = current->pid; n = 0; qlock(&proctab); for(i=0; ipid != pid) continue; p->pgid = pgid; n++; } qunlock(&proctab); return n ? 0 : -ESRCH; } int sys_getpgid(int pid) { int i; int pgid; trace("sys_getpgid(%d)", pid); pgid = -ESRCH; if(pid == 0) return current->pgid; qlock(&proctab); for(i=0; ipid != pid) continue; pgid = p->pgid; break; } qunlock(&proctab); return pgid; } int sys_getpgrp(void) { trace("sys_getpgrp()"); return sys_getpgid(0); } int sys_getuid(void) { trace("sys_getuid()"); return current->uid; } int sys_getgid(void) { trace("sys_getgid()"); return current->gid; } int sys_setuid(int uid) { trace("sys_setuid(%d)", uid); current->uid = uid; return 0; } int sys_setgid(int gid) { trace("sys_setgid(%d)", gid); current->gid = gid; return 0; } int sys_setresuid(int ruid, int euid, int suid) { trace("sys_setresuid(%d, %d, %d)", ruid, euid, suid); return 0; } int sys_setresgid(int rgid, int egid, int sgid) { trace("sys_setresgid(%d, %d, %d)", rgid, egid, sgid); return 0; } int sys_setreuid(int ruid, int euid) { trace("sys_setreuid(%d, %d)", ruid, euid); return 0; } int sys_setregid(int rgid, int egid) { trace("sys_setregid(%d, %d)", rgid, egid); return 0; } int sys_getresuid(int *ruid, int *euid, int *suid) { trace("sys_getresuid(%p, %p, %p)", ruid, euid, suid); if(ruid == nil) return -EINVAL; if(euid == nil) return -EINVAL; if(suid == nil) return -EINVAL; *ruid = current->uid; *euid = current->uid; *suid = current->uid; return 0; } int sys_getresgid(int *rgid, int *egid, int *sgid) { trace("sys_getresgid(%p, %p, %p)", rgid, egid, sgid); if(rgid == nil) return -EINVAL; if(egid == nil) return -EINVAL; if(sgid == nil) return -EINVAL; *rgid = current->gid; *egid = current->gid; *sgid = current->gid; return 0; } int sys_setsid(void) { int i; trace("sys_setsid()"); if(current->pid == current->pgid) return -EPERM; qlock(&proctab); for(i=0; ipid != current->pid) continue; p->pgid = current->pid; p->psid = current->pid; } qunlock(&proctab); settty(nil); return current->pgid; } int sys_getsid(int pid) { int i, pgid; trace("sys_getsid(%d)", pid); pgid = -ESRCH; if(pid == 0) pid = current->pid; qlock(&proctab); for(i=0; ipid != pid) continue; if(p->pid != p->psid) continue; pgid = p->pgid; break; } qunlock(&proctab); return pgid; } int sys_getgroups(int size, int *groups) { trace("sys_getgroups(%d, %p)", size, groups); if(size < 0) return -EINVAL; return 0; } int sys_setgroups(int size, int *groups) { trace("sys_setgroups(%d, %p)", size, groups); return 0; } struct linux_utsname { char sysname[65]; char nodename[65]; char release[65]; char version[65]; char machine[65]; char domainname[65]; }; int sys_uname(void *a) { struct linux_utsname *p = a; trace("sys_uname(%p)", a); strncpy(p->sysname, "Linux", 65); strncpy(p->nodename, sysname(), 65); strncpy(p->release, "3.2.1", 65); strncpy(p->version, "linuxemu", 65); strncpy(p->machine, "i386", 65); strncpy(p->domainname, sysname(), 65); return 0; } int sys_personality(ulong p) { trace("sys_personality(%lux)", p); if(p != 0 && p != 0xffffffff) return -EINVAL; return 0; } int sys_tkill(int tid, int sig) { int err; trace("sys_tkill(%d, %S)", tid, sig); err = -EINVAL; if(tid > 0){ Uproc *p; err = -ESRCH; qlock(&proctab); if(p = getproc(tid)){ Usiginfo si; memset(&si, 0, sizeof(si)); si.signo = sig; si.code = SI_TKILL; si.kill.pid = current->tid; si.kill.uid = current->uid; err = killproc(p, &si, 0); } qunlock(&proctab); } return err; } int sys_tgkill(int pid, int tid, int sig) { int err; trace("sys_tgkill(%d, %d, %S)", pid, tid, sig); err = -EINVAL; if(tid > 0){ Uproc *p; err = -ESRCH; qlock(&proctab); if((p = getproc(tid)) && (p->pid == pid)){ Usiginfo si; memset(&si, 0, sizeof(si)); si.signo = sig; si.code = SI_TKILL; si.kill.pid = current->tid; si.kill.uid = current->uid; err = killproc(p, &si, 0); } qunlock(&proctab); } return err; } int sys_rt_sigqueueinfo(int pid, int sig, void *info) { int err; Uproc *p; Usiginfo si; trace("sys_rt_sigqueueinfo(%d, %S, %p)", pid, sig, info); err = -ESRCH; qlock(&proctab); if(p = getproc(pid)){ memset(&si, 0, sizeof(si)); linux2siginfo(info, &si); si.signo = sig; si.code = SI_QUEUE; err = killproc(p, &si, 1); } qunlock(&proctab); return err; } enum { PIDMAPBITS1 = 8*sizeof(ulong), }; int sys_kill(int pid, int sig) { int i, j, n; Uproc *p; Usiginfo si; ulong pidmap[(MAXPROC + PIDMAPBITS1-1) / PIDMAPBITS1]; ulong m; trace("sys_kill(%d, %S)", pid, sig); n = 0; memset(pidmap, 0, sizeof(pidmap)); qlock(&proctab); for(i=0; iwstate & WEXITED) continue; if(p->kpid <= 0) continue; if(pid == 0){ if(p->pgid != current->pgid) continue; } else if(pid == -1){ if(p->pid <= 1) continue; if(p->tid == current->tid) continue; } else if(pid < -1) { if(p->pgid != -pid) continue; } else { if(p->pid != pid) continue; } /* make sure we send only one signal per pid */ j = pidhash(p->pid); m = 1 << (j % PIDMAPBITS1); j /= PIDMAPBITS1; if(pidmap[j] & m) continue; pidmap[j] |= m; if(sig > 0){ memset(&si, 0, sizeof(si)); si.signo = sig; si.code = SI_USER; si.kill.pid = current->tid; si.kill.uid = current->uid; killproc(p, &si, 1); } n++; } qunlock(&proctab); if(n == 0) return -ESRCH; return 0; } int sys_set_tid_address(int *tidptr) { trace("sys_set_tid_address(%p)", tidptr); current->cleartidptr = tidptr; return current->pid; } struct linux_sched_param { int sched_priority; }; int sys_sched_setscheduler(int pid, int policy, void *param) { trace("sys_sched_setscheduler(%d, %d, %p)", pid, policy, param); if(getproc(pid) == nil) return -ESRCH; return 0; } int sys_sched_getscheduler(int pid) { trace("sys_sched_getscheduler(%d)", pid); if(getproc(pid) == nil) return -ESRCH; return 0; } int sys_sched_setparam(int pid, void *param) { trace("sys_sched_setparam(%d, %p)", pid, param); if(getproc(pid) == nil) return -ESRCH; return 0; } int sys_sched_getparam(int pid, void *param) { struct linux_sched_param *p = param; trace("sys_sched_getparam(%d, %p)", pid, param); if(getproc(pid) == nil) return -ESRCH; if(p == nil) return -EINVAL; p->sched_priority = 0; return 0; } int sys_sched_yield(void) { trace("sys_sched_yield()"); sleep(0); return 0; } enum { RLIMIT_CPU, RLIMIT_FSIZE, RLIMIT_DATA, RLIMIT_STACK, RLIMIT_CORE, RLIMIT_RSS, RLIMIT_NPROC, RLIMIT_NOFILE, RLIMIT_MEMLOCK, RLIMIT_AS, RLIMIT_LOCKS, RLIMIT_SIGPENDING, RLIMIT_MSGQUEUE, RLIM_NLIMITS, RLIM_INFINITY = ~0UL, }; struct linux_rlimit { ulong rlim_cur; ulong rlim_max; }; int sys_getrlimit(long resource, void *rlim) { struct linux_rlimit *r = rlim; trace("sys_getrlimit(%ld, %p)", resource, rlim); if(resource >= RLIM_NLIMITS) return -EINVAL; if(rlim == nil) return -EFAULT; r->rlim_cur = RLIM_INFINITY; r->rlim_max = RLIM_INFINITY; switch(resource){ case RLIMIT_STACK: r->rlim_cur = USTACK; r->rlim_max = USTACK; break; case RLIMIT_CORE: r->rlim_cur = 0; break; case RLIMIT_NPROC: r->rlim_cur = MAXPROC; r->rlim_max = MAXPROC; break; case RLIMIT_NOFILE: r->rlim_cur = MAXFD; r->rlim_max = MAXFD; break; } return 0; } int sys_setrlimit(long resource, void *rlim) { trace("sys_setrlimit(%ld, %p)", resource, rlim); if(resource >= RLIM_NLIMITS) return -EINVAL; if(rlim == nil) return -EFAULT; return -EPERM; }