Skip to content
Advertisement

How do you check if a serial port is open in Linux?

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:

  1. Checking the file descriptor to see if the serial port is open and

  2. 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:

  1. 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 issues ioctl(fd, TIOCNXCL), any attempt to open the device will fail with EBUSY 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 with EWOULDBLOCK (or block until unlocked or closed if placed without LOCK_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.)
     

  2. 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 with p (and immediately followed with the PID and a newline n) specify the processes that have DEVICE open. (Each such line is followed by one or more lines starting with f, 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() and S_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/, where APPLICATION 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 example fscanf(). (Remember to use pclose() 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.

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement