Linux 系统错误码 errno 剖析

时间:2024-01-03 18:10:41 买帖  | 投诉/举报

篇首语:本文由小编为大家整理,主要介绍了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 5void *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 进行了宏定义:

defineerrnoexplain
EPERM1Operation not permitted
ENOENT2No such file or directory
ESRCH3No such process
EINTR4Interrupted system call
EIO5I/O error
ENXIO6No such device or address
E2BIG7Argument list too long
ENOEXEC8Exec format error
EBADF9Bad file number
ECHILD10No child processes
EAGAIN11Try again
ENOMEM12Out of memory
EACCES13Permission denied
EFAULT14Bad address
ENOTBLK15Block device required
EBUSY16Device or resource busy
EEXIST17File exists
EXDEV18Cross-device link
ENODEV19No such device
ENOTDIR20Not a directory
EISDIR21Is a directory
EINVAL22Invalid argument
ENFILE23File table overflow
EMFILE24Too many open files
ENOTTY25Not a typewriter
ETXTBSY26Text file busy
EFBIG27File too large
ENOSPC28No space left on device
ESPIPE29Illegal seek
EROFS30Read-only file system
EMLINK31Too many links
EPIPE32Broken pipe
EDOM33Math argument out of domain of func
ERANGE34Math result not representable

在 「/usr/include/asm-generic/errno.h」 中,对剩余的 errno 做了宏定义:

defineerrnoexplain
EDEADLK35Resource deadlock would occur
ENAMETOOLONG36File name too long
ENOLCK37No record locks available
ENOSYS38Function not implemented
ENOTEMPTY39Directory not empty
ELOOP40Too many symbolic links encountered
EWOULDBLOCKEAGAINOperation would block
ENOMSG42No message of desired type
EIDRM43Identifier removed
ECHRNG44Channel number out of range
EL2NSYNC45Level 2 not synchronized
EL3HLT46Level 3 halted
EL3RST47Level 3 reset
ELNRNG48Link number out of range
EUNATCH49Protocol driver not attached
ENOCSI50No CSI structure available
EL2HLT51Level 2 halted
EBADE52Invalid exchange
EBADR53Invalid request descriptor
EXFULL54Exchange full
ENOANO55No anode
EBADRQC56Invalid request code
EBADSLT57Invalid slot
EDEADLOCKEDEADLK
EBFONT59Bad font file format
ENOSTR60Device not a stream
ENODATA61No data available
ETIME62Timer expired
ENOSR63Out of streams resources
ENONET64Machine is not on the network
ENOPKG65Package not installed
EREMOTE66Object is remote
ENOLINK67Link has been severed
EADV68Advertise error
ESRMNT69Srmount error
ECOMM70Communication error on send
EPROTO71Protocol error
EMULTIHOP72Multihop attempted
EDOTDOT73RFS specific error
EBADMSG74Not a data message
EOVERFLOW75Value too large for defined data type
ENOTUNIQ76Name not unique on network
EBADFD77File descriptor in bad state
EREMCHG78Remote address changed
ELIBACC79Can not access a needed shared library
ELIBBAD80Accessing a corrupted shared library
ELIBSCN81.lib section in a.out corrupted
ELIBMAX82Attempting to link in too many shared libraries
ELIBEXEC83Cannot exec a shared library directly
EILSEQ84Illegal byte sequence
ERESTART85Interrupted system call should be restarted
ESTRPIPE86Streams pipe error
EUSERS87Too many users
ENOTSOCK88Socket operation on non-socket
EDESTADDRREQ89Destination address required
EMSGSIZE90Message too long
EPROTOTYPE91Protocol wrong type for socket
ENOPROTOOPT92Protocol not available
EPROTONOSUPPORT93Protocol not supported
ESOCKTNOSUPPORT94Socket type not supported
EOPNOTSUPP95Operation not supported on transport endpoint
EPFNOSUPPORT96Protocol family not supported
EAFNOSUPPORT97Address family not supported by protocol
EADDRINUSE98Address already in use
EADDRNOTAVAIL99Cannot assign requested address
ENETDOWN100Network is down
ENETUNREACH101Network is unreachable
ENETRESET102Network dropped connection because of reset
ECONNABORTED103Software caused connection abort
ECONNRESET104Connection reset by peer
ENOBUFS105No buffer space available
EISCONN106Transport endpoint is already connected
ENOTCONN107Transport endpoint is not connected
ESHUTDOWN108Cannot send after transport endpoint shutdown
ETOOMANYREFS109Too many references: cannot splice
ETIMEDOUT110Connection timed out
ECONNREFUSED111Connection refused
EHOSTDOWN112Host is down
EHOSTUNREACH113No route to host
EALREADY114Operation already in progress
EINPROGRESS115Operation now in progress
ESTALE116Stale file handle
EUCLEAN117Structure needs cleaning
ENOTNAM118Not a XENIX named type file
ENAVAIL119No XENIX semaphores available
EISNAM120Is a named type file
EREMOTEIO121Remote I/O error
EDQUOT122Quota exceeded
ENOMEDIUM123No medium found
EMEDIUMTYPE124Wrong medium type
ECANCELED125Operation Canceled
ENOKEY126Required key not available
EKEYEXPIRED127Key has expired
EKEYREVOKED128Key has been revoked
EKEYREJECTED129Key was rejected by service
EOWNERDEAD130Owner died
ENOTRECOVERABLE131State not recoverable
ERFKILL132Operation not possible due to RF-kill
EHWPOISON133Memory 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博客

linxu中系统错误码errno

Unix errno值、

  •   只要一个Unix函数(如,某个套接字函数)中有错误发生,全局变量errno就被设置为一个指明该错误类型的正直,函数本身则通过返回-1.
  •   errno的值只在函数发生错误时被设置,如果函数不返回错误,errno的值就没有定义。
  •   errno的所有证书错误值都是常值,具有以“E”开头的全大写字母名字,并通常在<sys/errno.h>头文件中定义,0值不表示任何错误;
  •   sys_errlist

#include <iostream>#include <stdio.h>#include <sys/types.h>#include <sys/socket.h>#include <errno.h>
#include <string.h>int main(int argc, char **argv){ int sockfd = 0; if ((sockfd = socket(0, SOCK_STREAM, 0)) < 0) { if (errno >= 0 && errno <= sys_nerr) printf("socket created, failed[%d], reason:%s", errno, sys_errlist[errno]);
     printf("%s",strerror(errno)); //头文件string.h内 }
else { printf("socket successful"); } return 0;}

输出结果:

socket created, failed[97], reason:Address family not supported by protocol
Address family not supported by protocol

 

以上是关于Linux 系统错误码 errno 剖析的主要内容,如果未能解决你的问题,请参考以下文章