3 # https://sourceware.org/bugzilla/show_bug.cgi?id=26034
4 export "BUP_ARGV_0"="$0"
7 export "BUP_ARGV_${arg_i}"="$arg"
11 # Here to end of preamble replaced during install
12 bup_python="$(dirname "$0")/../../config/bin/python" || exit $?
13 exec "$bup_python" "$0"
17 from __future__ import absolute_import
19 # Intentionally replace the dirname "$0" that python prepends
21 sys.path[0] = os.path.dirname(os.path.realpath(__file__)) + '/..'
23 from subprocess import PIPE
24 import getopt, signal, struct, subprocess
26 from bup import compat, options, ssh, path
27 from bup.compat import argv_bytes
28 from bup.helpers import DemuxConn, log
29 from bup.io import byte_stream
33 bup on <hostname> index ...
34 bup on <hostname> save ...
35 bup on <hostname> split ...
36 bup on <hostname> get ...
38 o = options.Options(optspec, optfunc=getopt.getopt)
39 opt, flags, extra = o.parse(compat.argv[1:])
41 o.fatal('arguments expected')
43 class SigException(Exception):
44 def __init__(self, signum):
46 Exception.__init__(self, 'signal %d received' % signum)
47 def handler(signum, frame):
48 raise SigException(signum)
50 signal.signal(signal.SIGTERM, handler)
51 signal.signal(signal.SIGINT, handler)
54 out = byte_stream(sys.stdout)
61 hp = argv_bytes(extra[0]).split(b':')
63 (hostname, port) = (hp[0], None)
66 argv = [argv_bytes(x) for x in extra[1:]]
67 p = ssh.connect(hostname, port, b'on--server', stderr=PIPE)
70 argvs = b'\0'.join([b'bup'] + argv)
71 p.stdin.write(struct.pack('!I', len(argvs)) + argvs)
73 sp = subprocess.Popen([path.exe(), b'server'],
74 stdin=p.stdout, stdout=p.stdin)
77 # Demultiplex remote client's stderr (back to stdout/stderr).
78 dmc = DemuxConn(p.stderr.fileno(), open(os.devnull, "wb"))
79 for line in iter(dmc.readline, b''):
83 # if we get a signal while waiting, we have to keep waiting, just
84 # in case our child doesn't die.
90 except SigException as e:
91 log('\nbup on: %s\n' % e)
92 os.kill(p.pid, e.signum)
94 except SigException as e:
97 log('\nbup on: %s\n' % e)