/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#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>
/*
* str_to_utf8 - converts a null-terminated C string to a utf8 string
*/
utf8string *
str_to_utf8(char *nm, utf8string *str)
{
int len;
if (str == NULL)
return (NULL);
if (nm == NULL || *nm == '\0') {
str->utf8string_len = 0;
str->utf8string_val = NULL;
return (NULL);
}
len = strlen(nm);
str->utf8string_val = malloc(len);
if (str->utf8string_val == NULL) {
str->utf8string_len = 0;
return (NULL);
}
str->utf8string_len = len;
bcopy(nm, str->utf8string_val, len);
return (str);
}
/*
* Converts a utf8 string to a C string.
* kmem_allocs a new string if not supplied
*/
char *
utf8_to_str(utf8string *str, uint_t *lenp, char *s)
{
char *sp;
char *u8p;
int len;
int i;
if (str == NULL)
return (NULL);
u8p = str->utf8string_val;
len = str->utf8string_len;
if (len <= 0 || u8p == NULL) {
if (s)
*s = '\0';
return (NULL);
}
sp = s;
if (sp == NULL)
sp = malloc(len + 1);
if (sp == NULL)
return (NULL);
/*
* At least check for embedded nulls
*/
for (i = 0; i < len; i++) {
sp[i] = u8p[i];
if (u8p[i] == '\0') {
if (s == NULL)
free(sp);
return (NULL);
}
}
sp[len] = '\0';
*lenp = len + 1;
return (sp);
}
void
print_referral_summary(fs_locations4 *fsl)
{
int i, j;
uint_t l;
char *s;
fs_location4 *fs;
if (fsl == NULL) {
printf("NULL\n");
return;
}
for (i = 0; i < fsl->locations.locations_len; i++) {
if (i > 0)
printf("\n");
fs = &fsl->locations.locations_val[i];
for (j = 0; j < fs->server.server_len; j++) {
s = utf8_to_str(&fs->server.server_val[j], &l, NULL);
if (j > 0)
printf(",");
printf("%s", s ? s : "");
if (s)
free(s);
}
printf(":");
for (j = 0; j < fs->rootpath.pathname4_len; j++) {
s = utf8_to_str(&fs->rootpath.pathname4_val[j],
&l, NULL);
printf("/%s", s ? s : "");
if (s)
free(s);
}
if (fs->rootpath.pathname4_len == 0)
printf("/");
}
printf("\n");
}
/*
* There is a kernel copy of this routine in nfs4_srv.c.
* Changes should be kept in sync.
*/
static int
nfs4_create_components(char *path, component4 *comp4)
{
int slen, plen, ncomp;
char *ori_path, *nxtc, buf[MAXNAMELEN];
if (path == NULL)
return (0);
plen = strlen(path) + 1; /* include the terminator */
ori_path = path;
ncomp = 0;
/* count number of components in the path */
for (nxtc = path; nxtc < ori_path + plen; nxtc++) {
if (*nxtc == '/' || *nxtc == '\0' || *nxtc == '\n') {
if ((slen = nxtc - path) == 0) {
path = nxtc + 1;
continue;
}
if (comp4 != NULL) {
bcopy(path, buf, slen);
buf[slen] = '\0';
if (str_to_utf8(buf, &comp4[ncomp]) == NULL)
return (NULL);
}
ncomp++; /* 1 valid component */
path = nxtc + 1;
}
if (*nxtc == '\0' || *nxtc == '\n')
break;
}
return (ncomp);
}
/*
* There is a kernel copy of this routine in nfs4_srv.c.
* Changes should be kept in sync.
*/
int
make_pathname4(char *path, pathname4 *pathname)
{
int ncomp;
component4 *comp4;
if (pathname == NULL)
return (0);
if (path == NULL) {
pathname->pathname4_val = NULL;
pathname->pathname4_len = 0;
return (0);
}
/* count number of components to alloc buffer */
if ((ncomp = nfs4_create_components(path, NULL)) == 0) {
pathname->pathname4_val = NULL;
pathname->pathname4_len = 0;
return (0);
}
comp4 = calloc(ncomp * sizeof (component4), 1);
if (comp4 == NULL) {
pathname->pathname4_val = NULL;
pathname->pathname4_len = 0;
return (0);
}
/* copy components into allocated buffer */
ncomp = nfs4_create_components(path, comp4);
pathname->pathname4_val = comp4;
pathname->pathname4_len = ncomp;
return (ncomp);
}
bool_t
xdr_component4(register XDR *xdrs, component4 *objp)
{
if (!xdr_utf8string(xdrs, objp))
return (FALSE);
return (TRUE);
}
bool_t
xdr_utf8string(register XDR *xdrs, utf8string *objp)
{
if (xdrs->x_op != XDR_FREE)
return (xdr_bytes(xdrs, (char **)&objp->utf8string_val,
(uint_t *)&objp->utf8string_len, NFS4_MAX_UTF8STRING));
return (TRUE);
}
bool_t
xdr_pathname4(register XDR *xdrs, pathname4 *objp)
{
if (!xdr_array(xdrs, (char **)&objp->pathname4_val,
(uint_t *)&objp->pathname4_len, NFS4_MAX_PATHNAME4,
sizeof (component4), (xdrproc_t)xdr_component4))
return (FALSE);
return (TRUE);
}
bool_t
xdr_fs_location4(register XDR *xdrs, fs_location4 *objp)
{
if (xdrs->x_op == XDR_DECODE) {
objp->server.server_val = NULL;
objp->rootpath.pathname4_val = NULL;
}
if (!xdr_array(xdrs, (char **)&objp->server.server_val,
(uint_t *)&objp->server.server_len, ~0,
sizeof (utf8string), (xdrproc_t)xdr_utf8string))
return (FALSE);
if (!xdr_pathname4(xdrs, &objp->rootpath))
return (FALSE);
return (TRUE);
}
bool_t
xdr_fs_locations4(register XDR *xdrs, fs_locations4 *objp)
{
if (xdrs->x_op == XDR_DECODE) {
objp->fs_root.pathname4_len = 0;
objp->fs_root.pathname4_val = NULL;
objp->locations.locations_val = NULL;
}
if (!xdr_pathname4(xdrs, &objp->fs_root))
return (FALSE);
if (!xdr_array(xdrs, (char **)&objp->locations.locations_val,
(uint_t *)&objp->locations.locations_len, ~0,
sizeof (fs_location4), (xdrproc_t)xdr_fs_location4))
return (FALSE);
return (TRUE);
}