
This should allow importing a volume and changing the size at the same time, without performing the resize operation on original volume first. The internal API has been renamed to internal.vm.volume.ImportBegin to avoid confusion, and for symmetry with ImportEnd. See QubesOS/qubes-issues#5239.
72 lines
2.6 KiB
Bash
Executable File
72 lines
2.6 KiB
Bash
Executable File
#!/bin/sh
|
|
#
|
|
# This Admin API call is implemented as a custom script, instead of dumb
|
|
# passthrough to qubesd because it may get huge amount of data (whole root.img
|
|
# for example). qubesd cannot handle it because:
|
|
# 1. It loads the whole payload into memory, before even start looking at it
|
|
# (and later, do not allow to modify/append it).
|
|
# 2. There is 64kB limit on payload size that qubesd can handle (because of
|
|
# point 1).
|
|
# 3. Performance reasons (qubesd is not optimized for performance, passing
|
|
# such large data stream through it would take ages).
|
|
#
|
|
# The whole admin.vm.volume.Import consists of:
|
|
# 1. Permissions checks, getting a path from appropriate storage pool (done
|
|
# by qubesd)
|
|
# 2. Actual data import (done by this script, using dd)
|
|
# 3. Report final result, produce final response to the caller (done by
|
|
# qubesd)
|
|
#
|
|
# This way we do not pass all the data through qubesd, but still can
|
|
# control the process from there in a meaningful way. Note that the last
|
|
# part (second call to qubesd) may perform all kind of verification (like
|
|
# a signature check on the data, or so) and can also prevent VM from
|
|
# starting (hooking also domain-pre-start event) from not verified image.
|
|
#
|
|
# Note that this script implements two calls:
|
|
# - admin.vm.volume.Import
|
|
# - admin.vm.volume.ImportWithSize
|
|
# In the case of admin.vm.ImportWithSize, the first line of payload is then
|
|
# data size in bytes. This is so that we can already notify qubesd to create a
|
|
# volume with the new size.
|
|
|
|
set -e
|
|
|
|
# use temporary file, because env variables deal poorly with \0 inside
|
|
tmpfile=$(mktemp)
|
|
trap "rm -f $tmpfile" EXIT
|
|
|
|
requested_size=""
|
|
if [[ ${0##*/} == admin.vm.volume.ImportWithSize ]]; then
|
|
read requested_size
|
|
fi
|
|
|
|
echo -n "$requested_size" | qubesd-query -c /var/run/qubesd.internal.sock \
|
|
"$QREXEC_REMOTE_DOMAIN" \
|
|
"internal.vm.volume.ImportBegin" \
|
|
"$QREXEC_REQUESTED_TARGET" \
|
|
"$1" >$tmpfile
|
|
|
|
# exit if qubesd returned an error (not '0\0')
|
|
if [ "$(head -c 2 $tmpfile | xxd -p)" != "3000" ]; then
|
|
cat "$tmpfile"
|
|
exit 1
|
|
fi
|
|
size=$(tail -c +3 "$tmpfile"|cut -d ' ' -f 1)
|
|
path=$(tail -c +3 "$tmpfile"|cut -d ' ' -f 2)
|
|
|
|
# now process stdin into this path
|
|
if sudo dd bs=128K of="$path" count="$size" iflag=count_bytes,fullblock \
|
|
conv=sparse,notrunc,nocreat,fdatasync status=none; then
|
|
status="ok"
|
|
else
|
|
status="fail"
|
|
fi
|
|
|
|
# send status notification to qubesd, and pass its response to the caller
|
|
echo -n "$status" | qubesd-query -c /var/run/qubesd.internal.sock \
|
|
"$QREXEC_REMOTE_DOMAIN" \
|
|
"internal.vm.volume.ImportEnd" \
|
|
"$QREXEC_REQUESTED_TARGET" \
|
|
"$1"
|