]>
Commit | Line | Data |
---|---|---|
7fafc032 | 1 | /* |
55e9959b | 2 | * Copyright (C) 2004-2008 Kay Sievers <kay.sievers@vrfy.org> |
2f6cbd19 | 3 | * Copyright (C) 2004 Chris Friesen <chris_friesen@sympatico.ca> |
7fafc032 | 4 | * |
55e9959b KS |
5 | * This program is free software: you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation, either version 2 of the License, or | |
8 | * (at your option) any later version. | |
7fafc032 | 9 | * |
55e9959b KS |
10 | * This program is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
7fafc032 | 14 | * |
55e9959b KS |
15 | * You should have received a copy of the GNU General Public License |
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
7fafc032 KS |
17 | */ |
18 | ||
a695feae | 19 | #include <stddef.h> |
7fafc032 KS |
20 | #include <signal.h> |
21 | #include <unistd.h> | |
22 | #include <errno.h> | |
23 | #include <stdio.h> | |
24 | #include <stdlib.h> | |
25 | #include <string.h> | |
085cce37 | 26 | #include <ctype.h> |
085cce37 | 27 | #include <fcntl.h> |
0b3dfb3d | 28 | #include <time.h> |
b52a01ee | 29 | #include <getopt.h> |
78230c0d | 30 | #include <dirent.h> |
138068d6 | 31 | #include <sys/select.h> |
3210a72b | 32 | #include <sys/poll.h> |
138068d6 | 33 | #include <sys/wait.h> |
dc117daa | 34 | #include <sys/stat.h> |
c895fd00 | 35 | #include <sys/ioctl.h> |
01618658 KS |
36 | #ifdef HAVE_INOTIFY |
37 | #include <sys/inotify.h> | |
38 | #endif | |
7fafc032 KS |
39 | |
40 | #include "udev.h" | |
7fafc032 | 41 | |
d59f11e1 KS |
42 | #define UDEVD_PRIORITY -4 |
43 | #define UDEV_PRIORITY -2 | |
44 | ||
45 | /* maximum limit of forked childs */ | |
46 | #define UDEVD_MAX_CHILDS 256 | |
d59f11e1 | 47 | |
c70560fe | 48 | static int debug; |
9e8fe79b | 49 | |
7d563a17 KS |
50 | static void log_fn(struct udev *udev, int priority, |
51 | const char *file, int line, const char *fn, | |
52 | const char *format, va_list args) | |
53 | { | |
54 | if (debug) { | |
55 | fprintf(stderr, "[%d] %s: ", (int) getpid(), fn); | |
56 | vfprintf(stderr, format, args); | |
57 | } else { | |
58 | vsyslog(priority, format, args); | |
59 | } | |
60 | } | |
61 | ||
d1cc6562 OK |
62 | static void reap_sigchilds(void); |
63 | ||
7d563a17 | 64 | static int debug_trace; |
d7ddce18 | 65 | static struct udev_rules *rules; |
d59f11e1 | 66 | static struct udev_ctrl *udev_ctrl; |
aa8734ff | 67 | static struct udev_monitor *kernel_monitor; |
5cab7caa | 68 | static volatile int sigchilds_waiting; |
63cc8f04 | 69 | static volatile int udev_exit; |
c895fd00 | 70 | static volatile int reload_config; |
3210a72b | 71 | static volatile int signal_received; |
f27125f9 | 72 | static int run_exec_q; |
3b47c739 | 73 | static int stop_exec_q; |
a15f42c4 | 74 | static int max_childs; |
0bc74ea7 KS |
75 | static int childs; |
76 | static struct udev_list_node event_list; | |
a15f42c4 | 77 | |
7a770250 KS |
78 | enum event_state { |
79 | EVENT_QUEUED, | |
80 | EVENT_FINISHED, | |
81 | EVENT_FAILED, | |
82 | }; | |
83 | ||
7e027927 KS |
84 | static struct udev_event *node_to_event(struct udev_list_node *node) |
85 | { | |
86 | char *event; | |
87 | ||
88 | event = (char *)node; | |
89 | event -= offsetof(struct udev_event, node); | |
90 | return (struct udev_event *)event; | |
91 | } | |
92 | ||
aa8734ff | 93 | static void export_event_state(struct udev_event *event, enum event_state state) |
7a770250 | 94 | { |
17fcfb59 KS |
95 | char filename[UTIL_PATH_SIZE]; |
96 | char filename_failed[UTIL_PATH_SIZE]; | |
9c6ad9fb | 97 | size_t start; |
7a770250 | 98 | |
a2f2270e | 99 | /* location of queue file */ |
aa8734ff KS |
100 | snprintf(filename, sizeof(filename), "%s/.udev/queue/%llu", |
101 | udev_get_dev_path(event->udev), udev_device_get_seqnum(event->dev)); | |
7a770250 | 102 | |
a2f2270e | 103 | /* location of failed file */ |
aa8734ff | 104 | util_strlcpy(filename_failed, udev_get_dev_path(event->udev), sizeof(filename_failed)); |
31c1f537 KS |
105 | util_strlcat(filename_failed, "/", sizeof(filename_failed)); |
106 | start = util_strlcat(filename_failed, ".udev/failed/", sizeof(filename_failed)); | |
aa8734ff | 107 | util_strlcat(filename_failed, udev_device_get_devpath(event->dev), sizeof(filename_failed)); |
ecc9ec57 | 108 | util_path_encode(&filename_failed[start], sizeof(filename_failed) - start); |
7a770250 KS |
109 | |
110 | switch (state) { | |
111 | case EVENT_QUEUED: | |
836dcf95 | 112 | if(unlink(filename_failed) == 0) |
54808d77 KS |
113 | util_delete_path(event->udev, filename_failed); |
114 | util_create_path(event->udev, filename); | |
aa8734ff KS |
115 | udev_selinux_setfscreatecon(event->udev, filename, S_IFLNK); |
116 | symlink(udev_device_get_devpath(event->dev), filename); | |
117 | udev_selinux_resetfscreatecon(event->udev); | |
ce398745 | 118 | break; |
7a770250 | 119 | case EVENT_FINISHED: |
aa8734ff | 120 | if (udev_device_get_devpath_old(event->dev) != NULL) { |
a2f2270e | 121 | /* "move" event - rename failed file to current name, do not delete failed */ |
17fcfb59 | 122 | char filename_failed_old[UTIL_PATH_SIZE]; |
a2f2270e | 123 | |
aa8734ff | 124 | util_strlcpy(filename_failed_old, udev_get_dev_path(event->udev), sizeof(filename_failed_old)); |
31c1f537 KS |
125 | util_strlcat(filename_failed_old, "/", sizeof(filename_failed_old)); |
126 | start = util_strlcat(filename_failed_old, ".udev/failed/", sizeof(filename_failed_old)); | |
aa8734ff | 127 | util_strlcat(filename_failed_old, udev_device_get_devpath_old(event->dev), sizeof(filename_failed_old)); |
ecc9ec57 | 128 | util_path_encode(&filename_failed_old[start], sizeof(filename) - start); |
a2f2270e KS |
129 | |
130 | if (rename(filename_failed_old, filename_failed) == 0) | |
aa8734ff KS |
131 | info(event->udev, "renamed devpath, moved failed state of '%s' to %s'\n", |
132 | udev_device_get_devpath_old(event->dev), udev_device_get_devpath(event->dev)); | |
a2f2270e | 133 | } else { |
836dcf95 | 134 | if (unlink(filename_failed) == 0) |
54808d77 | 135 | util_delete_path(event->udev, filename_failed); |
a2f2270e | 136 | } |
7a770250 | 137 | |
ce398745 | 138 | unlink(filename); |
836dcf95 AJ |
139 | |
140 | /* clean up possibly empty queue directory */ | |
0bc74ea7 | 141 | if (udev_list_is_empty(&event_list)) |
54808d77 | 142 | util_delete_path(event->udev, filename); |
ce398745 KS |
143 | break; |
144 | case EVENT_FAILED: | |
a2f2270e | 145 | /* move failed event to the failed directory */ |
54808d77 | 146 | util_create_path(event->udev, filename_failed); |
ce398745 | 147 | rename(filename, filename_failed); |
1b75f109 | 148 | |
a2f2270e | 149 | /* clean up possibly empty queue directory */ |
0bc74ea7 | 150 | if (udev_list_is_empty(&event_list)) |
54808d77 | 151 | util_delete_path(event->udev, filename); |
ce398745 | 152 | break; |
7a770250 | 153 | } |
ce398745 KS |
154 | |
155 | return; | |
7a770250 KS |
156 | } |
157 | ||
aa8734ff | 158 | static void event_queue_delete(struct udev_event *event) |
fc465079 | 159 | { |
7e027927 | 160 | udev_list_node_remove(&event->node); |
7a770250 | 161 | |
a2f2270e | 162 | /* mark as failed, if "add" event returns non-zero */ |
aa8734ff KS |
163 | if (event->exitstatus && strcmp(udev_device_get_action(event->dev), "add") == 0) |
164 | export_event_state(event, EVENT_FAILED); | |
7a770250 | 165 | else |
aa8734ff KS |
166 | export_event_state(event, EVENT_FINISHED); |
167 | ||
168 | udev_device_unref(event->dev); | |
169 | udev_event_unref(event); | |
170 | } | |
7a770250 | 171 | |
aa8734ff KS |
172 | static void asmlinkage event_sig_handler(int signum) |
173 | { | |
174 | if (signum == SIGALRM) | |
175 | exit(1); | |
fc465079 KS |
176 | } |
177 | ||
aa8734ff | 178 | static void event_fork(struct udev_event *event) |
7fafc032 | 179 | { |
90c210eb | 180 | pid_t pid; |
aa8734ff KS |
181 | struct sigaction act; |
182 | int err; | |
90c210eb | 183 | |
0bc74ea7 KS |
184 | if (debug_trace) { |
185 | event->trace = 1; | |
27691aa3 | 186 | fprintf(stderr, "fork %s (%llu)\n", |
0bc74ea7 KS |
187 | udev_device_get_syspath(event->dev), |
188 | udev_device_get_seqnum(event->dev)); | |
189 | } | |
190 | ||
90c210eb KS |
191 | pid = fork(); |
192 | switch (pid) { | |
193 | case 0: | |
33db4b8d | 194 | /* child */ |
aa8734ff | 195 | udev_monitor_unref(kernel_monitor); |
d59f11e1 | 196 | udev_ctrl_unref(udev_ctrl); |
f602ccf0 | 197 | logging_close(); |
c895fd00 | 198 | logging_init("udevd-event"); |
085cce37 | 199 | setpriority(PRIO_PROCESS, 0, UDEV_PRIORITY); |
b437ec95 | 200 | |
aa8734ff KS |
201 | /* set signal handlers */ |
202 | memset(&act, 0x00, sizeof(act)); | |
203 | act.sa_handler = (void (*)(int)) event_sig_handler; | |
204 | sigemptyset (&act.sa_mask); | |
205 | act.sa_flags = 0; | |
206 | sigaction(SIGALRM, &act, NULL); | |
207 | ||
208 | /* reset to default */ | |
209 | act.sa_handler = SIG_DFL; | |
210 | sigaction(SIGINT, &act, NULL); | |
211 | sigaction(SIGTERM, &act, NULL); | |
212 | sigaction(SIGCHLD, &act, NULL); | |
213 | sigaction(SIGHUP, &act, NULL); | |
214 | ||
215 | /* set timeout to prevent hanging processes */ | |
216 | alarm(UDEV_EVENT_TIMEOUT); | |
217 | ||
218 | /* apply rules, create node, symlinks */ | |
dcdcb8cc | 219 | err = udev_event_execute_rules(event, rules); |
aa8734ff KS |
220 | |
221 | /* rules may change/disable the timeout */ | |
222 | if (udev_device_get_event_timeout(event->dev) >= 0) | |
223 | alarm(udev_device_get_event_timeout(event->dev)); | |
224 | ||
225 | /* execute RUN= */ | |
226 | if (err == 0 && !event->ignore_device && udev_get_run(event->udev)) | |
2d73813e | 227 | udev_event_execute_run(event); |
0bc74ea7 | 228 | |
cb25a958 | 229 | info(event->udev, "seq %llu exit with %i\n", udev_device_get_seqnum(event->dev), err); |
c895fd00 | 230 | logging_close(); |
aa8734ff | 231 | if (err != 0) |
f4fc0136 | 232 | exit(1); |
c895fd00 | 233 | exit(0); |
90c210eb | 234 | case -1: |
aa8734ff KS |
235 | err(event->udev, "fork of child failed: %m\n"); |
236 | event_queue_delete(event); | |
2f6cbd19 | 237 | break; |
90c210eb | 238 | default: |
2f6cbd19 | 239 | /* get SIGCHLD in main loop */ |
aa8734ff KS |
240 | info(event->udev, "seq %llu forked, pid [%d], '%s' '%s', %ld seconds old\n", |
241 | udev_device_get_seqnum(event->dev), | |
242 | pid, | |
243 | udev_device_get_action(event->dev), | |
244 | udev_device_get_subsystem(event->dev), | |
245 | time(NULL) - event->queue_time); | |
246 | event->pid = pid; | |
0bc74ea7 | 247 | childs++; |
90c210eb | 248 | } |
7fafc032 KS |
249 | } |
250 | ||
aa8734ff | 251 | static void event_queue_insert(struct udev_event *event) |
fc465079 | 252 | { |
17fcfb59 | 253 | char filename[UTIL_PATH_SIZE]; |
7baada47 KS |
254 | int fd; |
255 | ||
aa8734ff | 256 | event->queue_time = time(NULL); |
7baada47 | 257 | |
aa8734ff | 258 | export_event_state(event, EVENT_QUEUED); |
cb25a958 KS |
259 | info(event->udev, "seq %llu queued, '%s' '%s'\n", udev_device_get_seqnum(event->dev), |
260 | udev_device_get_action(event->dev), udev_device_get_subsystem(event->dev)); | |
0f624f16 | 261 | |
aa8734ff | 262 | util_strlcpy(filename, udev_get_dev_path(event->udev), sizeof(filename)); |
31c1f537 | 263 | util_strlcat(filename, "/.udev/uevent_seqnum", sizeof(filename)); |
7baada47 | 264 | fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0644); |
90cd961e | 265 | if (fd >= 0) { |
7baada47 KS |
266 | char str[32]; |
267 | int len; | |
268 | ||
aa8734ff | 269 | len = sprintf(str, "%llu\n", udev_device_get_seqnum(event->dev)); |
7baada47 KS |
270 | write(fd, str, len); |
271 | close(fd); | |
272 | } | |
fc465079 | 273 | |
0bc74ea7 KS |
274 | |
275 | udev_list_node_append(&event->node, &event_list); | |
276 | run_exec_q = 1; | |
c7c00276 | 277 | |
fc465079 | 278 | /* run all events with a timeout set immediately */ |
aa8734ff | 279 | if (udev_device_get_timeout(event->dev) > 0) { |
aa8734ff | 280 | event_fork(event); |
fc465079 KS |
281 | return; |
282 | } | |
fc465079 KS |
283 | } |
284 | ||
f051e340 KS |
285 | static int mem_size_mb(void) |
286 | { | |
9f1f67b1 KS |
287 | FILE* f; |
288 | char buf[4096]; | |
289 | long int memsize = -1; | |
f051e340 | 290 | |
9f1f67b1 KS |
291 | f = fopen("/proc/meminfo", "r"); |
292 | if (f == NULL) | |
f051e340 | 293 | return -1; |
f051e340 | 294 | |
9f1f67b1 KS |
295 | while (fgets(buf, sizeof(buf), f) != NULL) { |
296 | long int value; | |
f051e340 | 297 | |
9f1f67b1 KS |
298 | if (sscanf(buf, "MemTotal: %ld kB", &value) == 1) { |
299 | memsize = value / 1024; | |
300 | break; | |
301 | } | |
302 | } | |
f051e340 | 303 | |
fdc9a0b5 | 304 | fclose(f); |
9f1f67b1 | 305 | return memsize; |
f051e340 KS |
306 | } |
307 | ||
7b6571a9 KS |
308 | static int compare_devpath(const char *running, const char *waiting) |
309 | { | |
e25fa4fa | 310 | int i = 0; |
7b6571a9 | 311 | |
0bc74ea7 | 312 | while (running[i] != '\0' && running[i] == waiting[i]) |
e25fa4fa | 313 | i++; |
7b6571a9 | 314 | |
e25fa4fa AJ |
315 | /* identical device event found */ |
316 | if (running[i] == '\0' && waiting[i] == '\0') | |
317 | return 1; | |
7b6571a9 | 318 | |
e25fa4fa AJ |
319 | /* parent device event found */ |
320 | if (running[i] == '\0' && waiting[i] == '/') | |
321 | return 2; | |
7b6571a9 | 322 | |
e25fa4fa AJ |
323 | /* child device event found */ |
324 | if (running[i] == '/' && waiting[i] == '\0') | |
325 | return 3; | |
7b6571a9 | 326 | |
e25fa4fa | 327 | /* no matching event */ |
7b6571a9 KS |
328 | return 0; |
329 | } | |
330 | ||
fc630eda | 331 | /* lookup event for identical, parent, child, or physical device */ |
0bc74ea7 | 332 | static int devpath_busy(struct udev_event *event) |
7fafc032 | 333 | { |
7e027927 | 334 | struct udev_list_node *loop; |
7b6571a9 | 335 | |
0bc74ea7 KS |
336 | if (event->delaying_seqnum > 0) { |
337 | } | |
338 | /* check if queue contains events we depend on */ | |
339 | udev_list_node_foreach(loop, &event_list) { | |
7e027927 KS |
340 | struct udev_event *loop_event = node_to_event(loop); |
341 | ||
0bc74ea7 KS |
342 | /* we already found a later event, earlier can not block us, no need to check again */ |
343 | if (udev_device_get_seqnum(loop_event->dev) < event->delaying_seqnum) | |
344 | continue; | |
345 | ||
346 | /* event we checked earlier still exists, no need to check again */ | |
347 | if (udev_device_get_seqnum(loop_event->dev) == event->delaying_seqnum) | |
348 | return 2; | |
349 | ||
350 | /* found ourself, no later event can block us */ | |
aa8734ff | 351 | if (udev_device_get_seqnum(loop_event->dev) >= udev_device_get_seqnum(event->dev)) |
fc630eda KS |
352 | break; |
353 | ||
a2f2270e | 354 | /* check our old name */ |
aa8734ff | 355 | if (udev_device_get_devpath_old(event->dev) != NULL) |
0bc74ea7 KS |
356 | if (strcmp(udev_device_get_devpath(loop_event->dev), udev_device_get_devpath_old(event->dev)) == 0) { |
357 | event->delaying_seqnum = udev_device_get_seqnum(loop_event->dev); | |
358 | return 3; | |
359 | } | |
a2f2270e | 360 | |
fc630eda | 361 | /* check identical, parent, or child device event */ |
aa8734ff KS |
362 | if (compare_devpath(udev_device_get_devpath(loop_event->dev), udev_device_get_devpath(event->dev)) != 0) { |
363 | dbg(event->udev, "%llu, device event still pending %llu (%s)\n", | |
364 | udev_device_get_seqnum(event->dev), | |
365 | udev_device_get_seqnum(loop_event->dev), | |
366 | udev_device_get_devpath(loop_event->dev)); | |
0bc74ea7 | 367 | event->delaying_seqnum = udev_device_get_seqnum(loop_event->dev); |
c3b145a3 MK |
368 | return 4; |
369 | } | |
370 | ||
c3b145a3 | 371 | /* check for our major:minor number */ |
aa8734ff KS |
372 | if (major(udev_device_get_devnum(event->dev)) > 0 && |
373 | udev_device_get_devnum(loop_event->dev) == udev_device_get_devnum(event->dev) && | |
374 | strcmp(udev_device_get_subsystem(event->dev), udev_device_get_subsystem(loop_event->dev)) == 0) { | |
375 | dbg(event->udev, "%llu, device event still pending %llu (%d:%d)\n", | |
376 | udev_device_get_seqnum(event->dev), | |
377 | udev_device_get_seqnum(loop_event->dev), | |
378 | major(udev_device_get_devnum(loop_event->dev)), minor(udev_device_get_devnum(loop_event->dev))); | |
0bc74ea7 KS |
379 | event->delaying_seqnum = udev_device_get_seqnum(loop_event->dev); |
380 | return 5; | |
c3b145a3 MK |
381 | } |
382 | ||
fc630eda | 383 | /* check physical device event (special case of parent) */ |
aa8734ff KS |
384 | if (udev_device_get_physdevpath(event->dev) != NULL && |
385 | strcmp(udev_device_get_action(event->dev), "add") == 0) | |
386 | if (compare_devpath(udev_device_get_devpath(loop_event->dev), | |
387 | udev_device_get_physdevpath(event->dev)) != 0) { | |
388 | dbg(event->udev, "%llu, physical device event still pending %llu (%s)\n", | |
389 | udev_device_get_seqnum(event->dev), | |
390 | udev_device_get_seqnum(loop_event->dev), | |
391 | udev_device_get_devpath(loop_event->dev)); | |
0bc74ea7 KS |
392 | event->delaying_seqnum = udev_device_get_seqnum(loop_event->dev); |
393 | return 6; | |
a15f42c4 | 394 | } |
80513ea3 | 395 | } |
a15f42c4 | 396 | return 0; |
7fafc032 KS |
397 | } |
398 | ||
fc630eda | 399 | /* serializes events for the identical and parent and child devices */ |
aa8734ff | 400 | static void event_queue_manager(struct udev *udev) |
7fafc032 | 401 | { |
7e027927 KS |
402 | struct udev_list_node *loop; |
403 | struct udev_list_node *tmp; | |
085cce37 | 404 | |
d1cc6562 | 405 | start_over: |
0bc74ea7 KS |
406 | if (udev_list_is_empty(&event_list)) { |
407 | if (childs > 0) { | |
408 | err(udev, "event list empty, but childs count is %i", childs); | |
409 | childs = 0; | |
410 | } | |
8ab44e3f | 411 | return; |
0bc74ea7 | 412 | } |
8ab44e3f | 413 | |
0bc74ea7 | 414 | udev_list_node_foreach_safe(loop, tmp, &event_list) { |
7e027927 KS |
415 | struct udev_event *loop_event = node_to_event(loop); |
416 | ||
0bc74ea7 KS |
417 | if (childs >= max_childs) { |
418 | info(udev, "maximum number (%i) of childs reached\n", childs); | |
419 | break; | |
420 | } | |
421 | ||
422 | if (loop_event->pid != 0) | |
423 | continue; | |
424 | ||
425 | /* do not start event if parent or child event is still running */ | |
426 | if (devpath_busy(loop_event) != 0) { | |
aa8734ff KS |
427 | dbg(udev, "delay seq %llu (%s)\n", |
428 | udev_device_get_seqnum(loop_event->dev), | |
429 | udev_device_get_devpath(loop_event->dev)); | |
fc465079 KS |
430 | continue; |
431 | } | |
432 | ||
aa8734ff KS |
433 | event_fork(loop_event); |
434 | dbg(udev, "moved seq %llu to running list\n", udev_device_get_seqnum(loop_event->dev)); | |
d1cc6562 OK |
435 | |
436 | /* retry if events finished in the meantime */ | |
437 | if (sigchilds_waiting) { | |
438 | sigchilds_waiting = 0; | |
439 | reap_sigchilds(); | |
440 | goto start_over; | |
441 | } | |
e825b59b | 442 | } |
88f4b648 KS |
443 | } |
444 | ||
3b47c739 | 445 | /* receive the udevd message from userspace */ |
d59f11e1 | 446 | static void handle_ctrl_msg(struct udev_ctrl *uctrl) |
7fafc032 | 447 | { |
d59f11e1 KS |
448 | struct udev *udev = udev_ctrl_get_udev(uctrl); |
449 | struct udev_ctrl_msg *ctrl_msg; | |
450 | const char *str; | |
451 | int i; | |
7b1cbec9 | 452 | |
d59f11e1 KS |
453 | ctrl_msg = udev_ctrl_receive_msg(uctrl); |
454 | if (ctrl_msg == NULL) | |
b437ec95 | 455 | return; |
4a231017 | 456 | |
d59f11e1 KS |
457 | i = udev_ctrl_get_set_log_level(ctrl_msg); |
458 | if (i >= 0) { | |
459 | info(udev, "udevd message (SET_LOG_PRIORITY) received, log_priority=%i\n", i); | |
460 | udev_set_log_priority(udev, i); | |
0028653c KS |
461 | } |
462 | ||
d59f11e1 | 463 | if (udev_ctrl_get_stop_exec_queue(ctrl_msg) > 0) { |
7d563a17 | 464 | info(udev, "udevd message (STOP_EXEC_QUEUE) received\n"); |
3b47c739 | 465 | stop_exec_q = 1; |
d59f11e1 KS |
466 | } |
467 | ||
468 | if (udev_ctrl_get_start_exec_queue(ctrl_msg) > 0) { | |
7d563a17 | 469 | info(udev, "udevd message (START_EXEC_QUEUE) received\n"); |
3b47c739 | 470 | stop_exec_q = 0; |
aa8734ff | 471 | event_queue_manager(udev); |
d59f11e1 KS |
472 | } |
473 | ||
474 | if (udev_ctrl_get_reload_rules(ctrl_msg) > 0) { | |
7d563a17 | 475 | info(udev, "udevd message (RELOAD_RULES) received\n"); |
c895fd00 | 476 | reload_config = 1; |
3b47c739 | 477 | } |
d59f11e1 KS |
478 | |
479 | str = udev_ctrl_get_set_env(ctrl_msg); | |
480 | if (str != NULL) { | |
aa8734ff KS |
481 | char *key; |
482 | ||
483 | key = strdup(str); | |
484 | if (key != NULL) { | |
485 | char *val; | |
486 | ||
487 | val = strchr(key, '='); | |
488 | if (val != NULL) { | |
489 | val[0] = '\0'; | |
490 | val = &val[1]; | |
491 | if (val[0] == '\0') { | |
492 | info(udev, "udevd message (ENV) received, unset '%s'\n", key); | |
493 | udev_add_property(udev, key, NULL); | |
494 | } else { | |
495 | info(udev, "udevd message (ENV) received, set '%s=%s'\n", key, val); | |
496 | udev_add_property(udev, key, val); | |
497 | } | |
d59f11e1 | 498 | } else { |
aa8734ff | 499 | err(udev, "wrong key format '%s'\n", key); |
d59f11e1 | 500 | } |
aa8734ff | 501 | free(key); |
d59f11e1 | 502 | } |
d59f11e1 KS |
503 | } |
504 | ||
505 | i = udev_ctrl_get_set_max_childs(ctrl_msg); | |
506 | if (i >= 0) { | |
507 | info(udev, "udevd message (SET_MAX_CHILDS) received, max_childs=%i\n", i); | |
508 | max_childs = i; | |
509 | } | |
d59f11e1 | 510 | udev_ctrl_msg_unref(ctrl_msg); |
88f4b648 | 511 | } |
4a231017 | 512 | |
bd284db1 SJR |
513 | /* read inotify messages */ |
514 | static int handle_inotify(struct udev *udev) | |
515 | { | |
516 | int nbytes, pos; | |
517 | char *buf; | |
518 | struct inotify_event *ev; | |
519 | int reload_config = 0; | |
520 | ||
521 | if ((ioctl(inotify_fd, FIONREAD, &nbytes) < 0) || (nbytes <= 0)) | |
522 | return 0; | |
523 | ||
524 | buf = malloc(nbytes); | |
525 | if (buf == NULL) { | |
526 | err(udev, "error getting buffer for inotify, disable watching\n"); | |
527 | close(inotify_fd); | |
528 | inotify_fd = -1; | |
529 | return 0; | |
530 | } | |
531 | ||
532 | read(inotify_fd, buf, nbytes); | |
533 | ||
534 | for (pos = 0, ev = (struct inotify_event *)(buf + pos); pos < nbytes; pos += sizeof(struct inotify_event) + ev->len) { | |
535 | const char *syspath; | |
536 | ||
537 | dbg(udev, "inotify event: %x for %d (%s)\n", ev->mask, ev->wd, ev->len ? ev->name : "*"); | |
538 | ||
539 | syspath = udev_watch_lookup(udev, ev->wd); | |
540 | if (syspath != NULL) { | |
541 | dbg(udev, "inotify event: %x for %s\n", ev->mask, syspath); | |
542 | if (ev->mask & IN_CLOSE_WRITE) { | |
543 | char filename[UTIL_PATH_SIZE]; | |
544 | int fd; | |
545 | ||
546 | info(udev, "device %s closed, synthesising write\n", syspath); | |
547 | util_strlcpy(filename, syspath, sizeof(filename)); | |
548 | util_strlcat(filename, "/uevent", sizeof(filename)); | |
549 | fd = open(filename, O_WRONLY); | |
550 | if (fd < 0 || write(fd, "change", 6) < 0) | |
551 | info(udev, "error writing uevent: %m\n"); | |
552 | close(fd); | |
553 | } | |
554 | if (ev->mask & IN_IGNORED) | |
555 | udev_watch_end(udev, ev->wd); | |
556 | } else { | |
557 | reload_config = 1; | |
558 | } | |
559 | } | |
560 | ||
561 | free (buf); | |
562 | return reload_config; | |
563 | } | |
564 | ||
e5a5b54a | 565 | static void asmlinkage sig_handler(int signum) |
7fafc032 | 566 | { |
53921bfa KS |
567 | switch (signum) { |
568 | case SIGINT: | |
569 | case SIGTERM: | |
63cc8f04 | 570 | udev_exit = 1; |
53921bfa | 571 | break; |
2f6cbd19 | 572 | case SIGCHLD: |
f27125f9 | 573 | /* set flag, then write to pipe if needed */ |
5cab7caa | 574 | sigchilds_waiting = 1; |
2f6cbd19 | 575 | break; |
c895fd00 KS |
576 | case SIGHUP: |
577 | reload_config = 1; | |
578 | break; | |
f27125f9 | 579 | } |
5a73b25f | 580 | |
3210a72b | 581 | signal_received = 1; |
33db4b8d | 582 | } |
7fafc032 | 583 | |
f4fc0136 | 584 | static void udev_done(int pid, int exitstatus) |
2f6cbd19 | 585 | { |
7e027927 KS |
586 | struct udev_list_node *loop; |
587 | ||
aa8734ff | 588 | /* find event associated with pid and delete it */ |
0bc74ea7 | 589 | udev_list_node_foreach(loop, &event_list) { |
7e027927 | 590 | struct udev_event *loop_event = node_to_event(loop); |
2f6cbd19 | 591 | |
7e027927 KS |
592 | if (loop_event->pid == pid) { |
593 | info(loop_event->udev, "seq %llu cleanup, pid [%d], status %i, %ld seconds old\n", | |
594 | udev_device_get_seqnum(loop_event->dev), loop_event->pid, | |
595 | exitstatus, time(NULL) - loop_event->queue_time); | |
596 | loop_event->exitstatus = exitstatus; | |
0bc74ea7 | 597 | if (debug_trace) |
27691aa3 | 598 | fprintf(stderr, "exit %s (%llu)\n", |
0bc74ea7 KS |
599 | udev_device_get_syspath(loop_event->dev), |
600 | udev_device_get_seqnum(loop_event->dev)); | |
7e027927 | 601 | event_queue_delete(loop_event); |
0bc74ea7 | 602 | childs--; |
3169e8d1 | 603 | |
0bc74ea7 | 604 | /* there may be dependent events waiting */ |
f27125f9 | 605 | run_exec_q = 1; |
2f6cbd19 KS |
606 | return; |
607 | } | |
608 | } | |
609 | } | |
610 | ||
5cab7caa | 611 | static void reap_sigchilds(void) |
f27125f9 | 612 | { |
40caaeec | 613 | pid_t pid; |
f4fc0136 | 614 | int status; |
ce043f85 | 615 | |
40caaeec | 616 | while (1) { |
f4fc0136 | 617 | pid = waitpid(-1, &status, WNOHANG); |
40caaeec | 618 | if (pid <= 0) |
f27125f9 | 619 | break; |
f4fc0136 KS |
620 | if (WIFEXITED(status)) |
621 | status = WEXITSTATUS(status); | |
82de5983 KS |
622 | else if (WIFSIGNALED(status)) |
623 | status = WTERMSIG(status) + 128; | |
f4fc0136 KS |
624 | else |
625 | status = 0; | |
626 | udev_done(pid, status); | |
f27125f9 | 627 | } |
628 | } | |
629 | ||
78230c0d KS |
630 | static void cleanup_queue_dir(struct udev *udev) |
631 | { | |
632 | char dirname[UTIL_PATH_SIZE]; | |
633 | char filename[UTIL_PATH_SIZE]; | |
634 | DIR *dir; | |
635 | ||
636 | util_strlcpy(filename, udev_get_dev_path(udev), sizeof(filename)); | |
637 | util_strlcat(filename, "/.udev/uevent_seqnum", sizeof(filename)); | |
638 | unlink(filename); | |
639 | ||
640 | util_strlcpy(dirname, udev_get_dev_path(udev), sizeof(dirname)); | |
641 | util_strlcat(dirname, "/.udev/queue", sizeof(dirname)); | |
642 | dir = opendir(dirname); | |
643 | if (dir != NULL) { | |
644 | while (1) { | |
645 | struct dirent *dent; | |
646 | ||
647 | dent = readdir(dir); | |
648 | if (dent == NULL || dent->d_name[0] == '\0') | |
649 | break; | |
650 | if (dent->d_name[0] == '.') | |
651 | continue; | |
652 | util_strlcpy(filename, dirname, sizeof(filename)); | |
653 | util_strlcat(filename, "/", sizeof(filename)); | |
654 | util_strlcat(filename, dent->d_name, sizeof(filename)); | |
655 | unlink(filename); | |
656 | } | |
657 | closedir(dir); | |
658 | rmdir(dirname); | |
659 | } | |
660 | } | |
661 | ||
7d563a17 | 662 | static void export_initial_seqnum(struct udev *udev) |
90cd961e | 663 | { |
17fcfb59 | 664 | char filename[UTIL_PATH_SIZE]; |
90cd961e KS |
665 | int fd; |
666 | char seqnum[32]; | |
667 | ssize_t len = 0; | |
668 | ||
31c1f537 KS |
669 | util_strlcpy(filename, udev_get_sys_path(udev), sizeof(filename)); |
670 | util_strlcat(filename, "/kernel/uevent_seqnum", sizeof(filename)); | |
90cd961e KS |
671 | fd = open(filename, O_RDONLY); |
672 | if (fd >= 0) { | |
673 | len = read(fd, seqnum, sizeof(seqnum)-1); | |
674 | close(fd); | |
675 | } | |
676 | if (len <= 0) { | |
677 | strcpy(seqnum, "0\n"); | |
678 | len = 3; | |
679 | } | |
31c1f537 KS |
680 | util_strlcpy(filename, udev_get_dev_path(udev), sizeof(filename)); |
681 | util_strlcat(filename, "/.udev/uevent_seqnum", sizeof(filename)); | |
54808d77 | 682 | util_create_path(udev, filename); |
90cd961e KS |
683 | fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0644); |
684 | if (fd >= 0) { | |
685 | write(fd, seqnum, len); | |
686 | close(fd); | |
687 | } | |
688 | } | |
689 | ||
59345311 | 690 | int main(int argc, char *argv[]) |
c2cf4012 | 691 | { |
7d563a17 | 692 | struct udev *udev; |
3904a758 | 693 | int fd; |
f8911dbb | 694 | struct sigaction act; |
a15f42c4 | 695 | const char *value; |
561d4c5a | 696 | int daemonize = 0; |
5f03ed8a | 697 | int resolve_names = 1; |
b52a01ee | 698 | static const struct option options[] = { |
033e9f8c KS |
699 | { "daemon", no_argument, NULL, 'd' }, |
700 | { "debug-trace", no_argument, NULL, 't' }, | |
701 | { "debug", no_argument, NULL, 'D' }, | |
702 | { "help", no_argument, NULL, 'h' }, | |
703 | { "version", no_argument, NULL, 'V' }, | |
5f03ed8a | 704 | { "resolve-names", required_argument, NULL, 'N' }, |
b52a01ee KS |
705 | {} |
706 | }; | |
e3396a2d | 707 | int rc = 1; |
53921bfa | 708 | |
7d563a17 KS |
709 | udev = udev_new(); |
710 | if (udev == NULL) | |
711 | goto exit; | |
712 | ||
7257cb18 | 713 | logging_init("udevd"); |
7d563a17 | 714 | udev_set_log_fn(udev, log_fn); |
aa8734ff | 715 | info(udev, "version %s\n", VERSION); |
c3b1fa66 | 716 | udev_selinux_init(udev); |
95a6f4c8 | 717 | |
b52a01ee | 718 | while (1) { |
7d563a17 KS |
719 | int option; |
720 | ||
c70560fe | 721 | option = getopt_long(argc, argv, "dDthV", options, NULL); |
b52a01ee KS |
722 | if (option == -1) |
723 | break; | |
724 | ||
725 | switch (option) { | |
726 | case 'd': | |
561d4c5a | 727 | daemonize = 1; |
b52a01ee | 728 | break; |
c7c00276 KS |
729 | case 't': |
730 | debug_trace = 1; | |
731 | break; | |
c70560fe KS |
732 | case 'D': |
733 | debug = 1; | |
7d563a17 KS |
734 | if (udev_get_log_priority(udev) < LOG_INFO) |
735 | udev_set_log_priority(udev, LOG_INFO); | |
9e8fe79b | 736 | break; |
5f03ed8a SJR |
737 | case 'N': |
738 | if (strcmp (optarg, "early") == 0) { | |
739 | resolve_names = 1; | |
9032f119 SJR |
740 | } else if (strcmp (optarg, "late") == 0) { |
741 | resolve_names = 0; | |
5f03ed8a SJR |
742 | } else if (strcmp (optarg, "never") == 0) { |
743 | resolve_names = -1; | |
744 | } else { | |
9032f119 SJR |
745 | fprintf(stderr, "resolve-names must be early, late or never\n"); |
746 | err(udev, "resolve-names must be early, late or never\n"); | |
5f03ed8a SJR |
747 | goto exit; |
748 | } | |
749 | break; | |
b52a01ee | 750 | case 'h': |
6469c772 KS |
751 | printf("Usage: udevd [--help] [--daemon] [--debug-trace] [--debug] " |
752 | "[--resolve-names=early|late|never] [--version]\n"); | |
841e168c MS |
753 | goto exit; |
754 | case 'V': | |
01618658 | 755 | printf("%s\n", VERSION); |
e3396a2d | 756 | goto exit; |
b52a01ee KS |
757 | default: |
758 | goto exit; | |
561d4c5a | 759 | } |
561d4c5a | 760 | } |
40caaeec | 761 | |
fc89fe7e KS |
762 | if (getuid() != 0) { |
763 | fprintf(stderr, "root privileges required\n"); | |
7d563a17 | 764 | err(udev, "root privileges required\n"); |
fc89fe7e KS |
765 | goto exit; |
766 | } | |
767 | ||
5edec024 MS |
768 | /* make sure std{in,out,err} fd's are in a sane state */ |
769 | fd = open("/dev/null", O_RDWR); | |
770 | if (fd < 0) { | |
771 | fprintf(stderr, "cannot open /dev/null\n"); | |
7d563a17 | 772 | err(udev, "cannot open /dev/null\n"); |
5edec024 | 773 | } |
5edec024 MS |
774 | if (write(STDOUT_FILENO, 0, 0) < 0) |
775 | dup2(fd, STDOUT_FILENO); | |
776 | if (write(STDERR_FILENO, 0, 0) < 0) | |
777 | dup2(fd, STDERR_FILENO); | |
778 | ||
d59f11e1 KS |
779 | /* init control socket, bind() ensures, that only one udevd instance is running */ |
780 | udev_ctrl = udev_ctrl_new_from_socket(udev, UDEV_CTRL_SOCK_PATH); | |
781 | if (udev_ctrl == NULL) { | |
782 | fprintf(stderr, "error initializing control socket"); | |
783 | err(udev, "error initializing udevd socket"); | |
784 | rc = 1; | |
785 | goto exit; | |
786 | } | |
787 | ||
788 | if (udev_ctrl_enable_receiving(udev_ctrl) < 0) { | |
789 | fprintf(stderr, "error binding control socket, seems udevd is already running\n"); | |
790 | err(udev, "error binding control socket, seems udevd is already running\n"); | |
791 | rc = 1; | |
833b3c68 KS |
792 | goto exit; |
793 | } | |
794 | ||
aa8734ff KS |
795 | kernel_monitor = udev_monitor_new_from_netlink(udev); |
796 | if (kernel_monitor == NULL || udev_monitor_enable_receiving(kernel_monitor) < 0) { | |
e3396a2d | 797 | fprintf(stderr, "error initializing netlink socket\n"); |
7d563a17 | 798 | err(udev, "error initializing netlink socket\n"); |
833b3c68 KS |
799 | rc = 3; |
800 | goto exit; | |
801 | } | |
cb25a958 | 802 | udev_monitor_set_receive_buffer_size(kernel_monitor, 128*1024*1024); |
833b3c68 | 803 | |
5f03ed8a | 804 | rules = udev_rules_new(udev, resolve_names); |
d7ddce18 KS |
805 | if (rules == NULL) { |
806 | err(udev, "error reading rules\n"); | |
807 | goto exit; | |
808 | } | |
0bc74ea7 | 809 | udev_list_init(&event_list); |
78230c0d | 810 | cleanup_queue_dir(udev); |
7d563a17 | 811 | export_initial_seqnum(udev); |
90cd961e | 812 | |
561d4c5a | 813 | if (daemonize) { |
f15515b5 KS |
814 | pid_t pid; |
815 | ||
816 | pid = fork(); | |
817 | switch (pid) { | |
818 | case 0: | |
7d563a17 | 819 | dbg(udev, "daemonized fork running\n"); |
f15515b5 KS |
820 | break; |
821 | case -1: | |
659353f5 | 822 | err(udev, "fork of daemon failed: %m\n"); |
833b3c68 | 823 | rc = 4; |
f15515b5 KS |
824 | goto exit; |
825 | default: | |
7d563a17 | 826 | dbg(udev, "child [%u] running, parent exits\n", pid); |
2f64aa40 | 827 | rc = 0; |
833b3c68 | 828 | goto exit; |
f15515b5 KS |
829 | } |
830 | } | |
831 | ||
d59f11e1 | 832 | /* redirect std{out,err} */ |
0bc74ea7 KS |
833 | if (!debug && !debug_trace) { |
834 | dup2(fd, STDIN_FILENO); | |
5edec024 | 835 | dup2(fd, STDOUT_FILENO); |
d59f11e1 KS |
836 | dup2(fd, STDERR_FILENO); |
837 | } | |
5edec024 MS |
838 | if (fd > STDERR_FILENO) |
839 | close(fd); | |
e3396a2d | 840 | |
3904a758 | 841 | /* set scheduling priority for the daemon */ |
085cce37 KS |
842 | setpriority(PRIO_PROCESS, 0, UDEVD_PRIORITY); |
843 | ||
3904a758 | 844 | chdir("/"); |
74adec7d | 845 | umask(022); |
3bc7c84c | 846 | setsid(); |
3904a758 KS |
847 | |
848 | /* OOM_DISABLE == -17 */ | |
849 | fd = open("/proc/self/oom_adj", O_RDWR); | |
850 | if (fd < 0) | |
659353f5 | 851 | err(udev, "error disabling OOM: %m\n"); |
3904a758 KS |
852 | else { |
853 | write(fd, "-17", 3); | |
854 | close(fd); | |
855 | } | |
856 | ||
798d7ab6 KS |
857 | fd = open("/dev/kmsg", O_WRONLY); |
858 | if (fd > 0) { | |
f13e4c36 KS |
859 | const char *ver_str = "<6>udev: starting version " VERSION "\n"; |
860 | char path[UTIL_PATH_SIZE]; | |
861 | struct stat statbuf; | |
862 | ||
863 | write(fd, ver_str, strlen(ver_str)); | |
864 | util_strlcpy(path, udev_get_sys_path(udev), sizeof(path)); | |
865 | util_strlcat(path, "/class/mem/null", sizeof(path)); | |
866 | if (lstat(path, &statbuf) == 0) { | |
867 | if (S_ISDIR(statbuf.st_mode)) { | |
64be1437 KS |
868 | const char *depr_str = |
869 | "<6>udev: deprecated sysfs layout; update the kernel or " | |
870 | "disable CONFIG_SYSFS_DEPRECATED; some udev features will " | |
871 | "not work correctly\n"; | |
f13e4c36 KS |
872 | |
873 | write(fd, depr_str, strlen(depr_str)); | |
874 | } | |
875 | } | |
798d7ab6 KS |
876 | close(fd); |
877 | } | |
878 | ||
f27125f9 | 879 | /* set signal handlers */ |
0786e8e5 | 880 | memset(&act, 0x00, sizeof(struct sigaction)); |
6b493a20 | 881 | act.sa_handler = (void (*)(int)) sig_handler; |
f27125f9 | 882 | sigemptyset(&act.sa_mask); |
5db88229 | 883 | act.sa_flags = SA_RESTART; |
f8911dbb KS |
884 | sigaction(SIGINT, &act, NULL); |
885 | sigaction(SIGTERM, &act, NULL); | |
f8911dbb | 886 | sigaction(SIGCHLD, &act, NULL); |
63cc8f04 | 887 | sigaction(SIGHUP, &act, NULL); |
7fafc032 | 888 | |
c895fd00 | 889 | /* watch rules directory */ |
bd284db1 | 890 | udev_watch_init(udev); |
254d6d3c | 891 | if (inotify_fd >= 0) { |
7d563a17 KS |
892 | if (udev_get_rules_path(udev) != NULL) { |
893 | inotify_add_watch(inotify_fd, udev_get_rules_path(udev), | |
282988c4 KS |
894 | IN_CREATE | IN_DELETE | IN_MOVE | IN_CLOSE_WRITE); |
895 | } else { | |
0bc74ea7 | 896 | char filename[UTIL_PATH_SIZE]; |
282988c4 | 897 | |
01618658 | 898 | inotify_add_watch(inotify_fd, UDEV_PREFIX "/lib/udev/rules.d", |
282988c4 | 899 | IN_CREATE | IN_DELETE | IN_MOVE | IN_CLOSE_WRITE); |
01618658 | 900 | inotify_add_watch(inotify_fd, SYSCONFDIR "/udev/rules.d", |
282988c4 KS |
901 | IN_CREATE | IN_DELETE | IN_MOVE | IN_CLOSE_WRITE); |
902 | ||
903 | /* watch dynamic rules directory */ | |
31c1f537 KS |
904 | util_strlcpy(filename, udev_get_dev_path(udev), sizeof(filename)); |
905 | util_strlcat(filename, "/.udev/rules.d", sizeof(filename)); | |
282988c4 KS |
906 | inotify_add_watch(inotify_fd, filename, |
907 | IN_CREATE | IN_DELETE | IN_MOVE | IN_CLOSE_WRITE); | |
908 | } | |
bd284db1 SJR |
909 | |
910 | udev_watch_restore(udev); | |
911 | } | |
0028653c | 912 | |
0bc74ea7 KS |
913 | /* in trace mode run one event after the other */ |
914 | if (debug_trace) { | |
915 | max_childs = 1; | |
916 | } else { | |
f051e340 KS |
917 | int memsize = mem_size_mb(); |
918 | if (memsize > 0) | |
919 | max_childs = 128 + (memsize / 4); | |
920 | else | |
921 | max_childs = UDEVD_MAX_CHILDS; | |
922 | } | |
0bc74ea7 KS |
923 | /* possibly overwrite maximum limit of executed events */ |
924 | value = getenv("UDEVD_MAX_CHILDS"); | |
925 | if (value) | |
926 | max_childs = strtoul(value, NULL, 10); | |
7d563a17 | 927 | info(udev, "initialize max_childs to %u\n", max_childs); |
a15f42c4 | 928 | |
63cc8f04 | 929 | while (!udev_exit) { |
3210a72b | 930 | sigset_t blocked_mask, orig_mask; |
e9a77fd8 | 931 | struct pollfd pfd[4]; |
3210a72b | 932 | struct pollfd *ctrl_poll, *monitor_poll, *inotify_poll = NULL; |
e9a77fd8 KS |
933 | int nfds = 0; |
934 | int fdcount; | |
3210a72b OK |
935 | |
936 | sigfillset(&blocked_mask); | |
937 | sigprocmask(SIG_SETMASK, &blocked_mask, &orig_mask); | |
938 | if (signal_received) { | |
939 | sigprocmask(SIG_SETMASK, &orig_mask, NULL); | |
940 | goto handle_signals; | |
941 | } | |
021a294c | 942 | |
e9a77fd8 KS |
943 | ctrl_poll = &pfd[nfds++]; |
944 | ctrl_poll->fd = udev_ctrl_get_fd(udev_ctrl); | |
945 | ctrl_poll->events = POLLIN; | |
946 | ||
947 | monitor_poll = &pfd[nfds++]; | |
948 | monitor_poll->fd = udev_monitor_get_fd(kernel_monitor); | |
949 | monitor_poll->events = POLLIN; | |
950 | ||
951 | if (inotify_fd >= 0) { | |
952 | inotify_poll = &pfd[nfds++]; | |
953 | inotify_poll->fd = inotify_fd; | |
954 | inotify_poll->events = POLLIN; | |
955 | } | |
3210a72b OK |
956 | |
957 | fdcount = ppoll(pfd, nfds, NULL, &orig_mask); | |
958 | sigprocmask(SIG_SETMASK, &orig_mask, NULL); | |
40caaeec | 959 | if (fdcount < 0) { |
3210a72b OK |
960 | if (errno == EINTR) |
961 | goto handle_signals; | |
962 | err(udev, "error in select: %m\n"); | |
f27125f9 | 963 | continue; |
2f6cbd19 | 964 | } |
e5a2989e | 965 | |
b3518c16 | 966 | /* get control message */ |
3210a72b | 967 | if (ctrl_poll->revents & POLLIN) |
d59f11e1 | 968 | handle_ctrl_msg(udev_ctrl); |
88f4b648 | 969 | |
aa8734ff | 970 | /* get kernel uevent */ |
3210a72b | 971 | if (monitor_poll->revents & POLLIN) { |
aa8734ff KS |
972 | struct udev_device *dev; |
973 | ||
974 | dev = udev_monitor_receive_device(kernel_monitor); | |
975 | if (dev != NULL) { | |
976 | struct udev_event *event; | |
977 | ||
978 | event = udev_event_new(dev); | |
979 | if (event != NULL) | |
980 | event_queue_insert(event); | |
981 | else | |
982 | udev_device_unref(dev); | |
983 | } | |
021a294c | 984 | } |
e5a2989e | 985 | |
c895fd00 | 986 | /* rules directory inotify watch */ |
bd284db1 SJR |
987 | if (inotify_poll && (inotify_poll->revents & POLLIN)) |
988 | reload_config = handle_inotify(udev); | |
c895fd00 | 989 | |
3210a72b OK |
990 | handle_signals: |
991 | signal_received = 0; | |
992 | ||
e3396a2d | 993 | /* rules changed, set by inotify or a HUP signal */ |
c895fd00 | 994 | if (reload_config) { |
d7ddce18 KS |
995 | struct udev_rules *rules_new; |
996 | ||
c895fd00 | 997 | reload_config = 0; |
5f03ed8a | 998 | rules_new = udev_rules_new(udev, resolve_names); |
d7ddce18 KS |
999 | if (rules_new != NULL) { |
1000 | udev_rules_unref(rules); | |
1001 | rules = rules_new; | |
1002 | } | |
c895fd00 KS |
1003 | } |
1004 | ||
5cab7caa KS |
1005 | if (sigchilds_waiting) { |
1006 | sigchilds_waiting = 0; | |
1007 | reap_sigchilds(); | |
f27125f9 | 1008 | } |
e5a2989e | 1009 | |
f27125f9 | 1010 | if (run_exec_q) { |
f27125f9 | 1011 | run_exec_q = 0; |
3b47c739 | 1012 | if (!stop_exec_q) |
aa8734ff | 1013 | event_queue_manager(udev); |
53921bfa | 1014 | } |
53921bfa | 1015 | } |
c969f880 | 1016 | cleanup_queue_dir(udev); |
e3396a2d | 1017 | rc = 0; |
53921bfa | 1018 | exit: |
d7ddce18 | 1019 | udev_rules_unref(rules); |
d59f11e1 | 1020 | udev_ctrl_unref(udev_ctrl); |
90cd961e | 1021 | if (inotify_fd >= 0) |
c895fd00 | 1022 | close(inotify_fd); |
aa8734ff | 1023 | udev_monitor_unref(kernel_monitor); |
c3b1fa66 | 1024 | udev_selinux_exit(udev); |
e598c573 | 1025 | udev_unref(udev); |
7257cb18 | 1026 | logging_close(); |
833b3c68 | 1027 | return rc; |
7fafc032 | 1028 | } |