在Linux上从根节点获得对tty设备的独占访问权限

我有一个在Linux上以root身份运行的程序,与一个tty(实际上是一个tty实现的LCD)交谈。 该设备的价值是/ dev / ttyUSB0。 我想让我的程序写入这个设备能够独占访问设备,以免同时运行的程序的其他实例的任何干扰。

我发现有一个名为TIOCEXCL的ioctl选项,它将阻止设备的额外打开,除非TIOCEXCL ioctl被发出,否则对同一个文件的多个open()调用将会成功。 “ 我testing了这一点,它的工作原理和广告一样:如果一个非root用户试图打开/ dev / ttyUSB0(一旦我改变了权限),那么打开失败,像“设备繁忙”,如果一个root用户试图打开它, 有用。

我最想要的是通过这种独占方式访问tty,以便为root用户工作。 所以我会有多个root用户使用写入LCD的程序,但是他们对LCD(tty)的访问将被序列化。 显然,TIOCEXCL ioctl选项不适用于我,因为它不会阻止root用户打开已经打开的tty设备。

我想这里有很多select,但是我想深入了解你们是否有其他想法或build议。

  1. 也许我错过了使用TIOCEXCL的一些东西…

  2. 也许有一些其他方式通过开放()或ioctl()或什么 – 不是获得独占访问。

  3. 如果有某种方法可以检测到某个其他进程已打开设备,则可以等待并重试。 我知道lsof,但是我不愿意从这个程序中调用它来学习。 而且还有与此相关的竞争条件。 (也许我可以克服?:))

  4. 我可以实现锁,就像显然习惯于获得对tty设备的独占访问一样。

更新1:

由于唯一的程序写入液晶显示设备是我的,我倾向于做类似于以下(伪代码)来locking代码:

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) 

也许这个关于LKML的讨论:[TTY]独家模式的问题可以帮助你!

答:Root始终有权访问。 总是。

也许如果你更多地谈论了还有什么东西是抓住这个设备,或者你担心什么可能抓住设备…

我鼓励你看看UUCP锁定。 Linux上应该有一个库来实现它,但是如果没有的话,实现起来相当容易。 我已经在类似的情况下广泛地使用了它,我不希望同一个程序的多个实例互相踩在一起。

作为一个方面说明,也许你应该重新考虑你的解决方案的架构。 访问LCD / ttyUSB0的过程可以充当服务器,并处理需要写入LCD的客户端进程的消息。 这将需要某种形式的IPC。 这可能是你的项目过度

请记住,只有在访问设备的所有进程符合协议的情况下,您所提出的任何解决方案才会起作用。 如果您担心以root身份运行的恶意进程,那么您可能会被黑客攻击内核以获得所需的解决方案。

我不知道你是否已经找到了一个解决方案,或者你只是改变了你的设计,但是这里有一个“根源地”的解决方案:

  1. 在你的系统中创建另一个与你的端口相同的文件,或者像ttyUSB0_islocked这样的ttyUSB0_islocked
  2. 当你打开这个端口时,你的进程会查找/创建并打开这个文件并写入一些信息,比如它的进程ID。
  3. 在其他程序中打开端口之前,请检查此文件是否存在,并在文件中有一个具有相同进程ID的进程,然后在没有其他进程等待或退出的情况下继续进行。

我有像你这样的问题。 如果你可以破解你的linux内核,你可以这样做肮脏的破解。 在文件中

linux/drivers/char/tty_io.c

添加新的命令功能

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

tty->count的值是当前打开描述符的计数。

在你的应用程序中你可以试试这个代码

 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; } } }