summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Moody <moody@posixcafe.org>2022-08-15 03:45:42 +0000
committerJacob Moody <moody@posixcafe.org>2022-08-15 03:45:42 +0000
commit69352f66684cbc75e2cd68c80cd028324964c5aa (patch)
treefd31d2a76fef40da1415138d154e9c68955a183e
parent79c1842979b5c5579bb0db41861d63f5562c85f1 (diff)
ktrans: tow inside the environment
-rw-r--r--sys/man/1/ktrans (renamed from sys/man/4/ktrans)65
-rw-r--r--sys/src/cmd/ktrans/fs.c401
-rw-r--r--sys/src/cmd/ktrans/ktrans.h25
-rw-r--r--sys/src/cmd/ktrans/main.c208
-rw-r--r--sys/src/cmd/ktrans/mkfile3
5 files changed, 155 insertions, 547 deletions
diff --git a/sys/man/4/ktrans b/sys/man/1/ktrans
index 8c4f446cc..a5acd1125 100644
--- a/sys/man/4/ktrans
+++ b/sys/man/1/ktrans
@@ -1,66 +1,40 @@
-.TH KTRANS 4
+.TH KTRANS 1
.SH NAME
ktrans \- language transliterator
.SH SYNOPSIS
.B ktrans
[
-.B -K
-]
-[
-.B -k
-.I kbd
+.B -t
+.I kbdtap
]
[
.B -l
.I lang
]
-[
-.B -m
-.I mnt
-]
-.nf
-
-.IB /mnt/ktrans/kbd
-.IB /mnt/ktrans/kbdin
-.IB /mnt/ktrans/lang
-.fi
.SH DESCRIPTION
-.I ktrans
-is a fileserver that provides a transliteration overlay to
-.IR kbdfs (8).
-When run,
-.I ktrans
-mounts itself to
-.B /mnt/ktrans
-and binds its own
-.B kbd
-and
-.B kbdin
-files over those present in
-.BR /dev .
-.PP
-By default,
-.I ktrans
-also forks and reads input from the existing
-.BR /dev/kbd .
+.I Ktrans
+provides a transliteration layer
+to keyboard input through reads and
+writes to
+.BR /dev/kbdtap .
The
-.B -k
-flag changes which file is read. The
-.B -K
-flag disables this process all together, limiting
-input to only the
-.B kbdin
-file.
+.B -t
+flag changes the
+.I kbdtap
+file used. The
+.B -l
+flag changes the initial
+language.
.SH CONVERSION
Conversion is done in two steps: An implicit layer
-that is used for direct mappings between latin characters and
+that is used for direct mappings between ascii characters and
an explicit multi rune conversion used for compound mappings.
.I Ktrans
does implicit conversion by passing through characters
as they are input. Then when a sequence of input is matched,
backspaces are emitted to clear the input sequence and the matched
rune sequence is emitted. The last 'word' of input may be then
-additionaly transliterated by typing ctrl-\\. A newline character also
+explicitely transliterated by typing ctrl-\\. A newline character also
performs this lookup, but additional newline characters will not
cycle through alternatives.
.SH CONTROL
@@ -109,7 +83,7 @@ Korean mode. Implicit layer converts latin to Korean Hangul.
.SH SOURCE
.B /sys/src/cmd/ktrans
.SH SEE ALSO
-.IR rio (1)
+.IR rio (4)
.IR kbdfs (8)
.br
.IR /sys/src/cmd/ktrans/README.kenji
@@ -139,4 +113,5 @@ There is no way to generate the control characters literally.
.SH HISTORY
Ktrans was originally written by Kenji Okamoto in August of 2000 for
the 2nd edition of Plan 9. It was imported in to 9front in July of
-2022, with patches by several contributors.
+2022, with patches by several contributors. It was towed inside
+the environment during the 2022 9front hackathon.
diff --git a/sys/src/cmd/ktrans/fs.c b/sys/src/cmd/ktrans/fs.c
deleted file mode 100644
index 1a465bae5..000000000
--- a/sys/src/cmd/ktrans/fs.c
+++ /dev/null
@@ -1,401 +0,0 @@
-#include <u.h>
-#include <libc.h>
-#include <fcall.h>
-#include <thread.h>
-#include <9p.h>
-
-#include "hash.h"
-#include "ktrans.h"
-
-static Channel *globalkbd;
-static char *user;
-
-char*
-parsekbd(Channel *out, char *buf, int n)
-{
- char *p, *e;
- Msg msg;
-
- for(p = buf; p < buf+n;){
- msg.code = p[0];
- p++;
- switch(msg.code){
- case 'c': case 'k': case 'K':
- break;
- default:
- return "malformed kbd message";
- }
- e = utfecpy(msg.buf, msg.buf + sizeof msg.buf, p);
- if(e == msg.buf)
- return "short command";
- p += e - msg.buf;
- p++;
- if(send(out, &msg) == -1)
- return nil;
- }
- return nil;
-}
-
-void
-kbdproc(void *a)
-{
- char *s;
- int fd, n;
- char buf[128];
-
- s = a;
- fd = open(s, OREAD);
- if(fd < 0){
- fprint(2, "could not open file %s: %r", s);
- chanclose(globalkbd);
- return;
- }
- for(;;){
- n = read(fd, buf, sizeof buf);
- if(n < 3){
- continue;
- }
- parsekbd(globalkbd, buf, n);
- }
-}
-
-Trans*
-spawntrans(int global)
-{
- Trans *t;
-
- t = mallocz(sizeof *t, 1);
- if(global)
- t->input = globalkbd;
- else
- t->input = chancreate(sizeof(Msg), 0);
- t->output = chancreate(sizeof(Msg), 0);
- t->dict = chancreate(sizeof(Msg), 0);
- t->done = chancreate(1, 0);
- t->lang = chancreate(sizeof(char*), 0);
- proccreate(keyproc, t, mainstacksize);
- return t;
-}
-
-void
-closetrans(Trans *t)
-{
- chanclose(t->input);
- chanclose(t->output);
- chanclose(t->dict);
-
- /* wait for threads to exit */
- recv(t->done, nil);
- recv(t->done, nil);
-
- chanfree(t->done);
- chanfree(t->input);
- chanfree(t->output);
- chanfree(t->dict);
- free(t);
-}
-
-enum{
- Qroot,
- Qkbd,
- Qkbdin,
- Qlang,
-};
-
-Dir dirtab[] = {
- {.qid={Qroot, 0, QTDIR}, .mode=0555, .name="/"},
- {.qid={Qkbd, 0, QTFILE}, .mode=0600, .name="kbd"},
- {.qid={Qkbdin, 0, QTFILE}, .mode=0200, .name="kbdin"},
- {.qid={Qlang, 0, QTFILE}, .mode=0600, .name="lang"},
-};
-
-static int
-dirgen(int n, Dir *dir, void*)
-{
- n++;
- if(n >= nelem(dirtab))
- return -1;
-
- *dir = dirtab[n];
- dir->name = estrdup9p(dir->name);
- dir->uid = estrdup9p(user);
- dir->gid = estrdup9p(user);
- dir->muid = estrdup9p(user);
- return 0;
-}
-
-typedef struct Aux Aux;
-struct Aux {
- Ref;
- Reqqueue *q;
- Trans *t;
-};
-
-static void
-fsattach(Req *r)
-{
- Aux *aux;
- Trans *t;
- char *aname;
-
- /*
- * Each attach allocates a new "keyboard".
- * The global attach argument denotes to
- * use /dev/kbd as the source of keyboard input.
- *
- * Sessions include one translation
- * process, and one read queue. Since
- * it is common for clients to constantly be
- * blocked on the kbd file, we need to assign it to
- * it's own process so we can service other requests
- * in the meantime.
- */
-
- aname = r->ifcall.aname;
- if(aname != nil && strcmp(aname, "global") == 0)
- t = spawntrans(1);
- else
- t = spawntrans(0);
-
- aux = mallocz(sizeof *aux, 1);
- aux->t = t;
- aux->q = reqqueuecreate();
- incref(aux);
-
- r->fid->aux = aux;
- r->ofcall.qid = dirtab[0].qid;
- r->fid->qid = dirtab[0].qid;
- respond(r, nil);
-}
-
-static void
-fsopen(Req *r)
-{
- respond(r, nil);
-}
-
-static void
-fskbd(Req *r)
-{
- Aux *aux;
- Msg m;
- char *p;
- char buf[1+128], *bp;
- Rune rn;
-
- aux = r->fid->aux;
- if(recv(aux->t->output, &m) == -1){
- respond(r, "closing");
- return;
- }
- if(m.code != 'c'){
- bp = seprint(buf, buf + sizeof buf, "%c%s", m.code, m.buf);
- goto Send;
- }
- p = m.buf;
- bp = buf;
- for(;bp < buf + sizeof buf;){
- p += chartorune(&rn, p);
- if(rn == Runeerror || rn == '\0')
- break;
- bp = seprint(bp, buf + sizeof buf, "c%C", rn);
- bp++;
- }
- if(bp >= buf + sizeof buf){
- while(*bp-- != '\0')
- ;
- bp++;
- }
-
-Send:
- r->ifcall.offset = 0;
- readbuf(r, buf, (bp-buf)+1);
- respond(r, nil);
-}
-
-static void
-fsread(Req *r)
-{
- Aux *aux;
- Msg m;
- char *p;
-
- aux = r->fid->aux;
- switch((uint)r->fid->qid.path){
- case Qroot:
- dirread9p(r, dirgen, nil);
- respond(r, nil);
- break;
- case Qkbd:
-
- reqqueuepush(aux->q, r, fskbd);
- break;
- case Qlang:
- m.code = 'q';
- m.buf[0] = '\0';
- if(send(aux->t->input, &m) == -1){
- respond(r, "closing");
- break;
- }
- if(recv(aux->t->lang, &p) == -1){
- respond(r, "closing");
- break;
- }
- snprint(m.buf, sizeof m.buf, "%s\n", p);
- readstr(r, m.buf);
- respond(r, nil);
- break;
- default:
- respond(r, "bad op");
- break;
- }
-}
-
-static void
-fswrite(Req *r)
-{
- Aux *aux;
- int n, lang;
- char *err, *p;
- Msg m;
-
- aux = r->fid->aux;
- n = r->ifcall.count;
- switch((uint)r->fid->qid.path){
- case Qkbdin:
- if(n < 3){
- respond(r, "short write");
- return;
- }
- err = parsekbd(aux->t->input, r->ifcall.data, n);
- if(err != nil){
- respond(r, err);
- return;
- }
- break;
- case Qlang:
- if(n >= sizeof m.buf){
- respond(r, "large write");
- return;
- }
- memmove(m.buf, r->ifcall.data, n);
- m.buf[n] = '\0';
- p = strchr(m.buf, '\n');
- if(p != nil)
- *p = '\0';
- lang = parselang(m.buf);
- if(lang < 0){
- respond(r, "unkonwn lang");
- return;
- }
- m.buf[0] = lang;
- m.buf[1] = '\0';
- m.code = 'c';
- send(aux->t->input, &m);
- }
- r->ofcall.count = n;
- respond(r, nil);
-}
-
-static void
-fsstat(Req *r)
-{
- if(dirgen(r->fid->qid.path - 1, &r->d, nil) == -1)
- respond(r, "invalid fid");
- else
- respond(r, nil);
-
-}
-
-static char*
-fswalk1(Fid *fid, char *name, Qid *qid)
-{
- int i;
-
- if(fid->qid.path != Qroot)
- return "walk from non root";
-
- for(i = 0; i < nelem(dirtab); i++)
- if(strcmp(name, dirtab[i].name) == 0){
- *qid = dirtab[i].qid;
- break;
- }
-
- if(i == nelem(dirtab))
- return "file does not exist";
-
- fid->qid = *qid;
- return nil;
-}
-
-static char*
-fsclone(Fid *oldfid, Fid *newfid)
-{
- Aux *aux;
-
- aux = oldfid->aux;
- incref(aux);
- newfid->aux = aux;
-
- return nil;
-}
-
-static void
-fidclunk(Fid *fid)
-{
- Aux *aux;
-
- aux = fid->aux;
- if(decref(aux) != 0)
- return;
-
- closetrans(aux->t);
- reqqueuefree(aux->q);
-}
-
-
-static Srv fs = {
- .attach=fsattach,
- .open=fsopen,
- .read=fsread,
- .write=fswrite,
- .stat=fsstat,
-
- .walk1=fswalk1,
- .clone=fsclone,
- .destroyfid=fidclunk,
-};
-
-void
-launchfs(char *srv, char *mnt, char *kbd)
-{
- int fd;
- char buf[128];
-
- user = getenv("user");
- if(user == nil)
- user = "glenda";
- if(kbd != nil){
- globalkbd = chancreate(sizeof(Msg), 0);
- proccreate(kbdproc, kbd, mainstacksize);
- }
-
- fd = threadpostsrv(&fs, srv);
- if(fd < 0)
- sysfatal("postsrv %r");
-
- if(kbd != nil){
- if(mount(fd, -1, mnt, MREPL, "global") < 0)
- sysfatal("mount %r");
-
- snprint(buf, sizeof buf, "%s/kbd", mnt);
- if(bind(buf, "/dev/kbd", MREPL) < 0)
- sysfatal("bind %r");
-
- snprint(buf, sizeof buf, "%s/kbdin", mnt);
- if(bind(buf, "/dev/kbdin", MREPL) < 0)
- sysfatal("bind %r");
- } else
- if(mount(fd, -1, mnt, MREPL, "") < 0)
- sysfatal("mount %r");
-}
diff --git a/sys/src/cmd/ktrans/ktrans.h b/sys/src/cmd/ktrans/ktrans.h
deleted file mode 100644
index 151fe666c..000000000
--- a/sys/src/cmd/ktrans/ktrans.h
+++ /dev/null
@@ -1,25 +0,0 @@
-typedef struct Map Map;
-struct Map {
- char *roma;
- char *kana;
- char leadstomore;
-};
-
-typedef struct Msg Msg;
-struct Msg {
- char code;
- char buf[64];
-};
-
-typedef struct Trans Trans;
-struct Trans {
- Channel *input;
- Channel *output;
- Channel *dict;
- Channel *done;
- Channel *lang;
-};
-
-void keyproc(void*);
-void launchfs(char*,char*,char*);
-int parselang(char*);
diff --git a/sys/src/cmd/ktrans/main.c b/sys/src/cmd/ktrans/main.c
index 4105ad242..f41d3cfe3 100644
--- a/sys/src/cmd/ktrans/main.c
+++ b/sys/src/cmd/ktrans/main.c
@@ -1,11 +1,3 @@
-/*
- * Mostly based on the original source codes of Plan 9 release 2
- * distribution.
- * by Kenji Okamoto, August 4 2000
- * Osaka Prefecture Univ.
- * okamoto@granite.cias.osakafu-u.ac.jp
- */
-
#include <u.h>
#include <libc.h>
#include <ctype.h>
@@ -13,15 +5,7 @@
#include <fcall.h>
#include <thread.h>
#include <9p.h>
-
#include "hash.h"
-#include "ktrans.h"
-
-static Hmap *jisho, *zidian;
-static int deflang;
-static char backspace[64];
-
-mainstacksize = 8192*2;
char*
pushutf(char *dst, char *e, char *u, int nrune)
@@ -83,12 +67,19 @@ resetstr(Str *s, ...)
void
popstr(Str *s)
{
- while(s->p > s->b && (*--s->p & 0xC0)==0x80)
+ while(s->p > s->b && (*--s->p & 0xC0)==Runesync)
;
s->p[0] = '\0';
}
+typedef struct Map Map;
+struct Map {
+ char *roma;
+ char *kana;
+ char leadstomore;
+};
+
Hmap*
openmap(char *file)
{
@@ -201,12 +192,14 @@ enum{
LangZH = '', // ^c
};
+int deflang;
+
Hmap *natural;
-Hmap *hira, *kata;
+Hmap *hira, *kata, *jisho;
Hmap *cyril;
Hmap *greek;
Hmap *hangul;
-Hmap *hanzi;
+Hmap *hanzi, *zidian;
Hmap **langtab[] = {
[LangEN] &natural,
@@ -274,6 +267,16 @@ maplkup(int lang, char *s, Map *m)
return hmapget(*h, s, m);
}
+typedef struct Msg Msg;
+struct Msg {
+ char code;
+ char buf[64];
+};
+static Channel *dictch;
+static Channel *output;
+static Channel *input;
+static char backspace[64];
+
static int
emitutf(Channel *out, char *u, int nrune)
{
@@ -287,9 +290,8 @@ emitutf(Channel *out, char *u, int nrune)
}
static void
-dictthread(void *a)
+dictthread(void*)
{
- Trans *t;
Msg m;
Rune r;
int n;
@@ -308,7 +310,6 @@ dictthread(void *a)
};
int mode;
- t = a;
dict = jisho;
selected = -1;
kouho[0] = nil;
@@ -316,7 +317,7 @@ dictthread(void *a)
resetstr(&last, &line, &okuri, nil);
threadsetname("dict");
- while(recv(t->dict, &m) != -1){
+ while(recv(dictch, &m) != -1){
for(p = m.buf; *p; p += n){
n = chartorune(&r, p);
if(r != ''){
@@ -337,10 +338,10 @@ dictthread(void *a)
break;
case '':
if(line.b == line.p){
- emitutf(t->output, "", 1);
+ emitutf(output, "", 1);
break;
}
- emitutf(t->output, backspace, utflen(line.b));
+ emitutf(output, backspace, utflen(line.b));
/* fallthrough */
case ' ': case ',': case '.':
case ' ':
@@ -360,7 +361,7 @@ dictthread(void *a)
break;
case '\n':
if(line.b == line.p){
- emitutf(t->output, "\n", 1);
+ emitutf(output, "\n", 1);
break;
}
/* fallthrough */
@@ -377,23 +378,23 @@ dictthread(void *a)
}
if(kouho[selected] == nil){
/* cycled through all matches; bail */
- emitutf(t->output, backspace, utflen(last.b));
- emitutf(t->output, line.b, 0);
+ emitutf(output, backspace, utflen(last.b));
+ emitutf(output, line.b, 0);
resetstr(&line, &last, &okuri, nil);
selected = -1;
break;
}
if(okuri.p != okuri.b)
- emitutf(t->output, backspace, utflen(okuri.b));
+ emitutf(output, backspace, utflen(okuri.b));
if(selected == 0)
- emitutf(t->output, backspace, utflen(line.b));
+ emitutf(output, backspace, utflen(line.b));
else
- emitutf(t->output, backspace, utflen(last.b));
+ emitutf(output, backspace, utflen(last.b));
- emitutf(t->output, kouho[selected], 0);
+ emitutf(output, kouho[selected], 0);
last.p = pushutf(last.b, strend(&last), kouho[selected], 0);
- emitutf(t->output, okuri.b, 0);
+ emitutf(output, okuri.b, 0);
resetstr(&line, nil);
mode = Kanji;
@@ -430,14 +431,11 @@ dictthread(void *a)
}
}
}
-
- send(t->done, nil);
}
-void
-keyproc(void *a)
+static void
+keythread(void*)
{
- Trans *t;
int lang;
Msg m;
Map lkup;
@@ -448,35 +446,35 @@ keyproc(void *a)
Str line;
int mode;
- t = a;
mode = 0;
peek[0] = lang = deflang;
- threadcreate(dictthread, a, mainstacksize);
resetstr(&line, nil);
if(lang == LangJP || lang == LangZH)
- emitutf(t->dict, peek, 1);
+ emitutf(dictch, peek, 1);
- threadsetname("key");
- while(recv(t->input, &m) != -1){
+ threadsetname("keytrans");
+ while(recv(input, &m) != -1){
+ if(m.code == 'r'){
+ emitutf(dictch, " ", 1);
+ resetstr(&line, nil);
+ continue;
+ }
if(m.code != 'c'){
- if(m.code == 'q')
- send(t->lang, &langcodetab[lang]);
- else
- send(t->output, &m);
+ send(output, &m);
continue;
}
for(p = m.buf; *p; p += n){
n = chartorune(&r, p);
if(checklang(&lang, r)){
- emitutf(t->dict, " ", 1);
+ emitutf(dictch, " ", 1);
if(lang == LangJP || lang == LangZH)
- emitutf(t->dict, p, 1);
+ emitutf(dictch, p, 1);
resetstr(&line, nil);
continue;
}
if(lang == LangZH || lang == LangJP){
- emitutf(t->dict, p, 1);
+ emitutf(dictch, p, 1);
if(utfrune(" \n", r) != nil){
resetstr(&line, nil);
continue;
@@ -489,7 +487,7 @@ keyproc(void *a)
}
}
- emitutf(t->output, p, 1);
+ emitutf(output, p, 1);
if(lang == LangEN || lang == LangZH)
continue;
if(r == '\b'){
@@ -512,58 +510,111 @@ keyproc(void *a)
resetstr(&line, nil);
if(lang == LangJP){
- emitutf(t->dict, backspace, utflen(lkup.roma));
- emitutf(t->dict, lkup.kana, 0);
+ emitutf(dictch, backspace, utflen(lkup.roma));
+ emitutf(dictch, lkup.kana, 0);
}
- emitutf(t->output, backspace, utflen(lkup.roma));
- emitutf(t->output, lkup.kana, 0);
+ emitutf(output, backspace, utflen(lkup.roma));
+ emitutf(output, lkup.kana, 0);
+ }
+ }
+}
+
+static int kbdin;
+static int kbdout;
+
+void
+kbdtap(void*)
+{
+ Msg msg;
+ char buf[128];
+ char *p, *e;
+ int n;
+
+ threadsetname("kbdtap");
+ for(;;){
+Drop:
+ n = read(kbdin, buf, sizeof buf);
+ if(n < 0)
+ break;
+ for(p = buf; p < buf+n;){
+ msg.code = p[0];
+ p++;
+ switch(msg.code){
+ case 'c': case 'k': case 'K':
+ case 'r':
+ break;
+ default:
+ goto Drop;
+ }
+ e = utfecpy(msg.buf, msg.buf + sizeof msg.buf, p);
+ p += e - msg.buf;
+ p++;
+ if(send(input, &msg) == -1)
+ return;
+ }
+ }
+}
+
+void
+kbdsink(void*)
+{
+ Msg m;
+ char *p;
+ Rune rn;
+
+ threadsetname("kbdsink");
+ while(recv(output, &m) != -1){
+ if(m.code != 'c'){
+ fprint(kbdout, "%c%s", m.code, m.buf);
+ continue;
+ }
+ p = m.buf;
+ for(;;){
+ p += chartorune(&rn, p);
+ if(rn == Runeerror || rn == '\0')
+ break;
+ fprint(kbdout, "c%C", rn);
}
}
- send(t->done, nil);
}
void
usage(void)
{
- fprint(2, "usage: %s [ -K ] [ -l lang ]\n", argv0);
- exits("usage");
+ fprint(2, "usage: %s [ -t tap ] [ -l lang ]\n", argv0);
+ threadexits("usage");
}
+mainstacksize = 8192*2;
+
void
threadmain(int argc, char *argv[])
{
char *jishoname, *zidianname;
- char *kbd, *srv, *mntpt;
+ char *tap;
- kbd = "/dev/kbd";
- srv = nil;
- mntpt = "/mnt/ktrans";
+ tap = "/dev/kbdtap";
deflang = LangEN;
ARGBEGIN{
- case 'K':
- kbd = nil;
- break;
- case 'k':
- kbd = EARGF(usage());
+ case 't':
+ tap = EARGF(usage());
break;
case 'l':
deflang = parselang(EARGF(usage()));
if(deflang < 0)
usage();
break;
- case 's':
- srv = EARGF(usage());
- break;
- case 'm':
- mntpt = EARGF(usage());
- break;
default:
usage();
}ARGEND;
if(argc != 0)
usage();
+ kbdin = kbdout = open(tap, ORDWR);
+ if(kbdin < 0 || kbdout < 0)
+ sysfatal("failed to get keyboard: %r");
+
memset(backspace, '\b', sizeof backspace-1);
backspace[sizeof backspace-1] = '\0';
@@ -582,5 +633,14 @@ threadmain(int argc, char *argv[])
cyril = openmap("/lib/ktrans/cyril.map");
hangul = openmap("/lib/ktrans/hangul.map");
- launchfs(srv, mntpt, kbd);
+ dictch = chancreate(sizeof(Msg), 0);
+ input = chancreate(sizeof(Msg), 0);
+ output = chancreate(sizeof(Msg), 0);
+
+ proccreate(kbdtap, nil, mainstacksize);
+ proccreate(kbdsink, nil, mainstacksize);
+ threadcreate(dictthread, nil, mainstacksize);
+ threadcreate(keythread, nil, mainstacksize);
+
+ threadexits(nil);
}
diff --git a/sys/src/cmd/ktrans/mkfile b/sys/src/cmd/ktrans/mkfile
index 5de77a8d0..3b3fee778 100644
--- a/sys/src/cmd/ktrans/mkfile
+++ b/sys/src/cmd/ktrans/mkfile
@@ -2,10 +2,9 @@
BIN=/$objtype/bin
TARG=ktrans
-HFILES=ktrans.h
+HFILES=hash.h
OFILES=\
hash.$O\
main.$O\
- fs.$O\
</sys/src/cmd/mkone