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