1914 lines · 34.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>#include <bio.h>#include <ctype.h>#include <ndb.h>#include <ip.h>#include <String.h> enum{	Nreply=			20,	Maxreply=		256,	Maxrequest=		128,	Maxpath=		128,	Maxfdata=		8192,	Maxhost=		64,		/* maximum host name size */	Maxservice=		64,		/* maximum service name size */ 	Qdir=			0,	Qcs=			1,}; typedef struct Mfile	Mfile;typedef struct Mlist	Mlist;typedef struct Network	Network;typedef struct Flushreq	Flushreq;typedef struct Job	Job; int vers;		/* incremented each clone/attach */ struct Mfile{	int		busy; 	char		*user;	Qid		qid;	int		fid; 	/*	 *  current request	 */	char		*net;	char		*host;	char		*serv;	char		*rem; 	/*	 *  result of the last lookup	 */	Network		*nextnet;	int		nreply;	char		*reply[Nreply];	int		replylen[Nreply];}; struct Mlist{	Mlist	*next;	Mfile	mf;};  /* *  active requests */struct Job{	Job	*next;	int	flushed;	Fcall	request;	Fcall	reply;};Lock	joblock;Job	*joblist; Mlist	*mlist;int	mfd[2];int	debug;int	paranoia;int	ipv6lookups = 1;jmp_buf	masterjmp;	/* return through here after a slave process has been created */int	*isslave;	/* *isslave non-zero means this is a slave process */char	*dbfile;Ndb	*db, *netdb; void	rversion(Job*);void	rflush(Job*);void	rattach(Job*, Mfile*);char*	rwalk(Job*, Mfile*);void	ropen(Job*, Mfile*);void	rcreate(Job*, Mfile*);void	rread(Job*, Mfile*);void	rwrite(Job*, Mfile*);void	rclunk(Job*, Mfile*);void	rremove(Job*, Mfile*);void	rstat(Job*, Mfile*);void	rwstat(Job*, Mfile*);void	rauth(Job*);void	sendmsg(Job*, char*);void	error(char*);void	mountinit(char*, char*);void	io(void);void	ndbinit(void);void	netinit(int);void	netadd(char*);char	*genquery(Mfile*, char*);char*	ipinfoquery(Mfile*, char**, int);int	needproto(Network*, Ndbtuple*);int	lookup(Mfile*);Ndbtuple*	reorder(Ndbtuple*, Ndbtuple*);void	ipid(void);void	readipinterfaces(void);void*	emalloc(int);char*	estrdup(char*);Job*	newjob(void);void	freejob(Job*);void	setext(char*, int, char*);void	cleanmf(Mfile*); extern void	paralloc(void); Lock	dblock;		/* mutex on database operations */Lock	netlock;	/* mutex for netinit() */ char	*logfile = "cs";char	*paranoiafile = "cs.paranoia"; char	mntpt[Maxpath];char	netndb[Maxpath]; /* *  Network specific translators */Ndbtuple*	iplookup(Network*, char*, char*, int);char*		iptrans(Ndbtuple*, Network*, char*, char*, int);Ndbtuple*	telcolookup(Network*, char*, char*, int);char*		telcotrans(Ndbtuple*, Network*, char*, char*, int);Ndbtuple*	dnsiplookup(char*, Ndbs*); struct Network{	char		*net;	Ndbtuple	*(*lookup)(Network*, char*, char*, int);	char		*(*trans)(Ndbtuple*, Network*, char*, char*, int);	int		considered;		/* flag: ignored for "net!"? */	int		fasttimeouthack;	/* flag. was for IL */	Network		*next;}; enum{	Ntcp = 0,}; /* *  net doesn't apply to (r)udp, icmp(v6), or telco (for speed). */Network network[] = {[Ntcp]	{ "tcp",	iplookup,	iptrans,	0 },	{ "udp",	iplookup,	iptrans,	1 },	{ "icmp",	iplookup,	iptrans,	1 },	{ "icmpv6",	iplookup,	iptrans,	1 },	{ "rudp",	iplookup,	iptrans,	1 },	{ "ssh",	iplookup,	iptrans,	1 },	{ "telco",	telcolookup,	telcotrans,	1 },	{ 0 },}; Lock ipifclock;Ipifc *ipifcs; char	eaddr[16];		/* ascii ethernet address */char	ipaddr[64];		/* ascii internet address */uchar	ipa[IPaddrlen];		/* binary internet address */char	*mysysname; Network *netlist;		/* networks ordered by preference */Network *last; static voidnstrcpy(char *to, char *from, int len){	strncpy(to, from, len);	to[len-1] = 0;} voidusage(void){	fprint(2, "usage: %s [-dn] [-f ndb-file] [-x netmtpt]\n", argv0);	exits("usage");} /* * based on libthread's threadsetname, but drags in less library code. * actually just sets the arguments displayed. */voidprocsetname(char *fmt, ...){	int fd;	char *cmdname;	char buf[128];	va_list arg; 	va_start(arg, fmt);	cmdname = vsmprint(fmt, arg);	va_end(arg);	if (cmdname == nil)		return;	snprint(buf, sizeof buf, "#p/%d/args", getpid());	if((fd = open(buf, OWRITE)) >= 0){		write(fd, cmdname, strlen(cmdname)+1);		close(fd);	}	free(cmdname);} voidmain(int argc, char *argv[]){	int justsetname;	char ext[Maxpath], servefile[Maxpath]; 	justsetname = 0;	setnetmtpt(mntpt, sizeof(mntpt), nil);	ext[0] = 0;	ARGBEGIN{	case '4':		ipv6lookups = 0;		break;	case 'd':		debug = 1;		break;	case 'f':		dbfile = EARGF(usage());		break;	case 'n':		justsetname = 1;		break;	case 'x':		setnetmtpt(mntpt, sizeof(mntpt), EARGF(usage()));		setext(ext, sizeof(ext), mntpt);		break;	}ARGEND	USED(argc);	USED(argv); 	rfork(RFREND|RFNOTEG); 	snprint(servefile, sizeof(servefile), "#s/cs%s", ext);	snprint(netndb, sizeof(netndb), "%s/ndb", mntpt);	unmount(servefile, mntpt);	remove(servefile); 	fmtinstall('E', eipfmt);	fmtinstall('I', eipfmt);	fmtinstall('M', eipfmt);	fmtinstall('F', fcallfmt); 	ndbinit();	netinit(0); 	if(!justsetname){		mountinit(servefile, mntpt);		io();	}	exits(0);} /* *  if a mount point is specified, set the cs extention to be the mount point *  with '_'s replacing '/'s */voidsetext(char *ext, int n, char *p){	int i, c; 	n--;	for(i = 0; i < n; i++){		c = p[i];		if(c == 0)			break;		if(c == '/')			c = '_';		ext[i] = c;	}	ext[i] = 0;} voidmountinit(char *service, char *mntpt){	int f;	int p[2];	char buf[32]; 	if(pipe(p) < 0)		error("pipe failed"); 	/*	 *  make a /srv/cs	 */	f = create(service, OWRITE|ORCLOSE, 0666);	if(f < 0)		error(service);	snprint(buf, sizeof(buf), "%d", p[1]);	if(write(f, buf, strlen(buf)) != strlen(buf))		error("write /srv/cs"); 	switch(rfork(RFFDG|RFPROC|RFNAMEG)){	case 0:		close(p[1]);		procsetname("%s", mntpt);		break;	case -1:		error("fork failed\n");	default:		/*		 *  put ourselves into the file system		 */		close(p[0]);		if(mount(p[1], -1, mntpt, MAFTER, "") < 0)			error("mount failed\n");		_exits(0);	}	mfd[0] = mfd[1] = p[0];} voidndbinit(void){	db = ndbopen(dbfile);	if(db == nil)		error("can't open network database"); 	netdb = ndbopen(netndb);	if(netdb != nil){		netdb->nohash = 1;		db = ndbcat(netdb, db);	}} Mfile*newfid(int fid){	Mlist *f, *ff;	Mfile *mf; 	ff = 0;	for(f = mlist; f; f = f->next)		if(f->mf.busy && f->mf.fid == fid)			return &f->mf;		else if(!ff && !f->mf.busy)			ff = f;	if(ff == 0){		ff = emalloc(sizeof *f);		ff->next = mlist;		mlist = ff;	}	mf = &ff->mf;	memset(mf, 0, sizeof *mf);	mf->fid = fid;	return mf;} Job*newjob(void){	Job *job; 	job = mallocz(sizeof(Job), 1);	lock(&joblock);	job->next = joblist;	joblist = job;	job->request.tag = -1;	unlock(&joblock);	return job;} voidfreejob(Job *job){	Job **l; 	lock(&joblock);	for(l = &joblist; *l; l = &(*l)->next){		if((*l) == job){			*l = job->next;			free(job);			break;		}	}	unlock(&joblock);} voidflushjob(int tag){	Job *job; 	lock(&joblock);	for(job = joblist; job; job = job->next){		if(job->request.tag == tag && job->request.type != Tflush){			job->flushed = 1;			break;		}	}	unlock(&joblock);} voidio(void){	long n;	Mfile *mf;	int slaveflag;	uchar mdata[IOHDRSZ + Maxfdata];	Job *job; 	/*	 *  if we ask dns to fulfill requests,	 *  a slave process is created to wait for replies.  The	 *  master process returns immediately via a longjmp	 *  through 'masterjmp'.	 *	 *  *isslave is a pointer into the call stack to a variable	 *  that tells whether or not the current process is a slave.	 */	slaveflag = 0;		/* init slave variable */	isslave = &slaveflag;	setjmp(masterjmp); 	for(;;){		n = read9pmsg(mfd[0], mdata, sizeof mdata);		if(n<=0)			error("mount read");		job = newjob();		if(convM2S(mdata, n, &job->request) != n){			syslog(1, logfile, "format error %ux %ux %ux %ux %ux",				mdata[0], mdata[1], mdata[2], mdata[3], mdata[4]);			freejob(job);			continue;		}		lock(&dblock);		mf = newfid(job->request.fid);		if(debug)			syslog(0, logfile, "%F", &job->request);  		switch(job->request.type){		default:			syslog(1, logfile, "unknown request type %d", job->request.type);			break;		case Tversion:			rversion(job);			break;		case Tauth:			rauth(job);			break;		case Tflush:			rflush(job);			break;		case Tattach:			rattach(job, mf);			break;		case Twalk:			rwalk(job, mf);			break;		case Topen:			ropen(job, mf);			break;		case Tcreate:			rcreate(job, mf);			break;		case Tread:			rread(job, mf);			break;		case Twrite:			rwrite(job, mf);			break;		case Tclunk:			rclunk(job, mf);			break;		case Tremove:			rremove(job, mf);			break;		case Tstat:

Lines 1–500 of 1914.