home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 1999 May / pcp151c.iso / misc / src / install / nfsmount.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-01-21  |  11.0 KB  |  465 lines

  1. /*
  2.  * nfsmount.c -- Linux NFS mount
  3.  * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2, or (at your option)
  8.  * any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * Wed Feb  8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
  16.  * numbers to be specified on the command line.
  17.  */
  18.  
  19. /*
  20.  * nfsmount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
  21.  */
  22.  
  23. #include <stdio.h>
  24. #include <rpc/rpc.h>
  25. #include <rpc/pmap_prot.h>
  26. #include <rpc/pmap_clnt.h>
  27. #include <sys/socket.h>
  28. #include <sys/time.h>
  29. #include <string.h>
  30. #include <netdb.h>
  31. #include <arpa/inet.h>
  32. #include <errno.h>
  33. #include <string.h>
  34. #include <unistd.h>
  35. #include <sys/stat.h>
  36.  
  37. #include "dns.h"
  38. #include "log.h"
  39. #include "mount.h"
  40.  
  41. #define MS_REMOUNT    32
  42.  
  43. #include <rpcsvc/nfs_prot.h>
  44. #include <linux/nfs_mount.h>
  45.  
  46. static char *nfs_strerror(int stat);
  47.  
  48. int nfsmount(const char *spec, const char *node, int *flags,
  49.          char **extra_opts, char **mount_opts)
  50. {
  51.     char hostdir[1024];
  52.     CLIENT *mclient;
  53.     char *hostname;
  54.     char *dirname;
  55.     char *old_opts;
  56.     char *mounthost=NULL;
  57.     char new_opts[1024];
  58.     fhandle root_fhandle;
  59.     struct timeval total_timeout;
  60.     enum clnt_stat clnt_stat;
  61.     static struct nfs_mount_data data;
  62.     char *opt, *opteq;
  63.     int val;
  64.     struct sockaddr_in server_addr;
  65.     struct sockaddr_in mount_server_addr;
  66.     int msock, fsock;
  67.     struct timeval pertry_timeout;
  68.     struct fhstatus status;
  69.     char *s;
  70.     int port;
  71.     int mountport;
  72.     int bg;
  73.     int soft;
  74.     int intr;
  75.     int posix;
  76.     int nocto;
  77.     int noac;
  78.     int retry;
  79.     int tcp;
  80.     int mountprog;
  81.     int mountvers;
  82.     int nfsprog;
  83.     int nfsvers;
  84.  
  85.     msock = fsock = -1;
  86.     mclient = NULL;
  87.     strcpy(hostdir, spec);
  88.     if ((s = (strchr(hostdir, ':')))) {
  89.         hostname = hostdir;
  90.         dirname = s + 1;
  91.         *s = '\0';
  92.     }
  93.     else {
  94.         logMessage("mount: "
  95.             "directory to mount not in host:dir format");
  96.         goto fail;
  97.     }
  98.  
  99.     if (hostname[0] >= '0' && hostname[0] <= '9') {
  100.         server_addr.sin_family = AF_INET;
  101.         server_addr.sin_addr.s_addr = inet_addr(hostname);
  102.     }
  103.     else if (mygethostbyname(hostname, &server_addr.sin_addr)) {
  104.         logMessage("mount: can't get address for %s", hostname);
  105.         goto fail;
  106.     }
  107.     else {
  108.         server_addr.sin_family = AF_INET;
  109.     }
  110.  
  111.     memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr));
  112.  
  113.     /* add IP address to mtab options for use when unmounting */
  114.  
  115.     old_opts = *extra_opts;
  116.     if (!old_opts)
  117.         old_opts = "";
  118.     sprintf(new_opts, "%s%saddr=%s",
  119.         old_opts, *old_opts ? "," : "",
  120.         inet_ntoa(server_addr.sin_addr));
  121.     *extra_opts = strdup(new_opts);
  122.  
  123.     /* set default options */
  124.  
  125.     data.rsize    = 0; /* let kernel decide */
  126.     data.wsize    = 0; /* let kernel decide */
  127.     data.timeo    = 7;
  128.     data.retrans    = 3;
  129.     data.acregmin    = 3;
  130.     data.acregmax    = 60;
  131.     data.acdirmin    = 30;
  132.     data.acdirmax    = 60;
  133. #if NFS_MOUNT_VERSION >= 2
  134.     data.namlen    = NAME_MAX;
  135. #endif
  136.  
  137.     bg = 0;
  138.     soft = 0;
  139.     intr = 0;
  140.     posix = 0;
  141.     nocto = 0;
  142.     noac = 0;
  143.     retry = 10000;
  144.     tcp = 0;
  145.  
  146.     mountprog = MOUNTPROG;
  147.     mountvers = MOUNTVERS;
  148.     port = 0;
  149.     mountport = 0;
  150.     nfsprog = NFS_PROGRAM;
  151.     nfsvers = NFS_VERSION;
  152.  
  153.     /* parse options */
  154.  
  155.     for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
  156.         if ((opteq = strchr(opt, '='))) {
  157.             val = atoi(opteq + 1);    
  158.             *opteq = '\0';
  159.             if (!strcmp(opt, "rsize"))
  160.                 data.rsize = val;
  161.             else if (!strcmp(opt, "wsize"))
  162.                 data.wsize = val;
  163.             else if (!strcmp(opt, "timeo"))
  164.                 data.timeo = val;
  165.             else if (!strcmp(opt, "retrans"))
  166.                 data.retrans = val;
  167.             else if (!strcmp(opt, "acregmin"))
  168.                 data.acregmin = val;
  169.             else if (!strcmp(opt, "acregmax"))
  170.                 data.acregmax = val;
  171.             else if (!strcmp(opt, "acdirmin"))
  172.                 data.acdirmin = val;
  173.             else if (!strcmp(opt, "acdirmax"))
  174.                 data.acdirmax = val;
  175.             else if (!strcmp(opt, "actimeo")) {
  176.                 data.acregmin = val;
  177.                 data.acregmax = val;
  178.                 data.acdirmin = val;
  179.                 data.acdirmax = val;
  180.             }
  181.             else if (!strcmp(opt, "retry"))
  182.                 retry = val;
  183.             else if (!strcmp(opt, "port"))
  184.                 port = val;
  185.             else if (!strcmp(opt, "mountport"))
  186.                     mountport = val;
  187.             else if (!strcmp(opt, "mounthost"))
  188.                     mounthost=strndup(opteq+1,
  189.                           strcspn(opteq+1," \t\n\r,"));
  190.             else if (!strcmp(opt, "mountprog"))
  191.                 mountprog = val;
  192.             else if (!strcmp(opt, "mountvers"))
  193.                 mountvers = val;
  194.             else if (!strcmp(opt, "nfsprog"))
  195.                 nfsprog = val;
  196.             else if (!strcmp(opt, "nfsvers"))
  197.                 nfsvers = val;
  198.             else if (!strcmp(opt, "namlen")) {
  199. #if NFS_MOUNT_VERSION >= 2
  200.                 data.namlen = val;
  201. #else
  202.                 logMessage("Warning: Option namlen is not supported.");
  203. #endif
  204.             }
  205.             else if (!strcmp(opt, "addr"))
  206.                 /* ignore */;
  207.             else {
  208.                 logMessage("unknown nfs mount parameter: "
  209.                        "%s=%d", opt, val);
  210.                 goto fail;
  211.             }
  212.         }
  213.         else {
  214.             val = 1;
  215.             if (!strncmp(opt, "no", 2)) {
  216.                 val = 0;
  217.                 opt += 2;
  218.             }
  219.             if (!strcmp(opt, "bg")) 
  220.                 bg = val;
  221.             else if (!strcmp(opt, "fg")) 
  222.                 bg = !val;
  223.             else if (!strcmp(opt, "soft"))
  224.                 soft = val;
  225.             else if (!strcmp(opt, "hard"))
  226.                 soft = !val;
  227.             else if (!strcmp(opt, "intr"))
  228.                 intr = val;
  229.             else if (!strcmp(opt, "posix"))
  230.                 posix = val;
  231.             else if (!strcmp(opt, "cto"))
  232.                 nocto = !val;
  233.             else if (!strcmp(opt, "ac"))
  234.                 noac = !val;
  235.             else if (!strcmp(opt, "tcp"))
  236.                 tcp = val;
  237.             else if (!strcmp(opt, "udp"))
  238.                 tcp = !val;
  239.             else {
  240.                 logMessage("unknown nfs mount option: "
  241.                        "%s%s", val ? "" : "no", opt);
  242.                 goto fail;
  243.             }
  244.         }
  245.     }
  246.     data.flags = (soft ? NFS_MOUNT_SOFT : 0)
  247.         | (intr ? NFS_MOUNT_INTR : 0)
  248.         | (posix ? NFS_MOUNT_POSIX : 0)
  249.         | (nocto ? NFS_MOUNT_NOCTO : 0)
  250.         | (noac ? NFS_MOUNT_NOAC : 0);
  251. #if NFS_MOUNT_VERSION >= 2
  252.     data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
  253. #endif
  254.  
  255. #ifdef NFS_MOUNT_DEBUG
  256.     logMessage("rsize = %d, wsize = %d, timeo = %d, retrans = %d",
  257.         data.rsize, data.wsize, data.timeo, data.retrans);
  258.     logMessage("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)",
  259.         data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
  260.     logMessage("port = %d, bg = %d, retry = %d, flags = %.8x",
  261.         port, bg, retry, data.flags);
  262.     logMessage("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d",
  263.         mountprog, mountvers, nfsprog, nfsvers);
  264.     logMessage("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d",
  265.         (data.flags & NFS_MOUNT_SOFT) != 0,
  266.         (data.flags & NFS_MOUNT_INTR) != 0,
  267.         (data.flags & NFS_MOUNT_POSIX) != 0,
  268.         (data.flags & NFS_MOUNT_NOCTO) != 0,
  269.         (data.flags & NFS_MOUNT_NOAC) != 0);
  270. #if NFS_MOUNT_VERSION >= 2
  271.     logMessage("tcp = %d",
  272.         (data.flags & NFS_MOUNT_TCP) != 0);
  273. #endif
  274. #if 0
  275.     goto fail;
  276. #endif
  277. #endif
  278.  
  279.     data.version = NFS_MOUNT_VERSION;
  280.     *mount_opts = (char *) &data;
  281.  
  282.     if (*flags & MS_REMOUNT)
  283.         return 0;
  284.  
  285.     /* create mount deamon client */
  286.     /* See if the nfs host = mount host. */
  287.     if (mounthost) {
  288.       if (mounthost[0] >= '0' && mounthost[0] <= '9') {
  289.         mount_server_addr.sin_family = AF_INET;
  290.         mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
  291.       }
  292.       else if (mygethostbyname(mounthost, &mount_server_addr.sin_addr)) {
  293.         logMessage("mount: can't get address for %s", hostname);
  294.         goto fail;
  295.       }
  296.       else {
  297.         mount_server_addr.sin_family = AF_INET;
  298.       }
  299.     }
  300.  
  301.     mount_server_addr.sin_port = htons(mountport);
  302.     msock = RPC_ANYSOCK;
  303.     if ((mclient = clnttcp_create(&mount_server_addr,
  304.         mountprog, mountvers, &msock, 0, 0)) == NULL) {
  305.         mount_server_addr.sin_port = htons(mountport);
  306.         msock = RPC_ANYSOCK;
  307.         pertry_timeout.tv_sec = 3;
  308.         pertry_timeout.tv_usec = 0;
  309.         if ((mclient = clntudp_create(&mount_server_addr,
  310.             mountprog, mountvers, pertry_timeout, &msock)) == NULL) {
  311.             clnt_pcreateerror("mount clntudp_create");
  312.             goto fail;
  313.         }
  314. #ifdef NFS_MOUNT_DEBUG
  315.         logMessage("using UDP for mount deamon");
  316. #endif
  317.     }
  318. #ifdef NFS_MOUNT_DEBUG
  319.     else
  320.         logMessage("using TCP for mount deamon");
  321. #endif
  322.     mclient->cl_auth = authunix_create_default();
  323.     total_timeout.tv_sec = 20;
  324.     total_timeout.tv_usec = 0;
  325.  
  326.     /* try to mount hostname:dirname */
  327.  
  328.     clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
  329.         xdr_dirpath, &dirname,
  330.         xdr_fhstatus, &status,
  331.         total_timeout);
  332.     if (clnt_stat != RPC_SUCCESS) {
  333.         clnt_perror(mclient, "rpc mount");
  334.         goto fail;
  335.     }
  336.     if (status.fhs_status != 0) {
  337.         logMessage("mount: %s:%s failed, reason given by server: %s",
  338.             hostname, dirname, nfs_strerror(status.fhs_status));
  339.         goto fail;
  340.     }
  341.     memcpy((char *) &root_fhandle, (char *) status.fhstatus_u.fhs_fhandle,
  342.         sizeof (root_fhandle));
  343.  
  344.     /* create nfs socket for kernel */
  345.  
  346.     if (tcp) {
  347. #if NFS_MOUNT_VERSION >= 2
  348.         fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  349. #else
  350.         logMessage("NFS over TCP is not supported.");
  351.         goto fail;
  352. #endif
  353.     }
  354.     else
  355.         fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  356.     if (fsock < 0) {
  357.         perror("nfs socket");
  358.         goto fail;
  359.     }
  360.     if (bindresvport(fsock, 0) < 0) {
  361.         perror("nfs bindresvport");
  362.         goto fail;
  363.     }
  364.     if (port == 0) {
  365.         server_addr.sin_port = PMAPPORT;
  366.         port = pmap_getport(&server_addr, nfsprog, nfsvers,
  367.             tcp ? IPPROTO_TCP : IPPROTO_UDP);
  368.         if (port == 0)
  369.             port = NFS_PORT;
  370. #ifdef NFS_MOUNT_DEBUG
  371.         else
  372.             logMessage("used portmapper to find NFS port");
  373. #endif
  374.     }
  375. #ifdef NFS_MOUNT_DEBUG
  376.     logMessage("using port %d for nfs deamon", port);
  377. #endif
  378.     server_addr.sin_port = htons(port);
  379.     if (connect(fsock, (struct sockaddr *) &server_addr,
  380.         sizeof (server_addr)) < 0) {
  381.         perror("nfs connect");
  382.         goto fail;
  383.     }
  384.  
  385.     /* prepare data structure for kernel */
  386.  
  387.     data.fd = fsock;
  388.     memcpy((char *) &data.root, (char *) &root_fhandle,
  389.         sizeof (root_fhandle));
  390.     memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
  391.     strncpy(data.hostname, hostname, sizeof(data.hostname));
  392.  
  393.     /* clean up */
  394.  
  395.     auth_destroy(mclient->cl_auth);
  396.     clnt_destroy(mclient);
  397.     close(msock);
  398.     return 0;
  399.  
  400.     /* abort */
  401.  
  402. fail:
  403.     if (msock != -1) {
  404.         auth_destroy(mclient->cl_auth);
  405.         clnt_destroy(mclient);
  406.         close(msock);
  407.     }
  408.     if (fsock != -1)
  409.         close(fsock);
  410.     return 1;}
  411.     
  412.  
  413. /*
  414.  * We need to translate between nfs status return values and
  415.  * the local errno values which may not be the same.
  416.  */
  417.  
  418. #ifndef EDQUOT
  419. #define EDQUOT    ENOSPC
  420. #endif
  421.  
  422. static struct {
  423.     enum nfsstat stat;
  424.     int nfs_errno;
  425. } nfs_errtbl[] = {
  426.     { NFS_OK,        0        },
  427.     { NFSERR_PERM,        EPERM        },
  428.     { NFSERR_NOENT,        ENOENT        },
  429.     { NFSERR_IO,        EIO        },
  430.     { NFSERR_NXIO,        ENXIO        },
  431.     { NFSERR_ACCES,        EACCES        },
  432.     { NFSERR_EXIST,        EEXIST        },
  433.     { NFSERR_NODEV,        ENODEV        },
  434.     { NFSERR_NOTDIR,    ENOTDIR        },
  435.     { NFSERR_ISDIR,        EISDIR        },
  436. #ifdef NFSERR_INVAL
  437.     { NFSERR_INVAL,        EINVAL        },    /* that Sun forgot */
  438. #endif
  439.     { NFSERR_FBIG,        EFBIG        },
  440.     { NFSERR_NOSPC,        ENOSPC        },
  441.     { NFSERR_ROFS,        EROFS        },
  442.     { NFSERR_NAMETOOLONG,    ENAMETOOLONG    },
  443.     { NFSERR_NOTEMPTY,    ENOTEMPTY    },
  444.     { NFSERR_DQUOT,        EDQUOT        },
  445.     { NFSERR_STALE,        ESTALE        },
  446. #ifdef EWFLUSH
  447.     { NFSERR_WFLUSH,    EWFLUSH        },
  448. #endif
  449.     { -1,            EIO        }
  450. };
  451.  
  452. static char *nfs_strerror(int stat)
  453. {
  454.     int i;
  455.     static char buf[256];
  456.  
  457.     for (i = 0; nfs_errtbl[i].stat != -1; i++) {
  458.         if (nfs_errtbl[i].stat == stat)
  459.             return strerror(nfs_errtbl[i].nfs_errno);
  460.     }
  461.     sprintf(buf, "unknown nfs status return value: %d", stat);
  462.     return buf;
  463. }
  464.  
  465.