restore the rather unnice ru*.h to support telnet control messages. this is helpful when serving to unix systems. Reference: /n/atom/patch/applied2013/consignals Date: Wed Jun 19 22:01:51 CES 2013 Signed-off-by: quanstro@quanstro.net --- /sys/src/cmd/con/con.c Wed Jun 19 22:01:09 2013 +++ /sys/src/cmd/con/con.c Wed Jun 19 22:01:09 2013 @@ -1,11 +1,17 @@ #include #include +#include "rustream.h" +#include "ruttyio.h" +#include "rusignal.h" +#include "rufilio.h" + int debug; /* true if debugging */ int ctl = -1; /* control fd (for break's) */ int raw; /* true if raw is on */ int consctl = -1; /* control fd for cons */ int ttypid; /* pid's if the 2 processes (used to kill them) */ +int msgfd = -1; /* mesgld file descriptor (for signals to be written to) */ int outfd = 1; /* local output file descriptor */ int cooked; /* non-zero forces cooked mode */ int returns; /* non-zero forces carriage returns not to be filtered out */ @@ -19,9 +25,9 @@ int baud; int notkbd; int nltocr; /* translate kbd nl to cr and vice versa */ +int esc = 0x1c; -static char *srv; - +typedef struct Msg Msg; #define MAXMSG (2*8192) int dodial(char*, char*, char*); @@ -30,10 +36,16 @@ long iread(int, void*, int); long iwrite(int, void*, int); int menu(int); +void msgfromkbd(int); +void msgfromnet(int); +int msgwrite(int, void*, int); void notifyf(void*, char*); void pass(int, int, int); void rawoff(void); void rawon(void); +int readupto(int, char*, int); +int sendctl(int, int); +int sendctl1(int, int, int); void stdcon(int); char* system(int, char*); void dosystem(int, char*); @@ -50,8 +62,7 @@ void usage(void) { - punt("usage: con [-CdnrRsTv] [-b baud] [-l [user]] [-c cmd] [-S svc] " - "net!host[!service]"); + punt("usage: con [-CdnrRsTv] [-e esc] [-b baud] [-l [user]] [-c cmd] net!host[!service]"); } void @@ -65,19 +76,19 @@ case 'b': baud = atoi(EARGF(usage())); break; - case 'C': - cooked = 1; - break; - case 'c': - cmd = EARGF(usage()); - break; case 'd': debug = 1; break; + case 'e': + esc = *EARGF(usage()); + if(esc >= 'a' && esc <= 'z') + esc -= 0x20; + esc -= '@'; + break; case 'l': limited = 1; if(argv[1] != nil && argv[1][0] != '-') - remuser = EARGF(usage()); + remuser = ARGF(); break; case 'n': notkbd = 1; @@ -85,21 +96,24 @@ case 'r': returns = 0; break; - case 's': - strip = 1; - break; - case 'S': - srv = EARGF(usage()); - break; case 'R': nltocr = 1; break; case 'T': crtonl = 1; break; + case 'C': + cooked = 1; + break; + case 'c': + cmd = ARGF(); + break; case 'v': verbose = 1; break; + case 's': + strip = 1; + break; default: usage(); }ARGEND @@ -225,10 +239,8 @@ snprint(cname, sizeof cname, "%sctl", dest); ctl = open(cname, ORDWR); if (baud > 0) { - if(ctl >= 0){ - /* set speed and use fifos if available */ - fprint(ctl, "b%d i1", baud); - } + if(ctl >= 0) + fprint(ctl, "b%d", baud); else fprint(2, "con: cannot open %s: %r\n", cname); } @@ -335,11 +347,16 @@ return -1; case 'i': buf[0] = 0x1c; - write(net, buf, 1); + if(msgfd <= 0) + write(net, buf, 1); + else + sendctl1(msgfd, M_SIGNAL, SIGQUIT); done = 1; break; case 'b': - if(ctl >= 0) + if(msgfd >= 0) + sendctl(msgfd, M_BREAK); + else if(ctl >= 0) write(ctl, "k", 1); done = 1; break; @@ -362,21 +379,6 @@ return 0; } -void -post(char *srv, int fd) -{ - int f; - char buf[32]; - - f = create(srv, OWRITE /* |ORCLOSE */ , 0666); - if(f < 0) - 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); -} - /* * the real work. two processes pass bytes back and forth between the * terminal and the network. @@ -385,23 +387,7 @@ stdcon(int net) { int netpid; - int p[2]; - char *svc; - svc = nil; - if (srv) { - if(pipe(p) < 0) - sysfatal("pipe: %r"); - if (srv[0] != '/') - svc = smprint("/srv/%s", srv); - else - svc = srv; - post(svc, p[0]); - close(p[0]); - dup(p[1], 0); - dup(p[1], 1); - /* pipe is now std in & out */ - } ttypid = getpid(); switch(netpid = rfork(RFMEM|RFPROC)){ case -1: @@ -410,18 +396,13 @@ case 0: notify(notifyf); fromnet(net); - if (svc) - remove(svc); postnote(PNPROC, ttypid, "die yankee dog"); exits(0); default: notify(notifyf); fromkbd(net); - if (svc) - remove(svc); if(notkbd) - for(;;) - sleep(0); + for(;;)sleep(0); postnote(PNPROC, netpid, "die yankee dog"); exits(0); } @@ -457,7 +438,7 @@ return; } else eofs = 0; - if(n && memchr(buf, 0x1c, n)){ + if(n && memchr(buf, esc, n)){ if(menu(net) < 0) return; }else{ @@ -606,9 +587,15 @@ break; default: close(pfd[0]); - while((n = read(pfd[1], buf, sizeof(buf))) > 0) - if(write(fd, buf, n) != n) - break; + while((n = read(pfd[1], buf, sizeof(buf))) > 0){ + if(msgfd >= 0){ + if(msgwrite(fd, buf, n) != n) + break; + } else { + if(write(fd, buf, n) != n) + break; + } + } p = waitpid(); outfd = 1; close(pfd[1]); @@ -681,3 +668,261 @@ return n; return m; } + +/* + * The rest is to support the V10 mesgld protocol. + */ + +/* + * network orderings + */ +#define get2byte(p) ((p)[0] + ((p)[1]<<8)) +#define get4byte(p) ((p)[0] + ((p)[1]<<8) + ((p)[2]<<16) + ((p)[3]<<24)) +#define put2byte(p, i) ((p)[0]=(i), (p)[1]=(i)>>8) +#define put4byte(p, i) ((p)[0]=(i), (p)[1]=(i)>>8, (p)[2]=(i)>>16, (p)[3]=(i)>>24) + +/* + * tty parameters + */ +int sgflags = ECHO; + +/* + * a mesgld message + */ +struct Msg { + struct mesg h; + char b[MAXMSG]; +}; + + +/* + * send an empty mesgld message + */ +int +sendctl(int net, int type) +{ + Msg m; + + m.h.type = type; + m.h.magic = MSGMAGIC; + put2byte(m.h.size, 0); + if(iwrite(net, &m, sizeof(struct mesg)) != sizeof(struct mesg)) + return -1; + return 0; +} + +/* + * send a one byte mesgld message + */ +int +sendctl1(int net, int type, int parm) +{ + Msg m; + + m.h.type = type; + m.h.magic = MSGMAGIC; + m.b[0] = parm; + put2byte(m.h.size, 1); + if(iwrite(net, &m, sizeof(struct mesg)+1) != sizeof(struct mesg)+1) + return -1; + return 0; +} + +/* + * read n bytes. return -1 if it fails, 0 otherwise. + */ +int +readupto(int from, char *a, int len) +{ + int n; + + while(len > 0){ + n = iread(from, a, len); + if(n < 0) + return -1; + a += n; + len -= n; + } + return 0; +} + +/* + * Decode a mesgld message from the network + */ +void +msgfromnet(int net) +{ + ulong com; + struct stioctl *io; + struct sgttyb *sg; + struct ttydevb *td; + struct tchars *tc; + int len; + Msg m; + + for(;;){ + /* get a complete mesgld message */ + if(readupto(net, (char*)&m.h, sizeof(struct mesg)) < 0) + break; + if(m.h.magic != MSGMAGIC){ + fprint(2, "con: bad message magic 0x%ux\n", m.h.magic); + break; + } + len = get2byte(m.h.size); + if(len > sizeof(m.b)){ + len = sizeof(m.b); + fprint(2, "con: mesgld message too long\n"); + } + if(len && readupto(net, m.b, len) < 0) + break; + + /* decode */ + switch(m.h.type){ + case M_HANGUP: + if(debug) + fprint(2, "M_HANGUP\n"); + return; + case M_DATA: + if(debug) + fprint(2, "M_DATA %d bytes\n", len); + if(iwrite(outfd, m.b, len) != len){ + if(outfd == 1) + return; + outfd = 1; + if(iwrite(outfd, m.b, len) != len) + return; + } + continue; + case M_IOCTL: + break; + default: + /* ignore */ + if(debug) + fprint(2, "con: unknown message\n"); + continue; + } + + /* + * answer an ioctl + */ + io = (struct stioctl *)m.b; + com = get4byte(io->com); + if(debug) + fprint(2, "M_IOCTL %lud\n", com); + switch(com){ + case FIOLOOKLD: + put4byte(io->data, tty_ld); + len = 0; + break; + case TIOCGETP: + sg = (struct sgttyb *)io->data; + sg->sg_ispeed = sg->sg_ospeed = B9600; + sg->sg_erase = 0010; /* back space */ + sg->sg_kill = 0025; /* CNTL U */ + put2byte(sg->sg_flags, sgflags); + len = sizeof(struct sgttyb); + break; + case TIOCSETN: + case TIOCSETP: + sg = (struct sgttyb *)io->data; + sgflags = get2byte(sg->sg_flags); + if((sgflags&(RAW|CBREAK)) || !(sgflags&ECHO)) + rawon(); + else + rawoff(); + len = 0; + break; + case TIOCGETC: + tc = (struct tchars *)io->data; + tc->t_intrc = 0177; + tc->t_quitc = 0034; + tc->t_startc = 0; + tc->t_stopc = 0; + tc->t_eofc = 0004; + tc->t_brkc = 0; + len = sizeof(struct tchars); + break; + case TIOCSETC: + len = 0; + break; + case TIOCGDEV: + td = (struct ttydevb *)io->data; + td->ispeed = td->ospeed = B9600; + put2byte(td->flags, 0); + len = sizeof(struct ttydevb); + break; + case TIOCSDEV: + len = 0; + break; + default: + /* + * unimplemented + */ + m.b[len] = 0; + if(sendctl(net, M_IOCNAK) < 0) + return; + continue; + } + + /* + * acknowledge + */ + m.h.type = M_IOCACK; + m.h.magic = MSGMAGIC; + len += 4; + put2byte(m.h.size, len); + len += sizeof(struct mesg); + if(iwrite(net, &m, len) != len) + return; + } +} + +/* + * Read the keyboard, convert to mesgld messages, and write it to the network. + * '^\' gets us into the menu. + */ +void +msgfromkbd(int net) +{ + long n; + char buf[MAXMSG]; + + for(;;){ + n = iread(0, buf, sizeof(buf)); + if(n < 0) + return; + if(n && memchr(buf, 0034, n)){ + if(menu(net) < 0) + return; + } else { + if(msgwrite(net, buf, n) != n) + return; + } + } +} + +int +msgwrite(int fd, void *buf, int len) +{ + Msg m; + int n; + + n = len; + memmove(m.b, buf, n); + put2byte(m.h.size, n); + m.h.magic = MSGMAGIC; + m.h.type = M_DATA; + n += sizeof(struct mesg); + if(iwrite(fd, &m, n) != n) + return -1; + + put2byte(m.h.size, 0); + m.h.magic = MSGMAGIC; + m.h.type = M_DELIM; + n = sizeof(struct mesg); + if(iwrite(fd, &m, n) != n) + return -1; + + return len; +} + --- /sys/src/cmd/con/mkfile Wed Jun 19 22:01:09 2013 +++ /sys/src/cmd/con/mkfile Wed Jun 19 22:01:09 2013 @@ -15,4 +15,5 @@ t_local<OSTOP) */ +#define SIGTINT 23 /* to pgrp on every input character if LINTRUP */ +#define SIGXCPU 24 /* exceeded CPU time limit */ +#define SIGXFSZ 25 /* exceeded file size limit */ +#define SIGLAB 26 /* file label changed; secure unix only (not reset) */ --- /sys/src/cmd/con/rustream.h Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/con/rustream.h Wed Jun 19 22:01:09 2013 @@ -0,0 +1,77 @@ +/* + * Control messages (regular priority) + */ +#define M_DATA 0 /* regular data (not ctl) */ +#define M_BREAK 01 /* line break */ +#define M_HANGUP 02 /* line disconnect */ +#define M_DELIM 03 /* data delimiter */ +#define M_ECHO 04 /* request ACK (1 param) */ +#define M_ACK 05 /* response to ECHO (1 param) */ +#define M_IOCTL 06 /* ioctl; set/get params */ +#define M_DELAY 07 /* real-time xmit delay (1 param) */ +#define M_CTL 010 /* device-specific control message */ +#define M_PASS 011 /* pass file */ +#define M_YDEL 012 /* stream has started generating delims */ +#define M_NDEL 013 /* stream has stopped generating delims */ + +/* + * Control messages (high priority; go to head of queue) + */ +#define M_SIGNAL 0101 /* generate process signal */ +#define M_FLUSH 0102 /* flush your queues */ +#define M_STOP 0103 /* stop transmission immediately */ +#define M_START 0104 /* restart transmission after stop */ +#define M_IOCACK 0105 /* acknowledge ioctl */ +#define M_IOCNAK 0106 /* negative ioctl acknowledge */ +#define M_CLOSE 0107 /* channel closes (dk only) */ +#define M_IOCWAIT 0110 /* stop ioctl timeout, ack/nak follows later */ + +/* + * ioctl message packet + */ + +#define STIOCSIZE 16 +#define STIOCHDR 4 + +struct stioctl { + unsigned char com[STIOCHDR]; /* four-byte command, low order byte first */ + char data[STIOCSIZE]; /* depends on command */ +}; + +/* + * header for messages, see mesg.c + */ +#define MSLEN 2 +struct mesg { + char type; + unsigned char magic; + unsigned char size[MSLEN]; /* 2 byte size, low order first */ +}; + +#define MSGMAGIC 0345 +#define MSGHLEN 4 /* true length of struct mesg in bytes */ + +/* + * magic numbers of line disciplines + */ + +#define tty_ld 0 /* tty processing */ +#define cdkp_ld 1 /* URP protocol -- character mode (same as 1) */ +#define rdk_ld 2 /* raw datakit protocol */ +#define pk_ld 3 /* packet driver */ +#define mesg_ld 4 /* data message protocol */ +#define dkp_ld 5 /* URP protocol -- block mode */ +#define ntty_ld 6 /* new tty processing */ +#define buf_ld 7 /* buffer up characters till timeout */ +#define trc_ld 8 /* stream tracer */ +#define rmesg_ld 9 /* reverse message processing */ +#define ip_ld 10 /* IP - push on net interfaces (il, ec, ...) */ +#define tcp_ld 11 /* TCP (inet) - only one instance, on /dev/ip6 */ +#define chroute_ld 12 /* Chaosnet - push on net interfaces (il, ec, ...) */ +#define arp_ld 13 /* Ethernet address resolution - on net interfaces */ +#define udp_ld 14 /* UDP (inet) - only one instance, on /dev/ip */ +#define chaos_ld 15 /* Chaosnet - only one, above any chroute_ld */ +#define filter_ld 16 /* Delimiter filtering */ +#define dump_ld 17 /* Debug dumper */ +#define conn_ld 18 /* Connection line discipline */ +#define uxp_ld 19 /* unix common control protocol */ --- /sys/src/cmd/con/ruttyio.h Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/con/ruttyio.h Wed Jun 19 22:01:09 2013 @@ -0,0 +1,116 @@ +/* + * teletype-related ioctls + */ + +struct sgttyb { + char sg_ispeed; /* no longer set/returned by kernel */ + char sg_ospeed; /* no longer set/returned by kernel */ + char sg_erase; /* erase character */ + char sg_kill; /* kill character */ + unsigned char sg_flags[2]; /* mode flags, low byte first */ +}; + +/* + * Structure for setting and getting tty device parammeters. + */ +struct ttydevb { + char ispeed; /* input speed */ + char ospeed; /* output speed */ + unsigned char flags[2]; /* mode flags, low byte first */ +}; + +/* + * List of special characters + */ +struct tchars { + char t_intrc; /* interrupt */ + char t_quitc; /* quit */ + char t_startc; /* start output */ + char t_stopc; /* stop output */ + char t_eofc; /* end-of-file */ + char t_brkc; /* input delimiter (like nl) */ +}; + +/* + * modes in sg_flags + */ +#define TANDEM 01 +#define CBREAK 02 +#define LCASE 04 +#define ECHO 010 +#define CRMOD 020 +#define RAW 040 +/* 0300: former parity bits */ +#define NLDELAY 001400 +#define TBDELAY 006000 +#define XTABS 06000 +#define CRDELAY 030000 +#define VTDELAY 040000 +#define BSDELAY 0100000 +#define ALLDELAY 0177400 + +/* + * Delay algorithms + */ +#define CR0 0 +#define CR1 010000 +#define CR2 020000 +#define CR3 030000 +#define NL0 0 +#define NL1 000400 +#define NL2 001000 +#define NL3 001400 +#define TAB0 0 +#define TAB1 002000 +#define TAB2 004000 +#define FF0 0 +#define FF1 040000 +#define BS0 0 +#define BS1 0100000 + +/* + * Speeds + */ +#define B0 0 +#define B50 1 +#define B75 2 +#define B110 3 +#define B134 4 +#define B150 5 +#define B200 6 +#define B300 7 +#define B600 8 +#define B1200 9 +#define B1800 10 +#define B2400 11 +#define B4800 12 +#define B9600 13 +#define EXTA 14 +#define EXTB 15 + +/* + * device flags + */ + +#define F8BIT 040 /* eight-bit path */ +#define ODDP 0100 +#define EVENP 0200 +#define ANYP 0300 + +/* + * tty ioctl commands + */ +#define TIOCHPCL (('t'<<8)|2) +#define TIOCGETP (('t'<<8)|8) +#define TIOCSETP (('t'<<8)|9) +#define TIOCSETN (('t'<<8)|10) +#define TIOCEXCL (('t'<<8)|13) +#define TIOCNXCL (('t'<<8)|14) +#define TIOCFLUSH (('t'<<8)|16) +#define TIOCSETC (('t'<<8)|17) +#define TIOCGETC (('t'<<8)|18) +#define TIOCSBRK (('t'<<8)|19) +#define TIOCGDEV (('t'<<8)|23) /* get device parameters */ +#define TIOCSDEV (('t'<<8)|24) /* set device parameters */ +#define TIOCSPGRP (('t'<<8)|118) /* set pgrp of tty */ +#define TIOCGPGRP (('t'<<8)|119) /* get pgrp of tty */