linux用户空间&内核空间常用函数

678 阅读7分钟

一、文件操作函数

1. 用户空间

查看用户空间文件操作函数说明可在终端:man 2 xxfunc 进行查看

(1)open函数

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags)

pathname:要打开的设备或者文件名
flags:文件打开模式,以下三种模式必选其一:
    O_RDONLY 只读模式
    O_WRONLY 只写模式
    O_RDWR 读写模式
    除了上述三种模式以外还有其他的可选模式,通过逻辑或来选择多种模式:
    O_APPEND 每次写操作都写入文件的末尾
    O_CREAT 如果指定文件不存在,则创建这个文件
    O_EXCL 如果要创建的文件已存在,则返回 -1,并且修改 errno 的值
    O_TRUNC 如果文件存在,并且以只写/读写方式打开,则清空文件全部内容
    O_NOCTTY 如果路径名指向终端设备,不要把这个设备用作控制终端。
    O_NONBLOCK 如果路径名指向 FIFO/块文件/字符文件,则把文件的打开和后继
    I/O 设置为非阻塞
    DSYNC 等待物理 I/O 结束后再 write。在不影响读取新写入的数据的前提
    下,不等待文件属性更新。
    O_RSYNC read 等待所有写入同一区域的写操作完成后再进行。
    O_SYNC 等待物理 I/O 结束后再 write,包括更新文件属性的 I/O。
返回值:如果文件打开成功的话返回文件的文件描述符

(2)read函数

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count)

fd:要读取的文件描述符。
buf:数据读取到此 buf 中。
count:要读取的数据长度,也就是字节数。
返回值:读取成功的话返回读取到的字节数;如果返回0表示读取到了文件末尾;如果返回负值,表示读取失败。

(3)write函数

#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count)

fd:文件描述符。
buf:要写入的数据。
count:要写入的数据长度,也就是字节数。
返回值:写入成功的话返回写入的字节数;如果返回0表示没有写入任何数据;如果返回负值,表示写入失败。

(4)close函数

#include <unistd.h>
int close(int fd);

fd:要关闭的文件描述符。
返回值:0 表示关闭成功,负值表示关闭失败。

(5)ioctl函数

#include <sys/ioctl.h> 

int ioctl(int fd, int cmd, ...) ;

ioctl() 函数执行成功时返回 0,失败则返回 -1 并设置全局变量 errorno 值,如下:
EBADF: fd is not a valid descriptor.
EFAULT: argp references an inaccessible memory area.
EINVAL: Request or argp is not valid.
ENOTTY: fd is not associated with a character special device.
ENOTTY: The specified request does not apply to the kind of object that the descriptor d references.

因此,在用户空间使用 ioctl 时,可以做如下的出错判断以及处理:

int ret;
ret = ioctl(fd, MYCMD);
if (ret == -1) {
    printf("ioctl: %s\n", strerror(errno));
}

在实际应用中,ioctl 最常见的 errorno 值为 ENOTTY(error not a typewriter),顾名思义,即第一个参数 fd 指向的不是一个字符设备,不支持 ioctl 操作,这时候应该检查前面的 open 函数是否出错或者设备路径是否正确

2. 内核空间

(1)open函数

static int xxx_open(struct inode *inode, struct file *filp)

(2)read函数

static ssize_t xxx_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off)

(3)write函数

static ssize_t xxx_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)

(4)close函数

static int xxx_release(struct inode *inode, struct file *filp)

(5)ioctl函数

long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);

具体使用解析见ioctl函数详解

二、内核空间与应用空间得数据交互

1.数据传递函数

(1)copy_from_user

copy_from_user(void *to, const void __user *from, unsigned long n)

@descrption: 将用户空间的数据传递给内核
*to:内核空间的指针
*from:用户空间的指针
n:长度字节数

(2)copy_to_user

copy_to_user(void __user *to, const void *from, unsigned long n)

@descrption: 将内核空间的数据传递给用户
*to:是用户空间的指针
*from:内核空间的指针
n:长度字节数

三、linux内核打印调试等函数

1.内核printk的打印级别

#define KERN_EMERG      "<0>" /* system is unusable */

#define KERN_ALERT      "<1>" /* action must be taken immediately */

#define KERN_CRIT       "<2>" /* critical conditions */

#define KERN_ERR        "<3>" /* error conditions */

#define KERN_WARNING    "<4>" /* warning conditions */

#define KERN_NOTICE     "<5>" /* normal but significant condition */

#define KERN_INFO       "<6>" /* informational */

#define KERN_DEBUG      "<7>" /* debug-level messages */

2.自定义调试宏

/* 调试宏:通过DEBUG_A进行控制*/
#define DEBUG_A
#ifdef DEBUG_A
#define DEBUG(fmt, args...) printk(KERN_ALERT "DEBUG: " fmt, ## args)
#else
#define DEBUG(fmt, args...)
#endif

3.系统自带终端输出机制以及DEBUG机制

  • 终端输出
#define pr_emerg(fmt, ...) \
	printk(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__)
#define pr_alert(fmt, ...) \
	printk(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__)
#define pr_crit(fmt, ...) \
	printk(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__)
#define pr_err(fmt, ...) \
	printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
#define pr_warning(fmt, ...) \
	printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
#define pr_warn pr_warning
#define pr_notice(fmt, ...) \
	printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
#define pr_info(fmt, ...) \
	printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
  • DEBUG
/* pr_devel() should produce zero code unless DEBUG is defined */
#ifdef DEBUG
#define pr_devel(fmt, ...) \
	printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#else
#define pr_devel(fmt, ...) \
	no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#endif

#include <linux/dynamic_debug.h>

/* If you are writing a driver, please use dev_dbg instead */
#if defined(CONFIG_DYNAMIC_DEBUG)
/* dynamic_pr_debug() uses pr_fmt() internally so we don't need it here */
#define pr_debug(fmt, ...) \
	dynamic_pr_debug(fmt, ##__VA_ARGS__)
#elif defined(DEBUG)
#define pr_debug(fmt, ...) \
	printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#else
#define pr_debug(fmt, ...) \
	no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#endif

4.linux内核错误码

#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 */

四、字符设备注册函数

1.设备号注册

(1)alloc_chrdev_region

int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)

@description:动态注册设备号(未指定设备号)
*dev:存放分配的设备号指针
baseminor:次设备号的起始号
count:要注册设备号的数量
*name:设备名指针

(2)register_chrdev_region

int register_chrdev_region(dev_t from, unsigned count, const char *name)
@description:静态注册设备号(已知设备号)
from:要注册的起始设备号
count:要注册的数量
*name:设备名称指针

(3)unregister_chrdev_region

void unregister_chrdev_region(dev_t from, unsigned count)
@description:注销设备号
from:要注销的起始设备号
count:要注销的数量

(4)一些宏

MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS)) 
@description:取主设备号
MINOR(dev) ((unsigned int) ((dev) & MINORMASK))
@description:取次设备号
MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))
@description:将主次设备号组合成设备号

2.字符设备注册、节点创建(区别于设备号)

(1)cdev_init

void cdev_init(struct cdev *cdev, const struct file_operations *fops)
@description:初始化cdev结构体。建立操作函数与cdev的联系,cdev就是一个字符设备。
*cdev:字符设备结构体指针
*fops:操作函数结构体指针

(2)cdev_add

int cdev_add(struct cdev *p, dev_t dev, unsigned count)
@description:向系统添加一个cdev,进而完成字符设备的注册。
*p:cdev指针
dev:设备号
count:设备数量

(3)cdev_del

void cdev_del(struct cdev *p)
@description:在系统中删除一个cdev,进而完成字符设备的注销。
*p:cdev

(4)class_create

struct class *class_create (struct module *owner, const char *name)
@description:创建一个类,这个类存放于sysfs下面,一旦创建好了这个类,再调用device_create(…)函数在/dev目录下创建相应的设备节点。这样,加载模块的时候,用户空间中的udev会自动响应device_create(…)函数,去/sysfs下寻找对应的类从而创建设备节点。
*owner:一般为THIS_MODULE
*name:类的名字指针 /sys/class/*name

(5)class_destroy

void class_destroy(struct class *cls);
@description:删除一个类

(6)device_create

struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...)

@descrition:在创建好类之后,在/dev下创建相应的节点。
struct class *class:类
struct device *parent:NULL
dev_t devt :设备号
void *drvdata :null
const char *fmt:名字 /dev/*fmt

(7)device_destroy

void device_destroy(struct class *class, dev_t devt)

@description:删除类与设备节点