Commit ba619ec3 authored by Tom Niget's avatar Tom Niget

nemu works in python 3

parent f8914e80
import os
import socket as pysocket
def pipe() -> tuple[int, int]:
a, b = os.pipe2(0)
os.set_inheritable(a, True)
os.set_inheritable(b, True)
return a, b
def socket(*args, **kwargs) -> pysocket.socket:
s = pysocket.socket(*args, **kwargs)
s.set_inheritable(True)
return s
def socketpair(*args, **kwargs) -> tuple[pysocket.socket, pysocket.socket]:
a, b = pysocket.socketpair(*args, **kwargs)
a.set_inheritable(True)
b.set_inheritable(True)
return a, b
def fromfd(*args, **kwargs) -> pysocket.socket:
s = pysocket.fromfd(*args, **kwargs)
s.set_inheritable(True)
return s
def fdopen(*args, **kwargs) -> pysocket.socket:
s = os.fdopen(*args, **kwargs)
s.set_inheritable(True)
return s
\ No newline at end of file
...@@ -25,8 +25,12 @@ import subprocess ...@@ -25,8 +25,12 @@ import subprocess
import sys import sys
import syslog import syslog
from syslog import LOG_ERR, LOG_WARNING, LOG_NOTICE, LOG_INFO, LOG_DEBUG from syslog import LOG_ERR, LOG_WARNING, LOG_NOTICE, LOG_INFO, LOG_DEBUG
from typing import TypeVar, Callable
__all__ = ["IP_PATH", "TC_PATH", "BRCTL_PATH", "SYSCTL_PATH", "HZ"] __all__ = ["IP_PATH", "TC_PATH", "BRCTL_PATH", "SYSCTL_PATH", "HZ"]
from nemu import compat
__all__ += ["TCPDUMP_PATH", "NETPERF_PATH", "XAUTH_PATH", "XDPYINFO_PATH"] __all__ += ["TCPDUMP_PATH", "NETPERF_PATH", "XAUTH_PATH", "XDPYINFO_PATH"]
__all__ += ["execute", "backticks", "eintr_wrapper"] __all__ += ["execute", "backticks", "eintr_wrapper"]
__all__ += ["find_listen_port"] __all__ += ["find_listen_port"]
...@@ -35,14 +39,14 @@ __all__ += ["set_log_level", "logger"] ...@@ -35,14 +39,14 @@ __all__ += ["set_log_level", "logger"]
__all__ += ["error", "warning", "notice", "info", "debug"] __all__ += ["error", "warning", "notice", "info", "debug"]
def find_bin(name, extra_path = None): def find_bin(name, extra_path=None):
"""Try hard to find the location of needed programs.""" """Try hard to find the location of needed programs."""
search = [] search = []
if "PATH" in os.environ: if "PATH" in os.environ:
search += os.environ["PATH"].split(":") search += os.environ["PATH"].split(":")
search.extend(os.path.join(x, y) search.extend(os.path.join(x, y)
for x in ("/", "/usr/", "/usr/local/") for x in ("/", "/usr/", "/usr/local/")
for y in ("bin", "sbin")) for y in ("bin", "sbin"))
if extra_path: if extra_path:
search += extra_path search += extra_path
...@@ -52,16 +56,18 @@ def find_bin(name, extra_path = None): ...@@ -52,16 +56,18 @@ def find_bin(name, extra_path = None):
return path return path
return None return None
def find_bin_or_die(name, extra_path = None):
def find_bin_or_die(name, extra_path=None):
"""Try hard to find the location of needed programs; raise on failure.""" """Try hard to find the location of needed programs; raise on failure."""
res = find_bin(name, extra_path) res = find_bin(name, extra_path)
if not res: if not res:
raise RuntimeError("Cannot find `%s', impossible to continue." % name) raise RuntimeError("Cannot find `%s', impossible to continue." % name)
return res return res
IP_PATH = find_bin_or_die("ip")
TC_PATH = find_bin_or_die("tc") IP_PATH = find_bin_or_die("ip")
BRCTL_PATH = find_bin_or_die("brctl") TC_PATH = find_bin_or_die("tc")
BRCTL_PATH = find_bin_or_die("brctl")
SYSCTL_PATH = find_bin_or_die("sysctl") SYSCTL_PATH = find_bin_or_die("sysctl")
# Optional tools # Optional tools
...@@ -78,21 +84,23 @@ try: ...@@ -78,21 +84,23 @@ try:
os.stat("/sys/class/net") os.stat("/sys/class/net")
except: except:
raise RuntimeError("Sysfs does not seem to be mounted, impossible to " + raise RuntimeError("Sysfs does not seem to be mounted, impossible to " +
"continue.") "continue.")
def execute(cmd):
def execute(cmd: list[str]):
"""Execute a command, if the return value is non-zero, raise an exception. """Execute a command, if the return value is non-zero, raise an exception.
Raises: Raises:
RuntimeError: the command was unsuccessful (return code != 0). RuntimeError: the command was unsuccessful (return code != 0).
""" """
debug("execute(%s)" % cmd) debug("execute(%s)" % cmd)
proc = subprocess.Popen(cmd, stdout = subprocess.DEVNULL, stderr = subprocess.PIPE) proc = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE)
_, err = proc.communicate() _, err = proc.communicate()
if proc.returncode != 0: if proc.returncode != 0:
raise RuntimeError("Error executing `%s': %s" % (" ".join(cmd), err)) raise RuntimeError("Error executing `%s': %s" % (" ".join(cmd), err))
def backticks(cmd):
def backticks(cmd: list[str]) -> str:
"""Execute a command and capture its output. """Execute a command and capture its output.
If the return value is non-zero, raise an exception. If the return value is non-zero, raise an exception.
...@@ -102,30 +110,35 @@ def backticks(cmd): ...@@ -102,30 +110,35 @@ def backticks(cmd):
RuntimeError: the command was unsuccessful (return code != 0). RuntimeError: the command was unsuccessful (return code != 0).
""" """
debug("backticks(%s)" % cmd) debug("backticks(%s)" % cmd)
proc = subprocess.Popen(cmd, stdout = subprocess.PIPE, proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr = subprocess.PIPE) stderr=subprocess.PIPE)
out, err = proc.communicate() out, err = proc.communicate()
if proc.returncode != 0: if proc.returncode != 0:
raise RuntimeError("Error executing `%s': %s" % (" ".join(cmd), err)) raise RuntimeError("Error executing `%s': %s" % (" ".join(cmd), err))
return out.decode("utf-8") return out.decode("utf-8")
def eintr_wrapper(func, *args):
T = TypeVar("T")
def eintr_wrapper(func: Callable[..., T], *args) -> T:
"Wraps some callable with a loop that retries on EINTR." "Wraps some callable with a loop that retries on EINTR."
while True: while True:
try: try:
return func(*args) return func(*args)
except OSError as ex: # pragma: no cover except OSError as ex: # pragma: no cover
if ex.errno == errno.EINTR: if ex.errno == errno.EINTR:
continue continue
raise raise
except IOError as ex: # pragma: no cover except IOError as ex: # pragma: no cover
if ex.errno == errno.EINTR: if ex.errno == errno.EINTR:
continue continue
raise raise
def find_listen_port(family = socket.AF_INET, type = socket.SOCK_STREAM,
proto = 0, addr = "127.0.0.1", min_port = 1, max_port = 65535): def find_listen_port(family=socket.AF_INET, type=socket.SOCK_STREAM,
sock = socket.socket(family, type, proto) proto=0, addr="127.0.0.1", min_port=1, max_port=65535):
sock = compat.socket(family, type, proto)
for port in range(min_port, max_port + 1): for port in range(min_port, max_port + 1):
try: try:
sock.bind((addr, port)) sock.bind((addr, port))
...@@ -134,44 +147,50 @@ def find_listen_port(family = socket.AF_INET, type = socket.SOCK_STREAM, ...@@ -134,44 +147,50 @@ def find_listen_port(family = socket.AF_INET, type = socket.SOCK_STREAM,
pass pass
raise RuntimeError("Cannot find an usable port in the range specified") raise RuntimeError("Cannot find an usable port in the range specified")
# Logging # Logging
_log_level = LOG_DEBUG _log_level = LOG_WARNING
_log_use_syslog = False _log_use_syslog = False
_log_stream = sys.stderr _log_stream = sys.stderr
_log_syslog_opts = () _log_syslog_opts = ()
_log_pid = os.getpid() _log_pid = os.getpid()
def set_log_level(level): def set_log_level(level):
"Sets the log level for console messages, does not affect syslog logging." "Sets the log level for console messages, does not affect syslog logging."
global _log_level global _log_level
assert level > LOG_ERR and level <= LOG_DEBUG assert level > LOG_ERR and level <= LOG_DEBUG
_log_level = level _log_level = level
def set_log_output(stream): def set_log_output(stream):
"Redirect console messages to the provided stream." "Redirect console messages to the provided stream."
global _log_stream global _log_stream
assert hasattr(stream, "write") and hasattr(stream, "flush") assert hasattr(stream, "write") and hasattr(stream, "flush")
_log_stream = stream _log_stream = stream
def log_use_syslog(use = True, ident = None, logopt = 0,
facility = syslog.LOG_USER): def log_use_syslog(use=True, ident=None, logopt=0,
facility=syslog.LOG_USER):
"Enable or disable the use of syslog for logging messages." "Enable or disable the use of syslog for logging messages."
global _log_use_syslog, _log_syslog_opts global _log_use_syslog, _log_syslog_opts
_log_syslog_opts = (ident, logopt, facility) _log_syslog_opts = (ident, logopt, facility)
_log_use_syslog = use _log_use_syslog = use
_init_log() _init_log()
def _init_log(): def _init_log():
if not _log_use_syslog: if not _log_use_syslog:
syslog.closelog() syslog.closelog()
return return
(ident, logopt, facility) = _log_syslog_opts (ident, logopt, facility) = _log_syslog_opts
if not ident: if not ident:
#ident = os.path.basename(sys.argv[0]) # ident = os.path.basename(sys.argv[0])
ident = "nemu" ident = "nemu"
syslog.openlog("%s[%d]" % (ident, os.getpid()), logopt, facility) syslog.openlog("%s[%d]" % (ident, os.getpid()), logopt, facility)
info("Syslog logging started") info("Syslog logging started")
def logger(priority, message): def logger(priority, message):
"Print a log message in syslog, console or both." "Print a log message in syslog, console or both."
if _log_use_syslog: if _log_use_syslog:
...@@ -183,27 +202,37 @@ def logger(priority, message): ...@@ -183,27 +202,37 @@ def logger(priority, message):
return return
eintr_wrapper(_log_stream.write, eintr_wrapper(_log_stream.write,
"[%d] %s\n" % (os.getpid(), message.rstrip())) "[%d] %s\n" % (os.getpid(), message.rstrip()))
_log_stream.flush() _log_stream.flush()
def error(message): def error(message):
logger(LOG_ERR, message) logger(LOG_ERR, message)
def warning(message): def warning(message):
logger(LOG_WARNING, message) logger(LOG_WARNING, message)
def notice(message): def notice(message):
logger(LOG_NOTICE, message) logger(LOG_NOTICE, message)
def info(message): def info(message):
logger(LOG_INFO, message) logger(LOG_INFO, message)
def debug(message): def debug(message):
logger(LOG_DEBUG, message) logger(LOG_DEBUG, message)
def _custom_hook(tipe, value, traceback): # pragma: no cover
def _custom_hook(tipe, value, traceback): # pragma: no cover
"""Custom exception hook, to print nested exceptions information.""" """Custom exception hook, to print nested exceptions information."""
if hasattr(value, "child_traceback"): if hasattr(value, "child_traceback"):
sys.stderr.write("Nested exception, original traceback " + sys.stderr.write("Nested exception, original traceback " +
"(most recent call last):\n") "(most recent call last):\n")
sys.stderr.write(value.child_traceback + ("-" * 70) + "\n") sys.stderr.write(value.child_traceback + ("-" * 70) + "\n")
sys.__excepthook__(tipe, value, traceback) sys.__excepthook__(tipe, value, traceback)
sys.excepthook = _custom_hook
sys.excepthook = _custom_hook
...@@ -40,7 +40,7 @@ class Interface(object): ...@@ -40,7 +40,7 @@ class Interface(object):
def _gen_if_name(): def _gen_if_name():
n = Interface._gen_next_id() n = Interface._gen_next_id()
# Max 15 chars # Max 15 chars
return "NETNSif-%.4x%.3x" % (os.getpid() % 0xffff, n) return "NETNSif-%.4x%.3x" % (os.getpid() & 0xffff, n)
def __init__(self, index): def __init__(self, index):
self._idx = index self._idx = index
...@@ -386,7 +386,7 @@ class Switch(ExternalInterface): ...@@ -386,7 +386,7 @@ class Switch(ExternalInterface):
def _gen_br_name(): def _gen_br_name():
n = Switch._gen_next_id() n = Switch._gen_next_id()
# Max 15 chars # Max 15 chars
return "NETNSbr-%.4x%.3x" % (os.getpid() % 0xffff, n) return "NETNSbr-%.4x%.3x" % (os.getpid() & 0xffff, n)
def __init__(self, **args): def __init__(self, **args):
"""Creates a new Switch object, which models a linux bridge device. """Creates a new Switch object, which models a linux bridge device.
......
...@@ -27,6 +27,7 @@ import weakref ...@@ -27,6 +27,7 @@ import weakref
import nemu.interface import nemu.interface
import nemu.protocol import nemu.protocol
import nemu.subprocess_ import nemu.subprocess_
from nemu import compat
from nemu.environ import * from nemu.environ import *
__all__ = ['Node', 'get_nodes', 'import_if'] __all__ = ['Node', 'get_nodes', 'import_if']
...@@ -195,7 +196,7 @@ class Node(object): ...@@ -195,7 +196,7 @@ class Node(object):
# Requires CAP_SYS_ADMIN privileges to run. # Requires CAP_SYS_ADMIN privileges to run.
def _start_child(nonetns) -> (socket.socket, int): def _start_child(nonetns) -> (socket.socket, int):
# Create socket pair to communicate # Create socket pair to communicate
(s0, s1) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0) (s0, s1) = compat.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0)
# Spawn a child that will run in a loop # Spawn a child that will run in a loop
pid = os.fork() pid = os.fork()
if pid: if pid:
......
This diff is collapsed.
This diff is collapsed.
...@@ -6,14 +6,16 @@ import nemu.protocol ...@@ -6,14 +6,16 @@ import nemu.protocol
import os, socket, sys, threading, unittest import os, socket, sys, threading, unittest
import test_util import test_util
from nemu import compat
class TestServer(unittest.TestCase): class TestServer(unittest.TestCase):
@test_util.skip("python 3 can't makefile a socket in r+")
def test_server_startup(self): def test_server_startup(self):
# Test the creation of the server object with different ways of passing # Test the creation of the server object with different ways of passing
# the file descriptor; and check the banner. # the file descriptor; and check the banner.
(s0, s1) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0) (s0, s1) = compat.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0)
(s2, s3) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0) (s2, s3) = compat.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0)
def test_help(fd): def test_help(fd):
fd.write("HELP\n") fd.write("HELP\n")
...@@ -34,13 +36,13 @@ class TestServer(unittest.TestCase): ...@@ -34,13 +36,13 @@ class TestServer(unittest.TestCase):
t = threading.Thread(target = run_server) t = threading.Thread(target = run_server)
t.start() t.start()
s = os.fdopen(s1.fileno(), "r+", 1) s = os.fdopen(s1.fileno(), "r", 1)
self.assertEqual(s.readline()[0:4], "220 ") self.assertEqual(s.readline()[0:4], "220 ")
test_help(s) test_help(s)
s.close() s.close()
s0.close() s0.close()
s = os.fdopen(s3.fileno(), "r+", 1) s = os.fdopen(s3.fileno(), "r", 1)
self.assertEqual(s.readline()[0:4], "220 ") self.assertEqual(s.readline()[0:4], "220 ")
test_help(s) test_help(s)
s.close() s.close()
...@@ -48,7 +50,7 @@ class TestServer(unittest.TestCase): ...@@ -48,7 +50,7 @@ class TestServer(unittest.TestCase):
t.join() t.join()
def test_server_clean(self): def test_server_clean(self):
(s0, s1) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0) (s0, s1) = compat.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0)
def run_server(): def run_server():
nemu.protocol.Server(s0, s0).run() nemu.protocol.Server(s0, s0).run()
...@@ -56,8 +58,9 @@ class TestServer(unittest.TestCase): ...@@ -56,8 +58,9 @@ class TestServer(unittest.TestCase):
t.start() t.start()
cli = nemu.protocol.Client(s1, s1) cli = nemu.protocol.Client(s1, s1)
argv = [ '/bin/sh', '-c', 'yes' ] argv = [ '/bin/sh', '-c', 'yes' ]
pid = cli.spawn(argv, stdout = subprocess.DEVNULL) nullfd = open("/dev/null", "wb")
pid = cli.spawn(argv, stdout = nullfd.fileno())
self.assertTrue(os.path.exists("/proc/%d" % pid)) self.assertTrue(os.path.exists("/proc/%d" % pid))
# try to exit while there are still processes running # try to exit while there are still processes running
cli.shutdown() cli.shutdown()
...@@ -68,7 +71,7 @@ class TestServer(unittest.TestCase): ...@@ -68,7 +71,7 @@ class TestServer(unittest.TestCase):
self.assertFalse(os.path.exists("/proc/%d" % pid)) self.assertFalse(os.path.exists("/proc/%d" % pid))
def test_spawn_recovery(self): def test_spawn_recovery(self):
(s0, s1) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0) (s0, s1) = compat.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0)
def run_server(): def run_server():
nemu.protocol.Server(s0, s0).run() nemu.protocol.Server(s0, s0).run()
...@@ -93,7 +96,7 @@ class TestServer(unittest.TestCase): ...@@ -93,7 +96,7 @@ class TestServer(unittest.TestCase):
@test_util.skip("python 3 can't makefile a socket in r+") @test_util.skip("python 3 can't makefile a socket in r+")
def test_basic_stuff(self): def test_basic_stuff(self):
(s0, s1) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0) (s0, s1) = compat.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0)
srv = nemu.protocol.Server(s0, s0) srv = nemu.protocol.Server(s0, s0)
s1 = s1.makefile("r+", 1) s1 = s1.makefile("r+", 1)
......
...@@ -6,6 +6,9 @@ import nemu, test_util ...@@ -6,6 +6,9 @@ import nemu, test_util
import nemu.subprocess_ as sp import nemu.subprocess_ as sp
import grp, os, pwd, signal, socket, sys, time, unittest import grp, os, pwd, signal, socket, sys, time, unittest
from nemu import compat
def _stat(path): def _stat(path):
try: try:
return os.stat(path) return os.stat(path)
...@@ -104,7 +107,7 @@ class TestSubprocess(unittest.TestCase): ...@@ -104,7 +107,7 @@ class TestSubprocess(unittest.TestCase):
# uses a default search path # uses a default search path
self.assertRaises(OSError, sp.spawn, 'sleep', env = {'PATH': ''}) self.assertRaises(OSError, sp.spawn, 'sleep', env = {'PATH': ''})
r, w = os.pipe() r, w = compat.pipe()
p = sp.spawn('/bin/echo', ['echo', 'hello world'], stdout = w) p = sp.spawn('/bin/echo', ['echo', 'hello world'], stdout = w)
os.close(w) os.close(w)
self.assertEqual(_readall(r), b"hello world\n") self.assertEqual(_readall(r), b"hello world\n")
...@@ -120,8 +123,8 @@ class TestSubprocess(unittest.TestCase): ...@@ -120,8 +123,8 @@ class TestSubprocess(unittest.TestCase):
# It cannot be wait()ed again. # It cannot be wait()ed again.
self.assertRaises(OSError, sp.wait, p) self.assertRaises(OSError, sp.wait, p)
r0, w0 = os.pipe() r0, w0 = compat.pipe()
r1, w1 = os.pipe() r1, w1 = compat.pipe()
p = sp.spawn('/bin/cat', stdout = w0, stdin = r1, close_fds = [r0, w1]) p = sp.spawn('/bin/cat', stdout = w0, stdin = r1, close_fds = [r0, w1])
os.close(w0) os.close(w0)
os.close(r1) os.close(r1)
...@@ -140,25 +143,25 @@ class TestSubprocess(unittest.TestCase): ...@@ -140,25 +143,25 @@ class TestSubprocess(unittest.TestCase):
self.assertRaises(ValueError, node.Subprocess, self.assertRaises(ValueError, node.Subprocess,
['/bin/sleep', '1000'], user = self.nouid) ['/bin/sleep', '1000'], user = self.nouid)
# Invalid CWD: it is a file # Invalid CWD: it is a file
self.assertRaises(OSError, node.Subprocess, self.assertRaises(NotADirectoryError, node.Subprocess,
'/bin/sleep', cwd = '/bin/sleep') '/bin/sleep', cwd = '/bin/sleep')
# Invalid CWD: does not exist # Invalid CWD: does not exist
self.assertRaises(OSError, node.Subprocess, self.assertRaises(FileNotFoundError, node.Subprocess,
'/bin/sleep', cwd = self.nofile) '/bin/sleep', cwd = self.nofile)
# Exec failure # Exec failure
self.assertRaises(OSError, node.Subprocess, self.nofile) self.assertRaises(FileNotFoundError, node.Subprocess, self.nofile)
# Test that the environment is cleared: sleep should not be found # Test that the environment is cleared: sleep should not be found
self.assertRaises(OSError, node.Subprocess, self.assertRaises(FileNotFoundError, node.Subprocess,
'sleep', env = {'PATH': ''}) 'sleep', env = {'PATH': ''})
# Argv # Argv
self.assertRaises(OSError, node.Subprocess, 'true; false') self.assertRaises(FileNotFoundError, node.Subprocess, 'true; false')
self.assertEqual(node.Subprocess('true').wait(), 0) self.assertEqual(node.Subprocess('true').wait(), 0)
self.assertEqual(node.Subprocess('true; false', shell = True).wait(), self.assertEqual(node.Subprocess('true; false', shell = True).wait(),
1) 1)
# Piping # Piping
r, w = os.pipe() r, w = compat.pipe()
p = node.Subprocess(['echo', 'hello world'], stdout = w) p = node.Subprocess(['echo', 'hello world'], stdout = w)
os.close(w) os.close(w)
self.assertEqual(_readall(r), b"hello world\n") self.assertEqual(_readall(r), b"hello world\n")
...@@ -166,7 +169,7 @@ class TestSubprocess(unittest.TestCase): ...@@ -166,7 +169,7 @@ class TestSubprocess(unittest.TestCase):
p.wait() p.wait()
# cwd # cwd
r, w = os.pipe() r, w = compat.pipe()
p = node.Subprocess('/bin/pwd', stdout = w, cwd = "/") p = node.Subprocess('/bin/pwd', stdout = w, cwd = "/")
os.close(w) os.close(w)
self.assertEqual(_readall(r), b"/\n") self.assertEqual(_readall(r), b"/\n")
...@@ -194,7 +197,7 @@ class TestSubprocess(unittest.TestCase): ...@@ -194,7 +197,7 @@ class TestSubprocess(unittest.TestCase):
# closing stdout (so _readall finishes) # closing stdout (so _readall finishes)
cmd = 'trap "" TERM; echo; exec sleep 100 > /dev/null' cmd = 'trap "" TERM; echo; exec sleep 100 > /dev/null'
r, w = os.pipe() r, w = compat.pipe()
p = node.Subprocess(cmd, shell = True, stdout = w) p = node.Subprocess(cmd, shell = True, stdout = w)
os.close(w) os.close(w)
self.assertEqual(_readall(r), b"\n") # wait for trap to be installed self.assertEqual(_readall(r), b"\n") # wait for trap to be installed
...@@ -202,9 +205,10 @@ class TestSubprocess(unittest.TestCase): ...@@ -202,9 +205,10 @@ class TestSubprocess(unittest.TestCase):
pid = p.pid pid = p.pid
os.kill(pid, 0) # verify process still there os.kill(pid, 0) # verify process still there
# Avoid the warning about the process being killed # Avoid the warning about the process being killed
old_err = sys.stderr
with open("/dev/null", "w") as sys.stderr: with open("/dev/null", "w") as sys.stderr:
p.destroy() p.destroy()
sys.stderr = sys.__stderr__ sys.stderr = old_err
self.assertRaises(OSError, os.kill, pid, 0) # should be dead by now self.assertRaises(OSError, os.kill, pid, 0) # should be dead by now
p = node.Subprocess(['sleep', '100']) p = node.Subprocess(['sleep', '100'])
...@@ -217,8 +221,8 @@ class TestSubprocess(unittest.TestCase): ...@@ -217,8 +221,8 @@ class TestSubprocess(unittest.TestCase):
node = nemu.Node(nonetns = True) node = nemu.Node(nonetns = True)
# repeat test with Popen interface # repeat test with Popen interface
r0, w0 = os.pipe() r0, w0 = compat.pipe()
r1, w1 = os.pipe() r1, w1 = compat.pipe()
p = node.Popen('cat', stdout = w0, stdin = r1) p = node.Popen('cat', stdout = w0, stdin = r1)
os.close(w0) os.close(w0)
os.close(r1) os.close(r1)
...@@ -228,7 +232,7 @@ class TestSubprocess(unittest.TestCase): ...@@ -228,7 +232,7 @@ class TestSubprocess(unittest.TestCase):
os.close(r0) os.close(r0)
# now with a socketpair, not using integers # now with a socketpair, not using integers
(s0, s1) = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0) (s0, s1) = compat.socketpair(socket.AF_UNIX, socket.SOCK_STREAM, 0)
p = node.Popen('cat', stdout = s0, stdin = s0) p = node.Popen('cat', stdout = s0, stdin = s0)
s0.close() s0.close()
s1.send(b"hello world\n") s1.send(b"hello world\n")
...@@ -255,9 +259,9 @@ class TestSubprocess(unittest.TestCase): ...@@ -255,9 +259,9 @@ class TestSubprocess(unittest.TestCase):
p = node.Popen('cat >&2', shell = True, stdin = sp.PIPE, p = node.Popen('cat >&2', shell = True, stdin = sp.PIPE,
stderr = sp.PIPE) stderr = sp.PIPE)
p.stdin.write("hello world\n") p.stdin.write(b"hello world\n")
p.stdin.close() p.stdin.close()
self.assertEqual(p.stderr.readlines(), ["hello world\n"]) self.assertEqual(p.stderr.readlines(), [b"hello world\n"])
self.assertEqual(p.stdout, None) self.assertEqual(p.stdout, None)
self.assertEqual(p.wait(), 0) self.assertEqual(p.wait(), 0)
...@@ -268,9 +272,9 @@ class TestSubprocess(unittest.TestCase): ...@@ -268,9 +272,9 @@ class TestSubprocess(unittest.TestCase):
# #
p = node.Popen(['sh', '-c', 'cat >&2'], p = node.Popen(['sh', '-c', 'cat >&2'],
stdin = sp.PIPE, stdout = sp.PIPE, stderr = sp.STDOUT) stdin = sp.PIPE, stdout = sp.PIPE, stderr = sp.STDOUT)
p.stdin.write("hello world\n") p.stdin.write(b"hello world\n")
p.stdin.close() p.stdin.close()
self.assertEqual(p.stdout.readlines(), ["hello world\n"]) self.assertEqual(p.stdout.readlines(), [b"hello world\n"])
self.assertEqual(p.stderr, None) self.assertEqual(p.stderr, None)
self.assertEqual(p.wait(), 0) self.assertEqual(p.wait(), 0)
...@@ -281,9 +285,9 @@ class TestSubprocess(unittest.TestCase): ...@@ -281,9 +285,9 @@ class TestSubprocess(unittest.TestCase):
# #
p = node.Popen(['tee', '/dev/stderr'], p = node.Popen(['tee', '/dev/stderr'],
stdin = sp.PIPE, stdout = sp.PIPE, stderr = sp.STDOUT) stdin = sp.PIPE, stdout = sp.PIPE, stderr = sp.STDOUT)
p.stdin.write("hello world\n") p.stdin.write(b"hello world\n")
p.stdin.close() p.stdin.close()
self.assertEqual(p.stdout.readlines(), ["hello world\n"] * 2) self.assertEqual(p.stdout.readlines(), [b"hello world\n"] * 2)
self.assertEqual(p.stderr, None) self.assertEqual(p.stderr, None)
self.assertEqual(p.wait(), 0) self.assertEqual(p.wait(), 0)
...@@ -295,10 +299,10 @@ class TestSubprocess(unittest.TestCase): ...@@ -295,10 +299,10 @@ class TestSubprocess(unittest.TestCase):
# #
p = node.Popen(['tee', '/dev/stderr'], p = node.Popen(['tee', '/dev/stderr'],
stdin = sp.PIPE, stdout = sp.PIPE, stderr = sp.PIPE) stdin = sp.PIPE, stdout = sp.PIPE, stderr = sp.PIPE)
p.stdin.write("hello world\n") p.stdin.write(b"hello world\n")
p.stdin.close() p.stdin.close()
self.assertEqual(p.stdout.readlines(), ["hello world\n"]) self.assertEqual(p.stdout.readlines(), [b"hello world\n"])
self.assertEqual(p.stderr.readlines(), ["hello world\n"]) self.assertEqual(p.stderr.readlines(), [b"hello world\n"])
self.assertEqual(p.wait(), 0) self.assertEqual(p.wait(), 0)
p = node.Popen(['tee', '/dev/stderr'], p = node.Popen(['tee', '/dev/stderr'],
......
...@@ -5,7 +5,7 @@ import os, re, subprocess, sys ...@@ -5,7 +5,7 @@ import os, re, subprocess, sys
import nemu.subprocess_ import nemu.subprocess_
from nemu.environ import * from nemu.environ import *
def process_ipcmd(str): def process_ipcmd(str: str):
cur = None cur = None
out = {} out = {}
for line in str.split("\n"): for line in str.split("\n"):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment