607 lines · 9.1 KB · C
RawDownload
/* * cec — simple ethernet console * Copyright © Coraid, Inc. 2006-2009 * All Rights Reserved. */#include <u.h>#include <libc.h>#include <ip.h>		/* really! */#include <bio.h>#include <ndb.h>#include "cec.h" enum {	Tinita		= 0,	Tinitb,	Tinitc,	Tdata,	Tack,	Tdiscover,	Toffer,	Treset,		Hdrsz		= 18,	Timeout		= 7500,}; typedef struct {	uchar	ea[Eaddrlen];	int	major;	char	name[28];} Shelf; int 	conn(int);int 	pickone(void);void 	probe(void); uchar	bcast[Eaddrlen]	= {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};uchar	ea[Eaddrlen];uchar	ea0[Eaddrlen];uchar	contag;char 	esc		= '';char	*host;int	ntab;char	pflag;int	shelf		= -1;char	*srv;char	*svc;Shelf	*con;Shelf	tab[1000]; extern 	int fd;		/* set in netopen */ voidpost(char *srv, int fd){	char buf[32];	int f; 	if((f = create(srv, OWRITE, 0666)) == -1)		sysfatal("create %s: %r", srv);	snprint(buf, sizeof buf, "%d", fd);	if(write(f, buf, strlen(buf)) != strlen(buf))		sysfatal("write %s: %r", srv);	close(f);} voiddosrv(char *s){	int p[2]; 	if(pipe(p) < 0)		sysfatal("pipe: %r");	if (srv[0] != '/')		svc = smprint("/srv/%s", s);	else		svc = smprint("%s", s);	post(svc, p[0]);	close(p[0]);	dup(p[1], 0);	dup(p[1], 1); 	switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){	case -1:		sysfatal("fork: %r");	case 0:		break;	default:		exits("");	}	close(2);} voidusage(void){	fprint(2, "usage: cec [-dp] [-c esc] [-e ea] [-s shelf] [-h host] [-S srv] interface\n");	exits0("usage");} voidcatch(void*, char *note){	if(strcmp(note, "alarm") == 0)		noted(NCONT);	noted(NDFLT);} intnilea(uchar *ea){	return memcmp(ea, ea0, sizeof ea0) == 0;} intspecific(void){	return shelf != -1 || host != 0 || !nilea(ea);} voidmain(int argc, char **argv){	char *p, *v;	int r, n; 	ARGBEGIN{	case 'S':		srv = EARGF(usage());		break;	case 'c':		esc = toupper(*(EARGF(usage()))) - 'A' + 1;		if(esc < 1 || esc > 0x19)			usage();		break;	case 'd':		debug++;		break;	case 'e':		p = EARGF(usage());		if(v = csgetvalue(nil, "sys", p, "ether", 0))			p = v;		if(parseether(ea, p) == -1)			usage();		free(v);		pflag = 1;		break;	case 'h':		host = EARGF(usage());		break;	case 'p':		pflag = 1;		break;	case 's':		shelf = atoi(EARGF(usage()));		break;	default:		usage();	}ARGEND	if(argc == 0)		*argv = "/net/ether0";	else if(argc != 1)		usage();	fmtinstall('E', eipfmt);	if(srv != nil)		dosrv(srv);	r = netopen(*argv);	if(r == -1){		fprint(2, "cec: can't netopen %s\n", *argv);		exits0("open");	}	notify(catch);	probe();	for(;;){		n = 0;		if(!specific())			n = pickone();		rawon();		conn(n);		rawoff();		if(pflag == 0){			if(shelf != -1)				exits0("shelf not found");			if(host)				exits0("host not found");			if(!nilea(ea))				exits0("ea not found");		}else if(specific())			exits0("");	}} voidtimewait(int ms){	alarm(ms);} intdidtimeout(void){	char buf[ERRMAX]; 	rerrstr(buf, sizeof buf);	if(strcmp(buf, "interrupted") == 0){		werrstr(buf, 0);		return 1;	}	return 0;} ushorthtons(ushort h){	ushort n;	uchar *p; 	p = (uchar*)&n;	p[0] = h >> 8;	p[1] = h;	return n;} ushortntohs(int h){	ushort n;	uchar *p; 	n = h;	p = (uchar*)&n;	return p[0] << 8 | p[1];} inttcmp(void *a, void *b){	int d;	Shelf *s, *t; 	s = a;	t = b;	d = s->major - t->major;	if(d == 0)		d = strcmp(s->name, t->name);	if(d == 0)		d = memcmp(s->ea, t->ea, Eaddrlen);	return d;} voidprobe(void){	char *sh, *other;	int n, i;	Pkt q;	Shelf *p; top:	ntab = 0;	memset(q.dst, 0xff, Eaddrlen);	memset(q.src, 0, Eaddrlen);	putbe(q.etype, Etype, 2);	q.type = Tdiscover;	q.len = 0;	q.conn = 0;	q.seq = 1;		/* protocol extension */	netsend(&q, 60);	timewait(Iowait);	while((n = netget(&q, sizeof q)) >= 0){		if((n <= 0 && didtimeout()) || ntab == nelem(tab))			break;		if(n < 60 || q.len == 0 || q.type != Toffer)			continue;		q.data[q.len] = 0;		sh = strtok((char *)q.data, " \t");		if(sh == nil)			continue;		if(!nilea(ea) && memcmp(ea, q.src, Eaddrlen))			continue;		if(shelf != -1 && atoi(sh) != shelf)			continue;		other = strtok(nil, "\x1");		if(other == 0)			other = "";		if(host && strcmp(host, other))			continue;		p = tab + ntab++;		memcpy(p->ea, q.src, Eaddrlen);		p->major = atoi(sh);		p->name[0] = 0;		if(p->name)			snprint(p->name, sizeof p->name, "%s", other);		if(specific())			break; 		/* dedup; prefer hostnames */		for(i = 0; i < ntab-1; i++)			if(memcmp(p->ea, tab[i].ea, Eaddrlen) == 0){				if(strlen(p->name) > 0)					memcpy(tab+i, p, sizeof *p);				ntab--;				break;			}	}	alarm(0);	if(ntab == 0){		if(pflag)			goto top;		fprint(2, "none found.\n");		exits0("none found");	}	qsort(tab, ntab, sizeof tab[0], tcmp);} voidshowtable(void){	int i; 	for(i = 0; i < ntab; i++){		if(i > 0 && tcmp(tab - 1, tab) == 0)			continue;		print("%2d   %5d %E %s\n", i, tab[i].major, tab[i].ea, tab[i].name);	}} intpickone(void){	char buf[80];	int n, i; 	for(;;){		showtable();		print("[#qp]: ");		switch(n = read(0, buf, sizeof buf)){		case 1:			if(buf[0] == '\n')				continue;		case 2:			if(buf[0] == 'p'){				probe();				break;			}			if(buf[0] == 'q')		case 0:		case -1:				exits0(0);		}		if(buf[0] >= '0' && buf[0] <= '9'){			buf[n] = 0;			i = atoi(buf);			if(i >= 0 && i < ntab)				break;		}	}	return i;} voidsethdr(Pkt *p, int type){	memmove(p->dst, con->ea, Eaddrlen);	memset(p->src, 0, Eaddrlen);	putbe(p->etype, Etype, 2);	p->type = type;	p->len = 0;	p->conn = contag;} voidethclose(void){	static Pkt msg; 	sethdr(&msg, Treset);	timewait(Iowait);	netsend(&msg, 60);	alarm(0);	con = 0;} intethopen(int force){	int t, w;	Pkt tpk, rpk; 	contag = (getpid() >> 8) ^ (getpid() & 0xff);	sethdr(&tpk, Tinita);	sethdr(&rpk, 0);	t = time(0);	while(rpk.type != Tinitb){		netsend(&tpk, 60);		w = 30*Iowait;		if(t - time(0) > 6){			if(!force)				break;			w = Iowait;		}		timewait(w);		netget(&rpk, sizeof rpk);		alarm(0);	}	if(rpk.type != Tinitb)		return -1;	sethdr(&tpk, Tinitc);	netsend(&tpk, 60);	return 0;} charescape(void){	char buf[64];	int r; 	for(;;){		fprint(2, ">>> ");		buf[0] = '.';		rawoff();		r = read(0, buf, sizeof buf - 1);		rawon();		if(r == -1)			exits0("kbd: %r");		switch(buf[0]){		case 'i':		case 'q':		case '.':			return buf[0];		}		fprint(2, "	(q)uit, (i)nterrupt, (.)continue\n");	}} /* * this is a bit too agressive.  it really needs to replace only \n\r with \n. */static uchar crbuf[256]; voidnocrwrite(int fd, uchar *buf, int n){	int i, j, c; 	j = 0;	for(i = 0; i < n; i++){		if((c = buf[i]) == '\r')			continue;		crbuf[j++] = c;	}	write(fd, crbuf, j);} intdoloop(void){	uchar c, tseq, rseq, ea[Eaddrlen];	int l, unacked, set[2];	Pkt tpk, spk, ppk;	Mux *m; 	memmove(ea, con->ea, Eaddrlen);	tseq = 0;	rseq = -1;	set[0] = 0;	set[1] = fd;top:	if((m = mux(set)) == 0)		exits0("mux: %r");	unacked = 0;	sethdr(&ppk, Tdata);	for(;;) switch(muxread(m, &spk)){	case -1:		break;	case Ftimedout:		if(ppk.len > 0){			tpk = ppk;			tpk.seq = ++tseq;			unacked = tpk.len;			netsend(&tpk, Hdrsz+tpk.len);			muxtimeout(m, Timeout);			ppk.len = 0;		}else{			unacked = 0;			muxtimeout(m, 0);		}		break;	case Ftimeout:		netsend(&tpk, Hdrsz+unacked);		break;	case Fkbd:		c = spk.data[0];		if(c == esc) {			muxfree(m);			switch(escape()) {			case 'q':				tpk.len = 0;				tpk.type = Treset;

Lines 1–500 of 607.