1 /* $NetBSD: nfs.c,v 1.12 1995/09/23 03:36:08 gwr 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/param.h> 32 #include <sys/time.h> 33 #include <sys/socket.h> 34 #include <sys/stat.h> 35 #include <string.h> 36 37 #include <netinet/in.h> 38 #include <netinet/in_systm.h> 39 40 #include <nfs/rpcv2.h> 41 #include <nfs/nfsv2.h> 42 #include <nfs/xdr_subs.h> 43 44 #include "stand.h" 45 #include "net.h" 46 #include "netif.h" 47 #include "nfs.h" 48 #include "rpc.h" 49 50 /* Define our own NFS attributes without NQNFS stuff. */ 51 struct nfsv2_fattrs { 52 n_long fa_type; 53 n_long fa_mode; 54 n_long fa_nlink; 55 n_long fa_uid; 56 n_long fa_gid; 57 n_long fa_size; 58 n_long fa_blocksize; 59 n_long fa_rdev; 60 n_long fa_blocks; 61 n_long fa_fsid; 62 n_long fa_fileid; 63 struct nfsv2_time fa_atime; 64 struct nfsv2_time fa_mtime; 65 struct nfsv2_time fa_ctime; 66 }; 67 68 69 struct nfs_read_args { 70 u_char fh[NFS_FHSIZE]; 71 n_long off; 72 n_long len; 73 n_long xxx; /* XXX what's this for? */ 74 }; 75 76 /* Data part of nfs rpc reply (also the largest thing we receive) */ 77 #define NFSREAD_SIZE 1024 78 struct nfs_read_repl { 79 n_long errno; 80 struct nfsv2_fattrs fa; 81 n_long count; 82 u_char data[NFSREAD_SIZE]; 83 }; 84 85 struct nfs_iodesc { 86 struct iodesc *iodesc; 87 off_t off; 88 u_char fh[NFS_FHSIZE]; 89 struct nfsv2_fattrs fa; /* all in network order */ 90 }; 91 92 struct nfs_iodesc nfs_root_node; 93 94 95 /* 96 * Fetch the root file handle (call mount daemon) 97 * On error, return non-zero and set errno. 98 */ 99 int 100 nfs_getrootfh(d, path, fhp) 101 register struct iodesc *d; 102 char *path; 103 u_char *fhp; 104 { 105 register int len; 106 struct args { 107 n_long len; 108 char path[FNAME_SIZE]; 109 } *args; 110 struct repl { 111 n_long errno; 112 u_char fh[NFS_FHSIZE]; 113 } *repl; 114 struct { 115 n_long h[RPC_HEADER_WORDS]; 116 struct args d; 117 } sdata; 118 struct { 119 n_long h[RPC_HEADER_WORDS]; 120 struct repl d; 121 } rdata; 122 size_t cc; 123 124 #ifdef NFS_DEBUG 125 if (debug) 126 printf("nfs_getrootfh: %s\n", path); 127 #endif 128 129 args = &sdata.d; 130 repl = &rdata.d; 131 132 bzero(args, sizeof(*args)); 133 len = strlen(path); 134 if (len > sizeof(args->path)) 135 len = sizeof(args->path); 136 args->len = htonl(len); 137 bcopy(path, args->path, len); 138 len = 4 + roundup(len, 4); 139 140 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT, 141 args, len, repl, sizeof(*repl)); 142 if (cc == -1) { 143 /* errno was set by rpc_call */ 144 return (-1); 145 } 146 if (cc < 4) { 147 errno = EBADRPC; 148 return (-1); 149 } 150 if (repl->errno) { 151 errno = ntohl(repl->errno); 152 return (-1); 153 } 154 bcopy(repl->fh, fhp, sizeof(repl->fh)); 155 return (0); 156 } 157 158 /* 159 * Lookup a file. Store handle and attributes. 160 * Return zero or error number. 161 */ 162 int 163 nfs_lookupfh(d, name, newfd) 164 struct nfs_iodesc *d; 165 char *name; 166 struct nfs_iodesc *newfd; 167 { 168 register int len, rlen; 169 struct args { 170 u_char fh[NFS_FHSIZE]; 171 n_long len; 172 char name[FNAME_SIZE]; 173 } *args; 174 struct repl { 175 n_long errno; 176 u_char fh[NFS_FHSIZE]; 177 struct nfsv2_fattrs fa; 178 } *repl; 179 struct { 180 n_long h[RPC_HEADER_WORDS]; 181 struct args d; 182 } sdata; 183 struct { 184 n_long h[RPC_HEADER_WORDS]; 185 struct repl d; 186 } rdata; 187 ssize_t cc; 188 189 #ifdef NFS_DEBUG 190 if (debug) 191 printf("lookupfh: called\n"); 192 #endif 193 194 args = &sdata.d; 195 repl = &rdata.d; 196 197 bzero(args, sizeof(*args)); 198 bcopy(d->fh, args->fh, sizeof(args->fh)); 199 len = strlen(name); 200 if (len > sizeof(args->name)) 201 len = sizeof(args->name); 202 bcopy(name, args->name, len); 203 args->len = htonl(len); 204 len = 4 + roundup(len, 4); 205 len += NFS_FHSIZE; 206 207 rlen = sizeof(*repl); 208 209 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP, 210 args, len, repl, rlen); 211 if (cc == -1) 212 return (errno); /* XXX - from rpc_call */ 213 if (cc < 4) 214 return (EIO); 215 if (repl->errno) { 216 /* saerrno.h now matches NFS error numbers. */ 217 return (ntohl(repl->errno)); 218 } 219 bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh)); 220 bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa)); 221 return (0); 222 } 223 224 /* 225 * Read data from a file. 226 * Return transfer count or -1 (and set errno) 227 */ 228 ssize_t 229 nfs_readdata(d, off, addr, len) 230 struct nfs_iodesc *d; 231 off_t off; 232 void *addr; 233 size_t len; 234 { 235 struct nfs_read_args *args; 236 struct nfs_read_repl *repl; 237 struct { 238 n_long h[RPC_HEADER_WORDS]; 239 struct nfs_read_args d; 240 } sdata; 241 struct { 242 n_long h[RPC_HEADER_WORDS]; 243 struct nfs_read_repl d; 244 } rdata; 245 size_t cc; 246 long x; 247 int hlen, rlen; 248 249 args = &sdata.d; 250 repl = &rdata.d; 251 252 bcopy(d->fh, args->fh, NFS_FHSIZE); 253 args->off = txdr_unsigned(off); 254 if (len > NFSREAD_SIZE) 255 len = NFSREAD_SIZE; 256 args->len = txdr_unsigned(len); 257 args->xxx = txdr_unsigned(0); 258 hlen = sizeof(*repl) - NFSREAD_SIZE; 259 260 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ, 261 args, sizeof(*args), 262 repl, sizeof(*repl)); 263 if (cc == -1) { 264 /* errno was already set by rpc_call */ 265 return (-1); 266 } 267 if (cc < hlen) { 268 errno = EBADRPC; 269 return (-1); 270 } 271 if (repl->errno) { 272 errno = ntohl(repl->errno); 273 return (-1); 274 } 275 rlen = cc - hlen; 276 x = ntohl(repl->count); 277 if (rlen < x) { 278 printf("nfsread: short packet, %d < %d\n", rlen, x); 279 errno = EBADRPC; 280 return(-1); 281 } 282 bcopy(repl->data, addr, x); 283 return (x); 284 } 285 286 /* 287 * nfs_mount - mount this nfs filesystem to a host 288 * On error, return non-zero and set errno. 289 */ 290 int 291 nfs_mount(sock, ip, path) 292 int sock; 293 struct in_addr ip; 294 char *path; 295 { 296 struct iodesc *desc; 297 struct nfsv2_fattrs *fa; 298 299 if (!(desc = socktodesc(sock))) { 300 errno = EINVAL; 301 return(-1); 302 } 303 304 /* Bind to a reserved port. */ 305 desc->myport = htons(--rpc_port); 306 desc->destip = ip; 307 if (nfs_getrootfh(desc, path, nfs_root_node.fh)) 308 return (-1); 309 nfs_root_node.iodesc = desc; 310 /* Fake up attributes for the root dir. */ 311 fa = &nfs_root_node.fa; 312 fa->fa_type = htonl(NFDIR); 313 fa->fa_mode = htonl(0755); 314 fa->fa_nlink = htonl(2); 315 316 #ifdef NFS_DEBUG 317 if (debug) 318 printf("nfs_mount: got fh for %s\n", path); 319 #endif 320 321 return(0); 322 } 323 324 /* 325 * Open a file. 326 * return zero or error number 327 */ 328 int 329 nfs_open(path, f) 330 char *path; 331 struct open_file *f; 332 { 333 struct nfs_iodesc *newfd; 334 int error = 0; 335 336 #ifdef NFS_DEBUG 337 if (debug) 338 printf("nfs_open: %s\n", path); 339 #endif 340 if (nfs_root_node.iodesc == NULL) { 341 printf("nfs_open: must mount first.\n"); 342 return (ENXIO); 343 } 344 345 /* allocate file system specific data structure */ 346 newfd = alloc(sizeof(*newfd)); 347 newfd->iodesc = nfs_root_node.iodesc; 348 newfd->off = 0; 349 350 /* lookup a file handle */ 351 error = nfs_lookupfh(&nfs_root_node, path, newfd); 352 if (!error) { 353 f->f_fsdata = (void *)newfd; 354 return (0); 355 } 356 357 #ifdef NFS_DEBUG 358 if (debug) 359 printf("nfs_open: %s lookupfh failed: %s\n", 360 path, strerror(error)); 361 #endif 362 free(newfd, sizeof(*newfd)); 363 return (error); 364 } 365 366 int 367 nfs_close(f) 368 struct open_file *f; 369 { 370 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 371 372 #ifdef NFS_DEBUG 373 if (debug) 374 printf("nfs_close: fp=0x%x\n", fp); 375 #endif 376 377 if (fp) 378 free(fp, sizeof(struct nfs_iodesc)); 379 f->f_fsdata = (void *)0; 380 381 return (0); 382 } 383 384 /* 385 * read a portion of a file 386 */ 387 int 388 nfs_read(f, buf, size, resid) 389 struct open_file *f; 390 void *buf; 391 size_t size; 392 size_t *resid; /* out */ 393 { 394 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 395 register ssize_t cc; 396 register char *addr = buf; 397 398 #ifdef NFS_DEBUG 399 if (debug) 400 printf("nfs_read: size=%d off=%d\n", size, (int)fp->off); 401 #endif 402 while ((int)size > 0) { 403 twiddle(); 404 cc = nfs_readdata(fp, fp->off, (void *)addr, size); 405 /* XXX maybe should retry on certain errors */ 406 if (cc == -1) { 407 #ifdef NFS_DEBUG 408 if (debug) 409 printf("nfs_read: read: %s", strerror(errno)); 410 #endif 411 return (errno); /* XXX - from nfs_readdata */ 412 } 413 if (cc == 0) { 414 if (debug) 415 printf("nfs_read: hit EOF unexpectantly"); 416 goto ret; 417 } 418 fp->off += cc; 419 addr += cc; 420 size -= cc; 421 } 422 ret: 423 if (resid) 424 *resid = size; 425 426 return (0); 427 } 428 429 /* 430 * Not implemented. 431 */ 432 int 433 nfs_write(f, buf, size, resid) 434 struct open_file *f; 435 void *buf; 436 size_t size; 437 size_t *resid; /* out */ 438 { 439 return (EROFS); 440 } 441 442 off_t 443 nfs_seek(f, offset, where) 444 struct open_file *f; 445 off_t offset; 446 int where; 447 { 448 register struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 449 n_long size = ntohl(d->fa.fa_size); 450 451 switch (where) { 452 case SEEK_SET: 453 d->off = offset; 454 break; 455 case SEEK_CUR: 456 d->off += offset; 457 break; 458 case SEEK_END: 459 d->off = size - offset; 460 break; 461 default: 462 return (-1); 463 } 464 465 return (d->off); 466 } 467 468 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */ 469 int nfs_stat_types[8] = { 470 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 }; 471 472 int 473 nfs_stat(f, sb) 474 struct open_file *f; 475 struct stat *sb; 476 { 477 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 478 register n_long ftype, mode; 479 480 ftype = ntohl(fp->fa.fa_type); 481 mode = ntohl(fp->fa.fa_mode); 482 mode |= nfs_stat_types[ftype & 7]; 483 484 sb->st_mode = mode; 485 sb->st_nlink = ntohl(fp->fa.fa_nlink); 486 sb->st_uid = ntohl(fp->fa.fa_uid); 487 sb->st_gid = ntohl(fp->fa.fa_gid); 488 sb->st_size = ntohl(fp->fa.fa_size); 489 490 return (0); 491 } 492