How to find all serial devices (ttyS, ttyUSB, ..) on Linux without opening them?
What is the proper way to get a list of all available serial ports/devices on a Linux system? In other words, when I iterate over all devices in /dev/ , how do I tell which ones are serial ports in the classic way, that is, those usually supporting baud rates and RTS/CTS flow control? The solution would be coded in C. I ask because I am using a third-party library that does this clearly wrong: It appears to only iterate over /dev/ttyS* . The problem is that there are, for instance, serial ports over USB (provided by USB-RS232 adapters), and those are listed under /dev/ttyUSB*. And reading the Serial-HOWTO at Linux.org, I get the idea that there’ll be other name spaces as well, as time comes. So I need to find the official way to detect serial devices. The problem is that none appears to be documented, or I can’t find it. I imagine one way would be to open all files from /dev/tty* and call a specific ioctl() on them that is only available on serial devices. Would that be a good solution, though?
Update
hrickards suggested to look at the source for «setserial». Its code does exactly what I had in mind: First, it opens a device with:
fd = open (path, O_RDWR | O_NONBLOCK)
ioctl (fd, TIOCGSERIAL, &serinfo)
If that call returns no error, then it’s a serial device, apparently. I found similar code in Serial Programming/termios, which suggested to also add the O_NOCTTY option. There is one problem with this approach, though: When I tested this code on BSD Unix (that is, Mac OS X), it worked as well. However, serial devices that are provided through Bluetooth cause the system (driver) to try to connect to the Bluetooth device, which takes a while before it’ll return with a timeout error. This is caused by just opening the device. And I can imagine that similar things can happen on Linux as well — ideally, I should not need to open the device to figure out its type. I wonder if there’s also a way to invoke ioctl functions without an open, or open a device in a way that it does not cause connections to be made? What should I do?
How do I know which /dev/ttyS* is my serial port?
Running that on my own Linux box (which only has 1 Serial port) produces a single ttyS0 output line. Try it on your own, you will see what I mean.
Does that mean that after running that command, if the response is . console [tty0] enabled. and no other, any device is connected to /dev/tty0 (sorry for the apparent silliness of the question)?
The only problem is that dmesg output can be cleared — so if you run this too late, you’re out of luck. Looking at /proc/tty/driver/serial seems the more robust answer and then check for rx interrupts increasing in count as you write data to that port
if you’re currently in a terminal over said serial line, you can just type tty to get the name of your tty. I assume that’s what OP meant since they did not pose the question as «which serial port(s) have getty running?»
See which UARTs where detected in /proc/tty/driver/serial . A line with uart:unknown means: nothing detected (and likely not existent).
# cat /proc/tty/driver/serial serinfo:1.0 driver revision: 0: uart:16550A port:000003F8 irq:4 tx:0 rx:0 1: uart:16550A port:000002F8 irq:3 tx:111780 rx:1321 RTS|DTR|DSR 2: uart:unknown port:000003E8 irq:4 3: uart:unknown port:000002E8 irq:3
If you see any of the CTS, DSR, (D)CD or RI flags (these are input signals), like on UART no. 1 above, you can even be pretty sure that there actually is something connected and driving these lines. Same is true for the rx-byte-count.
Seeing a positive tx-byte-count, RTS and/or DTR only reveals that some software accessed the device and ordered it to set those signals or send bytes here, but not if something was listening.
Note: you might see more ports available in hardware than ports reaching the outside of your computer in form of a connector.
Find out what device /dev/root represents in Linux?
On linux, there is a /dev/root device node. This will be the same block device as another device node, like /dev/sdaX . How can I resolve /dev/root to the ‘real’ device node in this situation, so that I can show a user a sensible device name? For example, I might encounter this situation when parsing /proc/mounts . I’m looking for solutions that would work from a shell/python script but not C.
have you checked here ? linux-diag.sourceforge.net/Sysfsutils.html It recommends way to query the kernel about attached devices of all kinds, not sure, if its what you are looking for !
6 Answers 6
Parse the root= parameter from /proc/cmdline .
This works on the three distros (fc14, rhel5, ubuntu 11.04) that I’ve looked at, with the slight caveat that there is an extra step needed to deal with root=UUID= type arguments.
readlink does not always work, I’m working on this problem right now and found a user whose system shows no results from: readlink /dev/root — which tripped a glitch in the program I’m working on, which is why I came to this thread. The correct test is to first do: readlink /dev/root, then if null, find it in /proc/cmdline, but parsing /proc/cmdline is not as easy as a better solution, so I’ll keep looking.
On the systems I’ve looked at, /dev/root is a symlink to the real device, so readlink /dev/root (or readlink -f /dev/root if you want the full path), will do it.
Just to clarify, some systems with /dev/root will NOT show output for either ls -l or readlink because it’s not a link, not in the normal sense we think of links anyway. I’m hitting this issue right now. So I’d update this answer to be correct for the systems he’s looked at, but incorrect for an entire class of systems, like current ubuntu I believe, that he had not seen. I also had not seen this new variant for what it’s worth until recently.
This should probably be updated, because a lot of the information given here is misleading, and may actually never have been comprehensively correct.
For the / mount point, you are just told that it corresponds to /dev/root, which is not the real device you are looking for.
Of course, you can look at the kernel command line and see on which initial root filesystem Linux was instructed to boot (root parameter):
$ cat /proc/cmdline mem=512M console=ttyS2,115200n8 root=/dev/mmcblk0p2 rw rootwait
However, this doesn’t mean that what you see is the current root device. Many Linux systems boot on intermediate root filesystems (like initramdisks and initramfs), which are just used to access the final one.
One thing this points out was that the thing in /proc/cmdline is not necessarily the actual final device root actually live on.
That’s from the busybox people, who I assume know what they are talking about when it comes to boot situations.
The second useful resource I found is a very old Slackware thread about the question of /dev/root, from the age of this thread, we can see that all the variants were always present, but I believe ‘most’ distros were using the symbolic link method, but that was a simple kernel compile switch, it could make one, or not make one if I understood the posters correctly, that is, switch it one way, and readlink /dev/root reports the real device name, switch it the other, and it doesn’t.
Since the main topic of that thread was how to get rid of /dev/root, they had to get into what it actually is, what makes it, etc, which means, they had to understand it to get rid of it.
gnashly explained it well:
/dev/root is a generic device which can be used in the fstab. One can also use ‘rootfs’. Doing this offers some advantage in that it allows yout to be less specific. What I mean is, if the root partition is on an external drive, it may not always show up as the same device and successfully mounting it as / would require changing the fstab to match the correct device. By using /dev/root it will always match whatever device is specified in the kernel boot paramters from lilo or grub.
/dev/root has always been present as a virtual mount point, even if you never saw it. So has rootfs (compare this to the special virtual devices like proc and tmpfs which have no preceeding /dev)
/dev/root is a virtual device like ‘proc’ or /dev/tcp’. There is no device node in /dev for these things -it’s already in the kernel as a virtual device.
This explains why a symbolic link does not necessarily exist. I’m surprised I never hit this issue before now, given that I maintain some programs that need to know this information, but better late than never.
I believe some of the solutions offered here will ‘often’ work, and are probably what I will do, but they are not the actual true solution to the problem, which as the busybox author noted, is significantly more complicated to implement in a very robust manner.
[UPDATE:> After getting some user test data, I’m going with the mount method, which seemed to be ok for some cases at least. The /proc/cmdline was not useful because there are too many variants. In the first example, you see the old method. This is less and less common because it’s strongly discouraged to use it (the original /dev/sdx1 type syntax) because those paths can change dynamically (swap disk order, insert new disk, etc, and suddenly /dev/sda1 becomes /dev/sdb1).
root=/dev/sda1 root=UUID=5a25cf4a-9772-40cd-b527-62848d4bdfda root=LABEL=random string root=PARTUUID=a2079bfb-02
VS the very clean and easy to parse:
mount /dev/sda1 on / type ext4 (rw,noatime,data=ordered)
In the case of cmdline, you’ll see, the only variant that is the right ‘answer’ in theory is the first, deprecated one, since you should not refer root to a moving target like /dev/sdxy
The next two require doing the further action of getting the symbolic link from that string in either /dev/disk/by-uuid or /dev/disk/by-label
The last one requires I believe using parted -l to find what that parted id is pointing to.
That’s only the variants I know of and have seen, there could well be others, like GPTID, for example.
So the solution I’m using is this:
first, see if /dev/root is a symbolic link. If it is, verify it’s not to /dev/disk/by-uuid or by-label, if it is, you have to do a second step of processing to get the last real path. Depends on the tool you use.
If you got nothing, then go to mount, and see how that is. As a last fallback case, one I’m not using because the arguments given against it not even necessarily being the actual partition or device in question are good enough for me to reject that solution for my program. mount is not a fully robust solution, and I’m sure given enough samples, it would be easy to find cases where it’s not right at all, but I believe these two cases cover ‘most’ users, which is all I needed.
The nicest, cleanest, and most reliable solution would have been for the kernel to just always make the symbolic link, which would not have hurt anything or anyone, and call it good, but that’s not how it worked out in the real world. .
I don’t consider any of these as ‘good or robust’ solutions, but the mount option appears to satisfy the ‘good enough’, and if the truly robust solution is required, use the stuff that busybox recommended.