]> arthur.barton.de Git - bup.git/blob - lib/bup/ssh.py
get: adjust for python 3 and test there
[bup.git] / lib / bup / ssh.py
1 """SSH connection.
2 Connect to a remote host via SSH and execute a command on the host.
3 """
4
5 from __future__ import absolute_import, print_function
6 import sys, os, re, subprocess
7
8 from bup import helpers, path
9 from bup.compat import environ
10
11 def connect(rhost, port, subcmd, stderr=None):
12     """Connect to 'rhost' and execute the bup subcommand 'subcmd' on it."""
13     assert not re.search(br'[^\w-]', subcmd)
14     nicedir = re.sub(b':', b'_', path.exedir())
15     if rhost == b'-':
16         rhost = None
17     if not rhost:
18         argv = [b'bup', subcmd]
19     else:
20         # WARNING: shell quoting security holes are possible here, so we
21         # have to be super careful.  We have to use 'sh -c' because
22         # csh-derived shells can't handle PATH= notation.  We can't
23         # set PATH in advance, because ssh probably replaces it.  We
24         # can't exec *safely* using argv, because *both* ssh and 'sh -c'
25         # allow shellquoting.  So we end up having to double-shellquote
26         # stuff here.
27         escapedir = re.sub(br'([^\w/])', br'\\\\\\\1', nicedir)
28         buglvl = helpers.atoi(environ.get(b'BUP_DEBUG'))
29         force_tty = helpers.atoi(environ.get(b'BUP_FORCE_TTY'))
30         cmd = b"""
31                    sh -c PATH=%s:'$PATH BUP_DEBUG=%s BUP_FORCE_TTY=%s bup %s'
32                """ % (escapedir, buglvl, force_tty, subcmd)
33         argv = [b'ssh']
34         if port:
35             argv.extend((b'-p', port))
36         argv.extend((rhost, b'--', cmd.strip()))
37         #helpers.log('argv is: %r\n' % argv)
38     if rhost:
39         env = environ
40     else:
41         envpath = environ.get(b'PATH')
42         env = environ.copy()
43         env[b'PATH'] = nicedir if not envpath else nicedir + b':' + envpath
44     if sys.version_info[0] < 3:
45         return subprocess.Popen(argv,
46                                 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
47                                 stderr=stderr,
48                                 env=env,
49                                 preexec_fn=lambda: os.setsid())
50     else:
51         return subprocess.Popen(argv,
52                                 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
53                                 stderr=stderr,
54                                 env=env,
55                                 start_new_session=True)