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

📄 mount.c

📁 FUSE文件系统开发工具,将内核层面的文件系统开发过程平移到应用层面上来。
💻 C
字号:
/*  FUSE: Filesystem in Userspace  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>  This program can be distributed under the terms of the GNU LGPLv2.  See the file COPYING.LIB.*/#include "config.h"#include "fuse_i.h"#include "fuse_misc.h"#include "fuse_opt.h"#include "fuse_common_compat.h"#include "mount_util.h"#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <stddef.h>#include <fcntl.h>#include <errno.h>#include <sys/poll.h>#include <sys/socket.h>#include <sys/un.h>#include <sys/wait.h>#include <sys/mount.h>#define FUSERMOUNT_PROG		"fusermount"#define FUSE_COMMFD_ENV		"_FUSE_COMMFD"#ifndef HAVE_FORK#define fork() vfork()#endif#ifndef MS_DIRSYNC#define MS_DIRSYNC 128#endifenum {	KEY_KERN_FLAG,	KEY_KERN_OPT,	KEY_FUSERMOUNT_OPT,	KEY_SUBTYPE_OPT,	KEY_MTAB_OPT,	KEY_ALLOW_ROOT,	KEY_RO,	KEY_HELP,	KEY_VERSION,};struct mount_opts {	int allow_other;	int allow_root;	int ishelp;	int flags;	int nonempty;	int blkdev;	char *fsname;	char *subtype;	char *subtype_opt;	char *mtab_opts;	char *fusermount_opts;	char *kernel_opts;};#define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 }static const struct fuse_opt fuse_mount_opts[] = {	FUSE_MOUNT_OPT("allow_other",	    allow_other),	FUSE_MOUNT_OPT("allow_root",	    allow_root),	FUSE_MOUNT_OPT("nonempty",	    nonempty),	FUSE_MOUNT_OPT("blkdev",	    blkdev),	FUSE_MOUNT_OPT("fsname=%s",	    fsname),	FUSE_MOUNT_OPT("subtype=%s",	    subtype),	FUSE_OPT_KEY("allow_other",	    KEY_KERN_OPT),	FUSE_OPT_KEY("allow_root",	    KEY_ALLOW_ROOT),	FUSE_OPT_KEY("nonempty",	    KEY_FUSERMOUNT_OPT),	FUSE_OPT_KEY("blkdev",		    KEY_FUSERMOUNT_OPT),	FUSE_OPT_KEY("fsname=",		    KEY_FUSERMOUNT_OPT),	FUSE_OPT_KEY("subtype=",	    KEY_SUBTYPE_OPT),	FUSE_OPT_KEY("large_read",	    KEY_KERN_OPT),	FUSE_OPT_KEY("blksize=",	    KEY_KERN_OPT),	FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT),	FUSE_OPT_KEY("max_read=",	    KEY_KERN_OPT),	FUSE_OPT_KEY("max_read=",	    FUSE_OPT_KEY_KEEP),	FUSE_OPT_KEY("user=",		    KEY_MTAB_OPT),	FUSE_OPT_KEY("-r",		    KEY_RO),	FUSE_OPT_KEY("ro",		    KEY_KERN_FLAG),	FUSE_OPT_KEY("rw",		    KEY_KERN_FLAG),	FUSE_OPT_KEY("suid",		    KEY_KERN_FLAG),	FUSE_OPT_KEY("nosuid",		    KEY_KERN_FLAG),	FUSE_OPT_KEY("dev",		    KEY_KERN_FLAG),	FUSE_OPT_KEY("nodev",		    KEY_KERN_FLAG),	FUSE_OPT_KEY("exec",		    KEY_KERN_FLAG),	FUSE_OPT_KEY("noexec",		    KEY_KERN_FLAG),	FUSE_OPT_KEY("async",		    KEY_KERN_FLAG),	FUSE_OPT_KEY("sync",		    KEY_KERN_FLAG),	FUSE_OPT_KEY("dirsync",		    KEY_KERN_FLAG),	FUSE_OPT_KEY("atime",		    KEY_KERN_FLAG),	FUSE_OPT_KEY("noatime",		    KEY_KERN_FLAG),	FUSE_OPT_KEY("-h",		    KEY_HELP),	FUSE_OPT_KEY("--help",		    KEY_HELP),	FUSE_OPT_KEY("-V",		    KEY_VERSION),	FUSE_OPT_KEY("--version",	    KEY_VERSION),	FUSE_OPT_END};static void mount_help(void){	fprintf(stderr,"    -o allow_other         allow access to other users\n""    -o allow_root          allow access to root\n""    -o nonempty            allow mounts over non-empty file/dir\n""    -o default_permissions enable permission checking by kernel\n""    -o fsname=NAME         set filesystem name\n""    -o subtype=NAME        set filesystem type\n""    -o large_read          issue large read requests (2.4 only)\n""    -o max_read=N          set maximum size of read requests\n""\n");}static void exec_fusermount(const char *argv[]){	execv(FUSERMOUNT_DIR "/" FUSERMOUNT_PROG, (char **) argv);	execvp(FUSERMOUNT_PROG, (char **) argv);}static void mount_version(void){	int pid = fork();	if (!pid) {		const char *argv[] = { FUSERMOUNT_PROG, "--version", NULL };		exec_fusermount(argv);		_exit(1);	} else if (pid != -1)		waitpid(pid, NULL, 0);}struct mount_flags {	const char *opt;	unsigned long flag;	int on;};static struct mount_flags mount_flags[] = {	{"rw",	    MS_RDONLY,	    0},	{"ro",	    MS_RDONLY,	    1},	{"suid",    MS_NOSUID,	    0},	{"nosuid",  MS_NOSUID,	    1},	{"dev",	    MS_NODEV,	    0},	{"nodev",   MS_NODEV,	    1},	{"exec",    MS_NOEXEC,	    0},	{"noexec",  MS_NOEXEC,	    1},	{"async",   MS_SYNCHRONOUS, 0},	{"sync",    MS_SYNCHRONOUS, 1},	{"atime",   MS_NOATIME,	    0},	{"noatime", MS_NOATIME,	    1},	{"dirsync", MS_DIRSYNC,	    1},	{NULL,	    0,		    0}};static void set_mount_flag(const char *s, int *flags){	int i;	for (i = 0; mount_flags[i].opt != NULL; i++) {		const char *opt = mount_flags[i].opt;		if (strcmp(opt, s) == 0) {			if (mount_flags[i].on)				*flags |= mount_flags[i].flag;			else				*flags &= ~mount_flags[i].flag;			return;		}	}	fprintf(stderr, "fuse: internal error, can't find mount flag\n");	abort();}static int fuse_mount_opt_proc(void *data, const char *arg, int key,			       struct fuse_args *outargs){	struct mount_opts *mo = data;	switch (key) {	case KEY_ALLOW_ROOT:		if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 ||		    fuse_opt_add_arg(outargs, "-oallow_root") == -1)			return -1;		return 0;	case KEY_RO:		arg = "ro";		/* fall through */	case KEY_KERN_FLAG:		set_mount_flag(arg, &mo->flags);		return 0;	case KEY_KERN_OPT:		return fuse_opt_add_opt(&mo->kernel_opts, arg);	case KEY_FUSERMOUNT_OPT:		return fuse_opt_add_opt(&mo->fusermount_opts, arg);	case KEY_SUBTYPE_OPT:		return fuse_opt_add_opt(&mo->subtype_opt, arg);	case KEY_MTAB_OPT:		return fuse_opt_add_opt(&mo->mtab_opts, arg);	case KEY_HELP:		mount_help();		mo->ishelp = 1;		break;	case KEY_VERSION:		mount_version();		mo->ishelp = 1;		break;	}	return 1;}/* return value: * >= 0	 => fd * -1	 => error */static int receive_fd(int fd){	struct msghdr msg;	struct iovec iov;	char buf[1];	int rv;	size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)];	struct cmsghdr *cmsg;	iov.iov_base = buf;	iov.iov_len = 1;	msg.msg_name = 0;	msg.msg_namelen = 0;	msg.msg_iov = &iov;	msg.msg_iovlen = 1;	/* old BSD implementations should use msg_accrights instead of	 * msg_control; the interface is different. */	msg.msg_control = ccmsg;	msg.msg_controllen = sizeof(ccmsg);	while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);	if (rv == -1) {		perror("recvmsg");		return -1;	}	if(!rv) {		/* EOF */		return -1;	}	cmsg = CMSG_FIRSTHDR(&msg);	if (!cmsg->cmsg_type == SCM_RIGHTS) {		fprintf(stderr, "got control message of unknown type %d\n",			cmsg->cmsg_type);		return -1;	}	return *(int*)CMSG_DATA(cmsg);}void fuse_kern_unmount(const char *mountpoint, int fd){	int res;	int pid;	if (!mountpoint)		return;	if (fd != -1) {		struct pollfd pfd;		pfd.fd = fd;		pfd.events = 0;		res = poll(&pfd, 1, 0);		/* If file poll returns POLLERR on the device file descriptor,		   then the filesystem is already unmounted */		if (res == 1 && (pfd.revents & POLLERR))			return;		/* Need to close file descriptor, otherwise synchronous umount		   would recurse into filesystem, and deadlock */		close(fd);	}	if (geteuid() == 0) {		fuse_mnt_umount("fuse", mountpoint, 1);		return;	}	res = umount2(mountpoint, 2);	if (res == 0)		return;	pid = fork();	if(pid == -1)		return;	if(pid == 0) {		const char *argv[] = { FUSERMOUNT_PROG, "-u", "-q", "-z",				       "--", mountpoint, NULL };		exec_fusermount(argv);		_exit(1);	}	waitpid(pid, NULL, 0);}void fuse_unmount_compat22(const char *mountpoint){	fuse_kern_unmount(mountpoint, -1);}static int fuse_mount_fusermount(const char *mountpoint, const char *opts,				 int quiet){	int fds[2], pid;	int res;	int rv;	if (!mountpoint) {		fprintf(stderr, "fuse: missing mountpoint\n");		return -1;	}	res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);	if(res == -1) {		perror("fuse: socketpair() failed");		return -1;	}	pid = fork();	if(pid == -1) {		perror("fuse: fork() failed");		close(fds[0]);		close(fds[1]);		return -1;	}	if(pid == 0) {		char env[10];		const char *argv[32];		int a = 0;		if (quiet) {			int fd = open("/dev/null", O_RDONLY);			dup2(fd, 1);			dup2(fd, 2);		}		argv[a++] = FUSERMOUNT_PROG;		if (opts) {			argv[a++] = "-o";			argv[a++] = opts;		}		argv[a++] = "--";		argv[a++] = mountpoint;		argv[a++] = NULL;		close(fds[1]);		fcntl(fds[0], F_SETFD, 0);		snprintf(env, sizeof(env), "%i", fds[0]);		setenv(FUSE_COMMFD_ENV, env, 1);		exec_fusermount(argv);		perror("fuse: failed to exec fusermount");		_exit(1);	}	close(fds[0]);	rv = receive_fd(fds[1]);	close(fds[1]);	waitpid(pid, NULL, 0); /* bury zombie */	return rv;}int fuse_mount_compat22(const char *mountpoint, const char *opts){	return fuse_mount_fusermount(mountpoint, opts, 0);}static int fuse_mount_sys(const char *mnt, struct mount_opts *mo,			  const char *mnt_opts){	char tmp[128];	const char *devname = "/dev/fuse";	char *source = NULL;	char *type = NULL;	struct stat stbuf;	int fd;	int res;	if (!mnt) {		fprintf(stderr, "fuse: missing mountpoint\n");		return -1;	}	res = lstat(mnt, &stbuf);	if (res == -1) {		fprintf(stderr ,"fuse: failed to access mountpoint %s: %s\n",			mnt, strerror(errno));		return -1;	}	if (!mo->nonempty) {		res = fuse_mnt_check_empty("fuse", mnt, stbuf.st_mode,					   stbuf.st_size);		if (res == -1)			return -1;	}	fd = open(devname, O_RDWR);	if (fd == -1) {		if (errno == ENODEV || errno == ENOENT)			fprintf(stderr, "fuse: device not found, try 'modprobe fuse' first\n");		else			fprintf(stderr, "fuse: failed to open %s: %s\n",				devname, strerror(errno));		return -1;	}	snprintf(tmp, sizeof(tmp),  "fd=%i,rootmode=%o,user_id=%i,group_id=%i",		 fd, stbuf.st_mode & S_IFMT, getuid(), getgid());	res = fuse_opt_add_opt(&mo->kernel_opts, tmp);	if (res == -1)		goto out_close;	source = malloc((mo->fsname ? strlen(mo->fsname) : 0) +			(mo->subtype ? strlen(mo->subtype) : 0) +			strlen(devname) + 32);	type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32);	if (!type || !source) {		fprintf(stderr, "fuse: failed to allocate memory\n");		goto out_close;	}	strcpy(type, mo->blkdev ? "fuseblk" : "fuse");	if (mo->subtype) {		strcat(type, ".");		strcat(type, mo->subtype);	}	strcpy(source,	       mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname));	res = mount(source, mnt, type, mo->flags, mo->kernel_opts);	if (res == -1 && errno == ENODEV && mo->subtype) {		/* Probably missing subtype support */		strcpy(type, mo->blkdev ? "fuseblk" : "fuse");		if (mo->fsname) {			if (!mo->blkdev)				sprintf(source, "%s#%s", mo->subtype,					mo->fsname);		} else {			strcpy(source, type);		}		res = mount(source, mnt, type, mo->flags, mo->kernel_opts);	}	if (res == -1) {		/*		 * Maybe kernel doesn't support unprivileged mounts, in this		 * case try falling back to fusermount		 */		if (errno == EPERM) {			res = -2;		} else {			int errno_save = errno;			if (mo->blkdev && errno == ENODEV &&			    !fuse_mnt_check_fuseblk())				fprintf(stderr,					"fuse: 'fuseblk' support missing\n");			else				fprintf(stderr, "fuse: mount failed: %s\n",					strerror(errno_save));		}		goto out_close;	}	if (geteuid() == 0) {		char *newmnt = fuse_mnt_resolve_path("fuse", mnt);		res = -1;		if (!newmnt)			goto out_umount;		res = fuse_mnt_add_mount("fuse", source, newmnt, type,					 mnt_opts);		free(newmnt);		if (res == -1)			goto out_umount;	}	return fd;out_umount:	umount2(mnt, 2); /* lazy umount */out_close:	free(type);	free(source);	close(fd);	return res;}static int get_mnt_flag_opts(char **mnt_optsp, int flags){	int i;	if (!(flags & MS_RDONLY) && fuse_opt_add_opt(mnt_optsp, "rw") == -1)		return -1;	for (i = 0; mount_flags[i].opt != NULL; i++) {		if (mount_flags[i].on && (flags & mount_flags[i].flag) &&		    fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1)			return -1;	}	return 0;}int fuse_kern_mount(const char *mountpoint, struct fuse_args *args){	struct mount_opts mo;	int res = -1;	char *mnt_opts = NULL;	memset(&mo, 0, sizeof(mo));	mo.flags = MS_NOSUID | MS_NODEV;	if (args &&	    fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)		return -1;	if (mo.allow_other && mo.allow_root) {		fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n");		goto out;	}	res = 0;	if (mo.ishelp)		goto out;	res = -1;	if (get_mnt_flag_opts(&mnt_opts, mo.flags) == -1)		goto out;	if (mo.kernel_opts && fuse_opt_add_opt(&mnt_opts, mo.kernel_opts) == -1)		goto out;	if (mo.mtab_opts &&  fuse_opt_add_opt(&mnt_opts, mo.mtab_opts) == -1)		goto out;	res = fuse_mount_sys(mountpoint, &mo, mnt_opts);	if (res == -2) {		if (mo.fusermount_opts &&		    fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) == -1)			goto out;		if (mo.subtype) {			char *tmp_opts = NULL;			res = -1;			if (fuse_opt_add_opt(&tmp_opts, mnt_opts) == -1 ||			    fuse_opt_add_opt(&tmp_opts, mo.subtype_opt) == -1) {				free(tmp_opts);				goto out;			}			res = fuse_mount_fusermount(mountpoint, tmp_opts, 1);			free(tmp_opts);			if (res == -1)				res = fuse_mount_fusermount(mountpoint,							    mnt_opts, 0);		} else {			res = fuse_mount_fusermount(mountpoint, mnt_opts, 0);		}	}out:	free(mnt_opts);	free(mo.fsname);	free(mo.subtype);	free(mo.fusermount_opts);	free(mo.subtype_opt);	free(mo.kernel_opts);	free(mo.mtab_opts);	return res;}FUSE_SYMVER(".symver fuse_mount_compat22,fuse_mount@FUSE_2.2");FUSE_SYMVER(".symver fuse_unmount_compat22,fuse_unmount@FUSE_2.2");

⌨️ 快捷键说明

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