#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;
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;
}
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)
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;
}
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;
}
}
nfs_destroy_context(nfs);
+ if (mount_context != NULL) {
+ rpc_destroy_context(mount_context);
+ mount_context = NULL;
+ }
printf("nfsclient finished\n");
return 0;
}
#include <stdint.h>
struct nfs_context;
+struct rpc_context;
/*
* Used for interfacing the async version of the api into an external eventsystem
*/
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);
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);
* High level api to nfs filesystems
*/
+#define _GNU_SOURCE
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
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;
+}
+