博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
linux中的errno,你是否踩过它的坑?
阅读量:4026 次
发布时间:2019-05-24

本文共 7628 字,大约阅读时间需要 25 分钟。

之所以写这篇文章,是因为我踩过它的坑。背景是我在做一个项目时,其中有一部分是在QEMU中调用cephfs的接口,期间有个函数ceph_lstat(),明明返回了错误的值,但QEMU缺认为这个调用没用问题,当时我没有觉得这个函数本身有问题,所以一直在debug别的东西。整整花了一周,终于找到了原因:QEMU中有些错误处理依赖于errno的值,但cephfs的接口在发生error时不会去设置它,我勒个去,当时我就泪奔了。。。鉴于我惨痛的经历,所以在这里将errno的信息整理一下,方便大家了解。另外也希望给大家提一个醒,当你得程序涉及系统调用时,记得要考虑errno这个隐形的杀手。

1. errno是个什么东西?

The 
header file defines the integer variable errno, which is set by system calls and some library functions in the event of an error to indicate what went wrong. Its value is significant only when the return value of the call indicated an error (i.e., -1 from most system calls; -1 or NULL from most library functions); a function that succeeds is allowed to change errno. Valid error numbers are all nonzero; errno is never set to zero by any system call or library function. For some system calls and library functions (e.g., getpriority(2)), -1 is a valid return on success. In such cases, a successful return can be distinguished from an error return by setting errno to zero before the call, and then, if the call returns a status that indicates that an error may have occurred, checking to see if errno has a nonzero value. errno is defined by the ISO C standard to be a modifiable lvalue of type int, and must not be explicitly declared; errno may be a macro. errno is thread-local; setting it in one thread does not affect its value in any other thread.
以上是linux中关于errno的manpage,大意可以概括为:
1)errno是一个整型变量,当系统调用和一些库函数发生错误时会通过设置errno的值来告诉调用者出了什么问题。
2)errno的有效值都是非零的。(这个manpage有个悖论,第二段中说,errno从来不能被设为0,而在第三段又说有些接口会将其设置为0)
3)errno在ISO C标准中定义的,它可能是一个宏并且不能被显示声明(也就是重新定义)。
4)errno是线程安全的,在一个线程中设置它,不会影响别的线程对它的使用。这一点很重要,不知道有没有像我之前有过这样的问题:看起来errno像是一个全局的变量,应该不是线程安全的吧?看了这个之后,就有答案了,errno是thread-local的,也就是每个线程都有一个。

2. errno的定义

errno被定义在/usr/include/bits/errno.h文件中:

#  if !defined _LIBC || defined _LIBC_REENTRANT/* When using threads, errno is a per-thread value.  */#   define errno (*__errno_location ())#  endif# endif /* !__ASSEMBLER__ */#endif /* _ERRNO_H */
也就是说当编译器检查没有定义_LIBC或者定义了_LIBC_REENTRANT,errno就是线程安全的。可以通过如下程序来判断你的系统中这些宏是否被定义:
[root@cephenv ~]# cat testenv.c#include 
#include
int main( void ){#ifndef __ASSEMBLER__ printf( "__ASSEMBLER__ is not defined\n");#else printf( "__ASSEMBLER__ is defined\n");#endif#ifndef __LIBC printf( "__LIBC is not defined\n");#else printf( "__LIBC is defined\n");#endif#ifndef _LIBC_REENTRANT printf( "_LIBC_REENTRANT is not defined\n");#else printf( "_LIBC_REENTRANT is defined\n");#endif return 0;}
在我的系统中输出的结果是:
[root@cephenv ~]# ./a.out__ASSEMBLER__ is not defined__LIBC is not defined_LIBC_REENTRANT is not defined
由于 __LIBC没有被定义,所以errno是线程安全的。其实,通过gcc编译一般的应用程序时__LIBC都是没有定义的。

3. errno各返回值的含义:

它的每个值的含义定义在/usr/include/asm-generic/errno-base.h文件中(貌似不全啊),也可以通过strerror写一个小程序来输出错误码对应的解释:

[root@cephenv ~]# cat printerrno.c#include 
#include
int main(int argc, char *argv[]){ int i = 0; for (; i < 256; i++) printf("errno %d: %s\n", i, strerror(i)); return 0;}
趁机也贴出每个errno的解释:
[root@cephenv ~]# ./a.outerrno 0: Successerrno 1: Operation not permittederrno 2: No such file or directoryerrno 3: No such processerrno 4: Interrupted system callerrno 5: Input/output errorerrno 6: No such device or addresserrno 7: Argument list too longerrno 8: Exec format errorerrno 9: Bad file descriptorerrno 10: No child processeserrno 11: Resource temporarily unavailableerrno 12: Cannot allocate memoryerrno 13: Permission deniederrno 14: Bad addresserrno 15: Block device requirederrno 16: Device or resource busyerrno 17: File existserrno 18: Invalid cross-device linkerrno 19: No such deviceerrno 20: Not a directoryerrno 21: Is a directoryerrno 22: Invalid argumenterrno 23: Too many open files in systemerrno 24: Too many open fileserrno 25: Inappropriate ioctl for deviceerrno 26: Text file busyerrno 27: File too largeerrno 28: No space left on deviceerrno 29: Illegal seekerrno 30: Read-only file systemerrno 31: Too many linkserrno 32: Broken pipeerrno 33: Numerical argument out of domainerrno 34: Numerical result out of rangeerrno 35: Resource deadlock avoidederrno 36: File name too longerrno 37: No locks availableerrno 38: Function not implementederrno 39: Directory not emptyerrno 40: Too many levels of symbolic linkserrno 41: Unknown error 41errno 42: No message of desired typeerrno 43: Identifier removederrno 44: Channel number out of rangeerrno 45: Level 2 not synchronizederrno 46: Level 3 haltederrno 47: Level 3 reseterrno 48: Link number out of rangeerrno 49: Protocol driver not attachederrno 50: No CSI structure availableerrno 51: Level 2 haltederrno 52: Invalid exchangeerrno 53: Invalid request descriptorerrno 54: Exchange fullerrno 55: No anodeerrno 56: Invalid request codeerrno 57: Invalid sloterrno 58: Unknown error 58errno 59: Bad font file formaterrno 60: Device not a streamerrno 61: No data availableerrno 62: Timer expirederrno 63: Out of streams resourceserrno 64: Machine is not on the networkerrno 65: Package not installederrno 66: Object is remoteerrno 67: Link has been severederrno 68: Advertise errorerrno 69: Srmount errorerrno 70: Communication error on senderrno 71: Protocol errorerrno 72: Multihop attemptederrno 73: RFS specific errorerrno 74: Bad messageerrno 75: Value too large for defined data typeerrno 76: Name not unique on networkerrno 77: File descriptor in bad stateerrno 78: Remote address changederrno 79: Can not access a needed shared libraryerrno 80: Accessing a corrupted shared libraryerrno 81: .lib section in a.out corruptederrno 82: Attempting to link in too many shared librarieserrno 83: Cannot exec a shared library directlyerrno 84: Invalid or incomplete multibyte or wide charactererrno 85: Interrupted system call should be restartederrno 86: Streams pipe errorerrno 87: Too many userserrno 88: Socket operation on non-socketerrno 89: Destination address requirederrno 90: Message too longerrno 91: Protocol wrong type for socketerrno 92: Protocol not availableerrno 93: Protocol not supportederrno 94: Socket type not supportederrno 95: Operation not supportederrno 96: Protocol family not supportederrno 97: Address family not supported by protocolerrno 98: Address already in useerrno 99: Cannot assign requested addresserrno 100: Network is downerrno 101: Network is unreachableerrno 102: Network dropped connection on reseterrno 103: Software caused connection aborterrno 104: Connection reset by peererrno 105: No buffer space availableerrno 106: Transport endpoint is already connectederrno 107: Transport endpoint is not connectederrno 108: Cannot send after transport endpoint shutdownerrno 109: Too many references: cannot spliceerrno 110: Connection timed outerrno 111: Connection refusederrno 112: Host is downerrno 113: No route to hosterrno 114: Operation already in progresserrno 115: Operation now in progresserrno 116: Stale file handleerrno 117: Structure needs cleaningerrno 118: Not a XENIX named type fileerrno 119: No XENIX semaphores availableerrno 120: Is a named type fileerrno 121: Remote I/O errorerrno 122: Disk quota exceedederrno 123: No medium founderrno 124: Wrong medium typeerrno 125: Operation cancelederrno 126: Required key not availableerrno 127: Key has expirederrno 128: Key has been revokederrno 129: Key was rejected by serviceerrno 130: Owner diederrno 131: State not recoverableerrno 132: Operation not possible due to RF-kill
4. errno使用的注意事项。
其实也就两条:
1)当使用系统调用和库函数时,除了函数的返回值,记得还要考虑errno的值啊。
2)并不是所有的系统调用活着库函数都会设置errno的值,如果你的程序对它有依赖,需要开发人员在接口错误处理中,手工设置。

转载地址:http://usxbi.baihongyu.com/

你可能感兴趣的文章
iOS QQ侧滑菜单(高仿)
查看>>
iOS 扫一扫功能开发
查看>>
iOS app之间的跳转以及传参数
查看>>
iOS __block和__weak的区别
查看>>
Android(三)数据存储之XML解析技术
查看>>
Spring JTA应用之JOTM配置
查看>>
spring JdbcTemplate 的若干问题
查看>>
Servlet和JSP的线程安全问题
查看>>
GBK编码下jQuery Ajax中文乱码终极暴力解决方案
查看>>
jQuery性能优化指南
查看>>
Oracle 物化视图
查看>>
PHP那点小事--三元运算符
查看>>
解决国内NPM安装依赖速度慢问题
查看>>
Brackets安装及常用插件安装
查看>>
在CentOS 7系统上搭建LNMP 环境
查看>>
Centos 7(Linux)环境下安装PHP(编译添加)相应动态扩展模块so(以openssl.so为例)
查看>>
fastcgi_param 详解
查看>>
Nginx配置文件(nginx.conf)配置详解
查看>>
标记一下
查看>>
一个ahk小函数, 实现版本号的比较
查看>>