From 793b7b25967735d64d4f2153571a506a5801cd53 Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Wed, 2 Jun 2010 15:50:22 +0200 Subject: [PATCH] Quick VM restore support --- appvm/fstab | 2 +- appvm/qubes_core | 64 ++-- appvm/qubes_timestamp | 2 + dom0/init.d/qubes_core | 2 + dom0/restore/Makefile | 9 + dom0/restore/block.qubes | 54 +++ dom0/restore/qubes_prepare_saved_domain.sh | 42 +++ dom0/restore/qubes_restore.c | 406 +++++++++++++++++++++ dom0/restore/xenstore-watch.c | 28 ++ rpm_spec/core-appvm.spec | 8 +- rpm_spec/core-dom0.spec | 15 + 11 files changed, 608 insertions(+), 24 deletions(-) create mode 100755 appvm/qubes_timestamp create mode 100644 dom0/restore/Makefile create mode 100755 dom0/restore/block.qubes create mode 100755 dom0/restore/qubes_prepare_saved_domain.sh create mode 100644 dom0/restore/qubes_restore.c create mode 100644 dom0/restore/xenstore-watch.c diff --git a/appvm/fstab b/appvm/fstab index ac4eacbd..968d9b77 100644 --- a/appvm/fstab +++ b/appvm/fstab @@ -8,7 +8,7 @@ # /dev/mapper/dmroot / ext4 defaults,noatime 1 1 /dev/mapper/dmswap swap swap defaults 0 0 -/dev/xvdb /rw ext4 defaults 0 0 +/dev/xvdb /rw ext4 noauto,defaults 0 0 tmpfs /dev/shm tmpfs defaults 0 0 devpts /dev/pts devpts gid=5,mode=620 0 0 sysfs /sys sysfs defaults 0 0 diff --git a/appvm/qubes_core b/appvm/qubes_core index f432963c..e05b5319 100755 --- a/appvm/qubes_core +++ b/appvm/qubes_core @@ -14,6 +14,20 @@ start() echo "ERROR: /usr/bin/xenstore-read not found!" exit 1 fi + if xenstore-read qubes_save_request ; then + dmesg -c >/dev/null +# echo 1 >/proc/sys/vm/drop_caches +# free | grep buffers/cache | +# (read a b c d ; xenstore-write device/qubes_used_mem $c) + free | grep Mem: | + (read a b c d ; xenstore-write device/qubes_used_mem $c) + echo "Waiting for restore" + while ! dmesg -c | grep "using vcpu" ; do usleep 10 ; done + while ! xenstore-read qubes_vm_type 2>/dev/null ; do + usleep 10 + done + echo Back to life. + fi name=$(/usr/bin/xenstore-read name) hostname $name @@ -29,30 +43,36 @@ start() echo "nameserver $secondary_dns" >> /etc/resolv.conf fi - if ! [ -d /rw/home ] ; then - echo - echo "--> Virgin boot of the VM: Linking /home to /rw/home" - mv /home /home.orig - mkdir -p /rw/config - mkdir -p /rw/home - ln -s /rw/home/ /home - cp -a /home.orig/user /home - touch /rw/config/rc.local - rm -fr /home.orig - touch /var/lib/qubes/first_boot_completed - fi + if [ -e /dev/xvdb ] ; then + mount /rw - if ! [ -L /home ] ; then - mv /home /home.orig - ln -s /rw/home /home - fi - if ! [ -L /usr/local ] ; then - mv /usr/local /usr/local.orig - ln -s /rw/usrlocal /usr/local - fi + if ! [ -d /rw/home ] ; then + echo + echo "--> Virgin boot of the VM: Linking /home to /rw/home" + mv /home /home.orig + mkdir -p /rw/config + mkdir -p /rw/home + ln -s /rw/home/ /home + cp -a /home.orig/user /home + touch /rw/config/rc.local + rm -fr /home.orig + touch /var/lib/qubes/first_boot_completed + fi + + if ! [ -L /home ] ; then + mv /home /home.orig + ln -s /rw/home /home + fi + if ! [ -L /usr/local ] ; then + mv /usr/local /usr/local.orig + ln -s /rw/usrlocal /usr/local + fi #make it last, we want all above to work without /rw mounted - if ! [ -d /rw/usrlocal ] ; then - cp -a /usr/local.orig /rw/usrlocal + if ! [ -d /rw/usrlocal ] ; then + cp -a /usr/local.orig /rw/usrlocal + fi + else + ln -sf /home_volatile /home fi [ -x /rw/config/rc.local ] && /rw/config/rc.local diff --git a/appvm/qubes_timestamp b/appvm/qubes_timestamp new file mode 100755 index 00000000..fc3d8d75 --- /dev/null +++ b/appvm/qubes_timestamp @@ -0,0 +1,2 @@ +#!/bin/sh +exec xenstore-write device/qubes_timestamp $(date +%s.%N) diff --git a/dom0/init.d/qubes_core b/dom0/init.d/qubes_core index e0945572..d6b4ea99 100755 --- a/dom0/init.d/qubes_core +++ b/dom0/init.d/qubes_core @@ -30,6 +30,8 @@ start() chgrp qubes /var/run/xenstored/* chmod 660 /var/run/xenstored/* xm sched-credit -d 0 -w 65535 + printf "\x00\x00\x00\x00" > /var/run/qubes/dispVM_seq + xm mem-set 0 700 cp /var/lib/qubes/qubes.xml /var/lib/qubes/backup/qubes-$(date +%F-%T).xml touch /var/lock/subsys/qubes_core success diff --git a/dom0/restore/Makefile b/dom0/restore/Makefile new file mode 100644 index 00000000..e279bbb6 --- /dev/null +++ b/dom0/restore/Makefile @@ -0,0 +1,9 @@ +CC=gcc +all: qubes_restore xenstore-watch +qubes_restore: qubes_restore.o + $(CC) -o qubes_restore qubes_restore.o -lxenstore + +xenstore-watch: xenstore-watch.o + $(CC) -o xenstore-watch xenstore-watch.o -lxenstore +clean: + rm -f *.o *~ qubes_restore xenstore-watch diff --git a/dom0/restore/block.qubes b/dom0/restore/block.qubes new file mode 100755 index 00000000..435418a2 --- /dev/null +++ b/dom0/restore/block.qubes @@ -0,0 +1,54 @@ +#!/bin/bash + +hd_arr[10]=a +hd_arr[11]=b +hd_arr[12]=c +hd_arr[13]=d +hd_arr[14]=e +hd_arr[15]=f + +hexdigit() +{ + if [ $1 -lt 10 ] ; then + RET=$1 + else + RET=${hd_arr[$1]} + fi +} + +hexnumber() +{ + hexdigit $(($1/16)) + ret2=$RET + hexdigit $(($1%16)) + HEXNUMBER="$ret2"$RET +} + + +process() +{ + if ! [ "x""$1" = "xfile" ] ; then + exec /etc/xen/scripts/block "$@" + fi + while true ; do + dev=$(losetup -f --show $2) + if [ -n "$dev" ] ; then break ; fi + done + hexnumber ${dev:9:70} + xenstore-write "$XENBUS_PATH/node" "$dev" \ + "$XENBUS_PATH/physical-device" "7:"$HEXNUMBER \ + "$XENBUS_PATH/hotplug-status" connected +} + +#exec 2>>/tmp/block.$$ +#set -x +export PATH="/sbin:/bin:/usr/bin:/usr/sbin:$PATH" + +XENBUS_PATH="${XENBUS_PATH:?}" +if ! [ "$1" = "add" ] || ! [ -f /var/run/qubes/fast_block_attach ] ; then + exec /etc/xen/scripts/block "$@" +fi + +vars=$(xenstore-read "$XENBUS_PATH/type" "$XENBUS_PATH/params") +process $vars +exit 0 diff --git a/dom0/restore/qubes_prepare_saved_domain.sh b/dom0/restore/qubes_prepare_saved_domain.sh new file mode 100755 index 00000000..cf994160 --- /dev/null +++ b/dom0/restore/qubes_prepare_saved_domain.sh @@ -0,0 +1,42 @@ +#!/bin/sh +if ! [ $# = 2 ] ; then + echo usage: $0 domainname savefile_to_be_created + exit 1 +fi +VMDIR=/var/lib/qubes/appvms/$1 +if ! [ -d $VMDIR ] ; then + echo $VMDIR does not exist ? + exit 1 +fi +if ! qvm-start $1 --no-guid ; then + exit 1 +fi + +ID=none +for i in $(xenstore-list /local/domain) ; do + name=$(xenstore-read /local/domain/$i/name) + if [ "x"$name = "x"$1 ] ; then + ID=$i + fi +done +set -x +if [ $ID = none ] ; then + echo cannot get domain id + exit 1 +fi +echo domainid=$ID +xenstore-write /local/domain/$ID/qubes_save_request 1 +xenstore-watch /local/domain/$ID/device/qubes_used_mem +xenstore-read /local/domain/$ID/qubes_gateway | \ + cut -d . -f 2 | tr -d "\n" > $VMDIR/netvm_id.txt +xm block-detach $1 /dev/xvdb +MEM=$(xenstore-read /local/domain/$ID/device/qubes_used_mem) +echo MEM=$MEM +xm mem-set $1 $(($MEM/1000)) +sleep 1 +touch $2 +xm save $1 $2 +cd $VMDIR +tar -Scvf saved_cows.tar root-cow.img swap-cow.img + + diff --git a/dom0/restore/qubes_restore.c b/dom0/restore/qubes_restore.c new file mode 100644 index 00000000..8ebb742f --- /dev/null +++ b/dom0/restore/qubes_restore.c @@ -0,0 +1,406 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char xmlrpc_header[] = + "POST /RPC2 HTTP/1.0\r\n" + "Host: \r\n" + "User-Agent: xmlrpclib.py/1.0.1 (by www.pythonware.com)\r\n" + "Content-Type: text/xml\r\n" "Content-Length: %d\r\n" "\r\n"; +char xmlrpc_body_restore[] = + "\n" + "\n" + "xend.domain.restore\n" + "\n" + "\n" + "%s\n" + "\n" + "\n" + "0\n" + "\n" "\n" "\n"; + +char xmlrpc_body_setmem[] = + "\n\nxend.domain.setMemoryTarget\n\n\n%d\n\n\n%d\n\n\n\n"; + +void send_raw(int fd, char *body) +{ + char *header; + asprintf(&header, xmlrpc_header, strlen(body)); + if (write(fd, header, strlen(header)) != strlen(header)) { + perror("write xend"); + exit(1); + } + if (write(fd, body, strlen(body)) != strlen(body)) { + perror("write xend"); + exit(1); + } + shutdown(fd, SHUT_WR); +} + + +void send_req_restore(int fd, char *name) +{ + char *body; + asprintf(&body, xmlrpc_body_restore, name); + send_raw(fd, body); +} + +void send_req_setmem(int fd, int domid, int mem) +{ + char *body; + asprintf(&body, xmlrpc_body_setmem, domid, mem); + send_raw(fd, body); +} + +char *recv_resp(int fd) +{ +#define RESPSIZE 65536 + static char buf[RESPSIZE]; + int total = 0; + int n; + for (;;) { + n = read(fd, buf + total, RESPSIZE - total); + if (n == 0) { + buf[total] = 0; + close(fd); + return buf; + } + if (n < 0) { + perror("xend read"); + exit(1); + } + total += n; + } +} + +void bad_resp(char *resp) +{ + fprintf(stderr, "Error; Xend response:\n%s\n", resp); + exit(1); +} + +int parse_resp(char *resp) +{ + char *domid; + if (strstr(resp, "")) + bad_resp(resp); + if (!strstr(resp, "domid")) + bad_resp(resp); + domid = strstr(resp, ""); + if (!domid) + bad_resp(resp); + return strtoul(domid + 5, NULL, 0); +} + +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; +#define FAST_FLAG_PATH "/var/run/qubes/fast_block_attach" +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); + } +} + +int xend_connect() +{ + struct sockaddr_un server; + int s; + + s = socket(AF_UNIX, SOCK_STREAM, 0); + if (s < 0) { + perror("socket af_unix"); + exit(1); + } + server.sun_family = AF_UNIX; + strcpy(server.sun_path, "/var/run/xend/xmlrpc.sock"); + if (connect + (s, (struct sockaddr *) &server, + strlen(server.sun_path) + sizeof(server.sun_family))) { + perror("connext xend"); + exit(1); + } + return s; +} + +void start_guid(int domid, int argc, char **argv) +{ + char dstr[40]; + snprintf(dstr, sizeof(dstr), "%d", domid); + if (argc == 2) + execl("/usr/bin/qubes_guid", "guid", "-d", dstr, "-c", + "red", "-i", "red", NULL); + else + execl("/usr/bin/qubes_guid", "guid", "-d", dstr, "-c", + "red", "-i", "red", "-e", argv[2], NULL); + perror("execl"); +} + +void fix_savefile(int fd, char *buf, char *pattern, char *val) +{ + int i, len = strlen(val), origlen; + char *bracket; + char *loc = strstr(buf + 20, pattern) + strlen(pattern); + if (!loc) + return; + bracket = index(loc, ')'); + if (!bracket) + return; + origlen = (long) bracket - (long) loc; + if (origlen < len) { + fprintf(stderr, "too long string %s\n", val); + exit(1); + } + for (i = 0; i < origlen - len; i++) + loc[i] = ' '; + memcpy(loc + i, val, strlen(val)); + lseek(fd, (long) loc - (long) buf, SEEK_SET); + write(fd, loc, origlen); +} + + + + + + +#define NAME_PATTERN "/root-cow.img" +char *fix_savefile_and_get_vmname(int fd, int dispid) +{ + static char buf[4096]; + char *name; + char *slash; + char val[256]; + if (read(fd, buf, sizeof(buf)) != sizeof(buf)) { + perror("read savefile"); + exit(1); + } + buf[sizeof(buf) - 1] = 0; + snprintf(val, sizeof(val), + "064cd14c-95ad-4fc2-a4c9-cf9f522e5b%02x", dispid); + fix_savefile(fd, buf, "(uuid ", val); + snprintf(val, sizeof(val), "disp%02d", dispid); + fix_savefile(fd, buf, "(name ", val); + snprintf(val, sizeof(val), "00:16:3e:7c:8b:%02x", dispid); + fix_savefile(fd, buf, "(mac ", val); + lseek(fd, 0, SEEK_SET); + name = strstr(buf + 20, NAME_PATTERN); + if (!name) { + fprintf(stderr, + "cannot find 'root-cow.img' in savefile\n"); + 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; +} + +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), + "/var/lib/qubes/appvms/%s/saved_cows.tar", name); + 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); + } +} + + +void setup_xenstore(int domid, char *name) +{ + char val[256]; + char netvm_id_path[256]; + int fd, n; + char netvm_id[256]; + struct xs_handle *xs = xs_daemon_open(); + if (!xs) { + perror("xs_daemon_open"); + exit(1); + } + snprintf(netvm_id_path, sizeof(netvm_id_path), + "/var/lib/qubes/appvms/%s/netvm_id.txt", name); + 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; + + snprintf(val, sizeof(val), "10.%s.%d.%d", netvm_id, + domid / 254 + 200, (domid % 254) + 1); + write_xs_single(xs, domid, "qubes_ip", val); + write_xs_single(xs, domid, "qubes_netmask", "255.255.0.0"); + snprintf(val, sizeof(val), "10.%s.0.1", netvm_id); + write_xs_single(xs, domid, "qubes_gateway", val); + snprintf(val, sizeof(val), "10.%s.255.254", netvm_id); + write_xs_single(xs, domid, "qubes_secondary_dns", val); + write_xs_single(xs, domid, "qubes_vm_type", "AppVM"); + xs_daemon_close(xs); + +} + +int get_next_disposable_id() +{ + int seq = 0; + int fd = open("/var/run/qubes/dispVM_seq", O_RDWR); + if (fd < 0) { + perror("open dispVM_seq"); + exit(1); + } + read(fd, &seq, sizeof(seq)); + seq++; + lseek(fd, 0, SEEK_SET); + write(fd, &seq, sizeof(seq)); + close(fd); + return seq; +} + +void write_varrun_domid(int domid) +{ + FILE *f = fopen("/var/run/qubes/dispVM_xid", "w"); + if (!f) { + perror("fopen dispVM_xid"); + exit(1); + } + fprintf(f, "%d", domid); + fclose(f); +} + + +int main(int argc, char **argv) +{ + int fd, domid, dispid; + char *resp; + char *name; + if (argc != 2 && argc != 3) { + fprintf(stderr, "usage: %s savefile\n", argv[0]); + exit(1); + } + fprintf(stderr, "time=%s, starting\n", gettime()); + set_fast_flag(); + atexit(rm_fast_flag); + fd = open(argv[1], O_RDWR); + if (fd < 0) { + perror("open savefile"); + exit(1); + } + dispid = get_next_disposable_id(); + name = fix_savefile_and_get_vmname(fd, dispid); +// printf("name=%s\n", name); + unpack_cows(name); +// no preloading for now, assume savefile in shm +// preload_cache(fd); + fd = xend_connect(); + send_req_restore(fd, argv[1]); + resp = recv_resp(fd); + domid = parse_resp(resp); + write_varrun_domid(domid); + fprintf(stderr, + "time=%s, created domid=%d, executing set_mem 400\n", + gettime(), domid); + fd = xend_connect(); + send_req_setmem(fd, domid, 400); + resp = recv_resp(fd); +// printf("%s\n", resp); + fprintf(stderr, "time=%s, creating xenstore entries\n", gettime()); + setup_xenstore(domid, name); + fprintf(stderr, "time=%s, starting qubes_guid\n", gettime()); + rm_fast_flag(); + start_guid(domid, argc, argv); + return 0; +} diff --git a/dom0/restore/xenstore-watch.c b/dom0/restore/xenstore-watch.c new file mode 100644 index 00000000..2e622d8b --- /dev/null +++ b/dom0/restore/xenstore-watch.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include +main(int argc, char **argv) +{ + struct xs_handle *xs; + unsigned int count; + char **vec; + char dummy; + if (argc != 2) { + fprintf(stderr, "usage: %s xenstore_path\n", argv[0]); + exit(1); + } + xs = xs_daemon_open(); + if (!xs) { + perror("xs_daemon_open"); + exit(1); + } + if (!xs_watch(xs, argv[1], &dummy)) { + perror("xs_watch"); + exit(1); + } + vec = xs_read_watch(xs, &count); + free(vec); + vec = xs_read_watch(xs, &count); + free(vec); +} diff --git a/rpm_spec/core-appvm.spec b/rpm_spec/core-appvm.spec index 75ce8530..0319b3fe 100644 --- a/rpm_spec/core-appvm.spec +++ b/rpm_spec/core-appvm.spec @@ -60,7 +60,7 @@ mkdir -p $RPM_BUILD_ROOT/etc/init.d cp qubes_core $RPM_BUILD_ROOT/etc/init.d/ mkdir -p $RPM_BUILD_ROOT/var/lib/qubes mkdir -p $RPM_BUILD_ROOT/usr/bin -cp qubes_add_pendrive_script qubes_penctl qvm-copy-to-vm qvm-copy-to-vm.kde $RPM_BUILD_ROOT/usr/bin +cp qubes_timestamp qubes_add_pendrive_script qubes_penctl qvm-copy-to-vm qvm-copy-to-vm.kde $RPM_BUILD_ROOT/usr/bin mkdir -p $RPM_BUILD_ROOT/%{kde_service_dir} cp qvm-copy.desktop $RPM_BUILD_ROOT/%{kde_service_dir} mkdir -p $RPM_BUILD_ROOT/etc/udev/rules.d @@ -77,6 +77,9 @@ cp ../common/qubes_serial_login $RPM_BUILD_ROOT/sbin mkdir -p $RPM_BUILD_ROOT/etc cp ../common/serial.conf $RPM_BUILD_ROOT/var/lib/qubes/ +mkdir -p $RPM_BUILD_ROOT/home_volatile/user +chown 500:500 $RPM_BUILD_ROOT/home_volatile/user + %triggerin -- initscripts cp /var/lib/qubes/serial.conf /etc/init/serial.conf @@ -186,3 +189,6 @@ rm -rf $RPM_BUILD_ROOT %dir /mnt/removable /etc/yum.repos.d/qubes.repo /sbin/qubes_serial_login +/usr/bin/qubes_timestamp +%dir /home_volatile +%attr(700,user,user) /home_volatile/user diff --git a/rpm_spec/core-dom0.spec b/rpm_spec/core-dom0.spec index 753f93cf..4de584e6 100644 --- a/rpm_spec/core-dom0.spec +++ b/rpm_spec/core-dom0.spec @@ -46,6 +46,7 @@ The Qubes core files for installation on Dom0. %build python -m compileall qvm-core python -O -m compileall qvm-core +make -C restore %install @@ -57,6 +58,12 @@ mkdir -p $RPM_BUILD_ROOT/usr/bin/ cp qvm-tools/qvm-* $RPM_BUILD_ROOT/usr/bin cp clipboard_notifier/qclipd $RPM_BUILD_ROOT/usr/bin cp pendrive_swapper/qfilexchgd $RPM_BUILD_ROOT/usr/bin +cp restore/xenstore-watch $RPM_BUILD_ROOT/usr/bin +cp restore/qubes_restore $RPM_BUILD_ROOT/usr/bin +cp restore/qubes_prepare_saved_domain.sh $RPM_BUILD_ROOT/usr/bin + +mkdir -p $RPM_BUILD_ROOT/etc/xen/scripts +cp restore/block.qubes $RPM_BUILD_ROOT/etc/xen/scripts mkdir -p $RPM_BUILD_ROOT%{python_sitearch}/qubes cp qvm-core/qubes.py $RPM_BUILD_ROOT%{python_sitearch}/qubes @@ -99,6 +106,9 @@ mkdir -p $RPM_BUILD_ROOT/usr/lib64/pm-utils/sleep.d cp pm-utils/01qubes-sync-vms-clock $RPM_BUILD_ROOT/usr/lib64/pm-utils/sleep.d/ cp pm-utils/02qubes-pause-vms $RPM_BUILD_ROOT/usr/lib64/pm-utils/sleep.d/ +%triggerin -- xen-runtime +sed -i 's/\/block /\/block.qubes /' /etc/udev/rules.d/xen-backend.rules + %post if [ -e /etc/yum.repos.d/qubes-r1-dom0.repo ]; then @@ -167,6 +177,7 @@ if [ "$1" = 0 ] ; then chgrp root /etc/xen chmod 700 /etc/xen groupdel qubes + sed -i 's/\/block.qubes /\/block /' /etc/udev/rules.d/xen-backend.rules fi %files @@ -202,3 +213,7 @@ fi /etc/sysconfig/iptables /usr/lib64/pm-utils/sleep.d/01qubes-sync-vms-clock /usr/lib64/pm-utils/sleep.d/02qubes-pause-vms +/usr/bin/xenstore-watch +/usr/bin/qubes_restore +/usr/bin/qubes_prepare_saved_domain.sh +/etc/xen/scripts/block.qubes