Home | History | Annotate | Download | only in test
      1 import array
      2 import unittest
      3 from test.support import import_module, get_attribute
      4 import os, struct
      5 fcntl = import_module('fcntl')
      6 termios = import_module('termios')
      7 get_attribute(termios, 'TIOCGPGRP') #Can't run tests without this feature
      8 
      9 try:
     10     tty = open("/dev/tty", "rb")
     11 except OSError:
     12     raise unittest.SkipTest("Unable to open /dev/tty")
     13 else:
     14     # Skip if another process is in foreground
     15     r = fcntl.ioctl(tty, termios.TIOCGPGRP, "    ")
     16     tty.close()
     17     rpgrp = struct.unpack("i", r)[0]
     18     if rpgrp not in (os.getpgrp(), os.getsid(0)):
     19         raise unittest.SkipTest("Neither the process group nor the session "
     20                                 "are attached to /dev/tty")
     21     del tty, r, rpgrp
     22 
     23 try:
     24     import pty
     25 except ImportError:
     26     pty = None
     27 
     28 class IoctlTests(unittest.TestCase):
     29     def test_ioctl(self):
     30         # If this process has been put into the background, TIOCGPGRP returns
     31         # the session ID instead of the process group id.
     32         ids = (os.getpgrp(), os.getsid(0))
     33         with open("/dev/tty", "rb") as tty:
     34             r = fcntl.ioctl(tty, termios.TIOCGPGRP, "    ")
     35             rpgrp = struct.unpack("i", r)[0]
     36             self.assertIn(rpgrp, ids)
     37 
     38     def _check_ioctl_mutate_len(self, nbytes=None):
     39         buf = array.array('i')
     40         intsize = buf.itemsize
     41         ids = (os.getpgrp(), os.getsid(0))
     42         # A fill value unlikely to be in `ids`
     43         fill = -12345
     44         if nbytes is not None:
     45             # Extend the buffer so that it is exactly `nbytes` bytes long
     46             buf.extend([fill] * (nbytes // intsize))
     47             self.assertEqual(len(buf) * intsize, nbytes)   # sanity check
     48         else:
     49             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)
     55 
     56     def test_ioctl_mutate(self):
     57         self._check_ioctl_mutate_len()
     58 
     59     def test_ioctl_mutate_1024(self):
     60         # Issue #9758: a mutable buffer of exactly 1024 bytes wouldn't be
     61         # copied back after the system call.
     62         self._check_ioctl_mutate_len(1024)
     63 
     64     def test_ioctl_mutate_2048(self):
     65         # Test with a larger buffer, just for the record.
     66         self._check_ioctl_mutate_len(2048)
     67 
     68     def test_ioctl_signed_unsigned_code_param(self):
     69         if not pty:
     70             raise unittest.SkipTest('pty module required')
     71         mfd, sfd = pty.openpty()
     72         try:
     73             if termios.TIOCSWINSZ < 0:
     74                 set_winsz_opcode_maybe_neg = termios.TIOCSWINSZ
     75                 set_winsz_opcode_pos = termios.TIOCSWINSZ & 0xffffffff
     76             else:
     77                 set_winsz_opcode_pos = termios.TIOCSWINSZ
     78                 set_winsz_opcode_maybe_neg, = struct.unpack("i",
     79                         struct.pack("I", termios.TIOCSWINSZ))
     80 
     81             our_winsz = struct.pack("HHHH",80,25,0,0)
     82             # test both with a positive and potentially negative ioctl code
     83             new_winsz = fcntl.ioctl(mfd, set_winsz_opcode_pos, our_winsz)
     84             new_winsz = fcntl.ioctl(mfd, set_winsz_opcode_maybe_neg, our_winsz)
     85         finally:
     86             os.close(mfd)
     87             os.close(sfd)
     88 
     89 
     90 if __name__ == "__main__":
     91     unittest.main()
     92