2010-06-02 15:50:22 +02:00
|
|
|
#define _GNU_SOURCE
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/un.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/wait.h>
|
2010-06-29 12:58:11 +02:00
|
|
|
#include <syslog.h>
|
2010-06-02 15:50:22 +02:00
|
|
|
#include <xs.h>
|
|
|
|
|
2011-06-08 03:36:02 +02:00
|
|
|
int restore_domain(char *restore_file, char *conf_file, char *name) {
|
|
|
|
int pid, status, domid;
|
|
|
|
int pipe_fd[2];
|
|
|
|
char buf[256];
|
|
|
|
char *endptr;
|
|
|
|
switch (pid = fork()) {
|
|
|
|
case -1:
|
|
|
|
perror("fork");
|
2010-06-02 15:50:22 +02:00
|
|
|
exit(1);
|
2011-06-08 03:36:02 +02:00
|
|
|
case 0:
|
|
|
|
close(1);
|
|
|
|
if (dup2(open("/dev/null", O_RDWR), 1)==-1) {
|
|
|
|
perror("dup2 or open");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
execl("/usr/sbin/xl", "xl", "restore", conf_file, restore_file, NULL);
|
|
|
|
perror("execl");
|
|
|
|
exit(1);
|
|
|
|
default:;
|
2010-06-02 15:50:22 +02:00
|
|
|
}
|
2011-06-08 03:36:02 +02:00
|
|
|
if (waitpid(pid, &status, 0) < 0) {
|
|
|
|
perror("waitpid");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (status != 0) {
|
|
|
|
fprintf(stderr, "Error starting VM\n");
|
2010-06-02 15:50:22 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2011-06-08 03:36:02 +02:00
|
|
|
// read domid
|
|
|
|
if (pipe(pipe_fd)==-1) {
|
|
|
|
perror("pipe");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
switch (pid = fork()) {
|
|
|
|
case -1:
|
|
|
|
perror("fork");
|
|
|
|
exit(1);
|
|
|
|
case 0:
|
|
|
|
close(1);
|
|
|
|
if (dup2(pipe_fd[1], 1) == -1) {
|
|
|
|
perror("dup2");
|
2010-06-02 15:50:22 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
2011-06-08 03:36:02 +02:00
|
|
|
execl("/usr/sbin/xl", "xl", "domid", name, NULL);
|
|
|
|
perror("execl");
|
|
|
|
exit(1);
|
|
|
|
default:;
|
2010-06-02 15:50:22 +02:00
|
|
|
}
|
2011-06-08 03:36:02 +02:00
|
|
|
read(pipe_fd[0], buf, sizeof(buf)-1);
|
|
|
|
buf[sizeof(buf)-1] = 0;
|
|
|
|
domid = strtoul(buf, &endptr, 10);
|
|
|
|
if (domid <= 0 || *endptr != '\n') {
|
|
|
|
fprintf(stderr, "Cannot get DispVM xid\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (waitpid(pid, &status, 0) < 0) {
|
|
|
|
perror("waitpid");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (status != 0) {
|
|
|
|
fprintf(stderr, "Error getting DispVM xid\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
return domid;
|
2010-06-02 15:50:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *gettime()
|
|
|
|
{
|
|
|
|
static char retbuf[60];
|
|
|
|
struct timeval tv;
|
|
|
|
gettimeofday(&tv, NULL);
|
|
|
|
snprintf(retbuf, sizeof(retbuf), "%lld.%lld",
|
|
|
|
(long long) tv.tv_sec, (long long) tv.tv_usec);
|
|
|
|
return retbuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
int actually_do_unlink = 1;
|
2013-03-14 14:45:45 +01:00
|
|
|
#define FAST_FLAG_PATH "/var/run/qubes/fast-block-attach"
|
2010-06-02 15:50:22 +02:00
|
|
|
void set_fast_flag()
|
|
|
|
{
|
|
|
|
int fd = open(FAST_FLAG_PATH, O_CREAT | O_RDONLY, 0600);
|
|
|
|
if (fd < 0) {
|
|
|
|
perror("set_fast_flag");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
void rm_fast_flag()
|
|
|
|
{
|
|
|
|
if (actually_do_unlink)
|
|
|
|
unlink(FAST_FLAG_PATH);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define BUFSIZE (512*1024)
|
|
|
|
void do_read(int fd)
|
|
|
|
{
|
|
|
|
static char buf[BUFSIZE];
|
|
|
|
int n;
|
|
|
|
while ((n = read(fd, buf, BUFSIZE))) {
|
|
|
|
if (n < 0) {
|
|
|
|
perror("read savefile");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void preload_cache(int fd)
|
|
|
|
{
|
|
|
|
signal(SIGCHLD, SIG_IGN);
|
|
|
|
switch (fork()) {
|
|
|
|
case -1:
|
|
|
|
perror("fork");
|
|
|
|
exit(1);
|
|
|
|
case 0:
|
|
|
|
actually_do_unlink = 0;
|
|
|
|
do_read(fd);
|
|
|
|
fprintf(stderr, "time=%s, fs cache preload complete\n",
|
|
|
|
gettime());
|
|
|
|
exit(0);
|
|
|
|
default:
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-19 00:07:25 +02:00
|
|
|
void start_rexec(int domid, char *domain_name, char *default_user)
|
2011-03-08 13:03:55 +01:00
|
|
|
{
|
|
|
|
int pid, status;
|
|
|
|
char dstr[40];
|
|
|
|
snprintf(dstr, sizeof(dstr), "%d", domid);
|
|
|
|
switch (pid = fork()) {
|
|
|
|
case -1:
|
|
|
|
perror("fork");
|
|
|
|
exit(1);
|
|
|
|
case 0:
|
2013-03-14 04:06:55 +01:00
|
|
|
execl("/usr/lib/qubes/qrexec-daemon", "qrexec-daemon",
|
2013-10-19 00:07:25 +02:00
|
|
|
dstr, domain_name, default_user, NULL);
|
2011-03-08 13:03:55 +01:00
|
|
|
perror("execl");
|
|
|
|
exit(1);
|
|
|
|
default:;
|
|
|
|
}
|
|
|
|
if (waitpid(pid, &status, 0) < 0) {
|
|
|
|
perror("waitpid");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-06-02 15:50:22 +02:00
|
|
|
void start_guid(int domid, int argc, char **argv)
|
|
|
|
{
|
2010-07-13 01:51:33 +02:00
|
|
|
int i;
|
2010-06-02 15:50:22 +02:00
|
|
|
char dstr[40];
|
2011-07-02 22:44:49 +02:00
|
|
|
char *guid_args[argc + 1];
|
2010-06-02 15:50:22 +02:00
|
|
|
snprintf(dstr, sizeof(dstr), "%d", domid);
|
2013-03-14 04:46:27 +01:00
|
|
|
guid_args[0] = "qubes-guid";
|
2010-07-13 01:51:33 +02:00
|
|
|
guid_args[1] = "-d";
|
|
|
|
guid_args[2] = dstr;
|
2012-11-13 04:02:49 +01:00
|
|
|
for (i = 0; i < argc; i++)
|
|
|
|
guid_args[i+3] = argv[i];
|
|
|
|
guid_args[argc+3] = NULL;
|
2013-03-14 04:46:27 +01:00
|
|
|
execv("/usr/bin/qubes-guid", guid_args);
|
2010-07-13 01:51:33 +02:00
|
|
|
perror("execv");
|
2010-06-02 15:50:22 +02:00
|
|
|
}
|
2011-03-08 13:03:55 +01:00
|
|
|
|
2010-09-07 17:36:28 +02:00
|
|
|
char *dispname_by_dispid(int dispid)
|
2010-07-13 01:51:33 +02:00
|
|
|
{
|
|
|
|
static char retbuf[16];
|
|
|
|
snprintf(retbuf, sizeof(retbuf), "disp%d", dispid);
|
|
|
|
return retbuf;
|
|
|
|
}
|
2010-06-02 15:50:22 +02:00
|
|
|
|
2010-09-07 17:36:28 +02:00
|
|
|
char *build_dvm_ip(int netvm, int id)
|
|
|
|
{
|
|
|
|
static char buf[256];
|
2011-06-08 03:33:45 +02:00
|
|
|
snprintf(buf, sizeof(buf), "10.138.%d.%d", netvm, (id % 254) + 1);
|
2010-09-07 17:36:28 +02:00
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2011-03-19 03:15:32 +01:00
|
|
|
#define NAME_PATTERN "/volatile.img"
|
2010-08-03 07:12:59 +02:00
|
|
|
// replaces the unique portions of the savefile with per-dvm values
|
|
|
|
// returns the name of VM the savefile was taken for
|
2011-03-19 03:15:32 +01:00
|
|
|
// by looking for /.../vmname/volatile.img
|
2010-08-03 07:12:59 +02:00
|
|
|
// normally, it should be "templatename-dvm"
|
2010-09-07 17:36:28 +02:00
|
|
|
char *get_vmname_from_savefile(int fd)
|
2010-06-02 15:50:22 +02:00
|
|
|
{
|
2011-06-08 03:36:02 +02:00
|
|
|
int buflen;
|
2010-06-02 15:50:22 +02:00
|
|
|
static char buf[4096];
|
|
|
|
char *name;
|
|
|
|
char *slash;
|
2010-09-07 17:36:28 +02:00
|
|
|
lseek(fd, 0, SEEK_SET);
|
2011-06-08 03:36:02 +02:00
|
|
|
buflen = read(fd, buf, sizeof(buf) - 1);
|
|
|
|
if (buflen < 0) {
|
|
|
|
perror("read vm conf");
|
2010-06-02 15:50:22 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
2011-06-08 03:36:02 +02:00
|
|
|
buf[buflen] = 0;
|
2010-06-02 15:50:22 +02:00
|
|
|
name = strstr(buf + 20, NAME_PATTERN);
|
|
|
|
if (!name) {
|
|
|
|
fprintf(stderr,
|
2011-03-19 03:15:32 +01:00
|
|
|
"cannot find 'volatile.img' in savefile\n");
|
2010-06-02 15:50:22 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
*name = 0;
|
|
|
|
slash = name - 1;
|
|
|
|
while (slash[0] && slash[0] != '/')
|
|
|
|
slash--;
|
|
|
|
if (!*slash) {
|
|
|
|
fprintf(stderr, "cannot find / in savefile\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
return slash + 1;
|
|
|
|
}
|
|
|
|
|
2011-06-08 03:36:02 +02:00
|
|
|
void fill_field(FILE *conf, char *field, int dispid, int netvm_id)
|
2010-09-07 17:36:28 +02:00
|
|
|
{
|
2011-06-08 03:36:02 +02:00
|
|
|
if (!strcmp(field, "NAME")) {
|
|
|
|
fprintf(conf, "%s", dispname_by_dispid(dispid));
|
|
|
|
} else if (!strcmp(field, "MAC")) {
|
|
|
|
fprintf(conf, "00:16:3e:7c:8b:%02x", dispid);
|
|
|
|
} else if (!strcmp(field, "IP")) {
|
|
|
|
fprintf(conf, "%s", build_dvm_ip(netvm_id, dispid));
|
|
|
|
} else if (!strcmp(field, "UUID")) {
|
|
|
|
// currently not present in conf file
|
|
|
|
fprintf(conf, "064cd14c-95ad-4fc2-a4c9-cf9f522e5b%02x", dispid);
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "unknown field in vm conf: %s\n", field);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// modify the config file. conf = FILE of the new config,
|
|
|
|
// conf_templ - fd of config template
|
|
|
|
// pattern - pattern to search for
|
|
|
|
// val - string to replace pattern with
|
|
|
|
void fix_conffile(FILE *conf, int conf_templ, int dispid, int netvm_id)
|
|
|
|
{
|
2011-06-29 19:24:32 +02:00
|
|
|
int buflen = 0, cur_len = 0;
|
2010-09-07 17:36:28 +02:00
|
|
|
char buf[4096];
|
2011-06-08 03:36:02 +02:00
|
|
|
char *bufpos = buf;
|
|
|
|
char *pattern, *patternend;
|
|
|
|
|
|
|
|
/* read config template */
|
|
|
|
lseek(conf_templ, 0, SEEK_SET);
|
|
|
|
while ((cur_len = read(conf_templ, buf+cur_len, sizeof(buf)-cur_len)) > 0) {
|
|
|
|
buflen+=cur_len;
|
|
|
|
}
|
|
|
|
if (cur_len < 0) {
|
|
|
|
perror("read vm conf");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
while ((pattern = index(bufpos, '%'))) {
|
|
|
|
fwrite(bufpos, 1, pattern-bufpos, conf);
|
|
|
|
if (ferror(conf)) {
|
|
|
|
perror("write vm conf");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
patternend = index(pattern+1, '%');
|
|
|
|
if (!patternend) {
|
|
|
|
fprintf(stderr, "Unmatched '%%' in VM config\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
*patternend = '\0';
|
|
|
|
fill_field(conf, pattern+1, dispid, netvm_id);
|
|
|
|
bufpos = patternend+1;
|
|
|
|
}
|
|
|
|
while ((cur_len = fwrite(bufpos, 1, buflen-(bufpos-buf), conf)) > 0) {
|
|
|
|
bufpos+=cur_len;
|
|
|
|
}
|
|
|
|
if (ferror(conf)) {
|
|
|
|
perror("write vm conf");
|
|
|
|
exit(1);
|
|
|
|
}
|
2010-09-07 17:36:28 +02:00
|
|
|
}
|
|
|
|
|
2011-06-08 03:36:02 +02:00
|
|
|
|
2010-06-02 15:50:22 +02:00
|
|
|
void unpack_cows(char *name)
|
|
|
|
{
|
|
|
|
char vmdir[4096];
|
|
|
|
char tarfile[4096];
|
|
|
|
int status;
|
|
|
|
snprintf(vmdir, sizeof(vmdir), "/var/lib/qubes/appvms/%s", name);
|
|
|
|
snprintf(tarfile, sizeof(tarfile),
|
2013-03-14 14:45:45 +01:00
|
|
|
"/var/lib/qubes/appvms/%s/saved-cows.tar", name);
|
2010-06-02 15:50:22 +02:00
|
|
|
switch (fork()) {
|
|
|
|
case -1:
|
|
|
|
fprintf(stderr, "fork");
|
|
|
|
exit(1);
|
|
|
|
case 0:
|
|
|
|
execl("/bin/tar", "tar", "-C", vmdir, "-Sxf",
|
|
|
|
tarfile, NULL);
|
|
|
|
perror("execl");
|
|
|
|
exit(1);
|
|
|
|
default:
|
|
|
|
wait(&status);
|
|
|
|
if (WEXITSTATUS(status)) {
|
|
|
|
fprintf(stderr, "tar exited with status=0x%x\n",
|
|
|
|
status);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
fprintf(stderr, "time=%s, cows restored\n", gettime());
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void write_xs_single(struct xs_handle *xs, int domid, char *name,
|
|
|
|
char *val)
|
|
|
|
{
|
|
|
|
char key[256];
|
|
|
|
snprintf(key, sizeof(key), "/local/domain/%d/%s", domid, name);
|
|
|
|
if (!xs_write(xs, XBT_NULL, key, val, strlen(val))) {
|
|
|
|
fprintf(stderr, "xs_write");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-08 03:36:02 +02:00
|
|
|
void perm_xs_single(struct xs_handle *xs, int domid, char *name,
|
|
|
|
struct xs_permissions *perms, int nperms)
|
|
|
|
{
|
|
|
|
char key[256];
|
|
|
|
snprintf(key, sizeof(key), "/local/domain/%d/%s", domid, name);
|
|
|
|
if (!xs_set_permissions(xs, XBT_NULL, key, perms, nperms)) {
|
|
|
|
fprintf(stderr, "xs_set_permissions");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-07 17:36:28 +02:00
|
|
|
int get_netvm_id_from_name(char *name)
|
2010-06-02 15:50:22 +02:00
|
|
|
{
|
|
|
|
int fd, n;
|
|
|
|
char netvm_id[256];
|
2010-09-07 17:36:28 +02:00
|
|
|
char netvm_id_path[256];
|
2010-06-02 15:50:22 +02:00
|
|
|
snprintf(netvm_id_path, sizeof(netvm_id_path),
|
2013-03-14 14:45:45 +01:00
|
|
|
"/var/lib/qubes/appvms/%s/netvm-id.txt", name);
|
2010-06-02 15:50:22 +02:00
|
|
|
fd = open(netvm_id_path, O_RDONLY);
|
|
|
|
if (fd < 0) {
|
|
|
|
perror("open netvm_id");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
n = read(fd, netvm_id, sizeof(netvm_id) - 1);
|
|
|
|
close(fd);
|
|
|
|
netvm_id[n] = 0;
|
2010-09-07 17:36:28 +02:00
|
|
|
return atoi(netvm_id);
|
|
|
|
}
|
2010-06-02 15:50:22 +02:00
|
|
|
|
2010-09-07 17:36:28 +02:00
|
|
|
void setup_xenstore(int netvm_id, int domid, int dvmid, char *name)
|
|
|
|
{
|
|
|
|
char val[256];
|
|
|
|
struct xs_handle *xs = xs_daemon_open();
|
2011-06-08 03:36:02 +02:00
|
|
|
struct xs_permissions perm[1];
|
2010-09-07 17:36:28 +02:00
|
|
|
if (!xs) {
|
|
|
|
perror("xs_daemon_open");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2013-03-14 04:16:41 +01:00
|
|
|
write_xs_single(xs, domid, "qubes-ip",
|
2010-09-07 17:36:28 +02:00
|
|
|
build_dvm_ip(netvm_id, dvmid));
|
2013-03-14 04:16:41 +01:00
|
|
|
write_xs_single(xs, domid, "qubes-netmask", "255.255.0.0");
|
2011-06-08 03:33:45 +02:00
|
|
|
snprintf(val, sizeof(val), "10.137.%d.1", netvm_id);
|
2013-03-14 04:16:41 +01:00
|
|
|
write_xs_single(xs, domid, "qubes-gateway", val);
|
2011-06-08 03:33:45 +02:00
|
|
|
snprintf(val, sizeof(val), "10.137.%d.254", netvm_id);
|
2013-03-14 04:16:41 +01:00
|
|
|
write_xs_single(xs, domid, "qubes-secondary-dns", val);
|
|
|
|
write_xs_single(xs, domid, "qubes-vm-type", "DisposableVM");
|
|
|
|
write_xs_single(xs, domid, "qubes-restore-complete", "True");
|
2011-06-08 03:36:02 +02:00
|
|
|
|
|
|
|
perm[0].id = domid;
|
|
|
|
perm[0].perms = XS_PERM_NONE;
|
|
|
|
perm_xs_single(xs, domid, "device", perm, 1);
|
|
|
|
perm_xs_single(xs, domid, "memory", perm, 1);
|
|
|
|
|
2010-06-02 15:50:22 +02:00
|
|
|
xs_daemon_close(xs);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int get_next_disposable_id()
|
|
|
|
{
|
|
|
|
int seq = 0;
|
2013-03-14 14:45:45 +01:00
|
|
|
int fd = open("/var/run/qubes/dispVM.seq", O_RDWR);
|
2010-06-02 15:50:22 +02:00
|
|
|
if (fd < 0) {
|
2013-03-14 14:45:45 +01:00
|
|
|
perror("open dispVM.seq");
|
2010-06-02 15:50:22 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
read(fd, &seq, sizeof(seq));
|
|
|
|
seq++;
|
|
|
|
lseek(fd, 0, SEEK_SET);
|
|
|
|
write(fd, &seq, sizeof(seq));
|
|
|
|
close(fd);
|
|
|
|
return seq;
|
|
|
|
}
|
|
|
|
|
2010-09-07 17:36:28 +02:00
|
|
|
void write_varrun_domid(int domid, char *dispname, char *orig)
|
2010-06-02 15:50:22 +02:00
|
|
|
{
|
2013-03-14 14:45:45 +01:00
|
|
|
FILE *f = fopen("/var/run/qubes/dispVM.xid", "w");
|
2010-06-02 15:50:22 +02:00
|
|
|
if (!f) {
|
2013-03-14 14:45:45 +01:00
|
|
|
perror("fopen dispVM.xid");
|
2010-06-02 15:50:22 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
2010-07-13 01:51:33 +02:00
|
|
|
fprintf(f, "%d\n%s\n%s\n", domid, dispname, orig);
|
2010-06-02 15:50:22 +02:00
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-06-29 12:16:32 +02:00
|
|
|
void redirect_stderr()
|
|
|
|
{
|
2013-03-14 14:45:45 +01:00
|
|
|
int fd = open("/var/log/qubes/qubes-restore.log",
|
2010-09-07 17:36:28 +02:00
|
|
|
O_CREAT | O_TRUNC | O_WRONLY, 0600);
|
2010-06-29 12:16:32 +02:00
|
|
|
if (fd < 0) {
|
2013-03-14 14:45:45 +01:00
|
|
|
syslog(LOG_DAEMON | LOG_ERR, "open qubes-restore.log");
|
2010-06-29 12:16:32 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
dup2(fd, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-06-02 15:50:22 +02:00
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
2011-06-08 03:36:02 +02:00
|
|
|
int conf_templ, domid, dispid, netvm_id;
|
|
|
|
FILE *conf;
|
2010-06-02 15:50:22 +02:00
|
|
|
char *name;
|
2011-06-08 03:36:02 +02:00
|
|
|
char confname[256];
|
2012-11-13 04:02:49 +01:00
|
|
|
char *default_user = NULL;
|
|
|
|
int guid_args_start = 3;
|
2011-06-08 03:36:02 +02:00
|
|
|
if (argc < 3) {
|
2010-09-07 17:36:28 +02:00
|
|
|
fprintf(stderr,
|
2012-11-13 04:02:49 +01:00
|
|
|
"usage: %s savefile conf_templ [-u default_user] [guid args] \n", argv[0]);
|
2010-06-02 15:50:22 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
2010-06-29 12:16:32 +02:00
|
|
|
redirect_stderr();
|
2010-06-02 15:50:22 +02:00
|
|
|
fprintf(stderr, "time=%s, starting\n", gettime());
|
|
|
|
set_fast_flag();
|
|
|
|
atexit(rm_fast_flag);
|
2011-06-08 03:36:02 +02:00
|
|
|
conf_templ = open(argv[2], O_RDONLY);
|
|
|
|
if (conf_templ < 0) {
|
|
|
|
perror("fopen vm conf");
|
2010-06-02 15:50:22 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
2012-11-13 04:02:49 +01:00
|
|
|
if (argc > 4 && strcmp(argv[3], "-u")==0) {
|
|
|
|
default_user = argv[4];
|
|
|
|
guid_args_start += 2;
|
|
|
|
}
|
2010-06-02 15:50:22 +02:00
|
|
|
dispid = get_next_disposable_id();
|
2011-06-08 03:36:02 +02:00
|
|
|
name = get_vmname_from_savefile(conf_templ);
|
2010-09-07 17:36:28 +02:00
|
|
|
netvm_id = get_netvm_id_from_name(name);
|
2011-06-08 03:36:02 +02:00
|
|
|
snprintf(confname, sizeof(confname), "/tmp/qubes-dvm-%d.xl", dispid);
|
|
|
|
conf = fopen(confname, "w");
|
|
|
|
if (!conf) {
|
|
|
|
perror("fopen new vm conf");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
fix_conffile(conf, conf_templ, dispid, netvm_id);
|
|
|
|
close(conf_templ);
|
|
|
|
fclose(conf);
|
2010-06-02 15:50:22 +02:00
|
|
|
// printf("name=%s\n", name);
|
|
|
|
unpack_cows(name);
|
|
|
|
// no preloading for now, assume savefile in shm
|
|
|
|
// preload_cache(fd);
|
2011-06-08 03:36:02 +02:00
|
|
|
domid=restore_domain(argv[1], confname, dispname_by_dispid(dispid));
|
2010-07-13 01:51:33 +02:00
|
|
|
write_varrun_domid(domid, dispname_by_dispid(dispid), name);
|
2010-06-02 15:50:22 +02:00
|
|
|
fprintf(stderr,
|
2010-09-30 18:26:35 +02:00
|
|
|
"time=%s, created domid=%d, creating xenstore entries\n",
|
2010-06-02 15:50:22 +02:00
|
|
|
gettime(), domid);
|
2010-09-07 17:36:28 +02:00
|
|
|
setup_xenstore(netvm_id, domid, dispid, name);
|
2010-06-02 15:50:22 +02:00
|
|
|
rm_fast_flag();
|
2013-02-25 06:48:29 +01:00
|
|
|
fprintf(stderr, "time=%s, starting qrexec\n", gettime());
|
2013-10-19 15:55:31 +02:00
|
|
|
start_rexec(domid, dispname_by_dispid(dispid), default_user);
|
2013-03-14 04:46:27 +01:00
|
|
|
fprintf(stderr, "time=%s, starting qubes-guid\n", gettime());
|
2012-11-13 04:02:49 +01:00
|
|
|
start_guid(domid, argc-guid_args_start, argv+guid_args_start);
|
2013-03-14 04:46:27 +01:00
|
|
|
fprintf(stderr, "time=%s, started qubes-guid\n", gettime());
|
2010-06-02 15:50:22 +02:00
|
|
|
return 0;
|
|
|
|
}
|