test_ioctl.py 3.2 KB

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