view src/common/fscall.c @ 800:f679541c8142

switch to new buffer_init_static libjeffpc API The function gained a second size argument removing the need for some truncate calls. Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
date Fri, 03 Apr 2020 15:54:51 -0400
parents e1086d53181a
children 171787b0bc06
line wrap: on
line source

/*
 * Copyright (c) 2016-2020 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
 * Copyright (c) 2016 Steve Dougherty
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include <jeffpc/sock.h>
#include <jeffpc/io.h>

#include <nomad/rpc_fs.h>
#include <nomad/fscall.h>

static int __fscall_req(int fd, uint32_t opcode,
			int (*xmit)(XDR *, void *),
			void *req)
{
	struct rpc_header_req header;
	struct buffer rpc_buffer;
	char _rpc_buffer[1024];
	XDR xdr;
	int ret;

	header.opcode = opcode;

	buffer_init_static(&rpc_buffer, _rpc_buffer, 0, sizeof(_rpc_buffer),
			   true);

	xdrfd_create(&xdr, fd, &rpc_buffer, XDR_ENCODE);

	ret = NERR_RPC_ERROR;

	/* send generic RPC header */
	if (!xdr_rpc_header_req(&xdr, &header))
		goto err;

	if (xmit && !xmit(&xdr, req))
		goto err;

	ret = 0;

err:
	xdr_destroy(&xdr);

	return ret;
}

static int __fscall_res(int fd,
			int (*xmit)(XDR *, void *),
			void *res, size_t ressize)
{
	struct rpc_header_res header;
	XDR xdr;
	int ret;

	if (res)
		memset(res, 0, ressize);

	xdrfd_create(&xdr, fd, NULL, XDR_DECODE);

	ret = NERR_RPC_ERROR;

	if (!xdr_rpc_header_res(&xdr, &header))
		goto err;

	ret = header.err;
	if (ret)
		goto err;

	if (xmit && !xmit(&xdr, res))
		ret = NERR_RPC_ERROR;
	else
		ret = 0;

err:
	xdr_destroy(&xdr);

	return ret;
}

static int __fscall(int fd, uint32_t opcode,
		    int (*reqxmit)(XDR *, void *),
		    int (*resxmit)(XDR *, void *),
		    void *req, void *res,
		    size_t ressize)
{
	int ret;

	ret = __fscall_req(fd, opcode, reqxmit, req);
	if (ret)
		return ret;

	return __fscall_res(fd, resxmit, res, ressize);
}

int fscall_login(struct fscall_state *state, const char *conn,
		 const struct xuuid *volid)
{
	struct rpc_login_req login_req;
	struct rpc_login_res login_res;
	int ret;

	login_req.conn = (char *) conn;
	login_req.volid = *volid;

	ret = __fscall(state->sock, NRPC_LOGIN,
		       (void *) xdr_rpc_login_req,
		       (void *) xdr_rpc_login_res,
		       &login_req,
		       &login_res,
		       sizeof(login_res));
	if (ret)
		return ret;

	state->root_oid = login_res.root;

	return 0;
}

int fscall_open(struct fscall_state *state, const struct noid *oid,
		uint64_t ino, uint32_t *handle)
{
	struct rpc_open_req open_req;
	struct rpc_open_res open_res;
	int ret;

	/* only one of oid and ino is allowed */
	if ((oid && !noid_is_null(oid) && ino) ||
	    ((!oid || noid_is_null(oid)) && !ino))
		return -EINVAL;

	if (oid)
		open_req.oid = *oid;
	else
		memset(&open_req.oid, 0, sizeof(open_req.oid));

	open_req.ino = ino;
	memset(&open_req.clock, 0, sizeof(open_req.clock));

	ret = __fscall(state->sock, NRPC_OPEN,
		       (void *) xdr_rpc_open_req,
		       (void *) xdr_rpc_open_res,
		       &open_req,
		       &open_res,
		       sizeof(open_res));
	if (ret)
		return ret;

	*handle = open_res.handle;

	return 0;
}

int fscall_close(struct fscall_state *state, const uint32_t handle)
{
	struct rpc_close_req close_req;

	close_req.handle = handle;

	return __fscall(state->sock, NRPC_CLOSE,
			(void *) xdr_rpc_close_req,
			NULL,
			&close_req,
			NULL,
			0);
}

int fscall_getattr(struct fscall_state *state, const uint32_t handle,
		   struct nattr *attr)
{
	struct rpc_getattr_req getattr_req;
	struct rpc_getattr_res getattr_res;
	int ret;

	getattr_req.handle = handle;

	ret = __fscall(state->sock, NRPC_GETATTR,
		       (void *) xdr_rpc_getattr_req,
		       (void *) xdr_rpc_getattr_res,
		       &getattr_req,
		       &getattr_res,
		       sizeof(getattr_res));
	if (ret)
		return ret;

	*attr = getattr_res.attr;

	return 0;
}

int fscall_setattr(struct fscall_state *state, const uint32_t handle,
		   struct nattr *attr, bool mode_is_valid,
		   bool size_is_valid, bool atime_is_valid,
		   bool btime_is_valid, bool ctime_is_valid,
		   bool mtime_is_valid, bool owner_is_valid,
		   bool group_is_valid)
{
	struct rpc_setattr_req setattr_req;
	struct rpc_setattr_res setattr_res;
	int ret;

	setattr_req.handle = handle;
	setattr_req.attr = *attr;
	setattr_req.mode_is_valid = mode_is_valid;
	setattr_req.size_is_valid = size_is_valid;
	setattr_req.atime_is_valid = atime_is_valid;
	setattr_req.btime_is_valid = btime_is_valid;
	setattr_req.ctime_is_valid = ctime_is_valid;
	setattr_req.mtime_is_valid = mtime_is_valid;
	setattr_req.owner_is_valid = owner_is_valid;
	setattr_req.group_is_valid = group_is_valid;

	ret = __fscall(state->sock, NRPC_SETATTR,
		       (void *) xdr_rpc_setattr_req,
		       (void *) xdr_rpc_setattr_res,
		       &setattr_req,
		       &setattr_res,
		       sizeof(setattr_res));
	if (ret)
		return ret;

	*attr = setattr_res.attr;

	return 0;
}

int fscall_lookup(struct fscall_state *state, const uint32_t parent_handle,
		  const char *name, struct noid *child)
{
	struct rpc_lookup_req lookup_req;
	struct rpc_lookup_res lookup_res;
	int ret;

	lookup_req.parent = parent_handle;
	memset(&lookup_req.desired, 0, sizeof(struct noid));
	lookup_req.path = (char *) name;

	ret = __fscall(state->sock, NRPC_LOOKUP,
		       (void *) xdr_rpc_lookup_req,
		       (void *) xdr_rpc_lookup_res,
		       &lookup_req,
		       &lookup_res,
		       sizeof(lookup_res));
	if (ret)
		return ret;

	*child = lookup_res.child;

	return 0;
}

int fscall_create(struct fscall_state *state, const uint32_t parent_handle,
		  const char *name, const uint32_t owner, const uint32_t group,
		  const uint16_t mode, struct noid *child)
{
	struct rpc_create_req create_req;
	struct rpc_create_res create_res;
	int ret;

	create_req.parent = parent_handle;
	create_req.path = (char *) name;
	create_req.owner = owner;
	create_req.group = group;
	create_req.mode = mode;

	ret = __fscall(state->sock, NRPC_CREATE,
		       (void *) xdr_rpc_create_req,
		       (void *) xdr_rpc_create_res,
		       &create_req,
		       &create_res,
		       sizeof(create_res));
	if (ret)
		return ret;

	*child = create_res.oid;

	return 0;
}

int fscall_unlink(struct fscall_state *state, const uint32_t parent_handle,
		  const char *name, const struct noid *desired)

{
	struct rpc_unlink_req unlink_req;
	int ret;

	unlink_req.parent = parent_handle;
	unlink_req.path = (char *) name;

	if (desired)
		unlink_req.desired = *desired;
	else
		memset(&unlink_req.desired, 0, sizeof(unlink_req.desired));

	ret = __fscall(state->sock, NRPC_UNLINK,
		       (void *) xdr_rpc_unlink_req,
		       NULL,
		       &unlink_req,
		       NULL,
		       0);
	if (ret)
		return ret;

	return 0;
}

int fscall_read(struct fscall_state *state, const uint32_t handle,
		void *buf, size_t len, uint64_t off)
{
	struct rpc_read_req read_req;
	struct rpc_read_res read_res;
	int ret;

	/* TODO: check for length being too much? */

	read_req.handle = handle;
	read_req.offset = off;
	read_req.length = len;

	ret = __fscall(state->sock, NRPC_READ,
		       (void *) xdr_rpc_read_req,
		       (void *) xdr_rpc_read_res,
		       &read_req,
		       &read_res,
		       sizeof(read_res));
	if (ret)
		return ret;

	FIXME("NRPC_READ may return length != the requested length");
	memcpy(buf, read_res.data.data_val, read_res.data.data_len);

	free(read_res.data.data_val);

	return 0;
}

int fscall_write(struct fscall_state *state, const uint32_t handle,
		 const void *buf, size_t len, uint64_t off)
{
	struct rpc_write_req write_req;

	/* TODO: check for length being too much? */

	write_req.handle = handle;
	write_req.offset = off;
	write_req.data.data_len = len;
	write_req.data.data_val = (void *) buf;

	return __fscall(state->sock, NRPC_WRITE,
			(void *) xdr_rpc_write_req,
			NULL,
			&write_req,
			NULL,
			0);
}

int fscall_getdent(struct fscall_state *state, const uint32_t handle,
		   const uint64_t off, struct ndirent *child)
{
	struct rpc_getdent_req getdent_req;
	struct rpc_getdent_res getdent_res;
	int ret;

	getdent_req.parent = handle;
	getdent_req.offset = off;

	ret = __fscall(state->sock, NRPC_GETDENT,
		       (void *) xdr_rpc_getdent_req,
		       (void *) xdr_rpc_getdent_res,
		       &getdent_req,
		       &getdent_res,
		       sizeof(getdent_res));
	if (ret)
		return ret;

	*child = getdent_res.ent;

	return 0;
}

int fscall_obj_info(struct fscall_state *state, const struct noid *oid,
		    struct obj_info **infos, size_t *ninfos)
{
	struct rpc_obj_info_req obj_info_req;
	struct rpc_obj_info_res obj_info_res;
	int ret;

	obj_info_req.oid = *oid;

	ret = __fscall(state->sock, NRPC_OBJ_INFO,
		       (void *) xdr_rpc_obj_info_req,
		       (void *) xdr_rpc_obj_info_res,
		       &obj_info_req,
		       &obj_info_res,
		       sizeof(obj_info_res));
	if (ret)
		return ret;

	/* steal the length & value */
	*ninfos = obj_info_res.info.info_len;
	*infos = obj_info_res.info.info_val;

	return 0;
}

int fscall_vdev_import(struct fscall_state *state, const char *type,
		       const char *path, bool create,
		       struct xuuid *uuid)
{
	struct rpc_vdev_import_req vdev_import_req;
	struct rpc_vdev_import_res vdev_import_res;
	int ret;

	vdev_import_req.type = (char *) type;
	vdev_import_req.path = (char *) path;
	vdev_import_req.create = create;

	ret = __fscall(state->sock, NRPC_VDEV_IMPORT,
		       (void *) xdr_rpc_vdev_import_req,
		       (void *) xdr_rpc_vdev_import_res,
		       &vdev_import_req,
		       &vdev_import_res,
		       sizeof(vdev_import_res));
	if (ret)
		return ret;

	*uuid = vdev_import_res.uuid;

	return 0;
}

int fscall_vdev_list(struct fscall_state *state, struct vdev_info **vdevs,
		     size_t *nvdevs)
{
	struct rpc_vdev_list_res list_res;
	int ret;

	ret = __fscall(state->sock, NRPC_VDEV_LIST,
		       NULL,
		       (void *) xdr_rpc_vdev_list_res,
		       NULL,
		       &list_res,
		       sizeof(list_res));
	if (ret)
		return ret;

	/* steal the length & value */
	*nvdevs = list_res.vdevs.vdevs_len;
	*vdevs = list_res.vdevs.vdevs_val;

	return 0;
}

int fscall_vol_clone(struct fscall_state *state, const struct xuuid *vdevid,
		     const struct xuuid *volid)
{
	struct rpc_vol_create_req vol_create_req;
	struct rpc_vol_create_res vol_create_res;

	vol_create_req.vdevid = *vdevid;
	vol_create_req.volid = *volid;

	return __fscall(state->sock, NRPC_VOL_CREATE,
			(void *) xdr_rpc_vol_create_req,
			(void *) xdr_rpc_vol_create_res,
			&vol_create_req,
			&vol_create_res,
			sizeof(vol_create_res));
}

int fscall_vol_create(struct fscall_state *state, const struct xuuid *vdevid,
		      struct xuuid *volid)
{
	struct rpc_vol_create_req vol_create_req;
	struct rpc_vol_create_res vol_create_res;
	int ret;

	vol_create_req.vdevid = *vdevid;
	vol_create_req.volid = xuuid_null_uuid;

	ret = __fscall(state->sock, NRPC_VOL_CREATE,
		       (void *) xdr_rpc_vol_create_req,
		       (void *) xdr_rpc_vol_create_res,
		       &vol_create_req,
		       &vol_create_res,
		       sizeof(vol_create_res));
	if (ret)
		return ret;

	*volid = vol_create_res.volid;

	return 0;
}

int fscall_vol_list(struct fscall_state *state, const struct xuuid *vdevid,
		    struct vol_info **vols, size_t *nvols)
{
	struct rpc_vol_list_req list_req;
	struct rpc_vol_list_res list_res;
	int ret;

	list_req.vdevid = vdevid ? *vdevid : xuuid_null_uuid;

	ret = __fscall(state->sock, NRPC_VOL_LIST,
		       (void *) xdr_rpc_vol_list_req,
		       (void *) xdr_rpc_vol_list_res,
		       &list_req,
		       &list_res,
		       sizeof(list_res));
	if (ret)
		return ret;

	/* steal the length & value */
	*nvols = list_res.vols.vols_len;
	*vols = list_res.vols.vols_val;

	return 0;
}

static int __fscall_handshake(int fd)
{
	struct rpc_handshake_req request;
	XDR xdr;
	int ret;

	request.vers = NRPC_VERSION;

	xdrfd_create(&xdr, fd, NULL, XDR_ENCODE);

	ret = NERR_RPC_ERROR;

	if (!xdr_rpc_handshake_req(&xdr, &request))
		goto err;

	ret = __fscall_res(fd, NULL, NULL, 0);

err:
	xdr_destroy(&xdr);

	return ret;
}

int fscall_connect(struct fscall_state *state, int fd)
{
	int ret;

	ret = __fscall_handshake(fd);
	if (ret)
		return ret;

	state->sock = fd;

	return 0;
}

void fscall_disconnect(struct fscall_state *state)
{
	xclose(state->sock);
}

int fscall_mount(struct fscall_state *state, const struct xuuid *volid)
{
	int ret;

	ret = fscall_login(state, "unused", volid);
	if (ret)
		return ret;

	ret = fscall_open(state, &state->root_oid, 0, &state->root_ohandle);
	if (ret)
		return ret;

	return 0;
}