Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
0be42e4354 | ||
|
4b6924a27b | ||
|
5c6ad4c669 | ||
|
6e4fa03459 | ||
|
11365e353e | ||
|
d4b23691f1 | ||
|
0771ddaab3 | ||
|
9b762acd0b | ||
|
f6460d6e95 | ||
|
034b066700 | ||
|
d0a23bdd09 | ||
|
ba61c8405c | ||
|
bbdb5ed67f | ||
|
d6eb7e5c58 | ||
|
d88242bb99 | ||
|
509ae49001 | ||
|
72069d8526 | ||
|
129aeeacd5 |
39
.travis.yml
39
.travis.yml
@ -1,39 +0,0 @@
|
||||
sudo: required
|
||||
dist: bionic
|
||||
language: python
|
||||
python:
|
||||
- '2.7'
|
||||
install:
|
||||
- test -z "$TESTS_ONLY" || pip install -r ci/requirements.txt
|
||||
- test -n "$TESTS_ONLY" || git clone https://github.com/QubesOS/qubes-builder ~/qubes-builder
|
||||
script:
|
||||
- test -z "$TESTS_ONLY" || python -m unittest discover -v imgconverter -p test.py
|
||||
- test -n "$TESTS_ONLY" || ~/qubes-builder/scripts/travis-build
|
||||
env:
|
||||
- DIST_DOM0=fc31 USE_QUBES_REPO_VERSION=4.1 USE_QUBES_REPO_TESTING=1
|
||||
- DISTS_VM=fc29 USE_QUBES_REPO_VERSION=4.1 USE_QUBES_REPO_TESTING=1
|
||||
- DISTS_VM=fc30 USE_QUBES_REPO_VERSION=4.1 USE_QUBES_REPO_TESTING=1
|
||||
- DISTS_VM=stretch USE_QUBES_REPO_VERSION=4.1 USE_QUBES_REPO_TESTING=1
|
||||
- DISTS_VM=buster USE_QUBES_REPO_VERSION=4.1 USE_QUBES_REPO_TESTING=1
|
||||
- DISTS_VM=centos7 USE_QUBES_REPO_VERSION=4.1 USE_QUBES_REPO_TESTING=1
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- env: TESTS_ONLY=1
|
||||
python: 2.7
|
||||
- env: TESTS_ONLY=1
|
||||
python: 3.5
|
||||
- env: TESTS_ONLY=1
|
||||
python: 3.6
|
||||
- env: TESTS_ONLY=1
|
||||
python: 3.7
|
||||
- stage: deploy
|
||||
python: 3.6
|
||||
env: DIST_DOM0=fc31 TESTS_ONLY=
|
||||
script: ~/qubes-builder/scripts/travis-deploy
|
||||
|
||||
# don't build tags which are meant for code signing only
|
||||
branches:
|
||||
except:
|
||||
- /.*_.*/
|
||||
|
35
Makefile
35
Makefile
@ -1,13 +1,13 @@
|
||||
ifeq ($(shell uname -m),x86_64)
|
||||
LIBDIR ?= /usr/lib64
|
||||
else
|
||||
LIBDIR ?= /usr/lib
|
||||
ifndef LIBDIR
|
||||
ifeq ($(shell uname -m),x86_64)
|
||||
LIBDIR = /usr/lib64
|
||||
else
|
||||
LIBDIR = /usr/lib
|
||||
endif
|
||||
endif
|
||||
SCRIPTSDIR ?= /usr/lib/qubes
|
||||
SYSLIBDIR ?= /lib
|
||||
INCLUDEDIR ?= /usr/include
|
||||
INCLUDEDIR = /usr/include
|
||||
|
||||
export LIBDIR SCRIPTSDIR SYSLIBDIR INCLUDEDIR
|
||||
export LIBDIR INCLUDEDIR
|
||||
|
||||
help:
|
||||
echo "Use rpmbuild to compile this pacakge"
|
||||
@ -16,29 +16,18 @@ help:
|
||||
|
||||
rpms:
|
||||
rpmbuild --define "_rpmdir rpm/" --define "_builddir ." -bb rpm_spec/qubes-utils.spec
|
||||
all:
|
||||
all:
|
||||
$(MAKE) -C qrexec-lib all
|
||||
$(MAKE) -C qmemman all
|
||||
$(MAKE) -C imgconverter all
|
||||
$(MAKE) -C core all
|
||||
|
||||
install:
|
||||
$(MAKE) -C udev install
|
||||
$(MAKE) -C qrexec-lib install
|
||||
$(MAKE) -C qmemman install
|
||||
$(MAKE) -C imgconverter install
|
||||
|
||||
install-fedora-kernel-support:
|
||||
$(MAKE) -C dracut install
|
||||
$(MAKE) -C kernel-modules install
|
||||
$(MAKE) -C grub install-fedora
|
||||
|
||||
install-debian-kernel-support:
|
||||
$(MAKE) -C initramfs-tools install
|
||||
$(MAKE) -C dracut install
|
||||
$(MAKE) -C kernel-modules install
|
||||
$(MAKE) -C grub install-debian
|
||||
$(MAKE) -C core install
|
||||
|
||||
clean:
|
||||
$(MAKE) -C qrexec-lib clean
|
||||
$(MAKE) -C qmemman clean
|
||||
$(MAKE) -C imgconverter clean
|
||||
$(MAKE) -C core clean
|
||||
|
@ -1,3 +1,3 @@
|
||||
RPM_SPEC_FILES := rpm_spec/qubes-utils.spec rpm_spec/qubes-kernel-vm-support.spec
|
||||
RPM_SPEC_FILES := rpm_spec/qubes-utils.spec
|
||||
ARCH_BUILD_DIRS := archlinux
|
||||
DEBIAN_BUILD_DIRS := debian
|
||||
|
@ -4,16 +4,17 @@
|
||||
# then please put 'unknown'.
|
||||
|
||||
# Maintainer: Olivier Medoc <o_medoc@yahoo.fr>
|
||||
pkgname=(qubes-vm-utils qubes-vm-kernel-support)
|
||||
pkgname=qubes-vm-utils
|
||||
pkgver=`cat version`
|
||||
pkgrel=10
|
||||
pkgrel=9
|
||||
epoch=
|
||||
pkgdesc="Common Linux files for Qubes VM."
|
||||
arch=("x86_64")
|
||||
url="http://qubes-os.org/"
|
||||
license=('GPL')
|
||||
groups=()
|
||||
makedepends=(gcc make pkgconfig 'python-setuptools' 'python2-setuptools')
|
||||
depends=(qubes-libvchan)
|
||||
makedepends=(qubes-libvchan)
|
||||
checkdepends=()
|
||||
optdepends=()
|
||||
provides=()
|
||||
@ -21,55 +22,30 @@ conflicts=()
|
||||
replaces=()
|
||||
backup=()
|
||||
options=('staticlibs')
|
||||
install=PKGBUILD-qubes-vm-utils.install
|
||||
changelog=
|
||||
|
||||
source=(PKGBUILD-initcpio-hook.sh PKGBUILD-initcpio-install.sh)
|
||||
source=()
|
||||
|
||||
noextract=()
|
||||
md5sums=(SKIP)
|
||||
md5sums=() #generate with 'makepkg -g'
|
||||
|
||||
|
||||
build() {
|
||||
|
||||
for source in qrexec-lib udev qmemman core kernel-modules Makefile dracut imgconverter; do
|
||||
for source in qrexec-lib udev qmemman core Makefile; do
|
||||
(ln -s $srcdir/../$source $srcdir/$source)
|
||||
done
|
||||
|
||||
# Build all with python2
|
||||
PYTHON=python2 make all
|
||||
|
||||
# Build imgconverter with python3
|
||||
make -C imgconverter all
|
||||
|
||||
make all LIBDIR=/usr/lib SBINDIR=/usr/bin
|
||||
|
||||
}
|
||||
|
||||
package_qubes-vm-utils() {
|
||||
depends=(imagemagick python2-cairo python2-pillow python2-numpy python-pillow python-numpy)
|
||||
install=PKGBUILD-qubes-vm-utils.install
|
||||
package() {
|
||||
|
||||
# Install all for python2
|
||||
PYTHON=python2 make install DESTDIR=$pkgdir LIBDIR=/usr/lib SYSLIBDIR=/usr/lib SBINDIR=/usr/bin
|
||||
|
||||
# Install imgconverter as python3
|
||||
make -C imgconverter install DESTDIR=$pkgdir LIBDIR=/usr/lib SYSLIBDIR=/usr/lib SBINDIR=/usr/bin
|
||||
make install DESTDIR=$pkgdir LIBDIR=/usr/lib SBINDIR=/usr/bin
|
||||
|
||||
}
|
||||
|
||||
package_qubes-vm-kernel-support() {
|
||||
depends=(mkinitcpio grub)
|
||||
install=PKGBUILD-qubes-vm-kernel-support.install
|
||||
|
||||
mkdir -p ${pkgdir}/usr/lib/initcpio/install/
|
||||
mkdir -p ${pkgdir}/usr/lib/initcpio/hooks/
|
||||
mkdir -p ${pkgdir}/usr/lib/qubes/
|
||||
mkdir -p ${pkgdir}/usr/bin/
|
||||
|
||||
install -m 611 ${srcdir}/PKGBUILD-initcpio-install.sh ${pkgdir}/usr/lib/initcpio/install/qubes
|
||||
install -m 611 ${srcdir}/PKGBUILD-initcpio-hook.sh ${pkgdir}/usr/lib/initcpio/hooks/qubes
|
||||
install -m 755 ${srcdir}/dracut/full-dmroot/qubes_cow_setup.sh ${pkgdir}/usr/lib/qubes/qubes_cow_setup.sh
|
||||
}
|
||||
|
||||
|
||||
# vim:set ts=2 sw=2 et:
|
||||
|
||||
|
@ -1,9 +0,0 @@
|
||||
#!/usr/bin/ash
|
||||
|
||||
run_earlyhook() {
|
||||
|
||||
msg "Starting Qubes copy on write setup script"
|
||||
|
||||
/usr/lib/qubes/qubes_cow_setup.sh
|
||||
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
#!/usr/bin/bash
|
||||
|
||||
build() {
|
||||
|
||||
add_module "xen-blkfront"
|
||||
add_binary "/usr/bin/sfdisk"
|
||||
add_binary "/usr/bin/mkswap"
|
||||
add_binary "/usr/bin/dmsetup"
|
||||
add_binary "/usr/lib/qubes/qubes_cow_setup.sh"
|
||||
|
||||
add_runscript
|
||||
|
||||
}
|
||||
|
||||
help() {
|
||||
cat <<HELPEOF
|
||||
This hook enables Qubes COW Setup (using lvm) in initramfs.
|
||||
HELPEOF
|
||||
}
|
||||
|
@ -1,27 +0,0 @@
|
||||
|
||||
help() {
|
||||
echo "Before using pvgrub, the kernel you want to use needs to be regenerated with Qubes kernel modules in the TemplateVM:"
|
||||
echo "1/ Ensure that your kernel and kernel sources are installed (ex: pacman -S linux-lts linux-lts-headers)"
|
||||
echo "2/ Ensure that grub config file has been generated for your kernel (ex: grub-mkconfig > /boot/grub/grub.cfg)"
|
||||
echo "3/ Reinstall qubes-vm-kernel-support to ensure Qubes-OS kernel module is compiled and that the initcpio is rebuilt"
|
||||
echo "This should then be handled automatically in your next kernel updates"
|
||||
}
|
||||
|
||||
## arg 1: the new package version
|
||||
post_install() {
|
||||
echo "Adding qubes required hooks to mkinitcpio.conf"
|
||||
sed 's/^HOOKS="base/HOOKS="lvm2 qubes base/' -i /etc/mkinitcpio.conf
|
||||
help
|
||||
}
|
||||
|
||||
post_upgrade() {
|
||||
echo "Adding qubes required hooks to mkinitcpio.conf"
|
||||
sed 's/^HOOKS="base/HOOKS="lvm2 qubes base/' -i /etc/mkinitcpio.conf
|
||||
help
|
||||
}
|
||||
|
||||
post_remove() {
|
||||
echo "Removing qubes required hooks to mkinitcpio.conf"
|
||||
sed 's/^HOOKS="lvm2 qubes base/HOOKS="base/' -i /etc/mkinitcpio.conf
|
||||
}
|
||||
|
@ -2,8 +2,13 @@
|
||||
## arg 1: the new package version
|
||||
post_install() {
|
||||
ldconfig
|
||||
/bin/systemctl enable qubes-meminfo-writer-dom0.service > /dev/null 2>&1
|
||||
/bin/systemctl enable qubes-meminfo-writer.service > /dev/null 2>&1
|
||||
if [ -r /etc/qubes-release ]; then
|
||||
# dom0
|
||||
/bin/systemctl enable qubes-meminfo-writer-dom0.service > /dev/null 2>&1
|
||||
else
|
||||
# VM
|
||||
/bin/systemctl enable qubes-meminfo-writer.service > /dev/null 2>&1
|
||||
fi
|
||||
}
|
||||
|
||||
post_upgrade() {
|
||||
|
@ -1,2 +0,0 @@
|
||||
Pillow
|
||||
numpy
|
20
core/Makefile
Normal file
20
core/Makefile
Normal file
@ -0,0 +1,20 @@
|
||||
PYTHON = /usr/bin/python2
|
||||
PYTHON_SITEARCH = `python2 -c 'import distutils.sysconfig; print distutils.sysconfig.get_python_lib(1)'`
|
||||
|
||||
all:
|
||||
$(PYTHON) -m compileall .
|
||||
$(PYTHON) -O -m compileall .
|
||||
.PHONY: all
|
||||
|
||||
clean:
|
||||
$(RM) *.py[co]
|
||||
.PHONY: clean
|
||||
|
||||
install:
|
||||
mkdir -p $(DESTDIR)/$(PYTHON_SITEARCH)/qubes/
|
||||
ifeq (1,${DEBIANBUILD})
|
||||
cp *.py $(DESTDIR)/$(PYTHON_SITEARCH)/qubes/
|
||||
else
|
||||
cp *.py* $(DESTDIR)/$(PYTHON_SITEARCH)/qubes/
|
||||
endif
|
||||
.PHONY: install
|
0
core/__init__.py
Normal file
0
core/__init__.py
Normal file
227
imgconverter/qubesimgconverter/__init__.py → core/imgconverter.py
Normal file → Executable file
227
imgconverter/qubesimgconverter/__init__.py → core/imgconverter.py
Normal file → Executable file
@ -23,18 +23,16 @@ Toolkit for secure transfer and conversion of images between Qubes VMs.'''
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
|
||||
import colorsys
|
||||
import math
|
||||
import os
|
||||
import re
|
||||
try:
|
||||
from io import BytesIO
|
||||
except ImportError:
|
||||
from cStringIO import StringIO as BytesIO
|
||||
import cStringIO as StringIO
|
||||
import subprocess
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
import PIL.Image
|
||||
import numpy
|
||||
import cairo
|
||||
|
||||
# those are for "zOMG UlTRa HD! WalLLpapPer 8K!!1!" to work seamlessly;
|
||||
# 8192 * 5120 * 4 B = 160 MiB, so DoS by memory exhaustion is unlikely
|
||||
@ -44,13 +42,13 @@ MAX_HEIGHT = 5120
|
||||
# current max raster icon size in hicolor theme is 256 as of 2013/fedora-18
|
||||
# beyond that one probably shall use scalable icons
|
||||
# (SVG is currently unsupported)
|
||||
ICON_MAXSIZE = 2048
|
||||
ICON_MAXSIZE = 512
|
||||
|
||||
# header consists of two decimal numbers, SPC and LF
|
||||
re_imghdr = re.compile(br'^\d+ \d+\n$')
|
||||
def imghdrlen(w, h):
|
||||
# width & height are inclusive max vals, and +2 for ' ' and '\n'
|
||||
return len(str(w)) + len(str(h)) + 2
|
||||
re_imghdr = re.compile(r'^\d+ \d+\n$')
|
||||
imghdrlen = lambda w, h: int(math.ceil(math.log10(w)) \
|
||||
+ math.ceil(math.log10(h)) \
|
||||
+ 2)
|
||||
|
||||
class Image(object):
|
||||
def __init__(self, rgba, size):
|
||||
@ -72,87 +70,21 @@ get_from_stream(), get_from_vm(), get_xdg_icon_from_vm(), get_through_dvm()'''
|
||||
if p.wait():
|
||||
raise Exception('Conversion failed')
|
||||
|
||||
def save_pil(self, dst):
|
||||
'''Save image to disk using PIL.'''
|
||||
|
||||
img = PIL.Image.frombytes('RGBA', self._size, self._rgba)
|
||||
img.save(dst)
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
return self._rgba
|
||||
|
||||
@property
|
||||
def width(self):
|
||||
return self._size[0]
|
||||
|
||||
@property
|
||||
def height(self):
|
||||
return self._size[1]
|
||||
|
||||
def tint(self, colour):
|
||||
'''Return new tinted image'''
|
||||
|
||||
tr, tg, tb = hex_to_int(colour)
|
||||
tM = max(tr, tg, tb)
|
||||
tm = min(tr, tg, tb)
|
||||
r, g, b = hex_to_float(colour)
|
||||
h, _, s = colorsys.rgb_to_hls(r, g, b)
|
||||
result = StringIO.StringIO()
|
||||
|
||||
# (trn/tdn, tgn/tdn, tbn/tdn) is the tint color with maximum saturation
|
||||
if tm == tM:
|
||||
trn = 1
|
||||
tgn = 1
|
||||
tbn = 1
|
||||
tdn = 2
|
||||
else:
|
||||
trn = tr - tm
|
||||
tgn = tg - tm
|
||||
tbn = tb - tm
|
||||
tdn = tM - tm
|
||||
for i in xrange(0, self._size[0] * self._size[1] * 4, 4):
|
||||
r, g, b, a = tuple(ord(c) / 255. for c in self._rgba[i:i+4])
|
||||
_, l, _ = colorsys.rgb_to_hls(r, g, b)
|
||||
r, g, b = colorsys.hls_to_rgb(h, l, s)
|
||||
|
||||
# use a 1D image representation since we only process a single pixel at a time
|
||||
pixels = self._size[0] * self._size[1]
|
||||
x = numpy.fromstring(self._rgba, 'B').reshape(pixels, 4)
|
||||
r = x[:, 0]
|
||||
g = x[:, 1]
|
||||
b = x[:, 2]
|
||||
a = x[:, 3]
|
||||
M = numpy.maximum(numpy.maximum(r, g), b).astype('u4')
|
||||
m = numpy.minimum(numpy.minimum(r, g), b).astype('u4')
|
||||
result.write(''.join(chr(int(i * 255)) for i in [r, g, b, a]))
|
||||
|
||||
# Tn/Td is how much chroma range is reserved for the tint color
|
||||
# 0 -> greyscale image becomes greyscale image
|
||||
# 1 -> image becomes solid tint color
|
||||
Tn = 1
|
||||
Td = 4
|
||||
|
||||
# set chroma to the original pixel chroma mapped to the Tn/Td .. 1 range
|
||||
# float c2 = (Tn/Td) + (1.0 - Tn/Td) * c
|
||||
|
||||
# set lightness to the original pixel lightness mapped to the range for the new chroma value
|
||||
# float m2 = m * (1.0 - c2) / (1.0 - c)
|
||||
|
||||
c = M - m
|
||||
|
||||
c2 = (Tn * 255) + (Td - Tn) * c
|
||||
c2d = Td
|
||||
|
||||
m2 = ((255 * c2d) - c2) * m
|
||||
# the maximum avoids division by 0 when c = 255 (m2 is 0 anyway, so m2d doesn't matter)
|
||||
m2d = numpy.maximum((255 - c) * c2d, 1)
|
||||
|
||||
# precomputed values
|
||||
c2d_tdn = tdn * c2d
|
||||
m2_c2d_tdn = m2 * c2d_tdn
|
||||
m2d_c2d_tdn = m2d * c2d_tdn
|
||||
c2_m2d = c2 * m2d
|
||||
|
||||
# float vt = m2 + tvn * c2
|
||||
rt = ((m2_c2d_tdn + trn * c2_m2d) // m2d_c2d_tdn).astype('B')
|
||||
gt = ((m2_c2d_tdn + tgn * c2_m2d) // m2d_c2d_tdn).astype('B')
|
||||
bt = ((m2_c2d_tdn + tbn * c2_m2d) // m2d_c2d_tdn).astype('B')
|
||||
|
||||
xt = numpy.column_stack((rt, gt, bt, a))
|
||||
return self.__class__(rgba=xt.tobytes(), size=self._size)
|
||||
return self.__class__(rgba=result.getvalue(), size=self._size)
|
||||
|
||||
@classmethod
|
||||
def load_from_file(cls, filename):
|
||||
@ -174,13 +106,6 @@ get_from_stream(), get_from_vm(), get_xdg_icon_from_vm(), get_through_dvm()'''
|
||||
|
||||
return cls(rgba=rgba, size=size)
|
||||
|
||||
@classmethod
|
||||
def load_from_file_pil(cls, filename):
|
||||
'''Loads image from local file using PIL.'''
|
||||
img = PIL.Image.open(filename)
|
||||
img = img.convert('RGBA')
|
||||
return cls(rgba=img.tobytes(), size=img.size)
|
||||
|
||||
@classmethod
|
||||
def get_from_stream(cls, stream, max_width=MAX_WIDTH, max_height=MAX_HEIGHT):
|
||||
'''Carefully parse image data from stream.
|
||||
@ -223,8 +148,8 @@ get_from_stream(), get_from_vm(), get_xdg_icon_from_vm(), get_through_dvm()'''
|
||||
def get_from_vm(cls, vm, src, **kwargs):
|
||||
'Get image from VM by QUBESRPC (qubes.GetImageRGBA).'
|
||||
|
||||
p = vm.run_service('qubes.GetImageRGBA')
|
||||
p.stdin.write('{0}\n'.format(src).encode())
|
||||
p = vm.run('QUBESRPC qubes.GetImageRGBA dom0', passio_popen=True)
|
||||
p.stdin.write('{0}\n'.format(src))
|
||||
p.stdin.close()
|
||||
|
||||
try:
|
||||
@ -250,15 +175,16 @@ get_from_stream(), get_from_vm(), get_xdg_icon_from_vm(), get_through_dvm()'''
|
||||
'''Master end of image filter: writes untrusted image to stdout and
|
||||
expects header+RGBA on stdin. This method is invoked from qvm-imgconverter-client.'''
|
||||
|
||||
filetype = None
|
||||
if ':' in filename:
|
||||
filetype, filename = filename.split(':', 1)
|
||||
filetype, filename = filename.split(':', 1)[0]
|
||||
sys.stdout.write('{0}:-\n'.format(filetype))
|
||||
else:
|
||||
sys.stdout.write('-\n')
|
||||
|
||||
try:
|
||||
sys.stdout.write(open(filename).read())
|
||||
except Exception as e:
|
||||
except Exception, e:
|
||||
raise Exception('Something went wrong: {0!s}'.format(e))
|
||||
finally:
|
||||
sys.stdout.close()
|
||||
@ -267,29 +193,112 @@ expects header+RGBA on stdin. This method is invoked from qvm-imgconverter-clien
|
||||
|
||||
return cls.get_from_stream(sys.stdin, **kwargs)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self._size == other._size and self._rgba == other._rgba
|
||||
def hex_to_float(colour, channels=3, depth=8):
|
||||
'''Convert hex colour definition to tuple of floats.'''
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
if depth % 4 != 0:
|
||||
raise NotImplementedError('depths not divisible by 4 are unsupported')
|
||||
|
||||
def hex_to_int(colour, channels=3, depth=1):
|
||||
'''Convert hex colour definition to tuple of ints.'''
|
||||
|
||||
length = channels * depth * 2
|
||||
step = depth * 2
|
||||
length = channels * depth / 4
|
||||
step = depth / 4
|
||||
|
||||
# get rid of '#' or '0x' in front of hex values
|
||||
colour = colour[-length:]
|
||||
|
||||
return tuple(int(colour[i:i+step], 0x10) for i in range(0, length, step))
|
||||
return tuple(int(colour[i:i+step], 0x10) / float(2**depth - 1) for i in range(0, length, step))
|
||||
|
||||
def tint(src, dst, colour):
|
||||
'''Tint image to reflect vm label.
|
||||
|
||||
src and dst may NOT specify ImageMagick format'''
|
||||
src and dst may specify format, like png:aqq.gif'''
|
||||
|
||||
Image.load_from_file_pil(src).tint(colour).save_pil(dst)
|
||||
Image.load_from_file(src).tint(colour).save(dst)
|
||||
|
||||
def make_padlock(dst, colour, size=ICON_MAXSIZE):
|
||||
cs = cairo.ImageSurface(cairo.FORMAT_ARGB32, size, size)
|
||||
|
||||
cr = cairo.Context(cs)
|
||||
cr.set_source_rgb(*hex_to_float(colour))
|
||||
cr.set_line_width(.125 * size)
|
||||
|
||||
cr.rectangle(.125 * size, .5 * size, .75 * size, .4375 * size)
|
||||
cr.fill()
|
||||
|
||||
cr.move_to(.25 * size, .5 * size)
|
||||
cr.line_to(.25 * size, .375 * size)
|
||||
cr.arc(.5 * size, .375 * size, .25 * size, math.pi, 2 * math.pi)
|
||||
cr.move_to(.75 * size, .375 * size) # this is unneccessary, but helps readability
|
||||
cr.line_to(.75 * size, .5 * size)
|
||||
cr.stroke()
|
||||
|
||||
cs.write_to_png(dst)
|
||||
|
||||
|
||||
class TestCaseImage(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.rgba = \
|
||||
'\x00\x00\x00\xff' '\xff\x00\x00\xff' \
|
||||
'\x00\xff\x00\xff' '\x00\x00\x00\xff'
|
||||
self.size = (2, 2)
|
||||
|
||||
self.image = Image(rgba=self.rgba, size=self.size)
|
||||
|
||||
def test_00_init(self):
|
||||
self.assertEqual(self.image._rgba, self.rgba)
|
||||
self.assertEqual(self.image._size, self.size)
|
||||
|
||||
def test_01_tint(self):
|
||||
image = self.image.tint('#0000ff')
|
||||
|
||||
self.assertEqual(image._rgba,
|
||||
'\x00\x00\x00\xff' '\x00\x00\xff\xff'
|
||||
'\x00\x00\xff\xff' '\x00\x00\x00\xff')
|
||||
|
||||
def test_10_get_from_stream(self):
|
||||
io = StringIO.StringIO('{0[0]} {0[1]}\n{1}'.format(self.size, self.rgba))
|
||||
|
||||
image = Image.get_from_stream(io)
|
||||
|
||||
self.assertEqual(image._rgba, self.rgba)
|
||||
self.assertEqual(image._size, self.size)
|
||||
|
||||
def test_11_get_from_stream_malformed(self):
|
||||
io = StringIO.StringIO('{0[0]} {0[1]}\n{1}'.format(self.size, self.rgba[-1])) # one byte too short
|
||||
|
||||
with self.assertRaises(Exception):
|
||||
image = Image.get_from_stream(io)
|
||||
|
||||
def test_12_get_from_stream_too_big(self):
|
||||
io = StringIO.StringIO('{0[0]} {0[1]}\n{1}'.format(self.size, self.rgba)) # 2x2
|
||||
|
||||
with self.assertRaises(Exception):
|
||||
image = Image.get_from_stream(io, max_width=1)
|
||||
|
||||
io.seek(0)
|
||||
with self.assertRaises(Exception):
|
||||
image = Image.get_from_stream(io, max_height=1)
|
||||
|
||||
class TestCaseFunctionsAndConstants(unittest.TestCase):
|
||||
def test_00_imghdrlen(self):
|
||||
self.assertEqual(imghdrlen(8, 15), len('8 15\n'))
|
||||
|
||||
def test_01_re_imghdr(self):
|
||||
self.assertTrue(re_imghdr.match('8 15\n'))
|
||||
self.assertIsNone(re_imghdr.match('8 15'))
|
||||
self.assertIsNone(re_imghdr.match('815\n'))
|
||||
self.assertIsNone(re_imghdr.match('x yx\n'))
|
||||
|
||||
def test_10_hex_to_float_result_00(self):
|
||||
self.assertEqual(hex_to_float('#000000'), (0.0, 0.0, 0.0))
|
||||
|
||||
def test_11_hex_to_float_result_ff(self):
|
||||
self.assertEqual(hex_to_float('0xffffff'), (1.0, 1.0, 1.0))
|
||||
|
||||
def test_12_hex_to_float_depth_3_not_implemented(self):
|
||||
with self.assertRaises(NotImplementedError):
|
||||
hex_to_float('123456', depth=3)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
# vim: ft=python sw=4 ts=4 et
|
704
debian/changelog
vendored
704
debian/changelog
vendored
@ -1,703 +1,53 @@
|
||||
qubes-utils (4.1.3) unstable; urgency=medium
|
||||
|
||||
[ xaki23 ]
|
||||
* partition full volatile for non-COW setups too
|
||||
|
||||
[ Frédéric Pierret (fepitre) ]
|
||||
* travis: switch to bionic
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* travis: update python versions
|
||||
|
||||
[ Patrick Schleizer ]
|
||||
* qubes-kernel-vm-support.preinst create folder /boot/grub
|
||||
* qubes-kernel-vm-support.postinst run update-grub
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* debian: fix dependencies of qubes-kernel-vm-support pkg
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sat, 07 Dec 2019 05:50:26 +0100
|
||||
|
||||
qubes-utils (4.1.2) unstable; urgency=medium
|
||||
|
||||
[ xaki23 ]
|
||||
* align volatile swap partition to 1Mb instead of 512b
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* rpm: update python2 deps
|
||||
* Disable BLS config style in grub
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sun, 22 Sep 2019 05:10:19 +0200
|
||||
|
||||
qubes-utils (4.1.1) unstable; urgency=medium
|
||||
|
||||
* initrd: mount / rw for the overlayfs setup time
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Mon, 10 Jun 2019 00:48:40 +0200
|
||||
|
||||
qubes-utils (4.1.0) unstable; urgency=medium
|
||||
|
||||
* Remove qrexec related files
|
||||
* Remove u2mfn module
|
||||
* travis: update to R4.1
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sat, 08 Jun 2019 03:20:55 +0200
|
||||
|
||||
qubes-utils (4.0.24) unstable; urgency=medium
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* Declare u2mfn module version, skip build for qubes kernels
|
||||
|
||||
[ Frédéric Pierret (fepitre) ]
|
||||
* python3: use macro pkgversion
|
||||
* travis: switch to xenial
|
||||
* travis: remove older Fedora releases and add Fedora 30
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* initramfs: use overlayfs for /lib/modules, if available
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Thu, 06 Jun 2019 21:30:30 +0200
|
||||
|
||||
qubes-utils (4.0.23) unstable; urgency=medium
|
||||
|
||||
* Disable scrubbing memory pages during initial balloon down
|
||||
* dracut: fix checking for "Root filesystem" label, improve udev sync
|
||||
* dracut: add a flag file indicating scrub-pages option support
|
||||
* Adjust permissions of /dev/xen/hypercall
|
||||
* Do not use /proc/xen for detecting dom0 anymore
|
||||
* Really install xen-scrub-pages dracut module
|
||||
* Add xen_scrub_pages=0 kernel option only if initramfs was rebuilt
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Mon, 25 Feb 2019 21:46:52 +0100
|
||||
|
||||
qubes-utils (4.0.22) unstable; urgency=medium
|
||||
|
||||
* tests: skip img converter test if qubes-img-converter is not
|
||||
installed
|
||||
* imgconverter: allow icons up to 2048x2048
|
||||
* tests: skip the other img converter test too
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Mon, 29 Oct 2018 01:03:59 +0100
|
||||
|
||||
qubes-utils (4.0.21) unstable; urgency=medium
|
||||
|
||||
[ Rusty Bird ]
|
||||
* Order qubes-meminfo-writer-dom0 before systemd-user-sessions
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* rpm: adjust for fc29
|
||||
* travis: update Fedora and Debian versions
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Tue, 09 Oct 2018 00:25:11 +0200
|
||||
|
||||
qubes-utils (4.0.20) unstable; urgency=medium
|
||||
|
||||
* udev: create /dev/mapper/dmroot -> xvda3 symlink when its mounted
|
||||
directly
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Tue, 03 Jul 2018 21:11:00 +0200
|
||||
|
||||
qubes-utils (4.0.19) unstable; urgency=medium
|
||||
|
||||
* rpm: use proper macros for systemd handling
|
||||
* travis: add centos7
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Wed, 02 May 2018 17:55:09 +0200
|
||||
|
||||
qubes-utils (4.0.18) unstable; urgency=medium
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* udev: don't call udev-block-add-change for devices excluded by other
|
||||
rules
|
||||
* rpm: preparation for src.rpm building
|
||||
|
||||
[ Frédéric Pierret ]
|
||||
* Makefile.builder: currently disable Mock
|
||||
* Remove _builddir
|
||||
* Fix debug symbols
|
||||
* spec.in: add changelog placeholder
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* travis: update Fedora versions
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sat, 21 Apr 2018 14:36:39 +0200
|
||||
|
||||
qubes-utils (4.0.17) unstable; urgency=medium
|
||||
|
||||
[ Frédéric Pierret ]
|
||||
* Fix python3 package names with respect to CentOS for consistency
|
||||
with python34 names
|
||||
* Remove busybox as it is not provided in RHEL7 anymore
|
||||
* centos: fix python packages names
|
||||
* drop busybox dependance
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Tue, 27 Feb 2018 15:17:12 +0100
|
||||
|
||||
qubes-utils (4.0.16) unstable; urgency=medium
|
||||
|
||||
* qrexec: provide common function for handling service call
|
||||
* debian: adjust required version after adding new function
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Tue, 20 Feb 2018 00:05:31 +0100
|
||||
|
||||
qubes-utils (4.0.15) unstable; urgency=medium
|
||||
|
||||
* udev: update detecting usbip-connected devices
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Thu, 18 Jan 2018 19:07:40 +0100
|
||||
|
||||
qubes-utils (4.0.14) unstable; urgency=medium
|
||||
|
||||
[ Reynir Björnsson ]
|
||||
* Remove duplicate #define
|
||||
|
||||
[ Rusty Bird ]
|
||||
* udev-block-add-change: ignore unconnected Network Block Device
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Fri, 12 Jan 2018 06:16:05 +0100
|
||||
|
||||
qubes-utils (4.0.13) unstable; urgency=medium
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* imgconverter: fix make_padlock function
|
||||
* Update tests
|
||||
* travis: run imgconverter unit tests
|
||||
* Make tests python3 compatible
|
||||
* travis: run tests also on python3
|
||||
* travis: enable deploy stage for master-staging -> master gate
|
||||
|
||||
[ Gianluca Guida ]
|
||||
* Fix qrexec-lib headers
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* imgconverter: fix handling explicit file type
|
||||
* tests: integration tests for qvm-convert-img
|
||||
* travis: run only unit tests
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sat, 23 Dec 2017 02:50:19 +0100
|
||||
|
||||
qubes-utils (4.0.12) unstable; urgency=medium
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* debian: make it easier to spot missing files in debian/*.install
|
||||
* debian: include drauct module in qubes-kernel-vm-support
|
||||
|
||||
[ Patrick Schleizer ]
|
||||
* qubes-kernel-vm-support compatibility with dracut
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Tue, 12 Dec 2017 01:41:52 +0100
|
||||
|
||||
qubes-utils (4.0.11) unstable; urgency=medium
|
||||
|
||||
[ qubesuser ]
|
||||
* remove unused cairo import
|
||||
* add Python pillow and numpy dependencies
|
||||
* use PIL image library instead of ImageMagick to load/save images
|
||||
when tinting
|
||||
* reimplement tint algorithm with numpy for reasonable performance
|
||||
* replace tinting algorithm with one that partially preserves
|
||||
saturation too
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* Add missing classmethod decorator
|
||||
* Make udev-block-add-change executable again
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Tue, 21 Nov 2017 05:34:50 +0100
|
||||
|
||||
qubes-utils (4.0.10) unstable; urgency=medium
|
||||
|
||||
[ Olivier MEDOC ]
|
||||
* archlinux: build imgconverter with both python2 and python3
|
||||
|
||||
[ qubesuser ]
|
||||
* Speed up udev-block-add-change by not using xenstore
|
||||
|
||||
[ Your Name ]
|
||||
* This commit specifies the integer width explicitly to match
|
||||
`result_header_ext` etc.
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* Initialize pad field in filecopy final response
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Tue, 21 Nov 2017 04:46:49 +0100
|
||||
|
||||
qubes-utils (4.0.9) unstable; urgency=medium
|
||||
|
||||
* Fix initramfs scripts on Debian
|
||||
* qubes-prepare-vm-kernel: Include kernel and initramfs inside
|
||||
modules.img
|
||||
* initramfs: add support for variable partitions layout
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Tue, 17 Oct 2017 23:54:15 +0200
|
||||
|
||||
qubes-utils (4.0.8) unstable; urgency=medium
|
||||
|
||||
[ Frédéric Pierret ]
|
||||
* Fix CentOS dependencies: python3
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* travis: add fc26 build
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sat, 30 Sep 2017 01:59:38 +0200
|
||||
|
||||
qubes-utils (4.0.7) unstable; urgency=medium
|
||||
|
||||
[ Olivier MEDOC ]
|
||||
* Fix gcc Werror because of a typo in a switch/case explicit
|
||||
fallthrough comment
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* udev: fix loop devices exclusion based on directory flagfile
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Fri, 15 Sep 2017 13:43:18 +0200
|
||||
|
||||
qubes-utils (4.0.6) unstable; urgency=medium
|
||||
|
||||
[ Jean-Philippe Ouellet ]
|
||||
* Fix off-by-one error in header length calculation
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* udev: major cleanup in block devices handling
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Tue, 12 Sep 2017 04:52:48 +0200
|
||||
|
||||
qubes-utils (4.0.5) unstable; urgency=medium
|
||||
|
||||
* udev: filter-out QEMU devices
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Fri, 11 Aug 2017 13:34:11 +0200
|
||||
|
||||
qubes-utils (4.0.4) unstable; urgency=medium
|
||||
|
||||
[ HW42 ]
|
||||
* u2mfn: get mfn via pte
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sat, 29 Jul 2017 05:19:34 +0200
|
||||
|
||||
qubes-utils (4.0.3) unstable; urgency=medium
|
||||
|
||||
[ Rusty Bird ]
|
||||
* Fall back to sync() if syncfs() is unavailable
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* udev: don't list in qvm-block any device marked to be ignored by
|
||||
udev
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Thu, 06 Jul 2017 19:41:04 +0200
|
||||
|
||||
qubes-utils (4.0.2) unstable; urgency=medium
|
||||
|
||||
[ Paras Chetal ]
|
||||
* Fix include header syntax
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* initramfs: use symlink for rw root.img, instead of dm-linear
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sat, 24 Jun 2017 14:55:03 +0200
|
||||
|
||||
qubes-utils (4.0.1) unstable; urgency=medium
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* travis: switch to Qubes 4.0
|
||||
* rpm: add missing build requires
|
||||
* travis: drop fc23 vm packages building
|
||||
|
||||
[ unman ]
|
||||
* Improve error message when file exists
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* rpm: packge qubesimgconverter for both python2 and python3
|
||||
* imgconverter: make it really work on python3
|
||||
* imgconverter: use core3 API in get_from_vm()
|
||||
* rpm: add missing build requires
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Thu, 18 May 2017 01:54:46 +0200
|
||||
|
||||
qubes-utils (4.0.0) unstable; urgency=medium
|
||||
|
||||
[ Wojtek Porczyk ]
|
||||
* debian/control: remove unneeded qubesdb dependency
|
||||
* Package imgconverter as separate Python module
|
||||
* Move imggen module from artwork.
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* dracut: add missing 'die' function to 'simple' module
|
||||
* qmemman-meminfo-writer: send simplified meminfo value
|
||||
* Add python-setuptools to build depends
|
||||
* debian: adjust file list
|
||||
* Install python modules to /usr
|
||||
* initramfs: move qubes_cow_setup hook to pre-trigger
|
||||
* initramfs: add support for root.img with partition table
|
||||
* debian: fix install location of python files
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sat, 08 Apr 2017 13:58:53 +0200
|
||||
|
||||
qubes-utils (3.2.4) unstable; urgency=medium
|
||||
|
||||
[ Johanna A ]
|
||||
* Builds against 4.9
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* udev: use DM ignore device flag only for DM devices
|
||||
|
||||
[ Olivier MEDOC ]
|
||||
* archlinux: clean up qubes-prepare-vm-kernel
|
||||
* archlinux: clean up PKGBUILD and bump version number
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* travis: drop debootstrap workaround
|
||||
|
||||
[ Olivier MEDOC ]
|
||||
* archlinux: use dracut native file instead of our own
|
||||
|
||||
[ M. Vefa Bicakci ]
|
||||
* qubes-prepare-vm-kernel: Do not hardcode path to dracut
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Thu, 23 Mar 2017 11:34:01 +0100
|
||||
|
||||
qubes-utils (3.2.3) wheezy; urgency=medium
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* udev: make USB device version detection more generic
|
||||
* debian: reformat Build-Depends
|
||||
* debian: add pkg-config to Build-Depends
|
||||
|
||||
[ Rusty Bird ]
|
||||
* udev-block-add-change: better mount status check
|
||||
* udev-block-add-change: don't exclude already attached devs
|
||||
* udev-block-add-change: simplify a check
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* udev-block-add-change: fix checking if partition is mounted
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sun, 17 Jul 2016 05:17:40 +0200
|
||||
|
||||
qubes-utils (3.2.2) wheezy; urgency=medium
|
||||
|
||||
* udev: expose USB 3.0 devices for PV USB
|
||||
* udev: ignore usbip-connected USB devices
|
||||
* udev: fix removing USB entries
|
||||
* qrexec-lib: convert tabs to spaces
|
||||
* travis: initial version
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Thu, 02 Jun 2016 02:55:11 +0200
|
||||
|
||||
qubes-utils (3.2.1) wheezy; urgency=medium
|
||||
|
||||
* udev: fix deadlock on xenstore access during dom0 boot
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Wed, 18 May 2016 02:59:37 +0200
|
||||
|
||||
qubes-utils (3.2.0) wheezy; urgency=medium
|
||||
|
||||
[ Johanna A ]
|
||||
* Builds against linux v4.6-rc4
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* u2mfn: build for both 4.6+ and older kernels
|
||||
* udev/qvm-block: exclude devices used elsewhere
|
||||
* udev/qvm-block: exclude device if its partition is already attached
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Mon, 16 May 2016 11:54:16 +0200
|
||||
|
||||
qubes-utils (3.1.8) wheezy; urgency=medium
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* udev: fix hiding devices from qvm-block
|
||||
|
||||
[ Olivier MEDOC ]
|
||||
* archlinux: ensure gcc, make and pkgconfig are makedependencies
|
||||
* archlinux: implement kernel-support
|
||||
* kernel-support: compile u2mfn from source even if it has been never
|
||||
built
|
||||
* archlinux: add an install file specifically for vm-kernel-support
|
||||
* archlinux: fix syntax errors in install file
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Mon, 08 Feb 2016 05:06:21 +0100
|
||||
|
||||
qubes-utils (3.1.7) wheezy; urgency=medium
|
||||
|
||||
[ pqg ]
|
||||
* Fix build (installation) on Archlinux
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* Fix building Fedora package after Archlinux build fixes
|
||||
* udev: do not assume static device-mapper major number
|
||||
* udev: ignore devices set to be ignore elsewhere
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Thu, 07 Jan 2016 05:59:40 +0100
|
||||
|
||||
qubes-utils (3.1.6) wheezy; urgency=medium
|
||||
|
||||
[ HW42 ]
|
||||
* debian: remove obsolete conffiles in /etc/udev/rules.d
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* qrexec-lib: add glibc version test check for having syncfs
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sun, 13 Dec 2015 04:38:27 +0100
|
||||
|
||||
qubes-utils (3.1.5) wheezy; urgency=medium
|
||||
|
||||
* Fix for "debian: split libraries out of qubes-utils package"
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Mon, 30 Nov 2015 05:55:14 +0100
|
||||
|
||||
qubes-utils (3.1.4) wheezy; urgency=medium
|
||||
|
||||
[ qubesuser ]
|
||||
* Fix u2mfn.ko for > 16TB RAM by not truncating to 32-bit improperly
|
||||
|
||||
[ Rusty Bird ]
|
||||
* Check if QubesIncoming filesystem supports O_TMPFILE
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* rpm: disable debuginfo subpackage in qubes-kernel-vm-support
|
||||
* initramfs: fix swap size
|
||||
* qrexec: add clarification commends in qrexec.h
|
||||
|
||||
[ Rusty Bird ]
|
||||
* qfile-unpacker: syncfs() to avoid qvm-move-to-vm data loss
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* initramfs: use units of sectors in sfdisk call
|
||||
* initramfs: initialize volatile.img partition table also in
|
||||
TemplateVM
|
||||
* qubes-prepare-vm-kernel: ensure proper permissions on initramfs
|
||||
* debian: resolve quilt-build-dep-but-no-series-file lintian warning
|
||||
* Move udev scripts to /usr/lib/qubes, move rules to /lib/udev/
|
||||
* makefile: honor build env CFLAGS and LDFLAGS
|
||||
* debian: split libraries out of qubes-utils package
|
||||
* debian: break hardlink before modifying debian/....dkms
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Fri, 27 Nov 2015 20:44:04 +0100
|
||||
|
||||
qubes-utils (3.1.3) wheezy; urgency=medium
|
||||
|
||||
* qrexec-lib: add qfile packing functions to libqubes-rpc-filecopy
|
||||
* dracut: split 'full' dracut module into 'full-dmroot' and 'full-
|
||||
modules'
|
||||
* dracut: fix qubes-vm module dependencies
|
||||
* dracut: mount only subdirectory of /lib/modules
|
||||
* kernel-modules: build/install u2mfn module by default
|
||||
* dracut: add dmsetup --noudevsync since we're running in pre-udev
|
||||
hook
|
||||
* debian: introduce qubes-kernel-vm-support package
|
||||
* dracut: add a safety check preventing qubes_cow_setup.sh running in
|
||||
dom0
|
||||
* qrexec: define NOGUI_CMD_PREFIX
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Wed, 11 Nov 2015 05:12:11 +0100
|
||||
|
||||
qubes-utils (3.1.2) wheezy; urgency=medium
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* dracut: expand tabs to spaces
|
||||
* dracut: abort on dmroot assemble error
|
||||
* dracut: initialize volatile.img partitions
|
||||
* libqrexec-utils: fix linker options
|
||||
* libqrexec-utils: bring back buffered write helpers
|
||||
* libqrexec-utils: bump SO version because of ABI change
|
||||
|
||||
[ qubesuser ]
|
||||
* Fix u2mfn.ko for > 16TB RAM by not truncating to 32-bit improperly
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sat, 24 Oct 2015 23:05:02 +0200
|
||||
|
||||
qubes-utils (3.1.1) wheezy; urgency=medium
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* qfile-unpacker: do not call fdatasync() at each file (#1257)
|
||||
|
||||
[ qubesuser ]
|
||||
* Report Xen balloon current size instead of Linux total memory
|
||||
* use 64-bit integers for memory sizes to support > 2 TB RAM
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sun, 11 Oct 2015 02:48:12 +0200
|
||||
|
||||
qubes-utils (3.1.0) wheezy; urgency=medium
|
||||
|
||||
* impconverter: add icon data getters
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Wed, 30 Sep 2015 22:13:51 +0200
|
||||
|
||||
qubes-utils (3.0.10) wheezy; urgency=medium
|
||||
|
||||
[ Olivier MEDOC ]
|
||||
* archlinux: update to match new dependancies and archlinux /usr/lib
|
||||
guidelines
|
||||
* archlinux: ensure /usr/sbin is not use to follow archlinux packaging
|
||||
guidelines
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* imgconverter: ensure that connection to the VM is properly closed
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sat, 08 Aug 2015 04:23:00 +0200
|
||||
|
||||
qubes-utils (3.0.9) wheezy; urgency=medium
|
||||
|
||||
* imgconverter: use more meaningful error for empty icon image
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Wed, 08 Jul 2015 05:58:15 +0200
|
||||
|
||||
qubes-utils (3.0.8) wheezy; urgency=medium
|
||||
qubes-utils (2.0.21) wheezy; urgency=medium
|
||||
|
||||
* fedora: fix systemd service files permission
|
||||
* udev: do not use a separate lock for udev block scripts
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Wed, 01 Jul 2015 07:11:28 +0200
|
||||
|
||||
qubes-utils (3.0.7) wheezy; urgency=medium
|
||||
|
||||
* imgconverter: add eq operation for Image class
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Tue, 28 Apr 2015 13:23:09 +0200
|
||||
|
||||
qubes-utils (3.0.6) wheezy; urgency=medium
|
||||
|
||||
* imgconverter: do not start gui daemon
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Wed, 15 Apr 2015 18:49:02 +0200
|
||||
|
||||
qubes-utils (3.0.5) wheezy; urgency=medium
|
||||
|
||||
* udev: fix block devices ignoring rule
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Fri, 03 Apr 2015 11:26:47 +0200
|
||||
|
||||
qubes-utils (3.0.4) wheezy; urgency=medium
|
||||
|
||||
* udev: ignore temporary devices created during VM startup
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Wed, 01 Apr 2015 00:11:15 +0200
|
||||
|
||||
qubes-utils (3.0.3) wheezy; urgency=medium
|
||||
|
||||
* qrexec-lib: enable compiler optimization
|
||||
* udev: allow normal user to access /dev/xen/xenbus for vchan
|
||||
connections
|
||||
* Add VM kernel related files as qubes-core-vm-kernel-support package
|
||||
* dracut: do not assume full udevd running inside initramfs
|
||||
* Provide a script to generate VM kernel files
|
||||
* dracut: Provide minimalistic initramfs files - no udev, no systemd
|
||||
* dracut: load ext4 module manually in minimalistic dracut module
|
||||
* Compile u2mfn module only when not already present
|
||||
* udev: ignore temporary devices created during VM startup
|
||||
* udev: fix block devices ignoring rule
|
||||
* imgconverter: use more meaningful error for empty icon image
|
||||
* imgconverter: ensure that connection to the VM is properly closed
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Thu, 26 Mar 2015 23:57:42 +0100
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Tue, 29 Sep 2015 12:47:50 +0200
|
||||
|
||||
qubes-utils (3.0.2) jessie; urgency=medium
|
||||
qubes-utils (2.0.20) jessie; urgency=medium
|
||||
|
||||
* archlinux: fix new packaging requirements related to run, sbin,
|
||||
lib64...
|
||||
|
||||
-- Olivier MEDOC <o_medoc@yahoo.fr> Mon, 02 Feb 2015 00:19:22 +0100
|
||||
|
||||
qubes-utils (2.0.19) jessie; urgency=medium
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* qrexec: create stdin/out/err as sockets instead of pipes
|
||||
* debian: O_TMPFILE already defined
|
||||
|
||||
[ Jason Mehring ]
|
||||
* Removed -Werror from qrexec Makefile to allow unpack to compile for
|
||||
both Fedora 20 and 21
|
||||
* debian: Modified control file for new R3 Debian depends
|
||||
* debian: Updated changelog to reflect 3.0.1 version change
|
||||
* debian: Added qubesdb-vm as a depend
|
||||
* debian: Revert back to using libxen-dev as depend
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sun, 01 Feb 2015 03:07:29 +0100
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* Revert "Removed -Werror from qrexec Makefile to allow unpack to
|
||||
compile for both Fedora 20 and 21"
|
||||
qubes-utils (2.0.18) jessie; urgency=medium
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Tue, 17 Feb 2015 14:22:38 +0100
|
||||
|
||||
qubes-utils (3.0.1) jessie; urgency=medium
|
||||
|
||||
[ Wojciech Zygmunt Porczyk ]
|
||||
* v3.0.1
|
||||
* This has to be versioned because of dependency in core-agent-linux.
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* Update for new vchan API, remove code not needed anymore
|
||||
* filecopy: fix handling ENOENT error
|
||||
* Do not fail when file was successfully created.
|
||||
* I will test before commit. I will test before commit. I will...
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Fri, 23 Jan 2015 01:22:10 +0100
|
||||
|
||||
qubes-utils (2.0.17) jessie; urgency=medium
|
||||
|
||||
* filecopy: really do not use O_TMPFILE when use_tmpfile==0
|
||||
* When file opened with O_TMPFILE but use_tmpfile==0, the file will not be
|
||||
linked to the directory (the code at the end of process_one_file_reg).
|
||||
Additionally it is waste of time trying using O_TMPFILE when it's
|
||||
already known it shouldn't be.
|
||||
Also use_tmpfile==0 can mean we don't have access to /proc
|
||||
(set_procfs_fd wasn't called), so even if linking the file to its
|
||||
directory would be attempted, it would fail. This is the case for
|
||||
dom0-updates copy.
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* filecopy: create new file unaccessible to the user until fully written
|
||||
Otherwise source domain can modify (append) the file while the user
|
||||
already is accessing it. While incoming files should be treated as
|
||||
untrusted, this problem could allow file modification after the user
|
||||
makes some sanity checks.
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Wed, 21 Jan 2015 16:07:40 +0100
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* udev: update hotplug block scripts for QubesDB
|
||||
* Some initial work was done, but apparently not complete and buggy.
|
||||
qubes-utils (2.0.16) jessie; urgency=medium
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* version 3.0.0
|
||||
* filecopy: create new file unaccessible to the user until fully
|
||||
written
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* Fix compile warnings
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sun, 18 Jan 2015 18:05:35 +0100
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* qrexec-utils: add read_vchan_all and write_vchan_all
|
||||
* Similar to read_all and write_all.
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* qrexec: update protocol
|
||||
- add new messages
|
||||
- uniform packet header
|
||||
- organize #defines
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* code style: change tabs to spaces
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* qrexec-utils: disable write-stdin (buffered writes) compilation
|
||||
* Not compatible with new qrexec protocol yet. To be done.
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* New qrexec protocol
|
||||
* Use separate vchan to pass I/O for each process, which greatly simplify
|
||||
protocol implementation (eg. no flow control needed).
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* udev: setup permissions on xen device nodes
|
||||
|
||||
[ Marek Marczykowski ]
|
||||
* qrexec-lib: prevent deadlock on vchan
|
||||
It can happen that we already cleared libvchan_fd pending state via
|
||||
libvchan_wait, but data arrived later. This is especially true just
|
||||
after connection, when client send unsolicited notification to server,
|
||||
which can confuse it with some requested notification.
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Tue, 10 Feb 2015 00:00:00 +0100
|
||||
|
||||
qubes-utils (3.0.0) jessie; urgency=medium
|
||||
qubes-utils (2.0.15) jessie; urgency=medium
|
||||
|
||||
[ HW42 ]
|
||||
* use systemd in debian
|
||||
|
||||
[ Marek Marczykowski ]
|
||||
* Update for new vchan API, remove code not needed anymore
|
||||
* Use Qubes DB instead of Xenstore
|
||||
* qrexec-lib: prevent deadlock on vchan
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Mon, 01 Dec 2014 04:32:48 +0100
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
* udev: setup permissions on xen device nodes
|
||||
* New qrexec protocol
|
||||
* qrexec-utils: disable write-stdin (buffered writes) compilation
|
||||
* code style: change tabs to spaces
|
||||
* qrexec: update protocol
|
||||
* qrexec-utils: add read_vchan_all and write_vchan_all
|
||||
|
||||
-- Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Sat, 22 Nov 2014 16:24:11 +0100
|
||||
qubes-utils (2.0.14) jessie; urgency=medium
|
||||
|
||||
[ Marek Marczykowski-Górecki ]
|
||||
|
42
debian/control
vendored
42
debian/control
vendored
@ -2,12 +2,7 @@ Source: qubes-utils
|
||||
Section: admin
|
||||
Priority: extra
|
||||
Maintainer: Davíð Steinn Geirsson <david@dsg.is>
|
||||
Build-Depends:
|
||||
libxen-dev,
|
||||
pkg-config,
|
||||
debhelper (>= 9.0.0),
|
||||
dh-systemd,
|
||||
python-setuptools,
|
||||
Build-Depends: libvchan-xen-dev, libxen-dev, debhelper (>= 8.0.0), quilt (>= 0.60), dh-systemd
|
||||
Standards-Version: 3.9.3
|
||||
Homepage: http://www.qubes-os.org
|
||||
Vcs-Git: http://dsg.is/qubes/qubes-linux-utils.git
|
||||
@ -15,41 +10,8 @@ Vcs-Git: http://dsg.is/qubes/qubes-linux-utils.git
|
||||
|
||||
Package: qubes-utils
|
||||
Architecture: any
|
||||
Depends: lsb-base, python-pil, python-numpy, python3-pil, python3-numpy, ${shlibs:Depends}, ${misc:Depends}
|
||||
Depends: libvchan-xen, lsb-base, ${shlibs:Depends}, ${misc:Depends}
|
||||
Conflicts: qubes-linux-utils
|
||||
Breaks: qubes-core-agent (<< 3.1.4)
|
||||
Recommends: python2.7
|
||||
Description: Qubes Linux utilities
|
||||
This package includes the basic qubes utilities necessary for domU.
|
||||
|
||||
Package: qubes-kernel-vm-support
|
||||
Architecture: any
|
||||
Depends:
|
||||
busybox,
|
||||
initramfs-tools | dracut,
|
||||
grub2-common,
|
||||
${misc:Depends}
|
||||
Description: Qubes VM kernel and initramfs modules
|
||||
This package contains:
|
||||
1. mkinitramfs module required to setup Qubes VM root filesystem. This package
|
||||
is needed in VM only when the VM uses its own kernel (via pvgrub or so).
|
||||
Otherwise initrd is provided by dom0.
|
||||
|
||||
Package: libqubes-rpc-filecopy2
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Breaks: qubes-utils (<< 3.1.4)
|
||||
Replaces: qubes-utils (<< 3.1.4)
|
||||
Description: Qubes file copy protocol library
|
||||
This library can be used for both sending files using qfile protocol and for
|
||||
receiving them.
|
||||
|
||||
Package: libqubes-rpc-filecopy-dev
|
||||
Architecture: any
|
||||
Section: libdevel
|
||||
Depends: libqubes-rpc-filecopy2 (= ${binary:Version}), ${misc:Depends}
|
||||
Breaks: qubes-utils (<< 3.1.4)
|
||||
Replaces: qubes-utils (<< 3.1.4)
|
||||
Description: Development headers for libqrexec-utils
|
||||
This package contains files required to compile Qubes file copy related
|
||||
utilities like qfile-agent.
|
||||
|
2
debian/libqubes-rpc-filecopy-dev.install
vendored
2
debian/libqubes-rpc-filecopy-dev.install
vendored
@ -1,2 +0,0 @@
|
||||
usr/include/libqubes-rpc-filecopy.h
|
||||
usr/lib/libqubes-rpc-filecopy.so
|
1
debian/libqubes-rpc-filecopy2.install
vendored
1
debian/libqubes-rpc-filecopy2.install
vendored
@ -1 +0,0 @@
|
||||
usr/lib/libqubes-rpc-filecopy.so.2*
|
1
debian/libqubes-rpc-filecopy2.shlibs
vendored
1
debian/libqubes-rpc-filecopy2.shlibs
vendored
@ -1 +0,0 @@
|
||||
libqubes-rpc-filecopy 2 libqubes-rpc-filecopy2 (>= 3.1.3)
|
8
debian/qubes-kernel-vm-support.install
vendored
8
debian/qubes-kernel-vm-support.install
vendored
@ -1,8 +0,0 @@
|
||||
usr/share/initramfs-tools/scripts/local-top/scrub_pages
|
||||
usr/share/initramfs-tools/scripts/local-top/qubes_cow_setup
|
||||
usr/share/initramfs-tools/hooks/qubes_vm
|
||||
usr/lib/dracut/modules.d/90qubes-vm/*
|
||||
usr/lib/dracut/modules.d/90qubes-vm-modules/*
|
||||
usr/lib/dracut/modules.d/90qubes-vm-simple/*
|
||||
usr/lib/dracut/modules.d/80xen-scrub-pages/*
|
||||
etc/default/grub.d/30-qubes-kernel-vm-support.cfg
|
64
debian/qubes-kernel-vm-support.postinst
vendored
64
debian/qubes-kernel-vm-support.postinst
vendored
@ -1,64 +0,0 @@
|
||||
#!/bin/bash
|
||||
# postinst script for qubes-kernel-vm-support
|
||||
#
|
||||
# see: dh_installdeb(1)
|
||||
|
||||
set -e
|
||||
|
||||
# The postinst script may be called in the following ways:
|
||||
# * <postinst> 'configure' <most-recently-configured-version>
|
||||
# * <old-postinst> 'abort-upgrade' <new version>
|
||||
# * <conflictor's-postinst> 'abort-remove' 'in-favour' <package>
|
||||
# <new-version>
|
||||
# * <postinst> 'abort-remove'
|
||||
# * <deconfigured's-postinst> 'abort-deconfigure' 'in-favour'
|
||||
# <failed-install-package> <version> 'removing'
|
||||
# <conflicting-package> <version>
|
||||
#
|
||||
# For details, see http://www.debian.org/doc/debian-policy/ or
|
||||
# https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html or
|
||||
# the debian-policy package
|
||||
|
||||
|
||||
case "${1}" in
|
||||
configure)
|
||||
if [ -x /usr/sbin/update-initramfs ]; then
|
||||
if update-initramfs -u; then
|
||||
# "milestone" initramfs update version:
|
||||
# 1 - addition of xen scrub_pages enabling code
|
||||
echo 1 > /var/lib/qubes/initramfs-updated
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
|
||||
abort-upgrade|abort-remove|abort-deconfigure)
|
||||
exit 0
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "postinst called with unknown argument \`${1}'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# dh_installdeb will replace this with shell code automatically
|
||||
# generated by other debhelper scripts.
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
## https://phabricator.whonix.org/T377
|
||||
## Debian has no update-grub trigger yet:
|
||||
## https://bugs.debian.org/481542
|
||||
|
||||
if command -v update-grub >/dev/null 2>&1; then
|
||||
update-grub || \
|
||||
echo "$DPKG_MAINTSCRIPT_PACKAGE $DPKG_MAINTSCRIPT_NAME ERROR: Running \
|
||||
'update-grub' failed with exit code $?. $DPKG_MAINTSCRIPT_PACKAGE is most \
|
||||
likely only the trigger, not the cause. Unless you know this is not an issue, \
|
||||
you should fix running 'update-grub', otherwise your system might no longer \
|
||||
boot." >&2
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
||||
# vim: set ts=4 sw=4 sts=4 et :
|
9
debian/qubes-kernel-vm-support.preinst
vendored
9
debian/qubes-kernel-vm-support.preinst
vendored
@ -1,9 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
mkdir --parents /boot/grub || true
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
5
debian/qubes-utils.install
vendored
5
debian/qubes-utils.install
vendored
@ -1,5 +0,0 @@
|
||||
usr/sbin/meminfo-writer
|
||||
lib/systemd/system/qubes-meminfo-writer.service
|
||||
usr/lib/qubes/*
|
||||
usr/lib/python2.7/dist-packages/qubesimgconverter*/*
|
||||
lib/udev/*
|
3
debian/qubes-utils.maintscript
vendored
3
debian/qubes-utils.maintscript
vendored
@ -1,3 +0,0 @@
|
||||
rm_conffile /etc/udev/rules.d/99-qubes-block.rules 3.1.6~
|
||||
rm_conffile /etc/udev/rules.d/99-qubes-usb.rules 3.1.6~
|
||||
rm_conffile /etc/udev/rules.d/99-qubes-misc.rules 3.1.6~
|
10
debian/rules
vendored
10
debian/rules
vendored
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/make -f
|
||||
# -*- makefile -*-
|
||||
|
||||
export DESTDIR=$(shell pwd)/debian/tmp
|
||||
export DESTDIR=$(shell pwd)/debian/qubes-utils
|
||||
|
||||
# Uncomment this to turn on verbose mode.
|
||||
#export DH_VERBOSE=1
|
||||
@ -13,10 +13,4 @@ override_dh_auto_build:
|
||||
make all LIBDIR=/usr/lib DEBIANBUILD=1
|
||||
|
||||
override_dh_auto_install:
|
||||
make install LIBDIR=/usr/lib DEBIANBUILD=1 PYTHON_PREFIX_ARG=--install-layout=deb
|
||||
make install-debian-kernel-support LIBDIR=/usr/lib DEBIANBUILD=1
|
||||
# dom0-only file
|
||||
rm -f $(DESTDIR)/usr/sbin/qubes-prepare-vm-kernel
|
||||
|
||||
override_dh_install:
|
||||
dh_install --fail-missing
|
||||
make install LIBDIR=/usr/lib DEBIANBUILD=1
|
||||
|
@ -1,5 +0,0 @@
|
||||
install:
|
||||
$(MAKE) -C simple
|
||||
$(MAKE) -C full-dmroot
|
||||
$(MAKE) -C full-modules
|
||||
$(MAKE) -C xen-balloon-scrub-pages
|
@ -1,4 +0,0 @@
|
||||
install:
|
||||
install -d $(DESTDIR)/usr/lib/dracut/modules.d/90qubes-vm
|
||||
install module-setup.sh qubes_cow_setup.sh \
|
||||
$(DESTDIR)/usr/lib/dracut/modules.d/90qubes-vm/
|
@ -1,21 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
check() {
|
||||
if xenstore-read qubes-vm-type &>/dev/null || qubesdb-read /qubes-vm-type &>/dev/null; then
|
||||
return 0
|
||||
else
|
||||
return 255
|
||||
fi
|
||||
}
|
||||
|
||||
depends() {
|
||||
echo dm
|
||||
return 0
|
||||
}
|
||||
|
||||
install() {
|
||||
inst_hook pre-trigger 90 $moddir/qubes_cow_setup.sh
|
||||
inst_multiple \
|
||||
sfdisk \
|
||||
mkswap
|
||||
}
|
@ -1,114 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# This file should be placed in pre-trigger directory in dracut's initramfs, or
|
||||
# scripts/local-top in case of initramfs-tools
|
||||
#
|
||||
|
||||
# initramfs-tools (Debian) API
|
||||
PREREQS=""
|
||||
case "$1" in
|
||||
prereqs)
|
||||
# This runs during initramfs creation
|
||||
echo "$PREREQS"
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
# This runs inside real initramfs
|
||||
if [ -r /scripts/functions ]; then
|
||||
# We're running in Debian's initramfs
|
||||
. /scripts/functions
|
||||
alias die=panic
|
||||
alias info=true
|
||||
alias warn=log_warning_msg
|
||||
alias log_begin=log_begin_msg
|
||||
alias log_end=log_end_msg
|
||||
elif [ -r /lib/dracut-lib.sh ]; then
|
||||
. /lib/dracut-lib.sh
|
||||
alias log_begin=info
|
||||
alias log_end=true
|
||||
else
|
||||
die() {
|
||||
echo "$@"
|
||||
exit 1
|
||||
}
|
||||
alias info=echo
|
||||
alias warn=echo
|
||||
alias log_begin=echo
|
||||
alias log_end=true
|
||||
fi
|
||||
|
||||
|
||||
info "Qubes initramfs script here:"
|
||||
|
||||
if ! grep -q 'root=[^ ]*dmroot' /proc/cmdline; then
|
||||
warn "dmroot not requested, probably not a Qubes VM"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -e /dev/mapper/dmroot ] ; then
|
||||
die "Qubes: FATAL error: /dev/mapper/dmroot already exists?!"
|
||||
fi
|
||||
|
||||
modprobe xenblk || modprobe xen-blkfront || warn "Qubes: Cannot load Xen Block Frontend..."
|
||||
|
||||
log_begin "Waiting for /dev/xvda* devices..."
|
||||
udevadm settle --exit-if-exists=/dev/xvda
|
||||
log_end
|
||||
|
||||
# prefer partition if exists
|
||||
if [ -b /dev/xvda1 ]; then
|
||||
if [ -e "/dev/disk/by-partlabel/Root\\x20filesystem" ]; then
|
||||
ROOT_DEV=$(basename $(readlink "/dev/disk/by-partlabel/Root\\x20filesystem"))
|
||||
else
|
||||
ROOT_DEV=xvda3
|
||||
fi
|
||||
else
|
||||
ROOT_DEV=xvda
|
||||
fi
|
||||
|
||||
SWAP_SIZE=$(( 1024 * 1024 * 2 )) # sectors, 1GB
|
||||
|
||||
if [ `cat /sys/class/block/$ROOT_DEV/ro` = 1 ] ; then
|
||||
log_begin "Qubes: Doing COW setup for AppVM..."
|
||||
|
||||
while ! [ -e /dev/xvdc ]; do sleep 0.1; done
|
||||
VOLATILE_SIZE=$(cat /sys/class/block/xvdc/size) # sectors
|
||||
ROOT_SIZE=$(cat /sys/class/block/$ROOT_DEV/size) # sectors
|
||||
if [ $VOLATILE_SIZE -lt $SWAP_SIZE ]; then
|
||||
die "volatile.img smaller than 1GB, cannot continue"
|
||||
fi
|
||||
sfdisk -q --unit S /dev/xvdc >/dev/null <<EOF
|
||||
xvdc1: type=82,start=2048,size=$SWAP_SIZE
|
||||
xvdc2: type=83
|
||||
EOF
|
||||
if [ $? -ne 0 ]; then
|
||||
die "Qubes: failed to setup partitions on volatile device"
|
||||
fi
|
||||
while ! [ -e /dev/xvdc1 ]; do sleep 0.1; done
|
||||
mkswap /dev/xvdc1
|
||||
while ! [ -e /dev/xvdc2 ]; do sleep 0.1; done
|
||||
|
||||
echo "0 `cat /sys/class/block/$ROOT_DEV/size` snapshot /dev/$ROOT_DEV /dev/xvdc2 N 16" | \
|
||||
dmsetup --noudevsync create dmroot || die "Qubes: FATAL: cannot create dmroot!"
|
||||
dmsetup mknodes dmroot
|
||||
log_end
|
||||
else
|
||||
log_begin "Qubes: Doing R/W setup for TemplateVM..."
|
||||
while ! [ -e /dev/xvdc ]; do sleep 0.1; done
|
||||
sfdisk -q --unit S /dev/xvdc >/dev/null <<EOF
|
||||
xvdc1: type=82,start=2048,size=$SWAP_SIZE
|
||||
xvdc3: type=83
|
||||
EOF
|
||||
if [ $? -ne 0 ]; then
|
||||
die "Qubes: failed to setup partitions on volatile device"
|
||||
fi
|
||||
while ! [ -e /dev/xvdc1 ]; do sleep 0.1; done
|
||||
mkswap /dev/xvdc1
|
||||
mkdir -p /etc/udev/rules.d
|
||||
printf 'KERNEL=="%s", SYMLINK+="mapper/dmroot"\n' "$ROOT_DEV" >> \
|
||||
/etc/udev/rules.d/99-root.rules
|
||||
udevadm control -R
|
||||
udevadm trigger
|
||||
log_end
|
||||
fi
|
@ -1,4 +0,0 @@
|
||||
install:
|
||||
install -d $(DESTDIR)/usr/lib/dracut/modules.d/90qubes-vm-modules
|
||||
install module-setup.sh mount_modules.sh \
|
||||
$(DESTDIR)/usr/lib/dracut/modules.d/90qubes-vm-modules/
|
@ -1,9 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
check() {
|
||||
return 255
|
||||
}
|
||||
|
||||
install() {
|
||||
inst_hook pre-pivot 50 $moddir/mount_modules.sh
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# This file should be places in pre-pivot directory in dracut's initramfs
|
||||
#
|
||||
|
||||
|
||||
kver="`uname -r`"
|
||||
if ! [ -d "$NEWROOT/lib/modules/$kver/kernel" ]; then
|
||||
echo "Waiting for /dev/xvdd device..."
|
||||
while ! [ -e /dev/xvdd ]; do sleep 0.1; done
|
||||
|
||||
# Mount only `uname -r` subdirectory, to leave the rest of /lib/modules writable
|
||||
mkdir -p /tmp/modules
|
||||
mount -n -t ext3 /dev/xvdd /tmp/modules
|
||||
if ! [ -d "$NEWROOT/lib/modules/$kver" ]; then
|
||||
mount "$NEWROOT" -o remount,rw
|
||||
mkdir -p "$NEWROOT/lib/modules/$kver"
|
||||
mount "$NEWROOT" -o remount,ro
|
||||
fi
|
||||
mount --bind "/tmp/modules/$kver" "$NEWROOT/lib/modules/$kver"
|
||||
umount /tmp/modules
|
||||
rmdir /tmp/modules
|
||||
fi
|
||||
|
||||
killall udevd systemd-udevd
|
@ -1,6 +0,0 @@
|
||||
install:
|
||||
install -d $(DESTDIR)/usr/lib/dracut/modules.d/90qubes-vm-simple
|
||||
install module-setup.sh init.sh \
|
||||
$(DESTDIR)/usr/lib/dracut/modules.d/90qubes-vm-simple/
|
||||
# flag indicating the module will (re-)enable scrub-pages option
|
||||
touch $(DESTDIR)/usr/lib/dracut/modules.d/90qubes-vm-simple/xen-scrub-pages-supported
|
@ -1,121 +0,0 @@
|
||||
#!/bin/sh
|
||||
echo "Qubes initramfs script here:"
|
||||
|
||||
mkdir -p /proc /sys /dev
|
||||
mount -t proc proc /proc
|
||||
mount -t sysfs sysfs /sys
|
||||
mount -t devtmpfs devtmpfs /dev
|
||||
|
||||
if [ -w /sys/devices/system/xen_memory/xen_memory0/scrub_pages ]; then
|
||||
# re-enable xen-balloon pages scrubbing, after initial balloon down
|
||||
echo 1 > /sys/devices/system/xen_memory/xen_memory0/scrub_pages
|
||||
fi
|
||||
|
||||
if [ -e /dev/mapper/dmroot ] ; then
|
||||
echo "Qubes: FATAL error: /dev/mapper/dmroot already exists?!"
|
||||
fi
|
||||
|
||||
/sbin/modprobe xenblk || /sbin/modprobe xen-blkfront || echo "Qubes: Cannot load Xen Block Frontend..."
|
||||
|
||||
die() {
|
||||
echo "$@" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "Waiting for /dev/xvda* devices..."
|
||||
while ! [ -e /dev/xvda ]; do sleep 0.1; done
|
||||
|
||||
# prefer partition if exists
|
||||
if [ -b /dev/xvda1 ]; then
|
||||
if [ -d /dev/disk/by-partlabel ]; then
|
||||
ROOT_DEV=$(basename $(readlink "/dev/disk/by-partlabel/Root\\x20filesystem"))
|
||||
else
|
||||
ROOT_DEV=$(grep -l "PARTNAME=Root filesystem" /sys/block/xvda/xvda*/uevent |\
|
||||
grep -o "xvda[0-9]")
|
||||
fi
|
||||
if [ -z "$ROOT_DEV" ]; then
|
||||
# fallback to third partition
|
||||
ROOT_DEV=xvda3
|
||||
fi
|
||||
else
|
||||
ROOT_DEV=xvda
|
||||
fi
|
||||
|
||||
SWAP_SIZE=$(( 1024 * 1024 * 2 )) # sectors, 1GB
|
||||
|
||||
if [ `cat /sys/class/block/$ROOT_DEV/ro` = 1 ] ; then
|
||||
echo "Qubes: Doing COW setup for AppVM..."
|
||||
|
||||
while ! [ -e /dev/xvdc ]; do sleep 0.1; done
|
||||
VOLATILE_SIZE=$(cat /sys/class/block/xvdc/size) # sectors
|
||||
ROOT_SIZE=$(cat /sys/class/block/$ROOT_DEV/size) # sectors
|
||||
if [ $VOLATILE_SIZE -lt $SWAP_SIZE ]; then
|
||||
die "volatile.img smaller than 1GB, cannot continue"
|
||||
fi
|
||||
/sbin/sfdisk -q --unit S /dev/xvdc >/dev/null <<EOF
|
||||
xvdc1: type=82,start=2048,size=$SWAP_SIZE
|
||||
xvdc2: type=83
|
||||
EOF
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Qubes: failed to setup partitions on volatile device"
|
||||
exit 1
|
||||
fi
|
||||
while ! [ -e /dev/xvdc1 ]; do sleep 0.1; done
|
||||
/sbin/mkswap /dev/xvdc1
|
||||
while ! [ -e /dev/xvdc2 ]; do sleep 0.1; done
|
||||
|
||||
echo "0 `cat /sys/class/block/$ROOT_DEV/size` snapshot /dev/$ROOT_DEV /dev/xvdc2 N 16" | \
|
||||
/sbin/dmsetup create dmroot || { echo "Qubes: FATAL: cannot create dmroot!"; exit 1; }
|
||||
/sbin/dmsetup mknodes dmroot
|
||||
echo Qubes: done.
|
||||
else
|
||||
echo "Qubes: Doing R/W setup for TemplateVM..."
|
||||
while ! [ -e /dev/xvdc ]; do sleep 0.1; done
|
||||
/sbin/sfdisk -q --unit S /dev/xvdc >/dev/null <<EOF
|
||||
xvdc1: type=82,start=2048,size=$SWAP_SIZE
|
||||
xvdc3: type=83
|
||||
EOF
|
||||
if [ $? -ne 0 ]; then
|
||||
die "Qubes: failed to setup partitions on volatile device"
|
||||
fi
|
||||
while ! [ -e /dev/xvdc1 ]; do sleep 0.1; done
|
||||
/sbin/mkswap /dev/xvdc1
|
||||
ln -s ../$ROOT_DEV /dev/mapper/dmroot
|
||||
echo Qubes: done.
|
||||
fi
|
||||
|
||||
/sbin/modprobe ext4
|
||||
|
||||
mkdir -p /sysroot
|
||||
mount /dev/mapper/dmroot /sysroot -o rw
|
||||
NEWROOT=/sysroot
|
||||
|
||||
kver="`uname -r`"
|
||||
if ! [ -d "$NEWROOT/lib/modules/$kver/kernel" ]; then
|
||||
echo "Waiting for /dev/xvdd device..."
|
||||
while ! [ -e /dev/xvdd ]; do sleep 0.1; done
|
||||
|
||||
mkdir -p /tmp/modules
|
||||
mount -n -t ext3 /dev/xvdd /tmp/modules
|
||||
if /sbin/modprobe overlay; then
|
||||
# if overlayfs is supported, use that to provide fully writable /lib/modules
|
||||
if ! [ -d "$NEWROOT/lib/.modules_work" ]; then
|
||||
mkdir -p "$NEWROOT/lib/.modules_work"
|
||||
fi
|
||||
mount -t overlay none $NEWROOT/lib/modules -o lowerdir=/tmp/modules,upperdir=$NEWROOT/lib/modules,workdir=$NEWROOT/lib/.modules_work
|
||||
else
|
||||
# otherwise mount only `uname -r` subdirectory, to leave the rest of
|
||||
# /lib/modules writable
|
||||
if ! [ -d "$NEWROOT/lib/modules/$kver" ]; then
|
||||
mkdir -p "$NEWROOT/lib/modules/$kver"
|
||||
fi
|
||||
mount --bind "/tmp/modules/$kver" "$NEWROOT/lib/modules/$kver"
|
||||
fi
|
||||
umount /tmp/modules
|
||||
rmdir /tmp/modules
|
||||
fi
|
||||
|
||||
umount /dev /sys /proc
|
||||
mount "$NEWROOT" -o remount,ro
|
||||
|
||||
exec /sbin/switch_root $NEWROOT /sbin/init
|
@ -1,34 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
check() {
|
||||
return 255
|
||||
}
|
||||
|
||||
depends() {
|
||||
echo dm
|
||||
return 0
|
||||
}
|
||||
|
||||
installkernel() {
|
||||
hostonly='' instmods overlay
|
||||
}
|
||||
|
||||
install() {
|
||||
inst $moddir/init.sh /init
|
||||
inst_multiple \
|
||||
basename \
|
||||
readlink \
|
||||
uname \
|
||||
grep \
|
||||
kmod \
|
||||
modprobe \
|
||||
ln \
|
||||
switch_root \
|
||||
mount \
|
||||
umount \
|
||||
mkdir \
|
||||
rmdir \
|
||||
sleep \
|
||||
sfdisk \
|
||||
mkswap
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
install:
|
||||
install -d $(DESTDIR)/usr/lib/dracut/modules.d/80xen-scrub-pages
|
||||
install module-setup.sh scrub_pages.sh \
|
||||
$(DESTDIR)/usr/lib/dracut/modules.d/80xen-scrub-pages/
|
@ -1,17 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
check() {
|
||||
if [ -r /usr/share/qubes/marker-vm ]; then
|
||||
return 0
|
||||
else
|
||||
return 255
|
||||
fi
|
||||
}
|
||||
|
||||
depends() {
|
||||
return 0
|
||||
}
|
||||
|
||||
install() {
|
||||
inst_hook pre-trigger 60 $moddir/scrub_pages.sh
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# This file should be placed in pre-trigger directory in dracut's initramfs, or
|
||||
# scripts/local-top in case of initramfs-tools
|
||||
#
|
||||
|
||||
# initramfs-tools (Debian) API
|
||||
PREREQS=""
|
||||
case "$1" in
|
||||
prereqs)
|
||||
# This runs during initramfs creation
|
||||
echo "$PREREQS"
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -w /sys/devices/system/xen_memory/xen_memory0/scrub_pages ]; then
|
||||
# re-enable xen-balloon pages scrubbing, after initial balloon down
|
||||
echo 1 > /sys/devices/system/xen_memory/xen_memory0/scrub_pages
|
||||
fi
|
@ -1,7 +0,0 @@
|
||||
install-fedora:
|
||||
install -D -m 0644 grub.qubes-kernel-vm-support \
|
||||
$(DESTDIR)/etc/default/grub.qubes-kernel-vm-support
|
||||
|
||||
install-debian:
|
||||
install -D -m 0644 grub.qubes-kernel-vm-support \
|
||||
$(DESTDIR)/etc/default/grub.d/30-qubes-kernel-vm-support.cfg
|
@ -1,8 +0,0 @@
|
||||
# add kernel options only in VM, and only if initramfs is updated already
|
||||
# /var/lib/qubes/initramfs-updated contains "milestone" initramfs update version:
|
||||
# 1 - addition of xen scrub_pages enabling code
|
||||
if [ -r /usr/share/qubes/marker-vm ] &&
|
||||
[ "$(cat /var/lib/qubes/initramfs-updated 2>/dev/null || echo 0)" -ge 1 ]; then
|
||||
GRUB_CMDLINE_LINUX="$GRUB_CMDLINE_LINUX xen_scrub_pages=0"
|
||||
fi
|
||||
GRUB_ENABLE_BLSCFG=false
|
@ -1,18 +0,0 @@
|
||||
PYTHON ?= python
|
||||
|
||||
all:
|
||||
$(PYTHON) setup.py build
|
||||
.PHONY: all
|
||||
|
||||
clean:
|
||||
$(PYTHON) setup.py clean
|
||||
.PHONY: clean
|
||||
|
||||
install:
|
||||
$(PYTHON) setup.py install -O1 $(PYTHON_PREFIX_ARG) --root $(DESTDIR)
|
||||
#ifeq (1,${DEBIANBUILD})
|
||||
# cp *.py $(DESTDIR)/$(PYTHON_SITEARCH)/qubes/
|
||||
#else
|
||||
# cp *.py* $(DESTDIR)/$(PYTHON_SITEARCH)/qubes/
|
||||
#endif
|
||||
.PHONY: install
|
@ -1,90 +0,0 @@
|
||||
#!/usr/bin/env python2
|
||||
|
||||
'''Qubes Image Generation
|
||||
|
||||
Toolkit for generating icons and images for Qubes OS.'''
|
||||
|
||||
# The Qubes OS Project, http://www.qubes-os.org
|
||||
#
|
||||
# Copyright (C) 2013-2015 Wojtek Porczyk <woju@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.
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
__all__ = ['make_padlock']
|
||||
|
||||
import math
|
||||
import cairo
|
||||
|
||||
import qubesimgconverter
|
||||
|
||||
def polar(r, a):
|
||||
return r * math.cos(a), r * math.sin(a)
|
||||
|
||||
def make_padlock(dst, colour, size=qubesimgconverter.ICON_MAXSIZE, disp=False):
|
||||
cs = cairo.ImageSurface(cairo.FORMAT_ARGB32, size, size)
|
||||
|
||||
cr = cairo.Context(cs)
|
||||
cr.set_source_rgb(*[c / 256.0
|
||||
for c in qubesimgconverter.hex_to_int(colour)])
|
||||
cr.set_line_width(.125 * size)
|
||||
|
||||
cr.rectangle(.125 * size, .5 * size, .75 * size, .4375 * size)
|
||||
cr.fill()
|
||||
|
||||
cr.move_to(.25 * size, .5 * size)
|
||||
cr.line_to(.25 * size, .375 * size)
|
||||
cr.arc(.5 * size, .375 * size, .25 * size, math.pi, 2 * math.pi)
|
||||
cr.move_to(.75 * size, .375 * size) # this is unneccessary, but helps readability
|
||||
cr.line_to(.75 * size, .5 * size)
|
||||
cr.stroke()
|
||||
|
||||
if disp:
|
||||
# Careful with those. I have run into severe
|
||||
# floating point errors when adjusting.
|
||||
arrows = 2
|
||||
gap = 45 * math.pi / 180
|
||||
offset = 0
|
||||
radius = .1875 * size
|
||||
width = 0.05 * size
|
||||
cx = .5 * size
|
||||
# cy = .6875 * size
|
||||
cy = .625 * size
|
||||
|
||||
arrow = 2 * math.pi / arrows
|
||||
|
||||
for i in range(arrows):
|
||||
cr.move_to(cx, cy)
|
||||
cr.rel_move_to(*polar( radius - width, offset + i * arrow))
|
||||
cr.arc(cx, cy, radius - width, offset + i * arrow, offset + (i + 1) * arrow - gap)
|
||||
cr.rel_line_to(*polar( width, offset + (i + 1) * arrow - gap + math.pi))
|
||||
cr.rel_line_to(*polar( width * math.sqrt(8), offset + (i + 1) * arrow - gap + math.pi / 4))
|
||||
cr.rel_line_to(*polar( width * math.sqrt(8), offset + (i + 1) * arrow - gap - math.pi / 4))
|
||||
cr.rel_line_to(*polar( width, offset + (i + 1) * arrow - gap + math.pi))
|
||||
cr.arc_negative(cx, cy, radius + width, offset + (i + 1) * arrow - gap, offset + i * arrow)
|
||||
cr.close_path()
|
||||
|
||||
cr.set_source_rgb(0xcc / 256.0, 0, 0) # tango's red
|
||||
cr.set_line_width(.0500 * size)
|
||||
cr.set_line_join(cairo.LINE_JOIN_ROUND)
|
||||
cr.stroke_preserve()
|
||||
|
||||
cr.set_source_rgb(1.0, 1.0, 1.0)
|
||||
cr.fill()
|
||||
|
||||
cs.write_to_png(dst)
|
||||
|
||||
# vim: ft=python sw=4 ts=4 et
|
@ -1,81 +0,0 @@
|
||||
#!/usr/bin/env python2
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
try:
|
||||
from io import BytesIO
|
||||
except ImportError:
|
||||
from cStringIO import StringIO as BytesIO
|
||||
import unittest
|
||||
|
||||
import qubesimgconverter
|
||||
|
||||
class TestCaseImage(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.rgba = \
|
||||
b'\x00\x00\x00\xff' b'\xff\x00\x00\xff' \
|
||||
b'\x00\xff\x00\xff' b'\x00\x00\x00\xff'
|
||||
self.size = (2, 2)
|
||||
|
||||
self.image = qubesimgconverter.Image(rgba=self.rgba, size=self.size)
|
||||
|
||||
def test_00_init(self):
|
||||
self.assertEqual(self.image._rgba, self.rgba)
|
||||
self.assertEqual(self.image._size, self.size)
|
||||
|
||||
def test_01_tint(self):
|
||||
image = self.image.tint('#0000ff')
|
||||
|
||||
self.assertEqual(image._rgba,
|
||||
b'\x00\x00\x3f\xff' b'\x00\x00\xff\xff'
|
||||
b'\x00\x00\xff\xff' b'\x00\x00\x3f\xff')
|
||||
|
||||
def test_10_get_from_stream(self):
|
||||
io = BytesIO('{0[0]} {0[1]}\n'.format(self.size).encode() + self.rgba)
|
||||
|
||||
image = qubesimgconverter.Image.get_from_stream(io)
|
||||
|
||||
self.assertEqual(image._rgba, self.rgba)
|
||||
self.assertEqual(image._size, self.size)
|
||||
|
||||
def test_11_get_from_stream_malformed(self):
|
||||
io = BytesIO('{0[0]} {0[1]}\n'.format(self.size).encode() +
|
||||
self.rgba[:-1]) # one byte too short
|
||||
|
||||
with self.assertRaises(Exception):
|
||||
image = qubesimgconverter.Image.get_from_stream(io)
|
||||
|
||||
def test_12_get_from_stream_too_big(self):
|
||||
io = BytesIO('{0[0]} {0[1]}\n'.format(self.size).encode() + self.rgba) # 2x2
|
||||
|
||||
with self.assertRaises(Exception):
|
||||
image = qubesimgconverter.Image.get_from_stream(io, max_width=1)
|
||||
|
||||
io.seek(0)
|
||||
with self.assertRaises(Exception):
|
||||
image = qubesimgconverter.Image.get_from_stream(io, max_height=1)
|
||||
|
||||
class TestCaseFunctionsAndConstants(unittest.TestCase):
|
||||
def test_00_imghdrlen(self):
|
||||
self.assertEqual(qubesimgconverter.imghdrlen(8, 15), len('8 15\n'))
|
||||
self.assertEqual(qubesimgconverter.imghdrlen(100, 100), len('100 100\n'))
|
||||
|
||||
def test_01_re_imghdr(self):
|
||||
self.assertTrue(qubesimgconverter.re_imghdr.match(b'8 15\n'))
|
||||
self.assertIsNone(qubesimgconverter.re_imghdr.match(b'8 15'))
|
||||
self.assertIsNone(qubesimgconverter.re_imghdr.match(b'815\n'))
|
||||
self.assertIsNone(qubesimgconverter.re_imghdr.match(b'x yx\n'))
|
||||
|
||||
def test_10_hex_to_float_result_00(self):
|
||||
self.assertEqual(qubesimgconverter.hex_to_int('#000000'), (0, 0, 0))
|
||||
|
||||
def test_11_hex_to_float_result_ff(self):
|
||||
self.assertEqual(qubesimgconverter.hex_to_int('0xffffff'),
|
||||
(0xff, 0xff, 0xff))
|
||||
|
||||
def test_12_hex_to_float_depth_3_not_implemented(self):
|
||||
with self.assertRaises(ValueError):
|
||||
qubesimgconverter.hex_to_int('123456', depth=3)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@ -1,99 +0,0 @@
|
||||
# vim: fileencoding=utf-8
|
||||
|
||||
#
|
||||
# The Qubes OS Project, https://www.qubes-os.org/
|
||||
#
|
||||
# Copyright (C) 2017
|
||||
# Marek Marczykowski-Górecki <marmarek@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.
|
||||
#
|
||||
|
||||
import itertools
|
||||
import qubes.tests.extra
|
||||
|
||||
|
||||
# noinspection PyPep8Naming
|
||||
class TC_00_ImgConverter(qubes.tests.extra.ExtraTestCase):
|
||||
def setUp(self):
|
||||
super(TC_00_ImgConverter, self).setUp()
|
||||
# noinspection PyAttributeOutsideInit
|
||||
self.vm = self.create_vms(["vm"])[0]
|
||||
self.vm.start()
|
||||
|
||||
self.image_size = 16
|
||||
# RGB data for the image
|
||||
self.image_data = [
|
||||
(0xff // self.image_size * x, 0x80, 0xff // self.image_size * y,
|
||||
0xff)
|
||||
for x in range(self.image_size)
|
||||
for y in range(self.image_size)]
|
||||
|
||||
def create_img(self, filename):
|
||||
'''Create image file with given sample content
|
||||
|
||||
:param filename: output filename
|
||||
'''
|
||||
p = self.vm.run(
|
||||
'convert -size {}x{} -depth 8 rgba:- "{}" 2>&1'.format(
|
||||
self.image_size, self.image_size, filename),
|
||||
passio_popen=True)
|
||||
bytes_data = bytes(bytearray(itertools.chain(*self.image_data)))
|
||||
(stdout, _) = p.communicate(bytes_data)
|
||||
if p.returncode != 0:
|
||||
self.skipTest('failed to create test image: {}'.format(stdout))
|
||||
|
||||
def assertCorrectlyTransformed(self, orig_filename, trusted_filename):
|
||||
self.assertEquals(
|
||||
self.vm.run('test -r "{}"'.format(trusted_filename), wait=True), 0)
|
||||
self.assertEquals(
|
||||
self.vm.run('test -r "{}"'.format(orig_filename), wait=True), 0)
|
||||
# retrieve original image too, to compensate for compression
|
||||
p = self.vm.run('convert "{}" rgb:-'.format(orig_filename),
|
||||
passio_popen=True)
|
||||
orig_image_data, _ = p.communicate()
|
||||
p = self.vm.run('convert "{}" rgb:-'.format(trusted_filename),
|
||||
passio_popen=True)
|
||||
trusted_image_data, _ = p.communicate()
|
||||
self.assertEquals(orig_image_data, trusted_image_data)
|
||||
|
||||
def test_000_png(self):
|
||||
self.create_img('test.png')
|
||||
p = self.vm.run('qvm-convert-img test.png trusted.png 2>&1',
|
||||
passio_popen=True)
|
||||
(stdout, _) = p.communicate()
|
||||
if p.returncode == 127:
|
||||
self.skipTest('qubes-img-converter not installed')
|
||||
self.assertEquals(p.returncode, 0, 'qvm-convert-img failed: {}'.format(
|
||||
stdout))
|
||||
self.assertCorrectlyTransformed('test.png', 'trusted.png')
|
||||
|
||||
def test_010_filename_with_spaces(self):
|
||||
self.create_img('test with spaces.png')
|
||||
p = self.vm.run('qvm-convert-img "test with spaces.png" '
|
||||
'"trusted with spaces.png" 2>&1',
|
||||
passio_popen=True)
|
||||
(stdout, _) = p.communicate()
|
||||
if p.returncode == 127:
|
||||
self.skipTest('qubes-img-converter not installed')
|
||||
self.assertEquals(p.returncode, 0, 'qvm-convert-img failed: {}'.format(
|
||||
stdout))
|
||||
self.assertCorrectlyTransformed(
|
||||
'test with spaces.png', 'trusted with spaces.png')
|
||||
|
||||
|
||||
def list_tests():
|
||||
tests = [TC_00_ImgConverter]
|
||||
return tests
|
@ -1,19 +0,0 @@
|
||||
import setuptools
|
||||
|
||||
setuptools.setup(
|
||||
name='qubesimgconverter',
|
||||
version=open('../version').read().strip(),
|
||||
author='Invisible Things Lab',
|
||||
author_email='woju@invisiblethingslab.com',
|
||||
description='Toolkit for secure transfer and conversion of images between Qubes VMs.',
|
||||
license='GPL2+',
|
||||
url='https://www.qubes-os.org/',
|
||||
packages=['qubesimgconverter'],
|
||||
entry_points={
|
||||
'qubes.tests.extra.for_template':
|
||||
'qubesimgconverter = qubesimgconverter.test_integ:list_tests',
|
||||
}
|
||||
|
||||
)
|
||||
|
||||
# vim: ts=4 sts=4 sw=4 et
|
@ -1,8 +0,0 @@
|
||||
install:
|
||||
install -D local-top/qubes_cow_setup.sh \
|
||||
$(DESTDIR)/usr/share/initramfs-tools/scripts/local-top/qubes_cow_setup
|
||||
install -D local-top/scrub_pages.sh \
|
||||
$(DESTDIR)/usr/share/initramfs-tools/scripts/local-top/scrub_pages
|
||||
install -D qubes_vm \
|
||||
$(DESTDIR)/usr/share/initramfs-tools/hooks/qubes_vm
|
||||
|
@ -1 +0,0 @@
|
||||
../../dracut/full-dmroot/qubes_cow_setup.sh
|
@ -1 +0,0 @@
|
||||
../../dracut/xen-balloon-scrub-pages/scrub_pages.sh
|
@ -1,21 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
if grep -q '^[0-]*$' /sys/hypervisor/uuid; then
|
||||
echo "Not intended for dom0"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
PREREQS="dmsetup"
|
||||
case "$1" in
|
||||
prereqs)
|
||||
echo "$PREREQS"
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
. /usr/share/initramfs-tools/hook-functions
|
||||
|
||||
copy_exec /sbin/sfdisk
|
||||
copy_exec /sbin/mkswap
|
||||
force_load xen-blkfront
|
||||
force_load dm-snapshot
|
@ -1,5 +0,0 @@
|
||||
install: install-scripts
|
||||
|
||||
install-scripts:
|
||||
install -d $(DESTDIR)/usr/sbin
|
||||
install qubes-prepare-vm-kernel $(DESTDIR)/usr/sbin
|
@ -1,84 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# The Qubes OS Project, http://www.qubes-os.org
|
||||
#
|
||||
# Copyright (C) 2015 Marek Marczykowski-Górecki
|
||||
# <marmarekp@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.
|
||||
#
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
basedir=/var/lib/qubes/vm-kernels
|
||||
|
||||
function build_modules_img() {
|
||||
kver=$1
|
||||
initramfs=$2
|
||||
output_file=$3
|
||||
|
||||
mkdir /tmp/qubes-modules-$kver
|
||||
truncate -s 400M /tmp/qubes-modules-$kver.img
|
||||
mkfs -t ext3 -F /tmp/qubes-modules-$kver.img > /dev/null
|
||||
mount /tmp/qubes-modules-$kver.img /tmp/qubes-modules-$kver -o loop
|
||||
cp -a -t /tmp/qubes-modules-$kver /lib/modules/$kver
|
||||
cp "/boot/vmlinuz-$kver" "/tmp/qubes-modules-$kver/vmlinuz"
|
||||
cp "$initramfs" "/tmp/qubes-modules-$kver/initramfs"
|
||||
umount /tmp/qubes-modules-$kver
|
||||
rmdir /tmp/qubes-modules-$kver
|
||||
mv /tmp/qubes-modules-$kver.img $output_file
|
||||
}
|
||||
|
||||
function build_initramfs() {
|
||||
kver=$1
|
||||
output_file=$2
|
||||
|
||||
dracut --nomdadmconf --nolvmconf --force \
|
||||
--modules "kernel-modules qubes-vm-simple" \
|
||||
--conf /dev/null --confdir /var/empty \
|
||||
-d "xenblk xen-blkfront cdrom ext4 jbd2 crc16 dm_snapshot" \
|
||||
$output_file $kver
|
||||
chmod 644 "$output_file"
|
||||
}
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <kernel-version> [<display-kernel-version>]" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -r /boot/vmlinuz-$1 -o ! -d /lib/modules/$1 ]; then
|
||||
echo "ERROR: Kernel version $1 not installed" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
kernel_version=$1
|
||||
if [ -n "$2" ]; then
|
||||
output_dir="$basedir/$2"
|
||||
else
|
||||
output_dir="$basedir/$kernel_version"
|
||||
fi
|
||||
|
||||
echo "--> Building files for $kernel_version in $output_dir"
|
||||
|
||||
mkdir -p "$output_dir"
|
||||
cp "/boot/vmlinuz-$kernel_version" "$output_dir/vmlinuz"
|
||||
echo "---> Generating initramfs"
|
||||
build_initramfs "$kernel_version" "$output_dir/initramfs"
|
||||
echo "---> Generating modules.img"
|
||||
build_modules_img "$kernel_version" "$output_dir/initramfs" \
|
||||
"$output_dir/modules.img"
|
||||
|
||||
echo "--> Done."
|
@ -1,7 +1,8 @@
|
||||
CC=gcc
|
||||
CFLAGS+=-Wall -Wextra -Werror -g -O3
|
||||
CFLAGS=-Wall -Wextra -Werror -g -O3
|
||||
SBINDIR ?= /usr/sbin
|
||||
|
||||
all: meminfo-writer
|
||||
SBINDIR?=/usr/sbin
|
||||
|
||||
_XENSTORE_H=$(shell ls /usr/include/xenstore.h)
|
||||
ifneq "$(_XENSTORE_H)" ""
|
||||
@ -9,9 +10,9 @@ ifneq "$(_XENSTORE_H)" ""
|
||||
endif
|
||||
|
||||
meminfo-writer: meminfo-writer.o
|
||||
$(CC) $(LDFLAGS) -g -o meminfo-writer meminfo-writer.o -lxenstore
|
||||
$(CC) -g -o meminfo-writer meminfo-writer.o -lxenstore
|
||||
install:
|
||||
install -D meminfo-writer $(DESTDIR)/$(SBINDIR)/meminfo-writer
|
||||
install -D meminfo-writer $(DESTDIR)$(SBINDIR)/meminfo-writer
|
||||
ifeq (1,${DEBIANBUILD})
|
||||
install -d $(DESTDIR)/lib/systemd/system/
|
||||
install -m 0644 qubes-meminfo-writer.service $(DESTDIR)/lib/systemd/system/
|
||||
|
@ -16,21 +16,21 @@ int used_mem_change_threshold;
|
||||
int delay;
|
||||
int usr1_received;
|
||||
|
||||
const char *parse(const char *meminfo_buf, const char* dom_current_buf)
|
||||
const char *parse(const char *buf)
|
||||
{
|
||||
const char *ptr = meminfo_buf;
|
||||
const char *ptr = buf;
|
||||
static char outbuf[4096];
|
||||
long long val;
|
||||
int val;
|
||||
int len;
|
||||
int ret;
|
||||
long long MemTotal = 0, MemFree = 0, Buffers = 0, Cached = 0, SwapTotal =
|
||||
int MemTotal = 0, MemFree = 0, Buffers = 0, Cached = 0, SwapTotal =
|
||||
0, SwapFree = 0;
|
||||
unsigned long long key;
|
||||
long long used_mem, used_mem_diff;
|
||||
long used_mem, used_mem_diff;
|
||||
int nitems = 0;
|
||||
|
||||
while (nitems != (1<<6)-1 || !*ptr) {
|
||||
ret = sscanf(ptr, "%*s %lld kB\n%n", &val, &len);
|
||||
ret = sscanf(ptr, "%*s %d kB\n%n", &val, &len);
|
||||
if (ret < 1 || len < (int)sizeof (unsigned long long)) {
|
||||
ptr += len;
|
||||
continue;
|
||||
@ -59,12 +59,6 @@ const char *parse(const char *meminfo_buf, const char* dom_current_buf)
|
||||
ptr += len;
|
||||
}
|
||||
|
||||
if(dom_current_buf) {
|
||||
long long DomTotal = strtoll(dom_current_buf, 0, 10);
|
||||
if(DomTotal)
|
||||
MemTotal = DomTotal;
|
||||
}
|
||||
|
||||
used_mem =
|
||||
MemTotal - Buffers - Cached - MemFree + SwapTotal - SwapFree;
|
||||
if (used_mem < 0)
|
||||
@ -78,7 +72,10 @@ const char *parse(const char *meminfo_buf, const char* dom_current_buf)
|
||||
|| (used_mem > prev_used_mem && used_mem / 10 > (MemTotal+12) / 13
|
||||
&& used_mem_diff > used_mem_change_threshold/2)) {
|
||||
prev_used_mem = used_mem;
|
||||
sprintf(outbuf, "%lld", used_mem);
|
||||
sprintf(outbuf,
|
||||
"MemTotal: %d kB\nMemFree: %d kB\nBuffers: %d kB\nCached: %d kB\n"
|
||||
"SwapTotal: %d kB\nSwapFree: %d kB\n", MemTotal,
|
||||
MemFree, Buffers, Cached, SwapTotal, SwapFree);
|
||||
return outbuf;
|
||||
}
|
||||
return NULL;
|
||||
@ -106,50 +103,13 @@ void usr1_handler(int sig __attribute__((__unused__))) {
|
||||
usr1_received = 1;
|
||||
}
|
||||
|
||||
static inline void pread0_string(int fd, char* buf, size_t buf_size)
|
||||
{
|
||||
int n = pread(fd, buf, buf_size - 1, 0);
|
||||
if (n < 0) {
|
||||
perror("pread");
|
||||
exit(1);
|
||||
}
|
||||
buf[n] = 0;
|
||||
}
|
||||
|
||||
static void update(struct xs_handle *xs, int meminfo_fd, int dom_current_fd)
|
||||
{
|
||||
char dom_current_buf[32];
|
||||
char dom_current_buf2[32];
|
||||
char meminfo_buf[4096];
|
||||
const char *meminfo_data;
|
||||
|
||||
pread0_string(dom_current_fd, dom_current_buf, sizeof(dom_current_buf));
|
||||
|
||||
/* check until the dom current reading is stable to avoid races */
|
||||
for(;;) {
|
||||
pread0_string(meminfo_fd, meminfo_buf, sizeof(meminfo_buf));
|
||||
pread0_string(dom_current_fd, dom_current_buf2, sizeof(dom_current_buf2));
|
||||
|
||||
if(!strcmp(dom_current_buf, dom_current_buf2))
|
||||
break;
|
||||
|
||||
pread0_string(meminfo_fd, meminfo_buf, sizeof(meminfo_buf));
|
||||
pread0_string(dom_current_fd, dom_current_buf, sizeof(dom_current_buf));
|
||||
|
||||
if(!strcmp(dom_current_buf, dom_current_buf2))
|
||||
break;
|
||||
}
|
||||
|
||||
meminfo_data = parse(meminfo_buf, dom_current_buf);
|
||||
if (meminfo_data)
|
||||
send_to_qmemman(xs, meminfo_data);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int meminfo_fd, dom_current_fd;
|
||||
struct xs_handle *xs;
|
||||
char buf[4096];
|
||||
int n;
|
||||
const char *meminfo_data;
|
||||
int fd;
|
||||
struct xs_handle *xs;
|
||||
|
||||
if (argc != 3 && argc != 4)
|
||||
usage();
|
||||
@ -161,8 +121,6 @@ int main(int argc, char **argv)
|
||||
if (argc == 4) {
|
||||
pid_t pid;
|
||||
sigset_t mask, oldmask;
|
||||
int fd;
|
||||
char buf[32];
|
||||
|
||||
switch (pid = fork()) {
|
||||
case -1:
|
||||
@ -197,14 +155,9 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
meminfo_fd = open("/proc/meminfo", O_RDONLY);
|
||||
if (meminfo_fd < 0) {
|
||||
perror("open /proc/meminfo");
|
||||
exit(1);
|
||||
}
|
||||
dom_current_fd = open("/sys/devices/system/xen_memory/xen_memory0/info/current_kb", O_RDONLY);
|
||||
if (dom_current_fd < 0) {
|
||||
perror("open /sys/devices/system/xen_memory/xen_memory0/info/current_kb");
|
||||
fd = open("/proc/meminfo", O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror("open meminfo");
|
||||
exit(1);
|
||||
}
|
||||
xs = xs_domain_open();
|
||||
@ -214,8 +167,15 @@ int main(int argc, char **argv)
|
||||
}
|
||||
if (argc == 3) {
|
||||
/* if not waiting for signal, fork after first info written to xenstore */
|
||||
update(xs, meminfo_fd, dom_current_fd);
|
||||
|
||||
n = pread(fd, buf, sizeof(buf)-1, 0);
|
||||
if (n < 0) {
|
||||
perror("pread");
|
||||
exit(1);
|
||||
}
|
||||
buf[n] = 0;
|
||||
meminfo_data = parse(buf);
|
||||
if (meminfo_data)
|
||||
send_to_qmemman(xs, meminfo_data);
|
||||
n = fork();
|
||||
if (n < 0) {
|
||||
perror("fork");
|
||||
@ -227,8 +187,15 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
update(xs, meminfo_fd, dom_current_fd);
|
||||
n = pread(fd, buf, sizeof(buf)-1, 0);
|
||||
if (n < 0) {
|
||||
perror("pread");
|
||||
exit(1);
|
||||
}
|
||||
buf[n] = 0;
|
||||
meminfo_data = parse(buf);
|
||||
if (meminfo_data)
|
||||
send_to_qmemman(xs, meminfo_data);
|
||||
usleep(delay);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
[Unit]
|
||||
Description=Qubes memory information reporter
|
||||
Before=systemd-user-sessions.service
|
||||
After=qubes-core.service qubes-qmemman.service
|
||||
ConditionPathExists=/var/run/qubes/qmemman.sock
|
||||
|
||||
|
@ -1,10 +1,20 @@
|
||||
CC=gcc
|
||||
CFLAGS+=-I. -g -O2 -Wall -Wextra -Werror -pie -fPIC
|
||||
SO_VER=2
|
||||
LDFLAGS+=-shared
|
||||
XENLIBS=-lxenctrl -lxenstore -lvchan
|
||||
COMMONIOALL=ioall.o
|
||||
SO_VER=1
|
||||
LDFLAGS=-shared
|
||||
|
||||
all: libqubes-rpc-filecopy.so.$(SO_VER)
|
||||
libqubes-rpc-filecopy.so.$(SO_VER): ioall.o copy-file.o crc32.o unpack.o pack.o
|
||||
_XENSTORE_H=$(shell ls /usr/include/xenstore.h)
|
||||
ifneq "$(_XENSTORE_H)" ""
|
||||
CFLAGS+= -DUSE_XENSTORE_H
|
||||
endif
|
||||
|
||||
|
||||
all: libqrexec-utils.so.$(SO_VER) libqubes-rpc-filecopy.so.$(SO_VER)
|
||||
libqrexec-utils.so.$(SO_VER): unix-server.o ioall.o buffer.o write-stdin.o exec.o txrx-vchan.o
|
||||
$(CC) $(LDFLAGS) -Wl,-soname,$@ -o $@ $^ $(XENLIBS)
|
||||
libqubes-rpc-filecopy.so.$(SO_VER): ioall.o copy-file.o crc32.o unpack.o
|
||||
$(CC) $(LDFLAGS) -Wl,-soname,$@ -o $@ $^
|
||||
|
||||
%.a:
|
||||
@ -14,7 +24,12 @@ clean:
|
||||
|
||||
install:
|
||||
mkdir -p $(DESTDIR)$(LIBDIR)
|
||||
cp libqrexec-utils.so.$(SO_VER) $(DESTDIR)$(LIBDIR)
|
||||
ln -s libqrexec-utils.so.$(SO_VER) $(DESTDIR)$(LIBDIR)/libqrexec-utils.so
|
||||
cp libqubes-rpc-filecopy.so.$(SO_VER) $(DESTDIR)$(LIBDIR)
|
||||
ln -s libqubes-rpc-filecopy.so.$(SO_VER) $(DESTDIR)$(LIBDIR)/libqubes-rpc-filecopy.so
|
||||
mkdir -p $(DESTDIR)$(INCLUDEDIR)
|
||||
cp libqrexec-utils.h $(DESTDIR)$(INCLUDEDIR)
|
||||
cp libqubes-rpc-filecopy.h $(DESTDIR)$(INCLUDEDIR)
|
||||
cp qrexec.h $(DESTDIR)$(INCLUDEDIR)
|
||||
|
||||
|
115
qrexec-lib/buffer.c
Normal file
115
qrexec-lib/buffer.c
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "libqrexec-utils.h"
|
||||
|
||||
#define BUFFER_LIMIT 50000000
|
||||
static int total_mem;
|
||||
static char *limited_malloc(int len)
|
||||
{
|
||||
char *ret;
|
||||
total_mem += len;
|
||||
if (total_mem > BUFFER_LIMIT) {
|
||||
fprintf(stderr, "attempt to allocate >BUFFER_LIMIT\n");
|
||||
exit(1);
|
||||
}
|
||||
ret = malloc(len);
|
||||
if (!ret) {
|
||||
perror("malloc");
|
||||
exit(1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void limited_free(char *ptr, int len)
|
||||
{
|
||||
free(ptr);
|
||||
total_mem -= len;
|
||||
}
|
||||
|
||||
void buffer_init(struct buffer *b)
|
||||
{
|
||||
b->buflen = 0;
|
||||
b->data = NULL;
|
||||
}
|
||||
|
||||
void buffer_free(struct buffer *b)
|
||||
{
|
||||
if (b->buflen)
|
||||
limited_free(b->data, b->buflen);
|
||||
buffer_init(b);
|
||||
}
|
||||
|
||||
/*
|
||||
The following two functions can be made much more efficient.
|
||||
Yet the profiling output show they are not significant CPU hogs, so
|
||||
we keep them so simple to make them obviously correct.
|
||||
*/
|
||||
|
||||
void buffer_append(struct buffer *b, const char *data, int len)
|
||||
{
|
||||
int newsize;
|
||||
char *qdata;
|
||||
if (len < 0 || len > BUFFER_LIMIT) {
|
||||
fprintf(stderr, "buffer_append %d\n", len);
|
||||
exit(1);
|
||||
}
|
||||
if (len == 0)
|
||||
return;
|
||||
newsize = len + b->buflen;
|
||||
qdata = limited_malloc(len + b->buflen);
|
||||
memcpy(qdata, b->data, b->buflen);
|
||||
memcpy(qdata + b->buflen, data, len);
|
||||
buffer_free(b);
|
||||
b->buflen = newsize;
|
||||
b->data = qdata;
|
||||
}
|
||||
|
||||
void buffer_remove(struct buffer *b, int len)
|
||||
{
|
||||
int newsize;
|
||||
char *qdata = NULL;
|
||||
if (len < 0 || len > b->buflen) {
|
||||
fprintf(stderr, "buffer_remove %d/%d\n", len, b->buflen);
|
||||
exit(1);
|
||||
}
|
||||
newsize = b->buflen - len;
|
||||
if (newsize > 0) {
|
||||
qdata = limited_malloc(newsize);
|
||||
memcpy(qdata, b->data + len, newsize);
|
||||
}
|
||||
buffer_free(b);
|
||||
b->buflen = newsize;
|
||||
b->data = qdata;
|
||||
}
|
||||
|
||||
int buffer_len(struct buffer *b)
|
||||
{
|
||||
return b->buflen;
|
||||
}
|
||||
|
||||
void *buffer_data(struct buffer *b)
|
||||
{
|
||||
return b->data;
|
||||
}
|
@ -1,49 +1,49 @@
|
||||
#include <unistd.h>
|
||||
#include "ioall.h"
|
||||
#include <ioall.h>
|
||||
#include "libqubes-rpc-filecopy.h"
|
||||
#include "crc32.h"
|
||||
|
||||
notify_progress_t *notify_progress_func = NULL;
|
||||
void register_notify_progress(notify_progress_t *func)
|
||||
{
|
||||
notify_progress_func = func;
|
||||
notify_progress_func = func;
|
||||
}
|
||||
|
||||
int copy_file(int outfd, int infd, long long size, unsigned long *crc32)
|
||||
{
|
||||
char buf[4096];
|
||||
long long written = 0;
|
||||
int ret;
|
||||
int count;
|
||||
while (written < size) {
|
||||
if (size - written > (int)sizeof(buf))
|
||||
count = sizeof buf;
|
||||
else
|
||||
count = size - written;
|
||||
ret = read(infd, buf, count);
|
||||
if (!ret)
|
||||
return COPY_FILE_READ_EOF;
|
||||
if (ret < 0)
|
||||
return COPY_FILE_READ_ERROR;
|
||||
/* acumulate crc32 if requested */
|
||||
if (crc32)
|
||||
*crc32 = Crc32_ComputeBuf(*crc32, buf, ret);
|
||||
if (!write_all(outfd, buf, ret))
|
||||
return COPY_FILE_WRITE_ERROR;
|
||||
if (notify_progress_func != NULL)
|
||||
notify_progress_func(ret, 0);
|
||||
written += ret;
|
||||
}
|
||||
return COPY_FILE_OK;
|
||||
char buf[4096];
|
||||
long long written = 0;
|
||||
int ret;
|
||||
int count;
|
||||
while (written < size) {
|
||||
if (size - written > (int)sizeof(buf))
|
||||
count = sizeof buf;
|
||||
else
|
||||
count = size - written;
|
||||
ret = read(infd, buf, count);
|
||||
if (!ret)
|
||||
return COPY_FILE_READ_EOF;
|
||||
if (ret < 0)
|
||||
return COPY_FILE_READ_ERROR;
|
||||
/* acumulate crc32 if requested */
|
||||
if (crc32)
|
||||
*crc32 = Crc32_ComputeBuf(*crc32, buf, ret);
|
||||
if (!write_all(outfd, buf, ret))
|
||||
return COPY_FILE_WRITE_ERROR;
|
||||
if (notify_progress_func != NULL)
|
||||
notify_progress_func(ret, 0);
|
||||
written += ret;
|
||||
}
|
||||
return COPY_FILE_OK;
|
||||
}
|
||||
|
||||
const char * copy_file_status_to_str(int status)
|
||||
{
|
||||
switch (status) {
|
||||
case COPY_FILE_OK: return "OK";
|
||||
case COPY_FILE_READ_EOF: return "Unexpected end of data while reading";
|
||||
case COPY_FILE_READ_ERROR: return "Error reading";
|
||||
case COPY_FILE_WRITE_ERROR: return "Error writing";
|
||||
default: return "????????";
|
||||
}
|
||||
switch (status) {
|
||||
case COPY_FILE_OK: return "OK";
|
||||
case COPY_FILE_READ_EOF: return "Unexpected end of data while reading";
|
||||
case COPY_FILE_READ_ERROR: return "Error reading";
|
||||
case COPY_FILE_WRITE_ERROR: return "Error writing";
|
||||
default: return "????????";
|
||||
}
|
||||
}
|
||||
|
79
qrexec-lib/exec.c
Normal file
79
qrexec-lib/exec.c
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include "libqrexec-utils.h"
|
||||
|
||||
static do_exec_t *exec_func = NULL;
|
||||
void register_exec_func(do_exec_t *func) {
|
||||
exec_func = func;
|
||||
}
|
||||
|
||||
void fix_fds(int fdin, int fdout, int fderr)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 256; i++)
|
||||
if (i != fdin && i != fdout && i != fderr)
|
||||
close(i);
|
||||
dup2(fdin, 0);
|
||||
dup2(fdout, 1);
|
||||
dup2(fderr, 2);
|
||||
close(fdin);
|
||||
close(fdout);
|
||||
if (fderr != 2)
|
||||
close(fderr);
|
||||
}
|
||||
|
||||
void do_fork_exec(const char *cmdline, int *pid, int *stdin_fd, int *stdout_fd,
|
||||
int *stderr_fd)
|
||||
{
|
||||
int inpipe[2], outpipe[2], errpipe[2];
|
||||
|
||||
if (pipe(inpipe) || pipe(outpipe) || (stderr_fd && pipe(errpipe))) {
|
||||
perror("pipe");
|
||||
exit(1);
|
||||
}
|
||||
switch (*pid = fork()) {
|
||||
case -1:
|
||||
perror("fork");
|
||||
exit(-1);
|
||||
case 0:
|
||||
if (stderr_fd) {
|
||||
fix_fds(inpipe[0], outpipe[1], errpipe[1]);
|
||||
} else
|
||||
fix_fds(inpipe[0], outpipe[1], 2);
|
||||
|
||||
if (exec_func != NULL)
|
||||
exec_func(cmdline);
|
||||
exit(-1);
|
||||
default:;
|
||||
}
|
||||
close(inpipe[0]);
|
||||
close(outpipe[1]);
|
||||
*stdin_fd = inpipe[1];
|
||||
*stdout_fd = outpipe[0];
|
||||
if (stderr_fd) {
|
||||
close(errpipe[1]);
|
||||
*stderr_fd = errpipe[0];
|
||||
}
|
||||
}
|
@ -27,90 +27,90 @@
|
||||
|
||||
void perror_wrapper(const char * msg)
|
||||
{
|
||||
int prev=errno;
|
||||
perror(msg);
|
||||
errno=prev;
|
||||
int prev=errno;
|
||||
perror(msg);
|
||||
errno=prev;
|
||||
}
|
||||
|
||||
void set_nonblock(int fd)
|
||||
{
|
||||
int fl = fcntl(fd, F_GETFL, 0);
|
||||
if (fl & O_NONBLOCK)
|
||||
return;
|
||||
fcntl(fd, F_SETFL, fl | O_NONBLOCK);
|
||||
int fl = fcntl(fd, F_GETFL, 0);
|
||||
if (fl & O_NONBLOCK)
|
||||
return;
|
||||
fcntl(fd, F_SETFL, fl | O_NONBLOCK);
|
||||
}
|
||||
|
||||
void set_block(int fd)
|
||||
{
|
||||
int fl = fcntl(fd, F_GETFL, 0);
|
||||
if (!(fl & O_NONBLOCK))
|
||||
return;
|
||||
fcntl(fd, F_SETFL, fl & ~O_NONBLOCK);
|
||||
int fl = fcntl(fd, F_GETFL, 0);
|
||||
if (!(fl & O_NONBLOCK))
|
||||
return;
|
||||
fcntl(fd, F_SETFL, fl & ~O_NONBLOCK);
|
||||
}
|
||||
|
||||
int write_all(int fd, const void *buf, int size)
|
||||
{
|
||||
int written = 0;
|
||||
int ret;
|
||||
while (written < size) {
|
||||
ret = write(fd, (char *) buf + written, size - written);
|
||||
if (ret == -1 && errno == EINTR)
|
||||
continue;
|
||||
if (ret <= 0) {
|
||||
return 0;
|
||||
}
|
||||
written += ret;
|
||||
}
|
||||
// fprintf(stderr, "sent %d bytes\n", size);
|
||||
return 1;
|
||||
int written = 0;
|
||||
int ret;
|
||||
while (written < size) {
|
||||
ret = write(fd, (char *) buf + written, size - written);
|
||||
if (ret == -1 && errno == EINTR)
|
||||
continue;
|
||||
if (ret <= 0) {
|
||||
return 0;
|
||||
}
|
||||
written += ret;
|
||||
}
|
||||
// fprintf(stderr, "sent %d bytes\n", size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int read_all(int fd, void *buf, int size)
|
||||
{
|
||||
int got_read = 0;
|
||||
int ret;
|
||||
while (got_read < size) {
|
||||
ret = read(fd, (char *) buf + got_read, size - got_read);
|
||||
if (ret == -1 && errno == EINTR)
|
||||
continue;
|
||||
if (ret == 0) {
|
||||
errno = 0;
|
||||
fprintf(stderr, "EOF\n");
|
||||
return 0;
|
||||
}
|
||||
if (ret < 0) {
|
||||
if (errno != EAGAIN)
|
||||
perror_wrapper("read");
|
||||
return 0;
|
||||
}
|
||||
if (got_read == 0) {
|
||||
// force blocking operation on further reads
|
||||
set_block(fd);
|
||||
}
|
||||
got_read += ret;
|
||||
}
|
||||
// fprintf(stderr, "read %d bytes\n", size);
|
||||
return 1;
|
||||
int got_read = 0;
|
||||
int ret;
|
||||
while (got_read < size) {
|
||||
ret = read(fd, (char *) buf + got_read, size - got_read);
|
||||
if (ret == -1 && errno == EINTR)
|
||||
continue;
|
||||
if (ret == 0) {
|
||||
errno = 0;
|
||||
fprintf(stderr, "EOF\n");
|
||||
return 0;
|
||||
}
|
||||
if (ret < 0) {
|
||||
if (errno != EAGAIN)
|
||||
perror_wrapper("read");
|
||||
return 0;
|
||||
}
|
||||
if (got_read == 0) {
|
||||
// force blocking operation on further reads
|
||||
set_block(fd);
|
||||
}
|
||||
got_read += ret;
|
||||
}
|
||||
// fprintf(stderr, "read %d bytes\n", size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int copy_fd_all(int fdout, int fdin)
|
||||
{
|
||||
int ret;
|
||||
char buf[4096];
|
||||
for (;;) {
|
||||
ret = read(fdin, buf, sizeof(buf));
|
||||
if (ret == -1 && errno == EINTR)
|
||||
continue;
|
||||
if (!ret)
|
||||
break;
|
||||
if (ret < 0) {
|
||||
perror_wrapper("read");
|
||||
return 0;
|
||||
}
|
||||
if (!write_all(fdout, buf, ret)) {
|
||||
perror_wrapper("write");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
int ret;
|
||||
char buf[4096];
|
||||
for (;;) {
|
||||
ret = read(fdin, buf, sizeof(buf));
|
||||
if (ret == -1 && errno == EINTR)
|
||||
continue;
|
||||
if (!ret)
|
||||
break;
|
||||
if (ret < 0) {
|
||||
perror_wrapper("read");
|
||||
return 0;
|
||||
}
|
||||
if (!write_all(fdout, buf, ret)) {
|
||||
perror_wrapper("write");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
69
qrexec-lib/libqrexec-utils.h
Normal file
69
qrexec-lib/libqrexec-utils.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* The Qubes OS Project, http://www.qubes-os.org
|
||||
*
|
||||
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
|
||||
* Copyright (C) 2013 Marek Marczykowski <marmarek@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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/select.h>
|
||||
|
||||
struct buffer {
|
||||
char *data;
|
||||
int buflen;
|
||||
};
|
||||
|
||||
typedef void (do_exec_t)(const char *);
|
||||
void register_exec_func(do_exec_t *func);
|
||||
|
||||
void buffer_init(struct buffer *b);
|
||||
void buffer_free(struct buffer *b);
|
||||
void buffer_append(struct buffer *b, const char *data, int len);
|
||||
void buffer_remove(struct buffer *b, int len);
|
||||
int buffer_len(struct buffer *b);
|
||||
void *buffer_data(struct buffer *b);
|
||||
|
||||
|
||||
void do_fork_exec(const char *cmdline, int *pid, int *stdin_fd, int *stdout_fd,
|
||||
int *stderr_fd);
|
||||
int peer_server_init(int port);
|
||||
char *peer_client_init(int dom, int port);
|
||||
void wait_for_vchan_or_argfd(int max, fd_set * rdset, fd_set * wrset);
|
||||
unsigned int read_ready_vchan_ext(void);
|
||||
int read_all(int fd, void *buf, int size);
|
||||
int read_all_vchan_ext(void *buf, int size);
|
||||
int write_all(int fd, const void *buf, int size);
|
||||
int write_all_vchan_ext(const void *buf, int size);
|
||||
unsigned int buffer_space_vchan_ext(void);
|
||||
void fix_fds(int fdin, int fdout, int fderr);
|
||||
void set_nonblock(int fd);
|
||||
void set_block(int fd);
|
||||
|
||||
int get_server_socket(const char *);
|
||||
int do_accept(int s);
|
||||
|
||||
enum {
|
||||
WRITE_STDIN_OK = 0x200,
|
||||
WRITE_STDIN_BUFFERED,
|
||||
WRITE_STDIN_ERROR
|
||||
};
|
||||
|
||||
int flush_client_data(int fd, int client_id, struct buffer *buffer);
|
||||
int write_stdin(int fd, int client_id, const char *data, int len,
|
||||
struct buffer *buffer);
|
||||
void set_nonblock(int fd);
|
||||
int fork_and_flush_stdin(int fd, struct buffer *buffer);
|
@ -30,46 +30,38 @@
|
||||
#define LEGAL_EOF 31415926
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
struct file_header {
|
||||
uint32_t namelen;
|
||||
uint32_t mode;
|
||||
uint64_t filelen;
|
||||
uint32_t atime;
|
||||
uint32_t atime_nsec;
|
||||
uint32_t mtime;
|
||||
uint32_t mtime_nsec;
|
||||
unsigned int namelen;
|
||||
unsigned int mode;
|
||||
unsigned long long filelen;
|
||||
unsigned int atime;
|
||||
unsigned int atime_nsec;
|
||||
unsigned int mtime;
|
||||
unsigned int mtime_nsec;
|
||||
};
|
||||
|
||||
struct result_header {
|
||||
uint32_t error_code;
|
||||
uint32_t _pad;
|
||||
uint64_t crc32;
|
||||
uint32_t error_code;
|
||||
uint32_t _pad;
|
||||
uint64_t crc32;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* optional info about last processed file */
|
||||
struct result_header_ext {
|
||||
uint32_t last_namelen;
|
||||
char last_name[0];
|
||||
uint32_t last_namelen;
|
||||
char last_name[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
enum {
|
||||
COPY_FILE_OK,
|
||||
COPY_FILE_READ_EOF,
|
||||
COPY_FILE_READ_ERROR,
|
||||
COPY_FILE_WRITE_ERROR
|
||||
COPY_FILE_OK,
|
||||
COPY_FILE_READ_EOF,
|
||||
COPY_FILE_READ_ERROR,
|
||||
COPY_FILE_WRITE_ERROR
|
||||
};
|
||||
|
||||
/* feedback handling */
|
||||
typedef void (notify_progress_t)(int, int);
|
||||
typedef void (error_handler_t)(const char *fmt, va_list args);
|
||||
void register_notify_progress(notify_progress_t *func);
|
||||
void register_error_handler(error_handler_t *func);
|
||||
|
||||
/* common functions */
|
||||
int copy_file(int outfd, int infd, long long size, unsigned long *crc32);
|
||||
const char *copy_file_status_to_str(int status);
|
||||
void set_size_limit(unsigned long long new_bytes_limit, unsigned long long new_files_limit);
|
||||
@ -82,22 +74,9 @@ int copy_fd_all(int fdout, int fdin);
|
||||
void set_nonblock(int fd);
|
||||
void set_block(int fd);
|
||||
|
||||
/* unpacking */
|
||||
extern unsigned long Crc32_ComputeBuf( unsigned long inCrc32, const void *buf,
|
||||
size_t bufLen );
|
||||
|
||||
extern int do_unpack(void);
|
||||
|
||||
/* packing */
|
||||
int single_file_processor(const char *filename, const struct stat *st);
|
||||
int do_fs_walk(const char *file, int ignore_symlinks);
|
||||
/* used in tar2qfile to alter only headers, but keep original file stream */
|
||||
void write_headers(const struct file_header *hdr, const char *filename);
|
||||
int copy_file_with_crc(int outfd, int infd, long long size);
|
||||
/* MUST be called before first do_fs_walk/single_file_processor */
|
||||
void qfile_pack_init(void);
|
||||
void set_ignore_quota_error(int value);
|
||||
/* those two will call registered error handler if needed */
|
||||
void wait_for_result(void);
|
||||
void notify_end_and_wait_for_result(void);
|
||||
|
||||
#endif /* _LIBQUBES_RPC_FILECOPY_H */
|
||||
|
@ -1,229 +0,0 @@
|
||||
#define _GNU_SOURCE /* See feature_test_macros(7) */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include "libqubes-rpc-filecopy.h"
|
||||
|
||||
static unsigned long crc32_sum;
|
||||
static int ignore_quota_error = 0;
|
||||
error_handler_t *error_handler = NULL;
|
||||
|
||||
void register_error_handler(error_handler_t *value) {
|
||||
error_handler = value;
|
||||
}
|
||||
|
||||
_Noreturn static void call_error_handler(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
if (error_handler) {
|
||||
error_handler(fmt, args);
|
||||
} else {
|
||||
vfprintf(stderr, fmt, args);
|
||||
}
|
||||
va_end(args);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int write_all_with_crc(int fd, const void *buf, int size)
|
||||
{
|
||||
crc32_sum = Crc32_ComputeBuf(crc32_sum, buf, size);
|
||||
return write_all(fd, buf, size);
|
||||
}
|
||||
|
||||
void notify_end_and_wait_for_result(void)
|
||||
{
|
||||
struct file_header end_hdr;
|
||||
|
||||
/* nofity end of transfer */
|
||||
memset(&end_hdr, 0, sizeof(end_hdr));
|
||||
end_hdr.namelen = 0;
|
||||
end_hdr.filelen = 0;
|
||||
write_all_with_crc(1, &end_hdr, sizeof(end_hdr));
|
||||
|
||||
set_block(0);
|
||||
wait_for_result();
|
||||
}
|
||||
|
||||
void wait_for_result(void)
|
||||
{
|
||||
struct result_header hdr;
|
||||
struct result_header_ext hdr_ext;
|
||||
char last_filename[MAX_PATH_LENGTH + 1];
|
||||
char last_filename_prefix[] = "; Last file: ";
|
||||
|
||||
if (!read_all(0, &hdr, sizeof(hdr))) {
|
||||
if (errno == EAGAIN) {
|
||||
// no result sent and stdin still open
|
||||
return;
|
||||
} else {
|
||||
// other read error or EOF
|
||||
exit(1); // hopefully remote has produced error message
|
||||
}
|
||||
}
|
||||
if (!read_all(0, &hdr_ext, sizeof(hdr_ext))) {
|
||||
// remote used old result_header struct
|
||||
hdr_ext.last_namelen = 0;
|
||||
}
|
||||
if (hdr_ext.last_namelen > MAX_PATH_LENGTH) {
|
||||
// read only at most MAX_PATH_LENGTH chars
|
||||
hdr_ext.last_namelen = MAX_PATH_LENGTH;
|
||||
}
|
||||
if (!read_all(0, last_filename, hdr_ext.last_namelen)) {
|
||||
fprintf(stderr, "Failed to get last filename\n");
|
||||
hdr_ext.last_namelen = 0;
|
||||
}
|
||||
last_filename[hdr_ext.last_namelen] = '\0';
|
||||
if (!hdr_ext.last_namelen)
|
||||
/* set prefix to empty string */
|
||||
last_filename_prefix[0] = '\0';
|
||||
|
||||
errno = hdr.error_code;
|
||||
if (hdr.error_code != 0) {
|
||||
switch (hdr.error_code) {
|
||||
case EEXIST:
|
||||
call_error_handler("A file named %s already exists in QubesIncoming dir", last_filename);
|
||||
break;
|
||||
case EINVAL:
|
||||
call_error_handler("File copy: Corrupted data from packer%s%s", last_filename_prefix, last_filename);
|
||||
break;
|
||||
case EDQUOT:
|
||||
if (ignore_quota_error) {
|
||||
/* skip also CRC check as sender and receiver might be
|
||||
* desynchronized in this case */
|
||||
return;
|
||||
}
|
||||
/* fallthrough */
|
||||
default:
|
||||
call_error_handler("File copy: %s%s%s",
|
||||
strerror(hdr.error_code), last_filename_prefix, last_filename);
|
||||
}
|
||||
}
|
||||
if (hdr.crc32 != crc32_sum) {
|
||||
call_error_handler("File transfer failed: checksum mismatch");
|
||||
}
|
||||
}
|
||||
|
||||
void write_headers(const struct file_header *hdr, const char *filename)
|
||||
{
|
||||
if (!write_all_with_crc(1, hdr, sizeof(*hdr))
|
||||
|| !write_all_with_crc(1, filename, hdr->namelen)) {
|
||||
set_block(0);
|
||||
wait_for_result();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int copy_file_with_crc(int outfd, int infd, long long size) {
|
||||
return copy_file(outfd, infd, size, &crc32_sum);
|
||||
}
|
||||
|
||||
int single_file_processor(const char *filename, const struct stat *st)
|
||||
{
|
||||
struct file_header hdr;
|
||||
int fd;
|
||||
mode_t mode = st->st_mode;
|
||||
|
||||
hdr.namelen = strlen(filename) + 1;
|
||||
hdr.mode = mode;
|
||||
hdr.atime = st->st_atim.tv_sec;
|
||||
hdr.atime_nsec = st->st_atim.tv_nsec;
|
||||
hdr.mtime = st->st_mtim.tv_sec;
|
||||
hdr.mtime_nsec = st->st_mtim.tv_nsec;
|
||||
|
||||
if (S_ISREG(mode)) {
|
||||
int ret;
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
call_error_handler("open %s", filename);
|
||||
hdr.filelen = st->st_size;
|
||||
write_headers(&hdr, filename);
|
||||
ret = copy_file(1, fd, hdr.filelen, &crc32_sum);
|
||||
if (ret != COPY_FILE_OK) {
|
||||
if (ret != COPY_FILE_WRITE_ERROR)
|
||||
call_error_handler("Copying file %s: %s", filename,
|
||||
copy_file_status_to_str(ret));
|
||||
else {
|
||||
set_block(0);
|
||||
wait_for_result();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
if (S_ISDIR(mode)) {
|
||||
hdr.filelen = 0;
|
||||
write_headers(&hdr, filename);
|
||||
}
|
||||
if (S_ISLNK(mode)) {
|
||||
char name[st->st_size + 1];
|
||||
if (readlink(filename, name, sizeof(name)) != st->st_size)
|
||||
call_error_handler("readlink %s", filename);
|
||||
hdr.filelen = st->st_size;
|
||||
write_headers(&hdr, filename);
|
||||
if (!write_all_with_crc(1, name, st->st_size)) {
|
||||
set_block(0);
|
||||
wait_for_result();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
// check for possible error from qfile-unpacker
|
||||
wait_for_result();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_fs_walk(const char *file, int ignore_symlinks)
|
||||
{
|
||||
char *newfile;
|
||||
struct stat st;
|
||||
struct dirent *ent;
|
||||
DIR *dir;
|
||||
|
||||
if (lstat(file, &st))
|
||||
call_error_handler("stat %s", file);
|
||||
if (S_ISLNK(st.st_mode) && ignore_symlinks)
|
||||
return 0;
|
||||
single_file_processor(file, &st);
|
||||
if (!S_ISDIR(st.st_mode))
|
||||
return 0;
|
||||
dir = opendir(file);
|
||||
if (!dir)
|
||||
call_error_handler("opendir %s", file);
|
||||
while ((ent = readdir(dir))) {
|
||||
char *fname = ent->d_name;
|
||||
if (!strcmp(fname, ".") || !strcmp(fname, ".."))
|
||||
continue;
|
||||
if (asprintf(&newfile, "%s/%s", file, fname) >= 0) {
|
||||
do_fs_walk(newfile, ignore_symlinks);
|
||||
free(newfile);
|
||||
} else {
|
||||
fprintf(stderr, "asprintf failed\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
// directory metadata is resent; this makes the code simple,
|
||||
// and the atime/mtime is set correctly at the second time
|
||||
single_file_processor(file, &st);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void qfile_pack_init(void) {
|
||||
crc32_sum = 0;
|
||||
ignore_quota_error = 0;
|
||||
// this will allow checking for possible feedback packet in the middle of transfer
|
||||
set_nonblock(0);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
error_handler = NULL;
|
||||
}
|
||||
|
||||
void set_ignore_quota_error(int value) {
|
||||
ignore_quota_error = value;
|
||||
}
|
106
qrexec-lib/qrexec.h
Normal file
106
qrexec-lib/qrexec.h
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/* See also http://wiki.qubes-os.org/trac/wiki/Qrexec */
|
||||
|
||||
#define QREXEC_DAEMON_SOCKET_DIR "/var/run/qubes"
|
||||
#define MAX_FDS 256
|
||||
#define MAX_DATA_CHUNK 4096
|
||||
|
||||
#define REXEC_PORT 512
|
||||
|
||||
#define QREXEC_AGENT_TRIGGER_PATH "/var/run/qubes/qrexec-agent"
|
||||
#define QREXEC_AGENT_FDPASS_PATH "/var/run/qubes/qrexec-agent-fdpass"
|
||||
#define MEMINFO_WRITER_PIDFILE "/var/run/meminfo-writer.pid"
|
||||
#define QUBES_RPC_MULTIPLEXER_PATH "/usr/lib/qubes/qubes-rpc-multiplexer"
|
||||
|
||||
#define QUBES_RPC_MAGIC_CMD "QUBESRPC"
|
||||
|
||||
enum {
|
||||
/* messages from qrexec_client to qrexec_daemon (both in dom0) */
|
||||
/* start process in VM and pass its stdin/out/err to dom0 */
|
||||
MSG_CLIENT_TO_SERVER_EXEC_CMDLINE = 0x100,
|
||||
/* start process in VM discarding its stdin/out/err (connect to /dev/null) */
|
||||
MSG_CLIENT_TO_SERVER_JUST_EXEC,
|
||||
/* connect to existing process in VM to receive its stdin/out/err
|
||||
* struct connect_existing_params passed as data */
|
||||
MSG_CLIENT_TO_SERVER_CONNECT_EXISTING,
|
||||
|
||||
/* messages qrexec_daemon(dom0)->qrexec_agent(VM) */
|
||||
/* same as MSG_CLIENT_TO_SERVER_CONNECT_EXISTING */
|
||||
MSG_SERVER_TO_AGENT_CONNECT_EXISTING,
|
||||
/* same as MSG_CLIENT_TO_SERVER_EXEC_CMDLINE */
|
||||
MSG_SERVER_TO_AGENT_EXEC_CMDLINE,
|
||||
/* same as MSG_CLIENT_TO_SERVER_JUST_EXEC */
|
||||
MSG_SERVER_TO_AGENT_JUST_EXEC,
|
||||
/* pass data to process stdin */
|
||||
MSG_SERVER_TO_AGENT_INPUT,
|
||||
/* detach from process; qrexec_agent should close pipes to process
|
||||
* stdin/out/err; it's up to the VM child process if it cause its termination */
|
||||
MSG_SERVER_TO_AGENT_CLIENT_END,
|
||||
|
||||
/* flow control, qrexec_daemon->qrexec_agent */
|
||||
/* suspend reading of named fd from child process */
|
||||
MSG_XOFF,
|
||||
/* resume reading of named fd from child process */
|
||||
MSG_XON,
|
||||
|
||||
/* messages qrexec_agent(VM)->qrexec_daemon(dom0) */
|
||||
/* pass data from process stdout */
|
||||
MSG_AGENT_TO_SERVER_STDOUT,
|
||||
/* pass data from process stderr */
|
||||
MSG_AGENT_TO_SERVER_STDERR,
|
||||
/* inform that process terminated and pass its exit code; this should be
|
||||
* send after all data from stdout/err are send */
|
||||
MSG_AGENT_TO_SERVER_EXIT_CODE,
|
||||
/* call Qubes RPC service
|
||||
* struct trigger_connect_params passed as data */
|
||||
MSG_AGENT_TO_SERVER_TRIGGER_CONNECT_EXISTING,
|
||||
|
||||
/* messages qrexec_daemon->qrexec_client (both in dom0) */
|
||||
/* same as MSG_AGENT_TO_SERVER_STDOUT */
|
||||
MSG_SERVER_TO_CLIENT_STDOUT,
|
||||
/* same as MSG_AGENT_TO_SERVER_STDERR */
|
||||
MSG_SERVER_TO_CLIENT_STDERR,
|
||||
/* same as MSG_AGENT_TO_SERVER_EXIT_CODE */
|
||||
MSG_SERVER_TO_CLIENT_EXIT_CODE
|
||||
};
|
||||
|
||||
struct server_header {
|
||||
unsigned int type;
|
||||
unsigned int client_id;
|
||||
unsigned int len;
|
||||
};
|
||||
|
||||
struct client_header {
|
||||
unsigned int type;
|
||||
unsigned int len;
|
||||
};
|
||||
|
||||
struct connect_existing_params {
|
||||
char ident[32];
|
||||
};
|
||||
|
||||
struct trigger_connect_params {
|
||||
char exec_index[64];
|
||||
char target_vmname[32];
|
||||
struct connect_existing_params process_fds;
|
||||
};
|
247
qrexec-lib/txrx-vchan.c
Normal file
247
qrexec-lib/txrx-vchan.c
Normal file
@ -0,0 +1,247 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <libvchan.h>
|
||||
#ifdef USE_XENSTORE_H
|
||||
#include <xenstore.h>
|
||||
#else
|
||||
#include <xs.h>
|
||||
#endif
|
||||
#include <xenctrl.h>
|
||||
|
||||
static struct libvchan *ctrl;
|
||||
static int is_server;
|
||||
int write_all_vchan_ext(const void *buf, int size)
|
||||
{
|
||||
int written = 0;
|
||||
int ret;
|
||||
|
||||
while (written < size) {
|
||||
ret =
|
||||
libvchan_write(ctrl, (const char *) buf + written,
|
||||
size - written);
|
||||
if (ret <= 0) {
|
||||
perror("write");
|
||||
exit(1);
|
||||
}
|
||||
written += ret;
|
||||
}
|
||||
// fprintf(stderr, "sent %d bytes\n", size);
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
int read_all_vchan_ext(void *buf, int size)
|
||||
{
|
||||
int written = 0;
|
||||
int ret;
|
||||
while (written < size) {
|
||||
ret =
|
||||
libvchan_read(ctrl, (char *) buf + written,
|
||||
size - written);
|
||||
if (ret == 0) {
|
||||
fprintf(stderr, "EOF\n");
|
||||
exit(1);
|
||||
}
|
||||
if (ret < 0) {
|
||||
perror("read");
|
||||
exit(1);
|
||||
}
|
||||
written += ret;
|
||||
}
|
||||
// fprintf(stderr, "read %d bytes\n", size);
|
||||
return size;
|
||||
}
|
||||
|
||||
unsigned int read_ready_vchan_ext()
|
||||
{
|
||||
int ready = libvchan_data_ready(ctrl);
|
||||
if (ready < 0) {
|
||||
fprintf(stderr, "libvchan_data_ready returned invalid size\n");
|
||||
exit(1);
|
||||
}
|
||||
return ready;
|
||||
}
|
||||
|
||||
unsigned int buffer_space_vchan_ext()
|
||||
{
|
||||
int space = libvchan_buffer_space(ctrl);
|
||||
if (space < 0) {
|
||||
fprintf(stderr, "libvchan_buffer_space returned invalid size\n");
|
||||
exit(1);
|
||||
}
|
||||
return space;
|
||||
}
|
||||
|
||||
// if the remote domain is destroyed, we get no notification
|
||||
// thus, we check for the status periodically
|
||||
|
||||
#ifdef XENCTRL_HAS_XC_INTERFACE
|
||||
static xc_interface *xc_handle = NULL;
|
||||
#else
|
||||
static int xc_handle = -1;
|
||||
#endif
|
||||
void slow_check_for_libvchan_is_eof(struct libvchan *ctrl)
|
||||
{
|
||||
struct evtchn_status evst;
|
||||
evst.port = ctrl->evport;
|
||||
evst.dom = DOMID_SELF;
|
||||
if (xc_evtchn_status(xc_handle, &evst)) {
|
||||
perror("xc_evtchn_status");
|
||||
exit(1);
|
||||
}
|
||||
if (evst.status != EVTCHNSTAT_interdomain) {
|
||||
fprintf(stderr, "event channel disconnected\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int wait_for_vchan_or_argfd_once(int max, fd_set * rdset, fd_set * wrset)
|
||||
{
|
||||
int vfd, ret;
|
||||
struct timespec tv = { 1, 100000000 };
|
||||
sigset_t empty_set;
|
||||
|
||||
sigemptyset(&empty_set);
|
||||
|
||||
vfd = libvchan_fd_for_select(ctrl);
|
||||
FD_SET(vfd, rdset);
|
||||
if (vfd > max)
|
||||
max = vfd;
|
||||
max++;
|
||||
ret = pselect(max, rdset, wrset, NULL, &tv, &empty_set);
|
||||
if (ret < 0) {
|
||||
if (errno != EINTR) {
|
||||
perror("select");
|
||||
exit(1);
|
||||
} else {
|
||||
FD_ZERO(rdset);
|
||||
FD_ZERO(wrset);
|
||||
fprintf(stderr, "eintr\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
if (libvchan_is_eof(ctrl)) {
|
||||
fprintf(stderr, "libvchan_is_eof\n");
|
||||
exit(0);
|
||||
}
|
||||
if (!is_server && ret == 0)
|
||||
slow_check_for_libvchan_is_eof(ctrl);
|
||||
if (FD_ISSET(vfd, rdset))
|
||||
// the following will never block; we need to do this to
|
||||
// clear libvchan_fd pending state
|
||||
libvchan_wait(ctrl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void wait_for_vchan_or_argfd(int max, fd_set * rdset, fd_set * wrset)
|
||||
{
|
||||
fd_set r = *rdset, w = *wrset;
|
||||
do {
|
||||
*rdset = r;
|
||||
*wrset = w;
|
||||
}
|
||||
while (wait_for_vchan_or_argfd_once(max, rdset, wrset) == 0);
|
||||
}
|
||||
|
||||
int peer_server_init(int port)
|
||||
{
|
||||
is_server = 1;
|
||||
ctrl = libvchan_server_init(port);
|
||||
if (!ctrl) {
|
||||
perror("libvchan_server_init");
|
||||
exit(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *peer_client_init(int dom, int port)
|
||||
{
|
||||
struct xs_handle *xs;
|
||||
char buf[64];
|
||||
char *name;
|
||||
char *dummy, *dummy2;
|
||||
unsigned int len = 0;
|
||||
char devbuf[128];
|
||||
char dombuf[128];
|
||||
unsigned int count;
|
||||
char **vec;
|
||||
|
||||
// double_buffered = 1; // writes to vchan are buffered, nonblocking
|
||||
// double_buffer_init();
|
||||
xs = xs_daemon_open();
|
||||
if (!xs) {
|
||||
perror("xs_daemon_open");
|
||||
exit(1);
|
||||
}
|
||||
snprintf(buf, sizeof(buf), "/local/domain/%d/name", dom);
|
||||
name = xs_read(xs, 0, buf, &len);
|
||||
if (!name) {
|
||||
perror("xs_read domainname");
|
||||
exit(1);
|
||||
}
|
||||
snprintf(devbuf, sizeof(devbuf),
|
||||
"/local/domain/%d/device/vchan/%d/event-channel", dom,
|
||||
port);
|
||||
snprintf(dombuf, sizeof(dombuf), "/local/domain/%d", dom);
|
||||
xs_watch(xs, devbuf, devbuf);
|
||||
do {
|
||||
vec = xs_read_watch(xs, &count);
|
||||
if (vec)
|
||||
free(vec);
|
||||
len = 0;
|
||||
dummy = xs_read(xs, 0, devbuf, &len);
|
||||
if (dummy)
|
||||
free(dummy);
|
||||
else {
|
||||
/* check if domain still alive */
|
||||
dummy2 = xs_read(xs, 0, dombuf, &len);
|
||||
if (!dummy2) {
|
||||
fprintf(stderr, "domain dead\n");
|
||||
exit(1);
|
||||
}
|
||||
free(dummy2);
|
||||
}
|
||||
}
|
||||
while (!dummy || !len); // wait for the server to create xenstore entries
|
||||
xs_daemon_close(xs);
|
||||
|
||||
// now client init should succeed; "while" is redundant
|
||||
while (!(ctrl = libvchan_client_init(dom, port)));
|
||||
|
||||
#ifdef XENCTRL_HAS_XC_INTERFACE
|
||||
xc_handle = xc_interface_open(NULL, 0, 0);
|
||||
if (!xc_handle) {
|
||||
#else
|
||||
xc_handle = xc_interface_open();
|
||||
if (xc_handle < 0) {
|
||||
#endif
|
||||
perror("xc_interface_open");
|
||||
exit(1);
|
||||
}
|
||||
return name;
|
||||
}
|
73
qrexec-lib/unix-server.c
Normal file
73
qrexec-lib/unix-server.c
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
//#include "qrexec.h"
|
||||
|
||||
int get_server_socket(const char *socket_address)
|
||||
{
|
||||
struct sockaddr_un sockname;
|
||||
int s;
|
||||
|
||||
unlink(socket_address);
|
||||
|
||||
s = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (s < 0) {
|
||||
printf("socket() failed\n");
|
||||
exit(1);
|
||||
}
|
||||
memset(&sockname, 0, sizeof(sockname));
|
||||
sockname.sun_family = AF_UNIX;
|
||||
strncpy(sockname.sun_path, socket_address, sizeof sockname.sun_path);
|
||||
sockname.sun_path[sizeof sockname.sun_path - 1] = 0;
|
||||
|
||||
if (bind(s, (struct sockaddr *) &sockname, sizeof(sockname)) == -1) {
|
||||
printf("bind() failed\n");
|
||||
close(s);
|
||||
exit(1);
|
||||
}
|
||||
// chmod(sockname.sun_path, 0666);
|
||||
if (listen(s, 5) == -1) {
|
||||
perror("listen() failed\n");
|
||||
close(s);
|
||||
exit(1);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
int do_accept(int s)
|
||||
{
|
||||
struct sockaddr_un peer;
|
||||
unsigned int addrlen;
|
||||
int fd;
|
||||
addrlen = sizeof(peer);
|
||||
fd = accept(s, (struct sockaddr *) &peer, &addrlen);
|
||||
if (fd == -1) {
|
||||
perror("unix accept");
|
||||
exit(1);
|
||||
}
|
||||
return fd;
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
#define _GNU_SOURCE /* For O_NOFOLLOW. */
|
||||
#include <errno.h>
|
||||
#include <ioall.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
@ -9,7 +10,6 @@
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include "libqubes-rpc-filecopy.h"
|
||||
#include "ioall.h"
|
||||
#include "crc32.h"
|
||||
|
||||
char untrusted_namebuf[MAX_PATH_LENGTH];
|
||||
@ -35,203 +35,194 @@ void send_status_and_crc(int code, const char *last_filename);
|
||||
|
||||
void do_exit(int code, const char *last_filename)
|
||||
{
|
||||
close(0);
|
||||
send_status_and_crc(code, last_filename);
|
||||
exit(code);
|
||||
close(0);
|
||||
send_status_and_crc(code, last_filename);
|
||||
exit(code);
|
||||
}
|
||||
|
||||
void set_size_limit(unsigned long long new_bytes_limit, unsigned long long new_files_limit)
|
||||
{
|
||||
bytes_limit = new_bytes_limit;
|
||||
files_limit = new_files_limit;
|
||||
bytes_limit = new_bytes_limit;
|
||||
files_limit = new_files_limit;
|
||||
}
|
||||
|
||||
void set_verbose(int value)
|
||||
{
|
||||
verbose = value;
|
||||
verbose = value;
|
||||
}
|
||||
|
||||
void set_procfs_fd(int value)
|
||||
{
|
||||
procdir_fd = value;
|
||||
use_tmpfile = 1;
|
||||
procdir_fd = value;
|
||||
use_tmpfile = 1;
|
||||
}
|
||||
|
||||
unsigned long crc32_sum = 0;
|
||||
int read_all_with_crc(int fd, void *buf, int size) {
|
||||
int ret;
|
||||
ret = read_all(fd, buf, size);
|
||||
if (ret)
|
||||
crc32_sum = Crc32_ComputeBuf(crc32_sum, buf, size);
|
||||
return ret;
|
||||
int ret;
|
||||
ret = read_all(fd, buf, size);
|
||||
if (ret)
|
||||
crc32_sum = Crc32_ComputeBuf(crc32_sum, buf, size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void send_status_and_crc(int code, const char *last_filename) {
|
||||
struct result_header hdr;
|
||||
struct result_header_ext hdr_ext;
|
||||
int saved_errno;
|
||||
struct result_header hdr;
|
||||
struct result_header_ext hdr_ext;
|
||||
int saved_errno;
|
||||
|
||||
saved_errno = errno;
|
||||
hdr.error_code = code;
|
||||
hdr._pad = 0;
|
||||
hdr.crc32 = crc32_sum;
|
||||
if (!write_all(1, &hdr, sizeof(hdr)))
|
||||
perror("write status");
|
||||
if (last_filename) {
|
||||
hdr_ext.last_namelen = strlen(last_filename);
|
||||
if (!write_all(1, &hdr_ext, sizeof(hdr_ext)))
|
||||
perror("write status ext");
|
||||
if (!write_all(1, last_filename, hdr_ext.last_namelen))
|
||||
perror("write last_filename");
|
||||
}
|
||||
errno = saved_errno;
|
||||
saved_errno = errno;
|
||||
hdr.error_code = code;
|
||||
hdr.crc32 = crc32_sum;
|
||||
if (!write_all(1, &hdr, sizeof(hdr)))
|
||||
perror("write status");
|
||||
if (last_filename) {
|
||||
hdr_ext.last_namelen = strlen(last_filename);
|
||||
if (!write_all(1, &hdr_ext, sizeof(hdr_ext)))
|
||||
perror("write status ext");
|
||||
if (!write_all(1, last_filename, hdr_ext.last_namelen))
|
||||
perror("write last_filename");
|
||||
}
|
||||
errno = saved_errno;
|
||||
}
|
||||
|
||||
void fix_times_and_perms(struct file_header *untrusted_hdr,
|
||||
const char *untrusted_name)
|
||||
const char *untrusted_name)
|
||||
{
|
||||
struct timeval times[2] =
|
||||
{
|
||||
{untrusted_hdr->atime, untrusted_hdr->atime_nsec / 1000},
|
||||
{untrusted_hdr->mtime, untrusted_hdr->mtime_nsec / 1000}
|
||||
};
|
||||
if (chmod(untrusted_name, untrusted_hdr->mode & 07777)) /* safe because of chroot */
|
||||
do_exit(errno, untrusted_name);
|
||||
if (utimes(untrusted_name, times)) /* as above */
|
||||
do_exit(errno, untrusted_name);
|
||||
struct timeval times[2] =
|
||||
{ {untrusted_hdr->atime, untrusted_hdr->atime_nsec / 1000},
|
||||
{untrusted_hdr->mtime,
|
||||
untrusted_hdr->mtime_nsec / 1000}
|
||||
};
|
||||
if (chmod(untrusted_name, untrusted_hdr->mode & 07777)) /* safe because of chroot */
|
||||
do_exit(errno, untrusted_name);
|
||||
if (utimes(untrusted_name, times)) /* as above */
|
||||
do_exit(errno, untrusted_name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void process_one_file_reg(struct file_header *untrusted_hdr,
|
||||
const char *untrusted_name)
|
||||
const char *untrusted_name)
|
||||
{
|
||||
int ret;
|
||||
int fdout = -1;
|
||||
int ret;
|
||||
int fdout = -1;
|
||||
|
||||
/* make the file inaccessible until fully written */
|
||||
if (use_tmpfile) {
|
||||
fdout = open(".", O_WRONLY | O_TMPFILE, 0700);
|
||||
if (fdout < 0) {
|
||||
if (errno==ENOENT || /* most likely, kernel too old for O_TMPFILE */
|
||||
errno==EOPNOTSUPP) /* filesystem has no support for O_TMPFILE */
|
||||
use_tmpfile = 0;
|
||||
else
|
||||
do_exit(errno, untrusted_name);
|
||||
}
|
||||
}
|
||||
if (fdout < 0)
|
||||
fdout = open(untrusted_name, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0000); /* safe because of chroot */
|
||||
if (fdout < 0)
|
||||
do_exit(errno, untrusted_name);
|
||||
/* sizes are signed elsewhere */
|
||||
if (untrusted_hdr->filelen > LLONG_MAX || (bytes_limit && untrusted_hdr->filelen > bytes_limit))
|
||||
do_exit(EDQUOT, untrusted_name);
|
||||
if (bytes_limit && total_bytes > bytes_limit - untrusted_hdr->filelen)
|
||||
do_exit(EDQUOT, untrusted_name);
|
||||
total_bytes += untrusted_hdr->filelen;
|
||||
ret = copy_file(fdout, 0, untrusted_hdr->filelen, &crc32_sum);
|
||||
if (ret != COPY_FILE_OK) {
|
||||
if (ret == COPY_FILE_READ_EOF
|
||||
|| ret == COPY_FILE_READ_ERROR)
|
||||
do_exit(LEGAL_EOF, untrusted_name); // hopefully remote will produce error message
|
||||
else
|
||||
do_exit(errno, untrusted_name);
|
||||
}
|
||||
if (use_tmpfile) {
|
||||
char fd_str[7];
|
||||
snprintf(fd_str, sizeof(fd_str), "%d", fdout);
|
||||
if (linkat(procdir_fd, fd_str, AT_FDCWD, untrusted_name, AT_SYMLINK_FOLLOW) < 0)
|
||||
do_exit(errno, untrusted_name);
|
||||
}
|
||||
close(fdout);
|
||||
fix_times_and_perms(untrusted_hdr, untrusted_name);
|
||||
/* make the file inaccessible until fully written */
|
||||
if (use_tmpfile) {
|
||||
fdout = open(".", O_WRONLY | O_TMPFILE, 0700);
|
||||
if (fdout < 0) {
|
||||
if (errno==ENOENT)
|
||||
/* if it fails, do not attempt further use - most likely kernel too old */
|
||||
use_tmpfile = 0;
|
||||
else
|
||||
do_exit(errno, untrusted_name);
|
||||
}
|
||||
}
|
||||
if (fdout < 0)
|
||||
fdout = open(untrusted_name, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0000); /* safe because of chroot */
|
||||
if (fdout < 0)
|
||||
do_exit(errno, untrusted_name);
|
||||
/* sizes are signed elsewhere */
|
||||
if (untrusted_hdr->filelen > LLONG_MAX || (bytes_limit && untrusted_hdr->filelen > bytes_limit))
|
||||
do_exit(EDQUOT, untrusted_name);
|
||||
if (bytes_limit && total_bytes > bytes_limit - untrusted_hdr->filelen)
|
||||
do_exit(EDQUOT, untrusted_name);
|
||||
total_bytes += untrusted_hdr->filelen;
|
||||
ret = copy_file(fdout, 0, untrusted_hdr->filelen, &crc32_sum);
|
||||
if (ret != COPY_FILE_OK) {
|
||||
if (ret == COPY_FILE_READ_EOF
|
||||
|| ret == COPY_FILE_READ_ERROR)
|
||||
do_exit(LEGAL_EOF, untrusted_name); // hopefully remote will produce error message
|
||||
else
|
||||
do_exit(errno, untrusted_name);
|
||||
}
|
||||
fdatasync(fdout);
|
||||
if (use_tmpfile) {
|
||||
char fd_str[7];
|
||||
snprintf(fd_str, sizeof(fd_str), "%d", fdout);
|
||||
if (linkat(procdir_fd, fd_str, AT_FDCWD, untrusted_name, AT_SYMLINK_FOLLOW) < 0)
|
||||
do_exit(errno, untrusted_name);
|
||||
}
|
||||
close(fdout);
|
||||
fix_times_and_perms(untrusted_hdr, untrusted_name);
|
||||
}
|
||||
|
||||
|
||||
void process_one_file_dir(struct file_header *untrusted_hdr,
|
||||
const char *untrusted_name)
|
||||
const char *untrusted_name)
|
||||
{
|
||||
// fix perms only when the directory is sent for the second time
|
||||
// it allows to transfer r.x directory contents, as we create it rwx initially
|
||||
struct stat buf;
|
||||
if (!mkdir(untrusted_name, 0700)) /* safe because of chroot */
|
||||
return;
|
||||
if (errno != EEXIST)
|
||||
do_exit(errno, untrusted_name);
|
||||
if (stat(untrusted_name,&buf) < 0)
|
||||
do_exit(errno, untrusted_name);
|
||||
total_bytes += buf.st_size;
|
||||
/* size accumulated after the fact, so don't check limit here */
|
||||
fix_times_and_perms(untrusted_hdr, untrusted_name);
|
||||
// fix perms only when the directory is sent for the second time
|
||||
// it allows to transfer r.x directory contents, as we create it rwx initially
|
||||
struct stat buf;
|
||||
if (!mkdir(untrusted_name, 0700)) /* safe because of chroot */
|
||||
return;
|
||||
if (errno != EEXIST)
|
||||
do_exit(errno, untrusted_name);
|
||||
if (stat(untrusted_name,&buf) < 0)
|
||||
do_exit(errno, untrusted_name);
|
||||
total_bytes += buf.st_size;
|
||||
/* size accumulated after the fact, so don't check limit here */
|
||||
fix_times_and_perms(untrusted_hdr, untrusted_name);
|
||||
}
|
||||
|
||||
void process_one_file_link(struct file_header *untrusted_hdr,
|
||||
const char *untrusted_name)
|
||||
const char *untrusted_name)
|
||||
{
|
||||
char untrusted_content[MAX_PATH_LENGTH];
|
||||
unsigned int filelen;
|
||||
if (untrusted_hdr->filelen > MAX_PATH_LENGTH - 1)
|
||||
do_exit(ENAMETOOLONG, untrusted_name);
|
||||
filelen = untrusted_hdr->filelen; /* sanitized above */
|
||||
total_bytes += filelen;
|
||||
if (bytes_limit && total_bytes > bytes_limit)
|
||||
do_exit(EDQUOT, untrusted_name);
|
||||
if (!read_all_with_crc(0, untrusted_content, filelen))
|
||||
do_exit(LEGAL_EOF, untrusted_name); // hopefully remote has produced error message
|
||||
untrusted_content[filelen] = 0;
|
||||
if (symlink(untrusted_content, untrusted_name)) /* safe because of chroot */
|
||||
do_exit(errno, untrusted_name);
|
||||
char untrusted_content[MAX_PATH_LENGTH];
|
||||
unsigned int filelen;
|
||||
if (untrusted_hdr->filelen > MAX_PATH_LENGTH - 1)
|
||||
do_exit(ENAMETOOLONG, untrusted_name);
|
||||
filelen = untrusted_hdr->filelen; /* sanitized above */
|
||||
total_bytes += filelen;
|
||||
if (bytes_limit && total_bytes > bytes_limit)
|
||||
do_exit(EDQUOT, untrusted_name);
|
||||
if (!read_all_with_crc(0, untrusted_content, filelen))
|
||||
do_exit(LEGAL_EOF, untrusted_name); // hopefully remote has produced error message
|
||||
untrusted_content[filelen] = 0;
|
||||
if (symlink(untrusted_content, untrusted_name)) /* safe because of chroot */
|
||||
do_exit(errno, untrusted_name);
|
||||
|
||||
}
|
||||
|
||||
void process_one_file(struct file_header *untrusted_hdr)
|
||||
{
|
||||
unsigned int namelen;
|
||||
if (untrusted_hdr->namelen > MAX_PATH_LENGTH - 1)
|
||||
do_exit(ENAMETOOLONG, NULL); /* filename too long so not received at all */
|
||||
namelen = untrusted_hdr->namelen; /* sanitized above */
|
||||
if (!read_all_with_crc(0, untrusted_namebuf, namelen))
|
||||
do_exit(LEGAL_EOF, NULL); // hopefully remote has produced error message
|
||||
untrusted_namebuf[namelen] = 0;
|
||||
if (S_ISREG(untrusted_hdr->mode))
|
||||
process_one_file_reg(untrusted_hdr, untrusted_namebuf);
|
||||
else if (S_ISLNK(untrusted_hdr->mode))
|
||||
process_one_file_link(untrusted_hdr, untrusted_namebuf);
|
||||
else if (S_ISDIR(untrusted_hdr->mode))
|
||||
process_one_file_dir(untrusted_hdr, untrusted_namebuf);
|
||||
else
|
||||
do_exit(EINVAL, untrusted_namebuf);
|
||||
if (verbose && !S_ISDIR(untrusted_hdr->mode))
|
||||
fprintf(stderr, "%s\n", untrusted_namebuf);
|
||||
unsigned int namelen;
|
||||
if (untrusted_hdr->namelen > MAX_PATH_LENGTH - 1)
|
||||
do_exit(ENAMETOOLONG, NULL); /* filename too long so not received at all */
|
||||
namelen = untrusted_hdr->namelen; /* sanitized above */
|
||||
if (!read_all_with_crc(0, untrusted_namebuf, namelen))
|
||||
do_exit(LEGAL_EOF, NULL); // hopefully remote has produced error message
|
||||
untrusted_namebuf[namelen] = 0;
|
||||
if (S_ISREG(untrusted_hdr->mode))
|
||||
process_one_file_reg(untrusted_hdr, untrusted_namebuf);
|
||||
else if (S_ISLNK(untrusted_hdr->mode))
|
||||
process_one_file_link(untrusted_hdr, untrusted_namebuf);
|
||||
else if (S_ISDIR(untrusted_hdr->mode))
|
||||
process_one_file_dir(untrusted_hdr, untrusted_namebuf);
|
||||
else
|
||||
do_exit(EINVAL, untrusted_namebuf);
|
||||
if (verbose && !S_ISDIR(untrusted_hdr->mode))
|
||||
fprintf(stderr, "%s\n", untrusted_namebuf);
|
||||
}
|
||||
|
||||
int do_unpack(void)
|
||||
{
|
||||
struct file_header untrusted_hdr;
|
||||
int cwd_fd;
|
||||
int saved_errno;
|
||||
|
||||
total_bytes = total_files = 0;
|
||||
/* initialize checksum */
|
||||
crc32_sum = 0;
|
||||
while (read_all_with_crc(0, &untrusted_hdr, sizeof untrusted_hdr)) {
|
||||
/* check for end of transfer marker */
|
||||
if (untrusted_hdr.namelen == 0) {
|
||||
errno = 0;
|
||||
break;
|
||||
}
|
||||
total_files++;
|
||||
if (files_limit && total_files > files_limit)
|
||||
do_exit(EDQUOT, untrusted_namebuf);
|
||||
process_one_file(&untrusted_hdr);
|
||||
}
|
||||
|
||||
saved_errno = errno;
|
||||
cwd_fd = open(".", O_RDONLY);
|
||||
if (cwd_fd >= 0 && syncfs(cwd_fd) == 0 && close(cwd_fd) == 0)
|
||||
errno = saved_errno;
|
||||
|
||||
send_status_and_crc(errno, untrusted_namebuf);
|
||||
return errno;
|
||||
struct file_header untrusted_hdr;
|
||||
total_bytes = total_files = 0;
|
||||
/* initialize checksum */
|
||||
crc32_sum = 0;
|
||||
while (read_all_with_crc(0, &untrusted_hdr, sizeof untrusted_hdr)) {
|
||||
/* check for end of transfer marker */
|
||||
if (untrusted_hdr.namelen == 0) {
|
||||
errno = 0;
|
||||
break;
|
||||
}
|
||||
total_files++;
|
||||
if (files_limit && total_files > files_limit)
|
||||
do_exit(EDQUOT, untrusted_namebuf);
|
||||
process_one_file(&untrusted_hdr);
|
||||
}
|
||||
send_status_and_crc(errno, untrusted_namebuf);
|
||||
return errno;
|
||||
}
|
||||
|
135
qrexec-lib/write-stdin.c
Normal file
135
qrexec-lib/write-stdin.c
Normal file
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include "qrexec.h"
|
||||
#include "libqrexec-utils.h"
|
||||
|
||||
/*
|
||||
There is buffered data in "buffer" for client id "client_id", and select()
|
||||
reports that "fd" is writable. Write as much as possible to fd, if all sent,
|
||||
notify the peer that this client's pipe is no longer full.
|
||||
*/
|
||||
int flush_client_data(int fd, int client_id, struct buffer *buffer)
|
||||
{
|
||||
int ret;
|
||||
int len;
|
||||
for (;;) {
|
||||
len = buffer_len(buffer);
|
||||
if (len > MAX_DATA_CHUNK)
|
||||
len = MAX_DATA_CHUNK;
|
||||
ret = write(fd, buffer_data(buffer), len);
|
||||
if (ret == -1) {
|
||||
if (errno != EAGAIN) {
|
||||
return WRITE_STDIN_ERROR;
|
||||
} else
|
||||
return WRITE_STDIN_BUFFERED;
|
||||
}
|
||||
// we previously called buffer_remove(buffer, len)
|
||||
// it will be wrong if we change MAX_DATA_CHUNK to something large
|
||||
// as pipes writes are atomic only to PIPE_MAX limit
|
||||
buffer_remove(buffer, ret);
|
||||
len = buffer_len(buffer);
|
||||
if (!len) {
|
||||
struct server_header s_hdr;
|
||||
s_hdr.type = MSG_XON;
|
||||
s_hdr.client_id = client_id;
|
||||
s_hdr.len = 0;
|
||||
write_all_vchan_ext(&s_hdr, sizeof s_hdr);
|
||||
return WRITE_STDIN_OK;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Write "len" bytes from "data" to "fd". If not all written, buffer the rest
|
||||
to "buffer", and notify the peer that the client "client_id" pipe is full via
|
||||
MSG_XOFF message.
|
||||
*/
|
||||
int write_stdin(int fd, int client_id, const char *data, int len,
|
||||
struct buffer *buffer)
|
||||
{
|
||||
int ret;
|
||||
int written = 0;
|
||||
|
||||
if (buffer_len(buffer)) {
|
||||
buffer_append(buffer, data, len);
|
||||
return WRITE_STDIN_BUFFERED;
|
||||
}
|
||||
while (written < len) {
|
||||
ret = write(fd, data + written, len - written);
|
||||
if (ret == 0) {
|
||||
perror("write_stdin: write returns 0 ???");
|
||||
exit(1);
|
||||
}
|
||||
if (ret == -1) {
|
||||
struct server_header s_hdr;
|
||||
|
||||
if (errno != EAGAIN)
|
||||
return WRITE_STDIN_ERROR;
|
||||
|
||||
buffer_append(buffer, data + written,
|
||||
len - written);
|
||||
|
||||
s_hdr.type = MSG_XOFF;
|
||||
s_hdr.client_id = client_id;
|
||||
s_hdr.len = 0;
|
||||
write_all_vchan_ext(&s_hdr, sizeof s_hdr);
|
||||
|
||||
return WRITE_STDIN_BUFFERED;
|
||||
}
|
||||
written += ret;
|
||||
}
|
||||
return WRITE_STDIN_OK;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Data feed process has exited, so we need to clear all control structures for
|
||||
the client. However, if we have buffered data for the client (which is rare btw),
|
||||
fire&forget a separate process to flush them.
|
||||
*/
|
||||
int fork_and_flush_stdin(int fd, struct buffer *buffer)
|
||||
{
|
||||
int i;
|
||||
if (!buffer_len(buffer))
|
||||
return 0;
|
||||
switch (fork()) {
|
||||
case -1:
|
||||
perror("fork");
|
||||
exit(1);
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
for (i = 0; i < MAX_FDS; i++)
|
||||
if (i != fd && i != 2)
|
||||
close(i);
|
||||
set_block(fd);
|
||||
write_all(fd, buffer_data(buffer), buffer_len(buffer));
|
||||
_exit(0);
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
#
|
||||
# The Qubes OS Project, http://www.qubes-os.org
|
||||
#
|
||||
# Copyright (C) 2015 Marek Marczykowski-Górecki
|
||||
# <marmarek@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.
|
||||
#
|
||||
|
||||
Name: qubes-kernel-vm-support
|
||||
Version: @VERSION@
|
||||
Release: 1%{?dist}
|
||||
Summary: Qubes VM initramfs modules
|
||||
Source0: qubes-utils-%{version}.tar.gz
|
||||
|
||||
Group: Qubes
|
||||
Vendor: Invisible Things Lab
|
||||
License: GPL v2 only
|
||||
URL: http://www.qubes-os.org
|
||||
|
||||
Requires: dracut
|
||||
|
||||
%description
|
||||
This package contains:
|
||||
1. Dracut module required to setup Qubes VM root filesystem. This package is
|
||||
needed in VM only when the VM uses its own kernel (via pvgrub or so). Otherwise
|
||||
initrd is provided by dom0.
|
||||
|
||||
%prep
|
||||
%setup -q -n qubes-utils-%{version}
|
||||
|
||||
%install
|
||||
make install-fedora-kernel-support DESTDIR=%{buildroot}
|
||||
|
||||
%files
|
||||
/usr/lib/dracut/modules.d/90qubes-vm
|
||||
/usr/lib/dracut/modules.d/90qubes-vm-modules
|
||||
/usr/lib/dracut/modules.d/90qubes-vm-simple
|
||||
/usr/lib/dracut/modules.d/80xen-scrub-pages
|
||||
/usr/sbin/qubes-prepare-vm-kernel
|
||||
%config(noreplace) /etc/default/grub.qubes-kernel-vm-support
|
||||
|
||||
%triggerin -- grub2-tools
|
||||
if ! grep -q '/etc/default/grub.qubes-kernel-vm-support$' /etc/default/grub 2>/dev/null; then
|
||||
# do not keep Qubes-related settings directly in user-controlled config,
|
||||
# include another file
|
||||
echo '. /etc/default/grub.qubes-kernel-vm-support' >> /etc/default/grub
|
||||
fi
|
||||
|
||||
%preun
|
||||
if [ $1 -eq 0 ]; then
|
||||
if grep -q '/etc/default/grub.qubes-kernel-vm-support$' /etc/default/grub 2>/dev/null; then
|
||||
sed -i -e '/grub.qubes-kernel-vm-support$/d' /etc/default/grub
|
||||
fi
|
||||
fi
|
||||
|
||||
%posttrans
|
||||
|
||||
# Rebuild all initramfs images to include updated modules
|
||||
if [ -r /usr/share/qubes/marker-vm ] && [ -x /usr/bin/dracut ]; then
|
||||
ret=0
|
||||
for img in /boot/initramfs-*.img; do
|
||||
kver="${img#*initramfs-}"
|
||||
kver="${kver%.img}"
|
||||
dracut -f "$img" "$kver" || ret=$?
|
||||
done
|
||||
if [ "$ret" -eq 0 ]; then
|
||||
# "milestone" initramfs update version:
|
||||
# 1 - addition of xen scrub_pages enabling code
|
||||
echo 1 > /var/lib/qubes/initramfs-updated
|
||||
fi
|
||||
fi
|
||||
|
||||
%changelog
|
||||
@CHANGELOG@
|
100
rpm_spec/qubes-utils.spec
Normal file
100
rpm_spec/qubes-utils.spec
Normal file
@ -0,0 +1,100 @@
|
||||
%define version %(cat version)
|
||||
%if 0%{?qubes_builder}
|
||||
%define _builddir %(pwd)
|
||||
%endif
|
||||
|
||||
%{!?python_sitearch: %define python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")}
|
||||
|
||||
Name: qubes-utils
|
||||
Version: %{version}
|
||||
Release: 1%{?dist}
|
||||
Summary: Common Linux files for Qubes Dom0 and VM
|
||||
|
||||
Group: Qubes
|
||||
License: GPL
|
||||
URL: http://www.qubes-os.org
|
||||
|
||||
Requires: udev
|
||||
Requires: %{name}-libs
|
||||
Requires: ImageMagick
|
||||
Requires: pycairo
|
||||
BuildRequires: qubes-libvchan-devel
|
||||
|
||||
%description
|
||||
Common Linux files for Qubes Dom0 and VM
|
||||
|
||||
%package devel
|
||||
Summary: Development headers for qubes-utils
|
||||
Release: 1%{?dist}
|
||||
Requires: %{name}-libs
|
||||
|
||||
%description devel
|
||||
Development header and files for qubes-utils
|
||||
|
||||
%package libs
|
||||
Summary: Qubes utils libraries
|
||||
Release: 1%{?dist}
|
||||
|
||||
%description libs
|
||||
Libraries for qubes-utils
|
||||
|
||||
%prep
|
||||
# we operate on the current directory, so no need to unpack anything
|
||||
# symlink is to generate useful debuginfo packages
|
||||
rm -f %{name}-%{version}
|
||||
ln -sf . %{name}-%{version}
|
||||
%setup -T -D
|
||||
|
||||
|
||||
%build
|
||||
make all
|
||||
|
||||
%install
|
||||
make install DESTDIR=%{buildroot}
|
||||
|
||||
%post
|
||||
# dom0
|
||||
/bin/systemctl enable qubes-meminfo-writer-dom0.service > /dev/null 2>&1
|
||||
# VM
|
||||
/bin/systemctl enable qubes-meminfo-writer.service > /dev/null 2>&1
|
||||
|
||||
%postun
|
||||
if [ $1 -eq 0 ]; then
|
||||
/bin/systemctl disable qubes-meminfo-writer.service > /dev/null 2>&1
|
||||
/bin/systemctl disable qubes-meminfo-writer.service > /dev/null 2>&1
|
||||
fi
|
||||
|
||||
%post libs -p /sbin/ldconfig
|
||||
%postun libs -p /sbin/ldconfig
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%files
|
||||
%defattr(-,root,root,-)
|
||||
/etc/udev/rules.d/99-qubes-*.rules
|
||||
/usr/libexec/qubes/udev-*
|
||||
%{_sbindir}/meminfo-writer
|
||||
%{_unitdir}/qubes-meminfo-writer.service
|
||||
%{_unitdir}/qubes-meminfo-writer-dom0.service
|
||||
%{python_sitearch}/qubes/__init__.py
|
||||
%{python_sitearch}/qubes/__init__.pyc
|
||||
%{python_sitearch}/qubes/__init__.pyo
|
||||
%attr(0755,root,root) %{python_sitearch}/qubes/imgconverter.py
|
||||
%{python_sitearch}/qubes/imgconverter.pyc
|
||||
%{python_sitearch}/qubes/imgconverter.pyo
|
||||
|
||||
%files libs
|
||||
%{_libdir}/libqrexec-utils.so.1
|
||||
%{_libdir}/libqubes-rpc-filecopy.so.1
|
||||
|
||||
%files devel
|
||||
%defattr(-,root,root,-)
|
||||
/usr/include/libqrexec-utils.h
|
||||
/usr/include/libqubes-rpc-filecopy.h
|
||||
/usr/include/qrexec.h
|
||||
%{_libdir}/libqrexec-utils.so
|
||||
%{_libdir}/libqubes-rpc-filecopy.so
|
||||
|
||||
%changelog
|
||||
|
@ -1,132 +0,0 @@
|
||||
Name: qubes-utils
|
||||
Version: @VERSION@
|
||||
Release: 1%{?dist}
|
||||
Summary: Common Linux files for Qubes Dom0 and VM
|
||||
Source0: %{name}-%{version}.tar.gz
|
||||
|
||||
Group: Qubes
|
||||
License: GPL
|
||||
URL: http://www.qubes-os.org
|
||||
|
||||
Requires: udev
|
||||
Requires: %{name}-libs
|
||||
Requires: ImageMagick
|
||||
Requires: python%{python3_pkgversion}-qubesimgconverter
|
||||
%{?systemd_requires}
|
||||
BuildRequires: systemd
|
||||
BuildRequires: python2-setuptools
|
||||
BuildRequires: python%{python3_pkgversion}-setuptools
|
||||
BuildRequires: python2-rpm-macros
|
||||
BuildRequires: python3-rpm-macros
|
||||
# for meminfo-writer
|
||||
BuildRequires: xen-devel
|
||||
BuildRequires: gcc
|
||||
|
||||
%description
|
||||
Common Linux files for Qubes Dom0 and VM
|
||||
|
||||
%package -n python2-qubesimgconverter
|
||||
Summary: Python package qubesimgconverter
|
||||
Requires: python2
|
||||
Requires: pycairo
|
||||
%if 0%{?rhel} >= 7
|
||||
Requires: python-pillow
|
||||
Requires: numpy
|
||||
%else
|
||||
Requires: python2-pillow
|
||||
Requires: python2-numpy
|
||||
%endif
|
||||
|
||||
%description -n python2-qubesimgconverter
|
||||
Python package qubesimgconverter
|
||||
|
||||
%package -n python%{python3_pkgversion}-qubesimgconverter
|
||||
Summary: Python package qubesimgconverter
|
||||
Requires: python%{python3_pkgversion}
|
||||
Requires: python%{python3_pkgversion}-cairo
|
||||
Requires: python%{python3_pkgversion}-pillow
|
||||
Requires: python%{python3_pkgversion}-numpy
|
||||
|
||||
%description -n python%{python3_pkgversion}-qubesimgconverter
|
||||
Python package qubesimgconverter
|
||||
|
||||
%package devel
|
||||
Summary: Development headers for qubes-utils
|
||||
Release: 1%{?dist}
|
||||
Requires: %{name}-libs
|
||||
|
||||
%description devel
|
||||
Development header and files for qubes-utils
|
||||
|
||||
%package libs
|
||||
Summary: Qubes utils libraries
|
||||
Release: 1%{?dist}
|
||||
|
||||
%description libs
|
||||
Libraries for qubes-utils
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
%build
|
||||
export PYTHON=%{__python2}
|
||||
make all BACKEND_VMM=@BACKEND_VMM@
|
||||
|
||||
%install
|
||||
make install DESTDIR=%{buildroot} PYTHON=%{__python2}
|
||||
rm -rf imgconverter/build
|
||||
%make_install -C imgconverter PYTHON=%{__python3}
|
||||
|
||||
%post
|
||||
# dom0
|
||||
%systemd_post qubes-meminfo-writer-dom0.service
|
||||
# VM
|
||||
%systemd_post qubes-meminfo-writer.service
|
||||
|
||||
%preun
|
||||
%systemd_preun qubes-meminfo-writer-dom0.service
|
||||
%systemd_preun qubes-meminfo-writer.service
|
||||
|
||||
%postun
|
||||
%systemd_postun_with_restart qubes-meminfo-writer-dom0.service
|
||||
%systemd_postun_with_restart qubes-meminfo-writer.service
|
||||
|
||||
%post libs -p /sbin/ldconfig
|
||||
%postun libs -p /sbin/ldconfig
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%files
|
||||
%defattr(-,root,root,-)
|
||||
/lib/udev/rules.d/*-qubes-*.rules
|
||||
/usr/lib/qubes/udev-*
|
||||
%{_sbindir}/meminfo-writer
|
||||
%{_unitdir}/qubes-meminfo-writer.service
|
||||
%{_unitdir}/qubes-meminfo-writer-dom0.service
|
||||
|
||||
%files -n python2-qubesimgconverter
|
||||
%{python2_sitelib}/qubesimgconverter/__init__.py*
|
||||
%{python2_sitelib}/qubesimgconverter/imggen.py*
|
||||
%{python2_sitelib}/qubesimgconverter/test.py*
|
||||
%{python2_sitelib}/qubesimgconverter/test_integ.py*
|
||||
%{python2_sitelib}/qubesimgconverter-%{version}-py?.?.egg-info
|
||||
|
||||
%files -n python%{python3_pkgversion}-qubesimgconverter
|
||||
%{python3_sitelib}/qubesimgconverter/__init__.py
|
||||
%{python3_sitelib}/qubesimgconverter/imggen.py
|
||||
%{python3_sitelib}/qubesimgconverter/test.py
|
||||
%{python3_sitelib}/qubesimgconverter/test_integ.py
|
||||
%{python3_sitelib}/qubesimgconverter-%{version}-py?.?.egg-info
|
||||
%{python3_sitelib}/qubesimgconverter/__pycache__
|
||||
|
||||
%files libs
|
||||
%{_libdir}/libqubes-rpc-filecopy.so.2
|
||||
|
||||
%files devel
|
||||
%defattr(-,root,root,-)
|
||||
/usr/include/libqubes-rpc-filecopy.h
|
||||
%{_libdir}/libqubes-rpc-filecopy.so
|
||||
|
||||
%changelog
|
||||
@CHANGELOG@
|
@ -1,14 +1,13 @@
|
||||
all:
|
||||
|
||||
install:
|
||||
mkdir -p $(DESTDIR)$(SYSLIBDIR)/udev/rules.d
|
||||
cp udev-qubes-block.rules $(DESTDIR)$(SYSLIBDIR)/udev/rules.d/99-qubes-block.rules
|
||||
cp udev-qubes-usb.rules $(DESTDIR)$(SYSLIBDIR)/udev/rules.d/99-qubes-usb.rules
|
||||
cp udev-qubes-misc.rules $(DESTDIR)$(SYSLIBDIR)/udev/rules.d/99-qubes-misc.rules
|
||||
cp udev-qubes-dmroot.rules $(DESTDIR)$(SYSLIBDIR)/udev/rules.d/90-qubes-dmroot.rules
|
||||
mkdir -p $(DESTDIR)/etc/udev/rules.d
|
||||
cp udev-qubes-block.rules $(DESTDIR)/etc/udev/rules.d/99-qubes-block.rules
|
||||
cp udev-qubes-usb.rules $(DESTDIR)/etc/udev/rules.d/99-qubes-usb.rules
|
||||
|
||||
mkdir -p $(DESTDIR)$(SCRIPTSDIR)
|
||||
cp udev-block-add-change $(DESTDIR)$(SCRIPTSDIR)
|
||||
cp udev-block-remove $(DESTDIR)$(SCRIPTSDIR)
|
||||
cp udev-usb-add-change $(DESTDIR)$(SCRIPTSDIR)
|
||||
cp udev-usb-remove $(DESTDIR)$(SCRIPTSDIR)
|
||||
mkdir -p $(DESTDIR)/usr/libexec/qubes
|
||||
cp udev-block-add-change $(DESTDIR)/usr/libexec/qubes/
|
||||
cp udev-block-remove $(DESTDIR)/usr/libexec/qubes/
|
||||
cp udev-block-cleanup $(DESTDIR)/usr/libexec/qubes/
|
||||
cp udev-usb-add-change $(DESTDIR)/usr/libexec/qubes/
|
||||
cp udev-usb-remove $(DESTDIR)/usr/libexec/qubes/
|
||||
|
@ -1,145 +1,47 @@
|
||||
#!/bin/bash
|
||||
|
||||
shopt -s nullglob
|
||||
|
||||
|
||||
export LC_CTYPE=en_US.UTF-8
|
||||
NAME=${DEVNAME#/dev/}
|
||||
DESC="`echo "${ID_MODEL} (${ID_FS_LABEL})" | iconv -f utf8 -t ascii//TRANSLIT`"
|
||||
SIZE=$[ $(cat /sys/$DEVPATH/size) * 512 ]
|
||||
MODE=w
|
||||
QDB_KEY="/qubes-block-devices/$NAME"
|
||||
XS_KEY="qubes-block-devices/$NAME"
|
||||
|
||||
xs_remove() {
|
||||
if is_attached /sys$DEVPATH; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if qubesdb-read -q "$QDB_KEY/desc" >/dev/null; then
|
||||
qubesdb-rm "$QDB_KEY/"
|
||||
qubesdb-write /qubes-block-devices ''
|
||||
if [ "$QUBES_EXPOSED" == "1" ]; then
|
||||
xenstore-rm "$XS_KEY"
|
||||
fi
|
||||
echo QUBES_EXPOSED=0
|
||||
}
|
||||
|
||||
is_used() {
|
||||
local sys_devpath=$1
|
||||
local devname=$(grep ^DEVNAME= $sys_devpath/uevent | cut -f 2 -d =)
|
||||
# mounted; or enabled swap
|
||||
if lsblk -dnr -o MOUNTPOINT "/dev/$devname" | grep -q .; then
|
||||
return 0
|
||||
fi
|
||||
# part of other device-mapper
|
||||
if [ -n "`ls -A $sys_devpath/holders 2> /dev/null`" ]; then
|
||||
return 0
|
||||
fi
|
||||
# open device-mapper device
|
||||
if [ -f "$sys_devpath/dm/name" ] && \
|
||||
/sbin/dmsetup info "$(cat $sys_devpath/dm/name)" |\
|
||||
grep -q "^Open count:.*[1-9]"; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
refresh_another() {
|
||||
# launch this script for other device
|
||||
local devpath=$1
|
||||
local launch_env=$(udevadm info -q all -x -p "$devpath" \
|
||||
| grep ^E: | cut -d ' ' -f 2- | tr ' ' ':')
|
||||
env -i PATH=$PATH $launch_env $0
|
||||
}
|
||||
|
||||
is_attached() {
|
||||
dev_hex=$(stat -c %t:%T /dev/$(basename $1))
|
||||
if [ -z "$dev_hex" -o "$dev_hex" = "0:0" ]; then
|
||||
return 1
|
||||
fi
|
||||
# looking at sysfs is much faster than looking at xenstore
|
||||
# this code requires no subprocesses and doesn't hit argument length limitations
|
||||
for i in /sys/bus/xen-backend/drivers/vbd/vbd-*/physical_device; do
|
||||
read i_dev_hex < "$i"
|
||||
if test "$i_dev_hex" == "$dev_hex"; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# update info about parent devices, if any:
|
||||
if [ -f /sys$DEVPATH/partition ]; then
|
||||
parent=$(dirname $(readlink -f /sys$DEVPATH))
|
||||
refresh_another /$(realpath --relative-to=/sys $parent)
|
||||
# if parent device is already attached, skip its partitions
|
||||
if is_attached $parent; then
|
||||
xs_remove
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# and underlying devices of device-mapper (if any)
|
||||
for dev in /sys$DEVPATH/slaves/*; do
|
||||
refresh_another /$(realpath --relative-to=/sys $dev)
|
||||
done
|
||||
|
||||
# cache slave devices for remove event
|
||||
if [ -n "$DM_NAME" ]; then
|
||||
ls -1 /sys$DEVPATH/slaves/ > /var/run/qubes/block-slave-cache-$NAME
|
||||
fi
|
||||
|
||||
# then take care of this device:
|
||||
|
||||
# udev rules already excluded this device:
|
||||
|
||||
if [ "$DM_UDEV_DISABLE_DISK_RULES_FLAG" = "1" ]; then
|
||||
# Ignore mounted...
|
||||
if fgrep -q $DEVNAME /proc/mounts; then
|
||||
xs_remove
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# device itself is already used
|
||||
if is_used /sys$DEVPATH; then
|
||||
# ... and used by device-mapper
|
||||
if [ -n "`ls -A /sys/$DEVPATH/holders 2> /dev/null`" ]; then
|
||||
xs_remove
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# or one of its partitions is used
|
||||
# or already attached (prevent attaching both device and its partition(s) at
|
||||
# the same time)
|
||||
for part in /sys$DEVPATH/$NAME*; do
|
||||
if [ -d $part ]; then
|
||||
if is_used $part || is_attached $part; then
|
||||
xs_remove
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# or "empty" loop device
|
||||
# ... and used device-mapper devices
|
||||
if [ -n "$DM_NAME" ] && /sbin/dmsetup info "$DM_NAME" | grep -q "^Open count:.*[1-9]"; then
|
||||
xs_remove
|
||||
exit 0
|
||||
fi
|
||||
# ... and "empty" loop devices
|
||||
if [ "$MAJOR" -eq 7 -a ! -d /sys/$DEVPATH/loop ]; then
|
||||
xs_remove
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# or unconnected Network Block Device
|
||||
if [ "$MAJOR" -eq 43 -a ! -e /sys/$DEVPATH/pid ]; then
|
||||
# ... and temporary devices used during VM startup
|
||||
if [[ "$NAME" = 'loop'* ]] && \
|
||||
[[ "`cat /sys/block/${NAME%p*}/loop/backing_file`" = \
|
||||
'/var/lib/qubes/'*'/volatile.img' ]]; then
|
||||
xs_remove
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ... and loop devices from excluded directories
|
||||
if [[ "$NAME" = 'loop'* ]]; then
|
||||
backing_file=$(cat /sys/block/${NAME}/loop/backing_file)
|
||||
if [ -n "$backing_file" ]; then
|
||||
dir_to_check=$(dirname "$backing_file")
|
||||
while [ "$dir_to_check" != "/" -a "$dir_to_check" != "." ]; do
|
||||
if [ -e "$dir_to_check/.qubes-exclude-block-devices" ]; then
|
||||
xs_remove
|
||||
exit 0
|
||||
fi
|
||||
dir_to_check=$(dirname "$dir_to_check")
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if device is read-only
|
||||
if [ "`cat /sys/$DEVPATH/ro`" -eq 1 ]; then
|
||||
MODE=r
|
||||
@ -164,12 +66,18 @@ if [ -n "$DM_NAME" ]; then
|
||||
DESC="$DM_NAME"
|
||||
fi
|
||||
|
||||
# The last one is meant to trigger watches
|
||||
qubesdb-write \
|
||||
"$QDB_KEY/desc" "$DESC" \
|
||||
"$QDB_KEY/size" "$SIZE" \
|
||||
"$QDB_KEY/mode" "$MODE" \
|
||||
/qubes-block-devices ''
|
||||
# Get lock only in dom0 - there are so many block devices so it causes xenstore
|
||||
# deadlocks sometimes.
|
||||
if [ -f /etc/qubes-release ]; then
|
||||
# Skip xenstore-write if cannot obtain lock. This can mean very early system startup
|
||||
# stage without /run mounted (or populated). Devices will be rediscovered later
|
||||
# by qubes-core startup script.
|
||||
exec 9>>/var/run/qubes/block-xenstore.lock || exit 0
|
||||
flock 9
|
||||
fi
|
||||
|
||||
xenstore-write "$XS_KEY/desc" "$DESC" "$XS_KEY/size" "$SIZE" "$XS_KEY/mode" "$MODE"
|
||||
echo QUBES_EXPOSED=1
|
||||
|
||||
# Make sure that block backend is loaded
|
||||
/sbin/modprobe xen-blkback 2> /dev/null || /sbin/modprobe blkbk
|
||||
|
8
udev/udev-block-cleanup
Executable file
8
udev/udev-block-cleanup
Executable file
@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
DEVID=$[ $MAJOR * 256 + $MINOR ]
|
||||
|
||||
XS_PATH="device/vbd/$DEVID"
|
||||
|
||||
# Double check that DEVID is not empty
|
||||
[ -n "$DEVID" ] && xenstore-rm $XS_PATH
|
@ -1,16 +1,32 @@
|
||||
#!/bin/sh
|
||||
|
||||
NAME=${DEVNAME#/dev/}
|
||||
QDB_KEY="/qubes-block-devices/$NAME"
|
||||
# Trailing slash is intentional - it will remove the whole directory, instead of
|
||||
# a single base entry
|
||||
qubesdb-rm "$QDB_KEY/"
|
||||
qubesdb-write /qubes-block-devices ''
|
||||
XS_KEY="qubes-block-devices/$NAME"
|
||||
xenstore-rm "$XS_KEY"
|
||||
|
||||
if [ -r /var/run/qubes/block-slave-cache-$NAME ]; then
|
||||
# update info about underlying devices of device-mapper (if any);
|
||||
for dev in $(cat /var/run/qubes/block-slave-cache-$NAME); do
|
||||
udevadm trigger /sys/class/block/$dev
|
||||
# If device was connected to some VM - detach it
|
||||
# Notice: this can be run also in VM, so we cannot use xl...
|
||||
|
||||
device_detach() {
|
||||
xs_path=$1
|
||||
|
||||
xenstore-write $xs_path/online 0 $xs_path/state 5
|
||||
|
||||
# Wait for backend to finish dev shutdown
|
||||
try=30
|
||||
# -lt will break loop also when 'state' will be empty
|
||||
while [ "`xenstore-read $xs_path/state 2> /dev/null`" -lt 6 ]; do
|
||||
try=$[ $try - 1 ]
|
||||
[ "$try" -le 0 ] && break
|
||||
sleep 0.1
|
||||
done
|
||||
rm -f /var/run/qubes/block-slave-cache-$NAME
|
||||
fi
|
||||
xenstore-rm $xs_path
|
||||
}
|
||||
|
||||
for XS_DEV_PATH in `xenstore-ls -f backend/vbd | grep 'backend/vbd/[0-9]*/[0-9]* ' | cut -f 1 -d ' '`; do
|
||||
CUR_DEVICE=`xenstore-read "$XS_DEV_PATH/params"`
|
||||
if [ "$CUR_DEVICE" == "$DEVNAME" ]; then
|
||||
device_detach "$XS_DEV_PATH"
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Expose all (except xen-frontend) block devices via Qubes DB
|
||||
# Expose all (except xen-frontend) block devices via xenstore
|
||||
|
||||
# Only block devices are interesting
|
||||
SUBSYSTEM!="block", GOTO="qubes_block_end"
|
||||
@ -10,16 +10,17 @@ KERNEL=="xvda|xvdb|xvdc*|xvdd", ENV{UDISKS_IGNORE}="1"
|
||||
# Skip xen-blkfront devices
|
||||
ENV{MAJOR}=="202", GOTO="qubes_block_end"
|
||||
|
||||
# skip devices excluded elsewhere
|
||||
ENV{DM_UDEV_DISABLE_DISK_RULES_FLAG}=="1", GOTO="qubes_block_end"
|
||||
|
||||
# Skip device-mapper devices
|
||||
KERNEL=="dm-*", ENV{DM_NAME}=="snapshot-*", GOTO="qubes_block_end"
|
||||
KERNEL=="dm-*", ENV{DM_NAME}=="origin-*", GOTO="qubes_block_end"
|
||||
KERNEL=="dm-*", ENV{DM_NAME}=="", GOTO="qubes_block_end"
|
||||
ENV{MAJOR}=="253", ENV{DM_NAME}=="snapshot-*", GOTO="qubes_block_end"
|
||||
ENV{MAJOR}=="253", ENV{DM_NAME}=="origin-*", GOTO="qubes_block_end"
|
||||
ENV{MAJOR}=="253", ENV{DM_NAME}=="", GOTO="qubes_block_end"
|
||||
|
||||
ACTION=="add", RUN+="/usr/lib/qubes/udev-block-add-change"
|
||||
ACTION=="change", RUN+="/usr/lib/qubes/udev-block-add-change"
|
||||
ACTION=="remove", RUN+="/usr/lib/qubes/udev-block-remove"
|
||||
IMPORT{db}="QUBES_EXPOSED"
|
||||
ACTION=="add", IMPORT{program}="/usr/bin/flock /var/run/qubes-udev.lock -c /usr/libexec/qubes/udev-block-add-change"
|
||||
ACTION=="change", IMPORT{program}="/usr/bin/flock /var/run/qubes-udev.lock -c /usr/libexec/qubes/udev-block-add-change"
|
||||
ACTION=="remove", RUN+="/usr/libexec/qubes/udev-block-remove"
|
||||
|
||||
LABEL="qubes_block_end"
|
||||
|
||||
# Cleanup disconnected frontend from xenstore
|
||||
ACTION=="remove", SUBSYSTEM=="block", ENV{MAJOR}=="202", RUN+="/usr/libexec/qubes/udev-block-cleanup"
|
||||
|
@ -1,5 +0,0 @@
|
||||
# Create /dev/mapper/dmroot symlink on TemplateVM/StandaloneVM to make
|
||||
# grub-mkconfig happy.
|
||||
# On TemplateBasedVM, it is really a device mapper device.
|
||||
|
||||
SUBSYSTEM=="block", ENV{ID_PART_ENTRY_NAME}=="Root\x20filesystem", ATTR{ro}=="0", SYMLINK+="mapper/dmroot"
|
@ -1,7 +0,0 @@
|
||||
# Setup permissions to allow libvchan connections as normal user
|
||||
KERNEL=="xen/evtchn", MODE="0660", GROUP="qubes"
|
||||
KERNEL=="xen/gntdev", MODE="0660", GROUP="qubes"
|
||||
KERNEL=="xen/gntalloc", MODE="0660", GROUP="qubes"
|
||||
KERNEL=="xen/privcmd", MODE="0660", GROUP="qubes"
|
||||
KERNEL=="xen/xenbus", MODE="0660", GROUP="qubes"
|
||||
KERNEL=="xen/hypercall", MODE="0660", GROUP="qubes"
|
@ -1,13 +1,10 @@
|
||||
# Expose all USB devices (except block) via Qubes DB
|
||||
# Expose all USB devices (except block) via xenstore
|
||||
|
||||
# Handle only USB devices
|
||||
SUBSYSTEM!="usb", GOTO="qubes_usb_end"
|
||||
|
||||
# ignore qemu emulated devices in HVM
|
||||
ENV{ID_VENDOR}=="QEMU", GOTO="qubes_usb_end"
|
||||
|
||||
ACTION=="add", IMPORT{program}="/usr/lib/qubes/udev-usb-add-change"
|
||||
ACTION=="change", IMPORT{program}="/usr/lib/qubes/udev-usb-add-change"
|
||||
ACTION=="remove", RUN+="/usr/lib/qubes/udev-usb-remove"
|
||||
ACTION=="add", IMPORT{program}="/usr/libexec/qubes/udev-usb-add-change"
|
||||
ACTION=="change", IMPORT{program}="/usr/libexec/qubes/udev-usb-add-change"
|
||||
ACTION=="remove", RUN+="/usr/libexec/qubes/udev-usb-remove"
|
||||
|
||||
LABEL="qubes_usb_end"
|
||||
|
@ -12,7 +12,7 @@
|
||||
[ "`echo $TYPE | cut -f1 -d/`" = "9" ] && exit 0
|
||||
[ "$DEVTYPE" != "usb_device" ] && exit 0
|
||||
|
||||
# qubesdb doesn't allow dot in key name
|
||||
# xenstore doesn't allow dot in key name
|
||||
XSNAME=`basename ${DEVPATH} | tr . _`
|
||||
|
||||
# FIXME: For some devices (my Cherry keyboard) ID_SERIAL does not
|
||||
@ -21,19 +21,20 @@ XSNAME=`basename ${DEVPATH} | tr . _`
|
||||
#DESC=`python -c "dev='%d-%d' % (int('${BUSNUM}'.lstrip('0')), (int('${DEVNUM}'.lstrip('0'))-1)); from xen.util import vusb_util; print vusb_util.get_usbdevice_info(dev);"`
|
||||
DESC="${ID_VENDOR_ID}:${ID_MODEL_ID} ${ID_SERIAL}"
|
||||
|
||||
VERSION=`cat /sys/$DEVPATH/version | tr -d ' '|cut -f 1 -d .`
|
||||
|
||||
# ignore usbip-connected devices, as most likely already passed through from
|
||||
# another VM
|
||||
if echo $DEVPATH | grep -q /vhci_hcd; then
|
||||
exit 0
|
||||
VERSION=`cat /sys/$DEVPATH/version`
|
||||
if [ "${VERSION}" = " 1.00" -o "${VERSION}" = " 1.10" ] ; then
|
||||
VERSION=1
|
||||
elif [ "${VERSION}" = " 2.00" ] ; then
|
||||
VERSION=2
|
||||
else
|
||||
# FIXME: silently ignoring devices with unexpected USB version
|
||||
exit 0
|
||||
fi
|
||||
|
||||
QDB_KEY="/qubes-usb-devices/$XSNAME"
|
||||
XS_KEY="qubes-usb-devices/$XSNAME"
|
||||
|
||||
qubesdb-write "$QDB_KEY/desc" "$DESC"
|
||||
qubesdb-write "$QDB_KEY/usb-ver" "$VERSION"
|
||||
qubesdb-write /qubes-usb-devices ''
|
||||
xenstore-write "$XS_KEY/desc" "$DESC"
|
||||
xenstore-write "$XS_KEY/usb-ver" "$VERSION"
|
||||
|
||||
# Make sure PVUSB backend driver is loaded.
|
||||
/sbin/modprobe xen-usbback 2> /dev/null || true
|
||||
/sbin/modprobe xen-usbback 2> /dev/null || /sbin/modprobe usbbk
|
||||
|
@ -4,7 +4,6 @@
|
||||
[ "`echo $TYPE | cut -f1 -d/`" = "9" ] && exit 0
|
||||
|
||||
NAME=`basename ${DEVPATH} | tr . _`
|
||||
QDB_KEY="/qubes-usb-devices/$NAME/"
|
||||
XS_KEY="qubes-usb-devices/$NAME"
|
||||
|
||||
qubesdb-rm "$QDB_KEY"
|
||||
qubesdb-write /qubes-usb-devices ''
|
||||
xenstore-rm "$XS_KEY"
|
||||
|
Loading…
Reference in New Issue
Block a user