a
This commit is contained in:
50
kern/Makefile
Normal file
50
kern/Makefile
Normal 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
165
kern/allocb.c
Normal 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
46
kern/cache.c
Normal 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
1496
kern/chan.c
Normal file
File diff suppressed because it is too large
Load Diff
519
kern/dat.h
Normal file
519
kern/dat.h
Normal 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
31
kern/data.c
Normal 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
468
kern/dev.c
Normal 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
1238
kern/devcons.c
Normal file
File diff suppressed because it is too large
Load Diff
2100
kern/devdraw.c
Normal file
2100
kern/devdraw.c
Normal file
File diff suppressed because it is too large
Load Diff
638
kern/devfs.c
Normal file
638
kern/devfs.c
Normal 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
209
kern/devip-posix.c
Normal 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
208
kern/devip-win.c
Normal 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
936
kern/devip.c
Normal 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
17
kern/devip.h
Normal 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
1214
kern/devmnt.c
Normal file
File diff suppressed because it is too large
Load Diff
237
kern/devmouse.c
Normal file
237
kern/devmouse.c
Normal 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
704
kern/devntfs.c
Normal 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
398
kern/devpipe.c
Normal 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
268
kern/devroot.c
Normal 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
1512
kern/devssl.c
Normal file
File diff suppressed because it is too large
Load Diff
27
kern/devtab.c
Normal file
27
kern/devtab.c
Normal 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
50
kern/error.c
Normal 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
50
kern/error.h
Normal 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
821
kern/exportfs.c
Normal 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
377
kern/fns.h
Normal 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
47
kern/mkfile
Normal 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
133
kern/netif.h
Normal 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
184
kern/os-windows.c
Normal 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
113
kern/parse.c
Normal 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
272
kern/pgrp.c
Normal 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
190
kern/posix.c
Normal 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
67
kern/procinit.c
Normal 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
1524
kern/qio.c
Normal file
File diff suppressed because it is too large
Load Diff
94
kern/qlock.c
Normal file
94
kern/qlock.c
Normal 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
90
kern/rendez.c
Normal 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
39
kern/rwlock.c
Normal 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
59
kern/screen.h
Normal 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
90
kern/sleep.c
Normal 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
18
kern/smalloc.c
Normal 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
170
kern/stub.c
Normal 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
837
kern/syscall.c
Normal 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
1242
kern/sysfile.c
Normal file
File diff suppressed because it is too large
Load Diff
32
kern/sysproc.c
Normal file
32
kern/sysproc.c
Normal 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
204
kern/term.c
Normal 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
0
kern/todo.c
Normal file
14
kern/uart.c
Normal file
14
kern/uart.c
Normal 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
27
kern/waserror.c
Normal 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
18
kern/winduhz.h
Normal 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
601
kern/x
Normal 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,
|
||||
};
|
Reference in New Issue
Block a user