Files
xen/tools/libs/ctrl/xc_version.c
T
Andrew Cooper 1b421d52b2 tools: Introduce a non-truncating xc_xenver_changeset()
Update libxl and the ocaml stubs to match.  No API/ABI change in either.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Acked-by: Anthony PERARD <anthony.perard@citrix.com>
Acked-by: Christian Lindig <christian.lindig@citrix.com>
2024-12-20 22:44:42 +00:00

169 lines
4.1 KiB
C

/* SPDX-License-Identifier: LGPL-2.1 */
/*
* xc_version.c
*
* Wrappers aound XENVER_* hypercalls
*/
#include "xc_private.h"
#include <assert.h>
static int do_xen_version(xc_interface *xch, int cmd,
xc_hypercall_buffer_t *dest)
{
DECLARE_HYPERCALL_BUFFER_ARGUMENT(dest);
return xencall2(xch->xcall, __HYPERVISOR_xen_version,
cmd, HYPERCALL_BUFFER_AS_ARG(dest));
}
int xc_version(xc_interface *xch, int cmd, void *arg)
{
DECLARE_HYPERCALL_BOUNCE(arg, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT); /* Size unknown until cmd decoded */
size_t sz;
int rc;
switch ( cmd )
{
case XENVER_version:
sz = 0;
break;
case XENVER_extraversion:
sz = sizeof(xen_extraversion_t);
break;
case XENVER_compile_info:
sz = sizeof(xen_compile_info_t);
break;
case XENVER_capabilities:
sz = sizeof(xen_capabilities_info_t);
break;
case XENVER_changeset:
sz = sizeof(xen_changeset_info_t);
break;
case XENVER_platform_parameters:
sz = sizeof(xen_platform_parameters_t);
break;
case XENVER_get_features:
sz = sizeof(xen_feature_info_t);
break;
case XENVER_pagesize:
sz = 0;
break;
case XENVER_guest_handle:
sz = sizeof(xen_domain_handle_t);
break;
case XENVER_commandline:
sz = sizeof(xen_commandline_t);
break;
case XENVER_build_id:
{
xen_build_id_t *build_id = (xen_build_id_t *)arg;
sz = sizeof(*build_id) + build_id->len;
HYPERCALL_BOUNCE_SET_DIR(arg, XC_HYPERCALL_BUFFER_BOUNCE_BOTH);
break;
}
default:
ERROR("xc_version: unknown command %d\n", cmd);
return -EINVAL;
}
HYPERCALL_BOUNCE_SET_SIZE(arg, sz);
if ( (sz != 0) && xc_hypercall_bounce_pre(xch, arg) )
{
PERROR("Could not bounce buffer for version hypercall");
return -ENOMEM;
}
rc = do_xen_version(xch, cmd, HYPERCALL_BUFFER(arg));
if ( sz != 0 )
xc_hypercall_bounce_post(xch, arg);
return rc;
}
/*
* Raw hypercall wrapper, letting us pass NULL and things which aren't of
* xc_hypercall_buffer_t *.
*/
static int do_xen_version_raw(xc_interface *xch, int cmd, void *hbuf)
{
return xencall2(xch->xcall, __HYPERVISOR_xen_version,
cmd, (unsigned long)hbuf);
}
/*
* Issues a xen_varbuf_t subop, using manual hypercall buffer handling to
* avoid unnecessary buffering.
*
* On failure, returns NULL. errno probably useful.
* On success, returns a pointer which must be freed with xencall_free_buffer().
*/
static xen_varbuf_t *varbuf_op(xc_interface *xch, unsigned int subop)
{
xen_varbuf_t *hbuf = NULL;
ssize_t sz;
sz = do_xen_version_raw(xch, subop, NULL);
if ( sz < 0 )
return NULL;
hbuf = xencall_alloc_buffer(xch->xcall, sizeof(*hbuf) + sz);
if ( !hbuf )
return NULL;
hbuf->len = sz;
sz = do_xen_version_raw(xch, subop, hbuf);
if ( sz < 0 )
{
xencall_free_buffer(xch->xcall, hbuf);
return NULL;
}
hbuf->len = sz;
return hbuf;
}
/*
* Wrap varbuf_op() to obtain a simple string. Copy out of the hypercall
* buffer, stripping the xen_varbuf_t header and appending a NUL terminator.
*
* On failure, returns NULL, errno probably useful.
* On success, returns a pointer which must be free()'d.
*/
static char *varbuf_simple_string(xc_interface *xch, unsigned int subop)
{
xen_varbuf_t *hbuf = varbuf_op(xch, subop);
char *res;
if ( !hbuf )
return NULL;
res = malloc(hbuf->len + 1);
if ( res )
{
memcpy(res, hbuf->buf, hbuf->len);
res[hbuf->len] = '\0';
}
xencall_free_buffer(xch->xcall, hbuf);
return res;
}
char *xc_xenver_extraversion(xc_interface *xch)
{
return varbuf_simple_string(xch, XENVER_extraversion2);
}
char *xc_xenver_capabilities(xc_interface *xch)
{
return varbuf_simple_string(xch, XENVER_capabilities2);
}
char *xc_xenver_changeset(xc_interface *xch)
{
return varbuf_simple_string(xch, XENVER_changeset2);
}