]> git.proxmox.com Git - mirror_zfs.git/blobdiff - lib/libshare/nfs.c
cstyle: Resolve C style issues
[mirror_zfs.git] / lib / libshare / nfs.c
index 4d130146de413dc63502f6f00b3d0338e32dcd6c..d1b207e6508ff0350b0b8621f6c8dd4d43bd1503 100644 (file)
@@ -22,6 +22,7 @@
 /*
  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2011 Gunnar Beutner
+ * Copyright (c) 2012 Cyril Plisko. All rights reserved.
  */
 
 #include <stdio.h>
@@ -33,8 +34,9 @@
 #include <libshare.h>
 #include "libshare_impl.h"
 
+static boolean_t nfs_available(void);
+
 static sa_fstype_t *nfs_fstype;
-static boolean_t nfs_available;
 
 /*
  * nfs_exportfs_temp_fd refers to a temporary copy of the output
@@ -48,6 +50,10 @@ typedef int (*nfs_shareopt_callback_t)(const char *opt, const char *value,
 typedef int (*nfs_host_callback_t)(const char *sharepath, const char *host,
     const char *security, const char *access, void *cookie);
 
+/*
+ * Invokes the specified callback function for each Solaris share option
+ * listed in the specified string.
+ */
 static int
 foreach_nfs_shareopt(const char *shareopts,
     nfs_shareopt_callback_t callback, void *cookie)
@@ -56,12 +62,12 @@ foreach_nfs_shareopt(const char *shareopts,
        int was_nul, rc;
 
        if (shareopts == NULL)
-               return SA_OK;
+               return (SA_OK);
 
        shareopts_dup = strdup(shareopts);
 
        if (shareopts_dup == NULL)
-               return SA_NO_MEMORY;
+               return (SA_NO_MEMORY);
 
        opt = shareopts_dup;
        was_nul = 0;
@@ -89,7 +95,7 @@ foreach_nfs_shareopt(const char *shareopts,
 
                        if (rc != SA_OK) {
                                free(shareopts_dup);
-                               return rc;
+                               return (rc);
                        }
                }
 
@@ -101,7 +107,7 @@ foreach_nfs_shareopt(const char *shareopts,
 
        free(shareopts_dup);
 
-       return 0;
+       return (0);
 }
 
 typedef struct nfs_host_cookie_s {
@@ -111,6 +117,11 @@ typedef struct nfs_host_cookie_s {
        const char *security;
 } nfs_host_cookie_t;
 
+/*
+ * Helper function for foreach_nfs_host. This function checks whether the
+ * current share option is a host specification and invokes a callback
+ * function with information about the host.
+ */
 static int
 foreach_nfs_host_cb(const char *opt, const char *value, void *pcookie)
 {
@@ -135,7 +146,7 @@ foreach_nfs_host_cb(const char *opt, const char *value, void *pcookie)
                host_dup = strdup(value);
 
                if (host_dup == NULL)
-                       return SA_NO_MEMORY;
+                       return (SA_NO_MEMORY);
 
                host = host_dup;
 
@@ -152,7 +163,7 @@ foreach_nfs_host_cb(const char *opt, const char *value, void *pcookie)
                        if (rc != SA_OK) {
                                free(host_dup);
 
-                               return rc;
+                               return (rc);
                        }
 
                        host = next;
@@ -161,9 +172,12 @@ foreach_nfs_host_cb(const char *opt, const char *value, void *pcookie)
                free(host_dup);
        }
 
-       return SA_OK;
+       return (SA_OK);
 }
 
+/*
+ * Invokes a callback function for all NFS hosts that are set for a share.
+ */
 static int
 foreach_nfs_host(sa_share_impl_t impl_share, nfs_host_callback_t callback,
     void *cookie)
@@ -182,6 +196,9 @@ foreach_nfs_host(sa_share_impl_t impl_share, nfs_host_callback_t callback,
            &udata);
 }
 
+/*
+ * Converts a Solaris NFS host specification to its Linux equivalent.
+ */
 static int
 get_linux_hostspec(const char *solaris_hostspec, char **plinux_hostspec)
 {
@@ -200,40 +217,23 @@ get_linux_hostspec(const char *solaris_hostspec, char **plinux_hostspec)
        }
 
        if (*plinux_hostspec == NULL) {
-               return SA_NO_MEMORY;
+               return (SA_NO_MEMORY);
        }
 
-       return SA_OK;
+       return (SA_OK);
 }
 
+/*
+ * Used internally by nfs_enable_share to enable sharing for a single host.
+ */
 static int
 nfs_enable_share_one(const char *sharepath, const char *host,
     const char *security, const char *access, void *pcookie)
 {
-       pid_t pid;
-       int rc, status;
+       int rc;
        char *linuxhost, *hostpath, *opts;
        const char *linux_opts = (const char *)pcookie;
-
-       pid = fork();
-
-       if (pid < 0)
-               return SA_SYSTEM_ERR;
-
-       if (pid > 0) {
-               while ((rc = waitpid(pid, &status, 0)) <= 0 && errno == EINTR)
-                       ; /* empty loop body */
-
-               if (rc <= 0)
-                       return SA_SYSTEM_ERR;
-
-               if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
-                       return SA_CONFIG_ERR;
-
-               return SA_OK;
-       }
-
-       /* child */
+       char *argv[6];
 
        /* exportfs -i -o sec=XX,rX,<opts> <host>:<sharepath> */
 
@@ -268,18 +268,27 @@ nfs_enable_share_one(const char *sharepath, const char *host,
        fprintf(stderr, "sharing %s with opts %s\n", hostpath, opts);
 #endif
 
-       rc = execlp("/usr/sbin/exportfs", "exportfs", "-i", \
-           "-o", opts, hostpath, NULL);
+       argv[0] = "/usr/sbin/exportfs";
+       argv[1] = "-i";
+       argv[2] = "-o";
+       argv[3] = opts;
+       argv[4] = hostpath;
+       argv[5] = NULL;
 
-       if (rc < 0) {
-               free(hostpath);
-               free(opts);
-               exit(1);
-       }
+       rc = libzfs_run_process(argv[0], argv, 0);
 
-       exit(0);
+       free(hostpath);
+       free(opts);
+
+       if (rc < 0)
+               return (SA_SYSTEM_ERR);
+       else
+               return (SA_OK);
 }
 
+/*
+ * Adds a Linux share option to an array of NFS options.
+ */
 static int
 add_linux_shareopt(char **plinux_opts, const char *key, const char *value)
 {
@@ -293,7 +302,7 @@ add_linux_shareopt(char **plinux_opts, const char *key, const char *value)
            (value ? 1 + strlen(value) : 0) + 1);
 
        if (new_linux_opts == NULL)
-               return SA_NO_MEMORY;
+               return (SA_NO_MEMORY);
 
        new_linux_opts[len] = '\0';
 
@@ -309,9 +318,13 @@ add_linux_shareopt(char **plinux_opts, const char *key, const char *value)
 
        *plinux_opts = new_linux_opts;
 
-       return SA_OK;
+       return (SA_OK);
 }
 
+/*
+ * Validates and converts a single Solaris share option to its Linux
+ * equivalent.
+ */
 static int
 get_linux_shareopts_cb(const char *key, const char *value, void *cookie)
 {
@@ -320,15 +333,15 @@ get_linux_shareopts_cb(const char *key, const char *value, void *cookie)
        /* host-specific options, these are taken care of elsewhere */
        if (strcmp(key, "ro") == 0 || strcmp(key, "rw") == 0 ||
            strcmp(key, "sec") == 0)
-               return SA_OK;
+               return (SA_OK);
 
        if (strcmp(key, "anon") == 0)
                key = "anonuid";
 
-        if (strcmp(key, "root_mapping") == 0) {
-                (void) add_linux_shareopt(plinux_opts, "root_squash", NULL);
-                key = "anonuid";
-        }
+       if (strcmp(key, "root_mapping") == 0) {
+               (void) add_linux_shareopt(plinux_opts, "root_squash", NULL);
+               key = "anonuid";
+       }
 
        if (strcmp(key, "nosub") == 0)
                key = "subtree_check";
@@ -349,16 +362,20 @@ get_linux_shareopts_cb(const char *key, const char *value, void *cookie)
            strcmp(key, "root_squash") != 0 &&
            strcmp(key, "no_root_squash") != 0 &&
            strcmp(key, "all_squash") != 0 &&
-           strcmp(key, "no_all_squash") != 0 &&
+           strcmp(key, "no_all_squash") != 0 && strcmp(key, "fsid") != 0 &&
            strcmp(key, "anonuid") != 0 && strcmp(key, "anongid") != 0) {
-               return SA_SYNTAX_ERR;
+               return (SA_SYNTAX_ERR);
        }
 
        (void) add_linux_shareopt(plinux_opts, key, value);
 
-       return SA_OK;
+       return (SA_OK);
 }
 
+/*
+ * Takes a string containing Solaris share options (e.g. "sync,no_acl") and
+ * converts them to a NULL-terminated array of Linux NFS options.
+ */
 static int
 get_linux_shareopts(const char *shareopts, char **plinux_opts)
 {
@@ -373,70 +390,57 @@ get_linux_shareopts(const char *shareopts, char **plinux_opts)
        (void) add_linux_shareopt(plinux_opts, "no_root_squash", NULL);
        (void) add_linux_shareopt(plinux_opts, "mountpoint", NULL);
 
-       rc = foreach_nfs_shareopt(shareopts, get_linux_shareopts_cb, plinux_opts);
+       rc = foreach_nfs_shareopt(shareopts, get_linux_shareopts_cb,
+           plinux_opts);
 
        if (rc != SA_OK) {
                free(*plinux_opts);
                *plinux_opts = NULL;
        }
 
-       return rc;
+       return (rc);
 }
 
+/*
+ * Enables NFS sharing for the specified share.
+ */
 static int
 nfs_enable_share(sa_share_impl_t impl_share)
 {
        char *shareopts, *linux_opts;
        int rc;
 
-       if (!nfs_available) {
-               return SA_SYSTEM_ERR;
+       if (!nfs_available()) {
+               return (SA_SYSTEM_ERR);
        }
 
        shareopts = FSINFO(impl_share, nfs_fstype)->shareopts;
 
        if (shareopts == NULL)
-               return SA_OK;
+               return (SA_OK);
 
        rc = get_linux_shareopts(shareopts, &linux_opts);
 
        if (rc != SA_OK)
-               return rc;
+               return (rc);
 
        rc = foreach_nfs_host(impl_share, nfs_enable_share_one, linux_opts);
 
        free(linux_opts);
 
-       return rc;
+       return (rc);
 }
 
+/*
+ * Used internally by nfs_disable_share to disable sharing for a single host.
+ */
 static int
 nfs_disable_share_one(const char *sharepath, const char *host,
     const char *security, const char *access, void *cookie)
 {
-       pid_t pid;
-       int rc, status;
+       int rc;
        char *linuxhost, *hostpath;
-
-       pid = fork();
-
-       if (pid < 0)
-               return SA_SYSTEM_ERR;
-
-       if (pid > 0) {
-               while ((rc = waitpid(pid, &status, 0)) <= 0 && errno == EINTR)
-                       ; /* empty loop body */
-
-               if (rc <= 0)
-                       return SA_SYSTEM_ERR;
-
-               if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
-                       return SA_CONFIG_ERR;
-
-               return SA_OK;
-       }
-
-       /* child */
+       char *argv[4];
 
        rc = get_linux_hostspec(host, &linuxhost);
 
@@ -458,31 +462,41 @@ nfs_disable_share_one(const char *sharepath, const char *host,
        fprintf(stderr, "unsharing %s\n", hostpath);
 #endif
 
-       rc = execlp("/usr/sbin/exportfs", "exportfs", "-u", \
-           hostpath, NULL);
+       argv[0] = "/usr/sbin/exportfs";
+       argv[1] = "-u";
+       argv[2] = hostpath;
+       argv[3] = NULL;
 
-       if (rc < 0) {
-               free(hostpath);
-               exit(1);
-       }
+       rc = libzfs_run_process(argv[0], argv, 0);
 
-       exit(0);
+       free(hostpath);
+
+       if (rc < 0)
+               return (SA_SYSTEM_ERR);
+       else
+               return (SA_OK);
 }
 
+/*
+ * Disables NFS sharing for the specified share.
+ */
 static int
 nfs_disable_share(sa_share_impl_t impl_share)
 {
-       if (!nfs_available) {
+       if (!nfs_available()) {
                /*
                 * The share can't possibly be active, so nothing
                 * needs to be done to disable it.
                 */
-               return SA_OK;
+               return (SA_OK);
        }
 
-       return foreach_nfs_host(impl_share, nfs_disable_share_one, NULL);
+       return (foreach_nfs_host(impl_share, nfs_disable_share_one, NULL));
 }
 
+/*
+ * Checks whether the specified NFS share options are syntactically correct.
+ */
 static int
 nfs_validate_shareopts(const char *shareopts)
 {
@@ -492,32 +506,35 @@ nfs_validate_shareopts(const char *shareopts)
        rc = get_linux_shareopts(shareopts, &linux_opts);
 
        if (rc != SA_OK)
-               return rc;
+               return (rc);
 
        free(linux_opts);
 
-       return SA_OK;
+       return (SA_OK);
 }
 
+/*
+ * Checks whether a share is currently active.
+ */
 static boolean_t
-is_share_active(sa_share_impl_t impl_share)
+nfs_is_share_active(sa_share_impl_t impl_share)
 {
        char line[512];
        char *tab, *cur;
        FILE *nfs_exportfs_temp_fp;
 
-       if (nfs_exportfs_temp_fd < 0)
-               return B_FALSE;
+       if (!nfs_available())
+               return (B_FALSE);
 
        nfs_exportfs_temp_fp = fdopen(dup(nfs_exportfs_temp_fd), "r");
 
        if (nfs_exportfs_temp_fp == NULL ||
            fseek(nfs_exportfs_temp_fp, 0, SEEK_SET) < 0) {
                fclose(nfs_exportfs_temp_fp);
-               return B_FALSE;
+               return (B_FALSE);
        }
 
-       while (fgets(line, sizeof(line), nfs_exportfs_temp_fp) != NULL) {
+       while (fgets(line, sizeof (line), nfs_exportfs_temp_fp) != NULL) {
                /*
                 * exportfs uses separate lines for the share path
                 * and the export options when the share path is longer
@@ -548,15 +565,21 @@ is_share_active(sa_share_impl_t impl_share)
 
                if (strcmp(line, impl_share->sharepath) == 0) {
                        fclose(nfs_exportfs_temp_fp);
-                       return B_TRUE;
+                       return (B_TRUE);
                }
        }
 
        fclose(nfs_exportfs_temp_fp);
 
-       return B_FALSE;
+       return (B_FALSE);
 }
 
+/*
+ * Called to update a share's options. A share's options might be out of
+ * date if the share was loaded from disk (i.e. /etc/dfs/sharetab) and the
+ * "sharenfs" dataset property has changed in the meantime. This function
+ * also takes care of re-enabling the share if necessary.
+ */
 static int
 nfs_update_shareopts(sa_share_impl_t impl_share, const char *resource,
     const char *shareopts)
@@ -565,7 +588,8 @@ nfs_update_shareopts(sa_share_impl_t impl_share, const char *resource,
        boolean_t needs_reshare = B_FALSE;
        char *old_shareopts;
 
-       FSINFO(impl_share, nfs_fstype)->active = is_share_active(impl_share);
+       FSINFO(impl_share, nfs_fstype)->active =
+           nfs_is_share_active(impl_share);
 
        old_shareopts = FSINFO(impl_share, nfs_fstype)->shareopts;
 
@@ -581,7 +605,7 @@ nfs_update_shareopts(sa_share_impl_t impl_share, const char *resource,
        shareopts_dup = strdup(shareopts);
 
        if (shareopts_dup == NULL)
-               return SA_NO_MEMORY;
+               return (SA_NO_MEMORY);
 
        if (old_shareopts != NULL)
                free(old_shareopts);
@@ -591,10 +615,13 @@ nfs_update_shareopts(sa_share_impl_t impl_share, const char *resource,
        if (needs_reshare)
                nfs_enable_share(impl_share);
 
-       return SA_OK;
+       return (SA_OK);
 }
 
-
+/*
+ * Clears a share's NFS options. Used by libshare to
+ * clean up shares that are about to be free()'d.
+ */
 static void
 nfs_clear_shareopts(sa_share_impl_t impl_share)
 {
@@ -640,7 +667,7 @@ nfs_check_exportfs(void)
        nfs_exportfs_temp_fd = mkstemp(nfs_exportfs_tempfile);
 
        if (nfs_exportfs_temp_fd < 0)
-               return SA_SYSTEM_ERR;
+               return (SA_SYSTEM_ERR);
 
        unlink(nfs_exportfs_tempfile);
 
@@ -648,20 +675,28 @@ nfs_check_exportfs(void)
 
        pid = fork();
 
-       if (pid < 0)
-               return SA_SYSTEM_ERR;
+       if (pid < 0) {
+               (void) close(nfs_exportfs_temp_fd);
+               nfs_exportfs_temp_fd = -1;
+               return (SA_SYSTEM_ERR);
+       }
 
        if (pid > 0) {
-               while ((rc = waitpid(pid, &status, 0)) <= 0 && errno == EINTR)
-                       ; /* empty loop body */
+               while ((rc = waitpid(pid, &status, 0)) <= 0 && errno == EINTR);
 
-               if (rc <= 0)
-                       return SA_SYSTEM_ERR;
+               if (rc <= 0) {
+                       (void) close(nfs_exportfs_temp_fd);
+                       nfs_exportfs_temp_fd = -1;
+                       return (SA_SYSTEM_ERR);
+               }
 
-               if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
-                       return SA_CONFIG_ERR;
+               if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+                       (void) close(nfs_exportfs_temp_fd);
+                       nfs_exportfs_temp_fd = -1;
+                       return (SA_CONFIG_ERR);
+               }
 
-               return SA_OK;
+               return (SA_OK);
        }
 
        /* child */
@@ -680,10 +715,23 @@ nfs_check_exportfs(void)
        exit(0);
 }
 
+/*
+ * Provides a convenient wrapper for determing nfs availability
+ */
+static boolean_t
+nfs_available(void)
+{
+       if (nfs_exportfs_temp_fd == -1)
+               (void) nfs_check_exportfs();
+
+       return ((nfs_exportfs_temp_fd != -1) ? B_TRUE : B_FALSE);
+}
+
+/*
+ * Initializes the NFS functionality of libshare.
+ */
 void
 libshare_nfs_init(void)
 {
-       nfs_available = (nfs_check_exportfs() == SA_OK);
-
        nfs_fstype = register_fstype("nfs", &nfs_shareops);
 }