1#!/bin/sh
2"""": # -*-python-*-
3# https://sourceware.org/bugzilla/show_bug.cgi?id=26034
4export "BUP_ARGV_0"="$0"
5arg_i=1
6for arg in "$@"; do
7    export "BUP_ARGV_${arg_i}"="$arg"
8    shift
9    arg_i=$((arg_i + 1))
10done
11# Here to end of preamble replaced during install
12bup_python="$(dirname "$0")/../../config/bin/python" || exit $?
13exec "$bup_python" "$0"
14"""
15# end of bup preamble
16
17from __future__ import absolute_import
18from subprocess import PIPE
19import getopt, os, signal, struct, subprocess, sys
20
21sys.path[:0] = [os.path.dirname(os.path.realpath(__file__)) + '/..']
22
23from bup import compat, options, ssh, path
24from bup.compat import argv_bytes
25from bup.helpers import DemuxConn, log
26from bup.io import byte_stream
27
28
29optspec = """
30bup on <hostname> index ...
31bup on <hostname> save ...
32bup on <hostname> split ...
33bup on <hostname> get ...
34"""
35o = options.Options(optspec, optfunc=getopt.getopt)
36opt, flags, extra = o.parse(compat.argv[1:])
37if len(extra) < 2:
38    o.fatal('arguments expected')
39
40class SigException(Exception):
41    def __init__(self, signum):
42        self.signum = signum
43        Exception.__init__(self, 'signal %d received' % signum)
44def handler(signum, frame):
45    raise SigException(signum)
46
47signal.signal(signal.SIGTERM, handler)
48signal.signal(signal.SIGINT, handler)
49
50sys.stdout.flush()
51out = byte_stream(sys.stdout)
52
53try:
54    sp = None
55    p = None
56    ret = 99
57
58    hp = argv_bytes(extra[0]).split(b':')
59    if len(hp) == 1:
60        (hostname, port) = (hp[0], None)
61    else:
62        (hostname, port) = hp
63    argv = [argv_bytes(x) for x in extra[1:]]
64    p = ssh.connect(hostname, port, b'on--server', stderr=PIPE)
65
66    try:
67        argvs = b'\0'.join([b'bup'] + argv)
68        p.stdin.write(struct.pack('!I', len(argvs)) + argvs)
69        p.stdin.flush()
70        sp = subprocess.Popen([path.exe(), b'server'],
71                              stdin=p.stdout, stdout=p.stdin)
72        p.stdin.close()
73        p.stdout.close()
74        # Demultiplex remote client's stderr (back to stdout/stderr).
75        dmc = DemuxConn(p.stderr.fileno(), open(os.devnull, "wb"))
76        for line in iter(dmc.readline, b''):
77            out.write(line)
78    finally:
79        while 1:
80            # if we get a signal while waiting, we have to keep waiting, just
81            # in case our child doesn't die.
82            try:
83                ret = p.wait()
84                if sp:
85                    sp.wait()
86                break
87            except SigException as e:
88                log('\nbup on: %s\n' % e)
89                os.kill(p.pid, e.signum)
90                ret = 84
91except SigException as e:
92    if ret == 0:
93        ret = 99
94    log('\nbup on: %s\n' % e)
95
96sys.exit(ret)
97