1564 lines · 26.0 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #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));

Lines 1–500 of 1564.