]> arthur.barton.de Git - bup.git/blob - lib/cmd/on-cmd.py
prune-older-cmd: copy to bup.cmd.prune_older
[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")/../../config/bin/python" || exit $?
13 exec "$bup_python" "$0"
14 """
15 # end of bup preamble
16
17 from __future__ import absolute_import
18
19 # Intentionally replace the dirname "$0" that python prepends
20 import os, sys
21 sys.path[0] = os.path.dirname(os.path.realpath(__file__)) + '/..'
22
23 from subprocess import PIPE
24 import getopt, signal, struct, subprocess
25
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
30
31
32 optspec = """
33 bup on <hostname> index ...
34 bup on <hostname> save ...
35 bup on <hostname> split ...
36 bup on <hostname> get ...
37 """
38 o = options.Options(optspec, optfunc=getopt.getopt)
39 opt, flags, extra = o.parse(compat.argv[1:])
40 if len(extra) < 2:
41     o.fatal('arguments expected')
42
43 class SigException(Exception):
44     def __init__(self, signum):
45         self.signum = signum
46         Exception.__init__(self, 'signal %d received' % signum)
47 def handler(signum, frame):
48     raise SigException(signum)
49
50 signal.signal(signal.SIGTERM, handler)
51 signal.signal(signal.SIGINT, handler)
52
53 sys.stdout.flush()
54 out = byte_stream(sys.stdout)
55
56 try:
57     sp = None
58     p = None
59     ret = 99
60
61     hp = argv_bytes(extra[0]).split(b':')
62     if len(hp) == 1:
63         (hostname, port) = (hp[0], None)
64     else:
65         (hostname, port) = hp
66     argv = [argv_bytes(x) for x in extra[1:]]
67     p = ssh.connect(hostname, port, b'on--server', stderr=PIPE)
68
69     try:
70         argvs = b'\0'.join([b'bup'] + argv)
71         p.stdin.write(struct.pack('!I', len(argvs)) + argvs)
72         p.stdin.flush()
73         sp = subprocess.Popen([path.exe(), b'server'],
74                               stdin=p.stdout, stdout=p.stdin)
75         p.stdin.close()
76         p.stdout.close()
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''):
80             out.write(line)
81     finally:
82         while 1:
83             # if we get a signal while waiting, we have to keep waiting, just
84             # in case our child doesn't die.
85             try:
86                 ret = p.wait()
87                 if sp:
88                     sp.wait()
89                 break
90             except SigException as e:
91                 log('\nbup on: %s\n' % e)
92                 os.kill(p.pid, e.signum)
93                 ret = 84
94 except SigException as e:
95     if ret == 0:
96         ret = 99
97     log('\nbup on: %s\n' % e)
98
99 sys.exit(ret)