如何在 Mac 插件中使用 ioctl() 设置 RTS?
Posted
技术标签:
【中文标题】如何在 Mac 插件中使用 ioctl() 设置 RTS?【英文标题】:How can I set the RTS with ioctl() in a Mac plugin? 【发布时间】:2013-02-04 19:08:16 【问题描述】:我可以在一个小型终端应用程序中使用 ioctl 设置 RTS,但不能在我的 Mac 插件代码中设置,尽管两者都运行相同的代码。在插件中,我只能“获取”串行端口标志/引脚,但不能“设置”它们。在终端应用程序中,我可以“获取”和“设置”它们。我得到了 ENODEV 的 errno。错误号是 19,消息是“设备不支持操作。”
如果这是一个安全问题(在浏览器的上下文中),是否有办法获得使用 ioctl 修改标志的权限?我有一个连接到 USB 端口的串行设备。我正在使用 FTDI vcp(虚拟 com 端口)驱动程序。 Windows 端的一切都很顺利。顺便说一句,我使用 Safari 和 Firefox 得到了相同的结果。以下是我的代码:
int disableRTS ()
char fd, ret, flags;
// open device
if ((fd = open("/dev/cu.mydevice", O_RDWR | O_NDELAY)) < 0)
fprintf(stderr, "failed to open device");
return -1;
// Get the current state of the bits
ioctl(fd, TIOCMGET, &flags);
fprintf(stderr, "Flags are %x.\n", flags);
flags &= ~TIOCM_RTS; // Disable the RTS bit
ret = ioctl(fd, TIOCMSET, &flags);
if (ret == -1)
fprintf(stderr, "TIOCMSET failed\n");
else
fprintf(stderr, "TIOCMSET succeeded. flags: %x.\n", flags);
return 0;
=========
更新
如果我刷新浏览器页面,强制再次执行代码,ioctl()返回0,表示成功。不幸的是,我需要它第一次工作。即使我使用 usleep() 方法编写一个循环并暂时暂停,并进行后续尝试,它也会失败。但是,当我刷新它成功时。我还在 Mozilla 提供的第二个专门的 NPAPI 项目“BasicPlugin.xcodeproj”中复制了这个问题。我的第一个插件项目是 Firebreath 项目。他们都首先失败,然后在页面重新加载时成功。我还有 2 个独立的 Mac 应用程序可以正常工作。一种是 SerialTools,它使用与我的终端应用程序和插件完全相同的方法来设置 RTS 开启(和 DTR 关闭)。
========
更新 2
我已经获得了 Apple 对此的代码级支持,因此可能即将推出解决方案。工程师说,代码在插件中的运行方式与在插件之外的方式不同,这“很奇怪”,并且正在与 Safari 插件工程师交谈。
【问题讨论】:
将fprintf
错误案例更改为对 perror("TIOCMSET")
的调用,然后查看错误内容。
对不起,我忘了提。错误消息是“设备不支持操作”。它的错误号是 19。ENODEV。
至于悬赏即将到期还没有正确答案,我不知道该怎么办。我想我会失去它,即使苹果工程师已经接受了这个问题并试图找到解决方案。说插件代码与非插件代码的工作方式不同是“奇怪的”。至少我可以为任何可能有帮助的答案添加正确的答案。
您是否收到过 Apple 的回复?
Safari 是否有可能与独立应用程序具有不同的权利?似乎这可能会干扰...尝试从命令行以 root 身份运行 Safari?
【参考方案1】:
您可以制作一个 AppleScript 插件,该插件将在特定时间或登录期间自动运行,或在后台持续运行。
AppleScript 可以运行终端代码。因此,您可以轻松地让它自动运行您当前在终端中运行的获取/设置代码。
AppleScript 插件的代码将是这样的 ::
tell application "Finder"
display dialog explanation buttons "GET", "SET" default button "GET"
if result = button returned:"GET" then
tell application "Terminal"
set status to (do shell script "terminal code for getting the RTS here")
end tell
else if result = button returned:"SET" then
tell application "Terminal"
set status to (do shell script "terminal code for setting the RTS here")
end tell
end if
end tell
【讨论】:
【参考方案2】:答案是,每当在调用 ioctl() 时使用 TIOCMSET 或 TIOCMGET 时,第三个参数必须是 int。我正在使用一个字符。呃。不敢相信我错过了这个。 TIOCMSET 和 TIOCMGET 定义如下:
#define TIOCMSET _IOW('t', 109, int) /* set all modem bits */
…
#define TIOCMGET _IOR('t', 106, int) /* get all modem bits */
因此不难想象,使用 char 作为我的“标志”变量的类型可能会导致不可预知的行为。
【讨论】:
以上是关于如何在 Mac 插件中使用 ioctl() 设置 RTS?的主要内容,如果未能解决你的问题,请参考以下文章
Python - 使用 C 类型和本机 ioctl() 获取 Mac 地址会产生未知结果
如何从 Mac OS X 中完全删除 Eclipse(包括设置和插件)?