X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=lib%2Flibnfs.c;h=9053ab1884992ff7b01287d8c5ac655c90e4fc6e;hb=54bafab240be2a172ce8075fd25497a149bdf77c;hp=285e6dc2e42327252478f0d8f26c05a20a44baa7;hpb=2aec85d1329bba793140c8937c319df65b8144da;p=deb_libnfs.git diff --git a/lib/libnfs.c b/lib/libnfs.c index 285e6dc..9053ab1 100644 --- a/lib/libnfs.c +++ b/lib/libnfs.c @@ -73,6 +73,7 @@ #include "libnfs-raw.h" #include "libnfs-raw-mount.h" #include "libnfs-raw-nfs.h" +#include "libnfs-raw-portmap.h" #include "libnfs-private.h" struct nfsdir { @@ -394,6 +395,30 @@ void free_rpc_cb_data(struct rpc_cb_data *data) free(data); } +static void rpc_connect_program_5_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) +{ + struct rpc_cb_data *data = private_data; + + assert(rpc->magic == RPC_CONTEXT_MAGIC); + + /* Dont want any more callbacks even if the socket is closed */ + rpc->connect_cb = NULL; + + if (status == RPC_STATUS_ERROR) { + data->cb(rpc, status, command_data, data->private_data); + free_rpc_cb_data(data); + return; + } + if (status == RPC_STATUS_CANCEL) { + data->cb(rpc, status, "Command was cancelled", data->private_data); + free_rpc_cb_data(data); + return; + } + + data->cb(rpc, status, NULL, data->private_data); + free_rpc_cb_data(data); +} + static void rpc_connect_program_4_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { struct rpc_cb_data *data = private_data; @@ -414,6 +439,25 @@ static void rpc_connect_program_4_cb(struct rpc_context *rpc, int status, void * return; } + switch (data->program) { + case MOUNT_PROGRAM: + if (rpc_mount3_null_async(rpc, rpc_connect_program_5_cb, + data) != 0) { + data->cb(rpc, status, command_data, data->private_data); + free_rpc_cb_data(data); + return; + } + return; + case NFS_PROGRAM: + if (rpc_nfs3_null_async(rpc, rpc_connect_program_5_cb, + data) != 0) { + data->cb(rpc, status, command_data, data->private_data); + free_rpc_cb_data(data); + return; + } + return; + } + data->cb(rpc, status, NULL, data->private_data); free_rpc_cb_data(data); } @@ -421,7 +465,9 @@ static void rpc_connect_program_4_cb(struct rpc_context *rpc, int status, void * static void rpc_connect_program_3_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { struct rpc_cb_data *data = private_data; - uint32_t rpc_port; + struct pmap3_string_result *gar; + uint32_t rpc_port = 0; + unsigned char *ptr; assert(rpc->magic == RPC_CONTEXT_MAGIC); @@ -436,7 +482,29 @@ static void rpc_connect_program_3_cb(struct rpc_context *rpc, int status, void * return; } - rpc_port = *(uint32_t *)command_data; + switch (rpc->s.ss_family) { + case AF_INET: + rpc_port = *(uint32_t *)command_data; + break; + case AF_INET6: + /* ouch. portmapper and ipv6 are not great */ + gar = command_data; + if (gar->addr == NULL) { + break; + } + ptr = strrchr(gar->addr, '.'); + if (ptr == NULL) { + break; + } + rpc_port = atoi(ptr + 1); + *ptr = 0; + ptr = strrchr(gar->addr, '.'); + if (ptr == NULL) { + break; + } + rpc_port += 256 * atoi(ptr + 1); + break; + } if (rpc_port == 0) { rpc_set_error(rpc, "RPC error. Program is not available on %s", data->server); data->cb(rpc, RPC_STATUS_ERROR, rpc_get_error(rpc), data->private_data); @@ -455,6 +523,7 @@ static void rpc_connect_program_3_cb(struct rpc_context *rpc, int status, void * static void rpc_connect_program_2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { struct rpc_cb_data *data = private_data; + struct pmap3_mapping map; assert(rpc->magic == RPC_CONTEXT_MAGIC); @@ -469,10 +538,26 @@ static void rpc_connect_program_2_cb(struct rpc_context *rpc, int status, void * return; } - if (rpc_pmap_getport_async(rpc, data->program, data->version, IPPROTO_TCP, rpc_connect_program_3_cb, private_data) != 0) { - data->cb(rpc, status, command_data, data->private_data); - free_rpc_cb_data(data); - return; + switch (rpc->s.ss_family) { + case AF_INET: + if (rpc_pmap2_getport_async(rpc, data->program, data->version, IPPROTO_TCP, rpc_connect_program_3_cb, private_data) != 0) { + data->cb(rpc, status, command_data, data->private_data); + free_rpc_cb_data(data); + return; + } + break; + case AF_INET6: + map.prog=data->program; + map.vers=data->version; + map.netid=""; + map.addr=""; + map.owner=""; + if (rpc_pmap3_getaddr_async(rpc, &map, rpc_connect_program_3_cb, private_data) != 0) { + data->cb(rpc, status, command_data, data->private_data); + free_rpc_cb_data(data); + return; + } + break; } } @@ -496,14 +581,25 @@ static void rpc_connect_program_1_cb(struct rpc_context *rpc, int status, void * return; } - if (rpc_pmap_null_async(rpc, rpc_connect_program_2_cb, data) != 0) { - data->cb(rpc, status, command_data, data->private_data); - free_rpc_cb_data(data); - return; + switch (rpc->s.ss_family) { + case AF_INET: + if (rpc_pmap2_null_async(rpc, rpc_connect_program_2_cb, data) != 0) { + data->cb(rpc, status, command_data, data->private_data); + free_rpc_cb_data(data); + return; + } + break; + case AF_INET6: + if (rpc_pmap3_null_async(rpc, rpc_connect_program_2_cb, data) != 0) { + data->cb(rpc, status, command_data, data->private_data); + free_rpc_cb_data(data); + return; + } + break; } } -int rpc_connect_program_async(struct rpc_context *rpc, char *server, int program, int version, rpc_cb cb, void *private_data) +int rpc_connect_program_async(struct rpc_context *rpc, const char *server, int program, int version, rpc_cb cb, void *private_data) { struct rpc_cb_data *data; @@ -627,36 +723,6 @@ static void nfs_mount_8_cb(struct rpc_context *rpc, int status, void *command_da } } - -static void nfs_mount_7_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) -{ - struct nfs_cb_data *data = private_data; - struct nfs_context *nfs = data->nfs; - - assert(rpc->magic == RPC_CONTEXT_MAGIC); - - /* Dont want any more callbacks even if the socket is closed */ - rpc->connect_cb = NULL; - - if (status == RPC_STATUS_ERROR) { - data->cb(-EFAULT, nfs, command_data, data->private_data); - free_nfs_cb_data(data); - return; - } - if (status == RPC_STATUS_CANCEL) { - data->cb(-EINTR, nfs, "Command was cancelled", data->private_data); - free_nfs_cb_data(data); - return; - } - - if (rpc_nfs3_null_async(rpc, nfs_mount_8_cb, data) != 0) { - data->cb(-ENOMEM, nfs, command_data, data->private_data); - free_nfs_cb_data(data); - return; - } -} - - static void nfs_mount_6_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { struct nfs_cb_data *data = private_data; @@ -695,11 +761,13 @@ static void nfs_mount_6_cb(struct rpc_context *rpc, int status, void *command_da memcpy(nfs->rootfh.data.data_val, res->mountres3_u.mountinfo.fhandle.fhandle3_val, nfs->rootfh.data.data_len); rpc_disconnect(rpc, "normal disconnect"); - if (rpc_connect_async(rpc, nfs->server, 2049, nfs_mount_7_cb, data) != 0) { + + if (rpc_connect_program_async(nfs->rpc, nfs->server, NFS_PROGRAM, NFS_V3, nfs_mount_8_cb, data) != 0) { data->cb(-ENOMEM, nfs, command_data, data->private_data); free_nfs_cb_data(data); return; } + /* NFS TCP connections we want to autoreconnect after sessions are torn down (due to inactivity or error) */ rpc_set_autoreconnect(rpc); } @@ -730,123 +798,6 @@ static void nfs_mount_5_cb(struct rpc_context *rpc, int status, void *command_da } } -static void nfs_mount_4_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) -{ - struct nfs_cb_data *data = private_data; - struct nfs_context *nfs = data->nfs; - - assert(rpc->magic == RPC_CONTEXT_MAGIC); - - /* Dont want any more callbacks even if the socket is closed */ - rpc->connect_cb = NULL; - - if (status == RPC_STATUS_ERROR) { - data->cb(-EFAULT, nfs, command_data, data->private_data); - free_nfs_cb_data(data); - return; - } - if (status == RPC_STATUS_CANCEL) { - data->cb(-EINTR, nfs, "Command was cancelled", data->private_data); - free_nfs_cb_data(data); - return; - } - - if (rpc_mount3_null_async(rpc, nfs_mount_5_cb, data) != 0) { - data->cb(-ENOMEM, nfs, command_data, data->private_data); - free_nfs_cb_data(data); - return; - } -} - -static void nfs_mount_3_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) -{ - struct nfs_cb_data *data = private_data; - struct nfs_context *nfs = data->nfs; - uint32_t mount_port; - - assert(rpc->magic == RPC_CONTEXT_MAGIC); - - if (status == RPC_STATUS_ERROR) { - data->cb(-EFAULT, nfs, command_data, data->private_data); - free_nfs_cb_data(data); - return; - } - if (status == RPC_STATUS_CANCEL) { - data->cb(-EINTR, nfs, "Command was cancelled", data->private_data); - free_nfs_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 on %s", nfs->server); - data->cb(-ENOENT, nfs, command_data, data->private_data); - free_nfs_cb_data(data); - return; - } - - rpc_disconnect(rpc, "normal disconnect"); - if (rpc_connect_async(rpc, nfs->server, mount_port, nfs_mount_4_cb, data) != 0) { - data->cb(-ENOMEM, nfs, command_data, data->private_data); - free_nfs_cb_data(data); - return; - } -} - - -static void nfs_mount_2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) -{ - struct nfs_cb_data *data = private_data; - struct nfs_context *nfs = data->nfs; - - assert(rpc->magic == RPC_CONTEXT_MAGIC); - - if (status == RPC_STATUS_ERROR) { - data->cb(-EFAULT, nfs, command_data, data->private_data); - free_nfs_cb_data(data); - return; - } - if (status == RPC_STATUS_CANCEL) { - data->cb(-EINTR, nfs, "Command was cancelled", data->private_data); - free_nfs_cb_data(data); - return; - } - - if (rpc_pmap_getport_async(rpc, MOUNT_PROGRAM, MOUNT_V3, IPPROTO_TCP, nfs_mount_3_cb, private_data) != 0) { - data->cb(-ENOMEM, nfs, command_data, data->private_data); - free_nfs_cb_data(data); - return; - } -} - -static void nfs_mount_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) -{ - struct nfs_cb_data *data = private_data; - struct nfs_context *nfs = data->nfs; - - assert(rpc->magic == RPC_CONTEXT_MAGIC); - - /* Dont want any more callbacks even if the socket is closed */ - rpc->connect_cb = NULL; - - if (status == RPC_STATUS_ERROR) { - data->cb(-EFAULT, nfs, command_data, data->private_data); - free_nfs_cb_data(data); - return; - } - if (status == RPC_STATUS_CANCEL) { - data->cb(-EINTR, nfs, "Command was cancelled", data->private_data); - free_nfs_cb_data(data); - return; - } - - if (rpc_pmap_null_async(rpc, nfs_mount_2_cb, data) != 0) { - data->cb(-ENOMEM, nfs, command_data, data->private_data); - free_nfs_cb_data(data); - return; - } -} - /* * Async call for mounting an nfs share and geting the root filehandle */ @@ -875,7 +826,7 @@ int nfs_mount_async(struct nfs_context *nfs, const char *server, const char *exp data->cb = cb; data->private_data = private_data; - if (rpc_connect_async(nfs->rpc, server, 111, nfs_mount_1_cb, data) != 0) { + if (rpc_connect_program_async(nfs->rpc, server, MOUNT_PROGRAM, MOUNT_V3, nfs_mount_5_cb, data) != 0) { rpc_set_error(nfs->rpc, "Failed to start connection"); free_nfs_cb_data(data); return -1; @@ -1043,7 +994,7 @@ static int nfs_normalize_path(struct nfs_context *nfs, char *path) /* /$ -> \0 */ len = strlen(path); - if (len >= 1) { + if (len > 1) { if (path[len - 1] == '/') { path[len - 1] = '\0'; len--; @@ -1664,8 +1615,7 @@ int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offse assert(data->num_calls == 0); - /* trying to read more than maximum server read size, we has to chop it up into smaller - * reads and collect into a reassembly buffer. + /* chop requests into chunks of at most READMAX bytes if necessary. * we send all reads in parallel so that performance is still good. */ data->max_offset = offset; @@ -1688,6 +1638,7 @@ int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offse return -1; } data->oom = 1; + break; } memset(mdata, 0, sizeof(struct nfs_mcb_data)); mdata->data = data; @@ -1704,6 +1655,7 @@ int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offse return -1; } data->oom = 1; + break; } count -= readcount; @@ -1843,8 +1795,7 @@ int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offs /* hello, clang-analyzer */ assert(data->num_calls == 0); - /* trying to write more than maximum server write size, we has to chop it up into smaller - * chunks. + /* chop requests into chunks of at most WRITEMAX bytes if necessary. * we send all writes in parallel so that performance is still good. */ data->max_offset = offset; @@ -1867,6 +1818,7 @@ int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offs return -1; } data->oom = 1; + break; } memset(mdata, 0, sizeof(struct nfs_mcb_data)); mdata->data = data; @@ -1883,6 +1835,7 @@ int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offs return -1; } data->oom = 1; + break; } count -= writecount; @@ -2841,46 +2794,48 @@ static void nfs_opendir2_cb(struct rpc_context *rpc, int status, void *command_d /* steal the dirhandle */ nfsdir->current = nfsdir->entries; - rdpe_cb_data = malloc(sizeof(struct rdpe_cb_data)); - rdpe_cb_data->getattrcount = 0; - rdpe_cb_data->status = RPC_STATUS_SUCCESS; - rdpe_cb_data->data = data; - for (nfsdirent = nfsdir->entries; nfsdirent; nfsdirent = nfsdirent->next) { - struct rdpe_lookup_cb_data *rdpe_lookup_cb_data; - LOOKUP3args args; - - rdpe_lookup_cb_data = malloc(sizeof(struct rdpe_lookup_cb_data)); - rdpe_lookup_cb_data->rdpe_cb_data = rdpe_cb_data; - rdpe_lookup_cb_data->nfsdirent = nfsdirent; - - memset(&args, 0, sizeof(LOOKUP3args)); - args.what.dir = data->fh; - args.what.name = nfsdirent->name; - - if (rpc_nfs3_lookup_async(nfs->rpc, nfs_opendir3_cb, &args, rdpe_lookup_cb_data) != 0) { - rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIR LOOKUP call"); - - /* if we have already commands in flight, we cant just stop, we have to wait for the - * commands in flight to complete - */ - if (rdpe_cb_data->getattrcount > 0) { + if (nfsdir->entries) { + rdpe_cb_data = malloc(sizeof(struct rdpe_cb_data)); + rdpe_cb_data->getattrcount = 0; + rdpe_cb_data->status = RPC_STATUS_SUCCESS; + rdpe_cb_data->data = data; + for (nfsdirent = nfsdir->entries; nfsdirent; nfsdirent = nfsdirent->next) { + struct rdpe_lookup_cb_data *rdpe_lookup_cb_data; + LOOKUP3args args; + + rdpe_lookup_cb_data = malloc(sizeof(struct rdpe_lookup_cb_data)); + rdpe_lookup_cb_data->rdpe_cb_data = rdpe_cb_data; + rdpe_lookup_cb_data->nfsdirent = nfsdirent; + + memset(&args, 0, sizeof(LOOKUP3args)); + args.what.dir = data->fh; + args.what.name = nfsdirent->name; + + if (rpc_nfs3_lookup_async(nfs->rpc, nfs_opendir3_cb, &args, rdpe_lookup_cb_data) != 0) { + rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIR LOOKUP call"); + + /* if we have already commands in flight, we cant just stop, we have to wait for the + * commands in flight to complete + */ + if (rdpe_cb_data->getattrcount > 0) { + nfs_free_nfsdir(nfsdir); + data->continue_data = NULL; + free_nfs_cb_data(data); + rdpe_cb_data->status = RPC_STATUS_ERROR; + free(rdpe_lookup_cb_data); + return; + } + + data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); nfs_free_nfsdir(nfsdir); data->continue_data = NULL; free_nfs_cb_data(data); - rdpe_cb_data->status = RPC_STATUS_ERROR; free(rdpe_lookup_cb_data); + free(rdpe_cb_data); return; } - - data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); - nfs_free_nfsdir(nfsdir); - data->continue_data = NULL; - free_nfs_cb_data(data); - free(rdpe_lookup_cb_data); - free(rdpe_cb_data); - return; + rdpe_cb_data->getattrcount++; } - rdpe_cb_data->getattrcount++; } } @@ -4315,91 +4270,6 @@ static void mount_export_4_cb(struct rpc_context *rpc, int status, void *command } } -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; - - assert(rpc->magic == RPC_CONTEXT_MAGIC); - - 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; - - assert(rpc->magic == RPC_CONTEXT_MAGIC); - - 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, IPPROTO_TCP, 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; - - assert(rpc->magic == RPC_CONTEXT_MAGIC); - - /* Dont want any more callbacks even if the socket is closed */ - rpc->connect_cb = NULL; - - 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; @@ -4418,7 +4288,8 @@ int mount_getexports_async(struct rpc_context *rpc, const char *server, rpc_cb c free_mount_cb_data(data); return -1; } - if (rpc_connect_async(rpc, data->server, 111, mount_export_1_cb, data) != 0) { + if (rpc_connect_program_async(rpc, data->server, MOUNT_PROGRAM, MOUNT_V3, mount_export_4_cb, data) != 0) { + rpc_set_error(rpc, "Failed to start connection"); free_mount_cb_data(data); return -1; }