static void xioproc(void *a) { Channel *c; Ioproc *io; Iocall *r; c = a; if(io = mallocz(sizeof(*io), 1)){ char buf[128]; /* * open might fail, ignore it for programs like factotum * that don't use iointerrupt() anyway. */ snprint(buf, sizeof(buf), "/proc/%d/ctl", getpid()); io->ctl = open(buf, OWRITE); if((io->creply = chancreate(sizeof(void*), 0)) == nil){ if(io->ctl >= 0) close(io->ctl); free(io); io = nil; } else io->c = c; } while(send(c, &io) < 0) ; if(io == nil) return; for(;;){ while(recv(io->c, &r) < 0) ; if(r == 0) break; if(io->intr){ r->ret = -1; strcpy(r->err, "interrupted"); } else if((r->ret = r->op(&r->arg)) < 0) rerrstr(r->err, sizeof r->err); qlock(io); if(io->intr){ io->intr = 0; if(io->ctl >= 0) write(io->ctl, "nointerrupt", 11); } while(send(io->creply, &r) < 0) ; qunlock(io); } if(io->ctl >= 0) close(io->ctl); chanfree(io->c); chanfree(io->creply); free(io); }
void convfree(Conv *c) { freeattr(c->attr); free(c->sysuser); chanfree(c->rpcwait); chanfree(c->keywait); free(c); }
int main(void) { int i, nprocs, procn[Nproc]; fail = 0; nprocs = 0; ch = chancreate(1000, sizeof(int)); if(ch == nil){ fail = 1; printf("chancreate failed\n"); } for(i = 0; i < Nproc; ++i){ procn[i] = i + 1; if(proccreate(f, &procn[i], 0) == nil){ fail = 1; printf("proccreate failed\n"); }else{ nprocs++; } } for(i = 0; i < nprocs; ++i){ int n; if(chanrecv(ch, &n) != 1){ fail = 1; printf("recv error\n"); } } chanfree(ch); return fail; }
int sunsrvudp(SunSrv *srv, char *address) { int fd; char adir[40]; Arg *arg; fd = announce(address, adir); if(fd < 0) return -1; arg = emalloc(sizeof(Arg)); arg->fd = fd; arg->srv = srv; arg->creply = chancreate(sizeof(SunMsg*), 10); arg->csync = chancreate(sizeof(void*), 10); proccreate(sunudpread, arg, SunStackSize); proccreate(sunudpwrite, arg, SunStackSize); recvp(arg->csync); recvp(arg->csync); chanfree(arg->csync); free(arg); return 0; }
static void execthread(void *a) { Client *c; int p; char tmp[32]; c = a; snprint(tmp, sizeof tmp, "exec%d", c->num); threadsetname(tmp); c->execpid = chancreate(sizeof(ulong), 0); proccreate(execproc, c, STACK); p = recvul(c->execpid); chanfree(c->execpid); c->execpid = nil; close(c->fd[1]); c->fd[1] = c->fd[0]; if(p != -1){ c->pid = p; c->activethread = 2; threadcreate(readthread, c, STACK); threadcreate(writethread, c, STACK); if(c->execreq) respond(c->execreq, nil); }else{ if(c->execreq) respond(c->execreq, c->err); } }
int pipeline(int fd, char *cmd, ...) { Exec *e; va_list a; e = emalloc(sizeof(Exec)); if(pipe(e->p)<0 || pipe(e->q)<0) error("can't create pipe"); close(e->p[0]); e->p[0] = fd; va_start(a, cmd); e->cmd = vsmprint(cmd, a); va_end(a); e->sync = chancreate(sizeof(ulong), 0); if(e->sync == nil) error("can't create channel"); proccreate(execproc, e, STACK); recvul(e->sync); chanfree(e->sync); free(e->cmd); close(e->p[0]); close(e->p[1]); close(e->q[1]); fd = e->q[0]; free(e); return fd; }
static void etherfree(Ether *e) { int i; Buf *bp; if(e->free != nil) e->free(e); closedev(e->epin); closedev(e->epout); if(e->rc == nil){ /* not really started */ free(e); return; } for(i = 0; i < e->nconns; i++) if(e->conns[i] != nil){ while((bp = nbrecvp(e->conns[i]->rc)) != nil) free(bp); chanfree(e->conns[i]->rc); free(e->conns[i]); } shutdownchan(e->bc); shutdownchan(e->rc); shutdownchan(e->wc); e->epin = e->epout = nil; devctl(e->dev, "detach"); free(e); }
static Cimage * loadimg(Rune *src, int x , int y) { Channel *sync; Cimage *ci; Runestr rs; Exec *e; char *filter; int fd, p[2], q[2]; ci = emalloc(sizeof(Cimage)); rs. r = src; rs.nr = runestrlen(rs.r); ci->url = urlalloc(&rs, nil, HGet); fd = urlopen(ci->url); if(fd < 0){ Err1: return ci; } filter = getfilter(ci->url->ctype.r, x, y); if(filter == nil){ werrstr("%S unsupported: %S", ci->url->ctype.r, ci->url->act.r); Err2: close(fd); goto Err1; } if(pipe(p)<0 || pipe(q)<0) error("can't create pipe"); close(p[0]); p[0] = fd; sync = chancreate(sizeof(ulong), 0); if(sync == nil) error("can't create channel"); e = emalloc(sizeof(Exec)); e->p[0] = p[0]; e->p[1] = p[1]; e->q[0] = q[0]; e->q[1] = q[1]; e->cmd = filter; e->sync = sync; proccreate(execproc, e, STACK); recvul(sync); chanfree(sync); close(p[0]); close(p[1]); close(q[1]); ci->mi = readmemimage(q[0]); close(q[0]); if(ci->mi == nil){ werrstr("can't read image"); goto Err2; } free(filter); return ci; }
static void shutdownchan(Channel *c) { Packser *bp; while((bp=nbrecvp(c)) != nil) free(bp); chanfree(c); }
Waitmsg* twaitfor(int pid) { Waitreq r; Waitmsg *w; r.pid = pid; r.c = chancreate(sizeof(Waitmsg*), 1); send(twaitchan, &r); w = recvp(r.c); chanfree(r.c); return w; }
int wctlmesg(Window *w, int m, Console *i) { print_func_entry(); switch(m){ default: error("unknown control message"); break; case Wakeup: break; case Rawon: break; case Rawoff: if(w->deleted) break; while(w->nraw > 0){ //wkeyctl(w, w->raw[0]); --w->nraw; runemove(w->raw, w->raw+1, w->nraw); } break; case Holdon: case Holdoff: if(w->deleted) break; break; case Deleted: if(w->deleted) break; write(w->notefd, "hangup", 6); proccreate(deletetimeoutproc, estrdup(w->name), 4096); wclosewin(w); break; case Exited: close(w->notefd); chanfree(w->mc.c); chanfree(w->ck); chanfree(w->cctl); chanfree(w->conswrite); chanfree(w->consread); chanfree(w->mouseread); chanfree(w->wctlread); free(w->raw); free(w->run); free(w->dir); free(w->label); free(w); break; } print_func_exit(); return m; }
void closekeyboard(Keyboardctl *kc) { Rune r; if(kc == nil) return; /* postnote(PNPROC, kc->pid, "kill"); */ do; while(nbrecv(kc->c, &r) > 0); chanfree(kc->c); free(kc); }
static void chan_release(struct kref *kref) { struct chan *c = container_of(kref, struct chan, ref); ERRSTACK(1); /* this style discards the error from close(). picture it as * if (waserror()) { } else { close(); } chanfree_no_matter_what(); */ if (!waserror()) { printd("releasing chan %p, type %d\n", c, c->type); /* -1 means there is no dev yet. wants a noop for close() */ if (c->type != -1) devtab[c->type].close(c); } /* need to poperror regardless of whether we error'd or not */ poperror(); /* and chan free no matter what */ chanfree(c); }
int threadspawn(int fd[3], char *cmd, char *argv[]) { int pid; Execjob e; e.fd = fd; e.cmd = cmd; e.argv = argv; e.c = chancreate(sizeof(void*), 0); proccreate(execproc, &e, 65536); close(fd[0]); close(fd[1]); close(fd[2]); pid = recvul(e.c); chanfree(e.c); return pid; }
void threadmain(int argc, char *argv[]) { char buf[512]; int fd; Channel *c; progname = "plumber"; ARGBEGIN{ case 'p': plumbfile = ARGF(); break; }ARGEND user = getenv("user"); home = getenv("home"); if(user==nil || home==nil) error("can't initialize $user or $home: %r"); if(plumbfile == nil){ sprint(buf, "%s/lib/plumbing", home); plumbfile = estrdup(buf); } fd = open(plumbfile, OREAD); if(fd < 0) error("can't open rules file %s: %r", plumbfile); if(setjmp(parsejmp)) error("parse error"); rules = readrules(plumbfile, fd); close(fd); /* * Start all processes and threads from other proc * so we (main pid) can return to user. */ c = chancreate(sizeof(void*), 0); proccreate(mainproc, c, 8192); recvp(c); chanfree(c); threadexits(nil); }
void execproc(void *v) { struct Exec *e; int p[2], q[2]; char *prog; char *argv[NARGS+1], args[NARGCHAR]; e = v; p[0] = e->p[0]; p[1] = e->p[1]; q[0] = e->q[0]; q[1] = e->q[1]; prog = e->prog; /* known not to be malloc'ed */ rfork(RFFDG); sendul(e->sync, 1); buildargv(e->argv, argv, args); free(e->argv); chanfree(e->sync); free(e); dup(p[0], 0); close(p[0]); close(p[1]); if(q[0]){ dup(q[1], 1); close(q[0]); close(q[1]); } procexec(nil, prog, argv); //fprint(2, "exec: %s", e->prog); //{int i; //for(i=0; argv[i]; i++) print(" '%s'", argv[i]); //print("\n"); //} //argv[0] = "cat"; //argv[1] = nil; //procexec(nil, "/bin/cat", argv); fprint(2, "Mail: can't exec %s: %r\n", prog); threadexits("can't exec"); }
void ventiproc(void *dummy) { int i; Block *db; u32int bno; u64int bsize; USED(dummy); proccreate(vtsendproc, z, STACK); proccreate(vtrecvproc, z, STACK); writechan = chancreate(sizeof(WriteReq), 0); for(i=0; i<nwritethread; i++) threadcreate(writethread, nil, STACK); vtcachesetwrite(zcache, myvtwrite); bsize = fsys->blocksize; vtfilelock(vfile, -1); while((db = qread(qventi, &bno)) != nil){ if(nop){ blockput(db); continue; } if(vtfilewrite(vfile, db->data, bsize, bno*bsize) != bsize) sysfatal("ventiproc vtfilewrite: %r"); if(vtfileflushbefore(vfile, (bno+1)*bsize) < 0) sysfatal("ventiproc vtfileflushbefore: %r"); blockput(db); } vtfileunlock(vfile); vtcachesetwrite(zcache, nil); for(i=0; i<nwritethread; i++) send(writechan, nil); chanfree(writechan); if(statustime) print("# %T venti proc exiting - nsend %d nrecv %d\n", nsend, nrecv); runlock(&endlk); }
/* * create a pipe, no streams are created until an open */ static Chan* pipeattach(char *spec) { Pipe *p; Chan *c; c = devattach('|', spec); if(waserror()){ chanfree(c); nexterror(); } p = malloc(sizeof(Pipe)); if(p == 0) exhausted("memory"); p->ref = 1; p->q[0] = qopen(conf.pipeqsize, 0, 0, 0); if(p->q[0] == 0){ free(p); exhausted("memory"); } p->q[1] = qopen(conf.pipeqsize, 0, 0, 0); if(p->q[1] == 0){ qfree(p->q[0]); free(p); exhausted("memory"); } poperror(); lock(&pipealloc); p->path = ++pipealloc.path; unlock(&pipealloc); p->perm = pipedir[Qdata0].perm; mkqid(&c->qid, NETQID(2*p->path, Qdir), 0, QTDIR); c->aux = p; c->dev = 0; return c; }
void execproc(void *v) { struct Exec *e; int p[2], q[2]; char *prog; char *argv[NARGS+1], args[NARGCHAR]; int fd[3]; e = v; p[0] = e->p[0]; p[1] = e->p[1]; q[0] = e->q[0]; q[1] = e->q[1]; prog = e->prog; /* known not to be malloc'ed */ fd[0] = dup(p[0], -1); if(q[0]) fd[1] = dup(q[1], -1); else fd[1] = dup(1, -1); fd[2] = dup(2, -2); sendul(e->sync, 1); buildargv(e->argv, argv, args); free(e->argv); chanfree(e->sync); free(e); threadexec(nil, fd, prog, argv); close(fd[0]); close(fd[1]); close(fd[2]); fprint(2, "Mail: can't exec %s: %r\n", prog); threadexits("can't exec"); }
char * tcs(char *cs, char *s, long *np) { Channel *sync; Exec *e; Rune r; long i, n; void **a; uchar *us; char buf[BUFSIZE], cmd[50]; char *t, *u; int p[2], q[2]; if(s==nil || *s=='\0' || *np==0){ werrstr("tcs failed: no data"); return s; } if(cs == nil){ werrstr("tcs failed: no charset"); return s; } if(cistrncmp(cs, "utf-8", 5)==0 || cistrncmp(cs, "utf8", 4)==0) return s; for(i=0; tcstab[i].mime!=nil; i++) if(cistrncmp(cs, tcstab[i].mime, strlen(tcstab[i].mime)) == 0) break; if(tcstab[i].mime == nil){ fprint(2, "abaco: charset: %s not supported\n", cs); goto latin1; } if(cistrcmp(tcstab[i].tcs, "8859-1")==0 || cistrcmp(tcstab[i].tcs, "ascii")==0){ latin1: n = 0; for(us=(uchar*)s; *us; us++) n += runelen(*us); n++; t = emalloc(n); for(us=(uchar*)s, u=t; *us; us++){ if(*us>=Winstart && *us<=Winend) *u++ = winchars[*us-Winstart]; else{ r = *us; u += runetochar(u, &r); } } *u = 0; free(s); return t; } if(pipe(p)<0 || pipe(q)<0) error("can't create pipe"); sync = chancreate(sizeof(ulong), 0); if(sync == nil) error("can't create channel"); snprint(cmd, sizeof cmd, "tcs -f %s", tcstab[i].tcs); e = emalloc(sizeof(Exec)); e->p[0] = p[0]; e->p[1] = p[1]; e->q[0] = q[0]; e->q[1] = q[1]; e->cmd = cmd; e->sync = sync; proccreate(execproc, e, STACK); recvul(sync); chanfree(sync); close(p[0]); close(q[1]); /* in case tcs fails */ t = s; sync = chancreate(sizeof(ulong), 0); if(sync == nil) error("can't create channel"); a = emalloc(4*sizeof(void *)); a[0] = sync; a[1] = (void *)p[1]; a[2] = s; a[3] = (void *)*np; proccreate(writeproc, a, STACK); s = nil; while((n = read(q[0], buf, sizeof(buf))) > 0){ s = erealloc(s, i+n+1); memmove(s+i, buf, n); i += n; s[i] = '\0'; } n = recvul(sync); if(n != *np) fprint(2, "tcs: did not write %ld; wrote %uld\n", *np, n); *np = i; chanfree(sync); close(q[0]); if(s == nil){ fprint(2, "tcs failed: can't convert charset=%s to %s\n", cs, tcstab[i].tcs); return t; } free(t); return s; }
int spawngs(GSInfo *g, char *safer) { Channel *cp; char *args[16]; char tb[32], gb[32]; int i, nargs; int devnull; int stdinp[2]; int stdoutp[2]; int dataout[2]; int errout[2]; /* * spawn gs * * gs's standard input is fed from stdinout. * gs output written to fd-2 (i.e. output we generate intentionally) is fed to stdinout. * gs output written to fd 1 (i.e. ouptut gs generates on error) is fed to errout. * gs data output is written to fd 3, which is dataout. */ if(pipe(stdinp)<0 || pipe(stdoutp)<0 || pipe(dataout)<0 || pipe(errout)<0) return -1; nargs = 0; args[nargs++] = "gs"; args[nargs++] = "-dNOPAUSE"; args[nargs++] = "-dNOPROMPT"; args[nargs++] = "-dDELAYSAFER"; args[nargs++] = "-dQUIET"; args[nargs++] = "-sDEVICE=bmp16m"; args[nargs++] = "-sOutputFile=/dev/fd/3"; args[nargs++] = "-r100"; sprint(tb, "-dTextAlphaBits=%d", textbits); sprint(gb, "-dGraphicsAlphaBits=%d", gfxbits); if(textbits) args[nargs++] = tb; if(gfxbits) args[nargs++] = gb; args[nargs] = nil; gspid = fork(); if(gspid == 0) { close(stdinp[1]); close(stdoutp[0]); close(dataout[0]); close(errout[0]); /* * Horrible problem: we want to dup fd's 0-4 below, * but some of the source fd's might have those small numbers. * So we need to reallocate those. In order to not step on * anything else, we'll dup the fd's to higher ones using * dup(x, -1), but we need to use up the lower ones first. */ while((devnull = open("/dev/null", ORDWR)) < 5) ; stdinp[0] = dup(stdinp[0], -1); stdoutp[1] = dup(stdoutp[1], -1); errout[1] = dup(errout[1], -1); dataout[1] = dup(dataout[1], -1); dup(stdinp[0], 0); dup(errout[1], 1); dup(devnull, 2); /* never anything useful */ dup(dataout[1], 3); dup(stdoutp[1], 4); for(i=5; i<20; i++) close(i); execvp("gs", args); wexits("exec"); } close(stdinp[0]); close(stdoutp[1]); close(errout[1]); close(dataout[1]); atexit(killgs); cp = chancreate(sizeof(int), 0); if(teegs) { proccreate(spawnreader, cp, mainstacksize); send(cp, &stdoutp[0]); recv(cp, &stdoutp[0]); } gsfd = g->gsfd = stdinp[1]; g->gspid = gspid; g->g.fd = dataout[0]; g->g.name = "gs pipe"; g->g.type = Ibmp; proccreate(spawnmonitor, cp, mainstacksize); send(cp, &errout[0]); chanfree(cp); Binit(&g->gsrd, stdoutp[0], OREAD); gscmd(g, "/PAGEOUT (/dev/fd/4) (w) file def\n"); if(!strcmp(safer, "-dSAFER")) gscmd(g, ".setsafe\n"); gscmd(g, "/PAGE== { PAGEOUT exch write==only PAGEOUT (\\n) writestring PAGEOUT flushfile } def\n"); waitgs(g); return 0; }
int startdev(Port *pp) { Dev *d; Usbdev *ud; Devtab *dt; Sarg *sa; Channel *rc; d = pp->dev; assert(d); ud = d->usb; assert(ud != nil); writeinfo(d); if(ud->class == Clhub){ /* * Hubs are handled directly by this process avoiding * concurrent operation so that at most one device * has the config address in use. * We cancel kernel debug for these eps. too chatty. */ pp->hub = newhub(d->dir, d); if(pp->hub == nil) fprint(2, "%s: %s: %r\n", argv0, d->dir); else fprint(2, "usb/hub... "); if(usbdebug > 1) devctl(d, "debug 0"); /* polled hubs are chatty */ return pp->hub == nil ? -1 : 0; } for(dt = devtab; dt->name != nil; dt++) if(devmatch(dt, ud)) break; /* * From here on the device is for the driver. * When we return pp->dev contains a Dev just for us * with only the ctl open. Both devs are released on the last closedev: * driver's upon I/O errors and ours upon port dettach. */ if(dt->name == nil){ dprint(2, "%s: no configured entry for %s (csp %#08lx)\n", argv0, d->dir, ud->csp); close(d->dfd); d->dfd = -1; return 0; } sa = emallocz(sizeof(Sarg), 1); sa->pp = pp; sa->dt = dt; rc = sa->rc = chancreate(sizeof(uint32_t), 1); procrfork(startdevproc, sa, Stack, RFNOTEG); if(recvul(rc) != 0) free(sa); chanfree(rc); fprint(2, "usb/%s... ", dt->name); sleep(Spawndelay); /* in case we re-spawn too fast */ return 0; }
static void openfdthread(void *v) { Conn *c; Fid *fid; Msg *m; int n; vlong tot; Ioproc *io; char buf[1024]; c = v; fid = c->fdfid; io = ioproc(); threadsetname("openfd %s", c->fdfid); tot = 0; m = nil; if(c->fdmode == OREAD){ for(;;){ if(verbose) fprint(2, "%T tread..."); m = msgnew(0); m->internal = 1; m->c = c; m->tx.type = Tread; m->tx.count = msize - IOHDRSZ; m->tx.fid = fid->fid; m->tx.tag = m->tag; m->tx.offset = tot; m->fid = fid; fid->ref++; msgincref(m); sendomsg(m); recvp(c->internal); if(m->rx.type == Rerror){ /* fprint(2, "%T read error: %s\n", m->rx.ename); */ break; } if(m->rx.count == 0) break; tot += m->rx.count; if(iowrite(io, c->fd, m->rx.data, m->rx.count) != m->rx.count){ /* fprint(2, "%T pipe write error: %r\n"); */ break; } msgput(m); msgput(m); m = nil; } }else{ for(;;){ if(verbose) fprint(2, "%T twrite..."); n = sizeof buf; if(n > msize) n = msize; if((n=ioread(io, c->fd, buf, n)) <= 0){ if(n < 0) fprint(2, "%T pipe read error: %r\n"); break; } m = msgnew(0); m->internal = 1; m->c = c; m->tx.type = Twrite; m->tx.fid = fid->fid; m->tx.data = buf; m->tx.count = n; m->tx.tag = m->tag; m->tx.offset = tot; m->fid = fid; fid->ref++; msgincref(m); sendomsg(m); recvp(c->internal); if(m->rx.type == Rerror){ /* fprint(2, "%T write error: %s\n", m->rx.ename); */ } tot += n; msgput(m); msgput(m); m = nil; } } if(verbose) fprint(2, "%T eof on %d fid %d\n", c->fd, fid->fid); close(c->fd); closeioproc(io); if(m){ msgput(m); msgput(m); } if(verbose) fprint(2, "%T eof on %d fid %d ref %d\n", c->fd, fid->fid, fid->ref); if(--fid->openfd == 0){ m = msgnew(0); m->internal = 1; m->c = c; m->tx.type = Tclunk; m->tx.tag = m->tag; m->tx.fid = fid->fid; m->fid = fid; fid->ref++; msgincref(m); sendomsg(m); recvp(c->internal); msgput(m); msgput(m); } fidput(fid); c->fdfid = nil; chanfree(c->internal); c->internal = 0; free(c); }
void connthread(void *arg) { int i, fd; Conn *c; Hash *h, *hnext; Msg *m, *om, *mm, sync; Fid *f; Ioproc *io; c = arg; threadsetname("conn %s", c->dir); io = ioproc(); fd = ioaccept(io, c->fd, c->dir); if(fd < 0){ if(verbose) fprint(2, "%T accept %s: %r\n", c->dir); goto out; } close(c->fd); c->fd = fd; threadcreate(connoutthread, c, STACK); while((m = mread9p(io, c->fd)) != nil){ if(verbose > 1) fprint(2, "%T fd#%d -> %F\n", c->fd, &m->tx); m->c = c; m->ctag = m->tx.tag; c->nmsg++; if(verbose > 1) fprint(2, "%T fd#%d: new msg %p\n", c->fd, m); if(puthash(c->tag, m->tx.tag, m) < 0){ err(m, "duplicate tag"); continue; } msgincref(m); switch(m->tx.type){ case Tversion: m->rx.tag = m->tx.tag; m->rx.msize = m->tx.msize; if(m->rx.msize > msize) m->rx.msize = msize; m->rx.version = "9P2000"; m->rx.type = Rversion; send9pmsg(m); continue; case Tflush: if((m->oldm = gethash(c->tag, m->tx.oldtag)) == nil){ m->rx.tag = m->tx.tag; m->rx.type = Rflush; send9pmsg(m); continue; } msgincref(m->oldm); break; case Tattach: m->afid = nil; if(m->tx.afid != NOFID && (m->afid = gethash(c->fid, m->tx.afid)) == nil){ err(m, "unknown fid"); continue; } if(m->afid) m->afid->ref++; m->fid = fidnew(m->tx.fid); if(puthash(c->fid, m->tx.fid, m->fid) < 0){ err(m, "duplicate fid"); continue; } m->fid->ref++; if(attached && m->afid==nil){ if(m->tx.aname[0] && strcmp(xaname, m->tx.aname) != 0){ err(m, "invalid attach name"); continue; } m->tx.afid = xafid; m->tx.aname = xaname; m->tx.uname = getuser(); /* what srv.c used */ repack(&m->tx, &m->tpkt); } break; case Twalk: if((m->fid = gethash(c->fid, m->tx.fid)) == nil){ err(m, "unknown fid"); continue; } m->fid->ref++; if(m->tx.newfid == m->tx.fid){ m->fid->ref++; m->newfid = m->fid; }else{ m->newfid = fidnew(m->tx.newfid); if(puthash(c->fid, m->tx.newfid, m->newfid) < 0){ err(m, "duplicate fid"); continue; } m->newfid->ref++; } break; case Tauth: if(attached){ err(m, "authentication not required"); continue; } if(noauth){ err(m, "authentication rejected"); continue; } m->afid = fidnew(m->tx.afid); if(puthash(c->fid, m->tx.afid, m->afid) < 0){ err(m, "duplicate fid"); continue; } m->afid->ref++; break; case Tcreate: if(m->tx.perm&(DMSYMLINK|DMDEVICE|DMNAMEDPIPE|DMSOCKET)){ err(m, "unsupported file type"); continue; } goto caseTopen; case Topenfd: if(m->tx.mode&~(OTRUNC|3)){ err(m, "bad openfd mode"); continue; } m->isopenfd = 1; m->tx.type = Topen; m->tpkt[4] = Topen; /* fall through */ caseTopen: case Topen: case Tclunk: case Tread: case Twrite: case Tremove: case Tstat: case Twstat: if((m->fid = gethash(c->fid, m->tx.fid)) == nil){ err(m, "unknown fid"); continue; } m->fid->ref++; break; } /* have everything - translate and send */ m->c = c; m->ctag = m->tx.tag; m->tx.tag = m->tag; if(m->fid) m->tx.fid = m->fid->fid; if(m->newfid) m->tx.newfid = m->newfid->fid; if(m->afid) m->tx.afid = m->afid->fid; if(m->oldm) m->tx.oldtag = m->oldm->tag; /* reference passes to outq */ sendq(outq, m); while(c->nmsg >= MAXMSG){ c->inputstalled = 1; recvp(c->inc); } } if(verbose) fprint(2, "%T fd#%d eof; flushing conn\n", c->fd); /* flush all outstanding messages */ for(i=0; i<NHASH; i++){ while((h = c->tag[i]) != nil){ om = h->v; msgincref(om); /* for us */ m = msgnew(0); m->internal = 1; m->c = c; c->nmsg++; m->tx.type = Tflush; m->tx.tag = m->tag; m->tx.oldtag = om->tag; m->oldm = om; msgincref(om); msgincref(m); /* for outq */ sendomsg(m); mm = recvp(c->internal); assert(mm == m); msgput(m); /* got from recvp */ msgput(m); /* got from msgnew */ if(delhash(c->tag, om->ctag, om) == 0) msgput(om); /* got from hash table */ msgput(om); /* got from msgincref */ } } /* * outputthread has written all its messages * to the remote connection (because we've gotten all the replies!), * but it might not have gotten a chance to msgput * the very last one. sync up to make sure. */ memset(&sync, 0, sizeof sync); sync.sync = 1; sync.c = c; sendq(outq, &sync); recvp(c->outqdead); /* everything is quiet; can close the local output queue. */ sendq(c->outq, nil); recvp(c->outqdead); /* should be no messages left anywhere. */ assert(c->nmsg == 0); /* clunk all outstanding fids */ for(i=0; i<NHASH; i++){ for(h=c->fid[i]; h; h=hnext){ f = h->v; m = msgnew(0); m->internal = 1; m->c = c; c->nmsg++; m->tx.type = Tclunk; m->tx.tag = m->tag; m->tx.fid = f->fid; m->fid = f; f->ref++; msgincref(m); sendomsg(m); mm = recvp(c->internal); assert(mm == m); msgclear(m); msgput(m); /* got from recvp */ msgput(m); /* got from msgnew */ fidput(f); /* got from hash table */ hnext = h->next; free(h); } } out: closeioproc(io); assert(c->nmsg == 0); assert(c->nfid == 0); close(c->fd); chanfree(c->internal); c->internal = 0; chanfree(c->inc); c->inc = 0; free(c->inq); c->inq = 0; free(c); }
void winctl(void *arg) { print_func_entry(); Rune *rp, *bp, *kbdr; int nr, nb, c, wid, i, npart, lastb; char *s, *t, part[3]; Window *w; Mousestate *mp, m; enum { WKey, WMouse, WMouseread, WCtl, WCwrite, WCread, WWread, NWALT }; Alt alts[NWALT+1]; int walt; Mousereadmesg mrm; Conswritemesg cwm; Consreadmesg crm; Consreadmesg cwrm; Stringpair pair; Wctlmesg wcm; char buf[4*12+1]; w = arg; snprint(buf, sizeof buf, "winctl-id%d", w->id); threadsetname(buf); mrm.cm = chancreate(sizeof(Mouse), 0); cwm.cw = chancreate(sizeof(Stringpair), 0); crm.c1 = chancreate(sizeof(Stringpair), 0); crm.c2 = chancreate(sizeof(Stringpair), 0); cwrm.c1 = chancreate(sizeof(Stringpair), 0); cwrm.c2 = chancreate(sizeof(Stringpair), 0); alts[WKey].c = w->ck; alts[WKey].v = &kbdr; alts[WKey].op = CHANRCV; alts[WMouse].c = w->mc.c; alts[WMouse].v = &w->mc.Mouse; alts[WMouse].op = CHANNOP; // XXXCHANRCV; alts[WMouseread].c = w->mouseread; alts[WMouseread].v = &mrm; alts[WMouseread].op = CHANNOP; // XXXCHANSND; alts[WCtl].c = w->cctl; alts[WCtl].v = &wcm; alts[WCtl].op = CHANRCV; alts[WCwrite].c = w->conswrite; alts[WCwrite].v = &cwm; alts[WCwrite].op = CHANSND; alts[WCread].c = w->consread; alts[WCread].v = &crm; alts[WCread].op = CHANSND; alts[WWread].c = w->wctlread; alts[WWread].v = &cwrm; alts[WWread].op = CHANSND; alts[NWALT].op = CHANEND; npart = 0; lastb = -1; for(;;){ // TODO: mouses if(0 && w->mouseopen && w->mouse.counter != w->mouse.lastcounter) alts[WMouseread].op = CHANSND; else alts[WMouseread].op = CHANNOP; if(w->deleted || !w->wctlready) alts[WWread].op = CHANNOP; else alts[WWread].op = CHANSND; /* this code depends on NL and EOT fitting in a single byte */ /* kind of expensive for each loop; worth precomputing? */ /*if(w->holding) alts[WCread].op = CHANNOP; else*/ if(npart || (w->rawing && w->nraw>0)) alts[WCread].op = CHANSND; else { alts[WCread].op = CHANNOP; for(i=w->qh; i<w->nr; i++){ c = w->run[i]; if(c=='\n' || c=='\004'){ alts[WCread].op = CHANSND; break; } } } walt = alt(alts); switch(walt){ case WKey: for(i=0; kbdr[i]!=L'\0'; i++) wkeyctl(w, kbdr[i]); //wkeyctl(w, r); /// while(nbrecv(w->ck, &r)) //wkeyctl(w, r); break; case WMouse: if(w->mouseopen) { w->mouse.counter++; /* queue click events */ if(!w->mouse.qfull && lastb != w->mc.buttons) { /* add to ring */ mp = &w->mouse.queue[w->mouse.wi]; if(++w->mouse.wi == nelem(w->mouse.queue)) w->mouse.wi = 0; if(w->mouse.wi == w->mouse.ri) w->mouse.qfull = TRUE; mp->Mouse = w->mc.Mouse; mp->counter = w->mouse.counter; lastb = w->mc.buttons; } } else fprint(2, "MOUSECTL\n"); //wmousectl(w); break; case WMouseread: /* send a queued event or, if the queue is empty, the current state */ /* if the queue has filled, we discard all the events it contained. */ /* the intent is to discard frantic clicking by the user during long latencies. */ w->mouse.qfull = FALSE; if(w->mouse.wi != w->mouse.ri) { m = w->mouse.queue[w->mouse.ri]; if(++w->mouse.ri == nelem(w->mouse.queue)) w->mouse.ri = 0; } else m = (Mousestate){w->mc.Mouse, w->mouse.counter}; w->mouse.lastcounter = m.counter; send(mrm.cm, &m.Mouse); continue; case WCtl: exits("WCtl can't do"); #if 0 if(wctlmesg(w, wcm.type, wcm.r, wcm.image) == Exited){ chanfree(crm.c1); chanfree(crm.c2); chanfree(mrm.cm); chanfree(cwm.cw); chanfree(cwrm.c1); chanfree(cwrm.c2); threadexits(nil); } #endif continue; case WCwrite: recv(cwm.cw, &pair); rp = pair.s; nr = pair.ns; bp = rp; for(i=0; i<nr; i++) { // See rio for the run conversion crap. For now, I'm not going to // worry about it. This is designed to target Akaros too. fprint(/*w->Console->out*/1, "%c", *bp++); } free(rp); break; case WCread: recv(crm.c1, &pair); t = pair.s; nb = pair.ns; i = npart; npart = 0; if(i) memmove(t, part, i); while(i<nb && (w->qh<w->nr || w->nraw>0)){ if(w->qh == w->nr){ wid = runetochar(t+i, &w->raw[0]); w->nraw--; runemove(w->raw, w->raw+1, w->nraw); }else wid = runetochar(t+i, &w->run[w->qh++]); c = t[i]; /* knows break characters fit in a byte */ i += wid; if(!w->rawing && (c == '\n' || c=='\004')){ if(c == '\004') i--; break; } } if(i==nb && w->qh<w->nr && w->run[w->qh]=='\004') w->qh++; if(i > nb){ npart = i-nb; memmove(part, t+nb, npart); i = nb; } pair.s = t; pair.ns = i; send(crm.c2, &pair); continue; case WWread: w->wctlready = 0; recv(cwrm.c1, &pair); if(w->deleted) pair.ns = sprint(pair.s, ""); else{ s = "visible"; for(i=0; i<nhidden; i++) if(hidden[i] == w){ s = "hidden"; break; } t = "notcurrent"; if(w == input) t = "current"; pair.ns = snprint(pair.s, pair.ns, "%s %s ",t, s); } send(cwrm.c2, &pair); continue; } } print_func_exit(); }
void threadmain(int argc, char **argv) { int fd, i, nd; char *err, *mnt, *srv; Dir *d; srv = "usb"; mnt = "/dev"; ARGBEGIN{ case 'D': usbfsdebug++; break; case 'd': usbdebug++; break; case 's': srv = EARGF(usage()); break; case 'i': pollms = atoi(EARGF(usage())); break; case 'm': mnt = EARGF(usage()); break; default: usage(); }ARGEND; if(access("/dev/usb", AEXIST) < 0 && bind("#u", "/dev", MBEFORE) < 0) sysfatal("#u: %r"); args(); fmtinstall('U', Ufmt); quotefmtinstall(); rfork(RFNOTEG); portc = chancreate(sizeof(char *), 0); if(portc == nil) sysfatal("chancreate"); proccreate(work, portc, Stack); if(argc == 0){ fd = open("/dev/usb", OREAD); if(fd < 0) sysfatal("/dev/usb: %r"); nd = dirreadall(fd, &d); close(fd); if(nd < 2) sysfatal("/dev/usb: no hubs"); for(i = 0; i < nd; i++) if(strcmp(d[i].name, "ctl") != 0) sendp(portc, smprint("/dev/usb/%s", d[i].name)); free(d); }else for(i = 0; i < argc; i++) sendp(portc, strdup(argv[i])); sendp(portc, nil); err = recvp(portc); chanfree(portc); usbfsexits(0); usbfsinit(srv, mnt, &usbdirfs, MAFTER); snprint(ctlfs.name, sizeof(ctlfs.name), "usbdctl"); usbfsadd(&ctlfs); threadexits(err); }
static Chan* loopbackattach(char *spec) { Loop *volatile lb; Queue *q; Chan *c; int chan; int dev; dev = 0; if(spec != nil){ dev = atoi(spec); if(dev >= Nloopbacks) error(Ebadspec); } c = devattach('X', spec); if(waserror()){ chanfree(c); nexterror(); } lb = &loopbacks[dev]; qlock(lb); if(waserror()){ lb->ref--; qunlock(lb); nexterror(); } lb->ref++; if(lb->ref == 1){ for(chan = 0; chan < 2; chan++){ lb->link[chan].ci.mode = Trelative; lb->link[chan].ci.a = &lb->link[chan]; lb->link[chan].ci.f = linkintr; lb->link[chan].limit = Loopqlim; q = qopen(lb->link[chan].limit, 0, 0, 0); lb->link[chan].iq = q; if(q == nil){ freelb(lb); exhausted("memory"); } q = qopen(lb->link[chan].limit, 0, 0, 0); lb->link[chan].oq = q; if(q == nil){ freelb(lb); exhausted("memory"); } lb->link[chan].indrop = 1; lb->link[chan].delaynns = Delayn; lb->link[chan].delay0ns = Delay0; } } poperror(); qunlock(lb); poperror(); mkqid(&c->qid, QID(0, Qtopdir), 0, QTDIR); c->aux = lb; c->dev = dev; return c; }
int mesgcommand(Message *m, char *cmd) { char *s; char *args[10]; int ok, ret, nargs; s = cmd; ret = 1; nargs = tokenize(s, args, nelem(args)); if(nargs == 0) return 0; if(strcmp(args[0], "Post") == 0){ mesgsend(m); goto Return; } if(strncmp(args[0], "Save", 4) == 0){ if(m->isreply) goto Return; s = estrdup("\t[saved"); if(nargs==1 || strcmp(args[1], "")==0){ ok = mesgsave(m, "stored"); }else{ ok = mesgsave(m, args[1]); s = eappend(s, " ", args[1]); } if(ok){ s = egrow(s, "]", nil); mesgmenumark(mbox.w, m->name, s); } free(s); goto Return; } if(strcmp(args[0], "Reply")==0){ if(nargs>=2 && strcmp(args[1], "all")==0) mkreply(m, "Replyall", nil, nil, nil); else mkreply(m, "Reply", nil, nil, nil); goto Return; } if(strcmp(args[0], "Q") == 0){ s = winselection(m->w); /* will be freed by mkreply */ if(nargs>=3 && strcmp(args[1], "Reply")==0 && strcmp(args[2], "all")==0) mkreply(m, "QReplyall", nil, nil, s); else mkreply(m, "QReply", nil, nil, s); goto Return; } if(strcmp(args[0], "Del") == 0){ if(windel(m->w, 0)){ chanfree(m->w->cevent); free(m->w); m->w = nil; if(m->isreply) delreply(m); else{ m->opened = 0; m->tagposted = 0; } free(cmd); threadexits(nil); } goto Return; } if(strcmp(args[0], "Delmesg") == 0){ if(!m->isreply){ mesgmenumarkdel(wbox, &mbox, m, 1); free(cmd); /* mesgcommand might not return */ mesgcommand(m, estrdup("Del")); return 1; } goto Return; } if(strcmp(args[0], "UnDelmesg") == 0){ if(!m->isreply && m->deleted) mesgmenumarkundel(wbox, &mbox, m); goto Return; } // if(strcmp(args[0], "Headers") == 0){ // m->showheaders(); // return True; // } ret = 0; Return: free(cmd); return ret; }
int synckids(Syncpath *s) { int i, ret, n; Channel *c; Kids *ak, *bk; c = chan(Kids*); ak = emalloc(sizeof(*ak)); ak->repl = s->sync->ra; ak->p = s->p; ak->c = c; spawn(kidthread, ak); bk = emalloc(sizeof(*bk)); bk->repl = s->sync->rb; bk->p = s->p; bk->c = c; spawn(kidthread, bk); threadstate("synckids wait %p", c); recvp(c); threadstate("synckids wait %p", c); recvp(c); chanfree(c); ret = -1; if(ak->err){ s->err = ak->err; ak->err = 0; s->state = SyncError; goto End; } if(bk->err){ s->err = bk->err; bk->err = 0; s->state = SyncError; goto End; } ret = 0; if(ak->nk) qsort(ak->k, ak->nk, sizeof(ak->k[0]), kidnamecmp); if(bk->nk) qsort(bk->k, bk->nk, sizeof(bk->k[0]), kidnamecmp); n = mergekids(s, ak->k, ak->nk, bk->k, bk->nk, 0); if(n == 0){ s->state = SyncDone; syncfinish(s); goto End; } mergekids(s, ak->k, ak->nk, bk->k, bk->nk, n); s->npend = s->nkid; s->finishstate = SyncDone; for(i=0; i<n; i++){ if(s->kid[i].a.s == nil) s->kid[i].a.s = mkemptystate(s->a.s->synctime); if(s->kid[i].b.s == nil) s->kid[i].b.s = mkemptystate(s->b.s->synctime); qsend(s->sync->syncq, &s->kid[i]); } End: if(ak->err) free(ak->err); if(bk->err) free(bk->err); freekids(ak->k, ak->nk); freekids(bk->k, bk->nk); free(ak); free(bk); return ret; }