From 5f6d53f2948a9ae6fc15c457d58642a7d1489271 Mon Sep 17 00:00:00 2001 From: Stefan Huber Date: Tue, 15 May 2012 11:15:51 +0200 Subject: [PATCH] Fix blocking bug of tar's output --- shbackup | 44 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/shbackup b/shbackup index 4165869..d5b8b81 100755 --- a/shbackup +++ b/shbackup @@ -8,7 +8,7 @@ import datetime import os, shutil, sys import configparser import hashlib -import subprocess +import subprocess, fcntl import random, re import logging @@ -269,26 +269,46 @@ class BackupManager: for pat in self.conf.exclpatterns: taropts += ["--exclude", pat] + # Launch the tar process tarargs = [tarpath] + taropts + ["-f", fsfn] + fileset.dirs logfile.debug("tar call: " + " ".join(tarargs)) tarp = subprocess.Popen( tarargs, bufsize=-1, \ stdout=subprocess.PIPE, stderr=subprocess.PIPE ) - # Output stdout of tar + # Change tarp's stdout and stderr to non-blocking + for s in [tarp.stdout, tarp.stderr]: + fd = s.fileno() + fl = fcntl.fcntl(fd, fcntl.F_GETFL) + fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK) + + def readlineNonBlocking(stream): + """Read a line nonblocking. Returns b'' if nothing read.""" + try: + return stream.readline() + except: + return b'' + pass + + + # Read stdout and stderr of tarp + errmsg = b"" while tarp.poll() == None: - l = tarp.stdout.readline() - if l != "": - logging.debug(l.decode().rstrip()) + l = readlineNonBlocking(tarp.stdout) + if l != b"": + logging.debug(l[:-1].decode()) + errmsg += readlineNonBlocking(tarp.stderr) - # Output remaining output of tar + + # Get the remainging output of tarp for l in tarp.stdout.readlines(): logging.debug(l.decode().rstrip()) + errmsg += tarp.stderr.read() + # Get return code of tarp rett = tarp.wait() if rett != 0: - for l in tarp.stderr.readlines(): + for l in errmsg.split("\n"): logfile.error( l.decode().strip().rstrip() ) - sys.stderr.write( tarp.stderr.read().decode() ) logfile.error(tarpath + " returned with exit status " + str(rett) + ".") @@ -415,7 +435,11 @@ class BackupManager: yesno = self.ask_user_yesno("Remove entries marked by '*'? [y, N] ") if yesno == "y": for d in removeDirs: - shutil.rmtree(os.path.join(basedir, d)) + try: + shutil.rmtree(os.path.join(basedir, d)) + except OSError as e: + logging.error("Error when removing '%s': %s" % (d,e.strerror) ) + def ask_user_yesno(self, question): if LogConf.con.level <= logging.INFO: @@ -447,7 +471,7 @@ def printUsage(): print(" -m, --mode override mode: full, diff, or incr") print(" -v, --verbose be more verbose and interact with user") print(" --verbosity LEVEL set verbosity to LEVEL, which can be") - print(" warning, info, debug") + print(" error, warning, info, debug") print(" -V, --version print version info") -- 2.30.2