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

📄 u9fs.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
		sysfatal("strdup(%.20s) fails", p);	return p;}char*estrpath(char *p, char *q){	char *r, *s;	if(strcmp(q, "..") == 0){		r = estrdup(p);		if((s = strrchr(r, '/')) && s > r)			*s = '\0';		else if(s == r)			s[1] = '\0';		return r;	}	r = emalloc(strlen(p)+1+strlen(q)+1);	strcpy(r, p);	if(r[0]=='\0' || r[strlen(r)-1] != '/')		strcat(r, "/");	strcat(r, q);	return r;}Fid *fidtab[1];Fid*lookupfid(int fid){	Fid *f;	for(f=fidtab[fid%nelem(fidtab)]; f; f=f->next)		if(f->fid == fid)			return f;	return nil;}Fid*newfid(int fid, char **ep){	Fid *f;	if(lookupfid(fid) != nil){		*ep = Efidactive;		return nil;	}	f = emalloc(sizeof(*f));	f->next = fidtab[fid%nelem(fidtab)];	if(f->next)		f->next->prev = f;	fidtab[fid%nelem(fidtab)] = f;	f->fid = fid;	f->fd = -1;	f->omode = -1;	return f;}Fid*newauthfid(int fid, void *magic, char **ep){	Fid *af;	af = newfid(fid, ep);	if (af == nil)		return nil;	af->auth = 1;	af->authmagic = magic;	return af;}Fid*oldfidex(int fid, int auth, char **ep){	Fid *f;	if((f = lookupfid(fid)) == nil){		*ep = Ebadfid;		return nil;	}	if (auth != -1 && f->auth != auth) {		*ep = Ebadfid;		return nil;	}	if (!f->auth) {		if(userchange(f->u, ep) < 0)			return nil;	}	return f;}Fid*oldfid(int fid, char **ep){	return oldfidex(fid, 0, ep);}Fid*oldauthfid(int fid, void **magic, char **ep){	Fid *af;	af = oldfidex(fid, 1, ep);	if (af == nil)		return nil;	*magic = af->authmagic;	return af;}voidfreefid(Fid *f){	if(f->prev)		f->prev->next = f->next;	else		fidtab[f->fid%nelem(fidtab)] = f->next;	if(f->next)		f->next->prev = f->prev;	if(f->dir)		closedir(f->dir);	if(f->fd)		close(f->fd);	free(f->path);	free(f);}intfidstat(Fid *fid, char **ep){	if(stat(fid->path, &fid->st) < 0){		fprint(2, "fidstat(%s) failed\n", fid->path);		if(ep)			*ep = strerror(errno);		return -1;	}	if(S_ISDIR(fid->st.st_mode))		fid->st.st_size = 0;	return 0;}intuserchange(User *u, char **ep){	if(defaultuser)		return 0;	if(setreuid(0, 0) < 0){		fprint(2, "setreuid(0, 0) failed\n");		*ep = "cannot setuid back to root";		return -1;	}	/*	 * Initgroups does not appear to be SUSV standard.	 * But it exists on SGI and on Linux, which makes me	 * think it's standard enough.  We have to do something	 * like this, and the closest other function I can find is	 * setgroups (which initgroups eventually calls).	 * Setgroups is the same as far as standardization though,	 * so we're stuck using a non-SUSV call.  Sigh.	 */	if(initgroups(u->name, u->defaultgid) < 0)		fprint(2, "initgroups(%s) failed: %s\n", u->name, strerror(errno));	if(setreuid(-1, u->id) < 0){		fprint(2, "setreuid(-1, %s) failed\n", u->name);		*ep = strerror(errno);		return -1;	}	return 0;}/* * We do our own checking here, then switch to root temporarily * to set our gid.  In a perfect world, you'd be allowed to set your * egid to any of the supplemental groups of your euid, but this * is not the case on Linux 2.2.14 (and perhaps others). * * This is a race, of course, but it's a race against processes * that can edit the group lists.  If you can do that, you can * change your own group without our help. */intgroupchange(User *u, User *g, char **ep){	if(g == nil)		return -1;	if(!useringroup(u, g)){		if(chatty9p)			fprint(2, "%s not in group %s\n", u->name, g->name);		*ep = Enotingroup;		return -1;	}	setreuid(0,0);	if(setregid(-1, g->id) < 0){		fprint(2, "setegid(%s/%d) failed in groupchange\n", g->name, g->id);		*ep = strerror(errno);		return -1;	}	if(userchange(u, ep) < 0)		return -1;	return 0;}/* * An attempt to enforce permissions by looking at the  * file system.  Separation of checking permission and * actually performing the action is a terrible idea, of  * course, so we use setreuid for most of the permission * enforcement.  This is here only so we can give errors * on open(ORCLOSE) in some cases. */intuserperm(User *u, char *path, int type, int need){	char *p, *q;	int i, have;	struct stat st;	User *g;	switch(type){	default:		fprint(2, "bad type %d in userperm\n", type);		return -1;	case Tdot:		if(stat(path, &st) < 0){			fprint(2, "userperm: stat(%s) failed\n", path);			return -1;		}		break;	case Tdotdot:		p = estrdup(path);		if((q = strrchr(p, '/'))==nil){			fprint(2, "userperm(%s, ..): bad path\n", p);			free(p);			return -1;		}		if(q > p)			*q = '\0';		else			*(q+1) = '\0';		if(stat(p, &st) < 0){			fprint(2, "userperm: stat(%s) (dotdot of %s) failed\n",				p, path);			free(p);			return -1;		}		free(p);		break;	}	if(u == none){		fprint(2, "userperm: none wants %d in 0%luo\n", need, st.st_mode);		have = st.st_mode&7;		if((have&need)==need)			return 0;		return -1;	}	have = st.st_mode&7;	if((uid_t)u->id == st.st_uid)		have |= (st.st_mode>>6)&7;	if((have&need)==need)		return 0;	if(((have|((st.st_mode>>3)&7))&need) != need)	/* group won't help */		return -1;	g = gid2user(st.st_gid);	for(i=0; i<g->nmem; i++){		if(strcmp(g->mem[i], u->name) == 0){			have |= (st.st_mode>>3)&7;			break;		}	}	if((have&need)==need)		return 0;	return -1;}intuserwalk(User *u, char **path, char *elem, Qid *qid, char **ep){	char *npath;	struct stat st;	npath = estrpath(*path, elem);	if(stat(npath, &st) < 0){		free(npath);		*ep = strerror(errno);		return -1;	}	*qid = stat2qid(&st);	free(*path);	*path = npath;	return 0;}intuseropen(Fid *fid, int omode, char **ep){	int a, o;	/*	 * Check this anyway, to try to head off problems later.	 */	if((omode&ORCLOSE) && userperm(fid->u, fid->path, Tdotdot, W_OK) < 0){		*ep = Eperm;		return -1;	}	switch(omode&3){	default:		*ep = "programmer error";		return -1;	case OREAD:		a = R_OK;		o = O_RDONLY;		break;	case ORDWR:		a = R_OK|W_OK;		o = O_RDWR;		break;	case OWRITE:		a = W_OK;		o = O_WRONLY;		break;	case OEXEC:		a = X_OK;		o = O_RDONLY;		break;	}	if(omode & OTRUNC){		a |= W_OK;		o |= O_TRUNC;	}	if(S_ISDIR(fid->st.st_mode)){		if(a != R_OK){			fprint(2, "attempt by %s to open dir %d\n", fid->u->name, omode);			*ep = Eperm;			return -1;		}		if((fid->dir = opendir(fid->path)) == nil){			*ep = strerror(errno);			return -1;		}	}else{		/*		 * This is wrong because access used the real uid		 * and not the effective uid.  Let the open sort it out.		 *		if(access(fid->path, a) < 0){			*ep = strerror(errno);			return -1;		}		 *		 */		if((fid->fd = open(fid->path, o)) < 0){			*ep = strerror(errno);			return -1;		}	}	fid->omode = omode;	return 0;}intusercreate(Fid *fid, char *elem, int omode, long perm, char **ep){	int o, m;	char *opath, *npath;	struct stat st, parent;	if(stat(fid->path, &parent) < 0){		*ep = strerror(errno);		return -1;	}	/*	 * Change group so that created file has expected group	 * by Plan 9 semantics.  If that fails, might as well go	 * with the user's default group.	 */	if(groupchange(fid->u, gid2user(parent.st_gid), ep) < 0	&& groupchange(fid->u, gid2user(fid->u->defaultgid), ep) < 0)		return -1;	m = (perm & DMDIR) ? 0777 : 0666;	perm = perm & (~m | (fid->st.st_mode & m));	npath = estrpath(fid->path, elem);	if(perm & DMDIR){		if((omode&~ORCLOSE) != OREAD){			*ep = Eperm;			free(npath);			return -1;		}		if(stat(npath, &st) >= 0 || errno != ENOENT){			*ep = Eexist;			free(npath);			return -1;		}		/* race */		if(mkdir(npath, perm&0777) < 0){			*ep = strerror(errno);			free(npath);			return -1;		}		if((fid->dir = opendir(npath)) == nil){			*ep = strerror(errno);			remove(npath);		/* race */			free(npath);			return -1;		}	}else{		o = O_CREAT|O_EXCL;		switch(omode&3){		default:			*ep = "programmer error";			return -1;		case OREAD:		case OEXEC:			o |= O_RDONLY;			break;		case ORDWR:			o |= O_RDWR;			break;		case OWRITE:			o |= O_WRONLY;			break;		}		if(omode & OTRUNC)			o |= O_TRUNC;		if((fid->fd = open(npath, o, perm&0777)) < 0){			if(chatty9p)				fprint(2, "create(%s, 0x%x, 0%o) failed\n", npath, o, perm&0777);			*ep = strerror(errno);			free(npath);			return -1;		}	}	opath = fid->path;	fid->path = npath;	if(fidstat(fid, ep) < 0){		fprint(2, "stat after create on %s failed\n", npath);		remove(npath);	/* race */		free(npath);		fid->path = opath;		if(fid->fd >= 0){			close(fid->fd);			fid->fd = -1;		}else{			closedir(fid->dir);			fid->dir = nil;		}		return -1;	}	fid->omode = omode;	free(opath);	return 0;}intuserremove(Fid *fid, char **ep){	if(remove(fid->path) < 0){		*ep = strerror(errno);		return -1;	}	return 0;}voidusage(void){	fprint(2, "usage: u9fs [-Dnz] [-a authmethod] [-m msize] [-u user] [root]\n");	exit(1);}intmain(int argc, char **argv){	char *authtype;	int i;	int fd;	int logflag;	auth = authmethods[0];	logflag = O_WRONLY|O_APPEND|O_CREAT;	ARGBEGIN{	case 'D':		chatty9p = 1;		break;	case 'a':		authtype = EARGF(usage());		auth = nil;		for(i=0; i<nelem(authmethods); i++)			if(strcmp(authmethods[i]->name, authtype)==0)				auth = authmethods[i];		if(auth == nil)			sysfatal("unknown auth type '%s'", authtype);		break;	case 'A':		autharg = EARGF(usage());		break;	case 'l':		logfile = EARGF(usage());		break;	case 'm':		msize = strtol(EARGF(usage()), 0, 0);		break;	case 'n':		network = 0;		break;	case 'u':		defaultuser = EARGF(usage());		break;	case 'z':		logflag |= O_TRUNC;	}ARGEND	if(argc > 1)		usage();	fd = open(logfile, logflag, 0666);	if(fd < 0)		sysfatal("cannot open log '%s'", logfile);	if(dup2(fd, 2) < 0)		sysfatal("cannot dup fd onto stderr");	fprint(2, "u9fs\nkill %d\n", (int)getpid());	fmtinstall('F', fcallconv);	fmtinstall('D', dirconv);	fmtinstall('M', dirmodeconv);	rxbuf = emalloc(msize);	txbuf = emalloc(msize);	databuf = emalloc(msize);	if(auth->init)		auth->init();	if(network)		getremotehostname(remotehostname, sizeof remotehostname);	if(gethostname(hostname, sizeof hostname) < 0)		strcpy(hostname, "gnot");	umask(0);	if(argc == 1)		if(chroot(argv[0]) < 0)			sysfatal("chroot '%s' failed", argv[0]);	none = uname2user("none");	serve(0, 1);	return 0;}

⌨️ 快捷键说明

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