Merge branch 'dispvm'
This commit is contained in:
commit
fd619b605c
@ -1,9 +1,11 @@
|
||||
CC=gcc
|
||||
CFLAGS=-Wall
|
||||
all: qubes_penctl qubes_add_pendrive_script
|
||||
all: qubes_penctl qubes_add_pendrive_script qvm-open-in-dvm
|
||||
qubes_penctl: qubes_penctl.o
|
||||
$(CC) -o qubes_penctl qubes_penctl.o -lxenstore
|
||||
qubes_add_pendrive_script: qubes_add_pendrive_script.o
|
||||
$(CC) -o qubes_add_pendrive_script qubes_add_pendrive_script.o
|
||||
$(CC) -o qubes_add_pendrive_script qubes_add_pendrive_script.o -lxenstore
|
||||
qvm-open-in-dvm: qvm-open-in-dvm.o
|
||||
$(CC) -o qvm-open-in-dvm qvm-open-in-dvm.o -lxenstore
|
||||
clean:
|
||||
rm -f qubes_penctl qubes_add_pendrive_script *.o *~
|
||||
rm -f qubes_penctl qubes_add_pendrive_script qvm-open-in-dvm *.o *~
|
||||
|
6
appvm/dvm.h
Normal file
6
appvm/dvm.h
Normal file
@ -0,0 +1,6 @@
|
||||
#define DBDIR "/home/user/.dvm"
|
||||
struct dvm_header {
|
||||
unsigned long long file_size;
|
||||
char name[1024-sizeof(unsigned long long)];
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -1 +1 @@
|
||||
SUBSYSTEM=="block", KERNEL=="xvdh", ACTION=="add", RUN+="/usr/bin/qubes_add_pendrive_script"
|
||||
SUBSYSTEM=="block", KERNEL=="xvdh", ACTION=="add", RUN+="/usr/lib/qubes/qubes_add_pendrive_script"
|
||||
|
@ -18,17 +18,25 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <xs.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include "dvm.h"
|
||||
|
||||
int parse_events(char *buf, int len)
|
||||
{
|
||||
int i = 0;
|
||||
while (i < len) {
|
||||
struct inotify_event *ev = (struct inotify_event *)(buf + i);
|
||||
struct inotify_event *ev =
|
||||
(struct inotify_event *) (buf + i);
|
||||
if ((ev->mask & IN_UNMOUNT) || (ev->mask & IN_IGNORED))
|
||||
return 1;
|
||||
i += sizeof(struct inotify_event) + ev->len;
|
||||
@ -69,19 +77,201 @@ void background()
|
||||
switch (fork()) {
|
||||
case -1:
|
||||
exit(1);
|
||||
case 0: break;
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
int check_legal_filename(char *name)
|
||||
{
|
||||
if (index(name, '/')) {
|
||||
syslog(LOG_DAEMON | LOG_ERR,
|
||||
"the received filename contains /");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void drop_to_user()
|
||||
{
|
||||
struct passwd *pw = getpwnam("user");
|
||||
if (pw)
|
||||
setuid(pw->pw_uid);
|
||||
}
|
||||
|
||||
int copy_from_xvdh(int destfd, int srcfd, unsigned long long count)
|
||||
{
|
||||
int n, size;
|
||||
char buf[4096];
|
||||
unsigned long long total = 0;
|
||||
while (total < count) {
|
||||
if (count - total > sizeof(buf))
|
||||
size = sizeof(buf);
|
||||
else
|
||||
size = count - total;
|
||||
n = read(srcfd, buf, size);
|
||||
if (n != size) {
|
||||
syslog(LOG_DAEMON | LOG_ERR, "reading xvdh");
|
||||
return 0;
|
||||
}
|
||||
if (write(destfd, buf, size) != size) {
|
||||
syslog(LOG_DAEMON | LOG_ERR, "writing file");
|
||||
return 0;
|
||||
}
|
||||
total += size;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void redirect_stderr()
|
||||
{
|
||||
int fd =
|
||||
open("/var/log/dvm.log", O_CREAT | O_TRUNC | O_WRONLY, 0600);
|
||||
if (fd < 0) {
|
||||
syslog(LOG_DAEMON | LOG_ERR, "open dvm.log");
|
||||
exit(1);
|
||||
}
|
||||
dup2(fd, 2);
|
||||
}
|
||||
|
||||
void suicide(struct xs_handle *xs)
|
||||
{
|
||||
xs_write(xs, XBT_NULL, "device/qpen", "killme", 6);
|
||||
xs_daemon_close(xs);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void dvm_transaction_request(char *seq, struct xs_handle *xs)
|
||||
{
|
||||
char filename[1024], cmdbuf[1024];
|
||||
struct dvm_header header;
|
||||
int xvdh_fd, file_fd;
|
||||
char *src_vm;
|
||||
unsigned int len;
|
||||
struct stat stat_pre, stat_post;
|
||||
xvdh_fd = open("/dev/xvdh", O_RDONLY);
|
||||
if (read(xvdh_fd, &header, sizeof(header)) != sizeof(header)) {
|
||||
syslog(LOG_DAEMON | LOG_ERR, "read dvm_header");
|
||||
suicide(xs);
|
||||
}
|
||||
|
||||
header.name[sizeof(header.name) - 1] = 0;
|
||||
if (!check_legal_filename(header.name))
|
||||
suicide(xs);
|
||||
snprintf(filename, sizeof(filename), "/tmp/%s", header.name);
|
||||
drop_to_user();
|
||||
|
||||
file_fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);
|
||||
if (file_fd < 0) {
|
||||
syslog(LOG_DAEMON | LOG_ERR, "open file");
|
||||
suicide(xs);
|
||||
}
|
||||
if (!copy_from_xvdh(file_fd, xvdh_fd, header.file_size))
|
||||
suicide(xs);
|
||||
close(xvdh_fd);
|
||||
close(file_fd);
|
||||
if (stat(filename, &stat_pre)) {
|
||||
syslog(LOG_DAEMON | LOG_ERR, "stat pre");
|
||||
suicide(xs);
|
||||
}
|
||||
snprintf(cmdbuf, sizeof(cmdbuf),
|
||||
"DISPLAY=:0 mimeopen -n '/tmp/%s'", header.name);
|
||||
if (system(cmdbuf))
|
||||
system("DISPLAY=:0 /usr/bin/kdialog --sorry 'Unable to handle mimetype of the requested file'");
|
||||
if (stat(filename, &stat_post)) {
|
||||
syslog(LOG_DAEMON | LOG_ERR, "stat post");
|
||||
suicide(xs);
|
||||
}
|
||||
src_vm = xs_read(xs, XBT_NULL, "qubes_blocksrc", &len);
|
||||
xs_write(xs, XBT_NULL, "device/qpen", "umount", 6);
|
||||
if (stat_pre.st_mtime == stat_post.st_mtime)
|
||||
suicide(xs);
|
||||
xs_daemon_close(xs);
|
||||
execl("/usr/lib/qubes/qvm-dvm-transfer", "qvm-dvm-transfer", src_vm,
|
||||
filename, seq, NULL);
|
||||
syslog(LOG_DAEMON | LOG_ERR, "execl qvm-dvm-transfer");
|
||||
suicide(xs);
|
||||
}
|
||||
|
||||
void dvm_transaction_return(char *seq_string, struct xs_handle *xs)
|
||||
{
|
||||
int seq = strtoul(seq_string, 0, 10);
|
||||
char db_name[1024];
|
||||
char file_name[1024];
|
||||
int db_fd, file_fd, xvdh_fd;
|
||||
|
||||
struct dvm_header header;
|
||||
xvdh_fd = open("/dev/xvdh", O_RDONLY);
|
||||
if (xvdh_fd < 0) {
|
||||
syslog(LOG_DAEMON | LOG_ERR, "open xvdh");
|
||||
goto out_err;
|
||||
}
|
||||
if (read(xvdh_fd, &header, sizeof(header)) != sizeof(header)) {
|
||||
syslog(LOG_DAEMON | LOG_ERR, "read dvm_header");
|
||||
goto out_err;
|
||||
}
|
||||
drop_to_user();
|
||||
snprintf(db_name, sizeof(db_name), DBDIR "/%d", seq);
|
||||
db_fd = open(db_name, O_RDONLY);
|
||||
if (!db_fd) {
|
||||
syslog(LOG_DAEMON | LOG_ERR, "open db");
|
||||
goto out_err;
|
||||
}
|
||||
if (read(db_fd, file_name, sizeof(file_name)) < 0) {
|
||||
syslog(LOG_DAEMON | LOG_ERR, "read db");
|
||||
goto out_err;
|
||||
}
|
||||
close(db_fd);
|
||||
file_fd = open(file_name, O_WRONLY | O_TRUNC);
|
||||
if (file_fd < 0) {
|
||||
syslog(LOG_DAEMON | LOG_ERR, "open filename");
|
||||
goto out_err;
|
||||
}
|
||||
copy_from_xvdh(file_fd, xvdh_fd, header.file_size);
|
||||
close(xvdh_fd);
|
||||
close(file_fd);
|
||||
out_err:
|
||||
xs_write(xs, XBT_NULL, "device/qpen", "umount", 6);
|
||||
xs_daemon_close(xs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void dvm_transaction(char *seq, struct xs_handle *xs)
|
||||
{
|
||||
struct stat st;
|
||||
redirect_stderr();
|
||||
if (stat("/etc/this_is_dvm", &st))
|
||||
dvm_transaction_return(seq, xs);
|
||||
else
|
||||
dvm_transaction_request(seq, xs);
|
||||
}
|
||||
|
||||
#define MOUNTDIR "/mnt/incoming"
|
||||
int main()
|
||||
{
|
||||
struct xs_handle *xs;
|
||||
char *seq;
|
||||
unsigned int len;
|
||||
background();
|
||||
openlog("qubes_add_pendrive_script", LOG_CONS | LOG_PID,
|
||||
LOG_DAEMON);
|
||||
xs = xs_domain_open();
|
||||
if (!xs) {
|
||||
syslog(LOG_DAEMON | LOG_ERR, "xs_domain_open");
|
||||
exit(1);
|
||||
}
|
||||
seq = xs_read(xs, XBT_NULL, "qubes_transaction_seq", &len);
|
||||
if (seq && len > 0 && strcmp(seq, "0")) {
|
||||
dvm_transaction(seq, xs);
|
||||
exit(0);
|
||||
}
|
||||
if (!system("su - user -c 'mount " MOUNTDIR "'"))
|
||||
wait_for_umount(MOUNTDIR "/.");
|
||||
system("xenstore-write device/qpen umount");
|
||||
xs_write(xs, XBT_NULL, "device/qpen", "umount", 6);
|
||||
xs_daemon_close(xs);
|
||||
return 0;
|
||||
}
|
||||
|
@ -6,6 +6,18 @@
|
||||
# Source function library.
|
||||
. /etc/rc.d/init.d/functions
|
||||
|
||||
possibly_run_save_script()
|
||||
{
|
||||
ENCODED_SCRIPT=$(xenstore-read qubes_save_script)
|
||||
if [ -z "$ENCODED_SCRIPT" ] ; then return ; fi
|
||||
echo $ENCODED_SCRIPT|perl -e 'use MIME::Base64 qw(decode_base64); local($/) = undef;print decode_base64(<STDIN>)' >/tmp/qubes_save_script
|
||||
chmod 755 /tmp/qubes_save_script
|
||||
Xorg -config /etc/X11/xorg-preload-apps.conf :0 &
|
||||
sleep 2
|
||||
DISPLAY=:0 su - user -c /tmp/qubes_save_script
|
||||
killall Xorg
|
||||
}
|
||||
|
||||
start()
|
||||
{
|
||||
echo -n $"Executing Qubes Core scripts:"
|
||||
@ -14,6 +26,22 @@ start()
|
||||
echo "ERROR: /usr/bin/xenstore-read not found!"
|
||||
exit 1
|
||||
fi
|
||||
if xenstore-read qubes_save_request 2>/dev/null ; then
|
||||
possibly_run_save_script
|
||||
touch /etc/this_is_dvm
|
||||
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 +57,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
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <xs.h>
|
||||
int check_name(unsigned char *s)
|
||||
void check_name(unsigned char *s)
|
||||
{
|
||||
int c;
|
||||
for (; *s; s++) {
|
||||
@ -35,14 +35,21 @@ int check_name(unsigned char *s)
|
||||
continue;
|
||||
if (c == '_' || c == '-')
|
||||
continue;
|
||||
return 0;
|
||||
fprintf(stderr, "invalid string %s\n", s);
|
||||
exit(1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void usage(char *argv0)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [new|umount]\n"
|
||||
"%s send vmname [seq]\n", argv0, argv0);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char buf[256] = "new";
|
||||
char buf[256];
|
||||
struct xs_handle *xs;
|
||||
xs = xs_domain_open();
|
||||
setuid(getuid());
|
||||
@ -50,18 +57,25 @@ int main(int argc, char **argv)
|
||||
perror("xs_domain_open");
|
||||
exit(1);
|
||||
}
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "usage: %s new\n"
|
||||
"%s send vmname\n", argv[0], argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
if (argc > 2) {
|
||||
if (!check_name((unsigned char*)argv[2])) {
|
||||
fprintf(stderr, "invalid vmname %s\n", argv[2]);
|
||||
exit(1);
|
||||
}
|
||||
switch (argc) {
|
||||
case 2:
|
||||
if (!strcmp(argv[1], "umount"))
|
||||
strcpy(buf, "umount");
|
||||
else
|
||||
strcpy(buf, "new");
|
||||
break;
|
||||
case 3:
|
||||
check_name((unsigned char *) argv[2]);
|
||||
snprintf(buf, sizeof(buf), "send %s", argv[2]);
|
||||
break;
|
||||
case 4:
|
||||
check_name((unsigned char *) argv[2]);
|
||||
check_name((unsigned char *) argv[3]);
|
||||
snprintf(buf, sizeof(buf), "send %s %s", argv[2], argv[3]);
|
||||
default:
|
||||
usage(argv[0]);
|
||||
}
|
||||
|
||||
if (!xs_write(xs, 0, "device/qpen", buf, strlen(buf))) {
|
||||
perror("xs_write");
|
||||
exit(1);
|
||||
|
2
appvm/qubes_timestamp
Executable file
2
appvm/qubes_timestamp
Executable file
@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
exec xenstore-write device/qubes_timestamp $(date +%s.%N)
|
@ -24,7 +24,7 @@ if [ $# -lt 2 ] ; then
|
||||
echo usage: $0 'vmname file [file]*'
|
||||
exit 1
|
||||
fi
|
||||
qubes_penctl new || exit 1
|
||||
/usr/lib/qubes/qubes_penctl new || exit 1
|
||||
echo -n Waiting for the Qubes virtual pendrive
|
||||
while ! [ -e /dev/xvdg ] ; do
|
||||
echo -n .
|
||||
@ -37,4 +37,4 @@ shift
|
||||
cp -v -a "$@" /mnt/outgoing
|
||||
#sometimes Dolphin lags a bit
|
||||
umount /mnt/outgoing || (sleep 1; umount /mnt/outgoing) || exit 1
|
||||
qubes_penctl send $VMNAME || exit 1
|
||||
/usr/lib/qubes/qubes_penctl send $VMNAME || exit 1
|
||||
|
@ -4,7 +4,7 @@ Type=Service
|
||||
X-KDE-ServiceTypes=KonqPopupMenu/Plugin,inode/directory,all/allfiles
|
||||
|
||||
[Desktop Action QvmCopy]
|
||||
Exec=/usr/bin/qvm-copy-to-vm.kde %U
|
||||
Exec=/usr/lib/qubes/qvm-copy-to-vm.kde %U
|
||||
Icon=kget
|
||||
Name=Send To VM
|
||||
|
||||
|
10
appvm/qvm-dvm.desktop
Normal file
10
appvm/qvm-dvm.desktop
Normal file
@ -0,0 +1,10 @@
|
||||
[Desktop Entry]
|
||||
Actions=QvmDvm;
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=KonqPopupMenu/Plugin,all/allfiles
|
||||
|
||||
[Desktop Action QvmDvm]
|
||||
Exec=/usr/bin/qvm-open-in-dvm disposable %U
|
||||
Icon=kget
|
||||
Name=Open In DisposableVM
|
||||
|
176
appvm/qvm-open-in-dvm.c
Normal file
176
appvm/qvm-open-in-dvm.c
Normal file
@ -0,0 +1,176 @@
|
||||
/*
|
||||
* The Qubes OS Project, http://www.qubes-os.org
|
||||
*
|
||||
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <xs.h>
|
||||
#include "dvm.h"
|
||||
|
||||
void check_name(unsigned char *s)
|
||||
{
|
||||
int c;
|
||||
for (; *s; s++) {
|
||||
c = *s;
|
||||
if (c >= 'a' && c <= 'z')
|
||||
continue;
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
continue;
|
||||
if (c == '_' || c == '-')
|
||||
continue;
|
||||
fprintf(stderr, "invalid string %s\n", s);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int get_and_set_seq()
|
||||
{
|
||||
int seq_fd, seq, n;
|
||||
mkdir(DBDIR, 0700);
|
||||
seq_fd = open(DBDIR "/seq", O_CREAT | O_RDWR, 0600);
|
||||
if (seq_fd < 0) {
|
||||
perror("open seq_fd");
|
||||
exit(1);
|
||||
}
|
||||
n = read(seq_fd, &seq, sizeof(seq));
|
||||
if (n < sizeof(seq))
|
||||
seq = 0;
|
||||
seq++;
|
||||
lseek(seq_fd, 0, SEEK_SET);
|
||||
write(seq_fd, &seq, sizeof(seq));
|
||||
close(seq_fd);
|
||||
return seq;
|
||||
}
|
||||
|
||||
void write_db(char *name, int seq)
|
||||
{
|
||||
int db_fd;
|
||||
char dbname[256];
|
||||
struct stat st;
|
||||
if (!stat("/etc/this_is_dvm", &st))
|
||||
return;
|
||||
snprintf(dbname, sizeof(dbname), DBDIR "/%d", seq);
|
||||
db_fd = open(dbname, O_CREAT | O_WRONLY | O_TRUNC, 0600);
|
||||
if (db_fd < 0) {
|
||||
perror("open dbfile");
|
||||
exit(1);
|
||||
}
|
||||
if (write(db_fd, name, strlen(name) + 1) != strlen(name) + 1) {
|
||||
perror("write db");
|
||||
exit(1);
|
||||
}
|
||||
close(db_fd);
|
||||
}
|
||||
|
||||
void copy_file(int xvdg_fd, int file_fd)
|
||||
{
|
||||
int n;
|
||||
char buf[4096];
|
||||
|
||||
for (;;) {
|
||||
n = read(file_fd, buf, sizeof(buf));
|
||||
if (n < 0) {
|
||||
perror("read file");
|
||||
exit(1);
|
||||
}
|
||||
if (n == 0)
|
||||
break;
|
||||
if (write(xvdg_fd, buf, n) != n) {
|
||||
perror("write file");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct dvm_header header = { 0, };
|
||||
struct stat st;
|
||||
struct xs_handle *xs;
|
||||
int seq;
|
||||
int xvdg_fd, file_fd;
|
||||
char *abs_filename;
|
||||
char buf[4096];
|
||||
|
||||
if (argc != 3 && argc != 4) {
|
||||
fprintf(stderr, "usage: %s vmname file\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
check_name((unsigned char *) argv[1]);
|
||||
if (argv[2][0] == '/')
|
||||
abs_filename = argv[2];
|
||||
else {
|
||||
char cwd[4096];
|
||||
getcwd(cwd, sizeof(cwd));
|
||||
asprintf(&abs_filename, "%s/%s", cwd, argv[2]);
|
||||
}
|
||||
if (stat(abs_filename, &st)) {
|
||||
perror("stat file");
|
||||
exit(1);
|
||||
}
|
||||
header.file_size = st.st_size;
|
||||
strncpy(header.name, rindex(abs_filename, '/') + 1,
|
||||
sizeof(header.name) - 1);
|
||||
xs = xs_domain_open();
|
||||
if (!xs) {
|
||||
perror("xs_domain_open");
|
||||
exit(1);
|
||||
}
|
||||
if (!xs_write(xs, 0, "device/qpen", "new", 3)) {
|
||||
perror("xs_write");
|
||||
exit(1);
|
||||
}
|
||||
while (stat("/dev/xvdg", &st))
|
||||
usleep(100000);
|
||||
xvdg_fd = open("/dev/xvdg", O_WRONLY);
|
||||
if (xvdg_fd < 0) {
|
||||
perror("open xvdg");
|
||||
exit(1);
|
||||
}
|
||||
setuid(getuid());
|
||||
if (argc == 3)
|
||||
seq = get_and_set_seq();
|
||||
else
|
||||
seq = strtoul(argv[3], 0, 0);
|
||||
file_fd = open(abs_filename, O_RDONLY);
|
||||
if (file_fd < 0) {
|
||||
perror("open file");
|
||||
exit(1);
|
||||
}
|
||||
if (write(xvdg_fd, &header, sizeof(header)) != sizeof(header)) {
|
||||
perror("write filesize");
|
||||
exit(1);
|
||||
}
|
||||
copy_file(xvdg_fd, file_fd);
|
||||
close(file_fd);
|
||||
close(xvdg_fd);
|
||||
snprintf(buf, sizeof(buf), "send %s %d", argv[1], seq);
|
||||
if (!xs_write(xs, 0, "device/qpen", buf, strlen(buf))) {
|
||||
perror("xs_write");
|
||||
exit(1);
|
||||
}
|
||||
write_db(abs_filename, seq);
|
||||
xs_daemon_close(xs);
|
||||
return 0;
|
||||
}
|
30
appvm/xorg-preload-apps.conf
Normal file
30
appvm/xorg-preload-apps.conf
Normal file
@ -0,0 +1,30 @@
|
||||
Section "ServerLayout"
|
||||
Identifier "Default Layout"
|
||||
Screen 0 "Screen0" 0 0
|
||||
EndSection
|
||||
|
||||
Section "Device"
|
||||
Identifier "Videocard0"
|
||||
Driver "dummy"
|
||||
VideoRam 4001
|
||||
EndSection
|
||||
|
||||
Section "Monitor"
|
||||
Identifier "Monitor0"
|
||||
HorizSync 49-50
|
||||
VertRefresh 62-63
|
||||
Modeline "QB1280x800" 64 1280 1281 1282 1283 800 801 802 803
|
||||
EndSection
|
||||
|
||||
Section "Screen"
|
||||
Identifier "Screen0"
|
||||
Device "Videocard0"
|
||||
Monitor "Monitor0"
|
||||
DefaultDepth 24
|
||||
SubSection "Display"
|
||||
Viewport 0 0
|
||||
Depth 24
|
||||
Modes "QB1280x800"
|
||||
EndSubSection
|
||||
EndSection
|
||||
|
@ -1,2 +1,2 @@
|
||||
#!/bin/sh
|
||||
/usr/bin/qubes_setup_dnat_to_ns
|
||||
/usr/lib/qubes/qubes_setup_dnat_to_ns
|
||||
|
@ -10,7 +10,7 @@ addrule()
|
||||
fi
|
||||
}
|
||||
export PATH=$PATH:/sbin:/bin
|
||||
source /var/run/qubes_ns
|
||||
source /var/run/qubes/qubes_ns
|
||||
if [ "X"$NS1 = "X" ] ; then exit ; fi
|
||||
iptables -t nat -F PREROUTING
|
||||
FIRSTONE=yes
|
||||
|
@ -16,7 +16,27 @@
|
||||
# Source function library.
|
||||
. /etc/rc.d/init.d/functions
|
||||
|
||||
|
||||
setup_dvm_files()
|
||||
{
|
||||
ROOT=/var/lib/qubes/dvmdata/savefile_root
|
||||
DEFAULT=/var/lib/qubes/dvmdata/default_savefile
|
||||
if ! [ -f $DEFAULT ] ; then return ; fi
|
||||
if ! [ -f $ROOT ] ; then return ; fi
|
||||
if [ $ROOT -nt $DEFAULT ] ; then
|
||||
echo DVM require reconfiguration
|
||||
return
|
||||
fi
|
||||
if [ -f /var/lib/qubes/dvmdata/dont_use_shm ] ; then
|
||||
ln -s $DEFAULT /var/run/qubes/current_savefile
|
||||
else
|
||||
mkdir -m 770 /dev/shm/qubes
|
||||
chown root.qubes /dev/shm/qubes
|
||||
cp $DEFAULT /dev/shm/qubes/current_savefile
|
||||
chown root.qubes /dev/shm/qubes/current_savefile
|
||||
chmod 660 /dev/shm/qubes/current_savefile
|
||||
ln -s /dev/shm/qubes/current_savefile /var/run/qubes/current_savefile
|
||||
fi
|
||||
}
|
||||
|
||||
start()
|
||||
{
|
||||
@ -30,7 +50,12 @@ 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
|
||||
chown root:qubes /var/run/qubes/dispVM_seq
|
||||
chmod 660 /var/run/qubes/dispVM_seq
|
||||
xm mem-set 0 800
|
||||
cp /var/lib/qubes/qubes.xml /var/lib/qubes/backup/qubes-$(date +%F-%T).xml
|
||||
setup_dvm_files
|
||||
touch /var/lock/subsys/qubes_core
|
||||
success
|
||||
echo
|
||||
|
@ -31,11 +31,13 @@ start()
|
||||
|
||||
echo -n $"Setting up net backend in Dom0:"
|
||||
brctl addbr br0 || exit 1
|
||||
brctl stp br0 off
|
||||
brctl setfd br0 1
|
||||
ifconfig br0 10.0.0.1 netmask 255.255.0.0 up || exit 1
|
||||
ifconfig br0:1 10.0.255.254 netmask 255.255.0.0 up || exit 1
|
||||
echo "NS1=10.0.0.1" > /var/run/qubes_ns
|
||||
echo "NS2=10.0.255.254" >> /var/run/qubes_ns
|
||||
qubes_setup_dnat_to_ns
|
||||
echo "NS1=10.0.0.1" > /var/run/qubes/qubes_ns
|
||||
echo "NS2=10.0.255.254" >> /var/run/qubes/qubes_ns
|
||||
/usr/lib/qubes/qubes_setup_dnat_to_ns
|
||||
echo "1" > /proc/sys/net/ipv4/ip_forward || exit 1
|
||||
else
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
import xen.lowlevel.xs
|
||||
import os
|
||||
import os.path
|
||||
import sys
|
||||
import subprocess
|
||||
import daemon
|
||||
@ -32,6 +33,8 @@ from qubes.qubes import QubesDaemonPidfile
|
||||
|
||||
filename_seq = 50
|
||||
pen_cmd = '/usr/lib/qubes/qubes_pencmd'
|
||||
disposable_domains_dict = {}
|
||||
current_savefile = '/var/run/qubes/current_savefile'
|
||||
|
||||
def get_next_filename_seq():
|
||||
global filename_seq
|
||||
@ -71,7 +74,13 @@ class DomainState:
|
||||
self.send_seq = None
|
||||
self.rcv_seq = None
|
||||
self.waiting_sender = None
|
||||
self.allowed_dest = None
|
||||
self.allowed_seq = None
|
||||
|
||||
def killme(self):
|
||||
if not os.path.isfile('/etc/debug-dvm'):
|
||||
subprocess.call(['/usr/sbin/xm', 'destroy', self.domain_id])
|
||||
|
||||
def handle_request(self, request):
|
||||
req_ok = False
|
||||
if request is None:
|
||||
@ -79,9 +88,16 @@ class DomainState:
|
||||
tmp = request.split()
|
||||
rq = tmp[0]
|
||||
if len(tmp) > 1:
|
||||
arg = tmp[1]
|
||||
vmname = tmp[1]
|
||||
else:
|
||||
arg = None
|
||||
vmname = None
|
||||
if len(tmp) > 2:
|
||||
transaction_seq = tmp[2]
|
||||
else:
|
||||
transaction_seq = '0'
|
||||
if rq == 'killme':
|
||||
self.killme()
|
||||
req_ok = True
|
||||
if rq == 'new' and self.send_state == 'idle':
|
||||
self.send_seq = get_next_filename_seq()
|
||||
retcode = subprocess.call([pen_cmd, 'new', self.domain_id, self.send_seq])
|
||||
@ -89,9 +105,9 @@ class DomainState:
|
||||
if retcode == 0:
|
||||
self.send_state = 'has_clean_pendrive'
|
||||
req_ok = True
|
||||
if rq == 'send' and self.send_state == 'has_clean_pendrive' and arg is not None:
|
||||
logproc( 'send from ' + self.domain_id + ' to ' + arg)
|
||||
if self.handle_transfer(arg):
|
||||
if rq == 'send' and self.send_state == 'has_clean_pendrive' and vmname is not None:
|
||||
logproc( 'send from ' + self.domain_id + ' to ' + vmname)
|
||||
if self.handle_transfer(vmname, transaction_seq):
|
||||
self.send_state = 'idle'
|
||||
req_ok = True;
|
||||
if rq == 'umount' and self.rcv_state == 'has_loaded_pendrive':
|
||||
@ -112,7 +128,7 @@ class DomainState:
|
||||
tmp = self.waiting_sender
|
||||
self.waiting_sender = None
|
||||
if tmp.send_state == 'has_clean_pendrive':
|
||||
if tmp.handle_transfer(self.name):
|
||||
if tmp.handle_transfer(self.name, self.delayed_transaction_seq):
|
||||
tmp.send_state = 'idle'
|
||||
|
||||
if not req_ok:
|
||||
@ -129,7 +145,7 @@ class DomainState:
|
||||
else:
|
||||
return False
|
||||
|
||||
def handle_transfer(self, vmname):
|
||||
def handle_transfer_regular(self, vmname, transaction_seq):
|
||||
qvm_collection = QubesVmCollection()
|
||||
qvm_collection.lock_db_for_reading()
|
||||
qvm_collection.load()
|
||||
@ -147,19 +163,89 @@ class DomainState:
|
||||
if self.ask_to_umount(vmname):
|
||||
target.rcv_state='waits_to_umount'
|
||||
target.waiting_sender=self
|
||||
self.delayed_transaction_seq=transaction_seq
|
||||
logproc( 'target domain ' + target.domain_id + ' is not idle, now ' + target.rcv_state)
|
||||
return False
|
||||
retcode = subprocess.call(['/usr/bin/kdialog', '--yesno', 'Do you authorize pendrive transfer from ' + self.name + ' to ' + vmname + '?' , '--title', 'Security confirmation'])
|
||||
logproc('handle_transfer: kdialog retcode=' + str(retcode))
|
||||
if retcode != 0:
|
||||
return False
|
||||
if self.allowed_seq is not None:
|
||||
if self.allowed_seq != transaction_seq or self.allowed_dest != target.name:
|
||||
logproc('sender ' + self.name + ' receiver ' + target.name + ' : allowed attributes mismatch, denied')
|
||||
return False
|
||||
else:
|
||||
transaction_seq = '0'
|
||||
retcode = subprocess.call(['/usr/bin/kdialog', '--yesno', 'Do you authorize pendrive transfer from ' + self.name + ' to ' + vmname + '?' , '--title', 'Security confirmation'])
|
||||
logproc('handle_transfer: kdialog retcode=' + str(retcode))
|
||||
if retcode != 0:
|
||||
return False
|
||||
target.rcv_state='has_loaded_pendrive'
|
||||
retcode = subprocess.call([pen_cmd, 'send', self.domain_id, target.domain_id, self.send_seq])
|
||||
retcode = subprocess.call([pen_cmd, 'send', self.domain_id, target.domain_id, self.send_seq, transaction_seq])
|
||||
target.rcv_seq = self.send_seq
|
||||
self.send_seq = None
|
||||
logproc( 'set state of ' + target.domain_id + ' to has_loaded_pendrive, retcode=' + str(retcode))
|
||||
if self.allowed_seq is not None:
|
||||
self.killme()
|
||||
return True
|
||||
|
||||
def handle_transfer_disposable(self, transaction_seq):
|
||||
|
||||
qvm_collection = QubesVmCollection()
|
||||
qvm_collection.lock_db_for_writing()
|
||||
qvm_collection.load()
|
||||
|
||||
vm = qvm_collection.get_vm_by_name(self.name)
|
||||
if vm is None:
|
||||
logproc( 'Domain ' + vmname + ' does not exist ?')
|
||||
qvm_collection.unlock_db()
|
||||
return False
|
||||
retcode = subprocess.call(['/usr/lib/qubes/qubes_restore',
|
||||
current_savefile,
|
||||
'-c', vm.label.color,
|
||||
'-i', vm.label.icon,
|
||||
'-l', str(vm.label.index)])
|
||||
if retcode != 0:
|
||||
subprocess.call(['/usr/bin/kdialog', '--sorry', 'DisposableVM creation failed, see qubes_restore.log'])
|
||||
qvm_collection.unlock_db()
|
||||
return False
|
||||
f = open('/var/run/qubes/dispVM_xid', 'r');
|
||||
disp_xid = f.readline().rstrip('\n')
|
||||
disp_name = f.readline().rstrip('\n')
|
||||
disptempl = f.readline().rstrip('\n')
|
||||
f.close()
|
||||
vm_disptempl = qvm_collection.get_vm_by_name(disptempl);
|
||||
if vm_disptempl is None:
|
||||
logproc( 'Domain ' + disptempl + ' does not exist ?')
|
||||
qvm_collection.unlock_db()
|
||||
return False
|
||||
qvm_collection.add_new_appvm(disp_name, vm_disptempl.template_vm, label=vm.label)
|
||||
qvm_collection.save()
|
||||
qvm_collection.unlock_db()
|
||||
|
||||
dispdom = DomainState(disp_xid, self.domdict)
|
||||
disposable_domains_dict[disp_xid] = dispdom
|
||||
retcode = subprocess.call([pen_cmd, 'send', self.domain_id, disp_xid, self.send_seq, transaction_seq])
|
||||
dispdom.rcv_seq = self.send_seq
|
||||
dispdom.rcv_state = 'has_loaded_pendrive'
|
||||
dispdom.allowed_dest = self.name
|
||||
dispdom.allowed_seq = transaction_seq
|
||||
self.send_seq = None
|
||||
logproc( 'sent pendrive to disposable xid ' + disp_xid)
|
||||
return True
|
||||
|
||||
def handle_transfer(self, vmname, transaction_seq):
|
||||
dvmdata_dir = '/var/lib/qubes/dvmdata/'
|
||||
if vmname != 'disposable':
|
||||
return self.handle_transfer_regular(vmname, transaction_seq)
|
||||
if not os.path.isfile(current_savefile):
|
||||
subprocess.call(['/usr/bin/kdialog', '--sorry', 'There is no current savefile defined; run Qubes Manager'])
|
||||
return False
|
||||
if not os.path.isfile(dvmdata_dir+'default_savefile') or not os.path.isfile(dvmdata_dir+'savefile_root'):
|
||||
subprocess.call(['/usr/bin/kdialog', '--sorry', 'Default savefile misconfiguration; run Qubes Manager'])
|
||||
return False
|
||||
dvm_mtime = os.stat(current_savefile).st_mtime
|
||||
root_mtime = os.stat(dvmdata_dir+'savefile_root').st_mtime
|
||||
if dvm_mtime < root_mtime:
|
||||
subprocess.call(['/usr/bin/kdialog', '--sorry', 'Your current savefile is outdated, as you have updated the template VM. Run Qubes Manager and recreate the savefile'])
|
||||
return False
|
||||
return self.handle_transfer_disposable(transaction_seq)
|
||||
|
||||
class XS_Watcher:
|
||||
def __init__(self):
|
||||
@ -172,15 +258,21 @@ class XS_Watcher:
|
||||
if curr == None:
|
||||
return
|
||||
for i in only_in_first_list(curr, self.domdict.keys()):
|
||||
newdom = DomainState(i, self.domdict)
|
||||
if disposable_domains_dict.has_key(i):
|
||||
newdom = disposable_domains_dict[i]
|
||||
else:
|
||||
newdom = DomainState(i, self.domdict)
|
||||
newdom.name = ''
|
||||
self.domdict[i] = newdom
|
||||
newdom.watch_token = WatchType(XS_Watcher.request, newdom)
|
||||
newdom.watch_name = WatchType(XS_Watcher.namechange, newdom)
|
||||
self.domdict[i] = newdom
|
||||
self.handle.watch(get_req_node(i), newdom.watch_token)
|
||||
self.handle.watch(get_name_node(i), newdom.watch_name)
|
||||
newdom.name = ''
|
||||
logproc( 'added domain ' + i)
|
||||
for i in only_in_first_list(self.domdict.keys(), curr):
|
||||
if disposable_domains_dict.has_key(i):
|
||||
self.remove_disposable_from_qdb(self.domdict[i].name)
|
||||
disposable_domains_dict.pop(i)
|
||||
self.handle.unwatch(get_req_node(i), self.domdict[i].watch_token)
|
||||
self.handle.unwatch(get_name_node(i), self.domdict[i].watch_name)
|
||||
self.domdict.pop(i)
|
||||
@ -196,6 +288,20 @@ class XS_Watcher:
|
||||
domain_param.name = ret
|
||||
logproc( 'Name for domain xid ' + domain_param.domain_id + ' is ' + ret )
|
||||
|
||||
def remove_disposable_from_qdb(self, name):
|
||||
qvm_collection = QubesVmCollection()
|
||||
qvm_collection.lock_db_for_writing()
|
||||
qvm_collection.load()
|
||||
|
||||
vm = qvm_collection.get_vm_by_name(name)
|
||||
if vm is None:
|
||||
logproc( 'remove_disposable_from_qdb: Domain ' + vmname + ' does not exist ?')
|
||||
qvm_collection.unlock_db()
|
||||
return False
|
||||
qvm_collection.pop(vm.qid)
|
||||
qvm_collection.save()
|
||||
qvm_collection.unlock_db()
|
||||
|
||||
def watch_loop(self):
|
||||
sys.stderr = file('/var/log/qubes/qfileexchgd.errors', 'a')
|
||||
while True:
|
||||
|
@ -41,10 +41,11 @@ function do_send()
|
||||
FILE=$SHARE_DIR/pendrive.$3
|
||||
vmname=$(xenstore-read /local/domain/$1/name)
|
||||
xenstore-write /local/domain/$2/qubes_blocksrc $vmname
|
||||
xenstore-write /local/domain/$2/qubes_transaction_seq "$4"
|
||||
xm block-detach $1 /dev/xvdg || exit 1
|
||||
xm block-attach $2 file:/$FILE /dev/xvdh w || exit 1
|
||||
}
|
||||
|
||||
export PATH=$PATH:/sbin:/usr/sbin
|
||||
if [ $# -lt 1 ] ; then
|
||||
echo args missing ?
|
||||
exit 1
|
||||
@ -62,11 +63,11 @@ elif [ "$1" = "umount" ] ; then
|
||||
fi
|
||||
do_umount "$2" "$3"
|
||||
elif [ "$1" = "send" ] ; then
|
||||
if ! [ $# = 4 ] ; then
|
||||
echo send requires 3 more args
|
||||
if ! [ $# = 5 ] ; then
|
||||
echo send requires 4 more args
|
||||
exit 1
|
||||
fi
|
||||
do_send "$2" "$3" "$4"
|
||||
do_send "$2" "$3" "$4" "$5"
|
||||
else
|
||||
echo bad cmd
|
||||
exit 1
|
||||
|
9
dom0/restore/Makefile
Normal file
9
dom0/restore/Makefile
Normal file
@ -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
|
54
dom0/restore/block.qubes
Executable file
54
dom0/restore/block.qubes
Executable file
@ -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
|
58
dom0/restore/qubes_prepare_saved_domain.sh
Executable file
58
dom0/restore/qubes_prepare_saved_domain.sh
Executable file
@ -0,0 +1,58 @@
|
||||
#!/bin/sh
|
||||
get_encoded_script()
|
||||
{
|
||||
if ! [ -f "$1" ] ; then
|
||||
echo $1 is not a file ?
|
||||
exit 1
|
||||
fi
|
||||
ENCODED_SCRIPT=`cat "$1" | perl -e 'use MIME::Base64 qw(encode_base64); local($/) = undef;print encode_base64(<STDIN>)'|tr -d "\n"`
|
||||
}
|
||||
|
||||
if [ $# != 2 -a $# != 3 ] ; then
|
||||
echo usage: $0 domainname savefile_to_be_created [preload script]
|
||||
exit 1
|
||||
fi
|
||||
export PATH=$PATH:/sbin:/usr/sbin
|
||||
if [ $# = 3 ] ; then
|
||||
get_encoded_script $3
|
||||
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
|
||||
if [ $ID = none ] ; then
|
||||
echo cannot get domain id
|
||||
exit 1
|
||||
fi
|
||||
echo domainid=$ID
|
||||
if [ -n "$ENCODED_SCRIPT" ] ; then
|
||||
xenstore-write /local/domain/$ID/qubes_save_script "$ENCODED_SCRIPT"
|
||||
fi
|
||||
set -x
|
||||
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
|
||||
if ! xm save $1 $2 ; then exit 1 ; fi
|
||||
cd $VMDIR
|
||||
tar -Scvf saved_cows.tar root-cow.img swap-cow.img
|
||||
|
||||
|
427
dom0/restore/qubes_restore.c
Normal file
427
dom0/restore/qubes_restore.c
Normal file
@ -0,0 +1,427 @@
|
||||
#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>
|
||||
#include <syslog.h>
|
||||
#include <xs.h>
|
||||
|
||||
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[] =
|
||||
"<?xml version='1.0'?>\n"
|
||||
"<methodCall>\n"
|
||||
"<methodName>xend.domain.restore</methodName>\n"
|
||||
"<params>\n"
|
||||
"<param>\n"
|
||||
"<value><string>%s</string></value>\n"
|
||||
"</param>\n"
|
||||
"<param>\n"
|
||||
"<value><boolean>0</boolean></value>\n"
|
||||
"</param>\n" "</params>\n" "</methodCall>\n";
|
||||
|
||||
char xmlrpc_body_setmem[] =
|
||||
"<?xml version='1.0'?>\n<methodCall>\n<methodName>xend.domain.setMemoryTarget</methodName>\n<params>\n<param>\n<value><string>%d</string></value>\n</param>\n<param>\n<value><int>%d</int></value>\n</param>\n</params>\n</methodCall>\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, "<fault>"))
|
||||
bad_resp(resp);
|
||||
if (!strstr(resp, "domid"))
|
||||
bad_resp(resp);
|
||||
domid = strstr(resp, "<int>");
|
||||
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)
|
||||
{
|
||||
int i;
|
||||
char dstr[40];
|
||||
char *guid_args[argc + 2];
|
||||
snprintf(dstr, sizeof(dstr), "%d", domid);
|
||||
guid_args[0] = "qubes_guid";
|
||||
guid_args[1] = "-d";
|
||||
guid_args[2] = dstr;
|
||||
for (i = 2; i < argc; i++)
|
||||
guid_args[i + 1] = argv[i];
|
||||
guid_args[argc + 1] = NULL;
|
||||
execv("/usr/bin/qubes_guid", guid_args);
|
||||
perror("execv");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
char * dispname_by_dispid(int dispid)
|
||||
{
|
||||
static char retbuf[16];
|
||||
snprintf(retbuf, sizeof(retbuf), "disp%d", dispid);
|
||||
return retbuf;
|
||||
}
|
||||
|
||||
#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);
|
||||
fix_savefile(fd, buf, "(name ", dispname_by_dispid(dispid));
|
||||
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, char * dispname, char *orig)
|
||||
{
|
||||
FILE *f = fopen("/var/run/qubes/dispVM_xid", "w");
|
||||
if (!f) {
|
||||
perror("fopen dispVM_xid");
|
||||
exit(1);
|
||||
}
|
||||
fprintf(f, "%d\n%s\n%s\n", domid, dispname, orig);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
|
||||
void redirect_stderr()
|
||||
{
|
||||
int fd =
|
||||
open("/var/log/qubes/qubes_restore.log",
|
||||
O_CREAT | O_TRUNC | O_WRONLY, 0600);
|
||||
if (fd < 0) {
|
||||
syslog(LOG_DAEMON | LOG_ERR, "open qubes_restore.log");
|
||||
exit(1);
|
||||
}
|
||||
dup2(fd, 2);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int fd, domid, dispid;
|
||||
char *resp;
|
||||
char *name;
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "usage: %s savefile [guid args] \n",
|
||||
argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
redirect_stderr();
|
||||
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, dispname_by_dispid(dispid), name);
|
||||
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;
|
||||
}
|
35
dom0/restore/qvm-create-default-dvm
Executable file
35
dom0/restore/qvm-create-default-dvm
Executable file
@ -0,0 +1,35 @@
|
||||
#!/bin/sh
|
||||
if [ $# != 1 -a $# != 2 ] ; then
|
||||
echo Usage: qvm-create-default-dvm templatename [script-name]
|
||||
exit 1
|
||||
fi
|
||||
if ! [ -d "/var/lib/qubes/vm-templates/$1" ] ; then
|
||||
echo /var/lib/qubes/vm-templates/$1 is not a directory
|
||||
exit 1
|
||||
fi
|
||||
DVMTMPL="$1"-dvm
|
||||
if ! [ -d "/var/lib/qubes/appvms/$DVMTMPL" ] ; then
|
||||
if ! qvm-create -t "$1" -l red "$DVMTMPL" ; then exit 1 ; fi
|
||||
fi
|
||||
if ! /usr/lib/qubes/qubes_prepare_saved_domain.sh \
|
||||
"$DVMTMPL" "/var/lib/qubes/appvms/$DVMTMPL/dvm-savefile" $2 ; then
|
||||
exit 1
|
||||
fi
|
||||
ROOT=/var/lib/qubes/dvmdata/savefile_root
|
||||
DEFAULT=/var/lib/qubes/dvmdata/default_savefile
|
||||
CURRENT=/var/run/qubes/current_savefile
|
||||
SHMDIR=/dev/shm/qubes
|
||||
SHMCOPY=$SHMDIR/current_savefile
|
||||
rm -f $ROOT $DEFAULT $CURRENT
|
||||
ln -s "/var/lib/qubes/appvms/$DVMTMPL/dvm-savefile" $DEFAULT
|
||||
ln -s "/var/lib/qubes/vm-templates/$1/root.img" $ROOT
|
||||
if [ -f /var/lib/qubes/dvmdata/dont_use_shm ] ; then
|
||||
ln -s $DEFAULT $CURRENT
|
||||
else
|
||||
mkdir -m 770 $SHMDIR 2>/dev/null
|
||||
chgrp qubes $SHMDIR 2>/dev/null
|
||||
cp $DEFAULT $SHMCOPY || exit 1
|
||||
chgrp qubes $SHMCOPY
|
||||
chmod 660 $SHMCOPY
|
||||
ln -s $SHMCOPY $CURRENT
|
||||
fi
|
28
dom0/restore/xenstore-watch.c
Normal file
28
dom0/restore/xenstore-watch.c
Normal file
@ -0,0 +1,28 @@
|
||||
#include <sys/types.h>
|
||||
#include <xs.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
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);
|
||||
}
|
@ -20,15 +20,17 @@ start()
|
||||
|
||||
# Setup gateway for all the VMs this netVM is serviceing...
|
||||
brctl addbr br0
|
||||
brctl stp br0 off
|
||||
brctl setfd br0 1
|
||||
gateway=$(/usr/bin/xenstore-read qubes_netvm_gateway)
|
||||
netmask=$(/usr/bin/xenstore-read qubes_netvm_netmask)
|
||||
network=$(/usr/bin/xenstore-read qubes_netvm_network)
|
||||
secondary_dns=$(/usr/bin/xenstore-read qubes_netvm_secondary_dns)
|
||||
ifconfig br0 $gateway netmask $netmask up
|
||||
ifconfig br0:1 $secondary_dns netmask $netmask
|
||||
echo "NS1=$gateway" > /var/run/qubes_ns
|
||||
echo "NS2=$secondary_dns" >> /var/run/qubes_ns
|
||||
qubes_setup_dnat_to_ns
|
||||
echo "NS1=$gateway" > /var/run/qubes/qubes_ns
|
||||
echo "NS2=$secondary_dns" >> /var/run/qubes/qubes_ns
|
||||
/usr/lib/qubes/qubes_setup_dnat_to_ns
|
||||
echo "1" > /proc/sys/net/ipv4/ip_forward
|
||||
#now no need for dnsmasq
|
||||
# dnsmasq --listen-address $gateway --bind-interfaces
|
||||
|
@ -33,6 +33,7 @@ License: GPL
|
||||
URL: http://www.qubes-os.org
|
||||
Requires: /usr/bin/xenstore-read
|
||||
Requires: fedora-release = 13
|
||||
Requires: /usr/bin/mimeopen
|
||||
Provides: qubes-core-vm
|
||||
|
||||
%define _builddir %(pwd)/appvm
|
||||
@ -60,9 +61,12 @@ 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 qvm-copy-to-vm qvm-open-in-dvm $RPM_BUILD_ROOT/usr/bin
|
||||
mkdir -p $RPM_BUILD_ROOT/usr/lib/qubes
|
||||
cp qubes_add_pendrive_script qubes_penctl qvm-copy-to-vm.kde $RPM_BUILD_ROOT/usr/lib/qubes
|
||||
ln -s /usr/bin/qvm-open-in-dvm $RPM_BUILD_ROOT/usr/lib/qubes/qvm-dvm-transfer
|
||||
mkdir -p $RPM_BUILD_ROOT/%{kde_service_dir}
|
||||
cp qvm-copy.desktop $RPM_BUILD_ROOT/%{kde_service_dir}
|
||||
cp qvm-copy.desktop qvm-dvm.desktop $RPM_BUILD_ROOT/%{kde_service_dir}
|
||||
mkdir -p $RPM_BUILD_ROOT/etc/udev/rules.d
|
||||
cp qubes.rules $RPM_BUILD_ROOT/etc/udev/rules.d
|
||||
mkdir -p $RPM_BUILD_ROOT/etc/sysconfig
|
||||
@ -77,6 +81,12 @@ 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/etc/X11
|
||||
cp xorg-preload-apps.conf $RPM_BUILD_ROOT/etc/X11
|
||||
|
||||
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
|
||||
|
||||
@ -174,10 +184,13 @@ rm -rf $RPM_BUILD_ROOT
|
||||
/etc/fstab
|
||||
/etc/init.d/qubes_core
|
||||
/usr/bin/qvm-copy-to-vm
|
||||
/usr/bin/qvm-copy-to-vm.kde
|
||||
/usr/lib/qubes/qvm-copy-to-vm.kde
|
||||
%attr(4755,root,root) /usr/bin/qvm-open-in-dvm
|
||||
/usr/lib/qubes/qvm-dvm-transfer
|
||||
%{kde_service_dir}/qvm-copy.desktop
|
||||
%attr(4755,root,root) /usr/bin/qubes_penctl
|
||||
/usr/bin/qubes_add_pendrive_script
|
||||
%{kde_service_dir}/qvm-dvm.desktop
|
||||
%attr(4755,root,root) /usr/lib/qubes/qubes_penctl
|
||||
/usr/lib/qubes/qubes_add_pendrive_script
|
||||
/etc/udev/rules.d/qubes.rules
|
||||
/etc/sysconfig/iptables
|
||||
/var/lib/qubes
|
||||
@ -186,3 +199,7 @@ 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
|
||||
/etc/X11/xorg-preload-apps.conf
|
||||
|
@ -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
|
||||
|
||||
@ -58,6 +59,9 @@ 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
|
||||
|
||||
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
|
||||
cp qvm-core/qubes.py[co] $RPM_BUILD_ROOT%{python_sitearch}/qubes
|
||||
@ -74,11 +78,16 @@ cp aux-tools/create_apps_for_appvm.sh $RPM_BUILD_ROOT/usr/lib/qubes
|
||||
cp aux-tools/remove_appvm_appmenus.sh $RPM_BUILD_ROOT/usr/lib/qubes
|
||||
cp pendrive_swapper/qubes_pencmd $RPM_BUILD_ROOT/usr/lib/qubes
|
||||
|
||||
cp restore/xenstore-watch restore/qvm-create-default-dvm $RPM_BUILD_ROOT/usr/bin
|
||||
cp restore/qubes_restore $RPM_BUILD_ROOT/usr/lib/qubes
|
||||
cp restore/qubes_prepare_saved_domain.sh $RPM_BUILD_ROOT/usr/lib/qubes
|
||||
|
||||
mkdir -p $RPM_BUILD_ROOT/var/lib/qubes
|
||||
mkdir -p $RPM_BUILD_ROOT/var/lib/qubes/vm-templates
|
||||
mkdir -p $RPM_BUILD_ROOT/var/lib/qubes/appvms
|
||||
|
||||
mkdir -p $RPM_BUILD_ROOT/var/lib/qubes/backup
|
||||
mkdir -p $RPM_BUILD_ROOT/var/lib/qubes/dvmdata
|
||||
|
||||
mkdir -p $RPM_BUILD_ROOT/usr/share/qubes/icons
|
||||
cp icons/*.png $RPM_BUILD_ROOT/usr/share/qubes/icons
|
||||
@ -87,9 +96,9 @@ mkdir -p $RPM_BUILD_ROOT/etc/yum.repos.d
|
||||
cp ../dom0/qubes.repo $RPM_BUILD_ROOT/etc/yum.repos.d
|
||||
|
||||
mkdir -p $RPM_BUILD_ROOT/usr/bin
|
||||
cp ../common/qubes_setup_dnat_to_ns $RPM_BUILD_ROOT/usr/bin
|
||||
cp ../common/qubes_setup_dnat_to_ns $RPM_BUILD_ROOT/usr/lib/qubes
|
||||
mkdir -p $RPM_BUILD_ROOT/etc/dhclient.d
|
||||
ln -s /usr/bin/qubes_setup_dnat_to_ns $RPM_BUILD_ROOT/etc/dhclient.d/qubes_setup_dnat_to_ns.sh
|
||||
ln -s /usr/lib/qubes/qubes_setup_dnat_to_ns $RPM_BUILD_ROOT/etc/dhclient.d/qubes_setup_dnat_to_ns.sh
|
||||
mkdir -p $RPM_BUILD_ROOT/etc/NetworkManager/dispatcher.d/
|
||||
cp ../common/qubes_nmhook $RPM_BUILD_ROOT/etc/NetworkManager/dispatcher.d/
|
||||
mkdir -p $RPM_BUILD_ROOT/etc/sysconfig
|
||||
@ -99,6 +108,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 +179,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
|
||||
@ -194,11 +207,17 @@ fi
|
||||
%attr(770,root,qubes) %dir /var/lib/qubes/vm-templates
|
||||
%attr(770,root,qubes) %dir /var/lib/qubes/appvms
|
||||
%attr(770,root,qubes) %dir /var/lib/qubes/backup
|
||||
%attr(770,root,qubes) %dir /var/lib/qubes/dvmdata
|
||||
%dir /usr/share/qubes/icons/*.png
|
||||
/etc/yum.repos.d/qubes.repo
|
||||
/usr/bin/qubes_setup_dnat_to_ns
|
||||
/usr/lib/qubes/qubes_setup_dnat_to_ns
|
||||
/etc/dhclient.d/qubes_setup_dnat_to_ns.sh
|
||||
/etc/NetworkManager/dispatcher.d/qubes_nmhook
|
||||
/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/qvm-create-default-dvm
|
||||
/usr/lib/qubes/qubes_restore
|
||||
/usr/lib/qubes/qubes_prepare_saved_domain.sh
|
||||
/etc/xen/scripts/block.qubes
|
||||
|
@ -59,10 +59,10 @@ cp fstab $RPM_BUILD_ROOT/etc/fstab
|
||||
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 ../common/qubes_setup_dnat_to_ns $RPM_BUILD_ROOT/usr/bin
|
||||
mkdir -p $RPM_BUILD_ROOT/usr/lib/qubes
|
||||
cp ../common/qubes_setup_dnat_to_ns $RPM_BUILD_ROOT/usr/lib/qubes
|
||||
mkdir -p $RPM_BUILD_ROOT/etc/dhclient.d
|
||||
ln -s /usr/bin/qubes_setup_dnat_to_ns $RPM_BUILD_ROOT/etc/dhclient.d/qubes_setup_dnat_to_ns.sh
|
||||
ln -s /usr/lib/qubes/qubes_setup_dnat_to_ns $RPM_BUILD_ROOT/etc/dhclient.d/qubes_setup_dnat_to_ns.sh
|
||||
mkdir -p $RPM_BUILD_ROOT/etc/NetworkManager/dispatcher.d/
|
||||
cp ../common/qubes_nmhook $RPM_BUILD_ROOT/etc/NetworkManager/dispatcher.d/
|
||||
mkdir -p $RPM_BUILD_ROOT/etc/yum.repos.d
|
||||
@ -71,6 +71,7 @@ mkdir -p $RPM_BUILD_ROOT/sbin
|
||||
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/var/run/qubes
|
||||
|
||||
%triggerin -- initscripts
|
||||
cp /var/lib/qubes/serial.conf /etc/init/serial.conf
|
||||
@ -168,8 +169,9 @@ rm -rf $RPM_BUILD_ROOT
|
||||
/etc/sysconfig/iptables
|
||||
/etc/init.d/qubes_core
|
||||
/var/lib/qubes
|
||||
/usr/bin/qubes_setup_dnat_to_ns
|
||||
/usr/lib/qubes/qubes_setup_dnat_to_ns
|
||||
/etc/dhclient.d/qubes_setup_dnat_to_ns.sh
|
||||
/etc/NetworkManager/dispatcher.d/qubes_nmhook
|
||||
/etc/yum.repos.d/qubes.repo
|
||||
/sbin/qubes_serial_login
|
||||
%dir /var/run/qubes
|
||||
|
Loading…
Reference in New Issue
Block a user