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