1 数组的定义初始化
constchar*const pm_states[PM_SUSPEND_MAX]={
#ifdef CONFIG_EARLYSUSPEND
[PM_SUSPEND_ON] ="on",
#endif
[PM_SUSPEND_STANDBY] ="standby",
[PM_SUSPEND_MEM] ="mem",
};
2结构体的定义初始化
struct attribute {
const char *name;
mode_t mode;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lock_class_key *key;
struct lock_class_key skey;
#endif
};
struct map_sysfs_entry {
struct attribute attr;
ssize_t (*show)(struct uio_mem *, char *);
ssize_t (*store)(struct uio_mem *, const char*, size_t);
};
#define __ATTR(_name,_mode,_show,_store) {\
.attr = {.name = __stringify(_name), .mode =_mode }, \
.show = _show, \
.store = _store, \
}
static struct map_sysfs_entryname_attribute =
__ATTR(name, S_IRUGO, map_name_show, NULL;
static struct attribute *attrs[] = {
&name_attribute.attr,
&addr_attribute.attr,
&size_attribute.attr,
&offset_attribute.attr,
NULL, /* need to NULL terminate the list ofattributes */
};
struct attribute_group {
const char *name;
mode_t (*is_visible)(struct kobject *,
struct attribute *, int);
struct attribute **attrs;
};
static struct attribute_group attr_group ={
.attrs = attrs,
};
sysfs_create_group(power_kobj,&attr_group);
3结构体定义
struct attribute {
const char *name;
mode_t mode;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lock_class_key *key;
struct lock_class_key skey;
#endif
};
struct kobj_attribute {
struct attribute attr;
ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,
char *buf);
ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count);
};
#define power_attr(_name) \
static struct kobj_attribute _name##_attr = { \
.attr = { \
.name = __stringify(_name), \
.mode = 0644, \
}, \
.show = _name##_show, \
.store = _name##_store, \
}
power_attr(state);
C(和C++)中的宏(Macro)属于编译器预处理的范畴,属于编译期概念(而非运行期概念)。下面对常遇到的宏的使用问题做了简单总结。
关于#和##
在C语言的宏中,#的功能是将其后面的宏参数进行字符串化操作(Stringfication),简单说就是在对它所引用的宏变量通过替换后在其左右各加上一个双引号。比如下面代码中的宏:
#define WARN_IF(EXP) \
do{ if (EXP) \
fprintf(stderr, "Warning: " #EXP "\n"); } \
while(0)
那么实际使用中会出现下面所示的替换过程:
WARN_IF (divider == 0);
被替换为
do {
if (divider == 0)
fprintf(stderr, "Warning" "divider == 0" "\n");
} while(0);
这样每次divider(除数)为0的时候便会在标准错误流上输出一个提示信息。
而##被称为连接符(concatenator),用来将两个Token连接为一个Token。注意这里连接的对象是Token就行,而不一定是宏的变量。比如你要做一个菜单项命令名和函数指针组成的结构体的数组,并且希望在函数名和菜单项命令名之间有直观的、名字上的关系。那么下面的代码就非常实用:
struct command
{
char * name;
void (*function) (void);
};
#define COMMAND(NAME) { NAME, NAME ## _command }
//然后你就用一些预先定义好的命令来方便的初始化一个command结构的数组了:
struct command commands[] = {
COMMAND(quit),
COMMAND(help),
...
}
COMMAND宏在这里充当一个代码生成器的作用,这样可以在一定程度上减少代码密度,间接地也可以减少不留心所造成的错误。我们还可以n个##符号连接 n+1个Token,这个特性也是#符号所不具备的。比如:
#define LINK_MULTIPLE(a,b,c,d) a##_##b##_##c##_##d
typedef struct _record_type LINK_MULTIPLE(name,company,position,salary);
//这里这个语句将展开为:
// typedef struct _record_type name_company_position_salary;
关于...的使用
...在C宏中称为Variadic Macro,也就是变参宏。比如:
#define myprintf(templt,...) fprintf(stderr,templt,__VA_ARGS__)
//或者
#define myprintf(templt,args...) fprintf(stderr,templt,args)
第一个宏中由于没有对变参起名,我们用默认的宏__VA_ARGS__来替代它。第二个宏中,我们显式地命名变参为args,那么我们在宏定义中就可以用args来代指变参了。同C语言的stdcall一样,变参必须作为参数表的最有一项出现。当上面的宏中我们只能提供第一个参数templt时,C标准要求我们必须写成:
myprintf(templt,);
的形式。这时的替换过程为:
myprintf("Error!\n",);
替换为:
fprintf(stderr,"Error!\n",);
这是一个语法错误,不能正常编译。这个问题一般有两个解决方法。首先,GNU CPP提供的解决方法允许上面的宏调用写成:
myprintf(templt);
而它将会被通过替换变成:
fprintf(stderr,"Error!\n",);
很明显,这里仍然会产生编译错误(非本例的某些情况下不会产生编译错误)。除了这种方式外,c99和GNU CPP都支持下面的宏定义方式:
#define myprintf(templt, ...) fprintf(stderr,templt, ##__VAR_ARGS__)
这时,##这个连接符号充当的作用就是当__VAR_ARGS__为空的时候,消除前面的那个逗号。那么此时的翻译过程如下:
myprintf(templt);
被转化为:
fprintf(stderr,templt);
这样如果templt合法,将不会产生编译错误。 这里列出了一些宏使用中容易出错的地方,以及合适的使用方式。
原文地址 http://hi.baidu.com/xliuchen/blog/item/f7913f01a379d404728da561.html
4 define定义使用
struct exception_table_entry
{
unsigned long insn;
unsigned long fixup;
};
extern const struct exception_table_entry __attribute__((aligned(8))) __start___ex_table[];
#ifdef __CHECKER__
#define __bitwise__ __attribute__((bitwise))
#else
#define __bitwise__
#endif
#ifdef __CHECK_ENDIAN__
#define __bitwise __bitwise__
#else
#define __bitwise
#endif
/*#ifndef __u16
#define __u16 unsigned short
#endif
typedef __u16 __bitwise __le16;*/未使用
typedef int __bitwise suspend_state_t;
#define PM_SUSPEND_ON ((__force suspend_state_t) 0)
__force等同于__bitwise
4内核函数的典型应用
static int setopt(int count, int lineno,char *vars[])
{
int c;
int retval = 0, rc;
optind = 0;
opterr = 0;
key[0] = 0;
keylen = AUDIT_MAX_KEY_LEN;
while ((retval >= 0) && (c = getopt(count, vars,
"hislDvte:f:r:b:a:A:d:S:F:m:R:w:W:k:p:q:")) != EOF) {
intflags = AUDIT_FILTER_UNSET;
rc =10; // Init to something impossible to see if unused.
switch (c) {
case 'h':
usage();
retval = -1;
break;
case'i':
ignore = 1;
break;
case 's':
retval = audit_request_status(fd);
if(retval <= 0)
retval = -1;
else
retval = 0; /* success - just get the reply */
break;
case 'e':
if(optarg && ((strcmp(optarg, "0") == 0) ||
(strcmp(optarg, "1") == 0) ||
(strcmp(optarg, "2") == 0))) {
if(audit_set_enabled(fd, strtoul(optarg,NULL,0)) > 0)
audit_request_status(fd);
else
retval = -1;
}else {
fprintf(stderr, "Enable must be 0, 1, or 2 was %s\n",
optarg);
retval = -1;
}
break;
case 'f':
if(optarg && ((strcmp(optarg, "0") == 0) ||
(strcmp(optarg, "1") == 0) ||
(strcmp(optarg, "2") == 0))) {
if(audit_set_failure(fd, strtoul(optarg,NULL,0)) > 0)
audit_request_status(fd);
else
return -1;
}else {
fprintf(stderr, "Failure must be 0, 1, or 2 was %s\n",
optarg);
retval = -1;
}
break;
case 'r':
if(optarg && isdigit(optarg[0])) {
uint32_t rate;
errno = 0;
rate = strtoul(optarg,NULL,0);
if(errno) {
fprintf(stderr, "Error converting rate\n");
return -1;
}
if(audit_set_rate_limit(fd, rate) > 0)
audit_request_status(fd);
else
return -1;
}else {
fprintf(stderr, "Rate must be a numeric value was %s\n",
optarg);
retval = -1;
}
break;
case 'b':
if(optarg && isdigit(optarg[0])) {
uint32_t limit;
errno = 0;
limit = strtoul(optarg,NULL,0);
if(errno) {
fprintf(stderr, "Error converting backlog\n");
return -1;
}
if(audit_set_backlog_limit(fd, limit) > 0)
audit_request_status(fd);
else
return -1;
}else {
fprintf(stderr,
"Backlog must be a numeric value was %s\n",
optarg);
retval = -1;
}
break;
case 'l':
if(count > 4 || count == 3) {
fprintf(stderr,
"Wrong number of options for list request\n");
retval = -1;
break;
}
if(count == 4) {
if(strcmp(vars[optind], "-k") == 0) {
strncat(key, vars[3], keylen);
count -= 2;
}else {
fprintf(stderr,
"Only the -k option is allowed\n");
retval = -1;
break;
}
}
audit_request_rule_list(fd);
retval = -2;
break;
case 'a':
if(strstr(optarg, "task") && audit_syscalladded) {
fprintf(stderr,
"Syscall auditing requested for task list\n");
retval = -1;
}else {
rc= audit_rule_setup(optarg, &add, &action, lineno);
if(rc == 3) {
fprintf(stderr,
"Multiple rule insert/delete operations are not allowed\n");
retval = -1;
}else if (rc == 2) {
fprintf(stderr,
"Append rule - bad keyword %s\n",
optarg);
retval = -1;
}else if (rc == 1) {
fprintf(stderr,
"Append rule - possible is deprecated\n");
return -3; /* deprecated - eat it */
}else
retval = 1; /* success - please send */
}
break;
case 'A':
if(strstr(optarg, "task") && audit_syscalladded) {
fprintf(stderr,
"Error: syscall auditing requested fortask list\n");
retval = -1;
}else {
rc= audit_rule_setup(optarg, &add, &action, lineno);
if(rc == 3) {
fprintf(stderr,
"Multiple rule insert/delete operations are not allowed\n");
retval = -1;
}else if (rc == 2) {
fprintf(stderr,
"Add rule - bad keyword %s\n", optarg);
retval = -1;
}else if (rc == 1) {
fprintf(stderr,
"Append rule - possible is deprecated\n");
return -3; /* deprecated - eat it */
}else {
if(add ==AUDIT_FILTER_DAC)
add=AUDIT_FILTER_EXIT;
add |= AUDIT_FILTER_PREPEND;
retval = 1; /* success - please send */
}
}
break;
case 'd':
rc= audit_rule_setup(optarg, &del, &action, lineno);
if(rc == 3) {
fprintf(stderr,
"Multiple rule insert/delete operations are not allowed\n");
retval = -1;
}else if (rc == 2) {
fprintf(stderr, "Delete rule - bad keyword %s\n",
optarg);
retval = -1;
}else if (rc == 1) {
fprintf(stderr,
"Delete rule - possible isdeprecated\n");
return -3; /* deprecated - eat it */
}else
retval = 1; /* success - please send */
break;
case 'S': {
intunknown_arch = !audit_elf;
/*Do some checking to make sure that we are not adding a
*syscall rule to a list that does not make sense. */
if(((add & (AUDIT_FILTER_MASK|AUDIT_FILTER_UNSET)) ==
AUDIT_FILTER_TASK || (del &
(AUDIT_FILTER_MASK|AUDIT_FILTER_UNSET)) ==
AUDIT_FILTER_TASK)) {
fprintf(stderr,
"Error: syscall auditing being added to task list\n");
return -1;
}else if (((add & (AUDIT_FILTER_MASK|AUDIT_FILTER_UNSET)) ==
AUDIT_FILTER_USER || (del &
(AUDIT_FILTER_MASK|AUDIT_FILTER_UNSET)) ==
AUDIT_FILTER_USER)) {
fprintf(stderr,
"Error: syscall auditing being added to user list\n");
return -1;
}else if (((add & (AUDIT_FILTER_MASK|AUDIT_FILTER_UNSET)) ==
AUDIT_FILTER_DAC || (del &
(AUDIT_FILTER_MASK|AUDIT_FILTER_UNSET)) ==
AUDIT_FILTER_DAC)) {
fprintf(stderr,
"Error: syscall auditing being added to dac list\n");
return -1;
}else if (exclude) {
fprintf(stderr,
"Error: syscall auditing cannot be put on exclude list\n");
return -1;
}else {
if(unknown_arch) {
int machine;
unsigned int elf;
machine = audit_detect_machine();
if (machine < 0) {
fprintf(stderr,
"Error detecting machine type");
return -1;
}
elf = audit_machine_to_elf(machine);
if (elf == 0) {
fprintf(stderr,
"Error looking up elf type");
return -1;
}
audit_elf = elf;
}
}
rc= audit_rule_syscallbyname_data(rule_new, optarg);
switch (rc)
{
case 0:
audit_syscalladded = 1;
if (unknown_arch && add != AUDIT_FILTER_UNSET)
check_rule_mismatch(lineno, optarg);
break;
case -1:
fprintf(stderr, "Syscall name unknown: %s\n",
optarg);
retval = -1;
break;
case -2:
fprintf(stderr, "Elf type unknown: 0x%x\n",
audit_elf);
retval = -1;
break;
}}
break;
case 'F':
if(add != AUDIT_FILTER_UNSET)
flags = add & AUDIT_FILTER_MASK;
else if (del != AUDIT_FILTER_UNSET)
flags = del & AUDIT_FILTER_MASK;
//if the field is arch & there is a -t option...we
//can allow it
else if ((optind >= count) || (strstr(optarg, "arch=") ==NULL)
|| (strcmp(vars[optind], "-t") != 0)) {
fprintf(stderr, "List must be given before field\n");
retval = -1;
break;
}
rc= audit_rule_fieldpair_data(&rule_new,optarg,flags);
if(rc != 0) {
audit_number_to_errmsg(rc, optarg);
retval = -1;
}else {
if(rule_new->fields[rule_new->field_count-1] ==
AUDIT_PERM)
audit_permadded = 1;
}
break;
case 'm':
if(count > 3) {
fprintf(stderr,
"The -m option must be only the onlyoption and takes 1 parameter\n");
retval = -1;
}else if (audit_log_user_message( fd, AUDIT_USER, optarg, NULL,
NULL, NULL, 1) <=0)
retval = -1;
else
return -2; // success - no replyfor this
break;
case'R':
fprintf(stderr, "Error - nested rule files not supported\n");
retval = -1;
break;
case'D':
if(count > 4 || count == 3) {
fprintf(stderr,
"Wrong number of options for Delete all request\n");
retval = -1;
break;
}
if(count == 4) {
if(strcmp(vars[optind], "-k") == 0) {
strncat(key, vars[3], keylen);
count -= 2;
}else {
fprintf(stderr,
"Only the -k option is allowed\n");
retval = -1;
break;
}
}
retval = delete_all_rules(fd);
if(retval == 0) {
audit_request_rule_list(fd);
key[0] = 0;
retval = -2;
}
break;
case'w':
if(add != AUDIT_FILTER_UNSET ||
del != AUDIT_FILTER_UNSET) {
fprintf(stderr,
"watch option can't be given with a syscall\n");
retval = -1;
}else if (optarg) {
add = AUDIT_FILTER_EXIT;
action = AUDIT_ALWAYS;
audit_syscalladded = 1;
retval = audit_setup_watch_name(&rule_new, optarg);
}else {
fprintf(stderr, "watch option needs a path\n");
retval = -1;
}
break;
case'W':
if(optarg) {
del = AUDIT_FILTER_EXIT;
action = AUDIT_ALWAYS;
audit_syscalladded = 1;
retval = audit_setup_watch_name(&rule_new, optarg);
}else {
fprintf(stderr, "watch option needs a path\n");
retval = -1;
}
break;
case'k':
if(!(audit_syscalladded || audit_permadded ) ||
(add==AUDIT_FILTER_UNSET &&
del==AUDIT_FILTER_UNSET)) {
fprintf(stderr,
"key option needs a watch or syscall given prior to it\n");
retval = -1;
}else if (!optarg) {
fprintf(stderr, "key option needs a value\n");
retval = -1;
}else if ((strlen(optarg)+strlen(key)+(!!key[0])) >
AUDIT_MAX_KEY_LEN) {
fprintf(stderr, "key option exceeds size limit\n");
retval = -1;
}else {
if(strncmp(optarg, "ids-", 4) == 0) {
if (check_ids_key(optarg)) {
retval = -1;
break;
}
}
if(strchr(optarg, AUDIT_KEY_SEPARATOR))
fprintf(stderr,
"key %s has illegal character\n", optarg);
if(key[0]) { // Add the separator if we need to
strcat(key, key_sep);
keylen--;
}
strncat(key, optarg, keylen);
keylen= AUDIT_MAX_KEY_LEN - strlen(key);
}
break;
case'p':
if(!add && !del) {
fprintf(stderr,
"permission option needs a watch given prior to it\n");
retval = -1;
}else if (!optarg) {
fprintf(stderr, "permission option needs a filter\n");
retval = -1;
}else
retval = audit_setup_perms(rule_new, optarg);
break;
case 'q':
if(audit_syscalladded) {
fprintf(stderr,
"Syscall auditing requested for make equivalent\n");
retval = -1;
}else {
char *mp, *sub;
retval = equiv_parse(optarg, &mp, &sub);
if(retval < 0) {
fprintf(stderr,
"Error parsing equivalent parts\n");
retval = -1;
}else {
retval = audit_make_equivalent(fd, mp, sub);
if (retval <= 0) {
retval = -1;
}else
return -2; // success - no reply needed
}
}
break;
case 't':
retval = audit_trim_subtrees(fd);
if(retval <= 0)
retval = -1;
else
return -2; // success - no replyfor this
break;
case'v':
printf("auditctl version %s\n", VERSION);
retval = -2;
break;
default:
usage();
retval = -1;
break;
}
}
/* catch extra args or errors where the user types "- s" */
if (optind == 1)
retval = -1;
else if ((optind < count) && (retval != -1)) {
fprintf(stderr, "parameter passed withoutan option given\n");
retval = -1;
}
/* See if we were adding a key */
if (key[0] && list_requested == 0) {
intflags = 0;
char*cmd=NULL;
/*Get the flag */
if(add != AUDIT_FILTER_UNSET)
flags = add & AUDIT_FILTER_MASK;
elseif (del != AUDIT_FILTER_UNSET)
flags = del & AUDIT_FILTER_MASK;
/*Build the command */
asprintf(&cmd, "key=%s", key);
if(cmd) {
/*Add this to the rule */
intret = audit_rule_fieldpair_data(&rule_new, cmd, flags);
if(ret < 0)
retval = -1;
free(cmd);
}else {
fprintf(stderr, "Out of memory adding key\n");
retval = -1;
}
}
if (retval == -1 && errno == ECONNREFUSED)
fprintf(stderr, "The audit system is disabled\n");
return retval;
}