|
@@ -1,16 +1,16 @@
|
|
|
/*
|
|
|
- * Copyright © Coraid, Inc. 2006, 2007. All Rights Reserved.
|
|
|
- * ethernet console for Coraid storage products.
|
|
|
- * simple command line version.
|
|
|
+ * cec — coraid ethernet console
|
|
|
+ * Copyright © Coraid, Inc. 2006-2008.
|
|
|
+ * All Rights Reserved.
|
|
|
*/
|
|
|
#include <u.h>
|
|
|
#include <libc.h>
|
|
|
-#include <ip.h> /* really! */
|
|
|
+#include <ip.h> /* really! */
|
|
|
#include <ctype.h>
|
|
|
#include "cec.h"
|
|
|
|
|
|
enum {
|
|
|
- Tinita = 0,
|
|
|
+ Tinita = 0,
|
|
|
Tinitb,
|
|
|
Tinitc,
|
|
|
Tdata,
|
|
@@ -19,40 +19,89 @@ enum {
|
|
|
Toffer,
|
|
|
Treset,
|
|
|
|
|
|
- HDRSIZ = 18,
|
|
|
- Eaddrlen = 6,
|
|
|
+ Hdrsz = 18,
|
|
|
+ Eaddrlen = 6,
|
|
|
};
|
|
|
|
|
|
-typedef struct Shelf Shelf;
|
|
|
-
|
|
|
-struct Shelf {
|
|
|
+typedef struct{
|
|
|
uchar ea[Eaddrlen];
|
|
|
- int shelfno;
|
|
|
- char *str;
|
|
|
-};
|
|
|
+ int major;
|
|
|
+ char name[28];
|
|
|
+} Shelf;
|
|
|
|
|
|
-void conn(int);
|
|
|
-void exits0(char *);
|
|
|
+int conn(int);
|
|
|
void gettingkilled(int);
|
|
|
int pickone(void);
|
|
|
void probe(void);
|
|
|
void sethdr(Pkt *, int);
|
|
|
int shelfidx(void);
|
|
|
|
|
|
-extern int errno;
|
|
|
-extern int fd; /* set in netopen */
|
|
|
-
|
|
|
+Shelf *con;
|
|
|
Shelf tab[1000];
|
|
|
+
|
|
|
+char *host;
|
|
|
+char *srv;
|
|
|
+char *svc;
|
|
|
+
|
|
|
+char pflag;
|
|
|
+
|
|
|
int ntab;
|
|
|
-uchar contag;
|
|
|
int shelf = -1;
|
|
|
-Shelf *connp;
|
|
|
-char esc = '';
|
|
|
+
|
|
|
+uchar bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
|
|
+uchar contag;
|
|
|
+uchar esc = '';
|
|
|
+uchar ea[Eaddrlen];
|
|
|
+uchar unsetea[Eaddrlen];
|
|
|
+
|
|
|
+extern int fd; /* set in netopen */
|
|
|
+
|
|
|
+void
|
|
|
+post(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);
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+dosrv(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);
|
|
|
+}
|
|
|
|
|
|
void
|
|
|
usage(void)
|
|
|
{
|
|
|
- fprint(2, "usage: cec [-d] [-e esc] [-s shelf] interface\n");
|
|
|
+ fprint(2, "usage: cec [-dp] [-c esc] [-e ea] [-h host] [-s shelf] "
|
|
|
+ "[-S srv] interface\n");
|
|
|
exits0("usage");
|
|
|
}
|
|
|
|
|
@@ -64,32 +113,54 @@ catch(void*, char *note)
|
|
|
noted(NDFLT);
|
|
|
}
|
|
|
|
|
|
+int
|
|
|
+nilea(uchar *ea)
|
|
|
+{
|
|
|
+ return memcmp(ea, unsetea, Eaddrlen) == 0;
|
|
|
+}
|
|
|
+
|
|
|
void
|
|
|
main(int argc, char **argv)
|
|
|
{
|
|
|
int r, n;
|
|
|
|
|
|
ARGBEGIN{
|
|
|
+ case 'S':
|
|
|
+ srv = EARGF(usage());
|
|
|
+ break;
|
|
|
+ case 'c':
|
|
|
+ esc = tolower(*(EARGF(usage()))) - 'a' + 1;
|
|
|
+ if(esc == 0 || esc >= ' ')
|
|
|
+ usage();
|
|
|
+ break;
|
|
|
case 'd':
|
|
|
debug++;
|
|
|
break;
|
|
|
- case 's':
|
|
|
- shelf = atoi(EARGF(usage()));
|
|
|
- break;
|
|
|
case 'e':
|
|
|
- esc = toupper(*(EARGF(usage()))) - 'A' + 1;
|
|
|
- if(esc <= 0 || esc >= ' ')
|
|
|
+ if(parseether(ea, EARGF(usage())) == -1)
|
|
|
usage();
|
|
|
+ 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(debug)
|
|
|
- fprint(2, "debug is on\n");
|
|
|
- if(argc != 1)
|
|
|
+ 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);
|
|
@@ -99,18 +170,25 @@ main(int argc, char **argv)
|
|
|
probe();
|
|
|
for(;;){
|
|
|
n = 0;
|
|
|
- if(shelf == -1)
|
|
|
+ if(shelf == -1 && host == 0 && nilea(ea))
|
|
|
n = pickone();
|
|
|
rawon();
|
|
|
conn(n);
|
|
|
rawoff();
|
|
|
- if(shelf != -1)
|
|
|
- exits0("shelf not found");
|
|
|
+ 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(shelf != -1 || host || !nilea(ea))
|
|
|
+ exits0("");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void
|
|
|
-timewait(int ms) /* arrange for a sig_alarm signal after `ms' milliseconds */
|
|
|
+timewait(int ms)
|
|
|
{
|
|
|
alarm(ms);
|
|
|
}
|
|
@@ -151,54 +229,73 @@ ntohs(int h)
|
|
|
return p[0] << 8 | p[1];
|
|
|
}
|
|
|
|
|
|
+int
|
|
|
+tcmp(void *a, void *b)
|
|
|
+{
|
|
|
+ Shelf *s, *t;
|
|
|
+ int d;
|
|
|
+
|
|
|
+ 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;
|
|
|
+}
|
|
|
+
|
|
|
void
|
|
|
probe(void)
|
|
|
{
|
|
|
- int n;
|
|
|
char *sh, *other;
|
|
|
- uchar buf[1500];
|
|
|
+ int n;
|
|
|
Pkt q;
|
|
|
Shelf *p;
|
|
|
|
|
|
- ntab = 0;
|
|
|
- memset(buf, 0xff, Eaddrlen);
|
|
|
- memset(q.dst, 0xff, Eaddrlen);
|
|
|
- memset(q.src, 0, Eaddrlen);
|
|
|
- q.etype = htons(Etype);
|
|
|
- q.type = Tdiscover;
|
|
|
- q.len = 0;
|
|
|
- q.conn = 0;
|
|
|
- q.seq = 0;
|
|
|
- netsend(&q, 60);
|
|
|
-// fprint(2, "Probing for shelves ... ");
|
|
|
- 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(shelf != -1 && atoi(sh) != shelf)
|
|
|
- continue;
|
|
|
- other = strtok(nil, "\x1");
|
|
|
- p = tab + ntab++;
|
|
|
- memcpy(p->ea, q.src, Eaddrlen);
|
|
|
- p->shelfno = atoi(sh);
|
|
|
- p->str = other? strdup(other): "";
|
|
|
- if(shelf != -1) {
|
|
|
- fprint(2, "shelf %d found.\n", shelf);
|
|
|
- break;
|
|
|
+ do {
|
|
|
+ ntab = 0;
|
|
|
+ memset(q.dst, 0xff, Eaddrlen);
|
|
|
+ memset(q.src, 0, Eaddrlen);
|
|
|
+ q.etype = htons(Etype);
|
|
|
+ q.type = Tdiscover;
|
|
|
+ q.len = 0;
|
|
|
+ q.conn = 0;
|
|
|
+ q.seq = 0;
|
|
|
+ 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) != 0)
|
|
|
+ continue;
|
|
|
+ if(shelf != -1 && atoi(sh) != shelf)
|
|
|
+ continue;
|
|
|
+ other = strtok(nil, "\x1");
|
|
|
+ if(other == 0)
|
|
|
+ other = "";
|
|
|
+ if(host && strcmp(host, other) != 0)
|
|
|
+ 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);
|
|
|
}
|
|
|
- }
|
|
|
- alarm(0);
|
|
|
- if(ntab == 0) {
|
|
|
+ alarm(0);
|
|
|
+ } while (ntab == 0 && pflag);
|
|
|
+ if(ntab == 0){
|
|
|
fprint(2, "none found.\n");
|
|
|
exits0("none found");
|
|
|
}
|
|
|
-// fprint(2, "done.\n");
|
|
|
+ qsort(tab, ntab, sizeof tab[0], tcmp);
|
|
|
}
|
|
|
|
|
|
void
|
|
@@ -207,8 +304,7 @@ showtable(void)
|
|
|
int i;
|
|
|
|
|
|
for(i = 0; i < ntab; i++)
|
|
|
- print("%2d %5d %E %s\n", i,
|
|
|
- tab[i].shelfno, tab[i].ea, tab[i].str);
|
|
|
+ print("%2d %5d %E %s\n", i, tab[i].major, tab[i].ea, tab[i].name);
|
|
|
}
|
|
|
|
|
|
int
|
|
@@ -231,10 +327,11 @@ pickone(void)
|
|
|
break;
|
|
|
}
|
|
|
if(buf[0] == 'q')
|
|
|
- /* fall through */
|
|
|
+ /* fall through */
|
|
|
case 0:
|
|
|
case -1:
|
|
|
exits0(0);
|
|
|
+ break;
|
|
|
}
|
|
|
if(isdigit(buf[0])){
|
|
|
buf[n] = 0;
|
|
@@ -249,7 +346,7 @@ pickone(void)
|
|
|
void
|
|
|
sethdr(Pkt *pp, int type)
|
|
|
{
|
|
|
- memmove(pp->dst, connp->ea, Eaddrlen);
|
|
|
+ memmove(pp->dst, con->ea, Eaddrlen);
|
|
|
memset(pp->src, 0, Eaddrlen);
|
|
|
pp->etype = htons(Etype);
|
|
|
pp->type = type;
|
|
@@ -266,7 +363,7 @@ ethclose(void)
|
|
|
timewait(Iowait);
|
|
|
netsend(&msg, 60);
|
|
|
alarm(0);
|
|
|
- connp = 0;
|
|
|
+ con = 0;
|
|
|
}
|
|
|
|
|
|
int
|
|
@@ -297,13 +394,16 @@ char
|
|
|
escape(void)
|
|
|
{
|
|
|
char buf[64];
|
|
|
+ int r;
|
|
|
|
|
|
for(;;){
|
|
|
fprint(2, ">>> ");
|
|
|
buf[0] = '.';
|
|
|
rawoff();
|
|
|
- read(0, buf, sizeof buf-1);
|
|
|
+ r = read(0, buf, sizeof buf - 1);
|
|
|
rawon();
|
|
|
+ if(r == -1)
|
|
|
+ exits0("kbd: %r");
|
|
|
switch(buf[0]){
|
|
|
case 'i':
|
|
|
case 'q':
|
|
@@ -315,9 +415,9 @@ escape(void)
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * this is a bit too agressive. it really needs to replace only \n\r with \n.
|
|
|
+ * this is a bit too aggressive. it really needs to replace only \n\r with \n.
|
|
|
*/
|
|
|
-static uchar crbuf[1514];
|
|
|
+static uchar crbuf[256];
|
|
|
|
|
|
void
|
|
|
nocrwrite(int fd, uchar *buf, int n)
|
|
@@ -325,11 +425,9 @@ nocrwrite(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;
|
|
|
- }
|
|
|
+ for(i = 0; i < n; i++)
|
|
|
+ if((c = buf[i]) != '\r')
|
|
|
+ crbuf[j++] = c;
|
|
|
write(fd, crbuf, j);
|
|
|
}
|
|
|
|
|
@@ -339,10 +437,10 @@ doloop(void)
|
|
|
int unacked, retries, set[2];
|
|
|
uchar c, tseq, rseq;
|
|
|
uchar ea[Eaddrlen];
|
|
|
- Mux * m;
|
|
|
Pkt tpk, spk;
|
|
|
+ Mux *m;
|
|
|
|
|
|
- memmove(ea, connp->ea, Eaddrlen);
|
|
|
+ memmove(ea, con->ea, Eaddrlen);
|
|
|
retries = 0;
|
|
|
unacked = 0;
|
|
|
tseq = 0;
|
|
@@ -362,9 +460,9 @@ top:
|
|
|
muxfree(m);
|
|
|
return 0;
|
|
|
}
|
|
|
- netsend(&tpk, HDRSIZ + unacked);
|
|
|
+ netsend(&tpk, Hdrsz + unacked);
|
|
|
break;
|
|
|
- case 0:
|
|
|
+ case Fkbd:
|
|
|
c = spk.data[0];
|
|
|
if (c == esc) {
|
|
|
muxfree(m);
|
|
@@ -388,13 +486,14 @@ top:
|
|
|
tpk.seq = ++tseq;
|
|
|
unacked = spk.len;
|
|
|
retries = 2;
|
|
|
- netsend(&tpk, HDRSIZ + spk.len);
|
|
|
+ netsend(&tpk, Hdrsz + spk.len);
|
|
|
break;
|
|
|
- default:
|
|
|
+ case Fcec:
|
|
|
if (memcmp(spk.src, ea, Eaddrlen) != 0 ||
|
|
|
ntohs(spk.etype) != Etype)
|
|
|
continue;
|
|
|
- if (spk.type == Toffer) {
|
|
|
+ if (spk.type == Toffer &&
|
|
|
+ memcmp(spk.dst, bcast, Eaddrlen) != 0) {
|
|
|
muxfree(m);
|
|
|
return 1;
|
|
|
}
|
|
@@ -405,8 +504,6 @@ top:
|
|
|
if (spk.seq == rseq)
|
|
|
break;
|
|
|
nocrwrite(1, spk.data, spk.len);
|
|
|
- if (0)
|
|
|
- write(1, spk.data, spk.len);
|
|
|
memmove(spk.dst, spk.src, Eaddrlen);
|
|
|
memset(spk.src, 0, Eaddrlen);
|
|
|
spk.type = Tack;
|
|
@@ -422,28 +519,40 @@ top:
|
|
|
muxfree(m);
|
|
|
return 1;
|
|
|
}
|
|
|
+ break;
|
|
|
+ case Ffatal:
|
|
|
+ muxfree(m);
|
|
|
+ fprint(2, "kbd read error\n");
|
|
|
+ exits0("fatal");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void
|
|
|
+int
|
|
|
conn(int n)
|
|
|
{
|
|
|
- do {
|
|
|
- if(connp)
|
|
|
+ int r;
|
|
|
+
|
|
|
+ for(;;){
|
|
|
+ if(con)
|
|
|
ethclose();
|
|
|
- connp = &tab[n];
|
|
|
+ con = tab + n;
|
|
|
if(ethopen() < 0){
|
|
|
- fprint(2, "connection failed.\n");
|
|
|
- return;
|
|
|
+ fprint(2, "connection failed\n");
|
|
|
+ return 0;
|
|
|
}
|
|
|
- } while(doloop());
|
|
|
+ r = doloop();
|
|
|
+ if(r <= 0)
|
|
|
+ return r;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
void
|
|
|
exits0(char *s)
|
|
|
{
|
|
|
- if(connp != nil)
|
|
|
+ if(con != nil)
|
|
|
ethclose();
|
|
|
rawoff();
|
|
|
+ if(svc != nil)
|
|
|
+ remove(svc);
|
|
|
exits(s);
|
|
|
}
|