From 93e5b749fd20ae7c3ce879057e469f09cd2dcd04 Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Tue, 29 Mar 2011 13:05:57 +0200 Subject: [PATCH 1/7] qfile-copy: try to produce only one error message --- appvm/copy_file.c | 22 +++++++++++++++++----- appvm/filecopy.h | 24 ++++++++++++++++-------- appvm/qfile-agent.c | 18 ++++++++++++------ appvm/qvm-copy-to-vm2.kde | 7 ++++--- appvm/unpack.c | 15 ++++++++++----- 5 files changed, 59 insertions(+), 27 deletions(-) diff --git a/appvm/copy_file.c b/appvm/copy_file.c index 5f7fc793..9e65c652 100644 --- a/appvm/copy_file.c +++ b/appvm/copy_file.c @@ -1,8 +1,10 @@ #include #include +#include "filecopy.h" + extern void notify_progress(int, int); -char * copy_file(int outfd, int infd, long long size) +int copy_file(int outfd, int infd, long long size) { char buf[4096]; long long written = 0; @@ -15,14 +17,24 @@ char * copy_file(int outfd, int infd, long long size) count = size - written; ret = read(infd, buf, count); if (!ret) - return("EOF while reading file"); + return COPY_FILE_READ_EOF; if (ret < 0) - return("error reading file"); + return COPY_FILE_READ_ERROR; if (!write_all(outfd, buf, ret)) - return("error writing file content"); + return COPY_FILE_WRITE_ERROR; notify_progress(ret, 0); written += ret; } - return NULL; + return COPY_FILE_OK; } +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 "????????"; + } +} diff --git a/appvm/filecopy.h b/appvm/filecopy.h index b4f6638c..1fcd2d04 100644 --- a/appvm/filecopy.h +++ b/appvm/filecopy.h @@ -6,13 +6,21 @@ #define LEGAL_EOF 31415926 struct file_header { -unsigned int namelen; -unsigned int mode; -unsigned long long filelen; -unsigned int atime; -unsigned int atime_nsec; -unsigned int mtime; -unsigned int 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; }; -char * copy_file(int outfd, int infd, long long size); +enum { + COPY_FILE_OK, + COPY_FILE_READ_EOF, + COPY_FILE_READ_ERROR, + COPY_FILE_WRITE_ERROR +}; + +int copy_file(int outfd, int infd, long long size); +char *copy_file_status_to_str(int status); diff --git a/appvm/qfile-agent.c b/appvm/qfile-agent.c index f7e27a98..e33b61c6 100644 --- a/appvm/qfile-agent.c +++ b/appvm/qfile-agent.c @@ -50,7 +50,7 @@ void write_headers(struct file_header *hdr, char *filename) { if (!write_all(1, hdr, sizeof(*hdr)) || !write_all(1, filename, hdr->namelen)) - gui_fatal("writing file headers to remove AppVM"); + exit(1); } int single_file_processor(char *filename, struct stat *st) @@ -67,15 +67,21 @@ int single_file_processor(char *filename, struct stat *st) hdr.mtime_nsec = st->st_mtim.tv_nsec; if (S_ISREG(mode)) { - char *ret; + int ret; fd = open(filename, O_RDONLY); if (!fd) gui_fatal("open %s", filename); hdr.filelen = st->st_size; write_headers(&hdr, filename); ret = copy_file(1, fd, hdr.filelen); - if (ret) - gui_fatal("Copying file %s: %s", filename, ret); + // if COPY_FILE_WRITE_ERROR, hopefully remote will produce a message + if (ret != COPY_FILE_OK) { + if (ret != COPY_FILE_WRITE_ERROR) + gui_fatal("Copying file %s: %s", filename, + copy_file_status_to_str(ret)); + else + exit(1); + } close(fd); } if (S_ISDIR(mode)) { @@ -89,7 +95,7 @@ int single_file_processor(char *filename, struct stat *st) hdr.filelen = st->st_size + 1; write_headers(&hdr, filename); if (!write_all(1, name, st->st_size + 1)) - gui_fatal("write to remote VM"); + exit(1); } return 0; } @@ -130,7 +136,7 @@ void send_vmname(char *vmname) memset(buf, 0, sizeof(buf)); strncat(buf, vmname, sizeof(buf) - 1); if (!write_all(1, buf, sizeof buf)) - gui_fatal("writing vmname to remote VM"); + exit(1); } char *get_item(char *data, char **current, int size) diff --git a/appvm/qvm-copy-to-vm2.kde b/appvm/qvm-copy-to-vm2.kde index 879279be..de28feec 100755 --- a/appvm/qvm-copy-to-vm2.kde +++ b/appvm/qvm-copy-to-vm2.kde @@ -43,6 +43,7 @@ done qdbus $REF close rm -f $PROGRESS_FILE -if ! [ "x"$agentstatus = xDONE ] ; then - kdialog --sorry 'Abnormal file copy termination; see /var/log/qubes/qrexec.xid.log in dom0 for more details' -fi +# we do not want a dozen error messages, do we +# if ! [ "x"$agentstatus = xDONE ] ; then +# kdialog --sorry 'Abnormal file copy termination; see /var/log/qubes/qrexec.xid.log in dom0 for more details' +# fi diff --git a/appvm/unpack.c b/appvm/unpack.c index ad53ebf5..eaa1744c 100644 --- a/appvm/unpack.c +++ b/appvm/unpack.c @@ -38,14 +38,19 @@ void fix_times_and_perms(struct file_header *hdr, char *name) void process_one_file_reg(struct file_header *hdr, char *name) { - char *ret; + int ret; int fdout = open(name, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0700); if (fdout < 0) do_exit(errno); ret = copy_file(fdout, 0, hdr->filelen); - if (ret) - do_exit(errno); + if (ret != COPY_FILE_OK) { + if (ret == COPY_FILE_READ_EOF + || ret == COPY_FILE_READ_ERROR) + do_exit(LEGAL_EOF); // hopefully remote will produce error message + else + do_exit(errno); + } close(fdout); fix_times_and_perms(hdr, name); } @@ -68,7 +73,7 @@ void process_one_file_link(struct file_header *hdr, char *name) if (hdr->filelen > MAX_PATH_LENGTH - 1) do_exit(ENAMETOOLONG); if (!read_all(0, content, hdr->filelen)) - do_exit(errno); + do_exit(LEGAL_EOF); // hopefully remote has produced error message content[hdr->filelen] = 0; if (symlink(content, name)) do_exit(errno); @@ -80,7 +85,7 @@ void process_one_file(struct file_header *hdr) if (hdr->namelen > MAX_PATH_LENGTH - 1) do_exit(ENAMETOOLONG); if (!read_all(0, namebuf, hdr->namelen)) - do_exit(errno); + do_exit(LEGAL_EOF); // hopefully remote has produced error message namebuf[hdr->namelen] = 0; if (S_ISREG(hdr->mode)) process_one_file_reg(hdr, namebuf); From 7ac754eb636b9eceb0d162307df513453bdbce57 Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Wed, 30 Mar 2011 10:28:25 +0200 Subject: [PATCH 2/7] qvm-copy-to-vm2.kde: prepare for a race in PROGRESS_FILE creation Apparently a tight race may happen when PROGRESS_FILE has been created, but not yet written to by qfile-agent. Check if its content are sane before use. --- appvm/qvm-copy-to-vm2.kde | 1 + 1 file changed, 1 insertion(+) diff --git a/appvm/qvm-copy-to-vm2.kde b/appvm/qvm-copy-to-vm2.kde index de28feec..4c477534 100755 --- a/appvm/qvm-copy-to-vm2.kde +++ b/appvm/qvm-copy-to-vm2.kde @@ -34,6 +34,7 @@ while ! [ -s $PROGRESS_FILE ] ; do done while true ; do read agentpid sentsize agentstatus < $PROGRESS_FILE + if [ "x"$agentstatus = x ] ; then continue ; fi if ! [ -e /proc/$agentpid ] ; then break ; fi if [ "x"$agentstatus = xdone ] ; then break ; fi CURRSIZE=$(($sentsize/1024)) From fab96d222511daae3b1aabe10c8378b260b4ec58 Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Wed, 30 Mar 2011 10:30:27 +0200 Subject: [PATCH 3/7] qvm-copy-to-vm2.kde: calculate size of sparse files correctly --- appvm/qvm-copy-to-vm2.kde | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appvm/qvm-copy-to-vm2.kde b/appvm/qvm-copy-to-vm2.kde index 4c477534..2ccf73a9 100755 --- a/appvm/qvm-copy-to-vm2.kde +++ b/appvm/qvm-copy-to-vm2.kde @@ -23,7 +23,7 @@ VM=$(kdialog -inputbox "Enter the VM name to send files to:") if [ X$VM = X ] ; then exit 0 ; fi -SIZE=$(du -c "$@" | tail -1 | cut -f 1) +SIZE=$(du --apparent-size -c "$@" | tail -1 | cut -f 1) REF=$(kdialog --progressbar "Copy progress") qdbus $REF org.freedesktop.DBus.Properties.Set "" maximum $SIZE From 9e9fd4c9bac77b2ce25b2aa5fd8adebda4a934a3 Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Wed, 30 Mar 2011 12:37:47 +0200 Subject: [PATCH 4/7] core-appvm.spec: create /home/user/.gnome2/nautilus-scripts And symlinks in it that will be visible in "scripts" context menu of nautilus. --- rpm_spec/core-appvm.spec | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rpm_spec/core-appvm.spec b/rpm_spec/core-appvm.spec index f5b8fa0f..5f847d33 100644 --- a/rpm_spec/core-appvm.spec +++ b/rpm_spec/core-appvm.spec @@ -54,6 +54,9 @@ exit 0 fi adduser --create-home user +su user -c 'mkdir -p /home/user/.gnome2/nautilus-scripts' +su user -c 'ln -s /usr/lib/qubes/qvm-copy-to-vm2.kde /home/user/.gnome2/nautilus-scripts/"Copy to other AppVM"' +su user -c 'ln -s /usr/bin/qvm-open-in-dvm2 /home/user/.gnome2/nautilus-scripts/"Open in DisposableVM"' mkdir -p $RPM_BUILD_ROOT/var/lib/qubes From 8e2aa6c8252870508f6d8d803ea3d60d85e292d5 Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Wed, 30 Mar 2011 16:48:48 +0200 Subject: [PATCH 5/7] Renamed qvm-copy-to-vm2 to qvm-trigger-copy-to-vm The new name describes the task of the script better. --- appvm/qvm-copy-to-vm2.kde | 2 +- appvm/{qvm-copy-to-vm2 => qvm-trigger-copy-to-vm} | 0 rpm_spec/core-appvm.spec | 4 ++-- 3 files changed, 3 insertions(+), 3 deletions(-) rename appvm/{qvm-copy-to-vm2 => qvm-trigger-copy-to-vm} (100%) diff --git a/appvm/qvm-copy-to-vm2.kde b/appvm/qvm-copy-to-vm2.kde index 2ccf73a9..7600bb56 100755 --- a/appvm/qvm-copy-to-vm2.kde +++ b/appvm/qvm-copy-to-vm2.kde @@ -28,7 +28,7 @@ REF=$(kdialog --progressbar "Copy progress") qdbus $REF org.freedesktop.DBus.Properties.Set "" maximum $SIZE export PROGRESS_FILE=$(mktemp) -qvm-copy-to-vm2 $VM "$@" +/usr/lib/qubes/qvm-trigger-copy-to-vm $VM "$@" while ! [ -s $PROGRESS_FILE ] ; do sleep 0.1 done diff --git a/appvm/qvm-copy-to-vm2 b/appvm/qvm-trigger-copy-to-vm similarity index 100% rename from appvm/qvm-copy-to-vm2 rename to appvm/qvm-trigger-copy-to-vm diff --git a/rpm_spec/core-appvm.spec b/rpm_spec/core-appvm.spec index 5f847d33..666c5710 100644 --- a/rpm_spec/core-appvm.spec +++ b/rpm_spec/core-appvm.spec @@ -74,9 +74,9 @@ cp qubes_core_appvm $RPM_BUILD_ROOT/etc/init.d/ mkdir -p $RPM_BUILD_ROOT/var/lib/qubes mkdir -p $RPM_BUILD_ROOT/usr/bin cp qubes_timestamp qvm-open-in-dvm2 $RPM_BUILD_ROOT/usr/bin -cp qvm-copy-to-vm2 $RPM_BUILD_ROOT/usr/bin mkdir -p $RPM_BUILD_ROOT/usr/lib/qubes cp qvm-copy-to-vm2.kde $RPM_BUILD_ROOT/usr/lib/qubes +cp qvm-trigger-copy-to-vm $RPM_BUILD_ROOT/usr/lib/qubes cp ../qrexec/qrexec_agent $RPM_BUILD_ROOT/usr/lib/qubes cp dvm_file_editor qfile-agent qfile-agent-dvm qfile-unpacker $RPM_BUILD_ROOT/usr/lib/qubes cp ../common/meminfo-writer $RPM_BUILD_ROOT/usr/lib/qubes @@ -126,13 +126,13 @@ rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root,-) /etc/init.d/qubes_core_appvm -/usr/bin/qvm-copy-to-vm2 /usr/lib/qubes/qvm-copy-to-vm2.kde /usr/bin/qvm-open-in-dvm2 /usr/lib/qubes/meminfo-writer /usr/lib/qubes/dvm_file_editor %{kde_service_dir}/qvm-copy.desktop %{kde_service_dir}/qvm-dvm.desktop +/usr/lib/qubes/qvm-trigger-copy-to-vm /usr/lib/qubes/qrexec_agent /usr/lib/qubes/qfile-agent /usr/lib/qubes/qfile-agent-dvm From 6104af2b2c12b10e3c18c6ba63a69360adb26b06 Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Wed, 30 Mar 2011 17:25:57 +0200 Subject: [PATCH 6/7] Implemented console qvm-copy-to-vm It waits for the copy to finish, and is capable of killer progress indicator. --- rpm_spec/core-appvm.spec | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rpm_spec/core-appvm.spec b/rpm_spec/core-appvm.spec index 666c5710..5b4005b0 100644 --- a/rpm_spec/core-appvm.spec +++ b/rpm_spec/core-appvm.spec @@ -74,6 +74,7 @@ cp qubes_core_appvm $RPM_BUILD_ROOT/etc/init.d/ mkdir -p $RPM_BUILD_ROOT/var/lib/qubes mkdir -p $RPM_BUILD_ROOT/usr/bin cp qubes_timestamp qvm-open-in-dvm2 $RPM_BUILD_ROOT/usr/bin +cp qvm-copy-to-vm $RPM_BUILD_ROOT/usr/bin mkdir -p $RPM_BUILD_ROOT/usr/lib/qubes cp qvm-copy-to-vm2.kde $RPM_BUILD_ROOT/usr/lib/qubes cp qvm-trigger-copy-to-vm $RPM_BUILD_ROOT/usr/lib/qubes @@ -126,6 +127,7 @@ rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root,-) /etc/init.d/qubes_core_appvm +/usr/bin/qvm-copy-to-vm /usr/lib/qubes/qvm-copy-to-vm2.kde /usr/bin/qvm-open-in-dvm2 /usr/lib/qubes/meminfo-writer From 7753d26dd826d00b5b04f15de80e10aa7f72e402 Mon Sep 17 00:00:00 2001 From: Rafal Wojtczuk Date: Wed, 30 Mar 2011 17:27:04 +0200 Subject: [PATCH 7/7] Actually add appvm/qvm-copy-to-vm --- appvm/qvm-copy-to-vm | 69 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100755 appvm/qvm-copy-to-vm diff --git a/appvm/qvm-copy-to-vm b/appvm/qvm-copy-to-vm new file mode 100755 index 00000000..4817b43b --- /dev/null +++ b/appvm/qvm-copy-to-vm @@ -0,0 +1,69 @@ +#!/bin/sh +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2010 Rafal Wojtczuk +# +# 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. +# +# + +if [ x"$1" = "x--with-progress" ] ; then + DO_PROGRESS=1 + shift +else + DO_PROGRESS=0 +fi + +if [ $# -lt 2 ] ; then + echo usage: $0 '[--with-progress] dest_vmname file [file]+' + exit 1 +fi + +VM="$1" +shift + +if [ $DO_PROGRESS = 1 ] ; then + SIZE=$(du --apparent-size -c "$@" | tail -1 | cut -f 1) +fi + +export PROGRESS_FILE=$(mktemp) +/usr/lib/qubes/qvm-trigger-copy-to-vm $VM "$@" +while ! [ -s $PROGRESS_FILE ] ; do + sleep 0.1 +done + +while true ; do + read agentpid sentsize agentstatus < $PROGRESS_FILE + if [ "x"$agentstatus = x ] ; then continue ; fi + if ! [ -e /proc/$agentpid ] ; then break ; fi + if [ "x"$agentstatus = xdone ] ; then break ; fi + CURRSIZE=$(($sentsize/1024)) + if [ $DO_PROGRESS = 1 ] ; then + echo -ne "\r sent $CURRSIZE/$SIZE KB " + fi + sleep 0.4 +done + +rm -f $PROGRESS_FILE +if [ $DO_PROGRESS = 1 ] ; then + echo +fi + +if ! [ "x"$agentstatus = xDONE ] ; then + exit 1 +else + exit 0 +fi