原创 写代码的篮球球痴 嵌入式Linux 2020-07-20

收录于话题

#Linux

130个

DEVICE_ATTR设置0777引发血案_嵌入式

这个宏我们在内核里面使用非常频繁,这个宏的作用可以抛出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;
}

输出
DEVICE_ATTR设置0777引发血案_嵌入式_02



VERIFY_OCTAL_PERMISSIONS 的作用?

所以在回到这个宏,这个宏的作用就是限制我们在内核里面设置DEVICE_ATTR的权限,如果你要是设置 0777,那肯定就会给你提示编译错误。

0777 对应的是 8进制


DEVICE_ATTR设置0777引发血案_嵌入式_03

整个流程DEVICE_ATTR设置0777引发血案_嵌入式_04

整个流程是如上图,代码是在mode部分那里做了限制。

怎么让DEVICE_ATTR 0777 生效?

既然我们知道是

VERIFY_OCTAL_PERMISSIONS 这个宏限制的,那就直接把这个宏修改就好了。

当然了,这样使用是不符合要求的,如果这样,很容易被裁员的哦,毕竟用户可能随便写一段代码就可能让你的系统不正常。

DEVICE_ATTR设置0777引发血案_嵌入式_05

看烧录看效果DEVICE_ATTR设置0777引发血案_嵌入式_06



  推荐阅读:  专辑|Linux文章汇总  专辑|程序人生  专辑|C语言