]> arthur.barton.de Git - bup.git/blob - lib/cmd/on-cmd.py
0644a46a4e6cdc58abd1c3d6216ffd940eb8dec1
[bup.git] / lib / cmd / on-cmd.py
1 #!/bin/sh
2 """": # -*-python-*-
3 # https://sourceware.org/bugzilla/show_bug.cgi?id=26034
4 export "BUP_ARGV_0"="$0"
5 arg_i=1
6 for arg in "$@"; do
7     export "BUP_ARGV_${arg_i}"="$arg"
8     shift
9     arg_i=$((arg_i + 1))
10 done
11 # Here to end of preamble replaced during install
12 bup_python="$(dirname "$0")/bup-python" || exit $?
13 exec "$bup_python" "$0"
14 """
15 # end of bup preamble
16
17 from __future__ import absolute_import
18 from subprocess import PIPE
19 import getopt, os, signal, struct, subprocess, sys
20
21 sys.path[:0] = [os.path.dirname(os.path.realpath(__file__)) + '/..']
22
23 from bup import compat, options, ssh, path
24 from bup.compat import argv_bytes
25 from bup.helpers import DemuxConn, log
26 from bup.io import byte_stream
27
28
29 optspec = """
30 bup on <hostname> index ...
31 bup on <hostname> save ...
32 bup on <hostname> split ...
33 bup on <hostname> get ...
34 """
35 o = options.Options(optspec, optfunc=getopt.getopt)
36 opt, flags, extra = o.parse(compat.argv[1:])
37 if len(extra) < 2:
38     o.fatal('arguments expected')
39
40 class SigException(Exception):
41     def __init__(self, signum):
42         self.signum = signum
43         Exception.__init__(self, 'signal %d received' % signum)
44 def handler(signum, frame):
45     raise SigException(signum)
46
47 signal.signal(signal.SIGTERM, handler)
48 signal.signal(signal.SIGINT, handler)
49
50 sys.stdout.flush()
51 out = byte_stream(sys.stdout)
52
53 try:
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
91 except SigException as e:
92     if ret == 0:
93         ret = 99
94     log('\nbup on: %s\n' % e)
95
96 sys.exit(ret)