test_ioctl.py 3.19 KB
Newer Older
1
import array
Michael W. Hudson's avatar
Michael W. Hudson committed
2
import unittest
3
from test.support import import_module, get_attribute
Michael W. Hudson's avatar
Michael W. Hudson committed
4
import os, struct
5 6 7
fcntl = import_module('fcntl')
termios = import_module('termios')
get_attribute(termios, 'TIOCGPGRP') #Can't run tests without this feature
Michael W. Hudson's avatar
Michael W. Hudson committed
8

9
try:
10
    tty = open("/dev/tty", "rb")
11
except OSError:
Benjamin Peterson's avatar
Benjamin Peterson committed
12
    raise unittest.SkipTest("Unable to open /dev/tty")
13 14 15 16 17 18 19 20 21
else:
    # Skip if another process is in foreground
    r = fcntl.ioctl(tty, termios.TIOCGPGRP, "    ")
    tty.close()
    rpgrp = struct.unpack("i", r)[0]
    if rpgrp not in (os.getpgrp(), os.getsid(0)):
        raise unittest.SkipTest("Neither the process group nor the session "
                                "are attached to /dev/tty")
    del tty, r, rpgrp
22

23 24 25 26 27
try:
    import pty
except ImportError:
    pty = None

Michael W. Hudson's avatar
Michael W. Hudson committed
28 29
class IoctlTests(unittest.TestCase):
    def test_ioctl(self):
30 31 32
        # If this process has been put into the background, TIOCGPGRP returns
        # the session ID instead of the process group id.
        ids = (os.getpgrp(), os.getsid(0))
33
        with open("/dev/tty", "rb") as tty:
34 35 36
            r = fcntl.ioctl(tty, termios.TIOCGPGRP, "    ")
            rpgrp = struct.unpack("i", r)[0]
            self.assertIn(rpgrp, ids)
Michael W. Hudson's avatar
Michael W. Hudson committed
37

38 39 40
    def _check_ioctl_mutate_len(self, nbytes=None):
        buf = array.array('i')
        intsize = buf.itemsize
41
        ids = (os.getpgrp(), os.getsid(0))
42 43 44 45 46 47 48 49
        # A fill value unlikely to be in `ids`
        fill = -12345
        if nbytes is not None:
            # Extend the buffer so that it is exactly `nbytes` bytes long
            buf.extend([fill] * (nbytes // intsize))
            self.assertEqual(len(buf) * intsize, nbytes)   # sanity check
        else:
            buf.append(fill)
50
        with open("/dev/tty", "rb") as tty:
51
            r = fcntl.ioctl(tty, termios.TIOCGPGRP, buf, 1)
52
        rpgrp = buf[0]
53
        self.assertEqual(r, 0)
54
        self.assertIn(rpgrp, ids)
Michael W. Hudson's avatar
Michael W. Hudson committed
55

56 57 58 59 60 61 62 63 64 65 66 67
    def test_ioctl_mutate(self):
        self._check_ioctl_mutate_len()

    def test_ioctl_mutate_1024(self):
        # Issue #9758: a mutable buffer of exactly 1024 bytes wouldn't be
        # copied back after the system call.
        self._check_ioctl_mutate_len(1024)

    def test_ioctl_mutate_2048(self):
        # Test with a larger buffer, just for the record.
        self._check_ioctl_mutate_len(2048)

68 69
    def test_ioctl_signed_unsigned_code_param(self):
        if not pty:
Benjamin Peterson's avatar
Benjamin Peterson committed
70
            raise unittest.SkipTest('pty module required')
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
        mfd, sfd = pty.openpty()
        try:
            if termios.TIOCSWINSZ < 0:
                set_winsz_opcode_maybe_neg = termios.TIOCSWINSZ
                set_winsz_opcode_pos = termios.TIOCSWINSZ & 0xffffffff
            else:
                set_winsz_opcode_pos = termios.TIOCSWINSZ
                set_winsz_opcode_maybe_neg, = struct.unpack("i",
                        struct.pack("I", termios.TIOCSWINSZ))

            our_winsz = struct.pack("HHHH",80,25,0,0)
            # test both with a positive and potentially negative ioctl code
            new_winsz = fcntl.ioctl(mfd, set_winsz_opcode_pos, our_winsz)
            new_winsz = fcntl.ioctl(mfd, set_winsz_opcode_maybe_neg, our_winsz)
        finally:
            os.close(mfd)
            os.close(sfd)

Michael W. Hudson's avatar
Michael W. Hudson committed
89 90

if __name__ == "__main__":
91
    unittest.main()