udev-rules.c revision 84198c1892cce2cb27d22bfa816da5d43c05add0
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering * Copyright (C) 2003-2012 Kay Sievers <kay@vrfy.org>
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering * This program is free software: you can redistribute it and/or modify
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering * it under the terms of the GNU General Public License as published by
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering * the Free Software Foundation, either version 2 of the License, or
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering * (at your option) any later version.
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering * This program is distributed in the hope that it will be useful,
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering * but WITHOUT ANY WARRANTY; without even the implied warranty of
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering * GNU General Public License for more details.
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering * You should have received a copy of the GNU General Public License
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering * along with this program. If not, see <http://www.gnu.org/licenses/>.
ad79565d6b37bcc93cf773a39b975e5b85d122daUmut Tezduyar Lindskogstatic const char* const rules_dirs[] = {
ad79565d6b37bcc93cf773a39b975e5b85d122daUmut Tezduyar Lindskog /* every key in the rules file becomes a token */
fb4729006a7174472e8a435b0887e532cd6217fcZbigniew Jędrzejewski-Szmek /* all key strings are copied and de-duplicated in a single continuous string buffer */
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering /* during rule parsing, uid/gid lookup results are cached */
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmekstatic char *rules_str(struct udev_rules *rules, unsigned int off) {
de0671ee7fe465e108f62dcbbbe9366f81dd9e9aZbigniew Jędrzejewski-Szmek return rules->strbuf->buf + off;
ad79565d6b37bcc93cf773a39b975e5b85d122daUmut Tezduyar Lindskogstatic unsigned int rules_add_string(struct udev_rules *rules, const char *s) {
ad79565d6b37bcc93cf773a39b975e5b85d122daUmut Tezduyar Lindskog return strbuf_add_string(rules->strbuf, s, strlen(s));
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering/* KEY=="", KEY!="", KEY+="", KEY-="", KEY="", KEY:="" */
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering GL_SPLIT_GLOB, /* multi-value with glob A*|B* */
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering/* tokens of a rule are sorted/handled in this order */
struct token {
unsigned short token_count;
unsigned int label_off;
unsigned short filename_off;
unsigned short filename_line;
} rule;
unsigned int value_off;
unsigned int attr_off;
unsigned int rule_goto;
int devlink_prio;
int watch;
} key;
struct rule_tmp {
unsigned int token_cur;
#ifdef DEBUG
static const char *operation_strs[] = {
static const char *string_glob_strs[] = {
static const char *token_strs[] = {
switch (type) {
case TK_RULE:
case TK_M_ACTION:
case TK_M_DEVPATH:
case TK_M_KERNEL:
case TK_M_SUBSYSTEM:
case TK_M_DRIVER:
case TK_M_WAITFOR:
case TK_M_DEVLINK:
case TK_M_NAME:
case TK_M_KERNELS:
case TK_M_SUBSYSTEMS:
case TK_M_DRIVERS:
case TK_M_TAGS:
case TK_M_PROGRAM:
case TK_M_IMPORT_FILE:
case TK_M_IMPORT_PROG:
case TK_M_IMPORT_DB:
case TK_M_IMPORT_CMDLINE:
case TK_M_IMPORT_PARENT:
case TK_M_RESULT:
case TK_A_NAME:
case TK_A_DEVLINK:
case TK_A_OWNER:
case TK_A_GROUP:
case TK_A_MODE:
case TK_A_RUN_BUILTIN:
case TK_A_RUN_PROGRAM:
case TK_M_IMPORT_BUILTIN:
case TK_M_ATTR:
case TK_M_ATTRS:
case TK_M_ENV:
case TK_A_ATTR:
case TK_A_ENV:
case TK_M_TAG:
case TK_A_TAG:
case TK_A_STRING_ESCAPE_NONE:
case TK_A_DB_PERSIST:
case TK_M_TEST:
case TK_A_INOTIFY_WATCH:
case TK_A_DEVLINK_PRIO:
case TK_A_OWNER_ID:
case TK_A_GROUP_ID:
case TK_A_MODE_ID:
case TK_A_STATIC_NODE:
case TK_A_SECLABEL:
case TK_A_GOTO:
case TK_END:
case TK_M_PARENTS_MIN:
case TK_M_PARENTS_MAX:
case TK_M_MAX:
case TK_UNSET:
unsigned int add;
unsigned int off;
return uid;
unsigned int add;
return uid;
if (off <= 0)
return uid;
return uid;
unsigned int off;
return gid;
unsigned int add;
return gid;
if (off <= 0)
return gid;
return gid;
char *key;
char *val;
key++;
val++;
val++;
if (len == 0)
len--;
if (len == 0)
len--;
if (len == 0)
val++;
FILE *f;
if (f == NULL)
fclose(f);
char **envp;
char *line;
int err;
err = udev_event_spawn(event, timeout_usec, timeout_warn_usec, program, envp, sigmask, result, sizeof(result));
if (err < 0)
return err;
char *pos;
while (--loop) {
bool found = false;
char *pos;
const char *tail;
found = true;
return found;
static int get_key(struct udev *udev, char **line, char **key, enum operation_type *op, char **value) {
char *linepos;
char *temp;
linepos++;
linepos++;
linepos++;
linepos++;
linepos++;
linepos++;
if (!temp)
temp++;
char *pos;
char *attr;
attr++;
return NULL;
return attr;
return NULL;
switch (type) {
case TK_M_ACTION:
case TK_M_DEVPATH:
case TK_M_KERNEL:
case TK_M_SUBSYSTEM:
case TK_M_DRIVER:
case TK_M_WAITFOR:
case TK_M_DEVLINK:
case TK_M_NAME:
case TK_M_KERNELS:
case TK_M_SUBSYSTEMS:
case TK_M_DRIVERS:
case TK_M_TAGS:
case TK_M_PROGRAM:
case TK_M_IMPORT_FILE:
case TK_M_IMPORT_PROG:
case TK_M_IMPORT_DB:
case TK_M_IMPORT_CMDLINE:
case TK_M_IMPORT_PARENT:
case TK_M_RESULT:
case TK_A_OWNER:
case TK_A_GROUP:
case TK_A_MODE:
case TK_A_DEVLINK:
case TK_A_NAME:
case TK_A_GOTO:
case TK_M_TAG:
case TK_A_TAG:
case TK_A_STATIC_NODE:
case TK_M_IMPORT_BUILTIN:
case TK_M_ENV:
case TK_M_ATTR:
case TK_M_ATTRS:
case TK_A_ATTR:
case TK_A_ENV:
case TK_A_SECLABEL:
case TK_M_TEST:
case TK_A_STRING_ESCAPE_NONE:
case TK_A_DB_PERSIST:
case TK_A_RUN_BUILTIN:
case TK_A_RUN_PROGRAM:
case TK_A_INOTIFY_WATCH:
case TK_A_DEVLINK_PRIO:
case TK_A_OWNER_ID:
case TK_A_GROUP_ID:
case TK_A_MODE_ID:
case TK_RULE:
case TK_M_PARENTS_MIN:
case TK_M_PARENTS_MAX:
case TK_M_MAX:
case TK_END:
case TK_UNSET:
int has_split;
int has_glob;
} else if (has_split) {
} else if (has_glob) {
unsigned int start = 0;
unsigned int next_idx = 0;
next_idx = j;
start++;
end--;
char *linepos;
const char *attr;
char *key;
char *value;
linepos++;
goto invalid;
goto invalid;
goto invalid;
goto invalid;
goto invalid;
goto invalid;
goto invalid;
if (!attr) {
goto invalid;
goto invalid;
goto invalid;
goto invalid;
goto invalid;
goto invalid;
goto invalid;
goto invalid;
goto invalid;
goto invalid;
goto invalid;
static const char *blacklist[] = {
goto invalid;
goto invalid;
goto invalid;
goto invalid;
goto invalid;
goto invalid;
goto invalid;
goto invalid;
goto invalid;
goto invalid;
goto invalid;
goto invalid;
char *endptr;
goto invalid;
char *endptr;
goto invalid;
char *endptr;
goto invalid;
const char *pos;
goto invalid;
const int off = 0;
goto invalid;
goto invalid;
goto invalid;
unsigned int first_token;
unsigned int filename_off;
int line_nr = 0;
return -errno;
char *key;
line_nr++;
key++;
line_nr++;
char **files, **f;
return NULL;
rules->token_max * sizeof(struct token), rules->token_max, sizeof(struct token), rules->strbuf->len);
return rules;
return NULL;
return NULL;
if (!rules)
char *pos;
bool match = false;
case GL_PLAIN:
case GL_GLOB:
case GL_SPLIT:
const char *next;
if (match)
case GL_SPLIT_GLOB:
if (match)
case GL_SOMETHING:
case GL_UNSET:
static int match_attr(struct udev_rules *rules, struct udev_device *dev, struct udev_event *event, struct token *cur) {
const char *name;
const char *value;
case SB_FORMAT:
case SB_NONE:
case SB_SUBSYS:
const char *key_value;
enum escape_type {
bool can_set_name;
case TK_RULE:
goto nomatch;
case TK_M_ACTION:
goto nomatch;
case TK_M_DEVPATH:
goto nomatch;
case TK_M_KERNEL:
goto nomatch;
case TK_M_DEVLINK: {
bool match = false;
const char *devlink;
match = true;
if (!match)
goto nomatch;
case TK_M_NAME:
goto nomatch;
case TK_M_ENV: {
const char *value;
if (!value)
goto nomatch;
case TK_M_TAG: {
bool match = false;
match = true;
goto nomatch;
case TK_M_SUBSYSTEM:
goto nomatch;
case TK_M_DRIVER:
goto nomatch;
case TK_M_WAITFOR: {
int found;
goto nomatch;
case TK_M_ATTR:
goto nomatch;
case TK_M_KERNELS:
case TK_M_SUBSYSTEMS:
case TK_M_DRIVERS:
case TK_M_ATTRS:
case TK_M_TAGS: {
next++;
case TK_M_KERNELS:
goto try_parent;
case TK_M_SUBSYSTEMS:
goto try_parent;
case TK_M_DRIVERS:
goto try_parent;
case TK_M_ATTRS:
goto try_parent;
case TK_M_TAGS: {
goto try_parent;
goto try_parent;
goto nomatch;
goto nomatch;
case TK_M_TEST: {
int match;
goto nomatch;
goto nomatch;
case TK_M_PROGRAM: {
char **envp;
if (udev_event_spawn(event, timeout_usec, timeout_warn_usec, program, envp, sigmask, result, sizeof(result)) < 0) {
goto nomatch;
int count;
if (count > 0)
goto nomatch;
case TK_M_IMPORT_FILE: {
goto nomatch;
case TK_M_IMPORT_PROG: {
goto nomatch;
case TK_M_IMPORT_BUILTIN: {
goto nomatch;
goto nomatch;
case TK_M_IMPORT_DB: {
const char *value;
goto nomatch;
case TK_M_IMPORT_CMDLINE: {
FILE *f;
bool imported = false;
if (f != NULL) {
char *pos;
imported = true;
const char *value;
pos++;
pos++;
imported = true;
fclose(f);
goto nomatch;
case TK_M_IMPORT_PARENT: {
goto nomatch;
case TK_M_RESULT:
goto nomatch;
case TK_A_STRING_ESCAPE_NONE:
case TK_A_DB_PERSIST:
case TK_A_INOTIFY_WATCH:
case TK_A_DEVLINK_PRIO:
case TK_A_OWNER: {
case TK_A_GROUP: {
case TK_A_MODE: {
char *endptr;
case TK_A_OWNER_ID:
case TK_A_GROUP_ID:
case TK_A_MODE_ID:
case TK_A_SECLABEL: {
case TK_A_ENV: {
if (value_old) {
case TK_A_TAG: {
case TK_A_NAME: {
int count;
if (count > 0)
case TK_A_DEVLINK: {
int count = 0;
if (count > 0)
pos++;
next++;
case TK_A_ATTR: {
FILE *f;
if (f != NULL) {
fclose(f);
case TK_A_RUN_BUILTIN:
case TK_A_RUN_PROGRAM: {
case TK_A_GOTO:
case TK_END:
case TK_M_PARENTS_MIN:
case TK_M_PARENTS_MAX:
case TK_M_MAX:
case TK_UNSET:
goto nomatch;
cur++;
case TK_RULE:
goto next;
uid = 0;
gid = 0;
mode = 0;
case TK_A_OWNER_ID:
case TK_A_GROUP_ID:
case TK_A_MODE_ID:
case TK_A_TAG:
goto finish;
case TK_A_STATIC_NODE: {
goto next;
if (tags) {
if (mode == 0) {
if (gid > 0)
return -errno;
return -errno;
case TK_END:
goto finish;
cur++;
next:
fflush(f);
r = -errno;
fclose(f);