14
14
else :
15
15
with tty :
16
16
# Skip if another process is in foreground
17
- r = fcntl .ioctl (tty , termios .TIOCGPGRP , " " )
17
+ r = fcntl .ioctl (tty , termios .TIOCGPGRP , struct . pack ( "i" , 0 ) )
18
18
rpgrp = struct .unpack ("i" , r )[0 ]
19
19
if rpgrp not in (os .getpgrp (), os .getsid (0 )):
20
20
raise unittest .SkipTest ("Neither the process group nor the session "
27
27
pty = None
28
28
29
29
class IoctlTests (unittest .TestCase ):
30
- def test_ioctl (self ):
30
+ def test_ioctl_immutable_buf (self ):
31
31
# If this process has been put into the background, TIOCGPGRP returns
32
32
# the session ID instead of the process group id.
33
33
ids = (os .getpgrp (), os .getsid (0 ))
34
34
with open ("/dev/tty" , "rb" ) as tty :
35
- r = fcntl .ioctl (tty , termios .TIOCGPGRP , " " )
36
- rpgrp = struct .unpack ("i" , r )[0 ]
35
+ # string
36
+ buf = " " * 8
37
+ r = fcntl .ioctl (tty , termios .TIOCGPGRP , buf )
38
+ self .assertIsInstance (r , bytes )
39
+ rpgrp = memoryview (r ).cast ('i' )[0 ]
37
40
self .assertIn (rpgrp , ids )
38
41
39
- def _check_ioctl_mutate_len (self , nbytes = None ):
42
+ # bytes
43
+ buf = b" " * 8
44
+ r = fcntl .ioctl (tty , termios .TIOCGPGRP , buf )
45
+ self .assertIsInstance (r , bytes )
46
+ rpgrp = memoryview (r ).cast ('i' )[0 ]
47
+ self .assertIn (rpgrp , ids )
48
+
49
+ # read-only buffer
50
+ r = fcntl .ioctl (tty , termios .TIOCGPGRP , memoryview (buf ))
51
+ self .assertIsInstance (r , bytes )
52
+ rpgrp = memoryview (r ).cast ('i' )[0 ]
53
+ self .assertIn (rpgrp , ids )
54
+
55
+ def test_ioctl_mutable_buf (self ):
56
+ ids = (os .getpgrp (), os .getsid (0 ))
57
+ with open ("/dev/tty" , "rb" ) as tty :
58
+ buf = bytearray (b" " * 8 )
59
+ r = fcntl .ioctl (tty , termios .TIOCGPGRP , buf )
60
+ self .assertEqual (r , 0 )
61
+ rpgrp = memoryview (buf ).cast ('i' )[0 ]
62
+ self .assertIn (rpgrp , ids )
63
+
64
+ def test_ioctl_no_mutate_buf (self ):
65
+ ids = (os .getpgrp (), os .getsid (0 ))
66
+ with open ("/dev/tty" , "rb" ) as tty :
67
+ buf = bytearray (b" " * 8 )
68
+ save_buf = bytes (buf )
69
+ r = fcntl .ioctl (tty , termios .TIOCGPGRP , buf , False )
70
+ self .assertEqual (bytes (buf ), save_buf )
71
+ self .assertIsInstance (r , bytes )
72
+ rpgrp = memoryview (r ).cast ('i' )[0 ]
73
+ self .assertIn (rpgrp , ids )
74
+
75
+ def _create_int_buf (self , nbytes = None ):
40
76
buf = array .array ('i' )
41
77
intsize = buf .itemsize
42
- ids = (os .getpgrp (), os .getsid (0 ))
43
78
# A fill value unlikely to be in `ids`
44
79
fill = - 12345
45
80
if nbytes is not None :
@@ -48,23 +83,59 @@ def _check_ioctl_mutate_len(self, nbytes=None):
48
83
self .assertEqual (len (buf ) * intsize , nbytes ) # sanity check
49
84
else :
50
85
buf .append (fill )
86
+ return buf
87
+
88
+ def _check_ioctl_mutate_len (self , nbytes = None ):
89
+ ids = (os .getpgrp (), os .getsid (0 ))
90
+ buf = self ._create_int_buf (nbytes )
51
91
with open ("/dev/tty" , "rb" ) as tty :
52
- r = fcntl .ioctl (tty , termios .TIOCGPGRP , buf , True )
92
+ r = fcntl .ioctl (tty , termios .TIOCGPGRP , buf )
53
93
rpgrp = buf [0 ]
54
94
self .assertEqual (r , 0 )
55
95
self .assertIn (rpgrp , ids )
56
96
97
+ def _check_ioctl_not_mutate_len (self , nbytes = None ):
98
+ ids = (os .getpgrp (), os .getsid (0 ))
99
+ buf = self ._create_int_buf (nbytes )
100
+ save_buf = bytes (buf )
101
+ with open ("/dev/tty" , "rb" ) as tty :
102
+ r = fcntl .ioctl (tty , termios .TIOCGPGRP , buf , False )
103
+ self .assertIsInstance (r , bytes )
104
+ self .assertEqual (len (r ), len (save_buf ))
105
+ self .assertEqual (bytes (buf ), save_buf )
106
+ rpgrp = array .array ('i' , r )[0 ]
107
+ rpgrp = memoryview (r ).cast ('i' )[0 ]
108
+ self .assertIn (rpgrp , ids )
109
+
110
+ buf = bytes (buf )
111
+ with open ("/dev/tty" , "rb" ) as tty :
112
+ r = fcntl .ioctl (tty , termios .TIOCGPGRP , buf , True )
113
+ self .assertIsInstance (r , bytes )
114
+ self .assertEqual (len (r ), len (save_buf ))
115
+ self .assertEqual (buf , save_buf )
116
+ rpgrp = array .array ('i' , r )[0 ]
117
+ rpgrp = memoryview (r ).cast ('i' )[0 ]
118
+ self .assertIn (rpgrp , ids )
119
+
57
120
def test_ioctl_mutate (self ):
58
121
self ._check_ioctl_mutate_len ()
122
+ self ._check_ioctl_not_mutate_len ()
59
123
60
124
def test_ioctl_mutate_1024 (self ):
61
125
# Issue #9758: a mutable buffer of exactly 1024 bytes wouldn't be
62
126
# copied back after the system call.
63
127
self ._check_ioctl_mutate_len (1024 )
128
+ self ._check_ioctl_not_mutate_len (1024 )
64
129
65
130
def test_ioctl_mutate_2048 (self ):
66
131
# Test with a larger buffer, just for the record.
67
132
self ._check_ioctl_mutate_len (2048 )
133
+ self .assertRaises (ValueError , self ._check_ioctl_not_mutate_len , 2048 )
134
+
135
+ def test_ioctl_tcflush (self ):
136
+ with open ("/dev/tty" , "rb" ) as tty :
137
+ r = fcntl .ioctl (tty , termios .TCFLSH , termios .TCIFLUSH )
138
+ self .assertEqual (r , 0 )
68
139
69
140
@unittest .skipIf (pty is None , 'pty module required' )
70
141
def test_ioctl_set_window_size (self ):
0 commit comments