Add a high-level async function to read the export list
authorRonnie Sahlberg <ronniesahlberg@gmail.com>
Sun, 19 Jun 2011 04:54:17 +0000 (14:54 +1000)
committerRonnie Sahlberg <ronniesahlberg@gmail.com>
Sun, 19 Jun 2011 04:54:17 +0000 (14:54 +1000)
examples/nfsclient-async.c
include/libnfs-raw.h
include/libnfs.h
lib/libnfs.c
mount/mount.c

index b630f4e794c7ce0305baa332dfbec805470a52aa..d8420e14f13dad0d93c2523256943fd82a21e60e 100644 (file)
 #include <fcntl.h>
 #include <poll.h>
 #include "libnfs.h"
+#include "libnfs-raw.h"
+#include "libnfs-raw-mount.h"
+
+struct rpc_context *mount_context;
 
 struct client {
        char *server;
@@ -41,6 +45,27 @@ struct client {
        int is_finished;
 };
 
+void mount_export_cb(struct rpc_context *mount_context, int status, void *data, void *private_data)
+{
+       struct client *client = private_data;
+       exports export = *(exports *)data;
+
+       if (status < 0) {
+               printf("MOUNT/EXPORT failed with \"%s\"\n", rpc_get_error(mount_context));
+               exit(10);
+       }
+
+       printf("Got exports list from server %s\n", client->server);
+       while (export != NULL) {
+             printf("Export: %s\n", export->ex_dir);
+             export = export->ex_next;
+       }
+
+       mount_context = NULL;
+
+       client->is_finished = 1;
+}
+
 void nfs_opendir_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
 {
        struct client *client = private_data;
@@ -58,7 +83,11 @@ void nfs_opendir_cb(int status, struct nfs_context *nfs, void *data, void *priva
        }
        nfs_closedir(nfs, nfsdir);
 
-       client->is_finished = 1;
+       mount_context = rpc_init_context();
+       if (mount_getexports_async(mount_context, client->server, mount_export_cb, client) != 0) {
+               printf("Failed to start MOUNT/EXPORT\n");
+               exit(10);
+       }
 }
 
 void nfs_close_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
@@ -190,9 +219,9 @@ void nfs_mount_cb(int status, struct nfs_context *nfs, void *data, void *private
 int main(int argc _U_, char *argv[] _U_)
 {
        struct nfs_context *nfs;
-       struct pollfd pfd;
        int ret;
        struct client client;
+       struct pollfd pfds[2]; /* nfs:0  mount:1 */
 
        client.server = SERVER;
        client.export = EXPORT;
@@ -211,14 +240,28 @@ int main(int argc _U_, char *argv[] _U_)
        }
 
        for (;;) {
-               pfd.fd = nfs_get_fd(nfs);
-               pfd.events = nfs_which_events(nfs);
+               int num_fds;
+
+               pfds[0].fd = nfs_get_fd(nfs);
+               pfds[0].events = nfs_which_events(nfs);
+               num_fds = 1;
 
-               if (poll(&pfd, 1, -1) < 0) {
+               if (mount_context != 0 && rpc_get_fd(mount_context) != -1) {
+                       pfds[1].fd = rpc_get_fd(mount_context);
+                       pfds[1].events = rpc_which_events(mount_context);
+                       num_fds = 2;
+               }
+               if (poll(&pfds[0], 2, -1) < 0) {
                        printf("Poll failed");
                        exit(10);
                }
-               if (nfs_service(nfs, pfd.revents) < 0) {
+               if (mount_context != NULL) {
+                       if (rpc_service(mount_context, pfds[1].revents) < 0) {
+                               printf("rpc_service failed\n");
+                               break;
+                       }
+               }
+               if (nfs_service(nfs, pfds[0].revents) < 0) {
                        printf("nfs_service failed\n");
                        break;
                }
@@ -228,6 +271,10 @@ int main(int argc _U_, char *argv[] _U_)
        }
        
        nfs_destroy_context(nfs);
+       if (mount_context != NULL) {
+               rpc_destroy_context(mount_context);
+               mount_context = NULL;
+       }
        printf("nfsclient finished\n");
        return 0;
 }
index c1eb00d5e24f1b0afde113e1ae9e5b1c02d745ae..bd23dc11665ac74fb26b3c3f1d60d448a72dba0d 100644 (file)
@@ -43,8 +43,6 @@ char *rpc_get_error(struct rpc_context *rpc);
 #define RPC_STATUS_ERROR               1
 #define RPC_STATUS_CANCEL              2
 
-typedef void (*rpc_cb)(struct rpc_context *rpc, int status, void *data, void *private_data);
-
 /*
  * Async connection to the tcp port at server:port.
  * Function returns
@@ -194,13 +192,17 @@ int rpc_mount_umntall_async(struct rpc_context *rpc, rpc_cb cb, void *private_da
 
 /*
  * Call MOUNT/EXPORT
+ * NOTE: You must include 'libnfs-raw-mount.h' to get the definitions of the
+ * returned structures.
+ *
  * Function returns
  *  0 : The call was initiated. The callback will be invoked when the call completes.
  * <0 : An error occured when trying to set up the call. The callback will not be invoked.
  *
  * When the callback is invoked, status indicates the result:
  * RPC_STATUS_SUCCESS : We got a successful response from the mount daemon.
- *                      data is an exports.
+ *                      data is a pointer to an exports pointer:
+ *                      exports export = *(exports *)data;
  * RPC_STATUS_ERROR   : An error occured when trying to contact the mount daemon.
  *                      data is the error string.
  * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
index e95cdbe589ccf81e4f209af8fe5c5ff0c56372bc..bbca07e1f809192a34138929640689ef361bbdc1 100644 (file)
@@ -20,6 +20,7 @@
 #include <stdint.h>
 
 struct nfs_context;
+struct rpc_context;
 
 /*
  * Used for interfacing the async version of the api into an external eventsystem
@@ -46,6 +47,10 @@ char *nfs_get_error(struct nfs_context *nfs);
  */
 typedef void (*nfs_cb)(int err, struct nfs_context *nfs, void *data, void *private_data);
 
+/*
+ * Callback for all ASYNC rpc functions
+ */
+typedef void (*rpc_cb)(struct rpc_context *rpc, int status, void *data, void *private_data);
 
 
 
@@ -910,6 +915,30 @@ int nfs_link_async(struct nfs_context *nfs, const char *oldpath, const char *new
 int nfs_link(struct nfs_context *nfs, const char *oldpath, const char *newpath);
 
 
+/*
+ * GETEXPORTS()
+ */
+/*
+ * Async getexports()
+ * NOTE: You must include 'libnfs-raw-mount.h' to get the definitions of the
+ * returned structures.
+ *
+ * This function will return the list of exports from an NFS server.
+ *
+ * Function returns
+ *  0 : The operation was initiated. Once the operation finishes, the callback will be invoked.
+ * <0 : An error occured when trying to set up the operation. The callback will not be invoked.
+ *
+ * When the callback is invoked, status indicates the result:
+ *      0 : Success.
+ *          data is a pointer to an exports pointer:
+ *          exports export = *(exports *)data;
+ * -errno : An error occured.
+ *          data is the error string.
+ */
+int mount_getexports_async(struct rpc_context *rpc, const char *server, rpc_cb cb, void *private_data);
+
+
 
 //qqq replace later with lseek(cur, 0)
 off_t nfs_get_current_offset(struct nfsfh *nfsfh);
index 40b6a8dc18a1c2bd5bec7dc7c0c2ca6f6c5e23e6..4b63a704ec9faf911bf5d1d407a7d61fd1bee240 100644 (file)
@@ -18,6 +18,7 @@
  * High level api to nfs filesystems
  */
 
+#define _GNU_SOURCE
 #include <stdio.h>
 #include <stdarg.h>
 #include <stdlib.h>
@@ -2871,3 +2872,166 @@ void nfs_set_error(struct nfs_context *nfs, char *error_string, ...)
        nfs->rpc->error_string = str;
         va_end(ap);
 }
+
+
+
+struct mount_cb_data {
+       rpc_cb cb;
+       void *private_data;
+       char *server;
+};
+
+static void free_mount_cb_data(struct mount_cb_data *data)
+{
+       if (data->server != NULL) {
+               free(data->server);
+               data->server = NULL;
+       }
+
+       free(data);
+}
+
+static void mount_export_5_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
+{
+       struct mount_cb_data *data = private_data;
+
+       if (status == RPC_STATUS_ERROR) {       
+               data->cb(rpc, -EFAULT, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+       if (status == RPC_STATUS_CANCEL) {
+               data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+
+       data->cb(rpc, 0, command_data, data->private_data);
+       if (rpc_disconnect(rpc, "normal disconnect") != 0) {
+               rpc_set_error(rpc, "Failed to disconnect\n");
+       }
+       free_mount_cb_data(data);
+}
+
+static void mount_export_4_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
+{
+       struct mount_cb_data *data = private_data;
+
+       if (status == RPC_STATUS_ERROR) {       
+               data->cb(rpc, -EFAULT, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+       if (status == RPC_STATUS_CANCEL) {
+               data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+
+       if (rpc_mount_export_async(rpc, mount_export_5_cb, data) != 0) {
+               data->cb(rpc, -ENOMEM, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+}
+
+static void mount_export_3_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
+{
+       struct mount_cb_data *data = private_data;
+       uint32_t mount_port;
+
+       if (status == RPC_STATUS_ERROR) {       
+               data->cb(rpc, -EFAULT, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+       if (status == RPC_STATUS_CANCEL) {
+               data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+
+       mount_port = *(uint32_t *)command_data;
+       if (mount_port == 0) {
+               rpc_set_error(rpc, "RPC error. Mount program is not available");
+               data->cb(rpc, -ENOENT, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+
+       rpc_disconnect(rpc, "normal disconnect");
+       if (rpc_connect_async(rpc, data->server, mount_port, mount_export_4_cb, data) != 0) {
+               data->cb(rpc, -ENOMEM, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+}
+
+static void mount_export_2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
+{
+       struct mount_cb_data *data = private_data;
+
+       if (status == RPC_STATUS_ERROR) {
+               data->cb(rpc, -EFAULT, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+       if (status == RPC_STATUS_CANCEL) {
+               data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+
+       if (rpc_pmap_getport_async(rpc, MOUNT_PROGRAM, MOUNT_V3, mount_export_3_cb, private_data) != 0) {
+               data->cb(rpc, -ENOMEM, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+}
+
+static void mount_export_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
+{
+       struct mount_cb_data *data = private_data;
+
+       if (status == RPC_STATUS_ERROR) {
+               data->cb(rpc, -EFAULT, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+       if (status == RPC_STATUS_CANCEL) {
+               data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+
+       if (rpc_pmap_null_async(rpc, mount_export_2_cb, data) != 0) {
+               data->cb(rpc, -ENOMEM, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+}
+
+int mount_getexports_async(struct rpc_context *rpc, const char *server, rpc_cb cb, void *private_data)
+{
+       struct mount_cb_data *data;
+
+       data = malloc(sizeof(struct mount_cb_data));
+       if (data == NULL) {
+               return -1;
+       }
+       bzero(data, sizeof(struct mount_cb_data));
+       data->cb           = cb;
+       data->private_data = private_data;
+       data->server       = strdup(server);
+       if (data->server == NULL) {
+               free_mount_cb_data(data);
+               return -1;
+       }       
+       if (rpc_connect_async(rpc, data->server, 111, mount_export_1_cb, data) != 0) {
+               free_mount_cb_data(data);
+               return -1;
+       }
+
+       return 0;
+}
+
index 15aacd8f2834de9a1a0754b1ed532fcd010b45a9..525c8526a5fd12e94e80da5d463c9b2e88105570 100644 (file)
@@ -190,3 +190,6 @@ int mountstat3_to_errno(int st)
        }
        return -ERANGE;
 }
+
+
+