]> arthur.barton.de Git - bup.git/blob - lib/bup/ssh.py
34b5f3c38a2c30740d97dd097a9906c1a8e00f5f
[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 import sys, os, re, subprocess
5 from bup import helpers, path
6
7
8 def connect(rhost, port, subcmd, stderr=None):
9     """Connect to 'rhost' and execute the bup subcommand 'subcmd' on it."""
10     assert(not re.search(r'[^\w-]', subcmd))
11     nicedir = re.sub(r':', "_", path.exedir())
12     if rhost == '-':
13         rhost = None
14     if not rhost:
15         argv = ['bup', subcmd]
16     else:
17         # WARNING: shell quoting security holes are possible here, so we
18         # have to be super careful.  We have to use 'sh -c' because
19         # csh-derived shells can't handle PATH= notation.  We can't
20         # set PATH in advance, because ssh probably replaces it.  We
21         # can't exec *safely* using argv, because *both* ssh and 'sh -c'
22         # allow shellquoting.  So we end up having to double-shellquote
23         # stuff here.
24         escapedir = re.sub(r'([^\w/])', r'\\\\\\\1', nicedir)
25         buglvl = helpers.atoi(os.environ.get('BUP_DEBUG'))
26         force_tty = helpers.atoi(os.environ.get('BUP_FORCE_TTY'))
27         cmd = r"""
28                    sh -c PATH=%s:'$PATH BUP_DEBUG=%s BUP_FORCE_TTY=%s bup %s'
29                """ % (escapedir, buglvl, force_tty, subcmd)
30         argv = ['ssh']
31         if port:
32             argv.extend(('-p', port))
33         argv.extend((rhost, '--', cmd.strip()))
34         #helpers.log('argv is: %r\n' % argv)
35     def setup():
36         # runs in the child process
37         if not rhost:
38             os.environ['PATH'] = ':'.join([nicedir,
39                                            os.environ.get('PATH', '')])
40         os.setsid()
41     return subprocess.Popen(argv, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
42                             stderr=stderr,
43                             preexec_fn=setup)