Linux内核中错误码与错误处理函数

Linux错误处理

1. Linux下编号前50错误码

内核定义了许多常见的错误码,如EPERM(操作不允许)、ENOENT(无此文件或目录)、EINTR系统调用被中断)等。
位于文件linux\include\uapi\asm-generic\errno-base.h

#define EPERM          1     /* Operation not permitted */
#define ENOENT         2     /* No such file or directory */
#define ESRCH          3     /* No such process */
#define EINTR          4     /* Interrupted system call */
#define EIO            5     /* I/O error */
#define ENXIO          6     /* No such device or address */
#define E2BIG          7     /* Argument list too long */
#define ENOEXEC        8     /* Exec format error */
#define EBADF          9     /* Bad file number */
#define ECHILD        10     /* No child processes */
#define EAGAIN        11     /* Try again */
#define ENOMEM        12     /* Out of memory */
#define EACCES        13     /* Permission denied */
#define EFAULT        14     /* Bad address */
#define ENOTBLK       15     /* Block device required */
#define EBUSY         16     /* Device or resource busy */
#define EEXIST        17     /* File exists */
#define EXDEV         18     /* Cross-device link */
#define ENODEV        19     /* No such device */
#define ENOTDIR       20     /* Not a directory */
#define EISDIR        21     /* Is a directory */
#define EINVAL        22     /* Invalid argument */
#define ENFILE        23     /* File table overflow */
#define EMFILE        24     /* Too many open files */
#define ENOTTY        25     /* Not a typewriter */
#define ETXTBSY       26     /* Text file busy */
#define EFBIG         27     /* File too large */
#define ENOSPC        28     /* No space left on device */
#define ESPIPE        29     /* Illegal seek */
#define EROFS         30     /* Read-only file system */
#define EMLINK        31     /* Too many links */
#define EPIPE         32     /* Broken pipe */
#define EDOM          33     /* Math argument out of domain of func */
#define ERANGE        34     /* Math result not representable */
#define	EDEADLK		  35	/* Resource deadlock would occur */
#define	ENAMETOOLONG  36	/* File name too long */
#define	ENOLCK		  37	/* No record locks available */
#define	ENOSYS		  38	/* Invalid system call number */#define	ENOTEMPTY	  39	/* Directory not empty */
#define	ELOOP		  40	/* Too many symbolic links encountered */
#define	EWOULDBLOCK	 EAGAIN	/* Operation would block */
#define	ENOMSG		  42	/* No message of desired type */
#define	EIDRM		  43	/* Identifier removed */
#define	ECHRNG		  44	/* Channel number out of range */
#define	EL2NSYNC	  45	/* Level 2 not synchronized */
#define	EL3HLT		  46	/* Level 3 halted */
#define	EL3RST		  47	/* Level 3 reset */
#define	ELNRNG		  48	/* Link number out of range */
#define	EUNATCH		  49	/* Protocol driver not attached */
#define	ENOCSI		  50	/* No CSI structure available */
.......................................
...... ...............................

2. linux错误处理函数

Linux 下错误处理函数位于 linux\include\linux\err.h

/* SPDX-License-Identifier: GPL-2.0 */
/* 声明遵循GPL-2.0许可证 */#ifndef _LINUX_ERR_H
#define _LINUX_ERR_H/* 包含必要的编译器和类型定义的头文件 */
#include <linux/compiler.h>
#include <linux/types.h>/* 包含架构特定的errno定义 */
#include <asm/errno.h>/** 内核指针包含冗余信息,因此我们可以使用一种方案,通过该方案可以返回错误码或普通指针,* 并且返回值相同。这应该是按架构划分的事情,以允许不同的错误和指针决策。*/
#define MAX_ERRNO	4095
/* 定义最大errno值,用于确定错误指针的范围 */#ifndef __ASSEMBLY__
/* 如果不是汇编代码,则定义以下宏和函数 *//* 检查给定的值是否是一个错误指针的值 */
#define IS_ERR_VALUE(x) unlikely((unsigned long)(void *)(x) >= (unsigned long)-MAX_ERRNO)/** 将一个错误码转换为一个错误指针。* 注意:这里直接将错误码(一个long类型)转换为void*类型,* 利用了错误码通常为负数的特性,以及void*指针无法直接表示负地址的特性。*/
static inline void * __must_check ERR_PTR(long error)
{return (void *) error;
}/** 将一个错误指针转换回其对应的错误码。* 注意:这里直接将void*类型的错误指针转换回long类型。*/
static inline long __must_check PTR_ERR(__force const void *ptr)
{return (long) ptr;
}/* 检查给定的指针是否是一个错误指针 */
static inline bool __must_check IS_ERR(__force const void *ptr)
{return IS_ERR_VALUE((unsigned long)ptr);
}/* 检查给定的指针是否为NULL或错误指针 */
static inline bool __must_check IS_ERR_OR_NULL(__force const void *ptr)
{return unlikely(!ptr) || IS_ERR_VALUE((unsigned long)ptr);
}/*** ERR_CAST - 显式地将一个错误值指针转换为另一种指针类型* @ptr: 要转换的指针。** 显式地将一个错误值指针转换为另一种指针类型,以便清楚地表明正在执行的操作。* 注意:这个宏实际上并没有进行特殊的转换,只是简单地返回了输入指针。* 它主要用于在代码中清晰地表明正在进行的操作是类型转换。*/
static inline void * __must_check ERR_CAST(__force const void *ptr)
{/* 去除const限定符 */return (void *) ptr;
}/** 如果给定的指针是一个错误指针,则返回其错误码;否则返回0。* 这在需要处理可能返回错误指针的函数调用时非常有用。*/
static inline int __must_check PTR_ERR_OR_ZERO(__force const void *ptr)
{if (IS_ERR(ptr))return PTR_ERR(ptr);elsereturn 0;
}/* 已弃用:建议使用PTR_ERR_OR_ZERO代替 */
#define PTR_RET(p) PTR_ERR_OR_ZERO(p)#endif /* __ASSEMBLY__ */#endif /* _LINUX_ERR_H */

这段代码是Linux内核中用于处理错误指针的宏和函数定义,它们被包含在linux/err.h头文件中。这个机制允许内核函数在返回指针时,如果发生错误,可以返回一个特殊的“错误指针”,这个指针实际上是一个错误码的负值(通过ERR_PTR宏创建)。调用者可以使用IS_ERRPTR_ERR等宏和函数来检查和处理这些错误指针。

下面是对这些宏和函数的解释:

  1. MAX_ERRNO:定义了最大错误码值,为4095。这是因为在Linux中,错误码通常是正整数,并且使用-errno来表示错误指针(通过取负值来避免与有效的内存地址冲突)。

  2. IS_ERR_VALUE(x):检查给定的值x是否是一个错误指针的值。它通过比较x是否大于等于-MAX_ERRNO来判断。

  3. ERR_PTR(error):将一个错误码error转换为一个错误指针。这个宏简单地将错误码(一个long类型的值)强制转换为void*类型。

  4. PTR_ERR(ptr):将一个错误指针ptr转换回它表示的错误码。这个宏通过强制转换ptrlong类型来实现。

  5. IS_ERR(ptr):检查给定的指针ptr是否是一个错误指针。它通过调用IS_ERR_VALUE宏来判断。

  6. IS_ERR_OR_NULL(ptr):检查给定的指针ptr是否为NULL或是一个错误指针。

  7. ERR_CAST(ptr):将给定的指针ptr(可能是一个错误指针)显式地转换为另一个指针类型,同时去除其const属性。这个宏主要用于类型安全的转换,但实际上它并没有改变指针的值或类型(除了去除const)。

  8. PTR_ERR_OR_ZERO(ptr):如果ptr是一个错误指针,则返回它表示的错误码;否则返回0。这个宏通常用于处理可能返回错误指针的函数调用,如果调用成功则返回0。

  9. PTR_RET(p):这是一个已废弃的宏,其功能与PTR_ERR_OR_ZERO相同。建议使用PTR_ERR_OR_ZERO代替PTR_RET

这个头文件和其中的宏、函数是Linux内核中处理错误指针的标准方式,它们使得内核代码更加健壮和易于维护。通过检查返回值是否为错误指针,调用者可以适当地处理错误情况,而不会导致未定义的行为或安全漏洞。

3 .举例

一般情况下,返回错误的方式: return -ERROR

例如 #define EPERM 1 /* Operation not permitted */
操作不允许 return -EPERM

实际案例

在Linux内核空间编写驱动程序时,处理“操作不允许”(EPERM)错误通常涉及检查调用者的权限,并在权限不足时返回适当的错误码。

一个字符设备驱动程序举例

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/cdev.h>
#include <linux/device.h>#define DEVICE_NAME "my_privileged_device"static int major;
static struct class *my_class;
static struct cdev my_cdev;static int my_open(struct inode *inode, struct file *file) {// 在这里检查权限,例如检查调用者是否是root用户if (!capable(CAP_SYS_ADMIN)) { // 检查是否具有系统管理员权限printk(KERN_WARNING "Operation not permitted for %s\n", current->comm);return -EPERM; // 返回EPERM错误码}// 如果权限检查通过,则执行其他打开逻辑(如果有的话)// ...return 0; // 返回0表示成功
}static int my_release(struct inode *inode, struct file *file) {// 释放资源(如果有的话)// ...return 0; // 返回0表示成功
}// 其他文件操作函数,如read、write等,可以根据需要实现
// ...static const struct file_operations my_fops = {.owner = THIS_MODULE,.open = my_open,.release = my_release,// .read = my_read,// .write = my_write,// 其他文件操作可以按需添加
};static int __init my_driver_init(void) {int ret;// 分配主设备号if ((major = register_chrdev(0, DEVICE_NAME, &my_fops)) < 0) {printk(KERN_ALERT "Failed to register character device\n");return major; // 返回错误码}// 创建类my_class = class_create(THIS_MODULE, DEVICE_NAME);if (IS_ERR(my_class)) {unregister_chrdev(major, DEVICE_NAME);printk(KERN_ALERT "Failed to create class\n");return PTR_ERR(my_class); // 返回错误码}// 创建设备节点device_create(my_class, NULL, MKDEV(major, 0), NULL, DEVICE_NAME);// 初始化cdev结构并添加到内核cdev_init(&my_cdev, &my_fops);ret = cdev_add(&my_cdev, MKDEV(major, 0), 1);if (ret < 0) {device_destroy(my_class, MKDEV(major, 0));class_destroy(my_class);unregister_chrdev(major, DEVICE_NAME);printk(KERN_ALERT "Failed to add cdev\n");return ret; // 返回错误码}printk(KERN_INFO "Driver initialized successfully\n");return 0; // 返回0表示成功
}static void __exit my_driver_exit(void) {// 清理资源cdev_del(&my_cdev);device_destroy(my_class, MKDEV(major, 0));class_destroy(my_class);unregister_chrdev(major, DEVICE_NAME);printk(KERN_INFO "Driver exited successfully\n");
}module_init(my_driver_init);
module_exit(my_driver_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Linux driver example with permission check");

在这个示例中,my_open函数检查调用者是否具有系统管理员权限(CAP_SYS_ADMIN)。如果没有,它将打印一条警告消息并返回-EPERM错误码。这表示调用者没有足够的权限来打开设备。

对返回错误码的处理举例

IS_ERR_VALUE, ERR_PTR, PTR_ERR, 和 IS_ERR 是一组用于错误处理的宏和函数。它们允许内核函数返回指针类型的值时,能够区分有效的指针地址和错误码(通常是通过负整数表示的)。

#include <linux/errno.h>
#include <linux/types.h>// 假设这是一个可能返回错误的内核函数
void *my_function_that_might_fail(void) {// 模拟一个错误情况return ERR_PTR(-EPERM); // 返回EPERM错误
}// 使用这些宏和函数来处理错误的示例函数
int process_my_function(void) {void *result = my_function_that_might_fail();if (IS_ERR(result)) {// 处理错误,将指针转成错误码long error = PTR_ERR(result);//打印错误码printk(KERN_ERR "my_function_that_might_fail failed with error: %ld\n", error);// 根据错误码执行相应的错误处理逻辑// ...return error; // 将错误码返回给调用者} else if (IS_ERR_OR_NULL(result)) {// 处理NULL指针的情况(虽然在这个例子中不太可能,因为ERR_PTR不会返回NULL)printk(KERN_ERR "my_function_that_might_fail returned NULL\n");// 执行相应的错误处理逻辑// ...return -EINVAL; // 或者其他适当的错误码} else {// 成功情况:处理有效的指针// ...printk(KERN_INFO "my_function_that_might_fail succeeded\n");// 执行成功逻辑// ...return 0; // 返回0表示成功}
}

在这个示例中,my_function_that_might_fail 函数模拟了一个错误情况,并返回了 ERR_PTR(-EPERM),表示操作不允许。调用者 process_my_function 使用 IS_ERR 宏来检查返回值是否是一个错误指针。如果是,它使用 PTR_ERR 宏将错误指针转换回错误码,并打印出错误信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/479715.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

femor 第三方Emby应用全平台支持v1.0.54更新

femor v1.0.54 版本更新 mpv播放器增加切换后台和恢复时隐藏状态栏的功能修复服务器首页因为连接超时异常的问题 获取路径&#xff1a;【femor 历史版本收录】

如何搭建一个小程序:从零开始的详细指南

在当今数字化时代&#xff0c;小程序以其轻便、无需下载安装即可使用的特点&#xff0c;成为了连接用户与服务的重要桥梁。无论是零售、餐饮、教育还是娱乐行业&#xff0c;小程序都展现了巨大的潜力。如果你正考虑搭建一个小程序&#xff0c;本文将为你提供一个从零开始的详细…

nrm镜像管理工具使用方法

nrm&#xff08;NPM Registry Manager&#xff09;是一款专门用于管理 npm 包镜像源的命令行工具。在使用 npm 安装各种包时&#xff0c;默认会从官方的 npm 仓库&#xff08;registry&#xff09;获取资源&#xff0c;但有时候由于网络环境等因素&#xff0c;访问官方源可能速…

OpenCV截取指定图片区域

import cv2 img cv2.imread(F:/2024/Python/demo1/test1/man.jpg) cv2.imshow(Image, img) # 显示图片 #cv2.waitKey(0) # 等待按键x, y, w, h 500, 100, 200, 200 # 示例坐标 roi img[y:yh, x:xw] # 截取指定区域 cv2.imshow(ROI, roi) cv2.waitKey(0) cv…

易速鲜花聊天客服机器人的开发(下)

目录 “聊天机器人”项目说明 方案 1 &#xff1a;通过 Streamlit 部署聊天机器人 方案2 &#xff1a;通过 Gradio 部署聊天机器人 总结 上一节&#xff0c;咱们的聊天机器人已经基本完成&#xff0c;这节课&#xff0c;我们要看一看如何把它部署到网络上。 “聊天机器人”…

STM32笔记(串口IAP升级)

一、IAP简介 IAP&#xff08;In Application Programming&#xff09;即在应用编程&#xff0c; IAP 是用户自己的程序在运行过程中对 User Flash 的部分区域进行烧写&#xff0c;目的是为了在产品发布后可以方便地通过预留的通信口对产 品中的固件程序进行更新升级。 通常实…

斐波那契堆与二叉堆在Prim算法中的性能比较:稀疏图与稠密图的分析

斐波那契堆与二叉堆在Prim算法中的性能比较:稀疏图与稠密图的分析 引言基本概念回顾Prim算法的时间复杂度分析稀疏图中的性能比较稠密图中的性能比较|E| 和 |V| 的关系伪代码与C代码示例结论引言 在图论中,Prim算法是一种用于求解最小生成树(MST)的贪心算法。其性能高度依…

使用argo workflow 实现springboot 项目的CI、CD

文章目录 基础镜像制作基础镜像设置镜像源并安装工具git下载和安装 Maven设置环境变量设置工作目录默认命令最终dockerfile 制作ci argo workflow 模版volumeClaimTemplatestemplatesvolumes完整workflow文件 制作cd argo workflow 模版Workflow 结构Templates 定义创建 Kubern…

BUUCTF—Reverse—不一样的flag(7)

是不是做习惯了常规的逆向题目&#xff1f;试试这道题&#xff0c;看你在能不能在程序中找到真正的flag&#xff01;注意&#xff1a;flag并非是flag{XXX}形式&#xff0c;就是一个’字符串‘&#xff0c;考验眼力的时候到了&#xff01; 注意&#xff1a;得到的 flag 请包上 f…

insmod一个ko提供基础函数供后insmod的ko使用的方法

一、背景 在内核模块开发时&#xff0c;多个不同的内核模块&#xff0c;有时候可能需要都共用一些公共的函数&#xff0c;比如申请一些平台性的公共资源。但是&#xff0c;这些公共的函数又不方便去加入到内核镜像里&#xff0c;这时候就需要把这些各个内核模块需要用到的一些…

LangGraph中的State管理

本教程将介绍如何使用LangGraph库构建和测试状态图。我们将通过一系列示例代码&#xff0c;逐步解释程序的运行逻辑。 1. 基本状态图构建 首先&#xff0c;我们定义一个状态图的基本结构和节点。 定义状态类 from langgraph.graph import StateGraph, START, END from typi…

MATLAB中Simulink的基础知识

Simulink是MATLAB中的一种可视化仿真工具&#xff0c; 是一种基于MATLAB的框图设计环境&#xff0c;是实现动态系统建模、仿真和分析的一个软件包&#xff0c;被广泛应用于线性系统、非线性系统、数字控制及数字信号处理的建模和仿真中。 Simulink提供一个动态系统建模、仿真和…

最小生成树-Prim与Kruskal算法

文章目录 什么是最小生成树&#xff1f;Prim算法求最小生成树Python实现&#xff1a; Kruskal算法求最小生成树并查集 Python实现&#xff1a; Reference 什么是最小生成树&#xff1f; 在图论中&#xff0c;树是图的一种&#xff0c;无法构成闭合回路的节点-边连接组合称之为…

关闭AWS账号后,服务是否仍会继续运行?

在使用亚马逊网络服务&#xff08;AWS&#xff09;时&#xff0c;用户有时可能会考虑关闭自己的AWS账户。这可能是因为项目结束、费用过高&#xff0c;或是转向使用其他云服务平台。然而&#xff0c;许多人对关闭账户后的服务状态感到困惑&#xff0c;我们九河云和大家一起探讨…

Could not locate device support files.

报错信息&#xff1a;Failure Reason: The device may be running a version of iOS (13.6.1 17G80) that is not supported by this version of Xcode.[missing string: 869a8e318f07f3e2f42e11d435502286094f76de] 问题&#xff1a;xcode15升级到xcode16之后&#xff0c;13.…

Linux文件基础

目录 一、文件类型 二、文件权限 三、权限修改 Linux中一切皆文件&#xff0c;文件目录分布呈树状数据结构&#xff0c;/是根目录&#xff0c;目录的源头 一、文件类型 类型字符说明普通-Linux中最多的一种文件类型&#xff0c;包括 纯文本文件(ASCII)、二进制文件(binary…

自然语言处理基础之文本预处理

一. NLP介绍 1957年, 怛特摩斯会议 二. 文本预处理 文本预处理及作用 将文本转换成模型可以识别的数据 文本转化成张量(可以利用GPU计算), 规范张量的尺寸. 科学的文本预处理可以有效的指导模型超参数的选择, 提升模型的评估指标 文本处理形式 分词 词性标注 命名实体识别…

外卖点餐系统小程序

目录 开发前准备 项目展示项目分析项目初始化封装网络请求 任务1 商家首页 任务分析焦点图切换中间区域单击跳转到菜单列表底部商品展示 任务2 菜单列表 任务分析折扣信息区设计菜单列表布局请求数据实现菜单栏联动单品列表功能 任务3 购物车 任务分析设计底部购物车区域添加商…

彻底理解如何保证ElasticSearch和数据库数据一致性问题

一.业务场景举例 需求&#xff1a; 一个卖房业务&#xff0c;双十一前一天&#xff0c;维护楼盘的运营人员突然接到合作开发商的通知&#xff0c;需要上线一批热门的楼盘列表&#xff0c;上传完成后&#xff0c;C端小程序支持按楼盘的名称、户型、面积等产品属性全模糊搜索热门…

单片机将图片数组调出来显示MPU8_8bpp_Memory_Write

界面显示图片是很常见的需求&#xff0c;使用外挂的FLASH是最常用的方法。但是如果图片需求不大&#xff0c;比如说我们只要显示一个小图标&#xff0c;那么为了节省硬件成本&#xff0c;是不需要外挂一颗FLASH芯片的&#xff0c;我们可以将图标转成数组&#xff0c;存在单片机…