]>
Commit | Line | Data |
---|---|---|
f13467ec | 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
d46f37fd | 2 | |
b5efdb8a | 3 | #include "alloc-util.h" |
ff88b949 | 4 | #include "device-internal.h" |
947ce772 | 5 | #include "device-private.h" |
e9343893 | 6 | #include "device-util.h" |
25de7aa7 | 7 | #include "fs-util.h" |
068b0f77 | 8 | #include "netif-naming-scheme.h" |
07630cea | 9 | #include "netlink-util.h" |
feaa6db7 | 10 | #include "path-util.h" |
07630cea | 11 | #include "string-util.h" |
5ea78a39 | 12 | #include "strv.h" |
25de7aa7 | 13 | #include "udev-event.h" |
a2554ace | 14 | #include "udev-node.h" |
1c3edc2e | 15 | #include "udev-trace.h" |
c0af9dee | 16 | #include "udev-util.h" |
25de7aa7 | 17 | #include "user-util.h" |
8128f229 | 18 | |
eb1a51b8 YW |
19 | UdevEvent *udev_event_new(sd_device *dev, UdevWorker *worker) { |
20 | int log_level = worker ? worker->log_level : log_get_max_level(); | |
2e088715 | 21 | UdevEvent *event; |
912541b0 | 22 | |
89665d09 YW |
23 | assert(dev); |
24 | ||
2e088715 | 25 | event = new(UdevEvent, 1); |
89665d09 | 26 | if (!event) |
912541b0 | 27 | return NULL; |
89665d09 | 28 | |
2e088715 | 29 | *event = (UdevEvent) { |
eb1a51b8 YW |
30 | .worker = worker, |
31 | .rtnl = worker ? sd_netlink_ref(worker->rtnl) : NULL, | |
cf28ad46 | 32 | .dev = sd_device_ref(dev), |
89665d09 | 33 | .birth_usec = now(CLOCK_MONOTONIC), |
25de7aa7 YW |
34 | .uid = UID_INVALID, |
35 | .gid = GID_INVALID, | |
36 | .mode = MODE_INVALID, | |
1a0bd015 YW |
37 | .log_level_was_debug = log_level == LOG_DEBUG, |
38 | .default_log_level = log_level, | |
89665d09 YW |
39 | }; |
40 | ||
912541b0 | 41 | return event; |
aa8734ff KS |
42 | } |
43 | ||
2e088715 | 44 | UdevEvent *udev_event_free(UdevEvent *event) { |
c1118ceb YW |
45 | if (!event) |
46 | return NULL; | |
47 | ||
cf28ad46 | 48 | sd_device_unref(event->dev); |
480ecb7d | 49 | sd_device_unref(event->dev_db_clone); |
1c4baffc | 50 | sd_netlink_unref(event->rtnl); |
39a15c8a YW |
51 | ordered_hashmap_free_free_key(event->run_list); |
52 | ordered_hashmap_free_free_free(event->seclabel_list); | |
912541b0 KS |
53 | free(event->program_result); |
54 | free(event->name); | |
9094ae52 | 55 | strv_free(event->altnames); |
c1118ceb YW |
56 | |
57 | return mfree(event); | |
aa8734ff KS |
58 | } |
59 | ||
ff88b949 YW |
60 | static int device_rename(sd_device *device, const char *name) { |
61 | _cleanup_free_ char *new_syspath = NULL; | |
62 | const char *s; | |
63 | int r; | |
64 | ||
65 | assert(device); | |
66 | assert(name); | |
67 | ||
68 | if (!filename_is_valid(name)) | |
69 | return -EINVAL; | |
70 | ||
71 | r = sd_device_get_syspath(device, &s); | |
72 | if (r < 0) | |
73 | return r; | |
74 | ||
75 | r = path_extract_directory(s, &new_syspath); | |
76 | if (r < 0) | |
77 | return r; | |
78 | ||
79 | if (!path_extend(&new_syspath, name)) | |
80 | return -ENOMEM; | |
81 | ||
82 | if (!path_is_safe(new_syspath)) | |
83 | return -EINVAL; | |
84 | ||
85 | /* At the time this is called, the renamed device may not exist yet. Hence, we cannot validate | |
86 | * the new syspath. */ | |
87 | r = device_set_syspath(device, new_syspath, /* verify = */ false); | |
88 | if (r < 0) | |
89 | return r; | |
90 | ||
91 | r = sd_device_get_property_value(device, "INTERFACE", &s); | |
92 | if (r == -ENOENT) | |
93 | return 0; | |
94 | if (r < 0) | |
95 | return r; | |
96 | ||
97 | /* like DEVPATH_OLD, INTERFACE_OLD is not saved to the db, but only stays around for the current event */ | |
98 | r = device_add_property_internal(device, "INTERFACE_OLD", s); | |
99 | if (r < 0) | |
100 | return r; | |
101 | ||
102 | return device_add_property_internal(device, "INTERFACE", name); | |
103 | } | |
104 | ||
2e088715 | 105 | static int rename_netif(UdevEvent *event) { |
21003384 YW |
106 | _cleanup_free_ char *old_syspath = NULL, *old_sysname = NULL; |
107 | const char *s; | |
60e50fb2 | 108 | sd_device *dev; |
2740750d YW |
109 | int ifindex, r; |
110 | ||
60e50fb2 YW |
111 | assert(event); |
112 | ||
2740750d YW |
113 | if (!event->name) |
114 | return 0; /* No new name is requested. */ | |
115 | ||
60e50fb2 YW |
116 | dev = ASSERT_PTR(event->dev); |
117 | ||
2740750d YW |
118 | r = sd_device_get_ifindex(dev, &ifindex); |
119 | if (r == -ENOENT) | |
120 | return 0; /* Device is not a network interface. */ | |
121 | if (r < 0) | |
21003384 | 122 | return log_device_warning_errno(dev, r, "Failed to get ifindex: %m"); |
912541b0 | 123 | |
068b0f77 YW |
124 | if (naming_scheme_has(NAMING_REPLACE_STRICTLY) && |
125 | !ifname_valid(event->name)) { | |
126 | log_device_warning(dev, "Invalid network interface name, ignoring: %s", event->name); | |
127 | return 0; | |
128 | } | |
129 | ||
21003384 | 130 | r = sd_device_get_sysname(dev, &s); |
a4055a60 | 131 | if (r < 0) |
21003384 | 132 | return log_device_warning_errno(dev, r, "Failed to get sysname: %m"); |
912541b0 | 133 | |
21003384 YW |
134 | if (streq(event->name, s)) |
135 | return 0; /* The interface name is already requested name. */ | |
136 | ||
137 | old_sysname = strdup(s); | |
138 | if (!old_sysname) | |
139 | return -ENOMEM; | |
140 | ||
141 | r = sd_device_get_syspath(dev, &s); | |
f647962d | 142 | if (r < 0) |
21003384 YW |
143 | return log_device_warning_errno(dev, r, "Failed to get syspath: %m"); |
144 | ||
145 | old_syspath = strdup(s); | |
146 | if (!old_syspath) | |
147 | return -ENOMEM; | |
148 | ||
149 | r = device_rename(dev, event->name); | |
150 | if (r < 0) { | |
2b43c5cb YW |
151 | /* Here and below, use dev_db_clone for logging, otherwise, logged message is prefixed with |
152 | * the new interface name, and e.g. 'networkctl status INTERFACE' does not show the message. */ | |
153 | log_device_warning_errno(event->dev_db_clone, r, | |
154 | "Failed to update properties with new name '%s': %m", event->name); | |
21003384 YW |
155 | goto revert; |
156 | } | |
157 | ||
158 | /* Set ID_RENAMING boolean property here. It will be dropped when the corresponding move uevent is processed. */ | |
159 | r = device_add_property(dev, "ID_RENAMING", "1"); | |
160 | if (r < 0) { | |
2b43c5cb | 161 | log_device_warning_errno(event->dev_db_clone, r, "Failed to add 'ID_RENAMING' property: %m"); |
21003384 YW |
162 | goto revert; |
163 | } | |
16d26d55 | 164 | |
ae353ec2 YW |
165 | /* Also set ID_RENAMING boolean property to cloned sd_device object and save it to database |
166 | * before calling rtnl_set_link_name(). Otherwise, clients (e.g., systemd-networkd) may receive | |
167 | * RTM_NEWLINK netlink message before the database is updated. */ | |
168 | r = device_add_property(event->dev_db_clone, "ID_RENAMING", "1"); | |
21003384 YW |
169 | if (r < 0) { |
170 | log_device_warning_errno(event->dev_db_clone, r, "Failed to add 'ID_RENAMING' property: %m"); | |
171 | goto revert; | |
172 | } | |
ae353ec2 YW |
173 | |
174 | r = device_update_db(event->dev_db_clone); | |
21003384 YW |
175 | if (r < 0) { |
176 | log_device_debug_errno(event->dev_db_clone, r, "Failed to update database under /run/udev/data/: %m"); | |
177 | goto revert; | |
178 | } | |
ae353ec2 | 179 | |
9094ae52 | 180 | r = rtnl_set_link_name(&event->rtnl, ifindex, event->name, event->altnames); |
21003384 YW |
181 | if (r < 0) { |
182 | if (r == -EBUSY) { | |
2b43c5cb YW |
183 | log_device_info(event->dev_db_clone, |
184 | "Network interface '%s' is already up, cannot rename to '%s'.", | |
21003384 YW |
185 | old_sysname, event->name); |
186 | r = 0; | |
187 | } else | |
2b43c5cb YW |
188 | log_device_error_errno(event->dev_db_clone, r, |
189 | "Failed to rename network interface %i from '%s' to '%s': %m", | |
21003384 YW |
190 | ifindex, old_sysname, event->name); |
191 | goto revert; | |
53584e7b | 192 | } |
16d26d55 | 193 | |
21003384 | 194 | log_device_debug(dev, "Network interface %i is renamed from '%s' to '%s'", ifindex, old_sysname, event->name); |
2740750d | 195 | return 1; |
21003384 YW |
196 | |
197 | revert: | |
198 | /* Restore 'dev_db_clone' */ | |
199 | (void) device_add_property(event->dev_db_clone, "ID_RENAMING", NULL); | |
200 | (void) device_update_db(event->dev_db_clone); | |
201 | ||
202 | /* Restore 'dev' */ | |
203 | (void) device_set_syspath(dev, old_syspath, /* verify = */ false); | |
204 | if (sd_device_get_property_value(dev, "INTERFACE_OLD", &s) >= 0) { | |
205 | (void) device_add_property_internal(dev, "INTERFACE", s); | |
206 | (void) device_add_property_internal(dev, "INTERFACE_OLD", NULL); | |
207 | } | |
208 | (void) device_add_property(dev, "ID_RENAMING", NULL); | |
209 | ||
210 | return r; | |
d46f37fd KS |
211 | } |
212 | ||
9094ae52 YW |
213 | static int assign_altnames(UdevEvent *event) { |
214 | sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev); | |
215 | int ifindex, r; | |
216 | const char *s; | |
217 | ||
218 | if (strv_isempty(event->altnames)) | |
219 | return 0; | |
220 | ||
221 | r = sd_device_get_ifindex(dev, &ifindex); | |
222 | if (r == -ENOENT) | |
223 | return 0; /* Device is not a network interface. */ | |
224 | if (r < 0) | |
225 | return log_device_warning_errno(dev, r, "Failed to get ifindex: %m"); | |
226 | ||
227 | r = sd_device_get_sysname(dev, &s); | |
228 | if (r < 0) | |
229 | return log_device_warning_errno(dev, r, "Failed to get sysname: %m"); | |
230 | ||
231 | /* Filter out the current interface name. */ | |
232 | strv_remove(event->altnames, s); | |
233 | ||
234 | r = rtnl_append_link_alternative_names(&event->rtnl, ifindex, event->altnames); | |
235 | if (r < 0) | |
236 | log_device_full_errno(dev, r == -EOPNOTSUPP ? LOG_DEBUG : LOG_WARNING, r, | |
237 | "Could not set AlternativeName= or apply AlternativeNamesPolicy=, ignoring: %m"); | |
238 | ||
239 | return 0; | |
240 | } | |
241 | ||
2e088715 | 242 | static int update_devnode(UdevEvent *event) { |
fbd747a4 | 243 | sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev); |
e52eaf56 YW |
244 | int r; |
245 | ||
7af1c780 | 246 | r = sd_device_get_devnum(dev, NULL); |
e52eaf56 YW |
247 | if (r == -ENOENT) |
248 | return 0; | |
249 | if (r < 0) | |
250 | return log_device_error_errno(dev, r, "Failed to get devnum: %m"); | |
251 | ||
25de7aa7 | 252 | if (!uid_is_valid(event->uid)) { |
e52eaf56 | 253 | r = device_get_devnode_uid(dev, &event->uid); |
3708c0f4 | 254 | if (r < 0 && r != -ENOENT) |
e52eaf56 YW |
255 | return log_device_error_errno(dev, r, "Failed to get devnode UID: %m"); |
256 | } | |
257 | ||
25de7aa7 | 258 | if (!gid_is_valid(event->gid)) { |
e52eaf56 | 259 | r = device_get_devnode_gid(dev, &event->gid); |
3708c0f4 | 260 | if (r < 0 && r != -ENOENT) |
e52eaf56 YW |
261 | return log_device_error_errno(dev, r, "Failed to get devnode GID: %m"); |
262 | } | |
263 | ||
25de7aa7 | 264 | if (event->mode == MODE_INVALID) { |
e52eaf56 YW |
265 | r = device_get_devnode_mode(dev, &event->mode); |
266 | if (r < 0 && r != -ENOENT) | |
267 | return log_device_error_errno(dev, r, "Failed to get devnode mode: %m"); | |
e52eaf56 | 268 | } |
3708c0f4 | 269 | |
a1130022 | 270 | bool apply_mac = device_for_action(dev, SD_DEVICE_ADD); |
e52eaf56 | 271 | |
2f48561e YW |
272 | r = udev_node_apply_permissions(dev, apply_mac, event->mode, event->uid, event->gid, event->seclabel_list); |
273 | if (r < 0) | |
274 | return log_device_error_errno(dev, r, "Failed to apply devnode permissions: %m"); | |
275 | ||
276 | return udev_node_update(dev, event->dev_db_clone); | |
e52eaf56 YW |
277 | } |
278 | ||
eb1a51b8 | 279 | static int event_execute_rules_on_remove(UdevEvent *event, UdevRules *rules) { |
fbd747a4 | 280 | sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev); |
eb1f9e30 | 281 | int r; |
912541b0 | 282 | |
ebcc52fa | 283 | r = device_read_db_internal(dev, true); |
eb1f9e30 YW |
284 | if (r < 0) |
285 | log_device_debug_errno(dev, r, "Failed to read database under /run/udev/data/: %m"); | |
107f2e25 | 286 | |
eb1f9e30 YW |
287 | r = device_tag_index(dev, NULL, false); |
288 | if (r < 0) | |
289 | log_device_debug_errno(dev, r, "Failed to remove corresponding tag files under /run/udev/tag/, ignoring: %m"); | |
912541b0 | 290 | |
eb1f9e30 YW |
291 | r = device_delete_db(dev); |
292 | if (r < 0) | |
293 | log_device_debug_errno(dev, r, "Failed to delete database under /run/udev/data/, ignoring: %m"); | |
912541b0 | 294 | |
eb1a51b8 | 295 | r = udev_rules_apply_to_event(rules, event); |
eb1f9e30 | 296 | |
d4a95a95 | 297 | if (sd_device_get_devnum(dev, NULL) >= 0) |
eb1f9e30 | 298 | (void) udev_node_remove(dev); |
4cac2260 YW |
299 | |
300 | return r; | |
eb1f9e30 YW |
301 | } |
302 | ||
e77b146f | 303 | static int copy_all_tags(sd_device *d, sd_device *s) { |
e77b146f LP |
304 | int r; |
305 | ||
306 | assert(d); | |
307 | ||
308 | if (!s) | |
309 | return 0; | |
310 | ||
5b90b906 | 311 | FOREACH_DEVICE_TAG(s, tag) { |
e77b146f LP |
312 | r = device_add_tag(d, tag, false); |
313 | if (r < 0) | |
314 | return r; | |
315 | } | |
316 | ||
317 | return 0; | |
318 | } | |
319 | ||
eb1a51b8 | 320 | int udev_event_execute_rules(UdevEvent *event, UdevRules *rules) { |
a1130022 | 321 | sd_device_action_t action; |
6d0fdf45 | 322 | sd_device *dev; |
eb1f9e30 YW |
323 | int r; |
324 | ||
28235d10 | 325 | dev = ASSERT_PTR(ASSERT_PTR(event)->dev); |
eb1f9e30 YW |
326 | assert(rules); |
327 | ||
a1130022 | 328 | r = sd_device_get_action(dev, &action); |
eb1f9e30 | 329 | if (r < 0) |
d4d690fa | 330 | return log_device_error_errno(dev, r, "Failed to get ACTION: %m"); |
b081b27e | 331 | |
4cac2260 | 332 | if (action == SD_DEVICE_REMOVE) |
eb1a51b8 | 333 | return event_execute_rules_on_remove(event, rules); |
e7f781e4 | 334 | |
480ecb7d | 335 | r = device_clone_with_db(dev, &event->dev_db_clone); |
eb1f9e30 | 336 | if (r < 0) |
99058cd6 | 337 | return log_device_debug_errno(dev, r, "Failed to clone sd_device object: %m"); |
912541b0 | 338 | |
e77b146f LP |
339 | r = copy_all_tags(dev, event->dev_db_clone); |
340 | if (r < 0) | |
341 | log_device_warning_errno(dev, r, "Failed to copy all tags from old database entry, ignoring: %m"); | |
342 | ||
7137f2f3 YW |
343 | /* Drop previously added property for safety to make IMPORT{db}="ID_RENAMING" not work. This is |
344 | * mostly for 'move' uevent, but let's do unconditionally. Why? If a network interface is renamed in | |
345 | * initrd, then udevd may lose the 'move' uevent during switching root. Usually, we do not set the | |
346 | * persistent flag for network interfaces, but user may set it. Just for safety. */ | |
347 | r = device_add_property(event->dev_db_clone, "ID_RENAMING", NULL); | |
348 | if (r < 0) | |
349 | return log_device_debug_errno(dev, r, "Failed to remove 'ID_RENAMING' property: %m"); | |
eb1f9e30 | 350 | |
b428efa5 MS |
351 | DEVICE_TRACE_POINT(rules_start, dev); |
352 | ||
eb1a51b8 | 353 | r = udev_rules_apply_to_event(rules, event); |
99058cd6 YW |
354 | if (r < 0) |
355 | return log_device_debug_errno(dev, r, "Failed to apply udev rules: %m"); | |
eb1f9e30 | 356 | |
b428efa5 MS |
357 | DEVICE_TRACE_POINT(rules_finished, dev); |
358 | ||
9094ae52 YW |
359 | if (action == SD_DEVICE_ADD) { |
360 | r = rename_netif(event); | |
361 | if (r < 0) | |
362 | return r; | |
363 | if (r == 0) | |
364 | (void) assign_altnames(event); | |
365 | } | |
99058cd6 YW |
366 | |
367 | r = update_devnode(event); | |
368 | if (r < 0) | |
369 | return r; | |
eb1f9e30 YW |
370 | |
371 | /* preserve old, or get new initialization timestamp */ | |
480ecb7d | 372 | r = device_ensure_usec_initialized(dev, event->dev_db_clone); |
eb1f9e30 | 373 | if (r < 0) |
99058cd6 | 374 | return log_device_debug_errno(dev, r, "Failed to set initialization timestamp: %m"); |
eb1f9e30 YW |
375 | |
376 | /* (re)write database file */ | |
480ecb7d | 377 | r = device_tag_index(dev, event->dev_db_clone, true); |
eb1f9e30 | 378 | if (r < 0) |
99058cd6 | 379 | return log_device_debug_errno(dev, r, "Failed to update tags under /run/udev/tag/: %m"); |
eb1f9e30 YW |
380 | |
381 | r = device_update_db(dev); | |
382 | if (r < 0) | |
99058cd6 | 383 | return log_device_debug_errno(dev, r, "Failed to update database under /run/udev/data/: %m"); |
eb1f9e30 | 384 | |
996c8390 MS |
385 | device_set_is_initialized(dev); |
386 | ||
7920d0a1 | 387 | return 0; |
d46f37fd | 388 | } |