#include <stdio.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/errno.h>
#include <limits.h>
#include <libnvpair.h>
#include <dlfcn.h>
#include <link.h>
#include <rp_plugin.h>
#include <fcntl.h>
#include <uuid/uuid.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <rpc/auth.h>
#include <rpc/clnt.h>
#include <rpc/rpc_msg.h>
#include <sys/param.h>
#include <nfs/nfs4.h>
#include <rpcsvc/nfs4_prot.h>
#include "ref_subr.h"
extern int errno;
#define SERVICE_TYPE "nfs-basic"
char *nfs_basic_service_type(void);
boolean_t nfs_basic_supports_svc(const char *);
int nfs_basic_deref(const char *, const char *, char *, size_t *);
int nfs_basic_form(const char *, const char *, char *, size_t *);
struct rp_plugin_ops rp_plugin_ops = {
RP_PLUGIN_V1,
NULL,
NULL,
nfs_basic_service_type,
nfs_basic_supports_svc,
nfs_basic_form,
nfs_basic_deref
};
char *
nfs_basic_service_type()
{
return (SERVICE_TYPE);
}
boolean_t
nfs_basic_supports_svc(const char *svc_type)
{
if (!svc_type)
return (0);
return (!strncasecmp(svc_type, SERVICE_TYPE, strlen(SERVICE_TYPE)));
}
static fs_locations4 *
get_fs_locations(char *buf)
{
fs_locations4 *result = NULL;
fs_location4 *fsl_array;
int i, gothost;
int fsl_count = 0, escape = 0, delimiter = 0;
int len;
char *p, *sp, *dp, buf2[SYMLINK_MAX];
if (buf == NULL)
return (NULL);
#ifdef DEBUG
printf("get_fs_locations: input %s\n", buf);
#endif
for (sp = buf; sp && *sp; sp++) {
if (*sp == '\\') {
escape = 1;
delimiter = 0;
continue;
}
if (*sp == ' ') {
if (delimiter == 1)
continue;
if (escape == 0) {
delimiter = 1;
fsl_count++;
*sp = '\0';
} else
escape = 0;
} else
delimiter = 0;
}
len = sp - buf;
sp--;
if (escape == 0 && *sp != '\0')
fsl_count++;
#ifdef DEBUG
printf("get_fs_locations: fsl_count %d\n", fsl_count);
#endif
if (fsl_count == 0)
goto out;
result = calloc(1, sizeof (fs_locations4));
if (result == NULL)
goto out;
fsl_array = calloc(fsl_count, sizeof (fs_location4));
if (fsl_array == NULL) {
free(result);
result = NULL;
goto out;
}
result->locations.locations_len = fsl_count;
result->locations.locations_val = fsl_array;
result->fs_root.pathname4_len = 0;
result->fs_root.pathname4_val = NULL;
sp = buf;
dp = buf2;
bzero(buf2, sizeof (buf2));
i = gothost = 0;
while ((sp && *sp && (sp - buf < len)) || gothost) {
if (!gothost) {
if (*sp == ' ') {
sp++;
continue;
}
p = strrchr(sp, ':');
if (!p) {
#ifdef DEBUG
printf("get_fs_locations: skipping %s\n", sp);
#endif
fsl_count--;
sp += strlen(sp) + 1;
} else {
bcopy(sp, dp, p - sp);
sp = p + 1;
#ifdef DEBUG
printf("get_fs_locations: host %s\n", buf2);
#endif
fsl_array[i].server.server_len = 1;
fsl_array[i].server.server_val =
malloc(sizeof (utf8string));
if (fsl_array[i].server.server_val == NULL) {
int j;
free(result);
result = NULL;
for (j = 0; j < i; j++)
free(fsl_array[j].
server.server_val);
free(fsl_array);
goto out;
}
str_to_utf8(buf2,
fsl_array[i].server.server_val);
gothost = 1;
dp = buf2;
bzero(buf2, sizeof (buf2));
}
continue;
}
if (*sp == '\0' && gothost) {
#ifdef DEBUG
printf("get_fs_locations: path %s\n", buf2);
#endif
(void) make_pathname4(buf2, &fsl_array[i].rootpath);
i++;
gothost = 0;
dp = buf2;
bzero(buf2, sizeof (buf2));
if (sp - buf < len)
sp++;
continue;
}
if (*sp == '\\')
sp++;
*dp++ = *sp++;
}
if (gothost) {
fsl_count--;
free(fsl_array[i].server.server_val);
fsl_array[i].server.server_val = NULL;
fsl_array[i].server.server_len = 0;
}
if (fsl_count <= 0) {
free(result);
free(fsl_array);
return (NULL);
}
if (fsl_count < result->locations.locations_len)
result->locations.locations_len = fsl_count;
out:
return (result);
}
int
nfs_basic_deref(const char *svc_type, const char *svc_data, char *buf,
size_t *bufsz)
{
int slen, err;
fs_locations4 *fsl;
XDR xdr;
if ((!svc_type) || (!svc_data) || (!buf) || (!bufsz) || (*bufsz == 0))
return (EINVAL);
if (strcasecmp(svc_type, SERVICE_TYPE))
return (ENOTSUP);
fsl = get_fs_locations((char *)svc_data);
if (fsl == NULL)
return (ENOENT);
#ifdef DEBUG
printf("nfs_basic_deref: past get_fs_locations()\n");
#endif
slen = xdr_sizeof(xdr_fs_locations4, (void *)fsl);
if (slen > *bufsz) {
*bufsz = slen;
xdr_free(xdr_fs_locations4, (char *)fsl);
return (EOVERFLOW);
}
#ifdef DEBUG
printf("nfs_basic_deref: past buffer check\n");
print_referral_summary(fsl);
#endif
xdrmem_create(&xdr, buf, *bufsz, XDR_ENCODE);
err = xdr_fs_locations4(&xdr, fsl);
XDR_DESTROY(&xdr);
xdr_free(xdr_fs_locations4, (char *)fsl);
if (err != TRUE)
return (EINVAL);
*bufsz = slen;
#ifdef DEBUG
printf("nfs_basic_deref: past xdr_fs_locations4() and done\n");
#endif
return (0);
}
int
nfs_basic_form(const char *svc_type, const char *svc_data, char *buf,
size_t *bufsz)
{
int slen;
if ((!svc_type) || (!svc_data) || (!buf) || (*bufsz == 0))
return (EINVAL);
if (strcmp(svc_type, SERVICE_TYPE))
return (ENOTSUP);
slen = strlen(svc_data) + 1;
if (slen > *bufsz) {
*bufsz = slen;
return (EOVERFLOW);
}
*bufsz = slen;
strncpy(buf, svc_data, slen);
return (0);
}