]> git.decadent.org.uk Git - nfs-utils.git/blobdiff - utils/exportfs/exportfs.c
exportfs: exportfs.c no longer needs #include "xmalloc.h"
[nfs-utils.git] / utils / exportfs / exportfs.c
index 18dfe5ad8046c124b7e2cb8fb76da6800eeb8dba..93bad32241fae7d5d0c4f7276e75f3290da5ffdf 100644 (file)
 #include <config.h>
 #endif
 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/vfs.h>
+#include <sys/stat.h>
 #include <unistd.h>
+#include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
 #include <getopt.h>
+#include <fcntl.h>
 #include <netdb.h>
 #include <errno.h>
-#include "xmalloc.h"
+
 #include "misc.h"
 #include "nfslib.h"
 #include "exportfs.h"
-#include "xmalloc.h"
 #include "xlog.h"
 
 static void    export_all(int verbose);
@@ -34,6 +39,7 @@ static void   dump(int verbose);
 static void    error(nfs_export *exp, int err);
 static void    usage(void);
 static void    validate_export(nfs_export *exp);
+static int     matchhostname(const char *hostname1, const char *hostname2);
 
 int
 main(int argc, char **argv)
@@ -110,7 +116,6 @@ main(int argc, char **argv)
                        return 0;
                }
        }
-
        if (f_export && ! f_ignore)
                export_read(_PATH_EXPORTS);
        if (f_export) {
@@ -192,10 +197,10 @@ exports_update(int verbose)
 {
        nfs_export      *exp;
 
-       for (exp = exportlist[MCL_FQDN]; exp; exp=exp->m_next) {
+       for (exp = exportlist[MCL_FQDN].p_head; exp; exp=exp->m_next) {
                exports_update_one(exp, verbose);
        }
-       for (exp = exportlist[MCL_GSS]; exp; exp=exp->m_next) {
+       for (exp = exportlist[MCL_GSS].p_head; exp; exp=exp->m_next) {
                exports_update_one(exp, verbose);
        }
 }
@@ -211,7 +216,7 @@ export_all(int verbose)
        int             i;
 
        for (i = 0; i < MCL_MAXTYPES; i++) {
-               for (exp = exportlist[i]; exp; exp = exp->m_next) {
+               for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
                        if (verbose)
                                printf("exporting %s:%s\n",
                                       exp->m_client->m_hostname, 
@@ -231,7 +236,7 @@ exportfs(char *arg, char *options, int verbose)
 {
        struct exportent *eep;
        nfs_export      *exp;
-       struct hostent  *hp = NULL;
+       struct addrinfo *ai = NULL;
        char            *path;
        char            *hname = arg;
        int             htype;
@@ -244,32 +249,21 @@ exportfs(char *arg, char *options, int verbose)
                return;
        }
 
-       if ((htype = client_gettype(hname)) == MCL_FQDN &&
-           (hp = gethostbyname(hname)) != NULL) {
-               struct hostent *hp2 = hostent_dup (hp);
-               hp = gethostbyaddr(hp2->h_addr, hp2->h_length,
-                                  hp2->h_addrtype);
-               if (hp) {
-                       free(hp2);
-                       hp = hostent_dup(hp);
-               } else
-                       hp = hp2;
-               exp = export_find(hp, path);
-               hname = hp->h_name;
-       } else {
+       if ((htype = client_gettype(hname)) == MCL_FQDN) {
+               ai = host_addrinfo(hname);
+               if (ai != NULL) {
+                       exp = export_find(ai, path);
+                       hname = ai->ai_canonname;
+               }
+       } else
                exp = export_lookup(hname, path, 0);
-       }
 
        if (!exp) {
                if (!(eep = mkexportent(hname, path, options)) ||
-                   !(exp = export_create(eep, 0))) {
-                       if (hp) free (hp);
-                       return;
-               }
-       } else if (!updateexportent(&exp->m_export, options)) {
-               if (hp) free (hp);
-               return;
-       }
+                   !(exp = export_create(eep, 0)))
+                       goto out;
+       } else if (!updateexportent(&exp->m_export, options))
+               goto out;
 
        if (verbose)
                printf("exporting %s:%s\n", exp->m_client->m_hostname, 
@@ -279,14 +273,16 @@ exportfs(char *arg, char *options, int verbose)
        exp->m_changed = 1;
        exp->m_warned = 0;
        validate_export(exp);
-       if (hp) free (hp);
+
+out:
+       freeaddrinfo(ai);
 }
 
 static void
 unexportfs(char *arg, int verbose)
 {
        nfs_export      *exp;
-       struct hostent  *hp = NULL;
+       struct addrinfo *ai = NULL;
        char            *path;
        char            *hname = arg;
        int             htype;
@@ -301,13 +297,12 @@ unexportfs(char *arg, int verbose)
        }
 
        if ((htype = client_gettype(hname)) == MCL_FQDN) {
-               if ((hp = gethostbyname(hname)) != 0) {
-                       hp = hostent_dup (hp);
-                       hname = (char *) hp->h_name;
-               }
+               ai = host_addrinfo(hname);
+               if (ai)
+                       hname = ai->ai_canonname;
        }
 
-       for (exp = exportlist[htype]; exp; exp = exp->m_next) {
+       for (exp = exportlist[htype].p_head; exp; exp = exp->m_next) {
                if (path && strcmp(path, exp->m_export.e_path))
                        continue;
                if (htype != exp->m_client->m_type)
@@ -340,7 +335,7 @@ unexportfs(char *arg, int verbose)
                exp->m_mayexport = 0;
        }
 
-       if (hp) free (hp);
+       freeaddrinfo(ai);
 }
 
 static int can_test(void)
@@ -388,6 +383,8 @@ validate_export(nfs_export *exp)
         */
        struct stat stb;
        char *path = exp->m_export.e_path;
+       struct statfs64 stf;
+       int fs_has_fsid = 0;
 
        if (stat(path, &stb) < 0) {
                fprintf(stderr, "exportfs: Warning: %s does not exist\n",
@@ -403,7 +400,12 @@ validate_export(nfs_export *exp)
        if (!can_test())
                return;
 
-       if ((exp->m_export.e_flags & NFSEXP_FSID) || exp->m_export.e_uuid) {
+       if (!statfs64(path, &stf) &&
+           (stf.f_fsid.__val[0] || stf.f_fsid.__val[1]))
+               fs_has_fsid = 1;
+
+       if ((exp->m_export.e_flags & NFSEXP_FSID) || exp->m_export.e_uuid ||
+           fs_has_fsid) {
                if ( !test_export(path, 1)) {
                        fprintf(stderr, "exportfs: Warning: %s does not "
                                "support NFS export.\n",
@@ -423,6 +425,82 @@ validate_export(nfs_export *exp)
        }
 }
 
+static _Bool
+is_hostname(const char *sp)
+{
+       if (*sp == '\0' || *sp == '@')
+               return false;
+
+       for (; *sp != '\0'; sp++) {
+               if (*sp == '*' || *sp == '?' || *sp == '[' || *sp == '/')
+                       return false;
+               if (*sp == '\\' && sp[1] != '\0')
+                       sp++;
+       }
+
+       return true;
+}
+
+static _Bool
+compare_sockaddrs4(const struct sockaddr *sa1, const struct sockaddr *sa2)
+{
+       const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1;
+       const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2;
+       return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
+}
+
+static _Bool
+compare_sockaddrs(const struct sockaddr *sa1, const struct sockaddr *sa2)
+{
+       if (sa1->sa_family == sa2->sa_family)
+               switch (sa1->sa_family) {
+               case AF_INET:
+                       return compare_sockaddrs4(sa1, sa2);
+               }
+
+       return false;
+}
+
+static int
+matchhostname(const char *hostname1, const char *hostname2)
+{
+       struct addrinfo *results1 = NULL, *results2 = NULL;
+       struct addrinfo *ai1, *ai2;
+       int result = 0;
+
+       if (strcasecmp(hostname1, hostname2) == 0)
+               return 1;
+
+       /*
+        * Don't pass export wildcards or netgroup names to DNS
+        */
+       if (!is_hostname(hostname1) || !is_hostname(hostname2))
+               return 0;
+
+       results1 = host_addrinfo(hostname1);
+       if (results1 == NULL)
+               goto out;
+       results2 = host_addrinfo(hostname2);
+       if (results2 == NULL)
+               goto out;
+
+       if (strcasecmp(results1->ai_canonname, results2->ai_canonname) == 0) {
+               result = 1;
+               goto out;
+       }
+
+       for (ai1 = results1; ai1 != NULL; ai1 = ai1->ai_next)
+               for (ai2 = results2; ai2 != NULL; ai2 = ai2->ai_next)
+                       if (compare_sockaddrs(ai1->ai_addr, ai2->ai_addr)) {
+                               result = 1;
+                               break;
+                       }
+
+out:
+       freeaddrinfo(results1);
+       freeaddrinfo(results2);
+       return result;
+}
 
 static char
 dumpopt(char c, char *fmt, ...)
@@ -445,7 +523,7 @@ dump(int verbose)
        char            *hname, c;
 
        for (htype = 0; htype < MCL_MAXTYPES; htype++) {
-               for (exp = exportlist[htype]; exp; exp = exp->m_next) {
+               for (exp = exportlist[htype].p_head; exp; exp = exp->m_next) {
                        ep = &exp->m_export;
                        if (!exp->m_xtabent)
                            continue; /* neilb */