Discussion:
Detect difference between pseudo terminal and real serial port?
(too old to reply)
Jef Driesen
2009-12-15 20:11:17 UTC
Permalink
Hi,

Is there some way to detect the difference between a file descriptor
that refers to a pseudo terminal and a real serial port? My application
works with real serial ports, but for testing I use pseudo terminals.
But they do not appear to support some of the ioctl's for setting
DTR/RTS lines, asserting breaks, etc. Thus for testing, I replace those
functions with stubs that do nothing and always return success. But that
means I have to build two variants of my application, and I would like
to replace that with a runtime check. But I don't know if that is possible.

Thanks in advance,

Jef
John Gordon
2009-12-15 20:53:17 UTC
Permalink
Post by Jef Driesen
Hi,
Is there some way to detect the difference between a file descriptor
that refers to a pseudo terminal and a real serial port? My application
Would isatty() work?
--
John Gordon A is for Amy, who fell down the stairs
***@panix.com B is for Basil, assaulted by bears
-- Edward Gorey, "The Gashlycrumb Tinies"
Barry Margolin
2009-12-15 21:06:41 UTC
Permalink
Post by John Gordon
Post by Jef Driesen
Hi,
Is there some way to detect the difference between a file descriptor
that refers to a pseudo terminal and a real serial port? My application
Would isatty() work?
No. ptys are often used in applications specifically to trick
applications and libraries that call isatty(). In particular, this is
how "unbuffer" works to get programs that use stdio to unbuffer their
output when it's going to a pipe.

Maybe you can use ttyname(), and check the name to see if it looks like
a pty name. However, I think pty naming schemes vary between flavors of
Unix, so this might not be portable.

There are probably some ioctls that only work on ptys. I've found some
that work on the master end, but you're interested in detecting this on
the slave.
--
Barry Margolin, ***@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
David Schwartz
2009-12-15 21:32:35 UTC
Permalink
Post by Jef Driesen
Is there some way to detect the difference between a file descriptor
that refers to a pseudo terminal and a real serial port? My application
works with real serial ports, but for testing I use pseudo terminals.
But they do not appear to support some of the ioctl's for setting
DTR/RTS lines, asserting breaks, etc. Thus for testing, I replace those
functions with stubs that do nothing and always return success. But that
means I have to build two variants of my application, and I would like
to replace that with a runtime check. But I don't know if that is possible.
If the difference is undetectable, why do you care? If the difference
is detectable, then you already have your answer. For example, if
setting DTR/RTS lines fail, then you know you have something that
doesn't have settable DTR/RTS lines.

DS
Barry Margolin
2009-12-15 21:41:02 UTC
Permalink
In article
Post by David Schwartz
Post by Jef Driesen
Is there some way to detect the difference between a file descriptor
that refers to a pseudo terminal and a real serial port? My application
works with real serial ports, but for testing I use pseudo terminals.
But they do not appear to support some of the ioctl's for setting
DTR/RTS lines, asserting breaks, etc. Thus for testing, I replace those
functions with stubs that do nothing and always return success. But that
means I have to build two variants of my application, and I would like
to replace that with a runtime check. But I don't know if that is possible.
If the difference is undetectable, why do you care? If the difference
is detectable, then you already have your answer. For example, if
setting DTR/RTS lines fail, then you know you have something that
doesn't have settable DTR/RTS lines.
I suspect he wants his application to report an error if one of these
ioctls fails on a real serial line.

Perhaps the right solution is to look at the specific errno code that
comes back. There's probably a unique error code returned if the device
isn't the kind that supports these operations. If you get this, just
ignore it and go on, otherwise report the error.
--
Barry Margolin, ***@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
Jef Driesen
2009-12-15 22:35:46 UTC
Permalink
Post by Barry Margolin
In article
Post by David Schwartz
Post by Jef Driesen
Is there some way to detect the difference between a file descriptor
that refers to a pseudo terminal and a real serial port? My application
works with real serial ports, but for testing I use pseudo terminals.
But they do not appear to support some of the ioctl's for setting
DTR/RTS lines, asserting breaks, etc. Thus for testing, I replace those
functions with stubs that do nothing and always return success. But that
means I have to build two variants of my application, and I would like
to replace that with a runtime check. But I don't know if that is possible.
If the difference is undetectable, why do you care? If the difference
is detectable, then you already have your answer. For example, if
setting DTR/RTS lines fail, then you know you have something that
doesn't have settable DTR/RTS lines.
I suspect he wants his application to report an error if one of these
ioctls fails on a real serial line.
That's indeed what I want. In my test setup, the DTR/RTS lines are not
required to get things working, so it's fine to ignore errors (or omit
the ioctl call). But in the real application, a failing ioctl indicates
a problem that should be reported.
Post by Barry Margolin
Perhaps the right solution is to look at the specific errno code that
comes back. There's probably a unique error code returned if the device
isn't the kind that supports these operations. If you get this, just
ignore it and go on, otherwise report the error.
The error code that I'm getting on my system is EINVAL. That's an error
you shouldn't get during normal operation, so this approach might work
just fine.
David Schwartz
2009-12-16 00:18:31 UTC
Permalink
Post by Jef Driesen
Post by Barry Margolin
I suspect he wants his application to report an error if one of these
ioctls fails on a real serial line.
That's indeed what I want. In my test setup, the DTR/RTS lines are not
required to get things working, so it's fine to ignore errors (or omit
the ioctl call). But in the real application, a failing ioctl indicates
a problem that should be reported.
But it doesn't. It could just as well mean the line doesn't have DTR/
RTS lines. A failing DTR/RTS ioctl is only worth reporting if you know
for a fact that the line should support DTR/RTS.
Post by Jef Driesen
Post by Barry Margolin
Perhaps the right solution is to look at the specific errno code that
comes back.  There's probably a unique error code returned if the device
isn't the kind that supports these operations.  If you get this, just
ignore it and go on, otherwise report the error.
The error code that I'm getting on my system is EINVAL. That's an error
you shouldn't get during normal operation, so this approach might work
just fine.
I don't see how this could ever indicate an actual error.

DS
Barry Margolin
2009-12-16 05:10:50 UTC
Permalink
In article
Post by David Schwartz
Post by Jef Driesen
Post by Barry Margolin
I suspect he wants his application to report an error if one of these
ioctls fails on a real serial line.
That's indeed what I want. In my test setup, the DTR/RTS lines are not
required to get things working, so it's fine to ignore errors (or omit
the ioctl call). But in the real application, a failing ioctl indicates
a problem that should be reported.
But it doesn't. It could just as well mean the line doesn't have DTR/
RTS lines. A failing DTR/RTS ioctl is only worth reporting if you know
for a fact that the line should support DTR/RTS.
If his application requires this, and you connect it to lines that don't
support it, that's an error that should be reported, isn't it? The user
needs to know that they connected the device to the wrong kind of serial
interface.
--
Barry Margolin, ***@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
Jef Driesen
2009-12-16 08:05:34 UTC
Permalink
Post by Barry Margolin
In article
Post by David Schwartz
Post by Jef Driesen
Post by Barry Margolin
I suspect he wants his application to report an error if one of these
ioctls fails on a real serial line.
That's indeed what I want. In my test setup, the DTR/RTS lines are not
required to get things working, so it's fine to ignore errors (or omit
the ioctl call). But in the real application, a failing ioctl indicates
a problem that should be reported.
But it doesn't. It could just as well mean the line doesn't have DTR/
RTS lines. A failing DTR/RTS ioctl is only worth reporting if you know
for a fact that the line should support DTR/RTS.
If his application requires this, and you connect it to lines that don't
support it, that's an error that should be reported, isn't it? The user
needs to know that they connected the device to the wrong kind of serial
interface.
I need the DTR/RTS lines because they are part of the communication
protocol. So if the ioctl fails, the communication will fail too. The
only exception is when running in my test environment.
Moi
2009-12-16 12:24:39 UTC
Permalink
Post by Jef Driesen
Post by Barry Margolin
In article
If his application requires this, and you connect it to lines that
don't support it, that's an error that should be reported, isn't it?
The user needs to know that they connected the device to the wrong kind
of serial interface.
I need the DTR/RTS lines because they are part of the communication
protocol. So if the ioctl fails, the communication will fail too. The
only exception is when running in my test environment.
Yet another problem would be serial ports connected via a serial to USB-
connector. (which will probably be "mounted" by the kernel as a pty, too).

[ These protocol-bridges tend to appear a lot in GPS receivers ]

AvK
Jef Driesen
2009-12-16 12:42:00 UTC
Permalink
Post by Moi
Post by Jef Driesen
Post by Barry Margolin
In article
If his application requires this, and you connect it to lines that
don't support it, that's an error that should be reported, isn't it?
The user needs to know that they connected the device to the wrong kind
of serial interface.
I need the DTR/RTS lines because they are part of the communication
protocol. So if the ioctl fails, the communication will fail too. The
only exception is when running in my test environment.
Yet another problem would be serial ports connected via a serial to USB-
connector. (which will probably be "mounted" by the kernel as a pty, too).
[ These protocol-bridges tend to appear a lot in GPS receivers ]
USB-to-serial connectors work fine for me. Most of the devices I need to
communicate with have such a chip built-in. PC's with real serial ports
are becoming rare :-)
Moi
2009-12-16 12:51:38 UTC
Permalink
Post by Jef Driesen
Post by Barry Margolin
In article
USB-to-serial connectors work fine for me. Most of the devices I need to
communicate with have such a chip built-in. PC's with real serial ports
are becoming rare :-)
I have one of these, I'll try and test it on my DCF77 receiver,
which uses the modem control lines to obtain its power.

AvK
David Schwartz
2009-12-16 21:37:28 UTC
Permalink
Post by Jef Driesen
I need the DTR/RTS lines because they are part of the communication
protocol. So if the ioctl fails, the communication will fail too. The
only exception is when running in my test environment.
So why does it work in your test environment and not in the real
world? You have to find the real thing you need and test for that.
Trying to find some proxy for the real question will just lead to
pain. Spend the time to figure out what the right question is -- what
does your application *really* need? What is the characteristic of the
environment in which it doesn't work? And test for that.

If it works in your test environment without DTR/RTS then either it
doesn't need DTR/RTS or it works by magic.

DS
Jef Driesen
2009-12-17 07:49:22 UTC
Permalink
Post by David Schwartz
Post by Jef Driesen
I need the DTR/RTS lines because they are part of the communication
protocol. So if the ioctl fails, the communication will fail too. The
only exception is when running in my test environment.
So why does it work in your test environment and not in the real
world? You have to find the real thing you need and test for that.
Trying to find some proxy for the real question will just lead to
pain. Spend the time to figure out what the right question is -- what
does your application *really* need? What is the characteristic of the
environment in which it doesn't work? And test for that.
If it works in your test environment without DTR/RTS then either it
doesn't need DTR/RTS or it works by magic.
In the real environment, my application communicates with external
devices that are connected to the PC through a serial port (or usb with
a built-in usb-to-serial chip). The communication protocol of some of
these devices requires the use of the RTS/DTR lines. For instance the
DTR line is often used as a power supply, and the RTS line is typically
used for flow control.

In the test environment, I use a simulator application to emulate the
real device. It works by creating two pseudo terminals, connected with a
virtual nullmodem cable. For instance with socat:

socat PTY,link=/tmp/ttyS0 PTY,link=/tmp/ttyS1

The application connects to one end of the pair, while the simulator
application connects to the other end and answer the commands that are
send by the application. Just like a real device would do, but the
difference is that the simulator doesn't need the serial lines to
operate. Even if I wanted to implement that, I can't because the pseudo
terminals don't support them.

So that's the reason why it's fine to ignore or even omit those ioctl in
the test environment, but not in the real environment.
David Schwartz
2009-12-17 22:18:17 UTC
Permalink
Post by Jef Driesen
So that's the reason why it's fine to ignore or even omit those ioctl in
the test environment, but not in the real environment.
So what you need is a way to tell which environment you are in. Well,
what are some of the differences between those two environments? Can
you simply have your simulated devices send a slightly different
header or something like that? Can you have a file that's present in
your test environment but not the real one?

Test what you really want to know, not some proxy for it.

DS

David Schwartz
2009-12-16 21:35:49 UTC
Permalink
Post by Barry Margolin
Post by David Schwartz
But it doesn't. It could just as well mean the line doesn't have DTR/
RTS lines. A failing DTR/RTS ioctl is only worth reporting if you know
for a fact that the line should support DTR/RTS.
If his application requires this, and you connect it to lines that don't
support it, that's an error that should be reported, isn't it?
But we know his application doesn't require this, since it works with
a pseudo terminal. That's why he's asking this question.
Post by Barry Margolin
 The user
needs to know that they connected the device to the wrong kind of serial
interface.
Right, so the question is what does his application *need*? We *know*
it doesn't need DTR/RTS lines.

DS
Barry Margolin
2009-12-16 22:25:15 UTC
Permalink
In article
Post by David Schwartz
Post by Barry Margolin
Post by David Schwartz
But it doesn't. It could just as well mean the line doesn't have DTR/
RTS lines. A failing DTR/RTS ioctl is only worth reporting if you know
for a fact that the line should support DTR/RTS.
If his application requires this, and you connect it to lines that don't
support it, that's an error that should be reported, isn't it?
But we know his application doesn't require this, since it works with
a pseudo terminal. That's why he's asking this question.
It doesn't really work with a pseudo-terminal. The pty is only good
enough for debugging, not production use.
Post by David Schwartz
Post by Barry Margolin
 The user
needs to know that they connected the device to the wrong kind of serial
interface.
Right, so the question is what does his application *need*? We *know*
it doesn't need DTR/RTS lines.
He's already replied, saying that the application DOES need these
signals. If it's used in production with a device that doesn't support
it, he wants to report an error and abort.
--
Barry Margolin, ***@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
David Schwartz
2009-12-17 06:00:19 UTC
Permalink
Post by Barry Margolin
He's already replied, saying that the application DOES need these
signals.  If it's used in production with a device that doesn't support
it, he wants to report an error and abort.
Then he needs some way to test whether he's in production or not, not
a way to test whether he's talking to a pseudo-terminal or a serial
port.

DS
Jef Driesen
2009-12-17 11:23:50 UTC
Permalink
Post by David Schwartz
Post by Barry Margolin
He's already replied, saying that the application DOES need these
signals. If it's used in production with a device that doesn't support
it, he wants to report an error and abort.
Then he needs some way to test whether he's in production or not, not
a way to test whether he's talking to a pseudo-terminal or a serial
port.
Well, that's exactly what I'm doing now: building separate applications
for use in the test and real environment. But it is annoying, because I
always have to patch my code when switching environment. And because I
often forget to do the patching, I would like to change to something
that works in both environments.

Note that the pseudo-terminal vs serial port *is* the key difference
between the two environments.
Jef Driesen
2009-12-16 14:02:00 UTC
Permalink
Post by Jef Driesen
Post by Barry Margolin
Perhaps the right solution is to look at the specific errno code that
comes back. There's probably a unique error code returned if the device
isn't the kind that supports these operations. If you get this, just
ignore it and go on, otherwise report the error.
The error code that I'm getting on my system is EINVAL. That's an error
you shouldn't get during normal operation, so this approach might work
just fine.
On a Mac OS X system, I'm getting ENOTTY. That's kind of weird, because
the file descriptor is a pseudo terminal. Other functions like
tcgetattr() and friends do work as expected.
Stephane CHAZELAS
2009-12-16 14:43:38 UTC
Permalink
Post by Jef Driesen
Is there some way to detect the difference between a file descriptor
that refers to a pseudo terminal and a real serial port?
[...]

What about doing an fstat(2) and checking the major(st.st_rdev)?
(maybe comparing with the rdev of a pseuto-tty you created
yourself, note however than some systems like Linux or HPUX have
more than one pty implementations, so possibly more than one
possible major number for ptys).
--
Stéphane
Gordon Burditt
2009-12-16 22:46:14 UTC
Permalink
Post by Jef Driesen
Is there some way to detect the difference between a file descriptor
that refers to a pseudo terminal and a real serial port? My application
works with real serial ports, but for testing I use pseudo terminals.
But they do not appear to support some of the ioctl's for setting
DTR/RTS lines, asserting breaks, etc. Thus for testing, I replace those
functions with stubs that do nothing and always return success. But that
means I have to build two variants of my application, and I would like
to replace that with a runtime check. But I don't know if that is possible.
I'd say you have found the way to detect the difference. Pick one
of the ioctl()s that fails on a pty, preferably one that *reads*
status of control lines rather than changing it. If it fails, it's
a pty.

Another possibility is that you don't really need to check for
errors on those calls. Is there a realistic possibility that
these calls will fail on real serial lines?
Loading...