summaryrefslogtreecommitdiff
path: root/tools/display-maxcanon.py
blob: cbd664ffec73c261ae58dcd0afe1eec2bcbd0d30 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#!/usr/bin/env python
"""
This tool uses pexpect to test expected Canonical mode length.

All systems use the value of MAX_CANON which can be found using
fpathconf(3) value PC_MAX_CANON -- with the exception of Linux
and FreeBSD.

Linux, though defining a value of 255, actually honors the value
of 4096 from linux kernel include file tty.h definition
N_TTY_BUF_SIZE.

Linux also does not honor IMAXBEL. termios(3) states, "Linux does not
implement this bit, and acts as if it is always set." Although these
tests ensure it is enabled, this is a non-op for Linux.

FreeBSD supports neither, and instead uses a fraction (1/5) of the tty
speed which is always 9600.  Therefor, the maximum limited input line
length is 9600 / 5 = 1920.

These tests only ensure the correctness of the behavior described by
the sendline() docstring -- the values listed there, and above should
be equal to the output of the given OS described, but no promises!
"""
# std import
from __future__ import print_function
import sys
import os


def detect_maxcanon():
    import pexpect
    bashrc = os.path.join(
        # re-use pexpect/replwrap.py's bashrc file,
        os.path.dirname(__file__), os.path.pardir, 'pexpect', 'bashrc.sh')

    child = pexpect.spawn('bash', ['--rcfile', bashrc],
                          echo=True, encoding='utf8', timeout=3)

    child.sendline(u'echo -n READY_; echo GO')
    child.expect_exact(u'READY_GO')

    child.sendline(u'stty icanon imaxbel erase ^H; echo -n retval: $?')
    child.expect_exact(u'retval: 0')

    child.sendline(u'echo -n GO_; echo AGAIN')
    child.expect_exact(u'GO_AGAIN')
    child.sendline(u'cat')

    child.delaybeforesend = 0

    column, blocksize = 0, 64
    ch_marker = u'_'

    print('auto-detecting MAX_CANON: ', end='')
    sys.stdout.flush()

    while True:
        child.send(ch_marker * blocksize)
        result = child.expect([ch_marker * blocksize, u'\a'])
        if result == 0:
            # entire block fit without emitting bel
            column += blocksize
        elif result == 1:
            # an '\a' was emitted, count the number of ch_markers
            # found since last blocksize, determining our MAX_CANON
            column += child.before.count(ch_marker)
            break
    print(column)

if __name__ == '__main__':
    try:
        detect_maxcanon()
    except ImportError:
        # we'd like to use this with CI -- but until we integrate
        # with tox, we can't determine a period in testing when
        # the pexpect module has been installed 
        print('warning: pexpect not in module path, MAX_CANON '
              'could not be determined by systems test.',
              file=sys.stderr)