Echo console to a device (and vice-versa)?

F

Francis Avila

This is not really a python question, but a posix question. (If it's too
little of a python question to be OT, please let me know.)

I wanted a simple "bi-directional cat", i.e. something that passes stdin to
a device, and takes the device's output to stdout (Like 'screen
/dev/ttyS0'). I couldn't find a simple thing like this anywhere, so I
figured I would just write one.

However, I can't seem to get it to work: nothing is ever output or input on
either end (also, if run in emacs it hangs it until I can kill python--it's
eating stdin and stdout, I suspect). I suspect I have a deep ignorance of
file descriptors, but I don't understand what it could be. Might it also be
possible that the interpreter is somehow getting "in the way" of
stdin/stdout? A C-c still sends KeyboardInterrupt, for example, so I know
python is still looking at stdin.

Here's the important code, which went through some revisions:


import os, sys
from errno import EAGAIN
import fcntl


usage = """usage: scat TTY-DEV"""

def main():
try:
ttyfn = sys.argv[1]
except IndexError:
print >> sys.stderr, usage
return 1

try:
ttyfdout = os.open(ttyfn, os.O_RDONLY | os.O_NONBLOCK)
ttyfdin = os.open(ttyfn, os.O_WRONLY | os.O_NONBLOCK)
except:
print >> sys.stderr, usage
print >> sys.stderr, "invalid filename " + ttyfn
return 1

if not os.isatty(ttyfdin):
print >> sys.stderr, usage
print >> sys.stderr, ttyfn + " is not a tty"
return 1

stdin = sys.stdin.fileno()
stdout = sys.stdout.fileno()

# make the above non-blocking
fcntl.fcntl(stdin, fcntl.F_SETFL, os.O_NONBLOCK)
fcntl.fcntl(stdout, fcntl.F_SETFL, os.O_NONBLOCK)

while 1:
#read tty, write to stdout
try:
ttybuf = os.read(ttyfdout, 1)
except OSError, err:
if err == EAGAIN:
pass
else:
os.write(stdout, ttybuf)

#read stdin, write to tty
try:
stdinbuf = os.read(stdin, 1)
except OSError, err:
if err == EAGAIN:
pass
else:
os.write(ttyfdin, stdinbuf)


if __name__ == '__main__':
main()
 
P

Peter Otten

Francis said:
try:
ttybuf = os.read(ttyfdout, 1)
except OSError, err:
if err == EAGAIN:
pass
else:
os.write(stdout, ttybuf)

Well, admitting that I don't have any idea what you want to do, the above
code silences *any* OSError, i. e.

if err == EAGAIN:
pass

is a NOOP. If you want to catch only EAGAIN, you might consider

try:
ttybuf = os.read(ttyfdout, 1)
except OSError, err:
if err != EAGAIN:
raise
else:
os.write(stdout, ttybuf)

instead.

Peter
 
F

Francis Avila

Peter Otten said:
Well, admitting that I don't have any idea what you want to do, the above
code silences *any* OSError, i. e.

if err == EAGAIN:
pass

is a NOOP. If you want to catch only EAGAIN, you might consider

try:
ttybuf = os.read(ttyfdout, 1)
except OSError, err:
if err != EAGAIN:
raise
else:
os.write(stdout, ttybuf)

instead.

Peter


That's true, thanks. I was thinking a bit sloppily, catching EAGAIN as
though it were itself an exception. However, it doesn't effect functioning
unless some other fatal exception pops up.

The problem was simply that my tty wasn't raw enough. It wasn't sufficient
to make the tty raw from the shell (using, in this case, 'stty raw pass8').
Calling tty.setraw on each of the four fd's solved the problem without
incident, and the code works exactly as expected.

Of course, now there are no excape characters, so I can't even ^C to exit,
but this is all resolvable.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top