root/lib/libsa/nfs.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nfs_getrootfh
  2. nfs_lookupfh
  3. nfs_readlink
  4. nfs_readdata
  5. nfs_mount
  6. nfs_open
  7. nfs_close
  8. nfs_read
  9. nfs_write
  10. nfs_seek
  11. nfs_stat
  12. nfs_readdir

    1 /*      $OpenBSD: nfs.c,v 1.10 2003/08/11 06:23:09 deraadt Exp $        */
    2 /*      $NetBSD: nfs.c,v 1.19 1996/10/13 02:29:04 christos Exp $        */
    3 
    4 /*-
    5  *  Copyright (c) 1993 John Brezak
    6  *  All rights reserved.
    7  *
    8  *  Redistribution and use in source and binary forms, with or without
    9  *  modification, are permitted provided that the following conditions
   10  *  are met:
   11  *  1. Redistributions of source code must retain the above copyright
   12  *     notice, this list of conditions and the following disclaimer.
   13  *  2. Redistributions in binary form must reproduce the above copyright
   14  *     notice, this list of conditions and the following disclaimer in the
   15  *     documentation and/or other materials provided with the distribution.
   16  *  3. The name of the author may not be used to endorse or promote products
   17  *     derived from this software without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
   20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   22  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
   23  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   28  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 #include <sys/param.h>
   33 #include <sys/time.h>
   34 #include <sys/socket.h>
   35 #include <sys/stat.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 "saerrno.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_readlnk_repl {
   86         n_long  errno;
   87         n_long  len;
   88         char    path[NFS_MAXPATHLEN];
   89 };
   90 
   91 struct nfs_iodesc {
   92         struct  iodesc  *iodesc;
   93         off_t   off;
   94         u_char  fh[NFS_FHSIZE];
   95         struct nfsv2_fattrs fa; /* all in network order */
   96 };
   97 
   98 struct nfs_iodesc nfs_root_node;
   99 
  100 
  101 /*
  102  * Fetch the root file handle (call mount daemon)
  103  * On error, return non-zero and set errno.
  104  */
  105 static int
  106 nfs_getrootfh(struct iodesc *d, char *path, u_char *fhp)
  107 {
  108         int len;
  109         struct args {
  110                 n_long  len;
  111                 char    path[FNAME_SIZE];
  112         } *args;
  113         struct repl {
  114                 n_long  errno;
  115                 u_char  fh[NFS_FHSIZE];
  116         } *repl;
  117         struct {
  118                 n_long  h[RPC_HEADER_WORDS];
  119                 struct args d;
  120         } sdata;
  121         struct {
  122                 n_long  h[RPC_HEADER_WORDS];
  123                 struct repl d;
  124         } rdata;
  125         size_t cc;
  126 
  127 #ifdef NFS_DEBUG
  128         if (debug)
  129                 printf("nfs_getrootfh: %s\n", path);
  130 #endif
  131 
  132         args = &sdata.d;
  133         repl = &rdata.d;
  134 
  135         bzero(args, sizeof(*args));
  136         len = strlen(path);
  137         if (len > sizeof(args->path))
  138                 len = sizeof(args->path);
  139         args->len = htonl(len);
  140         bcopy(path, args->path, len);
  141         len = 4 + roundup(len, 4);
  142 
  143         cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
  144             args, len, repl, sizeof(*repl));
  145         if (cc == -1) {
  146                 /* errno was set by rpc_call */
  147                 return (-1);
  148         }
  149         if (cc < 4) {
  150                 errno = EBADRPC;
  151                 return (-1);
  152         }
  153         if (repl->errno) {
  154                 errno = ntohl(repl->errno);
  155                 return (-1);
  156         }
  157         bcopy(repl->fh, fhp, sizeof(repl->fh));
  158         return (0);
  159 }
  160 
  161 /*
  162  * Lookup a file.  Store handle and attributes.
  163  * Return zero or error number.
  164  */
  165 static int
  166 nfs_lookupfh(struct nfs_iodesc *d, char *name, struct nfs_iodesc *newfd)
  167 {
  168         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  * Get the destination of a symbolic link.
  226  */
  227 static int
  228 nfs_readlink(struct nfs_iodesc *d, char *buf)
  229 {
  230         struct {
  231                 n_long  h[RPC_HEADER_WORDS];
  232                 u_char fh[NFS_FHSIZE];
  233         } sdata;
  234         struct {
  235                 n_long  h[RPC_HEADER_WORDS];
  236                 struct nfs_readlnk_repl d;
  237         } rdata;
  238         ssize_t cc;
  239 
  240 #ifdef NFS_DEBUG
  241         if (debug)
  242                 printf("readlink: called\n");
  243 #endif
  244 
  245         bcopy(d->fh, sdata.fh, NFS_FHSIZE);
  246         cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK,
  247             sdata.fh, NFS_FHSIZE,
  248             &rdata.d, sizeof(rdata.d));
  249         if (cc == -1)
  250                 return (errno);
  251 
  252         if (cc < 4)
  253                 return (EIO);
  254 
  255         if (rdata.d.errno)
  256                 return (ntohl(rdata.d.errno));
  257 
  258         rdata.d.len = ntohl(rdata.d.len);
  259         if (rdata.d.len > NFS_MAXPATHLEN)
  260                 return (ENAMETOOLONG);
  261 
  262         bcopy(rdata.d.path, buf, rdata.d.len);
  263         buf[rdata.d.len] = 0;
  264         return (0);
  265 }
  266 
  267 /*
  268  * Read data from a file.
  269  * Return transfer count or -1 (and set errno)
  270  */
  271 static ssize_t
  272 nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
  273 {
  274         struct nfs_read_args *args;
  275         struct nfs_read_repl *repl;
  276         struct {
  277                 n_long  h[RPC_HEADER_WORDS];
  278                 struct nfs_read_args d;
  279         } sdata;
  280         struct {
  281                 n_long  h[RPC_HEADER_WORDS];
  282                 struct nfs_read_repl d;
  283         } rdata;
  284         size_t cc;
  285         long x;
  286         int hlen, rlen;
  287 
  288         args = &sdata.d;
  289         repl = &rdata.d;
  290 
  291         bcopy(d->fh, args->fh, NFS_FHSIZE);
  292         args->off = htonl((n_long)off);
  293         if (len > NFSREAD_SIZE)
  294                 len = NFSREAD_SIZE;
  295         args->len = htonl((n_long)len);
  296         args->xxx = htonl((n_long)0);
  297         hlen = sizeof(*repl) - NFSREAD_SIZE;
  298 
  299         cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ,
  300             args, sizeof(*args),
  301             repl, sizeof(*repl));
  302         if (cc == -1) {
  303                 /* errno was already set by rpc_call */
  304                 return (-1);
  305         }
  306         if (cc < hlen) {
  307                 errno = EBADRPC;
  308                 return (-1);
  309         }
  310         if (repl->errno) {
  311                 errno = ntohl(repl->errno);
  312                 return (-1);
  313         }
  314         rlen = cc - hlen;
  315         x = ntohl(repl->count);
  316         if (rlen < x) {
  317                 printf("nfsread: short packet, %d < %ld\n", rlen, x);
  318                 errno = EBADRPC;
  319                 return(-1);
  320         }
  321         bcopy(repl->data, addr, x);
  322         return (x);
  323 }
  324 
  325 /*
  326  * nfs_mount - mount this nfs filesystem to a host
  327  * On error, return non-zero and set errno.
  328  */
  329 int
  330 nfs_mount(int sock, struct in_addr ip, char *path)
  331 {
  332         struct iodesc *desc;
  333         struct nfsv2_fattrs *fa;
  334 
  335         if (!(desc = socktodesc(sock))) {
  336                 errno = EINVAL;
  337                 return(-1);
  338         }
  339 
  340         /* Bind to a reserved port. */
  341         desc->myport = htons(--rpc_port);
  342         desc->destip = ip;
  343         if (nfs_getrootfh(desc, path, nfs_root_node.fh))
  344                 return (-1);
  345         nfs_root_node.iodesc = desc;
  346         /* Fake up attributes for the root dir. */
  347         fa = &nfs_root_node.fa;
  348         fa->fa_type  = htonl(NFDIR);
  349         fa->fa_mode  = htonl(0755);
  350         fa->fa_nlink = htonl(2);
  351 
  352 #ifdef NFS_DEBUG
  353         if (debug)
  354                 printf("nfs_mount: got fh for %s\n", path);
  355 #endif
  356 
  357         return(0);
  358 }
  359 
  360 /*
  361  * Open a file.
  362  * return zero or error number
  363  */
  364 int
  365 nfs_open(char *path, struct open_file *f)
  366 {
  367         struct nfs_iodesc *newfd, *currfd;
  368         char namebuf[NFS_MAXPATHLEN + 1], *cp, *ncp;
  369         char linkbuf[NFS_MAXPATHLEN + 1];
  370         int nlinks = 0, error = 0, c;
  371 
  372 #ifdef NFS_DEBUG
  373         if (debug)
  374                 printf("nfs_open: %s\n", path);
  375 #endif
  376         if (nfs_root_node.iodesc == NULL) {
  377                 printf("nfs_open: must mount first.\n");
  378                 return (ENXIO);
  379         }
  380 
  381         currfd = &nfs_root_node;
  382         newfd = 0;
  383 
  384         cp = path;
  385         while (*cp) {
  386                 /*
  387                  * Remove extra separators
  388                  */
  389                 while (*cp == '/')
  390                         cp++;
  391 
  392                 if (*cp == '\0')
  393                         break;
  394                 /*
  395                  * Check that current node is a directory.
  396                  */
  397                 if (currfd->fa.fa_type != htonl(NFDIR)) {
  398                         error = ENOTDIR;
  399                         goto out;
  400                 }
  401 
  402                 /* allocate file system specific data structure */
  403                 newfd = alloc(sizeof(*newfd));
  404                 newfd->iodesc = currfd->iodesc;
  405                 newfd->off = 0;
  406 
  407                 /*
  408                  * Get next component of path name.
  409                  */
  410                 {
  411                         int len = 0;
  412 
  413                         ncp = cp;
  414                         while ((c = *cp) != '\0' && c != '/') {
  415                                 if (++len > NFS_MAXNAMLEN) {
  416                                         error = ENOENT;
  417                                         goto out;
  418                                 }
  419                                 cp++;
  420                         }
  421                         *cp = '\0';
  422                 }
  423 
  424                 /* lookup a file handle */
  425                 error = nfs_lookupfh(currfd, ncp, newfd);
  426                 *cp = c;
  427                 if (error)
  428                         goto out;
  429 
  430                 /*
  431                  * Check for symbolic link
  432                  */
  433                 if (newfd->fa.fa_type == htonl(NFLNK)) {
  434                         int link_len, len;
  435 
  436                         error = nfs_readlink(newfd, linkbuf);
  437                         if (error)
  438                                 goto out;
  439 
  440                         link_len = strlen(linkbuf);
  441                         len = strlen(cp);
  442 
  443                         if (link_len + len > MAXPATHLEN ||
  444                             ++nlinks > MAXSYMLINKS) {
  445                                 error = ENOENT;
  446                                 goto out;
  447                         }
  448 
  449                         bcopy(cp, &namebuf[link_len], len + 1);
  450                         bcopy(linkbuf, namebuf, link_len);
  451 
  452                         /*
  453                          * If absolute pathname, restart at root.
  454                          * If relative pathname, restart at parent directory.
  455                          */
  456                         cp = namebuf;
  457                         if (*cp == '/') {
  458                                 if (currfd != &nfs_root_node)
  459                                         free(currfd, sizeof(*currfd));
  460                                 currfd = &nfs_root_node;
  461                         }
  462 
  463                         free(newfd, sizeof(*newfd));
  464                         newfd = 0;
  465 
  466                         continue;
  467                 }
  468 
  469                 if (currfd != &nfs_root_node)
  470                         free(currfd, sizeof(*currfd));
  471                 currfd = newfd;
  472                 newfd = 0;
  473         }
  474 
  475         error = 0;
  476 
  477 out:
  478         if (!error) {
  479                 f->f_fsdata = (void *)currfd;
  480                 return (0);
  481         }
  482 
  483 #ifdef NFS_DEBUG
  484         if (debug)
  485                 printf("nfs_open: %s lookupfh failed: %s\n",
  486                     path, strerror(error));
  487 #endif
  488         if (currfd != &nfs_root_node)
  489                 free(currfd, sizeof(*currfd));
  490         if (newfd)
  491                 free(newfd, sizeof(*newfd));
  492 
  493         return (error);
  494 }
  495 
  496 int
  497 nfs_close(struct open_file *f)
  498 {
  499         struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
  500 
  501 #ifdef NFS_DEBUG
  502         if (debug)
  503                 printf("nfs_close: fp=%p\n", fp);
  504 #endif
  505 
  506         if (fp)
  507                 free(fp, sizeof(struct nfs_iodesc));
  508         f->f_fsdata = (void *)0;
  509 
  510         return (0);
  511 }
  512 
  513 /*
  514  * read a portion of a file
  515  */
  516 int
  517 nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
  518 {
  519         struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
  520         ssize_t cc;
  521         char *addr = buf;
  522 
  523 #ifdef NFS_DEBUG
  524         if (debug)
  525                 printf("nfs_read: size=%d off=%d\n", size, (int)fp->off);
  526 #endif
  527         while ((int)size > 0) {
  528                 twiddle();
  529                 cc = nfs_readdata(fp, fp->off, (void *)addr, size);
  530                 /* XXX maybe should retry on certain errors */
  531                 if (cc == -1) {
  532 #ifdef NFS_DEBUG
  533                         if (debug)
  534                                 printf("nfs_read: read: %s", strerror(errno));
  535 #endif
  536                         return (errno); /* XXX - from nfs_readdata */
  537                 }
  538                 if (cc == 0) {
  539                         if (debug)
  540                                 printf("nfs_read: hit EOF unexpectantly");
  541                         goto ret;
  542                 }
  543                 fp->off += cc;
  544                 addr += cc;
  545                 size -= cc;
  546         }
  547 ret:
  548         if (resid)
  549                 *resid = size;
  550 
  551         return (0);
  552 }
  553 
  554 /*
  555  * Not implemented.
  556  */
  557 int
  558 nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
  559 {
  560         return (EROFS);
  561 }
  562 
  563 off_t
  564 nfs_seek(struct open_file *f, off_t offset, int where)
  565 {
  566         struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
  567         n_long size = ntohl(d->fa.fa_size);
  568 
  569         switch (where) {
  570         case SEEK_SET:
  571                 d->off = offset;
  572                 break;
  573         case SEEK_CUR:
  574                 d->off += offset;
  575                 break;
  576         case SEEK_END:
  577                 d->off = size - offset;
  578                 break;
  579         default:
  580                 return (-1);
  581         }
  582 
  583         return (d->off);
  584 }
  585 
  586 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
  587 int nfs_stat_types[8] = {
  588         0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
  589 
  590 int
  591 nfs_stat(struct open_file *f, struct stat *sb)
  592 {
  593         struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
  594         n_long ftype, mode;
  595 
  596         ftype = ntohl(fp->fa.fa_type);
  597         mode  = ntohl(fp->fa.fa_mode);
  598         mode |= nfs_stat_types[ftype & 7];
  599 
  600         sb->st_mode  = mode;
  601         sb->st_nlink = ntohl(fp->fa.fa_nlink);
  602         sb->st_uid   = ntohl(fp->fa.fa_uid);
  603         sb->st_gid   = ntohl(fp->fa.fa_gid);
  604         sb->st_size  = ntohl(fp->fa.fa_size);
  605 
  606         return (0);
  607 }
  608 
  609 /*
  610  * Not implemented.
  611  */
  612 #ifndef NO_READDIR
  613 int
  614 nfs_readdir(struct open_file *f, char *name)
  615 {
  616         return (EROFS);
  617 }
  618 #endif

/* [<][>][^][v][top][bottom][index][help] */