import os, shutil, sys
import configparser
import hashlib
-import subprocess
+import subprocess, fcntl
import random, re
import logging
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) + ".")
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:
print(" -m, --mode <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")