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

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,
};