]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
b237a168 | 2 | |
152d0efa | 3 | #include <errno.h> |
b237a168 | 4 | |
152d0efa | 5 | #include "alloc-util.h" |
686d13b9 | 6 | #include "env-file.h" |
b237a168 | 7 | #include "log.h" |
4b3ca79e | 8 | #include "parse-util.h" |
bc768f04 | 9 | #include "string-table.h" |
b237a168 ZJS |
10 | #include "string-util.h" |
11 | #include "udev-util.h" | |
12 | ||
bc768f04 ZJS |
13 | static const char* const resolve_name_timing_table[_RESOLVE_NAME_TIMING_MAX] = { |
14 | [RESOLVE_NAME_NEVER] = "never", | |
15 | [RESOLVE_NAME_LATE] = "late", | |
16 | [RESOLVE_NAME_EARLY] = "early", | |
17 | }; | |
18 | ||
19 | DEFINE_STRING_TABLE_LOOKUP(resolve_name_timing, ResolveNameTiming); | |
20 | ||
4b3ca79e ZJS |
21 | int udev_parse_config_full( |
22 | unsigned *ret_children_max, | |
23 | usec_t *ret_exec_delay_usec, | |
a14e7af1 ZJS |
24 | usec_t *ret_event_timeout_usec, |
25 | ResolveNameTiming *ret_resolve_name_timing) { | |
4b3ca79e | 26 | |
a14e7af1 | 27 | _cleanup_free_ char *log_val = NULL, *children_max = NULL, *exec_delay = NULL, *event_timeout = NULL, *resolve_names = NULL; |
b237a168 ZJS |
28 | int r; |
29 | ||
aa8fbc74 | 30 | r = parse_env_file(NULL, "/etc/udev/udev.conf", |
4b3ca79e ZJS |
31 | "udev_log", &log_val, |
32 | "children_max", &children_max, | |
33 | "exec_delay", &exec_delay, | |
9b2934cb YW |
34 | "event_timeout", &event_timeout, |
35 | "resolve_names", &resolve_names); | |
4b3ca79e | 36 | if (r == -ENOENT) |
b237a168 ZJS |
37 | return 0; |
38 | if (r < 0) | |
39 | return r; | |
40 | ||
4b3ca79e ZJS |
41 | if (log_val) { |
42 | const char *log; | |
43 | size_t n; | |
44 | ||
45 | /* unquote */ | |
46 | n = strlen(log_val); | |
47 | if (n >= 2 && | |
48 | ((log_val[0] == '"' && log_val[n-1] == '"') || | |
49 | (log_val[0] == '\'' && log_val[n-1] == '\''))) { | |
50 | log_val[n - 1] = '\0'; | |
51 | log = log_val + 1; | |
52 | } else | |
53 | log = log_val; | |
54 | ||
55 | /* we set the udev log level here explicitly, this is supposed | |
56 | * to regulate the code in libudev/ and udev/. */ | |
57 | r = log_set_max_level_from_string_realm(LOG_REALM_UDEV, log); | |
58 | if (r < 0) | |
59 | log_debug_errno(r, "/etc/udev/udev.conf: failed to set udev log level '%s', ignoring: %m", log); | |
60 | } | |
61 | ||
62 | if (ret_children_max && children_max) { | |
63 | r = safe_atou(children_max, ret_children_max); | |
64 | if (r < 0) | |
65 | log_notice_errno(r, "/etc/udev/udev.conf: failed to set parse children_max=%s, ignoring: %m", children_max); | |
66 | } | |
67 | ||
68 | if (ret_exec_delay_usec && exec_delay) { | |
69 | r = parse_sec(exec_delay, ret_exec_delay_usec); | |
70 | if (r < 0) | |
71 | log_notice_errno(r, "/etc/udev/udev.conf: failed to set parse exec_delay=%s, ignoring: %m", exec_delay); | |
72 | } | |
73 | ||
74 | if (ret_event_timeout_usec && event_timeout) { | |
75 | r = parse_sec(event_timeout, ret_event_timeout_usec); | |
76 | if (r < 0) | |
77 | log_notice_errno(r, "/etc/udev/udev.conf: failed to set parse event_timeout=%s, ignoring: %m", event_timeout); | |
78 | } | |
b237a168 | 79 | |
a14e7af1 ZJS |
80 | if (ret_resolve_name_timing && resolve_names) { |
81 | ResolveNameTiming t; | |
82 | ||
83 | t = resolve_name_timing_from_string(resolve_names); | |
84 | if (t < 0) | |
85 | log_notice("/etc/udev/udev.conf: failed to set parse resolve_names=%s, ignoring.", resolve_names); | |
86 | else | |
87 | *ret_resolve_name_timing = t; | |
88 | } | |
89 | ||
b237a168 ZJS |
90 | return 0; |
91 | } | |
ed435031 ZJS |
92 | |
93 | struct DeviceMonitorData { | |
94 | const char *sysname; | |
95 | sd_device *device; | |
96 | }; | |
97 | ||
98 | static int device_monitor_handler(sd_device_monitor *monitor, sd_device *device, void *userdata) { | |
99 | struct DeviceMonitorData *data = userdata; | |
100 | const char *sysname; | |
101 | ||
102 | assert(device); | |
103 | assert(data); | |
104 | assert(data->sysname); | |
105 | assert(!data->device); | |
106 | ||
107 | if (sd_device_get_sysname(device, &sysname) >= 0 && streq(sysname, data->sysname)) { | |
108 | data->device = sd_device_ref(device); | |
109 | return sd_event_exit(sd_device_monitor_get_event(monitor), 0); | |
110 | } | |
111 | ||
112 | return 0; | |
113 | } | |
114 | ||
115 | int device_wait_for_initialization(sd_device *device, const char *subsystem, sd_device **ret) { | |
116 | _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL; | |
117 | _cleanup_(sd_event_unrefp) sd_event *event = NULL; | |
118 | struct DeviceMonitorData data = {}; | |
119 | int r; | |
120 | ||
121 | assert(device); | |
122 | assert(subsystem); | |
123 | ||
124 | if (sd_device_get_is_initialized(device) > 0) { | |
125 | if (ret) | |
126 | *ret = sd_device_ref(device); | |
127 | return 0; | |
128 | } | |
129 | ||
130 | assert_se(sd_device_get_sysname(device, &data.sysname) >= 0); | |
131 | ||
132 | /* Wait until the device is initialized, so that we can get access to the ID_PATH property */ | |
133 | ||
fc40bfa7 | 134 | r = sd_event_new(&event); |
ed435031 ZJS |
135 | if (r < 0) |
136 | return log_error_errno(r, "Failed to get default event: %m"); | |
137 | ||
138 | r = sd_device_monitor_new(&monitor); | |
139 | if (r < 0) | |
140 | return log_error_errno(r, "Failed to acquire monitor: %m"); | |
141 | ||
142 | r = sd_device_monitor_filter_add_match_subsystem_devtype(monitor, subsystem, NULL); | |
143 | if (r < 0) | |
144 | return log_error_errno(r, "Failed to add %s subsystem match to monitor: %m", subsystem); | |
145 | ||
146 | r = sd_device_monitor_attach_event(monitor, event); | |
147 | if (r < 0) | |
148 | return log_error_errno(r, "Failed to attach event to device monitor: %m"); | |
149 | ||
150 | r = sd_device_monitor_start(monitor, device_monitor_handler, &data); | |
151 | if (r < 0) | |
152 | return log_error_errno(r, "Failed to start device monitor: %m"); | |
153 | ||
154 | /* Check again, maybe things changed. Udev will re-read the db if the device wasn't initialized | |
155 | * yet. */ | |
156 | if (sd_device_get_is_initialized(device) > 0) { | |
157 | if (ret) | |
158 | *ret = sd_device_ref(device); | |
159 | return 0; | |
160 | } | |
161 | ||
162 | r = sd_event_loop(event); | |
163 | if (r < 0) | |
164 | return log_error_errno(r, "Event loop failed: %m"); | |
165 | ||
166 | if (ret) | |
167 | *ret = TAKE_PTR(data.device); | |
168 | return 0; | |
169 | } | |
90ba130f YW |
170 | |
171 | int device_is_renaming(sd_device *dev) { | |
172 | int r; | |
173 | ||
174 | assert(dev); | |
175 | ||
176 | r = sd_device_get_property_value(dev, "ID_RENAMING", NULL); | |
177 | if (r < 0 && r != -ENOENT) | |
178 | return r; | |
179 | ||
180 | return r >= 0; | |
181 | } | |
a707c65b YW |
182 | |
183 | bool device_for_action(sd_device *dev, DeviceAction action) { | |
184 | DeviceAction a; | |
185 | ||
186 | assert(dev); | |
187 | ||
188 | if (device_get_action(dev, &a) < 0) | |
189 | return false; | |
190 | ||
191 | return a == action; | |
192 | } |