From: Ronnie Sahlberg Date: Sun, 19 Jun 2011 04:54:17 +0000 (+1000) Subject: Add a high-level async function to read the export list X-Git-Tag: upstream/1.9.6^2~396 X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=7f0242ca9a109c6825646609b8eda0ce0b866b67;p=deb_libnfs.git Add a high-level async function to read the export list --- diff --git a/examples/nfsclient-async.c b/examples/nfsclient-async.c index b630f4e..d8420e1 100644 --- a/examples/nfsclient-async.c +++ b/examples/nfsclient-async.c @@ -32,6 +32,10 @@ #include #include #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; } diff --git a/include/libnfs-raw.h b/include/libnfs-raw.h index c1eb00d..bd23dc1 100644 --- a/include/libnfs-raw.h +++ b/include/libnfs-raw.h @@ -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. diff --git a/include/libnfs.h b/include/libnfs.h index e95cdbe..bbca07e 100644 --- a/include/libnfs.h +++ b/include/libnfs.h @@ -20,6 +20,7 @@ #include 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); diff --git a/lib/libnfs.c b/lib/libnfs.c index 40b6a8d..4b63a70 100644 --- a/lib/libnfs.c +++ b/lib/libnfs.c @@ -18,6 +18,7 @@ * High level api to nfs filesystems */ +#define _GNU_SOURCE #include #include #include @@ -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; +} + diff --git a/mount/mount.c b/mount/mount.c index 15aacd8..525c852 100644 --- a/mount/mount.c +++ b/mount/mount.c @@ -190,3 +190,6 @@ int mountstat3_to_errno(int st) } return -ERANGE; } + + +