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