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