From 54f08e00b9dad3dab1eff38d5c5dd04852fdba13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Sat, 9 Nov 2013 17:09:44 +0100 Subject: [PATCH] backup: fix race condition with inner tar process Do not assume that tar will finish quickly - explicitly wait for either process termination or request for the next archive part. --- core/qubesutils.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/core/qubesutils.py b/core/qubesutils.py index d9b751d4..4fd3ed1a 100644 --- a/core/qubesutils.py +++ b/core/qubesutils.py @@ -1342,6 +1342,7 @@ def restore_vm_dirs (backup_dir, backup_tmpdir, passphrase, vms_dirs, vms, vms_s self.print_callback("Extracting file "+filename+" to "+system_path["qubes_base_dir"]) + pipe = open(self.restore_pipe,'r+b') if self.tar2_command == None: # FIXME: Make the extraction safer by avoiding to erase other vms: # - extracting directly to the target directory (based on the vm name and by using the --strip=2). @@ -1349,9 +1350,8 @@ def restore_vm_dirs (backup_dir, backup_tmpdir, passphrase, vms_dirs, vms, vms_s # marmarek: use other (local) variable for command line self.tar2_command = ['tar', '--tape-length','1000000', '-C', system_path["qubes_base_dir"], '-xvf', self.restore_pipe] self.print_callback("Running command "+str(self.tar2_command)) - self.tar2_command = subprocess.Popen(self.tar2_command,stdin=subprocess.PIPE) + self.tar2_command = subprocess.Popen(self.tar2_command, stdin=subprocess.PIPE, stderr=subprocess.PIPE) - pipe = open(self.restore_pipe,'r+b') if self.encrypted: # Start decrypt encryptor = subprocess.Popen (["openssl", "enc", "-d", "-aes-256-cbc", "-pass", "pass:"+passphrase], stdin=open(filename,'rb'), stdout=subprocess.PIPE) @@ -1364,11 +1364,13 @@ def restore_vm_dirs (backup_dir, backup_tmpdir, passphrase, vms_dirs, vms, vms_s pipe.close() - self.print_callback("Run error:"+run_error) - self.print_callback(str(self.tar2_command.poll())) - - if self.tar2_command.poll() != None: - if self.tar2_command.poll() != 0: + # tar2 input closed, wait for either it finishes, or prompt for the next + # file part; in both cases we can use read() on stderr - in the former case + # it will return "" (EOF) + tar2_stderr=self.tar2_command.stderr.readline() + if tar2_stderr == "": + # EOF, so collect process exit status + if self.tar2_command.wait() != 0: raise QubesException("ERROR: unable to extract files for {0}.".format(filename)) else: # Finished extracting the tar file