]> arthur.barton.de Git - bup.git/blob - lib/cmd/on-cmd.py
fd89da4e8bc51c9653f1b2aa968a75c1fa9c25d6
[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 sys, os, struct, getopt, subprocess, signal
20
21 from bup import compat, options, ssh, path
22 from bup.compat import argv_bytes
23 from bup.helpers import DemuxConn, log
24 from bup.io import byte_stream
25
26
27 optspec = """
28 bup on <hostname> index ...
29 bup on <hostname> save ...
30 bup on <hostname> split ...
31 bup on <hostname> get ...
32 """
33 o = options.Options(optspec, optfunc=getopt.getopt)
34 opt, flags, extra = o.parse(compat.argv[1:])
35 if len(extra) < 2:
36     o.fatal('arguments expected')
37
38 class SigException(Exception):
39     def __init__(self, signum):
40         self.signum = signum
41         Exception.__init__(self, 'signal %d received' % signum)
42 def handler(signum, frame):
43     raise SigException(signum)
44
45 signal.signal(signal.SIGTERM, handler)
46 signal.signal(signal.SIGINT, handler)
47
48 sys.stdout.flush()
49 out = byte_stream(sys.stdout)
50
51 try:
52     sp = None
53     p = None
54     ret = 99
55
56     hp = argv_bytes(extra[0]).split(b':')
57     if len(hp) == 1:
58         (hostname, port) = (hp[0], None)
59     else:
60         (hostname, port) = hp
61     argv = [argv_bytes(x) for x in extra[1:]]
62     p = ssh.connect(hostname, port, b'on--server', stderr=PIPE)
63
64     try:
65         argvs = b'\0'.join([b'bup'] + argv)
66         p.stdin.write(struct.pack('!I', len(argvs)) + argvs)
67         p.stdin.flush()
68         sp = subprocess.Popen([path.exe(), b'server'],
69                               stdin=p.stdout, stdout=p.stdin)
70         p.stdin.close()
71         p.stdout.close()
72         # Demultiplex remote client's stderr (back to stdout/stderr).
73         dmc = DemuxConn(p.stderr.fileno(), open(os.devnull, "wb"))
74         for line in iter(dmc.readline, b''):
75             out.write(line)
76     finally:
77         while 1:
78             # if we get a signal while waiting, we have to keep waiting, just
79             # in case our child doesn't die.
80             try:
81                 ret = p.wait()
82                 if sp:
83                     sp.wait()
84                 break
85             except SigException as e:
86                 log('\nbup on: %s\n' % e)
87                 os.kill(p.pid, e.signum)
88                 ret = 84
89 except SigException as e:
90     if ret == 0:
91         ret = 99
92     log('\nbup on: %s\n' % e)
93
94 sys.exit(ret)