summaryrefslogtreecommitdiff
path: root/sys/src/cmd/vt/fs.c
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2017-08-20 19:22:30 +0200
committercinap_lenrek <cinap_lenrek@felloff.net>2017-08-20 19:22:30 +0200
commitb28c3db57884d406d5a39750fdc9e46baeb139af (patch)
tree1eda6f403ac77e46d3a9f5098a0b6869aec7a00d /sys/src/cmd/vt/fs.c
parentbc54898807d27e79ba9f1b595ef3e09e3da67522 (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.c213
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);
+}