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 ...
随机推荐
- c++基础之函数
距离上次更新又过了一周,又该更新新的读书笔记了.本次更新的主要是c++中函数部分的内容 c++ 中的函数与c语言中的函数大致用法或者语法是一样的,这里就不就这点详细展开了.需要注意的是c/c++中并没 ...
- PaddleNLP基于ERNIR3.0文本分类以CAIL2018-SMALL数据集罪名预测任务为例【多标签】
相关项目链接: Paddlenlp之UIE模型实战实体抽取任务[打车数据.快递单] Paddlenlp之UIE分类模型[以情感倾向分析新闻分类为例]含智能标注方案) 应用实践:分类模型大集成者[Pad ...
- CE修改器入门:查找多级指针
本关是第6关的加强版,CE 6.X 教程中的4级指针比5.X的要简单些.多级指针就像玩解谜游戏一样,谜团不只一个,盒子中还有盒子.这里面是4级指针,游戏中也有比如8级指针,12级指针等等,思路都是一样 ...
- Python 原生Socket实现端口扫描
端口扫描,就是逐个对一段端口或指定的端口进行扫描.通过扫描结果可以知道一台计算机上都提供了哪些服务,Python中使用Socket即可实现对特定端口的探测,以及对C段的扫描. 扫描目标主机Banner ...
- C/C++ 获取自身IP与域名片段
判断大端序小端序: 通常情况下,数值在内存中存储的方式有两种,一种是大尾字节序,另一种是小尾,比如0x01020304这样一个数值,如果用大尾方式存储,其存储方式为01 02 03 04而用小尾方式存 ...
- FFmpeg的录制命令
FFmpeg的录制命令 命令的作用 它可以捕捉桌面窗口,摄像头的视频流和麦克风的音频流. 命令的格式 ffmpeg [输入格式] [输入选项] -i [输入设备索引] [输出选项] 输出文件 其中输入 ...
- powerDesigner 逆向工程 mysql 生成 PDM
1. 信息补充说明 powerDesigner 16.5 mysql 5.6 主要内容:使用powerDesigner的逆向工程,将mysql中的数据库转换成PDM文件 所需资源: powerDe ...
- (Python)每日代码||2024.1.18
m = 10 a = 10 print(id(m)) print(id(a)) '''输出 140713874176728 140713874176728 ''' print() a = 1 b = ...
- 素数打表,洛谷P1217 [USACO1.5]回文质数 Prime Palindromes
这道题的最后一个样例TLE(超时)了,判断素数的条件是 i*i<n 1 #include<stdio.h> 2 #include<stdlib.h> 3 #include ...
- 基于keras的残差网络
1 前言 理论上,网络层数越深,拟合效果越好.但是,层数加深也会导致梯度消失或梯度爆炸现象产生.当网络层数已经过深时,深层网络表现为"恒等映射".实践表明,神经网络对残差的学习比对 ...