How does one check if a serial port is already open in Linux using Posix/C functions? I want to check the status of the serial port to check if the serial port is open or not.
I would like to know what methods work for:
Checking the file descriptor to see if the serial port is open and
Checking the serial port file name to see if the the serial port is open which in the example below is “/dev/ttyUSB0”
—
// This code is for example purposes only int open_port() { int fd; fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY); if (fd < 0) { perror("open_port: Unable to open /dev/ttyf1 - "); } return fd; }
I imagine there is a “standard” way of doing this, and that is what I am trying to get to.
Advertisement
Answer
There are two aspects to the stated question, which really require two different solutions:
An application or service daemon using a serial port should exclude other processes from using the port concurrently.
There are two ways of doing this: exclusive mode, and an advisory lock. An application can choose to do one, or both.
After opening the device, use
ioctl(fd, TIOCEXCL)
to put the serial port into exclusive mode. Until the descriptor is closed, or the process issuesioctl(fd, TIOCNXCL)
, any attempt to open the device will fail withEBUSY
error code.After opening the device, use
flock(fd, LOCK_EX | LOCK_NB)
to try and place an exclusive advisory lock on the open device. Other processes can still open the device normally, and even read and write to it, but trying to place an advisory flock lock on it will fail withEWOULDBLOCK
(or block until unlocked or closed if placed withoutLOCK_NB
).
The difference between the above two approaches is that the latter is co-operative, allowing other processes to open the device; while the former disallows further opens.
The reason to use both, is to detect if another process has already opened the device without putting it into exclusive mode, but has hopefully set the advisory lock. In that case, the open() and ioctl() both succeed, but the flock() fails.
(We can use the second aspect of this question discussed below — after having opened the device, set it to exclusive mode, and even obtained the exclusive lock on it —, to detect if other processes have the device open but not exclusive or locked. Personally, I wouldn’t bother; I do expect users to only use sane applications on their systems. If they really did that, I’d expect them to have a reason for it, so I’d prefer to allow that oddball scenario. It definitely should not occur with standard utilities.)
An application or daemon can use
lsof
(from the lsof package) to examine if any process has the specified file or device open.The idea is to run the equivalent of
LANG=C LC_ALL=C lsof -F -p DEVICE
with root privileges. The output will contain zero or more lines. The lines beginning withp
(and immediately followed with the PID and a newlinen
) specify the processes that haveDEVICE
open. (Each such line is followed by one or more lines starting withf
, describing which descriptor in that process refer to the device.)If the application or daemon does not have root privileges, a helper program that is installed setuid root is needed. It is supplied with one or more device names. The helper program verifies each one is a character device using
stat()
andS_IFCHR(st_mode)
(to avoid the helper being used in security exploits); and if they are, executes the above-mentioned command. In Linux, such helpers are usually installed in/usr/lib/APPLICATION/
, whereAPPLICATION
is the name of the application or daemon.The application or daemon itself can execute the helper via
popen("/path/to/helper 2>/dev/null", "r")
, and read the input using for examplefscanf()
. (Remember to usepclose()
to obtain the status, and use e.g.(WIFEXITED(status) && !WEXITSTATUS(status))
to verify the command was successful.Note that the helper program approach allows easier portability to other POSIXy systems from Linux, by simply replacing the helper program with one appropriate to the new system. Even if it is not installed as setuid root, it gives system maintainers an easy hook to modify the behaviour of the application or service, if such need arises. I personally warmly recommend the helper approach.