/* * 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. Load more
/* * 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"; void usage(void) { fprint(2, "usage: %s [-vp] [-i srcid] dev ...\n", argv0); exits("usage"); } void notifyf(void *a, char *s) { USED(a); if(strncmp(s, "interrupt", 9) == 0) noted(NCONT); noted(NDFLT); } void main(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 */ int devstat(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 */ int devgen(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));