diff options
author | Brian May <brian@linuxpenguins.xyz> | 2015-11-16 08:41:25 +1100 |
---|---|---|
committer | Brian May <brian@linuxpenguins.xyz> | 2015-11-16 09:09:01 +1100 |
commit | ba1cf58a6cbe4953f6e012c10d5a66964d22a21f (patch) | |
tree | 6f2ca41c8b8416dd78a30c2367512060c8a49c25 /sshuttle | |
parent | dd8e68b6dcb0a8b10d4949d07f5b3dd949af5409 (diff) |
Add Python 3.5 support.
Diffstat (limited to 'sshuttle')
-rw-r--r-- | sshuttle/__main__.py | 8 | ||||
-rw-r--r-- | sshuttle/assembler.py | 2 | ||||
-rw-r--r-- | sshuttle/client.py | 93 | ||||
-rw-r--r-- | sshuttle/compat/__init__.py | 0 | ||||
-rw-r--r-- | sshuttle/compat/ssubprocess.py | 1296 | ||||
-rw-r--r-- | sshuttle/firewall.py | 30 | ||||
-rw-r--r-- | sshuttle/helpers.py | 2 | ||||
-rw-r--r-- | sshuttle/hostwatch.py | 14 | ||||
-rw-r--r-- | sshuttle/options.py | 6 | ||||
-rw-r--r-- | sshuttle/server.py | 14 | ||||
-rw-r--r-- | sshuttle/ssh.py | 14 | ||||
-rw-r--r-- | sshuttle/ssnet.py | 49 | ||||
-rw-r--r-- | sshuttle/ssyslog.py | 2 | ||||
-rwxr-xr-x | sshuttle/stresstest.py | 20 | ||||
-rw-r--r-- | sshuttle/ui-macos/main.py | 20 | ||||
-rw-r--r-- | sshuttle/ui-macos/models.py | 2 | ||||
-rw-r--r-- | sshuttle/ui-macos/my.py | 2 |
17 files changed, 145 insertions, 1429 deletions
diff --git a/sshuttle/__main__.py b/sshuttle/__main__.py index 2c8aed6..1144c68 100644 --- a/sshuttle/__main__.py +++ b/sshuttle/__main__.py @@ -1,8 +1,8 @@ import sys import re import socket -import helpers -import options +import sshuttle.helpers as helpers +import sshuttle.options as options import sshuttle.client as client import sshuttle.server as server import sshuttle.firewall as firewall @@ -145,7 +145,7 @@ o = options.Options(optspec) if opt.daemon: opt.syslog = 1 if opt.wrap: - import ssnet + import sshuttle.ssnet as ssnet ssnet.MAX_CHANNEL = int(opt.wrap) helpers.verbose = opt.verbose @@ -230,7 +230,7 @@ try: log('Abnormal exit code detected, failing...' % return_code) sys.exit(return_code) -except Fatal, e: +except Fatal as e: log('fatal: %s\n' % e) sys.exit(99) except KeyboardInterrupt: diff --git a/sshuttle/assembler.py b/sshuttle/assembler.py index be5b957..ee2b12e 100644 --- a/sshuttle/assembler.py +++ b/sshuttle/assembler.py @@ -18,7 +18,7 @@ while 1: setattr(sys.modules[parent], parent_name, module) code = compile(content, name, "exec") - exec code in module.__dict__ + exec(code, module.__dict__) sys.modules[name] = module else: break diff --git a/sshuttle/client.py b/sshuttle/client.py index 55be9b3..cf4fc91 100644 --- a/sshuttle/client.py +++ b/sshuttle/client.py @@ -3,12 +3,12 @@ import errno import re import signal import time -import sshuttle.compat.ssubprocess as ssubprocess -import helpers +import subprocess as ssubprocess +import sshuttle.helpers as helpers import os import sshuttle.ssnet as ssnet import sshuttle.ssh as ssh -import ssyslog +import sshuttle.ssyslog as ssyslog import sys from sshuttle.ssnet import SockWrapper, Handler, Proxy, Mux, MuxWrapper from sshuttle.helpers import log, debug1, debug2, debug3, Fatal, islocal, \ @@ -124,7 +124,7 @@ def check_daemon(pidfile): _pidname = os.path.abspath(pidfile) try: oldpid = open(_pidname).read(1024) - except IOError, e: + except IOError as e: if e.errno == errno.ENOENT: return # no pidfile, ok else: @@ -138,7 +138,7 @@ def check_daemon(pidfile): return # invalid pidfile, ok try: os.kill(oldpid, 0) - except OSError, e: + except OSError as e: if e.errno == errno.ESRCH: os.unlink(_pidname) return # outdated pidfile, ok @@ -157,7 +157,7 @@ def daemonize(): if os.fork(): os._exit(0) - outfd = os.open(_pidname, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0666) + outfd = os.open(_pidname, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o666) try: os.write(outfd, '%d\n' % os.getpid()) finally: @@ -179,7 +179,7 @@ def daemonize(): def daemon_cleanup(): try: os.unlink(_pidname) - except OSError, e: + except OSError as e: if e.errno == errno.ENOENT: pass else: @@ -215,7 +215,7 @@ def original_dst(sock): assert(socket.htons(proto) == socket.AF_INET) ip = '%d.%d.%d.%d' % (a, b, c, d) return (ip, port) - except socket.error, e: + except socket.error as e: if e.args[0] == errno.ENOPROTOOPT: return sock.getsockname() raise @@ -251,7 +251,7 @@ class MultiListener: if self.v4: try: self.v4.listen(backlog) - except socket.error, e: + except socket.error as e: # on some systems v4 bind will fail if the v6 suceeded, # in this case the v6 socket will receive v4 too. if e.errno == errno.EADDRINUSE and self.v6: @@ -321,17 +321,22 @@ class FirewallClient: self.p = ssubprocess.Popen(argv, stdout=s1, preexec_fn=setup) e = None break - except OSError, e: + except OSError as e: pass self.argv = argv s1.close() - self.pfile = s2.makefile('wb+') + if sys.version_info < (3, 0): + # python 2.7 + self.pfile = s2.makefile('wb+') + else: + # python 3.5 + self.pfile = s2.makefile('rwb') if e: log('Spawning firewall manager: %r\n' % self.argv) raise Fatal(e) line = self.pfile.readline() self.check() - if line[0:5] != 'READY': + if line[0:5] != b'READY': raise Fatal('%r expected READY, got %r' % (self.argv, line)) self.method = line[6:-1] @@ -341,22 +346,26 @@ class FirewallClient: raise Fatal('%r returned %d' % (self.argv, rv)) def start(self): - self.pfile.write('ROUTES\n') - for (family, ip, width) in self.subnets_include + self.auto_nets: - self.pfile.write('%d,%d,0,%s\n' % (family, width, ip)) - for (family, ip, width) in self.subnets_exclude: - self.pfile.write('%d,%d,1,%s\n' % (family, width, ip)) - self.pfile.write('GO\n') + self.pfile.write(b'ROUTES\n') + try: + for (family, ip, width) in self.subnets_include + self.auto_nets: + self.pfile.write(b'%d,%d,0,%s\n' % (family, width, ip.encode("ASCII"))) + for (family, ip, width) in self.subnets_exclude: + self.pfile.write(b'%d,%d,1,%s\n' % (family, width, ip.encode("ASCII"))) + except Exception as e: + debug1("exception occured %r" % e) + raise + self.pfile.write(b'GO\n') self.pfile.flush() line = self.pfile.readline() self.check() - if line != 'STARTED\n': + if line != b'STARTED\n': raise Fatal('%r expected STARTED, got %r' % (self.argv, line)) def sethostip(self, hostname, ip): assert(not re.search(r'[^-\w]', hostname)) assert(not re.search(r'[^0-9.]', ip)) - self.pfile.write('HOST %s,%s\n' % (hostname, ip)) + self.pfile.write(b'HOST %s,%s\n' % (hostname, ip)) self.pfile.flush() def done(self): @@ -390,7 +399,7 @@ def onaccept_tcp(listener, method, mux, handlers): global _extra_fd try: sock, srcip = listener.accept() - except socket.error, e: + except socket.error as e: if e.args[0] in [errno.EMFILE, errno.ENFILE]: debug1('Rejected incoming connection: too many open files!\n') # free up an fd so we can eat the connection @@ -403,9 +412,9 @@ def onaccept_tcp(listener, method, mux, handlers): return else: raise - if method == "tproxy": + if method == b"tproxy": dstip = sock.getsockname() - elif method == "pf": + elif method == b"pf": dstip = pf_dst(sock) else: dstip = original_dst(sock) @@ -420,8 +429,8 @@ def onaccept_tcp(listener, method, mux, handlers): log('warning: too many open channels. Discarded connection.\n') sock.close() return - mux.send(chan, ssnet.CMD_TCP_CONNECT, '%d,%s,%s' % - (sock.family, dstip[0], dstip[1])) + mux.send(chan, ssnet.CMD_TCP_CONNECT, b'%d,%s,%d' % + (sock.family, dstip[0].encode("ASCII"), dstip[1])) outwrap = MuxWrapper(mux, chan) handlers.append(Proxy(SockWrapper(sock, sock), outwrap)) expire_connections(time.time(), mux) @@ -439,7 +448,7 @@ def udp_done(chan, data, method, family, dstip): sender.bind(srcip) sender.sendto(data, dstip) sender.close() - except socket.error, e: + except socket.error as e: debug1('-- ignored socket error sending UDP data: %r\n' % e) @@ -471,7 +480,7 @@ def dns_done(chan, data, method, sock, srcip, dstip, mux): debug3('dns_done: channel=%d src=%r dst=%r\n' % (chan, srcip, dstip)) del mux.channels[chan] del dnsreqs[chan] - if method == "tproxy": + if method == b"tproxy": debug3('doing send from %r to %r\n' % (srcip, dstip,)) sender = socket.socket(sock.family, socket.SOCK_DGRAM) sender.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) @@ -487,7 +496,7 @@ def dns_done(chan, data, method, sock, srcip, dstip, mux): def ondns(listener, method, mux, handlers): now = time.time() srcip, dstip, data = recv_udp(listener, 4096) - if method == "tproxy" and not dstip: + if method == b"tproxy" and not dstip: debug1( "-- ignored UDP from %r: " "couldn't determine destination IP address\n" % (srcip,)) @@ -517,7 +526,7 @@ def _main(tcp_listener, udp_listener, fw, ssh_cmd, remotename, ssh_cmd, remotename, python, stderr=ssyslog._p and ssyslog._p.stdin, options=dict(latency_control=latency_control, method=method)) - except socket.error, e: + except socket.error as e: if e.args[0] == errno.EPIPE: raise Fatal("failed to establish ssh session (1)") else: @@ -525,17 +534,17 @@ def _main(tcp_listener, udp_listener, fw, ssh_cmd, remotename, mux = Mux(serversock, serversock) handlers.append(mux) - expected = 'SSHUTTLE0001' + expected = b'SSHUTTLE0001' try: v = 'x' - while v and v != '\0': + while v and v != b'\0': v = serversock.recv(1) v = 'x' - while v and v != '\0': + while v and v != b'\0': v = serversock.recv(1) initstring = serversock.recv(len(expected)) - except socket.error, e: + except socket.error as e: if e.args[0] == errno.ECONNRESET: raise Fatal("failed to establish ssh session (2)") else: @@ -549,7 +558,7 @@ def _main(tcp_listener, udp_listener, fw, ssh_cmd, remotename, raise Fatal('expected server init string %r; got %r' % (expected, initstring)) debug1('connected.\n') - print 'Connected.' + print('Connected.') sys.stdout.flush() if daemon: daemonize() @@ -616,7 +625,7 @@ def main(listenip_v6, listenip_v4, if daemon: try: check_daemon(pidfile) - except Fatal, e: + except Fatal as e: log("%s\n" % e) return 5 debug1('Starting sshuttle proxy.\n') @@ -624,7 +633,7 @@ def main(listenip_v6, listenip_v4, if recvmsg is not None: debug1("recvmsg %s support enabled.\n" % recvmsg) - if method == "tproxy": + if method == b"tproxy": if recvmsg is not None: debug1("tproxy UDP support enabled.\n") udp = True @@ -643,7 +652,7 @@ def main(listenip_v6, listenip_v4, ports = [0, ] else: # if at least one port missing, we have to search - ports = xrange(12300, 9000, -1) + ports = range(12300, 9000, -1) # search for free ports and try to bind last_e = None @@ -688,7 +697,7 @@ def main(listenip_v6, listenip_v4, udp_listener.bind(lv6, lv4) bound = True break - except socket.error, e: + except socket.error as e: if e.errno == errno.EADDRINUSE: last_e = e else: @@ -708,7 +717,7 @@ def main(listenip_v6, listenip_v4, nslist += resolvconf_nameservers() # search for spare port for DNS debug2('Binding DNS:') - ports = xrange(12300, 9000, -1) + ports = range(12300, 9000, -1) for port in ports: debug2(' %d' % port) dns_listener = MultiListener(socket.SOCK_DGRAM) @@ -731,7 +740,7 @@ def main(listenip_v6, listenip_v4, dns_listener.bind(lv6, lv4) bound = True break - except socket.error, e: + except socket.error as e: if e.errno == errno.EADDRINUSE: last_e = e else: @@ -750,7 +759,7 @@ def main(listenip_v6, listenip_v4, subnets_exclude, dnsport_v6, dnsport_v4, nslist, method, udp) - if fw.method == "tproxy": + if fw.method == b"tproxy": tcp_listener.setsockopt(socket.SOL_IP, IP_TRANSPARENT, 1) if udp_listener: udp_listener.setsockopt(socket.SOL_IP, IP_TRANSPARENT, 1) @@ -767,7 +776,7 @@ def main(listenip_v6, listenip_v4, if dns_listener.v6 is not None: dns_listener.v6.setsockopt(SOL_IPV6, IPV6_RECVORIGDSTADDR, 1) - if fw.method == "pf": + if fw.method == b"pf": global pf_command_file pf_command_file = fw.pfile diff --git a/sshuttle/compat/__init__.py b/sshuttle/compat/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/sshuttle/compat/__init__.py +++ /dev/null diff --git a/sshuttle/compat/ssubprocess.py b/sshuttle/compat/ssubprocess.py deleted file mode 100644 index 87797e6..0000000 --- a/sshuttle/compat/ssubprocess.py +++ /dev/null @@ -1,1296 +0,0 @@ -# subprocess - Subprocesses with accessible I/O streams -# -# For more information about this module, see PEP 324. -# -# This module should remain compatible with Python 2.2, see PEP 291. -# -# Copyright (c) 2003-2005 by Peter Astrand <astrand@lysator.liu.se> -# -# Licensed to PSF under a Contributor Agreement. -# See http://www.python.org/2.4/license for licensing details. - -r"""subprocess - Subprocesses with accessible I/O streams - -This module allows you to spawn processes, connect to their -input/output/error pipes, and obtain their return codes. This module -intends to replace several other, older modules and functions, like: - -os.system -os.spawn* -os.popen* -popen2.* -commands.* - -Information about how the subprocess module can be used to replace these -modules and functions can be found below. - - - -Using the subprocess module -=========================== -This module defines one class called Popen: - -class Popen(args, bufsize=0, executable=None, - stdin=None, stdout=None, stderr=None, - preexec_fn=None, close_fds=False, shell=False, - cwd=None, env=None, universal_newlines=False, - startupinfo=None, creationflags=0): - - -Arguments are: - -args should be a string, or a sequence of program arguments. The -program to execute is normally the first item in the args sequence or -string, but can be explicitly set by using the executable argument. - -On UNIX, with shell=False (default): In this case, the Popen class -uses os.execvp() to execute the child program. args should normally -be a sequence. A string will be treated as a sequence with the string -as the only item (the program to execute). - -On UNIX, with shell=True: If args is a string, it specifies the -command string to execute through the shell. If args is a sequence, -the first item specifies the command string, and any additional items -will be treated as additional shell arguments. - -On Windows: the Popen class uses CreateProcess() to execute the child -program, which operates on strings. If args is a sequence, it will be -converted to a string using the list2cmdline method. Please note that -not all MS Windows applications interpret the command line the same -way: The list2cmdline is designed for applications using the same -rules as the MS C runtime. - -bufsize, if given, has the same meaning as the corresponding argument -to the built-in open() function: 0 means unbuffered, 1 means line -buffered, any other positive value means use a buffer of -(approximately) that size. A negative bufsize means to use the system -default, which usually means fully buffered. The default value for -bufsize is 0 (unbuffered). - -stdin, stdout and stderr specify the executed programs' standard -input, standard output and standard error file handles, respectively. -Valid values are PIPE, an existing file descriptor (a positive -integer), an existing file object, and None. PIPE indicates that a -new pipe to the child should be created. With None, no redirection -will occur; the child's file handles will be inherited from the -parent. Additionally, stderr can be STDOUT, which indicates that the -stderr data from the applications should be captured into the same -file handle as for stdout. - -If preexec_fn is set to a callable object, this object will be called -in the child process just before the child is executed. - -If close_fds is true, all file descriptors except 0, 1 and 2 will be -closed before the child process is executed. - -if shell is true, the specified command will be executed through the -shell. - -If cwd is not None, the current directory will be changed to cwd -before the child is executed. - -If env is not None, it defines the environment variables for the new -process. - -If universal_newlines is true, the file objects stdout and stderr are -opened as a text files, but lines may be terminated by any of '\n', -the Unix end-of-line convention, '\r', the Macintosh convention or -'\r\n', the Windows convention. All of these external representations -are seen as '\n' by the Python program. Note: This feature is only -available if Python is built with universal newline support (the -default). Also, the newlines attribute of the file objects stdout, -stdin and stderr are not updated by the communicate() method. - -The startupinfo and creationflags, if given, will be passed to the -underlying CreateProcess() function. They can specify things such as -appearance of the main window and priority for the new process. -(Windows only) - - -This module also defines two shortcut functions: - -call(*popenargs, **kwargs): - Run command with arguments. Wait for command to complete, then - return the returncode attribute. - - The arguments are the same as for the Popen constructor. Example: - - retcode = call(["ls", "-l"]) - -check_call(*popenargs, **kwargs): - Run command with arguments. Wait for command to complete. If the - exit code was zero then return, otherwise raise - CalledProcessError. The CalledProcessError object will have the - return code in the returncode attribute. - - The arguments are the same as for the Popen constructor. Example: - - check_call(["ls", "-l"]) - -Exceptions ----------- -Exceptions raised in the child process, before the new program has -started to execute, will be re-raised in the parent. Additionally, -the exception object will have one extra attribute called -'child_traceback', which is a string containing traceback information -from the childs point of view. - -The most common exception raised is OSError. This occurs, for -example, when trying to execute a non-existent file. Applications -should prepare for OSErrors. - -A ValueError will be raised if Popen is called with invalid arguments. - -check_call() will raise CalledProcessError, if the called process -returns a non-zero return code. - - -Security --------- -Unlike some other popen functions, this implementation will never call -/bin/sh implicitly. This means that all characters, including shell -metacharacters, can safely be passed to child processes. - - -Popen objects -============= -Instances of the Popen class have the following methods: - -poll() - Check if child process has terminated. Returns returncode - attribute. - -wait() - Wait for child process to terminate. Returns returncode attribute. - -communicate(input=None) - Interact with process: Send data to stdin. Read data from stdout - and stderr, until end-of-file is reached. Wait for process to - terminate. The optional input argument should be a string to be - sent to the child process, or None, if no data should be sent to - the child. - - communicate() returns a tuple (stdout, stderr). - - Note: The data read is buffered in memory, so do not use this - method if the data size is large or unlimited. - -The following attributes are also available: - -stdin - If the stdin argument is PIPE, this attribute is a file object - that provides input to the child process. Otherwise, it is None. - -stdout - If the stdout argument is PIPE, this attribute is a file object - that provides output from the child process. Otherwise, it is - None. - -stderr - If the stderr argument is PIPE, this attribute is file object that - provides error output from the child process. Otherwise, it is - None. - -pid - The process ID of the child process. - -returncode - The child return code. A None value indicates that the process - hasn't terminated yet. A negative value -N indicates that the - child was terminated by signal N (UNIX only). - - -Replacing older functions with the subprocess module -==================================================== -In this section, "a ==> b" means that b can be used as a replacement -for a. - -Note: All functions in this section fail (more or less) silently if -the executed program cannot be found; this module raises an OSError -exception. - -In the following examples, we assume that the subprocess module is -imported with "from subprocess import *". - - -Replacing /bin/sh shell backquote ---------------------------------- -output=`mycmd myarg` -==> -output = Popen(["mycmd", "myarg"], stdout=PIPE).communicate()[0] - - -Replacing shell pipe line -------------------------- -output=`dmesg | grep hda` -==> -p1 = Popen(["dmesg"], stdout=PIPE) -p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE) -output = p2.communicate()[0] - - -Replacing os.system() ---------------------- -sts = os.system("mycmd" + " myarg") -==> -p = Popen("mycmd" + " myarg", shell=True) -pid, sts = os.waitpid(p.pid, 0) - -Note: - -* Calling the program through the shell is usually not required. - -* It's easier to look at the returncode attribute than the - exitstatus. - -A more real-world example would look like this: - -try: - retcode = call("mycmd" + " myarg", shell=True) - if retcode < 0: - print >>sys.stderr, "Child was terminated by signal", -retcode - else: - print >>sys.stderr, "Child returned", retcode -except OSError, e: - print >>sys.stderr, "Execution failed:", e - - -Replacing os.spawn* -------------------- -P_NOWAIT example: - -pid = os.spawnlp(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg") -==> -pid = Popen(["/bin/mycmd", "myarg"]).pid - - -P_WAIT example: - -retcode = os.spawnlp(os.P_WAIT, "/bin/mycmd", "mycmd", "myarg") -==> -retcode = call(["/bin/mycmd", "myarg"]) - - -Vector example: - -os.spawnvp(os.P_NOWAIT, path, args) -==> -Popen([path] + args[1:]) - - -Environment example: - -os.spawnlpe(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg", env) -==> -Popen(["/bin/mycmd", "myarg"], env={"PATH": "/usr/bin"}) - - -Replacing os.popen* -------------------- -pipe = os.popen(cmd, mode='r', bufsize) -==> -pipe = Popen(cmd, shell=True, bufsize=bufsize, stdout=PIPE).stdout - -pipe = os.popen(cmd, mode='w', bufsize) -==> -pipe = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE).stdin - - -(child_stdin, child_stdout) = os.popen2(cmd, mode, bufsize) -==> -p = Popen(cmd, shell=True, bufsize=bufsize, - stdin=PIPE, stdout=PIPE, close_fds=True) -(child_stdin, child_stdout) = (p.stdin, p.stdout) - - -(child_stdin, - child_stdout, - child_stderr) = os.popen3(cmd, mode, bufsize) -==> -p = Popen(cmd, shell=True, bufsize=bufsize, - stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) -(child_stdin, - child_stdout, - child_stderr) = (p.stdin, p.stdout, p.stderr) - - -(child_stdin, child_stdout_and_stderr) = os.popen4(cmd, mode, bufsize) -==> -p = Popen(cmd, shell=True, bufsize=bufsize, - stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) -(child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout) - - -Replacing popen2.* ------------------- -Note: If the cmd argument to popen2 functions is a string, the command -is executed through /bin/sh. If it is a list, the command is directly -executed. - -(child_stdout, child_stdin) = popen2.popen2("somestring", bufsize, mode) -==> -p = Popen(["somestring"], shell=True, bufsize=bufsize - stdin=PIPE, stdout=PIPE, close_fds=True) -(child_stdout, child_stdin) = (p.stdout, p.stdin) - - -(child_stdout, child_stdin) = popen2.popen2(["mycmd", "myarg"], bufsize, mode) -==> -p = Popen(["mycmd", "myarg"], bufsize=bufsize, - stdin=PIPE, stdout=PIPE, close_fds=True) -(child_stdout, child_stdin) = (p.stdout, p.stdin) - -The popen2.Popen3 and popen2.Popen4 basically works as subprocess.Popen, -except that: - -* subprocess.Popen raises an exception if the execution fails -* the capturestderr argument is replaced with the stderr argument. -* stdin=PIPE and stdout=PIPE must be specified. -* popen2 closes all filedescriptors by default, but you have to specify - close_fds=True with subprocess.Popen. -""" - -import sys -mswindows = (sys.platform == "win32") - -import os -import types -import traceback -import gc -import signal - -# Exception classes used by this module. - - -class CalledProcessError(Exception): - """This exception is raised when a process run by check_call() returns - a non-zero exit status. The exit status will be stored in the - returncode attribute.""" - - def __init__(self, returncode, cmd): - self.returncode = returncode - self.cmd = cmd - - def __str__(self): - return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode) - - -if mswindows: - import threading - import msvcrt - if 0: # <-- change this to use pywin32 instead of the _subprocess driver - import pywintypes - from win32api import GetStdHandle, STD_INPUT_HANDLE, \ - STD_OUTPUT_HANDLE, STD_ERROR_HANDLE - from win32api import GetCurrentProcess, DuplicateHandle, \ - GetModuleFileName, GetVersion - from win32con import DUPLICATE_SAME_ACCESS, SW_HIDE - from win32pipe import CreatePipe - from win32process import CreateProcess, STARTUPINFO, \ - GetExitCodeProcess, STARTF_USESTDHANDLES, \ - STARTF_USESHOWWINDOW, CREATE_NEW_CONSOLE - from win32process import TerminateProcess - from win32event import WaitForSingleObject, INFINITE, WAIT_OBJECT_0 - else: - from _subprocess import * - - class STARTUPINFO: - dwFlags = 0 - hStdInput = None - hStdOutput = None - hStdError = None - wShowWindow = 0 - - class pywintypes: - error = IOError -else: - import select - import errno - import fcntl - import pickle - -__all__ = ["Popen", "PIPE", "STDOUT", "call", - "check_call", "CalledProcessError"] - -try: - MAXFD = os.sysconf("SC_OPEN_MAX") -except: - MAXFD = 256 - -# True/False does not exist on 2.2.0 -# try: -# False -# except NameError: -# False = 0 -# True = 1 - -_active = [] - - -def _cleanup(): - for inst in _active[:]: - if inst._internal_poll(_deadstate=sys.maxint) >= 0: - try: - _active.remove(inst) - except ValueError: - # This can happen if two threads create a new Popen instance. - # It's harmless that it was already removed, so ignore. - pass - -PIPE = -1 -STDOUT = -2 - - -def call(*popenargs, **kwargs): - """Run command with arguments. Wait for command to complete, then - return the returncode attribute. - - The arguments are the same as for the Popen constructor. Example: - - retcode = call(["ls", "-l"]) - """ - return Popen(*popenargs, **kwargs).wait() - - -def check_call(*popenargs, **kwargs): - """Run command with arguments. Wait for command to complete. If - the exit code was zero then return, otherwise raise - CalledProcessError. The CalledProcessError object will have the - return code in the returncode attribute. - - The arguments are the same as for the Popen constructor. Example: - - check_call(["ls", "-l"]) - """ - retcode = call(*popenargs, **kwargs) - cmd = kwargs.get("args") - if cmd is None: - cmd = popenargs[0] - if retcode: - raise CalledProcessError(retcode, cmd) - return retcode - - -def list2cmdline(seq): - """ - Translate a sequence of arguments into a command line - string, using the same rules as the MS C runtime: - - 1) Arguments are delimited by white space, which is either a - space or a tab. - - 2) A string surrounded by double quotation marks is - interpreted as a single argument, regardless of white space - or pipe characters contained within. A quoted string can be - embedded in an argument. - - 3) A double quotation mark preceded by a backslash is - interpreted as a literal double quotation mark. - - 4) Backslashes are interpreted literally, unless they - immediately precede a double quotation mark. - - 5) If backslashes immediately precede a double quotation mark, - every pair of backslashes is interpreted as a literal - backslash. If the number of backslashes is odd, the last - backslash escapes the next double quotation mark as - described in rule 3. - """ - - # See - # http://msdn.microsoft.com/library/en-us/vccelng/htm/progs_12.asp - result = [] - needquote = False - for arg in seq: - bs_buf = [] - - # Add a space to separate this argument from the others - if result: - result.append(' ') - - needquote = (" " in arg) or ("\t" in arg) or ("|" in arg) or not arg - if needquote: - result.append('"') - - for c in arg: - if c == '\\': - # Don't know if we need to double yet. - bs_buf.append(c) - elif c == '"': - # Double backslashes. - result.append('\\' * len(bs_buf) * 2) - bs_buf = [] - result.append('\\"') - else: - # Normal char - if bs_buf: - result.extend(bs_buf) - bs_buf = [] - result.append(c) - - # Add remaining backslashes, if any. - if bs_buf: - result.extend(bs_buf) - - if needquote: - result.extend(bs_buf) - result.append('"') - - return ''.join(result) - - -def _closerange(start, max): - try: - os.closerange(start, max) - except AttributeError: - for i in xrange(start, max): - try: - os.close(i) - except: - pass - - -class Popen(object): - - def __init__(self, args, bufsize=0, executable=None, - stdin=None, stdout=None, stderr=None, - preexec_fn=None, close_fds=False, shell=False, - cwd=None, env=None, universal_newlines=False, |