bucket 'o changes, synched after the fact. i didn't realize this was in the dist. Notes: Wed Mar 19 15:08:07 EDT 2008 geoff Please (re)read style(6) and edit your code to conform, then resubmit this patch. Thanks. Reference: /n/sources/patch/sorry/cecupd Date: Wed Mar 12 16:30:55 CET 2008 Signed-off-by: quanstro@quanstro.net Reviewed-by: geoff --- /sys/src/cmd/cec/LICENSE Wed Mar 12 16:26:40 2008 +++ /sys/src/cmd/cec/LICENSE Wed Mar 12 16:26:39 2008 @@ -1,6 +1,6 @@ The FreeBSD License -Copyright 2006 Coraid, Inc. All rights reserved. +Copyright © 2006-8 Coraid, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -14,19 +14,18 @@ disclaimer in the documentation and/or other materials provided with the distribution. -THIS SOFTWARE IS PROVIDED BY THE BRANTLEY COILE COMPANY ``AS IS'' AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE BRANTLEY COILE COMPANY -OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +This software is provided by Coraid “as is” and any express or +implied warranties, including, but not limited to, the implied +warranties of merchantability and fitness for a particular purpose are +disclaimed. In no event shall Coraid or contributors be liable for +any direct, indirect, incidental, special, exemplary, or consequential +damages (including, but not limited to, procurement of substitute +goods or services; loss of use, data, or profits; or business +interruption) however caused and on any theory of liability, whether +in contract, strict liability, or tort (including negligence or +otherwise) arising in any way out of the use of this software, even if +advised of the possibility of such damage. The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing -official policies, either expressed or implied, of the Brantley Coile -Company. +official policies, either expressed or implied, of Coraid. --- /sys/src/cmd/cec/Protocol Wed Mar 12 16:26:45 2008 +++ /sys/src/cmd/cec/Protocol Wed Mar 12 16:26:44 2008 @@ -68,7 +68,7 @@ 3. Initializing a connection. Tinit[abc] A connection is initialized by the following conversation: In addition -to the fields set for the Tdiscover packet, he client sends a packet +to the fields set for the Tdiscover packet, the client sends a packet of type Tinita with the conntag of its choice. The server responds to Tinita with a packet of type Tinitb. And finally the client sents a Tinitc packet back to the server, completing the connection. @@ -78,7 +78,7 @@ Data is sent from the client to the console server with the Tdata packet. The seq field is incremented for each data packet sent. Thus data packets may be transmitted if lost. The data is whatever data the client has to -send to the server, up to 1500 bytes. Typically, however, each keystroke +send to the server, up to 255 bytes. Typically, however, each keystroke is sent in a seperate packet. The len field is the length of the data. --- /sys/src/cmd/cec/cec.c Wed Mar 12 16:26:52 2008 +++ /sys/src/cmd/cec/cec.c Wed Mar 12 16:26:51 2008 @@ -1,11 +1,10 @@ /* - * Copyright © Coraid, Inc. 2006, 2007. All Rights Reserved. - * ethernet console for Coraid storage products. - * simple command line version. - */ + * cec -- simple ethernet console + * Copyright © Coraid, Inc. 2006—2008. All Rights Reserved. +*/ #include #include -#include /* really! */ +#include /* really! */ #include #include "cec.h" @@ -18,41 +17,40 @@ Tdiscover, Toffer, Treset, - - HDRSIZ = 18, + + Hdrsz = 18, Eaddrlen = 6, }; -typedef struct Shelf Shelf; - -struct Shelf { - uchar ea[Eaddrlen]; +typedef struct{ + uchar ea[6]; int shelfno; char *str; -}; +}Shelf; void conn(int); -void exits0(char *); 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 tab[1000]; -int ntab; +Shelf *connp; uchar contag; +uchar ea[6]; +char *host; +int ntab; +char pflag; int shelf = -1; -Shelf *connp; +Shelf tab[1000]; +uchar unsetea[6]; char esc = ''; +extern int fd; /* set in netopen */ void usage(void) { - fprint(2, "usage: cec [-d] [-e esc] [-s shelf] interface\n"); + fprint(2, "usage: cec [-dp] [-c esc] [-e ea] [-s shelf] [-h host] interface\n"); exits0("usage"); } @@ -64,31 +62,47 @@ noted(NDFLT); } +int +nilea(uchar *ea) +{ + return memcmp(ea, unsetea, 6) == 0; +} + void main(int argc, char **argv) { int r, n; ARGBEGIN{ + case 'c': + esc = toupper(*(EARGF(usage()))) - 'A' + 1; + if(esc < 1 || esc > 0x19) + 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); r = netopen(*argv); if(r == -1){ @@ -99,18 +113,25 @@ 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,17 +172,32 @@ return p[0] << 8 | p[1]; } +int +tcmp(void *a, void *b) +{ + Shelf *s, *t; + int d; + + s = a; + t = b; + d = s->shelfno-t->shelfno; + if(d == 0) + d = strcmp(s->str, t->str); + if(d == 0) + d = memcmp(s->ea, t->ea, 6); + return d; +} + void probe(void) { - int n; char *sh, *other; - uchar buf[1500]; + int n; Pkt q; Shelf *p; +top: ntab = 0; - memset(buf, 0xff, Eaddrlen); memset(q.dst, 0xff, Eaddrlen); memset(q.src, 0, Eaddrlen); q.etype = htons(Etype); @@ -170,9 +206,8 @@ q.conn = 0; q.seq = 0; netsend(&q, 60); -// fprint(2, "Probing for shelves ... "); timewait(Iowait); - while((n = netget(&q, sizeof q)) >= 0) { + while((n = netget(&q, sizeof q)) >= 0){ if((n <= 0 && didtimeout()) || ntab == nelem(tab)) break; if(n < 60 || q.len == 0 || q.type != Toffer) @@ -181,24 +216,28 @@ 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->shelfno = atoi(sh); p->str = other? strdup(other): ""; - if(shelf != -1) { - fprint(2, "shelf %d found.\n", shelf); - break; - } } alarm(0); if(ntab == 0) { + if(pflag) + goto top; fprint(2, "none found.\n"); exits0("none found"); } -// fprint(2, "done.\n"); + qsort(tab, ntab, sizeof tab[0], tcmp); } void @@ -207,8 +246,7 @@ 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].shelfno, tab[i].ea, tab[i].str); } int @@ -224,14 +262,12 @@ case 1: if(buf[0] == '\n') continue; - /* fall through */ case 2: if(buf[0] == 'p'){ probe(); break; } if(buf[0] == 'q') - /* fall through */ case 0: case -1: exits0(0); @@ -317,7 +353,7 @@ /* * this is a bit too agressive. 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) @@ -339,8 +375,8 @@ int unacked, retries, set[2]; uchar c, tseq, rseq; uchar ea[Eaddrlen]; - Mux * m; Pkt tpk, spk; + Mux *m; memmove(ea, connp->ea, Eaddrlen); retries = 0; @@ -350,79 +386,76 @@ set[0] = 0; set[1] = fd; top: - if ((m = mux(set)) == 0) + if((m = mux(set)) == 0) exits0("mux: %r"); - for (; ; ) - switch (muxread(m, &spk)) { - case -1: - if (unacked == 0) - break; - if (retries-- == 0) { - fprint(2, "Connection timed out\n"); - muxfree(m); + for(;;) switch(muxread(m, &spk)){ + case -1: + if(unacked == 0) + break; + if(retries-- == 0){ + fprint(2, "Connection timed out\n"); + muxfree(m); + return 0; + } + netsend(&tpk, Hdrsz+unacked); + break; + case 0: + c = spk.data[0]; + if(c == esc) { + muxfree(m); + switch(escape()) { + case 'q': + tpk.len = 0; + tpk.type = Treset; + netsend(&tpk, 60); return 0; + case '.': + goto top; + case 'i': + if((m = mux(set)) == 0) + exits0("mux: %r"); + break; } - netsend(&tpk, HDRSIZ + unacked); + } + sethdr(&tpk, Tdata); + memcpy(tpk.data, spk.data, spk.len); + tpk.len = spk.len; + tpk.seq = ++tseq; + unacked = spk.len; + retries = 2; + netsend(&tpk, Hdrsz+spk.len); + break; + default: + if(memcmp(spk.src, ea, 6) != 0 || ntohs(spk.etype) != Etype) + continue; + if(spk.type == Toffer){ + muxfree(m); + return 1; + } + if(spk.conn != contag) + continue; + switch(spk.type){ + case Tdata: + if(spk.seq == rseq) + break; + nocrwrite(1, spk.data, spk.len); +// write(1, spk.data, spk.len); + memmove(spk.dst, spk.src, 6); + memset(spk.src, 0, 6); + spk.type = Tack; + spk.len = 0; + rseq = spk.seq; + netsend(&spk, 60); break; - case 0: - c = spk.data[0]; - if (c == esc) { - muxfree(m); - switch (escape()) { - case 'q': - tpk.len = 0; - tpk.type = Treset; - netsend(&tpk, 60); - return 0; - case '.': - goto top; - case 'i': - if ((m = mux(set)) == 0) - exits0("mux: %r"); - break; - } - } - sethdr(&tpk, Tdata); - memcpy(tpk.data, spk.data, spk.len); - tpk.len = spk.len; - tpk.seq = ++tseq; - unacked = spk.len; - retries = 2; - netsend(&tpk, HDRSIZ + spk.len); + case Tack: + if(spk.seq == tseq) + unacked = 0; break; - default: - if (memcmp(spk.src, ea, Eaddrlen) != 0 || - ntohs(spk.etype) != Etype) - continue; - if (spk.type == Toffer) { - muxfree(m); - return 1; - } - if (spk.conn != contag) - continue; - switch (spk.type) { - case Tdata: - 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; - spk.len = 0; - rseq = spk.seq; - netsend(&spk, 60); - break; - case Tack: - if (spk.seq == tseq) - unacked = 0; - break; - case Treset: - muxfree(m); - return 1; - } + case Treset: + muxfree(m); + return 1; } + } } void --- /sys/src/cmd/cec/cec.h Wed Mar 12 16:27:00 2008 +++ /sys/src/cmd/cec/cec.h Wed Mar 12 16:26:58 2008 @@ -1,5 +1,3 @@ -/* cec.h: definitions for cec */ - typedef struct { uchar dst[6]; uchar src[6]; @@ -20,21 +18,21 @@ typedef struct Mux Mux; #pragma incomplete Mux; -enum { +enum{ Iowait = 2000, Etype = 0xbcbc, }; int debug; -Mux *mux(int fd[2]); -int muxread(Mux*, Pkt*); -void muxfree(Mux*); - -int netopen(char *name); -int netsend(void *, int); -int netget(void *, int); - -void rawon(void); -void rawoff(void); -void dump(uchar*, int); -void exits0(char*); +Mux *mux(int fd[2]); +void muxfree(Mux*); +int muxread(Mux*, Pkt*); + +int netget(void *, int); +int netopen(char *name); +int netsend(void *, int); + +void dump(uchar*, int); +void exits0(char*); +void rawoff(void); +void rawon(void); --- /sys/src/cmd/cec/mux.c Wed Mar 12 16:27:19 2008 +++ /sys/src/cmd/cec/mux.c Wed Mar 12 16:27:17 2008 @@ -1,4 +1,3 @@ -/* Copyright © Coraid, Inc. 2006. All rights reserved. */ #include #include #include "cec.h" --- /sys/src/cmd/cec/plan9.c Wed Mar 12 16:27:31 2008 +++ /sys/src/cmd/cec/plan9.c Wed Mar 12 16:27:29 2008 @@ -1,4 +1,3 @@ -/* Copyright © Coraid, Inc. 2006. All rights reserved. */ #include #include #include "cec.h" @@ -84,6 +83,7 @@ dump(p, len); } if (len < 60) - len = 60; /* mintu */ + len = 60; return write(fd, p, len); } + --- /sys/src/cmd/cec/utils.c Wed Mar 12 16:27:44 2008 +++ /sys/src/cmd/cec/utils.c Wed Mar 12 16:27:43 2008 @@ -1,4 +1,3 @@ -/* Copyright Coraid, Inc. 2006. All Rights Reserved */ #include #include #include "cec.h" --- /sys/man/8/cec Wed Mar 12 16:27:59 2008 +++ /sys/man/8/cec Wed Mar 12 16:27:58 2008 @@ -1,44 +1,57 @@ -.TH CEC 8 +.TH cec 8 .SH NAME cec \- Coraid Ethernet Console .SH SYNOPSIS .B cec [ -.B -d +.B -dp +] [ +.B -c +.I esc ] [ +.B -e +.I ea +] [ +.B -h +.I host +[ .B -s .I shelf ] [ -.B -e -.I esc +.B interface ] -.I interface .SH DESCRIPTION The .I cec -command uses raw Ethernet frames to connect to a CEC -server for console access. All clients share the same session. Coraid -appliances are currently the only CEC servers. +command uses raw ethernet to connect to a CEC +server for console access. All clients share the same session. +Coraid appliances and Coraid Plan 9 kernels can currently be +CEC servers. .PP A .I cec process starts by probing the specified network interface -(e.g., -.LR /net/ether0 ) -for available CEC servers. If the shelf address of the server is -specified with the +for available CEC servers. The default is +.I /net/ether0 . +If the server is specified with the +.BR -b , +.BR -h , +or +.B -s .B -s flag, the connection will proceed immediately upon discovery of the first CEC server -with this shelf address. Otherwise, a selection prompt -will be displayed showing the discovered CEC servers -available for communication. If no servers are discovered, +with the specified address. Otherwise, a selection prompt +will be displayed showing the discovered CEC servers +available for communication. Unless the +.B -p +flag is specified, .I cec -exits. +exits if no matching servers are found. .IP .EX -0 5 003048865f1e shelf5 -[#qp]: + 0 5 003048865f1e shelf5 + [#qp]: .EE .LP The selection prompt accepts @@ -56,43 +69,58 @@ .PP Note the selection number is not the shelf address but the .IR cec -generated -ID number printed in the leftmost column. -.PP -Once connected to a CEC server, entering the escape sequence +sequence number printed in the leftmost column. + +Once connected to a cec server, entering the escape sequence will drop the user into an escape prompt where the user may -type -.L q -to quit the connection, -.L i -to send the escape sequence -across the connection, or -.L . -to continue the connection. +type 'q' to quit the connection, 'i' to send the escape sequence +across the connection, or '.' to continue the connection. The escape sequence is printed on connection. -.PP -If the -.B -s -option is used, -.I cec -will exit upon closing the connection. -Otherwise, -.I cec -will return to the selection prompt upon connection close. .SS Options .TP 1i .B -d Output debugging information. .TP -.BI -s " shelf" -Connect to the server at shelf address -.IR shelf . -.TP -.BI -e " esc" +.BI -c " esc" Set the escape caracter to -.BI control - +.BI ctl - .IR esc . The default setting is -.BR control -\e. +.BR ctl -\e. +.TP +.BI -e "ea" +Connect to the server with ethernet address +.IR ea . This option implies +.IR -p . +.TP +.BI -h "host" +Connect to the server named +.IR host . +Note this name may not be the same as the value of +.LR /dev/sysname . +.TP +.B -p +Persistence. Continue trying to connect even if +there are no matching servers. This is useful when +connecting to a cpu server before it boots. +.TP +.BI -s " shelf" +Connect to the server at shelf address +.IR shelf . +.SH NOTES +If the +.BI -e , +.BI -s , +or +.B -h +flags are used cec will exit upon closing the connection. +Otherwise, cec will return to the selection prompt upon connection +close. +.SH SEE ALSO +.IR cec (3) . .SH BUGS The CEC protocol should be integrated with the console server. The arbitration between the keyboard and network is suboptimal. +.PP +Early boot information and very late crash information from servers +may be lost due to timing quirks.