]>
Commit | Line | Data |
---|---|---|
d46f37fd | 1 | /* |
55e9959b | 2 | * Copyright (C) 2004-2008 Kay Sievers <kay.sievers@vrfy.org> |
d46f37fd | 3 | * |
55e9959b KS |
4 | * This program is free software: you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation, either version 2 of the License, or | |
7 | * (at your option) any later version. | |
d46f37fd | 8 | * |
55e9959b KS |
9 | * This program is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License | |
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
d46f37fd KS |
16 | */ |
17 | ||
d46f37fd KS |
18 | #include <stdlib.h> |
19 | #include <stdio.h> | |
20 | #include <stddef.h> | |
21 | #include <unistd.h> | |
22 | #include <fcntl.h> | |
23 | #include <errno.h> | |
24 | #include <ctype.h> | |
25 | #include <string.h> | |
26 | #include <sys/ioctl.h> | |
27 | #include <sys/socket.h> | |
28 | #include <net/if.h> | |
29 | #include <linux/sockios.h> | |
30 | ||
31 | #include "udev.h" | |
d46f37fd | 32 | |
aa8734ff KS |
33 | struct udev_event *udev_event_new(struct udev_device *dev) |
34 | { | |
35 | struct udev_event *event; | |
36 | ||
b29a5e4a | 37 | event = calloc(1, sizeof(struct udev_event)); |
aa8734ff KS |
38 | if (event == NULL) |
39 | return NULL; | |
aa8734ff KS |
40 | event->dev = dev; |
41 | event->udev = udev_device_get_udev(dev); | |
42 | udev_list_init(&event->run_list); | |
43 | event->mode = 0660; | |
aa8734ff KS |
44 | dbg(event->udev, "allocated event %p\n", event); |
45 | return event; | |
46 | } | |
47 | ||
48 | void udev_event_unref(struct udev_event *event) | |
49 | { | |
40fd3bc8 KS |
50 | if (event == NULL) |
51 | return; | |
eb8837e1 | 52 | udev_list_cleanup_entries(event->udev, &event->run_list); |
40fd3bc8 KS |
53 | free(event->tmp_node); |
54 | free(event->program_result); | |
b99028c9 | 55 | free(event->name); |
aa8734ff KS |
56 | dbg(event->udev, "free event %p\n", event); |
57 | free(event); | |
58 | } | |
59 | ||
f1128767 KS |
60 | /* extract possible {attr} and move str behind it */ |
61 | static char *get_format_attribute(struct udev *udev, char **str) | |
62 | { | |
63 | char *pos; | |
64 | char *attr = NULL; | |
65 | ||
66 | if (*str[0] == '{') { | |
67 | pos = strchr(*str, '}'); | |
68 | if (pos == NULL) { | |
69 | err(udev, "missing closing brace for format\n"); | |
70 | return NULL; | |
71 | } | |
72 | pos[0] = '\0'; | |
73 | attr = *str+1; | |
74 | *str = pos+1; | |
75 | dbg(udev, "attribute='%s', str='%s'\n", attr, *str); | |
76 | } | |
77 | return attr; | |
78 | } | |
79 | ||
80 | /* extract possible format length and move str behind it*/ | |
81 | static int get_format_len(struct udev *udev, char **str) | |
82 | { | |
83 | int num; | |
84 | char *tail; | |
85 | ||
86 | if (isdigit(*str[0])) { | |
87 | num = (int) strtoul(*str, &tail, 10); | |
88 | if (num > 0) { | |
89 | *str = tail; | |
90 | dbg(udev, "format length=%i\n", num); | |
91 | return num; | |
92 | } else { | |
93 | err(udev, "format parsing error '%s'\n", *str); | |
94 | } | |
95 | } | |
96 | return -1; | |
97 | } | |
98 | ||
f1128767 KS |
99 | void udev_event_apply_format(struct udev_event *event, char *string, size_t maxsize) |
100 | { | |
101 | struct udev_device *dev = event->dev; | |
102 | char temp[UTIL_PATH_SIZE]; | |
103 | char temp2[UTIL_PATH_SIZE]; | |
104 | char *head, *tail, *cpos, *attr, *rest; | |
105 | int len; | |
106 | int i; | |
107 | int count; | |
108 | enum subst_type { | |
109 | SUBST_UNKNOWN, | |
110 | SUBST_DEVPATH, | |
111 | SUBST_KERNEL, | |
112 | SUBST_KERNEL_NUMBER, | |
113 | SUBST_ID, | |
114 | SUBST_DRIVER, | |
115 | SUBST_MAJOR, | |
116 | SUBST_MINOR, | |
117 | SUBST_RESULT, | |
118 | SUBST_ATTR, | |
119 | SUBST_PARENT, | |
120 | SUBST_TEMP_NODE, | |
121 | SUBST_NAME, | |
122 | SUBST_LINKS, | |
123 | SUBST_ROOT, | |
124 | SUBST_SYS, | |
125 | SUBST_ENV, | |
126 | }; | |
127 | static const struct subst_map { | |
128 | char *name; | |
129 | char fmt; | |
130 | enum subst_type type; | |
131 | } map[] = { | |
132 | { .name = "devpath", .fmt = 'p', .type = SUBST_DEVPATH }, | |
133 | { .name = "number", .fmt = 'n', .type = SUBST_KERNEL_NUMBER }, | |
134 | { .name = "kernel", .fmt = 'k', .type = SUBST_KERNEL }, | |
135 | { .name = "id", .fmt = 'b', .type = SUBST_ID }, | |
136 | { .name = "driver", .fmt = 'd', .type = SUBST_DRIVER }, | |
137 | { .name = "major", .fmt = 'M', .type = SUBST_MAJOR }, | |
138 | { .name = "minor", .fmt = 'm', .type = SUBST_MINOR }, | |
139 | { .name = "result", .fmt = 'c', .type = SUBST_RESULT }, | |
140 | { .name = "attr", .fmt = 's', .type = SUBST_ATTR }, | |
141 | { .name = "sysfs", .fmt = 's', .type = SUBST_ATTR }, | |
142 | { .name = "parent", .fmt = 'P', .type = SUBST_PARENT }, | |
143 | { .name = "tempnode", .fmt = 'N', .type = SUBST_TEMP_NODE }, | |
144 | { .name = "name", .fmt = 'D', .type = SUBST_NAME }, | |
145 | { .name = "links", .fmt = 'L', .type = SUBST_LINKS }, | |
146 | { .name = "root", .fmt = 'r', .type = SUBST_ROOT }, | |
147 | { .name = "sys", .fmt = 'S', .type = SUBST_SYS }, | |
148 | { .name = "env", .fmt = 'E', .type = SUBST_ENV }, | |
149 | { NULL, '\0', 0 } | |
150 | }; | |
151 | enum subst_type type; | |
152 | const struct subst_map *subst; | |
153 | ||
154 | head = string; | |
155 | while (1) { | |
156 | len = -1; | |
157 | while (head[0] != '\0') { | |
158 | if (head[0] == '$') { | |
159 | /* substitute named variable */ | |
160 | if (head[1] == '\0') | |
161 | break; | |
162 | if (head[1] == '$') { | |
163 | util_strlcpy(temp, head+2, sizeof(temp)); | |
164 | util_strlcpy(head+1, temp, maxsize); | |
165 | head++; | |
166 | continue; | |
167 | } | |
168 | head[0] = '\0'; | |
169 | for (subst = map; subst->name; subst++) { | |
170 | if (strncasecmp(&head[1], subst->name, strlen(subst->name)) == 0) { | |
171 | type = subst->type; | |
172 | tail = head + strlen(subst->name)+1; | |
173 | dbg(event->udev, "will substitute format name '%s'\n", subst->name); | |
174 | goto found; | |
175 | } | |
176 | } | |
177 | head[0] = '$'; | |
178 | err(event->udev, "unknown format variable '%s'\n", head); | |
179 | } else if (head[0] == '%') { | |
180 | /* substitute format char */ | |
181 | if (head[1] == '\0') | |
182 | break; | |
183 | if (head[1] == '%') { | |
184 | util_strlcpy(temp, head+2, sizeof(temp)); | |
185 | util_strlcpy(head+1, temp, maxsize); | |
186 | head++; | |
187 | continue; | |
188 | } | |
189 | head[0] = '\0'; | |
190 | tail = head+1; | |
191 | len = get_format_len(event->udev, &tail); | |
192 | for (subst = map; subst->name; subst++) { | |
193 | if (tail[0] == subst->fmt) { | |
194 | type = subst->type; | |
195 | tail++; | |
196 | dbg(event->udev, "will substitute format char '%c'\n", subst->fmt); | |
197 | goto found; | |
198 | } | |
199 | } | |
200 | head[0] = '%'; | |
201 | err(event->udev, "unknown format char '%c'\n", tail[0]); | |
202 | } | |
203 | head++; | |
204 | } | |
205 | break; | |
206 | found: | |
207 | attr = get_format_attribute(event->udev, &tail); | |
208 | util_strlcpy(temp, tail, sizeof(temp)); | |
209 | dbg(event->udev, "format=%i, string='%s', tail='%s'\n", type ,string, tail); | |
210 | ||
211 | switch (type) { | |
212 | case SUBST_DEVPATH: | |
213 | util_strlcat(string, udev_device_get_devpath(dev), maxsize); | |
214 | dbg(event->udev, "substitute devpath '%s'\n", udev_device_get_devpath(dev)); | |
215 | break; | |
216 | case SUBST_KERNEL: | |
217 | util_strlcat(string, udev_device_get_sysname(dev), maxsize); | |
218 | dbg(event->udev, "substitute kernel name '%s'\n", udev_device_get_sysname(dev)); | |
219 | break; | |
220 | case SUBST_KERNEL_NUMBER: | |
221 | if (udev_device_get_sysnum(dev) == NULL) | |
222 | break; | |
223 | util_strlcat(string, udev_device_get_sysnum(dev), maxsize); | |
224 | dbg(event->udev, "substitute kernel number '%s'\n", udev_device_get_sysnum(dev)); | |
225 | break; | |
226 | case SUBST_ID: | |
227 | if (event->dev_parent != NULL) { | |
228 | util_strlcat(string, udev_device_get_sysname(event->dev_parent), maxsize); | |
229 | dbg(event->udev, "substitute id '%s'\n", udev_device_get_sysname(event->dev_parent)); | |
230 | } | |
231 | break; | |
232 | case SUBST_DRIVER: | |
233 | if (event->dev_parent != NULL) { | |
234 | const char *driver = udev_device_get_driver(event->dev_parent); | |
235 | ||
236 | if (driver == NULL) | |
237 | break; | |
238 | util_strlcat(string, driver, maxsize); | |
239 | dbg(event->udev, "substitute driver '%s'\n", driver); | |
240 | } | |
241 | break; | |
242 | case SUBST_MAJOR: | |
243 | sprintf(temp2, "%d", major(udev_device_get_devnum(dev))); | |
244 | util_strlcat(string, temp2, maxsize); | |
245 | dbg(event->udev, "substitute major number '%s'\n", temp2); | |
246 | break; | |
247 | case SUBST_MINOR: | |
248 | sprintf(temp2, "%d", minor(udev_device_get_devnum(dev))); | |
249 | util_strlcat(string, temp2, maxsize); | |
250 | dbg(event->udev, "substitute minor number '%s'\n", temp2); | |
251 | break; | |
252 | case SUBST_RESULT: | |
40fd3bc8 | 253 | if (event->program_result == NULL) |
f1128767 KS |
254 | break; |
255 | /* get part part of the result string */ | |
256 | i = 0; | |
257 | if (attr != NULL) | |
258 | i = strtoul(attr, &rest, 10); | |
259 | if (i > 0) { | |
40fd3bc8 KS |
260 | char result[UTIL_PATH_SIZE]; |
261 | ||
f1128767 | 262 | dbg(event->udev, "request part #%d of result string\n", i); |
40fd3bc8 KS |
263 | util_strlcpy(result, event->program_result, sizeof(result)); |
264 | cpos = result; | |
f1128767 KS |
265 | while (--i) { |
266 | while (cpos[0] != '\0' && !isspace(cpos[0])) | |
267 | cpos++; | |
268 | while (isspace(cpos[0])) | |
269 | cpos++; | |
270 | } | |
271 | if (i > 0) { | |
272 | err(event->udev, "requested part of result string not found\n"); | |
273 | break; | |
274 | } | |
275 | util_strlcpy(temp2, cpos, sizeof(temp2)); | |
276 | /* %{2+}c copies the whole string from the second part on */ | |
277 | if (rest[0] != '+') { | |
278 | cpos = strchr(temp2, ' '); | |
279 | if (cpos) | |
280 | cpos[0] = '\0'; | |
281 | } | |
282 | util_strlcat(string, temp2, maxsize); | |
283 | dbg(event->udev, "substitute part of result string '%s'\n", temp2); | |
284 | } else { | |
285 | util_strlcat(string, event->program_result, maxsize); | |
286 | dbg(event->udev, "substitute result string '%s'\n", event->program_result); | |
287 | } | |
288 | break; | |
289 | case SUBST_ATTR: | |
290 | if (attr == NULL) | |
291 | err(event->udev, "missing file parameter for attr\n"); | |
292 | else { | |
6880b25d | 293 | const char *val; |
1822e9b0 | 294 | char value[UTIL_NAME_SIZE]; |
f1128767 KS |
295 | size_t size; |
296 | ||
1822e9b0 | 297 | value[0] = '\0'; |
dc4c7e46 | 298 | /* read the value specified by [usb/]*/ |
6880b25d KS |
299 | util_resolve_subsys_kernel(event->udev, attr, value, sizeof(value), 1); |
300 | ||
dc4c7e46 KS |
301 | /* try to read attribute of the current device */ |
302 | if (value[0] == '\0') { | |
303 | val = udev_device_get_sysattr_value(event->dev, attr); | |
304 | if (val != NULL) | |
305 | util_strlcpy(value, val, sizeof(value)); | |
306 | } | |
f1128767 | 307 | |
dc4c7e46 | 308 | /* try to read the attribute of the parent device, other matches have selected */ |
f1128767 | 309 | if (value[0] == '\0' && event->dev_parent != NULL && event->dev_parent != event->dev) { |
69239210 | 310 | val = udev_device_get_sysattr_value(event->dev_parent, attr); |
f1128767 KS |
311 | if (val != NULL) |
312 | util_strlcpy(value, val, sizeof(value)); | |
313 | } | |
314 | ||
f1128767 KS |
315 | if (value[0]=='\0') |
316 | break; | |
317 | ||
318 | /* strip trailing whitespace, and replace unwanted characters */ | |
319 | size = strlen(value); | |
320 | while (size > 0 && isspace(value[--size])) | |
321 | value[size] = '\0'; | |
92f43136 | 322 | count = udev_util_replace_chars(value, UDEV_ALLOWED_CHARS_INPUT); |
f1128767 KS |
323 | if (count > 0) |
324 | info(event->udev, "%i character(s) replaced\n" , count); | |
325 | util_strlcat(string, value, maxsize); | |
326 | dbg(event->udev, "substitute sysfs value '%s'\n", value); | |
327 | } | |
328 | break; | |
329 | case SUBST_PARENT: | |
330 | { | |
331 | struct udev_device *dev_parent; | |
332 | const char *devnode; | |
333 | ||
334 | dev_parent = udev_device_get_parent(event->dev); | |
335 | if (dev_parent == NULL) | |
336 | break; | |
337 | devnode = udev_device_get_devnode(dev_parent); | |
338 | if (devnode != NULL) { | |
339 | size_t devlen = strlen(udev_get_dev_path(event->udev))+1; | |
340 | ||
341 | util_strlcat(string, &devnode[devlen], maxsize); | |
342 | dbg(event->udev, "found parent '%s', got node name '%s'\n", | |
343 | udev_device_get_syspath(dev_parent), &devnode[devlen]); | |
344 | } | |
345 | } | |
346 | break; | |
347 | case SUBST_TEMP_NODE: | |
5a05e120 KS |
348 | { |
349 | dev_t devnum; | |
350 | struct stat statbuf; | |
351 | char filename[UTIL_PATH_SIZE]; | |
352 | const char *devtype; | |
353 | ||
40fd3bc8 | 354 | if (event->tmp_node != NULL) { |
5a05e120 KS |
355 | util_strlcat(string, event->tmp_node, maxsize); |
356 | dbg(event->udev, "return existing temporary node\n"); | |
357 | break; | |
358 | } | |
359 | devnum = udev_device_get_devnum(dev); | |
360 | if (major(udev_device_get_devnum(dev) == 0)) | |
361 | break; | |
362 | if (strcmp(udev_device_get_subsystem(dev), "block") == 0) | |
363 | devtype = "block"; | |
364 | else | |
365 | devtype = "char"; | |
366 | snprintf(filename, sizeof(filename), "%s/%s/%u:%u", | |
367 | udev_get_dev_path(event->udev), devtype, | |
368 | major(udev_device_get_devnum(dev)), | |
369 | minor(udev_device_get_devnum(dev))); | |
370 | if (stat(filename, &statbuf) == 0 && statbuf.st_rdev == devnum) { | |
371 | util_strlcat(string, filename, maxsize); | |
372 | dbg(event->udev, "return existing temporary node\n"); | |
373 | break; | |
374 | } | |
375 | dbg(event->udev, "create temporary node\n"); | |
40fd3bc8 | 376 | asprintf(&event->tmp_node, "%s/.tmp-%s-%u:%u", |
5a05e120 KS |
377 | udev_get_dev_path(event->udev), devtype, |
378 | major(udev_device_get_devnum(dev)), | |
379 | minor(udev_device_get_devnum(dev))); | |
40fd3bc8 KS |
380 | if (event->tmp_node == NULL) |
381 | break; | |
5a05e120 KS |
382 | udev_node_mknod(dev, event->tmp_node, makedev(0, 0), 0600, 0, 0); |
383 | util_strlcat(string, event->tmp_node, maxsize); | |
f1128767 | 384 | } |
f1128767 KS |
385 | break; |
386 | case SUBST_NAME: | |
387 | if (event->name != NULL) { | |
388 | util_strlcat(string, event->name, maxsize); | |
389 | dbg(event->udev, "substitute name '%s'\n", event->name); | |
390 | } else { | |
391 | util_strlcat(string, udev_device_get_sysname(dev), maxsize); | |
392 | dbg(event->udev, "substitute sysname '%s'\n", udev_device_get_sysname(dev)); | |
393 | } | |
394 | break; | |
395 | case SUBST_LINKS: | |
396 | { | |
397 | struct udev_list_entry *list_entry; | |
398 | ||
7c4573e4 KS |
399 | list_entry = udev_device_get_devlinks_list_entry(dev); |
400 | util_strlcat(string, udev_list_entry_get_name(list_entry), maxsize); | |
f1128767 KS |
401 | udev_list_entry_foreach(list_entry, udev_list_entry_get_next(list_entry)) { |
402 | util_strlcat(string, " ", maxsize); | |
403 | util_strlcat(string, udev_list_entry_get_name(list_entry), maxsize); | |
404 | } | |
405 | } | |
406 | break; | |
407 | case SUBST_ROOT: | |
408 | util_strlcat(string, udev_get_dev_path(event->udev), maxsize); | |
409 | dbg(event->udev, "substitute udev_root '%s'\n", udev_get_dev_path(event->udev)); | |
410 | break; | |
411 | case SUBST_SYS: | |
412 | util_strlcat(string, udev_get_sys_path(event->udev), maxsize); | |
413 | dbg(event->udev, "substitute sys_path '%s'\n", udev_get_sys_path(event->udev)); | |
414 | break; | |
415 | case SUBST_ENV: | |
416 | if (attr == NULL) { | |
417 | dbg(event->udev, "missing attribute\n"); | |
418 | break; | |
419 | } else { | |
420 | struct udev_list_entry *list_entry; | |
421 | const char *value; | |
422 | ||
423 | list_entry = udev_device_get_properties_list_entry(event->dev); | |
424 | list_entry = udev_list_entry_get_by_name(list_entry, attr); | |
425 | if (list_entry == NULL) | |
426 | break; | |
427 | value = udev_list_entry_get_value(list_entry); | |
428 | dbg(event->udev, "substitute env '%s=%s'\n", attr, value); | |
429 | util_strlcat(string, value, maxsize); | |
430 | break; | |
431 | } | |
432 | default: | |
433 | err(event->udev, "unknown substitution type=%i\n", type); | |
434 | break; | |
435 | } | |
436 | /* possibly truncate to format-char specified length */ | |
437 | if (len >= 0 && len < (int)strlen(head)) { | |
438 | head[len] = '\0'; | |
439 | dbg(event->udev, "truncate to %i chars, subtitution string becomes '%s'\n", len, head); | |
440 | } | |
441 | util_strlcat(string, temp, maxsize); | |
442 | } | |
443 | } | |
444 | ||
445 | static void rename_netif_kernel_log(struct ifreq ifr) | |
d46f37fd KS |
446 | { |
447 | int klog; | |
448 | FILE *f; | |
449 | ||
450 | klog = open("/dev/kmsg", O_WRONLY); | |
451 | if (klog < 0) | |
452 | return; | |
453 | ||
454 | f = fdopen(klog, "w"); | |
455 | if (f == NULL) { | |
456 | close(klog); | |
457 | return; | |
458 | } | |
459 | ||
460 | fprintf(f, "<6>udev: renamed network interface %s to %s\n", | |
461 | ifr.ifr_name, ifr.ifr_newname); | |
462 | fclose(f); | |
463 | } | |
464 | ||
aa8734ff | 465 | static int rename_netif(struct udev_event *event) |
d46f37fd | 466 | { |
aa8734ff | 467 | struct udev_device *dev = event->dev; |
d46f37fd KS |
468 | int sk; |
469 | struct ifreq ifr; | |
aa8734ff | 470 | int err; |
d46f37fd | 471 | |
aa8734ff KS |
472 | info(event->udev, "changing net interface name from '%s' to '%s'\n", |
473 | udev_device_get_sysname(dev), event->name); | |
474 | if (event->test) | |
d46f37fd KS |
475 | return 0; |
476 | ||
477 | sk = socket(PF_INET, SOCK_DGRAM, 0); | |
478 | if (sk < 0) { | |
aa8734ff | 479 | err(event->udev, "error opening socket: %m\n"); |
d46f37fd KS |
480 | return -1; |
481 | } | |
482 | ||
483 | memset(&ifr, 0x00, sizeof(struct ifreq)); | |
aa8734ff KS |
484 | util_strlcpy(ifr.ifr_name, udev_device_get_sysname(dev), IFNAMSIZ); |
485 | util_strlcpy(ifr.ifr_newname, event->name, IFNAMSIZ); | |
486 | err = ioctl(sk, SIOCSIFNAME, &ifr); | |
487 | if (err == 0) | |
f1128767 | 488 | rename_netif_kernel_log(ifr); |
d46f37fd KS |
489 | else { |
490 | int loop; | |
491 | ||
492 | /* see if the destination interface name already exists */ | |
493 | if (errno != EEXIST) { | |
aa8734ff | 494 | err(event->udev, "error changing netif name %s to %s: %m\n", |
659353f5 | 495 | ifr.ifr_name, ifr.ifr_newname); |
d46f37fd KS |
496 | goto exit; |
497 | } | |
498 | ||
499 | /* free our own name, another process may wait for us */ | |
aa8734ff | 500 | util_strlcpy(ifr.ifr_newname, udev_device_get_sysname(dev), IFNAMSIZ); |
31c1f537 | 501 | util_strlcat(ifr.ifr_newname, "_rename", IFNAMSIZ); |
aa8734ff KS |
502 | err = ioctl(sk, SIOCSIFNAME, &ifr); |
503 | if (err != 0) { | |
504 | err(event->udev, "error changing netif name %s to %s: %m\n", | |
659353f5 | 505 | ifr.ifr_name, ifr.ifr_newname); |
d46f37fd KS |
506 | goto exit; |
507 | } | |
508 | ||
509 | /* wait 30 seconds for our target to become available */ | |
31c1f537 | 510 | util_strlcpy(ifr.ifr_name, ifr.ifr_newname, IFNAMSIZ); |
aa8734ff | 511 | util_strlcpy(ifr.ifr_newname, udev_device_get_devnode(dev), IFNAMSIZ); |
d46f37fd KS |
512 | loop = 30 * 20; |
513 | while (loop--) { | |
aa8734ff KS |
514 | err = ioctl(sk, SIOCSIFNAME, &ifr); |
515 | if (err == 0) { | |
f1128767 | 516 | rename_netif_kernel_log(ifr); |
d46f37fd KS |
517 | break; |
518 | } | |
519 | ||
520 | if (errno != EEXIST) { | |
aa8734ff | 521 | err(event->udev, "error changing net interface name %s to %s: %m\n", |
659353f5 | 522 | ifr.ifr_name, ifr.ifr_newname); |
d46f37fd KS |
523 | break; |
524 | } | |
aa8734ff KS |
525 | dbg(event->udev, "wait for netif '%s' to become free, loop=%i\n", |
526 | udev_device_get_devnode(dev), (30 * 20) - loop); | |
d46f37fd KS |
527 | usleep(1000 * 1000 / 20); |
528 | } | |
529 | } | |
d46f37fd KS |
530 | exit: |
531 | close(sk); | |
aa8734ff | 532 | return err; |
d46f37fd KS |
533 | } |
534 | ||
dcdcb8cc | 535 | int udev_event_execute_rules(struct udev_event *event, struct udev_rules *rules) |
d46f37fd | 536 | { |
aa8734ff KS |
537 | struct udev_device *dev = event->dev; |
538 | int err = 0; | |
d46f37fd | 539 | |
aa8734ff KS |
540 | if (udev_device_get_devpath_old(dev) != NULL) { |
541 | if (udev_device_rename_db(dev, udev_device_get_devpath(dev)) == 0) | |
542 | info(event->udev, "moved database from '%s' to '%s'\n", | |
543 | udev_device_get_devpath_old(dev), udev_device_get_devpath(dev)); | |
544 | } | |
d46f37fd KS |
545 | |
546 | /* add device node */ | |
aa8734ff KS |
547 | if (major(udev_device_get_devnum(dev)) != 0 && |
548 | (strcmp(udev_device_get_action(dev), "add") == 0 || strcmp(udev_device_get_action(dev), "change") == 0)) { | |
549 | char filename[UTIL_PATH_SIZE]; | |
550 | struct udev_device *dev_old; | |
d46f37fd | 551 | |
aa8734ff | 552 | dbg(event->udev, "device node add '%s'\n", udev_device_get_devpath(dev)); |
d46f37fd | 553 | |
6880b25d | 554 | udev_rules_apply_to_event(rules, event); |
40fd3bc8 | 555 | if (event->tmp_node != NULL) { |
6880b25d KS |
556 | dbg(event->udev, "removing temporary device node\n"); |
557 | util_unlink_secure(event->udev, event->tmp_node); | |
40fd3bc8 KS |
558 | free(event->tmp_node); |
559 | event->tmp_node = NULL; | |
6880b25d KS |
560 | } |
561 | ||
aa8734ff KS |
562 | if (event->ignore_device) { |
563 | info(event->udev, "device event will be ignored\n"); | |
d46f37fd KS |
564 | goto exit; |
565 | } | |
aa8734ff | 566 | |
b99028c9 | 567 | if (event->name != NULL && event->name[0] == '\0') { |
aa8734ff | 568 | info(event->udev, "device node creation supressed\n"); |
d46f37fd KS |
569 | goto exit; |
570 | } | |
571 | ||
b99028c9 | 572 | if (event->name == NULL) { |
6880b25d KS |
573 | info(event->udev, "no node name set, will use kernel name '%s'\n", |
574 | udev_device_get_sysname(event->dev)); | |
b99028c9 KS |
575 | event->name = strdup(udev_device_get_sysname(event->dev)); |
576 | if (event->name == NULL) | |
577 | goto exit; | |
6880b25d KS |
578 | } |
579 | ||
aa8734ff KS |
580 | /* set device node name */ |
581 | util_strlcpy(filename, udev_get_dev_path(event->udev), sizeof(filename)); | |
582 | util_strlcat(filename, "/", sizeof(filename)); | |
583 | util_strlcat(filename, event->name, sizeof(filename)); | |
584 | udev_device_set_devnode(dev, filename); | |
585 | ||
6e0cb78c | 586 | /* read current database entry */ |
aa8734ff | 587 | dev_old = udev_device_new_from_syspath(event->udev, udev_device_get_syspath(dev)); |
77b852f3 KS |
588 | if (dev_old != NULL) { |
589 | udev_device_read_db(dev_old); | |
590 | udev_device_set_info_loaded(dev_old); | |
591 | } | |
d46f37fd | 592 | |
6e0cb78c | 593 | /* update database, create node and symlinks */ |
aa8734ff | 594 | udev_device_update_db(dev); |
6880b25d | 595 | err = udev_node_add(dev, event->mode, event->uid, event->gid, event->test); |
d46f37fd | 596 | |
6e0cb78c KS |
597 | /* remove/update possible left-over symlinks from old database entry */ |
598 | if (dev_old != NULL) { | |
599 | udev_node_update_old_links(dev, dev_old, event->test); | |
600 | udev_device_unref(dev_old); | |
601 | } | |
d46f37fd KS |
602 | goto exit; |
603 | } | |
604 | ||
605 | /* add netif */ | |
aa8734ff KS |
606 | if (strcmp(udev_device_get_subsystem(dev), "net") == 0 && strcmp(udev_device_get_action(dev), "add") == 0) { |
607 | dbg(event->udev, "netif add '%s'\n", udev_device_get_devpath(dev)); | |
608 | ||
6880b25d | 609 | udev_rules_apply_to_event(rules, event); |
aa8734ff KS |
610 | if (event->ignore_device) { |
611 | info(event->udev, "device event will be ignored\n"); | |
d46f37fd KS |
612 | goto exit; |
613 | } | |
b99028c9 | 614 | if (event->name == NULL) |
d46f37fd | 615 | goto exit; |
d46f37fd KS |
616 | |
617 | /* look if we want to change the name of the netif */ | |
aa8734ff KS |
618 | if (strcmp(event->name, udev_device_get_sysname(dev)) != 0) { |
619 | char syspath[UTIL_PATH_SIZE]; | |
d46f37fd KS |
620 | char *pos; |
621 | ||
aa8734ff KS |
622 | err = rename_netif(event); |
623 | if (err != 0) | |
d46f37fd | 624 | goto exit; |
aa8734ff | 625 | info(event->udev, "renamed netif to '%s'\n", event->name); |
d46f37fd | 626 | |
aa8734ff KS |
627 | /* remember old name */ |
628 | udev_device_add_property(dev, "INTERFACE_OLD", udev_device_get_sysname(dev)); | |
d46f37fd KS |
629 | |
630 | /* now change the devpath, because the kernel device name has changed */ | |
aa8734ff KS |
631 | util_strlcpy(syspath, udev_device_get_syspath(dev), sizeof(syspath)); |
632 | pos = strrchr(syspath, '/'); | |
d46f37fd KS |
633 | if (pos != NULL) { |
634 | pos[1] = '\0'; | |
aa8734ff KS |
635 | util_strlcat(syspath, event->name, sizeof(syspath)); |
636 | udev_device_set_syspath(event->dev, syspath); | |
637 | udev_device_add_property(dev, "INTERFACE", udev_device_get_sysname(dev)); | |
638 | info(event->udev, "changed devpath to '%s'\n", udev_device_get_devpath(dev)); | |
d46f37fd KS |
639 | } |
640 | } | |
641 | goto exit; | |
642 | } | |
643 | ||
644 | /* remove device node */ | |
aa8734ff KS |
645 | if (major(udev_device_get_devnum(dev)) != 0 && strcmp(udev_device_get_action(dev), "remove") == 0) { |
646 | /* import database entry and delete it */ | |
77b852f3 KS |
647 | udev_device_read_db(dev); |
648 | udev_device_set_info_loaded(dev); | |
6e0cb78c | 649 | udev_device_delete_db(dev); |
aa8734ff KS |
650 | |
651 | if (udev_device_get_devnode(dev) == NULL) { | |
652 | char devnode[UTIL_PATH_SIZE]; | |
653 | ||
654 | info(event->udev, "'%s' not found in database, using kernel name '%s'\n", | |
655 | udev_device_get_syspath(dev), udev_device_get_sysname(dev)); | |
656 | util_strlcpy(devnode, udev_get_dev_path(event->udev), sizeof(devnode)); | |
657 | util_strlcat(devnode, "/", sizeof(devnode)); | |
658 | util_strlcat(devnode, udev_device_get_sysname(dev), sizeof(devnode)); | |
659 | udev_device_set_devnode(dev, devnode); | |
d46f37fd KS |
660 | } |
661 | ||
6880b25d | 662 | udev_rules_apply_to_event(rules, event); |
aa8734ff KS |
663 | if (event->ignore_device) { |
664 | info(event->udev, "device event will be ignored\n"); | |
d46f37fd KS |
665 | goto exit; |
666 | } | |
667 | ||
aa8734ff KS |
668 | if (udev_device_get_ignore_remove(dev)) { |
669 | info(event->udev, "ignore_remove for '%s'\n", udev_device_get_devnode(dev)); | |
d46f37fd KS |
670 | goto exit; |
671 | } | |
d46f37fd | 672 | |
aa8734ff | 673 | err = udev_node_remove(dev, event->test); |
d46f37fd KS |
674 | goto exit; |
675 | } | |
676 | ||
677 | /* default devices */ | |
6880b25d | 678 | udev_rules_apply_to_event(rules, event); |
aa8734ff KS |
679 | if (event->ignore_device) |
680 | info(event->udev, "device event will be ignored\n"); | |
d46f37fd | 681 | exit: |
aa8734ff | 682 | return err; |
d46f37fd | 683 | } |
2d73813e KS |
684 | |
685 | int udev_event_execute_run(struct udev_event *event) | |
686 | { | |
687 | struct udev_list_entry *list_entry; | |
688 | int err = 0; | |
689 | ||
690 | dbg(event->udev, "executing run list\n"); | |
691 | udev_list_entry_foreach(list_entry, udev_list_get_entry(&event->run_list)) { | |
692 | const char *cmd = udev_list_entry_get_name(list_entry); | |
693 | ||
694 | if (strncmp(cmd, "socket:", strlen("socket:")) == 0) { | |
695 | struct udev_monitor *monitor; | |
696 | ||
697 | monitor = udev_monitor_new_from_socket(event->udev, &cmd[strlen("socket:")]); | |
698 | if (monitor == NULL) | |
699 | continue; | |
700 | udev_monitor_send_device(monitor, event->dev); | |
701 | udev_monitor_unref(monitor); | |
702 | } else { | |
703 | char program[UTIL_PATH_SIZE]; | |
704 | char **envp; | |
705 | ||
706 | util_strlcpy(program, cmd, sizeof(program)); | |
f1128767 | 707 | udev_event_apply_format(event, program, sizeof(program)); |
0bc74ea7 | 708 | if (event->trace) |
27691aa3 | 709 | fprintf(stderr, "run %s (%llu) '%s'\n", |
0bc74ea7 KS |
710 | udev_device_get_syspath(event->dev), |
711 | udev_device_get_seqnum(event->dev), | |
712 | program); | |
2d73813e | 713 | envp = udev_device_get_properties_envp(event->dev); |
54808d77 | 714 | if (util_run_program(event->udev, program, envp, NULL, 0, NULL) != 0) { |
2d73813e KS |
715 | if (!udev_list_entry_get_flag(list_entry)) |
716 | err = -1; | |
717 | } | |
718 | } | |
719 | } | |
720 | return err; | |
721 | } |