Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1058217
  • 博文数量: 573
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 66
  • 用 户 组: 普通用户
  • 注册时间: 2016-06-28 16:21
文章分类

全部博文(573)

文章存档

2018年(3)

2016年(48)

2015年(522)

分类: LINUX

2015-12-07 15:56:33

 

linux中的errno,你是否踩过它的坑?

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

1. errno是个什么东西?

[plain] view plaincopy
  1. The  header file defines the integer variable errno, which  
  2. is set by system calls and some library functions in the event of an  
  3. error to indicate what went wrong.  Its value is significant only  
  4. when the return value of the call indicated an error (i.e., -1 from  
  5. most system calls; -1 or NULL from most library functions); a  
  6. function that succeeds is allowed to change errno.  
  7.   
  8. Valid error numbers are all nonzero; errno is never set to zero by  
  9. any system call or library function.  
  10.   
  11. For some system calls and library functions (e.g., getpriority(2)),  
  12. -1 is a valid return on success.  In such cases, a successful return  
  13. can be distinguished from an error return by setting errno to zero  
  14. before the call, and then, if the call returns a status that  
  15. indicates that an error may have occurred, checking to see if errno  
  16. has a nonzero value.  
  17.   
  18. errno is defined by the ISO C standard to be a modifiable lvalue of  
  19. type int, and must not be explicitly declared; errno may be a macro.  
  20. errno is thread-local; setting it in one thread does not affect its  
  21. 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文件中:

[plain] view plaincopy
  1. #  if !defined _LIBC || defined _LIBC_REENTRANT  
  2. /* When using threads, errno is a per-thread value.  */  
  3. #   define errno (*__errno_location ())  
  4. #  endif  
  5. # endif /* !__ASSEMBLER__ */  
  6. #endif /* _ERRNO_H */  
也就是说当编译器检查没有定义_LIBC或者定义了_LIBC_REENTRANT,errno就是线程安全的。可以通过如下程序来判断你的系统中这些宏是否被定义:
[plain] view plaincopy
  1. [root@cephenv ~]# cat testenv.c  
  2. #include   
  3. #include   
  4.   
  5. int main( void )  
  6. {  
  7. #ifndef __ASSEMBLER__  
  8.         printf( "__ASSEMBLER__ is not defined\n");  
  9. #else  
  10.         printf( "__ASSEMBLER__ is defined\n");  
  11. #endif  
  12.   
  13. #ifndef __LIBC  
  14.         printf( "__LIBC is not defined\n");  
  15. #else  
  16.         printf( "__LIBC is defined\n");  
  17. #endif  
  18.   
  19. #ifndef _LIBC_REENTRANT  
  20.         printf( "_LIBC_REENTRANT is not defined\n");  
  21. #else  
  22.         printf( "_LIBC_REENTRANT is defined\n");  
  23. #endif  
  24.   
  25.         return 0;  
  26. }  
在我的系统中输出的结果是:
[plain] view plaincopy
  1. [root@cephenv ~]# ./a.out  
  2. __ASSEMBLER__ is not defined  
  3. __LIBC is not defined  
  4. _LIBC_REENTRANT is not defined  
由于 __LIBC没有被定义,所以errno是线程安全的。其实,通过gcc编译一般的应用程序时__LIBC都是没有定义的。


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

[plain] view plaincopy
  1. [root@cephenv ~]# cat printerrno.c  
  2. #include   
  3. #include   
  4.   
  5. int main(int argc, char *argv[])  
  6. {  
  7.     int i = 0;  
  8.   
  9.     for (; i < 256; i++)  
  10.         printf("errno %d: %s\n", i, strerror(i));  
  11.   
  12.     return 0;  
  13. }  
趁机也贴出每个errno的解释:
[plain] view plaincopy
  1. [root@cephenv ~]# ./a.out  
  2. errno 0: Success  
  3. errno 1: Operation not permitted  
  4. errno 2: No such file or directory  
  5. errno 3: No such process  
  6. errno 4: Interrupted system call  
  7. errno 5: Input/output error  
  8. errno 6: No such device or address  
  9. errno 7: Argument list too long  
  10. errno 8: Exec format error  
  11. errno 9: Bad file descriptor  
  12. errno 10: No child processes  
  13. errno 11: Resource temporarily unavailable  
  14. errno 12: Cannot allocate memory  
  15. errno 13: Permission denied  
  16. errno 14: Bad address  
  17. errno 15: Block device required  
  18. errno 16: Device or resource busy  
  19. errno 17: File exists  
  20. errno 18: Invalid cross-device link  
  21. errno 19: No such device  
  22. errno 20: Not a directory  
  23. errno 21: Is a directory  
  24. errno 22: Invalid argument  
  25. errno 23: Too many open files in system  
  26. errno 24: Too many open files  
  27. errno 25: Inappropriate ioctl for device  
  28. errno 26: Text file busy  
  29. errno 27: File too large  
  30. errno 28: No space left on device  
  31. errno 29: Illegal seek  
  32. errno 30: Read-only file system  
  33. errno 31: Too many links  
  34. errno 32: Broken pipe  
  35. errno 33: Numerical argument out of domain  
  36. errno 34: Numerical result out of range  
  37. errno 35: Resource deadlock avoided  
  38. errno 36: File name too long  
  39. errno 37: No locks available  
  40. errno 38: Function not implemented  
  41. errno 39: Directory not empty  
  42. errno 40: Too many levels of symbolic links  
  43. errno 41: Unknown error 41  
  44. errno 42: No message of desired type  
  45. errno 43: Identifier removed  
  46. errno 44: Channel number out of range  
  47. errno 45: Level 2 not synchronized  
  48. errno 46: Level 3 halted  
  49. errno 47: Level 3 reset  
  50. errno 48: Link number out of range  
  51. errno 49: Protocol driver not attached  
  52. errno 50: No CSI structure available  
  53. errno 51: Level 2 halted  
  54. errno 52: Invalid exchange  
  55. errno 53: Invalid request descriptor  
  56. errno 54: Exchange full  
  57. errno 55: No anode  
  58. errno 56: Invalid request code  
  59. errno 57: Invalid slot  
  60. errno 58: Unknown error 58  
  61. errno 59: Bad font file format  
  62. errno 60: Device not a stream  
  63. errno 61: No data available  
  64. errno 62: Timer expired  
  65. errno 63: Out of streams resources  
  66. errno 64: Machine is not on the network  
  67. errno 65: Package not installed  
  68. errno 66: Object is remote  
  69. errno 67: Link has been severed  
  70. errno 68: Advertise error  
  71. errno 69: Srmount error  
  72. errno 70: Communication error on send  
  73. errno 71: Protocol error  
  74. errno 72: Multihop attempted  
  75. errno 73: RFS specific error  
  76. errno 74: Bad message  
  77. errno 75: Value too large for defined data type  
  78. errno 76: Name not unique on network  
  79. errno 77: File descriptor in bad state  
  80. errno 78: Remote address changed  
  81. errno 79: Can not access a needed shared library  
  82. errno 80: Accessing a corrupted shared library  
  83. errno 81: .lib section in a.out corrupted  
  84. errno 82: Attempting to link in too many shared libraries  
  85. errno 83: Cannot exec a shared library directly  
  86. errno 84: Invalid or incomplete multibyte or wide character  
  87. errno 85: Interrupted system call should be restarted  
  88. errno 86: Streams pipe error  
  89. errno 87: Too many users  
  90. errno 88: Socket operation on non-socket  
  91. errno 89: Destination address required  
  92. errno 90: Message too long  
  93. errno 91: Protocol wrong type for socket  
  94. errno 92: Protocol not available  
  95. errno 93: Protocol not supported  
  96. errno 94: Socket type not supported  
  97. errno 95: Operation not supported  
  98. errno 96: Protocol family not supported  
  99. errno 97: Address family not supported by protocol  
  100. errno 98: Address already in use  
  101. errno 99: Cannot assign requested address  
  102. errno 100: Network is down  
  103. errno 101: Network is unreachable  
  104. errno 102: Network dropped connection on reset  
  105. errno 103: Software caused connection abort  
  106. errno 104: Connection reset by peer  
  107. errno 105: No buffer space available  
  108. errno 106: Transport endpoint is already connected  
  109. errno 107: Transport endpoint is not connected  
  110. errno 108: Cannot send after transport endpoint shutdown  
  111. errno 109: Too many references: cannot splice  
  112. errno 110: Connection timed out  
  113. errno 111: Connection refused  
  114. errno 112: Host is down  
  115. errno 113: No route to host  
  116. errno 114: Operation already in progress  
  117. errno 115: Operation now in progress  
  118. errno 116: Stale file handle  
  119. errno 117: Structure needs cleaning  
  120. errno 118: Not a XENIX named type file  
  121. errno 119: No XENIX semaphores available  
  122. errno 120: Is a named type file  
  123. errno 121: Remote I/O error  
  124. errno 122: Disk quota exceeded  
  125. errno 123: No medium found  
  126. errno 124: Wrong medium type  
  127. errno 125: Operation canceled  
  128. errno 126: Required key not available  
  129. errno 127: Key has expired  
  130. errno 128: Key has been revoked  
  131. errno 129: Key was rejected by service  
  132. errno 130: Owner died  
  133. errno 131: State not recoverable  
  134. errno 132: Operation not possible due to RF-kill  
4. errno使用的注意事项。
其实也就两条:
1)当使用系统调用和库函数时,除了函数的返回值,记得还要考虑errno的值啊。
2)并不是所有的系统调用活着库函数都会设置errno的值,如果你的程序对它有依赖,需要开发人员在接口错误处理中,手工设置。
阅读(1593) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~