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

📄 nfs.c

📁 linux下从网卡远程启动
💻 C
📖 第 1 页 / 共 2 页
字号:
#ifdef	DOWNLOAD_PROTO_NFS#include "etherboot.h"#include "nic.h"/* NOTE: the NFS code is heavily inspired by the NetBSD netboot code (read: * large portions are copied verbatim) as distributed in OSKit 0.97.  A few * changes were necessary to adapt the code to Etherboot and to fix several * inconsistencies.  Also the RPC message preparation is done "by hand" to * avoid adding netsprintf() which I find hard to understand and use.  *//* NOTE 2: Etherboot does not care about things beyond the kernel image, so * it loads the kernel image off the boot server (ARP_SERVER) and does not * access the client root disk (root-path in dhcpd.conf), which would use * ARP_ROOTSERVER.  The root disk is something the operating system we are * about to load needs to use.  This is different from the OSKit 0.97 logic.  *//* NOTE 3: Symlink handling introduced by Anselm M Hoffmeister, 2003-July-14 * If a symlink is encountered, it is followed as far as possible (recursion * possible, maximum 16 steps). There is no clearing of ".."'s inside the * path, so please DON'T DO THAT. thx. */#define START_OPORT 700		/* mountd usually insists on secure ports */#define OPORT_SWEEP 200		/* make sure we don't leave secure range */static int oport = START_OPORT;static int mount_port = -1;static int nfs_port = -1;static int fs_mounted = 0;static unsigned long rpc_id;/**************************************************************************RPC_INIT - set up the ID counter to something fairly random**************************************************************************/void rpc_init(void){	unsigned long t;	t = currticks();	rpc_id = t ^ (t << 8) ^ (t << 16);}/**************************************************************************RPC_PRINTERROR - Print a low level RPC error message**************************************************************************/static void rpc_printerror(struct rpc_t *rpc){	if (rpc->u.reply.rstatus || rpc->u.reply.verifier ||	    rpc->u.reply.astatus) {		/* rpc_printerror() is called for any RPC related error,		 * suppress output if no low level RPC error happened.  */		printf("RPC error: (%d,%d,%d)\n", ntohl(rpc->u.reply.rstatus),			ntohl(rpc->u.reply.verifier),			ntohl(rpc->u.reply.astatus));	}}/**************************************************************************AWAIT_RPC - Wait for an rpc packet**************************************************************************/static int await_rpc(int ival, void *ptr,	unsigned short ptype, struct iphdr *ip, struct udphdr *udp){	struct rpc_t *rpc;	if (!udp) 		return 0;	if (arptable[ARP_CLIENT].ipaddr.s_addr != ip->dest.s_addr)		return 0;	if (ntohs(udp->dest) != ival)		return 0;	if (nic.packetlen < ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr) + 8)		return 0;	rpc = (struct rpc_t *)&nic.packet[ETH_HLEN];	if (*(unsigned long *)ptr != ntohl(rpc->u.reply.id))		return 0;	if (MSG_REPLY != ntohl(rpc->u.reply.type))		return 0;	return 1;}/**************************************************************************RPC_LOOKUP - Lookup RPC Port numbers**************************************************************************/static int rpc_lookup(int addr, int prog, int ver, int sport){	struct rpc_t buf, *rpc;	unsigned long id;	int retries;	long *p;	id = rpc_id++;	buf.u.call.id = htonl(id);	buf.u.call.type = htonl(MSG_CALL);	buf.u.call.rpcvers = htonl(2);	/* use RPC version 2 */	buf.u.call.prog = htonl(PROG_PORTMAP);	buf.u.call.vers = htonl(2);	/* portmapper is version 2 */	buf.u.call.proc = htonl(PORTMAP_GETPORT);	p = (long *)buf.u.call.data;	*p++ = 0; *p++ = 0;				/* auth credential */	*p++ = 0; *p++ = 0;				/* auth verifier */	*p++ = htonl(prog);	*p++ = htonl(ver);	*p++ = htonl(IP_UDP);	*p++ = 0;	for (retries = 0; retries < MAX_RPC_RETRIES; retries++) {		long timeout;		udp_transmit(arptable[addr].ipaddr.s_addr, sport, SUNRPC_PORT,			(char *)p - (char *)&buf, &buf);		timeout = rfc2131_sleep_interval(TIMEOUT, retries);		if (await_reply(await_rpc, sport, &id, timeout)) {			rpc = (struct rpc_t *)&nic.packet[ETH_HLEN];			if (rpc->u.reply.rstatus || rpc->u.reply.verifier ||			    rpc->u.reply.astatus) {				rpc_printerror(rpc);				return -1;			} else {				return ntohl(rpc->u.reply.data[0]);			}		}	}	return -1;}/**************************************************************************RPC_ADD_CREDENTIALS - Add RPC authentication/verifier entries**************************************************************************/static long *rpc_add_credentials(long *p){	int hl;	/* Here's the executive summary on authentication requirements of the	 * various NFS server implementations:  Linux accepts both AUTH_NONE	 * and AUTH_UNIX authentication (also accepts an empty hostname field	 * in the AUTH_UNIX scheme).  *BSD refuses AUTH_NONE, but accepts	 * AUTH_UNIX (also accepts an empty hostname field in the AUTH_UNIX	 * scheme).  To be safe, use AUTH_UNIX and pass the hostname if we have	 * it (if the BOOTP/DHCP reply didn't give one, just use an empty	 * hostname).  */	hl = (hostnamelen + 3) & ~3;	/* Provide an AUTH_UNIX credential.  */	*p++ = htonl(1);		/* AUTH_UNIX */	*p++ = htonl(hl+20);		/* auth length */	*p++ = htonl(0);		/* stamp */	*p++ = htonl(hostnamelen);	/* hostname string */	if (hostnamelen & 3) {		*(p + hostnamelen / 4) = 0; /* add zero padding */	}	memcpy(p, hostname, hostnamelen);	p += hl / 4;	*p++ = 0;			/* uid */	*p++ = 0;			/* gid */	*p++ = 0;			/* auxiliary gid list */	/* Provide an AUTH_NONE verifier.  */	*p++ = 0;			/* AUTH_NONE */	*p++ = 0;			/* auth length */	return p;}/**************************************************************************NFS_PRINTERROR - Print a NFS error message**************************************************************************/static void nfs_printerror(int err){	switch (-err) {	case NFSERR_PERM:		printf("Not owner\n");		break;	case NFSERR_NOENT:		printf("No such file or directory\n");		break;	case NFSERR_ACCES:		printf("Permission denied\n");		break;	case NFSERR_ISDIR:		printf("Directory given where filename expected\n");		break;	case NFSERR_INVAL:		printf("Invalid filehandle\n");		break; // INVAL is not defined in NFSv2, some NFS-servers		// seem to use it in answers to v2 nevertheless.	case 9998:		printf("low-level RPC failure (parameter decoding problem?)\n");		break;	case 9999:		printf("low-level RPC failure (authentication problem?)\n");		break;	default:		printf("Unknown NFS error %d\n", -err);	}}/**************************************************************************NFS_MOUNT - Mount an NFS Filesystem**************************************************************************/static int nfs_mount(int server, int port, char *path, char *fh, int sport){	struct rpc_t buf, *rpc;	unsigned long id;	int retries;	long *p;	int pathlen = strlen(path);	id = rpc_id++;	buf.u.call.id = htonl(id);	buf.u.call.type = htonl(MSG_CALL);	buf.u.call.rpcvers = htonl(2);	/* use RPC version 2 */	buf.u.call.prog = htonl(PROG_MOUNT);	buf.u.call.vers = htonl(1);	/* mountd is version 1 */	buf.u.call.proc = htonl(MOUNT_ADDENTRY);	p = rpc_add_credentials((long *)buf.u.call.data);	*p++ = htonl(pathlen);	if (pathlen & 3) {		*(p + pathlen / 4) = 0;	/* add zero padding */	}	memcpy(p, path, pathlen);	p += (pathlen + 3) / 4;	for (retries = 0; retries < MAX_RPC_RETRIES; retries++) {		long timeout;		udp_transmit(arptable[server].ipaddr.s_addr, sport, port,			(char *)p - (char *)&buf, &buf);		timeout = rfc2131_sleep_interval(TIMEOUT, retries);		if (await_reply(await_rpc, sport, &id, timeout)) {			rpc = (struct rpc_t *)&nic.packet[ETH_HLEN];			if (rpc->u.reply.rstatus || rpc->u.reply.verifier ||			    rpc->u.reply.astatus || rpc->u.reply.data[0]) {				rpc_printerror(rpc);				if (rpc->u.reply.rstatus) {					/* RPC failed, no verifier, data[0] */					return -9999;				}				if (rpc->u.reply.astatus) {					/* RPC couldn't decode parameters */					return -9998;				}				return -ntohl(rpc->u.reply.data[0]);			} else {				fs_mounted = 1;				memcpy(fh, rpc->u.reply.data + 1, NFS_FHSIZE);				return 0;			}		}	}	return -1;}/**************************************************************************NFS_UMOUNTALL - Unmount all our NFS Filesystems on the Server**************************************************************************/void nfs_umountall(int server){	struct rpc_t buf, *rpc;	unsigned long id;	int retries;	long *p;	if (!arptable[server].ipaddr.s_addr) {		/* Haven't sent a single UDP packet to this server */		return;	}	if ((mount_port == -1) || (!fs_mounted)) {		/* Nothing mounted, nothing to umount */		return;	}	id = rpc_id++;	buf.u.call.id = htonl(id);	buf.u.call.type = htonl(MSG_CALL);	buf.u.call.rpcvers = htonl(2);	/* use RPC version 2 */	buf.u.call.prog = htonl(PROG_MOUNT);	buf.u.call.vers = htonl(1);	/* mountd is version 1 */	buf.u.call.proc = htonl(MOUNT_UMOUNTALL);	p = rpc_add_credentials((long *)buf.u.call.data);	for (retries = 0; retries < MAX_RPC_RETRIES; retries++) {		long timeout = rfc2131_sleep_interval(TIMEOUT, retries);		udp_transmit(arptable[server].ipaddr.s_addr, oport, mount_port,			(char *)p - (char *)&buf, &buf);		if (await_reply(await_rpc, oport, &id, timeout)) {			rpc = (struct rpc_t *)&nic.packet[ETH_HLEN];			if (rpc->u.reply.rstatus || rpc->u.reply.verifier ||			    rpc->u.reply.astatus) {				rpc_printerror(rpc);			}			fs_mounted = 0;			return;		}	}}/*************************************************************************** * NFS_READLINK (AH 2003-07-14) * This procedure is called when read of the first block fails - * this probably happens when it's a directory or a symlink * In case of successful readlink(), the dirname is manipulated, * so that inside the nfs() function a recursion can be done. **************************************************************************/static int nfs_readlink(int server, int port, char *fh, char *path, char *nfh,	int sport){	struct rpc_t buf, *rpc;	unsigned long id;	long *p;	int retries;	int pathlen = strlen(path);

⌨️ 快捷键说明

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