Ejemplo n.º 1
0
/*
 *  find the local address 'closest' to the remote system, copy it to
 *  local and return the ifc for that address
 */
void
findlocalip(Fs *f, uint8_t *local, uint8_t *remote)
{
	int version, atype = unspecifiedv6, atypel = unknownv6;
	int atyper, deprecated;
	uint8_t gate[IPaddrlen], gnet[IPaddrlen];
	Ipifc *ifc;
	Iplifc *lifc;
	Route *r;

	USED(atype);
	USED(atypel);
	qlock(f->ipifc);
	r = v6lookup(f, remote, nil);
 	version = (memcmp(remote, v4prefix, IPv4off) == 0)? V4: V6;

	if(r != nil){
		ifc = r->ifc;
		if(r->type & Rv4)
			v4tov6(gate, r->v4.gate);
		else {
			ipmove(gate, r->v6.gate);
			ipmove(local, v6Unspecified);
		}

		switch(version) {
		case V4:
			/* find ifc address closest to the gateway to use */
			for(lifc = ifc->lifc; lifc; lifc = lifc->next){
				maskip(gate, lifc->mask, gnet);
				if(ipcmp(gnet, lifc->net) == 0){
					ipmove(local, lifc->local);
					goto out;
				}
			}
			break;
		case V6:
			/* find ifc address with scope matching the destination */
			atyper = v6addrtype(remote);
			deprecated = 0;
			for(lifc = ifc->lifc; lifc; lifc = lifc->next){
				atypel = v6addrtype(lifc->local);
				/* prefer appropriate scope */
				if(atypel > atype && atype < atyper ||
				   atypel < atype && atype > atyper){
					ipmove(local, lifc->local);
					deprecated = !v6addrcurr(lifc);
					atype = atypel;
				} else if(atypel == atype){
					/* avoid deprecated addresses */
					if(deprecated && v6addrcurr(lifc)){
						ipmove(local, lifc->local);
						atype = atypel;
						deprecated = 0;
					}
				}
				if(atype == atyper && !deprecated)
					goto out;
			}
			if(atype >= atyper)
				goto out;
			break;
		default:
			panic("findlocalip: version %d", version);
		}
	}

	switch(version){
	case V4:
		findprimaryipv4(f, local);
		break;
	case V6:
		findprimaryipv6(f, local);
		break;
	default:
		panic("findlocalip2: version %d", version);
	}

out:
	qunlock(f->ipifc);
}
Ejemplo n.º 2
0
long
sysrfork(ulong *arg)
{
	Proc *p;
	int n, i;
	Fgrp *ofg;
	Pgrp *opg;
	Rgrp *org;
	Egrp *oeg;
	ulong pid, flag;
	Mach *wm;

	flag = arg[0];
	/* Check flags before we commit */
	if((flag & (RFFDG|RFCFDG)) == (RFFDG|RFCFDG))
		error(Ebadarg);
	if((flag & (RFNAMEG|RFCNAMEG)) == (RFNAMEG|RFCNAMEG))
		error(Ebadarg);
	if((flag & (RFENVG|RFCENVG)) == (RFENVG|RFCENVG))
		error(Ebadarg);

	if((flag&RFPROC) == 0) {
		if(flag & (RFMEM|RFNOWAIT))
			error(Ebadarg);
		if(flag & (RFFDG|RFCFDG)) {
			ofg = up->fgrp;
			if(flag & RFFDG)
				up->fgrp = dupfgrp(ofg);
			else
				up->fgrp = dupfgrp(nil);
			closefgrp(ofg);
		}
		if(flag & (RFNAMEG|RFCNAMEG)) {
			opg = up->pgrp;
			up->pgrp = newpgrp();
			if(flag & RFNAMEG)
				pgrpcpy(up->pgrp, opg);
			/* inherit noattach */
			up->pgrp->noattach = opg->noattach;
			closepgrp(opg);
		}
		if(flag & RFNOMNT)
			up->pgrp->noattach = 1;
		if(flag & RFREND) {
			org = up->rgrp;
			up->rgrp = newrgrp();
			closergrp(org);
		}
		if(flag & (RFENVG|RFCENVG)) {
			oeg = up->egrp;
			up->egrp = smalloc(sizeof(Egrp));
			up->egrp->ref = 1;
			if(flag & RFENVG)
				envcpy(up->egrp, oeg);
			closeegrp(oeg);
		}
		if(flag & RFNOTEG)
			up->noteid = incref(&noteidalloc);
		return 0;
	}

	p = newproc();

	p->fpsave = up->fpsave;
	p->scallnr = up->scallnr;
	p->s = up->s;
	p->nerrlab = 0;
	p->slash = up->slash;
	p->dot = up->dot;
	incref(p->dot);

	memmove(p->note, up->note, sizeof(p->note));
	p->privatemem = up->privatemem;
	p->noswap = up->noswap;
	p->nnote = up->nnote;
	p->notified = 0;
	p->lastnote = up->lastnote;
	p->notify = up->notify;
	p->ureg = up->ureg;
	p->dbgreg = 0;

	/* Make a new set of memory segments */
	n = flag & RFMEM;
	qlock(&p->seglock);
	if(waserror()){
		qunlock(&p->seglock);
		nexterror();
	}
	for(i = 0; i < NSEG; i++)
		if(up->seg[i])
			p->seg[i] = dupseg(up->seg, i, n);
	qunlock(&p->seglock);
	poperror();

	/* File descriptors */
	if(flag & (RFFDG|RFCFDG)) {
		if(flag & RFFDG)
			p->fgrp = dupfgrp(up->fgrp);
		else
			p->fgrp = dupfgrp(nil);
	}
	else {
		p->fgrp = up->fgrp;
		incref(p->fgrp);
	}

	/* Process groups */
	if(flag & (RFNAMEG|RFCNAMEG)) {
		p->pgrp = newpgrp();
		if(flag & RFNAMEG)
			pgrpcpy(p->pgrp, up->pgrp);
		/* inherit noattach */
		p->pgrp->noattach = up->pgrp->noattach;
	}
	else {
		p->pgrp = up->pgrp;
		incref(p->pgrp);
	}
	if(flag & RFNOMNT)
		up->pgrp->noattach = 1;

	if(flag & RFREND)
		p->rgrp = newrgrp();
	else {
		incref(up->rgrp);
		p->rgrp = up->rgrp;
	}

	/* Environment group */
	if(flag & (RFENVG|RFCENVG)) {
		p->egrp = smalloc(sizeof(Egrp));
		p->egrp->ref = 1;
		if(flag & RFENVG)
			envcpy(p->egrp, up->egrp);
	}
	else {
		p->egrp = up->egrp;
		incref(p->egrp);
	}
	p->hang = up->hang;
	p->procmode = up->procmode;

	/* Craft a return frame which will cause the child to pop out of
	 * the scheduler in user mode with the return register zero
	 */
	forkchild(p, up->dbgreg);

	p->parent = up;
	p->parentpid = up->pid;
	if(flag&RFNOWAIT)
		p->parentpid = 0;
	else {
		lock(&up->exl);
		up->nchild++;
		unlock(&up->exl);
	}
	if((flag&RFNOTEG) == 0)
		p->noteid = up->noteid;

	/* don't penalize the child, it hasn't done FP in a note handler. */
	p->fpstate = up->fpstate & ~FPillegal;
	pid = p->pid;
	memset(p->time, 0, sizeof(p->time));
	p->time[TReal] = MACHP(0)->ticks;

	kstrdup(&p->text, up->text);
	kstrdup(&p->user, up->user);
	/*
	 *  since the bss/data segments are now shareable,
	 *  any mmu info about this process is now stale
	 *  (i.e. has bad properties) and has to be discarded.
	 */
	flushmmu();
	p->basepri = up->basepri;
	p->priority = up->basepri;
	p->fixedpri = up->fixedpri;
	p->mp = up->mp;
	wm = up->wired;
	if(wm)
		procwired(p, wm->machno);
	ready(p);
	sched();
	return pid;
}
Ejemplo n.º 3
0
Archivo: rpc.c Proyecto: 99years/plan9
Packet*
_vtrpc(VtConn *z, Packet *p, VtFcall *tx)
{
	int i;
	uchar tag, buf[2], *top;
	Rwait *r, *rr;

	if(z == nil){
		werrstr("not connected");
		packetfree(p);
		return nil;
	}

	/* must malloc because stack could be private */
	r = vtmallocz(sizeof(Rwait));

	qlock(&z->lk);
	r->r.l = &z->lk;
	tag = gettag(z, r);
	if(tx){
		/* vtfcallrpc can't print packet because it doesn't have tag */
		tx->tag = tag;
		if(chattyventi)
			fprint(2, "%s -> %F\n", argv0, tx);
	}

	/* slam tag into packet */
	top = packetpeek(p, buf, 0, 2);
	if(top == nil){
		packetfree(p);
		return nil;
	}
	if(top == buf){
		werrstr("first two bytes must be in same packet fragment");
		packetfree(p);
		vtfree(r);
		return nil;
	}
	top[1] = tag;
	qunlock(&z->lk);
	if(vtsend(z, p) < 0){
		vtfree(r);
		return nil;
	}

	qlock(&z->lk);
	/* wait for the muxer to give us our packet */
	r->sleeping = 1;
	z->nsleep++;
	while(z->muxer && !r->done)
		rsleep(&r->r);
	z->nsleep--;
	r->sleeping = 0;

	/* if not done, there's no muxer: start muxing */
	if(!r->done){
		if(z->muxer)
			abort();
		z->muxer = 1;
		while(!r->done){
			qunlock(&z->lk);
			if((p = vtrecv(z)) == nil){
				werrstr("unexpected eof on venti connection");
				z->muxer = 0;
				vtfree(r);
				return nil;
			}
			qlock(&z->lk);
			muxrpc(z, p);
		}
		z->muxer = 0;
		/* if there is anyone else sleeping, wake first unfinished to mux */
		if(z->nsleep)
		for(i=0; i<256; i++){
			rr = z->wait[i];
			if(rr && rr->sleeping && !rr->done){
				rwakeup(&rr->r);
				break;
			}
		}
	}

	p = r->p;
	puttag(z, r, tag);
	vtfree(r);
	qunlock(&z->lk);
	return p;
}
Ejemplo n.º 4
0
static
Xfid*
fsysread(Xfid *x, Fid *f)
{
	Fcall t;
	uchar *b;
	int i, id, n, o, e, j, k, *ids, nids;
	Dirtab *d, dt;
	Column *c;
	uint clock, len;
	char buf[16];

	if(f->qid.type & QTDIR){
		if(FILE(f->qid) == Qacme){	/* empty dir */
			t.data = nil;
			t.count = 0;
			respond(x, &t, nil);
			return x;
		}
		o = x->offset;
		e = x->offset+x->count;
		clock = getclock();
		b = emalloc(messagesize);
		id = WIN(f->qid);
		n = 0;
		if(id > 0)
			d = dirtabw;
		else
			d = dirtab;
		d++;	/* first entry is '.' */
		for(i=0; d->name!=nil && i<e; i+=len){
			len = dostat(WIN(x->f->qid), d, b+n, x->count-n, clock);
			if(len <= BIT16SZ)
				break;
			if(i >= o)
				n += len;
			d++;
		}
		if(id == 0){
			qlock(&row);
			nids = 0;
			ids = nil;
			for(j=0; j<row.ncol; j++){
				c = row.col[j];
				for(k=0; k<c->nw; k++){
					ids = erealloc(ids, (nids+1)*sizeof(int));
					ids[nids++] = c->w[k]->id;
				}
			}
			qunlock(&row);
			qsort(ids, nids, sizeof ids[0], idcmp);
			j = 0;
			dt.name = buf;
			for(; j<nids && i<e; i+=len){
				k = ids[j];
				sprint(dt.name, "%d", k);
				dt.qid = QID(k, Qdir);
				dt.type = QTDIR;
				dt.perm = DMDIR|0700;
				len = dostat(k, &dt, b+n, x->count-n, clock);
				if(len == 0)
					break;
				if(i >= o)
					n += len;
				j++;
			}
			free(ids);
		}
		t.data = (char*)b;
		t.count = n;
		respond(x, &t, nil);
		free(b);
		return x;
	}
	sendp(x->c, xfidread);
	return nil;
}
Ejemplo n.º 5
0
long
consread(Chan *c, void *va, long count, vlong offset)
{
	int i, n, ch, eol;
	Pointer m;
	char *p, buf[64];

	if(c->qid.type & QTDIR)
		return devdirread(c, va, count, contab, nelem(contab), devgen);

	switch((ulong)c->qid.path) {
	default:
		error(Egreg);
	case Qsysctl:
		return readstr(offset, va, count, VERSION);
	case Qsysname:
		if(ossysname == nil)
			return 0;
		return readstr(offset, va, count, ossysname);
	case Qrandom:
		return randomread(va, count);
	case Qnotquiterandom:
		pseudoRandomBytes(va, count);
		return count;
	case Qpin:
		p = "pin set";
		if(up->env->pgrp->pin == Nopin)
			p = "no pin";
		return readstr(offset, va, count, p);
	case Qhostowner:
		return readstr(offset, va, count, eve);
	case Qhoststdin:
		return read(0, va, count);	/* should be pread */
	case Quser:
		return readstr(offset, va, count, up->env->user);
	case Qjit:
		snprint(buf, sizeof(buf), "%d", cflag);
		return readstr(offset, va, count, buf);
	case Qtime:
		snprint(buf, sizeof(buf), "%.lld", timeoffset + osusectime());
		return readstr(offset, va, count, buf);
	case Qdrivers:
		p = malloc(READSTR);
		if(p == nil)
			error(Enomem);
		n = 0;
		for(i = 0; devtab[i] != nil; i++)
			n += snprint(p+n, READSTR-n, "#%C %s\n", devtab[i]->dc,  devtab[i]->name);
		n = readstr(offset, va, count, p);
		free(p);
		return n;
	case Qmemory:
		return poolread(va, count, offset);

	case Qnull:
		return 0;
	case Qmsec:
		return readnum(offset, va, count, osmillisec(), NUMSIZE);
	case Qcons:
		qlock(&kbd.q);
		if(waserror()){
			qunlock(&kbd.q);
			nexterror();
		}

		if(dflag)
			error(Enonexist);

		while(!qcanread(lineq)) {
			qread(kbdq, &kbd.line[kbd.x], 1);
			ch = kbd.line[kbd.x];
			if(kbd.raw){
				qiwrite(lineq, &kbd.line[kbd.x], 1);
				continue;
			}
			eol = 0;
			switch(ch) {
			case '\b':
				if(kbd.x)
					kbd.x--;
				break;
			case 0x15:
				kbd.x = 0;
				break;
			case '\n':
			case 0x04:
				eol = 1;
			default:
				kbd.line[kbd.x++] = ch;
				break;
			}
			if(kbd.x == sizeof(kbd.line) || eol){
				if(ch == 0x04)
					kbd.x--;
				qwrite(lineq, kbd.line, kbd.x);
				kbd.x = 0;
			}
		}
		n = qread(lineq, va, count);
		qunlock(&kbd.q);
		poperror();
		return n;
	case Qscancode:
		if(offset == 0)
			return readstr(0, va, count, gkscanid);
		else
			return qread(gkscanq, va, count);
	case Qkeyboard:
		return qread(gkbdq, va, count);
	case Qpointer:
		m = mouseconsume();
		n = sprint(buf, "m%11d %11d %11d %11lud ", m.x, m.y, m.b, m.msec);
		if (count < n)
			n = count;
		memmove(va, buf, n);
		return n;
	case Qkprint:
		rlock(&kprintq.l);
		if(waserror()){
			runlock(&kprintq.l);
			nexterror();
		}
		n = qread(kprintq.q, va, count);
		poperror();
		runlock(&kprintq.l);
		return n;
	case Qsnarf: 
		if(offset == 0) {
			free(c->aux);
			c->aux = clipread();
		}
		if(c->aux == nil)
			return 0;
		return readstr(offset, va, count, c->aux);
	}
}
Ejemplo n.º 6
0
static void
tcpreader(void *a)
{
	Session *s = a;
	uchar *buf;
	int buflen = 0x1ffff + 4;
	buf = nbemalloc(buflen);
	for (;;) {
		int n;
		uchar flags;
		ushort length;

		n = readn(s->fd, buf, 4);
		if (n != 4) {
		die:
			free(buf);
			if (s->state == Connected)
				(*s->write)(s, nil, -1);
			deletesession(s);
			return;
		}
		flags = buf[1];
		length = nhgets(buf + 2) | ((flags & 1) << 16);
		n = readn(s->fd, buf + 4, length);
		if (n != length)
			goto die;
		if (flags & 0xfe) {
			print("nbss: invalid flags field 0x%.2ux\n", flags);
			goto die;
		}
		switch (buf[0]) {
		case 0: /* session message */
			if (s->state != Connected && s->state != Dead) {
				print("nbss: unexpected session message\n");
				goto die;
			}
			if (s->state == Connected) {
				if ((*s->write)(s, buf + 4, length) != 0) {
					s->state = Dead;
					goto die;
				}
			}
			break;
		case 0x81: /* session request */ {
			uchar *p, *ep;
			Listen *l;
			int k;
			int called_found;
			uchar error_code;

			if (s->state == Connected) {
				print("nbss: unexpected session request\n");
				goto die;
			}
			p = buf + 4;
			ep = p + length;
			k = nbnamedecode(p, p, ep, s->to);
			if (k == 0) {
				print("nbss: malformed called name in session request\n");
				goto die;
			}
			p += k;
			k = nbnamedecode(p, p, ep, s->from);
			if (k == 0) {
				print("nbss: malformed calling name in session request\n");
				goto die;
			}
/*
			p += k;
			if (p != ep) {
				print("nbss: extra data at end of session request\n");
				goto die;
			}
*/
			called_found = 0;
//print("nbss: called %B calling %B\n", s->to, s->from);
			qlock(&listens);
			for (l = listens.head; l; l = l->next)
				if (nbnameequal(l->to, s->to)) {
					called_found = 1;
					if (nbnameequal(l->from, s->from))
						break;
				}
			if (l == nil) {
				qunlock(&listens);
				error_code  = called_found ? 0x81 : 0x80;
			replydie:
				buf[0] = 0x83;
				buf[1] = 0;
				hnputs(buf + 2, 1);
				buf[4] = error_code;
				write(s->fd, buf, 5);
				goto die;
			}
			if (!(*l->accept)(l->magic, s, &s->write)) {
				qunlock(&listens);
				error_code = 0x83;
				goto replydie;
			}
			buf[0] = 0x82;
			buf[1] = 0;
			hnputs(buf + 2, 0);
			if (write(s->fd, buf, 4) != 4) {
				qunlock(&listens);
				goto die;
			}
			s->state = Connected;
			qunlock(&listens);
			break;
		}
		case 0x85: /* keep awake */
			break;
		default:
			print("nbss: opcode 0x%.2ux unexpected\n", buf[0]);
			goto die;
		}
	}
}
Ejemplo n.º 7
0
void
waitthread(void *v)
{
    Waitmsg *w;
    Command *c, *lc;
    uint pid;
    int found, ncmd;
    Rune *cmd;
    char *err;
    Text *t;
    Pid *pids, *p, *lastp;
    enum { WErr, WKill, WWait, WCmd, NWALT };
    Alt alts[NWALT+1];

    USED(v);
    threadsetname("waitthread");
    pids = nil;
    alts[WErr].c = cerr;
    alts[WErr].v = &err;
    alts[WErr].op = CHANRCV;
    alts[WKill].c = ckill;
    alts[WKill].v = &cmd;
    alts[WKill].op = CHANRCV;
    alts[WWait].c = cwait;
    alts[WWait].v = &w;
    alts[WWait].op = CHANRCV;
    alts[WCmd].c = ccommand;
    alts[WCmd].v = &c;
    alts[WCmd].op = CHANRCV;
    alts[NWALT].op = CHANEND;

    command = nil;
    for(;;) {
        switch(alt(alts)) {
        case WErr:
            qlock(&row.lk);
            warning(nil, "%s", err);
            free(err);
            flushimage(display, 1);
            qunlock(&row.lk);
            break;
        case WKill:
            found = FALSE;
            ncmd = runestrlen(cmd);
            for(c=command; c; c=c->next) {
                /* -1 for blank */
                if(runeeq(c->name, c->nname-1, cmd, ncmd) == TRUE) {
                    if(postnote(PNGROUP, c->pid, "kill") < 0)
                        warning(nil, "kill %S: %r\n", cmd);
                    found = TRUE;
                }
            }
            if(!found)
                warning(nil, "Kill: no process %S\n", cmd);
            free(cmd);
            break;
        case WWait:
            pid = w->pid;
            lc = nil;
            for(c=command; c; c=c->next) {
                if(c->pid == pid) {
                    if(lc)
                        lc->next = c->next;
                    else
                        command = c->next;
                    break;
                }
                lc = c;
            }
            qlock(&row.lk);
            t = &row.tag;
            textcommit(t, TRUE);
            if(c == nil) {
                /* helper processes use this exit status */
                if(strncmp(w->msg, "libthread", 9) != 0) {
                    p = emalloc(sizeof(Pid));
                    p->pid = pid;
                    strncpy(p->msg, w->msg, sizeof(p->msg));
                    p->next = pids;
                    pids = p;
                }
            } else {
                if(search(t, c->name, c->nname)) {
                    textdelete(t, t->q0, t->q1, TRUE);
                    textsetselect(t, 0, 0);
                }
                if(w->msg[0])
                    warning(c->md, "%.*S: exit %s\n", c->nname-1, c->name, w->msg);
                flushimage(display, 1);
            }
            qunlock(&row.lk);
            free(w);
Freecmd:
            if(c) {
                if(c->iseditcmd)
                    sendul(cedit, 0);
                free(c->text);
                free(c->name);
                fsysdelid(c->md);
                free(c);
            }
            break;
        case WCmd:
            /* has this command already exited? */
            lastp = nil;
            for(p=pids; p!=nil; p=p->next) {
                if(p->pid == c->pid) {
                    if(p->msg[0])
                        warning(c->md, "%s\n", p->msg);
                    if(lastp == nil)
                        pids = p->next;
                    else
                        lastp->next = p->next;
                    free(p);
                    goto Freecmd;
                }
                lastp = p;
            }
            c->next = command;
            command = c;
            qlock(&row.lk);
            t = &row.tag;
            textcommit(t, TRUE);
            textinsert(t, 0, c->name, c->nname, TRUE);
            textsetselect(t, 0, 0);
            flushimage(display, 1);
            qunlock(&row.lk);
            break;
        }
    }
}
Ejemplo n.º 8
0
static int
xgraph(HConnect *c)
{
	char *name;
	Hio *hout;
	Memimage *m;
	int dotext;
	Graph g;
	Arg arg;
	char *graph, *a;

	name = hargstr(c, "arg", "");
	if((arg.index = findname(name)) == -1 && strcmp(name, "*") != 0){
		werrstr("unknown name %s", name);
		goto error;
	}
	a = hargstr(c, "arg2", "");
	if(a[0] && (arg.index2 = findname(a)) == -1){
		werrstr("unknown name %s", a);
		goto error;
	}

	g.arg = &arg;
	g.t0 = hargint(c, "t0", -120);
	g.t1 = hargint(c, "t1", 0);
	g.min = hargint(c, "min", -1);
	g.max = hargint(c, "max", -1);
	g.wid = hargint(c, "wid", -1);
	g.ht = hargint(c, "ht", -1);
	dotext = hargstr(c, "text", "")[0] != 0;
	g.fill = hargint(c, "fill", -1);
	
	graph = hargstr(c, "graph", "raw");
	if(strcmp(graph, "raw") == 0)
		g.fn = rawgraph;
	else if(strcmp(graph, "diskbw") == 0)
		g.fn = diskgraph;
	else if(strcmp(graph, "iobw") == 0)
		g.fn = iograph;
	else if(strcmp(graph, "netbw") == 0)
		g.fn = netgraph;
	else if(strcmp(graph, "diff") == 0)
		g.fn = diffgraph;
	else if(strcmp(graph, "pct") == 0)
		g.fn = pctgraph;
	else if(strcmp(graph, "pctdiff") == 0)
		g.fn = pctdiffgraph;
	else if(strcmp(graph, "divdiff") == 0)
		g.fn = divdiffgraph;
	else{
		werrstr("unknown graph %s", graph);
		goto error;
	}

	if(dotext){
		hsettype(c, "text/plain");
		dotextbin(&c->hout, &g);
		hflush(&c->hout);
		return 0;
	}

	m = statgraph(&g);
	if(m == nil)
		goto error;

	if(hsettype(c, "image/png") < 0)
		return -1;
	hout = &c->hout;
	writepng(hout, m);
	qlock(&memdrawlock);
	freememimage(m);
	qunlock(&memdrawlock);
	hflush(hout);
	return 0;

error:
	return herror(c);
}
Ejemplo n.º 9
0
static int
chanio(Ep *ep, Hostchan *hc, int dir, int pid, void *a, int len)
{
	Ctlr *ctlr;
	int nleft, n, nt, i, maxpkt, npkt;
	uint hcdma, hctsiz;

	ctlr = ep->hp->aux;
	maxpkt = ep->maxpkt;
	npkt = HOWMANY(len, ep->maxpkt);
	if(npkt == 0)
		npkt = 1;

	hc->hcchar = (hc->hcchar & ~Epdir) | dir;
	if(dir == Epin)
		n = ROUND(len, ep->maxpkt);
	else
		n = len;
	hc->hctsiz = n | npkt<<OPktcnt | pid;
	hc->hcdma  = dmaaddr(a);

	nleft = len;
	logstart(ep);
	for(;;){
		hcdma = hc->hcdma;
		hctsiz = hc->hctsiz;
		hc->hctsiz = hctsiz & ~Dopng;
		if(hc->hcchar&Chen){
			dprint("ep%d.%d before chanio hcchar=%8.8ux\n",
				ep->dev->nb, ep->nb, hc->hcchar);
			hc->hcchar |= Chen | Chdis;
			while(hc->hcchar&Chen)
				;
			hc->hcint = Chhltd;
		}
		if((i = hc->hcint) != 0){
			dprint("ep%d.%d before chanio hcint=%8.8ux\n",
				ep->dev->nb, ep->nb, i);
			hc->hcint = i;
		}
		if(hc->hcsplt & Spltena){
			qlock(&ctlr->split);
			sofwait(ctlr, hc - ctlr->regs->hchan);
			if((dwc.regs->hfnum & 1) == 0)
				hc->hcchar &= ~Oddfrm;
			else
				hc->hcchar |= Oddfrm;
		}
		hc->hcchar = (hc->hcchar &~ Chdis) | Chen;
		clog(ep, hc);
		if(ep->ttype == Tbulk && dir == Epin)
			i = chanwait(ep, ctlr, hc, /* Ack| */ Chhltd);
		else if(ep->ttype == Tintr && (hc->hcsplt & Spltena))
			i = chanwait(ep, ctlr, hc, Chhltd);
		else
			i = chanwait(ep, ctlr, hc, Chhltd|Nak);
		clog(ep, hc);
		hc->hcint = i;

		if(hc->hcsplt & Spltena){
			hc->hcsplt &= ~Compsplt;
			qunlock(&ctlr->split);
		}

		if((i & Xfercomp) == 0 && i != (Chhltd|Ack) && i != Chhltd){
			if(i & Stall)
				error(Estalled);
			if(i & (Nyet|Frmovrun))
				continue;
			if(i & Nak){
				if(ep->ttype == Tintr)
					tsleep(&up->sleep, return0, 0, ep->pollival);
				else
					tsleep(&up->sleep, return0, 0, 1);
				continue;
			}
			logdump(ep);
			print("usbotg: ep%d.%d error intr %8.8ux\n",
				ep->dev->nb, ep->nb, i);
			if(i & ~(Chhltd|Ack))
				error(Eio);
			if(hc->hcdma != hcdma)
				print("usbotg: weird hcdma %x->%x intr %x->%x\n",
					hcdma, hc->hcdma, i, hc->hcint);
		}
		n = hc->hcdma - hcdma;
		if(n == 0){
			if((hc->hctsiz & Pktcnt) != (hctsiz & Pktcnt))
				break;
			else
				continue;
		}
		if(dir == Epin && ep->ttype == Tbulk && n == nleft){
			nt = (hctsiz & Xfersize) - (hc->hctsiz & Xfersize);
			if(nt != n){
				if(n == ROUND(nt, 4))
					n = nt;
				else
					print("usbotg: intr %8.8ux "
						"dma %8.8ux-%8.8ux "
						"hctsiz %8.8ux-%8.ux\n",
						i, hcdma, hc->hcdma, hctsiz,
						hc->hctsiz);
			}
		}
		if(n > nleft){
			if(n != ROUND(nleft, 4))
				dprint("too much: wanted %d got %d\n",
					len, len - nleft + n);
			n = nleft;
		}
		nleft -= n;
		if(nleft == 0 || (n % maxpkt) != 0)
			break;
		if((i & Xfercomp) && ep->ttype != Tctl)
			break;
		if(dir == Epout)
			dprint("too little: nleft %d hcdma %x->%x hctsiz %x->%x intr %x\n",
				nleft, hcdma, hc->hcdma, hctsiz, hc->hctsiz, i);
	}
	logdump(ep);
	return len - nleft;
}
Ejemplo n.º 10
0
static int
sdgen(Chan* c, char*, Dirtab*, int, int s, Dir* dp)
{
	Qid q;
	uvlong l;
	int i, r;
	SDpart *pp;
	SDunit *unit;
	SDev *sdev;

	switch(TYPE(c->qid)){
	case Qtopdir:
		if(s == DEVDOTDOT){
			mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR);
			snprint(up->genbuf, sizeof up->genbuf, "#%C",
				sddevtab.dc);
			devdir(c, q, up->genbuf, 0, eve, 0555, dp);
			return 1;
		}

		if(s+Qtopbase < Qunitdir)
			return sd1gen(c, s+Qtopbase, dp);
		s -= (Qunitdir-Qtopbase);

		qlock(&devslock);
		for(i=0; i<nelem(devs); i++){
			if(devs[i]){
				if(s < devs[i]->nunit)
					break;
				s -= devs[i]->nunit;
			}
		}

		if(i == nelem(devs)){
			/* Run off the end of the list */
			qunlock(&devslock);
			return -1;
		}

		if((sdev = devs[i]) == nil){
			qunlock(&devslock);
			return 0;
		}

		incref(&sdev->r);
		qunlock(&devslock);

		if((unit = sdev->unit[s]) == nil)
			if((unit = sdgetunit(sdev, s)) == nil){
				decref(&sdev->r);
				return 0;
			}

		mkqid(&q, QID(sdev->idno, s, 0, Qunitdir), 0, QTDIR);
		if(emptystr(unit->user))
			kstrdup(&unit->user, eve);
		devdir(c, q, unit->name, 0, unit->user, unit->perm, dp);
		decref(&sdev->r);
		return 1;

	case Qunitdir:
		if(s == DEVDOTDOT){
			mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR);
			snprint(up->genbuf, sizeof up->genbuf, "#%C",
				sddevtab.dc);
			devdir(c, q, up->genbuf, 0, eve, 0555, dp);
			return 1;
		}

		if((sdev = sdgetdev(DEV(c->qid))) == nil){
			devdir(c, c->qid, "unavailable", 0, eve, 0, dp);
			return 1;
		}

		unit = sdev->unit[UNIT(c->qid)];
		qlock(&unit->ctl);

		/*
		 * Check for media change.
		 * If one has already been detected, sectors will be zero.
		 * If there is one waiting to be detected, online
		 * will return > 1.
		 * Online is a bit of a large hammer but does the job.
		 */
		if(unit->sectors == 0
		|| (unit->dev->ifc->online && unit->dev->ifc->online(unit) > 1))
			sdinitpart(unit);

		i = s+Qunitbase;
		if(i < Qpart){
			r = sd2gen(c, i, dp);
			qunlock(&unit->ctl);
			decref(&sdev->r);
			return r;
		}
		i -= Qpart;
		if(unit->part == nil || i >= unit->npart){
			qunlock(&unit->ctl);
			decref(&sdev->r);
			break;
		}
		pp = &unit->part[i];
		if(!pp->valid){
			qunlock(&unit->ctl);
			decref(&sdev->r);
			return 0;
		}
		l = (pp->end - pp->start) * unit->secsize;
		mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), i, Qpart),
			unit->vers+pp->vers, QTFILE);
		if(emptystr(pp->user))
			kstrdup(&pp->user, eve);
		devdir(c, q, pp->name, l, pp->user, pp->perm, dp);
		qunlock(&unit->ctl);
		decref(&sdev->r);
		return 1;
	case Qraw:
	case Qctl:
	case Qpart:
		if((sdev = sdgetdev(DEV(c->qid))) == nil){
			devdir(c, q, "unavailable", 0, eve, 0, dp);
			return 1;
		}
		unit = sdev->unit[UNIT(c->qid)];
		qlock(&unit->ctl);
		r = sd2gen(c, TYPE(c->qid), dp);
		qunlock(&unit->ctl);
		decref(&sdev->r);
		return r;
	case Qtopctl:
		return sd1gen(c, TYPE(c->qid), dp);
	default:
		break;
	}

	return -1;
}
Ejemplo n.º 11
0
static long
sdbio(Chan* c, int write, char* a, long len, uvlong off)
{
	int nchange;
	long l;
	uchar *b;
	SDpart *pp;
	SDunit *unit;
	SDev *sdev;
	ulong max, nb, offset;
	uvlong bno;

	sdev = sdgetdev(DEV(c->qid));
	if(sdev == nil){
		decref(&sdev->r);
		error(Enonexist);
	}
	unit = sdev->unit[UNIT(c->qid)];
	if(unit == nil)
		error(Enonexist);

	nchange = 0;
	qlock(&unit->ctl);
	while(waserror()){
		/* notification of media change; go around again */
		if(strcmp(up->env->errstr, Eio) == 0 && unit->sectors == 0 && nchange++ == 0){
			sdinitpart(unit);
			continue;
		}

		/* other errors; give up */
		qunlock(&unit->ctl);
		decref(&sdev->r);
		nexterror();
	}
	pp = &unit->part[PART(c->qid)];
	if(unit->vers+pp->vers != c->qid.vers)
		error(Echange);

	/*
	 * Check the request is within bounds.
	 * Removeable drives are locked throughout the I/O
	 * in case the media changes unexpectedly.
	 * Non-removeable drives are not locked during the I/O
	 * to allow the hardware to optimise if it can; this is
	 * a little fast and loose.
	 * It's assumed that non-removeable media parameters
	 * (sectors, secsize) can't change once the drive has
	 * been brought online.
	 */
	bno = (off/unit->secsize) + pp->start;
	nb = ((off+len+unit->secsize-1)/unit->secsize) + pp->start - bno;
	max = SDmaxio/unit->secsize;
	if(nb > max)
		nb = max;
	if(bno+nb > pp->end)
		nb = pp->end - bno;
	if(bno >= pp->end || nb == 0){
		if(write)
			error(Eio);
		qunlock(&unit->ctl);
		decref(&sdev->r);
		poperror();
		return 0;
	}
	if(!(unit->inquiry[1] & SDinq1removable)){
		qunlock(&unit->ctl);
		poperror();
	}

	b = sdmalloc(nb*unit->secsize);
	if(b == nil)
		error(Enomem);
	if(waserror()){
		sdfree(b);
		if(!(unit->inquiry[1] & SDinq1removable))
			decref(&sdev->r);		/* gadverdamme! */
		nexterror();
	}

	offset = off%unit->secsize;
	if(offset+len > nb*unit->secsize)
		len = nb*unit->secsize - offset;
	if(write){
		if(offset || (len%unit->secsize)){
			l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
			if(l < 0)
				error(Eio);
			if(l < (nb*unit->secsize)){
				nb = l/unit->secsize;
				l = nb*unit->secsize - offset;
				if(len > l)
					len = l;
			}
		}
		memmove(b+offset, a, len);
		l = unit->dev->ifc->bio(unit, 0, 1, b, nb, bno);
		if(l < 0)
			error(Eio);
		if(l < offset)
			len = 0;
		else if(len > l - offset)
			len = l - offset;
	}
	else{
		l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
		if(l < 0)
			error(Eio);
		if(l < offset)
			len = 0;
		else if(len > l - offset)
			len = l - offset;
		memmove(a, b+offset, len);
	}
	sdfree(b);
	poperror();

	if(unit->inquiry[1] & SDinq1removable){
		qunlock(&unit->ctl);
		poperror();
	}

	decref(&sdev->r);
	return len;
}
Ejemplo n.º 12
0
static long
sdwrite(Chan* c, void* a, long n, vlong off)
{
	char *f0;
	int i;
	uvlong end, start;
	Cmdbuf *cb;
	SDifc *ifc;
	SDreq *req;
	SDunit *unit;
	SDev *sdev;

	switch(TYPE(c->qid)){
	default:
		error(Eperm);
	case Qtopctl:
		cb = parsecmd(a, n);
		if(waserror()){
			free(cb);
			nexterror();
		}
		if(cb->nf == 0)
			error("empty control message");
		f0 = cb->f[0];
		cb->f++;
		cb->nf--;
		if(strcmp(f0, "config") == 0){
			/* wormhole into ugly legacy interface */
			legacytopctl(cb);
			poperror();
			free(cb);
			break;
		}
		/*
		 * "ata arg..." invokes sdifc[i]->wtopctl(nil, cb),
		 * where sdifc[i]->name=="ata" and cb contains the args.
		 */
		ifc = nil;
		sdev = nil;
		for(i=0; sdifc[i]; i++){
			if(strcmp(sdifc[i]->name, f0) == 0){
				ifc = sdifc[i];
				sdev = nil;
				goto subtopctl;
			}
		}
		/*
		 * "sd1 arg..." invokes sdifc[i]->wtopctl(sdev, cb),
		 * where sdifc[i] and sdev match controller letter "1",
		 * and cb contains the args.
		 */
		if(f0[0]=='s' && f0[1]=='d' && f0[2] && f0[3] == 0){
			if((sdev = sdgetdev(f0[2])) != nil){
				ifc = sdev->ifc;
				goto subtopctl;
			}
		}
		error("unknown interface");

	subtopctl:
		if(waserror()){
			if(sdev)
				decref(&sdev->r);
			nexterror();
		}
		if(ifc->wtopctl)
			ifc->wtopctl(sdev, cb);
		else
			error(Ebadctl);
		poperror();
		poperror();
		if (sdev)
			decref(&sdev->r);
		free(cb);
		break;

	case Qctl:
		cb = parsecmd(a, n);
		sdev = sdgetdev(DEV(c->qid));
		if(sdev == nil)
			error(Enonexist);
		unit = sdev->unit[UNIT(c->qid)];

		qlock(&unit->ctl);
		if(waserror()){
			qunlock(&unit->ctl);
			decref(&sdev->r);
			free(cb);
			nexterror();
		}
		if(unit->vers != c->qid.vers)
			error(Echange);

		if(cb->nf < 1)
			error(Ebadctl);
		if(strcmp(cb->f[0], "part") == 0){
			if(cb->nf != 4)
				error(Ebadctl);
			if(unit->sectors == 0 && !sdinitpart(unit))
				error(Eio);
			start = strtoull(cb->f[2], 0, 0);
			end = strtoull(cb->f[3], 0, 0);
			sdaddpart(unit, cb->f[1], start, end);
		}
		else if(strcmp(cb->f[0], "delpart") == 0){
			if(cb->nf != 2 || unit->part == nil)
				error(Ebadctl);
			sddelpart(unit, cb->f[1]);
		}
		else if(unit->dev->ifc->wctl)
			unit->dev->ifc->wctl(unit, cb);
		else
			error(Ebadctl);
		qunlock(&unit->ctl);
		decref(&sdev->r);
		poperror();
		free(cb);
		break;

	case Qraw:
		sdev = sdgetdev(DEV(c->qid));
		if(sdev == nil)
			error(Enonexist);
		unit = sdev->unit[UNIT(c->qid)];
		qlock(&unit->raw);
		if(waserror()){
			qunlock(&unit->raw);
			decref(&sdev->r);
			nexterror();
		}
		switch(unit->state){
		case Rawcmd:
			if(n < 6 || n > sizeof(req->cmd))
				error(Ebadarg);
			if((req = malloc(sizeof(SDreq))) == nil)
				error(Enomem);
			req->unit = unit;
			memmove(req->cmd, a, n);
			req->clen = n;
			req->flags = SDnosense;
			req->status = ~0;

			unit->req = req;
			unit->state = Rawdata;
			break;

		case Rawstatus:
			unit->state = Rawcmd;
			free(unit->req);
			unit->req = nil;
			error(Ebadusefd);

		case Rawdata:
			unit->state = Rawstatus;
			unit->req->write = 1;
			n = sdrio(unit->req, a, n);
		}
		qunlock(&unit->raw);
		decref(&sdev->r);
		poperror();
		break;
	case Qpart:
		return sdbio(c, 1, a, n, off);
	}

	return n;
}
Ejemplo n.º 13
0
static long
sdread(Chan *c, void *a, long n, vlong off)
{
	char *p, *e, *buf;
	SDpart *pp;
	SDunit *unit;
	SDev *sdev;
	ulong offset;
	int i, l, m, status;

	offset = off;
	switch(TYPE(c->qid)){
	default:
		error(Eperm);
	case Qtopctl:
		m = 64*1024;	/* room for register dumps */
		p = buf = malloc(m);
		if(p == nil)
			error(Enomem);
		e = p + m;
		qlock(&devslock);
		for(i = 0; i < nelem(devs); i++){
			sdev = devs[i];
			if(sdev && sdev->ifc->rtopctl)
				p = sdev->ifc->rtopctl(sdev, p, e);
		}
		qunlock(&devslock);
		n = readstr(off, a, n, buf);
		free(buf);
		return n;

	case Qtopdir:
	case Qunitdir:
		return devdirread(c, a, n, 0, 0, sdgen);

	case Qctl:
		sdev = sdgetdev(DEV(c->qid));
		if(sdev == nil)
			error(Enonexist);

		unit = sdev->unit[UNIT(c->qid)];
		m = 16*1024;	/* room for register dumps */
		p = malloc(m);
		if(p == nil)
			error(Enomem);
		l = snprint(p, m, "inquiry %.48s\n",
			(char*)unit->inquiry+8);
		qlock(&unit->ctl);
		/*
		 * If there's a device specific routine it must
		 * provide all information pertaining to night geometry
		 * and the garscadden trains.
		 */
		if(unit->dev->ifc->rctl)
			l += unit->dev->ifc->rctl(unit, p+l, m-l);
		if(unit->sectors == 0)
			sdinitpart(unit);
		if(unit->sectors){
			if(unit->dev->ifc->rctl == nil)
				l += snprint(p+l, m-l,
					"geometry %llud %lud\n",
					unit->sectors, unit->secsize);
			pp = unit->part;
			for(i = 0; i < unit->npart; i++){
				if(pp->valid)
					l += snprint(p+l, m-l,
						"part %s %llud %llud\n",
						pp->name, pp->start, pp->end);
				pp++;
			}
		}
		qunlock(&unit->ctl);
		decref(&sdev->r);
		l = readstr(offset, a, n, p);
		free(p);
		return l;

	case Qraw:
		sdev = sdgetdev(DEV(c->qid));
		if(sdev == nil)
			error(Enonexist);

		unit = sdev->unit[UNIT(c->qid)];
		qlock(&unit->raw);
		if(waserror()){
			qunlock(&unit->raw);
			decref(&sdev->r);
			nexterror();
		}
		if(unit->state == Rawdata){
			unit->state = Rawstatus;
			i = sdrio(unit->req, a, n);
		}
		else if(unit->state == Rawstatus){
			status = unit->req->status;
			unit->state = Rawcmd;
			free(unit->req);
			unit->req = nil;
			i = readnum(0, a, n, status, NUMSIZE);
		} else
			i = 0;
		qunlock(&unit->raw);
		decref(&sdev->r);
		poperror();
		return i;

	case Qpart:
		return sdbio(c, 0, a, n, off);
	}
}
Ejemplo n.º 14
0
/*
 *  Decrement reference for this address on this link.
 *  Unlink from selftab if this is the last ref.
 *	called with c->car locked
 */
static void
remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uint8_t *a)
{
	Ipself *p, **l;
	Iplink *link, **l_self, **l_lifc;

	qlock(f->self);

	/* find the unique selftab entry */
	l = &f->self->hash[hashipa(a)];
	for(p = *l; p; p = *l){
		if(ipcmp(p->a, a) == 0)
			break;
		l = &p->next;
	}

	if(p == nil)
		goto out;

	/*
	 *  walk down links from an ifc looking for one
	 *  that matches the selftab entry
	 */
	l_lifc = &lifc->link;
	for(link = *l_lifc; link; link = *l_lifc){
		if(link->self == p)
			break;
		l_lifc = &link->lifclink;
	}

	if(link == nil)
		goto out;

	/*
	 *  walk down the links from the selftab looking for
	 *  the one we just found
	 */
	l_self = &p->link;
	for(link = *l_self; link; link = *l_self){
		if(link == *l_lifc)
			break;
		l_self = &link->selflink;
	}

	if(link == nil)
		panic("remselfcache");

	if(--(link->ref) != 0)
		goto out;

	if((p->type & Rmulti) && ifc->medium->remmulti != nil)
		(*ifc->medium->remmulti)(ifc, a, lifc->local);

	/* ref == 0, remove from both chains and free the link */
	*l_lifc = link->lifclink;
	*l_self = link->selflink;
	iplinkfree(link);

	if(p->link != nil)
		goto out;

	/* remove from routing table */
	if(isv4(a))
		v4delroute(f, a+IPv4off, IPallbits+IPv4off, 1);
	else
		v6delroute(f, a, IPallbits, 1);

	/* no more links, remove from hash and free */
	*l = p->next;
	ipselffree(p);

	/* if IPnoaddr, forget */
	if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
		f->self->acceptall = 0;

out:
	qunlock(f->self);
}
Ejemplo n.º 15
0
void
cwrite(Chan* c, uchar *buf, int len, vlong off)
{
	int o, eo;
	Mntcache *m;
	ulong eblock, ee;
	Extent *p, *f, *e, *tail;
	ulong offset;

	if(off > maxcache || len == 0)
		return;

	m = c->mcp;
	if(m == 0)
		return;

	qlock(m);
	if(cdev(m, c) == 0) {
		qunlock(m);
		c->mcp = 0;
		return;
	}

	offset = off;
	m->qid.vers++;
	c->qid.vers++;

	p = 0;
	for(f = m->list; f; f = f->next) {
		if(f->start >= offset)
			break;
		p = f;
	}

	if(p != 0) {
		ee = p->start+p->len;
		eo = offset - p->start;
		/* pack in predecessor if there is space */
		if(offset <= ee && eo < BY2PG) {
			o = len;
			if(o > BY2PG - eo)
				o = BY2PG - eo;
			if(cpgmove(p, buf, eo, o)) {
				if(eo+o > p->len)
					p->len = eo+o;
				buf += o;
				len -= o;
				offset += o;
			}
		}
	}

	/* free the overlap -- it's a rare case */
	eblock = offset+len;
	while(f && f->start < eblock) {
		e = f->next;
		extentfree(f);
		f = e;
	}

	/* link the block (if any) into the middle */
	e = cchain(buf, offset, len, &tail);
	if(e != 0) {
		tail->next = f;
		f = e;
	}

	if(p == 0)
		m->list = f;
	else
		p->next = f;
	qunlock(m);
}
Ejemplo n.º 16
0
void
respond(Req *r, char *error)
{
	int i, m, n;
	char errbuf[ERRMAX];
	Srv *srv;

	srv = r->srv;
	assert(srv != nil);

	assert(r->responded == 0);
	r->error = error;

	switch(r->ifcall.type){
	default:
		assert(0);
	/*
	 * Flush is special.  If the handler says so, we return
	 * without further processing.  Respond will be called
	 * again once it is safe.
	 */
	case Tflush:
		if(rflush(r, error)<0)
			return;
		break;
	case Tversion:	rversion(r, error);	break;
	case Tauth:	rauth(r, error);	break;
	case Tattach:	rattach(r, error);	break;
	case Twalk:	rwalk(r, error);	break;
	case Topen:	ropen(r, error);	break;
	case Tcreate:	rcreate(r, error);	break;
	case Tread:	rread(r, error);	break;
	case Twrite:	rwrite(r, error);	break;
	case Tclunk:	rclunk(r, error);	break;
	case Tremove:	rremove(r, error, errbuf);	break;
	case Tstat:	rstat(r, error);	break;
	case Twstat:	rwstat(r, error);	break;
	}

	r->ofcall.tag = r->ifcall.tag;
	r->ofcall.type = r->ifcall.type+1;
	if(r->error)
		setfcallerror(&r->ofcall, r->error);

if(chatty9p)
	fprint(2, "-%d-> %F\n", srv->outfd, &r->ofcall);

	qlock(&srv->wlock);
	n = convS2M(&r->ofcall, srv->wbuf, srv->msize);
	if(n <= 0){
		fprint(2, "n = %d %F\n", n, &r->ofcall);
		abort();
	}
	assert(n > 2);
	if(r->pool)	/* not a fake */
		closereq(removereq(r->pool, r->ifcall.tag));
	m = write(srv->outfd, srv->wbuf, n);
	if(m != n)
		sysfatal("lib9p srv: write %d returned %d on fd %d: %r", n, m, srv->outfd);
	qunlock(&srv->wlock);

	qlock(&r->lk);	/* no one will add flushes now */
	r->responded = 1;
	qunlock(&r->lk);

	for(i=0; i<r->nflush; i++)
		respond(r->flush[i], nil);
	free(r->flush);
	r->flush = nil;
	r->nflush = 0;

	if(r->pool)
		closereq(r);
	else
		free(r);
}
Ejemplo n.º 17
0
NbSession *
nbssconnect(NbName to, NbName from)
{
	Session *s;
	uchar ipaddr[IPaddrlen];
	char dialaddress[100];
	char dir[NETPATHLEN];
	uchar msg[576];
	int fd;
	long o;
	uchar flags;
	long length;

	if (!nbnameresolve(to, ipaddr))
		return nil;
	fmtinstall('I', eipfmt);
	snprint(dialaddress, sizeof(dialaddress), "tcp!%I!netbios", ipaddr);
	fd = dial(dialaddress, nil, dir, nil);
	if (fd < 0)
		return nil;
	msg[0] = 0x81;
	msg[1] = 0;
	o = 4;
	o += nbnameencode(msg + o, msg + sizeof(msg) - o, to);
	o += nbnameencode(msg + o, msg + sizeof(msg) - o, from);
	hnputs(msg + 2, o - 4);
	if (write(fd, msg, o) != o) {
		close(fd);
		return nil;
	}
	if (readn(fd, msg, 4) != 4) {
		close(fd);
		return nil;
	}
	flags = msg[1];
	length = nhgets(msg + 2) | ((flags & 1) << 16);
	switch (msg[0]) {
	default:
		close(fd);
		werrstr("unexpected session message code 0x%.2ux", msg[0]);
		return nil;
	case 0x82:
		if (length != 0) {
			close(fd);
			werrstr("length not 0 in positive session response");
			return nil;
		}
		break;
	case 0x83:
		if (length != 1) {
			close(fd);
			werrstr("length not 1 in negative session response");
			return nil;
		}
		if (readn(fd, msg + 4, 1) != 1) {
			close(fd);
			return nil;
		}
		close(fd);
		werrstr("negative session response 0x%.2ux", msg[4]);
		return nil;
	}
	s = nbemalloc(sizeof(Session));
	s->fd = fd;
	s->state = Connected;
	qlock(&sessions);
	s->next = sessions.head;
	sessions.head = s;
	qunlock(&sessions);
	return s;
}
Ejemplo n.º 18
0
static void
connproc(void *v)
{
	VtSconn *sc;
	VtConn *c;
	Packet *p;
	VtReq *r;
	int fd;
static int first=1;

if(first && chattyventi){
	first=0;
	fmtinstall('F', vtfcallfmt);
}
	r = nil;
	sc = v;
	sc->c = nil;
	if(0) fprint(2, "new call %s on %d\n", sc->dir, sc->ctl);
	fd = accept(sc->ctl, sc->dir);
	close(sc->ctl);
	if(fd < 0){
		fprint(2, "accept %s: %r\n", sc->dir);
		goto out;
	}

	c = vtconn(fd, fd);
	sc->c = c;
	if(vtversion(c) < 0){
		fprint(2, "vtversion %s: %r\n", sc->dir);
		goto out;
	}
	if(vtsrvhello(c) < 0){
		fprint(2, "vtsrvhello %s: %r\n", sc->dir);
		goto out;
	}

	if(0) fprint(2, "new proc %s\n", sc->dir);
	proccreate(vtsendproc, c, STACK);
	qlock(&c->lk);
	while(!c->writeq)
		rsleep(&c->rpcfork);
	qunlock(&c->lk);

	while((p = vtrecv(c)) != nil){
		r = vtmallocz(sizeof(VtReq));
		if(vtfcallunpack(&r->tx, p) < 0){
			vtlog(VtServerLog, "<font size=-1>%T %s:</font> recv bad packet %p: %r<br>\n", c->addr, p);
			fprint(2, "bad packet on %s: %r\n", sc->dir);
			packetfree(p);
			continue;
		}
		vtlog(VtServerLog, "<font size=-1>%T %s:</font> recv packet %p (%F)<br>\n", c->addr, p, &r->tx);
		if(chattyventi)
			fprint(2, "%s <- %F\n", argv0, &r->tx);
		packetfree(p);
		if(r->tx.msgtype == VtTgoodbye)
			break;
		r->rx.tag = r->tx.tag;
		r->sc = sc;
		scincref(sc);
		if(_vtqsend(sc->srv->q, r) < 0){
			scdecref(sc);
			fprint(2, "hungup queue\n");
			break;
		}
		r = nil;
	}

	if(0) fprint(2, "eof on %s\n", sc->dir);

out:
	if(r){
		vtfcallclear(&r->tx);
		vtfree(r);
	}
	if(0) fprint(2, "freed %s\n", sc->dir);
	scdecref(sc);
	return;
}
Ejemplo n.º 19
0
void
mousethread(void *v)
{
    Text *t, *argt;
    int but;
    uint q0, q1;
    Window *w;
    Plumbmsg *pm;
    Mouse m;
    char *act;
    enum { MResize, MMouse, MPlumb, MWarnings, NMALT };
    static Alt alts[NMALT+1];

    USED(v);
    threadsetname("mousethread");
    alts[MResize].c = mousectl->resizec;
    alts[MResize].v = nil;
    alts[MResize].op = CHANRCV;
    alts[MMouse].c = mousectl->c;
    alts[MMouse].v = &mousectl->m;
    alts[MMouse].op = CHANRCV;
    alts[MPlumb].c = cplumb;
    alts[MPlumb].v = &pm;
    alts[MPlumb].op = CHANRCV;
    alts[MWarnings].c = cwarn;
    alts[MWarnings].v = nil;
    alts[MWarnings].op = CHANRCV;
    if(cplumb == nil)
        alts[MPlumb].op = CHANNOP;
    alts[NMALT].op = CHANEND;

    for(;;) {
        qlock(&row.lk);
        flushwarnings();
        qunlock(&row.lk);
        flushimage(display, 1);
        switch(alt(alts)) {
        case MResize:
            if(getwindow(display, Refnone) < 0)
                error("attach to window");
            draw(screen, screen->r, display->white, nil, ZP);
            iconinit();
            scrlresize();
            rowresize(&row, screen->clipr);
            break;
        case MPlumb:
            if(strcmp(pm->type, "text") == 0) {
                act = plumblookup(pm->attr, "action");
                if(act==nil || strcmp(act, "showfile")==0)
                    plumblook(pm);
                else if(strcmp(act, "showdata")==0)
                    plumbshow(pm);
            }
            plumbfree(pm);
            break;
        case MWarnings:
            break;
        case MMouse:
            /*
             * Make a copy so decisions are consistent; mousectl changes
             * underfoot.  Can't just receive into m because this introduces
             * another race; see /sys/src/libdraw/mouse.c.
             */
            m = mousectl->m;
            qlock(&row.lk);
            t = rowwhich(&row, m.xy);
            if(t!=mousetext && mousetext!=nil && mousetext->w!=nil) {
                winlock(mousetext->w, 'M');
                mousetext->eq0 = ~0;
                wincommit(mousetext->w, mousetext);
                winunlock(mousetext->w);
            }
            mousetext = t;
            if(t == nil)
                goto Continue;
            w = t->w;
            if(t==nil || m.buttons==0)
                goto Continue;
            but = 0;
            if(m.buttons == 1)
                but = 1;
            else if(m.buttons == 2)
                but = 2;
            else if(m.buttons == 4)
                but = 3;
            barttext = t;
            if(t->what==Body && ptinrect(m.xy, t->scrollr)) {
                if(but) {
                    if(swapscrollbuttons) {
                        if(but == 1)
                            but = 3;
                        else if(but == 3)
                            but = 1;
                    }
                    winlock(w, 'M');
                    t->eq0 = ~0;
                    textscroll(t, but);
                    winunlock(w);
                }
                goto Continue;
            }
            /* scroll buttons, wheels, etc. */
            if(w != nil && (m.buttons & (8|16))) {
                if(m.buttons & 8)
                    but = Kscrolloneup;
                else
                    but = Kscrollonedown;
                winlock(w, 'M');
                t->eq0 = ~0;
                texttype(t, but);
                winunlock(w);
                goto Continue;
            }
            if(ptinrect(m.xy, t->scrollr)) {
                if(but) {
                    if(t->what == Columntag)
                        rowdragcol(&row, t->col, but);
                    else if(t->what == Tag) {
                        coldragwin(t->col, t->w, but);
                        if(t->w)
                            barttext = &t->w->body;
                    }
                    if(t->col)
                        activecol = t->col;
                }
                goto Continue;
            }
            if(m.buttons) {
                if(w)
                    winlock(w, 'M');
                t->eq0 = ~0;
                if(w)
                    wincommit(w, t);
                else
                    textcommit(t, TRUE);
                if(m.buttons & 1) {
                    textselect(t);
                    if(w)
                        winsettag(w);
                    argtext = t;
                    seltext = t;
                    if(t->col)
                        activecol = t->col;	/* button 1 only */
                    if(t->w!=nil && t==&t->w->body)
                        activewin = t->w;
                } else if(m.buttons & 2) {
                    if(textselect2(t, &q0, &q1, &argt))
                        execute(t, q0, q1, FALSE, argt);
                } else if(m.buttons & 4) {
                    if(textselect3(t, &q0, &q1))
                        look3(t, q0, q1, FALSE);
                }
                if(w)
                    winunlock(w);
                goto Continue;
            }
Continue:
            qunlock(&row.lk);
            break;
        }
    }
}
Ejemplo n.º 20
0
void
threadmain(int argc, char *argv[])
{
	int i;
	char *file;
	Arena *arena;
	u64int offset, aoffset;
	Part *part;
	uchar buf[8192];
	ArenaHead head;
	ZClump zerocl;

	ventifmtinstall();
	qlock(&godot);
	aoffset = 0;
	ARGBEGIN{
	case 'f':
		fast = 1;
		ventidoublechecksha1 = 0;
		break;
	case 'h':
		host = EARGF(usage());
		break;
	case 'o':
		haveaoffset = 1;
		aoffset = strtoull(EARGF(usage()), 0, 0);
		break;
	case 'M':
		maxwrites = atoi(EARGF(usage()));
		break;
	case 'v':
		verbose = 1;
		break;
	default:
		usage();
		break;
	}ARGEND

	offset = ~(u64int)0;
	switch(argc) {
	default:
		usage();
	case 2:
		offset = strtoull(argv[1], 0, 0);
		/* fall through */
	case 1:
		file = argv[0];
	}

	fmtinstall('V', vtscorefmt);

	statsinit();

	part = initpart(file, OREAD);
	if(part == nil)
		sysfatal("can't open file %s: %r", file);
	if(readpart(part, aoffset, buf, sizeof buf) < 0)
		sysfatal("can't read file %s: %r", file);

	if(unpackarenahead(&head, buf) < 0)
		sysfatal("corrupted arena header: %r");

	if(aoffset+head.size > part->size)
		sysfatal("arena is truncated: want %llud bytes have %llud",
			head.size, part->size);

	partblocksize(part, head.blocksize);
	initdcache(8 * MaxDiskBlock);

	arena = initarena(part, aoffset, head.size, head.blocksize);
	if(arena == nil)
		sysfatal("initarena: %r");

	z = nil;
	if(host==nil || strcmp(host, "/dev/null") != 0){
		z = vtdial(host);
		if(z == nil)
			sysfatal("could not connect to server: %r");
		if(vtconnect(z) < 0)
			sysfatal("vtconnect: %r");
	}
	
	c = chancreate(sizeof(ZClump), 0);
	for(i=0; i<12; i++)
		vtproc(vtsendthread, nil);

	rdarena(arena, offset);
	if(vtsync(z) < 0)
		sysfatal("executing sync: %r");

	memset(&zerocl, 0, sizeof zerocl);
	for(i=0; i<12; i++)
		send(c, &zerocl);
	if(z){
		vthangup(z);
	}
	threadexitsall(0);
}
Ejemplo n.º 21
0
static
Xfid*
fsyswalk(Xfid *x, Fid *f)
{
	Fcall t;
	int c, i, j, id;
	Qid q;
	uchar type;
	ulong path;
	Fid *nf;
	Dirtab *d, *dir;
	Window *w;
	char *err;

	nf = nil;
	w = nil;
	if(f->open)
		return respond(x, &t, "walk of open file");
	if(x->fid != x->newfid){
		nf = newfid(x->newfid);
		if(nf->busy)
			return respond(x, &t, "newfid already in use");
		nf->busy = TRUE;
		nf->open = FALSE;
		nf->mntdir = f->mntdir;
		if(f->mntdir)
			f->mntdir->ref++;
		nf->dir = f->dir;
		nf->qid = f->qid;
		nf->w = f->w;
		nf->nrpart = 0;	/* not open, so must be zero */
		if(nf->w)
			incref(nf->w);
		f = nf;	/* walk f */
	}

	t.nwqid = 0;
	err = nil;
	dir = nil;
	id = WIN(f->qid);
	q = f->qid;

	if(x->nwname > 0){
		for(i=0; i<x->nwname; i++){
			if((q.type & QTDIR) == 0){
				err = Enotdir;
				break;
			}

			if(strcmp(x->wname[i], "..") == 0){
				type = QTDIR;
				path = Qdir;
				id = 0;
				if(w){
					winclose(w);
					w = nil;
				}
    Accept:
				if(i == MAXWELEM){
					err = "name too long";
					break;
				}
				q.type = type;
				q.vers = 0;
				q.path = QID(id, path);
				t.wqid[t.nwqid++] = q;
				continue;
			}

			/* is it a numeric name? */
			for(j=0; (c=x->wname[i][j]); j++)
				if(c<'0' || '9'<c)
					goto Regular;
			/* yes: it's a directory */
			if(w)	/* name has form 27/23; get out before losing w */
				break;
			id = atoi(x->wname[i]);
			qlock(&row);
			w = lookid(id, FALSE);
			if(w == nil){
				qunlock(&row);
				break;
			}
			incref(w);	/* we'll drop reference at end if there's an error */
			path = Qdir;
			type = QTDIR;
			qunlock(&row);
			dir = dirtabw;
			goto Accept;
	
    Regular:
//			if(FILE(f->qid) == Qacme)	/* empty directory */
//				break;
			if(strcmp(x->wname[i], "new") == 0){
				if(w)
					error("w set in walk to new");
				sendp(cnewwindow, nil);	/* signal newwindowthread */
				w = recvp(cnewwindow);	/* receive new window */
				incref(w);
				type = QTDIR;
				path = QID(w->id, Qdir);
				id = w->id;
				dir = dirtabw;
				goto Accept;
			}

			if(id == 0)
				d = dirtab;
			else
				d = dirtabw;
			d++;	/* skip '.' */
			for(; d->name; d++)
				if(strcmp(x->wname[i], d->name) == 0){
					path = d->qid;
					type = d->type;
					dir = d;
					goto Accept;
				}

			break;	/* file not found */
		}

		if(i==0 && err == nil)
			err = Eexist;
	}

	if(err!=nil || t.nwqid<x->nwname){
		if(nf){
			nf->busy = FALSE;
			fsysdelid(nf->mntdir);
		}
	}else if(t.nwqid  == x->nwname){
		if(w){
			f->w = w;
			w = nil;	/* don't drop the reference */
		}
		if(dir)
			f->dir = dir;
		f->qid = q;
	}

	if(w != nil)
		winclose(w);

	return respond(x, &t, err);
}
Ejemplo n.º 22
0
Archivo: qio.c Proyecto: dhootha/akaros
/*
 *  read a queue.  if no data is queued, post a struct block
 *  and wait on its Rendez.
 */
long qread(struct queue *q, void *vp, int len)
{
	ERRSTACK(1);
	struct block *b, *first, **l;
	int m, n;

	qlock(&q->rlock);
	if (waserror()) {
		qunlock(&q->rlock);
		nexterror();
	}

	spin_lock_irqsave(&q->lock);
again:
	if (!qwait(q)) {
		/* queue closed */
		spin_unlock_irqsave(&q->lock);
		qunlock(&q->rlock);
		poperror();
		return 0;
	}

	/* if we get here, there's at least one block in the queue */
	// TODO: Consider removing the Qcoalesce flag and force a coalescing
	// strategy by default.
	if (q->state & Qcoalesce) {
		/* when coalescing, 0 length blocks just go away */
		b = q->bfirst;
		if (BLEN(b) <= 0) {
			freeb(qremove(q));
			goto again;
		}

		/*  grab the first block plus as many
		 *  following blocks as will completely
		 *  fit in the read.
		 */
		n = 0;
		l = &first;
		m = BLEN(b);
		for (;;) {
			*l = qremove(q);
			l = &b->next;
			n += m;

			b = q->bfirst;
			if (b == NULL)
				break;
			m = BLEN(b);
			if (n + m > len)
				break;
		}
	} else {
		first = qremove(q);
		n = BLEN(first);
	}

	/* copy to user space outside of the ilock */
	spin_unlock_irqsave(&q->lock);
	b = bl2mem(vp, first, len);
	spin_lock_irqsave(&q->lock);

	/* take care of any left over partial block */
	if (b != NULL) {
		n -= BLEN(b);
		if (q->state & Qmsg)
			freeb(b);
		else
			qputback(q, b);
	}

	/* restart producer */
	qwakeup_iunlock(q);

	poperror();
	qunlock(&q->rlock);
	return n;
}
Ejemplo n.º 23
0
void
respond(Req *r, char *error)
{
	int i, m, n;
	char errbuf[ERRMAX];
	Srv *srv;

	srv = r->srv;
	assert(srv != nil);

	if(r->responded){
		assert(r->pool);
		goto free;
	}
		
	assert(r->responded == 0);
	r->error = error;

	switch(r->ifcall.type){
	default:
		assert(0);
	/*
	 * Flush is special.  If the handler says so, we return
	 * without further processing.  Respond will be called
	 * again once it is safe.
	 */
	case Tflush:
		if(rflush(r, error)<0)
			return;
		break;
	case Tversion:	rversion(r, error);	break;
	case Tauth:	rauth(r, error);	break;
	case Tattach:	rattach(r, error);	break;
	case Twalk:	rwalk(r, error);	break;
	case Topen:	ropen(r, error);	break;
	case Tcreate:	rcreate(r, error);	break;
	case Tread:	rread(r, error);	break;
	case Twrite:	rwrite(r, error);	break;
	case Tclunk:	rclunk(r, error);	break;
	case Tremove:	rremove(r, error, errbuf);	break;
	case Tstat:	rstat(r, error);	break;
	case Twstat:	rwstat(r, error);	break;
	}

	r->ofcall.tag = r->ifcall.tag;
	r->ofcall.type = r->ifcall.type+1;
	if(r->error)
		setfcallerror(&r->ofcall, r->error);

	if(srv->fake)
		return;

if(chatty9p)
	fprint(2, "-%d-> %F\n", srv->outfd, &r->ofcall);

	qlock(&srv->wlock);
	n = convS2M(&r->ofcall, srv->wbuf, srv->msize);
	if(n <= 0){
		fprint(2, "n = %d %F\n", n, &r->ofcall);
		abort();
	}
	assert(n > 2);
	/*
	 * There is a race here - we must remove the entry before
	 * the write, so that if the client is very fast and reuses the
	 * tag, the read loop won't think it is still in use.
	 * 
	 * By removing the entry before the write, we open up a 
	 * race with incoming Tflush messages.  Specifically, an
	 * incoming Tflush might not see r even though it has not
	 * yet been responded to.  It would then send an Rflush
	 * immediately, potentially before we do the write.  This can't
	 * happen because we already old srv->wlock, so nothing
	 * is going out on the wire before this write.
	 */
	if(r->pool)	/* not a fake */
		closereq(removereq(r->pool, r->ifcall.tag));

	qlock(&r->lk);
	r->responded = 1;
	if(r->pool)
	if(r->ref.ref == 1+r->nflush)
	if(r->fid){
		/*
		 * There are no references other than in our r->flush array,
		 * so no one else should be accessing r concurrently.
		 * Close the fid now, before responding to the message.
		 * 
		 * If the client is behaving (there are no outstanding T-messages
		 * that reference r->fid) and the message is a Tclunk or Tremove,
		 * then this closefid will call destroyfid.  
		 * 
		 * This means destroyfid can't piddle around 
		 * indefinitely (we're holding srv->wlock!), but it provides
		 * for tighter semantics as to when destroyfid is called.
		 *
		 * LANL has observed cases where waiting until after the write
		 * can delay a closefid on a Twrite for many 9P transactions,
		 * so that a handful of transactions can happen including a Tclunk
		 * and a Topen, and the original fid will still not be destroyed.
		 */
		closefid(r->fid);
		r->fid = nil;
	}
	qunlock(&r->lk);
	m = write(srv->outfd, srv->wbuf, n);
	if(m != n)
		sysfatal("lib9p srv: write %d returned %d on fd %d: %r", n, m, srv->outfd);
	qunlock(&srv->wlock);

free:
	qlock(&r->lk);	/* no one will add flushes now */

	for(i=0; i<r->nflush; i++){
		r->flush[i]->oldreq = nil;	/* so it doesn't try to lock us! */
		respond(r->flush[i], nil);
	}
	free(r->flush);
	r->nflush = 0;
	r->flush = nil;
	qunlock(&r->lk);

	if(r->pool)
		closereq(r);
	else
		free(r);
}
Ejemplo n.º 24
0
Archivo: qio.c Proyecto: dhootha/akaros
/*
 *  add a block to a queue obeying flow control
 */
long qbwrite(struct queue *q, struct block *b)
{
	ERRSTACK(1);
	int n, dowakeup;
	volatile bool should_free_b = TRUE;

	n = BLEN(b);

	if (q->bypass) {
		(*q->bypass) (q->arg, b);
		return n;
	}

	dowakeup = 0;
	qlock(&q->wlock);
	if (waserror()) {
		if (b != NULL && should_free_b)
			freeb(b);
		qunlock(&q->wlock);
		nexterror();
	}

	spin_lock_irqsave(&q->lock);

	/* give up if the queue is closed */
	if (q->state & Qclosed) {
		spin_unlock_irqsave(&q->lock);
		error(EFAIL, q->err);
	}

	/* if nonblocking, don't queue over the limit */
	if (q->len >= q->limit) {
		/* drop overflow takes priority over regular non-blocking */
		if (q->state & Qdropoverflow) {
			spin_unlock_irqsave(&q->lock);
			freeb(b);
			dropcnt += n;
			qunlock(&q->wlock);
			poperror();
			return n;
		}
		if (q->state & Qnonblock) {
			spin_unlock_irqsave(&q->lock);
			freeb(b);
			error(EAGAIN, "queue full");
		}
	}

	/* queue the block */
	should_free_b = FALSE;
	if (q->bfirst)
		q->blast->next = b;
	else
		q->bfirst = b;
	q->blast = b;
	b->next = 0;
	q->len += BALLOC(b);
	q->dlen += n;
	QDEBUG checkb(b, "qbwrite");
	b = NULL;

	/* make sure other end gets awakened */
	if (q->state & Qstarve) {
		q->state &= ~Qstarve;
		dowakeup = 1;
	}
	spin_unlock_irqsave(&q->lock);

	/*  get output going again */
	if (q->kick && (dowakeup || (q->state & Qkick)))
		q->kick(q->arg);

	/* wakeup anyone consuming at the other end */
	if (dowakeup) {
		rendez_wakeup(&q->rr);
		qwake_cb(q, FDTAP_FILT_READABLE);
	}

	/*
	 *  flow control, wait for queue to get below the limit
	 *  before allowing the process to continue and queue
	 *  more.  We do this here so that postnote can only
	 *  interrupt us after the data has been queued.  This
	 *  means that things like 9p flushes and ssl messages
	 *  will not be disrupted by software interrupts.
	 *
	 *  Note - this is moderately dangerous since a process
	 *  that keeps getting interrupted and rewriting will
	 *  queue infinite crud.
	 */
	for (;;) {
		if ((q->state & (Qdropoverflow | Qnonblock)) || qnotfull(q))
			break;

		spin_lock_irqsave(&q->lock);
		q->state |= Qflow;
		spin_unlock_irqsave(&q->lock);
		rendez_sleep(&q->wr, qnotfull, q);
	}

	qunlock(&q->wlock);
	poperror();
	return n;
}
Ejemplo n.º 25
0
long
sysexec(ulong *arg)
{
	Segment *s, *ts;
	ulong t, d, b;
	int i;
	Chan *tc;
	char **argv, **argp;
	char *a, *charp, *args, *file, *file0;
	char *progarg[sizeof(Exec)/2+1], *elem, progelem[64];
	ulong ssize, spage, nargs, nbytes, n, bssend;
	int indir;
	Exec exec;
	char line[sizeof(Exec)];
	Fgrp *f;
	Image *img;
	ulong magic, text, entry, data, bss;
	Tos *tos;

	indir = 0;
	elem = nil;
	validaddr(arg[0], 1, 0);
	file0 = validnamedup((char*)arg[0], 1);
	if(waserror()){
		free(file0);
		free(elem);
		nexterror();
	}
	file = file0;
	for(;;){
		tc = namec(file, Aopen, OEXEC, 0);
		if(waserror()){
			cclose(tc);
			nexterror();
		}
		if(!indir)
			kstrdup(&elem, up->genbuf);

		n = devtab[tc->type]->read(tc, &exec, sizeof(Exec), 0);
		if(n < 2)
			error(Ebadexec);
		magic = l2be(exec.magic);
		text = l2be(exec.text);
		entry = l2be(exec.entry);
		if(n==sizeof(Exec) && (magic == AOUT_MAGIC)){
			if(text >= USTKTOP-UTZERO
			|| entry < UTZERO+sizeof(Exec)
			|| entry >= UTZERO+sizeof(Exec)+text)
				error(Ebadexec);
			break; /* for binary */
		}

		/*
		 * Process #! /bin/sh args ...
		 */
		memmove(line, &exec, sizeof(Exec));
		if(indir || line[0]!='#' || line[1]!='!')
			error(Ebadexec);
		n = shargs(line, n, progarg);
		if(n == 0)
			error(Ebadexec);
		indir = 1;
		/*
		 * First arg becomes complete file name
		 */
		progarg[n++] = file;
		progarg[n] = 0;
		validaddr(arg[1], BY2WD, 1);
		arg[1] += BY2WD;
		file = progarg[0];
		if(strlen(elem) >= sizeof progelem)
			error(Ebadexec);
		strcpy(progelem, elem);
		progarg[0] = progelem;
		poperror();
		cclose(tc);
	}

	data = l2be(exec.data);
	bss = l2be(exec.bss);
	t = (UTZERO+sizeof(Exec)+text+(BY2PG-1)) & ~(BY2PG-1);
	d = (t + data + (BY2PG-1)) & ~(BY2PG-1);
	bssend = t + data + bss;
	b = (bssend + (BY2PG-1)) & ~(BY2PG-1);
	if(t >= KZERO || d >= KZERO || b >= KZERO)
		error(Ebadexec);

	/*
	 * Args: pass 1: count
	 */
	nbytes = sizeof(Tos);		/* hole for profiling clock at top of stack (and more) */
	nargs = 0;
	if(indir){
		argp = progarg;
		while(*argp){
			a = *argp++;
			nbytes += strlen(a) + 1;
			nargs++;
		}
	}
	evenaddr(arg[1]);
	argp = (char**)arg[1];
	validaddr((ulong)argp, BY2WD, 0);
	while(*argp){
		a = *argp++;
		if(((ulong)argp&(BY2PG-1)) < BY2WD)
			validaddr((ulong)argp, BY2WD, 0);
		validaddr((ulong)a, 1, 0);
		nbytes += ((char*)vmemchr(a, 0, 0x7FFFFFFF) - a) + 1;
		nargs++;
	}
	ssize = BY2WD*(nargs+1) + ((nbytes+(BY2WD-1)) & ~(BY2WD-1));

	/*
	 * 8-byte align SP for those (e.g. sparc) that need it.
	 * execregs() will subtract another 4 bytes for argc.
	 */
	if((ssize+4) & 7)
		ssize += 4;
	spage = (ssize+(BY2PG-1)) >> PGSHIFT;

	/*
	 * Build the stack segment, putting it in kernel virtual for the moment
	 */
	if(spage > TSTKSIZ)
		error(Enovmem);

	qlock(&up->seglock);
	if(waserror()){
		qunlock(&up->seglock);
		nexterror();
	}
	up->seg[ESEG] = newseg(SG_STACK, TSTKTOP-USTKSIZE, USTKSIZE/BY2PG);

	/*
	 * Args: pass 2: assemble; the pages will be faulted in
	 */
	tos = (Tos*)(TSTKTOP - sizeof(Tos));
	tos->cyclefreq = m->cyclefreq;
	cycles((uvlong*)&tos->pcycles);
	tos->pcycles = -tos->pcycles;
	tos->kcycles = tos->pcycles;
	tos->clock = 0;
	argv = (char**)(TSTKTOP - ssize);
	charp = (char*)(TSTKTOP - nbytes);
	args = charp;
	if(indir)
		argp = progarg;
	else
		argp = (char**)arg[1];

	for(i=0; i<nargs; i++){
		if(indir && *argp==0) {
			indir = 0;
			argp = (char**)arg[1];
		}
		*argv++ = charp + (USTKTOP-TSTKTOP);
		n = strlen(*argp) + 1;
		memmove(charp, *argp++, n);
		charp += n;
	}
	free(file0);

	free(up->text);
	up->text = elem;
	elem = nil;	/* so waserror() won't free elem */
	USED(elem);

	/* copy args; easiest from new process's stack */
	n = charp - args;
	if(n > 128)	/* don't waste too much space on huge arg lists */
		n = 128;
	a = up->args;
	up->args = nil;
	free(a);
	up->args = smalloc(n);
	memmove(up->args, args, n);
	if(n>0 && up->args[n-1]!='\0'){
		/* make sure last arg is NUL-terminated */
		/* put NUL at UTF-8 character boundary */
		for(i=n-1; i>0; --i)
			if(fullrune(up->args+i, n-i))
				break;
		up->args[i] = 0;
		n = i+1;
	}
	up->nargs = n;

	/*
	 * Committed.
	 * Free old memory.
	 * Special segments are maintained across exec
	 */
	for(i = SSEG; i <= BSEG; i++) {
		putseg(up->seg[i]);
		/* prevent a second free if we have an error */
		up->seg[i] = 0;
	}
	for(i = BSEG+1; i < NSEG; i++) {
		s = up->seg[i];
		if(s != 0 && (s->type&SG_CEXEC)) {
			putseg(s);
			up->seg[i] = 0;
		}
	}

	/*
	 * Close on exec
	 */
	f = up->fgrp;
	for(i=0; i<=f->maxfd; i++)
		fdclose(i, CCEXEC);

	/* Text.  Shared. Attaches to cache image if possible */
	/* attachimage returns a locked cache image */
	img = attachimage(SG_TEXT|SG_RONLY, tc, UTZERO, (t-UTZERO)>>PGSHIFT);
	ts = img->s;
	up->seg[TSEG] = ts;
	ts->flushme = 1;
	ts->fstart = 0;
	ts->flen = sizeof(Exec)+text;
	unlock(img);

	/* Data. Shared. */
	s = newseg(SG_DATA, t, (d-t)>>PGSHIFT);
	up->seg[DSEG] = s;

	/* Attached by hand */
	incref(img);
	s->image = img;
	s->fstart = ts->fstart+ts->flen;
	s->flen = data;

	/* BSS. Zero fill on demand */
	up->seg[BSEG] = newseg(SG_BSS, d, (b-d)>>PGSHIFT);

	/*
	 * Move the stack
	 */
	s = up->seg[ESEG];
	up->seg[ESEG] = 0;
	up->seg[SSEG] = s;
	qunlock(&up->seglock);
	poperror();	/* seglock */
	poperror();	/* elem */
	s->base = USTKTOP-USTKSIZE;
	s->top = USTKTOP;
	relocateseg(s, USTKTOP-TSTKTOP);

	/*
	 *  '/' processes are higher priority (hack to make /ip more responsive).
	 */
	if(devtab[tc->type]->dc == L'/')
		up->basepri = PriRoot;
	up->priority = up->basepri;
	poperror();
	cclose(tc);

	/*
	 *  At this point, the mmu contains info about the old address
	 *  space and needs to be flushed
	 */
	flushmmu();
	qlock(&up->debug);
	up->nnote = 0;
	up->notify = 0;
	up->notified = 0;
	up->privatemem = 0;
	procsetup(up);
	qunlock(&up->debug);
	if(up->hang)
		up->procctl = Proc_stopme;

	return execregs(entry, ssize, nargs);
}
Ejemplo n.º 26
0
int
cread(Chan *c, uchar *buf, int len, vlong off)
{
	KMap *k;
	Page *p;
	Mntcache *m;
	Extent *e, **t;
	int o, l, total;
	ulong offset;

	if(off+len > maxcache)
		return 0;

	m = c->mcp;
	if(m == 0)
		return 0;

	qlock(m);
	if(cdev(m, c) == 0) {
		qunlock(m);
		c->mcp = 0;
		return 0;
	}

	offset = off;
	t = &m->list;
	for(e = *t; e; e = e->next) {
		if(offset >= e->start && offset < e->start+e->len)
			break;
		t = &e->next;
	}

	if(e == 0) {
		qunlock(m);
		return 0;
	}

	total = 0;
	while(len) {
		p = cpage(e);
		if(p == 0) {
			*t = e->next;
			extentfree(e);
			qunlock(m);
			return total;
		}

		o = offset - e->start;
		l = len;
		if(l > e->len-o)
			l = e->len-o;

		k = kmap(p);
		if(waserror()) {
			kunmap(k);
			putpage(p);
			qunlock(m);
			nexterror();
		}

		memmove(buf, (uchar*)VA(k) + o, l);

		poperror();
		kunmap(k);

		putpage(p);

		buf += l;
		len -= l;
		offset += l;
		total += l;
		t = &e->next;
		e = e->next;
		if(e == 0 || e->start != offset)
			break;
	}

	qunlock(m);
	return total;
}
Ejemplo n.º 27
0
Archivo: main.c Proyecto: 99years/plan9
void
mousethread(void *)
{
	Plumbmsg *pm;
	Mouse m;
	Text *t;
	int but;
	enum { MResize, MMouse, MPlumb, MRefresh, NMALT };
	static Alt alts[NMALT+1];

	threadsetname("mousethread");
	alts[MResize].c = mousectl->resizec;
	alts[MResize].v = nil;
	alts[MResize].op = CHANRCV;
	alts[MMouse].c = mousectl->c;
	alts[MMouse].v = &mousectl->Mouse;
	alts[MMouse].op = CHANRCV;
	alts[MPlumb].c = cplumb;
	alts[MPlumb].v = &pm;
	alts[MPlumb].op = CHANRCV;
	alts[MRefresh].c = crefresh;
	alts[MRefresh].v = nil;
	alts[MRefresh].op = CHANRCV;
	if(cplumb == nil)
		alts[MPlumb].op = CHANNOP;
	alts[NMALT].op = CHANEND;

	for(;;){
		qlock(&row);
		flushrefresh();
		qunlock(&row);
		flushimage(display, 1);
		switch(alt(alts)){
		case MResize:
			if(getwindow(display, Refnone) < 0)
				error("resized");
			scrlresize();
			tmpresize();
			rowresize(&row, screen->clipr);
			break;
		case MPlumb:
			plumblook(pm);
			plumbfree(pm);
			break;
		case MRefresh:
			break;
		case MMouse:
			m = mousectl->Mouse;
			if(m.buttons == 0)
				continue;

			qlock(&row);
			but = 0;
			if(m.buttons == 1)
				but = 1;
			else if(m.buttons == 2)
				but = 2;
			else if(m.buttons == 4)
				but = 3;

			if(m.buttons & (8|16)){
				if(m.buttons & 8)
					but = Kscrolloneup;
				else
					but = Kscrollonedown;
				rowwhich(&row, m.xy, but, TRUE);
			}else	if(but){
				t = rowwhich(&row, m.xy, but, FALSE);
				if(t)
					textmouse(t, m.xy, but);
			}
			qunlock(&row);
			break;
		}
	}
}
Ejemplo n.º 28
0
void
cupdate(Chan *c, uchar *buf, int len, vlong off)
{
	Mntcache *m;
	Extent *tail;
	Extent *e, *f, *p;
	int o, ee, eblock;
	ulong offset;

	if(off > maxcache || len == 0)
		return;

	m = c->mcp;
	if(m == 0)
		return;
	qlock(m);
	if(cdev(m, c) == 0) {
		qunlock(m);
		c->mcp = 0;
		return;
	}

	/*
	 * Find the insertion point
	 */
	offset = off;
	p = 0;
	for(f = m->list; f; f = f->next) {
		if(f->start > offset)
			break;
		p = f;
	}

	/* trim if there is a successor */
	eblock = offset+len;
	if(f != 0 && eblock > f->start) {
		len -= (eblock - f->start);
		if(len <= 0) {
			qunlock(m);
			return;
		}
	}

	if(p == 0) {		/* at the head */
		e = cchain(buf, offset, len, &tail);
		if(e != 0) {
			m->list = e;
			tail->next = f;
		}
		qunlock(m);
		return;
	}

	/* trim to the predecessor */
	ee = p->start+p->len;
	if(offset < ee) {
		o = ee - offset;
		len -= o;
		if(len <= 0) {
			qunlock(m);
			return;
		}
		buf += o;
		offset += o;
	}

	/* try and pack data into the predecessor */
	if(offset == ee && p->len < BY2PG) {
		o = len;
		if(o > BY2PG - p->len)
			o = BY2PG - p->len;
		if(cpgmove(p, buf, p->len, o)) {
			p->len += o;
			buf += o;
			len -= o;
			offset += o;
			if(len <= 0) {
				if(f && p->start + p->len > f->start)
					print("CACHE: p->start=%uld p->len=%d f->start=%uld\n",
						p->start, p->len, f->start);
				qunlock(m);
				return;
			}
		}
	}

	e = cchain(buf, offset, len, &tail);
	if(e != 0) {
		p->next = e;
		tail->next = f;
	}
	qunlock(m);
}
Ejemplo n.º 29
0
/*
 *  Call user, if necessary, with note.
 *  Pass user the Ureg struct and the note on his stack.
 */
int
notify(Ureg* ureg)
{
	int l;
	Note *n;
	u32int s;
	uintptr sp;
	NFrame *nf;

	if(up->procctl)
		procctl(up);
	if(up->nnote == 0)
		return 0;

	fpunotify(ureg);

	s = spllo();
	qlock(&up->debug);

	up->notepending = 0;
	n = &up->note[0];
	if(strncmp(n->msg, "sys:", 4) == 0){
		l = strlen(n->msg);
		if(l > ERRMAX-23)	/* " pc=0x0123456789abcdef\0" */
			l = ERRMAX-23;
		snprint(n->msg + l, sizeof n->msg - l, " pc=%#lux", ureg->pc);
	}

	if(n->flag != NUser && (up->notified || up->notify == 0)){
		if(n->flag == NDebug)
			pprint("suicide: %s\n", n->msg);
		qunlock(&up->debug);
		pexit(n->msg, n->flag != NDebug);
	}

	if(up->notified){
		qunlock(&up->debug);
		splhi();
		return 0;
	}
		
	if(up->notify == nil){
		qunlock(&up->debug);
		pexit(n->msg, n->flag != NDebug);
	}
	if(!okaddr(PTR2UINT(up->notify), 1, 0)){
		pprint("suicide: notify function address %#p\n", up->notify);
		qunlock(&up->debug);
		pexit("Suicide", 0);
	}

	sp = ureg->sp - sizeof(NFrame);
	if(!okaddr(sp, sizeof(NFrame), 1)){
		qunlock(&up->debug);
		pprint("suicide: notify stack address %#p\n", sp);
		pexit("Suicide", 0);
	}

	nf = UINT2PTR(sp);
	memmove(&nf->ureg, ureg, sizeof(Ureg));
	nf->old = up->ureg;
	up->ureg = nf;
	memmove(nf->msg, up->note[0].msg, ERRMAX);
	nf->arg1 = nf->msg;
	nf->arg0 = &nf->ureg;
	nf->ip = 0;

	ureg->sp = sp;
	ureg->pc = PTR2UINT(up->notify);
	up->notified = 1;
	up->nnote--;
	memmove(&up->lastnote, &up->note[0], sizeof(Note));
	memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));

	qunlock(&up->debug);
	splx(s);

	return 1;
}
Ejemplo n.º 30
0
/*
 * decapsulate IP packet from IP/ESP packet in bp and
 * pass the result up the spi's Conv's read queue.
 */
void
espiput(Proto *esp, Ipifc*, Block *bp)
{
	int payload, nexthdr;
	uchar *auth, *espspi;
	Conv *c;
	Espcb *ecb;
	Esptail *et;
	Fs *f;
	Userhdr *uh;
	Versdep vers;

	f = esp->f;

	getverslens(pktipvers(f, &bp), &vers);

	bp = pullupblock(bp, vers.hdrlen + Esptaillen);
	if(bp == nil) {
		netlog(f, Logesp, "esp: short packet\n");
		return;
	}
	getpktspiaddrs(bp->rp, &vers);

	qlock(esp);
	/* Look for a conversation structure for this port */
	c = convlookup(esp, vers.spi);
	if(c == nil) {
		qunlock(esp);
		netlog(f, Logesp, "esp: no conv %I -> %I!%lud\n", vers.raddr,
			vers.laddr, vers.spi);
		icmpnoconv(f, bp);
		freeblist(bp);
		return;
	}

	qlock(c);
	qunlock(esp);

	ecb = c->ptcl;
	/* too hard to do decryption/authentication on block lists */
	if(bp->next)
		bp = concatblock(bp);

	if(BLEN(bp) < vers.hdrlen + ecb->espivlen + Esptaillen + ecb->ahlen) {
		qunlock(c);
		netlog(f, Logesp, "esp: short block %I -> %I!%lud\n", vers.raddr,
			vers.laddr, vers.spi);
		freeb(bp);
		return;
	}

	auth = bp->wp - ecb->ahlen;
	espspi = vers.version == V4?	((Esp4hdr*)bp->rp)->espspi:
					((Esp6hdr*)bp->rp)->espspi;

	/* compute secure hash and authenticate */
	if(!ecb->auth(ecb, espspi, auth - espspi, auth)) {
		qunlock(c);
print("esp: bad auth %I -> %I!%ld\n", vers.raddr, vers.laddr, vers.spi);
		netlog(f, Logesp, "esp: bad auth %I -> %I!%lud\n", vers.raddr,
			vers.laddr, vers.spi);
		freeb(bp);
		return;
	}

	payload = BLEN(bp) - vers.hdrlen - ecb->ahlen;
	if(payload <= 0 || payload % 4 != 0 || payload % ecb->espblklen != 0) {
		qunlock(c);
		netlog(f, Logesp, "esp: bad length %I -> %I!%lud payload=%d BLEN=%lud\n",
			vers.raddr, vers.laddr, vers.spi, payload, BLEN(bp));
		freeb(bp);
		return;
	}

	/* decrypt payload */
	if(!ecb->cipher(ecb, bp->rp + vers.hdrlen, payload)) {
		qunlock(c);
print("esp: cipher failed %I -> %I!%ld: %s\n", vers.raddr, vers.laddr, vers.spi, up->errstr);
		netlog(f, Logesp, "esp: cipher failed %I -> %I!%lud: %s\n",
			vers.raddr, vers.laddr, vers.spi, up->errstr);
		freeb(bp);
		return;
	}

	payload -= Esptaillen;
	et = (Esptail*)(bp->rp + vers.hdrlen + payload);
	payload -= et->pad + ecb->espivlen;
	nexthdr = et->nexthdr;
	if(payload <= 0) {
		qunlock(c);
		netlog(f, Logesp, "esp: short packet after decrypt %I -> %I!%lud\n",
			vers.raddr, vers.laddr, vers.spi);
		freeb(bp);
		return;
	}

	/* trim packet */
	bp->rp += vers.hdrlen + ecb->espivlen; /* toss original IP & ESP hdrs */
	bp->wp = bp->rp + payload;
	if(ecb->header) {
		/* assume Userhdrlen < Esp4hdrlen < Esp6hdrlen */
		bp->rp -= Userhdrlen;
		uh = (Userhdr*)bp->rp;
		memset(uh, 0, Userhdrlen);
		uh->nexthdr = nexthdr;
	}

	/* ingress filtering here? */

	if(qfull(c->rq)){
		netlog(f, Logesp, "esp: qfull %I -> %I.%uld\n", vers.raddr,
			vers.laddr, vers.spi);
		freeblist(bp);
	}else {
//		print("esp: pass up: %uld\n", BLEN(bp));
		qpass(c->rq, bp);	/* pass packet up the read queue */
	}

	qunlock(c);
}