设备不支持的ioctl操作

86

我有一个Perl脚本在AIX服务器上运行。

该脚本尝试从特定目录打开文件,但由于该文件没有读取权限导致无法读取文件,但我收到了一个不同的错误消息,显示为inappropriate ioctl for device

难道它不应该显示类似于文件没有读取权限或类似的内容吗?

这个inappropriate ioctl for device信息是什么意思?

我该如何解决它?

编辑:当我执行strace时,找到了以下内容:

open("/local/logs/xxx/xxxxServer.log", O_WRONLY|O_CREAT|O_APPEND|O_LARGEFILE, 
    0666) = 4 _llseek(4, 0, [77146], SEEK_END) = 0
ioctl(4, SNDCTL_TMR_TIMEBASE or TCGETS, 0xbffc14f8) = -1 ENOTTY 
    (不适当的设备ioctl)

如果你怀疑权限问题,你是否已经尝试在相关文件上设置读取权限了? - Critical Skill
1
更新回应:那是一个可写/追加的打开方式,而不是读取,并且它已成功。 - hobbs
1
是的,正如我在帖子中指出的那样,这根本不是错误。无论如何,它是一种预期的错误,在您使用的抽象级别上没有暴露出来 :) - hobbs
4
不需要再说一遍。请仔细阅读我的回答。只有在正确使用$!时,你才能信任它。 - hobbs
2
或者说ysth的回答。 :) - hobbs
显示剩余3条评论
12个回答

51
很可能意味着打开文件没有失败。当Perl打开文件时,它会检查文件是否为TTY(以便可以回答-T $fh文件测试运算符),方法是发出TCGETS ioctl命令。如果文件是普通文件而不是tty,则ioctl失败并将errno设置为ENOTTY(字符串值:“Inappropriate ioctl for device”)。正如ysth所说,看到$!中出现意外值的最常见原因是在无效情况下进行检查——即在系统调用失败之后的任何其他地方,因此测试操作的结果代码至关重要。如果open实际上对您返回了false,并且您在$!中找到了ENOTTY,那么我认为这是一个小错误(给出了无用的$!值),但我也会非常好奇它是如何发生的。代码和/或跟踪输出将会很棒。

提前进行备忘录记录以便在实际使用/需要时能够更好地利用。这种方法的浪费在于在繁忙的服务器上打开/关闭套接字...Perl也会测试它们是否为tty。 - Erik Aronesty

25

诸如“不适当的ioctl设备”之类的奇怪错误通常是由于在系统调用失败后的某个时间点检查$!而不是仅在其后立即检查引起的。如果您展示代码,我打赌有人会很快指出您的错误。


1
die 总是检查 $! 吗?例如,die "my bad!\n" 并没有明确引用 $! -- 但我却得到了 OP 的错误信息。 - wcochran
@wcochran:die 不会根据 $1 显示消息,但它可以更改进程的错误代码(这将是 $! || $? >> 8 || 255)。 - ysth
所以我想,die 应该只用于由系统调用生成的错误。谢谢。 - wcochran
@wcochran:不,完全不是。如果你关心进程的退出代码,请避免使用die并显式地使用exit(某个数字)。但是,如果你不关心,die将尝试使用具有某些含义的代码,而不仅仅是使用单个默认值。这并不是坏事。 - ysth

11

由于这是一个致命错误,而且很难调试,所以也许可以在提供的命令行中修改修复:

export GPG_TTY=$(tty)

来源:https://github.com/keybase/keybase-issues/issues/2798

该问题可能与您的网络设置有关。在启动Keybase之前,请确保您的计算机已连接到可靠和稳定的互联网连接。如果您使用代理服务器,请尝试将其禁用并重新启动Keybase。如果问题仍然存在,请考虑更改DNS设置或尝试手动打开端口。


3
无论你在谈论什么,似乎都与这个问题不同? - ysth
1
是的,那是一个错误,但我没有删除它,因为出乎意料地得到了一票赞。也许对于在这里迷失的某个人来说会有用。 - Felipe
2
这个答案确实解决了我的问题。我在使用maven-gpg-plugin时遇到了“inappropriate ioctl for device”错误消息(在WSL中,如果有影响的话)。 - gebi

9
“不适当的 ioctl 设备”是 ENOTTY error 的错误字符串。它通常由于在非终端文件描述符(如普通文件)上尝试配置终端属性(例如回显模式)而触发,因此出现 ENOTTY。更一般地,在不支持该ioctl的设备上执行ioctl时也会触发该错误,因此出现该错误字符串。
要找出失败的ioctl及其所在的文件描述符,请在 strace/truss 下运行脚本。您将认出 ENOTTY,然后是实际的错误消息打印。然后找出使用的文件编号以及返回该文件编号的 open() 调用。

7
在*nix类型系统中,“files”是一个非常抽象的概念。它们可以是由文件系统组织的磁盘上的区域,也可以是网络连接、共享内存片段、另一个进程的缓冲输出、屏幕或键盘。
为了让Perl真正有用,它非常接近这种模型,不像许多4GL那样通过模拟磁带来处理文件。
因此,它在一个不允许写操作的文件句柄上尝试了一个“open for write”的“IOCTL”操作,这是该设备/文件的不适当的IOCTL操作。
最简单的方法是在打开操作的末尾放置一个“or die 'Cannot open $myfile'”语句,您可以选择自己的有意义的消息。

4

由于perl5(像往常一样)决定不修复此错误,因此您必须使用已经修复了它的cperl。 - rurban

2

恍然大悟!

我以前遇到过这个错误。

你是否使用类似以下命令调用Perl调试器:-

perl -d yourprog.pl > log.txt

如果是这样,那么Perl调试器会尝试查询并可能重置终端宽度。当stdout不是终端时,这将失败并显示IOCTL消息。
否则,您的调试会话将永远挂起,因为您没有看到指令提示符。

0
我尝试了下面的代码,似乎可以工作:
if(open(my $FILE, "<File.txt")) {
    while(<$FILE>){
    print "$_";}
} else {
    print "File could not be opened or did not exists\n";
}

0
今天在尝试使用代码删除一个挂载在Centos服务器上的Windoze 7共享文件夹/文件时,遇到了这个错误。收到了不适当的设备icotl错误,并尝试了一切能想到的方法。阅读了几乎所有与此相关的网络帖子。
显然,问题仅限于Linux服务器上挂载的Windoze共享。查看了Windoze盒子上的文件权限,并注意到文件的权限设置为只读。
更改了这些权限,回到Linux服务器,一切都按预期工作。这可能不是大多数人的解决方案,但希望它能为某些人节省时间。

0
我在尝试获取文件状态时也遇到了错误 "设备上的不恰当 ioctl"。 这是我第一次有机会使用perl脚本。
以上代码片段抛出了错误。Perl脚本是在Windows上的版本5.12中编写的,我必须在Amazon Linux上运行它,该系统上安装了perl 5.15。
在我的情况下,错误是因为数组索引超出范围(从Java语言角度来看)。
当我修改了代码 my $var = (stat("/home/ec2-user/sample/test/status.xml"))[0][9]; 错误消失了,我得到了正确的值。
当然,回答已经太晚了,但我发表了我的发现,以便对开发者社区有所帮助。 如果一些perl专家能验证一下,那就太好了。。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接