1/* $NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $ */ 2 3/*- 4 * Copyright (c) 1993 John Brezak 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 27 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include <sys/cdefs.h>
| 1/* $NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $ */ 2 3/*- 4 * Copyright (c) 1993 John Brezak 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 27 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include <sys/cdefs.h>
|
32__FBSDID("$FreeBSD: stable/9/lib/libstand/nfs.c 252700 2013-07-04 15:19:45Z mav $");
| 32__FBSDID("$FreeBSD: stable/9/lib/libstand/nfs.c 252701 2013-07-04 15:21:27Z mav $");
|
33 34#include <sys/param.h> 35#include <sys/time.h> 36#include <sys/socket.h> 37#include <sys/stat.h> 38#include <string.h> 39 40#include <netinet/in.h> 41#include <netinet/in_systm.h> 42 43#include "rpcv2.h" 44#include "nfsv2.h" 45 46#include "stand.h" 47#include "net.h" 48#include "netif.h" 49#include "rpc.h" 50 51#define NFS_DEBUGxx 52 53#define NFSREAD_SIZE 1024 54 55/* Define our own NFS attributes without NQNFS stuff. */ 56#ifdef OLD_NFSV2 57struct nfsv2_fattrs { 58 n_long fa_type; 59 n_long fa_mode; 60 n_long fa_nlink; 61 n_long fa_uid; 62 n_long fa_gid; 63 n_long fa_size; 64 n_long fa_blocksize; 65 n_long fa_rdev; 66 n_long fa_blocks; 67 n_long fa_fsid; 68 n_long fa_fileid; 69 struct nfsv2_time fa_atime; 70 struct nfsv2_time fa_mtime; 71 struct nfsv2_time fa_ctime; 72}; 73 74struct nfs_read_args { 75 u_char fh[NFS_FHSIZE]; 76 n_long off; 77 n_long len; 78 n_long xxx; /* XXX what's this for? */ 79}; 80 81/* Data part of nfs rpc reply (also the largest thing we receive) */ 82struct nfs_read_repl { 83 n_long errno; 84 struct nfsv2_fattrs fa; 85 n_long count; 86 u_char data[NFSREAD_SIZE]; 87}; 88 89#ifndef NFS_NOSYMLINK 90struct nfs_readlnk_repl { 91 n_long errno; 92 n_long len; 93 char path[NFS_MAXPATHLEN]; 94}; 95#endif 96 97struct nfs_readdir_args { 98 u_char fh[NFS_FHSIZE]; 99 n_long cookie; 100 n_long count; 101}; 102 103struct nfs_readdir_data { 104 n_long fileid; 105 n_long len; 106 char name[0]; 107}; 108 109struct nfs_readdir_off { 110 n_long cookie; 111 n_long follows; 112}; 113 114struct nfs_iodesc { 115 struct iodesc *iodesc; 116 off_t off; 117 u_char fh[NFS_FHSIZE]; 118 struct nfsv2_fattrs fa; /* all in network order */ 119}; 120#else /* !OLD_NFSV2 */ 121 122/* NFSv3 definitions */ 123#define NFS_V3MAXFHSIZE 64 124#define NFS_VER3 3 125#define RPCMNT_VER3 3 126#define NFSPROCV3_LOOKUP 3 127#define NFSPROCV3_READLINK 5 128#define NFSPROCV3_READ 6 129#define NFSPROCV3_READDIR 16 130 131typedef struct { 132 uint32_t val[2]; 133} n_quad; 134 135struct nfsv3_time { 136 uint32_t nfs_sec; 137 uint32_t nfs_nsec; 138}; 139 140struct nfsv3_fattrs { 141 uint32_t fa_type; 142 uint32_t fa_mode; 143 uint32_t fa_nlink; 144 uint32_t fa_uid; 145 uint32_t fa_gid; 146 n_quad fa_size; 147 n_quad fa_used; 148 n_quad fa_rdev; 149 n_quad fa_fsid; 150 n_quad fa_fileid; 151 struct nfsv3_time fa_atime; 152 struct nfsv3_time fa_mtime; 153 struct nfsv3_time fa_ctime; 154}; 155 156/* 157 * For NFSv3, the file handle is variable in size, so most fixed sized 158 * structures for arguments won't work. For most cases, a structure 159 * that starts with any fixed size section is followed by an array 160 * that covers the maximum size required. 161 */ 162struct nfsv3_readdir_repl { 163 uint32_t errno; 164 uint32_t ok; 165 struct nfsv3_fattrs fa; 166 uint32_t cookiev0; 167 uint32_t cookiev1; 168}; 169 170struct nfsv3_readdir_entry { 171 uint32_t follows; 172 uint32_t fid0; 173 uint32_t fid1; 174 uint32_t len; 175 uint32_t nameplus[0]; 176}; 177 178struct nfs_iodesc { 179 struct iodesc *iodesc; 180 off_t off; 181 uint32_t fhsize; 182 u_char fh[NFS_V3MAXFHSIZE]; 183 struct nfsv3_fattrs fa; /* all in network order */
| 33 34#include <sys/param.h> 35#include <sys/time.h> 36#include <sys/socket.h> 37#include <sys/stat.h> 38#include <string.h> 39 40#include <netinet/in.h> 41#include <netinet/in_systm.h> 42 43#include "rpcv2.h" 44#include "nfsv2.h" 45 46#include "stand.h" 47#include "net.h" 48#include "netif.h" 49#include "rpc.h" 50 51#define NFS_DEBUGxx 52 53#define NFSREAD_SIZE 1024 54 55/* Define our own NFS attributes without NQNFS stuff. */ 56#ifdef OLD_NFSV2 57struct nfsv2_fattrs { 58 n_long fa_type; 59 n_long fa_mode; 60 n_long fa_nlink; 61 n_long fa_uid; 62 n_long fa_gid; 63 n_long fa_size; 64 n_long fa_blocksize; 65 n_long fa_rdev; 66 n_long fa_blocks; 67 n_long fa_fsid; 68 n_long fa_fileid; 69 struct nfsv2_time fa_atime; 70 struct nfsv2_time fa_mtime; 71 struct nfsv2_time fa_ctime; 72}; 73 74struct nfs_read_args { 75 u_char fh[NFS_FHSIZE]; 76 n_long off; 77 n_long len; 78 n_long xxx; /* XXX what's this for? */ 79}; 80 81/* Data part of nfs rpc reply (also the largest thing we receive) */ 82struct nfs_read_repl { 83 n_long errno; 84 struct nfsv2_fattrs fa; 85 n_long count; 86 u_char data[NFSREAD_SIZE]; 87}; 88 89#ifndef NFS_NOSYMLINK 90struct nfs_readlnk_repl { 91 n_long errno; 92 n_long len; 93 char path[NFS_MAXPATHLEN]; 94}; 95#endif 96 97struct nfs_readdir_args { 98 u_char fh[NFS_FHSIZE]; 99 n_long cookie; 100 n_long count; 101}; 102 103struct nfs_readdir_data { 104 n_long fileid; 105 n_long len; 106 char name[0]; 107}; 108 109struct nfs_readdir_off { 110 n_long cookie; 111 n_long follows; 112}; 113 114struct nfs_iodesc { 115 struct iodesc *iodesc; 116 off_t off; 117 u_char fh[NFS_FHSIZE]; 118 struct nfsv2_fattrs fa; /* all in network order */ 119}; 120#else /* !OLD_NFSV2 */ 121 122/* NFSv3 definitions */ 123#define NFS_V3MAXFHSIZE 64 124#define NFS_VER3 3 125#define RPCMNT_VER3 3 126#define NFSPROCV3_LOOKUP 3 127#define NFSPROCV3_READLINK 5 128#define NFSPROCV3_READ 6 129#define NFSPROCV3_READDIR 16 130 131typedef struct { 132 uint32_t val[2]; 133} n_quad; 134 135struct nfsv3_time { 136 uint32_t nfs_sec; 137 uint32_t nfs_nsec; 138}; 139 140struct nfsv3_fattrs { 141 uint32_t fa_type; 142 uint32_t fa_mode; 143 uint32_t fa_nlink; 144 uint32_t fa_uid; 145 uint32_t fa_gid; 146 n_quad fa_size; 147 n_quad fa_used; 148 n_quad fa_rdev; 149 n_quad fa_fsid; 150 n_quad fa_fileid; 151 struct nfsv3_time fa_atime; 152 struct nfsv3_time fa_mtime; 153 struct nfsv3_time fa_ctime; 154}; 155 156/* 157 * For NFSv3, the file handle is variable in size, so most fixed sized 158 * structures for arguments won't work. For most cases, a structure 159 * that starts with any fixed size section is followed by an array 160 * that covers the maximum size required. 161 */ 162struct nfsv3_readdir_repl { 163 uint32_t errno; 164 uint32_t ok; 165 struct nfsv3_fattrs fa; 166 uint32_t cookiev0; 167 uint32_t cookiev1; 168}; 169 170struct nfsv3_readdir_entry { 171 uint32_t follows; 172 uint32_t fid0; 173 uint32_t fid1; 174 uint32_t len; 175 uint32_t nameplus[0]; 176}; 177 178struct nfs_iodesc { 179 struct iodesc *iodesc; 180 off_t off; 181 uint32_t fhsize; 182 u_char fh[NFS_V3MAXFHSIZE]; 183 struct nfsv3_fattrs fa; /* all in network order */
|
| 184 uint64_t cookie;
|
184}; 185#endif /* OLD_NFSV2 */ 186 187/* 188 * XXX interactions with tftp? See nfswrapper.c for a confusing 189 * issue. 190 */ 191int nfs_open(const char *path, struct open_file *f); 192static int nfs_close(struct open_file *f); 193static int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid); 194static int nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid); 195static off_t nfs_seek(struct open_file *f, off_t offset, int where); 196static int nfs_stat(struct open_file *f, struct stat *sb); 197static int nfs_readdir(struct open_file *f, struct dirent *d); 198 199struct nfs_iodesc nfs_root_node; 200 201struct fs_ops nfs_fsops = { 202 "nfs", 203 nfs_open, 204 nfs_close, 205 nfs_read, 206 nfs_write, 207 nfs_seek, 208 nfs_stat, 209 nfs_readdir 210}; 211 212#ifdef OLD_NFSV2 213/* 214 * Fetch the root file handle (call mount daemon) 215 * Return zero or error number. 216 */ 217int 218nfs_getrootfh(struct iodesc *d, char *path, u_char *fhp) 219{ 220 int len; 221 struct args { 222 n_long len; 223 char path[FNAME_SIZE]; 224 } *args; 225 struct repl { 226 n_long errno; 227 u_char fh[NFS_FHSIZE]; 228 } *repl; 229 struct { 230 n_long h[RPC_HEADER_WORDS]; 231 struct args d; 232 } sdata; 233 struct { 234 n_long h[RPC_HEADER_WORDS]; 235 struct repl d; 236 } rdata; 237 size_t cc; 238 239#ifdef NFS_DEBUG 240 if (debug) 241 printf("nfs_getrootfh: %s\n", path); 242#endif 243 244 args = &sdata.d; 245 repl = &rdata.d; 246 247 bzero(args, sizeof(*args)); 248 len = strlen(path); 249 if (len > sizeof(args->path)) 250 len = sizeof(args->path); 251 args->len = htonl(len); 252 bcopy(path, args->path, len); 253 len = 4 + roundup(len, 4); 254 255 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT, 256 args, len, repl, sizeof(*repl)); 257 if (cc == -1) { 258 /* errno was set by rpc_call */ 259 return (errno); 260 } 261 if (cc < 4) 262 return (EBADRPC); 263 if (repl->errno) 264 return (ntohl(repl->errno)); 265 bcopy(repl->fh, fhp, sizeof(repl->fh)); 266 return (0); 267} 268 269/* 270 * Lookup a file. Store handle and attributes. 271 * Return zero or error number. 272 */ 273int 274nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) 275{ 276 int len, rlen; 277 struct args { 278 u_char fh[NFS_FHSIZE]; 279 n_long len; 280 char name[FNAME_SIZE]; 281 } *args; 282 struct repl { 283 n_long errno; 284 u_char fh[NFS_FHSIZE]; 285 struct nfsv2_fattrs fa; 286 } *repl; 287 struct { 288 n_long h[RPC_HEADER_WORDS]; 289 struct args d; 290 } sdata; 291 struct { 292 n_long h[RPC_HEADER_WORDS]; 293 struct repl d; 294 } rdata; 295 ssize_t cc; 296 297#ifdef NFS_DEBUG 298 if (debug) 299 printf("lookupfh: called\n"); 300#endif 301 302 args = &sdata.d; 303 repl = &rdata.d; 304 305 bzero(args, sizeof(*args)); 306 bcopy(d->fh, args->fh, sizeof(args->fh)); 307 len = strlen(name); 308 if (len > sizeof(args->name)) 309 len = sizeof(args->name); 310 bcopy(name, args->name, len); 311 args->len = htonl(len); 312 len = 4 + roundup(len, 4); 313 len += NFS_FHSIZE; 314 315 rlen = sizeof(*repl); 316 317 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP, 318 args, len, repl, rlen); 319 if (cc == -1) 320 return (errno); /* XXX - from rpc_call */ 321 if (cc < 4) 322 return (EIO); 323 if (repl->errno) { 324 /* saerrno.h now matches NFS error numbers. */ 325 return (ntohl(repl->errno)); 326 } 327 bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh)); 328 bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa)); 329 return (0); 330} 331 332#ifndef NFS_NOSYMLINK 333/* 334 * Get the destination of a symbolic link. 335 */ 336int 337nfs_readlink(struct nfs_iodesc *d, char *buf) 338{ 339 struct { 340 n_long h[RPC_HEADER_WORDS]; 341 u_char fh[NFS_FHSIZE]; 342 } sdata; 343 struct { 344 n_long h[RPC_HEADER_WORDS]; 345 struct nfs_readlnk_repl d; 346 } rdata; 347 ssize_t cc; 348 349#ifdef NFS_DEBUG 350 if (debug) 351 printf("readlink: called\n"); 352#endif 353 354 bcopy(d->fh, sdata.fh, NFS_FHSIZE); 355 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK, 356 sdata.fh, NFS_FHSIZE, 357 &rdata.d, sizeof(rdata.d)); 358 if (cc == -1) 359 return (errno); 360 361 if (cc < 4) 362 return (EIO); 363 364 if (rdata.d.errno) 365 return (ntohl(rdata.d.errno)); 366 367 rdata.d.len = ntohl(rdata.d.len); 368 if (rdata.d.len > NFS_MAXPATHLEN) 369 return (ENAMETOOLONG); 370 371 bcopy(rdata.d.path, buf, rdata.d.len); 372 buf[rdata.d.len] = 0; 373 return (0); 374} 375#endif 376 377/* 378 * Read data from a file. 379 * Return transfer count or -1 (and set errno) 380 */ 381ssize_t 382nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) 383{ 384 struct nfs_read_args *args; 385 struct nfs_read_repl *repl; 386 struct { 387 n_long h[RPC_HEADER_WORDS]; 388 struct nfs_read_args d; 389 } sdata; 390 struct { 391 n_long h[RPC_HEADER_WORDS]; 392 struct nfs_read_repl d; 393 } rdata; 394 size_t cc; 395 long x; 396 int hlen, rlen; 397 398 args = &sdata.d; 399 repl = &rdata.d; 400 401 bcopy(d->fh, args->fh, NFS_FHSIZE); 402 args->off = htonl((n_long)off); 403 if (len > NFSREAD_SIZE) 404 len = NFSREAD_SIZE; 405 args->len = htonl((n_long)len); 406 args->xxx = htonl((n_long)0); 407 hlen = sizeof(*repl) - NFSREAD_SIZE; 408 409 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ, 410 args, sizeof(*args), 411 repl, sizeof(*repl)); 412 if (cc == -1) { 413 /* errno was already set by rpc_call */ 414 return (-1); 415 } 416 if (cc < hlen) { 417 errno = EBADRPC; 418 return (-1); 419 } 420 if (repl->errno) { 421 errno = ntohl(repl->errno); 422 return (-1); 423 } 424 rlen = cc - hlen; 425 x = ntohl(repl->count); 426 if (rlen < x) { 427 printf("nfsread: short packet, %d < %ld\n", rlen, x); 428 errno = EBADRPC; 429 return(-1); 430 } 431 bcopy(repl->data, addr, x); 432 return (x); 433} 434 435/* 436 * Open a file. 437 * return zero or error number 438 */ 439int 440nfs_open(const char *upath, struct open_file *f) 441{ 442 struct iodesc *desc; 443 struct nfs_iodesc *currfd; 444 char buf[2 * NFS_FHSIZE + 3]; 445 u_char *fh; 446 char *cp; 447 int i; 448#ifndef NFS_NOSYMLINK 449 struct nfs_iodesc *newfd; 450 struct nfsv2_fattrs *fa; 451 char *ncp; 452 int c; 453 char namebuf[NFS_MAXPATHLEN + 1]; 454 char linkbuf[NFS_MAXPATHLEN + 1]; 455 int nlinks = 0; 456#endif 457 int error; 458 char *path; 459 460#ifdef NFS_DEBUG 461 if (debug) 462 printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath); 463#endif 464 if (!rootpath[0]) { 465 printf("no rootpath, no nfs\n"); 466 return (ENXIO); 467 } 468 469 /* 470 * This is silly - we should look at dv_type but that value is 471 * arch dependant and we can't use it here. 472 */ 473#ifndef __i386__ 474 if (strcmp(f->f_dev->dv_name, "net") != 0) 475 return(EINVAL); 476#else 477 if (strcmp(f->f_dev->dv_name, "pxe") != 0) 478 return(EINVAL); 479#endif 480 481 if (!(desc = socktodesc(*(int *)(f->f_devdata)))) 482 return(EINVAL); 483 484 /* Bind to a reserved port. */ 485 desc->myport = htons(--rpc_port); 486 desc->destip = rootip; 487 if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh))) 488 return (error); 489 nfs_root_node.fa.fa_type = htonl(NFDIR); 490 nfs_root_node.fa.fa_mode = htonl(0755); 491 nfs_root_node.fa.fa_nlink = htonl(2); 492 nfs_root_node.iodesc = desc; 493 494 fh = &nfs_root_node.fh[0]; 495 buf[0] = 'X'; 496 cp = &buf[1]; 497 for (i = 0; i < NFS_FHSIZE; i++, cp += 2) 498 sprintf(cp, "%02x", fh[i]); 499 sprintf(cp, "X"); 500 setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); 501 setenv("boot.nfsroot.path", rootpath, 1); 502 setenv("boot.nfsroot.nfshandle", buf, 1); 503 504 /* Allocate file system specific data structure */ 505 currfd = malloc(sizeof(*newfd)); 506 if (currfd == NULL) { 507 error = ENOMEM; 508 goto out; 509 } 510 511#ifndef NFS_NOSYMLINK 512 bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 513 newfd = 0; 514 515 cp = path = strdup(upath); 516 if (path == NULL) { 517 error = ENOMEM; 518 goto out; 519 } 520 while (*cp) { 521 /* 522 * Remove extra separators 523 */ 524 while (*cp == '/') 525 cp++; 526 527 if (*cp == '\0') 528 break; 529 /* 530 * Check that current node is a directory. 531 */ 532 if (currfd->fa.fa_type != htonl(NFDIR)) { 533 error = ENOTDIR; 534 goto out; 535 } 536 537 /* allocate file system specific data structure */ 538 newfd = malloc(sizeof(*newfd)); 539 newfd->iodesc = currfd->iodesc; 540 541 /* 542 * Get next component of path name. 543 */ 544 { 545 int len = 0; 546 547 ncp = cp; 548 while ((c = *cp) != '\0' && c != '/') { 549 if (++len > NFS_MAXNAMLEN) { 550 error = ENOENT; 551 goto out; 552 } 553 cp++; 554 } 555 *cp = '\0'; 556 } 557 558 /* lookup a file handle */ 559 error = nfs_lookupfh(currfd, ncp, newfd); 560 *cp = c; 561 if (error) 562 goto out; 563 564 /* 565 * Check for symbolic link 566 */ 567 if (newfd->fa.fa_type == htonl(NFLNK)) { 568 int link_len, len; 569 570 error = nfs_readlink(newfd, linkbuf); 571 if (error) 572 goto out; 573 574 link_len = strlen(linkbuf); 575 len = strlen(cp); 576 577 if (link_len + len > MAXPATHLEN 578 || ++nlinks > MAXSYMLINKS) { 579 error = ENOENT; 580 goto out; 581 } 582 583 bcopy(cp, &namebuf[link_len], len + 1); 584 bcopy(linkbuf, namebuf, link_len); 585 586 /* 587 * If absolute pathname, restart at root. 588 * If relative pathname, restart at parent directory. 589 */ 590 cp = namebuf; 591 if (*cp == '/') 592 bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 593 594 free(newfd); 595 newfd = 0; 596 597 continue; 598 } 599 600 free(currfd); 601 currfd = newfd; 602 newfd = 0; 603 } 604 605 error = 0; 606 607out: 608 if (newfd) 609 free(newfd); 610 if (path) 611 free(path); 612#else 613 currfd->iodesc = desc; 614 615 error = nfs_lookupfh(&nfs_root_node, upath, currfd); 616#endif 617 if (!error) { 618 currfd->off = 0; 619 f->f_fsdata = (void *)currfd; 620 return (0); 621 } 622 623#ifdef NFS_DEBUG 624 if (debug) 625 printf("nfs_open: %s lookupfh failed: %s\n", 626 path, strerror(error)); 627#endif 628 free(currfd); 629 630 return (error); 631} 632 633int 634nfs_close(struct open_file *f) 635{ 636 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 637 638#ifdef NFS_DEBUG 639 if (debug) 640 printf("nfs_close: fp=0x%lx\n", (u_long)fp); 641#endif 642 643 if (fp) 644 free(fp); 645 f->f_fsdata = (void *)0; 646 647 return (0); 648} 649 650/* 651 * read a portion of a file 652 */ 653int 654nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 655{ 656 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 657 ssize_t cc; 658 char *addr = buf; 659 660#ifdef NFS_DEBUG 661 if (debug) 662 printf("nfs_read: size=%lu off=%d\n", (u_long)size, 663 (int)fp->off); 664#endif 665 while ((int)size > 0) { 666 twiddle(); 667 cc = nfs_readdata(fp, fp->off, (void *)addr, size); 668 /* XXX maybe should retry on certain errors */ 669 if (cc == -1) { 670#ifdef NFS_DEBUG 671 if (debug) 672 printf("nfs_read: read: %s", strerror(errno)); 673#endif 674 return (errno); /* XXX - from nfs_readdata */ 675 } 676 if (cc == 0) { 677#ifdef NFS_DEBUG 678 if (debug) 679 printf("nfs_read: hit EOF unexpectantly"); 680#endif 681 goto ret; 682 } 683 fp->off += cc; 684 addr += cc; 685 size -= cc; 686 } 687ret: 688 if (resid) 689 *resid = size; 690 691 return (0); 692} 693 694/* 695 * Not implemented. 696 */ 697int 698nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) 699{ 700 return (EROFS); 701} 702 703off_t 704nfs_seek(struct open_file *f, off_t offset, int where) 705{ 706 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 707 n_long size = ntohl(d->fa.fa_size); 708 709 switch (where) { 710 case SEEK_SET: 711 d->off = offset; 712 break; 713 case SEEK_CUR: 714 d->off += offset; 715 break; 716 case SEEK_END: 717 d->off = size - offset; 718 break; 719 default: 720 errno = EINVAL; 721 return (-1); 722 } 723 724 return (d->off); 725} 726 727/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */ 728int nfs_stat_types[8] = { 729 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 }; 730 731int 732nfs_stat(struct open_file *f, struct stat *sb) 733{ 734 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 735 n_long ftype, mode; 736 737 ftype = ntohl(fp->fa.fa_type); 738 mode = ntohl(fp->fa.fa_mode); 739 mode |= nfs_stat_types[ftype & 7]; 740 741 sb->st_mode = mode; 742 sb->st_nlink = ntohl(fp->fa.fa_nlink); 743 sb->st_uid = ntohl(fp->fa.fa_uid); 744 sb->st_gid = ntohl(fp->fa.fa_gid); 745 sb->st_size = ntohl(fp->fa.fa_size); 746 747 return (0); 748} 749 750static int 751nfs_readdir(struct open_file *f, struct dirent *d) 752{ 753 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 754 struct nfs_readdir_args *args; 755 struct nfs_readdir_data *rd; 756 struct nfs_readdir_off *roff = NULL; 757 static char *buf;
| 185}; 186#endif /* OLD_NFSV2 */ 187 188/* 189 * XXX interactions with tftp? See nfswrapper.c for a confusing 190 * issue. 191 */ 192int nfs_open(const char *path, struct open_file *f); 193static int nfs_close(struct open_file *f); 194static int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid); 195static int nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid); 196static off_t nfs_seek(struct open_file *f, off_t offset, int where); 197static int nfs_stat(struct open_file *f, struct stat *sb); 198static int nfs_readdir(struct open_file *f, struct dirent *d); 199 200struct nfs_iodesc nfs_root_node; 201 202struct fs_ops nfs_fsops = { 203 "nfs", 204 nfs_open, 205 nfs_close, 206 nfs_read, 207 nfs_write, 208 nfs_seek, 209 nfs_stat, 210 nfs_readdir 211}; 212 213#ifdef OLD_NFSV2 214/* 215 * Fetch the root file handle (call mount daemon) 216 * Return zero or error number. 217 */ 218int 219nfs_getrootfh(struct iodesc *d, char *path, u_char *fhp) 220{ 221 int len; 222 struct args { 223 n_long len; 224 char path[FNAME_SIZE]; 225 } *args; 226 struct repl { 227 n_long errno; 228 u_char fh[NFS_FHSIZE]; 229 } *repl; 230 struct { 231 n_long h[RPC_HEADER_WORDS]; 232 struct args d; 233 } sdata; 234 struct { 235 n_long h[RPC_HEADER_WORDS]; 236 struct repl d; 237 } rdata; 238 size_t cc; 239 240#ifdef NFS_DEBUG 241 if (debug) 242 printf("nfs_getrootfh: %s\n", path); 243#endif 244 245 args = &sdata.d; 246 repl = &rdata.d; 247 248 bzero(args, sizeof(*args)); 249 len = strlen(path); 250 if (len > sizeof(args->path)) 251 len = sizeof(args->path); 252 args->len = htonl(len); 253 bcopy(path, args->path, len); 254 len = 4 + roundup(len, 4); 255 256 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT, 257 args, len, repl, sizeof(*repl)); 258 if (cc == -1) { 259 /* errno was set by rpc_call */ 260 return (errno); 261 } 262 if (cc < 4) 263 return (EBADRPC); 264 if (repl->errno) 265 return (ntohl(repl->errno)); 266 bcopy(repl->fh, fhp, sizeof(repl->fh)); 267 return (0); 268} 269 270/* 271 * Lookup a file. Store handle and attributes. 272 * Return zero or error number. 273 */ 274int 275nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) 276{ 277 int len, rlen; 278 struct args { 279 u_char fh[NFS_FHSIZE]; 280 n_long len; 281 char name[FNAME_SIZE]; 282 } *args; 283 struct repl { 284 n_long errno; 285 u_char fh[NFS_FHSIZE]; 286 struct nfsv2_fattrs fa; 287 } *repl; 288 struct { 289 n_long h[RPC_HEADER_WORDS]; 290 struct args d; 291 } sdata; 292 struct { 293 n_long h[RPC_HEADER_WORDS]; 294 struct repl d; 295 } rdata; 296 ssize_t cc; 297 298#ifdef NFS_DEBUG 299 if (debug) 300 printf("lookupfh: called\n"); 301#endif 302 303 args = &sdata.d; 304 repl = &rdata.d; 305 306 bzero(args, sizeof(*args)); 307 bcopy(d->fh, args->fh, sizeof(args->fh)); 308 len = strlen(name); 309 if (len > sizeof(args->name)) 310 len = sizeof(args->name); 311 bcopy(name, args->name, len); 312 args->len = htonl(len); 313 len = 4 + roundup(len, 4); 314 len += NFS_FHSIZE; 315 316 rlen = sizeof(*repl); 317 318 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP, 319 args, len, repl, rlen); 320 if (cc == -1) 321 return (errno); /* XXX - from rpc_call */ 322 if (cc < 4) 323 return (EIO); 324 if (repl->errno) { 325 /* saerrno.h now matches NFS error numbers. */ 326 return (ntohl(repl->errno)); 327 } 328 bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh)); 329 bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa)); 330 return (0); 331} 332 333#ifndef NFS_NOSYMLINK 334/* 335 * Get the destination of a symbolic link. 336 */ 337int 338nfs_readlink(struct nfs_iodesc *d, char *buf) 339{ 340 struct { 341 n_long h[RPC_HEADER_WORDS]; 342 u_char fh[NFS_FHSIZE]; 343 } sdata; 344 struct { 345 n_long h[RPC_HEADER_WORDS]; 346 struct nfs_readlnk_repl d; 347 } rdata; 348 ssize_t cc; 349 350#ifdef NFS_DEBUG 351 if (debug) 352 printf("readlink: called\n"); 353#endif 354 355 bcopy(d->fh, sdata.fh, NFS_FHSIZE); 356 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK, 357 sdata.fh, NFS_FHSIZE, 358 &rdata.d, sizeof(rdata.d)); 359 if (cc == -1) 360 return (errno); 361 362 if (cc < 4) 363 return (EIO); 364 365 if (rdata.d.errno) 366 return (ntohl(rdata.d.errno)); 367 368 rdata.d.len = ntohl(rdata.d.len); 369 if (rdata.d.len > NFS_MAXPATHLEN) 370 return (ENAMETOOLONG); 371 372 bcopy(rdata.d.path, buf, rdata.d.len); 373 buf[rdata.d.len] = 0; 374 return (0); 375} 376#endif 377 378/* 379 * Read data from a file. 380 * Return transfer count or -1 (and set errno) 381 */ 382ssize_t 383nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) 384{ 385 struct nfs_read_args *args; 386 struct nfs_read_repl *repl; 387 struct { 388 n_long h[RPC_HEADER_WORDS]; 389 struct nfs_read_args d; 390 } sdata; 391 struct { 392 n_long h[RPC_HEADER_WORDS]; 393 struct nfs_read_repl d; 394 } rdata; 395 size_t cc; 396 long x; 397 int hlen, rlen; 398 399 args = &sdata.d; 400 repl = &rdata.d; 401 402 bcopy(d->fh, args->fh, NFS_FHSIZE); 403 args->off = htonl((n_long)off); 404 if (len > NFSREAD_SIZE) 405 len = NFSREAD_SIZE; 406 args->len = htonl((n_long)len); 407 args->xxx = htonl((n_long)0); 408 hlen = sizeof(*repl) - NFSREAD_SIZE; 409 410 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ, 411 args, sizeof(*args), 412 repl, sizeof(*repl)); 413 if (cc == -1) { 414 /* errno was already set by rpc_call */ 415 return (-1); 416 } 417 if (cc < hlen) { 418 errno = EBADRPC; 419 return (-1); 420 } 421 if (repl->errno) { 422 errno = ntohl(repl->errno); 423 return (-1); 424 } 425 rlen = cc - hlen; 426 x = ntohl(repl->count); 427 if (rlen < x) { 428 printf("nfsread: short packet, %d < %ld\n", rlen, x); 429 errno = EBADRPC; 430 return(-1); 431 } 432 bcopy(repl->data, addr, x); 433 return (x); 434} 435 436/* 437 * Open a file. 438 * return zero or error number 439 */ 440int 441nfs_open(const char *upath, struct open_file *f) 442{ 443 struct iodesc *desc; 444 struct nfs_iodesc *currfd; 445 char buf[2 * NFS_FHSIZE + 3]; 446 u_char *fh; 447 char *cp; 448 int i; 449#ifndef NFS_NOSYMLINK 450 struct nfs_iodesc *newfd; 451 struct nfsv2_fattrs *fa; 452 char *ncp; 453 int c; 454 char namebuf[NFS_MAXPATHLEN + 1]; 455 char linkbuf[NFS_MAXPATHLEN + 1]; 456 int nlinks = 0; 457#endif 458 int error; 459 char *path; 460 461#ifdef NFS_DEBUG 462 if (debug) 463 printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath); 464#endif 465 if (!rootpath[0]) { 466 printf("no rootpath, no nfs\n"); 467 return (ENXIO); 468 } 469 470 /* 471 * This is silly - we should look at dv_type but that value is 472 * arch dependant and we can't use it here. 473 */ 474#ifndef __i386__ 475 if (strcmp(f->f_dev->dv_name, "net") != 0) 476 return(EINVAL); 477#else 478 if (strcmp(f->f_dev->dv_name, "pxe") != 0) 479 return(EINVAL); 480#endif 481 482 if (!(desc = socktodesc(*(int *)(f->f_devdata)))) 483 return(EINVAL); 484 485 /* Bind to a reserved port. */ 486 desc->myport = htons(--rpc_port); 487 desc->destip = rootip; 488 if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh))) 489 return (error); 490 nfs_root_node.fa.fa_type = htonl(NFDIR); 491 nfs_root_node.fa.fa_mode = htonl(0755); 492 nfs_root_node.fa.fa_nlink = htonl(2); 493 nfs_root_node.iodesc = desc; 494 495 fh = &nfs_root_node.fh[0]; 496 buf[0] = 'X'; 497 cp = &buf[1]; 498 for (i = 0; i < NFS_FHSIZE; i++, cp += 2) 499 sprintf(cp, "%02x", fh[i]); 500 sprintf(cp, "X"); 501 setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); 502 setenv("boot.nfsroot.path", rootpath, 1); 503 setenv("boot.nfsroot.nfshandle", buf, 1); 504 505 /* Allocate file system specific data structure */ 506 currfd = malloc(sizeof(*newfd)); 507 if (currfd == NULL) { 508 error = ENOMEM; 509 goto out; 510 } 511 512#ifndef NFS_NOSYMLINK 513 bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 514 newfd = 0; 515 516 cp = path = strdup(upath); 517 if (path == NULL) { 518 error = ENOMEM; 519 goto out; 520 } 521 while (*cp) { 522 /* 523 * Remove extra separators 524 */ 525 while (*cp == '/') 526 cp++; 527 528 if (*cp == '\0') 529 break; 530 /* 531 * Check that current node is a directory. 532 */ 533 if (currfd->fa.fa_type != htonl(NFDIR)) { 534 error = ENOTDIR; 535 goto out; 536 } 537 538 /* allocate file system specific data structure */ 539 newfd = malloc(sizeof(*newfd)); 540 newfd->iodesc = currfd->iodesc; 541 542 /* 543 * Get next component of path name. 544 */ 545 { 546 int len = 0; 547 548 ncp = cp; 549 while ((c = *cp) != '\0' && c != '/') { 550 if (++len > NFS_MAXNAMLEN) { 551 error = ENOENT; 552 goto out; 553 } 554 cp++; 555 } 556 *cp = '\0'; 557 } 558 559 /* lookup a file handle */ 560 error = nfs_lookupfh(currfd, ncp, newfd); 561 *cp = c; 562 if (error) 563 goto out; 564 565 /* 566 * Check for symbolic link 567 */ 568 if (newfd->fa.fa_type == htonl(NFLNK)) { 569 int link_len, len; 570 571 error = nfs_readlink(newfd, linkbuf); 572 if (error) 573 goto out; 574 575 link_len = strlen(linkbuf); 576 len = strlen(cp); 577 578 if (link_len + len > MAXPATHLEN 579 || ++nlinks > MAXSYMLINKS) { 580 error = ENOENT; 581 goto out; 582 } 583 584 bcopy(cp, &namebuf[link_len], len + 1); 585 bcopy(linkbuf, namebuf, link_len); 586 587 /* 588 * If absolute pathname, restart at root. 589 * If relative pathname, restart at parent directory. 590 */ 591 cp = namebuf; 592 if (*cp == '/') 593 bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 594 595 free(newfd); 596 newfd = 0; 597 598 continue; 599 } 600 601 free(currfd); 602 currfd = newfd; 603 newfd = 0; 604 } 605 606 error = 0; 607 608out: 609 if (newfd) 610 free(newfd); 611 if (path) 612 free(path); 613#else 614 currfd->iodesc = desc; 615 616 error = nfs_lookupfh(&nfs_root_node, upath, currfd); 617#endif 618 if (!error) { 619 currfd->off = 0; 620 f->f_fsdata = (void *)currfd; 621 return (0); 622 } 623 624#ifdef NFS_DEBUG 625 if (debug) 626 printf("nfs_open: %s lookupfh failed: %s\n", 627 path, strerror(error)); 628#endif 629 free(currfd); 630 631 return (error); 632} 633 634int 635nfs_close(struct open_file *f) 636{ 637 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 638 639#ifdef NFS_DEBUG 640 if (debug) 641 printf("nfs_close: fp=0x%lx\n", (u_long)fp); 642#endif 643 644 if (fp) 645 free(fp); 646 f->f_fsdata = (void *)0; 647 648 return (0); 649} 650 651/* 652 * read a portion of a file 653 */ 654int 655nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 656{ 657 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 658 ssize_t cc; 659 char *addr = buf; 660 661#ifdef NFS_DEBUG 662 if (debug) 663 printf("nfs_read: size=%lu off=%d\n", (u_long)size, 664 (int)fp->off); 665#endif 666 while ((int)size > 0) { 667 twiddle(); 668 cc = nfs_readdata(fp, fp->off, (void *)addr, size); 669 /* XXX maybe should retry on certain errors */ 670 if (cc == -1) { 671#ifdef NFS_DEBUG 672 if (debug) 673 printf("nfs_read: read: %s", strerror(errno)); 674#endif 675 return (errno); /* XXX - from nfs_readdata */ 676 } 677 if (cc == 0) { 678#ifdef NFS_DEBUG 679 if (debug) 680 printf("nfs_read: hit EOF unexpectantly"); 681#endif 682 goto ret; 683 } 684 fp->off += cc; 685 addr += cc; 686 size -= cc; 687 } 688ret: 689 if (resid) 690 *resid = size; 691 692 return (0); 693} 694 695/* 696 * Not implemented. 697 */ 698int 699nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) 700{ 701 return (EROFS); 702} 703 704off_t 705nfs_seek(struct open_file *f, off_t offset, int where) 706{ 707 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 708 n_long size = ntohl(d->fa.fa_size); 709 710 switch (where) { 711 case SEEK_SET: 712 d->off = offset; 713 break; 714 case SEEK_CUR: 715 d->off += offset; 716 break; 717 case SEEK_END: 718 d->off = size - offset; 719 break; 720 default: 721 errno = EINVAL; 722 return (-1); 723 } 724 725 return (d->off); 726} 727 728/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */ 729int nfs_stat_types[8] = { 730 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 }; 731 732int 733nfs_stat(struct open_file *f, struct stat *sb) 734{ 735 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 736 n_long ftype, mode; 737 738 ftype = ntohl(fp->fa.fa_type); 739 mode = ntohl(fp->fa.fa_mode); 740 mode |= nfs_stat_types[ftype & 7]; 741 742 sb->st_mode = mode; 743 sb->st_nlink = ntohl(fp->fa.fa_nlink); 744 sb->st_uid = ntohl(fp->fa.fa_uid); 745 sb->st_gid = ntohl(fp->fa.fa_gid); 746 sb->st_size = ntohl(fp->fa.fa_size); 747 748 return (0); 749} 750 751static int 752nfs_readdir(struct open_file *f, struct dirent *d) 753{ 754 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 755 struct nfs_readdir_args *args; 756 struct nfs_readdir_data *rd; 757 struct nfs_readdir_off *roff = NULL; 758 static char *buf;
|
| 759 static struct nfs_iodesc *pfp = NULL;
|
758 static n_long cookie = 0; 759 size_t cc; 760 n_long eof; 761 762 struct { 763 n_long h[RPC_HEADER_WORDS]; 764 struct nfs_readdir_args d; 765 } sdata; 766 static struct { 767 n_long h[RPC_HEADER_WORDS]; 768 u_char d[NFS_READDIRSIZE]; 769 } rdata; 770
| 760 static n_long cookie = 0; 761 size_t cc; 762 n_long eof; 763 764 struct { 765 n_long h[RPC_HEADER_WORDS]; 766 struct nfs_readdir_args d; 767 } sdata; 768 static struct { 769 n_long h[RPC_HEADER_WORDS]; 770 u_char d[NFS_READDIRSIZE]; 771 } rdata; 772
|
771 if (cookie == 0) {
| 773 if (fp != pfp || fp->off != cookie) { 774 pfp = NULL;
|
772 refill: 773 args = &sdata.d; 774 bzero(args, sizeof(*args)); 775 776 bcopy(fp->fh, args->fh, NFS_FHSIZE);
| 775 refill: 776 args = &sdata.d; 777 bzero(args, sizeof(*args)); 778 779 bcopy(fp->fh, args->fh, NFS_FHSIZE);
|
777 args->cookie = htonl(cookie);
| 780 args->cookie = htonl(fp->off);
|
778 args->count = htonl(NFS_READDIRSIZE); 779 780 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR, 781 args, sizeof(*args), 782 rdata.d, sizeof(rdata.d)); 783 buf = rdata.d; 784 roff = (struct nfs_readdir_off *)buf; 785 if (ntohl(roff->cookie) != 0) 786 return EIO;
| 781 args->count = htonl(NFS_READDIRSIZE); 782 783 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR, 784 args, sizeof(*args), 785 rdata.d, sizeof(rdata.d)); 786 buf = rdata.d; 787 roff = (struct nfs_readdir_off *)buf; 788 if (ntohl(roff->cookie) != 0) 789 return EIO;
|
| 790 pfp = fp; 791 cookie = fp->off;
|
787 } 788 roff = (struct nfs_readdir_off *)buf; 789 790 if (ntohl(roff->follows) == 0) { 791 eof = ntohl((roff+1)->cookie); 792 if (eof) { 793 cookie = 0; 794 return ENOENT; 795 } 796 goto refill; 797 } 798 799 buf += sizeof(struct nfs_readdir_off); 800 rd = (struct nfs_readdir_data *)buf; 801 d->d_namlen = ntohl(rd->len); 802 bcopy(rd->name, d->d_name, d->d_namlen); 803 d->d_name[d->d_namlen] = '\0'; 804 805 buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4)); 806 roff = (struct nfs_readdir_off *)buf;
| 792 } 793 roff = (struct nfs_readdir_off *)buf; 794 795 if (ntohl(roff->follows) == 0) { 796 eof = ntohl((roff+1)->cookie); 797 if (eof) { 798 cookie = 0; 799 return ENOENT; 800 } 801 goto refill; 802 } 803 804 buf += sizeof(struct nfs_readdir_off); 805 rd = (struct nfs_readdir_data *)buf; 806 d->d_namlen = ntohl(rd->len); 807 bcopy(rd->name, d->d_name, d->d_namlen); 808 d->d_name[d->d_namlen] = '\0'; 809 810 buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4)); 811 roff = (struct nfs_readdir_off *)buf;
|
807 cookie = ntohl(roff->cookie);
| 812 fp->off = cookie = ntohl(roff->cookie);
|
808 return 0; 809} 810#else /* !OLD_NFSV2 */ 811/* 812 * Fetch the root file handle (call mount daemon) 813 * Return zero or error number. 814 */ 815int 816nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp) 817{ 818 int len; 819 struct args { 820 uint32_t len; 821 char path[FNAME_SIZE]; 822 } *args; 823 struct repl { 824 uint32_t errno; 825 uint32_t fhsize; 826 u_char fh[NFS_V3MAXFHSIZE]; 827 uint32_t authcnt; 828 uint32_t auth[7]; 829 } *repl; 830 struct { 831 uint32_t h[RPC_HEADER_WORDS]; 832 struct args d; 833 } sdata; 834 struct { 835 uint32_t h[RPC_HEADER_WORDS]; 836 struct repl d; 837 } rdata; 838 size_t cc; 839 840#ifdef NFS_DEBUG 841 if (debug) 842 printf("nfs_getrootfh: %s\n", path); 843#endif 844 845 args = &sdata.d; 846 repl = &rdata.d; 847 848 bzero(args, sizeof(*args)); 849 len = strlen(path); 850 if (len > sizeof(args->path)) 851 len = sizeof(args->path); 852 args->len = htonl(len); 853 bcopy(path, args->path, len); 854 len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t)); 855 856 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT, 857 args, len, repl, sizeof(*repl)); 858 if (cc == -1) 859 /* errno was set by rpc_call */ 860 return (errno); 861 if (cc < 2 * sizeof (uint32_t)) 862 return (EBADRPC); 863 if (repl->errno != 0) 864 return (ntohl(repl->errno)); 865 *fhlenp = ntohl(repl->fhsize); 866 bcopy(repl->fh, fhp, *fhlenp); 867 return (0); 868} 869 870/* 871 * Lookup a file. Store handle and attributes. 872 * Return zero or error number. 873 */ 874int 875nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) 876{ 877 int len, rlen, pos; 878 struct args { 879 uint32_t fhsize; 880 uint32_t fhplusname[1 + 881 (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)]; 882 } *args; 883 struct repl { 884 uint32_t errno; 885 uint32_t fhsize; 886 uint32_t fhplusattr[(NFS_V3MAXFHSIZE + 887 2 * (sizeof(uint32_t) + 888 sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)]; 889 } *repl; 890 struct { 891 uint32_t h[RPC_HEADER_WORDS]; 892 struct args d; 893 } sdata; 894 struct { 895 uint32_t h[RPC_HEADER_WORDS]; 896 struct repl d; 897 } rdata; 898 ssize_t cc; 899 900#ifdef NFS_DEBUG 901 if (debug) 902 printf("lookupfh: called\n"); 903#endif 904 905 args = &sdata.d; 906 repl = &rdata.d; 907 908 bzero(args, sizeof(*args)); 909 args->fhsize = htonl(d->fhsize); 910 bcopy(d->fh, args->fhplusname, d->fhsize); 911 len = strlen(name); 912 if (len > FNAME_SIZE) 913 len = FNAME_SIZE; 914 pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 915 args->fhplusname[pos++] = htonl(len); 916 bcopy(name, &args->fhplusname[pos], len); 917 len = sizeof(uint32_t) + pos * sizeof(uint32_t) + 918 roundup(len, sizeof(uint32_t)); 919 920 rlen = sizeof(*repl); 921 922 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP, 923 args, len, repl, rlen); 924 if (cc == -1) 925 return (errno); /* XXX - from rpc_call */ 926 if (cc < 2 * sizeof(uint32_t)) 927 return (EIO); 928 if (repl->errno != 0) 929 /* saerrno.h now matches NFS error numbers. */ 930 return (ntohl(repl->errno)); 931 newfd->fhsize = ntohl(repl->fhsize); 932 bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize); 933 pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 934 if (repl->fhplusattr[pos++] == 0) 935 return (EIO); 936 bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa)); 937 return (0); 938} 939 940#ifndef NFS_NOSYMLINK 941/* 942 * Get the destination of a symbolic link. 943 */ 944int 945nfs_readlink(struct nfs_iodesc *d, char *buf) 946{ 947 struct args { 948 uint32_t fhsize; 949 u_char fh[NFS_V3MAXFHSIZE]; 950 } *args; 951 struct repl { 952 uint32_t errno; 953 uint32_t ok; 954 struct nfsv3_fattrs fa; 955 uint32_t len; 956 u_char path[NFS_MAXPATHLEN]; 957 } *repl; 958 struct { 959 uint32_t h[RPC_HEADER_WORDS]; 960 struct args d; 961 } sdata; 962 struct { 963 uint32_t h[RPC_HEADER_WORDS]; 964 struct repl d; 965 } rdata; 966 ssize_t cc; 967 968#ifdef NFS_DEBUG 969 if (debug) 970 printf("readlink: called\n"); 971#endif 972 973 args = &sdata.d; 974 repl = &rdata.d; 975 976 bzero(args, sizeof(*args)); 977 args->fhsize = htonl(d->fhsize); 978 bcopy(d->fh, args->fh, d->fhsize); 979 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK, 980 args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), 981 repl, sizeof(*repl)); 982 if (cc == -1) 983 return (errno); 984 985 if (cc < 2 * sizeof(uint32_t)) 986 return (EIO); 987 988 if (repl->errno != 0) 989 return (ntohl(repl->errno)); 990 991 if (repl->ok == 0) 992 return (EIO); 993 994 repl->len = ntohl(repl->len); 995 if (repl->len > NFS_MAXPATHLEN) 996 return (ENAMETOOLONG); 997 998 bcopy(repl->path, buf, repl->len); 999 buf[repl->len] = 0; 1000 return (0); 1001} 1002#endif 1003 1004/* 1005 * Read data from a file. 1006 * Return transfer count or -1 (and set errno) 1007 */ 1008ssize_t 1009nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) 1010{ 1011 struct args { 1012 uint32_t fhsize; 1013 uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3]; 1014 } *args; 1015 struct repl { 1016 uint32_t errno; 1017 uint32_t ok; 1018 struct nfsv3_fattrs fa; 1019 uint32_t count; 1020 uint32_t eof; 1021 uint32_t len; 1022 u_char data[NFSREAD_SIZE]; 1023 } *repl; 1024 struct { 1025 uint32_t h[RPC_HEADER_WORDS]; 1026 struct args d; 1027 } sdata; 1028 struct { 1029 uint32_t h[RPC_HEADER_WORDS]; 1030 struct repl d; 1031 } rdata; 1032 size_t cc; 1033 long x; 1034 int hlen, rlen, pos; 1035 1036 args = &sdata.d; 1037 repl = &rdata.d; 1038 1039 bzero(args, sizeof(*args)); 1040 args->fhsize = htonl(d->fhsize); 1041 bcopy(d->fh, args->fhoffcnt, d->fhsize); 1042 pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 1043 args->fhoffcnt[pos++] = 0; 1044 args->fhoffcnt[pos++] = htonl((uint32_t)off); 1045 if (len > NFSREAD_SIZE) 1046 len = NFSREAD_SIZE; 1047 args->fhoffcnt[pos] = htonl((uint32_t)len); 1048 hlen = sizeof(*repl) - NFSREAD_SIZE; 1049 1050 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ, 1051 args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), 1052 repl, sizeof(*repl)); 1053 if (cc == -1) 1054 /* errno was already set by rpc_call */ 1055 return (-1); 1056 if (cc < hlen) { 1057 errno = EBADRPC; 1058 return (-1); 1059 } 1060 if (repl->errno != 0) { 1061 errno = ntohl(repl->errno); 1062 return (-1); 1063 } 1064 rlen = cc - hlen; 1065 x = ntohl(repl->count); 1066 if (rlen < x) { 1067 printf("nfsread: short packet, %d < %ld\n", rlen, x); 1068 errno = EBADRPC; 1069 return (-1); 1070 } 1071 bcopy(repl->data, addr, x); 1072 return (x); 1073} 1074 1075/* 1076 * Open a file. 1077 * return zero or error number 1078 */ 1079int 1080nfs_open(const char *upath, struct open_file *f) 1081{ 1082 struct iodesc *desc; 1083 struct nfs_iodesc *currfd; 1084 char buf[2 * NFS_V3MAXFHSIZE + 3]; 1085 u_char *fh; 1086 char *cp; 1087 int i; 1088#ifndef NFS_NOSYMLINK 1089 struct nfs_iodesc *newfd; 1090 struct nfsv3_fattrs *fa; 1091 char *ncp; 1092 int c; 1093 char namebuf[NFS_MAXPATHLEN + 1]; 1094 char linkbuf[NFS_MAXPATHLEN + 1]; 1095 int nlinks = 0; 1096#endif 1097 int error; 1098 char *path; 1099 1100#ifdef NFS_DEBUG 1101 if (debug) 1102 printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath); 1103#endif 1104 if (!rootpath[0]) { 1105 printf("no rootpath, no nfs\n"); 1106 return (ENXIO); 1107 } 1108 1109 /* 1110 * This is silly - we should look at dv_type but that value is 1111 * arch dependant and we can't use it here. 1112 */ 1113#ifndef __i386__ 1114 if (strcmp(f->f_dev->dv_name, "net") != 0) 1115 return (EINVAL); 1116#else 1117 if (strcmp(f->f_dev->dv_name, "pxe") != 0) 1118 return (EINVAL); 1119#endif 1120 1121 if (!(desc = socktodesc(*(int *)(f->f_devdata)))) 1122 return (EINVAL); 1123 1124 /* Bind to a reserved port. */ 1125 desc->myport = htons(--rpc_port); 1126 desc->destip = rootip; 1127 if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize, 1128 nfs_root_node.fh))) 1129 return (error); 1130 nfs_root_node.fa.fa_type = htonl(NFDIR); 1131 nfs_root_node.fa.fa_mode = htonl(0755); 1132 nfs_root_node.fa.fa_nlink = htonl(2); 1133 nfs_root_node.iodesc = desc; 1134 1135 fh = &nfs_root_node.fh[0]; 1136 buf[0] = 'X'; 1137 cp = &buf[1]; 1138 for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2) 1139 sprintf(cp, "%02x", fh[i]); 1140 sprintf(cp, "X"); 1141 setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); 1142 setenv("boot.nfsroot.path", rootpath, 1); 1143 setenv("boot.nfsroot.nfshandle", buf, 1); 1144 sprintf(buf, "%d", nfs_root_node.fhsize); 1145 setenv("boot.nfsroot.nfshandlelen", buf, 1); 1146 1147 /* Allocate file system specific data structure */ 1148 currfd = malloc(sizeof(*newfd)); 1149 if (currfd == NULL) { 1150 error = ENOMEM; 1151 goto out; 1152 } 1153#ifndef NFS_NOSYMLINK 1154 bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 1155 newfd = 0; 1156 1157 cp = path = strdup(upath); 1158 if (path == NULL) { 1159 error = ENOMEM; 1160 goto out; 1161 } 1162 while (*cp) { 1163 /* 1164 * Remove extra separators 1165 */ 1166 while (*cp == '/') 1167 cp++; 1168 1169 if (*cp == '\0') 1170 break; 1171 /* 1172 * Check that current node is a directory. 1173 */ 1174 if (currfd->fa.fa_type != htonl(NFDIR)) { 1175 error = ENOTDIR; 1176 goto out; 1177 } 1178 1179 /* allocate file system specific data structure */ 1180 newfd = malloc(sizeof(*newfd)); 1181 if (newfd == NULL) { 1182 error = ENOMEM; 1183 goto out; 1184 } 1185 newfd->iodesc = currfd->iodesc; 1186 1187 /* 1188 * Get next component of path name. 1189 */ 1190 { 1191 int len = 0; 1192 1193 ncp = cp; 1194 while ((c = *cp) != '\0' && c != '/') { 1195 if (++len > NFS_MAXNAMLEN) { 1196 error = ENOENT; 1197 goto out; 1198 } 1199 cp++; 1200 } 1201 *cp = '\0'; 1202 } 1203 1204 /* lookup a file handle */ 1205 error = nfs_lookupfh(currfd, ncp, newfd); 1206 *cp = c; 1207 if (error) 1208 goto out; 1209 1210 /* 1211 * Check for symbolic link 1212 */ 1213 if (newfd->fa.fa_type == htonl(NFLNK)) { 1214 int link_len, len; 1215 1216 error = nfs_readlink(newfd, linkbuf); 1217 if (error) 1218 goto out; 1219 1220 link_len = strlen(linkbuf); 1221 len = strlen(cp); 1222 1223 if (link_len + len > MAXPATHLEN 1224 || ++nlinks > MAXSYMLINKS) { 1225 error = ENOENT; 1226 goto out; 1227 } 1228 1229 bcopy(cp, &namebuf[link_len], len + 1); 1230 bcopy(linkbuf, namebuf, link_len); 1231 1232 /* 1233 * If absolute pathname, restart at root. 1234 * If relative pathname, restart at parent directory. 1235 */ 1236 cp = namebuf; 1237 if (*cp == '/') 1238 bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 1239 1240 free(newfd); 1241 newfd = 0; 1242 1243 continue; 1244 } 1245 1246 free(currfd); 1247 currfd = newfd; 1248 newfd = 0; 1249 } 1250 1251 error = 0; 1252 1253out: 1254 free(newfd); 1255 free(path); 1256#else 1257 currfd->iodesc = desc; 1258 1259 error = nfs_lookupfh(&nfs_root_node, upath, currfd); 1260#endif 1261 if (!error) { 1262 currfd->off = 0;
| 813 return 0; 814} 815#else /* !OLD_NFSV2 */ 816/* 817 * Fetch the root file handle (call mount daemon) 818 * Return zero or error number. 819 */ 820int 821nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp) 822{ 823 int len; 824 struct args { 825 uint32_t len; 826 char path[FNAME_SIZE]; 827 } *args; 828 struct repl { 829 uint32_t errno; 830 uint32_t fhsize; 831 u_char fh[NFS_V3MAXFHSIZE]; 832 uint32_t authcnt; 833 uint32_t auth[7]; 834 } *repl; 835 struct { 836 uint32_t h[RPC_HEADER_WORDS]; 837 struct args d; 838 } sdata; 839 struct { 840 uint32_t h[RPC_HEADER_WORDS]; 841 struct repl d; 842 } rdata; 843 size_t cc; 844 845#ifdef NFS_DEBUG 846 if (debug) 847 printf("nfs_getrootfh: %s\n", path); 848#endif 849 850 args = &sdata.d; 851 repl = &rdata.d; 852 853 bzero(args, sizeof(*args)); 854 len = strlen(path); 855 if (len > sizeof(args->path)) 856 len = sizeof(args->path); 857 args->len = htonl(len); 858 bcopy(path, args->path, len); 859 len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t)); 860 861 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT, 862 args, len, repl, sizeof(*repl)); 863 if (cc == -1) 864 /* errno was set by rpc_call */ 865 return (errno); 866 if (cc < 2 * sizeof (uint32_t)) 867 return (EBADRPC); 868 if (repl->errno != 0) 869 return (ntohl(repl->errno)); 870 *fhlenp = ntohl(repl->fhsize); 871 bcopy(repl->fh, fhp, *fhlenp); 872 return (0); 873} 874 875/* 876 * Lookup a file. Store handle and attributes. 877 * Return zero or error number. 878 */ 879int 880nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) 881{ 882 int len, rlen, pos; 883 struct args { 884 uint32_t fhsize; 885 uint32_t fhplusname[1 + 886 (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)]; 887 } *args; 888 struct repl { 889 uint32_t errno; 890 uint32_t fhsize; 891 uint32_t fhplusattr[(NFS_V3MAXFHSIZE + 892 2 * (sizeof(uint32_t) + 893 sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)]; 894 } *repl; 895 struct { 896 uint32_t h[RPC_HEADER_WORDS]; 897 struct args d; 898 } sdata; 899 struct { 900 uint32_t h[RPC_HEADER_WORDS]; 901 struct repl d; 902 } rdata; 903 ssize_t cc; 904 905#ifdef NFS_DEBUG 906 if (debug) 907 printf("lookupfh: called\n"); 908#endif 909 910 args = &sdata.d; 911 repl = &rdata.d; 912 913 bzero(args, sizeof(*args)); 914 args->fhsize = htonl(d->fhsize); 915 bcopy(d->fh, args->fhplusname, d->fhsize); 916 len = strlen(name); 917 if (len > FNAME_SIZE) 918 len = FNAME_SIZE; 919 pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 920 args->fhplusname[pos++] = htonl(len); 921 bcopy(name, &args->fhplusname[pos], len); 922 len = sizeof(uint32_t) + pos * sizeof(uint32_t) + 923 roundup(len, sizeof(uint32_t)); 924 925 rlen = sizeof(*repl); 926 927 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP, 928 args, len, repl, rlen); 929 if (cc == -1) 930 return (errno); /* XXX - from rpc_call */ 931 if (cc < 2 * sizeof(uint32_t)) 932 return (EIO); 933 if (repl->errno != 0) 934 /* saerrno.h now matches NFS error numbers. */ 935 return (ntohl(repl->errno)); 936 newfd->fhsize = ntohl(repl->fhsize); 937 bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize); 938 pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 939 if (repl->fhplusattr[pos++] == 0) 940 return (EIO); 941 bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa)); 942 return (0); 943} 944 945#ifndef NFS_NOSYMLINK 946/* 947 * Get the destination of a symbolic link. 948 */ 949int 950nfs_readlink(struct nfs_iodesc *d, char *buf) 951{ 952 struct args { 953 uint32_t fhsize; 954 u_char fh[NFS_V3MAXFHSIZE]; 955 } *args; 956 struct repl { 957 uint32_t errno; 958 uint32_t ok; 959 struct nfsv3_fattrs fa; 960 uint32_t len; 961 u_char path[NFS_MAXPATHLEN]; 962 } *repl; 963 struct { 964 uint32_t h[RPC_HEADER_WORDS]; 965 struct args d; 966 } sdata; 967 struct { 968 uint32_t h[RPC_HEADER_WORDS]; 969 struct repl d; 970 } rdata; 971 ssize_t cc; 972 973#ifdef NFS_DEBUG 974 if (debug) 975 printf("readlink: called\n"); 976#endif 977 978 args = &sdata.d; 979 repl = &rdata.d; 980 981 bzero(args, sizeof(*args)); 982 args->fhsize = htonl(d->fhsize); 983 bcopy(d->fh, args->fh, d->fhsize); 984 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK, 985 args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), 986 repl, sizeof(*repl)); 987 if (cc == -1) 988 return (errno); 989 990 if (cc < 2 * sizeof(uint32_t)) 991 return (EIO); 992 993 if (repl->errno != 0) 994 return (ntohl(repl->errno)); 995 996 if (repl->ok == 0) 997 return (EIO); 998 999 repl->len = ntohl(repl->len); 1000 if (repl->len > NFS_MAXPATHLEN) 1001 return (ENAMETOOLONG); 1002 1003 bcopy(repl->path, buf, repl->len); 1004 buf[repl->len] = 0; 1005 return (0); 1006} 1007#endif 1008 1009/* 1010 * Read data from a file. 1011 * Return transfer count or -1 (and set errno) 1012 */ 1013ssize_t 1014nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) 1015{ 1016 struct args { 1017 uint32_t fhsize; 1018 uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3]; 1019 } *args; 1020 struct repl { 1021 uint32_t errno; 1022 uint32_t ok; 1023 struct nfsv3_fattrs fa; 1024 uint32_t count; 1025 uint32_t eof; 1026 uint32_t len; 1027 u_char data[NFSREAD_SIZE]; 1028 } *repl; 1029 struct { 1030 uint32_t h[RPC_HEADER_WORDS]; 1031 struct args d; 1032 } sdata; 1033 struct { 1034 uint32_t h[RPC_HEADER_WORDS]; 1035 struct repl d; 1036 } rdata; 1037 size_t cc; 1038 long x; 1039 int hlen, rlen, pos; 1040 1041 args = &sdata.d; 1042 repl = &rdata.d; 1043 1044 bzero(args, sizeof(*args)); 1045 args->fhsize = htonl(d->fhsize); 1046 bcopy(d->fh, args->fhoffcnt, d->fhsize); 1047 pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 1048 args->fhoffcnt[pos++] = 0; 1049 args->fhoffcnt[pos++] = htonl((uint32_t)off); 1050 if (len > NFSREAD_SIZE) 1051 len = NFSREAD_SIZE; 1052 args->fhoffcnt[pos] = htonl((uint32_t)len); 1053 hlen = sizeof(*repl) - NFSREAD_SIZE; 1054 1055 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ, 1056 args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), 1057 repl, sizeof(*repl)); 1058 if (cc == -1) 1059 /* errno was already set by rpc_call */ 1060 return (-1); 1061 if (cc < hlen) { 1062 errno = EBADRPC; 1063 return (-1); 1064 } 1065 if (repl->errno != 0) { 1066 errno = ntohl(repl->errno); 1067 return (-1); 1068 } 1069 rlen = cc - hlen; 1070 x = ntohl(repl->count); 1071 if (rlen < x) { 1072 printf("nfsread: short packet, %d < %ld\n", rlen, x); 1073 errno = EBADRPC; 1074 return (-1); 1075 } 1076 bcopy(repl->data, addr, x); 1077 return (x); 1078} 1079 1080/* 1081 * Open a file. 1082 * return zero or error number 1083 */ 1084int 1085nfs_open(const char *upath, struct open_file *f) 1086{ 1087 struct iodesc *desc; 1088 struct nfs_iodesc *currfd; 1089 char buf[2 * NFS_V3MAXFHSIZE + 3]; 1090 u_char *fh; 1091 char *cp; 1092 int i; 1093#ifndef NFS_NOSYMLINK 1094 struct nfs_iodesc *newfd; 1095 struct nfsv3_fattrs *fa; 1096 char *ncp; 1097 int c; 1098 char namebuf[NFS_MAXPATHLEN + 1]; 1099 char linkbuf[NFS_MAXPATHLEN + 1]; 1100 int nlinks = 0; 1101#endif 1102 int error; 1103 char *path; 1104 1105#ifdef NFS_DEBUG 1106 if (debug) 1107 printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath); 1108#endif 1109 if (!rootpath[0]) { 1110 printf("no rootpath, no nfs\n"); 1111 return (ENXIO); 1112 } 1113 1114 /* 1115 * This is silly - we should look at dv_type but that value is 1116 * arch dependant and we can't use it here. 1117 */ 1118#ifndef __i386__ 1119 if (strcmp(f->f_dev->dv_name, "net") != 0) 1120 return (EINVAL); 1121#else 1122 if (strcmp(f->f_dev->dv_name, "pxe") != 0) 1123 return (EINVAL); 1124#endif 1125 1126 if (!(desc = socktodesc(*(int *)(f->f_devdata)))) 1127 return (EINVAL); 1128 1129 /* Bind to a reserved port. */ 1130 desc->myport = htons(--rpc_port); 1131 desc->destip = rootip; 1132 if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize, 1133 nfs_root_node.fh))) 1134 return (error); 1135 nfs_root_node.fa.fa_type = htonl(NFDIR); 1136 nfs_root_node.fa.fa_mode = htonl(0755); 1137 nfs_root_node.fa.fa_nlink = htonl(2); 1138 nfs_root_node.iodesc = desc; 1139 1140 fh = &nfs_root_node.fh[0]; 1141 buf[0] = 'X'; 1142 cp = &buf[1]; 1143 for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2) 1144 sprintf(cp, "%02x", fh[i]); 1145 sprintf(cp, "X"); 1146 setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); 1147 setenv("boot.nfsroot.path", rootpath, 1); 1148 setenv("boot.nfsroot.nfshandle", buf, 1); 1149 sprintf(buf, "%d", nfs_root_node.fhsize); 1150 setenv("boot.nfsroot.nfshandlelen", buf, 1); 1151 1152 /* Allocate file system specific data structure */ 1153 currfd = malloc(sizeof(*newfd)); 1154 if (currfd == NULL) { 1155 error = ENOMEM; 1156 goto out; 1157 } 1158#ifndef NFS_NOSYMLINK 1159 bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 1160 newfd = 0; 1161 1162 cp = path = strdup(upath); 1163 if (path == NULL) { 1164 error = ENOMEM; 1165 goto out; 1166 } 1167 while (*cp) { 1168 /* 1169 * Remove extra separators 1170 */ 1171 while (*cp == '/') 1172 cp++; 1173 1174 if (*cp == '\0') 1175 break; 1176 /* 1177 * Check that current node is a directory. 1178 */ 1179 if (currfd->fa.fa_type != htonl(NFDIR)) { 1180 error = ENOTDIR; 1181 goto out; 1182 } 1183 1184 /* allocate file system specific data structure */ 1185 newfd = malloc(sizeof(*newfd)); 1186 if (newfd == NULL) { 1187 error = ENOMEM; 1188 goto out; 1189 } 1190 newfd->iodesc = currfd->iodesc; 1191 1192 /* 1193 * Get next component of path name. 1194 */ 1195 { 1196 int len = 0; 1197 1198 ncp = cp; 1199 while ((c = *cp) != '\0' && c != '/') { 1200 if (++len > NFS_MAXNAMLEN) { 1201 error = ENOENT; 1202 goto out; 1203 } 1204 cp++; 1205 } 1206 *cp = '\0'; 1207 } 1208 1209 /* lookup a file handle */ 1210 error = nfs_lookupfh(currfd, ncp, newfd); 1211 *cp = c; 1212 if (error) 1213 goto out; 1214 1215 /* 1216 * Check for symbolic link 1217 */ 1218 if (newfd->fa.fa_type == htonl(NFLNK)) { 1219 int link_len, len; 1220 1221 error = nfs_readlink(newfd, linkbuf); 1222 if (error) 1223 goto out; 1224 1225 link_len = strlen(linkbuf); 1226 len = strlen(cp); 1227 1228 if (link_len + len > MAXPATHLEN 1229 || ++nlinks > MAXSYMLINKS) { 1230 error = ENOENT; 1231 goto out; 1232 } 1233 1234 bcopy(cp, &namebuf[link_len], len + 1); 1235 bcopy(linkbuf, namebuf, link_len); 1236 1237 /* 1238 * If absolute pathname, restart at root. 1239 * If relative pathname, restart at parent directory. 1240 */ 1241 cp = namebuf; 1242 if (*cp == '/') 1243 bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 1244 1245 free(newfd); 1246 newfd = 0; 1247 1248 continue; 1249 } 1250 1251 free(currfd); 1252 currfd = newfd; 1253 newfd = 0; 1254 } 1255 1256 error = 0; 1257 1258out: 1259 free(newfd); 1260 free(path); 1261#else 1262 currfd->iodesc = desc; 1263 1264 error = nfs_lookupfh(&nfs_root_node, upath, currfd); 1265#endif 1266 if (!error) { 1267 currfd->off = 0;
|
| 1268 currfd->cookie = 0;
|
1263 f->f_fsdata = (void *)currfd; 1264 return (0); 1265 } 1266 1267#ifdef NFS_DEBUG 1268 if (debug) 1269 printf("nfs_open: %s lookupfh failed: %s\n", 1270 path, strerror(error)); 1271#endif 1272 free(currfd); 1273 1274 return (error); 1275} 1276 1277int 1278nfs_close(struct open_file *f) 1279{ 1280 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1281 1282#ifdef NFS_DEBUG 1283 if (debug) 1284 printf("nfs_close: fp=0x%lx\n", (u_long)fp); 1285#endif 1286 1287 if (fp) 1288 free(fp); 1289 f->f_fsdata = (void *)0; 1290 1291 return (0); 1292} 1293 1294/* 1295 * read a portion of a file 1296 */ 1297int 1298nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 1299{ 1300 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1301 ssize_t cc; 1302 char *addr = buf; 1303 1304#ifdef NFS_DEBUG 1305 if (debug) 1306 printf("nfs_read: size=%lu off=%d\n", (u_long)size, 1307 (int)fp->off); 1308#endif 1309 while ((int)size > 0) { 1310 twiddle(); 1311 cc = nfs_readdata(fp, fp->off, (void *)addr, size); 1312 /* XXX maybe should retry on certain errors */ 1313 if (cc == -1) { 1314#ifdef NFS_DEBUG 1315 if (debug) 1316 printf("nfs_read: read: %s", strerror(errno)); 1317#endif 1318 return (errno); /* XXX - from nfs_readdata */ 1319 } 1320 if (cc == 0) { 1321#ifdef NFS_DEBUG 1322 if (debug) 1323 printf("nfs_read: hit EOF unexpectantly"); 1324#endif 1325 goto ret; 1326 } 1327 fp->off += cc; 1328 addr += cc; 1329 size -= cc; 1330 } 1331ret: 1332 if (resid) 1333 *resid = size; 1334 1335 return (0); 1336} 1337 1338/* 1339 * Not implemented. 1340 */ 1341int 1342nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) 1343{ 1344 return (EROFS); 1345} 1346 1347off_t 1348nfs_seek(struct open_file *f, off_t offset, int where) 1349{ 1350 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 1351 uint32_t size = ntohl(d->fa.fa_size.val[1]); 1352 1353 switch (where) { 1354 case SEEK_SET: 1355 d->off = offset; 1356 break; 1357 case SEEK_CUR: 1358 d->off += offset; 1359 break; 1360 case SEEK_END: 1361 d->off = size - offset; 1362 break; 1363 default: 1364 errno = EINVAL; 1365 return (-1); 1366 } 1367 1368 return (d->off); 1369} 1370 1371/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */ 1372int nfs_stat_types[9] = { 1373 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 }; 1374 1375int 1376nfs_stat(struct open_file *f, struct stat *sb) 1377{ 1378 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1379 uint32_t ftype, mode; 1380 1381 ftype = ntohl(fp->fa.fa_type); 1382 mode = ntohl(fp->fa.fa_mode); 1383 mode |= nfs_stat_types[ftype & 7]; 1384 1385 sb->st_mode = mode; 1386 sb->st_nlink = ntohl(fp->fa.fa_nlink); 1387 sb->st_uid = ntohl(fp->fa.fa_uid); 1388 sb->st_gid = ntohl(fp->fa.fa_gid); 1389 sb->st_size = ntohl(fp->fa.fa_size.val[1]); 1390 1391 return (0); 1392} 1393 1394static int 1395nfs_readdir(struct open_file *f, struct dirent *d) 1396{ 1397 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1398 struct nfsv3_readdir_repl *repl; 1399 struct nfsv3_readdir_entry *rent; 1400 static char *buf;
| 1269 f->f_fsdata = (void *)currfd; 1270 return (0); 1271 } 1272 1273#ifdef NFS_DEBUG 1274 if (debug) 1275 printf("nfs_open: %s lookupfh failed: %s\n", 1276 path, strerror(error)); 1277#endif 1278 free(currfd); 1279 1280 return (error); 1281} 1282 1283int 1284nfs_close(struct open_file *f) 1285{ 1286 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1287 1288#ifdef NFS_DEBUG 1289 if (debug) 1290 printf("nfs_close: fp=0x%lx\n", (u_long)fp); 1291#endif 1292 1293 if (fp) 1294 free(fp); 1295 f->f_fsdata = (void *)0; 1296 1297 return (0); 1298} 1299 1300/* 1301 * read a portion of a file 1302 */ 1303int 1304nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 1305{ 1306 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1307 ssize_t cc; 1308 char *addr = buf; 1309 1310#ifdef NFS_DEBUG 1311 if (debug) 1312 printf("nfs_read: size=%lu off=%d\n", (u_long)size, 1313 (int)fp->off); 1314#endif 1315 while ((int)size > 0) { 1316 twiddle(); 1317 cc = nfs_readdata(fp, fp->off, (void *)addr, size); 1318 /* XXX maybe should retry on certain errors */ 1319 if (cc == -1) { 1320#ifdef NFS_DEBUG 1321 if (debug) 1322 printf("nfs_read: read: %s", strerror(errno)); 1323#endif 1324 return (errno); /* XXX - from nfs_readdata */ 1325 } 1326 if (cc == 0) { 1327#ifdef NFS_DEBUG 1328 if (debug) 1329 printf("nfs_read: hit EOF unexpectantly"); 1330#endif 1331 goto ret; 1332 } 1333 fp->off += cc; 1334 addr += cc; 1335 size -= cc; 1336 } 1337ret: 1338 if (resid) 1339 *resid = size; 1340 1341 return (0); 1342} 1343 1344/* 1345 * Not implemented. 1346 */ 1347int 1348nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) 1349{ 1350 return (EROFS); 1351} 1352 1353off_t 1354nfs_seek(struct open_file *f, off_t offset, int where) 1355{ 1356 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 1357 uint32_t size = ntohl(d->fa.fa_size.val[1]); 1358 1359 switch (where) { 1360 case SEEK_SET: 1361 d->off = offset; 1362 break; 1363 case SEEK_CUR: 1364 d->off += offset; 1365 break; 1366 case SEEK_END: 1367 d->off = size - offset; 1368 break; 1369 default: 1370 errno = EINVAL; 1371 return (-1); 1372 } 1373 1374 return (d->off); 1375} 1376 1377/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */ 1378int nfs_stat_types[9] = { 1379 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 }; 1380 1381int 1382nfs_stat(struct open_file *f, struct stat *sb) 1383{ 1384 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1385 uint32_t ftype, mode; 1386 1387 ftype = ntohl(fp->fa.fa_type); 1388 mode = ntohl(fp->fa.fa_mode); 1389 mode |= nfs_stat_types[ftype & 7]; 1390 1391 sb->st_mode = mode; 1392 sb->st_nlink = ntohl(fp->fa.fa_nlink); 1393 sb->st_uid = ntohl(fp->fa.fa_uid); 1394 sb->st_gid = ntohl(fp->fa.fa_gid); 1395 sb->st_size = ntohl(fp->fa.fa_size.val[1]); 1396 1397 return (0); 1398} 1399 1400static int 1401nfs_readdir(struct open_file *f, struct dirent *d) 1402{ 1403 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1404 struct nfsv3_readdir_repl *repl; 1405 struct nfsv3_readdir_entry *rent; 1406 static char *buf;
|
1401 static uint32_t cookie0 = 0; 1402 static uint32_t cookie1 = 0;
| 1407 static struct nfs_iodesc *pfp = NULL; 1408 static uint64_t cookie = 0;
|
1403 size_t cc;
| 1409 size_t cc;
|
1404 static uint32_t cookieverf0 = 0; 1405 static uint32_t cookieverf1 = 0;
| |
1406 int pos; 1407 1408 struct args { 1409 uint32_t fhsize; 1410 uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE]; 1411 } *args; 1412 struct { 1413 uint32_t h[RPC_HEADER_WORDS]; 1414 struct args d; 1415 } sdata; 1416 static struct { 1417 uint32_t h[RPC_HEADER_WORDS]; 1418 u_char d[NFS_READDIRSIZE]; 1419 } rdata; 1420
| 1410 int pos; 1411 1412 struct args { 1413 uint32_t fhsize; 1414 uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE]; 1415 } *args; 1416 struct { 1417 uint32_t h[RPC_HEADER_WORDS]; 1418 struct args d; 1419 } sdata; 1420 static struct { 1421 uint32_t h[RPC_HEADER_WORDS]; 1422 u_char d[NFS_READDIRSIZE]; 1423 } rdata; 1424
|
1421 if (cookie0 == 0 && cookie1 == 0) {
| 1425 if (fp != pfp || fp->off != cookie) { 1426 pfp = NULL;
|
1422 refill: 1423 args = &sdata.d; 1424 bzero(args, sizeof(*args)); 1425 1426 args->fhsize = htonl(fp->fhsize); 1427 bcopy(fp->fh, args->fhpluscookie, fp->fhsize); 1428 pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
| 1427 refill: 1428 args = &sdata.d; 1429 bzero(args, sizeof(*args)); 1430 1431 args->fhsize = htonl(fp->fhsize); 1432 bcopy(fp->fh, args->fhpluscookie, fp->fhsize); 1433 pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
|
1429 args->fhpluscookie[pos++] = cookie0; 1430 args->fhpluscookie[pos++] = cookie1; 1431 args->fhpluscookie[pos++] = cookieverf0; 1432 args->fhpluscookie[pos++] = cookieverf1;
| 1434 args->fhpluscookie[pos++] = htonl(fp->off >> 32); 1435 args->fhpluscookie[pos++] = htonl(fp->off); 1436 args->fhpluscookie[pos++] = htonl(fp->cookie >> 32); 1437 args->fhpluscookie[pos++] = htonl(fp->cookie);
|
1433 args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE); 1434 1435 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR, 1436 args, 6 * sizeof(uint32_t) + 1437 roundup(fp->fhsize, sizeof(uint32_t)), 1438 rdata.d, sizeof(rdata.d)); 1439 buf = rdata.d; 1440 repl = (struct nfsv3_readdir_repl *)buf; 1441 if (repl->errno != 0) 1442 return (ntohl(repl->errno));
| 1438 args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE); 1439 1440 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR, 1441 args, 6 * sizeof(uint32_t) + 1442 roundup(fp->fhsize, sizeof(uint32_t)), 1443 rdata.d, sizeof(rdata.d)); 1444 buf = rdata.d; 1445 repl = (struct nfsv3_readdir_repl *)buf; 1446 if (repl->errno != 0) 1447 return (ntohl(repl->errno));
|
1443 cookieverf0 = repl->cookiev0; 1444 cookieverf1 = repl->cookiev1;
| 1448 pfp = fp; 1449 cookie = fp->off; 1450 fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) | 1451 ntohl(repl->cookiev1);
|
1445 buf += sizeof (struct nfsv3_readdir_repl); 1446 } 1447 rent = (struct nfsv3_readdir_entry *)buf; 1448 1449 if (rent->follows == 0) { 1450 /* fid0 is actually eof */ 1451 if (rent->fid0 != 0) {
| 1452 buf += sizeof (struct nfsv3_readdir_repl); 1453 } 1454 rent = (struct nfsv3_readdir_entry *)buf; 1455 1456 if (rent->follows == 0) { 1457 /* fid0 is actually eof */ 1458 if (rent->fid0 != 0) {
|
1452 cookie0 = 0; 1453 cookie1 = 0; 1454 cookieverf0 = 0; 1455 cookieverf1 = 0;
| 1459 cookie = 0;
|
1456 return (ENOENT); 1457 } 1458 goto refill; 1459 } 1460 1461 d->d_namlen = ntohl(rent->len); 1462 bcopy(rent->nameplus, d->d_name, d->d_namlen); 1463 d->d_name[d->d_namlen] = '\0'; 1464 1465 pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t);
| 1460 return (ENOENT); 1461 } 1462 goto refill; 1463 } 1464 1465 d->d_namlen = ntohl(rent->len); 1466 bcopy(rent->nameplus, d->d_name, d->d_namlen); 1467 d->d_name[d->d_namlen] = '\0'; 1468 1469 pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t);
|
1466 cookie0 = rent->nameplus[pos++]; 1467 cookie1 = rent->nameplus[pos++];
| 1470 fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos]) << 32) | 1471 ntohl(rent->nameplus[pos + 1]); 1472 pos += 2;
|
1468 buf = (u_char *)&rent->nameplus[pos]; 1469 return (0); 1470} 1471#endif /* OLD_NFSV2 */
| 1473 buf = (u_char *)&rent->nameplus[pos]; 1474 return (0); 1475} 1476#endif /* OLD_NFSV2 */
|