Merge pull request #12700 from yuwata/udev-propagate-critical-errors
udev: modernize code and propagate critical errors
This commit is contained in:
@@ -14,6 +14,13 @@
|
||||
#include "errno-util.h"
|
||||
#include "time-util.h"
|
||||
|
||||
#define MODE_INVALID ((mode_t) -1)
|
||||
|
||||
/* The following macros add 1 when converting things, since 0 is a valid mode, while the pointer
|
||||
* NULL is special */
|
||||
#define PTR_TO_MODE(p) ((mode_t) ((uintptr_t) (p)-1))
|
||||
#define MODE_TO_PTR(u) ((void *) ((uintptr_t) (u)+1))
|
||||
|
||||
int unlink_noerrno(const char *path);
|
||||
|
||||
int rmdir_parents(const char *path, const char *stop);
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
|
||||
#include "macro.h"
|
||||
|
||||
#define MODE_INVALID ((mode_t) -1)
|
||||
|
||||
int parse_boolean(const char *v) _pure_;
|
||||
int parse_dev(const char *s, dev_t *ret);
|
||||
int parse_pid(const char *s, pid_t* ret_pid);
|
||||
|
||||
+17
-6
@@ -17,16 +17,13 @@
|
||||
|
||||
#include "strxcpyx.h"
|
||||
|
||||
size_t strpcpy(char **dest, size_t size, const char *src) {
|
||||
size_t len;
|
||||
|
||||
size_t strnpcpy(char **dest, size_t size, const char *src, size_t len) {
|
||||
assert(dest);
|
||||
assert(src);
|
||||
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
len = strlen(src);
|
||||
if (len >= size) {
|
||||
if (size > 1)
|
||||
*dest = mempcpy(*dest, src, size-1);
|
||||
@@ -40,6 +37,13 @@ size_t strpcpy(char **dest, size_t size, const char *src) {
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t strpcpy(char **dest, size_t size, const char *src) {
|
||||
assert(dest);
|
||||
assert(src);
|
||||
|
||||
return strnpcpy(dest, size, src, strlen(src));
|
||||
}
|
||||
|
||||
size_t strpcpyf(char **dest, size_t size, const char *src, ...) {
|
||||
va_list va;
|
||||
int i;
|
||||
@@ -76,14 +80,21 @@ size_t strpcpyl(char **dest, size_t size, const char *src, ...) {
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t strscpy(char *dest, size_t size, const char *src) {
|
||||
size_t strnscpy(char *dest, size_t size, const char *src, size_t len) {
|
||||
char *s;
|
||||
|
||||
assert(dest);
|
||||
assert(src);
|
||||
|
||||
s = dest;
|
||||
return strpcpy(&s, size, src);
|
||||
return strnpcpy(&s, size, src, len);
|
||||
}
|
||||
|
||||
size_t strscpy(char *dest, size_t size, const char *src) {
|
||||
assert(dest);
|
||||
assert(src);
|
||||
|
||||
return strnscpy(dest, size, src, strlen(src));
|
||||
}
|
||||
|
||||
size_t strscpyl(char *dest, size_t size, const char *src, ...) {
|
||||
|
||||
@@ -5,8 +5,10 @@
|
||||
|
||||
#include "macro.h"
|
||||
|
||||
size_t strnpcpy(char **dest, size_t size, const char *src, size_t len);
|
||||
size_t strpcpy(char **dest, size_t size, const char *src);
|
||||
size_t strpcpyf(char **dest, size_t size, const char *src, ...) _printf_(3, 4);
|
||||
size_t strpcpyl(char **dest, size_t size, const char *src, ...) _sentinel_;
|
||||
size_t strnscpy(char *dest, size_t size, const char *src, size_t len);
|
||||
size_t strscpy(char *dest, size_t size, const char *src);
|
||||
size_t strscpyl(char *dest, size_t size, const char *src, ...) _sentinel_;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include "rm-rf.h"
|
||||
#include "string-util.h"
|
||||
#include "tests.h"
|
||||
#include "udev.h"
|
||||
#include "udev-rules.h"
|
||||
|
||||
static struct fakefs {
|
||||
const char *target;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "env-file.h"
|
||||
@@ -10,7 +9,6 @@
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
#include "udev-util.h"
|
||||
#include "udev.h"
|
||||
|
||||
static const char* const resolve_name_timing_table[_RESOLVE_NAME_TIMING_MAX] = {
|
||||
[RESOLVE_NAME_NEVER] = "never",
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "signal-util.h"
|
||||
#include "string-util.h"
|
||||
#include "tests.h"
|
||||
#include "udev.h"
|
||||
#include "udev-event.h"
|
||||
|
||||
static int fake_filesystems(void) {
|
||||
static const struct fakefs {
|
||||
|
||||
@@ -18,13 +18,14 @@ udevadm_sources = files('''
|
||||
systemd_udevd_sources = files('udevd.c')
|
||||
|
||||
libudev_core_sources = '''
|
||||
udev.h
|
||||
udev-ctrl.c
|
||||
udev-ctrl.h
|
||||
udev-event.c
|
||||
udev-event.h
|
||||
udev-node.c
|
||||
udev-node.h
|
||||
udev-rules.c
|
||||
udev-rules.h
|
||||
udev-watch.c
|
||||
udev-watch.h
|
||||
udev-builtin.c
|
||||
@@ -117,7 +118,6 @@ libudev_basic = static_library(
|
||||
|
||||
libudev_static = static_library(
|
||||
'udev_static',
|
||||
'udev.h',
|
||||
include_directories : includes,
|
||||
link_with : udev_link_with,
|
||||
link_whole : libudev_basic)
|
||||
|
||||
@@ -310,7 +310,7 @@ static int builtin_blkid(sd_device *dev, int argc, char *argv[], bool test) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct udev_builtin udev_builtin_blkid = {
|
||||
const UdevBuiltin udev_builtin_blkid = {
|
||||
.name = "blkid",
|
||||
.cmd = builtin_blkid,
|
||||
.help = "Filesystem and partition probing",
|
||||
|
||||
@@ -33,7 +33,7 @@ static int builtin_btrfs(sd_device *dev, int argc, char *argv[], bool test) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct udev_builtin udev_builtin_btrfs = {
|
||||
const UdevBuiltin udev_builtin_btrfs = {
|
||||
.name = "btrfs",
|
||||
.cmd = builtin_btrfs,
|
||||
.help = "btrfs volume management",
|
||||
|
||||
@@ -208,7 +208,7 @@ static bool builtin_hwdb_validate(void) {
|
||||
return hwdb_validate(hwdb);
|
||||
}
|
||||
|
||||
const struct udev_builtin udev_builtin_hwdb = {
|
||||
const UdevBuiltin udev_builtin_hwdb = {
|
||||
.name = "hwdb",
|
||||
.cmd = builtin_hwdb,
|
||||
.init = builtin_hwdb_init,
|
||||
|
||||
@@ -357,7 +357,7 @@ static int builtin_input_id(sd_device *dev, int argc, char *argv[], bool test) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct udev_builtin udev_builtin_input_id = {
|
||||
const UdevBuiltin udev_builtin_input_id = {
|
||||
.name = "input_id",
|
||||
.cmd = builtin_input_id,
|
||||
.help = "Input device properties",
|
||||
|
||||
@@ -251,7 +251,7 @@ static int builtin_keyboard(sd_device *dev, int argc, char *argv[], bool test) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct udev_builtin udev_builtin_keyboard = {
|
||||
const UdevBuiltin udev_builtin_keyboard = {
|
||||
.name = "keyboard",
|
||||
.cmd = builtin_keyboard,
|
||||
.help = "Keyboard scan code to key mapping",
|
||||
|
||||
@@ -66,7 +66,7 @@ static bool builtin_kmod_validate(void) {
|
||||
return (kmod_validate_resources(ctx) != KMOD_RESOURCES_OK);
|
||||
}
|
||||
|
||||
const struct udev_builtin udev_builtin_kmod = {
|
||||
const UdevBuiltin udev_builtin_kmod = {
|
||||
.name = "kmod",
|
||||
.cmd = builtin_kmod,
|
||||
.init = builtin_kmod_init,
|
||||
|
||||
@@ -927,7 +927,7 @@ static int builtin_net_id(sd_device *dev, int argc, char *argv[], bool test) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct udev_builtin udev_builtin_net_id = {
|
||||
const UdevBuiltin udev_builtin_net_id = {
|
||||
.name = "net_id",
|
||||
.cmd = builtin_net_id,
|
||||
.help = "Network device properties",
|
||||
|
||||
@@ -74,7 +74,7 @@ static bool builtin_net_setup_link_validate(void) {
|
||||
return link_config_should_reload(ctx);
|
||||
}
|
||||
|
||||
const struct udev_builtin udev_builtin_net_setup_link = {
|
||||
const UdevBuiltin udev_builtin_net_setup_link = {
|
||||
.name = "net_setup_link",
|
||||
.cmd = builtin_net_setup_link,
|
||||
.init = builtin_net_setup_link_init,
|
||||
|
||||
@@ -675,7 +675,7 @@ static int builtin_path_id(sd_device *dev, int argc, char *argv[], bool test) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct udev_builtin udev_builtin_path_id = {
|
||||
const UdevBuiltin udev_builtin_path_id = {
|
||||
.name = "path_id",
|
||||
.cmd = builtin_path_id,
|
||||
.help = "Compose persistent device path",
|
||||
|
||||
@@ -73,7 +73,7 @@ finish:
|
||||
return r;
|
||||
}
|
||||
|
||||
const struct udev_builtin udev_builtin_uaccess = {
|
||||
const UdevBuiltin udev_builtin_uaccess = {
|
||||
.name = "uaccess",
|
||||
.cmd = builtin_uaccess,
|
||||
.help = "Manage device node user ACL",
|
||||
|
||||
@@ -455,7 +455,7 @@ fallback:
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct udev_builtin udev_builtin_usb_id = {
|
||||
const UdevBuiltin udev_builtin_usb_id = {
|
||||
.name = "usb_id",
|
||||
.cmd = builtin_usb_id,
|
||||
.help = "USB device properties",
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
static bool initialized;
|
||||
|
||||
static const struct udev_builtin *const builtins[_UDEV_BUILTIN_MAX] = {
|
||||
static const UdevBuiltin *const builtins[_UDEV_BUILTIN_MAX] = {
|
||||
#if HAVE_BLKID
|
||||
[UDEV_BUILTIN_BLKID] = &udev_builtin_blkid,
|
||||
#endif
|
||||
@@ -75,7 +75,7 @@ void udev_builtin_list(void) {
|
||||
fprintf(stderr, " %-14s %s\n", builtins[i]->name, builtins[i]->help);
|
||||
}
|
||||
|
||||
const char *udev_builtin_name(enum udev_builtin_cmd cmd) {
|
||||
const char *udev_builtin_name(UdevBuiltinCommand cmd) {
|
||||
assert(cmd >= 0 && cmd < _UDEV_BUILTIN_MAX);
|
||||
|
||||
if (!builtins[cmd])
|
||||
@@ -84,7 +84,7 @@ const char *udev_builtin_name(enum udev_builtin_cmd cmd) {
|
||||
return builtins[cmd]->name;
|
||||
}
|
||||
|
||||
bool udev_builtin_run_once(enum udev_builtin_cmd cmd) {
|
||||
bool udev_builtin_run_once(UdevBuiltinCommand cmd) {
|
||||
assert(cmd >= 0 && cmd < _UDEV_BUILTIN_MAX);
|
||||
|
||||
if (!builtins[cmd])
|
||||
@@ -93,8 +93,8 @@ bool udev_builtin_run_once(enum udev_builtin_cmd cmd) {
|
||||
return builtins[cmd]->run_once;
|
||||
}
|
||||
|
||||
enum udev_builtin_cmd udev_builtin_lookup(const char *command) {
|
||||
enum udev_builtin_cmd i;
|
||||
UdevBuiltinCommand udev_builtin_lookup(const char *command) {
|
||||
UdevBuiltinCommand i;
|
||||
size_t n;
|
||||
|
||||
assert(command);
|
||||
@@ -108,7 +108,7 @@ enum udev_builtin_cmd udev_builtin_lookup(const char *command) {
|
||||
return _UDEV_BUILTIN_INVALID;
|
||||
}
|
||||
|
||||
int udev_builtin_run(sd_device *dev, enum udev_builtin_cmd cmd, const char *command, bool test) {
|
||||
int udev_builtin_run(sd_device *dev, UdevBuiltinCommand cmd, const char *command, bool test) {
|
||||
_cleanup_strv_free_ char **argv = NULL;
|
||||
|
||||
assert(dev);
|
||||
|
||||
+22
-19
@@ -5,7 +5,7 @@
|
||||
|
||||
#include "sd-device.h"
|
||||
|
||||
enum udev_builtin_cmd {
|
||||
typedef enum {
|
||||
#if HAVE_BLKID
|
||||
UDEV_BUILTIN_BLKID,
|
||||
#endif
|
||||
@@ -25,9 +25,9 @@ enum udev_builtin_cmd {
|
||||
#endif
|
||||
_UDEV_BUILTIN_MAX,
|
||||
_UDEV_BUILTIN_INVALID = -1,
|
||||
};
|
||||
} UdevBuiltinCommand;
|
||||
|
||||
struct udev_builtin {
|
||||
typedef struct UdevBuiltin {
|
||||
const char *name;
|
||||
int (*cmd)(sd_device *dev, int argc, char *argv[], bool test);
|
||||
const char *help;
|
||||
@@ -35,32 +35,35 @@ struct udev_builtin {
|
||||
void (*exit)(void);
|
||||
bool (*validate)(void);
|
||||
bool run_once;
|
||||
};
|
||||
} UdevBuiltin;
|
||||
|
||||
#define PTR_TO_UDEV_BUILTIN_CMD(p) ((UdevBuiltinCommand) ((intptr_t) (p)-1))
|
||||
#define UDEV_BUILTIN_CMD_TO_PTR(u) ((void *) ((intptr_t) (u)+1))
|
||||
|
||||
#if HAVE_BLKID
|
||||
extern const struct udev_builtin udev_builtin_blkid;
|
||||
extern const UdevBuiltin udev_builtin_blkid;
|
||||
#endif
|
||||
extern const struct udev_builtin udev_builtin_btrfs;
|
||||
extern const struct udev_builtin udev_builtin_hwdb;
|
||||
extern const struct udev_builtin udev_builtin_input_id;
|
||||
extern const struct udev_builtin udev_builtin_keyboard;
|
||||
extern const UdevBuiltin udev_builtin_btrfs;
|
||||
extern const UdevBuiltin udev_builtin_hwdb;
|
||||
extern const UdevBuiltin udev_builtin_input_id;
|
||||
extern const UdevBuiltin udev_builtin_keyboard;
|
||||
#if HAVE_KMOD
|
||||
extern const struct udev_builtin udev_builtin_kmod;
|
||||
extern const UdevBuiltin udev_builtin_kmod;
|
||||
#endif
|
||||
extern const struct udev_builtin udev_builtin_net_id;
|
||||
extern const struct udev_builtin udev_builtin_net_setup_link;
|
||||
extern const struct udev_builtin udev_builtin_path_id;
|
||||
extern const struct udev_builtin udev_builtin_usb_id;
|
||||
extern const UdevBuiltin udev_builtin_net_id;
|
||||
extern const UdevBuiltin udev_builtin_net_setup_link;
|
||||
extern const UdevBuiltin udev_builtin_path_id;
|
||||
extern const UdevBuiltin udev_builtin_usb_id;
|
||||
#if HAVE_ACL
|
||||
extern const struct udev_builtin udev_builtin_uaccess;
|
||||
extern const UdevBuiltin udev_builtin_uaccess;
|
||||
#endif
|
||||
|
||||
void udev_builtin_init(void);
|
||||
void udev_builtin_exit(void);
|
||||
enum udev_builtin_cmd udev_builtin_lookup(const char *command);
|
||||
const char *udev_builtin_name(enum udev_builtin_cmd cmd);
|
||||
bool udev_builtin_run_once(enum udev_builtin_cmd cmd);
|
||||
int udev_builtin_run(sd_device *dev, enum udev_builtin_cmd cmd, const char *command, bool test);
|
||||
UdevBuiltinCommand udev_builtin_lookup(const char *command);
|
||||
const char *udev_builtin_name(UdevBuiltinCommand cmd);
|
||||
bool udev_builtin_run_once(UdevBuiltinCommand cmd);
|
||||
int udev_builtin_run(sd_device *dev, UdevBuiltinCommand cmd, const char *command, bool test);
|
||||
void udev_builtin_list(void);
|
||||
bool udev_builtin_validate(void);
|
||||
int udev_builtin_add_property(sd_device *dev, bool test, const char *key, const char *val);
|
||||
|
||||
+291
-213
@@ -16,9 +16,11 @@
|
||||
#include "device-private.h"
|
||||
#include "device-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "format-util.h"
|
||||
#include "libudev-util.h"
|
||||
#include "netlink-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "process-util.h"
|
||||
#include "rlimit-util.h"
|
||||
@@ -28,10 +30,11 @@
|
||||
#include "strv.h"
|
||||
#include "strxcpyx.h"
|
||||
#include "udev-builtin.h"
|
||||
#include "udev-event.h"
|
||||
#include "udev-node.h"
|
||||
#include "udev-util.h"
|
||||
#include "udev-watch.h"
|
||||
#include "udev.h"
|
||||
#include "user-util.h"
|
||||
|
||||
typedef struct Spawn {
|
||||
const char *cmd;
|
||||
@@ -61,6 +64,9 @@ UdevEvent *udev_event_new(sd_device *dev, usec_t exec_delay_usec, sd_netlink *rt
|
||||
.birth_usec = now(CLOCK_MONOTONIC),
|
||||
.exec_delay_usec = exec_delay_usec,
|
||||
.rtnl = sd_netlink_ref(rtnl),
|
||||
.uid = UID_INVALID,
|
||||
.gid = GID_INVALID,
|
||||
.mode = MODE_INVALID,
|
||||
};
|
||||
|
||||
return event;
|
||||
@@ -81,77 +87,171 @@ UdevEvent *udev_event_free(UdevEvent *event) {
|
||||
return mfree(event);
|
||||
}
|
||||
|
||||
enum subst_type {
|
||||
SUBST_DEVNODE,
|
||||
SUBST_ATTR,
|
||||
SUBST_ENV,
|
||||
SUBST_KERNEL,
|
||||
SUBST_KERNEL_NUMBER,
|
||||
SUBST_DRIVER,
|
||||
SUBST_DEVPATH,
|
||||
SUBST_ID,
|
||||
SUBST_MAJOR,
|
||||
SUBST_MINOR,
|
||||
SUBST_RESULT,
|
||||
SUBST_PARENT,
|
||||
SUBST_NAME,
|
||||
SUBST_LINKS,
|
||||
SUBST_ROOT,
|
||||
SUBST_SYS,
|
||||
};
|
||||
typedef enum {
|
||||
FORMAT_SUBST_DEVNODE,
|
||||
FORMAT_SUBST_ATTR,
|
||||
FORMAT_SUBST_ENV,
|
||||
FORMAT_SUBST_KERNEL,
|
||||
FORMAT_SUBST_KERNEL_NUMBER,
|
||||
FORMAT_SUBST_DRIVER,
|
||||
FORMAT_SUBST_DEVPATH,
|
||||
FORMAT_SUBST_ID,
|
||||
FORMAT_SUBST_MAJOR,
|
||||
FORMAT_SUBST_MINOR,
|
||||
FORMAT_SUBST_RESULT,
|
||||
FORMAT_SUBST_PARENT,
|
||||
FORMAT_SUBST_NAME,
|
||||
FORMAT_SUBST_LINKS,
|
||||
FORMAT_SUBST_ROOT,
|
||||
FORMAT_SUBST_SYS,
|
||||
_FORMAT_SUBST_TYPE_MAX,
|
||||
_FORMAT_SUBST_TYPE_INVALID = -1
|
||||
} FormatSubstitutionType;
|
||||
|
||||
struct subst_map_entry {
|
||||
const char *name;
|
||||
const char fmt;
|
||||
enum subst_type type;
|
||||
FormatSubstitutionType type;
|
||||
};
|
||||
|
||||
static const struct subst_map_entry map[] = {
|
||||
{ .name = "devnode", .fmt = 'N', .type = SUBST_DEVNODE },
|
||||
{ .name = "tempnode", .fmt = 'N', .type = SUBST_DEVNODE },
|
||||
{ .name = "attr", .fmt = 's', .type = SUBST_ATTR },
|
||||
{ .name = "sysfs", .fmt = 's', .type = SUBST_ATTR },
|
||||
{ .name = "env", .fmt = 'E', .type = SUBST_ENV },
|
||||
{ .name = "kernel", .fmt = 'k', .type = SUBST_KERNEL },
|
||||
{ .name = "number", .fmt = 'n', .type = SUBST_KERNEL_NUMBER },
|
||||
{ .name = "driver", .fmt = 'd', .type = SUBST_DRIVER },
|
||||
{ .name = "devpath", .fmt = 'p', .type = SUBST_DEVPATH },
|
||||
{ .name = "id", .fmt = 'b', .type = SUBST_ID },
|
||||
{ .name = "major", .fmt = 'M', .type = SUBST_MAJOR },
|
||||
{ .name = "minor", .fmt = 'm', .type = SUBST_MINOR },
|
||||
{ .name = "result", .fmt = 'c', .type = SUBST_RESULT },
|
||||
{ .name = "parent", .fmt = 'P', .type = SUBST_PARENT },
|
||||
{ .name = "name", .fmt = 'D', .type = SUBST_NAME },
|
||||
{ .name = "links", .fmt = 'L', .type = SUBST_LINKS },
|
||||
{ .name = "root", .fmt = 'r', .type = SUBST_ROOT },
|
||||
{ .name = "sys", .fmt = 'S', .type = SUBST_SYS },
|
||||
{ .name = "devnode", .fmt = 'N', .type = FORMAT_SUBST_DEVNODE },
|
||||
{ .name = "tempnode", .fmt = 'N', .type = FORMAT_SUBST_DEVNODE }, /* deprecated */
|
||||
{ .name = "attr", .fmt = 's', .type = FORMAT_SUBST_ATTR },
|
||||
{ .name = "sysfs", .fmt = 's', .type = FORMAT_SUBST_ATTR }, /* deprecated */
|
||||
{ .name = "env", .fmt = 'E', .type = FORMAT_SUBST_ENV },
|
||||
{ .name = "kernel", .fmt = 'k', .type = FORMAT_SUBST_KERNEL },
|
||||
{ .name = "number", .fmt = 'n', .type = FORMAT_SUBST_KERNEL_NUMBER },
|
||||
{ .name = "driver", .fmt = 'd', .type = FORMAT_SUBST_DRIVER },
|
||||
{ .name = "devpath", .fmt = 'p', .type = FORMAT_SUBST_DEVPATH },
|
||||
{ .name = "id", .fmt = 'b', .type = FORMAT_SUBST_ID },
|
||||
{ .name = "major", .fmt = 'M', .type = FORMAT_SUBST_MAJOR },
|
||||
{ .name = "minor", .fmt = 'm', .type = FORMAT_SUBST_MINOR },
|
||||
{ .name = "result", .fmt = 'c', .type = FORMAT_SUBST_RESULT },
|
||||
{ .name = "parent", .fmt = 'P', .type = FORMAT_SUBST_PARENT },
|
||||
{ .name = "name", .fmt = 'D', .type = FORMAT_SUBST_NAME },
|
||||
{ .name = "links", .fmt = 'L', .type = FORMAT_SUBST_LINKS },
|
||||
{ .name = "root", .fmt = 'r', .type = FORMAT_SUBST_ROOT },
|
||||
{ .name = "sys", .fmt = 'S', .type = FORMAT_SUBST_SYS },
|
||||
};
|
||||
|
||||
static ssize_t subst_format_var(UdevEvent *event,
|
||||
const struct subst_map_entry *entry, char *attr,
|
||||
char *dest, size_t l) {
|
||||
static const char *format_type_to_string(FormatSubstitutionType t) {
|
||||
for (size_t i = 0; i < ELEMENTSOF(map); i++)
|
||||
if (map[i].type == t)
|
||||
return map[i].name;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char format_type_to_char(FormatSubstitutionType t) {
|
||||
for (size_t i = 0; i < ELEMENTSOF(map); i++)
|
||||
if (map[i].type == t)
|
||||
return map[i].fmt;
|
||||
return '\0';
|
||||
}
|
||||
|
||||
static int get_subst_type(const char **str, bool strict, FormatSubstitutionType *ret_type, char ret_attr[static UTIL_PATH_SIZE]) {
|
||||
const char *p = *str, *q = NULL;
|
||||
size_t i;
|
||||
|
||||
assert(str);
|
||||
assert(*str);
|
||||
assert(ret_type);
|
||||
|
||||
if (p[0] == '$') {
|
||||
p++;
|
||||
if (p[0] == '$') {
|
||||
*str = p;
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < ELEMENTSOF(map); i++)
|
||||
if ((q = startswith(p, map[i].name)))
|
||||
break;
|
||||
} else if (p[0] == '%') {
|
||||
p++;
|
||||
if (p[0] == '%') {
|
||||
*str = p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(map); i++)
|
||||
if (p[0] == map[i].fmt) {
|
||||
q = p + 1;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
return 0;
|
||||
if (!q)
|
||||
/* When 'strict' flag is set, then '$' and '%' must be escaped. */
|
||||
return strict ? -EINVAL : 0;
|
||||
|
||||
if (q[0] == '{') {
|
||||
const char *start, *end;
|
||||
size_t len;
|
||||
|
||||
start = q + 1;
|
||||
end = strchr(start, '}');
|
||||
if (!end)
|
||||
return -EINVAL;
|
||||
|
||||
len = end - start;
|
||||
if (len == 0 || len >= UTIL_PATH_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
strnscpy(ret_attr, UTIL_PATH_SIZE, start, len);
|
||||
q = end + 1;
|
||||
} else
|
||||
ret_attr[0] = '\0';
|
||||
|
||||
*str = q;
|
||||
*ret_type = map[i].type;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int safe_atou_optional_plus(const char *s, unsigned *ret) {
|
||||
const char *p;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(ret);
|
||||
|
||||
/* Returns 1 if plus, 0 if no plus, negative on error */
|
||||
|
||||
p = endswith(s, "+");
|
||||
if (p)
|
||||
s = strndupa(s, p - s);
|
||||
|
||||
r = safe_atou(s, ret);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return !!p;
|
||||
}
|
||||
|
||||
static ssize_t udev_event_subst_format(
|
||||
UdevEvent *event,
|
||||
FormatSubstitutionType type,
|
||||
const char *attr,
|
||||
char *dest,
|
||||
size_t l) {
|
||||
sd_device *parent, *dev = event->dev;
|
||||
const char *val = NULL;
|
||||
char *s = dest;
|
||||
dev_t devnum;
|
||||
int r;
|
||||
|
||||
assert(entry);
|
||||
|
||||
switch (entry->type) {
|
||||
case SUBST_DEVPATH:
|
||||
switch (type) {
|
||||
case FORMAT_SUBST_DEVPATH:
|
||||
r = sd_device_get_devpath(dev, &val);
|
||||
if (r < 0)
|
||||
return r;
|
||||
l = strpcpy(&s, l, val);
|
||||
break;
|
||||
case SUBST_KERNEL:
|
||||
case FORMAT_SUBST_KERNEL:
|
||||
r = sd_device_get_sysname(dev, &val);
|
||||
if (r < 0)
|
||||
return r;
|
||||
l = strpcpy(&s, l, val);
|
||||
break;
|
||||
case SUBST_KERNEL_NUMBER:
|
||||
case FORMAT_SUBST_KERNEL_NUMBER:
|
||||
r = sd_device_get_sysnum(dev, &val);
|
||||
if (r == -ENOENT)
|
||||
goto null_terminate;
|
||||
@@ -159,7 +259,7 @@ static ssize_t subst_format_var(UdevEvent *event,
|
||||
return r;
|
||||
l = strpcpy(&s, l, val);
|
||||
break;
|
||||
case SUBST_ID:
|
||||
case FORMAT_SUBST_ID:
|
||||
if (!event->dev_parent)
|
||||
goto null_terminate;
|
||||
r = sd_device_get_sysname(event->dev_parent, &val);
|
||||
@@ -167,7 +267,7 @@ static ssize_t subst_format_var(UdevEvent *event,
|
||||
return r;
|
||||
l = strpcpy(&s, l, val);
|
||||
break;
|
||||
case SUBST_DRIVER:
|
||||
case FORMAT_SUBST_DRIVER:
|
||||
if (!event->dev_parent)
|
||||
goto null_terminate;
|
||||
r = sd_device_get_driver(event->dev_parent, &val);
|
||||
@@ -177,63 +277,68 @@ static ssize_t subst_format_var(UdevEvent *event,
|
||||
return r;
|
||||
l = strpcpy(&s, l, val);
|
||||
break;
|
||||
case SUBST_MAJOR:
|
||||
case SUBST_MINOR: {
|
||||
char buf[DECIMAL_STR_MAX(unsigned)];
|
||||
case FORMAT_SUBST_MAJOR:
|
||||
case FORMAT_SUBST_MINOR: {
|
||||
dev_t devnum;
|
||||
|
||||
r = sd_device_get_devnum(dev, &devnum);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
xsprintf(buf, "%u", r < 0 ? 0 : entry->type == SUBST_MAJOR ? major(devnum) : minor(devnum));
|
||||
l = strpcpy(&s, l, buf);
|
||||
l = strpcpyf(&s, l, "%u", r < 0 ? 0 : type == FORMAT_SUBST_MAJOR ? major(devnum) : minor(devnum));
|
||||
break;
|
||||
}
|
||||
case SUBST_RESULT: {
|
||||
char *rest;
|
||||
int i;
|
||||
case FORMAT_SUBST_RESULT: {
|
||||
unsigned index = 0; /* 0 means whole string */
|
||||
bool has_plus;
|
||||
|
||||
if (!event->program_result)
|
||||
goto null_terminate;
|
||||
|
||||
/* get part of the result string */
|
||||
i = 0;
|
||||
if (attr)
|
||||
i = strtoul(attr, &rest, 10);
|
||||
if (i > 0) {
|
||||
char result[UTIL_PATH_SIZE], tmp[UTIL_PATH_SIZE], *cpos;
|
||||
if (!isempty(attr)) {
|
||||
r = safe_atou_optional_plus(attr, &index);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
strscpy(result, sizeof(result), event->program_result);
|
||||
cpos = result;
|
||||
while (--i) {
|
||||
while (cpos[0] != '\0' && !isspace(cpos[0]))
|
||||
cpos++;
|
||||
while (isspace(cpos[0]))
|
||||
cpos++;
|
||||
if (cpos[0] == '\0')
|
||||
has_plus = r;
|
||||
}
|
||||
|
||||
if (index == 0)
|
||||
l = strpcpy(&s, l, event->program_result);
|
||||
else {
|
||||
const char *start, *p;
|
||||
unsigned i;
|
||||
|
||||
p = skip_leading_chars(event->program_result, NULL);
|
||||
|
||||
for (i = 1; i < index; i++) {
|
||||
while (p[0] != '\0' && !strchr(WHITESPACE, p[0]))
|
||||
p++;
|
||||
p = skip_leading_chars(p, NULL);
|
||||
if (*p == '\0')
|
||||
break;
|
||||
}
|
||||
if (i > 0) {
|
||||
log_error("requested part of result string not found");
|
||||
break;
|
||||
if (i != index) {
|
||||
log_device_debug(dev, "requested part of result string not found");
|
||||
goto null_terminate;
|
||||
}
|
||||
strscpy(tmp, sizeof(tmp), cpos);
|
||||
/* %{2+}c copies the whole string from the second part on */
|
||||
if (rest[0] != '+') {
|
||||
cpos = strchr(tmp, ' ');
|
||||
if (cpos)
|
||||
cpos[0] = '\0';
|
||||
|
||||
start = p;
|
||||
/* %c{2+} copies the whole string from the second part on */
|
||||
if (has_plus)
|
||||
l = strpcpy(&s, l, start);
|
||||
else {
|
||||
while (p[0] != '\0' && !strchr(WHITESPACE, p[0]))
|
||||
p++;
|
||||
l = strnpcpy(&s, l, start, p - start);
|
||||
}
|
||||
l = strpcpy(&s, l, tmp);
|
||||
} else
|
||||
l = strpcpy(&s, l, event->program_result);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SUBST_ATTR: {
|
||||
case FORMAT_SUBST_ATTR: {
|
||||
char vbuf[UTIL_NAME_SIZE];
|
||||
size_t len;
|
||||
int count;
|
||||
|
||||
if (!attr)
|
||||
if (isempty(attr))
|
||||
return -EINVAL;
|
||||
|
||||
/* try to read the value specified by "[dmi/id]product_name" */
|
||||
@@ -254,16 +359,14 @@ static ssize_t subst_format_var(UdevEvent *event,
|
||||
/* strip trailing whitespace, and replace unwanted characters */
|
||||
if (val != vbuf)
|
||||
strscpy(vbuf, sizeof(vbuf), val);
|
||||
len = strlen(vbuf);
|
||||
while (len > 0 && isspace(vbuf[--len]))
|
||||
vbuf[len] = '\0';
|
||||
delete_trailing_chars(vbuf, NULL);
|
||||
count = util_replace_chars(vbuf, UDEV_ALLOWED_CHARS_INPUT);
|
||||
if (count > 0)
|
||||
log_device_debug(dev, "%i character(s) replaced", count);
|
||||
l = strpcpy(&s, l, vbuf);
|
||||
break;
|
||||
}
|
||||
case SUBST_PARENT:
|
||||
case FORMAT_SUBST_PARENT:
|
||||
r = sd_device_get_parent(dev, &parent);
|
||||
if (r == -ENODEV)
|
||||
goto null_terminate;
|
||||
@@ -276,7 +379,7 @@ static ssize_t subst_format_var(UdevEvent *event,
|
||||
return r;
|
||||
l = strpcpy(&s, l, val + STRLEN("/dev/"));
|
||||
break;
|
||||
case SUBST_DEVNODE:
|
||||
case FORMAT_SUBST_DEVNODE:
|
||||
r = sd_device_get_devname(dev, &val);
|
||||
if (r == -ENOENT)
|
||||
goto null_terminate;
|
||||
@@ -284,7 +387,7 @@ static ssize_t subst_format_var(UdevEvent *event,
|
||||
return r;
|
||||
l = strpcpy(&s, l, val);
|
||||
break;
|
||||
case SUBST_NAME:
|
||||
case FORMAT_SUBST_NAME:
|
||||
if (event->name)
|
||||
l = strpcpy(&s, l, event->name);
|
||||
else if (sd_device_get_devname(dev, &val) >= 0)
|
||||
@@ -296,7 +399,7 @@ static ssize_t subst_format_var(UdevEvent *event,
|
||||
l = strpcpy(&s, l, val);
|
||||
}
|
||||
break;
|
||||
case SUBST_LINKS:
|
||||
case FORMAT_SUBST_LINKS:
|
||||
FOREACH_DEVICE_DEVLINK(dev, val)
|
||||
if (s == dest)
|
||||
l = strpcpy(&s, l, val + STRLEN("/dev/"));
|
||||
@@ -305,15 +408,15 @@ static ssize_t subst_format_var(UdevEvent *event,
|
||||
if (s == dest)
|
||||
goto null_terminate;
|
||||
break;
|
||||
case SUBST_ROOT:
|
||||
case FORMAT_SUBST_ROOT:
|
||||
l = strpcpy(&s, l, "/dev");
|
||||
break;
|
||||
case SUBST_SYS:
|
||||
case FORMAT_SUBST_SYS:
|
||||
l = strpcpy(&s, l, "/sys");
|
||||
break;
|
||||
case SUBST_ENV:
|
||||
if (!attr)
|
||||
goto null_terminate;
|
||||
case FORMAT_SUBST_ENV:
|
||||
if (isempty(attr))
|
||||
return -EINVAL;
|
||||
r = sd_device_get_property_value(dev, attr, &val);
|
||||
if (r == -ENOENT)
|
||||
goto null_terminate;
|
||||
@@ -335,9 +438,8 @@ null_terminate:
|
||||
ssize_t udev_event_apply_format(UdevEvent *event,
|
||||
const char *src, char *dest, size_t size,
|
||||
bool replace_whitespace) {
|
||||
const char *from;
|
||||
char *s;
|
||||
size_t l;
|
||||
const char *s = src;
|
||||
int r;
|
||||
|
||||
assert(event);
|
||||
assert(event->dev);
|
||||
@@ -345,108 +447,70 @@ ssize_t udev_event_apply_format(UdevEvent *event,
|
||||
assert(dest);
|
||||
assert(size > 0);
|
||||
|
||||
from = src;
|
||||
s = dest;
|
||||
l = size;
|
||||
|
||||
for (;;) {
|
||||
const struct subst_map_entry *entry = NULL;
|
||||
char attrbuf[UTIL_PATH_SIZE], *attr;
|
||||
bool format_dollar = false;
|
||||
while (s[0] != '\0') {
|
||||
FormatSubstitutionType type;
|
||||
char attr[UTIL_PATH_SIZE];
|
||||
ssize_t subst_len;
|
||||
|
||||
while (from[0] != '\0') {
|
||||
if (from[0] == '$') {
|
||||
/* substitute named variable */
|
||||
unsigned i;
|
||||
|
||||
if (from[1] == '$') {
|
||||
from++;
|
||||
goto copy;
|
||||
}
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(map); i++) {
|
||||
if (startswith(&from[1], map[i].name)) {
|
||||
entry = &map[i];
|
||||
from += strlen(map[i].name)+1;
|
||||
format_dollar = true;
|
||||
goto subst;
|
||||
}
|
||||
}
|
||||
} else if (from[0] == '%') {
|
||||
/* substitute format char */
|
||||
unsigned i;
|
||||
|
||||
if (from[1] == '%') {
|
||||
from++;
|
||||
goto copy;
|
||||
}
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(map); i++) {
|
||||
if (from[1] == map[i].fmt) {
|
||||
entry = &map[i];
|
||||
from += 2;
|
||||
goto subst;
|
||||
}
|
||||
}
|
||||
}
|
||||
copy:
|
||||
/* copy char */
|
||||
if (l < 2) /* need space for this char and the terminating NUL */
|
||||
goto out;
|
||||
s[0] = from[0];
|
||||
from++;
|
||||
s++;
|
||||
l--;
|
||||
}
|
||||
|
||||
goto out;
|
||||
subst:
|
||||
/* extract possible $format{attr} */
|
||||
if (from[0] == '{') {
|
||||
unsigned i;
|
||||
|
||||
from++;
|
||||
for (i = 0; from[i] != '}'; i++)
|
||||
if (from[i] == '\0') {
|
||||
log_error("missing closing brace for format '%s'", src);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (i >= sizeof(attrbuf))
|
||||
goto out;
|
||||
memcpy(attrbuf, from, i);
|
||||
attrbuf[i] = '\0';
|
||||
from += i+1;
|
||||
attr = attrbuf;
|
||||
} else
|
||||
attr = NULL;
|
||||
|
||||
subst_len = subst_format_var(event, entry, attr, s, l);
|
||||
if (subst_len < 0) {
|
||||
if (format_dollar)
|
||||
log_device_warning_errno(event->dev, subst_len, "Failed to substitute variable '$%s', ignoring: %m", entry->name);
|
||||
else
|
||||
log_device_warning_errno(event->dev, subst_len, "Failed to apply format '%%%c', ignoring: %m", entry->fmt);
|
||||
|
||||
r = get_subst_type(&s, false, &type, attr);
|
||||
if (r < 0)
|
||||
return log_device_warning_errno(event->dev, r, "Invalid format string, ignoring: %s", src);
|
||||
if (r == 0) {
|
||||
if (size < 2) /* need space for this char and the terminating NUL */
|
||||
break;
|
||||
*dest++ = *s++;
|
||||
size--;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* SUBST_RESULT handles spaces itself */
|
||||
if (replace_whitespace && entry->type != SUBST_RESULT)
|
||||
/* util_replace_whitespace can replace in-place,
|
||||
* and does nothing if subst_len == 0
|
||||
*/
|
||||
subst_len = util_replace_whitespace(s, s, subst_len);
|
||||
subst_len = udev_event_subst_format(event, type, attr, dest, size);
|
||||
if (subst_len < 0)
|
||||
return log_device_warning_errno(event->dev, subst_len,
|
||||
"Failed to substitute variable '$%s' or apply format '%%%c', ignoring: %m",
|
||||
format_type_to_string(type), format_type_to_char(type));
|
||||
|
||||
s += subst_len;
|
||||
l -= subst_len;
|
||||
/* FORMAT_SUBST_RESULT handles spaces itself */
|
||||
if (replace_whitespace && type != FORMAT_SUBST_RESULT)
|
||||
/* util_replace_whitespace can replace in-place,
|
||||
* and does nothing if subst_len == 0 */
|
||||
subst_len = util_replace_whitespace(dest, dest, subst_len);
|
||||
|
||||
dest += subst_len;
|
||||
size -= subst_len;
|
||||
}
|
||||
|
||||
out:
|
||||
assert(l >= 1);
|
||||
s[0] = '\0';
|
||||
return l;
|
||||
assert(size >= 1);
|
||||
dest[0] = '\0';
|
||||
return size;
|
||||
}
|
||||
|
||||
int udev_check_format(const char *s) {
|
||||
FormatSubstitutionType type;
|
||||
char attr[UTIL_PATH_SIZE];
|
||||
int r;
|
||||
|
||||
while (s[0] != '\0') {
|
||||
r = get_subst_type(&s, true, &type, attr);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
s++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IN_SET(type, FORMAT_SUBST_ATTR, FORMAT_SUBST_ENV) && isempty(attr))
|
||||
return -EINVAL;
|
||||
|
||||
if (type == FORMAT_SUBST_RESULT && !isempty(attr)) {
|
||||
unsigned i;
|
||||
|
||||
r = safe_atou_optional_plus(attr, &i);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int on_spawn_io(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
||||
@@ -753,19 +817,23 @@ static int update_devnode(UdevEvent *event) {
|
||||
if (event->dev_db_clone)
|
||||
(void) udev_node_update_old_links(dev, event->dev_db_clone);
|
||||
|
||||
if (!event->owner_set) {
|
||||
if (!uid_is_valid(event->uid)) {
|
||||
r = device_get_devnode_uid(dev, &event->uid);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
if (r == -ENOENT)
|
||||
event->uid = 0;
|
||||
else if (r < 0)
|
||||
return log_device_error_errno(dev, r, "Failed to get devnode UID: %m");
|
||||
}
|
||||
|
||||
if (!event->group_set) {
|
||||
if (!gid_is_valid(event->gid)) {
|
||||
r = device_get_devnode_gid(dev, &event->gid);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
if (r == -ENOENT)
|
||||
event->gid = 0;
|
||||
else if (r < 0)
|
||||
return log_device_error_errno(dev, r, "Failed to get devnode GID: %m");
|
||||
}
|
||||
|
||||
if (!event->mode_set) {
|
||||
if (event->mode == MODE_INVALID) {
|
||||
r = device_get_devnode_mode(dev, &event->mode);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return log_device_error_errno(dev, r, "Failed to get devnode mode: %m");
|
||||
@@ -779,7 +847,10 @@ static int update_devnode(UdevEvent *event) {
|
||||
}
|
||||
}
|
||||
|
||||
apply = device_for_action(dev, DEVICE_ACTION_ADD) || event->owner_set || event->group_set || event->mode_set;
|
||||
apply = device_for_action(dev, DEVICE_ACTION_ADD) ||
|
||||
uid_is_valid(event->uid) ||
|
||||
gid_is_valid(event->gid) ||
|
||||
event->mode != MODE_INVALID;
|
||||
return udev_node_add(dev, apply, event->mode, event->uid, event->gid, event->seclabel_list);
|
||||
}
|
||||
|
||||
@@ -897,25 +968,32 @@ int udev_event_execute_rules(UdevEvent *event,
|
||||
}
|
||||
|
||||
void udev_event_execute_run(UdevEvent *event, usec_t timeout_usec) {
|
||||
const char *cmd;
|
||||
const char *command;
|
||||
void *val;
|
||||
Iterator i;
|
||||
int r;
|
||||
|
||||
ORDERED_HASHMAP_FOREACH_KEY(val, cmd, event->run_list, i) {
|
||||
enum udev_builtin_cmd builtin_cmd = PTR_TO_INT(val);
|
||||
char command[UTIL_PATH_SIZE];
|
||||
ORDERED_HASHMAP_FOREACH_KEY(val, command, event->run_list, i) {
|
||||
UdevBuiltinCommand builtin_cmd = PTR_TO_UDEV_BUILTIN_CMD(val);
|
||||
|
||||
udev_event_apply_format(event, cmd, command, sizeof(command), false);
|
||||
|
||||
if (builtin_cmd >= 0 && builtin_cmd < _UDEV_BUILTIN_MAX)
|
||||
udev_builtin_run(event->dev, builtin_cmd, command, false);
|
||||
else {
|
||||
if (builtin_cmd != _UDEV_BUILTIN_INVALID) {
|
||||
log_device_debug(event->dev, "Running built-in command \"%s\"", command);
|
||||
r = udev_builtin_run(event->dev, builtin_cmd, command, false);
|
||||
if (r < 0)
|
||||
log_device_debug_errno(event->dev, r, "Failed to run built-in command \"%s\", ignoring: %m", command);
|
||||
} else {
|
||||
if (event->exec_delay_usec > 0) {
|
||||
log_debug("delay execution of '%s'", command);
|
||||
char buf[FORMAT_TIMESPAN_MAX];
|
||||
|
||||
log_device_debug(event->dev, "Delaying execution of \"%s\" for %s.",
|
||||
command, format_timespan(buf, sizeof(buf), event->exec_delay_usec, USEC_PER_SEC));
|
||||
(void) usleep(event->exec_delay_usec);
|
||||
}
|
||||
|
||||
(void) udev_event_spawn(event, timeout_usec, false, command, NULL, 0);
|
||||
log_device_debug(event->dev, "Running command \"%s\"", command);
|
||||
r = udev_event_spawn(event, timeout_usec, false, command, NULL, 0);
|
||||
if (r > 0) /* returned value is positive when program fails */
|
||||
log_device_debug(event->dev, "Command \"%s\" returned %d (error), ignoring.", command, r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "hashmap.h"
|
||||
#include "macro.h"
|
||||
#include "udev-rules.h"
|
||||
#include "udev-util.h"
|
||||
#include "util.h"
|
||||
|
||||
@@ -32,41 +33,25 @@ typedef struct UdevEvent {
|
||||
sd_netlink *rtnl;
|
||||
unsigned builtin_run;
|
||||
unsigned builtin_ret;
|
||||
bool inotify_watch;
|
||||
bool inotify_watch_final;
|
||||
bool group_set;
|
||||
bool group_final;
|
||||
bool owner_set;
|
||||
bool owner_final;
|
||||
bool mode_set;
|
||||
bool mode_final;
|
||||
bool name_final;
|
||||
bool devlink_final;
|
||||
bool run_final;
|
||||
UdevRuleEscapeType esc:8;
|
||||
bool inotify_watch:1;
|
||||
bool inotify_watch_final:1;
|
||||
bool group_final:1;
|
||||
bool owner_final:1;
|
||||
bool mode_final:1;
|
||||
bool name_final:1;
|
||||
bool devlink_final:1;
|
||||
bool run_final:1;
|
||||
} UdevEvent;
|
||||
|
||||
/* udev-rules.c */
|
||||
typedef struct UdevRules UdevRules;
|
||||
|
||||
int udev_rules_new(UdevRules **ret_rules, ResolveNameTiming resolve_name_timing);
|
||||
UdevRules *udev_rules_free(UdevRules *rules);
|
||||
|
||||
bool udev_rules_check_timestamp(UdevRules *rules);
|
||||
int udev_rules_apply_to_event(UdevRules *rules, UdevEvent *event,
|
||||
usec_t timeout_usec,
|
||||
Hashmap *properties_list);
|
||||
int udev_rules_apply_static_dev_perms(UdevRules *rules);
|
||||
|
||||
static inline usec_t udev_warn_timeout(usec_t timeout_usec) {
|
||||
return DIV_ROUND_UP(timeout_usec, 3);
|
||||
}
|
||||
|
||||
/* udev-event.c */
|
||||
UdevEvent *udev_event_new(sd_device *dev, usec_t exec_delay_usec, sd_netlink *rtnl);
|
||||
UdevEvent *udev_event_free(UdevEvent *event);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(UdevEvent*, udev_event_free);
|
||||
|
||||
ssize_t udev_event_apply_format(UdevEvent *event,
|
||||
const char *src, char *dest, size_t size,
|
||||
bool replace_whitespace);
|
||||
int udev_check_format(const char *s);
|
||||
int udev_event_spawn(UdevEvent *event,
|
||||
usec_t timeout_usec,
|
||||
bool accept_failure,
|
||||
@@ -77,6 +62,6 @@ int udev_event_execute_rules(UdevEvent *event,
|
||||
UdevRules *rules);
|
||||
void udev_event_execute_run(UdevEvent *event, usec_t timeout_usec);
|
||||
|
||||
/* Cleanup functions */
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(UdevEvent*, udev_event_free);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(UdevRules*, udev_rules_free);
|
||||
static inline usec_t udev_warn_timeout(usec_t timeout_usec) {
|
||||
return DIV_ROUND_UP(timeout_usec, 3);
|
||||
}
|
||||
+1894
-2381
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,226 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
#pragma once
|
||||
|
||||
#include "device-util.h"
|
||||
#include "hashmap.h"
|
||||
#include "list.h"
|
||||
#include "time-util.h"
|
||||
#include "udev-util.h"
|
||||
|
||||
typedef struct UdevRules UdevRules;
|
||||
typedef struct UdevRuleFile UdevRuleFile;
|
||||
typedef struct UdevRuleLine UdevRuleLine;
|
||||
typedef struct UdevRuleToken UdevRuleToken;
|
||||
typedef struct UdevEvent UdevEvent;
|
||||
|
||||
typedef enum {
|
||||
OP_MATCH, /* == */
|
||||
OP_NOMATCH, /* != */
|
||||
OP_ADD, /* += */
|
||||
OP_REMOVE, /* -= */
|
||||
OP_ASSIGN, /* = */
|
||||
OP_ASSIGN_FINAL, /* := */
|
||||
_OP_TYPE_MAX,
|
||||
_OP_TYPE_INVALID = -1
|
||||
} UdevRuleOperatorType;
|
||||
|
||||
typedef enum {
|
||||
MATCH_TYPE_EMPTY, /* empty string */
|
||||
MATCH_TYPE_PLAIN, /* no special characters */
|
||||
MATCH_TYPE_GLOB, /* shell globs ?,*,[] */
|
||||
MATCH_TYPE_SUBSYSTEM, /* "subsystem", "bus", or "class" */
|
||||
_MATCH_TYPE_MAX,
|
||||
_MATCH_TYPE_INVALID = -1
|
||||
} UdevRuleMatchType;
|
||||
|
||||
typedef enum {
|
||||
SUBST_TYPE_PLAIN, /* no substitution */
|
||||
SUBST_TYPE_FORMAT, /* % or $ */
|
||||
SUBST_TYPE_SUBSYS, /* "[<SUBSYSTEM>/<KERNEL>]<attribute>" format */
|
||||
_SUBST_TYPE_MAX,
|
||||
_SUBST_TYPE_INVALID = -1
|
||||
} UdevRuleSubstituteType;
|
||||
|
||||
typedef enum {
|
||||
ESCAPE_UNSET,
|
||||
ESCAPE_NONE, /* OPTIONS="string_escape=none" */
|
||||
ESCAPE_REPLACE, /* OPTIONS="string_escape=replace" */
|
||||
_ESCAPE_TYPE_MAX,
|
||||
_ESCAPE_TYPE_INVALID = -1
|
||||
} UdevRuleEscapeType;
|
||||
|
||||
typedef enum {
|
||||
/* lvalues which take match or nomatch operator */
|
||||
TK_M_ACTION, /* string, device_get_action() */
|
||||
TK_M_DEVPATH, /* path, sd_device_get_devpath() */
|
||||
TK_M_KERNEL, /* string, sd_device_get_sysname() */
|
||||
TK_M_DEVLINK, /* strv, sd_device_get_devlink_first(), sd_device_get_devlink_next() */
|
||||
TK_M_NAME, /* string, name of network interface */
|
||||
TK_M_ENV, /* string, device property, takes key through attribute */
|
||||
TK_M_TAG, /* strv, sd_device_get_tag_first(), sd_device_get_tag_next() */
|
||||
TK_M_SUBSYSTEM, /* string, sd_device_get_subsystem() */
|
||||
TK_M_DRIVER, /* string, sd_device_get_driver() */
|
||||
TK_M_ATTR, /* string, takes filename through attribute, sd_device_get_sysattr_value(), util_resolve_subsys_kernel(), etc. */
|
||||
TK_M_SYSCTL, /* string, takes kernel parameter through attribute */
|
||||
|
||||
/* matches parent paramters */
|
||||
TK_M_PARENTS_KERNEL, /* string */
|
||||
TK_M_PARENTS_SUBSYSTEM, /* string */
|
||||
TK_M_PARENTS_DRIVER, /* string */
|
||||
TK_M_PARENTS_ATTR, /* string */
|
||||
TK_M_PARENTS_TAG, /* strv */
|
||||
|
||||
TK_M_TEST, /* path, optionally mode_t can be specified by attribute, test the existence of a file */
|
||||
TK_M_PROGRAM, /* string, execute a program */
|
||||
TK_M_IMPORT_FILE, /* path */
|
||||
TK_M_IMPORT_PROGRAM, /* string, import properties from the result of program */
|
||||
TK_M_IMPORT_BUILTIN, /* string, import properties from the result of built-in command */
|
||||
TK_M_IMPORT_DB, /* string, import properties from database */
|
||||
TK_M_IMPORT_CMDLINE, /* string, kernel command line */
|
||||
TK_M_IMPORT_PARENT, /* string, parent property */
|
||||
TK_M_RESULT, /* string, result of TK_M_PROGRAM */
|
||||
|
||||
#define _TK_M_MAX (TK_M_RESULT + 1)
|
||||
#define _TK_A_MIN _TK_M_MAX
|
||||
|
||||
/* lvalues which take one of assign operators */
|
||||
TK_A_OPTIONS_STRING_ESCAPE_NONE, /* no argument */
|
||||
TK_A_OPTIONS_STRING_ESCAPE_REPLACE, /* no argument */
|
||||
TK_A_OPTIONS_DB_PERSIST, /* no argument */
|
||||
TK_A_OPTIONS_INOTIFY_WATCH, /* boolean */
|
||||
TK_A_OPTIONS_DEVLINK_PRIORITY, /* int */
|
||||
TK_A_OWNER, /* user name */
|
||||
TK_A_GROUP, /* group name */
|
||||
TK_A_MODE, /* mode string */
|
||||
TK_A_OWNER_ID, /* uid_t */
|
||||
TK_A_GROUP_ID, /* gid_t */
|
||||
TK_A_MODE_ID, /* mode_t */
|
||||
TK_A_TAG, /* string */
|
||||
TK_A_OPTIONS_STATIC_NODE, /* device path, /dev/... */
|
||||
TK_A_SECLABEL, /* string with attribute */
|
||||
TK_A_ENV, /* string with attribute */
|
||||
TK_A_NAME, /* ifname */
|
||||
TK_A_DEVLINK, /* string */
|
||||
TK_A_ATTR, /* string with attribute */
|
||||
TK_A_SYSCTL, /* string with attribute */
|
||||
TK_A_RUN_BUILTIN, /* string */
|
||||
TK_A_RUN_PROGRAM, /* string */
|
||||
|
||||
_TK_TYPE_MAX,
|
||||
_TK_TYPE_INVALID = -1,
|
||||
} UdevRuleTokenType;
|
||||
|
||||
typedef enum {
|
||||
LINE_HAS_NAME = 1 << 0, /* has NAME= */
|
||||
LINE_HAS_DEVLINK = 1 << 1, /* has SYMLINK=, OWNER=, GROUP= or MODE= */
|
||||
LINE_HAS_STATIC_NODE = 1 << 2, /* has OPTIONS=static_node */
|
||||
LINE_HAS_GOTO = 1 << 3, /* has GOTO= */
|
||||
LINE_HAS_LABEL = 1 << 4, /* has LABEL= */
|
||||
LINE_UPDATE_SOMETHING = 1 << 5, /* has other TK_A_* or TK_M_IMPORT tokens */
|
||||
} UdevRuleLineType;
|
||||
|
||||
struct UdevRuleToken {
|
||||
UdevRuleTokenType type:8;
|
||||
UdevRuleOperatorType op:8;
|
||||
UdevRuleMatchType match_type:8;
|
||||
UdevRuleSubstituteType attr_subst_type:7;
|
||||
bool attr_match_remove_trailing_whitespace:1;
|
||||
const char *value;
|
||||
void *data;
|
||||
LIST_FIELDS(UdevRuleToken, tokens);
|
||||
};
|
||||
|
||||
struct UdevRuleLine {
|
||||
char *line;
|
||||
unsigned line_number;
|
||||
UdevRuleLineType type;
|
||||
|
||||
const char *label;
|
||||
const char *goto_label;
|
||||
UdevRuleLine *goto_line;
|
||||
|
||||
UdevRuleFile *rule_file;
|
||||
UdevRuleToken *current_token;
|
||||
LIST_HEAD(UdevRuleToken, tokens);
|
||||
LIST_FIELDS(UdevRuleLine, rule_lines);
|
||||
};
|
||||
|
||||
struct UdevRuleFile {
|
||||
char *filename;
|
||||
UdevRuleLine *current_line;
|
||||
LIST_HEAD(UdevRuleLine, rule_lines);
|
||||
LIST_FIELDS(UdevRuleFile, rule_files);
|
||||
};
|
||||
|
||||
struct UdevRules {
|
||||
usec_t dirs_ts_usec;
|
||||
ResolveNameTiming resolve_name_timing;
|
||||
Hashmap *known_users;
|
||||
Hashmap *known_groups;
|
||||
UdevRuleFile *current_file;
|
||||
LIST_HEAD(UdevRuleFile, rule_files);
|
||||
};
|
||||
|
||||
int udev_rules_new(UdevRules **ret_rules, ResolveNameTiming resolve_name_timing);
|
||||
UdevRules *udev_rules_free(UdevRules *rules);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(UdevRules*, udev_rules_free);
|
||||
|
||||
bool udev_rules_check_timestamp(UdevRules *rules);
|
||||
int udev_rules_apply_to_event(UdevRules *rules, UdevEvent *event,
|
||||
usec_t timeout_usec,
|
||||
Hashmap *properties_list);
|
||||
int udev_rules_apply_static_dev_perms(UdevRules *rules);
|
||||
|
||||
#define log_rule_full(device, rules, level, error, fmt, ...) \
|
||||
({ \
|
||||
UdevRules *_r = (rules); \
|
||||
UdevRuleFile *_f = _r ? _r->current_file : NULL; \
|
||||
UdevRuleLine *_l = _f ? _f->current_line : NULL; \
|
||||
const char *_n = _f ? _f->filename : NULL; \
|
||||
\
|
||||
log_device_full(device, level, error, "%s:%u " fmt, \
|
||||
strna(_n), _l ? _l->line_number : 0, \
|
||||
##__VA_ARGS__); \
|
||||
})
|
||||
|
||||
#define log_rule_debug(device, rules, ...) log_rule_full(device, rules, LOG_DEBUG, 0, ##__VA_ARGS__)
|
||||
#define log_rule_info(device, rules, ...) log_rule_full(device, rules, LOG_INFO, 0, ##__VA_ARGS__)
|
||||
#define log_rule_notice(device, rules, ...) log_rule_full(device, rules, LOG_NOTICE, 0, ##__VA_ARGS__)
|
||||
#define log_rule_warning(device, rules, ...) log_rule_full(device, rules, LOG_WARNING, 0, ##__VA_ARGS__)
|
||||
#define log_rule_error(device, rules, ...) log_rule_full(device, rules, LOG_ERR, 0, ##__VA_ARGS__)
|
||||
|
||||
#define log_rule_debug_errno(device, rules, error, ...) log_rule_full(device, rules, LOG_DEBUG, error, ##__VA_ARGS__)
|
||||
#define log_rule_info_errno(device, rules, error, ...) log_rule_full(device, rules, LOG_INFO, error, ##__VA_ARGS__)
|
||||
#define log_rule_notice_errno(device, rules, error, ...) log_rule_full(device, rules, LOG_NOTICE, error, ##__VA_ARGS__)
|
||||
#define log_rule_warning_errno(device, rules, error, ...) log_rule_full(device, rules, LOG_WARNING, error, ##__VA_ARGS__)
|
||||
#define log_rule_error_errno(device, rules, error, ...) log_rule_full(device, rules, LOG_ERR, error, ##__VA_ARGS__)
|
||||
|
||||
#define log_token_full(rules, ...) log_rule_full(NULL, rules, ##__VA_ARGS__)
|
||||
|
||||
#define log_token_debug(rules, ...) log_token_full(rules, LOG_DEBUG, 0, ##__VA_ARGS__)
|
||||
#define log_token_info(rules, ...) log_token_full(rules, LOG_INFO, 0, ##__VA_ARGS__)
|
||||
#define log_token_notice(rules, ...) log_token_full(rules, LOG_NOTICE, 0, ##__VA_ARGS__)
|
||||
#define log_token_warning(rules, ...) log_token_full(rules, LOG_WARNING, 0, ##__VA_ARGS__)
|
||||
#define log_token_error(rules, ...) log_token_full(rules, LOG_ERR, 0, ##__VA_ARGS__)
|
||||
|
||||
#define log_token_debug_errno(rules, error, ...) log_token_full(rules, LOG_DEBUG, error, ##__VA_ARGS__)
|
||||
#define log_token_info_errno(rules, error, ...) log_token_full(rules, LOG_INFO, error, ##__VA_ARGS__)
|
||||
#define log_token_notice_errno(rules, error, ...) log_token_full(rules, LOG_NOTICE, error, ##__VA_ARGS__)
|
||||
#define log_token_warning_errno(rules, error, ...) log_token_full(rules, LOG_WARNING, error, ##__VA_ARGS__)
|
||||
#define log_token_error_errno(rules, error, ...) log_token_full(rules, LOG_ERR, error, ##__VA_ARGS__)
|
||||
|
||||
#define _log_token_invalid(rules, key, type) \
|
||||
log_token_error_errno(rules, SYNTHETIC_ERRNO(EINVAL), \
|
||||
"Invalid %s for %s.", type, key)
|
||||
|
||||
#define log_token_invalid_op(rules, key) _log_token_invalid(rules, key, "operator")
|
||||
#define log_token_invalid_attr(rules, key) _log_token_invalid(rules, key, "attribute")
|
||||
|
||||
#define log_token_invalid_attr_format(rules, key, attr) \
|
||||
log_token_error_errno(rules, SYNTHETIC_ERRNO(EINVAL), \
|
||||
"Invalid attribute \"%s\" for %s, ignoring, but please fix it.", \
|
||||
attr, key)
|
||||
#define log_token_invalid_value(rules, key, value) \
|
||||
log_token_error_errno(rules, SYNTHETIC_ERRNO(EINVAL), \
|
||||
"Invalid value \"%s\" for %s, ignoring, but please fix it.", \
|
||||
value, key)
|
||||
@@ -63,7 +63,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
|
||||
int builtin_main(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
|
||||
enum udev_builtin_cmd cmd;
|
||||
UdevBuiltinCommand cmd;
|
||||
int r;
|
||||
|
||||
log_set_max_level(LOG_DEBUG);
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "string-util.h"
|
||||
#include "strxcpyx.h"
|
||||
#include "udev-builtin.h"
|
||||
#include "udev.h"
|
||||
#include "udev-event.h"
|
||||
#include "udevadm.h"
|
||||
|
||||
static const char *arg_action = "add";
|
||||
|
||||
+1
-1
@@ -64,9 +64,9 @@
|
||||
#include "syslog-util.h"
|
||||
#include "udev-builtin.h"
|
||||
#include "udev-ctrl.h"
|
||||
#include "udev-event.h"
|
||||
#include "udev-util.h"
|
||||
#include "udev-watch.h"
|
||||
#include "udev.h"
|
||||
#include "user-util.h"
|
||||
|
||||
#define WORKER_NUM_MAX 2048U
|
||||
|
||||
Reference in New Issue
Block a user