This commit is contained in:
Russ Cox 2005-08-08 12:50:13 +00:00
parent 0189e66e88
commit 934846f35c
382 changed files with 62614 additions and 0 deletions

82
Makefile Normal file
View File

@ -0,0 +1,82 @@
TARG=drawterm
CC=gcc
CFLAGS=-Iinclude -c -ggdb -D_THREAD_SAFE -pthread # not ready for this yet: -Wall
O=o
#CC=cl
#CFLAGS=-c -nologo -W3 -YX -Zi -MT -Zl -Iinclude -DWINDOWS
#O=obj
OFILES=\
main.$O\
cpu.$O\
readcons.$O\
secstore.$O\
latin1.$O\
LIBS=\
kern/libkern.a\
exportfs/libexportfs.a\
libauthsrv/libauthsrv.a\
libsec/libsec.a\
libmp/libmp.a\
libmemdraw/libmemdraw.a\
libmemlayer/libmemlayer.a\
libdraw/libdraw.a\
libc/libc.a\
kern/libkern.a\
gui-x11/libx11.a\
libmemdraw/libmemdraw.a\
libdraw/libdraw.a\
kern/libkern.a\
libc/libc.a\
libmemdraw/libmemdraw.a\
libmemlayer/libmemlayer.a\
libdraw/libdraw.a\
libmachdep.a
$(TARG): $(OFILES) $(LIBS)
$(CC) -pthread -o $(TARG) $(OFILES) $(LIBS) -L/usr/X11R6/lib -lX11 -ggdb
%.$O: %.c
$(CC) $(CFLAGS) $*.c
clean:
rm -f *.o */*.o */*.a drawterm *.a
kern/libkern.a:
(cd kern; make)
exportfs/libexportfs.a:
(cd exportfs; make)
libauthsrv/libauthsrv.a:
(cd libauthsrv; make)
libmp/libmp.a:
(cd libmp; make)
libsec/libsec.a:
(cd libsec; make)
libmemdraw/libmemdraw.a:
(cd libmemdraw; make)
libmemlayer/libmemlayer.a:
(cd libmemlayer; make)
libdraw/libdraw.a:
(cd libdraw; make)
libc/libc.a:
(cd libc; make)
gui-x11/libx11.a:
(cd gui-x11; make)
#libmachdep.a:
# arch=`uname -m|sed 's/i.86/386/;s/Power Macintosh/power/'`; \
# (cd gcc$$arch && make)
libmachdep.a:
(cd posix-386; make)

16
Notes Normal file
View File

@ -0,0 +1,16 @@
Win32 port Notes:
* Issues:
** ownership questions on files are completely deferred by
marking them as unknown. It works for now, but probably
should be handled correctly.
** No performance measurements have been done. The interactive
response seems faster than old drawterm, but the i/o seems
slower.
** fs functions in devntfs.c need to handle conversions to/from
widechar and utf-8.

20
args.h Normal file
View File

@ -0,0 +1,20 @@
extern char *argv0;
#define ARGBEGIN for((argv0? 0: (argv0=*argv)),argv++,argc--;\
argv[0] && argv[0][0]=='-' && argv[0][1];\
argc--, argv++) {\
char *_args, *_argt;\
Rune _argc;\
_args = &argv[0][1];\
if(_args[0]=='-' && _args[1]==0){\
argc--; argv++; break;\
}\
_argc = 0;\
while(*_args && (_args += chartorune(&_argc, _args)))\
switch(_argc)
#define ARGEND SET(_argt);USED(_argt); USED(_argc); USED(_args);}USED(argv); USED(argc);
#define ARGF() (_argt=_args, _args="",\
(*_argt? _argt: argv[1]? (argc--, *++argv): 0))
#define ARGC() _argc
#define EARGF(x) (_argt=_args, _args="",\
(*_argt? _argt: argv[1]? (argc--, *++argv): (x, (char*)0)))

606
cpu.c Normal file
View File

@ -0,0 +1,606 @@
/*
* cpu.c - Make a connection to a cpu server
*
* Invoked by listen as 'cpu -R | -N service net netdir'
* by users as 'cpu [-h system] [-c cmd args ...]'
*/
#include <u.h>
#include <libc.h>
#include <auth.h>
#include <fcall.h>
#include <authsrv.h>
#include <libsec.h>
#include "args.h"
#include "drawterm.h"
#define Maxfdata 8192
#define MaxStr 128
static char* getuser(void);
static void fatal(int, char*, ...);
static void catcher(void*, char*);
static void usage(void);
static void writestr(int, char*, char*, int);
static int readstr(int, char*, int);
static char *rexcall(int*, char*, char*);
static int setamalg(char*);
static char *keyspec = "";
static AuthInfo *p9any(int);
static int notechan;
#define system csystem
static char *system;
static int cflag;
int dbg;
static char *srvname = "ncpu";
static char *ealgs = "rc4_256 sha1";
/* message size for exportfs; may be larger so we can do big graphics in CPU window */
static int msgsize = Maxfdata+IOHDRSZ;
/* authentication mechanisms */
static int netkeyauth(int);
static int netkeysrvauth(int, char*);
static int p9auth(int);
static int srvp9auth(int, char*);
static int noauth(int);
static int srvnoauth(int, char*);
char *authserver;
typedef struct AuthMethod AuthMethod;
struct AuthMethod {
char *name; /* name of method */
int (*cf)(int); /* client side authentication */
int (*sf)(int, char*); /* server side authentication */
} authmethod[] =
{
{ "p9", p9auth, srvp9auth,},
{ "netkey", netkeyauth, netkeysrvauth,},
// { "none", noauth, srvnoauth,},
{ nil, nil}
};
AuthMethod *am = authmethod; /* default is p9 */
char *p9authproto = "p9any";
int setam(char*);
void
exits(char *s)
{
print("\ngoodbye\n");
for(;;) osyield();
}
void
usage(void)
{
fprint(2, "usage: drawterm [-a authserver] [-c cpuserver] [-s secstore] [-u user]\n");
exits("usage");
}
int fdd;
void
cpumain(int argc, char **argv)
{
char dat[MaxStr], buf[MaxStr], cmd[MaxStr], *p, *err, *secstoreserver, *s;
int fd, ms, data;
/* see if we should use a larger message size */
fd = open("/dev/draw", OREAD);
if(fd > 0){
ms = iounit(fd);
if(msgsize < ms+IOHDRSZ)
msgsize = ms+IOHDRSZ;
close(fd);
}
user = readcons("user", getenv("USER"), 0);
secstoreserver = nil;
ARGBEGIN{
case 'a':
authserver = EARGF(usage());
break;
case 'e':
ealgs = EARGF(usage());
if(*ealgs == 0 || strcmp(ealgs, "clear") == 0)
ealgs = nil;
break;
case 'd':
dbg++;
break;
case 'c':
system = EARGF(usage());
break;
/*
case 'c':
cflag++;
cmd[0] = '!';
cmd[1] = '\0';
while(p = ARGF()) {
strcat(cmd, " ");
strcat(cmd, p);
}
break;
*/
case 'u':
user = EARGF(usage());
break;
case 's':
secstoreserver = EARGF(usage());
break;
default:
usage();
}ARGEND;
if(secstoreserver == nil)
secstoreserver = authserver;
if(secstoreserver && havesecstore(secstoreserver, user)){
s = secstorefetch(secstoreserver, user, nil);
if(s){
if(strlen(s) >= sizeof secstorebuf)
panic("secstore data too big");
strcpy(secstorebuf, s);
}
}
if(argc != 0)
usage();
if(system == nil) {
p = getenv("cpu");
if(p == 0)
fatal(0, "set $cpu");
system = p;
}
if(err = rexcall(&data, system, srvname))
fatal(1, "%s: %s", err, system);
/* Tell the remote side the command to execute and where our working directory is */
if(cflag)
writestr(data, cmd, "command", 0);
if(getcwd(dat, sizeof(dat)) == 0)
writestr(data, "NO", "dir", 0);
else
writestr(data, dat, "dir", 0);
/*
* Wait for the other end to execute and start our file service
* of /mnt/term
*/
if(readstr(data, buf, sizeof(buf)) < 0)
fatal(1, "waiting for FS: %r");
if(strncmp("FS", buf, 2) != 0) {
print("remote cpu: %s", buf);
exits(buf);
}
if(readstr(data, buf, sizeof buf) < 0)
fatal(1, "waiting for remote export: %r");
if(strcmp(buf, "/") != 0){
print("remote cpu: %s" , buf);
exits(buf);
}
write(data, "OK", 2);
/* Begin serving the gnot namespace */
exportfs(data, msgsize);
fatal(1, "starting exportfs");
}
void
fatal(int syserr, char *fmt, ...)
{
Fmt f;
char *str;
va_list arg;
fmtstrinit(&f);
fmtprint(&f, "cpu: ");
va_start(arg, fmt);
fmtvprint(&f, fmt, arg);
va_end(arg);
if(syserr)
fmtprint(&f, ": %r");
fmtprint(&f, "\n");
str = fmtstrflush(&f);
write(2, str, strlen(str));
exits(str);
}
char *negstr = "negotiating authentication method";
char bug[256];
char*
rexcall(int *fd, char *host, char *service)
{
char *na;
char dir[MaxStr];
char err[ERRMAX];
char msg[MaxStr];
int n;
na = netmkaddr(host, "tcp", "17010");
if((*fd = dial(na, 0, dir, 0)) < 0)
return "can't dial";
/* negotiate authentication mechanism */
if(ealgs != nil)
snprint(msg, sizeof(msg), "%s %s", am->name, ealgs);
else
snprint(msg, sizeof(msg), "%s", am->name);
writestr(*fd, msg, negstr, 0);
n = readstr(*fd, err, sizeof err);
if(n < 0)
return negstr;
if(*err){
werrstr(err);
return negstr;
}
/* authenticate */
*fd = (*am->cf)(*fd);
if(*fd < 0)
return "can't authenticate";
return 0;
}
void
writestr(int fd, char *str, char *thing, int ignore)
{
int l, n;
l = strlen(str);
n = write(fd, str, l+1);
if(!ignore && n < 0)
fatal(1, "writing network: %s", thing);
}
int
readstr(int fd, char *str, int len)
{
int n;
while(len) {
n = read(fd, str, 1);
if(n < 0)
return -1;
if(*str == '\0')
return 0;
str++;
len--;
}
return -1;
}
static int
readln(char *buf, int n)
{
int i;
char *p;
n--; /* room for \0 */
p = buf;
for(i=0; i<n; i++){
if(read(0, p, 1) != 1)
break;
if(*p == '\n' || *p == '\r')
break;
p++;
}
*p = '\0';
return p-buf;
}
/*
* user level challenge/response
*/
static int
netkeyauth(int fd)
{
char chall[32];
char resp[32];
strecpy(chall, chall+sizeof chall, getuser());
print("user[%s]: ", chall);
if(readln(resp, sizeof(resp)) < 0)
return -1;
if(*resp != 0)
strcpy(chall, resp);
writestr(fd, chall, "challenge/response", 1);
for(;;){
if(readstr(fd, chall, sizeof chall) < 0)
break;
if(*chall == 0)
return fd;
print("challenge: %s\nresponse: ", chall);
if(readln(resp, sizeof(resp)) < 0)
break;
writestr(fd, resp, "challenge/response", 1);
}
return -1;
}
static int
netkeysrvauth(int fd, char *user)
{
return -1;
}
static void
mksecret(char *t, uchar *f)
{
sprint(t, "%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9]);
}
/*
* plan9 authentication followed by rc4 encryption
*/
static int
p9auth(int fd)
{
uchar key[16];
uchar digest[SHA1dlen];
char fromclientsecret[21];
char fromserversecret[21];
int i;
AuthInfo *ai;
ai = p9any(fd);
if(ai == nil)
return -1;
memmove(key+4, ai->secret, ai->nsecret);
if(ealgs == nil)
return fd;
/* exchange random numbers */
srand(truerand());
for(i = 0; i < 4; i++)
key[i] = rand();
if(write(fd, key, 4) != 4)
return -1;
if(readn(fd, key+12, 4) != 4)
return -1;
/* scramble into two secrets */
sha1(key, sizeof(key), digest, nil);
mksecret(fromclientsecret, digest);
mksecret(fromserversecret, digest+10);
/* set up encryption */
i = pushssl(fd, ealgs, fromclientsecret, fromserversecret, nil);
if(i < 0)
werrstr("can't establish ssl connection: %r");
return i;
}
int
authdial(char *net, char *dom)
{
int fd;
fd = dial(netmkaddr(authserver, "tcp", "567"), 0, 0, 0);
//print("authdial %d\n", fd);
return fd;
}
static int
getastickets(Ticketreq *tr, char *trbuf, char *tbuf)
{
int asfd, rv;
char *dom;
dom = tr->authdom;
asfd = authdial(nil, dom);
if(asfd < 0)
return -1;
rv = _asgetticket(asfd, trbuf, tbuf);
close(asfd);
return rv;
}
static int
mkserverticket(Ticketreq *tr, char *authkey, char *tbuf)
{
int i;
Ticket t;
if(strcmp(tr->authid, tr->hostid) != 0)
return -1;
memset(&t, 0, sizeof(t));
memmove(t.chal, tr->chal, CHALLEN);
strcpy(t.cuid, tr->uid);
strcpy(t.suid, tr->uid);
for(i=0; i<DESKEYLEN; i++)
t.key[i] = fastrand();
t.num = AuthTc;
convT2M(&t, tbuf, authkey);
t.num = AuthTs;
convT2M(&t, tbuf+TICKETLEN, authkey);
return 0;
}
static int
gettickets(Ticketreq *tr, char *key, char *trbuf, char *tbuf)
{
if(getastickets(tr, trbuf, tbuf) >= 0)
return 0;
return mkserverticket(tr, key, tbuf);
}
AuthInfo*
p9any(int fd)
{
char buf[1024], buf2[1024], cchal[CHALLEN], *bbuf, *p, *dom, *u;
char *pass;
char tbuf[TICKETLEN+TICKETLEN+AUTHENTLEN], trbuf[TICKREQLEN];
char authkey[DESKEYLEN];
Authenticator auth;
int i, v2, n;
Ticketreq tr;
Ticket t;
AuthInfo *ai;
if((n = readstr(fd, buf, sizeof buf)) < 0)
fatal(1, "cannot read p9any negotiation");
bbuf = buf;
v2 = 0;
if(strncmp(buf, "v.2 ", 4) == 0){
v2 = 1;
bbuf += 4;
}
if(p = strchr(bbuf, ' '))
*p = 0;
p = bbuf;
if((dom = strchr(p, '@')) == nil)
fatal(1, "bad p9any domain");
*dom++ = 0;
if(strcmp(p, "p9sk1") != 0)
fatal(1, "server did not offer p9sk1");
sprint(buf2, "%s %s", p, dom);
if(write(fd, buf2, strlen(buf2)+1) != strlen(buf2)+1)
fatal(1, "cannot write user/domain choice in p9any");
if(v2){
if((n = readstr(fd, buf, sizeof buf)) != 3)
fatal(1, "cannot read OK in p9any");
if(memcmp(buf, "OK\0", 3) != 0)
fatal(1, "did not get OK in p9any");
}
for(i=0; i<CHALLEN; i++)
cchal[i] = fastrand();
if(write(fd, cchal, 8) != 8)
fatal(1, "cannot write p9sk1 challenge");
if(readn(fd, trbuf, TICKREQLEN) != TICKREQLEN)
fatal(1, "cannot read ticket request in p9sk1");
convM2TR(trbuf, &tr);
u = user;
pass = findkey(&u, tr.authdom);
if(pass == nil)
again:
pass = getkey(u, tr.authdom);
if(pass == nil)
fatal(1, "no password");
passtokey(authkey, pass);
memset(pass, 0, strlen(pass));
tr.type = AuthTreq;
strecpy(tr.hostid, tr.hostid+sizeof tr.hostid, u);
strecpy(tr.uid, tr.uid+sizeof tr.uid, u);
convTR2M(&tr, trbuf);
if(gettickets(&tr, authkey, trbuf, tbuf) < 0)
fatal(1, "cannot get auth tickets in p9sk1");
convM2T(tbuf, &t, authkey);
if(t.num != AuthTc){
print("?password mismatch with auth server\n");
goto again;
}
memmove(tbuf, tbuf+TICKETLEN, TICKETLEN);
auth.num = AuthAc;
memmove(auth.chal, tr.chal, CHALLEN);
auth.id = 0;
convA2M(&auth, tbuf+TICKETLEN, t.key);
if(write(fd, tbuf, TICKETLEN+AUTHENTLEN) != TICKETLEN+AUTHENTLEN)
fatal(1, "cannot send ticket and authenticator back in p9sk1");
if(readn(fd, tbuf, AUTHENTLEN) != AUTHENTLEN)
fatal(1, "cannot read authenticator in p9sk1");
convM2A(tbuf, &auth, t.key);
if(auth.num != AuthAs
|| memcmp(auth.chal, cchal, CHALLEN) != 0
|| auth.id != 0){
print("?you and auth server agree about password.\n");
print("?server is confused.\n");
fatal(1, "server lies got %llux.%d want %llux.%d", *(vlong*)auth.chal, auth.id, *(vlong*)cchal, 0);
}
//print("i am %s there.\n", t.suid);
ai = mallocz(sizeof(AuthInfo), 1);
ai->secret = mallocz(8, 1);
des56to64((uchar*)t.key, ai->secret);
ai->nsecret = 8;
ai->suid = strdup(t.suid);
ai->cuid = strdup(t.cuid);
memset(authkey, 0, sizeof authkey);
return ai;
}
static int
noauth(int fd)
{
ealgs = nil;
return fd;
}
static int
srvnoauth(int fd, char *user)
{
strecpy(user, user+MaxStr, getuser());
ealgs = nil;
return fd;
}
void
loghex(uchar *p, int n)
{
char buf[100];
int i;
for(i = 0; i < n; i++)
sprint(buf+2*i, "%2.2ux", p[i]);
// syslog(0, "cpu", buf);
}
static int
srvp9auth(int fd, char *user)
{
return -1;
}
/*
* set authentication mechanism
*/
int
setam(char *name)
{
for(am = authmethod; am->name != nil; am++)
if(strcmp(am->name, name) == 0)
return 0;
am = authmethod;
return -1;
}
/*
* set authentication mechanism and encryption/hash algs
*/
int
setamalg(char *s)
{
ealgs = strchr(s, ' ');
if(ealgs != nil)
*ealgs++ = 0;
return setam(s);
}
char*
getuser(void)
{
return getenv("USER");
}

10
drawterm.h Normal file
View File

@ -0,0 +1,10 @@
extern int havesecstore(char *addr, char *owner);
extern char *secstore;
extern char secstorebuf[65536];
extern char *secstorefetch(char *addr, char *owner, char *passwd);
extern char *authaddr;
extern char *readcons(char *prompt, char *def, int secret);
extern int exportfs(int, int);
extern char *user;
extern char *getkey(char*, char*);
extern char *findkey(char**, char*);

BIN
drawterm.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

72
drawterm.rc Normal file
View File

@ -0,0 +1,72 @@
//Microsoft Developer Studio generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ICON1 ICON DISCARDABLE "drawterm.ico"
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

BIN
drawterm.res Normal file

Binary file not shown.

16
exportfs/Makefile Normal file
View File

@ -0,0 +1,16 @@
LIB=libexportfs.a
CC=gcc
CFLAGS=-I../include -I. -I.. -c -ggdb -D_THREAD_SAFE -pthread
O=o
OFILES=\
exportfs.$O\
exportsrv.$O
$(LIB): $(OFILES)
ar r $(LIB) $(OFILES)
ranlib $(LIB)
%.$O: %.c
$(CC) $(CFLAGS) $*.c

503
exportfs/exportfs.c Normal file
View File

@ -0,0 +1,503 @@
/*
* exportfs - Export a plan 9 name space across a network
*/
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <libsec.h>
#include "drawterm.h"
#define Extern
#include "exportfs.h"
/* #define QIDPATH ((1LL<<48)-1) */
#define QIDPATH ((((vlong)1)<<48)-1)
vlong newqid = 0;
void (*fcalls[256])(Fsrpc*);
/* accounting and debugging counters */
int filecnt;
int freecnt;
int qidcnt;
int qfreecnt;
int ncollision;
int netfd;
int
exportfs(int fd, int msgsz)
{
char buf[ERRMAX], ebuf[ERRMAX];
Fsrpc *r;
int n;
char *dbfile, *srv, *file;
ulong initial;
fcalls[Tversion] = Xversion;
fcalls[Tauth] = Xauth;
fcalls[Tflush] = Xflush;
fcalls[Tattach] = Xattach;
fcalls[Twalk] = Xwalk;
fcalls[Topen] = slave;
fcalls[Tcreate] = Xcreate;
fcalls[Tclunk] = Xclunk;
fcalls[Tread] = slave;
fcalls[Twrite] = slave;
fcalls[Tremove] = Xremove;
fcalls[Tstat] = Xstat;
fcalls[Twstat] = Xwstat;
srvfd = -1;
netfd = fd;
//dbg = 1;
strcpy(buf, "this is buf");
strcpy(ebuf, "this is ebuf");
DEBUG(DFD, "exportfs: started\n");
// rfork(RFNOTEG);
messagesize = msgsz;
if(messagesize == 0){
messagesize = iounit(netfd);
if(messagesize == 0)
messagesize = 8192+IOHDRSZ;
}
Workq = emallocz(sizeof(Fsrpc)*Nr_workbufs);
// for(i=0; i<Nr_workbufs; i++)
// Workq[i].buf = emallocz(messagesize);
fhash = emallocz(sizeof(Fid*)*FHASHSIZE);
fmtinstall('F', fcallfmt);
initroot();
DEBUG(DFD, "exportfs: %s\n", buf);
/*
* Start serving file requests from the network
*/
for(;;) {
r = getsbuf();
if(r == 0)
fatal("Out of service buffers");
DEBUG(DFD, "read9p...");
n = read9pmsg(netfd, r->buf, messagesize);
if(n <= 0)
fatal(nil);
if(convM2S(r->buf, n, &r->work) == 0)
fatal("convM2S format error");
DEBUG(DFD, "%F\n", &r->work);
(fcalls[r->work.type])(r);
}
}
void
reply(Fcall *r, Fcall *t, char *err)
{
uchar *data;
int m, n;
t->tag = r->tag;
t->fid = r->fid;
if(err) {
t->type = Rerror;
t->ename = err;
}
else
t->type = r->type + 1;
DEBUG(DFD, "\t%F\n", t);
data = malloc(messagesize); /* not mallocz; no need to clear */
if(data == nil)
fatal(Enomem);
n = convS2M(t, data, messagesize);
if((m=write(netfd, data, n))!=n){
fprint(2, "wrote %d got %d (%r)\n", n, m);
fatal("write");
}
free(data);
}
Fid *
getfid(int nr)
{
Fid *f;
for(f = fidhash(nr); f; f = f->next)
if(f->nr == nr)
return f;
return 0;
}
int
freefid(int nr)
{
Fid *f, **l;
char buf[128];
l = &fidhash(nr);
for(f = *l; f; f = f->next) {
if(f->nr == nr) {
if(f->mid) {
sprint(buf, "/mnt/exportfs/%d", f->mid);
unmount(0, buf);
psmap[f->mid] = 0;
}
if(f->f) {
freefile(f->f);
f->f = nil;
}
*l = f->next;
f->next = fidfree;
fidfree = f;
return 1;
}
l = &f->next;
}
return 0;
}
Fid *
newfid(int nr)
{
Fid *new, **l;
int i;
l = &fidhash(nr);
for(new = *l; new; new = new->next)
if(new->nr == nr)
return 0;
if(fidfree == 0) {
fidfree = emallocz(sizeof(Fid) * Fidchunk);
for(i = 0; i < Fidchunk-1; i++)
fidfree[i].next = &fidfree[i+1];
fidfree[Fidchunk-1].next = 0;
}
new = fidfree;
fidfree = new->next;
memset(new, 0, sizeof(Fid));
new->next = *l;
*l = new;
new->nr = nr;
new->fid = -1;
new->mid = 0;
return new;
}
Fsrpc *
getsbuf(void)
{
static int ap;
int look, rounds;
Fsrpc *wb;
int small_instead_of_fast = 1;
if(small_instead_of_fast)
ap = 0; /* so we always start looking at the beginning and reuse buffers */
for(rounds = 0; rounds < 10; rounds++) {
for(look = 0; look < Nr_workbufs; look++) {
if(++ap == Nr_workbufs)
ap = 0;
if(Workq[ap].busy == 0)
break;
}
if(look == Nr_workbufs){
sleep(10 * rounds);
continue;
}
wb = &Workq[ap];
wb->pid = 0;
wb->canint = 0;
wb->flushtag = NOTAG;
wb->busy = 1;
if(wb->buf == nil) /* allocate buffers dynamically to keep size down */
wb->buf = emallocz(messagesize);
return wb;
}
fatal("No more work buffers");
return nil;
}
void
freefile(File *f)
{
File *parent, *child;
Loop:
f->ref--;
if(f->ref > 0)
return;
freecnt++;
if(f->ref < 0) abort();
DEBUG(DFD, "free %s\n", f->name);
/* delete from parent */
parent = f->parent;
if(parent->child == f)
parent->child = f->childlist;
else{
for(child=parent->child; child->childlist!=f; child=child->childlist)
if(child->childlist == nil)
fatal("bad child list");
child->childlist = f->childlist;
}
freeqid(f->qidt);
free(f->name);
f->name = nil;
free(f);
f = parent;
if(f != nil)
goto Loop;
}
File *
file(File *parent, char *name)
{
Dir *dir;
char *path;
File *f;
DEBUG(DFD, "\tfile: 0x%p %s name %s\n", parent, parent->name, name);
path = makepath(parent, name);
dir = dirstat(path);
free(path);
if(dir == nil)
return nil;
for(f = parent->child; f; f = f->childlist)
if(strcmp(name, f->name) == 0)
break;
if(f == nil){
f = emallocz(sizeof(File));
f->name = estrdup(name);
f->parent = parent;
f->childlist = parent->child;
parent->child = f;
parent->ref++;
f->ref = 0;
filecnt++;
}
f->ref++;
f->qid.type = dir->qid.type;
f->qid.vers = dir->qid.vers;
f->qidt = uniqueqid(dir);
f->qid.path = f->qidt->uniqpath;
f->inval = 0;
free(dir);
return f;
}
void
initroot(void)
{
Dir *dir;
root = emallocz(sizeof(File));
root->name = estrdup(".");
dir = dirstat(root->name);
if(dir == nil)
fatal("root stat");
root->ref = 1;
root->qid.vers = dir->qid.vers;
root->qidt = uniqueqid(dir);
root->qid.path = root->qidt->uniqpath;
root->qid.type = QTDIR;
free(dir);
psmpt = emallocz(sizeof(File));
psmpt->name = estrdup("/");
dir = dirstat(psmpt->name);
if(dir == nil)
return;
psmpt->ref = 1;
psmpt->qid.vers = dir->qid.vers;
psmpt->qidt = uniqueqid(dir);
psmpt->qid.path = psmpt->qidt->uniqpath;
free(dir);
psmpt = file(psmpt, "mnt");
if(psmpt == 0)
return;
psmpt = file(psmpt, "exportfs");
}
char*
makepath(File *p, char *name)
{
int i, n;
char *c, *s, *path, *seg[256];
seg[0] = name;
n = strlen(name)+2;
for(i = 1; i < 256 && p; i++, p = p->parent){
seg[i] = p->name;
n += strlen(p->name)+1;
}
path = malloc(n);
if(path == nil)
fatal("out of memory");
s = path;
while(i--) {
for(c = seg[i]; *c; c++)
*s++ = *c;
*s++ = '/';
}
while(s[-1] == '/')
s--;
*s = '\0';
return path;
}
int
qidhash(vlong path)
{
int h, n;
h = 0;
for(n=0; n<64; n+=Nqidbits){
h ^= path;
path >>= Nqidbits;
}
return h & (Nqidtab-1);
}
void
freeqid(Qidtab *q)
{
ulong h;
Qidtab *l;
q->ref--;
if(q->ref > 0)
return;
qfreecnt++;
h = qidhash(q->path);
if(qidtab[h] == q)
qidtab[h] = q->next;
else{
for(l=qidtab[h]; l->next!=q; l=l->next)
if(l->next == nil)
fatal("bad qid list");
l->next = q->next;
}
free(q);
}
Qidtab*
qidlookup(Dir *d)
{
ulong h;
Qidtab *q;
h = qidhash(d->qid.path);
for(q=qidtab[h]; q!=nil; q=q->next)
if(q->type==d->type && q->dev==d->dev && q->path==d->qid.path)
return q;
return nil;
}
int
qidexists(vlong path)
{
int h;
Qidtab *q;
for(h=0; h<Nqidtab; h++)
for(q=qidtab[h]; q!=nil; q=q->next)
if(q->uniqpath == path)
return 1;
return 0;
}
Qidtab*
uniqueqid(Dir *d)
{
ulong h;
vlong path;
Qidtab *q;
q = qidlookup(d);
if(q != nil){
q->ref++;
return q;
}
path = d->qid.path;
while(qidexists(path)){
DEBUG(DFD, "collision on %s\n", d->name);
/* collision: find a new one */
ncollision++;
path &= QIDPATH;
++newqid;
if(newqid >= (1<<16)){
DEBUG(DFD, "collision wraparound\n");
newqid = 1;
}
path |= newqid<<48;
DEBUG(DFD, "assign qid %.16llux\n", path);
}
q = mallocz(sizeof(Qidtab), 1);
if(q == nil)
fatal("no memory for qid table");
qidcnt++;
q->ref = 1;
q->type = d->type;
q->dev = d->dev;
q->path = d->qid.path;
q->uniqpath = path;
h = qidhash(d->qid.path);
q->next = qidtab[h];
qidtab[h] = q;
return q;
}
void
fatal(char *s, ...)
{
char buf[ERRMAX];
va_list arg;
Proc *m;
if (s) {
va_start(arg, s);
vsnprint(buf, ERRMAX, s, arg);
va_end(arg);
}
/* Clear away the slave children */
// for(m = Proclist; m; m = m->next)
// postnote(PNPROC, m->pid, "kill");
DEBUG(DFD, "%s\n", buf);
if (s)
sysfatal(buf);
else
exits(nil);
}

148
exportfs/exportfs.h Normal file
View File

@ -0,0 +1,148 @@
/*
* exportfs.h - definitions for exporting file server
*/
#define DEBUG if(!dbg){}else fprint
#define DFD 2
#define fidhash(s) fhash[s%FHASHSIZE]
#define Proc Exproc
typedef struct Fsrpc Fsrpc;
typedef struct Fid Fid;
typedef struct File File;
typedef struct Proc Proc;
typedef struct Qidtab Qidtab;
struct Fsrpc
{
int busy; /* Work buffer has pending rpc to service */
int pid; /* Pid of slave process executing the rpc */
int canint; /* Interrupt gate */
int flushtag; /* Tag on which to reply to flush */
Fcall work; /* Plan 9 incoming Fcall */
uchar *buf; /* Data buffer */
};
struct Fid
{
int fid; /* system fd for i/o */
File *f; /* File attached to this fid */
int mode;
int nr; /* fid number */
int mid; /* Mount id */
Fid *next; /* hash link */
};
struct File
{
char *name;
int ref;
Qid qid;
Qidtab *qidt;
int inval;
File *parent;
File *child;
File *childlist;
};
struct Proc
{
int pid;
int busy;
Proc *next;
};
struct Qidtab
{
int ref;
int type;
int dev;
vlong path;
vlong uniqpath;
Qidtab *next;
};
enum
{
MAXPROC = 50,
FHASHSIZE = 64,
Nr_workbufs = 50,
Fidchunk = 1000,
Npsmpt = 32,
Nqidbits = 5,
Nqidtab = (1<<Nqidbits),
};
#define Enomem Exenomem
#define Ebadfix Exebadfid
#define Enotdir Exenotdir
#define Edupfid Exedupfid
#define Eopen Exeopen
#define Exmnt Exexmnt
#define Emip Exemip
#define Enopsmt Exenopsmt
extern char Ebadfid[];
extern char Enotdir[];
extern char Edupfid[];
extern char Eopen[];
extern char Exmnt[];
extern char Enomem[];
extern char Emip[];
extern char Enopsmt[];
Extern Fsrpc *Workq;
Extern int dbg;
Extern File *root;
Extern File *psmpt;
Extern Fid **fhash;
Extern Fid *fidfree;
Extern Proc *Proclist;
Extern char psmap[Npsmpt];
Extern Qidtab *qidtab[Nqidtab];
Extern ulong messagesize;
Extern int srvfd;
/* File system protocol service procedures */
void Xattach(Fsrpc*);
void Xauth(Fsrpc*);
void Xclunk(Fsrpc*);
void Xcreate(Fsrpc*);
void Xflush(Fsrpc*);
void Xnop(Fsrpc*);
void Xremove(Fsrpc*);
void Xstat(Fsrpc*);
void Xversion(Fsrpc*);
void Xwalk(Fsrpc*);
void Xwstat(Fsrpc*);
void slave(Fsrpc*);
void reply(Fcall*, Fcall*, char*);
Fid *getfid(int);
int freefid(int);
Fid *newfid(int);
Fsrpc *getsbuf(void);
void initroot(void);
void fatal(char*, ...);
char* makepath(File*, char*);
File *file(File*, char*);
void freefile(File*);
void slaveopen(Fsrpc*);
void slaveread(Fsrpc*);
void slavewrite(Fsrpc*);
void blockingslave(void*);
void reopen(Fid *f);
void noteproc(int, char*);
void flushaction(void*, char*);
void pushfcall(char*);
Qidtab* uniqueqid(Dir*);
void freeqid(Qidtab*);
char* estrdup(char*);
void* emallocz(uint);
int readmessage(int, char*, int);
#define notify
#define noted
#define exits

679
exportfs/exportsrv.c Normal file
View File

@ -0,0 +1,679 @@
#include <u.h>
#include <libc.h>
#include <fcall.h>
#define Extern extern
#include "exportfs.h"
char Ebadfid[] = "Bad fid";
char Enotdir[] = "Not a directory";
char Edupfid[] = "Fid already in use";
char Eopen[] = "Fid already opened";
char Exmnt[] = "Cannot .. past mount point";
char Emip[] = "Mount in progress";
char Enopsmt[] = "Out of pseudo mount points";
char Enomem[] = "No memory";
char Eversion[] = "Bad 9P2000 version";
int iounit(int x)
{
return 8192+IOHDRSZ;
}
void*
emallocz(ulong n)
{
void *v;
v = mallocz(n, 1);
if(v == nil)
panic("out of memory");
return v;
}
ulong messagesize;
void
Xversion(Fsrpc *t)
{
Fcall rhdr;
if(t->work.msize > messagesize)
t->work.msize = messagesize;
messagesize = t->work.msize;
if(strncmp(t->work.version, "9P2000", 6) != 0){
reply(&t->work, &rhdr, Eversion);
return;
}
rhdr.version = "9P2000";
rhdr.msize = t->work.msize;
reply(&t->work, &rhdr, 0);
t->busy = 0;
}
void
Xauth(Fsrpc *t)
{
Fcall rhdr;
reply(&t->work, &rhdr, "exportfs: authentication not required");
t->busy = 0;
}
void
Xflush(Fsrpc *t)
{
Fsrpc *w, *e;
Fcall rhdr;
e = &Workq[Nr_workbufs];
for(w = Workq; w < e; w++) {
if(w->work.tag == t->work.oldtag) {
DEBUG(DFD, "\tQ busy %d pid %d can %d\n", w->busy, w->pid, w->canint);
if(w->busy && w->pid) {
w->flushtag = t->work.tag;
DEBUG(DFD, "\tset flushtag %d\n", t->work.tag);
// if(w->canint)
// postnote(PNPROC, w->pid, "flush");
t->busy = 0;
return;
}
}
}
reply(&t->work, &rhdr, 0);
DEBUG(DFD, "\tflush reply\n");
t->busy = 0;
}
void
Xattach(Fsrpc *t)
{
int i, nfd;
Fcall rhdr;
Fid *f;
char buf[128];
f = newfid(t->work.fid);
if(f == 0) {
reply(&t->work, &rhdr, Ebadfid);
t->busy = 0;
return;
}
if(srvfd >= 0){
/*
if(psmpt == 0){
Nomount:
reply(&t->work, &rhdr, Enopsmt);
t->busy = 0;
freefid(t->work.fid);
return;
}
for(i=0; i<Npsmpt; i++)
if(psmap[i] == 0)
break;
if(i >= Npsmpt)
goto Nomount;
sprint(buf, "%d", i);
f->f = file(psmpt, buf);
if(f->f == nil)
goto Nomount;
sprint(buf, "/mnt/exportfs/%d", i);
nfd = dup(srvfd, -1);
if(amount(nfd, buf, MREPL|MCREATE, t->work.aname) < 0){
errstr(buf, sizeof buf);
reply(&t->work, &rhdr, buf);
t->busy = 0;
freefid(t->work.fid);
close(nfd);
return;
}
psmap[i] = 1;
f->mid = i;
*/
}else{
f->f = root;
f->f->ref++;
}
rhdr.qid = f->f->qid;
reply(&t->work, &rhdr, 0);
t->busy = 0;
}
Fid*
clonefid(Fid *f, int new)
{
Fid *n;
n = newfid(new);
if(n == 0) {
n = getfid(new);
if(n == 0)
fatal("inconsistent fids");
if(n->fid >= 0)
close(n->fid);
freefid(new);
n = newfid(new);
if(n == 0)
fatal("inconsistent fids2");
}
n->f = f->f;
n->f->ref++;
return n;
}
void
Xwalk(Fsrpc *t)
{
char err[ERRMAX], *e;
Fcall rhdr;
Fid *f, *nf;
File *wf;
int i;
f = getfid(t->work.fid);
if(f == 0) {
reply(&t->work, &rhdr, Ebadfid);
t->busy = 0;
return;
}
nf = nil;
if(t->work.newfid != t->work.fid){
nf = clonefid(f, t->work.newfid);
f = nf;
}
rhdr.nwqid = 0;
e = nil;
for(i=0; i<t->work.nwname; i++){
if(i == MAXWELEM){
e = "Too many path elements";
break;
}
if(strcmp(t->work.wname[i], "..") == 0) {
if(f->f->parent == nil) {
e = Exmnt;
break;
}
wf = f->f->parent;
wf->ref++;
goto Accept;
}
wf = file(f->f, t->work.wname[i]);
if(wf == 0){
errstr(err, sizeof err);
e = err;
break;
}
Accept:
freefile(f->f);
rhdr.wqid[rhdr.nwqid++] = wf->qid;
f->f = wf;
continue;
}
if(nf!=nil && (e!=nil || rhdr.nwqid!=t->work.nwname))
freefid(t->work.newfid);
if(rhdr.nwqid > 0)
e = nil;
reply(&t->work, &rhdr, e);
t->busy = 0;
}
void
Xclunk(Fsrpc *t)
{
Fcall rhdr;
Fid *f;
f = getfid(t->work.fid);
if(f == 0) {
reply(&t->work, &rhdr, Ebadfid);
t->busy = 0;
return;
}
if(f->fid >= 0)
close(f->fid);
freefid(t->work.fid);
reply(&t->work, &rhdr, 0);
t->busy = 0;
}
void
Xstat(Fsrpc *t)
{
char err[ERRMAX], *path;
Fcall rhdr;
Fid *f;
Dir *d;
int s;
uchar *statbuf;
f = getfid(t->work.fid);
if(f == 0) {
reply(&t->work, &rhdr, Ebadfid);
t->busy = 0;
return;
}
if(f->fid >= 0)
d = dirfstat(f->fid);
else {
path = makepath(f->f, "");
d = dirstat(path);
free(path);
}
if(d == nil) {
errstr(err, sizeof err);
reply(&t->work, &rhdr, err);
t->busy = 0;
return;
}
d->qid.path = f->f->qidt->uniqpath;
s = sizeD2M(d);
statbuf = emallocz(s);
s = convD2M(d, statbuf, s);
free(d);
rhdr.nstat = s;
rhdr.stat = statbuf;
reply(&t->work, &rhdr, 0);
free(statbuf);
t->busy = 0;
}
static int
getiounit(int fd)
{
int n;
n = iounit(fd);
if(n > messagesize-IOHDRSZ)
n = messagesize-IOHDRSZ;
return n;
}
void
Xcreate(Fsrpc *t)
{
char err[ERRMAX], *path;
Fcall rhdr;
Fid *f;
File *nf;
f = getfid(t->work.fid);
if(f == 0) {
reply(&t->work, &rhdr, Ebadfid);
t->busy = 0;
return;
}
path = makepath(f->f, t->work.name);
f->fid = create(path, t->work.mode, t->work.perm);
free(path);
if(f->fid < 0) {
errstr(err, sizeof err);
reply(&t->work, &rhdr, err);
t->busy = 0;
return;
}
nf = file(f->f, t->work.name);
if(nf == 0) {
errstr(err, sizeof err);
reply(&t->work, &rhdr, err);
t->busy = 0;
return;
}
f->mode = t->work.mode;
freefile(f->f);
f->f = nf;
rhdr.qid = f->f->qid;
rhdr.iounit = getiounit(f->fid);
reply(&t->work, &rhdr, 0);
t->busy = 0;
}
void
Xremove(Fsrpc *t)
{
char err[ERRMAX], *path;
Fcall rhdr;
Fid *f;
f = getfid(t->work.fid);
if(f == 0) {
reply(&t->work, &rhdr, Ebadfid);
t->busy = 0;
return;
}
path = makepath(f->f, "");
DEBUG(DFD, "\tremove: %s\n", path);
if(remove(path) < 0) {
free(path);
errstr(err, sizeof err);
reply(&t->work, &rhdr, err);
t->busy = 0;
return;
}
free(path);
f->f->inval = 1;
if(f->fid >= 0)
close(f->fid);
freefid(t->work.fid);
reply(&t->work, &rhdr, 0);
t->busy = 0;
}
void
Xwstat(Fsrpc *t)
{
char err[ERRMAX], *path;
Fcall rhdr;
Fid *f;
int s;
char *strings;
Dir d;
f = getfid(t->work.fid);
if(f == 0) {
reply(&t->work, &rhdr, Ebadfid);
t->busy = 0;
return;
}
strings = emallocz(t->work.nstat); /* ample */
if(convM2D(t->work.stat, t->work.nstat, &d, strings) < 0){
rerrstr(err, sizeof err);
reply(&t->work, &rhdr, err);
t->busy = 0;
free(strings);
return;
}
if(f->fid >= 0)
s = dirfwstat(f->fid, &d);
else {
path = makepath(f->f, "");
s = dirwstat(path, &d);
free(path);
}
if(s < 0) {
rerrstr(err, sizeof err);
reply(&t->work, &rhdr, err);
}
else {
/* wstat may really be rename */
if(strcmp(d.name, f->f->name)!=0 && strcmp(d.name, "")!=0){
free(f->f->name);
f->f->name = estrdup(d.name);
}
reply(&t->work, &rhdr, 0);
}
free(strings);
t->busy = 0;
}
void
slave(Fsrpc *f)
{
Proc *p;
int pid;
static int nproc;
for(;;) {
for(p = Proclist; p; p = p->next) {
if(p->busy == 0) {
f->pid = p->pid;
p->busy = 1;
pid = rendezvous(p->pid, (ulong)f);
if(pid != p->pid)
fatal("rendezvous sync fail");
return;
}
}
if(++nproc > MAXPROC)
fatal("too many procs");
pid = kproc("slave", blockingslave, nil);
DEBUG(DFD, "slave pid %d\n", pid);
if(pid == -1)
fatal("kproc");
p = malloc(sizeof(Proc));
if(p == 0)
fatal("out of memory");
p->busy = 0;
p->pid = pid;
p->next = Proclist;
Proclist = p;
DEBUG(DFD, "parent %d rendez\n", pid);
rendezvous(pid, (ulong)p);
DEBUG(DFD, "parent %d went\n", pid);
}
}
void
blockingslave(void *x)
{
Fsrpc *p;
Fcall rhdr;
Proc *m;
int pid;
USED(x);
notify(flushaction);
pid = getpid();
DEBUG(DFD, "blockingslave %d rendez\n", pid);
m = (Proc*)rendezvous(pid, 0);
DEBUG(DFD, "blockingslave %d rendez got %p\n", pid, m);
for(;;) {
p = (Fsrpc*)rendezvous(pid, pid);
if((int)p == ~0) /* Interrupted */
continue;
DEBUG(DFD, "\tslave: %d %F b %d p %d\n", pid, &p->work, p->busy, p->pid);
if(p->flushtag != NOTAG)
goto flushme;
switch(p->work.type) {
case Tread:
slaveread(p);
break;
case Twrite:
slavewrite(p);
break;
case Topen:
slaveopen(p);
break;
default:
reply(&p->work, &rhdr, "exportfs: slave type error");
}
if(p->flushtag != NOTAG) {
flushme:
p->work.type = Tflush;
p->work.tag = p->flushtag;
reply(&p->work, &rhdr, 0);
}
p->busy = 0;
m->busy = 0;
}
}
int
openmount(int sfd)
{
werrstr("openmount not implemented");
return -1;
}
void
slaveopen(Fsrpc *p)
{
char err[ERRMAX], *path;
Fcall *work, rhdr;
Fid *f;
Dir *d;
work = &p->work;
f = getfid(work->fid);
if(f == 0) {
reply(work, &rhdr, Ebadfid);
return;
}
if(f->fid >= 0) {
close(f->fid);
f->fid = -1;
}
path = makepath(f->f, "");
DEBUG(DFD, "\topen: %s %d\n", path, work->mode);
p->canint = 1;
if(p->flushtag != NOTAG){
free(path);
return;
}
/* There is a race here I ignore because there are no locks */
f->fid = open(path, work->mode);
free(path);
p->canint = 0;
if(f->fid < 0 || (d = dirfstat(f->fid)) == nil) {
Error:
errstr(err, sizeof err);
reply(work, &rhdr, err);
return;
}
f->f->qid = d->qid;
free(d);
if(f->f->qid.type & QTMOUNT){ /* fork new exportfs for this */
f->fid = openmount(f->fid);
if(f->fid < 0)
goto Error;
}
DEBUG(DFD, "\topen: fd %d\n", f->fid);
f->mode = work->mode;
rhdr.iounit = getiounit(f->fid);
rhdr.qid = f->f->qid;
reply(work, &rhdr, 0);
}
void
slaveread(Fsrpc *p)
{
Fid *f;
int n, r;
Fcall *work, rhdr;
char *data, err[ERRMAX];
work = &p->work;
f = getfid(work->fid);
if(f == 0) {
reply(work, &rhdr, Ebadfid);
return;
}
n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count;
p->canint = 1;
if(p->flushtag != NOTAG)
return;
data = malloc(n);
if(data == nil)
fatal(Enomem);
/* can't just call pread, since directories must update the offset */
r = pread(f->fid, data, n, work->offset);
p->canint = 0;
if(r < 0) {
free(data);
errstr(err, sizeof err);
reply(work, &rhdr, err);
return;
}
DEBUG(DFD, "\tread: fd=%d %d bytes\n", f->fid, r);
rhdr.data = data;
rhdr.count = r;
reply(work, &rhdr, 0);
free(data);
}
void
slavewrite(Fsrpc *p)
{
char err[ERRMAX];
Fcall *work, rhdr;
Fid *f;
int n;
work = &p->work;
f = getfid(work->fid);
if(f == 0) {
reply(work, &rhdr, Ebadfid);
return;
}
n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count;
p->canint = 1;
if(p->flushtag != NOTAG)
return;
n = pwrite(f->fid, work->data, n, work->offset);
p->canint = 0;
if(n < 0) {
errstr(err, sizeof err);
reply(work, &rhdr, err);
return;
}
DEBUG(DFD, "\twrite: %d bytes fd=%d\n", n, f->fid);
rhdr.count = n;
reply(work, &rhdr, 0);
}
void
reopen(Fid *f)
{
USED(f);
fatal("reopen");
}
void
flushaction(void *a, char *cause)
{
USED(a);
if(strncmp(cause, "sys:", 4) == 0 && !strstr(cause, "pipe")) {
fprint(2, "exportsrv: note: %s\n", cause);
exits("noted");
}
if(strncmp(cause, "kill", 4) == 0)
noted(NDFLT);
noted(NCONT);
}

11
exportfs/mkfile Normal file
View File

@ -0,0 +1,11 @@
<$DSRC/mkfile-$CONF
TARG=libexportfs.$L
OFILES=\
exportfs.$O\
exportsrv.$O
HFILES=\
exportfs.h
<$DSRC/mklib-$CONF

23
gui-win32/alloc.c Normal file
View File

@ -0,0 +1,23 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
Memimage*
allocmemimage(Rectangle r, ulong chan)
{
return _allocmemimage(r, chan);
}
void
freememimage(Memimage *i)
{
_freememimage(i);
}
void
memfillcolor(Memimage *i, ulong val)
{
_memfillcolor(i, val);
}

10
gui-win32/cload.c Normal file
View File

@ -0,0 +1,10 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
int
cloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
{
return _cloadmemimage(i, r, data, ndata);
}

22
gui-win32/draw.c Normal file
View File

@ -0,0 +1,22 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
void
memimagedraw(Memimage *dst, Rectangle r, Memimage *src, Point sp, Memimage *mask, Point mp, int op)
{
_memimagedraw(_memimagedrawsetup(dst, r, src, sp, mask, mp, op));
}
ulong
pixelbits(Memimage *m, Point p)
{
return _pixelbits(m, p);
}
void
memimageinit(void)
{
_memimageinit();
}

10
gui-win32/load.c Normal file
View File

@ -0,0 +1,10 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
int
loadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
{
return _loadmemimage(i, r, data, ndata);
}

14
gui-win32/mkfile Normal file
View File

@ -0,0 +1,14 @@
<$DSRC/mkfile-$CONF
TARG=libgui.$L
OFILES=\
alloc.$O\
cload.$O\
draw.$O\
load.$O\
screen.$O\
wstrtoutf.$O
HFILES=\
<$DSRC/mklib-$CONF

642
gui-win32/screen.c Normal file
View File

@ -0,0 +1,642 @@
#include <windows.h>
// #include "winduhz.h"
#undef Rectangle
#define Rectangle _Rectangle
#include <u.h>
#include <libc.h>
#include <dat.h>
#include <draw.h>
#include <memdraw.h>
#include "error.h"
#include "screen.h"
#include "keyboard.h"
#include "fns.h"
Memimage *gscreen;
Screeninfo screen;
extern int mousequeue;
static int depth;
static HINSTANCE inst;
static HWND window;
static HPALETTE palette;
static LOGPALETTE *logpal;
static Lock gdilock;
static BITMAPINFO *bmi;
static HCURSOR hcursor;
static void winproc(void *);
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
static void paletteinit(void);
static void bmiinit(void);
static void screenload2(Rectangle r, int ldepth, uchar *p, Point pt, int step);
static int readybit;
static Rendez rend;
Point ZP;
static
isready(void*a)
{
return readybit;
}
void
screeninit(void)
{
int fmt;
int dx, dy;
memimageinit();
if(depth == 0)
depth = GetDeviceCaps(GetDC(NULL), BITSPIXEL);
switch(depth){
case 32:
screen.dibtype = DIB_RGB_COLORS;
screen.depth = 32;
fmt = XRGB32;
break;
case 24:
screen.dibtype = DIB_RGB_COLORS;
screen.depth = 24;
fmt = RGB24;
break;
case 16:
screen.dibtype = DIB_RGB_COLORS;
screen.depth = 16;
fmt = RGB15; /* [sic] */
break;
case 8:
default:
screen.dibtype = DIB_PAL_COLORS;
screen.depth = 8;
depth = 8;
fmt = CMAP8;
break;
}
dx = GetDeviceCaps(GetDC(NULL), HORZRES);
dy = GetDeviceCaps(GetDC(NULL), VERTRES);
gscreen = allocmemimage(Rect(0,0,dx,dy), fmt);
kproc("winscreen", winproc, 0);
sleep(&rend, isready, 0);
}
uchar*
attachscreen(Rectangle *r, ulong *chan, int *depth, int *width, int *softscreen, void **X)
{
*r = gscreen->r;
*chan = gscreen->chan;
*depth = gscreen->depth;
*width = gscreen->width;
*softscreen = 1;
return gscreen->data->bdata;
}
void
flushmemscreen(Rectangle r)
{
screenload(r, gscreen->depth, byteaddr(gscreen, ZP), ZP,
gscreen->width*sizeof(ulong));
// Sleep(100);
}
void
screenload(Rectangle r, int depth, uchar *p, Point pt, int step)
{
int dx, dy, delx;
HDC hdc;
RECT winr;
if(depth != gscreen->depth)
panic("screenload: bad ldepth");
/*
* Sometimes we do get rectangles that are off the
* screen to the negative axes, for example, when
* dragging around a window border in a Move operation.
*/
if(rectclip(&r, gscreen->r) == 0)
return;
if(step&3 != 0 || ((pt.x*depth)%32) != 0 || (ulong)p&3 != 0)
panic("screenload: bad params %d %d %ux", step, pt.x, p);
dx = r.max.x - r.min.x;
dy = r.max.y - r.min.y;
if(dx <= 0 || dy <= 0)
return;
if(depth == 24)
delx = r.min.x % 4;
else
delx = r.min.x & (31/depth);
p += (r.min.y-pt.y)*step;
p += ((r.min.x-delx-pt.x)*depth)>>3;
if(GetWindowRect(window, &winr)==0)
return;
if(rectclip(&r, Rect(0, 0, winr.right-winr.left, winr.bottom-winr.top))==0)
return;
lock(&gdilock);
hdc = GetDC(window);
SelectPalette(hdc, palette, 0);
RealizePalette(hdc);
//FillRect(hdc,(void*)&r, GetStockObject(BLACK_BRUSH));
//GdiFlush();
//Sleep(100);
bmi->bmiHeader.biWidth = (step*8)/depth;
bmi->bmiHeader.biHeight = -dy; /* - => origin upper left */
StretchDIBits(hdc, r.min.x, r.min.y, dx, dy,
delx, 0, dx, dy, p, bmi, screen.dibtype, SRCCOPY);
ReleaseDC(window, hdc);
GdiFlush();
unlock(&gdilock);
}
static void
winproc(void *a)
{
WNDCLASS wc;
MSG msg;
inst = GetModuleHandle(NULL);
paletteinit();
bmiinit();
terminit();
wc.style = 0;
wc.lpfnWndProc = WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = inst;
wc.hIcon = LoadIcon(inst, NULL);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = 0;
wc.lpszClassName = "9pmgraphics";
RegisterClass(&wc);
window = CreateWindowEx(
0, /* extended style */
"9pmgraphics", /* class */
"drawterm screen", /* caption */
WS_OVERLAPPEDWINDOW, /* style */
CW_USEDEFAULT, /* init. x pos */
CW_USEDEFAULT, /* init. y pos */
CW_USEDEFAULT, /* init. x size */
CW_USEDEFAULT, /* init. y size */
NULL, /* parent window (actually owner window for overlapped)*/
NULL, /* menu handle */
inst, /* program handle */
NULL /* create parms */
);
if(window == nil)
panic("can't make window\n");
ShowWindow(window, SW_SHOWDEFAULT);
UpdateWindow(window);
readybit = 1;
wakeup(&rend);
screen.reshaped = 0;
while(GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// MessageBox(0, "winproc", "exits", MB_OK);
ExitProcess(0);
}
int
col(int v, int n)
{
int i, c;
c = 0;
for(i = 0; i < 8; i += n)
c |= v << (16-(n+i));
return c >> 8;
}
void
paletteinit(void)
{
PALETTEENTRY *pal;
int r, g, b, cr, cg, cb, v;
int num, den;
int i, j;
logpal = mallocz(sizeof(LOGPALETTE) + 256*sizeof(PALETTEENTRY), 1);
if(logpal == nil)
panic("out of memory");
logpal->palVersion = 0x300;
logpal->palNumEntries = 256;
pal = logpal->palPalEntry;
for(r=0,i=0; r<4; r++) {
for(v=0; v<4; v++,i+=16){
for(g=0,j=v-r; g<4; g++) {
for(b=0; b<4; b++,j++){
den=r;
if(g>den)
den=g;
if(b>den)
den=b;
/* divide check -- pick grey shades */
if(den==0)
cr=cg=cb=v*17;
else{
num=17*(4*den+v);
cr=r*num/den;
cg=g*num/den;
cb=b*num/den;
}
pal[i+(j&15)].peRed = cr;
pal[i+(j&15)].peGreen = cg;
pal[i+(j&15)].peBlue = cb;
pal[i+(j&15)].peFlags = 0;
}
}
}
}
palette = CreatePalette(logpal);
}
void
getcolor(ulong i, ulong *r, ulong *g, ulong *b)
{
PALETTEENTRY *pal;
pal = logpal->palPalEntry;
*r = pal[i].peRed;
*g = pal[i].peGreen;
*b = pal[i].peBlue;
}
void
bmiinit(void)
{
ushort *p;
int i;
bmi = mallocz(sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD), 1);
if(bmi == 0)
panic("out of memory");
bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi->bmiHeader.biWidth = 0;
bmi->bmiHeader.biHeight = 0; /* - => origin upper left */
bmi->bmiHeader.biPlanes = 1;
bmi->bmiHeader.biBitCount = depth;
bmi->bmiHeader.biCompression = BI_RGB;
bmi->bmiHeader.biSizeImage = 0;
bmi->bmiHeader.biXPelsPerMeter = 0;
bmi->bmiHeader.biYPelsPerMeter = 0;
bmi->bmiHeader.biClrUsed = 0;
bmi->bmiHeader.biClrImportant = 0; /* number of important colors: 0 means all */
p = (ushort*)bmi->bmiColors;
for(i = 0; i < 256; i++)
p[i] = i;
}
LRESULT CALLBACK
WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
PAINTSTRUCT paint;
HDC hdc;
LONG x, y, b;
int i;
Rectangle r;
switch(msg) {
case WM_CREATE:
break;
case WM_SETCURSOR:
/* User set */
if(hcursor != NULL) {
SetCursor(hcursor);
return 1;
}
return DefWindowProc(hwnd, msg, wparam, lparam);
case WM_MOUSEMOVE:
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_RBUTTONUP:
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
x = LOWORD(lparam);
y = HIWORD(lparam);
b = 0;
if(wparam & MK_LBUTTON)
b = 1;
if(wparam & MK_MBUTTON)
b |= 2;
if(wparam & MK_RBUTTON) {
if(wparam & MK_SHIFT)
b |= 2;
else
b |= 4;
}
lock(&mouse.lk);
i = mouse.wi;
if(mousequeue) {
if(i == mouse.ri || mouse.lastb != b || mouse.trans) {
mouse.wi = (i+1)%Mousequeue;
if(mouse.wi == mouse.ri)
mouse.ri = (mouse.ri+1)%Mousequeue;
mouse.trans = mouse.lastb != b;
} else {
i = (i-1+Mousequeue)%Mousequeue;
}
} else {
mouse.wi = (i+1)%Mousequeue;
mouse.ri = i;
}
mouse.queue[i].xy.x = x;
mouse.queue[i].xy.y = y;
mouse.queue[i].buttons = b;
mouse.queue[i].msec = ticks();
mouse.lastb = b;
unlock(&mouse.lk);
wakeup(&mouse.r);
break;
case WM_CHAR:
/* repeat count is lparam & 0xf */
switch(wparam){
case '\n':
wparam = '\r';
break;
case '\r':
wparam = '\n';
break;
}
kbdputc(kbdq, wparam);
break;
case WM_SYSKEYUP:
break;
case WM_SYSKEYDOWN:
case WM_KEYDOWN:
switch(wparam) {
case VK_MENU:
kbdputc(kbdq, Kalt);
break;
case VK_INSERT:
kbdputc(kbdq, Kins);
break;
case VK_DELETE:
// kbdputc(kbdq, Kdel);
kbdputc(kbdq, 0x7f); // should have Kdel in keyboard.h
break;
case VK_UP:
kbdputc(kbdq, Kup);
break;
case VK_DOWN:
kbdputc(kbdq, Kdown);
break;
case VK_LEFT:
kbdputc(kbdq, Kleft);
break;
case VK_RIGHT:
kbdputc(kbdq, Kright);
break;
}
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_PALETTECHANGED:
if((HWND)wparam == hwnd)
break;
/* fall through */
case WM_QUERYNEWPALETTE:
hdc = GetDC(hwnd);
SelectPalette(hdc, palette, 0);
if(RealizePalette(hdc) != 0)
InvalidateRect(hwnd, nil, 0);
ReleaseDC(hwnd, hdc);
break;
case WM_PAINT:
hdc = BeginPaint(hwnd, &paint);
r.min.x = paint.rcPaint.left;
r.min.y = paint.rcPaint.top;
r.max.x = paint.rcPaint.right;
r.max.y = paint.rcPaint.bottom;
flushmemscreen(r);
EndPaint(hwnd, &paint);
break;
case WM_COMMAND:
case WM_SETFOCUS:
case WM_DEVMODECHANGE:
case WM_WININICHANGE:
case WM_INITMENU:
default:
return DefWindowProc(hwnd, msg, wparam, lparam);
}
return 0;
}
void
mouseset(Point xy)
{
POINT pt;
pt.x = xy.x;
pt.y = xy.y;
MapWindowPoints(window, 0, &pt, 1);
SetCursorPos(pt.x, pt.y);
}
void
setcursor(void)
{
HCURSOR nh;
int x, y, h, w;
uchar *sp, *cp;
uchar *and, *xor;
h = GetSystemMetrics(SM_CYCURSOR);
w = (GetSystemMetrics(SM_CXCURSOR)+7)/8;
and = mallocz(h*w, 1);
memset(and, 0xff, h*w);
xor = mallocz(h*w, 1);
lock(&cursor.lk);
for(y=0,sp=cursor.set,cp=cursor.clr; y<16; y++) {
for(x=0; x<2; x++) {
and[y*w+x] = ~(*sp|*cp);
xor[y*w+x] = ~*sp & *cp;
cp++;
sp++;
}
}
nh = CreateCursor(inst, -cursor.offset.x, -cursor.offset.y,
GetSystemMetrics(SM_CXCURSOR), h,
and, xor);
if(nh != NULL) {
SetCursor(nh);
if(hcursor != NULL)
DestroyCursor(hcursor);
hcursor = nh;
}
unlock(&cursor.lk);
free(and);
free(xor);
PostMessage(window, WM_SETCURSOR, (int)window, 0);
}
void
cursorarrow(void)
{
if(hcursor != 0) {
DestroyCursor(hcursor);
hcursor = 0;
}
SetCursor(LoadCursor(0, IDC_ARROW));
PostMessage(window, WM_SETCURSOR, (int)window, 0);
}
void
setcolor(ulong index, ulong red, ulong green, ulong blue)
{
}
uchar*
clipreadunicode(HANDLE h)
{
Rune *p;
int n;
uchar *q;
p = GlobalLock(h);
n = wstrutflen(p)+1;
q = malloc(n);
wstrtoutf(q, p, n);
GlobalUnlock(h);
return q;
}
uchar *
clipreadutf(HANDLE h)
{
uchar *p;
p = GlobalLock(h);
p = strdup(p);
GlobalUnlock(h);
return p;
}
uchar*
clipread()
{
HANDLE h;
uchar *p;
if(!OpenClipboard(window)) {
oserror();
return strdup("");
}
if(h = GetClipboardData(CF_UNICODETEXT))
p = clipreadunicode(h);
else if(h = GetClipboardData(CF_TEXT))
p = clipreadutf(h);
else {
oserror();
p = strdup("");
}
CloseClipboard();
return p;
}
int
clipwrite(char *buf)
{
HANDLE h;
char *p, *e;
Rune *rp;
int n = strlen(buf);
if(!OpenClipboard(window)) {
oserror();
return -1;
}
if(!EmptyClipboard()) {
oserror();
CloseClipboard();
return -1;
}
h = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, (n+1)*sizeof(Rune));
if(h == NULL)
panic("out of memory");
rp = GlobalLock(h);
p = buf;
e = p+n;
while(p<e)
p += chartorune(rp++, p);
*rp = 0;
GlobalUnlock(h);
SetClipboardData(CF_UNICODETEXT, h);
h = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, n+1);
if(h == NULL)
panic("out of memory");
p = GlobalLock(h);
memcpy(p, buf, n);
p[n] = 0;
GlobalUnlock(h);
SetClipboardData(CF_TEXT, h);
CloseClipboard();
return n;
}
int
atlocalconsole(void)
{
return 1;
}

35
gui-win32/wstrtoutf.c Normal file
View File

@ -0,0 +1,35 @@
#include <u.h>
#include <libc.h>
int
wstrutflen(Rune *s)
{
int n;
for(n=0; *s; n+=runelen(*s),s++)
;
return n;
}
int
wstrtoutf(char *s, Rune *t, int n)
{
int i;
char *s0;
s0 = s;
if(n <= 0)
return wstrutflen(t)+1;
while(*t) {
if(n < UTFmax+1 && n < runelen(*t)+1) {
*s = 0;
return i+wstrutflen(t)+1;
}
i = runetochar(s, t);
s += i;
n -= i;
t++;
}
*s = 0;
return s-s0;
}

20
gui-x11/Makefile Normal file
View File

@ -0,0 +1,20 @@
LIB=libx11.a
CC=gcc
CFLAGS=-I../include -I. -I/usr/X11R6/include -I../kern -c -ggdb -D_THREAD_SAFE -pthread
O=o
OFILES=\
alloc.$O\
cload.$O\
draw.$O\
load.$O\
screen.$O\
keysym2ucs-x11.$O
$(LIB): $(OFILES)
ar r $(LIB) $(OFILES)
ranlib $(LIB)
%.$O: %.c
$(CC) $(CFLAGS) $*.c

209
gui-x11/alloc.c Normal file
View File

@ -0,0 +1,209 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include "xmem.h"
/* perfect approximation to NTSC = .299r+.587g+.114b when 0 ≤ r,g,b < 256 */
#define RGB2K(r,g,b) ((156763*(r)+307758*(g)+59769*(b))>>19)
Memimage*
xallocmemimage(Rectangle r, ulong chan, int pmid)
{
Memimage *m;
Xmem *xm;
XImage *xi;
int offset;
int d;
m = _allocmemimage(r, chan);
if(chan != GREY1 && chan != xscreenchan)
return m;
d = m->depth;
xm = mallocz(sizeof(Xmem), 1);
if(pmid != PMundef)
xm->pmid = pmid;
else
xm->pmid = XCreatePixmap(xdisplay, xscreenid, Dx(r), Dy(r), (d==32) ? 24 : d);
if(m->depth == 24)
offset = r.min.x&(4-1);
else
offset = r.min.x&(31/m->depth);
r.min.x -= offset;
assert(wordsperline(r, m->depth) <= m->width);
xi = XCreateImage(xdisplay, xvis, m->depth==32?24:m->depth, ZPixmap, 0,
(char*)m->data->bdata, Dx(r), Dy(r), 32, m->width*sizeof(ulong));
if(xi == nil){
_freememimage(m);
return nil;
}
xm->xi = xi;
xm->pc = getcallerpc(&r);
xm->r = r;
/*
* Set the parameters of the XImage so its memory looks exactly like a
* Memimage, so we can call _memimagedraw on the same data. All frame
* buffers we've seen, and Plan 9's graphics code, require big-endian
* bits within bytes, but little endian byte order within pixels.
*/
xi->bitmap_unit = m->depth < 8 || m->depth == 24 ? 8 : m->depth;
xi->byte_order = LSBFirst;
xi->bitmap_bit_order = MSBFirst;
xi->bitmap_pad = 32;
xm->r = Rect(0,0,0,0);
XInitImage(xi);
XFlush(xdisplay);
m->X = xm;
return m;
}
Memimage*
allocmemimage(Rectangle r, ulong chan)
{
return xallocmemimage(r, chan, PMundef);
}
void
freememimage(Memimage *m)
{
Xmem *xm;
if(m == nil)
return;
if(m->data->ref == 1){
if((xm = m->X) != nil){
if(xm->xi){
xm->xi->data = nil;
XFree(xm->xi);
}
XFreePixmap(xdisplay, xm->pmid);
free(xm);
m->X = nil;
}
}
_freememimage(m);
}
void
memfillcolor(Memimage *m, ulong val)
{
_memfillcolor(m, val);
if(m->X){
if((val & 0xFF) == 0xFF)
xfillcolor(m, m->r, _rgbatoimg(m, val));
else
putXdata(m, m->r);
}
}
static void
addrect(Rectangle *rp, Rectangle r)
{
if(rp->min.x >= rp->max.x)
*rp = r;
else
combinerect(rp, r);
}
XImage*
getXdata(Memimage *m, Rectangle r)
{
uchar *p;
int x, y;
Xmem *xm;
Point xdelta, delta;
Point tp;
xm = m->X;
if(xm == nil)
return;
assert(xm != nil && xm->xi != nil);
if(xm->dirty == 0)
return xm->xi;
r = xm->dirtyr;
if(Dx(r)==0 || Dy(r)==0)
return xm->xi;
delta = subpt(r.min, m->r.min);
tp = xm->r.min; /* avoid unaligned access on digital unix */
xdelta = subpt(r.min, tp);
XGetSubImage(xdisplay, xm->pmid, delta.x, delta.y, Dx(r), Dy(r),
AllPlanes, ZPixmap, xm->xi, xdelta.x, xdelta.y);
if(xtblbit && m->chan == CMAP8)
for(y=r.min.y; y<r.max.y; y++)
for(x=r.min.x, p=byteaddr(m, Pt(x,y)); x<r.max.x; x++, p++)
*p = x11toplan9[*p];
xm->dirty = 0;
xm->dirtyr = Rect(0,0,0,0);
return xm->xi;
}
void
putXdata(Memimage *m, Rectangle r)
{
Xmem *xm;
XImage *xi;
GC g;
int offset;
Point xdelta, delta;
Point tp;
int x, y;
uchar *p;
xm = m->X;
if(xm == nil)
return;
assert(xm != nil);
assert(xm->xi != nil);
xi = xm->xi;
g = (m->chan == GREY1) ? xgccopy0 : xgccopy;
if(m->depth == 24)
offset = r.min.x % 4;
else
offset = m->r.min.x & (31/m->depth);
delta = subpt(r.min, m->r.min);
tp = xm->r.min; /* avoid unaligned access on digital unix */
xdelta = subpt(r.min, tp);
if(xtblbit && m->chan == CMAP8)
for(y=r.min.y; y<r.max.y; y++)
for(x=r.min.x, p=byteaddr(m, Pt(x,y)); x<r.max.x; x++, p++)
*p = plan9tox11[*p];
XPutImage(xdisplay, xm->pmid, g, xi, xdelta.x, xdelta.y, delta.x, delta.y, Dx(r), Dy(r));
if(xtblbit && m->chan == CMAP8)
for(y=r.min.y; y<r.max.y; y++)
for(x=r.min.x, p=byteaddr(m, Pt(x,y)); x<r.max.x; x++, p++)
*p = x11toplan9[*p];
}
void
dirtyXdata(Memimage *m, Rectangle r)
{
Xmem *xm;
if((xm = m->X) != nil){
xm->dirty = 1;
addrect(&xm->dirtyr, r);
}
}

16
gui-x11/cload.c Normal file
View File

@ -0,0 +1,16 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include "xmem.h"
int
cloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
{
int n;
n = _cloadmemimage(i, r, data, ndata);
if(n > 0 && i->X)
putXdata(i, r);
return n;
}

189
gui-x11/draw.c Normal file
View File

@ -0,0 +1,189 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include "xmem.h"
void xfillcolor(Memimage*, Rectangle, ulong);
static int xdraw(Memdrawparam*);
int xgcfillcolor = 0;
int xgcfillcolor0 = 0;
int xgczeropm = 0;
int xgczeropm0 = 0;
int xgcsimplecolor = 0;
int xgcsimplecolor0 = 0;
int xgcsimplepm = 0;
int xgcsimplepm0 = 0;
int xgcreplsrctile = 0;
int xgcreplsrctile0 = 0;
void
memimageinit(void)
{
static int didinit = 0;
if(didinit)
return;
didinit = 1;
_memimageinit();
xfillcolor(memblack, memblack->r, 0);
xfillcolor(memwhite, memwhite->r, 1);
}
void
memimagedraw(Memimage *dst, Rectangle r, Memimage *src, Point sp, Memimage *mask, Point mp, int op)
{
int didx;
Rectangle dr, mr, sr;
Memdrawparam *par;
if((par = _memimagedrawsetup(dst, r, src, sp, mask, mp, op)) == nil)
return;
_memimagedraw(par);
if(!xdraw(par))
putXdata(dst, par->r);
}
void
xfillcolor(Memimage *m, Rectangle r, ulong v)
{
GC gc;
Xmem *dxm;
dxm = m->X;
assert(dxm != nil);
r = rectsubpt(r, m->r.min);
if(m->chan == GREY1){
gc = xgcfill0;
if(xgcfillcolor0 != v){
XSetForeground(xdisplay, gc, v);
xgcfillcolor0 = v;
}
}else{
if(m->chan == CMAP8 && xtblbit)
v = plan9tox11[v];
gc = xgcfill;
if(xgcfillcolor != v){
XSetForeground(xdisplay, gc, v);
xgcfillcolor = v;
}
}
XFillRectangle(xdisplay, dxm->pmid, gc, r.min.x, r.min.y, Dx(r), Dy(r));
}
static int
xdraw(Memdrawparam *par)
{
int dy, dx;
unsigned m;
Memimage *src, *dst, *mask;
Xmem *dxm, *sxm, *mxm;
GC gc;
Rectangle r, sr, mr;
ulong sdval;
dx = Dx(par->r);
dy = Dy(par->r);
src = par->src;
dst = par->dst;
mask = par->mask;
r = par->r;
sr = par->sr;
mr = par->mr;
sdval = par->sdval;
return 0;
if((dxm = dst->X) == nil)
return 0;
/*
* If we have an opaque mask and source is one opaque pixel we can convert to the
* destination format and just XFillRectangle.
*/
m = Simplesrc|Simplemask|Fullmask;
if((par->state&m)==m){
xfillcolor(dst, r, sdval);
dirtyXdata(dst, par->r);
return 1;
}
/*
* If no source alpha, an opaque mask, we can just copy the
* source onto the destination. If the channels are the same and
* the source is not replicated, XCopyArea suffices.
*/
m = Simplemask|Fullmask;
if((par->state&(m|Replsrc))==m && src->chan == dst->chan && src->X){
sxm = src->X;
r = rectsubpt(r, dst->r.min);
sr = rectsubpt(sr, src->r.min);
if(dst->chan == GREY1)
gc = xgccopy0;
else
gc = xgccopy;
XCopyArea(xdisplay, sxm->pmid, dxm->pmid, gc,
sr.min.x, sr.min.y, dx, dy, r.min.x, r.min.y);
dirtyXdata(dst, par->r);
return 1;
}
/*
* If no source alpha, a 1-bit mask, and a simple source
* we can just copy through the mask onto the destination.
*/
if(dst->X && mask->X && !(mask->flags&Frepl)
&& mask->chan == GREY1 && (par->state&Simplesrc)){
Point p;
mxm = mask->X;
r = rectsubpt(r, dst->r.min);
mr = rectsubpt(mr, mask->r.min);
p = subpt(r.min, mr.min);
if(dst->chan == GREY1){
gc = xgcsimplesrc0;
if(xgcsimplecolor0 != sdval){
XSetForeground(xdisplay, gc, sdval);
xgcsimplecolor0 = sdval;
}
if(xgcsimplepm0 != mxm->pmid){
XSetStipple(xdisplay, gc, mxm->pmid);
xgcsimplepm0 = mxm->pmid;
}
}else{
/* somehow this doesn't work on rob's mac
gc = xgcsimplesrc;
if(dst->chan == CMAP8 && xtblbit)
sdval = plan9tox11[sdval];
if(xgcsimplecolor != sdval){
XSetForeground(xdisplay, gc, sdval);
xgcsimplecolor = sdval;
}
if(xgcsimplepm != mxm->pmid){
XSetStipple(xdisplay, gc, mxm->pmid);
xgcsimplepm = mxm->pmid;
}
*/
return 0;
}
XSetTSOrigin(xdisplay, gc, p.x, p.y);
XFillRectangle(xdisplay, dxm->pmid, gc, r.min.x, r.min.y, dx, dy);
dirtyXdata(dst, par->r);
return 1;
}
return 0;
}
ulong
pixelbits(Memimage *m, Point p)
{
Xmem *xm;
if(m->X)
getXdata(m, Rect(p.x, p.y, p.x+1, p.y+1));
return _pixelbits(m, p);
}

857
gui-x11/keysym2ucs-x11.c Normal file
View File

@ -0,0 +1,857 @@
/* $XFree86: xc/programs/xterm/keysym2ucs.c,v 1.5 2001/06/18 19:09:26 dickey Exp $
* This module converts keysym values into the corresponding ISO 10646
* (UCS, Unicode) values.
*
* The array keysymtab[] contains pairs of X11 keysym values for graphical
* characters and the corresponding Unicode value. The function
* keysym2ucs() maps a keysym onto a Unicode value using a binary search,
* therefore keysymtab[] must remain SORTED by keysym value.
*
* The keysym -> UTF-8 conversion will hopefully one day be provided
* by Xlib via XmbLookupString() and should ideally not have to be
* done in X applications. But we are not there yet.
*
* We allow to represent any UCS character in the range U-00000000 to
* U-00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff.
* This admittedly does not cover the entire 31-bit space of UCS, but
* it does cover all of the characters up to U-10FFFF, which can be
* represented by UTF-16, and more, and it is very unlikely that higher
* UCS codes will ever be assigned by ISO. So to get Unicode character
* U+ABCD you can directly use keysym 0x0100abcd.
*
* NOTE: The comments in the table below contain the actual character
* encoded in UTF-8, so for viewing and editing best use an editor in
* UTF-8 mode.
*
* Author: Markus G. Kuhn <mkuhn@acm.org>, University of Cambridge, April 2001
*
* Special thanks to Richard Verhoeven <river@win.tue.nl> for preparing
* an initial draft of the mapping table.
*
* This software is in the public domain. Share and enjoy!
*
* AUTOMATICALLY GENERATED FILE, DO NOT EDIT !!! (unicode/convmap.pl)
*/
#ifndef KEYSYM2UCS_INCLUDED
#include "keysym2ucs.h"
#define VISIBLE /* */
#else
#define VISIBLE static
#endif
static struct codepair {
unsigned short keysym;
unsigned short ucs;
} keysymtab[] = {
{ 0x01a1, 0x0104 }, /* Aogonek Ą LATIN CAPITAL LETTER A WITH OGONEK */
{ 0x01a2, 0x02d8 }, /* breve ˘ BREVE */
{ 0x01a3, 0x0141 }, /* Lstroke Ł LATIN CAPITAL LETTER L WITH STROKE */
{ 0x01a5, 0x013d }, /* Lcaron Ľ LATIN CAPITAL LETTER L WITH CARON */
{ 0x01a6, 0x015a }, /* Sacute Ś LATIN CAPITAL LETTER S WITH ACUTE */
{ 0x01a9, 0x0160 }, /* Scaron Š LATIN CAPITAL LETTER S WITH CARON */
{ 0x01aa, 0x015e }, /* Scedilla Ş LATIN CAPITAL LETTER S WITH CEDILLA */
{ 0x01ab, 0x0164 }, /* Tcaron Ť LATIN CAPITAL LETTER T WITH CARON */
{ 0x01ac, 0x0179 }, /* Zacute Ź LATIN CAPITAL LETTER Z WITH ACUTE */
{ 0x01ae, 0x017d }, /* Zcaron Ž LATIN CAPITAL LETTER Z WITH CARON */
{ 0x01af, 0x017b }, /* Zabovedot Ż LATIN CAPITAL LETTER Z WITH DOT ABOVE */
{ 0x01b1, 0x0105 }, /* aogonek ą LATIN SMALL LETTER A WITH OGONEK */
{ 0x01b2, 0x02db }, /* ogonek ˛ OGONEK */
{ 0x01b3, 0x0142 }, /* lstroke ł LATIN SMALL LETTER L WITH STROKE */
{ 0x01b5, 0x013e }, /* lcaron ľ LATIN SMALL LETTER L WITH CARON */
{ 0x01b6, 0x015b }, /* sacute ś LATIN SMALL LETTER S WITH ACUTE */
{ 0x01b7, 0x02c7 }, /* caron ˇ CARON */
{ 0x01b9, 0x0161 }, /* scaron š LATIN SMALL LETTER S WITH CARON */
{ 0x01ba, 0x015f }, /* scedilla ş LATIN SMALL LETTER S WITH CEDILLA */
{ 0x01bb, 0x0165 }, /* tcaron ť LATIN SMALL LETTER T WITH CARON */
{ 0x01bc, 0x017a }, /* zacute ź LATIN SMALL LETTER Z WITH ACUTE */
{ 0x01bd, 0x02dd }, /* doubleacute ˝ DOUBLE ACUTE ACCENT */
{ 0x01be, 0x017e }, /* zcaron ž LATIN SMALL LETTER Z WITH CARON */
{ 0x01bf, 0x017c }, /* zabovedot ż LATIN SMALL LETTER Z WITH DOT ABOVE */
{ 0x01c0, 0x0154 }, /* Racute Ŕ LATIN CAPITAL LETTER R WITH ACUTE */
{ 0x01c3, 0x0102 }, /* Abreve Ă LATIN CAPITAL LETTER A WITH BREVE */
{ 0x01c5, 0x0139 }, /* Lacute Ĺ LATIN CAPITAL LETTER L WITH ACUTE */
{ 0x01c6, 0x0106 }, /* Cacute Ć LATIN CAPITAL LETTER C WITH ACUTE */
{ 0x01c8, 0x010c }, /* Ccaron Č LATIN CAPITAL LETTER C WITH CARON */
{ 0x01ca, 0x0118 }, /* Eogonek Ę LATIN CAPITAL LETTER E WITH OGONEK */
{ 0x01cc, 0x011a }, /* Ecaron Ě LATIN CAPITAL LETTER E WITH CARON */
{ 0x01cf, 0x010e }, /* Dcaron Ď LATIN CAPITAL LETTER D WITH CARON */
{ 0x01d0, 0x0110 }, /* Dstroke Đ LATIN CAPITAL LETTER D WITH STROKE */
{ 0x01d1, 0x0143 }, /* Nacute Ń LATIN CAPITAL LETTER N WITH ACUTE */
{ 0x01d2, 0x0147 }, /* Ncaron Ň LATIN CAPITAL LETTER N WITH CARON */
{ 0x01d5, 0x0150 }, /* Odoubleacute Ő LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */
{ 0x01d8, 0x0158 }, /* Rcaron Ř LATIN CAPITAL LETTER R WITH CARON */
{ 0x01d9, 0x016e }, /* Uring Ů LATIN CAPITAL LETTER U WITH RING ABOVE */
{ 0x01db, 0x0170 }, /* Udoubleacute Ű LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */
{ 0x01de, 0x0162 }, /* Tcedilla Ţ LATIN CAPITAL LETTER T WITH CEDILLA */
{ 0x01e0, 0x0155 }, /* racute ŕ LATIN SMALL LETTER R WITH ACUTE */
{ 0x01e3, 0x0103 }, /* abreve ă LATIN SMALL LETTER A WITH BREVE */
{ 0x01e5, 0x013a }, /* lacute ĺ LATIN SMALL LETTER L WITH ACUTE */
{ 0x01e6, 0x0107 }, /* cacute ć LATIN SMALL LETTER C WITH ACUTE */
{ 0x01e8, 0x010d }, /* ccaron č LATIN SMALL LETTER C WITH CARON */
{ 0x01ea, 0x0119 }, /* eogonek ę LATIN SMALL LETTER E WITH OGONEK */
{ 0x01ec, 0x011b }, /* ecaron ě LATIN SMALL LETTER E WITH CARON */
{ 0x01ef, 0x010f }, /* dcaron ď LATIN SMALL LETTER D WITH CARON */
{ 0x01f0, 0x0111 }, /* dstroke đ LATIN SMALL LETTER D WITH STROKE */
{ 0x01f1, 0x0144 }, /* nacute ń LATIN SMALL LETTER N WITH ACUTE */
{ 0x01f2, 0x0148 }, /* ncaron ň LATIN SMALL LETTER N WITH CARON */
{ 0x01f5, 0x0151 }, /* odoubleacute ő LATIN SMALL LETTER O WITH DOUBLE ACUTE */
{ 0x01f8, 0x0159 }, /* rcaron ř LATIN SMALL LETTER R WITH CARON */
{ 0x01f9, 0x016f }, /* uring ů LATIN SMALL LETTER U WITH RING ABOVE */
{ 0x01fb, 0x0171 }, /* udoubleacute ű LATIN SMALL LETTER U WITH DOUBLE ACUTE */
{ 0x01fe, 0x0163 }, /* tcedilla ţ LATIN SMALL LETTER T WITH CEDILLA */
{ 0x01ff, 0x02d9 }, /* abovedot ˙ DOT ABOVE */
{ 0x02a1, 0x0126 }, /* Hstroke Ħ LATIN CAPITAL LETTER H WITH STROKE */
{ 0x02a6, 0x0124 }, /* Hcircumflex Ĥ LATIN CAPITAL LETTER H WITH CIRCUMFLEX */
{ 0x02a9, 0x0130 }, /* Iabovedot İ LATIN CAPITAL LETTER I WITH DOT ABOVE */
{ 0x02ab, 0x011e }, /* Gbreve Ğ LATIN CAPITAL LETTER G WITH BREVE */
{ 0x02ac, 0x0134 }, /* Jcircumflex Ĵ LATIN CAPITAL LETTER J WITH CIRCUMFLEX */
{ 0x02b1, 0x0127 }, /* hstroke ħ LATIN SMALL LETTER H WITH STROKE */
{ 0x02b6, 0x0125 }, /* hcircumflex ĥ LATIN SMALL LETTER H WITH CIRCUMFLEX */
{ 0x02b9, 0x0131 }, /* idotless ı LATIN SMALL LETTER DOTLESS I */
{ 0x02bb, 0x011f }, /* gbreve ğ LATIN SMALL LETTER G WITH BREVE */
{ 0x02bc, 0x0135 }, /* jcircumflex ĵ LATIN SMALL LETTER J WITH CIRCUMFLEX */
{ 0x02c5, 0x010a }, /* Cabovedot Ċ LATIN CAPITAL LETTER C WITH DOT ABOVE */
{ 0x02c6, 0x0108 }, /* Ccircumflex Ĉ LATIN CAPITAL LETTER C WITH CIRCUMFLEX */
{ 0x02d5, 0x0120 }, /* Gabovedot Ġ LATIN CAPITAL LETTER G WITH DOT ABOVE */
{ 0x02d8, 0x011c }, /* Gcircumflex Ĝ LATIN CAPITAL LETTER G WITH CIRCUMFLEX */
{ 0x02dd, 0x016c }, /* Ubreve Ŭ LATIN CAPITAL LETTER U WITH BREVE */
{ 0x02de, 0x015c }, /* Scircumflex Ŝ LATIN CAPITAL LETTER S WITH CIRCUMFLEX */
{ 0x02e5, 0x010b }, /* cabovedot ċ LATIN SMALL LETTER C WITH DOT ABOVE */
{ 0x02e6, 0x0109 }, /* ccircumflex ĉ LATIN SMALL LETTER C WITH CIRCUMFLEX */
{ 0x02f5, 0x0121 }, /* gabovedot ġ LATIN SMALL LETTER G WITH DOT ABOVE */
{ 0x02f8, 0x011d }, /* gcircumflex ĝ LATIN SMALL LETTER G WITH CIRCUMFLEX */
{ 0x02fd, 0x016d }, /* ubreve ŭ LATIN SMALL LETTER U WITH BREVE */
{ 0x02fe, 0x015d }, /* scircumflex ŝ LATIN SMALL LETTER S WITH CIRCUMFLEX */
{ 0x03a2, 0x0138 }, /* kra ĸ LATIN SMALL LETTER KRA */
{ 0x03a3, 0x0156 }, /* Rcedilla Ŗ LATIN CAPITAL LETTER R WITH CEDILLA */
{ 0x03a5, 0x0128 }, /* Itilde Ĩ LATIN CAPITAL LETTER I WITH TILDE */
{ 0x03a6, 0x013b }, /* Lcedilla Ļ LATIN CAPITAL LETTER L WITH CEDILLA */
{ 0x03aa, 0x0112 }, /* Emacron Ē LATIN CAPITAL LETTER E WITH MACRON */
{ 0x03ab, 0x0122 }, /* Gcedilla Ģ LATIN CAPITAL LETTER G WITH CEDILLA */
{ 0x03ac, 0x0166 }, /* Tslash Ŧ LATIN CAPITAL LETTER T WITH STROKE */
{ 0x03b3, 0x0157 }, /* rcedilla ŗ LATIN SMALL LETTER R WITH CEDILLA */
{ 0x03b5, 0x0129 }, /* itilde ĩ LATIN SMALL LETTER I WITH TILDE */
{ 0x03b6, 0x013c }, /* lcedilla ļ LATIN SMALL LETTER L WITH CEDILLA */
{ 0x03ba, 0x0113 }, /* emacron ē LATIN SMALL LETTER E WITH MACRON */
{ 0x03bb, 0x0123 }, /* gcedilla ģ LATIN SMALL LETTER G WITH CEDILLA */
{ 0x03bc, 0x0167 }, /* tslash ŧ LATIN SMALL LETTER T WITH STROKE */
{ 0x03bd, 0x014a }, /* ENG Ŋ LATIN CAPITAL LETTER ENG */
{ 0x03bf, 0x014b }, /* eng ŋ LATIN SMALL LETTER ENG */
{ 0x03c0, 0x0100 }, /* Amacron Ā LATIN CAPITAL LETTER A WITH MACRON */
{ 0x03c7, 0x012e }, /* Iogonek Į LATIN CAPITAL LETTER I WITH OGONEK */
{ 0x03cc, 0x0116 }, /* Eabovedot Ė LATIN CAPITAL LETTER E WITH DOT ABOVE */
{ 0x03cf, 0x012a }, /* Imacron Ī LATIN CAPITAL LETTER I WITH MACRON */
{ 0x03d1, 0x0145 }, /* Ncedilla Ņ LATIN CAPITAL LETTER N WITH CEDILLA */
{ 0x03d2, 0x014c }, /* Omacron Ō LATIN CAPITAL LETTER O WITH MACRON */
{ 0x03d3, 0x0136 }, /* Kcedilla Ķ LATIN CAPITAL LETTER K WITH CEDILLA */
{ 0x03d9, 0x0172 }, /* Uogonek Ų LATIN CAPITAL LETTER U WITH OGONEK */
{ 0x03dd, 0x0168 }, /* Utilde Ũ LATIN CAPITAL LETTER U WITH TILDE */
{ 0x03de, 0x016a }, /* Umacron Ū LATIN CAPITAL LETTER U WITH MACRON */
{ 0x03e0, 0x0101 }, /* amacron ā LATIN SMALL LETTER A WITH MACRON */
{ 0x03e7, 0x012f }, /* iogonek į LATIN SMALL LETTER I WITH OGONEK */
{ 0x03ec, 0x0117 }, /* eabovedot ė LATIN SMALL LETTER E WITH DOT ABOVE */
{ 0x03ef, 0x012b }, /* imacron ī LATIN SMALL LETTER I WITH MACRON */
{ 0x03f1, 0x0146 }, /* ncedilla ņ LATIN SMALL LETTER N WITH CEDILLA */
{ 0x03f2, 0x014d }, /* omacron ō LATIN SMALL LETTER O WITH MACRON */
{ 0x03f3, 0x0137 }, /* kcedilla ķ LATIN SMALL LETTER K WITH CEDILLA */
{ 0x03f9, 0x0173 }, /* uogonek ų LATIN SMALL LETTER U WITH OGONEK */
{ 0x03fd, 0x0169 }, /* utilde ũ LATIN SMALL LETTER U WITH TILDE */
{ 0x03fe, 0x016b }, /* umacron ū LATIN SMALL LETTER U WITH MACRON */
{ 0x047e, 0x203e }, /* overline ‾ OVERLINE */
{ 0x04a1, 0x3002 }, /* kana_fullstop 。 IDEOGRAPHIC FULL STOP */
{ 0x04a2, 0x300c }, /* kana_openingbracket 「 LEFT CORNER BRACKET */
{ 0x04a3, 0x300d }, /* kana_closingbracket 」 RIGHT CORNER BRACKET */
{ 0x04a4, 0x3001 }, /* kana_comma 、 IDEOGRAPHIC COMMA */
{ 0x04a5, 0x30fb }, /* kana_conjunctive ・ KATAKANA MIDDLE DOT */
{ 0x04a6, 0x30f2 }, /* kana_WO ヲ KATAKANA LETTER WO */
{ 0x04a7, 0x30a1 }, /* kana_a ァ KATAKANA LETTER SMALL A */
{ 0x04a8, 0x30a3 }, /* kana_i ィ KATAKANA LETTER SMALL I */
{ 0x04a9, 0x30a5 }, /* kana_u ゥ KATAKANA LETTER SMALL U */
{ 0x04aa, 0x30a7 }, /* kana_e ェ KATAKANA LETTER SMALL E */
{ 0x04ab, 0x30a9 }, /* kana_o ォ KATAKANA LETTER SMALL O */
{ 0x04ac, 0x30e3 }, /* kana_ya ャ KATAKANA LETTER SMALL YA */
{ 0x04ad, 0x30e5 }, /* kana_yu ュ KATAKANA LETTER SMALL YU */
{ 0x04ae, 0x30e7 }, /* kana_yo ョ KATAKANA LETTER SMALL YO */
{ 0x04af, 0x30c3 }, /* kana_tsu ッ KATAKANA LETTER SMALL TU */
{ 0x04b0, 0x30fc }, /* prolongedsound ー KATAKANA-HIRAGANA PROLONGED SOUND MARK */
{ 0x04b1, 0x30a2 }, /* kana_A ア KATAKANA LETTER A */
{ 0x04b2, 0x30a4 }, /* kana_I イ KATAKANA LETTER I */
{ 0x04b3, 0x30a6 }, /* kana_U ウ KATAKANA LETTER U */
{ 0x04b4, 0x30a8 }, /* kana_E エ KATAKANA LETTER E */
{ 0x04b5, 0x30aa }, /* kana_O オ KATAKANA LETTER O */
{ 0x04b6, 0x30ab }, /* kana_KA カ KATAKANA LETTER KA */
{ 0x04b7, 0x30ad }, /* kana_KI キ KATAKANA LETTER KI */
{ 0x04b8, 0x30af }, /* kana_KU ク KATAKANA LETTER KU */
{ 0x04b9, 0x30b1 }, /* kana_KE ケ KATAKANA LETTER KE */
{ 0x04ba, 0x30b3 }, /* kana_KO コ KATAKANA LETTER KO */
{ 0x04bb, 0x30b5 }, /* kana_SA サ KATAKANA LETTER SA */
{ 0x04bc, 0x30b7 }, /* kana_SHI シ KATAKANA LETTER SI */
{ 0x04bd, 0x30b9 }, /* kana_SU ス KATAKANA LETTER SU */
{ 0x04be, 0x30bb }, /* kana_SE セ KATAKANA LETTER SE */
{ 0x04bf, 0x30bd }, /* kana_SO ソ KATAKANA LETTER SO */
{ 0x04c0, 0x30bf }, /* kana_TA タ KATAKANA LETTER TA */
{ 0x04c1, 0x30c1 }, /* kana_CHI チ KATAKANA LETTER TI */
{ 0x04c2, 0x30c4 }, /* kana_TSU ツ KATAKANA LETTER TU */
{ 0x04c3, 0x30c6 }, /* kana_TE テ KATAKANA LETTER TE */
{ 0x04c4, 0x30c8 }, /* kana_TO ト KATAKANA LETTER TO */
{ 0x04c5, 0x30ca }, /* kana_NA ナ KATAKANA LETTER NA */
{ 0x04c6, 0x30cb }, /* kana_NI ニ KATAKANA LETTER NI */
{ 0x04c7, 0x30cc }, /* kana_NU ヌ KATAKANA LETTER NU */
{ 0x04c8, 0x30cd }, /* kana_NE ネ KATAKANA LETTER NE */
{ 0x04c9, 0x30ce }, /* kana_NO KATAKANA LETTER NO */
{ 0x04ca, 0x30cf }, /* kana_HA ハ KATAKANA LETTER HA */
{ 0x04cb, 0x30d2 }, /* kana_HI ヒ KATAKANA LETTER HI */
{ 0x04cc, 0x30d5 }, /* kana_FU フ KATAKANA LETTER HU */
{ 0x04cd, 0x30d8 }, /* kana_HE ヘ KATAKANA LETTER HE */
{ 0x04ce, 0x30db }, /* kana_HO ホ KATAKANA LETTER HO */
{ 0x04cf, 0x30de }, /* kana_MA マ KATAKANA LETTER MA */
{ 0x04d0, 0x30df }, /* kana_MI ミ KATAKANA LETTER MI */
{ 0x04d1, 0x30e0 }, /* kana_MU ム KATAKANA LETTER MU */
{ 0x04d2, 0x30e1 }, /* kana_ME メ KATAKANA LETTER ME */
{ 0x04d3, 0x30e2 }, /* kana_MO モ KATAKANA LETTER MO */
{ 0x04d4, 0x30e4 }, /* kana_YA ヤ KATAKANA LETTER YA */
{ 0x04d5, 0x30e6 }, /* kana_YU ユ KATAKANA LETTER YU */
{ 0x04d6, 0x30e8 }, /* kana_YO ヨ KATAKANA LETTER YO */
{ 0x04d7, 0x30e9 }, /* kana_RA ラ KATAKANA LETTER RA */
{ 0x04d8, 0x30ea }, /* kana_RI リ KATAKANA LETTER RI */
{ 0x04d9, 0x30eb }, /* kana_RU ル KATAKANA LETTER RU */
{ 0x04da, 0x30ec }, /* kana_RE レ KATAKANA LETTER RE */
{ 0x04db, 0x30ed }, /* kana_RO ロ KATAKANA LETTER RO */
{ 0x04dc, 0x30ef }, /* kana_WA ワ KATAKANA LETTER WA */
{ 0x04dd, 0x30f3 }, /* kana_N ン KATAKANA LETTER N */
{ 0x04de, 0x309b }, /* voicedsound ゛ KATAKANA-HIRAGANA VOICED SOUND MARK */
{ 0x04df, 0x309c }, /* semivoicedsound ゜ KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */
{ 0x05ac, 0x060c }, /* Arabic_comma ، ARABIC COMMA */
{ 0x05bb, 0x061b }, /* Arabic_semicolon ؛ ARABIC SEMICOLON */
{ 0x05bf, 0x061f }, /* Arabic_question_mark ؟ ARABIC QUESTION MARK */
{ 0x05c1, 0x0621 }, /* Arabic_hamza ء ARABIC LETTER HAMZA */
{ 0x05c2, 0x0622 }, /* Arabic_maddaonalef آ ARABIC LETTER ALEF WITH MADDA ABOVE */
{ 0x05c3, 0x0623 }, /* Arabic_hamzaonalef أ ARABIC LETTER ALEF WITH HAMZA ABOVE */
{ 0x05c4, 0x0624 }, /* Arabic_hamzaonwaw ؤ ARABIC LETTER WAW WITH HAMZA ABOVE */
{ 0x05c5, 0x0625 }, /* Arabic_hamzaunderalef إ ARABIC LETTER ALEF WITH HAMZA BELOW */
{ 0x05c6, 0x0626 }, /* Arabic_hamzaonyeh ئ ARABIC LETTER YEH WITH HAMZA ABOVE */
{ 0x05c7, 0x0627 }, /* Arabic_alef ا ARABIC LETTER ALEF */
{ 0x05c8, 0x0628 }, /* Arabic_beh ب ARABIC LETTER BEH */
{ 0x05c9, 0x0629 }, /* Arabic_tehmarbuta ة ARABIC LETTER TEH MARBUTA */
{ 0x05ca, 0x062a }, /* Arabic_teh ت ARABIC LETTER TEH */
{ 0x05cb, 0x062b }, /* Arabic_theh ث ARABIC LETTER THEH */
{ 0x05cc, 0x062c }, /* Arabic_jeem ج ARABIC LETTER JEEM */
{ 0x05cd, 0x062d }, /* Arabic_hah ح ARABIC LETTER HAH */
{ 0x05ce, 0x062e }, /* Arabic_khah خ ARABIC LETTER KHAH */
{ 0x05cf, 0x062f }, /* Arabic_dal د ARABIC LETTER DAL */
{ 0x05d0, 0x0630 }, /* Arabic_thal ذ ARABIC LETTER THAL */
{ 0x05d1, 0x0631 }, /* Arabic_ra ر ARABIC LETTER REH */
{ 0x05d2, 0x0632 }, /* Arabic_zain ز ARABIC LETTER ZAIN */
{ 0x05d3, 0x0633 }, /* Arabic_seen س ARABIC LETTER SEEN */
{ 0x05d4, 0x0634 }, /* Arabic_sheen ش ARABIC LETTER SHEEN */
{ 0x05d5, 0x0635 }, /* Arabic_sad ص ARABIC LETTER SAD */
{ 0x05d6, 0x0636 }, /* Arabic_dad ض ARABIC LETTER DAD */
{ 0x05d7, 0x0637 }, /* Arabic_tah ط ARABIC LETTER TAH */
{ 0x05d8, 0x0638 }, /* Arabic_zah ظ ARABIC LETTER ZAH */
{ 0x05d9, 0x0639 }, /* Arabic_ain ع ARABIC LETTER AIN */
{ 0x05da, 0x063a }, /* Arabic_ghain غ ARABIC LETTER GHAIN */
{ 0x05e0, 0x0640 }, /* Arabic_tatweel ـ ARABIC TATWEEL */
{ 0x05e1, 0x0641 }, /* Arabic_feh ف ARABIC LETTER FEH */
{ 0x05e2, 0x0642 }, /* Arabic_qaf ق ARABIC LETTER QAF */
{ 0x05e3, 0x0643 }, /* Arabic_kaf ك ARABIC LETTER KAF */
{ 0x05e4, 0x0644 }, /* Arabic_lam ل ARABIC LETTER LAM */
{ 0x05e5, 0x0645 }, /* Arabic_meem م ARABIC LETTER MEEM */
{ 0x05e6, 0x0646 }, /* Arabic_noon ن ARABIC LETTER NOON */
{ 0x05e7, 0x0647 }, /* Arabic_ha ه ARABIC LETTER HEH */
{ 0x05e8, 0x0648 }, /* Arabic_waw و ARABIC LETTER WAW */
{ 0x05e9, 0x0649 }, /* Arabic_alefmaksura ى ARABIC LETTER ALEF MAKSURA */
{ 0x05ea, 0x064a }, /* Arabic_yeh ي ARABIC LETTER YEH */
{ 0x05eb, 0x064b }, /* Arabic_fathatan ً ARABIC FATHATAN */
{ 0x05ec, 0x064c }, /* Arabic_dammatan ٌ ARABIC DAMMATAN */
{ 0x05ed, 0x064d }, /* Arabic_kasratan ٍ ARABIC KASRATAN */
{ 0x05ee, 0x064e }, /* Arabic_fatha َ ARABIC FATHA */
{ 0x05ef, 0x064f }, /* Arabic_damma ُ ARABIC DAMMA */
{ 0x05f0, 0x0650 }, /* Arabic_kasra ِ ARABIC KASRA */
{ 0x05f1, 0x0651 }, /* Arabic_shadda ّ ARABIC SHADDA */
{ 0x05f2, 0x0652 }, /* Arabic_sukun ْ ARABIC SUKUN */
{ 0x06a1, 0x0452 }, /* Serbian_dje ђ CYRILLIC SMALL LETTER DJE */
{ 0x06a2, 0x0453 }, /* Macedonia_gje ѓ CYRILLIC SMALL LETTER GJE */
{ 0x06a3, 0x0451 }, /* Cyrillic_io ё CYRILLIC SMALL LETTER IO */
{ 0x06a4, 0x0454 }, /* Ukrainian_ie є CYRILLIC SMALL LETTER UKRAINIAN IE */
{ 0x06a5, 0x0455 }, /* Macedonia_dse ѕ CYRILLIC SMALL LETTER DZE */
{ 0x06a6, 0x0456 }, /* Ukrainian_i і CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */
{ 0x06a7, 0x0457 }, /* Ukrainian_yi ї CYRILLIC SMALL LETTER YI */
{ 0x06a8, 0x0458 }, /* Cyrillic_je ј CYRILLIC SMALL LETTER JE */
{ 0x06a9, 0x0459 }, /* Cyrillic_lje љ CYRILLIC SMALL LETTER LJE */
{ 0x06aa, 0x045a }, /* Cyrillic_nje њ CYRILLIC SMALL LETTER NJE */
{ 0x06ab, 0x045b }, /* Serbian_tshe ћ CYRILLIC SMALL LETTER TSHE */
{ 0x06ac, 0x045c }, /* Macedonia_kje ќ CYRILLIC SMALL LETTER KJE */
{ 0x06ae, 0x045e }, /* Byelorussian_shortu ў CYRILLIC SMALL LETTER SHORT U */
{ 0x06af, 0x045f }, /* Cyrillic_dzhe џ CYRILLIC SMALL LETTER DZHE */
{ 0x06b0, 0x2116 }, /* numerosign № NUMERO SIGN */
{ 0x06b1, 0x0402 }, /* Serbian_DJE Ђ CYRILLIC CAPITAL LETTER DJE */
{ 0x06b2, 0x0403 }, /* Macedonia_GJE Ѓ CYRILLIC CAPITAL LETTER GJE */
{ 0x06b3, 0x0401 }, /* Cyrillic_IO Ё CYRILLIC CAPITAL LETTER IO */
{ 0x06b4, 0x0404 }, /* Ukrainian_IE Є CYRILLIC CAPITAL LETTER UKRAINIAN IE */
{ 0x06b5, 0x0405 }, /* Macedonia_DSE Ѕ CYRILLIC CAPITAL LETTER DZE */
{ 0x06b6, 0x0406 }, /* Ukrainian_I І CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */
{ 0x06b7, 0x0407 }, /* Ukrainian_YI Ї CYRILLIC CAPITAL LETTER YI */
{ 0x06b8, 0x0408 }, /* Cyrillic_JE Ј CYRILLIC CAPITAL LETTER JE */
{ 0x06b9, 0x0409 }, /* Cyrillic_LJE Љ CYRILLIC CAPITAL LETTER LJE */
{ 0x06ba, 0x040a }, /* Cyrillic_NJE Њ CYRILLIC CAPITAL LETTER NJE */
{ 0x06bb, 0x040b }, /* Serbian_TSHE Ћ CYRILLIC CAPITAL LETTER TSHE */
{ 0x06bc, 0x040c }, /* Macedonia_KJE Ќ CYRILLIC CAPITAL LETTER KJE */
{ 0x06be, 0x040e }, /* Byelorussian_SHORTU Ў CYRILLIC CAPITAL LETTER SHORT U */
{ 0x06bf, 0x040f }, /* Cyrillic_DZHE Џ CYRILLIC CAPITAL LETTER DZHE */
{ 0x06c0, 0x044e }, /* Cyrillic_yu ю CYRILLIC SMALL LETTER YU */
{ 0x06c1, 0x0430 }, /* Cyrillic_a а CYRILLIC SMALL LETTER A */
{ 0x06c2, 0x0431 }, /* Cyrillic_be б CYRILLIC SMALL LETTER BE */
{ 0x06c3, 0x0446 }, /* Cyrillic_tse ц CYRILLIC SMALL LETTER TSE */
{ 0x06c4, 0x0434 }, /* Cyrillic_de д CYRILLIC SMALL LETTER DE */
{ 0x06c5, 0x0435 }, /* Cyrillic_ie е CYRILLIC SMALL LETTER IE */
{ 0x06c6, 0x0444 }, /* Cyrillic_ef ф CYRILLIC SMALL LETTER EF */
{ 0x06c7, 0x0433 }, /* Cyrillic_ghe г CYRILLIC SMALL LETTER GHE */
{ 0x06c8, 0x0445 }, /* Cyrillic_ha х CYRILLIC SMALL LETTER HA */
{ 0x06c9, 0x0438 }, /* Cyrillic_i и CYRILLIC SMALL LETTER I */
{ 0x06ca, 0x0439 }, /* Cyrillic_shorti й CYRILLIC SMALL LETTER SHORT I */
{ 0x06cb, 0x043a }, /* Cyrillic_ka к CYRILLIC SMALL LETTER KA */
{ 0x06cc, 0x043b }, /* Cyrillic_el л CYRILLIC SMALL LETTER EL */
{ 0x06cd, 0x043c }, /* Cyrillic_em м CYRILLIC SMALL LETTER EM */
{ 0x06ce, 0x043d }, /* Cyrillic_en н CYRILLIC SMALL LETTER EN */
{ 0x06cf, 0x043e }, /* Cyrillic_o о CYRILLIC SMALL LETTER O */
{ 0x06d0, 0x043f }, /* Cyrillic_pe п CYRILLIC SMALL LETTER PE */
{ 0x06d1, 0x044f }, /* Cyrillic_ya я CYRILLIC SMALL LETTER YA */
{ 0x06d2, 0x0440 }, /* Cyrillic_er р CYRILLIC SMALL LETTER ER */
{ 0x06d3, 0x0441 }, /* Cyrillic_es с CYRILLIC SMALL LETTER ES */
{ 0x06d4, 0x0442 }, /* Cyrillic_te т CYRILLIC SMALL LETTER TE */
{ 0x06d5, 0x0443 }, /* Cyrillic_u у CYRILLIC SMALL LETTER U */
{ 0x06d6, 0x0436 }, /* Cyrillic_zhe ж CYRILLIC SMALL LETTER ZHE */
{ 0x06d7, 0x0432 }, /* Cyrillic_ve в CYRILLIC SMALL LETTER VE */
{ 0x06d8, 0x044c }, /* Cyrillic_softsign ь CYRILLIC SMALL LETTER SOFT SIGN */
{ 0x06d9, 0x044b }, /* Cyrillic_yeru ы CYRILLIC SMALL LETTER YERU */
{ 0x06da, 0x0437 }, /* Cyrillic_ze з CYRILLIC SMALL LETTER ZE */
{ 0x06db, 0x0448 }, /* Cyrillic_sha ш CYRILLIC SMALL LETTER SHA */
{ 0x06dc, 0x044d }, /* Cyrillic_e э CYRILLIC SMALL LETTER E */
{ 0x06dd, 0x0449 }, /* Cyrillic_shcha щ CYRILLIC SMALL LETTER SHCHA */
{ 0x06de, 0x0447 }, /* Cyrillic_che ч CYRILLIC SMALL LETTER CHE */
{ 0x06df, 0x044a }, /* Cyrillic_hardsign ъ CYRILLIC SMALL LETTER HARD SIGN */
{ 0x06e0, 0x042e }, /* Cyrillic_YU Ю CYRILLIC CAPITAL LETTER YU */
{ 0x06e1, 0x0410 }, /* Cyrillic_A А CYRILLIC CAPITAL LETTER A */
{ 0x06e2, 0x0411 }, /* Cyrillic_BE Б CYRILLIC CAPITAL LETTER BE */
{ 0x06e3, 0x0426 }, /* Cyrillic_TSE Ц CYRILLIC CAPITAL LETTER TSE */
{ 0x06e4, 0x0414 }, /* Cyrillic_DE Д CYRILLIC CAPITAL LETTER DE */
{ 0x06e5, 0x0415 }, /* Cyrillic_IE Е CYRILLIC CAPITAL LETTER IE */
{ 0x06e6, 0x0424 }, /* Cyrillic_EF Ф CYRILLIC CAPITAL LETTER EF */
{ 0x06e7, 0x0413 }, /* Cyrillic_GHE Г CYRILLIC CAPITAL LETTER GHE */
{ 0x06e8, 0x0425 }, /* Cyrillic_HA Х CYRILLIC CAPITAL LETTER HA */
{ 0x06e9, 0x0418 }, /* Cyrillic_I И CYRILLIC CAPITAL LETTER I */
{ 0x06ea, 0x0419 }, /* Cyrillic_SHORTI Й CYRILLIC CAPITAL LETTER SHORT I */
{ 0x06eb, 0x041a }, /* Cyrillic_KA К CYRILLIC CAPITAL LETTER KA */
{ 0x06ec, 0x041b }, /* Cyrillic_EL Л CYRILLIC CAPITAL LETTER EL */
{ 0x06ed, 0x041c }, /* Cyrillic_EM М CYRILLIC CAPITAL LETTER EM */
{ 0x06ee, 0x041d }, /* Cyrillic_EN Н CYRILLIC CAPITAL LETTER EN */
{ 0x06ef, 0x041e }, /* Cyrillic_O О CYRILLIC CAPITAL LETTER O */
{ 0x06f0, 0x041f }, /* Cyrillic_PE П CYRILLIC CAPITAL LETTER PE */
{ 0x06f1, 0x042f }, /* Cyrillic_YA Я CYRILLIC CAPITAL LETTER YA */
{ 0x06f2, 0x0420 }, /* Cyrillic_ER Р CYRILLIC CAPITAL LETTER ER */
{ 0x06f3, 0x0421 }, /* Cyrillic_ES С CYRILLIC CAPITAL LETTER ES */
{ 0x06f4, 0x0422 }, /* Cyrillic_TE Т CYRILLIC CAPITAL LETTER TE */
{ 0x06f5, 0x0423 }, /* Cyrillic_U У CYRILLIC CAPITAL LETTER U */
{ 0x06f6, 0x0416 }, /* Cyrillic_ZHE Ж CYRILLIC CAPITAL LETTER ZHE */
{ 0x06f7, 0x0412 }, /* Cyrillic_VE В CYRILLIC CAPITAL LETTER VE */
{ 0x06f8, 0x042c }, /* Cyrillic_SOFTSIGN Ь CYRILLIC CAPITAL LETTER SOFT SIGN */
{ 0x06f9, 0x042b }, /* Cyrillic_YERU Ы CYRILLIC CAPITAL LETTER YERU */
{ 0x06fa, 0x0417 }, /* Cyrillic_ZE З CYRILLIC CAPITAL LETTER ZE */
{ 0x06fb, 0x0428 }, /* Cyrillic_SHA Ш CYRILLIC CAPITAL LETTER SHA */
{ 0x06fc, 0x042d }, /* Cyrillic_E Э CYRILLIC CAPITAL LETTER E */
{ 0x06fd, 0x0429 }, /* Cyrillic_SHCHA Щ CYRILLIC CAPITAL LETTER SHCHA */
{ 0x06fe, 0x0427 }, /* Cyrillic_CHE Ч CYRILLIC CAPITAL LETTER CHE */
{ 0x06ff, 0x042a }, /* Cyrillic_HARDSIGN Ъ CYRILLIC CAPITAL LETTER HARD SIGN */
{ 0x07a1, 0x0386 }, /* Greek_ALPHAaccent Ά GREEK CAPITAL LETTER ALPHA WITH TONOS */
{ 0x07a2, 0x0388 }, /* Greek_EPSILONaccent Έ GREEK CAPITAL LETTER EPSILON WITH TONOS */
{ 0x07a3, 0x0389 }, /* Greek_ETAaccent Ή GREEK CAPITAL LETTER ETA WITH TONOS */
{ 0x07a4, 0x038a }, /* Greek_IOTAaccent Ί GREEK CAPITAL LETTER IOTA WITH TONOS */
{ 0x07a5, 0x03aa }, /* Greek_IOTAdiaeresis Ϊ GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */
{ 0x07a7, 0x038c }, /* Greek_OMICRONaccent Ό GREEK CAPITAL LETTER OMICRON WITH TONOS */
{ 0x07a8, 0x038e }, /* Greek_UPSILONaccent Ύ GREEK CAPITAL LETTER UPSILON WITH TONOS */
{ 0x07a9, 0x03ab }, /* Greek_UPSILONdieresis Ϋ GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */
{ 0x07ab, 0x038f }, /* Greek_OMEGAaccent Ώ GREEK CAPITAL LETTER OMEGA WITH TONOS */
{ 0x07ae, 0x0385 }, /* Greek_accentdieresis ΅ GREEK DIALYTIKA TONOS */
{ 0x07af, 0x2015 }, /* Greek_horizbar ― HORIZONTAL BAR */
{ 0x07b1, 0x03ac }, /* Greek_alphaaccent ά GREEK SMALL LETTER ALPHA WITH TONOS */
{ 0x07b2, 0x03ad }, /* Greek_epsilonaccent έ GREEK SMALL LETTER EPSILON WITH TONOS */
{ 0x07b3, 0x03ae }, /* Greek_etaaccent ή GREEK SMALL LETTER ETA WITH TONOS */
{ 0x07b4, 0x03af }, /* Greek_iotaaccent ί GREEK SMALL LETTER IOTA WITH TONOS */
{ 0x07b5, 0x03ca }, /* Greek_iotadieresis ϊ GREEK SMALL LETTER IOTA WITH DIALYTIKA */
{ 0x07b6, 0x0390 }, /* Greek_iotaaccentdieresis ΐ GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */
{ 0x07b7, 0x03cc }, /* Greek_omicronaccent ό GREEK SMALL LETTER OMICRON WITH TONOS */
{ 0x07b8, 0x03cd }, /* Greek_upsilonaccent ύ GREEK SMALL LETTER UPSILON WITH TONOS */
{ 0x07b9, 0x03cb }, /* Greek_upsilondieresis ϋ GREEK SMALL LETTER UPSILON WITH DIALYTIKA */
{ 0x07ba, 0x03b0 }, /* Greek_upsilonaccentdieresis ΰ GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */
{ 0x07bb, 0x03ce }, /* Greek_omegaaccent ώ GREEK SMALL LETTER OMEGA WITH TONOS */
{ 0x07c1, 0x0391 }, /* Greek_ALPHA Α GREEK CAPITAL LETTER ALPHA */
{ 0x07c2, 0x0392 }, /* Greek_BETA Β GREEK CAPITAL LETTER BETA */
{ 0x07c3, 0x0393 }, /* Greek_GAMMA Γ GREEK CAPITAL LETTER GAMMA */
{ 0x07c4, 0x0394 }, /* Greek_DELTA Δ GREEK CAPITAL LETTER DELTA */
{ 0x07c5, 0x0395 }, /* Greek_EPSILON Ε GREEK CAPITAL LETTER EPSILON */
{ 0x07c6, 0x0396 }, /* Greek_ZETA Ζ GREEK CAPITAL LETTER ZETA */
{ 0x07c7, 0x0397 }, /* Greek_ETA Η GREEK CAPITAL LETTER ETA */
{ 0x07c8, 0x0398 }, /* Greek_THETA Θ GREEK CAPITAL LETTER THETA */
{ 0x07c9, 0x0399 }, /* Greek_IOTA Ι GREEK CAPITAL LETTER IOTA */
{ 0x07ca, 0x039a }, /* Greek_KAPPA Κ GREEK CAPITAL LETTER KAPPA */
{ 0x07cb, 0x039b }, /* Greek_LAMBDA Λ GREEK CAPITAL LETTER LAMDA */
{ 0x07cc, 0x039c }, /* Greek_MU Μ GREEK CAPITAL LETTER MU */
{ 0x07cd, 0x039d }, /* Greek_NU Ν GREEK CAPITAL LETTER NU */
{ 0x07ce, 0x039e }, /* Greek_XI Ξ GREEK CAPITAL LETTER XI */
{ 0x07cf, 0x039f }, /* Greek_OMICRON Ο GREEK CAPITAL LETTER OMICRON */
{ 0x07d0, 0x03a0 }, /* Greek_PI Π GREEK CAPITAL LETTER PI */
{ 0x07d1, 0x03a1 }, /* Greek_RHO Ρ GREEK CAPITAL LETTER RHO */
{ 0x07d2, 0x03a3 }, /* Greek_SIGMA Σ GREEK CAPITAL LETTER SIGMA */
{ 0x07d4, 0x03a4 }, /* Greek_TAU Τ GREEK CAPITAL LETTER TAU */
{ 0x07d5, 0x03a5 }, /* Greek_UPSILON Υ GREEK CAPITAL LETTER UPSILON */
{ 0x07d6, 0x03a6 }, /* Greek_PHI Φ GREEK CAPITAL LETTER PHI */
{ 0x07d7, 0x03a7 }, /* Greek_CHI Χ GREEK CAPITAL LETTER CHI */
{ 0x07d8, 0x03a8 }, /* Greek_PSI Ψ GREEK CAPITAL LETTER PSI */
{ 0x07d9, 0x03a9 }, /* Greek_OMEGA Ω GREEK CAPITAL LETTER OMEGA */
{ 0x07e1, 0x03b1 }, /* Greek_alpha α GREEK SMALL LETTER ALPHA */
{ 0x07e2, 0x03b2 }, /* Greek_beta β GREEK SMALL LETTER BETA */
{ 0x07e3, 0x03b3 }, /* Greek_gamma γ GREEK SMALL LETTER GAMMA */
{ 0x07e4, 0x03b4 }, /* Greek_delta δ GREEK SMALL LETTER DELTA */
{ 0x07e5, 0x03b5 }, /* Greek_epsilon ε GREEK SMALL LETTER EPSILON */
{ 0x07e6, 0x03b6 }, /* Greek_zeta ζ GREEK SMALL LETTER ZETA */
{ 0x07e7, 0x03b7 }, /* Greek_eta η GREEK SMALL LETTER ETA */
{ 0x07e8, 0x03b8 }, /* Greek_theta θ GREEK SMALL LETTER THETA */
{ 0x07e9, 0x03b9 }, /* Greek_iota ι GREEK SMALL LETTER IOTA */
{ 0x07ea, 0x03ba }, /* Greek_kappa κ GREEK SMALL LETTER KAPPA */
{ 0x07eb, 0x03bb }, /* Greek_lambda λ GREEK SMALL LETTER LAMDA */
{ 0x07ec, 0x03bc }, /* Greek_mu μ GREEK SMALL LETTER MU */
{ 0x07ed, 0x03bd }, /* Greek_nu ν GREEK SMALL LETTER NU */
{ 0x07ee, 0x03be }, /* Greek_xi ξ GREEK SMALL LETTER XI */
{ 0x07ef, 0x03bf }, /* Greek_omicron ο GREEK SMALL LETTER OMICRON */
{ 0x07f0, 0x03c0 }, /* Greek_pi π GREEK SMALL LETTER PI */
{ 0x07f1, 0x03c1 }, /* Greek_rho ρ GREEK SMALL LETTER RHO */
{ 0x07f2, 0x03c3 }, /* Greek_sigma σ GREEK SMALL LETTER SIGMA */
{ 0x07f3, 0x03c2 }, /* Greek_finalsmallsigma ς GREEK SMALL LETTER FINAL SIGMA */
{ 0x07f4, 0x03c4 }, /* Greek_tau τ GREEK SMALL LETTER TAU */
{ 0x07f5, 0x03c5 }, /* Greek_upsilon υ GREEK SMALL LETTER UPSILON */
{ 0x07f6, 0x03c6 }, /* Greek_phi φ GREEK SMALL LETTER PHI */
{ 0x07f7, 0x03c7 }, /* Greek_chi χ GREEK SMALL LETTER CHI */
{ 0x07f8, 0x03c8 }, /* Greek_psi ψ GREEK SMALL LETTER PSI */
{ 0x07f9, 0x03c9 }, /* Greek_omega ω GREEK SMALL LETTER OMEGA */
{ 0x08a1, 0x23b7 }, /* leftradical ⎷ ??? */
{ 0x08a2, 0x250c }, /* topleftradical ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */
{ 0x08a3, 0x2500 }, /* horizconnector ─ BOX DRAWINGS LIGHT HORIZONTAL */
{ 0x08a4, 0x2320 }, /* topintegral ⌠ TOP HALF INTEGRAL */
{ 0x08a5, 0x2321 }, /* botintegral ⌡ BOTTOM HALF INTEGRAL */
{ 0x08a6, 0x2502 }, /* vertconnector │ BOX DRAWINGS LIGHT VERTICAL */
{ 0x08a7, 0x23a1 }, /* topleftsqbracket ⎡ ??? */
{ 0x08a8, 0x23a3 }, /* botleftsqbracket ⎣ ??? */
{ 0x08a9, 0x23a4 }, /* toprightsqbracket ⎤ ??? */
{ 0x08aa, 0x23a6 }, /* botrightsqbracket ⎦ ??? */
{ 0x08ab, 0x239b }, /* topleftparens ⎛ ??? */
{ 0x08ac, 0x239d }, /* botleftparens ⎝ ??? */
{ 0x08ad, 0x239e }, /* toprightparens ⎞ ??? */
{ 0x08ae, 0x23a0 }, /* botrightparens ⎠ ??? */
{ 0x08af, 0x23a8 }, /* leftmiddlecurlybrace ⎨ ??? */
{ 0x08b0, 0x23ac }, /* rightmiddlecurlybrace ⎬ ??? */
/* 0x08b1 topleftsummation ? ??? */
/* 0x08b2 botleftsummation ? ??? */
/* 0x08b3 topvertsummationconnector ? ??? */
/* 0x08b4 botvertsummationconnector ? ??? */
/* 0x08b5 toprightsummation ? ??? */
/* 0x08b6 botrightsummation ? ??? */
/* 0x08b7 rightmiddlesummation ? ??? */
{ 0x08bc, 0x2264 }, /* lessthanequal ≤ LESS-THAN OR EQUAL TO */
{ 0x08bd, 0x2260 }, /* notequal ≠ NOT EQUAL TO */
{ 0x08be, 0x2265 }, /* greaterthanequal ≥ GREATER-THAN OR EQUAL TO */
{ 0x08bf, 0x222b }, /* integral ∫ INTEGRAL */
{ 0x08c0, 0x2234 }, /* therefore ∴ THEREFORE */
{ 0x08c1, 0x221d }, /* variation ∝ PROPORTIONAL TO */
{ 0x08c2, 0x221e }, /* infinity ∞ INFINITY */
{ 0x08c5, 0x2207 }, /* nabla ∇ NABLA */
{ 0x08c8, 0x223c }, /* approximate TILDE OPERATOR */
{ 0x08c9, 0x2243 }, /* similarequal ≃ ASYMPTOTICALLY EQUAL TO */
{ 0x08cd, 0x21d4 }, /* ifonlyif ⇔ LEFT RIGHT DOUBLE ARROW */
{ 0x08ce, 0x21d2 }, /* implies ⇒ RIGHTWARDS DOUBLE ARROW */
{ 0x08cf, 0x2261 }, /* identical ≡ IDENTICAL TO */
{ 0x08d6, 0x221a }, /* radical √ SQUARE ROOT */
{ 0x08da, 0x2282 }, /* includedin ⊂ SUBSET OF */
{ 0x08db, 0x2283 }, /* includes ⊃ SUPERSET OF */
{ 0x08dc, 0x2229 }, /* intersection ∩ INTERSECTION */
{ 0x08dd, 0x222a }, /* union UNION */
{ 0x08de, 0x2227 }, /* logicaland ∧ LOGICAL AND */
{ 0x08df, 0x2228 }, /* logicalor LOGICAL OR */
{ 0x08ef, 0x2202 }, /* partialderivative ∂ PARTIAL DIFFERENTIAL */
{ 0x08f6, 0x0192 }, /* function ƒ LATIN SMALL LETTER F WITH HOOK */
{ 0x08fb, 0x2190 }, /* leftarrow ← LEFTWARDS ARROW */
{ 0x08fc, 0x2191 }, /* uparrow ↑ UPWARDS ARROW */
{ 0x08fd, 0x2192 }, /* rightarrow → RIGHTWARDS ARROW */
{ 0x08fe, 0x2193 }, /* downarrow ↓ DOWNWARDS ARROW */
/* 0x09df blank ? ??? */
{ 0x09e0, 0x25c6 }, /* soliddiamond ◆ BLACK DIAMOND */
{ 0x09e1, 0x2592 }, /* checkerboard ▒ MEDIUM SHADE */
{ 0x09e2, 0x2409 }, /* ht ␉ SYMBOL FOR HORIZONTAL TABULATION */
{ 0x09e3, 0x240c }, /* ff ␌ SYMBOL FOR FORM FEED */
{ 0x09e4, 0x240d }, /* cr ␍ SYMBOL FOR CARRIAGE RETURN */
{ 0x09e5, 0x240a }, /* lf ␊ SYMBOL FOR LINE FEED */
{ 0x09e8, 0x2424 }, /* nl ␤ SYMBOL FOR NEWLINE */
{ 0x09e9, 0x240b }, /* vt ␋ SYMBOL FOR VERTICAL TABULATION */
{ 0x09ea, 0x2518 }, /* lowrightcorner ┘ BOX DRAWINGS LIGHT UP AND LEFT */
{ 0x09eb, 0x2510 }, /* uprightcorner ┐ BOX DRAWINGS LIGHT DOWN AND LEFT */
{ 0x09ec, 0x250c }, /* upleftcorner ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */
{ 0x09ed, 0x2514 }, /* lowleftcorner └ BOX DRAWINGS LIGHT UP AND RIGHT */
{ 0x09ee, 0x253c }, /* crossinglines ┼ BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */
{ 0x09ef, 0x23ba }, /* horizlinescan1 ⎺ HORIZONTAL SCAN LINE-1 (Unicode 3.2 draft) */
{ 0x09f0, 0x23bb }, /* horizlinescan3 ⎻ HORIZONTAL SCAN LINE-3 (Unicode 3.2 draft) */
{ 0x09f1, 0x2500 }, /* horizlinescan5 ─ BOX DRAWINGS LIGHT HORIZONTAL */
{ 0x09f2, 0x23bc }, /* horizlinescan7 ⎼ HORIZONTAL SCAN LINE-7 (Unicode 3.2 draft) */
{ 0x09f3, 0x23bd }, /* horizlinescan9 ⎽ HORIZONTAL SCAN LINE-9 (Unicode 3.2 draft) */
{ 0x09f4, 0x251c }, /* leftt ├ BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
{ 0x09f5, 0x2524 }, /* rightt ┤ BOX DRAWINGS LIGHT VERTICAL AND LEFT */
{ 0x09f6, 0x2534 }, /* bott ┴ BOX DRAWINGS LIGHT UP AND HORIZONTAL */
{ 0x09f7, 0x252c }, /* topt ┬ BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */
{ 0x09f8, 0x2502 }, /* vertbar │ BOX DRAWINGS LIGHT VERTICAL */
{ 0x0aa1, 0x2003 }, /* emspace EM SPACE */
{ 0x0aa2, 0x2002 }, /* enspace EN SPACE */
{ 0x0aa3, 0x2004 }, /* em3space THREE-PER-EM SPACE */
{ 0x0aa4, 0x2005 }, /* em4space FOUR-PER-EM SPACE */
{ 0x0aa5, 0x2007 }, /* digitspace FIGURE SPACE */
{ 0x0aa6, 0x2008 }, /* punctspace PUNCTUATION SPACE */
{ 0x0aa7, 0x2009 }, /* thinspace THIN SPACE */
{ 0x0aa8, 0x200a }, /* hairspace HAIR SPACE */
{ 0x0aa9, 0x2014 }, /* emdash — EM DASH */
{ 0x0aaa, 0x2013 }, /* endash EN DASH */
/* 0x0aac signifblank ? ??? */
{ 0x0aae, 0x2026 }, /* ellipsis … HORIZONTAL ELLIPSIS */
{ 0x0aaf, 0x2025 }, /* doubbaselinedot ‥ TWO DOT LEADER */
{ 0x0ab0, 0x2153 }, /* onethird ⅓ VULGAR FRACTION ONE THIRD */
{ 0x0ab1, 0x2154 }, /* twothirds ⅔ VULGAR FRACTION TWO THIRDS */
{ 0x0ab2, 0x2155 }, /* onefifth ⅕ VULGAR FRACTION ONE FIFTH */
{ 0x0ab3, 0x2156 }, /* twofifths ⅖ VULGAR FRACTION TWO FIFTHS */
{ 0x0ab4, 0x2157 }, /* threefifths ⅗ VULGAR FRACTION THREE FIFTHS */
{ 0x0ab5, 0x2158 }, /* fourfifths ⅘ VULGAR FRACTION FOUR FIFTHS */
{ 0x0ab6, 0x2159 }, /* onesixth ⅙ VULGAR FRACTION ONE SIXTH */
{ 0x0ab7, 0x215a }, /* fivesixths ⅚ VULGAR FRACTION FIVE SIXTHS */
{ 0x0ab8, 0x2105 }, /* careof ℅ CARE OF */
{ 0x0abb, 0x2012 }, /* figdash FIGURE DASH */
{ 0x0abc, 0x2329 }, /* leftanglebracket 〈 LEFT-POINTING ANGLE BRACKET */
/* 0x0abd decimalpoint ? ??? */
{ 0x0abe, 0x232a }, /* rightanglebracket 〉 RIGHT-POINTING ANGLE BRACKET */
/* 0x0abf marker ? ??? */
{ 0x0ac3, 0x215b }, /* oneeighth ⅛ VULGAR FRACTION ONE EIGHTH */
{ 0x0ac4, 0x215c }, /* threeeighths ⅜ VULGAR FRACTION THREE EIGHTHS */
{ 0x0ac5, 0x215d }, /* fiveeighths ⅝ VULGAR FRACTION FIVE EIGHTHS */
{ 0x0ac6, 0x215e }, /* seveneighths ⅞ VULGAR FRACTION SEVEN EIGHTHS */
{ 0x0ac9, 0x2122 }, /* trademark ™ TRADE MARK SIGN */
{ 0x0aca, 0x2613 }, /* signaturemark ☓ SALTIRE */
/* 0x0acb trademarkincircle ? ??? */
{ 0x0acc, 0x25c1 }, /* leftopentriangle ◁ WHITE LEFT-POINTING TRIANGLE */
{ 0x0acd, 0x25b7 }, /* rightopentriangle ▷ WHITE RIGHT-POINTING TRIANGLE */
{ 0x0ace, 0x25cb }, /* emopencircle ○ WHITE CIRCLE */
{ 0x0acf, 0x25af }, /* emopenrectangle ▯ WHITE VERTICAL RECTANGLE */
{ 0x0ad0, 0x2018 }, /* leftsinglequotemark LEFT SINGLE QUOTATION MARK */
{ 0x0ad1, 0x2019 }, /* rightsinglequotemark RIGHT SINGLE QUOTATION MARK */
{ 0x0ad2, 0x201c }, /* leftdoublequotemark “ LEFT DOUBLE QUOTATION MARK */
{ 0x0ad3, 0x201d }, /* rightdoublequotemark ” RIGHT DOUBLE QUOTATION MARK */
{ 0x0ad4, 0x211e }, /* prescription ℞ PRESCRIPTION TAKE */
{ 0x0ad6, 0x2032 }, /* minutes PRIME */
{ 0x0ad7, 0x2033 }, /* seconds ″ DOUBLE PRIME */
{ 0x0ad9, 0x271d }, /* latincross ✝ LATIN CROSS */
/* 0x0ada hexagram ? ??? */
{ 0x0adb, 0x25ac }, /* filledrectbullet ▬ BLACK RECTANGLE */
{ 0x0adc, 0x25c0 }, /* filledlefttribullet ◀ BLACK LEFT-POINTING TRIANGLE */
{ 0x0add, 0x25b6 }, /* filledrighttribullet ▶ BLACK RIGHT-POINTING TRIANGLE */
{ 0x0ade, 0x25cf }, /* emfilledcircle ● BLACK CIRCLE */
{ 0x0adf, 0x25ae }, /* emfilledrect ▮ BLACK VERTICAL RECTANGLE */
{ 0x0ae0, 0x25e6 }, /* enopencircbullet ◦ WHITE BULLET */
{ 0x0ae1, 0x25ab }, /* enopensquarebullet ▫ WHITE SMALL SQUARE */
{ 0x0ae2, 0x25ad }, /* openrectbullet ▭ WHITE RECTANGLE */
{ 0x0ae3, 0x25b3 }, /* opentribulletup △ WHITE UP-POINTING TRIANGLE */
{ 0x0ae4, 0x25bd }, /* opentribulletdown ▽ WHITE DOWN-POINTING TRIANGLE */
{ 0x0ae5, 0x2606 }, /* openstar ☆ WHITE STAR */
{ 0x0ae6, 0x2022 }, /* enfilledcircbullet • BULLET */
{ 0x0ae7, 0x25aa }, /* enfilledsqbullet ▪ BLACK SMALL SQUARE */
{ 0x0ae8, 0x25b2 }, /* filledtribulletup ▲ BLACK UP-POINTING TRIANGLE */
{ 0x0ae9, 0x25bc }, /* filledtribulletdown ▼ BLACK DOWN-POINTING TRIANGLE */
{ 0x0aea, 0x261c }, /* leftpointer ☜ WHITE LEFT POINTING INDEX */
{ 0x0aeb, 0x261e }, /* rightpointer ☞ WHITE RIGHT POINTING INDEX */
{ 0x0aec, 0x2663 }, /* club ♣ BLACK CLUB SUIT */
{ 0x0aed, 0x2666 }, /* diamond ♦ BLACK DIAMOND SUIT */
{ 0x0aee, 0x2665 }, /* heart ♥ BLACK HEART SUIT */
{ 0x0af0, 0x2720 }, /* maltesecross ✠ MALTESE CROSS */
{ 0x0af1, 0x2020 }, /* dagger † DAGGER */
{ 0x0af2, 0x2021 }, /* doubledagger ‡ DOUBLE DAGGER */
{ 0x0af3, 0x2713 }, /* checkmark ✓ CHECK MARK */
{ 0x0af4, 0x2717 }, /* ballotcross ✗ BALLOT X */
{ 0x0af5, 0x266f }, /* musicalsharp ♯ MUSIC SHARP SIGN */
{ 0x0af6, 0x266d }, /* musicalflat ♭ MUSIC FLAT SIGN */
{ 0x0af7, 0x2642 }, /* malesymbol ♂ MALE SIGN */
{ 0x0af8, 0x2640 }, /* femalesymbol ♀ FEMALE SIGN */
{ 0x0af9, 0x260e }, /* telephone ☎ BLACK TELEPHONE */
{ 0x0afa, 0x2315 }, /* telephonerecorder ⌕ TELEPHONE RECORDER */
{ 0x0afb, 0x2117 }, /* phonographcopyright ℗ SOUND RECORDING COPYRIGHT */
{ 0x0afc, 0x2038 }, /* caret ‸ CARET */
{ 0x0afd, 0x201a }, /* singlelowquotemark SINGLE LOW-9 QUOTATION MARK */
{ 0x0afe, 0x201e }, /* doublelowquotemark „ DOUBLE LOW-9 QUOTATION MARK */
/* 0x0aff cursor ? ??? */
{ 0x0ba3, 0x003c }, /* leftcaret < LESS-THAN SIGN */
{ 0x0ba6, 0x003e }, /* rightcaret > GREATER-THAN SIGN */
{ 0x0ba8, 0x2228 }, /* downcaret LOGICAL OR */
{ 0x0ba9, 0x2227 }, /* upcaret ∧ LOGICAL AND */
{ 0x0bc0, 0x00af }, /* overbar ¯ MACRON */
{ 0x0bc2, 0x22a5 }, /* downtack ⊥ UP TACK */
{ 0x0bc3, 0x2229 }, /* upshoe ∩ INTERSECTION */
{ 0x0bc4, 0x230a }, /* downstile ⌊ LEFT FLOOR */
{ 0x0bc6, 0x005f }, /* underbar _ LOW LINE */
{ 0x0bca, 0x2218 }, /* jot ∘ RING OPERATOR */
{ 0x0bcc, 0x2395 }, /* quad ⎕ APL FUNCTIONAL SYMBOL QUAD */
{ 0x0bce, 0x22a4 }, /* uptack DOWN TACK */
{ 0x0bcf, 0x25cb }, /* circle ○ WHITE CIRCLE */
{ 0x0bd3, 0x2308 }, /* upstile ⌈ LEFT CEILING */
{ 0x0bd6, 0x222a }, /* downshoe UNION */
{ 0x0bd8, 0x2283 }, /* rightshoe ⊃ SUPERSET OF */
{ 0x0bda, 0x2282 }, /* leftshoe ⊂ SUBSET OF */
{ 0x0bdc, 0x22a2 }, /* lefttack ⊢ RIGHT TACK */
{ 0x0bfc, 0x22a3 }, /* righttack ⊣ LEFT TACK */
{ 0x0cdf, 0x2017 }, /* hebrew_doublelowline ‗ DOUBLE LOW LINE */
{ 0x0ce0, 0x05d0 }, /* hebrew_aleph א HEBREW LETTER ALEF */
{ 0x0ce1, 0x05d1 }, /* hebrew_bet ב HEBREW LETTER BET */
{ 0x0ce2, 0x05d2 }, /* hebrew_gimel ג HEBREW LETTER GIMEL */
{ 0x0ce3, 0x05d3 }, /* hebrew_dalet ד HEBREW LETTER DALET */
{ 0x0ce4, 0x05d4 }, /* hebrew_he ה HEBREW LETTER HE */
{ 0x0ce5, 0x05d5 }, /* hebrew_waw ו HEBREW LETTER VAV */
{ 0x0ce6, 0x05d6 }, /* hebrew_zain ז HEBREW LETTER ZAYIN */
{ 0x0ce7, 0x05d7 }, /* hebrew_chet ח HEBREW LETTER HET */
{ 0x0ce8, 0x05d8 }, /* hebrew_tet ט HEBREW LETTER TET */
{ 0x0ce9, 0x05d9 }, /* hebrew_yod י HEBREW LETTER YOD */
{ 0x0cea, 0x05da }, /* hebrew_finalkaph ך HEBREW LETTER FINAL KAF */
{ 0x0ceb, 0x05db }, /* hebrew_kaph כ HEBREW LETTER KAF */
{ 0x0cec, 0x05dc }, /* hebrew_lamed ל HEBREW LETTER LAMED */
{ 0x0ced, 0x05dd }, /* hebrew_finalmem ם HEBREW LETTER FINAL MEM */
{ 0x0cee, 0x05de }, /* hebrew_mem מ HEBREW LETTER MEM */
{ 0x0cef, 0x05df }, /* hebrew_finalnun ן HEBREW LETTER FINAL NUN */
{ 0x0cf0, 0x05e0 }, /* hebrew_nun נ HEBREW LETTER NUN */
{ 0x0cf1, 0x05e1 }, /* hebrew_samech ס HEBREW LETTER SAMEKH */
{ 0x0cf2, 0x05e2 }, /* hebrew_ayin ע HEBREW LETTER AYIN */
{ 0x0cf3, 0x05e3 }, /* hebrew_finalpe ף HEBREW LETTER FINAL PE */
{ 0x0cf4, 0x05e4 }, /* hebrew_pe פ HEBREW LETTER PE */
{ 0x0cf5, 0x05e5 }, /* hebrew_finalzade ץ HEBREW LETTER FINAL TSADI */
{ 0x0cf6, 0x05e6 }, /* hebrew_zade צ HEBREW LETTER TSADI */
{ 0x0cf7, 0x05e7 }, /* hebrew_qoph ק HEBREW LETTER QOF */
{ 0x0cf8, 0x05e8 }, /* hebrew_resh ר HEBREW LETTER RESH */
{ 0x0cf9, 0x05e9 }, /* hebrew_shin ש HEBREW LETTER SHIN */
{ 0x0cfa, 0x05ea }, /* hebrew_taw ת HEBREW LETTER TAV */
{ 0x0da1, 0x0e01 }, /* Thai_kokai ก THAI CHARACTER KO KAI */
{ 0x0da2, 0x0e02 }, /* Thai_khokhai ข THAI CHARACTER KHO KHAI */
{ 0x0da3, 0x0e03 }, /* Thai_khokhuat ฃ THAI CHARACTER KHO KHUAT */
{ 0x0da4, 0x0e04 }, /* Thai_khokhwai ค THAI CHARACTER KHO KHWAI */
{ 0x0da5, 0x0e05 }, /* Thai_khokhon ฅ THAI CHARACTER KHO KHON */
{ 0x0da6, 0x0e06 }, /* Thai_khorakhang ฆ THAI CHARACTER KHO RAKHANG */
{ 0x0da7, 0x0e07 }, /* Thai_ngongu ง THAI CHARACTER NGO NGU */
{ 0x0da8, 0x0e08 }, /* Thai_chochan จ THAI CHARACTER CHO CHAN */
{ 0x0da9, 0x0e09 }, /* Thai_choching ฉ THAI CHARACTER CHO CHING */
{ 0x0daa, 0x0e0a }, /* Thai_chochang ช THAI CHARACTER CHO CHANG */
{ 0x0dab, 0x0e0b }, /* Thai_soso ซ THAI CHARACTER SO SO */
{ 0x0dac, 0x0e0c }, /* Thai_chochoe ฌ THAI CHARACTER CHO CHOE */
{ 0x0dad, 0x0e0d }, /* Thai_yoying ญ THAI CHARACTER YO YING */
{ 0x0dae, 0x0e0e }, /* Thai_dochada ฎ THAI CHARACTER DO CHADA */
{ 0x0daf, 0x0e0f }, /* Thai_topatak ฏ THAI CHARACTER TO PATAK */
{ 0x0db0, 0x0e10 }, /* Thai_thothan ฐ THAI CHARACTER THO THAN */
{ 0x0db1, 0x0e11 }, /* Thai_thonangmontho ฑ THAI CHARACTER THO NANGMONTHO */
{ 0x0db2, 0x0e12 }, /* Thai_thophuthao ฒ THAI CHARACTER THO PHUTHAO */
{ 0x0db3, 0x0e13 }, /* Thai_nonen ณ THAI CHARACTER NO NEN */
{ 0x0db4, 0x0e14 }, /* Thai_dodek ด THAI CHARACTER DO DEK */
{ 0x0db5, 0x0e15 }, /* Thai_totao ต THAI CHARACTER TO TAO */
{ 0x0db6, 0x0e16 }, /* Thai_thothung ถ THAI CHARACTER THO THUNG */
{ 0x0db7, 0x0e17 }, /* Thai_thothahan ท THAI CHARACTER THO THAHAN */
{ 0x0db8, 0x0e18 }, /* Thai_thothong ธ THAI CHARACTER THO THONG */
{ 0x0db9, 0x0e19 }, /* Thai_nonu น THAI CHARACTER NO NU */
{ 0x0dba, 0x0e1a }, /* Thai_bobaimai บ THAI CHARACTER BO BAIMAI */
{ 0x0dbb, 0x0e1b }, /* Thai_popla ป THAI CHARACTER PO PLA */
{ 0x0dbc, 0x0e1c }, /* Thai_phophung ผ THAI CHARACTER PHO PHUNG */
{ 0x0dbd, 0x0e1d }, /* Thai_fofa ฝ THAI CHARACTER FO FA */
{ 0x0dbe, 0x0e1e }, /* Thai_phophan พ THAI CHARACTER PHO PHAN */
{ 0x0dbf, 0x0e1f }, /* Thai_fofan ฟ THAI CHARACTER FO FAN */
{ 0x0dc0, 0x0e20 }, /* Thai_phosamphao ภ THAI CHARACTER PHO SAMPHAO */
{ 0x0dc1, 0x0e21 }, /* Thai_moma ม THAI CHARACTER MO MA */
{ 0x0dc2, 0x0e22 }, /* Thai_yoyak ย THAI CHARACTER YO YAK */
{ 0x0dc3, 0x0e23 }, /* Thai_rorua ร THAI CHARACTER RO RUA */
{ 0x0dc4, 0x0e24 }, /* Thai_ru ฤ THAI CHARACTER RU */
{ 0x0dc5, 0x0e25 }, /* Thai_loling ล THAI CHARACTER LO LING */
{ 0x0dc6, 0x0e26 }, /* Thai_lu ฦ THAI CHARACTER LU */
{ 0x0dc7, 0x0e27 }, /* Thai_wowaen ว THAI CHARACTER WO WAEN */
{ 0x0dc8, 0x0e28 }, /* Thai_sosala ศ THAI CHARACTER SO SALA */
{ 0x0dc9, 0x0e29 }, /* Thai_sorusi ษ THAI CHARACTER SO RUSI */
{ 0x0dca, 0x0e2a }, /* Thai_sosua ส THAI CHARACTER SO SUA */
{ 0x0dcb, 0x0e2b }, /* Thai_hohip ห THAI CHARACTER HO HIP */
{ 0x0dcc, 0x0e2c }, /* Thai_lochula ฬ THAI CHARACTER LO CHULA */
{ 0x0dcd, 0x0e2d }, /* Thai_oang อ THAI CHARACTER O ANG */
{ 0x0dce, 0x0e2e }, /* Thai_honokhuk ฮ THAI CHARACTER HO NOKHUK */
{ 0x0dcf, 0x0e2f }, /* Thai_paiyannoi ฯ THAI CHARACTER PAIYANNOI */
{ 0x0dd0, 0x0e30 }, /* Thai_saraa ะ THAI CHARACTER SARA A */
{ 0x0dd1, 0x0e31 }, /* Thai_maihanakat ั THAI CHARACTER MAI HAN-AKAT */
{ 0x0dd2, 0x0e32 }, /* Thai_saraaa า THAI CHARACTER SARA AA */
{ 0x0dd3, 0x0e33 }, /* Thai_saraam ำ THAI CHARACTER SARA AM */
{ 0x0dd4, 0x0e34 }, /* Thai_sarai ิ THAI CHARACTER SARA I */
{ 0x0dd5, 0x0e35 }, /* Thai_saraii ี THAI CHARACTER SARA II */
{ 0x0dd6, 0x0e36 }, /* Thai_saraue ึ THAI CHARACTER SARA UE */
{ 0x0dd7, 0x0e37 }, /* Thai_sarauee ื THAI CHARACTER SARA UEE */
{ 0x0dd8, 0x0e38 }, /* Thai_sarau ุ THAI CHARACTER SARA U */
{ 0x0dd9, 0x0e39 }, /* Thai_sarauu ู THAI CHARACTER SARA UU */
{ 0x0dda, 0x0e3a }, /* Thai_phinthu ฺ THAI CHARACTER PHINTHU */
/* 0x0dde Thai_maihanakat_maitho ? ??? */
{ 0x0ddf, 0x0e3f }, /* Thai_baht ฿ THAI CURRENCY SYMBOL BAHT */
{ 0x0de0, 0x0e40 }, /* Thai_sarae เ THAI CHARACTER SARA E */
{ 0x0de1, 0x0e41 }, /* Thai_saraae แ THAI CHARACTER SARA AE */
{ 0x0de2, 0x0e42 }, /* Thai_sarao โ THAI CHARACTER SARA O */
{ 0x0de3, 0x0e43 }, /* Thai_saraaimaimuan ใ THAI CHARACTER SARA AI MAIMUAN */
{ 0x0de4, 0x0e44 }, /* Thai_saraaimaimalai ไ THAI CHARACTER SARA AI MAIMALAI */
{ 0x0de5, 0x0e45 }, /* Thai_lakkhangyao ๅ THAI CHARACTER LAKKHANGYAO */
{ 0x0de6, 0x0e46 }, /* Thai_maiyamok ๆ THAI CHARACTER MAIYAMOK */
{ 0x0de7, 0x0e47 }, /* Thai_maitaikhu ็ THAI CHARACTER MAITAIKHU */
{ 0x0de8, 0x0e48 }, /* Thai_maiek ่ THAI CHARACTER MAI EK */
{ 0x0de9, 0x0e49 }, /* Thai_maitho ้ THAI CHARACTER MAI THO */
{ 0x0dea, 0x0e4a }, /* Thai_maitri ๊ THAI CHARACTER MAI TRI */
{ 0x0deb, 0x0e4b }, /* Thai_maichattawa ๋ THAI CHARACTER MAI CHATTAWA */
{ 0x0dec, 0x0e4c }, /* Thai_thanthakhat ์ THAI CHARACTER THANTHAKHAT */
{ 0x0ded, 0x0e4d }, /* Thai_nikhahit ํ THAI CHARACTER NIKHAHIT */
{ 0x0df0, 0x0e50 }, /* Thai_leksun THAI DIGIT ZERO */
{ 0x0df1, 0x0e51 }, /* Thai_leknung ๑ THAI DIGIT ONE */
{ 0x0df2, 0x0e52 }, /* Thai_leksong ๒ THAI DIGIT TWO */
{ 0x0df3, 0x0e53 }, /* Thai_leksam ๓ THAI DIGIT THREE */
{ 0x0df4, 0x0e54 }, /* Thai_leksi ๔ THAI DIGIT FOUR */
{ 0x0df5, 0x0e55 }, /* Thai_lekha ๕ THAI DIGIT FIVE */
{ 0x0df6, 0x0e56 }, /* Thai_lekhok ๖ THAI DIGIT SIX */
{ 0x0df7, 0x0e57 }, /* Thai_lekchet ๗ THAI DIGIT SEVEN */
{ 0x0df8, 0x0e58 }, /* Thai_lekpaet ๘ THAI DIGIT EIGHT */
{ 0x0df9, 0x0e59 }, /* Thai_lekkao ๙ THAI DIGIT NINE */
{ 0x0ea1, 0x3131 }, /* Hangul_Kiyeog ㄱ HANGUL LETTER KIYEOK */
{ 0x0ea2, 0x3132 }, /* Hangul_SsangKiyeog ㄲ HANGUL LETTER SSANGKIYEOK */
{ 0x0ea3, 0x3133 }, /* Hangul_KiyeogSios ㄳ HANGUL LETTER KIYEOK-SIOS */
{ 0x0ea4, 0x3134 }, /* Hangul_Nieun ㄴ HANGUL LETTER NIEUN */
{ 0x0ea5, 0x3135 }, /* Hangul_NieunJieuj ㄵ HANGUL LETTER NIEUN-CIEUC */
{ 0x0ea6, 0x3136 }, /* Hangul_NieunHieuh ㄶ HANGUL LETTER NIEUN-HIEUH */
{ 0x0ea7, 0x3137 }, /* Hangul_Dikeud ㄷ HANGUL LETTER TIKEUT */
{ 0x0ea8, 0x3138 }, /* Hangul_SsangDikeud ㄸ HANGUL LETTER SSANGTIKEUT */
{ 0x0ea9, 0x3139 }, /* Hangul_Rieul ㄹ HANGUL LETTER RIEUL */
{ 0x0eaa, 0x313a }, /* Hangul_RieulKiyeog ㄺ HANGUL LETTER RIEUL-KIYEOK */
{ 0x0eab, 0x313b }, /* Hangul_RieulMieum ㄻ HANGUL LETTER RIEUL-MIEUM */
{ 0x0eac, 0x313c }, /* Hangul_RieulPieub ㄼ HANGUL LETTER RIEUL-PIEUP */
{ 0x0ead, 0x313d }, /* Hangul_RieulSios ㄽ HANGUL LETTER RIEUL-SIOS */
{ 0x0eae, 0x313e }, /* Hangul_RieulTieut ㄾ HANGUL LETTER RIEUL-THIEUTH */
{ 0x0eaf, 0x313f }, /* Hangul_RieulPhieuf ㄿ HANGUL LETTER RIEUL-PHIEUPH */
{ 0x0eb0, 0x3140 }, /* Hangul_RieulHieuh ㅀ HANGUL LETTER RIEUL-HIEUH */
{ 0x0eb1, 0x3141 }, /* Hangul_Mieum ㅁ HANGUL LETTER MIEUM */
{ 0x0eb2, 0x3142 }, /* Hangul_Pieub ㅂ HANGUL LETTER PIEUP */
{ 0x0eb3, 0x3143 }, /* Hangul_SsangPieub ㅃ HANGUL LETTER SSANGPIEUP */
{ 0x0eb4, 0x3144 }, /* Hangul_PieubSios ㅄ HANGUL LETTER PIEUP-SIOS */
{ 0x0eb5, 0x3145 }, /* Hangul_Sios ㅅ HANGUL LETTER SIOS */
{ 0x0eb6, 0x3146 }, /* Hangul_SsangSios ㅆ HANGUL LETTER SSANGSIOS */
{ 0x0eb7, 0x3147 }, /* Hangul_Ieung ㅇ HANGUL LETTER IEUNG */
{ 0x0eb8, 0x3148 }, /* Hangul_Jieuj ㅈ HANGUL LETTER CIEUC */
{ 0x0eb9, 0x3149 }, /* Hangul_SsangJieuj ㅉ HANGUL LETTER SSANGCIEUC */
{ 0x0eba, 0x314a }, /* Hangul_Cieuc ㅊ HANGUL LETTER CHIEUCH */
{ 0x0ebb, 0x314b }, /* Hangul_Khieuq ㅋ HANGUL LETTER KHIEUKH */
{ 0x0ebc, 0x314c }, /* Hangul_Tieut ㅌ HANGUL LETTER THIEUTH */
{ 0x0ebd, 0x314d }, /* Hangul_Phieuf ㅍ HANGUL LETTER PHIEUPH */
{ 0x0ebe, 0x314e }, /* Hangul_Hieuh ㅎ HANGUL LETTER HIEUH */
{ 0x0ebf, 0x314f }, /* Hangul_A ㅏ HANGUL LETTER A */
{ 0x0ec0, 0x3150 }, /* Hangul_AE ㅐ HANGUL LETTER AE */
{ 0x0ec1, 0x3151 }, /* Hangul_YA ㅑ HANGUL LETTER YA */
{ 0x0ec2, 0x3152 }, /* Hangul_YAE ㅒ HANGUL LETTER YAE */
{ 0x0ec3, 0x3153 }, /* Hangul_EO ㅓ HANGUL LETTER EO */
{ 0x0ec4, 0x3154 }, /* Hangul_E ㅔ HANGUL LETTER E */
{ 0x0ec5, 0x3155 }, /* Hangul_YEO ㅕ HANGUL LETTER YEO */
{ 0x0ec6, 0x3156 }, /* Hangul_YE ㅖ HANGUL LETTER YE */
{ 0x0ec7, 0x3157 }, /* Hangul_O ㅗ HANGUL LETTER O */
{ 0x0ec8, 0x3158 }, /* Hangul_WA ㅘ HANGUL LETTER WA */
{ 0x0ec9, 0x3159 }, /* Hangul_WAE ㅙ HANGUL LETTER WAE */
{ 0x0eca, 0x315a }, /* Hangul_OE ㅚ HANGUL LETTER OE */
{ 0x0ecb, 0x315b }, /* Hangul_YO ㅛ HANGUL LETTER YO */
{ 0x0ecc, 0x315c }, /* Hangul_U ㅜ HANGUL LETTER U */
{ 0x0ecd, 0x315d }, /* Hangul_WEO ㅝ HANGUL LETTER WEO */
{ 0x0ece, 0x315e }, /* Hangul_WE ㅞ HANGUL LETTER WE */
{ 0x0ecf, 0x315f }, /* Hangul_WI ㅟ HANGUL LETTER WI */
{ 0x0ed0, 0x3160 }, /* Hangul_YU ㅠ HANGUL LETTER YU */
{ 0x0ed1, 0x3161 }, /* Hangul_EU ㅡ HANGUL LETTER EU */
{ 0x0ed2, 0x3162 }, /* Hangul_YI ㅢ HANGUL LETTER YI */
{ 0x0ed3, 0x3163 }, /* Hangul_I ㅣ HANGUL LETTER I */
{ 0x0ed4, 0x11a8 }, /* Hangul_J_Kiyeog ᆨ HANGUL JONGSEONG KIYEOK */
{ 0x0ed5, 0x11a9 }, /* Hangul_J_SsangKiyeog ᆩ HANGUL JONGSEONG SSANGKIYEOK */
{ 0x0ed6, 0x11aa }, /* Hangul_J_KiyeogSios ᆪ HANGUL JONGSEONG KIYEOK-SIOS */
{ 0x0ed7, 0x11ab }, /* Hangul_J_Nieun ᆫ HANGUL JONGSEONG NIEUN */
{ 0x0ed8, 0x11ac }, /* Hangul_J_NieunJieuj ᆬ HANGUL JONGSEONG NIEUN-CIEUC */
{ 0x0ed9, 0x11ad }, /* Hangul_J_NieunHieuh ᆭ HANGUL JONGSEONG NIEUN-HIEUH */
{ 0x0eda, 0x11ae }, /* Hangul_J_Dikeud ᆮ HANGUL JONGSEONG TIKEUT */
{ 0x0edb, 0x11af }, /* Hangul_J_Rieul ᆯ HANGUL JONGSEONG RIEUL */
{ 0x0edc, 0x11b0 }, /* Hangul_J_RieulKiyeog ᆰ HANGUL JONGSEONG RIEUL-KIYEOK */
{ 0x0edd, 0x11b1 }, /* Hangul_J_RieulMieum ᆱ HANGUL JONGSEONG RIEUL-MIEUM */
{ 0x0ede, 0x11b2 }, /* Hangul_J_RieulPieub ᆲ HANGUL JONGSEONG RIEUL-PIEUP */
{ 0x0edf, 0x11b3 }, /* Hangul_J_RieulSios ᆳ HANGUL JONGSEONG RIEUL-SIOS */
{ 0x0ee0, 0x11b4 }, /* Hangul_J_RieulTieut ᆴ HANGUL JONGSEONG RIEUL-THIEUTH */
{ 0x0ee1, 0x11b5 }, /* Hangul_J_RieulPhieuf ᆵ HANGUL JONGSEONG RIEUL-PHIEUPH */
{ 0x0ee2, 0x11b6 }, /* Hangul_J_RieulHieuh ᆶ HANGUL JONGSEONG RIEUL-HIEUH */
{ 0x0ee3, 0x11b7 }, /* Hangul_J_Mieum ᆷ HANGUL JONGSEONG MIEUM */
{ 0x0ee4, 0x11b8 }, /* Hangul_J_Pieub ᆸ HANGUL JONGSEONG PIEUP */
{ 0x0ee5, 0x11b9 }, /* Hangul_J_PieubSios ᆹ HANGUL JONGSEONG PIEUP-SIOS */
{ 0x0ee6, 0x11ba }, /* Hangul_J_Sios ᆺ HANGUL JONGSEONG SIOS */
{ 0x0ee7, 0x11bb }, /* Hangul_J_SsangSios ᆻ HANGUL JONGSEONG SSANGSIOS */
{ 0x0ee8, 0x11bc }, /* Hangul_J_Ieung ᆼ HANGUL JONGSEONG IEUNG */
{ 0x0ee9, 0x11bd }, /* Hangul_J_Jieuj ᆽ HANGUL JONGSEONG CIEUC */
{ 0x0eea, 0x11be }, /* Hangul_J_Cieuc ᆾ HANGUL JONGSEONG CHIEUCH */
{ 0x0eeb, 0x11bf }, /* Hangul_J_Khieuq ᆿ HANGUL JONGSEONG KHIEUKH */
{ 0x0eec, 0x11c0 }, /* Hangul_J_Tieut ᇀ HANGUL JONGSEONG THIEUTH */
{ 0x0eed, 0x11c1 }, /* Hangul_J_Phieuf ᇁ HANGUL JONGSEONG PHIEUPH */
{ 0x0eee, 0x11c2 }, /* Hangul_J_Hieuh ᇂ HANGUL JONGSEONG HIEUH */
{ 0x0eef, 0x316d }, /* Hangul_RieulYeorinHieuh ㅭ HANGUL LETTER RIEUL-YEORINHIEUH */
{ 0x0ef0, 0x3171 }, /* Hangul_SunkyeongeumMieum ㅱ HANGUL LETTER KAPYEOUNMIEUM */
{ 0x0ef1, 0x3178 }, /* Hangul_SunkyeongeumPieub ㅸ HANGUL LETTER KAPYEOUNPIEUP */
{ 0x0ef2, 0x317f }, /* Hangul_PanSios ㅿ HANGUL LETTER PANSIOS */
{ 0x0ef3, 0x3181 }, /* Hangul_KkogjiDalrinIeung ㆁ HANGUL LETTER YESIEUNG */
{ 0x0ef4, 0x3184 }, /* Hangul_SunkyeongeumPhieuf ㆄ HANGUL LETTER KAPYEOUNPHIEUPH */
{ 0x0ef5, 0x3186 }, /* Hangul_YeorinHieuh ㆆ HANGUL LETTER YEORINHIEUH */
{ 0x0ef6, 0x318d }, /* Hangul_AraeA ㆍ HANGUL LETTER ARAEA */
{ 0x0ef7, 0x318e }, /* Hangul_AraeAE ㆎ HANGUL LETTER ARAEAE */
{ 0x0ef8, 0x11eb }, /* Hangul_J_PanSios ᇫ HANGUL JONGSEONG PANSIOS */
{ 0x0ef9, 0x11f0 }, /* Hangul_J_KkogjiDalrinIeung ᇰ HANGUL JONGSEONG YESIEUNG */
{ 0x0efa, 0x11f9 }, /* Hangul_J_YeorinHieuh ᇹ HANGUL JONGSEONG YEORINHIEUH */
{ 0x0eff, 0x20a9 }, /* Korean_Won ₩ WON SIGN */
{ 0x13a4, 0x20ac }, /* Euro € EURO SIGN */
{ 0x13bc, 0x0152 }, /* OE ΠLATIN CAPITAL LIGATURE OE */
{ 0x13bd, 0x0153 }, /* oe œ LATIN SMALL LIGATURE OE */
{ 0x13be, 0x0178 }, /* Ydiaeresis Ÿ LATIN CAPITAL LETTER Y WITH DIAERESIS */
{ 0x20ac, 0x20ac }, /* EuroSign € EURO SIGN */
};
VISIBLE
long keysym2ucs(KeySym keysym)
{
int min = 0;
int max = sizeof(keysymtab) / sizeof(struct codepair) - 1;
int mid;
/* first check for Latin-1 characters (1:1 mapping) */
if ((keysym >= 0x0020 && keysym <= 0x007e) ||
(keysym >= 0x00a0 && keysym <= 0x00ff))
return keysym;
/* also check for directly encoded 24-bit UCS characters */
if ((keysym & 0xff000000) == 0x01000000)
return keysym & 0x00ffffff;
/* binary search in table */
while (max >= min) {
mid = (min + max) / 2;
if (keysymtab[mid].keysym < keysym)
min = mid + 1;
else if (keysymtab[mid].keysym > keysym)
max = mid - 1;
else {
/* found it */
return keysymtab[mid].ucs;
}
}
/* no matching Unicode value found */
return -1;
}

9
gui-x11/keysym2ucs.h Normal file
View File

@ -0,0 +1,9 @@
/* $XFree86: xc/programs/xterm/keysym2ucs.h,v 1.1 1999/06/12 15:37:18 dawes Exp $ */
/*
* This module converts keysym values into the corresponding ISO 10646-1
* (UCS, Unicode) values.
*/
#include <X11/X.h>
long keysym2ucs(KeySym keysym);

754
gui-x11/ksym2utf.h Normal file
View File

@ -0,0 +1,754 @@
static ulong
ksym2utf[] = {
[0x01a1] 0x0104,
[0x01a2] 0x02d8,
[0x01a3] 0x0141,
[0x01a5] 0x013d,
[0x01a6] 0x015a,
[0x01a9] 0x0160,
[0x01aa] 0x015e,
[0x01ab] 0x0164,
[0x01ac] 0x0179,
[0x01ae] 0x017d,
[0x01af] 0x017b,
[0x01b1] 0x0105,
[0x01b2] 0x02db,
[0x01b3] 0x0142,
[0x01b5] 0x013e,
[0x01b6] 0x015b,
[0x01b7] 0x02c7,
[0x01b9] 0x0161,
[0x01ba] 0x015f,
[0x01bb] 0x0165,
[0x01bc] 0x017a,
[0x01bd] 0x02dd,
[0x01be] 0x017e,
[0x01bf] 0x017c,
[0x01c0] 0x0154,
[0x01c3] 0x0102,
[0x01c5] 0x0139,
[0x01c6] 0x0106,
[0x01c8] 0x010c,
[0x01ca] 0x0118,
[0x01cc] 0x011a,
[0x01cf] 0x010e,
[0x01d0] 0x0110,
[0x01d1] 0x0143,
[0x01d2] 0x0147,
[0x01d5] 0x0150,
[0x01d8] 0x0158,
[0x01d9] 0x016e,
[0x01db] 0x0170,
[0x01de] 0x0162,
[0x01e0] 0x0155,
[0x01e3] 0x0103,
[0x01e5] 0x013a,
[0x01e6] 0x0107,
[0x01e8] 0x010d,
[0x01ea] 0x0119,
[0x01ec] 0x011b,
[0x01ef] 0x010f,
[0x01f0] 0x0111,
[0x01f1] 0x0144,
[0x01f2] 0x0148,
[0x01f5] 0x0151,
[0x01f8] 0x0159,
[0x01f9] 0x016f,
[0x01fb] 0x0171,
[0x01fe] 0x0163,
[0x01ff] 0x02d9,
[0x02a1] 0x0126,
[0x02a6] 0x0124,
[0x02a9] 0x0130,
[0x02ab] 0x011e,
[0x02ac] 0x0134,
[0x02b1] 0x0127,
[0x02b6] 0x0125,
[0x02b9] 0x0131,
[0x02bb] 0x011f,
[0x02bc] 0x0135,
[0x02c5] 0x010a,
[0x02c6] 0x0108,
[0x02d5] 0x0120,
[0x02d8] 0x011c,
[0x02dd] 0x016c,
[0x02de] 0x015c,
[0x02e5] 0x010b,
[0x02e6] 0x0109,
[0x02f5] 0x0121,
[0x02f8] 0x011d,
[0x02fd] 0x016d,
[0x02fe] 0x015d,
[0x03a2] 0x0138,
[0x03a3] 0x0156,
[0x03a5] 0x0128,
[0x03a6] 0x013b,
[0x03aa] 0x0112,
[0x03ab] 0x0122,
[0x03ac] 0x0166,
[0x03b3] 0x0157,
[0x03b5] 0x0129,
[0x03b6] 0x013c,
[0x03ba] 0x0113,
[0x03bb] 0x0123,
[0x03bc] 0x0167,
[0x03bd] 0x014a,
[0x03bf] 0x014b,
[0x03c0] 0x0100,
[0x03c7] 0x012e,
[0x03cc] 0x0116,
[0x03cf] 0x012a,
[0x03d1] 0x0145,
[0x03d2] 0x014c,
[0x03d3] 0x0136,
[0x03d9] 0x0172,
[0x03dd] 0x0168,
[0x03de] 0x016a,
[0x03e0] 0x0101,
[0x03e7] 0x012f,
[0x03ec] 0x0117,
[0x03ef] 0x012b,
[0x03f1] 0x0146,
[0x03f2] 0x014d,
[0x03f3] 0x0137,
[0x03f9] 0x0173,
[0x03fd] 0x0169,
[0x03fe] 0x016b,
[0x047e] 0x203e,
[0x04a1] 0x3002,
[0x04a2] 0x300c,
[0x04a3] 0x300d,
[0x04a4] 0x3001,
[0x04a5] 0x30fb,
[0x04a6] 0x30f2,
[0x04a7] 0x30a1,
[0x04a8] 0x30a3,
[0x04a9] 0x30a5,
[0x04aa] 0x30a7,
[0x04ab] 0x30a9,
[0x04ac] 0x30e3,
[0x04ad] 0x30e5,
[0x04ae] 0x30e7,
[0x04af] 0x30c3,
[0x04b0] 0x30fc,
[0x04b1] 0x30a2,
[0x04b2] 0x30a4,
[0x04b3] 0x30a6,
[0x04b4] 0x30a8,
[0x04b5] 0x30aa,
[0x04b6] 0x30ab,
[0x04b7] 0x30ad,
[0x04b8] 0x30af,
[0x04b9] 0x30b1,
[0x04ba] 0x30b3,
[0x04bb] 0x30b5,
[0x04bc] 0x30b7,
[0x04bd] 0x30b9,
[0x04be] 0x30bb,
[0x04bf] 0x30bd,
[0x04c0] 0x30bf,
[0x04c1] 0x30c1,
[0x04c2] 0x30c4,
[0x04c3] 0x30c6,
[0x04c4] 0x30c8,
[0x04c5] 0x30ca,
[0x04c6] 0x30cb,
[0x04c7] 0x30cc,
[0x04c8] 0x30cd,
[0x04c9] 0x30ce,
[0x04ca] 0x30cf,
[0x04cb] 0x30d2,
[0x04cc] 0x30d5,
[0x04cd] 0x30d8,
[0x04ce] 0x30db,
[0x04cf] 0x30de,
[0x04d0] 0x30df,
[0x04d1] 0x30e0,
[0x04d2] 0x30e1,
[0x04d3] 0x30e2,
[0x04d4] 0x30e4,
[0x04d5] 0x30e6,
[0x04d6] 0x30e8,
[0x04d7] 0x30e9,
[0x04d8] 0x30ea,
[0x04d9] 0x30eb,
[0x04da] 0x30ec,
[0x04db] 0x30ed,
[0x04dc] 0x30ef,
[0x04dd] 0x30f3,
[0x04de] 0x309b,
[0x04df] 0x309c,
[0x05ac] 0x060c,
[0x05bb] 0x061b,
[0x05bf] 0x061f,
[0x05c1] 0x0621,
[0x05c2] 0x0622,
[0x05c3] 0x0623,
[0x05c4] 0x0624,
[0x05c5] 0x0625,
[0x05c6] 0x0626,
[0x05c7] 0x0627,
[0x05c8] 0x0628,
[0x05c9] 0x0629,
[0x05ca] 0x062a,
[0x05cb] 0x062b,
[0x05cc] 0x062c,
[0x05cd] 0x062d,
[0x05ce] 0x062e,
[0x05cf] 0x062f,
[0x05d0] 0x0630,
[0x05d1] 0x0631,
[0x05d2] 0x0632,
[0x05d3] 0x0633,
[0x05d4] 0x0634,
[0x05d5] 0x0635,
[0x05d6] 0x0636,
[0x05d7] 0x0637,
[0x05d8] 0x0638,
[0x05d9] 0x0639,
[0x05da] 0x063a,
[0x05e0] 0x0640,
[0x05e1] 0x0641,
[0x05e2] 0x0642,
[0x05e3] 0x0643,
[0x05e4] 0x0644,
[0x05e5] 0x0645,
[0x05e6] 0x0646,
[0x05e7] 0x0647,
[0x05e8] 0x0648,
[0x05e9] 0x0649,
[0x05ea] 0x064a,
[0x05eb] 0x064b,
[0x05ec] 0x064c,
[0x05ed] 0x064d,
[0x05ee] 0x064e,
[0x05ef] 0x064f,
[0x05f0] 0x0650,
[0x05f1] 0x0651,
[0x05f2] 0x0652,
[0x06a1] 0x0452,
[0x06a2] 0x0453,
[0x06a3] 0x0451,
[0x06a4] 0x0454,
[0x06a5] 0x0455,
[0x06a6] 0x0456,
[0x06a7] 0x0457,
[0x06a8] 0x0458,
[0x06a9] 0x0459,
[0x06aa] 0x045a,
[0x06ab] 0x045b,
[0x06ac] 0x045c,
[0x06ae] 0x045e,
[0x06af] 0x045f,
[0x06b0] 0x2116,
[0x06b1] 0x0402,
[0x06b2] 0x0403,
[0x06b3] 0x0401,
[0x06b4] 0x0404,
[0x06b5] 0x0405,
[0x06b6] 0x0406,
[0x06b7] 0x0407,
[0x06b8] 0x0408,
[0x06b9] 0x0409,
[0x06ba] 0x040a,
[0x06bb] 0x040b,
[0x06bc] 0x040c,
[0x06be] 0x040e,
[0x06bf] 0x040f,
[0x06c0] 0x044e,
[0x06c1] 0x0430,
[0x06c2] 0x0431,
[0x06c3] 0x0446,
[0x06c4] 0x0434,
[0x06c5] 0x0435,
[0x06c6] 0x0444,
[0x06c7] 0x0433,
[0x06c8] 0x0445,
[0x06c9] 0x0438,
[0x06ca] 0x0439,
[0x06cb] 0x043a,
[0x06cc] 0x043b,
[0x06cd] 0x043c,
[0x06ce] 0x043d,
[0x06cf] 0x043e,
[0x06d0] 0x043f,
[0x06d1] 0x044f,
[0x06d2] 0x0440,
[0x06d3] 0x0441,
[0x06d4] 0x0442,
[0x06d5] 0x0443,
[0x06d6] 0x0436,
[0x06d7] 0x0432,
[0x06d8] 0x044c,
[0x06d9] 0x044b,
[0x06da] 0x0437,
[0x06db] 0x0448,
[0x06dc] 0x044d,
[0x06dd] 0x0449,
[0x06de] 0x0447,
[0x06df] 0x044a,
[0x06e0] 0x042e,
[0x06e1] 0x0410,
[0x06e2] 0x0411,
[0x06e3] 0x0426,
[0x06e4] 0x0414,
[0x06e5] 0x0415,
[0x06e6] 0x0424,
[0x06e7] 0x0413,
[0x06e8] 0x0425,
[0x06e9] 0x0418,
[0x06ea] 0x0419,
[0x06eb] 0x041a,
[0x06ec] 0x041b,
[0x06ed] 0x041c,
[0x06ee] 0x041d,
[0x06ef] 0x041e,
[0x06f0] 0x041f,
[0x06f1] 0x042f,
[0x06f2] 0x0420,
[0x06f3] 0x0421,
[0x06f4] 0x0422,
[0x06f5] 0x0423,
[0x06f6] 0x0416,
[0x06f7] 0x0412,
[0x06f8] 0x042c,
[0x06f9] 0x042b,
[0x06fa] 0x0417,
[0x06fb] 0x0428,
[0x06fc] 0x042d,
[0x06fd] 0x0429,
[0x06fe] 0x0427,
[0x06ff] 0x042a,
[0x07a1] 0x0386,
[0x07a2] 0x0388,
[0x07a3] 0x0389,
[0x07a4] 0x038a,
[0x07a5] 0x03aa,
[0x07a7] 0x038c,
[0x07a8] 0x038e,
[0x07a9] 0x03ab,
[0x07ab] 0x038f,
[0x07ae] 0x0385,
[0x07af] 0x2015,
[0x07b1] 0x03ac,
[0x07b2] 0x03ad,
[0x07b3] 0x03ae,
[0x07b4] 0x03af,
[0x07b5] 0x03ca,
[0x07b6] 0x0390,
[0x07b7] 0x03cc,
[0x07b8] 0x03cd,
[0x07b9] 0x03cb,
[0x07ba] 0x03b0,
[0x07bb] 0x03ce,
[0x07c1] 0x0391,
[0x07c2] 0x0392,
[0x07c3] 0x0393,
[0x07c4] 0x0394,
[0x07c5] 0x0395,
[0x07c6] 0x0396,
[0x07c7] 0x0397,
[0x07c8] 0x0398,
[0x07c9] 0x0399,
[0x07ca] 0x039a,
[0x07cb] 0x039b,
[0x07cc] 0x039c,
[0x07cd] 0x039d,
[0x07ce] 0x039e,
[0x07cf] 0x039f,
[0x07d0] 0x03a0,
[0x07d1] 0x03a1,
[0x07d2] 0x03a3,
[0x07d4] 0x03a4,
[0x07d5] 0x03a5,
[0x07d6] 0x03a6,
[0x07d7] 0x03a7,
[0x07d8] 0x03a8,
[0x07d9] 0x03a9,
[0x07e1] 0x03b1,
[0x07e2] 0x03b2,
[0x07e3] 0x03b3,
[0x07e4] 0x03b4,
[0x07e5] 0x03b5,
[0x07e6] 0x03b6,
[0x07e7] 0x03b7,
[0x07e8] 0x03b8,
[0x07e9] 0x03b9,
[0x07ea] 0x03ba,
[0x07eb] 0x03bb,
[0x07ec] 0x03bc,
[0x07ed] 0x03bd,
[0x07ee] 0x03be,
[0x07ef] 0x03bf,
[0x07f0] 0x03c0,
[0x07f1] 0x03c1,
[0x07f2] 0x03c3,
[0x07f3] 0x03c2,
[0x07f4] 0x03c4,
[0x07f5] 0x03c5,
[0x07f6] 0x03c6,
[0x07f7] 0x03c7,
[0x07f8] 0x03c8,
[0x07f9] 0x03c9,
[0x08a4] 0x2320,
[0x08a5] 0x2321,
[0x08a6] 0x2502,
[0x08bc] 0x2264,
[0x08bd] 0x2260,
[0x08be] 0x2265,
[0x08bf] 0x222b,
[0x08c0] 0x2234,
[0x08c1] 0x221d,
[0x08c2] 0x221e,
[0x08c5] 0x2207,
[0x08c8] 0x2245,
[0x08cd] 0x21d4,
[0x08ce] 0x21d2,
[0x08cf] 0x2261,
[0x08d6] 0x221a,
[0x08da] 0x2282,
[0x08db] 0x2283,
[0x08dc] 0x2229,
[0x08dd] 0x222a,
[0x08de] 0x2227,
[0x08df] 0x2228,
[0x08ef] 0x2202,
[0x08f6] 0x0192,
[0x08fb] 0x2190,
[0x08fc] 0x2191,
[0x08fd] 0x2192,
[0x08fe] 0x2193,
[0x09df] 0x2422,
[0x09e0] 0x25c6,
[0x09e1] 0x2592,
[0x09e2] 0x2409,
[0x09e3] 0x240c,
[0x09e4] 0x240d,
[0x09e5] 0x240a,
[0x09e8] 0x2424,
[0x09e9] 0x240b,
[0x09ea] 0x2518,
[0x09eb] 0x2510,
[0x09ec] 0x250c,
[0x09ed] 0x2514,
[0x09ee] 0x253c,
[0x09f1] 0x2500,
[0x09f4] 0x251c,
[0x09f5] 0x2524,
[0x09f6] 0x2534,
[0x09f7] 0x252c,
[0x09f8] 0x2502,
[0x0aa1] 0x2003,
[0x0aa2] 0x2002,
[0x0aa3] 0x2004,
[0x0aa4] 0x2005,
[0x0aa5] 0x2007,
[0x0aa6] 0x2008,
[0x0aa7] 0x2009,
[0x0aa8] 0x200a,
[0x0aa9] 0x2014,
[0x0aaa] 0x2013,
[0x0aae] 0x2026,
[0x0ab0] 0x2153,
[0x0ab1] 0x2154,
[0x0ab2] 0x2155,
[0x0ab3] 0x2156,
[0x0ab4] 0x2157,
[0x0ab5] 0x2158,
[0x0ab6] 0x2159,
[0x0ab7] 0x215a,
[0x0ab8] 0x2105,
[0x0abb] 0x2012,
[0x0abc] 0x2329,
[0x0abd] 0x002e,
[0x0abe] 0x232a,
[0x0ac3] 0x215b,
[0x0ac4] 0x215c,
[0x0ac5] 0x215d,
[0x0ac6] 0x215e,
[0x0ac9] 0x2122,
[0x0aca] 0x2613,
[0x0acc] 0x25c1,
[0x0acd] 0x25b7,
[0x0ace] 0x25cb,
[0x0acf] 0x25a1,
[0x0ad0] 0x2018,
[0x0ad1] 0x2019,
[0x0ad2] 0x201c,
[0x0ad3] 0x201d,
[0x0ad4] 0x211e,
[0x0ad6] 0x2032,
[0x0ad7] 0x2033,
[0x0ad9] 0x271d,
[0x0adb] 0x25ac,
[0x0adc] 0x25c0,
[0x0add] 0x25b6,
[0x0ade] 0x25cf,
[0x0adf] 0x25a0,
[0x0ae0] 0x25e6,
[0x0ae1] 0x25ab,
[0x0ae2] 0x25ad,
[0x0ae3] 0x25b3,
[0x0ae4] 0x25bd,
[0x0ae5] 0x2606,
[0x0ae6] 0x2022,
[0x0ae7] 0x25aa,
[0x0ae8] 0x25b2,
[0x0ae9] 0x25bc,
[0x0aea] 0x261c,
[0x0aeb] 0x261e,
[0x0aec] 0x2663,
[0x0aed] 0x2666,
[0x0aee] 0x2665,
[0x0af0] 0x2720,
[0x0af1] 0x2020,
[0x0af2] 0x2021,
[0x0af3] 0x2713,
[0x0af4] 0x2717,
[0x0af5] 0x266f,
[0x0af6] 0x266d,
[0x0af7] 0x2642,
[0x0af8] 0x2640,
[0x0af9] 0x260e,
[0x0afa] 0x2315,
[0x0afb] 0x2117,
[0x0afc] 0x2038,
[0x0afd] 0x201a,
[0x0afe] 0x201e,
[0x0ba3] 0x003c,
[0x0ba6] 0x003e,
[0x0ba8] 0x2228,
[0x0ba9] 0x2227,
[0x0bc0] 0x00af,
[0x0bc2] 0x22a4,
[0x0bc3] 0x2229,
[0x0bc4] 0x230a,
[0x0bc6] 0x005f,
[0x0bca] 0x2218,
[0x0bcc] 0x2395,
[0x0bce] 0x22a5,
[0x0bcf] 0x25cb,
[0x0bd3] 0x2308,
[0x0bd6] 0x222a,
[0x0bd8] 0x2283,
[0x0bda] 0x2282,
[0x0bdc] 0x22a3,
[0x0bfc] 0x22a2,
[0x0cdf] 0x2017,
[0x0ce0] 0x05d0,
[0x0ce1] 0x05d1,
[0x0ce2] 0x05d2,
[0x0ce3] 0x05d3,
[0x0ce4] 0x05d4,
[0x0ce5] 0x05d5,
[0x0ce6] 0x05d6,
[0x0ce7] 0x05d7,
[0x0ce8] 0x05d8,
[0x0ce9] 0x05d9,
[0x0cea] 0x05da,
[0x0ceb] 0x05db,
[0x0cec] 0x05dc,
[0x0ced] 0x05dd,
[0x0cee] 0x05de,
[0x0cef] 0x05df,
[0x0cf0] 0x05e0,
[0x0cf1] 0x05e1,
[0x0cf2] 0x05e2,
[0x0cf3] 0x05e3,
[0x0cf4] 0x05e4,
[0x0cf5] 0x05e5,
[0x0cf6] 0x05e6,
[0x0cf7] 0x05e7,
[0x0cf8] 0x05e8,
[0x0cf9] 0x05e9,
[0x0cfa] 0x05ea,
[0x0da1] 0x0e01,
[0x0da2] 0x0e02,
[0x0da3] 0x0e03,
[0x0da4] 0x0e04,
[0x0da5] 0x0e05,
[0x0da6] 0x0e06,
[0x0da7] 0x0e07,
[0x0da8] 0x0e08,
[0x0da9] 0x0e09,
[0x0daa] 0x0e0a,
[0x0dab] 0x0e0b,
[0x0dac] 0x0e0c,
[0x0dad] 0x0e0d,
[0x0dae] 0x0e0e,
[0x0daf] 0x0e0f,
[0x0db0] 0x0e10,
[0x0db1] 0x0e11,
[0x0db2] 0x0e12,
[0x0db3] 0x0e13,
[0x0db4] 0x0e14,
[0x0db5] 0x0e15,
[0x0db6] 0x0e16,
[0x0db7] 0x0e17,
[0x0db8] 0x0e18,
[0x0db9] 0x0e19,
[0x0dba] 0x0e1a,
[0x0dbb] 0x0e1b,
[0x0dbc] 0x0e1c,
[0x0dbd] 0x0e1d,
[0x0dbe] 0x0e1e,
[0x0dbf] 0x0e1f,
[0x0dc0] 0x0e20,
[0x0dc1] 0x0e21,
[0x0dc2] 0x0e22,
[0x0dc3] 0x0e23,
[0x0dc4] 0x0e24,
[0x0dc5] 0x0e25,
[0x0dc6] 0x0e26,
[0x0dc7] 0x0e27,
[0x0dc8] 0x0e28,
[0x0dc9] 0x0e29,
[0x0dca] 0x0e2a,
[0x0dcb] 0x0e2b,
[0x0dcc] 0x0e2c,
[0x0dcd] 0x0e2d,
[0x0dce] 0x0e2e,
[0x0dcf] 0x0e2f,
[0x0dd0] 0x0e30,
[0x0dd1] 0x0e31,
[0x0dd2] 0x0e32,
[0x0dd3] 0x0e33,
[0x0dd4] 0x0e34,
[0x0dd5] 0x0e35,
[0x0dd6] 0x0e36,
[0x0dd7] 0x0e37,
[0x0dd8] 0x0e38,
[0x0dd9] 0x0e39,
[0x0dda] 0x0e3a,
[0x0dde] 0x0e3e,
[0x0ddf] 0x0e3f,
[0x0de0] 0x0e40,
[0x0de1] 0x0e41,
[0x0de2] 0x0e42,
[0x0de3] 0x0e43,
[0x0de4] 0x0e44,
[0x0de5] 0x0e45,
[0x0de6] 0x0e46,
[0x0de7] 0x0e47,
[0x0de8] 0x0e48,
[0x0de9] 0x0e49,
[0x0dea] 0x0e4a,
[0x0deb] 0x0e4b,
[0x0dec] 0x0e4c,
[0x0ded] 0x0e4d,
[0x0df0] 0x0e50,
[0x0df1] 0x0e51,
[0x0df2] 0x0e52,
[0x0df3] 0x0e53,
[0x0df4] 0x0e54,
[0x0df5] 0x0e55,
[0x0df6] 0x0e56,
[0x0df7] 0x0e57,
[0x0df8] 0x0e58,
[0x0df9] 0x0e59,
[0x0ea1] 0x3131,
[0x0ea2] 0x3132,
[0x0ea3] 0x3133,
[0x0ea4] 0x3134,
[0x0ea5] 0x3135,
[0x0ea6] 0x3136,
[0x0ea7] 0x3137,
[0x0ea8] 0x3138,
[0x0ea9] 0x3139,
[0x0eaa] 0x313a,
[0x0eab] 0x313b,
[0x0eac] 0x313c,
[0x0ead] 0x313d,
[0x0eae] 0x313e,
[0x0eaf] 0x313f,
[0x0eb0] 0x3140,
[0x0eb1] 0x3141,
[0x0eb2] 0x3142,
[0x0eb3] 0x3143,
[0x0eb4] 0x3144,
[0x0eb5] 0x3145,
[0x0eb6] 0x3146,
[0x0eb7] 0x3147,
[0x0eb8] 0x3148,
[0x0eb9] 0x3149,
[0x0eba] 0x314a,
[0x0ebb] 0x314b,
[0x0ebc] 0x314c,
[0x0ebd] 0x314d,
[0x0ebe] 0x314e,
[0x0ebf] 0x314f,
[0x0ec0] 0x3150,
[0x0ec1] 0x3151,
[0x0ec2] 0x3152,
[0x0ec3] 0x3153,
[0x0ec4] 0x3154,
[0x0ec5] 0x3155,
[0x0ec6] 0x3156,
[0x0ec7] 0x3157,
[0x0ec8] 0x3158,
[0x0ec9] 0x3159,
[0x0eca] 0x315a,
[0x0ecb] 0x315b,
[0x0ecc] 0x315c,
[0x0ecd] 0x315d,
[0x0ece] 0x315e,
[0x0ecf] 0x315f,
[0x0ed0] 0x3160,
[0x0ed1] 0x3161,
[0x0ed2] 0x3162,
[0x0ed3] 0x3163,
[0x0ed4] 0x11a8,
[0x0ed5] 0x11a9,
[0x0ed6] 0x11aa,
[0x0ed7] 0x11ab,
[0x0ed8] 0x11ac,
[0x0ed9] 0x11ad,
[0x0eda] 0x11ae,
[0x0edb] 0x11af,
[0x0edc] 0x11b0,
[0x0edd] 0x11b1,
[0x0ede] 0x11b2,
[0x0edf] 0x11b3,
[0x0ee0] 0x11b4,
[0x0ee1] 0x11b5,
[0x0ee2] 0x11b6,
[0x0ee3] 0x11b7,
[0x0ee4] 0x11b8,
[0x0ee5] 0x11b9,
[0x0ee6] 0x11ba,
[0x0ee7] 0x11bb,
[0x0ee8] 0x11bc,
[0x0ee9] 0x11bd,
[0x0eea] 0x11be,
[0x0eeb] 0x11bf,
[0x0eec] 0x11c0,
[0x0eed] 0x11c1,
[0x0eee] 0x11c2,
[0x0eef] 0x316d,
[0x0ef0] 0x3171,
[0x0ef1] 0x3178,
[0x0ef2] 0x317f,
[0x0ef4] 0x3184,
[0x0ef5] 0x3186,
[0x0ef6] 0x318d,
[0x0ef7] 0x318e,
[0x0ef8] 0x11eb,
[0x0efa] 0x11f9,
[0x0eff] 0x20a9,
[0x13bc] 0x0152,
[0x13bd] 0x0153,
[0x13be] 0x0178,
[0x20a0] 0x20a0,
[0x20a1] 0x20a1,
[0x20a2] 0x20a2,
[0x20a3] 0x20a3,
[0x20a4] 0x20a4,
[0x20a5] 0x20a5,
[0x20a6] 0x20a6,
[0x20a7] 0x20a7,
[0x20a8] 0x20a8,
[0x20a9] 0x20a9,
[0x20aa] 0x20aa,
[0x20ab] 0x20ab,
[0x20ac] 0x20ac,
};

16
gui-x11/load.c Normal file
View File

@ -0,0 +1,16 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include "xmem.h"
int
loadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
{
int n;
n = _loadmemimage(i, r, data, ndata);
if(n > 0 && i->X)
putXdata(i, r);
return n;
}

1094
gui-x11/screen.c Normal file

File diff suppressed because it is too large Load Diff

60
gui-x11/xmem.h Normal file
View File

@ -0,0 +1,60 @@
#define Font XXFont
#define Screen XXScreen
#define Display XXDisplay
#include <X11/Xlib.h>
/* #include <X11/Xlibint.h> */
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#undef Font
#undef Screen
#undef Display
/*
* Structure pointed to by X field of Memimage
*/
typedef struct Xmem Xmem;
enum
{
PMundef = ~0 /* undefined pixmap id */
};
struct Xmem
{
int pmid; /* pixmap id for screen ldepth instance */
XImage *xi; /* local image if we currenty have the data */
int dirty;
Rectangle dirtyr;
Rectangle r;
ulong pc; /* who wrote into xi */
};
extern int xtblbit;
extern int x24bitswap;
extern int plan9tox11[];
extern int x11toplan9[];
extern int xscreendepth;
extern XXDisplay *xdisplay;
extern Drawable xscreenid;
extern Visual *xvis;
extern GC xgcfill, xgcfill0;
extern int xgcfillcolor, xgcfillcolor0;
extern GC xgccopy, xgccopy0;
extern GC xgczero, xgczero0;
extern int xgczeropm, xgczeropm0;
extern GC xgcsimplesrc, xgcsimplesrc0;
extern int xgcsimplecolor, xgcsimplecolor0, xgcsimplepm, xgcsimplepm0;
extern GC xgcreplsrc, xgcreplsrc0;
extern int xgcreplsrcpm, xgcreplsrcpm0, xgcreplsrctile, xgcreplsrctile0;
extern XImage* allocXdata(Memimage*, Rectangle);
extern void putXdata(Memimage*, Rectangle);
extern XImage* getXdata(Memimage*, Rectangle);
extern void freeXdata(Memimage*);
extern void dirtyXdata(Memimage*, Rectangle);
extern ulong xscreenchan;
extern void xfillcolor(Memimage*, Rectangle, ulong);

BIN
include/a.out Normal file

Binary file not shown.

144
include/auth.h Normal file
View File

@ -0,0 +1,144 @@
#pragma src "/sys/src/libauth"
#pragma lib "libauth.a"
/*
* Interface for typical callers.
*/
typedef struct AuthInfo AuthInfo;
typedef struct Chalstate Chalstate;
typedef struct Chapreply Chapreply;
typedef struct MSchapreply MSchapreply;
typedef struct UserPasswd UserPasswd;
typedef struct AuthRpc AuthRpc;
enum
{
MAXCHLEN= 256, /* max challenge length */
MAXNAMELEN= 256, /* maximum name length */
MD5LEN= 16,
ARok = 0, /* rpc return values */
ARdone,
ARerror,
ARneedkey,
ARbadkey,
ARwritenext,
ARtoosmall,
ARtoobig,
ARrpcfailure,
ARphase,
AuthRpcMax = 4096,
};
struct AuthRpc
{
int afd;
char ibuf[AuthRpcMax];
char obuf[AuthRpcMax];
char *arg;
uint narg;
};
struct AuthInfo
{
char *cuid; /* caller id */
char *suid; /* server id */
char *cap; /* capability (only valid on server side) */
int nsecret; /* length of secret */
uchar *secret; /* secret */
};
struct Chalstate
{
char *user;
char chal[MAXCHLEN];
int nchal;
void *resp;
int nresp;
/* for implementation only */
int afd; /* to factotum */
AuthRpc *rpc; /* to factotum */
char userbuf[MAXNAMELEN]; /* temp space if needed */
int userinchal; /* user was sent to obtain challenge */
};
struct Chapreply /* for protocol "chap" */
{
uchar id;
char resp[MD5LEN];
};
struct MSchapreply /* for protocol "mschap" */
{
char LMresp[24]; /* Lan Manager response */
char NTresp[24]; /* NT response */
};
struct UserPasswd
{
char *user;
char *passwd;
};
extern int newns(char*, char*);
extern int addns(char*, char*);
extern int noworld(char*);
extern int amount(int, char*, int, char*);
/* these two may get generalized away -rsc */
extern int login(char*, char*, char*);
extern int httpauth(char*, char*);
typedef struct Attr Attr;
typedef struct String String;
enum {
AttrNameval, /* name=val -- when matching, must have name=val */
AttrQuery, /* name? -- when matching, must be present */
AttrDefault, /* name:=val -- when matching, if present must match INTERNAL */
};
struct Attr
{
int type;
Attr *next;
char *name;
char *val;
};
typedef int AuthGetkey(char*);
int _attrfmt(Fmt*);
Attr *_copyattr(Attr*);
Attr *_delattr(Attr*, char*);
Attr *_findattr(Attr*, char*);
void _freeattr(Attr*);
Attr *_mkattr(int, char*, char*, Attr*);
Attr *_parseattr(char*);
char *_strfindattr(Attr*, char*);
#pragma varargck type "A" Attr*
extern AuthInfo* fauth_proxy(int, AuthRpc *rpc, AuthGetkey *getkey, char *params);
extern AuthInfo* auth_proxy(int fd, AuthGetkey *getkey, char *fmt, ...);
extern int auth_getkey(char*);
extern int (*amount_getkey)(char*);
extern void auth_freeAI(AuthInfo *ai);
extern int auth_chuid(AuthInfo *ai, char *ns);
extern Chalstate *auth_challenge(char*, ...);
extern AuthInfo* auth_response(Chalstate*);
extern int auth_respond(void*, uint, char*, uint, void*, uint, AuthGetkey *getkey, char*, ...);
extern void auth_freechal(Chalstate*);
extern AuthInfo* auth_userpasswd(char *user, char *passwd);
extern UserPasswd* auth_getuserpasswd(AuthGetkey *getkey, char*, ...);
extern AuthInfo* auth_getinfo(AuthRpc *rpc);
extern AuthRpc* auth_allocrpc(int afd);
extern Attr* auth_attr(AuthRpc *rpc);
extern void auth_freerpc(AuthRpc *rpc);
extern uint auth_rpc(AuthRpc *rpc, char *verb, void *a, int n);
extern int auth_wep(char*, char*, ...);
#pragma varargck argpos auth_proxy 3
#pragma varargck argpos auth_challenge 1
#pragma varargck argpos auth_respond 3
#pragma varargck argpos auth_getuserpasswd 2

166
include/authsrv.h Normal file
View File

@ -0,0 +1,166 @@
#pragma src "/sys/src/libauthsrv"
#pragma lib "libauthsrv.a"
/*
* Interface for talking to authentication server.
*/
typedef struct Ticket Ticket;
typedef struct Ticketreq Ticketreq;
typedef struct Authenticator Authenticator;
typedef struct Nvrsafe Nvrsafe;
typedef struct Passwordreq Passwordreq;
typedef struct OChapreply OChapreply;
typedef struct OMSchapreply OMSchapreply;
enum
{
ANAMELEN= 28, /* maximum size of name in previous proto */
AERRLEN= 64, /* maximum size of errstr in previous proto */
DOMLEN= 48, /* length of an authentication domain name */
DESKEYLEN= 7, /* length of a des key for encrypt/decrypt */
CHALLEN= 8, /* length of a plan9 sk1 challenge */
NETCHLEN= 16, /* max network challenge length (used in AS protocol) */
CONFIGLEN= 14,
SECRETLEN= 32, /* max length of a secret */
KEYDBOFF= 8, /* length of random data at the start of key file */
OKEYDBLEN= ANAMELEN+DESKEYLEN+4+2, /* length of an entry in old key file */
KEYDBLEN= OKEYDBLEN+SECRETLEN, /* length of an entry in key file */
OMD5LEN= 16,
};
/* encryption numberings (anti-replay) */
enum
{
AuthTreq=1, /* ticket request */
AuthChal=2, /* challenge box request */
AuthPass=3, /* change password */
AuthOK=4, /* fixed length reply follows */
AuthErr=5, /* error follows */
AuthMod=6, /* modify user */
AuthApop=7, /* apop authentication for pop3 */
AuthOKvar=9, /* variable length reply follows */
AuthChap=10, /* chap authentication for ppp */
AuthMSchap=11, /* MS chap authentication for ppp */
AuthCram=12, /* CRAM verification for IMAP (RFC2195 & rfc2104) */
AuthHttp=13, /* http domain login */
AuthVNC=14, /* VNC server login (deprecated) */
AuthTs=64, /* ticket encrypted with server's key */
AuthTc, /* ticket encrypted with client's key */
AuthAs, /* server generated authenticator */
AuthAc, /* client generated authenticator */
AuthTp, /* ticket encrypted with client's key for password change */
AuthHr, /* http reply */
};
struct Ticketreq
{
char type;
char authid[ANAMELEN]; /* server's encryption id */
char authdom[DOMLEN]; /* server's authentication domain */
char chal[CHALLEN]; /* challenge from server */
char hostid[ANAMELEN]; /* host's encryption id */
char uid[ANAMELEN]; /* uid of requesting user on host */
};
#define TICKREQLEN (3*ANAMELEN+CHALLEN+DOMLEN+1)
struct Ticket
{
char num; /* replay protection */
char chal[CHALLEN]; /* server challenge */
char cuid[ANAMELEN]; /* uid on client */
char suid[ANAMELEN]; /* uid on server */
char key[DESKEYLEN]; /* nonce DES key */
};
#define TICKETLEN (CHALLEN+2*ANAMELEN+DESKEYLEN+1)
struct Authenticator
{
char num; /* replay protection */
char chal[CHALLEN];
ulong id; /* authenticator id, ++'d with each auth */
};
#define AUTHENTLEN (CHALLEN+4+1)
struct Passwordreq
{
char num;
char old[ANAMELEN];
char new[ANAMELEN];
char changesecret;
char secret[SECRETLEN]; /* new secret */
};
#define PASSREQLEN (2*ANAMELEN+1+1+SECRETLEN)
struct OChapreply
{
uchar id;
char uid[ANAMELEN];
char resp[OMD5LEN];
};
struct OMSchapreply
{
char uid[ANAMELEN];
char LMresp[24]; /* Lan Manager response */
char NTresp[24]; /* NT response */
};
/*
* convert to/from wire format
*/
extern int convT2M(Ticket*, char*, char*);
extern void convM2T(char*, Ticket*, char*);
extern void convM2Tnoenc(char*, Ticket*);
extern int convA2M(Authenticator*, char*, char*);
extern void convM2A(char*, Authenticator*, char*);
extern int convTR2M(Ticketreq*, char*);
extern void convM2TR(char*, Ticketreq*);
extern int convPR2M(Passwordreq*, char*, char*);
extern void convM2PR(char*, Passwordreq*, char*);
/*
* convert ascii password to DES key
*/
extern int opasstokey(char*, char*);
extern int passtokey(char*, char*);
/*
* Nvram interface
*/
enum {
NVwrite = 1<<0, /* always prompt and rewrite nvram */
NVwriteonerr = 1<<1, /* prompt and rewrite nvram when corrupt */
};
struct Nvrsafe
{
char machkey[DESKEYLEN];
uchar machsum;
char authkey[DESKEYLEN];
uchar authsum;
char config[CONFIGLEN];
uchar configsum;
char authid[ANAMELEN];
uchar authidsum;
char authdom[DOMLEN];
uchar authdomsum;
};
extern uchar nvcsum(void*, int);
extern int readnvram(Nvrsafe*, int);
/*
* call up auth server
*/
extern int authdial(char *netroot, char *authdom);
/*
* exchange messages with auth server
*/
extern int _asgetticket(int, char*, char*);
extern int _asrdresp(int, char*, int);
extern int sslnegotiate(int, Ticket*, char**, char**);
extern int srvsslnegotiate(int, Ticket*, char**, char**);

6
include/cursor.h Normal file
View File

@ -0,0 +1,6 @@
struct Cursor
{
Point offset;
uchar clr[2*16];
uchar set[2*16];
};

519
include/draw.h Normal file
View File

@ -0,0 +1,519 @@
#pragma src "/sys/src/libdraw"
#pragma lib "libdraw.a"
typedef struct Cachefont Cachefont;
typedef struct Cacheinfo Cacheinfo;
typedef struct Cachesubf Cachesubf;
typedef struct Display Display;
typedef struct Font Font;
typedef struct Fontchar Fontchar;
typedef struct Image Image;
typedef struct Mouse Mouse;
typedef struct Point Point;
typedef struct Rectangle Rectangle;
typedef struct RGB RGB;
typedef struct Screen Screen;
typedef struct Subfont Subfont;
#pragma varargck type "R" Rectangle
#pragma varargck type "P" Point
extern int Rfmt(Fmt*);
extern int Pfmt(Fmt*);
enum
{
DOpaque = 0xFFFFFFFF,
DTransparent = 0x00000000, /* only useful for allocimage, memfillcolor */
DBlack = 0x000000FF,
DWhite = 0xFFFFFFFF,
DRed = 0xFF0000FF,
DGreen = 0x00FF00FF,
DBlue = 0x0000FFFF,
DCyan = 0x00FFFFFF,
DMagenta = 0xFF00FFFF,
DYellow = 0xFFFF00FF,
DPaleyellow = 0xFFFFAAFF,
DDarkyellow = 0xEEEE9EFF,
DDarkgreen = 0x448844FF,
DPalegreen = 0xAAFFAAFF,
DMedgreen = 0x88CC88FF,
DDarkblue = 0x000055FF,
DPalebluegreen= 0xAAFFFFFF,
DPaleblue = 0x0000BBFF,
DBluegreen = 0x008888FF,
DGreygreen = 0x55AAAAFF,
DPalegreygreen = 0x9EEEEEFF,
DYellowgreen = 0x99994CFF,
DMedblue = 0x000099FF,
DGreyblue = 0x005DBBFF,
DPalegreyblue = 0x4993DDFF,
DPurpleblue = 0x8888CCFF,
DNotacolor = 0xFFFFFF00,
DNofill = DNotacolor,
};
enum
{
Displaybufsize = 8000,
ICOSSCALE = 1024,
Borderwidth = 4,
};
enum
{
/* refresh methods */
Refbackup = 0,
Refnone = 1,
Refmesg = 2
};
#define NOREFRESH ((void*)-1)
enum
{
/* line ends */
Endsquare = 0,
Enddisc = 1,
Endarrow = 2,
Endmask = 0x1F
};
#define ARROW(a, b, c) (Endarrow|((a)<<5)|((b)<<14)|((c)<<23))
typedef enum
{
/* Porter-Duff compositing operators */
Clear = 0,
SinD = 8,
DinS = 4,
SoutD = 2,
DoutS = 1,
S = SinD|SoutD,
SoverD = SinD|SoutD|DoutS,
SatopD = SinD|DoutS,
SxorD = SoutD|DoutS,
D = DinS|DoutS,
DoverS = DinS|DoutS|SoutD,
DatopS = DinS|SoutD,
DxorS = DoutS|SoutD, /* == SxorD */
Ncomp = 12,
} Drawop;
/*
* image channel descriptors
*/
enum {
CRed = 0,
CGreen,
CBlue,
CGrey,
CAlpha,
CMap,
CIgnore,
NChan,
};
#define __DC(type, nbits) ((((type)&15)<<4)|((nbits)&15))
#define CHAN1(a,b) __DC(a,b)
#define CHAN2(a,b,c,d) (CHAN1((a),(b))<<8|__DC((c),(d)))
#define CHAN3(a,b,c,d,e,f) (CHAN2((a),(b),(c),(d))<<8|__DC((e),(f)))
#define CHAN4(a,b,c,d,e,f,g,h) (CHAN3((a),(b),(c),(d),(e),(f))<<8|__DC((g),(h)))
#define NBITS(c) ((c)&15)
#define TYPE(c) (((c)>>4)&15)
enum {
GREY1 = CHAN1(CGrey, 1),
GREY2 = CHAN1(CGrey, 2),
GREY4 = CHAN1(CGrey, 4),
GREY8 = CHAN1(CGrey, 8),
CMAP8 = CHAN1(CMap, 8),
RGB15 = CHAN4(CIgnore, 1, CRed, 5, CGreen, 5, CBlue, 5),
RGB16 = CHAN3(CRed, 5, CGreen, 6, CBlue, 5),
RGB24 = CHAN3(CRed, 8, CGreen, 8, CBlue, 8),
BGR24 = CHAN3(CBlue, 8, CGreen, 8, CRed, 8),
RGBA32 = CHAN4(CRed, 8, CGreen, 8, CBlue, 8, CAlpha, 8),
ARGB32 = CHAN4(CAlpha, 8, CRed, 8, CGreen, 8, CBlue, 8), /* stupid VGAs */
XRGB32 = CHAN4(CIgnore, 8, CRed, 8, CGreen, 8, CBlue, 8),
XBGR32 = CHAN4(CIgnore, 8, CBlue, 8, CGreen, 8, CRed, 8),
};
extern char* chantostr(char*, ulong);
extern ulong strtochan(char*);
extern int chantodepth(ulong);
struct Point
{
int x;
int y;
};
struct Rectangle
{
Point min;
Point max;
};
typedef void (*Reffn)(Image*, Rectangle, void*);
struct Screen
{
Display *display; /* display holding data */
int id; /* id of system-held Screen */
Image *image; /* unused; for reference only */
Image *fill; /* color to paint behind windows */
};
struct Display
{
QLock qlock;
int locking; /*program is using lockdisplay */
int dirno;
int fd;
int reffd;
int ctlfd;
int imageid;
int local;
void (*error)(Display*, char*);
char *devdir;
char *windir;
char oldlabel[64];
ulong dataqid;
Image *white;
Image *black;
Image *opaque;
Image *transparent;
Image *image;
uchar *buf;
int bufsize;
uchar *bufp;
Font *defaultfont;
Subfont *defaultsubfont;
Image *windows;
Image *screenimage;
int _isnewdisplay;
};
struct Image
{
Display *display; /* display holding data */
int id; /* id of system-held Image */
Rectangle r; /* rectangle in data area, local coords */
Rectangle clipr; /* clipping region */
int depth; /* number of bits per pixel */
ulong chan;
int repl; /* flag: data replicates to tile clipr */
Screen *screen; /* 0 if not a window */
Image *next; /* next in list of windows */
};
struct RGB
{
ulong red;
ulong green;
ulong blue;
};
/*
* Subfonts
*
* given char c, Subfont *f, Fontchar *i, and Point p, one says
* i = f->info+c;
* draw(b, Rect(p.x+i->left, p.y+i->top,
* p.x+i->left+((i+1)->x-i->x), p.y+i->bottom),
* color, f->bits, Pt(i->x, i->top));
* p.x += i->width;
* to draw characters in the specified color (itself an Image) in Image b.
*/
struct Fontchar
{
int x; /* left edge of bits */
uchar top; /* first non-zero scan-line */
uchar bottom; /* last non-zero scan-line + 1 */
char left; /* offset of baseline */
uchar width; /* width of baseline */
};
struct Subfont
{
char *name;
short n; /* number of chars in font */
uchar height; /* height of image */
char ascent; /* top of image to baseline */
Fontchar *info; /* n+1 character descriptors */
Image *bits; /* of font */
int ref;
};
enum
{
/* starting values */
LOG2NFCACHE = 6,
NFCACHE = (1<<LOG2NFCACHE), /* #chars cached */
NFLOOK = 5, /* #chars to scan in cache */
NFSUBF = 2, /* #subfonts to cache */
/* max value */
MAXFCACHE = 1024+NFLOOK, /* upper limit */
MAXSUBF = 50, /* generous upper limit */
/* deltas */
DSUBF = 4,
/* expiry ages */
SUBFAGE = 10000,
CACHEAGE = 10000
};
struct Cachefont
{
Rune min; /* lowest rune value to be taken from subfont */
Rune max; /* highest rune value+1 to be taken from subfont */
int offset; /* position in subfont of character at min */
char *name; /* stored in font */
char *subfontname; /* to access subfont */
};
struct Cacheinfo
{
ushort x; /* left edge of bits */
uchar width; /* width of baseline */
schar left; /* offset of baseline */
Rune value; /* value of character at this slot in cache */
ushort age;
};
struct Cachesubf
{
ulong age; /* for replacement */
Cachefont *cf; /* font info that owns us */
Subfont *f; /* attached subfont */
};
struct Font
{
char *name;
Display *display;
short height; /* max height of image, interline spacing */
short ascent; /* top of image to baseline */
short width; /* widest so far; used in caching only */
short nsub; /* number of subfonts */
ulong age; /* increasing counter; used for LRU */
int maxdepth; /* maximum depth of all loaded subfonts */
int ncache; /* size of cache */
int nsubf; /* size of subfont list */
Cacheinfo *cache;
Cachesubf *subf;
Cachefont **sub; /* as read from file */
Image *cacheimage;
};
#define Dx(r) ((r).max.x-(r).min.x)
#define Dy(r) ((r).max.y-(r).min.y)
/*
* Image management
*/
extern Image* _allocimage(Image*, Display*, Rectangle, ulong, int, ulong, int, int);
extern Image* allocimage(Display*, Rectangle, ulong, int, ulong);
extern uchar* bufimage(Display*, int);
extern int bytesperline(Rectangle, int);
extern void closedisplay(Display*);
extern void drawerror(Display*, char*);
extern int flushimage(Display*, int);
extern int freeimage(Image*);
extern int _freeimage1(Image*);
extern int geninitdraw(char*, void(*)(Display*, char*), char*, char*, char*, int);
extern int initdraw(void(*)(Display*, char*), char*, char*);
extern int newwindow(char*);
extern Display* initdisplay(char*, char*, void(*)(Display*, char*));
extern int loadimage(Image*, Rectangle, uchar*, int);
extern int cloadimage(Image*, Rectangle, uchar*, int);
extern int getwindow(Display*, int);
extern int gengetwindow(Display*, char*, Image**, Screen**, int);
extern Image* readimage(Display*, int, int);
extern Image* creadimage(Display*, int, int);
extern int unloadimage(Image*, Rectangle, uchar*, int);
extern int wordsperline(Rectangle, int);
extern int writeimage(int, Image*, int);
extern Image* namedimage(Display*, char*);
extern int nameimage(Image*, char*, int);
extern Image* allocimagemix(Display*, ulong, ulong);
/*
* Colors
*/
extern void readcolmap(Display*, RGB*);
extern void writecolmap(Display*, RGB*);
extern ulong setalpha(ulong, uchar);
/*
* Windows
*/
extern Screen* allocscreen(Image*, Image*, int);
extern Image* _allocwindow(Image*, Screen*, Rectangle, int, ulong);
extern Image* allocwindow(Screen*, Rectangle, int, ulong);
extern void bottomnwindows(Image**, int);
extern void bottomwindow(Image*);
extern int freescreen(Screen*);
extern Screen* publicscreen(Display*, int, ulong);
extern void topnwindows(Image**, int);
extern void topwindow(Image*);
extern int originwindow(Image*, Point, Point);
/*
* Geometry
*/
extern Point Pt(int, int);
extern Rectangle Rect(int, int, int, int);
extern Rectangle Rpt(Point, Point);
extern Point addpt(Point, Point);
extern Point subpt(Point, Point);
extern Point divpt(Point, int);
extern Point mulpt(Point, int);
extern int eqpt(Point, Point);
extern int eqrect(Rectangle, Rectangle);
extern Rectangle insetrect(Rectangle, int);
extern Rectangle rectaddpt(Rectangle, Point);
extern Rectangle rectsubpt(Rectangle, Point);
extern Rectangle canonrect(Rectangle);
extern int rectXrect(Rectangle, Rectangle);
extern int rectinrect(Rectangle, Rectangle);
extern void combinerect(Rectangle*, Rectangle);
extern int rectclip(Rectangle*, Rectangle);
extern int ptinrect(Point, Rectangle);
extern void replclipr(Image*, int, Rectangle);
extern int drawreplxy(int, int, int); /* used to be drawsetxy */
extern Point drawrepl(Rectangle, Point);
extern int rgb2cmap(int, int, int);
extern int cmap2rgb(int);
extern int cmap2rgba(int);
extern void icossin(int, int*, int*);
extern void icossin2(int, int, int*, int*);
/*
* Graphics
*/
extern void draw(Image*, Rectangle, Image*, Image*, Point);
extern void drawop(Image*, Rectangle, Image*, Image*, Point, Drawop);
extern void gendraw(Image*, Rectangle, Image*, Point, Image*, Point);
extern void gendrawop(Image*, Rectangle, Image*, Point, Image*, Point, Drawop);
extern void line(Image*, Point, Point, int, int, int, Image*, Point);
extern void lineop(Image*, Point, Point, int, int, int, Image*, Point, Drawop);
extern void poly(Image*, Point*, int, int, int, int, Image*, Point);
extern void polyop(Image*, Point*, int, int, int, int, Image*, Point, Drawop);
extern void fillpoly(Image*, Point*, int, int, Image*, Point);
extern void fillpolyop(Image*, Point*, int, int, Image*, Point, Drawop);
extern Point string(Image*, Point, Image*, Point, Font*, char*);
extern Point stringop(Image*, Point, Image*, Point, Font*, char*, Drawop);
extern Point stringn(Image*, Point, Image*, Point, Font*, char*, int);
extern Point stringnop(Image*, Point, Image*, Point, Font*, char*, int, Drawop);
extern Point runestring(Image*, Point, Image*, Point, Font*, Rune*);
extern Point runestringop(Image*, Point, Image*, Point, Font*, Rune*, Drawop);
extern Point runestringn(Image*, Point, Image*, Point, Font*, Rune*, int);
extern Point runestringnop(Image*, Point, Image*, Point, Font*, Rune*, int, Drawop);
extern Point stringbg(Image*, Point, Image*, Point, Font*, char*, Image*, Point);
extern Point stringbgop(Image*, Point, Image*, Point, Font*, char*, Image*, Point, Drawop);
extern Point stringnbg(Image*, Point, Image*, Point, Font*, char*, int, Image*, Point);
extern Point stringnbgop(Image*, Point, Image*, Point, Font*, char*, int, Image*, Point, Drawop);
extern Point runestringbg(Image*, Point, Image*, Point, Font*, Rune*, Image*, Point);
extern Point runestringbgop(Image*, Point, Image*, Point, Font*, Rune*, Image*, Point, Drawop);
extern Point runestringnbg(Image*, Point, Image*, Point, Font*, Rune*, int, Image*, Point);
extern Point runestringnbgop(Image*, Point, Image*, Point, Font*, Rune*, int, Image*, Point, Drawop);
extern Point _string(Image*, Point, Image*, Point, Font*, char*, Rune*, int, Rectangle, Image*, Point, Drawop);
extern Point stringsubfont(Image*, Point, Image*, Subfont*, char*);
extern int bezier(Image*, Point, Point, Point, Point, int, int, int, Image*, Point);
extern int bezierop(Image*, Point, Point, Point, Point, int, int, int, Image*, Point, Drawop);
extern int bezspline(Image*, Point*, int, int, int, int, Image*, Point);
extern int bezsplineop(Image*, Point*, int, int, int, int, Image*, Point, Drawop);
extern int bezsplinepts(Point*, int, Point**);
extern int fillbezier(Image*, Point, Point, Point, Point, int, Image*, Point);
extern int fillbezierop(Image*, Point, Point, Point, Point, int, Image*, Point, Drawop);
extern int fillbezspline(Image*, Point*, int, int, Image*, Point);
extern int fillbezsplineop(Image*, Point*, int, int, Image*, Point, Drawop);
extern void ellipse(Image*, Point, int, int, int, Image*, Point);
extern void ellipseop(Image*, Point, int, int, int, Image*, Point, Drawop);
extern void fillellipse(Image*, Point, int, int, Image*, Point);
extern void fillellipseop(Image*, Point, int, int, Image*, Point, Drawop);
extern void arc(Image*, Point, int, int, int, Image*, Point, int, int);
extern void arcop(Image*, Point, int, int, int, Image*, Point, int, int, Drawop);
extern void fillarc(Image*, Point, int, int, Image*, Point, int, int);
extern void fillarcop(Image*, Point, int, int, Image*, Point, int, int, Drawop);
extern void border(Image*, Rectangle, int, Image*, Point);
extern void borderop(Image*, Rectangle, int, Image*, Point, Drawop);
/*
* Font management
*/
extern Font* openfont(Display*, char*);
extern Font* buildfont(Display*, char*, char*);
extern void freefont(Font*);
extern Font* mkfont(Subfont*, Rune);
extern int cachechars(Font*, char**, Rune**, ushort*, int, int*, char**);
extern void agefont(Font*);
extern Subfont* allocsubfont(char*, int, int, int, Fontchar*, Image*);
extern Subfont* lookupsubfont(Display*, char*);
extern void installsubfont(char*, Subfont*);
extern void uninstallsubfont(Subfont*);
extern void freesubfont(Subfont*);
extern Subfont* readsubfont(Display*, char*, int, int);
extern Subfont* readsubfonti(Display*, char*, int, Image*, int);
extern int writesubfont(int, Subfont*);
extern void _unpackinfo(Fontchar*, uchar*, int);
extern Point stringsize(Font*, char*);
extern int stringwidth(Font*, char*);
extern int stringnwidth(Font*, char*, int);
extern Point runestringsize(Font*, Rune*);
extern int runestringwidth(Font*, Rune*);
extern int runestringnwidth(Font*, Rune*, int);
extern Point strsubfontwidth(Subfont*, char*);
extern int loadchar(Font*, Rune, Cacheinfo*, int, int, char**);
extern char* subfontname(char*, char*, int);
extern Subfont* _getsubfont(Display*, char*);
extern Subfont* getdefont(Display*);
extern void lockdisplay(Display*);
extern void unlockdisplay(Display*);
extern int drawlsetrefresh(ulong, int, void*, void*);
/*
* Predefined
*/
extern uchar defontdata[];
extern int sizeofdefont;
extern Point ZP;
extern Rectangle ZR;
/*
* Set up by initdraw()
*/
extern Display *display;
extern Font *font;
/* extern Image *screen; */
extern Screen *_screen;
extern int _cursorfd;
extern int _drawdebug; /* set to 1 to see errors from flushimage */
extern void _setdrawop(Display*, Drawop);
#define BGSHORT(p) (((p)[0]<<0) | ((p)[1]<<8))
#define BGLONG(p) ((BGSHORT(p)<<0) | (BGSHORT(p+2)<<16))
#define BPSHORT(p, v) ((p)[0]=(v), (p)[1]=((v)>>8))
#define BPLONG(p, v) (BPSHORT(p, (v)), BPSHORT(p+2, (v)>>16))
/*
* Compressed image file parameters and helper routines
*/
#define NMATCH 3 /* shortest match possible */
#define NRUN (NMATCH+31) /* longest match possible */
#define NMEM 1024 /* window size */
#define NDUMP 128 /* maximum length of dump */
#define NCBLOCK 6000 /* size of compressed blocks */
extern void _twiddlecompressed(uchar*, int);
extern int _compblocksize(Rectangle, int);
/* XXX backwards helps; should go */
extern int log2[];
extern ulong drawld2chan[];
extern void drawsetdebug(int);

10
include/dtos.h Normal file
View File

@ -0,0 +1,10 @@
#if defined(linux) || defined(IRIX) || defined(SOLARIS) || defined(OSF1) || defined(__FreeBSD__) || defined(__APPLE__)
# include "unix.h"
# ifdef __APPLE__
# define panic dt_panic
# endif
#elif defined(WINDOWS)
# include "winduhz.h"
#else
# error "Define an OS"
#endif

110
include/fcall.h Normal file
View File

@ -0,0 +1,110 @@
#define VERSION9P "9P2000"
#define MAXWELEM 16
typedef
struct Fcall
{
uchar type;
u32int fid;
ushort tag;
u32int msize; /* Tversion, Rversion */
char *version; /* Tversion, Rversion */
ushort oldtag; /* Tflush */
char *ename; /* Rerror */
Qid qid; /* Rattach, Ropen, Rcreate */
u32int iounit; /* Ropen, Rcreate */
Qid aqid; /* Rauth */
u32int afid; /* Tauth, Tattach */
char *uname; /* Tauth, Tattach */
char *aname; /* Tauth, Tattach */
u32int perm; /* Tcreate */
char *name; /* Tcreate */
uchar mode; /* Tcreate, Topen */
u32int newfid; /* Twalk */
ushort nwname; /* Twalk */
char *wname[MAXWELEM]; /* Twalk */
ushort nwqid; /* Rwalk */
Qid wqid[MAXWELEM]; /* Rwalk */
vlong offset; /* Tread, Twrite */
u32int count; /* Tread, Twrite, Rread */
char *data; /* Twrite, Rread */
ushort nstat; /* Twstat, Rstat */
uchar *stat; /* Twstat, Rstat */
} Fcall;
#define GBIT8(p) ((p)[0])
#define GBIT16(p) ((p)[0]|((p)[1]<<8))
#define GBIT32(p) ((p)[0]|((p)[1]<<8)|((p)[2]<<16)|((p)[3]<<24))
#define GBIT64(p) ((vlong)((p)[0]|((p)[1]<<8)|((p)[2]<<16)|((p)[3]<<24)) |\
((vlong)((p)[4]|((p)[5]<<8)|((p)[6]<<16)|((p)[7]<<24)) << 32))
#define PBIT8(p,v) (p)[0]=(v)
#define PBIT16(p,v) (p)[0]=(v);(p)[1]=(v)>>8
#define PBIT32(p,v) (p)[0]=(v);(p)[1]=(v)>>8;(p)[2]=(v)>>16;(p)[3]=(v)>>24
#define PBIT64(p,v) (p)[0]=(v);(p)[1]=(v)>>8;(p)[2]=(v)>>16;(p)[3]=(v)>>24;\
(p)[4]=(v)>>32;(p)[5]=(v)>>40;(p)[6]=(v)>>48;(p)[7]=(v)>>56
#define BIT8SZ 1
#define BIT16SZ 2
#define BIT32SZ 4
#define BIT64SZ 8
#define QIDSZ (BIT8SZ+BIT32SZ+BIT64SZ)
/* STATFIXLEN includes leading 16-bit count */
/* The count, however, excludes itself; total size is BIT16SZ+count */
#define STATFIXLEN (BIT16SZ+QIDSZ+5*BIT16SZ+4*BIT32SZ+1*BIT64SZ) /* amount of fixed length data in a stat buffer */
#define NOTAG (ushort)~0U /* Dummy tag */
#define NOFID (u32int)~0U /* Dummy fid */
#define IOHDRSZ 24 /* ample room for Twrite/Rread header (iounit) */
enum
{
Tversion = 100,
Rversion,
Tauth = 102,
Rauth,
Tattach = 104,
Rattach,
Terror = 106, /* illegal */
Rerror,
Tflush = 108,
Rflush,
Twalk = 110,
Rwalk,
Topen = 112,
Ropen,
Tcreate = 114,
Rcreate,
Tread = 116,
Rread,
Twrite = 118,
Rwrite,
Tclunk = 120,
Rclunk,
Tremove = 122,
Rremove,
Tstat = 124,
Rstat,
Twstat = 126,
Rwstat,
Tmax,
};
uint convM2S(uchar*, uint, Fcall*);
uint convS2M(Fcall*, uchar*, uint);
uint sizeS2M(Fcall*);
int statcheck(uchar *abuf, uint nbuf);
uint convM2D(uchar*, uint, Dir*, char*);
uint convD2M(Dir*, uchar*, uint);
uint sizeD2M(Dir*);
int fcallfmt(Fmt*);
int dirfmt(Fmt*);
int dirmodefmt(Fmt*);
int read9pmsg(int, void*, uint);

42
include/keyboard.h Normal file
View File

@ -0,0 +1,42 @@
#pragma src "/sys/src/libdraw"
#pragma lib "libdraw.a"
typedef struct Keyboardctl Keyboardctl;
typedef struct Channel Channel;
struct Keyboardctl
{
Channel *c; /* chan(Rune)[20] */
char *file;
int consfd; /* to cons file */
int ctlfd; /* to ctl file */
int pid; /* of slave proc */
};
extern Keyboardctl* initkeyboard(char*);
extern int ctlkeyboard(Keyboardctl*, char*);
extern void closekeyboard(Keyboardctl*);
enum {
KF= 0xF000, /* Rune: beginning of private Unicode space */
Spec= 0xF800,
/* KF|1, KF|2, ..., KF|0xC is F1, F2, ..., F12 */
Khome= KF|0x0D,
Kup= KF|0x0E,
Kpgup= KF|0x0F,
Kprint= KF|0x10,
Kleft= KF|0x11,
Kright= KF|0x12,
Kdown= Spec|0x00,
Kview= Spec|0x00,
Kpgdown= KF|0x13,
Kins= KF|0x14,
Kend= KF|0x18,
Kalt= KF|0x15,
Kshift= KF|0x16,
Kctl= KF|0x17,
};

246
include/lib.h Normal file
View File

@ -0,0 +1,246 @@
/* avoid name conflicts */
#define accept pm_accept
#define listen pm_listen
#define sleep ksleep
#define wakeup kwakeup
#define strtod libstrtod
#define pow10 libpow10
/* conflicts on some os's */
#define encrypt libencrypt
#define decrypt libdecrypt
#define oserror liboserror
#define clone libclone
#define atexit libatexit
#define log2 liblog2
#define log liblog
#define reboot libreboot
#define srand dtsrand
#define rand dtrand
#define nrand dtnrand
#define lrand dtlrand
#define lnrand dtlnrand
#undef timeradd
#define timeradd xtimeradd
#define nil ((void*)0)
typedef unsigned char p9_uchar;
typedef unsigned int p9_uint;
typedef unsigned int p9_ulong;
typedef int p9_long;
typedef signed char p9_schar;
typedef unsigned short p9_ushort;
typedef unsigned short Rune;
typedef unsigned int p9_u32int;
typedef p9_u32int mpdigit;
/* make sure we don't conflict with predefined types */
#define schar p9_schar
#define uchar p9_uchar
#define ushort p9_ushort
#define uint p9_uint
#define u32int p9_u32int
/* #define long int rather than p9_long so that "unsigned long" is valid */
#define long int
#define ulong p9_ulong
#define vlong p9_vlong
#define uvlong p9_uvlong
#define nelem(x) (sizeof(x)/sizeof((x)[0]))
#define USED(x) if(x);else
#define SET(x)
enum
{
UTFmax = 3, /* maximum bytes per rune */
Runesync = 0x80, /* cannot represent part of a UTF sequence (<) */
Runeself = 0x80, /* rune and UTF sequences are the same (<) */
Runeerror = 0x80 /* decoding error in UTF */
};
/*
* new rune routines
*/
extern int runetochar(char*, Rune*);
extern int chartorune(Rune*, char*);
extern int runelen(long);
extern int fullrune(char*, int);
extern int wstrtoutf(char*, Rune*, int);
extern int wstrutflen(Rune*);
/*
* rune routines from converted str routines
*/
extern long utflen(char*);
extern char* utfrune(char*, long);
extern char* utfrrune(char*, long);
/*
* Syscall data structures
*/
#define MORDER 0x0003 /* mask for bits defining order of mounting */
#define MREPL 0x0000 /* mount replaces object */
#define MBEFORE 0x0001 /* mount goes before others in union directory */
#define MAFTER 0x0002 /* mount goes after others in union directory */
#define MCREATE 0x0004 /* permit creation in mounted directory */
#define MCACHE 0x0010 /* cache some data */
#define MMASK 0x0017 /* all bits on */
#define OREAD 0 /* open for read */
#define OWRITE 1 /* write */
#define ORDWR 2 /* read and write */
#define OEXEC 3 /* execute, == read but check execute permission */
#define OTRUNC 16 /* or'ed in (except for exec), truncate file first */
#define OCEXEC 32 /* or'ed in, close on exec */
#define ORCLOSE 64 /* or'ed in, remove on close */
#define OEXCL 0x1000 /* or'ed in, exclusive create */
#define NCONT 0 /* continue after note */
#define NDFLT 1 /* terminate after note */
#define NSAVE 2 /* clear note but hold state */
#define NRSTR 3 /* restore saved state */
#define ERRMAX 128 /* max length of error string */
#define KNAMELEN 28 /* max length of name held in kernel */
/* bits in Qid.type */
#define QTDIR 0x80 /* type bit for directories */
#define QTAPPEND 0x40 /* type bit for append only files */
#define QTEXCL 0x20 /* type bit for exclusive use files */
#define QTMOUNT 0x10 /* type bit for mounted channel */
#define QTAUTH 0x08 /* type bit for authentication file */
#define QTFILE 0x00 /* plain file */
/* bits in Dir.mode */
#define DMDIR 0x80000000 /* mode bit for directories */
#define DMAPPEND 0x40000000 /* mode bit for append only files */
#define DMEXCL 0x20000000 /* mode bit for exclusive use files */
#define DMMOUNT 0x10000000 /* mode bit for mounted channel */
#define DMAUTH 0x08000000 /* mode bit for authentication files */
#define DMREAD 0x4 /* mode bit for read permission */
#define DMWRITE 0x2 /* mode bit for write permission */
#define DMEXEC 0x1 /* mode bit for execute permission */
typedef struct Lock
{
long key;
} Lock;
typedef struct QLock
{
Lock lk;
struct Proc *hold;
struct Proc *first;
struct Proc *last;
} QLock;
typedef
struct Qid
{
uvlong path;
ulong vers;
uchar type;
} Qid;
typedef
struct Dir {
/* system-modified data */
ushort type; /* server type */
uint dev; /* server subtype */
/* file data */
Qid qid; /* unique id from server */
ulong mode; /* permissions */
ulong atime; /* last read time */
ulong mtime; /* last write time */
vlong length; /* file length */
char *name; /* last element of path */
char *uid; /* owner name */
char *gid; /* group name */
char *muid; /* last modifier name */
} Dir;
typedef
struct Waitmsg
{
int pid; /* of loved one */
ulong time[3]; /* of loved one & descendants */
char *msg;
} Waitmsg;
/*
* print routines
*/
typedef struct Fmt Fmt;
struct Fmt{
uchar runes; /* output buffer is runes or chars? */
void *start; /* of buffer */
void *to; /* current place in the buffer */
void *stop; /* end of the buffer; overwritten if flush fails */
int (*flush)(Fmt *); /* called when to == stop */
void *farg; /* to make flush a closure */
int nfmt; /* num chars formatted so far */
va_list args; /* args passed to dofmt */
int r; /* % format Rune */
int width;
int prec;
ulong flags;
};
enum{
FmtWidth = 1,
FmtLeft = FmtWidth << 1,
FmtPrec = FmtLeft << 1,
FmtSharp = FmtPrec << 1,
FmtSpace = FmtSharp << 1,
FmtSign = FmtSpace << 1,
FmtZero = FmtSign << 1,
FmtUnsigned = FmtZero << 1,
FmtShort = FmtUnsigned << 1,
FmtLong = FmtShort << 1,
FmtVLong = FmtLong << 1,
FmtComma = FmtVLong << 1,
FmtByte = FmtComma << 1,
FmtFlag = FmtByte << 1
};
extern int print(char*, ...);
extern char* seprint(char*, char*, char*, ...);
extern char* vseprint(char*, char*, char*, va_list);
extern int snprint(char*, int, char*, ...);
extern int vsnprint(char*, int, char*, va_list);
extern char* smprint(char*, ...);
extern char* vsmprint(char*, va_list);
extern int sprint(char*, char*, ...);
extern int fprint(int, char*, ...);
extern int vfprint(int, char*, va_list);
extern int (*doquote)(int);
extern int runesprint(Rune*, char*, ...);
extern int runesnprint(Rune*, int, char*, ...);
extern int runevsnprint(Rune*, int, char*, va_list);
extern Rune* runeseprint(Rune*, Rune*, char*, ...);
extern Rune* runevseprint(Rune*, Rune*, char*, va_list);
extern Rune* runesmprint(char*, ...);
extern Rune* runevsmprint(char*, va_list);
extern int fmtfdinit(Fmt*, int, char*, int);
extern int fmtfdflush(Fmt*);
extern int fmtstrinit(Fmt*);
extern int fmtinstall(int, int (*)(Fmt*));
extern char* fmtstrflush(Fmt*);
extern int runefmtstrinit(Fmt*);
extern Rune* runefmtstrflush(Fmt*);
extern void* mallocz(ulong, int);
extern void srand(long);
extern int rand(void);
extern int nrand(int);
extern long lrand(void);
extern long lnrand(long);
extern double frand(void);

3
include/libc.h Normal file
View File

@ -0,0 +1,3 @@
#include "lib.h"
#include "user.h"

340
include/libsec.h Normal file
View File

@ -0,0 +1,340 @@
#ifndef _MPINT
typedef struct mpint mpint;
#endif
/////////////////////////////////////////////////////////
// AES definitions
/////////////////////////////////////////////////////////
enum
{
AESbsize= 16,
AESmaxkey= 32,
AESmaxrounds= 14
};
typedef struct AESstate AESstate;
struct AESstate
{
ulong setup;
int rounds;
int keybytes;
uchar key[AESmaxkey]; /* unexpanded key */
u32int ekey[4*(AESmaxrounds + 1)]; /* encryption key */
u32int dkey[4*(AESmaxrounds + 1)]; /* decryption key */
uchar ivec[AESbsize]; /* initialization vector */
};
void setupAESstate(AESstate *s, uchar key[], int keybytes, uchar *ivec);
void aesCBCencrypt(uchar *p, int len, AESstate *s);
void aesCBCdecrypt(uchar *p, int len, AESstate *s);
/////////////////////////////////////////////////////////
// Blowfish Definitions
/////////////////////////////////////////////////////////
enum
{
BFbsize = 8,
BFrounds = 16
};
// 16-round Blowfish
typedef struct BFstate BFstate;
struct BFstate
{
ulong setup;
uchar key[56];
uchar ivec[8];
u32int pbox[BFrounds+2];
u32int sbox[1024];
};
void setupBFstate(BFstate *s, uchar key[], int keybytes, uchar *ivec);
void bfCBCencrypt(uchar*, int, BFstate*);
void bfCBCdecrypt(uchar*, int, BFstate*);
void bfECBencrypt(uchar*, int, BFstate*);
void bfECBdecrypt(uchar*, int, BFstate*);
/////////////////////////////////////////////////////////
// DES definitions
/////////////////////////////////////////////////////////
enum
{
DESbsize= 8
};
// single des
typedef struct DESstate DESstate;
struct DESstate
{
ulong setup;
uchar key[8]; /* unexpanded key */
ulong expanded[32]; /* expanded key */
uchar ivec[8]; /* initialization vector */
};
void setupDESstate(DESstate *s, uchar key[8], uchar *ivec);
void des_key_setup(uchar[8], ulong[32]);
void block_cipher(ulong*, uchar*, int);
void desCBCencrypt(uchar*, int, DESstate*);
void desCBCdecrypt(uchar*, int, DESstate*);
void desECBencrypt(uchar*, int, DESstate*);
void desECBdecrypt(uchar*, int, DESstate*);
// for backward compatibility with 7 byte DES key format
void des56to64(uchar *k56, uchar *k64);
void des64to56(uchar *k64, uchar *k56);
void key_setup(uchar[7], ulong[32]);
// triple des encrypt/decrypt orderings
enum {
DES3E= 0,
DES3D= 1,
DES3EEE= 0,
DES3EDE= 2,
DES3DED= 5,
DES3DDD= 7
};
typedef struct DES3state DES3state;
struct DES3state
{
ulong setup;
uchar key[3][8]; /* unexpanded key */
ulong expanded[3][32]; /* expanded key */
uchar ivec[8]; /* initialization vector */
};
void setupDES3state(DES3state *s, uchar key[3][8], uchar *ivec);
void triple_block_cipher(ulong keys[3][32], uchar*, int);
void des3CBCencrypt(uchar*, int, DES3state*);
void des3CBCdecrypt(uchar*, int, DES3state*);
void des3ECBencrypt(uchar*, int, DES3state*);
void des3ECBdecrypt(uchar*, int, DES3state*);
/////////////////////////////////////////////////////////
// digests
/////////////////////////////////////////////////////////
enum
{
SHA1dlen= 20, /* SHA digest length */
MD4dlen= 16, /* MD4 digest length */
MD5dlen= 16 /* MD5 digest length */
};
typedef struct DigestState DigestState;
struct DigestState
{
ulong len;
u32int state[5];
uchar buf[128];
int blen;
char malloced;
char seeded;
};
typedef struct DigestState SHAstate; /* obsolete name */
typedef struct DigestState SHA1state;
typedef struct DigestState MD5state;
typedef struct DigestState MD4state;
DigestState* md4(uchar*, ulong, uchar*, DigestState*);
DigestState* md5(uchar*, ulong, uchar*, DigestState*);
DigestState* sha1(uchar*, ulong, uchar*, DigestState*);
DigestState* hmac_md5(uchar*, ulong, uchar*, ulong, uchar*, DigestState*);
DigestState* hmac_sha1(uchar*, ulong, uchar*, ulong, uchar*, DigestState*);
char* sha1pickle(SHA1state*);
SHA1state* sha1unpickle(char*);
/////////////////////////////////////////////////////////
// random number generation
/////////////////////////////////////////////////////////
void genrandom(uchar *buf, int nbytes);
void prng(uchar *buf, int nbytes);
ulong fastrand(void);
ulong nfastrand(ulong);
/////////////////////////////////////////////////////////
// primes
/////////////////////////////////////////////////////////
void genprime(mpint *p, int n, int accuracy); // generate an n bit probable prime
void gensafeprime(mpint *p, mpint *alpha, int n, int accuracy); // prime and generator
void genstrongprime(mpint *p, int n, int accuracy); // generate an n bit strong prime
void DSAprimes(mpint *q, mpint *p, uchar seed[SHA1dlen]);
int probably_prime(mpint *n, int nrep); // miller-rabin test
int smallprimetest(mpint *p); // returns -1 if not prime, 0 otherwise
/////////////////////////////////////////////////////////
// rc4
/////////////////////////////////////////////////////////
typedef struct RC4state RC4state;
struct RC4state
{
uchar state[256];
uchar x;
uchar y;
};
void setupRC4state(RC4state*, uchar*, int);
void rc4(RC4state*, uchar*, int);
void rc4skip(RC4state*, int);
void rc4back(RC4state*, int);
/////////////////////////////////////////////////////////
// rsa
/////////////////////////////////////////////////////////
typedef struct RSApub RSApub;
typedef struct RSApriv RSApriv;
// public/encryption key
struct RSApub
{
mpint *n; // modulus
mpint *ek; // exp (encryption key)
};
// private/decryption key
struct RSApriv
{
RSApub pub;
mpint *dk; // exp (decryption key)
// precomputed values to help with chinese remainder theorem calc
mpint *p;
mpint *q;
mpint *kp; // dk mod p-1
mpint *kq; // dk mod q-1
mpint *c2; // (inv p) mod q
};
RSApriv* rsagen(int nlen, int elen, int rounds);
RSApriv* rsafill(mpint *n, mpint *e, mpint *d, mpint *p, mpint *q);
mpint* rsaencrypt(RSApub *k, mpint *in, mpint *out);
mpint* rsadecrypt(RSApriv *k, mpint *in, mpint *out);
RSApub* rsapuballoc(void);
void rsapubfree(RSApub*);
RSApriv* rsaprivalloc(void);
void rsaprivfree(RSApriv*);
RSApub* rsaprivtopub(RSApriv*);
RSApub* X509toRSApub(uchar*, int, char*, int);
RSApriv* asn1toRSApriv(uchar*, int);
void asn1dump(uchar *der, int len);
uchar* decodepem(char *s, char *type, int *len);
uchar* X509gen(RSApriv *priv, char *subj, ulong valid[2], int *certlen);
uchar* X509req(RSApriv *priv, char *subj, int *certlen);
char* X509verify(uchar *cert, int ncert, RSApub *pk);
void X509dump(uchar *cert, int ncert);
/////////////////////////////////////////////////////////
// elgamal
/////////////////////////////////////////////////////////
typedef struct EGpub EGpub;
typedef struct EGpriv EGpriv;
typedef struct EGsig EGsig;
// public/encryption key
struct EGpub
{
mpint *p; // modulus
mpint *alpha; // generator
mpint *key; // (encryption key) alpha**secret mod p
};
// private/decryption key
struct EGpriv
{
EGpub pub;
mpint *secret; // (decryption key)
};
// signature
struct EGsig
{
mpint *r, *s;
};
EGpriv* eggen(int nlen, int rounds);
mpint* egencrypt(EGpub *k, mpint *in, mpint *out);
mpint* egdecrypt(EGpriv *k, mpint *in, mpint *out);
EGsig* egsign(EGpriv *k, mpint *m);
int egverify(EGpub *k, EGsig *sig, mpint *m);
EGpub* egpuballoc(void);
void egpubfree(EGpub*);
EGpriv* egprivalloc(void);
void egprivfree(EGpriv*);
EGsig* egsigalloc(void);
void egsigfree(EGsig*);
EGpub* egprivtopub(EGpriv*);
/////////////////////////////////////////////////////////
// dsa
/////////////////////////////////////////////////////////
typedef struct DSApub DSApub;
typedef struct DSApriv DSApriv;
typedef struct DSAsig DSAsig;
// public/encryption key
struct DSApub
{
mpint *p; // modulus
mpint *q; // group order, q divides p-1
mpint *alpha; // group generator
mpint *key; // (encryption key) alpha**secret mod p
};
// private/decryption key
struct DSApriv
{
DSApub pub;
mpint *secret; // (decryption key)
};
// signature
struct DSAsig
{
mpint *r, *s;
};
DSApriv* dsagen(DSApub *opub);
DSAsig* dsasign(DSApriv *k, mpint *m);
int dsaverify(DSApub *k, DSAsig *sig, mpint *m);
DSApub* dsapuballoc(void);
void dsapubfree(DSApub*);
DSApriv* dsaprivalloc(void);
void dsaprivfree(DSApriv*);
DSAsig* dsasigalloc(void);
void dsasigfree(DSAsig*);
DSApub* dsaprivtopub(DSApriv*);
/////////////////////////////////////////////////////////
// TLS
/////////////////////////////////////////////////////////
typedef struct Thumbprint{
struct Thumbprint *next;
uchar sha1[SHA1dlen];
} Thumbprint;
typedef struct TLSconn{
char dir[40]; // connection directory
uchar *cert; // certificate (local on input, remote on output)
uchar *sessionID;
int certlen, sessionIDlen;
int (*trace)(char*fmt, ...);
} TLSconn;
// tlshand.c
extern int tlsClient(int fd, TLSconn *c);
extern int tlsServer(int fd, TLSconn *c);
// thumb.c
extern Thumbprint* initThumbprints(char *ok, char *crl);
extern void freeThumbprints(Thumbprint *ok);
extern int okThumbprint(uchar *sha1, Thumbprint *ok);
// readcert.c
extern uchar *readcert(char *filename, int *pcertlen);

200
include/memdraw.h Normal file
View File

@ -0,0 +1,200 @@
#pragma src "/sys/src/libmemdraw"
#pragma lib "libmemdraw.a"
typedef struct Memimage Memimage;
typedef struct Memdata Memdata;
typedef struct Memsubfont Memsubfont;
typedef struct Memlayer Memlayer;
typedef struct Memcmap Memcmap;
typedef struct Memdrawparam Memdrawparam;
/*
* Memdata is allocated from main pool, but .data from the image pool.
* Memdata is allocated separately to permit patching its pointer after
* compaction when windows share the image data.
* The first word of data is a back pointer to the Memdata, to find
* The word to patch.
*/
struct Memdata
{
ulong *base; /* allocated data pointer */
uchar *bdata; /* pointer to first byte of actual data; word-aligned */
int ref; /* number of Memimages using this data */
void* imref;
int allocd; /* is this malloc'd? */
};
enum {
Frepl = 1<<0, /* is replicated */
Fsimple = 1<<1, /* is 1x1 */
Fgrey = 1<<2, /* is grey */
Falpha = 1<<3, /* has explicit alpha */
Fcmap = 1<<4, /* has cmap channel */
Fbytes = 1<<5, /* has only 8-bit channels */
};
struct Memimage
{
Rectangle r; /* rectangle in data area, local coords */
Rectangle clipr; /* clipping region */
int depth; /* number of bits of storage per pixel */
int nchan; /* number of channels */
ulong chan; /* channel descriptions */
Memcmap *cmap;
Memdata *data; /* pointer to data; shared by windows in this image */
int zero; /* data->bdata+zero==&byte containing (0,0) */
ulong width; /* width in words of a single scan line */
Memlayer *layer; /* nil if not a layer*/
ulong flags;
int shift[NChan];
int mask[NChan];
int nbits[NChan];
void *X;
};
struct Memcmap
{
uchar cmap2rgb[3*256];
uchar rgb2cmap[16*16*16];
};
/*
* Subfonts
*
* given char c, Subfont *f, Fontchar *i, and Point p, one says
* i = f->info+c;
* draw(b, Rect(p.x+i->left, p.y+i->top,
* p.x+i->left+((i+1)->x-i->x), p.y+i->bottom),
* color, f->bits, Pt(i->x, i->top));
* p.x += i->width;
* to draw characters in the specified color (itself a Memimage) in Memimage b.
*/
struct Memsubfont
{
char *name;
short n; /* number of chars in font */
uchar height; /* height of bitmap */
char ascent; /* top of bitmap to baseline */
Fontchar *info; /* n+1 character descriptors */
Memimage *bits; /* of font */
};
/*
* Encapsulated parameters and information for sub-draw routines.
*/
enum {
Simplesrc=1<<0,
Simplemask=1<<1,
Replsrc=1<<2,
Replmask=1<<3,
Fullmask=1<<4,
};
struct Memdrawparam
{
Memimage *dst;
Rectangle r;
Memimage *src;
Rectangle sr;
Memimage *mask;
Rectangle mr;
int op;
ulong state;
ulong mval; /* if Simplemask, the mask pixel in mask format */
ulong mrgba; /* mval in rgba */
ulong sval; /* if Simplesrc, the source pixel in src format */
ulong srgba; /* sval in rgba */
ulong sdval; /* sval in dst format */
};
/*
* Memimage management
*/
extern Memimage* allocmemimage(Rectangle, ulong);
extern Memimage* _allocmemimage(Rectangle, ulong);
extern Memimage* allocmemimaged(Rectangle, ulong, Memdata*, void*);
extern Memimage* readmemimage(int);
extern Memimage* creadmemimage(int);
extern int writememimage(int, Memimage*);
extern void freememimage(Memimage*);
extern int _loadmemimage(Memimage*, Rectangle, uchar*, int);
extern int _cloadmemimage(Memimage*, Rectangle, uchar*, int);
extern int _unloadmemimage(Memimage*, Rectangle, uchar*, int);
extern int loadmemimage(Memimage*, Rectangle, uchar*, int);
extern int cloadmemimage(Memimage*, Rectangle, uchar*, int);
extern int unloadmemimage(Memimage*, Rectangle, uchar*, int);
extern ulong* wordaddr(Memimage*, Point);
extern uchar* byteaddr(Memimage*, Point);
extern int drawclip(Memimage*, Rectangle*, Memimage*, Point*, Memimage*, Point*, Rectangle*, Rectangle*);
extern void memfillcolor(Memimage*, ulong);
extern int memsetchan(Memimage*, ulong);
/*
* Graphics
*/
extern void memdraw(Memimage*, Rectangle, Memimage*, Point, Memimage*, Point, int);
extern void memline(Memimage*, Point, Point, int, int, int, Memimage*, Point, int);
extern void mempoly(Memimage*, Point*, int, int, int, int, Memimage*, Point, int);
extern void memfillpoly(Memimage*, Point*, int, int, Memimage*, Point, int);
extern void _memfillpolysc(Memimage*, Point*, int, int, Memimage*, Point, int, int, int, int);
extern Memdrawparam* _memimagedrawsetup(Memimage*, Rectangle, Memimage*, Point, Memimage*, Point, int);
extern void _memimagedraw(Memdrawparam*);
extern void memimagedraw(Memimage*, Rectangle, Memimage*, Point, Memimage*, Point, int);
extern int hwdraw(Memdrawparam*);
extern void memimageline(Memimage*, Point, Point, int, int, int, Memimage*, Point, int);
extern void _memimageline(Memimage*, Point, Point, int, int, int, Memimage*, Point, Rectangle, int);
extern Point memimagestring(Memimage*, Point, Memimage*, Point, Memsubfont*, char*);
extern void memellipse(Memimage*, Point, int, int, int, Memimage*, Point, int);
extern void memarc(Memimage*, Point, int, int, int, Memimage*, Point, int, int, int);
extern Rectangle memlinebbox(Point, Point, int, int, int);
extern int memlineendsize(int);
extern void _memmkcmap(void);
extern void memimageinit(void);
/*
* Subfont management
*/
extern Memsubfont* allocmemsubfont(char*, int, int, int, Fontchar*, Memimage*);
extern Memsubfont* openmemsubfont(char*);
extern void freememsubfont(Memsubfont*);
extern Point memsubfontwidth(Memsubfont*, char*);
extern Memsubfont* getmemdefont(void);
/*
* Predefined
*/
extern Memimage* memwhite;
extern Memimage* memblack;
extern Memimage* memopaque;
extern Memimage* memtransparent;
extern Memcmap *memdefcmap;
/*
* Kernel interface
*/
void memimagemove(void*, void*);
/*
* Kernel cruft
*/
extern void rdb(void);
extern int iprint(char*, ...);
#pragma varargck argpos iprint 1
extern int drawdebug;
/*
* doprint interface: numbconv bit strings
*/
#pragma varargck type "llb" vlong
#pragma varargck type "llb" uvlong
#pragma varargck type "lb" long
#pragma varargck type "lb" ulong
#pragma varargck type "b" int
#pragma varargck type "b" uint

51
include/memlayer.h Normal file
View File

@ -0,0 +1,51 @@
#pragma src "/sys/src/libmemlayer"
#pragma lib "libmemlayer.a"
typedef struct Memscreen Memscreen;
typedef void (*Refreshfn)(Memimage*, Rectangle, void*);
struct Memscreen
{
Memimage *frontmost; /* frontmost layer on screen */
Memimage *rearmost; /* rearmost layer on screen */
Memimage *image; /* upon which all layers are drawn */
Memimage *fill; /* if non-zero, picture to use when repainting */
};
struct Memlayer
{
Rectangle screenr; /* true position of layer on screen */
Point delta; /* add delta to go from image coords to screen */
Memscreen *screen; /* screen this layer belongs to */
Memimage *front; /* window in front of this one */
Memimage *rear; /* window behind this one*/
int clear; /* layer is fully visible */
Memimage *save; /* save area for obscured parts */
Refreshfn refreshfn; /* function to call to refresh obscured parts if save==nil */
void *refreshptr; /* argument to refreshfn */
};
/*
* These functions accept local coordinates
*/
int memload(Memimage*, Rectangle, uchar*, int, int);
int memunload(Memimage*, Rectangle, uchar*, int);
/*
* All these functions accept screen coordinates, not local ones.
*/
void _memlayerop(void (*fn)(Memimage*, Rectangle, Rectangle, void*, int), Memimage*, Rectangle, Rectangle, void*);
Memimage* memlalloc(Memscreen*, Rectangle, Refreshfn, void*, ulong);
void memldelete(Memimage*);
void memlfree(Memimage*);
void memltofront(Memimage*);
void memltofrontn(Memimage**, int);
void _memltofrontfill(Memimage*, int);
void memltorear(Memimage*);
void memltorearn(Memimage**, int);
int memlsetrefresh(Memimage*, Refreshfn, void*);
void memlhide(Memimage*, Rectangle);
void memlexpose(Memimage*, Rectangle);
void _memlsetclear(Memscreen*);
int memlorigin(Memimage*, Point, Point);
void memlnorefresh(Memimage*, Rectangle, void*);

134
include/mp.h Normal file
View File

@ -0,0 +1,134 @@
#define _MPINT 1
// the code assumes mpdigit to be at least an int
// mpdigit must be an atomic type. mpdigit is defined
// in the architecture specific u.h
typedef struct mpint mpint;
struct mpint
{
int sign; // +1 or -1
int size; // allocated digits
int top; // significant digits
mpdigit *p;
char flags;
};
enum
{
MPstatic= 0x01,
Dbytes= sizeof(mpdigit), // bytes per digit
Dbits= Dbytes*8 // bits per digit
};
// allocation
void mpsetminbits(int n); // newly created mpint's get at least n bits
mpint* mpnew(int n); // create a new mpint with at least n bits
void mpfree(mpint *b);
void mpbits(mpint *b, int n); // ensure that b has at least n bits
void mpnorm(mpint *b); // dump leading zeros
mpint* mpcopy(mpint *b);
void mpassign(mpint *old, mpint *new);
// random bits
mpint* mprand(int bits, void (*gen)(uchar*, int), mpint *b);
// conversion
mpint* strtomp(char*, char**, int, mpint*); // ascii
int mpfmt(Fmt*);
char* mptoa(mpint*, int, char*, int);
mpint* letomp(uchar*, uint, mpint*); // byte array, little-endian
int mptole(mpint*, uchar*, uint, uchar**);
mpint* betomp(uchar*, uint, mpint*); // byte array, little-endian
int mptobe(mpint*, uchar*, uint, uchar**);
uint mptoui(mpint*); // unsigned int
mpint* uitomp(uint, mpint*);
int mptoi(mpint*); // int
mpint* itomp(int, mpint*);
uvlong mptouv(mpint*); // unsigned vlong
mpint* uvtomp(uvlong, mpint*);
vlong mptov(mpint*); // vlong
mpint* vtomp(vlong, mpint*);
// divide 2 digits by one
void mpdigdiv(mpdigit *dividend, mpdigit divisor, mpdigit *quotient);
// in the following, the result mpint may be
// the same as one of the inputs.
void mpadd(mpint *b1, mpint *b2, mpint *sum); // sum = b1+b2
void mpsub(mpint *b1, mpint *b2, mpint *diff); // diff = b1-b2
void mpleft(mpint *b, int shift, mpint *res); // res = b<<shift
void mpright(mpint *b, int shift, mpint *res); // res = b>>shift
void mpmul(mpint *b1, mpint *b2, mpint *prod); // prod = b1*b2
void mpexp(mpint *b, mpint *e, mpint *m, mpint *res); // res = b**e mod m
void mpmod(mpint *b, mpint *m, mpint *remainder); // remainder = b mod m
// quotient = dividend/divisor, remainder = dividend % divisor
void mpdiv(mpint *dividend, mpint *divisor, mpint *quotient, mpint *remainder);
// return neg, 0, pos as b1-b2 is neg, 0, pos
int mpcmp(mpint *b1, mpint *b2);
// extended gcd return d, x, and y, s.t. d = gcd(a,b) and ax+by = d
void mpextendedgcd(mpint *a, mpint *b, mpint *d, mpint *x, mpint *y);
// res = b**-1 mod m
void mpinvert(mpint *b, mpint *m, mpint *res);
// bit counting
int mpsignif(mpint*); // number of sigificant bits in mantissa
int mplowbits0(mpint*); // k, where n = 2**k * q for odd q
// well known constants
extern mpint *mpzero, *mpone, *mptwo;
// sum[0:alen] = a[0:alen-1] + b[0:blen-1]
// prereq: alen >= blen, sum has room for alen+1 digits
void mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum);
// diff[0:alen-1] = a[0:alen-1] - b[0:blen-1]
// prereq: alen >= blen, diff has room for alen digits
void mpvecsub(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *diff);
// p[0:n] += m * b[0:n-1]
// prereq: p has room for n+1 digits
void mpvecdigmuladd(mpdigit *b, int n, mpdigit m, mpdigit *p);
// p[0:n] -= m * b[0:n-1]
// prereq: p has room for n+1 digits
int mpvecdigmulsub(mpdigit *b, int n, mpdigit m, mpdigit *p);
// p[0:alen*blen-1] = a[0:alen-1] * b[0:blen-1]
// prereq: alen >= blen, p has room for m*n digits
void mpvecmul(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *p);
// sign of a - b or zero if the same
int mpveccmp(mpdigit *a, int alen, mpdigit *b, int blen);
// divide the 2 digit dividend by the one digit divisor and stick in quotient
// we assume that the result is one digit - overflow is all 1's
void mpdigdiv(mpdigit *dividend, mpdigit divisor, mpdigit *quotient);
// playing with magnitudes
int mpmagcmp(mpint *b1, mpint *b2);
void mpmagadd(mpint *b1, mpint *b2, mpint *sum); // sum = b1+b2
void mpmagsub(mpint *b1, mpint *b2, mpint *sum); // sum = b1+b2
// chinese remainder theorem
typedef struct CRTpre CRTpre; // precomputed values for converting
// twixt residues and mpint
typedef struct CRTres CRTres; // residue form of an mpint
struct CRTres
{
int n; // number of residues
mpint *r[1]; // residues
};
CRTpre* crtpre(int, mpint**); // precompute conversion values
CRTres* crtin(CRTpre*, mpint*); // convert mpint to residues
void crtout(CRTpre*, CRTres*, mpint*); // convert residues to mpint
void crtprefree(CRTpre*);
void crtresfree(CRTres*);

26
include/u.h Normal file
View File

@ -0,0 +1,26 @@
#include "dtos.h"
/* avoid name conflicts */
#undef accept
#undef listen
/* sys calls */
#undef bind
#undef chdir
#undef close
#undef create
#undef dup
#undef export
#undef fstat
#undef fwstat
#undef mount
#undef open
#undef start
#undef read
#undef remove
#undef seek
#undef stat
#undef write
#undef wstat
#undef unmount
#undef pipe

14
include/unix.h Normal file
View File

@ -0,0 +1,14 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <fcntl.h>
#include <setjmp.h>
#include <time.h>
#include <assert.h>
#include <unistd.h>
#include <stdarg.h>
typedef long long p9_vlong;
typedef unsigned long long p9_uvlong;

65
include/user.h Normal file
View File

@ -0,0 +1,65 @@
/* sys calls */
#define bind sysbind
#define chdir syschdir
#define close sysclose
#define create syscreate
#define dup sysdup
#define export sysexport
#define fstat sysfstat
#define fwstat sysfwstat
#define mount sysmount
#define open sysopen
#define read sysread
#define remove sysremove
#define seek sysseek
#define stat sysstat
#define write syswrite
#define wstat syswstat
#define unmount sysunmount
#define pipe syspipe
#define rendezvous sysrendezvous
#define getpid sysgetpid
#define time systime
#define nsec sysnsec
#define pread syspread
#define pwrite syspwrite
extern int bind(char*, char*, int);
extern int chdir(char*);
extern int close(int);
extern int create(char*, int, ulong);
extern int dup(int, int);
extern int export(int);
extern int fstat(int, uchar*, int);
extern int fwstat(int, uchar*, int);
extern int mount(int, int, char*, int, char*);
extern int unmount(char*, char*);
extern int open(char*, int);
extern int pipe(int*);
extern long read(int, void*, long);
extern long readn(int, void*, long);
extern int remove(char*);
extern vlong seek(int, vlong, int);
extern int stat(char*, uchar*, int);
extern long write(int, void*, long);
extern int wstat(char*, uchar*, int);
extern Dir *dirstat(char*);
extern Dir *dirfstat(int);
extern int dirwstat(char*, Dir*);
extern int dirfwstat(int, Dir*);
extern long dirread(int, Dir*, long);
/*
* network dialing and authentication
*/
#define NETPATHLEN 40
extern int accept(int, char*);
extern int announce(char*, char*);
extern int dial(char*, char*, char*, int*);
extern int hangup(int);
extern int listen(char*, char*);
extern char *netmkaddr(char*, char*, char*);
extern int reject(int, char*, char*);
extern char* argv0;

0
include/x Normal file
View File

6
include/x.c Normal file
View File

@ -0,0 +1,6 @@
#include <stdio.h>
void
main(void)
{
}

50
kern/Makefile Normal file
View File

@ -0,0 +1,50 @@
LIB=libkern.a
CC=gcc
CFLAGS=-I../include -I. -c -ggdb -D_THREAD_SAFE -pthread
O=o
#CC=cl
#CFLAGS=-c -nologo -W3 -YX -Zi -MT -Zl -I../include -DWINDOWS
#O=obj
OFILES=\
allocb.$O\
cache.$O\
chan.$O\
data.$O\
dev.$O\
devcons.$O\
devdraw.$O\
devfs.$O\
devip.$O\
devip-posix.$O\
devmnt.$O\
devmouse.$O\
devpipe.$O\
devroot.$O\
devssl.$O\
devtab.$O\
error.$O\
parse.$O\
pgrp.$O\
posix.$O\
procinit.$O\
rwlock.$O\
sleep.$O\
smalloc.$O\
stub.$O\
sysfile.$O\
sysproc.$O\
qio.$O\
qlock.$O\
term.$O\
todo.$O\
uart.$O\
waserror.$O
$(LIB): $(OFILES)
ar r $(LIB) $(OFILES)
ranlib $(LIB)
%.$O: %.c
$(CC) $(CFLAGS) $*.c

165
kern/allocb.c Normal file
View File

@ -0,0 +1,165 @@
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
enum
{
Hdrspc = 64, /* leave room for high-level headers */
Bdead = 0x51494F42, /* "QIOB" */
};
struct
{
Lock lk;
ulong bytes;
} ialloc;
static Block*
_allocb(int size)
{
Block *b;
ulong addr;
if((b = mallocz(sizeof(Block)+size+Hdrspc, 0)) == nil)
return nil;
b->next = nil;
b->list = nil;
b->free = 0;
b->flag = 0;
/* align start of data portion by rounding up */
addr = (ulong)b;
addr = ROUND(addr + sizeof(Block), BLOCKALIGN);
b->base = (uchar*)addr;
/* align end of data portion by rounding down */
b->lim = ((uchar*)b) + sizeof(Block)+size+Hdrspc;
addr = (ulong)(b->lim);
addr = addr & ~(BLOCKALIGN-1);
b->lim = (uchar*)addr;
/* leave sluff at beginning for added headers */
b->rp = b->lim - ROUND(size, BLOCKALIGN);
if(b->rp < b->base)
panic("_allocb");
b->wp = b->rp;
return b;
}
Block*
allocb(int size)
{
Block *b;
/*
* Check in a process and wait until successful.
* Can still error out of here, though.
*/
if(up == nil)
panic("allocb without up: %luX\n", getcallerpc(&size));
if((b = _allocb(size)) == nil){
panic("allocb: no memory for %d bytes\n", size);
}
setmalloctag(b, getcallerpc(&size));
return b;
}
Block*
iallocb(int size)
{
Block *b;
static int m1, m2;
if(ialloc.bytes > conf.ialloc){
if((m1++%10000)==0)
print("iallocb: limited %lud/%lud\n",
ialloc.bytes, conf.ialloc);
return 0;
}
if((b = _allocb(size)) == nil){
if((m2++%10000)==0)
print("iallocb: no memory %lud/%lud\n",
ialloc.bytes, conf.ialloc);
return nil;
}
setmalloctag(b, getcallerpc(&size));
b->flag = BINTR;
ilock(&ialloc.lk);
ialloc.bytes += b->lim - b->base;
iunlock(&ialloc.lk);
return b;
}
void
freeb(Block *b)
{
void *dead = (void*)Bdead;
if(b == nil)
return;
/*
* drivers which perform non cache coherent DMA manage their own buffer
* pool of uncached buffers and provide their own free routine.
*/
if(b->free) {
b->free(b);
return;
}
if(b->flag & BINTR) {
ilock(&ialloc.lk);
ialloc.bytes -= b->lim - b->base;
iunlock(&ialloc.lk);
}
/* poison the block in case someone is still holding onto it */
b->next = dead;
b->rp = dead;
b->wp = dead;
b->lim = dead;
b->base = dead;
free(b);
}
void
checkb(Block *b, char *msg)
{
void *dead = (void*)Bdead;
if(b == dead)
panic("checkb b %s %lux", msg, b);
if(b->base == dead || b->lim == dead || b->next == dead
|| b->rp == dead || b->wp == dead){
print("checkb: base 0x%8.8luX lim 0x%8.8luX next 0x%8.8luX\n",
b->base, b->lim, b->next);
print("checkb: rp 0x%8.8luX wp 0x%8.8luX\n", b->rp, b->wp);
panic("checkb dead: %s\n", msg);
}
if(b->base > b->lim)
panic("checkb 0 %s %lux %lux", msg, b->base, b->lim);
if(b->rp < b->base)
panic("checkb 1 %s %lux %lux", msg, b->base, b->rp);
if(b->wp < b->base)
panic("checkb 2 %s %lux %lux", msg, b->base, b->wp);
if(b->rp > b->lim)
panic("checkb 3 %s %lux %lux", msg, b->rp, b->lim);
if(b->wp > b->lim)
panic("checkb 4 %s %lux %lux", msg, b->wp, b->lim);
}
void
iallocsummary(void)
{
print("ialloc %lud/%lud\n", ialloc.bytes, conf.ialloc);
}

46
kern/cache.c Normal file
View File

@ -0,0 +1,46 @@
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
void
cinit(void)
{
}
void
copen(Chan *c)
{
USED(c);
}
int
cread(Chan *c, uchar *buf, int len, vlong off)
{
USED(c);
USED(buf);
USED(len);
USED(off);
return 0;
}
void
cupdate(Chan *c, uchar *buf, int len, vlong off)
{
USED(c);
USED(buf);
USED(len);
USED(off);
}
void
cwrite(Chan* c, uchar *buf, int len, vlong off)
{
USED(c);
USED(buf);
USED(len);
USED(off);
}

1496
kern/chan.c Normal file

File diff suppressed because it is too large Load Diff

519
kern/dat.h Normal file
View File

@ -0,0 +1,519 @@
#define KNAMELEN 28 /* max length of name held in kernel */
#define DOMLEN 64
#define BLOCKALIGN 8
typedef struct Alarms Alarms;
typedef struct Block Block;
typedef struct CSN CSN;
typedef struct Chan Chan;
typedef struct Cmdbuf Cmdbuf;
typedef struct Cmdtab Cmdtab;
typedef struct Cname Cname;
typedef struct Conf Conf;
typedef struct Dev Dev;
typedef struct Dirtab Dirtab;
typedef struct Edfinterface Edfinterface;
typedef struct Egrp Egrp;
typedef struct Evalue Evalue;
typedef struct Fgrp Fgrp;
typedef struct FPsave FPsave;
typedef struct DevConf DevConf;
typedef struct Label Label;
typedef struct List List;
typedef struct Log Log;
typedef struct Logflag Logflag;
typedef struct Mntcache Mntcache;
typedef struct Mount Mount;
typedef struct Mntrpc Mntrpc;
typedef struct Mntwalk Mntwalk;
typedef struct Mnt Mnt;
typedef struct Mhead Mhead;
typedef struct Note Note;
typedef struct Page Page;
typedef struct Palloc Palloc;
typedef struct Perf Perf;
typedef struct Pgrps Pgrps;
typedef struct PhysUart PhysUart;
typedef struct Pgrp Pgrp;
typedef struct Physseg Physseg;
typedef struct Proc Proc;
typedef struct Pte Pte;
typedef struct Pthash Pthash;
typedef struct Queue Queue;
typedef struct Ref Ref;
typedef struct Rendez Rendez;
typedef struct Rgrp Rgrp;
typedef struct RWlock RWlock;
typedef struct Schedq Schedq;
typedef struct Segment Segment;
typedef struct Session Session;
typedef struct Task Task;
typedef struct Talarm Talarm;
typedef struct Timer Timer;
typedef struct Uart Uart;
typedef struct Ureg Ureg;
typedef struct Waitq Waitq;
typedef struct Walkqid Walkqid;
typedef int Devgen(Chan*, char*, Dirtab*, int, int, Dir*);
#include "fcall.h"
enum
{
SnarfSize = 64*1024,
};
struct Conf
{
ulong nmach; /* processors */
ulong nproc; /* processes */
ulong monitor; /* has monitor? */
ulong npage0; /* total physical pages of memory */
ulong npage1; /* total physical pages of memory */
ulong npage; /* total physical pages of memory */
ulong upages; /* user page pool */
ulong nimage; /* number of page cache image headers */
ulong nswap; /* number of swap pages */
int nswppo; /* max # of pageouts per segment pass */
ulong base0; /* base of bank 0 */
ulong base1; /* base of bank 1 */
ulong copymode; /* 0 is copy on write, 1 is copy on reference */
ulong ialloc; /* max interrupt time allocation in bytes */
ulong pipeqsize; /* size in bytes of pipe queues */
int nuart; /* number of uart devices */
};
struct Label
{
jmp_buf buf;
};
struct Ref
{
Lock lk;
long ref;
};
struct Rendez
{
Lock lk;
Proc *p;
};
struct RWlock /* changed from kernel */
{
int readers;
Lock lk;
QLock x;
QLock k;
};
struct Talarm
{
Lock lk;
Proc *list;
};
struct Alarms
{
QLock lk;
Proc *head;
};
/*
* Access types in namec & channel flags
*/
enum
{
Aaccess, /* as in stat, wstat */
Abind, /* for left-hand-side of bind */
Atodir, /* as in chdir */
Aopen, /* for i/o */
Amount, /* to be mounted or mounted upon */
Acreate, /* is to be created */
Aremove, /* will be removed by caller */
COPEN = 0x0001, /* for i/o */
CMSG = 0x0002, /* the message channel for a mount */
/*rsc CCREATE = 0x0004, /* permits creation if c->mnt */
CCEXEC = 0x0008, /* close on exec */
CFREE = 0x0010, /* not in use */
CRCLOSE = 0x0020, /* remove on close */
CCACHE = 0x0080, /* client cache */
};
/* flag values */
enum
{
BINTR = (1<<0),
BFREE = (1<<1),
Bipck = (1<<2), /* ip checksum */
Budpck = (1<<3), /* udp checksum */
Btcpck = (1<<4), /* tcp checksum */
Bpktck = (1<<5), /* packet checksum */
};
struct Block
{
Block* next;
Block* list;
uchar* rp; /* first unconsumed byte */
uchar* wp; /* first empty byte */
uchar* lim; /* 1 past the end of the buffer */
uchar* base; /* start of the buffer */
void (*free)(Block*);
ushort flag;
ushort checksum; /* IP checksum of complete packet (minus media header) */
};
#define BLEN(s) ((s)->wp - (s)->rp)
#define BALLOC(s) ((s)->lim - (s)->base)
struct Chan
{
Ref ref;
Chan* next; /* allocation */
Chan* link;
vlong offset; /* in file */
ushort type;
ulong dev;
ushort mode; /* read/write */
ushort flag;
Qid qid;
int fid; /* for devmnt */
ulong iounit; /* chunk size for i/o; 0==default */
Mhead* umh; /* mount point that derived Chan; used in unionread */
Chan* umc; /* channel in union; held for union read */
QLock umqlock; /* serialize unionreads */
int uri; /* union read index */
int dri; /* devdirread index */
ulong mountid;
Mntcache *mcp; /* Mount cache pointer */
Mnt *mux; /* Mnt for clients using me for messages */
void* aux;
Qid pgrpid; /* for #p/notepg */
ulong mid; /* for ns in devproc */
Chan* mchan; /* channel to mounted server */
Qid mqid; /* qid of root of mount point */
Session*session;
Cname *name;
};
struct Cname
{
Ref ref;
int alen; /* allocated length */
int len; /* strlen(s) */
char *s;
};
struct Dev
{
int dc;
char* name;
void (*reset)(void);
void (*init)(void);
void (*shutdown)(void);
Chan* (*attach)(char*);
Walkqid* (*walk)(Chan*, Chan*, char**, int);
int (*stat)(Chan*, uchar*, int);
Chan* (*open)(Chan*, int);
void (*create)(Chan*, char*, int, ulong);
void (*close)(Chan*);
long (*read)(Chan*, void*, long, vlong);
Block* (*bread)(Chan*, long, ulong);
long (*write)(Chan*, void*, long, vlong);
long (*bwrite)(Chan*, Block*, ulong);
void (*remove)(Chan*);
int (*wstat)(Chan*, uchar*, int);
void (*power)(int); /* power mgt: power(1) => on, power (0) => off */
int (*config)(int, char*, DevConf*); // returns nil on error
};
struct Dirtab
{
char name[KNAMELEN];
Qid qid;
vlong length;
long perm;
};
struct Walkqid
{
Chan *clone;
int nqid;
Qid qid[1];
};
enum
{
NSMAX = 1000,
NSLOG = 7,
NSCACHE = (1<<NSLOG),
};
struct Mntwalk /* state for /proc/#/ns */
{
int cddone;
ulong id;
Mhead* mh;
Mount* cm;
};
struct Mount
{
ulong mountid;
Mount* next;
Mhead* head;
Mount* copy;
Mount* order;
Chan* to; /* channel replacing channel */
int mflag;
char *spec;
};
struct Mhead
{
Ref ref;
RWlock lock;
Chan* from; /* channel mounted upon */
Mount* mount; /* what's mounted upon it */
Mhead* hash; /* Hash chain */
};
struct Mnt
{
Lock lk;
/* references are counted using c->ref; channels on this mount point incref(c->mchan) == Mnt.c */
Chan *c; /* Channel to file service */
Proc *rip; /* Reader in progress */
Mntrpc *queue; /* Queue of pending requests on this channel */
ulong id; /* Multiplexer id for channel check */
Mnt *list; /* Free list */
int flags; /* cache */
int msize; /* data + IOHDRSZ */
char *version; /* 9P version */
Queue *q; /* input queue */
};
enum
{
NUser, /* note provided externally */
NExit, /* deliver note quietly */
NDebug, /* print debug message */
};
struct Note
{
char msg[ERRMAX];
int flag; /* whether system posted it */
};
enum
{
RENDLOG = 5,
RENDHASH = 1<<RENDLOG, /* Hash to lookup rendezvous tags */
MNTLOG = 5,
MNTHASH = 1<<MNTLOG, /* Hash to walk mount table */
NFD = 100, /* per process file descriptors */
PGHLOG = 9,
PGHSIZE = 1<<PGHLOG, /* Page hash for image lookup */
};
#define REND(p,s) ((p)->rendhash[(s)&((1<<RENDLOG)-1)])
#define MOUNTH(p,qid) ((p)->mnthash[(qid).path&((1<<MNTLOG)-1)])
struct Pgrp
{
Ref ref; /* also used as a lock when mounting */
int noattach;
ulong pgrpid;
QLock debug; /* single access via devproc.c */
RWlock ns; /* Namespace n read/one write lock */
Mhead *mnthash[MNTHASH];
};
struct Rgrp
{
Ref ref;
Proc *rendhash[RENDHASH]; /* Rendezvous tag hash */
};
struct Egrp
{
Ref ref;
RWlock lk;
Evalue **ent;
int nent;
int ment;
ulong path; /* qid.path of next Evalue to be allocated */
ulong vers; /* of Egrp */
};
struct Evalue
{
char *name;
char *value;
int len;
Evalue *link;
Qid qid;
};
struct Fgrp
{
Ref ref;
Chan **fd;
int nfd; /* number allocated */
int maxfd; /* highest fd in use */
int exceed; /* debugging */
};
enum
{
DELTAFD = 20, /* incremental increase in Fgrp.fd's */
NERR = 20
};
typedef uvlong Ticks;
enum
{
Running,
Rendezvous,
Wakeme,
};
struct Proc
{
uint state;
uint mach;
ulong pid;
ulong parentpid;
Pgrp *pgrp; /* Process group for namespace */
Fgrp *fgrp; /* File descriptor group */
Rgrp *rgrp;
Lock rlock; /* sync sleep/wakeup with postnote */
Rendez *r; /* rendezvous point slept on */
Rendez sleep; /* place for syssleep/debug */
int notepending; /* note issued but not acted on */
int kp; /* true if a kernel process */
ulong rendtag; /* Tag for rendezvous */
ulong rendval; /* Value for rendezvous */
Proc *rendhash; /* Hash list for tag values */
int nerrlab;
Label errlab[NERR];
char user[KNAMELEN];
char *syserrstr; /* last error from a system call, errbuf0 or 1 */
char *errstr; /* reason we're unwinding the error stack, errbuf1 or 0 */
char errbuf0[ERRMAX];
char errbuf1[ERRMAX];
char genbuf[128]; /* buffer used e.g. for last name element from namec */
char text[KNAMELEN];
Chan *slash;
Chan *dot;
Proc *qnext;
void (*fn)(void*);
void *arg;
char oproc[1024]; /* reserved for os */
};
enum
{
PRINTSIZE = 256,
MAXCRYPT = 127,
NUMSIZE = 12, /* size of formatted number */
MB = (1024*1024),
READSTR = 1000, /* temporary buffer size for device reads */
};
extern char* conffile;
extern int cpuserver;
extern Dev* devtab[];
extern char *eve;
extern char hostdomain[];
extern uchar initcode[];
extern Queue* kbdq;
extern Queue* kprintoq;
extern Ref noteidalloc;
extern Palloc palloc;
extern Queue *serialoq;
extern char* statename[];
extern int nsyscall;
extern char *sysname;
extern uint qiomaxatomic;
extern Conf conf;
enum
{
LRESPROF = 3,
};
/*
* action log
*/
struct Log {
Lock lk;
int opens;
char* buf;
char *end;
char *rptr;
int len;
int nlog;
int minread;
int logmask; /* mask of things to debug */
QLock readq;
Rendez readr;
};
struct Logflag {
char* name;
int mask;
};
enum
{
NCMDFIELD = 128
};
struct Cmdbuf
{
char *buf;
char **f;
int nf;
};
struct Cmdtab
{
int index; /* used by client to switch on result */
char *cmd; /* command name */
int narg; /* expected #args; 0 ==> variadic */
};
/* queue state bits, Qmsg, Qcoalesce, and Qkick can be set in qopen */
enum
{
/* Queue.state */
Qstarve = (1<<0), /* consumer starved */
Qmsg = (1<<1), /* message stream */
Qclosed = (1<<2), /* queue has been closed/hungup */
Qflow = (1<<3), /* producer flow controlled */
Qcoalesce = (1<<4), /* coallesce packets on read */
Qkick = (1<<5), /* always call the kick routine after qwrite */
};
#define DEVDOTDOT -1
extern Proc *_getproc(void);
extern void _setproc(Proc*);
#define up (_getproc())

31
kern/data.c Normal file
View File

@ -0,0 +1,31 @@
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
Proc *up;
Conf conf =
{
1,
100,
0,
1024*1024*1024,
1024*1024*1024,
1024*1024*1024,
1024*1024*1024,
1024*1024*1024,
1024*1024*1024,
1024*1024*1024,
1024*1024*1024,
1024*1024*1024,
1024*1024*1024,
1024*1024*1024,
1024*1024*1024,
0,
};
char *eve = "eve";
ulong kerndate;
int cpuserver;
char hostdomain[] = "drawterm.net";

468
kern/dev.c Normal file
View File

@ -0,0 +1,468 @@
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
extern ulong kerndate;
void
mkqid(Qid *q, vlong path, ulong vers, int type)
{
q->type = type;
q->vers = vers;
q->path = path;
}
int
devno(int c, int user)
{
int i;
for(i = 0; devtab[i] != nil; i++) {
if(devtab[i]->dc == c)
return i;
}
if(user == 0)
panic("devno %C 0x%ux", c, c);
return -1;
}
void
devdir(Chan *c, Qid qid, char *n, vlong length, char *user, long perm, Dir *db)
{
db->name = n;
if(c->flag&CMSG)
qid.type |= QTMOUNT;
db->qid = qid;
db->type = devtab[c->type]->dc;
db->dev = c->dev;
db->mode = perm;
db->mode |= qid.type << 24;
db->atime = seconds();
db->mtime = kerndate;
db->length = length;
db->uid = user;
db->gid = eve;
db->muid = user;
}
/*
* (here, Devgen is the prototype; devgen is the function in dev.c.)
*
* a Devgen is expected to return the directory entry for ".."
* if you pass it s==DEVDOTDOT (-1). otherwise...
*
* there are two contradictory rules.
*
* (i) if c is a directory, a Devgen is expected to list its children
* as you iterate s.
*
* (ii) whether or not c is a directory, a Devgen is expected to list
* its siblings as you iterate s.
*
* devgen always returns the list of children in the root
* directory. thus it follows (i) when c is the root and (ii) otherwise.
* many other Devgens follow (i) when c is a directory and (ii) otherwise.
*
* devwalk assumes (i). it knows that devgen breaks (i)
* for children that are themselves directories, and explicitly catches them.
*
* devstat assumes (ii). if the Devgen in question follows (i)
* for this particular c, devstat will not find the necessary info.
* with our particular Devgen functions, this happens only for
* directories, so devstat makes something up, assuming
* c->name, c->qid, eve, DMDIR|0555.
*
* devdirread assumes (i). the callers have to make sure
* that the Devgen satisfies (i) for the chan being read.
*/
/*
* the zeroth element of the table MUST be the directory itself for ..
*/
int
devgen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp)
{
if(tab == 0)
return -1;
if(i == DEVDOTDOT){
/* nothing */
}else if(name){
for(i=1; i<ntab; i++)
if(strcmp(tab[i].name, name) == 0)
break;
if(i==ntab)
return -1;
tab += i;
}else{
/* skip over the first element, that for . itself */
i++;
if(i >= ntab)
return -1;
tab += i;
}
devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
return 1;
}
void
devreset(void)
{
}
void
devinit(void)
{
}
void
devshutdown(void)
{
}
Chan*
devattach(int tc, char *spec)
{
Chan *c;
char *buf;
c = newchan();
mkqid(&c->qid, 0, 0, QTDIR);
c->type = devno(tc, 0);
if(spec == nil)
spec = "";
buf = smalloc(4+strlen(spec)+1);
sprint(buf, "#%C%s", tc, spec);
c->name = newcname(buf);
free(buf);
return c;
}
Chan*
devclone(Chan *c)
{
Chan *nc;
if(c->flag & COPEN)
panic("clone of open file type %C\n", devtab[c->type]->dc);
nc = newchan();
nc->type = c->type;
nc->dev = c->dev;
nc->mode = c->mode;
nc->qid = c->qid;
nc->offset = c->offset;
nc->umh = nil;
nc->mountid = c->mountid;
nc->aux = c->aux;
nc->pgrpid = c->pgrpid;
nc->mid = c->mid;
nc->mqid = c->mqid;
nc->mcp = c->mcp;
return nc;
}
Walkqid*
devwalk(Chan *c, Chan *nc, char **name, int nname, Dirtab *tab, int ntab, Devgen *gen)
{
int i, j, alloc;
Walkqid *wq;
char *n;
Dir dir;
if(nname > 0)
isdir(c);
alloc = 0;
wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
if(waserror()){
if(alloc && wq->clone!=nil)
cclose(wq->clone);
free(wq);
return nil;
}
if(nc == nil){
nc = devclone(c);
nc->type = 0; /* device doesn't know about this channel yet */
alloc = 1;
}
wq->clone = nc;
for(j=0; j<nname; j++){
if(!(nc->qid.type&QTDIR)){
if(j==0)
error(Enotdir);
goto Done;
}
n = name[j];
if(strcmp(n, ".") == 0){
Accept:
wq->qid[wq->nqid++] = nc->qid;
continue;
}
if(strcmp(n, "..") == 0){
if((*gen)(nc, nil, tab, ntab, DEVDOTDOT, &dir) != 1){
print("devgen walk .. in dev%s %llux broken\n",
devtab[nc->type]->name, nc->qid.path);
error("broken devgen");
}
nc->qid = dir.qid;
goto Accept;
}
/*
* Ugly problem: If we're using devgen, make sure we're
* walking the directory itself, represented by the first
* entry in the table, and not trying to step into a sub-
* directory of the table, e.g. /net/net. Devgen itself
* should take care of the problem, but it doesn't have
* the necessary information (that we're doing a walk).
*/
if(gen==devgen && nc->qid.path!=tab[0].qid.path)
goto Notfound;
for(i=0;; i++) {
switch((*gen)(nc, n, tab, ntab, i, &dir)){
case -1:
Notfound:
if(j == 0)
error(Enonexist);
kstrcpy(up->errstr, Enonexist, ERRMAX);
goto Done;
case 0:
continue;
case 1:
if(strcmp(n, dir.name) == 0){
nc->qid = dir.qid;
goto Accept;
}
continue;
}
}
}
/*
* We processed at least one name, so will return some data.
* If we didn't process all nname entries succesfully, we drop
* the cloned channel and return just the Qids of the walks.
*/
Done:
poperror();
if(wq->nqid < nname){
if(alloc)
cclose(wq->clone);
wq->clone = nil;
}else if(wq->clone){
/* attach cloned channel to same device */
wq->clone->type = c->type;
}
return wq;
}
int
devstat(Chan *c, uchar *db, int n, Dirtab *tab, int ntab, Devgen *gen)
{
int i;
Dir dir;
char *p, *elem;
for(i=0;; i++)
switch((*gen)(c, nil, tab, ntab, i, &dir)){
case -1:
if(c->qid.type & QTDIR){
if(c->name == nil)
elem = "???";
else if(strcmp(c->name->s, "/") == 0)
elem = "/";
else
for(elem=p=c->name->s; *p; p++)
if(*p == '/')
elem = p+1;
devdir(c, c->qid, elem, 0, eve, DMDIR|0555, &dir);
n = convD2M(&dir, db, n);
if(n == 0)
error(Ebadarg);
return n;
}
print("devstat %C %llux\n", devtab[c->type]->dc, c->qid.path);
error(Enonexist);
case 0:
break;
case 1:
if(c->qid.path == dir.qid.path) {
if(c->flag&CMSG)
dir.mode |= DMMOUNT;
n = convD2M(&dir, db, n);
if(n == 0)
error(Ebadarg);
return n;
}
break;
}
error(Egreg); /* not reached? */
return -1;
}
long
devdirread(Chan *c, char *d, long n, Dirtab *tab, int ntab, Devgen *gen)
{
long m, dsz;
struct{
Dir d;
char slop[100];
}dir;
for(m=0; m<n; c->dri++) {
switch((*gen)(c, nil, tab, ntab, c->dri, &dir.d)){
case -1:
return m;
case 0:
break;
case 1:
dsz = convD2M(&dir.d, (uchar*)d, n-m);
if(dsz <= BIT16SZ){ /* <= not < because this isn't stat; read is stuck */
if(m == 0)
error(Eshort);
return m;
}
m += dsz;
d += dsz;
break;
}
}
return m;
}
/*
* error(Eperm) if open permission not granted for up->user.
*/
void
devpermcheck(char *fileuid, ulong perm, int omode)
{
ulong t;
static int access[] = { 0400, 0200, 0600, 0100 };
if(strcmp(up->user, fileuid) == 0)
perm <<= 0;
else
if(strcmp(up->user, eve) == 0)
perm <<= 3;
else
perm <<= 6;
t = access[omode&3];
if((t&perm) != t)
error(Eperm);
}
Chan*
devopen(Chan *c, int omode, Dirtab *tab, int ntab, Devgen *gen)
{
int i;
Dir dir;
for(i=0;; i++) {
switch((*gen)(c, nil, tab, ntab, i, &dir)){
case -1:
goto Return;
case 0:
break;
case 1:
if(c->qid.path == dir.qid.path) {
devpermcheck(dir.uid, dir.mode, omode);
goto Return;
}
break;
}
}
Return:
c->offset = 0;
if((c->qid.type&QTDIR) && omode!=OREAD)
error(Eperm);
c->mode = openmode(omode);
c->flag |= COPEN;
return c;
}
void
devcreate(Chan *c, char *name, int mode, ulong perm)
{
USED(c);
USED(name);
USED(mode);
USED(perm);
error(Eperm);
}
Block*
devbread(Chan *c, long n, ulong offset)
{
Block *bp;
bp = allocb(n);
if(bp == 0)
error(Enomem);
if(waserror()) {
freeb(bp);
nexterror();
}
bp->wp += devtab[c->type]->read(c, bp->wp, n, offset);
poperror();
return bp;
}
long
devbwrite(Chan *c, Block *bp, ulong offset)
{
long n;
if(waserror()) {
freeb(bp);
nexterror();
}
n = devtab[c->type]->write(c, bp->rp, BLEN(bp), offset);
poperror();
freeb(bp);
return n;
}
void
devremove(Chan *c)
{
USED(c);
error(Eperm);
}
int
devwstat(Chan *c, uchar *a, int n)
{
USED(c);
USED(a);
USED(n);
error(Eperm);
return 0;
}
void
devpower(int a)
{
USED(a);
error(Eperm);
}
int
devconfig(int a, char *b, DevConf *c)
{
USED(a);
USED(b);
USED(c);
error(Eperm);
return 0;
}

1238
kern/devcons.c Normal file

File diff suppressed because it is too large Load Diff

2100
kern/devdraw.c Normal file

File diff suppressed because it is too large Load Diff

638
kern/devfs.c Normal file
View File

@ -0,0 +1,638 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h> /* for remove, rename */
#include <limits.h>
#ifndef NAME_MAX
# define NAME_MAX 256
#endif
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
typedef struct Ufsinfo Ufsinfo;
enum
{
NUID = 256,
NGID = 256,
MAXPATH = 1024,
MAXCOMP = 128
};
struct Ufsinfo
{
int mode;
int fd;
int uid;
int gid;
DIR* dir;
ulong offset;
QLock oq;
char nextname[NAME_MAX];
};
char *base = "/";
static Qid fsqid(char*, struct stat *);
static void fspath(Chan*, char*, char*);
static ulong fsdirread(Chan*, uchar*, int, ulong);
static int fsomode(int);
/* clumsy hack, but not worse than the Path stuff in the last one */
static char*
uc2name(Chan *c)
{
char *s;
if(c->name == nil)
return "/";
s = c2name(c);
if(s[0]=='#' && s[1]=='U')
return s+2;
return s;
}
static char*
lastelem(Chan *c)
{
char *s, *t;
s = uc2name(c);
if((t = strrchr(s, '/')) == nil)
return s;
if(t[1] == 0)
return t;
return t+1;
}
static Chan*
fsattach(char *spec)
{
Chan *c;
struct stat stbuf;
static int devno;
Ufsinfo *uif;
if(stat(base, &stbuf) < 0)
error(strerror(errno));
c = devattach('U', spec);
uif = mallocz(sizeof(Ufsinfo), 1);
uif->mode = stbuf.st_mode;
uif->uid = stbuf.st_uid;
uif->gid = stbuf.st_gid;
c->aux = uif;
c->dev = devno++;
c->qid.type = QTDIR;
/*print("fsattach %s\n", c2name(c));*/
return c;
}
static Chan*
fsclone(Chan *c, Chan *nc)
{
Ufsinfo *uif;
uif = mallocz(sizeof(Ufsinfo), 1);
*uif = *(Ufsinfo*)c->aux;
nc->aux = uif;
return nc;
}
static int
fswalk1(Chan *c, char *name)
{
struct stat stbuf;
char path[MAXPATH];
Ufsinfo *uif;
fspath(c, name, path);
/*print("** fs walk '%s' -> %s\n", path, name); */
if(stat(path, &stbuf) < 0)
return 0;
uif = c->aux;
uif->mode = stbuf.st_mode;
uif->uid = stbuf.st_uid;
uif->gid = stbuf.st_gid;
c->qid = fsqid(path, &stbuf);
return 1;
}
extern Cname* addelem(Cname*, char*);
static Walkqid*
fswalk(Chan *c, Chan *nc, char **name, int nname)
{
int i;
Cname *cname;
Walkqid *wq;
if(nc != nil)
panic("fswalk: nc != nil");
wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
nc = devclone(c);
cname = c->name;
incref(&cname->ref);
fsclone(c, nc);
wq->clone = nc;
for(i=0; i<nname; i++){
nc->name = cname;
if(fswalk1(nc, name[i]) == 0)
break;
cname = addelem(cname, name[i]);
wq->qid[i] = nc->qid;
}
nc->name = nil;
cnameclose(cname);
if(i != nname){
cclose(nc);
wq->clone = nil;
}
wq->nqid = i;
return wq;
}
static int
fsstat(Chan *c, uchar *buf, int n)
{
Dir d;
struct stat stbuf;
char path[MAXPATH];
if(n < BIT16SZ)
error(Eshortstat);
fspath(c, 0, path);
if(stat(path, &stbuf) < 0)
error(strerror(errno));
d.name = lastelem(c);
d.uid = "unknown";
d.gid = "unknown";
d.muid = "unknown";
d.qid = c->qid;
d.mode = (c->qid.type<<24)|(stbuf.st_mode&0777);
d.atime = stbuf.st_atime;
d.mtime = stbuf.st_mtime;
d.length = stbuf.st_size;
d.type = 'U';
d.dev = c->dev;
return convD2M(&d, buf, n);
}
static Chan*
fsopen(Chan *c, int mode)
{
char path[MAXPATH];
int m, isdir;
Ufsinfo *uif;
/*print("fsopen %s\n", c2name(c));*/
m = mode & (OTRUNC|3);
switch(m) {
case 0:
break;
case 1:
case 1|16:
break;
case 2:
case 0|16:
case 2|16:
break;
case 3:
break;
default:
error(Ebadarg);
}
isdir = c->qid.type & QTDIR;
if(isdir && mode != OREAD)
error(Eperm);
m = fsomode(m & 3);
c->mode = openmode(mode);
uif = c->aux;
fspath(c, 0, path);
if(isdir) {
uif->dir = opendir(path);
if(uif->dir == 0)
error(strerror(errno));
}
else {
if(mode & OTRUNC)
m |= O_TRUNC;
uif->fd = open(path, m, 0666);
if(uif->fd < 0)
error(strerror(errno));
}
uif->offset = 0;
c->offset = 0;
c->flag |= COPEN;
return c;
}
static void
fscreate(Chan *c, char *name, int mode, ulong perm)
{
int fd, m;
char path[MAXPATH];
struct stat stbuf;
Ufsinfo *uif;
m = fsomode(mode&3);
fspath(c, name, path);
uif = c->aux;
if(perm & DMDIR) {
if(m)
error(Eperm);
if(mkdir(path, perm & 0777) < 0)
error(strerror(errno));
fd = open(path, 0);
if(fd >= 0) {
chmod(path, perm & 0777);
chown(path, uif->uid, uif->uid);
}
close(fd);
uif->dir = opendir(path);
if(uif->dir == 0)
error(strerror(errno));
}
else {
fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0666);
if(fd >= 0) {
if(m != 1) {
close(fd);
fd = open(path, m);
}
chmod(path, perm & 0777);
chown(path, uif->uid, uif->gid);
}
if(fd < 0)
error(strerror(errno));
uif->fd = fd;
}
if(stat(path, &stbuf) < 0)
error(strerror(errno));
c->qid = fsqid(path, &stbuf);
c->offset = 0;
c->flag |= COPEN;
c->mode = openmode(mode);
}
static void
fsclose(Chan *c)
{
Ufsinfo *uif;
uif = c->aux;
if(c->flag & COPEN) {
if(c->qid.type & QTDIR)
closedir(uif->dir);
else
close(uif->fd);
}
free(uif);
}
static long
fsread(Chan *c, void *va, long n, vlong offset)
{
int fd, r;
Ufsinfo *uif;
/*print("fsread %s\n", c2name(c));*/
if(c->qid.type & QTDIR)
return fsdirread(c, va, n, offset);
uif = c->aux;
qlock(&uif->oq);
if(waserror()) {
qunlock(&uif->oq);
nexterror();
}
fd = uif->fd;
if(uif->offset != offset) {
r = lseek(fd, offset, 0);
if(r < 0)
error(strerror(errno));
uif->offset = offset;
}
n = read(fd, va, n);
if(n < 0)
error(strerror(errno));
uif->offset += n;
qunlock(&uif->oq);
poperror();
return n;
}
static long
fswrite(Chan *c, void *va, long n, vlong offset)
{
int fd, r;
Ufsinfo *uif;
uif = c->aux;
qlock(&uif->oq);
if(waserror()) {
qunlock(&uif->oq);
nexterror();
}
fd = uif->fd;
if(uif->offset != offset) {
r = lseek(fd, offset, 0);
if(r < 0)
error(strerror(errno));
uif->offset = offset;
}
n = write(fd, va, n);
if(n < 0)
error(strerror(errno));
uif->offset += n;
qunlock(&uif->oq);
poperror();
return n;
}
static void
fsremove(Chan *c)
{
int n;
char path[MAXPATH];
fspath(c, 0, path);
if(c->qid.type & QTDIR)
n = rmdir(path);
else
n = remove(path);
if(n < 0)
error(strerror(errno));
}
int
fswstat(Chan *c, uchar *buf, int n)
{
Dir d;
struct stat stbuf;
char old[MAXPATH], new[MAXPATH], dir[MAXPATH];
char strs[MAXPATH*3], *p;
Ufsinfo *uif;
if(convM2D(buf, n, &d, strs) != n)
error(Ebadstat);
fspath(c, 0, old);
if(stat(old, &stbuf) < 0)
error(strerror(errno));
uif = c->aux;
if(d.name[0] && strcmp(d.name, lastelem(c)) != 0) {
fspath(c, 0, old);
strcpy(new, old);
p = strrchr(new, '/');
strcpy(p+1, d.name);
if(rename(old, new) < 0)
error(strerror(errno));
}
fspath(c, 0, old);
if(~d.mode != 0 && (int)(d.mode&0777) != (int)(stbuf.st_mode&0777)) {
if(chmod(old, d.mode&0777) < 0)
error(strerror(errno));
uif->mode &= ~0777;
uif->mode |= d.mode&0777;
}
/*
p = name2pass(gid, d.gid);
if(p == 0)
error(Eunknown);
if(p->id != stbuf.st_gid) {
if(chown(old, stbuf.st_uid, p->id) < 0)
error(strerror(errno));
uif->gid = p->id;
}
*/
return n;
}
static Qid
fsqid(char *p, struct stat *st)
{
Qid q;
int dev;
ulong h;
static int nqdev;
static uchar *qdev;
if(qdev == 0)
qdev = mallocz(65536U, 1);
q.type = 0;
if((st->st_mode&S_IFMT) == S_IFDIR)
q.type = QTDIR;
dev = st->st_dev & 0xFFFFUL;
if(qdev[dev] == 0)
qdev[dev] = ++nqdev;
h = 0;
while(*p != '\0')
h += *p++ * 13;
q.path = (vlong)qdev[dev]<<32;
q.path |= h;
q.vers = st->st_mtime;
return q;
}
static void
fspath(Chan *c, char *ext, char *path)
{
int i, n;
char *comp[MAXCOMP];
strcpy(path, base);
strcat(path, "/");
strcat(path, uc2name(c));
if(ext){
strcat(path, "/");
strcat(path, ext);
}
cleanname(path);
}
static int
isdots(char *name)
{
if(name[0] != '.')
return 0;
if(name[1] == '\0')
return 1;
if(name[1] != '.')
return 0;
if(name[2] == '\0')
return 1;
return 0;
}
static int
p9readdir(char *name, Ufsinfo *uif)
{
struct dirent *de;
if(uif->nextname[0]){
strcpy(name, uif->nextname);
uif->nextname[0] = 0;
return 1;
}
de = readdir(uif->dir);
if(de == NULL)
return 0;
strcpy(name, de->d_name);
return 1;
}
static ulong
fsdirread(Chan *c, uchar *va, int count, ulong offset)
{
int i;
Dir d;
long n;
char de[NAME_MAX];
struct stat stbuf;
char path[MAXPATH], dirpath[MAXPATH];
Ufsinfo *uif;
/*print("fsdirread %s\n", c2name(c));*/
i = 0;
uif = c->aux;
errno = 0;
if(uif->offset != offset) {
if(offset != 0)
error("bad offset in fsdirread");
uif->offset = offset; /* sync offset */
uif->nextname[0] = 0;
rewinddir(uif->dir);
}
fspath(c, 0, dirpath);
while(i+BIT16SZ < count) {
if(!p9readdir(de, uif))
break;
if(de[0]==0 || isdots(de))
continue;
d.name = de;
sprint(path, "%s/%s", dirpath, de);
memset(&stbuf, 0, sizeof stbuf);
if(stat(path, &stbuf) < 0) {
print("dir: bad path %s\n", path);
/* but continue... probably a bad symlink */
}
d.uid = "unknown";
d.gid = "unknown";
d.qid = fsqid(path, &stbuf);
d.mode = (d.qid.type<<24)|(stbuf.st_mode&0777);
d.atime = stbuf.st_atime;
d.mtime = stbuf.st_mtime;
d.length = stbuf.st_size;
d.type = 'U';
d.dev = c->dev;
n = convD2M(&d, (char*)va+i, count-i);
if(n == BIT16SZ){
strcpy(uif->nextname, de);
break;
}
i += n;
}
/*print("got %d\n", i);*/
uif->offset += i;
return i;
}
static int
fsomode(int m)
{
switch(m) {
case 0: /* OREAD */
case 3: /* OEXEC */
return 0;
case 1: /* OWRITE */
return 1;
case 2: /* ORDWR */
return 2;
}
error(Ebadarg);
return 0;
}
Dev fsdevtab = {
'U',
"fs",
devreset,
devinit,
devshutdown,
fsattach,
fswalk,
fsstat,
fsopen,
fscreate,
fsclose,
fsread,
devbread,
fswrite,
devbwrite,
fsremove,
fswstat,
};

209
kern/devip-posix.c Normal file
View File

@ -0,0 +1,209 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
#include "devip.h"
#undef listen
#undef accept
#undef bind
void
osipinit(void)
{
char buf[1024];
gethostname(buf, sizeof(buf));
kstrdup(&sysname, buf);
}
int
so_socket(int type)
{
int fd, one;
switch(type) {
default:
error("bad protocol type");
case S_TCP:
type = SOCK_STREAM;
break;
case S_UDP:
type = SOCK_DGRAM;
break;
}
fd = socket(AF_INET, type, 0);
if(fd < 0)
oserror();
one = 1;
if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one)) > 0){
oserrstr();
print("setsockopt: %r");
}
return fd;
}
void
so_connect(int fd, unsigned long raddr, unsigned short rport)
{
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
hnputs(&sin.sin_port, rport);
hnputl(&sin.sin_addr.s_addr, raddr);
if(connect(fd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
oserror();
}
void
so_getsockname(int fd, unsigned long *laddr, unsigned short *lport)
{
int len;
struct sockaddr_in sin;
len = sizeof(sin);
if(getsockname(fd, (struct sockaddr*)&sin, &len) < 0)
oserror();
if(sin.sin_family != AF_INET || len != sizeof(sin))
error("not AF_INET");
*laddr = nhgetl(&sin.sin_addr.s_addr);
*lport = nhgets(&sin.sin_port);
}
void
so_listen(int fd)
{
if(listen(fd, 5) < 0)
oserror();
}
int
so_accept(int fd, unsigned long *raddr, unsigned short *rport)
{
int nfd, len;
struct sockaddr_in sin;
len = sizeof(sin);
nfd = accept(fd, (struct sockaddr*)&sin, &len);
if(nfd < 0)
oserror();
if(sin.sin_family != AF_INET || len != sizeof(sin))
error("not AF_INET");
*raddr = nhgetl(&sin.sin_addr.s_addr);
*rport = nhgets(&sin.sin_port);
return nfd;
}
void
so_bind(int fd, int su, unsigned short port)
{
int i, one;
struct sockaddr_in sin;
one = 1;
if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one)) < 0){
oserrstr();
print("setsockopt: %r");
}
if(su) {
for(i = 600; i < 1024; i++) {
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = i;
if(bind(fd, (struct sockaddr*)&sin, sizeof(sin)) >= 0)
return;
}
oserror();
}
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
hnputs(&sin.sin_port, port);
if(bind(fd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
oserror();
}
int
so_gethostbyname(char *host, char**hostv, int n)
{
int i;
char buf[32];
unsigned char *p;
struct hostent *hp;
hp = gethostbyname(host);
if(hp == 0)
return 0;
for(i = 0; hp->h_addr_list[i] && i < n; i++) {
p = (unsigned char*)hp->h_addr_list[i];
sprint(buf, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
hostv[i] = strdup(buf);
if(hostv[i] == 0)
break;
}
return i;
}
char*
hostlookup(char *host)
{
char buf[100];
uchar *p;
struct hostent *he;
he = gethostbyname(host);
if(he != 0 && he->h_addr_list[0]) {
p = (uchar*)he->h_addr_list[0];
sprint(buf, "%ud.%ud.%ud.%ud", p[0], p[1], p[2], p[3]);
} else
strcpy(buf, host);
return strdup(buf);
}
int
so_getservbyname(char *service, char *net, char *port)
{
struct servent *s;
s = getservbyname(service, net);
if(s == 0)
return -1;
sprint(port, "%d", nhgets(&s->s_port));
return 0;
}
int
so_send(int fd, void *d, int n, int f)
{
send(fd, d, n, f);
}
int
so_recv(int fd, void *d, int n, int f)
{
return recv(fd, d, n, f);
}

208
kern/devip-win.c Normal file
View File

@ -0,0 +1,208 @@
#include <windows.h>
#include "winduhz.h"
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
#include "devip.h"
#pragma comment(lib, "wsock32.lib")
#undef listen
#undef accept
#undef bind
void
osipinit(void)
{
WSADATA wasdat;
char buf[1024];
if(WSAStartup(MAKEWORD(1, 1), &wasdat) != 0)
panic("no winsock.dll");
gethostname(buf, sizeof(buf));
kstrdup(&sysname, buf);
}
int
so_socket(int type)
{
int fd, one;
switch(type) {
default:
error("bad protocol type");
case S_TCP:
type = SOCK_STREAM;
break;
case S_UDP:
type = SOCK_DGRAM;
break;
}
fd = socket(AF_INET, type, 0);
if(fd < 0)
error(sys_errlist[errno]);
one = 1;
if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one)) > 0)
print("setsockopt: %s", sys_errlist[errno]);
return fd;
}
void
so_connect(int fd, unsigned long raddr, unsigned short rport)
{
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
hnputs(&sin.sin_port, rport);
hnputl(&sin.sin_addr.s_addr, raddr);
if(connect(fd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
error(sys_errlist[errno]);
}
void
so_getsockname(int fd, unsigned long *laddr, unsigned short *lport)
{
int len;
struct sockaddr_in sin;
len = sizeof(sin);
if(getsockname(fd, (struct sockaddr*)&sin, &len) < 0)
error(sys_errlist[errno]);
if(sin.sin_family != AF_INET || len != sizeof(sin))
error("not AF_INET");
*laddr = nhgetl(&sin.sin_addr.s_addr);
*lport = nhgets(&sin.sin_port);
}
void
so_listen(int fd)
{
if(listen(fd, 5) < 0)
error(sys_errlist[errno]);
}
int
so_accept(int fd, unsigned long *raddr, unsigned short *rport)
{
int nfd, len;
struct sockaddr_in sin;
len = sizeof(sin);
nfd = accept(fd, (struct sockaddr*)&sin, &len);
if(nfd < 0)
error(sys_errlist[errno]);
if(sin.sin_family != AF_INET || len != sizeof(sin))
error("not AF_INET");
*raddr = nhgetl(&sin.sin_addr.s_addr);
*rport = nhgets(&sin.sin_port);
return nfd;
}
void
so_bind(int fd, int su, unsigned short port)
{
int i, one;
struct sockaddr_in sin;
one = 1;
if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one)) < 0)
print("setsockopt: %s", sys_errlist[errno]);
if(su) {
for(i = 600; i < 1024; i++) {
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = i;
if(bind(fd, (struct sockaddr*)&sin, sizeof(sin)) >= 0)
return;
}
error(sys_errlist[errno]);
}
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
hnputs(&sin.sin_port, port);
if(bind(fd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
error(sys_errlist[errno]);
}
int
so_gethostbyname(char *host, char**hostv, int n)
{
int i;
char buf[32];
unsigned char *p;
struct hostent *hp;
hp = gethostbyname(host);
if(hp == 0)
return 0;
for(i = 0; hp->h_addr_list[i] && i < n; i++) {
p = (unsigned char*)hp->h_addr_list[i];
sprint(buf, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
hostv[i] = strdup(buf);
if(hostv[i] == 0)
break;
}
return i;
}
char*
hostlookup(char *host)
{
char buf[100];
uchar *p;
HOSTENT *he;
he = gethostbyname(host);
if(he != 0 && he->h_addr_list[0]) {
p = he->h_addr_list[0];
sprint(buf, "%ud.%ud.%ud.%ud", p[0], p[1], p[2], p[3]);
} else
strcpy(buf, host);
return strdup(buf);
}
int
so_getservbyname(char *service, char *net, char *port)
{
struct servent *s;
s = getservbyname(service, net);
if(s == 0)
return -1;
sprint(port, "%d", nhgets(&s->s_port));
return 0;
}
int
so_send(int fd, void *d, int n, int f)
{
return send(fd, d, n, f);
}
int
so_recv(int fd, void *d, int n, int f)
{
return recv(fd, d, n, f);
}

936
kern/devip.c Normal file
View File

@ -0,0 +1,936 @@
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
#include "devip.h"
void hnputl(void *p, unsigned long v);
void hnputs(void *p, unsigned short v);
unsigned long nhgetl(void *p);
unsigned short nhgets(void *p);
unsigned long parseip(char *to, char *from);
void csclose(Chan*);
long csread(Chan*, void*, long, vlong);
long cswrite(Chan*, void*, long, vlong);
void osipinit(void);
enum
{
Qtopdir = 1, /* top level directory */
Qcs,
Qprotodir, /* directory for a protocol */
Qclonus,
Qconvdir, /* directory for a conversation */
Qdata,
Qctl,
Qstatus,
Qremote,
Qlocal,
Qlisten,
MAXPROTO = 4
};
#define TYPE(x) ((int)((x).path & 0xf))
#define CONV(x) ((int)(((x).path >> 4)&0xfff))
#define PROTO(x) ((int)(((x).path >> 16)&0xff))
#define QID(p, c, y) (((p)<<16) | ((c)<<4) | (y))
typedef struct Proto Proto;
typedef struct Conv Conv;
struct Conv
{
int x;
Ref r;
int sfd;
int perm;
char owner[KNAMELEN];
char* state;
ulong laddr;
ushort lport;
ulong raddr;
ushort rport;
int restricted;
char cerr[KNAMELEN];
Proto* p;
};
struct Proto
{
Lock l;
int x;
int stype;
char name[KNAMELEN];
int nc;
int maxconv;
Conv** conv;
Qid qid;
};
static int np;
static Proto proto[MAXPROTO];
int eipfmt(Fmt*);
static Conv* protoclone(Proto*, char*, int);
static void setladdr(Conv*);
int
ipgen(Chan *c, char *nname, Dirtab *d, int nd, int s, Dir *dp)
{
Qid q;
Conv *cv;
char *p;
USED(nname);
q.vers = 0;
q.type = 0;
switch(TYPE(c->qid)) {
case Qtopdir:
if(s >= 1+np)
return -1;
if(s == 0){
q.path = QID(s, 0, Qcs);
devdir(c, q, "cs", 0, "network", 0666, dp);
}else{
s--;
q.path = QID(s, 0, Qprotodir);
q.type = QTDIR;
devdir(c, q, proto[s].name, 0, "network", DMDIR|0555, dp);
}
return 1;
case Qprotodir:
if(s < proto[PROTO(c->qid)].nc) {
cv = proto[PROTO(c->qid)].conv[s];
sprint(up->genbuf, "%d", s);
q.path = QID(PROTO(c->qid), s, Qconvdir);
q.type = QTDIR;
devdir(c, q, up->genbuf, 0, cv->owner, DMDIR|0555, dp);
return 1;
}
s -= proto[PROTO(c->qid)].nc;
switch(s) {
default:
return -1;
case 0:
p = "clone";
q.path = QID(PROTO(c->qid), 0, Qclonus);
break;
}
devdir(c, q, p, 0, "network", 0555, dp);
return 1;
case Qconvdir:
cv = proto[PROTO(c->qid)].conv[CONV(c->qid)];
switch(s) {
default:
return -1;
case 0:
q.path = QID(PROTO(c->qid), CONV(c->qid), Qdata);
devdir(c, q, "data", 0, cv->owner, cv->perm, dp);
return 1;
case 1:
q.path = QID(PROTO(c->qid), CONV(c->qid), Qctl);
devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp);
return 1;
case 2:
p = "status";
q.path = QID(PROTO(c->qid), CONV(c->qid), Qstatus);
break;
case 3:
p = "remote";
q.path = QID(PROTO(c->qid), CONV(c->qid), Qremote);
break;
case 4:
p = "local";
q.path = QID(PROTO(c->qid), CONV(c->qid), Qlocal);
break;
case 5:
p = "listen";
q.path = QID(PROTO(c->qid), CONV(c->qid), Qlisten);
break;
}
devdir(c, q, p, 0, cv->owner, 0444, dp);
return 1;
}
return -1;
}
static void
newproto(char *name, int type, int maxconv)
{
int l;
Proto *p;
if(np >= MAXPROTO) {
print("no %s: increase MAXPROTO", name);
return;
}
p = &proto[np];
strcpy(p->name, name);
p->stype = type;
p->qid.path = QID(np, 0, Qprotodir);
p->qid.type = QTDIR;
p->x = np++;
p->maxconv = maxconv;
l = sizeof(Conv*)*(p->maxconv+1);
p->conv = mallocz(l, 1);
if(p->conv == 0)
panic("no memory");
}
void
ipinit(void)
{
osipinit();
newproto("udp", S_UDP, 10);
newproto("tcp", S_TCP, 30);
fmtinstall('I', eipfmt);
fmtinstall('E', eipfmt);
}
Chan *
ipattach(char *spec)
{
Chan *c;
c = devattach('I', spec);
c->qid.path = QID(0, 0, Qtopdir);
c->qid.type = QTDIR;
c->qid.vers = 0;
return c;
}
static Walkqid*
ipwalk(Chan *c, Chan *nc, char **name, int nname)
{
return devwalk(c, nc, name, nname, 0, 0, ipgen);
}
int
ipstat(Chan *c, uchar *dp, int n)
{
return devstat(c, dp, n, 0, 0, ipgen);
}
Chan *
ipopen(Chan *c, int omode)
{
Proto *p;
ulong raddr;
ushort rport;
int perm, sfd;
Conv *cv, *lcv;
omode &= 3;
switch(omode) {
case OREAD:
perm = 4;
break;
case OWRITE:
perm = 2;
break;
case ORDWR:
perm = 6;
break;
}
switch(TYPE(c->qid)) {
default:
break;
case Qtopdir:
case Qprotodir:
case Qconvdir:
case Qstatus:
case Qremote:
case Qlocal:
if(omode != OREAD)
error(Eperm);
break;
case Qclonus:
p = &proto[PROTO(c->qid)];
cv = protoclone(p, up->user, -1);
if(cv == 0)
error(Enodev);
c->qid.path = QID(p->x, cv->x, Qctl);
c->qid.vers = 0;
break;
case Qdata:
case Qctl:
p = &proto[PROTO(c->qid)];
lock(&p->l);
cv = p->conv[CONV(c->qid)];
lock(&cv->r.lk);
if((perm & (cv->perm>>6)) != perm) {
if(strcmp(up->user, cv->owner) != 0 ||
(perm & cv->perm) != perm) {
unlock(&cv->r.lk);
unlock(&p->l);
error(Eperm);
}
}
cv->r.ref++;
if(cv->r.ref == 1) {
memmove(cv->owner, up->user, KNAMELEN);
cv->perm = 0660;
}
unlock(&cv->r.lk);
unlock(&p->l);
break;
case Qlisten:
p = &proto[PROTO(c->qid)];
lcv = p->conv[CONV(c->qid)];
sfd = so_accept(lcv->sfd, &raddr, &rport);
cv = protoclone(p, up->user, sfd);
if(cv == 0) {
close(sfd);
error(Enodev);
}
cv->raddr = raddr;
cv->rport = rport;
setladdr(cv);
cv->state = "Established";
c->qid.path = QID(p->x, cv->x, Qctl);
break;
}
c->mode = openmode(omode);
c->flag |= COPEN;
c->offset = 0;
return c;
}
void
ipclose(Chan *c)
{
Conv *cc;
switch(TYPE(c->qid)) {
case Qcs:
csclose(c);
break;
case Qdata:
case Qctl:
if((c->flag & COPEN) == 0)
break;
cc = proto[PROTO(c->qid)].conv[CONV(c->qid)];
if(decref(&cc->r) != 0)
break;
strcpy(cc->owner, "network");
cc->perm = 0666;
cc->state = "Closed";
cc->laddr = 0;
cc->raddr = 0;
cc->lport = 0;
cc->rport = 0;
close(cc->sfd);
break;
}
}
long
ipread(Chan *ch, void *a, long n, vlong offset)
{
int r;
Conv *c;
Proto *x;
uchar ip[4];
char buf[128], *p;
/*print("ipread %s %lux\n", c2name(ch), (long)ch->qid.path);*/
p = a;
switch(TYPE(ch->qid)) {
default:
error(Eperm);
case Qcs:
return csread(ch, a, n, offset);
case Qprotodir:
case Qtopdir:
case Qconvdir:
return devdirread(ch, a, n, 0, 0, ipgen);
case Qctl:
sprint(buf, "%d", CONV(ch->qid));
return readstr(offset, p, n, buf);
case Qremote:
c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)];
hnputl(ip, c->raddr);
sprint(buf, "%I!%d\n", ip, c->rport);
return readstr(offset, p, n, buf);
case Qlocal:
c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)];
hnputl(ip, c->laddr);
sprint(buf, "%I!%d\n", ip, c->lport);
return readstr(offset, p, n, buf);
case Qstatus:
x = &proto[PROTO(ch->qid)];
c = x->conv[CONV(ch->qid)];
sprint(buf, "%s/%d %d %s \n",
c->p->name, c->x, c->r.ref, c->state);
return readstr(offset, p, n, buf);
case Qdata:
c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)];
r = so_recv(c->sfd, a, n, 0);
if(r < 0){
oserrstr();
nexterror();
}
return r;
}
}
static void
setladdr(Conv *c)
{
so_getsockname(c->sfd, &c->laddr, &c->lport);
}
static void
setlport(Conv *c)
{
if(c->restricted == 0 && c->lport == 0)
return;
so_bind(c->sfd, c->restricted, c->lport);
}
static void
setladdrport(Conv *c, char *str)
{
char *p, addr[4];
p = strchr(str, '!');
if(p == 0) {
p = str;
c->laddr = 0;
}
else {
*p++ = 0;
parseip(addr, str);
c->laddr = nhgetl((uchar*)addr);
}
if(*p == '*')
c->lport = 0;
else
c->lport = atoi(p);
setlport(c);
}
static char*
setraddrport(Conv *c, char *str)
{
char *p, addr[4];
p = strchr(str, '!');
if(p == 0)
return "malformed address";
*p++ = 0;
parseip(addr, str);
c->raddr = nhgetl((uchar*)addr);
c->rport = atoi(p);
p = strchr(p, '!');
if(p) {
if(strcmp(p, "!r") == 0)
c->restricted = 1;
}
return 0;
}
long
ipwrite(Chan *ch, void *a, long n, vlong offset)
{
Conv *c;
Proto *x;
int r, nf;
char *p, *fields[3], buf[128];
switch(TYPE(ch->qid)) {
default:
error(Eperm);
case Qcs:
return cswrite(ch, a, n, offset);
case Qctl:
x = &proto[PROTO(ch->qid)];
c = x->conv[CONV(ch->qid)];
if(n > sizeof(buf)-1)
n = sizeof(buf)-1;
memmove(buf, a, n);
buf[n] = '\0';
nf = tokenize(buf, fields, 3);
if(strcmp(fields[0], "connect") == 0){
switch(nf) {
default:
error("bad args to connect");
case 2:
p = setraddrport(c, fields[1]);
if(p != 0)
error(p);
break;
case 3:
p = setraddrport(c, fields[1]);
if(p != 0)
error(p);
c->lport = atoi(fields[2]);
setlport(c);
break;
}
so_connect(c->sfd, c->raddr, c->rport);
setladdr(c);
c->state = "Established";
return n;
}
if(strcmp(fields[0], "announce") == 0) {
switch(nf){
default:
error("bad args to announce");
case 2:
setladdrport(c, fields[1]);
break;
}
so_listen(c->sfd);
c->state = "Announced";
return n;
}
if(strcmp(fields[0], "bind") == 0){
switch(nf){
default:
error("bad args to bind");
case 2:
c->lport = atoi(fields[1]);
break;
}
setlport(c);
return n;
}
error("bad control message");
case Qdata:
x = &proto[PROTO(ch->qid)];
c = x->conv[CONV(ch->qid)];
r = so_send(c->sfd, a, n, 0);
if(r < 0){
oserrstr();
nexterror();
}
return r;
}
return n;
}
static Conv*
protoclone(Proto *p, char *user, int nfd)
{
Conv *c, **pp, **ep;
c = 0;
lock(&p->l);
if(waserror()) {
unlock(&p->l);
nexterror();
}
ep = &p->conv[p->maxconv];
for(pp = p->conv; pp < ep; pp++) {
c = *pp;
if(c == 0) {
c = mallocz(sizeof(Conv), 1);
if(c == 0)
error(Enomem);
lock(&c->r.lk);
c->r.ref = 1;
c->p = p;
c->x = pp - p->conv;
p->nc++;
*pp = c;
break;
}
lock(&c->r.lk);
if(c->r.ref == 0) {
c->r.ref++;
break;
}
unlock(&c->r.lk);
}
if(pp >= ep) {
unlock(&p->l);
poperror();
return 0;
}
strcpy(c->owner, user);
c->perm = 0660;
c->state = "Closed";
c->restricted = 0;
c->laddr = 0;
c->raddr = 0;
c->lport = 0;
c->rport = 0;
c->sfd = nfd;
if(nfd == -1)
c->sfd = so_socket(p->stype);
unlock(&c->r.lk);
unlock(&p->l);
poperror();
return c;
}
enum
{
Isprefix= 16,
};
uchar prefixvals[256] =
{
/*0x00*/ 0 | Isprefix,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/*0x10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/*0x20*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/*0x30*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/*0x40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/*0x50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/*0x60*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/*0x70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/*0x80*/ 1 | Isprefix,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/*0x90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/*0xA0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/*0xB0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/*0xC0*/ 2 | Isprefix,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/*0xD0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/*0xE0*/ 3 | Isprefix,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/*0xF0*/ 4 | Isprefix,
0, 0, 0, 0, 0, 0, 0,
/*0xF8*/ 5 | Isprefix,
0, 0, 0,
/*0xFC*/ 6 | Isprefix,
0,
/*0xFE*/ 7 | Isprefix,
/*0xFF*/ 8 | Isprefix,
};
int
eipfmt(Fmt *f)
{
char buf[5*8];
static char *efmt = "%.2lux%.2lux%.2lux%.2lux%.2lux%.2lux";
static char *ifmt = "%d.%d.%d.%d";
uchar *p, ip[16];
ulong *lp;
ushort s;
int i, j, n, eln, eli;
ulong ul;
switch(f->r) {
case 'E': /* Ethernet address */
p = va_arg(f->args, uchar*);
snprint(buf, sizeof buf, efmt, p[0], p[1], p[2], p[3], p[4], p[5]);
return fmtstrcpy(f, buf);
case 'I':
ul = va_arg(f->args, ulong);
hnputl(ip, ul);
snprint(buf, sizeof buf, ifmt, ip[0], ip[1], ip[2], ip[3]);
return fmtstrcpy(f, buf);
}
return fmtstrcpy(f, "(eipfmt)");
}
void
hnputl(void *p, unsigned long v)
{
unsigned char *a;
a = p;
a[0] = v>>24;
a[1] = v>>16;
a[2] = v>>8;
a[3] = v;
}
void
hnputs(void *p, unsigned short v)
{
unsigned char *a;
a = p;
a[0] = v>>8;
a[1] = v;
}
unsigned long
nhgetl(void *p)
{
unsigned char *a;
a = p;
return (a[0]<<24)|(a[1]<<16)|(a[2]<<8)|(a[3]<<0);
}
unsigned short
nhgets(void *p)
{
unsigned char *a;
a = p;
return (a[0]<<8)|(a[1]<<0);
}
#define CLASS(p) ((*(unsigned char*)(p))>>6)
unsigned long
parseip(char *to, char *from)
{
int i;
char *p;
p = from;
memset(to, 0, 4);
for(i = 0; i < 4 && *p; i++){
to[i] = strtoul(p, &p, 0);
if(*p == '.')
p++;
}
switch(CLASS(to)){
case 0: /* class A - 1 byte net */
case 1:
if(i == 3){
to[3] = to[2];
to[2] = to[1];
to[1] = 0;
} else if (i == 2){
to[3] = to[1];
to[1] = 0;
}
break;
case 2: /* class B - 2 byte net */
if(i == 3){
to[3] = to[2];
to[2] = 0;
}
break;
}
return nhgetl(to);
}
void
csclose(Chan *c)
{
free(c->aux);
}
long
csread(Chan *c, void *a, long n, vlong offset)
{
if(c->aux == nil)
return 0;
return readstr(offset, a, n, c->aux);
}
static struct
{
char *name;
uint num;
} tab[] = {
"cs", 1,
"echo", 7,
"discard", 9,
"systat", 11,
"daytime", 13,
"netstat", 15,
"chargen", 19,
"ftp-data", 20,
"ftp", 21,
"ssh", 22,
"telnet", 23,
"smtp", 25,
"time", 37,
"whois", 43,
"dns", 53,
"domain", 53,
"uucp", 64,
"gopher", 70,
"rje", 77,
"finger", 79,
"http", 80,
"link", 87,
"supdup", 95,
"hostnames", 101,
"iso-tsap", 102,
"x400", 103,
"x400-snd", 104,
"csnet-ns", 105,
"pop-2", 109,
"pop3", 110,
"portmap", 111,
"uucp-path", 117,
"nntp", 119,
"netbios", 139,
"imap4", 143,
"NeWS", 144,
"print-srv", 170,
"z39.50", 210,
"fsb", 400,
"sysmon", 401,
"proxy", 402,
"proxyd", 404,
"https", 443,
"cifs", 445,
"ssmtp", 465,
"rexec", 512,
"login", 513,
"shell", 514,
"printer", 515,
"courier", 530,
"cscan", 531,
"uucp", 540,
"snntp", 563,
"9fs", 564,
"whoami", 565,
"guard", 566,
"ticket", 567,
"dlsftp", 666,
"fmclient", 729,
"imaps", 993,
"pop3s", 995,
"ingreslock", 1524,
"pptp", 1723,
"nfs", 2049,
"webster", 2627,
"weather", 3000,
"secstore", 5356,
"Xdisplay", 6000,
"styx", 6666,
"mpeg", 6667,
"rstyx", 6668,
"infdb", 6669,
"infsigner", 6671,
"infcsigner", 6672,
"inflogin", 6673,
"bandt", 7330,
"face", 32000,
"dhashgate", 11978,
"exportfs", 17007,
"rexexec", 17009,
"ncpu", 17010,
"cpu", 17013,
"glenglenda1", 17020,
"glenglenda2", 17021,
"glenglenda3", 17022,
"glenglenda4", 17023,
"glenglenda5", 17024,
"glenglenda6", 17025,
"glenglenda7", 17026,
"glenglenda8", 17027,
"glenglenda9", 17028,
"glenglenda10", 17029,
"flyboy", 17032,
"dlsftp", 17033,
"venti", 17034,
"wiki", 17035,
"vica", 17036,
0
};
static int
lookupport(char *s)
{
int i;
char buf[10], *p;
i = strtol(s, &p, 0);
if(*s && *p == 0)
return i;
i = so_getservbyname(s, "tcp", buf);
if(i != -1)
return atoi(buf);
for(i=0; tab[i].name; i++)
if(strcmp(s, tab[i].name) == 0)
return tab[i].num;
return 0;
}
static ulong
lookuphost(char *s)
{
char to[4];
ulong ip;
memset(to, 0, sizeof to);
parseip(to, s);
ip = nhgetl(to);
if(ip != 0)
return ip;
if((s = hostlookup(s)) == nil)
return 0;
parseip(to, s);
ip = nhgetl(to);
free(s);
return ip;
}
long
cswrite(Chan *c, void *a, long n, vlong offset)
{
char *f[4];
char *s, *ns;
ulong ip;
int nf, port;
s = malloc(n+1);
if(s == nil)
error(Enomem);
if(waserror()){
free(s);
nexterror();
}
memmove(s, a, n);
s[n] = 0;
nf = getfields(s, f, nelem(f), 0, "!");
if(nf != 3)
error("can't translate");
port = lookupport(f[2]);
if(port <= 0)
error("no translation for port found");
ip = lookuphost(f[1]);
if(ip == 0)
error("no translation for host found");
ns = smprint("/net/%s/clone %I!%d", f[0], ip, port);
if(ns == nil)
error(Enomem);
free(c->aux);
c->aux = ns;
poperror();
free(s);
return n;
}
Dev ipdevtab =
{
'I',
"ip",
devreset,
ipinit,
devshutdown,
ipattach,
ipwalk,
ipstat,
ipopen,
devcreate,
ipclose,
ipread,
devbread,
ipwrite,
devbwrite,
devremove,
devwstat,
};

17
kern/devip.h Normal file
View File

@ -0,0 +1,17 @@
enum
{
S_TCP,
S_UDP
};
int so_socket(int type);
void so_connect(int, unsigned long, unsigned short);
void so_getsockname(int, unsigned long*, unsigned short*);
void so_bind(int, int, unsigned short);
void so_listen(int);
int so_accept(int, unsigned long*, unsigned short*);
int so_getservbyname(char*, char*, char*);
int so_gethostbyname(char*, char**, int);
char* hostlookup(char*);

1214
kern/devmnt.c Normal file

File diff suppressed because it is too large Load Diff

237
kern/devmouse.c Normal file
View File

@ -0,0 +1,237 @@
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
#include "draw.h"
#include "memdraw.h"
#include "screen.h"
int mousequeue;
Mouseinfo mouse;
Cursorinfo cursor;
static int mousechanged(void*);
enum{
Qdir,
Qcursor,
Qmouse
};
Dirtab mousedir[]={
".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
"cursor", {Qcursor}, 0, 0666,
"mouse", {Qmouse}, 0, 0666,
};
#define NMOUSE (sizeof(mousedir)/sizeof(Dirtab))
static Chan*
mouseattach(char *spec)
{
return devattach('m', spec);
}
static Walkqid*
mousewalk(Chan *c, Chan *nc, char **name, int nname)
{
return devwalk(c, nc, name, nname, mousedir, NMOUSE, devgen);
}
static int
mousestat(Chan *c, uchar *db, int n)
{
return devstat(c, db, n, mousedir, NMOUSE, devgen);
}
static Chan*
mouseopen(Chan *c, int omode)
{
switch((long)c->qid.path){
case Qdir:
if(omode != OREAD)
error(Eperm);
break;
case Qmouse:
lock(&mouse.lk);
if(mouse.open){
unlock(&mouse.lk);
error(Einuse);
}
mouse.open = 1;
unlock(&mouse.lk);
break;
}
c->mode = openmode(omode);
c->flag |= COPEN;
c->offset = 0;
return c;
}
void
mouseclose(Chan *c)
{
if(!(c->flag&COPEN))
return;
switch((long)c->qid.path) {
case Qmouse:
lock(&mouse.lk);
mouse.open = 0;
unlock(&mouse.lk);
cursorarrow();
}
}
long
mouseread(Chan *c, void *va, long n, vlong offset)
{
char buf[4*12+1];
uchar *p;
int i, nn;
ulong msec;
/* static int map[8] = {0, 4, 2, 6, 1, 5, 3, 7 }; */
p = va;
switch((long)c->qid.path){
case Qdir:
return devdirread(c, va, n, mousedir, NMOUSE, devgen);
case Qcursor:
if(offset != 0)
return 0;
if(n < 2*4+2*2*16)
error(Eshort);
n = 2*4+2*2*16;
lock(&cursor.lk);
BPLONG(p+0, cursor.offset.x);
BPLONG(p+4, cursor.offset.y);
memmove(p+8, cursor.clr, 2*16);
memmove(p+40, cursor.set, 2*16);
unlock(&cursor.lk);
return n;
case Qmouse:
while(mousechanged(0) == 0)
sleep(&mouse.r, mousechanged, 0);
lock(&screen.lk);
if(screen.reshaped) {
screen.reshaped = 0;
sprint(buf, "t%11d %11d", 0, ticks());
if(n > 1+2*12)
n = 1+2*12;
memmove(va, buf, n);
unlock(&screen.lk);
return n;
}
unlock(&screen.lk);
lock(&mouse.lk);
i = mouse.ri;
nn = (mouse.wi + Mousequeue - i) % Mousequeue;
if(nn < 1)
panic("empty mouse queue");
msec = ticks();
while(nn > 1) {
if(mouse.queue[i].msec + Mousewindow > msec)
break;
i = (i+1)%Mousequeue;
nn--;
}
sprint(buf, "m%11d %11d %11d %11d",
mouse.queue[i].xy.x,
mouse.queue[i].xy.y,
mouse.queue[i].buttons,
mouse.queue[i].msec);
mouse.ri = (i+1)%Mousequeue;
unlock(&mouse.lk);
if(n > 1+4*12)
n = 1+4*12;
memmove(va, buf, n);
return n;
}
return 0;
}
long
mousewrite(Chan *c, void *va, long n, vlong offset)
{
char *p;
Point pt;
char buf[64];
USED(offset);
p = va;
switch((long)c->qid.path){
case Qdir:
error(Eisdir);
case Qcursor:
if(n < 2*4+2*2*16){
cursorarrow();
}else{
n = 2*4+2*2*16;
lock(&cursor.lk);
cursor.offset.x = BGLONG(p+0);
cursor.offset.y = BGLONG(p+4);
memmove(cursor.clr, p+8, 2*16);
memmove(cursor.set, p+40, 2*16);
unlock(&cursor.lk);
setcursor();
}
return n;
case Qmouse:
if(n > sizeof buf-1)
n = sizeof buf -1;
memmove(buf, va, n);
buf[n] = 0;
p = 0;
pt.x = strtoul(buf+1, &p, 0);
if(p == 0)
error(Eshort);
pt.y = strtoul(p, 0, 0);
if(ptinrect(pt, gscreen->r))
mouseset(pt);
return n;
}
error(Egreg);
return -1;
}
int
mousechanged(void *a)
{
USED(a);
return mouse.ri != mouse.wi || screen.reshaped;
}
Dev mousedevtab = {
'm',
"mouse",
devreset,
devinit,
devshutdown,
mouseattach,
mousewalk,
mousestat,
mouseopen,
devcreate,
mouseclose,
mouseread,
devbread,
mousewrite,
devbwrite,
devremove,
devwstat,
};

704
kern/devntfs.c Normal file
View File

@ -0,0 +1,704 @@
#include <windows.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifndef NAME_MAX
# define NAME_MAX 256
#endif
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
typedef struct DIR DIR;
typedef struct Ufsinfo Ufsinfo;
enum
{
NUID = 256,
NGID = 256,
MAXPATH = 1024,
MAXCOMP = 128
};
struct DIR
{
HANDLE handle;
char* path;
int index;
WIN32_FIND_DATA wfd;
};
struct Ufsinfo
{
int mode;
int fd;
int uid;
int gid;
DIR* dir;
ulong offset;
QLock oq;
char nextname[NAME_MAX];
};
DIR* opendir(char*);
int readdir(char*, DIR*);
void closedir(DIR*);
void rewinddir(DIR*);
char *base = "c:/.";
static Qid fsqid(char*, struct stat *);
static void fspath(Chan*, char*, char*);
// static void fsperm(Chan*, int);
static ulong fsdirread(Chan*, uchar*, int, ulong);
static int fsomode(int);
static int chown(char *path, int uid, int);
static int link(char *path, char *next);
/* clumsy hack, but not worse than the Path stuff in the last one */
static char*
uc2name(Chan *c)
{
char *s;
if(c->name == nil)
return "/";
s = c2name(c);
if(s[0]=='#' && s[1]=='U')
return s+2;
return s;
}
static char*
lastelem(Chan *c)
{
char *s, *t;
s = uc2name(c);
if((t = strrchr(s, '/')) == nil)
return s;
if(t[1] == 0)
return t;
return t+1;
}
static Chan*
fsattach(void *spec)
{
Chan *c;
struct stat stbuf;
static int devno;
Ufsinfo *uif;
if(stat(base, &stbuf) < 0)
error(strerror(errno));
c = devattach('U', spec);
uif = mallocz(sizeof(Ufsinfo), 1);
uif->gid = stbuf.st_gid;
uif->uid = stbuf.st_uid;
uif->mode = stbuf.st_mode;
c->aux = uif;
c->dev = devno++;
c->qid.type = QTDIR;
/*print("fsattach %s\n", c2name(c));*/
return c;
}
static Chan*
fsclone(Chan *c, Chan *nc)
{
Ufsinfo *uif;
uif = mallocz(sizeof(Ufsinfo), 1);
*uif = *(Ufsinfo*)c->aux;
nc->aux = uif;
return nc;
}
static int
fswalk1(Chan *c, char *name)
{
struct stat stbuf;
char path[MAXPATH];
Ufsinfo *uif;
fspath(c, name, path);
/* print("** fs walk '%s' -> %s\n", path, name); /**/
if(stat(path, &stbuf) < 0)
return 0;
uif = c->aux;
uif->gid = stbuf.st_gid;
uif->uid = stbuf.st_uid;
uif->mode = stbuf.st_mode;
c->qid = fsqid(path, &stbuf);
return 1;
}
extern Cname* addelem(Cname*, char*);
static Walkqid*
fswalk(Chan *c, Chan *nc, char **name, int nname)
{
int i;
Cname *cname;
Walkqid *wq;
if(nc != nil)
panic("fswalk: nc != nil");
wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
nc = devclone(c);
cname = c->name;
incref(&cname->ref);
fsclone(c, nc);
wq->clone = nc;
for(i=0; i<nname; i++){
nc->name = cname;
if(fswalk1(nc, name[i]) == 0)
break;
cname = addelem(cname, name[i]);
wq->qid[i] = nc->qid;
}
nc->name = nil;
cnameclose(cname);
if(i != nname){
cclose(nc);
wq->clone = nil;
}
wq->nqid = i;
return wq;
}
static int
fsstat(Chan *c, uchar *buf, int n)
{
Dir d;
struct stat stbuf;
char path[MAXPATH];
if(n < BIT16SZ)
error(Eshortstat);
fspath(c, 0, path);
if(stat(path, &stbuf) < 0)
error(strerror(errno));
d.name = lastelem(c);
d.uid = "unknown";
d.gid = "unknown";
d.muid = "unknown";
d.qid = c->qid;
d.mode = (c->qid.type<<24)|(stbuf.st_mode&0777);
d.atime = stbuf.st_atime;
d.mtime = stbuf.st_mtime;
d.length = stbuf.st_size;
d.type = 'U';
d.dev = c->dev;
return convD2M(&d, buf, n);
}
static Chan*
fsopen(Chan *c, int mode)
{
char path[MAXPATH];
int m, isdir;
Ufsinfo *uif;
/*print("fsopen %s\n", c2name(c));*/
m = mode & (OTRUNC|3);
switch(m) {
case 0:
break;
case 1:
case 1|16:
break;
case 2:
case 0|16:
case 2|16:
break;
case 3:
break;
default:
error(Ebadarg);
}
isdir = c->qid.type & QTDIR;
if(isdir && mode != OREAD)
error(Eperm);
m = fsomode(m & 3);
c->mode = openmode(mode);
uif = c->aux;
fspath(c, 0, path);
if(isdir) {
uif->dir = opendir(path);
if(uif->dir == 0)
error(strerror(errno));
}
else {
if(mode & OTRUNC)
m |= O_TRUNC;
uif->fd = open(path, m|_O_BINARY, 0666);
if(uif->fd < 0)
error(strerror(errno));
}
uif->offset = 0;
c->offset = 0;
c->flag |= COPEN;
return c;
}
static void
fscreate(Chan *c, char *name, int mode, ulong perm)
{
int fd, m;
char path[MAXPATH];
struct stat stbuf;
Ufsinfo *uif;
m = fsomode(mode&3);
fspath(c, name, path);
uif = c->aux;
if(perm & DMDIR) {
if(m)
error(Eperm);
if(mkdir(path) < 0)
error(strerror(errno));
fd = open(path, 0);
if(fd >= 0) {
chmod(path, perm & 0777);
chown(path, uif->uid, uif->uid);
}
close(fd);
uif->dir = opendir(path);
if(uif->dir == 0)
error(strerror(errno));
}
else {
fd = open(path, _O_WRONLY|_O_BINARY|_O_CREAT|_O_TRUNC, 0666);
if(fd >= 0) {
if(m != 1) {
close(fd);
fd = open(path, m|_O_BINARY);
}
chmod(path, perm & 0777);
chown(path, uif->uid, uif->gid);
}
if(fd < 0)
error(strerror(errno));
uif->fd = fd;
}
if(stat(path, &stbuf) < 0)
error(strerror(errno));
c->qid = fsqid(path, &stbuf);
c->offset = 0;
c->flag |= COPEN;
c->mode = openmode(mode);
}
static void
fsclose(Chan *c)
{
Ufsinfo *uif;
uif = c->aux;
if(c->flag & COPEN) {
if(c->qid.type & QTDIR)
closedir(uif->dir);
else
close(uif->fd);
}
free(uif);
}
static long
fsread(Chan *c, void *va, long n, ulong offset)
{
int fd, r;
Ufsinfo *uif;
/*print("fsread %s\n", c2name(c));*/
if(c->qid.type & QTDIR)
return fsdirread(c, va, n, offset);
uif = c->aux;
qlock(&uif->oq);
if(waserror()) {
qunlock(&uif->oq);
nexterror();
}
fd = uif->fd;
if(uif->offset != offset) {
r = lseek(fd, offset, 0);
if(r < 0)
error(strerror(errno));
uif->offset = offset;
}
n = read(fd, va, n);
if(n < 0)
error(strerror(errno));
uif->offset += n;
qunlock(&uif->oq);
poperror();
return n;
}
static long
fswrite(Chan *c, void *va, long n, ulong offset)
{
int fd, r;
Ufsinfo *uif;
uif = c->aux;
qlock(&uif->oq);
if(waserror()) {
qunlock(&uif->oq);
nexterror();
}
fd = uif->fd;
if(uif->offset != offset) {
r = lseek(fd, offset, 0);
if(r < 0)
error(strerror(errno));
uif->offset = offset;
}
n = write(fd, va, n);
if(n < 0)
error(strerror(errno));
uif->offset += n;
qunlock(&uif->oq);
poperror();
return n;
}
static void
fsremove(Chan *c)
{
int n;
char path[MAXPATH];
fspath(c, 0, path);
if(c->qid.type & QTDIR)
n = rmdir(path);
else
n = remove(path);
if(n < 0)
error(strerror(errno));
}
static int
fswstat(Chan *c, uchar *buf, int n)
{
Dir d;
struct stat stbuf;
char old[MAXPATH], new[MAXPATH];
char strs[MAXPATH*3], *p;
Ufsinfo *uif;
if (convM2D(buf, n, &d, strs) != n)
error(Ebadstat);
fspath(c, 0, old);
if(stat(old, &stbuf) < 0)
error(strerror(errno));
uif = c->aux;
// if(uif->uid != stbuf.st_uid)
// error(Eowner);
if(d.name[0] && strcmp(d.name, lastelem(c)) != 0) {
fspath(c, 0, old);
strcpy(new, old);
p = strrchr(new, '/');
strcpy(p+1, d.name);
if(rename(old, new) < 0)
error(strerror(errno));
}
fspath(c, 0, old);
if(~d.mode != 0 && (int)(d.mode&0777) != (int)(stbuf.st_mode&0777)) {
if(chmod(old, d.mode&0777) < 0)
error(strerror(errno));
uif->mode &= ~0777;
uif->mode |= d.mode&0777;
}
/*
p = name2pass(gid, d.gid);
if(p == 0)
error(Eunknown);
if(p->id != stbuf.st_gid) {
if(chown(old, stbuf.st_uid, p->id) < 0)
error(sys_errlist[errno]);
uif->gid = p->id;
}
*/
return n;
}
static Qid
fsqid(char *p, struct stat *st)
{
Qid q;
int dev;
ulong h;
static int nqdev;
static uchar *qdev;
if(qdev == 0)
qdev = mallocz(65536U, 1);
q.type = 0;
if((st->st_mode&S_IFMT) == S_IFDIR)
q.type = QTDIR;
dev = st->st_dev & 0xFFFFUL;
if(qdev[dev] == 0)
qdev[dev] = ++nqdev;
h = 0;
while(*p != '\0')
h += *p++ * 13;
q.path = (vlong)qdev[dev]<<32;
q.path |= h;
q.vers = st->st_mtime;
return q;
}
static void
fspath(Chan *c, char *ext, char *path)
{
strcpy(path, base);
strcat(path, "/");
strcat(path, uc2name(c));
if(ext) {
strcat(path, "/");
strcat(path, ext);
}
cleanname(path);
}
static int
isdots(char *name)
{
if(name[0] != '.')
return 0;
if(name[1] == '\0')
return 1;
if(name[1] != '.')
return 0;
if(name[2] == '\0')
return 1;
return 0;
}
static int
p9readdir(char *name, Ufsinfo *uif)
{
if(uif->nextname[0]){
strcpy(name, uif->nextname);
uif->nextname[0] = 0;
return 1;
}
return readdir(name, uif->dir);
}
static ulong
fsdirread(Chan *c, uchar *va, int count, ulong offset)
{
int i;
Dir d;
long n;
char de[NAME_MAX];
struct stat stbuf;
char path[MAXPATH], dirpath[MAXPATH];
Ufsinfo *uif;
/*print("fsdirread %s\n", c2name(c));*/
i = 0;
uif = c->aux;
errno = 0;
if(uif->offset != offset) {
if(offset != 0)
error("bad offset in fsdirread");
uif->offset = offset; /* sync offset */
uif->nextname[0] = 0;
rewinddir(uif->dir);
}
fspath(c, 0, dirpath);
while(i+BIT16SZ < count) {
if(!p9readdir(de, uif))
break;
if(de[0]==0 || isdots(de))
continue;
d.name = de;
sprint(path, "%s/%s", dirpath, de);
memset(&stbuf, 0, sizeof stbuf);
if(stat(path, &stbuf) < 0) {
print("dir: bad path %s\n", path);
/* but continue... probably a bad symlink */
}
d.uid = "unknown";
d.gid = "unknown";
d.muid = "unknown";
d.qid = fsqid(path, &stbuf);
d.mode = (d.qid.type<<24)|(stbuf.st_mode&0777);
d.atime = stbuf.st_atime;
d.mtime = stbuf.st_mtime;
d.length = stbuf.st_size;
d.type = 'U';
d.dev = c->dev;
n = convD2M(&d, (char*)va+i, count-i);
if(n == BIT16SZ){
strcpy(uif->nextname, de);
break;
}
i += n;
}
/*print("got %d\n", i);*/
uif->offset += i;
return i;
}
static int
fsomode(int m)
{
switch(m) {
case 0: /* OREAD */
case 3: /* OEXEC */
return 0;
case 1: /* OWRITE */
return 1;
case 2: /* ORDWR */
return 2;
}
error(Ebadarg);
return 0;
}
void
closedir(DIR *d)
{
FindClose(d->handle);
free(d->path);
}
int
readdir(char *name, DIR *d)
{
if(d->index != 0) {
if(FindNextFile(d->handle, &d->wfd) == FALSE)
return 0;
}
strcpy(name, d->wfd.cFileName);
d->index++;
return 1;
}
void
rewinddir(DIR *d)
{
FindClose(d->handle);
d->handle = FindFirstFile(d->path, &d->wfd);
d->index = 0;
}
static int
chown(char *path, int uid, int perm)
{
/* panic("chown"); */
return 0;
}
DIR*
opendir(char *p)
{
DIR *d;
char path[MAX_PATH];
snprint(path, sizeof(path), "%s/*.*", p);
d = mallocz(sizeof(DIR), 1);
if(d == 0)
return 0;
d->index = 0;
d->handle = FindFirstFile(path, &d->wfd);
if(d->handle == INVALID_HANDLE_VALUE) {
free(d);
return 0;
}
d->path = strdup(path);
return d;
}
Dev fsdevtab = {
'U',
"fs",
devreset,
devinit,
devshutdown,
fsattach,
fswalk,
fsstat,
fsopen,
fscreate,
fsclose,
fsread,
devbread,
fswrite,
devbwrite,
fsremove,
fswstat,
};

398
kern/devpipe.c Normal file
View File

@ -0,0 +1,398 @@
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
#include "netif.h"
typedef struct Pipe Pipe;
struct Pipe
{
QLock lk;
Pipe *next;
int ref;
ulong path;
Queue *q[2];
int qref[2];
};
struct
{
Lock lk;
ulong path;
} pipealloc;
enum
{
Qdir,
Qdata0,
Qdata1,
};
Dirtab pipedir[] =
{
".", {Qdir,0,QTDIR}, 0, DMDIR|0500,
"data", {Qdata0}, 0, 0600,
"data1", {Qdata1}, 0, 0600,
};
#define NPIPEDIR 3
static void
pipeinit(void)
{
if(conf.pipeqsize == 0){
if(conf.nmach > 1)
conf.pipeqsize = 256*1024;
else
conf.pipeqsize = 32*1024;
}
}
/*
* create a pipe, no streams are created until an open
*/
static Chan*
pipeattach(char *spec)
{
Pipe *p;
Chan *c;
c = devattach('|', spec);
p = malloc(sizeof(Pipe));
if(p == 0)
exhausted("memory");
p->ref = 1;
p->q[0] = qopen(conf.pipeqsize, 0, 0, 0);
if(p->q[0] == 0){
free(p);
exhausted("memory");
}
p->q[1] = qopen(conf.pipeqsize, 0, 0, 0);
if(p->q[1] == 0){
free(p->q[0]);
free(p);
exhausted("memory");
}
lock(&pipealloc.lk);
p->path = ++pipealloc.path;
unlock(&pipealloc.lk);
mkqid(&c->qid, NETQID(2*p->path, Qdir), 0, QTDIR);
c->aux = p;
c->dev = 0;
return c;
}
static int
pipegen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp)
{
Qid q;
int len;
Pipe *p;
USED(name);
if(i == DEVDOTDOT){
devdir(c, c->qid, "#|", 0, eve, DMDIR|0555, dp);
return 1;
}
i++; /* skip . */
if(tab==0 || i>=ntab)
return -1;
tab += i;
p = c->aux;
switch((ulong)tab->qid.path){
case Qdata0:
len = qlen(p->q[0]);
break;
case Qdata1:
len = qlen(p->q[1]);
break;
default:
len = tab->length;
break;
}
mkqid(&q, NETQID(NETID(c->qid.path), tab->qid.path), 0, QTFILE);
devdir(c, q, tab->name, len, eve, tab->perm, dp);
return 1;
}
static Walkqid*
pipewalk(Chan *c, Chan *nc, char **name, int nname)
{
Walkqid *wq;
Pipe *p;
wq = devwalk(c, nc, name, nname, pipedir, NPIPEDIR, pipegen);
if(wq != nil && wq->clone != nil && wq->clone != c){
p = c->aux;
qlock(&p->lk);
p->ref++;
if(c->flag & COPEN){
print("channel open in pipewalk\n");
switch(NETTYPE(c->qid.path)){
case Qdata0:
p->qref[0]++;
break;
case Qdata1:
p->qref[1]++;
break;
}
}
qunlock(&p->lk);
}
return wq;
}
static int
pipestat(Chan *c, uchar *db, int n)
{
Pipe *p;
Dir dir;
p = c->aux;
switch(NETTYPE(c->qid.path)){
case Qdir:
devdir(c, c->qid, ".", 0, eve, DMDIR|0555, &dir);
break;
case Qdata0:
devdir(c, c->qid, "data", qlen(p->q[0]), eve, 0600, &dir);
break;
case Qdata1:
devdir(c, c->qid, "data1", qlen(p->q[1]), eve, 0600, &dir);
break;
default:
panic("pipestat");
}
n = convD2M(&dir, db, n);
if(n < BIT16SZ)
error(Eshortstat);
return n;
}
/*
* if the stream doesn't exist, create it
*/
static Chan*
pipeopen(Chan *c, int omode)
{
Pipe *p;
if(c->qid.type & QTDIR){
if(omode != OREAD)
error(Ebadarg);
c->mode = omode;
c->flag |= COPEN;
c->offset = 0;
return c;
}
p = c->aux;
qlock(&p->lk);
switch(NETTYPE(c->qid.path)){
case Qdata0:
p->qref[0]++;
break;
case Qdata1:
p->qref[1]++;
break;
}
qunlock(&p->lk);
c->mode = openmode(omode);
c->flag |= COPEN;
c->offset = 0;
c->iounit = qiomaxatomic;
return c;
}
static void
pipeclose(Chan *c)
{
Pipe *p;
p = c->aux;
qlock(&p->lk);
if(c->flag & COPEN){
/*
* closing either side hangs up the stream
*/
switch(NETTYPE(c->qid.path)){
case Qdata0:
p->qref[0]--;
if(p->qref[0] == 0){
qhangup(p->q[1], 0);
qclose(p->q[0]);
}
break;
case Qdata1:
p->qref[1]--;
if(p->qref[1] == 0){
qhangup(p->q[0], 0);
qclose(p->q[1]);
}
break;
}
}
/*
* if both sides are closed, they are reusable
*/
if(p->qref[0] == 0 && p->qref[1] == 0){
qreopen(p->q[0]);
qreopen(p->q[1]);
}
/*
* free the structure on last close
*/
p->ref--;
if(p->ref == 0){
qunlock(&p->lk);
free(p->q[0]);
free(p->q[1]);
free(p);
} else
qunlock(&p->lk);
}
static long
piperead(Chan *c, void *va, long n, vlong offset)
{
Pipe *p;
USED(offset);
p = c->aux;
switch(NETTYPE(c->qid.path)){
case Qdir:
return devdirread(c, va, n, pipedir, NPIPEDIR, pipegen);
case Qdata0:
return qread(p->q[0], va, n);
case Qdata1:
return qread(p->q[1], va, n);
default:
panic("piperead");
}
return -1; /* not reached */
}
static Block*
pipebread(Chan *c, long n, ulong offset)
{
Pipe *p;
p = c->aux;
switch(NETTYPE(c->qid.path)){
case Qdata0:
return qbread(p->q[0], n);
case Qdata1:
return qbread(p->q[1], n);
}
return devbread(c, n, offset);
}
/*
* a write to a closed pipe causes a note to be sent to
* the process.
*/
static long
pipewrite(Chan *c, void *va, long n, vlong offset)
{
Pipe *p;
USED(offset);
if(!islo())
print("pipewrite hi %lux\n", getcallerpc(&c));
if(waserror()) {
/* avoid notes when pipe is a mounted queue */
if((c->flag & CMSG) == 0)
postnote(up, 1, "sys: write on closed pipe", NUser);
nexterror();
}
p = c->aux;
switch(NETTYPE(c->qid.path)){
case Qdata0:
n = qwrite(p->q[1], va, n);
break;
case Qdata1:
n = qwrite(p->q[0], va, n);
break;
default:
panic("pipewrite");
}
poperror();
return n;
}
static long
pipebwrite(Chan *c, Block *bp, ulong offset)
{
long n;
Pipe *p;
USED(offset);
if(waserror()) {
/* avoid notes when pipe is a mounted queue */
if((c->flag & CMSG) == 0)
postnote(up, 1, "sys: write on closed pipe", NUser);
nexterror();
}
p = c->aux;
switch(NETTYPE(c->qid.path)){
case Qdata0:
n = qbwrite(p->q[1], bp);
break;
case Qdata1:
n = qbwrite(p->q[0], bp);
break;
default:
n = 0;
panic("pipebwrite");
}
poperror();
return n;
}
Dev pipedevtab = {
'|',
"pipe",
devreset,
pipeinit,
devshutdown,
pipeattach,
pipewalk,
pipestat,
pipeopen,
devcreate,
pipeclose,
piperead,
pipebread,
pipewrite,
pipebwrite,
devremove,
devwstat,
};

268
kern/devroot.c Normal file
View File

@ -0,0 +1,268 @@
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
enum
{
Qdir = 0,
Qboot = 0x1000,
Nrootfiles = 32,
Nbootfiles = 32,
};
typedef struct Dirlist Dirlist;
struct Dirlist
{
uint base;
Dirtab *dir;
uchar **data;
int ndir;
int mdir;
};
static Dirtab rootdir[Nrootfiles] = {
"#/", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
"boot", {Qboot, 0, QTDIR}, 0, DMDIR|0555,
};
static uchar *rootdata[Nrootfiles];
static Dirlist rootlist =
{
0,
rootdir,
rootdata,
2,
Nrootfiles
};
static Dirtab bootdir[Nbootfiles] = {
"boot", {Qboot, 0, QTDIR}, 0, DMDIR|0555,
};
static uchar *bootdata[Nbootfiles];
static Dirlist bootlist =
{
Qboot,
bootdir,
bootdata,
1,
Nbootfiles
};
/*
* add a file to the list
*/
static void
addlist(Dirlist *l, char *name, uchar *contents, ulong len, int perm)
{
Dirtab *d;
if(l->ndir >= l->mdir)
panic("too many root files");
l->data[l->ndir] = contents;
d = &l->dir[l->ndir];
strcpy(d->name, name);
d->length = len;
d->perm = perm;
d->qid.type = 0;
d->qid.vers = 0;
d->qid.path = ++l->ndir + l->base;
if(perm & DMDIR)
d->qid.type |= QTDIR;
}
/*
* add a root file
*/
void
addbootfile(char *name, uchar *contents, ulong len)
{
addlist(&bootlist, name, contents, len, 0555);
}
/*
* add a root directory
*/
static void
addrootdir(char *name)
{
addlist(&rootlist, name, nil, 0, DMDIR|0555);
}
static void
rootreset(void)
{
addrootdir("bin");
addrootdir("dev");
addrootdir("env");
addrootdir("fd");
addrootdir("mnt");
addrootdir("net");
addrootdir("net.alt");
addrootdir("proc");
addrootdir("root");
addrootdir("srv");
}
static Chan*
rootattach(char *spec)
{
return devattach('/', spec);
}
static int
rootgen(Chan *c, char *name, Dirtab *dirt, int ndirt, int s, Dir *dp)
{
int t;
Dirtab *d;
Dirlist *l;
USED(dirt);
USED(ndirt);
switch((int)c->qid.path){
case Qdir:
if(s == DEVDOTDOT){
Qid tqiddir = {Qdir, 0, QTDIR};
devdir(c, tqiddir, "#/", 0, eve, 0555, dp);
return 1;
}
return devgen(c, name, rootlist.dir, rootlist.ndir, s, dp);
case Qboot:
if(s == DEVDOTDOT){
Qid tqiddir = {Qdir, 0, QTDIR};
devdir(c, tqiddir, "#/", 0, eve, 0555, dp);
return 1;
}
return devgen(c, name, bootlist.dir, bootlist.ndir, s, dp);
default:
if(s == DEVDOTDOT){
Qid tqiddir = {Qdir, 0, QTDIR};
if((int)c->qid.path < Qboot)
devdir(c, tqiddir, "#/", 0, eve, 0555, dp);
else {
tqiddir.path = Qboot;
devdir(c, tqiddir, "#/", 0, eve, 0555, dp);
}
return 1;
}
if(s != 0)
return -1;
if((int)c->qid.path < Qboot){
t = c->qid.path-1;
l = &rootlist;
}else{
t = c->qid.path - Qboot - 1;
l = &bootlist;
}
if(t >= l->ndir)
return -1;
if(t < 0){
print("rootgen %llud %d %d\n", c->qid.path, s, t);
panic("whoops");
}
d = &l->dir[t];
devdir(c, d->qid, d->name, d->length, eve, d->perm, dp);
return 1;
}
return -1;
}
static Walkqid*
rootwalk(Chan *c, Chan *nc, char **name, int nname)
{
return devwalk(c, nc, name, nname, nil, 0, rootgen);
}
static int
rootstat(Chan *c, uchar *dp, int n)
{
return devstat(c, dp, n, nil, 0, rootgen);
}
static Chan*
rootopen(Chan *c, int omode)
{
return devopen(c, omode, nil, 0, devgen);
}
/*
* sysremove() knows this is a nop
*/
static void
rootclose(Chan *c)
{
USED(c);
}
static long
rootread(Chan *c, void *buf, long n, vlong off)
{
ulong t;
Dirtab *d;
Dirlist *l;
uchar *data;
ulong offset = off;
t = c->qid.path;
switch(t){
case Qdir:
case Qboot:
return devdirread(c, buf, n, nil, 0, rootgen);
}
if(t<Qboot)
l = &rootlist;
else{
t -= Qboot;
l = &bootlist;
}
t--;
if(t >= l->ndir)
error(Egreg);
d = &l->dir[t];
data = l->data[t];
if(offset >= d->length)
return 0;
if(offset+n > d->length)
n = d->length - offset;
memmove(buf, data+offset, n);
return n;
}
static long
rootwrite(Chan *c, void *v, long n, vlong o)
{
USED(c);
USED(v);
USED(n);
USED(o);
error(Egreg);
return 0;
}
Dev rootdevtab = {
'/',
"root",
rootreset,
devinit,
devshutdown,
rootattach,
rootwalk,
rootstat,
rootopen,
devcreate,
rootclose,
rootread,
devbread,
rootwrite,
devbwrite,
devremove,
devwstat,
};

1512
kern/devssl.c Normal file

File diff suppressed because it is too large Load Diff

27
kern/devtab.c Normal file
View File

@ -0,0 +1,27 @@
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
extern Dev consdevtab;
extern Dev rootdevtab;
extern Dev pipedevtab;
extern Dev ssldevtab;
extern Dev mousedevtab;
extern Dev drawdevtab;
extern Dev ipdevtab;
extern Dev fsdevtab;
Dev *devtab[] = {
&rootdevtab,
&consdevtab,
&pipedevtab,
&ssldevtab,
&mousedevtab,
&drawdevtab,
&ipdevtab,
&fsdevtab,
0
};

50
kern/error.c Normal file
View File

@ -0,0 +1,50 @@
char Enoerror[] = "no error";
char Emount[] = "inconsistent mount";
char Eunmount[] = "not mounted";
char Eunion[] = "not in union";
char Emountrpc[] = "mount rpc error";
char Eshutdown[] = "device shut down";
char Enocreate[] = "mounted directory forbids creation";
char Enonexist[] = "file does not exist";
char Eexist[] = "file already exists";
char Ebadsharp[] = "unknown device in # filename";
char Enotdir[] = "not a directory";
char Eisdir[] = "file is a directory";
char Ebadchar[] = "bad character in file name";
char Efilename[] = "file name syntax";
char Eperm[] = "permission denied";
char Ebadusefd[] = "inappropriate use of fd";
char Ebadarg[] = "bad arg in system call";
char Einuse[] = "device or object already in use";
char Eio[] = "i/o error";
char Etoobig[] = "read or write too large";
char Etoosmall[] = "read or write too small";
char Enoport[] = "network port not available";
char Ehungup[] = "i/o on hungup channel";
char Ebadctl[] = "bad process or channel control request";
char Enodev[] = "no free devices";
char Eprocdied[] = "process exited";
char Enochild[] = "no living children";
char Eioload[] = "i/o error in demand load";
char Enovmem[] = "virtual memory allocation failed";
char Ebadfd[] = "fd out of range or not open";
char Enofd[] = "no free file descriptors";
char Eisstream[] = "seek on a stream";
char Ebadexec[] = "exec header invalid";
char Etimedout[] = "connection timed out";
char Econrefused[] = "connection refused";
char Econinuse[] = "connection in use";
char Eintr[] = "interrupted";
char Enomem[] = "kernel allocate failed";
char Enoswap[] = "swap space full";
char Esoverlap[] = "segments overlap";
char Emouseset[] = "mouse type already set";
char Eshort[] = "i/o count too small";
char Egreg[] = "ken has left the building";
char Ebadspec[] = "bad attach specifier";
char Enoreg[] = "process has no saved registers";
char Enoattach[] = "mount/attach disallowed";
char Eshortstat[] = "stat buffer too small";
char Ebadstat[] = "malformed stat buffer";
char Enegoff[] = "negative i/o offset";
char Ecmdargs[] = "wrong #args in control message";

50
kern/error.h Normal file
View File

@ -0,0 +1,50 @@
extern char Enoerror[]; /* no error */
extern char Emount[]; /* inconsistent mount */
extern char Eunmount[]; /* not mounted */
extern char Eunion[]; /* not in union */
extern char Emountrpc[]; /* mount rpc error */
extern char Eshutdown[]; /* device shut down */
extern char Enocreate[]; /* mounted directory forbids creation */
extern char Enonexist[]; /* file does not exist */
extern char Eexist[]; /* file already exists */
extern char Ebadsharp[]; /* unknown device in # filename */
extern char Enotdir[]; /* not a directory */
extern char Eisdir[]; /* file is a directory */
extern char Ebadchar[]; /* bad character in file name */
extern char Efilename[]; /* file name syntax */
extern char Eperm[]; /* permission denied */
extern char Ebadusefd[]; /* inappropriate use of fd */
extern char Ebadarg[]; /* bad arg in system call */
extern char Einuse[]; /* device or object already in use */
extern char Eio[]; /* i/o error */
extern char Etoobig[]; /* read or write too large */
extern char Etoosmall[]; /* read or write too small */
extern char Enoport[]; /* network port not available */
extern char Ehungup[]; /* i/o on hungup channel */
extern char Ebadctl[]; /* bad process or channel control request */
extern char Enodev[]; /* no free devices */
extern char Eprocdied[]; /* process exited */
extern char Enochild[]; /* no living children */
extern char Eioload[]; /* i/o error in demand load */
extern char Enovmem[]; /* virtual memory allocation failed */
extern char Ebadfd[]; /* fd out of range or not open */
extern char Enofd[]; /* no free file descriptors */
extern char Eisstream[]; /* seek on a stream */
extern char Ebadexec[]; /* exec header invalid */
extern char Etimedout[]; /* connection timed out */
extern char Econrefused[]; /* connection refused */
extern char Econinuse[]; /* connection in use */
extern char Eintr[]; /* interrupted */
extern char Enomem[]; /* kernel allocate failed */
extern char Enoswap[]; /* swap space full */
extern char Esoverlap[]; /* segments overlap */
extern char Emouseset[]; /* mouse type already set */
extern char Eshort[]; /* i/o count too small */
extern char Egreg[]; /* ken has left the building */
extern char Ebadspec[]; /* bad attach specifier */
extern char Enoreg[]; /* process has no saved registers */
extern char Enoattach[]; /* mount/attach disallowed */
extern char Eshortstat[]; /* stat buffer too small */
extern char Ebadstat[]; /* malformed stat buffer */
extern char Enegoff[]; /* negative i/o offset */
extern char Ecmdargs[]; /* wrong #args in control message */

821
kern/exportfs.c Normal file
View File

@ -0,0 +1,821 @@
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
typedef struct Fid Fid;
typedef struct Export Export;
typedef struct Exq Exq;
#define nil ((void*)0)
enum
{
Nfidhash = 1,
MAXRPC = MAXMSG+MAXFDATA,
MAXDIRREAD = (MAXFDATA/DIRLEN)*DIRLEN
};
struct Export
{
Ref r;
Exq* work;
Lock fidlock;
Fid* fid[Nfidhash];
Chan* root;
Chan* io;
Pgrp* pgrp;
int npart;
char part[MAXRPC];
};
struct Fid
{
Fid* next;
Fid** last;
Chan* chan;
long offset;
int fid;
int ref; /* fcalls using the fid; locked by Export.Lock */
int attached; /* fid attached or cloned but not clunked */
};
struct Exq
{
Lock lk;
int nointr;
int noresponse; /* don't respond to this one */
Exq* next;
int shut; /* has been noted for shutdown */
Export* export;
void* slave;
Fcall rpc;
char buf[MAXRPC];
};
struct
{
Lock l;
Qlock qwait;
Rendez rwait;
Exq *head; /* work waiting for a slave */
Exq *tail;
}exq;
static void exshutdown(Export*);
static void exflush(Export*, int, int);
static void exslave(void*);
static void exfree(Export*);
static void exportproc(Export*);
static char* Exauth(Export*, Fcall*);
static char* Exattach(Export*, Fcall*);
static char* Exclunk(Export*, Fcall*);
static char* Excreate(Export*, Fcall*);
static char* Exopen(Export*, Fcall*);
static char* Exread(Export*, Fcall*);
static char* Exremove(Export*, Fcall*);
static char* Exstat(Export*, Fcall*);
static char* Exwalk(Export*, Fcall*);
static char* Exwrite(Export*, Fcall*);
static char* Exwstat(Export*, Fcall*);
static char* Exversion(Export*, Fcall*);
static char *(*fcalls[Tmax])(Export*, Fcall*);
static char Enofid[] = "no such fid";
static char Eseekdir[] = "can't seek on a directory";
static char Ereaddir[] = "unaligned read of a directory";
static int exdebug = 0;
int
sysexport(int fd)
{
Chan *c;
Export *fs;
if(waserror())
return -1;
c = fdtochan(fd, ORDWR, 1, 1);
poperror();
c->flag |= CMSG;
fs = mallocz(sizeof(Export));
fs->r.ref = 1;
fs->pgrp = up->pgrp;
refinc(&fs->pgrp->r);
refinc(&up->slash->r);
fs->root = up->slash;
refinc(&fs->root->r);
fs->root = domount(fs->root);
fs->io = c;
exportproc(fs);
return 0;
}
static void
exportinit(void)
{
lock(&exq.l);
if(fcalls[Tversion] != nil) {
unlock(&exq.l);
return;
}
fmtinstall('F', fcallfmt);
fmtinstall('D', dirfmt);
fmtinstall('M', dirmodefmt);
fcalls[Tversion] = Exversion;
fcalls[Tauth] = Exauth;
fcalls[Tattach] = Exattach;
fcalls[Twalk] = Exwalk;
fcalls[Topen] = Exopen;
fcalls[Tcreate] = Excreate;
fcalls[Tread] = Exread;
fcalls[Twrite] = Exwrite;
fcalls[Tclunk] = Exclunk;
fcalls[Tremove] = Exremove;
fcalls[Tstat] = Exstat;
fcalls[Twstat] = Exwstat;
unlock(&exq.l);
}
void
exportproc(Export *fs)
{
Exq *q;
char *buf;
int n, cn, len;
exportinit();
for(;;){
q = mallocz(sizeof(Exq));
if(q == 0)
panic("no memory");
q->rpc.data = q->buf + MAXMSG;
buf = q->buf;
len = MAXRPC;
if(fs->npart) {
memmove(buf, fs->part, fs->npart);
buf += fs->npart;
len -= fs->npart;
goto chk;
}
for(;;) {
if(waserror())
goto bad;
n = (*devtab[fs->io->type].read)(fs->io, buf, len, 0);
poperror();
if(n <= 0)
goto bad;
buf += n;
len -= n;
chk:
n = buf - q->buf;
/* convM2S returns size of correctly decoded message */
cn = convM2S(q->buf, &q->rpc, n);
if(cn < 0){
iprint("bad message type in devmnt\n");
goto bad;
}
if(cn > 0) {
n -= cn;
if(n < 0){
iprint("negative size in devmnt");
goto bad;
}
fs->npart = n;
if(n != 0)
memmove(fs->part, q->buf+cn, n);
break;
}
}
if(exdebug)
iprint("export %d <- %F\n", getpid(), &q->rpc);
if(q->rpc.type == Tflush){
exflush(fs, q->rpc.tag, q->rpc.oldtag);
free(q);
continue;
}
q->export = fs;
refinc(&fs->r);
lock(&exq.l);
if(exq.head == nil)
exq.head = q;
else
exq.tail->next = q;
q->next = nil;
exq.tail = q;
unlock(&exq.l);
if(exq.qwait.first == nil) {
n = thread("exportfs", exslave, nil);
/* iprint("launch export (pid=%ux)\n", n); */
}
rendwakeup(&exq.rwait);
}
bad:
free(q);
exshutdown(fs);
exfree(fs);
}
void
exflush(Export *fs, int flushtag, int tag)
{
Exq *q, **last;
int n;
Fcall fc;
char buf[MAXMSG];
/* hasn't been started? */
lock(&exq.l);
last = &exq.head;
for(q = exq.head; q != nil; q = q->next){
if(q->export == fs && q->rpc.tag == tag){
*last = q->next;
unlock(&exq.l);
exfree(fs);
free(q);
goto Respond;
}
last = &q->next;
}
unlock(&exq.l);
/* in progress? */
lock(&fs->r.l);
for(q = fs->work; q != nil; q = q->next){
if(q->rpc.tag == tag && !q->noresponse){
lock(&q->lk);
q->noresponse = 1;
if(!q->nointr)
intr(q->slave);
unlock(&q->lk);
unlock(&fs->r.l);
goto Respond;
return;
}
}
unlock(&fs->r.l);
if(exdebug) iprint("exflush: did not find rpc: %d\n", tag);
Respond:
fc.type = Rflush;
fc.tag = flushtag;
n = convS2M(&fc, buf);
if(exdebug) iprint("exflush -> %F\n", &fc);
if(!waserror()){
(*devtab[fs->io->type].write)(fs->io, buf, n, 0);
poperror();
}
}
void
exshutdown(Export *fs)
{
Exq *q, **last;
lock(&exq.l);
last = &exq.head;
for(q = exq.head; q != nil; q = *last){
if(q->export == fs){
*last = q->next;
exfree(fs);
free(q);
continue;
}
last = &q->next;
}
unlock(&exq.l);
lock(&fs->r.l);
q = fs->work;
while(q != nil){
if(q->shut){
q = q->next;
continue;
}
q->shut = 1;
unlock(&fs->r.l);
/* postnote(q->slave, 1, "interrupted", NUser); */
iprint("postnote 2!\n");
lock(&fs->r.l);
q = fs->work;
}
unlock(&fs->r.l);
}
void
exfree(Export *fs)
{
Fid *f, *n;
int i;
if(refdec(&fs->r) != 0)
return;
closepgrp(fs->pgrp);
cclose(fs->root);
cclose(fs->io);
for(i = 0; i < Nfidhash; i++){
for(f = fs->fid[i]; f != nil; f = n){
if(f->chan != nil)
cclose(f->chan);
n = f->next;
free(f);
}
}
free(fs);
}
int
exwork(void *a)
{
return exq.head != nil;
}
void
exslave(void *a)
{
Export *fs;
Exq *q, *t, **last;
char *err;
int n;
/*
closepgrp(up->pgrp);
up->pgrp = nil;
*/
for(;;){
qlock(&exq.qwait);
rendsleep(&exq.rwait, exwork, nil);
lock(&exq.l);
q = exq.head;
if(q == nil) {
unlock(&exq.l);
qunlock(&exq.qwait);
continue;
}
exq.head = q->next;
q->slave = curthread();
unlock(&exq.l);
qunlock(&exq.qwait);
q->noresponse = 0;
q->nointr = 0;
fs = q->export;
lock(&fs->r.l);
q->next = fs->work;
fs->work = q;
unlock(&fs->r.l);
up->pgrp = q->export->pgrp;
if(exdebug > 1)
iprint("exslave dispatch %d %F\n", getpid(), &q->rpc);
if(waserror()){
iprint("exslave err %r\n");
err = up->errstr;
goto Err;
}
if(q->rpc.type >= Tmax || !fcalls[q->rpc.type])
err = "bad fcall type";
else
err = (*fcalls[q->rpc.type])(fs, &q->rpc);
poperror();
Err:;
q->rpc.type++;
if(err){
q->rpc.type = Rerror;
strncpy(q->rpc.ename, err, ERRLEN);
}
n = convS2M(&q->rpc, q->buf);
if(exdebug)
iprint("exslve %d -> %F\n", getpid(), &q->rpc);
lock(&q->lk);
if(q->noresponse == 0){
q->nointr = 1;
clearintr();
if(!waserror()){
(*devtab[fs->io->type].write)(fs->io, q->buf, n, 0);
poperror();
}
}
unlock(&q->lk);
/*
* exflush might set noresponse at this point, but
* setting noresponse means don't send a response now;
* it's okay that we sent a response already.
*/
if(exdebug > 1)
iprint("exslave %d written %d\n", getpid(), q->rpc.tag);
lock(&fs->r.l);
last = &fs->work;
for(t = fs->work; t != nil; t = t->next){
if(t == q){
*last = q->next;
break;
}
last = &t->next;
}
unlock(&fs->r.l);
exfree(q->export);
free(q);
}
iprint("exslave shut down");
threadexit();
}
Fid*
Exmkfid(Export *fs, int fid)
{
ulong h;
Fid *f, *nf;
nf = mallocz(sizeof(Fid));
if(nf == nil)
return nil;
lock(&fs->fidlock);
h = fid % Nfidhash;
for(f = fs->fid[h]; f != nil; f = f->next){
if(f->fid == fid){
unlock(&fs->fidlock);
free(nf);
return nil;
}
}
nf->next = fs->fid[h];
if(nf->next != nil)
nf->next->last = &nf->next;
nf->last = &fs->fid[h];
fs->fid[h] = nf;
nf->fid = fid;
nf->ref = 1;
nf->attached = 1;
nf->offset = 0;
nf->chan = nil;
unlock(&fs->fidlock);
return nf;
}
Fid*
Exgetfid(Export *fs, int fid)
{
Fid *f;
ulong h;
lock(&fs->fidlock);
h = fid % Nfidhash;
for(f = fs->fid[h]; f; f = f->next) {
if(f->fid == fid){
if(f->attached == 0)
break;
f->ref++;
unlock(&fs->fidlock);
return f;
}
}
unlock(&fs->fidlock);
return nil;
}
void
Exputfid(Export *fs, Fid *f)
{
lock(&fs->fidlock);
f->ref--;
if(f->ref == 0 && f->attached == 0){
if(f->chan != nil)
cclose(f->chan);
f->chan = nil;
*f->last = f->next;
if(f->next != nil)
f->next->last = f->last;
unlock(&fs->fidlock);
free(f);
return;
}
unlock(&fs->fidlock);
}
char*
Exsession(Export *e, Fcall *rpc)
{
memset(rpc->authid, 0, sizeof(rpc->authid));
memset(rpc->authdom, 0, sizeof(rpc->authdom));
memset(rpc->chal, 0, sizeof(rpc->chal));
return nil;
}
char*
Exauth(Export *e, Fcall *f)
{
return "authentication not required";
}
char*
Exattach(Export *fs, Fcall *rpc)
{
Fid *f;
f = Exmkfid(fs, rpc->fid);
if(f == nil)
return Einuse;
if(waserror()){
f->attached = 0;
Exputfid(fs, f);
return up->errstr;
}
f->chan = clone(fs->root, nil);
poperror();
rpc->qid = f->chan->qid;
Exputfid(fs, f);
return nil;
}
char*
Exclone(Export *fs, Fcall *rpc)
{
Fid *f, *nf;
if(rpc->fid == rpc->newfid)
return Einuse;
f = Exgetfid(fs, rpc->fid);
if(f == nil)
return Enofid;
nf = Exmkfid(fs, rpc->newfid);
if(nf == nil){
Exputfid(fs, f);
return Einuse;
}
if(waserror()){
Exputfid(fs, f);
Exputfid(fs, nf);
return up->errstr;
}
nf->chan = clone(f->chan, nil);
poperror();
Exputfid(fs, f);
Exputfid(fs, nf);
return nil;
}
char*
Exclunk(Export *fs, Fcall *rpc)
{
Fid *f;
f = Exgetfid(fs, rpc->fid);
if(f != nil){
f->attached = 0;
Exputfid(fs, f);
}
return nil;
}
char*
Exwalk(Export *fs, Fcall *rpc)
{
Fid *f;
Chan *c;
f = Exgetfid(fs, rpc->fid);
if(f == nil)
return Enofid;
if(waserror()){
Exputfid(fs, f);
return up->errstr;
}
c = walk(f->chan, rpc->name, 1);
if(c == nil)
error(Enonexist);
poperror();
f->chan = c;
rpc->qid = c->qid;
Exputfid(fs, f);
return nil;
}
char*
Exopen(Export *fs, Fcall *rpc)
{
Fid *f;
Chan *c;
f = Exgetfid(fs, rpc->fid);
if(f == nil)
return Enofid;
if(waserror()){
Exputfid(fs, f);
return up->errstr;
}
c = f->chan;
c = (*devtab[c->type].open)(c, rpc->mode);
poperror();
f->chan = c;
f->offset = 0;
rpc->qid = f->chan->qid;
Exputfid(fs, f);
return nil;
}
char*
Excreate(Export *fs, Fcall *rpc)
{
Fid *f;
Chan *c;
f = Exgetfid(fs, rpc->fid);
if(f == nil)
return Enofid;
if(waserror()){
Exputfid(fs, f);
return up->errstr;
}
c = f->chan;
if(c->mnt && !(c->flag&CCREATE))
c = createdir(c);
(*devtab[c->type].create)(c, rpc->name, rpc->mode, rpc->perm);
poperror();
f->chan = c;
rpc->qid = f->chan->qid;
Exputfid(fs, f);
return nil;
}
char*
Exread(Export *fs, Fcall *rpc)
{
Fid *f;
Chan *c;
long off;
int dir, n, seek;
f = Exgetfid(fs, rpc->fid);
if(f == nil)
return Enofid;
c = f->chan;
dir = c->qid.path & CHDIR;
if(dir){
rpc->count -= rpc->count%DIRLEN;
if(rpc->offset%DIRLEN || rpc->count==0){
Exputfid(fs, f);
return Ereaddir;
}
if(f->offset > rpc->offset){
Exputfid(fs, f);
return Eseekdir;
}
}
if(waserror()) {
Exputfid(fs, f);
return up->errstr;
}
for(;;){
n = rpc->count;
seek = 0;
off = rpc->offset;
if(dir && f->offset != off){
off = f->offset;
n = rpc->offset - off;
if(n > MAXDIRREAD)
n = MAXDIRREAD;
seek = 1;
}
if(dir && c->mnt != nil)
n = unionread(c, rpc->data, n);
else{
c->offset = off;
n = (*devtab[c->type].read)(c, rpc->data, n, off);
}
if(n == 0 || !seek)
break;
f->offset = off + n;
c->offset += n;
}
rpc->count = n;
poperror();
Exputfid(fs, f);
return nil;
}
char*
Exwrite(Export *fs, Fcall *rpc)
{
Fid *f;
Chan *c;
f = Exgetfid(fs, rpc->fid);
if(f == nil)
return Enofid;
if(waserror()){
Exputfid(fs, f);
return up->errstr;
}
c = f->chan;
if(c->qid.path & CHDIR)
error(Eisdir);
rpc->count = (*devtab[c->type].write)(c, rpc->data, rpc->count, rpc->offset);
poperror();
Exputfid(fs, f);
return nil;
}
char*
Exstat(Export *fs, Fcall *rpc)
{
Fid *f;
Chan *c;
f = Exgetfid(fs, rpc->fid);
if(f == nil)
return Enofid;
if(waserror()){
Exputfid(fs, f);
return up->errstr;
}
c = f->chan;
(*devtab[c->type].stat)(c, rpc->stat);
poperror();
Exputfid(fs, f);
return nil;
}
char*
Exwstat(Export *fs, Fcall *rpc)
{
Fid *f;
Chan *c;
f = Exgetfid(fs, rpc->fid);
if(f == nil)
return Enofid;
if(waserror()){
Exputfid(fs, f);
return up->errstr;
}
c = f->chan;
(*devtab[c->type].wstat)(c, rpc->stat);
poperror();
Exputfid(fs, f);
return nil;
}
char*
Exremove(Export *fs, Fcall *rpc)
{
Fid *f;
Chan *c;
f = Exgetfid(fs, rpc->fid);
if(f == nil)
return Enofid;
if(waserror()){
Exputfid(fs, f);
return up->errstr;
}
c = f->chan;
(*devtab[c->type].remove)(c);
poperror();
/*
* chan is already clunked by remove.
* however, we need to recover the chan,
* and follow sysremove's lead in making to point to root.
*/
c->type = 0;
f->attached = 0;
Exputfid(fs, f);
return nil;
}

377
kern/fns.h Normal file
View File

@ -0,0 +1,377 @@
#define ROUND(s, sz) (((s)+((sz)-1))&~((sz)-1))
void accounttime(void);
void addclock0link(void (*)(void), int);
int addphysseg(Physseg*);
void addbootfile(char*, uchar*, ulong);
Block* adjustblock(Block*, int);
void alarmkproc(void*);
Block* allocb(int);
int anyhigher(void);
int anyready(void);
Page* auxpage(void);
Block* bl2mem(uchar*, Block*, int);
int blocklen(Block*);
void callwithureg(void(*)(Ureg*));
char* c2name(Chan*);
int cangetc(void*);
int canlock(Lock*);
int canpage(Proc*);
int canputc(void*);
int canqlock(QLock*);
int canrlock(RWlock*);
void chandevinit(void);
void chandevreset(void);
void chandevshutdown(void);
void chanfree(Chan*);
void chanrec(Mnt*);
void checkalarms(void);
void checkb(Block*, char*);
void cinit(void);
Chan* cclone(Chan*);
void cclose(Chan*);
char* clipread(void);
int clipwrite(char*);
void closeegrp(Egrp*);
void closefgrp(Fgrp*);
void closemount(Mount*);
void closepgrp(Pgrp*);
void closergrp(Rgrp*);
long clrfpintr(void);
void cmderror(Cmdbuf*, char*);
int cmount(Chan**, Chan*, int, char*);
void cnameclose(Cname*);
void confinit(void);
void confinit1(int);
int consactive(void);
void (*consdebug)(void);
void copen(Chan*);
Block* concatblock(Block*);
Block* copyblock(Block*, int);
void copypage(Page*, Page*);
int cread(Chan*, uchar*, int, vlong);
void cunmount(Chan*, Chan*);
void cupdate(Chan*, uchar*, int, vlong);
void cwrite(Chan*, uchar*, int, vlong);
ulong dbgpc(Proc*);
int decref(Ref*);
int decrypt(void*, void*, int);
void delay(int);
Chan* devattach(int, char*);
Block* devbread(Chan*, long, ulong);
long devbwrite(Chan*, Block*, ulong);
Chan* devclone(Chan*);
int devconfig(int, char *, DevConf *);
void devcreate(Chan*, char*, int, ulong);
void devdir(Chan*, Qid, char*, vlong, char*, long, Dir*);
long devdirread(Chan*, char*, long, Dirtab*, int, Devgen*);
Devgen devgen;
void devinit(void);
int devno(int, int);
Chan* devopen(Chan*, int, Dirtab*, int, Devgen*);
void devpermcheck(char*, ulong, int);
void devpower(int);
void devremove(Chan*);
void devreset(void);
void devshutdown(void);
int devstat(Chan*, uchar*, int, Dirtab*, int, Devgen*);
Walkqid* devwalk(Chan*, Chan*, char**, int, Dirtab*, int, Devgen*);
int devwstat(Chan*, uchar*, int);
void drawactive(int);
void drawcmap(void);
void dumpaproc(Proc*);
void dumpqueues(void);
void dumpregs(Ureg*);
void dumpstack(void);
Fgrp* dupfgrp(Fgrp*);
void duppage(Page*);
void dupswap(Page*);
int emptystr(char*);
int encrypt(void*, void*, int);
void envcpy(Egrp*, Egrp*);
int eqchan(Chan*, Chan*, int);
int eqqid(Qid, Qid);
void error(char*);
long execregs(ulong, ulong, ulong);
void exhausted(char*);
void exit(int);
uvlong fastticks(uvlong*);
int fault(ulong, int);
void fdclose(int, int);
Chan* fdtochan(int, int, int, int);
int fixfault(Segment*, ulong, int, int);
void flushmmu(void);
void forkchild(Proc*, Ureg*);
void forkret(void);
void free(void*);
void freeb(Block*);
void freeblist(Block*);
int freebroken(void);
void freepte(Segment*, Pte*);
void freesegs(int);
void freesession(Session*);
ulong getmalloctag(void*);
ulong getrealloctag(void*);
void gotolabel(Label*);
char* getconfenv(void);
int haswaitq(void*);
long hostdomainwrite(char*, int);
long hostownerwrite(char*, int);
void hzsched(void);
void iallocinit(void);
Block* iallocb(int);
void iallocsummary(void);
long ibrk(ulong, int);
void ilock(Lock*);
void iunlock(Lock*);
int incref(Ref*);
void initseg(void);
int iprint(char*, ...);
void isdir(Chan*);
int iseve(void);
#define islo() (0)
Segment* isoverlap(Proc*, ulong, int);
int ispages(void*);
int isphysseg(char*);
void ixsummary(void);
void kbdclock(void);
int kbdcr2nl(Queue*, int);
int kbdputc(Queue*, int);
void kbdrepeat(int);
long keyread(char*, int, long);
void kickpager(void);
void killbig(void);
int kproc(char*, void(*)(void*), void*);
void kprocchild(Proc*, void (*)(void*), void*);
void (*kproftimer)(ulong);
void ksetenv(char*, char*, int);
void kstrcpy(char*, char*, int);
void kstrdup(char**, char*);
long latin1(Rune*, int);
int lock(Lock*);
void lockinit(void);
void logopen(Log*);
void logclose(Log*);
char* logctl(Log*, int, char**, Logflag*);
void logn(Log*, int, void*, int);
long logread(Log*, void*, ulong, long);
void log(Log*, int, char*, ...);
Cmdtab* lookupcmd(Cmdbuf*, Cmdtab*, int);
void machinit(void);
void* mallocz(ulong, int);
#define malloc kmalloc
void* malloc(ulong);
void mallocsummary(void);
Block* mem2bl(uchar*, int);
void mfreeseg(Segment*, ulong, int);
void microdelay(int);
void mkqid(Qid*, vlong, ulong, int);
void mmurelease(Proc*);
void mmuswitch(Proc*);
Chan* mntauth(Chan*, char*);
void mntdump(void);
long mntversion(Chan*, char*, int, int);
void mountfree(Mount*);
ulong ms2tk(ulong);
ulong msize(void*);
ulong ms2tk(ulong);
uvlong ms2fastticks(ulong);
void muxclose(Mnt*);
Chan* namec(char*, int, int, ulong);
Chan* newchan(void);
int newfd(Chan*);
Mhead* newmhead(Chan*);
Mount* newmount(Mhead*, Chan*, int, char*);
Page* newpage(int, Segment **, ulong);
Pgrp* newpgrp(void);
Rgrp* newrgrp(void);
Proc* newproc(void);
char* nextelem(char*, char*);
void nexterror(void);
Cname* newcname(char*);
int notify(Ureg*);
int nrand(int);
int okaddr(ulong, ulong, int);
int openmode(ulong);
Block* packblock(Block*);
Block* padblock(Block*, int);
void pagechainhead(Page*);
void pageinit(void);
void pagersummary(void);
void panic(char*, ...);
Cmdbuf* parsecmd(char *a, int n);
ulong perfticks(void);
void pexit(char*, int);
int preempted(void);
void printinit(void);
int procindex(ulong);
void pgrpcpy(Pgrp*, Pgrp*);
void pgrpnote(ulong, char*, long, int);
Pgrp* pgrptab(int);
void pio(Segment *, ulong, ulong, Page **);
#define poperror() up->nerrlab--
void portclock(Ureg*);
int postnote(Proc*, int, char*, int);
int pprint(char*, ...);
void prflush(void);
ulong procalarm(ulong);
int proccounter(char *name);
void procctl(Proc*);
void procdump(void);
int procfdprint(Chan*, int, int, char*, int);
void procinit0(void);
void procflushseg(Segment*);
void procpriority(Proc*, int, int);
Proc* proctab(int);
void procwired(Proc*, int);
Pte* ptealloc(void);
Pte* ptecpy(Pte*);
int pullblock(Block**, int);
Block* pullupblock(Block*, int);
Block* pullupqueue(Queue*, int);
void putmhead(Mhead*);
void putmmu(ulong, ulong, Page*);
void putpage(Page*);
void putseg(Segment*);
void putstr(char*);
void putstrn(char*, int);
void putswap(Page*);
ulong pwait(Waitmsg*);
Label* pwaserror(void);
void qaddlist(Queue*, Block*);
Block* qbread(Queue*, int);
long qbwrite(Queue*, Block*);
Queue* qbypass(void (*)(void*, Block*), void*);
int qcanread(Queue*);
void qclose(Queue*);
int qconsume(Queue*, void*, int);
Block* qcopy(Queue*, int, ulong);
int qdiscard(Queue*, int);
void qflush(Queue*);
void qfree(Queue*);
int qfull(Queue*);
Block* qget(Queue*);
void qhangup(Queue*, char*);
int qisclosed(Queue*);
void qinit(void);
int qiwrite(Queue*, void*, int);
int qlen(Queue*);
void qlock(QLock*);
Queue* qopen(int, int, void (*)(void*), void*);
int qpass(Queue*, Block*);
int qpassnolim(Queue*, Block*);
int qproduce(Queue*, void*, int);
void qputback(Queue*, Block*);
long qread(Queue*, void*, int);
Block* qremove(Queue*);
void qreopen(Queue*);
void qsetlimit(Queue*, int);
void qunlock(QLock*);
int qwindow(Queue*);
int qwrite(Queue*, void*, int);
void qnoblock(Queue*, int);
int rand(void);
void randominit(void);
ulong randomread(void*, ulong);
void rdb(void);
int readnum(ulong, char*, ulong, ulong, int);
int readstr(ulong, char*, ulong, char*);
void ready(Proc*);
void rebootcmd(int, char**);
void reboot(void*, void*, ulong);
void relocateseg(Segment*, ulong);
void renameuser(char*, char*);
void resched(char*);
void resrcwait(char*);
int return0(void*);
void rlock(RWlock*);
long rtctime(void);
void runlock(RWlock*);
Proc* runproc(void);
void savefpregs(FPsave*);
void (*saveintrts)(void);
void sched(void);
void scheddump(void);
void schedinit(void);
void (*screenputs)(char*, int);
long seconds(void);
ulong segattach(Proc*, ulong, char *, ulong, ulong);
void segclock(ulong);
void segpage(Segment*, Page*);
void setkernur(Ureg*, Proc*);
int setlabel(Label*);
void setmalloctag(void*, ulong);
void setrealloctag(void*, ulong);
void setregisters(Ureg*, char*, char*, int);
void setswapchan(Chan*);
char* skipslash(char*);
void sleep(Rendez*, int(*)(void*), void*);
void* smalloc(ulong);
int splhi(void);
int spllo(void);
void splx(int);
void splxpc(int);
char* srvname(Chan*);
int swapcount(ulong);
int swapfull(void);
void swapinit(void);
void timeradd(Timer*);
void timerdel(Timer*);
void timersinit(void);
void timerintr(Ureg*, uvlong);
void timerset(uvlong);
ulong tk2ms(ulong);
#define TK2MS(x) ((x)*(1000/HZ))
vlong todget(vlong*);
void todfix(void);
void todsetfreq(vlong);
void todinit(void);
void todset(vlong, vlong, int);
Block* trimblock(Block*, int, int);
void tsleep(Rendez*, int (*)(void*), void*, int);
int uartctl(Uart*, char*);
int uartgetc(void);
void uartkick(void*);
void uartmouse(Uart*, int (*)(Queue*, int), int);
void uartputc(int);
void uartputs(char*, int);
void uartrecv(Uart*, char);
Uart* uartsetup(Uart*);
int uartstageoutput(Uart*);
void unbreak(Proc*);
void uncachepage(Page*);
long unionread(Chan*, void*, long);
void unlock(Lock*);
Proc** uploc(void);
void userinit(void);
ulong userpc(void);
long userwrite(char*, int);
#define validaddr(a, b, c)
void validname(char*, int);
void validstat(uchar*, int);
void vcacheinval(Page*, ulong);
void* vmemchr(void*, int, int);
Proc* wakeup(Rendez*);
int walk(Chan**, char**, int, int, int*);
#define waserror() (setjmp(pwaserror()->buf))
void wlock(RWlock*);
void wunlock(RWlock*);
void* xalloc(ulong);
void* xallocz(ulong, int);
void xfree(void*);
void xhole(ulong, ulong);
void xinit(void);
int xmerge(void*, void*);
void* xspanalloc(ulong, int, ulong);
void xsummary(void);
void yield(void);
Segment* data2txt(Segment*);
Segment* dupseg(Segment**, int, int);
Segment* newseg(int, ulong, ulong);
Segment* seg(Proc*, ulong, int);
void hnputv(void*, vlong);
void hnputl(void*, ulong);
void hnputs(void*, ushort);
vlong nhgetv(void*);
ulong nhgetl(void*);
ushort nhgets(void*);

47
kern/mkfile Normal file
View File

@ -0,0 +1,47 @@
<$DSRC/mkfile-$CONF
TARG=libkern.$L
OFILES=\
allocb.$O\
cache.$O\
chan.$O\
data.$O\
dev.$O\
devcons.$O\
devdraw.$O\
devip.$O\
devmnt.$O\
devmouse.$O\
devpipe.$O\
devroot.$O\
devssl.$O\
devtab.$O\
error.$O\
parse.$O\
pgrp.$O\
procinit.$O\
rwlock.$O\
sleep.$O\
smalloc.$O\
stub.$O\
sysfile.$O\
sysproc.$O\
qio.$O\
qlock.$O\
term.$O\
todo.$O\
uart.$O\
waserror.$O\
$DEVIP.$O\
$OSHOOKS.$O\
$DEVFS.$O
HFILE=\
dat.h\
devip.h\
error.h\
fns.h\
netif.h\
screen.h
<$DSRC/mklib-$CONF

133
kern/netif.h Normal file
View File

@ -0,0 +1,133 @@
typedef struct Etherpkt Etherpkt;
typedef struct Netaddr Netaddr;
typedef struct Netfile Netfile;
typedef struct Netif Netif;
enum
{
Nmaxaddr= 64,
Nmhash= 31,
Ncloneqid= 1,
Naddrqid,
N2ndqid,
N3rdqid,
Ndataqid,
Nctlqid,
Nstatqid,
Ntypeqid,
Nifstatqid,
};
/*
* Macros to manage Qid's used for multiplexed devices
*/
#define NETTYPE(x) (((ulong)x)&0x1f)
#define NETID(x) ((((ulong)x))>>5)
#define NETQID(i,t) ((((ulong)i)<<5)|(t))
/*
* one per multiplexed connection
*/
struct Netfile
{
QLock lk;
int inuse;
ulong mode;
char owner[KNAMELEN];
int type; /* multiplexor type */
int prom; /* promiscuous mode */
int scan; /* base station scanning interval */
int bridge; /* bridge mode */
int headersonly; /* headers only - no data */
uchar maddr[8]; /* bitmask of multicast addresses requested */
int nmaddr; /* number of multicast addresses */
Queue *in; /* input buffer */
};
/*
* a network address
*/
struct Netaddr
{
Netaddr *next; /* allocation chain */
Netaddr *hnext;
uchar addr[Nmaxaddr];
int ref;
};
/*
* a network interface
*/
struct Netif
{
QLock lk;
/* multiplexing */
char name[KNAMELEN]; /* for top level directory */
int nfile; /* max number of Netfiles */
Netfile **f;
/* about net */
int limit; /* flow control */
int alen; /* address length */
int mbps; /* megabits per sec */
uchar addr[Nmaxaddr];
uchar bcast[Nmaxaddr];
Netaddr *maddr; /* known multicast addresses */
int nmaddr; /* number of known multicast addresses */
Netaddr *mhash[Nmhash]; /* hash table of multicast addresses */
int prom; /* number of promiscuous opens */
int scan; /* number of base station scanners */
int all; /* number of -1 multiplexors */
/* statistics */
int misses;
int inpackets;
int outpackets;
int crcs; /* input crc errors */
int oerrs; /* output errors */
int frames; /* framing errors */
int overflows; /* packet overflows */
int buffs; /* buffering errors */
int soverflows; /* software overflow */
/* routines for touching the hardware */
void *arg;
void (*promiscuous)(void*, int);
void (*multicast)(void*, uchar*, int);
void (*scanbs)(void*, uint); /* scan for base stations */
};
void netifinit(Netif*, char*, int, ulong);
Walkqid* netifwalk(Netif*, Chan*, Chan*, char **, int);
Chan* netifopen(Netif*, Chan*, int);
void netifclose(Netif*, Chan*);
long netifread(Netif*, Chan*, void*, long, ulong);
Block* netifbread(Netif*, Chan*, long, ulong);
long netifwrite(Netif*, Chan*, void*, long);
int netifwstat(Netif*, Chan*, uchar*, int);
int netifstat(Netif*, Chan*, uchar*, int);
int activemulti(Netif*, uchar*, int);
/*
* Ethernet specific
*/
enum
{
Eaddrlen= 6,
ETHERMINTU = 60, /* minimum transmit size */
ETHERMAXTU = 1514, /* maximum transmit size */
ETHERHDRSIZE = 14, /* size of an ethernet header */
};
struct Etherpkt
{
uchar d[Eaddrlen];
uchar s[Eaddrlen];
uchar type[2];
uchar data[1500];
};

184
kern/os-windows.c Normal file
View File

@ -0,0 +1,184 @@
#include <windows.h>
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
typedef struct Oproc Oproc;
struct Oproc {
int tid;
HANDLE *sema;
};
char *argv0;
_declspec(thread) Proc *CT;
Proc*
_getproc(void)
{
return CT;
}
void
_setproc(Proc *p)
{
CT = p;
}
void
oserrstr(void)
{
char *p;
char buf[ERRMAX];
if((p = strerror(errno)) != nil)
strecpy(up->errstr, up->errstr+ERRMAX, p);
else
snprint(up->errstr, ERRMAX, "unix error %d", errno);
}
void
oserror(void)
{
oserrstr();
nexterror();
}
void
osinit(void)
{
Oproc *t;
static Proc firstprocCTstore;
CT = &firstprocCTstore;
t = (Oproc*) CT->oproc;
assert(t != 0);
t->tid = GetCurrentThreadId();
t->sema = CreateSemaphore(0, 0, 1000, 0);
if(t->sema == 0) {
oserror();
fatal("could not create semaphore: %r");
}
}
void
osnewproc(Proc *p)
{
Oproc *op;
op = (Oproc*)p->oproc;
op->sema = CreateSemaphore(0, 0, 1000, 0);
if (op->sema == 0) {
oserror();
fatal("could not create semaphore: %r");
}
}
void
osmsleep(int ms)
{
Sleep((DWORD) ms);
}
void
osyield(void)
{
Sleep(0);
}
static DWORD WINAPI tramp(LPVOID vp);
void
osproc(Proc *p)
{
int tid;
if(CreateThread(0, 0, tramp, p, 0, &tid) == 0) {
oserror();
fatal("osproc: %r");
}
Sleep(0);
}
static DWORD WINAPI
tramp(LPVOID vp)
{
Proc *p = (Proc *) vp;
Oproc *op = (Oproc*) p->oproc;
CT = p;
op->tid = GetCurrentThreadId();
op->sema = CreateSemaphore(0, 0, 1000, 0);
if(op->sema == 0) {
oserror();
fatal("could not create semaphore: %r");
}
(*p->fn)(p->arg);
ExitThread(0);
return 0;
}
void
procsleep(void)
{
Proc *p;
Oproc *op;
p = up;
op = (Oproc*)p->oproc;
WaitForSingleObject(op->sema, INFINITE);}
void
procwakeup(Proc *p)
{
Oproc *op;
op = (Oproc*)p->oproc;
ReleaseSemaphore(op->sema, 1, 0);
}
void
randominit(void)
{
srand(seconds());
}
ulong
randomread(void *v, ulong n)
{
int m, i, *r;
m = (n / sizeof(int)) * sizeof(int);
for (i = 0, r = (int*)v; i < m; i += sizeof(int)) {
*r = rand();
r += sizeof(int);
}
return m;
}
long
seconds(void)
{
return time(0);
}
int
ticks(void)
{
return GetTickCount();
}
extern int main(int, char*[]);
static int args(char *argv[], int n, char *p);
int PASCAL
WinMain(HANDLE hInst, HANDLE hPrev, LPSTR arg, int nshow)
{
main(__argc, __argv);
ExitThread(0);
return 0;
}

113
kern/parse.c Normal file
View File

@ -0,0 +1,113 @@
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
/*
* Generous estimate of number of fields, including terminal nil pointer
*/
static int
ncmdfield(char *p, int n)
{
int white, nwhite;
char *ep;
int nf;
if(p == nil)
return 1;
nf = 0;
ep = p+n;
white = 1; /* first text will start field */
while(p < ep){
nwhite = (strchr(" \t\r\n", *p++ & 0xFF) != 0); /* UTF is irrelevant */
if(white && !nwhite) /* beginning of field */
nf++;
white = nwhite;
}
return nf+1; /* +1 for nil */
}
/*
* parse a command written to a device
*/
Cmdbuf*
parsecmd(char *p, int n)
{
Cmdbuf *volatile cb;
int nf;
char *sp;
nf = ncmdfield(p, n);
/* allocate Cmdbuf plus string pointers plus copy of string including \0 */
sp = smalloc(sizeof(*cb) + nf * sizeof(char*) + n + 1);
cb = (Cmdbuf*)sp;
cb->f = (char**)(&cb[1]);
cb->buf = (char*)(&cb->f[nf]);
if(up!=nil && waserror()){
free(cb);
nexterror();
}
memmove(cb->buf, p, n);
if(up != nil)
poperror();
/* dump new line and null terminate */
if(n > 0 && cb->buf[n-1] == '\n')
n--;
cb->buf[n] = '\0';
cb->nf = tokenize(cb->buf, cb->f, nf-1);
cb->f[cb->nf] = nil;
return cb;
}
/*
* Reconstruct original message, for error diagnostic
*/
void
cmderror(Cmdbuf *cb, char *s)
{
int i;
char *p, *e;
p = up->genbuf;
e = p+ERRMAX-10;
p = seprint(p, e, "%s \"", s);
for(i=0; i<cb->nf; i++){
if(i > 0)
p = seprint(p, e, " ");
p = seprint(p, e, "%q", cb->f[i]);
}
strcpy(p, "\"");
error(up->genbuf);
}
/*
* Look up entry in table
*/
Cmdtab*
lookupcmd(Cmdbuf *cb, Cmdtab *ctab, int nctab)
{
int i;
Cmdtab *ct;
if(cb->nf == 0)
error("empty control message");
for(ct = ctab, i=0; i<nctab; i++, ct++){
if(strcmp(ct->cmd, "*") !=0) /* wildcard always matches */
if(strcmp(ct->cmd, cb->f[0]) != 0)
continue;
if(ct->narg != 0 && ct->narg != cb->nf)
cmderror(cb, Ecmdargs);
return ct;
}
cmderror(cb, "unknown control message");
return nil;
}

272
kern/pgrp.c Normal file
View File

@ -0,0 +1,272 @@
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
static Ref pgrpid;
static Ref mountid;
#ifdef NOTDEF
void
pgrpnote(ulong noteid, char *a, long n, int flag)
{
Proc *p, *ep;
char buf[ERRMAX];
if(n >= ERRMAX-1)
error(Etoobig);
memmove(buf, a, n);
buf[n] = 0;
p = proctab(0);
ep = p+conf.nproc;
for(; p < ep; p++) {
if(p->state == Dead)
continue;
if(up != p && p->noteid == noteid && p->kp == 0) {
qlock(&p->debug);
if(p->pid == 0 || p->noteid != noteid){
qunlock(&p->debug);
continue;
}
if(!waserror()) {
postnote(p, 0, buf, flag);
poperror();
}
qunlock(&p->debug);
}
}
}
#endif
Pgrp*
newpgrp(void)
{
Pgrp *p;
p = smalloc(sizeof(Pgrp));
p->ref.ref = 1;
p->pgrpid = incref(&pgrpid);
return p;
}
Rgrp*
newrgrp(void)
{
Rgrp *r;
r = smalloc(sizeof(Rgrp));
r->ref.ref = 1;
return r;
}
void
closergrp(Rgrp *r)
{
if(decref(&r->ref) == 0)
free(r);
}
void
closepgrp(Pgrp *p)
{
Mhead **h, **e, *f, *next;
if(decref(&p->ref) != 0)
return;
qlock(&p->debug);
wlock(&p->ns);
p->pgrpid = -1;
e = &p->mnthash[MNTHASH];
for(h = p->mnthash; h < e; h++) {
for(f = *h; f; f = next) {
wlock(&f->lock);
cclose(f->from);
mountfree(f->mount);
f->mount = nil;
next = f->hash;
wunlock(&f->lock);
putmhead(f);
}
}
wunlock(&p->ns);
qunlock(&p->debug);
free(p);
}
void
pgrpinsert(Mount **order, Mount *m)
{
Mount *f;
m->order = 0;
if(*order == 0) {
*order = m;
return;
}
for(f = *order; f; f = f->order) {
if(m->mountid < f->mountid) {
m->order = f;
*order = m;
return;
}
order = &f->order;
}
*order = m;
}
/*
* pgrpcpy MUST preserve the mountid allocation order of the parent group
*/
void
pgrpcpy(Pgrp *to, Pgrp *from)
{
int i;
Mount *n, *m, **link, *order;
Mhead *f, **tom, **l, *mh;
wlock(&from->ns);
order = 0;
tom = to->mnthash;
for(i = 0; i < MNTHASH; i++) {
l = tom++;
for(f = from->mnthash[i]; f; f = f->hash) {
rlock(&f->lock);
mh = newmhead(f->from);
*l = mh;
l = &mh->hash;
link = &mh->mount;
for(m = f->mount; m; m = m->next) {
n = newmount(mh, m->to, m->mflag, m->spec);
m->copy = n;
pgrpinsert(&order, m);
*link = n;
link = &n->next;
}
runlock(&f->lock);
}
}
/*
* Allocate mount ids in the same sequence as the parent group
*/
lock(&mountid.lk);
for(m = order; m; m = m->order)
m->copy->mountid = mountid.ref++;
unlock(&mountid.lk);
wunlock(&from->ns);
}
Fgrp*
dupfgrp(Fgrp *f)
{
Fgrp *new;
Chan *c;
int i;
new = smalloc(sizeof(Fgrp));
if(f == nil){
new->fd = smalloc(DELTAFD*sizeof(Chan*));
new->nfd = DELTAFD;
new->ref.ref = 1;
return new;
}
lock(&f->ref.lk);
/* Make new fd list shorter if possible, preserving quantization */
new->nfd = f->maxfd+1;
i = new->nfd%DELTAFD;
if(i != 0)
new->nfd += DELTAFD - i;
new->fd = malloc(new->nfd*sizeof(Chan*));
if(new->fd == 0){
unlock(&f->ref.lk);
error("no memory for fgrp");
}
new->ref.ref = 1;
new->maxfd = f->maxfd;
for(i = 0; i <= f->maxfd; i++) {
if(c = f->fd[i]){
incref(&c->ref);
new->fd[i] = c;
}
}
unlock(&f->ref.lk);
return new;
}
void
closefgrp(Fgrp *f)
{
int i;
Chan *c;
if(f == 0)
return;
if(decref(&f->ref) != 0)
return;
for(i = 0; i <= f->maxfd; i++)
if(c = f->fd[i])
cclose(c);
free(f->fd);
free(f);
}
Mount*
newmount(Mhead *mh, Chan *to, int flag, char *spec)
{
Mount *m;
m = smalloc(sizeof(Mount));
m->to = to;
m->head = mh;
incref(&to->ref);
m->mountid = incref(&mountid);
m->mflag = flag;
if(spec != 0)
kstrdup(&m->spec, spec);
return m;
}
void
mountfree(Mount *m)
{
Mount *f;
while(m) {
f = m->next;
cclose(m->to);
m->mountid = 0;
free(m->spec);
free(m);
m = f;
}
}
#ifdef NOTDEF
void
resrcwait(char *reason)
{
char *p;
if(up == 0)
panic("resrcwait");
p = up->psstate;
if(reason) {
up->psstate = reason;
print("%s\n", reason);
}
tsleep(&up->sleep, return0, 0, 300);
up->psstate = p;
}
#endif

190
kern/posix.c Normal file
View File

@ -0,0 +1,190 @@
/*
* Posix generic OS implementation for drawterm.
*/
#include <pthread.h>
#include <time.h>
#include <sys/time.h>
#include <signal.h>
#include <pwd.h>
#include <errno.h>
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
typedef struct Oproc Oproc;
struct Oproc
{
int p[2];
};
static pthread_key_t prdakey;
Proc*
_getproc(void)
{
void *v;
if((v = pthread_getspecific(prdakey)) == nil)
panic("cannot getspecific");
return v;
}
void
_setproc(Proc *p)
{
if(pthread_setspecific(prdakey, p) != 0)
panic("cannot setspecific");
}
void
osinit(void)
{
if(pthread_key_create(&prdakey, 0))
panic("cannot pthread_key_create");
}
#undef pipe
void
osnewproc(Proc *p)
{
Oproc *op;
op = (Oproc*)p->oproc;
if(pipe(op->p) < 0)
panic("cannot pipe");
}
void
osmsleep(int ms)
{
struct timeval tv;
tv.tv_sec = ms / 1000;
tv.tv_usec = (ms % 1000) * 1000; /* micro */
if(select(0, NULL, NULL, NULL, &tv) < 0)
panic("select");
}
void
osyield(void)
{
sched_yield();
}
void
oserrstr(void)
{
char *p;
char buf[ERRMAX];
if((p = strerror(errno)) != nil)
strecpy(up->errstr, up->errstr+ERRMAX, p);
else
snprint(up->errstr, ERRMAX, "unix error %d", errno);
}
void
oserror(void)
{
oserrstr();
nexterror();
}
static void* tramp(void*);
void
osproc(Proc *p)
{
pthread_t pid;
if(pthread_create(&pid, nil, tramp, p)){
oserrstr();
panic("osproc: %r");
}
sched_yield();
}
static void*
tramp(void *vp)
{
Proc *p;
p = vp;
if(pthread_setspecific(prdakey, p))
panic("cannot setspecific");
(*p->fn)(p->arg);
/* BUG: leaks Proc */
pthread_setspecific(prdakey, 0);
pthread_exit(0);
}
void
procsleep(void)
{
int c;
Proc *p;
Oproc *op;
p = up;
op = (Oproc*)p->oproc;
while(read(op->p[0], &c, 1) != 1)
;
}
void
procwakeup(Proc *p)
{
char c;
Oproc *op;
op = (Oproc*)p->oproc;
c = 'a';
write(op->p[1], &c, 1);
}
int randfd;
#undef open
void
randominit(void)
{
if((randfd = open("/dev/urandom", OREAD)) < 0)
if((randfd = open("/dev/random", OREAD)) < 0)
panic("open /dev/random: %r");
}
#undef read
ulong
randomread(void *v, ulong n)
{
int m;
if((m = read(randfd, v, n)) != n)
panic("short read from /dev/random: %d but %d", n, m);
return m;
}
#undef time
long
seconds(void)
{
return time(0);
}
ulong
ticks(void)
{
static long sec0 = 0, usec0;
struct timeval t;
if(gettimeofday(&t, nil) < 0)
return 0;
if(sec0 == 0){
sec0 = t.tv_sec;
usec0 = t.tv_usec;
}
return (t.tv_sec-sec0)*1000+(t.tv_usec-usec0+500)/1000;
}

67
kern/procinit.c Normal file
View File

@ -0,0 +1,67 @@
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
Rgrp *thergrp;
void
procinit0(void)
{
Proc *p;
p = newproc();
p->fgrp = dupfgrp(nil);
p->rgrp = newrgrp();
p->pgrp = newpgrp();
_setproc(p);
up->slash = namec("#/", Atodir, 0, 0);
cnameclose(up->slash->name);
up->slash->name = newcname("/");
up->dot = cclone(up->slash);
}
Ref pidref;
Proc*
newproc(void)
{
Proc *p;
p = mallocz(sizeof(Proc), 1);
p->pid = incref(&pidref);
strcpy(p->user, eve);
p->syserrstr = p->errbuf0;
p->errstr = p->errbuf1;
strcpy(p->text, "drawterm");
osnewproc(p);
return p;
}
int
kproc(char *name, void (*fn)(void*), void *arg)
{
Proc *p;
p = newproc();
p->fn = fn;
p->arg = arg;
p->slash = cclone(up->slash);
p->dot = cclone(up->dot);
p->rgrp = up->rgrp;
if(p->rgrp)
incref(&p->rgrp->ref);
p->pgrp = up->pgrp;
if(up->pgrp)
incref(&up->pgrp->ref);
p->fgrp = up->fgrp;
if(p->fgrp)
incref(&p->fgrp->ref);
strecpy(p->text, sizeof p->text, name);
osproc(p);
return p->pid;
}

1524
kern/qio.c Normal file

File diff suppressed because it is too large Load Diff

94
kern/qlock.c Normal file
View File

@ -0,0 +1,94 @@
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
static void
queue(Proc **first, Proc **last)
{
Proc *t;
t = *last;
if(t == 0)
*first = up;
else
t->qnext = up;
*last = up;
up->qnext = 0;
}
static Proc*
dequeue(Proc **first, Proc **last)
{
Proc *t;
t = *first;
if(t == 0)
return 0;
*first = t->qnext;
if(*first == 0)
*last = 0;
return t;
}
void
qlock(QLock *q)
{
lock(&q->lk);
if(q->hold == 0) {
q->hold = up;
unlock(&q->lk);
return;
}
/*
* Can't assert this because of RWLock
assert(q->hold != up);
*/
queue((Proc**)&q->first, (Proc**)&q->last);
unlock(&q->lk);
procsleep();
}
int
canqlock(QLock *q)
{
lock(&q->lk);
if(q->hold == 0) {
q->hold = up;
unlock(&q->lk);
return 1;
}
unlock(&q->lk);
return 0;
}
void
qunlock(QLock *q)
{
Proc *p;
lock(&q->lk);
/*
* Can't assert this because of RWlock
assert(q->hold == CT);
*/
p = dequeue((Proc**)&q->first, (Proc**)&q->last);
if(p) {
q->hold = p;
unlock(&q->lk);
procwakeup(p);
} else {
q->hold = 0;
unlock(&q->lk);
}
}
int
holdqlock(QLock *q)
{
return q->hold == up;
}

90
kern/rendez.c Normal file
View File

@ -0,0 +1,90 @@
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
void
sleep(Rendez *r, int (*f)(void*), void *arg)
{
int s;
s = splhi();
lock(&r->lk);
lock(&up->rlock);
if(r->p){
print("double sleep %lud %lud\n", r->p->pid, up->pid);
dumpstack();
}
/*
* Wakeup only knows there may be something to do by testing
* r->p in order to get something to lock on.
* Flush that information out to memory in case the sleep is
* committed.
*/
r->p = up;
if((*f)(arg) || up->notepending){
/*
* if condition happened or a note is pending
* never mind
*/
r->p = nil;
unlock(&up->rlock);
unlock(&r->lk);
} else {
/*
* now we are committed to
* change state and call scheduler
*/
up->state = Wakeme;
up->r = r;
/* statistics */
/* m->cs++; */
unlock(&up->rlock);
unlock(&r->lk);
procsleep();
}
if(up->notepending) {
up->notepending = 0;
splx(s);
error(Eintr);
}
splx(s);
}
Proc*
wakeup(Rendez *r)
{
Proc *p;
int s;
s = splhi();
lock(&r->lk);
p = r->p;
if(p != nil){
lock(&p->rlock);
if(p->state != Wakeme || p->r != r)
panic("wakeup: state");
r->p = nil;
p->r = nil;
p->state = Running;
procwakeup(p);
unlock(&p->rlock);
}
unlock(&r->lk);
splx(s);
return p;
}

39
kern/rwlock.c Normal file
View File

@ -0,0 +1,39 @@
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
void
rlock(RWlock *l)
{
qlock(&l->x); /* wait here for writers and exclusion */
lock(&l->lk);
l->readers++;
canqlock(&l->k); /* block writers if we are the first reader */
unlock(&l->lk);
qunlock(&l->x);
}
void
runlock(RWlock *l)
{
lock(&l->lk);
if(--l->readers == 0) /* last reader out allows writers */
qunlock(&l->k);
unlock(&l->lk);
}
void
wlock(RWlock *l)
{
qlock(&l->x); /* wait here for writers and exclusion */
qlock(&l->k); /* wait here for last reader */
}
void
wunlock(RWlock *l)
{
qunlock(&l->k);
qunlock(&l->x);
}

59
kern/screen.h Normal file
View File

@ -0,0 +1,59 @@
typedef struct Mouseinfo Mouseinfo;
typedef struct Mousestate Mousestate;
typedef struct Cursorinfo Cursorinfo;
typedef struct Screeninfo Screeninfo;
#define Mousequeue 16 /* queue can only have Mousequeue-1 elements */
#define Mousewindow 500 /* mouse event window in millisec */
struct Mousestate {
int buttons;
Point xy;
ulong msec;
};
struct Mouseinfo {
Lock lk;
Mousestate queue[Mousequeue];
int ri, wi;
int lastb;
int trans;
int open;
Rendez r;
};
struct Cursorinfo {
Lock lk;
Point offset;
uchar clr[2*16];
uchar set[2*16];
};
struct Screeninfo {
Lock lk;
Memimage *newsoft;
int reshaped;
int depth;
int dibtype;
};
extern Memimage *gscreen;
extern Mouseinfo mouse;
extern Cursorinfo cursor;
extern Screeninfo screen;
void screeninit(void);
void screenload(Rectangle, int, uchar *, Point, int);
void getcolor(ulong, ulong*, ulong*, ulong*);
void setcolor(ulong, ulong, ulong, ulong);
void refreshrect(Rectangle);
void cursorarrow(void);
void setcursor(void);
void mouseset(Point);
void drawflushr(Rectangle);
void flushmemscreen(Rectangle);
uchar *attachscreen(Rectangle*, ulong*, int*, int*, int*, void**);

90
kern/sleep.c Normal file
View File

@ -0,0 +1,90 @@
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
void
sleep(Rendez *r, int (*f)(void*), void *arg)
{
int s;
s = splhi();
lock(&r->lk);
lock(&up->rlock);
if(r->p){
print("double sleep %lud %lud\n", r->p->pid, up->pid);
dumpstack();
}
/*
* Wakeup only knows there may be something to do by testing
* r->p in order to get something to lock on.
* Flush that information out to memory in case the sleep is
* committed.
*/
r->p = up;
if((*f)(arg) || up->notepending){
/*
* if condition happened or a note is pending
* never mind
*/
r->p = nil;
unlock(&up->rlock);
unlock(&r->lk);
} else {
/*
* now we are committed to
* change state and call scheduler
*/
up->state = Wakeme;
up->r = r;
/* statistics */
/* m->cs++; */
unlock(&up->rlock);
unlock(&r->lk);
procsleep();
}
if(up->notepending) {
up->notepending = 0;
splx(s);
error(Eintr);
}
splx(s);
}
Proc*
wakeup(Rendez *r)
{
Proc *p;
int s;
s = splhi();
lock(&r->lk);
p = r->p;
if(p != nil){
lock(&p->rlock);
if(p->state != Wakeme || p->r != r)
panic("wakeup: state");
r->p = nil;
p->r = nil;
p->state = Running;
procwakeup(p);
unlock(&p->rlock);
}
unlock(&r->lk);
splx(s);
return p;
}

18
kern/smalloc.c Normal file
View File

@ -0,0 +1,18 @@
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
void*
smalloc(ulong n)
{
return mallocz(n, 1);
}
void*
malloc(ulong n)
{
return mallocz(n, 1);
}

170
kern/stub.c Normal file
View File

@ -0,0 +1,170 @@
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
void
mallocsummary(void)
{
}
void
pagersummary(void)
{
}
int
iseve(void)
{
return 1;
}
void
setswapchan(Chan *c)
{
USED(c);
}
void
splx(int x)
{
USED(x);
}
int
splhi(void)
{
return 0;
}
int
spllo(void)
{
return 0;
}
void
procdump(void)
{
}
void
scheddump(void)
{
}
void
killbig(void)
{
}
void
dumpstack(void)
{
}
void
xsummary(void)
{
}
void
rebootcmd(int argc, char **argv)
{
USED(argc);
USED(argv);
}
void
kickpager(void)
{
}
int
userwrite(char *a, int n)
{
error(Eperm);
return 0;
}
vlong
todget(vlong *p)
{
if(p)
*p = 0;
return 0;
}
void
todset(vlong a, vlong b, int c)
{
USED(a);
USED(b);
USED(c);
}
void
todsetfreq(vlong a)
{
USED(a);
}
long
hostdomainwrite(char *a, int n)
{
USED(a);
USED(n);
error(Eperm);
return 0;
}
long
hostownerwrite(char *a, int n)
{
USED(a);
USED(n);
error(Eperm);
return 0;
}
void
todinit(void)
{
}
void
rdb(void)
{
}
void
setmalloctag(void *v, ulong tag)
{
USED(v);
USED(tag);
}
int
postnote(Proc *p, int x, char *msg, int flag)
{
USED(p);
USED(x);
USED(msg);
USED(flag);
}
void
exhausted(char *s)
{
panic("out of %s", s);
}
uvlong
fastticks(uvlong *v)
{
if(v)
*v = 1;
return 0;
}

837
kern/syscall.c Normal file
View File

@ -0,0 +1,837 @@
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
Chan*
fdtochan(int fd, int mode, int chkmnt, int iref)
{
Fgrp *f;
Chan *c;
c = 0;
f = up->fgrp;
lock(&f->ref.lk);
if(fd<0 || NFD<=fd || (c = f->fd[fd])==0) {
unlock(&f->ref.lk);
error(Ebadfd);
}
if(iref)
refinc(&c->ref);
unlock(&f->ref.lk);
if(chkmnt && (c->flag&CMSG))
goto bad;
if(mode<0 || c->mode==ORDWR)
return c;
if((mode&OTRUNC) && c->mode==OREAD)
goto bad;
if((mode&~OTRUNC) != c->mode)
goto bad;
return c;
bad:
if(iref)
cclose(c);
error(Ebadusefd);
return nil; /* shut up compiler */
}
static void
fdclose(int fd, int flag)
{
int i;
Chan *c;
Fgrp *f;
f = up->fgrp;
lock(&f->ref.lk);
c = f->fd[fd];
if(c == 0) {
unlock(&f->ref.lk);
return;
}
if(flag) {
if(c==0 || !(c->flag&flag)) {
unlock(&f->ref.lk);
return;
}
}
f->fd[fd] = 0;
if(fd == f->maxfd)
for(i=fd; --i>=0 && f->fd[i]==0; )
f->maxfd = i;
unlock(&f->ref.lk);
cclose(c);
}
static int
newfd(Chan *c)
{
int i;
Fgrp *f;
f = up->fgrp;
lock(&f->ref.lk);
for(i=0; i<NFD; i++)
if(f->fd[i] == 0){
if(i > f->maxfd)
f->maxfd = i;
f->fd[i] = c;
unlock(&f->ref.lk);
return i;
}
unlock(&f->ref.lk);
error("no file descriptors");
return 0;
}
int
sysclose(int fd)
{
if(waserror())
return -1;
fdtochan(fd, -1, 0, 0);
fdclose(fd, 0);
poperror();
return 0;
}
int
syscreate(char *path, int mode, ulong perm)
{
int fd;
Chan *c = 0;
if(waserror()) {
cclose(c);
return -1;
}
openmode(mode); /* error check only */
c = namec(path, Acreate, mode, perm);
fd = newfd((Chan*)c);
poperror();
return fd;
}
int
sysdup(int old, int new)
{
Chan *oc;
Fgrp *f = up->fgrp;
Chan *c = 0;
if(waserror())
return -1;
c = fdtochan(old, -1, 0, 1);
if(new != -1) {
if(new < 0 || NFD <= new) {
cclose(c);
error(Ebadfd);
}
lock(&f->ref.lk);
if(new > f->maxfd)
f->maxfd = new;
oc = f->fd[new];
f->fd[new] = (Chan*)c;
unlock(&f->ref.lk);
if(oc != 0)
cclose(oc);
}
else {
if(waserror()) {
cclose(c);
nexterror();
}
new = newfd((Chan*)c);
poperror();
}
poperror();
return new;
}
int
sysfstat(int fd, char *buf)
{
Chan *c = 0;
if(waserror()) {
cclose(c);
return -1;
}
c = fdtochan(fd, -1, 0, 1);
devtab[c->type]->stat((Chan*)c, buf);
poperror();
cclose(c);
return 0;
}
int
sysfwstat(int fd, char *buf)
{
Chan *c = 0;
if(waserror()) {
cclose(c);
return -1;
}
nameok(buf);
c = fdtochan(fd, -1, 1, 1);
devtab[c->type]->wstat((Chan*)c, buf);
poperror();
cclose(c);
return 0;
}
int
syschdir(char *dir)
{
return 0;
}
long
bindmount(Chan *c0, char *old, int flag, char *spec)
{
int ret;
Chan *c1 = 0;
if(flag>MMASK || (flag&MORDER) == (MBEFORE|MAFTER))
error(Ebadarg);
c1 = namec(old, Amount, 0, 0);
if(waserror()){
cclose(c1);
nexterror();
}
ret = cmount(c0, c1, flag, spec);
poperror();
cclose(c1);
return ret;
}
int
sysbind(char *new, char *old, int flags)
{
long r;
Chan *c0 = 0;
if(waserror()) {
cclose(c0);
return -1;
}
c0 = namec(new, Aaccess, 0, 0);
r = bindmount(c0, old, flags, "");
poperror();
cclose(c0);
return 0;
}
int
sysmount(int fd, char *old, int flags, char *spec)
{
long r;
Chan *c0 = 0, *bc = 0;
struct {
Chan* chan;
char* spec;
int flags;
} mntparam;
if(waserror()) {
cclose(bc);
cclose(c0);
return -1;
}
bc = fdtochan(fd, ORDWR, 0, 1);
mntparam.chan = (Chan*)bc;
mntparam.spec = spec;
mntparam.flags = flags;
c0 = (*devtab[devno('M', 0)].attach)(&mntparam);
cclose(bc);
r = bindmount(c0, old, flags, spec);
poperror();
cclose(c0);
return r;
}
int
sysunmount(char *old, char *new)
{
Chan *cmount = 0, *cmounted = 0;
if(waserror()) {
cclose(cmount);
cclose(cmounted);
return -1;
}
cmount = namec(new, Amount, OREAD, 0);
if(old != 0)
cmounted = namec(old, Aopen, OREAD, 0);
cunmount(cmount, cmounted);
poperror();
cclose(cmount);
cclose(cmounted);
return 0;
}
int
sysopen(char *path, int mode)
{
int fd;
Chan *c = 0;
if(waserror()){
cclose(c);
return -1;
}
openmode(mode); /* error check only */
c = namec(path, Aopen, mode, 0);
fd = newfd((Chan*)c);
poperror();
return fd;
}
long
unionread(Chan *c, void *va, long n)
{
long nr;
Chan *nc = 0;
Pgrp *pg = 0;
pg = up->pgrp;
rlock(&pg->ns);
for(;;) {
if(waserror()) {
runlock(&pg->ns);
nexterror();
}
nc = clone(c->mnt->to, 0);
poperror();
if(c->mountid != c->mnt->mountid) {
runlock(&pg->ns);
cclose(nc);
return 0;
}
/* Error causes component of union to be skipped */
if(waserror()) {
cclose(nc);
goto next;
}
nc = (*devtab[nc->type].open)((Chan*)nc, OREAD);
nc->offset = c->offset;
nr = (*devtab[nc->type].read)((Chan*)nc, va, n, nc->offset);
/* devdirread e.g. changes it */
c->offset = nc->offset;
poperror();
cclose(nc);
if(nr > 0) {
runlock(&pg->ns);
return nr;
}
/* Advance to next element */
next:
c->mnt = c->mnt->next;
if(c->mnt == 0)
break;
c->mountid = c->mnt->mountid;
c->offset = 0;
}
runlock(&pg->ns);
return 0;
}
long
sysread(int fd, void *va, long n)
{
int dir;
Lock *cl;
Chan *c = 0;
if(waserror()) {
cclose(c);
return -1;
}
c = fdtochan(fd, OREAD, 1, 1);
dir = c->qid.path&CHDIR;
if(dir) {
n -= n%DIRLEN;
if(c->offset%DIRLEN || n==0)
error(Etoosmall);
}
if(dir && c->mnt)
n = unionread((Chan*)c, va, n);
else
n = (*devtab[c->type].read)((Chan*)c, va, n, c->offset);
cl = (Lock*)&c->r.l;
lock(cl);
c->offset += n;
unlock(cl);
poperror();
cclose(c);
return n;
}
int
sysremove(char *path)
{
Chan *c = 0;
if(waserror()) {
if(c != 0)
c->type = 0; /* see below */
cclose(c);
return -1;
}
c = namec(path, Aaccess, 0, 0);
(*devtab[c->type].remove)((Chan*)c);
/*
* Remove clunks the fid, but we need to recover the Chan
* so fake it up. rootclose() is known to be a nop.
*/
c->type = 0;
poperror();
cclose(c);
return 0;
}
long
sysseek(int fd, long off, int whence)
{
Dir dir;
Chan *c;
char buf[DIRLEN];
if(waserror())
return -1;
c = fdtochan(fd, -1, 1, 0);
if(c->qid.path & CHDIR)
error(Eisdir);
switch(whence) {
case 0:
c->offset = off;
break;
case 1:
lock(&c->r.l); /* lock for read/write update */
c->offset += off;
off = c->offset;
unlock(&c->r.l);
break;
case 2:
(*devtab[c->type].stat)(c, buf);
convM2D(buf, &dir);
c->offset = dir.length + off;
off = c->offset;
break;
}
poperror();
return off;
}
int
sysstat(char *path, char *buf)
{
Chan *c = 0;
if(waserror()){
cclose(c);
return -1;
}
c = namec(path, Aaccess, 0, 0);
(*devtab[c->type].stat)((Chan*)c, buf);
poperror();
cclose(c);
return 0;
}
long
syswrite(int fd, void *va, long n)
{
Lock *cl;
Chan *c = 0;
if(waserror()) {
cclose(c);
return -1;
}
c = fdtochan(fd, OWRITE, 1, 1);
if(c->qid.path & CHDIR)
error(Eisdir);
n = (*devtab[c->type].write)((Chan*)c, va, n, c->offset);
cl = (Lock*)&c->r.l;
lock(cl);
c->offset += n;
unlock(cl);
poperror();
cclose(c);
return n;
}
int
syswstat(char *path, char *buf)
{
Chan *c = 0;
if(waserror()) {
cclose(c);
return -1;
}
nameok(buf);
c = namec(path, Aaccess, 0, 0);
(*devtab[c->type].wstat)((Chan*)c, buf);
poperror();
cclose(c);
return 0;
}
int
sysdirstat(char *name, Dir *dir)
{
char buf[DIRLEN];
if(sysstat(name, buf) == -1)
return -1;
convM2D(buf, dir);
return 0;
}
int
sysdirfstat(int fd, Dir *dir)
{
char buf[DIRLEN];
if(sysfstat(fd, buf) == -1)
return -1;
convM2D(buf, dir);
return 0;
}
int
sysdirwstat(char *name, Dir *dir)
{
char buf[DIRLEN];
convD2M(dir, buf);
return syswstat(name, buf);
}
int
sysdirfwstat(int fd, Dir *dir)
{
char buf[DIRLEN];
convD2M(dir, buf);
return sysfwstat(fd, buf);
}
long
sysdirread(int fd, Dir *dbuf, long count)
{
int c, n, i, r;
char buf[DIRLEN*50];
n = 0;
count = (count/sizeof(Dir)) * DIRLEN;
while(n < count) {
c = count - n;
if(c > sizeof(buf))
c = sizeof(buf);
r = sysread(fd, buf, c);
if(r == 0)
break;
if(r < 0 || r % DIRLEN)
return -1;
for(i=0; i<r; i+=DIRLEN) {
convM2D(buf+i, dbuf);
dbuf++;
}
n += r;
if(r != c)
break;
}
return (n/DIRLEN) * sizeof(Dir);
}
static int
call(char *clone, char *dest, int *cfdp, char *dir, char *local)
{
int fd, cfd, n;
char *p, name[3*NAMELEN+5], data[3*NAMELEN+10];
cfd = sysopen(clone, ORDWR);
if(cfd < 0){
werrstr("%s: %r", clone);
return -1;
}
/* get directory name */
n = sysread(cfd, name, sizeof(name)-1);
if(n < 0) {
sysclose(cfd);
return -1;
}
name[n] = 0;
sprint(name, "%d", strtoul(name, 0, 0));
p = strrchr(clone, '/');
*p = 0;
if(dir)
snprint(dir, 2*NAMELEN, "%s/%s", clone, name);
snprint(data, sizeof(data), "%s/%s/data", clone, name);
/* connect */
/* set local side (port number, for example) if we need to */
if(local)
snprint(name, sizeof(name), "connect %s %s", dest, local);
else
snprint(name, sizeof(name), "connect %s", dest);
if(syswrite(cfd, name, strlen(name)) < 0){
werrstr("%s failed: %r", name);
sysclose(cfd);
return -1;
}
/* open data connection */
fd = sysopen(data, ORDWR);
if(fd < 0){
werrstr("can't open %s: %r", data);
sysclose(cfd);
return -1;
}
if(cfdp)
*cfdp = cfd;
else
sysclose(cfd);
return fd;
}
int
sysdial(char *dest, char *local, char *dir, int *cfdp)
{
int n, fd, rv;
char *p, net[128], clone[NAMELEN+12];
/* go for a standard form net!... */
p = strchr(dest, '!');
if(p == 0){
snprint(net, sizeof(net), "net!%s", dest);
} else {
strncpy(net, dest, sizeof(net)-1);
net[sizeof(net)-1] = 0;
}
/* call the connection server */
fd = sysopen("/net/cs", ORDWR);
if(fd < 0){
/* no connection server, don't translate */
p = strchr(net, '!');
*p++ = 0;
snprint(clone, sizeof(clone), "/net/%s/clone", net);
return call(clone, p, cfdp, dir, local);
}
/*
* send dest to connection to translate
*/
if(syswrite(fd, net, strlen(net)) < 0){
werrstr("%s: %r", net);
sysclose(fd);
return -1;
}
/*
* loop through each address from the connection server till
* we get one that works.
*/
rv = -1;
sysseek(fd, 0, 0);
while((n = sysread(fd, net, sizeof(net) - 1)) > 0){
net[n] = 0;
p = strchr(net, ' ');
if(p == 0)
continue;
*p++ = 0;
rv = call(net, p, cfdp, dir, local);
if(rv >= 0)
break;
}
sysclose(fd);
return rv;
}
static int
identtrans(char *addr, char *naddr, int na, char *file, int nf)
{
char *p;
char reply[4*NAMELEN];
/* parse the network */
strncpy(reply, addr, sizeof(reply));
reply[sizeof(reply)-1] = 0;
p = strchr(reply, '!');
if(p)
*p++ = 0;
sprint(file, "/net/%.*s/clone", na - sizeof("/net//clone"), reply);
strncpy(naddr, p, na);
naddr[na-1] = 0;
return 1;
}
static int
nettrans(char *addr, char *naddr, int na, char *file, int nf)
{
long n;
int fd;
char *cp;
char reply[4*NAMELEN];
/*
* ask the connection server
*/
fd = sysopen("/net/cs", ORDWR);
if(fd < 0)
return identtrans(addr, naddr, na, file, nf);
if(syswrite(fd, addr, strlen(addr)) < 0){
sysclose(fd);
return -1;
}
sysseek(fd, 0, 0);
n = sysread(fd, reply, sizeof(reply)-1);
sysclose(fd);
if(n <= 0)
return -1;
reply[n] = '\0';
/*
* parse the reply
*/
cp = strchr(reply, ' ');
if(cp == 0)
return -1;
*cp++ = 0;
strncpy(naddr, cp, na);
naddr[na-1] = 0;
strncpy(file, reply, nf);
file[nf-1] = 0;
return 0;
}
int
sysannounce(char *addr, char *dir)
{
char *cp;
int ctl, n, m;
char buf[3*NAMELEN];
char buf2[3*NAMELEN];
char netdir[2*NAMELEN];
char naddr[3*NAMELEN];
/*
* translate the address
*/
if(nettrans(addr, naddr, sizeof(naddr), netdir, sizeof(netdir)) < 0){
werrstr("can't translate address");
return -1;
}
/*
* get a control channel
*/
ctl = sysopen(netdir, ORDWR);
if(ctl<0){
werrstr("can't open control channel");
return -1;
}
cp = strrchr(netdir, '/');
*cp = 0;
/*
* find out which line we have
*/
n = sprint(buf, "%.*s/", 2*NAMELEN+1, netdir);
m = sysread(ctl, &buf[n], sizeof(buf)-n-1);
if(m <= 0) {
sysclose(ctl);
werrstr("can't read control file");
return -1;
}
buf[n+m] = 0;
/*
* make the call
*/
n = sprint(buf2, "announce %.*s", 2*NAMELEN, naddr);
if(syswrite(ctl, buf2, n) != n) {
sysclose(ctl);
werrstr("announcement fails");
return -1;
}
strcpy(dir, buf);
return ctl;
}
int
syslisten(char *dir, char *newdir)
{
char *cp;
int ctl, n, m;
char buf[3*NAMELEN];
/*
* open listen, wait for a call
*/
sprint(buf, "%.*s/listen", 2*NAMELEN+1, dir);
ctl = sysopen(buf, ORDWR);
if(ctl < 0)
return -1;
/*
* find out which line we have
*/
strcpy(buf, dir);
cp = strrchr(buf, '/');
*++cp = 0;
n = cp-buf;
m = sysread(ctl, cp, sizeof(buf) - n - 1);
if(n<=0){
sysclose(ctl);
return -1;
}
buf[n+m] = 0;
strcpy(newdir, buf);
return ctl;
}

1242
kern/sysfile.c Normal file

File diff suppressed because it is too large Load Diff

32
kern/sysproc.c Normal file
View File

@ -0,0 +1,32 @@
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
long
sysexits(ulong *arg)
{
char *status;
char *inval = "invalid exit string";
char buf[ERRMAX];
status = (char*)arg[0];
if(status){
if(waserror())
status = inval;
else{
validaddr((ulong)status, 1, 0);
if(vmemchr(status, 0, ERRMAX) == 0){
memmove(buf, status, ERRMAX);
buf[ERRMAX-1] = 0;
status = buf;
}
}
poperror();
}
pexit(status, 1);
return 0; /* not reached */
}

204
kern/term.c Normal file
View File

@ -0,0 +1,204 @@
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
#include <draw.h>
#include <memdraw.h>
#include "screen.h"
#define MINX 8
#define Backgnd 0xFF /* white */
Memsubfont *memdefont;
struct{
Point pos;
int bwid;
}out;
Lock screenlock;
Memimage *conscol;
Memimage *back;
extern Memimage *gscreen;
static Rectangle flushr;
static Rectangle window;
static Point curpos;
static int h, w;
static void termscreenputs(char*, int);
Point ZP;
static void
screenflush(void)
{
drawflushr(flushr);
flushr = Rect(10000, 10000, -10000, -10000);
}
static void
addflush(Rectangle r)
{
if(flushr.min.x >= flushr.max.x)
flushr = r;
else
combinerect(&flushr, r);
}
static void
screenwin(void)
{
Point p, q;
char *greet;
Memimage *grey;
back = memwhite;
conscol = memblack;
memfillcolor(gscreen, 0x444488FF);
w = memdefont->info[' '].width;
h = memdefont->height;
window.min = addpt(gscreen->r.min, Pt(20,20));
window.max.x = window.min.x + Dx(gscreen->r)*3/4-40;
window.max.y = window.min.y + Dy(gscreen->r)*3/4-100;
memimagedraw(gscreen, window, memblack, ZP, memopaque, ZP, S);
window = insetrect(window, 4);
memimagedraw(gscreen, window, memwhite, ZP, memopaque, ZP, S);
/* a lot of work to get a grey color */
grey = allocmemimage(Rect(0,0,1,1), CMAP8);
grey->flags |= Frepl;
grey->clipr = gscreen->r;
memfillcolor(grey, 0xAAAAAAFF);
memimagedraw(gscreen, Rect(window.min.x, window.min.y,
window.max.x, window.min.y+h+5+6), grey, ZP, nil, ZP, S);
freememimage(grey);
window = insetrect(window, 5);
greet = " Plan 9 Console ";
p = addpt(window.min, Pt(10, 0));
q = memsubfontwidth(memdefont, greet);
memimagestring(gscreen, p, conscol, ZP, memdefont, greet);
window.min.y += h+6;
curpos = window.min;
window.max.y = window.min.y+((window.max.y-window.min.y)/h)*h;
flushmemscreen(gscreen->r);
}
void
terminit(void)
{
memdefont = getmemdefont();
out.pos.x = MINX;
out.pos.y = 0;
out.bwid = memdefont->info[' '].width;
screenwin();
screenputs = termscreenputs;
}
static void
scroll(void)
{
int o;
Point p;
Rectangle r;
o = 8*h;
r = Rpt(window.min, Pt(window.max.x, window.max.y-o));
p = Pt(window.min.x, window.min.y+o);
memimagedraw(gscreen, r, gscreen, p, nil, p, S);
r = Rpt(Pt(window.min.x, window.max.y-o), window.max);
memimagedraw(gscreen, r, back, ZP, nil, ZP, S);
flushmemscreen(gscreen->r);
curpos.y -= o;
}
static void
screenputc(char *buf)
{
Point p;
int w, pos;
Rectangle r;
static int *xp;
static int xbuf[256];
if(xp < xbuf || xp >= &xbuf[sizeof(xbuf)])
xp = xbuf;
switch(buf[0]) {
case '\n':
if(curpos.y+h >= window.max.y)
scroll();
curpos.y += h;
screenputc("\r");
break;
case '\r':
xp = xbuf;
curpos.x = window.min.x;
break;
case '\t':
p = memsubfontwidth(memdefont, " ");
w = p.x;
*xp++ = curpos.x;
pos = (curpos.x-window.min.x)/w;
pos = 8-(pos%8);
r = Rect(curpos.x, curpos.y, curpos.x+pos*w, curpos.y + h);
memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
addflush(r);
curpos.x += pos*w;
break;
case '\b':
if(xp <= xbuf)
break;
xp--;
r = Rect(*xp, curpos.y, curpos.x, curpos.y + h);
memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
addflush(r);
curpos.x = *xp;
break;
default:
p = memsubfontwidth(memdefont, buf);
w = p.x;
if(curpos.x >= window.max.x-w)
screenputc("\n");
*xp++ = curpos.x;
r = Rect(curpos.x, curpos.y, curpos.x+w, curpos.y + h);
memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
memimagestring(gscreen, curpos, conscol, ZP, memdefont, buf);
addflush(r);
curpos.x += w;
}
}
static void
termscreenputs(char *s, int n)
{
int i;
Rune r;
char buf[4];
lock(&screenlock);
while(n > 0){
i = chartorune(&r, s);
if(i == 0){
s++;
--n;
continue;
}
memmove(buf, s, i);
buf[i] = 0;
n -= i;
s += i;
screenputc(buf);
}
screenflush();
unlock(&screenlock);
}

0
kern/todo.c Normal file
View File

14
kern/uart.c Normal file
View File

@ -0,0 +1,14 @@
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
#undef write
void
uartputs(char *s, int n)
{
write(1, s, n);
}

27
kern/waserror.c Normal file
View File

@ -0,0 +1,27 @@
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
Label*
pwaserror(void)
{
if(up->nerrlab == NERR)
panic("error stack overflow");
return &up->errlab[up->nerrlab++];
}
void
nexterror(void)
{
longjmp(up->errlab[--up->nerrlab].buf, 1);
}
void
error(char *e)
{
kstrcpy(up->errstr, e, ERRMAX);
setjmp(up->errlab[NERR-1].buf);
nexterror();
}

18
kern/winduhz.h Normal file
View File

@ -0,0 +1,18 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <fcntl.h>
#include <io.h>
#include <setjmp.h>
#include <direct.h>
#include <process.h>
#include <time.h>
#include <assert.h>
#include <stdarg.h>
/* disable various silly warnings */
#pragma warning( disable : 4245 4305 4244 4102 4761 4090 4028 4024)
typedef __int64 p9_vlong;
typedef unsigned __int64 p9_uvlong;

601
kern/x Normal file
View File

@ -0,0 +1,601 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h> /* for remove, rename */
#include <limits.h>
#ifndef NAME_MAX
# define NAME_MAX 256
#endif
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
typedef struct Ufsinfo Ufsinfo;
enum
{
NUID = 256,
NGID = 256,
MAXPATH = 1024,
MAXCOMP = 128
};
struct Ufsinfo
{
int mode;
int fd;
DIR* dir;
ulong offset;
QLock oq;
char nextname[NAME_MAX];
};
char *base = "/";
static Qid fsqid(char*, struct stat *);
static void fspath(Chan*, char*, char*);
static ulong fsdirread(Chan*, uchar*, int, ulong);
static int fsomode(int);
static char*
lastelem(Chan *c)
{
char *s, *t;
s = c2name(c);
if((t = strrchr(s, '/')) == nil)
return s;
if(t[1] == 0)
return t;
return t+1;
}
static Chan*
fsattach(char *spec)
{
Chan *c;
struct stat stbuf;
static int devno;
Ufsinfo *uif;
if(stat(base, &stbuf) < 0)
error(strerror(errno));
c = devattach('U', spec);
uif = mallocz(sizeof(Ufsinfo), 1);
uif->mode = stbuf.st_mode;
c->aux = uif;
c->dev = devno++;
return c;
}
static Chan*
fsclone(Chan *c, Chan *nc)
{
Ufsinfo *uif;
uif = mallocz(sizeof(Ufsinfo), 1);
*uif = *(Ufsinfo*)c->aux;
nc->aux = uif;
return nc;
}
static int
fswalk1(Chan *c, char *name)
{
struct stat stbuf;
char path[MAXPATH];
Ufsinfo *uif;
fspath(c, name, path);
/* print("** fs walk '%s' -> %s\n", path, name); */
if(stat(path, &stbuf) < 0)
return 0;
uif = c->aux;
uif->mode = stbuf.st_mode;
c->qid = fsqid(path, &stbuf);
return 1;
}
static Walkqid*
fswalk(Chan *c, Chan *nc, char **name, int nname)
{
int i;
Walkqid *wq;
if(nc != nil)
panic("fswalk: nc != nil");
wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
nc = devclone(c);
fsclone(c, nc);
wq->clone = nc;
for(i=0; i<nname; i++){
if(fswalk1(nc, name[i]) == 0)
break;
wq->qid[i] = nc->qid;
}
if(i != nname){
cclose(nc);
wq->clone = nil;
}
wq->nqid = i;
return wq;
}
static int
fsstat(Chan *c, uchar *buf, int n)
{
Dir d;
struct stat stbuf;
char path[MAXPATH];
if(n < BIT16SZ)
error(Eshortstat);
fspath(c, 0, path);
if(stat(path, &stbuf) < 0)
error(strerror(errno));
d.name = lastelem(c);
d.uid = "unknown";
d.gid = "unknown";
d.qid = c->qid;
d.mode = (c->qid.type<<24)|(stbuf.st_mode&0777);
d.atime = stbuf.st_atime;
d.mtime = stbuf.st_mtime;
d.length = stbuf.st_size;
d.type = 'U';
d.dev = c->dev;
return convD2M(&d, buf, n);
}
static Chan*
fsopen(Chan *c, int mode)
{
char path[MAXPATH];
int m, isdir;
Ufsinfo *uif;
m = mode & (OTRUNC|3);
switch(m) {
case 0:
break;
case 1:
case 1|16:
break;
case 2:
case 0|16:
case 2|16:
break;
case 3:
break;
default:
error(Ebadarg);
}
isdir = c->qid.type & QTDIR;
if(isdir && mode != OREAD)
error(Eperm);
m = fsomode(m & 3);
c->mode = openmode(mode);
uif = c->aux;
fspath(c, 0, path);
if(isdir) {
uif->dir = opendir(path);
if(uif->dir == 0)
error(strerror(errno));
}
else {
if(mode & OTRUNC)
m |= O_TRUNC;
uif->fd = open(path, m, 0666);
if(uif->fd < 0)
error(strerror(errno));
}
uif->offset = 0;
c->offset = 0;
c->flag |= COPEN;
return c;
}
static void
fscreate(Chan *c, char *name, int mode, ulong perm)
{
int fd, m;
char path[MAXPATH];
struct stat stbuf;
Ufsinfo *uif;
m = fsomode(mode&3);
fspath(c, name, path);
uif = c->aux;
if(perm & DMDIR) {
if(m)
error(Eperm);
if(mkdir(path, perm & 0777) < 0)
error(strerror(errno));
fd = open(path, 0);
if(fd >= 0) {
chmod(path, perm & 0777);
chown(path, uif->uid, uif->uid);
}
close(fd);
uif->dir = opendir(path);
if(uif->dir == 0)
error(strerror(errno));
}
else {
fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0666);
if(fd >= 0) {
if(m != 1) {
close(fd);
fd = open(path, m);
}
chmod(path, perm & 0777);
chown(path, uif->uid, uif->gid);
}
if(fd < 0)
error(strerror(errno));
uif->fd = fd;
}
if(stat(path, &stbuf) < 0)
error(strerror(errno));
c->qid = fsqid(path, &stbuf);
c->offset = 0;
c->flag |= COPEN;
c->mode = openmode(mode);
}
static void
fsclose(Chan *c)
{
Ufsinfo *uif;
uif = c->aux;
if(c->flag & COPEN) {
if(c->qid.type & QTDIR)
closedir(uif->dir);
else
close(uif->fd);
}
free(uif);
}
static long
fsread(Chan *c, void *va, long n, vlong offset)
{
int fd, r;
Ufsinfo *uif;
if(c->qid.type & QTDIR)
return fsdirread(c, va, n, offset);
uif = c->aux;
qlock(&uif->oq);
if(waserror()) {
qunlock(&uif->oq);
nexterror();
}
fd = uif->fd;
if(uif->offset != offset) {
r = lseek(fd, offset, 0);
if(r < 0)
error(strerror(errno));
uif->offset = offset;
}
n = read(fd, va, n);
if(n < 0)
error(strerror(errno));
uif->offset += n;
qunlock(&uif->oq);
poperror();
return n;
}
static long
fswrite(Chan *c, void *va, long n, vlong offset)
{
int fd, r;
Ufsinfo *uif;
uif = c->aux;
qlock(&uif->oq);
if(waserror()) {
qunlock(&uif->oq);
nexterror();
}
fd = uif->fd;
if(uif->offset != offset) {
r = lseek(fd, offset, 0);
if(r < 0)
error(strerror(errno));
uif->offset = offset;
}
n = write(fd, va, n);
if(n < 0)
error(strerror(errno));
uif->offset += n;
qunlock(&uif->oq);
poperror();
return n;
}
static void
fsremove(Chan *c)
{
int n;
char path[MAXPATH];
fspath(c, 0, path);
if(c->qid.type & QTDIR)
n = rmdir(path);
else
n = remove(path);
if(n < 0)
error(strerror(errno));
}
void
fswstat(Chan *c, uchar *buf, int n)
{
Dir d;
struct stat stbuf;
char old[MAXPATH], new[MAXPATH], dir[MAXPATH];
char strs[MAXPATH*3];
Ufsinfo *uif;
if(convM2D(buf, n, &d, strs) != n)
error(Ebadstat);
fspath(c, 0, old);
if(stat(old, &stbuf) < 0)
error(strerror(errno));
uif = c->aux;
if(d.name[0] && strcmp(d.name, lastelem(c)) != 0) {
fspath(c->parent, 0, dir);
fspath(c, 0, old);
strcpy(new, old);
p = strrchr(new, '/');
strcpy(p+1, d.name);
if(rename(old, new) < 0)
error(strerror(errno));
}
fspath(c, 0, old);
if(~d.mode != 0 && (int)(d.mode&0777) != (int)(stbuf.st_mode&0777)) {
if(chmod(old, d.mode&0777) < 0)
error(strerror(errno));
uif->mode &= ~0777;
uif->mode |= d.mode&0777;
}
/*
p = name2pass(gid, d.gid);
if(p == 0)
error(Eunknown);
if(p->id != stbuf.st_gid) {
if(chown(old, stbuf.st_uid, p->id) < 0)
error(strerror(errno));
uif->gid = p->id;
}
*/
}
static Qid
fsqid(char *p, struct stat *st)
{
Qid q;
int dev;
ulong h;
static int nqdev;
static uchar *qdev;
if(qdev == 0)
qdev = mallocz(65536U, 1);
q.type = 0;
if((st->st_mode&S_IFMT) == S_IFDIR)
q.type = QTDIR;
dev = st->st_dev & 0xFFFFUL;
if(qdev[dev] == 0)
qdev[dev] = ++nqdev;
h = 0;
while(*p != '\0')
h += *p++ * 13;
q.path = (vlong)qdev[dev]<<32;
q.path |= h;
q.vers = st->st_mtime;
return q;
}
static void
fspath(Chan *c, char *ext, char *path)
{
int i, n;
char *comp[MAXCOMP];
strcpy(path, base);
strcat(path, "/");
strcat(path, c2name(c));
if(ext){
strcat(path, "/");
strcat(path, ext);
}
cleanname(path);
}
static int
isdots(char *name)
{
if(name[0] != '.')
return 0;
if(name[1] == '\0')
return 1;
if(name[1] != '.')
return 0;
if(name[2] == '\0')
return 1;
return 0;
}
static int
p9readdir(char *name, Ufsinfo *uif)
{
struct dirent *de;
if(uif->nextname[0]){
strcpy(name, uif->nextname);
uif->nextname[0] = 0;
return 1;
}
de = readdir(uif->dir);
if(de == NULL)
return 0;
strcpy(name, de->d_name);
return 1;
}
static ulong
fsdirread(Chan *c, uchar *va, int count, ulong offset)
{
int i;
Dir d;
long n;
char de[NAME_MAX];
struct stat stbuf;
char path[MAXPATH], dirpath[MAXPATH];
Ufsinfo *uif;
int n;
i = 0;
uif = c->aux;
errno = 0;
if(uif->offset != offset) {
if(offset != 0)
error("bad offset in fsdirread");
uif->offset = offset; /* sync offset */
uif->nextname[0] = 0;
rewinddir(uif->dir);
}
fspath(c, 0, dirpath);
while(i+BIT16SZ < count) {
if(!p9readdir(de, uif))
break;
if(de[0]==0 || isdots(de))
continue;
d.name = de;
sprint(path, "%s/%s", dirpath, de);
memset(&stbuf, 0, sizeof stbuf);
if(stat(path, &stbuf) < 0) {
fprint(2, "dir: bad path %s\n", path);
/* but continue... probably a bad symlink */
}
d.uid = "unknown";
d.gid = "unknown";
d.qid = fsqid(path, &stbuf);
d.mode = (d.qid.type<<24)|(stbuf.st_mode&0777);
d.atime = stbuf.st_atime;
d.mtime = stbuf.st_mtime;
d.length = stbuf.st_size;
d.type = 'U';
d.dev = c->dev;
n = convD2M(&d, (char*)va+i, count-i);
if(n == BIT16SZ){
strcpy(uif->nextname, de);
break;
}
i += n;
}
return i;
}
static int
fsomode(int m)
{
switch(m) {
case 0: /* OREAD */
case 3: /* OEXEC */
return 0;
case 1: /* OWRITE */
return 1;
case 2: /* ORDWR */
return 2;
}
error(Ebadarg);
return 0;
}
Dev fsdevtab = {
'U',
"fs",
devreset,
devinit,
devshutdown,
fsattach,
fswalk,
fsstat,
fsopen,
fscreate,
fsclose,
fsread,
devbread,
fswrite,
devbwrite,
fsremove,
fswstat,
};

177
latin1.c Normal file
View File

@ -0,0 +1,177 @@
#include "u.h"
#include "libc.h"
/*
* The code makes two assumptions: strlen(ld) is 1 or 2; latintab[i].ld can be a
* prefix of latintab[j].ld only when j<i.
*/
struct cvlist
{
char *ld; /* must be seen before using this conversion */
char *si; /* options for last input characters */
Rune so[50]; /* the corresponding Rune for each si entry */
} latintab[] = {
" ", " i", { 0x2423, 0x0131 },
"w", "kqrbnp", { 0x2654, 0x2655, 0x2656, 0x2657, 0x2658, 0x2659, },
"x", "O", { 0x2297, },
"f", "a", { 0x2200, },
"=", "V:=O<>", { 0x21D2, 0x2255, 0x2261, 0x229C, 0x22DC, 0x22DD, },
"V", "=", { 0x21D0, },
"7", "8", { 0x215E, },
"5", "68", { 0x215A, 0x215D, },
"4", "5", { 0x2158, },
"R", "R", { 0x211D, },
"Q", "Q", { 0x211A, },
"P", "P", { 0x2119, },
"C", "CAU", { 0x2102, 0x22C2, 0x22C3, },
"e", "nmsl", { 0x2013, 0x2014, 0x2205, 0x22EF, },
"b", "u0123456789+-=()kqrbnp", { 0x2022, 0x2080, 0x2081, 0x2082, 0x2083, 0x2084, 0x2085, 0x2086, 0x2087, 0x2088, 0x2089, 0x208A, 0x208B, 0x208C, 0x208D, 0x208E, 0x265A, 0x265B, 0x265C, 0x265D, 0x265E, 0x265F, },
"@e", "h", { 0x44D, },
"@\'", "\'", { 0x44A, },
"@s", "hc", { 0x448, 0x449, },
"@c", "h", { 0x447, },
"@t", "s", { 0x446, },
"@k", "h", { 0x445, },
"@z", "h", { 0x436, },
"@y", "euao", { 0x435, 0x44E, 0x44F, 0x451, },
"@E", "Hh", { 0x42D, 0x42D, },
"@S", "HhCc", { 0x428, 0x428, 0x429, 0x429, },
"@C", "Hh", { 0x427, 0x427, },
"@T", "Ss", { 0x426, 0x426, },
"@K", "Hh", { 0x425, 0x425, },
"@Z", "Hh", { 0x416, 0x416, },
"@@", "EZKSTYezksty\'", { 0x415, 0x417, 0x41A, 0x421, 0x422, 0x42B, 0x435, 0x437, 0x43A, 0x441, 0x442, 0x44B, 0x44C, },
"@Y", "OoEeUuAa", { 0x401, 0x401, 0x415, 0x415, 0x42E, 0x42E, 0x42F, 0x42F, },
"@", "ABVGDIJLMNOPRUFXabvgdijlmnoprufx", { 0x410, 0x411, 0x412, 0x413, 0x414, 0x418, 0x419, 0x41B, 0x41C, 0x41D, 0x41E, 0x41F, 0x420, 0x423, 0x424, 0x425, 0x430, 0x431, 0x432, 0x433, 0x434, 0x438, 0x439, 0x43B, 0x43C, 0x43D, 0x43E, 0x43F, 0x440, 0x443, 0x444, 0x445, },
"*", "ABGDEZYHIKLMNCOPRSTUFXQWabgdezyhiklmncoprstufxqw*", { 0x391, 0x392, 0x393, 0x394, 0x395, 0x396, 0x397, 0x398, 0x399, 0x39A, 0x39B, 0x39C, 0x39D, 0x39E, 0x39F, 0x3A0, 0x3A1, 0x3A3, 0x3A4, 0x3A5, 0x3A6, 0x3A7, 0x3A8, 0x3A9, 0x3B1, 0x3B2, 0x3B3, 0x3B4, 0x3B5, 0x3B6, 0x3B7, 0x3B8, 0x3B9, 0x3BA, 0x3BB, 0x3BC, 0x3BD, 0x3BE, 0x3BF, 0x3C0, 0x3C1, 0x3C3, 0x3C4, 0x3C5, 0x3C6, 0x3C7, 0x3C8, 0x3C9, 0x2217, },
"G", "-", { 0x1E4, },
"N", "JjN", { 0x1CA, 0x1CB, 0x2115, },
"2", "-35", { 0x1BB, 0x2154, 0x2156, },
"z", "-", { 0x1B6, },
"Z", "-Z", { 0x1B5, 0x2124, },
"Y", "R", { 0x1A6, },
"h", "v-", { 0x195, 0x210F, },
"$*", "hfk", { 0x3D1, 0x3D5, 0x3F0, },
"$", "fVavgHILlpRBeEFMo", { 0x192, 0x1B2, 0x251, 0x28B, 0x210A, 0x210B, 0x2110, 0x2112, 0x2113, 0x2118, 0x211B, 0x212C, 0x212F, 0x2130, 0x2131, 0x2133, 0x2134, },
"t", "-smefu", { 0x167, 0x3C2, 0x2122, 0x2203, 0x2234, 0x22A2, },
"T", "-u", { 0x166, 0x22A8, },
"L", "-Jj&|", { 0x141, 0x1C7, 0x1C8, 0x22C0, 0x22C1, },
"i", "j-fsbp", { 0x133, 0x268, 0x221E, 0x222B, 0x2286, 0x2287, },
"I", "J-", { 0x132, 0x197, },
"H", "-H", { 0x126, 0x210D, },
"v\"", "Uu", { 0x1D9, 0x1DA, },
"v", "CcDdEeLlNnRrSsTtZzAaIiOoUuGgKkj", { 0x10C, 0x10D, 0x10E, 0x10F, 0x11A, 0x11B, 0x13D, 0x13E, 0x147, 0x148, 0x158, 0x159, 0x160, 0x161, 0x164, 0x165, 0x17D, 0x17E, 0x1CD, 0x1CE, 0x1CF, 0x1D0, 0x1D1, 0x1D2, 0x1D3, 0x1D4, 0x1E6, 0x1E7, 0x1E8, 0x1E9, 0x1F0, },
"u", "AEeGgIiOoUu-a", { 0x102, 0x114, 0x115, 0x11E, 0x11F, 0x12C, 0x12D, 0x14E, 0x14F, 0x16C, 0x16D, 0x289, 0x2191, },
":", "-=()", { 0xF7, 0x2254, 0x2639, 0x263A, },
"a", "ebn", { 0xE6, 0x2194, 0x2220, },
"/", "Oo", { 0xD8, 0xF8, },
"Dv", "Zz", { 0x1C4, 0x1C5, },
"D", "-e", { 0xD0, 0x2206, },
"A", "E", { 0xC6, },
"o", "AaeUuiO", { 0xC5, 0xE5, 0x153, 0x16E, 0x16F, 0x1A3, 0x229A, },
"~!", "=", { 0x2246, },
"~", "ANOanoIiUu-=~", { 0xC3, 0xD1, 0xD5, 0xE3, 0xF1, 0xF5, 0x128, 0x129, 0x168, 0x169, 0x2243, 0x2245, 0x2248, },
"^", "AEIOUaeiouCcGgHhJjSsWwYy", { 0xC2, 0xCA, 0xCE, 0xD4, 0xDB, 0xE2, 0xEA, 0xEE, 0xF4, 0xFB, 0x108, 0x109, 0x11C, 0x11D, 0x124, 0x125, 0x134, 0x135, 0x15C, 0x15D, 0x174, 0x175, 0x176, 0x177, },
"`\"", "Uu", { 0x1DB, 0x1DC, },
"`", "AEIOUaeiou", { 0xC0, 0xC8, 0xCC, 0xD2, 0xD9, 0xE0, 0xE8, 0xEC, 0xF2, 0xF9, },
"?", "?!", { 0xBF, 0x203D, },
"3", "458", { 0xBE, 0x2157, 0x215C, },
"1", "423568", { 0xBC, 0xBD, 0x2153, 0x2155, 0x2159, 0x215B, },
">!", "=~", { 0x2269, 0x22E7, },
">", ">=~<", { 0xBB, 0x2265, 0x2273, 0x2277, },
",", ",CcAaEeGgIiKkLlNnRrSsTtUuOo", { 0xB8, 0xC7, 0xE7, 0x104, 0x105, 0x118, 0x119, 0x122, 0x123, 0x12E, 0x12F, 0x136, 0x137, 0x13B, 0x13C, 0x145, 0x146, 0x156, 0x157, 0x15E, 0x15F, 0x162, 0x163, 0x172, 0x173, 0x1EA, 0x1EB, },
".", ".CcEeGgILlZzO", { 0xB7, 0x10A, 0x10B, 0x116, 0x117, 0x120, 0x121, 0x130, 0x13F, 0x140, 0x17B, 0x17C, 0x2299, },
"p", "gOdrt", { 0xB6, 0x2117, 0x2202, 0x220F, 0x221D, },
"m", "iuo", { 0xB5, 0xD7, 0x2208, },
"\'\"", "Uu", { 0x1D7, 0x1D8, },
"\'", "\'AEIOUYaeiouyCcgLlNnRrSsZz", { 0xB4, 0xC1, 0xC9, 0xCD, 0xD3, 0xDA, 0xDD, 0xE1, 0xE9, 0xED, 0xF3, 0xFA, 0xFD, 0x106, 0x107, 0x123, 0x139, 0x13A, 0x143, 0x144, 0x154, 0x155, 0x15A, 0x15B, 0x179, 0x17A, },
"+", "-O", { 0xB1, 0x2295, },
"dv", "z", { 0x1C6, },
"d", "e-zgda", { 0xB0, 0xF0, 0x2A3, 0x2020, 0x2021, 0x2193, },
"_,", "Oo", { 0x1EC, 0x1ED, },
"_.", "Aa", { 0x1E0, 0x1E1, },
"_\"", "UuAa", { 0x1D5, 0x1D6, 0x1DE, 0x1DF, },
"_", "_AaEeIiOoUu", { 0xAF, 0x100, 0x101, 0x112, 0x113, 0x12A, 0x12B, 0x14C, 0x14D, 0x16A, 0x16B, },
"r", "O\'\"", { 0xAE, 0x2019, 0x201D, },
"-*", "l", { 0x19B, },
"-", "-Dd:HLlTtbIZz2Ggiuh>+~O", { 0xAD, 0xD0, 0xF0, 0xF7, 0x126, 0x141, 0x142, 0x166, 0x167, 0x180, 0x197, 0x1B5, 0x1B6, 0x1BB, 0x1E4, 0x1E5, 0x268, 0x289, 0x210F, 0x2192, 0x2213, 0x2242, 0x2296, },
"n", "oj", { 0xAC, 0x1CC, },
"<!", "=~", { 0x2268, 0x22E6, },
"<", "<-=~>", { 0xAB, 0x2190, 0x2264, 0x2272, 0x2276, },
"s", "a231os0456789+-=()nturbp", { 0xAA, 0xB2, 0xB3, 0xB9, 0xBA, 0xDF, 0x2070, 0x2074, 0x2075, 0x2076, 0x2077, 0x2078, 0x2079, 0x207A, 0x207B, 0x207C, 0x207D, 0x207E, 0x207F, 0x220D, 0x2211, 0x221A, 0x2282, 0x2283, },
"O", "crEIp+-x/.o*=", { 0xA9, 0xAE, 0x152, 0x1A2, 0x2117, 0x2295, 0x2296, 0x2297, 0x2298, 0x2299, 0x229A, 0x229B, 0x229C, },
"\"*", "IUiu", { 0x3AA, 0x3AB, 0x3CA, 0x3CB, },
"\"", "\"AEIOUaeiouyY", { 0xA8, 0xC4, 0xCB, 0xCF, 0xD6, 0xDC, 0xE4, 0xEB, 0xEF, 0xF6, 0xFC, 0xFF, 0x178, },
"S", "S", { 0xA7, },
"|", "|Pp", { 0xA6, 0xDE, 0xFE, },
"y", "$", { 0xA5, },
"g", "$-r", { 0xA4, 0x1E5, 0x2207, },
"l", "$-j\'\"&|z", { 0xA3, 0x142, 0x1C9, 0x2018, 0x201C, 0x2227, 0x2228, 0x22C4, },
"c", "$Oaug", { 0xA2, 0xA9, 0x2229, 0x222A, 0x2245, },
"!~", "-=~", { 0x2244, 0x2247, 0x2249, },
"!", "!?m=<>bp", { 0xA1, 0x203D, 0x2209, 0x2260, 0x226E, 0x226F, 0x2284, 0x2285, },
0, 0, { 0, }
};
/*
* Given 5 characters k[0]..k[4], find the rune or return -1 for failure.
*/
long
unicode(Rune *k)
{
long i, c;
k++; /* skip 'X' */
c = 0;
for(i=0; i<4; i++,k++){
c <<= 4;
if('0'<=*k && *k<='9')
c += *k-'0';
else if('a'<=*k && *k<='f')
c += 10 + *k-'a';
else if('A'<=*k && *k<='F')
c += 10 + *k-'A';
else
return -1;
}
return c;
}
/*
* Given n characters k[0]..k[n-1], find the corresponding rune or return -1 for
* failure, or something < -1 if n is too small. In the latter case, the result
* is minus the required n.
*/
long
latin1(Rune *k, int n)
{
struct cvlist *l;
int c;
char* p;
if(k[0] == 'X'){
if(n>=5)
return unicode(k);
else
return -5;
}
for(l=latintab; l->ld!=0; l++)
if(k[0] == l->ld[0]){
if(n == 1)
return -2;
if(l->ld[1] == 0)
c = k[1];
else if(l->ld[1] != k[1])
continue;
else if(n == 2)
return -3;
else
c = k[2];
for(p=l->si; *p!=0; p++)
if(*p == c)
return l->so[p - l->si];
return -1;
}
return -1;
}

28
libauthsrv/Makefile Normal file
View File

@ -0,0 +1,28 @@
LIB=libauthsrv.a
CC=gcc
CFLAGS=-I../include -I. -c -ggdb -D_THREAD_SAFE -pthread
O=o
OFILES=\
_asgetticket.$O\
_asrdresp.$O\
convA2M.$O\
convM2A.$O\
convM2PR.$O\
convM2T.$O\
convM2TR.$O\
convPR2M.$O\
convT2M.$O\
convTR2M.$O\
nvcsum.$O\
opasstokey.$O\
passtokey.$O\
readnvram.$O\
$(LIB): $(OFILES)
ar r $(LIB) $(OFILES)
ranlib $(LIB)
%.$O: %.c
$(CC) $(CFLAGS) $*.c

Some files were not shown because too many files have changed in this diff Show More