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

📄 mount.c

📁 klibc精简化的c程序库
💻 C
字号:
#include <sys/mount.h>#include <sys/types.h>#include <sys/socket.h>#include <arpa/inet.h>#include <netinet/in.h>#include <linux/nfs.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include "nfsmount.h"#include "sunrpc.h"static uint32_t mount_port;struct mount_call {	struct rpc_call rpc;	uint32_t path_len;	char path[0];};/* * The following structure is the NFS v3 on-the-wire file handle, * as defined in rfc1813. * This differs from the structure used by the kernel, * defined in <linux/nfh3.h>: rfc has a long in network order, * kernel has a short in native order. * Both kernel and rfc use the name nfs_fh; kernel name is * visible to user apps in some versions of libc. * Use different name to avoid clashes. */#define NFS_MAXFHSIZE_WIRE 64struct nfs_fh_wire {	uint32_t size;	char data[NFS_MAXFHSIZE_WIRE];} __attribute__ ((packed));struct mount_reply {	struct rpc_reply reply;	uint32_t status;	struct nfs_fh_wire fh;} __attribute__ ((packed));#define MNT_REPLY_MINSIZE (sizeof(struct rpc_reply) + sizeof(uint32_t))static int get_ports(uint32_t server, const struct nfs_mount_data *data){	uint32_t nfs_ver, mount_ver;	uint32_t proto;	if (data->flags & NFS_MOUNT_VER3) {		nfs_ver = NFS3_VERSION;		mount_ver = NFS_MNT3_VERSION;	} else {		nfs_ver = NFS2_VERSION;		mount_ver = NFS_MNT_VERSION;	}	proto = (data->flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP;	if (nfs_port == 0) {		nfs_port = portmap(server, NFS_PROGRAM, nfs_ver, proto);		if (nfs_port == 0) {			if (proto == IPPROTO_TCP) {				struct in_addr addr = { server };				fprintf(stderr, "NFS over TCP not "					"available from %s\n", inet_ntoa(addr));				return -1;			}			nfs_port = NFS_PORT;		}	}	if (mount_port == 0) {		mount_port = portmap(server, NFS_MNT_PROGRAM, mount_ver, proto);		if (mount_port == 0)			mount_port = MOUNT_PORT;	}	return 0;}static inline int pad_len(int len){	return (len + 3) & ~3;}static inline void dump_params(uint32_t server,			       const char *path,			       const struct nfs_mount_data *data){	(void)server;	(void)path;	(void)data;#ifdef NFS_DEBUG	struct in_addr addr = { server };	printf("NFS params:\n");	printf("  server = %s, path = \"%s\", ", inet_ntoa(addr), path);	printf("version = %d, proto = %s\n",	       data->flags & NFS_MOUNT_VER3 ? 3 : 2,	       (data->flags & NFS_MOUNT_TCP) ? "tcp" : "udp");	printf("  mount_port = %d, nfs_port = %d, flags = %08x\n",	       mount_port, nfs_port, data->flags);	printf("  rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",	       data->rsize, data->wsize, data->timeo, data->retrans);	printf("  acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",	       data->acregmin, data->acregmax, data->acdirmin, data->acdirmax);	printf("  soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n",	       (data->flags & NFS_MOUNT_SOFT) != 0,	       (data->flags & NFS_MOUNT_INTR) != 0,	       (data->flags & NFS_MOUNT_POSIX) != 0,	       (data->flags & NFS_MOUNT_NOCTO) != 0,	       (data->flags & NFS_MOUNT_NOAC) != 0);#endif}static inline void dump_fh(const char *data, int len){	(void)data;	(void)len;#ifdef NFS_DEBUG	int i = 0;	int max = len - (len % 8);	printf("Root file handle: %d bytes\n", NFS2_FHSIZE);	while (i < max) {		int j;		printf("  %4d:  ", i);		for (j = 0; j < 4; j++) {			printf("%02x %02x %02x %02x  ",			       data[i] & 0xff, data[i + 1] & 0xff,			       data[i + 2] & 0xff, data[i + 3] & 0xff);		}		i += j;		printf("\n");	}#endif}static struct mount_reply mnt_reply;static int mount_call(uint32_t proc, uint32_t version,		      const char *path, struct client *clnt){	struct mount_call *mnt_call = NULL;	size_t path_len, call_len;	struct rpc rpc;	int ret = 0;	path_len = strlen(path);	call_len = sizeof(*mnt_call) + pad_len(path_len);	if ((mnt_call = malloc(call_len)) == NULL) {		perror("malloc");		goto bail;	}	memset(mnt_call, 0, sizeof(*mnt_call));	mnt_call->rpc.program = htonl(NFS_MNT_PROGRAM);	mnt_call->rpc.prog_vers = htonl(version);	mnt_call->rpc.proc = htonl(proc);	mnt_call->path_len = htonl(path_len);	memcpy(mnt_call->path, path, path_len);	rpc.call = (struct rpc_call *)mnt_call;	rpc.call_len = call_len;	rpc.reply = (struct rpc_reply *)&mnt_reply;	rpc.reply_len = sizeof(mnt_reply);	if (rpc_call(clnt, &rpc) < 0)		goto bail;	if (proc != MNTPROC_MNT) {		goto done;	}	if (rpc.reply_len < MNT_REPLY_MINSIZE) {		fprintf(stderr, "incomplete reply: %zu < %zu\n",			rpc.reply_len, MNT_REPLY_MINSIZE);		goto bail;	}	if (mnt_reply.status != 0) {		fprintf(stderr, "mount call failed: %d\n",			ntohl(mnt_reply.status));		goto bail;	}	goto done;bail:	ret = -1;done:	if (mnt_call) {		free(mnt_call);	}	return ret;}static int mount_v2(const char *path,		    struct nfs_mount_data *data, struct client *clnt){	int ret = mount_call(MNTPROC_MNT, NFS_MNT_VERSION, path, clnt);	if (ret == 0) {		dump_fh((const char *)&mnt_reply.fh, NFS2_FHSIZE);		data->root.size = NFS_FHSIZE;		memcpy(data->root.data, &mnt_reply.fh, NFS_FHSIZE);		memcpy(data->old_root.data, &mnt_reply.fh, NFS_FHSIZE);	}	return ret;}static inline int umount_v2(const char *path, struct client *clnt){	return mount_call(MNTPROC_UMNT, NFS_MNT_VERSION, path, clnt);}static int mount_v3(const char *path,		    struct nfs_mount_data *data, struct client *clnt){	int ret = mount_call(MNTPROC_MNT, NFS_MNT3_VERSION, path, clnt);	if (ret == 0) {		size_t fhsize = ntohl(mnt_reply.fh.size);		dump_fh((const char *)&mnt_reply.fh.data, fhsize);		memset(data->old_root.data, 0, NFS_FHSIZE);		memset(&data->root, 0, sizeof(data->root));		data->root.size = fhsize;		memcpy(&data->root.data, mnt_reply.fh.data, fhsize);		data->flags |= NFS_MOUNT_VER3;	}	return ret;}static inline int umount_v3(const char *path, struct client *clnt){	return mount_call(MNTPROC_UMNT, NFS_MNT3_VERSION, path, clnt);}int nfs_mount(const char *pathname, const char *hostname,	      uint32_t server, const char *rem_path, const char *path,	      struct nfs_mount_data *data){	struct client *clnt = NULL;	struct sockaddr_in addr;	char mounted = 0;	int sock = -1;	int ret = 0;	int mountflags;	if (get_ports(server, data) != 0) {		goto bail;	}	dump_params(server, rem_path, data);	if (data->flags & NFS_MOUNT_TCP) {		clnt = tcp_client(server, mount_port, CLI_RESVPORT);	} else {		clnt = udp_client(server, mount_port, CLI_RESVPORT);	}	if (clnt == NULL) {		goto bail;	}	if (data->flags & NFS_MOUNT_VER3) {		ret = mount_v3(rem_path, data, clnt);	} else {		ret = mount_v2(rem_path, data, clnt);	}	if (ret == -1) {		goto bail;	}	mounted = 1;	if (data->flags & NFS_MOUNT_TCP) {		sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);	} else {		sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);	}	if (sock == -1) {		perror("socket");		goto bail;	}	if (bindresvport(sock, 0) == -1) {		perror("bindresvport");		goto bail;	}	addr.sin_family = AF_INET;	addr.sin_addr.s_addr = server;	addr.sin_port = htons(nfs_port);	memcpy(&data->addr, &addr, sizeof(data->addr));	strncpy(data->hostname, hostname, sizeof(data->hostname));	data->fd = sock;	mountflags = (data->flags & NFS_MOUNT_KLIBC_RONLY) ? MS_RDONLY : 0;	data->flags = data->flags & NFS_MOUNT_FLAGMASK;	ret = mount(pathname, path, "nfs", mountflags, data);	if (ret == -1) {		if (errno == ENODEV) {			fprintf(stderr, "mount: the kernel lacks NFS v%d "				"support\n",				(data->flags & NFS_MOUNT_VER3) ? 3 : 2);		} else {			perror("mount");		}		goto bail;	}	DEBUG(("Mounted %s on %s\n", pathname, path));	goto done;      bail:	if (mounted) {		if (data->flags & NFS_MOUNT_VER3) {			umount_v3(path, clnt);		} else {			umount_v2(path, clnt);		}	}	ret = -1;      done:	if (clnt) {		client_free(clnt);	}	if (sock != -1) {		close(sock);	}	return ret;}

⌨️ 快捷键说明

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