mirror of
https://github.com/troglobit/finit.git
synced 2026-10-30 12:50:34 +00:00
keventd: load udev rules in udev's order, with masking
The rules directories were read one after the other, each sorted on its own. udev instead sorts all files from all directories together and lets a file mask one of the same name in a lower priority directory. The difference broke both standard override idioms without a sound: copying a rules file to /etc/udev/rules.d/ to edit it left the original running too, and symlinking a name to /dev/null disabled nothing. Collect everything with glob(), drop entries shadowed by a later directory, and sort the survivors by filename, same as udev and the tmpfiles.d handling in Finit itself. The -r directory sits above /etc/ so a test ruleset can override anything shipped. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
1 parent
d23a9b8a16
commit
59945b87f7
2 files changed
+59
-37
No files matched your search
+1
-1
@@ -660,7 +660,7 @@ static int usage(int rc)
|
|||||||
" -h Show this help text\n"
|
" -h Show this help text\n"
|
||||||
" -n Run in foreground (no daemon)\n"
|
" -n Run in foreground (no daemon)\n"
|
||||||
" -p Passive mode: power supply events only (no device management)\n"
|
" -p Passive mode: power supply events only (no device management)\n"
|
||||||
" -r DIR Extra rules directory (in addition to standard udev paths)\n"
|
" -r DIR Extra rules directory, overrides the standard udev paths\n"
|
||||||
" -S Settle: wait until kernel uevent queue is quiet, then exit\n"
|
" -S Settle: wait until kernel uevent queue is quiet, then exit\n"
|
||||||
" -t SEC Settle timeout in seconds (default: 30, with -S)\n"
|
" -t SEC Settle timeout in seconds (default: 30, with -S)\n"
|
||||||
" -v Show version\n"
|
" -v Show version\n"
|
||||||
|
|||||||
+58
-36
@@ -22,10 +22,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <dirent.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <fnmatch.h>
|
#include <fnmatch.h>
|
||||||
|
#include <glob.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
@@ -50,6 +50,7 @@
|
|||||||
#include "rules.h"
|
#include "rules.h"
|
||||||
#include "sysfs.h"
|
#include "sysfs.h"
|
||||||
#include "udevdb.h"
|
#include "udevdb.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
/* ----- key-name lookup -------------------------------------------------- */
|
/* ----- key-name lookup -------------------------------------------------- */
|
||||||
|
|
||||||
@@ -347,12 +348,6 @@ static int parse_rule_line(struct rule *r, char *src)
|
|||||||
|
|
||||||
/* ----- file loading ----------------------------------------------------- */
|
/* ----- file loading ----------------------------------------------------- */
|
||||||
|
|
||||||
static int rules_dirent_filter(const struct dirent *e)
|
|
||||||
{
|
|
||||||
size_t l = strlen(e->d_name);
|
|
||||||
return l > 6 && !strcmp(e->d_name + l - 6, ".rules");
|
|
||||||
}
|
|
||||||
|
|
||||||
int rules_load(struct rule_list *list, const char *path)
|
int rules_load(struct rule_list *list, const char *path)
|
||||||
{
|
{
|
||||||
char line[2048], cont[4096];
|
char line[2048], cont[4096];
|
||||||
@@ -416,47 +411,74 @@ int rules_load(struct rule_list *list, const char *path)
|
|||||||
return nrules;
|
return nrules;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rule_file_cmp(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
return strcmp(basenm(*(char *const *)a), basenm(*(char *const *)b));
|
||||||
|
}
|
||||||
|
|
||||||
int rules_load_all(struct rule_list *list, const char *extra_dir)
|
int rules_load_all(struct rule_list *list, const char *extra_dir)
|
||||||
{
|
{
|
||||||
static const char *std_dirs[] = {
|
/*
|
||||||
|
* Like udev: a file masks one of the same name in an earlier
|
||||||
|
* (lower priority) directory, and the survivors are sorted
|
||||||
|
* together by filename, whichever directory they live in. A
|
||||||
|
* symlink to /dev/null thus disables the file it shadows.
|
||||||
|
*/
|
||||||
|
const char *dir[] = { /* in priority order, lowest first */
|
||||||
"/lib/udev/rules.d",
|
"/lib/udev/rules.d",
|
||||||
"/run/udev/rules.d",
|
"/run/udev/rules.d",
|
||||||
"/etc/udev/rules.d",
|
"/etc/udev/rules.d",
|
||||||
NULL
|
extra_dir
|
||||||
};
|
};
|
||||||
const char *dirs[8];
|
int flags = GLOB_NOESCAPE, total = 0;
|
||||||
int ndirs = 0, total = 0, d;
|
size_t i, j, nfiles = 0;
|
||||||
|
char **files;
|
||||||
|
glob_t gl;
|
||||||
|
|
||||||
for (d = 0; std_dirs[d]; d++)
|
for (i = 0; i < NELEMS(dir); i++) {
|
||||||
dirs[ndirs++] = std_dirs[d];
|
char pattern[PATH_MAX];
|
||||||
|
|
||||||
if (extra_dir)
|
if (!dir[i])
|
||||||
dirs[ndirs++] = extra_dir;
|
|
||||||
dirs[ndirs] = NULL;
|
|
||||||
|
|
||||||
for (d = 0; d < ndirs; d++) {
|
|
||||||
struct dirent **ents = NULL;
|
|
||||||
char path[PATH_MAX];
|
|
||||||
int n, i;
|
|
||||||
|
|
||||||
n = scandir(dirs[d], &ents, rules_dirent_filter, alphasort);
|
|
||||||
if (n < 0)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (i = 0; i < n; i++) {
|
snprintf(pattern, sizeof(pattern), "%s/*.rules", dir[i]);
|
||||||
int rc;
|
glob(pattern, flags, NULL, &gl);
|
||||||
|
flags |= GLOB_APPEND;
|
||||||
snprintf(path, sizeof(path), "%s/%s", dirs[d], ents[i]->d_name);
|
|
||||||
rc = rules_load(list, path);
|
|
||||||
if (rc > 0) {
|
|
||||||
logit(LOG_DEBUG, "rules: %d rules from %s", rc, path);
|
|
||||||
total += rc;
|
|
||||||
}
|
|
||||||
free(ents[i]);
|
|
||||||
}
|
|
||||||
free(ents);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
files = calloc(gl.gl_pathc, sizeof(char *));
|
||||||
|
if (!files) {
|
||||||
|
globfree(&gl);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < gl.gl_pathc; i++) {
|
||||||
|
/* masked by the same name in a later directory? */
|
||||||
|
for (j = i + 1; j < gl.gl_pathc; j++) {
|
||||||
|
if (!strcmp(basenm(gl.gl_pathv[i]), basenm(gl.gl_pathv[j])))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (j < gl.gl_pathc)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
files[nfiles++] = gl.gl_pathv[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
qsort(files, nfiles, sizeof(char *), rule_file_cmp);
|
||||||
|
|
||||||
|
for (i = 0; i < nfiles; i++) {
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = rules_load(list, files[i]);
|
||||||
|
if (rc > 0) {
|
||||||
|
logit(LOG_DEBUG, "rules: %d rules from %s", rc, files[i]);
|
||||||
|
total += rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(files);
|
||||||
|
globfree(&gl);
|
||||||
|
|
||||||
if (total)
|
if (total)
|
||||||
logit(LOG_NOTICE, "rules: %d rules loaded", total);
|
logit(LOG_NOTICE, "rules: %d rules loaded", total);
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user