diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2017-08-20 19:22:30 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2017-08-20 19:22:30 +0200 |
commit | b28c3db57884d406d5a39750fdc9e46baeb139af (patch) | |
tree | 1eda6f403ac77e46d3a9f5098a0b6869aec7a00d /sys/src/cmd/vt/fs.c | |
parent | bc54898807d27e79ba9f1b595ef3e09e3da67522 (diff) |
vt: implement /dev/cons and /dev/consctl as a fileserver, winch, incremental redraw
we used to bind a pipe to /dev/cons and /dev/consctl with some
shared segment hack to pass tty info arround. now we implement
this as a fileserver.
add support for "winchon"/"winchoff" ctl message to enable interrupt
on window size change. (used by ssh)
keep track of fullscreen scrolls, avoiding redrawing the whole
screen each time.
Diffstat (limited to 'sys/src/cmd/vt/fs.c')
-rw-r--r-- | sys/src/cmd/vt/fs.c | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/sys/src/cmd/vt/fs.c b/sys/src/cmd/vt/fs.c new file mode 100644 index 000000000..1c2b5ca23 --- /dev/null +++ b/sys/src/cmd/vt/fs.c @@ -0,0 +1,213 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> + +#include "cons.h" + +#include <thread.h> +#include <fcall.h> +#include <9p.h> + +extern Channel *hc[2]; + +static File *devcons, *devconsctl; + +static Channel *readreq; +static Channel *flushreq; + +static void +fsreader(void*) +{ + Req *r, *fr; + Buf *b; + int n; + + b = nil; + r = nil; + for(;;){ + Alt a[] = { + { flushreq, &fr, CHANRCV }, + { readreq, &r, r == nil ? CHANRCV : CHANNOP }, + { hc[0], &b, b == nil ? CHANRCV : CHANNOP }, + { nil, nil, b == nil || r == nil ? CHANEND : CHANNOBLK }, + }; + if(alt(a) == 0){ + if(fr->oldreq == r){ + respond(r, "interrupted"); + r = nil; + } + respond(fr, nil); + } + if(b == nil || r == nil) + continue; + r->ofcall.count = 0; + while((n = r->ifcall.count - r->ofcall.count) > 0){ + if(n > b->n) + n = b->n; + memmove((char*)r->ofcall.data + r->ofcall.count, b->s, n); + r->ofcall.count += n; + b->s += n, b->n -= n; + if(b->n <= 0){ + free(b); + if((b = nbrecvp(hc[0])) == nil) + break; + } + } + respond(r, nil); + r = nil; + } +} + +static void +fsread(Req *r) +{ + if(r->fid->file == devcons){ + sendp(readreq, r); + return; + } + respond(r, "not implemented"); +} + +typedef struct Partutf Partutf; +struct Partutf +{ + int n; + char s[UTFmax]; +}; + +static Rune* +cvtc2r(char *b, int n, Partutf *u) +{ + char *cp, *ep; + Rune *rp, *rb; + + cp = b, ep = b + n; + rp = rb = emalloc9p(sizeof(Rune)*(n+2)); + + while(u->n > 0 && cp < ep){ + u->s[u->n++] = *cp++; + if(fullrune(u->s, u->n)){ + chartorune(rp, u->s); + if(*rp != 0) + rp++; + u->n = 0; + break; + } + } + if(u->n == 0){ + while(cp < ep && fullrune(cp, ep - cp)){ + cp += chartorune(rp, cp); + if(*rp != 0) + rp++; + } + n = ep - cp; + if(n > 0){ + memmove(u->s, cp, n); + u->n = n; + } + } + if(rb == rp){ + free(rb); + return nil; + } + *rp = 0; + + return rb; +} + +static void +fswrite(Req *r) +{ + if(r->fid->file == devcons){ + Partutf *u; + Rune *rp; + + if((u = r->fid->aux) == nil) + u = r->fid->aux = emalloc9p(sizeof(*u)); + if((rp = cvtc2r((char*)r->ifcall.data, r->ifcall.count, u)) != nil) + sendp(hc[1], rp); + + r->ofcall.count = r->ifcall.count; + respond(r, nil); + return; + } + if(r->fid->file == devconsctl){ + char *s = r->ifcall.data; + int n = r->ifcall.count; + + if(n >= 5 && strncmp(s, "rawon", 5) == 0) + cs->raw = 1; + else if(n >= 6 && strncmp(s, "rawoff", 6) == 0) + cs->raw = 0; + else if(n >= 6 && strncmp(s, "holdon", 6) == 0) + cs->hold = 1; + else if(n >= 7 && strncmp(s, "holdoff", 7) == 0) + cs->hold = 0; + else if(n >= 7 && strncmp(s, "winchon", 7) == 0) + cs->winch = 1; + else if(n >= 8 && strncmp(s, "winchoff", 8) == 0) + cs->winch = 0; + + r->ofcall.count = r->ifcall.count; + respond(r, nil); + return; + } + + respond(r, "not implemented"); +} + +static void +fsflush(Req *r) +{ + sendp(flushreq, r); +} + +static void +fsdestroyfid(Fid *f) +{ + if(f->file == devconsctl && f->omode >= 0){ + cs->raw = 0; + cs->hold = 0; + cs->winch = 0; + } + if(f->aux != nil){ + free(f->aux); + f->aux = nil; + } +} + +static void +fsstart(Srv*) +{ + flushreq = chancreate(sizeof(Req*), 4); + readreq = chancreate(sizeof(Req*), 4); + proccreate(fsreader, nil, 16*1024); +} + +static void +fsend(Srv*) +{ + sendp(hc[1], nil); +} + +Srv fs = { +.read=fsread, +.write=fswrite, +.flush=fsflush, +.destroyfid=fsdestroyfid, +.start=fsstart, +.end=fsend, +}; + +void +mountcons(void) +{ + fs.tree = alloctree("vt", "vt", DMDIR|0555, nil); + devcons = createfile(fs.tree->root, "cons", "vt", 0666, nil); + if(devcons == nil) + sysfatal("creating /dev/cons: %r"); + devconsctl = createfile(fs.tree->root, "consctl", "vt", 0666, nil); + if(devconsctl == nil) + sysfatal("creating /dev/consctl: %r"); + threadpostmountsrv(&fs, nil, "/dev", MBEFORE); +} |