Files
xen/tools/helpers/init-xenstore-domain.c
T
Ian Campbell f15348afe9 init-xenstore-domain: cleanup all resources on a single exit path
Previously xs_fd would be left open, which is CID 1055993 (previously
partially fixed by 3bca826aae).

Instead arrange for both success and error cases to cleanup everything
on a single exit path instead of doing partial cleanup on the success
path a few operations higher up.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Acked-by: Wei Liu <wei.liu2@citrix.com>
2016-02-11 15:36:15 +00:00

345 lines
7.6 KiB
C

#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <getopt.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <xenctrl.h>
#include <xc_dom.h>
#include <xenstore.h>
#include <xen/sys/xenbus_dev.h>
#include <xen-xsm/flask/flask.h>
#include "init-dom-json.h"
static uint32_t domid = ~0;
static char *kernel;
static char *ramdisk;
static char *flask;
static char *param;
static char *name = "Xenstore";
static int memory;
static struct option options[] = {
{ "kernel", 1, NULL, 'k' },
{ "memory", 1, NULL, 'm' },
{ "flask", 1, NULL, 'f' },
{ "ramdisk", 1, NULL, 'r' },
{ "param", 1, NULL, 'p' },
{ "name", 1, NULL, 'n' },
{ NULL, 0, NULL, 0 }
};
static void usage(void)
{
fprintf(stderr,
"Usage:\n"
"\n"
"init-xenstore-domain <options>\n"
"\n"
"where options may include:\n"
"\n"
" --kernel <xenstore-kernel> kernel file of the xenstore domain, mandatory\n"
" --memory <memory size> size of the domain in MB, mandatory\n"
" --flask <flask-label> optional flask label of the domain\n"
" --ramdisk <ramdisk-file> optional ramdisk file for the domain\n"
" --param <cmdline> optional additional parameters for the domain\n"
" --name <name> name of the domain (default: Xenstore)\n");
}
static int build(xc_interface *xch)
{
char cmdline[512];
uint32_t ssid;
xen_domain_handle_t handle = { 0 };
int rv, xs_fd;
struct xc_dom_image *dom = NULL;
int limit_kb = (memory + 1) * 1024;
xs_fd = open("/dev/xen/xenbus_backend", O_RDWR);
if ( xs_fd == -1 )
{
fprintf(stderr, "Could not open /dev/xen/xenbus_backend\n");
return -1;
}
if ( flask )
{
rv = xc_flask_context_to_sid(xch, flask, strlen(flask), &ssid);
if ( rv )
{
fprintf(stderr, "xc_flask_context_to_sid failed\n");
goto err;
}
}
else
{
ssid = SECINITSID_DOMU;
}
rv = xc_domain_create(xch, ssid, handle, XEN_DOMCTL_CDF_xs_domain,
&domid, NULL);
if ( rv )
{
fprintf(stderr, "xc_domain_create failed\n");
goto err;
}
rv = xc_domain_max_vcpus(xch, domid, 1);
if ( rv )
{
fprintf(stderr, "xc_domain_max_vcpus failed\n");
goto err;
}
rv = xc_domain_setmaxmem(xch, domid, limit_kb);
if ( rv )
{
fprintf(stderr, "xc_domain_setmaxmem failed\n");
goto err;
}
rv = xc_domain_set_memmap_limit(xch, domid, limit_kb);
if ( rv )
{
fprintf(stderr, "xc_domain_set_memmap_limit failed\n");
goto err;
}
rv = ioctl(xs_fd, IOCTL_XENBUS_BACKEND_SETUP, domid);
if ( rv < 0 )
{
fprintf(stderr, "Xenbus setup ioctl failed\n");
goto err;
}
if ( param )
snprintf(cmdline, 512, "--event %d --internal-db %s", rv, param);
else
snprintf(cmdline, 512, "--event %d --internal-db", rv);
dom = xc_dom_allocate(xch, cmdline, NULL);
rv = xc_dom_kernel_file(dom, kernel);
if ( rv )
{
fprintf(stderr, "xc_dom_kernel_file failed\n");
goto err;
}
if ( ramdisk )
{
rv = xc_dom_ramdisk_file(dom, ramdisk);
if ( rv )
{
fprintf(stderr, "xc_dom_ramdisk_file failed\n");
goto err;
}
}
rv = xc_dom_boot_xen_init(dom, xch, domid);
if ( rv )
{
fprintf(stderr, "xc_dom_boot_xen_init failed\n");
goto err;
}
rv = xc_dom_parse_image(dom);
if ( rv )
{
fprintf(stderr, "xc_dom_parse_image failed\n");
goto err;
}
rv = xc_dom_mem_init(dom, memory);
if ( rv )
{
fprintf(stderr, "xc_dom_mem_init failed\n");
goto err;
}
rv = xc_dom_boot_mem_init(dom);
if ( rv )
{
fprintf(stderr, "xc_dom_boot_mem_init failed\n");
goto err;
}
rv = xc_dom_build_image(dom);
if ( rv )
{
fprintf(stderr, "xc_dom_build_image failed\n");
goto err;
}
rv = xc_dom_boot_image(dom);
if ( rv )
{
fprintf(stderr, "xc_dom_boot_image failed\n");
goto err;
}
rv = xc_domain_set_virq_handler(xch, domid, VIRQ_DOM_EXC);
if ( rv )
{
fprintf(stderr, "xc_domain_set_virq_handler failed\n");
goto err;
}
rv = xc_domain_unpause(xch, domid);
if ( rv )
{
fprintf(stderr, "xc_domain_unpause failed\n");
goto err;
}
rv = 0;
err:
if ( dom )
xc_dom_release(dom);
if ( xs_fd >= 0 )
close(xs_fd);
/* if we failed then destroy the domain */
if ( rv && domid != ~0 )
xc_domain_destroy(xch, domid);
return rv;
}
static int check_domain(xc_interface *xch)
{
xc_dominfo_t info;
uint32_t dom;
int ret;
dom = 1;
while ( (ret = xc_domain_getinfo(xch, dom, 1, &info)) == 1 )
{
if ( info.xenstore )
return 1;
dom = info.domid + 1;
}
if ( ret < 0 && errno != ESRCH )
{
fprintf(stderr, "xc_domain_getinfo failed\n");
return ret;
}
return 0;
}
static void do_xs_write(struct xs_handle *xsh, char *path, char *val)
{
if ( !xs_write(xsh, XBT_NULL, path, val, strlen(val)) )
fprintf(stderr, "writing %s to xenstore failed.\n", path);
}
static void do_xs_write_dom(struct xs_handle *xsh, char *path, char *val)
{
char full_path[64];
snprintf(full_path, 64, "/local/domain/%d/%s", domid, path);
do_xs_write(xsh, full_path, val);
}
int main(int argc, char** argv)
{
int opt;
xc_interface *xch;
struct xs_handle *xsh;
char buf[16];
int rv, fd;
while ( (opt = getopt_long(argc, argv, "", options, NULL)) != -1 )
{
switch ( opt )
{
case 'k':
kernel = optarg;
break;
case 'm':
memory = strtol(optarg, NULL, 10);
break;
case 'f':
flask = optarg;
break;
case 'r':
ramdisk = optarg;
break;
case 'p':
param = optarg;
break;
case 'n':
name = optarg;
break;
default:
usage();
return 2;
}
}
if ( optind != argc || !kernel || !memory )
{
usage();
return 2;
}
xch = xc_interface_open(NULL, NULL, 0);
if ( !xch )
{
fprintf(stderr, "xc_interface_open() failed\n");
return 1;
}
rv = check_domain(xch);
if ( !rv )
rv = build(xch);
else if ( rv > 0 )
fprintf(stderr, "xenstore domain already present.\n");
xc_interface_close(xch);
if ( rv )
return 1;
rv = gen_stub_json_config(domid);
if ( rv )
return 3;
xsh = xs_open(0);
if ( !xsh )
{
fprintf(stderr, "xs_open() failed.\n");
return 3;
}
snprintf(buf, 16, "%d", domid);
do_xs_write(xsh, "/tool/xenstored/domid", buf);
do_xs_write_dom(xsh, "domid", buf);
do_xs_write_dom(xsh, "name", name);
snprintf(buf, 16, "%d", memory * 1024);
do_xs_write_dom(xsh, "memory/target", buf);
do_xs_write_dom(xsh, "memory/static-max", buf);
xs_close(xsh);
fd = creat("/var/run/xenstored.pid", 0666);
if ( fd < 0 )
{
fprintf(stderr, "Creating /var/run/xenstored.pid failed\n");
return 3;
}
rv = snprintf(buf, 16, "domid:%d\n", domid);
rv = write(fd, buf, rv);
close(fd);
if ( rv < 0 )
{
fprintf(stderr, "Writing domid to /var/run/xenstored.pid failed\n");
return 3;
}
return 0;
}
/*
* Local variables:
* mode: C
* c-file-style: "BSD"
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/