X-Git-Url: https://git.camperquake.de/gitweb.cgi?a=blobdiff_plain;f=lib%2Flibshare%2Fnfs.c;h=00ba0f621347a5b1cafb18828cf7e4be5cfcfad2;hb=cc92e9d0c3e67a7e66c844466f85696a087bf60a;hp=4d130146de413dc63502f6f00b3d0338e32dcd6c;hpb=5333eb0b3b18d345052b8cfaf41b90a0c5781fb8;p=zfs.git diff --git a/lib/libshare/nfs.c b/lib/libshare/nfs.c index 4d13014..00ba0f6 100644 --- a/lib/libshare/nfs.c +++ b/lib/libshare/nfs.c @@ -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 @@ -33,8 +34,9 @@ #include #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) @@ -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) { @@ -164,6 +175,9 @@ foreach_nfs_host_cb(const char *opt, const char *value, void *pcookie) 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) { @@ -206,34 +223,17 @@ get_linux_hostspec(const char *solaris_hostspec, char **plinux_hostspec) 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, : */ @@ -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) { @@ -312,6 +321,10 @@ add_linux_shareopt(char **plinux_opts, const char *key, const char *value) 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) { @@ -349,7 +362,7 @@ 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; } @@ -359,6 +372,10 @@ get_linux_shareopts_cb(const char *key, const char *value, void *cookie) 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) { @@ -383,13 +400,16 @@ get_linux_shareopts(const char *shareopts, char **plinux_opts) 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) { + if (!nfs_available()) { return SA_SYSTEM_ERR; } @@ -410,33 +430,16 @@ nfs_enable_share(sa_share_impl_t impl_share) 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,21 +461,28 @@ 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. @@ -483,6 +493,9 @@ nfs_disable_share(sa_share_impl_t impl_share) 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) { @@ -499,14 +512,17 @@ nfs_validate_shareopts(const char *shareopts) 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) + if (!nfs_available()) return B_FALSE; nfs_exportfs_temp_fp = fdopen(dup(nfs_exportfs_temp_fd), "r"); @@ -557,6 +573,12 @@ is_share_active(sa_share_impl_t impl_share) 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 +587,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; @@ -594,7 +617,10 @@ nfs_update_shareopts(sa_share_impl_t impl_share, const char *resource, 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) { @@ -648,18 +674,27 @@ nfs_check_exportfs(void) pid = fork(); - if (pid < 0) + 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 */ - if (rc <= 0) + if (rc <= 0) { + (void) close(nfs_exportfs_temp_fd); + nfs_exportfs_temp_fd = -1; return SA_SYSTEM_ERR; + } - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + (void) close(nfs_exportfs_temp_fd); + nfs_exportfs_temp_fd = -1; return SA_CONFIG_ERR; + } return SA_OK; } @@ -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); }