Files
xen/tools/libxl/libxl_save_helper.c
T
Jason Andryuk b327a3f421 libxl: Reset toolstack_save file position in libxl
toolstack_save data is written to a temporary file in libxl and read
back in libxl-save-helper.  The file position must be reset prior to
reading the file, which is done in libxl-save-helper with lseek.

lseek is unsupported for pipes and sockets, so a wrapper passing such an
fd to libxl-save-helper fails the lseek.  Moving the lseek to libxl
avoids the error, allowing the save to continue.

Signed-off-by: Jason Andryuk <andryuk@aero.org>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
2014-05-22 16:35:22 +01:00

273 lines
8.2 KiB
C

/*
* Copyright (C) 2012 Citrix Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; version 2.1 only. with the special
* exception on linking described in file LICENSE.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*/
/*
* The libxl-save-helper utility speaks a protocol to its caller for
* the callbacks. The protocol is as follows.
*
* The helper talks on stdin and stdout, in binary in machine
* endianness. The helper speaks first, and only when it has a
* callback to make. It writes a 16-bit number being the message
* length, and then the message body.
*
* Each message starts with a 16-bit number indicating which of the
* messages it is, and then some arguments in a binary marshalled form.
* If the callback does not need a reply (it returns void), the helper
* just continues. Otherwise the helper waits for its caller to send a
* single int which is to be the return value from the callback.
*
* Where feasible the stubs and callbacks have prototypes identical to
* those required by xc_domain_save and xc_domain_restore, so that the
* autogenerated functions can be used/provided directly.
*
* The actual messages are in the array @msgs in libxl_save_msgs_gen.pl
*/
#include "libxl_osdeps.h"
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <inttypes.h>
#include "libxl.h"
#include "xenctrl.h"
#include "xenguest.h"
#include "_libxl_save_msgs_helper.h"
/*----- logger -----*/
static void tellparent_vmessage(xentoollog_logger *logger_in,
xentoollog_level level,
int errnoval,
const char *context,
const char *format,
va_list al)
{
char *formatted;
int r = vasprintf(&formatted, format, al);
if (r < 0) { perror("memory allocation failed during logging"); exit(-1); }
helper_stub_log(level, errnoval, context, formatted, 0);
free(formatted);
}
static void tellparent_progress(struct xentoollog_logger *logger_in,
const char *context,
const char *doing_what, int percent,
unsigned long done, unsigned long total)
{
helper_stub_progress(context, doing_what, done, total, 0);
}
static void tellparent_destroy(struct xentoollog_logger *logger_in)
{
abort();
}
/*----- globals -----*/
static const char *program = "libxl-save-helper";
static xentoollog_logger logger = {
tellparent_vmessage,
tellparent_progress,
tellparent_destroy,
};
static xc_interface *xch;
/*----- error handling -----*/
static void fail(int errnoval, const char *fmt, ...)
__attribute__((noreturn,format(printf,2,3)));
static void fail(int errnoval, const char *fmt, ...)
{
va_list al;
va_start(al,fmt);
xtl_logv(&logger,XTL_ERROR,errnoval,program,fmt,al);
exit(-1);
}
static int read_exactly(int fd, void *buf, size_t len)
/* returns 0 if we get eof, even if we got it midway through; 1 if ok */
{
while (len) {
ssize_t r = read(fd, buf, len);
if (r<=0) return r;
assert(r <= len);
len -= r;
buf = (char*)buf + r;
}
return 1;
}
static void *xmalloc(size_t sz)
{
if (!sz) return 0;
void *r = malloc(sz);
if (!r) { perror("memory allocation failed"); exit(-1); }
return r;
}
/*----- helper functions called by autogenerated stubs -----*/
unsigned char * helper_allocbuf(int len, void *user)
{
return xmalloc(len);
}
static void transmit(const unsigned char *msg, int len, void *user)
{
while (len) {
int r = write(1, msg, len);
if (r<0) { perror("write"); exit(-1); }
assert(r >= 0);
assert(r <= len);
len -= r;
msg += r;
}
}
void helper_transmitmsg(unsigned char *msg_freed, int len_in, void *user)
{
assert(len_in < 64*1024);
uint16_t len = len_in;
transmit((const void*)&len, sizeof(len), user);
transmit(msg_freed, len, user);
free(msg_freed);
}
int helper_getreply(void *user)
{
int v;
int r = read_exactly(0, &v, sizeof(v));
if (r<=0) exit(-2);
return v;
}
/*----- other callbacks -----*/
static int toolstack_save_fd;
static uint32_t toolstack_save_len;
static int toolstack_save_cb(uint32_t domid, uint8_t **buf,
uint32_t *len, void *data)
{
int r;
assert(toolstack_save_fd > 0);
*buf = xmalloc(toolstack_save_len);
r = read_exactly(toolstack_save_fd, *buf, toolstack_save_len);
if (r<0) fail(errno,"read toolstack data");
if (r==0) fail(0,"read toolstack data eof");
*len = toolstack_save_len;
return 0;
}
static void startup(const char *op) {
xtl_log(&logger,XTL_DEBUG,0,program,"starting %s",op);
xch = xc_interface_open(&logger,&logger,0);
if (!xch) fail(errno,"xc_interface_open failed");
}
static void complete(int retval) {
int errnoval = retval ? errno : 0; /* suppress irrelevant errnos */
xtl_log(&logger,XTL_DEBUG,errnoval,program,"complete r=%d",retval);
helper_stub_complete(retval,errnoval,0);
xc_interface_close(xch);
exit(0);
}
static struct save_callbacks helper_save_callbacks;
static struct restore_callbacks helper_restore_callbacks;
int main(int argc, char **argv)
{
int r;
#define NEXTARG (++argv, assert(*argv), *argv)
const char *mode = *++argv;
assert(mode);
if (!strcmp(mode,"--save-domain")) {
int io_fd = atoi(NEXTARG);
uint32_t dom = strtoul(NEXTARG,0,10);
uint32_t max_iters = strtoul(NEXTARG,0,10);
uint32_t max_factor = strtoul(NEXTARG,0,10);
uint32_t flags = strtoul(NEXTARG,0,10);
int hvm = atoi(NEXTARG);
unsigned long genidad = strtoul(NEXTARG,0,10);
toolstack_save_fd = atoi(NEXTARG);
toolstack_save_len = strtoul(NEXTARG,0,10);
unsigned cbflags = strtoul(NEXTARG,0,10);
assert(!*++argv);
if (toolstack_save_fd >= 0)
helper_save_callbacks.toolstack_save = toolstack_save_cb;
helper_setcallbacks_save(&helper_save_callbacks, cbflags);
startup("save");
r = xc_domain_save(xch, io_fd, dom, max_iters, max_factor, flags,
&helper_save_callbacks, hvm, genidad);
complete(r);
} else if (!strcmp(mode,"--restore-domain")) {
int io_fd = atoi(NEXTARG);
uint32_t dom = strtoul(NEXTARG,0,10);
unsigned store_evtchn = strtoul(NEXTARG,0,10);
domid_t store_domid = strtoul(NEXTARG,0,10);
unsigned console_evtchn = strtoul(NEXTARG,0,10);
domid_t console_domid = strtoul(NEXTARG,0,10);
unsigned int hvm = strtoul(NEXTARG,0,10);
unsigned int pae = strtoul(NEXTARG,0,10);
int superpages = strtoul(NEXTARG,0,10);
int no_incr_genidad = strtoul(NEXTARG,0,10);
unsigned cbflags = strtoul(NEXTARG,0,10);
int checkpointed = strtoul(NEXTARG,0,10);
assert(!*++argv);
helper_setcallbacks_restore(&helper_restore_callbacks, cbflags);
unsigned long store_mfn = 0;
unsigned long console_mfn = 0;
unsigned long genidad = 0;
startup("restore");
r = xc_domain_restore(xch, io_fd, dom, store_evtchn, &store_mfn,
store_domid, console_evtchn, &console_mfn,
console_domid, hvm, pae, superpages,
no_incr_genidad, checkpointed, &genidad,
&helper_restore_callbacks);
helper_stub_restore_results(store_mfn,console_mfn,genidad,0);
complete(r);
} else {
assert(!"unexpected mode argument");
}
}
/*
* Local variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/