原创 写代码的篮球球痴 嵌入式Linux 2020-07-20
收录于话题
#Linux
130个
这个宏我们在内核里面使用非常频繁,这个宏的作用可以抛出sys设备节点给用户使用。用户可以读写sys/class下面的文件节点,以达到控制内核驱动的功效。
比如,像这样的设备节点
weiqifa:/sys/class/zigbee/onoff $ ls
gpio_en power subsystem uevent
weiqifa:/sys/class/zigbee/onoff $
使用方法static ssize_t gpio_store_en(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct gpio_dev_data *dev_data = dev_get_drvdata(dev);
unsigned long value = 0;
int ret;
/*将echo进来的buf转换成整型*/
ret = kstrtoul(buf, 16, &value);
if (ret < 0) {
printk( "%s:kstrtoul failed, ret=%d\n", __func__, ret);
return ret;
}
printk("%s: en value : %d\n", __func__, (int)value);
if (value) {
gpio_direction_output(dev_data->en_pin, dev_data->en_val);
dev_data->gpio_val = 1;
} else {
gpio_direction_output(dev_data->en_pin, !dev_data->en_val);
dev_data->gpio_val = 0;
}
return count;
}
static char mybuf[10]="123";
/*cat命令时,将会调用该函数*/
static ssize_t gpio_show_en(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct gpio_dev_data *dev_data = dev_get_drvdata(dev);
snprintf(mybuf,sizeof(mybuf),"%d",dev_data->gpio_val);
return sprintf(buf, "%s\n", mybuf);
}
static DEVICE_ATTR(gpio_en,0664,gpio_show_en, gpio_store_en);
...
dev_class = class_create(THIS_MODULE, class_name);
ctl_dev = device_create(dev_class, NULL, 0, NULL, "onoff");
if (IS_ERR(ctl_dev)) {
dev_err(ctl_dev, "Failed to create device\n");
ret = PTR_ERR(ctl_dev);
goto err_create_dev;
}
err = device_create_file(ctl_dev, &dev_attr_gpio_en);
if (err){
printk("driver_create_file = %d\n", err);
}
DEVICE_ATTR 0777 引发的血案如果你想给一个节点设置 0777 或者写操作,那你编译的时候,会出现下面的编译错误。
/home/weiqifa/mt8167s-9.0-sdk/kernel-4.4/include/linux/kernel.h:840:3: note: in expansion of macro 'BUILD_BUG_ON_ZERO'
BUILD_BUG_ON_ZERO((perms) & 2) + \
^
/home/weiqifa/mt8167s-9.0-sdk/kernel-4.4/include/linux/sysfs.h:102:12: note: in expansion of macro 'VERIFY_OCTAL_PERMISSIONS'
.mode = VERIFY_OCTAL_PERMISSIONS(_mode) }, \
^
/home/weiqifa/mt8167s-9.0-sdk/kernel-4.4/include/linux/device.h:573:45: note: in expansion of macro '__ATTR'
struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
^
/home/weiqifa/mt8167s-9.0-sdk/kernel-4.4/drivers/misc/gpio_control.c:62:8: note: in expansion of macro 'DEVICE_ATTR'
static DEVICE_ATTR(gpio_en,0777,gpio_show_en, gpio_store_en);
这个错误的原因主要是出现在
VERIFY_OCTAL_PERMISSIONS
这个宏上面
这个宏定义在
include/linux/
下面
/* Permissions on a sysfs file: you didn't miss the 0 prefix did you? */
#define VERIFY_OCTAL_PERMISSIONS(perms) \
(BUILD_BUG_ON_ZERO((perms) < 0) + \
BUILD_BUG_ON_ZERO((perms) > 0777) + \
/* USER_READABLE >= GROUP_READABLE >= OTHER_READABLE */ \
BUILD_BUG_ON_ZERO((((perms) >> 6) & 4) < (((perms) >> 3) & 4)) + \
BUILD_BUG_ON_ZERO((((perms) >> 3) & 4) < ((perms) & 4)) + \
/* USER_WRITABLE >= GROUP_WRITABLE */ \
BUILD_BUG_ON_ZERO((((perms) >> 6) & 2) < (((perms) >> 3) & 2)) + \
/* OTHER_WRITABLE? Generally considered a bad idea. */ \
BUILD_BUG_ON_ZERO((perms) & 2) + \
(perms))
#endif
BUILD_BUG_ON_ZERO 的作用这个宏的作用是,如果里面传进来的值是 「true」编译的时候就会出错。
写个代码举个例子
#include <stdio.h>
#include <stdbool.h>
//#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
/* Force a compilation error if condition is true */
#define BUILD_BUG_ON(condition) ((void)BUILD_BUG_ON_ZERO(condition))
/* Force a compilation error if condition is true, but also produce a
result (of value 0 and type size_t), so the expression can be used
e.g. in a structure initializer (or where-ever else comma expressions
aren't permitted). */
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
#define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))
int main()
{
BUILD_BUG_ON(1!=0);
bool zero = false;
printf("%d\n", !!zero);
printf("%d\n", !zero);
return 0;
}
输出
VERIFY_OCTAL_PERMISSIONS 的作用?
所以在回到这个宏,这个宏的作用就是限制我们在内核里面设置DEVICE_ATTR的权限,如果你要是设置 0777,那肯定就会给你提示编译错误。
0777 对应的是 8进制
整个流程是如上图,代码是在mode部分那里做了限制。
怎么让DEVICE_ATTR 0777 生效?既然我们知道是
VERIFY_OCTAL_PERMISSIONS 这个宏限制的,那就直接把这个宏修改就好了。
当然了,这样使用是不符合要求的,如果这样,很容易被裁员的哦,毕竟用户可能随便写一段代码就可能让你的系统不正常。
看烧录看效果
推荐阅读: 专辑|Linux文章汇总 专辑|程序人生 专辑|C语言