udev: use conf_files_list() to search rules files
This commit is contained in:
parent
0a1a17aa2d
commit
775f8b3c74
|
@ -36,13 +36,6 @@
|
||||||
#define PREALLOC_STRBUF 32 * 1024
|
#define PREALLOC_STRBUF 32 * 1024
|
||||||
#define PREALLOC_TRIE 256
|
#define PREALLOC_TRIE 256
|
||||||
|
|
||||||
/* configuration directories with last modification timestamp */
|
|
||||||
static const char *rules_dirs[] = {
|
|
||||||
TEST_PREFIX UDEVLIBEXECDIR "/rules.d",
|
|
||||||
TEST_PREFIX "/run/udev/rules.d",
|
|
||||||
TEST_PREFIX SYSCONFDIR "/udev/rules.d",
|
|
||||||
};
|
|
||||||
|
|
||||||
struct uid_gid {
|
struct uid_gid {
|
||||||
unsigned int name_off;
|
unsigned int name_off;
|
||||||
union {
|
union {
|
||||||
|
@ -65,7 +58,8 @@ struct trie_node {
|
||||||
|
|
||||||
struct udev_rules {
|
struct udev_rules {
|
||||||
struct udev *udev;
|
struct udev *udev;
|
||||||
unsigned long long dirs_ts_usec[ELEMENTSOF(rules_dirs)];
|
char **dirs;
|
||||||
|
unsigned long long *dirs_ts_usec;
|
||||||
int resolve_names;
|
int resolve_names;
|
||||||
|
|
||||||
/* every key in the rules file becomes a token */
|
/* every key in the rules file becomes a token */
|
||||||
|
@ -79,7 +73,7 @@ struct udev_rules {
|
||||||
size_t buf_max;
|
size_t buf_max;
|
||||||
unsigned int buf_count;
|
unsigned int buf_count;
|
||||||
|
|
||||||
/* during rule parsing, strings are indexed to find duplicates */
|
/* during rule parsing, strings are indexed and de-duplicated */
|
||||||
struct trie_node *trie_nodes;
|
struct trie_node *trie_nodes;
|
||||||
unsigned int trie_nodes_cur;
|
unsigned int trie_nodes_cur;
|
||||||
unsigned int trie_nodes_max;
|
unsigned int trie_nodes_max;
|
||||||
|
@ -1188,7 +1182,9 @@ static int add_rule(struct udev_rules *rules, char *line,
|
||||||
memset(&rule_tmp, 0x00, sizeof(struct rule_tmp));
|
memset(&rule_tmp, 0x00, sizeof(struct rule_tmp));
|
||||||
rule_tmp.rules = rules;
|
rule_tmp.rules = rules;
|
||||||
rule_tmp.rule.type = TK_RULE;
|
rule_tmp.rule.type = TK_RULE;
|
||||||
rule_tmp.rule.rule.filename_off = filename_off;
|
/* the offset in the rule is limited to unsigned short */
|
||||||
|
if (filename_off < USHRT_MAX)
|
||||||
|
rule_tmp.rule.rule.filename_off = filename_off;
|
||||||
rule_tmp.rule.rule.filename_line = lineno;
|
rule_tmp.rule.rule.filename_line = lineno;
|
||||||
|
|
||||||
linepos = line;
|
linepos = line;
|
||||||
|
@ -1632,21 +1628,27 @@ invalid:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_file(struct udev_rules *rules, const char *filename, unsigned short filename_off)
|
static int parse_file(struct udev_rules *rules, const char *filename)
|
||||||
{
|
{
|
||||||
FILE *f;
|
FILE *f;
|
||||||
unsigned int first_token;
|
unsigned int first_token;
|
||||||
|
unsigned int filename_off;
|
||||||
char line[UTIL_LINE_SIZE];
|
char line[UTIL_LINE_SIZE];
|
||||||
int line_nr = 0;
|
int line_nr = 0;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
log_debug("reading '%s' as rules file\n", filename);
|
if (null_or_empty_path(filename)) {
|
||||||
|
log_debug("skip empty file: %s\n", filename);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
log_debug("read rules file: %s\n", filename);
|
||||||
|
|
||||||
f = fopen(filename, "r");
|
f = fopen(filename, "r");
|
||||||
if (f == NULL)
|
if (f == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
first_token = rules->token_cur;
|
first_token = rules->token_cur;
|
||||||
|
filename_off = add_string(rules, filename);
|
||||||
|
|
||||||
while (fgets(line, sizeof(line), f) != NULL) {
|
while (fgets(line, sizeof(line), f) != NULL) {
|
||||||
char *key;
|
char *key;
|
||||||
|
@ -1707,52 +1709,13 @@ static int parse_file(struct udev_rules *rules, const char *filename, unsigned s
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_matching_files(struct udev *udev, struct udev_list *file_list, const char *dirname, const char *suffix)
|
|
||||||
{
|
|
||||||
DIR *dir;
|
|
||||||
struct dirent *dent;
|
|
||||||
char filename[UTIL_PATH_SIZE];
|
|
||||||
|
|
||||||
dir = opendir(dirname);
|
|
||||||
if (dir == NULL) {
|
|
||||||
log_debug("unable to open '%s': %m\n", dirname);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
|
|
||||||
if (dent->d_name[0] == '.')
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* look for file matching with specified suffix */
|
|
||||||
if (suffix != NULL) {
|
|
||||||
const char *ext;
|
|
||||||
|
|
||||||
ext = strrchr(dent->d_name, '.');
|
|
||||||
if (ext == NULL)
|
|
||||||
continue;
|
|
||||||
if (!streq(ext, suffix))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
util_strscpyl(filename, sizeof(filename), dirname, "/", dent->d_name, NULL);
|
|
||||||
/*
|
|
||||||
* the basename is the key, the filename the value
|
|
||||||
* identical basenames from different directories override each other
|
|
||||||
* entries are sorted after basename
|
|
||||||
*/
|
|
||||||
udev_list_entry_add(file_list, dent->d_name, filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
closedir(dir);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names)
|
struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names)
|
||||||
{
|
{
|
||||||
struct udev_rules *rules;
|
struct udev_rules *rules;
|
||||||
struct udev_list file_list;
|
struct udev_list file_list;
|
||||||
struct udev_list_entry *file_loop;
|
|
||||||
struct token end_token;
|
struct token end_token;
|
||||||
unsigned int i;
|
char **files, **f;
|
||||||
|
int r;
|
||||||
|
|
||||||
rules = calloc(1, sizeof(struct udev_rules));
|
rules = calloc(1, sizeof(struct udev_rules));
|
||||||
if (rules == NULL)
|
if (rules == NULL)
|
||||||
|
@ -1792,41 +1755,37 @@ struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names)
|
||||||
memset(rules->trie_nodes, 0x00, sizeof(struct trie_node));
|
memset(rules->trie_nodes, 0x00, sizeof(struct trie_node));
|
||||||
rules->trie_nodes_cur = 1;
|
rules->trie_nodes_cur = 1;
|
||||||
|
|
||||||
for (i = 0; i < ELEMENTSOF(rules_dirs); i++)
|
rules->dirs = strv_new(TEST_PREFIX SYSCONFDIR "/udev/rules.d",
|
||||||
add_matching_files(udev, &file_list, rules_dirs[i], ".rules");
|
TEST_PREFIX "/run/udev/rules.d",
|
||||||
|
TEST_PREFIX UDEVLIBEXECDIR "/rules.d",
|
||||||
/* add all filenames to the string buffer */
|
NULL);
|
||||||
udev_list_entry_foreach(file_loop, udev_list_get_entry(&file_list)) {
|
if (!rules->dirs) {
|
||||||
const char *filename = udev_list_entry_get_value(file_loop);
|
log_error("failed to build config directory array");
|
||||||
unsigned int filename_off;
|
return NULL;
|
||||||
|
|
||||||
filename_off = add_string(rules, filename);
|
|
||||||
/* the offset in the rule is limited to unsigned short */
|
|
||||||
if (filename_off < USHRT_MAX)
|
|
||||||
udev_list_entry_set_num(file_loop, filename_off);
|
|
||||||
}
|
}
|
||||||
|
if (!strv_path_canonicalize(rules->dirs)) {
|
||||||
/* parse all rules files */
|
log_error("failed to canonicalize config directories\n");
|
||||||
udev_list_entry_foreach(file_loop, udev_list_get_entry(&file_list)) {
|
return NULL;
|
||||||
const char *filename = udev_list_entry_get_value(file_loop);
|
|
||||||
unsigned int filename_off = udev_list_entry_get_num(file_loop);
|
|
||||||
struct stat st;
|
|
||||||
|
|
||||||
if (stat(filename, &st) != 0) {
|
|
||||||
log_error("can not find '%s': %m\n", filename);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (S_ISREG(st.st_mode) && st.st_size <= 0) {
|
|
||||||
log_debug("ignore empty '%s'\n", filename);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (S_ISCHR(st.st_mode)) {
|
|
||||||
log_debug("ignore masked '%s'\n", filename);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
parse_file(rules, filename, filename_off);
|
|
||||||
}
|
}
|
||||||
udev_list_cleanup(&file_list);
|
strv_uniq(rules->dirs);
|
||||||
|
r = conf_files_list_strv(&files, ".rules", (const char **)rules->dirs);
|
||||||
|
if (r < 0) {
|
||||||
|
log_error("failed to enumerate rules files: %s\n", strerror(-r));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
rules->dirs_ts_usec = calloc(strv_length(rules->dirs), sizeof(long long));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The offset value in the rules strct is limited; add all
|
||||||
|
* rules file names to the beginning of the string buffer.
|
||||||
|
*/
|
||||||
|
STRV_FOREACH(f, files)
|
||||||
|
add_string(rules, *f);
|
||||||
|
|
||||||
|
STRV_FOREACH(f, files)
|
||||||
|
parse_file(rules, *f);
|
||||||
|
|
||||||
|
strv_free(files);
|
||||||
|
|
||||||
memset(&end_token, 0x00, sizeof(struct token));
|
memset(&end_token, 0x00, sizeof(struct token));
|
||||||
end_token.type = TK_END;
|
end_token.type = TK_END;
|
||||||
|
@ -1886,6 +1845,8 @@ struct udev_rules *udev_rules_unref(struct udev_rules *rules)
|
||||||
free(rules->trie_nodes);
|
free(rules->trie_nodes);
|
||||||
free(rules->uids);
|
free(rules->uids);
|
||||||
free(rules->gids);
|
free(rules->gids);
|
||||||
|
strv_free(rules->dirs);
|
||||||
|
free(rules->dirs_ts_usec);
|
||||||
free(rules);
|
free(rules);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1895,10 +1856,10 @@ bool udev_rules_check_timestamp(struct udev_rules *rules)
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
|
||||||
for (i = 0; i < ELEMENTSOF(rules_dirs); i++) {
|
for (i = 0; rules->dirs[i]; i++) {
|
||||||
struct stat stats;
|
struct stat stats;
|
||||||
|
|
||||||
if (stat(rules_dirs[i], &stats) < 0)
|
if (stat(rules->dirs[i], &stats) < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (rules->dirs_ts_usec[i] == ts_usec(&stats.st_mtim))
|
if (rules->dirs_ts_usec[i] == ts_usec(&stats.st_mtim))
|
||||||
|
@ -1906,7 +1867,7 @@ bool udev_rules_check_timestamp(struct udev_rules *rules)
|
||||||
|
|
||||||
/* first check */
|
/* first check */
|
||||||
if (rules->dirs_ts_usec[i] != 0) {
|
if (rules->dirs_ts_usec[i] != 0) {
|
||||||
log_debug("reload - timestamp of '%s' changed\n", rules_dirs[i]);
|
log_debug("reload - timestamp of '%s' changed\n", rules->dirs[i]);
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "libudev-private.h"
|
#include "libudev-private.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "label.h"
|
#include "label.h"
|
||||||
|
#include "strv.h"
|
||||||
|
|
||||||
struct udev_event {
|
struct udev_event {
|
||||||
struct udev *udev;
|
struct udev *udev;
|
||||||
|
|
Loading…
Reference in a new issue