Linux 系统错误码 errno 剖析
一、errno 介绍
1.1 errno 简介
Linux 中系统调用的错误都存储于错误码 errno 中。errno 由操作系统维护,存储就近发生的错误,即下一次的错误码会覆盖掉上一次的错误。
errno 是一个包含在 <errno.h> 中的预定义的外部 int 变量,用于表示最近一个函数调用是否产生了错误。
- 若为0,则无错误;
- 其它值均表示某一种错误。
代码中需要包含 #include <errno.h>,当一个系统调用或着库函数的调用失败时,将会重置错误码 errno。用户在判断程序出错后,立即检验 errno 的值可以获取错误码和错误信息。
1.2 errno是线程安全的
在 Linux 上,全局 errno 变量是特定于线程的。POSIX 要求 errno 必须是线程安全的。
参阅:Thread-safety and POSIX.1 (unix.org)
在 POSIX.1 中,errno 被定义为外部全局变量。但是此定义在多线程环境中是不可接受的,因为使用它会导致不确定的结果。问题是两个或多个线程可能会遇到错误,所有错误都会导致设置相同的错误号。在这种情况下,一个线程可能已经被另一个线程更新后,最终检查 errno。
为了避免产生不确定性,POSIX.1c 将 errno 重新定义为可以访问每个线程错误号的服务:
- 某些函数可能在通过符号 errno 访问的变量中提供错误号。
- errno 符号是通过包括 C 标准所指定的标头来定义的。
- 对于进程的每个线程,errno 的值不应受函数调用或其他线程对 errno 的分配的影响。
参阅:errno(3): number of last error - Linux man page (die.net)
errno 是线程本地的;在一个线程中设置它不会影响在其他任何线程中的值
我们可以通过在机器上运行一个简单的程序来进行检查。
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#define NTHREADS 5
void *thread_function(void *dummyPtr)
{
printf("Thread number %ld addr(errno):%p\n", pthread_self(), &errno);
}
int main()
{
pthread_t thread_id[NTHREADS];
int i, j;
for (i = 0; i < NTHREADS; i++)
{
pthread_create(&thread_id[i], NULL, thread_function, NULL);
}
for (j = 0; j < NTHREADS; j++)
{
pthread_join(thread_id[j], NULL);
}
return 0;
}
输出结果:

1.3 errno 宏定义
在头文件「/usr/include/asm-generic/errno-base.h」中对基础的常用 errno 进行了宏定义:
| define | errno | explain |
|---|---|---|
| EPERM | 1 | Operation not permitted |
| ENOENT | 2 | No such file or directory |
| ESRCH | 3 | No such process |
| EINTR | 4 | Interrupted system call |
| EIO | 5 | I/O error |
| ENXIO | 6 | No such device or address |
| E2BIG | 7 | Argument list too long |
| ENOEXEC | 8 | Exec format error |
| EBADF | 9 | Bad file number |
| ECHILD | 10 | No child processes |
| EAGAIN | 11 | Try again |
| ENOMEM | 12 | Out of memory |
| EACCES | 13 | Permission denied |
| EFAULT | 14 | Bad address |
| ENOTBLK | 15 | Block device required |
| EBUSY | 16 | Device or resource busy |
| EEXIST | 17 | File exists |
| EXDEV | 18 | Cross-device link |
| ENODEV | 19 | No such device |
| ENOTDIR | 20 | Not a directory |
| EISDIR | 21 | Is a directory |
| EINVAL | 22 | Invalid argument |
| ENFILE | 23 | File table overflow |
| EMFILE | 24 | Too many open files |
| ENOTTY | 25 | Not a typewriter |
| ETXTBSY | 26 | Text file busy |
| EFBIG | 27 | File too large |
| ENOSPC | 28 | No space left on device |
| ESPIPE | 29 | Illegal seek |
| EROFS | 30 | Read-only file system |
| EMLINK | 31 | Too many links |
| EPIPE | 32 | Broken pipe |
| EDOM | 33 | Math argument out of domain of func |
| ERANGE | 34 | Math result not representable |
在 「/usr/include/asm-generic/errno.h」 中,对剩余的 errno 做了宏定义:
| define | errno | explain |
|---|---|---|
| EDEADLK | 35 | Resource deadlock would occur |
| ENAMETOOLONG | 36 | File name too long |
| ENOLCK | 37 | No record locks available |
| ENOSYS | 38 | Function not implemented |
| ENOTEMPTY | 39 | Directory not empty |
| ELOOP | 40 | Too many symbolic links encountered |
| EWOULDBLOCK | EAGAIN | Operation would block |
| ENOMSG | 42 | No message of desired type |
| EIDRM | 43 | Identifier removed |
| ECHRNG | 44 | Channel number out of range |
| EL2NSYNC | 45 | Level 2 not synchronized |
| EL3HLT | 46 | Level 3 halted |
| EL3RST | 47 | Level 3 reset |
| ELNRNG | 48 | Link number out of range |
| EUNATCH | 49 | Protocol driver not attached |
| ENOCSI | 50 | No CSI structure available |
| EL2HLT | 51 | Level 2 halted |
| EBADE | 52 | Invalid exchange |
| EBADR | 53 | Invalid request descriptor |
| EXFULL | 54 | Exchange full |
| ENOANO | 55 | No anode |
| EBADRQC | 56 | Invalid request code |
| EBADSLT | 57 | Invalid slot |
| EDEADLOCK | EDEADLK | |
| EBFONT | 59 | Bad font file format |
| ENOSTR | 60 | Device not a stream |
| ENODATA | 61 | No data available |
| ETIME | 62 | Timer expired |
| ENOSR | 63 | Out of streams resources |
| ENONET | 64 | Machine is not on the network |
| ENOPKG | 65 | Package not installed |
| EREMOTE | 66 | Object is remote |
| ENOLINK | 67 | Link has been severed |
| EADV | 68 | Advertise error |
| ESRMNT | 69 | Srmount error |
| ECOMM | 70 | Communication error on send |
| EPROTO | 71 | Protocol error |
| EMULTIHOP | 72 | Multihop attempted |
| EDOTDOT | 73 | RFS specific error |
| EBADMSG | 74 | Not a data message |
| EOVERFLOW | 75 | Value too large for defined data type |
| ENOTUNIQ | 76 | Name not unique on network |
| EBADFD | 77 | File descriptor in bad state |
| EREMCHG | 78 | Remote address changed |
| ELIBACC | 79 | Can not access a needed shared library |
| ELIBBAD | 80 | Accessing a corrupted shared library |
| ELIBSCN | 81 | .lib section in a.out corrupted |
| ELIBMAX | 82 | Attempting to link in too many shared libraries |
| ELIBEXEC | 83 | Cannot exec a shared library directly |
| EILSEQ | 84 | Illegal byte sequence |
| ERESTART | 85 | Interrupted system call should be restarted |
| ESTRPIPE | 86 | Streams pipe error |
| EUSERS | 87 | Too many users |
| ENOTSOCK | 88 | Socket operation on non-socket |
| EDESTADDRREQ | 89 | Destination address required |
| EMSGSIZE | 90 | Message too long |
| EPROTOTYPE | 91 | Protocol wrong type for socket |
| ENOPROTOOPT | 92 | Protocol not available |
| EPROTONOSUPPORT | 93 | Protocol not supported |
| ESOCKTNOSUPPORT | 94 | Socket type not supported |
| EOPNOTSUPP | 95 | Operation not supported on transport endpoint |
| EPFNOSUPPORT | 96 | Protocol family not supported |
| EAFNOSUPPORT | 97 | Address family not supported by protocol |
| EADDRINUSE | 98 | Address already in use |
| EADDRNOTAVAIL | 99 | Cannot assign requested address |
| ENETDOWN | 100 | Network is down |
| ENETUNREACH | 101 | Network is unreachable |
| ENETRESET | 102 | Network dropped connection because of reset |
| ECONNABORTED | 103 | Software caused connection abort |
| ECONNRESET | 104 | Connection reset by peer |
| ENOBUFS | 105 | No buffer space available |
| EISCONN | 106 | Transport endpoint is already connected |
| ENOTCONN | 107 | Transport endpoint is not connected |
| ESHUTDOWN | 108 | Cannot send after transport endpoint shutdown |
| ETOOMANYREFS | 109 | Too many references: cannot splice |
| ETIMEDOUT | 110 | Connection timed out |
| ECONNREFUSED | 111 | Connection refused |
| EHOSTDOWN | 112 | Host is down |
| EHOSTUNREACH | 113 | No route to host |
| EALREADY | 114 | Operation already in progress |
| EINPROGRESS | 115 | Operation now in progress |
| ESTALE | 116 | Stale file handle |
| EUCLEAN | 117 | Structure needs cleaning |
| ENOTNAM | 118 | Not a XENIX named type file |
| ENAVAIL | 119 | No XENIX semaphores available |
| EISNAM | 120 | Is a named type file |
| EREMOTEIO | 121 | Remote I/O error |
| EDQUOT | 122 | Quota exceeded |
| ENOMEDIUM | 123 | No medium found |
| EMEDIUMTYPE | 124 | Wrong medium type |
| ECANCELED | 125 | Operation Canceled |
| ENOKEY | 126 | Required key not available |
| EKEYEXPIRED | 127 | Key has expired |
| EKEYREVOKED | 128 | Key has been revoked |
| EKEYREJECTED | 129 | Key was rejected by service |
| EOWNERDEAD | 130 | Owner died |
| ENOTRECOVERABLE | 131 | State not recoverable |
| ERFKILL | 132 | Operation not possible due to RF-kill |
| EHWPOISON | 133 | Memory page has hardware error |
二、打印 errno
若想要打印 errno,需要包含头文件 #include <errno.h>。
2.1 使用 perror 打印错误信息
函数原型:void perror(const char *s)
头 文 件:#include <stdio.h>
作 用:打印系统错误信息
2.2 使用 strerror 显示错误信息
函数原型:char *strerror(int errnum);
头 文 件:#include <string.h>
作 用:将错误码以字符串的信息显示出来
三、输出 errno 的小 Demo
#include <stdio.h>
#include <string.h>
static void __Process(char *str)
{
if (strstr(str, "_ASM_GENERIC_") != NULL || strstr(str, "define") == NULL)
{
return;
}
if (strstr(str, "EWOULDBLOCK") != NULL || strstr(str, "EDEADLOCK") != NULL)
{
return;
}
char szDefine[64] = {0};
int errno = -1;
char szExplain[64] = {0};
sscanf(str, "%*[^A-Z]%s%*[^0-9]%d %*[^*]* %[^*]s", szDefine, &errno, szExplain);
szExplain[strlen(szExplain) - 1] = 0; // 去除最后的空格
char buf[1024] = {0};
snprintf(buf, sizeof(buf), "|%s|%d|%s|", szDefine, errno, szExplain);
puts(buf);
}
int main()
{
freopen("/usr/include/asm-generic/errno-base.h", "r", stdin); // 读文件
// freopen("E:\\Documents\\stdin&&stdout\\stdout\\文件名", "w", stdout); // 写文件
while (1)
{
char str[1024] = {0};
fgets(str, sizeof(str), stdin);
if (0 == strncmp(str, "#endif", 6))
break;
__Process(str);
}
puts("-----------------------------------------------------------");
freopen("/usr/include/asm-generic/errno.h", "r", stdin); // 读文件
while (1)
{
char str[1024] = {0};
fgets(str, sizeof(str), stdin);
if (0 == strncmp(str, "#endif", 6))
break;
__Process(str);
}
}
参考资料
- Linux errno详解 - Jimmy_Nie - 博客园 (cnblogs.com)
- errno 介绍_shanandqiu的博客-CSDN博客
- sscanf函数使用详解_faihung的博客-CSDN博客
- fgets函数及其用法,C语言fgets函数详解_发狂的蜗牛的博客-CSDN博客
Linux 系统错误码 errno 剖析的更多相关文章
- Linux系统错误码对照表
C Name Value Description EPERM 1 Operation not permitted ENOENT 2 No such file or directory ESRCH 3 ...
- linux系统错误码大全
#define EPERM 1 /* Operation not permitted */ #define ENOENT 2 /* No such file or directory */ #defi ...
- Redis 源码简洁剖析 09 - Reactor 模型
Reactor 模型 事件驱动框架 Redis 如何实现 Reactor 模型 事件的数据结构:aeFileEvent 主循环:aeMain 函数 事件捕获与分发:aeProcessEvents 函数 ...
- Redis 源码简洁剖析 10 - aeEventLoop 及事件
aeEventLoop IO 事件处理 IO 事件创建 读事件处理 写事件处理 时间事件处理 时间事件定义 时间事件创建 时间事件回调函数 时间事件的触发处理 参考链接 Redis 源码简洁剖析系列 ...
- TCP/IP 某些最常见的错误原因码 (errno)列表
对于在基于 UNIX 的环境中的 TCP/IP 用户,下表列出了某些最常见的错误原因码 (errno).它不是完整的错误列表.可以在文件 /usr/include/sys/errno.h 中找到 Er ...
- TCP/IP 最常见的错误原因码 (errno)列表
对于在基于 UNIX 的环境中的 TCP/IP 用户,下表列出了某些最常见的错误原因码 (errno).它不是完整的错误列表.可以在文件 /usr/include/sys/errno.h 中找到 Er ...
- linux lcd设备驱动剖析四
在"linux lcd设备驱动剖析二"文章中,我们详细分析了s3c24xxfb_probe函数. 文章链接:http://blog.csdn.net/lwj103862095/ar ...
- linux lcd设备驱动剖析一
s3c2440 lcd驱动源码文件是:drivers/video/s3c2410fb.c 看驱动源码首先当然是先看入口函数,这里是s3c2410fb_init函数 [cpp] view plain? ...
- libevent源码深度剖析十一
libevent源码深度剖析十一 ——时间管理 张亮 为了支持定时器,Libevent必须和系统时间打交道,这一部分的内容也比较简单,主要涉及到时间的加减辅助函数.时间缓存.时间校正和定时器堆的时间值 ...
- libevent源码深度剖析十
libevent源码深度剖析十 ——支持I/O多路复用技术 张亮 Libevent的核心是事件驱动.同步非阻塞,为了达到这一目标,必须采用系统提供的I/O多路复用技术,而这些在Windows.Linu ...
随机推荐
- Markdown常用书写语法合集
1. 文字设置 1.1 文字颜色 中常用的文字颜色有: 红色文字:<font color="red">红色文字</font> 浅红色文字:<font ...
- 1.7 完善自定位ShellCode
在之前的文章中,我们实现了一个正向的匿名管道ShellCode后门,为了保证文章的简洁易懂并没有增加针对调用函数的动态定位功能,此类方法在更换系统后则由于地址变化导致我们的后门无法正常使用,接下来将实 ...
- C++ STL 标准模板库(容器总结)算法
C++ 标准模板库STL,是一个使用模板技术实现的通用程序库,该库由容器container,算法algorithm,迭代器iterator,容器和算法之间通过迭代器进行无缝连接,其中所包含的数据结构都 ...
- 10、数据库学习规划:MySQL - 学习规划系列文章
MySQL数据库是笔者认识的几个流行的数据库之一.类似于Linux重装系统,其也是开源的,最主要是有很多的社区支持,众多的开发者对其能够进行使用,所以其功能也挺强大,便于使用.通过对MySQL数据库的 ...
- 神经网络优化篇:详解Batch Norm 为什么奏效?(Why does Batch Norm work?)
Batch Norm 为什么奏效? 为什么Batch归一化会起作用呢? 一个原因是,已经看到如何归一化输入特征值\(x\),使其均值为0,方差1,它又是怎样加速学习的,有一些从0到1而不是从1到100 ...
- 小知识:PDML的注意事项补充
关于PDML,之前在 并行,想说爱你不容易中的第一节就介绍过,今天在客户现场协助测试时又遇到几个有关PDML的问题,都蛮典型的,记录一下: 问题1:某存储过程报错ORA-12839. 查看该错误号说明 ...
- OGG-Postgres实时同步到MySQL
(一)数据库信息 名称 源端数据库 目标端数据库 数据库类型 Postgresql 12.4 MySQL 5.7 IP地址 20.2.127.23 20.2.127.24 端口 5432 3306 数 ...
- Linux命令-文件、磁盘管理
Linux命令-文件.磁盘管理 1.文件管理 查看文件信息:ls ls是英文单词list的简写,其功能为列出目录的内容,是用户最常用的命令之一,它类似于DOS下的dir命令. Linux文件或者目 ...
- 100 行代码实现用户登录注册与 RESTful 接口 - 手把手教程附 Python 源码
在开发大多数应用时,用户系统都是必不可少的部分,而我们总是需要开发围绕用户的登录,注册,获取,更新等接口.在这篇文章将带你用一百多行代码简洁地实现一套这样的用户鉴权与 RESTful 接口,并使用 S ...
- CF1010C Border 题解
题目传送门 前置知识 最大公约数 | 裴蜀定理 简化题意 给定一个长度为 \(n\) 的序列 \(a\),求 \((\sum\limits_{i=1}^{n}d_ia_i) \bmod k\) 一共会 ...