⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 consolefs.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
#include <u.h>#include <libc.h>#include <auth.h>#include <fcall.h>#include <bio.h>#include <ndb.h>#include <thread.h>/* *  This fs presents a 1 level file system.  It contains *  up to three files per console (xxx and xxxctl and xxxstat) */typedef struct Console Console;typedef struct Fid Fid;typedef struct Request Request;typedef struct Reqlist Reqlist;typedef struct Fs Fs;enum{	/* last 5 bits of qid.path */	Textern=	0,		/* fake parent of top level */	Ttopdir,			/* top level directory */	Qctl,	Qstat,	Qdata,	Bufsize=	32*1024,	/* chars buffered per reader */	Maxcons=	64,		/* maximum consoles */	Nhash=		64,		/* Fid hash buckets */};#define TYPE(x)		(((ulong)x.path) & 0xf)#define CONS(x)		((((ulong)x.path) >> 4)&0xfff)#define QID(c, x)	(((c)<<4) | (x))struct Request{	Request	*next;	Fid	*fid;	Fs	*fs;	Fcall	f;	uchar	buf[1];};struct Reqlist{	Lock;	Request	*first;	Request *last;};struct Fid{	Lock;	Fid	*next;			/* hash list */	Fid	*cnext;			/* list of Fid's on a console */	int	fid;	int	ref;	int	attached;	int	open;	char	*user;	char	mbuf[Bufsize];		/* message */	int	bufn;	int	used;	Qid	qid;	Console	*c;	char	buf[Bufsize];	char	*rp;	char	*wp;	Reqlist	r;			/* active read requests */};struct Console{	Lock;	char	*name;	char	*dev;	int	speed;	int	cronly;	int	ondemand;		/* open only on demand */	int	chat;			/* chat consoles are special */	int	pid;			/* pid of reader */	int	fd;	int	cfd;	int	sfd;	Fid	*flist;			/* open fids to broadcast to */};struct Fs{	Lock;	int	fd;			/* to kernel mount point */	int	messagesize;	Fid	*hash[Nhash];	Console	*cons[Maxcons];	int	ncons;};extern	void	console(Fs*, char*, char*, int, int, int);extern	Fs*	fsmount(char*);extern	void	fsreader(void*);extern	void	fsrun(void*);extern	Fid*	fsgetfid(Fs*, int);extern	void	fsputfid(Fs*, Fid*);extern	int	fsdirgen(Fs*, Qid, int, Dir*, uchar*, int);extern	void	fsreply(Fs*, Request*, char*);extern	void	fskick(Fs*, Fid*);extern	int	fsreopen(Fs*, Console*);extern	void	fsversion(Fs*, Request*, Fid*);extern	void	fsflush(Fs*, Request*, Fid*);extern	void	fsauth(Fs*, Request*, Fid*);extern	void	fsattach(Fs*, Request*, Fid*);extern	void	fswalk(Fs*, Request*, Fid*);extern	void	fsclwalk(Fs*, Request*, Fid*);extern	void	fsopen(Fs*, Request*, Fid*);extern	void	fscreate(Fs*, Request*, Fid*);extern	void	fsread(Fs*, Request*, Fid*);extern	void	fswrite(Fs*, Request*, Fid*);extern	void	fsclunk(Fs*, Request*, Fid*);extern	void	fsremove(Fs*, Request*, Fid*);extern	void	fsstat(Fs*, Request*, Fid*);extern	void	fswstat(Fs*, Request*, Fid*);void 	(*fcall[])(Fs*, Request*, Fid*) ={	[Tflush]	fsflush,	[Tversion]	fsversion,	[Tauth]	fsauth,	[Tattach]	fsattach,	[Twalk]		fswalk,	[Topen]		fsopen,	[Tcreate]	fscreate,	[Tread]		fsread,	[Twrite]	fswrite,	[Tclunk]	fsclunk,	[Tremove]	fsremove,	[Tstat]		fsstat,	[Twstat]	fswstat};char Eperm[] = "permission denied";char Eexist[] = "file does not exist";char Enotdir[] = "not a directory";char Eisopen[] = "file already open";char Ebadcount[] = "bad read/write count";char Enofid[] = "no such fid";char *consoledb = "/lib/ndb/consoledb";char *mntpt = "/mnt/consoles";int messagesize = 8192+IOHDRSZ;voidfatal(char *fmt, ...){	va_list arg;	char buf[1024];	write(2, "consolefs: ", 10);	va_start(arg, fmt);	vseprint(buf, buf+1024, fmt, arg);	va_end(arg);	write(2, buf, strlen(buf));	write(2, "\n", 1);	threadexitsall(fmt);}void*emalloc(uint n){	void *p;	p = malloc(n);	if(p == nil)		fatal("malloc failed: %r");	memset(p, 0, n);	return p;}int debug;Ndb *db;/* *  any request that can get queued for a delayed reply */Request*allocreq(Fs *fs, int bufsize){	Request *r;	r = emalloc(sizeof(Request)+bufsize);	r->fs = fs;	r->next = nil;	return r;}/* *  for maintaining lists of requests */voidaddreq(Reqlist *l, Request *r){	lock(l);	if(l->first == nil)		l->first = r;	else		l->last->next = r;	l->last = r;	r->next = nil;	unlock(l);}/* *  remove the first request from a list of requests */Request*remreq(Reqlist *l){	Request *r;	lock(l);	r = l->first;	if(r != nil)		l->first = r->next;	unlock(l);	return r;}/* *  remove a request with the given tag from a list of requests */Request*remtag(Reqlist *l, int tag){	Request *or, **ll;	lock(l);	ll = &l->first;	for(or = *ll; or; or = or->next){		if(or->f.tag == tag){			*ll = or->next;			unlock(l);			return or;		}		ll = &or->next;	}	unlock(l);	return nil;}Qidparentqid(Qid q){	if(q.type & QTDIR)		return (Qid){QID(0, Textern), 0, QTDIR};	else		return (Qid){QID(0, Ttopdir), 0, QTDIR};}intfsdirgen(Fs *fs, Qid parent, int i, Dir *d, uchar *buf, int nbuf){	static char name[64];	char *p;	int xcons;	d->uid = d->gid = d->muid = "network";	d->length = 0;	d->atime = time(nil);	d->mtime = d->atime;	d->type = 'C';	d->dev = '0';	switch(TYPE(parent)){	case Textern:		if(i != 0)			return -1;		p = "consoles";		d->mode = DMDIR|0555;		d->qid.type = QTDIR;		d->qid.path = QID(0, Ttopdir);		d->qid.vers = 0;		break;	case Ttopdir:		xcons = i/3;		if(xcons >= fs->ncons)			return -1;		p = fs->cons[xcons]->name;		switch(i%3){		case 0:			if(fs->cons[xcons]->cfd < 0)				return 0;			snprint(name, sizeof name, "%sctl", p);			p = name;			d->qid.type = QTFILE;			d->qid.path = QID(xcons, Qctl);			d->qid.vers = 0;			break;		case 1:			if(fs->cons[xcons]->sfd < 0)				return 0;			snprint(name, sizeof name, "%sstat", p);			p = name;			d->qid.type = QTFILE;			d->qid.path = QID(xcons, Qstat);			d->qid.vers = 0;			break;		case 2:			d->qid.type = QTFILE;			d->qid.path = QID(xcons, Qdata);			d->qid.vers = 0;			break;		}		d->mode = 0666;		break;	default:		return -1;	}	d->name = p;	if(buf != nil)		return convD2M(d, buf, nbuf);	return 1;}/* *  mount the user interface and start a request processor */Fs*fsmount(char *mntpt){	Fs *fs;	int pfd[2], srv;	char buf[32];	int n;	static void *v[2];	fs = emalloc(sizeof(Fs));	if(pipe(pfd) < 0)		fatal("opening pipe: %r");	/* start up the file system process */	v[0] = fs;	v[1] = pfd;	proccreate(fsrun, v, 16*1024);	/* Typically mounted before /srv exists */	if(access("#s/consoles", AEXIST) < 0){		srv = create("#s/consoles", OWRITE, 0666);		if(srv < 0)			fatal("post: %r");		n = sprint(buf, "%d", pfd[1]);		if(write(srv, buf, n) < 0)			fatal("write srv: %r");		close(srv);	}	mount(pfd[1], -1, mntpt, MBEFORE, "");	close(pfd[1]);	return fs;}/* *  reopen a console */intfsreopen(Fs* fs, Console *c){	char buf[128];	static void *v[2];	if(c->pid){		if(postnote(PNPROC, c->pid, "reopen") != 0)			fprint(2, "postnote failed: %r\n");		c->pid = 0;	}	if(c->fd >= 0){		close(c->fd);		close(c->cfd);		close(c->sfd);		c->cfd = -1;		c->fd = -1;		c->sfd = -1;	}	if(c->flist == nil && c->ondemand)		return 0;	c->fd = open(c->dev, ORDWR);	if(c->fd < 0)		return -1;	snprint(buf, sizeof(buf), "%sctl", c->dev);	c->cfd = open(buf, ORDWR);	fprint(c->cfd, "b%d", c->speed);	snprint(buf, sizeof(buf), "%sstat", c->dev);	c->sfd = open(buf, OREAD);	v[0] = fs;	v[1] = c;	proccreate(fsreader, v, 16*1024);	return 0;}voidchange(Fs *fs, Console *c, int doreopen, int speed, int cronly, int ondemand){	lock(c);	if(speed != c->speed){		c->speed = speed;		doreopen = 1;	}	if(ondemand != c->ondemand){		c->ondemand = ondemand;		doreopen = 1;	}	c->cronly = cronly;	if(doreopen)		fsreopen(fs, c);	unlock(c);}/* *  create a console interface */voidconsole(Fs* fs, char *name, char *dev, int speed, int cronly, int ondemand){	Console *c;	char *x;	int i, doreopen;	if(fs->ncons >= Maxcons)		fatal("too many consoles, too little time");	doreopen = 0;	for(i = 0; i < fs->ncons; i++){		c = fs->cons[i];		if(strcmp(name, c->name) == 0){			if(strcmp(dev, c->dev) != 0){				/* new device */				x = c->dev;				c->dev = strdup(dev);				free(x);				doreopen = 1;			}			change(fs, c, doreopen, speed, cronly, ondemand);			return;		}	}	for(i = 0; i < fs->ncons; i++){		c = fs->cons[i];		if(strcmp(dev, c->dev) == 0){			/* at least a rename */			x = c->name;			c->name = strdup(name);			free(x);			change(fs, c, doreopen, speed, cronly, ondemand);			return;		}	}	c = emalloc(sizeof(Console));	fs->cons[fs->ncons] = c;	fs->ncons++;	c->name = strdup(name);	c->dev = strdup(dev);	if(strcmp(c->dev, "/dev/null") == 0) 		c->chat = 1;	else 		c->chat = 0;	c->fd = -1;	c->cfd = -1;	c->sfd = -1;	change(fs, c, 1, speed, cronly, ondemand);}/* *  buffer data from console to a client. *  circular q with writer able to catch up to reader. *  the reader may miss data but always sees an in order sequence. */voidfromconsole(Fid *f, char *p, int n){	char *rp, *wp, *ep;	int pass;	lock(f);	rp = f->rp;	wp = f->wp;	ep = f->buf + sizeof(f->buf);	pass = 0;	while(n--){		*wp++ = *p++;		if(wp >= ep)			wp = f->buf;		if(rp == wp)			pass = 1;	}	f->wp = wp;	/*  we overtook the read pointer, push it up so readers always	 *  see the tail of what was written	 */	if(pass){		wp++;		if(wp >= ep)			f->rp = f->buf;		else			f->rp = wp;	}	unlock(f);}/* *  broadcast a list of members to all listeners */voidbcastmembers(Fs *fs, Console *c, char *msg, Fid *f){	int n;	Fid *fl;	char buf[512];	sprint(buf, "[%s%s", msg, f->user);	for(fl = c->flist; fl != nil && strlen(buf) + 64 < sizeof(buf); fl = fl->cnext){		if(f == fl)			continue;		strcat(buf, ", ");		strcat(buf, fl->user);	}	strcat(buf, "]\n");	n = strlen(buf);	for(fl = c->flist; fl; fl = fl->cnext){		fromconsole(fl, buf, n);		fskick(fs, fl);	}}voidhandler(void*, char *msg){	if(strstr(msg, "reopen"))		noted(NCONT);	noted(NDFLT);}/* *  a process to read console output and broadcast it (one per console) */voidfsreader(void *v){	int n;	Fid *fl;	char buf[1024];	Fs *fs;	Console *c;	void **a;	a = v;	fs = a[0];	c = a[1];	c->pid = getpid();	notify(handler);	if(c->chat)		threadexits(nil);	for(;;){		n = read(c->fd, buf, sizeof(buf));		if(n < 0)			break;		lock(c);		for(fl = c->flist; fl; fl = fl->cnext){			fromconsole(fl, buf, n);			fskick(fs, fl);		}		unlock(c);	}}voidreaddb(Fs *fs){	Ndbtuple *t, *nt;	char *dev, *cons;	int cronly, speed, ondemand;	ndbreopen(db);	/* start a listener for each console */	for(;;){		t = ndbparse(db);		if(t == nil)			break;		dev = nil;		cons = nil;		speed = 9600;		cronly = 0;		ondemand = 0;		for(nt = t; nt; nt = nt->entry){			if(strcmp(nt->attr, "console") == 0)				cons = nt->val;			else if(strcmp(nt->attr, "dev") == 0)				dev = nt->val;			else if(strcmp(nt->attr, "speed") == 0)				speed = atoi(nt->val);			else if(strcmp(nt->attr, "cronly") == 0)				cronly = 1;			else if(strcmp(nt->attr, "openondemand") == 0)				ondemand = 1;		}		if(dev != nil && cons != nil)			console(fs, cons, dev, speed, cronly, ondemand);		ndbfree(t);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -