Chris Markle
Chris Markle

Reputation: 2106

Getting exclusive access to a tty device from a root program on Linux

I have a program running as root on Linux, talking to a tty (actually an LCD implemented as a tty). The device for what it's worth is /dev/ttyUSB0. I'd like to have my program that writes to this device be able to have exclusive access to the device, so as to not have any interference from other instances of the program running at the same time.

I see that there's a ioctl option called TIOCEXCL which will prevent additonal open's of the device to wit "multiple open() calls to the same file will succeed unless the TIOCEXCL ioctl is issued. This will prevent additional opens except by root-owned processes." I tested this and it works just as advertised: if a non-root user tries to open /dev/ttyUSB0 (once I changed the permissions) then the open fails with something like "device busy" and if a root user tries to open it, it works.

What I ideally want is a way to this exclusive access to the tty to work for root users. So I'd have multiple root users using the program that writes to the LCD, but somehow their access to the LCD (tty) would be serialized. Apparently the TIOCEXCL ioctl option will not work for me since it doesn't stop root users from opening an already-opened tty device.

I guess there are a number of options here, but I am reaching out to all ya'll to see if you might have other thoughts or suggestions.

  1. Maybe I'm missing something about using TIOCEXCL...

  2. Maybe there's some other way via open() or ioctl() or what-not to get exclusive access.

  3. If there was some way I could detect that some other process has the device open, I could just wait and retry. I know about lsof but I'm loath to invoke it from inside this program just to learn this. And there are race conditions with that. (Maybe I can get over that? :) )

  4. I could implement locking like apparently used to be done to get exclusive access to tty devices.

Update 1:

Since the only program writing to the LCD device is mine, I am inclined to do something like the following (pseudo-code) to lock inside the code:

f = open("/dev/ttyUSB0", O_RDWR)
flock(f, LOCK_EX)

// do any ioctl's, etc.

// do any write's

// sleep a tad to not flash messages too fast on LCD
nanosleep({0, 250000000}, NULL)

flock(f, LOCK_UN)
close(f)

Upvotes: 3

Views: 10098

Answers (5)

Anton Mikheev
Anton Mikheev

Reputation: 11

i have some issue like you. If you can hack you linux kernel, you can to do dirty hack like this. In file

linux/drivers/char/tty_io.c

add new command to function

long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    ...
    switch (cmd) {
    ...
    case 0x54FF:
        return put_user(tty->count, (int __user *)p);
    ...
}

The value of tty->count is a count of current open descriptors.

In your application you can try this code

int fd, count, res;
fd = open("/dev/ttyS0", O_RDWR|O_NOCTTY|O_NONBLOCK);
if (fd >= 0)
{
    count = 0;
    res = ioctl(fd, 0x54FF, &count);
    if (res>=0)
    {
        if (count > 1)
        {
            printf("Device already in use.\n")
            close(fd);
            fd = -1;
        }
    }
}

Upvotes: 1

max
max

Reputation: 2657

I don't know if you have already found a solution or you just changed your design but here's a work around in the "roots land":

  1. Create another file in your system with the same name of your port or something including it like ttyUSB0_islocked.
  2. when you open the port have your process look for/create and open this file and write some info like it's process Id in it.
  3. before opening the port in other programs check if this file exists and there's a process with the same process id within the file and then proceed if there's no such process other wise wait or exit.

Upvotes: 0

Rob Jones
Rob Jones

Reputation: 4985

I would encourage you to look into UUCP locking. There should be a library on Linux that implements it, but if not, it's fairly easy to implement. I've used it extensively in similar situations where I don't want multiple instances of the same program to step on each other.

As a side note, perhaps you should rethink the architecture of your solution. The process that accesses the LCD/ttyUSB0 could act as a server and handle messages from the client processes that need to write to the LCD. This would require some form of IPC. It may be overkill for your project.

Keep in mind that any solution you come up with will only work if all processes that access the device conform to the protocol. If you are worried about a rogue process running as root then you may be stuck with hacking the kernel to get the solution you want.

Upvotes: 0

dwc
dwc

Reputation: 24890

Answer: Root always has access. Always.

Perhaps if you said more about what else was grabbing the device, or what you fear might grab the device...

Upvotes: 0

Johannes Weiss
Johannes Weiss

Reputation: 54031

Perhaps this discussion on LKML: [TTY] exclusive mode question can help you!

Upvotes: 7

Related Questions