/* * NFS mount the kernel directory, and perform a lookup on the * kernel file. * * Places the directory filehandle in global "dirfh" * Places the kernel filehandle in global filefh * * returns 0 on success, nonzero on failure */ int fileinit(struct in_addr ip, char *dirname, char *filename) { int mount_port; char *readahead_option; int err; readahead_option = getenv("readahead"); if (readahead_option) kimg_readahead = atoi(readahead_option); if (kimg_readahead < 0) dprintf("NFS using whole-file readahead\n"); else if (kimg_readahead > 0) dprintf("NFS using %dkb readahead\n", kimg_readahead); rpc_init(); /* * Lookup NFS/MOUNTD ports for ROOT using PORTMAP. */ nfs_port = rpc_lookup(ip, PROG_NFS, 2); mount_port = rpc_lookup(ip, PROG_MOUNT, 1); if (nfs_port == -1 || mount_port == -1) { printf("Can't get root NFS/MOUNT ports.\n"); return 1; } dprintf("fileinit: NFS port = %d, MOUNT port = %d\n", nfs_port, mount_port); /* * NFS mount the directory. */ dprintf("Mounting %s ... ", dirname); err = nfs_mount(ip, mount_port, dirname, dirfh); if (err) { printf("Can't mount filesystem: %s.\n", nfs_strerror(err)); return 1; } dprintf("done\n"); /* * Lookup the file. */ dprintf("Looking up %s ... ", filename); err = nfs_lookup(ip, nfs_port, dirfh, filename, filefh); if (err) { printf("Can't lookup %s: %s.\n", filename, nfs_strerror(err)); return 1; } dprintf("done\n"); /* Stash ipaddr for subsequent calls */ ipaddr.s_addr = ip.s_addr; return 0; }
rpc_export_t* find_rpc_export(char* name, int flags) { return rpc_lookup((char*)name, strlen(name)); }
/************************************************************************** NFS - Download extended BOOTP data, or kernel image from NFS server **************************************************************************/ int nfs(const char *name, int (*fnc)(unsigned char *, unsigned int, unsigned int, int)) { static int recursion = 0; int sport; int err, namelen = strlen(name); char dirname[300], *fname; char dirfh[NFS_FHSIZE]; /* file handle of directory */ char filefh[NFS_FHSIZE]; /* file handle of kernel image */ unsigned int block; int rlen, size, offs, len; struct rpc_t *rpc; rx_qdrain(); sport = oport++; if (oport > START_OPORT+OPORT_SWEEP) { oport = START_OPORT; } if ( name != dirname ) { memcpy(dirname, name, namelen + 1); } recursion = 0; nfssymlink: if ( recursion > NFS_MAXLINKDEPTH ) { printf ( "\nRecursion: More than %d symlinks followed. Abort.\n", NFS_MAXLINKDEPTH ); return 0; } recursion++; fname = dirname + (namelen - 1); while (fname >= dirname) { if (*fname == '/') { *fname = '\0'; fname++; break; } fname--; } if (fname < dirname) { printf("can't parse file name %s\n", name); return 0; } if (mount_port == -1) { mount_port = rpc_lookup(ARP_SERVER, PROG_MOUNT, 1, sport); } if (nfs_port == -1) { nfs_port = rpc_lookup(ARP_SERVER, PROG_NFS, 2, sport); } if (nfs_port == -1 || mount_port == -1) { printf("can't get nfs/mount ports from portmapper\n"); return 0; } err = nfs_mount(ARP_SERVER, mount_port, dirname, dirfh, sport); if (err) { printf("mounting %s: ", dirname); nfs_printerror(err); /* just to be sure... */ nfs_umountall(ARP_SERVER); return 0; } err = nfs_lookup(ARP_SERVER, nfs_port, dirfh, fname, filefh, sport); if (err) { printf("looking up %s: ", fname); nfs_printerror(err); nfs_umountall(ARP_SERVER); return 0; } offs = 0; block = 1; /* blocks are numbered starting from 1 */ size = -1; /* will be set properly with the first reply */ len = NFS_READ_SIZE; /* first request is always full size */ do { err = nfs_read(ARP_SERVER, nfs_port, filefh, offs, len, sport); if ((err <= -NFSERR_ISDIR)&&(err >= -NFSERR_INVAL) && (offs == 0)) { // An error occured. NFS servers tend to sending // errors 21 / 22 when symlink instead of real file // is requested. So check if it's a symlink! block = nfs_readlink(ARP_SERVER, nfs_port, dirfh, dirname, filefh, sport); if ( 0 == block ) { printf("\nLoading symlink:%s ..",dirname); goto nfssymlink; } nfs_printerror(err); nfs_umountall(ARP_SERVER); return 0; } if (err) { printf("reading at offset %d: ", offs); nfs_printerror(err); nfs_umountall(ARP_SERVER); return 0; } rpc = (struct rpc_t *)&nic.packet[ETH_HLEN]; /* size must be found out early to allow EOF detection */ if (size == -1) { size = ntohl(rpc->u.reply.data[6]); } rlen = ntohl(rpc->u.reply.data[18]); if (rlen > len) { rlen = len; /* shouldn't happen... */ } err = fnc((char *)&rpc->u.reply.data[19], block, rlen, (offs+rlen == size)); if (err <= 0) { nfs_umountall(ARP_SERVER); return err; } block++; offs += rlen; /* last request is done with matching requested read size */ if (size-offs < NFS_READ_SIZE) { len = size-offs; } } while (len != 0); /* len == 0 means that all the file has been read */ return 1; }