Antoine Pitrou | 5e38aae | 2010-09-07 16:30:09 +0000 | [diff] [blame] | 1 | import array |
Michael W. Hudson | f008998 | 2003-03-03 12:29:42 +0000 | [diff] [blame] | 2 | import unittest |
Hai Shi | f7ba40b | 2020-06-25 18:38:51 +0800 | [diff] [blame] | 3 | from test.support import get_attribute |
| 4 | from test.support.import_helper import import_module |
Michael W. Hudson | f008998 | 2003-03-03 12:29:42 +0000 | [diff] [blame] | 5 | import os, struct |
R. David Murray | a21e4ca | 2009-03-31 23:16:50 +0000 | [diff] [blame] | 6 | fcntl = import_module('fcntl') |
| 7 | termios = import_module('termios') |
| 8 | get_attribute(termios, 'TIOCGPGRP') #Can't run tests without this feature |
Michael W. Hudson | f008998 | 2003-03-03 12:29:42 +0000 | [diff] [blame] | 9 | |
Neal Norwitz | 26f42f6 | 2003-03-20 04:33:16 +0000 | [diff] [blame] | 10 | try: |
Victor Stinner | a6d2c76 | 2011-06-30 18:20:11 +0200 | [diff] [blame] | 11 | tty = open("/dev/tty", "rb") |
Andrew Svetlov | f7a17b4 | 2012-12-25 16:47:37 +0200 | [diff] [blame] | 12 | except OSError: |
Benjamin Peterson | e549ead | 2009-03-28 21:42:05 +0000 | [diff] [blame] | 13 | raise unittest.SkipTest("Unable to open /dev/tty") |
Florent Xicluna | 39d795d | 2010-08-08 18:06:13 +0000 | [diff] [blame] | 14 | else: |
Serhiy Storchaka | 5b10b98 | 2019-03-05 10:06:26 +0200 | [diff] [blame] | 15 | with tty: |
| 16 | # Skip if another process is in foreground |
| 17 | r = fcntl.ioctl(tty, termios.TIOCGPGRP, " ") |
Florent Xicluna | 39d795d | 2010-08-08 18:06:13 +0000 | [diff] [blame] | 18 | rpgrp = struct.unpack("i", r)[0] |
| 19 | if rpgrp not in (os.getpgrp(), os.getsid(0)): |
| 20 | raise unittest.SkipTest("Neither the process group nor the session " |
| 21 | "are attached to /dev/tty") |
| 22 | del tty, r, rpgrp |
Neal Norwitz | 26f42f6 | 2003-03-20 04:33:16 +0000 | [diff] [blame] | 23 | |
Christian Heimes | e25f35e | 2008-03-20 10:49:03 +0000 | [diff] [blame] | 24 | try: |
| 25 | import pty |
| 26 | except ImportError: |
| 27 | pty = None |
| 28 | |
Michael W. Hudson | f008998 | 2003-03-03 12:29:42 +0000 | [diff] [blame] | 29 | class IoctlTests(unittest.TestCase): |
| 30 | def test_ioctl(self): |
Guido van Rossum | 8ee3e5a | 2005-09-14 18:09:42 +0000 | [diff] [blame] | 31 | # If this process has been put into the background, TIOCGPGRP returns |
| 32 | # the session ID instead of the process group id. |
| 33 | ids = (os.getpgrp(), os.getsid(0)) |
Victor Stinner | a6d2c76 | 2011-06-30 18:20:11 +0200 | [diff] [blame] | 34 | with open("/dev/tty", "rb") as tty: |
Brett Cannon | dff6985 | 2010-10-29 23:54:28 +0000 | [diff] [blame] | 35 | r = fcntl.ioctl(tty, termios.TIOCGPGRP, " ") |
| 36 | rpgrp = struct.unpack("i", r)[0] |
| 37 | self.assertIn(rpgrp, ids) |
Michael W. Hudson | f008998 | 2003-03-03 12:29:42 +0000 | [diff] [blame] | 38 | |
Antoine Pitrou | 5e38aae | 2010-09-07 16:30:09 +0000 | [diff] [blame] | 39 | def _check_ioctl_mutate_len(self, nbytes=None): |
| 40 | buf = array.array('i') |
| 41 | intsize = buf.itemsize |
Guido van Rossum | 8ee3e5a | 2005-09-14 18:09:42 +0000 | [diff] [blame] | 42 | ids = (os.getpgrp(), os.getsid(0)) |
Antoine Pitrou | 5e38aae | 2010-09-07 16:30:09 +0000 | [diff] [blame] | 43 | # A fill value unlikely to be in `ids` |
| 44 | fill = -12345 |
| 45 | if nbytes is not None: |
| 46 | # Extend the buffer so that it is exactly `nbytes` bytes long |
| 47 | buf.extend([fill] * (nbytes // intsize)) |
| 48 | self.assertEqual(len(buf) * intsize, nbytes) # sanity check |
| 49 | else: |
| 50 | buf.append(fill) |
Victor Stinner | a6d2c76 | 2011-06-30 18:20:11 +0200 | [diff] [blame] | 51 | with open("/dev/tty", "rb") as tty: |
Serhiy Storchaka | 1f21eaa | 2019-09-01 12:16:51 +0300 | [diff] [blame] | 52 | r = fcntl.ioctl(tty, termios.TIOCGPGRP, buf, True) |
Guido van Rossum | 8ee3e5a | 2005-09-14 18:09:42 +0000 | [diff] [blame] | 53 | rpgrp = buf[0] |
Ezio Melotti | b3aedd4 | 2010-11-20 19:04:17 +0000 | [diff] [blame] | 54 | self.assertEqual(r, 0) |
Benjamin Peterson | 577473f | 2010-01-19 00:09:57 +0000 | [diff] [blame] | 55 | self.assertIn(rpgrp, ids) |
Michael W. Hudson | f008998 | 2003-03-03 12:29:42 +0000 | [diff] [blame] | 56 | |
Antoine Pitrou | 5e38aae | 2010-09-07 16:30:09 +0000 | [diff] [blame] | 57 | def test_ioctl_mutate(self): |
| 58 | self._check_ioctl_mutate_len() |
| 59 | |
| 60 | def test_ioctl_mutate_1024(self): |
| 61 | # Issue #9758: a mutable buffer of exactly 1024 bytes wouldn't be |
| 62 | # copied back after the system call. |
| 63 | self._check_ioctl_mutate_len(1024) |
| 64 | |
| 65 | def test_ioctl_mutate_2048(self): |
| 66 | # Test with a larger buffer, just for the record. |
| 67 | self._check_ioctl_mutate_len(2048) |
| 68 | |
Christian Heimes | e25f35e | 2008-03-20 10:49:03 +0000 | [diff] [blame] | 69 | def test_ioctl_signed_unsigned_code_param(self): |
| 70 | if not pty: |
Benjamin Peterson | e549ead | 2009-03-28 21:42:05 +0000 | [diff] [blame] | 71 | raise unittest.SkipTest('pty module required') |
Christian Heimes | e25f35e | 2008-03-20 10:49:03 +0000 | [diff] [blame] | 72 | mfd, sfd = pty.openpty() |
| 73 | try: |
| 74 | if termios.TIOCSWINSZ < 0: |
| 75 | set_winsz_opcode_maybe_neg = termios.TIOCSWINSZ |
| 76 | set_winsz_opcode_pos = termios.TIOCSWINSZ & 0xffffffff |
| 77 | else: |
| 78 | set_winsz_opcode_pos = termios.TIOCSWINSZ |
| 79 | set_winsz_opcode_maybe_neg, = struct.unpack("i", |
| 80 | struct.pack("I", termios.TIOCSWINSZ)) |
| 81 | |
Christian Heimes | e25f35e | 2008-03-20 10:49:03 +0000 | [diff] [blame] | 82 | our_winsz = struct.pack("HHHH",80,25,0,0) |
| 83 | # test both with a positive and potentially negative ioctl code |
| 84 | new_winsz = fcntl.ioctl(mfd, set_winsz_opcode_pos, our_winsz) |
| 85 | new_winsz = fcntl.ioctl(mfd, set_winsz_opcode_maybe_neg, our_winsz) |
Christian Heimes | e25f35e | 2008-03-20 10:49:03 +0000 | [diff] [blame] | 86 | finally: |
| 87 | os.close(mfd) |
| 88 | os.close(sfd) |
| 89 | |
Michael W. Hudson | f008998 | 2003-03-03 12:29:42 +0000 | [diff] [blame] | 90 | |
| 91 | if __name__ == "__main__": |
Brett Cannon | 3e9a9ae | 2013-06-12 21:25:59 -0400 | [diff] [blame] | 92 | unittest.main() |