Permalink
Browse files

Initial commit.

Importing options.py, ssh.py, and LICENSE from the bup project.
  • Loading branch information...
apenwarr committed May 1, 2010
0 parents commit 2f3c86e962f4262f3c23a1360341accb3fc56533
Showing with 636 additions and 0 deletions.
  1. +2 −0 .gitignore
  2. +481 −0 LICENSE
  3. +2 −0 main.py
  4. +118 −0 options.py
  5. +32 −0 ssh.py
  6. +1 −0 sshuttle
@@ -0,0 +1,2 @@
+*.pyc
+*~
481 LICENSE

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -0,0 +1,2 @@
+#!/usr/bin/env python
+import ssh, options
@@ -0,0 +1,118 @@
+import sys, textwrap, getopt, re
+
+class OptDict:
+ def __init__(self):
+ self._opts = {}
+
+ def __setitem__(self, k, v):
+ self._opts[k] = v
+
+ def __getitem__(self, k):
+ return self._opts[k]
+
+ def __getattr__(self, k):
+ return self[k]
+
+
+class Options:
+ def __init__(self, exe, optspec, optfunc=getopt.gnu_getopt):
+ self.exe = exe
+ self.optspec = optspec
+ self.optfunc = optfunc
+ self._aliases = {}
+ self._shortopts = 'h?'
+ self._longopts = ['help']
+ self._hasparms = {}
+ self._usagestr = self._gen_usage()
+
+ def _gen_usage(self):
+ out = []
+ lines = self.optspec.strip().split('\n')
+ lines.reverse()
+ first_syn = True
+ while lines:
+ l = lines.pop()
+ if l == '--': break
+ out.append('%s: %s\n' % (first_syn and 'usage' or ' or', l))
+ first_syn = False
+ out.append('\n')
+ while lines:
+ l = lines.pop()
+ if l.startswith(' '):
+ out.append('\n%s\n' % l.lstrip())
+ elif l:
+ (flags, extra) = l.split(' ', 1)
+ extra = extra.strip()
+ if flags.endswith('='):
+ flags = flags[:-1]
+ has_parm = 1
+ else:
+ has_parm = 0
+ flagl = flags.split(',')
+ flagl_nice = []
+ for f in flagl:
+ f_nice = re.sub(r'\W', '_', f)
+ self._aliases[f] = flagl[0]
+ self._aliases[f_nice] = flagl[0]
+ self._hasparms[f] = has_parm
+ if len(f) == 1:
+ self._shortopts += f + (has_parm and ':' or '')
+ flagl_nice.append('-' + f)
+ else:
+ assert(not f.startswith('no-')) # supported implicitly
+ self._longopts.append(f + (has_parm and '=' or ''))
+ self._longopts.append('no-' + f)
+ flagl_nice.append('--' + f)
+ flags_nice = ', '.join(flagl_nice)
+ if has_parm:
+ flags_nice += ' ...'
+ prefix = ' %-20s ' % flags_nice
+ argtext = '\n'.join(textwrap.wrap(extra, width=70,
+ initial_indent=prefix,
+ subsequent_indent=' '*28))
+ out.append(argtext + '\n')
+ else:
+ out.append('\n')
+ return ''.join(out).rstrip() + '\n'
+
+ def usage(self):
+ sys.stderr.write(self._usagestr)
+ sys.exit(97)
+
+ def fatal(self, s):
+ sys.stderr.write('error: %s\n' % s)
+ return self.usage()
+
+ def parse(self, args):
+ try:
+ (flags,extra) = self.optfunc(args, self._shortopts, self._longopts)
+ except getopt.GetoptError, e:
+ self.fatal(e)
+
+ opt = OptDict()
+ for f in self._aliases.values():
+ opt[f] = None
+ for (k,v) in flags:
+ while k.startswith('-'):
+ k = k[1:]
+ if k in ['h', '?', 'help']:
+ self.usage()
+ if k.startswith('no-'):
+ k = self._aliases[k[3:]]
+ opt[k] = None
+ else:
+ k = self._aliases[k]
+ if not self._hasparms[k]:
+ assert(v == '')
+ opt[k] = (opt._opts.get(k) or 0) + 1
+ else:
+ try:
+ vv = int(v)
+ if str(vv) == v:
+ v = vv
+ except ValueError:
+ pass
+ opt[k] = v
+ for (f1,f2) in self._aliases.items():
+ opt[f1] = opt[f2]
+ return (opt,flags,extra)
32 ssh.py
@@ -0,0 +1,32 @@
+import os, re, subprocess
+
+def connect(rhost, subcmd):
+ assert(not re.search(r'[^\w-]', subcmd))
+ main_exe = sys.argv[0]
+ nicedir = os.path.split(os.path.abspath(main_exe))[0]
+ nicedir = re.sub(r':', "_", nicedir)
+ if rhost == '-':
+ rhost = None
+ if not rhost:
+ argv = ['sshuttle', subcmd]
+ else:
+ # WARNING: shell quoting security holes are possible here, so we
+ # have to be super careful. We have to use 'sh -c' because
+ # csh-derived shells can't handle PATH= notation. We can't
+ # set PATH in advance, because ssh probably replaces it. We
+ # can't exec *safely* using argv, because *both* ssh and 'sh -c'
+ # allow shellquoting. So we end up having to double-shellquote
+ # stuff here.
+ escapedir = re.sub(r'([^\w/])', r'\\\\\\\1', nicedir)
+ cmd = r"""
+ sh -c PATH=%s:'$PATH sshuttle %s'
+ """ % (escapedir, subcmd)
+ argv = ['ssh', rhost, '--', cmd.strip()]
+ def setup():
+ # runs in the child process
+ if not rhost:
+ os.environ['PATH'] = ':'.join([nicedir,
+ os.environ.get('PATH', '')])
+ os.setsid()
+ return subprocess.Popen(argv, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+ preexec_fn=setup)

0 comments on commit 2f3c86e

Please sign in to comment.