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

📄 telco.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
#include <u.h>#include <libc.h>#include <auth.h>#include <fcall.h>#define LOGFILE "telco"/* * Rather than reading /adm/users, which is a lot of work for * a toy progdev, we assume all groups have the form *	NNN:user:user: * meaning that each user is the leader of his own group. */enum{	OPERM	= 0x3,		/* mask of all permission types in open mode */	Ndev	= 8,	Nreq	= (Ndev*3)/2,	Nrbuf	= 32*1024,};typedef struct Fid Fid;typedef struct Dev Dev;typedef struct Request Request;typedef struct Type Type;struct Fid{	Qid	qid;	short	busy;	short	open;	int	fid;	Fid	*next;	char	*user;};struct Request{	Request	*next;	Fid	*fid;	ulong	tag;	int	count;	int	flushed;};struct Dev{	Lock;	/* device state */	int	ctl;		/* control fd */	int	data;		/* data fd */	char	*path;		/* to device */	Type	*t;	Type	*baset;	int	speed;	int	fclass;	/* fs emulation */	int	open;	long	perm;	char	*name;	char	*user;	char	msgbuf[128];	Request	*r;	Request *rlast;	/* input reader */	int	monitoring;	/* monitor pid */	char	rbuf[Nrbuf];	char	*rp;	char	*wp;	long	pid;};enum{	Devmask=	(Ndev-1)<<8,		Qlvl1=		0,	Qlvl2=		1,	Qclone=		2,	Qlvl3=		3,	Qdata=		4,	Qctl=		5,	Pexec =		1,	Pwrite = 	2,	Pread = 	4,	Pother = 	1,	Pgroup = 	8,	Powner =	64,};char *names[] ={[Qlvl1]		"/",[Qlvl2]		"telco",[Qclone]	"clone",[Qlvl3]		"",[Qdata]		"data",[Qctl]		"ctl",};#define DEV(q) ((((ulong)(q).path)&Devmask)>>8)#define TYPE(q) (((ulong)(q).path)&((1<<8)-1))#define MKQID(t, i) ((((i)<<8)&Devmask) | (t))enum{	/*	 *  modem specific commands	 */	Cerrorcorrection	= 0,	/* error correction */	Ccompression,			/* compression */	Cflowctl,			/* CTS/RTS */	Crateadjust,			/* follow line speed */	Cfclass2,			/* set up for fax */	Cfclass0,			/* set up for data */	Ncommand,};struct Type{	char	*name;	char	*ident;		/* inquire request */	char	*response;	/* inquire response (strstr) */	char	*basetype;	/* name of base type */	char	*commands[Ncommand];};/* *  Fax setup summary * *	FCLASS=2	- set to service class 2, i.e., one where the fax handles timing  *	FTBC=0		- ??? *	FREL=1		- ??? *	FCQ=1		- receive copy quality checking enabled *	FBOR=1		- set reversed bit order for phase C data *	FCR=1		- the DCE can receive message data, bit 10 in the DIS or *			  DTC frame will be set *	FDIS=,3		- limit com speed to 9600 baud */Type typetab[] ={ {	"Rockwell",		0,	0,	0,	"AT\\N7",	/* auto reliable (V.42, fall back to MNP, to none) */	"AT%C1\\J0",	/* negotiate for compression, don't change port baud rate */	"AT\\Q3",	/* CTS/RTS flow control */ 	"AT\\J1",	"AT+FCLASS=2\rAT+FCR=1\r",	"AT+FCLASS=0", }, {	"ATT2400",	"ATI9",	"E2400",	"Rockwell",	"AT\\N3",	/* auto reliable (MNP, fall back to none) */	0,		0,	0,	0, 	0, }, {	"ATT14400",	"ATI9",	"E14400",	"Rockwell",	0,	0,		0,	0,	0, 	0, }, {	"MT1432",	"ATI2",	"MT1432",	0,	"AT&E1",	/* auto reliable (V.42, fall back to none) */	"AT&E15$BA0",	/* negotiate for compression */	"AT&E4",	/* CTS/RTS flow control */	"AT$BA1",	/* don't change port baud rate */	"AT+FCLASS=2\rAT+FTBC=0\rAT+FREL=1\rAT+FCQ=1\rAT+FBOR=1\rAT+FCR=1\rAT+FDIS=,3",	"AT+FCLASS=0", }, {	"MT2834",	"ATI2",	"MT2834",	"MT1432",	0,	0,	0,	0, 	"AT+FCLASS=2\rAT+FTBC=0\rAT+FREL=1\rAT+FCQ=1\rAT+FBOR=1\rAT+FCR=1",	0, }, {	"VOCAL",	"ATI6",	"144DPL+FAX",	"Rockwell",	"AT\\N3",	/* auto reliable (V.42, fall back to MNP, fall back to none) */	"AT%C3\\J0",	/* negotiate for compression, don't change port baud rate */		0,	0, 	"AT+FCLASS=2\rAT+FTBC=0\rAT+FREL=1\rAT+FCQ=1\rAT+FBOR=1\rAT+FCR=1",	"AT+FCLASS=0", }, { 0, },};/* *  modem return codes */enum{	Ok,	Success,	Failure,	Noise,	Found,};/* *  modem return messages */typedef struct Msg	Msg;struct Msg{	char	*text;	int	type;};Msg msgs[] ={	{ "OK",			Ok, },	{ "NO CARRIER", 	Failure, },	{ "ERROR",		Failure, },	{ "NO DIALTONE",	Failure, },	{ "BUSY",		Failure, },	{ "NO ANSWER",		Failure, },	{ "CONNECT",		Success, },	{ 0,			0 },};Fid	*fids;Dev	*dev;int	ndev;int	mfd[2];char	*user;uchar	mdata[8192+IOHDRSZ];int	messagesize = sizeof mdata;Fcall	thdr;Fcall	rhdr;char	errbuf[ERRMAX];uchar	statbuf[STATMAX];int	pulsed;int	verbose;int	maxspeed = 56000;char	*srcid = "plan9";int	answer = 1;Fid	*newfid(int);int	devstat(Dir*, uchar*, int);int	devgen(Qid, int, Dir*, uchar*, int);void	error(char*);void	io(void);void	*erealloc(void*, ulong);void	*emalloc(ulong);void	usage(void);int	perm(Fid*, Dev*, int);void	setspeed(Dev*, int);int	getspeed(char*, int);char	*dialout(Dev*, char*);void	onhook(Dev*);int	readmsg(Dev*, int, char*);void	monitor(Dev*);int	getinput(Dev*, char*, int);void	serve(Dev*);void	receiver(Dev*);char*	modemtype(Dev*, int, int);char	*rflush(Fid*), *rversion(Fid*),	*rattach(Fid*), *rauth(Fid*), *rwalk(Fid*),	*ropen(Fid*), *rcreate(Fid*),	*rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),	*rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);char 	*(*fcalls[])(Fid*) = {	[Tflush]	rflush,	[Tversion]	rversion,	[Tattach]	rattach,	[Tauth]	rauth,	[Twalk]		rwalk,	[Topen]		ropen,	[Tcreate]	rcreate,	[Tread]		rread,	[Twrite]	rwrite,	[Tclunk]	rclunk,	[Tremove]	rremove,	[Tstat]		rstat,	[Twstat]	rwstat,};char	Eperm[] =	"permission denied";char	Enotdir[] =	"not a directory";char	Enotexist[] =	"file does not exist";char	Ebadaddr[] = 	"bad address";char	Eattn[] = 	"can't get modem's attention";char	Edial[] = 	"can't dial";char	Enoauth[] =	"telco: authentication not required";char	Eisopen[] = 	"file already open for I/O";char	Enodev[] = 	"no free modems";char	Enostream[] =	"stream closed prematurely";voidusage(void){	fprint(2, "usage: %s [-vp] [-i srcid] dev ...\n", argv0);	exits("usage");}voidnotifyf(void *a, char *s){	USED(a);	if(strncmp(s, "interrupt", 9) == 0)		noted(NCONT);	noted(NDFLT);}voidmain(int argc, char *argv[]){	int p[2];	int fd;	char buf[10];	Dev *d;	ARGBEGIN{	case 'p':		pulsed = 1;		break;	case 'v':		verbose = 1;		break;	case 'i':		srcid = ARGF();		break;	case 's':		maxspeed = atoi(ARGF());		break;	case 'n':		answer = 0;		break;	default:		usage();	}ARGEND	if(argc == 0)		usage();	if(argc > Ndev)		argc = Ndev;	if(pipe(p) < 0)		error("pipe failed");	notify(notifyf);	fmtinstall('F', fcallfmt);	user = getuser();	switch(rfork(RFFDG|RFPROC|RFREND|RFNOTEG)){	case -1:		error("fork");	case 0:		close(p[1]);		mfd[0] = mfd[1] = p[0];		break;	default:		close(p[0]);		fd = create("/srv/telco", OWRITE, 0666);		if(fd < 0)			error("create of /srv/telco failed");		sprint(buf, "%d", p[1]);		if(write(fd, buf, strlen(buf)) < 0)			error("writing /srv/telco");		close(fd);		if(mount(p[1], -1, "/net", MBEFORE, "") < 0)			error("mount failed");		exits(0);	}	dev = mallocz(argc*sizeof(Dev), 1);	for(ndev = 0; ndev < argc; ndev++){		d = &dev[ndev];		d->path = argv[ndev];		d->rp = d->wp = d->rbuf;		monitor(d);		d->open++;		onhook(d);		d->open--;	}	io();}/* *  generate a stat structure for a qid */intdevstat(Dir *dir, uchar *buf, int nbuf){	Dev *d;	int t;	static char tmp[10][32];	static int ntmp;	t = TYPE(dir->qid);	if(t != Qlvl3)		dir->name = names[t];	else{		dir->name = tmp[ntmp % nelem(tmp)];		sprint(dir->name, "%lud", DEV(dir->qid));		ntmp++;	}	dir->mode = 0755;	dir->uid = user;	dir->gid = user;	dir->muid = user;	if(t >= Qlvl3){		d = &dev[DEV(dir->qid)];		if(d->open){			dir->mode = d->perm;			dir->uid = d->user;		}	}	if(dir->qid.type & QTDIR)		dir->mode |= DMDIR;	if(t == Qdata){		d = &dev[DEV(dir->qid)];		dir->length = d->wp - d->rp;		if(dir->length < 0)			dir->length += Nrbuf;	} else		dir->length = 0;	dir->atime = time(0);	dir->mtime = dir->atime;	if(buf)		return convD2M(dir, buf, nbuf);	return 0;}/* *  enumerate file's we can walk to from q */intdevgen(Qid q, int i, Dir *d, uchar *buf, int nbuf){	static ulong v;	d->qid.vers = v++;	switch(TYPE(q)){	case Qlvl1:		if(i != 0)			return -1;		d->qid.type = QTDIR;		d->qid.path = Qlvl2;		break;	case Qlvl2:		switch(i){		case -1:			d->qid.type = QTDIR;			d->qid.path = Qlvl1;			break;		case 0:			d->qid.type = QTFILE;			d->qid.path = Qclone;			break;		default:			if(i > ndev)				return -1;			d->qid.type = QTDIR;			d->qid.path = MKQID(Qlvl3, i-1);			break;		}		break;	case Qlvl3:		switch(i){		case -1:			d->qid.type = QTDIR;			d->qid.path = Qlvl2;			break;		case 0:			d->qid.type = QTFILE;			d->qid.path = MKQID(Qdata, DEV(q));			break;		case 1:			d->qid.type = QTFILE;			d->qid.path = MKQID(Qctl, DEV(q));			break;		default:			return -1;		}		break;	default:		return -1;	}	return devstat(d, buf, nbuf);}char*rversion(Fid *){	Fid *f;	for(f = fids; f; f = f->next)		if(f->busy)			rclunk(f);	if(thdr.msize < 256)		return "version: message size too small";	messagesize = thdr.msize;	if(messagesize > sizeof mdata)		messagesize = sizeof mdata;	rhdr.msize = messagesize;	if(strncmp(thdr.version, "9P2000", 6) != 0)		return "unrecognized 9P version";	rhdr.version = "9P2000";	return 0;}char*rflush(Fid *f){	Request *r, **l;	Dev *d;	USED(f);	for(d = dev; d < &dev[ndev]; d++){		lock(d);		for(l = &d->r; r = *l; l = &r->next)			if(r->tag == thdr.oldtag){				*l = r->next;				free(r);				break;			}		unlock(d);	}	return 0;}char *rauth(Fid *f){	USED(f);	return Enoauth;}char*rattach(Fid *f){	f->busy = 1;	f->qid.type = QTDIR;	f->qid.path = Qlvl1;	f->qid.vers = 0;	rhdr.qid = f->qid;	if(thdr.uname[0])		f->user = strdup(thdr.uname);	else		f->user = "none";	return 0;}char*rwalk(Fid *f){	Fid *nf;	int i, nqid;	char *name, *err;	Dir dir;	Qid q;	nf = nil;	if(thdr.fid != thdr.newfid){		if(f->open)			return Eisopen;		if(f->busy == 0)			return Enotexist;		nf = newfid(thdr.newfid);		nf->busy = 1;		nf->open = 0;		nf->qid = f->qid;		nf->user = strdup(f->user);		f = nf;	/* walk f */	}	err = nil;	dir.qid = f->qid;	nqid = 0;	if(thdr.nwname > 0){		for(; nqid < thdr.nwname; nqid++) {			if((dir.qid.type & QTDIR) == 0){				err = Enotdir;				break;			}			name = thdr.wname[nqid];			if(strcmp(name, ".") == 0){				/* nothing to do */			}else if(strcmp(name, "..") == 0) {				if(devgen(f->qid, -1, &dir, 0, 0) < 0)					break;			}			else{				q = dir.qid;				for(i = 0;; i++){					if(devgen(q, i, &dir, 0, 0) < 0)						goto Out;					if(strcmp(name, dir.name) == 0)						break;				}			}			rhdr.wqid[nqid] = dir.qid;		}    Out:		if(nqid == 0 && err == nil)			err = Enotexist;		if(nf != nil && thdr.fid != thdr.newfid && nqid < thdr.nwname)			rclunk(nf);	}	rhdr.nwqid = nqid;	if(nqid > 0 && nqid == thdr.nwname)		f->qid = dir.qid;	return err;}char *ropen(Fid *f){	Dev *d;	int mode, t;	if(f->open)		return Eisopen;	mode = thdr.mode;	mode &= OPERM;	if(f->qid.type & QTDIR){		if(mode != OREAD)			return Eperm;		rhdr.qid = f->qid;		return 0;	}	if(mode==OEXEC)		return Eperm;	t = TYPE(f->qid);	if(t == Qclone){		for(d = dev; d < &dev[ndev]; d++)			if(d->open == 0)				break;		if(d == &dev[ndev])			return Enodev;		f->qid.path = MKQID(Qctl, d-dev);		t = Qctl;	}	switch(t){	case Qdata:	case Qctl:		d = &dev[DEV(f->qid)];		if(d->open == 0){			d->user = strdup(f->user);			d->perm = 0660;		}else {			if(mode==OWRITE || mode==ORDWR)				if(!perm(f, d, Pwrite))					return Eperm;			if(mode==OREAD || mode==ORDWR)				if(!perm(f, d, Pread))					return Eperm;		}		d->open++;		break;	}	rhdr.qid = f->qid;	rhdr.iounit = messagesize - IOHDRSZ;	f->open = 1;	return 0;}char *rcreate(Fid *f){	USED(f);	return Eperm;}/* *  intercept a note */voidtakeanote(void *u, char *note){	USED(u);	if(strstr(note, "flushed"))		noted(NCONT);	noted(NDFLT);}char*rread(Fid *f){	char *buf;	long off, start;	int i, m, n, cnt, t;	Dir dir;	char num[32];	Dev *d;	Request *r;	n = 0;	rhdr.count = 0;	off = thdr.offset;	cnt = thdr.count;	buf = rhdr.data;	t = TYPE(f->qid);	switch(t){	default:		start = 0;		for(i = 0; n < cnt; i++){			m = devgen(f->qid, i, &dir, (uchar*)buf+n, cnt-n);			if(m <= BIT16SZ)				break;			if(start >= off)				n += m;			start += m;		}		break;	case Qctl:		i = sprint(num, "%lud", DEV(f->qid));		if(off < i){			n = cnt;			if(off + n > i)				n = i - off;			memmove(buf, num + off, n);		} else			n = 0;		break;	case Qdata:		d = &dev[DEV(f->qid)];		r = mallocz(sizeof(Request), 1);		r->tag = thdr.tag;		r->count = thdr.count;		r->fid = f;		r->flushed = 0;		lock(d);		if(d->r)			d->rlast->next = r;		else			d->r = r;		d->rlast = r;		serve(d);		unlock(d);		return "";	}	rhdr.count = n;	return 0;}char *cmsg = "connect ";int clen;char*rwrite(Fid *f){	Dev *d;	ulong off;	int cnt;	char *cp;	char buf[64];	off = thdr.offset;	cnt = thdr.count;	switch(TYPE(f->qid)){

⌨️ 快捷键说明

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